diff --git a/README.md b/README.md index 96cd6f6b8a..e9429949b9 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,27 @@ - -

Dactyloidae web browser

-Official Discord server +Dactyloidae web browser +
+Official Discord server | Official Telegram channel

- + -Dactyloidae is a fork of Eclipse Hydra (fork of Basilisk made for Windows XP). +Dactyloidae is a heavily modified fork of Eclipse Hydra (fork of roytam1's Serpent, which is a fork of Basilisk, which is a fork of Firefox). -Some advantages over upstream, roytam1's Serpent and Hydra are: -- More optimizations -- Better interoperability with upstream. (using SQL storage instead of DBM) +Some advantages over upstream, roytam1's Serpent, Eclipse Hydra and Firefox are: +- More optimizations (SSE2, with additional boosts for future CPUs coming soon) +- Better interoperability with upstream (using SQL storage instead of DBM) - More modern theme - Better e10s support +- Support for extensions in the Chrome and Edge Web Store (soon) +- Support for extensions released for both Pale Moon, Basilisk and Firefox - WebExtensions support comparable to Firefox ESR 78 -- Literally being the fastest XUL browser (33.7 in Speedometer 2.1 compared to 22.4 in Pale Moon 34.1 AVX2) +- Literally being the fastest XUL browser (33.7 in Speedometer 2.1 compared to 22.4 in Pale Moon 34.2 AVX2) +- Re-add support for iOS, Android, Windows 2000 and later, NetBSD (soon OpenBSD) -We reccomend using Palefill to potentially fix any browser issues: -Download it here +## Interested in running Dactyloidae in Win9x? +Get DactJump alongside Dactyloidae if you want to use it on 9x. + +Get it here. ## Credits If I've forgotten to put your name here, please let me know and I'll add it. @@ -29,7 +34,7 @@ If I've forgotten to put your name here, please let me know and I'll add it. Major core browser engine contributions: - [Stossy11](https://www.github.com/stossy11) - Helping to develop and fix the macOS build. - [Eclipse Community](https://www.github.com/Eclipse-Community/UXP) - For creating Hydra and Lun3r, the bases of this fork. -- [Loongson Hobbists' community](https://loongfans.cn/en/) - Providing a LoongArch VM and general assistance in porting to LoongArch +- [Loongson Hobbists' community](https://loongfans.cn/en/) - Providing a LoongArch VM and general assistance in porting to LoongArch64 - [Basilisk-Dev](https://repo.palemoon.org/Basilisk-Dev) - For supporting and maintaining Basilisk, aswell as general advice for developing this browser. - [roytam1](https://github.com/roytam1) - Windows XP support code, e10s, WebExtensions, and more for UXP. - [Moonchild Productions](https://repo.palemoon.org/MoonchildProductions) - For creating the Unified XUL Platform and Basilisk, the core of this project. diff --git a/application/basilisk/app/module.ver b/application/basilisk/app/module.ver deleted file mode 100644 index 3520e8e0ff..0000000000 --- a/application/basilisk/app/module.ver +++ /dev/null @@ -1,8 +0,0 @@ -WIN32_MODULE_COMPANYNAME=@MOZ_APP_VENDOR@ -WIN32_MODULE_COPYRIGHT=Eclipse Community, Basilisk and Mozilla Developers; available under the MPL 2 license. -WIN32_MODULE_PRODUCTVERSION=@MOZ_APP_WINVERSION@ -WIN32_MODULE_PRODUCTVERSION_STRING=@MOZ_APP_VERSION@ -WIN32_MODULE_TRADEMARKS=The Hydra logo and project names are trademarks of Eclipse Community. -WIN32_MODULE_DESCRIPTION=@MOZ_APP_DISPLAYNAME@ web browser -WIN32_MODULE_PRODUCTNAME=@MOZ_APP_DISPLAYNAME@ -WIN32_MODULE_NAME=@MOZ_APP_DISPLAYNAME@ diff --git a/application/basilisk/branding/official/LICENSE b/application/basilisk/branding/official/LICENSE deleted file mode 100644 index 72a4bdcb82..0000000000 --- a/application/basilisk/branding/official/LICENSE +++ /dev/null @@ -1,10 +0,0 @@ -This location contains official branding for the Basilisk browser. - -Please note that you are not granted any trademark rights or licenses -to the trademarks of Moonchild Productions, the Basilisk Development Team, or any other party, -including without limitation the Basilisk name or logo. - -These branding materials are Copyrighted (c) the Basilisk Development Team. All rights reserved. - -Official branding using these files is only allowed by the copyright holder -or by third parties with express permission from the copyright holder. diff --git a/application/basilisk/branding/official/branding.nsi b/application/basilisk/branding/official/branding.nsi deleted file mode 100644 index 0fffc53372..0000000000 --- a/application/basilisk/branding/official/branding.nsi +++ /dev/null @@ -1,16 +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/. - -# NSIS branding defines for unofficial builds. -# The official release build branding.nsi is located in other-license/branding/firefox/ -# The nightly build branding.nsi is located in browser/installer/windows/nsis/ - -# BrandFullNameInternal is used for some registry and file system values -# instead of BrandFullName and typically should not be modified. -!define BrandFullNameInternal "Dactyloidae" -!define CompanyName "OwnedByWuigi" -!define URLInfoAbout "about:blank" -!define URLUpdateInfo "about:blank" -!define HelpLink "about:blank" -!define URLSystemRequirements "about:blank" diff --git a/application/basilisk/branding/official/configure.sh b/application/basilisk/branding/official/configure.sh deleted file mode 100644 index c0bc6542f0..0000000000 --- a/application/basilisk/branding/official/configure.sh +++ /dev/null @@ -1,25 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOZ_APP_NAME=dactyloidae - -MOZ_APP_BASENAME="Dactyloidae" - -MOZ_APP_DISPLAYNAME="Dactyloidae" - -MOZ_APP_UA_NAME="Basilisk" - -MOZ_APP_VENDOR="OwnedByWuigi" - -MOZ_APP_FULLNAME="Dactyloidae" - -MOZ_APP_PROFILE="OwnedByWuigi/Dactyloidae" - -MOZ_APP_REMOTINGNAME=com.OwnedByWuigi.Dactyloidae - -MOZ_DISTRIBUTION_ID=com.opensource - -MOZ_MACBUNDLE_NAME="Dactyloidae.app" - -MOZ_SOURCE_REPO=https://github.com/Eclipse-Community/UXP \ No newline at end of file diff --git a/application/basilisk/branding/official/content/about-background.png b/application/basilisk/branding/official/content/about-background.png deleted file mode 100644 index 5f549121e5..0000000000 Binary files a/application/basilisk/branding/official/content/about-background.png and /dev/null differ diff --git a/application/basilisk/branding/official/content/about-wordmark.png b/application/basilisk/branding/official/content/about-wordmark.png deleted file mode 100644 index 5dd55e8bf2..0000000000 Binary files a/application/basilisk/branding/official/content/about-wordmark.png and /dev/null differ diff --git a/application/basilisk/branding/official/content/about-wordmark.svg b/application/basilisk/branding/official/content/about-wordmark.svg deleted file mode 100644 index d950e0944c..0000000000 --- a/application/basilisk/branding/official/content/about-wordmark.svg +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - @roytam1's -own fork - diff --git a/application/basilisk/branding/official/content/aboutDialog.css b/application/basilisk/branding/official/content/aboutDialog.css deleted file mode 100644 index 84d9cea7e4..0000000000 --- a/application/basilisk/branding/official/content/aboutDialog.css +++ /dev/null @@ -1,49 +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/. */ - -#clientBox { - background-color: #F7F7F7; - color: #222; -} - -#leftBox { - background-image: url("chrome://branding/content/about-logo.png"); - background-repeat: no-repeat; - background-size: 192px auto; - /* min-width and min-height create room for the logo */ - min-width: 210px; - min-height: 210px; - margin-top: 20px; - margin-inline-start: 30px; -} - - -@media (min-resolution: 2dppx) { - #leftBox { - background-image: url("chrome://branding/content/about-logo@2x.png"); - } -} - -#rightBox { - margin-left: 30px; - margin-right: 30px; - background-image: url("chrome://branding/content/about-wordmark.png"); - background-repeat: no-repeat; - /* padding-top creates room for the wordmark */ - padding-top: 38px; - margin-top:20px; -} - - -#updateDeck > hbox > label:not([class="text-link"]) { - color: #909090; -} - -#trademark { - font-size: xx-small; - text-align: center; - color: #999; - margin-top: 10px; - margin-bottom: 10px; -} diff --git a/application/basilisk/branding/official/content/jar.mn b/application/basilisk/branding/official/content/jar.mn deleted file mode 100644 index 4b8c5fc9d3..0000000000 --- a/application/basilisk/branding/official/content/jar.mn +++ /dev/null @@ -1,18 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -browser.jar: -% content branding %content/branding/ contentaccessible=yes - content/branding/about.png - content/branding/about-logo.png - content/branding/about-logo@2x.png - content/branding/about-wordmark.png - content/branding/icon48.png - content/branding/icon64.png - content/branding/icon16.png (../default16.png) - content/branding/icon32.png (../default32.png) - content/branding/icon128.png (../mozicon128.png) - content/branding/identity-icons-brand.svg - content/branding/silhouette-40.svg - content/branding/aboutDialog.css diff --git a/application/basilisk/branding/official/default22.png b/application/basilisk/branding/official/default22.png deleted file mode 100644 index 20b378bbac..0000000000 Binary files a/application/basilisk/branding/official/default22.png and /dev/null differ diff --git a/application/basilisk/branding/official/default24.png b/application/basilisk/branding/official/default24.png deleted file mode 100644 index dbf121a6ea..0000000000 Binary files a/application/basilisk/branding/official/default24.png and /dev/null differ diff --git a/application/basilisk/branding/official/default256.png b/application/basilisk/branding/official/default256.png deleted file mode 100644 index b6278c51f3..0000000000 Binary files a/application/basilisk/branding/official/default256.png and /dev/null differ diff --git a/application/basilisk/branding/official/default64.png b/application/basilisk/branding/official/default64.png deleted file mode 100644 index 5aefe2a3c0..0000000000 Binary files a/application/basilisk/branding/official/default64.png and /dev/null differ diff --git a/application/basilisk/branding/official/disk.icns b/application/basilisk/branding/official/disk.icns deleted file mode 100644 index 718f1a3d3c..0000000000 Binary files a/application/basilisk/branding/official/disk.icns and /dev/null differ diff --git a/application/basilisk/branding/official/document.ico b/application/basilisk/branding/official/document.ico deleted file mode 100644 index 3111163247..0000000000 Binary files a/application/basilisk/branding/official/document.ico and /dev/null differ diff --git a/application/basilisk/branding/official/firefox.icns b/application/basilisk/branding/official/firefox.icns deleted file mode 100644 index 2c613634b6..0000000000 Binary files a/application/basilisk/branding/official/firefox.icns and /dev/null differ diff --git a/application/basilisk/branding/official/firefox.ico b/application/basilisk/branding/official/firefox.ico deleted file mode 100644 index 0518438a04..0000000000 Binary files a/application/basilisk/branding/official/firefox.ico and /dev/null differ diff --git a/application/basilisk/branding/official/hydra.VisualElementsManifest.xml b/application/basilisk/branding/official/hydra.VisualElementsManifest.xml deleted file mode 100644 index d675d573f2..0000000000 --- a/application/basilisk/branding/official/hydra.VisualElementsManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/application/basilisk/branding/official/hydra.desktop b/application/basilisk/branding/official/hydra.desktop deleted file mode 100644 index 6d38112231..0000000000 --- a/application/basilisk/branding/official/hydra.desktop +++ /dev/null @@ -1,353 +0,0 @@ -[Desktop Entry] -Name=Hydra -GenericName=Web Browser -GenericName[ar]=متصفح ويب -GenericName[ast]=Restolador Web -GenericName[bn]=ওয়েব ব্রাউজার -GenericName[ca]=Navegador web -GenericName[cs]=Webový prohlížeč -GenericName[da]=Webbrowser -GenericName[el]=Περιηγητής διαδικτύου -GenericName[es]=Navegador web -GenericName[et]=Veebibrauser -GenericName[fa]=مرورگر اینترنتی -GenericName[fi]=WWW-selain -GenericName[fr]=Navigateur Web -GenericName[gl]=Navegador Web -GenericName[he]=דפדפן אינטרנט -GenericName[hr]=Web preglednik -GenericName[hu]=Webböngésző -GenericName[it]=Browser web -GenericName[ja]=ウェブ・ブラウザ -GenericName[ko]=웹 브라우저 -GenericName[ku]=Geroka torê -GenericName[lt]=Interneto naršyklė -GenericName[nb]=Nettleser -GenericName[nl]=Webbrowser -GenericName[nn]=Nettlesar -GenericName[no]=Nettleser -GenericName[pl]=Przeglądarka WWW -GenericName[pt]=Navegador Web -GenericName[pt_BR]=Navegador Web -GenericName[ro]=Navigator Internet -GenericName[ru]=Веб-браузер -GenericName[sk]=Internetový prehliadač -GenericName[sl]=Spletni brskalnik -GenericName[sv]=Webbläsare -GenericName[tr]=Web Tarayıcı -GenericName[ug]=توركۆرگۈ -GenericName[uk]=Веб-браузер -GenericName[vi]=Trình duyệt Web -GenericName[zh_CN]=网络浏览器 -GenericName[zh_TW]=網路瀏覽器 -Comment=Browse the World Wide Web -Comment[ar]=تصفح الشبكة العنكبوتية العالمية -Comment[ast]=Restola pela Rede -Comment[bn]=ইন্টারনেট ব্রাউজ করুন -Comment[ca]=Navegueu per la web -Comment[cs]=Prohlížení stránek World Wide Webu -Comment[da]=Surf på internettet -Comment[de]=Im Internet surfen -Comment[el]=Μπορείτε να περιηγηθείτε στο διαδίκτυο (Web) -Comment[es]=Navegue por la web -Comment[et]=Lehitse veebi -Comment[fa]=صفحات شبکه جهانی اینترنت را مرور نمایید -Comment[fi]=Selaa Internetin WWW-sivuja -Comment[fr]=Naviguer sur le Web -Comment[gl]=Navegar pola rede -Comment[he]=גלישה ברחבי האינטרנט -Comment[hr]=Pretražite web -Comment[hu]=A világháló böngészése -Comment[it]=Esplora il web -Comment[ja]=ウェブを閲覧します -Comment[ko]=웹을 돌아 다닙니다 -Comment[ku]=Li torê bigere -Comment[lt]=Naršykite internete -Comment[nb]=Surf på nettet -Comment[nl]=Verken het internet -Comment[nn]=Surf på nettet -Comment[no]=Surf på nettet -Comment[pl]=Przeglądanie stron WWW -Comment[pt]=Navegue na Internet -Comment[pt_BR]=Navegue na Internet -Comment[ro]=Navigați pe Internet -Comment[ru]=Доступ в Интернет -Comment[sk]=Prehliadanie internetu -Comment[sl]=Brskajte po spletu -Comment[sv]=Surfa på webben -Comment[tr]=İnternet'te Gezinin -Comment[ug]=دۇنيادىكى توربەتلەرنى كۆرگىلى بولىدۇ -Comment[uk]=Перегляд сторінок Інтернету -Comment[vi]=Để duyệt các trang web -Comment[zh_CN]=浏览互联网 -Comment[zh_TW]=瀏覽網際網路 -Exec=hydra %u -Terminal=false -Type=Application -Icon=hydra -Categories=Network;WebBrowser; -MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp; -StartupNotify=false -Actions=NewTab;NewWindow;NewPrivateWindow; -StartupWMClass="hydra" - -[Desktop Action NewTab] -Name=Open new tab -Name[ach]=Yab dirica matidi manyen -Name[af]=Open nuwe oortjie -Name[an]=Ubrir una pestanya nueva -Name[ar]=افتح لسانًا جديدًا -Name[as]=নতুন টেব খোলক -Name[ast]=Abrir llingüeta nueva -Name[az]=Yeni vərəq aç -Name[be]=Адкрыць новую ўстаўку -Name[bg]=Отваряне на нов подпрозорец -Name[bn_BD]=নতুন ট্যাব খুলুন -Name[bn_IN]=নতুন ট্যাব খুলুন -Name[br]=Digeriñ un ivinell nevez -Name[bs]=Otvori novi tab -Name[ca]=Obre una pestanya nova -Name[cs]=Otevřít nový panel -Name[cy]=Agor tab newydd -Name[da]=Åbn nyt faneblad -Name[de]=Neuen Tab öffnen -Name[dsb]=Nowy rejtark wócyniś -Name[el]=Άνοιγμα νέας καρτέλας -Name[eo]=Malfermi novan langeton -Name[es_AR]=Abrir nueva pestaña -Name[es_CL]=Abrir nueva pestaña -Name[es_ES]=Abrir pestaña nueva -Name[es_MX]=Abrir una pestaña nueva -Name[et]=Ava uus kaart -Name[eu]=Ireki fitxa berria -Name[ff]=Uddit tabbere hesere -Name[fi]=Avaa uusi välilehti -Name[fr]=Ouvrir un nouvel onglet -Name[fy_NL]=Iepenje nij ljepblêd -Name[ga_IE]=Oscail i gcluaisín nua -Name[gd]=Fosgail taba ùr -Name[gl]=Abrir unha nova lapela -Name[gu_IN]=નવી ટૅબને ખોલો -Name[he]=פתיחת לשונית חדשה -Name[hi_IN]=नया टैब खोलें -Name[hr]=Otvori novu karticu -Name[hsb]=Nowy rajtark wočinić -Name[hu]=Új lap megnyitása -Name[hy_AM]=Բացել նոր ներդիր -Name[id]=Buka tab baru -Name[is]=Opna nýjan flipa -Name[it]=Apri nuova scheda -Name[ja]=新しいタブ -Name[kk]=Жаңа бетті ашу -Name[kn]=ಹೊಸ ಹಾಳೆಯನ್ನು ತೆರೆ -Name[ko]=새 탭 열기 -Name[lij]=Àrvi nêuvo féuggio -Name[lt]=Atverti naują kortelę -Name[mai]=नव टैब खोलू -Name[mk]=Отвори ново јазиче -Name[ml]=പുതിയ റ്റാബ് തുറക്കുക -Name[mr]=नवीन टॅब उघडा -Name[ms]=Buka tab baru -Name[nb_NO]=Åpne ny fane -Name[nl]=Nieuw tabblad openen -Name[nn_NO]=Opna ny fane -Name[or]=ନୂତନ ଟ୍ୟାବ ଖୋଲନ୍ତୁ -Name[pa_IN]=ਨਵੀਂ ਟੈਬ ਖੋਲ੍ਹੋ -Name[pl]=Otwórz nową kartę -Name[pt_BR]=Nova aba -Name[pt_PT]=Abrir novo separador -Name[rm]=Avrir in nov tab -Name[ro]=Deschide o filă nouă -Name[ru]=Открыть новую вкладку -Name[si]=නව ටැබය විවෘත කරන්න -Name[sk]=Otvoriť novú kartu -Name[sl]=Odpri nov zavihek -Name[son]=Nor loku taaga feeri -Name[sq]=Hap skedë të re -Name[sr]=Отвори нови језичак -Name[sv_SE]=Öppna ny flik -Name[ta]=புதிய கீற்றைத் திற -Name[te]=కొత్త టాబ్ తెరువుము -Name[th]=เปิดแท็บใหม่ -Name[tr]=Yeni sekme aç -Name[uk]=Відкрити нову вкладку -Name[uz]=Yangi ichki oyna ochish -Name[vi]=Mở thẻ mới -Name[xh]=Vula ithebhu entsha -Name[zh_CN]=打开新标签页 -Name[zh_TW]=開啟新分頁 -Exec=hydra -new-tab - -[Desktop Action NewWindow] -Name=Open new window -Name[ach]=Yab dirica manyen -Name[af]=Open nuwe venster -Name[an]=Ubrir una nueva finestra -Name[ar]=افتح نافذة جديدة -Name[as]=নতুন উইন্ডো খোলক -Name[ast]=Abrir ventana nueva -Name[az]=Yeni pəncərə aç -Name[be]=Адкрыць новае акно -Name[bg]=Отваряне на нов прозорец -Name[bn_BD]=নতুন উইন্ডো খুলুন -Name[bn_IN]=নতুন উইন্ডো খুলুন -Name[br]=Digeriñ ur prenestr nevez -Name[bs]=Otvori novi prozor -Name[ca]=Obre una finestra nova -Name[cs]=Otevřít nové okno -Name[cy]=Agor ffenestr newydd -Name[da]=Åbn nyt vindue -Name[de]=Neues Fenster öffnen -Name[dsb]=Nowe wokno wócyniś -Name[el]=Άνοιγμα νέου παραθύρου -Name[eo]=Malfermi novan fenestron -Name[es_AR]=Abrir nueva ventana -Name[es_CL]=Abrir nueva ventana -Name[es_ES]=Abrir nueva ventana -Name[es_MX]=Abrir nueva ventana -Name[et]=Ava uus aken -Name[eu]=Ireki leiho berria -Name[ff]=Uddit henorde hesere -Name[fi]=Avaa uusi ikkuna -Name[fr]=Ouvrir une nouvelle fenêtre -Name[fy_NL]=Iepenje nij finster -Name[ga_IE]=Oscail fuinneog nua -Name[gd]=Fosgail uinneag ùr -Name[gl]=Abrir unha nova xanela -Name[gu_IN]=નવી વિન્ડોને ખોલો -Name[he]=פתח חלון חדש -Name[hi_IN]=नई विंडो खोलें -Name[hr]=Otvori novi prozor -Name[hsb]=Nowe wokno wočinić -Name[hu]=Új ablak megnyitása -Name[hy_AM]=Բացել նոր պատուհան -Name[id]=Buka jendela baru -Name[is]=Opna nýjan glugga -Name[it]=Apri nuova finestra -Name[ja]=新しいウィンドウ -Name[kk]=Жаңа терезені ашу -Name[kn]=ಹೊಸ ವಿಂಡೊವನ್ನು ತೆರೆ -Name[ko]=새 창 열기 -Name[lij]=Àrvi nêuvo barcón -Name[lt]=Atverti naują langą -Name[mai]=नई विंडो खोलू -Name[mk]=Отвори нов прозорец -Name[ml]=പുതിയ ജാലകം തുറക്കുക -Name[mr]=नवीन पटल उघडा -Name[ms]=Buka tetingkap baru -Name[nb_NO]=Åpne nytt vindu -Name[nl]=Een nieuw venster openen -Name[nn_NO]=Opna nytt vindauge -Name[or]=ନୂତନ ୱିଣ୍ଡୋ ଖୋଲନ୍ତୁ -Name[pa_IN]=ਨਵੀਂ ਵਿੰਡੋ ਖੋਲ੍ਹੋ -Name[pl]=Otwórz nowe okno -Name[pt_BR]=Nova janela -Name[pt_PT]=Abrir nova janela -Name[rm]=Avrir ina nova fanestra -Name[ro]=Deschide o nouă fereastră -Name[ru]=Открыть новое окно -Name[si]=නව කවුළුවක් විවෘත කරන්න -Name[sk]=Otvoriť nové okno -Name[sl]=Odpri novo okno -Name[son]=Zanfun taaga feeri -Name[sq]=Hap dritare të re -Name[sr]=Отвори нови прозор -Name[sv_SE]=Öppna nytt fönster -Name[ta]=புதிய சாளரத்தை திற -Name[te]=కొత్త విండో తెరువుము -Name[th]=เปิดหน้าต่างใหม่ -Name[tr]=Yeni pencere aç -Name[uk]=Відкрити нове вікно -Name[uz]=Yangi oyna ochish -Name[vi]=Mở cửa sổ mới -Name[xh]=Vula iwindow entsha -Name[zh_CN]=打开新窗口 -Name[zh_TW]=開啟新視窗 -Exec=hydra -new-window - -[Desktop Action NewPrivateWindow] -Name=New private window -Name[ach]=Dirica manyen me mung -Name[af]=Nuwe privaatvenster -Name[an]=Nueva finestra de navegación privada -Name[ar]=نافذة خاصة جديدة -Name[as]=নতুন ব্যক্তিগত উইন্ডো -Name[ast]=Ventana privada nueva -Name[az]=Yeni məxfi pəncərə -Name[be]=Новае акно адасаблення -Name[bg]=Нов прозорец за поверително сърфиране -Name[bn_BD]=নতুন ব্যক্তিগত উইন্ডো -Name[bn_IN]=নতুন ব্যাক্তিগত উইন্ডো -Name[br]=Prenestr merdeiñ prevez nevez -Name[bs]=Novi privatni prozor -Name[ca]=Finestra privada nova -Name[cs]=Nové anonymní okno -Name[cy]=Ffenestr breifat newydd -Name[da]=Nyt privat vindue -Name[de]=Neues privates Fenster öffnen -Name[dsb]=Nowe priwatne wokno -Name[el]=Νέο παράθυρο ιδιωτικής περιήγησης -Name[eo]=Nova privata fenestro -Name[es_AR]=Nueva ventana privada -Name[es_CL]=Nueva ventana privada -Name[es_ES]=Nueva ventana privada -Name[es_MX]=Nueva ventana privada -Name[et]=Uus privaatne aken -Name[eu]=Leiho pribatu berria -Name[ff]=Henorde suturo hesere -Name[fi]=Uusi yksityinen ikkuna -Name[fr]=Nouvelle fenêtre de navigation privée -Name[fy_NL]=Nij priveefinster -Name[ga_IE]=Fuinneog nua phríobháideach -Name[gd]=Uinneag phrìobhaideach ùr -Name[gl]=Nova xanela privada -Name[gu_IN]=નવી ખાનગી વિન્ડો -Name[he]=חלון פרטי חדש -Name[hi_IN]=नया निजी विंडो -Name[hr]=Novi privatni prozor -Name[hsb]=Nowe priwatne wokno -Name[hu]=Új privát ablak -Name[hy_AM]=Գաղտնի դիտարկում -Name[id]=Jendela mode pribadi baru -Name[is]=Nýr einkagluggi -Name[it]=Nuova finestra anonima -Name[ja]=新しいプライベートウィンドウ -Name[kk]=Жаңа жекелік терезе -Name[kn]=ಹೊಸ ಖಾಸಗಿ ಕಿಟಕಿ -Name[ko]=새 사생활 보호 창 -Name[lij]=Nêuvo barcón privòu -Name[lt]=Atverti privačiojo naršymo langą -Name[mai]=नव निज विंडो -Name[mk]=Нов прозорец за приватно сурфање -Name[ml]=പുതിയ സ്വകാര്യ ജാലകം -Name[mr]=नवीन वैयक्तिक पटल -Name[ms]=Tetingkap peribadi baharu -Name[nb_NO]=Nytt privat vindu -Name[nl]=Nieuw privévenster -Name[nn_NO]=Nytt privat vindauge -Name[or]=ନୂତନ ବ୍ୟକ୍ତିଗତ ୱିଣ୍ଡୋ -Name[pa_IN]=ਨਵੀਂ ਪ੍ਰਾਈਵੇਟ ਵਿੰਡੋ -Name[pl]=Nowe okno w trybie prywatnym -Name[pt_BR]=Nova janela privativa -Name[pt_PT]=Nova janela privada -Name[rm]=Nova fanestra privata -Name[ro]=Fereastră fără urme nouă -Name[ru]=Новое приватное окно -Name[si]=නව පුද්ගලික කවුළුව -Name[sk]=Nové okno v režime Súkromné prehliadanie -Name[sl]=Novo zasebno okno -Name[son]=Sutura zanfun taaga -Name[sq]=Dritare e re private -Name[sr]=Нови приватни прозор -Name[sv_SE]=Nytt privat fönster -Name[ta]=புதிய தனிப்பட்ட சாளரம் -Name[te]=కొత్త ఆంతరంగిక విండో -Name[th]=หน้าต่างท่องเว็บแบบส่วนตัวใหม่ -Name[tr]=Yeni gizli pencere -Name[uk]=Нове приватне вікно -Name[uz]=Yangi shaxsiy oyna -Name[vi]=Cửa sổ riêng tư mới -Name[xh]=Ifestile yangasese entsha -Name[zh_CN]=新建隐私浏览窗口 -Name[zh_TW]=新增隱私視窗 -Exec=hydra -private-window diff --git a/application/basilisk/branding/official/locales/en-US/brand.dtd b/application/basilisk/branding/official/locales/en-US/brand.dtd deleted file mode 100644 index db5bae1a8d..0000000000 --- a/application/basilisk/branding/official/locales/en-US/brand.dtd +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - diff --git a/application/basilisk/branding/official/locales/en-US/brand.properties b/application/basilisk/branding/official/locales/en-US/brand.properties deleted file mode 100644 index 1c26c34953..0000000000 --- a/application/basilisk/branding/official/locales/en-US/brand.properties +++ /dev/null @@ -1,17 +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/. - -brandShortName=Eclipse Hydra -# The above controls the name shown in the app -brandShorterName=Hydra -brandFullName=Eclipse Hydra -vendorShortName=Eclipse Community - -homePageSingleStartMain=Internal home page with search. -homePageImport=Import your home page from %S - -homePageMigrationPageTitle=Home Page Selection -homePageMigrationDescription=Please select the home page you wish to use: - -syncBrandShortName=Sync diff --git a/application/basilisk/branding/official/locales/jar.mn b/application/basilisk/branding/official/locales/jar.mn deleted file mode 100644 index 9fdfe578b4..0000000000 --- a/application/basilisk/branding/official/locales/jar.mn +++ /dev/null @@ -1,11 +0,0 @@ -#filter substitution -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -@AB_CD@.jar: -% locale branding @AB_CD@ %locale/branding/ - locale/branding/brand.dtd (%brand.dtd) - locale/branding/brand.properties (%brand.properties) - locale/branding/browserconfig.properties diff --git a/application/basilisk/branding/official/moz.build b/application/basilisk/branding/official/moz.build deleted file mode 100644 index aba83ec3f3..0000000000 --- a/application/basilisk/branding/official/moz.build +++ /dev/null @@ -1,16 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += ['content', 'locales'] - -DIST_SUBDIR = 'browser' -export('DIST_SUBDIR') - -include('../shared/branding.mozbuild') -ApplicationBranding() - -FINAL_TARGET_FILES['..'] += [ - 'Hydra.VisualElementsManifest.xml', -] diff --git a/application/basilisk/branding/official/pref/basilisk-branding.js b/application/basilisk/branding/official/pref/basilisk-branding.js deleted file mode 100644 index 9bcd3918b8..0000000000 --- a/application/basilisk/branding/official/pref/basilisk-branding.js +++ /dev/null @@ -1,46 +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/. */ - -#filter substitution -#filter emptyLines - -// Set defines to construct URLs -#define BRANDING_BASEURL eclipse.cx -#define BRANDING_SITEURL eclipse.cx - -// Shared Branding Preferences -// XXX: These should REALLY go back to application preferences -#include ../../shared/preferences.inc - -// Branding Specific Preferences -pref("startup.homepage_override_url", ""); -pref("startup.homepage_welcome_url", ""); -pref("startup.homepage_welcome_url.additional", ""); -// Version release notes -pref("app.releaseNotesURL", "https://github.com/Eclipse-Community/UXP/releases"); - -// base url for web-based feedback pages -pref("app.feedback.baseURL", "https://board.eclipse.cx/viewtopic.php?t=710"); - -// Vendor home page -pref("app.vendorURL", "https://eclipse.cx"); - -pref("app.update.url", ""); - -// URL user can browse to manually if for some reason all update installation -// attempts fail. -pref("app.update.url.manual", "about:"); -// A default value for the "More information about this update" link -// supplied in the "An update is available" page of the update wizard. -pref("app.update.url.details", "about:"); - -// Provide UA Gecko and Firefox slices for web compatibility -pref("general.useragent.compatMode.firefox",true); -pref("general.useragent.compatMode.gecko",true); - -// Switch Application Updates off for unofficial branding -pref("app.update.enabled", false); - -// Shared User Agent Overrides -#include ../../shared/uaoverrides.inc diff --git a/application/basilisk/branding/official/wizHeader.bmp b/application/basilisk/branding/official/wizHeader.bmp deleted file mode 100644 index f67b452391..0000000000 Binary files a/application/basilisk/branding/official/wizHeader.bmp and /dev/null differ diff --git a/application/basilisk/branding/official/wizWatermark.bmp b/application/basilisk/branding/official/wizWatermark.bmp deleted file mode 100644 index 05f0e7f9b2..0000000000 Binary files a/application/basilisk/branding/official/wizWatermark.bmp and /dev/null differ diff --git a/application/basilisk/branding/unofficial/VisualElements_150.png b/application/basilisk/branding/unofficial/VisualElements_150.png deleted file mode 100644 index eb74e4adc5..0000000000 Binary files a/application/basilisk/branding/unofficial/VisualElements_150.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/VisualElements_70.png b/application/basilisk/branding/unofficial/VisualElements_70.png deleted file mode 100644 index 571532a9ba..0000000000 Binary files a/application/basilisk/branding/unofficial/VisualElements_70.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/appname.bmp b/application/basilisk/branding/unofficial/appname.bmp deleted file mode 100644 index 1ee08c9445..0000000000 Binary files a/application/basilisk/branding/unofficial/appname.bmp and /dev/null differ diff --git a/application/basilisk/branding/unofficial/background.png b/application/basilisk/branding/unofficial/background.png deleted file mode 100644 index 3fa4a0ec73..0000000000 Binary files a/application/basilisk/branding/unofficial/background.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/content/about-background.png b/application/basilisk/branding/unofficial/content/about-background.png deleted file mode 100644 index c59b53eb91..0000000000 Binary files a/application/basilisk/branding/unofficial/content/about-background.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/content/about-logo.png b/application/basilisk/branding/unofficial/content/about-logo.png deleted file mode 100644 index c5a838178a..0000000000 Binary files a/application/basilisk/branding/unofficial/content/about-logo.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/content/about-logo@2x.png b/application/basilisk/branding/unofficial/content/about-logo@2x.png deleted file mode 100644 index 48c31564c4..0000000000 Binary files a/application/basilisk/branding/unofficial/content/about-logo@2x.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/content/about.png b/application/basilisk/branding/unofficial/content/about.png deleted file mode 100644 index e323c8df5c..0000000000 Binary files a/application/basilisk/branding/unofficial/content/about.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/content/icon48.png b/application/basilisk/branding/unofficial/content/icon48.png deleted file mode 100644 index 16e022a647..0000000000 Binary files a/application/basilisk/branding/unofficial/content/icon48.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/content/icon64.png b/application/basilisk/branding/unofficial/content/icon64.png deleted file mode 100644 index 9860917e3e..0000000000 Binary files a/application/basilisk/branding/unofficial/content/icon64.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/content/identity-icons-brand.svg b/application/basilisk/branding/unofficial/content/identity-icons-brand.svg deleted file mode 100644 index 6c33113e56..0000000000 --- a/application/basilisk/branding/unofficial/content/identity-icons-brand.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/application/basilisk/branding/unofficial/content/silhouette-40.svg b/application/basilisk/branding/unofficial/content/silhouette-40.svg deleted file mode 100644 index aa17cd3093..0000000000 --- a/application/basilisk/branding/unofficial/content/silhouette-40.svg +++ /dev/null @@ -1,1360 +0,0 @@ - - - - - diff --git a/application/basilisk/branding/unofficial/default16.png b/application/basilisk/branding/unofficial/default16.png deleted file mode 100644 index e74f5cf2e4..0000000000 Binary files a/application/basilisk/branding/unofficial/default16.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/default32.png b/application/basilisk/branding/unofficial/default32.png deleted file mode 100644 index 9145090543..0000000000 Binary files a/application/basilisk/branding/unofficial/default32.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/default48.png b/application/basilisk/branding/unofficial/default48.png deleted file mode 100644 index 5fd71e110c..0000000000 Binary files a/application/basilisk/branding/unofficial/default48.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/document.icns b/application/basilisk/branding/unofficial/document.icns deleted file mode 100644 index ff419f2f7b..0000000000 Binary files a/application/basilisk/branding/unofficial/document.icns and /dev/null differ diff --git a/application/basilisk/branding/unofficial/mozicon128.png b/application/basilisk/branding/unofficial/mozicon128.png deleted file mode 100644 index 739b61084b..0000000000 Binary files a/application/basilisk/branding/unofficial/mozicon128.png and /dev/null differ diff --git a/application/basilisk/branding/unofficial/wizHeaderRTL.bmp b/application/basilisk/branding/unofficial/wizHeaderRTL.bmp deleted file mode 100644 index 7c57e461ba..0000000000 Binary files a/application/basilisk/branding/unofficial/wizHeaderRTL.bmp and /dev/null differ diff --git a/application/basilisk/build.mk b/application/basilisk/build.mk deleted file mode 100644 index 10fe02d4e7..0000000000 --- a/application/basilisk/build.mk +++ /dev/null @@ -1,61 +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/. - -installer: - @$(MAKE) -C application/basilisk/installer installer - -package: - @$(MAKE) -C application/basilisk/installer make-archive - -l10n-package: - @$(MAKE) -C application/basilisk/installer make-langpack - -mozpackage: - @$(MAKE) -C application/basilisk/installer - -package-compare: - @$(MAKE) -C application/basilisk/installer package-compare - -stage-package: - @$(MAKE) -C application/basilisk/installer stage-package make-buildinfo-file - -sdk: - @$(MAKE) -C application/basilisk/installer make-sdk - -install:: - @$(MAKE) -C application/basilisk/installer install - -clean:: - @$(MAKE) -C application/basilisk/installer clean - -distclean:: - @$(MAKE) -C application/basilisk/installer distclean - -source-package:: - @$(MAKE) -C application/basilisk/installer source-package - -upload:: - @$(MAKE) -C application/basilisk/installer upload - -source-upload:: - @$(MAKE) -C application/basilisk/installer source-upload - -hg-bundle:: - @$(MAKE) -C application/basilisk/installer hg-bundle - -l10n-check:: - @$(MAKE) -C application/basilisk/locales l10n-check - -ifdef ENABLE_TESTS -# Implemented in testing/testsuite-targets.mk - -mochitest-browser-chrome: - $(RUN_MOCHITEST) --flavor=browser - $(CHECK_TEST_ERROR) - -mochitest:: mochitest-browser-chrome - -.PHONY: mochitest-browser-chrome - -endif diff --git a/application/basilisk/config/version.txt b/application/basilisk/config/version.txt deleted file mode 100644 index c059982684..0000000000 --- a/application/basilisk/config/version.txt +++ /dev/null @@ -1 +0,0 @@ -52.13.2 \ No newline at end of file diff --git a/application/basilisk/config/version_display.txt b/application/basilisk/config/version_display.txt deleted file mode 100644 index 4092290770..0000000000 --- a/application/basilisk/config/version_display.txt +++ /dev/null @@ -1 +0,0 @@ -13.2 \ No newline at end of file diff --git a/application/basilisk/themes/osx/communicator/moz.build b/application/basilisk/themes/osx/communicator/moz.build deleted file mode 100644 index 635fa39c99..0000000000 --- a/application/basilisk/themes/osx/communicator/moz.build +++ /dev/null @@ -1,6 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/application/basilisk/.eslintrc.js b/browser/.eslintrc.js similarity index 100% rename from application/basilisk/.eslintrc.js rename to browser/.eslintrc.js diff --git a/application/basilisk/LICENSE b/browser/LICENSE similarity index 100% rename from application/basilisk/LICENSE rename to browser/LICENSE diff --git a/application/basilisk/Makefile.in b/browser/Makefile.in similarity index 100% rename from application/basilisk/Makefile.in rename to browser/Makefile.in diff --git a/application/basilisk/app-rules.mk b/browser/app-rules.mk similarity index 100% rename from application/basilisk/app-rules.mk rename to browser/app-rules.mk diff --git a/application/basilisk/app.mozbuild b/browser/app.mozbuild similarity index 92% rename from application/basilisk/app.mozbuild rename to browser/app.mozbuild index c686156438..8054a12e05 100644 --- a/application/basilisk/app.mozbuild +++ b/browser/app.mozbuild @@ -11,4 +11,4 @@ DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']] # Never add dirs after the browser root because they apparently won't # get packaged properly on Mac. -DIRS += ['/application/basilisk'] +DIRS += ['/browser'] diff --git a/application/basilisk/app/Makefile.in b/browser/app/Makefile.in similarity index 100% rename from application/basilisk/app/Makefile.in rename to browser/app/Makefile.in diff --git a/application/basilisk/app/application.ini b/browser/app/application.ini similarity index 100% rename from application/basilisk/app/application.ini rename to browser/app/application.ini diff --git a/application/basilisk/app/blocklist.xml b/browser/app/blocklist.xml similarity index 100% rename from application/basilisk/app/blocklist.xml rename to browser/app/blocklist.xml diff --git a/application/basilisk/app/dactyloidae.exe.manifest b/browser/app/dactyloidae.exe.manifest similarity index 100% rename from application/basilisk/app/dactyloidae.exe.manifest rename to browser/app/dactyloidae.exe.manifest diff --git a/application/basilisk/app/macbuild/Contents/Info.plist.in b/browser/app/macbuild/Contents/Info.plist.in similarity index 100% rename from application/basilisk/app/macbuild/Contents/Info.plist.in rename to browser/app/macbuild/Contents/Info.plist.in diff --git a/application/basilisk/app/macbuild/Contents/MacOS-files-copy.in b/browser/app/macbuild/Contents/MacOS-files-copy.in similarity index 100% rename from application/basilisk/app/macbuild/Contents/MacOS-files-copy.in rename to browser/app/macbuild/Contents/MacOS-files-copy.in diff --git a/application/basilisk/app/macbuild/Contents/MacOS-files.in b/browser/app/macbuild/Contents/MacOS-files.in similarity index 100% rename from application/basilisk/app/macbuild/Contents/MacOS-files.in rename to browser/app/macbuild/Contents/MacOS-files.in diff --git a/application/basilisk/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/browser/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in similarity index 100% rename from application/basilisk/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in rename to browser/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in diff --git a/application/basilisk/app/macversion.py b/browser/app/macversion.py similarity index 100% rename from application/basilisk/app/macversion.py rename to browser/app/macversion.py diff --git a/browser/app/module.ver b/browser/app/module.ver new file mode 100644 index 0000000000..fb17732577 --- /dev/null +++ b/browser/app/module.ver @@ -0,0 +1,8 @@ +WIN32_MODULE_COMPANYNAME=@MOZ_APP_VENDOR@ +WIN32_MODULE_COPYRIGHT=�Dactyloidae Project, Eclipse Community, Basilisk and Mozilla Developers; available under the MPL 2 license. +WIN32_MODULE_PRODUCTVERSION=@MOZ_APP_WINVERSION@ +WIN32_MODULE_PRODUCTVERSION_STRING=@MOZ_APP_VERSION@ +WIN32_MODULE_TRADEMARKS=The Dactyloidae logo and project names are trademarks of Eclipse Community and Dactyloidae Project. +WIN32_MODULE_DESCRIPTION=@MOZ_APP_DISPLAYNAME@ +WIN32_MODULE_PRODUCTNAME=@MOZ_APP_DISPLAYNAME@ +WIN32_MODULE_NAME=@MOZ_APP_DISPLAYNAME@ diff --git a/application/basilisk/app/moz.build b/browser/app/moz.build similarity index 100% rename from application/basilisk/app/moz.build rename to browser/app/moz.build diff --git a/application/basilisk/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp similarity index 100% rename from application/basilisk/app/nsBrowserApp.cpp rename to browser/app/nsBrowserApp.cpp diff --git a/application/basilisk/app/permissions b/browser/app/permissions similarity index 100% rename from application/basilisk/app/permissions rename to browser/app/permissions diff --git a/application/basilisk/app/profile/basilisk.js b/browser/app/profile/basilisk.js similarity index 100% rename from application/basilisk/app/profile/basilisk.js rename to browser/app/profile/basilisk.js diff --git a/application/basilisk/app/profile/channel-prefs.js b/browser/app/profile/channel-prefs.js similarity index 100% rename from application/basilisk/app/profile/channel-prefs.js rename to browser/app/profile/channel-prefs.js diff --git a/application/basilisk/app/profile/extensions/moz.build b/browser/app/profile/extensions/moz.build similarity index 100% rename from application/basilisk/app/profile/extensions/moz.build rename to browser/app/profile/extensions/moz.build diff --git a/application/basilisk/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf.in b/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf.in similarity index 100% rename from application/basilisk/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf.in rename to browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf.in diff --git a/application/basilisk/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/moz.build b/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/moz.build similarity index 100% rename from application/basilisk/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/moz.build rename to browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/moz.build diff --git a/application/basilisk/app/profile/pagethemes.rdf b/browser/app/profile/pagethemes.rdf similarity index 100% rename from application/basilisk/app/profile/pagethemes.rdf rename to browser/app/profile/pagethemes.rdf diff --git a/application/basilisk/app/profile/prefs.js b/browser/app/profile/prefs.js similarity index 100% rename from application/basilisk/app/profile/prefs.js rename to browser/app/profile/prefs.js diff --git a/application/basilisk/app/splash.rc b/browser/app/splash.rc similarity index 100% rename from application/basilisk/app/splash.rc rename to browser/app/splash.rc diff --git a/application/basilisk/base/.eslintrc.js b/browser/base/.eslintrc.js similarity index 100% rename from application/basilisk/base/.eslintrc.js rename to browser/base/.eslintrc.js diff --git a/application/basilisk/base/content/aboutDialog-appUpdater.js b/browser/base/content/aboutDialog-appUpdater.js similarity index 100% rename from application/basilisk/base/content/aboutDialog-appUpdater.js rename to browser/base/content/aboutDialog-appUpdater.js diff --git a/application/basilisk/base/content/aboutDialog.css b/browser/base/content/aboutDialog.css similarity index 94% rename from application/basilisk/base/content/aboutDialog.css rename to browser/base/content/aboutDialog.css index baeeada7a2..71177a6ee4 100644 --- a/application/basilisk/base/content/aboutDialog.css +++ b/browser/base/content/aboutDialog.css @@ -10,9 +10,15 @@ line-height: 1.5; } +#aboutDialog label, +#aboutDialog description { + text-align: center; +} + #rightBox { background-image: url("chrome://branding/content/about-wordmark.svg"); background-repeat: no-repeat; + background-position: center top; /* padding-top creates room for the wordmark */ padding-top: 38px; margin-top:20px; diff --git a/application/basilisk/base/content/aboutDialog.js b/browser/base/content/aboutDialog.js similarity index 100% rename from application/basilisk/base/content/aboutDialog.js rename to browser/base/content/aboutDialog.js diff --git a/application/basilisk/base/content/aboutDialog.xul b/browser/base/content/aboutDialog.xul similarity index 89% rename from application/basilisk/base/content/aboutDialog.xul rename to browser/base/content/aboutDialog.xul index 05d4bedd11..1b6e753cdc 100644 --- a/application/basilisk/base/content/aboutDialog.xul +++ b/browser/base/content/aboutDialog.xul @@ -42,16 +42,13 @@ #endif - - - + + + #ifdef HAVE_64BIT_BUILD #expand #else #expand -#endif -#ifndef NIGHTLY_BUILD - #endif @@ -141,13 +138,19 @@ #endif #else - - Dactyloidae is a custom browser, based on the best of Firefox. - Dactyloidae is designed and maintained by multiple open-source contributors (OwnedByWuigi, Eclipse Community, RT1), working together to make better software around the globe. - + Dactyloidae is released by . + + + + Dactyloidae is based on the work of the UXP team, aswell as the work of the Mozilla developers. + + + + Learn to this software. + - If you wish to contribute, please consider helping out by getting involved in our development by tackling some of the issues found in our . + If you wish to contribute, please consider helping out by getting involved in our development by tackling some of the issues found in our . #endif diff --git a/application/basilisk/base/content/aboutNetError.xhtml b/browser/base/content/aboutNetError.xhtml similarity index 100% rename from application/basilisk/base/content/aboutNetError.xhtml rename to browser/base/content/aboutNetError.xhtml diff --git a/application/basilisk/base/content/aboutRobots-icon.png b/browser/base/content/aboutRobots-icon.png similarity index 100% rename from application/basilisk/base/content/aboutRobots-icon.png rename to browser/base/content/aboutRobots-icon.png diff --git a/application/basilisk/base/content/aboutRobots-widget-left.png b/browser/base/content/aboutRobots-widget-left.png similarity index 100% rename from application/basilisk/base/content/aboutRobots-widget-left.png rename to browser/base/content/aboutRobots-widget-left.png diff --git a/application/basilisk/base/content/aboutRobots.xhtml b/browser/base/content/aboutRobots.xhtml similarity index 100% rename from application/basilisk/base/content/aboutRobots.xhtml rename to browser/base/content/aboutRobots.xhtml diff --git a/application/basilisk/base/content/aboutTabCrashed.css b/browser/base/content/aboutTabCrashed.css similarity index 100% rename from application/basilisk/base/content/aboutTabCrashed.css rename to browser/base/content/aboutTabCrashed.css diff --git a/application/basilisk/base/content/aboutTabCrashed.js b/browser/base/content/aboutTabCrashed.js similarity index 100% rename from application/basilisk/base/content/aboutTabCrashed.js rename to browser/base/content/aboutTabCrashed.js diff --git a/application/basilisk/base/content/aboutTabCrashed.xhtml b/browser/base/content/aboutTabCrashed.xhtml similarity index 100% rename from application/basilisk/base/content/aboutTabCrashed.xhtml rename to browser/base/content/aboutTabCrashed.xhtml diff --git a/application/basilisk/base/content/abouthealthreport/abouthealth.css b/browser/base/content/abouthealthreport/abouthealth.css similarity index 100% rename from application/basilisk/base/content/abouthealthreport/abouthealth.css rename to browser/base/content/abouthealthreport/abouthealth.css diff --git a/application/basilisk/base/content/abouthealthreport/abouthealth.js b/browser/base/content/abouthealthreport/abouthealth.js similarity index 100% rename from application/basilisk/base/content/abouthealthreport/abouthealth.js rename to browser/base/content/abouthealthreport/abouthealth.js diff --git a/application/basilisk/base/content/abouthealthreport/abouthealth.xhtml b/browser/base/content/abouthealthreport/abouthealth.xhtml similarity index 100% rename from application/basilisk/base/content/abouthealthreport/abouthealth.xhtml rename to browser/base/content/abouthealthreport/abouthealth.xhtml diff --git a/application/basilisk/base/content/abouthome/aboutHome.css b/browser/base/content/abouthome/aboutHome.css similarity index 100% rename from application/basilisk/base/content/abouthome/aboutHome.css rename to browser/base/content/abouthome/aboutHome.css diff --git a/application/basilisk/base/content/abouthome/aboutHome.js b/browser/base/content/abouthome/aboutHome.js similarity index 100% rename from application/basilisk/base/content/abouthome/aboutHome.js rename to browser/base/content/abouthome/aboutHome.js diff --git a/application/basilisk/base/content/abouthome/aboutHome.xhtml b/browser/base/content/abouthome/aboutHome.xhtml similarity index 100% rename from application/basilisk/base/content/abouthome/aboutHome.xhtml rename to browser/base/content/abouthome/aboutHome.xhtml diff --git a/application/basilisk/base/content/abouthome/addons.png b/browser/base/content/abouthome/addons.png similarity index 100% rename from application/basilisk/base/content/abouthome/addons.png rename to browser/base/content/abouthome/addons.png diff --git a/application/basilisk/base/content/abouthome/addons@2x.png b/browser/base/content/abouthome/addons@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/addons@2x.png rename to browser/base/content/abouthome/addons@2x.png diff --git a/application/basilisk/base/content/abouthome/bookmarks.png b/browser/base/content/abouthome/bookmarks.png similarity index 100% rename from application/basilisk/base/content/abouthome/bookmarks.png rename to browser/base/content/abouthome/bookmarks.png diff --git a/application/basilisk/base/content/abouthome/bookmarks@2x.png b/browser/base/content/abouthome/bookmarks@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/bookmarks@2x.png rename to browser/base/content/abouthome/bookmarks@2x.png diff --git a/application/basilisk/base/content/abouthome/downloads.png b/browser/base/content/abouthome/downloads.png similarity index 100% rename from application/basilisk/base/content/abouthome/downloads.png rename to browser/base/content/abouthome/downloads.png diff --git a/application/basilisk/base/content/abouthome/downloads@2x.png b/browser/base/content/abouthome/downloads@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/downloads@2x.png rename to browser/base/content/abouthome/downloads@2x.png diff --git a/application/basilisk/base/content/abouthome/history.png b/browser/base/content/abouthome/history.png similarity index 100% rename from application/basilisk/base/content/abouthome/history.png rename to browser/base/content/abouthome/history.png diff --git a/application/basilisk/base/content/abouthome/history@2x.png b/browser/base/content/abouthome/history@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/history@2x.png rename to browser/base/content/abouthome/history@2x.png diff --git a/application/basilisk/base/content/abouthome/mozilla.png b/browser/base/content/abouthome/mozilla.png similarity index 100% rename from application/basilisk/base/content/abouthome/mozilla.png rename to browser/base/content/abouthome/mozilla.png diff --git a/application/basilisk/base/content/abouthome/mozilla@2x.png b/browser/base/content/abouthome/mozilla@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/mozilla@2x.png rename to browser/base/content/abouthome/mozilla@2x.png diff --git a/application/basilisk/base/content/abouthome/restore-large.png b/browser/base/content/abouthome/restore-large.png similarity index 100% rename from application/basilisk/base/content/abouthome/restore-large.png rename to browser/base/content/abouthome/restore-large.png diff --git a/application/basilisk/base/content/abouthome/restore-large@2x.png b/browser/base/content/abouthome/restore-large@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/restore-large@2x.png rename to browser/base/content/abouthome/restore-large@2x.png diff --git a/application/basilisk/base/content/abouthome/restore.png b/browser/base/content/abouthome/restore.png similarity index 100% rename from application/basilisk/base/content/abouthome/restore.png rename to browser/base/content/abouthome/restore.png diff --git a/application/basilisk/base/content/abouthome/restore@2x.png b/browser/base/content/abouthome/restore@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/restore@2x.png rename to browser/base/content/abouthome/restore@2x.png diff --git a/application/basilisk/base/content/abouthome/settings.png b/browser/base/content/abouthome/settings.png similarity index 100% rename from application/basilisk/base/content/abouthome/settings.png rename to browser/base/content/abouthome/settings.png diff --git a/application/basilisk/base/content/abouthome/settings@2x.png b/browser/base/content/abouthome/settings@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/settings@2x.png rename to browser/base/content/abouthome/settings@2x.png diff --git a/application/basilisk/base/content/abouthome/snippet1.png b/browser/base/content/abouthome/snippet1.png similarity index 100% rename from application/basilisk/base/content/abouthome/snippet1.png rename to browser/base/content/abouthome/snippet1.png diff --git a/application/basilisk/base/content/abouthome/snippet1@2x.png b/browser/base/content/abouthome/snippet1@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/snippet1@2x.png rename to browser/base/content/abouthome/snippet1@2x.png diff --git a/application/basilisk/base/content/abouthome/snippet2.png b/browser/base/content/abouthome/snippet2.png similarity index 100% rename from application/basilisk/base/content/abouthome/snippet2.png rename to browser/base/content/abouthome/snippet2.png diff --git a/application/basilisk/base/content/abouthome/snippet2@2x.png b/browser/base/content/abouthome/snippet2@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/snippet2@2x.png rename to browser/base/content/abouthome/snippet2@2x.png diff --git a/application/basilisk/base/content/abouthome/sync.png b/browser/base/content/abouthome/sync.png similarity index 100% rename from application/basilisk/base/content/abouthome/sync.png rename to browser/base/content/abouthome/sync.png diff --git a/application/basilisk/base/content/abouthome/sync@2x.png b/browser/base/content/abouthome/sync@2x.png similarity index 100% rename from application/basilisk/base/content/abouthome/sync@2x.png rename to browser/base/content/abouthome/sync@2x.png diff --git a/application/basilisk/base/content/baseMenuOverlay.xul b/browser/base/content/baseMenuOverlay.xul similarity index 100% rename from application/basilisk/base/content/baseMenuOverlay.xul rename to browser/base/content/baseMenuOverlay.xul diff --git a/application/basilisk/base/content/browser-addons.js b/browser/base/content/browser-addons.js similarity index 100% rename from application/basilisk/base/content/browser-addons.js rename to browser/base/content/browser-addons.js diff --git a/application/basilisk/base/content/browser-captivePortal.js b/browser/base/content/browser-captivePortal.js similarity index 100% rename from application/basilisk/base/content/browser-captivePortal.js rename to browser/base/content/browser-captivePortal.js diff --git a/application/basilisk/base/content/browser-charsetmenu.inc b/browser/base/content/browser-charsetmenu.inc similarity index 100% rename from application/basilisk/base/content/browser-charsetmenu.inc rename to browser/base/content/browser-charsetmenu.inc diff --git a/application/basilisk/base/content/browser-context.inc b/browser/base/content/browser-context.inc similarity index 100% rename from application/basilisk/base/content/browser-context.inc rename to browser/base/content/browser-context.inc diff --git a/application/basilisk/base/content/browser-ctrlTab.js b/browser/base/content/browser-ctrlTab.js similarity index 100% rename from application/basilisk/base/content/browser-ctrlTab.js rename to browser/base/content/browser-ctrlTab.js diff --git a/application/basilisk/base/content/browser-customization.js b/browser/base/content/browser-customization.js similarity index 100% rename from application/basilisk/base/content/browser-customization.js rename to browser/base/content/browser-customization.js diff --git a/application/basilisk/base/content/browser-data-submission-info-bar.js b/browser/base/content/browser-data-submission-info-bar.js similarity index 100% rename from application/basilisk/base/content/browser-data-submission-info-bar.js rename to browser/base/content/browser-data-submission-info-bar.js diff --git a/application/basilisk/base/content/browser-doctype.inc b/browser/base/content/browser-doctype.inc similarity index 100% rename from application/basilisk/base/content/browser-doctype.inc rename to browser/base/content/browser-doctype.inc diff --git a/application/basilisk/base/content/browser-feeds.js b/browser/base/content/browser-feeds.js similarity index 100% rename from application/basilisk/base/content/browser-feeds.js rename to browser/base/content/browser-feeds.js diff --git a/application/basilisk/base/content/browser-fullScreenAndPointerLock.js b/browser/base/content/browser-fullScreenAndPointerLock.js similarity index 100% rename from application/basilisk/base/content/browser-fullScreenAndPointerLock.js rename to browser/base/content/browser-fullScreenAndPointerLock.js diff --git a/application/basilisk/base/content/browser-fullZoom.js b/browser/base/content/browser-fullZoom.js similarity index 100% rename from application/basilisk/base/content/browser-fullZoom.js rename to browser/base/content/browser-fullZoom.js diff --git a/application/basilisk/base/content/browser-gestureSupport.js b/browser/base/content/browser-gestureSupport.js similarity index 100% rename from application/basilisk/base/content/browser-gestureSupport.js rename to browser/base/content/browser-gestureSupport.js diff --git a/application/basilisk/base/content/browser-media.js b/browser/base/content/browser-media.js similarity index 100% rename from application/basilisk/base/content/browser-media.js rename to browser/base/content/browser-media.js diff --git a/application/basilisk/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc similarity index 100% rename from application/basilisk/base/content/browser-menubar.inc rename to browser/base/content/browser-menubar.inc diff --git a/application/basilisk/base/content/browser-places.js b/browser/base/content/browser-places.js similarity index 100% rename from application/basilisk/base/content/browser-places.js rename to browser/base/content/browser-places.js diff --git a/application/basilisk/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js similarity index 100% rename from application/basilisk/base/content/browser-plugins.js rename to browser/base/content/browser-plugins.js diff --git a/application/basilisk/base/content/browser-refreshblocker.js b/browser/base/content/browser-refreshblocker.js similarity index 100% rename from application/basilisk/base/content/browser-refreshblocker.js rename to browser/base/content/browser-refreshblocker.js diff --git a/application/basilisk/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc similarity index 100% rename from application/basilisk/base/content/browser-sets.inc rename to browser/base/content/browser-sets.inc diff --git a/application/basilisk/base/content/browser-sidebar.js b/browser/base/content/browser-sidebar.js similarity index 100% rename from application/basilisk/base/content/browser-sidebar.js rename to browser/base/content/browser-sidebar.js diff --git a/application/basilisk/base/content/browser-syncui.js b/browser/base/content/browser-syncui.js similarity index 100% rename from application/basilisk/base/content/browser-syncui.js rename to browser/base/content/browser-syncui.js diff --git a/application/basilisk/base/content/browser-tabPreviews.xml b/browser/base/content/browser-tabPreviews.xml similarity index 100% rename from application/basilisk/base/content/browser-tabPreviews.xml rename to browser/base/content/browser-tabPreviews.xml diff --git a/application/basilisk/base/content/browser-tabsintitlebar-stub.js b/browser/base/content/browser-tabsintitlebar-stub.js similarity index 100% rename from application/basilisk/base/content/browser-tabsintitlebar-stub.js rename to browser/base/content/browser-tabsintitlebar-stub.js diff --git a/application/basilisk/base/content/browser-tabsintitlebar.js b/browser/base/content/browser-tabsintitlebar.js similarity index 100% rename from application/basilisk/base/content/browser-tabsintitlebar.js rename to browser/base/content/browser-tabsintitlebar.js diff --git a/application/basilisk/base/content/browser-thumbnails.js b/browser/base/content/browser-thumbnails.js similarity index 100% rename from application/basilisk/base/content/browser-thumbnails.js rename to browser/base/content/browser-thumbnails.js diff --git a/application/basilisk/base/content/browser.css b/browser/base/content/browser.css similarity index 100% rename from application/basilisk/base/content/browser.css rename to browser/base/content/browser.css diff --git a/application/basilisk/base/content/browser.js b/browser/base/content/browser.js similarity index 100% rename from application/basilisk/base/content/browser.js rename to browser/base/content/browser.js diff --git a/application/basilisk/base/content/browser.xul b/browser/base/content/browser.xul similarity index 100% rename from application/basilisk/base/content/browser.xul rename to browser/base/content/browser.xul diff --git a/application/basilisk/base/content/browserMountPoints.inc b/browser/base/content/browserMountPoints.inc similarity index 100% rename from application/basilisk/base/content/browserMountPoints.inc rename to browser/base/content/browserMountPoints.inc diff --git a/application/basilisk/base/content/content.js b/browser/base/content/content.js similarity index 100% rename from application/basilisk/base/content/content.js rename to browser/base/content/content.js diff --git a/application/basilisk/base/content/contentSearchUI.css b/browser/base/content/contentSearchUI.css similarity index 100% rename from application/basilisk/base/content/contentSearchUI.css rename to browser/base/content/contentSearchUI.css diff --git a/application/basilisk/base/content/contentSearchUI.js b/browser/base/content/contentSearchUI.js similarity index 100% rename from application/basilisk/base/content/contentSearchUI.js rename to browser/base/content/contentSearchUI.js diff --git a/application/basilisk/base/content/defaultthemes/1.footer.jpg b/browser/base/content/defaultthemes/1.footer.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/1.footer.jpg rename to browser/base/content/defaultthemes/1.footer.jpg diff --git a/application/basilisk/base/content/defaultthemes/1.header.jpg b/browser/base/content/defaultthemes/1.header.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/1.header.jpg rename to browser/base/content/defaultthemes/1.header.jpg diff --git a/application/basilisk/base/content/defaultthemes/1.icon.jpg b/browser/base/content/defaultthemes/1.icon.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/1.icon.jpg rename to browser/base/content/defaultthemes/1.icon.jpg diff --git a/application/basilisk/base/content/defaultthemes/1.preview.jpg b/browser/base/content/defaultthemes/1.preview.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/1.preview.jpg rename to browser/base/content/defaultthemes/1.preview.jpg diff --git a/application/basilisk/base/content/defaultthemes/2.footer.jpg b/browser/base/content/defaultthemes/2.footer.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/2.footer.jpg rename to browser/base/content/defaultthemes/2.footer.jpg diff --git a/application/basilisk/base/content/defaultthemes/2.header.jpg b/browser/base/content/defaultthemes/2.header.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/2.header.jpg rename to browser/base/content/defaultthemes/2.header.jpg diff --git a/application/basilisk/base/content/defaultthemes/2.icon.jpg b/browser/base/content/defaultthemes/2.icon.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/2.icon.jpg rename to browser/base/content/defaultthemes/2.icon.jpg diff --git a/application/basilisk/base/content/defaultthemes/2.preview.jpg b/browser/base/content/defaultthemes/2.preview.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/2.preview.jpg rename to browser/base/content/defaultthemes/2.preview.jpg diff --git a/application/basilisk/base/content/defaultthemes/3.footer.png b/browser/base/content/defaultthemes/3.footer.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/3.footer.png rename to browser/base/content/defaultthemes/3.footer.png diff --git a/application/basilisk/base/content/defaultthemes/3.header.png b/browser/base/content/defaultthemes/3.header.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/3.header.png rename to browser/base/content/defaultthemes/3.header.png diff --git a/application/basilisk/base/content/defaultthemes/3.icon.png b/browser/base/content/defaultthemes/3.icon.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/3.icon.png rename to browser/base/content/defaultthemes/3.icon.png diff --git a/application/basilisk/base/content/defaultthemes/3.preview.png b/browser/base/content/defaultthemes/3.preview.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/3.preview.png rename to browser/base/content/defaultthemes/3.preview.png diff --git a/application/basilisk/base/content/defaultthemes/4.footer.png b/browser/base/content/defaultthemes/4.footer.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/4.footer.png rename to browser/base/content/defaultthemes/4.footer.png diff --git a/application/basilisk/base/content/defaultthemes/4.header.png b/browser/base/content/defaultthemes/4.header.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/4.header.png rename to browser/base/content/defaultthemes/4.header.png diff --git a/application/basilisk/base/content/defaultthemes/4.icon.png b/browser/base/content/defaultthemes/4.icon.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/4.icon.png rename to browser/base/content/defaultthemes/4.icon.png diff --git a/application/basilisk/base/content/defaultthemes/4.preview.png b/browser/base/content/defaultthemes/4.preview.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/4.preview.png rename to browser/base/content/defaultthemes/4.preview.png diff --git a/application/basilisk/base/content/defaultthemes/5.footer.png b/browser/base/content/defaultthemes/5.footer.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/5.footer.png rename to browser/base/content/defaultthemes/5.footer.png diff --git a/application/basilisk/base/content/defaultthemes/5.header.png b/browser/base/content/defaultthemes/5.header.png similarity index 100% rename from application/basilisk/base/content/defaultthemes/5.header.png rename to browser/base/content/defaultthemes/5.header.png diff --git a/application/basilisk/base/content/defaultthemes/5.icon.jpg b/browser/base/content/defaultthemes/5.icon.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/5.icon.jpg rename to browser/base/content/defaultthemes/5.icon.jpg diff --git a/application/basilisk/base/content/defaultthemes/5.preview.jpg b/browser/base/content/defaultthemes/5.preview.jpg similarity index 100% rename from application/basilisk/base/content/defaultthemes/5.preview.jpg rename to browser/base/content/defaultthemes/5.preview.jpg diff --git a/application/basilisk/base/content/docs/sslerrorreport/dataformat.rst b/browser/base/content/docs/sslerrorreport/dataformat.rst similarity index 100% rename from application/basilisk/base/content/docs/sslerrorreport/dataformat.rst rename to browser/base/content/docs/sslerrorreport/dataformat.rst diff --git a/application/basilisk/base/content/docs/sslerrorreport/index.rst b/browser/base/content/docs/sslerrorreport/index.rst similarity index 100% rename from application/basilisk/base/content/docs/sslerrorreport/index.rst rename to browser/base/content/docs/sslerrorreport/index.rst diff --git a/application/basilisk/base/content/downloadManagerOverlay.xul b/browser/base/content/downloadManagerOverlay.xul similarity index 100% rename from application/basilisk/base/content/downloadManagerOverlay.xul rename to browser/base/content/downloadManagerOverlay.xul diff --git a/application/basilisk/base/content/gcli_sec_bad.svg b/browser/base/content/gcli_sec_bad.svg similarity index 100% rename from application/basilisk/base/content/gcli_sec_bad.svg rename to browser/base/content/gcli_sec_bad.svg diff --git a/application/basilisk/base/content/gcli_sec_good.svg b/browser/base/content/gcli_sec_good.svg similarity index 100% rename from application/basilisk/base/content/gcli_sec_good.svg rename to browser/base/content/gcli_sec_good.svg diff --git a/application/basilisk/base/content/gcli_sec_moderate.svg b/browser/base/content/gcli_sec_moderate.svg similarity index 100% rename from application/basilisk/base/content/gcli_sec_moderate.svg rename to browser/base/content/gcli_sec_moderate.svg diff --git a/application/basilisk/base/content/global-scripts.inc b/browser/base/content/global-scripts.inc similarity index 100% rename from application/basilisk/base/content/global-scripts.inc rename to browser/base/content/global-scripts.inc diff --git a/application/basilisk/base/content/hiddenWindow.xul b/browser/base/content/hiddenWindow.xul similarity index 100% rename from application/basilisk/base/content/hiddenWindow.xul rename to browser/base/content/hiddenWindow.xul diff --git a/application/basilisk/base/content/jsConsoleOverlay.xul b/browser/base/content/jsConsoleOverlay.xul similarity index 100% rename from application/basilisk/base/content/jsConsoleOverlay.xul rename to browser/base/content/jsConsoleOverlay.xul diff --git a/application/basilisk/base/content/macBrowserOverlay.xul b/browser/base/content/macBrowserOverlay.xul similarity index 100% rename from application/basilisk/base/content/macBrowserOverlay.xul rename to browser/base/content/macBrowserOverlay.xul diff --git a/application/basilisk/base/content/newtab/cells.js b/browser/base/content/newtab/cells.js similarity index 100% rename from application/basilisk/base/content/newtab/cells.js rename to browser/base/content/newtab/cells.js diff --git a/application/basilisk/base/content/newtab/customize.js b/browser/base/content/newtab/customize.js similarity index 100% rename from application/basilisk/base/content/newtab/customize.js rename to browser/base/content/newtab/customize.js diff --git a/application/basilisk/base/content/newtab/drag.js b/browser/base/content/newtab/drag.js similarity index 100% rename from application/basilisk/base/content/newtab/drag.js rename to browser/base/content/newtab/drag.js diff --git a/application/basilisk/base/content/newtab/dragDataHelper.js b/browser/base/content/newtab/dragDataHelper.js similarity index 100% rename from application/basilisk/base/content/newtab/dragDataHelper.js rename to browser/base/content/newtab/dragDataHelper.js diff --git a/application/basilisk/base/content/newtab/drop.js b/browser/base/content/newtab/drop.js similarity index 100% rename from application/basilisk/base/content/newtab/drop.js rename to browser/base/content/newtab/drop.js diff --git a/application/basilisk/base/content/newtab/dropPreview.js b/browser/base/content/newtab/dropPreview.js similarity index 100% rename from application/basilisk/base/content/newtab/dropPreview.js rename to browser/base/content/newtab/dropPreview.js diff --git a/application/basilisk/base/content/newtab/dropTargetShim.js b/browser/base/content/newtab/dropTargetShim.js similarity index 100% rename from application/basilisk/base/content/newtab/dropTargetShim.js rename to browser/base/content/newtab/dropTargetShim.js diff --git a/application/basilisk/base/content/newtab/grid.js b/browser/base/content/newtab/grid.js similarity index 100% rename from application/basilisk/base/content/newtab/grid.js rename to browser/base/content/newtab/grid.js diff --git a/application/basilisk/base/content/newtab/newTab.css b/browser/base/content/newtab/newTab.css similarity index 100% rename from application/basilisk/base/content/newtab/newTab.css rename to browser/base/content/newtab/newTab.css diff --git a/application/basilisk/base/content/newtab/newTab.js b/browser/base/content/newtab/newTab.js similarity index 100% rename from application/basilisk/base/content/newtab/newTab.js rename to browser/base/content/newtab/newTab.js diff --git a/application/basilisk/base/content/newtab/newTab.xhtml b/browser/base/content/newtab/newTab.xhtml similarity index 100% rename from application/basilisk/base/content/newtab/newTab.xhtml rename to browser/base/content/newtab/newTab.xhtml diff --git a/application/basilisk/base/content/newtab/page.js b/browser/base/content/newtab/page.js similarity index 100% rename from application/basilisk/base/content/newtab/page.js rename to browser/base/content/newtab/page.js diff --git a/application/basilisk/base/content/newtab/search.js b/browser/base/content/newtab/search.js similarity index 100% rename from application/basilisk/base/content/newtab/search.js rename to browser/base/content/newtab/search.js diff --git a/application/basilisk/base/content/newtab/sites.js b/browser/base/content/newtab/sites.js similarity index 100% rename from application/basilisk/base/content/newtab/sites.js rename to browser/base/content/newtab/sites.js diff --git a/application/basilisk/base/content/newtab/transformations.js b/browser/base/content/newtab/transformations.js similarity index 100% rename from application/basilisk/base/content/newtab/transformations.js rename to browser/base/content/newtab/transformations.js diff --git a/application/basilisk/base/content/newtab/undo.js b/browser/base/content/newtab/undo.js similarity index 100% rename from application/basilisk/base/content/newtab/undo.js rename to browser/base/content/newtab/undo.js diff --git a/application/basilisk/base/content/newtab/updater.js b/browser/base/content/newtab/updater.js similarity index 100% rename from application/basilisk/base/content/newtab/updater.js rename to browser/base/content/newtab/updater.js diff --git a/application/basilisk/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js similarity index 100% rename from application/basilisk/base/content/nsContextMenu.js rename to browser/base/content/nsContextMenu.js diff --git a/application/basilisk/base/content/overrides/app-license.html b/browser/base/content/overrides/app-license.html similarity index 100% rename from application/basilisk/base/content/overrides/app-license.html rename to browser/base/content/overrides/app-license.html diff --git a/application/basilisk/base/content/pageinfo/feeds.js b/browser/base/content/pageinfo/feeds.js similarity index 100% rename from application/basilisk/base/content/pageinfo/feeds.js rename to browser/base/content/pageinfo/feeds.js diff --git a/application/basilisk/base/content/pageinfo/feeds.xml b/browser/base/content/pageinfo/feeds.xml similarity index 100% rename from application/basilisk/base/content/pageinfo/feeds.xml rename to browser/base/content/pageinfo/feeds.xml diff --git a/application/basilisk/base/content/pageinfo/pageInfo.css b/browser/base/content/pageinfo/pageInfo.css similarity index 100% rename from application/basilisk/base/content/pageinfo/pageInfo.css rename to browser/base/content/pageinfo/pageInfo.css diff --git a/application/basilisk/base/content/pageinfo/pageInfo.js b/browser/base/content/pageinfo/pageInfo.js similarity index 100% rename from application/basilisk/base/content/pageinfo/pageInfo.js rename to browser/base/content/pageinfo/pageInfo.js diff --git a/application/basilisk/base/content/pageinfo/pageInfo.xml b/browser/base/content/pageinfo/pageInfo.xml similarity index 100% rename from application/basilisk/base/content/pageinfo/pageInfo.xml rename to browser/base/content/pageinfo/pageInfo.xml diff --git a/application/basilisk/base/content/pageinfo/pageInfo.xul b/browser/base/content/pageinfo/pageInfo.xul similarity index 100% rename from application/basilisk/base/content/pageinfo/pageInfo.xul rename to browser/base/content/pageinfo/pageInfo.xul diff --git a/application/basilisk/base/content/pageinfo/permissions.js b/browser/base/content/pageinfo/permissions.js similarity index 100% rename from application/basilisk/base/content/pageinfo/permissions.js rename to browser/base/content/pageinfo/permissions.js diff --git a/application/basilisk/base/content/pageinfo/security.js b/browser/base/content/pageinfo/security.js similarity index 100% rename from application/basilisk/base/content/pageinfo/security.js rename to browser/base/content/pageinfo/security.js diff --git a/application/basilisk/base/content/popup-notifications.inc b/browser/base/content/popup-notifications.inc similarity index 100% rename from application/basilisk/base/content/popup-notifications.inc rename to browser/base/content/popup-notifications.inc diff --git a/application/basilisk/base/content/safeMode.css b/browser/base/content/safeMode.css similarity index 100% rename from application/basilisk/base/content/safeMode.css rename to browser/base/content/safeMode.css diff --git a/application/basilisk/base/content/safeMode.js b/browser/base/content/safeMode.js similarity index 100% rename from application/basilisk/base/content/safeMode.js rename to browser/base/content/safeMode.js diff --git a/application/basilisk/base/content/safeMode.xul b/browser/base/content/safeMode.xul similarity index 100% rename from application/basilisk/base/content/safeMode.xul rename to browser/base/content/safeMode.xul diff --git a/application/basilisk/base/content/sanitize.js b/browser/base/content/sanitize.js similarity index 100% rename from application/basilisk/base/content/sanitize.js rename to browser/base/content/sanitize.js diff --git a/application/basilisk/base/content/sanitize.xul b/browser/base/content/sanitize.xul similarity index 100% rename from application/basilisk/base/content/sanitize.xul rename to browser/base/content/sanitize.xul diff --git a/application/basilisk/base/content/sanitizeDialog.css b/browser/base/content/sanitizeDialog.css similarity index 100% rename from application/basilisk/base/content/sanitizeDialog.css rename to browser/base/content/sanitizeDialog.css diff --git a/application/basilisk/base/content/sanitizeDialog.js b/browser/base/content/sanitizeDialog.js similarity index 100% rename from application/basilisk/base/content/sanitizeDialog.js rename to browser/base/content/sanitizeDialog.js diff --git a/application/basilisk/base/content/softwareUpdateOverlay.xul b/browser/base/content/softwareUpdateOverlay.xul similarity index 100% rename from application/basilisk/base/content/softwareUpdateOverlay.xul rename to browser/base/content/softwareUpdateOverlay.xul diff --git a/application/basilisk/base/content/tab-content.js b/browser/base/content/tab-content.js similarity index 100% rename from application/basilisk/base/content/tab-content.js rename to browser/base/content/tab-content.js diff --git a/application/basilisk/base/content/tab-shape.inc.svg b/browser/base/content/tab-shape.inc.svg similarity index 100% rename from application/basilisk/base/content/tab-shape.inc.svg rename to browser/base/content/tab-shape.inc.svg diff --git a/application/basilisk/base/content/tabbrowser.css b/browser/base/content/tabbrowser.css similarity index 100% rename from application/basilisk/base/content/tabbrowser.css rename to browser/base/content/tabbrowser.css diff --git a/application/basilisk/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml similarity index 100% rename from application/basilisk/base/content/tabbrowser.xml rename to browser/base/content/tabbrowser.xml diff --git a/application/basilisk/base/content/themeManager.js b/browser/base/content/themeManager.js similarity index 100% rename from application/basilisk/base/content/themeManager.js rename to browser/base/content/themeManager.js diff --git a/application/basilisk/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml similarity index 100% rename from application/basilisk/base/content/urlbarBindings.xml rename to browser/base/content/urlbarBindings.xml diff --git a/application/basilisk/base/content/usercontext.svg b/browser/base/content/usercontext.svg similarity index 100% rename from application/basilisk/base/content/usercontext.svg rename to browser/base/content/usercontext.svg diff --git a/application/basilisk/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js similarity index 100% rename from application/basilisk/base/content/utilityOverlay.js rename to browser/base/content/utilityOverlay.js diff --git a/application/basilisk/base/content/viewSourceOverlay.xul b/browser/base/content/viewSourceOverlay.xul similarity index 100% rename from application/basilisk/base/content/viewSourceOverlay.xul rename to browser/base/content/viewSourceOverlay.xul diff --git a/application/basilisk/base/content/web-panels.js b/browser/base/content/web-panels.js similarity index 100% rename from application/basilisk/base/content/web-panels.js rename to browser/base/content/web-panels.js diff --git a/application/basilisk/base/content/web-panels.xul b/browser/base/content/web-panels.xul similarity index 100% rename from application/basilisk/base/content/web-panels.xul rename to browser/base/content/web-panels.xul diff --git a/application/basilisk/base/content/webrtcIndicator.js b/browser/base/content/webrtcIndicator.js similarity index 100% rename from application/basilisk/base/content/webrtcIndicator.js rename to browser/base/content/webrtcIndicator.js diff --git a/application/basilisk/base/content/webrtcIndicator.xul b/browser/base/content/webrtcIndicator.xul similarity index 100% rename from application/basilisk/base/content/webrtcIndicator.xul rename to browser/base/content/webrtcIndicator.xul diff --git a/application/basilisk/base/content/win6BrowserOverlay.xul b/browser/base/content/win6BrowserOverlay.xul similarity index 100% rename from application/basilisk/base/content/win6BrowserOverlay.xul rename to browser/base/content/win6BrowserOverlay.xul diff --git a/application/basilisk/base/jar.mn b/browser/base/jar.mn similarity index 100% rename from application/basilisk/base/jar.mn rename to browser/base/jar.mn diff --git a/application/basilisk/base/moz.build b/browser/base/moz.build similarity index 100% rename from application/basilisk/base/moz.build rename to browser/base/moz.build diff --git a/application/basilisk/branding/shared/branding.mozbuild b/browser/branding/shared/branding.mozbuild similarity index 100% rename from application/basilisk/branding/shared/branding.mozbuild rename to browser/branding/shared/branding.mozbuild diff --git a/application/basilisk/branding/shared/dsstore b/browser/branding/shared/dsstore similarity index 100% rename from application/basilisk/branding/shared/dsstore rename to browser/branding/shared/dsstore diff --git a/application/basilisk/branding/shared/newtab.ico b/browser/branding/shared/newtab.ico similarity index 100% rename from application/basilisk/branding/shared/newtab.ico rename to browser/branding/shared/newtab.ico diff --git a/application/basilisk/branding/shared/newwindow.ico b/browser/branding/shared/newwindow.ico similarity index 100% rename from application/basilisk/branding/shared/newwindow.ico rename to browser/branding/shared/newwindow.ico diff --git a/application/basilisk/branding/shared/pbmode.ico b/browser/branding/shared/pbmode.ico similarity index 100% rename from application/basilisk/branding/shared/pbmode.ico rename to browser/branding/shared/pbmode.ico diff --git a/application/basilisk/branding/shared/preferences.inc b/browser/branding/shared/preferences.inc similarity index 100% rename from application/basilisk/branding/shared/preferences.inc rename to browser/branding/shared/preferences.inc diff --git a/application/basilisk/branding/unofficial/LICENSE b/browser/branding/unofficial/LICENSE similarity index 100% rename from application/basilisk/branding/unofficial/LICENSE rename to browser/branding/unofficial/LICENSE diff --git a/application/basilisk/branding/official/VisualElements_150.png b/browser/branding/unofficial/VisualElements_150.png similarity index 100% rename from application/basilisk/branding/official/VisualElements_150.png rename to browser/branding/unofficial/VisualElements_150.png diff --git a/application/basilisk/branding/official/VisualElements_70.png b/browser/branding/unofficial/VisualElements_70.png similarity index 100% rename from application/basilisk/branding/official/VisualElements_70.png rename to browser/branding/unofficial/VisualElements_70.png diff --git a/application/basilisk/branding/official/appname.bmp b/browser/branding/unofficial/appname.bmp similarity index 100% rename from application/basilisk/branding/official/appname.bmp rename to browser/branding/unofficial/appname.bmp diff --git a/application/basilisk/branding/official/background.png b/browser/branding/unofficial/background.png similarity index 100% rename from application/basilisk/branding/official/background.png rename to browser/branding/unofficial/background.png diff --git a/application/basilisk/branding/unofficial/branding.nsi b/browser/branding/unofficial/branding.nsi similarity index 93% rename from application/basilisk/branding/unofficial/branding.nsi rename to browser/branding/unofficial/branding.nsi index 0fffc53372..842fae86c7 100644 --- a/application/basilisk/branding/unofficial/branding.nsi +++ b/browser/branding/unofficial/branding.nsi @@ -9,7 +9,7 @@ # BrandFullNameInternal is used for some registry and file system values # instead of BrandFullName and typically should not be modified. !define BrandFullNameInternal "Dactyloidae" -!define CompanyName "OwnedByWuigi" +!define CompanyName "Eclipse Community" !define URLInfoAbout "about:blank" !define URLUpdateInfo "about:blank" !define HelpLink "about:blank" diff --git a/application/basilisk/branding/unofficial/configure.sh b/browser/branding/unofficial/configure.sh similarity index 68% rename from application/basilisk/branding/unofficial/configure.sh rename to browser/branding/unofficial/configure.sh index bd579e6834..415c26427a 100644 --- a/application/basilisk/branding/unofficial/configure.sh +++ b/browser/branding/unofficial/configure.sh @@ -10,13 +10,13 @@ MOZ_APP_DISPLAYNAME="Dactyloidae" MOZ_APP_UA_NAME="Dactyloidae" -MOZ_APP_VENDOR="OwnedByWuigi" +MOZ_APP_VENDOR="Eclipse Community" MOZ_APP_FULLNAME="Dactyloidae" -MOZ_APP_PROFILE="OwnedByWuigi/Dactyloidae" +MOZ_APP_PROFILE="Eclipse Community/Dactyloidae" -MOZ_APP_REMOTINGNAME=com.OwnedByWuigi.Dactyloidae +MOZ_APP_REMOTINGNAME=com.Eclipse Community.Dactyloidae MOZ_DISTRIBUTION_ID=com.opensource diff --git a/browser/branding/unofficial/content/about-background.png b/browser/branding/unofficial/content/about-background.png new file mode 100644 index 0000000000..e7298b8754 Binary files /dev/null and b/browser/branding/unofficial/content/about-background.png differ diff --git a/application/basilisk/branding/official/content/about-logo.png b/browser/branding/unofficial/content/about-logo.png similarity index 100% rename from application/basilisk/branding/official/content/about-logo.png rename to browser/branding/unofficial/content/about-logo.png diff --git a/application/basilisk/branding/official/content/about-logo@2x.png b/browser/branding/unofficial/content/about-logo@2x.png similarity index 100% rename from application/basilisk/branding/official/content/about-logo@2x.png rename to browser/branding/unofficial/content/about-logo@2x.png diff --git a/application/basilisk/branding/unofficial/content/about-wordmark.svg b/browser/branding/unofficial/content/about-wordmark.svg similarity index 100% rename from application/basilisk/branding/unofficial/content/about-wordmark.svg rename to browser/branding/unofficial/content/about-wordmark.svg diff --git a/application/basilisk/branding/official/content/about.png b/browser/branding/unofficial/content/about.png similarity index 100% rename from application/basilisk/branding/official/content/about.png rename to browser/branding/unofficial/content/about.png diff --git a/application/basilisk/branding/unofficial/content/aboutDialog.css b/browser/branding/unofficial/content/aboutDialog.css similarity index 74% rename from application/basilisk/branding/unofficial/content/aboutDialog.css rename to browser/branding/unofficial/content/aboutDialog.css index dfecb8de23..11ae7c6d96 100644 --- a/application/basilisk/branding/unofficial/content/aboutDialog.css +++ b/browser/branding/unofficial/content/aboutDialog.css @@ -5,19 +5,28 @@ #aboutDialogContainer { background-image: url("chrome://branding/content/about-background.png"); background-repeat: no-repeat; + background-position: center top; background-color: rgb(10,17,37); color: #fff; } +#clientBox { + -moz-box-pack: center; +} + +#leftBox { + visibility: collapse; +} + .text-link { color: #fff !important; text-decoration: underline; } #rightBox { - /* this margin prevents text from overlapping the planet image */ - margin-left: 180px; - margin-right: 20px; + -moz-box-flex: 1 !important; + margin-left: 0; + margin-right: 0; } #bottomBox { diff --git a/application/basilisk/branding/official/content/icon48.png b/browser/branding/unofficial/content/icon48.png similarity index 100% rename from application/basilisk/branding/official/content/icon48.png rename to browser/branding/unofficial/content/icon48.png diff --git a/application/basilisk/branding/official/content/icon64.png b/browser/branding/unofficial/content/icon64.png similarity index 100% rename from application/basilisk/branding/official/content/icon64.png rename to browser/branding/unofficial/content/icon64.png diff --git a/application/basilisk/branding/official/content/identity-icons-brand.svg b/browser/branding/unofficial/content/identity-icons-brand.svg similarity index 100% rename from application/basilisk/branding/official/content/identity-icons-brand.svg rename to browser/branding/unofficial/content/identity-icons-brand.svg diff --git a/application/basilisk/branding/unofficial/content/jar.mn b/browser/branding/unofficial/content/jar.mn similarity index 100% rename from application/basilisk/branding/unofficial/content/jar.mn rename to browser/branding/unofficial/content/jar.mn diff --git a/application/basilisk/branding/official/content/moz.build b/browser/branding/unofficial/content/moz.build similarity index 100% rename from application/basilisk/branding/official/content/moz.build rename to browser/branding/unofficial/content/moz.build diff --git a/application/basilisk/branding/official/content/silhouette-40.svg b/browser/branding/unofficial/content/silhouette-40.svg similarity index 100% rename from application/basilisk/branding/official/content/silhouette-40.svg rename to browser/branding/unofficial/content/silhouette-40.svg diff --git a/application/basilisk/branding/unofficial/dactyloidae.VisualElementsManifest.xml b/browser/branding/unofficial/dactyloidae.VisualElementsManifest.xml similarity index 100% rename from application/basilisk/branding/unofficial/dactyloidae.VisualElementsManifest.xml rename to browser/branding/unofficial/dactyloidae.VisualElementsManifest.xml diff --git a/application/basilisk/branding/official/default16.png b/browser/branding/unofficial/default16.png similarity index 100% rename from application/basilisk/branding/official/default16.png rename to browser/branding/unofficial/default16.png diff --git a/application/basilisk/branding/official/default32.png b/browser/branding/unofficial/default32.png similarity index 100% rename from application/basilisk/branding/official/default32.png rename to browser/branding/unofficial/default32.png diff --git a/application/basilisk/branding/official/default48.png b/browser/branding/unofficial/default48.png similarity index 100% rename from application/basilisk/branding/official/default48.png rename to browser/branding/unofficial/default48.png diff --git a/application/basilisk/branding/unofficial/disk.icns b/browser/branding/unofficial/disk.icns similarity index 100% rename from application/basilisk/branding/unofficial/disk.icns rename to browser/branding/unofficial/disk.icns diff --git a/application/basilisk/branding/official/document.icns b/browser/branding/unofficial/document.icns similarity index 100% rename from application/basilisk/branding/official/document.icns rename to browser/branding/unofficial/document.icns diff --git a/application/basilisk/branding/unofficial/document.ico b/browser/branding/unofficial/document.ico similarity index 100% rename from application/basilisk/branding/unofficial/document.ico rename to browser/branding/unofficial/document.ico diff --git a/application/basilisk/branding/unofficial/dsstore b/browser/branding/unofficial/dsstore similarity index 100% rename from application/basilisk/branding/unofficial/dsstore rename to browser/branding/unofficial/dsstore diff --git a/application/basilisk/branding/unofficial/firefox.icns b/browser/branding/unofficial/firefox.icns similarity index 100% rename from application/basilisk/branding/unofficial/firefox.icns rename to browser/branding/unofficial/firefox.icns diff --git a/application/basilisk/branding/unofficial/firefox.ico b/browser/branding/unofficial/firefox.ico similarity index 100% rename from application/basilisk/branding/unofficial/firefox.ico rename to browser/branding/unofficial/firefox.ico diff --git a/application/basilisk/branding/official/locales/browserconfig.properties b/browser/branding/unofficial/locales/browserconfig.properties similarity index 100% rename from application/basilisk/branding/official/locales/browserconfig.properties rename to browser/branding/unofficial/locales/browserconfig.properties diff --git a/application/basilisk/branding/unofficial/locales/en-US/brand.dtd b/browser/branding/unofficial/locales/en-US/brand.dtd similarity index 62% rename from application/basilisk/branding/unofficial/locales/en-US/brand.dtd rename to browser/branding/unofficial/locales/en-US/brand.dtd index c1ccfcefef..6fecd5019e 100644 --- a/application/basilisk/branding/unofficial/locales/en-US/brand.dtd +++ b/browser/branding/unofficial/locales/en-US/brand.dtd @@ -5,6 +5,6 @@ - - - + + + diff --git a/application/basilisk/branding/unofficial/locales/en-US/brand.properties b/browser/branding/unofficial/locales/en-US/brand.properties similarity index 82% rename from application/basilisk/branding/unofficial/locales/en-US/brand.properties rename to browser/branding/unofficial/locales/en-US/brand.properties index d71b963a30..988e717462 100644 --- a/application/basilisk/branding/unofficial/locales/en-US/brand.properties +++ b/browser/branding/unofficial/locales/en-US/brand.properties @@ -5,7 +5,7 @@ brandShorterName=Dactyloidae brandShortName=Dactyloidae brandFullName=Dactyloidae -vendorShortName=OwnedByWuigi -vendorFullName=OwnedByWuigi +vendorShortName=Eclipse Community +vendorFullName=Eclipse Community syncBrandShortName=Sync diff --git a/application/basilisk/branding/unofficial/locales/jar.mn b/browser/branding/unofficial/locales/jar.mn similarity index 100% rename from application/basilisk/branding/unofficial/locales/jar.mn rename to browser/branding/unofficial/locales/jar.mn diff --git a/application/basilisk/branding/unofficial/locales/moz.build b/browser/branding/unofficial/locales/moz.build similarity index 100% rename from application/basilisk/branding/unofficial/locales/moz.build rename to browser/branding/unofficial/locales/moz.build diff --git a/application/basilisk/branding/unofficial/moz.build b/browser/branding/unofficial/moz.build similarity index 100% rename from application/basilisk/branding/unofficial/moz.build rename to browser/branding/unofficial/moz.build diff --git a/application/basilisk/branding/official/mozicon128.png b/browser/branding/unofficial/mozicon128.png similarity index 100% rename from application/basilisk/branding/official/mozicon128.png rename to browser/branding/unofficial/mozicon128.png diff --git a/application/basilisk/branding/unofficial/pref/basilisk-branding.js b/browser/branding/unofficial/pref/basilisk-branding.js similarity index 95% rename from application/basilisk/branding/unofficial/pref/basilisk-branding.js rename to browser/branding/unofficial/pref/basilisk-branding.js index efa4c104ae..1dabca672f 100644 --- a/application/basilisk/branding/unofficial/pref/basilisk-branding.js +++ b/browser/branding/unofficial/pref/basilisk-branding.js @@ -39,5 +39,5 @@ pref("general.useragent.compatMode.gecko",true); // Switch Application Updates off for unofficial branding pref("app.update.enabled", false); -// Shared User Agent Overrides -#include ../../shared/uaoverrides.inc +// User Agent Overrides +#include uaoverrides.inc diff --git a/application/basilisk/branding/shared/uaoverrides.inc b/browser/branding/unofficial/pref/uaoverrides.inc similarity index 92% rename from application/basilisk/branding/shared/uaoverrides.inc rename to browser/branding/unofficial/pref/uaoverrides.inc index 2df32a6ff5..e2659ecbe1 100644 --- a/application/basilisk/branding/shared/uaoverrides.inc +++ b/browser/branding/unofficial/pref/uaoverrides.inc @@ -9,7 +9,7 @@ #define GK_SLICE Gecko/20100101 #define FX_SLICE Firefox/@GK_VERSION@ -#define PALE_MOON_VERSION 34.2.0 +#define PALE_MOON_VERSION 34.3.1 #define PALE_MOON_SLICE PaleMoon/@PALE_MOON_VERSION@ // %OS_SLICE% macro is resolved at runtime, see MoonchildProductions/UXP/issues/1473 @@ -67,8 +67,7 @@ pref("@GUAO_PREF@.mewe.com", "Mozilla/5.0 (%OS_SLICE% rv:102.0) Gecko/20100101 F pref("@GUAO_PREF@.web.whatsapp.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36"); pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0"); pref("@GUAO_PREF@.studio.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0"); -pref("@GUAO_PREF@.gaming.youtube.com", "Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0"); -pref("@GUAO_PREF@.yeezy.com", "Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0"); +pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0"); // The following domains do not like the Goanna slice pref("@GUAO_PREF@.bab.la","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@"); @@ -88,4 +87,8 @@ pref("@GUAO_PREF@.apple.com","Mozilla/5.0 (%OS_SLICE% rv:128.0) @GK_SLICE@ Firef pref("@GUAO_PREF@.addons.palemoon.org","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ @UXP_VERSION_SLICE@ @FX_SLICE@ @PALE_MOON_SLICE@"); // Same goes for upstream Firefox addons on the Mozilla addons site since this fork has (some) WebExtensions support now pref("@GUAO_PREF@.addons.mozilla.org", "Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0"); +// (WIP) Chrome Web Store addons support - report as Chrome +pref("@GUAO_PREF@.chromewebstore.google.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36"); +// (WIP) Edge Addons store addons support - report as MS Edge (new) +pref("@GUAO_PREF@.microsoftedge..microsoft.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Edg/149.0.0.0 Safari/537.36"); // ============================================================================ diff --git a/application/basilisk/branding/unofficial/serpent.desktop b/browser/branding/unofficial/serpent.desktop similarity index 100% rename from application/basilisk/branding/unofficial/serpent.desktop rename to browser/branding/unofficial/serpent.desktop diff --git a/application/basilisk/branding/unofficial/wizHeader.bmp b/browser/branding/unofficial/wizHeader.bmp similarity index 100% rename from application/basilisk/branding/unofficial/wizHeader.bmp rename to browser/branding/unofficial/wizHeader.bmp diff --git a/application/basilisk/branding/official/wizHeaderRTL.bmp b/browser/branding/unofficial/wizHeaderRTL.bmp similarity index 100% rename from application/basilisk/branding/official/wizHeaderRTL.bmp rename to browser/branding/unofficial/wizHeaderRTL.bmp diff --git a/application/basilisk/branding/unofficial/wizWatermark.bmp b/browser/branding/unofficial/wizWatermark.bmp similarity index 100% rename from application/basilisk/branding/unofficial/wizWatermark.bmp rename to browser/branding/unofficial/wizWatermark.bmp diff --git a/browser/build.mk b/browser/build.mk new file mode 100644 index 0000000000..df52f1eaf7 --- /dev/null +++ b/browser/build.mk @@ -0,0 +1,61 @@ +# 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/. + +installer: + @$(MAKE) -C browser/installer installer + +package: + @$(MAKE) -C browser/installer make-archive + +l10n-package: + @$(MAKE) -C browser/installer make-langpack + +mozpackage: + @$(MAKE) -C browser/installer + +package-compare: + @$(MAKE) -C browser/installer package-compare + +stage-package: + @$(MAKE) -C browser/installer stage-package make-buildinfo-file + +sdk: + @$(MAKE) -C browser/installer make-sdk + +install:: + @$(MAKE) -C browser/installer install + +clean:: + @$(MAKE) -C browser/installer clean + +distclean:: + @$(MAKE) -C browser/installer distclean + +source-package:: + @$(MAKE) -C browser/installer source-package + +upload:: + @$(MAKE) -C browser/installer upload + +source-upload:: + @$(MAKE) -C browser/installer source-upload + +hg-bundle:: + @$(MAKE) -C browser/installer hg-bundle + +l10n-check:: + @$(MAKE) -C browser/locales l10n-check + +ifdef ENABLE_TESTS +# Implemented in testing/testsuite-targets.mk + +mochitest-browser-chrome: + $(RUN_MOCHITEST) --flavor=browser + $(CHECK_TEST_ERROR) + +mochitest:: mochitest-browser-chrome + +.PHONY: mochitest-browser-chrome + +endif diff --git a/application/basilisk/components/BrowserComponents.manifest b/browser/components/BrowserComponents.manifest similarity index 100% rename from application/basilisk/components/BrowserComponents.manifest rename to browser/components/BrowserComponents.manifest diff --git a/application/basilisk/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp similarity index 100% rename from application/basilisk/components/about/AboutRedirector.cpp rename to browser/components/about/AboutRedirector.cpp diff --git a/application/basilisk/components/about/AboutRedirector.h b/browser/components/about/AboutRedirector.h similarity index 100% rename from application/basilisk/components/about/AboutRedirector.h rename to browser/components/about/AboutRedirector.h diff --git a/application/basilisk/components/about/moz.build b/browser/components/about/moz.build similarity index 100% rename from application/basilisk/components/about/moz.build rename to browser/components/about/moz.build diff --git a/application/basilisk/components/build/Makefile.in b/browser/components/build/Makefile.in similarity index 100% rename from application/basilisk/components/build/Makefile.in rename to browser/components/build/Makefile.in diff --git a/application/basilisk/components/build/moz.build b/browser/components/build/moz.build similarity index 100% rename from application/basilisk/components/build/moz.build rename to browser/components/build/moz.build diff --git a/application/basilisk/components/build/nsBrowserCompsCID.h b/browser/components/build/nsBrowserCompsCID.h similarity index 100% rename from application/basilisk/components/build/nsBrowserCompsCID.h rename to browser/components/build/nsBrowserCompsCID.h diff --git a/application/basilisk/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp similarity index 100% rename from application/basilisk/components/build/nsModule.cpp rename to browser/components/build/nsModule.cpp diff --git a/application/basilisk/components/contextualidentity/content/usercontext.css b/browser/components/contextualidentity/content/usercontext.css similarity index 100% rename from application/basilisk/components/contextualidentity/content/usercontext.css rename to browser/components/contextualidentity/content/usercontext.css diff --git a/application/basilisk/components/contextualidentity/jar.mn b/browser/components/contextualidentity/jar.mn similarity index 100% rename from application/basilisk/components/contextualidentity/jar.mn rename to browser/components/contextualidentity/jar.mn diff --git a/application/basilisk/components/contextualidentity/moz.build b/browser/components/contextualidentity/moz.build similarity index 100% rename from application/basilisk/components/contextualidentity/moz.build rename to browser/components/contextualidentity/moz.build diff --git a/application/basilisk/components/controlcenter/content/panel.inc.xul b/browser/components/controlcenter/content/panel.inc.xul similarity index 100% rename from application/basilisk/components/controlcenter/content/panel.inc.xul rename to browser/components/controlcenter/content/panel.inc.xul diff --git a/application/basilisk/components/customizableui/CustomizableUI.jsm b/browser/components/customizableui/CustomizableUI.jsm similarity index 100% rename from application/basilisk/components/customizableui/CustomizableUI.jsm rename to browser/components/customizableui/CustomizableUI.jsm diff --git a/application/basilisk/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm similarity index 100% rename from application/basilisk/components/customizableui/CustomizableWidgets.jsm rename to browser/components/customizableui/CustomizableWidgets.jsm diff --git a/application/basilisk/components/customizableui/CustomizeMode.jsm b/browser/components/customizableui/CustomizeMode.jsm similarity index 100% rename from application/basilisk/components/customizableui/CustomizeMode.jsm rename to browser/components/customizableui/CustomizeMode.jsm diff --git a/application/basilisk/components/customizableui/DragPositionManager.jsm b/browser/components/customizableui/DragPositionManager.jsm similarity index 100% rename from application/basilisk/components/customizableui/DragPositionManager.jsm rename to browser/components/customizableui/DragPositionManager.jsm diff --git a/application/basilisk/components/customizableui/PanelWideWidgetTracker.jsm b/browser/components/customizableui/PanelWideWidgetTracker.jsm similarity index 100% rename from application/basilisk/components/customizableui/PanelWideWidgetTracker.jsm rename to browser/components/customizableui/PanelWideWidgetTracker.jsm diff --git a/application/basilisk/components/customizableui/ScrollbarSampler.jsm b/browser/components/customizableui/ScrollbarSampler.jsm similarity index 100% rename from application/basilisk/components/customizableui/ScrollbarSampler.jsm rename to browser/components/customizableui/ScrollbarSampler.jsm diff --git a/application/basilisk/components/customizableui/content/customizeMode.inc.xul b/browser/components/customizableui/content/customizeMode.inc.xul similarity index 100% rename from application/basilisk/components/customizableui/content/customizeMode.inc.xul rename to browser/components/customizableui/content/customizeMode.inc.xul diff --git a/application/basilisk/components/customizableui/content/jar.mn b/browser/components/customizableui/content/jar.mn similarity index 100% rename from application/basilisk/components/customizableui/content/jar.mn rename to browser/components/customizableui/content/jar.mn diff --git a/application/basilisk/branding/official/locales/moz.build b/browser/components/customizableui/content/moz.build similarity index 100% rename from application/basilisk/branding/official/locales/moz.build rename to browser/components/customizableui/content/moz.build diff --git a/application/basilisk/components/customizableui/content/panelUI.css b/browser/components/customizableui/content/panelUI.css similarity index 100% rename from application/basilisk/components/customizableui/content/panelUI.css rename to browser/components/customizableui/content/panelUI.css diff --git a/application/basilisk/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul similarity index 100% rename from application/basilisk/components/customizableui/content/panelUI.inc.xul rename to browser/components/customizableui/content/panelUI.inc.xul diff --git a/application/basilisk/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js similarity index 100% rename from application/basilisk/components/customizableui/content/panelUI.js rename to browser/components/customizableui/content/panelUI.js diff --git a/application/basilisk/components/customizableui/content/panelUI.xml b/browser/components/customizableui/content/panelUI.xml similarity index 100% rename from application/basilisk/components/customizableui/content/panelUI.xml rename to browser/components/customizableui/content/panelUI.xml diff --git a/application/basilisk/components/customizableui/content/toolbar.xml b/browser/components/customizableui/content/toolbar.xml similarity index 100% rename from application/basilisk/components/customizableui/content/toolbar.xml rename to browser/components/customizableui/content/toolbar.xml diff --git a/application/basilisk/components/customizableui/moz.build b/browser/components/customizableui/moz.build similarity index 100% rename from application/basilisk/components/customizableui/moz.build rename to browser/components/customizableui/moz.build diff --git a/application/basilisk/components/dirprovider/DirectoryProvider.cpp b/browser/components/dirprovider/DirectoryProvider.cpp similarity index 100% rename from application/basilisk/components/dirprovider/DirectoryProvider.cpp rename to browser/components/dirprovider/DirectoryProvider.cpp diff --git a/application/basilisk/components/dirprovider/DirectoryProvider.h b/browser/components/dirprovider/DirectoryProvider.h similarity index 100% rename from application/basilisk/components/dirprovider/DirectoryProvider.h rename to browser/components/dirprovider/DirectoryProvider.h diff --git a/application/basilisk/components/dirprovider/moz.build b/browser/components/dirprovider/moz.build similarity index 100% rename from application/basilisk/components/dirprovider/moz.build rename to browser/components/dirprovider/moz.build diff --git a/application/basilisk/components/distribution.js b/browser/components/distribution.js similarity index 100% rename from application/basilisk/components/distribution.js rename to browser/components/distribution.js diff --git a/application/basilisk/components/downloads/DownloadsCommon.jsm b/browser/components/downloads/DownloadsCommon.jsm similarity index 100% rename from application/basilisk/components/downloads/DownloadsCommon.jsm rename to browser/components/downloads/DownloadsCommon.jsm diff --git a/application/basilisk/components/downloads/DownloadsTaskbar.jsm b/browser/components/downloads/DownloadsTaskbar.jsm similarity index 100% rename from application/basilisk/components/downloads/DownloadsTaskbar.jsm rename to browser/components/downloads/DownloadsTaskbar.jsm diff --git a/application/basilisk/components/downloads/DownloadsViewUI.jsm b/browser/components/downloads/DownloadsViewUI.jsm similarity index 100% rename from application/basilisk/components/downloads/DownloadsViewUI.jsm rename to browser/components/downloads/DownloadsViewUI.jsm diff --git a/application/basilisk/components/downloads/content/allDownloadsViewOverlay.js b/browser/components/downloads/content/allDownloadsViewOverlay.js similarity index 100% rename from application/basilisk/components/downloads/content/allDownloadsViewOverlay.js rename to browser/components/downloads/content/allDownloadsViewOverlay.js diff --git a/application/basilisk/components/downloads/content/allDownloadsViewOverlay.xul b/browser/components/downloads/content/allDownloadsViewOverlay.xul similarity index 100% rename from application/basilisk/components/downloads/content/allDownloadsViewOverlay.xul rename to browser/components/downloads/content/allDownloadsViewOverlay.xul diff --git a/application/basilisk/components/downloads/content/contentAreaDownloadsView.css b/browser/components/downloads/content/contentAreaDownloadsView.css similarity index 100% rename from application/basilisk/components/downloads/content/contentAreaDownloadsView.css rename to browser/components/downloads/content/contentAreaDownloadsView.css diff --git a/application/basilisk/components/downloads/content/contentAreaDownloadsView.js b/browser/components/downloads/content/contentAreaDownloadsView.js similarity index 100% rename from application/basilisk/components/downloads/content/contentAreaDownloadsView.js rename to browser/components/downloads/content/contentAreaDownloadsView.js diff --git a/application/basilisk/components/downloads/content/contentAreaDownloadsView.xul b/browser/components/downloads/content/contentAreaDownloadsView.xul similarity index 100% rename from application/basilisk/components/downloads/content/contentAreaDownloadsView.xul rename to browser/components/downloads/content/contentAreaDownloadsView.xul diff --git a/application/basilisk/components/downloads/content/download.xml b/browser/components/downloads/content/download.xml similarity index 100% rename from application/basilisk/components/downloads/content/download.xml rename to browser/components/downloads/content/download.xml diff --git a/application/basilisk/components/downloads/content/downloads.css b/browser/components/downloads/content/downloads.css similarity index 100% rename from application/basilisk/components/downloads/content/downloads.css rename to browser/components/downloads/content/downloads.css diff --git a/application/basilisk/components/downloads/content/downloads.js b/browser/components/downloads/content/downloads.js similarity index 100% rename from application/basilisk/components/downloads/content/downloads.js rename to browser/components/downloads/content/downloads.js diff --git a/application/basilisk/components/downloads/content/downloadsOverlay.xul b/browser/components/downloads/content/downloadsOverlay.xul similarity index 100% rename from application/basilisk/components/downloads/content/downloadsOverlay.xul rename to browser/components/downloads/content/downloadsOverlay.xul diff --git a/application/basilisk/components/downloads/content/indicator.js b/browser/components/downloads/content/indicator.js similarity index 100% rename from application/basilisk/components/downloads/content/indicator.js rename to browser/components/downloads/content/indicator.js diff --git a/application/basilisk/components/downloads/content/indicatorOverlay.xul b/browser/components/downloads/content/indicatorOverlay.xul similarity index 100% rename from application/basilisk/components/downloads/content/indicatorOverlay.xul rename to browser/components/downloads/content/indicatorOverlay.xul diff --git a/application/basilisk/components/downloads/jar.mn b/browser/components/downloads/jar.mn similarity index 100% rename from application/basilisk/components/downloads/jar.mn rename to browser/components/downloads/jar.mn diff --git a/application/basilisk/components/downloads/moz.build b/browser/components/downloads/moz.build similarity index 100% rename from application/basilisk/components/downloads/moz.build rename to browser/components/downloads/moz.build diff --git a/application/basilisk/components/feeds/BrowserFeeds.manifest b/browser/components/feeds/BrowserFeeds.manifest similarity index 100% rename from application/basilisk/components/feeds/BrowserFeeds.manifest rename to browser/components/feeds/BrowserFeeds.manifest diff --git a/application/basilisk/components/feeds/FeedConverter.js b/browser/components/feeds/FeedConverter.js similarity index 100% rename from application/basilisk/components/feeds/FeedConverter.js rename to browser/components/feeds/FeedConverter.js diff --git a/application/basilisk/components/feeds/FeedWriter.js b/browser/components/feeds/FeedWriter.js similarity index 100% rename from application/basilisk/components/feeds/FeedWriter.js rename to browser/components/feeds/FeedWriter.js diff --git a/application/basilisk/components/feeds/WebContentConverter.js b/browser/components/feeds/WebContentConverter.js similarity index 100% rename from application/basilisk/components/feeds/WebContentConverter.js rename to browser/components/feeds/WebContentConverter.js diff --git a/application/basilisk/components/feeds/content/subscribe.js b/browser/components/feeds/content/subscribe.js similarity index 100% rename from application/basilisk/components/feeds/content/subscribe.js rename to browser/components/feeds/content/subscribe.js diff --git a/application/basilisk/components/feeds/content/subscribe.xhtml b/browser/components/feeds/content/subscribe.xhtml similarity index 100% rename from application/basilisk/components/feeds/content/subscribe.xhtml rename to browser/components/feeds/content/subscribe.xhtml diff --git a/application/basilisk/components/feeds/jar.mn b/browser/components/feeds/jar.mn similarity index 100% rename from application/basilisk/components/feeds/jar.mn rename to browser/components/feeds/jar.mn diff --git a/application/basilisk/components/feeds/moz.build b/browser/components/feeds/moz.build similarity index 100% rename from application/basilisk/components/feeds/moz.build rename to browser/components/feeds/moz.build diff --git a/application/basilisk/components/feeds/nsFeedSniffer.cpp b/browser/components/feeds/nsFeedSniffer.cpp similarity index 100% rename from application/basilisk/components/feeds/nsFeedSniffer.cpp rename to browser/components/feeds/nsFeedSniffer.cpp diff --git a/application/basilisk/components/feeds/nsFeedSniffer.h b/browser/components/feeds/nsFeedSniffer.h similarity index 100% rename from application/basilisk/components/feeds/nsFeedSniffer.h rename to browser/components/feeds/nsFeedSniffer.h diff --git a/application/basilisk/components/feeds/nsIFeedResultService.idl b/browser/components/feeds/nsIFeedResultService.idl similarity index 100% rename from application/basilisk/components/feeds/nsIFeedResultService.idl rename to browser/components/feeds/nsIFeedResultService.idl diff --git a/application/basilisk/components/feeds/nsIWebContentConverterRegistrar.idl b/browser/components/feeds/nsIWebContentConverterRegistrar.idl similarity index 100% rename from application/basilisk/components/feeds/nsIWebContentConverterRegistrar.idl rename to browser/components/feeds/nsIWebContentConverterRegistrar.idl diff --git a/application/basilisk/components/migration/.eslintrc.js b/browser/components/migration/.eslintrc.js similarity index 100% rename from application/basilisk/components/migration/.eslintrc.js rename to browser/components/migration/.eslintrc.js diff --git a/application/basilisk/components/migration/360seProfileMigrator.js b/browser/components/migration/360seProfileMigrator.js similarity index 100% rename from application/basilisk/components/migration/360seProfileMigrator.js rename to browser/components/migration/360seProfileMigrator.js diff --git a/application/basilisk/components/migration/AutoMigrate.jsm b/browser/components/migration/AutoMigrate.jsm similarity index 100% rename from application/basilisk/components/migration/AutoMigrate.jsm rename to browser/components/migration/AutoMigrate.jsm diff --git a/application/basilisk/components/migration/BrowserProfileMigrators.manifest b/browser/components/migration/BrowserProfileMigrators.manifest similarity index 100% rename from application/basilisk/components/migration/BrowserProfileMigrators.manifest rename to browser/components/migration/BrowserProfileMigrators.manifest diff --git a/application/basilisk/components/migration/ChromeProfileMigrator.js b/browser/components/migration/ChromeProfileMigrator.js similarity index 100% rename from application/basilisk/components/migration/ChromeProfileMigrator.js rename to browser/components/migration/ChromeProfileMigrator.js diff --git a/application/basilisk/components/migration/ESEDBReader.jsm b/browser/components/migration/ESEDBReader.jsm similarity index 100% rename from application/basilisk/components/migration/ESEDBReader.jsm rename to browser/components/migration/ESEDBReader.jsm diff --git a/application/basilisk/components/migration/EdgeProfileMigrator.js b/browser/components/migration/EdgeProfileMigrator.js similarity index 100% rename from application/basilisk/components/migration/EdgeProfileMigrator.js rename to browser/components/migration/EdgeProfileMigrator.js diff --git a/application/basilisk/components/migration/FirefoxProfileMigrator.js b/browser/components/migration/FirefoxProfileMigrator.js similarity index 100% rename from application/basilisk/components/migration/FirefoxProfileMigrator.js rename to browser/components/migration/FirefoxProfileMigrator.js diff --git a/application/basilisk/components/migration/IEProfileMigrator.js b/browser/components/migration/IEProfileMigrator.js similarity index 100% rename from application/basilisk/components/migration/IEProfileMigrator.js rename to browser/components/migration/IEProfileMigrator.js diff --git a/application/basilisk/components/migration/MSMigrationUtils.jsm b/browser/components/migration/MSMigrationUtils.jsm similarity index 100% rename from application/basilisk/components/migration/MSMigrationUtils.jsm rename to browser/components/migration/MSMigrationUtils.jsm diff --git a/application/basilisk/components/migration/MigrationUtils.jsm b/browser/components/migration/MigrationUtils.jsm similarity index 100% rename from application/basilisk/components/migration/MigrationUtils.jsm rename to browser/components/migration/MigrationUtils.jsm diff --git a/application/basilisk/components/migration/ProfileMigrator.js b/browser/components/migration/ProfileMigrator.js similarity index 100% rename from application/basilisk/components/migration/ProfileMigrator.js rename to browser/components/migration/ProfileMigrator.js diff --git a/application/basilisk/components/migration/SafariProfileMigrator.js b/browser/components/migration/SafariProfileMigrator.js similarity index 100% rename from application/basilisk/components/migration/SafariProfileMigrator.js rename to browser/components/migration/SafariProfileMigrator.js diff --git a/application/basilisk/components/migration/content/aboutWelcomeBack.xhtml b/browser/components/migration/content/aboutWelcomeBack.xhtml similarity index 100% rename from application/basilisk/components/migration/content/aboutWelcomeBack.xhtml rename to browser/components/migration/content/aboutWelcomeBack.xhtml diff --git a/application/basilisk/components/migration/content/extra-migration-strings.properties b/browser/components/migration/content/extra-migration-strings.properties similarity index 100% rename from application/basilisk/components/migration/content/extra-migration-strings.properties rename to browser/components/migration/content/extra-migration-strings.properties diff --git a/application/basilisk/components/migration/content/migration.js b/browser/components/migration/content/migration.js similarity index 100% rename from application/basilisk/components/migration/content/migration.js rename to browser/components/migration/content/migration.js diff --git a/application/basilisk/components/migration/content/migration.xul b/browser/components/migration/content/migration.xul similarity index 100% rename from application/basilisk/components/migration/content/migration.xul rename to browser/components/migration/content/migration.xul diff --git a/application/basilisk/components/migration/jar.mn b/browser/components/migration/jar.mn similarity index 100% rename from application/basilisk/components/migration/jar.mn rename to browser/components/migration/jar.mn diff --git a/application/basilisk/components/migration/moz.build b/browser/components/migration/moz.build similarity index 100% rename from application/basilisk/components/migration/moz.build rename to browser/components/migration/moz.build diff --git a/application/basilisk/components/migration/nsIBrowserProfileMigrator.idl b/browser/components/migration/nsIBrowserProfileMigrator.idl similarity index 100% rename from application/basilisk/components/migration/nsIBrowserProfileMigrator.idl rename to browser/components/migration/nsIBrowserProfileMigrator.idl diff --git a/application/basilisk/components/migration/nsIEHistoryEnumerator.cpp b/browser/components/migration/nsIEHistoryEnumerator.cpp similarity index 100% rename from application/basilisk/components/migration/nsIEHistoryEnumerator.cpp rename to browser/components/migration/nsIEHistoryEnumerator.cpp diff --git a/application/basilisk/components/migration/nsIEHistoryEnumerator.h b/browser/components/migration/nsIEHistoryEnumerator.h similarity index 100% rename from application/basilisk/components/migration/nsIEHistoryEnumerator.h rename to browser/components/migration/nsIEHistoryEnumerator.h diff --git a/application/basilisk/components/migration/nsWindowsMigrationUtils.h b/browser/components/migration/nsWindowsMigrationUtils.h similarity index 100% rename from application/basilisk/components/migration/nsWindowsMigrationUtils.h rename to browser/components/migration/nsWindowsMigrationUtils.h diff --git a/application/basilisk/components/moz.build b/browser/components/moz.build similarity index 100% rename from application/basilisk/components/moz.build rename to browser/components/moz.build diff --git a/application/basilisk/components/newtab/NewTabComponents.manifest b/browser/components/newtab/NewTabComponents.manifest similarity index 100% rename from application/basilisk/components/newtab/NewTabComponents.manifest rename to browser/components/newtab/NewTabComponents.manifest diff --git a/application/basilisk/components/newtab/NewTabMessages.jsm b/browser/components/newtab/NewTabMessages.jsm similarity index 100% rename from application/basilisk/components/newtab/NewTabMessages.jsm rename to browser/components/newtab/NewTabMessages.jsm diff --git a/application/basilisk/components/newtab/NewTabPrefsProvider.jsm b/browser/components/newtab/NewTabPrefsProvider.jsm similarity index 100% rename from application/basilisk/components/newtab/NewTabPrefsProvider.jsm rename to browser/components/newtab/NewTabPrefsProvider.jsm diff --git a/application/basilisk/components/newtab/NewTabRemoteResources.jsm b/browser/components/newtab/NewTabRemoteResources.jsm similarity index 100% rename from application/basilisk/components/newtab/NewTabRemoteResources.jsm rename to browser/components/newtab/NewTabRemoteResources.jsm diff --git a/application/basilisk/components/newtab/NewTabSearchProvider.jsm b/browser/components/newtab/NewTabSearchProvider.jsm similarity index 100% rename from application/basilisk/components/newtab/NewTabSearchProvider.jsm rename to browser/components/newtab/NewTabSearchProvider.jsm diff --git a/application/basilisk/components/newtab/NewTabURL.jsm b/browser/components/newtab/NewTabURL.jsm similarity index 100% rename from application/basilisk/components/newtab/NewTabURL.jsm rename to browser/components/newtab/NewTabURL.jsm diff --git a/application/basilisk/components/newtab/NewTabWebChannel.jsm b/browser/components/newtab/NewTabWebChannel.jsm similarity index 100% rename from application/basilisk/components/newtab/NewTabWebChannel.jsm rename to browser/components/newtab/NewTabWebChannel.jsm diff --git a/application/basilisk/components/newtab/PlacesProvider.jsm b/browser/components/newtab/PlacesProvider.jsm similarity index 100% rename from application/basilisk/components/newtab/PlacesProvider.jsm rename to browser/components/newtab/PlacesProvider.jsm diff --git a/application/basilisk/components/newtab/PreviewProvider.jsm b/browser/components/newtab/PreviewProvider.jsm similarity index 100% rename from application/basilisk/components/newtab/PreviewProvider.jsm rename to browser/components/newtab/PreviewProvider.jsm diff --git a/application/basilisk/components/newtab/aboutNewTabService.js b/browser/components/newtab/aboutNewTabService.js similarity index 100% rename from application/basilisk/components/newtab/aboutNewTabService.js rename to browser/components/newtab/aboutNewTabService.js diff --git a/application/basilisk/components/newtab/moz.build b/browser/components/newtab/moz.build similarity index 100% rename from application/basilisk/components/newtab/moz.build rename to browser/components/newtab/moz.build diff --git a/application/basilisk/components/newtab/nsIAboutNewTabService.idl b/browser/components/newtab/nsIAboutNewTabService.idl similarity index 100% rename from application/basilisk/components/newtab/nsIAboutNewTabService.idl rename to browser/components/newtab/nsIAboutNewTabService.idl diff --git a/application/basilisk/components/nsBrowserContentHandler.js b/browser/components/nsBrowserContentHandler.js similarity index 100% rename from application/basilisk/components/nsBrowserContentHandler.js rename to browser/components/nsBrowserContentHandler.js diff --git a/application/basilisk/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js similarity index 99% rename from application/basilisk/components/nsBrowserGlue.js rename to browser/components/nsBrowserGlue.js index b53536a0e5..a9d95bb0cf 100644 --- a/application/basilisk/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -9,6 +9,8 @@ const Cu = Components.utils; const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; +const PREF_INTERNAL_USERSCRIPTS_ENABLED = "browser.internal-userscripts.enabled"; + Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/AppConstants.jsm"); @@ -185,6 +187,7 @@ BrowserGlue.prototype = { break; case "final-ui-startup": this._finalUIStartup(); + this._syncInternalUserScripts(); break; case "browser-delayed-startup-finished": this._onFirstWindowLoaded(subject); @@ -357,6 +360,11 @@ BrowserGlue.prototype = { break; case "autocomplete-did-enter-text": break; + case "nsPref:changed": + if (data == PREF_INTERNAL_USERSCRIPTS_ENABLED) { + this._syncInternalUserScripts(); + } + break; case "test-initialize-sanitizer": this._sanitizer.onStartup(); break; @@ -398,6 +406,7 @@ BrowserGlue.prototype = { os.addObserver(this, "flash-plugin-hang", false); os.addObserver(this, "xpi-signature-changed", false); os.addObserver(this, "autocomplete-did-enter-text", false); + Services.prefs.addObserver(PREF_INTERNAL_USERSCRIPTS_ENABLED, this); if (AppConstants.NIGHTLY_BUILD) { os.addObserver(this, AddonWatcher.TOPIC_SLOW_ADDON_DETECTED, false); @@ -448,6 +457,7 @@ BrowserGlue.prototype = { os.removeObserver(this, "flash-plugin-hang"); os.removeObserver(this, "xpi-signature-changed"); os.removeObserver(this, "autocomplete-did-enter-text"); + Services.prefs.removeObserver(PREF_INTERNAL_USERSCRIPTS_ENABLED, this); }, _onAppDefaults: function() { @@ -816,6 +826,15 @@ BrowserGlue.prototype = { nb.PRIORITY_WARNING_MEDIUM, buttons); }, + _syncInternalUserScripts: function () { + let enabled = true; + try { + enabled = Services.prefs.getBoolPref(PREF_INTERNAL_USERSCRIPTS_ENABLED); + } catch (ex) {} + // Internal userscripts service checks this pref on startup. + Services.prefs.setBoolPref(PREF_INTERNAL_USERSCRIPTS_ENABLED, enabled); + }, + // the first browser window has finished initializing _onFirstWindowLoaded: function(aWindow) { // Initialize PdfJs when running in-process and remote. This only diff --git a/application/basilisk/components/nsIBrowserGlue.idl b/browser/components/nsIBrowserGlue.idl similarity index 100% rename from application/basilisk/components/nsIBrowserGlue.idl rename to browser/components/nsIBrowserGlue.idl diff --git a/application/basilisk/components/nsIBrowserHandler.idl b/browser/components/nsIBrowserHandler.idl similarity index 100% rename from application/basilisk/components/nsIBrowserHandler.idl rename to browser/components/nsIBrowserHandler.idl diff --git a/application/basilisk/components/places/PlacesUIUtils.jsm b/browser/components/places/PlacesUIUtils.jsm similarity index 100% rename from application/basilisk/components/places/PlacesUIUtils.jsm rename to browser/components/places/PlacesUIUtils.jsm diff --git a/application/basilisk/components/places/content/bookmarkProperties.js b/browser/components/places/content/bookmarkProperties.js similarity index 100% rename from application/basilisk/components/places/content/bookmarkProperties.js rename to browser/components/places/content/bookmarkProperties.js diff --git a/application/basilisk/components/places/content/bookmarkProperties.xul b/browser/components/places/content/bookmarkProperties.xul similarity index 100% rename from application/basilisk/components/places/content/bookmarkProperties.xul rename to browser/components/places/content/bookmarkProperties.xul diff --git a/application/basilisk/components/places/content/bookmarksPanel.js b/browser/components/places/content/bookmarksPanel.js similarity index 100% rename from application/basilisk/components/places/content/bookmarksPanel.js rename to browser/components/places/content/bookmarksPanel.js diff --git a/application/basilisk/components/places/content/bookmarksPanel.xul b/browser/components/places/content/bookmarksPanel.xul similarity index 100% rename from application/basilisk/components/places/content/bookmarksPanel.xul rename to browser/components/places/content/bookmarksPanel.xul diff --git a/application/basilisk/components/places/content/browserPlacesViews.js b/browser/components/places/content/browserPlacesViews.js similarity index 100% rename from application/basilisk/components/places/content/browserPlacesViews.js rename to browser/components/places/content/browserPlacesViews.js diff --git a/application/basilisk/components/places/content/controller.js b/browser/components/places/content/controller.js similarity index 100% rename from application/basilisk/components/places/content/controller.js rename to browser/components/places/content/controller.js diff --git a/application/basilisk/components/places/content/downloadsViewOverlay.xul b/browser/components/places/content/downloadsViewOverlay.xul similarity index 100% rename from application/basilisk/components/places/content/downloadsViewOverlay.xul rename to browser/components/places/content/downloadsViewOverlay.xul diff --git a/application/basilisk/components/places/content/editBookmarkOverlay.js b/browser/components/places/content/editBookmarkOverlay.js similarity index 100% rename from application/basilisk/components/places/content/editBookmarkOverlay.js rename to browser/components/places/content/editBookmarkOverlay.js diff --git a/application/basilisk/components/places/content/editBookmarkOverlay.xul b/browser/components/places/content/editBookmarkOverlay.xul similarity index 100% rename from application/basilisk/components/places/content/editBookmarkOverlay.xul rename to browser/components/places/content/editBookmarkOverlay.xul diff --git a/application/basilisk/components/places/content/history-panel.js b/browser/components/places/content/history-panel.js similarity index 100% rename from application/basilisk/components/places/content/history-panel.js rename to browser/components/places/content/history-panel.js diff --git a/application/basilisk/components/places/content/history-panel.xul b/browser/components/places/content/history-panel.xul similarity index 100% rename from application/basilisk/components/places/content/history-panel.xul rename to browser/components/places/content/history-panel.xul diff --git a/application/basilisk/components/places/content/menu.xml b/browser/components/places/content/menu.xml similarity index 100% rename from application/basilisk/components/places/content/menu.xml rename to browser/components/places/content/menu.xml diff --git a/application/basilisk/components/places/content/moveBookmarks.js b/browser/components/places/content/moveBookmarks.js similarity index 100% rename from application/basilisk/components/places/content/moveBookmarks.js rename to browser/components/places/content/moveBookmarks.js diff --git a/application/basilisk/components/places/content/moveBookmarks.xul b/browser/components/places/content/moveBookmarks.xul similarity index 100% rename from application/basilisk/components/places/content/moveBookmarks.xul rename to browser/components/places/content/moveBookmarks.xul diff --git a/application/basilisk/components/places/content/organizer.css b/browser/components/places/content/organizer.css similarity index 100% rename from application/basilisk/components/places/content/organizer.css rename to browser/components/places/content/organizer.css diff --git a/application/basilisk/components/places/content/places.css b/browser/components/places/content/places.css similarity index 100% rename from application/basilisk/components/places/content/places.css rename to browser/components/places/content/places.css diff --git a/application/basilisk/components/places/content/places.js b/browser/components/places/content/places.js similarity index 100% rename from application/basilisk/components/places/content/places.js rename to browser/components/places/content/places.js diff --git a/application/basilisk/components/places/content/places.xul b/browser/components/places/content/places.xul similarity index 100% rename from application/basilisk/components/places/content/places.xul rename to browser/components/places/content/places.xul diff --git a/application/basilisk/components/places/content/placesOverlay.xul b/browser/components/places/content/placesOverlay.xul similarity index 100% rename from application/basilisk/components/places/content/placesOverlay.xul rename to browser/components/places/content/placesOverlay.xul diff --git a/application/basilisk/components/places/content/sidebarUtils.js b/browser/components/places/content/sidebarUtils.js similarity index 100% rename from application/basilisk/components/places/content/sidebarUtils.js rename to browser/components/places/content/sidebarUtils.js diff --git a/application/basilisk/components/places/content/tree.xml b/browser/components/places/content/tree.xml similarity index 100% rename from application/basilisk/components/places/content/tree.xml rename to browser/components/places/content/tree.xml diff --git a/application/basilisk/components/places/content/treeView.js b/browser/components/places/content/treeView.js similarity index 100% rename from application/basilisk/components/places/content/treeView.js rename to browser/components/places/content/treeView.js diff --git a/application/basilisk/components/places/jar.mn b/browser/components/places/jar.mn similarity index 100% rename from application/basilisk/components/places/jar.mn rename to browser/components/places/jar.mn diff --git a/application/basilisk/components/places/moz.build b/browser/components/places/moz.build similarity index 100% rename from application/basilisk/components/places/moz.build rename to browser/components/places/moz.build diff --git a/application/basilisk/components/preferences/applicationManager.js b/browser/components/preferences/applicationManager.js similarity index 100% rename from application/basilisk/components/preferences/applicationManager.js rename to browser/components/preferences/applicationManager.js diff --git a/application/basilisk/components/preferences/applicationManager.xul b/browser/components/preferences/applicationManager.xul similarity index 100% rename from application/basilisk/components/preferences/applicationManager.xul rename to browser/components/preferences/applicationManager.xul diff --git a/application/basilisk/components/preferences/colors.xul b/browser/components/preferences/colors.xul similarity index 100% rename from application/basilisk/components/preferences/colors.xul rename to browser/components/preferences/colors.xul diff --git a/application/basilisk/components/preferences/connection.js b/browser/components/preferences/connection.js similarity index 100% rename from application/basilisk/components/preferences/connection.js rename to browser/components/preferences/connection.js diff --git a/application/basilisk/components/preferences/connection.xul b/browser/components/preferences/connection.xul similarity index 100% rename from application/basilisk/components/preferences/connection.xul rename to browser/components/preferences/connection.xul diff --git a/application/basilisk/components/preferences/containers.js b/browser/components/preferences/containers.js similarity index 100% rename from application/basilisk/components/preferences/containers.js rename to browser/components/preferences/containers.js diff --git a/application/basilisk/components/preferences/containers.xul b/browser/components/preferences/containers.xul similarity index 100% rename from application/basilisk/components/preferences/containers.xul rename to browser/components/preferences/containers.xul diff --git a/application/basilisk/components/preferences/cookies.js b/browser/components/preferences/cookies.js similarity index 100% rename from application/basilisk/components/preferences/cookies.js rename to browser/components/preferences/cookies.js diff --git a/application/basilisk/components/preferences/cookies.xul b/browser/components/preferences/cookies.xul similarity index 100% rename from application/basilisk/components/preferences/cookies.xul rename to browser/components/preferences/cookies.xul diff --git a/application/basilisk/components/preferences/fonts.js b/browser/components/preferences/fonts.js similarity index 100% rename from application/basilisk/components/preferences/fonts.js rename to browser/components/preferences/fonts.js diff --git a/application/basilisk/components/preferences/fonts.xul b/browser/components/preferences/fonts.xul similarity index 100% rename from application/basilisk/components/preferences/fonts.xul rename to browser/components/preferences/fonts.xul diff --git a/application/basilisk/components/preferences/handlers.css b/browser/components/preferences/handlers.css similarity index 100% rename from application/basilisk/components/preferences/handlers.css rename to browser/components/preferences/handlers.css diff --git a/application/basilisk/components/preferences/handlers.xml b/browser/components/preferences/handlers.xml similarity index 100% rename from application/basilisk/components/preferences/handlers.xml rename to browser/components/preferences/handlers.xml diff --git a/application/basilisk/components/preferences/in-content/advanced.js b/browser/components/preferences/in-content/advanced.js similarity index 100% rename from application/basilisk/components/preferences/in-content/advanced.js rename to browser/components/preferences/in-content/advanced.js diff --git a/application/basilisk/components/preferences/in-content/advanced.xul b/browser/components/preferences/in-content/advanced.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/advanced.xul rename to browser/components/preferences/in-content/advanced.xul diff --git a/application/basilisk/components/preferences/in-content/applications.js b/browser/components/preferences/in-content/applications.js similarity index 100% rename from application/basilisk/components/preferences/in-content/applications.js rename to browser/components/preferences/in-content/applications.js diff --git a/application/basilisk/components/preferences/in-content/applications.xul b/browser/components/preferences/in-content/applications.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/applications.xul rename to browser/components/preferences/in-content/applications.xul diff --git a/application/basilisk/components/preferences/in-content/containers.js b/browser/components/preferences/in-content/containers.js similarity index 100% rename from application/basilisk/components/preferences/in-content/containers.js rename to browser/components/preferences/in-content/containers.js diff --git a/application/basilisk/components/preferences/in-content/containers.xul b/browser/components/preferences/in-content/containers.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/containers.xul rename to browser/components/preferences/in-content/containers.xul diff --git a/application/basilisk/components/preferences/in-content/content.js b/browser/components/preferences/in-content/content.js similarity index 100% rename from application/basilisk/components/preferences/in-content/content.js rename to browser/components/preferences/in-content/content.js diff --git a/application/basilisk/components/preferences/in-content/content.xul b/browser/components/preferences/in-content/content.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/content.xul rename to browser/components/preferences/in-content/content.xul diff --git a/application/basilisk/components/preferences/in-content/jar.mn b/browser/components/preferences/in-content/jar.mn similarity index 100% rename from application/basilisk/components/preferences/in-content/jar.mn rename to browser/components/preferences/in-content/jar.mn diff --git a/application/basilisk/components/preferences/in-content/main.js b/browser/components/preferences/in-content/main.js similarity index 100% rename from application/basilisk/components/preferences/in-content/main.js rename to browser/components/preferences/in-content/main.js diff --git a/application/basilisk/components/preferences/in-content/main.xul b/browser/components/preferences/in-content/main.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/main.xul rename to browser/components/preferences/in-content/main.xul diff --git a/application/basilisk/components/preferences/in-content/moz.build b/browser/components/preferences/in-content/moz.build similarity index 100% rename from application/basilisk/components/preferences/in-content/moz.build rename to browser/components/preferences/in-content/moz.build diff --git a/application/basilisk/components/preferences/in-content/preferences.js b/browser/components/preferences/in-content/preferences.js similarity index 100% rename from application/basilisk/components/preferences/in-content/preferences.js rename to browser/components/preferences/in-content/preferences.js diff --git a/application/basilisk/components/preferences/in-content/preferences.xul b/browser/components/preferences/in-content/preferences.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/preferences.xul rename to browser/components/preferences/in-content/preferences.xul diff --git a/application/basilisk/components/preferences/in-content/privacy.js b/browser/components/preferences/in-content/privacy.js similarity index 100% rename from application/basilisk/components/preferences/in-content/privacy.js rename to browser/components/preferences/in-content/privacy.js diff --git a/application/basilisk/components/preferences/in-content/privacy.xul b/browser/components/preferences/in-content/privacy.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/privacy.xul rename to browser/components/preferences/in-content/privacy.xul diff --git a/application/basilisk/components/preferences/in-content/search.js b/browser/components/preferences/in-content/search.js similarity index 100% rename from application/basilisk/components/preferences/in-content/search.js rename to browser/components/preferences/in-content/search.js diff --git a/application/basilisk/components/preferences/in-content/search.xul b/browser/components/preferences/in-content/search.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/search.xul rename to browser/components/preferences/in-content/search.xul diff --git a/application/basilisk/components/preferences/in-content/security.js b/browser/components/preferences/in-content/security.js similarity index 100% rename from application/basilisk/components/preferences/in-content/security.js rename to browser/components/preferences/in-content/security.js diff --git a/application/basilisk/components/preferences/in-content/security.xul b/browser/components/preferences/in-content/security.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/security.xul rename to browser/components/preferences/in-content/security.xul diff --git a/application/basilisk/components/preferences/in-content/subdialogs.js b/browser/components/preferences/in-content/subdialogs.js similarity index 100% rename from application/basilisk/components/preferences/in-content/subdialogs.js rename to browser/components/preferences/in-content/subdialogs.js diff --git a/application/basilisk/components/preferences/in-content/sync.js b/browser/components/preferences/in-content/sync.js similarity index 100% rename from application/basilisk/components/preferences/in-content/sync.js rename to browser/components/preferences/in-content/sync.js diff --git a/application/basilisk/components/preferences/in-content/sync.xul b/browser/components/preferences/in-content/sync.xul similarity index 100% rename from application/basilisk/components/preferences/in-content/sync.xul rename to browser/components/preferences/in-content/sync.xul diff --git a/application/basilisk/components/preferences/jar.mn b/browser/components/preferences/jar.mn similarity index 100% rename from application/basilisk/components/preferences/jar.mn rename to browser/components/preferences/jar.mn diff --git a/application/basilisk/components/preferences/languages.js b/browser/components/preferences/languages.js similarity index 100% rename from application/basilisk/components/preferences/languages.js rename to browser/components/preferences/languages.js diff --git a/application/basilisk/components/preferences/languages.xul b/browser/components/preferences/languages.xul similarity index 100% rename from application/basilisk/components/preferences/languages.xul rename to browser/components/preferences/languages.xul diff --git a/application/basilisk/components/preferences/moz.build b/browser/components/preferences/moz.build similarity index 100% rename from application/basilisk/components/preferences/moz.build rename to browser/components/preferences/moz.build diff --git a/application/basilisk/components/preferences/permissions.js b/browser/components/preferences/permissions.js similarity index 100% rename from application/basilisk/components/preferences/permissions.js rename to browser/components/preferences/permissions.js diff --git a/application/basilisk/components/preferences/permissions.xul b/browser/components/preferences/permissions.xul similarity index 100% rename from application/basilisk/components/preferences/permissions.xul rename to browser/components/preferences/permissions.xul diff --git a/application/basilisk/components/preferences/sanitize.js b/browser/components/preferences/sanitize.js similarity index 100% rename from application/basilisk/components/preferences/sanitize.js rename to browser/components/preferences/sanitize.js diff --git a/application/basilisk/components/preferences/sanitize.xul b/browser/components/preferences/sanitize.xul similarity index 100% rename from application/basilisk/components/preferences/sanitize.xul rename to browser/components/preferences/sanitize.xul diff --git a/application/basilisk/components/preferences/selectBookmark.js b/browser/components/preferences/selectBookmark.js similarity index 100% rename from application/basilisk/components/preferences/selectBookmark.js rename to browser/components/preferences/selectBookmark.js diff --git a/application/basilisk/components/preferences/selectBookmark.xul b/browser/components/preferences/selectBookmark.xul similarity index 100% rename from application/basilisk/components/preferences/selectBookmark.xul rename to browser/components/preferences/selectBookmark.xul diff --git a/application/basilisk/components/privatebrowsing/content/aboutPrivateBrowsing.css b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css similarity index 100% rename from application/basilisk/components/privatebrowsing/content/aboutPrivateBrowsing.css rename to browser/components/privatebrowsing/content/aboutPrivateBrowsing.css diff --git a/application/basilisk/components/privatebrowsing/content/aboutPrivateBrowsing.js b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js similarity index 100% rename from application/basilisk/components/privatebrowsing/content/aboutPrivateBrowsing.js rename to browser/components/privatebrowsing/content/aboutPrivateBrowsing.js diff --git a/application/basilisk/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml similarity index 100% rename from application/basilisk/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml rename to browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml diff --git a/application/basilisk/components/privatebrowsing/jar.mn b/browser/components/privatebrowsing/jar.mn similarity index 100% rename from application/basilisk/components/privatebrowsing/jar.mn rename to browser/components/privatebrowsing/jar.mn diff --git a/application/basilisk/components/privatebrowsing/moz.build b/browser/components/privatebrowsing/moz.build similarity index 100% rename from application/basilisk/components/privatebrowsing/moz.build rename to browser/components/privatebrowsing/moz.build diff --git a/application/basilisk/components/search/content/search.xml b/browser/components/search/content/search.xml similarity index 100% rename from application/basilisk/components/search/content/search.xml rename to browser/components/search/content/search.xml diff --git a/application/basilisk/components/search/content/searchReset.js b/browser/components/search/content/searchReset.js similarity index 100% rename from application/basilisk/components/search/content/searchReset.js rename to browser/components/search/content/searchReset.js diff --git a/application/basilisk/components/search/content/searchReset.xhtml b/browser/components/search/content/searchReset.xhtml similarity index 100% rename from application/basilisk/components/search/content/searchReset.xhtml rename to browser/components/search/content/searchReset.xhtml diff --git a/application/basilisk/components/search/content/searchbarBindings.css b/browser/components/search/content/searchbarBindings.css similarity index 100% rename from application/basilisk/components/search/content/searchbarBindings.css rename to browser/components/search/content/searchbarBindings.css diff --git a/application/basilisk/components/search/jar.mn b/browser/components/search/jar.mn similarity index 100% rename from application/basilisk/components/search/jar.mn rename to browser/components/search/jar.mn diff --git a/application/basilisk/components/search/moz.build b/browser/components/search/moz.build similarity index 100% rename from application/basilisk/components/search/moz.build rename to browser/components/search/moz.build diff --git a/application/basilisk/components/search/service/SearchStaticData.jsm b/browser/components/search/service/SearchStaticData.jsm similarity index 100% rename from application/basilisk/components/search/service/SearchStaticData.jsm rename to browser/components/search/service/SearchStaticData.jsm diff --git a/application/basilisk/components/search/service/SearchSuggestionController.jsm b/browser/components/search/service/SearchSuggestionController.jsm similarity index 100% rename from application/basilisk/components/search/service/SearchSuggestionController.jsm rename to browser/components/search/service/SearchSuggestionController.jsm diff --git a/application/basilisk/components/search/service/moz.build b/browser/components/search/service/moz.build similarity index 100% rename from application/basilisk/components/search/service/moz.build rename to browser/components/search/service/moz.build diff --git a/application/basilisk/components/search/service/nsSearchService.js b/browser/components/search/service/nsSearchService.js similarity index 100% rename from application/basilisk/components/search/service/nsSearchService.js rename to browser/components/search/service/nsSearchService.js diff --git a/application/basilisk/components/search/service/nsSearchSuggestions.js b/browser/components/search/service/nsSearchSuggestions.js similarity index 100% rename from application/basilisk/components/search/service/nsSearchSuggestions.js rename to browser/components/search/service/nsSearchSuggestions.js diff --git a/application/basilisk/components/search/service/nsSidebar.js b/browser/components/search/service/nsSidebar.js similarity index 100% rename from application/basilisk/components/search/service/nsSidebar.js rename to browser/components/search/service/nsSidebar.js diff --git a/application/basilisk/components/search/service/toolkitsearch.manifest b/browser/components/search/service/toolkitsearch.manifest similarity index 100% rename from application/basilisk/components/search/service/toolkitsearch.manifest rename to browser/components/search/service/toolkitsearch.manifest diff --git a/application/basilisk/components/selfsupport/SelfSupportService.js b/browser/components/selfsupport/SelfSupportService.js similarity index 100% rename from application/basilisk/components/selfsupport/SelfSupportService.js rename to browser/components/selfsupport/SelfSupportService.js diff --git a/application/basilisk/components/selfsupport/SelfSupportService.manifest b/browser/components/selfsupport/SelfSupportService.manifest similarity index 100% rename from application/basilisk/components/selfsupport/SelfSupportService.manifest rename to browser/components/selfsupport/SelfSupportService.manifest diff --git a/application/basilisk/components/selfsupport/moz.build b/browser/components/selfsupport/moz.build similarity index 100% rename from application/basilisk/components/selfsupport/moz.build rename to browser/components/selfsupport/moz.build diff --git a/application/basilisk/components/sessionstore/ContentRestore.jsm b/browser/components/sessionstore/ContentRestore.jsm similarity index 100% rename from application/basilisk/components/sessionstore/ContentRestore.jsm rename to browser/components/sessionstore/ContentRestore.jsm diff --git a/application/basilisk/components/sessionstore/DocShellCapabilities.jsm b/browser/components/sessionstore/DocShellCapabilities.jsm similarity index 100% rename from application/basilisk/components/sessionstore/DocShellCapabilities.jsm rename to browser/components/sessionstore/DocShellCapabilities.jsm diff --git a/application/basilisk/components/sessionstore/FrameTree.jsm b/browser/components/sessionstore/FrameTree.jsm similarity index 100% rename from application/basilisk/components/sessionstore/FrameTree.jsm rename to browser/components/sessionstore/FrameTree.jsm diff --git a/application/basilisk/components/sessionstore/GlobalState.jsm b/browser/components/sessionstore/GlobalState.jsm similarity index 100% rename from application/basilisk/components/sessionstore/GlobalState.jsm rename to browser/components/sessionstore/GlobalState.jsm diff --git a/application/basilisk/components/sessionstore/PageStyle.jsm b/browser/components/sessionstore/PageStyle.jsm similarity index 100% rename from application/basilisk/components/sessionstore/PageStyle.jsm rename to browser/components/sessionstore/PageStyle.jsm diff --git a/application/basilisk/components/sessionstore/PrivacyFilter.jsm b/browser/components/sessionstore/PrivacyFilter.jsm similarity index 100% rename from application/basilisk/components/sessionstore/PrivacyFilter.jsm rename to browser/components/sessionstore/PrivacyFilter.jsm diff --git a/application/basilisk/components/sessionstore/PrivacyLevel.jsm b/browser/components/sessionstore/PrivacyLevel.jsm similarity index 100% rename from application/basilisk/components/sessionstore/PrivacyLevel.jsm rename to browser/components/sessionstore/PrivacyLevel.jsm diff --git a/application/basilisk/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm b/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm similarity index 100% rename from application/basilisk/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm rename to browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm diff --git a/application/basilisk/components/sessionstore/RunState.jsm b/browser/components/sessionstore/RunState.jsm similarity index 100% rename from application/basilisk/components/sessionstore/RunState.jsm rename to browser/components/sessionstore/RunState.jsm diff --git a/application/basilisk/components/sessionstore/SessionCookies.jsm b/browser/components/sessionstore/SessionCookies.jsm similarity index 100% rename from application/basilisk/components/sessionstore/SessionCookies.jsm rename to browser/components/sessionstore/SessionCookies.jsm diff --git a/application/basilisk/components/sessionstore/SessionFile.jsm b/browser/components/sessionstore/SessionFile.jsm similarity index 100% rename from application/basilisk/components/sessionstore/SessionFile.jsm rename to browser/components/sessionstore/SessionFile.jsm diff --git a/application/basilisk/components/sessionstore/SessionHistory.jsm b/browser/components/sessionstore/SessionHistory.jsm similarity index 100% rename from application/basilisk/components/sessionstore/SessionHistory.jsm rename to browser/components/sessionstore/SessionHistory.jsm diff --git a/application/basilisk/components/sessionstore/SessionMigration.jsm b/browser/components/sessionstore/SessionMigration.jsm similarity index 100% rename from application/basilisk/components/sessionstore/SessionMigration.jsm rename to browser/components/sessionstore/SessionMigration.jsm diff --git a/application/basilisk/components/sessionstore/SessionSaver.jsm b/browser/components/sessionstore/SessionSaver.jsm similarity index 100% rename from application/basilisk/components/sessionstore/SessionSaver.jsm rename to browser/components/sessionstore/SessionSaver.jsm diff --git a/application/basilisk/components/sessionstore/SessionStorage.jsm b/browser/components/sessionstore/SessionStorage.jsm similarity index 100% rename from application/basilisk/components/sessionstore/SessionStorage.jsm rename to browser/components/sessionstore/SessionStorage.jsm diff --git a/application/basilisk/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm similarity index 100% rename from application/basilisk/components/sessionstore/SessionStore.jsm rename to browser/components/sessionstore/SessionStore.jsm diff --git a/application/basilisk/components/sessionstore/SessionWorker.js b/browser/components/sessionstore/SessionWorker.js similarity index 100% rename from application/basilisk/components/sessionstore/SessionWorker.js rename to browser/components/sessionstore/SessionWorker.js diff --git a/application/basilisk/components/sessionstore/SessionWorker.jsm b/browser/components/sessionstore/SessionWorker.jsm similarity index 100% rename from application/basilisk/components/sessionstore/SessionWorker.jsm rename to browser/components/sessionstore/SessionWorker.jsm diff --git a/application/basilisk/components/sessionstore/StartupPerformance.jsm b/browser/components/sessionstore/StartupPerformance.jsm similarity index 100% rename from application/basilisk/components/sessionstore/StartupPerformance.jsm rename to browser/components/sessionstore/StartupPerformance.jsm diff --git a/application/basilisk/components/sessionstore/TabAttributes.jsm b/browser/components/sessionstore/TabAttributes.jsm similarity index 100% rename from application/basilisk/components/sessionstore/TabAttributes.jsm rename to browser/components/sessionstore/TabAttributes.jsm diff --git a/application/basilisk/components/sessionstore/TabState.jsm b/browser/components/sessionstore/TabState.jsm similarity index 100% rename from application/basilisk/components/sessionstore/TabState.jsm rename to browser/components/sessionstore/TabState.jsm diff --git a/application/basilisk/components/sessionstore/TabStateCache.jsm b/browser/components/sessionstore/TabStateCache.jsm similarity index 100% rename from application/basilisk/components/sessionstore/TabStateCache.jsm rename to browser/components/sessionstore/TabStateCache.jsm diff --git a/application/basilisk/components/sessionstore/TabStateFlusher.jsm b/browser/components/sessionstore/TabStateFlusher.jsm similarity index 100% rename from application/basilisk/components/sessionstore/TabStateFlusher.jsm rename to browser/components/sessionstore/TabStateFlusher.jsm diff --git a/application/basilisk/components/sessionstore/content/aboutSessionRestore.js b/browser/components/sessionstore/content/aboutSessionRestore.js similarity index 100% rename from application/basilisk/components/sessionstore/content/aboutSessionRestore.js rename to browser/components/sessionstore/content/aboutSessionRestore.js diff --git a/application/basilisk/components/sessionstore/content/aboutSessionRestore.xhtml b/browser/components/sessionstore/content/aboutSessionRestore.xhtml similarity index 100% rename from application/basilisk/components/sessionstore/content/aboutSessionRestore.xhtml rename to browser/components/sessionstore/content/aboutSessionRestore.xhtml diff --git a/application/basilisk/components/sessionstore/content/content-sessionStore.js b/browser/components/sessionstore/content/content-sessionStore.js similarity index 100% rename from application/basilisk/components/sessionstore/content/content-sessionStore.js rename to browser/components/sessionstore/content/content-sessionStore.js diff --git a/application/basilisk/components/sessionstore/jar.mn b/browser/components/sessionstore/jar.mn similarity index 100% rename from application/basilisk/components/sessionstore/jar.mn rename to browser/components/sessionstore/jar.mn diff --git a/application/basilisk/components/sessionstore/moz.build b/browser/components/sessionstore/moz.build similarity index 100% rename from application/basilisk/components/sessionstore/moz.build rename to browser/components/sessionstore/moz.build diff --git a/application/basilisk/components/sessionstore/nsISessionStartup.idl b/browser/components/sessionstore/nsISessionStartup.idl similarity index 100% rename from application/basilisk/components/sessionstore/nsISessionStartup.idl rename to browser/components/sessionstore/nsISessionStartup.idl diff --git a/application/basilisk/components/sessionstore/nsISessionStore.idl b/browser/components/sessionstore/nsISessionStore.idl similarity index 100% rename from application/basilisk/components/sessionstore/nsISessionStore.idl rename to browser/components/sessionstore/nsISessionStore.idl diff --git a/application/basilisk/components/sessionstore/nsSessionStartup.js b/browser/components/sessionstore/nsSessionStartup.js similarity index 100% rename from application/basilisk/components/sessionstore/nsSessionStartup.js rename to browser/components/sessionstore/nsSessionStartup.js diff --git a/application/basilisk/components/sessionstore/nsSessionStore.js b/browser/components/sessionstore/nsSessionStore.js similarity index 100% rename from application/basilisk/components/sessionstore/nsSessionStore.js rename to browser/components/sessionstore/nsSessionStore.js diff --git a/application/basilisk/components/sessionstore/nsSessionStore.manifest b/browser/components/sessionstore/nsSessionStore.manifest similarity index 100% rename from application/basilisk/components/sessionstore/nsSessionStore.manifest rename to browser/components/sessionstore/nsSessionStore.manifest diff --git a/application/basilisk/components/shell/ShellService.jsm b/browser/components/shell/ShellService.jsm similarity index 100% rename from application/basilisk/components/shell/ShellService.jsm rename to browser/components/shell/ShellService.jsm diff --git a/application/basilisk/components/shell/content/setDesktopBackground.js b/browser/components/shell/content/setDesktopBackground.js similarity index 100% rename from application/basilisk/components/shell/content/setDesktopBackground.js rename to browser/components/shell/content/setDesktopBackground.js diff --git a/application/basilisk/components/shell/content/setDesktopBackground.xul b/browser/components/shell/content/setDesktopBackground.xul similarity index 100% rename from application/basilisk/components/shell/content/setDesktopBackground.xul rename to browser/components/shell/content/setDesktopBackground.xul diff --git a/application/basilisk/components/shell/jar.mn b/browser/components/shell/jar.mn similarity index 100% rename from application/basilisk/components/shell/jar.mn rename to browser/components/shell/jar.mn diff --git a/application/basilisk/components/shell/moz.build b/browser/components/shell/moz.build similarity index 100% rename from application/basilisk/components/shell/moz.build rename to browser/components/shell/moz.build diff --git a/application/basilisk/components/shell/nsGNOMEShellService.cpp b/browser/components/shell/nsGNOMEShellService.cpp similarity index 100% rename from application/basilisk/components/shell/nsGNOMEShellService.cpp rename to browser/components/shell/nsGNOMEShellService.cpp diff --git a/application/basilisk/components/shell/nsGNOMEShellService.h b/browser/components/shell/nsGNOMEShellService.h similarity index 100% rename from application/basilisk/components/shell/nsGNOMEShellService.h rename to browser/components/shell/nsGNOMEShellService.h diff --git a/application/basilisk/components/shell/nsIGNOMEShellService.idl b/browser/components/shell/nsIGNOMEShellService.idl similarity index 100% rename from application/basilisk/components/shell/nsIGNOMEShellService.idl rename to browser/components/shell/nsIGNOMEShellService.idl diff --git a/application/basilisk/components/shell/nsIMacShellService.idl b/browser/components/shell/nsIMacShellService.idl similarity index 100% rename from application/basilisk/components/shell/nsIMacShellService.idl rename to browser/components/shell/nsIMacShellService.idl diff --git a/application/basilisk/components/shell/nsIShellService.idl b/browser/components/shell/nsIShellService.idl similarity index 100% rename from application/basilisk/components/shell/nsIShellService.idl rename to browser/components/shell/nsIShellService.idl diff --git a/application/basilisk/components/shell/nsIWindowsShellService.idl b/browser/components/shell/nsIWindowsShellService.idl similarity index 100% rename from application/basilisk/components/shell/nsIWindowsShellService.idl rename to browser/components/shell/nsIWindowsShellService.idl diff --git a/application/basilisk/components/shell/nsMacShellService.cpp b/browser/components/shell/nsMacShellService.cpp similarity index 100% rename from application/basilisk/components/shell/nsMacShellService.cpp rename to browser/components/shell/nsMacShellService.cpp diff --git a/application/basilisk/components/shell/nsMacShellService.h b/browser/components/shell/nsMacShellService.h similarity index 100% rename from application/basilisk/components/shell/nsMacShellService.h rename to browser/components/shell/nsMacShellService.h diff --git a/application/basilisk/components/shell/nsSetDefaultBrowser.js b/browser/components/shell/nsSetDefaultBrowser.js similarity index 100% rename from application/basilisk/components/shell/nsSetDefaultBrowser.js rename to browser/components/shell/nsSetDefaultBrowser.js diff --git a/application/basilisk/components/shell/nsSetDefaultBrowser.manifest b/browser/components/shell/nsSetDefaultBrowser.manifest similarity index 100% rename from application/basilisk/components/shell/nsSetDefaultBrowser.manifest rename to browser/components/shell/nsSetDefaultBrowser.manifest diff --git a/application/basilisk/components/shell/nsShellService.h b/browser/components/shell/nsShellService.h similarity index 100% rename from application/basilisk/components/shell/nsShellService.h rename to browser/components/shell/nsShellService.h diff --git a/application/basilisk/components/shell/nsWindowsShellService.cpp b/browser/components/shell/nsWindowsShellService.cpp similarity index 100% rename from application/basilisk/components/shell/nsWindowsShellService.cpp rename to browser/components/shell/nsWindowsShellService.cpp diff --git a/application/basilisk/components/shell/nsWindowsShellService.h b/browser/components/shell/nsWindowsShellService.h similarity index 100% rename from application/basilisk/components/shell/nsWindowsShellService.h rename to browser/components/shell/nsWindowsShellService.h diff --git a/application/basilisk/components/sync/aboutSyncTabs-bindings.xml b/browser/components/sync/aboutSyncTabs-bindings.xml similarity index 100% rename from application/basilisk/components/sync/aboutSyncTabs-bindings.xml rename to browser/components/sync/aboutSyncTabs-bindings.xml diff --git a/application/basilisk/components/sync/aboutSyncTabs.css b/browser/components/sync/aboutSyncTabs.css similarity index 100% rename from application/basilisk/components/sync/aboutSyncTabs.css rename to browser/components/sync/aboutSyncTabs.css diff --git a/application/basilisk/components/sync/aboutSyncTabs.js b/browser/components/sync/aboutSyncTabs.js similarity index 100% rename from application/basilisk/components/sync/aboutSyncTabs.js rename to browser/components/sync/aboutSyncTabs.js diff --git a/application/basilisk/components/sync/aboutSyncTabs.xul b/browser/components/sync/aboutSyncTabs.xul similarity index 100% rename from application/basilisk/components/sync/aboutSyncTabs.xul rename to browser/components/sync/aboutSyncTabs.xul diff --git a/application/basilisk/components/sync/addDevice.js b/browser/components/sync/addDevice.js similarity index 100% rename from application/basilisk/components/sync/addDevice.js rename to browser/components/sync/addDevice.js diff --git a/application/basilisk/components/sync/addDevice.xul b/browser/components/sync/addDevice.xul similarity index 100% rename from application/basilisk/components/sync/addDevice.xul rename to browser/components/sync/addDevice.xul diff --git a/application/basilisk/components/sync/genericChange.js b/browser/components/sync/genericChange.js similarity index 100% rename from application/basilisk/components/sync/genericChange.js rename to browser/components/sync/genericChange.js diff --git a/application/basilisk/components/sync/genericChange.xul b/browser/components/sync/genericChange.xul similarity index 100% rename from application/basilisk/components/sync/genericChange.xul rename to browser/components/sync/genericChange.xul diff --git a/application/basilisk/components/sync/jar.mn b/browser/components/sync/jar.mn similarity index 100% rename from application/basilisk/components/sync/jar.mn rename to browser/components/sync/jar.mn diff --git a/application/basilisk/components/sync/key.xhtml b/browser/components/sync/key.xhtml similarity index 100% rename from application/basilisk/components/sync/key.xhtml rename to browser/components/sync/key.xhtml diff --git a/application/basilisk/components/sync/moz.build b/browser/components/sync/moz.build similarity index 100% rename from application/basilisk/components/sync/moz.build rename to browser/components/sync/moz.build diff --git a/application/basilisk/components/sync/notification.xml b/browser/components/sync/notification.xml similarity index 100% rename from application/basilisk/components/sync/notification.xml rename to browser/components/sync/notification.xml diff --git a/application/basilisk/components/sync/progress.js b/browser/components/sync/progress.js similarity index 100% rename from application/basilisk/components/sync/progress.js rename to browser/components/sync/progress.js diff --git a/application/basilisk/components/sync/progress.xhtml b/browser/components/sync/progress.xhtml similarity index 100% rename from application/basilisk/components/sync/progress.xhtml rename to browser/components/sync/progress.xhtml diff --git a/application/basilisk/components/sync/quota.js b/browser/components/sync/quota.js similarity index 100% rename from application/basilisk/components/sync/quota.js rename to browser/components/sync/quota.js diff --git a/application/basilisk/components/sync/quota.xul b/browser/components/sync/quota.xul similarity index 100% rename from application/basilisk/components/sync/quota.xul rename to browser/components/sync/quota.xul diff --git a/application/basilisk/components/sync/setup.js b/browser/components/sync/setup.js similarity index 100% rename from application/basilisk/components/sync/setup.js rename to browser/components/sync/setup.js diff --git a/application/basilisk/components/sync/setup.xul b/browser/components/sync/setup.xul similarity index 100% rename from application/basilisk/components/sync/setup.xul rename to browser/components/sync/setup.xul diff --git a/application/basilisk/components/sync/utils.js b/browser/components/sync/utils.js similarity index 100% rename from application/basilisk/components/sync/utils.js rename to browser/components/sync/utils.js diff --git a/application/basilisk/components/translation/LanguageDetector.jsm b/browser/components/translation/LanguageDetector.jsm similarity index 100% rename from application/basilisk/components/translation/LanguageDetector.jsm rename to browser/components/translation/LanguageDetector.jsm diff --git a/application/basilisk/components/translation/cld2/Makefile b/browser/components/translation/cld2/Makefile similarity index 100% rename from application/basilisk/components/translation/cld2/Makefile rename to browser/components/translation/cld2/Makefile diff --git a/application/basilisk/components/translation/cld2/cld-worker.js b/browser/components/translation/cld2/cld-worker.js similarity index 100% rename from application/basilisk/components/translation/cld2/cld-worker.js rename to browser/components/translation/cld2/cld-worker.js diff --git a/application/basilisk/components/translation/cld2/cld-worker.js.mem b/browser/components/translation/cld2/cld-worker.js.mem similarity index 100% rename from application/basilisk/components/translation/cld2/cld-worker.js.mem rename to browser/components/translation/cld2/cld-worker.js.mem diff --git a/application/basilisk/components/translation/cld2/cld.idl b/browser/components/translation/cld2/cld.idl similarity index 100% rename from application/basilisk/components/translation/cld2/cld.idl rename to browser/components/translation/cld2/cld.idl diff --git a/application/basilisk/components/translation/cld2/cldapp.cc b/browser/components/translation/cld2/cldapp.cc similarity index 100% rename from application/basilisk/components/translation/cld2/cldapp.cc rename to browser/components/translation/cld2/cldapp.cc diff --git a/application/basilisk/components/translation/cld2/internal/LICENSE b/browser/components/translation/cld2/internal/LICENSE similarity index 100% rename from application/basilisk/components/translation/cld2/internal/LICENSE rename to browser/components/translation/cld2/internal/LICENSE diff --git a/application/basilisk/components/translation/cld2/internal/cld2_dynamic_data.h b/browser/components/translation/cld2/internal/cld2_dynamic_data.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld2_dynamic_data.h rename to browser/components/translation/cld2/internal/cld2_dynamic_data.h diff --git a/application/basilisk/components/translation/cld2/internal/cld2_dynamic_data_loader.h b/browser/components/translation/cld2/internal/cld2_dynamic_data_loader.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld2_dynamic_data_loader.h rename to browser/components/translation/cld2/internal/cld2_dynamic_data_loader.h diff --git a/application/basilisk/components/translation/cld2/internal/cld2_generated_cjk_compatible.cc b/browser/components/translation/cld2/internal/cld2_generated_cjk_compatible.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld2_generated_cjk_compatible.cc rename to browser/components/translation/cld2/internal/cld2_generated_cjk_compatible.cc diff --git a/application/basilisk/components/translation/cld2/internal/cld2_generated_deltaoctachrome0122.cc b/browser/components/translation/cld2/internal/cld2_generated_deltaoctachrome0122.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld2_generated_deltaoctachrome0122.cc rename to browser/components/translation/cld2/internal/cld2_generated_deltaoctachrome0122.cc diff --git a/application/basilisk/components/translation/cld2/internal/cld2_generated_distinctoctachrome0122.cc b/browser/components/translation/cld2/internal/cld2_generated_distinctoctachrome0122.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld2_generated_distinctoctachrome0122.cc rename to browser/components/translation/cld2/internal/cld2_generated_distinctoctachrome0122.cc diff --git a/application/basilisk/components/translation/cld2/internal/cld2_generated_quadchrome0122_16.cc b/browser/components/translation/cld2/internal/cld2_generated_quadchrome0122_16.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld2_generated_quadchrome0122_16.cc rename to browser/components/translation/cld2/internal/cld2_generated_quadchrome0122_16.cc diff --git a/application/basilisk/components/translation/cld2/internal/cld2tablesummary.h b/browser/components/translation/cld2/internal/cld2tablesummary.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld2tablesummary.h rename to browser/components/translation/cld2/internal/cld2tablesummary.h diff --git a/application/basilisk/components/translation/cld2/internal/cld_generated_cjk_delta_bi_4.cc b/browser/components/translation/cld2/internal/cld_generated_cjk_delta_bi_4.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld_generated_cjk_delta_bi_4.cc rename to browser/components/translation/cld2/internal/cld_generated_cjk_delta_bi_4.cc diff --git a/application/basilisk/components/translation/cld2/internal/cld_generated_cjk_uni_prop_80.cc b/browser/components/translation/cld2/internal/cld_generated_cjk_uni_prop_80.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld_generated_cjk_uni_prop_80.cc rename to browser/components/translation/cld2/internal/cld_generated_cjk_uni_prop_80.cc diff --git a/application/basilisk/components/translation/cld2/internal/cld_generated_score_quad_octa_0122_2.cc b/browser/components/translation/cld2/internal/cld_generated_score_quad_octa_0122_2.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cld_generated_score_quad_octa_0122_2.cc rename to browser/components/translation/cld2/internal/cld_generated_score_quad_octa_0122_2.cc diff --git a/application/basilisk/components/translation/cld2/internal/cldutil.cc b/browser/components/translation/cld2/internal/cldutil.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cldutil.cc rename to browser/components/translation/cld2/internal/cldutil.cc diff --git a/application/basilisk/components/translation/cld2/internal/cldutil.h b/browser/components/translation/cld2/internal/cldutil.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cldutil.h rename to browser/components/translation/cld2/internal/cldutil.h diff --git a/application/basilisk/components/translation/cld2/internal/cldutil_shared.cc b/browser/components/translation/cld2/internal/cldutil_shared.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cldutil_shared.cc rename to browser/components/translation/cld2/internal/cldutil_shared.cc diff --git a/application/basilisk/components/translation/cld2/internal/cldutil_shared.h b/browser/components/translation/cld2/internal/cldutil_shared.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/cldutil_shared.h rename to browser/components/translation/cld2/internal/cldutil_shared.h diff --git a/application/basilisk/components/translation/cld2/internal/compact_lang_det.cc b/browser/components/translation/cld2/internal/compact_lang_det.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/compact_lang_det.cc rename to browser/components/translation/cld2/internal/compact_lang_det.cc diff --git a/application/basilisk/components/translation/cld2/internal/compact_lang_det_hint_code.cc b/browser/components/translation/cld2/internal/compact_lang_det_hint_code.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/compact_lang_det_hint_code.cc rename to browser/components/translation/cld2/internal/compact_lang_det_hint_code.cc diff --git a/application/basilisk/components/translation/cld2/internal/compact_lang_det_hint_code.h b/browser/components/translation/cld2/internal/compact_lang_det_hint_code.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/compact_lang_det_hint_code.h rename to browser/components/translation/cld2/internal/compact_lang_det_hint_code.h diff --git a/application/basilisk/components/translation/cld2/internal/compact_lang_det_impl.cc b/browser/components/translation/cld2/internal/compact_lang_det_impl.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/compact_lang_det_impl.cc rename to browser/components/translation/cld2/internal/compact_lang_det_impl.cc diff --git a/application/basilisk/components/translation/cld2/internal/compact_lang_det_impl.h b/browser/components/translation/cld2/internal/compact_lang_det_impl.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/compact_lang_det_impl.h rename to browser/components/translation/cld2/internal/compact_lang_det_impl.h diff --git a/application/basilisk/components/translation/cld2/internal/debug.h b/browser/components/translation/cld2/internal/debug.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/debug.h rename to browser/components/translation/cld2/internal/debug.h diff --git a/application/basilisk/components/translation/cld2/internal/debug_empty.cc b/browser/components/translation/cld2/internal/debug_empty.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/debug_empty.cc rename to browser/components/translation/cld2/internal/debug_empty.cc diff --git a/application/basilisk/components/translation/cld2/internal/fixunicodevalue.cc b/browser/components/translation/cld2/internal/fixunicodevalue.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/fixunicodevalue.cc rename to browser/components/translation/cld2/internal/fixunicodevalue.cc diff --git a/application/basilisk/components/translation/cld2/internal/fixunicodevalue.h b/browser/components/translation/cld2/internal/fixunicodevalue.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/fixunicodevalue.h rename to browser/components/translation/cld2/internal/fixunicodevalue.h diff --git a/application/basilisk/components/translation/cld2/internal/generated_distinct_bi_0.cc b/browser/components/translation/cld2/internal/generated_distinct_bi_0.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/generated_distinct_bi_0.cc rename to browser/components/translation/cld2/internal/generated_distinct_bi_0.cc diff --git a/application/basilisk/components/translation/cld2/internal/generated_entities.cc b/browser/components/translation/cld2/internal/generated_entities.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/generated_entities.cc rename to browser/components/translation/cld2/internal/generated_entities.cc diff --git a/application/basilisk/components/translation/cld2/internal/generated_language.cc b/browser/components/translation/cld2/internal/generated_language.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/generated_language.cc rename to browser/components/translation/cld2/internal/generated_language.cc diff --git a/application/basilisk/components/translation/cld2/internal/generated_language.h b/browser/components/translation/cld2/internal/generated_language.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/generated_language.h rename to browser/components/translation/cld2/internal/generated_language.h diff --git a/application/basilisk/components/translation/cld2/internal/generated_ulscript.cc b/browser/components/translation/cld2/internal/generated_ulscript.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/generated_ulscript.cc rename to browser/components/translation/cld2/internal/generated_ulscript.cc diff --git a/application/basilisk/components/translation/cld2/internal/generated_ulscript.h b/browser/components/translation/cld2/internal/generated_ulscript.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/generated_ulscript.h rename to browser/components/translation/cld2/internal/generated_ulscript.h diff --git a/application/basilisk/components/translation/cld2/internal/getonescriptspan.cc b/browser/components/translation/cld2/internal/getonescriptspan.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/getonescriptspan.cc rename to browser/components/translation/cld2/internal/getonescriptspan.cc diff --git a/application/basilisk/components/translation/cld2/internal/getonescriptspan.h b/browser/components/translation/cld2/internal/getonescriptspan.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/getonescriptspan.h rename to browser/components/translation/cld2/internal/getonescriptspan.h diff --git a/application/basilisk/components/translation/cld2/internal/integral_types.h b/browser/components/translation/cld2/internal/integral_types.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/integral_types.h rename to browser/components/translation/cld2/internal/integral_types.h diff --git a/application/basilisk/components/translation/cld2/internal/lang_script.cc b/browser/components/translation/cld2/internal/lang_script.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/lang_script.cc rename to browser/components/translation/cld2/internal/lang_script.cc diff --git a/application/basilisk/components/translation/cld2/internal/lang_script.h b/browser/components/translation/cld2/internal/lang_script.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/lang_script.h rename to browser/components/translation/cld2/internal/lang_script.h diff --git a/application/basilisk/components/translation/cld2/internal/langspan.h b/browser/components/translation/cld2/internal/langspan.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/langspan.h rename to browser/components/translation/cld2/internal/langspan.h diff --git a/application/basilisk/components/translation/cld2/internal/offsetmap.cc b/browser/components/translation/cld2/internal/offsetmap.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/offsetmap.cc rename to browser/components/translation/cld2/internal/offsetmap.cc diff --git a/application/basilisk/components/translation/cld2/internal/offsetmap.h b/browser/components/translation/cld2/internal/offsetmap.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/offsetmap.h rename to browser/components/translation/cld2/internal/offsetmap.h diff --git a/application/basilisk/components/translation/cld2/internal/port.h b/browser/components/translation/cld2/internal/port.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/port.h rename to browser/components/translation/cld2/internal/port.h diff --git a/application/basilisk/components/translation/cld2/internal/scoreonescriptspan.cc b/browser/components/translation/cld2/internal/scoreonescriptspan.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/scoreonescriptspan.cc rename to browser/components/translation/cld2/internal/scoreonescriptspan.cc diff --git a/application/basilisk/components/translation/cld2/internal/scoreonescriptspan.h b/browser/components/translation/cld2/internal/scoreonescriptspan.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/scoreonescriptspan.h rename to browser/components/translation/cld2/internal/scoreonescriptspan.h diff --git a/application/basilisk/components/translation/cld2/internal/stringpiece.h b/browser/components/translation/cld2/internal/stringpiece.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/stringpiece.h rename to browser/components/translation/cld2/internal/stringpiece.h diff --git a/application/basilisk/components/translation/cld2/internal/tote.cc b/browser/components/translation/cld2/internal/tote.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/tote.cc rename to browser/components/translation/cld2/internal/tote.cc diff --git a/application/basilisk/components/translation/cld2/internal/tote.h b/browser/components/translation/cld2/internal/tote.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/tote.h rename to browser/components/translation/cld2/internal/tote.h diff --git a/application/basilisk/components/translation/cld2/internal/utf8prop_lettermarkscriptnum.h b/browser/components/translation/cld2/internal/utf8prop_lettermarkscriptnum.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/utf8prop_lettermarkscriptnum.h rename to browser/components/translation/cld2/internal/utf8prop_lettermarkscriptnum.h diff --git a/application/basilisk/components/translation/cld2/internal/utf8repl_lettermarklower.h b/browser/components/translation/cld2/internal/utf8repl_lettermarklower.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/utf8repl_lettermarklower.h rename to browser/components/translation/cld2/internal/utf8repl_lettermarklower.h diff --git a/application/basilisk/components/translation/cld2/internal/utf8scannot_lettermarkspecial.h b/browser/components/translation/cld2/internal/utf8scannot_lettermarkspecial.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/utf8scannot_lettermarkspecial.h rename to browser/components/translation/cld2/internal/utf8scannot_lettermarkspecial.h diff --git a/application/basilisk/components/translation/cld2/internal/utf8statetable.cc b/browser/components/translation/cld2/internal/utf8statetable.cc similarity index 100% rename from application/basilisk/components/translation/cld2/internal/utf8statetable.cc rename to browser/components/translation/cld2/internal/utf8statetable.cc diff --git a/application/basilisk/components/translation/cld2/internal/utf8statetable.h b/browser/components/translation/cld2/internal/utf8statetable.h similarity index 100% rename from application/basilisk/components/translation/cld2/internal/utf8statetable.h rename to browser/components/translation/cld2/internal/utf8statetable.h diff --git a/application/basilisk/components/translation/cld2/post.js b/browser/components/translation/cld2/post.js similarity index 100% rename from application/basilisk/components/translation/cld2/post.js rename to browser/components/translation/cld2/post.js diff --git a/application/basilisk/components/translation/cld2/public/compact_lang_det.h b/browser/components/translation/cld2/public/compact_lang_det.h similarity index 100% rename from application/basilisk/components/translation/cld2/public/compact_lang_det.h rename to browser/components/translation/cld2/public/compact_lang_det.h diff --git a/application/basilisk/components/translation/cld2/public/encodings.h b/browser/components/translation/cld2/public/encodings.h similarity index 100% rename from application/basilisk/components/translation/cld2/public/encodings.h rename to browser/components/translation/cld2/public/encodings.h diff --git a/application/basilisk/components/translation/moz.build b/browser/components/translation/moz.build similarity index 100% rename from application/basilisk/components/translation/moz.build rename to browser/components/translation/moz.build diff --git a/application/basilisk/components/webextensions/.eslintrc.js b/browser/components/webextensions/.eslintrc.js similarity index 100% rename from application/basilisk/components/webextensions/.eslintrc.js rename to browser/components/webextensions/.eslintrc.js diff --git a/application/basilisk/components/webextensions/ext-bookmarks.js b/browser/components/webextensions/ext-bookmarks.js similarity index 100% rename from application/basilisk/components/webextensions/ext-bookmarks.js rename to browser/components/webextensions/ext-bookmarks.js diff --git a/application/basilisk/components/webextensions/ext-browserAction.js b/browser/components/webextensions/ext-browserAction.js similarity index 100% rename from application/basilisk/components/webextensions/ext-browserAction.js rename to browser/components/webextensions/ext-browserAction.js diff --git a/application/basilisk/components/webextensions/ext-c-contextMenus.js b/browser/components/webextensions/ext-c-contextMenus.js similarity index 100% rename from application/basilisk/components/webextensions/ext-c-contextMenus.js rename to browser/components/webextensions/ext-c-contextMenus.js diff --git a/application/basilisk/components/webextensions/ext-c-omnibox.js b/browser/components/webextensions/ext-c-omnibox.js similarity index 100% rename from application/basilisk/components/webextensions/ext-c-omnibox.js rename to browser/components/webextensions/ext-c-omnibox.js diff --git a/application/basilisk/components/webextensions/ext-c-tabs.js b/browser/components/webextensions/ext-c-tabs.js similarity index 100% rename from application/basilisk/components/webextensions/ext-c-tabs.js rename to browser/components/webextensions/ext-c-tabs.js diff --git a/application/basilisk/components/webextensions/ext-commands.js b/browser/components/webextensions/ext-commands.js similarity index 100% rename from application/basilisk/components/webextensions/ext-commands.js rename to browser/components/webextensions/ext-commands.js diff --git a/application/basilisk/components/webextensions/ext-contextMenus.js b/browser/components/webextensions/ext-contextMenus.js similarity index 100% rename from application/basilisk/components/webextensions/ext-contextMenus.js rename to browser/components/webextensions/ext-contextMenus.js diff --git a/application/basilisk/components/webextensions/ext-desktop-runtime.js b/browser/components/webextensions/ext-desktop-runtime.js similarity index 100% rename from application/basilisk/components/webextensions/ext-desktop-runtime.js rename to browser/components/webextensions/ext-desktop-runtime.js diff --git a/application/basilisk/components/webextensions/ext-history.js b/browser/components/webextensions/ext-history.js similarity index 100% rename from application/basilisk/components/webextensions/ext-history.js rename to browser/components/webextensions/ext-history.js diff --git a/application/basilisk/components/webextensions/ext-omnibox.js b/browser/components/webextensions/ext-omnibox.js similarity index 100% rename from application/basilisk/components/webextensions/ext-omnibox.js rename to browser/components/webextensions/ext-omnibox.js diff --git a/application/basilisk/components/webextensions/ext-pageAction.js b/browser/components/webextensions/ext-pageAction.js similarity index 100% rename from application/basilisk/components/webextensions/ext-pageAction.js rename to browser/components/webextensions/ext-pageAction.js diff --git a/application/basilisk/components/webextensions/ext-sessions.js b/browser/components/webextensions/ext-sessions.js similarity index 100% rename from application/basilisk/components/webextensions/ext-sessions.js rename to browser/components/webextensions/ext-sessions.js diff --git a/application/basilisk/components/webextensions/ext-tabs.js b/browser/components/webextensions/ext-tabs.js similarity index 100% rename from application/basilisk/components/webextensions/ext-tabs.js rename to browser/components/webextensions/ext-tabs.js diff --git a/application/basilisk/components/webextensions/ext-utils.js b/browser/components/webextensions/ext-utils.js similarity index 100% rename from application/basilisk/components/webextensions/ext-utils.js rename to browser/components/webextensions/ext-utils.js diff --git a/application/basilisk/components/webextensions/ext-windows.js b/browser/components/webextensions/ext-windows.js similarity index 100% rename from application/basilisk/components/webextensions/ext-windows.js rename to browser/components/webextensions/ext-windows.js diff --git a/application/basilisk/components/webextensions/extension-mac-panel.css b/browser/components/webextensions/extension-mac-panel.css similarity index 100% rename from application/basilisk/components/webextensions/extension-mac-panel.css rename to browser/components/webextensions/extension-mac-panel.css diff --git a/application/basilisk/components/webextensions/extension-mac.css b/browser/components/webextensions/extension-mac.css similarity index 100% rename from application/basilisk/components/webextensions/extension-mac.css rename to browser/components/webextensions/extension-mac.css diff --git a/application/basilisk/components/webextensions/extension-win-panel.css b/browser/components/webextensions/extension-win-panel.css similarity index 100% rename from application/basilisk/components/webextensions/extension-win-panel.css rename to browser/components/webextensions/extension-win-panel.css diff --git a/application/basilisk/components/webextensions/extension.css b/browser/components/webextensions/extension.css similarity index 100% rename from application/basilisk/components/webextensions/extension.css rename to browser/components/webextensions/extension.css diff --git a/application/basilisk/components/webextensions/extension.svg b/browser/components/webextensions/extension.svg similarity index 100% rename from application/basilisk/components/webextensions/extension.svg rename to browser/components/webextensions/extension.svg diff --git a/application/basilisk/components/webextensions/extensions-browser.manifest b/browser/components/webextensions/extensions-browser.manifest similarity index 100% rename from application/basilisk/components/webextensions/extensions-browser.manifest rename to browser/components/webextensions/extensions-browser.manifest diff --git a/application/basilisk/components/webextensions/jar.mn b/browser/components/webextensions/jar.mn similarity index 100% rename from application/basilisk/components/webextensions/jar.mn rename to browser/components/webextensions/jar.mn diff --git a/application/basilisk/components/webextensions/moz.build b/browser/components/webextensions/moz.build similarity index 100% rename from application/basilisk/components/webextensions/moz.build rename to browser/components/webextensions/moz.build diff --git a/application/basilisk/components/webextensions/schemas/LICENSE b/browser/components/webextensions/schemas/LICENSE similarity index 100% rename from application/basilisk/components/webextensions/schemas/LICENSE rename to browser/components/webextensions/schemas/LICENSE diff --git a/application/basilisk/components/webextensions/schemas/bookmarks.json b/browser/components/webextensions/schemas/bookmarks.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/bookmarks.json rename to browser/components/webextensions/schemas/bookmarks.json diff --git a/application/basilisk/components/webextensions/schemas/browser_action.json b/browser/components/webextensions/schemas/browser_action.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/browser_action.json rename to browser/components/webextensions/schemas/browser_action.json diff --git a/application/basilisk/components/webextensions/schemas/commands.json b/browser/components/webextensions/schemas/commands.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/commands.json rename to browser/components/webextensions/schemas/commands.json diff --git a/application/basilisk/components/webextensions/schemas/context_menus.json b/browser/components/webextensions/schemas/context_menus.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/context_menus.json rename to browser/components/webextensions/schemas/context_menus.json diff --git a/application/basilisk/components/webextensions/schemas/context_menus_internal.json b/browser/components/webextensions/schemas/context_menus_internal.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/context_menus_internal.json rename to browser/components/webextensions/schemas/context_menus_internal.json diff --git a/application/basilisk/components/webextensions/schemas/history.json b/browser/components/webextensions/schemas/history.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/history.json rename to browser/components/webextensions/schemas/history.json diff --git a/application/basilisk/components/webextensions/schemas/jar.mn b/browser/components/webextensions/schemas/jar.mn similarity index 100% rename from application/basilisk/components/webextensions/schemas/jar.mn rename to browser/components/webextensions/schemas/jar.mn diff --git a/application/basilisk/components/webextensions/schemas/moz.build b/browser/components/webextensions/schemas/moz.build similarity index 100% rename from application/basilisk/components/webextensions/schemas/moz.build rename to browser/components/webextensions/schemas/moz.build diff --git a/application/basilisk/components/webextensions/schemas/omnibox.json b/browser/components/webextensions/schemas/omnibox.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/omnibox.json rename to browser/components/webextensions/schemas/omnibox.json diff --git a/application/basilisk/components/webextensions/schemas/page_action.json b/browser/components/webextensions/schemas/page_action.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/page_action.json rename to browser/components/webextensions/schemas/page_action.json diff --git a/application/basilisk/components/webextensions/schemas/sessions.json b/browser/components/webextensions/schemas/sessions.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/sessions.json rename to browser/components/webextensions/schemas/sessions.json diff --git a/application/basilisk/components/webextensions/schemas/tabs.json b/browser/components/webextensions/schemas/tabs.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/tabs.json rename to browser/components/webextensions/schemas/tabs.json diff --git a/application/basilisk/components/webextensions/schemas/windows.json b/browser/components/webextensions/schemas/windows.json similarity index 100% rename from application/basilisk/components/webextensions/schemas/windows.json rename to browser/components/webextensions/schemas/windows.json diff --git a/application/basilisk/config/mozconfig b/browser/config/mozconfig similarity index 100% rename from application/basilisk/config/mozconfig rename to browser/config/mozconfig diff --git a/application/basilisk/config/mozconfigs/common b/browser/config/mozconfigs/common similarity index 100% rename from application/basilisk/config/mozconfigs/common rename to browser/config/mozconfigs/common diff --git a/application/basilisk/config/mozconfigs/linux32/artifact b/browser/config/mozconfigs/linux32/artifact similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/artifact rename to browser/config/mozconfigs/linux32/artifact diff --git a/application/basilisk/config/mozconfigs/linux32/beta b/browser/config/mozconfigs/linux32/beta similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/beta rename to browser/config/mozconfigs/linux32/beta diff --git a/application/basilisk/config/mozconfigs/linux32/common-opt b/browser/config/mozconfigs/linux32/common-opt similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/common-opt rename to browser/config/mozconfigs/linux32/common-opt diff --git a/application/basilisk/config/mozconfigs/linux32/debug b/browser/config/mozconfigs/linux32/debug similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/debug rename to browser/config/mozconfigs/linux32/debug diff --git a/application/basilisk/config/mozconfigs/linux32/debug-artifact b/browser/config/mozconfigs/linux32/debug-artifact similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/debug-artifact rename to browser/config/mozconfigs/linux32/debug-artifact diff --git a/application/basilisk/config/mozconfigs/linux32/debug-asan b/browser/config/mozconfigs/linux32/debug-asan similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/debug-asan rename to browser/config/mozconfigs/linux32/debug-asan diff --git a/application/basilisk/config/mozconfigs/linux32/l10n-mozconfig b/browser/config/mozconfigs/linux32/l10n-mozconfig similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/l10n-mozconfig rename to browser/config/mozconfigs/linux32/l10n-mozconfig diff --git a/application/basilisk/config/mozconfigs/linux32/nightly b/browser/config/mozconfigs/linux32/nightly similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/nightly rename to browser/config/mozconfigs/linux32/nightly diff --git a/application/basilisk/config/mozconfigs/linux32/nightly-asan b/browser/config/mozconfigs/linux32/nightly-asan similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/nightly-asan rename to browser/config/mozconfigs/linux32/nightly-asan diff --git a/application/basilisk/config/mozconfigs/linux32/release b/browser/config/mozconfigs/linux32/release similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/release rename to browser/config/mozconfigs/linux32/release diff --git a/application/basilisk/config/mozconfigs/linux32/valgrind b/browser/config/mozconfigs/linux32/valgrind similarity index 100% rename from application/basilisk/config/mozconfigs/linux32/valgrind rename to browser/config/mozconfigs/linux32/valgrind diff --git a/application/basilisk/config/mozconfigs/linux64/add-on-devel b/browser/config/mozconfigs/linux64/add-on-devel similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/add-on-devel rename to browser/config/mozconfigs/linux64/add-on-devel diff --git a/application/basilisk/config/mozconfigs/linux64/artifact b/browser/config/mozconfigs/linux64/artifact similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/artifact rename to browser/config/mozconfigs/linux64/artifact diff --git a/application/basilisk/config/mozconfigs/linux64/beta b/browser/config/mozconfigs/linux64/beta similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/beta rename to browser/config/mozconfigs/linux64/beta diff --git a/application/basilisk/config/mozconfigs/linux64/code-coverage b/browser/config/mozconfigs/linux64/code-coverage similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/code-coverage rename to browser/config/mozconfigs/linux64/code-coverage diff --git a/application/basilisk/config/mozconfigs/linux64/common-opt b/browser/config/mozconfigs/linux64/common-opt similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/common-opt rename to browser/config/mozconfigs/linux64/common-opt diff --git a/application/basilisk/config/mozconfigs/linux64/debug b/browser/config/mozconfigs/linux64/debug similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/debug rename to browser/config/mozconfigs/linux64/debug diff --git a/application/basilisk/config/mozconfigs/linux64/debug-artifact b/browser/config/mozconfigs/linux64/debug-artifact similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/debug-artifact rename to browser/config/mozconfigs/linux64/debug-artifact diff --git a/application/basilisk/config/mozconfigs/linux64/debug-asan b/browser/config/mozconfigs/linux64/debug-asan similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/debug-asan rename to browser/config/mozconfigs/linux64/debug-asan diff --git a/application/basilisk/config/mozconfigs/linux64/debug-static-analysis-clang b/browser/config/mozconfigs/linux64/debug-static-analysis-clang similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/debug-static-analysis-clang rename to browser/config/mozconfigs/linux64/debug-static-analysis-clang diff --git a/application/basilisk/config/mozconfigs/linux64/hazards b/browser/config/mozconfigs/linux64/hazards similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/hazards rename to browser/config/mozconfigs/linux64/hazards diff --git a/application/basilisk/config/mozconfigs/linux64/l10n-mozconfig b/browser/config/mozconfigs/linux64/l10n-mozconfig similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/l10n-mozconfig rename to browser/config/mozconfigs/linux64/l10n-mozconfig diff --git a/application/basilisk/config/mozconfigs/linux64/nightly b/browser/config/mozconfigs/linux64/nightly similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/nightly rename to browser/config/mozconfigs/linux64/nightly diff --git a/application/basilisk/config/mozconfigs/linux64/nightly-asan b/browser/config/mozconfigs/linux64/nightly-asan similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/nightly-asan rename to browser/config/mozconfigs/linux64/nightly-asan diff --git a/application/basilisk/config/mozconfigs/linux64/opt-static-analysis-clang b/browser/config/mozconfigs/linux64/opt-static-analysis-clang similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/opt-static-analysis-clang rename to browser/config/mozconfigs/linux64/opt-static-analysis-clang diff --git a/application/basilisk/config/mozconfigs/linux64/opt-tsan b/browser/config/mozconfigs/linux64/opt-tsan similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/opt-tsan rename to browser/config/mozconfigs/linux64/opt-tsan diff --git a/application/basilisk/config/mozconfigs/linux64/release b/browser/config/mozconfigs/linux64/release similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/release rename to browser/config/mozconfigs/linux64/release diff --git a/application/basilisk/config/mozconfigs/linux64/source b/browser/config/mozconfigs/linux64/source similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/source rename to browser/config/mozconfigs/linux64/source diff --git a/application/basilisk/config/mozconfigs/linux64/valgrind b/browser/config/mozconfigs/linux64/valgrind similarity index 100% rename from application/basilisk/config/mozconfigs/linux64/valgrind rename to browser/config/mozconfigs/linux64/valgrind diff --git a/application/basilisk/config/mozconfigs/macosx-universal/beta b/browser/config/mozconfigs/macosx-universal/beta similarity index 100% rename from application/basilisk/config/mozconfigs/macosx-universal/beta rename to browser/config/mozconfigs/macosx-universal/beta diff --git a/application/basilisk/config/mozconfigs/macosx-universal/common-opt b/browser/config/mozconfigs/macosx-universal/common-opt similarity index 100% rename from application/basilisk/config/mozconfigs/macosx-universal/common-opt rename to browser/config/mozconfigs/macosx-universal/common-opt diff --git a/application/basilisk/config/mozconfigs/macosx-universal/l10n-mozconfig b/browser/config/mozconfigs/macosx-universal/l10n-mozconfig similarity index 100% rename from application/basilisk/config/mozconfigs/macosx-universal/l10n-mozconfig rename to browser/config/mozconfigs/macosx-universal/l10n-mozconfig diff --git a/application/basilisk/config/mozconfigs/macosx-universal/nightly b/browser/config/mozconfigs/macosx-universal/nightly similarity index 100% rename from application/basilisk/config/mozconfigs/macosx-universal/nightly rename to browser/config/mozconfigs/macosx-universal/nightly diff --git a/application/basilisk/config/mozconfigs/macosx-universal/release b/browser/config/mozconfigs/macosx-universal/release similarity index 100% rename from application/basilisk/config/mozconfigs/macosx-universal/release rename to browser/config/mozconfigs/macosx-universal/release diff --git a/application/basilisk/config/mozconfigs/macosx64/add-on-devel b/browser/config/mozconfigs/macosx64/add-on-devel similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/add-on-devel rename to browser/config/mozconfigs/macosx64/add-on-devel diff --git a/application/basilisk/config/mozconfigs/macosx64/artifact b/browser/config/mozconfigs/macosx64/artifact similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/artifact rename to browser/config/mozconfigs/macosx64/artifact diff --git a/application/basilisk/config/mozconfigs/macosx64/debug b/browser/config/mozconfigs/macosx64/debug similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/debug rename to browser/config/mozconfigs/macosx64/debug diff --git a/application/basilisk/config/mozconfigs/macosx64/debug-artifact b/browser/config/mozconfigs/macosx64/debug-artifact similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/debug-artifact rename to browser/config/mozconfigs/macosx64/debug-artifact diff --git a/application/basilisk/config/mozconfigs/macosx64/debug-asan b/browser/config/mozconfigs/macosx64/debug-asan similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/debug-asan rename to browser/config/mozconfigs/macosx64/debug-asan diff --git a/application/basilisk/config/mozconfigs/macosx64/debug-static-analysis b/browser/config/mozconfigs/macosx64/debug-static-analysis similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/debug-static-analysis rename to browser/config/mozconfigs/macosx64/debug-static-analysis diff --git a/application/basilisk/config/mozconfigs/macosx64/l10n-mozconfig b/browser/config/mozconfigs/macosx64/l10n-mozconfig similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/l10n-mozconfig rename to browser/config/mozconfigs/macosx64/l10n-mozconfig diff --git a/application/basilisk/config/mozconfigs/macosx64/nightly b/browser/config/mozconfigs/macosx64/nightly similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/nightly rename to browser/config/mozconfigs/macosx64/nightly diff --git a/application/basilisk/config/mozconfigs/macosx64/opt-static-analysis b/browser/config/mozconfigs/macosx64/opt-static-analysis similarity index 100% rename from application/basilisk/config/mozconfigs/macosx64/opt-static-analysis rename to browser/config/mozconfigs/macosx64/opt-static-analysis diff --git a/application/basilisk/config/mozconfigs/whitelist b/browser/config/mozconfigs/whitelist similarity index 100% rename from application/basilisk/config/mozconfigs/whitelist rename to browser/config/mozconfigs/whitelist diff --git a/application/basilisk/config/mozconfigs/win32/add-on-devel b/browser/config/mozconfigs/win32/add-on-devel similarity index 100% rename from application/basilisk/config/mozconfigs/win32/add-on-devel rename to browser/config/mozconfigs/win32/add-on-devel diff --git a/application/basilisk/config/mozconfigs/win32/artifact b/browser/config/mozconfigs/win32/artifact similarity index 100% rename from application/basilisk/config/mozconfigs/win32/artifact rename to browser/config/mozconfigs/win32/artifact diff --git a/application/basilisk/config/mozconfigs/win32/beta b/browser/config/mozconfigs/win32/beta similarity index 100% rename from application/basilisk/config/mozconfigs/win32/beta rename to browser/config/mozconfigs/win32/beta diff --git a/application/basilisk/config/mozconfigs/win32/common-opt b/browser/config/mozconfigs/win32/common-opt similarity index 100% rename from application/basilisk/config/mozconfigs/win32/common-opt rename to browser/config/mozconfigs/win32/common-opt diff --git a/application/basilisk/config/mozconfigs/win32/debug b/browser/config/mozconfigs/win32/debug similarity index 100% rename from application/basilisk/config/mozconfigs/win32/debug rename to browser/config/mozconfigs/win32/debug diff --git a/application/basilisk/config/mozconfigs/win32/debug-artifact b/browser/config/mozconfigs/win32/debug-artifact similarity index 100% rename from application/basilisk/config/mozconfigs/win32/debug-artifact rename to browser/config/mozconfigs/win32/debug-artifact diff --git a/application/basilisk/config/mozconfigs/win32/debug-static-analysis b/browser/config/mozconfigs/win32/debug-static-analysis similarity index 100% rename from application/basilisk/config/mozconfigs/win32/debug-static-analysis rename to browser/config/mozconfigs/win32/debug-static-analysis diff --git a/application/basilisk/config/mozconfigs/win32/l10n-mozconfig b/browser/config/mozconfigs/win32/l10n-mozconfig similarity index 100% rename from application/basilisk/config/mozconfigs/win32/l10n-mozconfig rename to browser/config/mozconfigs/win32/l10n-mozconfig diff --git a/application/basilisk/config/mozconfigs/win32/nightly b/browser/config/mozconfigs/win32/nightly similarity index 100% rename from application/basilisk/config/mozconfigs/win32/nightly rename to browser/config/mozconfigs/win32/nightly diff --git a/application/basilisk/config/mozconfigs/win32/release b/browser/config/mozconfigs/win32/release similarity index 100% rename from application/basilisk/config/mozconfigs/win32/release rename to browser/config/mozconfigs/win32/release diff --git a/application/basilisk/config/mozconfigs/win64/add-on-devel b/browser/config/mozconfigs/win64/add-on-devel similarity index 100% rename from application/basilisk/config/mozconfigs/win64/add-on-devel rename to browser/config/mozconfigs/win64/add-on-devel diff --git a/application/basilisk/config/mozconfigs/win64/artifact b/browser/config/mozconfigs/win64/artifact similarity index 100% rename from application/basilisk/config/mozconfigs/win64/artifact rename to browser/config/mozconfigs/win64/artifact diff --git a/application/basilisk/config/mozconfigs/win64/beta b/browser/config/mozconfigs/win64/beta similarity index 100% rename from application/basilisk/config/mozconfigs/win64/beta rename to browser/config/mozconfigs/win64/beta diff --git a/application/basilisk/config/mozconfigs/win64/common-opt b/browser/config/mozconfigs/win64/common-opt similarity index 100% rename from application/basilisk/config/mozconfigs/win64/common-opt rename to browser/config/mozconfigs/win64/common-opt diff --git a/application/basilisk/config/mozconfigs/win64/common-win64 b/browser/config/mozconfigs/win64/common-win64 similarity index 100% rename from application/basilisk/config/mozconfigs/win64/common-win64 rename to browser/config/mozconfigs/win64/common-win64 diff --git a/application/basilisk/config/mozconfigs/win64/debug b/browser/config/mozconfigs/win64/debug similarity index 100% rename from application/basilisk/config/mozconfigs/win64/debug rename to browser/config/mozconfigs/win64/debug diff --git a/application/basilisk/config/mozconfigs/win64/debug-artifact b/browser/config/mozconfigs/win64/debug-artifact similarity index 100% rename from application/basilisk/config/mozconfigs/win64/debug-artifact rename to browser/config/mozconfigs/win64/debug-artifact diff --git a/application/basilisk/config/mozconfigs/win64/l10n-mozconfig b/browser/config/mozconfigs/win64/l10n-mozconfig similarity index 100% rename from application/basilisk/config/mozconfigs/win64/l10n-mozconfig rename to browser/config/mozconfigs/win64/l10n-mozconfig diff --git a/application/basilisk/config/mozconfigs/win64/nightly b/browser/config/mozconfigs/win64/nightly similarity index 100% rename from application/basilisk/config/mozconfigs/win64/nightly rename to browser/config/mozconfigs/win64/nightly diff --git a/application/basilisk/config/mozconfigs/win64/release b/browser/config/mozconfigs/win64/release similarity index 100% rename from application/basilisk/config/mozconfigs/win64/release rename to browser/config/mozconfigs/win64/release diff --git a/application/basilisk/config/tooltool-manifests/linux32/clang.manifest b/browser/config/tooltool-manifests/linux32/clang.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux32/clang.manifest rename to browser/config/tooltool-manifests/linux32/clang.manifest diff --git a/application/basilisk/config/tooltool-manifests/linux32/releng.manifest b/browser/config/tooltool-manifests/linux32/releng.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux32/releng.manifest rename to browser/config/tooltool-manifests/linux32/releng.manifest diff --git a/application/basilisk/config/tooltool-manifests/linux64/asan.manifest b/browser/config/tooltool-manifests/linux64/asan.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux64/asan.manifest rename to browser/config/tooltool-manifests/linux64/asan.manifest diff --git a/application/basilisk/config/tooltool-manifests/linux64/clang.manifest b/browser/config/tooltool-manifests/linux64/clang.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux64/clang.manifest rename to browser/config/tooltool-manifests/linux64/clang.manifest diff --git a/application/basilisk/config/tooltool-manifests/linux64/clang.manifest.centos6 b/browser/config/tooltool-manifests/linux64/clang.manifest.centos6 similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux64/clang.manifest.centos6 rename to browser/config/tooltool-manifests/linux64/clang.manifest.centos6 diff --git a/application/basilisk/config/tooltool-manifests/linux64/hazard.manifest b/browser/config/tooltool-manifests/linux64/hazard.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux64/hazard.manifest rename to browser/config/tooltool-manifests/linux64/hazard.manifest diff --git a/application/basilisk/config/tooltool-manifests/linux64/msan.manifest b/browser/config/tooltool-manifests/linux64/msan.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux64/msan.manifest rename to browser/config/tooltool-manifests/linux64/msan.manifest diff --git a/application/basilisk/config/tooltool-manifests/linux64/releng.manifest b/browser/config/tooltool-manifests/linux64/releng.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux64/releng.manifest rename to browser/config/tooltool-manifests/linux64/releng.manifest diff --git a/application/basilisk/config/tooltool-manifests/linux64/tsan.manifest b/browser/config/tooltool-manifests/linux64/tsan.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/linux64/tsan.manifest rename to browser/config/tooltool-manifests/linux64/tsan.manifest diff --git a/application/basilisk/config/tooltool-manifests/macosx64/asan.manifest b/browser/config/tooltool-manifests/macosx64/asan.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/macosx64/asan.manifest rename to browser/config/tooltool-manifests/macosx64/asan.manifest diff --git a/application/basilisk/config/tooltool-manifests/macosx64/clang.manifest b/browser/config/tooltool-manifests/macosx64/clang.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/macosx64/clang.manifest rename to browser/config/tooltool-manifests/macosx64/clang.manifest diff --git a/application/basilisk/config/tooltool-manifests/macosx64/cross-releng.manifest b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/macosx64/cross-releng.manifest rename to browser/config/tooltool-manifests/macosx64/cross-releng.manifest diff --git a/application/basilisk/config/tooltool-manifests/macosx64/releng.manifest b/browser/config/tooltool-manifests/macosx64/releng.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/macosx64/releng.manifest rename to browser/config/tooltool-manifests/macosx64/releng.manifest diff --git a/application/basilisk/config/tooltool-manifests/win32/build-clang-cl.manifest b/browser/config/tooltool-manifests/win32/build-clang-cl.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/win32/build-clang-cl.manifest rename to browser/config/tooltool-manifests/win32/build-clang-cl.manifest diff --git a/application/basilisk/config/tooltool-manifests/win32/clang.manifest b/browser/config/tooltool-manifests/win32/clang.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/win32/clang.manifest rename to browser/config/tooltool-manifests/win32/clang.manifest diff --git a/application/basilisk/config/tooltool-manifests/win32/l10n.manifest b/browser/config/tooltool-manifests/win32/l10n.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/win32/l10n.manifest rename to browser/config/tooltool-manifests/win32/l10n.manifest diff --git a/application/basilisk/config/tooltool-manifests/win32/releng.manifest b/browser/config/tooltool-manifests/win32/releng.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/win32/releng.manifest rename to browser/config/tooltool-manifests/win32/releng.manifest diff --git a/application/basilisk/config/tooltool-manifests/win64/clang.manifest b/browser/config/tooltool-manifests/win64/clang.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/win64/clang.manifest rename to browser/config/tooltool-manifests/win64/clang.manifest diff --git a/application/basilisk/config/tooltool-manifests/win64/l10n.manifest b/browser/config/tooltool-manifests/win64/l10n.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/win64/l10n.manifest rename to browser/config/tooltool-manifests/win64/l10n.manifest diff --git a/application/basilisk/config/tooltool-manifests/win64/releng.manifest b/browser/config/tooltool-manifests/win64/releng.manifest similarity index 100% rename from application/basilisk/config/tooltool-manifests/win64/releng.manifest rename to browser/config/tooltool-manifests/win64/releng.manifest diff --git a/browser/config/version.txt b/browser/config/version.txt new file mode 100644 index 0000000000..ceedae9682 --- /dev/null +++ b/browser/config/version.txt @@ -0,0 +1 @@ +52.13.2.1 \ No newline at end of file diff --git a/browser/config/version_display.txt b/browser/config/version_display.txt new file mode 100644 index 0000000000..16b080e5b3 --- /dev/null +++ b/browser/config/version_display.txt @@ -0,0 +1 @@ +13.2.1 \ No newline at end of file diff --git a/application/basilisk/configure.in b/browser/configure.in similarity index 100% rename from application/basilisk/configure.in rename to browser/configure.in diff --git a/application/basilisk/confvars.sh b/browser/confvars.sh similarity index 100% rename from application/basilisk/confvars.sh rename to browser/confvars.sh diff --git a/application/basilisk/defs.mk b/browser/defs.mk similarity index 100% rename from application/basilisk/defs.mk rename to browser/defs.mk diff --git a/application/basilisk/extensions/moz.build b/browser/extensions/moz.build similarity index 100% rename from application/basilisk/extensions/moz.build rename to browser/extensions/moz.build diff --git a/application/basilisk/extensions/palefill@addons.martoks-place.de.xpi b/browser/extensions/palefill@addons.martoks-place.de.xpi similarity index 100% rename from application/basilisk/extensions/palefill@addons.martoks-place.de.xpi rename to browser/extensions/palefill@addons.martoks-place.de.xpi diff --git a/application/basilisk/extensions/pdfjs/LICENSE b/browser/extensions/pdfjs/LICENSE similarity index 100% rename from application/basilisk/extensions/pdfjs/LICENSE rename to browser/extensions/pdfjs/LICENSE diff --git a/application/basilisk/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla similarity index 100% rename from application/basilisk/extensions/pdfjs/README.mozilla rename to browser/extensions/pdfjs/README.mozilla diff --git a/application/basilisk/extensions/pdfjs/chrome.manifest b/browser/extensions/pdfjs/chrome.manifest similarity index 100% rename from application/basilisk/extensions/pdfjs/chrome.manifest rename to browser/extensions/pdfjs/chrome.manifest diff --git a/application/basilisk/extensions/pdfjs/content/PdfJs.jsm b/browser/extensions/pdfjs/content/PdfJs.jsm similarity index 100% rename from application/basilisk/extensions/pdfjs/content/PdfJs.jsm rename to browser/extensions/pdfjs/content/PdfJs.jsm diff --git a/application/basilisk/extensions/pdfjs/content/PdfJsNetwork.jsm b/browser/extensions/pdfjs/content/PdfJsNetwork.jsm similarity index 100% rename from application/basilisk/extensions/pdfjs/content/PdfJsNetwork.jsm rename to browser/extensions/pdfjs/content/PdfJsNetwork.jsm diff --git a/application/basilisk/extensions/pdfjs/content/PdfStreamConverter.jsm b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm similarity index 100% rename from application/basilisk/extensions/pdfjs/content/PdfStreamConverter.jsm rename to browser/extensions/pdfjs/content/PdfStreamConverter.jsm diff --git a/application/basilisk/extensions/pdfjs/content/PdfjsChromeUtils.jsm b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm similarity index 100% rename from application/basilisk/extensions/pdfjs/content/PdfjsChromeUtils.jsm rename to browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm diff --git a/application/basilisk/extensions/pdfjs/content/PdfjsContentUtils.jsm b/browser/extensions/pdfjs/content/PdfjsContentUtils.jsm similarity index 100% rename from application/basilisk/extensions/pdfjs/content/PdfjsContentUtils.jsm rename to browser/extensions/pdfjs/content/PdfjsContentUtils.jsm diff --git a/application/basilisk/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js similarity index 100% rename from application/basilisk/extensions/pdfjs/content/build/pdf.js rename to browser/extensions/pdfjs/content/build/pdf.js diff --git a/application/basilisk/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js similarity index 100% rename from application/basilisk/extensions/pdfjs/content/build/pdf.worker.js rename to browser/extensions/pdfjs/content/build/pdf.worker.js diff --git a/application/basilisk/extensions/pdfjs/content/pdfjschildbootstrap.js b/browser/extensions/pdfjs/content/pdfjschildbootstrap.js similarity index 100% rename from application/basilisk/extensions/pdfjs/content/pdfjschildbootstrap.js rename to browser/extensions/pdfjs/content/pdfjschildbootstrap.js diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/78-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/78-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/78-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/78-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/78-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/78-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/78-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/78-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/78-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/78-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/78-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/78-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/78-RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/78-RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/78-RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/78-RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/78-RKSJ-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/78-RKSJ-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/78-RKSJ-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/78-RKSJ-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/78-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/78-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/78-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/78-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/78ms-RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/78ms-RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/78ms-RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/78ms-RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/78ms-RKSJ-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/78ms-RKSJ-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/78ms-RKSJ-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/78ms-RKSJ-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/83pv-RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/83pv-RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/83pv-RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/83pv-RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/90ms-RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/90ms-RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/90ms-RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/90ms-RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/90ms-RKSJ-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/90ms-RKSJ-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/90ms-RKSJ-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/90ms-RKSJ-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/90msp-RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/90msp-RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/90msp-RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/90msp-RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/90msp-RKSJ-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/90msp-RKSJ-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/90msp-RKSJ-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/90msp-RKSJ-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/90pv-RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/90pv-RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/90pv-RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/90pv-RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/90pv-RKSJ-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/90pv-RKSJ-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/90pv-RKSJ-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/90pv-RKSJ-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Add-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Add-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Add-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Add-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Add-RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Add-RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Add-RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Add-RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Add-RKSJ-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Add-RKSJ-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Add-RKSJ-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Add-RKSJ-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Add-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Add-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Add-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Add-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-0.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-0.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-0.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-0.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-1.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-1.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-1.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-1.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-2.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-2.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-2.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-2.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-3.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-3.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-3.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-3.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-4.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-4.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-4.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-4.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-5.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-5.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-5.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-5.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-6.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-6.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-6.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-6.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-UCS2.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-UCS2.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-UCS2.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-CNS1-UCS2.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-0.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-0.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-0.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-0.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-1.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-1.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-1.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-1.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-2.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-2.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-2.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-2.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-3.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-3.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-3.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-3.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-4.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-4.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-4.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-4.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-5.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-5.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-5.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-5.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-UCS2.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-UCS2.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-GB1-UCS2.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-GB1-UCS2.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-0.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-0.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-0.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-0.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-1.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-1.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-1.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-1.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-2.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-2.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-2.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-2.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-3.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-3.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-3.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-3.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-4.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-4.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-4.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-4.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-5.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-5.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-5.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-5.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-6.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-6.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-6.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-6.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-UCS2.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-UCS2.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-UCS2.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Japan1-UCS2.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-0.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-0.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-0.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-0.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-1.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-1.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-1.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-1.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-2.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-2.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-2.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-2.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-UCS2.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-UCS2.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-UCS2.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Adobe-Korea1-UCS2.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/B5pc-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/B5pc-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/B5pc-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/B5pc-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/B5pc-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/B5pc-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/B5pc-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/B5pc-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/CNS-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/CNS-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/CNS-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/CNS-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/CNS-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/CNS-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/CNS-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/CNS-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/CNS1-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/CNS1-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/CNS1-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/CNS1-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/CNS1-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/CNS1-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/CNS1-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/CNS1-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/CNS2-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/CNS2-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/CNS2-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/CNS2-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/CNS2-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/CNS2-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/CNS2-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/CNS2-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/ETHK-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/ETHK-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/ETHK-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/ETHK-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/ETHK-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/ETHK-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/ETHK-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/ETHK-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/ETen-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/ETen-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/ETen-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/ETen-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/ETen-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/ETen-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/ETen-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/ETen-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/ETenms-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/ETenms-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/ETenms-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/ETenms-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/ETenms-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/ETenms-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/ETenms-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/ETenms-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Ext-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Ext-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Ext-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Ext-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Ext-RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Ext-RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Ext-RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Ext-RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Ext-RKSJ-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Ext-RKSJ-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Ext-RKSJ-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Ext-RKSJ-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Ext-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Ext-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Ext-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Ext-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GB-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GB-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GB-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GB-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GB-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GB-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GB-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GB-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GB-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GB-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GB-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GB-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GB-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GB-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GB-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GB-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBK-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBK-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBK-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBK-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBK-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBK-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBK-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBK-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBK2K-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBK2K-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBK2K-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBK2K-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBK2K-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBK2K-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBK2K-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBK2K-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBKp-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBKp-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBKp-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBKp-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBKp-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBKp-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBKp-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBKp-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBT-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBT-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBT-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBT-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBT-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBT-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBT-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBT-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBT-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBT-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBT-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBT-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBT-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBT-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBT-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBT-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBTpc-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBTpc-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBTpc-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBTpc-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBTpc-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBTpc-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBTpc-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBTpc-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBpc-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBpc-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBpc-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBpc-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/GBpc-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/GBpc-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/GBpc-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/GBpc-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKdla-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKdla-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKdla-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKdla-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKdla-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKdla-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKdla-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKdla-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKdlb-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKdlb-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKdlb-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKdlb-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKdlb-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKdlb-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKdlb-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKdlb-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKgccs-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKgccs-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKgccs-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKgccs-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKgccs-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKgccs-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKgccs-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKgccs-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKm314-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKm314-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKm314-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKm314-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKm314-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKm314-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKm314-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKm314-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKm471-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKm471-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKm471-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKm471-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKm471-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKm471-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKm471-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKm471-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKscs-B5-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKscs-B5-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKscs-B5-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKscs-B5-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/HKscs-B5-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/HKscs-B5-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/HKscs-B5-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/HKscs-B5-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Hankaku.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Hankaku.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Hankaku.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Hankaku.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Hiragana.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Hiragana.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Hiragana.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Hiragana.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSC-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSC-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSC-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSC-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-Johab-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSC-Johab-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-Johab-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSC-Johab-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-Johab-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSC-Johab-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-Johab-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSC-Johab-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSCms-UHC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSCms-UHC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSCms-UHC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSCms-UHC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSCms-UHC-HW-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSCms-UHC-HW-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSCms-UHC-HW-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSCms-UHC-HW-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSCms-UHC-HW-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSCms-UHC-HW-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSCms-UHC-HW-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSCms-UHC-HW-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSCms-UHC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSCms-UHC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSCms-UHC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSCms-UHC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSCpc-EUC-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSCpc-EUC-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSCpc-EUC-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSCpc-EUC-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/KSCpc-EUC-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/KSCpc-EUC-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/KSCpc-EUC-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/KSCpc-EUC-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Katakana.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Katakana.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Katakana.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Katakana.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/LICENSE b/browser/extensions/pdfjs/content/web/cmaps/LICENSE similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/LICENSE rename to browser/extensions/pdfjs/content/web/cmaps/LICENSE diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/NWP-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/NWP-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/NWP-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/NWP-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/NWP-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/NWP-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/NWP-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/NWP-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/RKSJ-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/RKSJ-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/RKSJ-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/RKSJ-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/RKSJ-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/RKSJ-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/RKSJ-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/RKSJ-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/Roman.bcmap b/browser/extensions/pdfjs/content/web/cmaps/Roman.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/Roman.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/Roman.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UCS2-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniCNS-UCS2-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UCS2-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniCNS-UCS2-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UCS2-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniCNS-UCS2-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UCS2-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniCNS-UCS2-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF16-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF16-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF16-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF16-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF16-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF16-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF16-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF16-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF32-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF32-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF32-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF32-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF32-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF32-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF32-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF32-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF8-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF8-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF8-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF8-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF8-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF8-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniCNS-UTF8-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniCNS-UTF8-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UCS2-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniGB-UCS2-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UCS2-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniGB-UCS2-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UCS2-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniGB-UCS2-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UCS2-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniGB-UCS2-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF16-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF16-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF16-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF16-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF16-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF16-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF16-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF16-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF32-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF32-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF32-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF32-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF32-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF32-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF32-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF32-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF8-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF8-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF8-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF8-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF8-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF8-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniGB-UTF8-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniGB-UTF8-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-HW-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-HW-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-HW-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-HW-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-HW-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-HW-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-HW-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-HW-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UCS2-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF16-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF16-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF16-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF16-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF16-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF16-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF16-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF16-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF32-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF32-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF32-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF32-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF32-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF32-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF32-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF32-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF8-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF8-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF8-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF8-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF8-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF8-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS-UTF8-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS-UTF8-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF16-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF16-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF16-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF16-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF16-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF16-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF16-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF16-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF32-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF32-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF32-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF32-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF32-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF32-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF32-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF32-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF8-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF8-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF8-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF8-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF8-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF8-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF8-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJIS2004-UTF8-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISPro-UCS2-HW-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJISPro-UCS2-HW-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISPro-UCS2-HW-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJISPro-UCS2-HW-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISPro-UCS2-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJISPro-UCS2-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISPro-UCS2-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJISPro-UCS2-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISPro-UTF8-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJISPro-UTF8-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISPro-UTF8-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJISPro-UTF8-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISX0213-UTF32-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJISX0213-UTF32-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISX0213-UTF32-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJISX0213-UTF32-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISX0213-UTF32-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJISX0213-UTF32-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISX0213-UTF32-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJISX0213-UTF32-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISX02132004-UTF32-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJISX02132004-UTF32-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISX02132004-UTF32-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJISX02132004-UTF32-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISX02132004-UTF32-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniJISX02132004-UTF32-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniJISX02132004-UTF32-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniJISX02132004-UTF32-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UCS2-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniKS-UCS2-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UCS2-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniKS-UCS2-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UCS2-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniKS-UCS2-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UCS2-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniKS-UCS2-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF16-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF16-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF16-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF16-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF16-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF16-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF16-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF16-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF32-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF32-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF32-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF32-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF32-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF32-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF32-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF32-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF8-H.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF8-H.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF8-H.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF8-H.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF8-V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF8-V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/UniKS-UTF8-V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/UniKS-UTF8-V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/V.bcmap b/browser/extensions/pdfjs/content/web/cmaps/V.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/V.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/V.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/cmaps/WP-Symbol.bcmap b/browser/extensions/pdfjs/content/web/cmaps/WP-Symbol.bcmap similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/cmaps/WP-Symbol.bcmap rename to browser/extensions/pdfjs/content/web/cmaps/WP-Symbol.bcmap diff --git a/application/basilisk/extensions/pdfjs/content/web/debugger.js b/browser/extensions/pdfjs/content/web/debugger.js similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/debugger.js rename to browser/extensions/pdfjs/content/web/debugger.js diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-check.svg b/browser/extensions/pdfjs/content/web/images/annotation-check.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-check.svg rename to browser/extensions/pdfjs/content/web/images/annotation-check.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-comment.svg b/browser/extensions/pdfjs/content/web/images/annotation-comment.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-comment.svg rename to browser/extensions/pdfjs/content/web/images/annotation-comment.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-help.svg b/browser/extensions/pdfjs/content/web/images/annotation-help.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-help.svg rename to browser/extensions/pdfjs/content/web/images/annotation-help.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-insert.svg b/browser/extensions/pdfjs/content/web/images/annotation-insert.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-insert.svg rename to browser/extensions/pdfjs/content/web/images/annotation-insert.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-key.svg b/browser/extensions/pdfjs/content/web/images/annotation-key.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-key.svg rename to browser/extensions/pdfjs/content/web/images/annotation-key.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-newparagraph.svg b/browser/extensions/pdfjs/content/web/images/annotation-newparagraph.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-newparagraph.svg rename to browser/extensions/pdfjs/content/web/images/annotation-newparagraph.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-noicon.svg b/browser/extensions/pdfjs/content/web/images/annotation-noicon.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-noicon.svg rename to browser/extensions/pdfjs/content/web/images/annotation-noicon.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-note.svg b/browser/extensions/pdfjs/content/web/images/annotation-note.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-note.svg rename to browser/extensions/pdfjs/content/web/images/annotation-note.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/annotation-paragraph.svg b/browser/extensions/pdfjs/content/web/images/annotation-paragraph.svg similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/annotation-paragraph.svg rename to browser/extensions/pdfjs/content/web/images/annotation-paragraph.svg diff --git a/application/basilisk/extensions/pdfjs/content/web/images/findbarButton-next-rtl.png b/browser/extensions/pdfjs/content/web/images/findbarButton-next-rtl.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/findbarButton-next-rtl.png rename to browser/extensions/pdfjs/content/web/images/findbarButton-next-rtl.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/findbarButton-next-rtl@2x.png b/browser/extensions/pdfjs/content/web/images/findbarButton-next-rtl@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/findbarButton-next-rtl@2x.png rename to browser/extensions/pdfjs/content/web/images/findbarButton-next-rtl@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/findbarButton-next.png b/browser/extensions/pdfjs/content/web/images/findbarButton-next.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/findbarButton-next.png rename to browser/extensions/pdfjs/content/web/images/findbarButton-next.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/findbarButton-next@2x.png b/browser/extensions/pdfjs/content/web/images/findbarButton-next@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/findbarButton-next@2x.png rename to browser/extensions/pdfjs/content/web/images/findbarButton-next@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/findbarButton-previous-rtl.png b/browser/extensions/pdfjs/content/web/images/findbarButton-previous-rtl.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/findbarButton-previous-rtl.png rename to browser/extensions/pdfjs/content/web/images/findbarButton-previous-rtl.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/findbarButton-previous-rtl@2x.png b/browser/extensions/pdfjs/content/web/images/findbarButton-previous-rtl@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/findbarButton-previous-rtl@2x.png rename to browser/extensions/pdfjs/content/web/images/findbarButton-previous-rtl@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/findbarButton-previous.png b/browser/extensions/pdfjs/content/web/images/findbarButton-previous.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/findbarButton-previous.png rename to browser/extensions/pdfjs/content/web/images/findbarButton-previous.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/findbarButton-previous@2x.png b/browser/extensions/pdfjs/content/web/images/findbarButton-previous@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/findbarButton-previous@2x.png rename to browser/extensions/pdfjs/content/web/images/findbarButton-previous@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/grab.cur b/browser/extensions/pdfjs/content/web/images/grab.cur similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/grab.cur rename to browser/extensions/pdfjs/content/web/images/grab.cur diff --git a/application/basilisk/extensions/pdfjs/content/web/images/grabbing.cur b/browser/extensions/pdfjs/content/web/images/grabbing.cur similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/grabbing.cur rename to browser/extensions/pdfjs/content/web/images/grabbing.cur diff --git a/application/basilisk/extensions/pdfjs/content/web/images/loading-icon.gif b/browser/extensions/pdfjs/content/web/images/loading-icon.gif similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/loading-icon.gif rename to browser/extensions/pdfjs/content/web/images/loading-icon.gif diff --git a/application/basilisk/extensions/pdfjs/content/web/images/loading-small.png b/browser/extensions/pdfjs/content/web/images/loading-small.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/loading-small.png rename to browser/extensions/pdfjs/content/web/images/loading-small.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/loading-small@2x.png b/browser/extensions/pdfjs/content/web/images/loading-small@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/loading-small@2x.png rename to browser/extensions/pdfjs/content/web/images/loading-small@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-documentProperties.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-documentProperties.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-documentProperties.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-documentProperties.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-documentProperties@2x.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-documentProperties@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-documentProperties@2x.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-documentProperties@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-firstPage.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-firstPage.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-firstPage.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-firstPage.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-firstPage@2x.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-firstPage@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-firstPage@2x.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-firstPage@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-handTool.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-handTool.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-handTool.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-handTool.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-handTool@2x.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-handTool@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-handTool@2x.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-handTool@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-lastPage.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-lastPage.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-lastPage.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-lastPage.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-lastPage@2x.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-lastPage@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-lastPage@2x.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-lastPage@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCcw.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCcw.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCcw.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCcw.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCcw@2x.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCcw@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCcw@2x.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCcw@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCw.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCw.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCw.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCw.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCw@2x.png b/browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCw@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCw@2x.png rename to browser/extensions/pdfjs/content/web/images/secondaryToolbarButton-rotateCw@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/shadow.png b/browser/extensions/pdfjs/content/web/images/shadow.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/shadow.png rename to browser/extensions/pdfjs/content/web/images/shadow.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/texture.png b/browser/extensions/pdfjs/content/web/images/texture.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/texture.png rename to browser/extensions/pdfjs/content/web/images/texture.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-bookmark.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-bookmark.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-bookmark.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-bookmark.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-bookmark@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-bookmark@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-bookmark@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-bookmark@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-download.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-download.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-download.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-download.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-download@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-download@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-download@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-download@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-menuArrows.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-menuArrows.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-menuArrows.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-menuArrows.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-menuArrows@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-menuArrows@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-menuArrows@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-menuArrows@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-openFile.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-openFile.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-openFile.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-openFile.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-openFile@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-openFile@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-openFile@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-openFile@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageDown-rtl.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-pageDown-rtl.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageDown-rtl.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-pageDown-rtl.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageDown-rtl@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-pageDown-rtl@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageDown-rtl@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-pageDown-rtl@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageDown.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-pageDown.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageDown.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-pageDown.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageDown@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-pageDown@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageDown@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-pageDown@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageUp-rtl.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-pageUp-rtl.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageUp-rtl.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-pageUp-rtl.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageUp-rtl@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-pageUp-rtl@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageUp-rtl@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-pageUp-rtl@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageUp.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-pageUp.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageUp.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-pageUp.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageUp@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-pageUp@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-pageUp@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-pageUp@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-presentationMode.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-presentationMode.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-presentationMode.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-presentationMode.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-presentationMode@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-presentationMode@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-presentationMode@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-presentationMode@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-print.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-print.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-print.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-print.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-print@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-print@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-print@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-print@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-search.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-search.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-search.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-search.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-search@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-search@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-search@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-search@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle-rtl.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle-rtl.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle-rtl.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle-rtl.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-secondaryToolbarToggle@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle-rtl.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle-rtl.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle-rtl.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle-rtl.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle-rtl@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle-rtl@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle-rtl@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle-rtl@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-sidebarToggle@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewAttachments.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-viewAttachments.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewAttachments.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-viewAttachments.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewAttachments@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-viewAttachments@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewAttachments@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-viewAttachments@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewOutline-rtl.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-viewOutline-rtl.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewOutline-rtl.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-viewOutline-rtl.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewOutline-rtl@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-viewOutline-rtl@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewOutline-rtl@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-viewOutline-rtl@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewOutline.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-viewOutline.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewOutline.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-viewOutline.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewOutline@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-viewOutline@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewOutline@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-viewOutline@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewThumbnail.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-viewThumbnail.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewThumbnail.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-viewThumbnail.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewThumbnail@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-viewThumbnail@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-viewThumbnail@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-viewThumbnail@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-zoomIn.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-zoomIn.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-zoomIn.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-zoomIn.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-zoomIn@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-zoomIn@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-zoomIn@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-zoomIn@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-zoomOut.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-zoomOut.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-zoomOut.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-zoomOut.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-zoomOut@2x.png b/browser/extensions/pdfjs/content/web/images/toolbarButton-zoomOut@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/toolbarButton-zoomOut@2x.png rename to browser/extensions/pdfjs/content/web/images/toolbarButton-zoomOut@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/treeitem-collapsed-rtl.png b/browser/extensions/pdfjs/content/web/images/treeitem-collapsed-rtl.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/treeitem-collapsed-rtl.png rename to browser/extensions/pdfjs/content/web/images/treeitem-collapsed-rtl.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/treeitem-collapsed-rtl@2x.png b/browser/extensions/pdfjs/content/web/images/treeitem-collapsed-rtl@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/treeitem-collapsed-rtl@2x.png rename to browser/extensions/pdfjs/content/web/images/treeitem-collapsed-rtl@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/treeitem-collapsed.png b/browser/extensions/pdfjs/content/web/images/treeitem-collapsed.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/treeitem-collapsed.png rename to browser/extensions/pdfjs/content/web/images/treeitem-collapsed.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/treeitem-collapsed@2x.png b/browser/extensions/pdfjs/content/web/images/treeitem-collapsed@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/treeitem-collapsed@2x.png rename to browser/extensions/pdfjs/content/web/images/treeitem-collapsed@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/treeitem-expanded.png b/browser/extensions/pdfjs/content/web/images/treeitem-expanded.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/treeitem-expanded.png rename to browser/extensions/pdfjs/content/web/images/treeitem-expanded.png diff --git a/application/basilisk/extensions/pdfjs/content/web/images/treeitem-expanded@2x.png b/browser/extensions/pdfjs/content/web/images/treeitem-expanded@2x.png similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/images/treeitem-expanded@2x.png rename to browser/extensions/pdfjs/content/web/images/treeitem-expanded@2x.png diff --git a/application/basilisk/extensions/pdfjs/content/web/l10n.js b/browser/extensions/pdfjs/content/web/l10n.js similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/l10n.js rename to browser/extensions/pdfjs/content/web/l10n.js diff --git a/application/basilisk/extensions/pdfjs/content/web/viewer.css b/browser/extensions/pdfjs/content/web/viewer.css similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/viewer.css rename to browser/extensions/pdfjs/content/web/viewer.css diff --git a/application/basilisk/extensions/pdfjs/content/web/viewer.html b/browser/extensions/pdfjs/content/web/viewer.html similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/viewer.html rename to browser/extensions/pdfjs/content/web/viewer.html diff --git a/application/basilisk/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js similarity index 100% rename from application/basilisk/extensions/pdfjs/content/web/viewer.js rename to browser/extensions/pdfjs/content/web/viewer.js diff --git a/application/basilisk/extensions/pdfjs/jar.mn b/browser/extensions/pdfjs/jar.mn similarity index 100% rename from application/basilisk/extensions/pdfjs/jar.mn rename to browser/extensions/pdfjs/jar.mn diff --git a/application/basilisk/extensions/pdfjs/moz.build b/browser/extensions/pdfjs/moz.build similarity index 100% rename from application/basilisk/extensions/pdfjs/moz.build rename to browser/extensions/pdfjs/moz.build diff --git a/application/basilisk/installer/Makefile.in b/browser/installer/Makefile.in similarity index 99% rename from application/basilisk/installer/Makefile.in rename to browser/installer/Makefile.in index 704305bb62..36be202509 100644 --- a/application/basilisk/installer/Makefile.in +++ b/browser/installer/Makefile.in @@ -192,7 +192,7 @@ endif # fail to produce a langpack. See bug 1255096. make-langpack: ifeq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS))) - $(MAKE) -C $(DEPTH)/application/basilisk/locales langpack + $(MAKE) -C $(DEPTH)/browser/locales langpack else @echo WARNING: "Language Pack was not generated due to using the hybrid FasterMake/RecursiveMake backend." >&2 endif diff --git a/application/basilisk/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn similarity index 100% rename from application/basilisk/installer/allowed-dupes.mn rename to browser/installer/allowed-dupes.mn diff --git a/application/basilisk/installer/macbuild/Contents/Info.plist.in b/browser/installer/macbuild/Contents/Info.plist.in similarity index 100% rename from application/basilisk/installer/macbuild/Contents/Info.plist.in rename to browser/installer/macbuild/Contents/Info.plist.in diff --git a/application/basilisk/installer/macbuild/Contents/PkgInfo b/browser/installer/macbuild/Contents/PkgInfo similarity index 100% rename from application/basilisk/installer/macbuild/Contents/PkgInfo rename to browser/installer/macbuild/Contents/PkgInfo diff --git a/application/basilisk/installer/package-manifest.in b/browser/installer/package-manifest.in similarity index 98% rename from application/basilisk/installer/package-manifest.in rename to browser/installer/package-manifest.in index a01855b6b5..c271a445e7 100644 --- a/application/basilisk/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -357,6 +357,8 @@ @RESPATH@/browser/components/nsBrowserGlue.js @RESPATH@/browser/components/nsSetDefaultBrowser.manifest @RESPATH@/browser/components/nsSetDefaultBrowser.js +@RESPATH@/browser/components/internaluserscripts.js +@RESPATH@/browser/components/internaluserscripts.manifest @RESPATH@/browser/components/devtools-startup.manifest @RESPATH@/browser/components/devtools-startup.js @RESPATH@/browser/components/webideCli.js @@ -585,6 +587,9 @@ @RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/chrome.manifest @RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/icon.png @RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf +@RESPATH@/browser/chrome/internaluserscripts.manifest +@RESPATH@/browser/chrome/internaluserscripts/* +@RESPATH@/browser/internal-userscripts/* @RESPATH@/chrome/toolkit@JAREXT@ @RESPATH@/chrome/toolkit.manifest @RESPATH@/chrome/recording.manifest diff --git a/application/basilisk/installer/removed-files.in b/browser/installer/removed-files.in similarity index 100% rename from application/basilisk/installer/removed-files.in rename to browser/installer/removed-files.in diff --git a/application/basilisk/installer/windows/Makefile.in b/browser/installer/windows/Makefile.in similarity index 89% rename from application/basilisk/installer/windows/Makefile.in rename to browser/installer/windows/Makefile.in index 22793fc0bf..6869921cd1 100644 --- a/application/basilisk/installer/windows/Makefile.in +++ b/browser/installer/windows/Makefile.in @@ -35,12 +35,12 @@ include $(topsrcdir)/config/config.mk ifdef LOCALE_MERGEDIR PPL_LOCALE_ARGS = \ - --l10n-dir=$(LOCALE_MERGEDIR)/application/basilisk/installer \ - --l10n-dir=$(call EXPAND_LOCALE_SRCDIR,application/basilisk/locales)/installer \ - --l10n-dir=$(topsrcdir)/application/basilisk/locales/en-US/installer \ + --l10n-dir=$(LOCALE_MERGEDIR)/browser/installer \ + --l10n-dir=$(call EXPAND_LOCALE_SRCDIR,browser/locales)/installer \ + --l10n-dir=$(topsrcdir)/browser/locales/en-US/installer \ $(NULL) else -PPL_LOCALE_ARGS=$(call EXPAND_LOCALE_SRCDIR,application/basilisk/locales)/installer +PPL_LOCALE_ARGS=$(call EXPAND_LOCALE_SRCDIR,browser/locales)/installer endif OVERRIDE_DEFAULT_GOAL := installer diff --git a/application/basilisk/installer/windows/app.tag b/browser/installer/windows/app.tag similarity index 100% rename from application/basilisk/installer/windows/app.tag rename to browser/installer/windows/app.tag diff --git a/application/basilisk/installer/windows/moz.build b/browser/installer/windows/moz.build similarity index 100% rename from application/basilisk/installer/windows/moz.build rename to browser/installer/windows/moz.build diff --git a/application/basilisk/installer/windows/nsis/defines.nsi.in b/browser/installer/windows/nsis/defines.nsi.in similarity index 100% rename from application/basilisk/installer/windows/nsis/defines.nsi.in rename to browser/installer/windows/nsis/defines.nsi.in diff --git a/application/basilisk/installer/windows/nsis/installer.nsi b/browser/installer/windows/nsis/installer.nsi similarity index 100% rename from application/basilisk/installer/windows/nsis/installer.nsi rename to browser/installer/windows/nsis/installer.nsi diff --git a/application/basilisk/installer/windows/nsis/shared.nsh b/browser/installer/windows/nsis/shared.nsh similarity index 100% rename from application/basilisk/installer/windows/nsis/shared.nsh rename to browser/installer/windows/nsis/shared.nsh diff --git a/application/basilisk/installer/windows/nsis/uninstaller.nsi b/browser/installer/windows/nsis/uninstaller.nsi similarity index 100% rename from application/basilisk/installer/windows/nsis/uninstaller.nsi rename to browser/installer/windows/nsis/uninstaller.nsi diff --git a/application/basilisk/installer/windows/nsis/updater_append.ini b/browser/installer/windows/nsis/updater_append.ini similarity index 100% rename from application/basilisk/installer/windows/nsis/updater_append.ini rename to browser/installer/windows/nsis/updater_append.ini diff --git a/browser/internaluserscripts/README.md b/browser/internaluserscripts/README.md new file mode 100644 index 0000000000..1831a58f2d --- /dev/null +++ b/browser/internaluserscripts/README.md @@ -0,0 +1,28 @@ +# Internal Userscripts (Polyfills Only) + +This directory contains a minimal, built-in userscript loader used to ship polyfill user scripts with Dactyloidae (forked from Basilisk's implementation of such). This originally started as a fork of GreaseMonkey, however at this point very little of GreaseMonkey remains. + +## How it works +- The XPCOM component `@internaluserscripts.mozdev.org/service;1` observes document creation and, when `browser.internal-userscripts.enabled` is true, injects bundled polyfill scripts into each page. +- Bundled scripts live in `basilisk/internaluserscripts/bundled-scripts/` and are packaged into the app. They are loaded in the page principal and can override missing APIs. +- The only default pref is `browser.internal-userscripts.enabled` (default: true). Toggle to disable all injection. + +## Bundled polyfills +- `elementfrompoint-finite-polyfill.user.js`: wraps `Document.elementFromPoint()` and `Document.elementsFromPoint()` to return `null`/`[]` when coordinates are not finite, avoiding page-breaking `TypeError`s from non-finite inputs. It exposes `window.__internalUserscriptsElementFromPointFinitePolyfill = true` for verification. +- `getanimations-polyfill.user.js`: minimal `getAnimations()` shim for `Document`, `Element`, and `CSSPseudoElement` that returns an empty array when native support is unavailable. It exposes `window.__internalUserscriptsGetAnimationsPolyfill = true` for verification. +- `imagedecode-polyfill.user.js`: best-effort `HTMLImageElement.decode()` shim that resolves on load and rejects on error. It exposes `window.__internalUserscriptsImageDecodePolyfill = true` for verification. +- `intl-displaynames-polyfill.user.js`: minimal Intl.DisplayNames shim that validates options and returns the input code when display data is unavailable. It exposes `window.__internalUserscriptsIntlDisplayNamesPolyfill = true` for verification. +- `intl-listformat-polyfill.user.js`: minimal Intl.ListFormat shim supporting `format()` and `formatToParts()` with simple fallback separators. It exposes `window.__internalUserscriptsIntlListFormatPolyfill = true` for verification. +- `intl-relativetimeformat-formattoparts-polyfill.user.js`: adds `formatToParts()` to native Intl.RelativeTimeFormat implementations that lack it. It exposes `window.__internalUserscriptsIntlRelativeTimeFormatFormatToPartsPolyfill = true` for verification. +- `intl-segmenter-polyfill.user.js`: minimal Intl.Segmenter shim supporting `segment()`, `resolvedOptions()`, and `supportedLocalesOf()` with best-effort grapheme/word/sentence segmentation. It exposes `window.__internalUserscriptsIntlSegmenterPolyfill = true` for verification. +- `readablestream-pipethrough-polyfill.user.js`: best-effort ReadableStream `pipeThrough` implementation backed by `pipeTo` or reader/writer pumping. It exposes `window.__internalUserscriptsReadableStreamPipeThroughPolyfill = true` for verification. +- `readablestream-pipeto-polyfill.user.js`: best-effort ReadableStream `pipeTo` implementation using reader/writer pumping. It exposes `window.__internalUserscriptsReadableStreamPipeToPolyfill = true` for verification. +- `textencoderstream-polyfill.user.js`: best-effort TextEncoderStream implementation backed by TransformStream. It exposes `window.__internalUserscriptsTextEncoderStreamPolyfill = true` for verification. +- `textdecoderstream-polyfill.user.js`: best-effort TextDecoderStream implementation backed by TransformStream. It exposes `window.__internalUserscriptsTextDecoderStreamPolyfill = true` for verification. +- `transformstream-polyfill.user.js`: minimal TransformStream polyfill backed by ReadableStream with a lightweight WritableStream shim. It exposes `window.__internalUserscriptsTransformStreamPolyfill = true` for verification. +- `webauthn-microsoft-shim.user.js`: Microsoft-domain WebAuthn capability shim that reports WebAuthn as unsupported by providing rejecting `navigator.credentials.create/get` stubs (when `navigator.credentials` is missing) and a `PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()` fallback that resolves `false`. It exposes `window.__internalUserscriptsWebAuthnMicrosoftShim = true` for verification. + +## Adding new polyfills +1. Drop a `*.user.js` file into `bundled-scripts/` with the appropriate header. +2. List it in `moz.build` under `FINAL_TARGET_FILES['internal-userscripts']`. +3. The loader will inject it automatically when enabled. diff --git a/browser/internaluserscripts/bundled-scripts/elementfrompoint-finite-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/elementfrompoint-finite-polyfill.user.js new file mode 100644 index 0000000000..228e149bea --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/elementfrompoint-finite-polyfill.user.js @@ -0,0 +1,93 @@ +// 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/. +// ==UserScript== +// @name elementFromPoint finite-args shim +// @namespace internal-userscripts +// @description Prevents throws when Document.elementFromPoint / elementsFromPoint receives non-finite coordinates. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global || !global.Document || !global.Document.prototype) { + return; + } + + var patched = false; + + function toFiniteNumber(value) { + var number = Number(value); + if (number !== number || number === Infinity || number === -Infinity) { + return null; + } + return number; + } + + function fallbackValue(methodName) { + return methodName === "elementsFromPoint" ? [] : null; + } + + function wrapMethod(proto, methodName) { + var nativeMethod = proto[methodName]; + if (typeof nativeMethod !== "function") { + return; + } + if (nativeMethod.__internalUserscriptsFinitePointShim) { + return; + } + + function wrappedMethod(x, y) { + var finiteX = toFiniteNumber(x); + var finiteY = toFiniteNumber(y); + if (finiteX === null || finiteY === null) { + return fallbackValue(methodName); + } + + try { + return nativeMethod.call(this, finiteX, finiteY); + } catch (e) { + var message = e && e.message ? String(e.message) : ""; + if (message.indexOf("not a finite floating-point value") !== -1 || + message.indexOf("is not finite") !== -1) { + return fallbackValue(methodName); + } + throw e; + } + } + + try { + Object.defineProperty(wrappedMethod, "__internalUserscriptsFinitePointShim", { + value: true + }); + } catch (e) {} + + try { + Object.defineProperty(proto, methodName, { + value: wrappedMethod, + writable: true, + configurable: true + }); + } catch (e) { + try { + proto[methodName] = wrappedMethod; + } catch (ignore) {} + } + + if (proto[methodName] === wrappedMethod) { + patched = true; + } + } + + wrapMethod(global.Document.prototype, "elementFromPoint"); + wrapMethod(global.Document.prototype, "elementsFromPoint"); + + if (patched) { + try { + global.__internalUserscriptsElementFromPointFinitePolyfill = true; + } catch (e) {} + } +})(); diff --git a/browser/internaluserscripts/bundled-scripts/getanimations-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/getanimations-polyfill.user.js new file mode 100644 index 0000000000..8be664dbf2 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/getanimations-polyfill.user.js @@ -0,0 +1,52 @@ +// 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/. +// ==UserScript== +// @name getAnimations Polyfill (minimal) +// @namespace internal-userscripts +// @description Adds minimal Document/Element getAnimations() methods that return an empty array when unsupported. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global) { + return; + } + + var patched = false; + + function getAnimations() { + return []; + } + + function defineGetAnimations(proto) { + if (!proto || typeof proto.getAnimations === "function") { + return; + } + + try { + Object.defineProperty(proto, "getAnimations", { + value: getAnimations, + writable: true, + configurable: true + }); + } catch (e) { + proto.getAnimations = getAnimations; + } + patched = true; + } + + defineGetAnimations(global.Document && global.Document.prototype); + defineGetAnimations(global.Element && global.Element.prototype); + defineGetAnimations(global.CSSPseudoElement && global.CSSPseudoElement.prototype); + + if (patched) { + try { + global.__internalUserscriptsGetAnimationsPolyfill = true; + } catch (e) {} + } +})(); diff --git a/browser/internaluserscripts/bundled-scripts/imagedecode-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/imagedecode-polyfill.user.js new file mode 100644 index 0000000000..74505f27c9 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/imagedecode-polyfill.user.js @@ -0,0 +1,111 @@ +// 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/. +// ==UserScript== +// @name HTMLImageElement.decode Polyfill (best-effort) +// @namespace internal-userscripts +// @description Adds a Promise-based decode() that resolves on load and rejects on error. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global || !global.HTMLImageElement) { + return; + } + + var proto = global.HTMLImageElement.prototype; + if (typeof proto.decode === "function") { + return; + } + + var PromiseCtor = global.Promise; + if (typeof PromiseCtor !== "function") { + return; + } + + function rejectPromise(error) { + return new PromiseCtor(function (resolve, reject) { + reject(error); + }); + } + + function hasLoadedImage(img) { + return img.complete && (img.naturalWidth > 0 || img.naturalHeight > 0); + } + + function isBrokenImage(img) { + return img.complete && img.naturalWidth === 0 && img.naturalHeight === 0; + } + + function decode() { + var img = this; + if (!(img instanceof global.HTMLImageElement)) { + return rejectPromise(new TypeError("decode can only be used on an HTMLImageElement")); + } + + if (hasLoadedImage(img)) { + return PromiseCtor.resolve(); + } + if (isBrokenImage(img)) { + return rejectPromise(new Error("Image decode failed")); + } + + var src = ""; + try { + src = img.currentSrc || img.src || ""; + } catch (e) {} + if (!src) { + return rejectPromise(new Error("Image has no src")); + } + + return new PromiseCtor(function (resolve, reject) { + var settled = false; + + function cleanup() { + if (settled) { + return; + } + settled = true; + img.removeEventListener("load", onLoad, false); + img.removeEventListener("error", onError, false); + } + + function onLoad() { + cleanup(); + resolve(); + } + + function onError() { + cleanup(); + reject(new Error("Image decode failed")); + } + + img.addEventListener("load", onLoad, false); + img.addEventListener("error", onError, false); + + if (hasLoadedImage(img)) { + cleanup(); + resolve(); + } else if (isBrokenImage(img)) { + cleanup(); + reject(new Error("Image decode failed")); + } + }); + } + + try { + Object.defineProperty(proto, "decode", { + value: decode, + writable: true, + configurable: true + }); + } catch (e) { + proto.decode = decode; + } + + try { global.__internalUserscriptsImageDecodePolyfill = true; } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/intl-displaynames-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/intl-displaynames-polyfill.user.js new file mode 100644 index 0000000000..5729fcbc11 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/intl-displaynames-polyfill.user.js @@ -0,0 +1,104 @@ +// 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/. +// ==UserScript== +// @name Intl.DisplayNames Polyfill (minimal) +// @namespace internal-userscripts +// @description Provides a minimal Intl.DisplayNames implementation for environments without native support. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + if (typeof Intl !== "object" || typeof Intl.DisplayNames === "function") { + return; + } + + var STYLE_VALUES = { long: true, short: true, narrow: true }; + var TYPE_VALUES = { language: true, region: true, script: true, currency: true }; + var FALLBACK_VALUES = { code: true, none: true }; + + function canonicalizeLocales(locales) { + if (typeof Intl.getCanonicalLocales === "function") { + return Intl.getCanonicalLocales(locales); + } + if (locales == null) { + return []; + } + if (Array.isArray(locales)) { + return locales.map(function (loc) { return String(loc); }); + } + return [String(locales)]; + } + + function defaultLocale() { + try { + if (typeof Intl.DateTimeFormat === "function") { + return Intl.DateTimeFormat().resolvedOptions().locale; + } + } catch (e) {} + if (typeof navigator !== "undefined" && navigator.language) { + return String(navigator.language); + } + return "en-US"; + } + + function DisplayNames(locales, options) { + if (!(this instanceof DisplayNames)) { + throw new TypeError("Intl.DisplayNames must be called with new"); + } + options = options || {}; + + var type = options.type; + if (type == null) { + throw new TypeError("Intl.DisplayNames requires a type option"); + } + type = String(type); + if (!TYPE_VALUES[type]) { + throw new RangeError("Invalid type"); + } + + var style = options.style == null ? "long" : String(options.style); + if (!STYLE_VALUES[style]) { + throw new RangeError("Invalid style"); + } + + var fallback = options.fallback == null ? "code" : String(options.fallback); + if (!FALLBACK_VALUES[fallback]) { + throw new RangeError("Invalid fallback"); + } + + var localeList = canonicalizeLocales(locales); + this._locale = localeList.length ? localeList[0] : defaultLocale(); + this._style = style; + this._type = type; + this._fallback = fallback; + } + + DisplayNames.supportedLocalesOf = function (locales) { + return canonicalizeLocales(locales); + }; + + DisplayNames.prototype.resolvedOptions = function () { + return { + locale: this._locale, + style: this._style, + type: this._type, + fallback: this._fallback, + }; + }; + + DisplayNames.prototype.of = function (code) { + if (this._fallback === "none") { + return undefined; + } + return String(code); + }; + + Intl.DisplayNames = DisplayNames; + try { + window.__internalUserscriptsIntlDisplayNamesPolyfill = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/intl-listformat-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/intl-listformat-polyfill.user.js new file mode 100644 index 0000000000..3f1232f04b --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/intl-listformat-polyfill.user.js @@ -0,0 +1,233 @@ +// 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/. +// ==UserScript== +// @name Intl.ListFormat Polyfill (minimal) +// @namespace internal-userscripts +// @description Provides a minimal Intl.ListFormat implementation for environments without native support. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + if (typeof Intl !== "object" || typeof Intl.ListFormat === "function") { + return; + } + + var TYPE_VALUES = { conjunction: true, disjunction: true, unit: true }; + var STYLE_VALUES = { long: true, short: true, narrow: true }; + var LOCALE_MATCHER_VALUES = { lookup: true, "best fit": true }; + var PATTERNS = { + conjunction: { + long: { pair: " and ", middle: ", ", end: ", and " }, + short: { pair: " & ", middle: ", ", end: ", & " }, + narrow: { pair: ", ", middle: ", ", end: ", " }, + }, + disjunction: { + long: { pair: " or ", middle: ", ", end: ", or " }, + short: { pair: " or ", middle: ", ", end: ", or " }, + narrow: { pair: " or ", middle: ", ", end: ", or " }, + }, + unit: { + long: { pair: ", ", middle: ", ", end: ", " }, + short: { pair: ", ", middle: ", ", end: ", " }, + narrow: { pair: " ", middle: " ", end: " " }, + }, + }; + + function canonicalizeLocales(locales) { + if (typeof Intl.getCanonicalLocales === "function") { + return Intl.getCanonicalLocales(locales); + } + if (locales == null) { + return []; + } + if (Array.isArray(locales)) { + return locales.map(function (locale) { + return String(locale); + }); + } + return [String(locales)]; + } + + function defaultLocale() { + try { + if (typeof Intl.DateTimeFormat === "function") { + return Intl.DateTimeFormat().resolvedOptions().locale; + } + } catch (e) {} + if (typeof navigator !== "undefined" && navigator.language) { + return String(navigator.language); + } + return "en-US"; + } + + function toStringValue(value) { + if (typeof value === "symbol") { + throw new TypeError("Cannot convert a Symbol value to a string"); + } + return String(value); + } + + function toStringList(list) { + if (list == null) { + throw new TypeError("List argument is required"); + } + + var result = []; + if (typeof Symbol !== "undefined" && list[Symbol.iterator] != null) { + var iterator = list[Symbol.iterator](); + if (!iterator || typeof iterator.next !== "function") { + throw new TypeError("List argument must be iterable"); + } + while (true) { + var step = iterator.next(); + if (step.done) { + break; + } + result.push(toStringValue(step.value)); + } + return result; + } + + // Fallback for very old environments without Symbol.iterator. + if (Array.isArray(list)) { + for (var i = 0; i < list.length; i++) { + result.push(toStringValue(list[i])); + } + return result; + } + + throw new TypeError("List argument must be iterable"); + } + + function requireListFormatInstance(value) { + if ( + value == null || + (typeof value !== "object" && typeof value !== "function") || + !TYPE_VALUES[value._type] || + !STYLE_VALUES[value._style] + ) { + throw new TypeError( + "Method Intl.ListFormat.prototype called on incompatible receiver", + ); + } + return value; + } + + function buildParts(items, pattern) { + var parts = []; + var i = 0; + var lastIndex = items.length - 1; + + if (items.length === 0) { + return parts; + } + if (items.length === 1) { + parts.push({ type: "element", value: items[0] }); + return parts; + } + if (items.length === 2) { + parts.push({ type: "element", value: items[0] }); + parts.push({ type: "literal", value: pattern.pair }); + parts.push({ type: "element", value: items[1] }); + return parts; + } + + parts.push({ type: "element", value: items[0] }); + for (i = 1; i < lastIndex; i++) { + parts.push({ type: "literal", value: pattern.middle }); + parts.push({ type: "element", value: items[i] }); + } + parts.push({ type: "literal", value: pattern.end }); + parts.push({ type: "element", value: items[lastIndex] }); + return parts; + } + + function ListFormat(locales, options) { + if (!(this instanceof ListFormat)) { + throw new TypeError("Intl.ListFormat must be called with new"); + } + + options = options || {}; + var type = options.type == null ? "conjunction" : String(options.type); + var style = options.style == null ? "long" : String(options.style); + var localeMatcher = + options.localeMatcher == null + ? "best fit" + : String(options.localeMatcher); + + if (!TYPE_VALUES[type]) { + throw new RangeError("Invalid type"); + } + if (!STYLE_VALUES[style]) { + throw new RangeError("Invalid style"); + } + if (!LOCALE_MATCHER_VALUES[localeMatcher]) { + throw new RangeError("Invalid localeMatcher"); + } + + var localeList = canonicalizeLocales(locales); + this._locale = localeList.length ? localeList[0] : defaultLocale(); + this._type = type; + this._style = style; + } + + ListFormat.supportedLocalesOf = function (locales, options) { + if (options != null && typeof options === "object") { + var localeMatcher = options.localeMatcher; + if ( + localeMatcher != null && + !LOCALE_MATCHER_VALUES[String(localeMatcher)] + ) { + throw new RangeError("Invalid localeMatcher"); + } + } + return canonicalizeLocales(locales); + }; + + ListFormat.prototype.resolvedOptions = function () { + var self = requireListFormatInstance(this); + return { + locale: self._locale, + type: self._type, + style: self._style, + }; + }; + + ListFormat.prototype.formatToParts = function (list) { + var self = requireListFormatInstance(this); + var items = toStringList(list); + var pattern = PATTERNS[self._type][self._style]; + return buildParts(items, pattern); + }; + + ListFormat.prototype._format = function (list) { + var parts = this.formatToParts(list); + var result = ""; + for (var i = 0; i < parts.length; i++) { + result += parts[i].value; + } + return result; + }; + + Object.defineProperty(ListFormat.prototype, "format", { + configurable: true, + get: function () { + var self = requireListFormatInstance(this); + if (!self._boundFormat) { + self._boundFormat = function (list) { + return self._format(list); + }; + } + return self._boundFormat; + }, + }); + + Intl.ListFormat = ListFormat; + try { + window.__internalUserscriptsIntlListFormatPolyfill = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/intl-relativetimeformat-formattoparts-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/intl-relativetimeformat-formattoparts-polyfill.user.js new file mode 100644 index 0000000000..0d0acfc30a --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/intl-relativetimeformat-formattoparts-polyfill.user.js @@ -0,0 +1,85 @@ +// 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/. +// ==UserScript== +// @name Intl.RelativeTimeFormat formatToParts Polyfill +// @namespace internal-userscripts +// @description Adds formatToParts() to native Intl.RelativeTimeFormat implementations that lack it. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + if ( + typeof Intl !== "object" || + typeof Intl.RelativeTimeFormat !== "function" || + typeof Intl.RelativeTimeFormat.prototype.formatToParts === "function" + ) { + return; + } + + function formatToParts(value, unit) { + var number = Number(value); + var formatted = this.format(number, unit); + var canonicalUnit = String(unit).replace(/s$/, ""); + var resolved = this.resolvedOptions(); + var numberOptions = { + maximumFractionDigits: 3, + }; + + if (resolved.numberingSystem) { + numberOptions.numberingSystem = resolved.numberingSystem; + } + + var numberFormat = new Intl.NumberFormat(resolved.locale, numberOptions); + var numberParts; + if (typeof numberFormat.formatToParts === "function") { + numberParts = numberFormat.formatToParts(Math.abs(number)); + } else { + numberParts = [ + { type: "integer", value: numberFormat.format(Math.abs(number)) }, + ]; + } + + var numberText = numberParts + .map(function (part) { + return part.value; + }) + .join(""); + var numberIndex = formatted.indexOf(numberText); + + // numeric: "auto" may produce a word such as "yesterday" with no number. + if (numberIndex === -1) { + return [{ type: "literal", value: formatted }]; + } + + var parts = []; + if (numberIndex > 0) { + parts.push({ type: "literal", value: formatted.slice(0, numberIndex) }); + } + numberParts.forEach(function (part) { + parts.push({ type: part.type, value: part.value, unit: canonicalUnit }); + }); + if (numberIndex + numberText.length < formatted.length) { + parts.push({ + type: "literal", + value: formatted.slice(numberIndex + numberText.length), + }); + } + return parts; + } + + Object.defineProperty( + Intl.RelativeTimeFormat.prototype, + "formatToParts", + { + configurable: true, + writable: true, + value: formatToParts, + }, + ); + + window.__internalUserscriptsIntlRelativeTimeFormatFormatToPartsPolyfill = true; +})(); diff --git a/browser/internaluserscripts/bundled-scripts/intl-segmenter-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/intl-segmenter-polyfill.user.js new file mode 100644 index 0000000000..2577e66388 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/intl-segmenter-polyfill.user.js @@ -0,0 +1,365 @@ +// 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/. +// ==UserScript== +// @name Intl.Segmenter Polyfill (minimal) +// @namespace internal-userscripts +// @description Provides a minimal Intl.Segmenter implementation for environments without native support. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = + (typeof globalThis !== "undefined" && globalThis) || + (typeof window !== "undefined" && window) || + (typeof self !== "undefined" && self) || + this; + if (typeof global.Intl !== "object" || global.Intl == null) { + global.Intl = {}; + } + if (typeof global.Intl.Segmenter === "function") { + return; + } + + var GRANULARITY_VALUES = { grapheme: true, word: true, sentence: true }; + var LOCALE_MATCHER_VALUES = { lookup: true, "best fit": true }; + var FALLBACK_WORD_LIKE = /^[A-Za-z0-9_]+$/; + var FALLBACK_WORD_SPLIT = /[A-Za-z0-9_]+|[\s]+|[^\s]/g; + var COMBINING_MARK_RANGES = [ + [0x0300, 0x036f], + [0x1ab0, 0x1aff], + [0x1dc0, 0x1dff], + [0x20d0, 0x20ff], + [0xfe20, 0xfe2f], + ]; + + var unicodeGraphemeRegex = null; + var unicodeWordSplit = null; + var unicodeWordLike = null; + try { + unicodeGraphemeRegex = new RegExp( + "(?:\\P{Mark}\\p{Mark}*|\\p{Mark}+)", + "gu", + ); + unicodeWordSplit = new RegExp("[\\p{L}\\p{N}\\p{M}_]+|[\\s]+|[^\\s]", "gu"); + unicodeWordLike = new RegExp("^[\\p{L}\\p{N}\\p{M}_]+$", "u"); + } catch (e) {} + + function canonicalizeLocales(locales) { + if (typeof global.Intl.getCanonicalLocales === "function") { + return global.Intl.getCanonicalLocales(locales); + } + if (locales == null) { + return []; + } + if (Array.isArray(locales)) { + return locales.map(function (locale) { + return String(locale); + }); + } + return [String(locales)]; + } + + function defaultLocale() { + try { + if (typeof global.Intl.DateTimeFormat === "function") { + return global.Intl.DateTimeFormat().resolvedOptions().locale; + } + } catch (e) {} + if (typeof navigator !== "undefined" && navigator.language) { + return String(navigator.language); + } + return "en-US"; + } + + function toStringValue(value) { + if (typeof value === "symbol") { + throw new TypeError("Cannot convert a Symbol value to a string"); + } + return String(value); + } + + function readCodePoint(str, index) { + var first = str.charCodeAt(index); + if (first >= 0xd800 && first <= 0xdbff && index + 1 < str.length) { + var second = str.charCodeAt(index + 1); + if (second >= 0xdc00 && second <= 0xdfff) { + return { + codePoint: ((first - 0xd800) << 10) + (second - 0xdc00) + 0x10000, + length: 2, + }; + } + } + return { codePoint: first, length: 1 }; + } + + function isCombiningMark(codePoint) { + for (var i = 0; i < COMBINING_MARK_RANGES.length; i++) { + var range = COMBINING_MARK_RANGES[i]; + if (codePoint >= range[0] && codePoint <= range[1]) { + return true; + } + } + return false; + } + + function segmentGrapheme(string) { + var segments = []; + var i = 0; + + if (unicodeGraphemeRegex) { + var match; + unicodeGraphemeRegex.lastIndex = 0; + while ((match = unicodeGraphemeRegex.exec(string))) { + segments.push({ + segment: match[0], + index: match.index, + }); + } + return segments; + } + + while (i < string.length) { + var start = i; + var current = readCodePoint(string, i); + i += current.length; + while (i < string.length) { + var next = readCodePoint(string, i); + if (!isCombiningMark(next.codePoint)) { + break; + } + i += next.length; + } + segments.push({ + segment: string.slice(start, i), + index: start, + }); + } + + return segments; + } + + function segmentWord(string) { + var segments = []; + var regex = unicodeWordSplit || FALLBACK_WORD_SPLIT; + var match; + + regex.lastIndex = 0; + while ((match = regex.exec(string))) { + segments.push({ + segment: match[0], + index: match.index, + }); + } + return segments; + } + + function isSentenceTerminal(ch) { + return ch === "." || ch === "!" || ch === "?"; + } + + function isWhitespaceChar(ch) { + return ( + ch === " " || ch === "\t" || ch === "\r" || ch === "\n" || ch === "\f" + ); + } + + function segmentSentence(string) { + var segments = []; + var start = 0; + var i = 0; + + if (!string) { + return segments; + } + + while (i < string.length) { + if (isSentenceTerminal(string.charAt(i))) { + i++; + while (i < string.length && isSentenceTerminal(string.charAt(i))) { + i++; + } + while (i < string.length && isWhitespaceChar(string.charAt(i))) { + i++; + } + segments.push({ + segment: string.slice(start, i), + index: start, + }); + start = i; + } else { + i++; + } + } + + if (start < string.length) { + segments.push({ + segment: string.slice(start), + index: start, + }); + } + + return segments; + } + + function segmentString(string, granularity) { + if (granularity === "word") { + return segmentWord(string); + } + if (granularity === "sentence") { + return segmentSentence(string); + } + return segmentGrapheme(string); + } + + function isWordLikeSegment(segment) { + if (unicodeWordLike) { + return unicodeWordLike.test(segment); + } + return FALLBACK_WORD_LIKE.test(segment); + } + + function requireSegmenter(value) { + if ( + value == null || + (typeof value !== "object" && typeof value !== "function") || + !GRANULARITY_VALUES[value._granularity] + ) { + throw new TypeError( + "Method Intl.Segmenter.prototype called on incompatible receiver", + ); + } + return value; + } + + function SegmentIterator(segments) { + this._segments = segments; + this._index = 0; + } + + SegmentIterator.prototype.next = function () { + if (this._index >= this._segments.length) { + return { value: undefined, done: true }; + } + var value = this._segments[this._index]; + this._index += 1; + return { value: value, done: false }; + }; + + if (typeof Symbol !== "undefined" && Symbol.iterator) { + SegmentIterator.prototype[Symbol.iterator] = function () { + return this; + }; + } + + function Segments(input, segments) { + this._input = input; + this._segments = segments; + } + + Segments.prototype.containing = function (index) { + if (index == null) { + return undefined; + } + var position = Number(index); + if (!isFinite(position)) { + return undefined; + } + position = Math.floor(position); + for (var i = 0; i < this._segments.length; i++) { + var segment = this._segments[i]; + if ( + position >= segment.index && + position < segment.index + segment.segment.length + ) { + return segment; + } + } + return undefined; + }; + + if (typeof Symbol !== "undefined" && Symbol.iterator) { + Segments.prototype[Symbol.iterator] = function () { + return new SegmentIterator(this._segments); + }; + } + + function Segmenter(locales, options) { + if (!(this instanceof Segmenter)) { + throw new TypeError("Intl.Segmenter must be called with new"); + } + + if (options == null) { + options = {}; + } else if (typeof options !== "object") { + options = Object(options); + } + + var granularity = + options.granularity == null ? "grapheme" : String(options.granularity); + if (!GRANULARITY_VALUES[granularity]) { + throw new RangeError("Invalid granularity"); + } + if ( + options.localeMatcher != null && + !LOCALE_MATCHER_VALUES[String(options.localeMatcher)] + ) { + throw new RangeError("Invalid localeMatcher"); + } + + var localeList = canonicalizeLocales(locales); + this._locale = localeList.length ? localeList[0] : defaultLocale(); + this._granularity = granularity; + } + + Segmenter.supportedLocalesOf = function (locales, options) { + if (options != null && typeof options === "object") { + var localeMatcher = options.localeMatcher; + if ( + localeMatcher != null && + !LOCALE_MATCHER_VALUES[String(localeMatcher)] + ) { + throw new RangeError("Invalid localeMatcher"); + } + } + return canonicalizeLocales(locales); + }; + + Segmenter.prototype.resolvedOptions = function () { + var self = requireSegmenter(this); + return { + locale: self._locale, + granularity: self._granularity, + }; + }; + + Segmenter.prototype.segment = function (input) { + var self = requireSegmenter(this); + var string = toStringValue(input); + var entries = segmentString(string, self._granularity); + var segments = []; + + for (var i = 0; i < entries.length; i++) { + var part = entries[i]; + segments.push({ + segment: part.segment, + index: part.index, + input: string, + isWordLike: + self._granularity === "word" + ? isWordLikeSegment(part.segment) + : undefined, + }); + } + + return new Segments(string, segments); + }; + + global.Intl.Segmenter = Segmenter; + try { + global.__internalUserscriptsIntlSegmenterPolyfill = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/readablestream-pipethrough-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/readablestream-pipethrough-polyfill.user.js new file mode 100644 index 0000000000..2d569a91a2 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/readablestream-pipethrough-polyfill.user.js @@ -0,0 +1,208 @@ +// 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/. +// ==UserScript== +// @name ReadableStream pipeThrough Polyfill (best-effort) +// @namespace internal-userscripts +// @description Adds ReadableStream.prototype.pipeThrough using pipeTo or reader/writer pumping when missing. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global || !global.ReadableStream || !global.ReadableStream.prototype) { + return; + } + var existingPipeThrough = global.ReadableStream.prototype.pipeThrough; + if (typeof existingPipeThrough === "function") { + if (typeof global.TransformStream !== "function") { + return; + } + try { + var probeStream = new global.ReadableStream({ + start: function (controller) { + controller.close(); + } + }); + probeStream.pipeThrough(new global.TransformStream(), { preventClose: true }); + return; + } catch (e) { + if (String(e).indexOf("not yet implemented") === -1) { + return; + } + } + } + + var PromiseCtor = global.Promise; + if (typeof PromiseCtor !== "function") { + return; + } + + function isObject(value) { + return value !== null && (typeof value === "object" || typeof value === "function"); + } + + function getTransformStream(transform, name) { + var stream = transform[name]; + if (!isObject(stream)) { + throw new TypeError("pipeThrough requires a transform stream with " + name); + } + return stream; + } + + function startPipeWithReader(source, writable, options) { + var reader = source.getReader(); + var writer = writable.getWriter(); + var preventClose = options && options.preventClose; + var preventAbort = options && options.preventAbort; + var preventCancel = options && options.preventCancel; + var signal = options && options.signal; + var abortHandler = null; + + function safeReleaseLock(stream, maybeReader, lockedProp) { + if (!maybeReader) { + return; + } + var isLocked = true; + if (typeof lockedProp === "function") { + try { + var lockedValue = lockedProp(); + if (typeof lockedValue === "boolean") { + isLocked = lockedValue; + } + } catch (e) { + isLocked = true; + } + } + if (!isLocked) { + return; + } + var releaseFn = null; + try { + releaseFn = maybeReader.releaseLock; + } catch (e) { + releaseFn = null; + } + if (typeof releaseFn === "function") { + try { releaseFn.call(maybeReader); } catch (e) {} + } + } + + function releaseLocks() { + safeReleaseLock(source, reader, function () { return source.locked; }); + safeReleaseLock(writable, writer, function () { return writable.locked; }); + reader = null; + writer = null; + } + + function cleanupAbort() { + if (abortHandler && signal && typeof signal.removeEventListener === "function") { + signal.removeEventListener("abort", abortHandler); + } + } + + if (signal) { + abortHandler = function () { + var reason = signal.reason; + if (!preventCancel) { + try { reader.cancel(reason); } catch (e) {} + } + if (!preventAbort) { + try { writer.abort(reason); } catch (e) {} + } + }; + if (signal.aborted) { + abortHandler(); + cleanupAbort(); + releaseLocks(); + return; + } + if (typeof signal.addEventListener === "function") { + signal.addEventListener("abort", abortHandler); + } + } + + function pump() { + var readPromise; + try { + readPromise = reader.read(); + } catch (e) { + return PromiseCtor.reject(e); + } + return readPromise.then(function (result) { + if (result.done) { + if (!preventClose) { + var closePromise; + try { + closePromise = writer.close(); + } catch (e) { + return PromiseCtor.reject(e); + } + return PromiseCtor.resolve(closePromise); + } + return undefined; + } + var writePromise; + try { + writePromise = writer.write(result.value); + } catch (e) { + return PromiseCtor.reject(e); + } + return PromiseCtor.resolve(writePromise).then(pump); + }); + } + + pump().catch(function (err) { + if (!preventCancel) { + try { reader.cancel(err); } catch (e) {} + } + if (!preventAbort) { + try { writer.abort(err); } catch (e) {} + } + }).then(function () { + cleanupAbort(); + releaseLocks(); + }, function () { + cleanupAbort(); + releaseLocks(); + }); + } + + function pipeThrough(transform, options) { + if (!isObject(this)) { + throw new TypeError("ReadableStream.prototype.pipeThrough called on incompatible receiver"); + } + if (!isObject(transform)) { + throw new TypeError("pipeThrough requires a transform stream"); + } + var readable = getTransformStream(transform, "readable"); + var writable = getTransformStream(transform, "writable"); + var source = this; + + if (typeof source.pipeTo === "function") { + var pipePromise = source.pipeTo(writable, options); + if (pipePromise && typeof pipePromise.catch === "function") { + pipePromise.catch(function () {}); + } + } else if (typeof source.getReader === "function" && typeof writable.getWriter === "function") { + startPipeWithReader(source, writable, options); + } else { + throw new TypeError("ReadableStream.prototype.pipeThrough is not supported"); + } + + return readable; + } + + Object.defineProperty(global.ReadableStream.prototype, "pipeThrough", { + value: pipeThrough, + writable: true, + configurable: true + }); + + try { + global.__internalUserscriptsReadableStreamPipeThroughPolyfill = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/readablestream-pipeto-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/readablestream-pipeto-polyfill.user.js new file mode 100644 index 0000000000..9c416402d4 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/readablestream-pipeto-polyfill.user.js @@ -0,0 +1,221 @@ +// 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/. +// ==UserScript== +// @name ReadableStream pipeTo Polyfill (best-effort) +// @namespace internal-userscripts +// @description Adds ReadableStream.prototype.pipeTo using reader/writer pumping. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global || !global.ReadableStream || !global.ReadableStream.prototype) { + return; + } + + var PromiseCtor = global.Promise; + if (typeof PromiseCtor !== "function") { + return; + } + + function isObject(value) { + return value !== null && (typeof value === "object" || typeof value === "function"); + } + + var existingPipeTo = global.ReadableStream.prototype.pipeTo; + if (typeof existingPipeTo === "function") { + if (typeof global.TransformStream !== "function" && + typeof global.WritableStream !== "function") { + return; + } + try { + var testWritable = null; + if (typeof global.TransformStream === "function") { + testWritable = new global.TransformStream().writable; + } else { + testWritable = new global.WritableStream(); + } + var probeStream = new global.ReadableStream({ + start: function (controller) { + controller.close(); + } + }); + probeStream.pipeTo(testWritable, { preventClose: true }); + return; + } catch (e) { + if (String(e).indexOf("not yet implemented") === -1) { + return; + } + } + } + + function pipeTo(writable, options) { + if (!isObject(this)) { + throw new TypeError("ReadableStream.prototype.pipeTo called on incompatible receiver"); + } + if (!isObject(writable) || typeof writable.getWriter !== "function") { + throw new TypeError("pipeTo requires a writable stream"); + } + + var source = this; + var reader = source.getReader(); + var writer = writable.getWriter(); + var preventClose = options && options.preventClose; + var preventAbort = options && options.preventAbort; + var preventCancel = options && options.preventCancel; + var signal = options && options.signal; + var abortHandler = null; + var abortReject = null; + var aborted = false; + var abortReason = undefined; + + function safeReleaseLock(stream, maybeReader, lockedProp) { + if (!maybeReader) { + return; + } + var isLocked = true; + if (typeof lockedProp === "function") { + try { + var lockedValue = lockedProp(); + if (typeof lockedValue === "boolean") { + isLocked = lockedValue; + } + } catch (e) { + isLocked = true; + } + } + if (!isLocked) { + return; + } + var releaseFn = null; + try { + releaseFn = maybeReader.releaseLock; + } catch (e) { + releaseFn = null; + } + if (typeof releaseFn === "function") { + try { releaseFn.call(maybeReader); } catch (e) {} + } + } + + function releaseLocks() { + safeReleaseLock(source, reader, function () { return source.locked; }); + safeReleaseLock(writable, writer, function () { return writable.locked; }); + reader = null; + writer = null; + } + + function cleanupAbort() { + if (abortHandler && signal && typeof signal.removeEventListener === "function") { + signal.removeEventListener("abort", abortHandler); + } + } + + function abortWith(reason) { + if (aborted) { + return; + } + aborted = true; + abortReason = reason; + if (!preventCancel) { + try { reader.cancel(reason); } catch (e) {} + } + if (!preventAbort) { + try { writer.abort(reason); } catch (e) {} + } + if (abortReject) { + abortReject(reason); + } + } + + var abortPromise = null; + if (signal) { + abortPromise = new PromiseCtor(function (_resolve, reject) { + abortReject = reject; + }); + abortHandler = function () { + abortWith(signal.reason); + }; + if (signal.aborted) { + abortWith(signal.reason); + } else if (typeof signal.addEventListener === "function") { + signal.addEventListener("abort", abortHandler); + } + } + + function pump() { + if (aborted) { + return PromiseCtor.reject(abortReason); + } + var readPromise; + try { + readPromise = reader.read(); + } catch (e) { + return PromiseCtor.reject(e); + } + return readPromise.then(function (result) { + if (aborted) { + throw abortReason; + } + if (result.done) { + if (!preventClose) { + return writer.close(); + } + return undefined; + } + var writePromise; + try { + writePromise = writer.write(result.value); + } catch (e) { + return PromiseCtor.reject(e); + } + return PromiseCtor.resolve(writePromise).then(pump); + }); + } + + var pipePromise = pump().catch(function (err) { + if (!preventCancel) { + try { reader.cancel(err); } catch (e) {} + } + if (!preventAbort) { + try { writer.abort(err); } catch (e) {} + } + throw err; + }); + + var finalPromise = abortPromise + ? PromiseCtor.race([pipePromise, abortPromise]) + : pipePromise; + + function settleAndRelease(err) { + return pipePromise.catch(function () {}).then(function () { + cleanupAbort(); + releaseLocks(); + if (err !== undefined) { + throw err; + } + return undefined; + }); + } + + return finalPromise.then(function () { + return settleAndRelease(); + }, function (err) { + return settleAndRelease(err); + }); + } + + Object.defineProperty(global.ReadableStream.prototype, "pipeTo", { + value: pipeTo, + writable: true, + configurable: true + }); + + try { + global.__internalUserscriptsReadableStreamPipeToPolyfill = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/textdecoderstream-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/textdecoderstream-polyfill.user.js new file mode 100644 index 0000000000..580d000947 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/textdecoderstream-polyfill.user.js @@ -0,0 +1,179 @@ +// 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/. +// ==UserScript== +// @name TextDecoderStream Polyfill (best-effort) +// @namespace internal-userscripts +// @description Minimal TextDecoderStream implementation backed by TransformStream. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global) { + return; + } + + var existingCtor = global.TextDecoderStream; + if (typeof existingCtor === "function") { + try { + var probe = new existingCtor(); + if (probe && probe.readable && probe.writable) { + return; + } + } catch (e) { + if (String(e).indexOf("not yet implemented") === -1) { + return; + } + } + } + + if (typeof global.TransformStream !== "function") { + return; + } + if (typeof global.TextDecoder !== "function") { + return; + } + + function isObject(value) { + return value !== null && (typeof value === "object" || typeof value === "function"); + } + + function streamBrandCheckException(name) { + return new TypeError("TextDecoderStream.prototype." + name + + " can only be used on a TextDecoderStream"); + } + + function isTextDecoderStream(value) { + return isObject(value) && value._isTextDecoderStream === true; + } + + function normalizeOptions(options) { + var normalized = { + fatal: false, + ignoreBOM: false + }; + + if (!isObject(options)) { + return normalized; + } + + normalized.fatal = !!options.fatal; + normalized.ignoreBOM = !!options.ignoreBOM; + return normalized; + } + + function PolyfillTextDecoderStream(label, options) { + if (!(this instanceof PolyfillTextDecoderStream)) { + throw new TypeError("TextDecoderStream must be constructed with 'new'"); + } + + var normalizedOptions = normalizeOptions(options); + var effectiveLabel = label === undefined ? "utf-8" : label; + + var decoder; + try { + decoder = new global.TextDecoder(effectiveLabel, { + fatal: normalizedOptions.fatal, + ignoreBOM: normalizedOptions.ignoreBOM + }); + } catch (e) { + decoder = new global.TextDecoder(effectiveLabel, { + fatal: normalizedOptions.fatal + }); + } + + this._decoder = decoder; + this._encoding = typeof decoder.encoding === "string" + ? decoder.encoding + : String(effectiveLabel).toLowerCase(); + this._fatal = typeof decoder.fatal === "boolean" + ? decoder.fatal + : normalizedOptions.fatal; + this._ignoreBOM = typeof decoder.ignoreBOM === "boolean" + ? decoder.ignoreBOM + : normalizedOptions.ignoreBOM; + + this._transform = new global.TransformStream({ + transform: function (chunk, controller) { + var output = decoder.decode(chunk, { stream: true }); + if (output.length > 0) { + controller.enqueue(output); + } + }, + flush: function (controller) { + var output = decoder.decode(); + if (output.length > 0) { + controller.enqueue(output); + } + } + }); + + this._readable = this._transform.readable; + this._writable = this._transform.writable; + this._isTextDecoderStream = true; + } + + Object.defineProperty(PolyfillTextDecoderStream.prototype, "encoding", { + get: function () { + if (!isTextDecoderStream(this)) { + throw streamBrandCheckException("encoding"); + } + return this._encoding; + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(PolyfillTextDecoderStream.prototype, "fatal", { + get: function () { + if (!isTextDecoderStream(this)) { + throw streamBrandCheckException("fatal"); + } + return this._fatal; + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(PolyfillTextDecoderStream.prototype, "ignoreBOM", { + get: function () { + if (!isTextDecoderStream(this)) { + throw streamBrandCheckException("ignoreBOM"); + } + return this._ignoreBOM; + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(PolyfillTextDecoderStream.prototype, "readable", { + get: function () { + if (!isTextDecoderStream(this)) { + throw streamBrandCheckException("readable"); + } + return this._readable; + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(PolyfillTextDecoderStream.prototype, "writable", { + get: function () { + if (!isTextDecoderStream(this)) { + throw streamBrandCheckException("writable"); + } + return this._writable; + }, + enumerable: true, + configurable: true + }); + + global.TextDecoderStream = PolyfillTextDecoderStream; + try { + global.__internalUserscriptsTextDecoderStreamPolyfill = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/textencoderstream-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/textencoderstream-polyfill.user.js new file mode 100644 index 0000000000..e28aef6e23 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/textencoderstream-polyfill.user.js @@ -0,0 +1,96 @@ +// 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/. +// ==UserScript== +// @name TextEncoderStream Polyfill (best-effort) +// @namespace internal-userscripts +// @description Minimal TextEncoderStream implementation backed by TransformStream. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global) { + return; + } + + var existingCtor = global.TextEncoderStream; + if (typeof existingCtor === "function") { + try { + var probe = new existingCtor(); + if (probe && probe.readable && probe.writable) { + return; + } + } catch (e) { + if (String(e).indexOf("not yet implemented") === -1) { + return; + } + } + } + + if (typeof global.TransformStream !== "function") { + return; + } + if (typeof global.TextEncoder !== "function") { + return; + } + + function isObject(value) { + return value !== null && (typeof value === "object" || typeof value === "function"); + } + + function streamBrandCheckException(name) { + return new TypeError("TextEncoderStream.prototype." + name + + " can only be used on a TextEncoderStream"); + } + + function isTextEncoderStream(value) { + return isObject(value) && value._isTextEncoderStream === true; + } + + function PolyfillTextEncoderStream() { + if (!(this instanceof PolyfillTextEncoderStream)) { + throw new TypeError("TextEncoderStream must be constructed with 'new'"); + } + + var encoder = new global.TextEncoder(); + this._transform = new global.TransformStream({ + transform: function (chunk, controller) { + controller.enqueue(encoder.encode(String(chunk))); + } + }); + this._readable = this._transform.readable; + this._writable = this._transform.writable; + this._isTextEncoderStream = true; + } + + Object.defineProperty(PolyfillTextEncoderStream.prototype, "readable", { + get: function () { + if (!isTextEncoderStream(this)) { + throw streamBrandCheckException("readable"); + } + return this._readable; + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(PolyfillTextEncoderStream.prototype, "writable", { + get: function () { + if (!isTextEncoderStream(this)) { + throw streamBrandCheckException("writable"); + } + return this._writable; + }, + enumerable: true, + configurable: true + }); + + global.TextEncoderStream = PolyfillTextEncoderStream; + try { + global.__internalUserscriptsTextEncoderStreamPolyfill = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/transformstream-polyfill.user.js b/browser/internaluserscripts/bundled-scripts/transformstream-polyfill.user.js new file mode 100644 index 0000000000..2b820c4abd --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/transformstream-polyfill.user.js @@ -0,0 +1,430 @@ +// 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/. +// ==UserScript== +// @name TransformStream Polyfill (best-effort) +// @namespace internal-userscripts +// @description Minimal TransformStream implementation backed by ReadableStream and a lightweight WritableStream shim. Not a full Streams spec implementation. +// @match *://*/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global || typeof global.TransformStream === "function") { + return; + } + + var ReadableStreamCtor = global.ReadableStream; + var PromiseCtor = global.Promise; + if (typeof PromiseCtor !== "function") { + return; + } + + function isObject(value) { + return value !== null && (typeof value === "object" || typeof value === "function"); + } + + function streamBrandCheckException(name) { + return new TypeError("TransformStream.prototype." + name + + " can only be used on a TransformStream"); + } + + function PolyfillWritableStream(underlyingSink) { + if (!(this instanceof PolyfillWritableStream)) { + throw new TypeError("WritableStream must be constructed with 'new'"); + } + this._sink = underlyingSink || {}; + this._state = "writable"; + this._storedError = undefined; + this._writer = null; + this._readyPromise = PromiseCtor.resolve(); + + var resolveClosed; + var rejectClosed; + this._closedPromise = new PromiseCtor(function (resolve, reject) { + resolveClosed = resolve; + rejectClosed = reject; + }); + this._closedResolve = resolveClosed; + this._closedReject = rejectClosed; + + if (typeof this._sink.start === "function") { + try { + this._sink.start(this); + } catch (e) { + this._error(e); + } + } + } + + PolyfillWritableStream.prototype.getWriter = function () { + if (this._writer) { + throw new TypeError("WritableStream is locked"); + } + this._writer = new PolyfillWritableStreamDefaultWriter(this); + return this._writer; + }; + + PolyfillWritableStream.prototype._releaseWriter = function (writer) { + if (this._writer === writer) { + this._writer = null; + } + }; + + PolyfillWritableStream.prototype._error = function (reason) { + if (this._state === "closed" || this._state === "errored") { + return; + } + this._state = "errored"; + this._storedError = reason; + if (this._closedReject) { + this._closedReject(reason); + } + }; + + PolyfillWritableStream.prototype._write = function (chunk) { + if (this._state !== "writable") { + return PromiseCtor.reject(new TypeError("WritableStream is not writable")); + } + if (!this._sink || typeof this._sink.write !== "function") { + return PromiseCtor.resolve(); + } + try { + return PromiseCtor.resolve(this._sink.write(chunk)); + } catch (e) { + this._error(e); + return PromiseCtor.reject(e); + } + }; + + PolyfillWritableStream.prototype._close = function () { + if (this._state !== "writable") { + return PromiseCtor.reject(new TypeError("WritableStream is not writable")); + } + this._state = "closing"; + + var closeResult; + if (this._sink && typeof this._sink.close === "function") { + try { + closeResult = this._sink.close(); + } catch (e) { + this._error(e); + return PromiseCtor.reject(e); + } + } + + var self = this; + return PromiseCtor.resolve(closeResult).then(function () { + self._state = "closed"; + if (self._closedResolve) { + self._closedResolve(); + } + }, function (e) { + self._error(e); + throw e; + }); + }; + + PolyfillWritableStream.prototype._abort = function (reason) { + if (this._state === "closed") { + return PromiseCtor.resolve(); + } + this._error(reason); + + if (this._sink && typeof this._sink.abort === "function") { + try { + return PromiseCtor.resolve(this._sink.abort(reason)); + } catch (e) { + return PromiseCtor.reject(e); + } + } + return PromiseCtor.resolve(); + }; + + function PolyfillWritableStreamDefaultWriter(stream) { + this._stream = stream; + } + + PolyfillWritableStreamDefaultWriter.prototype._assertStream = function (name) { + if (!this._stream) { + throw new TypeError("Cannot " + name + " a stream using a released writer"); + } + return this._stream; + }; + + Object.defineProperty(PolyfillWritableStreamDefaultWriter.prototype, "ready", { + get: function () { + return this._assertStream("get ready state for")._readyPromise; + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(PolyfillWritableStreamDefaultWriter.prototype, "closed", { + get: function () { + return this._assertStream("get closed state for")._closedPromise; + }, + enumerable: true, + configurable: true + }); + + PolyfillWritableStreamDefaultWriter.prototype.write = function (chunk) { + return this._assertStream("write to")._write(chunk); + }; + + PolyfillWritableStreamDefaultWriter.prototype.close = function () { + return this._assertStream("close")._close(); + }; + + PolyfillWritableStreamDefaultWriter.prototype.abort = function (reason) { + return this._assertStream("abort")._abort(reason); + }; + + PolyfillWritableStreamDefaultWriter.prototype.releaseLock = function () { + var stream = this._stream; + if (!stream) { + return; + } + stream._releaseWriter(this); + this._stream = null; + }; + + var WritableStreamCtor = typeof global.WritableStream === "function" + ? global.WritableStream + : PolyfillWritableStream; + + function TransformStreamDefaultController(stream) { + this._stream = stream; + this._readableController = null; + } + + Object.defineProperty(TransformStreamDefaultController.prototype, "desiredSize", { + get: function () { + if (!this._readableController) { + return null; + } + return this._readableController.desiredSize; + }, + enumerable: true, + configurable: true + }); + + TransformStreamDefaultController.prototype.enqueue = function (chunk) { + var controller = this._readableController; + if (!controller) { + throw new TypeError("ReadableStream controller is not available"); + } + controller.enqueue(chunk); + }; + + TransformStreamDefaultController.prototype.error = function (reason) { + this._stream._error(reason); + }; + + TransformStreamDefaultController.prototype.terminate = function () { + this._stream._terminate(); + }; + + function isTransformStream(value) { + return isObject(value) && value._isTransformStream === true; + } + + function PolyfillTransformStream(transformer, writableStrategy, readableStrategy) { + if (!(this instanceof PolyfillTransformStream)) { + throw new TypeError("TransformStream must be constructed with 'new'"); + } + + if (typeof ReadableStreamCtor !== "function") { + throw new TypeError("ReadableStream is not supported in this environment"); + } + + transformer = transformer || {}; + writableStrategy = writableStrategy || {}; + readableStrategy = readableStrategy || {}; + + if (transformer.writableType !== undefined) { + throw new RangeError("Invalid writable type specified"); + } + if (transformer.readableType !== undefined) { + throw new RangeError("Invalid readable type specified"); + } + + this._transformer = transformer; + this._controller = new TransformStreamDefaultController(this); + this._readableClosed = false; + this._errored = false; + this._terminated = false; + this._pendingError = undefined; + this._hasPendingError = false; + this._isTransformStream = true; + + var self = this; + + this._readable = new ReadableStreamCtor({ + start: function (controller) { + self._controller._readableController = controller; + if (self._hasPendingError) { + controller.error(self._pendingError); + return; + } + if (typeof transformer.start === "function") { + return transformer.start(self._controller); + } + }, + pull: function () {}, + cancel: function (reason) { + self._error(reason); + return PromiseCtor.resolve(); + } + }, readableStrategy); + + this._writable = new WritableStreamCtor({ + write: function (chunk) { + return self._transform(chunk); + }, + close: function () { + return self._flush(); + }, + abort: function (reason) { + self._error(reason); + return PromiseCtor.resolve(); + } + }, writableStrategy); + } + + Object.defineProperty(PolyfillTransformStream.prototype, "readable", { + get: function () { + if (!isTransformStream(this)) { + throw streamBrandCheckException("readable"); + } + return this._readable; + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(PolyfillTransformStream.prototype, "writable", { + get: function () { + if (!isTransformStream(this)) { + throw streamBrandCheckException("writable"); + } + return this._writable; + }, + enumerable: true, + configurable: true + }); + + PolyfillTransformStream.prototype._transform = function (chunk) { + if (this._errored || this._terminated) { + return PromiseCtor.reject(new TypeError("TransformStream is not writable")); + } + + var transformer = this._transformer; + var controller = this._controller; + var result; + + try { + if (typeof transformer.transform === "function") { + result = transformer.transform(chunk, controller); + } else { + controller.enqueue(chunk); + } + } catch (e) { + this._error(e); + return PromiseCtor.reject(e); + } + + var self = this; + return PromiseCtor.resolve(result).then(function () { + return undefined; + }, function (e) { + self._error(e); + throw e; + }); + }; + + PolyfillTransformStream.prototype._flush = function () { + if (this._errored || this._terminated) { + return PromiseCtor.reject(new TypeError("TransformStream is not writable")); + } + + var transformer = this._transformer; + var controller = this._controller; + var result; + + try { + if (typeof transformer.flush === "function") { + result = transformer.flush(controller); + } + } catch (e) { + this._error(e); + return PromiseCtor.reject(e); + } + + var self = this; + return PromiseCtor.resolve(result).then(function () { + self._closeReadable(); + }, function (e) { + self._error(e); + throw e; + }); + }; + + PolyfillTransformStream.prototype._closeReadable = function () { + if (this._readableClosed) { + return; + } + this._readableClosed = true; + + var controller = this._controller._readableController; + if (!controller) { + return; + } + try { + controller.close(); + } catch (e) {} + }; + + PolyfillTransformStream.prototype._error = function (reason) { + if (this._errored) { + return; + } + this._errored = true; + + var controller = this._controller._readableController; + if (controller) { + try { + controller.error(reason); + } catch (e) {} + } else { + this._pendingError = reason; + this._hasPendingError = true; + } + + if (this._writable && typeof this._writable._error === "function") { + this._writable._error(reason); + } + }; + + PolyfillTransformStream.prototype._terminate = function () { + if (this._terminated) { + return; + } + this._terminated = true; + this._closeReadable(); + if (this._writable && typeof this._writable._error === "function") { + this._writable._error(new TypeError("TransformStream terminated")); + } + }; + + global.TransformStream = PolyfillTransformStream; + if (typeof global.WritableStream !== "function") { + global.WritableStream = PolyfillWritableStream; + } + try { + global.__internalUserscriptsTransformStreamPolyfill = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/bundled-scripts/webauthn-microsoft-shim.user.js b/browser/internaluserscripts/bundled-scripts/webauthn-microsoft-shim.user.js new file mode 100644 index 0000000000..1ca9f02ad2 --- /dev/null +++ b/browser/internaluserscripts/bundled-scripts/webauthn-microsoft-shim.user.js @@ -0,0 +1,80 @@ +// 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/. +// ==UserScript== +// @name WebAuthn Shim for Microsoft +// @namespace internal-userscripts +// @description Forces WebAuthn capability checks to report unsupported on Microsoft auth domains. +// @match https://*.microsoft.com/* +// @match https://*.live.com/* +// @match https://*.msauth.net/* +// @match https://*.visualstudio.com/* +// @grant none +// @run-at document-start +// ==/UserScript== +(function () { + "use strict"; + + var global = typeof window !== "undefined" ? window : null; + if (!global || !global.location) { + return; + } + + if (global.location.protocol !== "https:") { + return; + } + + var host = String(global.location.hostname || "").toLowerCase(); + function matchesDomain(domain) { + return host === domain || host.slice(-(domain.length + 1)) === "." + domain; + } + + if ( + !matchesDomain("microsoft.com") && + !matchesDomain("live.com") && + !matchesDomain("msauth.net") && + !matchesDomain("visualstudio.com") + ) { + return; + } + + function installShim() { + if (typeof navigator.credentials === "undefined") { + var fake = { + create: function () { + return Promise.reject( + new DOMException("WebAuthn not supported", "NotSupportedError"), + ); + }, + get: function () { + return Promise.reject( + new DOMException("WebAuthn not supported", "NotSupportedError"), + ); + }, + }; + + try { + navigator.credentials = fake; + } catch (e) { + try { + Object.defineProperty(navigator, "credentials", { + value: fake, + }); + } catch (e2) {} + } + } + + if (typeof global.PublicKeyCredential === "undefined") { + global.PublicKeyCredential = function () {}; + global.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable = + function () { + return Promise.resolve(false); + }; + } + } + + installShim(); + try { + global.__internalUserscriptsWebAuthnMicrosoftShim = true; + } catch (e) {} +})(); diff --git a/browser/internaluserscripts/components/internaluserscripts.js b/browser/internaluserscripts/components/internaluserscripts.js new file mode 100644 index 0000000000..d60ce90ea9 --- /dev/null +++ b/browser/internaluserscripts/components/internaluserscripts.js @@ -0,0 +1,278 @@ +/* This source file is licensed under the MIT License. + * A copy of the MIT License should have been distributed with this + * file. If not, see https://opensource.org/licenses/MIT. + */ + +if (typeof Cc === "undefined") { + var Cc = Components.classes; +} +if (typeof Ci === "undefined") { + var Ci = Components.interfaces; +} +if (typeof Cu === "undefined") { + var Cu = Components.utils; +} + +const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); +const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); + +const PREF_ENABLED = "browser.internal-userscripts.enabled"; + +function InternalUserscriptsService() { + this.wrappedJSObject = this; +} + +InternalUserscriptsService.prototype = { + classDescription: "Internal Userscripts Loader", + classID: Components.ID("{d8b4bd27-b458-4417-8dfe-3b80bb6375bc}"), + contractID: "@internaluserscripts.mozdev.org/service;1", + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), + + observe: function (subject, topic, data) { + if (topic === "profile-after-change") { + this._startup(); + } else if (topic === "quit-application") { + this._shutdown(); + } else if (topic === "nsPref:changed" && data === PREF_ENABLED) { + this._updateObserverState(); + } else if (topic === "document-element-inserted") { + let win = subject && subject.defaultView; + if (!win) { + return; + } + let self = this; + Services.tm.mainThread.dispatch(function () { + self._inject(win); + }, Ci.nsIThread.DISPATCH_NORMAL); + } + }, + + _startup: function () { + Services.obs.addObserver(this, "quit-application", false); + Services.prefs.addObserver(PREF_ENABLED, this, false); + this._updateObserverState(); + }, + + _shutdown: function () { + try { + Services.obs.removeObserver(this, "document-element-inserted"); + } catch (e) {} + try { + Services.obs.removeObserver(this, "quit-application"); + } catch (e) {} + try { + Services.prefs.removeObserver(PREF_ENABLED, this); + } catch (e) {} + this._observingDocuments = false; + }, + + _updateObserverState: function () { + let enabled = true; + try { + enabled = Services.prefs.getBoolPref(PREF_ENABLED, true); + } catch (e) {} + + if (enabled && !this._observingDocuments) { + Services.obs.addObserver(this, "document-element-inserted", false); + this._observingDocuments = true; + } else if (!enabled && this._observingDocuments) { + try { + Services.obs.removeObserver(this, "document-element-inserted"); + } catch (e) {} + this._observingDocuments = false; + } + }, + + _inject: function (win) { + if (!Services.prefs.getBoolPref(PREF_ENABLED, true)) { + return; + } + if (!win) { + return; + } + try { + let doc = win.document; + let uri = doc && doc.documentURIObject; + if (uri && (uri.schemeIs("chrome") || uri.schemeIs("resource"))) { + return; + } + } catch (e) {} + let contentWin = win.wrappedJSObject || win; + let logPolyfill = function (name, source) { + try { + if ( + contentWin.console && + typeof contentWin.console.info === "function" + ) { + let suffix = source ? " (" + source + ")" : ""; + contentWin.console.info( + "[internal userscripts] Loaded polyfill script: " + name + suffix, + ); + } + } catch (e) {} + }; + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/intl-displaynames-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsIntlDisplayNamesPolyfill) { + logPolyfill("Intl.DisplayNames", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/intl-listformat-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsIntlListFormatPolyfill) { + logPolyfill("Intl.ListFormat", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/intl-relativetimeformat-formattoparts-polyfill.user.js", + contentWin, + ); + if ( + contentWin.__internalUserscriptsIntlRelativeTimeFormatFormatToPartsPolyfill + ) { + logPolyfill("Intl.RelativeTimeFormat.formatToParts", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/intl-segmenter-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsIntlSegmenterPolyfill) { + logPolyfill("Intl.Segmenter", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/webauthn-microsoft-shim.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsWebAuthnMicrosoftShim) { + logPolyfill("WebAuthn Microsoft unsupported shim", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/elementfrompoint-finite-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsElementFromPointFinitePolyfill) { + logPolyfill("Document.elementFromPoint finite-args shim", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/getanimations-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsGetAnimationsPolyfill) { + logPolyfill("getAnimations", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/imagedecode-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsImageDecodePolyfill) { + logPolyfill("HTMLImageElement.decode", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/transformstream-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsTransformStreamPolyfill) { + logPolyfill("TransformStream", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/textencoderstream-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsTextEncoderStreamPolyfill) { + logPolyfill("TextEncoderStream", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/textdecoderstream-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsTextDecoderStreamPolyfill) { + logPolyfill("TextDecoderStream", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/readablestream-pipeto-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsReadableStreamPipeToPolyfill) { + logPolyfill("ReadableStream.pipeTo", "bundled"); + } + } catch (e) { + // ignore + } + + try { + Services.scriptloader.loadSubScript( + "chrome://internaluserscripts/content/bundled-scripts/readablestream-pipethrough-polyfill.user.js", + contentWin, + ); + if (contentWin.__internalUserscriptsReadableStreamPipeThroughPolyfill) { + logPolyfill("ReadableStream.pipeThrough", "bundled"); + } + } catch (e) { + // ignore + } + }, +}; + +var NSGetFactory = XPCOMUtils.generateNSGetFactory([ + InternalUserscriptsService, +]); diff --git a/browser/internaluserscripts/components/internaluserscripts.manifest b/browser/internaluserscripts/components/internaluserscripts.manifest new file mode 100644 index 0000000000..9a43b19bae --- /dev/null +++ b/browser/internaluserscripts/components/internaluserscripts.manifest @@ -0,0 +1,7 @@ +# 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/. + +component {d8b4bd27-b458-4417-8dfe-3b80bb6375bc} internaluserscripts.js +contract @internaluserscripts.mozdev.org/service;1 {d8b4bd27-b458-4417-8dfe-3b80bb6375bc} +category profile-after-change internaluserscripts @internaluserscripts.mozdev.org/service;1 diff --git a/browser/internaluserscripts/defaults/preferences/internaluserscripts.js b/browser/internaluserscripts/defaults/preferences/internaluserscripts.js new file mode 100644 index 0000000000..f87d1d0121 --- /dev/null +++ b/browser/internaluserscripts/defaults/preferences/internaluserscripts.js @@ -0,0 +1,5 @@ +// 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/. + +pref("browser.internal-userscripts.enabled", true); diff --git a/application/basilisk/themes/windows/communicator/moz.build b/browser/internaluserscripts/internaluserscripts.manifest similarity index 63% rename from application/basilisk/themes/windows/communicator/moz.build rename to browser/internaluserscripts/internaluserscripts.manifest index 635fa39c99..fea7393c1b 100644 --- a/application/basilisk/themes/windows/communicator/moz.build +++ b/browser/internaluserscripts/internaluserscripts.manifest @@ -1,6 +1,6 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file +content internaluserscripts internaluserscripts/content/ +resource internaluserscripts internaluserscripts/content/ diff --git a/application/basilisk/branding/unofficial/locales/browserconfig.properties b/browser/internaluserscripts/jar.mn similarity index 55% rename from application/basilisk/branding/unofficial/locales/browserconfig.properties rename to browser/internaluserscripts/jar.mn index 06cefece3b..dbf882506f 100644 --- a/application/basilisk/branding/unofficial/locales/browserconfig.properties +++ b/browser/internaluserscripts/jar.mn @@ -2,5 +2,8 @@ # 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/. -# Do NOT localize or otherwise change these values -browser.startup.homepage=about:home +internaluserscripts.jar: +% content internaluserscripts %content/ +% resource internaluserscripts %content/ + + content/bundled-scripts/ (bundled-scripts/*) diff --git a/browser/internaluserscripts/moz.build b/browser/internaluserscripts/moz.build new file mode 100644 index 0000000000..40f2b86f9d --- /dev/null +++ b/browser/internaluserscripts/moz.build @@ -0,0 +1,33 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] + +FINAL_TARGET = 'dist/bin/browser' +FINAL_TARGET_FILES.components += [ + 'components/internaluserscripts.js', + 'components/internaluserscripts.manifest', +] + +FINAL_TARGET_FILES['defaults/preferences'] += [ + 'defaults/preferences/internaluserscripts.js', +] + +# Copy any bundled internal user scripts into the app dir for automatic import. +FINAL_TARGET_FILES['internal-userscripts'] += [ + 'bundled-scripts/elementfrompoint-finite-polyfill.user.js', + 'bundled-scripts/getanimations-polyfill.user.js', + 'bundled-scripts/imagedecode-polyfill.user.js', + 'bundled-scripts/intl-displaynames-polyfill.user.js', + 'bundled-scripts/intl-listformat-polyfill.user.js', + 'bundled-scripts/intl-relativetimeformat-formattoparts-polyfill.user.js', + 'bundled-scripts/intl-segmenter-polyfill.user.js', + 'bundled-scripts/readablestream-pipethrough-polyfill.user.js', + 'bundled-scripts/readablestream-pipeto-polyfill.user.js', + 'bundled-scripts/textdecoderstream-polyfill.user.js', + 'bundled-scripts/textencoderstream-polyfill.user.js', + 'bundled-scripts/transformstream-polyfill.user.js', + 'bundled-scripts/webauthn-microsoft-shim.user.js', +] diff --git a/application/basilisk/locales/Makefile.in b/browser/locales/Makefile.in similarity index 100% rename from application/basilisk/locales/Makefile.in rename to browser/locales/Makefile.in diff --git a/application/basilisk/locales/all-locales b/browser/locales/all-locales similarity index 100% rename from application/basilisk/locales/all-locales rename to browser/locales/all-locales diff --git a/application/basilisk/locales/en-US/chrome/browser-region/region.properties b/browser/locales/en-US/chrome/browser-region/region.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser-region/region.properties rename to browser/locales/en-US/chrome/browser-region/region.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutDialog.dtd b/browser/locales/en-US/chrome/browser/aboutDialog.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutDialog.dtd rename to browser/locales/en-US/chrome/browser/aboutDialog.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutHealthReport.dtd b/browser/locales/en-US/chrome/browser/aboutHealthReport.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutHealthReport.dtd rename to browser/locales/en-US/chrome/browser/aboutHealthReport.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutHome.dtd b/browser/locales/en-US/chrome/browser/aboutHome.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutHome.dtd rename to browser/locales/en-US/chrome/browser/aboutHome.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd b/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd rename to browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutPrivateBrowsing.properties b/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutPrivateBrowsing.properties rename to browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutRobots.dtd b/browser/locales/en-US/chrome/browser/aboutRobots.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutRobots.dtd rename to browser/locales/en-US/chrome/browser/aboutRobots.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutSearchReset.dtd b/browser/locales/en-US/chrome/browser/aboutSearchReset.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutSearchReset.dtd rename to browser/locales/en-US/chrome/browser/aboutSearchReset.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutSessionRestore.dtd b/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutSessionRestore.dtd rename to browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutSyncTabs.dtd b/browser/locales/en-US/chrome/browser/aboutSyncTabs.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutSyncTabs.dtd rename to browser/locales/en-US/chrome/browser/aboutSyncTabs.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutTabCrashed.dtd b/browser/locales/en-US/chrome/browser/aboutTabCrashed.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/aboutTabCrashed.dtd rename to browser/locales/en-US/chrome/browser/aboutTabCrashed.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/accounts.properties b/browser/locales/en-US/chrome/browser/accounts.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/accounts.properties rename to browser/locales/en-US/chrome/browser/accounts.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/baseMenuOverlay.dtd b/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/baseMenuOverlay.dtd rename to browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/browser.dtd rename to browser/locales/en-US/chrome/browser/browser.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/browser.properties rename to browser/locales/en-US/chrome/browser/browser.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties rename to browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/downloads/downloads.dtd b/browser/locales/en-US/chrome/browser/downloads/downloads.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/downloads/downloads.dtd rename to browser/locales/en-US/chrome/browser/downloads/downloads.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/downloads/downloads.properties b/browser/locales/en-US/chrome/browser/downloads/downloads.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/downloads/downloads.properties rename to browser/locales/en-US/chrome/browser/downloads/downloads.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/engineManager.properties b/browser/locales/en-US/chrome/browser/engineManager.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/engineManager.properties rename to browser/locales/en-US/chrome/browser/engineManager.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/feeds/subscribe.dtd b/browser/locales/en-US/chrome/browser/feeds/subscribe.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/feeds/subscribe.dtd rename to browser/locales/en-US/chrome/browser/feeds/subscribe.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/feeds/subscribe.properties b/browser/locales/en-US/chrome/browser/feeds/subscribe.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/feeds/subscribe.properties rename to browser/locales/en-US/chrome/browser/feeds/subscribe.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/lightweightThemes.properties b/browser/locales/en-US/chrome/browser/lightweightThemes.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/lightweightThemes.properties rename to browser/locales/en-US/chrome/browser/lightweightThemes.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/migration/migration.dtd b/browser/locales/en-US/chrome/browser/migration/migration.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/migration/migration.dtd rename to browser/locales/en-US/chrome/browser/migration/migration.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/migration/migration.properties b/browser/locales/en-US/chrome/browser/migration/migration.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/migration/migration.properties rename to browser/locales/en-US/chrome/browser/migration/migration.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/newTab.dtd b/browser/locales/en-US/chrome/browser/newTab.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/newTab.dtd rename to browser/locales/en-US/chrome/browser/newTab.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/newTab.properties b/browser/locales/en-US/chrome/browser/newTab.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/newTab.properties rename to browser/locales/en-US/chrome/browser/newTab.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/pageInfo.dtd b/browser/locales/en-US/chrome/browser/pageInfo.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/pageInfo.dtd rename to browser/locales/en-US/chrome/browser/pageInfo.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/pageInfo.properties b/browser/locales/en-US/chrome/browser/pageInfo.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/pageInfo.properties rename to browser/locales/en-US/chrome/browser/pageInfo.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/places/bookmarkProperties.properties b/browser/locales/en-US/chrome/browser/places/bookmarkProperties.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/places/bookmarkProperties.properties rename to browser/locales/en-US/chrome/browser/places/bookmarkProperties.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/places/editBookmarkOverlay.dtd b/browser/locales/en-US/chrome/browser/places/editBookmarkOverlay.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/places/editBookmarkOverlay.dtd rename to browser/locales/en-US/chrome/browser/places/editBookmarkOverlay.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/places/moveBookmarks.dtd b/browser/locales/en-US/chrome/browser/places/moveBookmarks.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/places/moveBookmarks.dtd rename to browser/locales/en-US/chrome/browser/places/moveBookmarks.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/places/places.dtd b/browser/locales/en-US/chrome/browser/places/places.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/places/places.dtd rename to browser/locales/en-US/chrome/browser/places/places.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/places/places.properties b/browser/locales/en-US/chrome/browser/places/places.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/places/places.properties rename to browser/locales/en-US/chrome/browser/places/places.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/advanced.dtd b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/advanced.dtd rename to browser/locales/en-US/chrome/browser/preferences/advanced.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/applicationManager.dtd b/browser/locales/en-US/chrome/browser/preferences/applicationManager.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/applicationManager.dtd rename to browser/locales/en-US/chrome/browser/preferences/applicationManager.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/applicationManager.properties b/browser/locales/en-US/chrome/browser/preferences/applicationManager.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/applicationManager.properties rename to browser/locales/en-US/chrome/browser/preferences/applicationManager.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/applications.dtd b/browser/locales/en-US/chrome/browser/preferences/applications.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/applications.dtd rename to browser/locales/en-US/chrome/browser/preferences/applications.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/blocklists.dtd b/browser/locales/en-US/chrome/browser/preferences/blocklists.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/blocklists.dtd rename to browser/locales/en-US/chrome/browser/preferences/blocklists.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/colors.dtd b/browser/locales/en-US/chrome/browser/preferences/colors.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/colors.dtd rename to browser/locales/en-US/chrome/browser/preferences/colors.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/connection.dtd b/browser/locales/en-US/chrome/browser/preferences/connection.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/connection.dtd rename to browser/locales/en-US/chrome/browser/preferences/connection.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/containers.dtd b/browser/locales/en-US/chrome/browser/preferences/containers.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/containers.dtd rename to browser/locales/en-US/chrome/browser/preferences/containers.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/containers.properties b/browser/locales/en-US/chrome/browser/preferences/containers.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/containers.properties rename to browser/locales/en-US/chrome/browser/preferences/containers.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/content.dtd b/browser/locales/en-US/chrome/browser/preferences/content.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/content.dtd rename to browser/locales/en-US/chrome/browser/preferences/content.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/cookies.dtd b/browser/locales/en-US/chrome/browser/preferences/cookies.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/cookies.dtd rename to browser/locales/en-US/chrome/browser/preferences/cookies.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/fonts.dtd b/browser/locales/en-US/chrome/browser/preferences/fonts.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/fonts.dtd rename to browser/locales/en-US/chrome/browser/preferences/fonts.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/languages.dtd b/browser/locales/en-US/chrome/browser/preferences/languages.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/languages.dtd rename to browser/locales/en-US/chrome/browser/preferences/languages.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/main.dtd b/browser/locales/en-US/chrome/browser/preferences/main.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/main.dtd rename to browser/locales/en-US/chrome/browser/preferences/main.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/permissions.dtd b/browser/locales/en-US/chrome/browser/preferences/permissions.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/permissions.dtd rename to browser/locales/en-US/chrome/browser/preferences/permissions.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/preferences.dtd b/browser/locales/en-US/chrome/browser/preferences/preferences.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/preferences.dtd rename to browser/locales/en-US/chrome/browser/preferences/preferences.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/preferences.properties b/browser/locales/en-US/chrome/browser/preferences/preferences.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/preferences.properties rename to browser/locales/en-US/chrome/browser/preferences/preferences.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/privacy.dtd b/browser/locales/en-US/chrome/browser/preferences/privacy.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/privacy.dtd rename to browser/locales/en-US/chrome/browser/preferences/privacy.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/search.dtd b/browser/locales/en-US/chrome/browser/preferences/search.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/search.dtd rename to browser/locales/en-US/chrome/browser/preferences/search.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/security.dtd b/browser/locales/en-US/chrome/browser/preferences/security.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/security.dtd rename to browser/locales/en-US/chrome/browser/preferences/security.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/selectBookmark.dtd b/browser/locales/en-US/chrome/browser/preferences/selectBookmark.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/selectBookmark.dtd rename to browser/locales/en-US/chrome/browser/preferences/selectBookmark.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/sync.dtd b/browser/locales/en-US/chrome/browser/preferences/sync.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/sync.dtd rename to browser/locales/en-US/chrome/browser/preferences/sync.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/tabs.dtd b/browser/locales/en-US/chrome/browser/preferences/tabs.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/preferences/tabs.dtd rename to browser/locales/en-US/chrome/browser/preferences/tabs.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/quitDialog.properties b/browser/locales/en-US/chrome/browser/quitDialog.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/quitDialog.properties rename to browser/locales/en-US/chrome/browser/quitDialog.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/safeMode.dtd b/browser/locales/en-US/chrome/browser/safeMode.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/safeMode.dtd rename to browser/locales/en-US/chrome/browser/safeMode.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/sanitize.dtd b/browser/locales/en-US/chrome/browser/sanitize.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/sanitize.dtd rename to browser/locales/en-US/chrome/browser/sanitize.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/search.properties b/browser/locales/en-US/chrome/browser/search.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/search.properties rename to browser/locales/en-US/chrome/browser/search.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/searchbar.dtd b/browser/locales/en-US/chrome/browser/searchbar.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/searchbar.dtd rename to browser/locales/en-US/chrome/browser/searchbar.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/setDesktopBackground.dtd b/browser/locales/en-US/chrome/browser/setDesktopBackground.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/setDesktopBackground.dtd rename to browser/locales/en-US/chrome/browser/setDesktopBackground.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/shellservice.properties b/browser/locales/en-US/chrome/browser/shellservice.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/shellservice.properties rename to browser/locales/en-US/chrome/browser/shellservice.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/sitePermissions.properties b/browser/locales/en-US/chrome/browser/sitePermissions.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/sitePermissions.properties rename to browser/locales/en-US/chrome/browser/sitePermissions.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/syncBrand.dtd b/browser/locales/en-US/chrome/browser/syncBrand.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncBrand.dtd rename to browser/locales/en-US/chrome/browser/syncBrand.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/syncCustomize.dtd b/browser/locales/en-US/chrome/browser/syncCustomize.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncCustomize.dtd rename to browser/locales/en-US/chrome/browser/syncCustomize.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/syncGenericChange.properties b/browser/locales/en-US/chrome/browser/syncGenericChange.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncGenericChange.properties rename to browser/locales/en-US/chrome/browser/syncGenericChange.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/syncKey.dtd b/browser/locales/en-US/chrome/browser/syncKey.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncKey.dtd rename to browser/locales/en-US/chrome/browser/syncKey.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/syncProgress.dtd b/browser/locales/en-US/chrome/browser/syncProgress.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncProgress.dtd rename to browser/locales/en-US/chrome/browser/syncProgress.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/syncQuota.dtd b/browser/locales/en-US/chrome/browser/syncQuota.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncQuota.dtd rename to browser/locales/en-US/chrome/browser/syncQuota.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/syncQuota.properties b/browser/locales/en-US/chrome/browser/syncQuota.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncQuota.properties rename to browser/locales/en-US/chrome/browser/syncQuota.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/syncSetup.dtd b/browser/locales/en-US/chrome/browser/syncSetup.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncSetup.dtd rename to browser/locales/en-US/chrome/browser/syncSetup.dtd diff --git a/application/basilisk/locales/en-US/chrome/browser/syncSetup.properties b/browser/locales/en-US/chrome/browser/syncSetup.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/syncSetup.properties rename to browser/locales/en-US/chrome/browser/syncSetup.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/tabbrowser.properties b/browser/locales/en-US/chrome/browser/tabbrowser.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/tabbrowser.properties rename to browser/locales/en-US/chrome/browser/tabbrowser.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/taskbar.properties b/browser/locales/en-US/chrome/browser/taskbar.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/taskbar.properties rename to browser/locales/en-US/chrome/browser/taskbar.properties diff --git a/application/basilisk/locales/en-US/chrome/browser/webrtcIndicator.properties b/browser/locales/en-US/chrome/browser/webrtcIndicator.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/browser/webrtcIndicator.properties rename to browser/locales/en-US/chrome/browser/webrtcIndicator.properties diff --git a/application/basilisk/locales/en-US/chrome/overrides/appstrings.properties b/browser/locales/en-US/chrome/overrides/appstrings.properties similarity index 100% rename from application/basilisk/locales/en-US/chrome/overrides/appstrings.properties rename to browser/locales/en-US/chrome/overrides/appstrings.properties diff --git a/application/basilisk/locales/en-US/chrome/overrides/netError.dtd b/browser/locales/en-US/chrome/overrides/netError.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/overrides/netError.dtd rename to browser/locales/en-US/chrome/overrides/netError.dtd diff --git a/application/basilisk/locales/en-US/chrome/overrides/settingsChange.dtd b/browser/locales/en-US/chrome/overrides/settingsChange.dtd similarity index 100% rename from application/basilisk/locales/en-US/chrome/overrides/settingsChange.dtd rename to browser/locales/en-US/chrome/overrides/settingsChange.dtd diff --git a/application/basilisk/locales/en-US/crashreporter/crashreporter-override.ini b/browser/locales/en-US/crashreporter/crashreporter-override.ini similarity index 100% rename from application/basilisk/locales/en-US/crashreporter/crashreporter-override.ini rename to browser/locales/en-US/crashreporter/crashreporter-override.ini diff --git a/application/basilisk/locales/en-US/defines.inc b/browser/locales/en-US/defines.inc similarity index 100% rename from application/basilisk/locales/en-US/defines.inc rename to browser/locales/en-US/defines.inc diff --git a/application/basilisk/locales/en-US/firefox-l10n.js b/browser/locales/en-US/firefox-l10n.js similarity index 100% rename from application/basilisk/locales/en-US/firefox-l10n.js rename to browser/locales/en-US/firefox-l10n.js diff --git a/application/basilisk/locales/en-US/installer/custom.properties b/browser/locales/en-US/installer/custom.properties similarity index 100% rename from application/basilisk/locales/en-US/installer/custom.properties rename to browser/locales/en-US/installer/custom.properties diff --git a/application/basilisk/locales/en-US/installer/mui.properties b/browser/locales/en-US/installer/mui.properties similarity index 100% rename from application/basilisk/locales/en-US/installer/mui.properties rename to browser/locales/en-US/installer/mui.properties diff --git a/application/basilisk/locales/en-US/installer/override.properties b/browser/locales/en-US/installer/override.properties similarity index 100% rename from application/basilisk/locales/en-US/installer/override.properties rename to browser/locales/en-US/installer/override.properties diff --git a/application/basilisk/locales/en-US/pdfviewer/chrome.properties b/browser/locales/en-US/pdfviewer/chrome.properties similarity index 100% rename from application/basilisk/locales/en-US/pdfviewer/chrome.properties rename to browser/locales/en-US/pdfviewer/chrome.properties diff --git a/application/basilisk/locales/en-US/pdfviewer/viewer.properties b/browser/locales/en-US/pdfviewer/viewer.properties similarity index 100% rename from application/basilisk/locales/en-US/pdfviewer/viewer.properties rename to browser/locales/en-US/pdfviewer/viewer.properties diff --git a/application/basilisk/locales/en-US/profile/bookmarks.inc b/browser/locales/en-US/profile/bookmarks.inc similarity index 100% rename from application/basilisk/locales/en-US/profile/bookmarks.inc rename to browser/locales/en-US/profile/bookmarks.inc diff --git a/application/basilisk/locales/en-US/updater/updater.ini b/browser/locales/en-US/updater/updater.ini similarity index 100% rename from application/basilisk/locales/en-US/updater/updater.ini rename to browser/locales/en-US/updater/updater.ini diff --git a/application/basilisk/locales/filter.py b/browser/locales/filter.py similarity index 100% rename from application/basilisk/locales/filter.py rename to browser/locales/filter.py diff --git a/application/basilisk/locales/generic/profile/bookmarks.html.in b/browser/locales/generic/profile/bookmarks.html.in similarity index 97% rename from application/basilisk/locales/generic/profile/bookmarks.html.in rename to browser/locales/generic/profile/bookmarks.html.in index c35f937447..58da30aad3 100644 --- a/application/basilisk/locales/generic/profile/bookmarks.html.in +++ b/browser/locales/generic/profile/bookmarks.html.in @@ -21,6 +21,6 @@

@bookmarks_toolbarfolder@

@bookmarks_toolbarfolder_description@

-

Report Issues
+
Report Issues

diff --git a/application/basilisk/locales/jar.mn b/browser/locales/jar.mn similarity index 100% rename from application/basilisk/locales/jar.mn rename to browser/locales/jar.mn diff --git a/application/basilisk/locales/l10n.ini b/browser/locales/l10n.ini similarity index 100% rename from application/basilisk/locales/l10n.ini rename to browser/locales/l10n.ini diff --git a/application/basilisk/branding/unofficial/content/moz.build b/browser/locales/moz.build similarity index 100% rename from application/basilisk/branding/unofficial/content/moz.build rename to browser/locales/moz.build diff --git a/application/basilisk/locales/search/list.json b/browser/locales/search/list.json similarity index 100% rename from application/basilisk/locales/search/list.json rename to browser/locales/search/list.json diff --git a/application/basilisk/locales/searchplugins/bing.xml b/browser/locales/searchplugins/bing.xml similarity index 100% rename from application/basilisk/locales/searchplugins/bing.xml rename to browser/locales/searchplugins/bing.xml diff --git a/application/basilisk/locales/searchplugins/ddg-lite.xml b/browser/locales/searchplugins/ddg-lite.xml similarity index 100% rename from application/basilisk/locales/searchplugins/ddg-lite.xml rename to browser/locales/searchplugins/ddg-lite.xml diff --git a/application/basilisk/locales/searchplugins/ddg.xml b/browser/locales/searchplugins/ddg.xml similarity index 100% rename from application/basilisk/locales/searchplugins/ddg.xml rename to browser/locales/searchplugins/ddg.xml diff --git a/application/basilisk/locales/searchplugins/google-2018.xml b/browser/locales/searchplugins/google-2018.xml similarity index 100% rename from application/basilisk/locales/searchplugins/google-2018.xml rename to browser/locales/searchplugins/google-2018.xml diff --git a/application/basilisk/locales/searchplugins/wikipedia.xml b/browser/locales/searchplugins/wikipedia.xml similarity index 100% rename from application/basilisk/locales/searchplugins/wikipedia.xml rename to browser/locales/searchplugins/wikipedia.xml diff --git a/application/basilisk/locales/searchplugins/yahoo.xml b/browser/locales/searchplugins/yahoo.xml similarity index 100% rename from application/basilisk/locales/searchplugins/yahoo.xml rename to browser/locales/searchplugins/yahoo.xml diff --git a/application/basilisk/locales/shipped-locales b/browser/locales/shipped-locales similarity index 100% rename from application/basilisk/locales/shipped-locales rename to browser/locales/shipped-locales diff --git a/application/basilisk/modules/AboutHome.jsm b/browser/modules/AboutHome.jsm similarity index 100% rename from application/basilisk/modules/AboutHome.jsm rename to browser/modules/AboutHome.jsm diff --git a/application/basilisk/modules/AboutNewTab.jsm b/browser/modules/AboutNewTab.jsm similarity index 100% rename from application/basilisk/modules/AboutNewTab.jsm rename to browser/modules/AboutNewTab.jsm diff --git a/application/basilisk/modules/AttributionCode.jsm b/browser/modules/AttributionCode.jsm similarity index 100% rename from application/basilisk/modules/AttributionCode.jsm rename to browser/modules/AttributionCode.jsm diff --git a/application/basilisk/modules/ContentClick.jsm b/browser/modules/ContentClick.jsm similarity index 100% rename from application/basilisk/modules/ContentClick.jsm rename to browser/modules/ContentClick.jsm diff --git a/application/basilisk/modules/ContentCrashHandlers.jsm b/browser/modules/ContentCrashHandlers.jsm similarity index 100% rename from application/basilisk/modules/ContentCrashHandlers.jsm rename to browser/modules/ContentCrashHandlers.jsm diff --git a/application/basilisk/modules/ContentLinkHandler.jsm b/browser/modules/ContentLinkHandler.jsm similarity index 100% rename from application/basilisk/modules/ContentLinkHandler.jsm rename to browser/modules/ContentLinkHandler.jsm diff --git a/application/basilisk/modules/ContentObservers.jsm b/browser/modules/ContentObservers.jsm similarity index 100% rename from application/basilisk/modules/ContentObservers.jsm rename to browser/modules/ContentObservers.jsm diff --git a/application/basilisk/modules/ContentSearch.jsm b/browser/modules/ContentSearch.jsm similarity index 100% rename from application/basilisk/modules/ContentSearch.jsm rename to browser/modules/ContentSearch.jsm diff --git a/application/basilisk/modules/ContentWebRTC.jsm b/browser/modules/ContentWebRTC.jsm similarity index 100% rename from application/basilisk/modules/ContentWebRTC.jsm rename to browser/modules/ContentWebRTC.jsm diff --git a/application/basilisk/modules/E10SUtils.jsm b/browser/modules/E10SUtils.jsm similarity index 100% rename from application/basilisk/modules/E10SUtils.jsm rename to browser/modules/E10SUtils.jsm diff --git a/application/basilisk/modules/Feeds.jsm b/browser/modules/Feeds.jsm similarity index 100% rename from application/basilisk/modules/Feeds.jsm rename to browser/modules/Feeds.jsm diff --git a/application/basilisk/modules/FormSubmitObserver.jsm b/browser/modules/FormSubmitObserver.jsm similarity index 100% rename from application/basilisk/modules/FormSubmitObserver.jsm rename to browser/modules/FormSubmitObserver.jsm diff --git a/application/basilisk/modules/FormValidationHandler.jsm b/browser/modules/FormValidationHandler.jsm similarity index 100% rename from application/basilisk/modules/FormValidationHandler.jsm rename to browser/modules/FormValidationHandler.jsm diff --git a/application/basilisk/modules/HiddenFrame.jsm b/browser/modules/HiddenFrame.jsm similarity index 100% rename from application/basilisk/modules/HiddenFrame.jsm rename to browser/modules/HiddenFrame.jsm diff --git a/application/basilisk/modules/LaterRun.jsm b/browser/modules/LaterRun.jsm similarity index 100% rename from application/basilisk/modules/LaterRun.jsm rename to browser/modules/LaterRun.jsm diff --git a/application/basilisk/modules/NetworkPrioritizer.jsm b/browser/modules/NetworkPrioritizer.jsm similarity index 100% rename from application/basilisk/modules/NetworkPrioritizer.jsm rename to browser/modules/NetworkPrioritizer.jsm diff --git a/application/basilisk/modules/PermissionUI.jsm b/browser/modules/PermissionUI.jsm similarity index 100% rename from application/basilisk/modules/PermissionUI.jsm rename to browser/modules/PermissionUI.jsm diff --git a/application/basilisk/modules/PluginContent.jsm b/browser/modules/PluginContent.jsm similarity index 100% rename from application/basilisk/modules/PluginContent.jsm rename to browser/modules/PluginContent.jsm diff --git a/application/basilisk/modules/ProcessHangMonitor.jsm b/browser/modules/ProcessHangMonitor.jsm similarity index 100% rename from application/basilisk/modules/ProcessHangMonitor.jsm rename to browser/modules/ProcessHangMonitor.jsm diff --git a/application/basilisk/modules/ReaderParent.jsm b/browser/modules/ReaderParent.jsm similarity index 100% rename from application/basilisk/modules/ReaderParent.jsm rename to browser/modules/ReaderParent.jsm diff --git a/application/basilisk/modules/RecentWindow.jsm b/browser/modules/RecentWindow.jsm similarity index 100% rename from application/basilisk/modules/RecentWindow.jsm rename to browser/modules/RecentWindow.jsm diff --git a/application/basilisk/modules/RemotePrompt.jsm b/browser/modules/RemotePrompt.jsm similarity index 100% rename from application/basilisk/modules/RemotePrompt.jsm rename to browser/modules/RemotePrompt.jsm diff --git a/application/basilisk/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm similarity index 100% rename from application/basilisk/modules/Sanitizer.jsm rename to browser/modules/Sanitizer.jsm diff --git a/application/basilisk/modules/SelfSupportBackend.jsm b/browser/modules/SelfSupportBackend.jsm similarity index 100% rename from application/basilisk/modules/SelfSupportBackend.jsm rename to browser/modules/SelfSupportBackend.jsm diff --git a/application/basilisk/modules/SitePermissions.jsm b/browser/modules/SitePermissions.jsm similarity index 100% rename from application/basilisk/modules/SitePermissions.jsm rename to browser/modules/SitePermissions.jsm diff --git a/application/basilisk/modules/TransientPrefs.jsm b/browser/modules/TransientPrefs.jsm similarity index 100% rename from application/basilisk/modules/TransientPrefs.jsm rename to browser/modules/TransientPrefs.jsm diff --git a/application/basilisk/modules/URLBarZoom.jsm b/browser/modules/URLBarZoom.jsm similarity index 100% rename from application/basilisk/modules/URLBarZoom.jsm rename to browser/modules/URLBarZoom.jsm diff --git a/application/basilisk/modules/Windows8WindowFrameColor.jsm b/browser/modules/Windows8WindowFrameColor.jsm similarity index 100% rename from application/basilisk/modules/Windows8WindowFrameColor.jsm rename to browser/modules/Windows8WindowFrameColor.jsm diff --git a/application/basilisk/modules/WindowsJumpLists.jsm b/browser/modules/WindowsJumpLists.jsm similarity index 100% rename from application/basilisk/modules/WindowsJumpLists.jsm rename to browser/modules/WindowsJumpLists.jsm diff --git a/application/basilisk/modules/WindowsPreviewPerTab.jsm b/browser/modules/WindowsPreviewPerTab.jsm similarity index 100% rename from application/basilisk/modules/WindowsPreviewPerTab.jsm rename to browser/modules/WindowsPreviewPerTab.jsm diff --git a/application/basilisk/modules/moz.build b/browser/modules/moz.build similarity index 100% rename from application/basilisk/modules/moz.build rename to browser/modules/moz.build diff --git a/application/basilisk/modules/offlineAppCache.jsm b/browser/modules/offlineAppCache.jsm similarity index 100% rename from application/basilisk/modules/offlineAppCache.jsm rename to browser/modules/offlineAppCache.jsm diff --git a/application/basilisk/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm similarity index 100% rename from application/basilisk/modules/webrtcUI.jsm rename to browser/modules/webrtcUI.jsm diff --git a/application/basilisk/moz.build b/browser/moz.build similarity index 96% rename from application/basilisk/moz.build rename to browser/moz.build index 2270476f9d..6e339e1888 100644 --- a/application/basilisk/moz.build +++ b/browser/moz.build @@ -10,6 +10,7 @@ SPHINX_TREES['browser'] = 'docs' DIRS += [ 'base', 'components', + 'internaluserscripts', 'locales', 'modules', 'themes', diff --git a/application/basilisk/moz.configure b/browser/moz.configure similarity index 89% rename from application/basilisk/moz.configure rename to browser/moz.configure index caa0a03616..ae130fde0c 100644 --- a/application/basilisk/moz.configure +++ b/browser/moz.configure @@ -6,4 +6,4 @@ # Specific options go here # Example: imply_option('MOZ_AV1', True) -include('../../toolkit/moz.configure') +include('../toolkit/moz.configure') diff --git a/application/basilisk/themes/LICENSE b/browser/themes/LICENSE similarity index 100% rename from application/basilisk/themes/LICENSE rename to browser/themes/LICENSE diff --git a/application/basilisk/themes/linux/Info.png b/browser/themes/linux/Info.png similarity index 100% rename from application/basilisk/themes/linux/Info.png rename to browser/themes/linux/Info.png diff --git a/application/basilisk/themes/linux/Privacy-16.png b/browser/themes/linux/Privacy-16.png similarity index 100% rename from application/basilisk/themes/linux/Privacy-16.png rename to browser/themes/linux/Privacy-16.png diff --git a/application/basilisk/themes/linux/Security-broken.png b/browser/themes/linux/Security-broken.png similarity index 100% rename from application/basilisk/themes/linux/Security-broken.png rename to browser/themes/linux/Security-broken.png diff --git a/application/basilisk/themes/linux/Toolbar-inverted.png b/browser/themes/linux/Toolbar-inverted.png similarity index 100% rename from application/basilisk/themes/linux/Toolbar-inverted.png rename to browser/themes/linux/Toolbar-inverted.png diff --git a/application/basilisk/themes/linux/Toolbar-inverted@2x.png b/browser/themes/linux/Toolbar-inverted@2x.png similarity index 100% rename from application/basilisk/themes/linux/Toolbar-inverted@2x.png rename to browser/themes/linux/Toolbar-inverted@2x.png diff --git a/application/basilisk/themes/linux/Toolbar-small.png b/browser/themes/linux/Toolbar-small.png similarity index 100% rename from application/basilisk/themes/linux/Toolbar-small.png rename to browser/themes/linux/Toolbar-small.png diff --git a/application/basilisk/themes/linux/Toolbar.png b/browser/themes/linux/Toolbar.png similarity index 100% rename from application/basilisk/themes/linux/Toolbar.png rename to browser/themes/linux/Toolbar.png diff --git a/application/basilisk/themes/linux/Toolbar@2x.png b/browser/themes/linux/Toolbar@2x.png similarity index 100% rename from application/basilisk/themes/linux/Toolbar@2x.png rename to browser/themes/linux/Toolbar@2x.png diff --git a/application/basilisk/themes/linux/aboutSessionRestore-window-icon.png b/browser/themes/linux/aboutSessionRestore-window-icon.png similarity index 100% rename from application/basilisk/themes/linux/aboutSessionRestore-window-icon.png rename to browser/themes/linux/aboutSessionRestore-window-icon.png diff --git a/application/basilisk/themes/linux/aboutSyncTabs.css b/browser/themes/linux/aboutSyncTabs.css similarity index 100% rename from application/basilisk/themes/linux/aboutSyncTabs.css rename to browser/themes/linux/aboutSyncTabs.css diff --git a/application/basilisk/themes/linux/actionicon-tab.png b/browser/themes/linux/actionicon-tab.png similarity index 100% rename from application/basilisk/themes/linux/actionicon-tab.png rename to browser/themes/linux/actionicon-tab.png diff --git a/application/basilisk/themes/linux/browser-lightweightTheme.css b/browser/themes/linux/browser-lightweightTheme.css similarity index 100% rename from application/basilisk/themes/linux/browser-lightweightTheme.css rename to browser/themes/linux/browser-lightweightTheme.css diff --git a/application/basilisk/themes/linux/browser.css b/browser/themes/linux/browser.css similarity index 100% rename from application/basilisk/themes/linux/browser.css rename to browser/themes/linux/browser.css diff --git a/application/basilisk/themes/linux/click-to-play-warning-stripes.png b/browser/themes/linux/click-to-play-warning-stripes.png similarity index 100% rename from application/basilisk/themes/linux/click-to-play-warning-stripes.png rename to browser/themes/linux/click-to-play-warning-stripes.png diff --git a/application/basilisk/themes/linux/communicator/communicator.css b/browser/themes/linux/communicator/communicator.css similarity index 100% rename from application/basilisk/themes/linux/communicator/communicator.css rename to browser/themes/linux/communicator/communicator.css diff --git a/application/basilisk/themes/linux/communicator/jar.mn b/browser/themes/linux/communicator/jar.mn similarity index 100% rename from application/basilisk/themes/linux/communicator/jar.mn rename to browser/themes/linux/communicator/jar.mn diff --git a/application/basilisk/components/customizableui/content/moz.build b/browser/themes/linux/communicator/moz.build similarity index 100% rename from application/basilisk/components/customizableui/content/moz.build rename to browser/themes/linux/communicator/moz.build diff --git a/application/basilisk/themes/linux/controlcenter/panel.css b/browser/themes/linux/controlcenter/panel.css similarity index 100% rename from application/basilisk/themes/linux/controlcenter/panel.css rename to browser/themes/linux/controlcenter/panel.css diff --git a/application/basilisk/themes/linux/customizableui/background-noise-toolbar.png b/browser/themes/linux/customizableui/background-noise-toolbar.png similarity index 100% rename from application/basilisk/themes/linux/customizableui/background-noise-toolbar.png rename to browser/themes/linux/customizableui/background-noise-toolbar.png diff --git a/application/basilisk/themes/linux/customizableui/customizeMode-gridTexture.png b/browser/themes/linux/customizableui/customizeMode-gridTexture.png similarity index 100% rename from application/basilisk/themes/linux/customizableui/customizeMode-gridTexture.png rename to browser/themes/linux/customizableui/customizeMode-gridTexture.png diff --git a/application/basilisk/themes/linux/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/linux/customizableui/customizeMode-separatorHorizontal.png similarity index 100% rename from application/basilisk/themes/linux/customizableui/customizeMode-separatorHorizontal.png rename to browser/themes/linux/customizableui/customizeMode-separatorHorizontal.png diff --git a/application/basilisk/themes/linux/customizableui/customizeMode-separatorVertical.png b/browser/themes/linux/customizableui/customizeMode-separatorVertical.png similarity index 100% rename from application/basilisk/themes/linux/customizableui/customizeMode-separatorVertical.png rename to browser/themes/linux/customizableui/customizeMode-separatorVertical.png diff --git a/application/basilisk/themes/linux/customizableui/panelUI.css b/browser/themes/linux/customizableui/panelUI.css similarity index 100% rename from application/basilisk/themes/linux/customizableui/panelUI.css rename to browser/themes/linux/customizableui/panelUI.css diff --git a/application/basilisk/themes/linux/devedition.css b/browser/themes/linux/devedition.css similarity index 100% rename from application/basilisk/themes/linux/devedition.css rename to browser/themes/linux/devedition.css diff --git a/application/basilisk/themes/linux/downloads/allDownloadsViewOverlay.css b/browser/themes/linux/downloads/allDownloadsViewOverlay.css similarity index 100% rename from application/basilisk/themes/linux/downloads/allDownloadsViewOverlay.css rename to browser/themes/linux/downloads/allDownloadsViewOverlay.css diff --git a/application/basilisk/themes/linux/downloads/download-glow-menuPanel.png b/browser/themes/linux/downloads/download-glow-menuPanel.png similarity index 100% rename from application/basilisk/themes/linux/downloads/download-glow-menuPanel.png rename to browser/themes/linux/downloads/download-glow-menuPanel.png diff --git a/application/basilisk/themes/linux/downloads/download-notification-finish.png b/browser/themes/linux/downloads/download-notification-finish.png similarity index 100% rename from application/basilisk/themes/linux/downloads/download-notification-finish.png rename to browser/themes/linux/downloads/download-notification-finish.png diff --git a/application/basilisk/themes/linux/downloads/download-notification-start.png b/browser/themes/linux/downloads/download-notification-start.png similarity index 100% rename from application/basilisk/themes/linux/downloads/download-notification-start.png rename to browser/themes/linux/downloads/download-notification-start.png diff --git a/application/basilisk/themes/linux/downloads/downloads.css b/browser/themes/linux/downloads/downloads.css similarity index 100% rename from application/basilisk/themes/linux/downloads/downloads.css rename to browser/themes/linux/downloads/downloads.css diff --git a/application/basilisk/themes/linux/downloads/indicator.css b/browser/themes/linux/downloads/indicator.css similarity index 100% rename from application/basilisk/themes/linux/downloads/indicator.css rename to browser/themes/linux/downloads/indicator.css diff --git a/application/basilisk/themes/linux/feeds/feedIcon.png b/browser/themes/linux/feeds/feedIcon.png similarity index 100% rename from application/basilisk/themes/linux/feeds/feedIcon.png rename to browser/themes/linux/feeds/feedIcon.png diff --git a/application/basilisk/themes/linux/feeds/feedIcon16.png b/browser/themes/linux/feeds/feedIcon16.png similarity index 100% rename from application/basilisk/themes/linux/feeds/feedIcon16.png rename to browser/themes/linux/feeds/feedIcon16.png diff --git a/application/basilisk/themes/linux/feeds/subscribe-ui.css b/browser/themes/linux/feeds/subscribe-ui.css similarity index 100% rename from application/basilisk/themes/linux/feeds/subscribe-ui.css rename to browser/themes/linux/feeds/subscribe-ui.css diff --git a/application/basilisk/themes/linux/feeds/subscribe.css b/browser/themes/linux/feeds/subscribe.css similarity index 100% rename from application/basilisk/themes/linux/feeds/subscribe.css rename to browser/themes/linux/feeds/subscribe.css diff --git a/application/basilisk/themes/linux/jar.mn b/browser/themes/linux/jar.mn similarity index 100% rename from application/basilisk/themes/linux/jar.mn rename to browser/themes/linux/jar.mn diff --git a/application/basilisk/themes/linux/linuxShared.inc b/browser/themes/linux/linuxShared.inc similarity index 100% rename from application/basilisk/themes/linux/linuxShared.inc rename to browser/themes/linux/linuxShared.inc diff --git a/application/basilisk/themes/linux/menuPanel-customize.png b/browser/themes/linux/menuPanel-customize.png similarity index 100% rename from application/basilisk/themes/linux/menuPanel-customize.png rename to browser/themes/linux/menuPanel-customize.png diff --git a/application/basilisk/themes/linux/menuPanel-customize@2x.png b/browser/themes/linux/menuPanel-customize@2x.png similarity index 100% rename from application/basilisk/themes/linux/menuPanel-customize@2x.png rename to browser/themes/linux/menuPanel-customize@2x.png diff --git a/application/basilisk/themes/linux/menuPanel-exit.png b/browser/themes/linux/menuPanel-exit.png similarity index 100% rename from application/basilisk/themes/linux/menuPanel-exit.png rename to browser/themes/linux/menuPanel-exit.png diff --git a/application/basilisk/themes/linux/menuPanel-exit@2x.png b/browser/themes/linux/menuPanel-exit@2x.png similarity index 100% rename from application/basilisk/themes/linux/menuPanel-exit@2x.png rename to browser/themes/linux/menuPanel-exit@2x.png diff --git a/application/basilisk/themes/linux/menuPanel-help.png b/browser/themes/linux/menuPanel-help.png similarity index 100% rename from application/basilisk/themes/linux/menuPanel-help.png rename to browser/themes/linux/menuPanel-help.png diff --git a/application/basilisk/themes/linux/menuPanel-help@2x.png b/browser/themes/linux/menuPanel-help@2x.png similarity index 100% rename from application/basilisk/themes/linux/menuPanel-help@2x.png rename to browser/themes/linux/menuPanel-help@2x.png diff --git a/application/basilisk/themes/linux/monitor.png b/browser/themes/linux/monitor.png similarity index 100% rename from application/basilisk/themes/linux/monitor.png rename to browser/themes/linux/monitor.png diff --git a/application/basilisk/themes/linux/monitor_16-10.png b/browser/themes/linux/monitor_16-10.png similarity index 100% rename from application/basilisk/themes/linux/monitor_16-10.png rename to browser/themes/linux/monitor_16-10.png diff --git a/application/basilisk/themes/linux/moz.build b/browser/themes/linux/moz.build similarity index 100% rename from application/basilisk/themes/linux/moz.build rename to browser/themes/linux/moz.build diff --git a/application/basilisk/themes/linux/newtab/newTab.css b/browser/themes/linux/newtab/newTab.css similarity index 100% rename from application/basilisk/themes/linux/newtab/newTab.css rename to browser/themes/linux/newtab/newTab.css diff --git a/application/basilisk/themes/linux/page-livemarks.png b/browser/themes/linux/page-livemarks.png similarity index 100% rename from application/basilisk/themes/linux/page-livemarks.png rename to browser/themes/linux/page-livemarks.png diff --git a/application/basilisk/themes/linux/pageInfo.css b/browser/themes/linux/pageInfo.css similarity index 100% rename from application/basilisk/themes/linux/pageInfo.css rename to browser/themes/linux/pageInfo.css diff --git a/application/basilisk/themes/linux/pageInfo.png b/browser/themes/linux/pageInfo.png similarity index 100% rename from application/basilisk/themes/linux/pageInfo.png rename to browser/themes/linux/pageInfo.png diff --git a/application/basilisk/themes/linux/places/autocomplete-star.png b/browser/themes/linux/places/autocomplete-star.png similarity index 100% rename from application/basilisk/themes/linux/places/autocomplete-star.png rename to browser/themes/linux/places/autocomplete-star.png diff --git a/application/basilisk/themes/linux/places/bookmarks-menu-arrow.png b/browser/themes/linux/places/bookmarks-menu-arrow.png similarity index 100% rename from application/basilisk/themes/linux/places/bookmarks-menu-arrow.png rename to browser/themes/linux/places/bookmarks-menu-arrow.png diff --git a/application/basilisk/themes/linux/places/bookmarks-notification-finish.png b/browser/themes/linux/places/bookmarks-notification-finish.png similarity index 100% rename from application/basilisk/themes/linux/places/bookmarks-notification-finish.png rename to browser/themes/linux/places/bookmarks-notification-finish.png diff --git a/application/basilisk/themes/linux/places/bookmarksMenu.png b/browser/themes/linux/places/bookmarksMenu.png similarity index 100% rename from application/basilisk/themes/linux/places/bookmarksMenu.png rename to browser/themes/linux/places/bookmarksMenu.png diff --git a/application/basilisk/themes/linux/places/bookmarksToolbar-menuPanel.png b/browser/themes/linux/places/bookmarksToolbar-menuPanel.png similarity index 100% rename from application/basilisk/themes/linux/places/bookmarksToolbar-menuPanel.png rename to browser/themes/linux/places/bookmarksToolbar-menuPanel.png diff --git a/application/basilisk/themes/linux/places/bookmarksToolbar.png b/browser/themes/linux/places/bookmarksToolbar.png similarity index 100% rename from application/basilisk/themes/linux/places/bookmarksToolbar.png rename to browser/themes/linux/places/bookmarksToolbar.png diff --git a/application/basilisk/themes/linux/places/calendar.png b/browser/themes/linux/places/calendar.png similarity index 100% rename from application/basilisk/themes/linux/places/calendar.png rename to browser/themes/linux/places/calendar.png diff --git a/application/basilisk/themes/linux/places/downloads.png b/browser/themes/linux/places/downloads.png similarity index 100% rename from application/basilisk/themes/linux/places/downloads.png rename to browser/themes/linux/places/downloads.png diff --git a/application/basilisk/themes/linux/places/editBookmarkOverlay.css b/browser/themes/linux/places/editBookmarkOverlay.css similarity index 100% rename from application/basilisk/themes/linux/places/editBookmarkOverlay.css rename to browser/themes/linux/places/editBookmarkOverlay.css diff --git a/application/basilisk/themes/linux/places/livemark-item.png b/browser/themes/linux/places/livemark-item.png similarity index 100% rename from application/basilisk/themes/linux/places/livemark-item.png rename to browser/themes/linux/places/livemark-item.png diff --git a/application/basilisk/themes/linux/places/organizer.css b/browser/themes/linux/places/organizer.css similarity index 100% rename from application/basilisk/themes/linux/places/organizer.css rename to browser/themes/linux/places/organizer.css diff --git a/application/basilisk/themes/linux/places/organizer.xml b/browser/themes/linux/places/organizer.xml similarity index 100% rename from application/basilisk/themes/linux/places/organizer.xml rename to browser/themes/linux/places/organizer.xml diff --git a/application/basilisk/themes/linux/places/places.css b/browser/themes/linux/places/places.css similarity index 100% rename from application/basilisk/themes/linux/places/places.css rename to browser/themes/linux/places/places.css diff --git a/application/basilisk/themes/linux/places/query.png b/browser/themes/linux/places/query.png similarity index 100% rename from application/basilisk/themes/linux/places/query.png rename to browser/themes/linux/places/query.png diff --git a/application/basilisk/themes/linux/places/starred48.png b/browser/themes/linux/places/starred48.png similarity index 100% rename from application/basilisk/themes/linux/places/starred48.png rename to browser/themes/linux/places/starred48.png diff --git a/application/basilisk/themes/linux/places/tag.png b/browser/themes/linux/places/tag.png similarity index 100% rename from application/basilisk/themes/linux/places/tag.png rename to browser/themes/linux/places/tag.png diff --git a/application/basilisk/themes/linux/places/toolbarDropMarker.png b/browser/themes/linux/places/toolbarDropMarker.png similarity index 100% rename from application/basilisk/themes/linux/places/toolbarDropMarker.png rename to browser/themes/linux/places/toolbarDropMarker.png diff --git a/application/basilisk/themes/linux/places/unsortedBookmarks.png b/browser/themes/linux/places/unsortedBookmarks.png similarity index 100% rename from application/basilisk/themes/linux/places/unsortedBookmarks.png rename to browser/themes/linux/places/unsortedBookmarks.png diff --git a/application/basilisk/themes/linux/places/unstarred48.png b/browser/themes/linux/places/unstarred48.png similarity index 100% rename from application/basilisk/themes/linux/places/unstarred48.png rename to browser/themes/linux/places/unstarred48.png diff --git a/application/basilisk/themes/linux/preferences/alwaysAsk.png b/browser/themes/linux/preferences/alwaysAsk.png similarity index 100% rename from application/basilisk/themes/linux/preferences/alwaysAsk.png rename to browser/themes/linux/preferences/alwaysAsk.png diff --git a/application/basilisk/themes/linux/preferences/applications.css b/browser/themes/linux/preferences/applications.css similarity index 100% rename from application/basilisk/themes/linux/preferences/applications.css rename to browser/themes/linux/preferences/applications.css diff --git a/application/basilisk/themes/linux/preferences/in-content/dialog.css b/browser/themes/linux/preferences/in-content/dialog.css similarity index 100% rename from application/basilisk/themes/linux/preferences/in-content/dialog.css rename to browser/themes/linux/preferences/in-content/dialog.css diff --git a/application/basilisk/themes/linux/preferences/in-content/preferences.css b/browser/themes/linux/preferences/in-content/preferences.css similarity index 100% rename from application/basilisk/themes/linux/preferences/in-content/preferences.css rename to browser/themes/linux/preferences/in-content/preferences.css diff --git a/application/basilisk/themes/linux/preferences/mail.png b/browser/themes/linux/preferences/mail.png similarity index 100% rename from application/basilisk/themes/linux/preferences/mail.png rename to browser/themes/linux/preferences/mail.png diff --git a/application/basilisk/themes/linux/preferences/preferences.css b/browser/themes/linux/preferences/preferences.css similarity index 100% rename from application/basilisk/themes/linux/preferences/preferences.css rename to browser/themes/linux/preferences/preferences.css diff --git a/application/basilisk/themes/linux/privatebrowsing-mask.png b/browser/themes/linux/privatebrowsing-mask.png similarity index 100% rename from application/basilisk/themes/linux/privatebrowsing-mask.png rename to browser/themes/linux/privatebrowsing-mask.png diff --git a/application/basilisk/themes/linux/reload-stop-go.png b/browser/themes/linux/reload-stop-go.png similarity index 100% rename from application/basilisk/themes/linux/reload-stop-go.png rename to browser/themes/linux/reload-stop-go.png diff --git a/application/basilisk/themes/linux/reload-stop-go@2x.png b/browser/themes/linux/reload-stop-go@2x.png similarity index 100% rename from application/basilisk/themes/linux/reload-stop-go@2x.png rename to browser/themes/linux/reload-stop-go@2x.png diff --git a/application/basilisk/themes/linux/sanitizeDialog.css b/browser/themes/linux/sanitizeDialog.css similarity index 100% rename from application/basilisk/themes/linux/sanitizeDialog.css rename to browser/themes/linux/sanitizeDialog.css diff --git a/application/basilisk/themes/linux/searchbar.css b/browser/themes/linux/searchbar.css similarity index 100% rename from application/basilisk/themes/linux/searchbar.css rename to browser/themes/linux/searchbar.css diff --git a/application/basilisk/themes/linux/setDesktopBackground.css b/browser/themes/linux/setDesktopBackground.css similarity index 100% rename from application/basilisk/themes/linux/setDesktopBackground.css rename to browser/themes/linux/setDesktopBackground.css diff --git a/application/basilisk/themes/linux/slowStartup-16.png b/browser/themes/linux/slowStartup-16.png similarity index 100% rename from application/basilisk/themes/linux/slowStartup-16.png rename to browser/themes/linux/slowStartup-16.png diff --git a/application/basilisk/themes/linux/sync-128.png b/browser/themes/linux/sync-128.png similarity index 100% rename from application/basilisk/themes/linux/sync-128.png rename to browser/themes/linux/sync-128.png diff --git a/application/basilisk/themes/linux/sync-16.png b/browser/themes/linux/sync-16.png similarity index 100% rename from application/basilisk/themes/linux/sync-16.png rename to browser/themes/linux/sync-16.png diff --git a/application/basilisk/themes/linux/sync-32.png b/browser/themes/linux/sync-32.png similarity index 100% rename from application/basilisk/themes/linux/sync-32.png rename to browser/themes/linux/sync-32.png diff --git a/application/basilisk/themes/linux/sync-bg.png b/browser/themes/linux/sync-bg.png similarity index 100% rename from application/basilisk/themes/linux/sync-bg.png rename to browser/themes/linux/sync-bg.png diff --git a/application/basilisk/themes/linux/sync-horizontalbar.png b/browser/themes/linux/sync-horizontalbar.png similarity index 100% rename from application/basilisk/themes/linux/sync-horizontalbar.png rename to browser/themes/linux/sync-horizontalbar.png diff --git a/application/basilisk/themes/linux/sync-horizontalbar@2x.png b/browser/themes/linux/sync-horizontalbar@2x.png similarity index 100% rename from application/basilisk/themes/linux/sync-horizontalbar@2x.png rename to browser/themes/linux/sync-horizontalbar@2x.png diff --git a/application/basilisk/themes/linux/sync-notification-24.png b/browser/themes/linux/sync-notification-24.png similarity index 100% rename from application/basilisk/themes/linux/sync-notification-24.png rename to browser/themes/linux/sync-notification-24.png diff --git a/application/basilisk/themes/linux/syncCommon.css b/browser/themes/linux/syncCommon.css similarity index 100% rename from application/basilisk/themes/linux/syncCommon.css rename to browser/themes/linux/syncCommon.css diff --git a/application/basilisk/themes/linux/syncProgress-horizontalbar.png b/browser/themes/linux/syncProgress-horizontalbar.png similarity index 100% rename from application/basilisk/themes/linux/syncProgress-horizontalbar.png rename to browser/themes/linux/syncProgress-horizontalbar.png diff --git a/application/basilisk/themes/linux/syncProgress-horizontalbar@2x.png b/browser/themes/linux/syncProgress-horizontalbar@2x.png similarity index 100% rename from application/basilisk/themes/linux/syncProgress-horizontalbar@2x.png rename to browser/themes/linux/syncProgress-horizontalbar@2x.png diff --git a/application/basilisk/themes/linux/syncProgress-menuPanel.png b/browser/themes/linux/syncProgress-menuPanel.png similarity index 100% rename from application/basilisk/themes/linux/syncProgress-menuPanel.png rename to browser/themes/linux/syncProgress-menuPanel.png diff --git a/application/basilisk/themes/linux/syncProgress-menuPanel@2x.png b/browser/themes/linux/syncProgress-menuPanel@2x.png similarity index 100% rename from application/basilisk/themes/linux/syncProgress-menuPanel@2x.png rename to browser/themes/linux/syncProgress-menuPanel@2x.png diff --git a/application/basilisk/themes/linux/syncProgress-toolbar-inverted.png b/browser/themes/linux/syncProgress-toolbar-inverted.png similarity index 100% rename from application/basilisk/themes/linux/syncProgress-toolbar-inverted.png rename to browser/themes/linux/syncProgress-toolbar-inverted.png diff --git a/application/basilisk/themes/linux/syncProgress-toolbar.png b/browser/themes/linux/syncProgress-toolbar.png similarity index 100% rename from application/basilisk/themes/linux/syncProgress-toolbar.png rename to browser/themes/linux/syncProgress-toolbar.png diff --git a/application/basilisk/themes/linux/syncProgress.css b/browser/themes/linux/syncProgress.css similarity index 100% rename from application/basilisk/themes/linux/syncProgress.css rename to browser/themes/linux/syncProgress.css diff --git a/application/basilisk/themes/linux/syncQuota.css b/browser/themes/linux/syncQuota.css similarity index 100% rename from application/basilisk/themes/linux/syncQuota.css rename to browser/themes/linux/syncQuota.css diff --git a/application/basilisk/themes/linux/syncSetup.css b/browser/themes/linux/syncSetup.css similarity index 100% rename from application/basilisk/themes/linux/syncSetup.css rename to browser/themes/linux/syncSetup.css diff --git a/application/basilisk/themes/linux/tabbrowser/alltabs-inverted.png b/browser/themes/linux/tabbrowser/alltabs-inverted.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/alltabs-inverted.png rename to browser/themes/linux/tabbrowser/alltabs-inverted.png diff --git a/application/basilisk/themes/linux/tabbrowser/alltabs.png b/browser/themes/linux/tabbrowser/alltabs.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/alltabs.png rename to browser/themes/linux/tabbrowser/alltabs.png diff --git a/application/basilisk/themes/linux/tabbrowser/newtab-inverted.svg b/browser/themes/linux/tabbrowser/newtab-inverted.svg similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/newtab-inverted.svg rename to browser/themes/linux/tabbrowser/newtab-inverted.svg diff --git a/application/basilisk/themes/linux/tabbrowser/newtab.svg b/browser/themes/linux/tabbrowser/newtab.svg similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/newtab.svg rename to browser/themes/linux/tabbrowser/newtab.svg diff --git a/application/basilisk/themes/linux/tabbrowser/tab-active-middle.png b/browser/themes/linux/tabbrowser/tab-active-middle.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-active-middle.png rename to browser/themes/linux/tabbrowser/tab-active-middle.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-active-middle@2x.png b/browser/themes/linux/tabbrowser/tab-active-middle@2x.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-active-middle@2x.png rename to browser/themes/linux/tabbrowser/tab-active-middle@2x.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-arrow-left-inverted.png b/browser/themes/linux/tabbrowser/tab-arrow-left-inverted.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-arrow-left-inverted.png rename to browser/themes/linux/tabbrowser/tab-arrow-left-inverted.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-arrow-left.png b/browser/themes/linux/tabbrowser/tab-arrow-left.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-arrow-left.png rename to browser/themes/linux/tabbrowser/tab-arrow-left.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-background-end.png b/browser/themes/linux/tabbrowser/tab-background-end.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-background-end.png rename to browser/themes/linux/tabbrowser/tab-background-end.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-background-end@2x.png b/browser/themes/linux/tabbrowser/tab-background-end@2x.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-background-end@2x.png rename to browser/themes/linux/tabbrowser/tab-background-end@2x.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-background-middle.png b/browser/themes/linux/tabbrowser/tab-background-middle.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-background-middle.png rename to browser/themes/linux/tabbrowser/tab-background-middle.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-background-middle@2x.png b/browser/themes/linux/tabbrowser/tab-background-middle@2x.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-background-middle@2x.png rename to browser/themes/linux/tabbrowser/tab-background-middle@2x.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-background-start.png b/browser/themes/linux/tabbrowser/tab-background-start.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-background-start.png rename to browser/themes/linux/tabbrowser/tab-background-start.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-background-start@2x.png b/browser/themes/linux/tabbrowser/tab-background-start@2x.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-background-start@2x.png rename to browser/themes/linux/tabbrowser/tab-background-start@2x.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-stroke-end.png b/browser/themes/linux/tabbrowser/tab-stroke-end.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-stroke-end.png rename to browser/themes/linux/tabbrowser/tab-stroke-end.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-stroke-end@2x.png b/browser/themes/linux/tabbrowser/tab-stroke-end@2x.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-stroke-end@2x.png rename to browser/themes/linux/tabbrowser/tab-stroke-end@2x.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-stroke-start.png b/browser/themes/linux/tabbrowser/tab-stroke-start.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-stroke-start.png rename to browser/themes/linux/tabbrowser/tab-stroke-start.png diff --git a/application/basilisk/themes/linux/tabbrowser/tab-stroke-start@2x.png b/browser/themes/linux/tabbrowser/tab-stroke-start@2x.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tab-stroke-start@2x.png rename to browser/themes/linux/tabbrowser/tab-stroke-start@2x.png diff --git a/application/basilisk/themes/linux/tabbrowser/tabDragIndicator.png b/browser/themes/linux/tabbrowser/tabDragIndicator.png similarity index 100% rename from application/basilisk/themes/linux/tabbrowser/tabDragIndicator.png rename to browser/themes/linux/tabbrowser/tabDragIndicator.png diff --git a/application/basilisk/themes/linux/webRTC-indicator.css b/browser/themes/linux/webRTC-indicator.css similarity index 100% rename from application/basilisk/themes/linux/webRTC-indicator.css rename to browser/themes/linux/webRTC-indicator.css diff --git a/application/basilisk/themes/moz.build b/browser/themes/moz.build similarity index 100% rename from application/basilisk/themes/moz.build rename to browser/themes/moz.build diff --git a/application/basilisk/themes/osx/Info.png b/browser/themes/osx/Info.png similarity index 100% rename from application/basilisk/themes/osx/Info.png rename to browser/themes/osx/Info.png diff --git a/application/basilisk/themes/osx/Privacy-16.png b/browser/themes/osx/Privacy-16.png similarity index 100% rename from application/basilisk/themes/osx/Privacy-16.png rename to browser/themes/osx/Privacy-16.png diff --git a/application/basilisk/themes/osx/Toolbar-background-noise.png b/browser/themes/osx/Toolbar-background-noise.png similarity index 100% rename from application/basilisk/themes/osx/Toolbar-background-noise.png rename to browser/themes/osx/Toolbar-background-noise.png diff --git a/application/basilisk/themes/osx/Toolbar-inverted.png b/browser/themes/osx/Toolbar-inverted.png similarity index 100% rename from application/basilisk/themes/osx/Toolbar-inverted.png rename to browser/themes/osx/Toolbar-inverted.png diff --git a/application/basilisk/themes/osx/Toolbar-inverted@2x.png b/browser/themes/osx/Toolbar-inverted@2x.png similarity index 100% rename from application/basilisk/themes/osx/Toolbar-inverted@2x.png rename to browser/themes/osx/Toolbar-inverted@2x.png diff --git a/application/basilisk/themes/osx/Toolbar-yosemite.png b/browser/themes/osx/Toolbar-yosemite.png similarity index 100% rename from application/basilisk/themes/osx/Toolbar-yosemite.png rename to browser/themes/osx/Toolbar-yosemite.png diff --git a/application/basilisk/themes/osx/Toolbar-yosemite@2x.png b/browser/themes/osx/Toolbar-yosemite@2x.png similarity index 100% rename from application/basilisk/themes/osx/Toolbar-yosemite@2x.png rename to browser/themes/osx/Toolbar-yosemite@2x.png diff --git a/application/basilisk/themes/osx/Toolbar.png b/browser/themes/osx/Toolbar.png similarity index 100% rename from application/basilisk/themes/osx/Toolbar.png rename to browser/themes/osx/Toolbar.png diff --git a/application/basilisk/themes/osx/Toolbar@2x.png b/browser/themes/osx/Toolbar@2x.png similarity index 100% rename from application/basilisk/themes/osx/Toolbar@2x.png rename to browser/themes/osx/Toolbar@2x.png diff --git a/application/basilisk/themes/osx/aboutSessionRestore-window-icon.png b/browser/themes/osx/aboutSessionRestore-window-icon.png similarity index 100% rename from application/basilisk/themes/osx/aboutSessionRestore-window-icon.png rename to browser/themes/osx/aboutSessionRestore-window-icon.png diff --git a/application/basilisk/themes/osx/aboutSyncTabs.css b/browser/themes/osx/aboutSyncTabs.css similarity index 100% rename from application/basilisk/themes/osx/aboutSyncTabs.css rename to browser/themes/osx/aboutSyncTabs.css diff --git a/application/basilisk/themes/osx/actionicon-tab.png b/browser/themes/osx/actionicon-tab.png similarity index 100% rename from application/basilisk/themes/osx/actionicon-tab.png rename to browser/themes/osx/actionicon-tab.png diff --git a/application/basilisk/themes/osx/actionicon-tab@2x.png b/browser/themes/osx/actionicon-tab@2x.png similarity index 100% rename from application/basilisk/themes/osx/actionicon-tab@2x.png rename to browser/themes/osx/actionicon-tab@2x.png diff --git a/application/basilisk/themes/osx/browser-lightweightTheme.css b/browser/themes/osx/browser-lightweightTheme.css similarity index 100% rename from application/basilisk/themes/osx/browser-lightweightTheme.css rename to browser/themes/osx/browser-lightweightTheme.css diff --git a/application/basilisk/themes/osx/browser.css b/browser/themes/osx/browser.css similarity index 100% rename from application/basilisk/themes/osx/browser.css rename to browser/themes/osx/browser.css diff --git a/application/basilisk/themes/osx/click-to-play-warning-stripes.png b/browser/themes/osx/click-to-play-warning-stripes.png similarity index 100% rename from application/basilisk/themes/osx/click-to-play-warning-stripes.png rename to browser/themes/osx/click-to-play-warning-stripes.png diff --git a/application/basilisk/themes/osx/communicator/communicator.css b/browser/themes/osx/communicator/communicator.css similarity index 100% rename from application/basilisk/themes/osx/communicator/communicator.css rename to browser/themes/osx/communicator/communicator.css diff --git a/application/basilisk/themes/osx/communicator/jar.mn b/browser/themes/osx/communicator/jar.mn similarity index 100% rename from application/basilisk/themes/osx/communicator/jar.mn rename to browser/themes/osx/communicator/jar.mn diff --git a/application/basilisk/locales/moz.build b/browser/themes/osx/communicator/moz.build similarity index 100% rename from application/basilisk/locales/moz.build rename to browser/themes/osx/communicator/moz.build diff --git a/application/basilisk/themes/osx/controlcenter/panel.css b/browser/themes/osx/controlcenter/panel.css similarity index 100% rename from application/basilisk/themes/osx/controlcenter/panel.css rename to browser/themes/osx/controlcenter/panel.css diff --git a/application/basilisk/themes/osx/customizableui/background-noise-toolbar.png b/browser/themes/osx/customizableui/background-noise-toolbar.png similarity index 100% rename from application/basilisk/themes/osx/customizableui/background-noise-toolbar.png rename to browser/themes/osx/customizableui/background-noise-toolbar.png diff --git a/application/basilisk/themes/osx/customizableui/customize-titleBar-toggle.png b/browser/themes/osx/customizableui/customize-titleBar-toggle.png similarity index 100% rename from application/basilisk/themes/osx/customizableui/customize-titleBar-toggle.png rename to browser/themes/osx/customizableui/customize-titleBar-toggle.png diff --git a/application/basilisk/themes/osx/customizableui/customize-titleBar-toggle@2x.png b/browser/themes/osx/customizableui/customize-titleBar-toggle@2x.png similarity index 100% rename from application/basilisk/themes/osx/customizableui/customize-titleBar-toggle@2x.png rename to browser/themes/osx/customizableui/customize-titleBar-toggle@2x.png diff --git a/application/basilisk/themes/osx/customizableui/customizeMode-gridTexture.png b/browser/themes/osx/customizableui/customizeMode-gridTexture.png similarity index 100% rename from application/basilisk/themes/osx/customizableui/customizeMode-gridTexture.png rename to browser/themes/osx/customizableui/customizeMode-gridTexture.png diff --git a/application/basilisk/themes/osx/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/osx/customizableui/customizeMode-separatorHorizontal.png similarity index 100% rename from application/basilisk/themes/osx/customizableui/customizeMode-separatorHorizontal.png rename to browser/themes/osx/customizableui/customizeMode-separatorHorizontal.png diff --git a/application/basilisk/themes/osx/customizableui/customizeMode-separatorVertical.png b/browser/themes/osx/customizableui/customizeMode-separatorVertical.png similarity index 100% rename from application/basilisk/themes/osx/customizableui/customizeMode-separatorVertical.png rename to browser/themes/osx/customizableui/customizeMode-separatorVertical.png diff --git a/application/basilisk/themes/osx/customizableui/panelUI.css b/browser/themes/osx/customizableui/panelUI.css similarity index 100% rename from application/basilisk/themes/osx/customizableui/panelUI.css rename to browser/themes/osx/customizableui/panelUI.css diff --git a/application/basilisk/themes/osx/devedition.css b/browser/themes/osx/devedition.css similarity index 100% rename from application/basilisk/themes/osx/devedition.css rename to browser/themes/osx/devedition.css diff --git a/application/basilisk/themes/osx/downloads/allDownloadsViewOverlay.css b/browser/themes/osx/downloads/allDownloadsViewOverlay.css similarity index 100% rename from application/basilisk/themes/osx/downloads/allDownloadsViewOverlay.css rename to browser/themes/osx/downloads/allDownloadsViewOverlay.css diff --git a/application/basilisk/themes/osx/downloads/download-glow-menuPanel.png b/browser/themes/osx/downloads/download-glow-menuPanel.png similarity index 100% rename from application/basilisk/themes/osx/downloads/download-glow-menuPanel.png rename to browser/themes/osx/downloads/download-glow-menuPanel.png diff --git a/application/basilisk/themes/osx/downloads/download-glow-menuPanel@2x.png b/browser/themes/osx/downloads/download-glow-menuPanel@2x.png similarity index 100% rename from application/basilisk/themes/osx/downloads/download-glow-menuPanel@2x.png rename to browser/themes/osx/downloads/download-glow-menuPanel@2x.png diff --git a/application/basilisk/themes/osx/downloads/download-notification-finish.png b/browser/themes/osx/downloads/download-notification-finish.png similarity index 100% rename from application/basilisk/themes/osx/downloads/download-notification-finish.png rename to browser/themes/osx/downloads/download-notification-finish.png diff --git a/application/basilisk/themes/osx/downloads/download-notification-finish@2x.png b/browser/themes/osx/downloads/download-notification-finish@2x.png similarity index 100% rename from application/basilisk/themes/osx/downloads/download-notification-finish@2x.png rename to browser/themes/osx/downloads/download-notification-finish@2x.png diff --git a/application/basilisk/themes/osx/downloads/download-notification-start.png b/browser/themes/osx/downloads/download-notification-start.png similarity index 100% rename from application/basilisk/themes/osx/downloads/download-notification-start.png rename to browser/themes/osx/downloads/download-notification-start.png diff --git a/application/basilisk/themes/osx/downloads/download-notification-start@2x.png b/browser/themes/osx/downloads/download-notification-start@2x.png similarity index 100% rename from application/basilisk/themes/osx/downloads/download-notification-start@2x.png rename to browser/themes/osx/downloads/download-notification-start@2x.png diff --git a/application/basilisk/themes/osx/downloads/downloads.css b/browser/themes/osx/downloads/downloads.css similarity index 100% rename from application/basilisk/themes/osx/downloads/downloads.css rename to browser/themes/osx/downloads/downloads.css diff --git a/application/basilisk/themes/osx/downloads/indicator.css b/browser/themes/osx/downloads/indicator.css similarity index 100% rename from application/basilisk/themes/osx/downloads/indicator.css rename to browser/themes/osx/downloads/indicator.css diff --git a/application/basilisk/themes/osx/feeds/feedIcon.png b/browser/themes/osx/feeds/feedIcon.png similarity index 100% rename from application/basilisk/themes/osx/feeds/feedIcon.png rename to browser/themes/osx/feeds/feedIcon.png diff --git a/application/basilisk/themes/osx/feeds/feedIcon16.png b/browser/themes/osx/feeds/feedIcon16.png similarity index 100% rename from application/basilisk/themes/osx/feeds/feedIcon16.png rename to browser/themes/osx/feeds/feedIcon16.png diff --git a/application/basilisk/themes/osx/feeds/subscribe-ui.css b/browser/themes/osx/feeds/subscribe-ui.css similarity index 100% rename from application/basilisk/themes/osx/feeds/subscribe-ui.css rename to browser/themes/osx/feeds/subscribe-ui.css diff --git a/application/basilisk/themes/osx/feeds/subscribe.css b/browser/themes/osx/feeds/subscribe.css similarity index 100% rename from application/basilisk/themes/osx/feeds/subscribe.css rename to browser/themes/osx/feeds/subscribe.css diff --git a/application/basilisk/themes/osx/jar.mn b/browser/themes/osx/jar.mn similarity index 100% rename from application/basilisk/themes/osx/jar.mn rename to browser/themes/osx/jar.mn diff --git a/application/basilisk/themes/osx/keyhole-circle.png b/browser/themes/osx/keyhole-circle.png similarity index 100% rename from application/basilisk/themes/osx/keyhole-circle.png rename to browser/themes/osx/keyhole-circle.png diff --git a/application/basilisk/themes/osx/keyhole-circle@2x.png b/browser/themes/osx/keyhole-circle@2x.png similarity index 100% rename from application/basilisk/themes/osx/keyhole-circle@2x.png rename to browser/themes/osx/keyhole-circle@2x.png diff --git a/application/basilisk/themes/osx/menu-back.png b/browser/themes/osx/menu-back.png similarity index 100% rename from application/basilisk/themes/osx/menu-back.png rename to browser/themes/osx/menu-back.png diff --git a/application/basilisk/themes/osx/menu-forward.png b/browser/themes/osx/menu-forward.png similarity index 100% rename from application/basilisk/themes/osx/menu-forward.png rename to browser/themes/osx/menu-forward.png diff --git a/application/basilisk/themes/osx/menuPanel-customize-yosemite.png b/browser/themes/osx/menuPanel-customize-yosemite.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-customize-yosemite.png rename to browser/themes/osx/menuPanel-customize-yosemite.png diff --git a/application/basilisk/themes/osx/menuPanel-customize-yosemite@2x.png b/browser/themes/osx/menuPanel-customize-yosemite@2x.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-customize-yosemite@2x.png rename to browser/themes/osx/menuPanel-customize-yosemite@2x.png diff --git a/application/basilisk/themes/osx/menuPanel-customize.png b/browser/themes/osx/menuPanel-customize.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-customize.png rename to browser/themes/osx/menuPanel-customize.png diff --git a/application/basilisk/themes/osx/menuPanel-customize@2x.png b/browser/themes/osx/menuPanel-customize@2x.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-customize@2x.png rename to browser/themes/osx/menuPanel-customize@2x.png diff --git a/application/basilisk/themes/osx/menuPanel-exit-yosemite.png b/browser/themes/osx/menuPanel-exit-yosemite.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-exit-yosemite.png rename to browser/themes/osx/menuPanel-exit-yosemite.png diff --git a/application/basilisk/themes/osx/menuPanel-exit-yosemite@2x.png b/browser/themes/osx/menuPanel-exit-yosemite@2x.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-exit-yosemite@2x.png rename to browser/themes/osx/menuPanel-exit-yosemite@2x.png diff --git a/application/basilisk/themes/osx/menuPanel-exit.png b/browser/themes/osx/menuPanel-exit.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-exit.png rename to browser/themes/osx/menuPanel-exit.png diff --git a/application/basilisk/themes/osx/menuPanel-exit@2x.png b/browser/themes/osx/menuPanel-exit@2x.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-exit@2x.png rename to browser/themes/osx/menuPanel-exit@2x.png diff --git a/application/basilisk/themes/osx/menuPanel-help-yosemite.png b/browser/themes/osx/menuPanel-help-yosemite.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-help-yosemite.png rename to browser/themes/osx/menuPanel-help-yosemite.png diff --git a/application/basilisk/themes/osx/menuPanel-help-yosemite@2x.png b/browser/themes/osx/menuPanel-help-yosemite@2x.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-help-yosemite@2x.png rename to browser/themes/osx/menuPanel-help-yosemite@2x.png diff --git a/application/basilisk/themes/osx/menuPanel-help.png b/browser/themes/osx/menuPanel-help.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-help.png rename to browser/themes/osx/menuPanel-help.png diff --git a/application/basilisk/themes/osx/menuPanel-help@2x.png b/browser/themes/osx/menuPanel-help@2x.png similarity index 100% rename from application/basilisk/themes/osx/menuPanel-help@2x.png rename to browser/themes/osx/menuPanel-help@2x.png diff --git a/application/basilisk/themes/osx/monitor.png b/browser/themes/osx/monitor.png similarity index 100% rename from application/basilisk/themes/osx/monitor.png rename to browser/themes/osx/monitor.png diff --git a/application/basilisk/themes/osx/monitor_16-10.png b/browser/themes/osx/monitor_16-10.png similarity index 100% rename from application/basilisk/themes/osx/monitor_16-10.png rename to browser/themes/osx/monitor_16-10.png diff --git a/application/basilisk/themes/osx/moz.build b/browser/themes/osx/moz.build similarity index 100% rename from application/basilisk/themes/osx/moz.build rename to browser/themes/osx/moz.build diff --git a/application/basilisk/themes/osx/newtab/newTab.css b/browser/themes/osx/newtab/newTab.css similarity index 100% rename from application/basilisk/themes/osx/newtab/newTab.css rename to browser/themes/osx/newtab/newTab.css diff --git a/application/basilisk/themes/osx/page-livemarks.png b/browser/themes/osx/page-livemarks.png similarity index 100% rename from application/basilisk/themes/osx/page-livemarks.png rename to browser/themes/osx/page-livemarks.png diff --git a/application/basilisk/themes/osx/page-livemarks@2x.png b/browser/themes/osx/page-livemarks@2x.png similarity index 100% rename from application/basilisk/themes/osx/page-livemarks@2x.png rename to browser/themes/osx/page-livemarks@2x.png diff --git a/application/basilisk/themes/osx/pageInfo.css b/browser/themes/osx/pageInfo.css similarity index 100% rename from application/basilisk/themes/osx/pageInfo.css rename to browser/themes/osx/pageInfo.css diff --git a/application/basilisk/themes/osx/panel-expander-closed.png b/browser/themes/osx/panel-expander-closed.png similarity index 100% rename from application/basilisk/themes/osx/panel-expander-closed.png rename to browser/themes/osx/panel-expander-closed.png diff --git a/application/basilisk/themes/osx/panel-expander-closed@2x.png b/browser/themes/osx/panel-expander-closed@2x.png similarity index 100% rename from application/basilisk/themes/osx/panel-expander-closed@2x.png rename to browser/themes/osx/panel-expander-closed@2x.png diff --git a/application/basilisk/themes/osx/panel-expander-open.png b/browser/themes/osx/panel-expander-open.png similarity index 100% rename from application/basilisk/themes/osx/panel-expander-open.png rename to browser/themes/osx/panel-expander-open.png diff --git a/application/basilisk/themes/osx/panel-expander-open@2x.png b/browser/themes/osx/panel-expander-open@2x.png similarity index 100% rename from application/basilisk/themes/osx/panel-expander-open@2x.png rename to browser/themes/osx/panel-expander-open@2x.png diff --git a/application/basilisk/themes/osx/panel-plus-sign.png b/browser/themes/osx/panel-plus-sign.png similarity index 100% rename from application/basilisk/themes/osx/panel-plus-sign.png rename to browser/themes/osx/panel-plus-sign.png diff --git a/application/basilisk/themes/osx/places/allBookmarks.png b/browser/themes/osx/places/allBookmarks.png similarity index 100% rename from application/basilisk/themes/osx/places/allBookmarks.png rename to browser/themes/osx/places/allBookmarks.png diff --git a/application/basilisk/themes/osx/places/autocomplete-star.png b/browser/themes/osx/places/autocomplete-star.png similarity index 100% rename from application/basilisk/themes/osx/places/autocomplete-star.png rename to browser/themes/osx/places/autocomplete-star.png diff --git a/application/basilisk/themes/osx/places/autocomplete-star@2x.png b/browser/themes/osx/places/autocomplete-star@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/autocomplete-star@2x.png rename to browser/themes/osx/places/autocomplete-star@2x.png diff --git a/application/basilisk/themes/osx/places/bookmarks-notification-finish.png b/browser/themes/osx/places/bookmarks-notification-finish.png similarity index 100% rename from application/basilisk/themes/osx/places/bookmarks-notification-finish.png rename to browser/themes/osx/places/bookmarks-notification-finish.png diff --git a/application/basilisk/themes/osx/places/bookmarks-notification-finish@2x.png b/browser/themes/osx/places/bookmarks-notification-finish@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/bookmarks-notification-finish@2x.png rename to browser/themes/osx/places/bookmarks-notification-finish@2x.png diff --git a/application/basilisk/themes/osx/places/bookmarksMenu.png b/browser/themes/osx/places/bookmarksMenu.png similarity index 100% rename from application/basilisk/themes/osx/places/bookmarksMenu.png rename to browser/themes/osx/places/bookmarksMenu.png diff --git a/application/basilisk/themes/osx/places/bookmarksToolbar-menuPanel.png b/browser/themes/osx/places/bookmarksToolbar-menuPanel.png similarity index 100% rename from application/basilisk/themes/osx/places/bookmarksToolbar-menuPanel.png rename to browser/themes/osx/places/bookmarksToolbar-menuPanel.png diff --git a/application/basilisk/themes/osx/places/bookmarksToolbar-menuPanel@2x.png b/browser/themes/osx/places/bookmarksToolbar-menuPanel@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/bookmarksToolbar-menuPanel@2x.png rename to browser/themes/osx/places/bookmarksToolbar-menuPanel@2x.png diff --git a/application/basilisk/themes/osx/places/bookmarksToolbar.png b/browser/themes/osx/places/bookmarksToolbar.png similarity index 100% rename from application/basilisk/themes/osx/places/bookmarksToolbar.png rename to browser/themes/osx/places/bookmarksToolbar.png diff --git a/application/basilisk/themes/osx/places/bookmarksToolbar@2x.png b/browser/themes/osx/places/bookmarksToolbar@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/bookmarksToolbar@2x.png rename to browser/themes/osx/places/bookmarksToolbar@2x.png diff --git a/application/basilisk/themes/osx/places/downloads.png b/browser/themes/osx/places/downloads.png similarity index 100% rename from application/basilisk/themes/osx/places/downloads.png rename to browser/themes/osx/places/downloads.png diff --git a/application/basilisk/themes/osx/places/editBookmarkOverlay.css b/browser/themes/osx/places/editBookmarkOverlay.css similarity index 100% rename from application/basilisk/themes/osx/places/editBookmarkOverlay.css rename to browser/themes/osx/places/editBookmarkOverlay.css diff --git a/application/basilisk/themes/osx/places/folderDropArrow.png b/browser/themes/osx/places/folderDropArrow.png similarity index 100% rename from application/basilisk/themes/osx/places/folderDropArrow.png rename to browser/themes/osx/places/folderDropArrow.png diff --git a/application/basilisk/themes/osx/places/folderDropArrow@2x.png b/browser/themes/osx/places/folderDropArrow@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/folderDropArrow@2x.png rename to browser/themes/osx/places/folderDropArrow@2x.png diff --git a/application/basilisk/themes/osx/places/history.png b/browser/themes/osx/places/history.png similarity index 100% rename from application/basilisk/themes/osx/places/history.png rename to browser/themes/osx/places/history.png diff --git a/application/basilisk/themes/osx/places/history@2x.png b/browser/themes/osx/places/history@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/history@2x.png rename to browser/themes/osx/places/history@2x.png diff --git a/application/basilisk/themes/osx/places/livemark-item.png b/browser/themes/osx/places/livemark-item.png similarity index 100% rename from application/basilisk/themes/osx/places/livemark-item.png rename to browser/themes/osx/places/livemark-item.png diff --git a/application/basilisk/themes/osx/places/minus-active.png b/browser/themes/osx/places/minus-active.png similarity index 100% rename from application/basilisk/themes/osx/places/minus-active.png rename to browser/themes/osx/places/minus-active.png diff --git a/application/basilisk/themes/osx/places/minus.png b/browser/themes/osx/places/minus.png similarity index 100% rename from application/basilisk/themes/osx/places/minus.png rename to browser/themes/osx/places/minus.png diff --git a/application/basilisk/themes/osx/places/organizer.css b/browser/themes/osx/places/organizer.css similarity index 100% rename from application/basilisk/themes/osx/places/organizer.css rename to browser/themes/osx/places/organizer.css diff --git a/application/basilisk/themes/osx/places/places.css b/browser/themes/osx/places/places.css similarity index 100% rename from application/basilisk/themes/osx/places/places.css rename to browser/themes/osx/places/places.css diff --git a/application/basilisk/themes/osx/places/plus-active.png b/browser/themes/osx/places/plus-active.png similarity index 100% rename from application/basilisk/themes/osx/places/plus-active.png rename to browser/themes/osx/places/plus-active.png diff --git a/application/basilisk/themes/osx/places/plus.png b/browser/themes/osx/places/plus.png similarity index 100% rename from application/basilisk/themes/osx/places/plus.png rename to browser/themes/osx/places/plus.png diff --git a/application/basilisk/themes/osx/places/query.png b/browser/themes/osx/places/query.png similarity index 100% rename from application/basilisk/themes/osx/places/query.png rename to browser/themes/osx/places/query.png diff --git a/application/basilisk/themes/osx/places/query@2x.png b/browser/themes/osx/places/query@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/query@2x.png rename to browser/themes/osx/places/query@2x.png diff --git a/application/basilisk/themes/osx/places/starred48.png b/browser/themes/osx/places/starred48.png similarity index 100% rename from application/basilisk/themes/osx/places/starred48.png rename to browser/themes/osx/places/starred48.png diff --git a/application/basilisk/themes/osx/places/starred48@2x.png b/browser/themes/osx/places/starred48@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/starred48@2x.png rename to browser/themes/osx/places/starred48@2x.png diff --git a/application/basilisk/themes/osx/places/tag.png b/browser/themes/osx/places/tag.png similarity index 100% rename from application/basilisk/themes/osx/places/tag.png rename to browser/themes/osx/places/tag.png diff --git a/application/basilisk/themes/osx/places/tag@2x.png b/browser/themes/osx/places/tag@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/tag@2x.png rename to browser/themes/osx/places/tag@2x.png diff --git a/application/basilisk/themes/osx/places/toolbar-lion.png b/browser/themes/osx/places/toolbar-lion.png similarity index 100% rename from application/basilisk/themes/osx/places/toolbar-lion.png rename to browser/themes/osx/places/toolbar-lion.png diff --git a/application/basilisk/themes/osx/places/toolbar.png b/browser/themes/osx/places/toolbar.png similarity index 100% rename from application/basilisk/themes/osx/places/toolbar.png rename to browser/themes/osx/places/toolbar.png diff --git a/application/basilisk/themes/osx/places/toolbarDropMarker.png b/browser/themes/osx/places/toolbarDropMarker.png similarity index 100% rename from application/basilisk/themes/osx/places/toolbarDropMarker.png rename to browser/themes/osx/places/toolbarDropMarker.png diff --git a/application/basilisk/themes/osx/places/unfiledBookmarks.png b/browser/themes/osx/places/unfiledBookmarks.png similarity index 100% rename from application/basilisk/themes/osx/places/unfiledBookmarks.png rename to browser/themes/osx/places/unfiledBookmarks.png diff --git a/application/basilisk/themes/osx/places/unfiledBookmarks@2x.png b/browser/themes/osx/places/unfiledBookmarks@2x.png similarity index 100% rename from application/basilisk/themes/osx/places/unfiledBookmarks@2x.png rename to browser/themes/osx/places/unfiledBookmarks@2x.png diff --git a/application/basilisk/themes/osx/places/unstarred48.png b/browser/themes/osx/places/unstarred48.png similarity index 100% rename from application/basilisk/themes/osx/places/unstarred48.png rename to browser/themes/osx/places/unstarred48.png diff --git a/application/basilisk/themes/osx/preferences/alwaysAsk.png b/browser/themes/osx/preferences/alwaysAsk.png similarity index 100% rename from application/basilisk/themes/osx/preferences/alwaysAsk.png rename to browser/themes/osx/preferences/alwaysAsk.png diff --git a/application/basilisk/themes/osx/preferences/application.png b/browser/themes/osx/preferences/application.png similarity index 100% rename from application/basilisk/themes/osx/preferences/application.png rename to browser/themes/osx/preferences/application.png diff --git a/application/basilisk/themes/osx/preferences/applications.css b/browser/themes/osx/preferences/applications.css similarity index 100% rename from application/basilisk/themes/osx/preferences/applications.css rename to browser/themes/osx/preferences/applications.css diff --git a/application/basilisk/themes/osx/preferences/in-content/dialog.css b/browser/themes/osx/preferences/in-content/dialog.css similarity index 100% rename from application/basilisk/themes/osx/preferences/in-content/dialog.css rename to browser/themes/osx/preferences/in-content/dialog.css diff --git a/application/basilisk/themes/osx/preferences/in-content/preferences.css b/browser/themes/osx/preferences/in-content/preferences.css similarity index 100% rename from application/basilisk/themes/osx/preferences/in-content/preferences.css rename to browser/themes/osx/preferences/in-content/preferences.css diff --git a/application/basilisk/themes/osx/preferences/preferences.css b/browser/themes/osx/preferences/preferences.css similarity index 100% rename from application/basilisk/themes/osx/preferences/preferences.css rename to browser/themes/osx/preferences/preferences.css diff --git a/application/basilisk/themes/osx/preferences/saveFile.png b/browser/themes/osx/preferences/saveFile.png similarity index 100% rename from application/basilisk/themes/osx/preferences/saveFile.png rename to browser/themes/osx/preferences/saveFile.png diff --git a/application/basilisk/themes/osx/privatebrowsing-mask-short.png b/browser/themes/osx/privatebrowsing-mask-short.png similarity index 100% rename from application/basilisk/themes/osx/privatebrowsing-mask-short.png rename to browser/themes/osx/privatebrowsing-mask-short.png diff --git a/application/basilisk/themes/osx/privatebrowsing-mask-short@2x.png b/browser/themes/osx/privatebrowsing-mask-short@2x.png similarity index 100% rename from application/basilisk/themes/osx/privatebrowsing-mask-short@2x.png rename to browser/themes/osx/privatebrowsing-mask-short@2x.png diff --git a/application/basilisk/themes/osx/privatebrowsing-mask.png b/browser/themes/osx/privatebrowsing-mask.png similarity index 100% rename from application/basilisk/themes/osx/privatebrowsing-mask.png rename to browser/themes/osx/privatebrowsing-mask.png diff --git a/application/basilisk/themes/osx/privatebrowsing-mask@2x.png b/browser/themes/osx/privatebrowsing-mask@2x.png similarity index 100% rename from application/basilisk/themes/osx/privatebrowsing-mask@2x.png rename to browser/themes/osx/privatebrowsing-mask@2x.png diff --git a/application/basilisk/themes/osx/reload-stop-go-yosemite.png b/browser/themes/osx/reload-stop-go-yosemite.png similarity index 100% rename from application/basilisk/themes/osx/reload-stop-go-yosemite.png rename to browser/themes/osx/reload-stop-go-yosemite.png diff --git a/application/basilisk/themes/osx/reload-stop-go-yosemite@2x.png b/browser/themes/osx/reload-stop-go-yosemite@2x.png similarity index 100% rename from application/basilisk/themes/osx/reload-stop-go-yosemite@2x.png rename to browser/themes/osx/reload-stop-go-yosemite@2x.png diff --git a/application/basilisk/themes/osx/reload-stop-go.png b/browser/themes/osx/reload-stop-go.png similarity index 100% rename from application/basilisk/themes/osx/reload-stop-go.png rename to browser/themes/osx/reload-stop-go.png diff --git a/application/basilisk/themes/osx/reload-stop-go@2x.png b/browser/themes/osx/reload-stop-go@2x.png similarity index 100% rename from application/basilisk/themes/osx/reload-stop-go@2x.png rename to browser/themes/osx/reload-stop-go@2x.png diff --git a/application/basilisk/themes/osx/sanitizeDialog.css b/browser/themes/osx/sanitizeDialog.css similarity index 100% rename from application/basilisk/themes/osx/sanitizeDialog.css rename to browser/themes/osx/sanitizeDialog.css diff --git a/application/basilisk/themes/osx/searchbar.css b/browser/themes/osx/searchbar.css similarity index 100% rename from application/basilisk/themes/osx/searchbar.css rename to browser/themes/osx/searchbar.css diff --git a/application/basilisk/themes/osx/setDesktopBackground.css b/browser/themes/osx/setDesktopBackground.css similarity index 100% rename from application/basilisk/themes/osx/setDesktopBackground.css rename to browser/themes/osx/setDesktopBackground.css diff --git a/application/basilisk/themes/osx/shared.inc b/browser/themes/osx/shared.inc similarity index 100% rename from application/basilisk/themes/osx/shared.inc rename to browser/themes/osx/shared.inc diff --git a/application/basilisk/themes/osx/slowStartup-16.png b/browser/themes/osx/slowStartup-16.png similarity index 100% rename from application/basilisk/themes/osx/slowStartup-16.png rename to browser/themes/osx/slowStartup-16.png diff --git a/application/basilisk/themes/osx/subtle-pattern.png b/browser/themes/osx/subtle-pattern.png similarity index 100% rename from application/basilisk/themes/osx/subtle-pattern.png rename to browser/themes/osx/subtle-pattern.png diff --git a/application/basilisk/themes/osx/sync-128.png b/browser/themes/osx/sync-128.png similarity index 100% rename from application/basilisk/themes/osx/sync-128.png rename to browser/themes/osx/sync-128.png diff --git a/application/basilisk/themes/osx/sync-16.png b/browser/themes/osx/sync-16.png similarity index 100% rename from application/basilisk/themes/osx/sync-16.png rename to browser/themes/osx/sync-16.png diff --git a/application/basilisk/themes/osx/sync-32.png b/browser/themes/osx/sync-32.png similarity index 100% rename from application/basilisk/themes/osx/sync-32.png rename to browser/themes/osx/sync-32.png diff --git a/application/basilisk/themes/osx/sync-bg.png b/browser/themes/osx/sync-bg.png similarity index 100% rename from application/basilisk/themes/osx/sync-bg.png rename to browser/themes/osx/sync-bg.png diff --git a/application/basilisk/themes/osx/sync-horizontalbar-yosemite.png b/browser/themes/osx/sync-horizontalbar-yosemite.png similarity index 100% rename from application/basilisk/themes/osx/sync-horizontalbar-yosemite.png rename to browser/themes/osx/sync-horizontalbar-yosemite.png diff --git a/application/basilisk/themes/osx/sync-horizontalbar-yosemite@2x.png b/browser/themes/osx/sync-horizontalbar-yosemite@2x.png similarity index 100% rename from application/basilisk/themes/osx/sync-horizontalbar-yosemite@2x.png rename to browser/themes/osx/sync-horizontalbar-yosemite@2x.png diff --git a/application/basilisk/themes/osx/sync-horizontalbar.png b/browser/themes/osx/sync-horizontalbar.png similarity index 100% rename from application/basilisk/themes/osx/sync-horizontalbar.png rename to browser/themes/osx/sync-horizontalbar.png diff --git a/application/basilisk/themes/osx/sync-horizontalbar@2x.png b/browser/themes/osx/sync-horizontalbar@2x.png similarity index 100% rename from application/basilisk/themes/osx/sync-horizontalbar@2x.png rename to browser/themes/osx/sync-horizontalbar@2x.png diff --git a/application/basilisk/themes/osx/sync-notification-24.png b/browser/themes/osx/sync-notification-24.png similarity index 100% rename from application/basilisk/themes/osx/sync-notification-24.png rename to browser/themes/osx/sync-notification-24.png diff --git a/application/basilisk/themes/osx/syncCommon.css b/browser/themes/osx/syncCommon.css similarity index 100% rename from application/basilisk/themes/osx/syncCommon.css rename to browser/themes/osx/syncCommon.css diff --git a/application/basilisk/themes/osx/syncProgress-horizontalbar.png b/browser/themes/osx/syncProgress-horizontalbar.png similarity index 100% rename from application/basilisk/themes/osx/syncProgress-horizontalbar.png rename to browser/themes/osx/syncProgress-horizontalbar.png diff --git a/application/basilisk/themes/osx/syncProgress-horizontalbar@2x.png b/browser/themes/osx/syncProgress-horizontalbar@2x.png similarity index 100% rename from application/basilisk/themes/osx/syncProgress-horizontalbar@2x.png rename to browser/themes/osx/syncProgress-horizontalbar@2x.png diff --git a/application/basilisk/themes/osx/syncProgress-menuPanel.png b/browser/themes/osx/syncProgress-menuPanel.png similarity index 100% rename from application/basilisk/themes/osx/syncProgress-menuPanel.png rename to browser/themes/osx/syncProgress-menuPanel.png diff --git a/application/basilisk/themes/osx/syncProgress-menuPanel@2x.png b/browser/themes/osx/syncProgress-menuPanel@2x.png similarity index 100% rename from application/basilisk/themes/osx/syncProgress-menuPanel@2x.png rename to browser/themes/osx/syncProgress-menuPanel@2x.png diff --git a/application/basilisk/themes/osx/syncProgress-toolbar-inverted.png b/browser/themes/osx/syncProgress-toolbar-inverted.png similarity index 100% rename from application/basilisk/themes/osx/syncProgress-toolbar-inverted.png rename to browser/themes/osx/syncProgress-toolbar-inverted.png diff --git a/application/basilisk/themes/osx/syncProgress-toolbar-inverted@2x.png b/browser/themes/osx/syncProgress-toolbar-inverted@2x.png similarity index 100% rename from application/basilisk/themes/osx/syncProgress-toolbar-inverted@2x.png rename to browser/themes/osx/syncProgress-toolbar-inverted@2x.png diff --git a/application/basilisk/themes/osx/syncProgress-toolbar.png b/browser/themes/osx/syncProgress-toolbar.png similarity index 100% rename from application/basilisk/themes/osx/syncProgress-toolbar.png rename to browser/themes/osx/syncProgress-toolbar.png diff --git a/application/basilisk/themes/osx/syncProgress-toolbar@2x.png b/browser/themes/osx/syncProgress-toolbar@2x.png similarity index 100% rename from application/basilisk/themes/osx/syncProgress-toolbar@2x.png rename to browser/themes/osx/syncProgress-toolbar@2x.png diff --git a/application/basilisk/themes/osx/syncProgress.css b/browser/themes/osx/syncProgress.css similarity index 100% rename from application/basilisk/themes/osx/syncProgress.css rename to browser/themes/osx/syncProgress.css diff --git a/application/basilisk/themes/osx/syncQuota.css b/browser/themes/osx/syncQuota.css similarity index 100% rename from application/basilisk/themes/osx/syncQuota.css rename to browser/themes/osx/syncQuota.css diff --git a/application/basilisk/themes/osx/syncSetup.css b/browser/themes/osx/syncSetup.css similarity index 100% rename from application/basilisk/themes/osx/syncSetup.css rename to browser/themes/osx/syncSetup.css diff --git a/application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png rename to browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png diff --git a/application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png rename to browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-lion.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-lion.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-lion.png rename to browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-lion.png diff --git a/application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-lion@2x.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-lion@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-lion@2x.png rename to browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-lion@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/alltabs-box-bkgnd-icon.png rename to browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon.png diff --git a/application/basilisk/themes/osx/tabbrowser/newtab-inverted.png b/browser/themes/osx/tabbrowser/newtab-inverted.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/newtab-inverted.png rename to browser/themes/osx/tabbrowser/newtab-inverted.png diff --git a/application/basilisk/themes/osx/tabbrowser/newtab-inverted@2x.png b/browser/themes/osx/tabbrowser/newtab-inverted@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/newtab-inverted@2x.png rename to browser/themes/osx/tabbrowser/newtab-inverted@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/newtab.png b/browser/themes/osx/tabbrowser/newtab.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/newtab.png rename to browser/themes/osx/tabbrowser/newtab.png diff --git a/application/basilisk/themes/osx/tabbrowser/newtab@2x.png b/browser/themes/osx/tabbrowser/newtab@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/newtab@2x.png rename to browser/themes/osx/tabbrowser/newtab@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-active-middle-yosemite-inactive.png b/browser/themes/osx/tabbrowser/tab-active-middle-yosemite-inactive.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-active-middle-yosemite-inactive.png rename to browser/themes/osx/tabbrowser/tab-active-middle-yosemite-inactive.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-active-middle-yosemite-inactive@2x.png b/browser/themes/osx/tabbrowser/tab-active-middle-yosemite-inactive@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-active-middle-yosemite-inactive@2x.png rename to browser/themes/osx/tabbrowser/tab-active-middle-yosemite-inactive@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-active-middle.png b/browser/themes/osx/tabbrowser/tab-active-middle.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-active-middle.png rename to browser/themes/osx/tabbrowser/tab-active-middle.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-active-middle@2x.png b/browser/themes/osx/tabbrowser/tab-active-middle@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-active-middle@2x.png rename to browser/themes/osx/tabbrowser/tab-active-middle@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-arrow-left-inverted.png b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-arrow-left-inverted.png rename to browser/themes/osx/tabbrowser/tab-arrow-left-inverted.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png rename to browser/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-arrow-left.png b/browser/themes/osx/tabbrowser/tab-arrow-left.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-arrow-left.png rename to browser/themes/osx/tabbrowser/tab-arrow-left.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-arrow-left@2x.png b/browser/themes/osx/tabbrowser/tab-arrow-left@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-arrow-left@2x.png rename to browser/themes/osx/tabbrowser/tab-arrow-left@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-arrow-right-inverted.png b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-arrow-right-inverted.png rename to browser/themes/osx/tabbrowser/tab-arrow-right-inverted.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png rename to browser/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-arrow-right.png b/browser/themes/osx/tabbrowser/tab-arrow-right.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-arrow-right.png rename to browser/themes/osx/tabbrowser/tab-arrow-right.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-arrow-right@2x.png b/browser/themes/osx/tabbrowser/tab-arrow-right@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-arrow-right@2x.png rename to browser/themes/osx/tabbrowser/tab-arrow-right@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-background-end.png b/browser/themes/osx/tabbrowser/tab-background-end.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-background-end.png rename to browser/themes/osx/tabbrowser/tab-background-end.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-background-end@2x.png b/browser/themes/osx/tabbrowser/tab-background-end@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-background-end@2x.png rename to browser/themes/osx/tabbrowser/tab-background-end@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-background-middle.png b/browser/themes/osx/tabbrowser/tab-background-middle.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-background-middle.png rename to browser/themes/osx/tabbrowser/tab-background-middle.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-background-middle@2x.png b/browser/themes/osx/tabbrowser/tab-background-middle@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-background-middle@2x.png rename to browser/themes/osx/tabbrowser/tab-background-middle@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-background-start.png b/browser/themes/osx/tabbrowser/tab-background-start.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-background-start.png rename to browser/themes/osx/tabbrowser/tab-background-start.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-background-start@2x.png b/browser/themes/osx/tabbrowser/tab-background-start@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-background-start@2x.png rename to browser/themes/osx/tabbrowser/tab-background-start@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-selected-end-yosemite-inactive.svg b/browser/themes/osx/tabbrowser/tab-selected-end-yosemite-inactive.svg similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-selected-end-yosemite-inactive.svg rename to browser/themes/osx/tabbrowser/tab-selected-end-yosemite-inactive.svg diff --git a/application/basilisk/themes/osx/tabbrowser/tab-selected-start-yosemite-inactive.svg b/browser/themes/osx/tabbrowser/tab-selected-start-yosemite-inactive.svg similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-selected-start-yosemite-inactive.svg rename to browser/themes/osx/tabbrowser/tab-selected-start-yosemite-inactive.svg diff --git a/application/basilisk/themes/osx/tabbrowser/tab-stroke-end-yosemite-inactive.png b/browser/themes/osx/tabbrowser/tab-stroke-end-yosemite-inactive.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-stroke-end-yosemite-inactive.png rename to browser/themes/osx/tabbrowser/tab-stroke-end-yosemite-inactive.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-stroke-end-yosemite-inactive@2x.png b/browser/themes/osx/tabbrowser/tab-stroke-end-yosemite-inactive@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-stroke-end-yosemite-inactive@2x.png rename to browser/themes/osx/tabbrowser/tab-stroke-end-yosemite-inactive@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-stroke-end.png b/browser/themes/osx/tabbrowser/tab-stroke-end.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-stroke-end.png rename to browser/themes/osx/tabbrowser/tab-stroke-end.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-stroke-end@2x.png b/browser/themes/osx/tabbrowser/tab-stroke-end@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-stroke-end@2x.png rename to browser/themes/osx/tabbrowser/tab-stroke-end@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-stroke-start-yosemite-inactive.png b/browser/themes/osx/tabbrowser/tab-stroke-start-yosemite-inactive.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-stroke-start-yosemite-inactive.png rename to browser/themes/osx/tabbrowser/tab-stroke-start-yosemite-inactive.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-stroke-start-yosemite-inactive@2x.png b/browser/themes/osx/tabbrowser/tab-stroke-start-yosemite-inactive@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-stroke-start-yosemite-inactive@2x.png rename to browser/themes/osx/tabbrowser/tab-stroke-start-yosemite-inactive@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-stroke-start.png b/browser/themes/osx/tabbrowser/tab-stroke-start.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-stroke-start.png rename to browser/themes/osx/tabbrowser/tab-stroke-start.png diff --git a/application/basilisk/themes/osx/tabbrowser/tab-stroke-start@2x.png b/browser/themes/osx/tabbrowser/tab-stroke-start@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tab-stroke-start@2x.png rename to browser/themes/osx/tabbrowser/tab-stroke-start@2x.png diff --git a/application/basilisk/themes/osx/tabbrowser/tabDragIndicator.png b/browser/themes/osx/tabbrowser/tabDragIndicator.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tabDragIndicator.png rename to browser/themes/osx/tabbrowser/tabDragIndicator.png diff --git a/application/basilisk/themes/osx/tabbrowser/tabDragIndicator@2x.png b/browser/themes/osx/tabbrowser/tabDragIndicator@2x.png similarity index 100% rename from application/basilisk/themes/osx/tabbrowser/tabDragIndicator@2x.png rename to browser/themes/osx/tabbrowser/tabDragIndicator@2x.png diff --git a/application/basilisk/themes/osx/toolbarbutton-dropmarker-lion.png b/browser/themes/osx/toolbarbutton-dropmarker-lion.png similarity index 100% rename from application/basilisk/themes/osx/toolbarbutton-dropmarker-lion.png rename to browser/themes/osx/toolbarbutton-dropmarker-lion.png diff --git a/application/basilisk/themes/osx/toolbarbutton-dropmarker-lion@2x.png b/browser/themes/osx/toolbarbutton-dropmarker-lion@2x.png similarity index 100% rename from application/basilisk/themes/osx/toolbarbutton-dropmarker-lion@2x.png rename to browser/themes/osx/toolbarbutton-dropmarker-lion@2x.png diff --git a/application/basilisk/themes/osx/toolbarbutton-dropmarker.png b/browser/themes/osx/toolbarbutton-dropmarker.png similarity index 100% rename from application/basilisk/themes/osx/toolbarbutton-dropmarker.png rename to browser/themes/osx/toolbarbutton-dropmarker.png diff --git a/application/basilisk/themes/osx/urlbar-history-dropmarker.png b/browser/themes/osx/urlbar-history-dropmarker.png similarity index 100% rename from application/basilisk/themes/osx/urlbar-history-dropmarker.png rename to browser/themes/osx/urlbar-history-dropmarker.png diff --git a/application/basilisk/themes/osx/urlbar-history-dropmarker@2x.png b/browser/themes/osx/urlbar-history-dropmarker@2x.png similarity index 100% rename from application/basilisk/themes/osx/urlbar-history-dropmarker@2x.png rename to browser/themes/osx/urlbar-history-dropmarker@2x.png diff --git a/application/basilisk/themes/osx/urlbar-popup-blocked.png b/browser/themes/osx/urlbar-popup-blocked.png similarity index 100% rename from application/basilisk/themes/osx/urlbar-popup-blocked.png rename to browser/themes/osx/urlbar-popup-blocked.png diff --git a/application/basilisk/themes/osx/urlbar-popup-blocked@2x.png b/browser/themes/osx/urlbar-popup-blocked@2x.png similarity index 100% rename from application/basilisk/themes/osx/urlbar-popup-blocked@2x.png rename to browser/themes/osx/urlbar-popup-blocked@2x.png diff --git a/application/basilisk/themes/osx/webRTC-indicator.css b/browser/themes/osx/webRTC-indicator.css similarity index 100% rename from application/basilisk/themes/osx/webRTC-indicator.css rename to browser/themes/osx/webRTC-indicator.css diff --git a/application/basilisk/themes/osx/webRTC-sharingDevice-menubar.png b/browser/themes/osx/webRTC-sharingDevice-menubar.png similarity index 100% rename from application/basilisk/themes/osx/webRTC-sharingDevice-menubar.png rename to browser/themes/osx/webRTC-sharingDevice-menubar.png diff --git a/application/basilisk/themes/osx/webRTC-sharingDevice-menubar@2x.png b/browser/themes/osx/webRTC-sharingDevice-menubar@2x.png similarity index 100% rename from application/basilisk/themes/osx/webRTC-sharingDevice-menubar@2x.png rename to browser/themes/osx/webRTC-sharingDevice-menubar@2x.png diff --git a/application/basilisk/themes/osx/webRTC-sharingMicrophone-menubar.png b/browser/themes/osx/webRTC-sharingMicrophone-menubar.png similarity index 100% rename from application/basilisk/themes/osx/webRTC-sharingMicrophone-menubar.png rename to browser/themes/osx/webRTC-sharingMicrophone-menubar.png diff --git a/application/basilisk/themes/osx/webRTC-sharingMicrophone-menubar@2x.png b/browser/themes/osx/webRTC-sharingMicrophone-menubar@2x.png similarity index 100% rename from application/basilisk/themes/osx/webRTC-sharingMicrophone-menubar@2x.png rename to browser/themes/osx/webRTC-sharingMicrophone-menubar@2x.png diff --git a/application/basilisk/themes/osx/webRTC-sharingScreen-menubar.png b/browser/themes/osx/webRTC-sharingScreen-menubar.png similarity index 100% rename from application/basilisk/themes/osx/webRTC-sharingScreen-menubar.png rename to browser/themes/osx/webRTC-sharingScreen-menubar.png diff --git a/application/basilisk/themes/osx/webRTC-sharingScreen-menubar@2x.png b/browser/themes/osx/webRTC-sharingScreen-menubar@2x.png similarity index 100% rename from application/basilisk/themes/osx/webRTC-sharingScreen-menubar@2x.png rename to browser/themes/osx/webRTC-sharingScreen-menubar@2x.png diff --git a/application/basilisk/themes/preprocess-tab-svgs.py b/browser/themes/preprocess-tab-svgs.py similarity index 100% rename from application/basilisk/themes/preprocess-tab-svgs.py rename to browser/themes/preprocess-tab-svgs.py diff --git a/application/basilisk/themes/shared/aboutNetError.css b/browser/themes/shared/aboutNetError.css similarity index 100% rename from application/basilisk/themes/shared/aboutNetError.css rename to browser/themes/shared/aboutNetError.css diff --git a/application/basilisk/themes/shared/aboutSessionRestore.css b/browser/themes/shared/aboutSessionRestore.css similarity index 100% rename from application/basilisk/themes/shared/aboutSessionRestore.css rename to browser/themes/shared/aboutSessionRestore.css diff --git a/application/basilisk/themes/shared/aboutSocialError.css b/browser/themes/shared/aboutSocialError.css similarity index 100% rename from application/basilisk/themes/shared/aboutSocialError.css rename to browser/themes/shared/aboutSocialError.css diff --git a/application/basilisk/themes/shared/aboutTabCrashed.css b/browser/themes/shared/aboutTabCrashed.css similarity index 100% rename from application/basilisk/themes/shared/aboutTabCrashed.css rename to browser/themes/shared/aboutTabCrashed.css diff --git a/application/basilisk/themes/shared/aboutWelcomeBack.css b/browser/themes/shared/aboutWelcomeBack.css similarity index 100% rename from application/basilisk/themes/shared/aboutWelcomeBack.css rename to browser/themes/shared/aboutWelcomeBack.css diff --git a/application/basilisk/themes/shared/addons/addon-install-anchor.svg b/browser/themes/shared/addons/addon-install-anchor.svg similarity index 100% rename from application/basilisk/themes/shared/addons/addon-install-anchor.svg rename to browser/themes/shared/addons/addon-install-anchor.svg diff --git a/application/basilisk/themes/shared/addons/addon-install-blocked.svg b/browser/themes/shared/addons/addon-install-blocked.svg similarity index 100% rename from application/basilisk/themes/shared/addons/addon-install-blocked.svg rename to browser/themes/shared/addons/addon-install-blocked.svg diff --git a/application/basilisk/themes/shared/addons/addon-install-confirm.svg b/browser/themes/shared/addons/addon-install-confirm.svg similarity index 100% rename from application/basilisk/themes/shared/addons/addon-install-confirm.svg rename to browser/themes/shared/addons/addon-install-confirm.svg diff --git a/application/basilisk/themes/shared/addons/addon-install-downloading.svg b/browser/themes/shared/addons/addon-install-downloading.svg similarity index 100% rename from application/basilisk/themes/shared/addons/addon-install-downloading.svg rename to browser/themes/shared/addons/addon-install-downloading.svg diff --git a/application/basilisk/themes/shared/addons/addon-install-error.svg b/browser/themes/shared/addons/addon-install-error.svg similarity index 100% rename from application/basilisk/themes/shared/addons/addon-install-error.svg rename to browser/themes/shared/addons/addon-install-error.svg diff --git a/application/basilisk/themes/shared/addons/addon-install-installed.svg b/browser/themes/shared/addons/addon-install-installed.svg similarity index 100% rename from application/basilisk/themes/shared/addons/addon-install-installed.svg rename to browser/themes/shared/addons/addon-install-installed.svg diff --git a/application/basilisk/themes/shared/addons/addon-install-restart.svg b/browser/themes/shared/addons/addon-install-restart.svg similarity index 100% rename from application/basilisk/themes/shared/addons/addon-install-restart.svg rename to browser/themes/shared/addons/addon-install-restart.svg diff --git a/application/basilisk/themes/shared/addons/addon-install-warning.svg b/browser/themes/shared/addons/addon-install-warning.svg similarity index 100% rename from application/basilisk/themes/shared/addons/addon-install-warning.svg rename to browser/themes/shared/addons/addon-install-warning.svg diff --git a/application/basilisk/themes/shared/autocomplete.inc.css b/browser/themes/shared/autocomplete.inc.css similarity index 100% rename from application/basilisk/themes/shared/autocomplete.inc.css rename to browser/themes/shared/autocomplete.inc.css diff --git a/application/basilisk/themes/shared/blockedSite.css b/browser/themes/shared/blockedSite.css similarity index 100% rename from application/basilisk/themes/shared/blockedSite.css rename to browser/themes/shared/blockedSite.css diff --git a/application/basilisk/themes/shared/browser.inc b/browser/themes/shared/browser.inc similarity index 100% rename from application/basilisk/themes/shared/browser.inc rename to browser/themes/shared/browser.inc diff --git a/application/basilisk/themes/shared/content-contextmenu.svg b/browser/themes/shared/content-contextmenu.svg similarity index 100% rename from application/basilisk/themes/shared/content-contextmenu.svg rename to browser/themes/shared/content-contextmenu.svg diff --git a/application/basilisk/themes/shared/contextmenu.inc.css b/browser/themes/shared/contextmenu.inc.css similarity index 100% rename from application/basilisk/themes/shared/contextmenu.inc.css rename to browser/themes/shared/contextmenu.inc.css diff --git a/application/basilisk/themes/shared/controlcenter/arrow-subview-back.svg b/browser/themes/shared/controlcenter/arrow-subview-back.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/arrow-subview-back.svg rename to browser/themes/shared/controlcenter/arrow-subview-back.svg diff --git a/application/basilisk/themes/shared/controlcenter/arrow-subview.svg b/browser/themes/shared/controlcenter/arrow-subview.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/arrow-subview.svg rename to browser/themes/shared/controlcenter/arrow-subview.svg diff --git a/application/basilisk/themes/shared/controlcenter/conn-not-secure.svg b/browser/themes/shared/controlcenter/conn-not-secure.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/conn-not-secure.svg rename to browser/themes/shared/controlcenter/conn-not-secure.svg diff --git a/application/basilisk/themes/shared/controlcenter/connection.svg b/browser/themes/shared/controlcenter/connection.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/connection.svg rename to browser/themes/shared/controlcenter/connection.svg diff --git a/application/basilisk/themes/shared/controlcenter/mcb-disabled.svg b/browser/themes/shared/controlcenter/mcb-disabled.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/mcb-disabled.svg rename to browser/themes/shared/controlcenter/mcb-disabled.svg diff --git a/application/basilisk/themes/shared/controlcenter/panel.inc.css b/browser/themes/shared/controlcenter/panel.inc.css similarity index 100% rename from application/basilisk/themes/shared/controlcenter/panel.inc.css rename to browser/themes/shared/controlcenter/panel.inc.css diff --git a/application/basilisk/themes/shared/controlcenter/permissions.svg b/browser/themes/shared/controlcenter/permissions.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/permissions.svg rename to browser/themes/shared/controlcenter/permissions.svg diff --git a/application/basilisk/themes/shared/controlcenter/tracking-protection.svg b/browser/themes/shared/controlcenter/tracking-protection.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/tracking-protection.svg rename to browser/themes/shared/controlcenter/tracking-protection.svg diff --git a/application/basilisk/themes/shared/controlcenter/warning-gray.svg b/browser/themes/shared/controlcenter/warning-gray.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/warning-gray.svg rename to browser/themes/shared/controlcenter/warning-gray.svg diff --git a/application/basilisk/themes/shared/controlcenter/warning-yellow.svg b/browser/themes/shared/controlcenter/warning-yellow.svg similarity index 100% rename from application/basilisk/themes/shared/controlcenter/warning-yellow.svg rename to browser/themes/shared/controlcenter/warning-yellow.svg diff --git a/application/basilisk/themes/shared/ctrlTab.inc.css b/browser/themes/shared/ctrlTab.inc.css similarity index 100% rename from application/basilisk/themes/shared/ctrlTab.inc.css rename to browser/themes/shared/ctrlTab.inc.css diff --git a/application/basilisk/themes/shared/customizableui/customize-illustration-rtl.png b/browser/themes/shared/customizableui/customize-illustration-rtl.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/customize-illustration-rtl.png rename to browser/themes/shared/customizableui/customize-illustration-rtl.png diff --git a/application/basilisk/themes/shared/customizableui/customize-illustration-rtl@2x.png b/browser/themes/shared/customizableui/customize-illustration-rtl@2x.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/customize-illustration-rtl@2x.png rename to browser/themes/shared/customizableui/customize-illustration-rtl@2x.png diff --git a/application/basilisk/themes/shared/customizableui/customize-illustration.png b/browser/themes/shared/customizableui/customize-illustration.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/customize-illustration.png rename to browser/themes/shared/customizableui/customize-illustration.png diff --git a/application/basilisk/themes/shared/customizableui/customize-illustration@2x.png b/browser/themes/shared/customizableui/customize-illustration@2x.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/customize-illustration@2x.png rename to browser/themes/shared/customizableui/customize-illustration@2x.png diff --git a/application/basilisk/themes/shared/customizableui/customizeFavicon.ico b/browser/themes/shared/customizableui/customizeFavicon.ico similarity index 100% rename from application/basilisk/themes/shared/customizableui/customizeFavicon.ico rename to browser/themes/shared/customizableui/customizeFavicon.ico diff --git a/application/basilisk/themes/shared/customizableui/customizeMode.inc.css b/browser/themes/shared/customizableui/customizeMode.inc.css similarity index 100% rename from application/basilisk/themes/shared/customizableui/customizeMode.inc.css rename to browser/themes/shared/customizableui/customizeMode.inc.css diff --git a/application/basilisk/themes/shared/customizableui/info-icon-customizeTip.png b/browser/themes/shared/customizableui/info-icon-customizeTip.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/info-icon-customizeTip.png rename to browser/themes/shared/customizableui/info-icon-customizeTip.png diff --git a/application/basilisk/themes/shared/customizableui/info-icon-customizeTip@2x.png b/browser/themes/shared/customizableui/info-icon-customizeTip@2x.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/info-icon-customizeTip@2x.png rename to browser/themes/shared/customizableui/info-icon-customizeTip@2x.png diff --git a/application/basilisk/themes/shared/customizableui/menuPanel-customizeFinish.png b/browser/themes/shared/customizableui/menuPanel-customizeFinish.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/menuPanel-customizeFinish.png rename to browser/themes/shared/customizableui/menuPanel-customizeFinish.png diff --git a/application/basilisk/themes/shared/customizableui/menuPanel-customizeFinish@2x.png b/browser/themes/shared/customizableui/menuPanel-customizeFinish@2x.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/menuPanel-customizeFinish@2x.png rename to browser/themes/shared/customizableui/menuPanel-customizeFinish@2x.png diff --git a/application/basilisk/themes/shared/customizableui/panelUI.inc.css b/browser/themes/shared/customizableui/panelUI.inc.css similarity index 100% rename from application/basilisk/themes/shared/customizableui/panelUI.inc.css rename to browser/themes/shared/customizableui/panelUI.inc.css diff --git a/application/basilisk/themes/shared/customizableui/panelarrow-customizeTip.png b/browser/themes/shared/customizableui/panelarrow-customizeTip.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/panelarrow-customizeTip.png rename to browser/themes/shared/customizableui/panelarrow-customizeTip.png diff --git a/application/basilisk/themes/shared/customizableui/panelarrow-customizeTip@2x.png b/browser/themes/shared/customizableui/panelarrow-customizeTip@2x.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/panelarrow-customizeTip@2x.png rename to browser/themes/shared/customizableui/panelarrow-customizeTip@2x.png diff --git a/application/basilisk/themes/shared/customizableui/subView-arrow-back-inverted-rtl.png b/browser/themes/shared/customizableui/subView-arrow-back-inverted-rtl.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/subView-arrow-back-inverted-rtl.png rename to browser/themes/shared/customizableui/subView-arrow-back-inverted-rtl.png diff --git a/application/basilisk/themes/shared/customizableui/subView-arrow-back-inverted-rtl@2x.png b/browser/themes/shared/customizableui/subView-arrow-back-inverted-rtl@2x.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/subView-arrow-back-inverted-rtl@2x.png rename to browser/themes/shared/customizableui/subView-arrow-back-inverted-rtl@2x.png diff --git a/application/basilisk/themes/shared/customizableui/subView-arrow-back-inverted.png b/browser/themes/shared/customizableui/subView-arrow-back-inverted.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/subView-arrow-back-inverted.png rename to browser/themes/shared/customizableui/subView-arrow-back-inverted.png diff --git a/application/basilisk/themes/shared/customizableui/subView-arrow-back-inverted@2x.png b/browser/themes/shared/customizableui/subView-arrow-back-inverted@2x.png similarity index 100% rename from application/basilisk/themes/shared/customizableui/subView-arrow-back-inverted@2x.png rename to browser/themes/shared/customizableui/subView-arrow-back-inverted@2x.png diff --git a/application/basilisk/themes/shared/devedition.inc.css b/browser/themes/shared/devedition.inc.css similarity index 100% rename from application/basilisk/themes/shared/devedition.inc.css rename to browser/themes/shared/devedition.inc.css diff --git a/application/basilisk/themes/shared/devedition/urlbar-history-dropmarker.svg b/browser/themes/shared/devedition/urlbar-history-dropmarker.svg similarity index 100% rename from application/basilisk/themes/shared/devedition/urlbar-history-dropmarker.svg rename to browser/themes/shared/devedition/urlbar-history-dropmarker.svg diff --git a/application/basilisk/themes/shared/downloads/allDownloadsViewOverlay.inc.css b/browser/themes/shared/downloads/allDownloadsViewOverlay.inc.css similarity index 100% rename from application/basilisk/themes/shared/downloads/allDownloadsViewOverlay.inc.css rename to browser/themes/shared/downloads/allDownloadsViewOverlay.inc.css diff --git a/application/basilisk/themes/shared/downloads/contentAreaDownloadsView.css b/browser/themes/shared/downloads/contentAreaDownloadsView.css similarity index 100% rename from application/basilisk/themes/shared/downloads/contentAreaDownloadsView.css rename to browser/themes/shared/downloads/contentAreaDownloadsView.css diff --git a/application/basilisk/themes/shared/downloads/download-blocked.svg b/browser/themes/shared/downloads/download-blocked.svg similarity index 100% rename from application/basilisk/themes/shared/downloads/download-blocked.svg rename to browser/themes/shared/downloads/download-blocked.svg diff --git a/application/basilisk/themes/shared/downloads/download-summary.svg b/browser/themes/shared/downloads/download-summary.svg similarity index 100% rename from application/basilisk/themes/shared/downloads/download-summary.svg rename to browser/themes/shared/downloads/download-summary.svg diff --git a/application/basilisk/themes/shared/downloads/downloads.inc.css b/browser/themes/shared/downloads/downloads.inc.css similarity index 100% rename from application/basilisk/themes/shared/downloads/downloads.inc.css rename to browser/themes/shared/downloads/downloads.inc.css diff --git a/application/basilisk/themes/shared/downloads/menubutton-dropmarker.svg b/browser/themes/shared/downloads/menubutton-dropmarker.svg similarity index 100% rename from application/basilisk/themes/shared/downloads/menubutton-dropmarker.svg rename to browser/themes/shared/downloads/menubutton-dropmarker.svg diff --git a/application/basilisk/themes/shared/downloads/progressmeter.inc.css b/browser/themes/shared/downloads/progressmeter.inc.css similarity index 100% rename from application/basilisk/themes/shared/downloads/progressmeter.inc.css rename to browser/themes/shared/downloads/progressmeter.inc.css diff --git a/application/basilisk/themes/shared/drm-icon.svg b/browser/themes/shared/drm-icon.svg similarity index 100% rename from application/basilisk/themes/shared/drm-icon.svg rename to browser/themes/shared/drm-icon.svg diff --git a/application/basilisk/themes/shared/e10s-64@2x.png b/browser/themes/shared/e10s-64@2x.png similarity index 100% rename from application/basilisk/themes/shared/e10s-64@2x.png rename to browser/themes/shared/e10s-64@2x.png diff --git a/application/basilisk/themes/shared/error-pages.css b/browser/themes/shared/error-pages.css similarity index 100% rename from application/basilisk/themes/shared/error-pages.css rename to browser/themes/shared/error-pages.css diff --git a/application/basilisk/themes/shared/favicon-search-16.svg b/browser/themes/shared/favicon-search-16.svg similarity index 100% rename from application/basilisk/themes/shared/favicon-search-16.svg rename to browser/themes/shared/favicon-search-16.svg diff --git a/application/basilisk/themes/shared/filters.svg b/browser/themes/shared/filters.svg similarity index 100% rename from application/basilisk/themes/shared/filters.svg rename to browser/themes/shared/filters.svg diff --git a/application/basilisk/themes/shared/fullscreen/insecure.svg b/browser/themes/shared/fullscreen/insecure.svg similarity index 100% rename from application/basilisk/themes/shared/fullscreen/insecure.svg rename to browser/themes/shared/fullscreen/insecure.svg diff --git a/application/basilisk/themes/shared/fullscreen/secure.svg b/browser/themes/shared/fullscreen/secure.svg similarity index 100% rename from application/basilisk/themes/shared/fullscreen/secure.svg rename to browser/themes/shared/fullscreen/secure.svg diff --git a/application/basilisk/themes/shared/fullscreen/warning.inc.css b/browser/themes/shared/fullscreen/warning.inc.css similarity index 100% rename from application/basilisk/themes/shared/fullscreen/warning.inc.css rename to browser/themes/shared/fullscreen/warning.inc.css diff --git a/application/basilisk/themes/shared/fxa/default-avatar.svg b/browser/themes/shared/fxa/default-avatar.svg similarity index 100% rename from application/basilisk/themes/shared/fxa/default-avatar.svg rename to browser/themes/shared/fxa/default-avatar.svg diff --git a/application/basilisk/themes/shared/fxa/logo.png b/browser/themes/shared/fxa/logo.png similarity index 100% rename from application/basilisk/themes/shared/fxa/logo.png rename to browser/themes/shared/fxa/logo.png diff --git a/application/basilisk/themes/shared/fxa/logo@2x.png b/browser/themes/shared/fxa/logo@2x.png similarity index 100% rename from application/basilisk/themes/shared/fxa/logo@2x.png rename to browser/themes/shared/fxa/logo@2x.png diff --git a/application/basilisk/themes/shared/fxa/sync-illustration.png b/browser/themes/shared/fxa/sync-illustration.png similarity index 100% rename from application/basilisk/themes/shared/fxa/sync-illustration.png rename to browser/themes/shared/fxa/sync-illustration.png diff --git a/application/basilisk/themes/shared/fxa/sync-illustration.svg b/browser/themes/shared/fxa/sync-illustration.svg similarity index 100% rename from application/basilisk/themes/shared/fxa/sync-illustration.svg rename to browser/themes/shared/fxa/sync-illustration.svg diff --git a/application/basilisk/themes/shared/fxa/sync-illustration@2x.png b/browser/themes/shared/fxa/sync-illustration@2x.png similarity index 100% rename from application/basilisk/themes/shared/fxa/sync-illustration@2x.png rename to browser/themes/shared/fxa/sync-illustration@2x.png diff --git a/application/basilisk/themes/shared/heartbeat-icon.svg b/browser/themes/shared/heartbeat-icon.svg similarity index 100% rename from application/basilisk/themes/shared/heartbeat-icon.svg rename to browser/themes/shared/heartbeat-icon.svg diff --git a/application/basilisk/themes/shared/heartbeat-star-lit.svg b/browser/themes/shared/heartbeat-star-lit.svg similarity index 100% rename from application/basilisk/themes/shared/heartbeat-star-lit.svg rename to browser/themes/shared/heartbeat-star-lit.svg diff --git a/application/basilisk/themes/shared/heartbeat-star-off.svg b/browser/themes/shared/heartbeat-star-off.svg similarity index 100% rename from application/basilisk/themes/shared/heartbeat-star-off.svg rename to browser/themes/shared/heartbeat-star-off.svg diff --git a/application/basilisk/themes/shared/icon-colors.inc.svg b/browser/themes/shared/icon-colors.inc.svg similarity index 100% rename from application/basilisk/themes/shared/icon-colors.inc.svg rename to browser/themes/shared/icon-colors.inc.svg diff --git a/application/basilisk/themes/shared/icon.png b/browser/themes/shared/icon.png similarity index 100% rename from application/basilisk/themes/shared/icon.png rename to browser/themes/shared/icon.png diff --git a/application/basilisk/themes/shared/identity-block/connection-mixed-active-loaded.svg b/browser/themes/shared/identity-block/connection-mixed-active-loaded.svg similarity index 100% rename from application/basilisk/themes/shared/identity-block/connection-mixed-active-loaded.svg rename to browser/themes/shared/identity-block/connection-mixed-active-loaded.svg diff --git a/application/basilisk/themes/shared/identity-block/connection-mixed-passive-loaded.svg b/browser/themes/shared/identity-block/connection-mixed-passive-loaded.svg similarity index 100% rename from application/basilisk/themes/shared/identity-block/connection-mixed-passive-loaded.svg rename to browser/themes/shared/identity-block/connection-mixed-passive-loaded.svg diff --git a/application/basilisk/themes/shared/identity-block/connection-secure.svg b/browser/themes/shared/identity-block/connection-secure.svg similarity index 100% rename from application/basilisk/themes/shared/identity-block/connection-secure.svg rename to browser/themes/shared/identity-block/connection-secure.svg diff --git a/application/basilisk/themes/shared/identity-block/icons.inc.css b/browser/themes/shared/identity-block/icons.inc.css similarity index 100% rename from application/basilisk/themes/shared/identity-block/icons.inc.css rename to browser/themes/shared/identity-block/icons.inc.css diff --git a/application/basilisk/themes/shared/identity-block/identity-block.inc.css b/browser/themes/shared/identity-block/identity-block.inc.css similarity index 100% rename from application/basilisk/themes/shared/identity-block/identity-block.inc.css rename to browser/themes/shared/identity-block/identity-block.inc.css diff --git a/application/basilisk/themes/shared/identity-block/identity-icon.svg b/browser/themes/shared/identity-block/identity-icon.svg similarity index 100% rename from application/basilisk/themes/shared/identity-block/identity-icon.svg rename to browser/themes/shared/identity-block/identity-icon.svg diff --git a/application/basilisk/themes/shared/identity-block/tracking-protection-16.svg b/browser/themes/shared/identity-block/tracking-protection-16.svg similarity index 100% rename from application/basilisk/themes/shared/identity-block/tracking-protection-16.svg rename to browser/themes/shared/identity-block/tracking-protection-16.svg diff --git a/application/basilisk/themes/shared/incontent-icons/cert-error.svg b/browser/themes/shared/incontent-icons/cert-error.svg similarity index 100% rename from application/basilisk/themes/shared/incontent-icons/cert-error.svg rename to browser/themes/shared/incontent-icons/cert-error.svg diff --git a/application/basilisk/themes/shared/incontent-icons/icon-search-64.svg b/browser/themes/shared/incontent-icons/icon-search-64.svg similarity index 100% rename from application/basilisk/themes/shared/incontent-icons/icon-search-64.svg rename to browser/themes/shared/incontent-icons/icon-search-64.svg diff --git a/application/basilisk/themes/shared/incontent-icons/session-restore.svg b/browser/themes/shared/incontent-icons/session-restore.svg similarity index 100% rename from application/basilisk/themes/shared/incontent-icons/session-restore.svg rename to browser/themes/shared/incontent-icons/session-restore.svg diff --git a/application/basilisk/themes/shared/incontent-icons/tab-crashed.svg b/browser/themes/shared/incontent-icons/tab-crashed.svg similarity index 100% rename from application/basilisk/themes/shared/incontent-icons/tab-crashed.svg rename to browser/themes/shared/incontent-icons/tab-crashed.svg diff --git a/application/basilisk/themes/shared/incontent-icons/welcome-back.svg b/browser/themes/shared/incontent-icons/welcome-back.svg similarity index 100% rename from application/basilisk/themes/shared/incontent-icons/welcome-back.svg rename to browser/themes/shared/incontent-icons/welcome-back.svg diff --git a/application/basilisk/themes/shared/incontent-icons/wifi.svg b/browser/themes/shared/incontent-icons/wifi.svg similarity index 100% rename from application/basilisk/themes/shared/incontent-icons/wifi.svg rename to browser/themes/shared/incontent-icons/wifi.svg diff --git a/application/basilisk/themes/shared/incontentprefs/containers.css b/browser/themes/shared/incontentprefs/containers.css similarity index 100% rename from application/basilisk/themes/shared/incontentprefs/containers.css rename to browser/themes/shared/incontentprefs/containers.css diff --git a/application/basilisk/themes/shared/incontentprefs/dialog.inc.css b/browser/themes/shared/incontentprefs/dialog.inc.css similarity index 100% rename from application/basilisk/themes/shared/incontentprefs/dialog.inc.css rename to browser/themes/shared/incontentprefs/dialog.inc.css diff --git a/application/basilisk/themes/shared/incontentprefs/favicon.ico b/browser/themes/shared/incontentprefs/favicon.ico similarity index 100% rename from application/basilisk/themes/shared/incontentprefs/favicon.ico rename to browser/themes/shared/incontentprefs/favicon.ico diff --git a/application/basilisk/themes/shared/incontentprefs/icons.svg b/browser/themes/shared/incontentprefs/icons.svg similarity index 100% rename from application/basilisk/themes/shared/incontentprefs/icons.svg rename to browser/themes/shared/incontentprefs/icons.svg diff --git a/application/basilisk/themes/shared/incontentprefs/preferences.inc.css b/browser/themes/shared/incontentprefs/preferences.inc.css similarity index 100% rename from application/basilisk/themes/shared/incontentprefs/preferences.inc.css rename to browser/themes/shared/incontentprefs/preferences.inc.css diff --git a/application/basilisk/themes/shared/incontentprefs/search.css b/browser/themes/shared/incontentprefs/search.css similarity index 100% rename from application/basilisk/themes/shared/incontentprefs/search.css rename to browser/themes/shared/incontentprefs/search.css diff --git a/application/basilisk/themes/shared/info.svg b/browser/themes/shared/info.svg similarity index 100% rename from application/basilisk/themes/shared/info.svg rename to browser/themes/shared/info.svg diff --git a/application/basilisk/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn similarity index 100% rename from application/basilisk/themes/shared/jar.inc.mn rename to browser/themes/shared/jar.inc.mn diff --git a/application/basilisk/themes/shared/menuPanel-small.svg b/browser/themes/shared/menuPanel-small.svg similarity index 100% rename from application/basilisk/themes/shared/menuPanel-small.svg rename to browser/themes/shared/menuPanel-small.svg diff --git a/application/basilisk/themes/shared/menuPanel.svg b/browser/themes/shared/menuPanel.svg similarity index 100% rename from application/basilisk/themes/shared/menuPanel.svg rename to browser/themes/shared/menuPanel.svg diff --git a/application/basilisk/themes/shared/menupanel.inc.css b/browser/themes/shared/menupanel.inc.css similarity index 100% rename from application/basilisk/themes/shared/menupanel.inc.css rename to browser/themes/shared/menupanel.inc.css diff --git a/application/basilisk/themes/shared/newtab/close.png b/browser/themes/shared/newtab/close.png similarity index 100% rename from application/basilisk/themes/shared/newtab/close.png rename to browser/themes/shared/newtab/close.png diff --git a/application/basilisk/themes/shared/newtab/controls.svg b/browser/themes/shared/newtab/controls.svg similarity index 100% rename from application/basilisk/themes/shared/newtab/controls.svg rename to browser/themes/shared/newtab/controls.svg diff --git a/application/basilisk/themes/shared/newtab/newTab.inc.css b/browser/themes/shared/newtab/newTab.inc.css similarity index 100% rename from application/basilisk/themes/shared/newtab/newTab.inc.css rename to browser/themes/shared/newtab/newTab.inc.css diff --git a/application/basilisk/themes/shared/newtab/whimsycorn.png b/browser/themes/shared/newtab/whimsycorn.png similarity index 100% rename from application/basilisk/themes/shared/newtab/whimsycorn.png rename to browser/themes/shared/newtab/whimsycorn.png diff --git a/application/basilisk/themes/shared/notification-icons.inc.css b/browser/themes/shared/notification-icons.inc.css similarity index 100% rename from application/basilisk/themes/shared/notification-icons.inc.css rename to browser/themes/shared/notification-icons.inc.css diff --git a/application/basilisk/themes/shared/notification-icons.svg b/browser/themes/shared/notification-icons.svg similarity index 100% rename from application/basilisk/themes/shared/notification-icons.svg rename to browser/themes/shared/notification-icons.svg diff --git a/application/basilisk/themes/shared/panel-icons.svg b/browser/themes/shared/panel-icons.svg similarity index 100% rename from application/basilisk/themes/shared/panel-icons.svg rename to browser/themes/shared/panel-icons.svg diff --git a/application/basilisk/themes/shared/panic-panel/header-small.png b/browser/themes/shared/panic-panel/header-small.png similarity index 100% rename from application/basilisk/themes/shared/panic-panel/header-small.png rename to browser/themes/shared/panic-panel/header-small.png diff --git a/application/basilisk/themes/shared/panic-panel/header-small@2x.png b/browser/themes/shared/panic-panel/header-small@2x.png similarity index 100% rename from application/basilisk/themes/shared/panic-panel/header-small@2x.png rename to browser/themes/shared/panic-panel/header-small@2x.png diff --git a/application/basilisk/themes/shared/panic-panel/header.png b/browser/themes/shared/panic-panel/header.png similarity index 100% rename from application/basilisk/themes/shared/panic-panel/header.png rename to browser/themes/shared/panic-panel/header.png diff --git a/application/basilisk/themes/shared/panic-panel/header@2x.png b/browser/themes/shared/panic-panel/header@2x.png similarity index 100% rename from application/basilisk/themes/shared/panic-panel/header@2x.png rename to browser/themes/shared/panic-panel/header@2x.png diff --git a/application/basilisk/themes/shared/panic-panel/icons.png b/browser/themes/shared/panic-panel/icons.png similarity index 100% rename from application/basilisk/themes/shared/panic-panel/icons.png rename to browser/themes/shared/panic-panel/icons.png diff --git a/application/basilisk/themes/shared/panic-panel/icons@2x.png b/browser/themes/shared/panic-panel/icons@2x.png similarity index 100% rename from application/basilisk/themes/shared/panic-panel/icons@2x.png rename to browser/themes/shared/panic-panel/icons@2x.png diff --git a/application/basilisk/themes/shared/plugin-doorhanger.inc.css b/browser/themes/shared/plugin-doorhanger.inc.css similarity index 100% rename from application/basilisk/themes/shared/plugin-doorhanger.inc.css rename to browser/themes/shared/plugin-doorhanger.inc.css diff --git a/application/basilisk/themes/shared/preferences/containers.css b/browser/themes/shared/preferences/containers.css similarity index 100% rename from application/basilisk/themes/shared/preferences/containers.css rename to browser/themes/shared/preferences/containers.css diff --git a/application/basilisk/themes/shared/privatebrowsing/aboutPrivateBrowsing.css b/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/aboutPrivateBrowsing.css rename to browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css diff --git a/application/basilisk/themes/shared/privatebrowsing/attention.png b/browser/themes/shared/privatebrowsing/attention.png similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/attention.png rename to browser/themes/shared/privatebrowsing/attention.png diff --git a/application/basilisk/themes/shared/privatebrowsing/attention@2x.png b/browser/themes/shared/privatebrowsing/attention@2x.png similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/attention@2x.png rename to browser/themes/shared/privatebrowsing/attention@2x.png diff --git a/application/basilisk/themes/shared/privatebrowsing/check.png b/browser/themes/shared/privatebrowsing/check.png similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/check.png rename to browser/themes/shared/privatebrowsing/check.png diff --git a/application/basilisk/themes/shared/privatebrowsing/check.svg b/browser/themes/shared/privatebrowsing/check.svg similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/check.svg rename to browser/themes/shared/privatebrowsing/check.svg diff --git a/application/basilisk/themes/shared/privatebrowsing/check@2x.png b/browser/themes/shared/privatebrowsing/check@2x.png similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/check@2x.png rename to browser/themes/shared/privatebrowsing/check@2x.png diff --git a/application/basilisk/themes/shared/privatebrowsing/favicon.svg b/browser/themes/shared/privatebrowsing/favicon.svg similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/favicon.svg rename to browser/themes/shared/privatebrowsing/favicon.svg diff --git a/application/basilisk/themes/shared/privatebrowsing/private-browsing.svg b/browser/themes/shared/privatebrowsing/private-browsing.svg similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/private-browsing.svg rename to browser/themes/shared/privatebrowsing/private-browsing.svg diff --git a/application/basilisk/themes/shared/privatebrowsing/shield-page.png b/browser/themes/shared/privatebrowsing/shield-page.png similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/shield-page.png rename to browser/themes/shared/privatebrowsing/shield-page.png diff --git a/application/basilisk/themes/shared/privatebrowsing/shield-page@2x.png b/browser/themes/shared/privatebrowsing/shield-page@2x.png similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/shield-page@2x.png rename to browser/themes/shared/privatebrowsing/shield-page@2x.png diff --git a/application/basilisk/themes/shared/privatebrowsing/tracking-protection-off.svg b/browser/themes/shared/privatebrowsing/tracking-protection-off.svg similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/tracking-protection-off.svg rename to browser/themes/shared/privatebrowsing/tracking-protection-off.svg diff --git a/application/basilisk/themes/shared/privatebrowsing/tracking-protection.svg b/browser/themes/shared/privatebrowsing/tracking-protection.svg similarity index 100% rename from application/basilisk/themes/shared/privatebrowsing/tracking-protection.svg rename to browser/themes/shared/privatebrowsing/tracking-protection.svg diff --git a/application/basilisk/themes/shared/reader/reader-mode-16.png b/browser/themes/shared/reader/reader-mode-16.png similarity index 100% rename from application/basilisk/themes/shared/reader/reader-mode-16.png rename to browser/themes/shared/reader/reader-mode-16.png diff --git a/application/basilisk/themes/shared/reader/reader-mode-16@2x.png b/browser/themes/shared/reader/reader-mode-16@2x.png similarity index 100% rename from application/basilisk/themes/shared/reader/reader-mode-16@2x.png rename to browser/themes/shared/reader/reader-mode-16@2x.png diff --git a/application/basilisk/themes/shared/reader/reader-tour.png b/browser/themes/shared/reader/reader-tour.png similarity index 100% rename from application/basilisk/themes/shared/reader/reader-tour.png rename to browser/themes/shared/reader/reader-tour.png diff --git a/application/basilisk/themes/shared/reader/reader-tour@2x.png b/browser/themes/shared/reader/reader-tour@2x.png similarity index 100% rename from application/basilisk/themes/shared/reader/reader-tour@2x.png rename to browser/themes/shared/reader/reader-tour@2x.png diff --git a/application/basilisk/themes/shared/reader/readerMode.svg b/browser/themes/shared/reader/readerMode.svg similarity index 100% rename from application/basilisk/themes/shared/reader/readerMode.svg rename to browser/themes/shared/reader/readerMode.svg diff --git a/application/basilisk/themes/shared/search/badge-add-engine.png b/browser/themes/shared/search/badge-add-engine.png similarity index 100% rename from application/basilisk/themes/shared/search/badge-add-engine.png rename to browser/themes/shared/search/badge-add-engine.png diff --git a/application/basilisk/themes/shared/search/badge-add-engine@2x.png b/browser/themes/shared/search/badge-add-engine@2x.png similarity index 100% rename from application/basilisk/themes/shared/search/badge-add-engine@2x.png rename to browser/themes/shared/search/badge-add-engine@2x.png diff --git a/application/basilisk/themes/shared/search/gear.svg b/browser/themes/shared/search/gear.svg similarity index 100% rename from application/basilisk/themes/shared/search/gear.svg rename to browser/themes/shared/search/gear.svg diff --git a/application/basilisk/themes/shared/search/history-icon.svg b/browser/themes/shared/search/history-icon.svg similarity index 100% rename from application/basilisk/themes/shared/search/history-icon.svg rename to browser/themes/shared/search/history-icon.svg diff --git a/application/basilisk/themes/shared/search/search-arrow-go.svg b/browser/themes/shared/search/search-arrow-go.svg similarity index 100% rename from application/basilisk/themes/shared/search/search-arrow-go.svg rename to browser/themes/shared/search/search-arrow-go.svg diff --git a/application/basilisk/themes/shared/search/search-engine-placeholder.png b/browser/themes/shared/search/search-engine-placeholder.png similarity index 100% rename from application/basilisk/themes/shared/search/search-engine-placeholder.png rename to browser/themes/shared/search/search-engine-placeholder.png diff --git a/application/basilisk/themes/shared/search/search-engine-placeholder@2x.png b/browser/themes/shared/search/search-engine-placeholder@2x.png similarity index 100% rename from application/basilisk/themes/shared/search/search-engine-placeholder@2x.png rename to browser/themes/shared/search/search-engine-placeholder@2x.png diff --git a/application/basilisk/themes/shared/search/search-indicator-badge-add.png b/browser/themes/shared/search/search-indicator-badge-add.png similarity index 100% rename from application/basilisk/themes/shared/search/search-indicator-badge-add.png rename to browser/themes/shared/search/search-indicator-badge-add.png diff --git a/application/basilisk/themes/shared/search/search-indicator-badge-add@2x.png b/browser/themes/shared/search/search-indicator-badge-add@2x.png similarity index 100% rename from application/basilisk/themes/shared/search/search-indicator-badge-add@2x.png rename to browser/themes/shared/search/search-indicator-badge-add@2x.png diff --git a/application/basilisk/themes/shared/search/search-indicator-magnifying-glass.svg b/browser/themes/shared/search/search-indicator-magnifying-glass.svg similarity index 100% rename from application/basilisk/themes/shared/search/search-indicator-magnifying-glass.svg rename to browser/themes/shared/search/search-indicator-magnifying-glass.svg diff --git a/application/basilisk/themes/shared/search/search-indicator.png b/browser/themes/shared/search/search-indicator.png similarity index 100% rename from application/basilisk/themes/shared/search/search-indicator.png rename to browser/themes/shared/search/search-indicator.png diff --git a/application/basilisk/themes/shared/search/search-indicator@2x.png b/browser/themes/shared/search/search-indicator@2x.png similarity index 100% rename from application/basilisk/themes/shared/search/search-indicator@2x.png rename to browser/themes/shared/search/search-indicator@2x.png diff --git a/application/basilisk/themes/shared/searchReset.css b/browser/themes/shared/searchReset.css similarity index 100% rename from application/basilisk/themes/shared/searchReset.css rename to browser/themes/shared/searchReset.css diff --git a/application/basilisk/themes/shared/sync-desktopIcon.svg b/browser/themes/shared/sync-desktopIcon.svg similarity index 100% rename from application/basilisk/themes/shared/sync-desktopIcon.svg rename to browser/themes/shared/sync-desktopIcon.svg diff --git a/application/basilisk/themes/shared/sync-mobileIcon.svg b/browser/themes/shared/sync-mobileIcon.svg similarity index 100% rename from application/basilisk/themes/shared/sync-mobileIcon.svg rename to browser/themes/shared/sync-mobileIcon.svg diff --git a/application/basilisk/themes/shared/tab-selected.svg b/browser/themes/shared/tab-selected.svg similarity index 100% rename from application/basilisk/themes/shared/tab-selected.svg rename to browser/themes/shared/tab-selected.svg diff --git a/application/basilisk/themes/shared/tabbrowser/connecting.png b/browser/themes/shared/tabbrowser/connecting.png similarity index 100% rename from application/basilisk/themes/shared/tabbrowser/connecting.png rename to browser/themes/shared/tabbrowser/connecting.png diff --git a/application/basilisk/themes/shared/tabbrowser/connecting@2x.png b/browser/themes/shared/tabbrowser/connecting@2x.png similarity index 100% rename from application/basilisk/themes/shared/tabbrowser/connecting@2x.png rename to browser/themes/shared/tabbrowser/connecting@2x.png diff --git a/application/basilisk/themes/shared/tabbrowser/crashed.svg b/browser/themes/shared/tabbrowser/crashed.svg similarity index 100% rename from application/basilisk/themes/shared/tabbrowser/crashed.svg rename to browser/themes/shared/tabbrowser/crashed.svg diff --git a/application/basilisk/themes/shared/tabbrowser/pendingpaint.png b/browser/themes/shared/tabbrowser/pendingpaint.png similarity index 100% rename from application/basilisk/themes/shared/tabbrowser/pendingpaint.png rename to browser/themes/shared/tabbrowser/pendingpaint.png diff --git a/application/basilisk/themes/shared/tabbrowser/tab-audio-small.svg b/browser/themes/shared/tabbrowser/tab-audio-small.svg similarity index 100% rename from application/basilisk/themes/shared/tabbrowser/tab-audio-small.svg rename to browser/themes/shared/tabbrowser/tab-audio-small.svg diff --git a/application/basilisk/themes/shared/tabbrowser/tab-audio.svg b/browser/themes/shared/tabbrowser/tab-audio.svg similarity index 100% rename from application/basilisk/themes/shared/tabbrowser/tab-audio.svg rename to browser/themes/shared/tabbrowser/tab-audio.svg diff --git a/application/basilisk/themes/shared/tabbrowser/tab-overflow-indicator.png b/browser/themes/shared/tabbrowser/tab-overflow-indicator.png similarity index 100% rename from application/basilisk/themes/shared/tabbrowser/tab-overflow-indicator.png rename to browser/themes/shared/tabbrowser/tab-overflow-indicator.png diff --git a/application/basilisk/themes/shared/tabs.inc.css b/browser/themes/shared/tabs.inc.css similarity index 100% rename from application/basilisk/themes/shared/tabs.inc.css rename to browser/themes/shared/tabs.inc.css diff --git a/application/basilisk/themes/shared/theme-switcher-icon.png b/browser/themes/shared/theme-switcher-icon.png similarity index 100% rename from application/basilisk/themes/shared/theme-switcher-icon.png rename to browser/themes/shared/theme-switcher-icon.png diff --git a/application/basilisk/themes/shared/theme-switcher-icon@2x.png b/browser/themes/shared/theme-switcher-icon@2x.png similarity index 100% rename from application/basilisk/themes/shared/theme-switcher-icon@2x.png rename to browser/themes/shared/theme-switcher-icon@2x.png diff --git a/application/basilisk/themes/shared/toolbarbutton-dropdown-arrow.png b/browser/themes/shared/toolbarbutton-dropdown-arrow.png similarity index 100% rename from application/basilisk/themes/shared/toolbarbutton-dropdown-arrow.png rename to browser/themes/shared/toolbarbutton-dropdown-arrow.png diff --git a/application/basilisk/themes/shared/toolbarbuttons.inc.css b/browser/themes/shared/toolbarbuttons.inc.css similarity index 100% rename from application/basilisk/themes/shared/toolbarbuttons.inc.css rename to browser/themes/shared/toolbarbuttons.inc.css diff --git a/application/basilisk/themes/shared/undoCloseTab.png b/browser/themes/shared/undoCloseTab.png similarity index 100% rename from application/basilisk/themes/shared/undoCloseTab.png rename to browser/themes/shared/undoCloseTab.png diff --git a/application/basilisk/themes/shared/undoCloseTab@2x.png b/browser/themes/shared/undoCloseTab@2x.png similarity index 100% rename from application/basilisk/themes/shared/undoCloseTab@2x.png rename to browser/themes/shared/undoCloseTab@2x.png diff --git a/application/basilisk/themes/shared/update-badge-failed.svg b/browser/themes/shared/update-badge-failed.svg similarity index 100% rename from application/basilisk/themes/shared/update-badge-failed.svg rename to browser/themes/shared/update-badge-failed.svg diff --git a/application/basilisk/themes/shared/update-badge.svg b/browser/themes/shared/update-badge.svg similarity index 100% rename from application/basilisk/themes/shared/update-badge.svg rename to browser/themes/shared/update-badge.svg diff --git a/application/basilisk/themes/shared/urlbar-star.svg b/browser/themes/shared/urlbar-star.svg similarity index 100% rename from application/basilisk/themes/shared/urlbar-star.svg rename to browser/themes/shared/urlbar-star.svg diff --git a/application/basilisk/themes/shared/urlbar-tab.svg b/browser/themes/shared/urlbar-tab.svg similarity index 100% rename from application/basilisk/themes/shared/urlbar-tab.svg rename to browser/themes/shared/urlbar-tab.svg diff --git a/application/basilisk/themes/shared/urlbarSearchSuggestionsNotification.inc.css b/browser/themes/shared/urlbarSearchSuggestionsNotification.inc.css similarity index 100% rename from application/basilisk/themes/shared/urlbarSearchSuggestionsNotification.inc.css rename to browser/themes/shared/urlbarSearchSuggestionsNotification.inc.css diff --git a/application/basilisk/themes/shared/warning-white.svg b/browser/themes/shared/warning-white.svg similarity index 100% rename from application/basilisk/themes/shared/warning-white.svg rename to browser/themes/shared/warning-white.svg diff --git a/application/basilisk/themes/shared/warning.svg b/browser/themes/shared/warning.svg similarity index 100% rename from application/basilisk/themes/shared/warning.svg rename to browser/themes/shared/warning.svg diff --git a/application/basilisk/themes/shared/webrtc/camera-white-16.png b/browser/themes/shared/webrtc/camera-white-16.png similarity index 100% rename from application/basilisk/themes/shared/webrtc/camera-white-16.png rename to browser/themes/shared/webrtc/camera-white-16.png diff --git a/application/basilisk/themes/shared/webrtc/camera-white-16@2x.png b/browser/themes/shared/webrtc/camera-white-16@2x.png similarity index 100% rename from application/basilisk/themes/shared/webrtc/camera-white-16@2x.png rename to browser/themes/shared/webrtc/camera-white-16@2x.png diff --git a/application/basilisk/themes/shared/webrtc/microphone-white-16.png b/browser/themes/shared/webrtc/microphone-white-16.png similarity index 100% rename from application/basilisk/themes/shared/webrtc/microphone-white-16.png rename to browser/themes/shared/webrtc/microphone-white-16.png diff --git a/application/basilisk/themes/shared/webrtc/microphone-white-16@2x.png b/browser/themes/shared/webrtc/microphone-white-16@2x.png similarity index 100% rename from application/basilisk/themes/shared/webrtc/microphone-white-16@2x.png rename to browser/themes/shared/webrtc/microphone-white-16@2x.png diff --git a/application/basilisk/themes/shared/webrtc/screen-white-16.png b/browser/themes/shared/webrtc/screen-white-16.png similarity index 100% rename from application/basilisk/themes/shared/webrtc/screen-white-16.png rename to browser/themes/shared/webrtc/screen-white-16.png diff --git a/application/basilisk/themes/shared/webrtc/screen-white-16@2x.png b/browser/themes/shared/webrtc/screen-white-16@2x.png similarity index 100% rename from application/basilisk/themes/shared/webrtc/screen-white-16@2x.png rename to browser/themes/shared/webrtc/screen-white-16@2x.png diff --git a/application/basilisk/themes/tab-svgs.mozbuild b/browser/themes/tab-svgs.mozbuild similarity index 84% rename from application/basilisk/themes/tab-svgs.mozbuild rename to browser/themes/tab-svgs.mozbuild index 5b9290c07c..f36f1fc081 100644 --- a/application/basilisk/themes/tab-svgs.mozbuild +++ b/browser/themes/tab-svgs.mozbuild @@ -3,8 +3,8 @@ # 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/. -script = '/application/basilisk/themes/preprocess-tab-svgs.py' -input = ['/application/basilisk/themes/shared/tab-selected.svg'] +script = '/browser/themes/preprocess-tab-svgs.py' +input = ['/browser/themes/shared/tab-selected.svg'] # Context variables can't be used inside functions, so hack around that. generated_files = GENERATED_FILES diff --git a/application/basilisk/themes/windows/Info-XP.png b/browser/themes/windows/Info-XP.png similarity index 100% rename from application/basilisk/themes/windows/Info-XP.png rename to browser/themes/windows/Info-XP.png diff --git a/application/basilisk/themes/windows/Info.png b/browser/themes/windows/Info.png similarity index 100% rename from application/basilisk/themes/windows/Info.png rename to browser/themes/windows/Info.png diff --git a/application/basilisk/themes/windows/Privacy-16-XP.png b/browser/themes/windows/Privacy-16-XP.png similarity index 100% rename from application/basilisk/themes/windows/Privacy-16-XP.png rename to browser/themes/windows/Privacy-16-XP.png diff --git a/application/basilisk/themes/windows/Privacy-16.png b/browser/themes/windows/Privacy-16.png similarity index 100% rename from application/basilisk/themes/windows/Privacy-16.png rename to browser/themes/windows/Privacy-16.png diff --git a/application/basilisk/themes/windows/Toolbar-XP.png b/browser/themes/windows/Toolbar-XP.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar-XP.png rename to browser/themes/windows/Toolbar-XP.png diff --git a/application/basilisk/themes/windows/Toolbar-aero.png b/browser/themes/windows/Toolbar-aero.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar-aero.png rename to browser/themes/windows/Toolbar-aero.png diff --git a/application/basilisk/themes/windows/Toolbar-aero@2x.png b/browser/themes/windows/Toolbar-aero@2x.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar-aero@2x.png rename to browser/themes/windows/Toolbar-aero@2x.png diff --git a/application/basilisk/themes/windows/Toolbar-inverted.png b/browser/themes/windows/Toolbar-inverted.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar-inverted.png rename to browser/themes/windows/Toolbar-inverted.png diff --git a/application/basilisk/themes/windows/Toolbar-inverted@2x.png b/browser/themes/windows/Toolbar-inverted@2x.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar-inverted@2x.png rename to browser/themes/windows/Toolbar-inverted@2x.png diff --git a/application/basilisk/themes/windows/Toolbar-lunaSilver.png b/browser/themes/windows/Toolbar-lunaSilver.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar-lunaSilver.png rename to browser/themes/windows/Toolbar-lunaSilver.png diff --git a/application/basilisk/themes/windows/Toolbar-win8.png b/browser/themes/windows/Toolbar-win8.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar-win8.png rename to browser/themes/windows/Toolbar-win8.png diff --git a/application/basilisk/themes/windows/Toolbar-win8@2x.png b/browser/themes/windows/Toolbar-win8@2x.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar-win8@2x.png rename to browser/themes/windows/Toolbar-win8@2x.png diff --git a/application/basilisk/themes/windows/Toolbar.png b/browser/themes/windows/Toolbar.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar.png rename to browser/themes/windows/Toolbar.png diff --git a/application/basilisk/themes/windows/Toolbar@2x.png b/browser/themes/windows/Toolbar@2x.png similarity index 100% rename from application/basilisk/themes/windows/Toolbar@2x.png rename to browser/themes/windows/Toolbar@2x.png diff --git a/application/basilisk/themes/windows/aboutSessionRestore-window-icon.png b/browser/themes/windows/aboutSessionRestore-window-icon.png similarity index 100% rename from application/basilisk/themes/windows/aboutSessionRestore-window-icon.png rename to browser/themes/windows/aboutSessionRestore-window-icon.png diff --git a/application/basilisk/themes/windows/aboutSyncTabs.css b/browser/themes/windows/aboutSyncTabs.css similarity index 100% rename from application/basilisk/themes/windows/aboutSyncTabs.css rename to browser/themes/windows/aboutSyncTabs.css diff --git a/application/basilisk/themes/windows/actionicon-tab-XPVista7.png b/browser/themes/windows/actionicon-tab-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/actionicon-tab-XPVista7.png rename to browser/themes/windows/actionicon-tab-XPVista7.png diff --git a/application/basilisk/themes/windows/actionicon-tab.png b/browser/themes/windows/actionicon-tab.png similarity index 100% rename from application/basilisk/themes/windows/actionicon-tab.png rename to browser/themes/windows/actionicon-tab.png diff --git a/application/basilisk/themes/windows/actionicon-tab@2x.png b/browser/themes/windows/actionicon-tab@2x.png similarity index 100% rename from application/basilisk/themes/windows/actionicon-tab@2x.png rename to browser/themes/windows/actionicon-tab@2x.png diff --git a/application/basilisk/themes/windows/browser-aero.css b/browser/themes/windows/browser-aero.css similarity index 100% rename from application/basilisk/themes/windows/browser-aero.css rename to browser/themes/windows/browser-aero.css diff --git a/application/basilisk/themes/windows/browser-lightweightTheme.css b/browser/themes/windows/browser-lightweightTheme.css similarity index 100% rename from application/basilisk/themes/windows/browser-lightweightTheme.css rename to browser/themes/windows/browser-lightweightTheme.css diff --git a/application/basilisk/themes/windows/browser.css b/browser/themes/windows/browser.css similarity index 99% rename from application/basilisk/themes/windows/browser.css rename to browser/themes/windows/browser.css index 10ac79ae1d..e632cc2974 100644 --- a/application/basilisk/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -4862,8 +4862,8 @@ toolbar[brighttext] .statuspanel-label { %include ../shared/fullscreen/warning.inc.css %include ../shared/ctrlTab.inc.css -%include ../../../../devtools/client/themes/responsivedesign.inc.css -%include ../../../../devtools/client/themes/commandline.inc.css +%include ../../../devtools/client/themes/responsivedesign.inc.css +%include ../../../devtools/client/themes/commandline.inc.css %include ../shared/plugin-doorhanger.inc.css notification.pluginVulnerable > .notification-inner > .messageCloseButton { diff --git a/application/basilisk/themes/windows/caption-buttons.svg b/browser/themes/windows/caption-buttons.svg similarity index 100% rename from application/basilisk/themes/windows/caption-buttons.svg rename to browser/themes/windows/caption-buttons.svg diff --git a/application/basilisk/themes/windows/click-to-play-warning-stripes.png b/browser/themes/windows/click-to-play-warning-stripes.png similarity index 100% rename from application/basilisk/themes/windows/click-to-play-warning-stripes.png rename to browser/themes/windows/click-to-play-warning-stripes.png diff --git a/application/basilisk/themes/windows/communicator/communicator.css b/browser/themes/windows/communicator/communicator.css similarity index 100% rename from application/basilisk/themes/windows/communicator/communicator.css rename to browser/themes/windows/communicator/communicator.css diff --git a/application/basilisk/themes/windows/communicator/jar.mn b/browser/themes/windows/communicator/jar.mn similarity index 100% rename from application/basilisk/themes/windows/communicator/jar.mn rename to browser/themes/windows/communicator/jar.mn diff --git a/application/basilisk/themes/linux/communicator/moz.build b/browser/themes/windows/communicator/moz.build similarity index 100% rename from application/basilisk/themes/linux/communicator/moz.build rename to browser/themes/windows/communicator/moz.build diff --git a/application/basilisk/themes/windows/content-contextmenu.svg b/browser/themes/windows/content-contextmenu.svg similarity index 100% rename from application/basilisk/themes/windows/content-contextmenu.svg rename to browser/themes/windows/content-contextmenu.svg diff --git a/application/basilisk/themes/windows/controlcenter/panel.css b/browser/themes/windows/controlcenter/panel.css similarity index 100% rename from application/basilisk/themes/windows/controlcenter/panel.css rename to browser/themes/windows/controlcenter/panel.css diff --git a/application/basilisk/themes/windows/customizableui/background-noise-toolbar.png b/browser/themes/windows/customizableui/background-noise-toolbar.png similarity index 100% rename from application/basilisk/themes/windows/customizableui/background-noise-toolbar.png rename to browser/themes/windows/customizableui/background-noise-toolbar.png diff --git a/application/basilisk/themes/windows/customizableui/customize-titleBar-toggle.png b/browser/themes/windows/customizableui/customize-titleBar-toggle.png similarity index 100% rename from application/basilisk/themes/windows/customizableui/customize-titleBar-toggle.png rename to browser/themes/windows/customizableui/customize-titleBar-toggle.png diff --git a/application/basilisk/themes/windows/customizableui/customize-titleBar-toggle@2x.png b/browser/themes/windows/customizableui/customize-titleBar-toggle@2x.png similarity index 100% rename from application/basilisk/themes/windows/customizableui/customize-titleBar-toggle@2x.png rename to browser/themes/windows/customizableui/customize-titleBar-toggle@2x.png diff --git a/application/basilisk/themes/windows/customizableui/customizeMode-gridTexture.png b/browser/themes/windows/customizableui/customizeMode-gridTexture.png similarity index 100% rename from application/basilisk/themes/windows/customizableui/customizeMode-gridTexture.png rename to browser/themes/windows/customizableui/customizeMode-gridTexture.png diff --git a/application/basilisk/themes/windows/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/windows/customizableui/customizeMode-separatorHorizontal.png similarity index 100% rename from application/basilisk/themes/windows/customizableui/customizeMode-separatorHorizontal.png rename to browser/themes/windows/customizableui/customizeMode-separatorHorizontal.png diff --git a/application/basilisk/themes/windows/customizableui/customizeMode-separatorVertical.png b/browser/themes/windows/customizableui/customizeMode-separatorVertical.png similarity index 100% rename from application/basilisk/themes/windows/customizableui/customizeMode-separatorVertical.png rename to browser/themes/windows/customizableui/customizeMode-separatorVertical.png diff --git a/application/basilisk/themes/windows/customizableui/menu-arrow.svg b/browser/themes/windows/customizableui/menu-arrow.svg similarity index 100% rename from application/basilisk/themes/windows/customizableui/menu-arrow.svg rename to browser/themes/windows/customizableui/menu-arrow.svg diff --git a/application/basilisk/themes/windows/customizableui/panelUI.css b/browser/themes/windows/customizableui/panelUI.css similarity index 100% rename from application/basilisk/themes/windows/customizableui/panelUI.css rename to browser/themes/windows/customizableui/panelUI.css diff --git a/application/basilisk/themes/windows/devedition.css b/browser/themes/windows/devedition.css similarity index 100% rename from application/basilisk/themes/windows/devedition.css rename to browser/themes/windows/devedition.css diff --git a/application/basilisk/themes/windows/downloads/allDownloadsViewOverlay.css b/browser/themes/windows/downloads/allDownloadsViewOverlay.css similarity index 100% rename from application/basilisk/themes/windows/downloads/allDownloadsViewOverlay.css rename to browser/themes/windows/downloads/allDownloadsViewOverlay.css diff --git a/application/basilisk/themes/windows/downloads/download-glow-XPVista7.png b/browser/themes/windows/downloads/download-glow-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/downloads/download-glow-XPVista7.png rename to browser/themes/windows/downloads/download-glow-XPVista7.png diff --git a/application/basilisk/themes/windows/downloads/download-glow-menuPanel-XPVista7.png b/browser/themes/windows/downloads/download-glow-menuPanel-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/downloads/download-glow-menuPanel-XPVista7.png rename to browser/themes/windows/downloads/download-glow-menuPanel-XPVista7.png diff --git a/application/basilisk/themes/windows/downloads/download-glow-menuPanel.png b/browser/themes/windows/downloads/download-glow-menuPanel.png similarity index 100% rename from application/basilisk/themes/windows/downloads/download-glow-menuPanel.png rename to browser/themes/windows/downloads/download-glow-menuPanel.png diff --git a/application/basilisk/themes/windows/downloads/download-glow.png b/browser/themes/windows/downloads/download-glow.png similarity index 100% rename from application/basilisk/themes/windows/downloads/download-glow.png rename to browser/themes/windows/downloads/download-glow.png diff --git a/application/basilisk/themes/windows/downloads/download-notification-finish.png b/browser/themes/windows/downloads/download-notification-finish.png similarity index 100% rename from application/basilisk/themes/windows/downloads/download-notification-finish.png rename to browser/themes/windows/downloads/download-notification-finish.png diff --git a/application/basilisk/themes/windows/downloads/download-notification-start.png b/browser/themes/windows/downloads/download-notification-start.png similarity index 100% rename from application/basilisk/themes/windows/downloads/download-notification-start.png rename to browser/themes/windows/downloads/download-notification-start.png diff --git a/application/basilisk/themes/windows/downloads/downloads.css b/browser/themes/windows/downloads/downloads.css similarity index 100% rename from application/basilisk/themes/windows/downloads/downloads.css rename to browser/themes/windows/downloads/downloads.css diff --git a/application/basilisk/themes/windows/downloads/indicator.css b/browser/themes/windows/downloads/indicator.css similarity index 100% rename from application/basilisk/themes/windows/downloads/indicator.css rename to browser/themes/windows/downloads/indicator.css diff --git a/application/basilisk/themes/windows/feeds/feedIcon-XP.png b/browser/themes/windows/feeds/feedIcon-XP.png similarity index 100% rename from application/basilisk/themes/windows/feeds/feedIcon-XP.png rename to browser/themes/windows/feeds/feedIcon-XP.png diff --git a/application/basilisk/themes/windows/feeds/feedIcon.png b/browser/themes/windows/feeds/feedIcon.png similarity index 100% rename from application/basilisk/themes/windows/feeds/feedIcon.png rename to browser/themes/windows/feeds/feedIcon.png diff --git a/application/basilisk/themes/windows/feeds/feedIcon16-XP.png b/browser/themes/windows/feeds/feedIcon16-XP.png similarity index 100% rename from application/basilisk/themes/windows/feeds/feedIcon16-XP.png rename to browser/themes/windows/feeds/feedIcon16-XP.png diff --git a/application/basilisk/themes/windows/feeds/feedIcon16.png b/browser/themes/windows/feeds/feedIcon16.png similarity index 100% rename from application/basilisk/themes/windows/feeds/feedIcon16.png rename to browser/themes/windows/feeds/feedIcon16.png diff --git a/application/basilisk/themes/windows/feeds/subscribe-ui.css b/browser/themes/windows/feeds/subscribe-ui.css similarity index 100% rename from application/basilisk/themes/windows/feeds/subscribe-ui.css rename to browser/themes/windows/feeds/subscribe-ui.css diff --git a/application/basilisk/themes/windows/feeds/subscribe.css b/browser/themes/windows/feeds/subscribe.css similarity index 100% rename from application/basilisk/themes/windows/feeds/subscribe.css rename to browser/themes/windows/feeds/subscribe.css diff --git a/application/basilisk/themes/windows/jar.mn b/browser/themes/windows/jar.mn similarity index 100% rename from application/basilisk/themes/windows/jar.mn rename to browser/themes/windows/jar.mn diff --git a/application/basilisk/themes/windows/keyhole-forward-mask.svg b/browser/themes/windows/keyhole-forward-mask.svg similarity index 100% rename from application/basilisk/themes/windows/keyhole-forward-mask.svg rename to browser/themes/windows/keyhole-forward-mask.svg diff --git a/application/basilisk/themes/windows/livemark-folder-XP.png b/browser/themes/windows/livemark-folder-XP.png similarity index 100% rename from application/basilisk/themes/windows/livemark-folder-XP.png rename to browser/themes/windows/livemark-folder-XP.png diff --git a/application/basilisk/themes/windows/livemark-folder.png b/browser/themes/windows/livemark-folder.png similarity index 100% rename from application/basilisk/themes/windows/livemark-folder.png rename to browser/themes/windows/livemark-folder.png diff --git a/application/basilisk/themes/windows/loop/toolbar-win10.png b/browser/themes/windows/loop/toolbar-win10.png similarity index 100% rename from application/basilisk/themes/windows/loop/toolbar-win10.png rename to browser/themes/windows/loop/toolbar-win10.png diff --git a/application/basilisk/themes/windows/loop/toolbar-win10@2x.png b/browser/themes/windows/loop/toolbar-win10@2x.png similarity index 100% rename from application/basilisk/themes/windows/loop/toolbar-win10@2x.png rename to browser/themes/windows/loop/toolbar-win10@2x.png diff --git a/application/basilisk/themes/windows/menu-back-XP.png b/browser/themes/windows/menu-back-XP.png similarity index 100% rename from application/basilisk/themes/windows/menu-back-XP.png rename to browser/themes/windows/menu-back-XP.png diff --git a/application/basilisk/themes/windows/menu-back.png b/browser/themes/windows/menu-back.png similarity index 100% rename from application/basilisk/themes/windows/menu-back.png rename to browser/themes/windows/menu-back.png diff --git a/application/basilisk/themes/windows/menu-forward-XP.png b/browser/themes/windows/menu-forward-XP.png similarity index 100% rename from application/basilisk/themes/windows/menu-forward-XP.png rename to browser/themes/windows/menu-forward-XP.png diff --git a/application/basilisk/themes/windows/menu-forward.png b/browser/themes/windows/menu-forward.png similarity index 100% rename from application/basilisk/themes/windows/menu-forward.png rename to browser/themes/windows/menu-forward.png diff --git a/application/basilisk/themes/windows/menuPanel-customize.png b/browser/themes/windows/menuPanel-customize.png similarity index 100% rename from application/basilisk/themes/windows/menuPanel-customize.png rename to browser/themes/windows/menuPanel-customize.png diff --git a/application/basilisk/themes/windows/menuPanel-customize@2x.png b/browser/themes/windows/menuPanel-customize@2x.png similarity index 100% rename from application/basilisk/themes/windows/menuPanel-customize@2x.png rename to browser/themes/windows/menuPanel-customize@2x.png diff --git a/application/basilisk/themes/windows/menuPanel-exit.png b/browser/themes/windows/menuPanel-exit.png similarity index 100% rename from application/basilisk/themes/windows/menuPanel-exit.png rename to browser/themes/windows/menuPanel-exit.png diff --git a/application/basilisk/themes/windows/menuPanel-exit@2x.png b/browser/themes/windows/menuPanel-exit@2x.png similarity index 100% rename from application/basilisk/themes/windows/menuPanel-exit@2x.png rename to browser/themes/windows/menuPanel-exit@2x.png diff --git a/application/basilisk/themes/windows/menuPanel-help.png b/browser/themes/windows/menuPanel-help.png similarity index 100% rename from application/basilisk/themes/windows/menuPanel-help.png rename to browser/themes/windows/menuPanel-help.png diff --git a/application/basilisk/themes/windows/menuPanel-help@2x.png b/browser/themes/windows/menuPanel-help@2x.png similarity index 100% rename from application/basilisk/themes/windows/menuPanel-help@2x.png rename to browser/themes/windows/menuPanel-help@2x.png diff --git a/application/basilisk/themes/windows/monitor.png b/browser/themes/windows/monitor.png similarity index 100% rename from application/basilisk/themes/windows/monitor.png rename to browser/themes/windows/monitor.png diff --git a/application/basilisk/themes/windows/monitor_16-10.png b/browser/themes/windows/monitor_16-10.png similarity index 100% rename from application/basilisk/themes/windows/monitor_16-10.png rename to browser/themes/windows/monitor_16-10.png diff --git a/application/basilisk/themes/windows/moz.build b/browser/themes/windows/moz.build similarity index 100% rename from application/basilisk/themes/windows/moz.build rename to browser/themes/windows/moz.build diff --git a/application/basilisk/themes/windows/newtab/newTab.css b/browser/themes/windows/newtab/newTab.css similarity index 100% rename from application/basilisk/themes/windows/newtab/newTab.css rename to browser/themes/windows/newtab/newTab.css diff --git a/application/basilisk/themes/windows/pageInfo-XP.png b/browser/themes/windows/pageInfo-XP.png similarity index 100% rename from application/basilisk/themes/windows/pageInfo-XP.png rename to browser/themes/windows/pageInfo-XP.png diff --git a/application/basilisk/themes/windows/pageInfo.css b/browser/themes/windows/pageInfo.css similarity index 100% rename from application/basilisk/themes/windows/pageInfo.css rename to browser/themes/windows/pageInfo.css diff --git a/application/basilisk/themes/windows/pageInfo.png b/browser/themes/windows/pageInfo.png similarity index 100% rename from application/basilisk/themes/windows/pageInfo.png rename to browser/themes/windows/pageInfo.png diff --git a/application/basilisk/themes/windows/places/allBookmarks-XP.png b/browser/themes/windows/places/allBookmarks-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/allBookmarks-XP.png rename to browser/themes/windows/places/allBookmarks-XP.png diff --git a/application/basilisk/themes/windows/places/allBookmarks.png b/browser/themes/windows/places/allBookmarks.png similarity index 100% rename from application/basilisk/themes/windows/places/allBookmarks.png rename to browser/themes/windows/places/allBookmarks.png diff --git a/application/basilisk/themes/windows/places/autocomplete-star-XPVista7.png b/browser/themes/windows/places/autocomplete-star-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/places/autocomplete-star-XPVista7.png rename to browser/themes/windows/places/autocomplete-star-XPVista7.png diff --git a/application/basilisk/themes/windows/places/autocomplete-star.png b/browser/themes/windows/places/autocomplete-star.png similarity index 100% rename from application/basilisk/themes/windows/places/autocomplete-star.png rename to browser/themes/windows/places/autocomplete-star.png diff --git a/application/basilisk/themes/windows/places/autocomplete-star@2x.png b/browser/themes/windows/places/autocomplete-star@2x.png similarity index 100% rename from application/basilisk/themes/windows/places/autocomplete-star@2x.png rename to browser/themes/windows/places/autocomplete-star@2x.png diff --git a/application/basilisk/themes/windows/places/bookmarks-notification-finish.png b/browser/themes/windows/places/bookmarks-notification-finish.png similarity index 100% rename from application/basilisk/themes/windows/places/bookmarks-notification-finish.png rename to browser/themes/windows/places/bookmarks-notification-finish.png diff --git a/application/basilisk/themes/windows/places/bookmarksMenu-XP.png b/browser/themes/windows/places/bookmarksMenu-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/bookmarksMenu-XP.png rename to browser/themes/windows/places/bookmarksMenu-XP.png diff --git a/application/basilisk/themes/windows/places/bookmarksMenu.png b/browser/themes/windows/places/bookmarksMenu.png similarity index 100% rename from application/basilisk/themes/windows/places/bookmarksMenu.png rename to browser/themes/windows/places/bookmarksMenu.png diff --git a/application/basilisk/themes/windows/places/bookmarksToolbar-XP.png b/browser/themes/windows/places/bookmarksToolbar-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/bookmarksToolbar-XP.png rename to browser/themes/windows/places/bookmarksToolbar-XP.png diff --git a/application/basilisk/themes/windows/places/bookmarksToolbar-menuPanel-XP.png b/browser/themes/windows/places/bookmarksToolbar-menuPanel-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/bookmarksToolbar-menuPanel-XP.png rename to browser/themes/windows/places/bookmarksToolbar-menuPanel-XP.png diff --git a/application/basilisk/themes/windows/places/bookmarksToolbar-menuPanel.png b/browser/themes/windows/places/bookmarksToolbar-menuPanel.png similarity index 100% rename from application/basilisk/themes/windows/places/bookmarksToolbar-menuPanel.png rename to browser/themes/windows/places/bookmarksToolbar-menuPanel.png diff --git a/application/basilisk/themes/windows/places/bookmarksToolbar.png b/browser/themes/windows/places/bookmarksToolbar.png similarity index 100% rename from application/basilisk/themes/windows/places/bookmarksToolbar.png rename to browser/themes/windows/places/bookmarksToolbar.png diff --git a/application/basilisk/themes/windows/places/calendar-XP.png b/browser/themes/windows/places/calendar-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/calendar-XP.png rename to browser/themes/windows/places/calendar-XP.png diff --git a/application/basilisk/themes/windows/places/calendar.png b/browser/themes/windows/places/calendar.png similarity index 100% rename from application/basilisk/themes/windows/places/calendar.png rename to browser/themes/windows/places/calendar.png diff --git a/application/basilisk/themes/windows/places/downloads.png b/browser/themes/windows/places/downloads.png similarity index 100% rename from application/basilisk/themes/windows/places/downloads.png rename to browser/themes/windows/places/downloads.png diff --git a/application/basilisk/themes/windows/places/editBookmarkOverlay.css b/browser/themes/windows/places/editBookmarkOverlay.css similarity index 100% rename from application/basilisk/themes/windows/places/editBookmarkOverlay.css rename to browser/themes/windows/places/editBookmarkOverlay.css diff --git a/application/basilisk/themes/windows/places/history-XP.png b/browser/themes/windows/places/history-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/history-XP.png rename to browser/themes/windows/places/history-XP.png diff --git a/application/basilisk/themes/windows/places/history.png b/browser/themes/windows/places/history.png similarity index 100% rename from application/basilisk/themes/windows/places/history.png rename to browser/themes/windows/places/history.png diff --git a/application/basilisk/themes/windows/places/libraryToolbar-XP.png b/browser/themes/windows/places/libraryToolbar-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/libraryToolbar-XP.png rename to browser/themes/windows/places/libraryToolbar-XP.png diff --git a/application/basilisk/themes/windows/places/libraryToolbar.png b/browser/themes/windows/places/libraryToolbar.png similarity index 100% rename from application/basilisk/themes/windows/places/libraryToolbar.png rename to browser/themes/windows/places/libraryToolbar.png diff --git a/application/basilisk/themes/windows/places/livemark-item.png b/browser/themes/windows/places/livemark-item.png similarity index 100% rename from application/basilisk/themes/windows/places/livemark-item.png rename to browser/themes/windows/places/livemark-item.png diff --git a/application/basilisk/themes/windows/places/organizer.css b/browser/themes/windows/places/organizer.css similarity index 100% rename from application/basilisk/themes/windows/places/organizer.css rename to browser/themes/windows/places/organizer.css diff --git a/application/basilisk/themes/windows/places/places.css b/browser/themes/windows/places/places.css similarity index 100% rename from application/basilisk/themes/windows/places/places.css rename to browser/themes/windows/places/places.css diff --git a/application/basilisk/themes/windows/places/query-XP.png b/browser/themes/windows/places/query-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/query-XP.png rename to browser/themes/windows/places/query-XP.png diff --git a/application/basilisk/themes/windows/places/query.png b/browser/themes/windows/places/query.png similarity index 100% rename from application/basilisk/themes/windows/places/query.png rename to browser/themes/windows/places/query.png diff --git a/application/basilisk/themes/windows/places/starred48-XP.png b/browser/themes/windows/places/starred48-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/starred48-XP.png rename to browser/themes/windows/places/starred48-XP.png diff --git a/application/basilisk/themes/windows/places/starred48.png b/browser/themes/windows/places/starred48.png similarity index 100% rename from application/basilisk/themes/windows/places/starred48.png rename to browser/themes/windows/places/starred48.png diff --git a/application/basilisk/themes/windows/places/tag-XP.png b/browser/themes/windows/places/tag-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/tag-XP.png rename to browser/themes/windows/places/tag-XP.png diff --git a/application/basilisk/themes/windows/places/tag.png b/browser/themes/windows/places/tag.png similarity index 100% rename from application/basilisk/themes/windows/places/tag.png rename to browser/themes/windows/places/tag.png diff --git a/application/basilisk/themes/windows/places/toolbarDropMarker-XP.png b/browser/themes/windows/places/toolbarDropMarker-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/toolbarDropMarker-XP.png rename to browser/themes/windows/places/toolbarDropMarker-XP.png diff --git a/application/basilisk/themes/windows/places/toolbarDropMarker.png b/browser/themes/windows/places/toolbarDropMarker.png similarity index 100% rename from application/basilisk/themes/windows/places/toolbarDropMarker.png rename to browser/themes/windows/places/toolbarDropMarker.png diff --git a/application/basilisk/themes/windows/places/unsortedBookmarks-XP.png b/browser/themes/windows/places/unsortedBookmarks-XP.png similarity index 100% rename from application/basilisk/themes/windows/places/unsortedBookmarks-XP.png rename to browser/themes/windows/places/unsortedBookmarks-XP.png diff --git a/application/basilisk/themes/windows/places/unsortedBookmarks.png b/browser/themes/windows/places/unsortedBookmarks.png similarity index 100% rename from application/basilisk/themes/windows/places/unsortedBookmarks.png rename to browser/themes/windows/places/unsortedBookmarks.png diff --git a/application/basilisk/themes/windows/places/unstarred48.png b/browser/themes/windows/places/unstarred48.png similarity index 100% rename from application/basilisk/themes/windows/places/unstarred48.png rename to browser/themes/windows/places/unstarred48.png diff --git a/application/basilisk/themes/windows/preferences/alwaysAsk-XP.png b/browser/themes/windows/preferences/alwaysAsk-XP.png similarity index 100% rename from application/basilisk/themes/windows/preferences/alwaysAsk-XP.png rename to browser/themes/windows/preferences/alwaysAsk-XP.png diff --git a/application/basilisk/themes/windows/preferences/alwaysAsk.png b/browser/themes/windows/preferences/alwaysAsk.png similarity index 100% rename from application/basilisk/themes/windows/preferences/alwaysAsk.png rename to browser/themes/windows/preferences/alwaysAsk.png diff --git a/application/basilisk/themes/windows/preferences/application-XP.png b/browser/themes/windows/preferences/application-XP.png similarity index 100% rename from application/basilisk/themes/windows/preferences/application-XP.png rename to browser/themes/windows/preferences/application-XP.png diff --git a/application/basilisk/themes/windows/preferences/application.png b/browser/themes/windows/preferences/application.png similarity index 100% rename from application/basilisk/themes/windows/preferences/application.png rename to browser/themes/windows/preferences/application.png diff --git a/application/basilisk/themes/windows/preferences/applications.css b/browser/themes/windows/preferences/applications.css similarity index 100% rename from application/basilisk/themes/windows/preferences/applications.css rename to browser/themes/windows/preferences/applications.css diff --git a/application/basilisk/themes/windows/preferences/in-content/dialog.css b/browser/themes/windows/preferences/in-content/dialog.css similarity index 100% rename from application/basilisk/themes/windows/preferences/in-content/dialog.css rename to browser/themes/windows/preferences/in-content/dialog.css diff --git a/application/basilisk/themes/windows/preferences/in-content/preferences.css b/browser/themes/windows/preferences/in-content/preferences.css similarity index 100% rename from application/basilisk/themes/windows/preferences/in-content/preferences.css rename to browser/themes/windows/preferences/in-content/preferences.css diff --git a/application/basilisk/themes/windows/preferences/preferences.css b/browser/themes/windows/preferences/preferences.css similarity index 100% rename from application/basilisk/themes/windows/preferences/preferences.css rename to browser/themes/windows/preferences/preferences.css diff --git a/application/basilisk/themes/windows/preferences/saveFile-XP.png b/browser/themes/windows/preferences/saveFile-XP.png similarity index 100% rename from application/basilisk/themes/windows/preferences/saveFile-XP.png rename to browser/themes/windows/preferences/saveFile-XP.png diff --git a/application/basilisk/themes/windows/preferences/saveFile.png b/browser/themes/windows/preferences/saveFile.png similarity index 100% rename from application/basilisk/themes/windows/preferences/saveFile.png rename to browser/themes/windows/preferences/saveFile.png diff --git a/application/basilisk/themes/windows/privatebrowsing-mask-tabstrip-XPVista7.png b/browser/themes/windows/privatebrowsing-mask-tabstrip-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/privatebrowsing-mask-tabstrip-XPVista7.png rename to browser/themes/windows/privatebrowsing-mask-tabstrip-XPVista7.png diff --git a/application/basilisk/themes/windows/privatebrowsing-mask-tabstrip.png b/browser/themes/windows/privatebrowsing-mask-tabstrip.png similarity index 100% rename from application/basilisk/themes/windows/privatebrowsing-mask-tabstrip.png rename to browser/themes/windows/privatebrowsing-mask-tabstrip.png diff --git a/application/basilisk/themes/windows/privatebrowsing-mask-titlebar-XPVista7-tall.png b/browser/themes/windows/privatebrowsing-mask-titlebar-XPVista7-tall.png similarity index 100% rename from application/basilisk/themes/windows/privatebrowsing-mask-titlebar-XPVista7-tall.png rename to browser/themes/windows/privatebrowsing-mask-titlebar-XPVista7-tall.png diff --git a/application/basilisk/themes/windows/privatebrowsing-mask-titlebar-XPVista7.png b/browser/themes/windows/privatebrowsing-mask-titlebar-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/privatebrowsing-mask-titlebar-XPVista7.png rename to browser/themes/windows/privatebrowsing-mask-titlebar-XPVista7.png diff --git a/application/basilisk/themes/windows/privatebrowsing-mask-titlebar.png b/browser/themes/windows/privatebrowsing-mask-titlebar.png similarity index 100% rename from application/basilisk/themes/windows/privatebrowsing-mask-titlebar.png rename to browser/themes/windows/privatebrowsing-mask-titlebar.png diff --git a/application/basilisk/themes/windows/reload-stop-go-XPVista7.png b/browser/themes/windows/reload-stop-go-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/reload-stop-go-XPVista7.png rename to browser/themes/windows/reload-stop-go-XPVista7.png diff --git a/application/basilisk/themes/windows/reload-stop-go-XPVista7@2x.png b/browser/themes/windows/reload-stop-go-XPVista7@2x.png similarity index 100% rename from application/basilisk/themes/windows/reload-stop-go-XPVista7@2x.png rename to browser/themes/windows/reload-stop-go-XPVista7@2x.png diff --git a/application/basilisk/themes/windows/reload-stop-go.png b/browser/themes/windows/reload-stop-go.png similarity index 100% rename from application/basilisk/themes/windows/reload-stop-go.png rename to browser/themes/windows/reload-stop-go.png diff --git a/application/basilisk/themes/windows/reload-stop-go@2x.png b/browser/themes/windows/reload-stop-go@2x.png similarity index 100% rename from application/basilisk/themes/windows/reload-stop-go@2x.png rename to browser/themes/windows/reload-stop-go@2x.png diff --git a/application/basilisk/themes/windows/sanitizeDialog.css b/browser/themes/windows/sanitizeDialog.css similarity index 100% rename from application/basilisk/themes/windows/sanitizeDialog.css rename to browser/themes/windows/sanitizeDialog.css diff --git a/application/basilisk/themes/windows/searchbar.css b/browser/themes/windows/searchbar.css similarity index 100% rename from application/basilisk/themes/windows/searchbar.css rename to browser/themes/windows/searchbar.css diff --git a/application/basilisk/themes/windows/setDesktopBackground.css b/browser/themes/windows/setDesktopBackground.css similarity index 100% rename from application/basilisk/themes/windows/setDesktopBackground.css rename to browser/themes/windows/setDesktopBackground.css diff --git a/application/basilisk/themes/windows/slowStartup-16.png b/browser/themes/windows/slowStartup-16.png similarity index 100% rename from application/basilisk/themes/windows/slowStartup-16.png rename to browser/themes/windows/slowStartup-16.png diff --git a/application/basilisk/themes/windows/sync-128.png b/browser/themes/windows/sync-128.png similarity index 100% rename from application/basilisk/themes/windows/sync-128.png rename to browser/themes/windows/sync-128.png diff --git a/application/basilisk/themes/windows/sync-16.png b/browser/themes/windows/sync-16.png similarity index 100% rename from application/basilisk/themes/windows/sync-16.png rename to browser/themes/windows/sync-16.png diff --git a/application/basilisk/themes/windows/sync-32.png b/browser/themes/windows/sync-32.png similarity index 100% rename from application/basilisk/themes/windows/sync-32.png rename to browser/themes/windows/sync-32.png diff --git a/application/basilisk/themes/windows/sync-bg.png b/browser/themes/windows/sync-bg.png similarity index 100% rename from application/basilisk/themes/windows/sync-bg.png rename to browser/themes/windows/sync-bg.png diff --git a/application/basilisk/themes/windows/sync-horizontalbar-XPVista7.png b/browser/themes/windows/sync-horizontalbar-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/sync-horizontalbar-XPVista7.png rename to browser/themes/windows/sync-horizontalbar-XPVista7.png diff --git a/application/basilisk/themes/windows/sync-horizontalbar-XPVista7@2x.png b/browser/themes/windows/sync-horizontalbar-XPVista7@2x.png similarity index 100% rename from application/basilisk/themes/windows/sync-horizontalbar-XPVista7@2x.png rename to browser/themes/windows/sync-horizontalbar-XPVista7@2x.png diff --git a/application/basilisk/themes/windows/sync-horizontalbar.png b/browser/themes/windows/sync-horizontalbar.png similarity index 100% rename from application/basilisk/themes/windows/sync-horizontalbar.png rename to browser/themes/windows/sync-horizontalbar.png diff --git a/application/basilisk/themes/windows/sync-horizontalbar@2x.png b/browser/themes/windows/sync-horizontalbar@2x.png similarity index 100% rename from application/basilisk/themes/windows/sync-horizontalbar@2x.png rename to browser/themes/windows/sync-horizontalbar@2x.png diff --git a/application/basilisk/themes/windows/sync-notification-24.png b/browser/themes/windows/sync-notification-24.png similarity index 100% rename from application/basilisk/themes/windows/sync-notification-24.png rename to browser/themes/windows/sync-notification-24.png diff --git a/application/basilisk/themes/windows/syncCommon.css b/browser/themes/windows/syncCommon.css similarity index 100% rename from application/basilisk/themes/windows/syncCommon.css rename to browser/themes/windows/syncCommon.css diff --git a/application/basilisk/themes/windows/syncProgress-horizontalbar-XPVista7.png b/browser/themes/windows/syncProgress-horizontalbar-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-horizontalbar-XPVista7.png rename to browser/themes/windows/syncProgress-horizontalbar-XPVista7.png diff --git a/application/basilisk/themes/windows/syncProgress-horizontalbar-XPVista7@2x.png b/browser/themes/windows/syncProgress-horizontalbar-XPVista7@2x.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-horizontalbar-XPVista7@2x.png rename to browser/themes/windows/syncProgress-horizontalbar-XPVista7@2x.png diff --git a/application/basilisk/themes/windows/syncProgress-horizontalbar.png b/browser/themes/windows/syncProgress-horizontalbar.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-horizontalbar.png rename to browser/themes/windows/syncProgress-horizontalbar.png diff --git a/application/basilisk/themes/windows/syncProgress-horizontalbar@2x.png b/browser/themes/windows/syncProgress-horizontalbar@2x.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-horizontalbar@2x.png rename to browser/themes/windows/syncProgress-horizontalbar@2x.png diff --git a/application/basilisk/themes/windows/syncProgress-menuPanel.png b/browser/themes/windows/syncProgress-menuPanel.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-menuPanel.png rename to browser/themes/windows/syncProgress-menuPanel.png diff --git a/application/basilisk/themes/windows/syncProgress-menuPanel@2x.png b/browser/themes/windows/syncProgress-menuPanel@2x.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-menuPanel@2x.png rename to browser/themes/windows/syncProgress-menuPanel@2x.png diff --git a/application/basilisk/themes/windows/syncProgress-toolbar-XPVista7.png b/browser/themes/windows/syncProgress-toolbar-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-toolbar-XPVista7.png rename to browser/themes/windows/syncProgress-toolbar-XPVista7.png diff --git a/application/basilisk/themes/windows/syncProgress-toolbar-XPVista7@2x.png b/browser/themes/windows/syncProgress-toolbar-XPVista7@2x.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-toolbar-XPVista7@2x.png rename to browser/themes/windows/syncProgress-toolbar-XPVista7@2x.png diff --git a/application/basilisk/themes/windows/syncProgress-toolbar-inverted.png b/browser/themes/windows/syncProgress-toolbar-inverted.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-toolbar-inverted.png rename to browser/themes/windows/syncProgress-toolbar-inverted.png diff --git a/application/basilisk/themes/windows/syncProgress-toolbar-inverted@2x.png b/browser/themes/windows/syncProgress-toolbar-inverted@2x.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-toolbar-inverted@2x.png rename to browser/themes/windows/syncProgress-toolbar-inverted@2x.png diff --git a/application/basilisk/themes/windows/syncProgress-toolbar.png b/browser/themes/windows/syncProgress-toolbar.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-toolbar.png rename to browser/themes/windows/syncProgress-toolbar.png diff --git a/application/basilisk/themes/windows/syncProgress-toolbar@2x.png b/browser/themes/windows/syncProgress-toolbar@2x.png similarity index 100% rename from application/basilisk/themes/windows/syncProgress-toolbar@2x.png rename to browser/themes/windows/syncProgress-toolbar@2x.png diff --git a/application/basilisk/themes/windows/syncProgress.css b/browser/themes/windows/syncProgress.css similarity index 100% rename from application/basilisk/themes/windows/syncProgress.css rename to browser/themes/windows/syncProgress.css diff --git a/application/basilisk/themes/windows/syncQuota.css b/browser/themes/windows/syncQuota.css similarity index 100% rename from application/basilisk/themes/windows/syncQuota.css rename to browser/themes/windows/syncQuota.css diff --git a/application/basilisk/themes/windows/syncSetup.css b/browser/themes/windows/syncSetup.css similarity index 100% rename from application/basilisk/themes/windows/syncSetup.css rename to browser/themes/windows/syncSetup.css diff --git a/application/basilisk/themes/windows/tabbrowser/newtab-XPVista7.svg b/browser/themes/windows/tabbrowser/newtab-XPVista7.svg similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/newtab-XPVista7.svg rename to browser/themes/windows/tabbrowser/newtab-XPVista7.svg diff --git a/application/basilisk/themes/windows/tabbrowser/newtab-inverted-XPVista7.svg b/browser/themes/windows/tabbrowser/newtab-inverted-XPVista7.svg similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/newtab-inverted-XPVista7.svg rename to browser/themes/windows/tabbrowser/newtab-inverted-XPVista7.svg diff --git a/application/basilisk/themes/windows/tabbrowser/newtab-inverted.svg b/browser/themes/windows/tabbrowser/newtab-inverted.svg similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/newtab-inverted.svg rename to browser/themes/windows/tabbrowser/newtab-inverted.svg diff --git a/application/basilisk/themes/windows/tabbrowser/newtab.svg b/browser/themes/windows/tabbrowser/newtab.svg similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/newtab.svg rename to browser/themes/windows/tabbrowser/newtab.svg diff --git a/application/basilisk/themes/windows/tabbrowser/tab-active-middle.png b/browser/themes/windows/tabbrowser/tab-active-middle.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-active-middle.png rename to browser/themes/windows/tabbrowser/tab-active-middle.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-active-middle@2x.png b/browser/themes/windows/tabbrowser/tab-active-middle@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-active-middle@2x.png rename to browser/themes/windows/tabbrowser/tab-active-middle@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-arrow-left-XPVista7.svg b/browser/themes/windows/tabbrowser/tab-arrow-left-XPVista7.svg similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-arrow-left-XPVista7.svg rename to browser/themes/windows/tabbrowser/tab-arrow-left-XPVista7.svg diff --git a/application/basilisk/themes/windows/tabbrowser/tab-arrow-left-inverted.svg b/browser/themes/windows/tabbrowser/tab-arrow-left-inverted.svg similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-arrow-left-inverted.svg rename to browser/themes/windows/tabbrowser/tab-arrow-left-inverted.svg diff --git a/application/basilisk/themes/windows/tabbrowser/tab-arrow-left.svg b/browser/themes/windows/tabbrowser/tab-arrow-left.svg similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-arrow-left.svg rename to browser/themes/windows/tabbrowser/tab-arrow-left.svg diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-end-preWin10.png b/browser/themes/windows/tabbrowser/tab-background-end-preWin10.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-end-preWin10.png rename to browser/themes/windows/tabbrowser/tab-background-end-preWin10.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-end-preWin10@2x.png b/browser/themes/windows/tabbrowser/tab-background-end-preWin10@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-end-preWin10@2x.png rename to browser/themes/windows/tabbrowser/tab-background-end-preWin10@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-end.png b/browser/themes/windows/tabbrowser/tab-background-end.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-end.png rename to browser/themes/windows/tabbrowser/tab-background-end.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-end@2x.png b/browser/themes/windows/tabbrowser/tab-background-end@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-end@2x.png rename to browser/themes/windows/tabbrowser/tab-background-end@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-middle-preWin10.png b/browser/themes/windows/tabbrowser/tab-background-middle-preWin10.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-middle-preWin10.png rename to browser/themes/windows/tabbrowser/tab-background-middle-preWin10.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-middle-preWin10@2x.png b/browser/themes/windows/tabbrowser/tab-background-middle-preWin10@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-middle-preWin10@2x.png rename to browser/themes/windows/tabbrowser/tab-background-middle-preWin10@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-middle.png b/browser/themes/windows/tabbrowser/tab-background-middle.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-middle.png rename to browser/themes/windows/tabbrowser/tab-background-middle.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-middle@2x.png b/browser/themes/windows/tabbrowser/tab-background-middle@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-middle@2x.png rename to browser/themes/windows/tabbrowser/tab-background-middle@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-start-preWin10.png b/browser/themes/windows/tabbrowser/tab-background-start-preWin10.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-start-preWin10.png rename to browser/themes/windows/tabbrowser/tab-background-start-preWin10.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-start-preWin10@2x.png b/browser/themes/windows/tabbrowser/tab-background-start-preWin10@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-start-preWin10@2x.png rename to browser/themes/windows/tabbrowser/tab-background-start-preWin10@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-start.png b/browser/themes/windows/tabbrowser/tab-background-start.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-start.png rename to browser/themes/windows/tabbrowser/tab-background-start.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-background-start@2x.png b/browser/themes/windows/tabbrowser/tab-background-start@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-background-start@2x.png rename to browser/themes/windows/tabbrowser/tab-background-start@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-stroke-end.png b/browser/themes/windows/tabbrowser/tab-stroke-end.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-stroke-end.png rename to browser/themes/windows/tabbrowser/tab-stroke-end.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-stroke-end@2x.png b/browser/themes/windows/tabbrowser/tab-stroke-end@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-stroke-end@2x.png rename to browser/themes/windows/tabbrowser/tab-stroke-end@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-stroke-start.png b/browser/themes/windows/tabbrowser/tab-stroke-start.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-stroke-start.png rename to browser/themes/windows/tabbrowser/tab-stroke-start.png diff --git a/application/basilisk/themes/windows/tabbrowser/tab-stroke-start@2x.png b/browser/themes/windows/tabbrowser/tab-stroke-start@2x.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tab-stroke-start@2x.png rename to browser/themes/windows/tabbrowser/tab-stroke-start@2x.png diff --git a/application/basilisk/themes/windows/tabbrowser/tabDragIndicator.png b/browser/themes/windows/tabbrowser/tabDragIndicator.png similarity index 100% rename from application/basilisk/themes/windows/tabbrowser/tabDragIndicator.png rename to browser/themes/windows/tabbrowser/tabDragIndicator.png diff --git a/application/basilisk/themes/windows/toolbarbutton-dropdown-arrow-XPVista7.png b/browser/themes/windows/toolbarbutton-dropdown-arrow-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/toolbarbutton-dropdown-arrow-XPVista7.png rename to browser/themes/windows/toolbarbutton-dropdown-arrow-XPVista7.png diff --git a/application/basilisk/themes/windows/toolbarbutton-dropdown-arrow-inverted.png b/browser/themes/windows/toolbarbutton-dropdown-arrow-inverted.png similarity index 100% rename from application/basilisk/themes/windows/toolbarbutton-dropdown-arrow-inverted.png rename to browser/themes/windows/toolbarbutton-dropdown-arrow-inverted.png diff --git a/application/basilisk/themes/windows/urlbar-history-dropmarker-XPVista7.png b/browser/themes/windows/urlbar-history-dropmarker-XPVista7.png similarity index 100% rename from application/basilisk/themes/windows/urlbar-history-dropmarker-XPVista7.png rename to browser/themes/windows/urlbar-history-dropmarker-XPVista7.png diff --git a/application/basilisk/themes/windows/urlbar-history-dropmarker-XPVista7@2x.png b/browser/themes/windows/urlbar-history-dropmarker-XPVista7@2x.png similarity index 100% rename from application/basilisk/themes/windows/urlbar-history-dropmarker-XPVista7@2x.png rename to browser/themes/windows/urlbar-history-dropmarker-XPVista7@2x.png diff --git a/application/basilisk/themes/windows/urlbar-history-dropmarker.png b/browser/themes/windows/urlbar-history-dropmarker.png similarity index 100% rename from application/basilisk/themes/windows/urlbar-history-dropmarker.png rename to browser/themes/windows/urlbar-history-dropmarker.png diff --git a/application/basilisk/themes/windows/urlbar-history-dropmarker@2x.png b/browser/themes/windows/urlbar-history-dropmarker@2x.png similarity index 100% rename from application/basilisk/themes/windows/urlbar-history-dropmarker@2x.png rename to browser/themes/windows/urlbar-history-dropmarker@2x.png diff --git a/application/basilisk/themes/windows/urlbar-popup-blocked.png b/browser/themes/windows/urlbar-popup-blocked.png similarity index 100% rename from application/basilisk/themes/windows/urlbar-popup-blocked.png rename to browser/themes/windows/urlbar-popup-blocked.png diff --git a/application/basilisk/themes/windows/webRTC-indicator.css b/browser/themes/windows/webRTC-indicator.css similarity index 100% rename from application/basilisk/themes/windows/webRTC-indicator.css rename to browser/themes/windows/webRTC-indicator.css diff --git a/application/basilisk/themes/windows/windowsShared.inc b/browser/themes/windows/windowsShared.inc similarity index 100% rename from application/basilisk/themes/windows/windowsShared.inc rename to browser/themes/windows/windowsShared.inc diff --git a/build/autoconf/acgeneral.m4 b/build/autoconf/acgeneral.m4 new file mode 100644 index 0000000000..ae971de139 --- /dev/null +++ b/build/autoconf/acgeneral.m4 @@ -0,0 +1,2607 @@ +dnl Parameterized macros. +dnl Requires GNU m4. +dnl This file is part of Autoconf. +dnl Copyright (C) 1992, 93, 94, 95, 96, 1998 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception, the Free Software Foundation gives unlimited +dnl permission to copy, distribute and modify the configure scripts that +dnl are the output of Autoconf. You need not follow the terms of the GNU +dnl General Public License when using or distributing such scripts, even +dnl though portions of the text of Autoconf appear in them. The GNU +dnl General Public License (GPL) does govern all other use of the material +dnl that constitutes the Autoconf program. +dnl +dnl Certain portions of the Autoconf source text are designed to be copied +dnl (in certain cases, depending on the input) into the output of +dnl Autoconf. We call these the "data" portions. The rest of the Autoconf +dnl source text consists of comments plus executable code that decides which +dnl of the data portions to output in any given case. We call these +dnl comments and executable code the "non-data" portions. Autoconf never +dnl copies any of the non-data portions into its output. +dnl +dnl This special exception to the GPL applies to versions of Autoconf +dnl released by the Free Software Foundation. When you make and +dnl distribute a modified version of Autoconf, you may extend this special +dnl exception to the GPL to apply to your modified version as well, *unless* +dnl your modified version has the potential to copy into its output some +dnl of the text that was the non-data portion of the version that you started +dnl with. (In other words, unless your change moves or copies text from +dnl the non-data portions to the data portions.) If your modification has +dnl such potential, you must delete any notice of this special exception +dnl to the GPL from your modified version. +dnl +dnl Written by David MacKenzie, with help from +dnl Franc,ois Pinard, Karl Berry, Richard Pixley, Ian Lance Taylor, +dnl Roland McGrath, Noah Friedman, david d zuhn, and many others. +dnl +divert(-1)dnl Throw away output until AC_INIT is called. +changequote([, ]) + +define(AC_ACVERSION, 2.13) + +dnl Some old m4's don't support m4exit. But they provide +dnl equivalent functionality by core dumping because of the +dnl long macros we define. +ifdef([__gnu__], , [errprint(Autoconf requires GNU m4. +Install it before installing Autoconf or set the +M4 environment variable to its path name. +)m4exit(2)]) + +undefine([eval]) +undefine([include]) +undefine([shift]) +undefine([format]) + + +dnl ### Defining macros + + +dnl m4 output diversions. We let m4 output them all in order at the end, +dnl except that we explicitly undivert AC_DIVERSION_SED, AC_DIVERSION_CMDS, +dnl and AC_DIVERSION_ICMDS. + +dnl AC_DIVERSION_NOTICE - 1 (= 0) AC_REQUIRE'd #! /bin/sh line +define(AC_DIVERSION_NOTICE, 1)dnl copyright notice & option help strings +define(AC_DIVERSION_INIT, 2)dnl initialization code +define(AC_DIVERSION_NORMAL_4, 3)dnl AC_REQUIRE'd code, 4 level deep +define(AC_DIVERSION_NORMAL_3, 4)dnl AC_REQUIRE'd code, 3 level deep +define(AC_DIVERSION_NORMAL_2, 5)dnl AC_REQUIRE'd code, 2 level deep +define(AC_DIVERSION_NORMAL_1, 6)dnl AC_REQUIRE'd code, 1 level deep +define(AC_DIVERSION_NORMAL, 7)dnl the tests and output code +define(AC_DIVERSION_SED, 8)dnl variable substitutions in config.status +define(AC_DIVERSION_CMDS, 9)dnl extra shell commands in config.status +define(AC_DIVERSION_ICMDS, 10)dnl extra initialization in config.status + +dnl Change the diversion stream to STREAM, while stacking old values. +dnl AC_DIVERT_PUSH(STREAM) +define(AC_DIVERT_PUSH, +[pushdef([AC_DIVERSION_CURRENT], $1)dnl +divert(AC_DIVERSION_CURRENT)dnl +]) + +dnl Change the diversion stream to its previous value, unstacking it. +dnl AC_DIVERT_POP() +define(AC_DIVERT_POP, +[popdef([AC_DIVERSION_CURRENT])dnl +divert(AC_DIVERSION_CURRENT)dnl +]) + +dnl Initialize the diversion setup. +define([AC_DIVERSION_CURRENT], AC_DIVERSION_NORMAL) +dnl This will be popped by AC_REQUIRE in AC_INIT. +pushdef([AC_DIVERSION_CURRENT], AC_DIVERSION_NOTICE) + +dnl The prologue for Autoconf macros. +dnl AC_PRO(MACRO-NAME) +define(AC_PRO, +[define([AC_PROVIDE_$1], )dnl +ifelse(AC_DIVERSION_CURRENT, AC_DIVERSION_NORMAL, +[AC_DIVERT_PUSH(builtin(eval, AC_DIVERSION_CURRENT - 1))], +[pushdef([AC_DIVERSION_CURRENT], AC_DIVERSION_CURRENT)])dnl +]) + +dnl The Epilogue for Autoconf macros. +dnl AC_EPI() +define(AC_EPI, +[AC_DIVERT_POP()dnl +ifelse(AC_DIVERSION_CURRENT, AC_DIVERSION_NORMAL, +[undivert(AC_DIVERSION_NORMAL_4)dnl +undivert(AC_DIVERSION_NORMAL_3)dnl +undivert(AC_DIVERSION_NORMAL_2)dnl +undivert(AC_DIVERSION_NORMAL_1)dnl +])dnl +]) + +dnl Define a macro which automatically provides itself. Add machinery +dnl so the macro automatically switches expansion to the diversion +dnl stack if it is not already using it. In this case, once finished, +dnl it will bring back all the code accumulated in the diversion stack. +dnl This, combined with AC_REQUIRE, achieves the topological ordering of +dnl macros. We don't use this macro to define some frequently called +dnl macros that are not involved in ordering constraints, to save m4 +dnl processing. +dnl AC_DEFUN(NAME, EXPANSION) +define([AC_DEFUN], +[define($1, [AC_PRO([$1])$2[]AC_EPI()])]) + + +dnl ### Initialization + + +dnl AC_INIT_NOTICE() +AC_DEFUN(AC_INIT_NOTICE, +[# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version] AC_ACVERSION [ +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +[#] Any additions from configure.in:]) + +dnl AC_PREFIX_DEFAULT(PREFIX) +AC_DEFUN(AC_PREFIX_DEFAULT, +[AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl +ac_default_prefix=$1 +AC_DIVERT_POP()]) + +dnl AC_INIT_PARSE_ARGS() +AC_DEFUN(AC_INIT_PARSE_ARGS, +[ +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +dnl Installation directory options. +dnl These are left unexpanded so users can "make install exec_prefix=/foo" +dnl and all the variables that are supposed to be based on exec_prefix +dnl by default will actually change. +dnl Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in +changequote(, )dnl + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; +changequote([, ])dnl + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_feature: invalid feature name) + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_feature: invalid feature name) + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +changequote(, )dnl +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +changequote([, ])dnl +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version AC_ACVERSION" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_package: invalid package name) + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_package: invalid package name) + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) AC_MSG_ERROR([$ac_option: invalid option; use --help to show usage]) + ;; + + *) +changequote(, )dnl + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then +changequote([, ])dnl + AC_MSG_WARN($ac_option: invalid host type) + fi + if test "x$nonopt" != xNONE; then + AC_MSG_ERROR(can only configure for one host and one target at a time) + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + AC_MSG_ERROR(missing argument to --`echo $ac_prev | sed 's/_/-/g'`) +fi +]) + +dnl Try to have only one #! line, so the script doesn't look funny +dnl for users of AC_REVISION. +dnl AC_INIT_BINSH() +AC_DEFUN(AC_INIT_BINSH, +[#! /bin/sh +]) + +dnl AC_INIT(UNIQUE-FILE-IN-SOURCE-DIR) +AC_DEFUN(AC_INIT, +[sinclude(acsite.m4)dnl +sinclude(./aclocal.m4)dnl +AC_REQUIRE([AC_INIT_BINSH])dnl +AC_INIT_NOTICE +AC_DIVERT_POP()dnl to NORMAL +AC_DIVERT_PUSH(AC_DIVERSION_INIT)dnl +AC_INIT_PARSE_ARGS +AC_INIT_PREPARE($1)dnl +AC_DIVERT_POP()dnl to NORMAL +]) + +dnl AC_INIT_PREPARE(UNIQUE-FILE-IN-SOURCE-DIR) +AC_DEFUN(AC_INIT_PREPARE, +[trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +define(AC_FD_MSG, 6)dnl +[#] AC_FD_MSG checking for... messages and results +define(AC_FD_CC, 5)dnl +[#] AC_FD_CC compiler messages saved in config.log +if test "$silent" = yes; then + exec AC_FD_MSG>/dev/null +else + exec AC_FD_MSG>&1 +fi +exec AC_FD_CC>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&AC_FD_CC + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; +changequote(<<, >>)dnl +dnl If you change this globbing pattern, test it on an old shell -- +dnl it's sensitive. Putting any kind of quote in it causes syntax errors. + *" "*|*" "*|*[\[\]\~\<<#>>\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; +changequote([, ])dnl + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=$1 + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=[$]0 +changequote(, )dnl + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` +changequote([, ])dnl + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + AC_MSG_ERROR(can not find sources in $ac_confdir or ..) + else + AC_MSG_ERROR(can not find sources in $srcdir) + fi +fi +dnl Double slashes in pathnames in object file debugging info +dnl mess up M-x gdb in Emacs. +changequote(, )dnl +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` +changequote([, ])dnl + +dnl Let the site file select an alternate cache file if it wants to. +AC_SITE_LOAD +AC_CACHE_LOAD +AC_LANG_C +dnl By default always use an empty string as the executable +dnl extension. Only change it if the script calls AC_EXEEXT. +ac_exeext= +dnl By default assume that objects files use an extension of .o. Only +dnl change it if the script calls AC_OBJEXT. +ac_objext=o +AC_PROG_ECHO_N +dnl Substitute for predefined variables. +AC_SUBST(SHELL)dnl +AC_SUBST(CFLAGS)dnl +AC_SUBST(CPPFLAGS)dnl +AC_SUBST(CXXFLAGS)dnl +AC_SUBST(FFLAGS)dnl +AC_SUBST(DEFS)dnl +AC_SUBST(LDFLAGS)dnl +AC_SUBST(LIBS)dnl +AC_SUBST(exec_prefix)dnl +AC_SUBST(prefix)dnl +AC_SUBST(program_transform_name)dnl +dnl Installation directory options. +AC_SUBST(bindir)dnl +AC_SUBST(sbindir)dnl +AC_SUBST(libexecdir)dnl +AC_SUBST(datadir)dnl +AC_SUBST(sysconfdir)dnl +AC_SUBST(sharedstatedir)dnl +AC_SUBST(localstatedir)dnl +AC_SUBST(libdir)dnl +AC_SUBST(includedir)dnl +AC_SUBST(oldincludedir)dnl +AC_SUBST(infodir)dnl +AC_SUBST(mandir)dnl +]) + + +dnl ### Selecting optional features + + +dnl AC_ARG_ENABLE(FEATURE, HELP-STRING, ACTION-IF-TRUE [, ACTION-IF-FALSE]) +AC_DEFUN(AC_ARG_ENABLE, +[AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl +ac_help="$ac_help +[$2]" +AC_DIVERT_POP()dnl +[#] Check whether --enable-[$1] or --disable-[$1] was given. +if test "[${enable_]patsubst([$1], -, _)+set}" = set; then + enableval="[$enable_]patsubst([$1], -, _)" + ifelse([$3], , :, [$3]) +ifelse([$4], , , [else + $4 +])dnl +fi +]) + +AC_DEFUN(AC_ENABLE, +[AC_OBSOLETE([$0], [; instead use AC_ARG_ENABLE])dnl +AC_ARG_ENABLE([$1], [ --enable-$1], [$2], [$3])dnl +]) + + +dnl ### Working with optional software + + +dnl AC_ARG_WITH(PACKAGE, HELP-STRING, ACTION-IF-TRUE [, ACTION-IF-FALSE]) +AC_DEFUN(AC_ARG_WITH, +[AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl +ac_help="$ac_help +[$2]" +AC_DIVERT_POP()dnl +[#] Check whether --with-[$1] or --without-[$1] was given. +if test "[${with_]patsubst([$1], -, _)+set}" = set; then + withval="[$with_]patsubst([$1], -, _)" + ifelse([$3], , :, [$3]) +ifelse([$4], , , [else + $4 +])dnl +fi +]) + +AC_DEFUN(AC_WITH, +[AC_OBSOLETE([$0], [; instead use AC_ARG_WITH])dnl +AC_ARG_WITH([$1], [ --with-$1], [$2], [$3])dnl +]) + + +dnl ### Transforming program names. + + +dnl AC_ARG_PROGRAM() +AC_DEFUN(AC_ARG_PROGRAM, +[if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," +]) + + +dnl ### Version numbers + + +dnl AC_REVISION(REVISION-INFO) +AC_DEFUN(AC_REVISION, +[AC_REQUIRE([AC_INIT_BINSH])dnl +[# From configure.in] translit([$1], $")]) + +dnl Subroutines of AC_PREREQ. + +dnl Change the dots in NUMBER into commas. +dnl AC_PREREQ_SPLIT(NUMBER) +define(AC_PREREQ_SPLIT, +[translit($1, ., [, ])]) + +dnl Default the ternary version number to 0 (e.g., 1, 7 -> 1, 7, 0). +dnl AC_PREREQ_CANON(MAJOR, MINOR [,TERNARY]) +define(AC_PREREQ_CANON, +[$1, $2, ifelse([$3], , 0, [$3])]) + +dnl Complain and exit if version number 1 is less than version number 2. +dnl PRINTABLE2 is the printable version of version number 2. +dnl AC_PREREQ_COMPARE(MAJOR1, MINOR1, TERNARY1, MAJOR2, MINOR2, TERNARY2, +dnl PRINTABLE2) +define(AC_PREREQ_COMPARE, +[ifelse(builtin([eval], +[$3 + $2 * 1000 + $1 * 1000000 < $6 + $5 * 1000 + $4 * 1000000]), 1, +[errprint(dnl +FATAL ERROR: Autoconf version $7 or higher is required for this script +)m4exit(3)])]) + +dnl Complain and exit if the Autoconf version is less than VERSION. +dnl AC_PREREQ(VERSION) +define(AC_PREREQ, +[AC_PREREQ_COMPARE(AC_PREREQ_CANON(AC_PREREQ_SPLIT(AC_ACVERSION)), +AC_PREREQ_CANON(AC_PREREQ_SPLIT([$1])), [$1])]) + + +dnl ### Getting the canonical system type + + +dnl Find install-sh, config.sub, config.guess, and Cygnus configure +dnl in directory DIR. These are auxiliary files used in configuration. +dnl DIR can be either absolute or relative to $srcdir. +dnl AC_CONFIG_AUX_DIR(DIR) +AC_DEFUN(AC_CONFIG_AUX_DIR, +[AC_CONFIG_AUX_DIRS($1 $srcdir/$1)]) + +dnl The default is `$srcdir' or `$srcdir/..' or `$srcdir/../..'. +dnl There's no need to call this macro explicitly; just AC_REQUIRE it. +AC_DEFUN(AC_CONFIG_AUX_DIR_DEFAULT, +[AC_CONFIG_AUX_DIRS($srcdir $srcdir/.. $srcdir/../..)]) + +dnl Internal subroutine. +dnl Search for the configuration auxiliary files in directory list $1. +dnl We look only for install-sh, so users of AC_PROG_INSTALL +dnl do not automatically need to distribute the other auxiliary files. +dnl AC_CONFIG_AUX_DIRS(DIR ...) +AC_DEFUN(AC_CONFIG_AUX_DIRS, +[ac_aux_dir= +for ac_dir in $1; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + AC_MSG_ERROR([can not find install-sh or install.sh in $1]) +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. +AC_PROVIDE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +]) + +dnl Canonicalize the host, target, and build system types. +AC_DEFUN(AC_CANONICAL_SYSTEM, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [AC_ARG_PROGRAM]) +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) AC_MSG_ERROR(can only configure for one host and one target at a time) ;; +esac + +AC_CANONICAL_HOST +AC_CANONICAL_TARGET +AC_CANONICAL_BUILD +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- +]) + +dnl Subroutines of AC_CANONICAL_SYSTEM. + +AC_DEFUN(AC_CANONICAL_HOST, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else AC_MSG_ERROR(can not run $ac_config_sub) +fi + +AC_MSG_CHECKING(host system type) + +dnl Set host_alias. +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else AC_MSG_ERROR(can not guess host type; you must specify one) + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +dnl Set the other host vars. +changequote(<<, >>)dnl +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +changequote([, ])dnl +AC_MSG_RESULT($host) +AC_SUBST(host)dnl +AC_SUBST(host_alias)dnl +AC_SUBST(host_cpu)dnl +AC_SUBST(host_vendor)dnl +AC_SUBST(host_os)dnl +]) + +dnl Internal use only. +AC_DEFUN(AC_CANONICAL_TARGET, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_MSG_CHECKING(target system type) + +dnl Set target_alias. +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +dnl Set the other target vars. +changequote(<<, >>)dnl +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +changequote([, ])dnl +AC_MSG_RESULT($target) +AC_SUBST(target)dnl +AC_SUBST(target_alias)dnl +AC_SUBST(target_cpu)dnl +AC_SUBST(target_vendor)dnl +AC_SUBST(target_os)dnl +]) + +dnl Internal use only. +AC_DEFUN(AC_CANONICAL_BUILD, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_MSG_CHECKING(build system type) + +dnl Set build_alias. +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +dnl Set the other build vars. +changequote(<<, >>)dnl +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +changequote([, ])dnl +AC_MSG_RESULT($build) +AC_SUBST(build)dnl +AC_SUBST(build_alias)dnl +AC_SUBST(build_cpu)dnl +AC_SUBST(build_vendor)dnl +AC_SUBST(build_os)dnl +]) + + +dnl AC_VALIDATE_CACHED_SYSTEM_TUPLE[(cmd)] +dnl if the cache file is inconsistent with the current host, +dnl target and build system types, execute CMD or print a default +dnl error message. +AC_DEFUN(AC_VALIDATE_CACHED_SYSTEM_TUPLE, [ + AC_REQUIRE([AC_CANONICAL_SYSTEM]) + AC_MSG_CHECKING([cached system tuple]) + if { test x"${ac_cv_host_system_type+set}" = x"set" && + test x"$ac_cv_host_system_type" != x"$host"; } || + { test x"${ac_cv_build_system_type+set}" = x"set" && + test x"$ac_cv_build_system_type" != x"$build"; } || + { test x"${ac_cv_target_system_type+set}" = x"set" && + test x"$ac_cv_target_system_type" != x"$target"; }; then + AC_MSG_RESULT([different]) + ifelse($#, 1, [$1], + [AC_MSG_ERROR([remove config.cache and re-run configure])]) + else + AC_MSG_RESULT(ok) + fi + ac_cv_host_system_type="$host" + ac_cv_build_system_type="$build" + ac_cv_target_system_type="$target" +]) + + +dnl ### Caching test results + + +dnl Look for site or system specific initialization scripts. +dnl AC_SITE_LOAD() +define(AC_SITE_LOAD, +[# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done +]) + +dnl AC_CACHE_LOAD() +define(AC_CACHE_LOAD, +[if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi +]) + +dnl AC_CACHE_SAVE() +define(AC_CACHE_SAVE, +[cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +dnl Allow a site initialization script to override cache values. +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +changequote(, )dnl +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +changequote([, ])dnl +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache +]) + +dnl The name of shell var CACHE-ID must contain `_cv_' in order to get saved. +dnl AC_CACHE_VAL(CACHE-ID, COMMANDS-TO-SET-IT) +define(AC_CACHE_VAL, +[dnl We used to use the below line, but it fails if the 1st arg is a +dnl shell variable, so we need the eval. +dnl if test "${$1+set}" = set; then +dnl the '' avoids an AIX 4.1 sh bug ("invalid expansion"). +if eval "test \"`echo '$''{'$1'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&AC_FD_MSG +else + $2 +fi +]) + +dnl AC_CACHE_CHECK(MESSAGE, CACHE-ID, COMMANDS) +define(AC_CACHE_CHECK, +[AC_MSG_CHECKING([$1]) +AC_CACHE_VAL([$2], [$3]) +AC_MSG_RESULT([$]$2)]) + + +dnl ### Defining symbols + + +dnl Set VARIABLE to VALUE, verbatim, or 1. +dnl AC_DEFINE(VARIABLE [, VALUE]) +define(AC_DEFINE, +[cat >> confdefs.h <<\EOF +[#define] $1 ifelse($#, 2, [$2], $#, 3, [$2], 1) +EOF +]) + +dnl Similar, but perform shell substitutions $ ` \ once on VALUE. +define(AC_DEFINE_UNQUOTED, +[cat >> confdefs.h <&AC_FD_MSG +echo "configure:__oline__: checking $1" >&AC_FD_CC]) + +dnl AC_CHECKING(FEATURE-DESCRIPTION) +define(AC_CHECKING, +[echo "checking $1" 1>&AC_FD_MSG +echo "configure:__oline__: checking $1" >&AC_FD_CC]) + +dnl AC_MSG_RESULT(RESULT-DESCRIPTION) +define(AC_MSG_RESULT, +[echo "$ac_t""$1" 1>&AC_FD_MSG]) + +dnl AC_VERBOSE(RESULT-DESCRIPTION) +define(AC_VERBOSE, +[AC_OBSOLETE([$0], [; instead use AC_MSG_RESULT])dnl +echo " $1" 1>&AC_FD_MSG]) + +dnl AC_MSG_WARN(PROBLEM-DESCRIPTION) +define(AC_MSG_WARN, +[echo "configure: warning: $1" 1>&2]) + +dnl AC_MSG_ERROR(ERROR-DESCRIPTION) +define(AC_MSG_ERROR, +[{ echo "configure: error: $1" 1>&2; exit 1; }]) + + +dnl ### Selecting which language to use for testing + + +dnl AC_LANG_C() +AC_DEFUN(AC_LANG_C, +[define([AC_LANG], [C])dnl +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&AC_FD_CC' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +cross_compiling=$ac_cv_prog_cc_cross +]) + +dnl AC_LANG_CPLUSPLUS() +AC_DEFUN(AC_LANG_CPLUSPLUS, +[define([AC_LANG], [CPLUSPLUS])dnl +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&AC_FD_CC' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +cross_compiling=$ac_cv_prog_cxx_cross +]) + +dnl AC_LANG_FORTRAN77() +AC_DEFUN(AC_LANG_FORTRAN77, +[define([AC_LANG], [FORTRAN77])dnl +ac_ext=f +ac_compile='${F77-f77} -c $FFLAGS conftest.$ac_ext 1>&AC_FD_CC' +ac_link='${F77-f77} -o conftest${ac_exeext} $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +cross_compiling=$ac_cv_prog_f77_cross +]) + +dnl Push the current language on a stack. +dnl AC_LANG_SAVE() +define(AC_LANG_SAVE, +[pushdef([AC_LANG_STACK], AC_LANG)]) + +dnl Restore the current language from the stack. +dnl AC_LANG_RESTORE() +pushdef([AC_LANG_RESTORE], +[ifelse(AC_LANG_STACK, [C], [AC_LANG_C],dnl +AC_LANG_STACK, [CPLUSPLUS], [AC_LANG_CPLUSPLUS],dnl +AC_LANG_STACK, [FORTRAN77], [AC_LANG_FORTRAN77])[]popdef([AC_LANG_STACK])]) + + +dnl ### Compiler-running mechanics + + +dnl The purpose of this macro is to "configure:123: command line" +dnl written into config.log for every test run. +dnl AC_TRY_EVAL(VARIABLE) +AC_DEFUN(AC_TRY_EVAL, +[{ (eval echo configure:__oline__: \"[$]$1\") 1>&AC_FD_CC; dnl +(eval [$]$1) 2>&AC_FD_CC; }]) + +dnl AC_TRY_COMMAND(COMMAND) +AC_DEFUN(AC_TRY_COMMAND, +[{ ac_try='$1'; AC_TRY_EVAL(ac_try); }]) + + +dnl ### Dependencies between macros + + +dnl AC_BEFORE(THIS-MACRO-NAME, CALLED-MACRO-NAME) +define(AC_BEFORE, +[ifdef([AC_PROVIDE_$2], [errprint(__file__:__line__: [$2 was called before $1 +])])]) + +dnl AC_REQUIRE(MACRO-NAME) +define(AC_REQUIRE, +[ifdef([AC_PROVIDE_$1], , +[AC_DIVERT_PUSH(builtin(eval, AC_DIVERSION_CURRENT - 1))dnl +indir([$1]) +AC_DIVERT_POP()dnl +])]) + +dnl AC_PROVIDE(MACRO-NAME) +define(AC_PROVIDE, +[define([AC_PROVIDE_$1], )]) + +dnl AC_OBSOLETE(THIS-MACRO-NAME [, SUGGESTION]) +define(AC_OBSOLETE, +[errprint(__file__:__line__: warning: [$1] is obsolete[$2] +)]) + + +dnl ### Checking for programs + + +dnl AC_CHECK_PROG(VARIABLE, PROG-TO-CHECK-FOR, VALUE-IF-FOUND +dnl [, [VALUE-IF-NOT-FOUND] [, [PATH] [, [REJECT]]]]) +AC_DEFUN(AC_CHECK_PROG, +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_prog_$1, +[if test -n "[$]$1"; then + ac_cv_prog_$1="[$]$1" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +ifelse([$6], , , [ ac_prog_rejected=no +])dnl +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$5], , $PATH, [$5])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then +ifelse([$6], , , dnl +[ if test "[$ac_dir/$ac_word]" = "$6"; then + ac_prog_rejected=yes + continue + fi +])dnl + ac_cv_prog_$1="$3" + break + fi + done + IFS="$ac_save_ifs" +ifelse([$6], , , [if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy [$]ac_cv_prog_$1 + shift + if test [$]# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set $1 to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "[$]@" + shift + ac_cv_prog_$1="[$]@" +ifelse([$2], [$4], dnl +[ else + # Default is a loser. + AC_MSG_ERROR([$1=$6 unacceptable, but no other $4 found in dnl +ifelse([$5], , [\$]PATH, [$5])]) +])dnl + fi +fi +])dnl +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_CHECK_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_prog_$1" && ac_cv_prog_$1="$4" +])dnl +fi])dnl +$1="$ac_cv_prog_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +dnl AC_PATH_PROG(VARIABLE, PROG-TO-CHECK-FOR [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN(AC_PATH_PROG, +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$4], , $PATH, [$4])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" +dnl If no 3rd arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$3], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$3" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +dnl AC_CHECK_PROGS(VARIABLE, PROGS-TO-CHECK-FOR [, VALUE-IF-NOT-FOUND +dnl [, PATH]]) +AC_DEFUN(AC_CHECK_PROGS, +[for ac_prog in $2 +do +AC_CHECK_PROG($1, [$]ac_prog, [$]ac_prog, , $4) +test -n "[$]$1" && break +done +ifelse([$3], , , [test -n "[$]$1" || $1="$3" +])]) + +dnl AC_PATH_PROGS(VARIABLE, PROGS-TO-CHECK-FOR [, VALUE-IF-NOT-FOUND +dnl [, PATH]]) +AC_DEFUN(AC_PATH_PROGS, +[for ac_prog in $2 +do +AC_PATH_PROG($1, [$]ac_prog, , $4) +test -n "[$]$1" && break +done +ifelse([$3], , , [test -n "[$]$1" || $1="$3" +])]) + +dnl Internal subroutine. +AC_DEFUN(AC_CHECK_TOOL_PREFIX, +[AC_REQUIRE([AC_CANONICAL_HOST])AC_REQUIRE([AC_CANONICAL_BUILD])dnl +if test $host != $build; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi +]) + +dnl AC_CHECK_TOOL(VARIABLE, PROG-TO-CHECK-FOR[, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN(AC_CHECK_TOOL, +[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl +AC_CHECK_PROG($1, ${ac_tool_prefix}$2, ${ac_tool_prefix}$2, + ifelse([$3], , [$2], ), $4) +ifelse([$3], , , [ +if test -z "$ac_cv_prog_$1"; then +if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG($1, $2, $2, $3) +else + $1="$3" +fi +fi]) +]) + +dnl Guess the value for the `prefix' variable by looking for +dnl the argument program along PATH and taking its parent. +dnl Example: if the argument is `gcc' and we find /usr/local/gnu/bin/gcc, +dnl set `prefix' to /usr/local/gnu. +dnl This comes too late to find a site file based on the prefix, +dnl and it might use a cached value for the path. +dnl No big loss, I think, since most configures don't use this macro anyway. +dnl AC_PREFIX_PROGRAM(PROGRAM) +AC_DEFUN(AC_PREFIX_PROGRAM, +[if test "x$prefix" = xNONE; then +changequote(<<, >>)dnl +define(<>, translit($1, [a-z], [A-Z]))dnl +changequote([, ])dnl +dnl We reimplement AC_MSG_CHECKING (mostly) to avoid the ... in the middle. +echo $ac_n "checking for prefix by $ac_c" 1>&AC_FD_MSG +AC_PATH_PROG(AC_VAR_NAME, $1) +changequote(<<, >>)dnl + if test -n "$ac_cv_path_<<>>AC_VAR_NAME"; then + prefix=`echo $ac_cv_path_<<>>AC_VAR_NAME|sed 's%/[^/][^/]*//*[^/][^/]*$%%'` +changequote([, ])dnl + fi +fi +undefine([AC_VAR_NAME])dnl +]) + +dnl Try to compile, link and execute TEST-PROGRAM. Set WORKING-VAR to +dnl `yes' if the current compiler works, otherwise set it ti `no'. Set +dnl CROSS-VAR to `yes' if the compiler and linker produce non-native +dnl executables, otherwise set it to `no'. Before calling +dnl `AC_TRY_COMPILER()', call `AC_LANG_*' to set-up for the right +dnl language. +dnl +dnl AC_TRY_COMPILER(TEST-PROGRAM, WORKING-VAR, CROSS-VAR) +AC_DEFUN(AC_TRY_COMPILER, +[cat > conftest.$ac_ext << EOF +ifelse(AC_LANG, [FORTRAN77], , +[ +[#]line __oline__ "configure" +#include "confdefs.h" +]) +[$1] +EOF +if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + [$2]=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + [$3]=no + else + [$3]=yes + fi +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC + [$2]=no +fi +rm -fr conftest*]) + + +dnl ### Checking for libraries + + +dnl AC_TRY_LINK_FUNC(func, action-if-found, action-if-not-found) +dnl Try to link a program that calls FUNC, handling GCC builtins. If +dnl the link succeeds, execute ACTION-IF-FOUND; otherwise, execute +dnl ACTION-IF-NOT-FOUND. + +AC_DEFUN(AC_TRY_LINK_FUNC, +AC_TRY_LINK(dnl +ifelse([$1], [main], , dnl Avoid conflicting decl of main. +[/* Override any gcc2 internal prototype to avoid an error. */ +]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus +extern "C" +#endif +])dnl +[/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $1(); +]), +[$1()], +[$2], +[$3])) + + +dnl AC_SEARCH_LIBS(FUNCTION, SEARCH-LIBS [, ACTION-IF-FOUND +dnl [, ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]]) +dnl Search for a library defining FUNC, if it's not already available. + +AC_DEFUN(AC_SEARCH_LIBS, +[AC_PREREQ([2.13]) +AC_CACHE_CHECK([for library containing $1], [ac_cv_search_$1], +[ac_func_search_save_LIBS="$LIBS" +ac_cv_search_$1="no" +AC_TRY_LINK_FUNC([$1], [ac_cv_search_$1="none required"]) +test "$ac_cv_search_$1" = "no" && for i in $2; do +LIBS="-l$i $5 $ac_func_search_save_LIBS" +AC_TRY_LINK_FUNC([$1], +[ac_cv_search_$1="-l$i" +break]) +done +LIBS="$ac_func_search_save_LIBS"]) +if test "$ac_cv_search_$1" != "no"; then + test "$ac_cv_search_$1" = "none required" || LIBS="$ac_cv_search_$1 $LIBS" + $3 +else : + $4 +fi]) + + + +dnl AC_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND +dnl [, OTHER-LIBRARIES]]]) +AC_DEFUN(AC_CHECK_LIB, +[AC_MSG_CHECKING([for $2 in -l$1]) +dnl Use a cache variable name containing both the library and function name, +dnl because the test really is for library $1 defining function $2, not +dnl just for library $1. Separate tests with the same $1 and different $2s +dnl may have different results. +ac_lib_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` +AC_CACHE_VAL(ac_cv_lib_$ac_lib_var, +[ac_save_LIBS="$LIBS" +LIBS="-l$1 $5 $LIBS" +AC_TRY_LINK(dnl +ifelse(AC_LANG, [FORTRAN77], , +ifelse([$2], [main], , dnl Avoid conflicting decl of main. +[/* Override any gcc2 internal prototype to avoid an error. */ +]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus +extern "C" +#endif +])dnl +[/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $2(); +])), + [$2()], + eval "ac_cv_lib_$ac_lib_var=yes", + eval "ac_cv_lib_$ac_lib_var=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$3], , +[changequote(, )dnl + ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_lib) + LIBS="-l$1 $LIBS" +], [$3]) +else + AC_MSG_RESULT(no) +ifelse([$4], , , [$4 +])dnl +fi +]) + +dnl AC_HAVE_LIBRARY(LIBRARY, [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND +dnl [, OTHER-LIBRARIES]]]) +AC_DEFUN(AC_HAVE_LIBRARY, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_LIB])dnl +changequote(<<, >>)dnl +define(<>, dnl +patsubst(patsubst($1, <>, <<\1>>), <<-l>>, <<>>))dnl +define(<>, ac_cv_lib_<<>>AC_LIB_NAME)dnl +changequote([, ])dnl +AC_MSG_CHECKING([for -l[]AC_LIB_NAME]) +AC_CACHE_VAL(AC_CV_NAME, +[ac_save_LIBS="$LIBS" +LIBS="-l[]AC_LIB_NAME[] $4 $LIBS" +AC_TRY_LINK( , [main()], AC_CV_NAME=yes, AC_CV_NAME=no) +LIBS="$ac_save_LIBS" +])dnl +AC_MSG_RESULT($AC_CV_NAME) +if test "$AC_CV_NAME" = yes; then + ifelse([$2], , +[AC_DEFINE([HAVE_LIB]translit(AC_LIB_NAME, [a-z], [A-Z])) + LIBS="-l[]AC_LIB_NAME[] $LIBS" +], [$2]) +ifelse([$3], , , [else + $3 +])dnl +fi +undefine([AC_LIB_NAME])dnl +undefine([AC_CV_NAME])dnl +]) + + +dnl ### Examining declarations + + +dnl AC_TRY_CPP(INCLUDES, [ACTION-IF-TRUE [, ACTION-IF-FALSE]]) +AC_DEFUN(AC_TRY_CPP, +[AC_REQUIRE_CPP()dnl +cat > conftest.$ac_ext <&AC_FD_CC + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +ifelse([$3], , , [ rm -rf conftest* + $3 +])dnl +fi +rm -f conftest*]) + +dnl AC_EGREP_HEADER(PATTERN, HEADER-FILE, ACTION-IF-FOUND [, +dnl ACTION-IF-NOT-FOUND]) +AC_DEFUN(AC_EGREP_HEADER, +[AC_EGREP_CPP([$1], [#include <$2>], [$3], [$4])]) + +dnl Because this macro is used by AC_PROG_GCC_TRADITIONAL, which must +dnl come early, it is not included in AC_BEFORE checks. +dnl AC_EGREP_CPP(PATTERN, PROGRAM, [ACTION-IF-FOUND [, +dnl ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_EGREP_CPP, +[AC_REQUIRE_CPP()dnl +cat > conftest.$ac_ext <&AC_FD_CC | +dnl Prevent m4 from eating character classes: +changequote(, )dnl + egrep "$1" >/dev/null 2>&1; then +changequote([, ])dnl + ifelse([$3], , :, [rm -rf conftest* + $3]) +ifelse([$4], , , [else + rm -rf conftest* + $4 +])dnl +fi +rm -f conftest* +]) + + +dnl ### Examining syntax + + +dnl AC_TRY_COMPILE(INCLUDES, FUNCTION-BODY, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_TRY_COMPILE, +[cat > conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +ifelse([$4], , , [ rm -rf conftest* + $4 +])dnl +fi +rm -f conftest*]) + + +dnl ### Examining libraries + + +dnl AC_COMPILE_CHECK(ECHO-TEXT, INCLUDES, FUNCTION-BODY, +dnl ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +AC_DEFUN(AC_COMPILE_CHECK, +[AC_OBSOLETE([$0], [; instead use AC_TRY_COMPILE or AC_TRY_LINK, and AC_MSG_CHECKING and AC_MSG_RESULT])dnl +ifelse([$1], , , [AC_CHECKING([for $1]) +])dnl +AC_TRY_LINK([$2], [$3], [$4], [$5]) +]) + +dnl AC_TRY_LINK(INCLUDES, FUNCTION-BODY, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_TRY_LINK, +[cat > conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +ifelse([$4], , , [ rm -rf conftest* + $4 +])dnl +fi +rm -f conftest*]) + + +dnl ### Checking for run-time features + + +dnl AC_TRY_RUN(PROGRAM, [ACTION-IF-TRUE [, ACTION-IF-FALSE +dnl [, ACTION-IF-CROSS-COMPILING]]]) +AC_DEFUN(AC_TRY_RUN, +[if test "$cross_compiling" = yes; then + ifelse([$4], , + [errprint(__file__:__line__: warning: [AC_TRY_RUN] called without default to allow cross compiling +)dnl + AC_MSG_ERROR(can not run test program while cross compiling)], + [$4]) +else + AC_TRY_RUN_NATIVE([$1], [$2], [$3]) +fi +]) + +dnl Like AC_TRY_RUN but assumes a native-environment (non-cross) compiler. +dnl AC_TRY_RUN_NATIVE(PROGRAM, [ACTION-IF-TRUE [, ACTION-IF-FALSE]]) +AC_DEFUN(AC_TRY_RUN_NATIVE, +[cat > conftest.$ac_ext </dev/null +then +dnl Don't remove the temporary files here, so they can be examined. + ifelse([$2], , :, [$2]) +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +ifelse([$3], , , [ rm -fr conftest* + $3 +])dnl +fi +rm -fr conftest*]) + + +dnl ### Checking for header files + + +dnl AC_CHECK_HEADER(HEADER-FILE, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_HEADER, +[dnl Do the transliteration at runtime so arg 1 can be a shell variable. +ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(ac_cv_header_$ac_safe, +[AC_TRY_CPP([#include <$1>], eval "ac_cv_header_$ac_safe=yes", + eval "ac_cv_header_$ac_safe=no")])dnl +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) +ifelse([$3], , , [$3 +])dnl +fi +]) + +dnl AC_CHECK_HEADERS(HEADER-FILE... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_HEADERS, +[for ac_hdr in $1 +do +AC_CHECK_HEADER($ac_hdr, +[changequote(, )dnl + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_hdr) $2], $3)dnl +done +]) + + +dnl ### Checking for the existence of files + +dnl AC_CHECK_FILE(FILE, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_FILE, +[AC_REQUIRE([AC_PROG_CC]) +dnl Do the transliteration at runtime so arg 1 can be a shell variable. +ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(ac_cv_file_$ac_safe, +[if test "$cross_compiling" = yes; then + errprint(__file__:__line__: warning: Cannot check for file existence when cross compiling +)dnl + AC_MSG_ERROR(Cannot check for file existence when cross compiling) +else + if test -r $1; then + eval "ac_cv_file_$ac_safe=yes" + else + eval "ac_cv_file_$ac_safe=no" + fi +fi])dnl +if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) +ifelse([$3], , , [$3]) +fi +]) + +dnl AC_CHECK_FILES(FILE... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_FILES, +[for ac_file in $1 +do +AC_CHECK_FILE($ac_file, +[changequote(, )dnl + ac_tr_file=HAVE_`echo $ac_file | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_file) $2], $3)dnl +done +]) + + +dnl ### Checking for library functions + + +dnl AC_CHECK_FUNC(FUNCTION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_FUNC, +[AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(ac_cv_func_$1, +[AC_TRY_LINK( +dnl Don't include because on OSF/1 3.0 it includes +dnl which includes which contains a prototype for +dnl select. Similarly for bzero. +[/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $1(); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus +extern "C" +#endif +])dnl +[/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $1(); +], [ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$1) || defined (__stub___$1) +choke me +#else +$1(); +#endif +], eval "ac_cv_func_$1=yes", eval "ac_cv_func_$1=no")]) +if eval "test \"`echo '$ac_cv_func_'$1`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) +ifelse([$3], , , [$3 +])dnl +fi +]) + +dnl AC_CHECK_FUNCS(FUNCTION... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_FUNCS, +[for ac_func in $1 +do +AC_CHECK_FUNC($ac_func, +[changequote(, )dnl + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_func) $2], $3)dnl +done +]) + +dnl AC_REPLACE_FUNCS(FUNCTION...) +AC_DEFUN(AC_REPLACE_FUNCS, +[AC_CHECK_FUNCS([$1], , [LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"]) +AC_SUBST(LIBOBJS)dnl +]) + + +dnl ### Checking compiler characteristics + + +dnl AC_CHECK_SIZEOF(TYPE [, CROSS-SIZE]) +AC_DEFUN(AC_CHECK_SIZEOF, +[changequote(<<, >>)dnl +dnl The name to #define. +define(<>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl +dnl The cache variable name. +define(<>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl +changequote([, ])dnl +AC_MSG_CHECKING(size of $1) +AC_CACHE_VAL(AC_CV_NAME, +[AC_TRY_RUN([#include +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof($1)); + exit(0); +}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$2], , , AC_CV_NAME=$2))])dnl +AC_MSG_RESULT($AC_CV_NAME) +AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME) +undefine([AC_TYPE_NAME])dnl +undefine([AC_CV_NAME])dnl +]) + + +dnl ### Checking for typedefs + + +dnl AC_CHECK_TYPE(TYPE, DEFAULT) +AC_DEFUN(AC_CHECK_TYPE, +[AC_REQUIRE([AC_HEADER_STDC])dnl +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(ac_cv_type_$1, +[AC_EGREP_CPP(dnl +changequote(<<,>>)dnl +<<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl +changequote([,]), [#include +#if STDC_HEADERS +#include +#include +#endif], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl +AC_MSG_RESULT($ac_cv_type_$1) +if test $ac_cv_type_$1 = no; then + AC_DEFINE($1, $2) +fi +]) + + +dnl ### Creating output files + + +dnl AC_CONFIG_HEADER(HEADER-TO-CREATE ...) +AC_DEFUN(AC_CONFIG_HEADER, +[define(AC_LIST_HEADER, $1)]) + +dnl Link each of the existing files SOURCE... to the corresponding +dnl link name in DEST... +dnl AC_LINK_FILES(SOURCE..., DEST...) +AC_DEFUN(AC_LINK_FILES, +[dnl +define([AC_LIST_FILES], ifdef([AC_LIST_FILES], [AC_LIST_FILES ],)[$1])dnl +define([AC_LIST_LINKS], ifdef([AC_LIST_LINKS], [AC_LIST_LINKS ],)[$2])]) + +dnl Add additional commands for AC_OUTPUT to put into config.status. +dnl Use diversions instead of macros so we can be robust in the +dnl presence of commas in $1 and/or $2. +dnl AC_OUTPUT_COMMANDS(EXTRA-CMDS, INIT-CMDS) +AC_DEFUN(AC_OUTPUT_COMMANDS, +[AC_DIVERT_PUSH(AC_DIVERSION_CMDS)dnl +[$1] +AC_DIVERT_POP()dnl +AC_DIVERT_PUSH(AC_DIVERSION_ICMDS)dnl +[$2] +AC_DIVERT_POP()]) + +dnl AC_CONFIG_SUBDIRS(DIR ...) +AC_DEFUN(AC_CONFIG_SUBDIRS, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +define([AC_LIST_SUBDIRS], ifdef([AC_LIST_SUBDIRS], [AC_LIST_SUBDIRS ],)[$1])dnl +subdirs="AC_LIST_SUBDIRS" +AC_SUBST(subdirs)dnl +]) + +dnl The big finish. +dnl Produce config.status, config.h, and links; and configure subdirs. +dnl AC_OUTPUT([FILE...] [, EXTRA-CMDS] [, INIT-CMDS]) +define(AC_OUTPUT, +[trap '' 1 2 15 +AC_CACHE_SAVE +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then +changequote(, )dnl + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +changequote([, ])dnl +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +ifdef([AC_LIST_HEADER], [DEFS=-DHAVE_CONFIG_H], [AC_OUTPUT_MAKE_DEFS()]) + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +[#] [$]0 [$]ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +changequote(, )dnl +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +changequote([, ])dnl +for ac_option +do + case "[\$]ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running [\$]{CONFIG_SHELL-/bin/sh} [$]0 [$]ac_configure_args --no-create --no-recursion" + exec [\$]{CONFIG_SHELL-/bin/sh} [$]0 [$]ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version AC_ACVERSION" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "[\$]ac_cs_usage"; exit 0 ;; + *) echo "[\$]ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ifdef([AC_PROVIDE_AC_PROG_INSTALL], [ac_given_INSTALL="$INSTALL" +])dnl + +changequote(<<, >>)dnl +ifdef(<>, +<>, +<>) +changequote([, ])dnl +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +undivert(AC_DIVERSION_CMDS)dnl +$2 +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 +dnl config.status should not do recursion. +ifdef([AC_LIST_SUBDIRS], [AC_OUTPUT_SUBDIRS(AC_LIST_SUBDIRS)])dnl +])dnl + +dnl Set the DEFS variable to the -D options determined earlier. +dnl This is a subroutine of AC_OUTPUT. +dnl It is called inside configure, outside of config.status. +dnl AC_OUTPUT_MAKE_DEFS() +define(AC_OUTPUT_MAKE_DEFS, +[# Transform confdefs.h into DEFS. +dnl Using a here document instead of a string reduces the quoting nightmare. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +changequote(<<, >>)dnl +s%<<#define>> \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~<<#>>$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +changequote([, ])dnl +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs +]) + +dnl Do the variable substitutions to create the Makefiles or whatever. +dnl This is a subroutine of AC_OUTPUT. It is called inside an unquoted +dnl here document whose contents are going into config.status, but +dnl upon returning, the here document is being quoted. +dnl AC_OUTPUT_FILES(FILE...) +define(AC_OUTPUT_FILES, +[# Protect against being on the right side of a sed subst in config.status. +changequote(, )dnl +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +changequote([, ])dnl +dnl These here document variables are unquoted when configure runs +dnl but quoted when config.status runs, so variables are expanded once. +$ac_vpsub +dnl Shell code in configure.in might set extrasub. +$extrasub +dnl Insert the sed substitutions of variables. +undivert(AC_DIVERSION_SED) +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then +changequote(, )dnl + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` +changequote([, ])dnl + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. +changequote(, )dnl + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` +changequote([, ])dnl + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + +ifdef([AC_PROVIDE_AC_PROG_INSTALL], +[ case "$ac_given_INSTALL" in +changequote(, )dnl + [/$]*) INSTALL="$ac_given_INSTALL" ;; +changequote([, ])dnl + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac +])dnl + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +ifdef([AC_PROVIDE_AC_PROG_INSTALL], [s%@INSTALL@%$INSTALL%g +])dnl +dnl The parens around the eval prevent an "illegal io" in Ultrix sh. +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +dnl This would break Makefile dependencies. +dnl if cmp -s $ac_file conftest.out 2>/dev/null; then +dnl echo "$ac_file is unchanged" +dnl rm -f conftest.out +dnl else +dnl rm -f $ac_file +dnl mv conftest.out $ac_file +dnl fi +fi; done +rm -f conftest.s* +]) + +dnl Create the config.h files from the config.h.in files. +dnl This is a subroutine of AC_OUTPUT. It is called inside a quoted +dnl here document whose contents are going into config.status. +dnl AC_OUTPUT_HEADER(HEADER-FILE...) +define(AC_OUTPUT_HEADER, +[changequote(<<, >>)dnl +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='<<$>>%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' +changequote([, ])dnl + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +dnl Support passing AC_CONFIG_HEADER a value containing shell variables. +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then +changequote(, )dnl + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac +changequote([, ])dnl + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +dnl Using a here document instead of a string reduces the quoting nightmare. +dnl Putting comments in sed scripts is not portable. +cat > conftest.hdr <<\EOF +changequote(<<, >>)dnl +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%<<#define>> \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +changequote([, ])dnl +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +changequote(, )dnl +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +changequote([, ])dnl +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +dnl Now back to your regularly scheduled config.status. +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + changequote(, )dnl + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + changequote([, ])dnl + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +]) + +dnl This is a subroutine of AC_OUTPUT. It is called inside a quoted +dnl here document whose contents are going into config.status. +dnl AC_OUTPUT_LINKS(SOURCE..., DEST...) +define(AC_OUTPUT_LINKS, +[EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +srcdir=$ac_given_srcdir +while test -n "$ac_sources"; do + set $ac_dests; ac_dest=[$]1; shift; ac_dests=[$]* + set $ac_sources; ac_source=[$]1; shift; ac_sources=[$]* + + echo "linking $srcdir/$ac_source to $ac_dest" + + if test ! -r $srcdir/$ac_source; then + AC_MSG_ERROR($srcdir/$ac_source: File not found) + fi + rm -f $ac_dest + + # Make relative symlinks. + # Remove last slash and all that follows it. Not all systems have dirname. +changequote(, )dnl + ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'` +changequote([, ])dnl + if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then + # The dest file is in a subdirectory. + test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir" + ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dest_dir_suffix. +changequote(, )dnl + ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'` +changequote([, ])dnl + else + ac_dest_dir_suffix= ac_dots= + fi + + case "$srcdir" in +changequote(, )dnl + [/$]*) ac_rel_source="$srcdir/$ac_source" ;; +changequote([, ])dnl + *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;; + esac + + # Make a symlink if possible; otherwise try a hard link. + if ln -s $ac_rel_source $ac_dest 2>/dev/null || + ln $srcdir/$ac_source $ac_dest; then : + else + AC_MSG_ERROR(can not link $ac_dest to $srcdir/$ac_source) + fi +done +]) + +dnl This is a subroutine of AC_OUTPUT. +dnl It is called after running config.status. +dnl AC_OUTPUT_SUBDIRS(DIRECTORY...) +define(AC_OUTPUT_SUBDIRS, +[ +if test "$no_recursion" != yes; then + + # Remove --cache-file and --srcdir arguments so they do not pile up. + ac_sub_configure_args= + ac_prev= + for ac_arg in $ac_configure_args; do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case "$ac_arg" in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;; + esac + done + + for ac_config_dir in $1; do + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + if test ! -d $srcdir/$ac_config_dir; then + continue + fi + + echo configuring in $ac_config_dir + + case "$srcdir" in + .) ;; + *) + if test -d ./$ac_config_dir || mkdir ./$ac_config_dir; then :; + else + AC_MSG_ERROR(can not create `pwd`/$ac_config_dir) + fi + ;; + esac + + ac_popdir=`pwd` + cd $ac_config_dir + +changequote(, )dnl + # A "../" for each directory in /$ac_config_dir. + ac_dots=`echo $ac_config_dir|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'` +changequote([, ])dnl + + case "$srcdir" in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + /*) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_config_dir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_config_dir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure; then + ac_sub_configure=$ac_sub_srcdir/configure + elif test -f $ac_sub_srcdir/configure.in; then + ac_sub_configure=$ac_configure + else + AC_MSG_WARN(no configuration information is in $ac_config_dir) + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + + # Make the cache file name correct relative to the subdirectory. + case "$cache_file" in + /*) ac_sub_cache_file=$cache_file ;; + *) # Relative path. + ac_sub_cache_file="$ac_dots$cache_file" ;; + esac +ifdef([AC_PROVIDE_AC_PROG_INSTALL], + [ case "$ac_given_INSTALL" in +changequote(, )dnl + [/$]*) INSTALL="$ac_given_INSTALL" ;; +changequote([, ])dnl + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac +])dnl + + echo "[running ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file] --srcdir=$ac_sub_srcdir" + # The eval makes quoting arguments work. + if eval ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir + then : + else + AC_MSG_ERROR($ac_sub_configure failed for $ac_config_dir) + fi + fi + + cd $ac_popdir + done +fi +]) diff --git a/build/autoconf/acoldnames.m4 b/build/autoconf/acoldnames.m4 new file mode 100644 index 0000000000..d31cdd754f --- /dev/null +++ b/build/autoconf/acoldnames.m4 @@ -0,0 +1,80 @@ +dnl Map old names of Autoconf macros to new regularized names. +dnl This file is part of Autoconf. +dnl Copyright (C) 1994 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl General macros. +dnl +define(AC_WARN, [indir([AC_MSG_WARN], $@)])dnl +define(AC_ERROR, [indir([AC_MSG_ERROR], $@)])dnl +AC_DEFUN(AC_PROGRAM_CHECK, [indir([AC_CHECK_PROG], $@)])dnl +AC_DEFUN(AC_PROGRAM_PATH, [indir([AC_PATH_PROG], $@)])dnl +AC_DEFUN(AC_PROGRAMS_CHECK, [indir([AC_CHECK_PROGS], $@)])dnl +AC_DEFUN(AC_PROGRAMS_PATH, [indir([AC_PATH_PROGS], $@)])dnl +AC_DEFUN(AC_PREFIX, [indir([AC_PREFIX_PROGRAM], $@)])dnl +AC_DEFUN(AC_HEADER_EGREP, [indir([AC_EGREP_HEADER], $@)])dnl +AC_DEFUN(AC_PROGRAM_EGREP, [indir([AC_EGREP_CPP], $@)])dnl +AC_DEFUN(AC_TEST_PROGRAM, [indir([AC_TRY_RUN], $@)])dnl +AC_DEFUN(AC_TEST_CPP, [indir([AC_TRY_CPP], $@)])dnl +AC_DEFUN(AC_HEADER_CHECK, [indir([AC_CHECK_HEADER], $@)])dnl +AC_DEFUN(AC_FUNC_CHECK, [indir([AC_CHECK_FUNC], $@)])dnl +AC_DEFUN(AC_HAVE_FUNCS, [indir([AC_CHECK_FUNCS], $@)])dnl +AC_DEFUN(AC_HAVE_HEADERS, [indir([AC_CHECK_HEADERS], $@)])dnl +AC_DEFUN(AC_SIZEOF_TYPE, [indir([AC_CHECK_SIZEOF], $@)])dnl +dnl +dnl Specific macros. +dnl +AC_DEFUN(AC_GCC_TRADITIONAL, [indir([AC_PROG_GCC_TRADITIONAL])])dnl +AC_DEFUN(AC_MINUS_C_MINUS_O, [indir([AC_PROG_CC_C_O])])dnl +AC_DEFUN(AC_SET_MAKE, [indir([AC_PROG_MAKE_SET])])dnl +AC_DEFUN(AC_YYTEXT_POINTER, [indir([AC_DECL_YYTEXT])])dnl +AC_DEFUN(AC_LN_S, [indir([AC_PROG_LN_S])])dnl +AC_DEFUN(AC_STDC_HEADERS, [indir([AC_HEADER_STDC])])dnl +AC_DEFUN(AC_MAJOR_HEADER, [indir([AC_HEADER_MAJOR])])dnl +AC_DEFUN(AC_STAT_MACROS_BROKEN, [indir([AC_HEADER_STAT])])dnl +AC_DEFUN(AC_SYS_SIGLIST_DECLARED, [indir([AC_DECL_SYS_SIGLIST])])dnl +AC_DEFUN(AC_GETGROUPS_T, [indir([AC_TYPE_GETGROUPS])])dnl +AC_DEFUN(AC_UID_T, [indir([AC_TYPE_UID_T])])dnl +AC_DEFUN(AC_SIZE_T, [indir([AC_TYPE_SIZE_T])])dnl +AC_DEFUN(AC_PID_T, [indir([AC_TYPE_PID_T])])dnl +AC_DEFUN(AC_OFF_T, [indir([AC_TYPE_OFF_T])])dnl +AC_DEFUN(AC_MODE_T, [indir([AC_TYPE_MODE_T])])dnl +AC_DEFUN(AC_RETSIGTYPE, [indir([AC_TYPE_SIGNAL])])dnl +AC_DEFUN(AC_MMAP, [indir([AC_FUNC_MMAP])])dnl +AC_DEFUN(AC_VPRINTF, [indir([AC_FUNC_VPRINTF])])dnl +AC_DEFUN(AC_VFORK, [indir([AC_FUNC_VFORK])])dnl +AC_DEFUN(AC_WAIT3, [indir([AC_FUNC_WAIT3])])dnl +AC_DEFUN(AC_ALLOCA, [indir([AC_FUNC_ALLOCA])])dnl +AC_DEFUN(AC_GETLOADAVG, [indir([AC_FUNC_GETLOADAVG])])dnl +AC_DEFUN(AC_UTIME_NULL, [indir([AC_FUNC_UTIME_NULL])])dnl +AC_DEFUN(AC_STRCOLL, [indir([AC_FUNC_STRCOLL])])dnl +AC_DEFUN(AC_SETVBUF_REVERSED, [indir([AC_FUNC_SETVBUF_REVERSED])])dnl +AC_DEFUN(AC_TIME_WITH_SYS_TIME, [indir([AC_HEADER_TIME])])dnl +AC_DEFUN(AC_TIMEZONE, [indir([AC_STRUCT_TIMEZONE])])dnl +AC_DEFUN(AC_ST_BLOCKS, [indir([AC_STRUCT_ST_BLOCKS])])dnl +AC_DEFUN(AC_ST_BLKSIZE, [indir([AC_STRUCT_ST_BLKSIZE])])dnl +AC_DEFUN(AC_ST_RDEV, [indir([AC_STRUCT_ST_RDEV])])dnl +AC_DEFUN(AC_CROSS_CHECK, [indir([AC_C_CROSS])])dnl +AC_DEFUN(AC_CHAR_UNSIGNED, [indir([AC_C_CHAR_UNSIGNED])])dnl +AC_DEFUN(AC_LONG_DOUBLE, [indir([AC_C_LONG_DOUBLE])])dnl +AC_DEFUN(AC_WORDS_BIGENDIAN, [indir([AC_C_BIGENDIAN])])dnl +AC_DEFUN(AC_INLINE, [indir([AC_C_INLINE])])dnl +AC_DEFUN(AC_CONST, [indir([AC_C_CONST])])dnl +AC_DEFUN(AC_LONG_FILE_NAMES, [indir([AC_SYS_LONG_FILE_NAMES])])dnl +AC_DEFUN(AC_RESTARTABLE_SYSCALLS, [indir([AC_SYS_RESTARTABLE_SYSCALLS])])dnl +AC_DEFUN(AC_FIND_X, [indir([AC_PATH_X])])dnl +AC_DEFUN(AC_FIND_XTRA, [indir([AC_PATH_XTRA])])dnl diff --git a/build/autoconf/acspecific.m4 b/build/autoconf/acspecific.m4 new file mode 100644 index 0000000000..73ae2109c0 --- /dev/null +++ b/build/autoconf/acspecific.m4 @@ -0,0 +1,2758 @@ +dnl Macros that test for specific features. +dnl This file is part of Autoconf. +dnl Copyright (C) 1992, 93, 94, 95, 96, 1998 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception, the Free Software Foundation gives unlimited +dnl permission to copy, distribute and modify the configure scripts that +dnl are the output of Autoconf. You need not follow the terms of the GNU +dnl General Public License when using or distributing such scripts, even +dnl though portions of the text of Autoconf appear in them. The GNU +dnl General Public License (GPL) does govern all other use of the material +dnl that constitutes the Autoconf program. +dnl +dnl Certain portions of the Autoconf source text are designed to be copied +dnl (in certain cases, depending on the input) into the output of +dnl Autoconf. We call these the "data" portions. The rest of the Autoconf +dnl source text consists of comments plus executable code that decides which +dnl of the data portions to output in any given case. We call these +dnl comments and executable code the "non-data" portions. Autoconf never +dnl copies any of the non-data portions into its output. +dnl +dnl This special exception to the GPL applies to versions of Autoconf +dnl released by the Free Software Foundation. When you make and +dnl distribute a modified version of Autoconf, you may extend this special +dnl exception to the GPL to apply to your modified version as well, *unless* +dnl your modified version has the potential to copy into its output some +dnl of the text that was the non-data portion of the version that you started +dnl with. (In other words, unless your change moves or copies text from +dnl the non-data portions to the data portions.) If your modification has +dnl such potential, you must delete any notice of this special exception +dnl to the GPL from your modified version. +dnl +dnl Written by David MacKenzie, with help from +dnl Franc,ois Pinard, Karl Berry, Richard Pixley, Ian Lance Taylor, +dnl Roland McGrath, Noah Friedman, david d zuhn, and many others. + + +dnl ### Checks for programs + + +dnl Check whether to use -n, \c, or newline-tab to separate +dnl checking messages from result messages. +dnl Idea borrowed from dist 3.0. +dnl Internal use only. +AC_DEFUN(AC_PROG_ECHO_N, +[if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi +]) + +AC_DEFUN(AC_PROG_CC, +[AC_BEFORE([$0], [AC_PROG_CPP])dnl +AC_CHECK_PROG(CC, gcc, gcc) +if test -z "$CC"; then + AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc) + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + AC_CHECK_PROG(CC, cl, cl) ;; + esac + fi + test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH]) +fi + +AC_PROG_CC_WORKS +AC_PROG_CC_GNU + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +dnl Check whether -g works, even if CFLAGS is set, in case the package +dnl plays around with CFLAGS (such as to build both debugging and +dnl normal versions of a library), tasteless as that idea is. +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +AC_PROG_CC_G +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +]) + +AC_DEFUN(AC_PROG_CXX, +[AC_BEFORE([$0], [AC_PROG_CXXCPP])dnl +AC_CHECK_PROGS(CXX, $CCC c++ g++ gcc CC cxx cc++ cl, gcc) + +AC_PROG_CXX_WORKS +AC_PROG_CXX_GNU + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +dnl Check whether -g works, even if CXXFLAGS is set, in case the package +dnl plays around with CXXFLAGS (such as to build both debugging and +dnl normal versions of a library), tasteless as that idea is. +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +AC_PROG_CXX_G +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +]) + +dnl Determine a Fortran 77 compiler to use. If `F77' is not already set +dnl in the environment, check for `g77', `f77' and `f2c', in that order. +dnl Set the output variable `F77' to the name of the compiler found. +dnl +dnl If using `g77' (the GNU Fortran 77 compiler), then `AC_PROG_F77' +dnl will set the shell variable `G77' to `yes', and empty otherwise. If +dnl the output variable `FFLAGS' was not already set in the environment, +dnl then set it to `-g -02' for `g77' (or `-O2' where `g77' does not +dnl accept `-g'). Otherwise, set `FFLAGS' to `-g' for all other Fortran +dnl 77 compilers. +dnl +dnl AC_PROG_F77() +AC_DEFUN(AC_PROG_F77, +[AC_BEFORE([$0], [AC_PROG_CPP])dnl +if test -z "$F77"; then + AC_CHECK_PROGS(F77, g77 f77 f2c) + test -z "$F77" && AC_MSG_ERROR([no acceptable Fortran 77 compiler found in \$PATH]) +fi + +AC_PROG_F77_WORKS +AC_PROG_F77_GNU + +if test $ac_cv_prog_g77 = yes; then + G77=yes +dnl Check whether -g works, even if FFLAGS is set, in case the package +dnl plays around with FFLAGS (such as to build both debugging and +dnl normal versions of a library), tasteless as that idea is. + ac_test_FFLAGS="${FFLAGS+set}" + ac_save_FFLAGS="$FFLAGS" + FFLAGS= + AC_PROG_F77_G + if test "$ac_test_FFLAGS" = set; then + FFLAGS="$ac_save_FFLAGS" + elif test $ac_cv_prog_f77_g = yes; then + FFLAGS="-g -O2" + else + FFLAGS="-O2" + fi +else + G77= + test "${FFLAGS+set}" = set || FFLAGS="-g" +fi +]) + +AC_DEFUN(AC_PROG_CC_WORKS, +[AC_MSG_CHECKING([whether the C compiler ($CC $CFLAGS $LDFLAGS) works]) +AC_LANG_SAVE +AC_LANG_C +AC_TRY_COMPILER([int main(){return(0);}], ac_cv_prog_cc_works, ac_cv_prog_cc_cross) +AC_LANG_RESTORE +AC_MSG_RESULT($ac_cv_prog_cc_works) +if test $ac_cv_prog_cc_works = no; then + AC_MSG_ERROR([installation or configuration problem: C compiler cannot create executables.]) +fi +AC_MSG_CHECKING([whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler]) +AC_MSG_RESULT($ac_cv_prog_cc_cross) +cross_compiling=$ac_cv_prog_cc_cross +]) + +AC_DEFUN(AC_PROG_CXX_WORKS, +[AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILER([int main(){return(0);}], ac_cv_prog_cxx_works, ac_cv_prog_cxx_cross) +AC_LANG_RESTORE +AC_MSG_RESULT($ac_cv_prog_cxx_works) +if test $ac_cv_prog_cxx_works = no; then + AC_MSG_ERROR([installation or configuration problem: C++ compiler cannot create executables.]) +fi +AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler]) +AC_MSG_RESULT($ac_cv_prog_cxx_cross) +cross_compiling=$ac_cv_prog_cxx_cross +]) + +dnl Test whether the Fortran 77 compiler can compile and link a trivial +dnl Fortran program. Also, test whether the Fortran 77 compiler is a +dnl cross-compiler (which may realistically be the case if the Fortran +dnl compiler is `g77'). +dnl +dnl AC_PROG_F77_WORKS() +AC_DEFUN(AC_PROG_F77_WORKS, +[AC_MSG_CHECKING([whether the Fortran 77 compiler ($F77 $FFLAGS $LDFLAGS) works]) +AC_LANG_SAVE +AC_LANG_FORTRAN77 +AC_TRY_COMPILER(dnl +[ program conftest + end +], ac_cv_prog_f77_works, ac_cv_prog_f77_cross) +AC_LANG_RESTORE +AC_MSG_RESULT($ac_cv_prog_f77_works) +if test $ac_cv_prog_f77_works = no; then + AC_MSG_ERROR([installation or configuration problem: Fortran 77 compiler cannot create executables.]) +fi +AC_MSG_CHECKING([whether the Fortran 77 compiler ($F77 $FFLAGS $LDFLAGS) is a cross-compiler]) +AC_MSG_RESULT($ac_cv_prog_f77_cross) +cross_compiling=$ac_cv_prog_f77_cross +]) + +AC_DEFUN(AC_PROG_CC_GNU, +[AC_CACHE_CHECK(whether we are using GNU C, ac_cv_prog_gcc, +[dnl The semicolon is to pacify NeXT's syntax-checking cpp. +cat > conftest.c </dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi])]) + +AC_DEFUN(AC_PROG_CXX_GNU, +[AC_CACHE_CHECK(whether we are using GNU C++, ac_cv_prog_gxx, +[dnl The semicolon is to pacify NeXT's syntax-checking cpp. +cat > conftest.C </dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi])]) + +dnl Test whether for Fortran 77 compiler is `g77' (the GNU Fortran 77 +dnl Compiler). This test depends on whether the Fortran 77 compiler can +dnl do CPP pre-processing. +dnl +dnl AC_PROG_F77_GNU() +AC_DEFUN(AC_PROG_F77_GNU, +[AC_CACHE_CHECK(whether we are using GNU Fortran 77, ac_cv_prog_g77, +[cat > conftest.fpp </dev/null 2>&1; then + ac_cv_prog_g77=yes +else + ac_cv_prog_g77=no +fi])]) + +AC_DEFUN(AC_PROG_CC_G, +[AC_CACHE_CHECK(whether ${CC-cc} accepts -g, ac_cv_prog_cc_g, +[echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* +])]) + +AC_DEFUN(AC_PROG_CXX_G, +[AC_CACHE_CHECK(whether ${CXX-g++} accepts -g, ac_cv_prog_cxx_g, +[echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* +])]) + +dnl Test whether the Fortran 77 compiler can accept the `-g' option to +dnl enable debugging. +dnl +dnl AC_PROG_F77_G() +AC_DEFUN(AC_PROG_F77_G, +[AC_CACHE_CHECK(whether $F77 accepts -g, ac_cv_prog_f77_g, +[cat > conftest.f << EOF + program conftest + end +EOF +if test -z "`$F77 -g -c conftest.f 2>&1`"; then + ac_cv_prog_f77_g=yes +else + ac_cv_prog_f77_g=no +fi +rm -f conftest* +])]) + +AC_DEFUN(AC_PROG_GCC_TRADITIONAL, +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +if test $ac_cv_prog_gcc = yes; then + AC_CACHE_CHECK(whether ${CC-cc} needs -traditional, + ac_cv_prog_gcc_traditional, +[ ac_pattern="Autoconf.*'x'" + AC_EGREP_CPP($ac_pattern, [#include +Autoconf TIOCGETP], + ac_cv_prog_gcc_traditional=yes, ac_cv_prog_gcc_traditional=no) + + if test $ac_cv_prog_gcc_traditional = no; then + AC_EGREP_CPP($ac_pattern, [#include +Autoconf TCGETA], + ac_cv_prog_gcc_traditional=yes) + fi]) + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi +]) + +AC_DEFUN(AC_PROG_CC_C_O, +[if test "x$CC" != xcc; then + AC_MSG_CHECKING(whether $CC and cc understand -c and -o together) +else + AC_MSG_CHECKING(whether cc understands -c and -o together) +fi +set dummy $CC; ac_cc="`echo [$]2 | +changequote(, )dnl + sed -e 's/[^a-zA-Z0-9_]/_/g' -e 's/^[0-9]/_/'`" +changequote([, ])dnl +AC_CACHE_VAL(ac_cv_prog_cc_${ac_cc}_c_o, +[echo 'foo(){}' > conftest.c +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='${CC-cc} -c conftest.c -o conftest.o 1>&AC_FD_CC' +if AC_TRY_EVAL(ac_try) && + test -f conftest.o && AC_TRY_EVAL(ac_try); +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if AC_TRY_COMMAND(cc -c conftest.c 1>&AC_FD_CC); then + ac_try='cc -c conftest.c -o conftest.o 1>&AC_FD_CC' + if AC_TRY_EVAL(ac_try) && + test -f conftest.o && AC_TRY_EVAL(ac_try); + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f conftest* +])dnl +if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = yes"; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) + AC_DEFINE(NO_MINUS_C_MINUS_O) +fi +]) + +dnl Test if the Fortran 77 compiler accepts the options `-c' and `-o' +dnl simultaneously, and define `F77_NO_MINUS_C_MINUS_O' if it does not. +dnl +dnl The usefulness of this macro is questionable, as I can't really see +dnl why anyone would use it. The only reason I include it is for +dnl completeness, since a similar test exists for the C compiler. +dnl +dnl AC_PROG_F77_C_O +AC_DEFUN(AC_PROG_F77_C_O, +[AC_BEFORE([$0], [AC_PROG_F77])dnl +AC_MSG_CHECKING(whether $F77 understand -c and -o together) +set dummy $F77; ac_f77="`echo [$]2 | +changequote(, )dnl +sed -e 's/[^a-zA-Z0-9_]/_/g' -e 's/^[0-9]/_/'`" +changequote([, ])dnl +AC_CACHE_VAL(ac_cv_prog_f77_${ac_f77}_c_o, +[cat > conftest.f << EOF + program conftest + end +EOF +# We do the `AC_TRY_EVAL' test twice because some compilers refuse to +# overwrite an existing `.o' file with `-o', although they will create +# one. +ac_try='$F77 $FFLAGS -c conftest.f -o conftest.o 1>&AC_FD_CC' +if AC_TRY_EVAL(ac_try) && test -f conftest.o && AC_TRY_EVAL(ac_try); then + eval ac_cv_prog_f77_${ac_f77}_c_o=yes +else + eval ac_cv_prog_f77_${ac_f77}_c_o=no +fi +rm -f conftest* +])dnl +if eval "test \"`echo '$ac_cv_prog_f77_'${ac_f77}_c_o`\" = yes"; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) + AC_DEFINE(F77_NO_MINUS_C_MINUS_O) +fi +]) + +dnl Define SET_MAKE to set ${MAKE} if make doesn't. +AC_DEFUN(AC_PROG_MAKE_SET, +[AC_MSG_CHECKING(whether ${MAKE-make} sets \${MAKE}) +set dummy ${MAKE-make}; ac_make=`echo "[$]2" | sed 'y%./+-%__p_%'` +AC_CACHE_VAL(ac_cv_prog_make_${ac_make}_set, +[cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +changequote(, )dnl +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +changequote([, ])dnl +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake])dnl +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + AC_MSG_RESULT(yes) + SET_MAKE= +else + AC_MSG_RESULT(no) + SET_MAKE="MAKE=${MAKE-make}" +fi +AC_SUBST([SET_MAKE])dnl +]) + +AC_DEFUN(AC_PROG_RANLIB, +[AC_CHECK_PROG(RANLIB, ranlib, ranlib, :)]) + +dnl Check for mawk first since it's generally faster. +AC_DEFUN(AC_PROG_AWK, +[AC_CHECK_PROGS(AWK, mawk gawk nawk awk, )]) + +AC_DEFUN(AC_PROG_YACC, +[AC_CHECK_PROGS(YACC, 'bison -y' byacc, yacc)]) + +AC_DEFUN(AC_PROG_CPP, +[AC_MSG_CHECKING(how to run the C preprocessor) +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +AC_CACHE_VAL(ac_cv_prog_CPP, +[ # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. +dnl Use a header file that comes with gcc, so configuring glibc +dnl with a fresh cross-compiler works. + AC_TRY_CPP([#include +Syntax Error], , + CPP="${CC-cc} -E -traditional-cpp" + AC_TRY_CPP([#include +Syntax Error], , + CPP="${CC-cc} -nologo -E" + AC_TRY_CPP([#include +Syntax Error], , CPP=/lib/cpp))) + ac_cv_prog_CPP="$CPP"])dnl + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +AC_MSG_RESULT($CPP) +AC_SUBST(CPP)dnl +]) + +AC_DEFUN(AC_PROG_CXXCPP, +[AC_MSG_CHECKING(how to run the C++ preprocessor) +if test -z "$CXXCPP"; then +AC_CACHE_VAL(ac_cv_prog_CXXCPP, +[AC_LANG_SAVE[]dnl +AC_LANG_CPLUSPLUS[]dnl + CXXCPP="${CXX-g++} -E" + AC_TRY_CPP([#include ], , CXXCPP=/lib/cpp) + ac_cv_prog_CXXCPP="$CXXCPP" +AC_LANG_RESTORE[]dnl +fi])dnl +CXXCPP="$ac_cv_prog_CXXCPP" +AC_MSG_RESULT($CXXCPP) +AC_SUBST(CXXCPP)dnl +]) + +dnl Require finding the C or C++ preprocessor, whichever is the +dnl current language. +AC_DEFUN(AC_REQUIRE_CPP, +[ifelse(AC_LANG, C, [AC_REQUIRE([AC_PROG_CPP])], [AC_REQUIRE([AC_PROG_CXXCPP])])]) + +AC_DEFUN(AC_PROG_LEX, +[AC_CHECK_PROG(LEX, flex, flex, lex) +if test -z "$LEXLIB" +then + case "$LEX" in + flex*) ac_lib=fl ;; + *) ac_lib=l ;; + esac + AC_CHECK_LIB($ac_lib, yywrap, LEXLIB="-l$ac_lib") +fi +AC_SUBST(LEXLIB)]) + +dnl Check if lex declares yytext as a char * by default, not a char[]. +undefine([AC_DECL_YYTEXT]) +AC_DEFUN(AC_DECL_YYTEXT, +[AC_REQUIRE_CPP()dnl +AC_REQUIRE([AC_PROG_LEX])dnl +AC_CACHE_CHECK(lex output file root, ac_cv_prog_lex_root, +[# The minimal lex program is just a single line: %%. But some broken lexes +# (Solaris, I think it was) want two %% lines, so accommodate them. +echo '%% +%%' | $LEX +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + AC_MSG_ERROR(cannot find output from $LEX; giving up) +fi]) +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root +AC_SUBST(LEX_OUTPUT_ROOT)dnl + +AC_CACHE_CHECK(whether yytext is a pointer, ac_cv_prog_lex_yytext_pointer, +[# POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c +ac_save_LIBS="$LIBS" +LIBS="$LIBS $LEXLIB" +AC_TRY_LINK(`cat $LEX_OUTPUT_ROOT.c`, , ac_cv_prog_lex_yytext_pointer=yes) +LIBS="$ac_save_LIBS" +rm -f "${LEX_OUTPUT_ROOT}.c" +]) +dnl +if test $ac_cv_prog_lex_yytext_pointer = yes; then + AC_DEFINE(YYTEXT_POINTER) +fi +]) + +AC_DEFUN(AC_PROG_INSTALL, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +AC_MSG_CHECKING(for a BSD compatible install) +if test -z "$INSTALL"; then +AC_CACHE_VAL(ac_cv_path_install, +[ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" +])dnl + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +dnl We do special magic for INSTALL instead of AC_SUBST, to get +dnl relative paths right. +AC_MSG_RESULT($INSTALL) + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' +AC_SUBST(INSTALL_PROGRAM)dnl + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' +AC_SUBST(INSTALL_SCRIPT)dnl + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' +AC_SUBST(INSTALL_DATA)dnl +]) + +AC_DEFUN(AC_PROG_LN_S, +[AC_MSG_CHECKING(whether ln -s works) +AC_CACHE_VAL(ac_cv_prog_LN_S, +[rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi])dnl +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_SUBST(LN_S)dnl +]) + +define(AC_RSH, +[errprint(__file__:__line__: [$0] has been removed; replace it with equivalent code +)m4exit(4)]) + + +dnl ### Checks for header files + + +AC_DEFUN(AC_HEADER_STDC, +[AC_REQUIRE_CPP()dnl +AC_CACHE_CHECK(for ANSI C header files, ac_cv_header_stdc, +[AC_TRY_CPP([#include +#include +#include +#include ], ac_cv_header_stdc=yes, ac_cv_header_stdc=no) + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +AC_EGREP_HEADER(memchr, string.h, , ac_cv_header_stdc=no) +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +AC_EGREP_HEADER(free, stdlib.h, , ac_cv_header_stdc=no) +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +AC_TRY_RUN([#include +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } +], , ac_cv_header_stdc=no, :) +fi]) +if test $ac_cv_header_stdc = yes; then + AC_DEFINE(STDC_HEADERS) +fi +]) + +AC_DEFUN(AC_UNISTD_H, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_HEADERS(unistd.h)])dnl +AC_CHECK_HEADER(unistd.h, AC_DEFINE(HAVE_UNISTD_H))]) + +AC_DEFUN(AC_USG, +[AC_OBSOLETE([$0], + [; instead use AC_CHECK_HEADERS(string.h) and HAVE_STRING_H])dnl +AC_MSG_CHECKING([for BSD string and memory functions]) +AC_TRY_LINK([#include ], [rindex(0, 0); bzero(0, 0);], + [AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no); AC_DEFINE(USG)])]) + + +dnl If memchr and the like aren't declared in , include . +dnl To avoid problems, don't check for gcc2 built-ins. +AC_DEFUN(AC_MEMORY_H, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_HEADERS(memory.h) and HAVE_MEMORY_H])dnl +AC_MSG_CHECKING(whether string.h declares mem functions) +AC_EGREP_HEADER(memchr, string.h, ac_found=yes, ac_found=no) +AC_MSG_RESULT($ac_found) +if test $ac_found = no; then + AC_CHECK_HEADER(memory.h, [AC_DEFINE(NEED_MEMORY_H)]) +fi +]) + +AC_DEFUN(AC_HEADER_MAJOR, +[AC_CACHE_CHECK(whether sys/types.h defines makedev, + ac_cv_header_sys_types_h_makedev, +[AC_TRY_LINK([#include ], [return makedev(0, 0);], + ac_cv_header_sys_types_h_makedev=yes, ac_cv_header_sys_types_h_makedev=no) +]) + +if test $ac_cv_header_sys_types_h_makedev = no; then +AC_CHECK_HEADER(sys/mkdev.h, [AC_DEFINE(MAJOR_IN_MKDEV)]) + + if test $ac_cv_header_sys_mkdev_h = no; then +AC_CHECK_HEADER(sys/sysmacros.h, [AC_DEFINE(MAJOR_IN_SYSMACROS)]) + fi +fi +]) + +AC_DEFUN(AC_HEADER_DIRENT, +[ac_header_dirent=no +AC_CHECK_HEADERS_DIRENT(dirent.h sys/ndir.h sys/dir.h ndir.h, + [ac_header_dirent=$ac_hdr; break]) +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +AC_CHECK_LIB(dir, opendir, LIBS="$LIBS -ldir") +else +AC_CHECK_LIB(x, opendir, LIBS="$LIBS -lx") +fi +]) + +dnl Like AC_CHECK_HEADER, except also make sure that HEADER-FILE +dnl defines the type `DIR'. dirent.h on NextStep 3.2 doesn't. +dnl AC_CHECK_HEADER_DIRENT(HEADER-FILE, ACTION-IF-FOUND) +AC_DEFUN(AC_CHECK_HEADER_DIRENT, +[ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` +AC_MSG_CHECKING([for $1 that defines DIR]) +AC_CACHE_VAL(ac_cv_header_dirent_$ac_safe, +[AC_TRY_COMPILE([#include +#include <$1>], [DIR *dirp = 0;], + eval "ac_cv_header_dirent_$ac_safe=yes", + eval "ac_cv_header_dirent_$ac_safe=no")])dnl +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + AC_MSG_RESULT(yes) + $2 +else + AC_MSG_RESULT(no) +fi +]) + +dnl Like AC_CHECK_HEADERS, except succeed only for a HEADER-FILE that +dnl defines `DIR'. +dnl AC_CHECK_HEADERS_DIRENT(HEADER-FILE... [, ACTION]) +define(AC_CHECK_HEADERS_DIRENT, +[for ac_hdr in $1 +do +AC_CHECK_HEADER_DIRENT($ac_hdr, +[changequote(, )dnl + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_hdr) $2])dnl +done]) + +AC_DEFUN(AC_DIR_HEADER, +[AC_OBSOLETE([$0], [; instead use AC_HEADER_DIRENT])dnl +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + AC_CHECK_HEADER_DIRENT($ac_hdr, [ac_header_dirent=$ac_hdr; break]) +done + +case "$ac_header_dirent" in +dirent.h) AC_DEFINE(DIRENT) ;; +sys/ndir.h) AC_DEFINE(SYSNDIR) ;; +sys/dir.h) AC_DEFINE(SYSDIR) ;; +ndir.h) AC_DEFINE(NDIR) ;; +esac + +AC_CACHE_CHECK(whether closedir returns void, ac_cv_func_closedir_void, +[AC_TRY_RUN([#include +#include <$ac_header_dirent> +int closedir(); main() { exit(closedir(opendir(".")) != 0); }], + ac_cv_func_closedir_void=no, ac_cv_func_closedir_void=yes, ac_cv_func_closedir_void=yes)]) +if test $ac_cv_func_closedir_void = yes; then + AC_DEFINE(VOID_CLOSEDIR) +fi +]) + +AC_DEFUN(AC_HEADER_STAT, +[AC_CACHE_CHECK(whether stat file-mode macros are broken, + ac_cv_header_stat_broken, +[AC_EGREP_CPP([You lose], [#include +#include + +#if defined(S_ISBLK) && defined(S_IFDIR) +# if S_ISBLK (S_IFDIR) +You lose. +# endif +#endif + +#if defined(S_ISBLK) && defined(S_IFCHR) +# if S_ISBLK (S_IFCHR) +You lose. +# endif +#endif + +#if defined(S_ISLNK) && defined(S_IFREG) +# if S_ISLNK (S_IFREG) +You lose. +# endif +#endif + +#if defined(S_ISSOCK) && defined(S_IFREG) +# if S_ISSOCK (S_IFREG) +You lose. +# endif +#endif +], ac_cv_header_stat_broken=yes, ac_cv_header_stat_broken=no)]) +if test $ac_cv_header_stat_broken = yes; then + AC_DEFINE(STAT_MACROS_BROKEN) +fi +]) + +AC_DEFUN(AC_DECL_SYS_SIGLIST, +[AC_CACHE_CHECK([for sys_siglist declaration in signal.h or unistd.h], + ac_cv_decl_sys_siglist, +[AC_TRY_COMPILE([#include +#include +/* NetBSD declares sys_siglist in unistd.h. */ +#ifdef HAVE_UNISTD_H +#include +#endif], [char *msg = *(sys_siglist + 1);], + ac_cv_decl_sys_siglist=yes, ac_cv_decl_sys_siglist=no)]) +if test $ac_cv_decl_sys_siglist = yes; then + AC_DEFINE(SYS_SIGLIST_DECLARED) +fi +]) + +AC_DEFUN(AC_HEADER_SYS_WAIT, +[AC_CACHE_CHECK([for sys/wait.h that is POSIX.1 compatible], + ac_cv_header_sys_wait_h, +[AC_TRY_COMPILE([#include +#include +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif], [int s; +wait (&s); +s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;], +ac_cv_header_sys_wait_h=yes, ac_cv_header_sys_wait_h=no)]) +if test $ac_cv_header_sys_wait_h = yes; then + AC_DEFINE(HAVE_SYS_WAIT_H) +fi +]) + + +dnl ### Checks for typedefs + + +AC_DEFUN(AC_TYPE_GETGROUPS, +[AC_REQUIRE([AC_TYPE_UID_T])dnl +AC_CACHE_CHECK(type of array argument to getgroups, ac_cv_type_getgroups, +[AC_TRY_RUN( +changequote(<<, >>)dnl +<< +/* Thanks to Mike Rendell for this test. */ +#include +#define NGID 256 +#undef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +main() +{ + gid_t gidset[NGID]; + int i, n; + union { gid_t gval; long lval; } val; + + val.lval = -1; + for (i = 0; i < NGID; i++) + gidset[i] = val.gval; + n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, + gidset); + /* Exit non-zero if getgroups seems to require an array of ints. This + happens when gid_t is short but getgroups modifies an array of ints. */ + exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0); +} +>>, +changequote([, ])dnl + ac_cv_type_getgroups=gid_t, ac_cv_type_getgroups=int, + ac_cv_type_getgroups=cross) +if test $ac_cv_type_getgroups = cross; then + dnl When we can't run the test program (we are cross compiling), presume + dnl that has either an accurate prototype for getgroups or none. + dnl Old systems without prototypes probably use int. + AC_EGREP_HEADER([getgroups.*int.*gid_t], unistd.h, + ac_cv_type_getgroups=gid_t, ac_cv_type_getgroups=int) +fi]) +AC_DEFINE_UNQUOTED(GETGROUPS_T, $ac_cv_type_getgroups) +]) + +AC_DEFUN(AC_TYPE_UID_T, +[AC_CACHE_CHECK(for uid_t in sys/types.h, ac_cv_type_uid_t, +[AC_EGREP_HEADER(uid_t, sys/types.h, + ac_cv_type_uid_t=yes, ac_cv_type_uid_t=no)]) +if test $ac_cv_type_uid_t = no; then + AC_DEFINE(uid_t, int) + AC_DEFINE(gid_t, int) +fi +]) + +AC_DEFUN(AC_TYPE_SIZE_T, +[AC_CHECK_TYPE(size_t, unsigned)]) + +AC_DEFUN(AC_TYPE_PID_T, +[AC_CHECK_TYPE(pid_t, int)]) + +AC_DEFUN(AC_TYPE_OFF_T, +[AC_CHECK_TYPE(off_t, long)]) + +AC_DEFUN(AC_TYPE_MODE_T, +[AC_CHECK_TYPE(mode_t, int)]) + +dnl Note that identifiers starting with SIG are reserved by ANSI C. +AC_DEFUN(AC_TYPE_SIGNAL, +[AC_CACHE_CHECK([return type of signal handlers], ac_cv_type_signal, +[AC_TRY_COMPILE([#include +#include +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif +], +[int i;], ac_cv_type_signal=void, ac_cv_type_signal=int)]) +AC_DEFINE_UNQUOTED(RETSIGTYPE, $ac_cv_type_signal) +]) + + +dnl ### Checks for functions + + +AC_DEFUN(AC_FUNC_CLOSEDIR_VOID, +[AC_REQUIRE([AC_HEADER_DIRENT])dnl +AC_CACHE_CHECK(whether closedir returns void, ac_cv_func_closedir_void, +[AC_TRY_RUN([#include +#include <$ac_header_dirent> +int closedir(); main() { exit(closedir(opendir(".")) != 0); }], + ac_cv_func_closedir_void=no, ac_cv_func_closedir_void=yes, ac_cv_func_closedir_void=yes)]) +if test $ac_cv_func_closedir_void = yes; then + AC_DEFINE(CLOSEDIR_VOID) +fi +]) + +AC_DEFUN(AC_FUNC_FNMATCH, +[AC_CACHE_CHECK(for working fnmatch, ac_cv_func_fnmatch_works, +# Some versions of Solaris or SCO have a broken fnmatch function. +# So we run a test program. If we are cross-compiling, take no chance. +# Thanks to John Oleynick and Franc,ois Pinard for this test. +[AC_TRY_RUN([main() { exit (fnmatch ("a*", "abc", 0) != 0); }], +ac_cv_func_fnmatch_works=yes, ac_cv_func_fnmatch_works=no, +ac_cv_func_fnmatch_works=no)]) +if test $ac_cv_func_fnmatch_works = yes; then + AC_DEFINE(HAVE_FNMATCH) +fi +]) + +AC_DEFUN(AC_FUNC_MMAP, +[AC_CHECK_HEADERS(unistd.h) +AC_CHECK_FUNCS(getpagesize) +AC_CACHE_CHECK(for working mmap, ac_cv_func_mmap_fixed_mapped, +[AC_TRY_RUN([ +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the filesystem buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propogated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ +#include +#include +#include + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef HAVE_UNISTD_H +# include +# endif + +/* Assume that all systems that can run configure have sys/param.h. */ +# ifndef HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +#ifdef __cplusplus +extern "C" { void *malloc(unsigned); } +#else +char *malloc(); +#endif + +int +main() +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize(); + + /* + * First, make a file with some known garbage in it. + */ + data = malloc(pagesize); + if (!data) + exit(1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand(); + umask(0); + fd = creat("conftestmmap", 0600); + if (fd < 0) + exit(1); + if (write(fd, data, pagesize) != pagesize) + exit(1); + close(fd); + + /* + * Next, try to mmap the file at a fixed address which + * already has something else allocated at it. If we can, + * also make sure that we see the same garbage. + */ + fd = open("conftestmmap", O_RDWR); + if (fd < 0) + exit(1); + data2 = malloc(2 * pagesize); + if (!data2) + exit(1); + data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit(1); + + /* + * Finally, make sure that changes to the mapped area + * do not percolate back to the file as seen by read(). + * (This is a bug on some variants of i386 svr4.0.) + */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = malloc(pagesize); + if (!data3) + exit(1); + if (read(fd, data3, pagesize) != pagesize) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit(1); + close(fd); + unlink("conftestmmap"); + exit(0); +} +], ac_cv_func_mmap_fixed_mapped=yes, ac_cv_func_mmap_fixed_mapped=no, +ac_cv_func_mmap_fixed_mapped=no)]) +if test $ac_cv_func_mmap_fixed_mapped = yes; then + AC_DEFINE(HAVE_MMAP) +fi +]) + +AC_DEFUN(AC_FUNC_GETPGRP, +[AC_CACHE_CHECK(whether getpgrp takes no argument, ac_cv_func_getpgrp_void, +[AC_TRY_RUN([ +/* + * If this system has a BSD-style getpgrp(), + * which takes a pid argument, exit unsuccessfully. + * + * Snarfed from Chet Ramey's bash pgrp.c test program + */ +#include +#include + +int pid; +int pg1, pg2, pg3, pg4; +int ng, np, s, child; + +main() +{ + pid = getpid(); + pg1 = getpgrp(0); + pg2 = getpgrp(); + pg3 = getpgrp(pid); + pg4 = getpgrp(1); + + /* + * If all of these values are the same, it's pretty sure that + * we're on a system that ignores getpgrp's first argument. + */ + if (pg2 == pg4 && pg1 == pg3 && pg2 == pg3) + exit(0); + + child = fork(); + if (child < 0) + exit(1); + else if (child == 0) { + np = getpid(); + /* + * If this is Sys V, this will not work; pgrp will be + * set to np because setpgrp just changes a pgrp to be + * the same as the pid. + */ + setpgrp(np, pg1); + ng = getpgrp(0); /* Same result for Sys V and BSD */ + if (ng == pg1) { + exit(1); + } else { + exit(0); + } + } else { + wait(&s); + exit(s>>8); + } +} +], ac_cv_func_getpgrp_void=yes, ac_cv_func_getpgrp_void=no, + AC_MSG_ERROR(cannot check getpgrp if cross compiling)) +]) +if test $ac_cv_func_getpgrp_void = yes; then + AC_DEFINE(GETPGRP_VOID) +fi +]) + +AC_DEFUN(AC_FUNC_SETPGRP, +[AC_CACHE_CHECK(whether setpgrp takes no argument, ac_cv_func_setpgrp_void, +AC_TRY_RUN([ +#ifdef HAVE_UNISTD_H +#include +#endif + +/* + * If this system has a BSD-style setpgrp, which takes arguments, exit + * successfully. + */ +main() +{ + if (setpgrp(1,1) == -1) + exit(0); + else + exit(1); +} +], ac_cv_func_setpgrp_void=no, ac_cv_func_setpgrp_void=yes, + AC_MSG_ERROR(cannot check setpgrp if cross compiling)) +) +if test $ac_cv_func_setpgrp_void = yes; then + AC_DEFINE(SETPGRP_VOID) +fi +]) + +AC_DEFUN(AC_FUNC_VPRINTF, +[AC_CHECK_FUNC(vprintf, AC_DEFINE(HAVE_VPRINTF)) +if test "$ac_cv_func_vprintf" != yes; then +AC_CHECK_FUNC(_doprnt, AC_DEFINE(HAVE_DOPRNT)) +fi +]) + +AC_DEFUN(AC_FUNC_VFORK, +[AC_REQUIRE([AC_TYPE_PID_T])dnl +AC_CHECK_HEADER(vfork.h, AC_DEFINE(HAVE_VFORK_H)) +AC_CACHE_CHECK(for working vfork, ac_cv_func_vfork_works, +[AC_TRY_RUN([/* Thanks to Paul Eggert for this test. */ +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_VFORK_H +#include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. + The compiler is told about this with #include , + but some compilers (e.g. gcc -O) don't grok . + Test for this by using a static variable whose address + is put into a register that is clobbered by the vfork. */ +static +#ifdef __cplusplus +sparc_address_test (int arg) +#else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} +main() { + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. + This test uses lots of local variables, at least + as many local variables as main has allocated so far + including compiler temporaries. 4 locals are enough for + gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. + A buggy compiler should reuse the register of parent + for one of the local variables, since it will think that + parent can't possibly be used any more in this routine. + Assigning to the local variable will thus munge parent + in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), + vfork doesn't separate parent from child file descriptors. + If the child closes a descriptor before it execs or exits, + this munges the parent's descriptor as well. + Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + exit( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +}], +ac_cv_func_vfork_works=yes, ac_cv_func_vfork_works=no, AC_CHECK_FUNC(vfork) +ac_cv_func_vfork_works=$ac_cv_func_vfork)]) +if test $ac_cv_func_vfork_works = no; then + AC_DEFINE(vfork, fork) +fi +]) + +AC_DEFUN(AC_FUNC_WAIT3, +[AC_CACHE_CHECK(for wait3 that fills in rusage, ac_cv_func_wait3_rusage, +[AC_TRY_RUN([#include +#include +#include +#include +/* HP-UX has wait3 but does not fill in rusage at all. */ +main() { + struct rusage r; + int i; + /* Use a field that we can force nonzero -- + voluntary context switches. + For systems like NeXT and OSF/1 that don't set it, + also use the system CPU time. And page faults (I/O) for Linux. */ + r.ru_nvcsw = 0; + r.ru_stime.tv_sec = 0; + r.ru_stime.tv_usec = 0; + r.ru_majflt = r.ru_minflt = 0; + switch (fork()) { + case 0: /* Child. */ + sleep(1); /* Give up the CPU. */ + _exit(0); + case -1: _exit(0); /* What can we do? */ + default: /* Parent. */ + wait3(&i, 0, &r); + sleep(2); /* Avoid "text file busy" from rm on fast HP-UX machines. */ + exit(r.ru_nvcsw == 0 && r.ru_majflt == 0 && r.ru_minflt == 0 + && r.ru_stime.tv_sec == 0 && r.ru_stime.tv_usec == 0); + } +}], ac_cv_func_wait3_rusage=yes, ac_cv_func_wait3_rusage=no, +ac_cv_func_wait3_rusage=no)]) +if test $ac_cv_func_wait3_rusage = yes; then + AC_DEFINE(HAVE_WAIT3) +fi +]) + +AC_DEFUN(AC_FUNC_ALLOCA, +[AC_REQUIRE_CPP()dnl Set CPP; we run AC_EGREP_CPP conditionally. +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +AC_CACHE_CHECK([for working alloca.h], ac_cv_header_alloca_h, +[AC_TRY_LINK([#include ], [char *p = alloca(2 * sizeof(int));], + ac_cv_header_alloca_h=yes, ac_cv_header_alloca_h=no)]) +if test $ac_cv_header_alloca_h = yes; then + AC_DEFINE(HAVE_ALLOCA_H) +fi + +AC_CACHE_CHECK([for alloca], ac_cv_func_alloca_works, +[AC_TRY_LINK([ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif +], [char *p = (char *) alloca(1);], + ac_cv_func_alloca_works=yes, ac_cv_func_alloca_works=no)]) +if test $ac_cv_func_alloca_works = yes; then + AC_DEFINE(HAVE_ALLOCA) +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.${ac_objext} + AC_DEFINE(C_ALLOCA) + +AC_CACHE_CHECK(whether alloca needs Cray hooks, ac_cv_os_cray, +[AC_EGREP_CPP(webecray, +[#if defined(CRAY) && ! defined(CRAY2) +webecray +#else +wenotbecray +#endif +], ac_cv_os_cray=yes, ac_cv_os_cray=no)]) +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + AC_CHECK_FUNC($ac_func, [AC_DEFINE_UNQUOTED(CRAY_STACKSEG_END, $ac_func) + break]) +done +fi + +AC_CACHE_CHECK(stack direction for C alloca, ac_cv_c_stack_direction, +[AC_TRY_RUN([find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +}], ac_cv_c_stack_direction=1, ac_cv_c_stack_direction=-1, + ac_cv_c_stack_direction=0)]) +AC_DEFINE_UNQUOTED(STACK_DIRECTION, $ac_cv_c_stack_direction) +fi +AC_SUBST(ALLOCA)dnl +]) + +AC_DEFUN(AC_FUNC_GETLOADAVG, +[ac_have_func=no # yes means we've found a way to get the load average. + +# Some systems with -lutil have (and need) -lkvm as well, some do not. +# On Solaris, -lkvm requires nlist from -lelf, so check that first +# to get the right answer into the cache. +AC_CHECK_LIB(elf, elf_begin, LIBS="-lelf $LIBS") +AC_CHECK_LIB(kvm, kvm_open, LIBS="-lkvm $LIBS") +# Check for the 4.4BSD definition of getloadavg. +AC_CHECK_LIB(util, getloadavg, + [LIBS="-lutil $LIBS" ac_have_func=yes ac_cv_func_getloadavg_setgid=yes]) + +if test $ac_have_func = no; then + # There is a commonly available library for RS/6000 AIX. + # Since it is not a standard part of AIX, it might be installed locally. + ac_getloadavg_LIBS="$LIBS"; LIBS="-L/usr/local/lib $LIBS" + AC_CHECK_LIB(getloadavg, getloadavg, + LIBS="-lgetloadavg $LIBS", LIBS="$ac_getloadavg_LIBS") +fi + +# Make sure it is really in the library, if we think we found it. +AC_REPLACE_FUNCS(getloadavg) + +if test $ac_cv_func_getloadavg = yes; then + AC_DEFINE(HAVE_GETLOADAVG) + ac_have_func=yes +else + # Figure out what our getloadavg.c needs. + ac_have_func=no + AC_CHECK_HEADER(sys/dg_sys_info.h, + [ac_have_func=yes; AC_DEFINE(DGUX) + AC_CHECK_LIB(dgc, dg_sys_info)]) + + # We cannot check for , because Solaris 2 does not use dwarf (it + # uses stabs), but it is still SVR4. We cannot check for because + # Irix 4.0.5F has the header but not the library. + if test $ac_have_func = no && test $ac_cv_lib_elf_elf_begin = yes; then + ac_have_func=yes; AC_DEFINE(SVR4) + fi + + if test $ac_have_func = no; then + AC_CHECK_HEADER(inq_stats/cpustats.h, + [ac_have_func=yes; AC_DEFINE(UMAX) + AC_DEFINE(UMAX4_3)]) + fi + + if test $ac_have_func = no; then + AC_CHECK_HEADER(sys/cpustats.h, + [ac_have_func=yes; AC_DEFINE(UMAX)]) + fi + + if test $ac_have_func = no; then + AC_CHECK_HEADERS(mach/mach.h) + fi + + AC_CHECK_HEADER(nlist.h, + [AC_DEFINE(NLIST_STRUCT) + AC_CACHE_CHECK([for n_un in struct nlist], ac_cv_struct_nlist_n_un, + [AC_TRY_COMPILE([#include ], + [struct nlist n; n.n_un.n_name = 0;], + ac_cv_struct_nlist_n_un=yes, ac_cv_struct_nlist_n_un=no)]) + if test $ac_cv_struct_nlist_n_un = yes; then + AC_DEFINE(NLIST_NAME_UNION) + fi + ])dnl +fi # Do not have getloadavg in system libraries. + +# Some definitions of getloadavg require that the program be installed setgid. +dnl FIXME Don't hardwire the path of getloadavg.c in the top-level directory. +AC_CACHE_CHECK(whether getloadavg requires setgid, + ac_cv_func_getloadavg_setgid, +[AC_EGREP_CPP([Yowza Am I SETGID yet], +[#include "$srcdir/getloadavg.c" +#ifdef LDAV_PRIVILEGED +Yowza Am I SETGID yet +#endif], + ac_cv_func_getloadavg_setgid=yes, ac_cv_func_getloadavg_setgid=no)]) +if test $ac_cv_func_getloadavg_setgid = yes; then + NEED_SETGID=true; AC_DEFINE(GETLOADAVG_PRIVILEGED) +else + NEED_SETGID=false +fi +AC_SUBST(NEED_SETGID)dnl + +if test $ac_cv_func_getloadavg_setgid = yes; then + AC_CACHE_CHECK(group of /dev/kmem, ac_cv_group_kmem, +[changequote(, )dnl + # On Solaris, /dev/kmem is a symlink. Get info on the real file. + ac_ls_output=`ls -lgL /dev/kmem 2>/dev/null` + # If we got an error (system does not support symlinks), try without -L. + test -z "$ac_ls_output" && ac_ls_output=`ls -lg /dev/kmem` + ac_cv_group_kmem=`echo $ac_ls_output \ + | sed -ne 's/[ ][ ]*/ /g; + s/^.[sSrwx-]* *[0-9]* *\([^0-9]*\) *.*/\1/; + / /s/.* //;p;'` +changequote([, ])dnl +]) + KMEM_GROUP=$ac_cv_group_kmem +fi +AC_SUBST(KMEM_GROUP)dnl +]) + +AC_DEFUN(AC_FUNC_UTIME_NULL, +[AC_CACHE_CHECK(whether utime accepts a null argument, ac_cv_func_utime_null, +[rm -f conftestdata; > conftestdata +# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. +AC_TRY_RUN([#include +#include +main() { +struct stat s, t; +exit(!(stat ("conftestdata", &s) == 0 && utime("conftestdata", (long *)0) == 0 +&& stat("conftestdata", &t) == 0 && t.st_mtime >= s.st_mtime +&& t.st_mtime - s.st_mtime < 120)); +}], ac_cv_func_utime_null=yes, ac_cv_func_utime_null=no, + ac_cv_func_utime_null=no) +rm -f core core.* *.core]) +if test $ac_cv_func_utime_null = yes; then + AC_DEFINE(HAVE_UTIME_NULL) +fi +]) + +AC_DEFUN(AC_FUNC_STRCOLL, +[AC_CACHE_CHECK(for working strcoll, ac_cv_func_strcoll_works, +[AC_TRY_RUN([#include +main () +{ + exit (strcoll ("abc", "def") >= 0 || + strcoll ("ABC", "DEF") >= 0 || + strcoll ("123", "456") >= 0); +}], ac_cv_func_strcoll_works=yes, ac_cv_func_strcoll_works=no, +ac_cv_func_strcoll_works=no)]) +if test $ac_cv_func_strcoll_works = yes; then + AC_DEFINE(HAVE_STRCOLL) +fi +]) + +AC_DEFUN(AC_FUNC_SETVBUF_REVERSED, +[AC_CACHE_CHECK(whether setvbuf arguments are reversed, + ac_cv_func_setvbuf_reversed, +[AC_TRY_RUN([#include +/* If setvbuf has the reversed format, exit 0. */ +main () { + /* This call has the arguments reversed. + A reversed system may check and see that the address of main + is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */ + if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0) + exit(1); + putc('\r', stdout); + exit(0); /* Non-reversed systems segv here. */ +}], ac_cv_func_setvbuf_reversed=yes, ac_cv_func_setvbuf_reversed=no) +rm -f core core.* *.core]) +if test $ac_cv_func_setvbuf_reversed = yes; then + AC_DEFINE(SETVBUF_REVERSED) +fi +]) + +AC_DEFUN(AC_FUNC_GETMNTENT, +[# getmntent is in -lsun on Irix 4, -lseq on Dynix/PTX, -lgen on Unixware. +AC_CHECK_LIB(sun, getmntent, LIBS="-lsun $LIBS", + [AC_CHECK_LIB(seq, getmntent, LIBS="-lseq $LIBS", + [AC_CHECK_LIB(gen, getmntent, LIBS="-lgen $LIBS")])]) +AC_CHECK_FUNC(getmntent, [AC_DEFINE(HAVE_GETMNTENT)])]) + +AC_DEFUN(AC_FUNC_STRFTIME, +[AC_CHECK_FUNC(strftime, [AC_DEFINE(HAVE_STRFTIME)], +[# strftime is in -lintl on SCO UNIX. +AC_CHECK_LIB(intl, strftime, +[AC_DEFINE(HAVE_STRFTIME) +LIBS="-lintl $LIBS"])])]) + +AC_DEFUN(AC_FUNC_MEMCMP, +[AC_CACHE_CHECK(for 8-bit clean memcmp, ac_cv_func_memcmp_clean, +[AC_TRY_RUN([ +main() +{ + char c0 = 0x40, c1 = 0x80, c2 = 0x81; + exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1); +} +], ac_cv_func_memcmp_clean=yes, ac_cv_func_memcmp_clean=no, +ac_cv_func_memcmp_clean=no)]) +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" +AC_SUBST(LIBOBJS)dnl +]) + +AC_DEFUN(AC_FUNC_SELECT_ARGTYPES, +[AC_MSG_CHECKING([types of arguments for select()]) + AC_CACHE_VAL(ac_cv_func_select_arg234,dnl + [AC_CACHE_VAL(ac_cv_func_select_arg1,dnl + [AC_CACHE_VAL(ac_cv_func_select_arg5,dnl + [for ac_cv_func_select_arg234 in 'fd_set *' 'int *' 'void *'; do + for ac_cv_func_select_arg1 in 'int' 'size_t' 'unsigned long' 'unsigned'; do + for ac_cv_func_select_arg5 in 'struct timeval *' 'const struct timeval *'; do + AC_TRY_COMPILE(dnl +[#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +extern select ($ac_cv_func_select_arg1,$ac_cv_func_select_arg234,$ac_cv_func_select_arg234,$ac_cv_func_select_arg234,$ac_cv_func_select_arg5);],,dnl + [ac_not_found=no ; break 3],ac_not_found=yes) + done + done + done + ])dnl AC_CACHE_VAL + ])dnl AC_CACHE_VAL + ])dnl AC_CACHE_VAL + if test "$ac_not_found" = yes; then + ac_cv_func_select_arg1=int + ac_cv_func_select_arg234='int *' + ac_cv_func_select_arg5='struct timeval *' + fi + AC_MSG_RESULT([$ac_cv_func_select_arg1,$ac_cv_func_select_arg234,$ac_cv_func_select_arg5]) + AC_DEFINE_UNQUOTED(SELECT_TYPE_ARG1,$ac_cv_func_select_arg1) + AC_DEFINE_UNQUOTED(SELECT_TYPE_ARG234,($ac_cv_func_select_arg234)) + AC_DEFINE_UNQUOTED(SELECT_TYPE_ARG5,($ac_cv_func_select_arg5)) +]) + + +dnl ### Checks for structure members + + +AC_DEFUN(AC_HEADER_TIME, +[AC_CACHE_CHECK([whether time.h and sys/time.h may both be included], + ac_cv_header_time, +[AC_TRY_COMPILE([#include +#include +#include ], +[struct tm *tp;], ac_cv_header_time=yes, ac_cv_header_time=no)]) +if test $ac_cv_header_time = yes; then + AC_DEFINE(TIME_WITH_SYS_TIME) +fi +]) + +AC_DEFUN(AC_STRUCT_TM, +[AC_CACHE_CHECK([whether struct tm is in sys/time.h or time.h], + ac_cv_struct_tm, +[AC_TRY_COMPILE([#include +#include ], +[struct tm *tp; tp->tm_sec;], + ac_cv_struct_tm=time.h, ac_cv_struct_tm=sys/time.h)]) +if test $ac_cv_struct_tm = sys/time.h; then + AC_DEFINE(TM_IN_SYS_TIME) +fi +]) + +AC_DEFUN(AC_STRUCT_TIMEZONE, +[AC_REQUIRE([AC_STRUCT_TM])dnl +AC_CACHE_CHECK([for tm_zone in struct tm], ac_cv_struct_tm_zone, +[AC_TRY_COMPILE([#include +#include <$ac_cv_struct_tm>], [struct tm tm; tm.tm_zone;], + ac_cv_struct_tm_zone=yes, ac_cv_struct_tm_zone=no)]) +if test "$ac_cv_struct_tm_zone" = yes; then + AC_DEFINE(HAVE_TM_ZONE) +else + AC_CACHE_CHECK(for tzname, ac_cv_var_tzname, +[AC_TRY_LINK( +changequote(<<, >>)dnl +<<#include +#ifndef tzname /* For SGI. */ +extern char *tzname[]; /* RS6000 and others reject char **tzname. */ +#endif>>, +changequote([, ])dnl +[atoi(*tzname);], ac_cv_var_tzname=yes, ac_cv_var_tzname=no)]) + if test $ac_cv_var_tzname = yes; then + AC_DEFINE(HAVE_TZNAME) + fi +fi +]) + +AC_DEFUN(AC_STRUCT_ST_BLOCKS, +[AC_CACHE_CHECK([for st_blocks in struct stat], ac_cv_struct_st_blocks, +[AC_TRY_COMPILE([#include +#include ], [struct stat s; s.st_blocks;], +ac_cv_struct_st_blocks=yes, ac_cv_struct_st_blocks=no)]) +if test $ac_cv_struct_st_blocks = yes; then + AC_DEFINE(HAVE_ST_BLOCKS) +else + LIBOBJS="$LIBOBJS fileblocks.${ac_objext}" +fi +AC_SUBST(LIBOBJS)dnl +]) + +AC_DEFUN(AC_STRUCT_ST_BLKSIZE, +[AC_CACHE_CHECK([for st_blksize in struct stat], ac_cv_struct_st_blksize, +[AC_TRY_COMPILE([#include +#include ], [struct stat s; s.st_blksize;], +ac_cv_struct_st_blksize=yes, ac_cv_struct_st_blksize=no)]) +if test $ac_cv_struct_st_blksize = yes; then + AC_DEFINE(HAVE_ST_BLKSIZE) +fi +]) + +AC_DEFUN(AC_STRUCT_ST_RDEV, +[AC_CACHE_CHECK([for st_rdev in struct stat], ac_cv_struct_st_rdev, +[AC_TRY_COMPILE([#include +#include ], [struct stat s; s.st_rdev;], +ac_cv_struct_st_rdev=yes, ac_cv_struct_st_rdev=no)]) +if test $ac_cv_struct_st_rdev = yes; then + AC_DEFINE(HAVE_ST_RDEV) +fi +]) + + +dnl ### Checks for compiler characteristics + + +AC_DEFUN(AC_C_CROSS, +[AC_OBSOLETE([$0], [; it has been merged into AC_PROG_CC])]) + +AC_DEFUN(AC_C_CHAR_UNSIGNED, +[AC_CACHE_CHECK(whether char is unsigned, ac_cv_c_char_unsigned, +[if test "$GCC" = yes; then + # GCC predefines this symbol on systems where it applies. +AC_EGREP_CPP(yes, +[#ifdef __CHAR_UNSIGNED__ + yes +#endif +], ac_cv_c_char_unsigned=yes, ac_cv_c_char_unsigned=no) +else +AC_TRY_RUN( +[/* volatile prevents gcc2 from optimizing the test away on sparcs. */ +#if !defined(__STDC__) || __STDC__ != 1 +#define volatile +#endif +main() { + volatile char c = 255; exit(c < 0); +}], ac_cv_c_char_unsigned=yes, ac_cv_c_char_unsigned=no) +fi]) +if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then + AC_DEFINE(__CHAR_UNSIGNED__) +fi +]) + +AC_DEFUN(AC_C_LONG_DOUBLE, +[AC_CACHE_CHECK(for long double, ac_cv_c_long_double, +[if test "$GCC" = yes; then + ac_cv_c_long_double=yes +else +AC_TRY_RUN([int main() { +/* The Stardent Vistra knows sizeof(long double), but does not support it. */ +long double foo = 0.0; +/* On Ultrix 4.3 cc, long double is 4 and double is 8. */ +exit(sizeof(long double) < sizeof(double)); }], +ac_cv_c_long_double=yes, ac_cv_c_long_double=no) +fi]) +if test $ac_cv_c_long_double = yes; then + AC_DEFINE(HAVE_LONG_DOUBLE) +fi +]) + +AC_DEFUN(AC_INT_16_BITS, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_SIZEOF(int)])dnl +AC_MSG_CHECKING(whether int is 16 bits) +AC_TRY_RUN([main() { exit(sizeof(int) != 2); }], + [AC_MSG_RESULT(yes) + AC_DEFINE(INT_16_BITS)], AC_MSG_RESULT(no)) +]) + +AC_DEFUN(AC_LONG_64_BITS, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_SIZEOF(long)])dnl +AC_MSG_CHECKING(whether long int is 64 bits) +AC_TRY_RUN([main() { exit(sizeof(long int) != 8); }], + [AC_MSG_RESULT(yes) + AC_DEFINE(LONG_64_BITS)], AC_MSG_RESULT(no)) +]) + +AC_DEFUN(AC_C_BIGENDIAN, +[AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian, +[ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +AC_TRY_COMPILE([#include +#include ], [ +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif], [# It does; now see whether it defined to BIG_ENDIAN or not. +AC_TRY_COMPILE([#include +#include ], [ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)]) +if test $ac_cv_c_bigendian = unknown; then +AC_TRY_RUN([main () { + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +}], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes) +fi]) +if test $ac_cv_c_bigendian = yes; then + AC_DEFINE(WORDS_BIGENDIAN) +fi +]) + +dnl Do nothing if the compiler accepts the inline keyword. +dnl Otherwise define inline to __inline__ or __inline if one of those work, +dnl otherwise define inline to be empty. +AC_DEFUN(AC_C_INLINE, +[AC_CACHE_CHECK([for inline], ac_cv_c_inline, +[ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + AC_TRY_COMPILE(, [} $ac_kw foo() {], [ac_cv_c_inline=$ac_kw; break]) +done +]) +case "$ac_cv_c_inline" in + inline | yes) ;; + no) AC_DEFINE(inline, ) ;; + *) AC_DEFINE_UNQUOTED(inline, $ac_cv_c_inline) ;; +esac +]) + +AC_DEFUN(AC_C_CONST, +[dnl This message is consistent in form with the other checking messages, +dnl and with the result message. +AC_CACHE_CHECK([for working const], ac_cv_c_const, +[AC_TRY_COMPILE(, +changequote(<<, >>)dnl +<< +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} +>>, +changequote([, ])dnl +ac_cv_c_const=yes, ac_cv_c_const=no)]) +if test $ac_cv_c_const = no; then + AC_DEFINE(const, ) +fi +]) + +AC_DEFUN(AC_C_STRINGIZE, [ +AC_REQUIRE([AC_PROG_CPP]) +AC_MSG_CHECKING([for preprocessor stringizing operator]) +AC_CACHE_VAL(ac_cv_c_stringize, +AC_EGREP_CPP([#teststring],[ +#define x(y) #y + +char *s = x(teststring); +], ac_cv_c_stringize=no, ac_cv_c_stringize=yes)) +if test "${ac_cv_c_stringize}" = yes +then + AC_DEFINE(HAVE_STRINGIZE) +fi +AC_MSG_RESULT([${ac_cv_c_stringize}]) +])dnl + +define(AC_ARG_ARRAY, +[errprint(__file__:__line__: [$0] has been removed; don't do unportable things with arguments +)m4exit(4)]) + +dnl Check the object extension used by the compiler: typically .o or +dnl .obj. If this is called, some other behaviour will change, +dnl determined by ac_objext. +AC_DEFUN(AC_OBJEXT, +[AC_MSG_CHECKING([for object suffix]) +AC_CACHE_VAL(ac_cv_objext, +[rm -f conftest* +echo 'int i = 1;' > conftest.$ac_ext +if AC_TRY_EVAL(ac_compile); then + for ac_file in conftest.*; do + case $ac_file in + *.c) ;; + *) ac_cv_objext=`echo $ac_file | sed -e s/conftest.//` ;; + esac + done +else + AC_MSG_ERROR([installation or configuration problem; compiler does not work]) +fi +rm -f conftest*]) +AC_MSG_RESULT($ac_cv_objext) +OBJEXT=$ac_cv_objext +ac_objext=$ac_cv_objext +AC_SUBST(OBJEXT)]) + +dnl Determine the linker flags (e.g. `-L' and `-l') for the Fortran 77 +dnl intrinsic and run-time libraries that are required to successfully +dnl link a Fortran 77 program or shared library. The output variable +dnl FLIBS is set to these flags. +dnl +dnl This macro is intended to be used in those situations when it is +dnl necessary to mix, e.g. C++ and Fortran 77, source code into a single +dnl program or shared library. +dnl +dnl For example, if object files from a C++ and Fortran 77 compiler must +dnl be linked together, then the C++ compiler/linker must be used for +dnl linking (since special C++-ish things need to happen at link time +dnl like calling global constructors, instantiating templates, enabling +dnl exception support, etc.). +dnl +dnl However, the Fortran 77 intrinsic and run-time libraries must be +dnl linked in as well, but the C++ compiler/linker doesn't know how to +dnl add these Fortran 77 libraries. Hence, the macro +dnl `AC_F77_LIBRARY_LDFLAGS' was created to determine these Fortran 77 +dnl libraries. +dnl +dnl This macro was packaged in its current form by Matthew D. Langston +dnl . However, nearly all of this macro +dnl came from the `OCTAVE_FLIBS' macro in `octave-2.0.13/aclocal.m4', +dnl and full credit should go to John W. Eaton for writing this +dnl extremely useful macro. Thank you John. +dnl +dnl AC_F77_LIBRARY_LDFLAGS() +AC_DEFUN(AC_F77_LIBRARY_LDFLAGS, +[AC_MSG_CHECKING([for Fortran 77 libraries]) +AC_REQUIRE([AC_PROG_F77]) +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_CACHE_VAL(ac_cv_flibs, +[changequote(, )dnl +dnl Write a minimal program and compile it with -v. I don't know what +dnl to do if your compiler doesn't have -v... +echo " END" > conftest.f +foutput=`${F77} -v -o conftest conftest.f 2>&1` +dnl +dnl The easiest thing to do for xlf output is to replace all the commas +dnl with spaces. Try to only do that if the output is really from xlf, +dnl since doing that causes problems on other systems. +dnl +xlf_p=`echo $foutput | grep xlfentry` +if test -n "$xlf_p"; then + foutput=`echo $foutput | sed 's/,/ /g'` +fi +dnl +ld_run_path=`echo $foutput | \ + sed -n -e 's/^.*LD_RUN_PATH *= *\([^ ]*\).*/\1/p'` +dnl +dnl We are only supposed to find this on Solaris systems... +dnl Uh, the run path should be absolute, shouldn't it? +dnl +case "$ld_run_path" in + /*) + if test "$ac_cv_prog_gcc" = yes; then + ld_run_path="-Xlinker -R -Xlinker $ld_run_path" + else + ld_run_path="-R $ld_run_path" + fi + ;; + *) + ld_run_path= + ;; +esac +dnl +flibs= +lflags= +dnl +dnl If want_arg is set, we know we want the arg to be added to the list, +dnl so we don't have to examine it. +dnl +want_arg= +dnl +for arg in $foutput; do + old_want_arg=$want_arg + want_arg= +dnl +dnl None of the options that take arguments expect the argument to +dnl start with a -, so pretend we didn't see anything special. +dnl + if test -n "$old_want_arg"; then + case "$arg" in + -*) + old_want_arg= + ;; + esac + fi + case "$old_want_arg" in + '') + case $arg in + /*.a) + exists=false + for f in $lflags; do + if test x$arg = x$f; then + exists=true + fi + done + if $exists; then + arg= + else + lflags="$lflags $arg" + fi + ;; + -bI:*) + exists=false + for f in $lflags; do + if test x$arg = x$f; then + exists=true + fi + done + if $exists; then + arg= + else + if test "$ac_cv_prog_gcc" = yes; then + lflags="$lflags -Xlinker $arg" + else + lflags="$lflags $arg" + fi + fi + ;; + -lang* | -lcrt0.o | -lc | -lgcc) + arg= + ;; + -[lLR]) + want_arg=$arg + arg= + ;; + -[lLR]*) + exists=false + for f in $lflags; do + if test x$arg = x$f; then + exists=true + fi + done + if $exists; then + arg= + else + case "$arg" in + -lkernel32) + case "$canonical_host_type" in + *-*-cygwin*) + arg= + ;; + *) + lflags="$lflags $arg" + ;; + esac + ;; + -lm) + ;; + *) + lflags="$lflags $arg" + ;; + esac + fi + ;; + -u) + want_arg=$arg + arg= + ;; + -Y) + want_arg=$arg + arg= + ;; + *) + arg= + ;; + esac + ;; + -[lLR]) + arg="$old_want_arg $arg" + ;; + -u) + arg="-u $arg" + ;; + -Y) +dnl +dnl Should probably try to ensure unique directory options here too. +dnl This probably only applies to Solaris systems, and then will only +dnl work with gcc... +dnl + arg=`echo $arg | sed -e 's%^P,%%'` + SAVE_IFS=$IFS + IFS=: + list= + for elt in $arg; do + list="$list -L$elt" + done + IFS=$SAVE_IFS + arg="$list" + ;; + esac +dnl + if test -n "$arg"; then + flibs="$flibs $arg" + fi +done +if test -n "$ld_run_path"; then + flibs_result="$ld_run_path $flibs" +else + flibs_result="$flibs" +fi +changequote([, ])dnl +ac_cv_flibs="$flibs_result"]) +FLIBS="$ac_cv_flibs" +AC_SUBST(FLIBS)dnl +AC_MSG_RESULT($FLIBS) +]) + + +dnl ### Checks for operating system services + + +AC_DEFUN(AC_SYS_INTERPRETER, +[# Pull the hash mark out of the macro call to avoid m4 problems. +ac_msg="whether #! works in shell scripts" +AC_CACHE_CHECK($ac_msg, ac_cv_sys_interpreter, +[echo '#! /bin/cat +exit 69 +' > conftest +chmod u+x conftest +(SHELL=/bin/sh; export SHELL; ./conftest >/dev/null) +if test $? -ne 69; then + ac_cv_sys_interpreter=yes +else + ac_cv_sys_interpreter=no +fi +rm -f conftest]) +interpval="$ac_cv_sys_interpreter" +]) + +define(AC_HAVE_POUNDBANG, +[errprint(__file__:__line__: [$0 has been replaced by AC_SYS_INTERPRETER, taking no arguments +])m4exit(4)]) + +AC_DEFUN(AC_SYS_LONG_FILE_NAMES, +[AC_CACHE_CHECK(for long file names, ac_cv_sys_long_file_names, +[ac_cv_sys_long_file_names=yes +# Test for long file names in all the places we know might matter: +# . the current directory, where building will happen +# $prefix/lib where we will be installing things +# $exec_prefix/lib likewise +# eval it to expand exec_prefix. +# $TMPDIR if set, where it might want to write temporary files +# if $TMPDIR is not set: +# /tmp where it might want to write temporary files +# /var/tmp likewise +# /usr/tmp likewise +if test -n "$TMPDIR" && test -d "$TMPDIR" && test -w "$TMPDIR"; then + ac_tmpdirs="$TMPDIR" +else + ac_tmpdirs='/tmp /var/tmp /usr/tmp' +fi +for ac_dir in . $ac_tmpdirs `eval echo $prefix/lib $exec_prefix/lib` ; do + test -d $ac_dir || continue + test -w $ac_dir || continue # It is less confusing to not echo anything here. + (echo 1 > $ac_dir/conftest9012345) 2>/dev/null + (echo 2 > $ac_dir/conftest9012346) 2>/dev/null + val=`cat $ac_dir/conftest9012345 2>/dev/null` + if test ! -f $ac_dir/conftest9012345 || test "$val" != 1; then + ac_cv_sys_long_file_names=no + rm -f $ac_dir/conftest9012345 $ac_dir/conftest9012346 2>/dev/null + break + fi + rm -f $ac_dir/conftest9012345 $ac_dir/conftest9012346 2>/dev/null +done]) +if test $ac_cv_sys_long_file_names = yes; then + AC_DEFINE(HAVE_LONG_FILE_NAMES) +fi +]) + +AC_DEFUN(AC_SYS_RESTARTABLE_SYSCALLS, +[AC_CACHE_CHECK(for restartable system calls, ac_cv_sys_restartable_syscalls, +[AC_TRY_RUN( +[/* Exit 0 (true) if wait returns something other than -1, + i.e. the pid of the child, which means that wait was restarted + after getting the signal. */ +#include +#include +ucatch (isig) { } +main () { + int i = fork (), status; + if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } + signal (SIGINT, ucatch); + status = wait(&i); + if (status == -1) wait(&i); + exit (status == -1); +} +], ac_cv_sys_restartable_syscalls=yes, ac_cv_sys_restartable_syscalls=no)]) +if test $ac_cv_sys_restartable_syscalls = yes; then + AC_DEFINE(HAVE_RESTARTABLE_SYSCALLS) +fi +]) + +AC_DEFUN(AC_PATH_X, +[AC_REQUIRE_CPP()dnl Set CPP; we run AC_PATH_X_DIRECT conditionally. +# If we find X, set shell vars x_includes and x_libraries to the +# paths, otherwise set no_x=yes. +# Uses ac_ vars as temps to allow command line to override cache and checks. +# --without-x overrides everything else, but does not touch the cache. +AC_MSG_CHECKING(for X) + +AC_ARG_WITH(x, [ --with-x use the X Window System]) +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else +AC_CACHE_VAL(ac_cv_have_x, +[# One or both of the vars are not set, and there is no cached value. +ac_x_includes=NO ac_x_libraries=NO +AC_PATH_X_XMKMF +AC_PATH_X_DIRECT +if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" +fi])dnl + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + AC_MSG_RESULT($have_x) + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$x_includes ac_x_libraries=$x_libraries" + AC_MSG_RESULT([libraries $x_libraries, headers $x_includes]) +fi +]) + +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN(AC_PATH_X_XMKMF, +[rm -fr conftestdir +if mkdir conftestdir; then + cd conftestdir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat > Imakefile <<'EOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; do + if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && + test -f $ac_im_libdir/libX11.$ac_extension; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case "$ac_im_incroot" in + /usr/include) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;; + esac + case "$ac_im_usrlibdir" in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;; + esac + fi + cd .. + rm -fr conftestdir +fi +]) + +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN(AC_PATH_X_DIRECT, +[if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +AC_TRY_CPP([#include <$x_direct_test_include>], +[# We can compile using X headers with no special include directory. +ac_x_includes=], +[# Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done]) +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +AC_TRY_LINK(, [${x_direct_test_function}()], +[LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries=], +[LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \ + /usr/X11/lib \ + /usr/X11R6/lib \ + /usr/X11R5/lib \ + /usr/X11R4/lib \ + \ + /usr/lib/X11 \ + /usr/lib/X11R6 \ + /usr/lib/X11R5 \ + /usr/lib/X11R4 \ + \ + /usr/local/X11/lib \ + /usr/local/X11R6/lib \ + /usr/local/X11R5/lib \ + /usr/local/X11R4/lib \ + \ + /usr/local/lib/X11 \ + /usr/local/lib/X11R6 \ + /usr/local/lib/X11R5 \ + /usr/local/lib/X11R4 \ + \ + /usr/X386/lib \ + /usr/x386/lib \ + /usr/XFree86/lib/X11 \ + \ + /usr/lib \ + /usr/local/lib \ + /usr/unsupported/lib \ + /usr/athena/lib \ + /usr/local/x11r5/lib \ + /usr/lpp/Xamples/lib \ + /lib/usr/lib/X11 \ + \ + /usr/openwin/lib \ + /usr/openwin/share/lib \ + ; \ +do +dnl Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done]) +fi # $ac_x_libraries = NO +]) + +dnl Find additional X libraries, magic flags, etc. +AC_DEFUN(AC_PATH_XTRA, +[AC_REQUIRE([AC_PATH_X])dnl +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + AC_DEFINE(X_DISPLAY_MISSING) + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" +dnl FIXME banish uname from this macro! + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + case "`(uname -sr) 2>/dev/null`" in + "SunOS 5"*) + AC_MSG_CHECKING(whether -R must be followed by a space) + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries" + AC_TRY_LINK(, , ac_R_nospace=yes, ac_R_nospace=no) + if test $ac_R_nospace = yes; then + AC_MSG_RESULT(no) + X_LIBS="$X_LIBS -R$x_libraries" + else + LIBS="$ac_xsave_LIBS -R $x_libraries" + AC_TRY_LINK(, , ac_R_space=yes, ac_R_space=no) + if test $ac_R_space = yes; then + AC_MSG_RESULT(yes) + X_LIBS="$X_LIBS -R $x_libraries" + else + AC_MSG_RESULT(neither works) + fi + fi + LIBS="$ac_xsave_LIBS" + esac + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And karl@cs.umb.edu says + # the Alpha needs dnet_stub (dnet does not exist). + AC_CHECK_LIB(dnet, dnet_ntoa, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"]) + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + AC_CHECK_LIB(dnet_stub, dnet_ntoa, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"]) + fi + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # chad@anasazi.com says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to dickey@clark.net. + AC_CHECK_FUNC(gethostbyname) + if test $ac_cv_func_gethostbyname = no; then + AC_CHECK_LIB(nsl, gethostbyname, X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl") + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says simon@lia.di.epfl.ch: it contains + # gethostby* variants that don't use the nameserver (or something). + # -lsocket must be given before -lnsl if both are needed. + # We assume that if connect needs -lnsl, so does gethostbyname. + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS", , + $X_EXTRA_LIBS) + fi + + # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX. + AC_CHECK_FUNC(remove) + if test $ac_cv_func_remove = no; then + AC_CHECK_LIB(posix, remove, X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix") + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + AC_CHECK_FUNC(shmat) + if test $ac_cv_func_shmat = no; then + AC_CHECK_LIB(ipc, shmat, X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc") + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS="$LDFLAGS" + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # --interran@uluru.Stanford.EDU, kb@cs.umb.edu. + AC_CHECK_LIB(ICE, IceConnectionNumber, + [X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"], , $X_EXTRA_LIBS) + LDFLAGS="$ac_save_LDFLAGS" + +fi +AC_SUBST(X_CFLAGS)dnl +AC_SUBST(X_PRE_LIBS)dnl +AC_SUBST(X_LIBS)dnl +AC_SUBST(X_EXTRA_LIBS)dnl +]) + +dnl The old Cygwin32 macro is deprecated. +AC_DEFUN(AC_CYGWIN32, +[AC_OBSOLETE([$0], [; instead use AC_CYGWIN])dnl +AC_CYGWIN]) + +dnl Check for Cygwin. This is a way to set the right value for +dnl EXEEXT. +AC_DEFUN(AC_CYGWIN, +[AC_CACHE_CHECK(for Cygwin environment, ac_cv_cygwin, +[AC_TRY_COMPILE(,[ +#ifndef __CYGWIN__ +#define __CYGWIN__ __CYGWIN32__ +#endif +return __CYGWIN__;], +ac_cv_cygwin=yes, ac_cv_cygwin=no) +rm -f conftest*]) +CYGWIN= +test "$ac_cv_cygwin" = yes && CYGWIN=yes]) + +dnl Check for mingw32. This is another way to set the right value for +dnl EXEEXT. +AC_DEFUN(AC_MINGW32, +[AC_CACHE_CHECK(for mingw32 environment, ac_cv_mingw32, +[AC_TRY_COMPILE(,[return __MINGW32__;], +ac_cv_mingw32=yes, ac_cv_mingw32=no) +rm -f conftest*]) +MINGW32= +test "$ac_cv_mingw32" = yes && MINGW32=yes]) + +dnl Check for the extension used for executables. This knows that we +dnl add .exe for Cygwin or mingw32. Otherwise, it compiles a test +dnl executable. If this is called, the executable extensions will be +dnl automatically used by link commands run by the configure script. +AC_DEFUN(AC_EXEEXT, +[AC_REQUIRE([AC_CYGWIN]) +AC_REQUIRE([AC_MINGW32]) +AC_MSG_CHECKING([for executable suffix]) +AC_CACHE_VAL(ac_cv_exeext, +[if test "$CYGWIN" = yes || test "$MINGW32" = yes; then + ac_cv_exeext=.exe +else + rm -f conftest* + echo 'int main () { return 0; }' > conftest.$ac_ext + ac_cv_exeext= + if AC_TRY_EVAL(ac_link); then + for file in conftest.*; do + case $file in + *.c | *.o | *.obj) ;; + *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;; + esac + done + else + AC_MSG_ERROR([installation or configuration problem: compiler cannot create executables.]) + fi + rm -f conftest* + test x"${ac_cv_exeext}" = x && ac_cv_exeext=no +fi]) +EXEEXT="" +test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext} +AC_MSG_RESULT(${ac_cv_exeext}) +dnl Setting ac_exeext will implicitly change the ac_link command. +ac_exeext=$EXEEXT +AC_SUBST(EXEEXT)]) + + +dnl ### Checks for UNIX variants +dnl These are kludges which should be replaced by a single POSIX check. +dnl They aren't cached, to discourage their use. + + +AC_DEFUN(AC_AIX, +[AC_BEFORE([$0], [AC_TRY_COMPILE])dnl +AC_BEFORE([$0], [AC_TRY_RUN])dnl +AC_MSG_CHECKING(for AIX) +AC_EGREP_CPP(yes, +[#ifdef _AIX + yes +#endif +], [AC_MSG_RESULT(yes); AC_DEFINE(_ALL_SOURCE)], AC_MSG_RESULT(no)) +]) + +AC_DEFUN(AC_MINIX, +[AC_BEFORE([$0], [AC_TRY_COMPILE])dnl +AC_BEFORE([$0], [AC_TRY_RUN])dnl +AC_CHECK_HEADER(minix/config.h, MINIX=yes, MINIX=) +if test "$MINIX" = yes; then + AC_DEFINE(_POSIX_SOURCE) + AC_DEFINE(_POSIX_1_SOURCE, 2) + AC_DEFINE(_MINIX) +fi +]) + +AC_DEFUN(AC_ISC_POSIX, +[AC_REQUIRE([AC_PROG_CC])dnl +AC_BEFORE([$0], [AC_TRY_COMPILE])dnl +AC_BEFORE([$0], [AC_TRY_RUN])dnl +AC_MSG_CHECKING(for POSIXized ISC) +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION [/usr/include/sys/unistd.h] >/dev/null 2>&1 +then + AC_MSG_RESULT(yes) + ISC=yes # If later tests want to check for ISC. + AC_DEFINE(_POSIX_SOURCE) + if test "$GCC" = yes; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +else + AC_MSG_RESULT(no) + ISC= +fi +]) + +AC_DEFUN(AC_XENIX_DIR, +[AC_OBSOLETE([$0], [; instead use AC_HEADER_DIRENT])dnl +AC_REQUIRE([AC_DIR_HEADER])dnl +AC_MSG_CHECKING(for Xenix) +AC_EGREP_CPP(yes, +[#if defined(M_XENIX) && !defined(M_UNIX) + yes +#endif +], [AC_MSG_RESULT(yes); XENIX=yes], [AC_MSG_RESULT(no); XENIX=]) +if test "$XENIX" = yes; then + # Make sure -ldir precedes -lx. + test $ac_header_dirent = dirent.h && LIBS="-ldir $LIBS" + LIBS="$LIBS -lx" +fi +]) + +AC_DEFUN(AC_DYNIX_SEQ, +[AC_OBSOLETE([$0], [; instead use AC_FUNC_GETMNTENT])dnl +AC_CHECK_LIB(seq, getmntent, LIBS="-lseq $LIBS") +]) + +AC_DEFUN(AC_IRIX_SUN, +[AC_OBSOLETE([$0], [; instead use AC_FUNC_GETMNTENT or AC_CHECK_LIB(sun, getpwnam)])dnl +AC_CHECK_LIB(sun, getmntent, LIBS="-lsun $LIBS") +]) + +AC_DEFUN(AC_SCO_INTL, +[AC_OBSOLETE([$0], [; instead use AC_FUNC_STRFTIME])dnl +AC_CHECK_LIB(intl, strftime, LIBS="-lintl $LIBS") +]) diff --git a/build/autoconf/autoconf.m4 b/build/autoconf/autoconf.m4 new file mode 100644 index 0000000000..dde59ab380 --- /dev/null +++ b/build/autoconf/autoconf.m4 @@ -0,0 +1,28 @@ +dnl Driver that loads the Autoconf macro files. +dnl Requires GNU m4. +dnl This file is part of Autoconf. +dnl Copyright (C) 1994 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl Written by David MacKenzie. +dnl +include(acgeneral.m4)dnl +builtin(include, acspecific.m4)dnl +builtin(include, acoldnames.m4)dnl +dnl Do not sinclude acsite.m4 here, because it may not be installed +dnl yet when Autoconf is frozen. +dnl Do not sinclude ./aclocal.m4 here, to prevent it from being frozen. diff --git a/build/autoconf/autoconf.sh b/build/autoconf/autoconf.sh new file mode 100755 index 0000000000..e6b0819fab --- /dev/null +++ b/build/autoconf/autoconf.sh @@ -0,0 +1,159 @@ +#! @SHELL@ +# autoconf -- create `configure' using m4 macros +# Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# If given no args, create `configure' from template file `configure.in'. +# With one arg, create a configure script on standard output from +# the given template file. + +usage="\ +Usage: autoconf [-h] [--help] [-m dir] [--macrodir=dir] + [-l dir] [--localdir=dir] [--version] [template-file]" + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +: ${AC_MACRODIR=@datadir@} +: ${M4=@M4@} +: ${AWK=@AWK@} +case "${M4}" in +/*) # Handle the case that m4 has moved since we were configured. + # It may have been found originally in a build directory. + test -f "${M4}" || M4=m4 ;; +esac + +: ${TMPDIR=/tmp} +tmpout=${TMPDIR}/acout.$$ +localdir= +show_version=no + +while test $# -gt 0 ; do + case "${1}" in + -h | --help | --h* ) + echo "${usage}" 1>&2; exit 0 ;; + --localdir=* | --l*=* ) + localdir="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" + shift ;; + -l | --localdir | --l*) + shift + test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } + localdir="${1}" + shift ;; + --macrodir=* | --m*=* ) + AC_MACRODIR="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" + shift ;; + -m | --macrodir | --m* ) + shift + test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } + AC_MACRODIR="${1}" + shift ;; + --version | --v* ) + show_version=yes; shift ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "${usage}" 1>&2; exit 1 ;; + * ) + break ;; + esac +done + +if test $show_version = yes; then + version=`sed -n 's/define.AC_ACVERSION.[ ]*\([0-9.]*\).*/\1/p' \ + $AC_MACRODIR/acgeneral.m4` + echo "Autoconf version $version" + exit 0 +fi + +case $# in + 0) infile=configure.in ;; + 1) infile="$1" ;; + *) echo "$usage" >&2; exit 1 ;; +esac + +trap 'rm -f $tmpin $tmpout; exit 1' 1 2 15 + +tmpin=${TMPDIR}/acin.$$ # Always set this, to avoid bogus errors from some rm's. +if test z$infile = z-; then + infile=$tmpin + cat > $infile +elif test ! -r "$infile"; then + echo "autoconf: ${infile}: No such file or directory" >&2 + exit 1 +fi + +if test -n "$localdir"; then + use_localdir="-I$localdir -DAC_LOCALDIR=$localdir" +else + use_localdir= +fi + +# Use the frozen version of Autoconf if available. +r= f= +# Some non-GNU m4's don't reject the --help option, so give them /dev/null. +case `$M4 --help < /dev/null 2>&1` in +*reload-state*) test -r $AC_MACRODIR/autoconf.m4f && { r=--reload f=f; } ;; +*traditional*) ;; +*) echo Autoconf requires GNU m4 1.1 or later >&2; rm -f $tmpin; exit 1 ;; +esac + +$M4 -I$AC_MACRODIR $use_localdir $r autoconf.m4$f $infile > $tmpout || + { rm -f $tmpin $tmpout; exit 2; } + +# You could add your own prefixes to pattern if you wanted to check for +# them too, e.g. pattern='\(AC_\|ILT_\)', except that UNIX sed doesn't do +# alternation. +pattern="AC_" + +status=0 +if grep "^[^#]*${pattern}" $tmpout > /dev/null 2>&1; then + echo "autoconf: Undefined macros:" >&2 + sed -n "s/^[^#]*\\(${pattern}[_A-Za-z0-9]*\\).*/\\1/p" $tmpout | + while read macro; do + grep -n "^[^#]*$macro" $infile /dev/null + test $? -eq 1 && echo >&2 "***BUG in Autoconf--please report*** $macro" + done | sort -u >&2 + status=1 +fi + +if test $# -eq 0; then + exec 4> configure; chmod +x configure +else + exec 4>&1 +fi + +# Put the real line numbers into configure to make config.log more helpful. +$AWK ' +/__oline__/ { printf "%d:", NR + 1 } + { print } +' $tmpout | sed ' +/__oline__/s/^\([0-9][0-9]*\):\(.*\)__oline__/\2\1/ +' >&4 + +rm -f $tmpout + +exit $status diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure index 5f121230d9..b01cfad0ac 100644 --- a/build/moz.configure/init.configure +++ b/build/moz.configure/init.configure @@ -619,10 +619,8 @@ def include_project_configure(project, external_source_dir, build_env, help): build_app = project[0] - # XXX: Change this when 'browser' becomes invalid as an alias - if build_app == 'browser': - build_app = 'basilisk' - #die('The project "browser" is no longer valid. Perhaps you meant "basilisk" or "palemoon"?') + if build_app == 'basilisk': + build_app = 'browser' path_project_src_dir_application = os.path.join(base_dir, 'application/' + build_app, 'moz.configure') path_project_src_dir_root = os.path.join(base_dir, build_app, 'moz.configure') diff --git a/build/moz.configure/old.configure b/build/moz.configure/old.configure index 8fa9cf1a38..1ff1e1d3b5 100644 --- a/build/moz.configure/old.configure +++ b/build/moz.configure/old.configure @@ -10,66 +10,28 @@ def encoded_open(path, mode): return codecs.open(path, mode, encoding) -option(env='AUTOCONF', nargs=1, help='Path to autoconf 2.13') +m4 = check_prog( + "M4", + ( + "gm4", + "m4", + ), +) -@depends(mozconfig, 'AUTOCONF') -@checking('for autoconf') -@imports(_from='os.path', _import='exists') -@imports('re') -def autoconf(mozconfig, autoconf): - mozconfig_autoconf = None - if mozconfig['path']: - make_extra = mozconfig['make_extra'] - if make_extra: - for assignment in make_extra: - m = re.match('(?:export\s+)?AUTOCONF\s*:?=\s*(.+)$', - assignment) - if m: - mozconfig_autoconf = m.group(1) - - autoconf = autoconf[0] if autoconf else None - - for ac in (mozconfig_autoconf, autoconf, 'autoconf-2.13', 'autoconf2.13', - 'autoconf213'): - if ac: - autoconf = find_program(ac) - if autoconf: - break - else: - fink = find_program('fink') - if fink: - autoconf = os.path.normpath(os.path.join( - fink, '..', '..', 'lib', 'autoconf2.13', 'bin', 'autoconf')) - else: - brew = find_program('brew') - if brew: - autoconf = os.path.normpath(os.path.join( - brew, '..', '..', 'Cellar', 'autoconf213', '2.13', 'bin', - 'autoconf213')) - - if not autoconf: - die('Could not find autoconf 2.13') - - if not exists(autoconf): - die('Could not find autoconf 2.13 at %s', autoconf) - - return autoconf - -set_config('AUTOCONF', autoconf) - - -@depends('OLD_CONFIGURE', mozconfig, autoconf, check_build_environment, shell, +@depends('OLD_CONFIGURE', mozconfig, awk, m4, check_build_environment, shell, old_configure_assignments, build_project) @imports(_from='__builtin__', _import='open') @imports(_from='__builtin__', _import='print') @imports('glob') +@imports('sys') @imports('itertools') @imports('subprocess') # Import getmtime without overwriting the sandbox os.path. @imports(_from='os.path', _import='getmtime') @imports(_from='os.path', _import='exists') @imports(_from='mozbuild.shellutil', _import='quote') -def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell, +@imports(_from='os', _import='environ') +def prepare_configure(old_configure, mozconfig, awk, m4, build_env, shell, old_configure_assignments, build_project): # os.path.abspath in the sandbox will ensure forward slashes on Windows, # which is actually necessary because this path actually ends up literally @@ -98,11 +60,22 @@ def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell, refresh = False if refresh: + autoconf = os.path.join(build_env.topsrcdir, 'build', 'autoconf', 'autoconf.sh') log.info('Refreshing %s with %s', old_configure, autoconf) + env = dict(environ) + env['M4'] = m4 + env['AWK'] = awk + env['AC_MACRODIR'] = os.path.join(build_env.topsrcdir, 'build', 'autoconf') + my_env = env + # Handle Python 2.7 not allowing unicode in the environment on Windows + if sys.platform == 'win32': + my_env = dict() + for e in env: + my_env[e.encode('ascii','ignore')] = env[e].encode('ascii','ignore') script = subprocess.check_output([ shell, autoconf, '--localdir=%s' % os.path.dirname(old_configure), - old_configure + '.in']) + old_configure + '.in'], env=my_env) # Make old-configure append to config.log, where we put our own log. # This could be done with a m4 macro, but it's way easier this way @@ -127,10 +100,6 @@ def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell, for key in mozconfig[t]['removed'].keys(): inject("unset %s" % key) - # Autoconf is special, because it might be passed from - # mozconfig['make_extra'], which we don't pass automatically above. - inject('export AUTOCONF=%s' % quote(autoconf)) - for assignment in old_configure_assignments: inject(assignment) diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure index 696a64f8a1..5254a44eb4 100644 --- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -69,6 +69,43 @@ def compiling_android(compile_env, build_project, gonkdir, _): return compile_env and (gonkdir or build_project in ('mobile/android', 'js')) include('android-ndk.configure', when=compiling_android) +# nasm detection +# ============================================================== +nasm = check_prog('NASM', ['nasm'], allow_missing=True) + +@depends_if(nasm) +@checking('nasm version') +def nasm_version(nasm): + version = check_cmd_output( + nasm, '-v', + onerror=lambda: die('Failed to get nasm version.') + ).splitlines()[0].split()[2] + return Version(version) + +@depends(nasm, nasm_version) +def have_nasm(nasm, version): + if nasm and version >= Version('2.14'): + return True + +set_config('HAVE_NASM', have_nasm) + +@depends(have_nasm, target) +def nasm_asflags(have_nasm, target): + if have_nasm: + asflags = { + ('OSX', 'x86'): '-f macho32', + ('OSX', 'x86_64'): '-f macho64', + ('WINNT', 'x86'): '-f win32', + ('WINNT', 'x86_64'): '-f win64', + }.get((target.os, target.cpu), None) + if asflags is None: + if target.cpu == 'x86': + asflags = '-f elf32' + elif target.cpu == 'x86_64': + asflags = '-f elf64' + return asflags + +set_config('NASM_ASFLAGS', nasm_asflags) # MacOS deployment target version # ============================================================== diff --git a/build/moz.configure/windows.configure b/build/moz.configure/windows.configure index 048b46eebe..4a28470d34 100644 --- a/build/moz.configure/windows.configure +++ b/build/moz.configure/windows.configure @@ -277,10 +277,6 @@ def dia_sdk_dir(vc_path): def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir): if not vc_path: return - atlmfc_dir = os.path.join(vc_path, 'atlmfc', 'include') - if not os.path.isdir(atlmfc_dir): - die('Cannot find the ATL/MFC headers in the Visual C++ directory (%s). ' - 'Please install them.' % vc_path) winrt_dir = os.path.join(windows_sdk_dir.include, 'winrt') if not os.path.isdir(winrt_dir): @@ -293,7 +289,6 @@ def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir): includes.append(include_env) includes.extend(( os.path.join(vc_path, 'include'), - atlmfc_dir, os.path.join(windows_sdk_dir.include, 'shared'), os.path.join(windows_sdk_dir.include, 'um'), winrt_dir, @@ -331,22 +326,12 @@ def lib_path(target, vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir): 'x86_64': 'x64', 'arm': 'arm', }.get(target.cpu) - - atlmfc_dir = os.path.join(vc_path, 'atlmfc', 'lib', *vc_target) - if not os.path.isdir(atlmfc_dir): - atlmfc_dir = atlmfc_dir.replace('amd64','x64') - if not os.path.isdir(atlmfc_dir): - die('Cannot find the ATL/MFC libraries in the Visual C++ directory (%s). ' - 'Please install them.' % vc_path) - - libs = [] lib_env = os.environ.get('LIB') if lib_env: libs.append(lib_env) libs.extend(( os.path.join(vc_path, 'lib', *vc_target), - atlmfc_dir, os.path.join(windows_sdk_dir.lib, 'um', sdk_target), os.path.join(ucrt_sdk_dir.lib, 'ucrt', sdk_target), )) @@ -392,26 +377,6 @@ mt = check_prog('MT', depends_win()(lambda: ('mt.exe',)), input='MT', paths=sdk_bin_path) -# Check that MT is not something unexpected like "magnetic tape manipulation -# utility". -@depends_win(mt) -@checking('whether MT is really Microsoft Manifest Tool', lambda x: bool(x)) -@imports('subprocess') -def valid_mt(path): - try: - out = subprocess.check_output([path]).splitlines() - out = '\n'.join(l for l in out - if 'Microsoft (R) Manifest Tool' in l) - if out: - return path - except subprocess.CalledProcessError: - pass - raise FatalCheckError('%s is not Microsoft Manifest Tool') - - -set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x))) - - # Ultimately, this will move to toolchain.configure and be turned into a # cross-platform check. option(env='LD', nargs=1, help='Path to the linker') diff --git a/config/external/moz.build b/config/external/moz.build index b5cd39ce75..1d33bcf3c8 100644 --- a/config/external/moz.build +++ b/config/external/moz.build @@ -30,7 +30,7 @@ if CONFIG['MOZ_WEBM_ENCODER']: external_dirs += ['media/libvpx'] if CONFIG['MOZ_AV1']: - external_dirs += ['media/libaom'] + external_dirs += ['media/libdav1d'] external_dirs += ['media/libpng'] diff --git a/docs/readme/demo.png b/docs/readme/demo.png new file mode 100644 index 0000000000..af13017634 Binary files /dev/null and b/docs/readme/demo.png differ diff --git a/readme/newtab.png b/docs/readme/newtab.png similarity index 100% rename from readme/newtab.png rename to docs/readme/newtab.png diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index a7afd310cb..7b7dbdf67d 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -138,6 +138,207 @@ StructuredCloneCallbacksError(JSContext* aCx, NS_WARNING("Failed to clone data."); } +struct SameThreadStreamTransferData +{ + SameThreadStreamTransferData(JSContext* aCx, JS::HandleObject aRecord) + : mRecord(aCx, aRecord) + {} + + ~SameThreadStreamTransferData() + { + mRecord.reset(); + } + + JS::PersistentRootedObject mRecord; +}; + +bool +CallStreamTransferHelper(JSContext* aCx, + const char* aHelperName, + JS::HandleValue aArgument, + JS::MutableHandleValue aResult) +{ + JS::Rooted global(aCx, JS::CurrentGlobalOrNull(aCx)); + if (!global) { + return false; + } + + // Resolve the stream extras lazily before looking up the internal helper. + JS::Rooted ignored(aCx); + if (!JS_GetProperty(aCx, global, "WritableStream", &ignored)) { + return false; + } + + JS::Rooted helper(aCx); + if (!JS_GetProperty(aCx, global, aHelperName, &helper)) { + return false; + } + + if (!helper.isObject() || !JS::IsCallable(&helper.toObject())) { + aResult.setUndefined(); + return true; + } + + JS::Rooted argument(aCx, aArgument); + if (!JS_WrapValue(aCx, &argument)) { + return false; + } + + return JS::Call(aCx, JS::UndefinedHandleValue, helper, + JS::HandleValueArray(argument), aResult); +} + +bool +TryWriteSameThreadStreamTransfer(JSContext* aCx, + JS::Handle aObj, + const char* aHelperName, + uint32_t aTransferTag, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData, + bool* aHandled) +{ + *aHandled = false; + + JS::Rooted argument(aCx, JS::ObjectValue(*aObj)); + JS::Rooted transferRecord(aCx); + if (!CallStreamTransferHelper(aCx, aHelperName, argument, &transferRecord)) { + return false; + } + + if (transferRecord.isUndefined()) { + return true; + } + + if (!transferRecord.isObject()) { + return false; + } + + JS::Rooted record(aCx, &transferRecord.toObject()); + SameThreadStreamTransferData* data = + new SameThreadStreamTransferData(aCx, record); + + *aTag = aTransferTag; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = data; + *aExtraData = 0; + *aHandled = true; + return true; +} + +bool +TryWriteReadableStreamPortTransfer(JSContext* aCx, + JS::Handle aObj, + nsTArray& aPortIdentifiers, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData, + bool* aHandled) +{ + *aHandled = false; + + JS::Rooted argument(aCx, JS::ObjectValue(*aObj)); + JS::Rooted transferPortValue(aCx); + if (!CallStreamTransferHelper(aCx, "__uxpTransferReadableStreamPort", + argument, &transferPortValue)) { + return false; + } + + if (transferPortValue.isUndefined()) { + return true; + } + + if (!transferPortValue.isObject()) { + return false; + } + + JS::Rooted transferPortObj(aCx, &transferPortValue.toObject()); + MessagePort* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, &transferPortObj, port); + if (NS_FAILED(rv) || !port) { + return false; + } + + *aExtraData = aPortIdentifiers.Length(); + MessagePortIdentifier* identifier = aPortIdentifiers.AppendElement(); + port->CloneAndDisentangle(*identifier); + + *aTag = SCTAG_DOM_TRANSFERRED_READABLESTREAM; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = nullptr; + *aHandled = true; + return true; +} + +bool +ReadSameThreadStreamTransfer(JSContext* aCx, + void* aContent, + const char* aHelperName, + JS::MutableHandleObject aReturnObject) +{ + MOZ_ASSERT(aContent); + SameThreadStreamTransferData* data = + static_cast(aContent); + + JS::Rooted record(aCx, JS::ObjectValue(*data->mRecord)); + JS::Rooted result(aCx); + if (!CallStreamTransferHelper(aCx, aHelperName, record, &result)) { + return false; + } + + if (!result.isObject()) { + return false; + } + + aReturnObject.set(&result.toObject()); + delete data; + return true; +} + +bool +ReadReadableStreamPortTransfer(JSContext* aCx, + nsISupports* aParent, + nsTArray& aPortIdentifiers, + uint64_t aExtraData, + JS::MutableHandleObject aReturnObject) +{ + if (aExtraData >= aPortIdentifiers.Length()) { + return false; + } + + nsCOMPtr global = do_QueryInterface(aParent); + + ErrorResult rv; + RefPtr port = + MessagePort::Create(global, aPortIdentifiers[aExtraData], rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + return false; + } + + JS::Rooted portValue(aCx); + if (!GetOrCreateDOMReflector(aCx, port, &portValue)) { + JS_ClearPendingException(aCx); + return false; + } + + JS::Rooted result(aCx); + if (!CallStreamTransferHelper(aCx, + "__uxpReceiveReadableStreamTransferFromPort", + portValue, &result)) { + return false; + } + + if (!result.isObject()) { + return false; + } + + aReturnObject.set(&result.toObject()); + return true; +} + } // anonymous namespace const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = { @@ -1375,6 +1576,35 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx, return true; } + if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) { + if (aTag == SCTAG_DOM_TRANSFERRED_WRITABLESTREAM) { + return ReadSameThreadStreamTransfer(aCx, aContent, + "__uxpReceiveWritableStreamTransfer", + aReturnObject); + } + + if (aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM) { + return ReadSameThreadStreamTransfer(aCx, aContent, + "__uxpReceiveReadableStreamTransfer", + aReturnObject); + } + + if (aTag == SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM) { + return ReadSameThreadStreamTransfer(aCx, aContent, + "__uxpReceiveTransformStreamTransfer", + aReturnObject); + } + } + + if ((mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread || + mStructuredCloneScope == StructuredCloneScope::DifferentProcess) && + aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM) { + MOZ_ASSERT(!aContent); + return ReadReadableStreamPortTransfer(aCx, mParent, mPortIdentifiers, + aExtraData, + aReturnObject); + } + return false; } @@ -1443,6 +1673,55 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx, } } + if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) { + bool handled = false; + if (!TryWriteSameThreadStreamTransfer(aCx, obj, + "__uxpTransferWritableStream", + SCTAG_DOM_TRANSFERRED_WRITABLESTREAM, + aTag, aOwnership, aContent, + aExtraData, &handled)) { + return false; + } + if (handled) { + return true; + } + + if (!TryWriteSameThreadStreamTransfer(aCx, obj, + "__uxpTransferReadableStream", + SCTAG_DOM_TRANSFERRED_READABLESTREAM, + aTag, aOwnership, aContent, + aExtraData, &handled)) { + return false; + } + if (handled) { + return true; + } + + if (!TryWriteSameThreadStreamTransfer(aCx, obj, + "__uxpTransferTransformStream", + SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM, + aTag, aOwnership, aContent, + aExtraData, &handled)) { + return false; + } + if (handled) { + return true; + } + } + + if (mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread || + mStructuredCloneScope == StructuredCloneScope::DifferentProcess) { + bool handled = false; + if (!TryWriteReadableStreamPortTransfer(aCx, obj, mPortIdentifiers, + aTag, aOwnership, aContent, + aExtraData, &handled)) { + return false; + } + if (handled) { + return true; + } + } + return false; } @@ -1480,6 +1759,26 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag, delete data; return; } + + if ((aTag == SCTAG_DOM_TRANSFERRED_WRITABLESTREAM || + aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM || + aTag == SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM) && + mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) { + MOZ_ASSERT(aContent); + SameThreadStreamTransferData* data = + static_cast(aContent); + delete data; + return; + } + + if (aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM && + (mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread || + mStructuredCloneScope == StructuredCloneScope::DifferentProcess)) { + MOZ_ASSERT(!aContent); + MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); + MessagePort::ForceClose(mPortIdentifiers[aExtraData]); + return; + } } bool diff --git a/dom/base/StructuredCloneTags.h b/dom/base/StructuredCloneTags.h index 09b91f7afb..15518104f9 100644 --- a/dom/base/StructuredCloneTags.h +++ b/dom/base/StructuredCloneTags.h @@ -68,6 +68,11 @@ enum StructuredCloneTags { // This tag is used by both main thread and workers. SCTAG_DOM_URLSEARCHPARAMS, + // Same-thread transferable stream records. These are not supported by IDB. + SCTAG_DOM_TRANSFERRED_READABLESTREAM, + SCTAG_DOM_TRANSFERRED_WRITABLESTREAM, + SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM, + // When adding a new tag for IDB, please don't add it to the end of the list! // Tags that are supported by IDB must not ever change. See the static assert // in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback. diff --git a/dom/base/nsDOMTokenList.cpp b/dom/base/nsDOMTokenList.cpp index 87fb11e8c7..02acabacac 100644 --- a/dom/base/nsDOMTokenList.cpp +++ b/dom/base/nsDOMTokenList.cpp @@ -127,7 +127,29 @@ void nsDOMTokenList::AddInternal(const nsAttrValue* aAttr, const nsTArray& aTokens) { - if (!mElement) { + if (!mElement || aTokens.IsEmpty()) { + return; + } + + // Hot path: single-token classList.add() when the class is already present. + // Skip attribute rebuild and SetAttr entirely (avoids mutation observers / + // style invalidation). Frameworks hit this constantly. + if (aTokens.Length() == 1) { + const nsString& token = aTokens[0]; + if (aAttr && aAttr->Contains(token)) { + return; + } + + nsAutoString resultStr; + if (aAttr) { + aAttr->ToString(resultStr); + if (!resultStr.IsEmpty() && + !nsContentUtils::IsHTMLWhitespace(resultStr.Last())) { + resultStr.Append(' '); + } + } + resultStr.Append(token); + mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true); return; } @@ -161,6 +183,11 @@ nsDOMTokenList::AddInternal(const nsAttrValue* aAttr, addedClasses.AppendElement(aToken); } + // No new tokens: leave the attribute untouched (do not create class=""). + if (!oneWasAdded) { + return; + } + mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true); } @@ -190,20 +217,37 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr, { MOZ_ASSERT(aAttr, "Need an attribute"); + if (aTokens.IsEmpty()) { + return; + } + + // Hot path: single-token classList.remove() when the class is absent. + if (aTokens.Length() == 1 && !aAttr->Contains(aTokens[0])) { + return; + } + nsAutoString input; aAttr->ToString(input); WhitespaceTokenizer tokenizer(input); nsAutoString output; + bool removed = false; while (tokenizer.hasMoreTokens()) { auto& currentToken = tokenizer.nextToken(); - if (!aTokens.Contains(currentToken)) { - if (!output.IsEmpty()) { - output.Append(char16_t(' ')); - } - output.Append(currentToken); + if (aTokens.Contains(currentToken)) { + removed = true; + continue; } + if (!output.IsEmpty()) { + output.Append(char16_t(' ')); + } + output.Append(currentToken); + } + + // Token set unchanged: skip SetAttr to avoid style/mutation work. + if (!removed) { + return; } mElement->SetAttr(kNameSpaceID_None, mAttrAtom, output, true); @@ -302,6 +346,16 @@ nsDOMTokenList::ReplaceInternal(const nsAttrValue* aAttr, const nsAString& aToken, const nsAString& aNewToken) { + // Replacing a token with itself cannot change the token set. + if (aToken.Equals(aNewToken)) { + return; + } + + // Old token absent: no update (and avoid rewriting whitespace). + if (!aAttr->Contains(aToken)) { + return; + } + nsAutoString attribute; aAttr->ToString(attribute); diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index ffb5709e46..a80d9164b9 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1929,6 +1929,9 @@ public: { ProcessGlobal* global = ProcessGlobal::Get(); MOZ_ASSERT(!aRunInGlobalScope); + if (NS_WARN_IF(!global)) { + return false; + } global->LoadScript(aURL); return true; } diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 5218938ca3..740c18417f 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -2927,6 +2927,35 @@ FindMatchingElementsWithId(const nsAString& aId, nsINode* aRoot, // Actually find elements matching aSelectorList (which must not be // null) and which are descendants of aRoot and put them in aList. If // onlyFirstMatch, then stop once the first one is found. +template +static void +FindMatchingElementsWithClass(nsINode* aRoot, nsIAtom* aClass, + nsCaseTreatment aCaseTreatment, T& aList) +{ + Collector results; + for (nsIContent* cur = aRoot->GetFirstChild(); cur; + cur = cur->GetNextNode(aRoot)) { + if (!cur->IsElement()) { + continue; + } + const nsAttrValue* classes = cur->AsElement()->GetClasses(); + if (classes && classes->Contains(aClass, aCaseTreatment)) { + if (onlyFirstMatch) { + aList.AppendElement(cur->AsElement()); + return; + } + results.AppendElement(cur->AsElement()); + } + } + const uint32_t len = results.Length(); + if (len) { + aList.SetCapacity(len); + for (uint32_t i = 0; i < len; ++i) { + aList.AppendElement(results.ElementAt(i)); + } + } +} + template MOZ_ALWAYS_INLINE static void FindMatchingElements(nsINode* aRoot, nsCSSSelectorList* aSelectorList, T &aList, @@ -2934,6 +2963,23 @@ FindMatchingElements(nsINode* aRoot, nsCSSSelectorList* aSelectorList, T &aList, { nsIDocument* doc = aRoot->OwnerDoc(); + // Parsed selectors are already cached by the document. A lone class needs + // only an atom lookup per element, not the general CSS matching context. + nsCSSSelector* selector = aSelectorList->mSelectors; + if (!aSelectorList->mNext && !selector->mNext && + selector->mClassList && !selector->mClassList->mNext && + !selector->mLowercaseTag && !selector->mIDList && + !selector->mAttrList && !selector->mPseudoClassList && + !selector->mNegations && selector->mNameSpace == kNameSpaceID_Unknown && + selector->IsRestrictedSelector() && !selector->IsHybridPseudoElement()) { + nsCaseTreatment caseTreatment = + doc->GetCompatibilityMode() == eCompatibility_NavQuirks + ? eIgnoreCase : eCaseMatters; + FindMatchingElementsWithClass( + aRoot, selector->mClassList->mAtom, caseTreatment, aList); + return; + } + TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited, doc, TreeMatchContext::eNeverMatchVisited); doc->FlushPendingLinkUpdates(); diff --git a/dom/base/test/file_class_selector_checks.js b/dom/base/test/file_class_selector_checks.js new file mode 100644 index 0000000000..0be76bc6ef --- /dev/null +++ b/dom/base/test/file_class_selector_checks.js @@ -0,0 +1,59 @@ +function checkClassSelectors(parse, equal) { + function check(root, selector, expected) { + var all = root.querySelectorAll(selector); + equal(all.length, expected.length, selector + " count"); + for (var i = 0; i < expected.length; i++) { + equal(all[i].id, expected[i], selector + " order " + i); + } + equal(root.querySelector(selector), all.length ? all[0] : null, + selector + " first match"); + } + + var doc = parse('' + + '

' + + '
' + + '
' + + '' + + '
', 'text/html'); + var root = doc.getElementById('root'); + for (var repeat = 0; repeat < 10; repeat++) { + check(root, '.toggle', ['a', 'b', 'd', 'svg']); + check(root, '*|*.toggle', ['a', 'b', 'd', 'svg']); + check(root, '.t\\6f ggle', ['a', 'b', 'd', 'svg']); + check(root, '.TOGGLE', ['c']); + check(root, '.missing', []); + check(root, '.toggle.completed', ['a']); + check(root, 'button.toggle', ['d']); + check(root, '.toggle:not(.completed)', ['b', 'd', 'svg']); + check(root, '.toggle, .other', ['a', 'b', 'd', 'svg']); + } + check(doc, '.toggle', ['root', 'a', 'b', 'd', 'svg']); + + var snapshot = root.querySelectorAll('.toggle'); + doc.getElementById('a').className = ''; + root.removeChild(doc.getElementById('d')); + doc.getElementById('c').className = 'toggle'; + check(root, '.toggle', ['b', 'c', 'svg']); + equal(snapshot.length, 4, 'querySelectorAll remains a static snapshot'); + equal(snapshot[0].id, 'a', 'snapshot retains a changed element'); + equal(snapshot[2].id, 'd', 'snapshot retains a removed element'); + + var fragment = doc.createDocumentFragment(); + fragment.appendChild(root); + check(fragment, '.toggle', ['root', 'b', 'c', 'svg']); + check(root, '.toggle', ['b', 'c', 'svg']); + + var quirks = parse('
' + + '
', 'text/html'); + equal(quirks.compatMode, 'BackCompat', 'quirks document'); + check(quirks, '.toggle', ['lower', 'upper']); + check(quirks, '.TOGGLE', ['lower', 'upper']); + + var xml = parse('' + + '' + + '', + 'application/xml'); + check(xml, '.toggle', ['plain', 'namespaced']); + check(xml, '|*.toggle', ['plain']); + check(xml, '*|*.toggle', ['plain', 'namespaced']); +} diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 6f5e0ea835..f903dc5a3d 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -1,5 +1,6 @@ [DEFAULT] support-files = + file_class_selector_checks.js audio.ogg audioEndedDuringPlaying.webm iframe_bug962251.html @@ -615,6 +616,7 @@ skip-if = os == "mac" # Different tab focus behavior on mac [test_caretPositionFromPoint.html] [test_change_policy.html] [test_classList.html] +[test_class_selector_fast_path.html] [test_clearTimeoutIntervalNoArg.html] [test_constructor-assignment.html] [test_constructor.html] diff --git a/dom/base/test/test_class_selector_fast_path.html b/dom/base/test/test_class_selector_fast_path.html new file mode 100644 index 0000000000..3eb87d2cf2 --- /dev/null +++ b/dom/base/test/test_class_selector_fast_path.html @@ -0,0 +1,10 @@ + + +Class selector query fast path + + + diff --git a/dom/console/ConsoleAPIStorage.js b/dom/console/ConsoleAPIStorage.js index 31be449e91..b17c6855ec 100644 --- a/dom/console/ConsoleAPIStorage.js +++ b/dom/console/ConsoleAPIStorage.js @@ -94,13 +94,24 @@ ConsoleAPIStorageService.prototype = { getEvents: function CS_getEvents(aId) { if (aId != null) { - return (_consoleStorage.get(aId) || []).slice(0); + let storage = _consoleStorage.get(aId); + if (!storage) { + return []; + } + let { events, next } = storage; + return next === 0 ? events.slice() : + events.slice(next).concat(events.slice(0, next)); } let result = []; - for (let [id, events] of _consoleStorage) { - result.push.apply(result, events); + for (let { events, next } of _consoleStorage.values()) { + for (let i = next; i < events.length; i++) { + result.push(events[i]); + } + for (let i = 0; i < next; i++) { + result.push(events[i]); + } } return result.sort(function(a, b) { @@ -122,16 +133,21 @@ ConsoleAPIStorageService.prototype = { */ recordEvent: function CS_recordEvent(aId, aOuterId, aEvent) { - if (!_consoleStorage.has(aId)) { - _consoleStorage.set(aId, []); + let storage = _consoleStorage.get(aId); + if (!storage) { + storage = { events: [], next: 0 }; + _consoleStorage.set(aId, storage); } - let storage = _consoleStorage.get(aId); - storage.push(aEvent); - - // truncate - if (storage.length > STORAGE_MAX_EVENTS) { - storage.shift(); + // Overwrite the oldest event once full, without moving the other entries. + // Advance before notifying observers, which may read or reenter storage. + if (storage.events.length < STORAGE_MAX_EVENTS) { + storage.events.push(aEvent); + } else { + storage.events[storage.next] = aEvent; + if (++storage.next === STORAGE_MAX_EVENTS) { + storage.next = 0; + } } Services.obs.notifyObservers(aEvent, "console-api-log-event", aOuterId); diff --git a/dom/console/moz.build b/dom/console/moz.build index d18b089626..ce2ae8d054 100644 --- a/dom/console/moz.build +++ b/dom/console/moz.build @@ -40,5 +40,6 @@ LOCAL_INCLUDES += [ MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ] MOCHITEST_CHROME_MANIFESTS += [ 'tests/chrome.ini' ] +XPCSHELL_TESTS_MANIFESTS += [ 'tests/xpcshell.ini' ] FINAL_LIBRARY = 'xul' diff --git a/dom/console/tests/test_console_storage_ring.js b/dom/console/tests/test_console_storage_ring.js new file mode 100644 index 0000000000..a4e3dbeee8 --- /dev/null +++ b/dom/console/tests/test_console_storage_ring.js @@ -0,0 +1,53 @@ +function run_test() { + const storage = Components.classes["@mozilla.org/consoleAPI-storage;1"] + .getService(Components.interfaces.nsIConsoleAPIStorage); + Components.utils.import("resource://gre/modules/Services.jsm"); + storage.clearEvents(); + try { + for (let i = 0; i < 3501; i++) { + storage.recordEvent("ring-test", "outer", { timeStamp: i }); + if (i === 998 || i === 999 || i === 1000 || i === 1999 || i === 3500) { + let events = storage.getEvents("ring-test"); + equal(events.length, Math.min(i + 1, 1000)); + for (let j = 0; j < events.length; j++) { + equal(events[j].timeStamp, i + 1 - events.length + j); + } + events.length = 0; + equal(storage.getEvents("ring-test").length, Math.min(i + 1, 1000)); + } + } + storage.recordEvent("other", "outer", { timeStamp: 2500.5 }); + let all = storage.getEvents(); + equal(all.length, 1001); + equal(all[0].timeStamp, 2500.5); + equal(all[1].timeStamp, 2501); + equal(all[1000].timeStamp, 3500); + + let reentered = false; + let observer = { + observe(subject, topic, data) { + if (data === "ring-test" && !reentered) { + equal(storage.getEvents(data)[999].timeStamp, 3501); + reentered = true; + storage.recordEvent("ring-test", "outer", { timeStamp: 3502 }); + } + } + }; + Services.obs.addObserver(observer, "console-storage-cache-event", false); + try { + storage.recordEvent("ring-test", "outer", { timeStamp: 3501 }); + } finally { + Services.obs.removeObserver(observer, "console-storage-cache-event"); + } + equal(reentered, true); + equal(storage.getEvents("ring-test")[999].timeStamp, 3502); + storage.clearEvents("ring-test"); + equal(storage.getEvents("ring-test").length, 0); + equal(storage.getEvents("other").length, 1); + storage.recordEvent("ring-test", "outer", { timeStamp: 4000 }); + equal(storage.getEvents("ring-test")[0].timeStamp, 4000); + } finally { + storage.clearEvents(); + } + equal(storage.getEvents().length, 0); +} diff --git a/dom/console/tests/xpcshell.ini b/dom/console/tests/xpcshell.ini new file mode 100644 index 0000000000..7d3af0c96c --- /dev/null +++ b/dom/console/tests/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = +tail = + +[test_console_storage_ring.js] diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h index 10eec1c94a..8c0bee04c6 100644 --- a/dom/media/MediaPrefs.h +++ b/dom/media/MediaPrefs.h @@ -112,7 +112,7 @@ private: DECL_MEDIA_PREF("media.ffmpeg.skip_loop_filter", FFmpegSkipLoopFilter, bool, false); #endif #ifdef MOZ_AV1 - DECL_MEDIA_PREF("media.av1.enabled", AV1Enabled, bool, false); + DECL_MEDIA_PREF("media.av1.enabled", AV1Enabled, bool, true); #endif #ifdef XP_WIN DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true); diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp deleted file mode 100644 index 1a6aca483f..0000000000 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */ - -#include "AOMDecoder.h" -#include "MediaResult.h" -#include "TimeUnits.h" -#include "aom/aomdx.h" -#include "aom/aom_image.h" -#include "gfx2DGlue.h" -#include "mozilla/PodOperations.h" -#include "mozilla/SyncRunnable.h" -#include "nsError.h" -#include "prsystem.h" - -#include - -#undef LOG -#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("AOMDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) - -namespace mozilla { - -using namespace gfx; -using namespace layers; - -AOMDecoder::AOMDecoder(const CreateDecoderParams& aParams) - : mImageContainer(aParams.mImageContainer) - , mTaskQueue(aParams.mTaskQueue) - , mCallback(aParams.mCallback) - , mIsFlushing(false) - , mInfo(aParams.VideoConfig()) -{ - PodZero(&mCodec); -} - -AOMDecoder::~AOMDecoder() -{ -} - -void -AOMDecoder::Shutdown() -{ - aom_codec_destroy(&mCodec); -} - -RefPtr -AOMDecoder::Init() -{ - int decode_threads = 2; - - aom_codec_iface_t* dx = aom_codec_av1_dx(); - if (mInfo.mDisplay.width >= 2048) { - decode_threads = 8; - } - else if (mInfo.mDisplay.width >= 1024) { - decode_threads = 4; - } - decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors()); - - aom_codec_dec_cfg_t config; - PodZero(&config); - config.threads = decode_threads; - config.w = config.h = 0; // set after decode - config.allow_lowbitdepth = true; - - aom_codec_flags_t flags = 0; - - if (!dx || aom_codec_dec_init(&mCodec, dx, &config, flags)) { - return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); - } - return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__); -} - -void -AOMDecoder::Flush() -{ - MOZ_ASSERT(mCallback->OnReaderTaskQueue()); - mIsFlushing = true; - nsCOMPtr r = NS_NewRunnableFunction([this] () { - // nothing to do for now. - }); - SyncRunnable::DispatchToThread(mTaskQueue, r); - mIsFlushing = false; -} - -// Ported from third_party/aom/tools_common.c. -static aom_codec_err_t -highbd_img_downshift(aom_image_t *dst, aom_image_t *src, int down_shift) { - int plane; - if (dst->d_w != src->d_w || dst->d_h != src->d_h) - return AOM_CODEC_INVALID_PARAM; - if (dst->x_chroma_shift != src->x_chroma_shift) - return AOM_CODEC_INVALID_PARAM; - if (dst->y_chroma_shift != src->y_chroma_shift) - return AOM_CODEC_INVALID_PARAM; - if (dst->fmt != (src->fmt & ~AOM_IMG_FMT_HIGHBITDEPTH)) - return AOM_CODEC_INVALID_PARAM; - if (down_shift < 0) - return AOM_CODEC_INVALID_PARAM; - switch (dst->fmt) { - case AOM_IMG_FMT_I420: - case AOM_IMG_FMT_I422: - case AOM_IMG_FMT_I444: - break; - default: - return AOM_CODEC_INVALID_PARAM; - } - switch (src->fmt) { - case AOM_IMG_FMT_I42016: - case AOM_IMG_FMT_I42216: - case AOM_IMG_FMT_I44416: - break; - default: - // We don't support anything that's not 16 bit - return AOM_CODEC_UNSUP_BITSTREAM; - } - for (plane = 0; plane < 3; plane++) { - int w = src->d_w; - int h = src->d_h; - int x, y; - if (plane) { - w = (w + src->x_chroma_shift) >> src->x_chroma_shift; - h = (h + src->y_chroma_shift) >> src->y_chroma_shift; - } - for (y = 0; y < h; y++) { - uint16_t *p_src = - (uint16_t *)(src->planes[plane] + y * src->stride[plane]); - uint8_t *p_dst = - dst->planes[plane] + y * dst->stride[plane]; - for (x = 0; x < w; x++) *p_dst++ = (*p_src++ >> down_shift) & 0xFF; - } - } - return AOM_CODEC_OK; -} - -// UniquePtr dtor wrapper for aom_image_t. -struct AomImageFree { - void operator()(aom_image_t* img) { aom_img_free(img); } -}; - -MediaResult -AOMDecoder::DoDecode(MediaRawData* aSample) -{ - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - -#if defined(DEBUG) - NS_ASSERTION(IsKeyframe(*aSample) == aSample->mKeyframe, - "AOM Decode Keyframe error sample->mKeyframe and si.si_kf out of sync"); -#endif - - if (aom_codec_err_t r = aom_codec_decode(&mCodec, aSample->Data(), aSample->Size(), nullptr)) { - LOG("AOM Decode error: %s", aom_codec_err_to_string(r)); - return MediaResult( - NS_ERROR_DOM_MEDIA_DECODE_ERR, - RESULT_DETAIL("AOM error decoding AV1 sample: %s", aom_codec_err_to_string(r))); - } - - aom_codec_iter_t iter = nullptr; - aom_image_t *img; - UniquePtr img8; - - while ((img = aom_codec_get_frame(&mCodec, &iter))) { - // Track whether the underlying buffer is 8 or 16 bits per channel. - bool highbd = bool(img->fmt & AOM_IMG_FMT_HIGHBITDEPTH); - if (highbd) { - // Downsample images with more than 8 bits per channel. - aom_img_fmt_t fmt8 = static_cast(img->fmt ^ AOM_IMG_FMT_HIGHBITDEPTH); - img8.reset(aom_img_alloc(NULL, fmt8, img->d_w, img->d_h, 16)); - if (img8 == nullptr) { - LOG("Couldn't allocate bitdepth reduction target!"); - return MediaResult( - NS_ERROR_OUT_OF_MEMORY, - RESULT_DETAIL("Couldn't allocate conversion buffer for AV1 frame")); - } - if (aom_codec_err_t r = highbd_img_downshift(img8.get(), img, img->bit_depth - 8)) { - return MediaResult( - NS_ERROR_DOM_MEDIA_DECODE_ERR, - RESULT_DETAIL("Error converting AV1 frame to 8 bits: %s", - aom_codec_err_to_string(r))); - } - // img normally points to storage owned by mCodec, so it is not freed. - // To copy out the contents of img8 we can overwrite img with an alias. - // Since img is assigned at the start of the while loop and img8 is held - // outside that loop, the alias won't outlive the storage it points to. - img = img8.get(); - highbd = false; - } - - NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 || - img->fmt == AOM_IMG_FMT_I42016 || - img->fmt == AOM_IMG_FMT_I444 || - img->fmt == AOM_IMG_FMT_I44416, - "AV1 image format not I420 or I444"); - - // Chroma shifts are rounded down as per the decoding examples in the SDK - VideoData::YCbCrBuffer b; - b.mPlanes[0].mData = img->planes[0]; - b.mPlanes[0].mStride = img->stride[0]; - b.mPlanes[0].mHeight = img->d_h; - b.mPlanes[0].mWidth = img->d_w; - b.mPlanes[0].mOffset = 0; - b.mPlanes[0].mSkip = highbd ? 1 : 0; - - b.mPlanes[1].mData = img->planes[1]; - b.mPlanes[1].mStride = img->stride[1]; - b.mPlanes[1].mOffset = 0; - b.mPlanes[1].mSkip = highbd ? 1 : 0; - - b.mPlanes[2].mData = img->planes[2]; - b.mPlanes[2].mStride = img->stride[2]; - b.mPlanes[2].mOffset = 0; - b.mPlanes[2].mSkip = highbd ? 1 : 0; - - if (img->fmt == AOM_IMG_FMT_I420 || - img->fmt == AOM_IMG_FMT_I42016) { - b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift; - b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift; - - b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift; - b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift; - } else if (img->fmt == AOM_IMG_FMT_I444) { - b.mPlanes[1].mHeight = img->d_h; - b.mPlanes[1].mWidth = img->d_w; - - b.mPlanes[2].mHeight = img->d_h; - b.mPlanes[2].mWidth = img->d_w; - } else { - LOG("AOM Unknown image format"); - return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, - RESULT_DETAIL("AOM Unknown image format")); - } - - switch (img->mc) { - case AOM_CICP_MC_BT_601: - b.mYUVColorSpace = YUVColorSpace::BT601; - break; - case AOM_CICP_MC_BT_709: - b.mYUVColorSpace = YUVColorSpace::BT709; - break; - case AOM_CICP_MC_IDENTITY: - b.mYUVColorSpace = YUVColorSpace::IDENTITY; - break; - default: - LOG("Unhandled colorspace %d", img->mc); - break; - } - b.mColorRange = img->range == AOM_CR_FULL_RANGE ? ColorRange::FULL - : ColorRange::LIMITED; - - RefPtr v = - VideoData::CreateAndCopyData(mInfo, - mImageContainer, - aSample->mOffset, - aSample->mTime, - aSample->mDuration, - b, - aSample->mKeyframe, - aSample->mTimecode, - mInfo.ScaledImageRect(img->d_w, - img->d_h)); - - if (!v) { - LOG("Image allocation error source %ux%u display %ux%u picture %ux%u", - img->d_w, img->d_h, mInfo.mDisplay.width, mInfo.mDisplay.height, - mInfo.mImage.width, mInfo.mImage.height); - return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__); - } - mCallback->Output(v); - } - return NS_OK; -} - -void -AOMDecoder::ProcessDecode(MediaRawData* aSample) -{ - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - if (mIsFlushing) { - return; - } - MediaResult rv = DoDecode(aSample); - if (NS_FAILED(rv)) { - mCallback->Error(rv); - } else { - mCallback->InputExhausted(); - } -} - -void -AOMDecoder::Input(MediaRawData* aSample) -{ - MOZ_ASSERT(mCallback->OnReaderTaskQueue()); - mTaskQueue->Dispatch(NewRunnableMethod>( - this, &AOMDecoder::ProcessDecode, aSample)); -} - -void -AOMDecoder::ProcessDrain() -{ - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - mCallback->DrainComplete(); -} - -void -AOMDecoder::Drain() -{ - MOZ_ASSERT(mCallback->OnReaderTaskQueue()); - mTaskQueue->Dispatch(NewRunnableMethod(this, &AOMDecoder::ProcessDrain)); -} - -/* static */ -bool -AOMDecoder::IsAV1(const nsACString& aMimeType) -{ - return aMimeType.EqualsLiteral("video/webm; codecs=av1") || - aMimeType.EqualsLiteral("video/av1"); -} - -/* static */ -bool -AOMDecoder::IsKeyframe(Span aBuffer) { - aom_codec_stream_info_t info; - PodZero(&info); - - aom_codec_peek_stream_info(aom_codec_av1_dx(), - aBuffer.Elements(), - aBuffer.Length(), - &info); - - return bool(info.is_kf); -} - -/* static */ -nsIntSize -AOMDecoder::GetFrameSize(Span aBuffer) { - aom_codec_stream_info_t info; - PodZero(&info); - - aom_codec_peek_stream_info(aom_codec_av1_dx(), - aBuffer.Elements(), - aBuffer.Length(), - &info); - - return nsIntSize(info.w, info.h); -} - -} // namespace mozilla -#undef LOG diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp index 10432ad493..a1ba164289 100644 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp @@ -13,7 +13,7 @@ #include "TheoraDecoder.h" #ifdef MOZ_AV1 -#include "AOMDecoder.h" +#include "Dav1dDecoder.h" #endif namespace mozilla { @@ -30,7 +30,7 @@ AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType, TheoraDecoder::IsTheora(aMimeType); #ifdef MOZ_AV1 if (MediaPrefs::AV1Enabled()) { - supports |= AOMDecoder::IsAV1(aMimeType); + supports |= Dav1dDecoder::IsAV1(aMimeType); } #endif MOZ_LOG(sPDMLog, LogLevel::Debug, ("Agnostic decoder %s requested type", @@ -47,9 +47,9 @@ AgnosticDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) m = new VPXDecoder(aParams); } #ifdef MOZ_AV1 - else if (AOMDecoder::IsAV1(aParams.mConfig.mMimeType) && + else if (Dav1dDecoder::IsAV1(aParams.mConfig.mMimeType) && MediaPrefs::AV1Enabled()) { - m = new AOMDecoder(aParams); + m = new Dav1dDecoder(aParams); } #endif else if (TheoraDecoder::IsTheora(aParams.mConfig.mMimeType)) { diff --git a/dom/media/platforms/agnostic/Dav1dDecoder.cpp b/dom/media/platforms/agnostic/Dav1dDecoder.cpp new file mode 100644 index 0000000000..9a94374251 --- /dev/null +++ b/dom/media/platforms/agnostic/Dav1dDecoder.cpp @@ -0,0 +1,376 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */ + +#include "Dav1dDecoder.h" +#include "MediaResult.h" +#include "TimeUnits.h" +#include "dav1d/dav1d.h" +#include "mozilla/CheckedInt.h" +#include "mozilla/PodOperations.h" +#include "mozilla/SyncRunnable.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/UniquePtrExtensions.h" +#include "nsError.h" +#include "prsystem.h" + +#include +#include +#include + +#undef LOG +#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("Dav1dDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) + +namespace mozilla { + +using namespace gfx; +using namespace layers; + +Dav1dDecoder::Dav1dDecoder(const CreateDecoderParams& aParams) + : mImageContainer(aParams.mImageContainer) + , mTaskQueue(aParams.mTaskQueue) + , mCallback(aParams.mCallback) + , mIsFlushing(false) + , mDecoder(nullptr) + , mInfo(aParams.VideoConfig()) +{ +} + +Dav1dDecoder::~Dav1dDecoder() +{ +} + +void +Dav1dDecoder::Shutdown() +{ + if (mDecoder) { + dav1d_close(&mDecoder); + } +} + +RefPtr +Dav1dDecoder::Init() +{ + int decodeThreads = 2; + if (mInfo.mDisplay.width >= 2048) { + decodeThreads = 8; + } else if (mInfo.mDisplay.width >= 1024) { + decodeThreads = 4; + } + decodeThreads = std::min(decodeThreads, PR_GetNumberOfProcessors()); + + Dav1dSettings settings; + dav1d_default_settings(&settings); + settings.n_threads = decodeThreads; + settings.logger.callback = nullptr; + + if (dav1d_open(&mDecoder, &settings) < 0) { + return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); + } + return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__); +} + +void +Dav1dDecoder::Flush() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mIsFlushing = true; + nsCOMPtr r = NS_NewRunnableFunction([this] () { + if (mDecoder) { + dav1d_flush(mDecoder); + } + }); + SyncRunnable::DispatchToThread(mTaskQueue, r); + mIsFlushing = false; +} + +static bool +GetPlaneSize(int aWidth, int aHeight, size_t* aSize) +{ + CheckedInt size = aWidth; + size *= aHeight; + if (!size.isValid()) { + return false; + } + *aSize = size.value(); + return true; +} + +static void +DownshiftPlane(uint8_t* aDst, int aDstStride, const uint8_t* aSrc, + ptrdiff_t aSrcStride, int aWidth, int aHeight, int aShift) +{ + for (int y = 0; y < aHeight; y++) { + const uint16_t* src = + reinterpret_cast(aSrc + y * aSrcStride); + uint8_t* dst = aDst + y * aDstStride; + for (int x = 0; x < aWidth; x++) { + dst[x] = (src[x] >> aShift) & 0xff; + } + } +} + +MediaResult +Dav1dDecoder::OutputPicture(const Dav1dPicture& aPicture) +{ + const int width = aPicture.p.w; + const int height = aPicture.p.h; + if (width <= 0 || height <= 0) { + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("dav1d returned invalid AV1 picture size")); + } + + int chromaWidth = width; + int chromaHeight = height; + switch (aPicture.p.layout) { + case DAV1D_PIXEL_LAYOUT_I420: + chromaWidth = (width + 1) >> 1; + chromaHeight = (height + 1) >> 1; + break; + case DAV1D_PIXEL_LAYOUT_I422: + chromaWidth = (width + 1) >> 1; + chromaHeight = height; + break; + case DAV1D_PIXEL_LAYOUT_I444: + break; + default: + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("dav1d returned unsupported AV1 pixel layout: %d", + int(aPicture.p.layout))); + } + + const int planeWidths[3] = { width, chromaWidth, chromaWidth }; + const int planeHeights[3] = { height, chromaHeight, chromaHeight }; + const ptrdiff_t srcStrides[3] = { + aPicture.stride[0], + aPicture.stride[1], + aPicture.stride[1] + }; + uint8_t* planeData[3] = { + static_cast(aPicture.data[0]), + static_cast(aPicture.data[1]), + static_cast(aPicture.data[2]) + }; + uint32_t planeStrides[3] = { 0, 0, 0 }; + UniquePtr downshifted[3]; + + if (aPicture.p.bpc > 8) { + const int shift = aPicture.p.bpc - 8; + for (int plane = 0; plane < 3; plane++) { + size_t planeSize; + if (!GetPlaneSize(planeWidths[plane], planeHeights[plane], &planeSize)) { + return MediaResult(NS_ERROR_OUT_OF_MEMORY, + RESULT_DETAIL("AV1 downshift plane size overflow")); + } + downshifted[plane] = MakeUniqueFallible(planeSize); + if (!downshifted[plane]) { + return MediaResult(NS_ERROR_OUT_OF_MEMORY, + RESULT_DETAIL("Couldn't allocate AV1 conversion buffer")); + } + DownshiftPlane(downshifted[plane].get(), planeWidths[plane], + planeData[plane], srcStrides[plane], + planeWidths[plane], planeHeights[plane], shift); + planeData[plane] = downshifted[plane].get(); + planeStrides[plane] = planeWidths[plane]; + } + } else { + for (int plane = 0; plane < 3; plane++) { + CheckedInt stride(srcStrides[plane]); + if (srcStrides[plane] < 0 || !stride.isValid()) { + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("dav1d returned invalid AV1 stride")); + } + planeStrides[plane] = stride.value(); + } + } + + VideoData::YCbCrBuffer b; + for (int plane = 0; plane < 3; plane++) { + b.mPlanes[plane].mData = planeData[plane]; + b.mPlanes[plane].mStride = planeStrides[plane]; + b.mPlanes[plane].mHeight = planeHeights[plane]; + b.mPlanes[plane].mWidth = planeWidths[plane]; + b.mPlanes[plane].mOffset = 0; + b.mPlanes[plane].mSkip = 0; + } + + if (aPicture.seq_hdr) { + switch (aPicture.seq_hdr->mtrx) { + case DAV1D_MC_BT601: + case DAV1D_MC_BT470BG: + b.mYUVColorSpace = YUVColorSpace::BT601; + break; + case DAV1D_MC_BT709: + b.mYUVColorSpace = YUVColorSpace::BT709; + break; + case DAV1D_MC_IDENTITY: + b.mYUVColorSpace = YUVColorSpace::IDENTITY; + break; + default: + LOG("Unhandled colorspace %d", aPicture.seq_hdr->mtrx); + break; + } + b.mColorRange = aPicture.seq_hdr->color_range ? ColorRange::FULL + : ColorRange::LIMITED; + } + + const int64_t time = + aPicture.m.timestamp == INT64_MIN ? 0 : aPicture.m.timestamp; + const int64_t duration = aPicture.m.duration; + const int64_t offset = aPicture.m.offset; + const bool keyframe = + aPicture.frame_hdr && + aPicture.frame_hdr->frame_type == DAV1D_FRAME_TYPE_KEY; + + RefPtr v = + VideoData::CreateAndCopyData(mInfo, + mImageContainer, + offset, + time, + duration, + b, + keyframe, + time, + mInfo.ScaledImageRect(width, height)); + + if (!v) { + LOG("Image allocation error source %dx%d display %ux%u picture %ux%u", + width, height, mInfo.mDisplay.width, mInfo.mDisplay.height, + mInfo.mImage.width, mInfo.mImage.height); + return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__); + } + mCallback->Output(v); + return NS_OK; +} + +MediaResult +Dav1dDecoder::DrainOutput() +{ + while (true) { + Dav1dPicture picture; + PodZero(&picture); + const int res = dav1d_get_picture(mDecoder, &picture); + if (res == DAV1D_ERR(EAGAIN)) { + return NS_OK; + } + if (res < 0) { + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("dav1d error getting AV1 picture: %d", + res)); + } + + MediaResult rv = OutputPicture(picture); + dav1d_picture_unref(&picture); + if (NS_FAILED(rv)) { + return rv; + } + } +} + +MediaResult +Dav1dDecoder::DoDecode(MediaRawData* aSample) +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + + Dav1dData data; + PodZero(&data); + uint8_t* dst = dav1d_data_create(&data, aSample->Size()); + if (!dst) { + return MediaResult(NS_ERROR_OUT_OF_MEMORY, + RESULT_DETAIL("Couldn't allocate dav1d AV1 input buffer")); + } + memcpy(dst, aSample->Data(), aSample->Size()); + data.m.timestamp = aSample->mTime; + data.m.duration = aSample->mDuration; + data.m.offset = aSample->mOffset; + data.m.size = aSample->Size(); + + while (data.sz) { + const int res = dav1d_send_data(mDecoder, &data); + if (res == DAV1D_ERR(EAGAIN)) { + MediaResult rv = DrainOutput(); + if (NS_FAILED(rv)) { + dav1d_data_unref(&data); + return rv; + } + continue; + } + if (res < 0) { + dav1d_data_unref(&data); + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("dav1d error decoding AV1 sample: %d", + res)); + } + } + + dav1d_data_unref(&data); + return DrainOutput(); +} + +void +Dav1dDecoder::ProcessDecode(MediaRawData* aSample) +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + if (mIsFlushing) { + return; + } + MediaResult rv = DoDecode(aSample); + if (NS_FAILED(rv)) { + mCallback->Error(rv); + } else { + mCallback->InputExhausted(); + } +} + +void +Dav1dDecoder::Input(MediaRawData* aSample) +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mTaskQueue->Dispatch(NewRunnableMethod>( + this, &Dav1dDecoder::ProcessDecode, aSample)); +} + +void +Dav1dDecoder::ProcessDrain() +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + MediaResult rv = DrainOutput(); + if (NS_FAILED(rv)) { + mCallback->Error(rv); + } else { + mCallback->DrainComplete(); + } +} + +void +Dav1dDecoder::Drain() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &Dav1dDecoder::ProcessDrain)); +} + +/* static */ +bool +Dav1dDecoder::IsAV1(const nsACString& aMimeType) +{ + return aMimeType.EqualsLiteral("video/webm; codecs=av1") || + aMimeType.EqualsLiteral("video/av1"); +} + +/* static */ +nsIntSize +Dav1dDecoder::GetFrameSize(Span aBuffer) +{ + Dav1dSequenceHeader seqHdr; + PodZero(&seqHdr); + if (dav1d_parse_sequence_header(&seqHdr, + aBuffer.Elements(), + aBuffer.Length()) < 0) { + return nsIntSize(0, 0); + } + return nsIntSize(seqHdr.max_width, seqHdr.max_height); +} + +} // namespace mozilla +#undef LOG diff --git a/dom/media/platforms/agnostic/AOMDecoder.h b/dom/media/platforms/agnostic/Dav1dDecoder.h similarity index 69% rename from dom/media/platforms/agnostic/AOMDecoder.h rename to dom/media/platforms/agnostic/Dav1dDecoder.h index 73b3be67c7..e8b1c6aee3 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.h +++ b/dom/media/platforms/agnostic/Dav1dDecoder.h @@ -3,21 +3,23 @@ * 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/. */ -#if !defined(AOMDecoder_h_) -#define AOMDecoder_h_ +#if !defined(Dav1dDecoder_h_) +#define Dav1dDecoder_h_ #include "PlatformDecoderModule.h" #include "mozilla/Span.h" #include -#include "aom/aom_decoder.h" + +typedef struct Dav1dContext Dav1dContext; +typedef struct Dav1dPicture Dav1dPicture; namespace mozilla { -class AOMDecoder : public MediaDataDecoder +class Dav1dDecoder : public MediaDataDecoder { public: - explicit AOMDecoder(const CreateDecoderParams& aParams); + explicit Dav1dDecoder(const CreateDecoderParams& aParams); RefPtr Init() override; void Input(MediaRawData* aSample) override; @@ -26,23 +28,22 @@ public: void Shutdown() override; const char* GetDescriptionName() const override { - return "libaom (AV1) video decoder"; + return "dav1d (AV1) video decoder"; } // Return true if aMimeType is a one of the strings used // by our demuxers to identify AV1 streams. static bool IsAV1(const nsACString& aMimeType); - // Return true if a sample is a keyframe. - static bool IsKeyframe(Span aBuffer); - - // Return the frame dimensions for a sample. + // Return the frame dimensions from a sequence header, when one is present. static nsIntSize GetFrameSize(Span aBuffer); private: - ~AOMDecoder(); + ~Dav1dDecoder(); void ProcessDecode(MediaRawData* aSample); MediaResult DoDecode(MediaRawData* aSample); + MediaResult DrainOutput(); + MediaResult OutputPicture(const Dav1dPicture& aPicture); void ProcessDrain(); const RefPtr mImageContainer; @@ -50,12 +51,11 @@ private: MediaDataDecoderCallback* mCallback; Atomic mIsFlushing; - // AOM decoder state - aom_codec_ctx_t mCodec; + Dav1dContext* mDecoder; const VideoInfo& mInfo; }; } // namespace mozilla -#endif // AOMDecoder_h_ +#endif // Dav1dDecoder_h_ diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 2997ffa8d7..6e8e1bcf30 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -58,10 +58,10 @@ if CONFIG['MOZ_FFMPEG']: if CONFIG['MOZ_AV1']: EXPORTS += [ - 'agnostic/AOMDecoder.h', + 'agnostic/Dav1dDecoder.h', ] UNIFIED_SOURCES += [ - 'agnostic/AOMDecoder.cpp', + 'agnostic/Dav1dDecoder.cpp', ] if CONFIG['MOZ_APPLEMEDIA']: diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp index da534b1cf5..24f02a43a2 100644 --- a/dom/media/webm/WebMDecoder.cpp +++ b/dom/media/webm/WebMDecoder.cpp @@ -4,9 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Preferences.h" -#ifdef MOZ_AV1 -#include "AOMDecoder.h" -#endif #include "MediaPrefs.h" #include "MediaDecoderStateMachine.h" #include "WebMDemuxer.h" @@ -136,4 +133,3 @@ WebMDecoder::GetMozDebugReaderData(nsAString& aString) } } // namespace mozilla - diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index fc98db4d77..a5dbdc52c7 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -8,7 +8,7 @@ #include "AbstractMediaDecoder.h" #include "MediaResource.h" #ifdef MOZ_AV1 -#include "AOMDecoder.h" +#include "Dav1dDecoder.h" #endif #include "OpusDecoder.h" #include "VPXDecoder.h" @@ -711,7 +711,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl break; #ifdef MOZ_AV1 case NESTEGG_CODEC_AV1: - isKeyframe = AOMDecoder::IsKeyframe(sample); + isKeyframe = nestegg_packet_has_keyframe(holder->Packet()) == NESTEGG_PACKET_HAS_KEYFRAME_TRUE; break; #endif case NESTEGG_CODEC_AVC1: @@ -734,16 +734,18 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl break; #ifdef MOZ_AV1 case NESTEGG_CODEC_AV1: - dimensions = AOMDecoder::GetFrameSize(sample); + dimensions = Dav1dDecoder::GetFrameSize(sample); break; #endif } - if (mLastSeenFrameSize.isSome() - && (dimensions != mLastSeenFrameSize.value())) { - mInfo.mVideo.mDisplay = dimensions; - mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID); + if (dimensions.width > 0 && dimensions.height > 0) { + if (mLastSeenFrameSize.isSome() + && (dimensions != mLastSeenFrameSize.value())) { + mInfo.mVideo.mDisplay = dimensions; + mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID); + } + mLastSeenFrameSize = Some(dimensions); } - mLastSeenFrameSize = Some(dimensions); } } } @@ -751,7 +753,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl WEBM_DEBUG("push sample tstamp: %ld next_tstamp: %ld length: %ld kf: %d", tstamp, next_tstamp, length, isKeyframe); RefPtr sample; - if (mInfo.mVideo.HasAlpha() && alphaLength != 0) { + if (mInfo.mVideo.HasAlpha() && alphaData != 0) { sample = new MediaRawData(data, length, alphaData, alphaLength); if (length && !sample->Data() || (alphaLength && !sample->AlphaData())) { // OOM. diff --git a/dom/media/webm/moz.build b/dom/media/webm/moz.build index e9387e8c98..b1926d9a04 100644 --- a/dom/media/webm/moz.build +++ b/dom/media/webm/moz.build @@ -24,6 +24,11 @@ if CONFIG['MOZ_WEBM_ENCODER']: 'WebMWriter.cpp', ] +if CONFIG['MOZ_AV1']: + LOCAL_INCLUDES += [ + '/dom/media/platforms/agnostic', + ] + CXXFLAGS += CONFIG['MOZ_LIBVPX_CFLAGS'] FINAL_LIBRARY = 'xul' diff --git a/dom/performance/PerformanceObserver.cpp b/dom/performance/PerformanceObserver.cpp index 7084ca0fba..6c5a60feed 100644 --- a/dom/performance/PerformanceObserver.cpp +++ b/dom/performance/PerformanceObserver.cpp @@ -10,9 +10,11 @@ #include "mozilla/dom/PerformanceEntryBinding.h" #include "mozilla/dom/PerformanceObserverBinding.h" #include "nsIScriptError.h" +#include "nsHashKeys.h" #include "nsPIDOMWindow.h" #include "nsQueryObject.h" #include "nsString.h" +#include "nsTHashtable.h" #include "PerformanceEntry.h" #include "PerformanceObserverEntryList.h" #include "WorkerPrivate.h" @@ -225,19 +227,28 @@ void PerformanceObserver::Observe(const PerformanceObserverInit& aOptions, } /* 3.3.1.5.2 */ + nsTHashtable requestedTypes(entryTypes.Length()); + for (const auto& type : entryTypes) { + requestedTypes.PutEntry(type); + } + nsTArray validEntryTypes; for (const char16_t* name : sValidTypeNames) { nsDependentString validTypeName(name); - if (entryTypes.Contains(validTypeName) && - !validEntryTypes.Contains(validTypeName)) { + if (requestedTypes.GetEntry(validTypeName)) { validEntryTypes.AppendElement(validTypeName); } } + nsTHashtable validTypeSet(validEntryTypes.Length()); + for (const auto& validType : validEntryTypes) { + validTypeSet.PutEntry(validType); + } + nsAutoString invalidTypesJoined; bool addComma = false; for (const auto& type : entryTypes) { - if (!validEntryTypes.Contains(type)) { + if (!validTypeSet.GetEntry(type)) { if (addComma) { invalidTypesJoined.AppendLiteral(", "); } @@ -289,13 +300,13 @@ void PerformanceObserver::Observe(const PerformanceObserverInit& aOptions, /* 3.3.1.6.4, 3.3.1.6.4 */ bool didUpdateOptionsList = false; - nsTArray updatedOptionsList; + nsTArray updatedOptionsList(mOptions.Length() + 1); for (auto& option : mOptions) { if (option.mType.WasPassed() && option.mType.Value() == type) { updatedOptionsList.AppendElement(aOptions); didUpdateOptionsList = true; } else { - updatedOptionsList.AppendElement(option); + updatedOptionsList.AppendElement(Move(option)); } } if (!didUpdateOptionsList) { diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index c0b970e58a..acf5027949 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -2334,8 +2334,7 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) } if (aRequest->IsModuleRequest()) { - // For modules, currentScript is set to null. - AutoCurrentScriptUpdater scriptUpdater(this, nullptr); + AutoCurrentScriptUpdater scriptUpdater(this, aRequest->Element()); ModuleLoadRequest* request = aRequest->AsModuleRequest(); MOZ_ASSERT(request->mModuleScript); diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index f63b1de981..65f778b5f9 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -301,6 +301,7 @@ LoadContextOptions(const char* aPrefName, void* /* aClosure */) .setAsyncStack(GetWorkerPref(NS_LITERAL_CSTRING("asyncstack"))) .setWerror(GetWorkerPref(NS_LITERAL_CSTRING("werror"))) .setStreams(GetWorkerPref(NS_LITERAL_CSTRING("streams"))) + .setWeakRefs(GetWorkerPref(NS_LITERAL_CSTRING("weakrefs"))) .setExtraWarnings(GetWorkerPref(NS_LITERAL_CSTRING("strict"))) .setArrayProtoValues(GetWorkerPref( NS_LITERAL_CSTRING("array_prototype_values"))); diff --git a/dom/workers/WorkerPrefs.h b/dom/workers/WorkerPrefs.h index 87806a6fbc..d870ac8e46 100644 --- a/dom/workers/WorkerPrefs.h +++ b/dom/workers/WorkerPrefs.h @@ -35,6 +35,7 @@ WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, O WORKER_SIMPLE_PREF("dom.storageManager.enabled", StorageManagerEnabled, STORAGEMANAGER_ENABLED) WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED) WORKER_SIMPLE_PREF("dom.streams.enabled", StreamsEnabled, STREAMS_ENABLED) +WORKER_SIMPLE_PREF("javascript.options.weakrefs", WeakRefsEnabled, WEAKREFS_ENABLED) WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED) WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED) WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK) diff --git a/gfx/angle/src/image_util/loadimage.cpp b/gfx/angle/src/image_util/loadimage.cpp index 56ad3b32e3..3a041b8c8e 100644 --- a/gfx/angle/src/image_util/loadimage.cpp +++ b/gfx/angle/src/image_util/loadimage.cpp @@ -25,7 +25,7 @@ void LoadA8ToRGBA8(size_t width, size_t outputRowPitch, size_t outputDepthPitch) { -#if defined(ANGLE_USE_SSE) +#if defined(ANGLE_USE_SSE) && !(defined(__GNUC__) && !defined(__clang__)) if (gl::supportsSSE2()) { __m128i zeroWide = _mm_setzero_si128(); @@ -594,7 +594,7 @@ void LoadRGBA8ToBGRA8(size_t width, size_t outputRowPitch, size_t outputDepthPitch) { -#if defined(ANGLE_USE_SSE) +#if defined(ANGLE_USE_SSE) && !(defined(__GNUC__) && !defined(__clang__)) if (gl::supportsSSE2()) { __m128i brMask = _mm_set1_epi32(0x00ff00ff); diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c index a2259c173a..bf2a8e9d2c 100644 --- a/gfx/cairo/cairo/src/cairo-ft-font.c +++ b/gfx/cairo/cairo/src/cairo-ft-font.c @@ -1578,7 +1578,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, if (unlikely (status)) return status; - if (cairo_image_surface_get_format (*surface) == CAIRO_FORMAT_ARGB32 && + if (cairo_image_surface_get_format ((cairo_surface_t *)*surface) == CAIRO_FORMAT_ARGB32 && !pixman_image_get_component_alpha ((*surface)->pixman_image)) image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); else diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c index c80ea8553f..e1a06dbc03 100644 --- a/gfx/cairo/cairo/src/cairo-surface.c +++ b/gfx/cairo/cairo/src/cairo-surface.c @@ -1428,7 +1428,7 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface, acquire_source_image_ptr[i] = (char*)surface->backend->acquire_source_image; } crasher = NULL; - *crasher = acquire_source_image_ptr[5]; + *crasher = (char)acquire_source_image_ptr[5]; } _cairo_debug_check_image_surface_is_defined (&(*image_out)->base); diff --git a/gfx/layers/LayerSorter.cpp b/gfx/layers/LayerSorter.cpp index ce180c374e..82a301d5b4 100644 --- a/gfx/layers/LayerSorter.cpp +++ b/gfx/layers/LayerSorter.cpp @@ -103,13 +103,23 @@ static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) { // Could we just check Contains() on the bounds rects. ie, is it possible // for layers to overlap without intersections (in 2d space) and yet still // have their bounds rects not completely enclose each other? - nsTArray points; + AutoTArray points; + auto appendUniquePoint = [&points](const gfxPoint& aPoint) { + static const gfxFloat kDuplicateEpsilon = 0.01; + for (const auto& point : points) { + if (fabs(point.x - aPoint.x) < kDuplicateEpsilon && + fabs(point.y - aPoint.y) < kDuplicateEpsilon) { + return; + } + } + points.AppendElement(aPoint); + }; for (uint32_t i = 0; i < 4; i++) { if (ourTransformedRect.Contains(otherTransformedRect.mPoints[i])) { - points.AppendElement(otherTransformedRect.mPoints[i]); + appendUniquePoint(otherTransformedRect.mPoints[i]); } if (otherTransformedRect.Contains(ourTransformedRect.mPoints[i])) { - points.AppendElement(ourTransformedRect.mPoints[i]); + appendUniquePoint(ourTransformedRect.mPoints[i]); } } @@ -123,7 +133,7 @@ static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) { gfxLineSegment two(otherTransformedRect.mPoints[j], otherTransformedRect.mPoints[(j + 1) % 4]); if (one.Intersects(two, intersection)) { - points.AppendElement(intersection); + appendUniquePoint(intersection); } } } diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index 904eaaab2d..5725fd9648 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -952,12 +952,38 @@ using namespace std; void imgCacheQueue::Remove(imgCacheEntry* entry) { - queueContainer::iterator it = find(mQueue.begin(), mQueue.end(), entry); - if (it != mQueue.end()) { - mSize -= (*it)->GetDataSize(); - mQueue.erase(it); - MarkDirty(); + uint64_t index = mQueue.IndexOf(entry); + if (index == queueContainer::NoIndex) { + return; } + + mSize -= mQueue[index]->GetDataSize(); + + // If the queue is clean and this is the first entry, + // then we can efficiently remove the entry without + // dirtying the sort order. + if (!IsDirty() && index == 0) { + std::pop_heap(mQueue.begin(), mQueue.end(), + imgLoader::CompareCacheEntries); + mQueue.RemoveElementAt(mQueue.Length() - 1); + return; + } + + // Remove from the middle of the list. This potentially + // breaks the binary heap sort order. + mQueue.RemoveElementAt(index); + + // If we only have one entry or the queue is empty, though, + // then the sort order is still effectively good. + // Simply refresh the list to clear the dirty flag. + if (mQueue.Length() <= 1) { + Refresh(); + return; + } + + // Otherwise we must mark the queue dirty and potentially + // trigger an expensive sort later. + MarkDirty(); } void @@ -966,23 +992,26 @@ imgCacheQueue::Push(imgCacheEntry* entry) mSize += entry->GetDataSize(); RefPtr refptr(entry); - mQueue.push_back(refptr); - MarkDirty(); + mQueue.AppendElement(Move(refptr)); + // If we're not dirty already, then we can efficiently add this to the binary heap immediately. + if (!IsDirty()) { + std::push_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries); + } } already_AddRefed imgCacheQueue::Pop() { - if (mQueue.empty()) { + if (mQueue.IsEmpty()) { return nullptr; } if (IsDirty()) { Refresh(); } - RefPtr entry = mQueue[0]; std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries); - mQueue.pop_back(); + RefPtr entry = Move(mQueue.LastElement()); + mQueue.RemoveElementAt(mQueue.Length() - 1); mSize -= entry->GetDataSize(); return entry.forget(); @@ -991,6 +1020,7 @@ imgCacheQueue::Pop() void imgCacheQueue::Refresh() { + // Re-heap the list. This is an O(3 * n) operation and best avoided if possible. std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries); mDirty = false; } @@ -1010,7 +1040,13 @@ imgCacheQueue::IsDirty() uint32_t imgCacheQueue::GetNumElements() const { - return mQueue.size(); + return mQueue.Length(); +} + +bool +imgCacheQueue::Contains(imgCacheEntry* aEntry) const +{ + return mQueue.Contains(aEntry); } imgCacheQueue::iterator @@ -1602,7 +1638,11 @@ void imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */) { imgCacheQueue& queue = GetCacheQueue(aForChrome); - queue.MarkDirty(); + // We only need to dirty the queue if there is any sorting taking place. + // Empty or single-entry lists can't become dirty. + if (queue.GetNumElements() > 1) { + queue.MarkDirty(); + } queue.UpdateSize(aSizeDiff); } @@ -1631,7 +1671,9 @@ imgLoader::CheckCacheLimits(imgCacheTable& cache, imgCacheQueue& queue) } if (entry) { - RemoveFromCache(entry); + // We just popped this entry from the queue, so pass AlreadyRemoved + // to avoid searching the queue again in RemoveFromCache. + RemoveFromCache(entry, QueueState::AlreadyRemoved); } } } @@ -1930,7 +1972,7 @@ imgLoader::RemoveFromCache(const ImageCacheKey& aKey) } bool -imgLoader::RemoveFromCache(imgCacheEntry* entry) +imgLoader::RemoveFromCache(imgCacheEntry* entry, QueueState aQueueState) { LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry"); @@ -1946,13 +1988,24 @@ imgLoader::RemoveFromCache(imgCacheEntry* entry) cache.Remove(key); + if (queue.IsDirty()) { + queue.Refresh(); + } + if (entry->HasNoProxies()) { LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache removing from tracker"); if (mCacheTracker) { mCacheTracker->RemoveObject(entry); } - queue.Remove(entry); + // Only search the queue to remove the entry if its possible it might + // be in the queue. If we know its not in the queue this would be + // wasted work. + MOZ_ASSERT_IF(aQueueState == QueueState::AlreadyRemoved, + !queue.Contains(entry)); + if (aQueueState == QueueState::MaybeExists) { + queue.Remove(entry); + } } entry->SetEvicted(true); @@ -1997,13 +2050,13 @@ imgLoader::EvictEntries(imgCacheQueue& aQueueToClear) // We have to make a temporary, since RemoveFromCache removes the element // from the queue, invalidating iterators. nsTArray > entries(aQueueToClear.GetNumElements()); - for (imgCacheQueue::const_iterator i = aQueueToClear.begin(); - i != aQueueToClear.end(); ++i) { + for (auto i = aQueueToClear.begin(); i != aQueueToClear.end(); ++i) { entries.AppendElement(*i); } - for (uint32_t i = 0; i < entries.Length(); ++i) { - if (!RemoveFromCache(entries[i])) { + // Iterate in reverse order to minimize array copying. + for (auto& entry : entries) { + if (!RemoveFromCache(entry)) { return NS_ERROR_FAILURE; } } diff --git a/image/imgLoader.h b/image/imgLoader.h index 7349a666e5..8557e92bd1 100644 --- a/image/imgLoader.h +++ b/image/imgLoader.h @@ -178,7 +178,8 @@ public: uint32_t GetSize() const; void UpdateSize(int32_t diff); uint32_t GetNumElements() const; - typedef std::vector > queueContainer; + bool Contains(imgCacheEntry* aEntry) const; + typedef nsTArray > queueContainer; typedef queueContainer::iterator iterator; typedef queueContainer::const_iterator const_iterator; @@ -316,7 +317,16 @@ public: nsresult InitCache(); bool RemoveFromCache(const ImageCacheKey& aKey); - bool RemoveFromCache(imgCacheEntry* entry); + + // Enumeration describing if a given entry is in the cache queue or not. + // There are some cases we know the entry is definitely not in the queue. + enum class QueueState { + MaybeExists, + AlreadyRemoved + }; + + bool RemoveFromCache(imgCacheEntry* entry, + QueueState aQueueState = QueueState::MaybeExists); bool PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* aEntry); diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 54446d2578..9a6022f340 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -253,6 +253,67 @@ function ArraySort(comparefn) { return MergeSort(O, len, comparefn); } +// ES2023 22.1.3.30 Array.prototype.toSorted ( comparefn ) +function ArrayToSorted(comparefn) { + if (comparefn !== undefined) { + if (!IsCallable(comparefn)) { + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, comparefn)); + } + } + + // Step 1: Let O be ? ToObject(this). Let len be ? ToLength(O.length). + var O = ToObject(this); + var len = ToLength(O.length); + + // Step 2: Snapshot values in ascending index order into a List. + var items = new List(); + var itemsLen = len; + for (var k = 0; k < len; k++) { + items[k] = O[k]; + } + + // Step 3: Create SortCompare per spec. + var wrappedCompareFn = comparefn; + var sortCompare; + if (wrappedCompareFn === undefined) { + sortCompare = function(x, y) { + if (x === undefined) + return y === undefined ? 0 : 1; + if (y === undefined) + return -1; + + var xString = ToString(x); + var yString = ToString(y); + if (xString < yString) + return -1; + if (xString > yString) + return 1; + return 0; + }; + } else { + sortCompare = function(x, y) { + if (x === undefined) + return y === undefined ? 0 : 1; + if (y === undefined) + return -1; + + var v = ToNumber(wrappedCompareFn(x, y)); + return v !== v ? 0 : v; + }; + } + + // Step 4: Sort the snapshot List using SortCompare. + if (itemsLen > 1) + MergeSort(items, itemsLen, sortCompare); + + // Step 5: Create result array and write sorted values. + var A = ArraySpeciesCreate(O, len); + for (var j = 0; j < itemsLen; j++) + _DefineDataProperty(A, j, items[j]); + + return A; +} + /* ES5 15.4.4.18. */ function ArrayForEach(callbackfn/*, thisArg*/) { /* Step 1. */ diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index a4ae0736d4..f917db9b21 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -47,10 +47,12 @@ #include "builtin/AtomicsObject.h" #include "mozilla/Atomics.h" +#include "mozilla/Casting.h" #include "mozilla/FloatingPoint.h" #include "mozilla/Maybe.h" #include "mozilla/Unused.h" +#include "builtin/Promise.h" #include "jsapi.h" #include "jsfriendapi.h" #include "jsnum.h" @@ -58,7 +60,9 @@ #include "jit/AtomicOperations.h" #include "jit/InlinableNatives.h" #include "js/Class.h" +#include "vm/BigIntType.h" #include "vm/GlobalObject.h" +#include "vm/HelperThreads.h" #include "vm/Time.h" #include "vm/TypedArrayObject.h" #include "wasm/WasmInstance.h" @@ -121,6 +125,68 @@ GetTypedArrayIndex(JSContext* cx, HandleValue v, Handle view, return true; } +static bool +IsWaitableTypedArray(Scalar::Type viewType) +{ + return viewType == Scalar::Int32 || viewType == Scalar::BigInt64; +} + +static uint32_t +GetWaiterByteOffset(Handle view, uint32_t offset) +{ + return view->byteOffset() + offset * TypedArrayElemSize(view->type()); +} + +static uint64_t +BigIntToRawBits(Scalar::Type viewType, BigInt* value) +{ + if (viewType == Scalar::BigInt64) + return uint64_t(BigInt::toInt64(value)); + MOZ_ASSERT(viewType == Scalar::BigUint64); + return BigInt::toUint64(value); +} + +static bool +BigIntToRawBits(JSContext* cx, Scalar::Type viewType, HandleValue value, uint64_t* bits) +{ + MOZ_ASSERT(Scalar::isBigIntType(viewType)); + + RootedBigInt bigint(cx, ToBigInt(cx, value)); + if (!bigint) + return false; + + *bits = BigIntToRawBits(viewType, bigint); + return true; +} + +static bool +SetBigIntResult(JSContext* cx, Scalar::Type viewType, uint64_t bits, MutableHandleValue result) +{ + MOZ_ASSERT(Scalar::isBigIntType(viewType)); + + BigInt* bigint = viewType == Scalar::BigInt64 + ? BigInt::createFromInt64(cx, mozilla::BitwiseCast(bits)) + : BigInt::createFromUint64(cx, bits); + if (!bigint) + return false; + + result.setBigInt(bigint); + return true; +} + +static bool +WaitValueMatches(Handle view, uint32_t offset, uint64_t expected) +{ + SharedMem viewData = view->viewDataShared(); + if (view->type() == Scalar::BigInt64) { + return jit::AtomicOperations::loadSafeWhenRacy(viewData.cast() + offset) == + expected; + } + + return uint32_t(jit::AtomicOperations::loadSafeWhenRacy(viewData.cast() + offset)) == + uint32_t(expected); +} + static int32_t CompareExchange(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidate, SharedMem viewData, uint32_t offset, bool* badArrayType = nullptr) @@ -191,6 +257,20 @@ js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp) uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; + + if (Scalar::isBigIntType(view->type())) { + uint64_t oldCandidate; + if (!BigIntToRawBits(cx, view->type(), oldv, &oldCandidate)) + return false; + uint64_t newCandidate; + if (!BigIntToRawBits(cx, view->type(), newv, &newCandidate)) + return false; + + uint64_t result = jit::AtomicOperations::compareExchangeSeqCst( + view->viewDataShared().cast() + offset, oldCandidate, newCandidate); + return SetBigIntResult(cx, view->type(), result, r); + } + int32_t oldCandidate; if (!ToInt32(cx, oldv, &oldCandidate)) return false; @@ -259,6 +339,22 @@ js::atomics_load(JSContext* cx, unsigned argc, Value* vp) r.setNumber(v); return true; } + case Scalar::BigInt64: { + int64_t v = jit::AtomicOperations::loadSeqCst(viewData.cast() + offset); + BigInt* bigint = BigInt::createFromInt64(cx, v); + if (!bigint) + return false; + r.setBigInt(bigint); + return true; + } + case Scalar::BigUint64: { + uint64_t v = jit::AtomicOperations::loadSeqCst(viewData.cast() + offset); + BigInt* bigint = BigInt::createFromUint64(cx, v); + if (!bigint) + return false; + r.setBigInt(bigint); + return true; + } default: return ReportBadArrayType(cx); } @@ -337,6 +433,25 @@ ExchangeOrStore(JSContext* cx, unsigned argc, Value* vp) uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; + + if (Scalar::isBigIntType(view->type())) { + RootedBigInt bigint(cx, ToBigInt(cx, valv)); + if (!bigint) + return false; + + uint64_t value = BigIntToRawBits(view->type(), bigint); + if (op == DoStore) { + jit::AtomicOperations::storeSeqCst(view->viewDataShared().cast() + offset, + value); + r.setBigInt(bigint); + return true; + } + + uint64_t result = jit::AtomicOperations::exchangeSeqCst( + view->viewDataShared().cast() + offset, value); + return SetBigIntResult(cx, view->type(), result, r); + } + double integerValue; if (!ToInteger(cx, valv, &integerValue)) return false; @@ -380,6 +495,24 @@ AtomicsBinop(JSContext* cx, HandleValue objv, HandleValue idxv, HandleValue valv uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; + + if (Scalar::isBigIntType(view->type())) { + uint64_t value; + if (!BigIntToRawBits(cx, view->type(), valv, &value)) + return false; + + SharedMem addr = view->viewDataShared().cast() + offset; + uint64_t old = jit::AtomicOperations::loadSeqCst(addr); + for (;;) { + uint64_t replacement = T::operate64(old, value); + uint64_t observed = jit::AtomicOperations::compareExchangeSeqCst(addr, old, + replacement); + if (observed == old) + return SetBigIntResult(cx, view->type(), old, r); + old = observed; + } + } + int32_t numberValue; if (!ToInt32(cx, valv, &numberValue)) return false; @@ -434,6 +567,7 @@ class PerformAdd public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAddSeqCst) static int32_t perform(int32_t x, int32_t y) { return x + y; } + static uint64_t operate64(uint64_t x, uint64_t y) { return x + y; } }; bool @@ -448,6 +582,7 @@ class PerformSub public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchSubSeqCst) static int32_t perform(int32_t x, int32_t y) { return x - y; } + static uint64_t operate64(uint64_t x, uint64_t y) { return x - y; } }; bool @@ -462,6 +597,7 @@ class PerformAnd public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAndSeqCst) static int32_t perform(int32_t x, int32_t y) { return x & y; } + static uint64_t operate64(uint64_t x, uint64_t y) { return x & y; } }; bool @@ -476,6 +612,7 @@ class PerformOr public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchOrSeqCst) static int32_t perform(int32_t x, int32_t y) { return x | y; } + static uint64_t operate64(uint64_t x, uint64_t y) { return x | y; } }; bool @@ -490,6 +627,7 @@ class PerformXor public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchXorSeqCst) static int32_t perform(int32_t x, int32_t y) { return x ^ y; } + static uint64_t operate64(uint64_t x, uint64_t y) { return x ^ y; } }; bool @@ -693,11 +831,13 @@ js::atomics_cmpxchg_asm_callout(wasm::Instance* instance, int32_t vt, int32_t of namespace js { +class AtomicsWaitAsyncTask; + // Represents one waiting worker. // // The type is declared opaque in SharedArrayObject.h. Instances of -// js::FutexWaiter are stack-allocated and linked onto a list across a -// call to FutexRuntime::wait(). +// js::FutexWaiter are linked onto a list across a call to FutexRuntime::wait() +// or an async wait task. // // The 'waiters' field of the SharedArrayRawBuffer points to the highest // priority waiter in the list, and lower priority nodes are linked through @@ -711,14 +851,34 @@ class FutexWaiter public: FutexWaiter(uint32_t offset, JSRuntime* rt) : offset(offset), + kind(Sync), rt(rt), + asyncTask(nullptr), lower_pri(nullptr), back(nullptr) { } - uint32_t offset; // int32 element index within the SharedArrayBuffer + FutexWaiter(uint32_t offset, AtomicsWaitAsyncTask* asyncTask) + : offset(offset), + kind(Async), + rt(nullptr), + asyncTask(asyncTask), + lower_pri(nullptr), + back(nullptr) + { + } + + bool isWaiting() const; + void notify(); + + uint32_t offset; // byte offset within the SharedArrayBuffer + enum WaiterKind { + Sync, + Async + } kind; JSRuntime* rt; // The runtime of the waiter + AtomicsWaitAsyncTask* asyncTask; // The async waiter task, if any FutexWaiter* lower_pri; // Lower priority nodes in circular doubly-linked list of waiters FutexWaiter* back; // Other direction }; @@ -742,8 +902,195 @@ class AutoLockFutexAPI js::UniqueLock& unique() { return *unique_; } }; +static void +AddWaiter(SharedArrayRawBuffer* sarb, FutexWaiter* waiter) +{ + if (FutexWaiter* waiters = sarb->waiters()) { + waiter->lower_pri = waiters; + waiter->back = waiters->back; + waiters->back->lower_pri = waiter; + waiters->back = waiter; + } else { + waiter->lower_pri = waiter->back = waiter; + sarb->setWaiters(waiter); + } +} + +static void +RemoveWaiter(SharedArrayRawBuffer* sarb, FutexWaiter* waiter) +{ + if (waiter->lower_pri == waiter) { + sarb->setWaiters(nullptr); + } else { + waiter->lower_pri->back = waiter->back; + waiter->back->lower_pri = waiter->lower_pri; + if (sarb->waiters() == waiter) + sarb->setWaiters(waiter->lower_pri); + } + waiter->lower_pri = nullptr; + waiter->back = nullptr; +} + +class AtomicsWaitAsyncTask : public PromiseTask +{ + enum class State { + Waiting, + Notified, + TimedOut + }; + + SharedArrayRawBuffer* sarb_; + FutexWaiter waiter_; + mozilla::Maybe timeout_; + ConditionVariable cond_; + State state_; + bool isInWaiterList_; + + public: + AtomicsWaitAsyncTask(JSContext* cx, Handle promise, + SharedArrayRawBuffer* sarb, uint32_t offset, + mozilla::Maybe& timeout) + : PromiseTask(cx, promise), + sarb_(sarb), + waiter_(offset, this), + timeout_(timeout), + state_(State::Waiting), + isInWaiterList_(false) + { + } + + ~AtomicsWaitAsyncTask() { + if (isInWaiterList_) { + AutoLockFutexAPI lock; + if (isInWaiterList_) + removeFromWaiterList(); + } + sarb_->dropReference(); + } + + FutexWaiter* waiter() { + return &waiter_; + } + + void setInWaiterList() { + isInWaiterList_ = true; + } + + bool isWaiting() const { + return state_ == State::Waiting; + } + + void notify() { + MOZ_ASSERT(isWaiting()); + state_ = State::Notified; + cond_.notify_all(); + } + + void execute() override { + AutoLockFutexAPI lock; + + const bool isTimed = timeout_.isSome(); + auto finalEnd = timeout_.map([](mozilla::TimeDuration& timeout) { + return mozilla::TimeStamp::Now() + timeout; + }); + auto maxSlice = mozilla::TimeDuration::FromSeconds(4000.0); + + while (state_ == State::Waiting) { + if (isTimed) { + auto sliceEnd = finalEnd.map([&](mozilla::TimeStamp& finalEnd) { + auto sliceEnd = mozilla::TimeStamp::Now() + maxSlice; + if (finalEnd < sliceEnd) + sliceEnd = finalEnd; + return sliceEnd; + }); + + mozilla::Unused << cond_.wait_until(lock.unique(), *sliceEnd); + if (state_ == State::Waiting && mozilla::TimeStamp::Now() >= *finalEnd) { + state_ = State::TimedOut; + break; + } + } else { + cond_.wait(lock.unique()); + } + } + + if (isInWaiterList_) + removeFromWaiterList(); + } + + private: + void removeFromWaiterList() { + MOZ_ASSERT(isInWaiterList_); + RemoveWaiter(sarb_, &waiter_); + isInWaiterList_ = false; + } + + bool finishPromise(JSContext* cx, Handle promise) override { + RootedValue result(cx); + if (state_ == State::TimedOut) + result.setString(cx->names().futexTimedOut); + else + result.setString(cx->names().futexOK); + return PromiseObject::resolve(cx, promise, result); + } +}; + +bool +FutexWaiter::isWaiting() const +{ + if (kind == Sync) + return rt->fx.isWaiting(); + return asyncTask->isWaiting(); +} + +void +FutexWaiter::notify() +{ + if (kind == Sync) { + rt->fx.notify(FutexRuntime::NotifyExplicit); + return; + } + asyncTask->notify(); +} + } // namespace js +static bool +GetWaitTimeout(JSContext* cx, HandleValue timeoutv, + mozilla::Maybe* timeout) +{ + timeout->reset(); + if (!timeoutv.isUndefined()) { + double timeout_ms; + if (!ToNumber(cx, timeoutv, &timeout_ms)) + return false; + if (!mozilla::IsNaN(timeout_ms)) { + if (timeout_ms < 0) + *timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0)); + else if (!mozilla::IsInfinite(timeout_ms)) + *timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms)); + } + } + return true; +} + +static bool +CreateWaitAsyncResult(JSContext* cx, bool isAsync, HandleValue value, MutableHandleValue rval) +{ + RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); + if (!obj) + return false; + + RootedValue asyncValue(cx, BooleanValue(isAsync)); + if (!NativeDefineDataProperty(cx, obj, cx->names().async, asyncValue, JSPROP_ENUMERATE)) + return false; + if (!NativeDefineDataProperty(cx, obj, cx->names().value, value, JSPROP_ENUMERATE)) + return false; + + rval.setObject(*obj); + return true; +} + bool js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) { @@ -759,26 +1106,24 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) Rooted view(cx, nullptr); if (!GetSharedTypedArray(cx, objv, &view)) return false; - if (view->type() != Scalar::Int32) + if (!IsWaitableTypedArray(view->type())) return ReportBadArrayType(cx); uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; - int32_t value; - if (!ToInt32(cx, valv, &value)) - return false; - mozilla::Maybe timeout; - if (!timeoutv.isUndefined()) { - double timeout_ms; - if (!ToNumber(cx, timeoutv, &timeout_ms)) + uint64_t value = 0; + if (view->type() == Scalar::BigInt64) { + if (!BigIntToRawBits(cx, view->type(), valv, &value)) return false; - if (!mozilla::IsNaN(timeout_ms)) { - if (timeout_ms < 0) - timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0)); - else if (!mozilla::IsInfinite(timeout_ms)) - timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms)); - } + } else { + int32_t int32Value; + if (!ToInt32(cx, valv, &int32Value)) + return false; + value = uint32_t(int32Value); } + mozilla::Maybe timeout; + if (!GetWaitTimeout(cx, timeoutv, &timeout)) + return false; if (!rt->fx.canWait()) return ReportCannotWait(cx); @@ -787,8 +1132,7 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) // and it provides the necessary memory fence. AutoLockFutexAPI lock; - SharedMem addr = view->viewDataShared().cast() + offset; - if (jit::AtomicOperations::loadSafeWhenRacy(addr) != value) { + if (!WaitValueMatches(view, offset, value)) { r.setString(cx->names().futexNotEqual); return true; } @@ -796,16 +1140,8 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) Rooted sab(cx, view->bufferShared()); SharedArrayRawBuffer* sarb = sab->rawBufferObject(); - FutexWaiter w(offset, rt); - if (FutexWaiter* waiters = sarb->waiters()) { - w.lower_pri = waiters; - w.back = waiters->back; - waiters->back->lower_pri = &w; - waiters->back = &w; - } else { - w.lower_pri = w.back = &w; - sarb->setWaiters(&w); - } + FutexWaiter w(GetWaiterByteOffset(view, offset), rt); + AddWaiter(sarb, &w); FutexRuntime::WaitResult result = FutexRuntime::FutexOK; bool retval = rt->fx.wait(cx, lock.unique(), timeout, &result); @@ -820,17 +1156,98 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) } } - if (w.lower_pri == &w) { - sarb->setWaiters(nullptr); - } else { - w.lower_pri->back = w.back; - w.back->lower_pri = w.lower_pri; - if (sarb->waiters() == &w) - sarb->setWaiters(w.lower_pri); - } + RemoveWaiter(sarb, &w); return retval; } +bool +js::atomics_waitAsync(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + HandleValue objv = args.get(0); + HandleValue idxv = args.get(1); + HandleValue valv = args.get(2); + HandleValue timeoutv = args.get(3); + MutableHandleValue r = args.rval(); + + Rooted view(cx, nullptr); + if (!GetSharedTypedArray(cx, objv, &view)) + return false; + if (!IsWaitableTypedArray(view->type())) + return ReportBadArrayType(cx); + uint32_t offset; + if (!GetTypedArrayIndex(cx, idxv, view, &offset)) + return false; + uint64_t value = 0; + if (view->type() == Scalar::BigInt64) { + if (!BigIntToRawBits(cx, view->type(), valv, &value)) + return false; + } else { + int32_t int32Value; + if (!ToInt32(cx, valv, &int32Value)) + return false; + value = uint32_t(int32Value); + } + mozilla::Maybe timeout; + if (!GetWaitTimeout(cx, timeoutv, &timeout)) + return false; + + Rooted promise(cx, PromiseObject::createSkippingExecutor(cx)); + if (!promise) + return false; + + RootedValue promiseValue(cx, ObjectValue(*promise)); + RootedValue result(cx); + if (!CreateWaitAsyncResult(cx, true, promiseValue, &result)) + return false; + + Rooted sab(cx, view->bufferShared()); + SharedArrayRawBuffer* sarb = sab->rawBufferObject(); + if (!sarb->addReference()) { + JS_ReportErrorASCII(cx, "Reference count overflow on SharedArrayBuffer"); + return false; + } + + auto task = cx->make_unique(cx, promise, sarb, offset, timeout); + if (!task) { + sarb->dropReference(); + return false; + } + + bool isAsync = false; + RootedValue immediateResult(cx); + { + AutoLockFutexAPI lock; + + if (!WaitValueMatches(view, offset, value)) { + immediateResult.setString(cx->names().futexNotEqual); + } else if (timeout.isSome() && timeout->ToMilliseconds() == 0.0) { + immediateResult.setString(cx->names().futexTimedOut); + } else { + if (!cx->startAsyncTaskCallback || !cx->finishAsyncTaskCallback || + !CanUseExtraThreads()) + { + JS_ReportErrorASCII(cx, "Atomics.waitAsync not supported in this runtime."); + return false; + } + + task->waiter()->offset = GetWaiterByteOffset(view, offset); + AddWaiter(sarb, task->waiter()); + task->setInWaiterList(); + isAsync = true; + } + } + + if (!isAsync) + return CreateWaitAsyncResult(cx, false, immediateResult, r); + + if (!StartPromiseTask(cx, Move(task))) + return false; + + r.set(result); + return true; +} + bool js::atomics_notify(JSContext* cx, unsigned argc, Value* vp) { @@ -843,11 +1260,12 @@ js::atomics_notify(JSContext* cx, unsigned argc, Value* vp) Rooted view(cx, nullptr); if (!GetSharedTypedArray(cx, objv, &view)) return false; - if (view->type() != Scalar::Int32) + if (!IsWaitableTypedArray(view->type())) return ReportBadArrayType(cx); uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; + offset = GetWaiterByteOffset(view, offset); double count; if (countv.isUndefined()) { count = mozilla::PositiveInfinity(); @@ -870,9 +1288,9 @@ js::atomics_notify(JSContext* cx, unsigned argc, Value* vp) do { FutexWaiter* c = iter; iter = iter->lower_pri; - if (c->offset != offset || !c->rt->fx.isWaiting()) + if (c->offset != offset || !c->isWaiting()) continue; - c->rt->fx.notify(FutexRuntime::NotifyExplicit); + c->notify(); ++woken; --count; } while (count > 0 && iter != waiters); @@ -1106,6 +1524,7 @@ const JSFunctionSpec AtomicsMethods[] = { JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor), JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree), JS_FN("wait", atomics_wait, 4,0), + JS_FN("waitAsync", atomics_waitAsync, 4,0), JS_FN("notify", atomics_notify, 3,0), JS_FN("wake", atomics_notify, 3,0), //Legacy name JS_FS_END diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h index 18f00dad16..309c97ae91 100644 --- a/js/src/builtin/AtomicsObject.h +++ b/js/src/builtin/AtomicsObject.h @@ -24,18 +24,19 @@ class AtomicsObject : public JSObject static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp); }; -MOZ_MUST_USE bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_load(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_store(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_add(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_sub(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_and(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_notify(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_load(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_store(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_add(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_sub(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_and(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_or(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_xor(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_wait(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_waitAsync(JSContext* cx, unsigned argc, Value* vp); +[[nodiscard]] bool atomics_notify(JSContext* cx, unsigned argc, Value* vp); /* asm.js callouts */ namespace wasm { class Instance; } diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js index 434cd6529b..8c5afa9f5e 100644 --- a/js/src/builtin/Map.js +++ b/js/src/builtin/Map.js @@ -55,6 +55,50 @@ function MapForEach(callbackfn, thisArg = undefined) { } } +// ES2024 +// Map.groupBy ( items, callbackfn ) +function MapGroupBy(items, callbackfn) { + // Step 1. + RequireObjectCoercible(items); + + // Step 2. + if (!IsCallable(callbackfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn)); + + // Step 3. + var groups = std_Map_create(); + + // Step 4. + var k = 0; + + // Steps 5-8. + for (var value of allowContentIter(items)) { + // Step 6.a. + if (k >= MAX_NUMERIC_INDEX) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + + // Step 6.b. + var key = callContentFunction(callbackfn, undefined, value, k); + + // Steps 6.c-d. + // Group values are always arrays, so undefined also tells us whether + // this is a new key without a second hash-table lookup. + var elements = callFunction(std_Map_get, groups, key); + if (elements !== undefined) { + callFunction(std_Array_push, elements, value); + } else { + elements = [value]; + callFunction(std_Map_set, groups, key, elements); + } + + // Step 6.e. + k++; + } + + // Step 9. + return groups; +} + var iteratorTemp = { mapIterationResultPair : null }; function MapIteratorNext() { diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index fe748a6bde..daeb930c86 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -332,9 +332,15 @@ const JSPropertySpec MapObject::staticProperties[] = { JS_PS_END }; +const JSFunctionSpec MapObject::staticMethods[] = { + JS_SELF_HOSTED_FN("groupBy", "MapGroupBy", 2, 0), + JS_FS_END +}; + static JSObject* InitClass(JSContext* cx, Handle global, const Class* clasp, JSProtoKey key, Native construct, const JSPropertySpec* properties, const JSFunctionSpec* methods, + const JSFunctionSpec* staticMethods, const JSPropertySpec* staticProperties) { RootedPlainObject proto(cx, NewBuiltinClassInstance(cx)); @@ -343,8 +349,13 @@ InitClass(JSContext* cx, Handle global, const Class* clasp, JSPro Rooted ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 0)); if (!ctor || - !JS_DefineProperties(cx, ctor, staticProperties) || - !LinkConstructorAndPrototype(cx, ctor, proto) || + !JS_DefineProperties(cx, ctor, staticProperties)) + { + return nullptr; + } + if (staticMethods && !JS_DefineFunctions(cx, ctor, staticMethods)) + return nullptr; + if (!LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndFunctions(cx, proto, properties, methods) || !GlobalObject::initBuiltinConstructor(cx, global, key, ctor, proto)) { @@ -359,7 +370,7 @@ MapObject::initClass(JSContext* cx, JSObject* obj) Rooted global(cx, &obj->as()); RootedObject proto(cx, InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods, - staticProperties)); + staticMethods, staticProperties)); if (proto) { // Define the "entries" method. JSFunction* fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0); @@ -1084,7 +1095,7 @@ SetObject::initClass(JSContext* cx, JSObject* obj) Rooted global(cx, &obj->as()); RootedObject proto(cx, InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods, - staticProperties)); + nullptr, staticProperties)); if (proto) { // Define the "values" method. JSFunction* fun = JS_DefineFunction(cx, proto, "values", values, 0, 0); diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h index a9f685ea00..2b46fec2c9 100644 --- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -109,8 +109,10 @@ class MapObject : public NativeObject { static MOZ_MUST_USE bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj, JS::MutableHandle> entries); - static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp); - static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp); static MapObject* create(JSContext* cx, HandleObject proto = nullptr); // Publicly exposed Map calls for JSAPI access (webidl maplike/setlike @@ -137,6 +139,7 @@ class MapObject : public NativeObject { static const JSPropertySpec properties[]; static const JSFunctionSpec methods[]; + static const JSFunctionSpec staticMethods[]; static const JSPropertySpec staticProperties[]; ValueMap* getData() { return static_cast(getPrivate()); } static ValueMap& extract(HandleObject o); @@ -150,22 +153,20 @@ class MapObject : public NativeObject { static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args, IteratorKind kind); - static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp); - static MOZ_MUST_USE bool get_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool get(JSContext* cx, unsigned argc, Value* vp); - static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool set_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool set(JSContext* cx, unsigned argc, Value* vp); - static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp); - static MOZ_MUST_USE bool keys_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool keys(JSContext* cx, unsigned argc, Value* vp); - static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp); - static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args); - static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool get_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool set_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool keys_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool keys(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp); + [[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args); + [[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp); }; class MapIteratorObject : public NativeObject diff --git a/js/src/builtin/Object.js b/js/src/builtin/Object.js index 6627aea593..01442144cc 100644 --- a/js/src/builtin/Object.js +++ b/js/src/builtin/Object.js @@ -240,12 +240,16 @@ function ObjectGroupBy(items, callbackfn) { // Steps 5-8. for (var value of allowContentIter(items)) { // Step 6.a. - var key = callContentFunction(callbackfn, undefined, value, k); + if (k >= MAX_NUMERIC_INDEX) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); // Step 6.b. + var key = callContentFunction(callbackfn, undefined, value, k); + + // Step 6.c. key = ToPropertyKey(key); - // Steps 6.c-d. + // Steps 6.d-e. var elements = groups[key]; if (elements === undefined) { _DefineDataProperty(groups, key, [value]); @@ -253,7 +257,7 @@ function ObjectGroupBy(items, callbackfn) { callFunction(std_Array_push, elements, value); } - // Step 6.e. + // Step 6.f. k++; } diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 9660a758a1..56803b5b91 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -3673,6 +3673,48 @@ Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) return true; } +// ES2024 +// Promise.withResolvers ( ) +static bool +Promise_static_withResolvers(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + // Step 1. + if (!args.thisv().isObject()) { + ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, -1, args.thisv(), nullptr); + return false; + } + RootedObject C(cx, &args.thisv().toObject()); + + // Step 2. + Rooted capability(cx); + if (!NewPromiseCapability(cx, C, &capability, false)) + return false; + + // Step 3. + RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); + if (!obj) + return false; + + // Steps 4-7. + RootedValue promise(cx, ObjectValue(*capability.promise())); + if (!::JS_DefineProperty(cx, obj, "promise", promise, JSPROP_ENUMERATE)) + return false; + + RootedValue resolve(cx, ObjectValue(*capability.resolve())); + if (!::JS_DefineProperty(cx, obj, "resolve", resolve, JSPROP_ENUMERATE)) + return false; + + RootedValue reject(cx, ObjectValue(*capability.reject())); + if (!::JS_DefineProperty(cx, obj, "reject", reject, JSPROP_ENUMERATE)) + return false; + + // Step 8. + args.rval().setObject(*obj); + return true; +} + /** * Unforgeable version of ES2016, 25.4.4.5, Promise.resolve. */ @@ -5180,6 +5222,7 @@ static const JSFunctionSpec promise_static_methods[] = { JS_FN("race", Promise_static_race, 1, 0), JS_FN("reject", Promise_reject, 1, 0), JS_FN("resolve", Promise_static_resolve, 1, 0), + JS_FN("withResolvers", Promise_static_withResolvers, 0, 0), JS_FS_END }; diff --git a/js/src/builtin/Stream.cpp b/js/src/builtin/Stream.cpp index 26457709d8..0d5d0b2701 100644 --- a/js/src/builtin/Stream.cpp +++ b/js/src/builtin/Stream.cpp @@ -5,6 +5,7 @@ #include "builtin/Stream.h" +#include "js/CompilationAndEvaluation.h" #include "js/Stream.h" #include "jscntxt.h" @@ -16,6 +17,10 @@ #include "vm/NativeObject-inl.h" +#include "zlib.h" + +#include + using namespace js; enum StreamSlots { @@ -96,14 +101,72 @@ Is(const HandleValue v) return v.isObject() && v.toObject().is(); } -#ifdef DEBUG +template +MOZ_ALWAYS_INLINE bool +IsMaybeWrapped(const HandleValue v) +{ + if (!v.isObject()) + return false; + + JSObject* obj = &v.toObject(); + if (obj->is()) + return true; + + JSObject* unwrapped = CheckedUnwrap(obj); + return unwrapped && unwrapped->is(); +} + +template +MOZ_ALWAYS_INLINE T* +UnwrapInternalSlotObject(JSObject* obj) +{ + JSObject* unwrapped = UncheckedUnwrap(obj); + MOZ_ASSERT(unwrapped); + MOZ_ASSERT(unwrapped->is()); + return &unwrapped->as(); +} + +template +MOZ_ALWAYS_INLINE T* +UnwrapMaybeWrappedArg(const HandleValue v) +{ + if (!v.isObject()) + return nullptr; + + JSObject* obj = &v.toObject(); + if (obj->is()) + return &obj->as(); + + JSObject* unwrapped = CheckedUnwrap(obj); + if (!unwrapped || !unwrapped->is()) + return nullptr; + + return &unwrapped->as(); +} + static bool IsReadableStreamController(const JSObject* controller) { return controller->is() || controller->is(); } -#endif // DEBUG + +[[nodiscard]] static NativeObject* +UnwrapMaybeWrappedReadableStreamController(const HandleValue v) +{ + if (!v.isObject()) + return nullptr; + + JSObject* obj = &v.toObject(); + if (IsReadableStreamController(obj)) + return &obj->as(); + + JSObject* unwrapped = CheckedUnwrap(obj); + if (!unwrapped || !IsReadableStreamController(unwrapped)) + return nullptr; + + return &unwrapped->as(); +} static inline uint32_t ControllerFlags(const NativeObject* controller) @@ -183,7 +246,8 @@ inline static MOZ_MUST_USE ReadableStream* StreamFromController(const NativeObject* controller) { MOZ_ASSERT(IsReadableStreamController(controller)); - return &controller->getFixedSlot(ControllerSlot_Stream).toObject().as(); + return UnwrapInternalSlotObject( + &controller->getFixedSlot(ControllerSlot_Stream).toObject()); } inline static MOZ_MUST_USE NativeObject* @@ -215,15 +279,17 @@ inline static MOZ_MUST_USE ReadableStream* StreamFromReader(const NativeObject* reader) { MOZ_ASSERT(ReaderHasStream(reader)); - return &reader->getFixedSlot(ReaderSlot_Stream).toObject().as(); + return UnwrapInternalSlotObject( + &reader->getFixedSlot(ReaderSlot_Stream).toObject()); } inline static MOZ_MUST_USE NativeObject* ReaderFromStream(const NativeObject* stream) { Value readerVal = stream->getFixedSlot(StreamSlot_Reader); - MOZ_ASSERT(JS::IsReadableStreamReader(&readerVal.toObject())); - return &readerVal.toObject().as(); + NativeObject* reader = UnwrapInternalSlotObject(&readerVal.toObject()); + MOZ_ASSERT(JS::IsReadableStreamReader(reader)); + return reader; } inline static bool @@ -305,26 +371,55 @@ RejectNonGenericMethod(JSContext* cx, const CallArgs& args, return ReturnPromiseRejectedWithPendingError(cx, args); } -inline static MOZ_MUST_USE NativeObject* +[[nodiscard]] static bool +ResolveMaybeWrappedPromise(JSContext* cx, HandleObject promise, HandleValue value) +{ + RootedObject wrappedPromise(cx, promise); + RootedValue wrappedValue(cx, value); + if (!JS_WrapObject(cx, &wrappedPromise) || !JS_WrapValue(cx, &wrappedValue)) + return false; + return ResolvePromise(cx, wrappedPromise, wrappedValue); +} + +[[nodiscard]] static bool +RejectMaybeWrappedPromise(JSContext* cx, HandleObject promise, HandleValue reason) +{ + RootedObject wrappedPromise(cx, promise); + RootedValue wrappedReason(cx, reason); + if (!JS_WrapObject(cx, &wrappedPromise) || !JS_WrapValue(cx, &wrappedReason)) + return false; + return RejectPromise(cx, wrappedPromise, wrappedReason); +} + +[[nodiscard]] inline static NativeObject* SetNewList(JSContext* cx, HandleNativeObject container, uint32_t slot) { - NativeObject* list = NewObjectWithNullTaggedProto(cx); - if (!list) - return nullptr; - container->setFixedSlot(slot, ObjectValue(*list)); + RootedNativeObject list(cx); + { + JSAutoCompartment ac(cx, container); + list = NewObjectWithNullTaggedProto(cx); + if (!list) + return nullptr; + container->setFixedSlot(slot, ObjectValue(*list)); + } return list; } inline static MOZ_MUST_USE bool AppendToList(JSContext* cx, HandleNativeObject list, HandleValue value) { + JSAutoCompartment ac(cx, list); + RootedValue wrappedValue(cx, value); + if (!JS_WrapValue(cx, &wrappedValue)) + return false; + uint32_t length = list->getDenseInitializedLength(); if (!list->ensureElements(cx, length + 1)) return false; list->ensureDenseInitializedLength(cx, length, 1); - list->setDenseElement(length, value); + list->setDenseElement(length, wrappedValue); return true; } @@ -341,6 +436,7 @@ template inline static MOZ_MUST_USE T* ShiftFromList(JSContext* cx, HandleNativeObject list) { + JSAutoCompartment ac(cx, list); uint32_t length = list->getDenseInitializedLength(); MOZ_ASSERT(length > 0); @@ -915,30 +1011,79 @@ ReadableStream_getReader(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod, ReadableStream_getReader_impl>(cx, args); } +[[nodiscard]] static bool +CallStreamExtra(JSContext* cx, const char* name, HandleValue streamVal, + HandleValue arg0, HandleValue arg1, MutableHandleValue rval) +{ + RootedObject global(cx, JS::CurrentGlobalOrNull(cx)); + if (!global) + return false; + + RootedValue fun(cx); + if (!JS_GetProperty(cx, global, name, &fun)) + return false; + + if (!fun.isObject() || !IsCallable(fun)) { + if (!InitStreamExtras(cx, global)) + return false; + if (!JS_GetProperty(cx, global, name, &fun)) + return false; + } + + if (!fun.isObject() || !IsCallable(fun)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, name); + return false; + } + + FixedInvokeArgs<3> invokeArgs(cx); + invokeArgs[0].set(streamVal); + invokeArgs[1].set(arg0); + invokeArgs[2].set(arg1); + return Call(cx, fun, UndefinedHandleValue, invokeArgs, rval); +} + // Streams spec, 3.2.4.4. pipeThrough({ writable, readable }, options) -static MOZ_MUST_USE bool +[[nodiscard]] static bool ReadableStream_pipeThrough(JSContext* cx, unsigned argc, Value* vp) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, "pipeThrough"); - return false; - // // Step 1: Perform ? Invoke(this, "pipeTo", « writable, options »). + CallArgs args = CallArgsFromVp(argc, vp); + if (!Is(args.thisv())) { + ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), + nullptr, "pipeThrough", ""); + return false; + } - // // Step 2: Return readable. - // return readable; + RootedValue rval(cx); + if (!CallStreamExtra(cx, "__uxpStreamsPipeThrough", args.thisv(), + args.get(0), args.get(1), &rval)) + return false; + + args.rval().set(rval); + return true; } // Streams spec, 3.2.4.5. pipeTo(dest, { preventClose, preventAbort, preventCancel } = {}) -// TODO: Unimplemented since spec is not complete yet. -static MOZ_MUST_USE bool +[[nodiscard]] static bool ReadableStream_pipeTo(JSContext* cx, unsigned argc, Value* vp) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, "pipeTo"); - return false; + CallArgs args = CallArgsFromVp(argc, vp); + if (!Is(args.thisv())) { + ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), + nullptr, "pipeTo", ""); + return false; + } + + RootedValue rval(cx); + if (!CallStreamExtra(cx, "__uxpStreamsPipeTo", args.thisv(), + args.get(0), args.get(1), &rval)) + return false; + + args.rval().set(rval); + return true; } -static MOZ_MUST_USE bool +[[nodiscard]] static bool ReadableStreamTee(JSContext* cx, Handle stream, bool cloneForBranch2, MutableHandle branch1, MutableHandle branch2); @@ -1313,7 +1458,8 @@ ReadableStreamAddReadIntoRequest(JSContext* cx, Handle stream) { // Step 1: MOZ_ASSERT: ! IsReadableStreamBYOBReader(stream.[[reader]]) is true. RootedValue val(cx, stream->getFixedSlot(StreamSlot_Reader)); - RootedNativeObject reader(cx, &val.toObject().as()); + RootedNativeObject reader(cx, ReaderFromStream(stream)); + MOZ_ASSERT(reader->is()); // Step 2: MOZ_ASSERT: stream.[[state]] is "readable" or "closed". MOZ_ASSERT(stream->readable() || stream->closed()); @@ -1326,7 +1472,8 @@ ReadableStreamAddReadIntoRequest(JSContext* cx, Handle stream) // Step 4: Let readIntoRequest be Record {[[promise]]: promise}. // Step 5: Append readIntoRequest as the last element of stream.[[reader]].[[readIntoRequests]]. val = reader->getFixedSlot(ReaderSlot_Requests); - RootedNativeObject readIntoRequests(cx, &val.toObject().as()); + RootedNativeObject readIntoRequests(cx); + readIntoRequests = UnwrapInternalSlotObject(&val.toObject()); // Since [[promise]] is the Record's only field, we store it directly. val = ObjectValue(*promise); if (!AppendToList(cx, readIntoRequests, val)) @@ -1356,7 +1503,8 @@ ReadableStreamAddReadRequest(JSContext* cx, Handle stream) // Step 4: Let readRequest be Record {[[promise]]: promise}. // Step 5: Append readRequest as the last element of stream.[[reader]].[[readRequests]]. RootedValue val(cx, reader->getFixedSlot(ReaderSlot_Requests)); - RootedNativeObject readRequests(cx, &val.toObject().as()); + RootedNativeObject readRequests(cx); + readRequests = UnwrapInternalSlotObject(&val.toObject()); // Since [[promise]] is the Record's only field, we store it directly. val = ObjectValue(*promise); @@ -1400,6 +1548,8 @@ ReadableStream::cancel(JSContext* cx, Handle stream, HandleValu // with stream.[[storedError]]. if (stream->errored()) { RootedValue storedError(cx, stream->getFixedSlot(StreamSlot_StoredError)); + if (!JS_WrapValue(cx, &storedError)) + return nullptr; return PromiseObject::unforgeableReject(cx, storedError); } @@ -1443,13 +1593,14 @@ ReadableStreamCloseInternal(JSContext* cx, Handle stream) return true; // Step 5: If ! IsReadableStreamDefaultReader(reader) is true, - RootedNativeObject reader(cx, &val.toObject().as()); + RootedNativeObject reader(cx, ReaderFromStream(stream)); if (reader->is()) { // Step a: Repeat for each readRequest that is an element of // reader.[[readRequests]], val = reader->getFixedSlot(ReaderSlot_Requests); if (!val.isUndefined()) { - RootedNativeObject readRequests(cx, &val.toObject().as()); + RootedNativeObject readRequests(cx); + readRequests = UnwrapInternalSlotObject(&val.toObject()); uint32_t len = readRequests->getDenseInitializedLength(); RootedObject readRequest(cx); RootedObject resultObj(cx); @@ -1462,7 +1613,7 @@ ReadableStreamCloseInternal(JSContext* cx, Handle stream) if (!resultObj) return false; resultVal = ObjectValue(*resultObj); - if (!ResolvePromise(cx, readRequest, resultVal)) + if (!ResolveMaybeWrappedPromise(cx, readRequest, resultVal)) return false; } @@ -1474,7 +1625,7 @@ ReadableStreamCloseInternal(JSContext* cx, Handle stream) // Step 6: Resolve reader.[[closedPromise]] with undefined. // Step 7: Return (implicit). RootedObject closedPromise(cx, &reader->getFixedSlot(ReaderSlot_ClosedPromise).toObject()); - if (!ResolvePromise(cx, closedPromise, UndefinedHandleValue)) + if (!ResolveMaybeWrappedPromise(cx, closedPromise, UndefinedHandleValue)) return false; if (stream->mode() == JS::ReadableStreamMode::ExternalSource && @@ -1502,7 +1653,13 @@ ReadableStreamErrorInternal(JSContext* cx, Handle stream, Handl SetStreamState(stream, (state & ReadableStream::Disturbed) | ReadableStream::Errored); // Step 4: Set stream.[[storedError]] to e. - stream->setFixedSlot(StreamSlot_StoredError, e); + RootedValue storedError(cx, e); + { + JSAutoCompartment ac(cx, stream); + if (!JS_WrapValue(cx, &storedError)) + return false; + stream->setFixedSlot(StreamSlot_StoredError, storedError); + } // Step 5: Let reader be stream.[[reader]]. RootedValue val(cx, stream->getFixedSlot(StreamSlot_Reader)); @@ -1510,20 +1667,21 @@ ReadableStreamErrorInternal(JSContext* cx, Handle stream, Handl // Step 6: If reader is undefined, return. if (val.isUndefined()) return true; - RootedNativeObject reader(cx, &val.toObject().as()); + RootedNativeObject reader(cx, ReaderFromStream(stream)); // Steps 7,8: (Identical in our implementation.) // Step a: Repeat for each readRequest that is an element of // reader.[[readRequests]], val = reader->getFixedSlot(ReaderSlot_Requests); - RootedNativeObject readRequests(cx, &val.toObject().as()); - Rooted readRequest(cx); + RootedNativeObject readRequests(cx); + readRequests = UnwrapInternalSlotObject(&val.toObject()); + RootedObject readRequest(cx); uint32_t len = readRequests->getDenseInitializedLength(); for (uint32_t i = 0; i < len; i++) { // Step i: Reject readRequest.[[promise]] with e. val = readRequests->getDenseElement(i); - readRequest = &val.toObject().as(); - if (!PromiseObject::reject(cx, readRequest, e)) + readRequest = &val.toObject(); + if (!RejectMaybeWrappedPromise(cx, readRequest, e)) return false; } @@ -1533,8 +1691,8 @@ ReadableStreamErrorInternal(JSContext* cx, Handle stream, Handl // Step 9: Reject reader.[[closedPromise]] with e. val = reader->getFixedSlot(ReaderSlot_ClosedPromise); - Rooted closedPromise(cx, &val.toObject().as()); - if (!PromiseObject::reject(cx, closedPromise, e)) + RootedObject closedPromise(cx, &val.toObject()); + if (!RejectMaybeWrappedPromise(cx, closedPromise, e)) return false; if (stream->mode() == JS::ReadableStreamMode::ExternalSource && @@ -1558,7 +1716,7 @@ ReadableStreamFulfillReadOrReadIntoRequest(JSContext* cx, HandlegetFixedSlot(StreamSlot_Reader)); - RootedNativeObject reader(cx, &val.toObject().as()); + RootedNativeObject reader(cx, ReaderFromStream(stream)); // Step 2: Let readIntoRequest be the first element of // reader.[[readIntoRequests]]. @@ -1566,7 +1724,8 @@ ReadableStreamFulfillReadOrReadIntoRequest(JSContext* cx, HandlegetFixedSlot(ReaderSlot_Requests); - RootedNativeObject readIntoRequests(cx, &val.toObject().as()); + RootedNativeObject readIntoRequests(cx); + readIntoRequests = UnwrapInternalSlotObject(&val.toObject()); Rooted readIntoRequest(cx); readIntoRequest = ShiftFromList(cx, readIntoRequests); MOZ_ASSERT(readIntoRequest); @@ -1577,7 +1736,8 @@ ReadableStreamFulfillReadOrReadIntoRequest(JSContext* cx, HandlegetFixedSlot(ReaderSlot_Requests); - return readRequests.toObject().as().getDenseInitializedLength(); + NativeObject* requests = UnwrapInternalSlotObject(&readRequests.toObject()); + return requests->getDenseInitializedLength(); } // Stream spec 3.4.10. ReadableStreamHasBYOBReader ( stream ) @@ -1604,7 +1765,10 @@ ReadableStreamHasBYOBReader(ReadableStream* stream) // Step 3: If ! IsReadableStreamBYOBReader(reader) is false, return false. // Step 4: Return true. Value reader = stream->getFixedSlot(StreamSlot_Reader); - return reader.isObject() && reader.toObject().is(); + if (!reader.isObject()) + return false; + JSObject* unwrapped = UncheckedUnwrap(&reader.toObject()); + return unwrapped && unwrapped->is(); } // Streap spec 3.4.11. ReadableStreamHasDefaultReader ( stream ) @@ -1616,7 +1780,10 @@ ReadableStreamHasDefaultReader(ReadableStream* stream) // Step 3: If ! ReadableStreamDefaultReader(reader) is false, return false. // Step 4: Return true. Value reader = stream->getFixedSlot(StreamSlot_Reader); - return reader.isObject() && reader.toObject().is(); + if (!reader.isObject()) + return false; + JSObject* unwrapped = UncheckedUnwrap(&reader.toObject()); + return unwrapped && unwrapped->is(); } static MOZ_MUST_USE bool @@ -1663,14 +1830,13 @@ ReadableStreamDefaultReader::constructor(JSContext* cx, unsigned argc, Value* vp return false; // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError exception. - if (!Is(args.get(0))) { + Rooted stream(cx, UnwrapMaybeWrappedArg(args.get(0))); + if (!stream) { ReportArgTypeError(cx, "ReadableStreamDefaultReader", "ReadableStream", args.get(0)); return false; } - Rooted stream(cx, &args.get(0).toObject().as()); - RootedObject reader(cx, CreateReadableStreamDefaultReader(cx, stream)); if (!reader) return false; @@ -1680,36 +1846,40 @@ ReadableStreamDefaultReader::constructor(JSContext* cx, unsigned argc, Value* vp } // Streams spec, 3.5.4.1 get closed -static MOZ_MUST_USE bool -ReadableStreamDefaultReader_closed(JSContext* cx, unsigned argc, Value* vp) +[[nodiscard]] static bool +ReadableStreamDefaultReader_closed_impl(JSContext* cx, const CallArgs& args) { - CallArgs args = CallArgsFromVp(argc, vp); - - // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise - // rejected with a TypeError exception. - if (!Is(args.thisv())) - return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "get closed"); - // Step 2: Return this.[[closedPromise]]. NativeObject* reader = &args.thisv().toObject().as(); args.rval().set(reader->getFixedSlot(ReaderSlot_ClosedPromise)); return true; } -static MOZ_MUST_USE JSObject* -ReadableStreamReaderGenericCancel(JSContext* cx, HandleNativeObject reader, HandleValue reason); - -// Streams spec, 3.5.4.2. cancel ( reason ) -static MOZ_MUST_USE bool -ReadableStreamDefaultReader_cancel(JSContext* cx, unsigned argc, Value* vp) +static bool +ReadableStreamDefaultReader_closed(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise // rejected with a TypeError exception. - if (!Is(args.thisv())) - return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "cancel"); + if (!Is(args.thisv())) { + if (IsMaybeWrapped(args.thisv())) { + return CallNonGenericMethod, + ReadableStreamDefaultReader_closed_impl>(cx, args); + } + return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "get closed"); + } + return ReadableStreamDefaultReader_closed_impl(cx, args); +} + +static MOZ_MUST_USE JSObject* +ReadableStreamReaderGenericCancel(JSContext* cx, HandleNativeObject reader, HandleValue reason); + +// Streams spec, 3.5.4.2. cancel ( reason ) +[[nodiscard]] static bool +ReadableStreamDefaultReader_cancel_impl(JSContext* cx, const CallArgs& args) +{ // Step 2: If this.[[ownerReadableStream]] is undefined, return a promise // rejected with a TypeError exception. RootedNativeObject reader(cx, &args.thisv().toObject().as()); @@ -1727,17 +1897,28 @@ ReadableStreamDefaultReader_cancel(JSContext* cx, unsigned argc, Value* vp) return true; } -// Streams spec, 3.5.4.3 read ( ) -static MOZ_MUST_USE bool -ReadableStreamDefaultReader_read(JSContext* cx, unsigned argc, Value* vp) +static bool +ReadableStreamDefaultReader_cancel(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise // rejected with a TypeError exception. - if (!Is(args.thisv())) - return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "read"); + if (!Is(args.thisv())) { + if (IsMaybeWrapped(args.thisv())) { + return CallNonGenericMethod, + ReadableStreamDefaultReader_cancel_impl>(cx, args); + } + return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "cancel"); + } + return ReadableStreamDefaultReader_cancel_impl(cx, args); +} + +// Streams spec, 3.5.4.3 read ( ) +[[nodiscard]] static bool +ReadableStreamDefaultReader_read_impl(JSContext* cx, const CallArgs& args) +{ // Step 2: If this.[[ownerReadableStream]] is undefined, return a promise // rejected with a TypeError exception. Rooted reader(cx); @@ -1756,7 +1937,25 @@ ReadableStreamDefaultReader_read(JSContext* cx, unsigned argc, Value* vp) return true; } -static MOZ_MUST_USE bool +static bool +ReadableStreamDefaultReader_read(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise + // rejected with a TypeError exception. + if (!Is(args.thisv())) { + if (IsMaybeWrapped(args.thisv())) { + return CallNonGenericMethod, + ReadableStreamDefaultReader_read_impl>(cx, args); + } + return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "read"); + } + + return ReadableStreamDefaultReader_read_impl(cx, args); +} + +[[nodiscard]] static bool ReadableStreamReaderGenericRelease(JSContext* cx, HandleNativeObject reader); // Streams spec, 3.5.4.4. releaseLock ( ) @@ -1811,8 +2010,7 @@ static const JSPropertySpec ReadableStreamDefaultReader_properties[] = { JS_PS_END }; -CLASS_SPEC(ReadableStreamDefaultReader, 1, ReaderSlotCount, ClassSpec::DontDefineConstructor, 0, - JS_NULL_CLASS_OPS); +CLASS_SPEC(ReadableStreamDefaultReader, 1, ReaderSlotCount, 0, 0, JS_NULL_CLASS_OPS); // Streams spec, 3.6.3 new ReadableStreamBYOBReader ( stream ) @@ -1862,12 +2060,12 @@ ReadableStreamBYOBReader::constructor(JSContext* cx, unsigned argc, Value* vp) return false; // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError exception. - if (!Is(args.get(0))) { + Rooted stream(cx, UnwrapMaybeWrappedArg(args.get(0))); + if (!stream) { ReportArgTypeError(cx, "ReadableStreamBYOBReader", "ReadableStream", args.get(0)); return false; } - Rooted stream(cx, &args.get(0).toObject().as()); RootedObject reader(cx, CreateReadableStreamBYOBReader(cx, stream)); if (!reader) return false; @@ -2026,7 +2224,7 @@ static const JSFunctionSpec ReadableStreamBYOBReader_methods[] = { JS_FS_END }; -CLASS_SPEC(ReadableStreamBYOBReader, 1, 3, ClassSpec::DontDefineConstructor, 0, JS_NULL_CLASS_OPS); +CLASS_SPEC(ReadableStreamBYOBReader, 1, 3, 0, 0, JS_NULL_CLASS_OPS); inline static MOZ_MUST_USE bool ReadableStreamControllerCallPullIfNeeded(JSContext* cx, HandleNativeObject controller); @@ -2047,7 +2245,21 @@ ReadableStreamReaderGenericCancel(JSContext* cx, HandleNativeObject reader, Hand // Step 2: Assert: stream is not undefined (implicit). // Step 3: Return ! ReadableStreamCancel(stream, reason). - return &ReadableStreamCancel(cx, stream, reason)->as(); + RootedObject cancelPromise(cx); + { + JSAutoCompartment ac(cx, stream); + RootedValue wrappedReason(cx, reason); + if (!JS_WrapValue(cx, &wrappedReason)) + return nullptr; + + cancelPromise = ReadableStreamCancel(cx, stream, wrappedReason); + if (!cancelPromise) + return nullptr; + } + + if (!JS_WrapObject(cx, &cancelPromise)) + return nullptr; + return cancelPromise; } // Streams spec, 3.7.4. ReadableStreamReaderGenericInitialize ( reader, stream ) @@ -2056,10 +2268,19 @@ ReadableStreamReaderGenericInitialize(JSContext* cx, HandleNativeObject reader, Handle stream) { // Step 1: Set reader.[[ownerReadableStream]] to stream. - reader->setFixedSlot(ReaderSlot_Stream, ObjectValue(*stream)); + RootedValue streamVal(cx, ObjectValue(*stream)); + if (!JS_WrapValue(cx, &streamVal)) + return false; + reader->setFixedSlot(ReaderSlot_Stream, streamVal); // Step 2: Set stream.[[reader]] to reader. - stream->setFixedSlot(StreamSlot_Reader, ObjectValue(*reader)); + RootedValue readerVal(cx, ObjectValue(*reader)); + { + JSAutoCompartment ac(cx, stream); + if (!JS_WrapValue(cx, &readerVal)) + return false; + stream->setFixedSlot(StreamSlot_Reader, readerVal); + } // Step 3: If stream.[[state]] is "readable", RootedObject promise(cx); @@ -2080,6 +2301,8 @@ ReadableStreamReaderGenericInitialize(JSContext* cx, HandleNativeObject reader, // Step ii: Set reader.[[closedPromise]] to a new promise rejected with // stream.[[storedError]]. RootedValue storedError(cx, stream->getFixedSlot(StreamSlot_StoredError)); + if (!JS_WrapValue(cx, &storedError)) + return false; promise = PromiseObject::unforgeableReject(cx, storedError); } @@ -2098,7 +2321,7 @@ ReadableStreamReaderGenericRelease(JSContext* cx, HandleNativeObject reader) Rooted stream(cx, StreamFromReader(reader)); // Step 2: Assert: reader.[[ownerReadableStream]].[[reader]] is reader. - MOZ_ASSERT(&stream->getFixedSlot(StreamSlot_Reader).toObject() == reader); + MOZ_ASSERT(ReaderFromStream(stream) == reader); // Create an exception to reject promises with below. We don't have a // clean way to do this, unfortunately. @@ -2156,6 +2379,8 @@ ReadableStreamBYOBReader::read(JSContext* cx, Handle // stream.[[storedError]]. if (stream->errored()) { RootedValue storedError(cx, stream->getFixedSlot(StreamSlot_StoredError)); + if (!JS_WrapValue(cx, &storedError)) + return nullptr; return PromiseObject::unforgeableReject(cx, storedError); } @@ -2347,40 +2572,12 @@ CreateReadableStreamDefaultController(JSContext* cx, Handle str bool ReadableStreamDefaultController::constructor(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - - if (!ThrowIfNotConstructing(cx, args, "ReadableStreamDefaultController")) - return false; - - // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError exception. - HandleValue streamVal = args.get(0); - if (!Is(streamVal)) { - ReportArgTypeError(cx, "ReadableStreamDefaultController", "ReadableStream", - args.get(0)); - return false; - } - - Rooted stream(cx, &streamVal.toObject().as()); - - // Step 2: If stream.[[readableStreamController]] is not undefined, throw a - // TypeError exception. - if (HasController(stream)) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_READABLESTREAM_CONTROLLER_SET); - return false; - } - - // Steps 3-11. - RootedObject controller(cx, CreateReadableStreamDefaultController(cx, stream, args.get(1), - args.get(2), args.get(3))); - if (!controller) - return false; - - args.rval().setObject(*controller); - return true; + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, + "ReadableStreamDefaultController"); + return false; } -static MOZ_MUST_USE double +[[nodiscard]] static double ReadableStreamControllerGetDesiredSizeUnchecked(NativeObject* controller); // Streams spec, 3.8.4.1. get desiredSize @@ -2390,7 +2587,8 @@ static MOZ_MUST_USE bool ReadableStreamController_desiredSize_impl(JSContext* cx, const CallArgs& args) { RootedNativeObject controller(cx); - controller = &args.thisv().toObject().as(); + controller = UnwrapMaybeWrappedReadableStreamController(args.thisv()); + MOZ_ASSERT(controller); // Streams spec, 3.9.8. steps 1-4. // 3.9.8. Step 1: Let stream be controller.[[controlledReadableStream]]. @@ -2420,8 +2618,12 @@ ReadableStreamDefaultController_desiredSize(JSContext* cx, unsigned argc, Value* // Step 1: If ! IsReadableStreamDefaultController(this) is false, throw a // TypeError exception. CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod, - ReadableStreamController_desiredSize_impl>(cx, args); + if (!IsMaybeWrapped(args.thisv())) { + ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), + nullptr, "ReadableStreamDefaultController", "get desiredSize"); + return false; + } + return ReadableStreamController_desiredSize_impl(cx, args); } static MOZ_MUST_USE bool @@ -2456,7 +2658,8 @@ static MOZ_MUST_USE bool ReadableStreamDefaultController_close_impl(JSContext* cx, const CallArgs& args) { Rooted controller(cx); - controller = &args.thisv().toObject().as(); + controller = UnwrapMaybeWrappedArg(args.thisv()); + MOZ_ASSERT(controller); // Steps 2-3. if (!VerifyControllerStateForClosing(cx, controller)) @@ -2476,8 +2679,12 @@ ReadableStreamDefaultController_close(JSContext* cx, unsigned argc, Value* vp) // TypeError exception. CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod, - ReadableStreamDefaultController_close_impl>(cx, args); + if (!IsMaybeWrapped(args.thisv())) { + ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), + nullptr, "ReadableStreamDefaultController", "close"); + return false; + } + return ReadableStreamDefaultController_close_impl(cx, args); } static MOZ_MUST_USE bool @@ -2490,7 +2697,8 @@ static MOZ_MUST_USE bool ReadableStreamDefaultController_enqueue_impl(JSContext* cx, const CallArgs& args) { Rooted controller(cx); - controller = &args.thisv().toObject().as(); + controller = UnwrapMaybeWrappedArg(args.thisv()); + MOZ_ASSERT(controller); // Step 2: If this.[[closeRequested]] is true, throw a TypeError exception. if (ControllerFlags(controller) & ControllerFlag_CloseRequested) { @@ -2522,8 +2730,12 @@ ReadableStreamDefaultController_enqueue(JSContext* cx, unsigned argc, Value* vp) // TypeError exception. CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod, - ReadableStreamDefaultController_enqueue_impl>(cx, args); + if (!IsMaybeWrapped(args.thisv())) { + ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), + nullptr, "ReadableStreamDefaultController", "enqueue"); + return false; + } + return ReadableStreamDefaultController_enqueue_impl(cx, args); } // Streams spec, 3.8.4.4. error ( e ) @@ -2531,7 +2743,8 @@ static MOZ_MUST_USE bool ReadableStreamDefaultController_error_impl(JSContext* cx, const CallArgs& args) { Rooted controller(cx); - controller = &args.thisv().toObject().as(); + controller = UnwrapMaybeWrappedArg(args.thisv()); + MOZ_ASSERT(controller); // Step 2: Let stream be this.[[controlledReadableStream]]. // Step 3: If stream.[[state]] is not "readable", throw a TypeError exception. @@ -2555,8 +2768,12 @@ ReadableStreamDefaultController_error(JSContext* cx, unsigned argc, Value* vp) // TypeError exception. CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod, - ReadableStreamDefaultController_error_impl>(cx, args); + if (!IsMaybeWrapped(args.thisv())) { + ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), + nullptr, "ReadableStreamDefaultController", "error"); + return false; + } + return ReadableStreamDefaultController_error_impl(cx, args); } static const JSPropertySpec ReadableStreamDefaultController_properties[] = { @@ -2571,8 +2788,7 @@ static const JSFunctionSpec ReadableStreamDefaultController_methods[] = { JS_FS_END }; -CLASS_SPEC(ReadableStreamDefaultController, 4, 7, ClassSpec::DontDefineConstructor, 0, - JS_NULL_CLASS_OPS); +CLASS_SPEC(ReadableStreamDefaultController, 4, 7, 0, 0, JS_NULL_CLASS_OPS); /** * Unified implementation of ReadableStream controllers' [[CancelSteps]] internal @@ -3116,36 +3332,9 @@ ReadableByteStreamController::hasExternalSource() { bool ReadableByteStreamController::constructor(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - - if (!ThrowIfNotConstructing(cx, args, "ReadableByteStreamController")) - return false; - - // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError exception. - HandleValue streamVal = args.get(0); - if (!Is(streamVal)) { - ReportArgTypeError(cx, "ReadableStreamDefaultController", "ReadableStream", - args.get(0)); - return false; - } - - Rooted stream(cx, &streamVal.toObject().as()); - - // Step 2: If stream.[[readableStreamController]] is not undefined, throw a - // TypeError exception. - if (HasController(stream)) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_READABLESTREAM_CONTROLLER_SET); - return false; - } - - RootedObject controller(cx, CreateReadableByteStreamController(cx, stream, args.get(1), - args.get(2))); - if (!controller) - return false; - - args.rval().setObject(*controller); - return true; + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, + "ReadableByteStreamController"); + return false; } // Version of the ReadableByteStreamConstructor that's specialized for @@ -3451,8 +3640,8 @@ static const ClassOps ReadableByteStreamControllerClassOps = { nullptr, /* trace */ }; -CLASS_SPEC(ReadableByteStreamController, 3, 9, ClassSpec::DontDefineConstructor, - JSCLASS_BACKGROUND_FINALIZE, &ReadableByteStreamControllerClassOps); +CLASS_SPEC(ReadableByteStreamController, 3, 9, 0, JSCLASS_BACKGROUND_FINALIZE, + &ReadableByteStreamControllerClassOps); // Streams spec, 3.10.5.1. [[PullSteps]] () // Unified with 3.8.5.1 above. @@ -3638,38 +3827,9 @@ CreateReadableStreamBYOBRequest(JSContext* cx, Handle(controllerVal)) { - ReportArgTypeError(cx, "ReadableStreamBYOBRequest", - "ReadableByteStreamController", args.get(0)); - return false; - } - - Rooted controller(cx); - controller = &controllerVal.toObject().as(); - - if (!viewVal.isObject() || !JS_IsArrayBufferViewObject(&viewVal.toObject())) { - ReportArgTypeError(cx, "ReadableStreamBYOBRequest", "ArrayBuffer view", - args.get(1)); - return false; - } - - RootedArrayBufferObject view(cx, &viewVal.toObject().as()); - - RootedObject request(cx, CreateReadableStreamBYOBRequest(cx, controller, view)); - if (!request) - return false; - - args.rval().setObject(*request); - return true; + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, + "ReadableStreamBYOBRequest"); + return false; } // Streams spec, 3.11.4.1 get view @@ -3804,8 +3964,7 @@ static const JSFunctionSpec ReadableStreamBYOBRequest_methods[] = { JS_FS_END }; -CLASS_SPEC(ReadableStreamBYOBRequest, 3, 2, ClassSpec::DontDefineConstructor, 0, - JS_NULL_CLASS_OPS); +CLASS_SPEC(ReadableStreamBYOBRequest, 3, 2, 0, 0, JS_NULL_CLASS_OPS); // Streams spec, 3.12.1. IsReadableStreamBYOBRequest ( x ) // Implemented via is() @@ -4899,7 +5058,15 @@ js::ByteLengthQueuingStrategy::constructor(JSContext* cx, unsigned argc, Value* { CallArgs args = CallArgsFromVp(argc, vp); - RootedObject strategy(cx, NewBuiltinClassInstance(cx)); + if (!ThrowIfNotConstructing(cx, args, "ByteLengthQueuingStrategy")) + return false; + + RootedObject proto(cx); + RootedObject newTarget(cx, &args.newTarget().toObject()); + if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) + return false; + + RootedObject strategy(cx, NewObjectWithClassProto(cx, proto)); if (!strategy) return false; @@ -4945,7 +5112,16 @@ js::CountQueuingStrategy::constructor(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - Rooted strategy(cx, NewBuiltinClassInstance(cx)); + if (!ThrowIfNotConstructing(cx, args, "CountQueuingStrategy")) + return false; + + RootedObject proto(cx); + RootedObject newTarget(cx, &args.newTarget().toObject()); + if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) + return false; + + Rooted strategy(cx); + strategy = NewObjectWithClassProto(cx, proto); if (!strategy) return false; @@ -4998,7 +5174,8 @@ DequeueValue(JSContext* cx, HandleNativeObject container, MutableHandleValue chu // Step 2: Assert: queue is not empty. RootedValue val(cx, container->getFixedSlot(QueueContainerSlot_Queue)); - RootedNativeObject queue(cx, &val.toObject().as()); + RootedNativeObject queue(cx); + queue = UnwrapInternalSlotObject(&val.toObject()); MOZ_ASSERT(queue->getDenseInitializedLength() > 0); // Step 3. Let pair be the first element of queue. @@ -5020,7 +5197,10 @@ DequeueValue(JSContext* cx, HandleNativeObject container, MutableHandleValue chu container->setFixedSlot(QueueContainerSlot_TotalSize, NumberValue(totalSize)); // Step 7: Return pair.[[value]]. - chunk.set(pair->value()); + RootedValue chunkVal(cx, pair->value()); + if (!JS_WrapValue(cx, &chunkVal)) + return false; + chunk.set(chunkVal); return true; } @@ -5049,19 +5229,27 @@ EnqueueValueWithSize(JSContext* cx, HandleNativeObject container, HandleValue va // Step 4: Append Record {[[value]]: value, [[size]]: size} as the last element // of container.[[queue]]. RootedValue val(cx, container->getFixedSlot(QueueContainerSlot_Queue)); - RootedNativeObject queue(cx, &val.toObject().as()); + RootedNativeObject queue(cx); + queue = UnwrapInternalSlotObject(&val.toObject()); - QueueEntry* entry = QueueEntry::create(cx, value, size); - if (!entry) - return false; - val = ObjectValue(*entry); - if (!AppendToList(cx, queue, val)) - return false; + { + JSAutoCompartment ac(cx, queue); + RootedValue wrappedValue(cx, value); + if (!JS_WrapValue(cx, &wrappedValue)) + return false; - // Step 5: Set container.[[queueTotalSize]] to - // container.[[queueTotalSize]] + size. - double totalSize = container->getFixedSlot(QueueContainerSlot_TotalSize).toNumber(); - container->setFixedSlot(QueueContainerSlot_TotalSize, NumberValue(totalSize + size)); + QueueEntry* entry = QueueEntry::create(cx, wrappedValue, size); + if (!entry) + return false; + val = ObjectValue(*entry); + if (!AppendToList(cx, queue, val)) + return false; + + // Step 5: Set container.[[queueTotalSize]] to + // container.[[queueTotalSize]] + size. + double totalSize = container->getFixedSlot(QueueContainerSlot_TotalSize).toNumber(); + container->setFixedSlot(QueueContainerSlot_TotalSize, NumberValue(totalSize + size)); + } return true; } @@ -5486,3 +5674,2285 @@ js::UnwrapReadableStream(JSObject* obj) return unwrapped->is() ? unwrapped : nullptr; return nullptr; } + +namespace { + +enum class StreamCompressionFormat { + Deflate, + DeflateRaw, + Gzip +}; + +struct StreamCompressionContext +{ + z_stream mStream; + StreamCompressionFormat mFormat; + bool mCompress; + bool mFinished; + bool mInitialized; + + StreamCompressionContext(StreamCompressionFormat format, bool compress) + : mFormat(format), + mCompress(compress), + mFinished(false), + mInitialized(false) + { + memset(&mStream, 0, sizeof(mStream)); + } + + ~StreamCompressionContext() + { + if (!mInitialized) + return; + if (mCompress) + deflateEnd(&mStream); + else + inflateEnd(&mStream); + } +}; + +static int +WindowBitsForFormat(StreamCompressionFormat format) +{ + switch (format) { + case StreamCompressionFormat::Deflate: + return MAX_WBITS; + case StreamCompressionFormat::DeflateRaw: + return -MAX_WBITS; + case StreamCompressionFormat::Gzip: + return MAX_WBITS + 16; + } + MOZ_CRASH("Unknown compression stream format"); +} + +static bool +ParseCompressionFormat(JSContext* cx, HandleValue value, + StreamCompressionFormat* format) +{ + RootedString str(cx, ToString(cx, value)); + if (!str) + return false; + + bool match = false; + if (!JS_StringEqualsAscii(cx, str, "deflate", &match)) + return false; + if (match) { + *format = StreamCompressionFormat::Deflate; + return true; + } + + if (!JS_StringEqualsAscii(cx, str, "deflate-raw", &match)) + return false; + if (match) { + *format = StreamCompressionFormat::DeflateRaw; + return true; + } + + if (!JS_StringEqualsAscii(cx, str, "gzip", &match)) + return false; + if (match) { + *format = StreamCompressionFormat::Gzip; + return true; + } + + if (!JS_StringEqualsAscii(cx, str, "brotli", &match)) + return false; + + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_NOT_EXPECTED_TYPE, + "CompressionStream", "supported format", + match ? "unsupported brotli format" : "unknown format"); + return false; +} + +static void +StreamCompressionContextFinalize(FreeOp* fop, JSObject* obj) +{ + auto* context = static_cast(JS_GetPrivate(obj)); + if (context) + js_delete(context); +} + +static const ClassOps StreamCompressionContextClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + StreamCompressionContextFinalize, + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr /* trace */ +}; + +static const Class StreamCompressionContextClass = { + "StreamCompressionContext", + JSCLASS_HAS_PRIVATE, + &StreamCompressionContextClassOps +}; + +static bool +CreateStreamCompressionContext(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() < 2) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_MORE_ARGS_NEEDED, + "__uxpCreateCompressionContext", "1", "s"); + return false; + } + + StreamCompressionFormat format; + if (!ParseCompressionFormat(cx, args.get(0), &format)) + return false; + + bool compress = ToBoolean(args.get(1)); + auto* context = js_new(format, compress); + if (!context) { + ReportOutOfMemory(cx); + return false; + } + + int windowBits = WindowBitsForFormat(format); + int zerr = compress + ? deflateInit2(&context->mStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, + windowBits, 8, Z_DEFAULT_STRATEGY) + : inflateInit2(&context->mStream, windowBits); + if (zerr != Z_OK) { + js_delete(context); + JS_ReportErrorASCII(cx, "Failed to initialize compression stream"); + return false; + } + context->mInitialized = true; + + RootedObject obj(cx, NewObjectWithGivenProto(cx, &StreamCompressionContextClass, nullptr)); + if (!obj) { + js_delete(context); + return false; + } + + JS_SetPrivate(obj, context); + args.rval().setObject(*obj); + return true; +} + +static bool +GetBufferSourceBytes(JSContext* cx, HandleValue value, Vector* bytes) +{ + if (!value.isObject()) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_NOT_EXPECTED_TYPE, + "CompressionStream", "BufferSource", + InformalValueTypeName(value)); + return false; + } + + RootedObject obj(cx, &value.toObject()); + if (JS_IsArrayBufferViewObject(obj)) { + uint32_t length = JS_GetArrayBufferViewByteLength(obj); + if (length == 0) + return true; + + JS::AutoCheckCannotGC nogc(cx); + bool isShared; + uint8_t* data = static_cast(JS_GetArrayBufferViewData(obj, &isShared, nogc)); + return bytes->append(data, length); + } + + if (JS_IsArrayBufferObject(obj)) { + uint32_t length = JS_GetArrayBufferByteLength(obj); + if (length == 0) + return true; + + JS::AutoCheckCannotGC nogc(cx); + bool isShared; + uint8_t* data = JS_GetArrayBufferData(obj, &isShared, nogc); + return bytes->append(data, length); + } + + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_NOT_EXPECTED_TYPE, + "CompressionStream", "BufferSource", + obj->getClass()->name); + return false; +} + +static bool +AppendUint8Array(JSContext* cx, HandleObject array, uint32_t* index, + const uint8_t* data, size_t length) +{ + if (length == 0) + return true; + + if (length > UINT32_MAX) { + ReportAllocationOverflow(cx); + return false; + } + + RootedObject view(cx, JS_NewUint8Array(cx, length)); + if (!view) + return false; + + { + JS::AutoCheckCannotGC nogc(cx); + bool isShared; + uint8_t* viewData = static_cast(JS_GetArrayBufferViewData(view, &isShared, nogc)); + memcpy(viewData, data, length); + } + + RootedValue viewVal(cx, ObjectValue(*view)); + return JS_SetElement(cx, array, (*index)++, viewVal); +} + +static bool +StreamCompressionProcess(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() < 3 || !args[0].isObject() || + !args[0].toObject().hasClass(&StreamCompressionContextClass)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_NOT_EXPECTED_TYPE, + "__uxpCompressionProcess", + "StreamCompressionContext", "other"); + return false; + } + + auto* context = + static_cast(JS_GetPrivate(&args[0].toObject())); + if (!context) { + JS_ReportErrorASCII(cx, "Compression stream is already finished"); + return false; + } + + bool finish = ToBoolean(args.get(2)); + + if (context->mFinished) { + if (finish && args.get(1).isUndefined()) { + RootedObject emptyChunks(cx, JS_NewArrayObject(cx, 0)); + if (!emptyChunks) + return false; + args.rval().setObject(*emptyChunks); + return true; + } + JS_ReportErrorASCII(cx, "Compression stream is already finished"); + return false; + } + + Vector input(cx); + if (!args.get(1).isUndefined() && !GetBufferSourceBytes(cx, args.get(1), &input)) + return false; + + RootedObject chunks(cx, JS_NewArrayObject(cx, 0)); + if (!chunks) + return false; + + z_stream& stream = context->mStream; + stream.next_in = input.empty() ? nullptr : input.begin(); + stream.avail_in = input.length(); + + uint32_t chunkIndex = 0; + const int flush = finish ? Z_FINISH : Z_NO_FLUSH; + bool madeProgress; + + do { + uint8_t output[16384]; + stream.next_out = output; + stream.avail_out = sizeof(output); + + uint32_t beforeIn = stream.avail_in; + uint32_t beforeOut = stream.avail_out; + int zerr = context->mCompress ? deflate(&stream, flush) : inflate(&stream, flush); + + size_t produced = sizeof(output) - stream.avail_out; + if (!AppendUint8Array(cx, chunks, &chunkIndex, output, produced)) + return false; + + madeProgress = produced > 0 || stream.avail_in != beforeIn || + stream.avail_out != beforeOut; + + if (zerr == Z_STREAM_END) { + context->mFinished = true; + if (!context->mCompress && stream.avail_in != 0) { + JS_ReportErrorASCII(cx, "Compressed input has trailing data"); + return false; + } + break; + } + + if (zerr == Z_BUF_ERROR && !madeProgress) + break; + + if (zerr != Z_OK && zerr != Z_BUF_ERROR) { + JS_ReportErrorASCII(cx, stream.msg ? stream.msg : "Compression stream error"); + return false; + } + } while (stream.avail_out == 0 || stream.avail_in != 0 || + (finish && !context->mFinished && madeProgress)); + + if (finish && !context->mFinished) { + JS_ReportErrorASCII(cx, "Compressed input ended before the end of stream"); + return false; + } + + args.rval().setObject(*chunks); + return true; +} + +bool +ReleaseReadableStreamReaderSilently(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + args.rval().setBoolean(true); + + if (!args.get(0).isObject()) + return true; + + RootedObject readerObj(cx, &args[0].toObject()); + if (!readerObj->is() && + !readerObj->is()) + return true; + + RootedNativeObject reader(cx, &readerObj->as()); + if (!ReaderHasStream(reader)) + return true; + + Value requestsVal = reader->getFixedSlot(ReaderSlot_Requests); + if (!requestsVal.isUndefined()) { + NativeObject* requests = &requestsVal.toObject().as(); + if (requests->getDenseInitializedLength() != 0) { + args.rval().setBoolean(false); + return true; + } + } + + Rooted stream(cx, StreamFromReader(reader)); + MOZ_ASSERT(&stream->getFixedSlot(StreamSlot_Reader).toObject() == reader); + + RootedObject closedPromise(cx, PromiseObject::unforgeableResolve(cx, UndefinedHandleValue)); + if (!closedPromise) + return false; + reader->setFixedSlot(ReaderSlot_ClosedPromise, ObjectValue(*closedPromise)); + + stream->setFixedSlot(StreamSlot_Reader, UndefinedValue()); + reader->setFixedSlot(ReaderSlot_Stream, UndefinedValue()); + return true; +} + +} // anonymous namespace + +bool +js::InitStreamExtras(JSContext* cx, HandleObject global) +{ + if (!JS_DefineFunction(cx, global, "__uxpCreateCompressionContext", + CreateStreamCompressionContext, 2, 0)) + return false; + + if (!JS_DefineFunction(cx, global, "__uxpCompressionProcess", + StreamCompressionProcess, 3, 0)) + return false; + + if (!JS_DefineFunction(cx, global, "__uxpReleaseReadableStreamReaderSilently", + ReleaseReadableStreamReaderSilently, 1, 0)) + return false; + + static const char source[] = + R"JS( +(function(global) { + "use strict"; + + if (global.__uxpStreamsInitialized) + return; + Object.defineProperty(global, "__uxpStreamsInitialized", + { value: true, configurable: true }); + + var objectToString = Object.prototype.toString; + var hasOwn = Object.prototype.hasOwnProperty; + + function isObject(value) { + return (typeof value === "object" && value !== null) || + typeof value === "function"; + } + + function requiredObject(value, name) { + if (!isObject(value)) + throw new TypeError(name + " is not an object"); + return value; + } + + function newPromiseCapability() { + var resolve, reject; + var promise = new Promise(function(res, rej) { + resolve = res; + reject = rej; + }); + return { promise: promise, resolve: resolve, reject: reject }; + } + + function promiseCall(fn, receiver, args) { + try { + return Promise.resolve(fn.apply(receiver, args || [])); + } catch (e) { + return Promise.reject(e); + } + } + + function getMethod(value, name) { + var method = value[name]; + if (method === undefined || method === null) + return undefined; + if (typeof method !== "function") + throw new TypeError(name + " is not callable"); + return method; + } + + function makeDOMException(message, name) { + if (typeof global.DOMException === "function") + return new global.DOMException(message, name); + var error = new Error(message); + error.name = name; + return error; + } + + function define(name, value) { + if (hasOwn.call(global, name) && global[name] !== undefined) + return; + Object.defineProperty(global, name, { + value: value, + writable: true, + configurable: true + }); + } + + var writableState = new WeakMap(); + var writerState = new WeakMap(); + var writableControllerState = new WeakMap(); + + function isWritableStream(stream) { + return writableState.has(stream); + } + + function isWritableStreamDefaultWriter(writer) { + return writerState.has(writer); + } + + function rejectPromise(error) { + return Promise.reject(error); + } + + function silenceRejection(promise) { + try { + if (promise && typeof promise.catch === "function") + promise.catch(function() {}); + } catch (e) {} + } + + function releaseReaderLock(reader) { + try { + if (global.__uxpReleaseReadableStreamReaderSilently(reader)) + return; + } catch (e) {} + Promise.resolve().then(function() { + try { + if (global.__uxpReleaseReadableStreamReaderSilently(reader)) + return; + } catch (e) {} + try { silenceRejection(reader.closed); } catch (e) {} + try { reader.releaseLock(); } catch (e) {} + }); + } + + function releaseWriterLock(writer) { + try { silenceRejection(writer.closed); } catch (e) {} + try { silenceRejection(writer.ready); } catch (e) {} + try { writer.releaseLock(); } catch (e) {} + } + + function syncWritableWriterWithStream(writer, state) { + var ws = writerState.get(writer); + if (!ws || ws.stream === undefined) + return; + + ws.readyPromise = state.readyPromise; + if (state.state === "closed") { + ws.closedPromise = Promise.resolve(undefined); + } else if (state.state === "errored") { + ws.closedPromise = Promise.reject(state.storedError); + ws.closedPromise.catch(function() {}); + } else { + ws.closedPromise = state.closedPromise; + } + } + + function writableError(stream, error) { + var state = writableState.get(stream); + if (!state || state.state === "closed" || state.state === "errored") + return; + state.state = "errored"; + state.storedError = error; + state.ready.reject(error); + state.closed.reject(error); + state.readyPromise.catch(function() {}); + state.closedPromise.catch(function() {}); + if (state.writer) + syncWritableWriterWithStream(state.writer, state); + } + + function writableClose(stream) { + var state = writableState.get(stream); + if (!state || state.state === "closed") + return; + state.state = "closed"; + state.ready.resolve(undefined); + state.closed.resolve(undefined); + if (state.writer) + syncWritableWriterWithStream(state.writer, state); + } + + function writableStreamWrite(stream, chunk) { + var state = writableState.get(stream); + if (!state) + return rejectPromise(new TypeError("WritableStream expected")); + if (state.state === "closed") + return rejectPromise(new TypeError("WritableStream is closed")); + if (state.state === "errored") + return rejectPromise(state.storedError); + if (state.state === "closing") + return rejectPromise(new TypeError("WritableStream is closing")); + + var size = 1; + try { + size = state.sizeAlgorithm(chunk); + if (!Number.isFinite(size) || size < 0) + throw new RangeError("Invalid chunk size"); + } catch (e) { + writableError(stream, e); + return rejectPromise(e); + } + + state.queueTotalSize += size; + if (state.queueTotalSize > state.highWaterMark && state.backpressure === false) { + state.backpressure = true; + state.ready = newPromiseCapability(); + state.readyPromise = state.ready.promise; + if (state.writer) + syncWritableWriterWithStream(state.writer, state); + } + + var write = state.sink.write; + var controller = state.controller; + var writePromise = state.writeChain.then(function() { + if (state.state === "errored") + throw state.storedError; + if (write) + return write.call(state.sink, chunk, controller); + return undefined; + }); + state.writeChain = writePromise.then(function(value) { + state.queueTotalSize -= size; + if (state.queueTotalSize <= state.highWaterMark && state.backpressure) { + state.backpressure = false; + state.ready.resolve(undefined); + state.ready = newPromiseCapability(); + state.ready.resolve(undefined); + state.readyPromise = state.ready.promise; + if (state.writer) + syncWritableWriterWithStream(state.writer, state); + } + return value; + }, function(error) { + writableError(stream, error); + throw error; + }); + state.writeChain.catch(function() {}); + return writePromise; + } + + function writableStreamClose(stream) { + var state = writableState.get(stream); + if (!state) + return rejectPromise(new TypeError("WritableStream expected")); + if (state.state === "closed") + return rejectPromise(new TypeError("WritableStream is already closed")); + if (state.state === "errored") + return rejectPromise(state.storedError); + if (state.state === "closing") + return rejectPromise(new TypeError("WritableStream is already closing")); + + state.state = "closing"; + var close = state.sink.close; + var closePromise = state.writeChain.then(function() { + if (close) + return close.call(state.sink); + return undefined; + }).then(function(value) { + writableClose(stream); + return value; + }, function(error) { + writableError(stream, error); + throw error; + }); + state.writeChain = closePromise.catch(function() {}); + return closePromise; + } + + function writableStreamAbort(stream, reason) { + var state = writableState.get(stream); + if (!state) + return rejectPromise(new TypeError("WritableStream expected")); + if (state.state === "closed") + return Promise.resolve(undefined); + if (state.state === "errored") + return rejectPromise(state.storedError); + + var abort = state.sink.abort; + state.state = "errored"; + state.storedError = reason; + if (state.abortController) { + try { state.abortController.abort(); } catch (e) {} + } + state.ready.reject(reason); + state.closed.reject(reason); + state.readyPromise.catch(function() {}); + state.closedPromise.catch(function() {}); + if (state.writer) + syncWritableWriterWithStream(state.writer, state); + + var abortPromise = abort ? promiseCall(abort, state.sink, [reason]) + : Promise.resolve(undefined); + return abortPromise; + } + + function WritableStreamDefaultController() { + throw new TypeError("Illegal constructor"); + } + + WritableStreamDefaultController.prototype.error = function(error) { + var state = writableControllerState.get(this); + if (!state) + throw new TypeError("WritableStreamDefaultController expected"); + writableError(state.stream, error); + }; + + try { + Object.defineProperty(WritableStreamDefaultController.prototype, "signal", { + configurable: true, + get: function() { + var state = writableControllerState.get(this); + if (!state) + throw new TypeError("WritableStreamDefaultController expected"); + return state.abortController ? state.abortController.signal : undefined; + } + }); + } catch (e) {} + + Object.defineProperty(WritableStreamDefaultController.prototype, + Symbol.toStringTag, + { value: "WritableStreamDefaultController", + configurable: true }); + + function WritableStream(underlyingSink, strategy) { + if (!(this instanceof WritableStream)) + throw new TypeError("WritableStream must be constructed with new"); + + underlyingSink = underlyingSink === undefined ? {} : requiredObject(underlyingSink, "underlyingSink"); + strategy = strategy === undefined ? {} : requiredObject(strategy, "strategy"); + + if (underlyingSink.type !== undefined) + throw new RangeError("Invalid writable stream type"); + + var highWaterMark = strategy.highWaterMark === undefined ? 1 : Number(strategy.highWaterMark); + if (Number.isNaN(highWaterMark) || highWaterMark < 0) + throw new RangeError("Invalid highWaterMark"); + + var sizeAlgorithm = strategy.size; + if (sizeAlgorithm === undefined) + sizeAlgorithm = function() { return 1; }; + if (typeof sizeAlgorithm !== "function") + throw new TypeError("strategy.size is not callable"); + + var controller = Object.create(WritableStreamDefaultController.prototype); + var abortController = typeof global.AbortController === "function" + ? new global.AbortController() + : undefined; + var ready = newPromiseCapability(); + ready.resolve(undefined); + var closed = newPromiseCapability(); + var state = { + sink: underlyingSink, + controller: controller, + signal: undefined, + state: "writable", + storedError: undefined, + writer: undefined, + abortController: abortController, + writeChain: Promise.resolve(undefined), + ready: ready, + readyPromise: ready.promise, + closed: closed, + closedPromise: closed.promise, + highWaterMark: highWaterMark, + sizeAlgorithm: sizeAlgorithm, + queueTotalSize: 0, + backpressure: false + }; + writableState.set(this, state); + writableControllerState.set(controller, { + stream: this, + abortController: abortController + }); + + var start = underlyingSink.start; + if (start !== undefined) { + if (typeof start !== "function") + throw new TypeError("underlyingSink.start is not callable"); + state.writeChain = promiseCall(start, underlyingSink, [controller]).catch(function(error) { + writableError(this, error); + throw error; + }.bind(this)); + state.writeChain.catch(function() {}); + } + } + + Object.defineProperty(WritableStream.prototype, "locked", { + configurable: true, + get: function() { + var state = writableState.get(this); + if (!state) + throw new TypeError("WritableStream expected"); + return state.writer !== undefined; + } + }); + + WritableStream.prototype.abort = function(reason) { + if (!isWritableStream(this)) + return rejectPromise(new TypeError("WritableStream expected")); + if (writableState.get(this).writer !== undefined) + return rejectPromise(new TypeError("WritableStream is locked")); + return writableStreamAbort(this, reason); + }; + + WritableStream.prototype.close = function() { + if (!isWritableStream(this)) + return rejectPromise(new TypeError("WritableStream expected")); + if (writableState.get(this).writer !== undefined) + return rejectPromise(new TypeError("WritableStream is locked")); + return writableStreamClose(this); + }; + + WritableStream.prototype.getWriter = function() { + if (!isWritableStream(this)) + throw new TypeError("WritableStream expected"); + return new WritableStreamDefaultWriter(this); + }; + + Object.defineProperty(WritableStream.prototype, Symbol.toStringTag, + { value: "WritableStream", configurable: true }); + + function WritableStreamDefaultWriter(stream) { + if (!(this instanceof WritableStreamDefaultWriter)) + throw new TypeError("WritableStreamDefaultWriter must be constructed with new"); + if (!isWritableStream(stream)) + throw new TypeError("WritableStream expected"); + + var state = writableState.get(stream); + if (state.writer !== undefined) + throw new TypeError("WritableStream is locked"); + + state.writer = this; + writerState.set(this, { + stream: stream, + readyPromise: state.readyPromise, + closedPromise: state.closedPromise + }); + } + + Object.defineProperty(WritableStreamDefaultWriter.prototype, "closed", { + configurable: true, + get: function() { + var state = writerState.get(this); + if (!state) + return rejectPromise(new TypeError("WritableStreamDefaultWriter expected")); + return state.closedPromise; + } + }); + + Object.defineProperty(WritableStreamDefaultWriter.prototype, "desiredSize", { + configurable: true, + get: function() { + var state = writerState.get(this); + if (!state) + throw new TypeError("WritableStreamDefaultWriter expected"); + if (state.stream === undefined) + throw new TypeError("Writer lock is released"); + var streamState = writableState.get(state.stream); + if (streamState.state === "errored") + return null; + if (streamState.state === "closed") + return 0; + return streamState.highWaterMark - streamState.queueTotalSize; + } + }); + + Object.defineProperty(WritableStreamDefaultWriter.prototype, "ready", { + configurable: true, + get: function() { + var state = writerState.get(this); + if (!state) + return rejectPromise(new TypeError("WritableStreamDefaultWriter expected")); + return state.readyPromise; + } + }); + + WritableStreamDefaultWriter.prototype.abort = function(reason) { + var state = writerState.get(this); + if (!state || state.stream === undefined) + return rejectPromise(new TypeError("Writer lock is released")); + return writableStreamAbort(state.stream, reason); + }; + + WritableStreamDefaultWriter.prototype.close = function() { + var state = writerState.get(this); + if (!state || state.stream === undefined) + return rejectPromise(new TypeError("Writer lock is released")); + return writableStreamClose(state.stream); + }; + + WritableStreamDefaultWriter.prototype.releaseLock = function() { + var state = writerState.get(this); + if (!state) + throw new TypeError("WritableStreamDefaultWriter expected"); + if (state.stream === undefined) + return; + var streamState = writableState.get(state.stream); + if (streamState.writer === this) + streamState.writer = undefined; + state.stream = undefined; + state.readyPromise = rejectPromise(new TypeError("Writer lock is released")); + state.closedPromise = rejectPromise(new TypeError("Writer lock is released")); + state.readyPromise.catch(function() {}); + state.closedPromise.catch(function() {}); + }; + + WritableStreamDefaultWriter.prototype.write = function(chunk) { + var state = writerState.get(this); + if (!state || state.stream === undefined) + return rejectPromise(new TypeError("Writer lock is released")); + return writableStreamWrite(state.stream, chunk); + }; + +)JS" +R"JS( + + Object.defineProperty(WritableStreamDefaultWriter.prototype, Symbol.toStringTag, + { value: "WritableStreamDefaultWriter", + configurable: true }); + + var transformState = new WeakMap(); + var transformControllerState = new WeakMap(); + + function TransformStreamDefaultController() { + throw new TypeError("Illegal constructor"); + } + + Object.defineProperty(TransformStreamDefaultController.prototype, "desiredSize", { + configurable: true, + get: function() { + var state = transformControllerState.get(this); + if (!state) + throw new TypeError("TransformStreamDefaultController expected"); + return state.readableController.desiredSize; + } + }); + + TransformStreamDefaultController.prototype.enqueue = function(chunk) { + var state = transformControllerState.get(this); + if (!state) + throw new TypeError("TransformStreamDefaultController expected"); + state.readableController.enqueue(chunk); + }; + + TransformStreamDefaultController.prototype.error = function(reason) { + var state = transformControllerState.get(this); + if (!state) + throw new TypeError("TransformStreamDefaultController expected"); + state.readableController.error(reason); + writableError(state.stream.writable, reason); + }; + + TransformStreamDefaultController.prototype.terminate = function() { + var state = transformControllerState.get(this); + if (!state) + throw new TypeError("TransformStreamDefaultController expected"); + try { + state.readableController.close(); + } catch (e) {} + writableError(state.stream.writable, new TypeError("TransformStream terminated")); + }; + + Object.defineProperty(TransformStreamDefaultController.prototype, + Symbol.toStringTag, + { value: "TransformStreamDefaultController", + configurable: true }); + + function errorReadableController(controller, error) { + try { + controller.error(error); + } catch (e) {} + } + + function TransformStream(transformer, writableStrategy, readableStrategy) { + if (!(this instanceof TransformStream)) + throw new TypeError("TransformStream must be constructed with new"); + + transformer = transformer === undefined ? {} : requiredObject(transformer, "transformer"); + writableStrategy = writableStrategy === undefined ? {} : requiredObject(writableStrategy, "writableStrategy"); + readableStrategy = readableStrategy === undefined ? {} : requiredObject(readableStrategy, "readableStrategy"); + + if (transformer.readableType !== undefined) + throw new RangeError("Invalid readableType"); + if (transformer.writableType !== undefined) + throw new RangeError("Invalid writableType"); + + var controller = Object.create(TransformStreamDefaultController.prototype); + var readableController; + var stream = this; + var startAlgorithm = getMethod(transformer, "start"); + var transformAlgorithm = getMethod(transformer, "transform"); + var flushAlgorithm = getMethod(transformer, "flush"); + var cancelAlgorithm = getMethod(transformer, "cancel"); + + var readable = new ReadableStream({ + start: function(c) { + readableController = c; + transformControllerState.set(controller, { + stream: stream, + readableController: c + }); + }, + cancel: function(reason) { + if (cancelAlgorithm) + return cancelAlgorithm.call(transformer, reason); + return undefined; + } + }, readableStrategy); + + var startPromise = startAlgorithm + ? promiseCall(startAlgorithm, transformer, [controller]) + : Promise.resolve(undefined); + startPromise = startPromise.then(undefined, function(error) { + if (readableController) + errorReadableController(readableController, error); + throw error; + }); + + var writable = new WritableStream({ + start: function() { + return startPromise; + }, + write: function(chunk) { + var result; + try { + if (transformAlgorithm) { + result = transformAlgorithm.call(transformer, chunk, controller); + } else { + controller.enqueue(chunk); + result = undefined; + } + } catch (error) { + errorReadableController(readableController, error); + throw error; + } + return Promise.resolve(result).then(undefined, function(error) { + errorReadableController(readableController, error); + throw error; + }); + }, + close: function() { + var result = flushAlgorithm + ? promiseCall(flushAlgorithm, transformer, [controller]) + : Promise.resolve(undefined); + return result.then(function() { + readableController.close(); + }, function(error) { + errorReadableController(readableController, error); + throw error; + }); + }, + abort: function(reason) { + readableController.error(reason); + } + }, writableStrategy); + + transformState.set(this, { + readable: readable, + writable: writable, + controller: controller + }); + } + + Object.defineProperty(TransformStream.prototype, "readable", { + configurable: true, + get: function() { + var state = transformState.get(this); + if (!state) + throw new TypeError("TransformStream expected"); + return state.readable; + } + }); + + Object.defineProperty(TransformStream.prototype, "writable", { + configurable: true, + get: function() { + var state = transformState.get(this); + if (!state) + throw new TypeError("TransformStream expected"); + return state.writable; + } + }); + + Object.defineProperty(TransformStream.prototype, Symbol.toStringTag, + { value: "TransformStream", configurable: true }); + + function isReadableStreamObject(value) { + if (!isObject(value) || !global.ReadableStream) + return false; + try { + return value instanceof global.ReadableStream; + } catch (e) { + return false; + } + } + + function isUncloneableStreamChunk(value) { + return isObject(value) && + (isWritableStream(value) || + isReadableStreamObject(value) || + transformState.has(value)); + } + + function makeDataCloneError() { + return makeDOMException("The object could not be cloned.", "DataCloneError"); + } + + function cloneTransferReasonError(value) { + var constructors = [ + global.EvalError, + global.RangeError, + global.ReferenceError, + global.SyntaxError, + global.TypeError, + global.URIError, + global.Error + ]; + + for (var i = 0; i < constructors.length; ++i) { + var C = constructors[i]; + if (typeof C !== "function") + continue; + try { + if (!(value instanceof C)) + continue; + } catch (e) { + continue; + } + + var message = ""; + var descriptor; + try { + descriptor = Object.getOwnPropertyDescriptor(value, "message"); + } catch (e) { + descriptor = undefined; + } + if (descriptor && hasOwn.call(descriptor, "value")) + message = String(descriptor.value); + return new C(message); + } + + return undefined; + } + + function cloneTransferReasonValue(value, memory) { + if (typeof value === "function" || typeof value === "symbol") + throw makeDataCloneError(); + if (!isObject(value)) + return value; + if (isUncloneableStreamChunk(value)) + throw makeDataCloneError(); + + memory = memory || new WeakMap(); + if (memory.has(value)) + return memory.get(value); + + if (typeof global.DOMException === "function") { + try { + if (value instanceof global.DOMException) { + return new global.DOMException(String(value.message), + String(value.name)); + } + } catch (e) {} + } + + var errorClone = cloneTransferReasonError(value); + if (errorClone !== undefined) + return errorClone; + + if (typeof global.ArrayBuffer === "function") { + try { + if (value instanceof global.ArrayBuffer) { + var bufferClone = value.slice(0); + memory.set(value, bufferClone); + return bufferClone; + } + } catch (e) {} + } + + if (global.ArrayBuffer && global.ArrayBuffer.isView && + global.ArrayBuffer.isView(value)) { + var clonedBuffer = cloneTransferReasonValue(value.buffer, memory); + var viewClone; + if (objectToString.call(value) === "[object DataView]") { + viewClone = new global.DataView(clonedBuffer, value.byteOffset, + value.byteLength); + } else { + viewClone = new value.constructor(clonedBuffer, value.byteOffset, + value.length); + } + memory.set(value, viewClone); + return viewClone; + } + + if (typeof global.Date === "function") { + try { + if (value instanceof global.Date) { + var dateClone = new global.Date(value.getTime()); + memory.set(value, dateClone); + return dateClone; + } + } catch (e) {} + } + + if (typeof global.RegExp === "function") { + try { + if (value instanceof global.RegExp) { + var flags = ""; + flags += value.global ? "g" : ""; + flags += value.ignoreCase ? "i" : ""; + flags += value.multiline ? "m" : ""; + flags += value.unicode ? "u" : ""; + flags += value.sticky ? "y" : ""; + var regexpClone = new global.RegExp(value.source, flags); + regexpClone.lastIndex = value.lastIndex; + memory.set(value, regexpClone); + return regexpClone; + } + } catch (e) {} + } + + if (typeof global.Map === "function") { + try { + if (value instanceof global.Map) { + var mapClone = new global.Map(); + memory.set(value, mapClone); + value.forEach(function(v, k) { + mapClone.set(cloneTransferReasonValue(k, memory), + cloneTransferReasonValue(v, memory)); + }); + return mapClone; + } + } catch (e) { + throw e; + } + } + + if (typeof global.Set === "function") { + try { + if (value instanceof global.Set) { + var setClone = new global.Set(); + memory.set(value, setClone); + value.forEach(function(v) { + setClone.add(cloneTransferReasonValue(v, memory)); + }); + return setClone; + } + } catch (e) { + throw e; + } + } + + var clone = Array.isArray(value) ? [] : {}; + memory.set(value, clone); + + var keys = Object.keys(value); + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + clone[key] = cloneTransferReasonValue(value[key], memory); + } + + return clone; + } + + function abortTransferredWritable(record, reason) { + try { + return record.writer.abort(reason); + } catch (e) { + return Promise.reject(e); + } + } + + function rejectTransferredWritableWrite(record, error) { + var abortPromise = abortTransferredWritable(record, error); + silenceRejection(abortPromise); + return Promise.reject(error); + } + + function forwardTransferredWritableWrite(record, chunk) { + if (isUncloneableStreamChunk(chunk)) + return rejectTransferredWritableWrite(record, makeDataCloneError()); + + var prior = record.tail || Promise.resolve(undefined); + var firstWrite = !record.started; + record.started = true; + + var forwarding = prior.then(function() { + var writePromise; + try { + writePromise = Promise.resolve(record.writer.write(chunk)); + } catch (e) { + writePromise = Promise.reject(e); + } + record.inFlight = writePromise; + silenceRejection(writePromise); + return writePromise; + }); + + record.tail = forwarding; + silenceRejection(forwarding); + + if (firstWrite) + return undefined; + + return prior.then(function() { return undefined; }); + } + + function closeTransferredWritable(record) { + var tail = record.tail || Promise.resolve(undefined); + var closePromise = tail.then(function() { + return record.writer.close(); + }); + record.tail = closePromise; + silenceRejection(closePromise); + return closePromise; + } + +)JS" +R"JS( + + function __uxpTransferWritableStream(stream) { + if (!isWritableStream(stream)) + return undefined; + if (stream.locked) + return null; + try { + return { + writer: stream.getWriter(), + started: false, + inFlight: undefined, + tail: undefined + }; + } catch (e) { + return null; + } + } + + function __uxpReceiveWritableStreamTransfer(record) { + return new WritableStream({ + write: function(chunk) { + return forwardTransferredWritableWrite(record, chunk); + }, + close: function() { + return closeTransferredWritable(record); + }, + abort: function(reason) { + return abortTransferredWritable(record, reason); + } + }); + } + + function __uxpTransferReadableStream(stream) { + if (!isReadableStreamObject(stream)) + return undefined; + if (stream.locked) + return null; + try { + var record = { + reader: stream.getReader(), + pendingRead: undefined, + pumping: undefined, + closed: false, + errored: false, + canceled: false + }; + ensureReadableTransferRead(record); + return record; + } catch (e) { + return null; + } + } + + function ensureReadableTransferRead(record) { + if (!record.pendingRead && !record.closed && !record.errored && + !record.canceled) { + try { + record.pendingRead = Promise.resolve(record.reader.read()); + } catch (e) { + record.pendingRead = Promise.reject(e); + } + silenceRejection(record.pendingRead); + } + return record.pendingRead; + } + + function errorReadableTransfer(record, controller, error) { + if (record.canceled || record.closed || record.errored) + return; + record.errored = true; + try { controller.error(error); } catch (e) {} + } + + function pumpReadableTransfer(record, controller) { + if (record.pumping || record.closed || record.errored || record.canceled) + return; + + var pendingRead = ensureReadableTransferRead(record); + if (!pendingRead) + return; + + record.pumping = pendingRead.then(function(result) { + record.pendingRead = undefined; + record.pumping = undefined; + + if (record.canceled || record.errored || record.closed) + return; + + if (result.done) { + record.closed = true; + try { controller.close(); } catch (e) {} + return; + } + + if (isUncloneableStreamChunk(result.value)) { + var cloneError = makeDataCloneError(); + silenceRejection(record.reader.cancel(cloneError)); + errorReadableTransfer(record, controller, cloneError); + return; + } + + try { + controller.enqueue(result.value); + } catch (e) { + silenceRejection(record.reader.cancel(e)); + errorReadableTransfer(record, controller, e); + return; + } + + if (controller.desiredSize > 0) + pumpReadableTransfer(record, controller); + }, function(error) { + record.pendingRead = undefined; + record.pumping = undefined; + errorReadableTransfer(record, controller, error); + }); + silenceRejection(record.pumping); + } + + function cancelReadableTransfer(record, reason) { + record.canceled = true; + var clonedReason; + try { + clonedReason = cloneTransferReasonValue(reason); + } catch (e) { + return Promise.reject(e); + } + + Promise.resolve().then(function() { + try { + silenceRejection(record.reader.cancel(clonedReason)); + } catch (e) {} + }); + return undefined; + } + + function closeReadableTransferPort(port) { + try { port.close(); } catch (e) {} + } + + function startReadableTransferPort(port) { + try { + if (port.start) + port.start(); + } catch (e) {} + } + + function tryPostReadableTransferPort(port, message) { + try { + port.postMessage(message); + return true; + } catch (e) { + return false; + } + } + +)JS" +R"JS( + + function postReadableTransferPortError(record, error) { + var posted = tryPostReadableTransferPort(record.port, + { type: "error", value: error }); + if (!posted) { + posted = tryPostReadableTransferPort(record.port, { + type: "error", + name: error && error.name, + message: error && error.message + }); + } + record.closed = true; + if (!posted) + closeReadableTransferPort(record.port); + } + +)JS" +R"JS( + + function requestReadableTransferPortChunk(state) { + if (state.closed || state.errored || state.canceled) + return; + if (!tryPostReadableTransferPort(state.port, { type: "pull" })) { + state.errored = true; + if (state.controller) + try { state.controller.error(makeDataCloneError()); } catch (e) {} + closeReadableTransferPort(state.port); + } + } + + function errorReadableTransferPortState(state, error) { + if (state.errored) + return; + state.errored = true; + try { + if (state.controller) + state.controller.error(error); + } catch (e) {} + closeReadableTransferPort(state.port); + } + + function pumpReadableTransferPort(record) { + if (record.reading || record.closed || record.canceled || + record.credits <= 0) + return; + + --record.credits; + record.reading = true; + + var readPromise; + try { + readPromise = Promise.resolve(record.reader.read()); + } catch (e) { + readPromise = Promise.reject(e); + } + silenceRejection(readPromise); + + readPromise.then(function(result) { + record.reading = false; + + if (record.canceled || record.closed) + return; + + if (result.done) { + record.closed = true; + if (!tryPostReadableTransferPort(record.port, { type: "close" })) + closeReadableTransferPort(record.port); + return; + } + + if (isUncloneableStreamChunk(result.value)) { + var cloneError = makeDataCloneError(); + silenceRejection(record.reader.cancel(cloneError)); + postReadableTransferPortError(record, cloneError); + return; + } + + if (!tryPostReadableTransferPort(record.port, + { type: "chunk", value: result.value })) { + record.closed = true; + closeReadableTransferPort(record.port); + return; + } + + pumpReadableTransferPort(record); + }, function(error) { + record.reading = false; + if (record.canceled || record.closed) + return; + postReadableTransferPortError(record, error); + }); + } + + function __uxpTransferReadableStreamPort(stream) { + +)JS" +R"JS( + if (!isReadableStreamObject(stream)) + return undefined; + if (stream.locked || typeof global.MessageChannel !== "function") + return null; + + var channel; + try { + channel = new global.MessageChannel(); + var record = { + reader: stream.getReader(), + port: channel.port1, + reading: false, + credits: 1, + closed: false, + canceled: false + }; + + record.port.onmessage = function(event) { + var message = event.data; + if (!message || record.canceled) + return; + + if (message.type === "closed") { + record.closed = true; + closeReadableTransferPort(record.port); + return; + } + + if (record.closed) + return; + + if (message.type === "pull") { + ++record.credits; + pumpReadableTransferPort(record); + return; + } + + if (message.type === "cancel") { + record.canceled = true; + Promise.resolve().then(function() { + try { + silenceRejection(record.reader.cancel(message.reason)); + } catch (e) {} + }); + closeReadableTransferPort(record.port); + } + }; + + startReadableTransferPort(record.port); + pumpReadableTransferPort(record); + return channel.port2; + } catch (e) { + if (channel) { + closeReadableTransferPort(channel.port1); + closeReadableTransferPort(channel.port2); + } + return null; + } + } + + function errorFromReadableTransferPortMessage(message) { + if ("value" in message) + return message.value; + return makeDOMException(message.message || "ReadableStream transfer failed", + message.name || "DataCloneError"); + } + + function __uxpReceiveReadableStreamTransferFromPort(port) { + var state = { + port: port, + controller: undefined, + closed: false, + errored: false, + canceled: false + }; + + port.onmessage = function(event) { + var message = event.data; + if (!message || state.closed || state.errored || state.canceled) + return; + + if (message.type === "chunk") { + if (isUncloneableStreamChunk(message.value)) { + errorReadableTransferPortState(state, makeDataCloneError()); + return; + } + + try { + state.controller.enqueue(message.value); + } catch (e) { + errorReadableTransferPortState(state, e); + return; + } + + if (state.controller.desiredSize > 0) + requestReadableTransferPortChunk(state); + return; + } + + if (message.type === "close") { + state.closed = true; + try { state.controller.close(); } catch (e) {} + tryPostReadableTransferPort(port, { type: "closed" }); + closeReadableTransferPort(port); + return; + } + + if (message.type === "error") { + if (!state.errored) { + state.errored = true; + try { + if (state.controller) + state.controller.error( + errorFromReadableTransferPortMessage(message)); + } catch (e) {} + } + tryPostReadableTransferPort(port, { type: "closed" }); + closeReadableTransferPort(port); + } + }; + + return new ReadableStream({ + start: function(controller) { + state.controller = controller; + startReadableTransferPort(port); + requestReadableTransferPortChunk(state); + }, + pull: function() { + requestReadableTransferPortChunk(state); + }, + cancel: function(reason) { + state.canceled = true; + try { + port.postMessage({ type: "cancel", reason: reason }); + } catch (e) { + closeReadableTransferPort(port); + return Promise.reject(e); + } + closeReadableTransferPort(port); + return undefined; + } + }); + } + + function __uxpTransferTransformStream(stream) { + if (!isObject(stream) || !transformState.has(stream)) + return undefined; + + var state = transformState.get(stream); + if (state.readable.locked || state.writable.locked) + return null; + + var readableRecord = __uxpTransferReadableStream(state.readable); + if (!readableRecord) + return null; + + var writableRecord = __uxpTransferWritableStream(state.writable); + if (!writableRecord) + return null; + + return { + readable: readableRecord, + writable: writableRecord + }; + } + + function __uxpReceiveTransformStreamTransfer(record) { + var stream = Object.create(global.TransformStream.prototype); + transformState.set(stream, { + readable: __uxpReceiveReadableStreamTransfer(record.readable), + writable: __uxpReceiveWritableStreamTransfer(record.writable), + controller: undefined + }); + return stream; + } + + function __uxpReceiveReadableStreamTransfer(record) { + return new ReadableStream({ + start: function(controller) { + pumpReadableTransfer(record, controller); + }, + pull: function(controller) { + pumpReadableTransfer(record, controller); + }, + cancel: function(reason) { + return cancelReadableTransfer(record, reason); + } + }); + } + + function pipeTo(readable, destination, options) { + options = options === undefined ? {} : requiredObject(options, "options"); + var signal = options.signal; + var preventClose = Boolean(options.preventClose); + var preventAbort = Boolean(options.preventAbort); + var preventCancel = Boolean(options.preventCancel); + var reader; + var writer; + + try { + destination = requiredObject(destination, "destination"); + reader = readable.getReader(); + writer = destination.getWriter(); + } catch (e) { + return rejectPromise(e); + } + + var closed = false; + function cleanup() { + if (closed) + return; + closed = true; + releaseReaderLock(reader); + releaseWriterLock(writer); + if (signal && signal.removeEventListener) + signal.removeEventListener("abort", onAbort); + } + + function abortReason() { + return signal && "reason" in signal + ? signal.reason + : makeDOMException("The operation was aborted.", "AbortError"); + } + + function shutdownWithAction(action, originalError) { + return action().then(function() { + cleanup(); + throw originalError; + }, function(actionError) { + cleanup(); + throw actionError; + }); + } + + function onAbort() {} + + var pipePromise = new Promise(function(resolve, reject) { + onAbort = function() { + var reason = abortReason(); + var actions = []; + if (!preventAbort) + actions.push(writer.abort(reason)); + if (!preventCancel) + actions.push(reader.cancel(reason)); + Promise.all(actions).then(function() { + cleanup(); + reject(reason); + }, function(error) { + cleanup(); + reject(error); + }); + }; + + if (signal && signal.aborted) { + onAbort(); + return; + } + if (signal && signal.addEventListener) + signal.addEventListener("abort", onAbort); + + function pump() { + if (closed) + return; + reader.read().then(function(result) { + if (closed) + return; + if (result.done) { + var closePromise = preventClose ? Promise.resolve(undefined) + : writer.close(); + closePromise.then(function() { + cleanup(); + resolve(undefined); + }, function(error) { + cleanup(); + reject(error); + }); + return; + } + + writer.write(result.value).then(pump, function(error) { + if (closed) + return; + var cancel = preventCancel + ? Promise.resolve(undefined) + : reader.cancel(error); + cancel.then(function() { + cleanup(); + reject(error); + }, function(cancelError) { + cleanup(); + reject(cancelError); + }); + }); + }, function(error) { + if (closed) + return; + var abort = preventAbort + ? Promise.resolve(undefined) + : writer.abort(error); + abort.then(function() { + cleanup(); + reject(error); + }, function(abortError) { + cleanup(); + reject(abortError); + }); + }); + } + + pump(); + }); + + return pipePromise; + } + + function pipeThrough(readable, pair, options) { + pair = requiredObject(pair, "transform"); + var writable = pair.writable; + var output = pair.readable; + if (readable.locked) + throw new TypeError("ReadableStream is locked"); + if (!isWritableStream(writable)) + throw new TypeError("transform.writable must be a WritableStream"); + if (!(output instanceof global.ReadableStream)) + throw new TypeError("transform.readable must be a ReadableStream"); + if (writable.locked) + throw new TypeError("WritableStream is locked"); + readable.pipeTo(writable, options).catch(function() {}); + return output; + } + + Object.defineProperty(global, "__uxpStreamsPipeTo", + { value: pipeTo, configurable: true }); + Object.defineProperty(global, "__uxpStreamsPipeThrough", + { value: pipeThrough, configurable: true }); + Object.defineProperty(global, "__uxpTransferWritableStream", + { value: __uxpTransferWritableStream, + configurable: true }); + Object.defineProperty(global, "__uxpReceiveWritableStreamTransfer", + { value: __uxpReceiveWritableStreamTransfer, + configurable: true }); + Object.defineProperty(global, "__uxpTransferReadableStream", + { value: __uxpTransferReadableStream, + configurable: true }); + Object.defineProperty(global, "__uxpReceiveReadableStreamTransfer", + { value: __uxpReceiveReadableStreamTransfer, + configurable: true }); + Object.defineProperty(global, "__uxpTransferReadableStreamPort", + { value: __uxpTransferReadableStreamPort, + configurable: true }); + Object.defineProperty(global, "__uxpReceiveReadableStreamTransferFromPort", + { value: __uxpReceiveReadableStreamTransferFromPort, + configurable: true }); + Object.defineProperty(global, "__uxpTransferTransformStream", + { value: __uxpTransferTransformStream, + configurable: true }); + Object.defineProperty(global, "__uxpReceiveTransformStreamTransfer", + { value: __uxpReceiveTransformStreamTransfer, + configurable: true }); + + if (global.ReadableStream && !global.ReadableStream.from) { + Object.defineProperty(global.ReadableStream, "from", { + value: function from(asyncIterable) { + if (asyncIterable == null) + throw new TypeError("ReadableStream.from requires an iterable"); + var method = asyncIterable[Symbol.asyncIterator] || + asyncIterable[Symbol.iterator]; + if (typeof method !== "function") + throw new TypeError("ReadableStream.from requires an iterable"); + var iterator = method.call(asyncIterable); + return new ReadableStream({ + pull: function(controller) { + return Promise.resolve(iterator.next()).then(function(result) { + if (!isObject(result)) + throw new TypeError("Iterator result is not an object"); + if (result.done) { + controller.close(); + } else { + controller.enqueue(result.value); + } + }); + }, + cancel: function(reason) { + var returnMethod = iterator.return; + if (returnMethod) + return returnMethod.call(iterator, reason); + return undefined; + } + }); + }, + writable: true, + configurable: true + }); + } + + if (global.ReadableStream && typeof Symbol === "function" && + Symbol.asyncIterator && !global.ReadableStream.prototype.values) { + function ReadableStreamAsyncIterator(stream, preventCancel) { + this._reader = stream.getReader(); + this._preventCancel = preventCancel; + this._done = false; + } + + ReadableStreamAsyncIterator.prototype.next = function() { + if (this._done) + return Promise.resolve({ value: undefined, done: true }); + var self = this; + return this._reader.read().then(function(result) { + if (result.done) { + self._done = true; + releaseReaderLock(self._reader); + } + return result; + }, function(error) { + self._done = true; + releaseReaderLock(self._reader); + throw error; + }); + }; + + ReadableStreamAsyncIterator.prototype.return = function(value) { + if (this._done) + return Promise.resolve({ value: value, done: true }); + this._done = true; + var reader = this._reader; + if (this._preventCancel) { + releaseReaderLock(reader); + return Promise.resolve({ value: value, done: true }); + } + return reader.cancel(value).then(function() { + releaseReaderLock(reader); + return { value: value, done: true }; + }, function(error) { + releaseReaderLock(reader); + throw error; + }); + }; + + ReadableStreamAsyncIterator.prototype[Symbol.asyncIterator] = function() { + return this; + }; + + Object.defineProperty(global.ReadableStream.prototype, "values", { + value: function values(options) { + var preventCancel = Boolean(options && options.preventCancel); + return new ReadableStreamAsyncIterator(this, preventCancel); + }, + writable: true, + configurable: true + }); + + Object.defineProperty(global.ReadableStream.prototype, Symbol.asyncIterator, { + value: global.ReadableStream.prototype.values, + writable: true, + configurable: true + }); + } + + )JS" + R"JS( + + var textEncoderStreamState = new WeakMap(); + var textDecoderStreamState = new WeakMap(); + + function enqueueEncoded(controller, encoder, string) { + if (string.length === 0) + return; + var chunk = encoder.encode(string); + if (chunk.byteLength) + controller.enqueue(chunk); + } + + function TextEncoderStream() { + if (!(this instanceof TextEncoderStream)) + throw new TypeError("TextEncoderStream must be constructed with new"); + + var encoder = new TextEncoder(); + var leadingSurrogate = null; + var transform = new TransformStream({ + transform: function(chunk, controller) { + var input = String(chunk); + var output = ""; + var i = 0; + + if (leadingSurrogate !== null) { + if (input.length > 0) { + var first = input.charCodeAt(0); + if (first >= 0xDC00 && first <= 0xDFFF) { + output += String.fromCharCode(leadingSurrogate) + input.charAt(0); + i = 1; + } else { + output += "\uFFFD"; + } + } else { + return; + } + leadingSurrogate = null; + } + + for (; i < input.length; ++i) { + var code = input.charCodeAt(i); + if (code >= 0xD800 && code <= 0xDBFF) { + if (i + 1 < input.length) { + var next = input.charCodeAt(i + 1); + if (next >= 0xDC00 && next <= 0xDFFF) { + output += input.charAt(i) + input.charAt(i + 1); + ++i; + } else { + output += "\uFFFD"; + } + } else { + leadingSurrogate = code; + break; + } + } else if (code >= 0xDC00 && code <= 0xDFFF) { + output += "\uFFFD"; + } else { + output += input.charAt(i); + } + } + + enqueueEncoded(controller, encoder, output); + }, + flush: function(controller) { + if (leadingSurrogate !== null) { + leadingSurrogate = null; + enqueueEncoded(controller, encoder, "\uFFFD"); + } + } + }); + + textEncoderStreamState.set(this, { transform: transform }); + } + + Object.defineProperty(TextEncoderStream.prototype, "encoding", { + configurable: true, + get: function() { + if (!textEncoderStreamState.has(this)) + throw new TypeError("TextEncoderStream expected"); + return "utf-8"; + } + }); + + Object.defineProperty(TextEncoderStream.prototype, "readable", { + configurable: true, + get: function() { + var state = textEncoderStreamState.get(this); + if (!state) + throw new TypeError("TextEncoderStream expected"); + return state.transform.readable; + } + }); + + Object.defineProperty(TextEncoderStream.prototype, "writable", { + configurable: true, + get: function() { + var state = textEncoderStreamState.get(this); + if (!state) + throw new TypeError("TextEncoderStream expected"); + return state.transform.writable; + } + }); + + Object.defineProperty(TextEncoderStream.prototype, Symbol.toStringTag, + { value: "TextEncoderStream", configurable: true }); + + function TextDecoderStream(label, options) { + if (!(this instanceof TextDecoderStream)) + throw new TypeError("TextDecoderStream must be constructed with new"); + label = label === undefined ? "utf-8" : label; + options = options === undefined ? {} : options; + + var decoder = new TextDecoder(label, options); + var transform = new TransformStream({ + transform: function(chunk, controller) { + var output = decoder.decode(chunk, { stream: true }); + if (output.length) + controller.enqueue(output); + }, + flush: function(controller) { + var output = decoder.decode(); + if (output.length) + controller.enqueue(output); + } + }); + + textDecoderStreamState.set(this, { + transform: transform, + encoding: decoder.encoding, + fatal: decoder.fatal, + ignoreBOM: Boolean(options && options.ignoreBOM) + }); + } + + Object.defineProperty(TextDecoderStream.prototype, "encoding", { + configurable: true, + get: function() { + var state = textDecoderStreamState.get(this); + if (!state) + throw new TypeError("TextDecoderStream expected"); + return state.encoding; + } + }); + + Object.defineProperty(TextDecoderStream.prototype, "fatal", { + configurable: true, + get: function() { + var state = textDecoderStreamState.get(this); + if (!state) + throw new TypeError("TextDecoderStream expected"); + return state.fatal; + } + }); + + Object.defineProperty(TextDecoderStream.prototype, "ignoreBOM", { + configurable: true, + get: function() { + var state = textDecoderStreamState.get(this); + if (!state) + throw new TypeError("TextDecoderStream expected"); + return state.ignoreBOM; + } + }); + + Object.defineProperty(TextDecoderStream.prototype, "readable", { + configurable: true, + get: function() { + var state = textDecoderStreamState.get(this); + if (!state) + throw new TypeError("TextDecoderStream expected"); + return state.transform.readable; + } + }); + + Object.defineProperty(TextDecoderStream.prototype, "writable", { + configurable: true, + get: function() { + var state = textDecoderStreamState.get(this); + if (!state) + throw new TypeError("TextDecoderStream expected"); + return state.transform.writable; + } + }); + + Object.defineProperty(TextDecoderStream.prototype, Symbol.toStringTag, + { value: "TextDecoderStream", configurable: true }); + + var compressionStreamState = new WeakMap(); + var decompressionStreamState = new WeakMap(); + + function enqueueCompressionChunks(nativeContext, chunk, finish, controller) { + var chunks = global.__uxpCompressionProcess(nativeContext, chunk, finish); + for (var i = 0; i < chunks.length; ++i) + controller.enqueue(chunks[i]); + } + + function CompressionStream(format) { + if (!(this instanceof CompressionStream)) + throw new TypeError("CompressionStream must be constructed with new"); + var nativeContext = global.__uxpCreateCompressionContext(format, true); + var transform = new TransformStream({ + transform: function(chunk, controller) { + enqueueCompressionChunks(nativeContext, chunk, false, controller); + }, + flush: function(controller) { + enqueueCompressionChunks(nativeContext, undefined, true, controller); + } + }); + compressionStreamState.set(this, { transform: transform }); + } + + Object.defineProperty(CompressionStream.prototype, "readable", { + configurable: true, + get: function() { + var state = compressionStreamState.get(this); + if (!state) + throw new TypeError("CompressionStream expected"); + return state.transform.readable; + } + }); + + Object.defineProperty(CompressionStream.prototype, "writable", { + configurable: true, + get: function() { + var state = compressionStreamState.get(this); + if (!state) + throw new TypeError("CompressionStream expected"); + return state.transform.writable; + } + }); + + Object.defineProperty(CompressionStream.prototype, Symbol.toStringTag, + { value: "CompressionStream", configurable: true }); + + function DecompressionStream(format) { + if (!(this instanceof DecompressionStream)) + throw new TypeError("DecompressionStream must be constructed with new"); + var nativeContext = global.__uxpCreateCompressionContext(format, false); + var transform = new TransformStream({ + transform: function(chunk, controller) { + enqueueCompressionChunks(nativeContext, chunk, false, controller); + }, + flush: function(controller) { + enqueueCompressionChunks(nativeContext, undefined, true, controller); + } + }); + decompressionStreamState.set(this, { transform: transform }); + } + + Object.defineProperty(DecompressionStream.prototype, "readable", { + configurable: true, + get: function() { + var state = decompressionStreamState.get(this); + if (!state) + throw new TypeError("DecompressionStream expected"); + return state.transform.readable; + } + }); + + Object.defineProperty(DecompressionStream.prototype, "writable", { + configurable: true, + get: function() { + var state = decompressionStreamState.get(this); + if (!state) + throw new TypeError("DecompressionStream expected"); + return state.transform.writable; + } + }); + + Object.defineProperty(DecompressionStream.prototype, Symbol.toStringTag, + { value: "DecompressionStream", configurable: true }); + + define("WritableStream", WritableStream); + define("WritableStreamDefaultWriter", WritableStreamDefaultWriter); + define("WritableStreamDefaultController", WritableStreamDefaultController); + define("TransformStream", TransformStream); + define("TransformStreamDefaultController", TransformStreamDefaultController); + define("TextEncoderStream", TextEncoderStream); + define("TextDecoderStream", TextDecoderStream); + define("CompressionStream", CompressionStream); + define("DecompressionStream", DecompressionStream); +})(this); +)JS"; + + RootedValue rval(cx); + JS::CompileOptions options(cx); + options.setFileAndLine("builtin/StreamExtras.js", 1); + options.setNoScriptRval(true); + return JS::Evaluate(cx, options, source, strlen(source), &rval); +} diff --git a/js/src/builtin/Stream.h b/js/src/builtin/Stream.h index 0726e78361..50bd7a52a1 100644 --- a/js/src/builtin/Stream.h +++ b/js/src/builtin/Stream.h @@ -165,6 +165,8 @@ class CountQueuingStrategy : public NativeObject static const Class protoClass_; }; +[[nodiscard]] bool InitStreamExtras(JSContext* cx, HandleObject global); + } // namespace js #endif /* builtin_Stream_h */ diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index e1c32482ae..a83a06ad2b 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -654,6 +654,82 @@ function String_repeat(count) { return T; } +// ES2024 +// String.prototype.isWellFormed ( ) +function String_isWellFormed() { + // Steps 1-2. + RequireObjectCoercible(this); + var S = ToString(this); + + // Step 3. + var length = S.length; + for (var k = 0; k < length; k++) { + var c = callFunction(std_String_charCodeAt, S, k); + if (c >= 0xD800 && c <= 0xDBFF) { + if (k + 1 >= length) + return false; + + var d = callFunction(std_String_charCodeAt, S, k + 1); + if (d < 0xDC00 || d > 0xDFFF) + return false; + + k++; + } else if (c >= 0xDC00 && c <= 0xDFFF) { + return false; + } + } + + // Step 4. + return true; +} + +// ES2024 +// String.prototype.toWellFormed ( ) +function String_toWellFormed() { + // Steps 1-2. + RequireObjectCoercible(this); + var S = ToString(this); + + // Step 3. + var length = S.length; + var result = ""; + var copied = 0; + + for (var k = 0; k < length; k++) { + var c = callFunction(std_String_charCodeAt, S, k); + var isUnpairedSurrogate = false; + + if (c >= 0xD800 && c <= 0xDBFF) { + if (k + 1 < length) { + var d = callFunction(std_String_charCodeAt, S, k + 1); + if (d >= 0xDC00 && d <= 0xDFFF) { + k++; + continue; + } + } + isUnpairedSurrogate = true; + } else if (c >= 0xDC00 && c <= 0xDFFF) { + isUnpairedSurrogate = true; + } + + if (isUnpairedSurrogate) { + if (copied < k) + result += callFunction(String_substring, S, copied, k); + result += "\uFFFD"; + copied = k + 1; + } + } + + if (copied === 0) + return S; + + if (copied < length) + result += callFunction(String_substring, S, copied, length); + + // Step 4. + return result; +} + // ES6 draft specification, section 21.1.3.27, version 2013-09-27. function String_iterator() { RequireObjectCoercible(this); diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js index a8510faa71..4311f27079 100644 --- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -37,10 +37,25 @@ function TypedArrayLengthMethod() { return TypedArrayLength(this); } +function TypedArrayContentTypeIsBigIntMethod() { + return IsBigInt64TypedArray(this) || IsBigUint64TypedArray(this); +} + +function ThrowIfTypedArrayOutOfBounds(tarray) { + if (TypedArrayIsOutOfBounds(tarray)) + ThrowTypeError(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); +} + +function ThrowIfPossiblyWrappedTypedArrayOutOfBounds(tarray) { + if (PossiblyWrappedTypedArrayIsOutOfBounds(tarray)) + ThrowTypeError(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); +} + function GetAttachedArrayBuffer(tarray) { var buffer = ViewedArrayBufferIfReified(tarray); if (IsDetachedBuffer(buffer)) ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); + ThrowIfTypedArrayOutOfBounds(tarray); return buffer; } @@ -60,6 +75,13 @@ function IsTypedArrayEnsuringArrayBuffer(arg) { return true; } + if (IsObject(arg) && IsPossiblyWrappedTypedArray(arg)) { + if (PossiblyWrappedTypedArrayHasDetachedBuffer(arg)) + ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); + ThrowIfPossiblyWrappedTypedArrayOutOfBounds(arg); + return false; + } + callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod"); return false; } @@ -79,6 +101,7 @@ function ValidateTypedArray(obj, error) { if (IsPossiblyWrappedTypedArray(obj)) { if (PossiblyWrappedTypedArrayHasDetachedBuffer(obj)) ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); + ThrowIfPossiblyWrappedTypedArrayOutOfBounds(obj); return false; } } @@ -903,6 +926,73 @@ function SetFromNonTypedArray(target, array, targetOffset, targetLength, targetB return undefined; } +// ES2023 23.2.3.33 %TypedArray%.prototype.toSorted ( comparator ) +function TypedArrayToSorted(comparator) { + // Step 1. + if (comparator !== undefined && !IsCallable(comparator)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, comparator)); + + // Step 2. + var O = this; + + // Step 3. + // This function is not generic. + // We want to make sure that we have an attached buffer, per spec prose. + var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O); + + // If we got here, `this` is either a typed array or a wrapper for one. + + // Step 4. + var len; + if (isTypedArray) + len = TypedArrayLength(O); + else + len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod"); + + // Step 5. + var A = TypedArrayCreateSameType(O, len); + + // Step 8. + var sortedList = new List(); + for (var k = 0; k < len; k++) { + sortedList[k] = O[k]; + } + + if (len > 1) { + // Steps 6-7. + var sortCompare; + if (comparator === undefined) { + var isBigIntContentType; + if (isTypedArray) { + isBigIntContentType = callFunction(TypedArrayContentTypeIsBigIntMethod, O); + } else { + isBigIntContentType = callFunction(CallTypedArrayMethodIfWrapped, O, + "TypedArrayContentTypeIsBigIntMethod"); + } + sortCompare = isBigIntContentType ? TypedArrayCompareBigInt : TypedArrayCompare; + } else { + var wrappedComparator = comparator; + sortCompare = function(x, y) { + // CompareTypedArrayElements step 2.a. + var v = ToNumber(callContentFunction(wrappedComparator, undefined, x, y)); + + // CompareTypedArrayElements step 2.b. + return Number_isNaN(v) ? 0 : v; + }; + } + + MergeSort(sortedList, len, sortCompare); + } + + // Steps 9-10. + for (var j = 0; j < len; j++) { + A[j] = sortedList[j]; + } + + // Step 11. + return A; +} + // ES6 draft 20150220 22.2.3.22.2 %TypedArray%.prototype.set(typedArray [, offset]) function SetFromTypedArray(target, typedArray, targetOffset, targetLength) { assert(IsPossiblyWrappedTypedArray(typedArray), @@ -957,12 +1047,18 @@ function TypedArraySet(overloaded, offset = 0) { // Steps 9-10. var targetBuffer = GetAttachedArrayBuffer(target); + ThrowIfTypedArrayOutOfBounds(target); + // Step 11. var targetLength = TypedArrayLength(target); // Steps 12 et seq. - if (IsPossiblyWrappedTypedArray(overloaded)) + if (IsPossiblyWrappedTypedArray(overloaded)) { + if (PossiblyWrappedTypedArrayHasDetachedBuffer(overloaded)) + ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); + ThrowIfPossiblyWrappedTypedArrayOutOfBounds(overloaded); return SetFromTypedArray(target, overloaded, targetOffset, targetLength); + } return SetFromNonTypedArray(target, overloaded, targetOffset, targetLength, targetBuffer); } @@ -1299,6 +1395,8 @@ function TypedArraySubarray(begin, end) { "TypedArraySubarray"); } + GetAttachedArrayBuffer(obj); + // Steps 4-6. var buffer = TypedArrayBuffer(obj); var srcLength = TypedArrayLength(obj); @@ -1779,7 +1877,10 @@ function ArrayBufferSlice(start, end) { ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); // Steps 19-21. - ArrayBufferCopyData(new_, 0, O, first | 0, newLen | 0, isWrapped); + var currentLen = ArrayBufferByteLength(O); + var copyLen = first >= currentLen ? 0 : std_Math_min(newLen, currentLen - first); + if (copyLen > 0) + ArrayBufferCopyData(new_, 0, O, first | 0, copyLen | 0, isWrapped); // Step 22. return new_; diff --git a/js/src/builtin/WeakMapObject.cpp b/js/src/builtin/WeakMapObject.cpp index 82b6ef1a7c..d68b9e05fd 100644 --- a/js/src/builtin/WeakMapObject.cpp +++ b/js/src/builtin/WeakMapObject.cpp @@ -8,6 +8,7 @@ #include "jsapi.h" #include "jscntxt.h" +#include "builtin/WeakRefObject.h" #include "vm/SelfHosting.h" #include "vm/Interpreter-inl.h" @@ -21,21 +22,80 @@ IsWeakMap(HandleValue v) return v.isObject() && v.toObject().is(); } +struct WeakMapObject::Data +{ + ObjectValueMap objectMap; + SymbolValueMap symbolMap; + + Data(JSContext* cx, JSObject* owner) + : objectMap(cx, owner), + symbolMap(cx, owner) + {} + + bool init() { + return objectMap.init() && symbolMap.init(); + } +}; + +ObjectValueMap* +WeakMapObject::getMap() +{ + Data* data = getData(); + return data ? &data->objectMap : nullptr; +} + +SymbolValueMap* +WeakMapObject::getSymbolMap() +{ + Data* data = getData(); + return data ? &data->symbolMap : nullptr; +} + +static bool +EnsureWeakMapData(JSContext* cx, Handle mapObj) +{ + if (mapObj->getData()) + return true; + + auto data = cx->make_unique(cx, mapObj.get()); + if (!data) + return false; + + if (!data->init()) { + JS_ReportOutOfMemory(cx); + return false; + } + + mapObj->setPrivate(data.release()); + return true; +} + MOZ_ALWAYS_INLINE bool WeakMap_has_impl(JSContext* cx, const CallArgs& args) { MOZ_ASSERT(IsWeakMap(args.thisv())); - if (!args.get(0).isObject()) { + if (!CanBeHeldWeakly(args.get(0))) { args.rval().setBoolean(false); return true; } - if (ObjectValueMap* map = args.thisv().toObject().as().getMap()) { - JSObject* key = &args[0].toObject(); - if (map->has(key)) { - args.rval().setBoolean(true); - return true; + WeakMapObject& weakMap = args.thisv().toObject().as(); + if (args.get(0).isObject()) { + if (ObjectValueMap* map = weakMap.getMap()) { + JSObject* key = &args[0].toObject(); + if (map->has(key)) { + args.rval().setBoolean(true); + return true; + } + } + } else { + if (SymbolValueMap* map = weakMap.getSymbolMap()) { + JS::Symbol* key = args[0].toSymbol(); + if (map->has(key)) { + args.rval().setBoolean(true); + return true; + } } } @@ -55,16 +115,27 @@ WeakMap_get_impl(JSContext* cx, const CallArgs& args) { MOZ_ASSERT(IsWeakMap(args.thisv())); - if (!args.get(0).isObject()) { + if (!CanBeHeldWeakly(args.get(0))) { args.rval().setUndefined(); return true; } - if (ObjectValueMap* map = args.thisv().toObject().as().getMap()) { - JSObject* key = &args[0].toObject(); - if (ObjectValueMap::Ptr ptr = map->lookup(key)) { - args.rval().set(ptr->value()); - return true; + WeakMapObject& weakMap = args.thisv().toObject().as(); + if (args.get(0).isObject()) { + if (ObjectValueMap* map = weakMap.getMap()) { + JSObject* key = &args[0].toObject(); + if (ObjectValueMap::Ptr ptr = map->lookup(key)) { + args.rval().set(ptr->value()); + return true; + } + } + } else { + if (SymbolValueMap* map = weakMap.getSymbolMap()) { + JS::Symbol* key = args[0].toSymbol(); + if (SymbolValueMap::Ptr ptr = map->lookup(key)) { + args.rval().set(ptr->value()); + return true; + } } } @@ -84,17 +155,29 @@ WeakMap_delete_impl(JSContext* cx, const CallArgs& args) { MOZ_ASSERT(IsWeakMap(args.thisv())); - if (!args.get(0).isObject()) { + if (!CanBeHeldWeakly(args.get(0))) { args.rval().setBoolean(false); return true; } - if (ObjectValueMap* map = args.thisv().toObject().as().getMap()) { - JSObject* key = &args[0].toObject(); - if (ObjectValueMap::Ptr ptr = map->lookup(key)) { - map->remove(ptr); - args.rval().setBoolean(true); - return true; + WeakMapObject& weakMap = args.thisv().toObject().as(); + if (args.get(0).isObject()) { + if (ObjectValueMap* map = weakMap.getMap()) { + JSObject* key = &args[0].toObject(); + if (ObjectValueMap::Ptr ptr = map->lookup(key)) { + map->remove(ptr); + args.rval().setBoolean(true); + return true; + } + } + } else { + if (SymbolValueMap* map = weakMap.getSymbolMap()) { + JS::Symbol* key = args[0].toSymbol(); + if (SymbolValueMap::Ptr ptr = map->lookup(key)) { + map->remove(ptr); + args.rval().setBoolean(true); + return true; + } } } @@ -126,22 +209,13 @@ TryPreserveReflector(JSContext* cx, HandleObject obj) return true; } -static MOZ_ALWAYS_INLINE bool -SetWeakMapEntryInternal(JSContext* cx, Handle mapObj, - HandleObject key, HandleValue value) +static bool +SetWeakMapObjectEntryInternal(JSContext* cx, Handle mapObj, + HandleObject key, HandleValue value) { + if (!EnsureWeakMapData(cx, mapObj)) + return false; ObjectValueMap* map = mapObj->getMap(); - if (!map) { - auto newMap = cx->make_unique(cx, mapObj.get()); - if (!newMap) - return false; - if (!newMap->init()) { - JS_ReportOutOfMemory(cx); - return false; - } - map = newMap.release(); - mapObj->setPrivate(map); - } // Preserve wrapped native keys to prevent wrapper optimization. if (!TryPreserveReflector(cx, key)) @@ -162,13 +236,28 @@ SetWeakMapEntryInternal(JSContext* cx, Handle mapObj, return true; } -MOZ_ALWAYS_INLINE bool -WeakMap_set_impl(JSContext* cx, const CallArgs& args) +static bool +SetWeakMapSymbolEntryInternal(JSContext* cx, Handle mapObj, + Handle key, HandleValue value) { - MOZ_ASSERT(IsWeakMap(args.thisv())); + if (!EnsureWeakMapData(cx, mapObj)) + return false; + SymbolValueMap* map = mapObj->getSymbolMap(); - if (!args.get(0).isObject()) { - UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr); + MOZ_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment()); + if (!map->put(key, value)) { + JS_ReportOutOfMemory(cx); + return false; + } + return true; +} + +static MOZ_ALWAYS_INLINE bool +SetWeakMapEntryInternal(JSContext* cx, Handle mapObj, + HandleValue key, HandleValue value) +{ + if (!CanBeHeldWeakly(key)) { + UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, key, nullptr); if (!bytes) return false; JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, @@ -176,11 +265,24 @@ WeakMap_set_impl(JSContext* cx, const CallArgs& args) return false; } - RootedObject key(cx, &args[0].toObject()); + if (key.isObject()) { + RootedObject objectKey(cx, &key.toObject()); + return SetWeakMapObjectEntryInternal(cx, mapObj, objectKey, value); + } + + Rooted symbolKey(cx, key.toSymbol()); + return SetWeakMapSymbolEntryInternal(cx, mapObj, symbolKey, value); +} + +MOZ_ALWAYS_INLINE bool +WeakMap_set_impl(JSContext* cx, const CallArgs& args) +{ + MOZ_ASSERT(IsWeakMap(args.thisv())); + Rooted thisObj(cx, &args.thisv().toObject()); Rooted map(cx, &thisObj->as()); - if (!SetWeakMapEntryInternal(cx, map, key, args.get(1))) + if (!SetWeakMapEntryInternal(cx, map, args.get(0), args.get(1))) return false; args.rval().set(args.thisv()); return true; @@ -193,6 +295,13 @@ js::WeakMap_set(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod(cx, args); } +bool +js::SetWeakMapEntryValue(JSContext* cx, HandleObject mapObj, HandleValue key, HandleValue val) +{ + Rooted rootedMap(cx, &mapObj->as()); + return SetWeakMapEntryInternal(cx, rootedMap, key, val); +} + JS_FRIEND_API(bool) JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret) { @@ -205,11 +314,11 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan RootedObject arr(cx, NewDenseEmptyArray(cx)); if (!arr) return false; - ObjectValueMap* map = obj->as().getMap(); - if (map) { + WeakMapObject::Data* data = obj->as().getData(); + if (data) { // Prevent GC from mutating the weakmap while iterating. AutoSuppressGC suppress(cx); - for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) { + for (ObjectValueMap::Base::Range r = data->objectMap.all(); !r.empty(); r.popFront()) { JS::ExposeObjectToActiveJS(r.front().key()); RootedObject key(cx, r.front().key()); if (!cx->compartment()->wrap(cx, &key)) @@ -217,6 +326,14 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan if (!NewbornArrayPush(cx, arr, ObjectValue(*key))) return false; } + for (SymbolValueMap::Base::Range r = data->symbolMap.all(); !r.empty(); r.popFront()) { + gc::ExposeGCThingToActiveJS(JS::GCCellPtr(r.front().key().get())); + RootedValue key(cx, SymbolValue(r.front().key())); + if (!cx->compartment()->wrap(cx, &key)) + return false; + if (!NewbornArrayPush(cx, arr, key)) + return false; + } } ret.set(arr); return true; @@ -225,21 +342,23 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan static void WeakMap_mark(JSTracer* trc, JSObject* obj) { - if (ObjectValueMap* map = obj->as().getMap()) - map->trace(trc); + if (WeakMapObject::Data* data = obj->as().getData()) { + data->objectMap.trace(trc); + data->symbolMap.trace(trc); + } } static void WeakMap_finalize(FreeOp* fop, JSObject* obj) { MOZ_ASSERT(fop->maybeOffMainThread()); - if (ObjectValueMap* map = obj->as().getMap()) { + if (WeakMapObject::Data* data = obj->as().getData()) { #ifdef DEBUG - map->~ObjectValueMap(); - memset(static_cast(map), 0xdc, sizeof(*map)); - fop->free_(map); + data->~Data(); + memset(static_cast(data), 0xdc, sizeof(*data)); + fop->free_(data); #else - fop->delete_(map); + fop->delete_(data); #endif } } @@ -282,7 +401,8 @@ JS::SetWeakMapEntry(JSContext* cx, HandleObject mapObj, HandleObject key, CHECK_REQUEST(cx); assertSameCompartment(cx, key, val); Rooted rootedMap(cx, &mapObj->as()); - return SetWeakMapEntryInternal(cx, rootedMap, key, val); + RootedValue keyValue(cx, ObjectValue(*key)); + return SetWeakMapEntryInternal(cx, rootedMap, keyValue, val); } static bool @@ -386,4 +506,3 @@ js::InitBareWeakMapCtor(JSContext* cx, HandleObject obj) { return InitWeakMapClass(cx, obj, false); } - diff --git a/js/src/builtin/WeakMapObject.h b/js/src/builtin/WeakMapObject.h index 507758d2fa..f19ad1d4df 100644 --- a/js/src/builtin/WeakMapObject.h +++ b/js/src/builtin/WeakMapObject.h @@ -16,7 +16,11 @@ class WeakMapObject : public NativeObject public: static const Class class_; - ObjectValueMap* getMap() { return static_cast(getPrivate()); } + struct Data; + + Data* getData() { return static_cast(getPrivate()); } + ObjectValueMap* getMap(); + SymbolValueMap* getSymbolMap(); }; } // namespace js diff --git a/js/src/builtin/WeakRefObject.cpp b/js/src/builtin/WeakRefObject.cpp new file mode 100644 index 0000000000..8e8feb3f3d --- /dev/null +++ b/js/src/builtin/WeakRefObject.cpp @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "builtin/WeakRefObject.h" + +#include "jsapi.h" +#include "jscntxt.h" + +#include "gc/Nursery.h" +#include "gc/Tracer.h" +#include "vm/GlobalObject.h" + +#include "jsobjinlines.h" + +#include "vm/Interpreter-inl.h" +#include "vm/NativeObject-inl.h" + +using namespace js; + +static WeakRefObject::Referent* +GetReferent(JSObject* obj) +{ + return obj->as().getData(); +} + +static MOZ_ALWAYS_INLINE bool +IsWeakRef(HandleValue v) +{ + return v.isObject() && v.toObject().is(); +} + +static bool +WeakRef_deref_impl(JSContext* cx, const CallArgs& args) +{ + MOZ_ASSERT(IsWeakRef(args.thisv())); + + WeakRefObject::Referent* data = GetReferent(&args.thisv().toObject()); + JSObject* target = data ? data->target.get() : nullptr; + if (target) + args.rval().setObject(*target); + else + args.rval().setUndefined(); + return true; +} + +const JSPropertySpec WeakRefObject::properties[] = { + JS_PS_END +}; + +const JSFunctionSpec WeakRefObject::methods[] = { + JS_FN("deref", WeakRefObject::deref, 0, 0), + JS_FS_END +}; + +static JSObject* +InitWeakRefClass(JSContext* cx, HandleObject obj, bool defineMembers) +{ + Handle global = obj.as(); + RootedPlainObject proto(cx, NewBuiltinClassInstance(cx)); + if (!proto) + return nullptr; + + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, WeakRefObject::construct, + ClassName(JSProto_WeakRef, cx), 1)); + if (!ctor) + return nullptr; + + if (!LinkConstructorAndPrototype(cx, ctor, proto)) + return nullptr; + + if (defineMembers) { + if (!DefinePropertiesAndFunctions(cx, proto, WeakRefObject::properties, WeakRefObject::methods)) + return nullptr; + if (!DefineToStringTag(cx, proto, cx->names().WeakRef)) + return nullptr; + } + + if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakRef, ctor, proto)) + return nullptr; + return proto; +} + +/* static */ WeakRefObject* +WeakRefObject::create(JSContext* cx, HandleObject target, HandleObject proto /* = nullptr */) +{ + Rooted obj(cx, NewObjectWithClassProto(cx, proto)); + if (!obj) + return nullptr; + + Referent* data = cx->new_(target, cx->options().weakRefs()); + if (!data) + return nullptr; + + obj->setPrivate(data); + return obj; +} + +/* static */ bool +WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (!ThrowIfNotConstructing(cx, args, "WeakRef")) + return false; + + if (!args.get(0).isObject()) { + UniqueChars bytes = + DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr); + if (!bytes) + return false; + + JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, + bytes.get()); + return false; + } + + RootedObject target(cx, &args[0].toObject()); + + RootedObject proto(cx); + RootedObject newTarget(cx, &args.newTarget().toObject()); + if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) + return false; + + Rooted obj(cx, WeakRefObject::create(cx, target, proto)); + if (!obj) + return false; + + args.rval().setObject(*obj); + return true; +} + +/* static */ bool +WeakRefObject::deref(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod(cx, args); +} + +/* static */ void +WeakRefObject::trace(JSTracer* trc, JSObject* obj) +{ + if (Referent* data = GetReferent(obj)) { + JSObject* target = data->target.unbarrieredGet(); + if (!target) + return; + + // When pref-disabled, keep referent alive via strong trace so deref() + // stays usable as a stub without touching GC internals. + if (!data->enabled) { + TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef stub referent"); + } else if (IsInsideNursery(target)) { + // Weak edges must be tenured; trace strongly while referent is in the nursery. + TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef nursery referent"); + } else { + TraceWeakEdge(trc, &data->target, "WeakRef referent"); + } + } +} + +/* static */ void +WeakRefObject::finalize(FreeOp* fop, JSObject* obj) +{ + if (Referent* data = GetReferent(obj)) + fop->delete_(data); +} + +static const ClassOps WeakRefObjectClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + WeakRefObject::finalize, + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + WeakRefObject::trace +}; + +const Class WeakRefObject::class_ = { + "WeakRef", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_CACHED_PROTO(JSProto_WeakRef) | + JSCLASS_BACKGROUND_FINALIZE, + &WeakRefObjectClassOps +}; + +/* static */ JSObject* +WeakRefObject::initClass(JSContext* cx, HandleObject obj) +{ + return ::InitWeakRefClass(cx, obj, true); +} + +JSObject* +js::InitWeakRefClass(JSContext* cx, HandleObject obj) +{ + return WeakRefObject::initClass(cx, obj); +} + +JSObject* +js::InitBareWeakRefCtor(JSContext* cx, HandleObject obj) +{ + return ::InitWeakRefClass(cx, obj, false); +} diff --git a/js/src/builtin/WeakRefObject.h b/js/src/builtin/WeakRefObject.h new file mode 100644 index 0000000000..6f2a2b4590 --- /dev/null +++ b/js/src/builtin/WeakRefObject.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#ifndef builtin_WeakRefObject_h +#define builtin_WeakRefObject_h + +#include "gc/Barrier.h" +#include "vm/NativeObject.h" + +namespace js { + +class WeakRefObject : public NativeObject +{ + public: + struct Referent { + explicit Referent(JSObject* obj, bool enabled) + : target(obj), enabled(enabled) {} + WeakRef target; + bool enabled; + }; + + static const Class class_; + + static JSObject* initClass(JSContext* cx, HandleObject obj); + static WeakRefObject* create(JSContext* cx, HandleObject target, HandleObject proto = nullptr); + + static void trace(JSTracer* trc, JSObject* obj); + static void finalize(FreeOp* fop, JSObject* obj); + [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp); + static bool deref(JSContext* cx, unsigned argc, Value* vp); + + Referent* getData() const { + return static_cast(getPrivate()); + } + + WeakRef& target() { + MOZ_ASSERT(getData()); + return getData()->target; + } + + static const JSPropertySpec properties[]; + static const JSFunctionSpec methods[]; + + private: +}; + +extern JSObject* +InitWeakRefClass(JSContext* cx, HandleObject obj); + +extern JSObject* +InitBareWeakRefCtor(JSContext* cx, HandleObject obj); + +static inline bool +CanBeHeldWeakly(const Value& value) +{ + return value.isObject() || value.isSymbol(); +} + +} // namespace js + +#endif /* builtin_WeakRefObject_h */ diff --git a/js/src/builtin/WeakSet.js b/js/src/builtin/WeakSet.js index b16b4634dd..88f7929c72 100644 --- a/js/src/builtin/WeakSet.js +++ b/js/src/builtin/WeakSet.js @@ -32,7 +32,7 @@ function WeakSet_add(value) { ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "add", typeof S); // Step 5. - if (!IsObject(value)) + if (!CanBeHeldWeakly(value)) ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, value)); // Steps 7-8. @@ -55,7 +55,7 @@ function WeakSet_delete(value) { ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "delete", typeof S); // Step 5. - if (!IsObject(value)) + if (!CanBeHeldWeakly(value)) return false; // Steps 7-8. @@ -75,7 +75,7 @@ function WeakSet_has(value) { ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "has", typeof S); // Step 6. - if (!IsObject(value)) + if (!CanBeHeldWeakly(value)) return false; // Steps 7-8. diff --git a/js/src/builtin/WeakSetObject.cpp b/js/src/builtin/WeakSetObject.cpp index bb9708f6f9..055f6b1abd 100644 --- a/js/src/builtin/WeakSetObject.cpp +++ b/js/src/builtin/WeakSetObject.cpp @@ -12,6 +12,7 @@ #include "builtin/MapObject.h" #include "builtin/SelfHostingDefines.h" #include "builtin/WeakMapObject.h" +#include "builtin/WeakRefObject.h" #include "vm/GlobalObject.h" #include "vm/SelfHosting.h" @@ -108,7 +109,6 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) if (optimized) { RootedValue keyVal(cx); - RootedObject keyObject(cx); RootedValue placeholder(cx, BooleanValue(true)); RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject()); RootedArrayObject array(cx, &iterable.toObject().as()); @@ -116,7 +116,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) keyVal.set(array->getDenseElement(index)); MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE)); - if (keyVal.isPrimitive()) { + if (!CanBeHeldWeakly(keyVal)) { UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr); if (!bytes) @@ -126,8 +126,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) return false; } - keyObject = &keyVal.toObject(); - if (!SetWeakMapEntry(cx, map, keyObject, placeholder)) + if (!SetWeakMapEntryValue(cx, map, keyVal, placeholder)) return false; } } else { diff --git a/js/src/devtools/number-to-string-bench.js b/js/src/devtools/number-to-string-bench.js new file mode 100644 index 0000000000..957183d31d --- /dev/null +++ b/js/src/devtools/number-to-string-bench.js @@ -0,0 +1,61 @@ +// Run with: js number-to-string-bench.js +// Also supports: xpcshell -f number-to-string-bench.js +// Compare identical optimized builds, alternating baseline and patched runs. +// Reports milliseconds (lower is better); this is not a browser-suite score. + +(function() { + "use strict"; + var iterations = 500000; + var samples = 7; + var checksum = 0; + + function convert(values, radix, count) { + var total = 0; + for (var i = 0; i < count; i++) + total += values[i % values.length].toString(radix).length; + return total; + } + + function unique(count) { + var total = 0; + for (var i = 0; i < count; i++) + total += (123456.125 + i).toString().length; + return total; + } + + function measure(name, run) { + checksum += run(20000); + var times = []; + var expected = run(iterations); + for (var sample = 0; sample < samples; sample++) { + if (typeof gc === "function") + gc(); + var start = Date.now(); + var result = run(iterations); + times.push(Date.now() - start); + if (result !== expected) + throw new Error("inconsistent conversion: " + name); + checksum += result; + } + times.sort(function(a, b) { return a - b; }); + print(name + ": median=" + times[3] + " ms; samples=" + times.join(",")); + } + + for (var size of [1, 2, 4, 5, 16]) { + var values = []; + for (var i = 0; i < size; i++) + values.push(123456.125 + i); + measure("decimal working set " + size, function(count) { + return convert(values, 10, count); + }); + } + measure("unique decimals", unique); + var integers = [123456, 654321, 123457, 654322]; + measure("integer working set 4", function(count) { + return convert(integers, 10, count); + }); + measure("hexadecimal working set 4", function(count) { + return convert(integers, 16, count); + }); + print("checksum=" + checksum); +})(); diff --git a/js/src/devtools/speedometer21-json-bench.js b/js/src/devtools/speedometer21-json-bench.js new file mode 100644 index 0000000000..264d7d713b --- /dev/null +++ b/js/src/devtools/speedometer21-json-bench.js @@ -0,0 +1,38 @@ +// Focused JSON workloads motivated by Speedometer 2.1's in-memory TodoMVC store. +// Run with a JS shell, or xpcshell -f. Lower times are better. This does not +// measure Speedometer's DOM, layout, event dispatch, or overall suite score. +(function() { + var iterations = 2000; + var checksum = 0; + function measure(name, records) { + var text = JSON.stringify(records); + var samples = []; + for (var i = 0; i < 100; i++) + checksum += JSON.parse(text).length; + for (var sample = 0; sample < 7; sample++) { + if (typeof gc === 'function') + gc(); + var start = Date.now(); + for (var i = 0; i < iterations; i++) + checksum += JSON.parse(text).length; + samples.push(Date.now() - start); + } + samples.sort(function(a, b) { return a - b; }); + print(name + ': median=' + samples[3] + ' ms; samples=' + samples.join(',')); + } + var todos = [], unicode = [], collisions = [], unique = []; + for (var i = 0; i < 100; i++) { + todos.push({ id: i, title: 'Something to do ' + i, completed: false }); + unicode.push({ '\u0101name': i, '\u03bbvalue': 'value', '\u4e2d': false }); + collisions.push({ item: i, identifier: i + 1, index: i + 2 }); + var record = {}; + record['uniqueName' + i] = i; + unique.push(record); + } + measure('TodoMVC-shaped records', todos); + measure('two-byte names', unicode); + measure('cache collisions', collisions); + measure('unique names', unique); + measure('small parse', [todos[0]]); + print('checksum=' + checksum); +})(); diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp index 7787fb07ee..a022210f6f 100644 --- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp +++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp @@ -424,7 +424,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only) LiveGeneralRegisterSet volatileRegs(GeneralRegisterSet::Volatile()); #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) volatileRegs.add(Register::FromCode(Registers::lr)); -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) volatileRegs.add(Register::FromCode(Registers::ra)); #endif volatileRegs.takeUnchecked(temp0); @@ -1365,7 +1365,7 @@ NativeRegExpMacroAssembler::CanReadUnaligned() { #if defined(JS_CODEGEN_ARM) return !jit::HasAlignmentFault(); -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) return false; #else return true; diff --git a/js/src/jit-test/tests/basic/json-property-name-cache.js b/js/src/jit-test/tests/basic/json-property-name-cache.js new file mode 100644 index 0000000000..92440c8952 --- /dev/null +++ b/js/src/jit-test/tests/basic/json-property-name-cache.js @@ -0,0 +1,43 @@ +// Repeated names, collisions, encodings, and escaped names must all agree. +var keys = ['id', 'title', 'completed', 'items', 'item', '', 'identifier', + 'i', 'a', 'same', 'samesize', '\u00e9', '\u0101', '\ud800', + 'quote"key', 'slash\\key', 'line\nkey', '__proto__']; +var records = []; +for (var i = 0; i < 100; i++) { + var record = Object.create(null); + for (var k = 0; k < keys.length; k++) + record[keys[k]] = i + k; + records.push(record); +} +var text = JSON.stringify(records); +for (var repeat = 0; repeat < 30; repeat++) { + var parsed = JSON.parse(text); + assertEq(parsed.length, records.length); + for (var i = 0; i < parsed.length; i++) { + for (var k = 0; k < keys.length; k++) + assertEq(parsed[i][keys[k]], records[i][keys[k]]); + } +} +assertEq(JSON.parse('[{"title":1},{"titleLonger":2}]')[1].titleLonger, 2); +assertEq(JSON.parse('[{"titleLonger":1},{"title":2}]')[1].title, 2); +assertEq(JSON.parse('[{"title":1},{"t\\u0069tle":2}]')[1].title, 2); +assertEq(JSON.parse('{"id":1,"id":2}').id, 2); +assertEq(JSON.parse('{"id":1}', function(key, value) { + return key === 'id' ? JSON.parse('{"id":2}').id : value; +}).id, 2); + +for (var bad of ['[{"title":1},{"title', '[{"title":1},{"title"', + '[{"title":1},{"titleX":}]', '[{"title":1},{"ti\ntle":2}]']) { + var threw = false; + try { JSON.parse(bad); } catch (e) { threw = e instanceof SyntaxError; } + assertEq(threw, true); +} + +// Keep cached atoms alive across allocations made while parsing later values. +var large = '[{"uncommonPropertyForGC":0},' + + '{"other":[' + new Array(20000).fill('"allocation"').join(',') + ']},' + + '{"uncommonPropertyForGC":1}]'; +for (var i = 0; i < 3; i++) { + gc(); + assertEq(JSON.parse(large)[2].uncommonPropertyForGC, 1); +} diff --git a/js/src/jit-test/tests/collections/Map-groupBy-lookup.js b/js/src/jit-test/tests/collections/Map-groupBy-lookup.js new file mode 100644 index 0000000000..945bb28b36 --- /dev/null +++ b/js/src/jit-test/tests/collections/Map-groupBy-lookup.js @@ -0,0 +1,47 @@ +// Repeated keys must reuse their group, including SameValueZero keys. +var objectKey = {}; +var symbolKey = Symbol(); +var keys = [undefined, null, false, 0, -0, NaN, "key", objectKey, symbolKey]; +for (var iteration = 0; iteration < 100; iteration++) { + var input = []; + for (var repeat = 0; repeat < 4; repeat++) { + for (var key of keys) + input.push(key); + } + var calls = 0; + var groups = Map.groupBy(input, function(value, index) { + assertEq(index, calls++); + return value; + }); + assertEq(calls, input.length); + assertEq(groups.size, 8); + for (var key of keys) + assertEq(groups.get(key).length, key === 0 ? 8 : 4); + assertEq(groups.get(objectKey)[0], objectKey); + assertEq(groups.get(symbolKey)[0], symbolKey); + assertEq(groups.get(undefined)[0], undefined); + var order = Array.from(groups.keys()); + assertEq(order[0], undefined); + assertEq(order[3], 0); + assertEq(order[4], NaN); + assertEq(order[7], symbolKey); +} + +// A throwing callback must still close the input iterator. +var closed = false; +function* values() { + try { + yield 1; + yield 2; + } finally { + closed = true; + } +} +var sentinel = {}; +try { + Map.groupBy(values(), function() { throw sentinel; }); + throw new Error("callback did not throw"); +} catch (error) { + assertEq(error, sentinel); +} +assertEq(closed, true); diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 4bcaadee47..be69f3f1ee 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -385,7 +385,7 @@ struct BaselineStackBuilder return virtualPointerAtStackOffset(priorOffset); #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ - defined(JS_CODEGEN_X64) + defined(JS_CODEGEN_LOONGARCH64) || defined(JS_CODEGEN_X64) // On X64, ARM, ARM64, and MIPS, the frame pointer save location depends on // the caller of the rectifier frame. BufferPointer priorFrame = diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index ab38011be2..282cdeaf9b 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -458,7 +458,6 @@ BaselineCompiler::emitEpilogue() masm.pop(BaselineFrameReg); emitProfilerExitFrame(); - masm.ret(); return true; } @@ -484,7 +483,7 @@ BaselineCompiler::emitOutOfLinePostBarrierSlot() // On ARM, save the link register before calling. It contains the return // address. The |masm.ret()| later will pop this into |pc| to return. masm.push(lr); -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) masm.push(ra); #endif masm.pushValue(R0); diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index 30da13d9c1..516be80609 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -15,6 +15,8 @@ # include "jit/arm/BaselineCompiler-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/BaselineCompiler-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/BaselineCompiler-loongarch64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/BaselineCompiler-mips32.h" #elif defined(JS_CODEGEN_MIPS64) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index a6adc122c7..4fc540e626 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -679,9 +679,15 @@ ICToBool_Object::Compiler::generateStubCode(MacroAssembler& masm) EmitReturnFromIC(masm); masm.bind(&slowPath); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.push(ra); +#endif masm.setupUnalignedABICall(scratch); masm.passABIArg(objReg); masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::EmulatesUndefined)); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.pop(ra); +#endif masm.convertBoolToInt32(ReturnReg, ReturnReg); masm.xor32(Imm32(1), ReturnReg); masm.tagValue(JSVAL_TYPE_BOOLEAN, ReturnReg, R0); @@ -1464,6 +1470,12 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_ res.isNumber() && !TypedArrayGetElemStubExists(stub, obj)) { + if (obj->is() && + obj->as().hasResizableOrGrowableBuffer()) + { + return true; + } + if (!cx->runtime()->jitSupportsFloatingPoint && (TypedThingRequiresFloatingPoint(obj) || rhs.isDouble())) { @@ -2154,6 +2166,8 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm) Register obj = masm.extractObject(R0, ExtractTemp0); masm.loadPtr(Address(ICStubReg, ICGetElem_TypedArray::offsetOfShape()), scratchReg); masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure); + if (layout_ == Layout_TypedArray) + GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure); // Ensure the index is an integer. if (cx->runtime()->jitSupportsFloatingPoint) { @@ -2625,6 +2639,9 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_ bool expectOutOfBounds; double idx = index.toNumber(); if (obj->is()) { + if (obj->as().hasResizableOrGrowableBuffer()) + return true; + expectOutOfBounds = (idx < 0 || idx >= double(obj->as().length())); } else { // Typed objects throw on out of bounds accesses. Don't attach @@ -3215,6 +3232,8 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm) Register obj = masm.extractObject(R0, ExtractTemp0); masm.loadPtr(Address(ICStubReg, ICSetElem_TypedArray::offsetOfShape()), scratchReg); masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure); + if (layout_ == Layout_TypedArray) + GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure); // Ensure the index is an integer. if (cx->runtime()->jitSupportsFloatingPoint) { @@ -7468,6 +7487,9 @@ ICTableSwitch::Compiler::generateStubCode(MacroAssembler& masm) masm.convertDoubleToInt32(FloatReg0, key, &outOfRange, /* negativeZeroCheck = */ false); } else { // Pass pointer to double value. +#ifdef JS_CODEGEN_LOONGARCH64 + masm.push(ra); +#endif masm.pushValue(R0); masm.moveStackPtrTo(R0.scratchReg()); @@ -7479,6 +7501,9 @@ ICTableSwitch::Compiler::generateStubCode(MacroAssembler& masm) // int32. masm.movePtr(ReturnReg, scratch); masm.popValue(R0); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.pop(ra); +#endif masm.branchIfFalseBool(scratch, &outOfRange); masm.unboxInt32(R0, key); } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index b10520252c..1ef6e607e8 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -6570,7 +6570,7 @@ CodeGenerator::visitAbsI(LAbsI* ins) masm.branchTest32(Assembler::NotSigned, input, input, &positive); masm.neg32(input); LSnapshot* snapshot = ins->snapshot(); -#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) if (snapshot) bailoutCmp32(Assembler::Equal, input, Imm32(INT32_MIN), snapshot); #else @@ -8428,7 +8428,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) // If index > initializedLength, call a stub. Note that this relies on the // condition flags sticking from the incoming branch. Label callStub; -#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) // Had to reimplement for MIPS because there are no flags. if (unboxedType == JSVAL_TYPE_MAGIC) { Address initLength(elements, ObjectElements::offsetOfInitializedLength()); @@ -8889,9 +8889,17 @@ CodeGenerator::branchIfNotEmptyObjectElements(Register obj, Label* target) Address(obj, NativeObject::offsetOfElements()), ImmPtr(js::emptyObjectElements), &emptyObj); - masm.branchPtr(Assembler::NotEqual, + masm.branchPtr(Assembler::Equal, Address(obj, NativeObject::offsetOfElements()), ImmPtr(js::emptyObjectElementsShared), + &emptyObj); + masm.branchPtr(Assembler::Equal, + Address(obj, NativeObject::offsetOfElements()), + ImmPtr(js::emptyObjectElementsResizableOrGrowable), + &emptyObj); + masm.branchPtr(Assembler::NotEqual, + Address(obj, NativeObject::offsetOfElements()), + ImmPtr(js::emptyObjectElementsSharedResizableOrGrowable), target); masm.bind(&emptyObj); } diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index b0fd03538d..0e554c17af 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -19,6 +19,8 @@ # include "jit/arm/CodeGenerator-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/CodeGenerator-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/CodeGenerator-loongarch64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/CodeGenerator-mips32.h" #elif defined(JS_CODEGEN_MIPS64) @@ -535,8 +537,7 @@ class CodeGenerator final : public CodeGeneratorSpecific Label* ifDoesntEmulateUndefined, Register scratch, OutOfLineTestObject* ool); - // Branch to target unless obj has an emptyObjectElements or emptyObjectElementsShared - // elements pointer. + // Branch to target unless obj has one of the empty elements pointers. void branchIfNotEmptyObjectElements(Register obj, Label* target); void emitStoreElementTyped(const LAllocation* value, MIRType valueType, MIRType elementType, diff --git a/js/src/jit/ExecutableAllocator.h b/js/src/jit/ExecutableAllocator.h index 8042ae7a98..eb53505879 100644 --- a/js/src/jit/ExecutableAllocator.h +++ b/js/src/jit/ExecutableAllocator.h @@ -64,6 +64,7 @@ extern "C" void sync_instruction_memory(caddr_t v, u_int len); #if defined(__linux__) && \ (defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)) && \ + !defined(JS_CODEGEN_LOONGARCH64) && \ (!defined(JS_SIMULATOR_MIPS32) && !defined(JS_SIMULATOR_MIPS64)) #include #endif @@ -220,6 +221,12 @@ class ExecutableAllocator { js::jit::Simulator::FlushICache(code, size); } +#elif defined(JS_CODEGEN_LOONGARCH64) + static void cacheFlush(void* code, size_t size) + { + intptr_t end = reinterpret_cast(code) + size; + __builtin___clear_cache(reinterpret_cast(code), reinterpret_cast(end)); + } #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) static void cacheFlush(void* code, size_t size) { diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 1a949fae62..8e28a93c0e 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -3341,7 +3341,9 @@ PerThreadData::setAutoFlushICache(AutoFlushICache* afc) void AutoFlushICache::setRange(uintptr_t start, size_t len) { -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ + defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) AutoFlushICache* afc = TlsPerThreadData.get()->PerThreadData::autoFlushICache(); MOZ_ASSERT(afc); MOZ_ASSERT(!afc->start_); @@ -3374,7 +3376,8 @@ AutoFlushICache::setRange(uintptr_t start, size_t len) void AutoFlushICache::flush(uintptr_t start, size_t len) { -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \ + defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) PerThreadData* pt = TlsPerThreadData.get(); AutoFlushICache* afc = pt ? pt->PerThreadData::autoFlushICache() : nullptr; if (!afc) { @@ -3401,7 +3404,8 @@ AutoFlushICache::flush(uintptr_t start, size_t len) void AutoFlushICache::setInhibit() { -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \ + defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) AutoFlushICache* afc = TlsPerThreadData.get()->PerThreadData::autoFlushICache(); MOZ_ASSERT(afc); MOZ_ASSERT(afc->start_); @@ -3428,14 +3432,18 @@ AutoFlushICache::setInhibit() // the respective AutoFlushICache dynamic context. // AutoFlushICache::AutoFlushICache(const char* nonce, bool inhibit) -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ + defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) : start_(0), stop_(0), name_(nonce), inhibit_(inhibit) #endif { -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ + defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) PerThreadData* pt = TlsPerThreadData.get(); AutoFlushICache* afc = pt->PerThreadData::autoFlushICache(); if (afc) @@ -3450,7 +3458,9 @@ AutoFlushICache::AutoFlushICache(const char* nonce, bool inhibit) AutoFlushICache::~AutoFlushICache() { -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ + defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) PerThreadData* pt = TlsPerThreadData.get(); MOZ_ASSERT(pt->PerThreadData::autoFlushICache() == this); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 5a7e437285..095dc14175 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -1245,6 +1245,7 @@ GenerateTypedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta masm.branchPtr(Assembler::AboveOrEqual, tmpReg, ImmPtr(&TypedArrayObject::classes[Scalar::MaxTypedArrayViewType]), failures); + GuardResizableOrGrowableTypedArray(masm, object, tmpReg, failures); // Load length. masm.loadTypedOrValue(Address(object, TypedArrayObject::lengthOffset()), output); @@ -1644,6 +1645,9 @@ GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript if (!JSID_IS_ATOM(id, cx->names().length)) return true; + if (obj->as().hasResizableOrGrowableBuffer()) + return true; + if (hasTypedArrayLengthStub(obj)) return true; @@ -4038,6 +4042,12 @@ GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& i if (!obj->is() && !obj->is()) return false; + if (obj->is() && + obj->as().hasResizableOrGrowableBuffer()) + { + return false; + } + MOZ_ASSERT(idval.isInt32() || idval.isString()); // Don't emit a stub if the access is out of bounds. We make to make @@ -4092,6 +4102,9 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm, // Decide to what type index the stub should be optimized Register tmpReg = output.scratchReg().gpr(); MOZ_ASSERT(tmpReg != InvalidReg); + if (array->is()) + GuardResizableOrGrowableTypedArray(masm, object, tmpReg, &failures); + Register indexReg = tmpReg; if (idval.isString()) { MOZ_ASSERT(GetIndexFromString(idval.toString()) != UINT32_MAX); @@ -4575,6 +4588,7 @@ GenerateSetTypedArrayElement(JSContext* cx, MacroAssembler& masm, IonCache::Stub if (!shape) return false; masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures); + GuardResizableOrGrowableTypedArray(masm, object, temp, &failures); // Ensure the index is an int32. Register indexReg; @@ -4661,6 +4675,9 @@ SetPropertyIC::tryAttachTypedArrayElement(JSContext* cx, HandleScript outerScrip if (!IsTypedArrayElementSetInlineable(obj, idval, val)) return true; + if (obj->as().hasResizableOrGrowableBuffer()) + return true; + *emitted = true; MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); diff --git a/js/src/jit/IonCaches.h b/js/src/jit/IonCaches.h index 914965055b..ef6965312a 100644 --- a/js/src/jit/IonCaches.h +++ b/js/src/jit/IonCaches.h @@ -10,6 +10,8 @@ # include "jit/arm/Assembler-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/Assembler-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/Assembler-loongarch64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/Assembler-mips32.h" #elif defined(JS_CODEGEN_MIPS64) diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h index 2d9469dead..e749738c82 100644 --- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -747,7 +747,9 @@ struct VMFunction; struct AutoFlushICache { private: -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ + defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) uintptr_t start_; uintptr_t stop_; const char* name_; diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 65b0e8abfb..a6fee5dec6 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2539,6 +2539,13 @@ MachineState::FromBailout(RegisterDump::GPRArray& regs, RegisterDump::FPUArray& machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Double), &fpregs[i]); machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Single), &fpregs[i]); } +#elif defined(JS_CODEGEN_LOONGARCH64) + for (unsigned i = 0; i < FloatRegisters::TotalPhys; i++) { + machine.setRegisterLocation(FloatRegister(FloatRegister::Encoding(i), FloatRegisters::Double), + &fpregs[i]); + machine.setRegisterLocation(FloatRegister(FloatRegister::Encoding(i), FloatRegisters::Single), + &fpregs[i]); + } #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) for (unsigned i = 0; i < FloatRegisters::TotalPhys; i++) { machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Single), &fpregs[i]); diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index bee3b3ebea..b88ebc046f 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -1927,6 +1927,9 @@ LAllocation::toRegister() const # include "jit/mips64/LIR-mips64.h" # endif # include "jit/mips-shared/LIR-mips-shared.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/mips64/LIR-mips64.h" +# include "jit/mips-shared/LIR-mips-shared.h" #elif defined(JS_CODEGEN_NONE) # include "jit/none/LIR-none.h" #else diff --git a/js/src/jit/LOpcodes.h b/js/src/jit/LOpcodes.h index 135c616bd1..a6891d98ee 100644 --- a/js/src/jit/LOpcodes.h +++ b/js/src/jit/LOpcodes.h @@ -14,6 +14,8 @@ # include "jit/arm/LOpcodes-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/LOpcodes-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/mips64/LOpcodes-mips64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/LOpcodes-mips32.h" #elif defined(JS_CODEGEN_MIPS64) diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index 8c380dcdef..499dc2b403 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -18,6 +18,8 @@ # include "jit/arm/Lowering-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/Lowering-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/Lowering-loongarch64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/Lowering-mips32.h" #elif defined(JS_CODEGEN_MIPS64) diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 0f78ef3f2f..4585a838b4 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -365,13 +365,9 @@ IonBuilder::inlineNativeGetter(CallInfo& callInfo, JSFunction* target) // Try to optimize typed array lengths. if (TypedArrayObject::isOriginalLengthGetter(native)) { - Scalar::Type type = thisTypes->getTypedArrayType(constraints()); - if (type == Scalar::MaxTypedArrayViewType) - return InliningStatus_NotInlined; - - MInstruction* length = addTypedArrayLength(thisArg); - current->push(length); - return InliningStatus_Inlined; + // RAB/GSAB views can have dynamic length or temporarily become + // out-of-bounds. Let the property IC/VM path handle the getter. + return InliningStatus_NotInlined; } // Try to optimize RegExp getters. @@ -2480,21 +2476,10 @@ IsTypedArrayObject(CompilerConstraintList* constraints, MDefinition* def) IonBuilder::InliningStatus IonBuilder::inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - if (callInfo.getArg(0)->type() != MIRType::Object) - return InliningStatus_NotInlined; - if (getInlineReturnType() != MIRType::Int32) - return InliningStatus_NotInlined; + (void) callInfo; - if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) - return InliningStatus_NotInlined; - - MInstruction* length = addTypedArrayLength(callInfo.getArg(0)); - current->push(length); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; + // RAB/GSAB views require dynamic length semantics. + return InliningStatus_NotInlined; } IonBuilder::InliningStatus @@ -3251,45 +3236,14 @@ bool IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayType, bool* requiresTagCheck, AtomicCheckResult checkResult) { - if (!JitSupportsAtomics()) - return false; + (void) callInfo; + (void) arrayType; + (void) requiresTagCheck; + (void) checkResult; - if (callInfo.getArg(0)->type() != MIRType::Object) - return false; - - if (callInfo.getArg(1)->type() != MIRType::Int32) - return false; - - // Ensure that the first argument is a TypedArray that maps shared - // memory. - // - // Then check both that the element type is something we can - // optimize and that the return type is suitable for that element - // type. - - TemporaryTypeSet* arg0Types = callInfo.getArg(0)->resultTypeSet(); - if (!arg0Types) - return false; - - TemporaryTypeSet::TypedArraySharedness sharedness; - *arrayType = arg0Types->getTypedArrayType(constraints(), &sharedness); - *requiresTagCheck = sharedness != TemporaryTypeSet::KnownShared; - switch (*arrayType) { - case Scalar::Int8: - case Scalar::Uint8: - case Scalar::Int16: - case Scalar::Uint16: - case Scalar::Int32: - return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Int32; - case Scalar::Uint32: - // Bug 1077305: it would be attractive to allow inlining even - // if the inline return type is Int32, which it will frequently - // be. - return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Double; - default: - // Excludes floating types and Uint8Clamped. - return false; - } + // Atomics bounds checks through addTypedArrayLengthAndData assume stable + // SharedArrayBuffer lengths. Avoid this path now that growable SAB exists. + return false; } void diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 197737c1ef..8f13179bfd 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -5505,25 +5505,15 @@ jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id, Scalar::Type* arrayType) { - if (obj->mightBeType(MIRType::String)) - return false; + (void) constraints; + (void) obj; + (void) id; + (void) arrayType; - if (id->type() != MIRType::Int32 && id->type() != MIRType::Double) - return false; - - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types) - return false; - - *arrayType = types->getTypedArrayType(constraints); - - // FIXME: https://bugzil.la/1536699 - if (*arrayType == Scalar::MaxTypedArrayViewType || - Scalar::isBigIntType(*arrayType)) { - return false; - } - - return true; + // Resizable ArrayBuffer and growable SharedArrayBuffer views need dynamic + // length/out-of-bounds handling. This older MIR path assumes stable + // typed-array length/data slots, so keep element accesses on IC/VM paths. + return false; } bool diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index 98316eb643..536b71399b 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -18,6 +18,8 @@ # include "jit/arm/MacroAssembler-arm-inl.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/MacroAssembler-arm64-inl.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/MacroAssembler-loongarch64-inl.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/MacroAssembler-mips32-inl.h" #elif defined(JS_CODEGEN_MIPS64) diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 9519e8f0eb..cab426d708 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -1875,7 +1875,8 @@ MacroAssembler::outOfLineTruncateSlow(FloatRegister src, Register dest, bool wid bool compilingWasm) { #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ - defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) + defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) if (widenFloatToDouble) { convertFloat32ToDouble(src, ScratchDoubleReg); src = ScratchDoubleReg; @@ -1905,7 +1906,8 @@ MacroAssembler::outOfLineTruncateSlow(FloatRegister src, Register dest, bool wid storeCallInt32Result(dest); #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ - defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) + defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) // Nothing #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) if (widenFloatToDouble) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index e5efb475c6..af7de1c16a 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -19,6 +19,8 @@ # include "jit/arm/MacroAssembler-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/MacroAssembler-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/MacroAssembler-loongarch64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/MacroAssembler-mips32.h" #elif defined(JS_CODEGEN_MIPS64) @@ -66,8 +68,8 @@ using mozilla::FloatingPoint; // architectures on each method declaration, such as PER_ARCH and // PER_SHARED_ARCH. -# define ALL_ARCH mips32, mips64, arm, arm64, x86, x64 -# define ALL_SHARED_ARCH arm, arm64, x86_shared, mips_shared +# define ALL_ARCH mips32, mips64, loongarch64, arm, arm64, x86, x64 +# define ALL_SHARED_ARCH arm, arm64, loongarch64, x86_shared, mips_shared // * How this macro works: // @@ -110,6 +112,7 @@ using mozilla::FloatingPoint; # define DEFINED_ON_x86_shared # define DEFINED_ON_arm # define DEFINED_ON_arm64 +# define DEFINED_ON_loongarch64 # define DEFINED_ON_mips32 # define DEFINED_ON_mips64 # define DEFINED_ON_mips_shared @@ -132,6 +135,9 @@ using mozilla::FloatingPoint; #elif defined(JS_CODEGEN_ARM64) # undef DEFINED_ON_arm64 # define DEFINED_ON_arm64 define +#elif defined(JS_CODEGEN_LOONGARCH64) +# undef DEFINED_ON_loongarch64 +# define DEFINED_ON_loongarch64 define #elif defined(JS_CODEGEN_MIPS32) # undef DEFINED_ON_mips32 # define DEFINED_ON_mips32 define @@ -419,13 +425,13 @@ class MacroAssembler : public MacroAssemblerSpecific // Stack manipulation functions. void PushRegsInMask(LiveRegisterSet set) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); void PushRegsInMask(LiveGeneralRegisterSet set); void PopRegsInMask(LiveRegisterSet set); void PopRegsInMask(LiveGeneralRegisterSet set); void PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); void Push(const Operand op) DEFINED_ON(x86_shared); void Push(Register reg) PER_SHARED_ARCH; @@ -497,8 +503,8 @@ class MacroAssembler : public MacroAssemblerSpecific void callAndPushReturnAddress(Register reg) DEFINED_ON(x86_shared); void callAndPushReturnAddress(Label* label) DEFINED_ON(x86_shared); - void pushReturnAddress() DEFINED_ON(mips_shared, arm, arm64); - void popReturnAddress() DEFINED_ON(mips_shared, arm, arm64); + void pushReturnAddress() DEFINED_ON(mips_shared, loongarch64, arm, arm64); + void popReturnAddress() DEFINED_ON(mips_shared, loongarch64, arm, arm64); public: // =============================================================== @@ -741,9 +747,9 @@ class MacroAssembler : public MacroAssemblerSpecific inline void xorPtr(Register src, Register dest) PER_ARCH; inline void xorPtr(Imm32 imm, Register dest) PER_ARCH; - inline void and64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64); - inline void or64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64); - inline void xor64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64); + inline void and64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64); + inline void or64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64); + inline void xor64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64); // =============================================================== // Arithmetic functions @@ -759,14 +765,14 @@ class MacroAssembler : public MacroAssemblerSpecific inline void addPtr(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64); inline void addPtr(ImmWord imm, Register dest) PER_ARCH; inline void addPtr(ImmPtr imm, Register dest); - inline void addPtr(Imm32 imm, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + inline void addPtr(Imm32 imm, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64); inline void addPtr(Imm32 imm, const AbsoluteAddress& dest) DEFINED_ON(x86, x64); - inline void addPtr(const Address& src, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + inline void addPtr(const Address& src, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64); inline void add64(Register64 src, Register64 dest) PER_ARCH; inline void add64(Imm32 imm, Register64 dest) PER_ARCH; - inline void add64(Imm64 imm, Register64 dest) DEFINED_ON(x86, x64, arm, mips32, mips64); - inline void add64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64); + inline void add64(Imm64 imm, Register64 dest) DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64); + inline void add64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64); inline void addFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; @@ -778,14 +784,14 @@ class MacroAssembler : public MacroAssemblerSpecific inline void sub32(Imm32 imm, Register dest) PER_SHARED_ARCH; inline void subPtr(Register src, Register dest) PER_ARCH; - inline void subPtr(Register src, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + inline void subPtr(Register src, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64); inline void subPtr(Imm32 imm, Register dest) PER_ARCH; inline void subPtr(ImmWord imm, Register dest) DEFINED_ON(x64); - inline void subPtr(const Address& addr, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + inline void subPtr(const Address& addr, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64); inline void sub64(Register64 src, Register64 dest) PER_ARCH; - inline void sub64(Imm64 imm, Register64 dest) DEFINED_ON(x86, x64, arm, mips32, mips64); - inline void sub64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64); + inline void sub64(Imm64 imm, Register64 dest) DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64); + inline void sub64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64); inline void subFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; @@ -798,10 +804,10 @@ class MacroAssembler : public MacroAssemblerSpecific inline void mul64(const Operand& src, const Register64& dest) DEFINED_ON(x64); inline void mul64(const Operand& src, const Register64& dest, const Register temp) - DEFINED_ON(x64, mips64); + DEFINED_ON(x64, mips64, loongarch64); inline void mul64(Imm64 imm, const Register64& dest) PER_ARCH; inline void mul64(Imm64 imm, const Register64& dest, const Register temp) - DEFINED_ON(x86, x64, arm, mips32, mips64); + DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64); inline void mul64(const Register64& src, const Register64& dest, const Register temp) PER_ARCH; @@ -810,7 +816,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline void mulFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; inline void mulDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; - inline void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + inline void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64); // Perform an integer division, returning the integer part rounded toward zero. // rhs must not be zero, and the division must not overflow. @@ -835,7 +841,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline void dec32(RegisterOrInt32Constant* key); inline void neg32(Register reg) PER_SHARED_ARCH; - inline void neg64(Register64 reg) DEFINED_ON(x86, x64, arm, mips32, mips64); + inline void neg64(Register64 reg) DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64); inline void negateFloat(FloatRegister reg) PER_SHARED_ARCH; @@ -896,19 +902,19 @@ class MacroAssembler : public MacroAssemblerSpecific inline void rotateLeft(Imm32 count, Register input, Register dest) PER_SHARED_ARCH; inline void rotateLeft(Register count, Register input, Register dest) PER_SHARED_ARCH; - inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64); - inline void rotateLeft64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64); + inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64, loongarch64); + inline void rotateLeft64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64, loongarch64); inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest, Register temp) - DEFINED_ON(x86, x64, arm, mips32, mips64); + DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64); inline void rotateLeft64(Register count, Register64 input, Register64 dest, Register temp) PER_ARCH; inline void rotateRight(Imm32 count, Register input, Register dest) PER_SHARED_ARCH; inline void rotateRight(Register count, Register input, Register dest) PER_SHARED_ARCH; - inline void rotateRight64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64); - inline void rotateRight64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64); + inline void rotateRight64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64, loongarch64); + inline void rotateRight64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64, loongarch64); inline void rotateRight64(Imm32 count, Register64 input, Register64 dest, Register temp) - DEFINED_ON(x86, x64, arm, mips32, mips64); + DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64); inline void rotateRight64(Register count, Register64 input, Register64 dest, Register temp) PER_ARCH; @@ -934,7 +940,7 @@ class MacroAssembler : public MacroAssemblerSpecific template inline void cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest) - DEFINED_ON(x86_shared, arm, arm64, mips32, mips64); + DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64); template inline void cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest) @@ -956,9 +962,9 @@ class MacroAssembler : public MacroAssemblerSpecific Label* label); inline void branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); inline void branch32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); inline void branch32(Condition cond, const BaseIndex& lhs, Register rhs, Label* label) DEFINED_ON(x86_shared); @@ -968,7 +974,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branch32(Condition cond, const Operand& lhs, Imm32 rhs, Label* label) DEFINED_ON(x86_shared); inline void branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); // The supported condition are Equal, NotEqual, LessThan(orEqual), GreaterThan(orEqual), // Below(orEqual) and Above(orEqual). @@ -977,7 +983,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branch64(Condition cond, Register64 lhs, Imm64 val, Label* success, Label* fail = nullptr) PER_ARCH; inline void branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success, - Label* fail = nullptr) DEFINED_ON(x86, x64, arm, mips32, mips64); + Label* fail = nullptr) DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64); // On x86 and x64 NotEqual and Equal conditions are allowed for the branch64 variants // with Address as lhs. On others only the NotEqual condition. inline void branch64(Condition cond, const Address& lhs, Imm64 val, Label* label) PER_ARCH; @@ -1001,12 +1007,12 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchPtr(Condition cond, const Address& lhs, ImmWord rhs, Label* label) PER_SHARED_ARCH; inline void branchPtr(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); inline void branchPtr(Condition cond, const AbsoluteAddress& lhs, ImmWord rhs, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); inline void branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); template inline CodeOffsetJump branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH; @@ -1014,7 +1020,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline CodeOffsetJump branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH; void branchPtrInNurseryChunk(Condition cond, Register ptr, Register temp, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); void branchPtrInNurseryChunk(Condition cond, const Address& address, Register temp, Label* label) DEFINED_ON(x86); void branchValueIsNurseryObject(Condition cond, const Address& address, Register temp, Label* label) PER_ARCH; @@ -1032,9 +1038,9 @@ class MacroAssembler : public MacroAssemblerSpecific // which isn't implemented on all architectures. // E.g. the x64 variants will do this only in the int64_t range. inline void branchTruncateFloat32MaybeModUint32(FloatRegister src, Register dest, Label* fail) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); inline void branchTruncateDoubleMaybeModUint32(FloatRegister src, Register dest, Label* fail) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); // Truncate a double/float32 to intptr and when it doesn't fit jump to the failure label. inline void branchTruncateFloat32ToPtr(FloatRegister src, Register dest, Label* fail) @@ -1044,9 +1050,9 @@ class MacroAssembler : public MacroAssemblerSpecific // Truncate a double/float32 to int32 and when it doesn't fit jump to the failure label. inline void branchTruncateFloat32ToInt32(FloatRegister src, Register dest, Label* fail) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); inline void branchTruncateDoubleToInt32(FloatRegister src, Register dest, Label* fail) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); inline void branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, Label* label) PER_SHARED_ARCH; @@ -1069,7 +1075,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchTest32(Condition cond, Register lhs, Imm32 rhs, L label) PER_SHARED_ARCH; inline void branchTest32(Condition cond, const Address& lhs, Imm32 rhh, Label* label) PER_SHARED_ARCH; inline void branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); + DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64); template inline void branchTestPtr(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH; @@ -1132,7 +1138,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchTestUndefined(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; inline void branchTestInt32(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; inline void branchTestDouble(Condition cond, Register tag, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestNumber(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; inline void branchTestBoolean(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; inline void branchTestString(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; @@ -1150,60 +1156,60 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchTestUndefined(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; inline void branchTestUndefined(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestUndefined(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestInt32(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; inline void branchTestInt32(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestInt32(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestDouble(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; inline void branchTestDouble(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestDouble(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestNumber(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestBoolean(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; inline void branchTestBoolean(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestBoolean(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestString(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestString(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestSymbol(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestSymbol(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestBigInt(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestBigInt(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestNull(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; inline void branchTestNull(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestNull(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); // Clobbers the ScratchReg on x64. inline void branchTestObject(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; inline void branchTestObject(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestObject(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestGCThing(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; inline void branchTestGCThing(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; inline void branchTestPrimitive(Condition cond, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestMagic(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; inline void branchTestMagic(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; template inline void branchTestMagic(Condition cond, const ValueOperand& value, L label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label) PER_ARCH; @@ -1216,13 +1222,13 @@ class MacroAssembler : public MacroAssemblerSpecific // Checks if given Value is evaluated to true or false in a condition. // The type of the value should match the type of the method. inline void branchTestInt32Truthy(bool truthy, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label* label) PER_SHARED_ARCH; inline void branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label) PER_ARCH; inline void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); inline void branchTestBigIntTruthy(bool truthy, const ValueOperand& value, Label* label) - DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared); private: @@ -1294,9 +1300,9 @@ class MacroAssembler : public MacroAssemblerSpecific // ======================================================================== // Memory access primitives. inline void storeUncanonicalizedDouble(FloatRegister src, const Address& dest) - DEFINED_ON(x86_shared, arm, arm64, mips32, mips64); + DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64); inline void storeUncanonicalizedDouble(FloatRegister src, const BaseIndex& dest) - DEFINED_ON(x86_shared, arm, arm64, mips32, mips64); + DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64); inline void storeUncanonicalizedDouble(FloatRegister src, const Operand& dest) DEFINED_ON(x86_shared); @@ -1304,9 +1310,9 @@ class MacroAssembler : public MacroAssemblerSpecific inline void storeDouble(FloatRegister src, const T& dest); inline void storeUncanonicalizedFloat32(FloatRegister src, const Address& dest) - DEFINED_ON(x86_shared, arm, arm64, mips32, mips64); + DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64); inline void storeUncanonicalizedFloat32(FloatRegister src, const BaseIndex& dest) - DEFINED_ON(x86_shared, arm, arm64, mips32, mips64); + DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64); inline void storeUncanonicalizedFloat32(FloatRegister src, const Operand& dest) DEFINED_ON(x86_shared); @@ -1747,7 +1753,7 @@ class MacroAssembler : public MacroAssemblerSpecific template inline void addToStackPtr(T t); template inline void addStackPtrTo(T t); - void subFromStackPtr(Imm32 imm32) DEFINED_ON(mips32, mips64, arm, x86, x64); + void subFromStackPtr(Imm32 imm32) DEFINED_ON(mips32, mips64, loongarch64, arm, x86, x64); void subFromStackPtr(Register reg); template diff --git a/js/src/jit/MoveEmitter.h b/js/src/jit/MoveEmitter.h index d8c808f0e2..eadd9d27bf 100644 --- a/js/src/jit/MoveEmitter.h +++ b/js/src/jit/MoveEmitter.h @@ -12,6 +12,8 @@ # include "jit/arm/MoveEmitter-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/MoveEmitter-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/mips64/MoveEmitter-mips64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/MoveEmitter-mips32.h" #elif defined(JS_CODEGEN_MIPS64) diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index 47df600945..dfc83f16d8 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -339,13 +339,25 @@ uint8_t UniqueTrackedOptimizations::indexOf(const TrackedOptimizations* optimizations) const { MOZ_ASSERT(sorted()); + + if (lastTypes_ == &optimizations->types_ && + lastAttempts_ == &optimizations->attempts_ && + lastIndex_ != UINT8_MAX) + { + return lastIndex_; + } + Key key; key.types = &optimizations->types_; key.attempts = &optimizations->attempts_; AttemptsMap::Ptr p = map_.lookup(key); MOZ_ASSERT(p); MOZ_ASSERT(p->value().index != UINT8_MAX); - return p->value().index; + uint8_t index = p->value().index; + lastTypes_ = key.types; + lastAttempts_ = key.attempts; + lastIndex_ = index; + return index; } // Assigns each unique tracked type an index; outputs a compact list. @@ -366,11 +378,15 @@ class jit::UniqueTrackedTypes TypesMap map_; Vector list_; + Maybe lastType_; + uint8_t lastTypeIndex_; public: explicit UniqueTrackedTypes(JSContext* cx) : map_(cx), - list_(cx) + list_(cx), + lastType_(Nothing()), + lastTypeIndex_(0) { } bool init() { return map_.init(); } @@ -383,9 +399,17 @@ class jit::UniqueTrackedTypes bool UniqueTrackedTypes::getIndexOf(JSContext* cx, TypeSet::Type ty, uint8_t* indexp) { + if (lastType_.isSome() && *lastType_ == ty) { + *indexp = lastTypeIndex_; + return true; + } + TypesMap::AddPtr p = map_.lookupForAdd(ty); if (p) { - *indexp = p->value(); + uint8_t index = p->value(); + lastType_ = Some(ty); + lastTypeIndex_ = index; + *indexp = index; return true; } @@ -399,6 +423,8 @@ UniqueTrackedTypes::getIndexOf(JSContext* cx, TypeSet::Type ty, uint8_t* indexp) return false; if (!list_.append(ty)) return false; + lastType_ = Some(ty); + lastTypeIndex_ = index; *indexp = index; return true; } diff --git a/js/src/jit/OptimizationTracking.h b/js/src/jit/OptimizationTracking.h index 1854fc1652..9dc347e2ad 100644 --- a/js/src/jit/OptimizationTracking.h +++ b/js/src/jit/OptimizationTracking.h @@ -167,10 +167,17 @@ class UniqueTrackedOptimizations // TempOptimizationAttemptsVectors sorted by frequency. SortedVector sorted_; + mutable const TempOptimizationTypeInfoVector* lastTypes_; + mutable const TempOptimizationAttemptsVector* lastAttempts_; + mutable uint8_t lastIndex_; + public: explicit UniqueTrackedOptimizations(JSContext* cx) : map_(cx), - sorted_(cx) + sorted_(cx), + lastTypes_(nullptr), + lastAttempts_(nullptr), + lastIndex_(UINT8_MAX) { } MOZ_MUST_USE bool init() { return map_.init(); } diff --git a/js/src/jit/RegisterAllocator.h b/js/src/jit/RegisterAllocator.h index 97333fbdca..8b5d0736a6 100644 --- a/js/src/jit/RegisterAllocator.h +++ b/js/src/jit/RegisterAllocator.h @@ -282,7 +282,8 @@ class RegisterAllocator if (mir->compilingWasm()) { #if defined(JS_CODEGEN_X64) allRegisters_.take(AnyRegister(HeapReg)); -#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \ + defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) allRegisters_.take(AnyRegister(HeapReg)); allRegisters_.take(AnyRegister(GlobalReg)); #elif defined(JS_CODEGEN_ARM64) diff --git a/js/src/jit/RegisterSets.h b/js/src/jit/RegisterSets.h index dcabcd4246..602f8fb1de 100644 --- a/js/src/jit/RegisterSets.h +++ b/js/src/jit/RegisterSets.h @@ -1319,7 +1319,8 @@ SavedNonVolatileRegisters(AllocatableGeneralRegisterSet unused) result.add(Register::FromCode(Registers::lr)); #elif defined(JS_CODEGEN_ARM64) result.add(Register::FromCode(Registers::lr)); -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) result.add(Register::FromCode(Registers::ra)); #endif diff --git a/js/src/jit/Registers.h b/js/src/jit/Registers.h index 1016c18379..1ed928a510 100644 --- a/js/src/jit/Registers.h +++ b/js/src/jit/Registers.h @@ -15,6 +15,8 @@ # include "jit/arm/Architecture-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/Architecture-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/Architecture-loongarch64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/Architecture-mips32.h" #elif defined(JS_CODEGEN_MIPS64) diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index d337534768..edf39837cd 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -848,6 +848,8 @@ ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler& masm, Register obj, Val // void PostWriteBarrier(JSRuntime* rt, JSObject* obj); #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) saveRegs.add(ICTailCallReg); +#elif defined(JS_CODEGEN_LOONGARCH64) + masm.push(ra); #endif saveRegs.set() = GeneralRegisterSet::Intersect(saveRegs.set(), GeneralRegisterSet::Volatile()); masm.PushRegsInMask(saveRegs); @@ -857,6 +859,9 @@ ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler& masm, Register obj, Val masm.passABIArg(obj); masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier)); masm.PopRegsInMask(saveRegs); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.pop(ra); +#endif masm.bind(&skipBarrier); } @@ -1292,10 +1297,16 @@ ICBinaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm) masm.divDouble(FloatReg1, FloatReg0); break; case JSOP_MOD: +#ifdef JS_CODEGEN_LOONGARCH64 + masm.push(ra); +#endif masm.setupUnalignedABICall(R0.scratchReg()); masm.passABIArg(FloatReg0, MoveOp::DOUBLE); masm.passABIArg(FloatReg1, MoveOp::DOUBLE); masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NumberMod), MoveOp::DOUBLE); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.pop(ra); +#endif MOZ_ASSERT(ReturnDoubleReg == FloatReg0); break; default: @@ -1417,9 +1428,15 @@ ICBinaryArith_DoubleWithInt32::Compiler::generateStubCode(MacroAssembler& masm) masm.bind(&truncateABICall); masm.push(intReg); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.push(ra); +#endif masm.setupUnalignedABICall(scratchReg); masm.passABIArg(FloatReg0, MoveOp::DOUBLE); masm.callWithABI(mozilla::BitwiseCast(JS::ToInt32)); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.pop(ra); +#endif masm.storeCallInt32Result(scratchReg); masm.pop(intReg); @@ -1581,9 +1598,15 @@ ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm) masm.jump(&doneTruncate); masm.bind(&truncateABICall); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.push(ra); +#endif masm.setupUnalignedABICall(scratchReg); masm.passABIArg(FloatReg0, MoveOp::DOUBLE); masm.callWithABI(BitwiseCast(JS::ToInt32)); +#ifdef JS_CODEGEN_LOONGARCH64 + masm.pop(ra); +#endif masm.storeCallInt32Result(scratchReg); masm.bind(&doneTruncate); @@ -3608,6 +3631,17 @@ CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Labe masm.branch32(Assembler::NotEqual, AbsoluteAddress(address), Imm32(0), failure); } +void +GuardResizableOrGrowableTypedArray(MacroAssembler& masm, Register obj, Register scratch, + Label* failure) +{ + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch); + masm.branchTest32(Assembler::NonZero, + Address(scratch, ObjectElements::offsetOfFlags()), + Imm32(ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER), + failure); +} + void LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result) { diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index d259ebf0bc..cf23490942 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -1067,6 +1067,8 @@ class ICStubCompiler MOZ_ASSERT(!regs.has(PseudoStackPointer)); MOZ_ASSERT(!regs.has(RealStackPointer)); MOZ_ASSERT(!regs.has(ICTailCallReg)); +#elif defined(JS_CODEGEN_LOONGARCH64) + MOZ_ASSERT(!regs.has(BaselineStackReg)); #else MOZ_ASSERT(!regs.has(BaselineStackReg)); #endif @@ -1075,6 +1077,9 @@ class ICStubCompiler #ifdef JS_CODEGEN_X64 regs.take(ExtractTemp0); regs.take(ExtractTemp1); +#elif defined(JS_CODEGEN_LOONGARCH64) + regs.take(ExtractTemp0); + regs.take(ExtractTemp1); #endif switch (numInputs) { @@ -2302,7 +2307,11 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, Register void CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure); -MOZ_MUST_USE bool +void +GuardResizableOrGrowableTypedArray(MacroAssembler& masm, Register obj, Register scratch, + Label* failure); + +[[nodiscard]] bool DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj, MutableHandleValue result); diff --git a/js/src/jit/SharedICHelpers.h b/js/src/jit/SharedICHelpers.h index 6093eb4ad8..aa73e795f7 100644 --- a/js/src/jit/SharedICHelpers.h +++ b/js/src/jit/SharedICHelpers.h @@ -14,6 +14,8 @@ # include "jit/arm/SharedICHelpers-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/SharedICHelpers-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/SharedICHelpers-loongarch64.h" #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) #include "jit/mips-shared/SharedICHelpers-mips-shared.h" #elif defined(JS_CODEGEN_NONE) diff --git a/js/src/jit/SharedICRegisters.h b/js/src/jit/SharedICRegisters.h index f8ad817e1a..ef6dde36ca 100644 --- a/js/src/jit/SharedICRegisters.h +++ b/js/src/jit/SharedICRegisters.h @@ -14,6 +14,8 @@ # include "jit/arm/SharedICRegisters-arm.h" #elif defined(JS_CODEGEN_ARM64) # include "jit/arm64/SharedICRegisters-arm64.h" +#elif defined(JS_CODEGEN_LOONGARCH64) +# include "jit/loongarch64/SharedICRegisters-loongarch64.h" #elif defined(JS_CODEGEN_MIPS32) # include "jit/mips32/SharedICRegisters-mips32.h" #elif defined(JS_CODEGEN_MIPS64) diff --git a/js/src/jit/loongarch64/Architecture-loongarch64.cpp b/js/src/jit/loongarch64/Architecture-loongarch64.cpp new file mode 100644 index 0000000000..41321265b8 --- /dev/null +++ b/js/src/jit/loongarch64/Architecture-loongarch64.cpp @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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 "jit/loongarch64/Architecture-loongarch64.h" + +#include + +#ifdef JS_SIMULATOR +# include "jit/loongarch64/Simulator-loongarch64.h" +#endif +#include "jit/RegisterSets.h" + +namespace js { +namespace jit { + +Registers::Code Registers::FromName(const char* name) { + for (size_t i = 0; i < TotalPhys; i++) { + if (strcmp(GetName(i), name) == 0) { + return Code(i); + } + } + + return Invalid; +} + +FloatRegisters::Code FloatRegisters::FromName(const char* name) { + for (size_t i = 0; i < TotalPhys; i++) { + if (strcmp(GetName(i), name) == 0) { + return Code(i); + } + } + + return Invalid; +} + +FloatRegisterSet FloatRegister::ReduceSetForPush(const FloatRegisterSet& s) { +#ifdef ENABLE_WASM_SIMD +# error "Needs more careful logic if SIMD is enabled" +#endif + + LiveFloatRegisterSet ret; + for (FloatRegisterIterator iter(s); iter.more(); ++iter) { + ret.addUnchecked(FromCode((*iter).encoding())); + } + return ret.set(); +} + +uint32_t FloatRegister::GetSizeInBytes(const FloatRegisterSet& s) { +#ifdef ENABLE_WASM_SIMD +# error "Needs more careful logic if SIMD is enabled" +#endif + + return s.size() * sizeof(double); +} + +uint32_t FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s) { +#ifdef ENABLE_WASM_SIMD +# error "Needs more careful logic if SIMD is enabled" +#endif + + return s.size() * sizeof(double); +} + +uint32_t FloatRegister::getRegisterDumpOffsetInBytes() { +#ifdef ENABLE_WASM_SIMD +# error "Needs more careful logic if SIMD is enabled" +#endif + + return encoding() * sizeof(double); +} + +bool CPUFlagsHaveBeenComputed() { + // TODO(loongarch64): Add CPU flags support. + return true; +} + +uint32_t GetLOONGARCH64Flags() { return 0; } + +void FlushICache(void* code, size_t size, bool codeIsThreadLocal) { +#if defined(JS_SIMULATOR) + js::jit::SimulatorProcess::FlushICache(code, size); + +#elif defined(__GNUC__) + intptr_t end = reinterpret_cast(code) + size; + __builtin___clear_cache(reinterpret_cast(code), + reinterpret_cast(end)); + +#else + _flush_cache(reinterpret_cast(code), size, BCACHE); + +#endif +} + +} // namespace jit +} // namespace js diff --git a/js/src/jit/loongarch64/Architecture-loongarch64.h b/js/src/jit/loongarch64/Architecture-loongarch64.h new file mode 100644 index 0000000000..4fab3cfcf5 --- /dev/null +++ b/js/src/jit/loongarch64/Architecture-loongarch64.h @@ -0,0 +1,511 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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/. */ + +#ifndef jit_loongarch64_Architecture_loongarch64_h +#define jit_loongarch64_Architecture_loongarch64_h + +#include "mozilla/MathAlgorithms.h" + +#include +#include +#include + +#include "js/Utility.h" + +namespace js { +namespace jit { + +// LoongArch64 has 32 64-bit integer registers, r0 though r31. +// The program counter is not accessible as a register. +// +// SIMD and scalar floating-point registers share a register bank. +// Floating-point registers are f0 through f31. +// 128 bit SIMD registers are vr0 through vr31. +// e.g., f0 is the bottom 64 bits of vr0. + +// LoongArch64 INT Register Convention: +// Name Alias Usage +// $r0 $zero Constant zero +// $r1 $ra Return address +// $r2 $tp TLS +// $r3 $sp Stack pointer +// $r4-$r11 $a0-$a7 Argument registers +// $r4-$r5 $v0-$v1 Return values +// $r12-$r20 $t0-$t8 Temporary registers +// $r21 $x Reserved +// $r22 $fp Frame pointer +// $r23-$r31 $s0-$s8 Callee-saved registers + +// LoongArch64 FP Register Convention: +// Name Alias Usage +// $f0-$f7 $fa0-$fa7 Argument registers +// $f0-$f1 $fv0-$fv1 Return values +// $f8-f23 $ft0-$ft15 Temporary registers +// $f24-$f31 $fs0-$fs7 Callee-saved registers + +class Registers { + public: + enum RegisterID { + r0 = 0, + r1, + r2, + r3, + r4, + r5, + r6, + r7, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + r16, + r17, + r18, + r19, + r20, + r21, + r22, + r23, + r24, + r25, + r26, + r27, + r28, + r29, + r30, + r31, + zero = r0, + ra = r1, + tp = r2, + sp = r3, + a0 = r4, + a1 = r5, + a2 = r6, + a3 = r7, + a4 = r8, + a5 = r9, + a6 = r10, + a7 = r11, + t0 = r12, + t1 = r13, + t2 = r14, + t3 = r15, + t4 = r16, + t5 = r17, + t6 = r18, + t7 = r19, + t8 = r20, + rx = r21, + fp = r22, + s0 = r23, + s1 = r24, + s2 = r25, + s3 = r26, + s4 = r27, + s5 = r28, + s6 = r29, + s7 = r30, + s8 = r31, + invalid_reg, + }; + typedef uint8_t Code; + typedef RegisterID Encoding; + typedef uint32_t SetType; + + static const Encoding StackPointer = sp; + static const Encoding Invalid = invalid_reg; + + // Content spilled during bailouts. + union RegisterContent { + uintptr_t r; + }; + + static uint32_t SetSize(SetType x) { + static_assert(sizeof(SetType) == 4, "SetType must be 32 bits"); + return mozilla::CountPopulation32(x); + } + static uint32_t FirstBit(SetType x) { + return mozilla::CountTrailingZeroes32(x); + } + static uint32_t LastBit(SetType x) { + return 31 - mozilla::CountLeadingZeroes32(x); + } + + static const char* GetName(uint32_t code) { + static const char* const Names[] = { + "zero", "ra", "tp", "sp", "a0", "a1", "a2", "a3", "a4", "a5", "a6", + "a7", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "rx", + "fp", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8"}; + static_assert(Total == sizeof(Names) / sizeof(Names[0]), + "Table is the correct size"); + if ((code & 31) >= TotalPhys) { + return "invalid"; + } + return Names[code & 31]; + } + + static Code FromName(const char* name); + + static const uint32_t Total = 32; + static const uint32_t TotalPhys = 32; + static const uint32_t Allocatable = + 23; // No named special-function registers. + + static const SetType AllMask = 0xFFFFFFFF; + static const SetType NoneMask = 0x0; + + static const SetType ArgRegMask = + (1 << Registers::a0) | (1 << Registers::a1) | (1 << Registers::a2) | + (1 << Registers::a3) | (1 << Registers::a4) | (1 << Registers::a5) | + (1 << Registers::a6) | (1 << Registers::a7); + + static const SetType VolatileMask = + (1 << Registers::a0) | (1 << Registers::a1) | (1 << Registers::a2) | + (1 << Registers::a3) | (1 << Registers::a4) | (1 << Registers::a5) | + (1 << Registers::a6) | (1 << Registers::a7) | (1 << Registers::t0) | + (1 << Registers::t1) | (1 << Registers::t2) | (1 << Registers::t3) | + (1 << Registers::t4) | (1 << Registers::t5) | (1 << Registers::t6); + + // We use this constant to save registers when entering functions. This + // is why $ra is added here even though it is not "Non Volatile". + static const SetType NonVolatileMask = + (1 << Registers::ra) | (1 << Registers::fp) | (1 << Registers::s0) | + (1 << Registers::s1) | (1 << Registers::s2) | (1 << Registers::s3) | + (1 << Registers::s4) | (1 << Registers::s5) | (1 << Registers::s6) | + (1 << Registers::s7) | (1 << Registers::s8); + + static const SetType SingleByteRegs = VolatileMask | NonVolatileMask; + + static const SetType NonAllocatableMask = + (1 << Registers::zero) | // Always be zero. + (1 << Registers::t7) | // First scratch register. + (1 << Registers::t8) | // Second scratch register. + (1 << Registers::rx) | // Reserved Register. + (1 << Registers::ra) | (1 << Registers::tp) | (1 << Registers::sp); + + static const SetType TempMask = VolatileMask & ~NonAllocatableMask; + + static const SetType WrapperMask = VolatileMask; + + // Registers returned from a JS -> JS call. + static const SetType JSCallMask = (1 << Registers::a2); + + // Registers returned from a JS -> C call. + static const SetType CallMask = (1 << Registers::a0); + + static const SetType AllocatableMask = AllMask & ~NonAllocatableMask; +}; + +// Smallest integer type that can hold a register bitmask. +typedef uint32_t PackedRegisterMask; + +template +class TypedRegisterSet; + +class FloatRegisters { + public: + enum FPRegisterID { + f0 = 0, + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + f23, // Scratch register. + f24, + f25, + f26, + f27, + f28, + f29, + f30, + f31, + }; + + // Eight bits: (invalid << 7) | (kind << 5) | encoding + typedef uint8_t Code; + typedef FPRegisterID Encoding; + typedef uint64_t SetType; + + enum Kind : uint8_t { Double, Single, NumTypes }; + + static constexpr Code Invalid = 0x80; + + static const char* GetName(uint32_t code) { + static const char* const Names[] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; + static_assert(TotalPhys == sizeof(Names) / sizeof(Names[0]), + "Table is the correct size"); + if ((code & 31) >= TotalPhys) { + return "invalid"; + } + return Names[code & 31]; + } + + static Code FromName(const char* name); + + static const uint32_t TotalPhys = 32; + static const uint32_t Total = TotalPhys * NumTypes; + static const uint32_t Allocatable = 31; // Without f23, the scratch register. + + static_assert(sizeof(SetType) * 8 >= Total, + "SetType should be large enough to enumerate all registers."); + + // Magic values which are used to duplicate a mask of physical register for + // a specific type of register. A multiplication is used to copy and shift + // the bits of the physical register mask. + static const SetType SpreadSingle = SetType(1) + << (uint32_t(Single) * TotalPhys); + static const SetType SpreadDouble = SetType(1) + << (uint32_t(Double) * TotalPhys); + static const SetType Spread = SpreadSingle | SpreadDouble; + + static const SetType AllPhysMask = ((SetType(1) << TotalPhys) - 1); + static const SetType AllMask = AllPhysMask * Spread; + static const SetType AllSingleMask = AllPhysMask * SpreadSingle; + static const SetType AllDoubleMask = AllPhysMask * SpreadDouble; + static const SetType NoneMask = SetType(0); + + // TODO(loongarch64): Much less than ARM64 here. + static const SetType NonVolatileMask = + SetType((1 << FloatRegisters::f24) | (1 << FloatRegisters::f25) | + (1 << FloatRegisters::f26) | (1 << FloatRegisters::f27) | + (1 << FloatRegisters::f28) | (1 << FloatRegisters::f29) | + (1 << FloatRegisters::f30) | (1 << FloatRegisters::f31)) * + Spread; + + static const SetType VolatileMask = AllMask & ~NonVolatileMask; + + static const SetType WrapperMask = VolatileMask; + + // f23 is the scratch register. + static const SetType NonAllocatableMask = + (SetType(1) << FloatRegisters::f23) * Spread; + + static const SetType TempMask = VolatileMask & ~NonAllocatableMask; + + static const SetType AllocatableMask = AllMask & ~NonAllocatableMask; + + // Content spilled during bailouts. + union RegisterContent { + float s; + double d; + }; + + static constexpr Encoding encoding(Code c) { + // assert() not available in constexpr function. + // assert(c < Total); + return Encoding(c & 31); + } + + static constexpr Kind kind(Code c) { + // assert() not available in constexpr function. + // assert(c < Total && ((c >> 5) & 3) < NumTypes); + return Kind((c >> 5) & 3); + } + + static constexpr Code fromParts(uint32_t encoding, uint32_t kind, + uint32_t invalid) { + return Code((invalid << 7) | (kind << 5) | encoding); + } +}; + +static const uint32_t SpillSlotSize = + std::max(sizeof(Registers::RegisterContent), + sizeof(FloatRegisters::RegisterContent)); + +static const uint32_t ION_FRAME_SLACK_SIZE = 24; +static const uint32_t ShadowStackSpace = 0; +static const uint32_t SizeOfReturnAddressAfterCall = 0; + +// When our only strategy for far jumps is to encode the offset directly, and +// not insert any jump islands during assembly for even further jumps, then the +// architecture restricts us to -2^27 .. 2^27-4, to fit into a signed 28-bit +// value. We further reduce this range to allow the far-jump inserting code to +// have some breathing room. +static const uint32_t JumpImmediateRange = ((1 << 27) - (20 * 1024 * 1024)); + +struct FloatRegister { + typedef FloatRegisters Codes; + typedef Codes::Code Code; + typedef Codes::Encoding Encoding; + typedef Codes::SetType SetType; + + static uint32_t SetSize(SetType x) { + static_assert(sizeof(SetType) == 8, "SetType must be 64 bits"); + x |= x >> FloatRegisters::TotalPhys; + x &= FloatRegisters::AllPhysMask; + return mozilla::CountPopulation32(x); + } + + static uint32_t FirstBit(SetType x) { + static_assert(sizeof(SetType) == 8, "SetType"); + return mozilla::CountTrailingZeroes64(x); + } + static uint32_t LastBit(SetType x) { + static_assert(sizeof(SetType) == 8, "SetType"); + return 63 - mozilla::CountLeadingZeroes64(x); + } + + private: + // These fields only hold valid values: an invalid register is always + // represented as a valid encoding and kind with the invalid_ bit set. + uint8_t encoding_; // 32 encodings + uint8_t kind_; // Double, Single; more later + bool invalid_; + + typedef Codes::Kind Kind; + + public: + union RegisterContent { + float s; + double d; + }; + + constexpr FloatRegister(Encoding encoding, Kind kind) + : encoding_(encoding), kind_(kind), invalid_(false) { + // assert(uint32_t(encoding) < Codes::TotalPhys); + } + + explicit constexpr FloatRegister(uint32_t code) + : encoding_(FloatRegisters::encoding(code)), + kind_(FloatRegisters::kind(code)), + invalid_(false) {} + + constexpr FloatRegister() + : encoding_(0), kind_(FloatRegisters::Double), invalid_(true) {} + + static FloatRegister FromCode(uint32_t i) { + MOZ_ASSERT(i < Codes::Total); + return FloatRegister(FloatRegisters::encoding(i), FloatRegisters::kind(i)); + } + + bool isSingle() const { + MOZ_ASSERT(!invalid_); + return kind_ == FloatRegisters::Single; + } + bool isDouble() const { + MOZ_ASSERT(!invalid_); + return kind_ == FloatRegisters::Double; + } + bool isSimd128() const { + MOZ_ASSERT(!invalid_); + return false; + } + bool isInvalid() const { return invalid_; } + + FloatRegister asSingle() const { + MOZ_ASSERT(!invalid_); + return FloatRegister(Encoding(encoding_), FloatRegisters::Single); + } + FloatRegister asDouble() const { + MOZ_ASSERT(!invalid_); + return FloatRegister(Encoding(encoding_), FloatRegisters::Double); + } + FloatRegister doubleOverlay() const { return asDouble(); } + FloatRegister asSimd128() const { MOZ_CRASH(); } + + constexpr uint32_t size() const { + MOZ_ASSERT(!invalid_); + if (kind_ == FloatRegisters::Double) { + return sizeof(double); + } + MOZ_ASSERT(kind_ == FloatRegisters::Single); + return sizeof(float); + } + + constexpr Code code() const { + // assert(!invalid_); + return Codes::fromParts(encoding_, kind_, invalid_); + } + + constexpr Encoding encoding() const { + MOZ_ASSERT(!invalid_); + return Encoding(encoding_); + } + + const char* name() const { return FloatRegisters::GetName(uint32_t(encoding_)); } + bool volatile_() const { + MOZ_ASSERT(!invalid_); + return !!((SetType(1) << code()) & FloatRegisters::VolatileMask); + } + constexpr bool operator!=(FloatRegister other) const { + return code() != other.code(); + } + constexpr bool operator==(FloatRegister other) const { + return code() == other.code(); + } + + bool aliases(FloatRegister other) const { + return other.encoding_ == encoding_; + } + // Ensure that two floating point registers' types are equivalent. + bool equiv(FloatRegister other) const { + MOZ_ASSERT(!invalid_); + return kind_ == other.kind_; + } + + uint32_t numAliased() const { return Codes::NumTypes; } + uint32_t numAlignedAliased() const { return numAliased(); } + + void aliased(uint32_t aliasIdx, FloatRegister* ret) const { + MOZ_ASSERT(!invalid_); + MOZ_ASSERT(aliasIdx < numAliased()); + *ret = FloatRegister(Encoding(encoding_), + Kind((aliasIdx + kind_) % numAliased())); + } + void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) const { + MOZ_ASSERT(aliasIdx < numAliased()); + aliased(aliasIdx, ret); + } + SetType alignedOrDominatedAliasedSet() const { + return Codes::Spread << encoding_; + } + + static Code FromName(const char* name) { return FloatRegisters::FromName(name); } + static TypedRegisterSet ReduceSetForPush( + const TypedRegisterSet& s); + static uint32_t GetSizeInBytes(const TypedRegisterSet& s); + static uint32_t GetPushSizeInBytes(const TypedRegisterSet& s); + uint32_t getRegisterDumpOffsetInBytes(); +}; + +// LoongArch doesn't have double registers that cannot be treated as float32. +inline bool hasUnaliasedDouble() { return false; } + +// LoongArch doesn't have double registers that alias multiple floats. +inline bool hasMultiAlias() { return false; } + +uint32_t GetLOONGARCH64Flags(); + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_Architecture_loongarch64_h */ diff --git a/js/src/jit/loongarch64/Assembler-loongarch64.cpp b/js/src/jit/loongarch64/Assembler-loongarch64.cpp new file mode 100644 index 0000000000..b8d33f2ef1 --- /dev/null +++ b/js/src/jit/loongarch64/Assembler-loongarch64.cpp @@ -0,0 +1,2581 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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 "jit/loongarch64/Assembler-loongarch64.h" + +#include "mozilla/DebugOnly.h" +#include "mozilla/Maybe.h" + +#include "gc/Marking.h" +#include "jit/JitCompartment.h" +#include "jit/ExecutableAllocator.h" + +using mozilla::DebugOnly; + +using namespace js; +using namespace js::jit; + +static size_t Load64PatchSize(Instruction* inst0) { + InstImm* i0 = (InstImm*)inst0; + InstImm* i1 = (InstImm*)i0->next(); + InstImm* i2 = (InstImm*)i1->next(); + InstImm* i3 = (InstImm*)i2->next(); + + MOZ_ASSERT((i0->extractBitField(31, 25)) == ((uint32_t)op_lu12i_w >> 25)); + MOZ_ASSERT((i1->extractBitField(31, 22)) == ((uint32_t)op_ori >> 22)); + MOZ_ASSERT((i2->extractBitField(31, 25)) == ((uint32_t)op_lu32i_d >> 25)); + + return ((i3->extractBitField(31, 22)) == ((uint32_t)op_lu52i_d >> 22)) + ? 4 * sizeof(uint32_t) + : 3 * sizeof(uint32_t); +} + +void js::jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, + ReprotectCode reprotect) { + Instruction* inst = reinterpret_cast(jump_.raw()); + + // jumpWithPatch() emits a long-jump template up front so patching only + // updates the embedded target pointer and never mutates live control-flow + // opcodes in place. + MaybeAutoWritableJitCode awjc(inst, 3 * sizeof(uint32_t), reprotect); + Assembler::UpdateLoad64Value(inst, uintptr_t(label.raw())); + + AutoFlushICache::flush(uintptr_t(inst), 3 * sizeof(uint32_t)); +} + +// Note this is used for inter-wasm calls and may pass arguments and results +// in floating point registers even if the system ABI does not. + +// TODO(loongarch64): Inconsistent with LoongArch's calling convention. +// LoongArch floating-point parameters calling convention: +// The first eight floating-point parameters should be passed in f0-f7, and +// the other floating point parameters will be passed like integer parameters. +// But we just pass the other floating-point parameters on stack here. +ABIArg ABIArgGenerator::next(MIRType type) { + switch (type) { + case MIRType::Int32: + case MIRType::Int64: + case MIRType::Pointer: { + if (intRegIndex_ == NumIntArgRegs) { + current_ = ABIArg(stackOffset_); + stackOffset_ += sizeof(uintptr_t); + break; + } + current_ = ABIArg(Register::FromCode(intRegIndex_ + a0.encoding())); + intRegIndex_++; + break; + } + case MIRType::Float32: + case MIRType::Double: { + if (floatRegIndex_ == NumFloatArgRegs) { + current_ = ABIArg(stackOffset_); + stackOffset_ += sizeof(double); + break; + } + current_ = ABIArg(FloatRegister( + FloatRegisters::Encoding(floatRegIndex_ + f0.encoding()), + type == MIRType::Double ? FloatRegisters::Double + : FloatRegisters::Single)); + floatRegIndex_++; + break; + } + default: + MOZ_CRASH("Unexpected argument type"); + } + return current_; +} + +// Encode a standard register when it is being used as rd, the rj, and +// an extra register(rk). These should never be called with an InvalidReg. +uint32_t js::jit::RJ(Register r) { + MOZ_ASSERT(r != InvalidReg); + return r.encoding() << RJShift; +} + +uint32_t js::jit::RK(Register r) { + MOZ_ASSERT(r != InvalidReg); + return r.encoding() << RKShift; +} + +uint32_t js::jit::RD(Register r) { + MOZ_ASSERT(r != InvalidReg); + return r.encoding() << RDShift; +} + +uint32_t js::jit::FJ(FloatRegister r) { return r.encoding() << RJShift; } + +uint32_t js::jit::FK(FloatRegister r) { return r.encoding() << RKShift; } + +uint32_t js::jit::FD(FloatRegister r) { return r.encoding() << RDShift; } + +uint32_t js::jit::FA(FloatRegister r) { return r.encoding() << FAShift; } + +uint32_t js::jit::SA2(uint32_t value) { + MOZ_ASSERT(value < 4); + return (value & SA2Mask) << SAShift; +} + +uint32_t js::jit::SA3(uint32_t value) { + MOZ_ASSERT(value < 8); + return (value & SA3Mask) << SAShift; +} + +Register js::jit::toRK(Instruction& i) { + return Register::FromCode((i.encode() & RKMask) >> RKShift); +} + +Register js::jit::toRJ(Instruction& i) { + return Register::FromCode((i.encode() & RJMask) >> RJShift); +} + +Register js::jit::toRD(Instruction& i) { + return Register::FromCode((i.encode() & RDMask) >> RDShift); +} + +Register js::jit::toR(Instruction& i) { + return Register::FromCode(i.encode() & RegMask); +} + +void InstImm::extractImm16(BOffImm16* dest) { *dest = BOffImm16(*this); } + +void AssemblerLOONGARCH64::finish() { + MOZ_ASSERT(!isFinished); + isFinished = true; +} + +bool AssemblerLOONGARCH64::appendRawCode(const uint8_t* code, size_t numBytes) { + return m_buffer.appendRawCode(code, numBytes); +} + +bool AssemblerLOONGARCH64::reserve(size_t size) { + // This buffer uses fixed-size chunks so there's no point in reserving + // now vs. on-demand. + return !oom(); +} + +bool AssemblerLOONGARCH64::swapBuffer(wasm::Bytes& bytes) { + // For now, specialize to the one use case. As long as wasm::Bytes is a + // Vector, not a linked-list of chunks, there's not much we can do other + // than copy. + MOZ_ASSERT(bytes.empty()); + if (!bytes.resize(bytesNeeded())) { + return false; + } + m_buffer.executableCopy(bytes.begin()); + return true; +} + +void AssemblerLOONGARCH64::copyJumpRelocationTable(uint8_t* dest) { + if (jumpRelocations_.length()) { + memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length()); + } +} + +void AssemblerLOONGARCH64::copyDataRelocationTable(uint8_t* dest) { + if (dataRelocations_.length()) { + memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length()); + } +} + +void AssemblerLOONGARCH64::copyPreBarrierTable(uint8_t* dest) { + if (preBarriers_.length()) { + memcpy(dest, preBarriers_.buffer(), preBarriers_.length()); + } +} + +AssemblerLOONGARCH64::Condition AssemblerLOONGARCH64::InvertCondition(Condition cond) { + switch (cond) { + case Equal: + return NotEqual; + case NotEqual: + return Equal; + case Zero: + return NonZero; + case NonZero: + return Zero; + case LessThan: + return GreaterThanOrEqual; + case LessThanOrEqual: + return GreaterThan; + case GreaterThan: + return LessThanOrEqual; + case GreaterThanOrEqual: + return LessThan; + case Above: + return BelowOrEqual; + case AboveOrEqual: + return Below; + case Below: + return AboveOrEqual; + case BelowOrEqual: + return Above; + case Signed: + return NotSigned; + case NotSigned: + return Signed; + default: + MOZ_CRASH("unexpected condition"); + } +} + +AssemblerLOONGARCH64::DoubleCondition AssemblerLOONGARCH64::InvertCondition( + DoubleCondition cond) { + switch (cond) { + case DoubleOrdered: + return DoubleUnordered; + case DoubleEqual: + return DoubleNotEqualOrUnordered; + case DoubleNotEqual: + return DoubleEqualOrUnordered; + case DoubleGreaterThan: + return DoubleLessThanOrEqualOrUnordered; + case DoubleGreaterThanOrEqual: + return DoubleLessThanOrUnordered; + case DoubleLessThan: + return DoubleGreaterThanOrEqualOrUnordered; + case DoubleLessThanOrEqual: + return DoubleGreaterThanOrUnordered; + case DoubleUnordered: + return DoubleOrdered; + case DoubleEqualOrUnordered: + return DoubleNotEqual; + case DoubleNotEqualOrUnordered: + return DoubleEqual; + case DoubleGreaterThanOrUnordered: + return DoubleLessThanOrEqual; + case DoubleGreaterThanOrEqualOrUnordered: + return DoubleLessThan; + case DoubleLessThanOrUnordered: + return DoubleGreaterThanOrEqual; + case DoubleLessThanOrEqualOrUnordered: + return DoubleGreaterThan; + default: + MOZ_CRASH("unexpected condition"); + } +} + +AssemblerLOONGARCH64::Condition AssemblerLOONGARCH64::InvertCmpCondition( + Condition cond) { + switch (cond) { + case Equal: + case NotEqual: + return cond; + case LessThan: + return GreaterThan; + case LessThanOrEqual: + return GreaterThanOrEqual; + case GreaterThan: + return LessThanOrEqual; + case GreaterThanOrEqual: + return LessThan; + case Above: + return Below; + case AboveOrEqual: + return BelowOrEqual; + case Below: + return Above; + case BelowOrEqual: + return AboveOrEqual; + default: + MOZ_CRASH("no meaningful swapped-operand condition"); + } +} + +BOffImm16::BOffImm16(InstImm inst) + : data((inst.encode() >> Imm16Shift) & Imm16Mask) {} + +Instruction* BOffImm16::getDest(Instruction* src) const { + return &src[(((int32_t)data << 16) >> 16) + 1]; +} + +bool AssemblerLOONGARCH64::oom() const { + return AssemblerShared::oom() || m_buffer.oom() || jumpRelocations_.oom() || + dataRelocations_.oom() || preBarriers_.oom(); +} + +// Size of the instruction stream, in bytes. +size_t AssemblerLOONGARCH64::size() const { return m_buffer.size(); } + +// Size of the relocation table, in bytes. +size_t AssemblerLOONGARCH64::jumpRelocationTableBytes() const { + return jumpRelocations_.length(); +} + +size_t AssemblerLOONGARCH64::dataRelocationTableBytes() const { + return dataRelocations_.length(); +} + +size_t AssemblerLOONGARCH64::preBarrierTableBytes() const { + return preBarriers_.length(); +} + +// Size of the data table, in bytes. +size_t AssemblerLOONGARCH64::bytesNeeded() const { + return size() + jumpRelocationTableBytes() + dataRelocationTableBytes() + + preBarrierTableBytes(); +} + +// write a blob of binary into the instruction stream +BufferOffset AssemblerLOONGARCH64::writeInst(uint32_t x, uint32_t* dest) { + MOZ_ASSERT(hasCreator()); + if (dest == nullptr) { + return m_buffer.putInt(x); + } + + WriteInstStatic(x, dest); + return BufferOffset(); +} + +void AssemblerLOONGARCH64::WriteInstStatic(uint32_t x, uint32_t* dest) { + MOZ_ASSERT(dest != nullptr); + *dest = x; +} + +BufferOffset AssemblerLOONGARCH64::haltingAlign(int alignment) { + // TODO(loongarch64): Implement a proper halting align. + return nopAlign(alignment); +} + +BufferOffset AssemblerLOONGARCH64::nopAlign(int alignment) { + BufferOffset ret; + MOZ_ASSERT(m_buffer.isAligned(4)); + if (alignment == 8) { + if (!m_buffer.isAligned(alignment)) { + BufferOffset tmp = as_nop(); + if (!ret.assigned()) { + ret = tmp; + } + } + } else { + MOZ_ASSERT((alignment & (alignment - 1)) == 0); + while (size() & (alignment - 1)) { + BufferOffset tmp = as_nop(); + if (!ret.assigned()) { + ret = tmp; + } + } + } + return ret; +} + +// Logical operations. +BufferOffset AssemblerLOONGARCH64::as_and(Register rd, Register rj, Register rk) { + spew("and %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_and, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_or(Register rd, Register rj, Register rk) { + spew("or %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_or, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_xor(Register rd, Register rj, Register rk) { + spew("xor %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_xor, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_nor(Register rd, Register rj, Register rk) { + spew("nor %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_nor, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_andn(Register rd, Register rj, Register rk) { + spew("andn %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_andn, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_orn(Register rd, Register rj, Register rk) { + spew("orn %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_orn, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_andi(Register rd, Register rj, int32_t ui12) { + MOZ_ASSERT(is_uintN(ui12, 12)); + spew("andi %3s,%3s,0x%x", rd.name(), rj.name(), ui12); + return writeInst(InstImm(op_andi, ui12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ori(Register rd, Register rj, int32_t ui12) { + MOZ_ASSERT(is_uintN(ui12, 12)); + spew("ori %3s,%3s,0x%x", rd.name(), rj.name(), ui12); + return writeInst(InstImm(op_ori, ui12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_xori(Register rd, Register rj, int32_t ui12) { + MOZ_ASSERT(is_uintN(ui12, 12)); + spew("xori %3s,%3s,0x%x", rd.name(), rj.name(), ui12); + return writeInst(InstImm(op_xori, ui12, rj, rd, 12).encode()); +} + +// Branch and jump instructions +BufferOffset AssemblerLOONGARCH64::as_b(JOffImm26 off) { + spew("b %d", off.decode()); + return writeInst(InstJump(op_b, off).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bl(JOffImm26 off) { + spew("bl %d", off.decode()); + return writeInst(InstJump(op_bl, off).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_jirl(Register rd, Register rj, + BOffImm16 off) { + spew("jirl %3s, %3s, %d", rd.name(), rj.name(), off.decode()); + return writeInst(InstImm(op_jirl, off, rj, rd).encode()); +} + +InstImm AssemblerLOONGARCH64::getBranchCode(JumpOrCall jumpOrCall) { + // jirl or beq + if (jumpOrCall == BranchIsCall) { + return InstImm(op_jirl, BOffImm16(0), zero, ra); + } + + return InstImm(op_beq, BOffImm16(0), zero, zero); +} + +InstImm AssemblerLOONGARCH64::getBranchCode(Register rj, Register rd, Condition c) { + // beq, bne + MOZ_ASSERT(c == AssemblerLOONGARCH64::Equal || c == AssemblerLOONGARCH64::NotEqual); + return InstImm(c == AssemblerLOONGARCH64::Equal ? op_beq : op_bne, BOffImm16(0), + rj, rd); +} + +InstImm AssemblerLOONGARCH64::getBranchCode(Register rj, Condition c) { + // beq, bne, blt, bge + switch (c) { + case AssemblerLOONGARCH64::Equal: + case AssemblerLOONGARCH64::Zero: + case AssemblerLOONGARCH64::BelowOrEqual: + return InstImm(op_beq, BOffImm16(0), rj, zero); + case AssemblerLOONGARCH64::NotEqual: + case AssemblerLOONGARCH64::NonZero: + case AssemblerLOONGARCH64::Above: + return InstImm(op_bne, BOffImm16(0), rj, zero); + case AssemblerLOONGARCH64::GreaterThan: + return InstImm(op_blt, BOffImm16(0), zero, rj); + case AssemblerLOONGARCH64::GreaterThanOrEqual: + case AssemblerLOONGARCH64::NotSigned: + return InstImm(op_bge, BOffImm16(0), rj, zero); + case AssemblerLOONGARCH64::LessThan: + case AssemblerLOONGARCH64::Signed: + return InstImm(op_blt, BOffImm16(0), rj, zero); + case AssemblerLOONGARCH64::LessThanOrEqual: + return InstImm(op_bge, BOffImm16(0), zero, rj); + default: + MOZ_CRASH("Condition not supported."); + } +} + +// Code semantics must conform to compareFloatingpoint +InstImm AssemblerLOONGARCH64::getBranchCode(FPConditionBit cj) { + return InstImm(op_bcz, 0, cj, true); // bcnez +} + +// Arithmetic instructions +BufferOffset AssemblerLOONGARCH64::as_add_w(Register rd, Register rj, Register rk) { + spew("add_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_add_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_add_d(Register rd, Register rj, Register rk) { + spew("add_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_add_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sub_w(Register rd, Register rj, Register rk) { + spew("sub_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_sub_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sub_d(Register rd, Register rj, Register rk) { + spew("sub_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_sub_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_addi_w(Register rd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("addi_w %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_addi_w, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_addi_d(Register rd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("addi_d %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_addi_d, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_addu16i_d(Register rd, Register rj, + int32_t si16) { + MOZ_ASSERT(Imm16::IsInSignedRange(si16)); + spew("addu16i_d %3s,%3s,0x%x", rd.name(), rj.name(), si16); + return writeInst(InstImm(op_addu16i_d, Imm16(si16), rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_alsl_w(Register rd, Register rj, Register rk, + uint32_t sa2) { + MOZ_ASSERT(sa2 < 4); + spew("alsl_w %3s,%3s,0x%x", rd.name(), rj.name(), sa2); + return writeInst(InstReg(op_alsl_w, sa2, rk, rj, rd, 2).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_alsl_wu(Register rd, Register rj, Register rk, + uint32_t sa2) { + MOZ_ASSERT(sa2 < 4); + spew("alsl_wu %3s,%3s,0x%x", rd.name(), rj.name(), sa2); + return writeInst(InstReg(op_alsl_wu, sa2, rk, rj, rd, 2).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_alsl_d(Register rd, Register rj, Register rk, + uint32_t sa2) { + MOZ_ASSERT(sa2 < 4); + spew("alsl_d %3s,%3s,%3s,0x%x", rd.name(), rj.name(), rk.name(), sa2); + return writeInst(InstReg(op_alsl_d, sa2, rk, rj, rd, 2).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_lu12i_w(Register rd, int32_t si20) { + spew("lu12i_w %3s,0x%x", rd.name(), si20); + return writeInst(InstImm(op_lu12i_w, si20, rd, false).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_lu32i_d(Register rd, int32_t si20) { + spew("lu32i_d %3s,0x%x", rd.name(), si20); + return writeInst(InstImm(op_lu32i_d, si20, rd, false).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_lu52i_d(Register rd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_uintN(si12, 12)); + spew("lu52i_d %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_lu52i_d, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_slt(Register rd, Register rj, Register rk) { + spew("slt %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_slt, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sltu(Register rd, Register rj, Register rk) { + spew("sltu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_sltu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_slti(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("slti %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_slti, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sltui(Register rd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("sltui %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_sltui, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_pcaddi(Register rd, int32_t si20) { + spew("pcaddi %3s,0x%x", rd.name(), si20); + return writeInst(InstImm(op_pcaddi, si20, rd, false).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_pcaddu12i(Register rd, int32_t si20) { + spew("pcaddu12i %3s,0x%x", rd.name(), si20); + return writeInst(InstImm(op_pcaddu12i, si20, rd, false).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_pcaddu18i(Register rd, int32_t si20) { + spew("pcaddu18i %3s,0x%x", rd.name(), si20); + return writeInst(InstImm(op_pcaddu18i, si20, rd, false).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_pcalau12i(Register rd, int32_t si20) { + spew("pcalau12i %3s,0x%x", rd.name(), si20); + return writeInst(InstImm(op_pcalau12i, si20, rd, false).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mul_w(Register rd, Register rj, Register rk) { + spew("mul_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mul_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mulh_w(Register rd, Register rj, + Register rk) { + spew("mulh_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mulh_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mulh_wu(Register rd, Register rj, + Register rk) { + spew("mulh_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mulh_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mul_d(Register rd, Register rj, Register rk) { + spew("mul_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mul_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mulh_d(Register rd, Register rj, + Register rk) { + spew("mulh_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mulh_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mulh_du(Register rd, Register rj, + Register rk) { + spew("mulh_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mulh_du, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mulw_d_w(Register rd, Register rj, + Register rk) { + spew("mulw_d_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mulw_d_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mulw_d_wu(Register rd, Register rj, + Register rk) { + spew("mulw_d_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mulw_d_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_div_w(Register rd, Register rj, Register rk) { + spew("div_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_div_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mod_w(Register rd, Register rj, Register rk) { + spew("mod_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mod_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_div_wu(Register rd, Register rj, + Register rk) { + spew("div_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_div_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mod_wu(Register rd, Register rj, + Register rk) { + spew("mod_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mod_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_div_d(Register rd, Register rj, Register rk) { + spew("div_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_div_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mod_d(Register rd, Register rj, Register rk) { + spew("mod_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mod_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_div_du(Register rd, Register rj, + Register rk) { + spew("div_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_div_du, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_mod_du(Register rd, Register rj, + Register rk) { + spew("mod_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_mod_du, rk, rj, rd).encode()); +} + +// Shift instructions +BufferOffset AssemblerLOONGARCH64::as_sll_w(Register rd, Register rj, Register rk) { + spew("sll_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_sll_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_srl_w(Register rd, Register rj, Register rk) { + spew("srl_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_srl_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sra_w(Register rd, Register rj, Register rk) { + spew("sra_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_sra_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_rotr_w(Register rd, Register rj, + Register rk) { + spew("rotr_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_rotr_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_slli_w(Register rd, Register rj, + int32_t ui5) { + MOZ_ASSERT(is_uintN(ui5, 5)); + spew("slli_w %3s,%3s,0x%x", rd.name(), rj.name(), ui5); + return writeInst(InstImm(op_slli_w, ui5, rj, rd, 5).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_srli_w(Register rd, Register rj, + int32_t ui5) { + MOZ_ASSERT(is_uintN(ui5, 5)); + spew("srli_w %3s,%3s,0x%x", rd.name(), rj.name(), ui5); + return writeInst(InstImm(op_srli_w, ui5, rj, rd, 5).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_srai_w(Register rd, Register rj, + int32_t ui5) { + MOZ_ASSERT(is_uintN(ui5, 5)); + spew("srai_w %3s,%3s,0x%x", rd.name(), rj.name(), ui5); + return writeInst(InstImm(op_srai_w, ui5, rj, rd, 5).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_rotri_w(Register rd, Register rj, + int32_t ui5) { + MOZ_ASSERT(is_uintN(ui5, 5)); + spew("rotri_w %3s,%3s,0x%x", rd.name(), rj.name(), ui5); + return writeInst(InstImm(op_rotri_w, ui5, rj, rd, 5).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sll_d(Register rd, Register rj, Register rk) { + spew("sll_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_sll_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_srl_d(Register rd, Register rj, Register rk) { + spew("srl_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_srl_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sra_d(Register rd, Register rj, Register rk) { + spew("sra_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_sra_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_rotr_d(Register rd, Register rj, + Register rk) { + spew("rotr_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_rotr_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_slli_d(Register rd, Register rj, + int32_t ui6) { + MOZ_ASSERT(is_uintN(ui6, 6)); + spew("slli_d %3s,%3s,0x%x", rd.name(), rj.name(), ui6); + return writeInst(InstImm(op_slli_d, ui6, rj, rd, 6).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_srli_d(Register rd, Register rj, + int32_t ui6) { + MOZ_ASSERT(is_uintN(ui6, 6)); + spew("srli_d %3s,%3s,0x%x", rd.name(), rj.name(), ui6); + return writeInst(InstImm(op_srli_d, ui6, rj, rd, 6).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_srai_d(Register rd, Register rj, + int32_t ui6) { + MOZ_ASSERT(is_uintN(ui6, 6)); + spew("srai_d %3s,%3s,0x%x", rd.name(), rj.name(), ui6); + return writeInst(InstImm(op_srai_d, ui6, rj, rd, 6).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_rotri_d(Register rd, Register rj, + int32_t ui6) { + MOZ_ASSERT(is_uintN(ui6, 6)); + spew("rotri_d %3s,%3s,0x%x", rd.name(), rj.name(), ui6); + return writeInst(InstImm(op_rotri_d, ui6, rj, rd, 6).encode()); +} + +// Bit operation instrucitons +BufferOffset AssemblerLOONGARCH64::as_ext_w_b(Register rd, Register rj) { + spew("ext_w_b %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_ext_w_b, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ext_w_h(Register rd, Register rj) { + spew("ext_w_h %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_ext_w_h, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_clo_w(Register rd, Register rj) { + spew("clo_w %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_clo_w, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_clz_w(Register rd, Register rj) { + spew("clz_w %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_clz_w, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_cto_w(Register rd, Register rj) { + spew("cto_w %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_cto_w, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ctz_w(Register rd, Register rj) { + spew("ctz_w %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_ctz_w, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_clo_d(Register rd, Register rj) { + spew("clo_d %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_clo_d, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_clz_d(Register rd, Register rj) { + spew("clz_d %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_clz_d, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_cto_d(Register rd, Register rj) { + spew("cto_d %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_cto_d, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ctz_d(Register rd, Register rj) { + spew("ctz_d %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_ctz_d, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bytepick_w(Register rd, Register rj, + Register rk, int32_t sa2) { + MOZ_ASSERT(sa2 < 4); + spew("bytepick_w %3s,%3s,%3s, 0x%x", rd.name(), rj.name(), rk.name(), sa2); + return writeInst(InstReg(op_bytepick_w, sa2, rk, rj, rd, 2).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bytepick_d(Register rd, Register rj, + Register rk, int32_t sa3) { + MOZ_ASSERT(sa3 < 8); + spew("bytepick_d %3s,%3s,%3s, 0x%x", rd.name(), rj.name(), rk.name(), sa3); + return writeInst(InstReg(op_bytepick_d, sa3, rk, rj, rd, 3).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_revb_2h(Register rd, Register rj) { + spew("revb_2h %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_revb_2h, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_revb_4h(Register rd, Register rj) { + spew("revb_4h %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_revb_4h, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_revb_2w(Register rd, Register rj) { + spew("revb_2w %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_revb_2w, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_revb_d(Register rd, Register rj) { + spew("revb_d %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_revb_d, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_revh_2w(Register rd, Register rj) { + spew("revh_2w %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_revh_2w, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_revh_d(Register rd, Register rj) { + spew("revh_d %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_revh_d, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bitrev_4b(Register rd, Register rj) { + spew("bitrev_4b %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_bitrev_4b, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bitrev_8b(Register rd, Register rj) { + spew("bitrev_8b %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_bitrev_8b, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bitrev_w(Register rd, Register rj) { + spew("bitrev_w %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_bitrev_w, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bitrev_d(Register rd, Register rj) { + spew("bitrev_d %3s,%3s", rd.name(), rj.name()); + return writeInst(InstReg(op_bitrev_d, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bstrins_w(Register rd, Register rj, + int32_t msbw, int32_t lsbw) { + MOZ_ASSERT(lsbw <= msbw); + spew("bstrins_w %3s,%3s,0x%x,0x%x", rd.name(), rj.name(), msbw, lsbw); + return writeInst(InstImm(op_bstr_w, msbw, lsbw, rj, rd, 5).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bstrins_d(Register rd, Register rj, + int32_t msbd, int32_t lsbd) { + MOZ_ASSERT(lsbd <= msbd); + spew("bstrins_d %3s,%3s,0x%x,0x%x", rd.name(), rj.name(), msbd, lsbd); + return writeInst(InstImm(op_bstrins_d, msbd, lsbd, rj, rd, 6).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bstrpick_w(Register rd, Register rj, + int32_t msbw, int32_t lsbw) { + MOZ_ASSERT(lsbw <= msbw); + spew("bstrpick_w %3s,%3s,0x%x,0x%x", rd.name(), rj.name(), msbw, lsbw); + return writeInst(InstImm(op_bstr_w, msbw, lsbw, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_bstrpick_d(Register rd, Register rj, + int32_t msbd, int32_t lsbd) { + MOZ_ASSERT(lsbd <= msbd); + spew("bstrpick_d %3s,%3s,0x%x,0x%x", rd.name(), rj.name(), msbd, lsbd); + return writeInst(InstImm(op_bstrpick_d, msbd, lsbd, rj, rd, 6).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_maskeqz(Register rd, Register rj, + Register rk) { + spew("maskeqz %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_maskeqz, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_masknez(Register rd, Register rj, + Register rk) { + spew("masknez %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_masknez, rk, rj, rd).encode()); +} + +// Load and store instructions +BufferOffset AssemblerLOONGARCH64::as_ld_b(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("ld_b %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_ld_b, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ld_h(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("ld_h %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_ld_h, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ld_w(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("ld_w %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_ld_w, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ld_d(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("ld_d %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_ld_d, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ld_bu(Register rd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("ld_bu %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_ld_bu, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ld_hu(Register rd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("ld_hu %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_ld_hu, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ld_wu(Register rd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("ld_wu %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_ld_wu, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_st_b(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("st_b %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_st_b, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_st_h(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("st_h %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_st_h, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_st_w(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("st_w %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_st_w, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_st_d(Register rd, Register rj, int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("st_d %3s,%3s,0x%x", rd.name(), rj.name(), si12); + return writeInst(InstImm(op_st_d, si12, rj, rd, 12).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldx_b(Register rd, Register rj, Register rk) { + spew("ldx_b %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ldx_b, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldx_h(Register rd, Register rj, Register rk) { + spew("ldx_h %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ldx_h, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldx_w(Register rd, Register rj, Register rk) { + spew("ldx_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ldx_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldx_d(Register rd, Register rj, Register rk) { + spew("ldx_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ldx_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldx_bu(Register rd, Register rj, + Register rk) { + spew("ldx_bu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ldx_bu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldx_hu(Register rd, Register rj, + Register rk) { + spew("ldx_hu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ldx_hu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldx_wu(Register rd, Register rj, + Register rk) { + spew("ldx_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ldx_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_stx_b(Register rd, Register rj, Register rk) { + spew("stx_b %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_stx_b, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_stx_h(Register rd, Register rj, Register rk) { + spew("stx_h %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_stx_h, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_stx_w(Register rd, Register rj, Register rk) { + spew("stx_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_stx_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_stx_d(Register rd, Register rj, Register rk) { + spew("stx_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_stx_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldptr_w(Register rd, Register rj, + int32_t si14) { + MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); + spew("ldptr_w %3s,%3s,0x%x", rd.name(), rj.name(), si14); + return writeInst(InstImm(op_ldptr_w, si14 >> 2, rj, rd, 14).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ldptr_d(Register rd, Register rj, + int32_t si14) { + MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); + spew("ldptr_d %3s,%3s,0x%x", rd.name(), rj.name(), si14); + return writeInst(InstImm(op_ldptr_d, si14 >> 2, rj, rd, 14).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_stptr_w(Register rd, Register rj, + int32_t si14) { + MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); + spew("stptr_w %3s,%3s,0x%x", rd.name(), rj.name(), si14); + return writeInst(InstImm(op_stptr_w, si14 >> 2, rj, rd, 14).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_stptr_d(Register rd, Register rj, + int32_t si14) { + MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); + spew("stptr_d %3s,%3s,0x%x", rd.name(), rj.name(), si14); + return writeInst(InstImm(op_stptr_d, si14 >> 2, rj, rd, 14).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_preld(int32_t hint, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("preld 0x%x,%3s,0x%x", hint, rj.name(), si12); + return writeInst(InstImm(op_preld, si12, rj, hint).encode()); +} + +// Atomic instructions +BufferOffset AssemblerLOONGARCH64::as_amswap_w(Register rd, Register rj, + Register rk) { + spew("amswap_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amswap_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amswap_d(Register rd, Register rj, + Register rk) { + spew("amswap_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amswap_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amadd_w(Register rd, Register rj, + Register rk) { + spew("amadd_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amadd_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amadd_d(Register rd, Register rj, + Register rk) { + spew("amadd_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amadd_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amand_w(Register rd, Register rj, + Register rk) { + spew("amand_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amand_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amand_d(Register rd, Register rj, + Register rk) { + spew("amand_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amand_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amor_w(Register rd, Register rj, + Register rk) { + spew("amor_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amor_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amor_d(Register rd, Register rj, + Register rk) { + spew("amor_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amor_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amxor_w(Register rd, Register rj, + Register rk) { + spew("amxor_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amxor_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amxor_d(Register rd, Register rj, + Register rk) { + spew("amxor_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amxor_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammax_w(Register rd, Register rj, + Register rk) { + spew("ammax_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammax_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammax_d(Register rd, Register rj, + Register rk) { + spew("ammax_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammax_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammin_w(Register rd, Register rj, + Register rk) { + spew("ammin_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammin_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammin_d(Register rd, Register rj, + Register rk) { + spew("ammin_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammin_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammax_wu(Register rd, Register rj, + Register rk) { + spew("ammax_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammax_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammax_du(Register rd, Register rj, + Register rk) { + spew("ammax_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammax_du, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammin_wu(Register rd, Register rj, + Register rk) { + spew("ammin_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammin_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammin_du(Register rd, Register rj, + Register rk) { + spew("ammin_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammin_du, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amswap_db_w(Register rd, Register rj, + Register rk) { + spew("amswap_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amswap_db_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amswap_db_d(Register rd, Register rj, + Register rk) { + spew("amswap_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amswap_db_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amadd_db_w(Register rd, Register rj, + Register rk) { + spew("amadd_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amadd_db_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amadd_db_d(Register rd, Register rj, + Register rk) { + spew("amadd_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amadd_db_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amand_db_w(Register rd, Register rj, + Register rk) { + spew("amand_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amand_db_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amand_db_d(Register rd, Register rj, + Register rk) { + spew("amand_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amand_db_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amor_db_w(Register rd, Register rj, + Register rk) { + spew("amor_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amor_db_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amor_db_d(Register rd, Register rj, + Register rk) { + spew("amor_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amor_db_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amxor_db_w(Register rd, Register rj, + Register rk) { + spew("amxor_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amxor_db_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_amxor_db_d(Register rd, Register rj, + Register rk) { + spew("amxor_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_amxor_db_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammax_db_w(Register rd, Register rj, + Register rk) { + spew("ammax_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammax_db_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammax_db_d(Register rd, Register rj, + Register rk) { + spew("ammax_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammax_db_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammin_db_w(Register rd, Register rj, + Register rk) { + spew("ammin_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammin_db_w, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammin_db_d(Register rd, Register rj, + Register rk) { + spew("ammin_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammin_db_d, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammax_db_wu(Register rd, Register rj, + Register rk) { + spew("ammax_db_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammax_db_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammax_db_du(Register rd, Register rj, + Register rk) { + spew("ammax_db_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammax_db_du, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammin_db_wu(Register rd, Register rj, + Register rk) { + spew("ammin_db_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammin_db_wu, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ammin_db_du(Register rd, Register rj, + Register rk) { + spew("ammin_db_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_ammin_db_du, rk, rj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ll_w(Register rd, Register rj, int32_t si14) { + spew("ll_w %3s,%3s,0x%x", rd.name(), rj.name(), si14); + MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); + return writeInst(InstImm(op_ll_w, si14 >> 2, rj, rd, 14).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ll_d(Register rd, Register rj, int32_t si14) { + spew("ll_d %3s,%3s,0x%x", rd.name(), rj.name(), si14); + MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); + return writeInst(InstImm(op_ll_d, si14 >> 2, rj, rd, 14).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sc_w(Register rd, Register rj, int32_t si14) { + spew("sc_w %3s,%3s,0x%x", rd.name(), rj.name(), si14); + MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); + return writeInst(InstImm(op_sc_w, si14 >> 2, rj, rd, 14).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_sc_d(Register rd, Register rj, int32_t si14) { + spew("sc_d %3s,%3s,0x%x", rd.name(), rj.name(), si14); + MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); + return writeInst(InstImm(op_sc_d, si14 >> 2, rj, rd, 14).encode()); +} + +// Barrier instructions +BufferOffset AssemblerLOONGARCH64::as_dbar(int32_t hint) { + MOZ_ASSERT(is_uintN(hint, 15)); + spew("dbar 0x%x", hint); + return writeInst(InstImm(op_dbar, hint).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ibar(int32_t hint) { + MOZ_ASSERT(is_uintN(hint, 15)); + spew("ibar 0x%x", hint); + return writeInst(InstImm(op_ibar, hint).encode()); +} + +/* =============================================================== */ + +// FP Arithmetic instructions +BufferOffset AssemblerLOONGARCH64::as_fadd_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fadd_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fadd_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fadd_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fadd_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fadd_d, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fsub_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fsub_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fsub_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fsub_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fsub_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fsub_d, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmul_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmul_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmul_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmul_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmul_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmul_d, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fdiv_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fdiv_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fdiv_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fdiv_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fdiv_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fdiv_d, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmadd_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FloatRegister fa) { + spew("fmadd_s %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), + fa.name()); + return writeInst(InstReg(op_fmadd_s, fa, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmadd_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FloatRegister fa) { + spew("fmadd_d %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), + fa.name()); + return writeInst(InstReg(op_fmadd_d, fa, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmsub_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FloatRegister fa) { + spew("fmsub_s %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), + fa.name()); + return writeInst(InstReg(op_fmsub_s, fa, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmsub_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FloatRegister fa) { + spew("fmsub_d %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), + fa.name()); + return writeInst(InstReg(op_fmsub_d, fa, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fnmadd_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FloatRegister fa) { + spew("fnmadd_s %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), + fa.name()); + return writeInst(InstReg(op_fnmadd_s, fa, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fnmadd_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FloatRegister fa) { + spew("fnmadd_d %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), + fa.name()); + return writeInst(InstReg(op_fnmadd_d, fa, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fnmsub_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FloatRegister fa) { + spew("fnmsub_s %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), + fa.name()); + return writeInst(InstReg(op_fnmsub_s, fa, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fnmsub_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FloatRegister fa) { + spew("fnmsub_d %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), + fa.name()); + return writeInst(InstReg(op_fnmsub_d, fa, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmax_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmax_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmax_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmax_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmax_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmax_d, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmin_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmin_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmin_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmin_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmin_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmin_d, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmaxa_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmaxa_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmaxa_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmaxa_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmaxa_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmaxa_d, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmina_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmina_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmina_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmina_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk) { + spew("fmina_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fmina_d, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fabs_s(FloatRegister fd, FloatRegister fj) { + spew("fabs_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fabs_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fabs_d(FloatRegister fd, FloatRegister fj) { + spew("fabs_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fabs_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fneg_s(FloatRegister fd, FloatRegister fj) { + spew("fneg_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fneg_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fneg_d(FloatRegister fd, FloatRegister fj) { + spew("fneg_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fneg_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fsqrt_s(FloatRegister fd, FloatRegister fj) { + spew("fsqrt_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fsqrt_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fsqrt_d(FloatRegister fd, FloatRegister fj) { + spew("fsqrt_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fsqrt_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fcopysign_s(FloatRegister fd, + FloatRegister fj, + FloatRegister fk) { + spew("fcopysign_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fcopysign_s, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fcopysign_d(FloatRegister fd, + FloatRegister fj, + FloatRegister fk) { + spew("fcopysign_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); + return writeInst(InstReg(op_fcopysign_d, fk, fj, fd).encode()); +} + +// FP compare instructions +// fcmp.cond.s and fcmp.cond.d instructions +BufferOffset AssemblerLOONGARCH64::as_fcmp_cor(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_cor_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, COR, fk, fj, cd).encode()); + } else { + spew("fcmp_cor_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, COR, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_ceq(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_ceq_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CEQ, fk, fj, cd).encode()); + } else { + spew("fcmp_ceq_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CEQ, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_cne(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_cne_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CNE, fk, fj, cd).encode()); + } else { + spew("fcmp_cne_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CNE, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_cle(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_cle_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CLE, fk, fj, cd).encode()); + } else { + spew("fcmp_cle_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CLE, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_clt(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_clt_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CLT, fk, fj, cd).encode()); + } else { + spew("fcmp_clt_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CLT, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_cun(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_cun_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CUN, fk, fj, cd).encode()); + } else { + spew("fcmp_cun_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CUN, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_cueq(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_cueq_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CUEQ, fk, fj, cd).encode()); + } else { + spew("fcmp_cueq_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CUEQ, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_cune(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_cune_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CUNE, fk, fj, cd).encode()); + } else { + spew("fcmp_cune_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CUNE, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_cule(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_cule_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CULE, fk, fj, cd).encode()); + } else { + spew("fcmp_cule_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CULE, fk, fj, cd).encode()); + } +} + +BufferOffset AssemblerLOONGARCH64::as_fcmp_cult(FloatFormat fmt, FloatRegister fj, + FloatRegister fk, + FPConditionBit cd) { + if (fmt == DoubleFloat) { + spew("fcmp_cult_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_d, CULT, fk, fj, cd).encode()); + } else { + spew("fcmp_cult_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); + return writeInst(InstReg(op_fcmp_cond_s, CULT, fk, fj, cd).encode()); + } +} + +// FP conversion instructions +BufferOffset AssemblerLOONGARCH64::as_fcvt_s_d(FloatRegister fd, FloatRegister fj) { + spew("fcvt_s_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fcvt_s_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fcvt_d_s(FloatRegister fd, FloatRegister fj) { + spew("fcvt_d_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fcvt_d_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ffint_s_w(FloatRegister fd, + FloatRegister fj) { + spew("ffint_s_w %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ffint_s_w, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ffint_s_l(FloatRegister fd, + FloatRegister fj) { + spew("ffint_s_l %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ffint_s_l, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ffint_d_w(FloatRegister fd, + FloatRegister fj) { + spew("ffint_d_w %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ffint_d_w, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ffint_d_l(FloatRegister fd, + FloatRegister fj) { + spew("ffint_d_l %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ffint_d_l, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftint_w_s(FloatRegister fd, + FloatRegister fj) { + spew("ftint_w_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftint_w_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftint_w_d(FloatRegister fd, + FloatRegister fj) { + spew("ftint_w_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftint_w_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftint_l_s(FloatRegister fd, + FloatRegister fj) { + spew("ftint_l_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftint_l_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftint_l_d(FloatRegister fd, + FloatRegister fj) { + spew("ftint_l_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftint_l_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrm_w_s(FloatRegister fd, + FloatRegister fj) { + spew("ftintrm_w_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrm_w_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrm_w_d(FloatRegister fd, + FloatRegister fj) { + spew("ftintrm_w_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrm_w_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrm_l_s(FloatRegister fd, + FloatRegister fj) { + spew("ftintrm_l_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrm_l_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrm_l_d(FloatRegister fd, + FloatRegister fj) { + spew("ftintrm_l_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrm_l_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrp_w_s(FloatRegister fd, + FloatRegister fj) { + spew("ftintrp_w_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrp_w_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrp_w_d(FloatRegister fd, + FloatRegister fj) { + spew("ftintrp_w_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrp_w_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrp_l_s(FloatRegister fd, + FloatRegister fj) { + spew("ftintrp_l_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrp_l_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrp_l_d(FloatRegister fd, + FloatRegister fj) { + spew("ftintrp_l_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrp_l_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrz_w_s(FloatRegister fd, + FloatRegister fj) { + spew("ftintrz_w_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrz_w_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrz_w_d(FloatRegister fd, + FloatRegister fj) { + spew("ftintrz_w_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrz_w_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrz_l_s(FloatRegister fd, + FloatRegister fj) { + spew("ftintrz_l_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrz_l_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrz_l_d(FloatRegister fd, + FloatRegister fj) { + spew("ftintrz_l_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrz_l_d, fj, fd).encode()); +} +BufferOffset AssemblerLOONGARCH64::as_ftintrne_w_s(FloatRegister fd, + FloatRegister fj) { + spew("ftintrne_w_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrne_w_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrne_w_d(FloatRegister fd, + FloatRegister fj) { + spew("ftintrne_w_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrne_w_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrne_l_s(FloatRegister fd, + FloatRegister fj) { + spew("ftintrne_l_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrne_l_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_ftintrne_l_d(FloatRegister fd, + FloatRegister fj) { + spew("ftintrne_l_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_ftintrne_l_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_frint_s(FloatRegister fd, FloatRegister fj) { + spew("frint_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_frint_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_frint_d(FloatRegister fd, FloatRegister fj) { + spew("frint_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_frint_d, fj, fd).encode()); +} + +// FP mov instructions +BufferOffset AssemblerLOONGARCH64::as_fmov_s(FloatRegister fd, FloatRegister fj) { + spew("fmov_s %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fmov_s, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fmov_d(FloatRegister fd, FloatRegister fj) { + spew("fmov_d %3s,%3s", fd.name(), fj.name()); + return writeInst(InstReg(op_fmov_d, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fsel(FloatRegister fd, FloatRegister fj, + FloatRegister fk, FPConditionBit ca) { + spew("fsel %3s,%3s,%3s,%d", fd.name(), fj.name(), fk.name(), ca); + return writeInst(InstReg(op_fsel, ca, fk, fj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movgr2fr_w(FloatRegister fd, Register rj) { + spew("movgr2fr_w %3s,%3s", fd.name(), rj.name()); + return writeInst(InstReg(op_movgr2fr_w, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movgr2fr_d(FloatRegister fd, Register rj) { + spew("movgr2fr_d %3s,%3s", fd.name(), rj.name()); + return writeInst(InstReg(op_movgr2fr_d, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movgr2frh_w(FloatRegister fd, Register rj) { + spew("movgr2frh_w %3s,%3s", fd.name(), rj.name()); + return writeInst(InstReg(op_movgr2frh_w, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movfr2gr_s(Register rd, FloatRegister fj) { + spew("movfr2gr_s %3s,%3s", rd.name(), fj.name()); + return writeInst(InstReg(op_movfr2gr_s, fj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movfr2gr_d(Register rd, FloatRegister fj) { + spew("movfr2gr_d %3s,%3s", rd.name(), fj.name()); + return writeInst(InstReg(op_movfr2gr_d, fj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movfrh2gr_s(Register rd, FloatRegister fj) { + spew("movfrh2gr_s %3s,%3s", rd.name(), fj.name()); + return writeInst(InstReg(op_movfrh2gr_s, fj, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movgr2fcsr(Register rj) { + spew("movgr2fcsr %3s", rj.name()); + return writeInst(InstReg(op_movgr2fcsr, rj, FCSR).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movfcsr2gr(Register rd) { + spew("movfcsr2gr %3s", rd.name()); + return writeInst(InstReg(op_movfcsr2gr, FCSR, rd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movfr2cf(FPConditionBit cd, + FloatRegister fj) { + spew("movfr2cf %d,%3s", cd, fj.name()); + return writeInst(InstReg(op_movfr2cf, fj, cd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movcf2fr(FloatRegister fd, + FPConditionBit cj) { + spew("movcf2fr %3s,%d", fd.name(), cj); + return writeInst(InstReg(op_movcf2fr, cj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movgr2cf(FPConditionBit cd, Register rj) { + spew("movgr2cf %d,%3s", cd, rj.name()); + return writeInst(InstReg(op_movgr2cf, rj, cd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_movcf2gr(Register rd, FPConditionBit cj) { + spew("movcf2gr %3s,%d", rd.name(), cj); + return writeInst(InstReg(op_movcf2gr, cj, rd).encode()); +} + +// FP load/store instructions +BufferOffset AssemblerLOONGARCH64::as_fld_s(FloatRegister fd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("fld_s %3s,%3s,0x%x", fd.name(), rj.name(), si12); + return writeInst(InstImm(op_fld_s, si12, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fld_d(FloatRegister fd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("fld_d %3s,%3s,0x%x", fd.name(), rj.name(), si12); + return writeInst(InstImm(op_fld_d, si12, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fst_s(FloatRegister fd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("fst_s %3s,%3s,0x%x", fd.name(), rj.name(), si12); + return writeInst(InstImm(op_fst_s, si12, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fst_d(FloatRegister fd, Register rj, + int32_t si12) { + MOZ_ASSERT(is_intN(si12, 12)); + spew("fst_d %3s,%3s,0x%x", fd.name(), rj.name(), si12); + return writeInst(InstImm(op_fst_d, si12, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fldx_s(FloatRegister fd, Register rj, + Register rk) { + spew("fldx_s %3s,%3s,%3s", fd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_fldx_s, rk, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fldx_d(FloatRegister fd, Register rj, + Register rk) { + spew("fldx_d %3s,%3s,%3s", fd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_fldx_d, rk, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fstx_s(FloatRegister fd, Register rj, + Register rk) { + spew("fstx_s %3s,%3s,%3s", fd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_fstx_s, rk, rj, fd).encode()); +} + +BufferOffset AssemblerLOONGARCH64::as_fstx_d(FloatRegister fd, Register rj, + Register rk) { + spew("fstx_d %3s,%3s,%3s", fd.name(), rj.name(), rk.name()); + return writeInst(InstReg(op_fstx_d, rk, rj, fd).encode()); +} + +/* ========================================================================= */ + +void AssemblerLOONGARCH64::bind(Label* label, BufferOffset boff) { + spew(".set Llabel %p", label); + // If our caller didn't give us an explicit target to bind to + // then we want to bind to the location of the next instruction + BufferOffset dest = boff.assigned() ? boff : nextOffset(); + if (label->used()) { + int32_t next; + + // A used label holds a link to branch that uses it. + BufferOffset b(label); + do { + // Even a 0 offset may be invalid if we're out of memory. + if (oom()) { + return; + } + + Instruction* inst = editSrc(b); + + // Second word holds a pointer to the next branch in label's chain. + next = inst[1].encode(); + bind(reinterpret_cast(inst), b.getOffset(), dest.getOffset()); + + b = BufferOffset(next); + } while (next != LabelBase::INVALID_OFFSET); + } + label->bind(dest.getOffset()); +} + +void AssemblerLOONGARCH64::retarget(Label* label, Label* target) { + spew("retarget %p -> %p", label, target); + if (label->used() && !oom()) { + if (target->bound()) { + bind(label, BufferOffset(target)); + } else if (target->used()) { + // The target is not bound but used. Prepend label's branch list + // onto target's. + int32_t next; + BufferOffset labelBranchOffset(label); + + // Find the head of the use chain for label. + do { + Instruction* inst = editSrc(labelBranchOffset); + + // Second word holds a pointer to the next branch in chain. + next = inst[1].encode(); + labelBranchOffset = BufferOffset(next); + } while (next != LabelBase::INVALID_OFFSET); + + // Then patch the head of label's use chain to the tail of + // target's use chain, prepending the entire use chain of target. + Instruction* inst = editSrc(labelBranchOffset); + int32_t prev = target->offset(); + target->use(label->offset()); + inst[1].setData(prev); + } else { + // The target is unbound and unused. We can just take the head of + // the list hanging off of label, and dump that into target. + target->use(label->offset()); + } + } + label->reset(); +} + +void dbg_break() {} + +void AssemblerLOONGARCH64::as_break(uint32_t code) { + MOZ_ASSERT(code <= MAX_BREAK_CODE); + spew("break %d", code); + writeInst(InstImm(op_break, code).encode()); +} + +// This just stomps over memory with 32 bits of raw data. Its purpose is to +// overwrite the call of JITed code with 32 bits worth of an offset. This will +// is only meant to function on code that has been invalidated, so it should +// be totally safe. Since that instruction will never be executed again, a +// ICache flush should not be necessary +void AssemblerLOONGARCH64::PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm) { + // Raw is going to be the return address. + uint32_t* raw = (uint32_t*)label.raw(); + // Overwrite the 4 bytes before the return address, which will + // end up being the call instruction. + *(raw - 1) = imm.value; +} + +uint8_t* AssemblerLOONGARCH64::NextInstruction(uint8_t* inst_, uint32_t* count) { + Instruction* inst = reinterpret_cast(inst_); + if (count != nullptr) { + *count += sizeof(Instruction); + } + return reinterpret_cast(inst->next()); +} + +void AssemblerLOONGARCH64::ToggleToJmp(CodeLocationLabel inst_) { + InstImm* inst = (InstImm*)inst_.raw(); + + MOZ_ASSERT(inst->extractBitField(31, 26) == (uint32_t)op_addu16i_d >> 26); + // We converted beq to addu16i_d, so now we restore it. + inst->setOpcode(op_beq, 6); +} + +void AssemblerLOONGARCH64::ToggleToCmp(CodeLocationLabel inst_) { + InstImm* inst = (InstImm*)inst_.raw(); + + // toggledJump is allways used for short jumps. + MOZ_ASSERT(inst->extractBitField(31, 26) == (uint32_t)op_beq >> 26); + // Replace "beq $zero, $zero, offset" with "addu16i_d $zero, $zero, offset" + inst->setOpcode(op_addu16i_d, 6); +} + +// Since there are no pools in LoongArch64 implementation, this should be +// simple. +Instruction* Instruction::next() { return this + 1; } + +InstImm AssemblerLOONGARCH64::invertBranch(InstImm branch, BOffImm16 skipOffset) { + uint32_t rj = 0; + OpcodeField opcode = (OpcodeField)((branch.extractBitField(31, 26)) << 26); + switch (opcode) { + case op_beq: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_bne, 6); + return branch; + case op_bne: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_beq, 6); + return branch; + case op_bge: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_blt, 6); + return branch; + case op_bgeu: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_bltu, 6); + return branch; + case op_blt: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_bge, 6); + return branch; + case op_bltu: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_bgeu, 6); + return branch; + case op_beqz: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_bnez, 6); + return branch; + case op_bnez: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_beqz, 6); + return branch; + case op_bcz: + branch.setBOffImm16(skipOffset); + rj = branch.extractRJ(); + if (rj & 0x8) { + branch.setRJ(rj & 0x17); + } else { + branch.setRJ(rj | 0x8); + } + return branch; + default: + MOZ_CRASH("Error creating long branch."); + } +} + +#ifdef JS_JITSPEW +void AssemblerLOONGARCH64::decodeBranchInstAndSpew(InstImm branch) { + OpcodeField opcode = (OpcodeField)((branch.extractBitField(31, 26)) << 26); + uint32_t rd_id; + uint32_t rj_id; + uint32_t cj_id; + uint32_t immi = branch.extractImm16Value(); + switch (opcode) { + case op_beq: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("beq 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), Registers::GetName(rd_id)); + break; + case op_bne: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("bne 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), Registers::GetName(rd_id)); + break; + case op_bge: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("bge 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), Registers::GetName(rd_id)); + break; + case op_bgeu: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("bgeu 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), Registers::GetName(rd_id)); + break; + case op_blt: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("blt 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), Registers::GetName(rd_id)); + break; + case op_bltu: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("bltu 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), Registers::GetName(rd_id)); + break; + case op_beqz: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("beqz 0x%x,%3s,0x%x", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), rd_id); + break; + case op_bnez: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("bnez 0x%x,%3s,0x%x", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), rd_id); + break; + case op_bcz: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + cj_id = branch.extractBitField(CJShift + CJBits - 1, CJShift); + if (rj_id & 0x8) { + spew("bcnez 0x%x,FCC%d,0x%x", (int32_t(immi << 18) >> 16) + 4, cj_id, + rd_id); + } else { + spew("bceqz 0x%x,FCC%d,0x%x", (int32_t(immi << 18) >> 16) + 4, cj_id, + rd_id); + } + break; + case op_jirl: + rd_id = branch.extractRD(); + rj_id = branch.extractRJ(); + spew("beqz 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, + Registers::GetName(rj_id), Registers::GetName(rd_id)); + break; + default: + MOZ_CRASH("Error disassemble branch."); + } +} +#endif + +void Assembler::executableCopy(uint8_t* buffer) { + MOZ_ASSERT(isFinished); + m_buffer.executableCopy(buffer); +} + +uintptr_t Assembler::GetPointer(uint8_t* instPtr) { + Instruction* inst = (Instruction*)instPtr; + return Assembler::ExtractLoad64Value(inst); +} + +static JitCode* CodeFromJump(Instruction* jump) { + uint8_t* target = (uint8_t*)Assembler::ExtractLoad64Value(jump); + return JitCode::FromExecutable(target); +} + +void Assembler::TraceJumpRelocations(JSTracer* trc, JitCode* code, + CompactBufferReader& reader) { + while (reader.more()) { + JitCode* child = + CodeFromJump((Instruction*)(code->raw() + reader.readUnsigned())); + TraceManuallyBarrieredEdge(trc, &child, "rel32"); + } +} + +static void TraceBufferDataRelocations(JSTracer* trc, + LOONGBufferWithExecutableCopy* buffer, + CompactBufferReader& reader); + +void Assembler::trace(JSTracer* trc) { + for (size_t i = 0; i < jumps_.length(); i++) { + RelativePatch& rp = jumps_[i]; + if (rp.kind == Relocation::JITCODE) { + JitCode* code = JitCode::FromExecutable((uint8_t*)rp.target); + TraceManuallyBarrieredEdge(trc, &code, "masmrel32"); + MOZ_ASSERT(code == JitCode::FromExecutable((uint8_t*)rp.target)); + } + } + if (dataRelocations_.length()) { + CompactBufferReader reader(dataRelocations_); + TraceBufferDataRelocations(trc, &m_buffer, reader); + } +} + +static void TraceOneDataRelocation(JSTracer* trc, Instruction* inst) { + void* ptr = (void*)Assembler::ExtractLoad64Value(inst); + void* prior = ptr; + + // Data relocations can be for Values or for raw pointers. If a Value is + // zero-tagged, we can trace it as if it were a raw pointer. If a Value + // is not zero-tagged, we have to interpret it as a Value to ensure that the + // tag bits are masked off to recover the actual pointer. + uintptr_t word = reinterpret_cast(ptr); + if (word >> JSVAL_TAG_SHIFT) { + // This relocation is a Value with a non-zero tag. + Value v = Value::fromRawBits(word); + TraceManuallyBarrieredEdge(trc, &v, "jit-masm-value"); + ptr = (void*)v.bitsAsPunboxPointer(); + } else { + // This relocation is a raw pointer or a Value with a zero tag. + // No barrier needed since these are constants. + TraceManuallyBarrieredGenericPointerEdge( + trc, reinterpret_cast(&ptr), "jit-masm-ptr"); + } + + if (ptr != prior) { + Assembler::UpdateLoad64Value(inst, uint64_t(ptr)); + } +} + +static void TraceOneDataRelocation(JSTracer* trc, + mozilla::Maybe& awjc, + JitCode* code, Instruction* inst) { + void* ptr = (void*)Assembler::ExtractLoad64Value(inst); + void* prior = ptr; + + // Data relocations can be for Values or for raw pointers. If a Value is + // zero-tagged, we can trace it as if it were a raw pointer. If a Value + // is not zero-tagged, we have to interpret it as a Value to ensure that the + // tag bits are masked off to recover the actual pointer. + uintptr_t word = reinterpret_cast(ptr); + if (word >> JSVAL_TAG_SHIFT) { + // This relocation is a Value with a non-zero tag. + Value v = Value::fromRawBits(word); + TraceManuallyBarrieredEdge(trc, &v, "jit-masm-value"); + ptr = (void*)v.bitsAsPunboxPointer(); + } else { + // This relocation is a raw pointer or a Value with a zero tag. + // No barrier needed since these are constants. + TraceManuallyBarrieredGenericPointerEdge( + trc, reinterpret_cast(&ptr), "jit-masm-ptr"); + } + + if (ptr != prior) { + if (awjc.isNothing()) { + awjc.emplace(code); + } + Assembler::UpdateLoad64Value(inst, uint64_t(ptr)); + AutoFlushICache::flush(uintptr_t(inst), Load64PatchSize(inst)); + } +} + +static void TraceBufferDataRelocations(JSTracer* trc, + LOONGBufferWithExecutableCopy* buffer, + CompactBufferReader& reader) { + while (reader.more()) { + BufferOffset bo(reader.readUnsigned()); + TraceOneDataRelocation(trc, buffer->getInst(bo)); + } +} + +/* static */ +void Assembler::TraceDataRelocations(JSTracer* trc, JitCode* code, + CompactBufferReader& reader) { + mozilla::Maybe awjc; + while (reader.more()) { + size_t offset = reader.readUnsigned(); + Instruction* inst = (Instruction*)(code->raw() + offset); + TraceOneDataRelocation(trc, awjc, code, inst); + } +} + +void Assembler::bind(RepatchLabel* label) { + BufferOffset dest = nextOffset(); + if (label->used() && !oom()) { + BufferOffset branch(label->offset()); + InstImm* inst = reinterpret_cast(editSrc(branch)); + if ((inst[0].extractBitField(31, 25)) == + ((uint32_t)op_lu12i_w >> 25)) { + addLongJump(branch, dest); + } else { + bind(inst, branch.getOffset(), dest.getOffset()); + } + } + label->bind(dest.getOffset()); +} + +void Assembler::Bind(uint8_t* rawCode, CodeLabel label) { + if (label.patchAt()->bound()) { + intptr_t offset = label.patchAt()->offset(); + intptr_t target = label.target()->offset(); + Instruction* inst = (Instruction*)(rawCode + offset); + Assembler::UpdateLoad64Value(inst, (uint64_t)(rawCode + target)); + } +} + +void Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target) { + int64_t offset = target - branch; + InstImm inst_jirl = InstImm(op_jirl, BOffImm16(0), zero, ra); + InstImm inst_beq = InstImm(op_beq, BOffImm16(0), zero, zero); + + // If encoded offset is 4, then the jump must be short + if (BOffImm16(inst[0]).decode() == 4) { + MOZ_ASSERT(BOffImm16::IsInRange(offset)); + inst[0].setBOffImm16(BOffImm16(offset)); + inst[1].makeNop(); // because before set INVALID_OFFSET + return; + } + + // Generate the long jump for calls because return address has to be the + // address after the reserved block. + if (inst[0].encode() == inst_jirl.encode()) { + addLongJump(BufferOffset(branch), BufferOffset(target)); + Assembler::WriteLoad64Instructions(inst, ScratchRegister, + LabelBase::INVALID_OFFSET); + inst[3].makeNop(); // There are 1 nop. + inst[4] = InstImm(op_jirl, BOffImm16(0), ScratchRegister, ra); + return; + } + + if (BOffImm16::IsInRange(offset)) { + // Skip trailing nops . + bool skipNops = (inst[0].encode() != inst_jirl.encode() && + inst[0].encode() != inst_beq.encode()); + + inst[0].setBOffImm16(BOffImm16(offset)); + inst[1].makeNop(); + + if (skipNops) { + inst[2] = InstImm(op_bge, BOffImm16(3 * sizeof(uint32_t)), zero, zero); + // There are 2 nops after this + } + return; + } + + if (inst[0].encode() == inst_beq.encode()) { + // Handle long unconditional jump. Only four 4 instruction. + addLongJump(BufferOffset(branch), BufferOffset(target)); + Assembler::WriteLoad64Instructions(inst, ScratchRegister, + LabelBase::INVALID_OFFSET); + inst[3] = InstImm(op_jirl, BOffImm16(0), ScratchRegister, zero); + } else { + // Handle long conditional jump. + inst[0] = invertBranch(inst[0], BOffImm16(5 * sizeof(uint32_t))); + // No need for a "nop" here because we can clobber scratch. + addLongJump(BufferOffset(branch + sizeof(uint32_t)), BufferOffset(target)); + Assembler::WriteLoad64Instructions(&inst[1], ScratchRegister, + LabelBase::INVALID_OFFSET); + inst[4] = InstImm(op_jirl, BOffImm16(0), ScratchRegister, zero); + } +} + +void Assembler::processCodeLabels(uint8_t* rawCode) { + for (const CodeLabel& label : codeLabels_) { + Bind(rawCode, label); + } +} + +uint32_t Assembler::PatchWrite_NearCallSize() { + // Load an address needs 3 instructions, and a jump. + return (3 + 1) * sizeof(uint32_t); +} + +void Assembler::PatchWrite_NearCall(CodeLocationLabel start, + CodeLocationLabel toCall) { + Instruction* inst = (Instruction*)start.raw(); + uint8_t* dest = toCall.raw(); + + // Overwrite whatever instruction used to be here with a call. + // Always use long jump for two reasons: + // - Jump has to be the same size because of PatchWrite_NearCallSize. + // - Return address has to be at the end of replaced block. + // Short jump wouldn't be more efficient. + Assembler::WriteLoad64Instructions(inst, ScratchRegister, (uint64_t)dest); + inst[3] = InstImm(op_jirl, BOffImm16(0), ScratchRegister, ra); + + AutoFlushICache::flush(uintptr_t(inst), PatchWrite_NearCallSize()); +} + +uint64_t Assembler::ExtractLoad64Value(Instruction* inst0) { + InstImm* i0 = (InstImm*)inst0; + InstImm* i1 = (InstImm*)i0->next(); + InstImm* i2 = (InstImm*)i1->next(); + InstImm* i3 = (InstImm*)i2->next(); + + MOZ_ASSERT((i0->extractBitField(31, 25)) == ((uint32_t)op_lu12i_w >> 25)); + MOZ_ASSERT((i1->extractBitField(31, 22)) == ((uint32_t)op_ori >> 22)); + MOZ_ASSERT((i2->extractBitField(31, 25)) == ((uint32_t)op_lu32i_d >> 25)); + + if ((i3->extractBitField(31, 22)) == ((uint32_t)op_lu52i_d >> 22)) { + // Li64 + uint64_t value = + (uint64_t(i0->extractBitField(Imm20Bits + Imm20Shift - 1, Imm20Shift)) + << 12) | + (uint64_t( + i1->extractBitField(Imm12Bits + Imm12Shift - 1, Imm12Shift))) | + (uint64_t(i2->extractBitField(Imm20Bits + Imm20Shift - 1, Imm20Shift)) + << 32) | + (uint64_t(i3->extractBitField(Imm12Bits + Imm12Shift - 1, Imm12Shift)) + << 52); + return value; + } else { + // Li48 + uint64_t value = + (uint64_t(i0->extractBitField(Imm20Bits + Imm20Shift - 1, Imm20Shift)) + << 12) | + (uint64_t( + i1->extractBitField(Imm12Bits + Imm12Shift - 1, Imm12Shift))) | + (uint64_t(i2->extractBitField(Imm20Bits + Imm20Shift - 1, Imm20Shift)) + << 32); + + return uint64_t((int64_t(value) << 16) >> 16); + } +} + +void Assembler::UpdateLoad64Value(Instruction* inst0, uint64_t value) { + // Todo: with ma_liPatchable + InstImm* i0 = (InstImm*)inst0; + InstImm* i1 = (InstImm*)i0->next(); + InstImm* i2 = (InstImm*)i1->next(); + InstImm* i3 = (InstImm*)i2->next(); + + MOZ_ASSERT((i0->extractBitField(31, 25)) == ((uint32_t)op_lu12i_w >> 25)); + MOZ_ASSERT((i1->extractBitField(31, 22)) == ((uint32_t)op_ori >> 22)); + MOZ_ASSERT((i2->extractBitField(31, 25)) == ((uint32_t)op_lu32i_d >> 25)); + + if ((i3->extractBitField(31, 22)) == ((uint32_t)op_lu52i_d >> 22)) { + // Li64 + *i0 = InstImm(op_lu12i_w, (int32_t)((value >> 12) & 0xfffff), + Register::FromCode(i0->extractRD()), false); + *i1 = InstImm(op_ori, (int32_t)(value & 0xfff), + Register::FromCode(i1->extractRJ()), + Register::FromCode(i1->extractRD()), 12); + *i2 = InstImm(op_lu32i_d, (int32_t)((value >> 32) & 0xfffff), + Register::FromCode(i2->extractRD()), false); + *i3 = InstImm(op_lu52i_d, (int32_t)((value >> 52) & 0xfff), + Register::FromCode(i3->extractRJ()), + Register::FromCode(i3->extractRD()), 12); + } else { + // Li48 + *i0 = InstImm(op_lu12i_w, (int32_t)((value >> 12) & 0xfffff), + Register::FromCode(i0->extractRD()), false); + *i1 = InstImm(op_ori, (int32_t)(value & 0xfff), + Register::FromCode(i1->extractRJ()), + Register::FromCode(i1->extractRD()), 12); + *i2 = InstImm(op_lu32i_d, (int32_t)((value >> 32) & 0xfffff), + Register::FromCode(i2->extractRD()), false); + } +} + +void Assembler::WriteLoad64Instructions(Instruction* inst0, Register reg, + uint64_t value) { + Instruction* inst1 = inst0->next(); + Instruction* inst2 = inst1->next(); + *inst0 = InstImm(op_lu12i_w, (int32_t)((value >> 12) & 0xfffff), reg, false); + *inst1 = InstImm(op_ori, (int32_t)(value & 0xfff), reg, reg, 12); + *inst2 = InstImm(op_lu32i_d, (int32_t)((value >> 32) & 0xfffff), reg, false); +} + +void Assembler::PatchDataWithValueCheck(CodeLocationLabel label, + ImmPtr newValue, ImmPtr expectedValue) { + PatchDataWithValueCheck(label, PatchedImmPtr(newValue.value), + PatchedImmPtr(expectedValue.value)); +} + +void Assembler::PatchDataWithValueCheck(CodeLocationLabel label, + PatchedImmPtr newValue, + PatchedImmPtr expectedValue) { + Instruction* inst = (Instruction*)label.raw(); + + // Extract old Value + DebugOnly value = Assembler::ExtractLoad64Value(inst); + MOZ_ASSERT(value == uint64_t(expectedValue.value)); + + // Replace with new value + Assembler::UpdateLoad64Value(inst, uint64_t(newValue.value)); + AutoFlushICache::flush(uintptr_t(inst), Load64PatchSize(inst)); +} + +void Assembler::PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm) { + Assembler::UpdateLoad64Value((Instruction*)code, uint64_t(imm.value)); +} + +uint64_t Assembler::ExtractInstructionImmediate(uint8_t* code) { + InstImm* inst = (InstImm*)code; + return Assembler::ExtractLoad64Value(inst); +} + +void Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled) { + Instruction* inst = (Instruction*)inst_.raw(); + InstImm* i0 = (InstImm*)inst; + InstImm* i1 = (InstImm*)i0->next(); + InstImm* i2 = (InstImm*)i1->next(); + Instruction* i3 = (Instruction*)i2->next(); + + MOZ_ASSERT((i0->extractBitField(31, 25)) == ((uint32_t)op_lu12i_w >> 25)); + MOZ_ASSERT((i1->extractBitField(31, 22)) == ((uint32_t)op_ori >> 22)); + MOZ_ASSERT((i2->extractBitField(31, 25)) == ((uint32_t)op_lu32i_d >> 25)); + + if (enabled) { + MOZ_ASSERT((i3->extractBitField(31, 25)) != ((uint32_t)op_lu12i_w >> 25)); + InstImm jirl = InstImm(op_jirl, BOffImm16(0), ScratchRegister, ra); + *i3 = jirl; + } else { + InstNOP nop; + *i3 = nop; + } + + AutoFlushICache::flush(uintptr_t(i3), sizeof(uint32_t)); +} diff --git a/js/src/jit/loongarch64/Assembler-loongarch64.h b/js/src/jit/loongarch64/Assembler-loongarch64.h new file mode 100644 index 0000000000..ec3df88388 --- /dev/null +++ b/js/src/jit/loongarch64/Assembler-loongarch64.h @@ -0,0 +1,1958 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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/. */ + +#ifndef jit_loongarch64_Assembler_loongarch64_h +#define jit_loongarch64_Assembler_loongarch64_h + +#include "mozilla/Sprintf.h" +#include + +#include "jit/CompactBuffer.h" +#include "jit/IonCode.h" +#include "jit/JitCompartment.h" +#include "jit/JitSpewer.h" +#include "jit/loongarch64/Architecture-loongarch64.h" +#include "jit/shared/Assembler-shared.h" + +namespace js { namespace jit { class Operand; } } + +#include "jit/shared/IonAssemblerBuffer.h" +#include "wasm/WasmTypes.h" + +namespace js { +namespace jit { + +static constexpr Register zero{Registers::zero}; +static constexpr Register ra{Registers::ra}; +static constexpr Register tp{Registers::tp}; +static constexpr Register sp{Registers::sp}; +static constexpr Register a0{Registers::a0}; +static constexpr Register a1{Registers::a1}; +static constexpr Register a2{Registers::a2}; +static constexpr Register a3{Registers::a3}; +static constexpr Register a4{Registers::a4}; +static constexpr Register a5{Registers::a5}; +static constexpr Register a6{Registers::a6}; +static constexpr Register a7{Registers::a7}; +static constexpr Register t0{Registers::t0}; +static constexpr Register t1{Registers::t1}; +static constexpr Register t2{Registers::t2}; +static constexpr Register t3{Registers::t3}; +static constexpr Register t4{Registers::t4}; +static constexpr Register t5{Registers::t5}; +static constexpr Register t6{Registers::t6}; +static constexpr Register t7{Registers::t7}; +static constexpr Register t8{Registers::t8}; +static constexpr Register rx{Registers::rx}; +static constexpr Register fp{Registers::fp}; +static constexpr Register s0{Registers::s0}; +static constexpr Register s1{Registers::s1}; +static constexpr Register s2{Registers::s2}; +static constexpr Register s3{Registers::s3}; +static constexpr Register s4{Registers::s4}; +static constexpr Register s5{Registers::s5}; +static constexpr Register s6{Registers::s6}; +static constexpr Register s7{Registers::s7}; +static constexpr Register s8{Registers::s8}; + +static constexpr FloatRegister f0{FloatRegisters::f0, FloatRegisters::Double}; +static constexpr FloatRegister f1{FloatRegisters::f1, FloatRegisters::Double}; +static constexpr FloatRegister f2{FloatRegisters::f2, FloatRegisters::Double}; +static constexpr FloatRegister f3{FloatRegisters::f3, FloatRegisters::Double}; +static constexpr FloatRegister f4{FloatRegisters::f4, FloatRegisters::Double}; +static constexpr FloatRegister f5{FloatRegisters::f5, FloatRegisters::Double}; +static constexpr FloatRegister f6{FloatRegisters::f6, FloatRegisters::Double}; +static constexpr FloatRegister f7{FloatRegisters::f7, FloatRegisters::Double}; +static constexpr FloatRegister f8{FloatRegisters::f8, FloatRegisters::Double}; +static constexpr FloatRegister f9{FloatRegisters::f9, FloatRegisters::Double}; +static constexpr FloatRegister f10{FloatRegisters::f10, FloatRegisters::Double}; +static constexpr FloatRegister f11{FloatRegisters::f11, FloatRegisters::Double}; +static constexpr FloatRegister f12{FloatRegisters::f12, FloatRegisters::Double}; +static constexpr FloatRegister f13{FloatRegisters::f13, FloatRegisters::Double}; +static constexpr FloatRegister f14{FloatRegisters::f14, FloatRegisters::Double}; +static constexpr FloatRegister f15{FloatRegisters::f15, FloatRegisters::Double}; +static constexpr FloatRegister f16{FloatRegisters::f16, FloatRegisters::Double}; +static constexpr FloatRegister f17{FloatRegisters::f17, FloatRegisters::Double}; +static constexpr FloatRegister f18{FloatRegisters::f18, FloatRegisters::Double}; +static constexpr FloatRegister f19{FloatRegisters::f19, FloatRegisters::Double}; +static constexpr FloatRegister f20{FloatRegisters::f20, FloatRegisters::Double}; +static constexpr FloatRegister f21{FloatRegisters::f21, FloatRegisters::Double}; +static constexpr FloatRegister f22{FloatRegisters::f22, FloatRegisters::Double}; +static constexpr FloatRegister f23{FloatRegisters::f23, FloatRegisters::Double}; +static constexpr FloatRegister f24{FloatRegisters::f24, FloatRegisters::Double}; +static constexpr FloatRegister f25{FloatRegisters::f25, FloatRegisters::Double}; +static constexpr FloatRegister f26{FloatRegisters::f26, FloatRegisters::Double}; +static constexpr FloatRegister f27{FloatRegisters::f27, FloatRegisters::Double}; +static constexpr FloatRegister f28{FloatRegisters::f28, FloatRegisters::Double}; +static constexpr FloatRegister f29{FloatRegisters::f29, FloatRegisters::Double}; +static constexpr FloatRegister f30{FloatRegisters::f30, FloatRegisters::Double}; +static constexpr FloatRegister f31{FloatRegisters::f31, FloatRegisters::Double}; + +static constexpr Register InvalidReg{Registers::Invalid}; +static constexpr FloatRegister InvalidFloatReg; + +static constexpr Register StackPointer = sp; +static constexpr Register FramePointer = fp; +static constexpr Register ReturnReg = a0; +static constexpr Register64 ReturnReg64(ReturnReg); +static constexpr FloatRegister ReturnFloat32Reg{FloatRegisters::f0, + FloatRegisters::Single}; +static constexpr FloatRegister ReturnDoubleReg = f0; +static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg; + +static constexpr Register ScratchRegister = t7; +static constexpr Register SecondScratchReg = t8; + +// Helper classes for ScratchRegister usage. Asserts that only one piece +// of code thinks it has exclusive ownership of each scratch register. +struct ScratchRegisterScope : public AutoRegisterScope { + explicit ScratchRegisterScope(MacroAssembler& masm) + : AutoRegisterScope(masm, ScratchRegister) {} +}; + +struct SecondScratchRegisterScope : public AutoRegisterScope { + explicit SecondScratchRegisterScope(MacroAssembler& masm) + : AutoRegisterScope(masm, SecondScratchReg) {} +}; + +static constexpr FloatRegister ScratchFloat32Reg{FloatRegisters::f23, + FloatRegisters::Single}; +static constexpr FloatRegister ScratchDoubleReg = f23; +static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg; + +struct ScratchFloat32Scope : public AutoFloatRegisterScope { + explicit ScratchFloat32Scope(MacroAssembler& masm) + : AutoFloatRegisterScope(masm, ScratchFloat32Reg) {} +}; + +struct ScratchDoubleScope : public AutoFloatRegisterScope { + explicit ScratchDoubleScope(MacroAssembler& masm) + : AutoFloatRegisterScope(masm, ScratchDoubleReg) {} +}; + +// Use arg reg from EnterJIT function as OsrFrameReg. +static constexpr Register OsrFrameReg = a3; +static constexpr Register PreBarrierReg = a1; +static constexpr Register InterpreterPCReg = t0; +static constexpr Register CallTempReg0 = t0; +static constexpr Register CallTempReg1 = t1; +static constexpr Register CallTempReg2 = t2; +static constexpr Register CallTempReg3 = t3; +static constexpr Register CallTempReg4 = t4; +static constexpr Register CallTempReg5 = t5; +static constexpr Register CallTempNonArgRegs[] = {t0, t1, t2, t3}; +static const uint32_t NumCallTempNonArgRegs = std::size(CallTempNonArgRegs); + +static constexpr Register IntArgReg0 = a0; +static constexpr Register IntArgReg1 = a1; +static constexpr Register IntArgReg2 = a2; +static constexpr Register IntArgReg3 = a3; +static constexpr Register IntArgReg4 = a4; +static constexpr Register IntArgReg5 = a5; +static constexpr Register IntArgReg6 = a6; +static constexpr Register IntArgReg7 = a7; +static constexpr Register GlobalReg = s6; +static constexpr Register HeapReg = s7; +static const int32_t WasmGlobalRegBias = 32768; + +// Registerd used in RegExpMatcher instruction (do not use JSReturnOperand). +static constexpr Register RegExpMatcherRegExpReg = CallTempReg0; +static constexpr Register RegExpMatcherStringReg = CallTempReg1; +static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2; + +// Registerd used in RegExpTester instruction (do not use ReturnReg). +static constexpr Register RegExpTesterRegExpReg = CallTempReg0; +static constexpr Register RegExpTesterStringReg = CallTempReg1; +static constexpr Register RegExpTesterLastIndexReg = CallTempReg2; + +static constexpr Register JSReturnReg_Type = a3; +static constexpr Register JSReturnReg_Data = a2; +static constexpr Register JSReturnReg = a2; +static constexpr ValueOperand JSReturnOperand = ValueOperand(JSReturnReg); +static constexpr Register ArgumentsRectifierReg = s3; + +// These registers may be volatile or nonvolatile. +static constexpr Register ABINonArgReg0 = t0; +static constexpr Register ABINonArgReg1 = t1; +static constexpr Register ABINonArgReg2 = t2; +static constexpr Register ABINonArgReg3 = t3; + +// These registers may be volatile or nonvolatile. +// Note: these three registers are all guaranteed to be different +static constexpr Register ABINonArgReturnReg0 = t0; +static constexpr Register ABINonArgReturnReg1 = t1; +static constexpr Register ABINonVolatileReg = s0; + +// This register is guaranteed to be clobberable during the prologue and +// epilogue of an ABI call which must preserve both ABI argument, return +// and non-volatile registers. +static constexpr Register ABINonArgReturnVolatileReg = ra; + +// This register may be volatile or nonvolatile. +// Avoid f23 which is the scratch register. +static constexpr FloatRegister ABINonArgDoubleReg{FloatRegisters::f21, + FloatRegisters::Double}; + +// TLS pointer argument register for WebAssembly functions. This must not alias +// any other register used for passing function arguments or return values. +// Preserved by WebAssembly functions. Must be nonvolatile. +static constexpr Register InstanceReg = s4; +static constexpr Register WasmTlsReg = InstanceReg; + +// Registers used for wasm table calls. These registers must be disjoint +// from the ABI argument registers, InstanceReg and each other. +static constexpr Register WasmTableCallScratchReg0 = ABINonArgReg0; +static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1; +static constexpr Register WasmTableCallScratchReg = WasmTableCallScratchReg0; +static constexpr Register WasmTableCallSigReg = ABINonArgReg2; +static constexpr Register WasmTableCallIndexReg = ABINonArgReg3; +static constexpr Register WasmIonExitRegCallee = t0; +static constexpr Register WasmIonExitRegE0 = a0; +static constexpr Register WasmIonExitRegE1 = a1; +static constexpr Register WasmIonExitRegD0 = a0; +static constexpr Register WasmIonExitRegD1 = a1; +static constexpr Register WasmIonExitRegD2 = t0; + +// Register used as a scratch along the return path in the fast js -> wasm stub +// code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg. +// It must be a volatile register. +static constexpr Register WasmJitEntryReturnScratch = t1; + +static constexpr uint32_t ABIStackAlignment = 16; +static constexpr uint32_t CodeAlignment = 16; + +// This boolean indicates whether we support SIMD instructions flavoured for +// this architecture or not. Rather than a method in the LIRGenerator, it is +// here such that it is accessible from the entire codebase. Once full support +// for SIMD is reached on all tier-1 platforms, this constant can be deleted. +static constexpr bool SupportsSimd = false; +static constexpr uint32_t JitStackAlignment = 16; + +static constexpr uint32_t JitStackValueAlignment = + JitStackAlignment / sizeof(Value); +static_assert(JitStackAlignment % sizeof(Value) == 0 && + JitStackValueAlignment >= 1, + "Stack alignment should be a non-zero multiple of sizeof(Value)"); + +// TODO(loongarch64): this is just a filler to prevent a build failure. The +// LoongArch SIMD alignment requirements still need to be explored. +static constexpr uint32_t SimdMemoryAlignment = 16; + +static_assert(CodeAlignment % SimdMemoryAlignment == 0, + "Code alignment should be larger than any of the alignments " + "which are used for " + "the constant sections of the code buffer. Thus it should be " + "larger than the " + "alignment for SIMD constants."); + +static constexpr uint32_t WasmStackAlignment = SimdMemoryAlignment; +static const uint32_t WasmTrapInstructionLength = 4; + +// See comments in wasm::GenerateFunctionPrologue. The difference between these +// is the size of the largest callable prologue on the platform. +static constexpr uint32_t WasmCheckedCallEntryOffset = 0u; +static constexpr uint32_t WasmCheckedTailEntryOffset = 16u; + +static constexpr Scale ScalePointer = TimesEight; + +// TODO(loongarch64): Add LoongArch instruction types description. + +// LoongArch instruction encoding constants. +static const uint32_t RJShift = 5; +static const uint32_t RJBits = 5; +static const uint32_t RKShift = 10; +static const uint32_t RKBits = 5; +static const uint32_t RDShift = 0; +static const uint32_t RDBits = 5; +static const uint32_t FJShift = 5; +static const uint32_t FJBits = 5; +static const uint32_t FKShift = 10; +static const uint32_t FKBits = 5; +static const uint32_t FDShift = 0; +static const uint32_t FDBits = 5; +static const uint32_t FAShift = 15; +static const uint32_t FABits = 5; +static const uint32_t CJShift = 5; +static const uint32_t CJBits = 3; +static const uint32_t CDShift = 0; +static const uint32_t CDBits = 3; +static const uint32_t CAShift = 15; +static const uint32_t CABits = 3; +static const uint32_t CONDShift = 15; +static const uint32_t CONDBits = 5; + +static const uint32_t SAShift = 15; +static const uint32_t SA2Bits = 2; +static const uint32_t SA3Bits = 3; +static const uint32_t LSBWShift = 10; +static const uint32_t LSBWBits = 5; +static const uint32_t LSBDShift = 10; +static const uint32_t LSBDBits = 6; +static const uint32_t MSBWShift = 16; +static const uint32_t MSBWBits = 5; +static const uint32_t MSBDShift = 16; +static const uint32_t MSBDBits = 6; +static const uint32_t Imm5Shift = 10; +static const uint32_t Imm5Bits = 5; +static const uint32_t Imm6Shift = 10; +static const uint32_t Imm6Bits = 6; +static const uint32_t Imm12Shift = 10; +static const uint32_t Imm12Bits = 12; +static const uint32_t Imm14Shift = 10; +static const uint32_t Imm14Bits = 14; +static const uint32_t Imm15Shift = 0; +static const uint32_t Imm15Bits = 15; +static const uint32_t Imm16Shift = 10; +static const uint32_t Imm16Bits = 16; +static const uint32_t Imm20Shift = 5; +static const uint32_t Imm20Bits = 20; +static const uint32_t Imm21Shift = 0; +static const uint32_t Imm21Bits = 21; +static const uint32_t Imm26Shift = 0; +static const uint32_t Imm26Bits = 26; +static const uint32_t CODEShift = 0; +static const uint32_t CODEBits = 15; + +// LoongArch instruction field bit masks. +static const uint32_t RJMask = (1 << RJBits) - 1; +static const uint32_t RKMask = (1 << RKBits) - 1; +static const uint32_t RDMask = (1 << RDBits) - 1; +static const uint32_t SA2Mask = (1 << SA2Bits) - 1; +static const uint32_t SA3Mask = (1 << SA3Bits) - 1; +static const uint32_t CONDMask = (1 << CONDBits) - 1; +static const uint32_t LSBWMask = (1 << LSBWBits) - 1; +static const uint32_t LSBDMask = (1 << LSBDBits) - 1; +static const uint32_t MSBWMask = (1 << MSBWBits) - 1; +static const uint32_t MSBDMask = (1 << MSBDBits) - 1; +static const uint32_t CODEMask = (1 << CODEBits) - 1; +static const uint32_t Imm5Mask = (1 << Imm5Bits) - 1; +static const uint32_t Imm6Mask = (1 << Imm6Bits) - 1; +static const uint32_t Imm12Mask = (1 << Imm12Bits) - 1; +static const uint32_t Imm14Mask = (1 << Imm14Bits) - 1; +static const uint32_t Imm15Mask = (1 << Imm15Bits) - 1; +static const uint32_t Imm16Mask = (1 << Imm16Bits) - 1; +static const uint32_t Imm20Mask = (1 << Imm20Bits) - 1; +static const uint32_t Imm21Mask = (1 << Imm21Bits) - 1; +static const uint32_t Imm26Mask = (1 << Imm26Bits) - 1; +static const uint32_t BOffImm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift; +static const uint32_t BOffImm21Mask = ((1 << Imm21Bits) - 1) << Imm21Shift; +static const uint32_t BOffImm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift; +static const uint32_t RegMask = Registers::Total - 1; + +// TODO(loongarch64) Change to syscall? +static const uint32_t MAX_BREAK_CODE = 1024 - 1; +static const uint32_t WASM_TRAP = 6; // BRK_OVERFLOW + +// TODO(loongarch64) Change to LoongArch instruction type. +class Instruction; +class InstReg; +class InstImm; +class InstJump; + +uint32_t RJ(Register r); +uint32_t RK(Register r); +uint32_t RD(Register r); +uint32_t FJ(FloatRegister r); +uint32_t FK(FloatRegister r); +uint32_t FD(FloatRegister r); +uint32_t FA(FloatRegister r); +uint32_t SA2(uint32_t value); +uint32_t SA2(FloatRegister r); +uint32_t SA3(uint32_t value); +uint32_t SA3(FloatRegister r); + +Register toRK(Instruction& i); +Register toRJ(Instruction& i); +Register toRD(Instruction& i); +Register toR(Instruction& i); + +// LoongArch enums for instruction fields +enum OpcodeField { + op_beqz = 0x10U << 26, + op_bnez = 0x11U << 26, + op_bcz = 0x12U << 26, // bceqz & bcnez + op_jirl = 0x13U << 26, + op_b = 0x14U << 26, + op_bl = 0x15U << 26, + op_beq = 0x16U << 26, + op_bne = 0x17U << 26, + op_blt = 0x18U << 26, + op_bge = 0x19U << 26, + op_bltu = 0x1aU << 26, + op_bgeu = 0x1bU << 26, + + op_addu16i_d = 0x4U << 26, + + op_lu12i_w = 0xaU << 25, + op_lu32i_d = 0xbU << 25, + op_pcaddi = 0xcU << 25, + op_pcalau12i = 0xdU << 25, + op_pcaddu12i = 0xeU << 25, + op_pcaddu18i = 0xfU << 25, + op_ll_w = 0x20U << 24, + op_sc_w = 0x21U << 24, + op_ll_d = 0x22U << 24, + op_sc_d = 0x23U << 24, + op_ldptr_w = 0x24U << 24, + op_stptr_w = 0x25U << 24, + op_ldptr_d = 0x26U << 24, + op_stptr_d = 0x27U << 24, + op_bstrins_d = 0x2U << 22, + op_bstrpick_d = 0x3U << 22, + op_slti = 0x8U << 22, + op_sltui = 0x9U << 22, + op_addi_w = 0xaU << 22, + op_addi_d = 0xbU << 22, + op_lu52i_d = 0xcU << 22, + op_andi = 0xdU << 22, + op_ori = 0xeU << 22, + op_xori = 0xfU << 22, + op_ld_b = 0xa0U << 22, + op_ld_h = 0xa1U << 22, + op_ld_w = 0xa2U << 22, + op_ld_d = 0xa3U << 22, + op_st_b = 0xa4U << 22, + op_st_h = 0xa5U << 22, + op_st_w = 0xa6U << 22, + op_st_d = 0xa7U << 22, + op_ld_bu = 0xa8U << 22, + op_ld_hu = 0xa9U << 22, + op_ld_wu = 0xaaU << 22, + op_preld = 0xabU << 22, + op_fld_s = 0xacU << 22, + op_fst_s = 0xadU << 22, + op_fld_d = 0xaeU << 22, + op_fst_d = 0xafU << 22, + op_bstr_w = 0x3U << 21, // BSTRINS_W & BSTRPICK_W + op_fmadd_s = 0x81U << 20, + op_fmadd_d = 0x82U << 20, + op_fmsub_s = 0x85U << 20, + op_fmsub_d = 0x86U << 20, + op_fnmadd_s = 0x89U << 20, + op_fnmadd_d = 0x8aU << 20, + op_fnmsub_s = 0x8dU << 20, + op_fnmsub_d = 0x8eU << 20, + op_fcmp_cond_s = 0xc1U << 20, + op_fcmp_cond_d = 0xc2U << 20, + + op_bytepick_d = 0x3U << 18, + op_fsel = 0x340U << 18, + + op_bytepick_w = 0x4U << 17, + op_alsl_w = 0x2U << 17, + op_alsl_wu = 0x3U << 17, + op_alsl_d = 0x16U << 17, + + op_slli_d = 0x41U << 16, + op_srli_d = 0x45U << 16, + op_srai_d = 0x49U << 16, + + op_slli_w = 0x81U << 15, + op_srli_w = 0x89U << 15, + op_srai_w = 0x91U << 15, + op_add_w = 0x20U << 15, + op_add_d = 0x21U << 15, + op_sub_w = 0x22U << 15, + op_sub_d = 0x23U << 15, + op_slt = 0x24U << 15, + op_sltu = 0x25U << 15, + op_maskeqz = 0x26U << 15, + op_masknez = 0x27U << 15, + op_nor = 0x28U << 15, + op_and = 0x29U << 15, + op_or = 0x2aU << 15, + op_xor = 0x2bU << 15, + op_orn = 0x2cU << 15, + op_andn = 0x2dU << 15, + op_sll_w = 0x2eU << 15, + op_srl_w = 0x2fU << 15, + op_sra_w = 0x30U << 15, + op_sll_d = 0x31U << 15, + op_srl_d = 0x32U << 15, + op_sra_d = 0x33U << 15, + op_rotr_w = 0x36U << 15, + op_rotr_d = 0x37U << 15, + op_rotri_w = 0x99U << 15, + op_rotri_d = 0x4DU << 16, + op_mul_w = 0x38U << 15, + op_mulh_w = 0x39U << 15, + op_mulh_wu = 0x3aU << 15, + op_mul_d = 0x3bU << 15, + op_mulh_d = 0x3cU << 15, + op_mulh_du = 0x3dU << 15, + op_mulw_d_w = 0x3eU << 15, + op_mulw_d_wu = 0x3fU << 15, + op_div_w = 0x40U << 15, + op_mod_w = 0x41U << 15, + op_div_wu = 0x42U << 15, + op_mod_wu = 0x43U << 15, + op_div_d = 0x44U << 15, + op_mod_d = 0x45U << 15, + op_div_du = 0x46U << 15, + op_mod_du = 0x47U << 15, + op_break = 0x54U << 15, + op_syscall = 0x56U << 15, + op_fadd_s = 0x201U << 15, + op_fadd_d = 0x202U << 15, + op_fsub_s = 0x205U << 15, + op_fsub_d = 0x206U << 15, + op_fmul_s = 0x209U << 15, + op_fmul_d = 0x20aU << 15, + op_fdiv_s = 0x20dU << 15, + op_fdiv_d = 0x20eU << 15, + op_fmax_s = 0x211U << 15, + op_fmax_d = 0x212U << 15, + op_fmin_s = 0x215U << 15, + op_fmin_d = 0x216U << 15, + op_fmaxa_s = 0x219U << 15, + op_fmaxa_d = 0x21aU << 15, + op_fmina_s = 0x21dU << 15, + op_fmina_d = 0x21eU << 15, + op_fcopysign_s = 0x225U << 15, + op_fcopysign_d = 0x226U << 15, + op_ldx_b = 0x7000U << 15, + op_ldx_h = 0x7008U << 15, + op_ldx_w = 0x7010U << 15, + op_ldx_d = 0x7018U << 15, + op_stx_b = 0x7020U << 15, + op_stx_h = 0x7028U << 15, + op_stx_w = 0x7030U << 15, + op_stx_d = 0x7038U << 15, + op_ldx_bu = 0x7040U << 15, + op_ldx_hu = 0x7048U << 15, + op_ldx_wu = 0x7050U << 15, + op_fldx_s = 0x7060U << 15, + op_fldx_d = 0x7068U << 15, + op_fstx_s = 0x7070U << 15, + op_fstx_d = 0x7078U << 15, + op_amswap_w = 0x70c0U << 15, + op_amswap_d = 0x70c1U << 15, + op_amadd_w = 0x70c2U << 15, + op_amadd_d = 0x70c3U << 15, + op_amand_w = 0x70c4U << 15, + op_amand_d = 0x70c5U << 15, + op_amor_w = 0x70c6U << 15, + op_amor_d = 0x70c7U << 15, + op_amxor_w = 0x70c8U << 15, + op_amxor_d = 0x70c9U << 15, + op_ammax_w = 0x70caU << 15, + op_ammax_d = 0x70cbU << 15, + op_ammin_w = 0x70ccU << 15, + op_ammin_d = 0x70cdU << 15, + op_ammax_wu = 0x70ceU << 15, + op_ammax_du = 0x70cfU << 15, + op_ammin_wu = 0x70d0U << 15, + op_ammin_du = 0x70d1U << 15, + op_amswap_db_w = 0x70d2U << 15, + op_amswap_db_d = 0x70d3U << 15, + op_amadd_db_w = 0x70d4U << 15, + op_amadd_db_d = 0x70d5U << 15, + op_amand_db_w = 0x70d6U << 15, + op_amand_db_d = 0x70d7U << 15, + op_amor_db_w = 0x70d8U << 15, + op_amor_db_d = 0x70d9U << 15, + op_amxor_db_w = 0x70daU << 15, + op_amxor_db_d = 0x70dbU << 15, + op_ammax_db_w = 0x70dcU << 15, + op_ammax_db_d = 0x70ddU << 15, + op_ammin_db_w = 0x70deU << 15, + op_ammin_db_d = 0x70dfU << 15, + op_ammax_db_wu = 0x70e0U << 15, + op_ammax_db_du = 0x70e1U << 15, + op_ammin_db_wu = 0x70e2U << 15, + op_ammin_db_du = 0x70e3U << 15, + op_dbar = 0x70e4U << 15, + op_ibar = 0x70e5U << 15, + op_clo_w = 0x4U << 10, + op_clz_w = 0x5U << 10, + op_cto_w = 0x6U << 10, + op_ctz_w = 0x7U << 10, + op_clo_d = 0x8U << 10, + op_clz_d = 0x9U << 10, + op_cto_d = 0xaU << 10, + op_ctz_d = 0xbU << 10, + op_revb_2h = 0xcU << 10, + op_revb_4h = 0xdU << 10, + op_revb_2w = 0xeU << 10, + op_revb_d = 0xfU << 10, + op_revh_2w = 0x10U << 10, + op_revh_d = 0x11U << 10, + op_bitrev_4b = 0x12U << 10, + op_bitrev_8b = 0x13U << 10, + op_bitrev_w = 0x14U << 10, + op_bitrev_d = 0x15U << 10, + op_ext_w_h = 0x16U << 10, + op_ext_w_b = 0x17U << 10, + op_fabs_s = 0x4501U << 10, + op_fabs_d = 0x4502U << 10, + op_fneg_s = 0x4505U << 10, + op_fneg_d = 0x4506U << 10, + op_fsqrt_s = 0x4511U << 10, + op_fsqrt_d = 0x4512U << 10, + op_fmov_s = 0x4525U << 10, + op_fmov_d = 0x4526U << 10, + op_movgr2fr_w = 0x4529U << 10, + op_movgr2fr_d = 0x452aU << 10, + op_movgr2frh_w = 0x452bU << 10, + op_movfr2gr_s = 0x452dU << 10, + op_movfr2gr_d = 0x452eU << 10, + op_movfrh2gr_s = 0x452fU << 10, + op_movgr2fcsr = 0x4530U << 10, + op_movfcsr2gr = 0x4532U << 10, + op_movfr2cf = 0x4534U << 10, + op_movgr2cf = 0x4536U << 10, + op_fcvt_s_d = 0x4646U << 10, + op_fcvt_d_s = 0x4649U << 10, + op_ftintrm_w_s = 0x4681U << 10, + op_ftintrm_w_d = 0x4682U << 10, + op_ftintrm_l_s = 0x4689U << 10, + op_ftintrm_l_d = 0x468aU << 10, + op_ftintrp_w_s = 0x4691U << 10, + op_ftintrp_w_d = 0x4692U << 10, + op_ftintrp_l_s = 0x4699U << 10, + op_ftintrp_l_d = 0x469aU << 10, + op_ftintrz_w_s = 0x46a1U << 10, + op_ftintrz_w_d = 0x46a2U << 10, + op_ftintrz_l_s = 0x46a9U << 10, + op_ftintrz_l_d = 0x46aaU << 10, + op_ftintrne_w_s = 0x46b1U << 10, + op_ftintrne_w_d = 0x46b2U << 10, + op_ftintrne_l_s = 0x46b9U << 10, + op_ftintrne_l_d = 0x46baU << 10, + op_ftint_w_s = 0x46c1U << 10, + op_ftint_w_d = 0x46c2U << 10, + op_ftint_l_s = 0x46c9U << 10, + op_ftint_l_d = 0x46caU << 10, + op_ffint_s_w = 0x4744U << 10, + op_ffint_s_l = 0x4746U << 10, + op_ffint_d_w = 0x4748U << 10, + op_ffint_d_l = 0x474aU << 10, + op_frint_s = 0x4791U << 10, + op_frint_d = 0x4792U << 10, + op_movcf2fr = 0x114d4U << 8, + op_movcf2gr = 0x114dcU << 8, +}; + +class Operand; + +// A BOffImm16 is a 16 bit immediate that is used for branches. +class BOffImm16 { + uint32_t data; + + public: + uint32_t encode() { + MOZ_ASSERT(!isInvalid()); + return data; + } + int32_t decode() { + MOZ_ASSERT(!isInvalid()); + return (int32_t(data << 18) >> 16); + } + + explicit BOffImm16(int offset) : data((offset) >> 2 & Imm16Mask) { + MOZ_ASSERT((offset & 0x3) == 0); + MOZ_ASSERT(IsInRange(offset)); + } + static bool IsInRange(int offset) { + if ((offset) < int(unsigned(INT16_MIN) << 2)) { + return false; + } + if ((offset) > (INT16_MAX << 2)) { + return false; + } + return true; + } + static const uint32_t INVALID = 0x00020000; + BOffImm16() : data(INVALID) {} + + bool isInvalid() { return data == INVALID; } + Instruction* getDest(Instruction* src) const; + + BOffImm16(InstImm inst); +}; + +// A JOffImm26 is a 26 bit immediate that is used for unconditional jumps. +class JOffImm26 { + uint32_t data; + + public: + uint32_t encode() { + MOZ_ASSERT(!isInvalid()); + return data; + } + int32_t decode() { + MOZ_ASSERT(!isInvalid()); + return (int32_t(data << 8) >> 6); + } + + explicit JOffImm26(int offset) : data((offset) >> 2 & Imm26Mask) { + MOZ_ASSERT((offset & 0x3) == 0); + MOZ_ASSERT(IsInRange(offset)); + } + static bool IsInRange(int offset) { + if ((offset) < -536870912) { + return false; + } + if ((offset) > 536870908) { + return false; + } + return true; + } + static const uint32_t INVALID = 0x20000000; + JOffImm26() : data(INVALID) {} + + bool isInvalid() { return data == INVALID; } + Instruction* getDest(Instruction* src); +}; + +class Imm16 { + uint16_t value; + + public: + Imm16(); + Imm16(uint32_t imm) : value(imm) {} + uint32_t encode() { return value; } + int32_t decodeSigned() { return value; } + uint32_t decodeUnsigned() { return value; } + + static bool IsInSignedRange(int32_t imm) { + return imm >= INT16_MIN && imm <= INT16_MAX; + } + + static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT16_MAX; } +}; + +class Imm8 { + uint8_t value; + + public: + Imm8(); + Imm8(uint32_t imm) : value(imm) {} + uint32_t encode(uint32_t shift) { return value << shift; } + int32_t decodeSigned() { return value; } + uint32_t decodeUnsigned() { return value; } + static bool IsInSignedRange(int32_t imm) { + return imm >= INT8_MIN && imm <= INT8_MAX; + } + static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT8_MAX; } + static Imm8 Lower(Imm16 imm) { return Imm8(imm.decodeSigned() & 0xff); } + static Imm8 Upper(Imm16 imm) { + return Imm8((imm.decodeSigned() >> 8) & 0xff); + } +}; + +class Operand { + public: + enum Tag { REG, FREG, MEM }; + + private: + Tag tag : 3; + uint32_t reg : 5; + int32_t offset; + + public: + Operand(Register reg_) : tag(REG), reg(reg_.code()) {} + + Operand(FloatRegister freg) : tag(FREG), reg(freg.code()) {} + + Operand(Register base, Imm32 off) + : tag(MEM), reg(base.code()), offset(off.value) {} + + Operand(Register base, int32_t off) + : tag(MEM), reg(base.code()), offset(off) {} + + Operand(const Address& addr) + : tag(MEM), reg(addr.base.code()), offset(addr.offset) {} + + Tag getTag() const { return tag; } + + Register toReg() const { + MOZ_ASSERT(tag == REG); + return Register::FromCode(reg); + } + + FloatRegister toFReg() const { + MOZ_ASSERT(tag == FREG); + return FloatRegister::FromCode(reg); + } + + void toAddr(Register* r, Imm32* dest) const { + MOZ_ASSERT(tag == MEM); + *r = Register::FromCode(reg); + *dest = Imm32(offset); + } + Address toAddress() const { + MOZ_ASSERT(tag == MEM); + return Address(Register::FromCode(reg), offset); + } + int32_t disp() const { + MOZ_ASSERT(tag == MEM); + return offset; + } + + int32_t base() const { + MOZ_ASSERT(tag == MEM); + return reg; + } + Register baseReg() const { + MOZ_ASSERT(tag == MEM); + return Register::FromCode(reg); + } +}; + +// int check. +inline bool is_intN(int32_t x, unsigned n) { + MOZ_ASSERT((0 < n) && (n < 64)); + int32_t limit = static_cast(1) << (n - 1); + return (-limit <= x) && (x < limit); +} + +inline bool is_uintN(int32_t x, unsigned n) { + MOZ_ASSERT((0 < n) && (n < (sizeof(x) * 8))); + return !(x >> n); +} + +inline Imm32 Imm64::firstHalf() const { return low(); } + +inline Imm32 Imm64::secondHalf() const { return hi(); } + +static constexpr int32_t SliceSize = 1024; +typedef js::jit::AssemblerBuffer LOONGBuffer; + +class LOONGBufferWithExecutableCopy : public LOONGBuffer { + public: + void executableCopy(uint8_t* buffer) { + if (this->oom()) { + return; + } + + for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) { + memcpy(buffer, &cur->instructions, cur->length()); + buffer += cur->length(); + } + } + + bool appendBuffer(const LOONGBufferWithExecutableCopy& other) { + if (this->oom() || other.oom()) { + return false; + } + + for (Slice* cur = other.head; cur != nullptr; cur = cur->getNext()) { + if (!appendRawCode(cur->instructions.begin(), cur->length())) { + return false; + } + } + return !this->oom(); + } + + bool appendRawCode(const uint8_t* code, size_t numBytes) { + if (this->oom()) { + return false; + } + while (numBytes > SliceSize) { + this->putBytes(SliceSize, code); + numBytes -= SliceSize; + code += SliceSize; + } + this->putBytes(numBytes, code); + return !this->oom(); + } +}; + +class AssemblerLOONGARCH64 : public AssemblerShared { + public: + // TODO(loongarch64): Should we remove these conditions here? + enum Condition { + Equal, + NotEqual, + Above, + AboveOrEqual, + Below, + BelowOrEqual, + GreaterThan, + GreaterThanOrEqual, + GreaterThanOrEqual_Signed, + GreaterThanOrEqual_NotSigned, + LessThan, + LessThan_Signed, + LessThan_NotSigned, + LessThanOrEqual, + Overflow, + CarrySet, + CarryClear, + Signed, + NotSigned, + Zero, + NonZero, + Always, + }; + + enum DoubleCondition { + DoubleOrdered, + DoubleEqual, + DoubleNotEqual, + DoubleGreaterThan, + DoubleGreaterThanOrEqual, + DoubleLessThan, + DoubleLessThanOrEqual, + DoubleUnordered, + DoubleEqualOrUnordered, + DoubleNotEqualOrUnordered, + DoubleGreaterThanOrUnordered, + DoubleGreaterThanOrEqualOrUnordered, + DoubleLessThanOrUnordered, + DoubleLessThanOrEqualOrUnordered + }; + + enum FPUCondition { + kNoFPUCondition = -1, + + CAF = 0x00, + SAF = 0x01, + CLT = 0x02, + SLT = 0x03, + CEQ = 0x04, + SEQ = 0x05, + CLE = 0x06, + SLE = 0x07, + CUN = 0x08, + SUN = 0x09, + CULT = 0x0a, + SULT = 0x0b, + CUEQ = 0x0c, + SUEQ = 0x0d, + CULE = 0x0e, + SULE = 0x0f, + CNE = 0x10, + SNE = 0x11, + COR = 0x14, + SOR = 0x15, + CUNE = 0x18, + SUNE = 0x19, + }; + + enum FPConditionBit { FCC0 = 0, FCC1, FFC2, FCC3, FCC4, FCC5, FCC6, FCC7 }; + + enum FPControl { FCSR = 0 }; + + enum FCSRBit { CauseI = 24, CauseU, CauseO, CauseZ, CauseV }; + + enum FloatFormat { SingleFloat, DoubleFloat }; + + enum JumpOrCall { BranchIsJump, BranchIsCall }; + + enum FloatTestKind { TestForTrue, TestForFalse }; + + // :( this should be protected, but since CodeGenerator + // wants to use it, It needs to go out here :( + + BufferOffset nextOffset() { return m_buffer.nextOffset(); } + + protected: + Instruction* editSrc(BufferOffset bo) { return m_buffer.getInst(bo); } + + // structure for fixing up pc-relative loads/jumps when a the machine code + // gets moved (executable copy, gc, etc.) + struct RelativePatch { + // the offset within the code buffer where the value is loaded that + // we want to fix-up + BufferOffset offset; + void* target; + Relocation::Kind kind; + + RelativePatch(BufferOffset offset, void* target, Relocation::Kind kind) + : offset(offset), target(target), kind(kind) {} + }; + + js::Vector jumps_; + + CompactBufferWriter jumpRelocations_; + CompactBufferWriter dataRelocations_; + CompactBufferWriter preBarriers_; + + LOONGBufferWithExecutableCopy m_buffer; + +#ifdef JS_JITSPEW + Sprinter* printer; +#endif + + public: + AssemblerLOONGARCH64() + : m_buffer(), +#ifdef JS_JITSPEW + printer(nullptr), +#endif + isFinished(false) { + } + + static Condition InvertCondition(Condition cond); + static DoubleCondition InvertCondition(DoubleCondition cond); + // This is changing the condition codes for cmp a, b to the same codes for cmp + // b, a. + static Condition InvertCmpCondition(Condition cond); + + // As opposed to x86/x64 version, the data relocation has to be executed + // before to recover the pointer, and not after. + void writeDataRelocation(ImmGCPtr ptr) { + // Raw GC pointer relocations and Value relocations both end up in + // TraceOneDataRelocation. + if (ptr.value) { + if (gc::IsInsideNursery(ptr.value)) { + embedsNurseryPointers_ = true; + } + dataRelocations_.writeUnsigned(nextOffset().getOffset()); + } + } + + void writePrebarrierOffset(CodeOffset label) { + preBarriers_.writeUnsigned(label.offset()); + } + + void assertNoGCThings() const { +#ifdef DEBUG + MOZ_ASSERT(dataRelocations_.length() == 0); + for (auto& j : jumps_) { + MOZ_ASSERT(j.kind == Relocation::HARDCODED); + } +#endif + } + + public: + void setUnlimitedBuffer() {} + bool oom() const; + bool bailed() const { return m_buffer.bail(); } + + void setPrinter(Sprinter* sp) { +#ifdef JS_JITSPEW + printer = sp; +#endif + } + +#ifdef JS_JITSPEW + inline void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) { + if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) { + va_list va; + va_start(va, fmt); + spew(fmt, va); + va_end(va); + } + } + + void decodeBranchInstAndSpew(InstImm branch); +#else + MOZ_ALWAYS_INLINE void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {} +#endif + +#ifdef JS_JITSPEW + MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0) { + // Buffer to hold the formatted string. Note that this may contain + // '%' characters, so do not pass it directly to printf functions. + char buf[200]; + + int i = VsprintfLiteral(buf, fmt, va); + if (i > -1) { + if (printer) { + printer->printf("%s\n", buf); + } + js::jit::JitSpew(js::jit::JitSpew_Codegen, "%s", buf); + } + } +#endif + + Register getStackPointer() const { return StackPointer; } + + protected: + bool isFinished; + + public: + void finish(); + bool appendRawCode(const uint8_t* code, size_t numBytes); + bool reserve(size_t size); + bool swapBuffer(wasm::Bytes& bytes); + void executableCopy(void* buffer); + void copyJumpRelocationTable(uint8_t* dest); + void copyDataRelocationTable(uint8_t* dest); + void copyPreBarrierTable(uint8_t* dest); + + // Size of the instruction stream, in bytes. + size_t size() const; + // Size of the jump relocation table, in bytes. + size_t jumpRelocationTableBytes() const; + size_t dataRelocationTableBytes() const; + size_t preBarrierTableBytes() const; + + // Size of the data table, in bytes. + size_t bytesNeeded() const; + + // Write a blob of binary into the instruction stream *OR* + // into a destination address. If dest is nullptr (the default), then the + // instruction gets written into the instruction stream. If dest is not null + // it is interpreted as a pointer to the location that we want the + // instruction to be written. + BufferOffset writeInst(uint32_t x, uint32_t* dest = nullptr); + // A static variant for the cases where we don't want to have an assembler + // object at all. Normally, you would use the dummy (nullptr) object. + static void WriteInstStatic(uint32_t x, uint32_t* dest); + + public: + BufferOffset haltingAlign(int alignment); + BufferOffset nopAlign(int alignment); + BufferOffset as_nop() { return as_andi(zero, zero, 0); } + + // Branch and jump instructions + BufferOffset as_b(JOffImm26 off); + BufferOffset as_bl(JOffImm26 off); + BufferOffset as_jirl(Register rd, Register rj, BOffImm16 off); + + InstImm getBranchCode(JumpOrCall jumpOrCall); // b, bl + InstImm getBranchCode(Register rd, Register rj, + Condition c); // beq, bne, bge, bgeu, blt, bltu + InstImm getBranchCode(Register rj, Condition c); // beqz, bnez + InstImm getBranchCode(FPConditionBit cj); // bceqz, bcnez + + // Arithmetic instructions + BufferOffset as_add_w(Register rd, Register rj, Register rk); + BufferOffset as_add_d(Register rd, Register rj, Register rk); + BufferOffset as_sub_w(Register rd, Register rj, Register rk); + BufferOffset as_sub_d(Register rd, Register rj, Register rk); + + BufferOffset as_addi_w(Register rd, Register rj, int32_t si12); + BufferOffset as_addi_d(Register rd, Register rj, int32_t si12); + BufferOffset as_addu16i_d(Register rd, Register rj, int32_t si16); + + BufferOffset as_alsl_w(Register rd, Register rj, Register rk, uint32_t sa2); + BufferOffset as_alsl_wu(Register rd, Register rj, Register rk, uint32_t sa2); + BufferOffset as_alsl_d(Register rd, Register rj, Register rk, uint32_t sa2); + + BufferOffset as_lu12i_w(Register rd, int32_t si20); + BufferOffset as_lu32i_d(Register rd, int32_t si20); + BufferOffset as_lu52i_d(Register rd, Register rj, int32_t si12); + + BufferOffset as_slt(Register rd, Register rj, Register rk); + BufferOffset as_sltu(Register rd, Register rj, Register rk); + BufferOffset as_slti(Register rd, Register rj, int32_t si12); + BufferOffset as_sltui(Register rd, Register rj, int32_t si12); + + BufferOffset as_pcaddi(Register rd, int32_t si20); + BufferOffset as_pcaddu12i(Register rd, int32_t si20); + BufferOffset as_pcaddu18i(Register rd, int32_t si20); + BufferOffset as_pcalau12i(Register rd, int32_t si20); + + BufferOffset as_mul_w(Register rd, Register rj, Register rk); + BufferOffset as_mulh_w(Register rd, Register rj, Register rk); + BufferOffset as_mulh_wu(Register rd, Register rj, Register rk); + BufferOffset as_mul_d(Register rd, Register rj, Register rk); + BufferOffset as_mulh_d(Register rd, Register rj, Register rk); + BufferOffset as_mulh_du(Register rd, Register rj, Register rk); + + BufferOffset as_mulw_d_w(Register rd, Register rj, Register rk); + BufferOffset as_mulw_d_wu(Register rd, Register rj, Register rk); + + BufferOffset as_div_w(Register rd, Register rj, Register rk); + BufferOffset as_mod_w(Register rd, Register rj, Register rk); + BufferOffset as_div_wu(Register rd, Register rj, Register rk); + BufferOffset as_mod_wu(Register rd, Register rj, Register rk); + BufferOffset as_div_d(Register rd, Register rj, Register rk); + BufferOffset as_mod_d(Register rd, Register rj, Register rk); + BufferOffset as_div_du(Register rd, Register rj, Register rk); + BufferOffset as_mod_du(Register rd, Register rj, Register rk); + + // Logical instructions + BufferOffset as_and(Register rd, Register rj, Register rk); + BufferOffset as_or(Register rd, Register rj, Register rk); + BufferOffset as_xor(Register rd, Register rj, Register rk); + BufferOffset as_nor(Register rd, Register rj, Register rk); + BufferOffset as_andn(Register rd, Register rj, Register rk); + BufferOffset as_orn(Register rd, Register rj, Register rk); + + BufferOffset as_andi(Register rd, Register rj, int32_t ui12); + BufferOffset as_ori(Register rd, Register rj, int32_t ui12); + BufferOffset as_xori(Register rd, Register rj, int32_t ui12); + + // Shift instructions + BufferOffset as_sll_w(Register rd, Register rj, Register rk); + BufferOffset as_srl_w(Register rd, Register rj, Register rk); + BufferOffset as_sra_w(Register rd, Register rj, Register rk); + BufferOffset as_rotr_w(Register rd, Register rj, Register rk); + + BufferOffset as_slli_w(Register rd, Register rj, int32_t ui5); + BufferOffset as_srli_w(Register rd, Register rj, int32_t ui5); + BufferOffset as_srai_w(Register rd, Register rj, int32_t ui5); + BufferOffset as_rotri_w(Register rd, Register rj, int32_t ui5); + + BufferOffset as_sll_d(Register rd, Register rj, Register rk); + BufferOffset as_srl_d(Register rd, Register rj, Register rk); + BufferOffset as_sra_d(Register rd, Register rj, Register rk); + BufferOffset as_rotr_d(Register rd, Register rj, Register rk); + + BufferOffset as_slli_d(Register rd, Register rj, int32_t ui6); + BufferOffset as_srli_d(Register rd, Register rj, int32_t ui6); + BufferOffset as_srai_d(Register rd, Register rj, int32_t ui6); + BufferOffset as_rotri_d(Register rd, Register rj, int32_t ui6); + + // Bit operation instrucitons + BufferOffset as_ext_w_b(Register rd, Register rj); + BufferOffset as_ext_w_h(Register rd, Register rj); + + BufferOffset as_clo_w(Register rd, Register rj); + BufferOffset as_clz_w(Register rd, Register rj); + BufferOffset as_cto_w(Register rd, Register rj); + BufferOffset as_ctz_w(Register rd, Register rj); + BufferOffset as_clo_d(Register rd, Register rj); + BufferOffset as_clz_d(Register rd, Register rj); + BufferOffset as_cto_d(Register rd, Register rj); + BufferOffset as_ctz_d(Register rd, Register rj); + + BufferOffset as_bytepick_w(Register rd, Register rj, Register rk, + int32_t sa2); + BufferOffset as_bytepick_d(Register rd, Register rj, Register rk, + int32_t sa3); + + BufferOffset as_revb_2h(Register rd, Register rj); + BufferOffset as_revb_4h(Register rd, Register rj); + BufferOffset as_revb_2w(Register rd, Register rj); + BufferOffset as_revb_d(Register rd, Register rj); + + BufferOffset as_revh_2w(Register rd, Register rj); + BufferOffset as_revh_d(Register rd, Register rj); + + BufferOffset as_bitrev_4b(Register rd, Register rj); + BufferOffset as_bitrev_8b(Register rd, Register rj); + + BufferOffset as_bitrev_w(Register rd, Register rj); + BufferOffset as_bitrev_d(Register rd, Register rj); + + BufferOffset as_bstrins_w(Register rd, Register rj, int32_t msbw, + int32_t lsbw); + BufferOffset as_bstrins_d(Register rd, Register rj, int32_t msbd, + int32_t lsbd); + BufferOffset as_bstrpick_w(Register rd, Register rj, int32_t msbw, + int32_t lsbw); + BufferOffset as_bstrpick_d(Register rd, Register rj, int32_t msbd, + int32_t lsbd); + + BufferOffset as_maskeqz(Register rd, Register rj, Register rk); + BufferOffset as_masknez(Register rd, Register rj, Register rk); + + // Load and store instructions + BufferOffset as_ld_b(Register rd, Register rj, int32_t si12); + BufferOffset as_ld_h(Register rd, Register rj, int32_t si12); + BufferOffset as_ld_w(Register rd, Register rj, int32_t si12); + BufferOffset as_ld_d(Register rd, Register rj, int32_t si12); + BufferOffset as_ld_bu(Register rd, Register rj, int32_t si12); + BufferOffset as_ld_hu(Register rd, Register rj, int32_t si12); + BufferOffset as_ld_wu(Register rd, Register rj, int32_t si12); + BufferOffset as_st_b(Register rd, Register rj, int32_t si12); + BufferOffset as_st_h(Register rd, Register rj, int32_t si12); + BufferOffset as_st_w(Register rd, Register rj, int32_t si12); + BufferOffset as_st_d(Register rd, Register rj, int32_t si12); + + BufferOffset as_ldx_b(Register rd, Register rj, Register rk); + BufferOffset as_ldx_h(Register rd, Register rj, Register rk); + BufferOffset as_ldx_w(Register rd, Register rj, Register rk); + BufferOffset as_ldx_d(Register rd, Register rj, Register rk); + BufferOffset as_ldx_bu(Register rd, Register rj, Register rk); + BufferOffset as_ldx_hu(Register rd, Register rj, Register rk); + BufferOffset as_ldx_wu(Register rd, Register rj, Register rk); + BufferOffset as_stx_b(Register rd, Register rj, Register rk); + BufferOffset as_stx_h(Register rd, Register rj, Register rk); + BufferOffset as_stx_w(Register rd, Register rj, Register rk); + BufferOffset as_stx_d(Register rd, Register rj, Register rk); + + BufferOffset as_ldptr_w(Register rd, Register rj, int32_t si14); + BufferOffset as_ldptr_d(Register rd, Register rj, int32_t si14); + BufferOffset as_stptr_w(Register rd, Register rj, int32_t si14); + BufferOffset as_stptr_d(Register rd, Register rj, int32_t si14); + + BufferOffset as_preld(int32_t hint, Register rj, int32_t si12); + + // Atomic instructions + BufferOffset as_amswap_w(Register rd, Register rj, Register rk); + BufferOffset as_amswap_d(Register rd, Register rj, Register rk); + BufferOffset as_amadd_w(Register rd, Register rj, Register rk); + BufferOffset as_amadd_d(Register rd, Register rj, Register rk); + BufferOffset as_amand_w(Register rd, Register rj, Register rk); + BufferOffset as_amand_d(Register rd, Register rj, Register rk); + BufferOffset as_amor_w(Register rd, Register rj, Register rk); + BufferOffset as_amor_d(Register rd, Register rj, Register rk); + BufferOffset as_amxor_w(Register rd, Register rj, Register rk); + BufferOffset as_amxor_d(Register rd, Register rj, Register rk); + BufferOffset as_ammax_w(Register rd, Register rj, Register rk); + BufferOffset as_ammax_d(Register rd, Register rj, Register rk); + BufferOffset as_ammin_w(Register rd, Register rj, Register rk); + BufferOffset as_ammin_d(Register rd, Register rj, Register rk); + BufferOffset as_ammax_wu(Register rd, Register rj, Register rk); + BufferOffset as_ammax_du(Register rd, Register rj, Register rk); + BufferOffset as_ammin_wu(Register rd, Register rj, Register rk); + BufferOffset as_ammin_du(Register rd, Register rj, Register rk); + + BufferOffset as_amswap_db_w(Register rd, Register rj, Register rk); + BufferOffset as_amswap_db_d(Register rd, Register rj, Register rk); + BufferOffset as_amadd_db_w(Register rd, Register rj, Register rk); + BufferOffset as_amadd_db_d(Register rd, Register rj, Register rk); + BufferOffset as_amand_db_w(Register rd, Register rj, Register rk); + BufferOffset as_amand_db_d(Register rd, Register rj, Register rk); + BufferOffset as_amor_db_w(Register rd, Register rj, Register rk); + BufferOffset as_amor_db_d(Register rd, Register rj, Register rk); + BufferOffset as_amxor_db_w(Register rd, Register rj, Register rk); + BufferOffset as_amxor_db_d(Register rd, Register rj, Register rk); + BufferOffset as_ammax_db_w(Register rd, Register rj, Register rk); + BufferOffset as_ammax_db_d(Register rd, Register rj, Register rk); + BufferOffset as_ammin_db_w(Register rd, Register rj, Register rk); + BufferOffset as_ammin_db_d(Register rd, Register rj, Register rk); + BufferOffset as_ammax_db_wu(Register rd, Register rj, Register rk); + BufferOffset as_ammax_db_du(Register rd, Register rj, Register rk); + BufferOffset as_ammin_db_wu(Register rd, Register rj, Register rk); + BufferOffset as_ammin_db_du(Register rd, Register rj, Register rk); + + BufferOffset as_ll_w(Register rd, Register rj, int32_t si14); + BufferOffset as_ll_d(Register rd, Register rj, int32_t si14); + BufferOffset as_sc_w(Register rd, Register rj, int32_t si14); + BufferOffset as_sc_d(Register rd, Register rj, int32_t si14); + + // Barrier instructions + BufferOffset as_dbar(int32_t hint); + BufferOffset as_ibar(int32_t hint); + + // FP Arithmetic instructions + BufferOffset as_fadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fmul_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fmul_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fdiv_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fdiv_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); + + BufferOffset as_fmadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FloatRegister fa); + BufferOffset as_fmadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FloatRegister fa); + BufferOffset as_fmsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FloatRegister fa); + BufferOffset as_fmsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FloatRegister fa); + BufferOffset as_fnmadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FloatRegister fa); + BufferOffset as_fnmadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FloatRegister fa); + BufferOffset as_fnmsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FloatRegister fa); + BufferOffset as_fnmsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FloatRegister fa); + + BufferOffset as_fmax_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fmax_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fmin_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fmin_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); + + BufferOffset as_fmaxa_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fmaxa_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fmina_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); + BufferOffset as_fmina_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); + + BufferOffset as_fabs_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_fabs_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_fneg_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_fneg_d(FloatRegister fd, FloatRegister fj); + + BufferOffset as_fsqrt_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_fsqrt_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_fcopysign_s(FloatRegister fd, FloatRegister fj, + FloatRegister fk); + BufferOffset as_fcopysign_d(FloatRegister fd, FloatRegister fj, + FloatRegister fk); + + // FP compare instructions (fcmp.cond.s fcmp.cond.d) + BufferOffset as_fcmp_cor(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_ceq(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_cne(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_cle(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_clt(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_cun(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_cueq(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_cune(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_cule(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + BufferOffset as_fcmp_cult(FloatFormat fmt, FloatRegister fj, FloatRegister fk, + FPConditionBit cd); + + // FP conversion instructions + BufferOffset as_fcvt_s_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_fcvt_d_s(FloatRegister fd, FloatRegister fj); + + BufferOffset as_ffint_s_w(FloatRegister fd, FloatRegister fj); + BufferOffset as_ffint_s_l(FloatRegister fd, FloatRegister fj); + BufferOffset as_ffint_d_w(FloatRegister fd, FloatRegister fj); + BufferOffset as_ffint_d_l(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftint_w_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftint_w_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftint_l_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftint_l_d(FloatRegister fd, FloatRegister fj); + + BufferOffset as_ftintrm_w_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrm_w_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrm_l_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrm_l_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrp_w_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrp_w_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrp_l_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrp_l_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrz_w_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrz_w_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrz_l_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrz_l_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrne_w_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrne_w_d(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrne_l_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_ftintrne_l_d(FloatRegister fd, FloatRegister fj); + + BufferOffset as_frint_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_frint_d(FloatRegister fd, FloatRegister fj); + + // FP mov instructions + BufferOffset as_fmov_s(FloatRegister fd, FloatRegister fj); + BufferOffset as_fmov_d(FloatRegister fd, FloatRegister fj); + + BufferOffset as_fsel(FloatRegister fd, FloatRegister fj, FloatRegister fk, + FPConditionBit ca); + + BufferOffset as_movgr2fr_w(FloatRegister fd, Register rj); + BufferOffset as_movgr2fr_d(FloatRegister fd, Register rj); + BufferOffset as_movgr2frh_w(FloatRegister fd, Register rj); + + BufferOffset as_movfr2gr_s(Register rd, FloatRegister fj); + BufferOffset as_movfr2gr_d(Register rd, FloatRegister fj); + BufferOffset as_movfrh2gr_s(Register rd, FloatRegister fj); + + BufferOffset as_movgr2fcsr(Register rj); + BufferOffset as_movfcsr2gr(Register rd); + + BufferOffset as_movfr2cf(FPConditionBit cd, FloatRegister fj); + BufferOffset as_movcf2fr(FloatRegister fd, FPConditionBit cj); + + BufferOffset as_movgr2cf(FPConditionBit cd, Register rj); + BufferOffset as_movcf2gr(Register rd, FPConditionBit cj); + + // FP load/store instructions + BufferOffset as_fld_s(FloatRegister fd, Register rj, int32_t si12); + BufferOffset as_fld_d(FloatRegister fd, Register rj, int32_t si12); + BufferOffset as_fst_s(FloatRegister fd, Register rj, int32_t si12); + BufferOffset as_fst_d(FloatRegister fd, Register rj, int32_t si12); + + BufferOffset as_fldx_s(FloatRegister fd, Register rj, Register rk); + BufferOffset as_fldx_d(FloatRegister fd, Register rj, Register rk); + BufferOffset as_fstx_s(FloatRegister fd, Register rj, Register rk); + BufferOffset as_fstx_d(FloatRegister fd, Register rj, Register rk); + + // label operations + void bind(Label* label, BufferOffset boff = BufferOffset()); + virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0; + void bind(CodeOffset* label) { label->bind(currentOffset()); } + void bind(CodeLabel* label) { label->target()->bind(currentOffset()); } + uint32_t currentOffset() { return nextOffset().getOffset(); } + void retarget(Label* label, Label* target); + + void call(Label* label); + void call(void* target); + + void as_break(uint32_t code); + + public: + static bool SupportsFloatingPoint() { +#if defined(__loongarch_hard_float) || defined(JS_SIMULATOR_LOONGARCH64) + return true; +#else + return false; +#endif + } + static bool SupportsSimd() { return false; } + static bool SupportsUnalignedAccesses() { return true; } + static bool SupportsFastUnalignedFPAccesses() { return true; } + + static bool HasRoundInstruction(int mode) { (void)mode; return false; } + + protected: + InstImm invertBranch(InstImm branch, BOffImm16 skipOffset); + void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { + enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); + if (kind == Relocation::JITCODE) { + jumpRelocations_.writeUnsigned(src.getOffset()); + } + } + + void addLongJump(BufferOffset src, BufferOffset dst) { + CodeLabel cl; + cl.patchAt()->bind(src.getOffset()); + cl.target()->bind(dst.getOffset()); + addCodeLabel(std::move(cl)); + } + + public: + void flushBuffer() {} + + void comment(const char* msg) { spew("; %s", msg); } + + static uint32_t NopSize() { return 4; } + + static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm); + + static uint8_t* NextInstruction(uint8_t* instruction, + uint32_t* count = nullptr); + + static void ToggleToJmp(CodeLocationLabel inst_); + static void ToggleToCmp(CodeLocationLabel inst_); + + void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, + const Disassembler::HeapAccess& heapAccess) { + // Implement this if we implement a disassembler. + } +}; // AssemblerLOONGARCH64 + +// andi r0, r0, 0 +const uint32_t NopInst = 0x03400000; + +// An Instruction is a structure for both encoding and decoding any and all +// LoongArch instructions. +class Instruction { + public: + uint32_t data; + + protected: + // Standard constructor + Instruction(uint32_t data_) : data(data_) {} + // You should never create an instruction directly. You should create a + // more specific instruction which will eventually call one of these + // constructors for you. + + public: + uint32_t encode() const { return data; } + + void makeNop() { data = NopInst; } + + void setData(uint32_t data) { this->data = data; } + + const Instruction& operator=(const Instruction& src) { + data = src.data; + return *this; + } + + // Extract the one particular bit. + uint32_t extractBit(uint32_t bit) { return (encode() >> bit) & 1; } + // Extract a bit field out of the instruction + uint32_t extractBitField(uint32_t hi, uint32_t lo) { + return (encode() >> lo) & ((2 << (hi - lo)) - 1); + } + + // Get the next instruction in the instruction stream. + // This does neat things like ignoreconstant pools and their guards. + Instruction* next(); + + // Sometimes, an api wants a uint32_t (or a pointer to it) rather than + // an instruction. raw() just coerces this into a pointer to a uint32_t + const uint32_t* raw() const { return &data; } + uint32_t size() const { return 4; } +}; // Instruction + +// make sure that it is the right size +static_assert(sizeof(Instruction) == 4, + "Size of Instruction class has to be 4 bytes."); + +class InstNOP : public Instruction { + public: + InstNOP() : Instruction(NopInst) {} +}; + +// Class for register type instructions. +class InstReg : public Instruction { + public: + InstReg(OpcodeField op, Register rj, Register rd) + : Instruction(op | RJ(rj) | RD(rd)) {} + InstReg(OpcodeField op, Register rk, Register rj, Register rd) + : Instruction(op | RK(rk) | RJ(rj) | RD(rd)) {} + InstReg(OpcodeField op, uint32_t sa, Register rk, Register rj, Register rd, + uint32_t sa_bit) + : Instruction(sa_bit == 2 ? op | SA2(sa) | RK(rk) | RJ(rj) | RD(rd) + : op | SA3(sa) | RK(rk) | RJ(rj) | RD(rd)) { + MOZ_ASSERT(sa_bit == 2 || sa_bit == 3); + } + InstReg(OpcodeField op, Register rj, Register rd, bool HasRd) + : Instruction(HasRd ? op | RJ(rj) | RD(rd) : op | RK(rj) | RJ(rd)) {} + + // For floating-point + InstReg(OpcodeField op, Register rj, FloatRegister fd) + : Instruction(op | RJ(rj) | FD(fd)) {} + InstReg(OpcodeField op, FloatRegister fj, FloatRegister fd) + : Instruction(op | FJ(fj) | FD(fd)) {} + InstReg(OpcodeField op, FloatRegister fk, FloatRegister fj, FloatRegister fd) + : Instruction(op | FK(fk) | FJ(fj) | FD(fd)) {} + InstReg(OpcodeField op, Register rk, Register rj, FloatRegister fd) + : Instruction(op | RK(rk) | RJ(rj) | FD(fd)) {} + InstReg(OpcodeField op, FloatRegister fa, FloatRegister fk, FloatRegister fj, + FloatRegister fd) + : Instruction(op | FA(fa) | FK(fk) | FJ(fj) | FD(fd)) {} + InstReg(OpcodeField op, AssemblerLOONGARCH64::FPConditionBit ca, FloatRegister fk, + FloatRegister fj, FloatRegister fd) + : Instruction(op | ca << CAShift | FK(fk) | FJ(fj) | FD(fd)) { + MOZ_ASSERT(op == op_fsel); + } + InstReg(OpcodeField op, FloatRegister fj, Register rd) + : Instruction(op | FJ(fj) | RD(rd)) { + MOZ_ASSERT((op == op_movfr2gr_s) || (op == op_movfr2gr_d) || + (op == op_movfrh2gr_s)); + } + InstReg(OpcodeField op, Register rj, uint32_t fd) + : Instruction(op | RJ(rj) | fd) { + MOZ_ASSERT(op == op_movgr2fcsr); + } + InstReg(OpcodeField op, uint32_t fj, Register rd) + : Instruction(op | (fj << FJShift) | RD(rd)) { + MOZ_ASSERT(op == op_movfcsr2gr); + } + InstReg(OpcodeField op, FloatRegister fj, AssemblerLOONGARCH64::FPConditionBit cd) + : Instruction(op | FJ(fj) | cd) { + MOZ_ASSERT(op == op_movfr2cf); + } + InstReg(OpcodeField op, AssemblerLOONGARCH64::FPConditionBit cj, FloatRegister fd) + : Instruction(op | (cj << CJShift) | FD(fd)) { + MOZ_ASSERT(op == op_movcf2fr); + } + InstReg(OpcodeField op, Register rj, AssemblerLOONGARCH64::FPConditionBit cd) + : Instruction(op | RJ(rj) | cd) { + MOZ_ASSERT(op == op_movgr2cf); + } + InstReg(OpcodeField op, AssemblerLOONGARCH64::FPConditionBit cj, Register rd) + : Instruction(op | (cj << CJShift) | RD(rd)) { + MOZ_ASSERT(op == op_movcf2gr); + } + InstReg(OpcodeField op, int32_t cond, FloatRegister fk, FloatRegister fj, + AssemblerLOONGARCH64::FPConditionBit cd) + : Instruction(op | (cond & CONDMask) << CONDShift | FK(fk) | FJ(fj) | + (cd & RDMask)) { + MOZ_ASSERT(is_uintN(cond, 5)); + } + + uint32_t extractRK() { + return extractBitField(RKShift + RKBits - 1, RKShift); + } + uint32_t extractRJ() { + return extractBitField(RJShift + RJBits - 1, RJShift); + } + uint32_t extractRD() { + return extractBitField(RDShift + RDBits - 1, RDShift); + } + uint32_t extractSA2() { + return extractBitField(SAShift + SA2Bits - 1, SAShift); + } + uint32_t extractSA3() { + return extractBitField(SAShift + SA3Bits - 1, SAShift); + } +}; + +// Class for branch, load and store instructions with immediate offset. +class InstImm : public Instruction { + public: + void extractImm16(BOffImm16* dest); + uint32_t genImm(int32_t value, uint32_t value_bits) { + uint32_t imm = value & Imm5Mask; + if (value_bits == 6) { + imm = value & Imm6Mask; + } else if (value_bits == 12) { + imm = value & Imm12Mask; + } else if (value_bits == 14) { + imm = value & Imm14Mask; + } + + return imm; + } + + InstImm(OpcodeField op, int32_t value, Register rj, Register rd, + uint32_t value_bits) + : Instruction(op | genImm(value, value_bits) << RKShift | RJ(rj) | + RD(rd)) { + MOZ_ASSERT(value_bits == 5 || value_bits == 6 || value_bits == 12 || + value_bits == 14); + } + InstImm(OpcodeField op, BOffImm16 off, Register rj, Register rd) + : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift | RJ(rj) | + RD(rd)) {} + InstImm(OpcodeField op, int32_t si21, Register rj, bool NotHasRd) + : Instruction(NotHasRd ? op | (si21 & Imm16Mask) << RKShift | RJ(rj) | + (si21 & Imm21Mask) >> 16 + : op | (si21 & Imm20Mask) << Imm20Shift | RD(rj)) { + if (NotHasRd) { + MOZ_ASSERT(op == op_beqz || op == op_bnez); + MOZ_ASSERT(is_intN(si21, 21)); + } else { + MOZ_ASSERT(op == op_lu12i_w || op == op_lu32i_d || op == op_pcaddi || + op == op_pcaddu12i || op == op_pcaddu18i || + op == op_pcalau12i); + // si20 + MOZ_ASSERT(is_intN(si21, 20) || is_uintN(si21, 20)); + } + } + InstImm(OpcodeField op, int32_t si21, AssemblerLOONGARCH64::FPConditionBit cj, + bool isNotEqual) + : Instruction(isNotEqual + ? op | (si21 & Imm16Mask) << RKShift | + (cj + 8) << CJShift | (si21 & Imm21Mask) >> 16 + : op | (si21 & Imm16Mask) << RKShift | cj << CJShift | + (si21 & Imm21Mask) >> 16) { + MOZ_ASSERT(is_intN(si21, 21)); + MOZ_ASSERT(op == op_bcz); + MOZ_ASSERT(cj >= 0 && cj <= 7); + } + InstImm(OpcodeField op, Imm16 off, Register rj, Register rd) + : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift | RJ(rj) | + RD(rd)) {} + InstImm(OpcodeField op, int32_t bit15) + : Instruction(op | (bit15 & Imm15Mask)) { + MOZ_ASSERT(is_uintN(bit15, 15)); + } + + InstImm(OpcodeField op, int32_t bit26, bool jump) + : Instruction(op | (bit26 & Imm16Mask) << Imm16Shift | + (bit26 & Imm26Mask) >> 16) { + MOZ_ASSERT(is_intN(bit26, 26)); + } + InstImm(OpcodeField op, int32_t si12, Register rj, int32_t hint) + : Instruction(op | (si12 & Imm12Mask) << Imm12Shift | RJ(rj) | + (hint & RDMask)) { + MOZ_ASSERT(op == op_preld); + } + InstImm(OpcodeField op, int32_t msb, int32_t lsb, Register rj, Register rd, + uint32_t sb_bits) + : Instruction((sb_bits == 5) + ? op | (msb & MSBWMask) << MSBWShift | + (lsb & LSBWMask) << LSBWShift | RJ(rj) | RD(rd) + : op | (msb & MSBDMask) << MSBDShift | + (lsb & LSBDMask) << LSBDShift | RJ(rj) | RD(rd)) { + MOZ_ASSERT(sb_bits == 5 || sb_bits == 6); + MOZ_ASSERT(op == op_bstr_w || op == op_bstrins_d || op == op_bstrpick_d); + } + InstImm(OpcodeField op, int32_t msb, int32_t lsb, Register rj, Register rd) + : Instruction(op | (msb & MSBWMask) << MSBWShift | + ((lsb + 0x20) & LSBDMask) << LSBWShift | RJ(rj) | RD(rd)) { + MOZ_ASSERT(op == op_bstr_w); + } + + // For floating-point loads and stores. + InstImm(OpcodeField op, int32_t si12, Register rj, FloatRegister fd) + : Instruction(op | (si12 & Imm12Mask) << Imm12Shift | RJ(rj) | FD(fd)) { + MOZ_ASSERT(is_intN(si12, 12)); + } + + void setOpcode(OpcodeField op, uint32_t opBits) { + // opBits not greater than 24. + MOZ_ASSERT(opBits < 25); + uint32_t OpcodeShift = 32 - opBits; + uint32_t OpcodeMask = ((1 << opBits) - 1) << OpcodeShift; + data = (data & ~OpcodeMask) | op; + } + uint32_t extractRK() { + return extractBitField(RKShift + RKBits - 1, RKShift); + } + uint32_t extractRJ() { + return extractBitField(RJShift + RJBits - 1, RJShift); + } + void setRJ(uint32_t rj) { data = (data & ~RJMask) | (rj << RJShift); } + uint32_t extractRD() { + return extractBitField(RDShift + RDBits - 1, RDShift); + } + uint32_t extractImm16Value() { + return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift); + } + void setBOffImm16(BOffImm16 off) { + // Reset immediate field and replace it + data = (data & ~BOffImm16Mask) | (off.encode() << Imm16Shift); + } + void setImm21(int32_t off) { + // Reset immediate field and replace it + uint32_t low16 = (off >> 2) & Imm16Mask; + int32_t high5 = (off >> 18) & Imm5Mask; + uint32_t fcc_info = (data >> 5) & 0x1F; + data = (data & ~BOffImm26Mask) | (low16 << Imm16Shift) | high5 | + (fcc_info << 5); + } +}; + +// Class for Jump type instructions. +class InstJump : public Instruction { + public: + InstJump(OpcodeField op, JOffImm26 off) + : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift | + (off.encode() & Imm26Mask) >> 16) { + MOZ_ASSERT(op == op_b || op == op_bl); + } + + void setJOffImm26(JOffImm26 off) { + // Reset immediate field and replace it + data = (data & ~BOffImm26Mask) | + ((off.encode() & Imm16Mask) << Imm16Shift) | + ((off.encode() >> 16) & 0x3ff); + } + uint32_t extractImm26Value() { + uint32_t low16 = extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift); + uint32_t high10 = extractBitField(9, 0); + return (high10 << 16) | low16; + } +}; + +inline bool IsUnaligned(const wasm::MemoryAccessDesc& access) { + if (!access.align()) { + return false; + } + return access.align() < access.byteSize(); +} + +class ABIArgGenerator { + public: + ABIArgGenerator() + : intRegIndex_(0), floatRegIndex_(0), stackOffset_(0), current_() {} + + ABIArg next(MIRType argType); + ABIArg& current() { return current_; } + uint32_t stackBytesConsumedSoFar() const { return stackOffset_; } + void increaseStackOffset(uint32_t bytes) { stackOffset_ += bytes; } + + protected: + unsigned intRegIndex_; + unsigned floatRegIndex_; + uint32_t stackOffset_; + ABIArg current_; +}; + +class Assembler : public AssemblerLOONGARCH64 { + public: + Assembler() : AssemblerLOONGARCH64() {} + + // MacroAssemblers hold onto gcthings, so they are traced by the GC. + void trace(JSTracer* trc); + + static uintptr_t GetPointer(uint8_t*); + + using AssemblerLOONGARCH64::bind; + + static void Bind(uint8_t* rawCode, CodeLabel label); + void bind(RepatchLabel* label); + void bindLater(Label* label, wasm::TrapDesc target) { + if (label->used()) { + int32_t next; + + BufferOffset b(label); + do { + Instruction* inst = editSrc(b); + + append(wasm::TrapSite(target, b.getOffset())); + next = inst[1].encode(); + inst[1].makeNop(); + + b = BufferOffset(next); + } while (next != LabelBase::INVALID_OFFSET); + } + label->reset(); + } + + void processCodeLabels(uint8_t* rawCode); + + static void TraceJumpRelocations(JSTracer* trc, JitCode* code, + CompactBufferReader& reader); + static void TraceDataRelocations(JSTracer* trc, JitCode* code, + CompactBufferReader& reader); + + void bind(InstImm* inst, uintptr_t branch, uintptr_t target); + + // Copy the assembly code to the given buffer, and perform any pending + // relocations relying on the target address. + void executableCopy(uint8_t* buffer); + + static uint32_t PatchWrite_NearCallSize(); + + static uint64_t ExtractLoad64Value(Instruction* inst0); + static void UpdateLoad64Value(Instruction* inst0, uint64_t value); + static void WriteLoad64Instructions(Instruction* inst0, Register reg, + uint64_t value); + + static void PatchWrite_NearCall(CodeLocationLabel start, + CodeLocationLabel toCall); + static void PatchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, + ImmPtr expectedValue); + static void PatchDataWithValueCheck(CodeLocationLabel label, + PatchedImmPtr newValue, + PatchedImmPtr expectedValue); + + static void PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm); + static uint64_t ExtractInstructionImmediate(uint8_t* code); + + static void ToggleCall(CodeLocationLabel inst_, bool enabled); +}; // Assembler + +static const uint32_t NumIntArgRegs = 8; +static const uint32_t NumFloatArgRegs = 8; + +static inline bool GetIntArgReg(uint32_t usedIntArgs, Register* out) { + if (usedIntArgs < NumIntArgRegs) { + *out = Register::FromCode(a0.code() + usedIntArgs); + return true; + } + return false; +} + +static inline bool GetFloatArgReg(uint32_t usedFloatArgs, FloatRegister* out) { + if (usedFloatArgs < NumFloatArgRegs) { + *out = FloatRegister::FromCode(f0.code() + usedFloatArgs); + return true; + } + return false; +} + +// Get a register in which we plan to put a quantity that will be used as an +// integer argument. This differs from GetIntArgReg in that if we have no more +// actual argument registers to use we will fall back on using whatever +// CallTempReg* don't overlap the argument registers, and only fail once those +// run out too. +static inline bool GetTempRegForIntArg(uint32_t usedIntArgs, + uint32_t usedFloatArgs, Register* out) { + // NOTE: We can't properly determine which regs are used if there are + // float arguments. If this is needed, we will have to guess. + MOZ_ASSERT(usedFloatArgs == 0); + + if (GetIntArgReg(usedIntArgs, out)) { + return true; + } + // Unfortunately, we have to assume things about the point at which + // GetIntArgReg returns false, because we need to know how many registers it + // can allocate. + usedIntArgs -= NumIntArgRegs; + if (usedIntArgs >= NumCallTempNonArgRegs) { + return false; + } + *out = CallTempNonArgRegs[usedIntArgs]; + return true; +} + +void PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, + ReprotectCode reprotect = DontReprotect); + +static inline void PatchBackedge(CodeLocationJump& jump_, + CodeLocationLabel label, + JitRuntime::BackedgeTarget target) { + (void)target; + PatchJump(jump_, label); +} + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_Assembler_loongarch64_h */ diff --git a/js/src/jit/loongarch64/Bailouts-loongarch64.cpp b/js/src/jit/loongarch64/Bailouts-loongarch64.cpp new file mode 100644 index 0000000000..9fc484db97 --- /dev/null +++ b/js/src/jit/loongarch64/Bailouts-loongarch64.cpp @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "jit/loongarch64/Bailouts-loongarch64.h" + +#include "jscntxt.h" +#include "jscompartment.h" + +using namespace js; +using namespace js::jit; + +BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations, + BailoutStack* bailout) + : machine_(bailout->machineState()) +{ + uint8_t* sp = bailout->parentStackPointer(); + framePointer_ = sp + bailout->frameSize(); + topFrameSize_ = framePointer_ - sp; + + JSScript* script = ScriptFromCalleeToken(((JitFrameLayout*) framePointer_)->calleeToken()); + topIonScript_ = script->ionScript(); + + attachOnJitActivation(activations); + snapshotOffset_ = bailout->snapshotOffset(); +} diff --git a/js/src/jit/loongarch64/Bailouts-loongarch64.h b/js/src/jit/loongarch64/Bailouts-loongarch64.h new file mode 100644 index 0000000000..d180c6e92c --- /dev/null +++ b/js/src/jit/loongarch64/Bailouts-loongarch64.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#ifndef jit_loongarch64_Bailouts_loongarch64_h +#define jit_loongarch64_Bailouts_loongarch64_h + +#include "jit/Bailouts.h" +#include "jit/JitCompartment.h" + +namespace js { +namespace jit { + +class BailoutStack +{ + RegisterDump::FPUArray fpregs_; + RegisterDump::GPRArray regs_; + uintptr_t frameSize_; + uintptr_t snapshotOffset_; + + public: + MachineState machineState() { + return MachineState::FromBailout(regs_, fpregs_); + } + uint32_t snapshotOffset() const { + return snapshotOffset_; + } + uint32_t frameSize() const { + return frameSize_; + } + uint8_t* parentStackPointer() { + return (uint8_t*)this + sizeof(BailoutStack); + } + static size_t offsetOfFrameSize() { + return offsetof(BailoutStack, frameSize_); + } +}; + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_Bailouts_loongarch64_h */ diff --git a/js/src/jit/loongarch64/BaselineCompiler-loongarch64.cpp b/js/src/jit/loongarch64/BaselineCompiler-loongarch64.cpp new file mode 100644 index 0000000000..a6e04dc2a3 --- /dev/null +++ b/js/src/jit/loongarch64/BaselineCompiler-loongarch64.cpp @@ -0,0 +1,15 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "jit/loongarch64/BaselineCompiler-loongarch64.h" + +using namespace js; +using namespace js::jit; + +BaselineCompilerLOONGARCH64::BaselineCompilerLOONGARCH64(JSContext* cx, TempAllocator& alloc, + JSScript* script) + : BaselineCompilerMIPSShared(cx, alloc, script) +{ +} diff --git a/js/src/jit/loongarch64/BaselineCompiler-loongarch64.h b/js/src/jit/loongarch64/BaselineCompiler-loongarch64.h new file mode 100644 index 0000000000..42a9fa1d14 --- /dev/null +++ b/js/src/jit/loongarch64/BaselineCompiler-loongarch64.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#ifndef jit_loongarch64_BaselineCompiler_loongarch64_h +#define jit_loongarch64_BaselineCompiler_loongarch64_h + +#include "jit/mips-shared/BaselineCompiler-mips-shared.h" + +namespace js { +namespace jit { + +class BaselineCompilerLOONGARCH64 : public BaselineCompilerMIPSShared +{ + protected: + BaselineCompilerLOONGARCH64(JSContext* cx, TempAllocator& alloc, JSScript* script); +}; + +typedef BaselineCompilerLOONGARCH64 BaselineCompilerSpecific; + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_BaselineCompiler_loongarch64_h */ diff --git a/js/src/jit/loongarch64/BaselineIC-loongarch64.cpp b/js/src/jit/loongarch64/BaselineIC-loongarch64.cpp new file mode 100644 index 0000000000..89bdb5f085 --- /dev/null +++ b/js/src/jit/loongarch64/BaselineIC-loongarch64.cpp @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "jit/BaselineCompiler.h" +#include "jit/BaselineIC.h" +#include "jit/BaselineJIT.h" +#include "jit/Linker.h" +#include "jit/SharedICHelpers.h" +#include "jit/MacroAssembler-inl.h" + +using namespace js; +using namespace js::jit; + +namespace js { +namespace jit { + +// ICCompare_Int32 + +bool +ICCompare_Int32::Compiler::generateStubCode(MacroAssembler& masm) +{ + // Guard that R0 is an integer and R1 is an integer. + Label failure; + Label conditionTrue; + Label done; + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); + masm.branchTestInt32(Assembler::NotEqual, R1, &failure); + + // Compare payload regs of R0 and R1. + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); + masm.move32(Imm32(0), R0.valueReg()); + masm.branch32(cond, ExtractTemp0, ExtractTemp1, &conditionTrue); + masm.jump(&done); + masm.bind(&conditionTrue); + masm.move32(Imm32(1), R0.valueReg()); + masm.bind(&done); + + masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.valueReg(), R0); + EmitReturnFromIC(masm); + + // Failure case - jump to next stub + masm.bind(&failure); + EmitStubGuardFailure(masm); + + return true; +} + +} // namespace jit +} // namespace js diff --git a/js/src/jit/loongarch64/CodeGenerator-loongarch64.cpp b/js/src/jit/loongarch64/CodeGenerator-loongarch64.cpp new file mode 100644 index 0000000000..1f5ba250ab --- /dev/null +++ b/js/src/jit/loongarch64/CodeGenerator-loongarch64.cpp @@ -0,0 +1,810 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "jit/loongarch64/CodeGenerator-loongarch64.h" + +#include "jit/JitFrames.h" +#include "jit/MIR.h" +#include "jit/MIRGraph.h" +#include "vm/Shape.h" +#include "vm/TraceLogging.h" + +#include "jit/MacroAssembler-inl.h" +#include "jit/shared/CodeGenerator-shared-inl.h" + +using namespace js; +using namespace js::jit; + +static constexpr uint32_t WasmTruncateInvalidCauseMask = + 1u << (Assembler::CauseV - Assembler::CauseI); + +static void +ExtractWasmTruncateInvalidCause(MacroAssemblerLOONGARCH64Compat& masm, Register reg) +{ + masm.as_cfc1(reg, Assembler::FCSR); + masm.as_bstrpick_d(reg, reg, Assembler::CauseV, Assembler::CauseI); + masm.as_andi(reg, reg, WasmTruncateInvalidCauseMask); +} + +class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase +{ + MTableSwitch* mir_; + CodeLabel jumpLabel_; + + void accept(CodeGeneratorLoongArch64* codegen) { + codegen->visitOutOfLineTableSwitch(this); + } + + public: + explicit OutOfLineTableSwitch(MTableSwitch* mir) + : mir_(mir) + {} + + MTableSwitch* mir() const { + return mir_; + } + + CodeLabel* jumpLabel() { + return &jumpLabel_; + } +}; + +void +CodeGeneratorLoongArch64::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool) +{ + MTableSwitch* mir = ool->mir(); + + masm.haltingAlign(sizeof(void*)); + masm.bind(ool->jumpLabel()->target()); + masm.addCodeLabel(*ool->jumpLabel()); + + for (size_t i = 0; i < mir->numCases(); i++) { + LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir(); + Label* caseheader = caseblock->label(); + uint32_t caseoffset = caseheader->offset(); + + // Keep loongarch64 table entries at a fixed 32-byte stride so dispatch + // can jump to a stub entry and let the stub jump to the case body. + CodeLabel cl; + masm.ma_li(ScratchRegister, cl.patchAt()); + masm.jump(ScratchRegister); + masm.as_nop(); + masm.as_nop(); + masm.as_nop(); + masm.as_nop(); + cl.target()->bind(caseoffset); + masm.addCodeLabel(cl); + } +} + +void +CodeGeneratorLoongArch64::emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base) +{ + Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label(); + + if (mir->low() != 0) + masm.subPtr(Imm32(mir->low()), index); + + int32_t cases = mir->numCases(); + masm.branch32(Assembler::AboveOrEqual, index, Imm32(cases), defaultcase); + + OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(mir); + addOutOfLineCode(ool, mir); + + masm.ma_li(base, ool->jumpLabel()->patchAt()); + masm.lshiftPtr(Imm32(5), index); + masm.addPtr(index, base); + masm.jump(base); +} + +void +CodeGeneratorLoongArch64::visitCompare(LCompare* comp) +{ + MCompare* mir = comp->mir(); + Assembler::Condition cond = JSOpToCondition(mir->compareType(), comp->jsop()); + const LAllocation* left = comp->getOperand(0); + const LAllocation* right = comp->getOperand(1); + const LDefinition* def = comp->getDef(0); + + if (mir->compareType() == MCompare::Compare_Object) { + if (right->isGeneralReg()) + masm.cmpPtrSet(cond, ToRegister(left), ToRegister(right), ToRegister(def)); + else + masm.cmpPtrSet(cond, ToRegister(left), ToAddress(right), ToRegister(def)); + return; + } + + CodeGeneratorMIPSShared::visitCompare(comp); +} + +void +CodeGeneratorLoongArch64::visitCompareAndBranch(LCompareAndBranch* comp) +{ + MCompare* mir = comp->cmpMir(); + Assembler::Condition cond = JSOpToCondition(mir->compareType(), comp->jsop()); + + if (mir->compareType() == MCompare::Compare_Object) { + if (comp->right()->isGeneralReg()) { + emitBranch(ToRegister(comp->left()), ToRegister(comp->right()), cond, + comp->ifTrue(), comp->ifFalse()); + } else { + masm.loadPtr(ToAddress(comp->right()), ScratchRegister); + emitBranch(ToRegister(comp->left()), ScratchRegister, cond, + comp->ifTrue(), comp->ifFalse()); + } + return; + } + + CodeGeneratorMIPSShared::visitCompareAndBranch(comp); +} + +void +CodeGeneratorLoongArch64::visitDivI(LDivI* ins) +{ + Register lhs = ToRegister(ins->lhs()); + Register rhs = ToRegister(ins->rhs()); + Register dest = ToRegister(ins->output()); + Register temp = ToRegister(ins->getTemp(0)); + MDiv* mir = ins->mir(); + + Label done; + + if (mir->canBeDivideByZero()) { + if (mir->trapOnError()) { + masm.ma_b(rhs, rhs, trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Zero); + } else if (mir->canTruncateInfinities()) { + Label notzero; + masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump); + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + masm.bind(¬zero); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Zero, rhs, rhs, ins->snapshot()); + } + } + + if (mir->canBeNegativeOverflow()) { + Label notMinInt; + masm.move32(Imm32(INT32_MIN), temp); + masm.ma_b(lhs, temp, ¬MinInt, Assembler::NotEqual, ShortJump); + + masm.move32(Imm32(-1), temp); + if (mir->trapOnError()) { + masm.ma_b(rhs, temp, trap(mir, wasm::Trap::IntegerOverflow), Assembler::Equal); + } else if (mir->canTruncateOverflow()) { + Label skip; + masm.ma_b(rhs, temp, &skip, Assembler::NotEqual, ShortJump); + masm.move32(Imm32(INT32_MIN), dest); + masm.ma_b(&done, ShortJump); + masm.bind(&skip); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, rhs, temp, ins->snapshot()); + } + masm.bind(¬MinInt); + } + + if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) { + Label nonzero; + masm.ma_b(lhs, lhs, &nonzero, Assembler::NonZero, ShortJump); + bailoutCmp32(Assembler::LessThan, rhs, Imm32(0), ins->snapshot()); + masm.bind(&nonzero); + } + + if (mir->canTruncateRemainder()) { + masm.as_div_w(dest, lhs, rhs); + } else { + MOZ_ASSERT(mir->fallible()); + + Label remainderNonZero; + masm.ma_div_branch_overflow(dest, lhs, rhs, &remainderNonZero); + bailoutFrom(&remainderNonZero, ins->snapshot()); + } + + masm.bind(&done); +} + +void +CodeGeneratorLoongArch64::visitModI(LModI* ins) +{ + Register lhs = ToRegister(ins->lhs()); + Register rhs = ToRegister(ins->rhs()); + Register dest = ToRegister(ins->output()); + Register callTemp = ToRegister(ins->callTemp()); + MMod* mir = ins->mir(); + Label done, prevent; + + masm.move32(lhs, callTemp); + + if (mir->canBeNegativeDividend()) { + masm.ma_b(lhs, Imm32(INT_MIN), &prevent, Assembler::NotEqual, ShortJump); + if (mir->isTruncated()) { + Label skip; + masm.ma_b(rhs, Imm32(-1), &skip, Assembler::NotEqual, ShortJump); + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + masm.bind(&skip); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, rhs, Imm32(-1), ins->snapshot()); + } + masm.bind(&prevent); + } + + if (mir->canBeDivideByZero()) { + if (mir->isTruncated()) { + if (mir->trapOnError()) { + masm.ma_b(rhs, rhs, trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Zero); + } else { + Label skip; + masm.ma_b(rhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump); + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + masm.bind(&skip); + } + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()); + } + } + + if (mir->canBeNegativeDividend()) { + Label notNegative; + masm.ma_b(rhs, Imm32(0), ¬Negative, Assembler::GreaterThan, ShortJump); + if (mir->isTruncated()) { + Label skip; + masm.ma_b(lhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump); + masm.move32(Imm32(0), dest); + masm.ma_b(&done, ShortJump); + masm.bind(&skip); + } else { + MOZ_ASSERT(mir->fallible()); + bailoutCmp32(Assembler::Equal, lhs, Imm32(0), ins->snapshot()); + } + masm.bind(¬Negative); + } + + masm.as_mod_w(dest, lhs, rhs); + + if (mir->canBeNegativeDividend() && !mir->isTruncated()) { + MOZ_ASSERT(mir->fallible()); + masm.ma_b(dest, Imm32(0), &done, Assembler::NotEqual, ShortJump); + bailoutCmp32(Assembler::Signed, callTemp, Imm32(0), ins->snapshot()); + } + masm.bind(&done); +} + +void +CodeGeneratorLoongArch64::visitUDivOrMod(LUDivOrMod* ins) +{ + Register lhs = ToRegister(ins->lhs()); + Register rhs = ToRegister(ins->rhs()); + Register output = ToRegister(ins->output()); + Label done; + + if (ins->canBeDivideByZero()) { + if (ins->mir()->isTruncated()) { + if (ins->trapOnError()) { + masm.ma_b(rhs, rhs, trap(ins, wasm::Trap::IntegerDivideByZero), Assembler::Zero); + } else { + Label notzero; + masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump); + masm.move32(Imm32(0), output); + masm.ma_b(&done, ShortJump); + masm.bind(¬zero); + } + } else { + bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()); + } + } + + masm.as_mod_wu(ScratchRegister, lhs, rhs); + masm.move32(ScratchRegister, output); + + if (ins->mir()->isDiv()) { + if (!ins->mir()->toDiv()->canTruncateRemainder()) + bailoutCmp32(Assembler::NonZero, output, output, ins->snapshot()); + masm.as_div_wu(output, lhs, rhs); + } + + if (!ins->mir()->isTruncated()) + bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot()); + + masm.bind(&done); +} + +void +CodeGeneratorLoongArch64::visitDivOrModI64(LDivOrModI64* lir) +{ + Register lhs = ToRegister(lir->lhs()); + Register rhs = ToRegister(lir->rhs()); + Register output = ToRegister(lir->output()); + + Label done; + + if (lir->canBeDivideByZero()) + masm.ma_b(rhs, rhs, trap(lir, wasm::Trap::IntegerDivideByZero), Assembler::Zero); + + if (lir->canBeNegativeOverflow()) { + Label notmin; + masm.branchPtr(Assembler::NotEqual, lhs, ImmWord(INT64_MIN), ¬min); + masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(-1), ¬min); + if (lir->mir()->isMod()) { + masm.ma_xor(output, output); + } else { + masm.jump(trap(lir, wasm::Trap::IntegerOverflow)); + } + masm.jump(&done); + masm.bind(¬min); + } + + if (lir->mir()->isMod()) + masm.as_mod_d(output, lhs, rhs); + else + masm.as_div_d(output, lhs, rhs); + + masm.bind(&done); +} + +void +CodeGeneratorLoongArch64::visitUDivOrModI64(LUDivOrModI64* lir) +{ + Register lhs = ToRegister(lir->lhs()); + Register rhs = ToRegister(lir->rhs()); + Register output = ToRegister(lir->output()); + + Label done; + + if (lir->canBeDivideByZero()) + masm.ma_b(rhs, rhs, trap(lir, wasm::Trap::IntegerDivideByZero), Assembler::Zero); + + if (lir->mir()->isMod()) + masm.as_mod_du(output, lhs, rhs); + else + masm.as_div_du(output, lhs, rhs); + + masm.bind(&done); +} + +void +CodeGeneratorLoongArch64::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir) +{ + auto input = ToFloatRegister(lir->input()); + auto output = ToRegister(lir->output()); + + MWasmTruncateToInt32* mir = lir->mir(); + MIRType fromType = mir->input()->type(); + + auto* ool = new (alloc()) OutOfLineWasmTruncateCheck(mir, input); + addOutOfLineCode(ool, mir); + + if (mir->isUnsigned()) { + if (fromType == MIRType::Double) + masm.as_truncld(ScratchDoubleReg, input); + else if (fromType == MIRType::Float32) + masm.as_truncls(ScratchDoubleReg, input); + else + MOZ_CRASH("unexpected type in visitWasmTruncateToInt32"); + + masm.moveFromDoubleHi(ScratchDoubleReg, output); + ExtractWasmTruncateInvalidCause(masm, ScratchRegister); + masm.ma_or(output, ScratchRegister); + masm.ma_b(output, Imm32(0), ool->entry(), Assembler::NotEqual); + + masm.moveFromFloat32(ScratchDoubleReg, output); + return; + } + + if (fromType == MIRType::Double) + masm.as_truncwd(ScratchFloat32Reg, input); + else if (fromType == MIRType::Float32) + masm.as_truncws(ScratchFloat32Reg, input); + else + MOZ_CRASH("unexpected type in visitWasmTruncateToInt32"); + + ExtractWasmTruncateInvalidCause(masm, output); + masm.ma_b(output, Imm32(0), ool->entry(), Assembler::NotEqual); + + masm.bind(ool->rejoin()); + masm.moveFromFloat32(ScratchFloat32Reg, output); +} + +void +CodeGeneratorLoongArch64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir) +{ + FloatRegister input = ToFloatRegister(lir->input()); + Register output = ToRegister(lir->output()); + + MWasmTruncateToInt64* mir = lir->mir(); + MIRType fromType = mir->input()->type(); + + MOZ_ASSERT(fromType == MIRType::Double || fromType == MIRType::Float32); + + auto* ool = new (alloc()) OutOfLineWasmTruncateCheck(mir, input); + addOutOfLineCode(ool, mir); + + if (mir->isUnsigned()) { + Label isLarge, done; + + if (fromType == MIRType::Double) { + masm.loadConstantDouble(double(INT64_MAX), ScratchDoubleReg); + masm.ma_bc1d(ScratchDoubleReg, input, &isLarge, + Assembler::DoubleLessThanOrEqual, ShortJump); + + masm.as_truncld(ScratchDoubleReg, input); + } else { + masm.loadConstantFloat32(float(INT64_MAX), ScratchFloat32Reg); + masm.ma_bc1s(ScratchFloat32Reg, input, &isLarge, + Assembler::DoubleLessThanOrEqual, ShortJump); + + masm.as_truncls(ScratchDoubleReg, input); + } + + masm.moveFromDouble(ScratchDoubleReg, output); + ExtractWasmTruncateInvalidCause(masm, ScratchRegister); + masm.ma_dsrl(SecondScratchReg, output, Imm32(63)); + masm.ma_or(SecondScratchReg, ScratchRegister); + masm.ma_b(SecondScratchReg, Imm32(0), ool->entry(), Assembler::NotEqual); + + masm.ma_b(&done, ShortJump); + + masm.bind(&isLarge); + if (fromType == MIRType::Double) { + masm.as_subd(ScratchDoubleReg, input, ScratchDoubleReg); + masm.as_truncld(ScratchDoubleReg, ScratchDoubleReg); + } else { + masm.as_subs(ScratchDoubleReg, input, ScratchDoubleReg); + masm.as_truncls(ScratchDoubleReg, ScratchDoubleReg); + } + + masm.moveFromDouble(ScratchDoubleReg, output); + ExtractWasmTruncateInvalidCause(masm, ScratchRegister); + masm.ma_dsrl(SecondScratchReg, output, Imm32(63)); + masm.ma_or(SecondScratchReg, ScratchRegister); + masm.ma_b(SecondScratchReg, Imm32(0), ool->entry(), Assembler::NotEqual); + + masm.ma_li(ScratchRegister, Imm32(1)); + masm.ma_dins(output, ScratchRegister, Imm32(63), Imm32(1)); + + masm.bind(&done); + return; + } + + if (fromType == MIRType::Double) + masm.as_truncld(ScratchDoubleReg, input); + else + masm.as_truncls(ScratchDoubleReg, input); + + ExtractWasmTruncateInvalidCause(masm, output); + masm.ma_b(output, Imm32(0), ool->entry(), Assembler::NotEqual); + + masm.bind(ool->rejoin()); + masm.moveFromDouble(ScratchDoubleReg, output); +} + +void +CodeGeneratorLoongArch64::visitWasmAddOffset(LWasmAddOffset* lir) +{ + MWasmAddOffset* mir = lir->mir(); + Register base = ToRegister(lir->base()); + Register out = ToRegister(lir->output()); + + Register limitBase = base; + if (base == out) { + limitBase = ScratchRegister; + masm.movePtr(base, limitBase); + } else { + masm.movePtr(base, out); + } + + masm.addPtr(Imm32(mir->offset()), out); + masm.branchPtr(Assembler::Below, out, limitBase, trap(mir, wasm::Trap::OutOfBounds)); +} + +template +static void +AtomicBinopToTypedIntArray(MacroAssemblerLOONGARCH64Compat& masm, AtomicOp op, + Scalar::Type arrayType, const S& value, + const T& mem, Register outTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, AnyRegister output) +{ + switch (arrayType) { + case Scalar::Int8: + masm.atomicFetchOp(1, true, op, value, mem, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint8: + masm.atomicFetchOp(1, false, op, value, mem, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Int16: + masm.atomicFetchOp(2, true, op, value, mem, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint16: + masm.atomicFetchOp(2, false, op, value, mem, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Int32: + masm.atomicFetchOp(4, false, op, value, mem, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint32: + MOZ_ASSERT(output.isFloat()); + MOZ_ASSERT(outTemp != InvalidReg); + masm.atomicFetchOp(4, false, op, value, mem, valueTemp, offsetTemp, + maskTemp, outTemp); + masm.convertUInt32ToDouble(outTemp, output.fpu()); + break; + default: + MOZ_CRASH("Invalid typed array type"); + } +} + +template +static void +AtomicBinopToTypedIntArray(MacroAssemblerLOONGARCH64Compat& masm, AtomicOp op, + Scalar::Type arrayType, const S& value, + const T& mem, Register valueTemp, + Register offsetTemp, Register maskTemp) +{ + switch (arrayType) { + case Scalar::Int8: + case Scalar::Uint8: + masm.atomicEffectOp(1, op, value, mem, valueTemp, offsetTemp, + maskTemp); + break; + case Scalar::Int16: + case Scalar::Uint16: + masm.atomicEffectOp(2, op, value, mem, valueTemp, offsetTemp, + maskTemp); + break; + case Scalar::Int32: + case Scalar::Uint32: + masm.atomicEffectOp(4, op, value, mem, valueTemp, offsetTemp, + maskTemp); + break; + default: + MOZ_CRASH("Invalid typed array type"); + } +} + +template +static void +AtomicBinopToTypedArray(MacroAssemblerLOONGARCH64Compat& masm, AtomicOp op, + Scalar::Type arrayType, const LAllocation* value, + const T& mem, Register outTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + AnyRegister output) +{ + if (value->isConstant()) { + AtomicBinopToTypedIntArray(masm, op, arrayType, Imm32(ToInt32(value)), + mem, outTemp, valueTemp, offsetTemp, + maskTemp, output); + } else { + AtomicBinopToTypedIntArray(masm, op, arrayType, ToRegister(value), + mem, outTemp, valueTemp, offsetTemp, + maskTemp, output); + } +} + +template +static void +AtomicBinopToTypedArray(MacroAssemblerLOONGARCH64Compat& masm, AtomicOp op, + Scalar::Type arrayType, const LAllocation* value, + const T& mem, Register valueTemp, Register offsetTemp, + Register maskTemp) +{ + if (value->isConstant()) { + AtomicBinopToTypedIntArray(masm, op, arrayType, Imm32(ToInt32(value)), + mem, valueTemp, offsetTemp, maskTemp); + } else { + AtomicBinopToTypedIntArray(masm, op, arrayType, ToRegister(value), + mem, valueTemp, offsetTemp, maskTemp); + } +} + +void +CodeGeneratorLoongArch64::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins) +{ + MAsmJSCompareExchangeHeap* mir = ins->mir(); + Scalar::Type vt = mir->access().type(); + Register ptrReg = ToRegister(ins->ptr()); + BaseIndex srcAddr(HeapReg, ptrReg, TimesOne); + MOZ_ASSERT(ins->addrTemp()->isBogusTemp()); + + Register oldval = ToRegister(ins->oldValue()); + Register newval = ToRegister(ins->newValue()); + Register valueTemp = ToRegister(ins->valueTemp()); + Register offsetTemp = ToRegister(ins->offsetTemp()); + Register maskTemp = ToRegister(ins->maskTemp()); + + masm.compareExchangeToTypedIntArray( + vt == Scalar::Uint32 ? Scalar::Int32 : vt, srcAddr, oldval, newval, + InvalidReg, valueTemp, offsetTemp, maskTemp, + ToAnyRegister(ins->output())); +} + +void +CodeGeneratorLoongArch64::visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins) +{ + MAsmJSAtomicExchangeHeap* mir = ins->mir(); + Scalar::Type vt = mir->access().type(); + Register ptrReg = ToRegister(ins->ptr()); + Register value = ToRegister(ins->value()); + BaseIndex srcAddr(HeapReg, ptrReg, TimesOne); + MOZ_ASSERT(ins->addrTemp()->isBogusTemp()); + + Register valueTemp = ToRegister(ins->valueTemp()); + Register offsetTemp = ToRegister(ins->offsetTemp()); + Register maskTemp = ToRegister(ins->maskTemp()); + + masm.atomicExchangeToTypedIntArray( + vt == Scalar::Uint32 ? Scalar::Int32 : vt, srcAddr, value, InvalidReg, + valueTemp, offsetTemp, maskTemp, ToAnyRegister(ins->output())); +} + +void +CodeGeneratorLoongArch64::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins) +{ + MOZ_ASSERT(ins->mir()->hasUses()); + MOZ_ASSERT(ins->addrTemp()->isBogusTemp()); + + MAsmJSAtomicBinopHeap* mir = ins->mir(); + Scalar::Type vt = mir->access().type(); + Register ptrReg = ToRegister(ins->ptr()); + Register valueTemp = ToRegister(ins->valueTemp()); + Register offsetTemp = ToRegister(ins->offsetTemp()); + Register maskTemp = ToRegister(ins->maskTemp()); + const LAllocation* value = ins->value(); + AtomicOp op = mir->operation(); + + BaseIndex srcAddr(HeapReg, ptrReg, TimesOne); + + AtomicBinopToTypedArray(masm, op, + vt == Scalar::Uint32 ? Scalar::Int32 : vt, value, + srcAddr, InvalidReg, valueTemp, offsetTemp, + maskTemp, ToAnyRegister(ins->output())); +} + +void +CodeGeneratorLoongArch64::visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins) +{ + MOZ_ASSERT(!ins->mir()->hasUses()); + MOZ_ASSERT(ins->addrTemp()->isBogusTemp()); + + MAsmJSAtomicBinopHeap* mir = ins->mir(); + Scalar::Type vt = mir->access().type(); + Register ptrReg = ToRegister(ins->ptr()); + Register valueTemp = ToRegister(ins->valueTemp()); + Register offsetTemp = ToRegister(ins->offsetTemp()); + Register maskTemp = ToRegister(ins->maskTemp()); + const LAllocation* value = ins->value(); + AtomicOp op = mir->operation(); + + BaseIndex srcAddr(HeapReg, ptrReg, TimesOne); + + AtomicBinopToTypedArray(masm, op, vt, value, srcAddr, valueTemp, + offsetTemp, maskTemp); +} + +void +CodeGeneratorLoongArch64::visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir) +{ + MOZ_ASSERT(lir->mir()->hasUses()); + + AnyRegister output = ToAnyRegister(lir->output()); + Register elements = ToRegister(lir->elements()); + Register outTemp = lir->temp2()->isBogusTemp() ? InvalidReg + : ToRegister(lir->temp2()); + Register valueTemp = ToRegister(lir->valueTemp()); + Register offsetTemp = ToRegister(lir->offsetTemp()); + Register maskTemp = ToRegister(lir->maskTemp()); + const LAllocation* value = lir->value(); + + Scalar::Type arrayType = lir->mir()->arrayType(); + int width = Scalar::byteSize(arrayType); + + if (lir->index()->isConstant()) { + Address mem(elements, ToInt32(lir->index()) * width); + AtomicBinopToTypedArray(masm, lir->mir()->operation(), arrayType, value, + mem, outTemp, valueTemp, offsetTemp, maskTemp, + output); + } else { + BaseIndex mem(elements, ToRegister(lir->index()), + ScaleFromElemWidth(width)); + AtomicBinopToTypedArray(masm, lir->mir()->operation(), arrayType, value, + mem, outTemp, valueTemp, offsetTemp, maskTemp, + output); + } +} + +void +CodeGeneratorLoongArch64::visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir) +{ + MOZ_ASSERT(!lir->mir()->hasUses()); + + Register elements = ToRegister(lir->elements()); + Register valueTemp = ToRegister(lir->valueTemp()); + Register offsetTemp = ToRegister(lir->offsetTemp()); + Register maskTemp = ToRegister(lir->maskTemp()); + const LAllocation* value = lir->value(); + Scalar::Type arrayType = lir->mir()->arrayType(); + int width = Scalar::byteSize(arrayType); + + if (lir->index()->isConstant()) { + Address mem(elements, ToInt32(lir->index()) * width); + AtomicBinopToTypedArray(masm, lir->mir()->operation(), arrayType, value, + mem, valueTemp, offsetTemp, maskTemp); + } else { + BaseIndex mem(elements, ToRegister(lir->index()), + ScaleFromElemWidth(width)); + AtomicBinopToTypedArray(masm, lir->mir()->operation(), arrayType, value, + mem, valueTemp, offsetTemp, maskTemp); + } +} + +void +CodeGeneratorLoongArch64::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir) +{ + Register elements = ToRegister(lir->elements()); + AnyRegister output = ToAnyRegister(lir->output()); + Register temp = lir->temp()->isBogusTemp() ? InvalidReg + : ToRegister(lir->temp()); + + Register oldval = ToRegister(lir->oldval()); + Register newval = ToRegister(lir->newval()); + Register valueTemp = ToRegister(lir->valueTemp()); + Register offsetTemp = ToRegister(lir->offsetTemp()); + Register maskTemp = ToRegister(lir->maskTemp()); + + Scalar::Type arrayType = lir->mir()->arrayType(); + int width = Scalar::byteSize(arrayType); + + if (lir->index()->isConstant()) { + Address dest(elements, ToInt32(lir->index()) * width); + masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, + temp, valueTemp, offsetTemp, + maskTemp, output); + } else { + BaseIndex dest(elements, ToRegister(lir->index()), + ScaleFromElemWidth(width)); + masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, + temp, valueTemp, offsetTemp, + maskTemp, output); + } +} + +void +CodeGeneratorLoongArch64::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir) +{ + Register elements = ToRegister(lir->elements()); + AnyRegister output = ToAnyRegister(lir->output()); + Register temp = lir->temp()->isBogusTemp() ? InvalidReg + : ToRegister(lir->temp()); + + Register value = ToRegister(lir->value()); + Register valueTemp = ToRegister(lir->valueTemp()); + Register offsetTemp = ToRegister(lir->offsetTemp()); + Register maskTemp = ToRegister(lir->maskTemp()); + + Scalar::Type arrayType = lir->mir()->arrayType(); + int width = Scalar::byteSize(arrayType); + + if (lir->index()->isConstant()) { + Address dest(elements, ToInt32(lir->index()) * width); + masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, + valueTemp, offsetTemp, maskTemp, + output); + } else { + BaseIndex dest(elements, ToRegister(lir->index()), + ScaleFromElemWidth(width)); + masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, + valueTemp, offsetTemp, maskTemp, + output); + } +} diff --git a/js/src/jit/loongarch64/CodeGenerator-loongarch64.h b/js/src/jit/loongarch64/CodeGenerator-loongarch64.h new file mode 100644 index 0000000000..782a2abdb7 --- /dev/null +++ b/js/src/jit/loongarch64/CodeGenerator-loongarch64.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#ifndef jit_loongarch64_CodeGenerator_loongarch64_h +#define jit_loongarch64_CodeGenerator_loongarch64_h + +#define CodeGeneratorSpecific CodeGeneratorMIPS64Specific +#include "jit/mips64/CodeGenerator-mips64.h" +#undef CodeGeneratorSpecific + +namespace js { +namespace jit { + +class CodeGeneratorLoongArch64 : public CodeGeneratorMIPS64 +{ + public: + using CodeGeneratorMIPS64::CodeGeneratorMIPS64; + + void visitCompare(LCompare* comp); + void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool); + void visitCompareAndBranch(LCompareAndBranch* comp); + void visitDivI(LDivI* ins); + void visitModI(LModI* ins); + void visitUDivOrMod(LUDivOrMod* ins); + void visitDivOrModI64(LDivOrModI64* lir); + void visitUDivOrModI64(LUDivOrModI64* lir); + void visitWasmTruncateToInt32(LWasmTruncateToInt32* lir); + void visitWasmTruncateToInt64(LWasmTruncateToInt64* lir); + void visitWasmAddOffset(LWasmAddOffset* lir); + void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins); + void visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins); + void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); + void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins); + void visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir); + void visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir); + void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir); + void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir); + + protected: + void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base); +}; + +typedef CodeGeneratorLoongArch64 CodeGeneratorSpecific; + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_CodeGenerator_loongarch64_h */ diff --git a/js/src/jit/loongarch64/Lowering-loongarch64.cpp b/js/src/jit/loongarch64/Lowering-loongarch64.cpp new file mode 100644 index 0000000000..1a71bd063d --- /dev/null +++ b/js/src/jit/loongarch64/Lowering-loongarch64.cpp @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "jit/loongarch64/Lowering-loongarch64.h" + +#include "jit/loongarch64/Assembler-loongarch64.h" + +#include "jit/MIR.h" + +#include "jit/shared/Lowering-shared-inl.h" + +using namespace js; +using namespace js::jit; + +void +LIRGeneratorLoongArch64::defineInt64Phi(MPhi* phi, size_t lirIndex) +{ + defineTypedPhi(phi, lirIndex); +} + +void +LIRGeneratorLoongArch64::lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, + LBlock* block, size_t lirIndex) +{ + lowerTypedPhiInput(phi, inputPosition, block, lirIndex); +} + +LBoxAllocation +LIRGeneratorLoongArch64::useBoxFixed(MDefinition* mir, Register reg1, Register reg2, bool useAtStart) +{ + MOZ_ASSERT(mir->type() == MIRType::Value); + + ensureDefined(mir); + return LBoxAllocation(LUse(reg1, mir->virtualRegister(), useAtStart)); +} + +void +LIRGeneratorLoongArch64::lowerDivI64(MDiv* div) +{ + if (div->isUnsigned()) { + lowerUDivI64(div); + return; + } + + LDivOrModI64* lir = new(alloc()) LDivOrModI64(useRegister(div->lhs()), useRegister(div->rhs()), + temp()); + defineInt64(lir, div); +} + +void +LIRGeneratorLoongArch64::lowerModI64(MMod* mod) +{ + if (mod->isUnsigned()) { + lowerUModI64(mod); + return; + } + + LDivOrModI64* lir = new(alloc()) LDivOrModI64(useRegister(mod->lhs()), useRegister(mod->rhs()), + temp()); + defineInt64(lir, mod); +} + +void +LIRGeneratorLoongArch64::lowerUDivI64(MDiv* div) +{ + LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useRegister(div->lhs()), + useRegister(div->rhs()), + temp()); + defineInt64(lir, div); +} + +void +LIRGeneratorLoongArch64::lowerUModI64(MMod* mod) +{ + LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useRegister(mod->lhs()), + useRegister(mod->rhs()), + temp()); + defineInt64(lir, mod); +} + +void +LIRGeneratorLoongArch64::visitBox(MBox* box) +{ + MDefinition* opd = box->getOperand(0); + + if (opd->isConstant() && box->canEmitAtUses()) { + emitAtUses(box); + return; + } + + if (opd->isConstant()) { + define(new(alloc()) LValue(opd->toConstant()->toJSValue()), box, LDefinition(LDefinition::BOX)); + } else { + LBox* ins = new(alloc()) LBox(useRegister(opd), opd->type()); + define(ins, box, LDefinition(LDefinition::BOX)); + } +} + +void +LIRGeneratorLoongArch64::visitUnbox(MUnbox* unbox) +{ + MDefinition* box = unbox->getOperand(0); + + if (box->type() == MIRType::ObjectOrNull) { + LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(box)); + if (unbox->fallible()) + assignSnapshot(lir, unbox->bailoutKind()); + defineReuseInput(lir, unbox, 0); + return; + } + + MOZ_ASSERT(box->type() == MIRType::Value); + + LUnbox* lir; + if (IsFloatingPointType(unbox->type())) { + lir = new(alloc()) LUnboxFloatingPoint(useRegisterAtStart(box), unbox->type()); + } else if (unbox->fallible()) { + lir = new(alloc()) LUnbox(useRegisterAtStart(box)); + } else { + lir = new(alloc()) LUnbox(useAtStart(box)); + } + + if (unbox->fallible()) + assignSnapshot(lir, unbox->bailoutKind()); + + define(lir, unbox); +} + +void +LIRGeneratorLoongArch64::visitReturn(MReturn* ret) +{ + MDefinition* opd = ret->getOperand(0); + MOZ_ASSERT(opd->type() == MIRType::Value); + + LReturn* ins = new(alloc()) LReturn; + ins->setOperand(0, useFixed(opd, JSReturnReg)); + add(ins); +} + +void +LIRGeneratorLoongArch64::defineUntypedPhi(MPhi* phi, size_t lirIndex) +{ + defineTypedPhi(phi, lirIndex); +} + +void +LIRGeneratorLoongArch64::lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, + LBlock* block, size_t lirIndex) +{ + lowerTypedPhiInput(phi, inputPosition, block, lirIndex); +} + +void +LIRGeneratorLoongArch64::lowerTruncateDToInt32(MTruncateToInt32* ins) +{ + MDefinition* opd = ins->input(); + MOZ_ASSERT(opd->type() == MIRType::Double); + + define(new(alloc()) + LTruncateDToInt32(useRegister(opd), tempDouble()), ins); +} + +void +LIRGeneratorLoongArch64::lowerTruncateFToInt32(MTruncateToInt32* ins) +{ + MDefinition* opd = ins->input(); + MOZ_ASSERT(opd->type() == MIRType::Float32); + + define(new(alloc()) + LTruncateFToInt32(useRegister(opd), tempFloat32()), ins); +} + +void +LIRGeneratorLoongArch64::visitRandom(MRandom* ins) +{ + LRandom *lir = new(alloc()) LRandom(temp(), temp(), temp()); + defineFixed(lir, ins, LFloatReg(ReturnDoubleReg)); +} + +void +LIRGeneratorLoongArch64::visitSignExtendInt64(MSignExtendInt64* ins) +{ + defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins); +} diff --git a/js/src/jit/loongarch64/Lowering-loongarch64.h b/js/src/jit/loongarch64/Lowering-loongarch64.h new file mode 100644 index 0000000000..e1d8e483c0 --- /dev/null +++ b/js/src/jit/loongarch64/Lowering-loongarch64.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#ifndef jit_loongarch64_Lowering_loongarch64_h +#define jit_loongarch64_Lowering_loongarch64_h + +#include "jit/mips-shared/Lowering-mips-shared.h" + +namespace js { +namespace jit { + +class LIRGeneratorLoongArch64 : public LIRGeneratorMIPSShared +{ + protected: + LIRGeneratorLoongArch64(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph) + : LIRGeneratorMIPSShared(gen, graph, lirGraph) + { } + + protected: + void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t); + void defineInt64Phi(MPhi*, size_t); + + LBoxAllocation useBoxFixed(MDefinition* mir, Register reg1, Register reg2, + bool useAtStart = false); + + inline LDefinition tempToUnbox() { + return temp(); + } + + bool needTempForPostBarrier() { return true; } + + void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex); + void defineUntypedPhi(MPhi* phi, size_t lirIndex); + + void lowerTruncateDToInt32(MTruncateToInt32* ins); + void lowerTruncateFToInt32(MTruncateToInt32* ins); + + void lowerDivI64(MDiv* div); + void lowerModI64(MMod* mod); + void lowerUDivI64(MDiv* div); + void lowerUModI64(MMod* mod); + + public: + void visitBox(MBox* box); + void visitUnbox(MUnbox* unbox); + void visitReturn(MReturn* ret); + void visitRandom(MRandom* ins); + void visitSignExtendInt64(MSignExtendInt64* ins); +}; + +typedef LIRGeneratorLoongArch64 LIRGeneratorSpecific; + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_Lowering_loongarch64_h */ diff --git a/js/src/jit/loongarch64/MacroAssembler-loongarch64-inl.h b/js/src/jit/loongarch64/MacroAssembler-loongarch64-inl.h new file mode 100644 index 0000000000..9a681446fa --- /dev/null +++ b/js/src/jit/loongarch64/MacroAssembler-loongarch64-inl.h @@ -0,0 +1,1607 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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/. */ + +#ifndef jit_loongarch64_MacroAssembler_loongarch64_inl_h +#define jit_loongarch64_MacroAssembler_loongarch64_inl_h + +#include "jit/loongarch64/MacroAssembler-loongarch64.h" + +namespace js { +namespace jit { + +//{{{ check_macroassembler_style + +void MacroAssembler::move64(Register64 src, Register64 dest) { + movePtr(src.reg, dest.reg); +} + +void MacroAssembler::move64(Imm64 imm, Register64 dest) { + movePtr(ImmWord(imm.value), dest.reg); +} +void MacroAssembler::moveFloat32ToGPR(FloatRegister src, Register dest) { + moveFromFloat32(src, dest); +} + +void MacroAssembler::moveGPRToFloat32(Register src, FloatRegister dest) { + moveToFloat32(src, dest); +} + +void MacroAssembler::move8SignExtend(Register src, Register dest) { + as_ext_w_b(dest, src); +} + +void MacroAssembler::move16SignExtend(Register src, Register dest) { + as_ext_w_h(dest, src); +} +// =============================================================== +// Load instructions +// =============================================================== +// Logical instructions + +void MacroAssembler::not32(Register reg) { as_nor(reg, reg, zero); } +void MacroAssembler::andPtr(Register src, Register dest) { + as_and(dest, dest, src); +} + +void MacroAssembler::andPtr(Imm32 imm, Register dest) { + ma_and(dest, dest, imm); +} + +void MacroAssembler::and64(Imm64 imm, Register64 dest) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, ImmWord(imm.value)); + as_and(dest.reg, dest.reg, scratch); +} + +void MacroAssembler::and64(Register64 src, Register64 dest) { + as_and(dest.reg, dest.reg, src.reg); +} + +void MacroAssembler::and64(const Operand& src, Register64 dest) { + if (src.getTag() == Operand::MEM) { + ScratchRegisterScope scratch(*this); + Register64 scratch64(scratch); + + load64(src.toAddress(), scratch64); + and64(scratch64, dest); + } else { + and64(Register64(src.toReg()), dest); + } +} + +void MacroAssembler::and32(Register src, Register dest) { + as_and(dest, dest, src); +} + +void MacroAssembler::and32(Imm32 imm, Register dest) { + ma_and(dest, dest, imm); +} + +void MacroAssembler::and32(Imm32 imm, const Address& dest) { + if (dest.base == SecondScratchReg) { + ScratchRegisterScope scratch(asMasm()); + load32(dest, scratch); + and32(imm, scratch); + store32(scratch, dest); + return; + } + + SecondScratchRegisterScope scratch2(asMasm()); + load32(dest, scratch2); + and32(imm, scratch2); + store32(scratch2, dest); +} + +void MacroAssembler::and32(const Address& src, Register dest) { + SecondScratchRegisterScope scratch2(asMasm()); + load32(src, scratch2); + as_and(dest, dest, scratch2); +} + +void MacroAssembler::or64(Imm64 imm, Register64 dest) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, ImmWord(imm.value)); + as_or(dest.reg, dest.reg, scratch); +} + +void MacroAssembler::or32(Register src, Register dest) { + as_or(dest, dest, src); +} + +void MacroAssembler::or32(Imm32 imm, Register dest) { ma_or(dest, dest, imm); } + +void MacroAssembler::or32(Imm32 imm, const Address& dest) { + if (dest.base == SecondScratchReg) { + ScratchRegisterScope scratch(asMasm()); + load32(dest, scratch); + or32(imm, scratch); + store32(scratch, dest); + return; + } + + SecondScratchRegisterScope scratch2(asMasm()); + load32(dest, scratch2); + or32(imm, scratch2); + store32(scratch2, dest); +} + +void MacroAssembler::xor64(Imm64 imm, Register64 dest) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, ImmWord(imm.value)); + as_xor(dest.reg, dest.reg, scratch); +} + +void MacroAssembler::orPtr(Register src, Register dest) { + as_or(dest, dest, src); +} + +void MacroAssembler::orPtr(Imm32 imm, Register dest) { ma_or(dest, dest, imm); } + +void MacroAssembler::or64(Register64 src, Register64 dest) { + as_or(dest.reg, dest.reg, src.reg); +} + +void MacroAssembler::or64(const Operand& src, Register64 dest) { + if (src.getTag() == Operand::MEM) { + ScratchRegisterScope scratch(asMasm()); + Register64 scratch64(scratch); + + load64(src.toAddress(), scratch64); + or64(scratch64, dest); + } else { + or64(Register64(src.toReg()), dest); + } +} + +void MacroAssembler::xor64(Register64 src, Register64 dest) { + as_xor(dest.reg, dest.reg, src.reg); +} + +void MacroAssembler::xor64(const Operand& src, Register64 dest) { + if (src.getTag() == Operand::MEM) { + ScratchRegisterScope scratch(asMasm()); + Register64 scratch64(scratch); + + load64(src.toAddress(), scratch64); + xor64(scratch64, dest); + } else { + xor64(Register64(src.toReg()), dest); + } +} + +void MacroAssembler::xorPtr(Register src, Register dest) { + as_xor(dest, dest, src); +} + +void MacroAssembler::xorPtr(Imm32 imm, Register dest) { + ma_xor(dest, dest, imm); +} + +void MacroAssembler::xor32(Register src, Register dest) { + as_xor(dest, dest, src); +} + +void MacroAssembler::xor32(Imm32 imm, Register dest) { + ma_xor(dest, dest, imm); +} + +// =============================================================== +// Swap instructions +// =============================================================== +// Arithmetic functions + +void MacroAssembler::addPtr(Register src, Register dest) { + as_add_d(dest, dest, src); +} + +void MacroAssembler::addPtr(Imm32 imm, Register dest) { + ma_add_d(dest, dest, imm); +} + +void MacroAssembler::addPtr(ImmWord imm, Register dest) { + ScratchRegisterScope scratch(asMasm()); + movePtr(imm, scratch); + addPtr(scratch, dest); +} + +void MacroAssembler::add64(Register64 src, Register64 dest) { + addPtr(src.reg, dest.reg); +} + +void MacroAssembler::add64(const Operand& src, Register64 dest) { + if (src.getTag() == Operand::MEM) { + ScratchRegisterScope scratch(asMasm()); + Register64 scratch64(scratch); + + load64(src.toAddress(), scratch64); + add64(scratch64, dest); + } else { + add64(Register64(src.toReg()), dest); + } +} + +void MacroAssembler::add64(Imm32 imm, Register64 dest) { + ma_add_d(dest.reg, dest.reg, imm); +} + +void MacroAssembler::add64(Imm64 imm, Register64 dest) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(dest.reg != scratch); + mov(ImmWord(imm.value), scratch); + as_add_d(dest.reg, dest.reg, scratch); +} + +void MacroAssembler::add32(Register src, Register dest) { + as_add_w(dest, dest, src); +} + +void MacroAssembler::add32(Imm32 imm, Register dest) { + ma_add_w(dest, dest, imm); +} + +void MacroAssembler::add32(Imm32 imm, const Address& dest) { + if (dest.base == SecondScratchReg) { + ScratchRegisterScope scratch(asMasm()); + load32(dest, scratch); + ma_add_w(scratch, scratch, imm); + store32(scratch, dest); + return; + } + + SecondScratchRegisterScope scratch2(asMasm()); + load32(dest, scratch2); + ma_add_w(scratch2, scratch2, imm); + store32(scratch2, dest); +} + +void MacroAssembler::addPtr(Imm32 imm, const Address& dest) { + if (dest.base == ScratchRegister) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(dest, scratch2); + addPtr(imm, scratch2); + storePtr(scratch2, dest); + return; + } + + ScratchRegisterScope scratch(asMasm()); + loadPtr(dest, scratch); + addPtr(imm, scratch); + storePtr(scratch, dest); +} + +void MacroAssembler::addPtr(const Address& src, Register dest) { + ScratchRegisterScope scratch(asMasm()); + loadPtr(src, scratch); + addPtr(scratch, dest); +} + +void MacroAssembler::addDouble(FloatRegister src, FloatRegister dest) { + as_fadd_d(dest, dest, src); +} + +void MacroAssembler::addFloat32(FloatRegister src, FloatRegister dest) { + as_fadd_s(dest, dest, src); +} +void MacroAssembler::subPtr(Register src, Register dest) { + as_sub_d(dest, dest, src); +} + +void MacroAssembler::subPtr(Imm32 imm, Register dest) { + ma_sub_d(dest, dest, imm); +} + +void MacroAssembler::sub64(Register64 src, Register64 dest) { + as_sub_d(dest.reg, dest.reg, src.reg); +} + +void MacroAssembler::sub64(const Operand& src, Register64 dest) { + if (src.getTag() == Operand::MEM) { + ScratchRegisterScope scratch(asMasm()); + Register64 scratch64(scratch); + + load64(src.toAddress(), scratch64); + sub64(scratch64, dest); + } else { + sub64(Register64(src.toReg()), dest); + } +} + +void MacroAssembler::sub64(Imm64 imm, Register64 dest) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(dest.reg != scratch); + mov(ImmWord(imm.value), scratch); + as_sub_d(dest.reg, dest.reg, scratch); +} + +void MacroAssembler::sub32(Register src, Register dest) { + as_sub_w(dest, dest, src); +} + +void MacroAssembler::sub32(Imm32 imm, Register dest) { + ma_sub_w(dest, dest, imm); +} + +void MacroAssembler::sub32(const Address& src, Register dest) { + SecondScratchRegisterScope scratch2(asMasm()); + load32(src, scratch2); + as_sub_w(dest, dest, scratch2); +} + +void MacroAssembler::subPtr(Register src, const Address& dest) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(dest, scratch2); + subPtr(src, scratch2); + storePtr(scratch2, dest); +} + +void MacroAssembler::subPtr(const Address& addr, Register dest) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(addr, scratch2); + subPtr(scratch2, dest); +} + +void MacroAssembler::subDouble(FloatRegister src, FloatRegister dest) { + as_fsub_d(dest, dest, src); +} + +void MacroAssembler::subFloat32(FloatRegister src, FloatRegister dest) { + as_fsub_s(dest, dest, src); +} + +void MacroAssembler::mul64(Imm64 imm, const Register64& dest) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(dest.reg != scratch); + mov(ImmWord(imm.value), scratch); + as_mul_d(dest.reg, dest.reg, scratch); +} + +void MacroAssembler::mul64(Imm64 imm, const Register64& dest, + const Register temp) { + MOZ_ASSERT(temp == Register::Invalid()); + mul64(imm, dest); +} + +void MacroAssembler::mul64(const Register64& src, const Register64& dest, + const Register temp) { + MOZ_ASSERT(temp == Register::Invalid()); + as_mul_d(dest.reg, dest.reg, src.reg); +} + +void MacroAssembler::mul64(const Operand& src, const Register64& dest, + const Register temp) { + if (src.getTag() == Operand::MEM) { + ScratchRegisterScope scratch(asMasm()); + Register64 scratch64(scratch); + + load64(src.toAddress(), scratch64); + mul64(scratch64, dest, temp); + } else { + mul64(Register64(src.toReg()), dest, temp); + } +} +void MacroAssembler::mulBy3(Register src, Register dest) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(src != scratch); + as_add_d(scratch, src, src); + as_add_d(dest, scratch, src); +} + +void MacroAssembler::mul32(Register rhs, Register srcDest) { + as_mul_w(srcDest, srcDest, rhs); +} + +void MacroAssembler::mulFloat32(FloatRegister src, FloatRegister dest) { + as_fmul_s(dest, dest, src); +} + +void MacroAssembler::mulDouble(FloatRegister src, FloatRegister dest) { + as_fmul_d(dest, dest, src); +} + +void MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, + FloatRegister dest) { + ScratchRegisterScope scratch(asMasm()); + ScratchDoubleScope fpscratch(asMasm()); + movePtr(imm, scratch); + loadDouble(Address(scratch, 0), fpscratch); + mulDouble(fpscratch, dest); +} + +void MacroAssembler::inc64(AbsoluteAddress dest) { + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch, ImmWord(uintptr_t(dest.addr))); + as_ld_d(scratch2, scratch, 0); + as_addi_d(scratch2, scratch2, 1); + as_st_d(scratch2, scratch, 0); +} + +void MacroAssembler::quotient32(Register rhs, Register srcDest, + bool isUnsigned) { + if (isUnsigned) { + as_div_wu(srcDest, srcDest, rhs); + } else { + as_div_w(srcDest, srcDest, rhs); + } +} + +void MacroAssembler::remainder32(Register rhs, Register srcDest, + bool isUnsigned) { + if (isUnsigned) { + as_mod_wu(srcDest, srcDest, rhs); + } else { + as_mod_w(srcDest, srcDest, rhs); + } +} + +void MacroAssembler::divFloat32(FloatRegister src, FloatRegister dest) { + as_fdiv_s(dest, dest, src); +} + +void MacroAssembler::divDouble(FloatRegister src, FloatRegister dest) { + as_fdiv_d(dest, dest, src); +} + +void MacroAssembler::neg64(Register64 reg) { as_sub_d(reg.reg, zero, reg.reg); } +void MacroAssembler::neg32(Register reg) { as_sub_w(reg, zero, reg); } + +void MacroAssembler::negateDouble(FloatRegister reg) { as_fneg_d(reg, reg); } + +void MacroAssembler::negateFloat(FloatRegister reg) { as_fneg_s(reg, reg); } +void MacroAssembler::absFloat32(FloatRegister src, FloatRegister dest) { + as_fabs_s(dest, src); +} + +void MacroAssembler::absDouble(FloatRegister src, FloatRegister dest) { + as_fabs_d(dest, src); +} + +void MacroAssembler::sqrtFloat32(FloatRegister src, FloatRegister dest) { + as_fsqrt_s(dest, src); +} + +void MacroAssembler::sqrtDouble(FloatRegister src, FloatRegister dest) { + as_fsqrt_d(dest, src); +} + +void MacroAssembler::minFloat32(FloatRegister other, FloatRegister srcDest, + bool handleNaN) { + minMaxFloat32(srcDest, other, handleNaN, false); +} + +void MacroAssembler::minDouble(FloatRegister other, FloatRegister srcDest, + bool handleNaN) { + minMaxDouble(srcDest, other, handleNaN, false); +} + +void MacroAssembler::maxFloat32(FloatRegister other, FloatRegister srcDest, + bool handleNaN) { + minMaxFloat32(srcDest, other, handleNaN, true); +} + +void MacroAssembler::maxDouble(FloatRegister other, FloatRegister srcDest, + bool handleNaN) { + minMaxDouble(srcDest, other, handleNaN, true); +} + +// =============================================================== +// Shift functions + +void MacroAssembler::lshift32(Register src, Register dest) { + as_sll_w(dest, dest, src); +} + +void MacroAssembler::lshift32(Imm32 imm, Register dest) { + as_slli_w(dest, dest, imm.value % 32); +} +void MacroAssembler::lshift64(Register shift, Register64 dest) { + as_sll_d(dest.reg, dest.reg, shift); +} + +void MacroAssembler::lshift64(Imm32 imm, Register64 dest) { + MOZ_ASSERT(0 <= imm.value && imm.value < 64); + as_slli_d(dest.reg, dest.reg, imm.value); +} + +void MacroAssembler::lshiftPtr(Imm32 imm, Register dest) { + MOZ_ASSERT(0 <= imm.value && imm.value < 64); + as_slli_d(dest, dest, imm.value); +} + +void MacroAssembler::rshift32(Register src, Register dest) { + as_srl_w(dest, dest, src); +} + +void MacroAssembler::rshift32(Imm32 imm, Register dest) { + as_srli_w(dest, dest, imm.value % 32); +} +void MacroAssembler::rshift32Arithmetic(Register src, Register dest) { + as_sra_w(dest, dest, src); +} + +void MacroAssembler::rshift32Arithmetic(Imm32 imm, Register dest) { + as_srai_w(dest, dest, imm.value % 32); +} +void MacroAssembler::rshift64(Register shift, Register64 dest) { + as_srl_d(dest.reg, dest.reg, shift); +} + +void MacroAssembler::rshift64(Imm32 imm, Register64 dest) { + MOZ_ASSERT(0 <= imm.value && imm.value < 64); + as_srli_d(dest.reg, dest.reg, imm.value); +} + +void MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest) { + MOZ_ASSERT(0 <= imm.value && imm.value < 64); + as_srai_d(dest.reg, dest.reg, imm.value); +} + +void MacroAssembler::rshift64Arithmetic(Register shift, Register64 dest) { + as_sra_d(dest.reg, dest.reg, shift); +} + +void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { + MOZ_ASSERT(0 <= imm.value && imm.value < 64); + as_srli_d(dest, dest, imm.value); +} + +void MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) { + MOZ_ASSERT(0 <= imm.value && imm.value < 64); + as_srai_d(dest, dest, imm.value); +} + +// =============================================================== +// Rotation functions + +void MacroAssembler::rotateLeft(Register count, Register input, Register dest) { + ScratchRegisterScope scratch(asMasm()); + as_sub_w(scratch, zero, count); + as_rotr_w(dest, input, scratch); +} + +void MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest) { + as_rotri_w(dest, input, (32 - count.value) & 31); +} + +void MacroAssembler::rotateLeft64(Register count, Register64 src, + Register64 dest) { + rotateLeft64(count, src, dest, Register::Invalid()); +} + +void MacroAssembler::rotateLeft64(Register count, Register64 src, + Register64 dest, Register temp) { + MOZ_ASSERT(temp == Register::Invalid()); + ScratchRegisterScope scratch(asMasm()); + as_sub_d(scratch, zero, count); + as_rotr_d(dest.reg, src.reg, scratch); +} + +void MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest) { + rotateLeft64(count, src, dest, Register::Invalid()); +} + +void MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest, + Register temp) { + MOZ_ASSERT(temp == Register::Invalid()); + as_rotri_d(dest.reg, src.reg, (64 - count.value) & 63); +} + +void MacroAssembler::rotateRight(Register count, Register input, + Register dest) { + as_rotr_w(dest, input, count); +} + +void MacroAssembler::rotateRight(Imm32 count, Register input, Register dest) { + as_rotri_w(dest, input, count.value & 31); +} + +void MacroAssembler::rotateRight64(Register count, Register64 src, + Register64 dest) { + rotateRight64(count, src, dest, Register::Invalid()); +} + +void MacroAssembler::rotateRight64(Register count, Register64 src, + Register64 dest, Register temp) { + MOZ_ASSERT(temp == Register::Invalid()); + as_rotr_d(dest.reg, src.reg, count); +} + +void MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest) { + rotateRight64(count, src, dest, Register::Invalid()); +} + +void MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest, + Register temp) { + MOZ_ASSERT(temp == Register::Invalid()); + as_rotri_d(dest.reg, src.reg, count.value & 63); +} + +// Bit counting functions + +void MacroAssembler::clz64(Register64 src, Register dest) { + as_clz_d(dest, src.reg); +} + +void MacroAssembler::ctz64(Register64 src, Register dest) { + as_ctz_d(dest, src.reg); +} + +void MacroAssembler::popcnt64(Register64 input, Register64 output, + Register tmp) { + ScratchRegisterScope scratch(asMasm()); + as_or(output.reg, input.reg, zero); + as_srai_d(tmp, input.reg, 1); + ma_li(scratch, Imm32(0x55555555)); + as_bstrins_d(scratch, scratch, 63, 32); + as_and(tmp, tmp, scratch); + as_sub_d(output.reg, output.reg, tmp); + as_srai_d(tmp, output.reg, 2); + ma_li(scratch, Imm32(0x33333333)); + as_bstrins_d(scratch, scratch, 63, 32); + as_and(output.reg, output.reg, scratch); + as_and(tmp, tmp, scratch); + as_add_d(output.reg, output.reg, tmp); + as_srli_d(tmp, output.reg, 4); + as_add_d(output.reg, output.reg, tmp); + ma_li(scratch, Imm32(0xF0F0F0F)); + as_bstrins_d(scratch, scratch, 63, 32); + as_and(output.reg, output.reg, scratch); + ma_li(tmp, Imm32(0x1010101)); + as_bstrins_d(tmp, tmp, 63, 32); + as_mul_d(output.reg, output.reg, tmp); + as_srai_d(output.reg, output.reg, 56); +} + +void MacroAssembler::clz32(Register src, Register dest, bool knownNotZero) { + as_clz_w(dest, src); +} + +void MacroAssembler::ctz32(Register src, Register dest, bool knownNotZero) { + as_ctz_w(dest, src); +} + +void MacroAssembler::popcnt32(Register input, Register output, Register tmp) { + // Equivalent to GCC output of mozilla::CountPopulation32() + as_or(output, input, zero); + as_srai_w(tmp, input, 1); + ma_and(tmp, tmp, Imm32(0x55555555)); + as_sub_w(output, output, tmp); + as_srai_w(tmp, output, 2); + ma_and(output, output, Imm32(0x33333333)); + ma_and(tmp, tmp, Imm32(0x33333333)); + as_add_w(output, output, tmp); + as_srli_w(tmp, output, 4); + as_add_w(output, output, tmp); + ma_and(output, output, Imm32(0xF0F0F0F)); + as_slli_w(tmp, output, 8); + as_add_w(output, output, tmp); + as_slli_w(tmp, output, 16); + as_add_w(output, output, tmp); + as_srai_w(output, output, 24); +} + +// =============================================================== +// Condition functions +// Also see below for specializations of cmpPtrSet. +template +void MacroAssembler::cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest) { + ma_cmp_set(dest, lhs, rhs, cond); +} +template +void MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest) { + ma_cmp_set(dest, lhs, rhs, cond); +} + +// =============================================================== +// Branch functions +template +void MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, + L label) { + ma_b(lhs, rhs, label, cond); +} + +template +void MacroAssembler::branch32(Condition cond, Register lhs, Imm32 imm, + L label) { + ma_b(lhs, imm, label, cond); +} + +void MacroAssembler::branch32(Condition cond, const Address& lhs, Register rhs, + Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + load32(lhs, scratch2); + ma_b(scratch2, rhs, label, cond); +} + +void MacroAssembler::branch32(Condition cond, const Address& lhs, Imm32 rhs, + Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + load32(lhs, scratch2); + ma_b(scratch2, rhs, label, cond); +} + +void MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, + Register rhs, Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + load32(lhs, scratch2); + ma_b(scratch2, rhs, label, cond); +} + +void MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, + Imm32 rhs, Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + load32(lhs, scratch2); + ma_b(scratch2, rhs, label, cond); +} + +void MacroAssembler::branch32(Condition cond, const BaseIndex& lhs, Imm32 rhs, + Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + load32(lhs, scratch2); + ma_b(scratch2, rhs, label, cond); +} + +void MacroAssembler::branch32(Condition cond, wasm::SymbolicAddress addr, + Imm32 imm, Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + load32(addr, scratch2); + ma_b(scratch2, imm, label, cond); +} + +void MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, + Label* success, Label* fail) { + MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal || + cond == Assembler::LessThan || + cond == Assembler::LessThanOrEqual || + cond == Assembler::GreaterThan || + cond == Assembler::GreaterThanOrEqual || + cond == Assembler::Below || cond == Assembler::BelowOrEqual || + cond == Assembler::Above || cond == Assembler::AboveOrEqual, + "other condition codes not supported"); + + branchPtr(cond, lhs.reg, ImmWord(val.value), success); + if (fail) { + jump(fail); + } +} + +void MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, + Label* success, Label* fail) { + MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal || + cond == Assembler::LessThan || + cond == Assembler::LessThanOrEqual || + cond == Assembler::GreaterThan || + cond == Assembler::GreaterThanOrEqual || + cond == Assembler::Below || cond == Assembler::BelowOrEqual || + cond == Assembler::Above || cond == Assembler::AboveOrEqual, + "other condition codes not supported"); + + branchPtr(cond, lhs.reg, rhs.reg, success); + if (fail) { + jump(fail); + } +} + +void MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, + Label* label) { + MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal, + "other condition codes not supported"); + + branchPtr(cond, lhs, ImmWord(val.value), label); +} + +void MacroAssembler::branch64(Condition cond, const Address& lhs, + const Address& rhs, Register scratch, + Label* label) { + MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal, + "other condition codes not supported"); + MOZ_ASSERT(lhs.base != scratch); + MOZ_ASSERT(rhs.base != scratch); + + loadPtr(rhs, scratch); + branchPtr(cond, lhs, scratch, label); +} + +template +void MacroAssembler::branchPtr(Condition cond, Register lhs, Register rhs, + L label) { + ma_b(lhs, rhs, label, cond); +} + +void MacroAssembler::branchPtr(Condition cond, Register lhs, Imm32 rhs, + Label* label) { + ma_b(lhs, rhs, label, cond); +} + +void MacroAssembler::branchPtr(Condition cond, Register lhs, ImmPtr rhs, + Label* label) { + ma_b(lhs, rhs, label, cond); +} + +void MacroAssembler::branchPtr(Condition cond, Register lhs, ImmGCPtr rhs, + Label* label) { + ma_b(lhs, rhs, label, cond); +} + +void MacroAssembler::branchPtr(Condition cond, Register lhs, ImmWord rhs, + Label* label) { + ma_b(lhs, rhs, label, cond); +} + +template +void MacroAssembler::branchPtr(Condition cond, const Address& lhs, Register rhs, + L label) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + branchPtr(cond, scratch2, rhs, label); +} + +void MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmPtr rhs, + Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + branchPtr(cond, scratch2, rhs, label); +} + +void MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmGCPtr rhs, + Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + branchPtr(cond, scratch2, rhs, label); +} + +void MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmWord rhs, + Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + branchPtr(cond, scratch2, rhs, label); +} + +void MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, + Register rhs, Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + branchPtr(cond, scratch2, rhs, label); +} + +void MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, + ImmWord rhs, Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + branchPtr(cond, scratch2, rhs, label); +} + +void MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, + Register rhs, Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + branchPtr(cond, scratch2, rhs, label); +} + +template +CodeOffsetJump MacroAssembler::branchPtrWithPatch(Condition cond, Register lhs, + T rhs, + RepatchLabel* label) { + movePtr(rhs, ScratchRegister); + Label skipJump; + ma_b(lhs, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); + CodeOffsetJump off = jumpWithPatch(label); + bind(&skipJump); + return off; +} + +template +CodeOffsetJump MacroAssembler::branchPtrWithPatch(Condition cond, Address lhs, + T rhs, + RepatchLabel* label) { + loadPtr(lhs, SecondScratchReg); + movePtr(rhs, ScratchRegister); + Label skipJump; + ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), + ShortJump); + CodeOffsetJump off = jumpWithPatch(label); + bind(&skipJump); + return off; +} + +void MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs, + Register rhs, Label* label) { + branchPtr(cond, lhs, rhs, label); +} + +void MacroAssembler::branchFloat(DoubleCondition cond, FloatRegister lhs, + FloatRegister rhs, Label* label) { + ma_bc_s(lhs, rhs, label, cond); +} + +void MacroAssembler::branchTruncateFloat32MaybeModUint32(FloatRegister src, + Register dest, + Label* fail) { + ScratchRegisterScope scratch(asMasm()); + ScratchDoubleScope fpscratch(asMasm()); + as_ftintrz_l_s(fpscratch, src); + as_movfcsr2gr(scratch); + moveFromDouble(fpscratch, dest); + MOZ_ASSERT(Assembler::CauseV < 32); + as_bstrpick_w(scratch, scratch, Assembler::CauseV, Assembler::CauseV); + ma_b(scratch, Imm32(0), fail, Assembler::NotEqual); + + as_slli_w(dest, dest, 0); +} + +void MacroAssembler::branchTruncateFloat32ToInt32(FloatRegister src, + Register dest, Label* fail) { + convertFloat32ToInt32(src, dest, fail, false); +} + +void MacroAssembler::branchDouble(DoubleCondition cond, FloatRegister lhs, + FloatRegister rhs, Label* label) { + ma_bc_d(lhs, rhs, label, cond); +} + +void MacroAssembler::branchTruncateDoubleMaybeModUint32(FloatRegister src, + Register dest, + Label* fail) { + ScratchRegisterScope scratch(asMasm()); + ScratchDoubleScope fpscratch(asMasm()); + as_ftintrz_l_d(fpscratch, src); + as_movfcsr2gr(scratch); + moveFromDouble(fpscratch, dest); + MOZ_ASSERT(Assembler::CauseV < 32); + as_bstrpick_w(scratch, scratch, Assembler::CauseV, Assembler::CauseV); + ma_b(scratch, Imm32(0), fail, Assembler::NotEqual); + + as_slli_w(dest, dest, 0); +} + +void MacroAssembler::branchTruncateDoubleToInt32(FloatRegister src, + Register dest, Label* fail) { + convertDoubleToInt32(src, dest, fail, false); +} + +template +void MacroAssembler::branchAdd32(Condition cond, T src, Register dest, + L overflow) { + switch (cond) { + case Overflow: + ma_add32TestOverflow(dest, dest, src, overflow); + break; + case CarryClear: + case CarrySet: + ma_add32TestCarry(cond, dest, dest, src, overflow); + break; + case Equal: + case NotEqual: + case Zero: + case NonZero: + case Signed: + case NotSigned: + add32(src, dest); + ma_b(dest, Imm32(0), overflow, cond); + break; + default: + MOZ_CRASH("Unexpected branchAdd32 condition"); + } +} + +// the type of 'T src' maybe a Register, maybe a Imm32,depends on who call it. +template +void MacroAssembler::branchSub32(Condition cond, T src, Register dest, + Label* overflow) { + switch (cond) { + case Overflow: + ma_sub32TestOverflow(dest, dest, src, overflow); + break; + case CarrySet: + case CarryClear: { + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + Register negSrc = dest == scratch ? Register(scratch2) : Register(scratch); + ma_sub_w(negSrc, zero, src); + // a - b borrows iff a + (-b) does not carry. + ma_add32TestCarry(cond == CarrySet ? CarryClear : CarrySet, dest, dest, + negSrc, overflow); + break; + } + case Equal: + case NotEqual: + case NonZero: + case Zero: + case Signed: + case NotSigned: + sub32(src, dest); + ma_b(dest, Imm32(0), overflow, cond); + break; + default: + MOZ_CRASH("Unexpected branchSub32 condition"); + } +} +void MacroAssembler::decBranchPtr(Condition cond, Register lhs, Imm32 rhs, + Label* label) { + subPtr(rhs, lhs); + branchPtr(cond, lhs, Imm32(0), label); +} + +template +void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, + L label) { + MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || + cond == NotSigned); + if (lhs == rhs) { + ma_b(lhs, rhs, label, cond); + } else { + ScratchRegisterScope scratch(asMasm()); + as_and(scratch, lhs, rhs); + ma_b(scratch, scratch, label, cond); + } +} + +template +void MacroAssembler::branchTest32(Condition cond, Register lhs, Imm32 rhs, + L label) { + MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || + cond == NotSigned); + SecondScratchRegisterScope scratch2(asMasm()); + ma_and(scratch2, lhs, rhs); + ma_b(scratch2, scratch2, label, cond); +} + +void MacroAssembler::branchTest32(Condition cond, const Address& lhs, Imm32 rhs, + Label* label) { + MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || + cond == NotSigned); + SecondScratchRegisterScope scratch2(asMasm()); + load32(lhs, scratch2); + and32(rhs, scratch2); + ma_b(scratch2, scratch2, label, cond); +} + +void MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs, + Imm32 rhs, Label* label) { + MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || + cond == NotSigned); + SecondScratchRegisterScope scratch2(asMasm()); + load32(lhs, scratch2); + and32(rhs, scratch2); + ma_b(scratch2, scratch2, label, cond); +} + +template +void MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, + L label) { + MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || + cond == NotSigned); + if (lhs == rhs) { + ma_b(lhs, rhs, label, cond); + } else { + ScratchRegisterScope scratch(asMasm()); + as_and(scratch, lhs, rhs); + ma_b(scratch, scratch, label, cond); + } +} + +void MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs, + Label* label) { + MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || + cond == NotSigned); + ScratchRegisterScope scratch(asMasm()); + ma_and(scratch, lhs, rhs); + ma_b(scratch, scratch, label, cond); +} + +void MacroAssembler::branchTestPtr(Condition cond, const Address& lhs, + Imm32 rhs, Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + branchTestPtr(cond, scratch2, rhs, label); +} + +template +void MacroAssembler::branchTest64(Condition cond, Register64 lhs, + Register64 rhs, Register temp, L label) { + branchTestPtr(cond, lhs.reg, rhs.reg, label); +} + +void MacroAssembler::branchTestUndefined(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_UNDEFINED), label, cond); +} + +void MacroAssembler::branchTestUndefined(Condition cond, + const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestUndefined(cond, scratch2, label); +} + +void MacroAssembler::branchTestUndefined(Condition cond, const Address& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestUndefined(cond, tag, label); +} + +void MacroAssembler::branchTestUndefined(Condition cond, + const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestUndefined(cond, tag, label); +} + +void MacroAssembler::branchTestInt32(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_INT32), label, cond); +} + +void MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestInt32(cond, scratch2, label); +} + +void MacroAssembler::branchTestInt32(Condition cond, const Address& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestInt32(cond, tag, label); +} + +void MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestInt32(cond, tag, label); +} + +void MacroAssembler::branchTestInt32Truthy(bool b, const ValueOperand& value, + Label* label) { + ScratchRegisterScope scratch(*this); + as_bstrpick_d(scratch, value.valueReg(), 31, 0); + ma_b(scratch, scratch, label, b ? NonZero : Zero); +} + +void MacroAssembler::branchTestDouble(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + Condition actual = (cond == Equal) ? BelowOrEqual : Above; + ma_b(tag, ImmTag(JSVAL_TAG_MAX_DOUBLE), label, actual); +} + +void MacroAssembler::branchTestDouble(Condition cond, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestDouble(cond, scratch2, label); +} + +void MacroAssembler::branchTestDouble(Condition cond, const Address& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestDouble(cond, tag, label); +} + +void MacroAssembler::branchTestDouble(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestDouble(cond, tag, label); +} + +void MacroAssembler::branchTestDoubleTruthy(bool b, FloatRegister value, + Label* label) { + ScratchDoubleScope fpscratch(*this); + ma_lid(fpscratch, 0.0); + DoubleCondition cond = b ? DoubleNotEqual : DoubleEqualOrUnordered; + ma_bc_d(value, fpscratch, label, cond); +} + +void MacroAssembler::branchTestNumber(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + Condition actual = cond == Equal ? BelowOrEqual : Above; + ma_b(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET), label, actual); +} + +void MacroAssembler::branchTestNumber(Condition cond, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestNumber(cond, scratch2, label); +} + +void MacroAssembler::branchTestBoolean(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_BOOLEAN), label, cond); +} + +void MacroAssembler::branchTestBoolean(Condition cond, + const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestBoolean(cond, scratch2, label); +} + +void MacroAssembler::branchTestBoolean(Condition cond, const Address& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestBoolean(cond, tag, label); +} + +void MacroAssembler::branchTestBoolean(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestBoolean(cond, tag, label); +} + +void MacroAssembler::branchTestBooleanTruthy(bool b, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + unboxBoolean(value, scratch2); + ma_b(scratch2, scratch2, label, b ? NonZero : Zero); +} + +void MacroAssembler::branchTestString(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_STRING), label, cond); +} + +void MacroAssembler::branchTestString(Condition cond, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestString(cond, scratch2, label); +} + +void MacroAssembler::branchTestString(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestString(cond, tag, label); +} + +void MacroAssembler::branchTestStringTruthy(bool b, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + unboxString(value, scratch2); + load32(Address(scratch2, JSString::offsetOfLength()), scratch2); + ma_b(scratch2, Imm32(0), label, b ? NotEqual : Equal); +} + +void MacroAssembler::branchTestSymbol(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_SYMBOL), label, cond); +} + +void MacroAssembler::branchTestSymbol(Condition cond, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestSymbol(cond, scratch2, label); +} + +void MacroAssembler::branchTestSymbol(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestSymbol(cond, tag, label); +} + +void MacroAssembler::branchTestBigInt(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_BIGINT), label, cond); +} + +void MacroAssembler::branchTestBigInt(Condition cond, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestBigInt(cond, scratch2, label); +} + +void MacroAssembler::branchTestBigInt(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + computeEffectiveAddress(address, scratch2); + splitTag(scratch2, scratch2); + branchTestBigInt(cond, scratch2, label); +} + +void MacroAssembler::branchTestBigIntTruthy(bool b, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + unboxBigInt(value, scratch2); + loadPtr(Address(scratch2, BigInt::offsetOfLengthSignAndReservedBits()), scratch2); + ma_b(scratch2, ImmWord(0), label, b ? NotEqual : Equal); +} + +void MacroAssembler::branchTestNull(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_NULL), label, cond); +} + +void MacroAssembler::branchTestNull(Condition cond, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestNull(cond, scratch2, label); +} + +void MacroAssembler::branchTestNull(Condition cond, const Address& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestNull(cond, tag, label); +} + +void MacroAssembler::branchTestNull(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestNull(cond, tag, label); +} + +void MacroAssembler::branchTestObject(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_OBJECT), label, cond); +} + +void MacroAssembler::branchTestObject(Condition cond, const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestObject(cond, scratch2, label); +} + +void MacroAssembler::branchTestObject(Condition cond, const Address& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestObject(cond, tag, label); +} + +void MacroAssembler::branchTestObject(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestObject(cond, tag, label); +} + +void MacroAssembler::branchTestPrimitive(Condition cond, + const ValueOperand& value, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + branchTestPrimitive(cond, scratch2, label); +} + +void MacroAssembler::branchTestGCThing(Condition cond, const Address& address, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + ma_b(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET), label, + (cond == Equal) ? AboveOrEqual : Below); +} + +void MacroAssembler::branchTestGCThing(Condition cond, const BaseIndex& address, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + ma_b(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET), label, + (cond == Equal) ? AboveOrEqual : Below); +} + +void MacroAssembler::branchTestPrimitive(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET), label, + (cond == Equal) ? Below : AboveOrEqual); +} + +void MacroAssembler::branchTestMagic(Condition cond, Register tag, + Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_MAGIC), label, cond); +} + +void MacroAssembler::branchTestMagic(Condition cond, const Address& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestMagic(cond, tag, label); +} + +void MacroAssembler::branchTestMagic(Condition cond, const BaseIndex& address, + Label* label) { + SecondScratchRegisterScope scratch2(*this); + Register tag = extractTag(address, scratch2); + branchTestMagic(cond, tag, label); +} + +template +void MacroAssembler::branchTestMagic(Condition cond, const ValueOperand& value, + L label) { + SecondScratchRegisterScope scratch2(*this); + splitTag(value, scratch2); + ma_b(scratch2, ImmTag(JSVAL_TAG_MAGIC), label, cond); +} + +void MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, + JSWhyMagic why, Label* label) { + uint64_t magic = MagicValue(why).asRawBits(); + SecondScratchRegisterScope scratch(*this); + loadPtr(valaddr, scratch); + ma_b(scratch, ImmWord(magic), label, cond); +} + +void MacroAssembler::storeUncanonicalizedDouble(FloatRegister src, + const Address& addr) { + ma_fst_d(src, addr); +} + +void MacroAssembler::storeUncanonicalizedDouble(FloatRegister src, + const BaseIndex& addr) { + MOZ_ASSERT(addr.offset == 0); + ma_fst_d(src, addr); +} + +void MacroAssembler::storeUncanonicalizedFloat32(FloatRegister src, + const Address& addr) { + ma_fst_s(src, addr); +} + +void MacroAssembler::storeUncanonicalizedFloat32(FloatRegister src, + const BaseIndex& addr) { + MOZ_ASSERT(addr.offset == 0); + ma_fst_s(src, addr); +} + +void MacroAssembler::clampIntToUint8(Register reg) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(reg != scratch); + + // Clamp semantics operate on int32 values; normalize the upper bits first in + // case the producer left the high 32 bits undefined. + as_slli_w(reg, reg, 0); + + as_slt(scratch, reg, zero); + as_masknez(reg, reg, scratch); + + as_sltui(scratch, reg, 255); + as_addi_d(reg, reg, -255); + as_maskeqz(reg, reg, scratch); + as_addi_d(reg, reg, 255); +} + +template +void MacroAssembler::wasmBoundsCheck(Condition cond, Register index, L label) { + BufferOffset bo = ma_BoundsCheck(ScratchRegister); + append(wasm::BoundsCheck(bo.getOffset())); + ma_b(index, ScratchRegister, label, cond); +} + +void MacroAssembler::wasmPatchBoundsCheck(uint8_t* patchAt, uint32_t limit) { + InstImm* i0 = reinterpret_cast(patchAt); + InstImm* i1 = reinterpret_cast(i0->next()); + + *i0 = InstImm(op_lu12i_w, int32_t((limit >> 12) & 0xfffff), + Register::FromCode(i0->extractRD()), false); + *i1 = InstImm(op_ori, int32_t(limit & 0xfff), + Register::FromCode(i1->extractRJ()), + Register::FromCode(i1->extractRD()), 12); +} + +void MacroAssembler::memoryBarrier(MemoryBarrierBits barrier) { + if (barrier == MembarNobits) { + return; + } + as_dbar(0); +} + +//}}} check_macroassembler_style +// =============================================================== + +// The specializations for cmpPtrSet are outside the braces because +// check_macroassembler_style can't yet deal with specializations. + +template <> +inline void MacroAssembler::cmpPtrSet(Assembler::Condition cond, Address lhs, + ImmPtr rhs, Register dest) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(lhs, scratch2); + cmpPtrSet(cond, Register(scratch2), rhs, dest); +} + +template <> +inline void MacroAssembler::cmpPtrSet(Assembler::Condition cond, Register lhs, + Address rhs, Register dest) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(lhs != scratch); + loadPtr(rhs, scratch); + cmpPtrSet(cond, lhs, Register(scratch), dest); +} + +template <> +inline void MacroAssembler::cmpPtrSet(Assembler::Condition cond, Address lhs, + Register rhs, Register dest) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(rhs != scratch2); + loadPtr(lhs, scratch2); + cmpPtrSet(cond, Register(scratch2), rhs, dest); +} + +template <> +inline void MacroAssembler::cmp32Set(Assembler::Condition cond, Register lhs, + Address rhs, Register dest) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(lhs != scratch); + load32(rhs, scratch); + cmp32Set(cond, lhs, Register(scratch), dest); +} + +template <> +inline void MacroAssembler::cmp32Set(Assembler::Condition cond, Address lhs, + Register rhs, Register dest) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(rhs != scratch2); + load32(lhs, scratch2); + cmp32Set(cond, Register(scratch2), rhs, dest); +} + +void MacroAssemblerLOONGARCH64Compat::incrementInt32Value(const Address& addr) { + asMasm().add32(Imm32(1), addr); +} + +void MacroAssemblerLOONGARCH64Compat::retn(Imm32 n) { + // pc <- [sp]; sp += n + loadPtr(Address(StackPointer, 0), ra); + asMasm().addPtr(n, StackPointer); + as_jirl(zero, ra, BOffImm16(0)); +} + +// If source is a double, load into dest. +// If source is int32, convert to double and store in dest. +// Else, branch to failure. +void MacroAssemblerLOONGARCH64Compat::ensureDouble(const ValueOperand& source, + FloatRegister dest, + Label* failure) { + Label isDouble, done; + { + ScratchTagScope tag(asMasm(), source); + splitTagForTest(source, tag); + asMasm().branchTestDouble(Assembler::Equal, tag, &isDouble); + asMasm().branchTestInt32(Assembler::NotEqual, tag, failure); + } + + convertInt32ToDouble(source.valueReg(), dest); + jump(&done); + + bind(&isDouble); + unboxDouble(source, dest); + + bind(&done); +} + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_MacroAssembler_loongarch64_inl_h */ diff --git a/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp b/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp new file mode 100644 index 0000000000..2459e0a13b --- /dev/null +++ b/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp @@ -0,0 +1,4180 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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 "jit/loongarch64/MacroAssembler-loongarch64.h" + +#include "jsmath.h" + +#include "jit/Bailouts.h" +#include "jit/BaselineFrame.h" +#include "jit/JitFrames.h" +#include "jit/loongarch64/SharedICRegisters-loongarch64.h" +#include "jit/MacroAssembler.h" +#include "jit/MoveEmitter.h" +#include "vm/Stack.h" +#include "jscntxt.h" + +#include "jit/MacroAssembler-inl.h" + +namespace js { +namespace jit { + +BufferOffset +MacroAssemblerLOONGARCH64Compat::as_div(Register lhs, Register rhs) +{ + pendingDivKind_ = PendingDivW; + pendingDivLhs_ = lhs; + pendingDivRhs_ = rhs; + return m_buffer.nextOffset(); +} + +BufferOffset +MacroAssemblerLOONGARCH64Compat::as_divu(Register lhs, Register rhs) +{ + pendingDivKind_ = PendingDivWU; + pendingDivLhs_ = lhs; + pendingDivRhs_ = rhs; + return m_buffer.nextOffset(); +} + +BufferOffset +MacroAssemblerLOONGARCH64Compat::as_ddiv(Register lhs, Register rhs) +{ + pendingDivKind_ = PendingDivD; + pendingDivLhs_ = lhs; + pendingDivRhs_ = rhs; + return m_buffer.nextOffset(); +} + +BufferOffset +MacroAssemblerLOONGARCH64Compat::as_ddivu(Register lhs, Register rhs) +{ + pendingDivKind_ = PendingDivDU; + pendingDivLhs_ = lhs; + pendingDivRhs_ = rhs; + return m_buffer.nextOffset(); +} + +BufferOffset +MacroAssemblerLOONGARCH64Compat::as_mflo(Register dest) +{ + switch (pendingDivKind_) { + case PendingDivW: + return as_div_w(dest, pendingDivLhs_, pendingDivRhs_); + case PendingDivWU: + return as_div_wu(dest, pendingDivLhs_, pendingDivRhs_); + case PendingDivD: + return as_div_d(dest, pendingDivLhs_, pendingDivRhs_); + case PendingDivDU: + return as_div_du(dest, pendingDivLhs_, pendingDivRhs_); + case PendingDivNone: + break; + } + MOZ_CRASH("mflo without pending div"); +} + +BufferOffset +MacroAssemblerLOONGARCH64Compat::as_mfhi(Register dest) +{ + switch (pendingDivKind_) { + case PendingDivW: + return as_mod_w(dest, pendingDivLhs_, pendingDivRhs_); + case PendingDivWU: + return as_mod_wu(dest, pendingDivLhs_, pendingDivRhs_); + case PendingDivD: + return as_mod_d(dest, pendingDivLhs_, pendingDivRhs_); + case PendingDivDU: + return as_mod_du(dest, pendingDivLhs_, pendingDivRhs_); + case PendingDivNone: + break; + } + MOZ_CRASH("mfhi without pending div"); +} + +namespace { + +static inline void MoveAtomicValue(MacroAssemblerLOONGARCH64Compat& masm, + Imm32 value, Register dest) { + masm.move32(value, dest); +} + +static inline void MoveAtomicValue(MacroAssemblerLOONGARCH64Compat& masm, + Register value, Register dest) { + masm.move32(value, dest); +} + +static inline void SignExtendAtomicResult(MacroAssemblerLOONGARCH64Compat& masm, + int nbytes, Register output) { + switch (nbytes) { + case 1: + masm.as_ext_w_b(output, output); + break; + case 2: + masm.as_ext_w_h(output, output); + break; + case 4: + break; + default: + MOZ_CRASH("unexpected atomic width"); + } +} + +static inline void ZeroExtendAtomicResult(MacroAssemblerLOONGARCH64Compat& masm, + int nbytes, Register output) { + switch (nbytes) { + case 1: + masm.as_bstrpick_d(output, output, 7, 0); + break; + case 2: + masm.as_bstrpick_d(output, output, 15, 0); + break; + case 4: + break; + default: + MOZ_CRASH("unexpected atomic width"); + } +} + +template +static inline void PrepareAtomicAddress( + MacroAssemblerLOONGARCH64Compat& masm, int nbytes, const T& address, + Register offsetTemp, Register maskTemp) { + masm.computeEffectiveAddress(address, ScratchRegister); + masm.as_andi(offsetTemp, ScratchRegister, 3); + masm.as_sub_d(ScratchRegister, ScratchRegister, offsetTemp); + masm.as_slli_w(offsetTemp, offsetTemp, 3); + masm.ma_li(maskTemp, Imm32(int32_t(UINT32_MAX >> ((4 - nbytes) * 8)))); + masm.as_sll_w(maskTemp, maskTemp, offsetTemp); +} + +template +static void AtomicFetchOpLoongArch64(MacroAssemblerLOONGARCH64Compat& masm, + int nbytes, bool signExtend, AtomicOp op, + const S& value, const T& address, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + Label again; + + PrepareAtomicAddress(masm, nbytes, address, offsetTemp, maskTemp); + + masm.bind(&again); + masm.as_dbar(0); + masm.as_ll_w(SecondScratchReg, ScratchRegister, 0); + + if (output != InvalidReg) { + masm.as_and(output, SecondScratchReg, maskTemp); + masm.as_srl_w(output, output, offsetTemp); + if (signExtend) { + SignExtendAtomicResult(masm, nbytes, output); + } + } + + MoveAtomicValue(masm, value, valueTemp); + masm.as_sll_w(valueTemp, valueTemp, offsetTemp); + + switch (op) { + case AtomicFetchAddOp: + masm.as_add_w(valueTemp, SecondScratchReg, valueTemp); + break; + case AtomicFetchSubOp: + masm.as_sub_w(valueTemp, SecondScratchReg, valueTemp); + break; + case AtomicFetchAndOp: + masm.as_and(valueTemp, SecondScratchReg, valueTemp); + break; + case AtomicFetchOrOp: + masm.as_or(valueTemp, SecondScratchReg, valueTemp); + break; + case AtomicFetchXorOp: + masm.as_xor(valueTemp, SecondScratchReg, valueTemp); + break; + default: + MOZ_CRASH("unexpected atomic op"); + } + + masm.as_and(valueTemp, valueTemp, maskTemp); + masm.as_or(SecondScratchReg, SecondScratchReg, maskTemp); + masm.as_xor(SecondScratchReg, SecondScratchReg, maskTemp); + masm.as_or(SecondScratchReg, SecondScratchReg, valueTemp); + masm.as_sc_w(SecondScratchReg, ScratchRegister, 0); + masm.ma_b(SecondScratchReg, SecondScratchReg, &again, Assembler::Zero, + ShortJump); + masm.as_dbar(0); +} + +template +static void CompareExchangeLoongArch64( + MacroAssemblerLOONGARCH64Compat& masm, int nbytes, bool signExtend, + const T& address, Register oldval, Register newval, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { + Label again, done; + + PrepareAtomicAddress(masm, nbytes, address, offsetTemp, maskTemp); + + masm.bind(&again); + masm.as_dbar(0); + masm.as_ll_w(SecondScratchReg, ScratchRegister, 0); + + masm.as_and(output, SecondScratchReg, maskTemp); + masm.as_srl_w(output, output, offsetTemp); + if (signExtend) { + SignExtendAtomicResult(masm, nbytes, output); + } + + if (oldval != InvalidReg) { + masm.move32(oldval, valueTemp); + if (nbytes != 4) { + if (signExtend) { + SignExtendAtomicResult(masm, nbytes, valueTemp); + } else { + ZeroExtendAtomicResult(masm, nbytes, valueTemp); + } + } + masm.ma_b(output, valueTemp, &done, Assembler::NotEqual, ShortJump); + } + + masm.move32(newval, valueTemp); + masm.as_sll_w(valueTemp, valueTemp, offsetTemp); + masm.as_and(valueTemp, valueTemp, maskTemp); + masm.as_or(SecondScratchReg, SecondScratchReg, maskTemp); + masm.as_xor(SecondScratchReg, SecondScratchReg, maskTemp); + masm.as_or(SecondScratchReg, SecondScratchReg, valueTemp); + masm.as_sc_w(SecondScratchReg, ScratchRegister, 0); + masm.ma_b(SecondScratchReg, SecondScratchReg, &again, Assembler::Zero, + ShortJump); + masm.as_dbar(0); + + masm.bind(&done); +} + +} // namespace + +void MacroAssembler::alignFrameForICArguments(AfterICSaveLive& aic) { + if (framePushed() % ABIStackAlignment != 0) { + aic.alignmentPadding = ABIStackAlignment - (framePushed() % ABIStackAlignment); + reserveStack(aic.alignmentPadding); + } else { + aic.alignmentPadding = 0; + } + MOZ_ASSERT(framePushed() % ABIStackAlignment == 0); +} + +void MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive& aic) { + if (aic.alignmentPadding != 0) { + freeStack(aic.alignmentPadding); + } +} + +void MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output) { + ScratchRegisterScope scratch(asMasm()); + ScratchDoubleScope fpscratch(asMasm()); + as_ftintrne_l_d(fpscratch, input); + as_movfr2gr_d(output, fpscratch); + // if (res < 0); res = 0; + as_slt(scratch, output, zero); + as_masknez(output, output, scratch); + // if res > 255; res = 255; + as_sltui(scratch, output, 255); + as_addi_d(output, output, -255); + as_maskeqz(output, output, scratch); + as_addi_d(output, output, 255); +} + +bool MacroAssemblerLOONGARCH64Compat::buildOOLFakeExitFrame(void* fakeReturnAddr) { + uint32_t descriptor = MakeFrameDescriptor( + asMasm().framePushed(), JitFrame_IonJS, ExitFrameLayout::Size()); + + asMasm().Push(Imm32(descriptor)); // descriptor_ + asMasm().Push(ImmPtr(fakeReturnAddr)); + + return true; +} + +void MacroAssemblerLOONGARCH64Compat::convertUInt32ToDouble(Register src, + FloatRegister dest) { + ScratchRegisterScope scratch(asMasm()); + as_bstrpick_d(scratch, src, 31, 0); + as_movgr2fr_d(dest, scratch); + as_ffint_d_l(dest, dest); +} + +void MacroAssemblerLOONGARCH64Compat::convertInt64ToDouble(Register src, + FloatRegister dest) { + as_movgr2fr_d(dest, src); + as_ffint_d_l(dest, dest); +} + +void MacroAssemblerLOONGARCH64Compat::convertInt64ToFloat32(Register src, + FloatRegister dest) { + as_movgr2fr_d(dest, src); + as_ffint_s_l(dest, dest); +} + +void MacroAssemblerLOONGARCH64Compat::convertUInt64ToDouble(Register src, + FloatRegister dest) { + Label positive, done; + ma_b(src, src, &positive, NotSigned, ShortJump); + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + + MOZ_ASSERT(src != scratch); + MOZ_ASSERT(src != scratch2); + + ma_and(scratch, src, Imm32(1)); + as_srli_d(scratch2, src, 1); + as_or(scratch, scratch, scratch2); + as_movgr2fr_d(dest, scratch); + as_ffint_d_l(dest, dest); + asMasm().addDouble(dest, dest); + ma_b(&done, ShortJump); + + bind(&positive); + as_movgr2fr_d(dest, src); + as_ffint_d_l(dest, dest); + + bind(&done); +} + +bool MacroAssemblerLOONGARCH64Compat::convertUInt64ToDoubleNeedsTemp() { + return false; +} + +void MacroAssemblerLOONGARCH64Compat::convertUInt64ToDouble( + Register64 src, FloatRegister dest, Register temp) { + MOZ_ASSERT(temp == InvalidReg); + convertUInt64ToDouble(src.reg, dest); +} + +void MacroAssemblerLOONGARCH64Compat::convertUInt32ToFloat32(Register src, + FloatRegister dest) { + ScratchRegisterScope scratch(asMasm()); + as_bstrpick_d(scratch, src, 31, 0); + as_movgr2fr_d(dest, scratch); + as_ffint_s_l(dest, dest); +} + +void MacroAssemblerLOONGARCH64Compat::convertUInt64ToFloat32(Register src, + FloatRegister dest) { + Label positive, done; + ma_b(src, src, &positive, NotSigned, ShortJump); + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + + MOZ_ASSERT(src != scratch); + MOZ_ASSERT(src != scratch2); + + ma_and(scratch, src, Imm32(1)); + as_srli_d(scratch2, src, 1); + as_or(scratch, scratch, scratch2); + as_movgr2fr_d(dest, scratch); + as_ffint_s_l(dest, dest); + asMasm().addFloat32(dest, dest); + ma_b(&done, ShortJump); + + bind(&positive); + as_movgr2fr_d(dest, src); + as_ffint_s_l(dest, dest); + + bind(&done); +} + +void MacroAssemblerLOONGARCH64Compat::convertDoubleToFloat32(FloatRegister src, + FloatRegister dest) { + as_fcvt_s_d(dest, src); +} + +const int CauseBitPos = int(Assembler::CauseI); +const int CauseBitCount = 1 + int(Assembler::CauseV) - int(Assembler::CauseI); +const int CauseIOrVMask = ((1 << int(Assembler::CauseI)) | + (1 << int(Assembler::CauseV))) >> + int(Assembler::CauseI); + +// Checks whether a double is representable as a 32-bit integer. If so, the +// integer is written to the output register. Otherwise, a bailout is taken to +// the given snapshot. This function overwrites the scratch float register. +void MacroAssemblerLOONGARCH64Compat::convertDoubleToInt32(FloatRegister src, + Register dest, + Label* fail, + bool negativeZeroCheck) { + if (negativeZeroCheck) { + moveFromDouble(src, dest); + as_rotri_d(dest, dest, 63); + ma_b(dest, Imm32(1), fail, Assembler::Equal); + } + + ScratchRegisterScope scratch(asMasm()); + ScratchFloat32Scope fpscratch(asMasm()); + // Truncate double to int ; if result is inexact or invalid fail. + as_ftintrz_w_d(fpscratch, src); + as_movfcsr2gr(scratch); + moveFromFloat32(fpscratch, dest); + as_bstrpick_d(scratch, scratch, CauseBitPos + CauseBitCount - 1, CauseBitPos); + as_andi(scratch, scratch, + CauseIOrVMask); // masking for Inexact and Invalid flag. + ma_b(scratch, zero, fail, Assembler::NotEqual); +} + +void MacroAssemblerLOONGARCH64Compat::convertDoubleToPtr(FloatRegister src, + Register dest, Label* fail, + bool negativeZeroCheck) { + if (negativeZeroCheck) { + moveFromDouble(src, dest); + as_rotri_d(dest, dest, 63); + ma_b(dest, Imm32(1), fail, Assembler::Equal); + } + + ScratchRegisterScope scratch(asMasm()); + ScratchDoubleScope fpscratch(asMasm()); + // Truncate double to int64 ; if result is inexact or invalid fail. + as_ftintrz_l_d(fpscratch, src); + as_movfcsr2gr(scratch); + moveFromDouble(fpscratch, dest); + as_bstrpick_d(scratch, scratch, CauseBitPos + CauseBitCount - 1, CauseBitPos); + as_andi(scratch, scratch, + CauseIOrVMask); // masking for Inexact and Invalid flag. + ma_b(scratch, zero, fail, Assembler::NotEqual); +} + +// Checks whether a float32 is representable as a 32-bit integer. If so, the +// integer is written to the output register. Otherwise, a bailout is taken to +// the given snapshot. This function overwrites the scratch float register. +void MacroAssemblerLOONGARCH64Compat::convertFloat32ToInt32( + FloatRegister src, Register dest, Label* fail, bool negativeZeroCheck) { + if (negativeZeroCheck) { + moveFromFloat32(src, dest); + ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal); + } + + ScratchRegisterScope scratch(asMasm()); + ScratchFloat32Scope fpscratch(asMasm()); + as_ftintrz_w_s(fpscratch, src); + as_movfcsr2gr(scratch); + moveFromFloat32(fpscratch, dest); + as_bstrpick_d(scratch, scratch, CauseBitPos + CauseBitCount - 1, CauseBitPos); + as_andi(scratch, scratch, CauseIOrVMask); + ma_b(scratch, zero, fail, Assembler::NotEqual); +} + +void MacroAssemblerLOONGARCH64Compat::convertFloat32ToDouble(FloatRegister src, + FloatRegister dest) { + as_fcvt_d_s(dest, src); +} + +void MacroAssemblerLOONGARCH64Compat::convertInt32ToFloat32(Register src, + FloatRegister dest) { + as_movgr2fr_w(dest, src); + as_ffint_s_w(dest, dest); +} + +void MacroAssemblerLOONGARCH64Compat::convertInt32ToFloat32(const Address& src, + FloatRegister dest) { + ma_fld_s(dest, src); + as_ffint_s_w(dest, dest); +} + +void MacroAssemblerLOONGARCH64Compat::movq(Register rj, Register rd) { + as_or(rd, rj, zero); +} + +void MacroAssemblerLOONGARCH64::ma_li(Register dest, CodeOffset* label) { + BufferOffset bo = m_buffer.nextOffset(); + ma_liPatchable(dest, ImmWord(/* placeholder */ 0)); + label->bind(bo.getOffset()); +} + +void MacroAssemblerLOONGARCH64::ma_li(Register dest, ImmWord imm) { + int64_t value = imm.value; + + if (-1 == (value >> 11) || 0 == (value >> 11)) { + as_addi_w(dest, zero, value); + return; + } + + if (0 == (value >> 12)) { + as_ori(dest, zero, value); + return; + } + + if (-1 == (value >> 31) || 0 == (value >> 31)) { + as_lu12i_w(dest, (value >> 12) & 0xfffff); + } else if (0 == (value >> 32)) { + as_lu12i_w(dest, (value >> 12) & 0xfffff); + as_bstrins_d(dest, zero, 63, 32); + } else if (-1 == (value >> 51) || 0 == (value >> 51)) { + if (is_uintN((value >> 12) & 0xfffff, 20)) { + as_lu12i_w(dest, (value >> 12) & 0xfffff); + } + as_lu32i_d(dest, (value >> 32) & 0xfffff); + } else if (0 == (value >> 52)) { + if (is_uintN((value >> 12) & 0xfffff, 20)) { + as_lu12i_w(dest, (value >> 12) & 0xfffff); + } + as_lu32i_d(dest, (value >> 32) & 0xfffff); + as_bstrins_d(dest, zero, 63, 52); + } else { + if (is_uintN((value >> 12) & 0xfffff, 20)) { + as_lu12i_w(dest, (value >> 12) & 0xfffff); + } + if (is_uintN((value >> 32) & 0xfffff, 20)) { + as_lu32i_d(dest, (value >> 32) & 0xfffff); + } + as_lu52i_d(dest, dest, (value >> 52) & 0xfff); + } + + if (is_uintN(value & 0xfff, 12)) { + as_ori(dest, dest, value & 0xfff); + } +} + +// This method generates lu32i_d, lu12i_w and ori instruction block that can be +// modified by UpdateLoad64Value, either during compilation (eg. +// Assembler::bind), or during execution (eg. jit::PatchJump). +void MacroAssemblerLOONGARCH64::ma_liPatchable(Register dest, ImmPtr imm) { + return ma_liPatchable(dest, ImmWord(uintptr_t(imm.value))); +} + +void MacroAssemblerLOONGARCH64::ma_liPatchable(Register dest, ImmWord imm, + LiFlags flags) { + // hi12, hi20, low20, low12 + if (Li64 == flags) { // Li64: Imm data + m_buffer.ensureSpace(4 * sizeof(uint32_t)); + as_lu12i_w(dest, imm.value >> 12 & 0xfffff); // low20 + as_ori(dest, dest, imm.value & 0xfff); // low12 + as_lu32i_d(dest, imm.value >> 32 & 0xfffff); // hi20 + as_lu52i_d(dest, dest, imm.value >> 52 & 0xfff); // hi12 + } else { // Li48 address + m_buffer.ensureSpace(3 * sizeof(uint32_t)); + as_lu12i_w(dest, imm.value >> 12 & 0xfffff); // low20 + as_ori(dest, dest, imm.value & 0xfff); // low12 + as_lu32i_d(dest, imm.value >> 32 & 0xfffff); // hi20 + } +} + +// Memory access ops. + +void MacroAssemblerLOONGARCH64::ma_ld_b(Register dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_ld_b(dest, base, offset); + } else if (base != dest) { + ma_li(dest, Imm32(offset)); + as_ldx_b(dest, base, dest); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_ldx_b(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_ld_bu(Register dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_ld_bu(dest, base, offset); + } else if (base != dest) { + ma_li(dest, Imm32(offset)); + as_ldx_bu(dest, base, dest); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_ldx_bu(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_ld_h(Register dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_ld_h(dest, base, offset); + } else if (base != dest) { + ma_li(dest, Imm32(offset)); + as_ldx_h(dest, base, dest); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_ldx_h(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_ld_hu(Register dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_ld_hu(dest, base, offset); + } else if (base != dest) { + ma_li(dest, Imm32(offset)); + as_ldx_hu(dest, base, dest); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_ldx_hu(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_ld_w(Register dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_ld_w(dest, base, offset); + } else if (base != dest) { + ma_li(dest, Imm32(offset)); + as_ldx_w(dest, base, dest); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_ldx_w(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_ld_wu(Register dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_ld_wu(dest, base, offset); + } else if (base != dest) { + ma_li(dest, Imm32(offset)); + as_ldx_wu(dest, base, dest); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_ldx_wu(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_ld_d(Register dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_ld_d(dest, base, offset); + } else if (base != dest) { + ma_li(dest, Imm32(offset)); + as_ldx_d(dest, base, dest); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_ldx_d(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_st_b(Register src, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_st_b(src, base, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(src != scratch); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_stx_b(src, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_st_h(Register src, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_st_h(src, base, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(src != scratch); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_stx_h(src, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_st_w(Register src, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_st_w(src, base, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(src != scratch); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_stx_w(src, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_st_d(Register src, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_st_d(src, base, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(src != scratch); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_stx_d(src, base, scratch); + } +} + +// Arithmetic-based ops. + +// Add. +void MacroAssemblerLOONGARCH64::ma_add_d(Register rd, Register rj, Imm32 imm) { + if (is_intN(imm.value, 12)) { + as_addi_d(rd, rj, imm.value); + } else if (rd != rj) { + ma_li(rd, imm); + as_add_d(rd, rj, rd); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_add_d(rd, rj, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_add32TestOverflow(Register rd, Register rj, + Register rk, Label* overflow) { + ScratchRegisterScope scratch(asMasm()); + as_add_d(scratch, rj, rk); + as_add_w(rd, rj, rk); + ma_b(rd, Register(scratch), overflow, Assembler::NotEqual); +} + +void MacroAssemblerLOONGARCH64::ma_add32TestOverflow(Register rd, Register rj, + Imm32 imm, Label* overflow) { + // Check for signed range because of as_addi_d + if (is_intN(imm.value, 12)) { + ScratchRegisterScope scratch(asMasm()); + as_addi_d(scratch, rj, imm.value); + as_addi_w(rd, rj, imm.value); + ma_b(rd, scratch, overflow, Assembler::NotEqual); + } else { + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch2, imm); + ma_add32TestOverflow(rd, rj, scratch2, overflow); + } +} + +void MacroAssemblerLOONGARCH64::ma_addPtrTestOverflow(Register rd, Register rj, + Register rk, + Label* overflow) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rd != scratch); + + if (rj == rk) { + if (rj == rd) { + as_or(scratch, rj, zero); + rj = scratch; + } + + as_add_d(rd, rj, rj); + as_xor(scratch, rj, rd); + ma_b(scratch, zero, overflow, Assembler::LessThan); + } else { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(rj != scratch); + MOZ_ASSERT(rd != scratch2); + + if (rj == rd) { + as_or(scratch2, rj, zero); + rj = scratch2; + } + + as_add_d(rd, rj, rk); + as_slti(scratch, rj, 0); + as_slt(scratch2, rd, rj); + ma_b(scratch, Register(scratch2), overflow, Assembler::NotEqual); + } +} + +void MacroAssemblerLOONGARCH64::ma_addPtrTestOverflow(Register rd, Register rj, + Imm32 imm, Label* overflow) { + SecondScratchRegisterScope scratch2(asMasm()); + + if (imm.value == 0) { + as_ori(rd, rj, 0); + return; + } + + if (rj == rd) { + as_ori(scratch2, rj, 0); + rj = scratch2; + } + + ma_add_d(rd, rj, imm); + + if (imm.value > 0) { + ma_b(rd, rj, overflow, Assembler::LessThan); + } else { + MOZ_ASSERT(imm.value < 0); + ma_b(rd, rj, overflow, Assembler::GreaterThan); + } +} + +void MacroAssemblerLOONGARCH64::ma_addPtrTestOverflow(Register rd, Register rj, + ImmWord imm, + Label* overflow) { + SecondScratchRegisterScope scratch2(asMasm()); + + if (imm.value == 0) { + as_ori(rd, rj, 0); + return; + } + + if (rj == rd) { + MOZ_ASSERT(rj != scratch2); + as_ori(scratch2, rj, 0); + rj = scratch2; + } + + ma_li(rd, imm); + as_add_d(rd, rj, rd); + + if (imm.value > 0) { + ma_b(rd, rj, overflow, Assembler::LessThan); + } else { + MOZ_ASSERT(imm.value < 0); + ma_b(rd, rj, overflow, Assembler::GreaterThan); + } +} + +void MacroAssemblerLOONGARCH64::ma_addPtrTestCarry(Condition cond, Register rd, + Register rj, Register rk, + Label* label) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rd != rk); + MOZ_ASSERT(rd != scratch); + as_add_d(rd, rj, rk); + as_sltu(scratch, rd, rk); + ma_b(scratch, Register(scratch), label, + cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero); +} + +void MacroAssemblerLOONGARCH64::ma_addPtrTestCarry(Condition cond, Register rd, + Register rj, Imm32 imm, + Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + + // Check for signed range because of as_addi_d + if (is_intN(imm.value, 12)) { + as_addi_d(rd, rj, imm.value); + as_sltui(scratch2, rd, imm.value); + ma_b(scratch2, scratch2, label, + cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero); + } else { + ma_li(scratch2, imm); + ma_addPtrTestCarry(cond, rd, rj, scratch2, label); + } +} + +void MacroAssemblerLOONGARCH64::ma_addPtrTestCarry(Condition cond, Register rd, + Register rj, ImmWord imm, + Label* label) { + SecondScratchRegisterScope scratch2(asMasm()); + + // Check for signed range because of as_addi_d + if (is_intN(imm.value, 12)) { + as_addi_d(rd, rj, imm.value); + as_sltui(scratch2, rd, imm.value); + ma_b(scratch2, scratch2, label, + cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero); + } else { + ma_li(scratch2, imm); + ma_addPtrTestCarry(cond, rd, rj, scratch2, label); + } +} + +// Subtract. +void MacroAssemblerLOONGARCH64::ma_sub_d(Register rd, Register rj, Imm32 imm) { + if (is_intN(-imm.value, 12)) { + as_addi_d(rd, rj, -imm.value); + } else { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + as_sub_d(rd, rj, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_sub32TestOverflow(Register rd, Register rj, + Register rk, Label* overflow) { + ScratchRegisterScope scratch(asMasm()); + as_sub_d(scratch, rj, rk); + as_sub_w(rd, rj, rk); + ma_b(rd, Register(scratch), overflow, Assembler::NotEqual); +} + +void MacroAssemblerLOONGARCH64::ma_subPtrTestOverflow(Register rd, Register rj, + Register rk, + Label* overflow) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT_IF(rj == rd, rj != rk); + MOZ_ASSERT(rj != scratch2); + MOZ_ASSERT(rk != scratch2); + MOZ_ASSERT(rd != scratch2); + + Register rj_copy = rj; + + if (rj == rd) { + as_or(scratch2, rj, zero); + rj_copy = scratch2; + } + + { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rd != scratch); + + as_sub_d(rd, rj, rk); + // If the sign of rj and rk are the same, no overflow + as_xor(scratch, rj_copy, rk); + // Check if the sign of rd and rj are the same + as_xor(scratch2, rd, rj_copy); + as_and(scratch2, scratch2, scratch); + } + + ma_b(scratch2, zero, overflow, Assembler::LessThan); +} + +void MacroAssemblerLOONGARCH64::ma_subPtrTestOverflow(Register rd, Register rj, + Imm32 imm, Label* overflow) { + // TODO(loongarch64): Check subPtrTestOverflow + MOZ_ASSERT(imm.value != INT32_MIN); + ma_addPtrTestOverflow(rd, rj, Imm32(-imm.value), overflow); +} + +void MacroAssemblerLOONGARCH64::ma_mul_d(Register rd, Register rj, Imm32 imm) { + // li handles the relocation. + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_mul_d(rd, rj, scratch); +} + +void MacroAssemblerLOONGARCH64::ma_mulh_d(Register rd, Register rj, Imm32 imm) { + // li handles the relocation. + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_mulh_d(rd, rj, scratch); +} + +void MacroAssemblerLOONGARCH64::ma_mulPtrTestOverflow(Register rd, Register rj, + Register rk, + Label* overflow) { + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(rd != scratch); + + if (rd == rj) { + as_or(scratch, rj, zero); + rj = scratch; + rk = (rd == rk) ? rj : rk; + } else if (rd == rk) { + as_or(scratch, rk, zero); + rk = scratch; + } + + as_mul_d(rd, rj, rk); + as_mulh_d(scratch, rj, rk); + as_srai_d(scratch2, rd, 63); + ma_b(scratch, Register(scratch2), overflow, Assembler::NotEqual); +} + +// Memory. + +void MacroAssemblerLOONGARCH64::ma_load(Register dest, Address address, + LoadStoreSize size, + LoadStoreExtension extension) { + switch (size) { + case SizeByte: + if (ZeroExtend == extension) { + ma_ld_bu(dest, address); + } else { + ma_ld_b(dest, address); + } + break; + case SizeHalfWord: + if (ZeroExtend == extension) { + ma_ld_hu(dest, address); + } else { + ma_ld_h(dest, address); + } + break; + case SizeWord: + if ((address.offset & 0x3) == 0 && SignExtend == extension && + Imm16::IsInSignedRange(address.offset)) { + as_ldptr_w(dest, address.base, address.offset); + } else if (ZeroExtend == extension) { + ma_ld_wu(dest, address); + } else { + ma_ld_w(dest, address); + } + break; + case SizeDouble: + if ((address.offset & 0x3) == 0 && + Imm16::IsInSignedRange(address.offset)) { + as_ldptr_d(dest, address.base, address.offset); + } else { + ma_ld_d(dest, address); + } + break; + default: + MOZ_CRASH("Invalid argument for ma_load"); + } +} + +void MacroAssemblerLOONGARCH64::ma_store(Register data, Address address, + LoadStoreSize size, + LoadStoreExtension extension) { + switch (size) { + case SizeByte: + ma_st_b(data, address); + break; + case SizeHalfWord: + ma_st_h(data, address); + break; + case SizeWord: + if ((address.offset & 0x3) == 0 && + Imm16::IsInSignedRange(address.offset)) { + as_stptr_w(data, address.base, address.offset); + } else { + ma_st_w(data, address); + } + break; + case SizeDouble: + if ((address.offset & 0x3) == 0 && + Imm16::IsInSignedRange(address.offset)) { + as_stptr_d(data, address.base, address.offset); + } else { + ma_st_d(data, address); + } + break; + default: + MOZ_CRASH("Invalid argument for ma_store"); + } +} + +void MacroAssemblerLOONGARCH64Compat::computeScaledAddress(const BaseIndex& address, + Register dest) { + Register base = address.base; + Register index = address.index; + int32_t shift = Imm32::ShiftOf(address.scale).value; + + if (shift) { + MOZ_ASSERT(shift <= 4); + as_alsl_d(dest, index, base, shift - 1); + } else { + as_add_d(dest, base, index); + } +} + +void MacroAssemblerLOONGARCH64::ma_pop(Register r) { + MOZ_ASSERT(r != StackPointer); + as_ld_d(r, StackPointer, 0); + as_addi_d(StackPointer, StackPointer, sizeof(intptr_t)); +} + +void MacroAssemblerLOONGARCH64::ma_push(Register r) { + if (r == StackPointer) { + ScratchRegisterScope scratch(asMasm()); + as_or(scratch, r, zero); + as_addi_d(StackPointer, StackPointer, (int32_t) - sizeof(intptr_t)); + as_st_d(scratch, StackPointer, 0); + } else { + as_addi_d(StackPointer, StackPointer, (int32_t) - sizeof(intptr_t)); + as_st_d(r, StackPointer, 0); + } +} + +// Branches when done from within loongarch-specific code. +void MacroAssemblerLOONGARCH64::ma_b(Register lhs, ImmWord imm, Label* label, + Condition c, JumpKind jumpKind) { + if (imm.value <= INT32_MAX) { + ma_b(lhs, Imm32(uint32_t(imm.value)), label, c, jumpKind); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(lhs != scratch); + ma_li(scratch, imm); + ma_b(lhs, Register(scratch), label, c, jumpKind); + } +} + +void MacroAssemblerLOONGARCH64::ma_b(Register lhs, Address addr, Label* label, + Condition c, JumpKind jumpKind) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(lhs != scratch); + ma_ld_d(scratch, addr); + ma_b(lhs, Register(scratch), label, c, jumpKind); +} + +void MacroAssemblerLOONGARCH64::ma_b(Address addr, Imm32 imm, Label* label, + Condition c, JumpKind jumpKind) { + SecondScratchRegisterScope scratch2(asMasm()); + ma_ld_d(scratch2, addr); + ma_b(Register(scratch2), imm, label, c, jumpKind); +} + +void MacroAssemblerLOONGARCH64::ma_b(Address addr, ImmGCPtr imm, Label* label, + Condition c, JumpKind jumpKind) { + SecondScratchRegisterScope scratch2(asMasm()); + ma_ld_d(scratch2, addr); + ma_b(Register(scratch2), imm, label, c, jumpKind); +} + +void MacroAssemblerLOONGARCH64::ma_bl(Label* label) { + spew("branch .Llabel %p\n", label); + if (label->bound()) { + // Generate the long jump for calls because return address has to be + // the address after the reserved block. + addLongJump(nextOffset(), BufferOffset(label->offset())); + ScratchRegisterScope scratch(asMasm()); + ma_liPatchable(scratch, ImmWord(LabelBase::INVALID_OFFSET)); + as_jirl(ra, scratch, BOffImm16(0)); + return; + } + + // Second word holds a pointer to the next branch in label's chain. + uint32_t nextInChain = + label->used() ? label->offset() : LabelBase::INVALID_OFFSET; + + // Make the whole branch continous in the buffer. The '5' + // instructions are writing at below. + m_buffer.ensureSpace(5 * sizeof(uint32_t)); + + spew("bal .Llabel %p\n", label); + BufferOffset bo = writeInst(getBranchCode(BranchIsCall).encode()); + writeInst(nextInChain); + if (!oom()) { + label->use(bo.getOffset()); + } + // Leave space for long jump. + as_nop(); + as_nop(); + as_nop(); +} + +void MacroAssemblerLOONGARCH64::branchWithCode(InstImm code, Label* label, + JumpKind jumpKind) { + // simply output the pointer of one label as its id, + // notice that after one label destructor, the pointer will be reused. + spew("branch .Llabel %p", label); + MOZ_ASSERT(code.encode() != + InstImm(op_jirl, BOffImm16(0), zero, ra).encode()); + InstImm inst_beq = InstImm(op_beq, BOffImm16(0), zero, zero); + + if (label->bound()) { + int32_t offset = label->offset() - m_buffer.nextOffset().getOffset(); + + if (BOffImm16::IsInRange(offset)) { + jumpKind = ShortJump; + } + + // ShortJump + if (jumpKind == ShortJump) { + MOZ_ASSERT(BOffImm16::IsInRange(offset)); + + if (code.extractBitField(31, 26) == ((uint32_t)op_bcz >> 26)) { + code.setImm21(offset); + } else { + code.setBOffImm16(BOffImm16(offset)); + } +#ifdef JS_JITSPEW + decodeBranchInstAndSpew(code); +#endif + writeInst(code.encode()); + return; + } + + // LongJump + if (code.encode() == inst_beq.encode()) { + // Handle long jump + addLongJump(nextOffset(), BufferOffset(label->offset())); + ScratchRegisterScope scratch(asMasm()); + ma_liPatchable(scratch, ImmWord(LabelBase::INVALID_OFFSET)); + as_jirl(zero, scratch, BOffImm16(0)); // jr scratch + as_nop(); + return; + } + + // OpenLongJump + // Handle long conditional branch, the target offset is based on self, + // point to next instruction of nop at below. + spew("invert branch .Llabel %p", label); + InstImm code_r = invertBranch(code, BOffImm16(5 * sizeof(uint32_t))); +#ifdef JS_JITSPEW + decodeBranchInstAndSpew(code_r); +#endif + writeInst(code_r.encode()); + addLongJump(nextOffset(), BufferOffset(label->offset())); + ScratchRegisterScope scratch(asMasm()); + ma_liPatchable(scratch, ImmWord(LabelBase::INVALID_OFFSET)); + as_jirl(zero, scratch, BOffImm16(0)); + as_nop(); + return; + } + + // Generate open jump and link it to a label. + + // Second word holds a pointer to the next branch in label's chain. + uint32_t nextInChain = + label->used() ? label->offset() : LabelBase::INVALID_OFFSET; + + if (jumpKind == ShortJump) { + // Make the whole branch continous in the buffer. + m_buffer.ensureSpace(2 * sizeof(uint32_t)); + + // Indicate that this is short jump with offset 4. + code.setBOffImm16(BOffImm16(4)); +#ifdef JS_JITSPEW + decodeBranchInstAndSpew(code); +#endif + BufferOffset bo = writeInst(code.encode()); + writeInst(nextInChain); + if (!oom()) { + label->use(bo.getOffset()); + } + return; + } + + bool conditional = code.encode() != inst_beq.encode(); + + // Make the whole branch continous in the buffer. The '5' + // instructions are writing at below (contain conditional nop). + m_buffer.ensureSpace(5 * sizeof(uint32_t)); + +#ifdef JS_JITSPEW + decodeBranchInstAndSpew(code); +#endif + BufferOffset bo = writeInst(code.encode()); // invert + writeInst(nextInChain); + if (!oom()) { + label->use(bo.getOffset()); + } + // Leave space for potential long jump. + as_nop(); + as_nop(); + if (conditional) { + as_nop(); + } +} + +void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Register rj, ImmWord imm, + Condition c) { + if (imm.value <= INT32_MAX) { + ma_cmp_set(rd, rj, Imm32(uint32_t(imm.value)), c); + } else { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + ma_cmp_set(rd, rj, scratch, c); + } +} + +void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Register rj, ImmPtr imm, + Condition c) { + ma_cmp_set(rd, rj, ImmWord(uintptr_t(imm.value)), c); +} + +void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Address address, Imm32 imm, + Condition c) { + // TODO(loongarch64): 32-bit ma_cmp_set? + SecondScratchRegisterScope scratch2(asMasm()); + ma_ld_w(scratch2, address); + ma_cmp_set(rd, Register(scratch2), imm, c); +} + +void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Address address, + ImmWord imm, Condition c) { + SecondScratchRegisterScope scratch2(asMasm()); + ma_ld_d(scratch2, address); + ma_cmp_set(rd, Register(scratch2), imm, c); +} + +// fp instructions +void MacroAssemblerLOONGARCH64::ma_lid(FloatRegister dest, double value) { + ImmWord imm(mozilla::BitwiseCast(value)); + + if (imm.value != 0) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + moveToDouble(scratch, dest); + } else { + moveToDouble(zero, dest); + } +} + +void MacroAssemblerLOONGARCH64::ma_mv(FloatRegister src, ValueOperand dest) { + as_movfr2gr_d(dest.valueReg(), src); +} + +void MacroAssemblerLOONGARCH64::ma_mv(ValueOperand src, FloatRegister dest) { + as_movgr2fr_d(dest, src.valueReg()); +} + +void MacroAssemblerLOONGARCH64::ma_fld_s(FloatRegister dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_fld_s(dest, base, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_fldx_s(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_fld_d(FloatRegister dest, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_fld_d(dest, base, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_fldx_d(dest, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_fst_s(FloatRegister src, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_fst_s(src, base, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_fstx_s(src, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_fst_d(FloatRegister src, Address address) { + int32_t offset = address.offset; + Register base = address.base; + + if (is_intN(offset, 12)) { + as_fst_d(src, base, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(base != scratch); + ma_li(scratch, Imm32(offset)); + as_fstx_d(src, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_pop(FloatRegister f) { + if (f.isDouble()) { + as_fld_d(f, StackPointer, 0); + } else { + as_fld_s(f, StackPointer, 0); + } + as_addi_d(StackPointer, StackPointer, f.size()); +} + +void MacroAssemblerLOONGARCH64::ma_push(FloatRegister f) { + as_addi_d(StackPointer, StackPointer, -int32_t(f.size())); + if (f.isDouble()) { + as_fst_d(f, StackPointer, 0); + } else { + as_fst_s(f, StackPointer, 0); + } +} + +void MacroAssemblerLOONGARCH64::ma_li(Register dest, ImmGCPtr ptr) { + writeDataRelocation(ptr); + asMasm().ma_liPatchable(dest, ImmPtr(ptr.value)); +} + +void MacroAssemblerLOONGARCH64::ma_li(Register dest, Imm32 imm) { + if (is_intN(imm.value, 12)) { + as_addi_w(dest, zero, imm.value); + } else if (is_uintN(imm.value, 12)) { + as_ori(dest, zero, imm.value & 0xfff); + } else { + as_lu12i_w(dest, imm.value >> 12 & 0xfffff); + if (imm.value & 0xfff) { + as_ori(dest, dest, imm.value & 0xfff); + } + } +} + +// This method generates lu12i_w and ori instruction pair that can be modified +// by UpdateLuiOriValue, either during compilation (eg. Assembler::bind), or +// during execution (eg. jit::PatchJump). +void MacroAssemblerLOONGARCH64::ma_liPatchable(Register dest, Imm32 imm) { + m_buffer.ensureSpace(2 * sizeof(uint32_t)); + as_lu12i_w(dest, imm.value >> 12 & 0xfffff); + as_ori(dest, dest, imm.value & 0xfff); +} + +void MacroAssemblerLOONGARCH64::ma_fmovz(FloatFormat fmt, FloatRegister fd, + FloatRegister fj, Register rk) { + Label done; + ma_b(rk, zero, &done, Assembler::NotEqual); + if (fmt == SingleFloat) { + as_fmov_s(fd, fj); + } else { + as_fmov_d(fd, fj); + } + bind(&done); +} + +void MacroAssemblerLOONGARCH64::ma_fmovn(FloatFormat fmt, FloatRegister fd, + FloatRegister fj, Register rk) { + Label done; + ma_b(rk, zero, &done, Assembler::Equal); + if (fmt == SingleFloat) { + as_fmov_s(fd, fj); + } else { + as_fmov_d(fd, fj); + } + bind(&done); +} + +void MacroAssemblerLOONGARCH64::ma_and(Register rd, Register rj, Imm32 imm, + bool bit32) { + if (is_uintN(imm.value, 12)) { + as_andi(rd, rj, imm.value); + } else if (rd != rj) { + ma_li(rd, imm); + as_and(rd, rj, rd); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_and(rd, rj, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_or(Register rd, Register rj, Imm32 imm, + bool bit32) { + if (is_uintN(imm.value, 12)) { + as_ori(rd, rj, imm.value); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_or(rd, rj, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_xor(Register rd, Register rj, Imm32 imm, + bool bit32) { + if (is_uintN(imm.value, 12)) { + as_xori(rd, rj, imm.value); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_xor(rd, rj, scratch); + } +} + +// Arithmetic-based ops. + +// Add. +void MacroAssemblerLOONGARCH64::ma_add_w(Register rd, Register rj, Imm32 imm) { + if (is_intN(imm.value, 12)) { + as_addi_w(rd, rj, imm.value); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_add_w(rd, rj, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_add32TestCarry(Condition cond, Register rd, + Register rj, Register rk, + Label* overflow) { + MOZ_ASSERT(cond == Assembler::CarrySet || cond == Assembler::CarryClear); + MOZ_ASSERT_IF(rd == rj, rk != rd); + ScratchRegisterScope scratch(asMasm()); + as_add_w(rd, rj, rk); + as_sltu(scratch, rd, rd == rj ? rk : rj); + ma_b(Register(scratch), Register(scratch), overflow, + cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero); +} + +void MacroAssemblerLOONGARCH64::ma_add32TestCarry(Condition cond, Register rd, + Register rj, Imm32 imm, + Label* overflow) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(rj != scratch2); + ma_li(scratch2, imm); + ma_add32TestCarry(cond, rd, rj, scratch2, overflow); +} + +// Subtract. +void MacroAssemblerLOONGARCH64::ma_sub_w(Register rd, Register rj, Imm32 imm) { + if (is_intN(-imm.value, 12)) { + as_addi_w(rd, rj, -imm.value); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_sub_w(rd, rj, scratch); + } +} + +void MacroAssemblerLOONGARCH64::ma_sub_w(Register rd, Register rj, Register rk) { + as_sub_w(rd, rj, rk); +} + +void MacroAssemblerLOONGARCH64::ma_sub32TestOverflow(Register rd, Register rj, + Imm32 imm, Label* overflow) { + if (imm.value != INT32_MIN) { + asMasm().ma_add32TestOverflow(rd, rj, Imm32(-imm.value), overflow); + } else { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, Imm32(imm.value)); + asMasm().ma_sub32TestOverflow(rd, rj, scratch, overflow); + } +} + +void MacroAssemblerLOONGARCH64::ma_mul(Register rd, Register rj, Imm32 imm) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rj != scratch); + ma_li(scratch, imm); + as_mul_w(rd, rj, scratch); +} + +void MacroAssemblerLOONGARCH64::ma_mul32TestOverflow(Register rd, Register rj, + Register rk, Label* overflow) { + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + as_mulh_w(scratch, rj, rk); + as_mul_w(rd, rj, rk); + as_srai_w(scratch2, rd, 31); + ma_b(scratch, Register(scratch2), overflow, Assembler::NotEqual); +} + +void MacroAssemblerLOONGARCH64::ma_mul32TestOverflow(Register rd, Register rj, + Imm32 imm, Label* overflow) { + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch, imm); + as_mulh_w(scratch2, rj, scratch); + as_mul_w(rd, rj, scratch); + as_srai_w(scratch, rd, 31); + ma_b(scratch, Register(scratch2), overflow, Assembler::NotEqual); +} + +void MacroAssemblerLOONGARCH64::ma_div_branch_overflow(Register rd, Register rj, + Register rk, + Label* overflow) { + ScratchRegisterScope scratch(asMasm()); + as_mod_w(scratch, rj, rk); + ma_b(scratch, scratch, overflow, Assembler::NonZero); + as_div_w(rd, rj, rk); +} + +void MacroAssemblerLOONGARCH64::ma_div_branch_overflow(Register rd, Register rj, + Imm32 imm, Label* overflow) { + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch2, imm); + ma_div_branch_overflow(rd, rj, scratch2, overflow); +} + +void MacroAssemblerLOONGARCH64::ma_mod_mask(Register src, Register dest, + Register hold, Register remain, + int32_t shift, Label* negZero) { + // MATH: + // We wish to compute x % (1< 0, store sum - C back into sum, thus performing a + // modulus. + ma_b(scratch2, Register(scratch2), &sumSigned, Signed, ShortJump); + as_or(dest, scratch2, zero); + bind(&sumSigned); + // Get rid of the bits that we extracted before. + as_srli_w(remain, remain, shift); + // If the shift produced zero, finish, otherwise, continue in the loop. + ma_b(remain, remain, &head, NonZero, ShortJump); + // Check the hold to see if we need to negate the result. + ma_b(hold, hold, &done, NotSigned, ShortJump); + + // If the hold was non-zero, negate the result to be in line with + // what JS wants + if (negZero != nullptr) { + // Jump out in case of negative zero. + ma_b(hold, hold, negZero, Zero); + as_sub_w(dest, zero, dest); + } else { + as_sub_w(dest, zero, dest); + } + + bind(&done); +} + +// Memory. + +void MacroAssemblerLOONGARCH64::ma_load(Register dest, const BaseIndex& src, + LoadStoreSize size, + LoadStoreExtension extension) { + SecondScratchRegisterScope scratch2(asMasm()); + asMasm().computeScaledAddress(src, scratch2); + asMasm().ma_load(dest, Address(scratch2, src.offset), size, extension); +} + +void MacroAssemblerLOONGARCH64::ma_store(Register data, const BaseIndex& dest, + LoadStoreSize size, + LoadStoreExtension extension) { + SecondScratchRegisterScope scratch2(asMasm()); + asMasm().computeScaledAddress(dest, scratch2); + asMasm().ma_store(data, Address(scratch2, dest.offset), size, extension); +} + +void MacroAssemblerLOONGARCH64::ma_store(Imm32 imm, const BaseIndex& dest, + LoadStoreSize size, + LoadStoreExtension extension) { + SecondScratchRegisterScope scratch2(asMasm()); + // Make sure that scratch2 contains absolute address so that offset is 0. + asMasm().computeEffectiveAddress(dest, scratch2); + + ScratchRegisterScope scratch(asMasm()); + // Scrach register is free now, use it for loading imm value + ma_li(scratch, imm); + + // with offset=0 ScratchRegister will not be used in ma_store() + // so we can use it as a parameter here + asMasm().ma_store(scratch, Address(scratch2, 0), size, extension); +} + +void MacroAssemblerLOONGARCH64::ma_load_unaligned( + const wasm::MemoryAccessDesc& access, Register dest, const BaseIndex& src, + Register temp, LoadStoreSize size, LoadStoreExtension extension) { + MOZ_ASSERT(dest != temp); + + asMasm().computeEffectiveAddress(src, temp); + + BufferOffset load = as_ld_bu(dest, temp, 0); + if (size != SizeByte) { + ScratchRegisterScope scratch(asMasm()); + const size_t byteSize = size / 8; + for (size_t i = 1; i < byteSize; i++) { + as_ld_bu(scratch, temp, i); + as_slli_d(scratch, scratch, 8 * i); + as_or(dest, dest, scratch); + } + } + + switch (size) { + case SizeByte: + if (extension == SignExtend) { + as_ext_w_b(dest, dest); + } + break; + case SizeHalfWord: + if (extension == SignExtend) { + as_ext_w_h(dest, dest); + } + break; + case SizeWord: + if (extension == SignExtend) { + as_addi_w(dest, dest, 0); + } + break; + case SizeDouble: + break; + default: + MOZ_CRASH("Invalid argument for ma_load_unaligned"); + } + + append(access, load.getOffset(), asMasm().framePushed()); +} + +void MacroAssemblerLOONGARCH64::ma_store_unaligned( + const wasm::MemoryAccessDesc& access, Register data, const BaseIndex& dest, + Register temp, LoadStoreSize size, LoadStoreExtension extension) { + (void)extension; + + MOZ_ASSERT(data != temp); + + asMasm().computeEffectiveAddress(dest, temp); + + BufferOffset store = as_st_b(data, temp, 0); + if (size != SizeByte) { + ScratchRegisterScope scratch(asMasm()); + const size_t byteSize = size / 8; + for (size_t i = 1; i < byteSize; i++) { + as_srli_d(scratch, data, 8 * i); + as_st_b(scratch, temp, i); + } + } + + append(access, store.getOffset(), asMasm().framePushed()); +} + +void MacroAssemblerLOONGARCH64::loadUnalignedDouble( + const wasm::MemoryAccessDesc& access, const BaseIndex& src, Register temp, + FloatRegister dest) { + asMasm().computeEffectiveAddress(src, temp); + + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + + BufferOffset load = as_ld_bu(scratch, temp, 0); + for (size_t i = 1; i < sizeof(double); i++) { + as_ld_bu(scratch2, temp, i); + as_slli_d(scratch2, scratch2, 8 * i); + as_or(scratch, scratch, scratch2); + } + + append(access, load.getOffset(), asMasm().framePushed()); + moveToDouble(scratch, dest); +} + +void MacroAssemblerLOONGARCH64::loadUnalignedFloat32( + const wasm::MemoryAccessDesc& access, const BaseIndex& src, Register temp, + FloatRegister dest) { + asMasm().computeEffectiveAddress(src, temp); + + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + + BufferOffset load = as_ld_bu(scratch, temp, 0); + for (size_t i = 1; i < sizeof(float); i++) { + as_ld_bu(scratch2, temp, i); + as_slli_d(scratch2, scratch2, 8 * i); + as_or(scratch, scratch, scratch2); + } + + append(access, load.getOffset(), asMasm().framePushed()); + moveToFloat32(scratch, dest); +} + +void MacroAssemblerLOONGARCH64::storeUnalignedDouble( + const wasm::MemoryAccessDesc& access, FloatRegister src, Register temp, + const BaseIndex& dest) { + asMasm().computeEffectiveAddress(dest, temp); + + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + moveFromDouble(src, scratch); + + BufferOffset store = as_st_b(scratch, temp, 0); + for (size_t i = 1; i < sizeof(double); i++) { + as_srli_d(scratch2, scratch, 8 * i); + as_st_b(scratch2, temp, i); + } + + append(access, store.getOffset(), asMasm().framePushed()); +} + +void MacroAssemblerLOONGARCH64::storeUnalignedFloat32( + const wasm::MemoryAccessDesc& access, FloatRegister src, Register temp, + const BaseIndex& dest) { + asMasm().computeEffectiveAddress(dest, temp); + + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + moveFromFloat32(src, scratch); + + BufferOffset store = as_st_b(scratch, temp, 0); + for (size_t i = 1; i < sizeof(float); i++) { + as_srli_d(scratch2, scratch, 8 * i); + as_st_b(scratch2, temp, i); + } + + append(access, store.getOffset(), asMasm().framePushed()); +} + +// Branches when done from within loongarch-specific code. +// TODO(loongarch64) Optimize ma_b +void MacroAssemblerLOONGARCH64::ma_b(Register lhs, Register rhs, Label* label, + Condition c, JumpKind jumpKind) { + switch (c) { + case Equal: + case NotEqual: + asMasm().branchWithCode(getBranchCode(lhs, rhs, c), label, jumpKind); + break; + case Always: + ma_b(label, jumpKind); + break; + case Zero: + case NonZero: + case Signed: + case NotSigned: + MOZ_ASSERT(lhs == rhs); + asMasm().branchWithCode(getBranchCode(lhs, c), label, jumpKind); + break; + default: { + Condition cond = ma_cmp(ScratchRegister, lhs, rhs, c); + asMasm().branchWithCode(getBranchCode(ScratchRegister, cond), label, + jumpKind); + break; + } + } +} + +void MacroAssemblerLOONGARCH64::ma_b(Register lhs, Imm32 imm, Label* label, + Condition c, JumpKind jumpKind) { + MOZ_ASSERT(c != Overflow); + if (imm.value == 0) { + if (c == Always || c == AboveOrEqual) { + ma_b(label, jumpKind); + } else if (c == Below) { + ; // This condition is always false. No branch required. + } else { + asMasm().branchWithCode(getBranchCode(lhs, c), label, jumpKind); + } + } else { + switch (c) { + case Equal: + case NotEqual: + MOZ_ASSERT(lhs != ScratchRegister); + ma_li(ScratchRegister, imm); + ma_b(lhs, ScratchRegister, label, c, jumpKind); + break; + default: + Condition cond = ma_cmp(ScratchRegister, lhs, imm, c); + asMasm().branchWithCode(getBranchCode(ScratchRegister, cond), label, + jumpKind); + } + } +} + +void MacroAssemblerLOONGARCH64::ma_b(Register lhs, ImmPtr imm, Label* l, + Condition c, JumpKind jumpKind) { + asMasm().ma_b(lhs, ImmWord(uintptr_t(imm.value)), l, c, jumpKind); +} + +void MacroAssemblerLOONGARCH64::ma_b(Label* label, JumpKind jumpKind) { + asMasm().branchWithCode(getBranchCode(BranchIsJump), label, jumpKind); +} + +Assembler::Condition MacroAssemblerLOONGARCH64::ma_cmp(Register dest, Register lhs, + Register rhs, Condition c) { + switch (c) { + case Above: + // bgtu s,t,label => + // sltu at,t,s + // bne at,$zero,offs + as_sltu(dest, rhs, lhs); + return NotEqual; + case AboveOrEqual: + // bgeu s,t,label => + // sltu at,s,t + // beq at,$zero,offs + as_sltu(dest, lhs, rhs); + return Equal; + case Below: + // bltu s,t,label => + // sltu at,s,t + // bne at,$zero,offs + as_sltu(dest, lhs, rhs); + return NotEqual; + case BelowOrEqual: + // bleu s,t,label => + // sltu at,t,s + // beq at,$zero,offs + as_sltu(dest, rhs, lhs); + return Equal; + case GreaterThan: + // bgt s,t,label => + // slt at,t,s + // bne at,$zero,offs + as_slt(dest, rhs, lhs); + return NotEqual; + case GreaterThanOrEqual: + // bge s,t,label => + // slt at,s,t + // beq at,$zero,offs + as_slt(dest, lhs, rhs); + return Equal; + case LessThan: + // blt s,t,label => + // slt at,s,t + // bne at,$zero,offs + as_slt(dest, lhs, rhs); + return NotEqual; + case LessThanOrEqual: + // ble s,t,label => + // slt at,t,s + // beq at,$zero,offs + as_slt(dest, rhs, lhs); + return Equal; + default: + MOZ_CRASH("Invalid condition."); + } + return Always; +} + +Assembler::Condition MacroAssemblerLOONGARCH64::ma_cmp(Register dest, Register lhs, + Imm32 imm, Condition c) { + ScratchRegisterScope scratch(asMasm()); + MOZ_RELEASE_ASSERT(lhs != scratch); + + switch (c) { + case Above: + case BelowOrEqual: + if (imm.value != 0x7fffffff && is_intN(imm.value + 1, 12) && + imm.value != -1) { + // lhs <= rhs via lhs < rhs + 1 if rhs + 1 does not overflow + as_sltui(dest, lhs, imm.value + 1); + + return (c == BelowOrEqual ? NotEqual : Equal); + } else { + ma_li(scratch, imm); + as_sltu(dest, scratch, lhs); + return (c == BelowOrEqual ? Equal : NotEqual); + } + case AboveOrEqual: + case Below: + if (is_intN(imm.value, 12)) { + as_sltui(dest, lhs, imm.value); + } else { + ma_li(scratch, imm); + as_sltu(dest, lhs, scratch); + } + return (c == AboveOrEqual ? Equal : NotEqual); + case GreaterThan: + case LessThanOrEqual: + if (imm.value != 0x7fffffff && is_intN(imm.value + 1, 12)) { + // lhs <= rhs via lhs < rhs + 1. + as_slti(dest, lhs, imm.value + 1); + return (c == LessThanOrEqual ? NotEqual : Equal); + } else { + ma_li(scratch, imm); + as_slt(dest, scratch, lhs); + return (c == LessThanOrEqual ? Equal : NotEqual); + } + case GreaterThanOrEqual: + case LessThan: + if (is_intN(imm.value, 12)) { + as_slti(dest, lhs, imm.value); + } else { + ma_li(scratch, imm); + as_slt(dest, lhs, scratch); + } + return (c == GreaterThanOrEqual ? Equal : NotEqual); + default: + MOZ_CRASH("Invalid condition."); + } + return Always; +} + +// fp instructions +void MacroAssemblerLOONGARCH64::ma_lis(FloatRegister dest, float value) { + Imm32 imm(mozilla::BitwiseCast(value)); + + if (imm.value != 0) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + moveToFloat32(scratch, dest); + } else { + moveToFloat32(zero, dest); + } +} + +void MacroAssemblerLOONGARCH64::ma_fst_d(FloatRegister ft, BaseIndex address) { + SecondScratchRegisterScope scratch2(asMasm()); + asMasm().computeScaledAddress(address, scratch2); + asMasm().ma_fst_d(ft, Address(scratch2, address.offset)); +} + +void MacroAssemblerLOONGARCH64::ma_fst_s(FloatRegister ft, BaseIndex address) { + SecondScratchRegisterScope scratch2(asMasm()); + asMasm().computeScaledAddress(address, scratch2); + asMasm().ma_fst_s(ft, Address(scratch2, address.offset)); +} + +void MacroAssemblerLOONGARCH64::ma_fld_d(FloatRegister ft, const BaseIndex& src) { + SecondScratchRegisterScope scratch2(asMasm()); + asMasm().computeScaledAddress(src, scratch2); + asMasm().ma_fld_d(ft, Address(scratch2, src.offset)); +} + +void MacroAssemblerLOONGARCH64::ma_fld_s(FloatRegister ft, const BaseIndex& src) { + SecondScratchRegisterScope scratch2(asMasm()); + asMasm().computeScaledAddress(src, scratch2); + asMasm().ma_fld_s(ft, Address(scratch2, src.offset)); +} + +void MacroAssemblerLOONGARCH64::ma_bc_s(FloatRegister lhs, FloatRegister rhs, + Label* label, DoubleCondition c, + JumpKind jumpKind, FPConditionBit fcc) { + compareFloatingPoint(SingleFloat, lhs, rhs, c, fcc); + asMasm().branchWithCode(getBranchCode(fcc), label, jumpKind); +} + +void MacroAssemblerLOONGARCH64::ma_bc_d(FloatRegister lhs, FloatRegister rhs, + Label* label, DoubleCondition c, + JumpKind jumpKind, FPConditionBit fcc) { + compareFloatingPoint(DoubleFloat, lhs, rhs, c, fcc); + asMasm().branchWithCode(getBranchCode(fcc), label, jumpKind); +} + +void MacroAssemblerLOONGARCH64::ma_call(ImmPtr dest) { + asMasm().ma_liPatchable(CallReg, dest); + as_jirl(ra, CallReg, BOffImm16(0)); +} + +void MacroAssemblerLOONGARCH64::ma_jump(ImmPtr dest) { + ScratchRegisterScope scratch(asMasm()); + asMasm().ma_liPatchable(scratch, dest); + as_jirl(zero, scratch, BOffImm16(0)); +} + +void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Register rj, Register rk, + Condition c) { + switch (c) { + case Equal: + // seq d,s,t => + // xor d,s,t + // sltiu d,d,1 + as_xor(rd, rj, rk); + as_sltui(rd, rd, 1); + break; + case NotEqual: + // sne d,s,t => + // xor d,s,t + // sltu d,$zero,d + as_xor(rd, rj, rk); + as_sltu(rd, zero, rd); + break; + case Above: + // sgtu d,s,t => + // sltu d,t,s + as_sltu(rd, rk, rj); + break; + case AboveOrEqual: + // sgeu d,s,t => + // sltu d,s,t + // xori d,d,1 + as_sltu(rd, rj, rk); + as_xori(rd, rd, 1); + break; + case Below: + // sltu d,s,t + as_sltu(rd, rj, rk); + break; + case BelowOrEqual: + // sleu d,s,t => + // sltu d,t,s + // xori d,d,1 + as_sltu(rd, rk, rj); + as_xori(rd, rd, 1); + break; + case GreaterThan: + // sgt d,s,t => + // slt d,t,s + as_slt(rd, rk, rj); + break; + case GreaterThanOrEqual: + // sge d,s,t => + // slt d,s,t + // xori d,d,1 + as_slt(rd, rj, rk); + as_xori(rd, rd, 1); + break; + case LessThan: + // slt d,s,t + as_slt(rd, rj, rk); + break; + case LessThanOrEqual: + // sle d,s,t => + // slt d,t,s + // xori d,d,1 + as_slt(rd, rk, rj); + as_xori(rd, rd, 1); + break; + case Zero: + MOZ_ASSERT(rj == rk); + // seq d,s,$zero => + // sltiu d,s,1 + as_sltui(rd, rj, 1); + break; + case NonZero: + MOZ_ASSERT(rj == rk); + // sne d,s,$zero => + // sltu d,$zero,s + as_sltu(rd, zero, rj); + break; + case Signed: + MOZ_ASSERT(rj == rk); + as_slt(rd, rj, zero); + break; + case NotSigned: + MOZ_ASSERT(rj == rk); + // sge d,s,$zero => + // slt d,s,$zero + // xori d,d,1 + as_slt(rd, rj, zero); + as_xori(rd, rd, 1); + break; + default: + MOZ_CRASH("Invalid condition."); + } +} + +void MacroAssemblerLOONGARCH64::ma_cmp_set_double(Register dest, FloatRegister lhs, + FloatRegister rhs, + DoubleCondition c) { + compareFloatingPoint(DoubleFloat, lhs, rhs, c); + as_movcf2gr(dest, FCC0); +} + +void MacroAssemblerLOONGARCH64::ma_cmp_set_float32(Register dest, FloatRegister lhs, + FloatRegister rhs, + DoubleCondition c) { + compareFloatingPoint(SingleFloat, lhs, rhs, c); + as_movcf2gr(dest, FCC0); +} + +void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Register rj, Imm32 imm, + Condition c) { + if (imm.value == 0) { + switch (c) { + case Equal: + case BelowOrEqual: + as_sltui(rd, rj, 1); + break; + case NotEqual: + case Above: + as_sltu(rd, zero, rj); + break; + case AboveOrEqual: + case Below: + as_ori(rd, zero, c == AboveOrEqual ? 1 : 0); + break; + case GreaterThan: + case LessThanOrEqual: + as_slt(rd, zero, rj); + if (c == LessThanOrEqual) { + as_xori(rd, rd, 1); + } + break; + case LessThan: + case GreaterThanOrEqual: + as_slt(rd, rj, zero); + if (c == GreaterThanOrEqual) { + as_xori(rd, rd, 1); + } + break; + case Zero: + as_sltui(rd, rj, 1); + break; + case NonZero: + as_sltu(rd, zero, rj); + break; + case Signed: + as_slt(rd, rj, zero); + break; + case NotSigned: + as_slt(rd, rj, zero); + as_xori(rd, rd, 1); + break; + default: + MOZ_CRASH("Invalid condition."); + } + return; + } + + switch (c) { + case Equal: + case NotEqual: + ma_xor(rd, rj, imm); + if (c == Equal) { + as_sltui(rd, rd, 1); + } else { + as_sltu(rd, zero, rd); + } + break; + case Zero: + case NonZero: + case Signed: + case NotSigned: + MOZ_CRASH("Invalid condition."); + default: + Condition cond = ma_cmp(rd, rj, imm, c); + MOZ_ASSERT(cond == Equal || cond == NotEqual); + + if (cond == Equal) as_xori(rd, rd, 1); + } +} + +void MacroAssemblerLOONGARCH64::compareFloatingPoint(FloatFormat fmt, + FloatRegister lhs, + FloatRegister rhs, + DoubleCondition c, + FPConditionBit fcc) { + switch (c) { + case DoubleOrdered: + as_fcmp_cor(fmt, lhs, rhs, fcc); + break; + case DoubleEqual: + as_fcmp_ceq(fmt, lhs, rhs, fcc); + break; + case DoubleNotEqual: + as_fcmp_cne(fmt, lhs, rhs, fcc); + break; + case DoubleGreaterThan: + as_fcmp_clt(fmt, rhs, lhs, fcc); + break; + case DoubleGreaterThanOrEqual: + as_fcmp_cle(fmt, rhs, lhs, fcc); + break; + case DoubleLessThan: + as_fcmp_clt(fmt, lhs, rhs, fcc); + break; + case DoubleLessThanOrEqual: + as_fcmp_cle(fmt, lhs, rhs, fcc); + break; + case DoubleUnordered: + as_fcmp_cun(fmt, lhs, rhs, fcc); + break; + case DoubleEqualOrUnordered: + as_fcmp_cueq(fmt, lhs, rhs, fcc); + break; + case DoubleNotEqualOrUnordered: + as_fcmp_cune(fmt, lhs, rhs, fcc); + break; + case DoubleGreaterThanOrUnordered: + as_fcmp_cult(fmt, rhs, lhs, fcc); + break; + case DoubleGreaterThanOrEqualOrUnordered: + as_fcmp_cule(fmt, rhs, lhs, fcc); + break; + case DoubleLessThanOrUnordered: + as_fcmp_cult(fmt, lhs, rhs, fcc); + break; + case DoubleLessThanOrEqualOrUnordered: + as_fcmp_cule(fmt, lhs, rhs, fcc); + break; + default: + MOZ_CRASH("Invalid DoubleCondition."); + } +} + +void MacroAssemblerLOONGARCH64::minMaxDouble(FloatRegister srcDest, + FloatRegister second, bool handleNaN, + bool isMax) { + if (srcDest == second) return; + + Label nan, done; + + // First or second is NaN, result is NaN. + ma_bc_d(srcDest, second, &nan, Assembler::DoubleUnordered, ShortJump); + if (isMax) { + as_fmax_d(srcDest, srcDest, second); + } else { + as_fmin_d(srcDest, srcDest, second); + } + ma_b(&done, ShortJump); + + bind(&nan); + as_fadd_d(srcDest, srcDest, second); + + bind(&done); +} + +void MacroAssemblerLOONGARCH64::minMaxFloat32(FloatRegister srcDest, + FloatRegister second, bool handleNaN, + bool isMax) { + if (srcDest == second) return; + + Label nan, done; + + // First or second is NaN, result is NaN. + ma_bc_s(srcDest, second, &nan, Assembler::DoubleUnordered, ShortJump); + if (isMax) { + as_fmax_s(srcDest, srcDest, second); + } else { + as_fmin_s(srcDest, srcDest, second); + } + ma_b(&done, ShortJump); + + bind(&nan); + as_fadd_s(srcDest, srcDest, second); + + bind(&done); +} + +void MacroAssemblerLOONGARCH64::loadDouble(const Address& address, + FloatRegister dest) { + asMasm().ma_fld_d(dest, address); +} + +void MacroAssemblerLOONGARCH64::loadDouble(const BaseIndex& src, + FloatRegister dest) { + asMasm().ma_fld_d(dest, src); +} + +void MacroAssemblerLOONGARCH64::loadFloatAsDouble(const Address& address, + FloatRegister dest) { + asMasm().ma_fld_s(dest, address); + as_fcvt_d_s(dest, dest); +} + +void MacroAssemblerLOONGARCH64::loadFloatAsDouble(const BaseIndex& src, + FloatRegister dest) { + asMasm().loadFloat32(src, dest); + as_fcvt_d_s(dest, dest); +} + +void MacroAssemblerLOONGARCH64::loadFloat32(const Address& address, + FloatRegister dest) { + asMasm().ma_fld_s(dest, address); +} + +void MacroAssemblerLOONGARCH64::loadFloat32(const BaseIndex& src, + FloatRegister dest) { + asMasm().ma_fld_s(dest, src); +} + +void MacroAssemblerLOONGARCH64::wasmLoadImpl(const wasm::MemoryAccessDesc& access, + Register memoryBase, Register ptr, + Register ptrScratch, + AnyRegister output, Register tmp) { + uint32_t offset = access.offset(); + MOZ_ASSERT(offset < asMasm().wasmMaxOffsetGuardLimit()); + MOZ_ASSERT_IF(offset, ptrScratch != InvalidReg); + + // Maybe add the offset. + if (offset) { + asMasm().addPtr(ImmWord(offset), ptrScratch); + ptr = ptrScratch; + } + + asMasm().memoryBarrier(access.barrierBefore()); + + switch (access.type()) { + case Scalar::Int8: + as_ldx_b(output.gpr(), memoryBase, ptr); + break; + case Scalar::Uint8: + as_ldx_bu(output.gpr(), memoryBase, ptr); + break; + case Scalar::Int16: + as_ldx_h(output.gpr(), memoryBase, ptr); + break; + case Scalar::Uint16: + as_ldx_hu(output.gpr(), memoryBase, ptr); + break; + case Scalar::Int32: + case Scalar::Uint32: + as_ldx_w(output.gpr(), memoryBase, ptr); + break; + case Scalar::Float64: + as_fldx_d(output.fpu(), memoryBase, ptr); + break; + case Scalar::Float32: + as_fldx_s(output.fpu(), memoryBase, ptr); + break; + default: + MOZ_CRASH("unexpected array type"); + } + + asMasm().append(access, asMasm().size() - 4, asMasm().framePushed()); + asMasm().memoryBarrier(access.barrierAfter()); +} + +void MacroAssemblerLOONGARCH64::wasmStoreImpl(const wasm::MemoryAccessDesc& access, + AnyRegister value, + Register memoryBase, Register ptr, + Register ptrScratch, Register tmp) { + uint32_t offset = access.offset(); + MOZ_ASSERT(offset < asMasm().wasmMaxOffsetGuardLimit()); + MOZ_ASSERT_IF(offset, ptrScratch != InvalidReg); + + // Maybe add the offset. + if (offset) { + asMasm().addPtr(ImmWord(offset), ptrScratch); + ptr = ptrScratch; + } + + asMasm().memoryBarrier(access.barrierBefore()); + + switch (access.type()) { + case Scalar::Int8: + case Scalar::Uint8: + as_stx_b(value.gpr(), memoryBase, ptr); + break; + case Scalar::Int16: + case Scalar::Uint16: + as_stx_h(value.gpr(), memoryBase, ptr); + break; + case Scalar::Int32: + case Scalar::Uint32: + as_stx_w(value.gpr(), memoryBase, ptr); + break; + case Scalar::Int64: + as_stx_d(value.gpr(), memoryBase, ptr); + break; + case Scalar::Float64: + as_fstx_d(value.fpu(), memoryBase, ptr); + break; + case Scalar::Float32: + as_fstx_s(value.fpu(), memoryBase, ptr); + break; + default: + MOZ_CRASH("unexpected array type"); + } + + // Only the last emitted instruction is a memory access. + asMasm().append(access, asMasm().size() - 4, asMasm().framePushed()); + asMasm().memoryBarrier(access.barrierAfter()); +} + +void MacroAssemblerLOONGARCH64Compat::wasmLoadI64Impl( + const wasm::MemoryAccessDesc& access, Register memoryBase, Register ptr, + Register ptrScratch, Register64 output, Register tmp) { + uint32_t offset = access.offset(); + MOZ_ASSERT(offset < asMasm().wasmMaxOffsetGuardLimit()); + MOZ_ASSERT_IF(offset, ptrScratch != InvalidReg); + + // Maybe add the offset. + if (offset) { + asMasm().addPtr(ImmWord(offset), ptrScratch); + ptr = ptrScratch; + } + + asMasm().memoryBarrier(access.barrierBefore()); + + switch (access.type()) { + case Scalar::Int8: + as_ldx_b(output.reg, memoryBase, ptr); + break; + case Scalar::Uint8: + as_ldx_bu(output.reg, memoryBase, ptr); + break; + case Scalar::Int16: + as_ldx_h(output.reg, memoryBase, ptr); + break; + case Scalar::Uint16: + as_ldx_hu(output.reg, memoryBase, ptr); + break; + case Scalar::Int32: + as_ldx_w(output.reg, memoryBase, ptr); + break; + case Scalar::Uint32: + // TODO(loongarch64): Why need zero-extension here? + as_ldx_wu(output.reg, memoryBase, ptr); + break; + case Scalar::Int64: + as_ldx_d(output.reg, memoryBase, ptr); + break; + default: + MOZ_CRASH("unexpected array type"); + } + + asMasm().append(access, asMasm().size() - 4, asMasm().framePushed()); + asMasm().memoryBarrier(access.barrierAfter()); +} + +void MacroAssemblerLOONGARCH64Compat::wasmStoreI64Impl( + const wasm::MemoryAccessDesc& access, Register64 value, Register memoryBase, + Register ptr, Register ptrScratch, Register tmp) { + uint32_t offset = access.offset(); + MOZ_ASSERT(offset < asMasm().wasmMaxOffsetGuardLimit()); + MOZ_ASSERT_IF(offset, ptrScratch != InvalidReg); + + // Maybe add the offset. + if (offset) { + asMasm().addPtr(ImmWord(offset), ptrScratch); + ptr = ptrScratch; + } + + asMasm().memoryBarrier(access.barrierBefore()); + + switch (access.type()) { + case Scalar::Int8: + case Scalar::Uint8: + as_stx_b(value.reg, memoryBase, ptr); + break; + case Scalar::Int16: + case Scalar::Uint16: + as_stx_h(value.reg, memoryBase, ptr); + break; + case Scalar::Int32: + case Scalar::Uint32: + as_stx_w(value.reg, memoryBase, ptr); + break; + case Scalar::Int64: + as_stx_d(value.reg, memoryBase, ptr); + break; + default: + MOZ_CRASH("unexpected array type"); + } + + asMasm().append(access, asMasm().size() - 4, asMasm().framePushed()); + asMasm().memoryBarrier(access.barrierAfter()); +} + +void MacroAssemblerLOONGARCH64Compat::profilerEnterFrame(Register framePtr, + Register scratch) { + AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation()); + loadPtr(activation, scratch); + storePtr(framePtr, + Address(scratch, JitActivation::offsetOfLastProfilingFrame())); + storePtr(ImmPtr(nullptr), + Address(scratch, JitActivation::offsetOfLastProfilingCallSite())); +} + +void MacroAssemblerLOONGARCH64Compat::profilerExitFrame() { + jump(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail()); +} + +MacroAssembler& MacroAssemblerLOONGARCH64::asMasm() { + return *static_cast(this); +} + +const MacroAssembler& MacroAssemblerLOONGARCH64::asMasm() const { + return *static_cast(this); +} + +void MacroAssembler::subFromStackPtr(Imm32 imm32) { + if (imm32.value) { + asMasm().subPtr(imm32, StackPointer); + } +} + +//{{{ check_macroassembler_style +// =============================================================== +// MacroAssembler high-level usage. + +void MacroAssembler::flush() {} + +// =============================================================== +// Stack manipulation functions. + +void MacroAssembler::PushRegsInMask(LiveRegisterSet set) { + int32_t diff = + set.gprs().size() * sizeof(intptr_t) + set.fpus().getPushSizeInBytes(); + const int32_t reserved = diff; + + reserveStack(reserved); + for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) { + diff -= sizeof(intptr_t); + storePtr(*iter, Address(StackPointer, diff)); + } + +#ifdef ENABLE_WASM_SIMD +# error "Needs more careful logic if SIMD is enabled" +#endif + + for (FloatRegisterBackwardIterator iter(set.fpus().reduceSetForPush()); + iter.more(); ++iter) { + diff -= sizeof(double); + storeDouble(*iter, Address(StackPointer, diff)); + } + MOZ_ASSERT(diff == 0); +} + +void MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set, + LiveRegisterSet ignore) { + int32_t diff = + set.gprs().size() * sizeof(intptr_t) + set.fpus().getPushSizeInBytes(); + const int32_t reserved = diff; + + for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) { + diff -= sizeof(intptr_t); + if (!ignore.has(*iter)) { + loadPtr(Address(StackPointer, diff), *iter); + } + } + +#ifdef ENABLE_WASM_SIMD +# error "Needs more careful logic if SIMD is enabled" +#endif + + for (FloatRegisterBackwardIterator iter(set.fpus().reduceSetForPush()); + iter.more(); ++iter) { + diff -= sizeof(double); + if (!ignore.has(*iter)) { + loadDouble(Address(StackPointer, diff), *iter); + } + } + MOZ_ASSERT(diff == 0); + freeStack(reserved); +} + +void MacroAssembler::Push(Register reg) { + ma_push(reg); + adjustFrame(int32_t(sizeof(intptr_t))); +} + +void MacroAssembler::Push(const Imm32 imm) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + ma_push(scratch); + adjustFrame(int32_t(sizeof(intptr_t))); +} + +void MacroAssembler::Push(const ImmWord imm) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + ma_push(scratch); + adjustFrame(int32_t(sizeof(intptr_t))); +} + +void MacroAssembler::Push(const ImmPtr imm) { + Push(ImmWord(uintptr_t(imm.value))); +} + +void MacroAssembler::Push(const ImmGCPtr ptr) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, ptr); + ma_push(scratch); + adjustFrame(int32_t(sizeof(intptr_t))); +} + +void MacroAssembler::Push(FloatRegister f) { + ma_push(f); + adjustFrame(int32_t(f.size())); +} + +void MacroAssembler::Pop(Register reg) { + ma_pop(reg); + adjustFrame(-int32_t(sizeof(intptr_t))); +} + +void MacroAssembler::Pop(FloatRegister f) { + ma_pop(f); + adjustFrame(-int32_t(f.size())); +} + +void MacroAssembler::Pop(const ValueOperand& val) { + popValue(val); + adjustFrame(-int32_t(sizeof(Value))); +} + +// =============================================================== +// Simple call functions. + +CodeOffset MacroAssembler::call(Register reg) { + as_jirl(ra, reg, BOffImm16(0)); + return CodeOffset(currentOffset()); +} + +CodeOffset MacroAssembler::call(Label* label) { + ma_bl(label); + return CodeOffset(currentOffset()); +} + +CodeOffset MacroAssembler::callWithPatch() { + as_bl(JOffImm26(1 * sizeof(uint32_t))); + return CodeOffset(currentOffset()); +} + +void MacroAssembler::patchCall(uint32_t callerOffset, uint32_t calleeOffset) { + BufferOffset call(callerOffset - 1 * sizeof(uint32_t)); + + JOffImm26 offset = BufferOffset(calleeOffset).diffB(call); + if (!offset.isInvalid()) { + InstJump* bal = (InstJump*)editSrc(call); + bal->setJOffImm26(offset); + } else { + uint32_t u32Offset = callerOffset - 4 * sizeof(uint32_t); + uint32_t* u32 = + reinterpret_cast(editSrc(BufferOffset(u32Offset))); + *u32 = calleeOffset - callerOffset; + } +} + +CodeOffset MacroAssembler::farJumpWithPatch() { + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + as_pcaddi(scratch, 4); + as_ld_w(scratch2, scratch, 0); + as_add_d(scratch, scratch, scratch2); + as_jirl(zero, scratch, BOffImm16(0)); + // Allocate space which will be patched by patchFarJump(). + CodeOffset farJump(currentOffset()); + spew(".space 32bit initValue 0xffff ffff"); + writeInst(UINT32_MAX); + return farJump; +} + +void MacroAssembler::patchFarJump(CodeOffset farJump, uint32_t targetOffset) { + uint32_t* u32 = + reinterpret_cast(editSrc(BufferOffset(farJump.offset()))); + MOZ_ASSERT(*u32 == UINT32_MAX); + *u32 = targetOffset - farJump.offset(); +} + +void MacroAssembler::repatchFarJump(uint8_t* code, uint32_t farJumpOffset, + uint32_t targetOffset) { + uint32_t* u32 = reinterpret_cast(code + farJumpOffset); + *u32 = targetOffset - farJumpOffset; +} + +CodeOffset MacroAssembler::nopPatchableToNearJump() { + CodeOffset offset(currentOffset()); + as_nop(); + return offset; +} + +void MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target) { + MOZ_ASSERT(reinterpret_cast(jump)->is()); + new (jump) InstJump(op_b, JOffImm26(target - jump)); +} + +void MacroAssembler::patchNearJumpToNop(uint8_t* jump) { + MOZ_ASSERT(reinterpret_cast(jump)->is()); + new (jump) InstNOP(); +} + +void MacroAssembler::call(wasm::SymbolicAddress target) { + movePtr(target, CallReg); + call(CallReg); +} + +void MacroAssembler::call(ImmWord target) { call(ImmPtr((void*)target.value)); } + +void MacroAssembler::call(ImmPtr target) { + BufferOffset bo = m_buffer.nextOffset(); + addPendingJump(bo, target, Relocation::HARDCODED); + ma_call(target); +} + +void MacroAssembler::call(JitCode* c) { + ScratchRegisterScope scratch(asMasm()); + BufferOffset bo = m_buffer.nextOffset(); + addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); + ma_liPatchable(scratch, ImmPtr(c->raw())); + callJitNoProfiler(scratch); +} + +CodeOffsetJump MacroAssemblerLOONGARCH64Compat::backedgeJump( + RepatchLabel* label, Label* documentation) { + return jumpWithPatch(label, documentation); +} + +CodeOffsetJump MacroAssemblerLOONGARCH64Compat::jumpWithPatch( + RepatchLabel* label, Label* documentation) { + (void)documentation; + MOZ_ASSERT(!label->used()); + + BufferOffset bo = nextOffset(); + label->use(bo.getOffset()); + + m_buffer.ensureSpace(4 * sizeof(uint32_t)); + if (label->bound()) { + addLongJump(bo, BufferOffset(label->offset())); + } + ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET)); + as_jirl(zero, ScratchRegister, BOffImm16(0)); + return CodeOffsetJump(bo.getOffset()); +} + +void MacroAssembler::pushReturnAddress() { push(ra); } + +void MacroAssembler::popReturnAddress() { pop(ra); } + +// =============================================================== +// ABI function calls. + +void MacroAssembler::setupUnalignedABICall(Register scratch) { + MOZ_ASSERT(!IsCompilingWasm(), "wasm should only use aligned ABI calls"); + setupABICall(); + dynamicAlignment_ = true; + + as_or(scratch, StackPointer, zero); + + // Force sp to be aligned + asMasm().subPtr(Imm32(sizeof(uintptr_t)), StackPointer); + ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1))); + storePtr(scratch, Address(StackPointer, 0)); +} + +void MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromWasm) { + MOZ_ASSERT(inCall_); + uint32_t stackForCall = abiArgs_.stackBytesConsumedSoFar(); + + // Reserve place for $ra. + stackForCall += sizeof(intptr_t); + + if (dynamicAlignment_) { + stackForCall += ComputeByteAlignment(stackForCall, ABIStackAlignment); + } else { + uint32_t alignmentAtPrologue = callFromWasm ? sizeof(wasm::Frame) : 0; + stackForCall += ComputeByteAlignment( + stackForCall + framePushed() + alignmentAtPrologue, ABIStackAlignment); + } + + *stackAdjust = stackForCall; + reserveStack(stackForCall); + + // Save $ra because call is going to clobber it. Restore it in + // callWithABIPost. NOTE: This is needed for calls from SharedIC. + // Maybe we can do this differently. + storePtr(ra, Address(StackPointer, stackForCall - sizeof(intptr_t))); + + // Position all arguments. + { + enoughMemory_ &= moveResolver_.resolve(); + if (!enoughMemory_) { + return; + } + + MoveEmitter emitter(*this); + emitter.emit(moveResolver_); + emitter.finish(); + } + + assertStackAlignment(ABIStackAlignment); +} + +void MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result) { + // Restore ra value (as stored in callWithABIPre()). + loadPtr(Address(StackPointer, stackAdjust - sizeof(intptr_t)), ra); + + if (dynamicAlignment_) { + // Restore sp value from stack (as stored in setupUnalignedABICall()). + loadPtr(Address(StackPointer, stackAdjust), StackPointer); + // Use adjustFrame instead of freeStack because we already restored sp. + adjustFrame(-stackAdjust); + } else { + freeStack(stackAdjust); + } + +#ifdef DEBUG + MOZ_ASSERT(inCall_); + inCall_ = false; +#endif +} + +void MacroAssembler::callWithABINoProfiler(Register fun, MoveOp::Type result) { + SecondScratchRegisterScope scratch2(asMasm()); + // Load the callee in scratch2, no instruction between the movePtr and + // call should clobber it. Note that we can't use fun because it may be + // one of the IntArg registers clobbered before the call. + movePtr(fun, scratch2); + + uint32_t stackAdjust; + callWithABIPre(&stackAdjust); + call(scratch2); + callWithABIPost(stackAdjust, result); +} + +void MacroAssembler::callWithABINoProfiler(const Address& fun, + MoveOp::Type result) { + SecondScratchRegisterScope scratch2(asMasm()); + // Load the callee in scratch2, as above. + loadPtr(fun, scratch2); + + uint32_t stackAdjust; + callWithABIPre(&stackAdjust); + call(scratch2); + callWithABIPost(stackAdjust, result); +} + +// =============================================================== +// Jit Frames. + +uint32_t MacroAssembler::pushFakeReturnAddress(Register scratch) { + CodeLabel cl; + + ma_li(scratch, &cl); + Push(scratch); + bind(&cl); + uint32_t retAddr = currentOffset(); + + addCodeLabel(cl); + return retAddr; +} + +// =============================================================== +// Move instructions + +void MacroAssemblerLOONGARCH64Compat::moveValue(const Value& src, Register dest) { + if (!src.isGCThing()) { + ma_li(dest, ImmWord(src.asRawBits())); + return; + } + + writeDataRelocation(src); + movWithPatch(ImmWord(src.asRawBits()), dest); +} + +void MacroAssemblerLOONGARCH64Compat::moveValue(const TypedOrValueRegister& src, + const ValueOperand& dest) { + if (src.hasValue()) { + moveValue(src.valueReg(), dest); + return; + } + + MIRType type = src.type(); + AnyRegister reg = src.typedReg(); + + if (!IsFloatingPointType(type)) { + boxNonDouble(ValueTypeFromMIRType(type), reg.gpr(), dest); + return; + } + + ScratchDoubleScope fpscratch(asMasm()); + FloatRegister scratch = fpscratch; + FloatRegister freg = reg.fpu(); + if (type == MIRType::Float32) { + convertFloat32ToDouble(freg, scratch); + freg = scratch; + } + boxDouble(freg, dest, scratch); +} + +void MacroAssemblerLOONGARCH64Compat::moveValue(const ValueOperand& src, + const ValueOperand& dest) { + if (src == dest) { + return; + } + movePtr(src.valueReg(), dest.valueReg()); +} + +void MacroAssemblerLOONGARCH64Compat::moveValue(const Value& src, const ValueOperand& dest) { + moveValue(src, dest.valueReg()); +} + +// =============================================================== +// Branch functions + +void MacroAssembler::branchPtrInNurseryChunk(Condition cond, Register ptr, + Register temp, Label* label) { + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + MOZ_ASSERT(ptr != temp); + MOZ_ASSERT(temp != SecondScratchReg); + + movePtr(ptr, temp); + orPtr(Imm32(gc::ChunkMask), temp); + load32(Address(temp, gc::ChunkLocationOffsetFromLastByte), temp); + branch32(cond, temp, Imm32(int32_t(gc::ChunkLocation::Nursery)), label); +} + +void MacroAssembler::branchValueIsNurseryObject(Condition cond, + const Address& address, + Register temp, Label* label) { + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + + Label done; + branchTestObject(Assembler::NotEqual, address, + cond == Assembler::Equal ? &done : label); + + extractObject(address, temp); + orPtr(Imm32(gc::ChunkMask), temp); + load32(Address(temp, gc::ChunkLocationOffsetFromLastByte), temp); + branch32(cond, temp, Imm32(int32_t(gc::ChunkLocation::Nursery)), label); + + bind(&done); +} + +void MacroAssembler::branchValueIsNurseryObject(Condition cond, + ValueOperand value, + Register temp, Label* label) { + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + + Label done; + branchTestObject(Assembler::NotEqual, value, + cond == Assembler::Equal ? &done : label); + + extractObject(value, temp); + orPtr(Imm32(gc::ChunkMask), temp); + load32(Address(temp, gc::ChunkLocationOffsetFromLastByte), temp); + branch32(cond, temp, Imm32(int32_t(gc::ChunkLocation::Nursery)), label); + + bind(&done); +} + +void MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs, + const Value& rhs, Label* label) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(lhs.valueReg() != scratch); + moveValue(rhs, ValueOperand(scratch)); + ma_b(lhs.valueReg(), scratch, label, cond); +} + +// ======================================================================== +// Memory access primitives. + +template +void MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, + MIRType valueType, const T& dest, + MIRType slotType) { + if (valueType == MIRType::Double) { + storeDouble(value.reg().typedReg().fpu(), dest); + return; + } + + // For known integers and booleans, we can just store the unboxed value if + // the slot has the same type. + if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && + slotType == valueType) { + if (value.constant()) { + Value val = value.value(); + if (valueType == MIRType::Int32) { + store32(Imm32(val.toInt32()), dest); + } else { + store32(Imm32(val.toBoolean() ? 1 : 0), dest); + } + } else { + store32(value.reg().typedReg().gpr(), dest); + } + return; + } + + if (value.constant()) { + storeValue(value.value(), dest); + } else { + storeValue(ValueTypeFromMIRType(valueType), value.reg().typedReg().gpr(), + dest); + } +} + +template void MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, + MIRType valueType, + const Address& dest, + MIRType slotType); +template void MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, + MIRType valueType, + const BaseIndex& dest, + MIRType slotType); +template void MacroAssembler::storeUnboxedValue( + const ConstantOrRegister& value, MIRType valueType, + const BaseObjectElementIndex& dest, MIRType slotType); + +void MacroAssembler::comment(const char* msg) { Assembler::comment(msg); } + +void MacroAssemblerLOONGARCH64Compat::move32(Imm32 imm, Register dest) { + ma_li(dest, imm); +} + +void MacroAssemblerLOONGARCH64Compat::move32(Register src, Register dest) { + as_slli_w(dest, src, 0); +} + +void MacroAssemblerLOONGARCH64Compat::movePtr(Register src, Register dest) { + as_or(dest, src, zero); +} +void MacroAssemblerLOONGARCH64Compat::movePtr(ImmWord imm, Register dest) { + ma_li(dest, imm); +} + +void MacroAssemblerLOONGARCH64Compat::movePtr(ImmGCPtr imm, Register dest) { + ma_li(dest, imm); +} + +void MacroAssemblerLOONGARCH64Compat::movePtr(ImmPtr imm, Register dest) { + movePtr(ImmWord(uintptr_t(imm.value)), dest); +} + +void MacroAssemblerLOONGARCH64Compat::movePtr(wasm::SymbolicAddress imm, + Register dest) { + append(wasm::SymbolicAccess(CodeOffset(nextOffset().getOffset()), imm)); + ma_liPatchable(dest, ImmWord(-1)); +} + +void MacroAssemblerLOONGARCH64Compat::load8ZeroExtend(const Address& address, + Register dest) { + ma_load(dest, address, SizeByte, ZeroExtend); +} + +void MacroAssemblerLOONGARCH64Compat::load8ZeroExtend(const BaseIndex& src, + Register dest) { + ma_load(dest, src, SizeByte, ZeroExtend); +} + +void MacroAssemblerLOONGARCH64Compat::load8SignExtend(const Address& address, + Register dest) { + ma_load(dest, address, SizeByte, SignExtend); +} + +void MacroAssemblerLOONGARCH64Compat::load8SignExtend(const BaseIndex& src, + Register dest) { + ma_load(dest, src, SizeByte, SignExtend); +} + +void MacroAssemblerLOONGARCH64Compat::load16ZeroExtend(const Address& address, + Register dest) { + ma_load(dest, address, SizeHalfWord, ZeroExtend); +} + +void MacroAssemblerLOONGARCH64Compat::load16ZeroExtend(const BaseIndex& src, + Register dest) { + ma_load(dest, src, SizeHalfWord, ZeroExtend); +} + +void MacroAssemblerLOONGARCH64Compat::load16SignExtend(const Address& address, + Register dest) { + ma_load(dest, address, SizeHalfWord, SignExtend); +} + +void MacroAssemblerLOONGARCH64Compat::load16SignExtend(const BaseIndex& src, + Register dest) { + ma_load(dest, src, SizeHalfWord, SignExtend); +} + +void MacroAssemblerLOONGARCH64Compat::load32(const Address& address, + Register dest) { + ma_ld_w(dest, address); +} + +void MacroAssemblerLOONGARCH64Compat::load32(const BaseIndex& address, + Register dest) { + Register base = address.base; + Register index = address.index; + int32_t offset = address.offset; + uint32_t shift = Imm32::ShiftOf(address.scale).value; + + if (offset != 0) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, Imm32(offset)); + if (shift != 0) { + MOZ_ASSERT(shift <= 4); + as_alsl_d(scratch, index, scratch, shift - 1); + } else { + as_add_d(scratch, index, scratch); + } + as_ldx_w(dest, base, scratch); + } else if (shift != 0) { + ScratchRegisterScope scratch(asMasm()); + as_slli_d(scratch, index, shift); + as_ldx_w(dest, base, scratch); + } else { + as_ldx_w(dest, base, index); + } +} + +void MacroAssemblerLOONGARCH64Compat::load32(AbsoluteAddress address, + Register dest) { + ScratchRegisterScope scratch(asMasm()); + movePtr(ImmPtr(address.addr), scratch); + load32(Address(scratch, 0), dest); +} + +void MacroAssemblerLOONGARCH64Compat::load32(wasm::SymbolicAddress address, + Register dest) { + ScratchRegisterScope scratch(asMasm()); + movePtr(address, scratch); + load32(Address(scratch, 0), dest); +} + +void MacroAssemblerLOONGARCH64Compat::loadPtr(const Address& address, + Register dest) { + ma_ld_d(dest, address); +} + +void MacroAssemblerLOONGARCH64Compat::loadPtr(const BaseIndex& src, Register dest) { + Register base = src.base; + Register index = src.index; + int32_t offset = src.offset; + uint32_t shift = Imm32::ShiftOf(src.scale).value; + + if (offset != 0) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, Imm32(offset)); + if (shift != 0) { + MOZ_ASSERT(shift <= 4); + as_alsl_d(scratch, index, scratch, shift - 1); + } else { + as_add_d(scratch, index, scratch); + } + as_ldx_d(dest, base, scratch); + } else if (shift != 0) { + ScratchRegisterScope scratch(asMasm()); + as_slli_d(scratch, index, shift); + as_ldx_d(dest, base, scratch); + } else { + as_ldx_d(dest, base, index); + } +} + +void MacroAssemblerLOONGARCH64Compat::loadPtr(AbsoluteAddress address, + Register dest) { + ScratchRegisterScope scratch(asMasm()); + movePtr(ImmPtr(address.addr), scratch); + loadPtr(Address(scratch, 0), dest); +} + +void MacroAssemblerLOONGARCH64Compat::loadPtr(wasm::SymbolicAddress address, + Register dest) { + ScratchRegisterScope scratch(asMasm()); + movePtr(address, scratch); + loadPtr(Address(scratch, 0), dest); +} + +void MacroAssemblerLOONGARCH64Compat::loadPrivate(const Address& address, + Register dest) { + loadPtr(address, dest); + as_slli_d(dest, dest, 1); +} + +void MacroAssemblerLOONGARCH64Compat::store8(Imm32 imm, const Address& address) { + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch2, imm); + ma_store(scratch2, address, SizeByte); +} + +void MacroAssemblerLOONGARCH64Compat::store8(Register src, const Address& address) { + ma_store(src, address, SizeByte); +} + +void MacroAssemblerLOONGARCH64Compat::store8(Imm32 imm, const BaseIndex& dest) { + ma_store(imm, dest, SizeByte); +} + +void MacroAssemblerLOONGARCH64Compat::store8(Register src, const BaseIndex& dest) { + ma_store(src, dest, SizeByte); +} + +void MacroAssemblerLOONGARCH64Compat::store16(Imm32 imm, const Address& address) { + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch2, imm); + ma_store(scratch2, address, SizeHalfWord); +} + +void MacroAssemblerLOONGARCH64Compat::store16(Register src, + const Address& address) { + ma_store(src, address, SizeHalfWord); +} + +void MacroAssemblerLOONGARCH64Compat::store16(Imm32 imm, const BaseIndex& dest) { + ma_store(imm, dest, SizeHalfWord); +} + +void MacroAssemblerLOONGARCH64Compat::store16(Register src, + const BaseIndex& address) { + ma_store(src, address, SizeHalfWord); +} + +void MacroAssemblerLOONGARCH64Compat::store32(Register src, + AbsoluteAddress address) { + ScratchRegisterScope scratch(asMasm()); + movePtr(ImmPtr(address.addr), scratch); + store32(src, Address(scratch, 0)); +} + +void MacroAssemblerLOONGARCH64Compat::store32(Register src, + const Address& address) { + ma_store(src, address, SizeWord); +} + +void MacroAssemblerLOONGARCH64Compat::store32(Imm32 src, const Address& address) { + SecondScratchRegisterScope scratch2(asMasm()); + move32(src, scratch2); + ma_store(scratch2, address, SizeWord); +} + +void MacroAssemblerLOONGARCH64Compat::store32(Imm32 imm, const BaseIndex& dest) { + ma_store(imm, dest, SizeWord); +} + +void MacroAssemblerLOONGARCH64Compat::store32(Register src, const BaseIndex& dest) { + ma_store(src, dest, SizeWord); +} + +template +void MacroAssemblerLOONGARCH64Compat::storePtr(ImmWord imm, T address) { + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch2, imm); + ma_store(scratch2, address, SizeDouble); +} + +template void MacroAssemblerLOONGARCH64Compat::storePtr
(ImmWord imm, + Address address); +template void MacroAssemblerLOONGARCH64Compat::storePtr( + ImmWord imm, BaseIndex address); + +template +void MacroAssemblerLOONGARCH64Compat::storePtr(ImmPtr imm, T address) { + storePtr(ImmWord(uintptr_t(imm.value)), address); +} + +template void MacroAssemblerLOONGARCH64Compat::storePtr
(ImmPtr imm, + Address address); +template void MacroAssemblerLOONGARCH64Compat::storePtr( + ImmPtr imm, BaseIndex address); + +template +void MacroAssemblerLOONGARCH64Compat::storePtr(ImmGCPtr imm, T address) { + SecondScratchRegisterScope scratch2(asMasm()); + movePtr(imm, scratch2); + storePtr(scratch2, address); +} + +template void MacroAssemblerLOONGARCH64Compat::storePtr
(ImmGCPtr imm, + Address address); +template void MacroAssemblerLOONGARCH64Compat::storePtr( + ImmGCPtr imm, BaseIndex address); + +void MacroAssemblerLOONGARCH64Compat::storePtr(Register src, + const Address& address) { + ma_st_d(src, address); +} + +void MacroAssemblerLOONGARCH64Compat::storePtr(Register src, + const BaseIndex& address) { + Register base = address.base; + Register index = address.index; + int32_t offset = address.offset; + int32_t shift = Imm32::ShiftOf(address.scale).value; + + if ((offset == 0) && (shift == 0)) { + as_stx_d(src, base, index); + } else if (is_intN(offset, 12)) { + ScratchRegisterScope scratch(asMasm()); + if (shift == 0) { + as_add_d(scratch, base, index); + } else { + as_alsl_d(scratch, index, base, shift - 1); + } + as_st_d(src, scratch, offset); + } else { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, Imm32(offset)); + if (shift == 0) { + as_add_d(scratch, scratch, index); + } else { + as_alsl_d(scratch, index, scratch, shift - 1); + } + as_stx_d(src, base, scratch); + } +} + +void MacroAssemblerLOONGARCH64Compat::storePtr(Register src, AbsoluteAddress dest) { + ScratchRegisterScope scratch(asMasm()); + movePtr(ImmPtr(dest.addr), scratch); + storePtr(src, Address(scratch, 0)); +} + +void MacroAssemblerLOONGARCH64Compat::atomicEffectOp( + int nbytes, AtomicOp op, Imm32 value, const Address& address, + Register valueTemp, Register offsetTemp, Register maskTemp) { + AtomicFetchOpLoongArch64(*this, nbytes, false, op, value, address, valueTemp, + offsetTemp, maskTemp, InvalidReg); +} + +void MacroAssemblerLOONGARCH64Compat::atomicEffectOp( + int nbytes, AtomicOp op, Imm32 value, const BaseIndex& address, + Register valueTemp, Register offsetTemp, Register maskTemp) { + AtomicFetchOpLoongArch64(*this, nbytes, false, op, value, address, valueTemp, + offsetTemp, maskTemp, InvalidReg); +} + +void MacroAssemblerLOONGARCH64Compat::atomicEffectOp( + int nbytes, AtomicOp op, Register value, const Address& address, + Register valueTemp, Register offsetTemp, Register maskTemp) { + AtomicFetchOpLoongArch64(*this, nbytes, false, op, value, address, valueTemp, + offsetTemp, maskTemp, InvalidReg); +} + +void MacroAssemblerLOONGARCH64Compat::atomicEffectOp( + int nbytes, AtomicOp op, Register value, const BaseIndex& address, + Register valueTemp, Register offsetTemp, Register maskTemp) { + AtomicFetchOpLoongArch64(*this, nbytes, false, op, value, address, valueTemp, + offsetTemp, maskTemp, InvalidReg); +} + +void MacroAssemblerLOONGARCH64Compat::atomicFetchOp( + int nbytes, bool signExtend, AtomicOp op, Imm32 value, + const Address& address, Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + AtomicFetchOpLoongArch64(*this, nbytes, signExtend, op, value, address, + valueTemp, offsetTemp, maskTemp, output); +} + +void MacroAssemblerLOONGARCH64Compat::atomicFetchOp( + int nbytes, bool signExtend, AtomicOp op, Imm32 value, + const BaseIndex& address, Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + AtomicFetchOpLoongArch64(*this, nbytes, signExtend, op, value, address, + valueTemp, offsetTemp, maskTemp, output); +} + +void MacroAssemblerLOONGARCH64Compat::atomicFetchOp( + int nbytes, bool signExtend, AtomicOp op, Register value, + const Address& address, Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + AtomicFetchOpLoongArch64(*this, nbytes, signExtend, op, value, address, + valueTemp, offsetTemp, maskTemp, output); +} + +void MacroAssemblerLOONGARCH64Compat::atomicFetchOp( + int nbytes, bool signExtend, AtomicOp op, Register value, + const BaseIndex& address, Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + AtomicFetchOpLoongArch64(*this, nbytes, signExtend, op, value, address, + valueTemp, offsetTemp, maskTemp, output); +} + +void MacroAssemblerLOONGARCH64Compat::compareExchange( + int nbytes, bool signExtend, const Address& address, Register oldval, + Register newval, Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + CompareExchangeLoongArch64(*this, nbytes, signExtend, address, oldval, + newval, valueTemp, offsetTemp, maskTemp, output); +} + +void MacroAssemblerLOONGARCH64Compat::compareExchange( + int nbytes, bool signExtend, const BaseIndex& address, Register oldval, + Register newval, Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + CompareExchangeLoongArch64(*this, nbytes, signExtend, address, oldval, + newval, valueTemp, offsetTemp, maskTemp, output); +} + +void MacroAssemblerLOONGARCH64Compat::compareExchangeToTypedIntArray( + Scalar::Type arrayType, const Address& mem, Register oldval, + Register newval, Register temp, Register valueTemp, Register offsetTemp, + Register maskTemp, AnyRegister output) { + switch (arrayType) { + case Scalar::Int8: + compareExchange(1, true, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint8: + compareExchange(1, false, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Int16: + compareExchange(2, true, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint16: + compareExchange(2, false, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Int32: + compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint32: + MOZ_ASSERT(output.isFloat()); + MOZ_ASSERT(temp != InvalidReg); + compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, temp); + convertUInt32ToDouble(temp, output.fpu()); + break; + default: + MOZ_CRASH("Invalid typed array type"); + } +} + +void MacroAssemblerLOONGARCH64Compat::compareExchangeToTypedIntArray( + Scalar::Type arrayType, const BaseIndex& mem, Register oldval, + Register newval, Register temp, Register valueTemp, Register offsetTemp, + Register maskTemp, AnyRegister output) { + switch (arrayType) { + case Scalar::Int8: + compareExchange(1, true, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint8: + compareExchange(1, false, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Int16: + compareExchange(2, true, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint16: + compareExchange(2, false, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Int32: + compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, output.gpr()); + break; + case Scalar::Uint32: + MOZ_ASSERT(output.isFloat()); + MOZ_ASSERT(temp != InvalidReg); + compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp, + maskTemp, temp); + convertUInt32ToDouble(temp, output.fpu()); + break; + default: + MOZ_CRASH("Invalid typed array type"); + } +} + +void MacroAssemblerLOONGARCH64Compat::atomicExchange( + int nbytes, bool signExtend, const Address& address, Register value, + Register valueTemp, Register offsetTemp, Register maskTemp, + Register output) { + CompareExchangeLoongArch64(*this, nbytes, signExtend, address, InvalidReg, + value, valueTemp, offsetTemp, maskTemp, output); +} + +void MacroAssemblerLOONGARCH64Compat::atomicExchange( + int nbytes, bool signExtend, const BaseIndex& address, Register value, + Register valueTemp, Register offsetTemp, Register maskTemp, + Register output) { + CompareExchangeLoongArch64(*this, nbytes, signExtend, address, InvalidReg, + value, valueTemp, offsetTemp, maskTemp, output); +} + +void MacroAssemblerLOONGARCH64Compat::atomicExchangeToTypedIntArray( + Scalar::Type arrayType, const Address& mem, Register value, Register temp, + Register valueTemp, Register offsetTemp, Register maskTemp, + AnyRegister output) { + switch (arrayType) { + case Scalar::Int8: + atomicExchange(1, true, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Uint8: + atomicExchange(1, false, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Int16: + atomicExchange(2, true, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Uint16: + atomicExchange(2, false, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Int32: + atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Uint32: + MOZ_ASSERT(output.isFloat()); + MOZ_ASSERT(temp != InvalidReg); + atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp, + temp); + convertUInt32ToDouble(temp, output.fpu()); + break; + default: + MOZ_CRASH("Invalid typed array type"); + } +} + +void MacroAssemblerLOONGARCH64Compat::atomicExchangeToTypedIntArray( + Scalar::Type arrayType, const BaseIndex& mem, Register value, + Register temp, Register valueTemp, Register offsetTemp, + Register maskTemp, AnyRegister output) { + switch (arrayType) { + case Scalar::Int8: + atomicExchange(1, true, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Uint8: + atomicExchange(1, false, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Int16: + atomicExchange(2, true, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Uint16: + atomicExchange(2, false, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Int32: + atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp, + output.gpr()); + break; + case Scalar::Uint32: + MOZ_ASSERT(output.isFloat()); + MOZ_ASSERT(temp != InvalidReg); + atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp, + temp); + convertUInt32ToDouble(temp, output.fpu()); + break; + default: + MOZ_CRASH("Invalid typed array type"); + } +} + +void MacroAssemblerLOONGARCH64Compat::testNullSet(Condition cond, + const ValueOperand& value, + Register dest) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + SecondScratchRegisterScope scratch2(asMasm()); + splitTag(value, scratch2); + ma_cmp_set(dest, scratch2, ImmTag(JSVAL_TAG_NULL), cond); +} + +void MacroAssemblerLOONGARCH64Compat::testObjectSet(Condition cond, + const ValueOperand& value, + Register dest) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + SecondScratchRegisterScope scratch2(asMasm()); + splitTag(value, scratch2); + ma_cmp_set(dest, scratch2, ImmTag(JSVAL_TAG_OBJECT), cond); +} + +void MacroAssemblerLOONGARCH64Compat::testUndefinedSet(Condition cond, + const ValueOperand& value, + Register dest) { + MOZ_ASSERT(cond == Equal || cond == NotEqual); + SecondScratchRegisterScope scratch2(asMasm()); + splitTag(value, scratch2); + ma_cmp_set(dest, scratch2, ImmTag(JSVAL_TAG_UNDEFINED), cond); +} + +void MacroAssemblerLOONGARCH64Compat::unboxInt32(const ValueOperand& operand, + Register dest) { + as_slli_w(dest, operand.valueReg(), 0); +} + +void MacroAssemblerLOONGARCH64Compat::unboxInt32(Register src, Register dest) { + as_slli_w(dest, src, 0); +} + +void MacroAssemblerLOONGARCH64Compat::unboxInt32(const Address& src, + Register dest) { + load32(Address(src.base, src.offset), dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxInt32(const BaseIndex& src, + Register dest) { + SecondScratchRegisterScope scratch2(asMasm()); + computeScaledAddress(src, scratch2); + load32(Address(scratch2, src.offset), dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxBoolean(const ValueOperand& operand, + Register dest) { + as_slli_w(dest, operand.valueReg(), 0); +} + +void MacroAssemblerLOONGARCH64Compat::unboxBoolean(Register src, Register dest) { + as_slli_w(dest, src, 0); +} + +void MacroAssemblerLOONGARCH64Compat::unboxBoolean(const Address& src, + Register dest) { + ma_ld_w(dest, src); +} + +void MacroAssemblerLOONGARCH64Compat::unboxBoolean(const BaseIndex& src, + Register dest) { + SecondScratchRegisterScope scratch2(asMasm()); + computeScaledAddress(src, scratch2); + ma_ld_w(dest, Address(scratch2, src.offset)); +} + +void MacroAssemblerLOONGARCH64Compat::unboxDouble(const ValueOperand& operand, + FloatRegister dest) { + as_movgr2fr_d(dest, operand.valueReg()); +} + +void MacroAssemblerLOONGARCH64Compat::unboxDouble(const Address& src, + FloatRegister dest) { + ma_fld_d(dest, Address(src.base, src.offset)); +} + +void MacroAssemblerLOONGARCH64Compat::unboxDouble(const BaseIndex& src, + FloatRegister dest) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(src, scratch2); + unboxDouble(ValueOperand(scratch2), dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxString(const ValueOperand& operand, + Register dest) { + unboxNonDouble(operand, dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxString(Register src, Register dest) { + as_bstrpick_d(dest, src, JSVAL_TAG_SHIFT - 1, 0); +} + +void MacroAssemblerLOONGARCH64Compat::unboxString(const Address& src, + Register dest) { + unboxNonDouble(src, dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxSymbol(const ValueOperand& operand, + Register dest) { + unboxNonDouble(operand, dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxSymbol(Register src, Register dest) { + as_bstrpick_d(dest, src, JSVAL_TAG_SHIFT - 1, 0); +} + +void MacroAssemblerLOONGARCH64Compat::unboxSymbol(const Address& src, + Register dest) { + unboxNonDouble(src, dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxBigInt(const ValueOperand& operand, + Register dest) { + unboxNonDouble(operand, dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxBigInt(Register src, Register dest) { + as_bstrpick_d(dest, src, JSVAL_TAG_SHIFT - 1, 0); +} + +void MacroAssemblerLOONGARCH64Compat::unboxBigInt(const Address& src, + Register dest) { + unboxNonDouble(src, dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxObject(const ValueOperand& src, + Register dest) { + unboxNonDouble(src, dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxObject(Register src, Register dest) { + as_bstrpick_d(dest, src, JSVAL_TAG_SHIFT - 1, 0); +} + +void MacroAssemblerLOONGARCH64Compat::unboxObject(const Address& src, + Register dest) { + unboxNonDouble(src, dest); +} + +void MacroAssemblerLOONGARCH64Compat::unboxNonDouble(const ValueOperand& operand, + Register dest) { + Label isInt32, done; + SecondScratchRegisterScope scratch2(asMasm()); + splitTag(operand, scratch2); + asMasm().branchTestInt32(Assembler::Equal, scratch2, &isInt32); + + as_bstrpick_d(dest, operand.valueReg(), JSVAL_TAG_SHIFT - 1, 0); + jump(&done); + + bind(&isInt32); + as_slli_w(dest, operand.valueReg(), 0); + + bind(&done); +} + +void MacroAssemblerLOONGARCH64Compat::unboxNonDouble(const Address& src, + Register dest) { + Label isInt32, done; + loadPtr(src, dest); + SecondScratchRegisterScope scratch2(asMasm()); + splitTag(dest, scratch2); + asMasm().branchTestInt32(Assembler::Equal, scratch2, &isInt32); + + as_bstrpick_d(dest, dest, JSVAL_TAG_SHIFT - 1, 0); + jump(&done); + + bind(&isInt32); + as_slli_w(dest, dest, 0); + + bind(&done); +} + +void MacroAssemblerLOONGARCH64Compat::unboxNonDouble(const BaseIndex& src, + Register dest) { + Label isInt32, done; + computeScaledAddress(src, SecondScratchReg); + loadPtr(Address(SecondScratchReg, src.offset), dest); + splitTag(dest, SecondScratchReg); + asMasm().branchTestInt32(Assembler::Equal, SecondScratchReg, &isInt32); + + as_bstrpick_d(dest, dest, JSVAL_TAG_SHIFT - 1, 0); + jump(&done); + + bind(&isInt32); + as_slli_w(dest, dest, 0); + + bind(&done); +} + +void MacroAssemblerLOONGARCH64Compat::unboxValue(const ValueOperand& src, + AnyRegister dest) { + if (dest.isFloat()) { + Label notInt32, end; + asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); + convertInt32ToDouble(src.valueReg(), dest.fpu()); + ma_b(&end, ShortJump); + bind(¬Int32); + unboxDouble(src, dest.fpu()); + bind(&end); + } else { + unboxNonDouble(src, dest.gpr()); + } +} + +void MacroAssemblerLOONGARCH64Compat::boxDouble(FloatRegister src, + const ValueOperand& dest, + FloatRegister) { + as_movfr2gr_d(dest.valueReg(), src); +} + +void MacroAssemblerLOONGARCH64Compat::boxNonDouble(JSValueType type, Register src, + const ValueOperand& dest) { + boxValue(type, src, dest.valueReg()); +} + +void MacroAssemblerLOONGARCH64Compat::boolValueToDouble(const ValueOperand& operand, + FloatRegister dest) { + ScratchRegisterScope scratch(asMasm()); + convertBoolToInt32(operand.valueReg(), scratch); + convertInt32ToDouble(scratch, dest); +} + +void MacroAssemblerLOONGARCH64Compat::int32ValueToDouble( + const ValueOperand& operand, FloatRegister dest) { + convertInt32ToDouble(operand.valueReg(), dest); +} + +void MacroAssemblerLOONGARCH64Compat::boolValueToFloat32( + const ValueOperand& operand, FloatRegister dest) { + ScratchRegisterScope scratch(asMasm()); + convertBoolToInt32(operand.valueReg(), scratch); + convertInt32ToFloat32(scratch, dest); +} + +void MacroAssemblerLOONGARCH64Compat::int32ValueToFloat32( + const ValueOperand& operand, FloatRegister dest) { + convertInt32ToFloat32(operand.valueReg(), dest); +} + +void MacroAssemblerLOONGARCH64Compat::loadConstantFloat32(float f, + FloatRegister dest) { + ma_lis(dest, f); +} + +void MacroAssemblerLOONGARCH64Compat::loadInt32OrDouble(const Address& src, + FloatRegister dest) { + SecondScratchRegisterScope scratch2(asMasm()); + Label end; + + // If it's an int, convert it to double. + loadPtr(Address(src.base, src.offset), scratch2); + as_movgr2fr_d(dest, scratch2); + as_srli_d(scratch2, scratch2, JSVAL_TAG_SHIFT); + asMasm().branchTestInt32(Assembler::NotEqual, scratch2, &end); + as_ffint_d_w(dest, dest); + + bind(&end); +} + +void MacroAssemblerLOONGARCH64Compat::loadInt32OrDouble(const BaseIndex& addr, + FloatRegister dest) { + SecondScratchRegisterScope scratch2(asMasm()); + Label end; + + // If it's an int, convert it to double. + computeScaledAddress(addr, scratch2); + // Since we only have one scratch, we need to stomp over it with the tag. + loadPtr(Address(scratch2, 0), scratch2); + as_movgr2fr_d(dest, scratch2); + as_srli_d(scratch2, scratch2, JSVAL_TAG_SHIFT); + asMasm().branchTestInt32(Assembler::NotEqual, scratch2, &end); + as_ffint_d_w(dest, dest); + + bind(&end); +} + +void MacroAssemblerLOONGARCH64Compat::loadConstantDouble(double dp, + FloatRegister dest) { + ma_lid(dest, dp); +} + +Register MacroAssemblerLOONGARCH64Compat::extractObject(const Address& address, + Register scratch) { + loadPtr(Address(address.base, address.offset), scratch); + as_bstrpick_d(scratch, scratch, JSVAL_TAG_SHIFT - 1, 0); + return scratch; +} + +Register MacroAssemblerLOONGARCH64Compat::extractTag(const Address& address, + Register scratch) { + loadPtr(Address(address.base, address.offset), scratch); + as_bstrpick_d(scratch, scratch, 63, JSVAL_TAG_SHIFT); + return scratch; +} + +Register MacroAssemblerLOONGARCH64Compat::extractTag(const BaseIndex& address, + Register scratch) { + computeScaledAddress(address, scratch); + return extractTag(Address(scratch, address.offset), scratch); +} + +///////////////////////////////////////////////////////////////// +// X86/X64-common/ARM/LoongArch interface. +///////////////////////////////////////////////////////////////// +void MacroAssemblerLOONGARCH64Compat::storeValue(ValueOperand val, + const Address& dest) { + storePtr(val.valueReg(), Address(dest.base, dest.offset)); +} + +void MacroAssemblerLOONGARCH64Compat::storeValue(ValueOperand val, + const BaseIndex& dest) { + storePtr(val.valueReg(), dest); +} + +void MacroAssemblerLOONGARCH64Compat::storeValue(JSValueType type, Register reg, + Address dest) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(dest.base != scratch2); + + tagValue(type, reg, ValueOperand(scratch2)); + storePtr(scratch2, dest); +} + +void MacroAssemblerLOONGARCH64Compat::storeValue(JSValueType type, Register reg, + BaseIndex dest) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(dest.base != scratch2); + + tagValue(type, reg, ValueOperand(scratch2)); + storePtr(scratch2, dest); +} + +void MacroAssemblerLOONGARCH64Compat::storeValue(const Value& val, Address dest) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(dest.base != scratch2); + + if (val.isGCThing()) { + writeDataRelocation(val); + movWithPatch(ImmWord(val.asRawBits()), scratch2); + } else { + ma_li(scratch2, ImmWord(val.asRawBits())); + } + storePtr(scratch2, dest); +} + +void MacroAssemblerLOONGARCH64Compat::storeValue(const Value& val, BaseIndex dest) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(dest.base != scratch2); + + if (val.isGCThing()) { + writeDataRelocation(val); + movWithPatch(ImmWord(val.asRawBits()), scratch2); + } else { + ma_li(scratch2, ImmWord(val.asRawBits())); + } + storePtr(scratch2, dest); +} + +void MacroAssemblerLOONGARCH64Compat::loadValue(Address src, ValueOperand val) { + loadPtr(src, val.valueReg()); +} + +void MacroAssemblerLOONGARCH64Compat::loadValue(const BaseIndex& src, + ValueOperand val) { + loadPtr(src, val.valueReg()); +} + +void MacroAssemblerLOONGARCH64Compat::tagValue(JSValueType type, Register payload, + ValueOperand dest) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(dest.valueReg() != scratch); + + if (payload == dest.valueReg()) { + as_or(scratch, payload, zero); + payload = scratch; + } + ma_li(dest.valueReg(), Imm32(int32_t(JSVAL_TYPE_TO_TAG(type)))); + as_slli_d(dest.valueReg(), dest.valueReg(), JSVAL_TAG_SHIFT); + if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { + as_bstrins_d(dest.valueReg(), payload, 31, 0); + } else { + as_bstrins_d(dest.valueReg(), payload, JSVAL_TAG_SHIFT - 1, 0); + } +} + +void MacroAssemblerLOONGARCH64Compat::pushValue(ValueOperand val) { + push(val.valueReg()); +} + +void MacroAssemblerLOONGARCH64Compat::pushValue(const Address& addr) { push(addr); } + +void MacroAssemblerLOONGARCH64Compat::popValue(ValueOperand val) { + pop(val.valueReg()); +} + +void MacroAssemblerLOONGARCH64Compat::breakpoint(uint32_t value) { + as_break(value); +} + +void MacroAssemblerLOONGARCH64Compat::handleFailureWithHandlerTail(void* handler) { + // Reserve space for exception information. + int size = (sizeof(ResumeFromException) + ABIStackAlignment) & + ~(ABIStackAlignment - 1); + asMasm().subPtr(Imm32(size), StackPointer); + mov(StackPointer, a0); // Use a0 since it is the first function argument. + + // Call the handler. + asMasm().setupUnalignedABICall(a1); + asMasm().passABIArg(a0); + asMasm().callWithABI(handler); + + Label entryFrame; + Label catch_; + Label finally; + Label return_; + Label bailout; + + // Already clobbered a0, so use it... + load32(Address(StackPointer, offsetof(ResumeFromException, kind)), a0); + asMasm().branch32(Assembler::Equal, a0, + Imm32(ResumeFromException::RESUME_ENTRY_FRAME), + &entryFrame); + asMasm().branch32(Assembler::Equal, a0, + Imm32(ResumeFromException::RESUME_CATCH), &catch_); + asMasm().branch32(Assembler::Equal, a0, + Imm32(ResumeFromException::RESUME_FINALLY), &finally); + asMasm().branch32(Assembler::Equal, a0, + Imm32(ResumeFromException::RESUME_FORCED_RETURN), + &return_); + asMasm().branch32(Assembler::Equal, a0, + Imm32(ResumeFromException::RESUME_BAILOUT), &bailout); + + breakpoint(); // Invalid kind. + + // No exception handler. Load the error value, load the new stack pointer + // and return from the entry frame. + bind(&entryFrame); + asMasm().moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand); + loadPtr(Address(StackPointer, offsetof(ResumeFromException, stackPointer)), + StackPointer); + ret(); + + // If we found a catch handler, this must be a baseline frame. Restore + // state and jump to the catch block. + bind(&catch_); + loadPtr(Address(StackPointer, offsetof(ResumeFromException, target)), a0); + loadPtr(Address(StackPointer, offsetof(ResumeFromException, framePointer)), + BaselineFrameReg); + loadPtr(Address(StackPointer, offsetof(ResumeFromException, stackPointer)), + StackPointer); + jump(a0); + + // If we found a finally block, this must be a baseline frame. Push + // two values expected by JSOP_RETSUB: BooleanValue(true) and the + // exception. + bind(&finally); + ValueOperand exception = ValueOperand(a1); + loadValue(Address(sp, offsetof(ResumeFromException, exception)), exception); + + loadPtr(Address(sp, offsetof(ResumeFromException, target)), a0); + loadPtr(Address(sp, offsetof(ResumeFromException, framePointer)), + BaselineFrameReg); + loadPtr(Address(sp, offsetof(ResumeFromException, stackPointer)), sp); + + pushValue(BooleanValue(true)); + pushValue(exception); + jump(a0); + + // Only used in debug mode. Return BaselineFrame->returnValue() to the + // caller. + bind(&return_); + loadPtr(Address(StackPointer, offsetof(ResumeFromException, framePointer)), + BaselineFrameReg); + loadPtr(Address(StackPointer, offsetof(ResumeFromException, stackPointer)), + StackPointer); + loadValue( + Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue()), + JSReturnOperand); + movePtr(BaselineFrameReg, StackPointer); + pop(BaselineFrameReg); + + // If profiling is enabled, then update the lastProfilingFrame to refer to + // caller frame before returning. + { + Label skipProfilingInstrumentation; + AbsoluteAddress addressOfEnabled( + GetJitContext()->runtime->spsProfiler().addressOfEnabled()); + asMasm().branch32(Assembler::Equal, addressOfEnabled, Imm32(0), + &skipProfilingInstrumentation); + profilerExitFrame(); + bind(&skipProfilingInstrumentation); + } + + ret(); + + // If we are bailing out to baseline to handle an exception, jump to + // the bailout tail stub. + bind(&bailout); + loadPtr(Address(sp, offsetof(ResumeFromException, bailoutInfo)), a2); + ma_li(ReturnReg, Imm32(BAILOUT_RETURN_OK)); + loadPtr(Address(sp, offsetof(ResumeFromException, target)), a1); + jump(a1); +} + +CodeOffset MacroAssemblerLOONGARCH64Compat::toggledJump(Label* label) { + CodeOffset ret(nextOffset().getOffset()); + ma_b(label); + return ret; +} + +CodeOffset MacroAssemblerLOONGARCH64Compat::toggledCall(JitCode* target, + bool enabled) { + ScratchRegisterScope scratch(asMasm()); + BufferOffset bo = nextOffset(); + CodeOffset offset(bo.getOffset()); // first instruction location,not changed. + addPendingJump(bo, ImmPtr(target->raw()), Relocation::JITCODE); + ma_liPatchable(scratch, ImmPtr(target->raw())); + if (enabled) { + as_jirl(ra, scratch, BOffImm16(0)); + } else { + as_nop(); + } + MOZ_ASSERT_IF(!oom(), nextOffset().getOffset() - offset.offset() == + ToggledCallSize(nullptr)); + return offset; // location of first instruction of call instr sequence. +} + +//}}} check_macroassembler_style + +} // namespace jit +} // namespace js diff --git a/js/src/jit/loongarch64/MacroAssembler-loongarch64.h b/js/src/jit/loongarch64/MacroAssembler-loongarch64.h new file mode 100644 index 0000000000..a3b89fe3af --- /dev/null +++ b/js/src/jit/loongarch64/MacroAssembler-loongarch64.h @@ -0,0 +1,1809 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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/. */ + +#ifndef jit_loongarch64_MacroAssembler_loongarch64_h +#define jit_loongarch64_MacroAssembler_loongarch64_h + +#include "jit/loongarch64/Assembler-loongarch64.h" +#include "jit/MoveResolver.h" +#include "wasm/WasmTypes.h" + +namespace js { +namespace jit { + +enum LoadStoreSize { + SizeByte = 8, + SizeHalfWord = 16, + SizeWord = 32, + SizeDouble = 64 +}; + +enum LoadStoreExtension { ZeroExtend = 0, SignExtend = 1 }; + +enum JumpKind { LongJump = 0, ShortJump = 1 }; + +static Register CallReg = t8; + +enum LiFlags { + Li64 = 0, + Li48 = 1, +}; + +struct ImmShiftedTag : public ImmWord { + explicit ImmShiftedTag(JSValueShiftedTag shtag) : ImmWord((uintptr_t)shtag) {} + + explicit ImmShiftedTag(JSValueType type) + : ImmWord(uintptr_t(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type)))) { + } +}; + +struct ImmTag : public Imm32 { + ImmTag(JSValueTag mask) : Imm32(int32_t(mask)) {} +}; + +static const int defaultShift = 3; +static_assert(1 << defaultShift == sizeof(JS::Value), + "The defaultShift is wrong"); + +// See documentation for ScratchTagScope and ScratchTagScopeRelease in +// MacroAssembler-x64.h. + +class ScratchTagScope : public SecondScratchRegisterScope { + public: + ScratchTagScope(MacroAssembler& masm, const ValueOperand&) + : SecondScratchRegisterScope(masm) {} + + void release() {} + void reacquire() {} +}; + +class ScratchTagScopeRelease { + ScratchTagScope* ts_; + + public: + explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) { + ts_->release(); + } + ~ScratchTagScopeRelease() { ts_->reacquire(); } +}; + +class MacroAssemblerLOONGARCH64 : public Assembler { + protected: + // Perform a downcast. Should be removed by Bug 996602. + MacroAssembler& asMasm(); + const MacroAssembler& asMasm() const; + + Condition ma_cmp(Register rd, Register lhs, Register rhs, Condition c); + Condition ma_cmp(Register rd, Register lhs, Imm32 imm, Condition c); + + void compareFloatingPoint(FloatFormat fmt, FloatRegister lhs, + FloatRegister rhs, DoubleCondition c, + FPConditionBit fcc = FCC0); + + public: + void ma_li(Register dest, CodeOffset* label); + void ma_li(Register dest, CodeLabel* label) { ma_li(dest, label->patchAt()); } + void ma_li(Register dest, ImmWord imm); + void ma_liPatchable(Register dest, ImmPtr imm); + void ma_liPatchable(Register dest, ImmWord imm, LiFlags flags = Li48); + + // load + void ma_ld_b(Register dest, Address address); + void ma_ld_h(Register dest, Address address); + void ma_ld_w(Register dest, Address address); + void ma_ld_d(Register dest, Address address); + void ma_ld_bu(Register dest, Address address); + void ma_ld_hu(Register dest, Address address); + void ma_ld_wu(Register dest, Address address); + void ma_load(Register dest, Address address, LoadStoreSize size = SizeWord, + LoadStoreExtension extension = SignExtend); + + // store + void ma_st_b(Register src, Address address); + void ma_st_h(Register src, Address address); + void ma_st_w(Register src, Address address); + void ma_st_d(Register src, Address address); + void ma_store(Register data, Address address, LoadStoreSize size = SizeWord, + LoadStoreExtension extension = SignExtend); + + // arithmetic based ops + // add + void ma_add_d(Register rd, Register rj, Imm32 imm); + void ma_add32TestOverflow(Register rd, Register rj, Register rk, + Label* overflow); + void ma_add32TestOverflow(Register rd, Register rj, Imm32 imm, + Label* overflow); + template + void ma_add32TestOverflow(Register rd, Register rj, Register rk, + L overflow) { + ScratchRegisterScope scratch(asMasm()); + as_add_d(scratch, rj, rk); + as_add_w(rd, rj, rk); + ma_b(rd, Register(scratch), overflow, Assembler::NotEqual); + } + template + void ma_add32TestOverflow(Register rd, Register rj, Imm32 imm, L overflow) { + if (is_intN(imm.value, 12)) { + ScratchRegisterScope scratch(asMasm()); + as_addi_d(scratch, rj, imm.value); + as_addi_w(rd, rj, imm.value); + ma_b(rd, scratch, overflow, Assembler::NotEqual); + } else { + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch2, imm); + ma_add32TestOverflow(rd, rj, scratch2, overflow); + } + } + void ma_addPtrTestOverflow(Register rd, Register rj, Register rk, + Label* overflow); + void ma_addPtrTestOverflow(Register rd, Register rj, Imm32 imm, + Label* overflow); + void ma_addPtrTestOverflow(Register rd, Register rj, ImmWord imm, + Label* overflow); + void ma_addPtrTestCarry(Condition cond, Register rd, Register rj, Register rk, + Label* overflow); + void ma_addPtrTestCarry(Condition cond, Register rd, Register rj, Imm32 imm, + Label* overflow); + void ma_addPtrTestCarry(Condition cond, Register rd, Register rj, ImmWord imm, + Label* overflow); + + // subtract + void ma_sub_d(Register rd, Register rj, Imm32 imm); + void ma_sub32TestOverflow(Register rd, Register rj, Register rk, + Label* overflow); + void ma_subPtrTestOverflow(Register rd, Register rj, Register rk, + Label* overflow); + void ma_subPtrTestOverflow(Register rd, Register rj, Imm32 imm, + Label* overflow); + + // multiplies. For now, there are only few that we care about. + void ma_mul_d(Register rd, Register rj, Imm32 imm); + void ma_mulh_d(Register rd, Register rj, Imm32 imm); + void ma_mulPtrTestOverflow(Register rd, Register rj, Register rk, + Label* overflow); + + // stack + void ma_pop(Register r); + void ma_push(Register r); + + void branchWithCode(InstImm code, Label* label, JumpKind jumpKind); + // branches when done from within la-specific code + void ma_b(Register lhs, ImmWord imm, Label* l, Condition c, + JumpKind jumpKind = LongJump); + void ma_b(Register lhs, Address addr, Label* l, Condition c, + JumpKind jumpKind = LongJump); + void ma_b(Address addr, Imm32 imm, Label* l, Condition c, + JumpKind jumpKind = LongJump); + void ma_b(Address addr, ImmGCPtr imm, Label* l, Condition c, + JumpKind jumpKind = LongJump); + void ma_b(Address addr, Register rhs, Label* l, Condition c, + JumpKind jumpKind = LongJump) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(rhs != scratch); + ma_ld_d(scratch, addr); + ma_b(scratch, rhs, l, c, jumpKind); + } + + void ma_bl(Label* l); + + // fp instructions + void ma_lid(FloatRegister dest, double value); + + void ma_mv(FloatRegister src, ValueOperand dest); + void ma_mv(ValueOperand src, FloatRegister dest); + + void ma_fld_s(FloatRegister ft, Address address); + void ma_fld_d(FloatRegister ft, Address address); + void ma_fst_d(FloatRegister ft, Address address); + void ma_fst_s(FloatRegister ft, Address address); + + void ma_pop(FloatRegister f); + void ma_push(FloatRegister f); + + void ma_cmp_set(Register dst, Register lhs, ImmWord imm, Condition c); + void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c); + void ma_cmp_set(Register dst, Address address, Imm32 imm, Condition c); + void ma_cmp_set(Register dst, Address address, ImmWord imm, Condition c); + + void moveIfZero(Register dst, Register src, Register cond) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(dst != scratch && cond != scratch); + as_masknez(scratch, src, cond); + as_maskeqz(dst, dst, cond); + as_or(dst, dst, scratch); + } + void moveIfNotZero(Register dst, Register src, Register cond) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(dst != scratch && cond != scratch); + as_maskeqz(scratch, src, cond); + as_masknez(dst, dst, cond); + as_or(dst, dst, scratch); + } + + // These functions abstract the access to high part of the double precision + // float register. They are intended to work on both 32 bit and 64 bit + // floating point coprocessor. + void moveToDoubleHi(Register src, FloatRegister dest) { + as_movgr2frh_w(dest, src); + } + void moveFromDoubleHi(FloatRegister src, Register dest) { + as_movfrh2gr_s(dest, src); + } + + void moveToDouble(Register src, FloatRegister dest) { + as_movgr2fr_d(dest, src); + } + void moveFromDouble(FloatRegister src, Register dest) { + as_movfr2gr_d(dest, src); + } + + public: + void ma_li(Register dest, ImmGCPtr ptr); + + void ma_li(Register dest, Imm32 imm); + void ma_liPatchable(Register dest, Imm32 imm); + + void ma_rotr_w(Register rd, Register rj, Imm32 shift); + + void ma_fmovz(FloatFormat fmt, FloatRegister fd, FloatRegister fj, + Register rk); + void ma_fmovn(FloatFormat fmt, FloatRegister fd, FloatRegister fj, + Register rk); + + void ma_and(Register rd, Register rj, Imm32 imm, bool bit32 = false); + + void ma_or(Register rd, Register rj, Imm32 imm, bool bit32 = false); + + void ma_xor(Register rd, Register rj, Imm32 imm, bool bit32 = false); + + // load + void ma_load(Register dest, const BaseIndex& src, + LoadStoreSize size = SizeWord, + LoadStoreExtension extension = SignExtend); + + // store + void ma_store(Register data, const BaseIndex& dest, + LoadStoreSize size = SizeWord, + LoadStoreExtension extension = SignExtend); + void ma_store(Imm32 imm, const BaseIndex& dest, LoadStoreSize size = SizeWord, + LoadStoreExtension extension = SignExtend); + + // arithmetic based ops + // add + void ma_add_w(Register rd, Register rj, Imm32 imm); + void ma_add32TestCarry(Condition cond, Register rd, Register rj, Register rk, + Label* overflow); + void ma_add32TestCarry(Condition cond, Register rd, Register rj, Imm32 imm, + Label* overflow); + template + void ma_add32TestCarry(Condition cond, Register rd, Register rj, Register rk, + L overflow) { + MOZ_ASSERT(cond == Assembler::CarrySet || cond == Assembler::CarryClear); + MOZ_ASSERT_IF(rd == rj, rk != rd); + ScratchRegisterScope scratch(asMasm()); + as_add_w(rd, rj, rk); + as_sltu(scratch, rd, rd == rj ? rk : rj); + ma_b(Register(scratch), Register(scratch), overflow, + cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero); + } + template + void ma_add32TestCarry(Condition cond, Register rd, Register rj, Imm32 imm, + L overflow) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(rj != scratch2); + ma_li(scratch2, imm); + ma_add32TestCarry(cond, rd, rj, scratch2, overflow); + } + template + void ma_addTestCarry(Register rd, Register rs, Register rt, L overflow) { + MOZ_ASSERT_IF(rd == rs, rt != rd); + SecondScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(scratch != rs); + MOZ_ASSERT(scratch != rt); + as_add_d(rd, rs, rt); + as_sltu(scratch, rd, rd == rs ? rt : rs); + ma_b(Register(scratch), Register(scratch), overflow, Assembler::NonZero); + } + template + void ma_addTestCarry(Register rd, Register rs, Imm32 imm, L overflow) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(scratch != rs); + ma_li(scratch, imm); + ma_addTestCarry(rd, rs, Register(scratch), overflow); + } + + // subtract + void ma_sub_w(Register rd, Register rj, Imm32 imm); + void ma_sub_w(Register rd, Register rj, Register rk); + void ma_sub32TestOverflow(Register rd, Register rj, Imm32 imm, + Label* overflow); + + // multiplies. For now, there are only few that we care about. + void ma_mul(Register rd, Register rj, Imm32 imm); + void ma_mul_branch_overflow(Register rd, Register rj, Register rk, + Label* overflow) { + ma_mul32TestOverflow(rd, rj, rk, overflow); + } + void ma_mul_branch_overflow(Register rd, Register rj, Imm32 imm, + Label* overflow) { + ma_mul32TestOverflow(rd, rj, imm, overflow); + } + void ma_mul32TestOverflow(Register rd, Register rj, Register rk, + Label* overflow); + void ma_mul32TestOverflow(Register rd, Register rj, Imm32 imm, + Label* overflow); + + // divisions + void ma_div_branch_overflow(Register rd, Register rj, Register rk, + Label* overflow); + void ma_div_branch_overflow(Register rd, Register rj, Imm32 imm, + Label* overflow); + + // fast mod, uses scratch registers, and thus needs to be in the assembler + // implicitly assumes that we can overwrite dest at the beginning of the + // sequence + void ma_mod_mask(Register src, Register dest, Register hold, Register remain, + int32_t shift, Label* negZero = nullptr); + + void ma_and(Register rd, Register rs) { as_and(rd, rd, rs); } + void ma_and(Register rd, Imm32 imm) { ma_and(rd, rd, imm); } + void as_addu(Register rd, Register rj, Register rk) { as_add_w(rd, rj, rk); } + void ma_addu(Register rd, Register rs) { as_add_w(rd, rd, rs); } + void ma_addu(Register rd, Imm32 imm) { ma_add_w(rd, rd, imm); } + void ma_addu(Register rd, Register rj, Register rk) { as_add_w(rd, rj, rk); } + void ma_addu(Register rd, Register rj, Imm32 imm) { ma_add_w(rd, rj, imm); } + void as_subu(Register rd, Register rj, Register rk) { as_sub_w(rd, rj, rk); } + void ma_subu(Register rd, Register rs) { as_sub_w(rd, rd, rs); } + void ma_subu(Register rd, Imm32 imm) { ma_sub_w(rd, rd, imm); } + void ma_subu(Register rd, Register rj, Register rk) { as_sub_w(rd, rj, rk); } + void ma_subu(Register rd, Register rj, Imm32 imm) { ma_sub_w(rd, rj, imm); } + void ma_addTestOverflow(Register rd, Register rj, Register rk, + Label* overflow) { + ma_add32TestOverflow(rd, rj, rk, overflow); + } + void ma_addTestOverflow(Register rd, Register rj, Imm32 imm, + Label* overflow) { + ma_add32TestOverflow(rd, rj, imm, overflow); + } + void ma_subTestOverflow(Register rd, Register rj, Register rk, + Label* overflow) { + ma_sub32TestOverflow(rd, rj, rk, overflow); + } + void ma_subTestOverflow(Register rd, Register rj, Imm32 imm, + Label* overflow) { + ma_sub32TestOverflow(rd, rj, imm, overflow); + } + void ma_negu(Register rd, Register rj) { as_sub_w(rd, zero, rj); } + void ma_not(Register rd, Register rj) { as_nor(rd, rj, zero); } + void ma_or(Register rd, Register rs) { as_or(rd, rd, rs); } + void ma_or(Register rd, Imm32 imm) { ma_or(rd, rd, imm); } + void ma_xor(Register rd, Register rs) { as_xor(rd, rd, rs); } + void ma_xor(Register rd, Imm32 imm) { ma_xor(rd, rd, imm); } + void ma_sll(Register rd, Register rj, Register rk) { as_sll_w(rd, rj, rk); } + void ma_sll(Register rd, Register rj, Imm32 imm) { + as_slli_w(rd, rj, imm.value & 0x1f); + } + void ma_dsll(Register rd, Register rj, Register rk) { as_sll_d(rd, rj, rk); } + void ma_dsll(Register rd, Register rj, Imm32 imm) { + as_slli_d(rd, rj, imm.value & 0x3f); + } + void ma_srl(Register rd, Register rj, Register rk) { as_srl_w(rd, rj, rk); } + void ma_srl(Register rd, Register rj, Imm32 imm) { + as_srli_w(rd, rj, imm.value & 0x1f); + } + void ma_dsrl(Register rd, Register rj, Register rk) { as_srl_d(rd, rj, rk); } + void ma_dsrl(Register rd, Register rj, Imm32 imm) { + as_srli_d(rd, rj, imm.value & 0x3f); + } + void ma_sra(Register rd, Register rj, Register rk) { as_sra_w(rd, rj, rk); } + void ma_sra(Register rd, Register rj, Imm32 imm) { + as_srai_w(rd, rj, imm.value & 0x1f); + } + void ma_dsra(Register rd, Register rj, Register rk) { as_sra_d(rd, rj, rk); } + void ma_dsra(Register rd, Register rj, Imm32 imm) { + as_srai_d(rd, rj, imm.value & 0x3f); + } + void ma_dins(Register rd, Register rj, Imm32 pos, Imm32 size) { + as_bstrins_d(rd, rj, pos.value + size.value - 1, pos.value); + } + void ma_dext(Register rd, Register rj, Imm32 pos, Imm32 size) { + as_bstrpick_d(rd, rj, pos.value + size.value - 1, pos.value); + } + void as_clz(Register rd, Register rj) { as_clz_w(rd, rj); } + void ma_ctz(Register rd, Register rj) { as_ctz_w(rd, rj); } + + // branches when done from within la-specific code + void ma_b(Register lhs, Register rhs, Label* l, Condition c, + JumpKind jumpKind = LongJump); + void ma_b(Register lhs, Imm32 imm, Label* l, Condition c, + JumpKind jumpKind = LongJump); + void ma_b(Register lhs, ImmPtr imm, Label* l, Condition c, + JumpKind jumpKind = LongJump); + void ma_b(Register lhs, ImmGCPtr imm, Label* l, Condition c, + JumpKind jumpKind = LongJump) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(lhs != scratch); + ma_li(scratch, imm); + ma_b(lhs, scratch, l, c, jumpKind); + } + + template + void ma_b(Register lhs, const T& rhs, wasm::TrapDesc target, + Condition c, JumpKind jumpKind = LongJump) { + Label label; + ma_b(lhs, rhs, &label, c, jumpKind); + bindLater(&label, target); + } + + void ma_b(wasm::TrapDesc target, JumpKind jumpKind = LongJump) { + Label label; + ma_b(&label, jumpKind); + bindLater(&label, target); + } + + void ma_b(Label* l, JumpKind jumpKind = LongJump); + + // fp instructions + void ma_lis(FloatRegister dest, float value); + + void ma_fst_d(FloatRegister src, BaseIndex address); + void ma_fst_s(FloatRegister src, BaseIndex address); + + void ma_fld_d(FloatRegister dest, const BaseIndex& src); + void ma_fld_s(FloatRegister dest, const BaseIndex& src); + + // FP branches + void ma_bc_s(FloatRegister lhs, FloatRegister rhs, Label* label, + DoubleCondition c, JumpKind jumpKind = LongJump, + FPConditionBit fcc = FCC0); + void ma_bc_d(FloatRegister lhs, FloatRegister rhs, Label* label, + DoubleCondition c, JumpKind jumpKind = LongJump, + FPConditionBit fcc = FCC0); + void ma_bc1s(FloatRegister lhs, FloatRegister rhs, Label* label, + DoubleCondition c, JumpKind jumpKind = LongJump, + FPConditionBit fcc = FCC0) { + ma_bc_s(lhs, rhs, label, c, jumpKind, fcc); + } + void ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label* label, + DoubleCondition c, JumpKind jumpKind = LongJump, + FPConditionBit fcc = FCC0) { + ma_bc_d(lhs, rhs, label, c, jumpKind, fcc); + } + + void ma_call(ImmPtr dest); + + void ma_jump(ImmPtr dest); + + void as_mul(Register rd, Register rj, Register rk) { as_mul_w(rd, rj, rk); } + void as_movz(Register rd, Register rs, Register rt) { moveIfZero(rd, rs, rt); } + void as_movz(FloatFormat fmt, FloatRegister fd, FloatRegister fs, + Register rt) { + ma_fmovz(fmt, fd, fs, rt); + } + void as_mtc1(Register rt, FloatRegister fs) { as_movgr2fr_w(fs, rt); } + void as_mfc1(Register rt, FloatRegister fs) { as_movfr2gr_s(rt, fs); } + void as_dmtc1(Register rt, FloatRegister fs) { as_movgr2fr_d(fs, rt); } + void as_dmfc1(Register rt, FloatRegister fs) { as_movfr2gr_d(rt, fs); } + BufferOffset as_cfc1(Register rd, FPControl) { return as_movfcsr2gr(rd); } + BufferOffset as_ext(Register rd, Register rj, int32_t pos, int32_t size) { + return as_bstrpick_w(rd, rj, pos + size - 1, pos); + } + BufferOffset as_ins(Register rd, Register rj, int32_t pos, int32_t size) { + return as_bstrins_w(rd, rj, pos + size - 1, pos); + } + BufferOffset as_sd(Register rd, Register rj, int32_t si12) { + return as_st_d(rd, rj, si12); + } + BufferOffset as_sd(FloatRegister fd, Register rj, int32_t si12) { + return as_fst_d(fd, rj, si12); + } + BufferOffset as_ld(FloatRegister fd, Register rj, int32_t si12) { + return as_fld_d(fd, rj, si12); + } + BufferOffset as_absd(FloatRegister fd, FloatRegister fj) { + return as_fabs_d(fd, fj); + } + BufferOffset as_abss(FloatRegister fd, FloatRegister fj) { + return as_fabs_s(fd, fj); + } + BufferOffset as_addd(FloatRegister fd, FloatRegister fj, FloatRegister fk) { + return as_fadd_d(fd, fj, fk); + } + BufferOffset as_adds(FloatRegister fd, FloatRegister fj, FloatRegister fk) { + return as_fadd_s(fd, fj, fk); + } + BufferOffset as_subd(FloatRegister fd, FloatRegister fj, FloatRegister fk) { + return as_fsub_d(fd, fj, fk); + } + BufferOffset as_subs(FloatRegister fd, FloatRegister fj, FloatRegister fk) { + return as_fsub_s(fd, fj, fk); + } + BufferOffset as_muld(FloatRegister fd, FloatRegister fj, FloatRegister fk) { + return as_fmul_d(fd, fj, fk); + } + BufferOffset as_muls(FloatRegister fd, FloatRegister fj, FloatRegister fk) { + return as_fmul_s(fd, fj, fk); + } + BufferOffset as_divd(FloatRegister fd, FloatRegister fj, FloatRegister fk) { + return as_fdiv_d(fd, fj, fk); + } + BufferOffset as_divs(FloatRegister fd, FloatRegister fj, FloatRegister fk) { + return as_fdiv_s(fd, fj, fk); + } + BufferOffset as_negd(FloatRegister fd, FloatRegister fj) { + return as_fneg_d(fd, fj); + } + BufferOffset as_negs(FloatRegister fd, FloatRegister fj) { + return as_fneg_s(fd, fj); + } + BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fj) { + return as_fsqrt_d(fd, fj); + } + BufferOffset as_sqrts(FloatRegister fd, FloatRegister fj) { + return as_fsqrt_s(fd, fj); + } + BufferOffset as_floorwd(FloatRegister fd, FloatRegister fj) { + return as_ftintrm_w_d(fd, fj); + } + BufferOffset as_floorws(FloatRegister fd, FloatRegister fj) { + return as_ftintrm_w_s(fd, fj); + } + BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fj) { + return as_ftintrp_w_d(fd, fj); + } + BufferOffset as_ceilws(FloatRegister fd, FloatRegister fj) { + return as_ftintrp_w_s(fd, fj); + } + BufferOffset as_truncld(FloatRegister fd, FloatRegister fj) { + return as_ftintrz_l_d(fd, fj); + } + BufferOffset as_truncls(FloatRegister fd, FloatRegister fj) { + return as_ftintrz_l_s(fd, fj); + } + BufferOffset as_truncwd(FloatRegister fd, FloatRegister fj) { + return as_ftintrz_w_d(fd, fj); + } + BufferOffset as_truncws(FloatRegister fd, FloatRegister fj) { + return as_ftintrz_w_s(fd, fj); + } + BufferOffset ma_BoundsCheck(Register bounded) { + BufferOffset bo = nextOffset(); + ma_liPatchable(bounded, Imm32(0)); + return bo; + } + void ma_load_unaligned(const wasm::MemoryAccessDesc& access, Register dest, + const BaseIndex& src, Register temp, + LoadStoreSize size, LoadStoreExtension extension); + void ma_store_unaligned(const wasm::MemoryAccessDesc& access, Register data, + const BaseIndex& dest, Register temp, + LoadStoreSize size, LoadStoreExtension extension); + void loadUnalignedDouble(const wasm::MemoryAccessDesc& access, + const BaseIndex& src, Register temp, + FloatRegister dest); + void loadUnalignedFloat32(const wasm::MemoryAccessDesc& access, + const BaseIndex& src, Register temp, + FloatRegister dest); + void storeUnalignedDouble(const wasm::MemoryAccessDesc& access, + FloatRegister src, Register temp, + const BaseIndex& dest); + void storeUnalignedFloat32(const wasm::MemoryAccessDesc& access, + FloatRegister src, Register temp, + const BaseIndex& dest); + + void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c); + void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c); + void ma_cmp_set_double(Register dst, FloatRegister lhs, FloatRegister rhs, + DoubleCondition c); + void ma_cmp_set_float32(Register dst, FloatRegister lhs, FloatRegister rhs, + DoubleCondition c); + + void moveToDoubleLo(Register src, FloatRegister dest) { + as_movgr2fr_w(dest, src); + } + void moveFromDoubleLo(FloatRegister src, Register dest) { + as_movfr2gr_s(dest, src); + } + + void moveToFloat32(Register src, FloatRegister dest) { + as_movgr2fr_w(dest, src); + } + void moveFromFloat32(FloatRegister src, Register dest) { + as_movfr2gr_s(dest, src); + } + + // Evaluate srcDest = minmax{Float32,Double}(srcDest, other). + // Handle NaN specially if handleNaN is true. + void minMaxDouble(FloatRegister srcDest, FloatRegister other, bool handleNaN, + bool isMax); + void minMaxFloat32(FloatRegister srcDest, FloatRegister other, bool handleNaN, + bool isMax); + + void loadDouble(const Address& addr, FloatRegister dest); + void loadDouble(const BaseIndex& src, FloatRegister dest); + + // Load a float value into a register, then expand it to a double. + void loadFloatAsDouble(const Address& addr, FloatRegister dest); + void loadFloatAsDouble(const BaseIndex& src, FloatRegister dest); + + void loadFloat32(const Address& addr, FloatRegister dest); + void loadFloat32(const BaseIndex& src, FloatRegister dest); + + + protected: + void wasmLoadImpl(const wasm::MemoryAccessDesc& access, Register memoryBase, + Register ptr, Register ptrScratch, AnyRegister output, + Register tmp); + void wasmStoreImpl(const wasm::MemoryAccessDesc& access, AnyRegister value, + Register memoryBase, Register ptr, Register ptrScratch, + Register tmp); +}; + +class MacroAssembler; + +class MacroAssemblerLOONGARCH64Compat : public MacroAssemblerLOONGARCH64 { + private: + enum PendingDivKind { + PendingDivNone, + PendingDivW, + PendingDivWU, + PendingDivD, + PendingDivDU + }; + + PendingDivKind pendingDivKind_; + Register pendingDivLhs_; + Register pendingDivRhs_; + + public: + using MacroAssemblerLOONGARCH64::call; + + MacroAssemblerLOONGARCH64Compat() + : pendingDivKind_(PendingDivNone), + pendingDivLhs_(InvalidReg), + pendingDivRhs_(InvalidReg) {} + + struct AutoPrepareForPatching { + explicit AutoPrepareForPatching(MacroAssemblerLOONGARCH64Compat&) {} + }; + + bool asmMergeWith(const MacroAssemblerLOONGARCH64Compat& other) { + if (!AssemblerShared::asmMergeWith(size(), other)) + return false; + return m_buffer.appendBuffer(other.m_buffer); + } + + size_t labelToPatchOffset(CodeOffset label) { return label.offset(); } + + void convertBoolToInt32(Register src, Register dest) { + ma_and(dest, src, Imm32(0xff)); + }; + void convertInt32ToDouble(Register src, FloatRegister dest) { + as_movgr2fr_w(dest, src); + as_ffint_d_w(dest, dest); + }; + void convertInt32ToDouble(const Address& src, FloatRegister dest) { + ma_fld_s(dest, src); + as_ffint_d_w(dest, dest); + }; + void convertInt32ToDouble(const BaseIndex& src, FloatRegister dest) { + ScratchRegisterScope scratch(asMasm()); + MOZ_ASSERT(scratch != src.base); + MOZ_ASSERT(scratch != src.index); + computeScaledAddress(src, scratch); + convertInt32ToDouble(Address(scratch, src.offset), dest); + }; + void convertUInt32ToDouble(Register src, FloatRegister dest); + void convertInt64ToDouble(Register src, FloatRegister dest); + void convertInt64ToFloat32(Register src, FloatRegister dest); + void convertUInt32ToFloat32(Register src, FloatRegister dest); + void convertDoubleToFloat32(FloatRegister src, FloatRegister dest); + void convertUInt64ToFloat32(Register src, FloatRegister dest); + void convertDoubleToInt32(FloatRegister src, Register dest, Label* fail, + bool negativeZeroCheck = true); + void convertDoubleToPtr(FloatRegister src, Register dest, Label* fail, + bool negativeZeroCheck = true); + void convertFloat32ToInt32(FloatRegister src, Register dest, Label* fail, + bool negativeZeroCheck = true); + + void convertFloat32ToDouble(FloatRegister src, FloatRegister dest); + void convertInt32ToFloat32(Register src, FloatRegister dest); + void convertInt32ToFloat32(const Address& src, FloatRegister dest); + + void movq(Register rj, Register rd); + + void computeScaledAddress(const BaseIndex& address, Register dest); + + void computeEffectiveAddress(const Address& address, Register dest) { + ma_add_d(dest, address.base, Imm32(address.offset)); + } + + void computeEffectiveAddress(const BaseIndex& address, Register dest) { + computeScaledAddress(address, dest); + if (address.offset) { + ma_add_d(dest, dest, Imm32(address.offset)); + } + } + + void j(Label* dest) { ma_b(dest); } + + void mov(Register src, Register dest) { as_ori(dest, src, 0); } + void mov(ImmWord imm, Register dest) { ma_li(dest, imm); } + void mov(ImmPtr imm, Register dest) { + mov(ImmWord(uintptr_t(imm.value)), dest); + } + void mov(CodeLabel* label, Register dest) { ma_li(dest, label); } + void mov(Register src, Address dest) { storePtr(src, dest); } + void mov(Address src, Register dest) { loadPtr(src, dest); } + BufferOffset as_div(Register lhs, Register rhs); + BufferOffset as_divu(Register lhs, Register rhs); + BufferOffset as_ddiv(Register lhs, Register rhs); + BufferOffset as_ddivu(Register lhs, Register rhs); + BufferOffset as_mflo(Register dest); + BufferOffset as_mfhi(Register dest); + + void writeDataRelocation(const Value& val) { + // Raw GC pointer relocations and Value relocations both end up in + // TraceOneDataRelocation. + if (val.isGCThing()) { + gc::Cell* cell = val.toGCThing(); + if (cell && gc::IsInsideNursery(cell)) { + embedsNurseryPointers_ = true; + } + dataRelocations_.writeUnsigned(currentOffset()); + } + } + + void branch(JitCode* c) { + ScratchRegisterScope scratch(asMasm()); + BufferOffset bo = m_buffer.nextOffset(); + addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); + ma_liPatchable(scratch, ImmPtr(c->raw())); + as_jirl(zero, scratch, BOffImm16(0)); + } + void branch(const Register reg) { as_jirl(zero, reg, BOffImm16(0)); } + void nop() { as_nop(); } + void ret() { + ma_pop(ra); + as_jirl(zero, ra, BOffImm16(0)); + } + inline void retn(Imm32 n); + void push(Imm32 imm) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + ma_push(scratch); + } + void push(ImmWord imm) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + ma_push(scratch); + } + void push(ImmGCPtr imm) { + ScratchRegisterScope scratch(asMasm()); + ma_li(scratch, imm); + ma_push(scratch); + } + void push(const Address& address) { + SecondScratchRegisterScope scratch2(asMasm()); + loadPtr(address, scratch2); + ma_push(scratch2); + } + void push(Register reg) { ma_push(reg); } + void push(FloatRegister reg) { ma_push(reg); } + void pop(Register reg) { ma_pop(reg); } + void pop(FloatRegister reg) { ma_pop(reg); } + void pop(const Address& address) { + ScratchRegisterScope scratch(asMasm()); + ma_pop(scratch); + storePtr(scratch, address); + } + + // Emit a branch that can be toggled to a non-operation. On LOONGARCH64 we use + // "andi" instruction to toggle the branch. + // See ToggleToJmp(), ToggleToCmp(). + CodeOffset toggledJump(Label* label); + + // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch + // this instruction. + CodeOffset toggledCall(JitCode* target, bool enabled); + + static size_t ToggledCallSize(uint8_t* code) { + // Four instructions used in: MacroAssemblerLOONGARCH64Compat::toggledCall + return 4 * sizeof(uint32_t); + } + + CodeOffset pushWithPatch(ImmWord imm) { + ScratchRegisterScope scratch(asMasm()); + CodeOffset offset = movWithPatch(imm, scratch); + ma_push(scratch); + return offset; + } + + CodeOffset movWithPatch(ImmWord imm, Register dest) { + CodeOffset offset = CodeOffset(currentOffset()); + ma_liPatchable(dest, imm, Li64); + return offset; + } + CodeOffset movWithPatch(ImmPtr imm, Register dest) { + CodeOffset offset = CodeOffset(currentOffset()); + ma_liPatchable(dest, imm); + return offset; + } + + void writeCodePointer(CodeLabel* label) { + label->patchAt()->bind(currentOffset()); + m_buffer.ensureSpace(sizeof(void*)); + writeInst(-1); + writeInst(-1); + } + + void jump(Label* label) { ma_b(label); } + void jump(Register reg) { as_jirl(zero, reg, BOffImm16(0)); } + void jump(const Address& address) { + ScratchRegisterScope scratch(asMasm()); + loadPtr(address, scratch); + as_jirl(zero, scratch, BOffImm16(0)); + } + + void jump(JitCode* code) { branch(code); } + void jump(wasm::TrapDesc target) { ma_b(target); } + + void jump(ImmPtr ptr) { + BufferOffset bo = m_buffer.nextOffset(); + addPendingJump(bo, ptr, Relocation::HARDCODED); + ma_jump(ptr); + } + + CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr); + CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr); + + void splitTag(Register src, Register dest) { + as_srli_d(dest, src, JSVAL_TAG_SHIFT); + } + + void splitTag(const ValueOperand& operand, Register dest) { + splitTag(operand.valueReg(), dest); + } + + Register splitTagForTest(const ValueOperand& value) { + splitTag(value, SecondScratchReg); + return SecondScratchReg; + } + + void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) { + splitTag(value, tag); + } + + // unboxing code + void unboxNonDouble(const ValueOperand& operand, Register dest); + void unboxNonDouble(const Address& src, Register dest); + void unboxNonDouble(const BaseIndex& src, Register dest); + + void unboxNonDouble(const ValueOperand& operand, Register dest, + JSValueType type) { + unboxNonDouble(operand.valueReg(), dest, type); + } + + template + void unboxNonDouble(T src, Register dest, JSValueType type) { + MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE); + if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { + load32(src, dest); + return; + } + loadPtr(src, dest); + unboxNonDouble(dest, dest, type); + } + + void unboxNonDouble(Register src, Register dest, JSValueType type) { + MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE); + if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { + as_slli_w(dest, src, 0); + return; + } + + as_bstrpick_d(dest, src, JSVAL_TAG_SHIFT - 1, 0); + } + + template + void unboxObjectOrNull(const T& src, Register dest) { + unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); + // Object and null differ by a single tag bit in the boxed value. + as_bstrins_d(dest, zero, JSVAL_TAG_SHIFT + 3, JSVAL_TAG_SHIFT + 3); + } + + void unboxGCThingForGCBarrier(const Address& src, Register dest) { + loadPtr(src, dest); + as_bstrpick_d(dest, dest, JSVAL_TAG_SHIFT - 1, 0); + } + void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) { + as_bstrpick_d(dest, src.valueReg(), JSVAL_TAG_SHIFT - 1, 0); + } + + void unboxInt32(const ValueOperand& operand, Register dest); + void unboxInt32(Register src, Register dest); + void unboxInt32(const Address& src, Register dest); + void unboxInt32(const BaseIndex& src, Register dest); + void unboxBoolean(const ValueOperand& operand, Register dest); + void unboxBoolean(Register src, Register dest); + void unboxBoolean(const Address& src, Register dest); + void unboxBoolean(const BaseIndex& src, Register dest); + void unboxDouble(const ValueOperand& operand, FloatRegister dest); + void unboxDouble(Register src, Register dest); + void unboxDouble(const Address& src, FloatRegister dest); + void unboxDouble(const BaseIndex& src, FloatRegister dest); + void unboxString(const ValueOperand& operand, Register dest); + void unboxString(Register src, Register dest); + void unboxString(const Address& src, Register dest); + void unboxSymbol(const ValueOperand& src, Register dest); + void unboxSymbol(Register src, Register dest); + void unboxSymbol(const Address& src, Register dest); + void unboxBigInt(const ValueOperand& operand, Register dest); + void unboxBigInt(Register src, Register dest); + void unboxBigInt(const Address& src, Register dest); + void unboxObject(const ValueOperand& src, Register dest); + void unboxObject(Register src, Register dest); + void unboxObject(const Address& src, Register dest); + void unboxObject(const BaseIndex& src, Register dest) { + unboxNonDouble(src, dest); + } + void unboxValue(const ValueOperand& src, AnyRegister dest); + + void notBoolean(const ValueOperand& val) { + as_xori(val.valueReg(), val.valueReg(), 1); + } + + // boxing code + void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister); + void boxDouble(FloatRegister src, const ValueOperand& dest) { + boxDouble(src, dest, ScratchDoubleReg); + } + void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest); + + // Extended unboxing API. If the payload is already in a register, returns + // that register. Otherwise, provides a move to the given scratch register, + // and returns that. + [[nodiscard]] Register extractObject(const Address& address, + Register scratch); + [[nodiscard]] Register extractString(const Address& address, + Register scratch) { + unboxString(address, scratch); + return scratch; + } + [[nodiscard]] Register extractObject(const ValueOperand& value, + Register scratch) { + unboxObject(value, scratch); + return scratch; + } + [[nodiscard]] Register extractString(const ValueOperand& value, + Register scratch) { + unboxString(value, scratch); + return scratch; + } + [[nodiscard]] Register extractSymbol(const ValueOperand& value, + Register scratch) { + unboxSymbol(value, scratch); + return scratch; + } + [[nodiscard]] Register extractInt32(const ValueOperand& value, + Register scratch) { + unboxInt32(value, scratch); + return scratch; + } + [[nodiscard]] Register extractBoolean(const ValueOperand& value, + Register scratch) { + unboxBoolean(value, scratch); + return scratch; + } + [[nodiscard]] Register extractTag(const Address& address, Register scratch); + [[nodiscard]] Register extractTag(const BaseIndex& address, Register scratch); + [[nodiscard]] Register extractTag(const ValueOperand& value, + Register scratch) { + splitTag(value, scratch); + return scratch; + } + + inline void ensureDouble(const ValueOperand& source, FloatRegister dest, + Label* failure); + + void boolValueToDouble(const ValueOperand& operand, FloatRegister dest); + void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest); + void loadInt32OrDouble(const Address& src, FloatRegister dest); + void loadInt32OrDouble(const BaseIndex& addr, FloatRegister dest); + void loadConstantDouble(double dp, FloatRegister dest); + void loadConstantDouble(wasm::RawF64 dp, FloatRegister dest) { + loadConstantDouble(dp.fp(), dest); + } + + void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest); + void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest); + void loadConstantFloat32(float f, FloatRegister dest); + void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest) { + loadConstantFloat32(f.fp(), dest); + } + + void testNullSet(Condition cond, const ValueOperand& value, Register dest); + + void testObjectSet(Condition cond, const ValueOperand& value, Register dest); + + void testUndefinedSet(Condition cond, const ValueOperand& value, + Register dest); + + // higher level tag testing code + Address ToPayload(Address value) { return value; } + + void moveValue(const Value& val, Register dest); + void moveValue(const TypedOrValueRegister& src, const ValueOperand& dest); + void moveValue(const Value& src, const ValueOperand& dest); + void moveValue(const ValueOperand& src, const ValueOperand& dest); + + template + void loadUnboxedValue(const T& address, MIRType type, AnyRegister dest) { + if (dest.isFloat()) { + loadInt32OrDouble(address, dest.fpu()); + } else { + unboxNonDouble(address, dest.gpr(), ValueTypeFromMIRType(type)); + } + } + + template + void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) { + switch (nbytes) { + case 8: + unboxNonDouble(value, ScratchRegister); + storePtr(ScratchRegister, address); + return; + case 4: + store32(value.valueReg(), address); + return; + case 1: + store8(value.valueReg(), address); + return; + default: + MOZ_CRASH("Bad payload width"); + } + } + + void storeUnboxedPayload(ValueOperand value, BaseIndex address, size_t nbytes, + JSValueType type) { + switch (nbytes) { + case 8: { + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + if (type == JSVAL_TYPE_OBJECT) { + unboxObjectOrNull(value, scratch2); + } else { + unboxNonDouble(value, scratch2, type); + } + computeEffectiveAddress(address, scratch); + as_st_d(scratch2, scratch, 0); + return; + } + case 4: + store32(value.valueReg(), address); + return; + case 1: + store8(value.valueReg(), address); + return; + default: + MOZ_CRASH("Bad payload width"); + } + } + + void storeUnboxedPayload(ValueOperand value, Address address, size_t nbytes, + JSValueType type) { + switch (nbytes) { + case 8: { + SecondScratchRegisterScope scratch2(asMasm()); + if (type == JSVAL_TYPE_OBJECT) { + unboxObjectOrNull(value, scratch2); + } else { + unboxNonDouble(value, scratch2, type); + } + storePtr(scratch2, address); + return; + } + case 4: + store32(value.valueReg(), address); + return; + case 1: + store8(value.valueReg(), address); + return; + default: + MOZ_CRASH("Bad payload width"); + } + } + + void boxValue(JSValueType type, Register src, Register dest) { + ScratchRegisterScope scratch(asMasm()); + if (src == dest) { + as_ori(scratch, src, 0); + src = scratch; + } +#ifdef DEBUG + if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { + Label upper32BitsSignExtended; + as_slli_w(dest, src, 0); + ma_b(src, dest, &upper32BitsSignExtended, Equal, ShortJump); + breakpoint(); + bind(&upper32BitsSignExtended); + } +#endif + ma_li(dest, Imm32(int32_t(JSVAL_TYPE_TO_TAG(type)))); + as_slli_d(dest, dest, JSVAL_TAG_SHIFT); + if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { + as_bstrins_d(dest, src, 31, 0); + } else { + as_bstrins_d(dest, src, JSVAL_TAG_SHIFT - 1, 0); + } + } + + void storeValue(ValueOperand val, const Address& dest); + void storeValue(ValueOperand val, const BaseIndex& dest); + void storeValue(JSValueType type, Register reg, Address dest); + void storeValue(JSValueType type, Register reg, BaseIndex dest); + void storeValue(const Value& val, Address dest); + void storeValue(const Value& val, BaseIndex dest); + void storeValue(const Address& src, const Address& dest, Register temp) { + loadPtr(src, temp); + storePtr(temp, dest); + } + + void storePrivateValue(Register src, const Address& dest) { + storePtr(src, dest); + } + void storePrivateValue(ImmGCPtr imm, const Address& dest) { + storePtr(imm, dest); + } + + void loadValue(Address src, ValueOperand val); + void loadValue(const BaseIndex& src, ValueOperand val); + + void loadUnalignedValue(const Address& src, ValueOperand dest) { + loadValue(src, dest); + } + + void tagValue(JSValueType type, Register payload, ValueOperand dest); + + void pushValue(ValueOperand val); + void popValue(ValueOperand val); + void pushValue(const Value& val) { + if (val.isGCThing()) { + ScratchRegisterScope scratch(asMasm()); + writeDataRelocation(val); + movWithPatch(ImmWord(val.asRawBits()), scratch); + push(scratch); + } else { + push(ImmWord(val.asRawBits())); + } + } + void pushValue(JSValueType type, Register reg) { + SecondScratchRegisterScope scratch2(asMasm()); + boxValue(type, reg, scratch2); + push(scratch2); + } + void pushValue(const Address& addr); + + void handleFailureWithHandlerTail(void* handler); + + ///////////////////////////////////////////////////////////////// + // Common interface. + ///////////////////////////////////////////////////////////////// + public: + // The following functions are exposed for use in platform-shared code. + + inline void incrementInt32Value(const Address& addr); + + void move32(Imm32 imm, Register dest); + void move32(Register src, Register dest); + + void movePtr(Register src, Register dest); + void movePtr(ImmWord imm, Register dest); + void movePtr(ImmPtr imm, Register dest); + void movePtr(wasm::SymbolicAddress imm, Register dest); + void movePtr(ImmGCPtr imm, Register dest); + + void load8SignExtend(const Address& address, Register dest); + void load8SignExtend(const BaseIndex& src, Register dest); + + void load8ZeroExtend(const Address& address, Register dest); + void load8ZeroExtend(const BaseIndex& src, Register dest); + + void load16SignExtend(const Address& address, Register dest); + void load16SignExtend(const BaseIndex& src, Register dest); + + template + void load16UnalignedSignExtend(const S& src, Register dest) { + load16SignExtend(src, dest); + } + + void load16ZeroExtend(const Address& address, Register dest); + void load16ZeroExtend(const BaseIndex& src, Register dest); + + template + void load16UnalignedZeroExtend(const S& src, Register dest) { + load16ZeroExtend(src, dest); + } + + void load32(const Address& address, Register dest); + void load32(const BaseIndex& address, Register dest); + void load32(AbsoluteAddress address, Register dest); + void load32(wasm::SymbolicAddress address, Register dest); + + template + void load32Unaligned(const S& src, Register dest) { + load32(src, dest); + } + + void load64(const Address& address, Register64 dest) { + loadPtr(address, dest.reg); + } + void load64(const BaseIndex& address, Register64 dest) { + loadPtr(address, dest.reg); + } + + template + void load64Unaligned(const S& src, Register64 dest) { + load64(src, dest); + } + + void loadPtr(const Address& address, Register dest); + void loadPtr(const BaseIndex& src, Register dest); + void loadPtr(AbsoluteAddress address, Register dest); + void loadPtr(wasm::SymbolicAddress address, Register dest); + + void loadPrivate(const Address& address, Register dest); + + void store8(Register src, const Address& address); + void store8(Imm32 imm, const Address& address); + void store8(Register src, const BaseIndex& address); + void store8(Imm32 imm, const BaseIndex& address); + + void store16(Register src, const Address& address); + void store16(Imm32 imm, const Address& address); + void store16(Register src, const BaseIndex& address); + void store16(Imm32 imm, const BaseIndex& address); + + template + void store16Unaligned(Register src, const T& dest) { + store16(src, dest); + } + + void store32(Register src, AbsoluteAddress address); + void store32(Register src, const Address& address); + void store32(Register src, const BaseIndex& address); + void store32(Imm32 src, const Address& address); + void store32(Imm32 src, const BaseIndex& address); + + // NOTE: This will use second scratch on LOONGARCH64. Only ARM needs the + // implementation without second scratch. + void store32_NoSecondScratch(Imm32 src, const Address& address) { + store32(src, address); + } + + template + void store32Unaligned(Register src, const T& dest) { + store32(src, dest); + } + + void store64(Imm64 imm, Address address) { + storePtr(ImmWord(imm.value), address); + } + void store64(Imm64 imm, const BaseIndex& address) { + storePtr(ImmWord(imm.value), address); + } + + void store64(Register64 src, Address address) { storePtr(src.reg, address); } + void store64(Register64 src, const BaseIndex& address) { + storePtr(src.reg, address); + } + + template + void store64Unaligned(Register64 src, const T& dest) { + store64(src, dest); + } + + template + void storePtr(ImmWord imm, T address); + template + void storePtr(ImmPtr imm, T address); + template + void storePtr(ImmGCPtr imm, T address); + void storePtr(Register src, const Address& address); + void storePtr(Register src, const BaseIndex& address); + void storePtr(Register src, AbsoluteAddress dest); + + void atomicEffectOp(int nbytes, AtomicOp op, Imm32 value, + const Address& address, Register valueTemp, + Register offsetTemp, Register maskTemp); + void atomicEffectOp(int nbytes, AtomicOp op, Imm32 value, + const BaseIndex& address, Register valueTemp, + Register offsetTemp, Register maskTemp); + void atomicEffectOp(int nbytes, AtomicOp op, Register value, + const Address& address, Register valueTemp, + Register offsetTemp, Register maskTemp); + void atomicEffectOp(int nbytes, AtomicOp op, Register value, + const BaseIndex& address, Register valueTemp, + Register offsetTemp, Register maskTemp); + void atomicEffectOp(int nbytes, AtomicOp op, Imm32 value, + const Address& address, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp) { + atomicEffectOp(nbytes, op, value, address, valueTemp, offsetTemp, + maskTemp); + } + void atomicEffectOp(int nbytes, AtomicOp op, Imm32 value, + const BaseIndex& address, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp) { + atomicEffectOp(nbytes, op, value, address, valueTemp, offsetTemp, + maskTemp); + } + void atomicEffectOp(int nbytes, AtomicOp op, Register value, + const Address& address, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp) { + atomicEffectOp(nbytes, op, value, address, valueTemp, offsetTemp, + maskTemp); + } + void atomicEffectOp(int nbytes, AtomicOp op, Register value, + const BaseIndex& address, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp) { + atomicEffectOp(nbytes, op, value, address, valueTemp, offsetTemp, + maskTemp); + } + + void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Imm32 value, + const Address& address, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output); + void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Imm32 value, + const BaseIndex& address, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output); + void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Register value, + const Address& address, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output); + void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Register value, + const BaseIndex& address, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output); + void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Imm32 value, + const Address& address, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(nbytes, signExtend, op, value, address, valueTemp, + offsetTemp, maskTemp, output); + } + void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Imm32 value, + const BaseIndex& address, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(nbytes, signExtend, op, value, address, valueTemp, + offsetTemp, maskTemp, output); + } + void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Register value, + const Address& address, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(nbytes, signExtend, op, value, address, valueTemp, + offsetTemp, maskTemp, output); + } + void atomicFetchOp(int nbytes, bool signExtend, AtomicOp op, Register value, + const BaseIndex& address, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(nbytes, signExtend, op, value, address, valueTemp, + offsetTemp, maskTemp, output); + } + + template + void atomicFetchAdd8SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, true, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchAdd8ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, false, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchAdd16SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, true, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchAdd16ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, false, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchAdd32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(4, false, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicAdd8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(1, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicAdd16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(2, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicAdd32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(4, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + + template + void atomicFetchSub8SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, true, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchSub8ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, false, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchSub16SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, true, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchSub16ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, false, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchSub32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(4, false, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicSub8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(1, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicSub16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(2, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicSub32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(4, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + + template + void atomicFetchAnd8SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, true, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchAnd8ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, false, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchAnd16SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, true, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchAnd16ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, false, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchAnd32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(4, false, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicAnd8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(1, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicAnd16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(2, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicAnd32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(4, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + + template + void atomicFetchOr8SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, true, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchOr8ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, false, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchOr16SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, true, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchOr16ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, false, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchOr32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(4, false, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicOr8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(1, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicOr16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(2, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicOr32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(4, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + + template + void atomicFetchXor8SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, true, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchXor8ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(1, false, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchXor16SignExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, true, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchXor16ZeroExtend(const S& value, const T& mem, + Register flagTemp, Register valueTemp, + Register offsetTemp, Register maskTemp, + Register output) { + atomicFetchOp(2, false, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicFetchXor32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, + Register maskTemp, Register output) { + atomicFetchOp(4, false, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp, output); + } + template + void atomicXor8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(1, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicXor16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(2, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + template + void atomicXor32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) { + atomicEffectOp(4, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, + offsetTemp, maskTemp); + } + + void compareExchange(int nbytes, bool signExtend, const Address& address, + Register oldval, Register newval, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output); + void compareExchange(int nbytes, bool signExtend, const BaseIndex& address, + Register oldval, Register newval, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output); + void compareExchangeToTypedIntArray(Scalar::Type arrayType, + const Address& mem, Register oldval, + Register newval, Register temp, + Register valueTemp, Register offsetTemp, + Register maskTemp, AnyRegister output); + void compareExchangeToTypedIntArray(Scalar::Type arrayType, + const BaseIndex& mem, Register oldval, + Register newval, Register temp, + Register valueTemp, Register offsetTemp, + Register maskTemp, AnyRegister output); + + void atomicExchange(int nbytes, bool signExtend, const Address& address, + Register value, Register valueTemp, Register offsetTemp, + Register maskTemp, Register output); + void atomicExchange(int nbytes, bool signExtend, const BaseIndex& address, + Register value, Register valueTemp, Register offsetTemp, + Register maskTemp, Register output); + void atomicExchangeToTypedIntArray(Scalar::Type arrayType, + const Address& mem, Register value, + Register temp, Register valueTemp, + Register offsetTemp, Register maskTemp, + AnyRegister output); + void atomicExchangeToTypedIntArray(Scalar::Type arrayType, + const BaseIndex& mem, Register value, + Register temp, Register valueTemp, + Register offsetTemp, Register maskTemp, + AnyRegister output); + + void moveDouble(FloatRegister src, FloatRegister dest) { + as_fmov_d(dest, src); + } + + void zeroDouble(FloatRegister reg) { moveToDouble(zero, reg); } + + void cmp64Set(Assembler::Condition cond, Register lhs, Imm32 rhs, + Register dest) { + ma_cmp_set(dest, lhs, rhs, cond); + } + + void convertUInt64ToDouble(Register src, FloatRegister dest); + static bool convertUInt64ToDoubleNeedsTemp(); + void convertUInt64ToDouble(Register64 src, FloatRegister dest, Register temp); + + void breakpoint(uint32_t value = 0); + + void checkStackAlignment() { +#ifdef DEBUG + Label aligned; + ScratchRegisterScope scratch(asMasm()); + as_andi(scratch, sp, ABIStackAlignment - 1); + ma_b(scratch, zero, &aligned, Equal, ShortJump); + breakpoint(); + bind(&aligned); +#endif + }; + + static void calculateAlignedStackPointer(void** stackPointer); + + void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { + loadPtr(Address(GlobalReg, globalDataOffset - WasmGlobalRegBias), dest); + } + void loadWasmPinnedRegsFromTls() { + loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg); + loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalData)), + GlobalReg); + ma_add_d(GlobalReg, GlobalReg, Imm32(WasmGlobalRegBias)); + } + + void cmpPtrSet(Assembler::Condition cond, Address lhs, ImmPtr rhs, + Register dest); + void cmpPtrSet(Assembler::Condition cond, Register lhs, Address rhs, + Register dest); + void cmpPtrSet(Assembler::Condition cond, Address lhs, Register rhs, + Register dest); + + void cmp32Set(Assembler::Condition cond, Register lhs, Address rhs, + Register dest); + + protected: + bool buildOOLFakeExitFrame(void* fakeReturnAddr); + + void wasmLoadI64Impl(const wasm::MemoryAccessDesc& access, + Register memoryBase, Register ptr, Register ptrScratch, + Register64 output, Register tmp); + void wasmStoreI64Impl(const wasm::MemoryAccessDesc& access, Register64 value, + Register memoryBase, Register ptr, Register ptrScratch, + Register tmp); + + public: + CodeOffset labelForPatch() { + return CodeOffset(nextOffset().getOffset()); + } + + void lea(Operand addr, Register dest) { + ma_add_d(dest, addr.baseReg(), Imm32(addr.disp())); + } + + void abiret() { as_jirl(zero, ra, BOffImm16(0)); } + + void moveFloat32(FloatRegister src, FloatRegister dest) { + as_fmov_s(dest, src); + } + + // Instrumentation for entering and leaving the profiler. + void profilerEnterFrame(Register framePtr, Register scratch); + void profilerExitFrame(); +}; + +typedef MacroAssemblerLOONGARCH64Compat MacroAssemblerSpecific; + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_MacroAssembler_loongarch64_h */ diff --git a/js/src/jit/loongarch64/SharedIC-loongarch64.cpp b/js/src/jit/loongarch64/SharedIC-loongarch64.cpp new file mode 100644 index 0000000000..37dbfbdaa5 --- /dev/null +++ b/js/src/jit/loongarch64/SharedIC-loongarch64.cpp @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "jsiter.h" + +#include "jit/BaselineCompiler.h" +#include "jit/BaselineIC.h" +#include "jit/BaselineJIT.h" +#include "jit/Linker.h" +#include "jit/SharedICHelpers.h" + +#include "jsboolinlines.h" + +using namespace js; +using namespace js::jit; + +namespace js { +namespace jit { + +// ICBinaryArith_Int32 + +bool +ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm) +{ + // Guard that R0 is an integer and R1 is an integer. + Label failure; + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); + masm.branchTestInt32(Assembler::NotEqual, R1, &failure); + + // Add R0 and R1. Don't need to explicitly unbox, just use R2's valueReg. + Register scratchReg = R2.valueReg(); + + Label goodMul, divTest1, divTest2; + switch(op_) { + case JSOP_ADD: + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + masm.ma_add32TestOverflow(scratchReg, ExtractTemp0, ExtractTemp1, &failure); + masm.boxValue(JSVAL_TYPE_INT32, scratchReg, R0.valueReg()); + break; + case JSOP_SUB: + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + masm.ma_sub32TestOverflow(scratchReg, ExtractTemp0, ExtractTemp1, &failure); + masm.boxValue(JSVAL_TYPE_INT32, scratchReg, R0.valueReg()); + break; + case JSOP_MUL: { + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + masm.ma_mul32TestOverflow(scratchReg, ExtractTemp0, ExtractTemp1, &failure); + + masm.ma_b(scratchReg, Imm32(0), &goodMul, Assembler::NotEqual, ShortJump); + + // Result is -0 if operands have different signs. + masm.as_xor(t8, ExtractTemp0, ExtractTemp1); + masm.ma_b(t8, Imm32(0), &failure, Assembler::LessThan, ShortJump); + + masm.bind(&goodMul); + masm.boxValue(JSVAL_TYPE_INT32, scratchReg, R0.valueReg()); + break; + } + case JSOP_DIV: + case JSOP_MOD: { + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + // Check for INT_MIN / -1, it results in a double. + masm.ma_b(ExtractTemp0, Imm32(INT_MIN), &divTest1, Assembler::NotEqual, ShortJump); + masm.ma_b(ExtractTemp1, Imm32(-1), &failure, Assembler::Equal, ShortJump); + masm.bind(&divTest1); + + // Check for division by zero. + masm.ma_b(ExtractTemp1, Imm32(0), &failure, Assembler::Equal, ShortJump); + + // Check for 0 / X with X < 0 (results in -0). + masm.ma_b(ExtractTemp0, Imm32(0), &divTest2, Assembler::NotEqual, ShortJump); + masm.ma_b(ExtractTemp1, Imm32(0), &failure, Assembler::LessThan, ShortJump); + masm.bind(&divTest2); + + masm.as_mod_w(scratchReg, ExtractTemp0, ExtractTemp1); + + if (op_ == JSOP_DIV) { + // Result is a double if the remainder != 0. + masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::NotEqual, ShortJump); + masm.as_div_w(scratchReg, ExtractTemp0, ExtractTemp1); + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); + } else { + Label done; + // If X % Y == 0 and X < 0, the result is -0. + masm.ma_b(scratchReg, Imm32(0), &done, Assembler::NotEqual, ShortJump); + masm.ma_b(ExtractTemp0, Imm32(0), &failure, Assembler::LessThan, ShortJump); + masm.bind(&done); + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); + } + break; + } + case JSOP_BITOR: + masm.as_or(R0.valueReg(), R0.valueReg(), R1.valueReg()); + break; + case JSOP_BITXOR: + masm.as_xor(scratchReg, R0.valueReg(), R1.valueReg()); + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); + break; + case JSOP_BITAND: + masm.as_and(R0.valueReg(), R0.valueReg(), R1.valueReg()); + break; + case JSOP_LSH: + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + // LoongArch only uses the low five bits of the shift count here. + masm.as_sll_w(scratchReg, ExtractTemp0, ExtractTemp1); + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); + break; + case JSOP_RSH: + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + masm.as_sra_w(scratchReg, ExtractTemp0, ExtractTemp1); + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); + break; + case JSOP_URSH: + masm.unboxInt32(R0, ExtractTemp0); + masm.unboxInt32(R1, ExtractTemp1); + masm.as_srl_w(scratchReg, ExtractTemp0, ExtractTemp1); + masm.as_bstrpick_d(ExtractTemp1, scratchReg, 31, 31); + if (allowDouble_) { + Label toUint; + masm.ma_b(ExtractTemp1, Imm32(0), &toUint, Assembler::NotEqual, ShortJump); + + // Move result and box for return. + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); + EmitReturnFromIC(masm); + + masm.bind(&toUint); + masm.convertUInt32ToDouble(scratchReg, FloatReg1); + masm.boxDouble(FloatReg1, R0); + } else { + masm.ma_b(ExtractTemp1, Imm32(0), &failure, Assembler::NotEqual, ShortJump); + // Move result for return. + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); + } + break; + default: + MOZ_CRASH("Unhandled op for BinaryArith_Int32."); + } + + EmitReturnFromIC(masm); + + // Failure case - jump to next stub + masm.bind(&failure); + EmitStubGuardFailure(masm); + + return true; +} + +bool +ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm) +{ + Label failure; + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); + + switch (op) { + case JSOP_BITNOT: + masm.not32(R0.valueReg()); + masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); + break; + case JSOP_NEG: + masm.unboxInt32(R0, ExtractTemp0); + // Guard against 0 and MIN_INT, both result in a double. + masm.branchTest32(Assembler::Zero, ExtractTemp0, Imm32(INT32_MAX), &failure); + + masm.neg32(ExtractTemp0); + masm.tagValue(JSVAL_TYPE_INT32, ExtractTemp0, R0); + break; + case JSOP_INC: { + RegisterOrInt32Constant rval = RegisterOrInt32Constant(R0.valueReg()); + masm.inc32(&rval); + masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); + break; + } + case JSOP_DEC: { + RegisterOrInt32Constant rval = RegisterOrInt32Constant(R0.valueReg()); + masm.dec32(&rval); + masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); + break; + } + default: + MOZ_CRASH("Unexpected op"); + return false; + } + + EmitReturnFromIC(masm); + + masm.bind(&failure); + EmitStubGuardFailure(masm); + return true; +} + + +} // namespace jit +} // namespace js diff --git a/js/src/jit/loongarch64/SharedICHelpers-loongarch64.h b/js/src/jit/loongarch64/SharedICHelpers-loongarch64.h new file mode 100644 index 0000000000..ab13b04752 --- /dev/null +++ b/js/src/jit/loongarch64/SharedICHelpers-loongarch64.h @@ -0,0 +1,381 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#ifndef jit_loongarch64_SharedICHelpers_loongarch64_h +#define jit_loongarch64_SharedICHelpers_loongarch64_h + +#include "jit/BaselineFrame.h" +#include "jit/BaselineIC.h" +#include "jit/MacroAssembler.h" +#include "jit/SharedICRegisters.h" + +namespace js { +namespace jit { + +// Distance from sp to the top Value inside an IC stub (no return address on +// the stack on LoongArch). +static const size_t ICStackValueOffset = 0; + +inline void +EmitRestoreTailCallReg(MacroAssembler& masm) +{ + // No-op on LoongArch because ra register is always holding the return address. +} + +inline void +EmitRepushTailCallReg(MacroAssembler& masm) +{ + // No-op on LoongArch because ra register is always holding the return address. +} + +inline void +EmitCallIC(CodeOffset* patchOffset, MacroAssembler& masm) +{ + // Move ICEntry offset into ICStubReg. + CodeOffset offset = masm.movWithPatch(ImmWord(-1), ICStubReg); + *patchOffset = offset; + + // Load stub pointer into ICStubReg. + masm.loadPtr(Address(ICStubReg, ICEntry::offsetOfFirstStub()), ICStubReg); + + // Load stubcode pointer from BaselineStubEntry. + // R2 won't be active when we call ICs, so we can use it as scratch. + masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); + + // Call the stubcode via a direct jump-and-link + masm.call(R2.scratchReg()); +} + +inline void +EmitEnterTypeMonitorIC(MacroAssembler& masm, + size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub()) +{ + // This is expected to be called from within an IC, when ICStubReg + // is properly initialized to point to the stub. + masm.loadPtr(Address(ICStubReg, (uint32_t) monitorStubOffset), ICStubReg); + + // Load stubcode pointer from BaselineStubEntry. + // R2 won't be active when we call ICs, so we can use it. + masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); + + // Jump to the stubcode. + masm.branch(R2.scratchReg()); +} + +inline void +EmitReturnFromIC(MacroAssembler& masm) +{ + masm.branch(ra); +} + +inline void +EmitChangeICReturnAddress(MacroAssembler& masm, Register reg) +{ + masm.movePtr(reg, ra); +} + +inline void +EmitBaselineTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) +{ + Register scratch = R2.scratchReg(); + + // Compute frame size. + masm.movePtr(BaselineFrameReg, scratch); + masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), scratch); + masm.subPtr(BaselineStackReg, scratch); + + // Store frame size without VMFunction arguments for GC marking. + masm.subPtr(Imm32(argSize), scratch); + masm.store32(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize())); + masm.addPtr(Imm32(argSize), scratch); + + // Push frame descriptor and perform the tail call. + // ICTailCallReg (ra) already contains the return address (as we + // keep it there through the stub calls), but the VMWrapper code being + // called expects the return address to also be pushed on the stack. + MOZ_ASSERT(ICTailCallReg == ra); + masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS, ExitFrameLayout::Size()); + masm.subPtr(Imm32(sizeof(CommonFrameLayout)), StackPointer); + masm.storePtr(scratch, Address(StackPointer, CommonFrameLayout::offsetOfDescriptor())); + masm.storePtr(ra, Address(StackPointer, CommonFrameLayout::offsetOfReturnAddress())); + + masm.branch(target); +} + +inline void +EmitIonTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t stackSize) +{ + Register scratch = R2.scratchReg(); + + masm.loadPtr(Address(sp, stackSize), scratch); + masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch); + masm.addPtr(Imm32(stackSize + JitStubFrameLayout::Size() - sizeof(intptr_t)), scratch); + + // Push frame descriptor and perform the tail call. + MOZ_ASSERT(ICTailCallReg == ra); + masm.makeFrameDescriptor(scratch, JitFrame_IonJS, ExitFrameLayout::Size()); + masm.push(scratch); + masm.push(ICTailCallReg); + masm.branch(target); +} + +inline void +EmitBaselineCreateStubFrameDescriptor(MacroAssembler& masm, Register reg, uint32_t headerSize) +{ + // Compute stub frame size. We have to add two pointers: the stub reg and + // previous frame pointer pushed by EmitEnterStubFrame. + masm.movePtr(BaselineFrameReg, reg); + masm.addPtr(Imm32(sizeof(intptr_t) * 2), reg); + masm.subPtr(BaselineStackReg, reg); + + masm.makeFrameDescriptor(reg, JitFrame_BaselineStub, headerSize); +} + +inline void +EmitBaselineCallVM(JitCode* target, MacroAssembler& masm) +{ + Register scratch = R2.scratchReg(); + EmitBaselineCreateStubFrameDescriptor(masm, scratch, ExitFrameLayout::Size()); + masm.push(scratch); + masm.call(target); +} + +inline void +EmitIonCallVM(JitCode* target, size_t stackSlots, MacroAssembler& masm) +{ + uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonStub, + ExitFrameLayout::Size()); + masm.Push(Imm32(descriptor)); + masm.callJit(target); + + // Remove rest of the frame left on the stack. We remove the return address + // which is implicitly popped when returning. + size_t framePop = sizeof(ExitFrameLayout) - sizeof(void*); + + // Pop arguments from framePushed. + masm.implicitPop(stackSlots * sizeof(void*) + framePop); +} + +struct BaselineStubFrame { + uintptr_t savedFrame; + uintptr_t savedStub; + uintptr_t returnAddress; + uintptr_t descriptor; +}; + +static const uint32_t STUB_FRAME_SIZE = sizeof(BaselineStubFrame); +static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = offsetof(BaselineStubFrame, savedStub); + +inline void +EmitBaselineEnterStubFrame(MacroAssembler& masm, Register scratch) +{ + MOZ_ASSERT(scratch != ICTailCallReg); + + // Compute frame size. + masm.movePtr(BaselineFrameReg, scratch); + masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), scratch); + masm.subPtr(BaselineStackReg, scratch); + + masm.store32(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize())); + + // Note: when making changes here, don't forget to update + // BaselineStubFrame if needed. + + // Push frame descriptor and return address. + masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS, BaselineStubFrameLayout::Size()); + masm.subPtr(Imm32(STUB_FRAME_SIZE), StackPointer); + masm.storePtr(scratch, Address(StackPointer, offsetof(BaselineStubFrame, descriptor))); + masm.storePtr(ICTailCallReg, Address(StackPointer, + offsetof(BaselineStubFrame, returnAddress))); + + // Save old frame pointer, stack pointer and stub reg. + masm.storePtr(ICStubReg, Address(StackPointer, + offsetof(BaselineStubFrame, savedStub))); + masm.storePtr(BaselineFrameReg, Address(StackPointer, + offsetof(BaselineStubFrame, savedFrame))); + masm.movePtr(BaselineStackReg, BaselineFrameReg); + + // Stack should remain aligned. + masm.assertStackAlignment(sizeof(Value), 0); +} + +inline void +EmitIonEnterStubFrame(MacroAssembler& masm, Register scratch) +{ + MOZ_ASSERT(ICTailCallReg == ra); + + // In LoongArch the ra register contains the return address, + // but in jit frames we expect it to be on the stack. As a result + // push the link register (which is actually part of the previous frame. + // Therefore using push instead of Push). + masm.push(ICTailCallReg); + + masm.Push(ICStubReg); +} + +inline void +EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) +{ + // Ion frames do not save and restore the frame pointer. If we called + // into Ion, we have to restore the stack pointer from the frame descriptor. + // If we performed a VM call, the descriptor has been popped already so + // in that case we use the frame pointer. + if (calledIntoIon) { + masm.pop(ScratchRegister); + masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), ScratchRegister); + masm.addPtr(ScratchRegister, BaselineStackReg); + } else { + masm.movePtr(BaselineFrameReg, BaselineStackReg); + } + + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedFrame)), + BaselineFrameReg); + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedStub)), + ICStubReg); + + // Load the return address. + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, returnAddress)), + ICTailCallReg); + + // Discard the frame descriptor. + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, descriptor)), ScratchRegister); + masm.addPtr(Imm32(STUB_FRAME_SIZE), StackPointer); +} + +inline void +EmitIonLeaveStubFrame(MacroAssembler& masm) +{ + masm.Pop(ICStubReg); + masm.pop(ICTailCallReg); // See EmitIonEnterStubFrame for explanation on pop/Pop. +} + +inline void +EmitStowICValues(MacroAssembler& masm, int values) +{ + MOZ_ASSERT(values >= 0 && values <= 2); + switch(values) { + case 1: + // Stow R0 + masm.Push(R0); + break; + case 2: + // Stow R0 and R1 + masm.Push(R0); + masm.Push(R1); + } +} + +inline void +EmitUnstowICValues(MacroAssembler& masm, int values, bool discard = false) +{ + MOZ_ASSERT(values >= 0 && values <= 2); + switch(values) { + case 1: + // Unstow R0. + if (discard) + masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg); + else + masm.popValue(R0); + break; + case 2: + // Unstow R0 and R1. + if (discard) { + masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg); + } else { + masm.popValue(R1); + masm.popValue(R0); + } + break; + } + masm.adjustFrame(-values * sizeof(Value)); +} + +inline void +EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) +{ + // R0 contains the value that needs to be typechecked. + // The object we're updating is a boxed Value on the stack, at offset + // objectOffset from $sp, excluding the return address. + + // Save the current ICStubReg to stack, as well as the TailCallReg, + // since on LoongArch, the $ra is live. + masm.subPtr(Imm32(2 * sizeof(intptr_t)), StackPointer); + masm.storePtr(ICStubReg, Address(StackPointer, sizeof(intptr_t))); + masm.storePtr(ICTailCallReg, Address(StackPointer, 0)); + + // This is expected to be called from within an IC, when ICStubReg + // is properly initialized to point to the stub. + masm.loadPtr(Address(ICStubReg, ICUpdatedStub::offsetOfFirstUpdateStub()), + ICStubReg); + + // Load stubcode pointer from ICStubReg into ICTailCallReg. + masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); + + // Call the stubcode. + masm.call(R2.scratchReg()); + + // Restore the old stub reg and tailcall reg. + masm.loadPtr(Address(StackPointer, 0), ICTailCallReg); + masm.loadPtr(Address(StackPointer, sizeof(intptr_t)), ICStubReg); + masm.addPtr(Imm32(2 * sizeof(intptr_t)), StackPointer); + + // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the + // value in R0 type-checked properly or not. + Label success; + masm.ma_b(R1.scratchReg(), Imm32(1), &success, Assembler::Equal, ShortJump); + + // If the IC failed, then call the update fallback function. + EmitBaselineEnterStubFrame(masm, R1.scratchReg()); + + masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1); + + masm.Push(R0); + masm.Push(R1); + masm.Push(ICStubReg); + + // Load previous frame pointer, push BaselineFrame*. + masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg()); + masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg()); + + EmitBaselineCallVM(code, masm); + EmitBaselineLeaveStubFrame(masm); + + // Success at end. + masm.bind(&success); +} + +template +inline void +EmitPreBarrier(MacroAssembler& masm, const AddrType& addr, MIRType type) +{ + // On LoongArch, $ra is clobbered by patchableCallPreBarrier. Save it first. + masm.push(ra); + masm.patchableCallPreBarrier(addr, type); + masm.pop(ra); +} + +inline void +EmitStubGuardFailure(MacroAssembler& masm) +{ + // NOTE: This routine assumes that the stub guard code left the stack in + // the same state it was in when it was entered. + + // BaselineStubEntry points to the current stub. + + // Load next stub into ICStubReg + masm.loadPtr(Address(ICStubReg, ICStub::offsetOfNext()), ICStubReg); + + // Load stubcode pointer from BaselineStubEntry into scratch register. + masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); + + // Return address is already loaded, just jump to the next stubcode. + MOZ_ASSERT(ICTailCallReg == ra); + masm.branch(R2.scratchReg()); +} + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_SharedICHelpers_loongarch64_h */ diff --git a/js/src/jit/loongarch64/SharedICRegisters-loongarch64.h b/js/src/jit/loongarch64/SharedICRegisters-loongarch64.h new file mode 100644 index 0000000000..f3062ec43a --- /dev/null +++ b/js/src/jit/loongarch64/SharedICRegisters-loongarch64.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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/. */ + +#ifndef jit_loongarch64_SharedICRegisters_loongarch64_h +#define jit_loongarch64_SharedICRegisters_loongarch64_h + +#include "jit/loongarch64/Assembler-loongarch64.h" +#include "jit/Registers.h" +#include "jit/RegisterSets.h" + +namespace js { +namespace jit { + +// Must be a callee-saved register for preservation around generateEnterJIT(). +static constexpr Register BaselineFrameReg = s5; +static constexpr Register BaselineStackReg = sp; + +// ValueOperands R0, R1, and R2. +// R0 == JSReturnReg, and R2 uses registers not preserved across calls. R1 value +// should be preserved across calls. +static constexpr ValueOperand R0(a2); +static constexpr ValueOperand R1(s1); +static constexpr ValueOperand R2(a0); + +// ICTailCallReg and ICStubReg +// These use registers that are not preserved across calls. +static constexpr Register ICTailCallReg = ra; +static constexpr Register ICStubReg = t0; + +// ExtractTemps must be callee-save registers: +// ICSetProp_Native::Compiler::generateStubCode() stores the object +// in ExtractTemp0, but then calls callTypeUpdateIC(), which clobbers +// caller-save registers. +static constexpr Register ExtractTemp0 = s7; +static constexpr Register ExtractTemp1 = s8; + +// Note that ICTailCallReg is actually just the link register. +// In LoongArch code emission, we do not clobber ICTailCallReg since we keep +// the return address for calls there. + +// FloatReg0 must be equal to ReturnFloatReg. +static constexpr FloatRegister FloatReg0 = f0; +static constexpr FloatRegister FloatReg1 = f1; +static constexpr FloatRegister FloatReg2 = f2; +static constexpr FloatRegister FloatReg3 = f3; + +} // namespace jit +} // namespace js + +#endif /* jit_loongarch64_SharedICRegisters_loongarch64_h */ diff --git a/js/src/jit/loongarch64/Trampoline-loongarch64.cpp b/js/src/jit/loongarch64/Trampoline-loongarch64.cpp new file mode 100644 index 0000000000..2244c76b78 --- /dev/null +++ b/js/src/jit/loongarch64/Trampoline-loongarch64.cpp @@ -0,0 +1,1340 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "mozilla/DebugOnly.h" + +#include "jscompartment.h" + +#include "jit/Bailouts.h" +#include "jit/JitCompartment.h" +#include "jit/JitFrames.h" +#include "jit/JitSpewer.h" +#include "jit/Linker.h" +#include "jit/loongarch64/SharedICHelpers-loongarch64.h" +#include "jit/loongarch64/Bailouts-loongarch64.h" +#ifdef JS_ION_PERF +# include "jit/PerfSpewer.h" +#endif +#include "jit/VMFunctions.h" + +#include "jit/MacroAssembler-inl.h" + +using namespace js; +using namespace js::jit; + +// All registers to save and restore. This includes the stack pointer, since we +// use the ability to reference register values on the stack by index. +static const LiveRegisterSet AllRegs = + LiveRegisterSet(GeneralRegisterSet(Registers::AllMask), + FloatRegisterSet(FloatRegisters::AllMask)); + +static_assert(sizeof(uintptr_t) == sizeof(uint64_t), "Not 32-bit clean."); + +struct EnterJITRegs +{ + double f31; + double f30; + double f29; + double f28; + double f27; + double f26; + double f25; + double f24; + + // non-volatile registers. + uint64_t ra; + uint64_t fp; + uint64_t s8; + uint64_t s7; + uint64_t s6; + uint64_t s5; + uint64_t s4; + uint64_t s3; + uint64_t s2; + uint64_t s1; + uint64_t s0; + // Save reg_vp(a7) on stack, use it after call jit code. + uint64_t a7; +}; + +static void +GenerateReturn(MacroAssembler& masm, int returnCode) +{ + MOZ_ASSERT(masm.framePushed() == sizeof(EnterJITRegs)); + + // Restore non-volatile registers. + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s0)), s0); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s1)), s1); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s2)), s2); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s3)), s3); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s4)), s4); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s5)), s5); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s6)), s6); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s7)), s7); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, s8)), s8); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, fp)), fp); + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, ra)), ra); + + // Restore non-volatile floating point registers. + masm.loadDouble(Address(StackPointer, offsetof(EnterJITRegs, f24)), f24); + masm.loadDouble(Address(StackPointer, offsetof(EnterJITRegs, f25)), f25); + masm.loadDouble(Address(StackPointer, offsetof(EnterJITRegs, f26)), f26); + masm.loadDouble(Address(StackPointer, offsetof(EnterJITRegs, f27)), f27); + masm.loadDouble(Address(StackPointer, offsetof(EnterJITRegs, f28)), f28); + masm.loadDouble(Address(StackPointer, offsetof(EnterJITRegs, f29)), f29); + masm.loadDouble(Address(StackPointer, offsetof(EnterJITRegs, f30)), f30); + masm.loadDouble(Address(StackPointer, offsetof(EnterJITRegs, f31)), f31); + + masm.freeStack(sizeof(EnterJITRegs)); + + masm.branch(ra); +} + +static void +GeneratePrologue(MacroAssembler& masm) +{ + masm.reserveStack(sizeof(EnterJITRegs)); + + masm.storePtr(s0, Address(StackPointer, offsetof(EnterJITRegs, s0))); + masm.storePtr(s1, Address(StackPointer, offsetof(EnterJITRegs, s1))); + masm.storePtr(s2, Address(StackPointer, offsetof(EnterJITRegs, s2))); + masm.storePtr(s3, Address(StackPointer, offsetof(EnterJITRegs, s3))); + masm.storePtr(s4, Address(StackPointer, offsetof(EnterJITRegs, s4))); + masm.storePtr(s5, Address(StackPointer, offsetof(EnterJITRegs, s5))); + masm.storePtr(s6, Address(StackPointer, offsetof(EnterJITRegs, s6))); + masm.storePtr(s7, Address(StackPointer, offsetof(EnterJITRegs, s7))); + masm.storePtr(s8, Address(StackPointer, offsetof(EnterJITRegs, s8))); + masm.storePtr(fp, Address(StackPointer, offsetof(EnterJITRegs, fp))); + masm.storePtr(ra, Address(StackPointer, offsetof(EnterJITRegs, ra))); + masm.storePtr(a7, Address(StackPointer, offsetof(EnterJITRegs, a7))); + + masm.storeDouble(f24, Address(StackPointer, offsetof(EnterJITRegs, f24))); + masm.storeDouble(f25, Address(StackPointer, offsetof(EnterJITRegs, f25))); + masm.storeDouble(f26, Address(StackPointer, offsetof(EnterJITRegs, f26))); + masm.storeDouble(f27, Address(StackPointer, offsetof(EnterJITRegs, f27))); + masm.storeDouble(f28, Address(StackPointer, offsetof(EnterJITRegs, f28))); + masm.storeDouble(f29, Address(StackPointer, offsetof(EnterJITRegs, f29))); + masm.storeDouble(f30, Address(StackPointer, offsetof(EnterJITRegs, f30))); + masm.storeDouble(f31, Address(StackPointer, offsetof(EnterJITRegs, f31))); +} + +// Generates a trampoline for calling Jit compiled code from a C++ function. +// The trampoline use the EnterJitCode signature, with the standard x64 fastcall +// calling convention. +JitCode * +JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type) +{ + const Register reg_code = IntArgReg0; + const Register reg_argc = IntArgReg1; + const Register reg_argv = IntArgReg2; + const mozilla::DebugOnly reg_frame = IntArgReg3; + const Register reg_token = IntArgReg4; + const Register reg_chain = IntArgReg5; + const Register reg_values = IntArgReg6; + const Register reg_vp = IntArgReg7; + MacroAssembler masm(cx); + + MOZ_ASSERT(OsrFrameReg == reg_frame); + + GeneratePrologue(masm); + + // Save stack pointer into s4 + masm.movePtr(StackPointer, s4); + + // Save stack pointer as baseline frame. + if (type == EnterJitBaseline) + masm.movePtr(StackPointer, BaselineFrameReg); + + // Load the number of actual arguments into s3. + masm.unboxInt32(Address(reg_vp, 0), s3); + + /*************************************************************** + Loop over argv vector, push arguments onto stack in reverse order + ***************************************************************/ + + // if we are constructing, that also needs to include newTarget + { + Label noNewTarget; + masm.branchTest32(Assembler::Zero, reg_token, Imm32(CalleeToken_FunctionConstructing), + &noNewTarget); + + masm.add32(Imm32(1), reg_argc); + + masm.bind(&noNewTarget); + } + + // Make stack algined + masm.ma_and(s0, reg_argc, Imm32(1)); + masm.ma_sub_d(s1, StackPointer, Imm32(sizeof(Value))); + masm.moveIfNotZero(StackPointer, s1, s0); + + masm.as_slli_d(s0, reg_argc, 3); // Value* argv + masm.addPtr(reg_argv, s0); // s0 = &argv[argc] + + // Loop over arguments, copying them from an unknown buffer onto the Ion + // stack so they can be accessed from JIT'ed code. + Label header, footer; + // If there aren't any arguments, don't do anything + masm.ma_b(s0, reg_argv, &footer, Assembler::BelowOrEqual, ShortJump); + { + masm.bind(&header); + + masm.subPtr(Imm32(sizeof(Value)), s0); + masm.subPtr(Imm32(sizeof(Value)), StackPointer); + + ValueOperand value = ValueOperand(s6); + masm.loadValue(Address(s0, 0), value); + masm.storeValue(value, Address(StackPointer, 0)); + + masm.ma_b(s0, reg_argv, &header, Assembler::Above, ShortJump); + } + masm.bind(&footer); + + masm.subPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer); + masm.storePtr(s3, Address(StackPointer, sizeof(uintptr_t))); // actual arguments + masm.storePtr(reg_token, Address(StackPointer, 0)); // callee token + + masm.subPtr(StackPointer, s4); + masm.makeFrameDescriptor(s4, JitFrame_Entry, JitFrameLayout::Size()); + masm.push(s4); // descriptor + + CodeLabel returnLabel; + CodeLabel oomReturnLabel; + if (type == EnterJitBaseline) { + // Handle OSR. + AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); + regs.take(OsrFrameReg); + regs.take(BaselineFrameReg); + regs.take(reg_code); + regs.take(ReturnReg); + regs.take(JSReturnOperand); + + Label notOsr; + masm.ma_b(OsrFrameReg, OsrFrameReg, ¬Osr, Assembler::Zero, ShortJump); + + Register numStackValues = reg_values; + regs.take(numStackValues); + Register scratch = regs.takeAny(); + + // Push return address. + masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer); + masm.ma_li(scratch, returnLabel.patchAt()); + masm.storePtr(scratch, Address(StackPointer, 0)); + + // Push previous frame pointer. + masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer); + masm.storePtr(BaselineFrameReg, Address(StackPointer, 0)); + + // Reserve frame. + Register framePtr = BaselineFrameReg; + masm.subPtr(Imm32(BaselineFrame::Size()), StackPointer); + masm.movePtr(StackPointer, framePtr); + + // Reserve space for locals and stack values. + masm.as_slli_d(scratch, numStackValues, 3); + masm.subPtr(scratch, StackPointer); + + // Enter exit frame. + masm.addPtr(Imm32(BaselineFrame::Size() + BaselineFrame::FramePointerOffset), scratch); + masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS, ExitFrameLayout::Size()); + + // Push frame descriptor and fake return address. + masm.reserveStack(2 * sizeof(uintptr_t)); + masm.storePtr(scratch, Address(StackPointer, sizeof(uintptr_t))); // Frame descriptor + masm.storePtr(zero, Address(StackPointer, 0)); // fake return address + + // No GC things to mark, push a bare token. + masm.enterFakeExitFrame(ExitFrameLayoutBareToken); + + masm.reserveStack(2 * sizeof(uintptr_t)); + masm.storePtr(framePtr, Address(StackPointer, sizeof(uintptr_t))); // BaselineFrame + masm.storePtr(reg_code, Address(StackPointer, 0)); // jitcode + + masm.setupUnalignedABICall(scratch); + masm.passABIArg(BaselineFrameReg); // BaselineFrame + masm.passABIArg(OsrFrameReg); // InterpreterFrame + masm.passABIArg(numStackValues); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr)); + + regs.add(OsrFrameReg); + Register jitcode = regs.takeAny(); + masm.loadPtr(Address(StackPointer, 0), jitcode); + masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), framePtr); + masm.freeStack(2 * sizeof(uintptr_t)); + + Label error; + masm.freeStack(ExitFrameLayout::SizeWithFooter()); + masm.addPtr(Imm32(BaselineFrame::Size()), framePtr); + masm.branchIfFalseBool(ReturnReg, &error); + + // If OSR-ing, then emit instrumentation for setting lastProfilerFrame + // if profiler instrumentation is enabled. + { + Label skipProfilingInstrumentation; + Register realFramePtr = numStackValues; + AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled()); + masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), + &skipProfilingInstrumentation); + masm.ma_add_d(realFramePtr, framePtr, Imm32(sizeof(void*))); + masm.profilerEnterFrame(realFramePtr, scratch); + masm.bind(&skipProfilingInstrumentation); + } + + masm.jump(jitcode); + + // OOM: load error value, discard return address and previous frame + // pointer and return. + masm.bind(&error); + masm.movePtr(framePtr, StackPointer); + masm.addPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer); + masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand); + masm.ma_li(scratch, oomReturnLabel.patchAt()); + masm.jump(scratch); + + masm.bind(¬Osr); + // Load the scope chain in R1. + MOZ_ASSERT(R1.scratchReg() != reg_code); + masm.movePtr(reg_chain, R1.scratchReg()); + } + + // The call will push the return address on the stack, thus we check that + // the stack would be aligned once the call is complete. + masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t)); + + // Call the function with pushing return address to stack. + masm.callJitNoProfiler(reg_code); + + if (type == EnterJitBaseline) { + // Baseline OSR will return here. + masm.bind(returnLabel.target()); + masm.addCodeLabel(returnLabel); + masm.bind(oomReturnLabel.target()); + masm.addCodeLabel(oomReturnLabel); + } + + // Pop arguments off the stack. + // s0 <- 8*argc (size of all arguments we pushed on the stack) + masm.pop(s0); + masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), s0); + masm.addPtr(s0, StackPointer); + + // Store the returned value into the vp + masm.loadPtr(Address(StackPointer, offsetof(EnterJITRegs, a7)), reg_vp); + masm.storeValue(JSReturnOperand, Address(reg_vp, 0)); + + // Restore non-volatile registers and return. + GenerateReturn(masm, ShortJump); + + Linker linker(masm); + AutoFlushICache afc("GenerateEnterJIT"); + JitCode* code = linker.newCode(cx, OTHER_CODE); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(code, "EnterJIT"); +#endif + + return code; +} + +JitCode* +JitRuntime::generateInvalidator(JSContext* cx) +{ + MacroAssembler masm(cx); + + // Stack has to be alligned here. If not, we will have to fix it. + masm.checkStackAlignment(); + + // Push registers such that we can access them from [base + code]. + masm.PushRegsInMask(AllRegs); + + // Pass pointer to InvalidationBailoutStack structure. + masm.movePtr(StackPointer, a0); + + // Reserve place for return value and BailoutInfo pointer + masm.subPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer); + // Pass pointer to return value. + masm.ma_add_d(a1, StackPointer, Imm32(sizeof(uintptr_t))); + // Pass pointer to BailoutInfo + masm.movePtr(StackPointer, a2); + + masm.setupAlignedABICall(); + masm.passABIArg(a0); + masm.passABIArg(a1); + masm.passABIArg(a2); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout)); + + masm.loadPtr(Address(StackPointer, 0), a2); + masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), a1); + // Remove the return address, the IonScript, the register state + // (InvaliationBailoutStack) and the space that was allocated for the + // return value. + masm.addPtr(Imm32(sizeof(InvalidationBailoutStack) + 2 * sizeof(uintptr_t)), StackPointer); + // remove the space that this frame was using before the bailout + // (computed by InvalidationBailout) + masm.addPtr(a1, StackPointer); + + // Jump to shared bailout tail. The BailoutInfo pointer has to be in r2. + JitCode* bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail(); + masm.branch(bailoutTail); + + Linker linker(masm); + AutoFlushICache afc("Invalidator"); + JitCode* code = linker.newCode(cx, OTHER_CODE); + JitSpew(JitSpew_IonInvalidate, " invalidation thunk created at %p", (void*) code->raw()); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(code, "Invalidator"); +#endif + + return code; +} + +JitCode* +JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut) +{ + // Do not erase the frame pointer in this function. + + MacroAssembler masm(cx); + masm.pushReturnAddress(); + // Caller: + // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- sp + // '--- s3 ---' + + // ArgumentsRectifierReg contains the |nargs| pushed onto the current + // frame. Including |this|, there are (|nargs| + 1) arguments to copy. + MOZ_ASSERT(ArgumentsRectifierReg == s3); + + // Add |this|, in the counter of known arguments. + masm.addPtr(Imm32(1), ArgumentsRectifierReg); + + Register numActArgsReg = a6; + Register calleeTokenReg = a7; + Register numArgsReg = a5; + + // Load |nformals| into numArgsReg. + masm.loadPtr(Address(StackPointer, RectifierFrameLayout::offsetOfCalleeToken()), + calleeTokenReg); + masm.mov(calleeTokenReg, numArgsReg); + masm.andPtr(Imm32(uint32_t(CalleeTokenMask)), numArgsReg); + masm.load16ZeroExtend(Address(numArgsReg, JSFunction::offsetOfNargs()), numArgsReg); + + // Stash another copy in t3, since we are going to do destructive operations + // on numArgsReg + masm.mov(numArgsReg, t3); + + static_assert(CalleeToken_FunctionConstructing == 1, + "Ensure that we can use the constructing bit to count the value"); + masm.mov(calleeTokenReg, t2); + masm.ma_and(t2, t2, Imm32(uint32_t(CalleeToken_FunctionConstructing))); + + // Including |this|, and |new.target|, there are (|nformals| + 1 + isConstructing) + // arguments to push to the stack. Then we push a JitFrameLayout. We + // compute the padding expressed in the number of extra |undefined| values + // to push on the stack. + static_assert(sizeof(JitFrameLayout) % JitStackAlignment == 0, + "No need to consider the JitFrameLayout for aligning the stack"); + static_assert(JitStackAlignment % sizeof(Value) == 0, + "Ensure that we can pad the stack by pushing extra UndefinedValue"); + + MOZ_ASSERT(mozilla::IsPowerOfTwo(JitStackValueAlignment)); + masm.add32(Imm32(JitStackValueAlignment - 1 /* for padding */ + 1 /* for |this| */), numArgsReg); + masm.add32(t2, numArgsReg); + masm.and32(Imm32(~(JitStackValueAlignment - 1)), numArgsReg); + + // Load the number of |undefined|s to push into t1. + masm.as_sub_d(t1, numArgsReg, s3); + + // Caller: + // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- sp <- t2 + // '------ s3 -------' + // + // Rectifier frame: + // [undef] [undef] [undef] [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] + // '-------- t1 ---------' '------- s3 -------' + + // Copy number of actual arguments into numActArgsReg + masm.loadPtr(Address(StackPointer, RectifierFrameLayout::offsetOfNumActualArgs()), + numActArgsReg); + + + masm.moveValue(UndefinedValue(), ValueOperand(t0)); + + masm.movePtr(StackPointer, t2); // Save %sp. + + // Push undefined. (including the padding) + { + Label undefLoopTop; + + masm.bind(&undefLoopTop); + masm.sub32(Imm32(1), t1); + masm.subPtr(Imm32(sizeof(Value)), StackPointer); + masm.storeValue(ValueOperand(t0), Address(StackPointer, 0)); + + masm.ma_b(t1, t1, &undefLoopTop, Assembler::NonZero, ShortJump); + } + + // Get the topmost argument. + static_assert(sizeof(Value) == 8, "TimesEight is used to skip arguments"); + + // | - sizeof(Value)| is used to put rcx such that we can read the last + // argument, and not the value which is after. + masm.as_slli_d(t0, s3, 3); // t0 <- nargs * 8 + masm.as_add_d(t1, t2, t0); // t1 <- t2(saved sp) + nargs * 8 + masm.addPtr(Imm32(sizeof(RectifierFrameLayout) - sizeof(Value)), t1); + + // Copy & Push arguments, |nargs| + 1 times (to include |this|). + { + Label copyLoopTop; + + masm.bind(©LoopTop); + masm.sub32(Imm32(1), s3); + masm.subPtr(Imm32(sizeof(Value)), StackPointer); + masm.loadValue(Address(t1, 0), ValueOperand(t0)); + masm.storeValue(ValueOperand(t0), Address(StackPointer, 0)); + masm.subPtr(Imm32(sizeof(Value)), t1); + + masm.ma_b(s3, s3, ©LoopTop, Assembler::NonZero, ShortJump); + } + + // if constructing, copy newTarget + { + Label notConstructing; + + masm.branchTest32(Assembler::Zero, calleeTokenReg, Imm32(CalleeToken_FunctionConstructing), + ¬Constructing); + + // thisFrame[numFormals] = prevFrame[argc] + ValueOperand newTarget(t0); + + // +1 for |this|. We want vp[argc], so don't subtract 1 + BaseIndex newTargetSrc(t2, numActArgsReg, TimesEight, sizeof(RectifierFrameLayout) + sizeof(Value)); + masm.loadValue(newTargetSrc, newTarget); + + // Again, 1 for |this| + BaseIndex newTargetDest(StackPointer, t3, TimesEight, sizeof(Value)); + masm.storeValue(newTarget, newTargetDest); + + masm.bind(¬Constructing); + } + + // Caller: + // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- t2 + // + // + // Rectifier frame: + // [undef] [undef] [undef] [arg2] [arg1] [this] <- sp [[argc] [callee] [descr] [raddr]] + + // Construct sizeDescriptor. + masm.subPtr(StackPointer, t2); + masm.makeFrameDescriptor(t2, JitFrame_Rectifier, JitFrameLayout::Size()); + + // Construct JitFrameLayout. + masm.subPtr(Imm32(3 * sizeof(uintptr_t)), StackPointer); + // Push actual arguments. + masm.storePtr(numActArgsReg, Address(StackPointer, 2 * sizeof(uintptr_t))); + // Push callee token. + masm.storePtr(calleeTokenReg, Address(StackPointer, sizeof(uintptr_t))); + // Push frame descriptor. + masm.storePtr(t2, Address(StackPointer, 0)); + + // Call the target function. + // Note that this code assumes the function is JITted. + masm.andPtr(Imm32(uint32_t(CalleeTokenMask)), calleeTokenReg); + masm.loadPtr(Address(calleeTokenReg, JSFunction::offsetOfNativeOrScript()), t1); + masm.loadBaselineOrIonRaw(t1, t1, nullptr); + uint32_t returnOffset = masm.callJitNoProfiler(t1); + + // Remove the rectifier frame. + // t2 <- descriptor with FrameType. + masm.loadPtr(Address(StackPointer, 0), t2); + masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), t2); // t2 <- descriptor. + + // Discard descriptor, calleeToken and number of actual arguments. + masm.addPtr(Imm32(3 * sizeof(uintptr_t)), StackPointer); + + // Discard pushed arguments. + masm.addPtr(t2, StackPointer); + masm.ret(); + Linker linker(masm); + AutoFlushICache afc("ArgumentsRectifier"); + JitCode* code = linker.newCode(cx, OTHER_CODE); + + if (returnAddrOut) + *returnAddrOut = (void*) (code->raw() + returnOffset); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(code, "ArgumentsRectifier"); +#endif + + return code; +} + +/* - When bailout is done via out of line code (lazy bailout). + * Frame size is stored in $ra (look at + * CodeGeneratorLOONGARCH64::generateOutOfLineCode()) and thunk code should save it + * on stack. Other difference is that members snapshotOffset_ and padding_ are + * pushed to the stack by CodeGeneratorLOONGARCH64::visitOutOfLineBailout(). Field + * frameClassId_ is forced to be NO_FRAME_SIZE_CLASS_ID + * (See: JitRuntime::generateBailoutHandler). + */ +static void +PushBailoutFrame(MacroAssembler& masm, Register spArg) +{ + // Push the frameSize_ stored in ra + // See: CodeGeneratorLOONGARCH64::generateOutOfLineCode() + masm.push(ra); + + // Push registers such that we can access them from [base + code]. + masm.PushRegsInMask(AllRegs); + + // Put pointer to BailoutStack as first argument to the Bailout() + masm.movePtr(StackPointer, spArg); +} + +static void +GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass) +{ + PushBailoutFrame(masm, a0); + + // Put pointer to BailoutInfo + static const uint32_t sizeOfBailoutInfo = sizeof(uintptr_t) * 2; + masm.subPtr(Imm32(sizeOfBailoutInfo), StackPointer); + masm.movePtr(StackPointer, a1); + + masm.setupAlignedABICall(); + masm.passABIArg(a0); + masm.passABIArg(a1); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout)); + + // Get BailoutInfo pointer + masm.loadPtr(Address(StackPointer, 0), a2); + + // Stack is: + // [frame] + // snapshotOffset + // frameSize + // [bailoutFrame] + // [bailoutInfo] + // + // Remove both the bailout frame and the topmost Ion frame's stack. + // Load frameSize from stack + masm.loadPtr(Address(StackPointer, + sizeOfBailoutInfo + BailoutStack::offsetOfFrameSize()), a1); + // Remove complete BailoutStack class and data after it + masm.addPtr(Imm32(sizeof(BailoutStack) + sizeOfBailoutInfo), StackPointer); + // Remove frame size srom stack + masm.addPtr(a1, StackPointer); + + // Jump to shared bailout tail. The BailoutInfo pointer has to be in a2. + JitCode* bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail(); + masm.branch(bailoutTail); +} + +JitCode* +JitRuntime::generateBailoutTable(JSContext* cx, uint32_t frameClass) +{ + MOZ_CRASH("LOONGARCH64 does not use bailout tables"); +} + +JitCode* +JitRuntime::generateBailoutHandler(JSContext* cx) +{ + MacroAssembler masm(cx); + GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID); + + Linker linker(masm); + AutoFlushICache afc("BailoutHandler"); + JitCode* code = linker.newCode(cx, OTHER_CODE); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(code, "BailoutHandler"); +#endif + + return code; +} + +JitCode* +JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f) +{ + MOZ_ASSERT(functionWrappers_); + MOZ_ASSERT(functionWrappers_->initialized()); + VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f); + if (p) + return p->value(); + + MacroAssembler masm(cx); + + AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask); + + static_assert((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0, + "Wrapper register set should be a superset of Volatile register set."); + + // The context is the first argument; a0 is the first argument register. + Register cxreg = a0; + regs.take(cxreg); + + // Non-tail calls keep the return address in |ra|, while tail-call sites + // have already materialized a CommonFrameLayout on the stack. + if (f.expectTailCall == NonTailCall) + masm.pushReturnAddress(); + + // We're aligned to an exit frame, so link it up. + masm.enterExitFrame(&f); + masm.loadJSContext(cxreg); + + // Save the base of the argument set stored on the stack. + Register argsBase = InvalidReg; + if (f.explicitArgs) { + argsBase = t1; // Use temporary register. + regs.take(argsBase); + masm.ma_add_d(argsBase, StackPointer, Imm32(ExitFrameLayout::SizeWithFooter())); + } + + // Reserve space for the outparameter. + Register outReg = InvalidReg; + switch (f.outParam) { + case Type_Value: + outReg = regs.takeAny(); + masm.reserveStack(sizeof(Value)); + masm.movePtr(StackPointer, outReg); + break; + + case Type_Handle: + outReg = regs.takeAny(); + masm.PushEmptyRooted(f.outParamRootType); + masm.movePtr(StackPointer, outReg); + break; + + case Type_Bool: + case Type_Int32: + outReg = regs.takeAny(); + // Reserve 4-byte space to make stack aligned to 8-byte. + masm.reserveStack(2 * sizeof(int32_t)); + masm.movePtr(StackPointer, outReg); + break; + + case Type_Pointer: + outReg = regs.takeAny(); + masm.reserveStack(sizeof(uintptr_t)); + masm.movePtr(StackPointer, outReg); + break; + + case Type_Double: + outReg = regs.takeAny(); + masm.reserveStack(sizeof(double)); + masm.movePtr(StackPointer, outReg); + break; + + default: + MOZ_ASSERT(f.outParam == Type_Void); + break; + } + + if (!generateTLEnterVM(cx, masm, f)) + return nullptr; + + masm.setupUnalignedABICall(regs.getAny()); + masm.passABIArg(cxreg); + + size_t argDisp = 0; + + // Copy any arguments. + for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) { + MoveOperand from; + switch (f.argProperties(explicitArg)) { + case VMFunction::WordByValue: + if (f.argPassedInFloatReg(explicitArg)) + masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE); + else + masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL); + argDisp += sizeof(void*); + break; + case VMFunction::WordByRef: + masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS), + MoveOp::GENERAL); + argDisp += sizeof(void*); + break; + case VMFunction::DoubleByValue: + case VMFunction::DoubleByRef: + MOZ_CRASH("NYI: LOONGARCH64 callVM should not be used with 128bits values."); + break; + } + } + + // Copy the implicit outparam, if any. + if (InvalidReg != outReg) + masm.passABIArg(outReg); + + masm.callWithABI(f.wrapped); + + if (!generateTLExitVM(cx, masm, f)) + return nullptr; + + // Test for failure. + switch (f.failType()) { + case Type_Object: + masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, masm.failureLabel()); + break; + case Type_Bool: + // Called functions return bools, which are 0/false and non-zero/true + masm.branchIfFalseBool(ReturnReg, masm.failureLabel()); + break; + default: + MOZ_CRASH("unknown failure kind"); + } + + // Load the outparam and free any allocated stack. + switch (f.outParam) { + case Type_Handle: + masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand); + break; + + case Type_Value: + masm.loadValue(Address(StackPointer, 0), JSReturnOperand); + masm.freeStack(sizeof(Value)); + break; + + case Type_Int32: + masm.load32(Address(StackPointer, 0), ReturnReg); + masm.freeStack(2 * sizeof(int32_t)); + break; + + case Type_Pointer: + masm.loadPtr(Address(StackPointer, 0), ReturnReg); + masm.freeStack(sizeof(uintptr_t)); + break; + + case Type_Bool: + masm.load8ZeroExtend(Address(StackPointer, 0), ReturnReg); + masm.freeStack(2 * sizeof(int32_t)); + break; + + case Type_Double: + if (cx->runtime()->jitSupportsFloatingPoint) { + masm.loadDouble(Address(StackPointer, 0), ReturnDoubleReg); + } else { + masm.assumeUnreachable("Unable to load into float reg, with no FP support."); + } + masm.freeStack(sizeof(double)); + break; + + default: + MOZ_ASSERT(f.outParam == Type_Void); + break; + } + + masm.leaveExitFrame(); + masm.retn(Imm32(sizeof(ExitFrameLayout) + + f.explicitStackSlots() * sizeof(void*) + + f.extraValuesToPop * sizeof(Value))); + + Linker linker(masm); + AutoFlushICache afc("VMWrapper"); + JitCode* wrapper = linker.newCode(cx, OTHER_CODE); + if (!wrapper) + return nullptr; + + // linker.newCode may trigger a GC and sweep functionWrappers_ so we have + // to use relookupOrAdd instead of add. + if (!functionWrappers_->relookupOrAdd(p, &f, wrapper)) + return nullptr; + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(wrapper, "VMWrapper"); +#endif + + return wrapper; +} + +JitCode* +JitRuntime::generatePreBarrier(JSContext* cx, MIRType type) +{ + MacroAssembler masm(cx); + + LiveRegisterSet save; + if (cx->runtime()->jitSupportsFloatingPoint) { + save.set() = RegisterSet(GeneralRegisterSet(Registers::VolatileMask), + FloatRegisterSet(FloatRegisters::VolatileMask)); + } else { + save.set() = RegisterSet(GeneralRegisterSet(Registers::VolatileMask), + FloatRegisterSet()); + } + save.add(ra); + masm.PushRegsInMask(save); + + MOZ_ASSERT(PreBarrierReg == a1); + masm.movePtr(ImmPtr(cx->runtime()), a0); + + masm.setupUnalignedABICall(a2); + masm.passABIArg(a0); + masm.passABIArg(a1); + masm.callWithABI(IonMarkFunction(type)); + + masm.PopRegsInMask(save); + masm.abiret(); + + Linker linker(masm); + AutoFlushICache afc("PreBarrier"); + JitCode* code = linker.newCode(cx, OTHER_CODE); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(code, "PreBarrier"); +#endif + + return code; +} + +typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*); +static const VMFunction HandleDebugTrapInfo = + FunctionInfo(HandleDebugTrap, "HandleDebugTrap"); + +JitCode* +JitRuntime::generateDebugTrapHandler(JSContext* cx) +{ + MacroAssembler masm(cx); + + Register scratch1 = t0; + Register scratch2 = t1; + + // Enter a stub frame and call the HandleDebugTrap VM function. Ensure + // the stub frame has a nullptr ICStub pointer, since this pointer is + // marked during GC. + masm.movePtr(ImmPtr(nullptr), ICStubReg); + EmitBaselineEnterStubFrame(masm, scratch2); + + JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo); + if (!code) + return nullptr; + + // Reload the caller's BaselineFrame pointer from the stub frame before + // reserving VM arguments. This avoids relying on a volatile scratch + // register across stub-frame setup. + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedFrame)), + scratch1); + masm.subPtr(Imm32(BaselineFrame::Size()), scratch1); + + masm.subPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer); + masm.storePtr(ra, Address(StackPointer, sizeof(uintptr_t))); + masm.storePtr(scratch1, Address(StackPointer, 0)); + + EmitBaselineCallVM(code, masm); + + EmitBaselineLeaveStubFrame(masm); + + // If the stub returns |true|, we have to perform a forced return + // (return from the JS frame). If the stub returns |false|, just return + // from the trap stub so that execution continues at the current pc. + Label forcedReturn; + masm.branchTest32(Assembler::NonZero, ReturnReg, ReturnReg, &forcedReturn); + + // ra was restored by EmitLeaveStubFrame + masm.branch(ra); + + masm.bind(&forcedReturn); + masm.loadValue(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue()), + JSReturnOperand); + masm.movePtr(BaselineFrameReg, StackPointer); + masm.pop(BaselineFrameReg); + + // Before returning, if profiling is turned on, make sure that lastProfilingFrame + // is set to the correct caller frame. + { + Label skipProfilingInstrumentation; + AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled()); + masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation); + masm.profilerExitFrame(); + masm.bind(&skipProfilingInstrumentation); + } + + masm.ret(); + + Linker linker(masm); + AutoFlushICache afc("DebugTrapHandler"); + JitCode* codeDbg = linker.newCode(cx, OTHER_CODE); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(codeDbg, "DebugTrapHandler"); +#endif + + return codeDbg; +} + + +JitCode* +JitRuntime::generateExceptionTailStub(JSContext* cx, void* handler) +{ + MacroAssembler masm; + + masm.handleFailureWithHandlerTail(handler); + + Linker linker(masm); + AutoFlushICache afc("ExceptionTailStub"); + JitCode* code = linker.newCode(cx, OTHER_CODE); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(code, "ExceptionTailStub"); +#endif + + return code; +} + +JitCode* +JitRuntime::generateBailoutTailStub(JSContext* cx) +{ + MacroAssembler masm; + + masm.generateBailoutTail(a1, a2); + + Linker linker(masm); + AutoFlushICache afc("BailoutTailStub"); + JitCode* code = linker.newCode(cx, OTHER_CODE); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(code, "BailoutTailStub"); +#endif + + return code; +} + +JitCode* +JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) +{ + MacroAssembler masm; + + Register scratch1 = t0; + Register scratch2 = t1; + Register scratch3 = t2; + Register scratch4 = t3; + + // + // The code generated below expects that the current stack pointer points + // to an Ion or Baseline frame, at the state it would be immediately + // before a ret(). Thus, after this stub's business is done, it executes + // a ret() and returns directly to the caller script, on behalf of the + // callee script that jumped to this code. + // + // Thus the expected stack is: + // + // StackPointer ----+ + // v + // ..., ActualArgc, CalleeToken, Descriptor, ReturnAddr + // MEM-HI MEM-LOW + // + // + // The generated jitcode is responsible for overwriting the + // jitActivation->lastProfilingFrame field with a pointer to the previous + // Ion or Baseline jit-frame that was pushed before this one. It is also + // responsible for overwriting jitActivation->lastProfilingCallSite with + // the return address into that frame. The frame could either be an + // immediate "caller" frame, or it could be a frame in a previous + // JitActivation (if the current frame was entered from C++, and the C++ + // was entered by some caller jit-frame further down the stack). + // + // So this jitcode is responsible for "walking up" the jit stack, finding + // the previous Ion or Baseline JS frame, and storing its address and the + // return address into the appropriate fields on the current jitActivation. + // + // There are a fixed number of different path types that can lead to the + // current frame, which is either a baseline or ion frame: + // + // + // ^ + // | + // ^--- Ion + // | + // ^--- Baseline Stub <---- Baseline + // | + // ^--- Argument Rectifier + // | ^ + // | | + // | ^--- Ion + // | | + // | ^--- Baseline Stub <---- Baseline + // | + // ^--- Entry Frame (From C++) + // + Register actReg = scratch4; + AbsoluteAddress activationAddr(GetJitContext()->runtime->addressOfProfilingActivation()); + masm.loadPtr(activationAddr, actReg); + + Address lastProfilingFrame(actReg, JitActivation::offsetOfLastProfilingFrame()); + Address lastProfilingCallSite(actReg, JitActivation::offsetOfLastProfilingCallSite()); + +#ifdef DEBUG + // Ensure that frame we are exiting is current lastProfilingFrame + { + masm.loadPtr(lastProfilingFrame, scratch1); + Label checkOk; + masm.branchPtr(Assembler::Equal, scratch1, ImmWord(0), &checkOk); + masm.branchPtr(Assembler::Equal, StackPointer, scratch1, &checkOk); + masm.assumeUnreachable( + "Mismatch between stored lastProfilingFrame and current stack pointer."); + masm.bind(&checkOk); + } +#endif + + // Load the frame descriptor into |scratch1|, figure out what to do depending on its type. + masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfDescriptor()), scratch1); + + // Going into the conditionals, we will have: + // FrameDescriptor.size in scratch1 + // FrameDescriptor.type in scratch2 + masm.ma_and(scratch2, scratch1, Imm32((1 << FRAMETYPE_BITS) - 1)); + masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch1); + + // Handling of each case is dependent on FrameDescriptor.type + Label handle_IonJS; + Label handle_BaselineStub; + Label handle_Rectifier; + Label handle_IonAccessorIC; + Label handle_Entry; + Label end; + + masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonJS), &handle_IonJS); + masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS); + masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub); + masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier); + masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonAccessorIC), &handle_IonAccessorIC); + masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry); + + masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame."); + + // + // JitFrame_IonJS + // + // Stack layout: + // ... + // Ion-Descriptor + // Prev-FP ---> Ion-ReturnAddr + // ... previous frame data ... |- Descriptor.Size + // ... arguments ... | + // ActualArgc | + // CalleeToken |- JitFrameLayout::Size() + // Descriptor | + // FP -----> ReturnAddr | + // + masm.bind(&handle_IonJS); + { + // |scratch1| contains Descriptor.size + + // returning directly to an IonJS frame. Store return addr to frame + // in lastProfilingCallSite. + masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfReturnAddress()), scratch2); + masm.storePtr(scratch2, lastProfilingCallSite); + + // Store return frame in lastProfilingFrame. + // scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size(); + masm.as_add_d(scratch2, StackPointer, scratch1); + masm.ma_add_d(scratch2, scratch2, Imm32(JitFrameLayout::Size())); + masm.storePtr(scratch2, lastProfilingFrame); + masm.ret(); + } + + // + // JitFrame_BaselineStub + // + // Look past the stub and store the frame pointer to + // the baselineJS frame prior to it. + // + // Stack layout: + // ... + // BL-Descriptor + // Prev-FP ---> BL-ReturnAddr + // +-----> BL-PrevFramePointer + // | ... BL-FrameData ... + // | BLStub-Descriptor + // | BLStub-ReturnAddr + // | BLStub-StubPointer | + // +------ BLStub-SavedFramePointer |- Descriptor.Size + // ... arguments ... | + // ActualArgc | + // CalleeToken |- JitFrameLayout::Size() + // Descriptor | + // FP -----> ReturnAddr | + // + // We take advantage of the fact that the stub frame saves the frame + // pointer pointing to the baseline frame, so a bunch of calculation can + // be avoided. + // + masm.bind(&handle_BaselineStub); + { + masm.as_add_d(scratch3, StackPointer, scratch1); + Address stubFrameReturnAddr(scratch3, + JitFrameLayout::Size() + + BaselineStubFrameLayout::offsetOfReturnAddress()); + masm.loadPtr(stubFrameReturnAddr, scratch2); + masm.storePtr(scratch2, lastProfilingCallSite); + + Address stubFrameSavedFramePtr(scratch3, + JitFrameLayout::Size() - (2 * sizeof(void*))); + masm.loadPtr(stubFrameSavedFramePtr, scratch2); + masm.addPtr(Imm32(sizeof(void*)), scratch2); // Skip past BL-PrevFramePtr + masm.storePtr(scratch2, lastProfilingFrame); + masm.ret(); + } + + + // + // JitFrame_Rectifier + // + // The rectifier frame can be preceded by either an IonJS or a + // BaselineStub frame. + // + // Stack layout if caller of rectifier was Ion: + // + // Ion-Descriptor + // Ion-ReturnAddr + // ... ion frame data ... |- Rect-Descriptor.Size + // < COMMON LAYOUT > + // + // Stack layout if caller of rectifier was Baseline: + // + // BL-Descriptor + // Prev-FP ---> BL-ReturnAddr + // +-----> BL-SavedFramePointer + // | ... baseline frame data ... + // | BLStub-Descriptor + // | BLStub-ReturnAddr + // | BLStub-StubPointer | + // +------ BLStub-SavedFramePointer |- Rect-Descriptor.Size + // ... args to rectifier ... | + // < COMMON LAYOUT > + // + // Common stack layout: + // + // ActualArgc | + // CalleeToken |- IonRectitiferFrameLayout::Size() + // Rect-Descriptor | + // Rect-ReturnAddr | + // ... rectifier data & args ... |- Descriptor.Size + // ActualArgc | + // CalleeToken |- JitFrameLayout::Size() + // Descriptor | + // FP -----> ReturnAddr | + // + masm.bind(&handle_Rectifier); + { + // scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size(); + masm.as_add_d(scratch2, StackPointer, scratch1); + masm.addPtr(Imm32(JitFrameLayout::Size()), scratch2); + masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfDescriptor()), scratch3); + masm.as_srli_d(scratch1, scratch3, FRAMESIZE_SHIFT); + masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch3); + + // Now |scratch1| contains Rect-Descriptor.Size + // and |scratch2| points to Rectifier frame + // and |scratch3| contains Rect-Descriptor.Type + + // Check for either Ion or BaselineStub frame. + Label handle_Rectifier_BaselineStub; + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), + &handle_Rectifier_BaselineStub); + + // Handle Rectifier <- IonJS + // scratch3 := RectFrame[ReturnAddr] + masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfReturnAddress()), scratch3); + masm.storePtr(scratch3, lastProfilingCallSite); + + // scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size() + masm.as_add_d(scratch3, scratch2, scratch1); + masm.addPtr(Imm32(RectifierFrameLayout::Size()), scratch3); + masm.storePtr(scratch3, lastProfilingFrame); + masm.ret(); + + // Handle Rectifier <- BaselineStub <- BaselineJS + masm.bind(&handle_Rectifier_BaselineStub); +#ifdef DEBUG + { + Label checkOk; + masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk); + masm.assumeUnreachable("Unrecognized frame preceding baselineStub."); + masm.bind(&checkOk); + } +#endif + masm.as_add_d(scratch3, scratch2, scratch1); + Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + + BaselineStubFrameLayout::offsetOfReturnAddress()); + masm.loadPtr(stubFrameReturnAddr, scratch2); + masm.storePtr(scratch2, lastProfilingCallSite); + + Address stubFrameSavedFramePtr(scratch3, + RectifierFrameLayout::Size() - (2 * sizeof(void*))); + masm.loadPtr(stubFrameSavedFramePtr, scratch2); + masm.addPtr(Imm32(sizeof(void*)), scratch2); + masm.storePtr(scratch2, lastProfilingFrame); + masm.ret(); + } + + // JitFrame_IonAccessorIC + // + // The caller is always an IonJS frame. + // + // Ion-Descriptor + // Ion-ReturnAddr + // ... ion frame data ... |- AccFrame-Descriptor.Size + // StubCode | + // AccFrame-Descriptor |- IonAccessorICFrameLayout::Size() + // AccFrame-ReturnAddr | + // ... accessor frame data & args ... |- Descriptor.Size + // ActualArgc | + // CalleeToken |- JitFrameLayout::Size() + // Descriptor | + // FP -----> ReturnAddr | + masm.bind(&handle_IonAccessorIC); + { + // scratch2 := StackPointer + Descriptor.size + JitFrameLayout::Size() + masm.as_add_d(scratch2, StackPointer, scratch1); + masm.addPtr(Imm32(JitFrameLayout::Size()), scratch2); + + // scratch3 := AccFrame-Descriptor.Size + masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfDescriptor()), scratch3); +#ifdef DEBUG + // Assert previous frame is an IonJS frame. + masm.movePtr(scratch3, scratch1); + masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch1); + { + Label checkOk; + masm.branch32(Assembler::Equal, scratch1, Imm32(JitFrame_IonJS), &checkOk); + masm.assumeUnreachable("IonAccessorIC frame must be preceded by IonJS frame"); + masm.bind(&checkOk); + } +#endif + masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch3); + + // lastProfilingCallSite := AccFrame-ReturnAddr + masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfReturnAddress()), scratch1); + masm.storePtr(scratch1, lastProfilingCallSite); + + // lastProfilingFrame := AccessorFrame + AccFrame-Descriptor.Size + + // IonAccessorICFrameLayout::Size() + masm.as_add_d(scratch1, scratch2, scratch3); + masm.addPtr(Imm32(IonAccessorICFrameLayout::Size()), scratch1); + masm.storePtr(scratch1, lastProfilingFrame); + masm.ret(); + } + + // + // JitFrame_Entry + // + // If at an entry frame, store null into both fields. + // + masm.bind(&handle_Entry); + { + masm.movePtr(ImmPtr(nullptr), scratch1); + masm.storePtr(scratch1, lastProfilingCallSite); + masm.storePtr(scratch1, lastProfilingFrame); + masm.ret(); + } + + Linker linker(masm); + AutoFlushICache afc("ProfilerExitFrameTailStub"); + JitCode* code = linker.newCode(cx, OTHER_CODE); + +#ifdef JS_ION_PERF + writePerfSpewerJitCodeProfile(code, "ProfilerExitFrameStub"); +#endif + + return code; +} diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 308d9f1a12..61185b3835 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -17,7 +17,8 @@ #include "wasm/WasmTypes.h" #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ - defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) + defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) // Push return addresses callee-side. # define JS_USE_LINK_REGISTER #endif diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 0d5b10bfeb..78f66bb9da 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -1620,7 +1620,8 @@ CodeGeneratorShared::getJumpLabelForBranch(MBasicBlock* block) } // This function is not used for MIPS/MIPS64. MIPS has branchToBlock. -#if !defined(JS_CODEGEN_MIPS32) && !defined(JS_CODEGEN_MIPS64) +#if !defined(JS_CODEGEN_MIPS32) && !defined(JS_CODEGEN_MIPS64) && \ + !defined(JS_CODEGEN_LOONGARCH64) void CodeGeneratorShared::jumpToBlock(MBasicBlock* mir, Assembler::Condition cond) { diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index 0cc10b567d..c4245614cf 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -27,6 +27,19 @@ class OutOfLineCode; class CodeGenerator; class MacroAssembler; class IonCache; +class LSimdSplatX4; +class LSimd128Int; +class LSimd128Float; +class LSimdReinterpretCast; +class LSimdExtractElementI; +class LSimdExtractElementF; +class LSimdBinaryCompIx4; +class LSimdBinaryCompFx4; +class LSimdBinaryArithIx4; +class LSimdBinaryArithFx4; +class LSimdBinaryBitwise; +class LSimdGeneralShuffleI; +class LSimdGeneralShuffleF; template class OutOfLineCallVM; diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index 75869595b5..95e315614e 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -301,7 +301,7 @@ LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefini #elif defined(JS_CODEGEN_ARM64) lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegisters::Double)))); -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(f2))); #elif defined(JS_CODEGEN_NONE) MOZ_CRASH(); diff --git a/js/src/js.msg b/js/src/js.msg index 499e7a1623..c635bb54ed 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -548,6 +548,8 @@ MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array") // Typed array MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") +MSG_DEF(JSMSG_ARRAYBUFFER_NOT_RESIZABLE, 0, JSEXN_TYPEERR, "ArrayBuffer is not resizable") +MSG_DEF(JSMSG_ARRAYBUFFER_CANNOT_DETACH, 0, JSEXN_TYPEERR, "ArrayBuffer cannot be detached") MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer") MSG_DEF(JSMSG_SAME_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different ArrayBuffer, but species constructor returned same ArrayBuffer") MSG_DEF(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected ArrayBuffer with at least {0} bytes, but species constructor returns ArrayBuffer with {1} bytes") @@ -555,12 +557,15 @@ MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_RANGEERR, "argument {0} must be >= 0") MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer") MSG_DEF(JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS, 0, JSEXN_RANGEERR, "attempting to construct out-of-bounds TypedArray on ArrayBuffer") +MSG_DEF(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS, 0, JSEXN_TYPEERR, "attempting to access out-of-bounds TypedArray") +MSG_DEF(JSMSG_DATA_VIEW_OUT_OF_BOUNDS, 0, JSEXN_TYPEERR, "attempting to access out-of-bounds DataView") MSG_DEF(JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT, 1, JSEXN_TYPEERR, "cannot directly {0} builtin %TypedArray%") MSG_DEF(JSMSG_NON_TYPED_ARRAY_RETURNED, 0, JSEXN_TYPEERR, "constructor didn't return TypedArray object") MSG_DEF(JSMSG_SHORT_TYPED_ARRAY_RETURNED, 2, JSEXN_TYPEERR, "expected TypedArray of at least length {0}, but constructor returned TypedArray of length {1}") // Shared array buffer MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH, 0, JSEXN_RANGEERR, "length argument out of range") +MSG_DEF(JSMSG_SHARED_ARRAY_NOT_GROWABLE, 0, JSEXN_TYPEERR, "SharedArrayBuffer is not growable") MSG_DEF(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected SharedArrayBuffer, but species constructor returned non-SharedArrayBuffer") MSG_DEF(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different SharedArrayBuffer, but species constructor returned same SharedArrayBuffer") MSG_DEF(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected SharedArrayBuffer with at least {0} bytes, but species constructor returns SharedArrayBuffer with {1} bytes") diff --git a/js/src/jsapi-tests/testIndexToString.cpp b/js/src/jsapi-tests/testIndexToString.cpp index 0c91d98873..58c854054b 100644 --- a/js/src/jsapi-tests/testIndexToString.cpp +++ b/js/src/jsapi-tests/testIndexToString.cpp @@ -66,6 +66,56 @@ BEGIN_TEST(testIndexToString) } END_TEST(testIndexToString) +BEGIN_TEST(testDtoaCacheInterleaved) +{ + JS::RootedString first(cx, js::NumberToString(cx, 1234.5)); + CHECK(first); + JS::RootedString second(cx, js::NumberToString(cx, 6789.5)); + CHECK(second); + JS::RootedString third(cx, js::IndexToString(cx, 123456)); + CHECK(third); + JS::RootedString fourth(cx, js::IndexToString(cx, 654321)); + CHECK(fourth); + + for (size_t i = 0; i < 10; i++) { + CHECK(js::NumberToString(cx, 1234.5) == first); + CHECK(js::NumberToString(cx, 6789.5) == second); + CHECK(js::IndexToString(cx, 123456) == third); + CHECK(js::IndexToString(cx, 654321) == fourth); + } + + // Every raw string pointer must be invalidated, not just the latest one. + JS_GC(cx); + CHECK(!cx->compartment()->dtoaCache.lookup(10, 1234.5)); + CHECK(!cx->compartment()->dtoaCache.lookup(10, 6789.5)); + CHECK(!cx->compartment()->dtoaCache.lookup(10, 123456)); + CHECK(!cx->compartment()->dtoaCache.lookup(10, 654321)); + + // The radix is part of the key. Signed zero can share its string. + js::DtoaCache cache; + cache.cache(10, 0.0, &first->asFlat()); + cache.cache(16, 0.0, &second->asFlat()); + CHECK(cache.lookup(10, -0.0) == first); + CHECK(cache.lookup(16, -0.0) == second); + CHECK(!cache.lookup(2, 0.0)); + cache.purge(); + CHECK(!cache.lookup(10, 0.0)); + CHECK(!cache.lookup(16, 0.0)); + + for (size_t i = 0; i < 12; i++) + cache.cache(10, double(i), &first->asFlat()); + for (size_t i = 0; i < 8; i++) + CHECK(!cache.lookup(10, double(i))); + for (size_t i = 8; i < 12; i++) + CHECK(cache.lookup(10, double(i)) == first); + + // A failed string allocation must never turn into a cache hit. + cache.cache(10, 12.0, nullptr); + CHECK(!cache.lookup(10, 12.0)); + return true; +} +END_TEST(testDtoaCacheInterleaved) + BEGIN_TEST(testStringIsIndex) { for (size_t i = 0, sz = ArrayLength(tests); i < sz; i++) { diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f1627e481e..3ea147eaff 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -951,6 +951,20 @@ LookupStdName(const JSAtomState& names, JSAtom* name, const JSStdName* table) return nullptr; } +static bool +IsStreamExtraName(JSFlatString* name) +{ + return JS_FlatStringEqualsAscii(name, "WritableStream") || + JS_FlatStringEqualsAscii(name, "WritableStreamDefaultWriter") || + JS_FlatStringEqualsAscii(name, "WritableStreamDefaultController") || + JS_FlatStringEqualsAscii(name, "TransformStream") || + JS_FlatStringEqualsAscii(name, "TransformStreamDefaultController") || + JS_FlatStringEqualsAscii(name, "TextEncoderStream") || + JS_FlatStringEqualsAscii(name, "TextDecoderStream") || + JS_FlatStringEqualsAscii(name, "CompressionStream") || + JS_FlatStringEqualsAscii(name, "DecompressionStream"); +} + /* * Table of standard classes, indexed by JSProtoKey. For entries where the * JSProtoKey does not correspond to a class with a meaningful constructor, we @@ -1041,11 +1055,27 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso if (!GlobalObject::ensureConstructor(cx, global, key)) return false; + if (key == JSProto_ReadableStream) { + RootedObject globalObj(cx, global); + if (!InitStreamExtras(cx, globalObj)) + return false; + } + *resolved = true; return true; } } + if (cx->options().streams() && IsStreamExtraName(idAtom)) { + RootedObject globalObj(cx, global); + if (!InitStreamExtras(cx, globalObj)) + return false; + + if (!HasOwnProperty(cx, globalObj, id, resolved)) + return false; + return true; + } + // There is no such property to resolve. An ordinary resolve hook would // just return true at this point. But the global object is special in one // more way: its prototype chain is lazily initialized. That is, @@ -1075,6 +1105,7 @@ JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj return atom == names.undefined || atom == names.globalThis || + IsStreamExtraName(atom) || LookupStdName(names, atom, standard_class_names) || LookupStdName(names, atom, builtin_property_names); } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index cae2297ae4..7744bdd592 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -998,7 +998,9 @@ class JS_PUBLIC_API(ContextOptions) { werror_(false), strictMode_(false), extraWarnings_(false), - arrayProtoValues_(true) + arrayProtoValues_(true), + streams_(true), + weakRefs_(false) { } @@ -1138,6 +1140,16 @@ class JS_PUBLIC_API(ContextOptions) { return *this; } + bool weakRefs() const { return weakRefs_; } + ContextOptions& setWeakRefs(bool flag) { + weakRefs_ = flag; + return *this; + } + ContextOptions& toggleWeakRefs() { + weakRefs_ = !weakRefs_; + return *this; + } + private: bool baseline_ : 1; bool ion_ : 1; @@ -1155,6 +1167,7 @@ class JS_PUBLIC_API(ContextOptions) { bool extraWarnings_ : 1; bool arrayProtoValues_ : 1; bool streams_ : 1; + bool weakRefs_ : 1; }; JS_PUBLIC_API(ContextOptions&) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7fa01b93a4..15cb23a213 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1221,7 +1221,12 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp) sepstr = cx->names().comma; } - // Step 6 is implicit in the loops below. + // Step 6: empty arrays always join to the empty string. + // (Separator ToString above still runs for side effects / OOM.) + if (length == 0) { + args.rval().setString(cx->names().empty); + return true; + } // An optimized version of a special case of steps 7-11: when length==1 and // the 0th element is a string, ToString() of that element is a no-op and @@ -1381,8 +1386,8 @@ template DenseElementResult ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) { - /* An empty array or an array with no elements is already reversed. */ - if (length == 0 || GetBoxedOrUnboxedInitializedLength(obj) == 0) + /* Empty, singleton, or uninitialized arrays are already reversed. */ + if (length <= 1 || GetBoxedOrUnboxedInitializedLength(obj) == 0) return DenseElementResult::Success; if (Type == JSVAL_TYPE_MAGIC) { @@ -1451,6 +1456,12 @@ js::array_reverse(JSContext* cx, unsigned argc, Value* vp) if (!GetLengthProperty(cx, obj, &len)) return false; + // length 0/1: reverse is a no-op; return this immediately. + if (len <= 1) { + args.rval().setObject(*obj); + return true; + } + if (!ObjectMayHaveExtraIndexedProperties(obj)) { ArrayReverseDenseKernelFunctor functor(cx, obj, len); DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj); @@ -3216,6 +3227,7 @@ static const JSFunctionSpec array_methods[] = { /* ES2023 proposals */ JS_SELF_HOSTED_FN("findLast", "ArrayFindLast", 1,0), JS_SELF_HOSTED_FN("findLastIndex", "ArrayFindLastIndex", 1,0), + JS_SELF_HOSTED_FN("toSorted", "ArrayToSorted", 1,0), JS_FS_END }; @@ -3390,7 +3402,8 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto) !DefineProperty(cx, unscopables, cx->names().flatMap, value) || !DefineProperty(cx, unscopables, cx->names().includes, value) || !DefineProperty(cx, unscopables, cx->names().keys, value) || - !DefineProperty(cx, unscopables, cx->names().values, value)) + !DefineProperty(cx, unscopables, cx->names().values, value) || + !DefineProperty(cx, unscopables, cx->names().toSorted, value)) { return false; } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 926c7e3c86..6778dd2ebe 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -214,7 +214,9 @@ JSCompartment::ensureJitCompartmentExists(JSContext* cx) void js::DtoaCache::checkCacheAfterMovingGC() { - MOZ_ASSERT(!s || !IsForwarded(s)); + MOZ_ASSERT(!recent.s || !IsForwarded(recent.s)); + for (const auto& entry : previous) + MOZ_ASSERT(!entry.s || !IsForwarded(entry.s)); } namespace { diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index a02b39301d..dd356aa41a 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -38,29 +38,47 @@ class ScriptSourceObject; struct NativeIterator; /* - * A single-entry cache for some base-10 double-to-string conversions. This - * helps date-format-xparb.js. It also avoids skewing the results for - * v8-splay.js when measured by the SunSpider harness, where the splay tree - * initialization (which includes many repeated double-to-string conversions) - * is erroneously included in the measurement; see bug 562553. + * A small cache for number-to-string conversions, keyed by number and radix. + * Keep several results so interleaved conversions do not evict each other. + * These strings are not traced: every entry must be cleared before GC. */ class DtoaCache { - double d; - int base; - JSFlatString* s; // if s==nullptr, d and base are not valid + struct Entry { + double d; + int base; + JSFlatString* s; // if s == nullptr, d and base are not valid + }; + static const size_t NumPrevious = 3; + Entry recent; + Entry previous[NumPrevious]; + size_t next; public: - DtoaCache() : s(nullptr) {} - void purge() { s = nullptr; } + DtoaCache() { purge(); } + void purge() { + recent.s = nullptr; + for (auto& entry : previous) + entry.s = nullptr; + next = 0; + } JSFlatString* lookup(int base, double d) { - return this->s && base == this->base && d == this->d ? this->s : nullptr; + // Preserve the cheap path for consecutive conversions of one value. + if (recent.s && base == recent.base && d == recent.d) + return recent.s; + for (const auto& entry : previous) { + if (entry.s && base == entry.base && d == entry.d) + return entry.s; + } + return nullptr; } void cache(int base, double d, JSFlatString* s) { - this->base = base; - this->d = d; - this->s = s; + if (recent.s) { + previous[next] = recent; + next = (next + 1) % NumPrevious; + } + recent = { d, base, s }; } #ifdef JSGC_HASH_TABLE_CHECKS diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index c463019dac..2697cb5337 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1748,6 +1748,9 @@ JS_IsFloat64Array(JSObject* obj); extern JS_FRIEND_API(bool) JS_GetTypedArraySharedness(JSObject* obj); +extern JS_FRIEND_API(uint32_t) +JS_GetTypedArrayLength(JSObject* obj); + /* * Test for specific typed array types (ArrayBufferView subtypes) and return * the unwrapped object if so, else nullptr. Never throws. @@ -1814,8 +1817,7 @@ inline void \ Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \ { \ MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \ - const JS::Value& lenSlot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ - *length = mozilla::AssertedCast(lenSlot.toInt32()); \ + *length = JS_GetTypedArrayLength(obj); \ *isSharedMemory = JS_GetTypedArraySharedness(obj); \ *data = static_cast(GetObjectPrivate(obj)); \ } diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index 9822a47b6c..6005724f89 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -119,6 +119,7 @@ IF_SAB(real,imaginary)(Atomics, InitAtomicsClass, OCLASP(Atomics)) \ imaginary(WritableStreamDefaultController,dummy, dummy) \ real(ByteLengthQueuingStrategy, InitViaClassSpec, &js::ByteLengthQueuingStrategy::class_) \ real(CountQueuingStrategy, InitViaClassSpec, &js::CountQueuingStrategy::class_) \ + real(WeakRef, InitWeakRefClass, OCLASP(WeakRef)) \ #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index e2e6e55631..67de5d7236 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2061,6 +2061,17 @@ js::str_includes(JSContext* cx, unsigned argc, Value* vp) // Step 12 uint32_t start = Min(Max(pos, 0U), textLen); + uint32_t searchLen = searchStr->length(); + if (searchLen == 0) { + args.rval().setBoolean(true); + return true; + } + + if (searchLen > textLen - start) { + args.rval().setBoolean(false); + return true; + } + // Steps 13 and 14 JSLinearString* text = str->ensureLinear(cx); if (!text) @@ -2113,6 +2124,17 @@ js::str_indexOf(JSContext* cx, unsigned argc, Value* vp) // Step 9 uint32_t start = Min(Max(pos, 0U), textLen); + uint32_t searchLen = searchStr->length(); + if (searchLen == 0) { + args.rval().setInt32(start); + return true; + } + + if (searchLen > textLen - start) { + args.rval().setInt32(-1); + return true; + } + // Steps 10 and 11 JSLinearString* text = str->ensureLinear(cx); if (!text) @@ -2174,6 +2196,11 @@ js::str_lastIndexOf(JSContext* cx, unsigned argc, Value* vp) // Step 8. size_t searchLen = searchStr->length(); + if (searchLen > len) { + args.rval().setInt32(-1); + return true; + } + // Steps 4-5, 7. int start = len - searchLen; // Start searching here if (args.hasDefined(1)) { @@ -2197,11 +2224,6 @@ js::str_lastIndexOf(JSContext* cx, unsigned argc, Value* vp) } } - if (searchLen > len) { - args.rval().setInt32(-1); - return true; - } - if (searchLen == 0) { args.rval().setInt32(start); return true; @@ -2307,6 +2329,12 @@ js::str_startsWith(JSContext* cx, unsigned argc, Value* vp) // Step 13 uint32_t searchLen = searchStr->length(); + // Empty search string always matches (and is extremely common). + if (searchLen == 0) { + args.rval().setBoolean(true); + return true; + } + // Step 14 if (searchLen + start < searchLen || searchLen + start > textLen) { args.rval().setBoolean(false); @@ -2373,6 +2401,12 @@ js::str_endsWith(JSContext* cx, unsigned argc, Value* vp) // Step 13 uint32_t searchLen = searchStr->length(); + // Empty search string always matches. + if (searchLen == 0) { + args.rval().setBoolean(true); + return true; + } + // Step 15 (reordered) if (searchLen > end) { args.rval().setBoolean(false); @@ -3310,6 +3344,8 @@ static const JSFunctionSpec string_methods[] = { JS_SELF_HOSTED_FN("toLocaleUpperCase", "String_toLocaleUpperCase", 0,0), JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0), JS_SELF_HOSTED_FN("repeat", "String_repeat", 1,0), + JS_SELF_HOSTED_FN("isWellFormed", "String_isWellFormed", 0,0), + JS_SELF_HOSTED_FN("toWellFormed", "String_toWellFormed", 0,0), JS_FN("normalize", str_normalize, 0,0), /* Perl-ish methods (search is actually Python-esque). */ diff --git a/js/src/jsutil.h b/js/src/jsutil.h index 00c2806c1d..1969a2e823 100644 --- a/js/src/jsutil.h +++ b/js/src/jsutil.h @@ -443,7 +443,7 @@ PodSet(T* aDst, const T& aSrc, size_t aNElem) # define JS_SWEPT_CODE_PATTERN 0xED // IN instruction, crashes in user mode. #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) # define JS_SWEPT_CODE_PATTERN 0xA3 // undefined instruction -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64) # define JS_SWEPT_CODE_PATTERN 0x01 // undefined instruction #else # error "JS_SWEPT_CODE_PATTERN not defined for this platform" diff --git a/js/src/jsweakmap.h b/js/src/jsweakmap.h index c13baa7825..ec0fd8ddc6 100644 --- a/js/src/jsweakmap.h +++ b/js/src/jsweakmap.h @@ -16,11 +16,25 @@ #include "gc/Marking.h" #include "gc/StoreBuffer.h" #include "js/HashTable.h" +#include "vm/Symbol.h" namespace js { class WeakMapBase; +template <> +struct MovableCellHasher +{ + using Key = JS::Symbol*; + using Lookup = JS::Symbol*; + + static bool hasHash(const Lookup& l) { return true; } + static bool ensureHash(const Lookup& l) { return true; } + static HashNumber hash(const Lookup& l) { return l->hash(); } + static bool match(const Key& k, const Lookup& l) { return k == l; } + static void rekey(Key& k, const Key& newKey) { k = newKey; } +}; + // A subclass template of js::HashMap whose keys and values may be garbage-collected. When // a key is collected, the table entry disappears, dropping its reference to the value. // @@ -296,9 +310,16 @@ class WeakMap : public HashMap, return nullptr; } + JSObject* getDelegate(JS::Symbol* sym) const { + return nullptr; + } + private: void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); } void exposeGCThingToActiveJS(JSObject* obj) const { JS::ExposeObjectToActiveJS(obj); } + void exposeGCThingToActiveJS(JS::Symbol* sym) const { + gc::ExposeGCThingToActiveJS(JS::GCCellPtr(sym)); + } bool keyNeedsMark(JSObject* key) const { JSObject* delegate = getDelegate(key); @@ -313,6 +334,10 @@ class WeakMap : public HashMap, return false; } + bool keyNeedsMark(JS::Symbol* sym) const { + return false; + } + bool findZoneEdges() override { // This is overridden by ObjectValueMap. return true; @@ -378,6 +403,9 @@ WeakMap_set(JSContext* cx, unsigned argc, Value* vp); extern bool WeakMap_delete(JSContext* cx, unsigned argc, Value* vp); +extern bool +SetWeakMapEntryValue(JSContext* cx, HandleObject mapObj, HandleValue key, HandleValue val); + extern JSObject* InitWeakMapClass(JSContext* cx, HandleObject obj); @@ -394,6 +422,16 @@ class ObjectValueMap : public WeakMap, HeapPtr, virtual bool findZoneEdges(); }; +class SymbolValueMap : public WeakMap, HeapPtr, + MovableCellHasher>> +{ + public: + SymbolValueMap(JSContext* cx, JSObject* obj) + : WeakMap, HeapPtr, + MovableCellHasher>>(cx, obj) + {} +}; + // Generic weak map for mapping objects to other objects. class ObjectWeakMap diff --git a/js/src/moz.build b/js/src/moz.build index cf43ed2bbe..6672e41220 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -142,6 +142,7 @@ main_deunified_sources = [ 'builtin/TestingFunctions.cpp', 'builtin/TypedObject.cpp', 'builtin/WeakMapObject.cpp', + 'builtin/WeakRefObject.cpp', 'builtin/WeakSetObject.cpp', 'devtools/sharkctl.cpp', 'ds/LifoAlloc.cpp', @@ -325,7 +326,6 @@ main_deunified_sources = [ 'vm/Runtime.cpp', 'vm/SavedStacks.cpp', 'vm/Scope.cpp', - 'vm/SelfHosting.cpp', 'vm/Shape.cpp', 'vm/SharedArrayObject.cpp', 'vm/SharedImmutableStringsCache.cpp', @@ -400,8 +400,15 @@ SOURCES += [ 'jsutil.cpp', 'vm/BigIntType.cpp', 'vm/Initialization.cpp', + 'vm/SelfHosting.cpp', ] +if CONFIG['CC_TYPE'] == 'gcc': + SOURCES['vm/SelfHosting.cpp'].flags += ['-fopenmp'] + OS_LIBS += ['gomp'] + if CONFIG['OS_ARCH'] == 'WINNT': + OS_LIBS += ['dl'] + if CONFIG['JS_POSIX_NSPR']: posix_nspr_deunified_sources = [ 'vm/PosixNSPR.cpp', @@ -519,6 +526,29 @@ elif CONFIG['JS_CODEGEN_ARM64']: 'jit/arm64/vixl/MozSimulator-vixl.cpp', 'jit/arm64/vixl/Simulator-vixl.cpp' ] +elif CONFIG['JS_CODEGEN_LOONGARCH64']: + jit_ioncheck1_deunified_sources += [ + 'jit/mips-shared/Bailouts-mips-shared.cpp', + 'jit/mips-shared/BaselineCompiler-mips-shared.cpp', + 'jit/mips-shared/BaselineIC-mips-shared.cpp', + 'jit/mips-shared/CodeGenerator-mips-shared.cpp', + 'jit/mips-shared/Lowering-mips-shared.cpp', + 'jit/mips-shared/MoveEmitter-mips-shared.cpp', + ] + jit_ioncheck2_deunified_sources += [ + 'jit/loongarch64/Architecture-loongarch64.cpp', + 'jit/loongarch64/Assembler-loongarch64.cpp', + 'jit/loongarch64/Bailouts-loongarch64.cpp', + 'jit/loongarch64/BaselineCompiler-loongarch64.cpp', + 'jit/loongarch64/BaselineIC-loongarch64.cpp', + 'jit/loongarch64/CodeGenerator-loongarch64.cpp', + 'jit/loongarch64/Lowering-loongarch64.cpp', + 'jit/loongarch64/MacroAssembler-loongarch64.cpp', + 'jit/loongarch64/SharedIC-loongarch64.cpp', + 'jit/loongarch64/Trampoline-loongarch64.cpp', + 'jit/mips64/CodeGenerator-mips64.cpp', + 'jit/mips64/MoveEmitter-mips64.cpp', + ] elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: jit_ioncheck1_deunified_sources += [ 'jit/mips-shared/Architecture-mips-shared.cpp', @@ -755,5 +785,3 @@ selfhosted.inputs = [ # We are keeping this in the main moz.build because it is file specific if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']: SOURCES['jsdtoa.cpp'].flags += ['-Wno-implicit-fallthrough'] - - diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 7329fc470d..b046699f17 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -222,13 +222,6 @@ case "$target" in AC_SUBST(MSVC_CMP_RUNTIME_DLL) AC_SUBST(MSVC_CXX_RUNTIME_DLL) - # Check linker version - _LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` - _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'` - if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then - AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION, does not match the compiler suite version, $_CC_SUITE.]) - fi - INCREMENTAL_LINKER=1 unset _MSVC_VER_FILTER @@ -976,6 +969,10 @@ arm*-*) ENABLE_ION=1 AC_DEFINE(JS_CPU_ARM) ;; +loongarch64*-*) + ENABLE_ION=1 + AC_DEFINE(JS_CPU_LOONGARCH64) + ;; sparc-*) dnl ENABLE_ION=0 AC_DEFINE(JS_CPU_SPARC) @@ -1724,7 +1721,7 @@ if test -n "$JS_SIMULATOR"; then esac fi -if test -z "$ENABLE_ION"; then +if test -z "$ENABLE_ION" && test "$CPU_ARCH" != "loongarch64"; then AC_DEFINE(JS_CODEGEN_NONE) JS_CODEGEN_NONE=1 elif test "$JS_SIMULATOR" = arm; then @@ -1781,6 +1778,9 @@ elif test "$CPU_ARCH" = "arm"; then dnl ARM platforms may trap on unaligned accesses; catch the signal and dnl recover. +elif test "$CPU_ARCH" = "loongarch64"; then + AC_DEFINE(JS_CODEGEN_LOONGARCH64) + JS_CODEGEN_LOONGARCH64=1 elif test "$CPU_ARCH" = "mips" || test "$CPU_ARCH" = "mips32" || test "$CPU_ARCH" = "mips64"; then if test ! "$HAVE_64BIT_BUILD"; then AC_DEFINE(JS_CODEGEN_MIPS32) @@ -1798,6 +1798,7 @@ AC_SUBST(JS_SIMULATOR_MIPS32) AC_SUBST(JS_SIMULATOR_MIPS64) AC_SUBST(JS_CODEGEN_ARM) AC_SUBST(JS_CODEGEN_ARM64) +AC_SUBST(JS_CODEGEN_LOONGARCH64) AC_SUBST(JS_CODEGEN_MIPS32) AC_SUBST(JS_CODEGEN_MIPS64) AC_SUBST(JS_CODEGEN_X86) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index ed30afa7ef..8f075ce228 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3330,6 +3330,15 @@ static const JSClass sandbox_class = { &sandbox_classOps }; +enum GlobalAppSlot { + GlobalAppSlotModuleMetadataHook, + GlobalAppSlotModuleDynamicImportHook, + GlobalAppSlotCount +}; + +static_assert(GlobalAppSlotCount <= JSCLASS_GLOBAL_APPLICATION_SLOTS, + "global application slots overflow"); + static void SetStandardCompartmentOptions(JS::CompartmentOptions& options) { @@ -4158,7 +4167,7 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp) const char16_t* chars = stableChars.twoByteRange().begin().get(); JS::SourceBufferHolder srcBuf(chars, scriptContents->length(), - SourceBufferHolder::NoOwnership); + JS::SourceBufferHolder::NoOwnership); RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf)); if (!module) @@ -4369,7 +4378,7 @@ AbortDynamicModuleImport(JSContext* cx, unsigned argc, Value* vp) RootedString specifier(cx, args[1].toString()); Rooted promise(cx, &args[2].toObject().as()); - cx->setPendingException(args[3]); + cx->setPendingException(args[3], nullptr); return js::FinishDynamicModuleImport(cx, args[0], specifier, promise); } @@ -8422,7 +8431,7 @@ main(int argc, char** argv, char** envp) JS::SetModuleResolveHook(cx->runtime(), ShellModuleResolveHook); JS::SetModuleDynamicImportHook(cx, ShellModuleDynamicImportHook); - JS::SetModuleMetadataHook(cx, ShellModuleMetadataHook); + JS::SetModuleMetadataHook(cx, CallModuleMetadataHook); result = Shell(cx, &op, envp); diff --git a/js/src/tests/ecma_6/Array/toSorted.html b/js/src/tests/ecma_6/Array/toSorted.html new file mode 100644 index 0000000000..3738b05c48 --- /dev/null +++ b/js/src/tests/ecma_6/Array/toSorted.html @@ -0,0 +1,59 @@ + + +Array.prototype.toSorted test + +

+
+
diff --git a/js/src/tests/ecma_6/Array/toSorted.js b/js/src/tests/ecma_6/Array/toSorted.js
new file mode 100644
index 0000000000..fbd2540deb
--- /dev/null
+++ b/js/src/tests/ecma_6/Array/toSorted.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+assertEq(typeof Array.prototype.toSorted, "function");
+
+// Non-mutating behavior.
+let original = [3, 1, 2];
+let sorted = original.toSorted();
+assertEq(original !== sorted, true);
+assertEq(original.join(","), "3,1,2");
+assertEq(sorted.join(","), "1,2,3");
+
+// Compare function.
+let nums = [10, 1, 5];
+let desc = nums.toSorted((a, b) => b - a);
+assertEq(desc.join(","), "10,5,1");
+
+// Stable sort.
+let stableInput = [
+    {v: 1, id: "a"},
+    {v: 1, id: "b"},
+    {v: 1, id: "c"}
+];
+let stableSorted = stableInput.toSorted((x, y) => x.v - y.v);
+assertEq(stableSorted.map(o => o.id).join(""), "abc");
+
+// Holes are treated as undefined (properties are created).
+let sparse = [3, , 1];
+let sparseSorted = sparse.toSorted();
+assertEq(sparseSorted.length, 3);
+assertEq(sparseSorted[0], 1);
+assertEq(sparseSorted[1], 3);
+assertEq(2 in sparseSorted, true);
+assertEq(sparseSorted[2], undefined);
+
+// Array-like input.
+let arrayLike = {0: 2, 1: 1, length: 2};
+let arrayLikeSorted = Array.prototype.toSorted.call(arrayLike);
+assertEq(Array.isArray(arrayLikeSorted), true);
+assertEq(arrayLikeSorted.join(","), "1,2");
+
+// Getter access order (ascending indices).
+let accessLog = [];
+let getterArr = {
+    length: 3,
+    get 0() { accessLog.push(0); return 3; },
+    get 1() { accessLog.push(1); return 1; },
+    get 2() { accessLog.push(2); return 2; }
+};
+Array.prototype.toSorted.call(getterArr);
+assertEq(accessLog.join(","), "0,1,2");
+
+// Comparator errors propagate.
+assertThrowsInstanceOf(() => [1, 2].toSorted(1), TypeError);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
diff --git a/js/src/tests/non262/ArrayBuffer/resizable-transfer.js b/js/src/tests/non262/ArrayBuffer/resizable-transfer.js
new file mode 100644
index 0000000000..f603edabff
--- /dev/null
+++ b/js/src/tests/non262/ArrayBuffer/resizable-transfer.js
@@ -0,0 +1,98 @@
+// |reftest| skip-if(!ArrayBuffer.prototype.transfer)
+
+var fixed = new ArrayBuffer(4);
+assertEq(fixed.byteLength, 4);
+assertEq(fixed.maxByteLength, 4);
+assertEq(fixed.resizable, false);
+assertEq(fixed.detached, false);
+new Uint8Array(fixed).set([1, 2, 3, 4]);
+fixed.extra = 17;
+assertEq(Array.from(new Uint8Array(fixed)).join(","), "1,2,3,4");
+assertThrowsInstanceOf(() => fixed.resize(2), TypeError);
+assertEq(ArrayBuffer.prototype.transfer.length, 0);
+assertEq(ArrayBuffer.prototype.transferToFixedLength.length, 0);
+var resizeArgumentConverted = false;
+assertThrowsInstanceOf(() => fixed.resize({ valueOf() { resizeArgumentConverted = true; return 1; } }),
+                       TypeError);
+assertEq(resizeArgumentConverted, false);
+
+var resizable = new ArrayBuffer(4, { maxByteLength: 8 });
+assertEq(resizable.byteLength, 4);
+assertEq(resizable.maxByteLength, 8);
+assertEq(resizable.resizable, true);
+
+var bytes = new Uint8Array(resizable);
+bytes[0] = 11;
+bytes[3] = 44;
+resizable.resize(6);
+assertEq(resizable.byteLength, 6);
+assertEq(new Uint8Array(resizable)[0], 11);
+assertEq(new Uint8Array(resizable)[3], 44);
+assertEq(new Uint8Array(resizable)[4], 0);
+assertThrowsInstanceOf(() => resizable.resize(9), RangeError);
+
+var source = new ArrayBuffer(4);
+var sourceBytes = new Uint8Array(source);
+sourceBytes[0] = 1;
+sourceBytes[1] = 2;
+var sourceView = new Uint8Array(source);
+var moved = source.transfer(6);
+assertEq(source.detached, true);
+assertEq(source.byteLength, 0);
+assertEq(source.maxByteLength, 0);
+assertEq(sourceView.length, 0);
+assertEq(moved.byteLength, 6);
+assertEq(moved.resizable, false);
+assertEq(moved.maxByteLength, 6);
+assertEq(new Uint8Array(moved)[0], 1);
+assertEq(new Uint8Array(moved)[1], 2);
+assertEq(new Uint8Array(moved)[4], 0);
+
+var resizableSource = new ArrayBuffer(4, { maxByteLength: 8 });
+new Uint8Array(resizableSource)[0] = 7;
+var resizableMoved = resizableSource.transfer();
+assertEq(resizableSource.detached, true);
+assertEq(resizableSource.resizable, true);
+assertEq(resizableMoved.byteLength, 4);
+assertEq(resizableMoved.maxByteLength, 8);
+assertEq(resizableMoved.resizable, true);
+assertEq(new Uint8Array(resizableMoved)[0], 7);
+
+var fixedMoved = resizableMoved.transferToFixedLength(10);
+assertEq(resizableMoved.detached, true);
+assertEq(fixedMoved.byteLength, 10);
+assertEq(fixedMoved.maxByteLength, 10);
+assertEq(fixedMoved.resizable, false);
+assertEq(new Uint8Array(fixedMoved)[0], 7);
+
+var sliceSource = new ArrayBuffer(8, { maxByteLength: 8 });
+var sliceSourceBytes = new Uint8Array(sliceSource);
+for (var i = 0; i < sliceSourceBytes.length; i++)
+  sliceSourceBytes[i] = i + 1;
+
+sliceSource.constructor = {
+  [Symbol.species]: function(byteLength) {
+    sliceSource.resize(4);
+    return new ArrayBuffer(byteLength);
+  }
+};
+
+var sliced = sliceSource.slice(2, 8);
+var slicedBytes = new Uint8Array(sliced);
+assertEq(sliced.byteLength, 6);
+assertEq(slicedBytes[0], 3);
+assertEq(slicedBytes[1], 4);
+assertEq(slicedBytes[2], 0);
+assertEq(slicedBytes[5], 0);
+
+sliceSource.resize(8);
+for (var i = 0; i < sliceSourceBytes.length; i++)
+  sliceSourceBytes[i] = i + 1;
+var zeroCopied = sliceSource.slice(6, 8);
+assertEq(zeroCopied.byteLength, 2);
+assertEq(new Uint8Array(zeroCopied)[0], 0);
+
+assertThrowsInstanceOf(() => new ArrayBuffer(4, { maxByteLength: 3 }), RangeError);
+
+if (typeof reportCompare === "function")
+  reportCompare(0, 0);
diff --git a/js/src/tests/non262/ArrayBuffer/resizable-views.js b/js/src/tests/non262/ArrayBuffer/resizable-views.js
new file mode 100644
index 0000000000..e8d810b165
--- /dev/null
+++ b/js/src/tests/non262/ArrayBuffer/resizable-views.js
@@ -0,0 +1,218 @@
+// |reftest| skip-if(!this.SharedArrayBuffer)
+
+var rab = new ArrayBuffer(4, { maxByteLength: 16 });
+var tracking = new Uint8Array(rab);
+var fixed = new Uint8Array(rab, 1, 2);
+var bytes = new Uint8Array(rab);
+
+bytes[1] = 11;
+bytes[2] = 22;
+
+assertEq(tracking.length, 4);
+assertEq(tracking.byteLength, 4);
+assertEq(tracking.byteOffset, 0);
+assertEq(fixed.length, 2);
+assertEq(fixed.byteLength, 2);
+assertEq(fixed.byteOffset, 1);
+
+rab.resize(2);
+assertEq(tracking.length, 2);
+assertEq(tracking.byteLength, 2);
+assertEq(fixed.length, 0);
+assertEq(fixed.byteLength, 0);
+assertEq(fixed.byteOffset, 0);
+assertEq(fixed[0], undefined);
+
+rab.resize(8);
+assertEq(tracking.length, 8);
+assertEq(tracking.byteLength, 8);
+assertEq(fixed.length, 2);
+assertEq(fixed.byteLength, 2);
+assertEq(fixed.byteOffset, 1);
+assertEq(fixed[0], 11);
+assertEq(fixed[1], 0);
+tracking[6] = 66;
+assertEq(new Uint8Array(rab)[6], 66);
+
+var dv = new DataView(rab, 4);
+assertEq(dv.byteOffset, 4);
+assertEq(dv.byteLength, 4);
+dv.setUint8(0, 44);
+assertEq(tracking[4], 44);
+
+rab.resize(3);
+assertThrowsInstanceOf(() => dv.byteOffset, TypeError);
+assertThrowsInstanceOf(() => dv.byteLength, TypeError);
+assertThrowsInstanceOf(() => dv.getUint8(0), TypeError);
+
+rab.resize(6);
+assertEq(dv.byteOffset, 4);
+assertEq(dv.byteLength, 2);
+assertEq(dv.getUint8(0), 0);
+
+var fixedDv = new DataView(rab, 4, 2);
+rab.resize(5);
+assertThrowsInstanceOf(() => fixedDv.byteOffset, TypeError);
+assertThrowsInstanceOf(() => fixedDv.byteLength, TypeError);
+assertThrowsInstanceOf(() => fixedDv.getUint8(0), TypeError);
+rab.resize(6);
+assertEq(fixedDv.byteOffset, 4);
+assertEq(fixedDv.byteLength, 2);
+
+var methodRab = new ArrayBuffer(4, { maxByteLength: 8 });
+var methodFixed = new Uint8Array(methodRab, 2, 2);
+methodRab.resize(2);
+[
+  () => methodFixed.at(0),
+  () => methodFixed.copyWithin(0, 0),
+  () => methodFixed.entries(),
+  () => methodFixed.every(x => true),
+  () => methodFixed.fill(1),
+  () => methodFixed.filter(x => true),
+  () => methodFixed.find(x => true),
+  () => methodFixed.findIndex(x => true),
+  () => methodFixed.findLast(x => true),
+  () => methodFixed.findLastIndex(x => true),
+  () => methodFixed.forEach(x => x),
+  () => methodFixed.includes(0),
+  () => methodFixed.indexOf(0),
+  () => methodFixed.join(","),
+  () => methodFixed.keys(),
+  () => methodFixed.lastIndexOf(0),
+  () => methodFixed.map(x => x),
+  () => methodFixed.reduce((a, b) => a + b, 0),
+  () => methodFixed.reduceRight((a, b) => a + b, 0),
+  () => methodFixed.reverse(),
+  () => methodFixed.set([1], 0),
+  () => methodFixed.slice(),
+  () => methodFixed.some(x => true),
+  () => methodFixed.sort(),
+  () => methodFixed.subarray(),
+  () => methodFixed.toLocaleString(),
+  () => methodFixed.toReversed(),
+  () => methodFixed.toSorted(),
+  () => methodFixed.toString(),
+  () => methodFixed.values(),
+  () => methodFixed.with(0, 1),
+  () => methodFixed[Symbol.iterator](),
+].forEach(fn => assertThrowsInstanceOf(fn, TypeError));
+
+methodRab.resize(4);
+assertEq(methodFixed.length, 2);
+
+var sourceRab = new ArrayBuffer(4, { maxByteLength: 8 });
+var oobSource = new Uint8Array(sourceRab, 2, 2);
+sourceRab.resize(2);
+assertThrowsInstanceOf(() => new Uint8Array(oobSource), TypeError);
+assertThrowsInstanceOf(() => new Uint16Array(oobSource), TypeError);
+assertThrowsInstanceOf(() => new Uint8Array(4).set(oobSource), TypeError);
+sourceRab.resize(4);
+assertEq(new Uint8Array(oobSource).length, 2);
+
+var ctorRab = new ArrayBuffer(8, { maxByteLength: 8 });
+var ShrinkingNewTarget = new Proxy(function() {}, {
+  get(target, prop, receiver) {
+    if (prop === "prototype") {
+      ctorRab.resize(2);
+      return DataView.prototype;
+    }
+    return Reflect.get(target, prop, receiver);
+  }
+});
+assertThrowsInstanceOf(() => Reflect.construct(DataView, [ctorRab, 4], ShrinkingNewTarget),
+                       RangeError);
+
+var fixedCtorRab = new ArrayBuffer(8, { maxByteLength: 8 });
+var FixedShrinkingNewTarget = new Proxy(function() {}, {
+  get(target, prop, receiver) {
+    if (prop === "prototype") {
+      fixedCtorRab.resize(5);
+      return DataView.prototype;
+    }
+    return Reflect.get(target, prop, receiver);
+  }
+});
+assertThrowsInstanceOf(() => Reflect.construct(DataView, [fixedCtorRab, 4, 2],
+                                               FixedShrinkingNewTarget),
+                       RangeError);
+
+var gsab = new SharedArrayBuffer(4, { maxByteLength: 16 });
+var sharedTracking = new Uint8Array(gsab);
+assertEq(sharedTracking.length, 4);
+gsab.grow(8);
+assertEq(sharedTracking.length, 8);
+sharedTracking[6] = 33;
+assertEq(new Uint8Array(gsab)[6], 33);
+
+var sharedDv = new DataView(gsab);
+assertEq(sharedDv.buffer, gsab);
+assertEq(sharedDv.byteOffset, 0);
+assertEq(sharedDv.byteLength, 8);
+sharedDv.setUint8(7, 99);
+assertEq(sharedTracking[7], 99);
+gsab.grow(12);
+assertEq(sharedDv.byteLength, 12);
+assertEq(sharedDv.getUint8(7), 99);
+
+var fixedSharedDv = new DataView(gsab, 4, 2);
+assertEq(fixedSharedDv.byteOffset, 4);
+assertEq(fixedSharedDv.byteLength, 2);
+gsab.grow(16);
+assertEq(fixedSharedDv.byteOffset, 4);
+assertEq(fixedSharedDv.byteLength, 2);
+
+function readLength(view) {
+  return view.length;
+}
+
+function readElement(view, index) {
+  return view[index];
+}
+
+function writeElement(view, index, value) {
+  view[index] = value;
+}
+
+var normal = new Uint8Array(4);
+normal[0] = 7;
+for (var i = 0; i < 2000; i++) {
+  assertEq(readLength(normal), 4);
+  assertEq(readElement(normal, 0), 7);
+  writeElement(normal, 1, 8);
+}
+
+var icRab = new ArrayBuffer(4, { maxByteLength: 8 });
+var icTracking = new Uint8Array(icRab);
+icTracking[0] = 9;
+assertEq(readLength(icTracking), 4);
+assertEq(readElement(icTracking, 0), 9);
+icRab.resize(0);
+assertEq(readLength(icTracking), 0);
+assertEq(readElement(icTracking, 0), undefined);
+writeElement(icTracking, 0, 1);
+icRab.resize(4);
+assertEq(readLength(icTracking), 4);
+assertEq(readElement(icTracking, 0), 0);
+writeElement(icTracking, 0, 12);
+assertEq(readElement(icTracking, 0), 12);
+
+var icFixed = new Uint8Array(icRab, 1, 2);
+assertEq(readLength(icFixed), 2);
+icRab.resize(2);
+assertEq(readLength(icFixed), 0);
+assertEq(readElement(icFixed, 0), undefined);
+writeElement(icFixed, 0, 55);
+icRab.resize(4);
+assertEq(readLength(icFixed), 2);
+assertEq(readElement(icFixed, 0), 0);
+
+var icGsab = new SharedArrayBuffer(4, { maxByteLength: 8 });
+var icSharedTracking = new Uint8Array(icGsab);
+assertEq(readLength(icSharedTracking), 4);
+icGsab.grow(8);
+assertEq(readLength(icSharedTracking), 8);
+writeElement(icSharedTracking, 5, 77);
+assertEq(readElement(icSharedTracking, 5), 77);
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
diff --git a/js/src/tests/non262/Atomics/waitAsync.js b/js/src/tests/non262/Atomics/waitAsync.js
new file mode 100644
index 0000000000..a2b23a4f80
--- /dev/null
+++ b/js/src/tests/non262/Atomics/waitAsync.js
@@ -0,0 +1,77 @@
+// |reftest| skip-if(!this.SharedArrayBuffer || !this.Atomics || !this.drainJobQueue)
+
+if (typeof SharedArrayBuffer === "function" && typeof Atomics === "object" &&
+    typeof drainJobQueue === "function") {
+  const sab = new SharedArrayBuffer(4);
+  const i32 = new Int32Array(sab);
+
+  let result = Atomics.waitAsync(i32, 0, 1, 10);
+  assertEq(result.async, false);
+  assertEq(result.value, "not-equal");
+
+  result = Atomics.waitAsync(i32, 0, 0, 0);
+  assertEq(result.async, false);
+  assertEq(result.value, "timed-out");
+
+  result = Atomics.waitAsync(i32, 0, 0);
+  assertEq(result.async, true);
+  let notified;
+  result.value.then(value => {
+    notified = value;
+  });
+  assertEq(Atomics.notify(i32, 0, 1), 1);
+  drainJobQueue();
+  assertEq(notified, "ok");
+
+  result = Atomics.waitAsync(i32, 0, 0, 1);
+  assertEq(result.async, true);
+  let timedOut;
+  result.value.then(value => {
+    timedOut = value;
+  });
+  drainJobQueue();
+  assertEq(timedOut, "timed-out");
+
+  if (typeof BigInt64Array === "function") {
+    const bigSab = new SharedArrayBuffer(16);
+    const i64 = new BigInt64Array(bigSab);
+    const u64 = new BigUint64Array(bigSab);
+
+    assertEq(Atomics.store(i64, 0, -1n), -1n);
+    assertEq(Atomics.load(i64, 0), -1n);
+    assertEq(Atomics.load(u64, 0), 18446744073709551615n);
+    assertEq(Atomics.exchange(i64, 0, 7n), -1n);
+    assertEq(Atomics.compareExchange(i64, 0, 7n, 10n), 7n);
+    assertEq(Atomics.add(i64, 0, 5n), 10n);
+    assertEq(Atomics.load(i64, 0), 15n);
+    assertEq(Atomics.sub(i64, 0, 20n), 15n);
+    assertEq(Atomics.load(i64, 0), -5n);
+    assertEq(Atomics.and(u64, 0, 7n), 18446744073709551611n);
+    assertEq(Atomics.or(u64, 0, 8n), 3n);
+    assertEq(Atomics.xor(u64, 0, 15n), 11n);
+
+    assertThrowsInstanceOf(() => Atomics.waitAsync(u64, 0, 0n), TypeError);
+
+    result = Atomics.waitAsync(i64, 1, 1n, 10);
+    assertEq(result.async, false);
+    assertEq(result.value, "not-equal");
+
+    result = Atomics.waitAsync(i64, 1, 0n, 0);
+    assertEq(result.async, false);
+    assertEq(result.value, "timed-out");
+
+    let offsetView = new BigInt64Array(bigSab, 8);
+    result = Atomics.waitAsync(offsetView, 0, 0n);
+    assertEq(result.async, true);
+    notified = undefined;
+    result.value.then(value => {
+      notified = value;
+    });
+    assertEq(Atomics.notify(i64, 1, 1), 1);
+    drainJobQueue();
+    assertEq(notified, "ok");
+  }
+}
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
diff --git a/js/src/tests/non262/Promise/with-resolvers.js b/js/src/tests/non262/Promise/with-resolvers.js
new file mode 100644
index 0000000000..985d458622
--- /dev/null
+++ b/js/src/tests/non262/Promise/with-resolvers.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!Promise.withResolvers)
+
+var desc = Object.getOwnPropertyDescriptor(Promise, "withResolvers");
+assertEq(desc.enumerable, false);
+assertEq(desc.configurable, true);
+assertEq(desc.writable, true);
+assertEq(Promise.withResolvers.length, 0);
+assertEq(Promise.withResolvers.name, "withResolvers");
+
+var capability = Promise.withResolvers();
+assertEq(capability.promise instanceof Promise, true);
+assertEq(typeof capability.resolve, "function");
+assertEq(typeof capability.reject, "function");
+assertEqArray(Object.keys(capability), ["promise", "resolve", "reject"]);
+
+capability.resolve(42);
+capability.promise.then(v => assertEq(v, 42));
+
+class MyPromise extends Promise {}
+var subCapability = Promise.withResolvers.call(MyPromise);
+assertEq(subCapability.promise instanceof MyPromise, true);
+subCapability.reject("rejected");
+subCapability.promise.then(
+  () => { throw new Error("expected rejection"); },
+  reason => assertEq(reason, "rejected")
+);
+
+assertThrowsInstanceOf(() => Promise.withResolvers.call({}), TypeError);
+
+if (typeof reportCompare === "function")
+  reportCompare(0, 0);
diff --git a/js/src/tests/non262/SharedArrayBuffer/growable.js b/js/src/tests/non262/SharedArrayBuffer/growable.js
new file mode 100644
index 0000000000..7b9ce85ffe
--- /dev/null
+++ b/js/src/tests/non262/SharedArrayBuffer/growable.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.SharedArrayBuffer)
+
+if (typeof SharedArrayBuffer === "function") {
+  const fixed = new SharedArrayBuffer(4);
+  assertEq(fixed.byteLength, 4);
+  assertEq(fixed.maxByteLength, 4);
+  assertEq(fixed.growable, false);
+  assertThrowsInstanceOf(() => fixed.grow(4), TypeError);
+
+  assertThrowsInstanceOf(() => new SharedArrayBuffer(-1), RangeError);
+  assertThrowsInstanceOf(() => new SharedArrayBuffer(8, {maxByteLength: 4}), RangeError);
+
+  let optionGetterCalled = false;
+  const growable = new SharedArrayBuffer(4, {
+    get maxByteLength() {
+      optionGetterCalled = true;
+      return 16;
+    }
+  });
+  assertEq(optionGetterCalled, true);
+  assertEq(growable.byteLength, 4);
+  assertEq(growable.maxByteLength, 16);
+  assertEq(growable.growable, true);
+
+  const before = new Uint8Array(growable);
+  before[0] = 37;
+  assertEq(growable.grow(12), undefined);
+  assertEq(growable.byteLength, 12);
+  assertEq(growable.maxByteLength, 16);
+
+  const after = new Uint8Array(growable);
+  assertEq(after.length, 12);
+  assertEq(after[0], 37);
+
+  assertThrowsInstanceOf(() => growable.grow(11), RangeError);
+  assertThrowsInstanceOf(() => growable.grow(17), RangeError);
+}
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
diff --git a/js/src/tests/non262/String/well-formed.js b/js/src/tests/non262/String/well-formed.js
new file mode 100644
index 0000000000..7472f6afa8
--- /dev/null
+++ b/js/src/tests/non262/String/well-formed.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!String.prototype.isWellFormed||!String.prototype.toWellFormed)
+
+assertEq("".isWellFormed(), true);
+assertEq("abc".isWellFormed(), true);
+assertEq("\uD83D\uDE00".isWellFormed(), true);
+assertEq("\uD800".isWellFormed(), false);
+assertEq("\uDC00".isWellFormed(), false);
+assertEq("\uD800a".isWellFormed(), false);
+assertEq("a\uDC00".isWellFormed(), false);
+assertEq("\uD800\uD800\uDC00".isWellFormed(), false);
+
+assertEq("abc".toWellFormed(), "abc");
+assertEq("\uD83D\uDE00".toWellFormed(), "\uD83D\uDE00");
+assertEq("\uD800".toWellFormed(), "\uFFFD");
+assertEq("\uDC00".toWellFormed(), "\uFFFD");
+assertEq("\uD800a\uDC00".toWellFormed(), "\uFFFDa\uFFFD");
+assertEq("\uD800\uD800\uDC00".toWellFormed(), "\uFFFD\uD800\uDC00");
+
+assertEq(String.prototype.isWellFormed.call(123), true);
+assertEq(String.prototype.toWellFormed.call({ toString() { return "\uD800x"; } }), "\uFFFDx");
+
+assertThrowsInstanceOf(() => String.prototype.isWellFormed.call(null), TypeError);
+assertThrowsInstanceOf(() => String.prototype.toWellFormed.call(undefined), TypeError);
+
+if (typeof reportCompare === "function")
+  reportCompare(0, 0);
diff --git a/js/src/tests/non262/WeakMap/symbol-keys.js b/js/src/tests/non262/WeakMap/symbol-keys.js
new file mode 100644
index 0000000000..0edb542974
--- /dev/null
+++ b/js/src/tests/non262/WeakMap/symbol-keys.js
@@ -0,0 +1,36 @@
+var key = Symbol("weak");
+var map = new WeakMap();
+assertEq(map.has(key), false);
+assertEq(map.get(key), undefined);
+assertEq(map.set(key, 13), map);
+assertEq(map.has(key), true);
+assertEq(map.get(key), 13);
+assertEq(map.delete(key), true);
+assertEq(map.has(key), false);
+
+var constructedKey = Symbol("constructed");
+var constructed = new WeakMap([[constructedKey, 7]]);
+assertEq(constructed.get(constructedKey), 7);
+
+var registered = Symbol.for("registered");
+assertEq(map.has(registered), false);
+assertEq(map.get(registered), undefined);
+assertEq(map.delete(registered), false);
+assertThrowsInstanceOf(() => map.set(registered, 1), TypeError);
+assertThrowsInstanceOf(() => new WeakMap([[registered, 1]]), TypeError);
+
+var setKey = Symbol("set");
+var set = new WeakSet([setKey]);
+assertEq(set.has(setKey), true);
+assertEq(set.delete(setKey), true);
+assertEq(set.has(setKey), false);
+assertEq(set.add(setKey), set);
+assertEq(set.has(setKey), true);
+
+assertEq(set.has(registered), false);
+assertEq(set.delete(registered), false);
+assertThrowsInstanceOf(() => set.add(registered), TypeError);
+assertThrowsInstanceOf(() => new WeakSet([registered]), TypeError);
+
+if (typeof reportCompare === "function")
+  reportCompare(0, 0);
diff --git a/js/src/tests/non262/collections/groupBy.js b/js/src/tests/non262/collections/groupBy.js
new file mode 100644
index 0000000000..121a899ede
--- /dev/null
+++ b/js/src/tests/non262/collections/groupBy.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!Object.groupBy||!Map.groupBy)
+
+var objectGroups = Object.groupBy(["a", "bb", "c"], value => value.length);
+assertEq(Object.getPrototypeOf(objectGroups), null);
+assertEqArray(objectGroups["1"], ["a", "c"]);
+assertEqArray(objectGroups["2"], ["bb"]);
+
+var symbol = Symbol();
+var symbolGroups = Object.groupBy([1, 2], value => value === 1 ? symbol : "__proto__");
+assertEqArray(symbolGroups[symbol], [1]);
+assertEqArray(symbolGroups.__proto__, [2]);
+
+var indexes = [];
+var mapGroups = Map.groupBy(["a", "bb", "c"], (value, index) => {
+  indexes.push(index);
+  return value.length;
+});
+assertEq(mapGroups instanceof Map, true);
+assertEqArray(indexes, [0, 1, 2]);
+assertEqArray(mapGroups.get(1), ["a", "c"]);
+assertEqArray(mapGroups.get(2), ["bb"]);
+
+var key = {};
+var objectKeyGroups = Map.groupBy([1, 2], value => value === 1 ? key : NaN);
+assertEqArray(objectKeyGroups.get(key), [1]);
+assertEqArray(objectKeyGroups.get(NaN), [2]);
+
+assertThrowsInstanceOf(() => Object.groupBy(null, x => x), TypeError);
+assertThrowsInstanceOf(() => Map.groupBy(undefined, x => x), TypeError);
+assertThrowsInstanceOf(() => Object.groupBy([], null), TypeError);
+assertThrowsInstanceOf(() => Map.groupBy([], null), TypeError);
+
+if (typeof reportCompare === "function")
+  reportCompare(0, 0);
diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp
index e43edab690..666fc774df 100644
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -22,6 +22,7 @@
 # include 
 #endif
 
+#include 
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jscntxt.h"
@@ -45,6 +46,7 @@
 #include "vm/Interpreter.h"
 #include "vm/SelfHosting.h"
 #include "vm/SharedArrayObject.h"
+#include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
 #include "wasm/WasmSignalHandlers.h"
 #include "wasm/WasmTypes.h"
@@ -170,12 +172,18 @@ static const JSPropertySpec static_properties[] = {
 
 
 static const JSFunctionSpec prototype_functions[] = {
+    JS_FN("resize", ArrayBufferObject::fun_resize, 1, 0),
     JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
+    JS_FN("transfer", ArrayBufferObject::fun_transfer, 0, 0),
+    JS_FN("transferToFixedLength", ArrayBufferObject::fun_transferToFixedLength, 0, 0),
     JS_FS_END
 };
 
 static const JSPropertySpec prototype_properties[] = {
     JS_PSG("byteLength", ArrayBufferObject::byteLengthGetter, 0),
+    JS_PSG("detached", ArrayBufferObject::detachedGetter, 0),
+    JS_PSG("maxByteLength", ArrayBufferObject::maxByteLengthGetter, 0),
+    JS_PSG("resizable", ArrayBufferObject::resizableGetter, 0),
     JS_STRING_SYM_PS(toStringTag, "ArrayBuffer", JSPROP_READONLY),
     JS_PS_END
 };
@@ -252,6 +260,52 @@ ArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
     return CallNonGenericMethod(cx, args);
 }
 
+MOZ_ALWAYS_INLINE bool
+ArrayBufferObject::detachedGetterImpl(JSContext* cx, const CallArgs& args)
+{
+    MOZ_ASSERT(IsArrayBuffer(args.thisv()));
+    args.rval().setBoolean(args.thisv().toObject().as().isDetached());
+    return true;
+}
+
+bool
+ArrayBufferObject::detachedGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
+}
+
+MOZ_ALWAYS_INLINE bool
+ArrayBufferObject::maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args)
+{
+    MOZ_ASSERT(IsArrayBuffer(args.thisv()));
+    ArrayBufferObject& buffer = args.thisv().toObject().as();
+    args.rval().setInt32(buffer.isDetached() ? 0 : int32_t(buffer.maxByteLength()));
+    return true;
+}
+
+bool
+ArrayBufferObject::maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
+}
+
+MOZ_ALWAYS_INLINE bool
+ArrayBufferObject::resizableGetterImpl(JSContext* cx, const CallArgs& args)
+{
+    MOZ_ASSERT(IsArrayBuffer(args.thisv()));
+    args.rval().setBoolean(args.thisv().toObject().as().isResizable());
+    return true;
+}
+
+bool
+ArrayBufferObject::resizableGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
+}
+
 /*
  * ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
  */
@@ -264,6 +318,39 @@ ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp)
     return true;
 }
 
+static bool
+GetArrayBufferMaxByteLengthOption(JSContext* cx, HandleValue options,
+                                  uint32_t byteLength, uint32_t* maxByteLength,
+                                  bool* resizable)
+{
+    *maxByteLength = byteLength;
+    *resizable = false;
+
+    if (!options.isObject())
+        return true;
+
+    RootedObject opts(cx, &options.toObject());
+    RootedValue maxByteLengthValue(cx);
+    if (!GetProperty(cx, opts, opts, cx->names().maxByteLength, &maxByteLengthValue))
+        return false;
+
+    if (maxByteLengthValue.isUndefined())
+        return true;
+
+    uint64_t max;
+    if (!ToIndex(cx, maxByteLengthValue, &max))
+        return false;
+
+    if (max > INT32_MAX || max < byteLength) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+        return false;
+    }
+
+    *maxByteLength = uint32_t(max);
+    *resizable = true;
+    return true;
+}
+
 
 // ES2017 draft 24.1.2.1
 bool
@@ -287,12 +374,22 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
     }
 
     // Step 3.
+    uint32_t maxByteLength;
+    bool resizable;
+    if (!GetArrayBufferMaxByteLengthOption(cx, args.get(1), uint32_t(byteLength),
+                                           &maxByteLength, &resizable))
+    {
+        return false;
+    }
+
+    // Step 4.
     RootedObject proto(cx);
     RootedObject newTarget(cx, &args.newTarget().toObject());
     if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
         return false;
 
-    JSObject* bufobj = create(cx, uint32_t(byteLength), proto);
+    JSObject* bufobj = create(cx, uint32_t(byteLength), BufferContents::createPlain(nullptr),
+                              OwnsData, proto, GenericObject, maxByteLength, resizable);
     if (!bufobj)
         return false;
     args.rval().setObject(*bufobj);
@@ -302,13 +399,66 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
 static ArrayBufferObject::BufferContents
 AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
 {
-    uint8_t* p = cx->runtime()->pod_callocCanGC(nbytes);
+    uint8_t* p = cx->runtime()->pod_callocCanGC(nbytes ? nbytes : 1);
     if (!p)
         ReportOutOfMemory(cx);
 
     return ArrayBufferObject::BufferContents::create(p);
 }
 
+static bool
+ReportArrayBufferNotResizable(JSContext* cx)
+{
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARRAYBUFFER_NOT_RESIZABLE);
+    return false;
+}
+
+static bool
+ReportArrayBufferCannotDetach(JSContext* cx)
+{
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARRAYBUFFER_CANNOT_DETACH);
+    return false;
+}
+
+static bool
+ReportArrayBufferLengthOutOfRange(JSContext* cx)
+{
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+    return false;
+}
+
+static bool
+ArrayBufferViewFits(ArrayBufferViewObject* view, uint32_t newByteLength)
+{
+    if (view->is()) {
+        DataViewObject& dataView = view->as();
+        uint32_t byteOffset = dataView.byteOffsetMaybeOutOfBounds();
+        if (byteOffset > newByteLength)
+            return false;
+        uint32_t byteLength = dataView.isLengthTracking()
+                              ? newByteLength - byteOffset
+                              : dataView.fixedByteLengthMaybeOutOfBounds();
+        return byteOffset <= newByteLength && byteLength <= newByteLength - byteOffset;
+    }
+
+    if (view->is()) {
+        TypedArrayObject& typedArray = view->as();
+        if (typedArray.isSharedMemory())
+            return true;
+        uint32_t byteOffset = typedArray.byteOffsetMaybeOutOfBounds();
+        if (byteOffset > newByteLength)
+            return false;
+        uint32_t byteLength = typedArray.isLengthTracking()
+                              ? newByteLength - byteOffset
+                              : typedArray.fixedLengthMaybeOutOfBounds() *
+                                typedArray.bytesPerElement();
+        return byteOffset <= newByteLength && byteLength <= newByteLength - byteOffset;
+    }
+
+    // Outline typed objects don't have a recoverable fixed byte range here.
+    return false;
+}
+
 static void
 NoteViewBufferWasDetached(ArrayBufferViewObject* view,
                           ArrayBufferObject::BufferContents newContents,
@@ -391,7 +541,8 @@ ArrayBufferObject::setNewData(FreeOp* fop, BufferContents newContents, OwnsState
 
 void
 ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
-                                      uint8_t* oldDataPointer, BufferContents newContents)
+                                      uint8_t* oldDataPointer, BufferContents newContents,
+                                      uint32_t newByteLength)
 {
     MOZ_ASSERT(!view->isSharedMemory());
 
@@ -402,7 +553,18 @@ ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view
     uint8_t* viewDataPointer = view->dataPointerUnshared(nogc);
     if (viewDataPointer) {
         MOZ_ASSERT(newContents);
-        ptrdiff_t offset = viewDataPointer - oldDataPointer;
+        uint32_t offset;
+        if (view->is()) {
+            offset = view->as().byteOffsetMaybeOutOfBounds();
+        } else if (view->is()) {
+            offset = view->as().byteOffsetMaybeOutOfBounds();
+        } else {
+            ptrdiff_t oldOffset = viewDataPointer - oldDataPointer;
+            MOZ_ASSERT(oldOffset >= 0);
+            offset = uint32_t(oldOffset);
+        }
+        if (offset > newByteLength)
+            offset = 0;
         viewDataPointer = static_cast(newContents.data()) + offset;
         view->setDataPointerUnshared(viewDataPointer);
     }
@@ -428,10 +590,180 @@ ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents,
     auto& innerViews = cx->compartment()->innerViews.get();
     if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
         for (size_t i = 0; i < views->length(); i++)
-            changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
+            changeViewContents(cx, (*views)[i], oldDataPointer, newContents, byteLength());
     }
     if (firstView())
-        changeViewContents(cx, firstView(), oldDataPointer, newContents);
+        changeViewContents(cx, firstView(), oldDataPointer, newContents, byteLength());
+}
+
+void
+ArrayBufferObject::changeContentsForResize(JSContext* cx, BufferContents newContents,
+                                           OwnsState ownsState, uint32_t newByteLength)
+{
+    MOZ_RELEASE_ASSERT(!isWasm());
+    MOZ_ASSERT(!forInlineTypedObject());
+
+    uint8_t* oldDataPointer = dataPointer();
+    setNewData(cx->runtime()->defaultFreeOp(), newContents, ownsState);
+    setByteLength(newByteLength);
+
+    auto& innerViews = cx->compartment()->innerViews.get();
+    if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
+        for (size_t i = 0; i < views->length(); i++) {
+            ArrayBufferViewObject* view = (*views)[i];
+            if (view->is() || view->is())
+                changeViewContents(cx, view, oldDataPointer, newContents, newByteLength);
+            else if (ArrayBufferViewFits(view, newByteLength))
+                changeViewContents(cx, view, oldDataPointer, newContents, newByteLength);
+            else
+                NoteViewBufferWasDetached(view, newContents, cx);
+        }
+    }
+
+    if (firstView()) {
+        if (firstView()->is() || firstView()->is())
+            changeViewContents(cx, firstView(), oldDataPointer, newContents, newByteLength);
+        else if (ArrayBufferViewFits(firstView(), newByteLength))
+            changeViewContents(cx, firstView(), oldDataPointer, newContents, newByteLength);
+        else
+            NoteViewBufferWasDetached(firstView(), newContents, cx);
+    }
+}
+
+static bool
+ResizeArrayBuffer(JSContext* cx, Handle buffer, uint32_t newByteLength)
+{
+    if (!buffer->isResizable())
+        return ReportArrayBufferNotResizable(cx);
+
+    if (buffer->isDetached()) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+        return false;
+    }
+
+    if (newByteLength > buffer->maxByteLength())
+        return ReportArrayBufferLengthOutOfRange(cx);
+
+    if (!buffer->isPlain() || buffer->isPreparedForAsmJS() || buffer->forInlineTypedObject())
+        return ReportArrayBufferCannotDetach(cx);
+
+    if (newByteLength == buffer->byteLength())
+        return true;
+
+    ArrayBufferObject::BufferContents newContents = AllocateArrayBufferContents(cx, newByteLength);
+    if (!newContents)
+        return false;
+
+    uint32_t copyLength = std::min(newByteLength, buffer->byteLength());
+    if (copyLength > 0)
+        memcpy(newContents.data(), buffer->dataPointer(), copyLength);
+
+    buffer->changeContentsForResize(cx, newContents, ArrayBufferObject::OwnsData, newByteLength);
+    return true;
+}
+
+bool
+ArrayBufferObject::fun_resize_impl(JSContext* cx, const CallArgs& args)
+{
+    MOZ_ASSERT(IsArrayBuffer(args.thisv()));
+
+    Rooted buffer(cx, &args.thisv().toObject().as());
+    if (!buffer->isResizable())
+        return ReportArrayBufferNotResizable(cx);
+
+    uint64_t newByteLength;
+    if (!ToIndex(cx, args.get(0), &newByteLength))
+        return false;
+    if (newByteLength > INT32_MAX)
+        return ReportArrayBufferLengthOutOfRange(cx);
+
+    if (!ResizeArrayBuffer(cx, buffer, uint32_t(newByteLength)))
+        return false;
+
+    args.rval().setUndefined();
+    return true;
+}
+
+bool
+ArrayBufferObject::fun_resize(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
+}
+
+static bool
+ArrayBufferTransfer(JSContext* cx, const CallArgs& args, bool preserveResizability)
+{
+    MOZ_ASSERT(IsArrayBuffer(args.thisv()));
+    Rooted buffer(cx, &args.thisv().toObject().as());
+
+    uint32_t newByteLength = buffer->byteLength();
+    if (args.hasDefined(0)) {
+        uint64_t newLength;
+        if (!ToIndex(cx, args.get(0), &newLength))
+            return false;
+        if (newLength > INT32_MAX)
+            return ReportArrayBufferLengthOutOfRange(cx);
+        newByteLength = uint32_t(newLength);
+    }
+
+    if (buffer->isDetached()) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+        return false;
+    }
+
+    if (buffer->isWasm() || buffer->isPreparedForAsmJS())
+        return ReportArrayBufferCannotDetach(cx);
+
+    bool newResizable = preserveResizability && buffer->isResizable();
+    uint32_t newMaxByteLength = newResizable ? buffer->maxByteLength() : newByteLength;
+    if (newResizable && newByteLength > newMaxByteLength)
+        return ReportArrayBufferLengthOutOfRange(cx);
+
+    Rooted newBuffer(cx,
+        ArrayBufferObject::create(cx, newByteLength, ArrayBufferObject::BufferContents::createPlain(nullptr),
+                                  ArrayBufferObject::OwnsData, nullptr, GenericObject,
+                                  newMaxByteLength, newResizable));
+    if (!newBuffer)
+        return false;
+
+    uint32_t copyLength = std::min(newByteLength, buffer->byteLength());
+    if (copyLength > 0)
+        memcpy(newBuffer->dataPointer(), buffer->dataPointer(), copyLength);
+
+    ArrayBufferObject::BufferContents detachedContents =
+        buffer->hasStealableContents() ? ArrayBufferObject::BufferContents::createPlain(nullptr)
+                                       : buffer->contents();
+    ArrayBufferObject::detach(cx, buffer, detachedContents);
+
+    args.rval().setObject(*newBuffer);
+    return true;
+}
+
+bool
+ArrayBufferObject::fun_transfer_impl(JSContext* cx, const CallArgs& args)
+{
+    return ArrayBufferTransfer(cx, args, true);
+}
+
+bool
+ArrayBufferObject::fun_transfer(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
+}
+
+bool
+ArrayBufferObject::fun_transferToFixedLength_impl(JSContext* cx, const CallArgs& args)
+{
+    return ArrayBufferTransfer(cx, args, false);
+}
+
+bool
+ArrayBufferObject::fun_transferToFixedLength(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
 }
 
 /*
@@ -887,6 +1219,14 @@ ArrayBufferObject::byteLength() const
     return getSlot(BYTE_LENGTH_SLOT).toInt32();
 }
 
+uint32_t
+ArrayBufferObject::maxByteLength() const
+{
+    if (!isResizable())
+        return byteLength();
+    return getSlot(MAX_BYTE_LENGTH_SLOT).toInt32();
+}
+
 void
 ArrayBufferObject::setByteLength(uint32_t length)
 {
@@ -929,7 +1269,7 @@ js::WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf)
     if (buf->is())
         return buf->as().wasmMaxSize();
 
-    return Some(buf->as().byteLength());
+    return Some(buf->as().maxByteLength());
 }
 
 /* static */ bool
@@ -1035,9 +1375,12 @@ ArrayBufferObject*
 ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents,
                           OwnsState ownsState /* = OwnsData */,
                           HandleObject proto /* = nullptr */,
-                          NewObjectKind newKind /* = GenericObject */)
+                          NewObjectKind newKind /* = GenericObject */,
+                          uint32_t maxByteLength /* = 0 */,
+                          bool resizable /* = false */)
 {
     MOZ_ASSERT_IF(contents.kind() == MAPPED, contents);
+    MOZ_ASSERT_IF(resizable, maxByteLength >= nbytes);
 
     // 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
     // Refuse to allocate too large buffers, currently limited to ~2 GiB.
@@ -1046,10 +1389,6 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
         return nullptr;
     }
 
-    // If we need to allocate data, try to use a larger object size class so
-    // that the array buffer's data can be allocated inline with the object.
-    // The extra space will be left unused by the object's fixed slots and
-    // available for the buffer's data, see NewObject().
     size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_);
 
     size_t nslots = reservedSlots;
@@ -1066,18 +1405,10 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
         }
     } else {
         MOZ_ASSERT(ownsState == OwnsData);
-        size_t usableSlots = NativeObject::MAX_FIXED_SLOTS - reservedSlots;
-        if (nbytes <= usableSlots * sizeof(Value)) {
-            int newSlots = (nbytes - 1) / sizeof(Value) + 1;
-            MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
-            nslots = reservedSlots + newSlots;
-            contents = BufferContents::createPlain(nullptr);
-        } else {
-            contents = AllocateArrayBufferContents(cx, nbytes);
-            if (!contents)
-                return nullptr;
-            allocated = true;
-        }
+        contents = AllocateArrayBufferContents(cx, nbytes);
+        if (!contents)
+            return nullptr;
+        allocated = true;
     }
 
     MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
@@ -1097,10 +1428,11 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
 
     if (!contents) {
         void* data = obj->inlineDataPointer();
-        js_memset(data, 0, nbytes);
-        obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData);
+        memset(data, 0, nbytes);
+        obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData,
+                        maxByteLength, resizable);
     } else {
-        obj->initialize(nbytes, contents, ownsState);
+        obj->initialize(nbytes, contents, ownsState, maxByteLength, resizable);
     }
 
     return obj;
@@ -1130,25 +1462,28 @@ ArrayBufferObject::createEmpty(JSContext* cx)
 bool
 ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args)
 {
-    MOZ_ASSERT(IsArrayBuffer(args.thisv()));
+    MOZ_ASSERT(IsAnyArrayBuffer(args.thisv()));
 
     /*
      * This method is only called for |DataView(alienBuf, ...)| which calls
      * this as |createDataViewForThis.call(alienBuf, byteOffset, byteLength,
-     *                                     DataView.prototype)|,
-     * ergo there must be exactly 3 arguments.
+     *                                     DataView.prototype, lengthTracking)|,
+     * ergo there must be exactly 4 arguments.
      */
-    MOZ_ASSERT(args.length() == 3);
+    MOZ_ASSERT(args.length() == 4);
 
     uint32_t byteOffset = args[0].toPrivateUint32();
     uint32_t byteLength = args[1].toPrivateUint32();
-    Rooted buffer(cx, &args.thisv().toObject().as());
+    bool lengthTracking = args[3].toBoolean();
+    Rooted buffer(cx,
+        &args.thisv().toObject().as());
 
     /*
      * Pop off the passed-along prototype and delegate to normal DataViewObject
      * construction.
      */
-    JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, &args[2].toObject());
+    JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer,
+                                           &args[2].toObject(), lengthTracking);
     if (!obj)
         return false;
     args.rval().setObject(*obj);
@@ -1159,7 +1494,7 @@ bool
 ArrayBufferObject::createDataViewForThis(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod(cx, args);
+    return CallNonGenericMethod(cx, args);
 }
 
 /* static */ ArrayBufferObject::BufferContents
@@ -1528,6 +1863,8 @@ ArrayBufferViewObject::trace(JSTracer* trc, JSObject* objArg)
                 // The data may or may not be inline with the buffer. The buffer
                 // can only move during a compacting GC, in which case its
                 // objectMoved hook has already updated the buffer's data pointer.
+                if (offset > buf.byteLength())
+                    offset = 0;
                 obj->initPrivate(buf.dataPointer() + offset);
             }
         }
@@ -1578,6 +1915,8 @@ ArrayBufferViewObject::dataPointerUnshared(const JS::AutoRequireNoGC& nogc)
 bool
 ArrayBufferViewObject::isSharedMemory()
 {
+    if (is())
+        return as().isSharedMemory();
     if (is())
         return as().isSharedMemory();
     return false;
@@ -1609,7 +1948,7 @@ ArrayBufferViewObject::bufferObject(JSContext* cx, Handleas().bufferEither();
     }
     MOZ_ASSERT(thisObject->is());
-    return &thisObject->as().arrayBuffer();
+    return &thisObject->as().arrayBufferEither();
 }
 
 /* JS Friend API */
@@ -1860,7 +2199,7 @@ JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoChe
     if (!obj)
         return nullptr;
     if (obj->is()) {
-        *isSharedMemory = false;
+        *isSharedMemory = obj->as().isSharedMemory();
         return obj->as().dataPointer();
     }
     TypedArrayObject& ta = obj->as();
@@ -1930,7 +2269,7 @@ js::GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSha
               : obj->as().byteLength();
 
     if (obj->is()) {
-        *isSharedMemory = false;
+        *isSharedMemory = obj->as().isSharedMemory();
         *data = static_cast(obj->as().dataPointer());
     }
     else {
diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h
index f4010c6c77..f9e3353b7e 100644
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -82,7 +82,7 @@ ArrayBufferObjectMaybeShared& AsAnyArrayBuffer(HandleValue val);
 class ArrayBufferObjectMaybeShared : public NativeObject
 {
   public:
-    uint32_t byteLength() {
+    uint32_t byteLength() const {
         return AnyArrayBufferByteLength(this);
     }
 
@@ -128,15 +128,22 @@ typedef MutableHandle MutableHandleArrayBufferObj
 class ArrayBufferObject : public ArrayBufferObjectMaybeShared
 {
     static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
+    static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
+    static bool resizableGetterImpl(JSContext* cx, const CallArgs& args);
+    static bool detachedGetterImpl(JSContext* cx, const CallArgs& args);
     static bool fun_slice_impl(JSContext* cx, const CallArgs& args);
+    static bool fun_resize_impl(JSContext* cx, const CallArgs& args);
+    static bool fun_transfer_impl(JSContext* cx, const CallArgs& args);
+    static bool fun_transferToFixedLength_impl(JSContext* cx, const CallArgs& args);
 
   public:
     static const uint8_t DATA_SLOT = 0;
     static const uint8_t BYTE_LENGTH_SLOT = 1;
     static const uint8_t FIRST_VIEW_SLOT = 2;
     static const uint8_t FLAGS_SLOT = 3;
+    static const uint8_t MAX_BYTE_LENGTH_SLOT = 4;
 
-    static const uint8_t RESERVED_SLOTS = 4;
+    static const uint8_t RESERVED_SLOTS = 5;
 
     static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
 
@@ -189,7 +196,11 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
 
         // This PLAIN or WASM buffer has been prepared for asm.js and cannot
         // henceforth be transferred/detached.
-        FOR_ASMJS           = 0x40
+        FOR_ASMJS           = 0x40,
+
+        // This buffer was created with [[ArrayBufferMaxByteLength]] and can
+        // be resized up to that maximum.
+        RESIZABLE           = 0x80
     };
 
     static_assert(JS_ARRAYBUFFER_DETACHED_FLAG == DETACHED,
@@ -230,8 +241,14 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
     static const Class class_;
 
     static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool resizableGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool detachedGetter(JSContext* cx, unsigned argc, Value* vp);
 
     static bool fun_slice(JSContext* cx, unsigned argc, Value* vp);
+    static bool fun_resize(JSContext* cx, unsigned argc, Value* vp);
+    static bool fun_transfer(JSContext* cx, unsigned argc, Value* vp);
+    static bool fun_transferToFixedLength(JSContext* cx, unsigned argc, Value* vp);
 
     static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
 
@@ -243,7 +260,9 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
                                      BufferContents contents,
                                      OwnsState ownsState = OwnsData,
                                      HandleObject proto = nullptr,
-                                     NewObjectKind newKind = GenericObject);
+                                     NewObjectKind newKind = GenericObject,
+                                     uint32_t maxByteLength = 0,
+                                     bool resizable = false);
     static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
                                      HandleObject proto = nullptr,
                                      NewObjectKind newKind = GenericObject);
@@ -294,6 +313,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
 
     void setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState);
     void changeContents(JSContext* cx, BufferContents newContents, OwnsState ownsState);
+    void changeContentsForResize(JSContext* cx, BufferContents newContents,
+                                 OwnsState ownsState, uint32_t newByteLength);
 
     // Detach this buffer from its original memory.  (This necessarily makes
     // views of this buffer unusable for modifying that original memory.)
@@ -302,7 +323,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
 
   private:
     void changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
-                            uint8_t* oldDataPointer, BufferContents newContents);
+                            uint8_t* oldDataPointer, BufferContents newContents,
+                            uint32_t newByteLength);
     void setFirstView(ArrayBufferViewObject* view);
 
     uint8_t* inlineDataPointer() const;
@@ -311,6 +333,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
     uint8_t* dataPointer() const;
     SharedMem dataPointerShared() const;
     uint32_t byteLength() const;
+    uint32_t maxByteLength() const;
 
     BufferContents contents() const {
         return BufferContents(dataPointer(), bufferKind());
@@ -334,6 +357,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
     bool isWasm() const { return bufferKind() == WASM; }
     bool isMapped() const { return bufferKind() == MAPPED; }
     bool isDetached() const { return flags() & DETACHED; }
+    bool isResizable() const { return flags() & RESIZABLE; }
     bool isPreparedForAsmJS() const { return flags() & FOR_ASMJS; }
 
     // WebAssembly support:
@@ -391,12 +415,17 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
 
     void setIsDetached() { setFlags(flags() | DETACHED); }
     void setIsPreparedForAsmJS() { setFlags(flags() | FOR_ASMJS); }
+    void setIsResizable() { setFlags(flags() | RESIZABLE); }
 
-    void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
+    void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState,
+                    uint32_t maxByteLength = 0, bool resizable = false) {
         setByteLength(byteLength);
         setFlags(0);
+        setFixedSlot(MAX_BYTE_LENGTH_SLOT, Int32Value(maxByteLength ? maxByteLength : byteLength));
         setFirstView(nullptr);
         setDataPointer(contents, ownsState);
+        if (resizable)
+            setIsResizable();
     }
 
     // Note: initialize() may be called after initEmpty(); initEmpty() must
@@ -404,6 +433,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
     void initEmpty() {
         setByteLength(0);
         setFlags(0);
+        setFixedSlot(MAX_BYTE_LENGTH_SLOT, Int32Value(0));
         setFirstView(nullptr);
         setDataPointer(BufferContents::createPlain(nullptr), DoesntOwnData);
     }
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
index 13af5c237d..82d49b201a 100644
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -248,6 +248,7 @@
     macro(lookupSetter, lookupSetter, "__lookupSetter__") \
     macro(MapConstructorInit, MapConstructorInit, "MapConstructorInit") \
     macro(MapIterator, MapIterator, "Map Iterator") \
+    macro(maxByteLength, maxByteLength, "maxByteLength") \
     macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
     macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \
     macro(message, message, "message") \
@@ -429,6 +430,7 @@
     macro(toJSON, toJSON, "toJSON") \
     macro(toLocaleString, toLocaleString, "toLocaleString") \
     macro(toSource, toSource, "toSource") \
+    macro(toSorted, toSorted, "toSorted") \
     macro(toString, toString, "toString") \
     macro(toUTCString, toUTCString, "toUTCString") \
     macro(true, true_, "true") \
diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp
index b3080d6edd..9d1dab322e 100644
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -27,6 +27,7 @@
 #include "builtin/SymbolObject.h"
 #include "builtin/TypedObject.h"
 #include "builtin/WeakMapObject.h"
+#include "builtin/WeakRefObject.h"
 #include "builtin/WeakSetObject.h"
 #include "vm/Debugger.h"
 #include "vm/EnvironmentObject.h"
@@ -464,6 +465,7 @@ GlobalObject::initStandardClasses(JSContext* cx, Handle global)
         if (!ensureConstructor(cx, global, static_cast(k)))
             return false;
     }
+
     return true;
 }
 
@@ -538,6 +540,7 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle globa
            InitBareBuiltinCtor(cx, global, JSProto_Int32Array) &&
            InitBareSymbolCtor(cx, global) &&
            InitBareWeakMapCtor(cx, global) &&
+           InitBareWeakRefCtor(cx, global) &&
            InitStopIterationClass(cx, global) &&
            DefineFunctions(cx, global, builtins, AsIntrinsic);
 }
diff --git a/js/src/vm/JSONParser.cpp b/js/src/vm/JSONParser.cpp
index 680a34fef0..2a70f9f771 100644
--- a/js/src/vm/JSONParser.cpp
+++ b/js/src/vm/JSONParser.cpp
@@ -43,6 +43,10 @@ JSONParserBase::~JSONParserBase()
 void
 JSONParserBase::trace(JSTracer* trc)
 {
+    for (auto& atom : propertyNameCache) {
+        if (atom)
+            TraceRoot(trc, &atom, "JSONParser cached property name");
+    }
     for (size_t i = 0; i < stack.length(); i++) {
         if (stack[i].state == FinishArrayElement) {
             ElementVector& elements = stack[i].elements();
@@ -123,6 +127,24 @@ JSONParser::readString()
         return token(Error);
     }
 
+    // Arrays of records repeatedly use the same property names. Verify the
+    // entire name and closing quote before skipping scanning and atomization.
+    // Only the unescaped path below populates this cache.
+    if (ST == JSONParser::PropertyName && *current != '"') {
+        JSAtom* atom = propertyNameCache[size_t(*current) % PropertyNameCacheSize];
+        if (atom && size_t(end - current) > atom->length() &&
+            current[atom->length()] == '"') {
+            JS::AutoCheckCannotGC nogc;
+            bool matches = atom->hasLatin1Chars()
+                           ? EqualChars(atom->latin1Chars(nogc), current.get(), atom->length())
+                           : EqualChars(atom->twoByteChars(nogc), current.get(), atom->length());
+            if (matches) {
+                current += atom->length() + 1;
+                return stringToken(atom);
+            }
+        }
+    }
+
     /*
      * Optimization: if the source contains no escaped characters, create the
      * string directly from the source text.
@@ -137,6 +159,9 @@ JSONParser::readString()
                                 : NewStringCopyN(cx, start.get(), length);
             if (!str)
                 return token(OOM);
+            if (ST == JSONParser::PropertyName && length) {
+                propertyNameCache[size_t(*start) % PropertyNameCacheSize] = &str->asAtom();
+            }
             return stringToken(str);
         }
 
diff --git a/js/src/vm/JSONParser.h b/js/src/vm/JSONParser.h
index 70ed86f58e..9c3a979c69 100644
--- a/js/src/vm/JSONParser.h
+++ b/js/src/vm/JSONParser.h
@@ -33,6 +33,11 @@ class MOZ_STACK_CLASS JSONParserBase
 
     const ErrorHandling errorHandling;
 
+    // Reuse unescaped property names within this parse. The cache is bounded
+    // and traced with the parser, including during compacting GC.
+    static const size_t PropertyNameCacheSize = 8;
+    JSAtom* propertyNameCache[PropertyNameCacheSize];
+
     enum Token { String, Number, True, False, Null,
                  ArrayOpen, ArrayClose,
                  ObjectOpen, ObjectClose,
@@ -109,6 +114,7 @@ class MOZ_STACK_CLASS JSONParserBase
     JSONParserBase(JSContext* cx, ErrorHandling errorHandling)
       : cx(cx),
         errorHandling(errorHandling),
+        propertyNameCache{},
         stack(cx),
         freeElements(cx),
         freeProperties(cx)
@@ -129,8 +135,10 @@ class MOZ_STACK_CLASS JSONParserBase
 #ifdef DEBUG
       , lastToken(mozilla::Move(other.lastToken))
 #endif
-    {}
-
+    {
+        for (size_t i = 0; i < PropertyNameCacheSize; i++)
+            propertyNameCache[i] = other.propertyNameCache[i];
+    }
 
     Value numberValue() const {
         MOZ_ASSERT(lastToken == Number);
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
index cde86fb829..b34a20c91b 100644
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -43,6 +43,22 @@ static const ObjectElements emptyElementsHeaderShared(0, 0, ObjectElements::Shar
 HeapSlot* const js::emptyObjectElementsShared =
     reinterpret_cast(uintptr_t(&emptyElementsHeaderShared) + sizeof(ObjectElements));
 
+static const ObjectElements emptyElementsHeaderResizableOrGrowable(
+    0, 0, ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER);
+
+/* Objects with no elements share one empty set of elements. */
+HeapSlot* const js::emptyObjectElementsResizableOrGrowable =
+    reinterpret_cast(uintptr_t(&emptyElementsHeaderResizableOrGrowable) +
+                                sizeof(ObjectElements));
+
+static const ObjectElements emptyElementsHeaderSharedResizableOrGrowable(
+    0, 0, ObjectElements::SHARED_MEMORY | ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER);
+
+/* Objects with no elements share one empty set of elements. */
+HeapSlot* const js::emptyObjectElementsSharedResizableOrGrowable =
+    reinterpret_cast(uintptr_t(&emptyElementsHeaderSharedResizableOrGrowable) +
+                                sizeof(ObjectElements));
+
 
 #ifdef DEBUG
 
@@ -61,10 +77,12 @@ ObjectElements::ConvertElementsToDoubles(JSContext* cx, uintptr_t elementsPtr)
      * This function is infallible, but has a fallible interface so that it can
      * be called directly from Ion code. Only arrays can have their dense
      * elements converted to doubles, and arrays never have empty elements.
-     */
+    */
     HeapSlot* elementsHeapPtr = (HeapSlot*) elementsPtr;
     MOZ_ASSERT(elementsHeapPtr != emptyObjectElements &&
-               elementsHeapPtr != emptyObjectElementsShared);
+               elementsHeapPtr != emptyObjectElementsShared &&
+               elementsHeapPtr != emptyObjectElementsResizableOrGrowable &&
+               elementsHeapPtr != emptyObjectElementsSharedResizableOrGrowable);
 
     ObjectElements* header = ObjectElements::fromElements(elementsHeapPtr);
     MOZ_ASSERT(!header->shouldConvertDoubleElements());
diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
index 86977d109f..67fd3a7a46 100644
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -185,6 +185,11 @@ class ObjectElements
 
         // These elements are set to integrity level "frozen".
         FROZEN                      = 0x10,
+
+        // For TypedArrays only: this TypedArray views a resizable
+        // ArrayBuffer or growable SharedArrayBuffer. JIT fast paths with
+        // cached length/data assumptions must fall back for these objects.
+        RESIZABLE_OR_GROWABLE_BUFFER = 0x20,
     };
 
   private:
@@ -255,6 +260,10 @@ class ObjectElements
       : flags(SHARED_MEMORY), initializedLength(0), capacity(capacity), length(length)
     {}
 
+    constexpr ObjectElements(uint32_t capacity, uint32_t length, uint32_t flags)
+      : flags(flags), initializedLength(0), capacity(capacity), length(length)
+    {}
+
     HeapSlot* elements() {
         return reinterpret_cast(uintptr_t(this) + sizeof(ObjectElements));
     }
@@ -269,6 +278,10 @@ class ObjectElements
         return flags & SHARED_MEMORY;
     }
 
+    bool hasResizableOrGrowableBuffer() const {
+        return flags & RESIZABLE_OR_GROWABLE_BUFFER;
+    }
+
     GCPtrNativeObject& ownerObject() const {
         MOZ_ASSERT(isCopyOnWrite());
         return *(GCPtrNativeObject*)(&elements()[initializedLength]);
@@ -326,6 +339,8 @@ static_assert(ObjectElements::VALUES_PER_HEADER * sizeof(HeapSlot) == sizeof(Obj
  */
 extern HeapSlot* const emptyObjectElements;
 extern HeapSlot* const emptyObjectElementsShared;
+extern HeapSlot* const emptyObjectElementsResizableOrGrowable;
+extern HeapSlot* const emptyObjectElementsSharedResizableOrGrowable;
 
 struct Class;
 class GCMarker;
@@ -480,6 +495,12 @@ class NativeObject : public ShapedObject
         elements_ = emptyObjectElementsShared;
     }
 
+    void setHasResizableOrGrowableBuffer() {
+        MOZ_ASSERT(elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared);
+        elements_ = isSharedMemory() ? emptyObjectElementsSharedResizableOrGrowable
+                                     : emptyObjectElementsResizableOrGrowable;
+    }
+
     bool isInWholeCellBuffer() const {
         const gc::TenuredCell* cell = &asTenured();
         gc::ArenaCellSet* cells = cell->arena()->bufferedCells;
@@ -1254,7 +1275,10 @@ class NativeObject : public ShapedObject
     }
 
     inline bool hasEmptyElements() const {
-        return elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared;
+        return elements_ == emptyObjectElements ||
+               elements_ == emptyObjectElementsShared ||
+               elements_ == emptyObjectElementsResizableOrGrowable ||
+               elements_ == emptyObjectElementsSharedResizableOrGrowable;
     }
 
     /*
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index c9f290463e..24b23f19ff 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -38,6 +38,7 @@
 #include "builtin/SelfHostingDefines.h"
 #include "builtin/Stream.h"
 #include "builtin/TypedObject.h"
+#include "builtin/WeakRefObject.h"
 #include "builtin/WeakSetObject.h"
 #include "gc/Marking.h"
 #include "gc/Policy.h"
@@ -105,6 +106,14 @@ intrinsic_IsObject(JSContext* cx, unsigned argc, Value* vp)
     return true;
 }
 
+static bool
+intrinsic_CanBeHeldWeakly(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    args.rval().setBoolean(CanBeHeldWeakly(args.get(0)));
+    return true;
+}
+
 static bool
 intrinsic_IsArray(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -270,6 +279,20 @@ intrinsic_GetBuiltinConstructor(JSContext* cx, unsigned argc, Value* vp)
     return true;
 }
 
+static bool
+intrinsic_NewMap(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 0);
+
+    Rooted map(cx, MapObject::create(cx));
+    if (!map)
+        return false;
+
+    args.rval().setObject(*map);
+    return true;
+}
+
 static bool
 intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -1287,6 +1310,36 @@ intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext* cx, unsigned arg
     return true;
 }
 
+static bool
+intrinsic_TypedArrayIsOutOfBounds(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+
+    RootedObject obj(cx, &args[0].toObject());
+    MOZ_ASSERT(obj->is());
+    args.rval().setBoolean(obj->as().isOutOfBounds());
+    return true;
+}
+
+static bool
+intrinsic_PossiblyWrappedTypedArrayIsOutOfBounds(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+    MOZ_ASSERT(args[0].isObject());
+
+    JSObject* obj = CheckedUnwrap(&args[0].toObject());
+    if (!obj) {
+        JS_ReportErrorASCII(cx, "Permission denied to access object");
+        return false;
+    }
+
+    MOZ_ASSERT(obj->is());
+    args.rval().setBoolean(obj->as().isOutOfBounds());
+    return true;
+}
+
 static bool
 intrinsic_MoveTypedArrayElements(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -1409,6 +1462,10 @@ intrinsic_SetFromTypedArrayApproach(JSContext* cx, unsigned argc, Value* vp)
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
+    if (unsafeTypedArrayCrossCompartment->isOutOfBounds()) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
+        return false;
+    }
 
     // Steps 21, 23.
     uint32_t unsafeSrcLengthCrossCompartment = unsafeTypedArrayCrossCompartment->length();
@@ -1492,9 +1549,22 @@ CopyValues(SharedMem dest, SharedMem src, uint32_t count)
 
     using namespace jit;
 
-    for (; count > 0; count--) {
-        AtomicOperations::storeSafeWhenRacy(dest++,
-                                            To(AtomicOperations::loadSafeWhenRacy(src++)));
+#if defined(_OPENMP)
+    const int64_t openMpCount = int64_t(count);
+    if (openMpCount >= (1 << 14)) {
+#pragma omp parallel for default(none) shared(dest, src, openMpCount) schedule(static)
+        for (int64_t i = 0; i < openMpCount; i++) {
+            uint32_t index = uint32_t(i);
+            AtomicOperations::storeSafeWhenRacy(dest + index,
+                                                To(AtomicOperations::loadSafeWhenRacy(src + index)));
+        }
+        return;
+    }
+#endif
+
+    for (uint32_t i = 0; i < count; i++) {
+        AtomicOperations::storeSafeWhenRacy(dest + i,
+                                            To(AtomicOperations::loadSafeWhenRacy(src + i)));
     }
 }
 
@@ -2255,7 +2325,10 @@ static const JSFunctionSpec intrinsic_functions[] = {
     JS_INLINABLE_FN("std_Math_min",              math_min,                     2,0, MathMin),
     JS_INLINABLE_FN("std_Math_abs",              math_abs,                     1,0, MathAbs),
 
+    JS_FN("std_Map_create",                      intrinsic_NewMap,             0,0),
+    JS_FN("std_Map_get",                         MapObject::get,               1,0),
     JS_FN("std_Map_has",                         MapObject::has,               1,0),
+    JS_FN("std_Map_set",                         MapObject::set,               2,0),
     JS_FN("std_Map_iterator",                    MapObject::entries,           0,0),
 
     JS_FN("std_Number_valueOf",                  num_valueOf,                  0,0),
@@ -2303,6 +2376,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
     // Helper funtions after this point.
     JS_INLINABLE_FN("ToObject",      intrinsic_ToObject,                1,0, IntrinsicToObject),
     JS_INLINABLE_FN("IsObject",      intrinsic_IsObject,                1,0, IntrinsicIsObject),
+    JS_FN("CanBeHeldWeakly",         intrinsic_CanBeHeldWeakly,         1,0),
     JS_INLINABLE_FN("IsArray",       intrinsic_IsArray,                 1,0, ArrayIsArray),
     JS_INLINABLE_FN("IsWrappedArrayConstructor", intrinsic_IsWrappedArrayConstructor, 1,0,
                     IntrinsicIsWrappedArrayConstructor),
@@ -2462,6 +2536,10 @@ static const JSFunctionSpec intrinsic_functions[] = {
                     1, 0, IntrinsicPossiblyWrappedTypedArrayLength),
     JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer",
           intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
+    JS_FN("TypedArrayIsOutOfBounds",
+          intrinsic_TypedArrayIsOutOfBounds, 1, 0),
+    JS_FN("PossiblyWrappedTypedArrayIsOutOfBounds",
+          intrinsic_PossiblyWrappedTypedArrayIsOutOfBounds, 1, 0),
 
     JS_FN("MoveTypedArrayElements",  intrinsic_MoveTypedArrayElements,  4,0),
     JS_FN("SetFromTypedArrayApproach",intrinsic_SetFromTypedArrayApproach, 4, 0),
diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp
index 6a3c6a91c3..a597564695 100644
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -8,6 +8,7 @@
 #include "mozilla/Atomics.h"
 
 #include "jsfriendapi.h"
+#include "jsnum.h"
 #include "jsprf.h"
 
 #ifdef XP_WIN
@@ -104,15 +105,18 @@ SharedArrayAllocSize(uint32_t length)
 }
 
 SharedArrayRawBuffer*
-SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
+SharedArrayRawBuffer::New(JSContext* cx, uint32_t length, uint32_t maxLength, bool growable)
 {
     // The value (uint32_t)-1 is used as a signal in various places,
     // so guard against it on principle.
     MOZ_ASSERT(length != (uint32_t)-1);
+    MOZ_ASSERT(maxLength != (uint32_t)-1);
+    MOZ_ASSERT(maxLength >= length);
 
     // Add a page for the header and round to a page boundary.
-    uint32_t allocSize = SharedArrayAllocSize(length);
-    if (allocSize <= length)
+    uint32_t allocationLength = growable ? maxLength : length;
+    uint32_t allocSize = SharedArrayAllocSize(allocationLength);
+    if (allocSize <= allocationLength)
         return nullptr;
 
     // Test >= to guard against the case where multiple extant runtimes
@@ -127,7 +131,8 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
         }
     }
 
-    bool preparedForAsmJS = jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length);
+    bool preparedForAsmJS =
+        !growable && jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length);
 
     void* p = nullptr;
     if (preparedForAsmJS) {
@@ -161,8 +166,9 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
 
     uint8_t* buffer = reinterpret_cast(p) + gc::SystemPageSize();
     uint8_t* base = buffer - sizeof(SharedArrayRawBuffer);
-    SharedArrayRawBuffer* rawbuf = new (base) SharedArrayRawBuffer(buffer, length, preparedForAsmJS);
-    MOZ_ASSERT(rawbuf->length == length); // Deallocation needs this
+    SharedArrayRawBuffer* rawbuf =
+        new (base) SharedArrayRawBuffer(buffer, length, maxLength, growable, preparedForAsmJS);
+    MOZ_ASSERT(rawbuf->allocatedByteLength() == allocationLength); // Deallocation needs this.
     return rawbuf;
 }
 
@@ -201,7 +207,7 @@ SharedArrayRawBuffer::dropReference()
     MOZ_ASSERT(p.asValue() % gc::SystemPageSize() == 0);
 
     uint8_t* address = p.unwrap(/*safe - only reference*/);
-    uint32_t allocSize = SharedArrayAllocSize(this->length);
+    uint32_t allocSize = SharedArrayAllocSize(this->allocatedByteLength());
 
     if (this->preparedForAsmJS) {
         uint32_t mappedSize = SharedArrayMappedSize(allocSize);
@@ -221,6 +227,23 @@ SharedArrayRawBuffer::dropReference()
     numLive--;
 }
 
+bool
+SharedArrayRawBuffer::growTo(uint32_t newLength)
+{
+    MOZ_ASSERT(growable);
+    MOZ_ASSERT(newLength <= maxLength);
+
+    for (;;) {
+        uint32_t oldLength = length;
+        if (newLength < oldLength)
+            return false;
+        if (newLength == oldLength)
+            return true;
+        if (length.compareExchange(oldLength, newLength))
+            return true;
+    }
+}
+
 
 MOZ_ALWAYS_INLINE bool
 SharedArrayBufferObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
@@ -237,6 +260,112 @@ SharedArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* v
     return CallNonGenericMethod(cx, args);
 }
 
+MOZ_ALWAYS_INLINE bool
+SharedArrayBufferObject::maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args)
+{
+    MOZ_ASSERT(IsSharedArrayBuffer(args.thisv()));
+    args.rval().setInt32(args.thisv().toObject().as().maxByteLength());
+    return true;
+}
+
+bool
+SharedArrayBufferObject::maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
+}
+
+MOZ_ALWAYS_INLINE bool
+SharedArrayBufferObject::growableGetterImpl(JSContext* cx, const CallArgs& args)
+{
+    MOZ_ASSERT(IsSharedArrayBuffer(args.thisv()));
+    args.rval().setBoolean(args.thisv().toObject().as().isGrowable());
+    return true;
+}
+
+bool
+SharedArrayBufferObject::growableGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
+}
+
+static bool
+ReportSharedArrayBufferNotGrowable(JSContext* cx)
+{
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_NOT_GROWABLE);
+    return false;
+}
+
+static bool
+ReportSharedArrayBufferLengthOutOfRange(JSContext* cx)
+{
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_BAD_LENGTH);
+    return false;
+}
+
+static bool
+GetSharedArrayBufferMaxByteLengthOption(JSContext* cx, HandleValue options,
+                                        uint32_t byteLength, uint32_t* maxByteLength,
+                                        bool* growable)
+{
+    *maxByteLength = byteLength;
+    *growable = false;
+
+    if (!options.isObject())
+        return true;
+
+    RootedObject opts(cx, &options.toObject());
+    RootedValue maxByteLengthValue(cx);
+    if (!GetProperty(cx, opts, opts, cx->names().maxByteLength, &maxByteLengthValue))
+        return false;
+
+    if (maxByteLengthValue.isUndefined())
+        return true;
+
+    uint64_t max;
+    if (!ToIndex(cx, maxByteLengthValue, &max))
+        return false;
+
+    if (max > INT32_MAX || max < byteLength)
+        return ReportSharedArrayBufferLengthOutOfRange(cx);
+
+    *maxByteLength = uint32_t(max);
+    *growable = true;
+    return true;
+}
+
+MOZ_ALWAYS_INLINE bool
+SharedArrayBufferObject::fun_grow_impl(JSContext* cx, const CallArgs& args)
+{
+    MOZ_ASSERT(IsSharedArrayBuffer(args.thisv()));
+
+    Rooted buffer(cx,
+        &args.thisv().toObject().as());
+    if (!buffer->isGrowable())
+        return ReportSharedArrayBufferNotGrowable(cx);
+
+    uint64_t newByteLength;
+    if (!ToIndex(cx, args.get(0), &newByteLength))
+        return false;
+    if (newByteLength > INT32_MAX)
+        return ReportSharedArrayBufferLengthOutOfRange(cx);
+
+    uint32_t newLength = uint32_t(newByteLength);
+    if (newLength > buffer->maxByteLength() || !buffer->growTo(newLength))
+        return ReportSharedArrayBufferLengthOutOfRange(cx);
+
+    args.rval().setUndefined();
+    return true;
+}
+
+bool
+SharedArrayBufferObject::fun_grow(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, args);
+}
+
 bool
 SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -245,11 +374,19 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value*
     if (!ThrowIfNotConstructing(cx, args, "SharedArrayBuffer"))
         return false;
 
+    uint64_t length64;
+    if (!ToIndex(cx, args.get(0), &length64))
+        return false;
     // Bugs 1068458, 1161298: Limit length to 2^31-1.
-    uint32_t length;
-    bool overflow_unused;
-    if (!ToLengthClamped(cx, args.get(0), &length, &overflow_unused) || length > INT32_MAX) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_BAD_LENGTH);
+    if (length64 > INT32_MAX)
+        return ReportSharedArrayBufferLengthOutOfRange(cx);
+    uint32_t length = uint32_t(length64);
+
+    uint32_t maxByteLength;
+    bool growable;
+    if (!GetSharedArrayBufferMaxByteLengthOption(cx, args.get(1), length,
+                                                 &maxByteLength, &growable))
+    {
         return false;
     }
 
@@ -258,7 +395,7 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value*
     if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
         return false;
 
-    JSObject* bufobj = New(cx, length, proto);
+    JSObject* bufobj = New(cx, length, maxByteLength, growable, proto);
     if (!bufobj)
         return false;
     args.rval().setObject(*bufobj);
@@ -266,9 +403,10 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value*
 }
 
 SharedArrayBufferObject*
-SharedArrayBufferObject::New(JSContext* cx, uint32_t length, HandleObject proto)
+SharedArrayBufferObject::New(JSContext* cx, uint32_t length, uint32_t maxLength, bool growable,
+                             HandleObject proto)
 {
-    SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length);
+    SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length, maxLength, growable);
     if (!buffer)
         return nullptr;
 
@@ -341,7 +479,7 @@ SharedArrayBufferObject::addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSi
     // just live with the risk.
     const SharedArrayBufferObject& buf = obj->as();
     info->objectsNonHeapElementsShared +=
-        buf.byteLength() / buf.rawBufferObject()->refcount();
+        buf.rawBufferObject()->allocatedByteLength() / buf.rawBufferObject()->refcount();
 }
 
 /* static */ void
@@ -409,12 +547,15 @@ static const JSPropertySpec static_properties[] = {
 };
 
 static const JSFunctionSpec prototype_functions[] = {
+    JS_FN("grow", SharedArrayBufferObject::fun_grow, 1, 0),
     JS_SELF_HOSTED_FN("slice", "SharedArrayBufferSlice", 2, 0),
     JS_FS_END
 };
 
 static const JSPropertySpec prototype_properties[] = {
     JS_PSG("byteLength", SharedArrayBufferObject::byteLengthGetter, 0),
+    JS_PSG("growable", SharedArrayBufferObject::growableGetter, 0),
+    JS_PSG("maxByteLength", SharedArrayBufferObject::maxByteLengthGetter, 0),
     JS_STRING_SYM_PS(toStringTag, "SharedArrayBuffer", JSPROP_READONLY),
     JS_PS_END
 };
diff --git a/js/src/vm/SharedArrayObject.h b/js/src/vm/SharedArrayObject.h
index 81fb49f3a8..01872aaff6 100644
--- a/js/src/vm/SharedArrayObject.h
+++ b/js/src/vm/SharedArrayObject.h
@@ -44,7 +44,9 @@ class SharedArrayRawBuffer
 {
   private:
     mozilla::Atomic refcount_;
-    uint32_t length;
+    mozilla::Atomic length;
+    uint32_t maxLength;
+    bool growable;
     bool preparedForAsmJS;
 
     // A list of structures representing tasks waiting on some
@@ -52,9 +54,12 @@ class SharedArrayRawBuffer
     FutexWaiter* waiters_;
 
   protected:
-    SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, bool preparedForAsmJS)
+    SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, uint32_t maxLength, bool growable,
+                         bool preparedForAsmJS)
       : refcount_(1),
         length(length),
+        maxLength(maxLength),
+        growable(growable),
         preparedForAsmJS(preparedForAsmJS),
         waiters_(nullptr)
     {
@@ -62,7 +67,11 @@ class SharedArrayRawBuffer
     }
 
   public:
-    static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length);
+    static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length, uint32_t maxLength,
+                                     bool growable);
+    static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length) {
+        return New(cx, length, length, false);
+    }
 
     // This may be called from multiple threads.  The caller must take
     // care of mutual exclusion.
@@ -85,6 +94,20 @@ class SharedArrayRawBuffer
         return length;
     }
 
+    uint32_t maxByteLength() const {
+        return growable ? maxLength : byteLength();
+    }
+
+    uint32_t allocatedByteLength() const {
+        return growable ? maxLength : byteLength();
+    }
+
+    bool isGrowable() const {
+        return growable;
+    }
+
+    [[nodiscard]] bool growTo(uint32_t newLength);
+
     bool isPreparedForAsmJS() const {
         return preparedForAsmJS;
     }
@@ -117,6 +140,9 @@ class SharedArrayRawBuffer
 class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
 {
     static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
+    static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
+    static bool growableGetterImpl(JSContext* cx, const CallArgs& args);
+    static bool fun_grow_impl(JSContext* cx, const CallArgs& args);
 
   public:
     // RAWBUF_SLOT holds a pointer (as "private" data) to the
@@ -128,13 +154,23 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
     static const Class class_;
 
     static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool growableGetter(JSContext* cx, unsigned argc, Value* vp);
+    static bool fun_grow(JSContext* cx, unsigned argc, Value* vp);
 
     static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
 
     // Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
     static SharedArrayBufferObject* New(JSContext* cx,
                                         uint32_t length,
+                                        uint32_t maxLength,
+                                        bool growable,
                                         HandleObject proto = nullptr);
+    static SharedArrayBufferObject* New(JSContext* cx,
+                                        uint32_t length,
+                                        HandleObject proto = nullptr) {
+        return New(cx, length, length, false, proto);
+    }
 
     // Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
     static SharedArrayBufferObject* New(JSContext* cx,
@@ -164,6 +200,15 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
     uint32_t byteLength() const {
         return rawBufferObject()->byteLength();
     }
+    uint32_t maxByteLength() const {
+        return rawBufferObject()->maxByteLength();
+    }
+    bool isGrowable() const {
+        return rawBufferObject()->isGrowable();
+    }
+    [[nodiscard]] bool growTo(uint32_t newLength) {
+        return rawBufferObject()->growTo(newLength);
+    }
     bool isPreparedForAsmJS() const {
         return rawBufferObject()->isPreparedForAsmJS();
     }
diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
index e1f1b2777e..50e6162923 100644
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -45,6 +45,7 @@
 #include "builtin/MapObject.h"
 #include "js/Date.h"
 #include "js/GCHashTable.h"
+#include "vm/ArrayBufferObject-inl.h"
 #include "vm/SavedFrame.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/TypedArrayObject.h"
diff --git a/js/src/vm/TypedArrayCommon.h b/js/src/vm/TypedArrayCommon.h
index fab7210417..056f8b52be 100644
--- a/js/src/vm/TypedArrayCommon.h
+++ b/js/src/vm/TypedArrayCommon.h
@@ -1065,16 +1065,40 @@ class TypedArrayMethods
             if (!ToInt32(cx, args[1], &offset))
                 return false;
 
-            if (offset < 0 || uint32_t(offset) > target->length()) {
-                // the given offset is bogus
+            if (offset < 0) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
                 return false;
             }
         }
 
+        if (target->hasDetachedBuffer()) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+            return false;
+        }
+        if (target->isOutOfBounds()) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
+            return false;
+        }
+
+        uint32_t targetLength = target->length();
+        if (uint32_t(offset) > targetLength) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+            return false;
+        }
+
         RootedObject arg0(cx, &args[0].toObject());
         if (arg0->is()) {
-            if (arg0->as().length() > target->length() - offset) {
+            Rooted source(cx, &arg0->as());
+            if (source->hasDetachedBuffer()) {
+                JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+                return false;
+            }
+            if (source->isOutOfBounds()) {
+                JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
+                return false;
+            }
+
+            if (source->length() > targetLength - offset) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
                 return false;
             }
@@ -1086,7 +1110,7 @@ class TypedArrayMethods
             if (!GetLengthProperty(cx, arg0, &len))
                 return false;
 
-            if (uint32_t(offset) > target->length() || len > target->length() - offset) {
+            if (len > targetLength - offset) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
                 return false;
             }
@@ -1099,13 +1123,32 @@ class TypedArrayMethods
         return true;
     }
 
-     static bool
-     setFromTypedArray(JSContext* cx, Handle target, HandleObject source,
-                       uint32_t offset = 0)
-     {
-         MOZ_ASSERT(source->is(), "use setFromNonTypedArray");
+    static bool
+    setFromTypedArray(JSContext* cx, Handle target, HandleObject source,
+                      uint32_t offset = 0)
+    {
+        MOZ_ASSERT(source->is(), "use setFromNonTypedArray");
 
-         bool isShared = target->isSharedMemory() || source->as().isSharedMemory();
+        if (target->hasDetachedBuffer()) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+            return false;
+        }
+        if (target->isOutOfBounds()) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
+            return false;
+        }
+
+        Rooted sourceArray(cx, &source->as());
+        if (sourceArray->hasDetachedBuffer()) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+            return false;
+        }
+        if (sourceArray->isOutOfBounds()) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
+            return false;
+        }
+
+        bool isShared = target->isSharedMemory() || sourceArray->isSharedMemory();
 
          switch (target->type()) {
            case Scalar::Int8:
diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp
index 3e9e82c844..22d21c8550 100644
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -484,8 +484,9 @@ class TypedArrayObjectTemplate : public TypedArrayObject
     }
 
     static TypedArrayObject*
-    makeInstance(JSContext* cx, Handle buffer, uint32_t byteOffset, uint32_t len,
-                 HandleObject proto)
+    makeInstance(JSContext* cx, Handle buffer,
+                 uint32_t byteOffset, uint32_t len, HandleObject proto,
+                 bool lengthTracking = false)
     {
         MOZ_ASSERT_IF(!buffer, byteOffset == 0);
 
@@ -510,12 +511,19 @@ class TypedArrayObjectTemplate : public TypedArrayObject
             return nullptr;
 
         bool isSharedMemory = buffer && IsSharedArrayBuffer(buffer.get());
+        bool hasResizableOrGrowableBuffer =
+            buffer &&
+            ((buffer->is() && buffer->as().isResizable()) ||
+             (buffer->is() &&
+              buffer->as().isGrowable()));
 
         obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectOrNullValue(buffer));
         // This is invariant.  Self-hosting code that sets BUFFER_SLOT
         // (if it does) must maintain it, should it need to.
         if (isSharedMemory)
             obj->setIsSharedMemory();
+        if (hasResizableOrGrowableBuffer)
+            obj->setHasResizableOrGrowableBuffer();
 
         if (buffer) {
             obj->initViewData(buffer->dataPointerEither() + byteOffset);
@@ -549,7 +557,9 @@ class TypedArrayObjectTemplate : public TypedArrayObject
 #endif
         }
 
-        obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(len));
+        obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT,
+                          Int32Value(lengthTracking ? TypedArrayObject::LENGTH_TRACKING
+                                                    : int32_t(len)));
         obj->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
 
 #ifdef DEBUG
@@ -898,6 +908,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
             return nullptr; // invalid byteOffset
         }
 
+        bool lengthTracking = false;
         uint32_t len;
         if (lengthInt == -1) {
             len = (buffer->byteLength() - byteOffset) / sizeof(NativeType);
@@ -906,6 +917,12 @@ class TypedArrayObjectTemplate : public TypedArrayObject
                                           JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
                 return nullptr; // given byte array doesn't map exactly to sizeof(NativeType) * N
             }
+            if ((buffer->is() && buffer->as().isResizable()) ||
+                (buffer->is() &&
+                 buffer->as().isGrowable()))
+            {
+                lengthTracking = true;
+            }
         } else {
             len = uint32_t(lengthInt);
         }
@@ -924,7 +941,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
             return nullptr; // byteOffset + len is too big for the arraybuffer
         }
 
-        return makeInstance(cx, buffer, byteOffset, len, proto);
+        return makeInstance(cx, buffer, byteOffset, len, proto, lengthTracking);
     }
 
     static bool
@@ -1320,6 +1337,10 @@ TypedArrayObjectTemplate::fromTypedArray(JSContext* cx, HandleObject other, b
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return nullptr;
     }
+    if (srcArray->isOutOfBounds()) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
+        return nullptr;
+    }
 
     // Step 9.
     uint32_t elementLength = srcArray->length();
@@ -1643,6 +1664,9 @@ TypedArrayObject::protoFunctions[] = {
     
     /* ES2022 additions */
     JS_SELF_HOSTED_FN("at", "TypedArrayAt", 1, 0),
+
+    /* ES2023 (WIP) */
+    JS_SELF_HOSTED_FN("toSorted", "TypedArrayToSorted", 1, 0),
     
     JS_FS_END
 };
@@ -1856,7 +1880,8 @@ DataViewNewObjectKind(JSContext* cx, uint32_t byteLength, JSObject* proto)
 
 DataViewObject*
 DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
-                       Handle arrayBuffer, JSObject* protoArg)
+                       Handle arrayBuffer, JSObject* protoArg,
+                       bool lengthTracking)
 {
     if (arrayBuffer->isDetached()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
@@ -1865,8 +1890,18 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
 
     MOZ_ASSERT(byteOffset <= INT32_MAX);
     MOZ_ASSERT(byteLength <= INT32_MAX);
-    MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX);
-    MOZ_ASSERT(!arrayBuffer || !arrayBuffer->is());
+
+    uint32_t bufferByteLength = arrayBuffer->byteLength();
+    if (byteOffset > bufferByteLength ||
+        (!lengthTracking && byteLength > bufferByteLength - byteOffset))
+    {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
+                                  "1");
+        return nullptr;
+    }
+
+    if (lengthTracking)
+        byteLength = bufferByteLength - byteOffset;
 
     RootedObject proto(cx, protoArg);
     RootedObject obj(cx);
@@ -1890,57 +1925,72 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
         }
     }
 
-    // Caller should have established these preconditions, and no
-    // (non-self-hosted) JS code has had an opportunity to run so nothing can
-    // have invalidated them.
     MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength());
     MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
 
     DataViewObject& dvobj = obj->as();
     dvobj.setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
-    dvobj.setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(byteLength));
+    dvobj.setFixedSlot(TypedArrayObject::LENGTH_SLOT,
+                       Int32Value(lengthTracking ? TypedArrayObject::LENGTH_TRACKING
+                                                 : int32_t(byteLength)));
     dvobj.setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*arrayBuffer));
-    dvobj.initPrivate(arrayBuffer->dataPointer() + byteOffset);
+    auto dataPointer = arrayBuffer->dataPointerEither();
+    dvobj.initPrivate((dataPointer + byteOffset).unwrap(/*safe - stored as private data*/));
 
     // Include a barrier if the data view's data pointer is in the nursery, as
     // is done for typed arrays.
-    if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(arrayBuffer->dataPointer()))
+    if (arrayBuffer->is() &&
+        !IsInsideNursery(obj) &&
+        cx->runtime()->gc.nursery.isInside(dataPointer))
+    {
         cx->runtime()->gc.storeBuffer.putWholeCell(obj);
+    }
 
     // Verify that the private slot is at the expected place
     MOZ_ASSERT(dvobj.numFixedSlots() == TypedArrayObject::DATA_SLOT);
 
-    if (!arrayBuffer->addView(cx, &dvobj))
-        return nullptr;
+    if (arrayBuffer->is()) {
+        if (!arrayBuffer->as().addView(cx, &dvobj))
+            return nullptr;
+    }
 
     return &dvobj;
 }
 
 bool
 DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
-                                           uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr)
+                                           uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr,
+                                           bool* lengthTrackingPtr)
 {
-    if (!IsArrayBuffer(bufobj)) {
+    if (!IsAnyArrayBuffer(bufobj)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
-                                  "DataView", "ArrayBuffer", bufobj->getClass()->name);
+                                  "DataView", "ArrayBuffer or SharedArrayBuffer",
+                                  bufobj->getClass()->name);
         return false;
     }
 
-    Rooted buffer(cx, &AsArrayBuffer(bufobj));
+    Rooted buffer(cx, &bufobj->as());
     uint32_t byteOffset = 0;
     uint32_t byteLength = buffer->byteLength();
+    bool isResizableOrGrowable =
+        (buffer->is() && buffer->as().isResizable()) ||
+        (buffer->is() &&
+         buffer->as().isGrowable());
+    bool lengthTracking = isResizableOrGrowable && !args.hasDefined(2);
 
     if (args.length() > 1) {
-        if (!ToUint32(cx, args[1], &byteOffset))
+        uint64_t offset;
+        if (!ToIndex(cx, args[1], &offset))
             return false;
-        if (byteOffset > INT32_MAX) {
+        if (offset > INT32_MAX) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
                                       "1");
             return false;
         }
+        byteOffset = uint32_t(offset);
     }
 
-    if (buffer->isDetached()) {
+    if (buffer->is() && buffer->as().isDetached()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
@@ -1954,14 +2004,18 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons
 
         if (args.get(2).isUndefined()) {
             byteLength -= byteOffset;
+            lengthTracking = isResizableOrGrowable;
         } else {
-            if (!ToUint32(cx, args[2], &byteLength))
+            uint64_t viewByteLength;
+            if (!ToIndex(cx, args[2], &viewByteLength))
                 return false;
-            if (byteLength > INT32_MAX) {
+            lengthTracking = false;
+            if (viewByteLength > INT32_MAX) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                           JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
                 return false;
             }
+            byteLength = uint32_t(viewByteLength);
 
             MOZ_ASSERT(byteOffset + byteLength >= byteOffset,
                        "can't overflow: both numbers are less than INT32_MAX");
@@ -1980,6 +2034,7 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons
 
     *byteOffsetPtr = byteOffset;
     *byteLengthPtr = byteLength;
+    *lengthTrackingPtr = lengthTracking;
 
     return true;
 }
@@ -1991,7 +2046,8 @@ DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, con
     assertSameCompartment(cx, bufobj);
 
     uint32_t byteOffset, byteLength;
-    if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength))
+    bool lengthTracking;
+    if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength, &lengthTracking))
         return false;
 
     RootedObject proto(cx);
@@ -1999,8 +2055,9 @@ DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, con
     if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
         return false;
 
-    Rooted buffer(cx, &AsArrayBuffer(bufobj));
-    JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
+    Rooted buffer(cx, &bufobj->as());
+    JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto,
+                                           lengthTracking);
     if (!obj)
         return false;
     args.rval().setObject(*obj);
@@ -2040,8 +2097,12 @@ DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallA
 
     // NB: This entails the IsArrayBuffer check
     uint32_t byteOffset, byteLength;
-    if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength))
+    bool lengthTracking;
+    if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength,
+                                    &lengthTracking))
+    {
         return false;
+    }
 
     // Make sure to get the [[Prototype]] for the created view from this
     // compartment.
@@ -2057,11 +2118,12 @@ DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallA
             return false;
     }
 
-    FixedInvokeArgs<3> args2(cx);
+    FixedInvokeArgs<4> args2(cx);
 
     args2[0].set(PrivateUint32Value(byteOffset));
     args2[1].set(PrivateUint32Value(byteLength));
     args2[2].setObject(*proto);
+    args2[3].setBoolean(lengthTracking);
 
     RootedValue fval(cx, global->createDataViewForThis());
     RootedValue thisv(cx, ObjectValue(*bufobj));
@@ -2089,6 +2151,11 @@ template 
 /* static */ uint8_t*
 DataViewObject::getDataPointer(JSContext* cx, Handle obj, uint64_t offset)
 {
+    if (obj->isOutOfBounds()) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS);
+        return nullptr;
+    }
+
     const size_t TypeSize = sizeof(NativeType);
     if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
@@ -2252,7 +2319,7 @@ DataViewObject::read(JSContext* cx, Handle obj,
     bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
 
     // Steps 6-7.
-    if (obj->arrayBuffer().isDetached()) {
+    if (obj->arrayBufferEither().isDetached()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
@@ -2351,7 +2418,7 @@ DataViewObject::write(JSContext* cx, Handle obj,
     bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
 
     // Steps 7-8.
-    if (obj->arrayBuffer().isDetached()) {
+    if (obj->arrayBufferEither().isDetached()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
@@ -3176,7 +3243,13 @@ template
 bool
 DataViewObject::getterImpl(JSContext* cx, const CallArgs& args)
 {
-    args.rval().set(ValueGetter(&args.thisv().toObject().as()));
+    Rooted view(cx, &args.thisv().toObject().as());
+    if (ValueGetter != bufferValue && view->isOutOfBounds()) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS);
+        return false;
+    }
+
+    args.rval().set(ValueGetter(view));
     return true;
 }
 
diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h
index 8b4b0b5092..8c08bb870e 100644
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -52,6 +52,8 @@ class TypedArrayObject : public NativeObject
                   "right buffer slot");
 
     // Slot containing length of the view in number of typed elements.
+    // Length-tracking views on resizable/growable buffers store
+    // LENGTH_TRACKING here and compute their visible length from the buffer.
     static const size_t LENGTH_SLOT = 1;
     static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT,
                   "self-hosted code with burned-in constants must get the "
@@ -65,6 +67,8 @@ class TypedArrayObject : public NativeObject
 
     static const size_t RESERVED_SLOTS = 3;
 
+    static const int32_t LENGTH_TRACKING = -1;
+
 #ifdef DEBUG
     static const uint8_t ZeroLengthArrayData = 0x4A;
 #endif
@@ -139,15 +143,13 @@ class TypedArrayObject : public NativeObject
         return tarr->getFixedSlot(BUFFER_SLOT);
     }
     static Value byteOffsetValue(TypedArrayObject* tarr) {
-        Value v = tarr->getFixedSlot(BYTEOFFSET_SLOT);
-        MOZ_ASSERT(v.toInt32() >= 0);
-        return v;
+        return Int32Value(tarr->byteOffset());
     }
     static Value byteLengthValue(TypedArrayObject* tarr) {
-        return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * tarr->bytesPerElement());
+        return Int32Value(tarr->byteLength());
     }
     static Value lengthValue(TypedArrayObject* tarr) {
-        return tarr->getFixedSlot(LENGTH_SLOT);
+        return Int32Value(tarr->length());
     }
 
     static bool
@@ -159,14 +161,70 @@ class TypedArrayObject : public NativeObject
     JSObject* bufferObject() const {
         return bufferValue(const_cast(this)).toObjectOrNull();
     }
+    bool isLengthTracking() const {
+        return getFixedSlot(LENGTH_SLOT).toInt32() == LENGTH_TRACKING;
+    }
+    bool hasResizableOrGrowableBuffer() const {
+        if (!hasBuffer())
+            return false;
+        if (isSharedMemory())
+            return bufferShared()->isGrowable();
+        return bufferUnshared()->isResizable();
+    }
+    uint32_t byteOffsetMaybeOutOfBounds() const {
+        Value v = getFixedSlot(BYTEOFFSET_SLOT);
+        MOZ_ASSERT(v.toInt32() >= 0);
+        return v.toInt32();
+    }
+    uint32_t fixedLengthMaybeOutOfBounds() const {
+        int32_t length = getFixedSlot(LENGTH_SLOT).toInt32();
+        MOZ_ASSERT(length >= 0);
+        return length;
+    }
+    uint32_t bufferByteLength() const {
+        MOZ_ASSERT(hasBuffer());
+        if (isSharedMemory())
+            return bufferShared()->byteLength();
+        return bufferUnshared()->byteLength();
+    }
+    bool isOutOfBounds() const {
+        if (!hasBuffer())
+            return false;
+        if (hasDetachedBuffer())
+            return true;
+
+        uint32_t bufferByteLength = this->bufferByteLength();
+        uint32_t offset = byteOffsetMaybeOutOfBounds();
+        if (offset > bufferByteLength)
+            return true;
+
+        if (isLengthTracking())
+            return false;
+
+        uint32_t byteLength = fixedLengthMaybeOutOfBounds() * bytesPerElement();
+        return byteLength > bufferByteLength - offset;
+    }
     uint32_t byteOffset() const {
-        return byteOffsetValue(const_cast(this)).toInt32();
+        if (isOutOfBounds())
+            return 0;
+        return byteOffsetMaybeOutOfBounds();
     }
     uint32_t byteLength() const {
-        return byteLengthValue(const_cast(this)).toInt32();
+        return length() * bytesPerElement();
     }
     uint32_t length() const {
-        return lengthValue(const_cast(this)).toInt32();
+        if (!isLengthTracking()) {
+            if (isOutOfBounds())
+                return 0;
+            return fixedLengthMaybeOutOfBounds();
+        }
+
+        if (isOutOfBounds())
+            return 0;
+
+        uint32_t bufferByteLength = this->bufferByteLength();
+        uint32_t offset = byteOffsetMaybeOutOfBounds();
+        return (bufferByteLength - offset) / bytesPerElement();
     }
 
     bool hasInlineElements() const;
@@ -466,28 +524,26 @@ class DataViewObject : public NativeObject
     defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto);
 
     static bool getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
-                                           uint32_t *byteOffset, uint32_t* byteLength);
+                                           uint32_t *byteOffset, uint32_t* byteLength,
+                                           bool* lengthTracking);
     static bool constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args);
     static bool constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args);
 
     friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
     static DataViewObject*
     create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
-           Handle arrayBuffer, JSObject* proto);
+           Handle arrayBuffer, JSObject* proto,
+           bool lengthTracking = false);
 
   public:
     static const Class class_;
 
     static Value byteOffsetValue(DataViewObject* view) {
-        Value v = view->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT);
-        MOZ_ASSERT(v.toInt32() >= 0);
-        return v;
+        return Int32Value(view->byteOffset());
     }
 
     static Value byteLengthValue(DataViewObject* view) {
-        Value v = view->getFixedSlot(TypedArrayObject::LENGTH_SLOT);
-        MOZ_ASSERT(v.toInt32() >= 0);
-        return v;
+        return Int32Value(view->byteLength());
     }
 
     static Value bufferValue(DataViewObject* view) {
@@ -495,21 +551,66 @@ class DataViewObject : public NativeObject
     }
 
     uint32_t byteOffset() const {
-        return byteOffsetValue(const_cast(this)).toInt32();
+        if (isOutOfBounds())
+            return 0;
+        return byteOffsetMaybeOutOfBounds();
     }
 
     uint32_t byteLength() const {
-        return byteLengthValue(const_cast(this)).toInt32();
+        if (isOutOfBounds())
+            return 0;
+        if (isLengthTracking())
+            return arrayBufferEither().byteLength() - byteOffsetMaybeOutOfBounds();
+        return fixedByteLengthMaybeOutOfBounds();
     }
 
-    ArrayBufferObject& arrayBuffer() const {
-        return bufferValue(const_cast(this)).toObject().as();
+    ArrayBufferObjectMaybeShared& arrayBufferEither() const {
+        return bufferValue(const_cast(this)).
+               toObject().as();
+    }
+
+    bool isSharedMemory() const {
+        return bufferValue(const_cast(this)).
+               toObject().is();
     }
 
     void* dataPointer() const {
         return getPrivate();
     }
 
+    bool isLengthTracking() const {
+        return getFixedSlot(TypedArrayObject::LENGTH_SLOT).toInt32() ==
+               TypedArrayObject::LENGTH_TRACKING;
+    }
+
+    uint32_t byteOffsetMaybeOutOfBounds() const {
+        Value v = getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT);
+        MOZ_ASSERT(v.toInt32() >= 0);
+        return v.toInt32();
+    }
+
+    uint32_t fixedByteLengthMaybeOutOfBounds() const {
+        int32_t length = getFixedSlot(TypedArrayObject::LENGTH_SLOT).toInt32();
+        MOZ_ASSERT(length >= 0);
+        return length;
+    }
+
+    bool isOutOfBounds() const {
+        const ArrayBufferObjectMaybeShared& buffer = arrayBufferEither();
+        if (buffer.isDetached())
+            return true;
+
+        uint32_t bufferByteLength = buffer.byteLength();
+        uint32_t offset = byteOffsetMaybeOutOfBounds();
+        if (offset > bufferByteLength)
+            return true;
+
+        if (isLengthTracking())
+            return false;
+
+        return fixedByteLengthMaybeOutOfBounds() > bufferByteLength - offset;
+    }
+
     static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
 
     static bool getInt8Impl(JSContext* cx, const CallArgs& args);
diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp
index f93ef18034..643757cd26 100644
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -109,6 +109,9 @@
 #if defined(JS_CODEGEN_ARM)
 # include "jit/arm/Assembler-arm.h"
 #endif
+#if defined(JS_CODEGEN_LOONGARCH64)
+# include "jit/loongarch64/Assembler-loongarch64.h"
+#endif
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
 # include "jit/x86-shared/Architecture-x86-shared.h"
 # include "jit/x86-shared/Assembler-x86-shared.h"
@@ -218,7 +221,8 @@ class BaseCompiler
     // We define our own ScratchRegister abstractions, deferring to
     // the platform's when possible.
 
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || \
+    defined(JS_CODEGEN_LOONGARCH64)
     typedef ScratchDoubleScope ScratchF64;
 #else
     class ScratchF64
@@ -231,7 +235,8 @@ class BaseCompiler
     };
 #endif
 
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || \
+    defined(JS_CODEGEN_LOONGARCH64)
     typedef ScratchFloat32Scope ScratchF32;
 #else
     class ScratchF32
@@ -246,7 +251,7 @@ class BaseCompiler
 
 #if defined(JS_CODEGEN_X64)
     typedef ScratchRegisterScope ScratchI32;
-#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_LOONGARCH64)
     class ScratchI32
     {
 # ifdef DEBUG
@@ -267,8 +272,10 @@ class BaseCompiler
         operator Register() const {
 # ifdef JS_CODEGEN_X86
             return ScratchRegX86;
-# else
+# elif defined(JS_CODEGEN_ARM)
             return ScratchRegARM;
+# else
+            return ScratchRegister;
 # endif
         }
     };
@@ -1096,7 +1103,11 @@ class BaseCompiler
     }
 
     void loadConstI32(Register r, Stk& src) {
+#if defined(JS_CODEGEN_LOONGARCH64)
+        masm.move32(Imm32(src.i32val()), r);
+#else
         masm.mov(ImmWord((uint32_t)src.i32val() & 0xFFFFFFFFU), r);
+#endif
     }
 
     void loadMemI32(Register r, Stk& src) {
@@ -1822,21 +1833,24 @@ class BaseCompiler
             Stk& v = stk_[i];
             switch (v.kind()) {
               case Stk::MemI32:
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || \
+    defined(JS_CODEGEN_LOONGARCH64)
                 size += sizeof(intptr_t);
 #else
                 MOZ_CRASH("BaseCompiler platform hook: stackConsumed I32");
 #endif
                 break;
               case Stk::MemI64:
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || \
+    defined(JS_CODEGEN_LOONGARCH64)
                 size += sizeof(int64_t);
 #else
                 MOZ_CRASH("BaseCompiler platform hook: stackConsumed I64");
 #endif
                 break;
               case Stk::MemF64:
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || \
+    defined(JS_CODEGEN_LOONGARCH64)
                 size += sizeof(double);
 #else
                 MOZ_CRASH("BaseCompiler platform hook: stackConsumed F64");
@@ -1845,7 +1859,7 @@ class BaseCompiler
               case Stk::MemF32:
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
                 size += sizeof(double);
-#elif defined(JS_CODEGEN_ARM)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_LOONGARCH64)
                 size += sizeof(float);
 #else
                 MOZ_CRASH("BaseCompiler platform hook: stackConsumed F32");
@@ -2241,6 +2255,9 @@ class BaseCompiler
                 masm.store32(scratch, Address(StackPointer, argLoc.offsetFromArgBase() + INT64LOW_OFFSET));
                 loadI64High(scratch, arg);
                 masm.store32(scratch, Address(StackPointer, argLoc.offsetFromArgBase() + INT64HIGH_OFFSET));
+#elif defined(JS_CODEGEN_LOONGARCH64)
+                loadI64(Register64(scratch), arg);
+                masm.store64(Register64(scratch), Address(StackPointer, argLoc.offsetFromArgBase()));
 #else
                 MOZ_CRASH("BaseCompiler platform hook: passArg I64");
 #endif
@@ -2394,6 +2411,18 @@ class BaseCompiler
             cl.target()->bind(labels[i]->offset());
             masm.addCodeLabel(cl);
         }
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        for (uint32_t i = 0; i < labels.length(); i++) {
+            CodeLabel cl;
+            masm.ma_li(ScratchRegister, cl.patchAt());
+            masm.jump(ScratchRegister);
+            masm.as_nop();
+            masm.as_nop();
+            masm.as_nop();
+            masm.as_nop();
+            cl.target()->bind(labels[i]->offset());
+            masm.addCodeLabel(cl);
+        }
 #else
         MOZ_CRASH("BaseCompiler platform hook: jumpTable");
 #endif
@@ -2430,6 +2459,17 @@ class BaseCompiler
         // Jump indirect via table element
         masm.ma_ldr(DTRAddr(scratch, DtrRegImmShift(switchValue.reg, LSL, 2)), pc, Offset,
                     Assembler::Always);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        ScratchI32 scratch(*this);
+        CodeLabel tableCl;
+
+        masm.ma_li(scratch, tableCl.patchAt());
+        tableCl.target()->bind(theTable->offset());
+        masm.addCodeLabel(tableCl);
+
+        masm.lshiftPtr(Imm32(5), switchValue.reg);
+        masm.addPtr(switchValue.reg, scratch);
+        masm.jump(scratch);
 #else
         MOZ_CRASH("BaseCompiler platform hook: tableSwitch");
 #endif
@@ -2585,6 +2625,11 @@ class BaseCompiler
             masm.cqo();
             masm.idivq(rhs.reg.reg);
         }
+# elif defined(JS_CODEGEN_LOONGARCH64)
+        if (isUnsigned)
+            masm.as_div_du(srcDest.reg.reg, srcDest.reg.reg, rhs.reg.reg);
+        else
+            masm.as_div_d(srcDest.reg.reg, srcDest.reg.reg, rhs.reg.reg);
 # else
         MOZ_CRASH("BaseCompiler platform hook: quotientI64");
 # endif
@@ -2612,6 +2657,11 @@ class BaseCompiler
             masm.idivq(rhs.reg.reg);
         }
         masm.movq(rdx, rax);
+# elif defined(JS_CODEGEN_LOONGARCH64)
+        if (isUnsigned)
+            masm.as_mod_du(srcDest.reg.reg, srcDest.reg.reg, rhs.reg.reg);
+        else
+            masm.as_mod_d(srcDest.reg.reg, srcDest.reg.reg, rhs.reg.reg);
 # else
         MOZ_CRASH("BaseCompiler platform hook: remainderI64");
 # endif
@@ -2648,7 +2698,7 @@ class BaseCompiler
     bool popcnt32NeedsTemp() const {
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
         return !AssemblerX86Shared::HasPOPCNT();
-#elif defined(JS_CODEGEN_ARM)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_LOONGARCH64)
         return true;
 #else
         MOZ_CRASH("BaseCompiler platform hook: popcnt32NeedsTemp");
@@ -2658,7 +2708,7 @@ class BaseCompiler
     bool popcnt64NeedsTemp() const {
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
         return !AssemblerX86Shared::HasPOPCNT();
-#elif defined(JS_CODEGEN_ARM)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_LOONGARCH64)
         return true;
 #else
         MOZ_CRASH("BaseCompiler platform hook: popcnt64NeedsTemp");
@@ -2675,6 +2725,8 @@ class BaseCompiler
         masm.freeStack(sizeof(uint64_t));
 #elif defined(JS_CODEGEN_ARM)
         masm.ma_vxfer(src.reg.low, src.reg.high, dest.reg);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        masm.moveToDouble(src.reg.reg, dest.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: reinterpretI64AsF64");
 #endif
@@ -2690,6 +2742,8 @@ class BaseCompiler
         masm.Pop(dest.reg.high);
 #elif defined(JS_CODEGEN_ARM)
         masm.ma_vxfer(src.reg, dest.reg.low, dest.reg.high);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        masm.moveFromDouble(src.reg, dest.reg.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: reinterpretF64AsI64");
 #endif
@@ -2701,6 +2755,8 @@ class BaseCompiler
         masm.movl(src.reg.reg, dest.reg);
 #elif defined(JS_NUNBOX32)
         masm.move32(src.reg.low, dest.reg);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        masm.move32(src.reg.reg, dest.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: wrapI64ToI32");
 #endif
@@ -2735,6 +2791,8 @@ class BaseCompiler
 #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
         masm.move8SignExtend(r.reg.low, r.reg.low);
         signExtendI32ToI64(RegI32(r.reg.low), r);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        masm.move8SignExtend(r.reg.reg, r.reg.reg);
 #else
         MOZ_CRASH("Basecompiler platform hook: signExtendI64_8");
 #endif
@@ -2746,6 +2804,8 @@ class BaseCompiler
 #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
         masm.move16SignExtend(r.reg.low, r.reg.low);
         signExtendI32ToI64(RegI32(r.reg.low), r);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        masm.move16SignExtend(r.reg.reg, r.reg.reg);
 #else
         MOZ_CRASH("Basecompiler platform hook: signExtendI64_16");
 #endif
@@ -2762,6 +2822,8 @@ class BaseCompiler
 #elif defined(JS_CODEGEN_ARM)
         masm.ma_mov(src.reg, dest.reg.low);
         masm.ma_asr(Imm32(31), src.reg, dest.reg.high);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        masm.move32(src.reg, dest.reg.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: signExtendI32ToI64");
 #endif
@@ -2773,6 +2835,8 @@ class BaseCompiler
 #elif defined(JS_NUNBOX32)
         masm.move32(src.reg, dest.reg.low);
         masm.move32(Imm32(0), dest.reg.high);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        masm.as_bstrpick_d(dest.reg.reg, src.reg, 31, 0);
 #else
         MOZ_CRASH("BaseCompiler platform hook: extendU32ToI64");
 #endif
@@ -2825,6 +2889,78 @@ class BaseCompiler
         }
     };
 
+#if defined(JS_CODEGEN_LOONGARCH64)
+    void truncateDoubleToI32LoongArch(FloatRegister input, RegI32 dest, bool isUnsigned) {
+        branchDoubleToTrap(Assembler::DoubleUnordered, input, input,
+                           Trap::InvalidConversionToInteger);
+        masm.loadConstantDouble(isUnsigned ? -1.0 : double(INT32_MIN) - 1.0, ScratchDoubleReg);
+        branchDoubleToTrap(isUnsigned ? Assembler::DoubleLessThanOrEqual
+                                      : Assembler::DoubleLessThanOrEqual,
+                           input, ScratchDoubleReg, Trap::IntegerOverflow);
+        masm.loadConstantDouble(isUnsigned ? double(UINT32_MAX) + 1.0
+                                           : double(INT32_MAX) + 1.0,
+                                ScratchDoubleReg);
+        branchDoubleToTrap(Assembler::DoubleGreaterThanOrEqual, input,
+                           ScratchDoubleReg, Trap::IntegerOverflow);
+
+        if (isUnsigned) {
+            masm.as_truncld(ScratchDoubleReg, input);
+            masm.moveFromFloat32(ScratchDoubleReg, dest.reg);
+        } else {
+            masm.as_truncwd(ScratchFloat32Reg, input);
+            masm.moveFromFloat32(ScratchFloat32Reg, dest.reg);
+        }
+    }
+
+    void truncateDoubleToI64LoongArch(FloatRegister input, RegI64 dest, bool isUnsigned) {
+        branchDoubleToTrap(Assembler::DoubleUnordered, input, input,
+                           Trap::InvalidConversionToInteger);
+        masm.loadConstantDouble(isUnsigned ? -1.0 : double(INT64_MIN), ScratchDoubleReg);
+        branchDoubleToTrap(isUnsigned ? Assembler::DoubleLessThanOrEqual
+                                      : Assembler::DoubleLessThan,
+                           input, ScratchDoubleReg, Trap::IntegerOverflow);
+
+        if (isUnsigned) {
+            Label isLarge, done;
+
+            masm.loadConstantDouble(double(UINT64_MAX), ScratchDoubleReg);
+            branchDoubleToTrap(Assembler::DoubleGreaterThanOrEqual, input,
+                               ScratchDoubleReg, Trap::IntegerOverflow);
+
+            masm.loadConstantDouble(double(INT64_MAX), ScratchDoubleReg);
+            masm.ma_bc1d(ScratchDoubleReg, input, &isLarge,
+                         Assembler::DoubleLessThanOrEqual, ShortJump);
+
+            masm.as_truncld(ScratchDoubleReg, input);
+            masm.moveFromDouble(ScratchDoubleReg, dest.reg.reg);
+            masm.ma_b(&done, ShortJump);
+
+            masm.bind(&isLarge);
+            masm.as_subd(ScratchDoubleReg, input, ScratchDoubleReg);
+            masm.as_truncld(ScratchDoubleReg, ScratchDoubleReg);
+            masm.moveFromDouble(ScratchDoubleReg, dest.reg.reg);
+            masm.ma_li(ScratchRegister, Imm32(1));
+            masm.ma_dins(dest.reg.reg, ScratchRegister, Imm32(63), Imm32(1));
+
+            masm.bind(&done);
+            return;
+        }
+
+        masm.loadConstantDouble(double(INT64_MAX), ScratchDoubleReg);
+        branchDoubleToTrap(Assembler::DoubleGreaterThanOrEqual, input,
+                           ScratchDoubleReg, Trap::IntegerOverflow);
+        masm.as_truncld(ScratchDoubleReg, input);
+        masm.moveFromDouble(ScratchDoubleReg, dest.reg.reg);
+    }
+
+    void branchDoubleToTrap(Assembler::DoubleCondition cond, FloatRegister lhs,
+                            FloatRegister rhs, Trap trapKind) {
+        Label trapLabel;
+        masm.branchDouble(cond, lhs, rhs, &trapLabel);
+        masm.bindLater(&trapLabel, trap(trapKind));
+    }
+#endif
+
     MOZ_MUST_USE bool truncateF32ToI32(RegF32 src, RegI32 dest, bool isUnsigned) {
         TrapOffset off = trapOffset();
         OutOfLineCode* ool;
@@ -2845,6 +2981,12 @@ class BaseCompiler
                 masm.wasmTruncateFloat32ToUInt32(src.reg, dest.reg, ool->entry());
             else
                 masm.wasmTruncateFloat32ToInt32(src.reg, dest.reg, ool->entry());
+#elif defined(JS_CODEGEN_LOONGARCH64)
+            RegF64 doubleInput = needF64();
+            masm.convertFloat32ToDouble(src.reg, doubleInput.reg);
+            truncateDoubleToI32LoongArch(doubleInput.reg, dest, isUnsigned);
+            freeF64(doubleInput);
+            return true;
 #else
             MOZ_CRASH("BaseCompiler platform hook: truncateF32ToI32 wasm");
 #endif
@@ -2873,6 +3015,9 @@ class BaseCompiler
                 masm.wasmTruncateDoubleToUInt32(src.reg, dest.reg, ool->entry());
             else
                 masm.wasmTruncateDoubleToInt32(src.reg, dest.reg, ool->entry());
+#elif defined(JS_CODEGEN_LOONGARCH64)
+            truncateDoubleToI32LoongArch(src.reg, dest, isUnsigned);
+            return true;
 #else
             MOZ_CRASH("BaseCompiler platform hook: truncateF64ToI32 wasm");
 #endif
@@ -2937,6 +3082,11 @@ class BaseCompiler
         else
             masm.wasmTruncateFloat32ToInt64(src.reg, dest.reg, ool->entry(),
                                             ool->rejoin(), temp.reg);
+# elif defined(JS_CODEGEN_LOONGARCH64)
+        RegF64 doubleInput = needF64();
+        masm.convertFloat32ToDouble(src.reg, doubleInput.reg);
+        truncateDoubleToI64LoongArch(doubleInput.reg, dest, isUnsigned);
+        freeF64(doubleInput);
 # else
         MOZ_CRASH("BaseCompiler platform hook: truncateF32ToI64");
 # endif
@@ -2957,6 +3107,8 @@ class BaseCompiler
         else
             masm.wasmTruncateDoubleToInt64(src.reg, dest.reg, ool->entry(),
                                            ool->rejoin(), temp.reg);
+# elif defined(JS_CODEGEN_LOONGARCH64)
+        truncateDoubleToI64LoongArch(src.reg, dest, isUnsigned);
 # else
         MOZ_CRASH("BaseCompiler platform hook: truncateF64ToI64");
 # endif
@@ -2979,6 +3131,11 @@ class BaseCompiler
             masm.convertUInt64ToFloat32(src.reg, dest.reg, temp.reg);
         else
             masm.convertInt64ToFloat32(src.reg, dest.reg);
+# elif defined(JS_CODEGEN_LOONGARCH64)
+        if (isUnsigned)
+            masm.convertUInt64ToFloat32(src.reg.reg, dest.reg);
+        else
+            masm.convertInt64ToFloat32(src.reg.reg, dest.reg);
 # else
         MOZ_CRASH("BaseCompiler platform hook: convertI64ToF32");
 # endif
@@ -2990,6 +3147,11 @@ class BaseCompiler
             masm.convertUInt64ToDouble(src.reg, dest.reg, temp.reg);
         else
             masm.convertInt64ToDouble(src.reg, dest.reg);
+# elif defined(JS_CODEGEN_LOONGARCH64)
+        if (isUnsigned)
+            masm.convertUInt64ToDouble(src.reg, dest.reg, temp.reg);
+        else
+            masm.convertInt64ToDouble(src.reg.reg, dest.reg);
 # else
         MOZ_CRASH("BaseCompiler platform hook: convertI64ToF64");
 # endif
@@ -3000,7 +3162,7 @@ class BaseCompiler
 #if defined(JS_CODEGEN_X64)
         masm.cmpq(rhs.reg.reg, lhs.reg.reg);
         masm.emitSet(cond, dest.reg);
-#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_LOONGARCH64)
         // TODO / OPTIMIZE (Bug 1316822): This is pretty branchy, we should be
         // able to do better.
         Label done, condTrue;
@@ -3041,6 +3203,9 @@ class BaseCompiler
         ScratchRegisterScope scratch(*this); // Really must be the ARM scratchreg
         unsigned addr = globalDataOffset - WasmGlobalRegBias;
         masm.ma_dtr(js::jit::IsLoad, GlobalReg, Imm32(addr), r.reg, scratch);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        unsigned addr = globalDataOffset - WasmGlobalRegBias;
+        masm.load32(Address(GlobalReg, addr), r.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: loadGlobalVarI32");
 #endif
@@ -3062,6 +3227,9 @@ class BaseCompiler
         masm.ma_dtr(js::jit::IsLoad, GlobalReg, Imm32(addr + INT64LOW_OFFSET), r.reg.low, scratch);
         masm.ma_dtr(js::jit::IsLoad, GlobalReg, Imm32(addr + INT64HIGH_OFFSET), r.reg.high,
                     scratch);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        unsigned addr = globalDataOffset - WasmGlobalRegBias;
+        masm.load64(Address(GlobalReg, addr), r.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: loadGlobalVarI64");
 #endif
@@ -3079,6 +3247,9 @@ class BaseCompiler
         unsigned addr = globalDataOffset - WasmGlobalRegBias;
         VFPRegister vd(r.reg);
         masm.ma_vldr(VFPAddr(GlobalReg, VFPOffImm(addr)), vd.singleOverlay());
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        unsigned addr = globalDataOffset - WasmGlobalRegBias;
+        masm.loadFloat32(Address(GlobalReg, addr), r.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: loadGlobalVarF32");
 #endif
@@ -3095,6 +3266,9 @@ class BaseCompiler
 #elif defined(JS_CODEGEN_ARM)
         unsigned addr = globalDataOffset - WasmGlobalRegBias;
         masm.ma_vldr(VFPAddr(GlobalReg, VFPOffImm(addr)), r.reg);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        unsigned addr = globalDataOffset - WasmGlobalRegBias;
+        masm.loadDouble(Address(GlobalReg, addr), r.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: loadGlobalVarF64");
 #endif
@@ -3114,6 +3288,9 @@ class BaseCompiler
         ScratchRegisterScope scratch(*this); // Really must be the ARM scratchreg
         unsigned addr = globalDataOffset - WasmGlobalRegBias;
         masm.ma_dtr(js::jit::IsStore, GlobalReg, Imm32(addr), r.reg, scratch);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        unsigned addr = globalDataOffset - WasmGlobalRegBias;
+        masm.store32(r.reg, Address(GlobalReg, addr));
 #else
         MOZ_CRASH("BaseCompiler platform hook: storeGlobalVarI32");
 #endif
@@ -3135,6 +3312,9 @@ class BaseCompiler
         masm.ma_dtr(js::jit::IsStore, GlobalReg, Imm32(addr + INT64LOW_OFFSET), r.reg.low, scratch);
         masm.ma_dtr(js::jit::IsStore, GlobalReg, Imm32(addr + INT64HIGH_OFFSET), r.reg.high,
                     scratch);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        unsigned addr = globalDataOffset - WasmGlobalRegBias;
+        masm.store64(r.reg, Address(GlobalReg, addr));
 #else
         MOZ_CRASH("BaseCompiler platform hook: storeGlobalVarI64");
 #endif
@@ -3152,6 +3332,9 @@ class BaseCompiler
         unsigned addr = globalDataOffset - WasmGlobalRegBias;
         VFPRegister vd(r.reg);
         masm.ma_vstr(vd.singleOverlay(), VFPAddr(GlobalReg, VFPOffImm(addr)));
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        unsigned addr = globalDataOffset - WasmGlobalRegBias;
+        masm.storeFloat32(r.reg, Address(GlobalReg, addr));
 #else
         MOZ_CRASH("BaseCompiler platform hook: storeGlobalVarF32");
 #endif
@@ -3168,6 +3351,9 @@ class BaseCompiler
 #elif defined(JS_CODEGEN_ARM)
         unsigned addr = globalDataOffset - WasmGlobalRegBias;
         masm.ma_vstr(r.reg, VFPAddr(GlobalReg, VFPOffImm(addr)));
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        unsigned addr = globalDataOffset - WasmGlobalRegBias;
+        masm.storeDouble(r.reg, Address(GlobalReg, addr));
 #else
         MOZ_CRASH("BaseCompiler platform hook: storeGlobalVarF64");
 #endif
@@ -3190,7 +3376,7 @@ class BaseCompiler
         {}
 
         void generate(MacroAssembler& masm) {
-# if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+# if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_LOONGARCH64)
             switch (viewType) {
               case Scalar::MaxTypedArrayViewType:
                 MOZ_CRASH("unexpected array type");
@@ -3244,6 +3430,8 @@ class BaseCompiler
             }
         }
         return 0;
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        return IsUnaligned(access) && access.byteSize() > 1 ? 1 : 0;
 #else
         return 0;
 #endif
@@ -3326,6 +3514,64 @@ class BaseCompiler
           default:
             MOZ_CRASH("Compiler bug: unexpected array type");
         }
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        switch (access.type()) {
+          case Scalar::Uint8:
+          case Scalar::Uint16:
+          case Scalar::Uint32:
+          case Scalar::Int8:
+          case Scalar::Int16:
+          case Scalar::Int32: {
+            BaseIndex srcAddr(HeapReg, ptr.reg, TimesOne, access.offset());
+            LoadStoreSize size = static_cast(access.byteSize() * 8);
+            LoadStoreExtension ext = (access.type() == Scalar::Uint8 ||
+                                      access.type() == Scalar::Uint16 ||
+                                      access.type() == Scalar::Uint32)
+                                         ? ZeroExtend
+                                         : SignExtend;
+            Register out = dest.tag == AnyReg::I64 ? dest.i64().reg.reg : dest.i32().reg;
+            if (IsUnaligned(access) && access.byteSize() > 1) {
+                masm.ma_load_unaligned(access, out, srcAddr, tmp1.reg, size, ext);
+            } else {
+                masm.ma_load(out, srcAddr, size, ext);
+                masm.append(access, masm.size() - 4, masm.framePushed());
+            }
+            break;
+          }
+          case Scalar::Int64: {
+            BaseIndex srcAddr(HeapReg, ptr.reg, TimesOne, access.offset());
+            if (IsUnaligned(access))
+                masm.ma_load_unaligned(access, dest.i64().reg.reg, srcAddr, tmp1.reg,
+                                       SizeDouble, SignExtend);
+            else {
+                masm.load64(srcAddr, dest.i64().reg);
+                masm.append(access, masm.size() - 4, masm.framePushed());
+            }
+            break;
+          }
+          case Scalar::Float32: {
+            BaseIndex srcAddr(HeapReg, ptr.reg, TimesOne, access.offset());
+            if (IsUnaligned(access))
+                masm.loadUnalignedFloat32(access, srcAddr, tmp1.reg, dest.f32().reg);
+            else {
+                masm.loadFloat32(srcAddr, dest.f32().reg);
+                masm.append(access, masm.size() - 4, masm.framePushed());
+            }
+            break;
+          }
+          case Scalar::Float64: {
+            BaseIndex srcAddr(HeapReg, ptr.reg, TimesOne, access.offset());
+            if (IsUnaligned(access))
+                masm.loadUnalignedDouble(access, srcAddr, tmp1.reg, dest.f64().reg);
+            else {
+                masm.loadDouble(srcAddr, dest.f64().reg);
+                masm.append(access, masm.size() - 4, masm.framePushed());
+            }
+            break;
+          }
+          default:
+            MOZ_CRASH("Compiler bug: unexpected array type");
+        }
 #else
         MOZ_CRASH("BaseCompiler platform hook: load");
 #endif
@@ -3405,6 +3651,59 @@ class BaseCompiler
           default:
             MOZ_CRASH("Compiler bug: unexpected array type");
         }
+#elif defined(JS_CODEGEN_LOONGARCH64)
+        switch (access.type()) {
+          case Scalar::Uint8:
+          case Scalar::Uint16:
+          case Scalar::Uint32:
+          case Scalar::Int8:
+          case Scalar::Int16:
+          case Scalar::Int32: {
+            Register rt = src.tag == AnyReg::I64 ? src.i64().reg.reg : src.i32().reg;
+            BaseIndex dstAddr(HeapReg, ptr.reg, TimesOne, access.offset());
+            LoadStoreSize size = static_cast(access.byteSize() * 8);
+            if (IsUnaligned(access) && access.byteSize() > 1)
+                masm.ma_store_unaligned(access, rt, dstAddr, tmp1.reg, size, SignExtend);
+            else {
+                masm.ma_store(rt, dstAddr, size, SignExtend);
+                masm.append(access, masm.size() - 4, masm.framePushed());
+            }
+            break;
+          }
+          case Scalar::Int64: {
+            BaseIndex dstAddr(HeapReg, ptr.reg, TimesOne, access.offset());
+            if (IsUnaligned(access))
+                masm.ma_store_unaligned(access, src.i64().reg.reg, dstAddr, tmp1.reg,
+                                        SizeDouble, SignExtend);
+            else {
+                masm.store64(src.i64().reg, dstAddr);
+                masm.append(access, masm.size() - 4, masm.framePushed());
+            }
+            break;
+          }
+          case Scalar::Float32: {
+            BaseIndex dstAddr(HeapReg, ptr.reg, TimesOne, access.offset());
+            if (IsUnaligned(access))
+                masm.storeUnalignedFloat32(access, src.f32().reg, tmp1.reg, dstAddr);
+            else {
+                masm.storeFloat32(src.f32().reg, dstAddr);
+                masm.append(access, masm.size() - 4, masm.framePushed());
+            }
+            break;
+          }
+          case Scalar::Float64: {
+            BaseIndex dstAddr(HeapReg, ptr.reg, TimesOne, access.offset());
+            if (IsUnaligned(access))
+                masm.storeUnalignedDouble(access, src.f64().reg, tmp1.reg, dstAddr);
+            else {
+                masm.storeDouble(src.f64().reg, dstAddr);
+                masm.append(access, masm.size() - 4, masm.framePushed());
+            }
+            break;
+          }
+          default:
+            MOZ_CRASH("Compiler bug: unexpected array type");
+        }
 #else
         MOZ_CRASH("BaseCompiler platform hook: store");
 #endif
@@ -3415,6 +3714,123 @@ class BaseCompiler
         return true;
     }
 
+#if defined(JS_CODEGEN_LOONGARCH64)
+    void coerceAtomicStoreResult(Scalar::Type viewType, RegI32 value) {
+        switch (viewType) {
+          case Scalar::Int8:
+            masm.as_ext_w_b(value.reg, value.reg);
+            break;
+          case Scalar::Uint8:
+            masm.as_bstrpick_d(value.reg, value.reg, 7, 0);
+            break;
+          case Scalar::Int16:
+            masm.as_ext_w_h(value.reg, value.reg);
+            break;
+          case Scalar::Uint16:
+            masm.as_bstrpick_d(value.reg, value.reg, 15, 0);
+            break;
+          case Scalar::Int32:
+          case Scalar::Uint32:
+            break;
+          default:
+            MOZ_CRASH("Unexpected atomic array type");
+        }
+    }
+
+    void atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type viewType, Register value,
+                                    const BaseIndex& addr, Register valueTemp,
+                                    Register offsetTemp, Register maskTemp,
+                                    Register output) {
+        switch (viewType) {
+          case Scalar::Int8:
+            masm.atomicFetchOp(1, true, op, value, addr, valueTemp, offsetTemp,
+                               maskTemp, output);
+            break;
+          case Scalar::Uint8:
+            masm.atomicFetchOp(1, false, op, value, addr, valueTemp, offsetTemp,
+                               maskTemp, output);
+            break;
+          case Scalar::Int16:
+            masm.atomicFetchOp(2, true, op, value, addr, valueTemp, offsetTemp,
+                               maskTemp, output);
+            break;
+          case Scalar::Uint16:
+            masm.atomicFetchOp(2, false, op, value, addr, valueTemp, offsetTemp,
+                               maskTemp, output);
+            break;
+          case Scalar::Int32:
+          case Scalar::Uint32:
+            masm.atomicFetchOp(4, false, op, value, addr, valueTemp, offsetTemp,
+                               maskTemp, output);
+            break;
+          default:
+            MOZ_CRASH("Unexpected atomic array type");
+        }
+    }
+
+    void atomicCompareExchangeToTypedIntArray(Scalar::Type viewType, const BaseIndex& addr,
+                                              Register oldval, Register newval,
+                                              Register valueTemp, Register offsetTemp,
+                                              Register maskTemp, Register output) {
+        switch (viewType) {
+          case Scalar::Int8:
+            masm.compareExchange(1, true, addr, oldval, newval, valueTemp,
+                                 offsetTemp, maskTemp, output);
+            break;
+          case Scalar::Uint8:
+            masm.compareExchange(1, false, addr, oldval, newval, valueTemp,
+                                 offsetTemp, maskTemp, output);
+            break;
+          case Scalar::Int16:
+            masm.compareExchange(2, true, addr, oldval, newval, valueTemp,
+                                 offsetTemp, maskTemp, output);
+            break;
+          case Scalar::Uint16:
+            masm.compareExchange(2, false, addr, oldval, newval, valueTemp,
+                                 offsetTemp, maskTemp, output);
+            break;
+          case Scalar::Int32:
+          case Scalar::Uint32:
+            masm.compareExchange(4, false, addr, oldval, newval, valueTemp,
+                                 offsetTemp, maskTemp, output);
+            break;
+          default:
+            MOZ_CRASH("Unexpected atomic array type");
+        }
+    }
+
+    void atomicExchangeToTypedIntArray(Scalar::Type viewType, const BaseIndex& addr,
+                                       Register value, Register valueTemp,
+                                       Register offsetTemp, Register maskTemp,
+                                       Register output) {
+        switch (viewType) {
+          case Scalar::Int8:
+            masm.atomicExchange(1, true, addr, value, valueTemp, offsetTemp,
+                                maskTemp, output);
+            break;
+          case Scalar::Uint8:
+            masm.atomicExchange(1, false, addr, value, valueTemp, offsetTemp,
+                                maskTemp, output);
+            break;
+          case Scalar::Int16:
+            masm.atomicExchange(2, true, addr, value, valueTemp, offsetTemp,
+                                maskTemp, output);
+            break;
+          case Scalar::Uint16:
+            masm.atomicExchange(2, false, addr, value, valueTemp, offsetTemp,
+                                maskTemp, output);
+            break;
+          case Scalar::Int32:
+          case Scalar::Uint32:
+            masm.atomicExchange(4, false, addr, value, valueTemp, offsetTemp,
+                                maskTemp, output);
+            break;
+          default:
+            MOZ_CRASH("Unexpected atomic array type");
+        }
+    }
+#endif
+
 #ifdef JS_CODEGEN_ARM
     void
     loadI32(MemoryAccessDesc access, bool isSigned, RegI32 ptr, Register rt) {
@@ -3761,8 +4177,15 @@ class BaseCompiler
 #endif
     void emitReinterpretI32AsF32();
     void emitReinterpretI64AsF64();
-    MOZ_MUST_USE bool emitGrowMemory();
-    MOZ_MUST_USE bool emitCurrentMemory();
+#if defined(JS_CODEGEN_LOONGARCH64)
+    [[nodiscard]] bool emitAtomicLoad();
+    [[nodiscard]] bool emitAtomicStore();
+    [[nodiscard]] bool emitAtomicBinOp();
+    [[nodiscard]] bool emitAtomicCompareExchange();
+    [[nodiscard]] bool emitAtomicExchange();
+#endif
+    [[nodiscard]] bool emitGrowMemory();
+    [[nodiscard]] bool emitCurrentMemory();
 };
 
 void
@@ -6685,6 +7108,209 @@ BaseCompiler::emitTeeStoreWithCoercion(ValType resultType, Scalar::Type viewType
     return true;
 }
 
+#if defined(JS_CODEGEN_LOONGARCH64)
+bool
+BaseCompiler::emitAtomicLoad()
+{
+    LinearMemoryAddress addr;
+    Scalar::Type viewType;
+    if (!iter_.readAtomicLoad(&addr, &viewType))
+        return false;
+
+    if (deadCode_)
+        return true;
+
+    MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(trapOffset()), 0,
+                            MembarBeforeLoad, MembarAfterLoad);
+
+    RegI32 rp = popI32();
+    checkOffset(&access, rp);
+#ifndef WASM_HUGE_MEMORY
+    masm.wasmBoundsCheck(Assembler::AboveOrEqual, rp.reg, trap(Trap::OutOfBounds));
+#endif
+
+    MOZ_ASSERT(!IsUnaligned(access));
+
+    BaseIndex srcAddr(HeapReg, rp.reg, TimesOne, access.offset());
+    LoadStoreSize size = static_cast(access.byteSize() * 8);
+    LoadStoreExtension ext = (viewType == Scalar::Uint8 ||
+                              viewType == Scalar::Uint16 ||
+                              viewType == Scalar::Uint32)
+                                 ? ZeroExtend
+                                 : SignExtend;
+
+    masm.memoryBarrier(access.barrierBefore());
+    masm.ma_load(rp.reg, srcAddr, size, ext);
+    masm.append(access, masm.size() - 4, masm.framePushed());
+    masm.memoryBarrier(access.barrierAfter());
+
+    pushI32(rp);
+    return true;
+}
+
+bool
+BaseCompiler::emitAtomicStore()
+{
+    LinearMemoryAddress addr;
+    Scalar::Type viewType;
+    Nothing unused_value;
+    if (!iter_.readAtomicStore(&addr, &viewType, &unused_value))
+        return false;
+
+    if (deadCode_)
+        return true;
+
+    MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(trapOffset()), 0,
+                            MembarBeforeStore, MembarAfterStore);
+
+    RegI32 rv = popI32();
+    RegI32 rp = popI32();
+    checkOffset(&access, rp);
+#ifndef WASM_HUGE_MEMORY
+    masm.wasmBoundsCheck(Assembler::AboveOrEqual, rp.reg, trap(Trap::OutOfBounds));
+#endif
+
+    MOZ_ASSERT(!IsUnaligned(access));
+
+    BaseIndex dstAddr(HeapReg, rp.reg, TimesOne, access.offset());
+    LoadStoreSize size = static_cast(access.byteSize() * 8);
+
+    masm.memoryBarrier(access.barrierBefore());
+    masm.ma_store(rv.reg, dstAddr, size, SignExtend);
+    masm.append(access, masm.size() - 4, masm.framePushed());
+    masm.memoryBarrier(access.barrierAfter());
+
+    freeI32(rp);
+    coerceAtomicStoreResult(viewType, rv);
+    pushI32(rv);
+    return true;
+}
+
+bool
+BaseCompiler::emitAtomicBinOp()
+{
+    LinearMemoryAddress addr;
+    Scalar::Type viewType;
+    AtomicOp op;
+    Nothing unused_value;
+    if (!iter_.readAtomicBinOp(&addr, &viewType, &op, &unused_value))
+        return false;
+
+    if (deadCode_)
+        return true;
+
+    MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(trapOffset()));
+
+    RegI32 rv = popI32();
+    RegI32 rp = popI32();
+    RegI32 rd = needI32();
+    RegI32 valueTemp = needI32();
+    RegI32 offsetTemp = needI32();
+    RegI32 maskTemp = needI32();
+
+    checkOffset(&access, rp);
+#ifndef WASM_HUGE_MEMORY
+    masm.wasmBoundsCheck(Assembler::AboveOrEqual, rp.reg, trap(Trap::OutOfBounds));
+#endif
+
+    MOZ_ASSERT(!IsUnaligned(access));
+    atomicBinopToTypedIntArray(op, viewType,
+                               rv.reg, BaseIndex(HeapReg, rp.reg, TimesOne, access.offset()),
+                               valueTemp.reg, offsetTemp.reg, maskTemp.reg, rd.reg);
+
+    freeI32(rp);
+    freeI32(rv);
+    freeI32(valueTemp);
+    freeI32(offsetTemp);
+    freeI32(maskTemp);
+    pushI32(rd);
+    return true;
+}
+
+bool
+BaseCompiler::emitAtomicCompareExchange()
+{
+    LinearMemoryAddress addr;
+    Scalar::Type viewType;
+    Nothing unused_oldValue, unused_newValue;
+    if (!iter_.readAtomicCompareExchange(&addr, &viewType, &unused_oldValue, &unused_newValue))
+        return false;
+
+    if (deadCode_)
+        return true;
+
+    MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(trapOffset()));
+
+    RegI32 newval = popI32();
+    RegI32 oldval = popI32();
+    RegI32 rp = popI32();
+    RegI32 rd = needI32();
+    RegI32 valueTemp = needI32();
+    RegI32 offsetTemp = needI32();
+    RegI32 maskTemp = needI32();
+
+    checkOffset(&access, rp);
+#ifndef WASM_HUGE_MEMORY
+    masm.wasmBoundsCheck(Assembler::AboveOrEqual, rp.reg, trap(Trap::OutOfBounds));
+#endif
+
+    MOZ_ASSERT(!IsUnaligned(access));
+    atomicCompareExchangeToTypedIntArray(viewType,
+                                         BaseIndex(HeapReg, rp.reg, TimesOne, access.offset()),
+                                         oldval.reg, newval.reg, valueTemp.reg,
+                                         offsetTemp.reg, maskTemp.reg, rd.reg);
+
+    freeI32(newval);
+    freeI32(oldval);
+    freeI32(rp);
+    freeI32(valueTemp);
+    freeI32(offsetTemp);
+    freeI32(maskTemp);
+    pushI32(rd);
+    return true;
+}
+
+bool
+BaseCompiler::emitAtomicExchange()
+{
+    LinearMemoryAddress addr;
+    Scalar::Type viewType;
+    Nothing unused_value;
+    if (!iter_.readAtomicExchange(&addr, &viewType, &unused_value))
+        return false;
+
+    if (deadCode_)
+        return true;
+
+    MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(trapOffset()));
+
+    RegI32 rv = popI32();
+    RegI32 rp = popI32();
+    RegI32 rd = needI32();
+    RegI32 valueTemp = needI32();
+    RegI32 offsetTemp = needI32();
+    RegI32 maskTemp = needI32();
+
+    checkOffset(&access, rp);
+#ifndef WASM_HUGE_MEMORY
+    masm.wasmBoundsCheck(Assembler::AboveOrEqual, rp.reg, trap(Trap::OutOfBounds));
+#endif
+
+    MOZ_ASSERT(!IsUnaligned(access));
+    atomicExchangeToTypedIntArray(viewType,
+                                  BaseIndex(HeapReg, rp.reg, TimesOne, access.offset()),
+                                  rv.reg, valueTemp.reg, offsetTemp.reg, maskTemp.reg, rd.reg);
+
+    freeI32(rv);
+    freeI32(rp);
+    freeI32(valueTemp);
+    freeI32(offsetTemp);
+    freeI32(maskTemp);
+    pushI32(rd);
+    return true;
+}
+#endif
+
 bool
 BaseCompiler::emitGrowMemory()
 {
@@ -7315,12 +7941,25 @@ BaseCompiler::emitBody()
             CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, JSOP_GE, MCompare::Compare_Double));
 
           // Atomics
+#if defined(JS_CODEGEN_LOONGARCH64)
+          case uint16_t(Op::I32AtomicsLoad):
+            CHECK_NEXT(emitAtomicLoad());
+          case uint16_t(Op::I32AtomicsStore):
+            CHECK_NEXT(emitAtomicStore());
+          case uint16_t(Op::I32AtomicsBinOp):
+            CHECK_NEXT(emitAtomicBinOp());
+          case uint16_t(Op::I32AtomicsCompareExchange):
+            CHECK_NEXT(emitAtomicCompareExchange());
+          case uint16_t(Op::I32AtomicsExchange):
+            CHECK_NEXT(emitAtomicExchange());
+#else
           case uint16_t(Op::I32AtomicsLoad):
           case uint16_t(Op::I32AtomicsStore):
           case uint16_t(Op::I32AtomicsBinOp):
           case uint16_t(Op::I32AtomicsCompareExchange):
           case uint16_t(Op::I32AtomicsExchange):
             MOZ_CRASH("Unimplemented Atomics");
+#endif
 
           // Sign extensions
           case uint16_t(Op::I32Extend8S):
@@ -7453,7 +8092,8 @@ BaseCompiler::BaseCompiler(const ModuleGeneratorData& mg,
     availGPR_.take(GlobalReg);
 #elif defined(JS_CODEGEN_X86)
     availGPR_.take(ScratchRegX86);
-#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
+      defined(JS_CODEGEN_LOONGARCH64)
     availGPR_.take(HeapReg);
     availGPR_.take(GlobalReg);
 #endif
@@ -7593,7 +8233,8 @@ js::wasm::BaselineCanCompile(const FunctionGenerator* fg)
         return false;
 #endif
 
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) || \
+    defined(JS_CODEGEN_LOONGARCH64)
     if (fg->usesAtomics())
         return false;
 
diff --git a/js/src/wasm/WasmFrameIterator.cpp b/js/src/wasm/WasmFrameIterator.cpp
index 427cece69b..b45ff404d9 100644
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -242,6 +242,11 @@ static const unsigned PushedRetAddr = 8;
 static const unsigned PushedFP = 32;
 static const unsigned StoredFP = 36;
 static const unsigned PostStorePrePopFP = 4;
+#elif defined(JS_CODEGEN_LOONGARCH64)
+static const unsigned PushedRetAddr = 8;
+static const unsigned PushedFP = 36;
+static const unsigned StoredFP = 40;
+static const unsigned PostStorePrePopFP = 0;
 #elif defined(JS_CODEGEN_NONE)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
@@ -258,7 +263,8 @@ PushRetAddr(MacroAssembler& masm)
 {
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
-#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
+      defined(JS_CODEGEN_LOONGARCH64)
     masm.push(ra);
 #else
     // The x86/x64 call instruction pushes the return address.
@@ -641,19 +647,23 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
         MOZ_ASSERT(offsetInModule < codeRange->end());
         uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
         void** sp = (void**)state.sp;
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \
+    defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64)
         if (offsetInCodeRange < PushedRetAddr || InThunk(*codeRange, offsetInModule)) {
-            // First instruction of the ARM/MIPS function; the return address is
-            // still in lr and fp still holds the caller's fp.
+            // First instruction of the ARM/MIPS/loongarch64 function; the
+            // return address is still in lr and fp still holds the caller's fp.
             callerPC_ = state.lr;
             callerFP_ = fp;
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp - 2);
+# if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \
+    defined(JS_CODEGEN_MIPS64)
         } else if (offsetInModule == codeRange->profilingReturn() - PostStorePrePopFP) {
             // Second-to-last instruction of the ARM/MIPS function; fp points to
             // the caller's fp; have not yet popped Frame.
             callerPC_ = ReturnAddressFromFP(sp);
             callerFP_ = CallerFPFromFP(sp);
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp);
+# endif
         } else
 #endif
         if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn() ||
@@ -826,6 +836,13 @@ wasm::ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled)
     BOffImm16 calleeOffset;
     callerInsn->extractImm16(&calleeOffset);
     void* callee = calleeOffset.getDest(reinterpret_cast(caller));
+#elif defined(JS_CODEGEN_LOONGARCH64)
+    uint8_t* caller = callerRetAddr - sizeof(uint32_t);
+    Instruction* callerInsn = reinterpret_cast(caller);
+    MOZ_ASSERT(callerInsn->extractOpcode() == ((uint32_t)op_bl >> OpcodeShift));
+    int32_t calleeOffset =
+        int32_t(reinterpret_cast(callerInsn)->extractImm26Value() << 8) >> 6;
+    void* callee = caller + calleeOffset;
 #elif defined(JS_CODEGEN_NONE)
     MOZ_CRASH();
     void* callee = nullptr;
@@ -853,6 +870,8 @@ wasm::ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled)
     MOZ_CRASH();
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     new (caller) InstImm(op_regimm, zero, rt_bgezal, BOffImm16(to - caller));
+#elif defined(JS_CODEGEN_LOONGARCH64)
+    reinterpret_cast(caller)->setJOffImm26(JOffImm26(to - caller));
 #elif defined(JS_CODEGEN_NONE)
     MOZ_CRASH();
 #else
diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp
index 69a0bdbcaa..09cd1c486b 100644
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -38,8 +38,10 @@ using mozilla::IsNaN;
 
 const char wasm::InstanceExportField[] = "exports";
 
-#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-// On MIPS, CodeLabels are instruction immediates so InternalLinks only
+#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
+    defined(JS_CODEGEN_LOONGARCH64)
+// On MIPS and loongarch64, CodeLabels are instruction immediates so
+// InternalLinks only
 // patch instruction immediates.
 LinkData::InternalLink::InternalLink(Kind kind)
 {
diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp
index f68285e401..a1eec6c9b7 100644
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -172,6 +172,11 @@ class AutoSetHandlingSegFault
 #  define RSP_sig(p) ((p)->uc_mcontext.gregs[29])
 #  define RFP_sig(p) ((p)->uc_mcontext.gregs[30])
 # endif
+# if defined(__linux__) && defined(__loongarch__)
+#  define EPC_sig(p) ((p)->uc_mcontext.__pc)
+#  define RSP_sig(p) ((p)->uc_mcontext.__gregs[3])
+#  define RFP_sig(p) ((p)->uc_mcontext.__gregs[22])
+# endif
 #elif defined(__NetBSD__)
 # define XMM_sig(p,i) (((struct fxsave64*)(p)->uc_mcontext.__fpregs)->fx_xmm[i])
 # define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP])
@@ -392,14 +397,14 @@ struct macos_aarch64_context {
 # define PC_sig(p) R15_sig(p)
 #elif defined(__aarch64__)
 # define PC_sig(p) EPC_sig(p)
-#elif defined(JS_CPU_MIPS)
+#elif defined(JS_CPU_MIPS) || defined(JS_CPU_LOONGARCH64)
 # define PC_sig(p) EPC_sig(p)
 #endif
 
 static uint8_t**
 ContextToPC(CONTEXT* context)
 {
-#ifdef JS_CODEGEN_NONE
+#if defined(JS_CODEGEN_NONE)
     MOZ_CRASH();
 #else
     return reinterpret_cast(&PC_sig(context));
diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp
index 67d744e585..e959227f25 100644
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -21,6 +21,7 @@
 #include "mozilla/ArrayUtils.h"
 
 #include "wasm/WasmCode.h"
+#include "wasm/WasmBaselineCompile.h"
 #include "wasm/WasmIonCompile.h"
 
 #include "jit/MacroAssembler-inl.h"
@@ -106,7 +107,8 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe)
     // Save the return address if it wasn't already saved by the call insn.
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
-#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
+      defined(JS_CODEGEN_LOONGARCH64)
     masm.push(ra);
 #endif
 
@@ -564,11 +566,13 @@ wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint3
     MOZ_ASSERT(NonVolatileRegs.has(WasmTlsReg));
 #if defined(JS_CODEGEN_X64) || \
     defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
-    defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+    defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
+    defined(JS_CODEGEN_LOONGARCH64)
     MOZ_ASSERT(NonVolatileRegs.has(HeapReg));
 #endif
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
-    defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+    defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
+    defined(JS_CODEGEN_LOONGARCH64)
     MOZ_ASSERT(NonVolatileRegs.has(GlobalReg));
 #endif
 
@@ -1049,6 +1053,37 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel)
     masm.ret();
 #elif defined(JS_CODEGEN_ARM64)
     MOZ_CRASH();
+#elif defined(JS_CODEGEN_LOONGARCH64)
+    // Reserve space to store the resumePC. We restore all machine state from
+    // the saved register image and use the reserved `rx` register as the final
+    // jump scratch to resume execution.
+    masm.subFromStackPtr(Imm32(sizeof(intptr_t)));
+    masm.setFramePushed(0);
+    static_assert(!SupportsSimd, "high lanes of SIMD registers need to be saved too.");
+    masm.PushRegsInMask(AllRegsExceptSP);
+
+    // Save the unaligned stack pointer in a non-volatile register, then align
+    // for the C++ call into HandleExecutionInterrupt.
+    masm.moveStackPtrTo(s0);
+    masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1)));
+
+    // Store resumePC into the reserved space above the saved register block.
+    masm.loadWasmActivationFromSymbolicAddress(IntArgReg0);
+    masm.loadPtr(Address(IntArgReg0, WasmActivation::offsetOfResumePC()), IntArgReg1);
+    masm.storePtr(IntArgReg1, Address(s0, masm.framePushed()));
+
+    masm.assertStackAlignment(ABIStackAlignment);
+    masm.call(SymbolicAddress::HandleExecutionInterrupt);
+
+    masm.branchIfFalseBool(ReturnReg, throwLabel);
+
+    // Restore the interrupted machine state before resuming execution.
+    masm.moveToStackPtr(s0);
+    masm.PopRegsInMask(AllRegsExceptSP);
+
+    masm.loadPtr(Address(StackPointer, 0), rx);
+    masm.addToStackPtr(Imm32(sizeof(intptr_t)));
+    masm.jump(rx);
 #elif defined (JS_CODEGEN_NONE)
     MOZ_CRASH();
 #else
diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp
index 993c4903be..a36e4fe17e 100644
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -379,6 +379,7 @@ GetCPUID()
         ARM = 0x3,
         MIPS = 0x4,
         MIPS64 = 0x5,
+        LOONGARCH64 = 0x6,
         ARCH_BITS = 3
     };
 
@@ -399,6 +400,9 @@ GetCPUID()
 #elif defined(JS_CODEGEN_MIPS64)
     MOZ_ASSERT(jit::GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
     return MIPS64 | (jit::GetMIPSFlags() << ARCH_BITS);
+#elif defined(JS_CODEGEN_LOONGARCH64)
+    MOZ_ASSERT(jit::GetLOONGARCH64Flags() <= (UINT32_MAX >> ARCH_BITS));
+    return LOONGARCH64 | (jit::GetLOONGARCH64Flags() << ARCH_BITS);
 #elif defined(JS_CODEGEN_NONE)
     return 0;
 #else
diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp
index 3ca3da6b8b..9365937fdd 100644
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -1446,6 +1446,7 @@ ReloadPrefsCallback(const char* pref, void* data)
     bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict");
     
     bool streams = Preferences::GetBool(JS_OPTIONS_DOT_STR "streams");
+    bool weakRefs = Preferences::GetBool(JS_OPTIONS_DOT_STR "weakrefs");
 
     bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
     
@@ -1472,7 +1473,8 @@ ReloadPrefsCallback(const char* pref, void* data)
                              .setWerror(werror)
                              .setExtraWarnings(extraWarnings)
                              .setArrayProtoValues(arrayProtoValues)
-                             .setStreams(streams);
+                             .setStreams(streams)
+                             .setWeakRefs(weakRefs);
 
     JS_SetParallelParsingEnabled(cx, parallelParsing);
     JS_SetOffthreadIonCompilationEnabled(cx, offthreadIonCompilation);
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index b501fa85f5..4616757076 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4652,7 +4652,10 @@ nsFrame::GetIntrinsicSize()
 /* virtual */ AspectRatio
 nsFrame::GetIntrinsicRatio()
 {
-  return AspectRatio();
+  const nsStylePosition* stylePos = StylePosition();
+  return stylePos->mAspectRatio == 0.0f
+         ? AspectRatio()
+         : AspectRatio(stylePos->mAspectRatio);
 }
 
 void
@@ -4721,9 +4724,16 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext,
                      const LogicalSize&  aPadding,
                      ComputeSizeFlags    aFlags)
 {
-  MOZ_ASSERT(!GetIntrinsicRatio(),
-             "Please override this method and call "
-             "nsFrame::ComputeSizeWithIntrinsicDimensions instead.");
+  AspectRatio intrinsicRatio = GetIntrinsicRatio();
+  if (intrinsicRatio) {
+    return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
+                                              GetIntrinsicSize(),
+                                              intrinsicRatio,
+                                              aCBSize, aMargin,
+                                              aBorder, aPadding,
+                                              aFlags);
+  }
+
   LogicalSize result = ComputeAutoSize(aRenderingContext, aWM,
                                        aCBSize, aAvailableISize,
                                        aMargin, aBorder, aPadding,
diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in
index 101e98d6fd..3ce51f9b3b 100644
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -71,15 +71,16 @@ vpx_codec_set_frame_buffer_functions
 vpx_codec_enc_init_multi_ver
 #endif
 #ifdef MOZ_AV1
-aom_codec_av1_dx
-aom_codec_dec_init_ver
-aom_codec_decode
-aom_codec_destroy
-aom_codec_err_to_string
-aom_codec_get_frame
-aom_codec_peek_stream_info
-aom_img_alloc
-aom_img_free
+dav1d_default_settings
+dav1d_open
+dav1d_parse_sequence_header
+dav1d_send_data
+dav1d_get_picture
+dav1d_flush
+dav1d_close
+dav1d_data_create
+dav1d_data_unref
+dav1d_picture_unref
 #endif
 #ifdef MOZ_JXL
 JxlDecoderCreate
diff --git a/layout/style/CSSNestingFlattener.cpp b/layout/style/CSSNestingFlattener.cpp
new file mode 100644
index 0000000000..287e2ca5d1
--- /dev/null
+++ b/layout/style/CSSNestingFlattener.cpp
@@ -0,0 +1,960 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
+
+#include "CSSNestingFlattener.h"
+
+#include "mozilla/Assertions.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace css {
+
+namespace {
+
+class CSSNestingFlattener final
+{
+  using SelectorList = nsTArray;
+
+public:
+  explicit CSSNestingFlattener(const nsAString& aInput)
+    : mInput(aInput)
+    , mPos(0)
+    , mSawNesting(false)
+  {
+  }
+
+  bool Flatten(nsAString& aOutput)
+  {
+    nsAutoString flattened;
+    if (!ProcessStylesheet(flattened, false)) {
+      return false;
+    }
+
+    SkipWhitespaceAndComments();
+    if (mPos != mInput.Length() || !mSawNesting) {
+      return false;
+    }
+
+    aOutput.Assign(flattened);
+    return true;
+  }
+
+private:
+  static bool
+  IsCSSWhitespace(char16_t aChar)
+  {
+    return aChar == ' ' || aChar == '\t' || aChar == '\r' ||
+           aChar == '\n' || aChar == '\f';
+  }
+
+  bool
+  AtEnd() const
+  {
+    return mPos >= mInput.Length();
+  }
+
+  char16_t
+  Peek() const
+  {
+    MOZ_ASSERT(!AtEnd(), "cannot peek past end");
+    return mInput.CharAt(mPos);
+  }
+
+  bool
+  StartsWithComment() const
+  {
+    return mPos + 1 < mInput.Length() &&
+           mInput.CharAt(mPos) == '/' &&
+           mInput.CharAt(mPos + 1) == '*';
+  }
+
+  bool
+  SkipComment()
+  {
+    MOZ_ASSERT(StartsWithComment(), "expected comment");
+
+    mPos += 2;
+    while (mPos + 1 < mInput.Length()) {
+      if (mInput.CharAt(mPos) == '*' && mInput.CharAt(mPos + 1) == '/') {
+        mPos += 2;
+        return true;
+      }
+      ++mPos;
+    }
+
+    return false;
+  }
+
+  void
+  SkipWhitespaceAndComments()
+  {
+    while (!AtEnd()) {
+      if (IsCSSWhitespace(Peek())) {
+        ++mPos;
+        continue;
+      }
+      if (StartsWithComment()) {
+        if (!SkipComment()) {
+          mPos = mInput.Length();
+          return;
+        }
+        continue;
+      }
+      break;
+    }
+  }
+
+  bool
+  SkipString(char16_t aQuote)
+  {
+    MOZ_ASSERT(!AtEnd() && Peek() == aQuote, "expected string start");
+
+    ++mPos;
+    while (!AtEnd()) {
+      char16_t c = Peek();
+      ++mPos;
+      if (c == aQuote) {
+        return true;
+      }
+      if (c == '\\' && !AtEnd()) {
+        ++mPos;
+        continue;
+      }
+      if (c == '\n' || c == '\r' || c == '\f') {
+        return false;
+      }
+    }
+
+    return false;
+  }
+
+  static void
+  TrimWhitespace(nsAString& aText)
+  {
+    uint32_t start = 0;
+    uint32_t end = aText.Length();
+
+    while (start < end && IsCSSWhitespace(aText.CharAt(start))) {
+      ++start;
+    }
+    while (end > start && IsCSSWhitespace(aText.CharAt(end - 1))) {
+      --end;
+    }
+
+    if (start == 0 && end == aText.Length()) {
+      return;
+    }
+
+    aText.Assign(Substring(aText, start, end - start));
+  }
+
+  bool
+  SplitSelectorList(const nsAString& aSelectorText, SelectorList& aSelectors)
+  {
+    uint32_t itemStart = 0;
+    int32_t parenDepth = 0;
+    int32_t bracketDepth = 0;
+    bool inComment = false;
+    char16_t stringQuote = 0;
+
+    for (uint32_t i = 0; i < aSelectorText.Length(); ++i) {
+      char16_t c = aSelectorText.CharAt(i);
+
+      if (inComment) {
+        if (c == '*' && i + 1 < aSelectorText.Length() &&
+            aSelectorText.CharAt(i + 1) == '/') {
+          inComment = false;
+          ++i;
+        }
+        continue;
+      }
+
+      if (stringQuote) {
+        if (c == '\\') {
+          ++i;
+          continue;
+        }
+        if (c == stringQuote) {
+          stringQuote = 0;
+        }
+        continue;
+      }
+
+      if (c == '/' && i + 1 < aSelectorText.Length() &&
+          aSelectorText.CharAt(i + 1) == '*') {
+        inComment = true;
+        ++i;
+        continue;
+      }
+
+      if (c == '"' || c == '\'') {
+        stringQuote = c;
+        continue;
+      }
+
+      if (c == '(') {
+        ++parenDepth;
+        continue;
+      }
+      if (c == ')' && parenDepth > 0) {
+        --parenDepth;
+        continue;
+      }
+      if (c == '[') {
+        ++bracketDepth;
+        continue;
+      }
+      if (c == ']' && bracketDepth > 0) {
+        --bracketDepth;
+        continue;
+      }
+
+      if (c == ',' && parenDepth == 0 && bracketDepth == 0) {
+        nsAutoString selector;
+        selector.Assign(Substring(aSelectorText, itemStart, i - itemStart));
+        TrimWhitespace(selector);
+        if (!selector.IsEmpty()) {
+          aSelectors.AppendElement(selector);
+        }
+        itemStart = i + 1;
+      }
+    }
+
+    nsAutoString selector;
+    selector.Assign(Substring(aSelectorText, itemStart));
+    TrimWhitespace(selector);
+    if (!selector.IsEmpty()) {
+      aSelectors.AppendElement(selector);
+    }
+
+    return !aSelectors.IsEmpty();
+  }
+
+  bool
+  SelectorHasAmpersand(const nsAString& aSelector) const
+  {
+    bool inComment = false;
+    char16_t stringQuote = 0;
+
+    for (uint32_t i = 0; i < aSelector.Length(); ++i) {
+      char16_t c = aSelector.CharAt(i);
+
+      if (inComment) {
+        if (c == '*' && i + 1 < aSelector.Length() &&
+            aSelector.CharAt(i + 1) == '/') {
+          inComment = false;
+          ++i;
+        }
+        continue;
+      }
+
+      if (stringQuote) {
+        if (c == '\\') {
+          ++i;
+          continue;
+        }
+        if (c == stringQuote) {
+          stringQuote = 0;
+        }
+        continue;
+      }
+
+      if (c == '/' && i + 1 < aSelector.Length() &&
+          aSelector.CharAt(i + 1) == '*') {
+        inComment = true;
+        ++i;
+        continue;
+      }
+
+      if (c == '"' || c == '\'') {
+        stringQuote = c;
+        continue;
+      }
+
+      if (c == '&') {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  void
+  ReplaceAmpersands(const nsAString& aSelector,
+                    const nsAString& aParent,
+                    nsAString& aOutput) const
+  {
+    bool inComment = false;
+    char16_t stringQuote = 0;
+
+    for (uint32_t i = 0; i < aSelector.Length(); ++i) {
+      char16_t c = aSelector.CharAt(i);
+
+      if (inComment) {
+        aOutput.Append(c);
+        if (c == '*' && i + 1 < aSelector.Length() &&
+            aSelector.CharAt(i + 1) == '/') {
+          aOutput.Append('/');
+          inComment = false;
+          ++i;
+        }
+        continue;
+      }
+
+      if (stringQuote) {
+        aOutput.Append(c);
+        if (c == '\\' && i + 1 < aSelector.Length()) {
+          aOutput.Append(aSelector.CharAt(i + 1));
+          ++i;
+          continue;
+        }
+        if (c == stringQuote) {
+          stringQuote = 0;
+        }
+        continue;
+      }
+
+      if (c == '/' && i + 1 < aSelector.Length() &&
+          aSelector.CharAt(i + 1) == '*') {
+        aOutput.AppendLiteral("/*");
+        inComment = true;
+        ++i;
+        continue;
+      }
+
+      if (c == '"' || c == '\'') {
+        aOutput.Append(c);
+        stringQuote = c;
+        continue;
+      }
+
+      if (c == '&') {
+        aOutput.Append(aParent);
+        continue;
+      }
+
+      aOutput.Append(c);
+    }
+  }
+
+  bool
+  ExpandNestedSelectors(const SelectorList& aParents,
+                        const nsAString& aNestedSelectorText,
+                        SelectorList& aSelectors)
+  {
+    SelectorList nestedSelectors;
+    if (!SplitSelectorList(aNestedSelectorText, nestedSelectors)) {
+      return false;
+    }
+
+    for (const nsString& nestedSelector : nestedSelectors) {
+      bool hasAmpersand = SelectorHasAmpersand(nestedSelector);
+      for (const nsString& parentSelector : aParents) {
+        nsAutoString combined;
+        if (hasAmpersand) {
+          ReplaceAmpersands(nestedSelector, parentSelector, combined);
+        } else {
+          combined.Assign(parentSelector);
+          if (!combined.IsEmpty()) {
+            combined.Append(' ');
+          }
+          combined.Append(nestedSelector);
+        }
+        TrimWhitespace(combined);
+        if (!combined.IsEmpty()) {
+          aSelectors.AppendElement(combined);
+        }
+      }
+    }
+
+    return !aSelectors.IsEmpty();
+  }
+
+  static void
+  AppendSelectors(const SelectorList& aSelectors, nsAString& aOutput)
+  {
+    for (uint32_t i = 0; i < aSelectors.Length(); ++i) {
+      if (i) {
+        aOutput.AppendLiteral(", ");
+      }
+      aOutput.Append(aSelectors[i]);
+    }
+  }
+
+  static bool
+  StartsNestedSelector(char16_t aChar)
+  {
+    switch (aChar) {
+      case '.':
+      case '#':
+      case '[':
+      case ':':
+      case '&':
+      case '|':
+      case '>':
+      case '+':
+      case '~':
+      case '*':
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  static bool
+  StartsPotentialTypeSelector(char16_t aChar)
+  {
+    return (aChar >= 'a' && aChar <= 'z') ||
+           (aChar >= 'A' && aChar <= 'Z') ||
+           aChar == '_' ||
+           aChar == '\\' ||
+           aChar >= 0x80;
+  }
+
+  bool
+  LooksLikeTypeSelectorRule() const
+  {
+    if (AtEnd() || !StartsPotentialTypeSelector(Peek())) {
+      return false;
+    }
+
+    uint32_t pos = mPos;
+    int32_t parenDepth = 0;
+    int32_t bracketDepth = 0;
+    bool inComment = false;
+    char16_t stringQuote = 0;
+
+    while (pos < mInput.Length()) {
+      char16_t c = mInput.CharAt(pos);
+
+      if (inComment) {
+        if (c == '*' && pos + 1 < mInput.Length() &&
+            mInput.CharAt(pos + 1) == '/') {
+          inComment = false;
+          ++pos;
+        }
+        ++pos;
+        continue;
+      }
+
+      if (stringQuote) {
+        if (c == '\\' && pos + 1 < mInput.Length()) {
+          pos += 2;
+          continue;
+        }
+        if (c == stringQuote) {
+          stringQuote = 0;
+        }
+        ++pos;
+        continue;
+      }
+
+      if (c == '/' && pos + 1 < mInput.Length() &&
+          mInput.CharAt(pos + 1) == '*') {
+        inComment = true;
+        pos += 2;
+        continue;
+      }
+
+      if (c == '"' || c == '\'') {
+        stringQuote = c;
+        ++pos;
+        continue;
+      }
+
+      if (c == '(') {
+        ++parenDepth;
+        ++pos;
+        continue;
+      }
+      if (c == ')' && parenDepth > 0) {
+        --parenDepth;
+        ++pos;
+        continue;
+      }
+      if (c == '[') {
+        ++bracketDepth;
+        ++pos;
+        continue;
+      }
+      if (c == ']' && bracketDepth > 0) {
+        --bracketDepth;
+        ++pos;
+        continue;
+      }
+
+      if (parenDepth == 0 && bracketDepth == 0) {
+        if (c == '{') {
+          return true;
+        }
+        if (c == ';' || c == '}') {
+          return false;
+        }
+      }
+
+      ++pos;
+    }
+
+    return false;
+  }
+
+  static bool
+  IsAtRuleNameChar(char16_t aChar)
+  {
+    return (aChar >= 'a' && aChar <= 'z') ||
+           (aChar >= 'A' && aChar <= 'Z') ||
+           (aChar >= '0' && aChar <= '9') ||
+           aChar == '-';
+  }
+
+  static void
+  LowercaseASCII(nsACString& aText)
+  {
+    for (uint32_t i = 0; i < aText.Length(); ++i) {
+      char c = aText.CharAt(i);
+      if (c >= 'A' && c <= 'Z') {
+        aText.BeginWriting()[i] = c - 'A' + 'a';
+      }
+    }
+  }
+
+  static bool
+  ShouldProcessGroupRule(const nsACString& aName)
+  {
+    return aName.EqualsLiteral("media") ||
+           aName.EqualsLiteral("supports") ||
+           aName.EqualsLiteral("document") ||
+           aName.EqualsLiteral("layer");
+  }
+
+  void
+  FlushDeclarations(const SelectorList& aSelectors,
+                    nsAString& aDeclarations,
+                    nsAString& aOutput)
+  {
+    nsAutoString declarations;
+    declarations.Assign(aDeclarations);
+    TrimWhitespace(declarations);
+    aDeclarations.Truncate();
+
+    if (declarations.IsEmpty()) {
+      return;
+    }
+
+    AppendSelectors(aSelectors, aOutput);
+    aOutput.AppendLiteral(" { ");
+    aOutput.Append(declarations);
+    aOutput.AppendLiteral(" }\n");
+  }
+
+  bool
+  ReadRawBlockBody(nsAString& aBody)
+  {
+    uint32_t start = mPos;
+    int32_t depth = 0;
+
+    while (!AtEnd()) {
+      char16_t c = Peek();
+      if (c == '"' || c == '\'') {
+        if (!SkipString(c)) {
+          return false;
+        }
+        continue;
+      }
+      if (StartsWithComment()) {
+        if (!SkipComment()) {
+          return false;
+        }
+        continue;
+      }
+      if (c == '{') {
+        ++depth;
+        ++mPos;
+        continue;
+      }
+      if (c == '}') {
+        if (depth == 0) {
+          aBody.Assign(Substring(mInput, start, mPos - start));
+          ++mPos;
+          return true;
+        }
+        --depth;
+        ++mPos;
+        continue;
+      }
+      ++mPos;
+    }
+
+    return false;
+  }
+
+  bool
+  ReadQualifiedRulePrelude(nsAString& aPrelude)
+  {
+    uint32_t start = mPos;
+    int32_t parenDepth = 0;
+    int32_t bracketDepth = 0;
+
+    while (!AtEnd()) {
+      char16_t c = Peek();
+      if (c == '"' || c == '\'') {
+        if (!SkipString(c)) {
+          return false;
+        }
+        continue;
+      }
+      if (StartsWithComment()) {
+        if (!SkipComment()) {
+          return false;
+        }
+        continue;
+      }
+      if (c == '(') {
+        ++parenDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == ')' && parenDepth > 0) {
+        --parenDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == '[') {
+        ++bracketDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == ']' && bracketDepth > 0) {
+        --bracketDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == '{' && parenDepth == 0 && bracketDepth == 0) {
+        aPrelude.Assign(Substring(mInput, start, mPos - start));
+        TrimWhitespace(aPrelude);
+        ++mPos;
+        return !aPrelude.IsEmpty();
+      }
+      if ((c == ';' || c == '}') && parenDepth == 0 && bracketDepth == 0) {
+        return false;
+      }
+      ++mPos;
+    }
+
+    return false;
+  }
+
+  bool
+  ReadAtRulePrelude(nsAString& aPrelude, nsACString& aName, bool& aHasBlock)
+  {
+    MOZ_ASSERT(!AtEnd() && Peek() == '@', "expected at-rule");
+
+    uint32_t start = mPos;
+    ++mPos;
+    aName.Truncate();
+    while (!AtEnd() && IsAtRuleNameChar(Peek())) {
+      char16_t c = Peek();
+      aName.Append(char(c <= 0x7f ? c : '?'));
+      ++mPos;
+    }
+    LowercaseASCII(aName);
+
+    int32_t parenDepth = 0;
+    int32_t bracketDepth = 0;
+    while (!AtEnd()) {
+      char16_t c = Peek();
+      if (c == '"' || c == '\'') {
+        if (!SkipString(c)) {
+          return false;
+        }
+        continue;
+      }
+      if (StartsWithComment()) {
+        if (!SkipComment()) {
+          return false;
+        }
+        continue;
+      }
+      if (c == '(') {
+        ++parenDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == ')' && parenDepth > 0) {
+        --parenDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == '[') {
+        ++bracketDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == ']' && bracketDepth > 0) {
+        --bracketDepth;
+        ++mPos;
+        continue;
+      }
+      if (parenDepth == 0 && bracketDepth == 0) {
+        if (c == ';') {
+          aPrelude.Assign(Substring(mInput, start, mPos - start));
+          TrimWhitespace(aPrelude);
+          ++mPos;
+          aHasBlock = false;
+          return true;
+        }
+        if (c == '{') {
+          aPrelude.Assign(Substring(mInput, start, mPos - start));
+          TrimWhitespace(aPrelude);
+          ++mPos;
+          aHasBlock = true;
+          return true;
+        }
+      }
+      ++mPos;
+    }
+
+    return false;
+  }
+
+  bool
+  ConsumeDeclaration(nsAString& aDeclaration)
+  {
+    uint32_t start = mPos;
+    int32_t parenDepth = 0;
+    int32_t bracketDepth = 0;
+    int32_t braceDepth = 0;
+
+    while (!AtEnd()) {
+      char16_t c = Peek();
+      if (c == '"' || c == '\'') {
+        if (!SkipString(c)) {
+          return false;
+        }
+        continue;
+      }
+      if (StartsWithComment()) {
+        if (!SkipComment()) {
+          return false;
+        }
+        continue;
+      }
+      if (c == '(') {
+        ++parenDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == ')' && parenDepth > 0) {
+        --parenDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == '[') {
+        ++bracketDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == ']' && bracketDepth > 0) {
+        --bracketDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == '{') {
+        ++braceDepth;
+        ++mPos;
+        continue;
+      }
+      if (c == '}') {
+        if (braceDepth == 0 && parenDepth == 0 && bracketDepth == 0) {
+          break;
+        }
+        if (braceDepth > 0) {
+          --braceDepth;
+        }
+        ++mPos;
+        continue;
+      }
+      if (c == ';' && parenDepth == 0 && bracketDepth == 0 &&
+          braceDepth == 0) {
+        ++mPos;
+        break;
+      }
+      ++mPos;
+    }
+
+    aDeclaration.Assign(Substring(mInput, start, mPos - start));
+    TrimWhitespace(aDeclaration);
+    if (aDeclaration.IsEmpty()) {
+      return false;
+    }
+    if (aDeclaration.Last() != ';') {
+      aDeclaration.Append(';');
+    }
+    return true;
+  }
+
+  bool
+  ParseAtRule(nsAString& aOutput, const SelectorList* aParents)
+  {
+    nsAutoString prelude;
+    nsAutoCString name;
+    bool hasBlock = false;
+    if (!ReadAtRulePrelude(prelude, name, hasBlock)) {
+      return false;
+    }
+
+    if (!hasBlock) {
+      aOutput.Append(prelude);
+      aOutput.AppendLiteral(";\n");
+      return true;
+    }
+
+    if (!ShouldProcessGroupRule(name)) {
+      nsAutoString body;
+      if (!ReadRawBlockBody(body)) {
+        return false;
+      }
+      aOutput.Append(prelude);
+      aOutput.AppendLiteral(" {");
+      aOutput.Append(body);
+      aOutput.AppendLiteral("}\n");
+      return true;
+    }
+
+    nsAutoString inner;
+    if (aParents) {
+      mSawNesting = true;
+      if (!ProcessStyleContext(*aParents, inner)) {
+        return false;
+      }
+    } else {
+      if (!ProcessStylesheet(inner, true)) {
+        return false;
+      }
+    }
+
+    aOutput.Append(prelude);
+    aOutput.AppendLiteral(" {\n");
+    aOutput.Append(inner);
+    aOutput.AppendLiteral("}\n");
+    return true;
+  }
+
+  bool
+  ParseQualifiedRule(nsAString& aOutput, const SelectorList* aParents)
+  {
+    nsAutoString prelude;
+    if (!ReadQualifiedRulePrelude(prelude)) {
+      return false;
+    }
+
+    SelectorList selectors;
+    if (aParents) {
+      mSawNesting = true;
+      if (!ExpandNestedSelectors(*aParents, prelude, selectors)) {
+        return false;
+      }
+    } else if (!SplitSelectorList(prelude, selectors)) {
+      return false;
+    }
+
+    return ProcessStyleContext(selectors, aOutput);
+  }
+
+  bool
+  ProcessStyleContext(const SelectorList& aSelectors, nsAString& aOutput)
+  {
+    nsAutoString declarations;
+
+    while (!AtEnd()) {
+      SkipWhitespaceAndComments();
+      if (AtEnd()) {
+        return false;
+      }
+
+      char16_t c = Peek();
+      if (c == '}') {
+        ++mPos;
+        FlushDeclarations(aSelectors, declarations, aOutput);
+        return true;
+      }
+
+      if (c == '@') {
+        FlushDeclarations(aSelectors, declarations, aOutput);
+        if (!ParseAtRule(aOutput, &aSelectors)) {
+          return false;
+        }
+        continue;
+      }
+
+      if (StartsNestedSelector(c) || LooksLikeTypeSelectorRule()) {
+        FlushDeclarations(aSelectors, declarations, aOutput);
+        if (!ParseQualifiedRule(aOutput, &aSelectors)) {
+          return false;
+        }
+        continue;
+      }
+
+      nsAutoString declaration;
+      if (!ConsumeDeclaration(declaration)) {
+        return false;
+      }
+      if (!declarations.IsEmpty()) {
+        declarations.Append(' ');
+      }
+      declarations.Append(declaration);
+    }
+
+    return false;
+  }
+
+  bool
+  ProcessStylesheet(nsAString& aOutput, bool aStopAtBlockEnd)
+  {
+    while (!AtEnd()) {
+      SkipWhitespaceAndComments();
+      if (AtEnd()) {
+        return !aStopAtBlockEnd;
+      }
+
+      if (Peek() == '}') {
+        if (!aStopAtBlockEnd) {
+          return false;
+        }
+        ++mPos;
+        return true;
+      }
+
+      if (Peek() == '@') {
+        if (!ParseAtRule(aOutput, nullptr)) {
+          return false;
+        }
+      } else {
+        if (!ParseQualifiedRule(aOutput, nullptr)) {
+          return false;
+        }
+      }
+    }
+
+    return !aStopAtBlockEnd;
+  }
+
+  const nsAString& mInput;
+  uint32_t mPos;
+  bool mSawNesting;
+};
+
+} // namespace
+
+bool
+FlattenBasicCSSNesting(const nsAString& aInput, nsAString& aOutput)
+{
+  CSSNestingFlattener flattener(aInput);
+  return flattener.Flatten(aOutput);
+}
+
+} // namespace css
+} // namespace mozilla
diff --git a/layout/style/CSSNestingFlattener.h b/layout/style/CSSNestingFlattener.h
new file mode 100644
index 0000000000..41a9d4432d
--- /dev/null
+++ b/layout/style/CSSNestingFlattener.h
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
+
+#ifndef CSSNestingFlattener_h
+#define CSSNestingFlattener_h
+
+class nsAString;
+
+namespace mozilla {
+namespace css {
+
+bool FlattenBasicCSSNesting(const nsAString& aInput, nsAString& aOutput);
+
+} // namespace css
+} // namespace mozilla
+
+#endif // CSSNestingFlattener_h
diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp
index 05bb84018f..7491c73644 100644
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -7,6 +7,8 @@
 
 #include "mozilla/CSSStyleSheet.h"
 
+#include 
+
 #include "nsIAtom.h"
 #include "nsCSSRuleProcessor.h"
 #include "mozilla/MemoryReporting.h"
@@ -130,6 +132,153 @@ int32_t DoCompare(Numeric a, Numeric b)
   return 1;
 }
 
+struct MediaQueryTypedCalcLengthResult
+{
+  double mValue;
+  int32_t mExponent;
+};
+
+static bool
+EvaluateMediaQueryTypedCalcLength(nsPresContext* aPresContext,
+                                  const nsCSSValue& aValue,
+                                  MediaQueryTypedCalcLengthResult& aResult)
+{
+  switch (aValue.GetUnit()) {
+    case eCSSUnit_Calc: {
+      nsCSSValue::Array* array = aValue.GetArrayValue();
+      MOZ_ASSERT(array->Count() == 1, "unexpected length");
+      return EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(0),
+                                               aResult);
+    }
+
+    case eCSSUnit_Calc_Plus:
+    case eCSSUnit_Calc_Minus: {
+      nsCSSValue::Array* array = aValue.GetArrayValue();
+      MOZ_ASSERT(array->Count() == 2, "unexpected length");
+      MediaQueryTypedCalcLengthResult lhs;
+      MediaQueryTypedCalcLengthResult rhs;
+      if (!EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(0), lhs) ||
+          !EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(1), rhs) ||
+          lhs.mExponent != rhs.mExponent) {
+        return false;
+      }
+      aResult.mExponent = lhs.mExponent;
+      aResult.mValue = aValue.GetUnit() == eCSSUnit_Calc_Plus
+                         ? lhs.mValue + rhs.mValue
+                         : lhs.mValue - rhs.mValue;
+      return true;
+    }
+
+    case eCSSUnit_Calc_Times_L:
+    case eCSSUnit_Calc_Times_R:
+    case eCSSUnit_Calc_Divided: {
+      nsCSSValue::Array* array = aValue.GetArrayValue();
+      MOZ_ASSERT(array->Count() == 2, "unexpected length");
+      MediaQueryTypedCalcLengthResult lhs;
+      MediaQueryTypedCalcLengthResult rhs;
+      if (!EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(0), lhs) ||
+          !EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(1), rhs)) {
+        return false;
+      }
+      if (aValue.GetUnit() == eCSSUnit_Calc_Divided) {
+        if (rhs.mValue == 0.0) {
+          return false;
+        }
+        aResult.mValue = lhs.mValue / rhs.mValue;
+        aResult.mExponent = lhs.mExponent - rhs.mExponent;
+      } else {
+        aResult.mValue = lhs.mValue * rhs.mValue;
+        aResult.mExponent = lhs.mExponent + rhs.mExponent;
+      }
+      return true;
+    }
+
+    case eCSSUnit_Calc_Min:
+    case eCSSUnit_Calc_Max:
+    case eCSSUnit_Calc_Clamp: {
+      nsCSSValue::Array* array = aValue.GetArrayValue();
+      MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Calc_Clamp ||
+                 array->Count() == 3, "unexpected length");
+      MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Calc_Clamp ||
+                 array->Count() >= 1, "unexpected length");
+
+      MediaQueryTypedCalcLengthResult result;
+      if (!EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(0),
+                                             result)) {
+        return false;
+      }
+
+      if (aValue.GetUnit() == eCSSUnit_Calc_Clamp) {
+        MediaQueryTypedCalcLengthResult center;
+        MediaQueryTypedCalcLengthResult max;
+        if (!EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(1),
+                                               center) ||
+            !EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(2),
+                                               max) ||
+            result.mExponent != center.mExponent ||
+            result.mExponent != max.mExponent) {
+          return false;
+        }
+        aResult.mExponent = result.mExponent;
+        aResult.mValue = std::max(result.mValue,
+                                  std::min(center.mValue, max.mValue));
+        return true;
+      }
+
+      for (uint32_t i = 1; i < array->Count(); ++i) {
+        MediaQueryTypedCalcLengthResult item;
+        if (!EvaluateMediaQueryTypedCalcLength(aPresContext, array->Item(i),
+                                               item) ||
+            result.mExponent != item.mExponent) {
+          return false;
+        }
+        result.mValue = aValue.GetUnit() == eCSSUnit_Calc_Min
+                          ? std::min(result.mValue, item.mValue)
+                          : std::max(result.mValue, item.mValue);
+      }
+      aResult = result;
+      return true;
+    }
+
+    case eCSSUnit_Number:
+      aResult.mValue = aValue.GetFloatValue();
+      aResult.mExponent = 0;
+      return true;
+
+    default:
+      break;
+  }
+
+  if (!aValue.IsLengthUnit()) {
+    return false;
+  }
+
+  aResult.mValue = double(nsRuleNode::CalcLengthWithInitialFont(aPresContext,
+                                                                aValue));
+  aResult.mExponent = 1;
+  return true;
+}
+
+static bool
+ComputeMediaQueryTypedCalcLength(nsPresContext* aPresContext,
+                                 const nsCSSValue& aValue,
+                                 nscoord& aResult)
+{
+  if (aValue.IsLengthUnit()) {
+    aResult = nsRuleNode::CalcLengthWithInitialFont(aPresContext, aValue);
+    return true;
+  }
+
+  MediaQueryTypedCalcLengthResult result;
+  if (!EvaluateMediaQueryTypedCalcLength(aPresContext, aValue, result) ||
+      result.mExponent != 1) {
+    return false;
+  }
+
+  aResult = NSToCoordFloorClamped(result.mValue);
+  return true;
+}
+
 bool
 nsMediaExpression::Matches(nsPresContext *aPresContext,
                            const nsCSSValue& aActualValue) const
@@ -283,6 +432,10 @@ nsMediaExpression::Matches(nsPresContext *aPresContext,
       return cmp != 1;
     case nsMediaExpression::eEqual:
       return cmp == 0;
+    case nsMediaExpression::eMinExclusive:
+      return cmp == 1;
+    case nsMediaExpression::eMaxExclusive:
+      return cmp == -1;
   }
   NS_NOTREACHED("unexpected mRange");
   return false;
@@ -487,7 +640,13 @@ nsMediaQuery::AppendToString(nsAString& aString) const
     aString.Append(nsDependentAtomString(*feature->mName));
 
     if (expr.mValue.GetUnit() != eCSSUnit_Null) {
-      aString.AppendLiteral(": ");
+      if (expr.mRange == nsMediaExpression::eMinExclusive) {
+        aString.AppendLiteral(" > ");
+      } else if (expr.mRange == nsMediaExpression::eMaxExclusive) {
+        aString.AppendLiteral(" < ");
+      } else {
+        aString.AppendLiteral(": ");
+      }
       switch (feature->mValueType) {
         case nsMediaFeature::eLength:
           NS_ASSERTION(expr.mValue.IsLengthUnit(), "bad unit");
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index 581fe9622d..a6a471a0b8 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -885,9 +885,10 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
   }
 
   // In standards mode, a style sheet must have one of these MIME
-  // types to be processed at all.  In quirks mode, we accept any
-  // MIME type, but only if the style sheet is same-origin with the
-  // requesting document or parent sheet.  See bug 524223.
+  // types to be processed at all, unless it is same-origin.
+  // For same-origin sheets, we accept any MIME type to match modern
+  // browser behavior (Chrome, Firefox). Cross-origin sheets require
+  // a valid CSS MIME type for security.
 
   bool validType = contentType.EqualsLiteral("text/css") ||
     contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
@@ -906,7 +907,7 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
       }
     }
 
-    if (sameOrigin && mLoader->mCompatMode == eCompatibility_NavQuirks) {
+    if (sameOrigin) {
       errorMessage = "MimeNotCssWarn";
       errorFlag = nsIScriptError::warningFlag;
     } else {
diff --git a/layout/style/moz.build b/layout/style/moz.build
index bc8959c1a3..3dfbd58012 100644
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -127,6 +127,7 @@ UNIFIED_SOURCES += [
     'CounterStyleManager.cpp',
     'CSS.cpp',
     'CSSLexer.cpp',
+    'CSSNestingFlattener.cpp',
     'CSSRuleList.cpp',
     'CSSStyleSheet.cpp',
     'CSSVariableDeclarations.cpp',
diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
index 59872b0f67..6e24a427b0 100644
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -7,6 +7,7 @@
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/Move.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/TypedEnumBits.h"
@@ -17,6 +18,7 @@
 #include      // for std::regex and std::regex_match
 
 #include "nsCSSParser.h"
+#include "CSSNestingFlattener.h"
 #include "nsAlgorithm.h"
 #include "nsCSSProps.h"
 #include "nsCSSKeywords.h"
@@ -71,6 +73,7 @@ static bool sMozGradientsEnabled;
 static bool sControlCharVisibility;
 static bool sLegacyNegationPseudoClassEnabled;
 static bool sCascadeLayersEnabled;
+static bool sNestingEnabled;
 
 const uint32_t
 nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
@@ -1823,7 +1826,14 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
                "Sheet principal does not match passed principal");
 #endif
 
-  nsCSSScanner scanner(aInput, aLineNumber);
+  nsAutoString flattenedInput;
+  const nsAString* input = &aInput;
+  if (sNestingEnabled &&
+      mozilla::css::FlattenBasicCSSNesting(aInput, flattenedInput)) {
+    input = &flattenedInput;
+  }
+
+  nsCSSScanner scanner(*input, aLineNumber);
   css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
   InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
 
@@ -18987,6 +18997,8 @@ nsCSSParser::Startup()
                                "layout.css.legacy-negation-pseudo.enabled");
   Preferences::AddBoolVarCache(&sCascadeLayersEnabled,
                                "layout.css.cascade-layers.enabled");
+  Preferences::AddBoolVarCache(&sNestingEnabled,
+                               "layout.css.nesting.enabled");
 }
 
 nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h
index 4bd0a53f8d..ea717c40df 100644
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -470,19 +470,17 @@ CSS_PROP_DISPLAY(
     kAppearanceKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Discrete)
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_POSITION(
     aspect-ratio,
     aspect_ratio,
     AspectRatio,
-    CSS_PROPERTY_INTERNAL |
-        CSS_PROPERTY_PARSE_INACCESSIBLE,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_PARSER_FUNCTION,
     "",
-    VARIANT_NUMBER,
+    0,
     nullptr,
     offsetof(nsStylePosition, mAspectRatio),
     eStyleAnimType_None)
-#endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_DISPLAY(
     backface-visibility,
     backface_visibility,
diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h
index ae50355147..b0fcbbeaa0 100644
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -477,6 +477,11 @@ enum nsCSSUnit {
   eCSSUnit_Calc_Times_L = 33,     // (nsCSSValue::Array*) num * val within calc
   eCSSUnit_Calc_Times_R = 34,     // (nsCSSValue::Array*) val * num within calc
   eCSSUnit_Calc_Divided = 35,     // (nsCSSValue::Array*) / within calc
+  // Min and Max have arrays with one or more elements. Clamp has an array
+  // with exactly 3 elements: lower bound, center, upper bound.
+  eCSSUnit_Calc_Min     = 36,     // (nsCSSValue::Array*) min() node
+  eCSSUnit_Calc_Max     = 37,     // (nsCSSValue::Array*) max() node
+  eCSSUnit_Calc_Clamp   = 38,     // (nsCSSValue::Array*) clamp() node
 
   eCSSUnit_URL          = 40,     // (nsCSSValue::URL*) value
   eCSSUnit_Image        = 41,     // (nsCSSValue::Image*) value
@@ -711,12 +716,12 @@ public:
   bool      IsTimeUnit() const  
     { return eCSSUnit_Seconds <= mUnit && mUnit <= eCSSUnit_Milliseconds; }
   bool      IsCalcUnit() const
-    { return eCSSUnit_Calc <= mUnit && mUnit <= eCSSUnit_Calc_Divided; }
+    { return eCSSUnit_Calc <= mUnit && mUnit <= eCSSUnit_Calc_Clamp; }
 
   bool      UnitHasStringValue() const
     { return eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Element; }
   bool      UnitHasArrayValue() const
-    { return eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Calc_Divided; }
+    { return eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Calc_Clamp; }
 
   // Checks for the nsCSSValue being of a particular type of color unit:
   //
diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp
index 686ea6a1f5..af512e2626 100644
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -964,6 +964,22 @@ nsComputedDOMStyle::DoGetBinding()
   return val.forget();
 }
 
+already_AddRefed
+nsComputedDOMStyle::DoGetAspectRatio()
+{
+  RefPtr val = new nsROCSSPrimitiveValue;
+  float ratio = StylePosition()->mAspectRatio;
+  if (ratio == 0.0f) {
+    val->SetIdent(eCSSKeyword_auto);
+  } else {
+    nsAutoString ratioString;
+    nsStyleUtil::AppendCSSNumber(ratio, ratioString);
+    ratioString.AppendLiteral(" / 1");
+    val->SetString(ratioString);
+  }
+  return val.forget();
+}
+
 already_AddRefed
 nsComputedDOMStyle::DoGetClear()
 {
@@ -1883,6 +1899,94 @@ nsComputedDOMStyle::DoGetBackgroundColor()
   return val.forget();
 }
 
+static void
+AppendCalcNodeToString(const nsStyleCoord::CalcNode* aNode,
+                       nsROCSSPrimitiveValue* aPrimitive,
+                       nsAString& aResult);
+
+static void
+AppendCalcLeafToString(const nsStyleCoord::CalcNode* aNode,
+                       nsROCSSPrimitiveValue* aPrimitive,
+                       nsAString& aResult)
+{
+  nsAutoString tmp;
+
+  if (!aNode->mHasPercent) {
+    aPrimitive->SetAppUnits(aNode->mLength);
+    aPrimitive->GetCssText(tmp);
+    aResult.Append(tmp);
+    return;
+  }
+
+  aResult.AppendLiteral("calc(");
+  aPrimitive->SetAppUnits(aNode->mLength);
+  aPrimitive->GetCssText(tmp);
+  aResult.Append(tmp);
+  aResult.AppendLiteral(" + ");
+  aPrimitive->SetPercent(aNode->mPercent);
+  aPrimitive->GetCssText(tmp);
+  aResult.Append(tmp);
+  aResult.Append(')');
+}
+
+static void
+AppendCalcNodeToString(const nsStyleCoord::CalcNode* aNode,
+                       nsROCSSPrimitiveValue* aPrimitive,
+                       nsAString& aResult)
+{
+  using Type = nsStyleCoord::CalcNode::Type;
+
+  switch (aNode->mType) {
+    case Type::Leaf:
+      AppendCalcLeafToString(aNode, aPrimitive, aResult);
+      return;
+    case Type::Add:
+    case Type::Subtract:
+      aResult.AppendLiteral("calc(");
+      AppendCalcNodeToString(aNode->mChildren[0], aPrimitive, aResult);
+      aResult.Append(aNode->mType == Type::Add
+                       ? NS_LITERAL_STRING(" + ")
+                       : NS_LITERAL_STRING(" - "));
+      AppendCalcNodeToString(aNode->mChildren[1], aPrimitive, aResult);
+      aResult.Append(')');
+      return;
+    case Type::Multiply:
+    case Type::Divide: {
+      nsAutoString tmp;
+      aResult.AppendLiteral("calc(");
+      AppendCalcNodeToString(aNode->mChildren[0], aPrimitive, aResult);
+      aResult.Append(aNode->mType == Type::Multiply
+                       ? NS_LITERAL_STRING(" * ")
+                       : NS_LITERAL_STRING(" / "));
+      aPrimitive->SetNumber(aNode->mNumber);
+      aPrimitive->GetCssText(tmp);
+      aResult.Append(tmp);
+      aResult.Append(')');
+      return;
+    }
+    case Type::Min:
+    case Type::Max:
+    case Type::Clamp:
+      if (aNode->mType == Type::Min) {
+        aResult.AppendLiteral("min(");
+      } else if (aNode->mType == Type::Max) {
+        aResult.AppendLiteral("max(");
+      } else {
+        aResult.AppendLiteral("clamp(");
+      }
+      for (uint32_t i = 0; i < aNode->mChildren.Length(); ++i) {
+        if (i != 0) {
+          aResult.AppendLiteral(", ");
+        }
+        AppendCalcNodeToString(aNode->mChildren[i], aPrimitive, aResult);
+      }
+      aResult.Append(')');
+      return;
+  }
+
+  MOZ_ASSERT_UNREACHABLE("unexpected calc node type");
+}
+
 static void
 SetValueToCalc(const nsStyleCoord::CalcValue* aCalc,
                nsROCSSPrimitiveValue*         aValue)
@@ -1909,6 +2013,21 @@ SetValueToCalc(const nsStyleCoord::CalcValue* aCalc,
   aValue->SetString(result); // not really SetString
 }
 
+static void
+SetValueToCalc(const nsStyleCoord::Calc* aCalc,
+               nsROCSSPrimitiveValue*    aValue)
+{
+  if (!aCalc->HasCalcNode()) {
+    SetValueToCalc(static_cast(aCalc), aValue);
+    return;
+  }
+
+  RefPtr val = new nsROCSSPrimitiveValue;
+  nsAutoString result;
+  AppendCalcNodeToString(aCalc->mNode, val, result);
+  aValue->SetString(result); // not really SetString
+}
+
 static void
 AppendCSSGradientLength(const nsStyleCoord&    aValue,
                         nsROCSSPrimitiveValue* aPrimitive,
@@ -6841,6 +6960,4 @@ already_AddRefed
 nsComputedDOMStyle::DoGetOverflowBlockEnd()
 {
   return DoGetOverflowBlock();
-}
-
-
+}
\ No newline at end of file
diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h
index 718a38ff47..a4c1b559a0 100644
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -226,6 +226,7 @@ private:
    */
 
   already_AddRefed DoGetAppearance();
+  already_AddRefed DoGetAspectRatio();
 
   /* Box properties */
   already_AddRefed DoGetBoxAlign();
diff --git a/layout/style/nsComputedDOMStylePropertyList.h b/layout/style/nsComputedDOMStylePropertyList.h
index db0a68c660..50a32dccc6 100644
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -51,6 +51,7 @@ COMPUTED_STYLE_PROP(animation_iteration_count,     AnimationIterationCount)
 COMPUTED_STYLE_PROP(animation_name,                AnimationName)
 COMPUTED_STYLE_PROP(animation_play_state,          AnimationPlayState)
 COMPUTED_STYLE_PROP(animation_timing_function,     AnimationTimingFunction)
+COMPUTED_STYLE_PROP(aspect_ratio,                  AspectRatio)
 COMPUTED_STYLE_PROP(backface_visibility,           BackfaceVisibility)
 //// COMPUTED_STYLE_PROP(background,               Background)
 COMPUTED_STYLE_PROP(background_attachment,         BackgroundAttachment)
diff --git a/layout/style/nsIMediaList.h b/layout/style/nsIMediaList.h
index 8f8c692cd6..52244b48f4 100644
--- a/layout/style/nsIMediaList.h
+++ b/layout/style/nsIMediaList.h
@@ -33,7 +33,7 @@ class DocumentRule;
 } // namespace mozilla
 
 struct nsMediaExpression {
-  enum Range { eMin, eMax, eEqual };
+  enum Range { eMin, eMax, eEqual, eMinExclusive, eMaxExclusive };
 
   const nsMediaFeature *mFeature;
   Range mRange;
diff --git a/layout/style/nsRuleNode.h b/layout/style/nsRuleNode.h
index 7ca3a165f9..b4118335e1 100644
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -986,9 +986,22 @@ public:
   struct ComputedCalc {
     nscoord mLength;
     float mPercent;
+    bool mHasPercent;
+    RefPtr mNode;
 
     ComputedCalc(nscoord aLength, float aPercent)
-      : mLength(aLength), mPercent(aPercent) {}
+      : mLength(aLength), mPercent(aPercent),
+        mHasPercent(aPercent != 0.0f) {}
+
+    ComputedCalc(nscoord aLength, float aPercent, bool aHasPercent)
+      : mLength(aLength), mPercent(aPercent),
+        mHasPercent(aHasPercent) {}
+
+    explicit ComputedCalc(already_AddRefed aNode)
+      : mLength(0), mPercent(0.0f), mHasPercent(true), mNode(aNode) {}
+
+    bool HasNode() const { return !!mNode; }
+    already_AddRefed ToCalcNode() const;
   };
   static ComputedCalc
   SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
diff --git a/layout/style/nsStyleCoord.cpp b/layout/style/nsStyleCoord.cpp
index f93bb53f63..d26e02438c 100644
--- a/layout/style/nsStyleCoord.cpp
+++ b/layout/style/nsStyleCoord.cpp
@@ -8,6 +8,150 @@
 #include "nsStyleCoord.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/PodOperations.h"
+#include 
+
+already_AddRefed
+nsStyleCoord::CalcNode::CreateLeaf(nscoord aLength, float aPercent,
+                                   bool aHasPercent)
+{
+  RefPtr node = new CalcNode(Type::Leaf);
+  node->mLength = aLength;
+  node->mPercent = aPercent;
+  node->mHasPercent = aHasPercent;
+  return node.forget();
+}
+
+already_AddRefed
+nsStyleCoord::CalcNode::Create(Type aType)
+{
+  RefPtr node = new CalcNode(aType);
+  return node.forget();
+}
+
+nsStyleCoord::CalcNode::CalcNode(Type aType)
+  : mType(aType)
+  , mLength(0)
+  , mPercent(0.0f)
+  , mNumber(0.0f)
+  , mHasPercent(false)
+{
+}
+
+bool
+nsStyleCoord::CalcNode::HasPercent() const
+{
+  if (mHasPercent) {
+    return true;
+  }
+  for (const RefPtr& child : mChildren) {
+    if (child->HasPercent()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool
+nsStyleCoord::CalcNode::Equals(const CalcNode& aOther) const
+{
+  if (mType != aOther.mType ||
+      mLength != aOther.mLength ||
+      mPercent != aOther.mPercent ||
+      mNumber != aOther.mNumber ||
+      mHasPercent != aOther.mHasPercent ||
+      mChildren.Length() != aOther.mChildren.Length()) {
+    return false;
+  }
+
+  for (uint32_t i = 0; i < mChildren.Length(); ++i) {
+    if (!mChildren[i]->Equals(*aOther.mChildren[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+uint32_t
+nsStyleCoord::CalcNode::HashValue(uint32_t aHash) const
+{
+  aHash = mozilla::AddToHash(aHash, uint8_t(mType), mLength, mPercent,
+                             mNumber, mHasPercent);
+  for (const RefPtr& child : mChildren) {
+    aHash = child->HashValue(aHash);
+  }
+  return aHash;
+}
+
+static nscoord
+ResolveCalcNode(const nsStyleCoord::CalcNode& aNode, nscoord aPercentageBasis)
+{
+  using Type = nsStyleCoord::CalcNode::Type;
+
+  switch (aNode.mType) {
+    case Type::Leaf:
+      return aNode.mLength +
+             NSToCoordFloorClamped(aPercentageBasis * aNode.mPercent);
+    case Type::Add:
+      MOZ_ASSERT(aNode.mChildren.Length() == 2, "unexpected child count");
+      return NSCoordSaturatingAdd(
+        ResolveCalcNode(*aNode.mChildren[0], aPercentageBasis),
+        ResolveCalcNode(*aNode.mChildren[1], aPercentageBasis));
+    case Type::Subtract:
+      MOZ_ASSERT(aNode.mChildren.Length() == 2, "unexpected child count");
+      return NSCoordSaturatingSubtract(
+        ResolveCalcNode(*aNode.mChildren[0], aPercentageBasis),
+        ResolveCalcNode(*aNode.mChildren[1], aPercentageBasis), 0);
+    case Type::Multiply:
+      MOZ_ASSERT(aNode.mChildren.Length() == 1, "unexpected child count");
+      return NSCoordSaturatingMultiply(
+        ResolveCalcNode(*aNode.mChildren[0], aPercentageBasis),
+        aNode.mNumber);
+    case Type::Divide:
+      MOZ_ASSERT(aNode.mChildren.Length() == 1, "unexpected child count");
+      return NSCoordSaturatingMultiply(
+        ResolveCalcNode(*aNode.mChildren[0], aPercentageBasis),
+        1.0f / aNode.mNumber);
+    case Type::Min: {
+      MOZ_ASSERT(!aNode.mChildren.IsEmpty(), "unexpected child count");
+      nscoord result = ResolveCalcNode(*aNode.mChildren[0], aPercentageBasis);
+      for (uint32_t i = 1; i < aNode.mChildren.Length(); ++i) {
+        result = std::min(result,
+                          ResolveCalcNode(*aNode.mChildren[i],
+                                          aPercentageBasis));
+      }
+      return result;
+    }
+    case Type::Max: {
+      MOZ_ASSERT(!aNode.mChildren.IsEmpty(), "unexpected child count");
+      nscoord result = ResolveCalcNode(*aNode.mChildren[0], aPercentageBasis);
+      for (uint32_t i = 1; i < aNode.mChildren.Length(); ++i) {
+        result = std::max(result,
+                          ResolveCalcNode(*aNode.mChildren[i],
+                                          aPercentageBasis));
+      }
+      return result;
+    }
+    case Type::Clamp:
+      MOZ_ASSERT(aNode.mChildren.Length() == 3, "unexpected child count");
+      return std::max(ResolveCalcNode(*aNode.mChildren[0], aPercentageBasis),
+                      std::min(ResolveCalcNode(*aNode.mChildren[1],
+                                               aPercentageBasis),
+                               ResolveCalcNode(*aNode.mChildren[2],
+                                               aPercentageBasis)));
+  }
+
+  MOZ_ASSERT_UNREACHABLE("unexpected calc node type");
+  return 0;
+}
+
+nscoord
+nsStyleCoord::Calc::Resolve(nscoord aPercentageBasis) const
+{
+  if (mNode) {
+    return ResolveCalcNode(*mNode, aPercentageBasis);
+  }
+  return mLength + NSToCoordFloorClamped(aPercentageBasis * mPercent);
+}
 
 nsStyleCoord::nsStyleCoord(nsStyleUnit aUnit)
   : mUnit(aUnit)
@@ -71,8 +215,15 @@ bool nsStyleCoord::operator==(const nsStyleCoord& aOther) const
     case eStyleUnit_Integer:
     case eStyleUnit_Enumerated:
       return mValue.mInt == aOther.mValue.mInt;
-    case eStyleUnit_Calc:
-      return *this->GetCalcValue() == *aOther.GetCalcValue();
+    case eStyleUnit_Calc: {
+      Calc* thisCalc = GetCalcValue();
+      Calc* otherCalc = aOther.GetCalcValue();
+      if (thisCalc->HasCalcNode() || otherCalc->HasCalcNode()) {
+        return thisCalc->HasCalcNode() == otherCalc->HasCalcNode() &&
+               thisCalc->mNode->Equals(*otherCalc->mNode);
+      }
+      return *thisCalc == *otherCalc;
+    }
   }
   MOZ_ASSERT(false, "unexpected unit");
   return false;
@@ -100,13 +251,17 @@ uint32_t nsStyleCoord::HashValue(uint32_t aHash = 0) const
     case eStyleUnit_Integer:
     case eStyleUnit_Enumerated:
       return mozilla::AddToHash(aHash, mValue.mInt);
-    case eStyleUnit_Calc:
+    case eStyleUnit_Calc: {
       Calc* calcValue = GetCalcValue();
+      if (calcValue->HasCalcNode()) {
+        return calcValue->mNode->HashValue(aHash);
+      }
       aHash = mozilla::AddToHash(aHash, calcValue->mLength);
       if (HasPercent()) {
         return mozilla::AddToHash(aHash, calcValue->mPercent);
       }
       return aHash;
+    }
   }
   MOZ_ASSERT(false, "unexpected unit");
   return aHash;
diff --git a/layout/style/nsStyleCoord.h b/layout/style/nsStyleCoord.h
index bd4f15ab51..df73c25355 100644
--- a/layout/style/nsStyleCoord.h
+++ b/layout/style/nsStyleCoord.h
@@ -10,6 +10,8 @@
 
 #include "nsCoord.h"
 #include "nsStyleConsts.h"
+#include "nsTArray.h"
+#include "mozilla/RefPtr.h"
 
 namespace mozilla {
 
@@ -106,15 +108,111 @@ public:
 
     // If this returns true the value is definitely zero. It it returns false
     // it might be zero. So it's best used for conservative optimization.
-    bool IsDefinitelyZero() const { return mLength == 0 && mPercent == 0; }
+    bool IsDefinitelyZero() const {
+      return mLength == 0 && mPercent == 0 && !mHasPercent;
+    }
+  };
+
+  struct CalcNode final {
+#if defined(__MINGW32__)
+    MOZ_NEVER_INLINE MozExternalRefCountType AddRef(void)
+    {
+      MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(CalcNode)
+      MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
+      nsrefcnt count = ++mRefCnt;
+      NS_LOG_ADDREF(this, count, "CalcNode", sizeof(*this));
+      return (nsrefcnt) count;
+    }
+
+    MOZ_NEVER_INLINE MozExternalRefCountType Release(void)
+    {
+      MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
+      nsrefcnt count = --mRefCnt;
+      NS_LOG_RELEASE(this, count, "CalcNode");
+      if (count == 0) {
+        delete (this);
+        return 0;
+      }
+      return count;
+    }
+    typedef mozilla::TrueType HasThreadSafeRefCnt;
+  protected:
+    ::mozilla::ThreadSafeAutoRefCnt mRefCnt;
+  public:
+#else
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CalcNode)
+#endif
+
+    enum class Type : uint8_t {
+      Leaf,
+      Add,
+      Subtract,
+      Multiply,
+      Divide,
+      Min,
+      Max,
+      Clamp
+    };
+
+    static already_AddRefed CreateLeaf(nscoord aLength,
+                                                 float aPercent,
+                                                 bool aHasPercent);
+    static already_AddRefed Create(Type aType);
+
+    bool HasPercent() const;
+    bool Equals(const CalcNode& aOther) const;
+    uint32_t HashValue(uint32_t aHash) const;
+
+    Type mType;
+    nscoord mLength;
+    float mPercent;
+    float mNumber;
+    bool mHasPercent;
+    nsTArray> mChildren;
+
+  private:
+    explicit CalcNode(Type aType);
+    ~CalcNode() {}
   };
 
   // Reference counted calc() value.  This is the type that is used to store
   // the calc() value in nsStyleCoord.
   struct Calc final : public CalcValue {
+#if defined(__MINGW32__)
+    MOZ_NEVER_INLINE MozExternalRefCountType AddRef(void)
+    {
+      MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Calc)
+      MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
+      nsrefcnt count = ++mRefCnt;
+      NS_LOG_ADDREF(this, count, "Calc", sizeof(*this));
+      return (nsrefcnt) count;
+    }
+
+    MOZ_NEVER_INLINE MozExternalRefCountType Release(void)
+    {
+      MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
+      nsrefcnt count = --mRefCnt;
+      NS_LOG_RELEASE(this, count, "Calc");
+      if (count == 0) {
+        delete (this);
+        return 0;
+      }
+      return count;
+    }
+    typedef mozilla::TrueType HasThreadSafeRefCnt;
+  protected:
+    ::mozilla::ThreadSafeAutoRefCnt mRefCnt;
+  public:
+#else
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Calc)
+#endif
     Calc() {}
 
+    bool HasCalcNode() const { return !!mNode; }
+    nscoord Resolve(nscoord aPercentageBasis) const;
+
+    RefPtr mNode;
+
   private:
     Calc(const Calc&) = delete;
     ~Calc() {}
diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp
index 11e7f18e22..a69bec00b5 100644
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -530,7 +530,7 @@ nsStyleSet::GatherRuleProcessors(SheetType aType)
         scope->SetIsScopedStyleRoot();
 
         // Create a rule processor for the scope.
-        nsTArray> sheetsForScope;
+        nsTArray> sheetsForScope(end - start);
         sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
         nsCSSRuleProcessor* oldRP = oldScopedRuleProcessorHash.Get(scope);
         mScopedDocSheetRuleProcessors.AppendElement
diff --git a/layout/style/test/ListCSSProperties.cpp b/layout/style/test/ListCSSProperties.cpp
index 5e0405bb55..a3262b2f80 100644
--- a/layout/style/test/ListCSSProperties.cpp
+++ b/layout/style/test/ListCSSProperties.cpp
@@ -105,7 +105,6 @@ const char *gInaccessibleProperties[] = {
     "-x-span",
     "-x-system-font",
     "-x-text-zoom",
-    "aspect-ratio",  // for now.
     "-moz-control-character-visibility",
     "-moz-script-level", // parsed by UA sheets only
     "-moz-script-size-multiplier",
diff --git a/layout/style/test/mochitest.ini b/layout/style/test/mochitest.ini
index 2f0ab87a28..6e4b68e82f 100644
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -70,9 +70,14 @@ support-files = file_animations_with_disabled_properties.html
 [test_any_dynamic.html]
 [test_at_rule_parse_serialize.html]
 [test_attribute_selector_eof_behavior.html]
+[test_aspect_ratio_property.html]
 [test_background_blend_mode.html]
+[test_basic_nesting_flattening.html]
+[test_nesting_flattening_parser_edges.html]
+[test_nesting_flattening_recovery.html]
 [test_box_size_keywords.html]
 [test_bug73586.html]
+[test_css_math_functions.html]
 [test_bug74880.html]
 [test_bug98997.html]
 [test_bug160403.html]
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
index f3b78f6c87..5a5f157882 100644
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1162,6 +1162,14 @@ var gCSSProperties = {
     other_values: ["url(foo.xml)"],
     invalid_values: [],
   },
+  "aspect-ratio": {
+    domProp: "aspectRatio",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: ["auto"],
+    other_values: ["1", "2"],
+    invalid_values: ["none", "-1", "1px", "1 / -1", "1 /", "auto auto"],
+  },
   "-moz-border-bottom-colors": {
     domProp: "MozBorderBottomColors",
     inherited: false,
diff --git a/layout/style/test/test_aspect_ratio_property.html b/layout/style/test/test_aspect_ratio_property.html
new file mode 100644
index 0000000000..b50788dcc1
--- /dev/null
+++ b/layout/style/test/test_aspect_ratio_property.html
@@ -0,0 +1,41 @@
+
+
+
+  Test CSS aspect-ratio property
+  
+  
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/layout/style/test/test_basic_nesting_flattening.html b/layout/style/test/test_basic_nesting_flattening.html new file mode 100644 index 0000000000..b24af42e76 --- /dev/null +++ b/layout/style/test/test_basic_nesting_flattening.html @@ -0,0 +1,146 @@ + + + + + Test for Basic CSS Nesting Flattening + + + + +
+ +
+
+

+
+
+
diff --git a/layout/style/test/test_css_math_functions.html b/layout/style/test/test_css_math_functions.html
new file mode 100644
index 0000000000..040251edf5
--- /dev/null
+++ b/layout/style/test/test_css_math_functions.html
@@ -0,0 +1,47 @@
+
+
+
+  Test CSS sizing math functions
+  
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/layout/style/test/test_media_queries.html b/layout/style/test/test_media_queries.html index a962215d34..90b55a2ac5 100644 --- a/layout/style/test/test_media_queries.html +++ b/layout/style/test/test_media_queries.html @@ -290,6 +290,12 @@ function run() { should_apply("all and (max-" + feature + ": " + value + "px)"); should_apply("all and (max-" + feature + ": " + (value + 1) + "px)"); should_not_apply("all and (max-" + feature + ": " + (value - 1) + "px)"); + should_apply("all and (" + feature + " >= " + value + "px)"); + should_not_apply("all and (" + feature + " > " + value + "px)"); + should_apply("all and (" + feature + " > " + (value - 1) + "px)"); + should_apply("all and (" + feature + " <= " + value + "px)"); + should_not_apply("all and (" + feature + " < " + value + "px)"); + should_apply("all and (" + feature + " < " + (value + 1) + "px)"); should_not_apply("all and (min-" + feature + ": " + (Math.ceil(value/em_size) + 1) + "em)"); should_apply("all and (min-" + feature + ": " + @@ -349,6 +355,9 @@ function run() { should_apply("(orientation: landscape)"); should_not_apply("(orientation: portrait)"); should_apply("not all and (orientation: portrait)"); + expression_should_not_be_parseable("orientation > landscape"); + expression_should_not_be_parseable("min-width > 1px"); + expression_should_not_be_parseable("width >"); // ratio that reduces to 59/80 change_state(function() { iframe_style.height = "320px"; diff --git a/layout/style/test/test_nesting_flattening_parser_edges.html b/layout/style/test/test_nesting_flattening_parser_edges.html new file mode 100644 index 0000000000..100ff1bf1d --- /dev/null +++ b/layout/style/test/test_nesting_flattening_parser_edges.html @@ -0,0 +1,161 @@ + + + + + Test CSS Nesting Flattening Parser Edges + + + + +
+ + + + + + +
+
+
+

+
+
+
diff --git a/layout/style/test/test_nesting_flattening_recovery.html b/layout/style/test/test_nesting_flattening_recovery.html
new file mode 100644
index 0000000000..63eed9091b
--- /dev/null
+++ b/layout/style/test/test_nesting_flattening_recovery.html
@@ -0,0 +1,149 @@
+
+
+
+  
+  Test CSS Nesting Flattening Recovery Paths
+  
+  
+
+
+
+
+
+
+

+
+
+
diff --git a/layout/svg/nsCSSFilterInstance.cpp b/layout/svg/nsCSSFilterInstance.cpp
index 79bf83b949..80388f77ce 100644
--- a/layout/svg/nsCSSFilterInstance.cpp
+++ b/layout/svg/nsCSSFilterInstance.cpp
@@ -409,7 +409,7 @@ nsCSSFilterInstance::SetBounds(FilterPrimitiveDescription& aDescr,
   nsIntRect inputBounds = (inputIndex < 0) ?
     mTargetBoundsInFilterSpace : aPrimitiveDescrs[inputIndex].PrimitiveSubregion();
 
-  nsTArray inputExtents;
+  AutoTArray inputExtents;
   inputExtents.AppendElement(inputBounds);
 
   nsIntRegion outputExtents =
diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp
index 0fb68ddd1b..8ca9ca13e8 100644
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -670,6 +670,7 @@ nsSVGEffects::EffectProperties::GetMaskFrames()
 
   bool ok = false;
   const nsTArray>& props = mMask->GetProps();
+  result.SetCapacity(props.Length());
   for (size_t i = 0; i < props.Length(); i++) {
     nsSVGMaskFrame* maskFrame =
       static_cast(props[i]->GetReferencedFrame(
@@ -731,6 +732,7 @@ nsSVGRenderingObserverList::InvalidateAll()
     return;
 
   AutoTArray observers;
+  observers.SetCapacity(mObservers.Count());
 
   for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
     observers.AppendElement(it.Get()->GetKey());
@@ -749,6 +751,7 @@ nsSVGRenderingObserverList::InvalidateAllForReflow()
     return;
 
   AutoTArray observers;
+  observers.SetCapacity(mObservers.Count());
 
   for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
     nsSVGRenderingObserver* obs = it.Get()->GetKey();
@@ -767,6 +770,7 @@ void
 nsSVGRenderingObserverList::RemoveAll()
 {
   AutoTArray observers;
+  observers.SetCapacity(mObservers.Count());
 
   for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
     observers.AppendElement(it.Get()->GetKey());
diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp
index efb0ed35df..4d99f80834 100644
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -938,6 +938,12 @@ BOOL WINAPI revert_mm_thread_characteristics_noop(HANDLE mmcss_handle)
 
 HRESULT register_notification_client(cubeb_stream * stm)
 {
+#if defined(__MINGW32__)
+  // MinGW builds have shown crashes in MMDevApi callback dispatch paths.
+  // Skip notification registration and rely on normal stream operation.
+  (void)stm;
+  return S_OK;
+#else
   HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                                 NULL, CLSCTX_INPROC_SERVER,
                                 IID_PPV_ARGS(&stm->device_enumerator));
@@ -958,10 +964,15 @@ HRESULT register_notification_client(cubeb_stream * stm)
   }
 
   return hr;
+#endif
 }
 
 HRESULT unregister_notification_client(cubeb_stream * stm)
 {
+#if defined(__MINGW32__)
+  (void)stm;
+  return S_OK;
+#else
   XASSERT(stm);
   HRESULT hr;
 
@@ -981,6 +992,7 @@ HRESULT unregister_notification_client(cubeb_stream * stm)
   SafeRelease(stm->device_enumerator);
 
   return S_OK;
+#endif
 }
 
 HRESULT get_endpoint(IMMDevice ** device, LPCWSTR devid)
diff --git a/media/libcubeb/src/moz.build b/media/libcubeb/src/moz.build
index b4515a3a9a..374a6df593 100644
--- a/media/libcubeb/src/moz.build
+++ b/media/libcubeb/src/moz.build
@@ -67,7 +67,7 @@ if CONFIG['OS_TARGET'] == 'WINNT':
         'cubeb_winmm.c',
     ]
     DEFINES['USE_WINMM'] = True
-    if CONFIG['MOZ_SAMPLE_TYPE_FLOAT32']:
+    if CONFIG['MOZ_SAMPLE_TYPE_FLOAT32'] and not CONFIG['GNU_CC']:
         DEFINES['USE_WASAPI'] = True
         SOURCES += [
             'cubeb_wasapi.cpp',
diff --git a/media/libdav1d/README_MCP b/media/libdav1d/README_MCP
new file mode 100644
index 0000000000..e238f8e94c
--- /dev/null
+++ b/media/libdav1d/README_MCP
@@ -0,0 +1,5 @@
+This directory contains dav1d 1.5.3 from VideoLAN:
+https://code.videolan.org/videolan/dav1d/-/tags/1.5.3
+
+Upstream source is stored in src/. Mozilla-specific build configuration lives
+in moz.build, config/, and moz/.
diff --git a/media/libdav1d/arm/moz.build b/media/libdav1d/arm/moz.build
new file mode 100644
index 0000000000..3b5864f811
--- /dev/null
+++ b/media/libdav1d/arm/moz.build
@@ -0,0 +1,79 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+SOURCES += [
+    '/media/libdav1d/src/src/arm/cpu.c',
+]
+
+if CONFIG['CPU_ARCH'] == 'aarch64':
+    SOURCES += [
+        '/media/libdav1d/src/src/arm/64/cdef.S',
+        '/media/libdav1d/src/src/arm/64/cdef16.S',
+        '/media/libdav1d/src/src/arm/64/filmgrain.S',
+        '/media/libdav1d/src/src/arm/64/filmgrain16.S',
+        '/media/libdav1d/src/src/arm/64/ipred.S',
+        '/media/libdav1d/src/src/arm/64/ipred16.S',
+        '/media/libdav1d/src/src/arm/64/itx.S',
+        '/media/libdav1d/src/src/arm/64/itx16.S',
+        '/media/libdav1d/src/src/arm/64/loopfilter.S',
+        '/media/libdav1d/src/src/arm/64/loopfilter16.S',
+        '/media/libdav1d/src/src/arm/64/looprestoration.S',
+        '/media/libdav1d/src/src/arm/64/looprestoration16.S',
+        '/media/libdav1d/src/src/arm/64/looprestoration_common.S',
+        '/media/libdav1d/src/src/arm/64/mc.S',
+        '/media/libdav1d/src/src/arm/64/mc16.S',
+        '/media/libdav1d/src/src/arm/64/mc16_sve.S',
+        '/media/libdav1d/src/src/arm/64/mc_dotprod.S',
+        '/media/libdav1d/src/src/arm/64/msac.S',
+        '/media/libdav1d/src/src/arm/64/refmvs.S',
+    ]
+else:
+    SOURCES += [
+        '/media/libdav1d/src/src/arm/32/cdef.S',
+        '/media/libdav1d/src/src/arm/32/cdef16.S',
+        '/media/libdav1d/src/src/arm/32/filmgrain.S',
+        '/media/libdav1d/src/src/arm/32/filmgrain16.S',
+        '/media/libdav1d/src/src/arm/32/ipred.S',
+        '/media/libdav1d/src/src/arm/32/ipred16.S',
+        '/media/libdav1d/src/src/arm/32/itx.S',
+        '/media/libdav1d/src/src/arm/32/itx16.S',
+        '/media/libdav1d/src/src/arm/32/loopfilter.S',
+        '/media/libdav1d/src/src/arm/32/loopfilter16.S',
+        '/media/libdav1d/src/src/arm/32/looprestoration.S',
+        '/media/libdav1d/src/src/arm/32/looprestoration16.S',
+        '/media/libdav1d/src/src/arm/32/looprestoration_common.S',
+        '/media/libdav1d/src/src/arm/32/mc.S',
+        '/media/libdav1d/src/src/arm/32/mc16.S',
+        '/media/libdav1d/src/src/arm/32/msac.S',
+        '/media/libdav1d/src/src/arm/32/refmvs.S',
+    ]
+
+ASFLAGS += [
+    '-I%s/media/libdav1d/config' % TOPSRCDIR,
+    '-I%s/media/libdav1d/src' % TOPSRCDIR,
+]
+
+if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['CLANG_CXX']:
+    ASFLAGS += [
+        '-no-integrated-as',
+    ]
+
+LOCAL_INCLUDES += [
+    '/media/libdav1d/config',
+    '/media/libdav1d/src',
+    '/media/libdav1d/src/include',
+    '/media/libdav1d/src/include/dav1d',
+]
+
+FINAL_LIBRARY = 'gkmedias'
+
+ALLOW_COMPILER_WARNINGS = True
+
+if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
+    CFLAGS += [
+        '-Wno-sign-compare',
+        '-Wno-unused-function',
+        '-Wno-unused-parameter',
+    ]
diff --git a/media/libdav1d/config/config.asm b/media/libdav1d/config/config.asm
new file mode 100644
index 0000000000..7eeb23b042
--- /dev/null
+++ b/media/libdav1d/config/config.asm
@@ -0,0 +1,65 @@
+; Mozilla build configuration for bundled dav1d x86 assembly.
+
+%define private_prefix dav1d
+
+%ifndef ARCH_X86_64
+    %ifidn __OUTPUT_FORMAT__,elf64
+        %define ARCH_X86_64 1
+    %elifidn __OUTPUT_FORMAT__,macho64
+        %define ARCH_X86_64 1
+    %elifidn __OUTPUT_FORMAT__,win64
+        %define ARCH_X86_64 1
+    %elifidn __OUTPUT_FORMAT__,x64
+        %define ARCH_X86_64 1
+    %else
+        %define ARCH_X86_64 0
+    %endif
+%endif
+
+%ifndef ARCH_X86_32
+    %if ARCH_X86_64
+        %define ARCH_X86_32 0
+    %else
+        %define ARCH_X86_32 1
+    %endif
+%endif
+
+%ifndef STACK_ALIGNMENT
+    %if ARCH_X86_64
+        %define STACK_ALIGNMENT 16
+    %elifidn __OUTPUT_FORMAT__,elf
+        %define STACK_ALIGNMENT 16
+    %elifidn __OUTPUT_FORMAT__,elf32
+        %define STACK_ALIGNMENT 16
+    %elifidn __OUTPUT_FORMAT__,macho
+        %define STACK_ALIGNMENT 16
+    %elifidn __OUTPUT_FORMAT__,macho32
+        %define STACK_ALIGNMENT 16
+    %else
+        %define STACK_ALIGNMENT 4
+    %endif
+%endif
+
+%ifndef PIC
+    %ifidn __OUTPUT_FORMAT__,win32
+        %define PIC 0
+    %else
+        %define PIC 1
+    %endif
+%endif
+
+%ifndef FORCE_VEX_ENCODING
+    %define FORCE_VEX_ENCODING 0
+%endif
+
+%ifidn __OUTPUT_FORMAT__,win32
+    %if ARCH_X86_32
+        %define PREFIX 1
+    %endif
+%elifidn __OUTPUT_FORMAT__,macho
+    %define PREFIX 1
+%elifidn __OUTPUT_FORMAT__,macho32
+    %define PREFIX 1
+%elifidn __OUTPUT_FORMAT__,macho64
+    %define PREFIX 1
+%endif
diff --git a/media/libdav1d/config/config.h b/media/libdav1d/config/config.h
new file mode 100644
index 0000000000..f4877a8aca
--- /dev/null
+++ b/media/libdav1d/config/config.h
@@ -0,0 +1,120 @@
+/* Mozilla build configuration for bundled dav1d. */
+#ifndef MOZ_DAV1D_CONFIG_H
+#define MOZ_DAV1D_CONFIG_H
+
+#if defined(__x86_64__) || defined(_M_X64)
+#  define ARCH_X86 1
+#  define ARCH_X86_64 1
+#  define ARCH_X86_32 0
+#elif defined(__i386__) || defined(_M_IX86)
+#  define ARCH_X86 1
+#  define ARCH_X86_64 0
+#  define ARCH_X86_32 1
+#else
+#  define ARCH_X86 0
+#  define ARCH_X86_64 0
+#  define ARCH_X86_32 0
+#endif
+
+#if defined(__aarch64__) || defined(_M_ARM64)
+#  define ARCH_AARCH64 1
+#else
+#  define ARCH_AARCH64 0
+#endif
+
+#if defined(__arm__) || defined(_M_ARM)
+#  define ARCH_ARM 1
+#else
+#  define ARCH_ARM 0
+#endif
+
+#if defined(__loongarch64)
+#  define ARCH_LOONGARCH 1
+#  define ARCH_LOONGARCH64 1
+#else
+#  define ARCH_LOONGARCH 0
+#  define ARCH_LOONGARCH64 0
+#endif
+
+#if defined(__powerpc64__) && \
+    (defined(_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN__) || \
+     (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+      __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+#  define ARCH_PPC64LE 1
+#else
+#  define ARCH_PPC64LE 0
+#endif
+
+#if defined(__riscv)
+#  define ARCH_RISCV 1
+#else
+#  define ARCH_RISCV 0
+#endif
+
+#if defined(IS_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
+#  define ENDIANNESS_BIG 1
+#else
+#  define ENDIANNESS_BIG 0
+#endif
+
+#define CONFIG_8BPC 1
+#define CONFIG_16BPC 1
+#define CONFIG_LOG 0
+#define CONFIG_MACOS_KPERF 0
+#if ARCH_AARCH64 || ARCH_ARM || ARCH_LOONGARCH64 || ARCH_PPC64LE || ARCH_X86
+#  define HAVE_ASM 1
+#else
+#  define HAVE_ASM 0
+#endif
+#define TRIM_DSP_FUNCTIONS 0
+
+#define HAVE_AS_FUNC 0
+#if ARCH_AARCH64
+#  define HAVE_AS_ARCH_DIRECTIVE 1
+#  define AS_ARCH_LEVEL armv8-a
+#  define HAVE_AS_ARCHEXT_DOTPROD_DIRECTIVE 1
+#  define HAVE_AS_ARCHEXT_I8MM_DIRECTIVE 1
+#  define HAVE_AS_ARCHEXT_SVE_DIRECTIVE 1
+#  define HAVE_AS_ARCHEXT_SVE2_DIRECTIVE 1
+#  define HAVE_DOTPROD 1
+#  define HAVE_I8MM 1
+#  define HAVE_SVE 1
+#  define HAVE_SVE2 1
+#else
+#  define HAVE_AS_ARCH_DIRECTIVE 0
+#  define HAVE_AS_ARCHEXT_DOTPROD_DIRECTIVE 0
+#  define HAVE_AS_ARCHEXT_I8MM_DIRECTIVE 0
+#  define HAVE_AS_ARCHEXT_SVE_DIRECTIVE 0
+#  define HAVE_AS_ARCHEXT_SVE2_DIRECTIVE 0
+#  define HAVE_DOTPROD 0
+#  define HAVE_I8MM 0
+#  define HAVE_SVE 0
+#  define HAVE_SVE2 0
+#endif
+
+#define HAVE_ALIGNED_ALLOC 0
+#define HAVE_DLSYM 0
+#define HAVE_ELF_AUX_INFO 0
+#if defined(__linux__)
+#  define HAVE_GETAUXVAL 1
+#else
+#  define HAVE_GETAUXVAL 0
+#endif
+#define HAVE_MEMALIGN 0
+#define HAVE_POSIX_MEMALIGN 0
+#define HAVE_PTHREAD_GETAFFINITY_NP 0
+#define HAVE_PTHREAD_NP_H 0
+#define HAVE_PTHREAD_SETNAME_NP 0
+#define HAVE_PTHREAD_SET_NAME_NP 0
+
+#ifdef _WIN32
+#  define HAVE_IO_H 1
+#  define HAVE_SYS_TYPES_H 1
+#  define HAVE_UNISTD_H 0
+#else
+#  define HAVE_IO_H 0
+#  define HAVE_SYS_TYPES_H 1
+#  define HAVE_UNISTD_H 1
+#endif
+
+#endif /* MOZ_DAV1D_CONFIG_H */
diff --git a/media/libdav1d/config/vcs_version.h b/media/libdav1d/config/vcs_version.h
new file mode 100644
index 0000000000..b7f73ec6e2
--- /dev/null
+++ b/media/libdav1d/config/vcs_version.h
@@ -0,0 +1 @@
+#define DAV1D_VERSION "1.5.3"
diff --git a/media/libdav1d/moz.build b/media/libdav1d/moz.build
new file mode 100644
index 0000000000..12a33fb4fa
--- /dev/null
+++ b/media/libdav1d/moz.build
@@ -0,0 +1,141 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+with Files('*'):
+    BUG_COMPONENT = ('Core', 'Audio/Video')
+
+common_sources = [
+    '/media/libdav1d/src/src/cdf.c',
+    '/media/libdav1d/src/src/cpu.c',
+    '/media/libdav1d/src/src/ctx.c',
+    '/media/libdav1d/src/src/data.c',
+    '/media/libdav1d/src/src/decode.c',
+    '/media/libdav1d/src/src/dequant_tables.c',
+    '/media/libdav1d/src/src/getbits.c',
+    '/media/libdav1d/src/src/intra_edge.c',
+    '/media/libdav1d/src/src/itx_1d.c',
+    '/media/libdav1d/src/src/lf_mask.c',
+    '/media/libdav1d/src/src/lib.c',
+    '/media/libdav1d/src/src/log.c',
+    '/media/libdav1d/src/src/mem.c',
+    '/media/libdav1d/src/src/msac.c',
+    '/media/libdav1d/src/src/obu.c',
+    '/media/libdav1d/src/src/pal.c',
+    '/media/libdav1d/src/src/picture.c',
+    '/media/libdav1d/src/src/qm.c',
+    '/media/libdav1d/src/src/ref.c',
+    '/media/libdav1d/src/src/refmvs.c',
+    '/media/libdav1d/src/src/scan.c',
+    '/media/libdav1d/src/src/tables.c',
+    '/media/libdav1d/src/src/thread_task.c',
+    '/media/libdav1d/src/src/warpmv.c',
+    '/media/libdav1d/src/src/wedge.c',
+]
+
+bitdepth_sources = [
+    '/media/libdav1d/moz/cdef_16bpc.c',
+    '/media/libdav1d/moz/cdef_8bpc.c',
+    '/media/libdav1d/moz/cdef_apply_16bpc.c',
+    '/media/libdav1d/moz/cdef_apply_8bpc.c',
+    '/media/libdav1d/moz/fg_apply_16bpc.c',
+    '/media/libdav1d/moz/fg_apply_8bpc.c',
+    '/media/libdav1d/moz/filmgrain_16bpc.c',
+    '/media/libdav1d/moz/filmgrain_8bpc.c',
+    '/media/libdav1d/moz/ipred_16bpc.c',
+    '/media/libdav1d/moz/ipred_8bpc.c',
+    '/media/libdav1d/moz/ipred_prepare_16bpc.c',
+    '/media/libdav1d/moz/ipred_prepare_8bpc.c',
+    '/media/libdav1d/moz/itx_16bpc.c',
+    '/media/libdav1d/moz/itx_8bpc.c',
+    '/media/libdav1d/moz/lf_apply_16bpc.c',
+    '/media/libdav1d/moz/lf_apply_8bpc.c',
+    '/media/libdav1d/moz/loopfilter_16bpc.c',
+    '/media/libdav1d/moz/loopfilter_8bpc.c',
+    '/media/libdav1d/moz/looprestoration_16bpc.c',
+    '/media/libdav1d/moz/looprestoration_8bpc.c',
+    '/media/libdav1d/moz/lr_apply_16bpc.c',
+    '/media/libdav1d/moz/lr_apply_8bpc.c',
+    '/media/libdav1d/moz/mc_16bpc.c',
+    '/media/libdav1d/moz/mc_8bpc.c',
+    '/media/libdav1d/moz/recon_16bpc.c',
+    '/media/libdav1d/moz/recon_8bpc.c',
+]
+
+SOURCES += common_sources
+SOURCES += bitdepth_sources
+
+if CONFIG['CPU_ARCH'].startswith('x86'):
+    DIRS += ['x86']
+elif CONFIG['CPU_ARCH'] in ('arm', 'aarch64'):
+    DIRS += ['arm']
+elif CONFIG['CPU_ARCH'] == 'ppc64' and CONFIG['TARGET_ENDIANNESS'] == 'little':
+    DIRS += ['ppc']
+
+if CONFIG['OS_TARGET'] == 'WINNT':
+    SOURCES += [
+        '/media/libdav1d/src/src/win32/thread.c',
+    ]
+else:
+    DEFINES['_GNU_SOURCE'] = True
+
+if CONFIG['CPU_ARCH'] == 'loongarch64':
+    SOURCES += [
+        '/media/libdav1d/moz/loongarch_cdef.S',
+        '/media/libdav1d/moz/loongarch_cpu.c',
+        '/media/libdav1d/moz/loongarch_ipred.S',
+        '/media/libdav1d/moz/loongarch_itx.S',
+        '/media/libdav1d/moz/loongarch_loopfilter.S',
+        '/media/libdav1d/moz/loongarch_looprestoration.S',
+        '/media/libdav1d/moz/loongarch_looprestoration_inner_16bpc.c',
+        '/media/libdav1d/moz/loongarch_looprestoration_inner_8bpc.c',
+        '/media/libdav1d/moz/loongarch_mc.S',
+        '/media/libdav1d/moz/loongarch_msac.S',
+        '/media/libdav1d/moz/loongarch_refmvs.S',
+    ]
+    ASFLAGS += [
+        '-I%s/dist/include' % OBJDIR,
+        '-I%s/media/libdav1d/src' % TOPSRCDIR,
+    ]
+
+EXPORTS.dav1d += [
+    '/media/libdav1d/src/include/dav1d/common.h',
+    '/media/libdav1d/src/include/dav1d/data.h',
+    '/media/libdav1d/src/include/dav1d/dav1d.h',
+    '/media/libdav1d/src/include/dav1d/headers.h',
+    '/media/libdav1d/src/include/dav1d/picture.h',
+    '/media/libdav1d/src/include/dav1d/version.h',
+]
+
+LOCAL_INCLUDES += [
+    '/media/libdav1d/config',
+    '/media/libdav1d/src',
+    '/media/libdav1d/src/include',
+    '/media/libdav1d/src/include/dav1d',
+]
+
+# Make dav1d's MSVC compatibility headers available to MSVC builds so
+# including  picks up the local compat header instead of
+# the system header which requires C11.
+if CONFIG['_MSC_VER'] and not CONFIG['CLANG_CL']:
+    LOCAL_INCLUDES += ['/media/libdav1d/src/include/compat/msvc']
+
+FINAL_LIBRARY = 'gkmedias'
+
+# We allow warnings for third-party code that can be updated from upstream.
+ALLOW_COMPILER_WARNINGS = True
+
+if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
+    CFLAGS += [
+        '-Wno-missing-field-initializers',
+        '-Wno-sign-compare',
+        '-Wno-unused-function',
+        '-Wno-unused-parameter',
+    ]
+
+if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']:
+    CFLAGS += [
+        '-Wno-shorten-64-to-32',
+        '-Wno-unreachable-code',
+    ]
diff --git a/media/libdav1d/moz/cdef_16bpc.c b/media/libdav1d/moz/cdef_16bpc.c
new file mode 100644
index 0000000000..09c80f0f79
--- /dev/null
+++ b/media/libdav1d/moz/cdef_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/cdef_tmpl.c"
diff --git a/media/libdav1d/moz/cdef_8bpc.c b/media/libdav1d/moz/cdef_8bpc.c
new file mode 100644
index 0000000000..306dcb72c1
--- /dev/null
+++ b/media/libdav1d/moz/cdef_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/cdef_tmpl.c"
diff --git a/media/libdav1d/moz/cdef_apply_16bpc.c b/media/libdav1d/moz/cdef_apply_16bpc.c
new file mode 100644
index 0000000000..fb17510c0a
--- /dev/null
+++ b/media/libdav1d/moz/cdef_apply_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/cdef_apply_tmpl.c"
diff --git a/media/libdav1d/moz/cdef_apply_8bpc.c b/media/libdav1d/moz/cdef_apply_8bpc.c
new file mode 100644
index 0000000000..fbdf63381d
--- /dev/null
+++ b/media/libdav1d/moz/cdef_apply_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/cdef_apply_tmpl.c"
diff --git a/media/libdav1d/moz/fg_apply_16bpc.c b/media/libdav1d/moz/fg_apply_16bpc.c
new file mode 100644
index 0000000000..77fb8c0c99
--- /dev/null
+++ b/media/libdav1d/moz/fg_apply_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/fg_apply_tmpl.c"
diff --git a/media/libdav1d/moz/fg_apply_8bpc.c b/media/libdav1d/moz/fg_apply_8bpc.c
new file mode 100644
index 0000000000..11c9a36faa
--- /dev/null
+++ b/media/libdav1d/moz/fg_apply_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/fg_apply_tmpl.c"
diff --git a/media/libdav1d/moz/filmgrain_16bpc.c b/media/libdav1d/moz/filmgrain_16bpc.c
new file mode 100644
index 0000000000..4f4f737ead
--- /dev/null
+++ b/media/libdav1d/moz/filmgrain_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/filmgrain_tmpl.c"
diff --git a/media/libdav1d/moz/filmgrain_8bpc.c b/media/libdav1d/moz/filmgrain_8bpc.c
new file mode 100644
index 0000000000..c357f059c1
--- /dev/null
+++ b/media/libdav1d/moz/filmgrain_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/filmgrain_tmpl.c"
diff --git a/media/libdav1d/moz/ipred_16bpc.c b/media/libdav1d/moz/ipred_16bpc.c
new file mode 100644
index 0000000000..cf1361cd43
--- /dev/null
+++ b/media/libdav1d/moz/ipred_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/ipred_tmpl.c"
diff --git a/media/libdav1d/moz/ipred_8bpc.c b/media/libdav1d/moz/ipred_8bpc.c
new file mode 100644
index 0000000000..0389449f98
--- /dev/null
+++ b/media/libdav1d/moz/ipred_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/ipred_tmpl.c"
diff --git a/media/libdav1d/moz/ipred_prepare_16bpc.c b/media/libdav1d/moz/ipred_prepare_16bpc.c
new file mode 100644
index 0000000000..83427e85f4
--- /dev/null
+++ b/media/libdav1d/moz/ipred_prepare_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/ipred_prepare_tmpl.c"
diff --git a/media/libdav1d/moz/ipred_prepare_8bpc.c b/media/libdav1d/moz/ipred_prepare_8bpc.c
new file mode 100644
index 0000000000..4d323e1ec3
--- /dev/null
+++ b/media/libdav1d/moz/ipred_prepare_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/ipred_prepare_tmpl.c"
diff --git a/media/libdav1d/moz/itx_16bpc.c b/media/libdav1d/moz/itx_16bpc.c
new file mode 100644
index 0000000000..0f01421f50
--- /dev/null
+++ b/media/libdav1d/moz/itx_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/itx_tmpl.c"
diff --git a/media/libdav1d/moz/itx_8bpc.c b/media/libdav1d/moz/itx_8bpc.c
new file mode 100644
index 0000000000..d4f7319e38
--- /dev/null
+++ b/media/libdav1d/moz/itx_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/itx_tmpl.c"
diff --git a/media/libdav1d/moz/lf_apply_16bpc.c b/media/libdav1d/moz/lf_apply_16bpc.c
new file mode 100644
index 0000000000..c27c06cd69
--- /dev/null
+++ b/media/libdav1d/moz/lf_apply_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/lf_apply_tmpl.c"
diff --git a/media/libdav1d/moz/lf_apply_8bpc.c b/media/libdav1d/moz/lf_apply_8bpc.c
new file mode 100644
index 0000000000..343c7f24ab
--- /dev/null
+++ b/media/libdav1d/moz/lf_apply_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/lf_apply_tmpl.c"
diff --git a/media/libdav1d/moz/loongarch_cdef.S b/media/libdav1d/moz/loongarch_cdef.S
new file mode 100644
index 0000000000..1fa24d6eac
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_cdef.S
@@ -0,0 +1 @@
+#include "../src/src/loongarch/cdef.S"
diff --git a/media/libdav1d/moz/loongarch_cpu.c b/media/libdav1d/moz/loongarch_cpu.c
new file mode 100644
index 0000000000..c1d77b126e
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_cpu.c
@@ -0,0 +1 @@
+#include "../src/src/loongarch/cpu.c"
diff --git a/media/libdav1d/moz/loongarch_ipred.S b/media/libdav1d/moz/loongarch_ipred.S
new file mode 100644
index 0000000000..097365bc21
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_ipred.S
@@ -0,0 +1 @@
+#include "../src/src/loongarch/ipred.S"
diff --git a/media/libdav1d/moz/loongarch_itx.S b/media/libdav1d/moz/loongarch_itx.S
new file mode 100644
index 0000000000..51a92208e0
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_itx.S
@@ -0,0 +1 @@
+#include "../src/src/loongarch/itx.S"
diff --git a/media/libdav1d/moz/loongarch_loopfilter.S b/media/libdav1d/moz/loongarch_loopfilter.S
new file mode 100644
index 0000000000..2ecc7358d7
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_loopfilter.S
@@ -0,0 +1 @@
+#include "../src/src/loongarch/loopfilter.S"
diff --git a/media/libdav1d/moz/loongarch_looprestoration.S b/media/libdav1d/moz/loongarch_looprestoration.S
new file mode 100644
index 0000000000..72be443f3a
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_looprestoration.S
@@ -0,0 +1 @@
+#include "../src/src/loongarch/looprestoration.S"
diff --git a/media/libdav1d/moz/loongarch_looprestoration_inner_16bpc.c b/media/libdav1d/moz/loongarch_looprestoration_inner_16bpc.c
new file mode 100644
index 0000000000..d8f9d46052
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_looprestoration_inner_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/loongarch/looprestoration_inner.c"
diff --git a/media/libdav1d/moz/loongarch_looprestoration_inner_8bpc.c b/media/libdav1d/moz/loongarch_looprestoration_inner_8bpc.c
new file mode 100644
index 0000000000..bf034465c3
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_looprestoration_inner_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/loongarch/looprestoration_inner.c"
diff --git a/media/libdav1d/moz/loongarch_mc.S b/media/libdav1d/moz/loongarch_mc.S
new file mode 100644
index 0000000000..7b0a767235
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_mc.S
@@ -0,0 +1 @@
+#include "../src/src/loongarch/mc.S"
diff --git a/media/libdav1d/moz/loongarch_msac.S b/media/libdav1d/moz/loongarch_msac.S
new file mode 100644
index 0000000000..2c380b4106
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_msac.S
@@ -0,0 +1 @@
+#include "../src/src/loongarch/msac.S"
diff --git a/media/libdav1d/moz/loongarch_refmvs.S b/media/libdav1d/moz/loongarch_refmvs.S
new file mode 100644
index 0000000000..f76fc383e3
--- /dev/null
+++ b/media/libdav1d/moz/loongarch_refmvs.S
@@ -0,0 +1 @@
+#include "../src/src/loongarch/refmvs.S"
diff --git a/media/libdav1d/moz/loopfilter_16bpc.c b/media/libdav1d/moz/loopfilter_16bpc.c
new file mode 100644
index 0000000000..9f5be59c26
--- /dev/null
+++ b/media/libdav1d/moz/loopfilter_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/loopfilter_tmpl.c"
diff --git a/media/libdav1d/moz/loopfilter_8bpc.c b/media/libdav1d/moz/loopfilter_8bpc.c
new file mode 100644
index 0000000000..1068f96c3d
--- /dev/null
+++ b/media/libdav1d/moz/loopfilter_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/loopfilter_tmpl.c"
diff --git a/media/libdav1d/moz/looprestoration_16bpc.c b/media/libdav1d/moz/looprestoration_16bpc.c
new file mode 100644
index 0000000000..daacd2dfeb
--- /dev/null
+++ b/media/libdav1d/moz/looprestoration_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/looprestoration_tmpl.c"
diff --git a/media/libdav1d/moz/looprestoration_8bpc.c b/media/libdav1d/moz/looprestoration_8bpc.c
new file mode 100644
index 0000000000..9624fdc337
--- /dev/null
+++ b/media/libdav1d/moz/looprestoration_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/looprestoration_tmpl.c"
diff --git a/media/libdav1d/moz/lr_apply_16bpc.c b/media/libdav1d/moz/lr_apply_16bpc.c
new file mode 100644
index 0000000000..ff8f961838
--- /dev/null
+++ b/media/libdav1d/moz/lr_apply_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/lr_apply_tmpl.c"
diff --git a/media/libdav1d/moz/lr_apply_8bpc.c b/media/libdav1d/moz/lr_apply_8bpc.c
new file mode 100644
index 0000000000..55195db9b1
--- /dev/null
+++ b/media/libdav1d/moz/lr_apply_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/lr_apply_tmpl.c"
diff --git a/media/libdav1d/moz/mc_16bpc.c b/media/libdav1d/moz/mc_16bpc.c
new file mode 100644
index 0000000000..d8a7efc6a8
--- /dev/null
+++ b/media/libdav1d/moz/mc_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/mc_tmpl.c"
diff --git a/media/libdav1d/moz/mc_8bpc.c b/media/libdav1d/moz/mc_8bpc.c
new file mode 100644
index 0000000000..459a075c73
--- /dev/null
+++ b/media/libdav1d/moz/mc_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/mc_tmpl.c"
diff --git a/media/libdav1d/moz/recon_16bpc.c b/media/libdav1d/moz/recon_16bpc.c
new file mode 100644
index 0000000000..2954537055
--- /dev/null
+++ b/media/libdav1d/moz/recon_16bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 16
+#include "../src/src/recon_tmpl.c"
diff --git a/media/libdav1d/moz/recon_8bpc.c b/media/libdav1d/moz/recon_8bpc.c
new file mode 100644
index 0000000000..04b17f4642
--- /dev/null
+++ b/media/libdav1d/moz/recon_8bpc.c
@@ -0,0 +1,2 @@
+#define BITDEPTH 8
+#include "../src/src/recon_tmpl.c"
diff --git a/media/libdav1d/ppc/moz.build b/media/libdav1d/ppc/moz.build
new file mode 100644
index 0000000000..b907bf4274
--- /dev/null
+++ b/media/libdav1d/ppc/moz.build
@@ -0,0 +1,55 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+vsx_sources = [
+    'ppc_cdef_vsx_16bpc.c',
+    'ppc_cdef_vsx_8bpc.c',
+    'ppc_looprestoration_vsx_16bpc.c',
+    'ppc_looprestoration_vsx_8bpc.c',
+]
+
+pwr9_sources = [
+    'ppc_itx_pwr9_16bpc.c',
+    'ppc_itx_pwr9_8bpc.c',
+    'ppc_loopfilter_pwr9_16bpc.c',
+    'ppc_loopfilter_pwr9_8bpc.c',
+    'ppc_mc_pwr9_16bpc.c',
+    'ppc_mc_pwr9_8bpc.c',
+]
+
+SOURCES += [
+    '/media/libdav1d/src/src/ppc/cpu.c',
+]
+SOURCES += pwr9_sources
+SOURCES += vsx_sources
+
+for f in pwr9_sources:
+    SOURCES[f].flags += [
+        '-mcpu=power9',
+    ]
+
+for f in vsx_sources:
+    SOURCES[f].flags += [
+        '-maltivec',
+        '-mvsx',
+    ]
+
+LOCAL_INCLUDES += [
+    '/media/libdav1d/config',
+    '/media/libdav1d/src',
+    '/media/libdav1d/src/include',
+    '/media/libdav1d/src/include/dav1d',
+]
+
+FINAL_LIBRARY = 'gkmedias'
+
+ALLOW_COMPILER_WARNINGS = True
+
+if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
+    CFLAGS += [
+        '-Wno-sign-compare',
+        '-Wno-unused-function',
+        '-Wno-unused-parameter',
+    ]
diff --git a/media/libdav1d/ppc/ppc_cdef_vsx_16bpc.c b/media/libdav1d/ppc/ppc_cdef_vsx_16bpc.c
new file mode 100644
index 0000000000..dff3c281e4
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_cdef_vsx_16bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 16
+#define DAV1D_VSX 1
+#include "../src/src/ppc/cdef_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_cdef_vsx_8bpc.c b/media/libdav1d/ppc/ppc_cdef_vsx_8bpc.c
new file mode 100644
index 0000000000..226cedbd30
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_cdef_vsx_8bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 8
+#define DAV1D_VSX 1
+#include "../src/src/ppc/cdef_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_itx_pwr9_16bpc.c b/media/libdav1d/ppc/ppc_itx_pwr9_16bpc.c
new file mode 100644
index 0000000000..dd604a9877
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_itx_pwr9_16bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 16
+#define DAV1D_PWR9 1
+#include "../src/src/ppc/itx_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_itx_pwr9_8bpc.c b/media/libdav1d/ppc/ppc_itx_pwr9_8bpc.c
new file mode 100644
index 0000000000..2de3d00dc6
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_itx_pwr9_8bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 8
+#define DAV1D_PWR9 1
+#include "../src/src/ppc/itx_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_loopfilter_pwr9_16bpc.c b/media/libdav1d/ppc/ppc_loopfilter_pwr9_16bpc.c
new file mode 100644
index 0000000000..1cb479c783
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_loopfilter_pwr9_16bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 16
+#define DAV1D_PWR9 1
+#include "../src/src/ppc/loopfilter_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_loopfilter_pwr9_8bpc.c b/media/libdav1d/ppc/ppc_loopfilter_pwr9_8bpc.c
new file mode 100644
index 0000000000..fe51f8ca3f
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_loopfilter_pwr9_8bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 8
+#define DAV1D_PWR9 1
+#include "../src/src/ppc/loopfilter_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_looprestoration_vsx_16bpc.c b/media/libdav1d/ppc/ppc_looprestoration_vsx_16bpc.c
new file mode 100644
index 0000000000..43c9cd4814
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_looprestoration_vsx_16bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 16
+#define DAV1D_VSX 1
+#include "../src/src/ppc/looprestoration_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_looprestoration_vsx_8bpc.c b/media/libdav1d/ppc/ppc_looprestoration_vsx_8bpc.c
new file mode 100644
index 0000000000..3d50ae1ff6
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_looprestoration_vsx_8bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 8
+#define DAV1D_VSX 1
+#include "../src/src/ppc/looprestoration_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_mc_pwr9_16bpc.c b/media/libdav1d/ppc/ppc_mc_pwr9_16bpc.c
new file mode 100644
index 0000000000..5c50bc06f1
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_mc_pwr9_16bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 16
+#define DAV1D_PWR9 1
+#include "../src/src/ppc/mc_tmpl.c"
diff --git a/media/libdav1d/ppc/ppc_mc_pwr9_8bpc.c b/media/libdav1d/ppc/ppc_mc_pwr9_8bpc.c
new file mode 100644
index 0000000000..9e142bf2fe
--- /dev/null
+++ b/media/libdav1d/ppc/ppc_mc_pwr9_8bpc.c
@@ -0,0 +1,3 @@
+#define BITDEPTH 8
+#define DAV1D_PWR9 1
+#include "../src/src/ppc/mc_tmpl.c"
diff --git a/media/libdav1d/src/.gitignore b/media/libdav1d/src/.gitignore
new file mode 100644
index 0000000000..2abeaa50ea
--- /dev/null
+++ b/media/libdav1d/src/.gitignore
@@ -0,0 +1,10 @@
+/build*
+/Session.vim
+[._]*.swp
+*~
+tags
+.DS_Store
+/tests/argon
+/tests/dav1d-test-data
+*.snap
+/tools/output/xxhash.h
diff --git a/media/libdav1d/src/.gitlab-ci.yml b/media/libdav1d/src/.gitlab-ci.yml
new file mode 100644
index 0000000000..c52ae364a2
--- /dev/null
+++ b/media/libdav1d/src/.gitlab-ci.yml
@@ -0,0 +1,930 @@
+stages:
+    - style
+    - build
+    - test
+
+.debian-amd64-common:
+    image: registry.videolan.org/dav1d-debian-unstable:20250207200301
+    stage: build
+    tags:
+        - docker
+        - amd64
+
+.debian-amd64-minimum:
+    image: registry.videolan.org/dav1d-debian-minimum:20250207200301
+    stage: build
+    tags:
+        - docker
+        - amd64
+
+.debian-llvm-mingw-common:
+    image: registry.videolan.org/vlc-debian-llvm-msvcrt:20250305204125
+    stage: build
+    tags:
+        - docker
+        - amd64
+
+.debian-aarch64-common:
+    image: registry.videolan.org/dav1d-debian-bookworm-aarch64:20250215002814
+    stage: build
+    tags:
+        - docker
+        - aarch64
+
+.debian-armv7-common:
+    image: registry.videolan.org/dav1d-debian-bookworm-armv7:20250215014239
+    stage: build
+    tags:
+        - docker
+        - armv7
+
+.debian-ppc64le-common:
+    image: registry.videolan.org/dav1d-debian-unstable-ppc64le:20250215003029
+    stage: build
+    tags:
+        - docker
+        - ppc64le
+
+.android-common:
+    image: registry.videolan.org/vlc-debian-android:20241118101328
+    stage: build
+    tags:
+        - docker
+        - amd64
+
+.debian-wasm-emscripten-common:
+    image: registry.videolan.org/vlc-debian-wasm-emscripten:20250207201514
+    stage: build
+    tags:
+        - docker
+        - amd64
+
+
+style-check:
+    extends: .debian-amd64-common
+    stage: style
+    script:
+        - git grep -I -n -P "\t|\r| $" -- . ':(exclude)*/compat/*' && echo "Trailing whitespace" && exit 1
+        - git grep -I -n -i -e 'david' --and --not -e 'copyright' -- . ':(exclude)THANKS.md' ':(exclude).gitlab-ci.yml' && echo "Misspelled dav1d" && exit 1
+        - git grep -I -l -z "" -- . ':(exclude)*/compat/*' | while IFS= read -r -d '' i; do
+              if [ -n "$(tail -c 1 "$i")" ]; then
+                  echo "No newline at end of $i";
+                  exit 1;
+              fi;
+          done
+        - rg '[\u061c\u2000-\u200f\u2028-\u202f\u205f-\u206f]' ./ && echo "Invisible Unicode characters" && exit 1
+        - git remote rm upstream 2> /dev/null || true
+        - git remote add upstream https://code.videolan.org/videolan/dav1d.git
+        - git fetch -q upstream master
+        - for i in $(git rev-list HEAD ^upstream/master); do
+              echo "Checking commit message of $i";
+              msg="$(git log --format=%B -n 1 $i)";
+              if [ -n "$(echo "$msg" | awk "NR==2")" ]; then
+                  echo "Malformed commit message in $i, second line must be empty";
+                  exit 1;
+              fi;
+              if echo "$msg" | head -1 | grep -q '\.$'; then
+                  echo "Malformed commit message in $i, trailing period in subject line";
+                  exit 1;
+              fi;
+          done
+
+x86inc-check:
+    extends: .debian-amd64-common
+    stage: style
+    script:
+        - git remote rm x86inc 2> /dev/null || true
+        - git remote add x86inc https://code.videolan.org/videolan/x86inc.asm.git
+        - git fetch -q x86inc master
+        - git diff --exit-code x86inc/master:x86inc.asm src/ext/x86/x86inc.asm
+    allow_failure: true
+
+
+build-debian:
+    extends: .debian-amd64-common
+    tags:
+        - docker
+        - avx2
+        - amd64
+    script:
+        - meson setup build --buildtype release
+                            -Dtrim_dsp=false
+                            --werror
+        - ninja -C build
+        - cd build && meson test -v
+    artifacts:
+        paths:
+            - build/
+        expire_in: 1 day
+
+build-debian-static:
+    extends: .debian-amd64-common
+    script:
+        - meson setup build --buildtype release
+                            --default-library static
+                            --werror
+        - ninja -C build
+        - cd build && meson test -v
+        - nm -A -g src/libdav1d.a | grep " [ABCDGRST] " | (! grep -v " _*dav1d_")
+
+build-debian-illegal-instructions:
+    extends: .debian-amd64-common
+    tags:
+        - docker
+        - avx2
+        - amd64
+    script:
+        - meson setup build --buildtype debug
+        - ninja -C build
+        - cd build
+        - exit_code=0
+        - time meson test -v --suite checkasm --wrapper 'qemu-x86_64 -cpu Conroe' || exit_code=$((exit_code + $?))
+        - time meson test -v --suite checkasm --wrapper 'qemu-x86_64 -cpu Penryn' || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+build-debian32:
+    extends: .debian-amd64-common
+    script:
+        - meson setup build --buildtype release
+                            -Dtrim_dsp=false
+                            --werror
+                            --cross-file package/crossfiles/i686-linux32.meson
+        - ninja -C build
+        - cd build && meson test -v
+    artifacts:
+        paths:
+            - build/
+        expire_in: 1 day
+
+build-debian-examples:
+    extends: .debian-amd64-common
+    script:
+        - meson setup build --buildtype release
+                            --werror
+                            -Denable_examples=true
+        - ninja -C build
+
+build-debian-no-tools:
+    extends: .debian-amd64-common
+    script:
+        - meson setup build --buildtype release
+                            --werror
+                            -Denable_tools=false
+        - ninja -C build
+
+build-debian-bitdepth:
+    extends: .debian-amd64-common
+    script:
+        - meson setup build --buildtype release
+                            --werror
+                            -Dbitdepths=$DEPTH
+        - ninja -C build
+    parallel:
+      matrix:
+        - DEPTH: [8, 16]
+
+build-debian-avx:
+    extends: .debian-amd64-common
+    tags:
+        - docker
+        - avx2
+        - amd64
+    variables:
+        CFLAGS: '-mavx'
+    script:
+        - meson setup build --buildtype debugoptimized
+                            --werror
+        - ninja -C build
+        - cd build
+        - time meson test -v --suite checkasm
+
+build-debian-minimum:
+    extends: .debian-amd64-minimum
+    script:
+        - meson setup build --buildtype release
+                            --werror
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && meson test -v
+
+build-debian-avx512:
+    extends: .debian-amd64-common
+    tags:
+        - docker
+        - amd64-avx512
+    variables:
+        CFLAGS: '-mavx'
+    script:
+        - meson setup build --buildtype debugoptimized
+                            --werror
+        - ninja -C build
+        - cd build
+        - time meson test -v --suite checkasm
+
+build-debian-clang:
+    extends: .debian-amd64-common
+    variables:
+        CC: clang
+        CC_LD: mold
+    script:
+        - meson setup build --buildtype release
+                            --werror
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && meson test -v
+
+build-win:
+    extends: .debian-amd64-common
+    script:
+        - wineserver -p && wine wineboot
+        - meson setup build --buildtype release
+                            --werror
+                            --libdir lib
+                            --prefix "$(pwd)/build/dav1d_install"
+                            --cross-file package/crossfiles/${CROSSFILE}.meson
+                            -Ddefault_library=both
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - ninja -C build install
+        - cd build && meson test -v
+        - ${CROSSFILE}-nm -A -g src/libdav1d.a | grep " [ABCDGRST] " | (! grep -E -v " \.| _*dav1d_")
+    artifacts:
+        name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
+        paths:
+            - build/dav1d_install/
+        expire_in: 1 week
+    parallel:
+      matrix:
+        - CROSSFILE: [i686-w64-mingw32, x86_64-w64-mingw32]
+
+build-win32-unaligned-stack:
+    extends: .debian-llvm-mingw-common
+    script:
+        - wineserver -p && wine wineboot
+        - meson setup build --buildtype release
+                            --werror
+                            --cross-file package/crossfiles/i686-w64-mingw32.meson
+                            -Dstack_alignment=4
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && meson test -v
+
+build-win-arm:
+    extends: .debian-llvm-mingw-common
+    script:
+        - meson setup build --buildtype release
+                            --werror
+                            --libdir lib
+                            --prefix "$(pwd)/build/dav1d_install"
+                            --cross-file package/crossfiles/${CROSSFILE}.meson
+                            -Ddefault_library=both
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - ninja -C build install
+        - ${CROSSFILE}-nm -A -g build/src/libdav1d.a | grep " [ABCDGRST] " | (! grep -E -v " \.| _*dav1d_")
+    artifacts:
+        name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
+        paths:
+            - build/dav1d_install/
+        expire_in: 1 week
+    parallel:
+      matrix:
+        - CROSSFILE: [armv7-w64-mingw32, aarch64-w64-mingw32]
+
+.build-android-common:
+    extends: .android-common
+    script:
+        - meson setup build --buildtype release
+                            --werror
+                            --libdir lib
+                            --prefix "$(pwd)/build/dav1d_install"
+                            --cross-file $CROSSFILE
+                            -Ddefault_library=both
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - ninja -C build install
+
+build-android-armv7:
+    extends: .build-android-common
+    variables:
+        CROSSFILE: package/crossfiles/arm-android.meson
+    rules:
+        - if: '$CI_COMMIT_BRANCH'
+
+build-android-aarch64:
+    extends: .build-android-common
+    variables:
+        CROSSFILE: package/crossfiles/aarch64-android.meson
+    rules:
+        - if: '$CI_COMMIT_BRANCH'
+
+build-android-armv7-release:
+    extends: build-android-armv7
+    rules:
+        - if: '$CI_COMMIT_TAG && $CI_PROJECT_PATH == "videolan/dav1d"'
+    artifacts:
+        name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
+        paths:
+            - build/dav1d_install/
+        expire_in: 1 week
+
+build-android-aarch64-release:
+    extends: build-android-aarch64
+    rules:
+        - if: '$CI_COMMIT_TAG && $CI_PROJECT_PATH == "videolan/dav1d"'
+    artifacts:
+        name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
+        paths:
+            - build/dav1d_install/
+        expire_in: 1 week
+
+build-debian-aarch64:
+    extends: .debian-aarch64-common
+    script:
+        - meson setup build --buildtype debugoptimized
+                            --werror
+        - ninja -C build
+        - cd build && meson test -v
+
+build-debian-aarch64-clang-5:
+    extends: .debian-aarch64-common
+    variables:
+        CC: clang-5.0
+        CFLAGS: '-integrated-as'
+    script:
+        - meson setup build --buildtype release
+        - ninja -C build
+        - cd build && meson test -v
+
+build-debian-aarch64-clang-18:
+    extends: .debian-amd64-common
+    variables:
+        QEMU_LD_PREFIX: /usr/aarch64-linux-gnu/
+    script:
+        - meson setup build --buildtype release
+                            -Dtrim_dsp=false
+                            --werror
+                            --cross-file package/crossfiles/aarch64-linux-clang.meson
+        - ninja -C build
+        - cd build && meson test -v
+
+build-macos:
+    stage: build
+    tags:
+        - amd64
+        - macos
+    script:
+        - meson setup build --buildtype release
+                            -Ddefault_library=both
+                            -Dtrim_dsp=false
+                            --werror
+        - ninja -C build
+        - cd build && meson test -v
+
+build-debian-werror:
+    extends: .debian-aarch64-common
+    variables:
+        CC: clang
+    script:
+        - meson setup build --buildtype debug
+                            --werror
+        - ninja -C build
+
+build-debian-armv7:
+    extends: .debian-armv7-common
+    script:
+        - linux32 meson setup build --buildtype debugoptimized
+                                    --werror
+        - ninja -C build
+        - cd build && meson test -v
+
+build-debian-armv7-clang-5:
+    extends: .debian-armv7-common
+    variables:
+        CC: clang-5.0
+        CFLAGS: '-integrated-as'
+    script:
+        - linux32 meson setup build --buildtype release
+        - ninja -C build
+        - cd build && meson test -v
+
+build-debian-ppc64le:
+    extends: .debian-ppc64le-common
+    variables:
+        CC: gcc-13
+    script:
+        - meson setup build --buildtype release
+                            -Dtrim_dsp=false
+                            --werror
+        - ninja -C build
+        - cd build && meson test -v
+
+build-debian-wasm:
+    extends: .debian-wasm-emscripten-common
+    script:
+        - source $EMSCRIPTEN_SDK/emsdk_env.sh
+        - meson setup build --buildtype release
+                            --werror
+                            --default-library static
+                            --cross-file package/crossfiles/${CROSSFILE}.meson
+        - ninja -C build
+        - cd build && meson test -v
+    parallel:
+      matrix:
+        - CROSSFILE: [wasm32, wasm64]
+
+build-debian-riscv64:
+    extends: .debian-amd64-common
+    variables:
+        QEMU_CPU: rv64,v=true,vext_spec=v1.0,vlen=256,elen=64
+        QEMU_LD_PREFIX: /usr/riscv64-linux-gnu/
+    script:
+        - meson setup build --buildtype release
+                            -Dtrim_dsp=false
+                            --werror
+                            --cross-file package/crossfiles/${CROSSFILE}.meson
+        - ninja -C build
+        - cd build && meson test -v
+    parallel:
+      matrix:
+        - CROSSFILE: [riscv64-linux, riscv64-linux-clang]
+
+build-debian-loongarch64:
+    extends: .debian-amd64-common
+    variables:
+        QEMU_CPU: max-loongarch-cpu
+        QEMU_LD_PREFIX: /opt/cross-tools/target/
+    script:
+        - meson setup build --buildtype release
+                            -Dtrim_dsp=false
+                            --werror
+                            --cross-file package/crossfiles/loongarch64-linux.meson
+        - ninja -C build
+        - cd build && meson test -v
+
+
+.test-common:
+    stage: test
+    cache:
+        key: testdata.git-20190215
+        paths:
+            - cache/dav1d-test-data.git/
+    before_script:
+        - test -d cache || mkdir cache
+        - test -d cache/dav1d-test-data.git && GIT_DIR=cache/dav1d-test-data.git git fetch --refmap=refs/heads/master:refs/heads/master origin master
+        - test -d cache/dav1d-test-data.git || git clone --bare https://code.videolan.org/videolan/dav1d-test-data.git cache/dav1d-test-data.git
+        - git clone cache/dav1d-test-data.git tests/dav1d-test-data
+        - git -C tests/dav1d-test-data describe --always --long
+    dependencies: []
+    artifacts:
+        when: always
+        reports:
+          junit: build/meson-logs/testlog.junit.xml
+
+.test-asm-common:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    tags:
+        - docker
+        - amd64
+        - avx2
+    script:
+        - meson configure build -Dtestdata_tests=true
+        - ninja -C build
+        - cd build
+        - exit_code=0
+        - time meson test -q --suite testdata --test-args "--cpumask 0"     || exit_code=$((exit_code + $?))
+        - time meson test -q --suite testdata --test-args "--cpumask sse2"  || exit_code=$((exit_code + $?))
+        - time meson test -q --suite testdata --test-args "--cpumask ssse3" || exit_code=$((exit_code + $?))
+        - time meson test -q --suite testdata --test-args "--cpumask sse41" || exit_code=$((exit_code + $?))
+        - time meson test -q --suite testdata --test-args "--cpumask avx2"  || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+.test-argon:
+    stage: test
+    cache:
+        key: argon-20230512
+        paths:
+            - cache/argon/
+    variables:
+        ARGON_URL: https://streams.videolan.org/argon/argon.tar.zst
+    before_script:
+        - test -d cache/argon || mkdir -p cache/argon
+        - test -f cache/argon/argon.tar.zst ||
+          (cd cache/argon && curl --remote-name "${ARGON_URL}" --remote-name "${ARGON_URL}.sha512sum" &&
+          sha512sum --check argon.tar.zst.sha512sum )
+        - tar -xf cache/argon/argon.tar.zst -C tests
+    dependencies: []
+    allow_failure: true
+    rules:
+        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+
+test-debian:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian"]
+    script:
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Denable_seek_stress=true
+                            -Dlogging=false
+                            -Db_coverage=true
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && time meson test -v
+        - ninja coverage-html
+        - mv meson-logs/coveragereport ../coverage
+        - ninja coverage-xml
+        - grep -Eo 'line-rate="[^"]+"' meson-logs/coverage.xml | head -n 1 |
+          grep -Eo '[0-9.]+' | awk '{ print "coverage:", $1 * 100 } '
+        - time meson test -v --suite testdata_seek-stress --test-args "--threads 2 --framedelay 1"
+        - time meson test -v --suite testdata_seek-stress --test-args "--threads 2 --framedelay 2"
+        - time meson test -v --suite testdata --test-args "--threads=1 --negstride"
+    coverage: '/^coverage: (\d+.\d+)$/'
+    artifacts:
+        expose_as: 'Coverage HTML report'
+        paths:
+            - coverage/
+        reports:
+            coverage_report:
+                coverage_format: cobertura
+                path: build/meson-logs/coverage.xml
+
+test-debian-asm:
+    extends:
+        - .test-asm-common
+    needs: ["build-debian"]
+    dependencies: ["build-debian"]
+
+test-debian32-asm:
+    extends:
+        - .test-asm-common
+    needs: ["build-debian32"]
+    dependencies: ["build-debian32"]
+
+test-debian-avx512:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    tags:
+        - docker
+        - amd64-avx512
+    variables:
+        CFLAGS: '-mavx'
+    needs: ["build-debian-avx512"]
+    script:
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && time meson test --suite testdata --test-args "--cpumask avx512icl"
+        - time meson test --suite testdata --test-args "--threads 2 --framedelay 2 --cpumask avx512icl"
+
+test-debian-unaligned-stack:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian"]
+    tags:
+        - docker
+        - avx2
+        - amd64
+    script:
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Denable_seek_stress=true
+                            -Dlogging=false
+                            -Dstack_alignment=16
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && time meson test -v
+
+test-debian-asan:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian"]
+    variables:
+        ASAN_OPTIONS: 'detect_leaks=0'
+    script:
+        - meson setup build --buildtype debugoptimized
+                            -Dtestdata_tests=true
+                            -Dlogging=false
+                            -Db_sanitize=address
+        - ninja -C build
+        - cd build
+        - exit_code=0
+        - time meson test -v --setup=sanitizer --suite checkasm || exit_code=$((exit_code + $?))
+        - time meson test -v --setup=sanitizer --suite testdata --test-args "--cpumask 0"    || exit_code=$((exit_code + $?))
+        - time meson test -v --setup=sanitizer --suite testdata --test-args "--cpumask 0xff" || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+test-debian-msan:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian"]
+    variables:
+        MSAN_OPTIONS: 'exitcode=1'
+        CC: clang
+    script:
+        - meson setup build --buildtype debugoptimized
+                            -Dtestdata_tests=true
+                            -Denable_seek_stress=true
+                            -Dlogging=false
+                            -Db_sanitize=memory
+                            -Db_lundef=false
+                            -Denable_asm=false
+        - ninja -C build
+        - cd build
+        - exit_code=0
+        - time meson test -v --setup=sanitizer || exit_code=$((exit_code + $?))
+        - time meson test -v --setup=sanitizer --suite testdata --test-args "--frametimes /dev/null" || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+test-debian-ubsan:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian"]
+    variables:
+        UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1'
+        CC: clang
+    script:
+        - meson setup build --buildtype debugoptimized
+                            -Dtestdata_tests=true
+                            -Denable_seek_stress=true
+                            -Dlogging=false
+                            -Db_sanitize=undefined
+                            -Db_lundef=false
+                            -Denable_asm=false
+        - ninja -C build
+        - cd build && time meson test -v --setup=sanitizer
+
+test-debian-tsan:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian"]
+    variables:
+        TSAN_OPTIONS: 'halt_on_error=1'
+        CC: clang
+    script:
+        - meson setup build --buildtype debugoptimized
+                            -Dtestdata_tests=true
+                            -Denable_seek_stress=true
+                            -Dlogging=false
+                            -Db_sanitize=thread
+                            -Db_lundef=false
+        - ninja -C build
+        - cd build
+        - exit_code=0
+        - time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 1"             || exit_code=$((exit_code + $?))
+        - time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 2"             || exit_code=$((exit_code + $?))
+        - time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 2 --negstride" || exit_code=$((exit_code + $?))
+        - time meson test -v --setup=sanitizer --suite testdata_seek-stress --test-args "--threads 2 --framedelay 1"                                           || exit_code=$((exit_code + $?))
+        - time meson test -v --setup=sanitizer --suite testdata_seek-stress --test-args "--threads 2 --framedelay 2"                                           || exit_code=$((exit_code + $?))
+        - time meson test -v --setup=sanitizer --suite oss-fuzz-asan --suite oss-fuzz-msan --suite oss-fuzz-ubsan                                              || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+test-win64:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-win: [x86_64-w64-mingw32]"]
+    tags:
+        - docker
+        - avx2
+        - amd64
+    script:
+        - wineserver -p && wine wineboot
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Dlogging=false
+                            -Dtrim_dsp=false
+                            --cross-file package/crossfiles/x86_64-w64-mingw32.meson
+        - ninja -C build
+        - cd build && time meson test -v
+
+test-debian-aarch64:
+    extends:
+        - .debian-aarch64-common
+        - .test-common
+    needs: ["build-debian-aarch64"]
+    script:
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Dlogging=false
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && time meson test -v
+
+test-debian-ppc64le:
+    extends:
+        - .debian-ppc64le-common
+        - .test-common
+    variables:
+        CC: gcc-13
+    needs: ["build-debian-ppc64le"]
+    script:
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Dlogging=false
+                            -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && time meson test -v
+
+test-debian-riscv64:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian-riscv64"]
+    script:
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Dlogging=false
+                            -Dtrim_dsp=false
+                            --cross-file package/crossfiles/riscv64-linux.meson
+        - ninja -C build
+        - cd build && time meson test -v --timeout-multiplier 10
+    variables:
+        QEMU_LD_PREFIX: /usr/riscv64-linux-gnu/
+    parallel:
+      matrix:
+        - QEMU_CPU: [ "rv64,v=true,vext_spec=v1.0,vlen=128,elen=64",
+                      "rv64,v=true,vext_spec=v1.0,vlen=256,elen=64",
+                      "rv64,v=true,vext_spec=v1.0,vlen=512,elen=64",
+                      "rv64,v=true,vext_spec=v1.0,vlen=1024,elen=64" ]
+
+test-debian-aarch64-qemu:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian-aarch64"]
+    script:
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Dlogging=false
+                            -Dtrim_dsp=false
+                            --cross-file package/crossfiles/aarch64-linux.meson
+        - ninja -C build
+        - cd build && time meson test -v --timeout-multiplier 10
+    variables:
+        QEMU_LD_PREFIX: /usr/aarch64-linux-gnu/
+    parallel:
+      matrix:
+        # sve-default-vector-length sets the max vector length in bytes;
+        # the default is 64, allowing up to 512 bit vectors. Testing 1024
+        # and 2048 bit vectors requires raising this limit. The sve
+        # option sets the active vector length in bits.
+        - QEMU_CPU: [ "max,sve-default-vector-length=256,sve128=on",
+                      "max,sve-default-vector-length=256,sve256=on",
+                      "max,sve-default-vector-length=256,sve512=on",
+                      "max,sve-default-vector-length=256,sve1024=on",
+                      "max,sve-default-vector-length=256,sve2048=on" ]
+
+test-debian-armv7-clang-5:
+    extends:
+        - .debian-armv7-common
+        - .test-common
+    needs: ["build-debian-armv7-clang-5"]
+    variables:
+        CC: clang-5.0
+        CFLAGS: '-integrated-as'
+    script:
+        - linux32 meson setup build --buildtype release
+                                    -Dtestdata_tests=true
+                                    -Dlogging=false
+                                    -Dtrim_dsp=false
+        - ninja -C build
+        - cd build && time meson test -v
+
+test-debian-loongarch64:
+    extends:
+        - .debian-amd64-common
+        - .test-common
+    needs: ["build-debian-loongarch64"]
+    variables:
+        QEMU_CPU: max-loongarch-cpu
+        QEMU_LD_PREFIX: /opt/cross-tools/target/
+    script:
+        - meson setup build --buildtype release
+                            -Dtestdata_tests=true
+                            -Dlogging=false
+                            -Dtrim_dsp=false
+                            --cross-file package/crossfiles/loongarch64-linux.meson
+        - ninja -C build
+        - cd build && time meson test -v --timeout-multiplier 10
+
+.test-argon-script: &test-argon-script
+        - meson setup build --buildtype release
+                            -Dlogging=false
+                            -Dtrim_dsp=false
+        - cd build && ninja
+        - exit_code=0
+
+test-debian-argon:
+    extends:
+        - .debian-amd64-common
+        - .test-argon
+    needs: ["build-debian"]
+    tags:
+        - docker
+        - amd64
+        - avx2
+    script:
+        - *test-argon-script
+        - ../tests/dav1d_argon.bash -t 1 -c 0         || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 2 -c sse2 -g 0 || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 3 -c ssse3     || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 4 -c sse41     || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 5 -c avx2      || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+test-debian32-argon:
+    extends:
+        - .debian-amd64-common
+        - .test-argon
+    needs: ["build-debian32"]
+    script:
+        - meson setup build --buildtype release
+                            -Dlogging=false
+                            -Dtrim_dsp=false
+                            --cross-file package/crossfiles/i686-linux32.meson
+        - cd build && ninja
+        - exit_code=0
+        - ../tests/dav1d_argon.bash -t 2 -c sse2       || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 2 -c ssse3      || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 2 -c sse41 -g 0 || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+test-debian-argon-avx512:
+    extends:
+        - .debian-amd64-common
+        - .test-argon
+    needs: ["build-debian-avx512"]
+    tags:
+        - docker
+        - amd64-avx512
+    script:
+        - *test-argon-script
+        - ../tests/dav1d_argon.bash -t 2 -c avx512icl || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+test-debian-armv7-argon:
+    extends:
+        - .debian-armv7-common
+        - .test-argon
+    needs: ["build-debian-armv7"]
+    script:
+        - *test-argon-script
+        - ../tests/dav1d_argon.bash -t 3 -c 0         || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 2 -c neon      || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 1 -c neon -g 0 || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+test-debian-aarch64-argon:
+    extends:
+        - .debian-aarch64-common
+        - .test-argon
+    needs: ["build-debian-aarch64"]
+    tags:
+        - docker
+        - aarch64
+        - dotprod
+    script:
+        - *test-argon-script
+        - ../tests/dav1d_argon.bash -t 2 -c 0         || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 3 -c neon      || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 1 -c neon -g 0 || exit_code=$((exit_code + $?))
+        - ../tests/dav1d_argon.bash -t 4 -c dotprod   || exit_code=$((exit_code + $?))
+        - if [ $exit_code -ne 0 ]; then exit $exit_code; fi
+
+
+.pages-common:
+    extends: .debian-amd64-common
+    script:
+        - meson setup build --buildtype release
+                            --werror
+                            -Denable_docs=true
+        - ninja -C build doc/html
+        - mv build/doc/html public
+    artifacts:
+        paths:
+            - public
+
+build-pages:
+    extends: .pages-common
+    rules:
+        - if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH'
+
+pages:
+    extends: .pages-common
+    rules:
+        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+          changes:
+              - include/dav1d/*
+              - doc/meson.build
+              - doc/Doxyfile.in.in
diff --git a/media/libdav1d/src/CONTRIBUTING.md b/media/libdav1d/src/CONTRIBUTING.md
new file mode 100644
index 0000000000..cdbc98be53
--- /dev/null
+++ b/media/libdav1d/src/CONTRIBUTING.md
@@ -0,0 +1,56 @@
+# dav1d contribution guide
+
+## CoC
+The [VideoLAN Code of Conduct](https://wiki.videolan.org/CoC) applies fully to this project.
+
+## ToDo
+
+The todo list can be found [on the wiki](https://code.videolan.org/videolan/dav1d/wikis/task-list).
+
+## Codebase language
+
+The codebase is developed with the following assumptions:
+
+For the library:
+- C language with C99 version, without the VLA or the Complex (*\_\_STDC_NO_COMPLEX__*) features, and without compiler extensions. Anonymous structures and unions are the only allowed compiler extensions for internal code.
+- x86 asm in .asm files, using the NASM syntax,
+- arm/arm64 in .S files, using the GAS syntax limited to subset llvm 5.0's internal assembler supports,
+- no C++ is allowed, whatever the version.
+
+For the tools and utils:
+- C *(see above for restrictions)*
+- Rust
+- C++ is only allowed for the MFT.
+
+If you want to use *Threads* or *Atomic* features, please conform to the **C11**/**POSIX** semantic and use a wrapper for older compilers/platforms *(like done in VLC)*.
+
+Please use modern standard POSIX functions *(strscpy, asprintf, tdestroy)*, and provide a compatibility fallback *(like done in VLC)*.
+
+We will make reasonable efforts for compilers that are a bit older, but we won't support gcc 3 or MSVC 2012.
+
+## Authorship
+
+Please provide a correct authorship for your commit logs, with a name and a valid email.
+
+We will reject anonymous contributions for now. As an exception, known pseudonyms from the multimedia community are accepted.
+
+This project is respecting **Copyright** and **Droit d'auteur**. There is no copyright attribution or CLA.
+
+## Commit logs
+
+Please read [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/).
+
+## Submit requests (WIP)
+
+- Code,
+- [Compile](https://xkcd.com/303/),
+- Check your [code style](https://code.videolan.org/videolan/dav1d/wikis/Coding-style),
+- Test,
+- Try,
+- Submit patches through merge requests,
+- Check that this passes the CI.
+
+## Patent license
+
+You need to read, understand, and agree to the [AV1 patents license](doc/PATENTS), before committing.
+
diff --git a/media/libdav1d/src/COPYING b/media/libdav1d/src/COPYING
new file mode 100644
index 0000000000..8d4d6418c1
--- /dev/null
+++ b/media/libdav1d/src/COPYING
@@ -0,0 +1,23 @@
+Copyright © 2018-2025, VideoLAN and dav1d authors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/media/libdav1d/src/NEWS b/media/libdav1d/src/NEWS
new file mode 100644
index 0000000000..6d1160b866
--- /dev/null
+++ b/media/libdav1d/src/NEWS
@@ -0,0 +1,460 @@
+Changes for 1.5.3 'Sonic':
+--------------------------
+
+1.5.3 is a minor release of dav1d, focused on RISC-V and maintenance:
+ - Misc small optimizations
+ - RISC-V assembly optimizations for ipred, emu_edge and w_mask,
+   and VLEN 512 for blend functions
+ - Fix issue with ivf files with 0 frames in tools
+
+
+Changes for 1.5.2 'Sonic':
+--------------------------
+
+1.5.2 is a minor release of dav1d, focused on maintenance:
+ - minor speed improvement in recon
+ - improvements on loongarch symboles visibility and asm
+ - mark C globals with small code model
+ - reduce the code size of the frame header parsing (OBU)
+ - minor fixes on tools and CI
+ - fix compilation with nasm 3.00
+
+
+Changes for 1.5.1 'Sonic':
+--------------------------
+
+1.5.1 is a minor release of dav1d, focusing on optimizations and stack reduction:
+
+ - Rewrite of the looprestoration (SGR, wiener) to reduce stack usage
+ - Rewrite of {put,prep}_scaled functions
+
+Now, the required stack space for dav1d should be: 62 KB on x86_64 and
+58KB on arm and aarch64.
+
+ - Improvements on the SSSE3 SGR
+ - Improvements on ARM32/ARM64 looprestoration optimizations
+ - RISC-V: blend optimizations for high bitdepth
+ - Power9: blend optimizations for 8bpc
+ - Port RISC-V to POSIX/non-Linux OS
+ - AArch64: Add Neon implementation of load_tmvs
+ - Fix a rare, but possible deadlock, in flush()
+
+
+Changes for 1.5.0 'Sonic':
+--------------------------
+
+1.5.0 is a major release of dav1d, that:
+ - WARNING: we removed some of the SSE2 optimizations, so if you care about
+            systems without SSSE3, you should be careful when updating!
+ - Add Arm OpenBSD run-time CPU feature
+ - Optimize index offset calculations for decode_coefs
+ - picture: copy HDR10+ and T35 metadata only to visible frames
+ - SSSE3 new optimizations for 6-tap (8bit and hbd)
+ - AArch64/SVE: Add HBD subpel filters using 128-bit SVE2
+ - AArch64: Add USMMLA Implementation for 6-tap H/HV
+ - AArch64: Optimize Armv8.0 NEON for HBD horizontal filters and 6-tap filters
+ - Power9: Optimized ITX till 16x4.
+ - Loongarch: numerous optimizations
+ - RISC-V optimizations for pal, cdef_filter, ipred, mc_blend, mc_bdir, itx
+ - Allow playing videos in full-screen mode in dav1dplay
+
+
+Changes for 1.4.3 'Road Runner':
+--------------------------------
+
+1.4.3 is a small release focused on security issues
+ - AArch64: Fix potential out of bounds access in DotProd H/HV filters
+ - cli: Prevent buffer over-read
+
+
+Changes for 1.4.2 'Road Runner':
+--------------------------------
+
+1.4.2 is a small release of dav1d, improving notably ARM, AVX-512 and PowerPC
+ - AVX2 optimizations for 8-tap and new variants for 6-tap
+ - AVX-512 optimizations for 8-tap and new variants for 6-tap
+ - Improve entropy decoding on ARM64
+ - New ARM64 optimizations for convolutions based on DotProd extension
+ - New ARM64 optimizations for convolutions based on i8mm extension
+ - New ARM64 optimizations for subpel and prep filters for i8mm
+ - Misc improvements on existing ARM64 optimizations, notably for put/prep
+ - New PowerPC9 optimizations for loopfilter
+ - Support for macOS kperf API for benchmarking
+
+
+Changes for 1.4.1 'Road Runner':
+--------------------------------
+
+1.4.1 is a small release of dav1d, improving notably ARM and RISC-V speed
+
+- Optimizations for 6tap filters for NEON (ARM)
+- More RISC-V optimizations for itx (4x8, 8x4, 4x16, 16x4, 8x16, 16x8)
+- Reduction of binary size on ARM64, ARM32 and RISC-V
+- Fix out-of-bounds read in 8bpc SSE2/SSSE3 wiener_filter
+- Msac optimizations
+
+
+Changes for 1.4.0 'Road Runner':
+--------------------------------
+
+1.4.0 is a medium release of dav1d, focusing on new architecture support and optimizations
+
+- AVX-512 optimizations for z1, z2, z3 in 8bit and high-bitdepth
+- New architecture supported: loongarch
+- Loongarch optimizations for 8bit
+- New architecture supported: RISC-V
+- RISC-V optimizations for itx
+- Misc improvements in threading and in reducing binary size
+- Fix potential integer overflow with extremely large frame sizes (CVE-2024-1580)
+
+
+Changes for 1.3.0 'Tundra Peregrine Falcon (Calidus)':
+------------------------------------------------------
+
+1.3.0 is a medium release of dav1d, focus on new APIs and memory usage reduction.
+
+- Reduce memory usage in numerous places
+- ABI break in Dav1dSequenceHeader, Dav1dFrameHeader, Dav1dContentLightLevel structures
+- new API function to check the API version: dav1d_version_api()
+- Rewrite of the SGR functions for ARM64 to be faster
+- NEON implemetation of save_tmvs for ARM32 and ARM64
+- x86 palette DSP for pal_idx_finish function
+
+
+Changes for 1.2.1 'Arctic Peregrine Falcon':
+--------------------------------------------
+
+1.2.1 is a small release of dav1d, adding more SIMD and fixes
+
+- Fix a threading race on task_thread.init_done
+- NEON z2 8bpc and high bit-depth optimizations
+- SSSE3 z2 high bit-depth optimziations
+- Fix a desynced luma/chroma planes issue with Film Grain
+- Reduce memory consumption
+- Improve dav1d_parse_sequence_header() speed
+- OBU: Improve header parsing and fix potential overflows
+- OBU: Improve ITU-T T.35 parsing speed
+- Misc buildsystems, CI and headers fixes
+
+
+Changes for 1.2.0 'Arctic Peregrine Falcon':
+--------------------------------------------
+
+1.2.0 is a small release of dav1d, adding more SIMD and fixes
+
+- Improvements on attachments of props and T.35 entries on output pictures
+- NEON z1/z3 high bit-depth optimizations and improvements for 8bpc
+- SSSE3 z2/z3 8bpc and SSSE3 z1/z3 high bit-depth optimziations
+- refmvs.save_tmvs optimizations in SSSE3/AVX2/AVX-512
+- AVX-512 optimizations for high bit-depth itx (16x64, 32x64, 64x16, 64x32, 64x64)
+- AVX2 optimizations for 12bpc for 16x32, 32x16, 32x32 itx
+
+
+Changes for 1.1.0 'Arctic Peregrine Falcon':
+--------------------------------------------
+
+1.1.0 is an important release of dav1d, fixing numerous bugs, and adding SIMD
+
+- New function dav1d_get_frame_delay to query the decoder frame delay
+- Numerous fixes for strict conformity to the specs and samples
+- NEON and AVX-512 misc fixes and improvements
+- Partial AVX2 12bpc transform implementations
+- AVX-512 high bit-depth cdef_filter, loopfilter, itx
+- NEON z1/z3 optimization for 8bpc
+- SSSE3 z1 optimization for 8bpc
+
+ "From VideoLAN with love"
+
+
+Changes for 1.0.0 'Peregrine Falcon':
+-------------------------------------
+
+1.0.0 is a major release of dav1d, adding important features and bug fixes.
+
+It notably changes, in an important way, the way threading works, by adding
+an automatic thread management.
+
+It also adds support for AVX-512 acceleration, and adds speedups to existing x86
+code (from SSE2 to AVX2).
+
+1.0.0 adds new grain API to ease acceleration on the GPU, and adds an API call
+to get information of which frame failed to decode, in error cases.
+
+Finally, 1.0.0 fixes numerous small bugs that were reported since the beginning
+of the project to have a proper release.
+
+                                     .''.
+         .''.      .        *''*    :_\/_:     .
+        :_\/_:   _\(/_  .:.*_\/_*   : /\ :  .'.:.'.
+    .''.: /\ :   ./)\   ':'* /\ * :  '..'.  -=:o:=-
+   :_\/_:'.:::.    ' *''*    * '.\'/.' _\(/_'.':'.'
+   : /\ : :::::     *_\/_*     -= o =-  /)\    '  *
+    '..'  ':::'     * /\ *     .'/.\'.   '
+        *            *..*         :
+          *                       :
+          *         1.0.0
+
+
+
+Changes for 0.9.2 'Golden Eagle':
+---------------------------------
+
+0.9.2 is a small update of dav1d on the 0.9.x branch:
+ - x86: SSE4 optimizations of inverse transforms for 10bit for all sizes
+ - x86: mc.resize optimizations with AVX2/SSSE3 for 10/12b
+ - x86: SSSE3 optimizations for cdef_filter in 10/12b and mc_w_mask_422/444 in 8b
+ - ARM NEON optimizations for FilmGrain Gen_grain functions
+ - Optimizations for splat_mv in SSE2/AVX2 and NEON
+ - x86: SGR improvements for SSSE3 CPUs
+ - x86: AVX2 optimizations for cfl_ac
+
+
+Changes for 0.9.1 'Golden Eagle':
+---------------------------------
+
+0.9.1 is a middle-size revision of dav1d, adding notably 10b acceleration for SSSE3:
+ - 10/12b SSSE3 optimizations for mc (avg, w_avg, mask, w_mask, emu_edge),
+   prep/put_bilin, prep/put_8tap, ipred (dc/h/v, paeth, smooth, pal, filter), wiener,
+   sgr (10b), warp8x8, deblock, film_grain, cfl_ac/pred for 32bit and 64bit x86 processors
+ - Film grain NEON for fguv 10/12b, fgy/fguv 8b and fgy/fguv 10/12 arm32
+ - Fixes for filmgrain on ARM
+ - itx 10bit optimizations for 4x4/x8/x16, 8x4/x8/x16 for SSE4
+ - Misc improvements on SSE2, SSE4
+
+
+Changes for 0.9.0 'Golden Eagle':
+---------------------------------
+
+0.9.0 is a major version of dav1d, adding notably 10b acceleration on x64.
+
+Details:
+ - x86 (64bit) AVX2 implementation of most 10b/12b functions, which should provide
+   a large boost for high-bitdepth decoding on modern x86 computers and servers.
+ - ARM64 neon implementation of FilmGrain (4:2:0/4:2:2/4:4:4 8bit)
+ - New API to signal events happening during the decoding process
+
+
+Changes for 0.8.2 'Eurasian Hobby':
+-----------------------------------
+
+0.8.2 is a middle-size update of the 0.8.0 branch:
+ - ARM32 optimizations for ipred and itx in 10/12bits,
+   completing the 10b/12b work on ARM64 and ARM32
+ - Give the post-filters their own threads
+ - ARM64: rewrite the wiener functions
+ - Speed up coefficient decoding, 0.5%-3% global decoding gain
+ - x86 optimizations for CDEF_filter and wiener in 10/12bit
+ - x86: rewrite the SGR AVX2 asm
+ - x86: improve msac speed on SSE2+ machines
+ - ARM32: improve speed of ipred and warp
+ - ARM64: improve speed of ipred, cdef_dir, cdef_filter, warp_motion and itx16
+ - ARM32/64: improve speed of looprestoration
+ - Add seeking, pausing to the player
+ - Update the player for rendering of 10b/12b
+ - Misc speed improvements and fixes on all platforms
+ - Add a xxh3 muxer in the dav1d application
+
+
+Changes for 0.8.1 'Eurasian Hobby':
+-----------------------------------
+
+0.8.1 is a minor update on 0.8.0:
+ - Keep references to buffers valid after dav1d_close(). Fixes a regression
+   caused by the picture buffer pool added in 0.8.0.
+ - ARM32 optimizations for 10bit bitdepth for SGR
+ - ARM32 optimizations for 16bit bitdepth for blend/w_masl/emu_edge
+ - ARM64 optimizations for 10bit bitdepth for SGR
+ - x86 optimizations for wiener in SSE2/SSSE3/AVX2
+
+
+Changes for 0.8.0 'Eurasian Hobby':
+-----------------------------------
+
+0.8.0 is a major update for dav1d:
+ - Improve the performance by using a picture buffer pool;
+   The improvements can reach 10% on some cases on Windows.
+ - Support for Apple ARM Silicon
+ - ARM32 optimizations for 8bit bitdepth for ipred paeth, smooth, cfl
+ - ARM32 optimizations for 10/12/16bit bitdepth for mc_avg/mask/w_avg,
+   put/prep 8tap/bilin, wiener and CDEF filters
+ - ARM64 optimizations for cfl_ac 444 for all bitdepths
+ - x86 optimizations for MC 8-tap, mc_scaled in AVX2
+ - x86 optimizations for CDEF in SSE and {put/prep}_{8tap/bilin} in SSSE3
+
+
+Changes for 0.7.1 'Frigatebird':
+------------------------------
+
+0.7.1 is a minor update on 0.7.0:
+ - ARM32 NEON optimizations for itxfm, which can give up to 28% speedup, and MSAC
+ - SSE2 optimizations for prep_bilin and prep_8tap
+ - AVX2 optimizations for MC scaled
+ - Fix a clamping issue in motion vector projection
+ - Fix an issue on some specific Haswell CPU on ipred_z AVX2 functions
+ - Improvements on the dav1dplay utility player to support resizing
+
+
+Changes for 0.7.0 'Frigatebird':
+------------------------------
+
+0.7.0 is a major release for dav1d:
+ - Faster refmv implementation gaining up to 12% speed while -25% of RAM (Single Thread)
+ - 10b/12b ARM64 optimizations are mostly complete:
+   - ipred (paeth, smooth, dc, pal, filter, cfl)
+   - itxfm (only 10b)
+ - AVX2/SSSE3 for non-4:2:0 film grain and for mc.resize
+ - AVX2 for cfl4:4:4
+ - AVX-512 CDEF filter
+ - ARM64 8b improvements for cfl_ac and itxfm
+ - ARM64 implementation for emu_edge in 8b/10b/12b
+ - ARM32 implementation for emu_edge in 8b
+ - Improvements on the dav1dplay utility player to support 10 bit,
+   non-4:2:0 pixel formats and film grain on the GPU
+
+
+Changes for 0.6.0 'Gyrfalcon':
+------------------------------
+
+0.6.0 is a major release for dav1d:
+ - New ARM64 optimizations for the 10/12bit depth:
+    - mc_avg, mc_w_avg, mc_mask
+    - mc_put/mc_prep 8tap/bilin
+    - mc_warp_8x8
+    - mc_w_mask
+    - mc_blend
+    - wiener
+    - SGR
+    - loopfilter
+    - cdef
+ - New AVX-512 optimizations for prep_bilin, prep_8tap, cdef_filter, mc_avg/w_avg/mask
+ - New SSSE3 optimizations for film grain
+ - New AVX2 optimizations for msac_adapt16
+ - Fix rare mismatches against the reference decoder, notably because of clipping
+ - Improvements on ARM64 on msac, cdef, mc_blend_v and looprestoration optimizations
+ - Improvements on AVX2 optimizations for cdef_filter
+ - Improvements in the C version for itxfm, cdef_filter
+
+
+Changes for 0.5.2 'Asiatic Cheetah':
+------------------------------------
+
+0.5.2 is a small release improving speed for ARM32 and adding minor features:
+ - ARM32 optimizations for loopfilter, ipred_dc|h|v
+ - Add section-5 raw OBU demuxer
+ - Improve the speed by reducing the L2 cache collisions
+ - Fix minor issues
+
+
+Changes for 0.5.1 'Asiatic Cheetah':
+------------------------------------
+
+0.5.1 is a small release improving speeds and fixing minor issues
+compared to 0.5.0:
+ - SSE2 optimizations for CDEF, wiener and warp_affine
+ - NEON optimizations for SGR on ARM32
+ - Fix mismatch issue in x86 asm in inverse identity transforms
+ - Fix build issue in ARM64 assembly if debug info was enabled
+ - Add a workaround for Xcode 11 -fstack-check bug
+
+
+Changes for 0.5.0 'Asiatic Cheetah':
+------------------------------------
+
+0.5.0 is a medium release fixing regressions and minor issues,
+and improving speed significantly:
+ - Export ITU T.35 metadata
+ - Speed improvements on blend_ on ARM
+ - Speed improvements on decode_coef and MSAC
+ - NEON optimizations for blend*, w_mask_, ipred functions for ARM64
+ - NEON optimizations for CDEF and warp on ARM32
+ - SSE2 optimizations for MSAC hi_tok decoding
+ - SSSE3 optimizations for deblocking loopfilters and warp_affine
+ - AVX2 optimizations for film grain and ipred_z2
+ - SSE4 optimizations for warp_affine
+ - VSX optimizations for wiener
+ - Fix inverse transform overflows in x86 and NEON asm
+ - Fix integer overflows with large frames
+ - Improve film grain generation to match reference code
+ - Improve compatibility with older binutils for ARM
+ - More advanced Player example in tools
+
+
+Changes for 0.4.0 'Cheetah':
+----------------------------
+
+ - Fix playback with unknown OBUs
+ - Add an option to limit the maximum frame size
+ - SSE2 and ARM64 optimizations for MSAC
+ - Improve speed on 32bits systems
+ - Optimization in obmc blend
+ - Reduce RAM usage significantly
+ - The initial PPC SIMD code, cdef_filter
+ - NEON optimizations for blend functions on ARM
+ - NEON optimizations for w_mask functions on ARM
+ - NEON optimizations for inverse transforms on ARM64
+ - VSX optimizations for CDEF filter
+ - Improve handling of malloc failures
+ - Simple Player example in tools
+
+
+Changes for 0.3.1 'Sailfish':
+------------------------------
+
+ - Fix a buffer overflow in frame-threading mode on SSSE3 CPUs
+ - Reduce binary size, notably on Windows
+ - SSSE3 optimizations for ipred_filter
+ - ARM optimizations for MSAC
+
+
+Changes for 0.3.0 'Sailfish':
+------------------------------
+
+This is the final release for the numerous speed improvements of 0.3.0-rc.
+It mostly:
+ - Fixes an annoying crash on SSSE3 that happened in the itx functions
+
+
+Changes for 0.2.2 (0.3.0-rc) 'Antelope':
+-----------------------------
+
+ - Large improvement on MSAC decoding with SSE, bringing 4-6% speed increase
+   The impact is important on SSSE3, SSE4 and AVX2 cpus
+ - SSSE3 optimizations for all blocks size in itx
+ - SSSE3 optimizations for ipred_paeth and ipred_cfl (420, 422 and 444)
+ - Speed improvements on CDEF for SSE4 CPUs
+ - NEON optimizations for SGR and loop filter
+ - Minor crashes, improvements and build changes
+
+
+Changes for 0.2.1 'Antelope':
+----------------------------
+
+ - SSSE3 optimization for cdef_dir
+ - AVX2 improvements of the existing CDEF optimizations
+ - NEON improvements of the existing CDEF and wiener optimizations
+ - Clarification about the numbering/versionning scheme
+
+
+Changes for 0.2.0 'Antelope':
+----------------------------
+
+ - ARM64 and ARM optimizations using NEON instructions
+ - SSSE3 optimizations for both 32 and 64bits
+ - More AVX2 assembly, reaching almost completion
+ - Fix installation of includes
+ - Rewrite inverse transforms to avoid overflows
+ - Snap packaging for Linux
+ - Updated API (ABI and API break)
+ - Fixes for un-decodable samples
+
+
+Changes for 0.1.0 'Gazelle':
+----------------------------
+
+Initial release of dav1d, the fast and small AV1 decoder.
+ - Support for all features of the AV1 bitstream
+ - Support for all bitdepth, 8, 10 and 12bits
+ - Support for all chroma subsamplings 4:2:0, 4:2:2, 4:4:4 *and* grayscale
+ - Full acceleration for AVX2 64bits processors, making it the fastest decoder
+ - Partial acceleration for SSSE3 processors
+ - Partial acceleration for NEON processors
diff --git a/media/libdav1d/src/README.md b/media/libdav1d/src/README.md
new file mode 100644
index 0000000000..3421b45921
--- /dev/null
+++ b/media/libdav1d/src/README.md
@@ -0,0 +1,168 @@
+![dav1d logo](doc/dav1d_logo.png)
+
+# dav1d
+
+**dav1d** is an **AV1** cross-platform **d**ecoder, open-source, and focused on speed and correctness.
+
+It is now battle-tested and production-ready and can be used everywhere.
+
+The canonical repository URL for this repo is https://code.videolan.org/videolan/dav1d
+
+This project was partially funded by the *Alliance for Open Media*/**AOM**.
+
+## Goal and Features
+
+The goal of this project is to provide a decoder for **most platforms**, and achieve the **highest speed** possible to overcome the temporary lack of AV1 hardware decoder.
+
+It supports all features from AV1, including all subsampling and bit-depth parameters.
+
+In the future, this project will host simple tools or simple wrappings *(like, for example, an MFT transform)*.
+
+## License
+
+**dav1d** is released under a very liberal license, a contrario from the other VideoLAN projects, so that it can be embedded anywhere, including non-open-source software; or even drivers, to allow the creation of hybrid decoders.
+
+The reasoning behind this decision is the same as for libvorbis, see [RMS on vorbis](https://lwn.net/2001/0301/a/rms-ov-license.php3).
+
+# Roadmap
+
+The plan is the following:
+
+### Reached
+1. Complete C implementation of the decoder,
+2. Provide a usable API,
+3. Port to most platforms,
+4. Make it fast on desktop, by writing asm for AVX2 chips.
+5. Make it fast on mobile, by writing asm for ARMv8 chips,
+6. Make it fast on older desktop, by writing asm for SSSE3+ chips,
+7. Make high bit-depth fast on mobile, by writing asm for ARMv8 chips.
+8. Make it fast on older mobile, by writing asm for ARMv7 chips,
+9. Make high bit-depth fast on older mobile, by writing asm for ARMv7 chips,
+10. Make high bit-depth fast on desktop, by writing asm for AVX2 chips,
+11. Make high bit-depth fast on older desktop, by writing asm for SSSE3+ chips,
+12. Improve threading.
+
+### On-going
+13. Improve C code base with [various tweaks](https://code.videolan.org/videolan/dav1d/wikis/task-list),
+14. Accelerate for less common architectures, like PPC, SSE2, RISC-V or AVX-512.
+
+### After
+15. Use more GPU decoding, when possible.
+
+# Contribute
+
+Currently, we are looking for help from:
+- C developers,
+- asm developers,
+- platform-specific developers,
+- GPGPU developers,
+- testers.
+
+Our contributions guidelines are quite strict. We want to build a coherent codebase to simplify maintenance and achieve the highest possible speed.
+
+Notably, the codebase is in pure C and asm.
+
+We are on IRC, on the **#dav1d** channel on [*Libera.chat*](http://libera.chat/). If you do not have an IRC Client at hand, use [IRC Web Interface](https://web.libera.chat/#dav1d).
+
+See the [contributions document](CONTRIBUTING.md).
+
+## CLA
+
+There is no CLA.
+
+People will keep their copyright and their authorship rights, while adhering to the BSD 2-clause license.
+
+VideoLAN will only have the collective work rights.
+
+## CoC
+
+The [VideoLAN Code of Conduct](https://wiki.videolan.org/CoC) applies to this project.
+
+# Compile
+## General compilation steps
+
+1. Install [Meson](https://mesonbuild.com/) (0.49 or higher), [Ninja](https://ninja-build.org/), and, for x86\* targets, [nasm](https://nasm.us/) (2.14 or higher)
+2. Run `mkdir build && cd build` to create a build directory and enter it
+3. Run `meson setup ..` to configure meson, add `--default-library=static` if static linking is desired
+4. Run `ninja` to compile
+
+Following are modification of step 3 and 4, for specific purpose.
+
+## Cross-Compilation for 32- or 64-bit Windows, 32-bit Linux
+
+If you're on a linux build machine trying to compile .exe for a Windows target/host machine, configure meson like this
+
+```
+meson setup .. --cross-file=../package/crossfiles/x86_64-w64-mingw32.meson
+```
+
+or, for 32-bit:
+
+```
+meson setup .. --cross-file=../package/crossfiles/i686-w64-mingw32.meson
+```
+
+`mingw-w64` is a pre-requisite and should be installed on your linux machine via your preferred method or package manager. Note the binary name formats may differ between distributions. Verify the names, and use `alias` if certain binaries cannot be found.
+
+For 32-bit linux, run
+
+```
+meson setup .. --cross-file=../package/crossfiles/i686-linux32.meson
+```
+
+## Build documentation
+
+1. Make sure [doxygen](https://www.doxygen.nl/) and [graphviz](https://www.graphviz.org/) are installed.
+2. Run `meson setup .. -Denable_docs=true` to configure meson to generate docs from the build directory.
+3. Run `ninja doc/html` to build the docs
+
+The result can be found in `build/doc/html/`. An online version built from master can be found [here](https://videolan.videolan.me/dav1d/).
+
+# Run tests
+
+1. In the root directory, run `git clone https://code.videolan.org/videolan/dav1d-test-data.git tests/dav1d-test-data` to fetch the test data repository
+2. During meson configuration, specify `-Dtestdata_tests=true`
+3. Run `meson test -v` after compiling
+
+## Decoder conformance tests (optional but encouraged)
+
+1. Download the argon conformance bitstreams from https://streams.videolan.org/argon/
+2. Extract into dav1d directory by running `tar -xvf argon.tar.zst`
+3. Execute tests with `tests/dav1d_argon.bash -d build/tools/dav1d -a argon`
+4. Expected outcome is `2763 files successfully verified in XXmYYs (dav1d 1.x.y-zz-gHHHHHHH filmgrain=1 cpumask=-1)`
+
+# Support
+
+This project is partially funded by the *Alliance for Open Media*/**AOM** and is supported by TwoOrioles and VideoLabs.
+
+These companies can provide support and integration help, should you need it.
+
+
+# FAQ
+
+## Why do you not improve libaom rather than starting a new project?
+
+- We believe that libaom is a very good library. It was however developed for research purposes during AV1 design.
+We think that an implementation written from scratch can achieve faster decoding, in the same way that *ffvp9* was faster than *libvpx*.
+
+## Is dav1d a recursive acronym?
+
+- Yes.
+
+## Can I help?
+
+- Yes. See the [contributions document](CONTRIBUTING.md).
+
+## I am not a developer. Can I help?
+
+- Yes. We need testers, bug reporters and documentation writers.
+
+## What about the AV1 patent license?
+
+- This project is an implementation of a decoder. It gives you no special rights on the AV1 patents.
+
+Please read the [AV1 patent license](doc/PATENTS) that applies to the AV1 specification and codec.
+
+## Will you care about ? ?
+
+- We do, but we don't have either the time or the knowledge. Therefore, patches and contributions welcome.
diff --git a/media/libdav1d/src/THANKS.md b/media/libdav1d/src/THANKS.md
new file mode 100644
index 0000000000..b7aa200d0e
--- /dev/null
+++ b/media/libdav1d/src/THANKS.md
@@ -0,0 +1,35 @@
+# The dav1d project and VideoLAN association would like to thank
+
+## AOM
+The Alliance for Open Media (AOM) for partially funding this project.
+
+## Companies
+* Two Orioles LLC, for important coding effort
+* VideoLabs SAS
+
+## Projects
+* VideoLAN
+* FFmpeg
+* libplacebo
+
+## Individual
+
+And all the dav1d Authors (git shortlog -sn), including:
+
+Henrik Gramner, Martin Storsjö, Ronald S. Bultje, Janne Grunau, James Almer,
+Victorien Le Couviour--Tuffet, Matthias Dressel, Nathan E. Egge,
+Jean-Baptiste Kempf, Marvin Scholz, Luc Trudeau, Niklas Haas,
+Hugo Beauzée-Luyssen, Konstantin Pavlov, David Michael Barr, Steve Lhomme,
+yuanhecai, Luca Barbato, Wan-Teh Chang, Kyle Siefring, B Krishnan Iyer,
+Francois Cartegnie, Liwei Wang, David Conrad, Derek Buitenhuis, Jan Beich,
+Michael Bradshaw, Raphaël Zumer, Xuefeng Jiang, Arpad Panyik, Christophe Gisquet,
+Justin Bull, Boyuan Xiao, Dale Curtis, Emmanuel Gil Peyrot, Raphael Zumer,
+Rupert Swarbrick, Thierry Foucu, Thomas Daede, jinbo, André Kempe, Colin Lee,
+Jonathan Wright, Lynne, Michail Alvanos, Nico Weber, Salome Thirot, SmilingWolf,
+Tristan Laurent, Tristan Matthews, Vittorio Giovara, Yannis Guyon,
+Andrey Semashev, Anisse Astier, Anton Mitrofanov, Charlie Hayden, Dmitriy Sychov,
+Ewout ter Hoeven, Fred Barbier, Hao Chen, Jean-Yves Avenard, Joe Drago,
+Mark Shuttleworth, Matthieu Bouron, Mehdi Sabwat, Nicolas Frattaroli,
+Pablo Stebler, Rostislav Pehlivanov, Sebastian Dröge, Shiz, Steinar Midtskogen,
+Sylvain BERTRAND, Sylvestre Ledru, Timo Gurr, Vibhoothi,
+Vignesh Venkatasubramanian, Xavier Claessens, Xu Guangxin, kossh1 and skal.
diff --git a/media/libdav1d/src/doc/Doxyfile.in.in b/media/libdav1d/src/doc/Doxyfile.in.in
new file mode 100644
index 0000000000..2f54f9a34a
--- /dev/null
+++ b/media/libdav1d/src/doc/Doxyfile.in.in
@@ -0,0 +1,23 @@
+PROJECT_NAME            = dav1d
+PROJECT_NUMBER          = \@VCS_TAG\@
+PROJECT_BRIEF           = dav1d is an AV1 decoder
+OUTPUT_DIRECTORY        = @DOXYGEN_OUTPUT@
+STRIP_FROM_PATH         = @DOXYGEN_STRIP@
+OUTPUT_LANGUAGE         = English
+TAB_SIZE                = 4
+EXTRACT_ALL             = YES
+OPTIMIZE_OUTPUT_FOR_C   = YES
+DOXYFILE_ENCODING       = UTF-8
+TYPEDEF_HIDES_STRUCT    = YES
+HAVE_DOT                = YES
+
+QUIET                   = YES
+WARNINGS                = YES
+WARN_IF_UNDOCUMENTED    = YES
+WARN_AS_ERROR           = FAIL_ON_WARNINGS
+
+INPUT                   = @DOXYGEN_INPUT@
+FILE_PATTERNS           = *.h
+
+GENERATE_HTML           = YES
+GENERATE_LATEX          = NO
diff --git a/media/libdav1d/src/doc/PATENTS b/media/libdav1d/src/doc/PATENTS
new file mode 100644
index 0000000000..d57102a5d4
--- /dev/null
+++ b/media/libdav1d/src/doc/PATENTS
@@ -0,0 +1,108 @@
+Alliance for Open Media Patent License 1.0
+
+1. License Terms.
+
+1.1. Patent License. Subject to the terms and conditions of this License, each
+     Licensor, on behalf of itself and successors in interest and assigns,
+     grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive,
+     no-charge, royalty-free, irrevocable (except as expressly stated in this
+     License) patent license to its Necessary Claims to make, use, sell, offer
+     for sale, import or distribute any Implementation.
+
+1.2. Conditions.
+
+1.2.1. Availability. As a condition to the grant of rights to Licensee to make,
+       sell, offer for sale, import or distribute an Implementation under
+       Section 1.1, Licensee must make its Necessary Claims available under
+       this License, and must reproduce this License with any Implementation
+       as follows:
+
+       a. For distribution in source code, by including this License in the
+          root directory of the source code with its Implementation.
+
+       b. For distribution in any other form (including binary, object form,
+          and/or hardware description code (e.g., HDL, RTL, Gate Level Netlist,
+          GDSII, etc.)), by including this License in the documentation, legal
+          notices, and/or other written materials provided with the
+          Implementation.
+
+1.2.2. Additional Conditions. This license is directly from Licensor to
+       Licensee.  Licensee acknowledges as a condition of benefiting from it
+       that no rights from Licensor are received from suppliers, distributors,
+       or otherwise in connection with this License.
+
+1.3. Defensive Termination. If any Licensee, its Affiliates, or its agents
+     initiates patent litigation or files, maintains, or voluntarily
+     participates in a lawsuit against another entity or any person asserting
+     that any Implementation infringes Necessary Claims, any patent licenses
+     granted under this License directly to the Licensee are immediately
+     terminated as of the date of the initiation of action unless 1) that suit
+     was in response to a corresponding suit regarding an Implementation first
+     brought against an initiating entity, or 2) that suit was brought to
+     enforce the terms of this License (including intervention in a third-party
+     action by a Licensee).
+
+1.4. Disclaimers. The Reference Implementation and Specification are provided
+     "AS IS" and without warranty. The entire risk as to implementing or
+     otherwise using the Reference Implementation or Specification is assumed
+     by the implementer and user. Licensor expressly disclaims any warranties
+     (express, implied, or otherwise), including implied warranties of
+     merchantability, non-infringement, fitness for a particular purpose, or
+     title, related to the material. IN NO EVENT WILL LICENSOR BE LIABLE TO
+     ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL,
+     INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF
+     ACTION OF ANY KIND WITH RESPECT TO THIS LICENSE, WHETHER BASED ON BREACH
+     OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR
+     NOT THE OTHER PARTRY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+2. Definitions.
+
+2.1. Affiliate.  “Affiliate” means an entity that directly or indirectly
+     Controls, is Controlled by, or is under common Control of that party.
+
+2.2. Control. “Control” means direct or indirect control of more than 50% of
+     the voting power to elect directors of that corporation, or for any other
+     entity, the power to direct management of such entity.
+
+2.3. Decoder.  "Decoder" means any decoder that conforms fully with all
+     non-optional portions of the Specification.
+
+2.4. Encoder.  "Encoder" means any encoder that produces a bitstream that can
+     be decoded by a Decoder only to the extent it produces such a bitstream.
+
+2.5. Final Deliverable.  “Final Deliverable” means the final version of a
+     deliverable approved by the Alliance for Open Media as a Final
+     Deliverable.
+
+2.6. Implementation.  "Implementation" means any implementation, including the
+     Reference Implementation, that is an Encoder and/or a Decoder. An
+     Implementation also includes components of an Implementation only to the
+     extent they are used as part of an Implementation.
+
+2.7. License. “License” means this license.
+
+2.8. Licensee. “Licensee” means any person or entity who exercises patent
+     rights granted under this License.
+
+2.9. Licensor.  "Licensor" means (i) any Licensee that makes, sells, offers
+     for sale, imports or distributes any Implementation, or (ii) a person
+     or entity that has a licensing obligation to the Implementation as a
+     result of its membership and/or participation in the Alliance for Open
+     Media working group that developed the Specification.
+
+2.10. Necessary Claims.  "Necessary Claims" means all claims of patents or
+      patent applications, (a) that currently or at any time in the future,
+      are owned or controlled by the Licensor, and (b) (i) would be an
+      Essential Claim as defined by the W3C Policy as of February 5, 2004
+      (https://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential)
+      as if the Specification was a W3C Recommendation; or (ii) are infringed
+      by the Reference Implementation.
+
+2.11. Reference Implementation. “Reference Implementation” means an Encoder
+      and/or Decoder released by the Alliance for Open Media as a Final
+      Deliverable.
+
+2.12. Specification. “Specification” means the specification designated by
+      the Alliance for Open Media as a Final Deliverable for which this
+      License was issued.
+
diff --git a/media/libdav1d/src/doc/dav1d_logo.png b/media/libdav1d/src/doc/dav1d_logo.png
new file mode 100644
index 0000000000..2d00855f70
Binary files /dev/null and b/media/libdav1d/src/doc/dav1d_logo.png differ
diff --git a/media/libdav1d/src/doc/dav1d_logo.svg b/media/libdav1d/src/doc/dav1d_logo.svg
new file mode 100644
index 0000000000..2795db8a93
--- /dev/null
+++ b/media/libdav1d/src/doc/dav1d_logo.svg
@@ -0,0 +1 @@
+dav1d
diff --git a/media/libdav1d/src/doc/meson.build b/media/libdav1d/src/doc/meson.build
new file mode 100644
index 0000000000..580ee7b9ca
--- /dev/null
+++ b/media/libdav1d/src/doc/meson.build
@@ -0,0 +1,51 @@
+# Copyright © 2018-2022, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+if not get_option('enable_docs')
+    subdir_done()
+endif
+
+doxygen = find_program('doxygen')
+dot = find_program('dot')
+
+conf_data = configuration_data()
+conf_data.set('DOXYGEN_INPUT', dav1d_src_root / 'include/dav1d')
+conf_data.set('DOXYGEN_STRIP', dav1d_src_root / 'include')
+conf_data.set('DOXYGEN_OUTPUT', meson.current_build_dir())
+doxyfile = configure_file(input: 'Doxyfile.in.in',
+                          output: 'Doxyfile.in',
+                          configuration: conf_data)
+
+doxyfile_rev_target = vcs_tag(command: [
+        'git', '--git-dir', dav1d_git_dir, 'describe', '--long', '--always'
+    ],
+    input: doxyfile,
+    output: 'Doxyfile'
+)
+
+custom_target('doc',
+              build_by_default: false,
+              command: [doxygen, doxyfile_rev_target],
+              output: ['html']
+)
diff --git a/media/libdav1d/src/examples/dav1dplay.c b/media/libdav1d/src/examples/dav1dplay.c
new file mode 100644
index 0000000000..1f64944483
--- /dev/null
+++ b/media/libdav1d/src/examples/dav1dplay.c
@@ -0,0 +1,792 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "vcs_version.h"
+
+#include 
+#include 
+
+#include 
+
+#include "dav1d/dav1d.h"
+
+#include "common/attributes.h"
+#include "tools/input/input.h"
+#include "dp_fifo.h"
+#include "dp_renderer.h"
+
+#define FRAME_OFFSET_TO_PTS(foff) \
+    (uint64_t)(((foff) * rd_ctx->spf) * 1000000000.0 + .5)
+#define TS_TO_PTS(ts) \
+    (uint64_t)(((ts) * rd_ctx->timebase) * 1000000000.0 + .5)
+
+// Selected renderer callbacks and cookie
+static const Dav1dPlayRenderInfo *renderer_info = { NULL };
+
+/**
+ * Render context structure
+ * This structure contains informations necessary
+ * to be shared between the decoder and the renderer
+ * threads.
+ */
+typedef struct render_context
+{
+    Dav1dPlaySettings settings;
+    Dav1dSettings lib_settings;
+
+    // Renderer private data (passed to callbacks)
+    void *rd_priv;
+
+    // Lock to protect access to the context structure
+    SDL_mutex *lock;
+
+    // Timestamp of last displayed frame (in timebase unit)
+    int64_t last_ts;
+    // Timestamp of last decoded frame (in timebase unit)
+    int64_t current_ts;
+    // Ticks when last frame was received
+    uint32_t last_ticks;
+    // PTS time base
+    double timebase;
+    // Seconds per frame
+    double spf;
+    // Number of frames
+    uint32_t total;
+
+    // Fifo
+    Dav1dPlayPtrFifo *fifo;
+
+    // Custom SDL2 event types
+    uint32_t event_types;
+
+    // User pause state
+    uint8_t user_paused;
+    // Internal pause state
+    uint8_t paused;
+    // Start of internal pause state
+    uint32_t pause_start;
+    // Duration of internal pause state
+    uint32_t pause_time;
+
+    // Seek accumulator
+    int seek;
+
+    // Indicates if termination of the decoder thread was requested
+    uint8_t dec_should_terminate;
+} Dav1dPlayRenderContext;
+
+static void dp_settings_print_usage(const char *const app,
+                                    const char *const reason, ...)
+{
+    if (reason) {
+        va_list args;
+
+        va_start(args, reason);
+        vfprintf(stderr, reason, args);
+        va_end(args);
+        fprintf(stderr, "\n\n");
+    }
+    fprintf(stderr, "Usage: %s [options]\n\n", app);
+    fprintf(stderr, "Supported options:\n"
+            " --input/-i  $file:    input file\n"
+            " --untimed/-u:         ignore PTS, render as fast as possible\n"
+            " --threads $num:       number of threads (default: 0)\n"
+            " --framedelay $num:    maximum frame delay, capped at $threads (default: 0);\n"
+            "                       set to 1 for low-latency decoding\n"
+            " --highquality:        enable high quality rendering\n"
+            " --zerocopy/-z:        enable zero copy upload path\n"
+            " --gpugrain/-g:        enable GPU grain synthesis\n"
+            " --fullscreen/-f:      enable full screen mode\n"
+            " --version/-v:         print version and exit\n"
+            " --renderer/-r:        select renderer backend (default: auto)\n");
+    exit(1);
+}
+
+static unsigned parse_unsigned(const char *const optarg, const int option,
+                               const char *const app)
+{
+    char *end;
+    const unsigned res = (unsigned) strtoul(optarg, &end, 0);
+    if (*end || end == optarg)
+        dp_settings_print_usage(app, "Invalid argument \"%s\" for option %s; should be an integer",
+          optarg, option);
+    return res;
+}
+
+static void dp_rd_ctx_parse_args(Dav1dPlayRenderContext *rd_ctx,
+                                 const int argc, char *const *const argv)
+{
+    int o;
+    Dav1dPlaySettings *settings = &rd_ctx->settings;
+    Dav1dSettings *lib_settings = &rd_ctx->lib_settings;
+
+    // Short options
+    static const char short_opts[] = "i:vuzgfr:";
+
+    enum {
+        ARG_THREADS = 256,
+        ARG_FRAME_DELAY,
+        ARG_HIGH_QUALITY,
+    };
+
+    // Long options
+    static const struct option long_opts[] = {
+        { "input",          1, NULL, 'i' },
+        { "version",        0, NULL, 'v' },
+        { "untimed",        0, NULL, 'u' },
+        { "threads",        1, NULL, ARG_THREADS },
+        { "framedelay",     1, NULL, ARG_FRAME_DELAY },
+        { "highquality",    0, NULL, ARG_HIGH_QUALITY },
+        { "zerocopy",       0, NULL, 'z' },
+        { "gpugrain",       0, NULL, 'g' },
+        { "fullscreen",     0, NULL, 'f'},
+        { "renderer",       0, NULL, 'r'},
+        { NULL,             0, NULL, 0 },
+    };
+
+    while ((o = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
+        switch (o) {
+            case 'i':
+                settings->inputfile = optarg;
+                break;
+            case 'v':
+                fprintf(stderr, "%s\n", dav1d_version());
+                exit(0);
+            case 'u':
+                settings->untimed = true;
+                break;
+            case ARG_HIGH_QUALITY:
+                settings->highquality = true;
+                break;
+            case 'z':
+                settings->zerocopy = true;
+                break;
+            case 'g':
+                settings->gpugrain = true;
+                break;
+            case 'f':
+                settings->fullscreen = true;
+                break;
+            case 'r':
+                settings->renderer_name = optarg;
+                break;
+            case ARG_THREADS:
+                lib_settings->n_threads =
+                    parse_unsigned(optarg, ARG_THREADS, argv[0]);
+                break;
+            case ARG_FRAME_DELAY:
+                lib_settings->max_frame_delay =
+                    parse_unsigned(optarg, ARG_FRAME_DELAY, argv[0]);
+                break;
+            default:
+                dp_settings_print_usage(argv[0], NULL);
+        }
+    }
+
+    if (optind < argc)
+        dp_settings_print_usage(argv[0],
+            "Extra/unused arguments found, e.g. '%s'\n", argv[optind]);
+    if (!settings->inputfile)
+        dp_settings_print_usage(argv[0], "Input file (-i/--input) is required");
+    if (settings->renderer_name && strcmp(settings->renderer_name, "auto") == 0)
+        settings->renderer_name = NULL;
+}
+
+/**
+ * Destroy a Dav1dPlayRenderContext
+ */
+static void dp_rd_ctx_destroy(Dav1dPlayRenderContext *rd_ctx)
+{
+    assert(rd_ctx != NULL);
+
+    renderer_info->destroy_renderer(rd_ctx->rd_priv);
+    dp_fifo_destroy(rd_ctx->fifo);
+    SDL_DestroyMutex(rd_ctx->lock);
+    free(rd_ctx);
+}
+
+/**
+ * Create a Dav1dPlayRenderContext
+ *
+ * \note  The Dav1dPlayRenderContext must be destroyed
+ *        again by using dp_rd_ctx_destroy.
+ */
+static Dav1dPlayRenderContext *dp_rd_ctx_create(int argc, char **argv)
+{
+    Dav1dPlayRenderContext *rd_ctx;
+
+    // Alloc
+    rd_ctx = calloc(1, sizeof(Dav1dPlayRenderContext));
+    if (rd_ctx == NULL) {
+        return NULL;
+    }
+
+    // Parse and validate arguments
+    dav1d_default_settings(&rd_ctx->lib_settings);
+    memset(&rd_ctx->settings, 0, sizeof(rd_ctx->settings));
+    dp_rd_ctx_parse_args(rd_ctx, argc, argv);
+
+    // Init SDL2 library
+    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
+        fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
+        goto fail;
+    }
+
+    // Register a custom event to notify our SDL main thread
+    // about new frames
+    rd_ctx->event_types = SDL_RegisterEvents(3);
+    if (rd_ctx->event_types == UINT32_MAX) {
+        fprintf(stderr, "Failure to create custom SDL event types!\n");
+        goto fail;
+    }
+
+    rd_ctx->fifo = dp_fifo_create(5);
+    if (rd_ctx->fifo == NULL) {
+        fprintf(stderr, "Failed to create FIFO for output pictures!\n");
+        goto fail;
+    }
+
+    rd_ctx->lock = SDL_CreateMutex();
+    if (rd_ctx->lock == NULL) {
+        fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
+        goto fail;
+    }
+
+    // Select renderer
+    renderer_info = dp_get_renderer(rd_ctx->settings.renderer_name);
+
+    if (renderer_info == NULL) {
+        printf("No suitable renderer matching %s found.\n",
+            (rd_ctx->settings.renderer_name) ? rd_ctx->settings.renderer_name : "auto");
+    } else {
+        printf("Using %s renderer\n", renderer_info->name);
+    }
+
+    rd_ctx->rd_priv = (renderer_info) ? renderer_info->create_renderer(&rd_ctx->settings) : NULL;
+    if (rd_ctx->rd_priv == NULL) {
+        goto fail;
+    }
+
+    return rd_ctx;
+
+fail:
+    if (rd_ctx->lock)
+        SDL_DestroyMutex(rd_ctx->lock);
+    if (rd_ctx->fifo)
+        dp_fifo_destroy(rd_ctx->fifo);
+    free(rd_ctx);
+    SDL_Quit();
+    return NULL;
+}
+
+/**
+ * Notify about new event
+ */
+static void dp_rd_ctx_post_event(Dav1dPlayRenderContext *rd_ctx, uint32_t type)
+{
+    SDL_Event event;
+    SDL_zero(event);
+    event.type = type;
+    SDL_PushEvent(&event);
+}
+
+/**
+ * Update the decoder context with a new dav1d picture
+ *
+ * Once the decoder decoded a new picture, this call can be used
+ * to update the internal texture of the render context with the
+ * new picture.
+ */
+static void dp_rd_ctx_update_with_dav1d_picture(Dav1dPlayRenderContext *rd_ctx,
+                                                Dav1dPicture *dav1d_pic)
+{
+    rd_ctx->current_ts = dav1d_pic->m.timestamp;
+    renderer_info->update_frame(rd_ctx->rd_priv, dav1d_pic, &rd_ctx->settings);
+}
+
+/**
+ * Toggle pause state
+ */
+static void dp_rd_ctx_toggle_pause(Dav1dPlayRenderContext *rd_ctx)
+{
+    SDL_LockMutex(rd_ctx->lock);
+    rd_ctx->user_paused = !rd_ctx->user_paused;
+    if (rd_ctx->seek)
+        goto out;
+    rd_ctx->paused = rd_ctx->user_paused;
+    uint32_t now = SDL_GetTicks();
+    if (rd_ctx->paused)
+        rd_ctx->pause_start = now;
+    else {
+        rd_ctx->pause_time += now - rd_ctx->pause_start;
+        rd_ctx->pause_start = 0;
+        rd_ctx->last_ticks = now;
+    }
+out:
+    SDL_UnlockMutex(rd_ctx->lock);
+}
+
+/**
+ * Query pause state
+ */
+static int dp_rd_ctx_is_paused(Dav1dPlayRenderContext *rd_ctx)
+{
+    int ret;
+    SDL_LockMutex(rd_ctx->lock);
+    ret = rd_ctx->paused;
+    SDL_UnlockMutex(rd_ctx->lock);
+    return ret;
+}
+
+/**
+ * Request seeking, in seconds
+ */
+static void dp_rd_ctx_seek(Dav1dPlayRenderContext *rd_ctx, int sec)
+{
+    SDL_LockMutex(rd_ctx->lock);
+    rd_ctx->seek += sec;
+    if (!rd_ctx->paused)
+        rd_ctx->pause_start = SDL_GetTicks();
+    rd_ctx->paused = 1;
+    SDL_UnlockMutex(rd_ctx->lock);
+}
+
+static int decode_frame(Dav1dPicture **p, Dav1dContext *c,
+                        Dav1dData *data, DemuxerContext *in_ctx);
+static inline void destroy_pic(void *a);
+
+/**
+ * Seek the stream, if requested
+ */
+static int dp_rd_ctx_handle_seek(Dav1dPlayRenderContext *rd_ctx,
+                                 DemuxerContext *in_ctx,
+                                 Dav1dContext *c, Dav1dData *data)
+{
+    int res = 0;
+    SDL_LockMutex(rd_ctx->lock);
+    if (!rd_ctx->seek)
+        goto out;
+    int64_t seek = rd_ctx->seek * 1000000000ULL;
+    uint64_t pts = TS_TO_PTS(rd_ctx->current_ts);
+    pts = ((int64_t)pts > -seek) ? pts + seek : 0;
+    int end = pts >= FRAME_OFFSET_TO_PTS(rd_ctx->total);
+    if (end)
+        pts = FRAME_OFFSET_TO_PTS(rd_ctx->total - 1);
+    uint64_t target_pts = pts;
+    dav1d_flush(c);
+    uint64_t shift = FRAME_OFFSET_TO_PTS(5);
+    while (1) {
+        if (shift > pts)
+            shift = pts;
+        if ((res = input_seek(in_ctx, pts - shift)))
+            goto out;
+        Dav1dSequenceHeader seq;
+        uint64_t cur_pts;
+        do {
+            if ((res = input_read(in_ctx, data)))
+                break;
+            cur_pts = TS_TO_PTS(data->m.timestamp);
+            res = dav1d_parse_sequence_header(&seq, data->data, data->sz);
+        } while (res && cur_pts < pts);
+        if (!res && cur_pts <= pts)
+            break;
+        if (shift > pts)
+            shift = pts;
+        pts -= shift;
+    }
+    if (!res) {
+        pts = TS_TO_PTS(data->m.timestamp);
+        while (pts < target_pts) {
+            Dav1dPicture *p;
+            if ((res = decode_frame(&p, c, data, in_ctx)))
+                break;
+            if (p) {
+                pts = TS_TO_PTS(p->m.timestamp);
+                if (pts < target_pts)
+                    destroy_pic(p);
+                else {
+                    dp_fifo_push(rd_ctx->fifo, p);
+                    uint32_t type = rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME;
+                    dp_rd_ctx_post_event(rd_ctx, type);
+                }
+            }
+        }
+        if (!res) {
+            rd_ctx->last_ts = data->m.timestamp - rd_ctx->spf / rd_ctx->timebase;
+            rd_ctx->current_ts = data->m.timestamp;
+        }
+    }
+out:
+    rd_ctx->paused = rd_ctx->user_paused;
+    if (!rd_ctx->paused && rd_ctx->seek) {
+        uint32_t now = SDL_GetTicks();
+        rd_ctx->pause_time += now - rd_ctx->pause_start;
+        rd_ctx->pause_start = 0;
+        rd_ctx->last_ticks = now;
+    }
+    rd_ctx->seek = 0;
+    SDL_UnlockMutex(rd_ctx->lock);
+    if (res)
+        fprintf(stderr, "Error seeking, aborting\n");
+    return res;
+}
+
+/**
+ * Terminate decoder thread (async)
+ */
+static void dp_rd_ctx_request_shutdown(Dav1dPlayRenderContext *rd_ctx)
+{
+    SDL_LockMutex(rd_ctx->lock);
+    rd_ctx->dec_should_terminate = 1;
+    SDL_UnlockMutex(rd_ctx->lock);
+}
+
+/**
+ * Query state of decoder shutdown request
+ */
+static int dp_rd_ctx_should_terminate(Dav1dPlayRenderContext *rd_ctx)
+{
+    int ret = 0;
+    SDL_LockMutex(rd_ctx->lock);
+    ret = rd_ctx->dec_should_terminate;
+    SDL_UnlockMutex(rd_ctx->lock);
+    return ret;
+}
+
+/**
+ * Render the currently available texture
+ *
+ * Renders the currently available texture, if any.
+ */
+static void dp_rd_ctx_render(Dav1dPlayRenderContext *rd_ctx)
+{
+    SDL_LockMutex(rd_ctx->lock);
+    // Calculate time since last frame was received
+    uint32_t ticks_now = SDL_GetTicks();
+    uint32_t ticks_diff = (rd_ctx->last_ticks != 0) ? ticks_now - rd_ctx->last_ticks : 0;
+
+    // Calculate when to display the frame
+    int64_t ts_diff = rd_ctx->current_ts - rd_ctx->last_ts;
+    int32_t pts_diff = (ts_diff * rd_ctx->timebase) * 1000.0 + .5;
+    int32_t wait_time = pts_diff - ticks_diff;
+
+    // In untimed mode, simply don't wait
+    if (rd_ctx->settings.untimed)
+        wait_time = 0;
+
+    // This way of timing the playback is not accurate, as there is no guarantee
+    // that SDL_Delay will wait for exactly the requested amount of time so in a
+    // accurate player this would need to be done in a better way.
+    if (wait_time > 0) {
+        SDL_Delay(wait_time);
+    } else if (wait_time < -10 && !rd_ctx->paused) { // Do not warn for minor time drifts
+        fprintf(stderr, "Frame displayed %f seconds too late\n", wait_time / 1000.0);
+    }
+
+    renderer_info->render(rd_ctx->rd_priv, &rd_ctx->settings);
+
+    rd_ctx->last_ts = rd_ctx->current_ts;
+    rd_ctx->last_ticks = SDL_GetTicks();
+
+    SDL_UnlockMutex(rd_ctx->lock);
+}
+
+static int decode_frame(Dav1dPicture **p, Dav1dContext *c,
+                        Dav1dData *data, DemuxerContext *in_ctx)
+{
+    int res;
+    // Send data packets we got from the demuxer to dav1d
+    if ((res = dav1d_send_data(c, data)) < 0) {
+        // On EAGAIN, dav1d can not consume more data and
+        // dav1d_get_picture needs to be called first, which
+        // will happen below, so just keep going in that case
+        // and do not error out.
+        if (res != DAV1D_ERR(EAGAIN)) {
+            dav1d_data_unref(data);
+            goto err;
+        }
+    }
+    *p = calloc(1, sizeof(**p));
+    // Try to get a decoded frame
+    if ((res = dav1d_get_picture(c, *p)) < 0) {
+        // In all error cases, even EAGAIN, p needs to be freed as
+        // it is never added to the queue and would leak.
+        free(*p);
+        *p = NULL;
+        // On EAGAIN, it means dav1d has not enough data to decode
+        // therefore this is not a decoding error but just means
+        // we need to feed it more data, which happens in the next
+        // run of the decoder loop.
+        if (res != DAV1D_ERR(EAGAIN))
+            goto err;
+    }
+    return data->sz == 0 ? input_read(in_ctx, data) : 0;
+err:
+    fprintf(stderr, "Error decoding frame: %s\n",
+            strerror(-res));
+    return res;
+}
+
+static inline void destroy_pic(void *a)
+{
+    Dav1dPicture *p = (Dav1dPicture *)a;
+    dav1d_picture_unref(p);
+    free(p);
+}
+
+/* Decoder thread "main" function */
+static int decoder_thread_main(void *cookie)
+{
+    Dav1dPlayRenderContext *rd_ctx = cookie;
+
+    Dav1dPicture *p;
+    Dav1dContext *c = NULL;
+    Dav1dData data;
+    DemuxerContext *in_ctx = NULL;
+    int res = 0;
+    unsigned total, timebase[2], fps[2];
+
+    Dav1dPlaySettings settings = rd_ctx->settings;
+
+    if ((res = input_open(&in_ctx, "ivf",
+                          settings.inputfile,
+                          fps, &total, timebase)) < 0)
+    {
+        fprintf(stderr, "Failed to open demuxer\n");
+        res = 1;
+        goto cleanup;
+    }
+
+    rd_ctx->timebase = (double)timebase[1] / timebase[0];
+    rd_ctx->spf = (double)fps[1] / fps[0];
+    rd_ctx->total = total;
+
+    if ((res = dav1d_open(&c, &rd_ctx->lib_settings))) {
+        fprintf(stderr, "Failed opening dav1d decoder\n");
+        res = 1;
+        goto cleanup;
+    }
+
+    if ((res = input_read(in_ctx, &data)) < 0) {
+        fprintf(stderr, "Failed demuxing input\n");
+        res = 1;
+        goto cleanup;
+    }
+
+    // Decoder loop
+    while (1) {
+        if (dp_rd_ctx_should_terminate(rd_ctx) ||
+            (res = dp_rd_ctx_handle_seek(rd_ctx, in_ctx, c, &data)) ||
+            (res = decode_frame(&p, c, &data, in_ctx)))
+        {
+            break;
+        }
+        else if (p) {
+            // Queue frame
+            SDL_LockMutex(rd_ctx->lock);
+            int seek = rd_ctx->seek;
+            SDL_UnlockMutex(rd_ctx->lock);
+            if (!seek) {
+                dp_fifo_push(rd_ctx->fifo, p);
+                uint32_t type = rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME;
+                dp_rd_ctx_post_event(rd_ctx, type);
+            }
+        }
+    }
+
+    // Release remaining data
+    if (data.sz > 0)
+        dav1d_data_unref(&data);
+    // Do not drain in case an error occured and caused us to leave the
+    // decoding loop early.
+    if (res < 0)
+        goto cleanup;
+
+    // Drain decoder
+    // When there is no more data to feed to the decoder, for example
+    // because the file ended, we still need to request pictures, as
+    // even though we do not have more data, there can be frames decoded
+    // from data we sent before. So we need to call dav1d_get_picture until
+    // we get an EAGAIN error.
+    do {
+        if (dp_rd_ctx_should_terminate(rd_ctx))
+            break;
+        p = calloc(1, sizeof(*p));
+        res = dav1d_get_picture(c, p);
+        if (res < 0) {
+            free(p);
+            if (res != DAV1D_ERR(EAGAIN)) {
+                fprintf(stderr, "Error decoding frame: %s\n",
+                        strerror(-res));
+                break;
+            }
+        } else {
+            // Queue frame
+            dp_fifo_push(rd_ctx->fifo, p);
+            uint32_t type = rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME;
+            dp_rd_ctx_post_event(rd_ctx, type);
+        }
+    } while (res != DAV1D_ERR(EAGAIN));
+
+cleanup:
+    dp_rd_ctx_post_event(rd_ctx, rd_ctx->event_types + DAV1D_EVENT_DEC_QUIT);
+
+    if (in_ctx)
+        input_close(in_ctx);
+    if (c)
+        dav1d_close(&c);
+
+    return (res != DAV1D_ERR(EAGAIN) && res < 0);
+}
+
+int main(int argc, char **argv)
+{
+    SDL_Thread *decoder_thread;
+
+    // Check for version mismatch between library and tool
+    const char *version = dav1d_version();
+    if (strcmp(version, DAV1D_VERSION)) {
+        fprintf(stderr, "Version mismatch (library: %s, executable: %s)\n",
+                version, DAV1D_VERSION);
+        return 1;
+    }
+
+    // Create render context
+    Dav1dPlayRenderContext *rd_ctx = dp_rd_ctx_create(argc, argv);
+    if (rd_ctx == NULL) {
+        fprintf(stderr, "Failed creating render context\n");
+        return 5;
+    }
+
+    if (rd_ctx->settings.zerocopy) {
+        if (renderer_info->alloc_pic) {
+            rd_ctx->lib_settings.allocator = (Dav1dPicAllocator) {
+                .cookie = rd_ctx->rd_priv,
+                .alloc_picture_callback = renderer_info->alloc_pic,
+                .release_picture_callback = renderer_info->release_pic,
+            };
+        } else {
+            fprintf(stderr, "--zerocopy unsupported by selected renderer\n");
+        }
+    }
+
+    if (rd_ctx->settings.gpugrain) {
+        if (renderer_info->supports_gpu_grain) {
+            rd_ctx->lib_settings.apply_grain = 0;
+        } else {
+            fprintf(stderr, "--gpugrain unsupported by selected renderer\n");
+        }
+    }
+
+    // Start decoder thread
+    decoder_thread = SDL_CreateThread(decoder_thread_main, "Decoder thread", rd_ctx);
+
+    // Main loop
+#define NUM_MAX_EVENTS 8
+    SDL_Event events[NUM_MAX_EVENTS];
+    int num_frame_events = 0;
+    uint32_t start_time = 0, n_out = 0;
+    while (1) {
+        int num_events = 0;
+        SDL_WaitEvent(NULL);
+        while (num_events < NUM_MAX_EVENTS && SDL_PollEvent(&events[num_events++]))
+            break;
+        for (int i = 0; i < num_events; ++i) {
+            SDL_Event *e = &events[i];
+            if (e->type == SDL_QUIT) {
+                dp_rd_ctx_request_shutdown(rd_ctx);
+                dp_fifo_flush(rd_ctx->fifo, destroy_pic);
+                goto out;
+            } else if (e->type == SDL_WINDOWEVENT) {
+                if (e->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
+                    // TODO: Handle window resizes
+                } else if(e->window.event == SDL_WINDOWEVENT_EXPOSED) {
+                    dp_rd_ctx_render(rd_ctx);
+                }
+            } else if (e->type == SDL_KEYDOWN) {
+                SDL_KeyboardEvent *kbde = (SDL_KeyboardEvent *)e;
+                if (kbde->keysym.sym == SDLK_SPACE) {
+                    dp_rd_ctx_toggle_pause(rd_ctx);
+                } else if (kbde->keysym.sym == SDLK_ESCAPE) {
+                    dp_rd_ctx_request_shutdown(rd_ctx);
+                    dp_fifo_flush(rd_ctx->fifo, destroy_pic);
+                    goto out;
+                } else if (kbde->keysym.sym == SDLK_LEFT ||
+                           kbde->keysym.sym == SDLK_RIGHT)
+                {
+                    if (kbde->keysym.sym == SDLK_LEFT)
+                        dp_rd_ctx_seek(rd_ctx, -5);
+                    else if (kbde->keysym.sym == SDLK_RIGHT)
+                        dp_rd_ctx_seek(rd_ctx, +5);
+                    dp_fifo_flush(rd_ctx->fifo, destroy_pic);
+                    SDL_FlushEvent(rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME);
+                    num_frame_events = 0;
+                }
+            } else if (e->type == rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME) {
+                num_frame_events++;
+                // Store current ticks for stats calculation
+                if (start_time == 0)
+                    start_time = SDL_GetTicks();
+            } else if (e->type == rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME) {
+                // Dequeue frame and update the render context with it
+                Dav1dPicture *p = dp_fifo_shift(rd_ctx->fifo);
+                // Do not update textures during termination
+                if (!dp_rd_ctx_should_terminate(rd_ctx)) {
+                    dp_rd_ctx_update_with_dav1d_picture(rd_ctx, p);
+                    n_out++;
+                }
+                destroy_pic(p);
+            } else if (e->type == rd_ctx->event_types + DAV1D_EVENT_DEC_QUIT) {
+                goto out;
+            }
+        }
+        if (num_frame_events && !dp_rd_ctx_is_paused(rd_ctx)) {
+            // Dequeue frame and update the render context with it
+            Dav1dPicture *p = dp_fifo_shift(rd_ctx->fifo);
+            // Do not update textures during termination
+            if (!dp_rd_ctx_should_terminate(rd_ctx)) {
+                dp_rd_ctx_update_with_dav1d_picture(rd_ctx, p);
+                dp_rd_ctx_render(rd_ctx);
+                n_out++;
+            }
+            destroy_pic(p);
+            num_frame_events--;
+        }
+    }
+
+out:;
+    // Print stats
+    uint32_t time_ms = SDL_GetTicks() - start_time - rd_ctx->pause_time;
+    printf("Decoded %u frames in %d seconds, avg %.02f fps\n",
+           n_out, time_ms / 1000, n_out/ (time_ms / 1000.0));
+
+    int decoder_ret = 0;
+    SDL_WaitThread(decoder_thread, &decoder_ret);
+    dp_rd_ctx_destroy(rd_ctx);
+    SDL_Quit();
+    return decoder_ret;
+}
diff --git a/media/libdav1d/src/examples/dp_fifo.c b/media/libdav1d/src/examples/dp_fifo.c
new file mode 100644
index 0000000000..0de00fcfe0
--- /dev/null
+++ b/media/libdav1d/src/examples/dp_fifo.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include 
+#include 
+
+#include "dp_fifo.h"
+
+// FIFO structure
+struct dp_fifo
+{
+    SDL_mutex *lock;
+    SDL_cond *cond_change;
+    size_t capacity;
+    size_t count;
+    void **entries;
+    int push_wait;
+    int flush;
+};
+
+
+Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity)
+{
+    Dav1dPlayPtrFifo *fifo;
+
+    assert(capacity > 0);
+    if (capacity <= 0)
+        return NULL;
+
+    fifo = malloc(sizeof(*fifo));
+    if (fifo == NULL)
+        return NULL;
+
+    fifo->capacity = capacity;
+    fifo->count = 0;
+    fifo->push_wait = 0;
+    fifo->flush = 0;
+
+    fifo->lock = SDL_CreateMutex();
+    if (fifo->lock == NULL) {
+        free(fifo);
+        return NULL;
+    }
+    fifo->cond_change = SDL_CreateCond();
+    if (fifo->cond_change == NULL) {
+        SDL_DestroyMutex(fifo->lock);
+        free(fifo);
+        return NULL;
+    }
+
+    fifo->entries = calloc(capacity, sizeof(void*));
+    if (fifo->entries == NULL) {
+        dp_fifo_destroy(fifo);
+        return NULL;
+    }
+
+    return fifo;
+}
+
+// Destroy FIFO
+void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo)
+{
+    assert(fifo->count == 0);
+    SDL_DestroyMutex(fifo->lock);
+    SDL_DestroyCond(fifo->cond_change);
+    free(fifo->entries);
+    free(fifo);
+}
+
+// Push to FIFO
+void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element)
+{
+    SDL_LockMutex(fifo->lock);
+    while (fifo->count == fifo->capacity) {
+        fifo->push_wait = 1;
+        SDL_CondWait(fifo->cond_change, fifo->lock);
+        fifo->push_wait = 0;
+        if (fifo->flush) {
+            SDL_CondSignal(fifo->cond_change);
+            SDL_UnlockMutex(fifo->lock);
+            return;
+        }
+    }
+    fifo->entries[fifo->count++] = element;
+    if (fifo->count == 1)
+        SDL_CondSignal(fifo->cond_change);
+    SDL_UnlockMutex(fifo->lock);
+}
+
+// Helper that shifts the FIFO array
+static void *dp_fifo_array_shift(void **arr, size_t len)
+{
+    void *shifted_element = arr[0];
+    for (size_t i = 1; i < len; ++i)
+        arr[i-1] = arr[i];
+    return shifted_element;
+}
+
+// Get item from FIFO
+void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo)
+{
+    SDL_LockMutex(fifo->lock);
+    while (fifo->count == 0)
+        SDL_CondWait(fifo->cond_change, fifo->lock);
+    void *res = dp_fifo_array_shift(fifo->entries, fifo->count--);
+    if (fifo->count == fifo->capacity - 1)
+        SDL_CondSignal(fifo->cond_change);
+    SDL_UnlockMutex(fifo->lock);
+    return res;
+}
+
+void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *))
+{
+    SDL_LockMutex(fifo->lock);
+    fifo->flush = 1;
+    if (fifo->push_wait) {
+        SDL_CondSignal(fifo->cond_change);
+        SDL_CondWait(fifo->cond_change, fifo->lock);
+    }
+    while (fifo->count)
+        destroy_elem(fifo->entries[--fifo->count]);
+    fifo->flush = 0;
+    SDL_UnlockMutex(fifo->lock);
+}
diff --git a/media/libdav1d/src/examples/dp_fifo.h b/media/libdav1d/src/examples/dp_fifo.h
new file mode 100644
index 0000000000..03d8e47933
--- /dev/null
+++ b/media/libdav1d/src/examples/dp_fifo.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Dav1dPlay FIFO helper
+ */
+
+typedef struct dp_fifo Dav1dPlayPtrFifo;
+
+/* Create a FIFO
+ *
+ * Creates a FIFO with the given capacity.
+ * If the capacity is reached, new inserts into the FIFO
+ * will block until enough space is available again.
+ */
+Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity);
+
+/* Destroy a FIFO
+ *
+ * The FIFO must be empty before it is destroyed!
+ */
+void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo);
+
+/* Shift FIFO
+ *
+ * Return the first item from the FIFO, thereby removing it from
+ * the FIFO and making room for new entries.
+ */
+void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo);
+
+/* Push to FIFO
+ *
+ * Add an item to the end of the FIFO.
+ * If the FIFO is full, this call will block until there is again enough
+ * space in the FIFO, so calling this from the "consumer" thread if no
+ * other thread will call dp_fifo_shift will lead to a deadlock.
+ */
+void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element);
+
+void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *));
diff --git a/media/libdav1d/src/examples/dp_renderer.h b/media/libdav1d/src/examples/dp_renderer.h
new file mode 100644
index 0000000000..24cd19300d
--- /dev/null
+++ b/media/libdav1d/src/examples/dp_renderer.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2020, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include 
+#include 
+
+#include "dav1d/dav1d.h"
+
+#include 
+#if HAVE_PLACEBO
+# include 
+#endif
+
+// Check libplacebo Vulkan rendering
+#if HAVE_VULKAN && defined(SDL_VIDEO_VULKAN)
+# if defined(PL_HAVE_VULKAN) && PL_HAVE_VULKAN
+#  define HAVE_RENDERER_PLACEBO 1
+#  define HAVE_PLACEBO_VULKAN 1
+# endif
+#endif
+
+// Check libplacebo OpenGL rendering
+#if defined(PL_HAVE_OPENGL) && PL_HAVE_OPENGL
+# define HAVE_RENDERER_PLACEBO 1
+# define HAVE_PLACEBO_OPENGL 1
+#endif
+
+#ifndef HAVE_RENDERER_PLACEBO
+#define HAVE_RENDERER_PLACEBO 0
+#endif
+#ifndef HAVE_PLACEBO_VULKAN
+#define HAVE_PLACEBO_VULKAN 0
+#endif
+#ifndef HAVE_PLACEBO_OPENGL
+#define HAVE_PLACEBO_OPENGL 0
+#endif
+
+/**
+ * Settings structure
+ * Hold all settings available for the player,
+ * this is usually filled by parsing arguments
+ * from the console.
+ */
+typedef struct {
+    const char *inputfile;
+    const char *renderer_name;
+    int highquality;
+    int untimed;
+    int zerocopy;
+    int gpugrain;
+    int fullscreen;
+} Dav1dPlaySettings;
+
+#define WINDOW_WIDTH  910
+#define WINDOW_HEIGHT 512
+
+enum {
+    DAV1D_EVENT_NEW_FRAME,
+    DAV1D_EVENT_SEEK_FRAME,
+    DAV1D_EVENT_DEC_QUIT
+};
+
+/**
+ * Renderer info
+ */
+typedef struct rdr_info
+{
+    // Renderer name
+    const char *name;
+    // Cookie passed to the renderer implementation callbacks
+    void *cookie;
+    // Callback to create the renderer
+    void* (*create_renderer)(const Dav1dPlaySettings *settings);
+    // Callback to destroy the renderer
+    void (*destroy_renderer)(void *cookie);
+    // Callback to the render function that renders a prevously sent frame
+    void (*render)(void *cookie, const Dav1dPlaySettings *settings);
+    // Callback to the send frame function, _may_ also unref dav1d_pic!
+    int (*update_frame)(void *cookie, Dav1dPicture *dav1d_pic,
+                        const Dav1dPlaySettings *settings);
+    // Callback for alloc/release pictures (optional)
+    int (*alloc_pic)(Dav1dPicture *pic, void *cookie);
+    void (*release_pic)(Dav1dPicture *pic, void *cookie);
+    // Whether or not this renderer can apply on-GPU film grain synthesis
+    int supports_gpu_grain;
+} Dav1dPlayRenderInfo;
+
+extern const Dav1dPlayRenderInfo rdr_placebo_vk;
+extern const Dav1dPlayRenderInfo rdr_placebo_gl;
+extern const Dav1dPlayRenderInfo rdr_sdl;
+
+// Available renderes ordered by priority
+static const Dav1dPlayRenderInfo* const dp_renderers[] = {
+    &rdr_placebo_vk,
+    &rdr_placebo_gl,
+    &rdr_sdl,
+};
+
+static inline const Dav1dPlayRenderInfo *dp_get_renderer(const char *name)
+{
+    for (size_t i = 0; i < (sizeof(dp_renderers)/sizeof(*dp_renderers)); ++i)
+    {
+        if (dp_renderers[i]->name == NULL)
+            continue;
+
+        if (name == NULL || strcmp(name, dp_renderers[i]->name) == 0) {
+            return dp_renderers[i];
+        }
+    }
+    return NULL;
+}
+
+static inline SDL_Window *dp_create_sdl_window(int window_flags)
+{
+    SDL_Window *win;
+    window_flags |= SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
+
+    win = SDL_CreateWindow("Dav1dPlay", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+        WINDOW_WIDTH, WINDOW_HEIGHT, window_flags);
+    if (!win)
+        return NULL;
+
+    SDL_SetWindowResizable(win, SDL_TRUE);
+
+    return win;
+}
diff --git a/media/libdav1d/src/examples/dp_renderer_placebo.c b/media/libdav1d/src/examples/dp_renderer_placebo.c
new file mode 100644
index 0000000000..603ab48d11
--- /dev/null
+++ b/media/libdav1d/src/examples/dp_renderer_placebo.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright © 2020, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dp_renderer.h"
+
+#if HAVE_RENDERER_PLACEBO
+#include 
+
+#include 
+#include 
+
+#if HAVE_PLACEBO_VULKAN
+# include 
+# include 
+#endif
+#if HAVE_PLACEBO_OPENGL
+# include 
+# include 
+#endif
+
+
+/**
+ * Renderer context for libplacebo
+ */
+typedef struct renderer_priv_ctx
+{
+    // SDL window
+    SDL_Window *win;
+    // Placebo log
+    pl_log log;
+    // Placebo renderer
+    pl_renderer renderer;
+#if HAVE_PLACEBO_VULKAN
+    // Placebo Vulkan handle
+    pl_vulkan vk;
+    // Placebo Vulkan instance
+    pl_vk_inst vk_inst;
+    // Vulkan surface
+    VkSurfaceKHR surf;
+#endif
+#if HAVE_PLACEBO_OPENGL
+    // Placebo OpenGL handle
+    pl_opengl gl;
+    // SDL OpenGL context
+    SDL_GLContext gl_context;
+#endif
+    // Placebo GPU
+    pl_gpu gpu;
+    // Placebo swapchain
+    pl_swapchain swapchain;
+    // Lock protecting access to the texture
+    SDL_mutex *lock;
+    // Image to render, and planes backing them
+    struct pl_frame image;
+    pl_tex plane_tex[3];
+} Dav1dPlayRendererPrivateContext;
+
+static Dav1dPlayRendererPrivateContext*
+    placebo_renderer_create_common(const Dav1dPlaySettings *settings, int window_flags)
+{
+    if (settings->fullscreen)
+        window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
+
+    // Create Window
+    SDL_Window *sdlwin = dp_create_sdl_window(window_flags | SDL_WINDOW_RESIZABLE);
+    if (sdlwin == NULL) {
+        fprintf(stderr, "Creating SDL window failed: %s\n", SDL_GetError());
+        return NULL;
+    }
+
+    SDL_ShowCursor(0);
+
+    // Alloc
+    Dav1dPlayRendererPrivateContext *const rd_priv_ctx =
+        calloc(1, sizeof(Dav1dPlayRendererPrivateContext));
+    if (rd_priv_ctx == NULL) {
+        fprintf(stderr, "Out of memory!\n");
+        return NULL;
+    }
+    rd_priv_ctx->win = sdlwin;
+
+    // Init libplacebo
+    rd_priv_ctx->log = pl_log_create(PL_API_VER, pl_log_params(
+        .log_cb     = pl_log_color,
+#ifndef NDEBUG
+        .log_level  = PL_LOG_DEBUG,
+#else
+        .log_level  = PL_LOG_WARN,
+#endif
+    ));
+    if (rd_priv_ctx->log == NULL) {
+        fprintf(stderr, "pl_log_create failed!\n");
+        free(rd_priv_ctx);
+        return NULL;
+    }
+
+    // Create Mutex
+    rd_priv_ctx->lock = SDL_CreateMutex();
+    if (rd_priv_ctx->lock == NULL) {
+        fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
+        pl_log_destroy(&rd_priv_ctx->log);
+        free(rd_priv_ctx);
+        return NULL;
+    }
+
+    return rd_priv_ctx;
+}
+
+#if HAVE_PLACEBO_OPENGL
+static void *placebo_renderer_create_gl(const Dav1dPlaySettings *settings)
+{
+    SDL_Window *sdlwin = NULL;
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+
+    // Common init
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx =
+        placebo_renderer_create_common(settings, SDL_WINDOW_OPENGL);
+
+    if (rd_priv_ctx == NULL)
+        return NULL;
+    sdlwin = rd_priv_ctx->win;
+
+    rd_priv_ctx->gl_context = SDL_GL_CreateContext(sdlwin);
+    if (!rd_priv_ctx->gl_context) {
+        fprintf(stderr, "Failed creating opengl context: %s\n", SDL_GetError());
+        exit(2);
+    }
+    SDL_GL_MakeCurrent(sdlwin, rd_priv_ctx->gl_context);
+
+    rd_priv_ctx->gl = pl_opengl_create(rd_priv_ctx->log, pl_opengl_params(
+        .allow_software = true,
+#ifndef NDEBUG
+        .debug = true,
+#endif
+    ));
+    if (!rd_priv_ctx->gl) {
+        fprintf(stderr, "Failed creating opengl device!\n");
+        exit(2);
+    }
+
+    rd_priv_ctx->swapchain = pl_opengl_create_swapchain(rd_priv_ctx->gl,
+        pl_opengl_swapchain_params(
+            .swap_buffers = (void (*)(void *)) SDL_GL_SwapWindow,
+            .priv = sdlwin,
+        ));
+
+    if (!rd_priv_ctx->swapchain) {
+        fprintf(stderr, "Failed creating opengl swapchain!\n");
+        exit(2);
+    }
+
+    int w = WINDOW_WIDTH, h = WINDOW_HEIGHT;
+    SDL_GL_GetDrawableSize(sdlwin, &w, &h);
+
+    if (!pl_swapchain_resize(rd_priv_ctx->swapchain, &w, &h)) {
+        fprintf(stderr, "Failed resizing vulkan swapchain!\n");
+        exit(2);
+    }
+
+    rd_priv_ctx->gpu = rd_priv_ctx->gl->gpu;
+
+    if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
+        printf("Note: window dimensions differ (got %dx%d)\n", w, h);
+
+    return rd_priv_ctx;
+}
+#endif
+
+#if HAVE_PLACEBO_VULKAN
+static void *placebo_renderer_create_vk(const Dav1dPlaySettings *settings)
+{
+    SDL_Window *sdlwin = NULL;
+
+    // Common init
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx =
+        placebo_renderer_create_common(settings, SDL_WINDOW_VULKAN);
+
+    if (rd_priv_ctx == NULL)
+        return NULL;
+    sdlwin = rd_priv_ctx->win;
+
+    // Init Vulkan
+    unsigned num = 0;
+    if (!SDL_Vulkan_GetInstanceExtensions(sdlwin, &num, NULL)) {
+        fprintf(stderr, "Failed enumerating Vulkan extensions: %s\n", SDL_GetError());
+        exit(1);
+    }
+
+    const char **extensions = malloc(num * sizeof(const char *));
+    assert(extensions);
+
+    SDL_bool ok = SDL_Vulkan_GetInstanceExtensions(sdlwin, &num, extensions);
+    if (!ok) {
+        fprintf(stderr, "Failed getting Vk instance extensions\n");
+        exit(1);
+    }
+
+    if (num > 0) {
+        printf("Requesting %d additional Vulkan extensions:\n", num);
+        for (unsigned i = 0; i < num; i++)
+            printf("    %s\n", extensions[i]);
+    }
+
+    rd_priv_ctx->vk_inst = pl_vk_inst_create(rd_priv_ctx->log, pl_vk_inst_params(
+        .extensions = extensions,
+        .num_extensions = num,
+    ));
+    if (!rd_priv_ctx->vk_inst) {
+        fprintf(stderr, "Failed creating Vulkan instance!\n");
+        exit(1);
+    }
+    free(extensions);
+
+    if (!SDL_Vulkan_CreateSurface(sdlwin, rd_priv_ctx->vk_inst->instance, &rd_priv_ctx->surf)) {
+        fprintf(stderr, "Failed creating vulkan surface: %s\n", SDL_GetError());
+        exit(1);
+    }
+
+    rd_priv_ctx->vk = pl_vulkan_create(rd_priv_ctx->log, pl_vulkan_params(
+        .instance = rd_priv_ctx->vk_inst->instance,
+        .surface = rd_priv_ctx->surf,
+        .allow_software = true,
+    ));
+    if (!rd_priv_ctx->vk) {
+        fprintf(stderr, "Failed creating vulkan device!\n");
+        exit(2);
+    }
+
+    // Create swapchain
+    rd_priv_ctx->swapchain = pl_vulkan_create_swapchain(rd_priv_ctx->vk,
+        pl_vulkan_swapchain_params(
+            .surface = rd_priv_ctx->surf,
+            .present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR,
+        ));
+
+    if (!rd_priv_ctx->swapchain) {
+        fprintf(stderr, "Failed creating vulkan swapchain!\n");
+        exit(2);
+    }
+
+    int w = WINDOW_WIDTH, h = WINDOW_HEIGHT;
+    if (!pl_swapchain_resize(rd_priv_ctx->swapchain, &w, &h)) {
+        fprintf(stderr, "Failed resizing vulkan swapchain!\n");
+        exit(2);
+    }
+
+    rd_priv_ctx->gpu = rd_priv_ctx->vk->gpu;
+
+    if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
+        printf("Note: window dimensions differ (got %dx%d)\n", w, h);
+
+    return rd_priv_ctx;
+}
+#endif
+
+static void placebo_renderer_destroy(void *cookie)
+{
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
+    assert(rd_priv_ctx != NULL);
+
+    pl_renderer_destroy(&(rd_priv_ctx->renderer));
+    pl_swapchain_destroy(&(rd_priv_ctx->swapchain));
+    for (int i = 0; i < 3; i++)
+        pl_tex_destroy(rd_priv_ctx->gpu, &(rd_priv_ctx->plane_tex[i]));
+
+#if HAVE_PLACEBO_VULKAN
+    if (rd_priv_ctx->vk) {
+        pl_vulkan_destroy(&(rd_priv_ctx->vk));
+        vkDestroySurfaceKHR(rd_priv_ctx->vk_inst->instance, rd_priv_ctx->surf, NULL);
+        pl_vk_inst_destroy(&(rd_priv_ctx->vk_inst));
+    }
+#endif
+#if HAVE_PLACEBO_OPENGL
+    if (rd_priv_ctx->gl)
+        pl_opengl_destroy(&(rd_priv_ctx->gl));
+    if (rd_priv_ctx->gl_context)
+        SDL_GL_DeleteContext(rd_priv_ctx->gl_context);
+#endif
+
+    SDL_DestroyWindow(rd_priv_ctx->win);
+
+    pl_log_destroy(&rd_priv_ctx->log);
+}
+
+static void placebo_render(void *cookie, const Dav1dPlaySettings *settings)
+{
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
+    assert(rd_priv_ctx != NULL);
+
+    SDL_LockMutex(rd_priv_ctx->lock);
+    if (!rd_priv_ctx->image.num_planes) {
+        SDL_UnlockMutex(rd_priv_ctx->lock);
+        return;
+    }
+
+    // Prepare rendering
+    if (rd_priv_ctx->renderer == NULL) {
+        rd_priv_ctx->renderer = pl_renderer_create(rd_priv_ctx->log, rd_priv_ctx->gpu);
+    }
+
+    struct pl_swapchain_frame frame;
+    bool ok = pl_swapchain_start_frame(rd_priv_ctx->swapchain, &frame);
+    if (!ok) {
+        SDL_UnlockMutex(rd_priv_ctx->lock);
+        return;
+    }
+
+    struct pl_frame target;
+    pl_frame_from_swapchain(&target, &frame);
+    pl_rect2df_aspect_copy(&target.crop, &rd_priv_ctx->image.crop, 0.0);
+    if (pl_frame_is_cropped(&target))
+        pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 0.0 });
+
+    if (!pl_render_image(rd_priv_ctx->renderer, &rd_priv_ctx->image, &target,
+                         settings->highquality ? &pl_render_default_params
+                                               : &pl_render_fast_params))
+    {
+        fprintf(stderr, "Failed rendering frame!\n");
+        pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 1.0 });
+    }
+
+    ok = pl_swapchain_submit_frame(rd_priv_ctx->swapchain);
+    if (!ok) {
+        fprintf(stderr, "Failed submitting frame!\n");
+        SDL_UnlockMutex(rd_priv_ctx->lock);
+        return;
+    }
+
+    pl_swapchain_swap_buffers(rd_priv_ctx->swapchain);
+    SDL_UnlockMutex(rd_priv_ctx->lock);
+}
+
+static int placebo_upload_image(void *cookie, Dav1dPicture *dav1d_pic,
+                                const Dav1dPlaySettings *settings)
+{
+    Dav1dPlayRendererPrivateContext *p = cookie;
+    assert(p != NULL);
+    int ret = 0;
+
+    if (!dav1d_pic)
+        return ret;
+
+    SDL_LockMutex(p->lock);
+    if (!pl_upload_dav1dpicture(p->gpu, &p->image, p->plane_tex, pl_dav1d_upload_params(
+        .picture = dav1d_pic,
+        .film_grain = settings->gpugrain,
+        .gpu_allocated = settings->zerocopy,
+        .asynchronous = true,
+    )))
+    {
+        fprintf(stderr, "Failed uploading planes!\n");
+        p->image = (struct pl_frame) {0};
+        ret = -1;
+    }
+    SDL_UnlockMutex(p->lock);
+    return ret;
+}
+
+static int placebo_alloc_pic(Dav1dPicture *const pic, void *cookie)
+{
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
+    assert(rd_priv_ctx != NULL);
+
+    SDL_LockMutex(rd_priv_ctx->lock);
+    int ret = pl_allocate_dav1dpicture(pic, (void *) rd_priv_ctx->gpu);
+    SDL_UnlockMutex(rd_priv_ctx->lock);
+    return ret;
+}
+
+static void placebo_release_pic(Dav1dPicture *pic, void *cookie)
+{
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
+    assert(rd_priv_ctx != NULL);
+
+    SDL_LockMutex(rd_priv_ctx->lock);
+    pl_release_dav1dpicture(pic, (void *) rd_priv_ctx->gpu);
+    SDL_UnlockMutex(rd_priv_ctx->lock);
+}
+
+#if HAVE_PLACEBO_VULKAN
+const Dav1dPlayRenderInfo rdr_placebo_vk = {
+    .name = "placebo-vk",
+    .create_renderer = placebo_renderer_create_vk,
+    .destroy_renderer = placebo_renderer_destroy,
+    .render = placebo_render,
+    .update_frame = placebo_upload_image,
+    .alloc_pic = placebo_alloc_pic,
+    .release_pic = placebo_release_pic,
+    .supports_gpu_grain = 1,
+};
+#else
+const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL };
+#endif
+
+#if HAVE_PLACEBO_OPENGL
+const Dav1dPlayRenderInfo rdr_placebo_gl = {
+    .name = "placebo-gl",
+    .create_renderer = placebo_renderer_create_gl,
+    .destroy_renderer = placebo_renderer_destroy,
+    .render = placebo_render,
+    .update_frame = placebo_upload_image,
+    .supports_gpu_grain = 1,
+};
+#else
+const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL };
+#endif
+
+#else
+const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL };
+const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL };
+#endif
diff --git a/media/libdav1d/src/examples/dp_renderer_sdl.c b/media/libdav1d/src/examples/dp_renderer_sdl.c
new file mode 100644
index 0000000000..773c48978f
--- /dev/null
+++ b/media/libdav1d/src/examples/dp_renderer_sdl.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright © 2020, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dp_renderer.h"
+
+#include 
+
+/**
+ * Renderer context for SDL
+ */
+typedef struct renderer_priv_ctx
+{
+    // SDL window
+    SDL_Window *win;
+    // SDL renderer
+    SDL_Renderer *renderer;
+    // Lock protecting access to the texture
+    SDL_mutex *lock;
+    // Texture to render
+    SDL_Texture *tex;
+} Dav1dPlayRendererPrivateContext;
+
+static void *sdl_renderer_create(const Dav1dPlaySettings *settings)
+{
+    int window_flags = 0;
+    if (settings->fullscreen)
+        window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
+
+    SDL_Window *win = dp_create_sdl_window(window_flags);
+    if (win == NULL) {
+        fprintf(stderr, "Creating SDL window failed: %s\n", SDL_GetError());
+        return NULL;
+    }
+    SDL_ShowCursor(0);
+
+    // Alloc
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx = malloc(sizeof(Dav1dPlayRendererPrivateContext));
+    if (rd_priv_ctx == NULL) {
+        fprintf(stderr, "Out of memory!\n");
+        return NULL;
+    }
+    rd_priv_ctx->win = win;
+
+    // Create renderer
+    rd_priv_ctx->renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
+    // Set scale quality
+    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
+
+    // Create Mutex
+    rd_priv_ctx->lock = SDL_CreateMutex();
+    if (rd_priv_ctx->lock == NULL) {
+        fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
+        free(rd_priv_ctx);
+        return NULL;
+    }
+
+    rd_priv_ctx->tex = NULL;
+
+    return rd_priv_ctx;
+}
+
+static void sdl_renderer_destroy(void *cookie)
+{
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
+    assert(rd_priv_ctx != NULL);
+
+    SDL_DestroyTexture(rd_priv_ctx->tex);
+    SDL_DestroyRenderer(rd_priv_ctx->renderer);
+    SDL_DestroyWindow(rd_priv_ctx->win);
+    SDL_DestroyMutex(rd_priv_ctx->lock);
+    free(rd_priv_ctx);
+}
+
+static void sdl_render(void *cookie, const Dav1dPlaySettings *settings)
+{
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
+    assert(rd_priv_ctx != NULL);
+
+    SDL_LockMutex(rd_priv_ctx->lock);
+
+    if (rd_priv_ctx->tex == NULL) {
+        SDL_UnlockMutex(rd_priv_ctx->lock);
+        return;
+    }
+
+    // Display the frame
+    SDL_RenderClear(rd_priv_ctx->renderer);
+    SDL_RenderCopy(rd_priv_ctx->renderer, rd_priv_ctx->tex, NULL, NULL);
+    SDL_RenderPresent(rd_priv_ctx->renderer);
+
+    SDL_UnlockMutex(rd_priv_ctx->lock);
+}
+
+static int sdl_update_texture(void *cookie, Dav1dPicture *dav1d_pic,
+                              const Dav1dPlaySettings *settings)
+{
+    Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
+    assert(rd_priv_ctx != NULL);
+
+    SDL_LockMutex(rd_priv_ctx->lock);
+
+    if (dav1d_pic == NULL) {
+        rd_priv_ctx->tex = NULL;
+        SDL_UnlockMutex(rd_priv_ctx->lock);
+        return 0;
+    }
+
+    int width = dav1d_pic->p.w;
+    int height = dav1d_pic->p.h;
+    int tex_w = width;
+    int tex_h = height;
+
+    enum Dav1dPixelLayout dav1d_layout = dav1d_pic->p.layout;
+
+    if (DAV1D_PIXEL_LAYOUT_I420 != dav1d_layout || dav1d_pic->p.bpc != 8) {
+        fprintf(stderr, "Unsupported pixel format, only 8bit 420 supported so far.\n");
+        exit(50);
+    }
+
+    SDL_Texture *texture = rd_priv_ctx->tex;
+    if (texture != NULL) {
+        SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h);
+        if (tex_w != width || tex_h != height) {
+            SDL_DestroyTexture(texture);
+            texture = NULL;
+        }
+    }
+
+    if (texture == NULL) {
+        texture = SDL_CreateTexture(rd_priv_ctx->renderer, SDL_PIXELFORMAT_IYUV,
+            SDL_TEXTUREACCESS_STREAMING, width, height);
+        SDL_RenderSetLogicalSize(rd_priv_ctx->renderer, width, height);
+    }
+
+    SDL_UpdateYUVTexture(texture, NULL,
+        dav1d_pic->data[0], (int)dav1d_pic->stride[0], // Y
+        dav1d_pic->data[1], (int)dav1d_pic->stride[1], // U
+        dav1d_pic->data[2], (int)dav1d_pic->stride[1]  // V
+        );
+
+    rd_priv_ctx->tex = texture;
+    SDL_UnlockMutex(rd_priv_ctx->lock);
+    return 0;
+}
+
+const Dav1dPlayRenderInfo rdr_sdl = {
+    .name = "sdl",
+    .create_renderer = sdl_renderer_create,
+    .destroy_renderer = sdl_renderer_destroy,
+    .render = sdl_render,
+    .update_frame = sdl_update_texture
+};
diff --git a/media/libdav1d/src/examples/meson.build b/media/libdav1d/src/examples/meson.build
new file mode 100644
index 0000000000..adbf85b784
--- /dev/null
+++ b/media/libdav1d/src/examples/meson.build
@@ -0,0 +1,78 @@
+# Copyright © 2018, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Build definition for the dav1d examples
+#
+
+# Leave subdir if examples are disabled
+if not get_option('enable_examples')
+    subdir_done()
+endif
+
+
+# dav1d player sources
+dav1dplay_sources = files(
+    'dav1dplay.c',
+    'dp_fifo.c',
+    'dp_renderer_placebo.c',
+    'dp_renderer_sdl.c',
+)
+
+sdl2_dependency = dependency('sdl2', version: '>= 2.0.1', required: true)
+
+if sdl2_dependency.found()
+    dav1dplay_deps = [sdl2_dependency, libm_dependency]
+    dav1dplay_cflags = []
+
+    placebo_dependency = dependency('libplacebo', version: '>= 4.160.0', required: false)
+
+    have_vulkan = false
+    have_placebo = placebo_dependency.found()
+    if have_placebo
+        dav1dplay_deps += placebo_dependency
+
+        # If libplacebo is found, we might be able to use Vulkan
+        # with it, in which case we need the Vulkan library too.
+        vulkan_dependency = dependency('vulkan', required: false)
+        if vulkan_dependency.found()
+            dav1dplay_deps += vulkan_dependency
+            have_vulkan = true
+        endif
+    endif
+
+    dav1dplay_cflags += '-DHAVE_PLACEBO=' + (have_placebo ? '1' : '0')
+    dav1dplay_cflags += '-DHAVE_VULKAN=' + (have_vulkan ? '1' : '0')
+
+    dav1dplay = executable('dav1dplay',
+        dav1dplay_sources,
+        rev_target,
+
+        link_with : [libdav1d, dav1d_input_objs],
+        include_directories : [dav1d_inc_dirs],
+        dependencies : [getopt_dependency, dav1dplay_deps],
+        install : true,
+        c_args : dav1dplay_cflags,
+    )
+endif
diff --git a/media/libdav1d/src/gcovr.cfg b/media/libdav1d/src/gcovr.cfg
new file mode 100644
index 0000000000..e02ae33c33
--- /dev/null
+++ b/media/libdav1d/src/gcovr.cfg
@@ -0,0 +1,4 @@
+exclude = .*/tests/.*
+exclude = .*/tools/.*
+exclude = .*/include/common/dump.h
+gcov-ignore-parse-errors = negative_hits.warn
diff --git a/media/libdav1d/src/include/common/attributes.h b/media/libdav1d/src/include/common/attributes.h
new file mode 100644
index 0000000000..c6cecc7aca
--- /dev/null
+++ b/media/libdav1d/src/include/common/attributes.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_COMMON_ATTRIBUTES_H
+#define DAV1D_COMMON_ATTRIBUTES_H
+
+#include "config.h"
+
+#include 
+#include 
+
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#ifdef __GNUC__
+#define ATTR_ALIAS __attribute__((may_alias))
+#if defined(__MINGW32__) && !defined(__clang__)
+#define ATTR_FORMAT_PRINTF(fmt, attr) __attribute__((__format__(__gnu_printf__, fmt, attr)))
+#else
+#define ATTR_FORMAT_PRINTF(fmt, attr) __attribute__((__format__(__printf__, fmt, attr)))
+#endif
+#define COLD __attribute__((cold))
+#else
+#define ATTR_ALIAS
+#define ATTR_FORMAT_PRINTF(fmt, attr)
+#define COLD
+#endif
+
+#if ARCH_X86_64
+/* x86-64 needs 32- and 64-byte alignment for AVX2 and AVX-512. */
+#define ALIGN_64_VAL 64
+#define ALIGN_32_VAL 32
+#define ALIGN_16_VAL 16
+#elif ARCH_AARCH64 || ARCH_ARM || ARCH_LOONGARCH || ARCH_PPC64LE || ARCH_X86_32
+/* ARM doesn't benefit from anything more than 16-byte alignment. */
+#define ALIGN_64_VAL 16
+#define ALIGN_32_VAL 16
+#define ALIGN_16_VAL 16
+#else
+/* No need for extra alignment on platforms without assembly. */
+#define ALIGN_64_VAL 8
+#define ALIGN_32_VAL 8
+#define ALIGN_16_VAL 8
+#endif
+
+/*
+ * API for variables, struct members (ALIGN()) like:
+ * uint8_t var[1][2][3][4]
+ * becomes:
+ * ALIGN(uint8_t var[1][2][3][4], alignment).
+ */
+#ifdef _MSC_VER
+#define ALIGN(ll, a) \
+    __declspec(align(a)) ll
+#else
+#define ALIGN(line, align) \
+    line __attribute__((aligned(align)))
+#endif
+
+/*
+ * API for stack alignment (ALIGN_STK_$align()) of variables like:
+ * uint8_t var[1][2][3][4]
+ * becomes:
+ * ALIGN_STK_$align(uint8_t, var, 1, [2][3][4])
+ */
+#define ALIGN_STK_64(type, var, sz1d, sznd) \
+    ALIGN(type var[sz1d]sznd, ALIGN_64_VAL)
+#define ALIGN_STK_32(type, var, sz1d, sznd) \
+    ALIGN(type var[sz1d]sznd, ALIGN_32_VAL)
+#define ALIGN_STK_16(type, var, sz1d, sznd) \
+    ALIGN(type var[sz1d]sznd, ALIGN_16_VAL)
+
+/*
+ * Forbid inlining of a function:
+ * static NOINLINE void func() {}
+ */
+#ifdef _MSC_VER
+#define NOINLINE __declspec(noinline)
+#elif __has_attribute(noclone)
+#define NOINLINE __attribute__((noinline, noclone))
+#else
+#define NOINLINE __attribute__((noinline))
+#endif
+
+#ifdef _MSC_VER
+#define ALWAYS_INLINE __forceinline
+#else
+#define ALWAYS_INLINE __attribute__((always_inline)) inline
+#endif
+
+#if (defined(__ELF__) || defined(__MACH__) || (defined(_WIN32) && defined(__clang__))) && __has_attribute(visibility)
+#define EXTERN extern __attribute__((visibility("hidden")))
+#else
+#define EXTERN extern
+#endif
+
+#if ARCH_X86_64 && __has_attribute(model)
+#define ATTR_MCMODEL_SMALL __attribute__((model("small")))
+#else
+#define ATTR_MCMODEL_SMALL
+#endif
+
+#ifdef __clang__
+#define NO_SANITIZE(x) __attribute__((no_sanitize(x)))
+#else
+#define NO_SANITIZE(x)
+#endif
+
+#if defined(NDEBUG) && (defined(__GNUC__) || defined(__clang__))
+#undef assert
+#define assert(x) do { if (!(x)) __builtin_unreachable(); } while (0)
+#elif defined(NDEBUG) && defined(_MSC_VER)
+#undef assert
+#define assert __assume
+#endif
+
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+#    define dav1d_uninit(x) x=x
+#else
+#    define dav1d_uninit(x) x
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#include 
+
+static inline int ctz(const unsigned int mask) {
+    unsigned long idx;
+    _BitScanForward(&idx, mask);
+    return idx;
+}
+
+static inline int clz(const unsigned int mask) {
+    unsigned long leading_zero = 0;
+    _BitScanReverse(&leading_zero, mask);
+    return (31 - leading_zero);
+}
+
+#ifdef _WIN64
+static inline int clzll(const unsigned long long mask) {
+    unsigned long leading_zero = 0;
+    _BitScanReverse64(&leading_zero, mask);
+    return (63 - leading_zero);
+}
+#else /* _WIN64 */
+static inline int clzll(const unsigned long long mask) {
+    if (mask >> 32)
+        return clz((unsigned)(mask >> 32));
+    else
+        return clz((unsigned)mask) + 32;
+}
+#endif /* _WIN64 */
+#else /* !_MSC_VER */
+static inline int ctz(const unsigned int mask) {
+    return __builtin_ctz(mask);
+}
+
+static inline int clz(const unsigned int mask) {
+    return __builtin_clz(mask);
+}
+
+static inline int clzll(const unsigned long long mask) {
+    return __builtin_clzll(mask);
+}
+#endif /* !_MSC_VER */
+
+#ifndef static_assert
+#define CHECK_OFFSET(type, field, name) \
+    struct check_##type##_##field { int x[(name == offsetof(type, field)) ? 1 : -1]; }
+#define CHECK_SIZE(type, size) \
+    struct check_##type##_size { int x[(size == sizeof(type)) ? 1 : -1]; }
+#else
+#define CHECK_OFFSET(type, field, name) \
+    static_assert(name == offsetof(type, field), #field)
+#define CHECK_SIZE(type, size) \
+    static_assert(size == sizeof(type), #type)
+#endif
+
+#ifdef _MSC_VER
+#define PACKED(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
+#else
+#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
+#endif
+
+#endif /* DAV1D_COMMON_ATTRIBUTES_H */
diff --git a/media/libdav1d/src/include/common/bitdepth.h b/media/libdav1d/src/include/common/bitdepth.h
new file mode 100644
index 0000000000..8a8f5740b8
--- /dev/null
+++ b/media/libdav1d/src/include/common/bitdepth.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_COMMON_BITDEPTH_H
+#define DAV1D_COMMON_BITDEPTH_H
+
+#include 
+#include 
+
+#include "common/attributes.h"
+
+#if !defined(BITDEPTH)
+typedef uint8_t pixel; /* can't be void due to pointer-to-array usage */
+typedef void coef;
+#define HIGHBD_DECL_SUFFIX /* nothing */
+#define HIGHBD_CALL_SUFFIX /* nothing */
+#define HIGHBD_TAIL_SUFFIX /* nothing */
+#elif BITDEPTH == 8
+typedef uint8_t pixel;
+typedef int16_t coef;
+#define PIXEL_TYPE uint8_t
+#define COEF_TYPE int16_t
+#define pixel_copy memcpy
+#define pixel_set memset
+#define iclip_pixel iclip_u8
+#define PIX_HEX_FMT "%02x"
+#define bitfn(x) x##_8bpc
+#define BF(x, suffix) x##_8bpc_##suffix
+#define PXSTRIDE(x) (x)
+#define highbd_only(x)
+#define HIGHBD_DECL_SUFFIX /* nothing */
+#define HIGHBD_CALL_SUFFIX /* nothing */
+#define HIGHBD_TAIL_SUFFIX /* nothing */
+#define bitdepth_from_max(x) 8
+#define BITDEPTH_MAX 0xff
+#elif BITDEPTH == 16
+typedef uint16_t pixel;
+typedef int32_t coef;
+#define PIXEL_TYPE uint16_t
+#define COEF_TYPE int32_t
+#define pixel_copy(a, b, c) memcpy(a, b, (c) << 1)
+static inline void pixel_set(pixel *const dst, const int val, const int num) {
+    for (int n = 0; n < num; n++)
+        dst[n] = val;
+}
+#define PIX_HEX_FMT "%03x"
+#define iclip_pixel(x) iclip(x, 0, bitdepth_max)
+#define HIGHBD_DECL_SUFFIX , const int bitdepth_max
+#define HIGHBD_CALL_SUFFIX , f->bitdepth_max
+#define HIGHBD_TAIL_SUFFIX , bitdepth_max
+#define bitdepth_from_max(bitdepth_max) (32 - clz(bitdepth_max))
+#define BITDEPTH_MAX bitdepth_max
+#define bitfn(x) x##_16bpc
+#define BF(x, suffix) x##_16bpc_##suffix
+static inline ptrdiff_t PXSTRIDE(const ptrdiff_t x) {
+    assert(!(x & 1));
+    return x >> 1;
+}
+#define highbd_only(x) x
+#else
+#error invalid value for bitdepth
+#endif
+#define bytefn(x) bitfn(x)
+
+#define bitfn_decls(name, ...) \
+name##_8bpc(__VA_ARGS__); \
+name##_16bpc(__VA_ARGS__)
+
+#endif /* DAV1D_COMMON_BITDEPTH_H */
diff --git a/media/libdav1d/src/include/common/dump.h b/media/libdav1d/src/include/common/dump.h
new file mode 100644
index 0000000000..9ffab6a45e
--- /dev/null
+++ b/media/libdav1d/src/include/common/dump.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_COMMON_DUMP_H
+#define DAV1D_COMMON_DUMP_H
+
+#include 
+#include 
+#include 
+
+#include "common/bitdepth.h"
+
+static inline void append_plane_to_file(const pixel *buf, ptrdiff_t stride,
+                                        int w, int h, const char *const file)
+{
+    FILE *const f = fopen(file, "ab");
+    while (h--) {
+        fwrite(buf, w * sizeof(pixel), 1, f);
+        buf += PXSTRIDE(stride);
+    }
+    fclose(f);
+}
+
+static inline void hex_fdump(FILE *out, const pixel *buf, ptrdiff_t stride,
+                             int w, int h, const char *what)
+{
+    fprintf(out, "%s\n", what);
+    while (h--) {
+        int x;
+        for (x = 0; x < w; x++)
+            fprintf(out, " " PIX_HEX_FMT, buf[x]);
+        buf += PXSTRIDE(stride);
+        fprintf(out, "\n");
+    }
+}
+
+static inline void hex_dump(const pixel *buf, ptrdiff_t stride,
+                            int w, int h, const char *what)
+{
+    hex_fdump(stdout, buf, stride, w, h, what);
+}
+
+static inline void coef_dump(const coef *buf, const int w, const int h,
+                             const int len, const char *what)
+{
+    int y;
+    printf("%s\n", what);
+    for (y = 0; y < h; y++) {
+        int x;
+        for (x = 0; x < w; x++)
+            printf(" %*d", len, buf[x]);
+        buf += w;
+        printf("\n");
+    }
+}
+
+static inline void ac_dump(const int16_t *buf, int w, int h, const char *what)
+{
+    printf("%s\n", what);
+    while (h--) {
+        for (int x = 0; x < w; x++)
+            printf(" %03d", buf[x]);
+        buf += w;
+        printf("\n");
+    }
+}
+
+#endif /* DAV1D_COMMON_DUMP_H */
diff --git a/media/libdav1d/src/include/common/frame.h b/media/libdav1d/src/include/common/frame.h
new file mode 100644
index 0000000000..767f7fd06a
--- /dev/null
+++ b/media/libdav1d/src/include/common/frame.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_COMMON_FRAME_H
+#define DAV1D_COMMON_FRAME_H
+
+/*
+ * Checks whether Dav1dFrameType == INTER || == SWITCH
+ * Both are defined as odd numbers {1, 3} and therefore have the LSB set.
+ * See also: AV1 spec 6.8.2
+ */
+#define IS_INTER_OR_SWITCH(frame_header) \
+    ((frame_header)->frame_type & 1)
+
+/*
+ * Checks whether Dav1dFrameType == KEY || == INTRA
+ * See also: AV1 spec 6.8.2
+ */
+#define IS_KEY_OR_INTRA(frame_header) \
+    (!IS_INTER_OR_SWITCH(frame_header))
+
+#endif /* DAV1D_COMMON_FRAME_H */
diff --git a/media/libdav1d/src/include/common/intops.h b/media/libdav1d/src/include/common/intops.h
new file mode 100644
index 0000000000..089da5e15e
--- /dev/null
+++ b/media/libdav1d/src/include/common/intops.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_COMMON_INTOPS_H
+#define DAV1D_COMMON_INTOPS_H
+
+#include 
+
+#include "common/attributes.h"
+
+static inline int imax(const int a, const int b) {
+    return a > b ? a : b;
+}
+
+static inline int imin(const int a, const int b) {
+    return a < b ? a : b;
+}
+
+static inline unsigned umax(const unsigned a, const unsigned b) {
+    return a > b ? a : b;
+}
+
+static inline unsigned umin(const unsigned a, const unsigned b) {
+    return a < b ? a : b;
+}
+
+static inline int iclip(const int v, const int min, const int max) {
+    return v < min ? min : v > max ? max : v;
+}
+
+static inline int iclip_u8(const int v) {
+    return iclip(v, 0, 255);
+}
+
+static inline int apply_sign(const int v, const int s) {
+    return s < 0 ? -v : v;
+}
+
+static inline int apply_sign64(const int v, const int64_t s) {
+    return s < 0 ? -v : v;
+}
+
+static inline int ulog2(const unsigned v) {
+    return 31 ^ clz(v);
+}
+
+static inline int u64log2(const uint64_t v) {
+    return 63 ^ clzll(v);
+}
+
+static inline unsigned inv_recenter(const unsigned r, const unsigned v) {
+    if (v > (r << 1))
+        return v;
+    else if ((v & 1) == 0)
+        return (v >> 1) + r;
+    else
+        return r - ((v + 1) >> 1);
+}
+
+#endif /* DAV1D_COMMON_INTOPS_H */
diff --git a/media/libdav1d/src/include/common/validate.h b/media/libdav1d/src/include/common/validate.h
new file mode 100644
index 0000000000..3aaed5bb92
--- /dev/null
+++ b/media/libdav1d/src/include/common/validate.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_COMMON_VALIDATE_H
+#define DAV1D_COMMON_VALIDATE_H
+
+#include 
+#include 
+
+#if defined(NDEBUG)
+#define debug_print(...) do {} while (0)
+#define debug_abort() do {} while (0)
+#else
+#define debug_print(...) fprintf(stderr, __VA_ARGS__)
+#define debug_abort abort
+#endif
+
+#define validate_input_or_ret_with_msg(x, r, ...) \
+    if (!(x)) { \
+        debug_print("Input validation check \'%s\' failed in %s!\n", \
+                    #x, __func__); \
+        debug_print(__VA_ARGS__); \
+        debug_abort(); \
+        return r; \
+    }
+
+#define validate_input_or_ret(x, r) \
+    if (!(x)) { \
+        debug_print("Input validation check \'%s\' failed in %s!\n", \
+                    #x, __func__); \
+        debug_abort(); \
+        return r; \
+    }
+
+#define validate_input(x) validate_input_or_ret(x, )
+
+#endif /* DAV1D_COMMON_VALIDATE_H */
diff --git a/media/libdav1d/src/include/compat/gcc/stdatomic.h b/media/libdav1d/src/include/compat/gcc/stdatomic.h
new file mode 100644
index 0000000000..29f906321f
--- /dev/null
+++ b/media/libdav1d/src/include/compat/gcc/stdatomic.h
@@ -0,0 +1,51 @@
+/*
+* Copyright © 2018, VideoLAN and dav1d authors
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice, this
+*    list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+*    this list of conditions and the following disclaimer in the documentation
+*    and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef GCCVER_STDATOMIC_H_
+#define GCCVER_STDATOMIC_H_
+
+#if !defined(__cplusplus)
+
+typedef int atomic_int;
+typedef unsigned int atomic_uint;
+
+#define memory_order_relaxed __ATOMIC_RELAXED
+#define memory_order_acquire __ATOMIC_ACQUIRE
+
+#define atomic_init(p_a, v)           do { *(p_a) = (v); } while(0)
+#define atomic_store(p_a, v)          __atomic_store_n(p_a, v, __ATOMIC_SEQ_CST)
+#define atomic_load(p_a)              __atomic_load_n(p_a, __ATOMIC_SEQ_CST)
+#define atomic_load_explicit(p_a, mo) __atomic_load_n(p_a, mo)
+#define atomic_fetch_add(p_a, inc)    __atomic_fetch_add(p_a, inc, __ATOMIC_SEQ_CST)
+#define atomic_fetch_add_explicit(p_a, inc, mo) __atomic_fetch_add(p_a, inc, mo)
+#define atomic_fetch_sub(p_a, dec)    __atomic_fetch_sub(p_a, dec, __ATOMIC_SEQ_CST)
+#define atomic_exchange(p_a, v)       __atomic_exchange_n(p_a, v, __ATOMIC_SEQ_CST)
+#define atomic_fetch_or(p_a, v)       __atomic_fetch_or(p_a, v, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_strong(p_a, expected, desired) __atomic_compare_exchange_n(p_a, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+
+#endif /* !defined(__cplusplus) */
+
+#endif /* GCCVER_STDATOMIC_H_ */
diff --git a/media/libdav1d/src/include/compat/getopt.h b/media/libdav1d/src/include/compat/getopt.h
new file mode 100644
index 0000000000..ad597691ef
--- /dev/null
+++ b/media/libdav1d/src/include/compat/getopt.h
@@ -0,0 +1,97 @@
+#ifndef __GETOPT_H__
+/**
+ * DISCLAIMER
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ *
+ * The mingw-w64 runtime package and its code is distributed in the hope that it 
+ * will be useful but WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESSED OR 
+ * IMPLIED ARE HEREBY DISCLAIMED.  This includes but is not limited to 
+ * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define __GETOPT_H__
+
+/* All the headers include this file. */
+#ifdef _WIN32
+#include 
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int optind;		/* index of first non-option in argv      */
+extern int optopt;		/* single option character, as parsed     */
+extern int opterr;		/* flag to enable built-in diagnostics... */
+				/* (user may set to zero, to suppress)    */
+
+extern char *optarg;		/* pointer to argument of current option  */
+
+extern int getopt(int nargc, char * const *nargv, const char *options);
+
+#ifdef _BSD_SOURCE
+/*
+ * BSD adds the non-standard `optreset' feature, for reinitialisation
+ * of `getopt' parsing.  We support this feature, for applications which
+ * proclaim their BSD heritage, before including this header; however,
+ * to maintain portability, developers are advised to avoid it.
+ */
+# define optreset  __mingw_optreset
+extern int optreset;
+#endif
+#ifdef __cplusplus
+}
+#endif
+/*
+ * POSIX requires the `getopt' API to be specified in `unistd.h';
+ * thus, `unistd.h' includes this header.  However, we do not want
+ * to expose the `getopt_long' or `getopt_long_only' APIs, when
+ * included in this manner.  Thus, close the standard __GETOPT_H__
+ * declarations block, and open an additional __GETOPT_LONG_H__
+ * specific block, only when *not* __UNISTD_H_SOURCED__, in which
+ * to declare the extended API.
+ */
+#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
+#define __GETOPT_LONG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct option		/* specification for a long form option...	*/
+{
+  const char *name;		/* option name, without leading hyphens */
+  int         has_arg;		/* does it take an argument?		*/
+  int        *flag;		/* where to save its status, or NULL	*/
+  int         val;		/* its associated status value		*/
+};
+
+enum    		/* permitted values for its `has_arg' field...	*/
+{
+  no_argument = 0,      	/* option never takes an argument	*/
+  required_argument,		/* option always requires an argument	*/
+  optional_argument		/* option may take an argument		*/
+};
+
+extern int getopt_long(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx);
+extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx);
+/*
+ * Previous MinGW implementation had...
+ */
+#ifndef HAVE_DECL_GETOPT
+/*
+ * ...for the long form API only; keep this for compatibility.
+ */
+# define HAVE_DECL_GETOPT	1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
+
+#endif /* !defined(__GETOPT_H__) */
diff --git a/media/libdav1d/src/include/compat/msvc/stdatomic.h b/media/libdav1d/src/include/compat/msvc/stdatomic.h
new file mode 100644
index 0000000000..618f0ee87d
--- /dev/null
+++ b/media/libdav1d/src/include/compat/msvc/stdatomic.h
@@ -0,0 +1,82 @@
+/*
+* Copyright © 2018, VideoLAN and dav1d authors
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice, this
+*    list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+*    this list of conditions and the following disclaimer in the documentation
+*    and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MSCVER_STDATOMIC_H_
+#define MSCVER_STDATOMIC_H_
+
+#if !defined(__cplusplus) && defined(_MSC_VER)
+
+#pragma warning(push)
+#pragma warning(disable:4067)    /* newline for __has_include_next */
+
+#if defined(__clang__) && __has_include_next()
+   /* use the clang stdatomic.h with clang-cl*/
+#  include_next 
+#else /* ! stdatomic.h */
+
+#include 
+
+#include "common/attributes.h"
+
+typedef volatile LONG  atomic_int;
+typedef volatile ULONG atomic_uint;
+
+typedef enum {
+    memory_order_relaxed,
+    memory_order_acquire
+} msvc_atomic_memory_order;
+
+#define atomic_init(p_a, v)           do { *(p_a) = (v); } while(0)
+#define atomic_store(p_a, v)          InterlockedExchange((LONG*)p_a, v)
+#define atomic_load(p_a)              InterlockedCompareExchange((LONG*)p_a, 0, 0)
+#define atomic_exchange(p_a, v)       InterlockedExchange(p_a, v)
+#define atomic_load_explicit(p_a, mo) atomic_load(p_a)
+
+static inline int atomic_compare_exchange_strong_int(LONG *obj, LONG *expected,
+                                                     LONG desired)
+{
+    LONG orig = *expected;
+    *expected = InterlockedCompareExchange(obj, desired, orig);
+    return *expected == orig;
+}
+#define atomic_compare_exchange_strong(p_a, expected, desired) atomic_compare_exchange_strong_int((LONG *)p_a, (LONG *)expected, (LONG)desired)
+
+/*
+ * TODO use a special call to increment/decrement
+ * using InterlockedIncrement/InterlockedDecrement
+ */
+#define atomic_fetch_add(p_a, inc)    InterlockedExchangeAdd(p_a, inc)
+#define atomic_fetch_sub(p_a, dec)    InterlockedExchangeAdd(p_a, -(dec))
+#define atomic_fetch_or(p_a, v)       InterlockedOr(p_a, v)
+#define atomic_fetch_add_explicit(p_a, inc, mo) atomic_fetch_add(p_a, inc)
+
+#endif /* ! stdatomic.h */
+
+#pragma warning(pop)
+
+#endif /* !defined(__cplusplus) && defined(_MSC_VER) */
+
+#endif /* MSCVER_STDATOMIC_H_ */
diff --git a/media/libdav1d/src/include/dav1d/common.h b/media/libdav1d/src/include/dav1d/common.h
new file mode 100644
index 0000000000..290e6ace32
--- /dev/null
+++ b/media/libdav1d/src/include/dav1d/common.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_COMMON_H
+#define DAV1D_COMMON_H
+
+#include 
+#include 
+#include 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef DAV1D_API
+    #if defined _WIN32
+      #if defined DAV1D_BUILDING_DLL
+        #define DAV1D_API __declspec(dllexport)
+      #else
+        #define DAV1D_API
+      #endif
+    #else
+      #if __GNUC__ >= 4
+        #define DAV1D_API __attribute__ ((visibility ("default")))
+      #else
+        #define DAV1D_API
+      #endif
+    #endif
+#endif
+
+#if EPERM > 0
+#define DAV1D_ERR(e) (-(e)) ///< Negate POSIX error code.
+#else
+#define DAV1D_ERR(e) (e)
+#endif
+
+/**
+ * A reference-counted object wrapper for a user-configurable pointer.
+ */
+typedef struct Dav1dUserData {
+    const uint8_t *data; ///< data pointer
+    struct Dav1dRef *ref; ///< allocation origin
+} Dav1dUserData;
+
+/**
+ * Input packet metadata which are copied from the input data used to
+ * decode each image into the matching structure of the output image
+ * returned back to the user. Since these are metadata fields, they
+ * can be used for other purposes than the documented ones, they will
+ * still be passed from input data to output picture without being
+ * used internally.
+ */
+typedef struct Dav1dDataProps {
+    int64_t timestamp; ///< container timestamp of input data, INT64_MIN if unknown (default)
+    int64_t duration; ///< container duration of input data, 0 if unknown (default)
+    int64_t offset; ///< stream offset of input data, -1 if unknown (default)
+    size_t size; ///< packet size, default Dav1dData.sz
+    struct Dav1dUserData user_data; ///< user-configurable data, default NULL members
+} Dav1dDataProps;
+
+/**
+ * Release reference to a Dav1dDataProps.
+ */
+DAV1D_API void dav1d_data_props_unref(Dav1dDataProps *props);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* DAV1D_COMMON_H */
diff --git a/media/libdav1d/src/include/dav1d/data.h b/media/libdav1d/src/include/dav1d/data.h
new file mode 100644
index 0000000000..e551ad6506
--- /dev/null
+++ b/media/libdav1d/src/include/dav1d/data.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_DATA_H
+#define DAV1D_DATA_H
+
+#include 
+#include 
+
+#include "common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Dav1dData {
+    const uint8_t *data; ///< data pointer
+    size_t sz; ///< data size
+    struct Dav1dRef *ref; ///< allocation origin
+    Dav1dDataProps m; ///< user provided metadata passed to the output picture
+} Dav1dData;
+
+/**
+ * Allocate data.
+ *
+ * @param data Input context.
+ * @param   sz Size of the data that should be allocated.
+ *
+ * @return Pointer to the allocated buffer on success. NULL on error.
+ */
+DAV1D_API uint8_t * dav1d_data_create(Dav1dData *data, size_t sz);
+
+/**
+ * Wrap an existing data array.
+ *
+ * @param          data Input context.
+ * @param           buf The data to be wrapped.
+ * @param            sz Size of the data.
+ * @param free_callback Function to be called when we release our last
+ *                      reference to this data. In this callback, $buf will be
+ *                      the $buf argument to this function, and $cookie will
+ *                      be the $cookie input argument to this function.
+ * @param        cookie Opaque parameter passed to free_callback().
+ *
+ * @return 0 on success. A negative DAV1D_ERR value on error.
+ */
+DAV1D_API int dav1d_data_wrap(Dav1dData *data, const uint8_t *buf, size_t sz,
+                              void (*free_callback)(const uint8_t *buf, void *cookie),
+                              void *cookie);
+
+/**
+ * Wrap a user-provided data pointer into a reference counted object.
+ *
+ * data->m.user_data field will initialized to wrap the provided $user_data
+ * pointer.
+ *
+ * $free_callback will be called on the same thread that released the last
+ * reference. If frame threading is used, make sure $free_callback is
+ * thread-safe.
+ *
+ * @param          data Input context.
+ * @param     user_data The user data to be wrapped.
+ * @param free_callback Function to be called when we release our last
+ *                      reference to this data. In this callback, $user_data
+ *                      will be the $user_data argument to this function, and
+ *                      $cookie will be the $cookie input argument to this
+ *                      function.
+ * @param        cookie Opaque parameter passed to $free_callback.
+ *
+ * @return 0 on success. A negative DAV1D_ERR value on error.
+ */
+DAV1D_API int dav1d_data_wrap_user_data(Dav1dData *data,
+                                        const uint8_t *user_data,
+                                        void (*free_callback)(const uint8_t *user_data,
+                                                              void *cookie),
+                                        void *cookie);
+
+/**
+ * Free the data reference.
+ *
+ * The reference count for data->m.user_data will be decremented (if it has been
+ * initialized with dav1d_data_wrap_user_data). The $data object will be memset
+ * to 0.
+ *
+ * @param data Input context.
+ */
+DAV1D_API void dav1d_data_unref(Dav1dData *data);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* DAV1D_DATA_H */
diff --git a/media/libdav1d/src/include/dav1d/dav1d.h b/media/libdav1d/src/include/dav1d/dav1d.h
new file mode 100644
index 0000000000..e8f0705779
--- /dev/null
+++ b/media/libdav1d/src/include/dav1d/dav1d.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_H
+#define DAV1D_H
+
+#include 
+#include 
+
+#include "common.h"
+#include "picture.h"
+#include "data.h"
+#include "version.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Dav1dContext Dav1dContext;
+typedef struct Dav1dRef Dav1dRef;
+
+#define DAV1D_MAX_THREADS 256
+#define DAV1D_MAX_FRAME_DELAY 256
+
+typedef struct Dav1dLogger {
+    void *cookie; ///< Custom data to pass to the callback.
+    /**
+     * Logger callback. May be NULL to disable logging.
+     *
+     * @param cookie Custom pointer passed to all calls.
+     * @param format The vprintf compatible format string.
+     * @param     ap List of arguments referenced by the format string.
+     */
+    void (*callback)(void *cookie, const char *format, va_list ap);
+} Dav1dLogger;
+
+enum Dav1dInloopFilterType {
+    DAV1D_INLOOPFILTER_NONE        = 0,
+    DAV1D_INLOOPFILTER_DEBLOCK     = 1 << 0,
+    DAV1D_INLOOPFILTER_CDEF        = 1 << 1,
+    DAV1D_INLOOPFILTER_RESTORATION = 1 << 2,
+    DAV1D_INLOOPFILTER_ALL = DAV1D_INLOOPFILTER_DEBLOCK |
+                             DAV1D_INLOOPFILTER_CDEF |
+                             DAV1D_INLOOPFILTER_RESTORATION,
+};
+
+enum Dav1dDecodeFrameType {
+    DAV1D_DECODEFRAMETYPE_ALL   = 0, ///< decode and return all frames
+    DAV1D_DECODEFRAMETYPE_REFERENCE = 1,///< decode and return frames referenced by other frames only
+    DAV1D_DECODEFRAMETYPE_INTRA = 2, ///< decode and return intra frames only (includes keyframes)
+    DAV1D_DECODEFRAMETYPE_KEY   = 3, ///< decode and return keyframes only
+};
+
+typedef struct Dav1dSettings {
+    int n_threads; ///< number of threads (0 = number of logical cores in host system, default 0)
+    int max_frame_delay; ///< Set to 1 for low-latency decoding (0 = ceil(sqrt(n_threads)), default 0)
+    int apply_grain; ///< whether to apply film grain on output frames (default 1)
+    int operating_point; ///< select an operating point for scalable AV1 bitstreams (0 - 31, default 0)
+    int all_layers; ///< output all spatial layers of a scalable AV1 biststream (default 1)
+    unsigned frame_size_limit; ///< maximum frame size, in pixels (0 = unlimited, default 0)
+    Dav1dPicAllocator allocator; ///< Picture allocator callback.
+    Dav1dLogger logger; ///< Logger callback.
+    int strict_std_compliance; ///< whether to abort decoding on standard compliance violations
+                               ///< that don't affect actual bitstream decoding (e.g. inconsistent
+                               ///< or invalid metadata, default 0)
+    int output_invisible_frames; ///< output invisibly coded frames (in coding order) in addition
+                                 ///< to all visible frames. Because of show-existing-frame, this
+                                 ///< means some frames may appear twice (once when coded,
+                                 ///< once when shown, default 0)
+    enum Dav1dInloopFilterType inloop_filters; ///< postfilters to enable during decoding (default
+                                               ///< DAV1D_INLOOPFILTER_ALL)
+    enum Dav1dDecodeFrameType decode_frame_type; ///< frame types to decode (default
+                                                 ///< DAV1D_DECODEFRAMETYPE_ALL)
+    uint8_t reserved[16]; ///< reserved for future use
+} Dav1dSettings;
+
+/**
+ * Get library version.
+ */
+DAV1D_API const char *dav1d_version(void);
+
+/**
+ * Get library API version.
+ *
+ * @return A value in the format 0x00XXYYZZ, where XX is the major version,
+ *         YY the minor version, and ZZ the patch version.
+ * @see DAV1D_API_MAJOR, DAV1D_API_MINOR, DAV1D_API_PATCH
+ */
+DAV1D_API unsigned dav1d_version_api(void);
+
+/**
+ * Initialize settings to default values.
+ *
+ * @param s Input settings context.
+ */
+DAV1D_API void dav1d_default_settings(Dav1dSettings *s);
+
+/**
+ * Allocate and open a decoder instance.
+ *
+ * @param c_out The decoder instance to open. *c_out will be set to the
+ *              allocated context.
+ * @param     s Input settings context.
+ *
+ * @note The context must be freed using dav1d_close() when decoding is
+ *       finished.
+ *
+ * @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
+ */
+DAV1D_API int dav1d_open(Dav1dContext **c_out, const Dav1dSettings *s);
+
+/**
+ * Parse a Sequence Header OBU from bitstream data.
+ *
+ * @param out Output Sequence Header.
+ * @param buf The data to be parser.
+ * @param sz  Size of the data.
+ *
+ * @return
+ *                  0: Success, and out is filled with the parsed Sequence Header
+ *                     OBU parameters.
+ *  DAV1D_ERR(ENOENT): No Sequence Header OBUs were found in the buffer.
+ *  Other negative DAV1D_ERR codes: Invalid data in the buffer, invalid passed-in
+ *                                  arguments, and other errors during parsing.
+ *
+ * @note It is safe to feed this function data containing other OBUs than a
+ *       Sequence Header, as they will simply be ignored. If there is more than
+ *       one Sequence Header OBU present, only the last will be returned.
+ */
+DAV1D_API int dav1d_parse_sequence_header(Dav1dSequenceHeader *out,
+                                          const uint8_t *buf, const size_t sz);
+
+/**
+ * Feed bitstream data to the decoder, in the form of one or multiple AV1
+ * Open Bitstream Units (OBUs).
+ *
+ * @param   c Input decoder instance.
+ * @param  in Input bitstream data. On success, ownership of the reference is
+ *            passed to the library.
+ *
+ * @return
+ *         0: Success, and the data was consumed.
+ *  DAV1D_ERR(EAGAIN): The data can't be consumed. dav1d_get_picture() should
+ *                     be called to get one or more frames before the function
+ *                     can consume new data.
+ *  Other negative DAV1D_ERR codes: Error during decoding or because of invalid
+ *                                  passed-in arguments. The reference remains
+ *                                  owned by the caller.
+ */
+DAV1D_API int dav1d_send_data(Dav1dContext *c, Dav1dData *in);
+
+/**
+ * Return a decoded picture.
+ *
+ * @param   c Input decoder instance.
+ * @param out Output frame. The caller assumes ownership of the returned
+ *            reference.
+ *
+ * @return
+ *         0: Success, and a frame is returned.
+ *  DAV1D_ERR(EAGAIN): Not enough data to output a frame. dav1d_send_data()
+ *                     should be called with new input.
+ *  Other negative DAV1D_ERR codes: Error during decoding or because of invalid
+ *                                  passed-in arguments.
+ *
+ * @note To drain buffered frames from the decoder (i.e. on end of stream),
+ *       call this function until it returns DAV1D_ERR(EAGAIN).
+ *
+ * @code{.c}
+ *  Dav1dData data = { 0 };
+ *  Dav1dPicture p = { 0 };
+ *  int res;
+ *
+ *  read_data(&data);
+ *  do {
+ *      res = dav1d_send_data(c, &data);
+ *      // Keep going even if the function can't consume the current data
+ *         packet. It eventually will after one or more frames have been
+ *         returned in this loop.
+ *      if (res < 0 && res != DAV1D_ERR(EAGAIN))
+ *          free_and_abort();
+ *      res = dav1d_get_picture(c, &p);
+ *      if (res < 0) {
+ *          if (res != DAV1D_ERR(EAGAIN))
+ *              free_and_abort();
+ *      } else
+ *          output_and_unref_picture(&p);
+ *  // Stay in the loop as long as there's data to consume.
+ *  } while (data.sz || read_data(&data) == SUCCESS);
+ *
+ *  // Handle EOS by draining all buffered frames.
+ *  do {
+ *      res = dav1d_get_picture(c, &p);
+ *      if (res < 0) {
+ *          if (res != DAV1D_ERR(EAGAIN))
+ *              free_and_abort();
+ *      } else
+ *          output_and_unref_picture(&p);
+ *  } while (res == 0);
+ * @endcode
+ */
+DAV1D_API int dav1d_get_picture(Dav1dContext *c, Dav1dPicture *out);
+
+/**
+ * Apply film grain to a previously decoded picture. If the picture contains no
+ * film grain metadata, then this function merely returns a new reference.
+ *
+ * @param   c Input decoder instance.
+ * @param out Output frame. The caller assumes ownership of the returned
+ *            reference.
+ * @param  in Input frame. No ownership is transferred.
+ *
+ * @return
+ *         0: Success, and a frame is returned.
+ *  Other negative DAV1D_ERR codes: Error due to lack of memory or because of
+ *                                  invalid passed-in arguments.
+ *
+ * @note If `Dav1dSettings.apply_grain` is true, film grain was already applied
+ *       by `dav1d_get_picture`, and so calling this function leads to double
+ *       application of film grain. Users should only call this when needed.
+ */
+DAV1D_API int dav1d_apply_grain(Dav1dContext *c, Dav1dPicture *out,
+                                const Dav1dPicture *in);
+
+/**
+ * Close a decoder instance and free all associated memory.
+ *
+ * @param c_out The decoder instance to close. *c_out will be set to NULL.
+ */
+DAV1D_API void dav1d_close(Dav1dContext **c_out);
+
+/**
+ * Flush all delayed frames in decoder and clear internal decoder state,
+ * to be used when seeking.
+ *
+ * @param c Input decoder instance.
+ *
+ * @note Decoding will start only after a valid sequence header OBU is
+ *       delivered to dav1d_send_data().
+ *
+ */
+DAV1D_API void dav1d_flush(Dav1dContext *c);
+
+enum Dav1dEventFlags {
+    /**
+     * The last returned picture contains a reference to a new Sequence Header,
+     * either because it's the start of a new coded sequence, or the decoder was
+     * flushed before it was generated.
+     */
+    DAV1D_EVENT_FLAG_NEW_SEQUENCE =       1 << 0,
+    /**
+     * The last returned picture contains a reference to a Sequence Header with
+     * new operating parameters information for the current coded sequence.
+     */
+    DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO = 1 << 1,
+};
+
+/**
+ * Fetch a combination of DAV1D_EVENT_FLAG_* event flags generated by the decoding
+ * process.
+ *
+ * @param c Input decoder instance.
+ * @param flags Where to write the flags.
+ *
+ * @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
+ *
+ * @note Calling this function will clear all the event flags currently stored in
+ *       the decoder.
+ *
+ */
+DAV1D_API int dav1d_get_event_flags(Dav1dContext *c, enum Dav1dEventFlags *flags);
+
+/**
+ * Retrieve the user-provided metadata associated with the input data packet
+ * for the last decoding error reported to the user, i.e. a negative return
+ * value (not EAGAIN) from dav1d_send_data() or dav1d_get_picture().
+ *
+ * @param   c Input decoder instance.
+ * @param out Output Dav1dDataProps. On success, the caller assumes ownership of
+ *            the returned reference.
+ *
+ * @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
+ */
+DAV1D_API int dav1d_get_decode_error_data_props(Dav1dContext *c, Dav1dDataProps *out);
+
+/**
+ * Get the decoder delay, which is the number of internally buffered frames, not
+ * including reference frames.
+ * This value is guaranteed to be >= 1 and <= max_frame_delay.
+ *
+ * @param s Input settings context.
+ *
+ * @return Decoder frame delay on success, or < 0 (a negative DAV1D_ERR code) on
+ *         error.
+ *
+ * @note The returned delay is valid only for a Dav1dContext initialized with the
+ *       provided Dav1dSettings.
+ */
+DAV1D_API int dav1d_get_frame_delay(const Dav1dSettings *s);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* DAV1D_H */
diff --git a/media/libdav1d/src/include/dav1d/headers.h b/media/libdav1d/src/include/dav1d/headers.h
new file mode 100644
index 0000000000..0fab9938eb
--- /dev/null
+++ b/media/libdav1d/src/include/dav1d/headers.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright © 2018-2020, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_HEADERS_H
+#define DAV1D_HEADERS_H
+
+#include 
+#include 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Constants from Section 3. "Symbols and abbreviated terms"
+#define DAV1D_MAX_CDEF_STRENGTHS 8
+#define DAV1D_MAX_OPERATING_POINTS 32
+#define DAV1D_MAX_TILE_COLS 64
+#define DAV1D_MAX_TILE_ROWS 64
+#define DAV1D_MAX_SEGMENTS 8
+#define DAV1D_NUM_REF_FRAMES 8
+#define DAV1D_PRIMARY_REF_NONE 7
+#define DAV1D_REFS_PER_FRAME 7
+#define DAV1D_TOTAL_REFS_PER_FRAME (DAV1D_REFS_PER_FRAME + 1)
+
+enum Dav1dObuType {
+    DAV1D_OBU_SEQ_HDR   = 1,
+    DAV1D_OBU_TD        = 2,
+    DAV1D_OBU_FRAME_HDR = 3,
+    DAV1D_OBU_TILE_GRP  = 4,
+    DAV1D_OBU_METADATA  = 5,
+    DAV1D_OBU_FRAME     = 6,
+    DAV1D_OBU_REDUNDANT_FRAME_HDR = 7,
+    DAV1D_OBU_PADDING   = 15,
+};
+
+enum Dav1dTxfmMode {
+    DAV1D_TX_4X4_ONLY,
+    DAV1D_TX_LARGEST,
+    DAV1D_TX_SWITCHABLE,
+    DAV1D_N_TX_MODES,
+};
+
+enum Dav1dFilterMode {
+    DAV1D_FILTER_8TAP_REGULAR,
+    DAV1D_FILTER_8TAP_SMOOTH,
+    DAV1D_FILTER_8TAP_SHARP,
+    DAV1D_N_SWITCHABLE_FILTERS,
+    DAV1D_FILTER_BILINEAR = DAV1D_N_SWITCHABLE_FILTERS,
+    DAV1D_N_FILTERS,
+    DAV1D_FILTER_SWITCHABLE = DAV1D_N_FILTERS,
+};
+
+enum Dav1dAdaptiveBoolean {
+    DAV1D_OFF = 0,
+    DAV1D_ON = 1,
+    DAV1D_ADAPTIVE = 2,
+};
+
+enum Dav1dRestorationType {
+    DAV1D_RESTORATION_NONE,
+    DAV1D_RESTORATION_SWITCHABLE,
+    DAV1D_RESTORATION_WIENER,
+    DAV1D_RESTORATION_SGRPROJ,
+};
+
+enum Dav1dWarpedMotionType {
+    DAV1D_WM_TYPE_IDENTITY,
+    DAV1D_WM_TYPE_TRANSLATION,
+    DAV1D_WM_TYPE_ROT_ZOOM,
+    DAV1D_WM_TYPE_AFFINE,
+};
+
+typedef struct Dav1dWarpedMotionParams {
+    enum Dav1dWarpedMotionType type;
+    int32_t matrix[6];
+    union {
+        struct {
+            int16_t alpha, beta, gamma, delta;
+        } p;
+        int16_t abcd[4];
+    } u;
+} Dav1dWarpedMotionParams;
+
+enum Dav1dPixelLayout {
+    DAV1D_PIXEL_LAYOUT_I400, ///< monochrome
+    DAV1D_PIXEL_LAYOUT_I420, ///< 4:2:0 planar
+    DAV1D_PIXEL_LAYOUT_I422, ///< 4:2:2 planar
+    DAV1D_PIXEL_LAYOUT_I444, ///< 4:4:4 planar
+};
+
+enum Dav1dFrameType {
+    DAV1D_FRAME_TYPE_KEY = 0,    ///< Key Intra frame
+    DAV1D_FRAME_TYPE_INTER = 1,  ///< Inter frame
+    DAV1D_FRAME_TYPE_INTRA = 2,  ///< Non key Intra frame
+    DAV1D_FRAME_TYPE_SWITCH = 3, ///< Switch Inter frame
+};
+
+enum Dav1dColorPrimaries {
+    DAV1D_COLOR_PRI_BT709 = 1,
+    DAV1D_COLOR_PRI_UNKNOWN = 2,
+    DAV1D_COLOR_PRI_BT470M = 4,
+    DAV1D_COLOR_PRI_BT470BG = 5,
+    DAV1D_COLOR_PRI_BT601 = 6,
+    DAV1D_COLOR_PRI_SMPTE240 = 7,
+    DAV1D_COLOR_PRI_FILM = 8,
+    DAV1D_COLOR_PRI_BT2020 = 9,
+    DAV1D_COLOR_PRI_XYZ = 10,
+    DAV1D_COLOR_PRI_SMPTE431 = 11,
+    DAV1D_COLOR_PRI_SMPTE432 = 12,
+    DAV1D_COLOR_PRI_EBU3213 = 22,
+    DAV1D_COLOR_PRI_RESERVED = 255,
+};
+
+enum Dav1dTransferCharacteristics {
+    DAV1D_TRC_BT709 = 1,
+    DAV1D_TRC_UNKNOWN = 2,
+    DAV1D_TRC_BT470M = 4,
+    DAV1D_TRC_BT470BG = 5,
+    DAV1D_TRC_BT601 = 6,
+    DAV1D_TRC_SMPTE240 = 7,
+    DAV1D_TRC_LINEAR = 8,
+    DAV1D_TRC_LOG100 = 9,         ///< logarithmic (100:1 range)
+    DAV1D_TRC_LOG100_SQRT10 = 10, ///< lograithmic (100*sqrt(10):1 range)
+    DAV1D_TRC_IEC61966 = 11,
+    DAV1D_TRC_BT1361 = 12,
+    DAV1D_TRC_SRGB = 13,
+    DAV1D_TRC_BT2020_10BIT = 14,
+    DAV1D_TRC_BT2020_12BIT = 15,
+    DAV1D_TRC_SMPTE2084 = 16,     ///< PQ
+    DAV1D_TRC_SMPTE428 = 17,
+    DAV1D_TRC_HLG = 18,           ///< hybrid log/gamma (BT.2100 / ARIB STD-B67)
+    DAV1D_TRC_RESERVED = 255,
+};
+
+enum Dav1dMatrixCoefficients {
+    DAV1D_MC_IDENTITY = 0,
+    DAV1D_MC_BT709 = 1,
+    DAV1D_MC_UNKNOWN = 2,
+    DAV1D_MC_FCC = 4,
+    DAV1D_MC_BT470BG = 5,
+    DAV1D_MC_BT601 = 6,
+    DAV1D_MC_SMPTE240 = 7,
+    DAV1D_MC_SMPTE_YCGCO = 8,
+    DAV1D_MC_BT2020_NCL = 9,
+    DAV1D_MC_BT2020_CL = 10,
+    DAV1D_MC_SMPTE2085 = 11,
+    DAV1D_MC_CHROMAT_NCL = 12, ///< Chromaticity-derived
+    DAV1D_MC_CHROMAT_CL = 13,
+    DAV1D_MC_ICTCP = 14,
+    DAV1D_MC_RESERVED = 255,
+};
+
+enum Dav1dChromaSamplePosition {
+    DAV1D_CHR_UNKNOWN = 0,
+    DAV1D_CHR_VERTICAL = 1,  ///< Horizontally co-located with luma(0, 0)
+                           ///< sample, between two vertical samples
+    DAV1D_CHR_COLOCATED = 2, ///< Co-located with luma(0, 0) sample
+};
+
+typedef struct Dav1dContentLightLevel {
+    uint16_t max_content_light_level;
+    uint16_t max_frame_average_light_level;
+} Dav1dContentLightLevel;
+
+typedef struct Dav1dMasteringDisplay {
+    uint16_t primaries[3][2]; ///< 0.16 fixed point
+    uint16_t white_point[2]; ///< 0.16 fixed point
+    uint32_t max_luminance; ///< 24.8 fixed point
+    uint32_t min_luminance; ///< 18.14 fixed point
+} Dav1dMasteringDisplay;
+
+typedef struct Dav1dITUTT35 {
+    uint8_t  country_code;
+    uint8_t  country_code_extension_byte;
+    size_t   payload_size;
+    uint8_t *payload;
+} Dav1dITUTT35;
+
+typedef struct Dav1dSequenceHeader {
+    /**
+     * Stream profile, 0 for 8-10 bits/component 4:2:0 or monochrome;
+     * 1 for 8-10 bits/component 4:4:4; 2 for 4:2:2 at any bits/component,
+     * or 12 bits/component at any chroma subsampling.
+     */
+    uint8_t profile;
+    /**
+     * Maximum dimensions for this stream. In non-scalable streams, these
+     * are often the actual dimensions of the stream, although that is not
+     * a normative requirement.
+     */
+    int max_width, max_height;
+    enum Dav1dPixelLayout layout; ///< format of the picture
+    enum Dav1dColorPrimaries pri; ///< color primaries (av1)
+    enum Dav1dTransferCharacteristics trc; ///< transfer characteristics (av1)
+    enum Dav1dMatrixCoefficients mtrx; ///< matrix coefficients (av1)
+    enum Dav1dChromaSamplePosition chr; ///< chroma sample position (av1)
+    /**
+     * 0, 1 and 2 mean 8, 10 or 12 bits/component, respectively. This is not
+     * exactly the same as 'hbd' from the spec; the spec's hbd distinguishes
+     * between 8 (0) and 10-12 (1) bits/component, and another element
+     * (twelve_bit) to distinguish between 10 and 12 bits/component. To get
+     * the spec's hbd, use !!our_hbd, and to get twelve_bit, use hbd == 2.
+     */
+    uint8_t hbd;
+    /**
+     * Pixel data uses JPEG pixel range ([0,255] for 8bits) instead of
+     * MPEG pixel range ([16,235] for 8bits luma, [16,240] for 8bits chroma).
+     */
+    uint8_t color_range;
+
+    uint8_t num_operating_points;
+    struct Dav1dSequenceHeaderOperatingPoint {
+        uint8_t major_level, minor_level;
+        uint8_t initial_display_delay;
+        uint16_t idc;
+        uint8_t tier;
+        uint8_t decoder_model_param_present;
+        uint8_t display_model_param_present;
+    } operating_points[DAV1D_MAX_OPERATING_POINTS];
+
+    uint8_t still_picture;
+    uint8_t reduced_still_picture_header;
+    uint8_t timing_info_present;
+    uint32_t num_units_in_tick;
+    uint32_t time_scale;
+    uint8_t equal_picture_interval;
+    uint32_t num_ticks_per_picture;
+    uint8_t decoder_model_info_present;
+    uint8_t encoder_decoder_buffer_delay_length;
+    uint32_t num_units_in_decoding_tick;
+    uint8_t buffer_removal_delay_length;
+    uint8_t frame_presentation_delay_length;
+    uint8_t display_model_info_present;
+    uint8_t width_n_bits, height_n_bits;
+    uint8_t frame_id_numbers_present;
+    uint8_t delta_frame_id_n_bits;
+    uint8_t frame_id_n_bits;
+    uint8_t sb128;
+    uint8_t filter_intra;
+    uint8_t intra_edge_filter;
+    uint8_t inter_intra;
+    uint8_t masked_compound;
+    uint8_t warped_motion;
+    uint8_t dual_filter;
+    uint8_t order_hint;
+    uint8_t jnt_comp;
+    uint8_t ref_frame_mvs;
+    enum Dav1dAdaptiveBoolean screen_content_tools;
+    enum Dav1dAdaptiveBoolean force_integer_mv;
+    uint8_t order_hint_n_bits;
+    uint8_t super_res;
+    uint8_t cdef;
+    uint8_t restoration;
+    uint8_t ss_hor, ss_ver, monochrome;
+    uint8_t color_description_present;
+    uint8_t separate_uv_delta_q;
+    uint8_t film_grain_present;
+
+    // Dav1dSequenceHeaders of the same sequence are required to be
+    // bit-identical until this offset. See 7.5 "Ordering of OBUs":
+    //   Within a particular coded video sequence, the contents of
+    //   sequence_header_obu must be bit-identical each time the
+    //   sequence header appears except for the contents of
+    //   operating_parameters_info.
+    struct Dav1dSequenceHeaderOperatingParameterInfo {
+        uint32_t decoder_buffer_delay;
+        uint32_t encoder_buffer_delay;
+        uint8_t low_delay_mode;
+    } operating_parameter_info[DAV1D_MAX_OPERATING_POINTS];
+} Dav1dSequenceHeader;
+
+typedef struct Dav1dSegmentationData {
+    int16_t delta_q;
+    int8_t delta_lf_y_v, delta_lf_y_h, delta_lf_u, delta_lf_v;
+    int8_t ref;
+    uint8_t skip;
+    uint8_t globalmv;
+} Dav1dSegmentationData;
+
+typedef struct Dav1dSegmentationDataSet {
+    Dav1dSegmentationData d[DAV1D_MAX_SEGMENTS];
+    uint8_t preskip;
+    int8_t last_active_segid;
+} Dav1dSegmentationDataSet;
+
+typedef struct Dav1dLoopfilterModeRefDeltas {
+    int8_t mode_delta[2 /* is_zeromv */];
+    int8_t ref_delta[DAV1D_TOTAL_REFS_PER_FRAME];
+} Dav1dLoopfilterModeRefDeltas;
+
+typedef struct Dav1dFilmGrainData {
+    unsigned seed;
+    int num_y_points;
+    uint8_t y_points[14][2 /* value, scaling */];
+    int chroma_scaling_from_luma;
+    int num_uv_points[2];
+    uint8_t uv_points[2][10][2 /* value, scaling */];
+    int scaling_shift;
+    int ar_coeff_lag;
+    int8_t ar_coeffs_y[24];
+    int8_t ar_coeffs_uv[2][25 + 3 /* padding for alignment purposes */];
+    uint64_t ar_coeff_shift;
+    int grain_scale_shift;
+    int uv_mult[2];
+    int uv_luma_mult[2];
+    int uv_offset[2];
+    int overlap_flag;
+    int clip_to_restricted_range;
+} Dav1dFilmGrainData;
+
+typedef struct Dav1dFrameHeader {
+    struct {
+        Dav1dFilmGrainData data;
+        uint8_t present, update;
+    } film_grain; ///< film grain parameters
+    enum Dav1dFrameType frame_type; ///< type of the picture
+    int width[2 /* { coded_width, superresolution_upscaled_width } */], height;
+    uint8_t frame_offset; ///< frame number
+    uint8_t temporal_id; ///< temporal id of the frame for SVC
+    uint8_t spatial_id; ///< spatial id of the frame for SVC
+
+    uint8_t show_existing_frame;
+    uint8_t existing_frame_idx;
+    uint32_t frame_id;
+    uint32_t frame_presentation_delay;
+    uint8_t show_frame;
+    uint8_t showable_frame;
+    uint8_t error_resilient_mode;
+    uint8_t disable_cdf_update;
+    uint8_t allow_screen_content_tools;
+    uint8_t force_integer_mv;
+    uint8_t frame_size_override;
+    uint8_t primary_ref_frame;
+    uint8_t buffer_removal_time_present;
+    struct Dav1dFrameHeaderOperatingPoint {
+        uint32_t buffer_removal_time;
+    } operating_points[DAV1D_MAX_OPERATING_POINTS];
+    uint8_t refresh_frame_flags;
+    int render_width, render_height;
+    struct {
+        uint8_t width_scale_denominator;
+        uint8_t enabled;
+    } super_res;
+    uint8_t have_render_size;
+    uint8_t allow_intrabc;
+    uint8_t frame_ref_short_signaling;
+    int8_t refidx[DAV1D_REFS_PER_FRAME];
+    uint8_t hp;
+    enum Dav1dFilterMode subpel_filter_mode;
+    uint8_t switchable_motion_mode;
+    uint8_t use_ref_frame_mvs;
+    uint8_t refresh_context;
+    struct {
+        uint8_t uniform;
+        uint8_t n_bytes;
+        uint8_t min_log2_cols, max_log2_cols, log2_cols, cols;
+        uint8_t min_log2_rows, max_log2_rows, log2_rows, rows;
+        uint16_t col_start_sb[DAV1D_MAX_TILE_COLS + 1];
+        uint16_t row_start_sb[DAV1D_MAX_TILE_ROWS + 1];
+        uint16_t update;
+    } tiling;
+    struct {
+        uint8_t yac;
+        int8_t ydc_delta;
+        int8_t udc_delta, uac_delta, vdc_delta, vac_delta;
+        uint8_t qm, qm_y, qm_u, qm_v;
+    } quant;
+    struct {
+        uint8_t enabled, update_map, temporal, update_data;
+        Dav1dSegmentationDataSet seg_data;
+        uint8_t lossless[DAV1D_MAX_SEGMENTS], qidx[DAV1D_MAX_SEGMENTS];
+    } segmentation;
+    struct {
+        struct {
+            uint8_t present;
+            uint8_t res_log2;
+        } q;
+        struct {
+            uint8_t present;
+            uint8_t res_log2;
+            uint8_t multi;
+        } lf;
+    } delta;
+    uint8_t all_lossless;
+    struct {
+        uint8_t level_y[2 /* dir */];
+        uint8_t level_u, level_v;
+        uint8_t mode_ref_delta_enabled;
+        uint8_t mode_ref_delta_update;
+        Dav1dLoopfilterModeRefDeltas mode_ref_deltas;
+        uint8_t sharpness;
+    } loopfilter;
+    struct {
+        uint8_t damping;
+        uint8_t n_bits;
+        uint8_t y_strength[DAV1D_MAX_CDEF_STRENGTHS];
+        uint8_t uv_strength[DAV1D_MAX_CDEF_STRENGTHS];
+    } cdef;
+    struct {
+        enum Dav1dRestorationType type[3 /* plane */];
+        uint8_t unit_size[2 /* y, uv */];
+    } restoration;
+    enum Dav1dTxfmMode txfm_mode;
+    uint8_t switchable_comp_refs;
+    uint8_t skip_mode_allowed, skip_mode_enabled;
+    int8_t skip_mode_refs[2];
+    uint8_t warp_motion;
+    uint8_t reduced_txtp_set;
+    Dav1dWarpedMotionParams gmv[DAV1D_REFS_PER_FRAME];
+} Dav1dFrameHeader;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* DAV1D_HEADERS_H */
diff --git a/media/libdav1d/src/include/dav1d/meson.build b/media/libdav1d/src/include/dav1d/meson.build
new file mode 100644
index 0000000000..dfb69a1c16
--- /dev/null
+++ b/media/libdav1d/src/include/dav1d/meson.build
@@ -0,0 +1,36 @@
+# Copyright © 2019, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+dav1d_api_headers = [
+    'common.h',
+    'data.h',
+    'dav1d.h',
+    'headers.h',
+    'picture.h',
+    'version.h',
+]
+
+# install headers
+install_headers(dav1d_api_headers,
+                subdir : 'dav1d')
diff --git a/media/libdav1d/src/include/dav1d/picture.h b/media/libdav1d/src/include/dav1d/picture.h
new file mode 100644
index 0000000000..cc291a4abb
--- /dev/null
+++ b/media/libdav1d/src/include/dav1d/picture.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright © 2018-2020, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_PICTURE_H
+#define DAV1D_PICTURE_H
+
+#include 
+#include 
+
+#include "common.h"
+#include "headers.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Number of bytes to align AND pad picture memory buffers by, so that SIMD
+ * implementations can over-read by a few bytes, and use aligned read/write
+ * instructions. */
+#define DAV1D_PICTURE_ALIGNMENT 64
+
+typedef struct Dav1dPictureParameters {
+    int w; ///< width (in pixels)
+    int h; ///< height (in pixels)
+    enum Dav1dPixelLayout layout; ///< format of the picture
+    int bpc; ///< bits per pixel component (8 or 10)
+} Dav1dPictureParameters;
+
+typedef struct Dav1dPicture {
+    Dav1dSequenceHeader *seq_hdr;
+    Dav1dFrameHeader *frame_hdr;
+
+    /**
+     * Pointers to planar image data (Y is [0], U is [1], V is [2]). The data
+     * should be bytes (for 8 bpc) or words (for 10 bpc). In case of words
+     * containing 10 bpc image data, the pixels should be located in the LSB
+     * bits, so that values range between [0, 1023]; the upper bits should be
+     * zero'ed out.
+     */
+    void *data[3];
+
+    /**
+     * Number of bytes between 2 lines in data[] for luma [0] or chroma [1].
+     */
+    ptrdiff_t stride[2];
+
+    Dav1dPictureParameters p;
+    Dav1dDataProps m;
+
+    /**
+     * High Dynamic Range Content Light Level metadata applying to this picture,
+     * as defined in section 5.8.3 and 6.7.3
+     */
+    Dav1dContentLightLevel *content_light;
+    /**
+     * High Dynamic Range Mastering Display Color Volume metadata applying to
+     * this picture, as defined in section 5.8.4 and 6.7.4
+     */
+    Dav1dMasteringDisplay *mastering_display;
+    /**
+     * Array of ITU-T T.35 metadata as defined in section 5.8.2 and 6.7.2
+     */
+    Dav1dITUTT35 *itut_t35;
+
+    /**
+     * Number of ITU-T T35 metadata entries in the array
+     */
+    size_t n_itut_t35;
+
+    uintptr_t reserved[4]; ///< reserved for future use
+
+    struct Dav1dRef *frame_hdr_ref; ///< Dav1dFrameHeader allocation origin
+    struct Dav1dRef *seq_hdr_ref; ///< Dav1dSequenceHeader allocation origin
+    struct Dav1dRef *content_light_ref; ///< Dav1dContentLightLevel allocation origin
+    struct Dav1dRef *mastering_display_ref; ///< Dav1dMasteringDisplay allocation origin
+    struct Dav1dRef *itut_t35_ref; ///< Dav1dITUTT35 allocation origin
+    uintptr_t reserved_ref[4]; ///< reserved for future use
+    struct Dav1dRef *ref; ///< Frame data allocation origin
+
+    void *allocator_data; ///< pointer managed by the allocator
+} Dav1dPicture;
+
+typedef struct Dav1dPicAllocator {
+    void *cookie; ///< custom data to pass to the allocator callbacks.
+    /**
+     * Allocate the picture buffer based on the Dav1dPictureParameters.
+     *
+     * The data[0], data[1] and data[2] must be DAV1D_PICTURE_ALIGNMENT byte
+     * aligned and with a pixel width/height multiple of 128 pixels. Any
+     * allocated memory area should also be padded by DAV1D_PICTURE_ALIGNMENT
+     * bytes.
+     * data[1] and data[2] must share the same stride[1].
+     *
+     * This function will be called on the main thread (the thread which calls
+     * dav1d_get_picture()).
+     *
+     * @param  pic The picture to allocate the buffer for. The callback needs to
+     *             fill the picture data[0], data[1], data[2], stride[0] and
+     *             stride[1].
+     *             The allocator can fill the pic allocator_data pointer with
+     *             a custom pointer that will be passed to
+     *             release_picture_callback().
+     * @param cookie Custom pointer passed to all calls.
+     *
+     * @note No fields other than data, stride and allocator_data must be filled
+     *       by this callback.
+     * @return 0 on success. A negative DAV1D_ERR value on error.
+     */
+    int (*alloc_picture_callback)(Dav1dPicture *pic, void *cookie);
+    /**
+     * Release the picture buffer.
+     *
+     * If frame threading is used, this function may be called by the main
+     * thread (the thread which calls dav1d_get_picture()) or any of the frame
+     * threads and thus must be thread-safe. If frame threading is not used,
+     * this function will only be called on the main thread.
+     *
+     * @param pic    The picture that was filled by alloc_picture_callback().
+     * @param cookie Custom pointer passed to all calls.
+     */
+    void (*release_picture_callback)(Dav1dPicture *pic, void *cookie);
+} Dav1dPicAllocator;
+
+/**
+ * Release reference to a picture.
+ */
+DAV1D_API void dav1d_picture_unref(Dav1dPicture *p);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* DAV1D_PICTURE_H */
diff --git a/media/libdav1d/src/include/dav1d/version.h b/media/libdav1d/src/include/dav1d/version.h
new file mode 100644
index 0000000000..43df603915
--- /dev/null
+++ b/media/libdav1d/src/include/dav1d/version.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2019-2024, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_VERSION_H
+#define DAV1D_VERSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DAV1D_API_VERSION_MAJOR 7
+#define DAV1D_API_VERSION_MINOR 0
+#define DAV1D_API_VERSION_PATCH 0
+
+/**
+ * Extract version components from the value returned by
+ * dav1d_version_int()
+ */
+#define DAV1D_API_MAJOR(v) (((v) >> 16) & 0xFF)
+#define DAV1D_API_MINOR(v) (((v) >>  8) & 0xFF)
+#define DAV1D_API_PATCH(v) (((v) >>  0) & 0xFF)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* DAV1D_VERSION_H */
diff --git a/media/libdav1d/src/include/meson.build b/media/libdav1d/src/include/meson.build
new file mode 100644
index 0000000000..e5971840c2
--- /dev/null
+++ b/media/libdav1d/src/include/meson.build
@@ -0,0 +1,34 @@
+# Copyright © 2018, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Revision file (vcs_version.h) generation
+dav1d_git_dir = join_paths(dav1d_src_root, '.git')
+rev_target = vcs_tag(command: [
+        'git', '--git-dir', dav1d_git_dir, 'describe', '--long', '--always'
+    ],
+    input: 'vcs_version.h.in',
+    output: 'vcs_version.h'
+)
+
+subdir('dav1d')
diff --git a/media/libdav1d/src/include/vcs_version.h.in b/media/libdav1d/src/include/vcs_version.h.in
new file mode 100644
index 0000000000..71ed2f6982
--- /dev/null
+++ b/media/libdav1d/src/include/vcs_version.h.in
@@ -0,0 +1,2 @@
+/* auto-generated, do not edit */
+#define DAV1D_VERSION "@VCS_TAG@"
diff --git a/media/libdav1d/src/meson.build b/media/libdav1d/src/meson.build
new file mode 100644
index 0000000000..2168b6ac21
--- /dev/null
+++ b/media/libdav1d/src/meson.build
@@ -0,0 +1,610 @@
+# Copyright © 2018-2024, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+project('dav1d', ['c'],
+    version: '1.5.3',
+    default_options: ['c_std=c99',
+                      'warning_level=2',
+                      'buildtype=release',
+                      'b_ndebug=if-release'],
+    meson_version: '>= 0.49.0')
+
+dav1d_src_root = meson.current_source_dir()
+cc = meson.get_compiler('c')
+
+# Configuratin data for config.h
+cdata = configuration_data()
+
+# Configuration data for config.asm
+cdata_asm = configuration_data()
+
+# Include directories
+dav1d_inc_dirs = include_directories(['.', 'include/dav1d', 'include'])
+
+dav1d_api_version_major    = cc.get_define('DAV1D_API_VERSION_MAJOR',
+                                           prefix: '#include "dav1d/version.h"',
+                                           include_directories: dav1d_inc_dirs).strip()
+dav1d_api_version_minor    = cc.get_define('DAV1D_API_VERSION_MINOR',
+                                           prefix: '#include "dav1d/version.h"',
+                                           include_directories: dav1d_inc_dirs).strip()
+dav1d_api_version_revision = cc.get_define('DAV1D_API_VERSION_PATCH',
+                                           prefix: '#include "dav1d/version.h"',
+                                           include_directories: dav1d_inc_dirs).strip()
+dav1d_soname_version       = '@0@.@1@.@2@'.format(dav1d_api_version_major,
+                                                  dav1d_api_version_minor,
+                                                  dav1d_api_version_revision)
+
+#
+# Option handling
+#
+
+# Bitdepth option
+dav1d_bitdepths = get_option('bitdepths')
+foreach bitdepth : ['8', '16']
+    cdata.set10('CONFIG_@0@BPC'.format(bitdepth), dav1d_bitdepths.contains(bitdepth))
+endforeach
+
+# ASM option
+is_asm_enabled = (get_option('enable_asm') == true and
+    (host_machine.cpu_family() == 'aarch64' or
+     host_machine.cpu_family().startswith('arm') or
+     host_machine.cpu() == 'ppc64le' or
+     host_machine.cpu_family().startswith('riscv') or
+     host_machine.cpu_family().startswith('loongarch') or
+     host_machine.cpu_family() == 'x86' or
+     (host_machine.cpu_family() == 'x86_64' and cc.get_define('__ILP32__').strip() == '')))
+cdata.set10('HAVE_ASM', is_asm_enabled)
+
+if is_asm_enabled and get_option('b_sanitize') == 'memory'
+    error('asm causes false positive with memory sanitizer. Use \'-Denable_asm=false\'.')
+endif
+
+cdata.set10('TRIM_DSP_FUNCTIONS', get_option('trim_dsp') == 'true' or
+    (get_option('trim_dsp') == 'if-release' and get_option('buildtype') == 'release'))
+
+# Logging option
+cdata.set10('CONFIG_LOG', get_option('logging'))
+
+cdata.set10('CONFIG_MACOS_KPERF', get_option('macos_kperf'))
+
+#
+# OS/Compiler checks and defines
+#
+
+# Arguments in test_args will be used even on feature tests
+test_args = []
+
+optional_arguments = []
+optional_link_arguments = []
+
+if host_machine.system() in ['linux', 'gnu', 'emscripten']
+    test_args += '-D_GNU_SOURCE'
+    add_project_arguments('-D_GNU_SOURCE', language: 'c')
+endif
+
+have_clock_gettime = false
+have_posix_memalign = false
+have_memalign = false
+have_aligned_alloc = false
+if host_machine.system() == 'windows'
+    cdata.set('_WIN32_WINNT',           '0x0601')
+    cdata.set('UNICODE',                1) # Define to 1 for Unicode (Wide Chars) APIs
+    cdata.set('_UNICODE',               1) # Define to 1 for Unicode (Wide Chars) APIs
+    cdata.set('__USE_MINGW_ANSI_STDIO', 1) # Define to force use of MinGW printf
+    cdata.set('_CRT_DECLARE_NONSTDC_NAMES', 1) # Define to get off_t from sys/types.h on MSVC
+    if cc.has_function('fseeko', prefix : '#include ', args : test_args)
+        cdata.set('_FILE_OFFSET_BITS', 64) # Not set by default by Meson on Windows
+    else
+        cdata.set('fseeko', '_fseeki64')
+        cdata.set('ftello', '_ftelli64')
+    endif
+
+    if host_machine.cpu_family() == 'x86_64'
+        if cc.get_argument_syntax() != 'msvc'
+            optional_link_arguments += '-Wl,--dynamicbase,--nxcompat,--tsaware,--high-entropy-va'
+        endif
+    elif host_machine.cpu_family() == 'x86' or host_machine.cpu_family() == 'arm'
+        if cc.get_argument_syntax() == 'msvc'
+            optional_link_arguments += '/largeaddressaware'
+        else
+            optional_link_arguments += '-Wl,--dynamicbase,--nxcompat,--tsaware,--large-address-aware'
+        endif
+    endif
+
+    # On Windows, we use a compatibility layer to emulate pthread
+    thread_dependency = []
+    thread_compat_dep = declare_dependency(sources : files('src/win32/thread.c'))
+
+    rt_dependency = []
+
+    rc_version_array = meson.project_version().split('.')
+    winmod = import('windows')
+    rc_data = configuration_data()
+    rc_data.set('PROJECT_VERSION_MAJOR', rc_version_array[0])
+    rc_data.set('PROJECT_VERSION_MINOR', rc_version_array[1])
+    rc_data.set('PROJECT_VERSION_REVISION', rc_version_array[2])
+    rc_data.set('API_VERSION_MAJOR', dav1d_api_version_major)
+    rc_data.set('API_VERSION_MINOR', dav1d_api_version_minor)
+    rc_data.set('API_VERSION_REVISION', dav1d_api_version_revision)
+    rc_data.set('COPYRIGHT_YEARS', '2018-2025')
+else
+    thread_dependency = dependency('threads')
+    thread_compat_dep = []
+
+    rt_dependency = []
+    if cc.has_function('clock_gettime', prefix : '#include ', args : test_args)
+        have_clock_gettime = true
+    elif host_machine.system() not in ['darwin', 'ios', 'tvos']
+        rt_dependency = cc.find_library('rt', required: false)
+        if not cc.has_function('clock_gettime', prefix : '#include ', args : test_args, dependencies : rt_dependency)
+            error('clock_gettime not found')
+        endif
+        have_clock_gettime = true
+    endif
+
+    have_posix_memalign = cc.has_function('posix_memalign', prefix : '#include ', args : test_args)
+    have_memalign = cc.has_function('memalign', prefix : '#include ', args : test_args)
+    have_aligned_alloc = cc.has_function('aligned_alloc', prefix : '#include ', args : test_args)
+endif
+
+cdata.set10('HAVE_CLOCK_GETTIME', have_clock_gettime)
+cdata.set10('HAVE_POSIX_MEMALIGN', have_posix_memalign)
+cdata.set10('HAVE_MEMALIGN', have_memalign)
+cdata.set10('HAVE_ALIGNED_ALLOC', have_aligned_alloc)
+
+# check for fseeko on android. It is not always available if _FILE_OFFSET_BITS is defined to 64
+have_fseeko = true
+if host_machine.system() == 'android'
+    if not cc.has_function('fseeko', prefix : '#include ', args : test_args)
+        if cc.has_function('fseeko', prefix : '#include ', args : test_args + ['-U_FILE_OFFSET_BITS'])
+            warning('Files larger than 2 gigabytes might not be supported in the dav1d CLI tool.')
+            add_project_arguments('-U_FILE_OFFSET_BITS', language: 'c')
+        elif get_option('enable_tools')
+            error('dav1d CLI tool needs fseeko()')
+        else
+            have_fseeko = false
+        endif
+    endif
+endif
+
+libdl_dependency = []
+have_dlsym = false
+if host_machine.system() == 'linux'
+    libdl_dependency = cc.find_library('dl', required : false)
+    have_dlsym = cc.has_function('dlsym', prefix : '#include ', args : test_args, dependencies : libdl_dependency)
+endif
+cdata.set10('HAVE_DLSYM', have_dlsym)
+
+libm_dependency = cc.find_library('m', required: false)
+
+
+# Header checks
+
+stdatomic_dependencies = []
+if not cc.check_header('stdatomic.h')
+    if cc.get_id() == 'msvc'
+        # we have a custom replacement for MSVC
+        stdatomic_dependencies += declare_dependency(
+            include_directories : include_directories('include/compat/msvc'),
+        )
+    elif cc.compiles('''int main() { int v = 0; return __atomic_fetch_add(&v, 1, __ATOMIC_SEQ_CST); }''',
+                     name : 'GCC-style atomics', args : test_args)
+        stdatomic_dependencies += declare_dependency(
+            include_directories : include_directories('include/compat/gcc'),
+        )
+    else
+        error('Atomics not supported')
+    endif
+endif
+
+if host_machine.cpu_family().startswith('wasm')
+    # enable atomics + bulk-memory features
+    stdatomic_dependencies += thread_dependency.partial_dependency(compile_args: true)
+endif
+
+cdata.set10('HAVE_SYS_TYPES_H', cc.check_header('sys/types.h'))
+cdata.set10('HAVE_UNISTD_H', cc.check_header('unistd.h'))
+cdata.set10('HAVE_IO_H', cc.check_header('io.h'))
+
+have_pthread_np = cc.check_header('pthread_np.h')
+cdata.set10('HAVE_PTHREAD_NP_H', have_pthread_np)
+test_args += '-DHAVE_PTHREAD_NP_H=' + (have_pthread_np ? '1' : '0')
+
+# Function checks
+
+if not cc.has_function('getopt_long', prefix : '#include ', args : test_args)
+    getopt_dependency = declare_dependency(
+        sources: files('tools/compat/getopt.c'),
+        include_directories : include_directories('include/compat'),
+    )
+else
+    getopt_dependency = []
+endif
+
+have_getauxval = false
+have_elf_aux_info = false
+if (host_machine.cpu_family() == 'aarch64' or
+    host_machine.cpu_family().startswith('arm') or
+    host_machine.cpu_family().startswith('loongarch') or
+    host_machine.cpu() == 'ppc64le' or
+    host_machine.cpu_family().startswith('riscv'))
+    have_getauxval = cc.has_function('getauxval', prefix : '#include ', args : test_args)
+    have_elf_aux_info = cc.has_function('elf_aux_info', prefix : '#include ', args : test_args)
+endif
+
+cdata.set10('HAVE_GETAUXVAL', have_getauxval)
+cdata.set10('HAVE_ELF_AUX_INFO', have_elf_aux_info)
+
+pthread_np_prefix = '''
+#include 
+#if HAVE_PTHREAD_NP_H
+#include 
+#endif
+'''
+cdata.set10('HAVE_PTHREAD_GETAFFINITY_NP', cc.has_function('pthread_getaffinity_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
+cdata.set10('HAVE_PTHREAD_SETAFFINITY_NP', cc.has_function('pthread_setaffinity_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
+cdata.set10('HAVE_PTHREAD_SETNAME_NP', cc.has_function('pthread_setname_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
+cdata.set10('HAVE_PTHREAD_SET_NAME_NP', cc.has_function('pthread_set_name_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
+
+cdata.set10('HAVE_C11_GENERIC', cc.compiles('int x = _Generic(0, default: 0);', name: '_Generic', args: test_args))
+
+# Compiler flag tests
+
+if cc.has_argument('-fvisibility=hidden')
+    add_project_arguments('-fvisibility=hidden', language: 'c')
+else
+    warning('Compiler does not support -fvisibility=hidden, all symbols will be public!')
+endif
+
+# Compiler flags that should be set
+# But when the compiler does not supports them
+# it is not an error and silently tolerated
+if cc.get_argument_syntax() != 'msvc'
+    optional_arguments += [
+      '-Wundef',
+      '-Werror=vla',
+      '-Wno-maybe-uninitialized',
+      '-Wno-missing-field-initializers',
+      '-Wno-unused-parameter',
+      '-Wstrict-prototypes',
+      '-Werror=missing-prototypes',
+      '-Wshorten-64-to-32',
+    ]
+    if host_machine.cpu_family() == 'x86'
+        optional_arguments += [
+          '-msse2',
+          '-mfpmath=sse',
+        ]
+    endif
+else
+    optional_arguments += [
+      '-wd4028', # parameter different from declaration
+      '-wd4090', # broken with arrays of pointers
+      '-wd4996'  # use of POSIX functions
+    ]
+endif
+
+if (get_option('buildtype') != 'debug' and get_option('buildtype') != 'plain')
+    optional_arguments += '-fomit-frame-pointer'
+    optional_arguments += '-ffast-math'
+endif
+
+if (host_machine.system() in ['darwin', 'ios', 'tvos'] and cc.get_id() == 'clang' and
+    cc.version().startswith('11'))
+    # Workaround for Xcode 11 -fstack-check bug, see #301
+    optional_arguments += '-fno-stack-check'
+endif
+
+if (host_machine.cpu_family() == 'aarch64' or host_machine.cpu_family().startswith('arm'))
+    optional_arguments += '-fno-align-functions'
+endif
+
+add_project_arguments(cc.get_supported_arguments(optional_arguments), language : 'c')
+add_project_link_arguments(cc.get_supported_link_arguments(optional_link_arguments), language : 'c')
+
+# libFuzzer related things
+fuzzing_engine = get_option('fuzzing_engine')
+if fuzzing_engine == 'libfuzzer'
+    if not cc.has_argument('-fsanitize=fuzzer')
+        error('fuzzing_engine libfuzzer requires "-fsanitize=fuzzer"')
+    endif
+    fuzzer_args = ['-fsanitize=fuzzer-no-link', '-fsanitize=fuzzer']
+    add_project_arguments(cc.first_supported_argument(fuzzer_args), language : 'c')
+endif
+
+cdata.set10('ENDIANNESS_BIG', host_machine.endian() == 'big')
+
+if host_machine.cpu_family().startswith('x86')
+    if get_option('stack_alignment') > 0
+        stack_alignment = get_option('stack_alignment')
+    elif host_machine.cpu_family() == 'x86_64' or host_machine.system() in ['linux', 'darwin', 'ios', 'tvos']
+        stack_alignment = 16
+    else
+        stack_alignment = 4
+    endif
+    cdata_asm.set('STACK_ALIGNMENT', stack_alignment)
+endif
+
+#
+# ASM specific stuff
+#
+
+use_gaspp = false
+if (is_asm_enabled and
+    (host_machine.cpu_family() == 'aarch64' or
+     host_machine.cpu_family().startswith('arm')) and
+    cc.get_argument_syntax() == 'msvc' and
+    (cc.get_id() != 'clang-cl' or meson.version().version_compare('<0.58.0')))
+    gaspp = find_program('gas-preprocessor.pl')
+    use_gaspp = true
+    gaspp_args = [
+            '-as-type', 'armasm',
+            '-arch', host_machine.cpu_family(),
+            '--',
+            host_machine.cpu_family() == 'aarch64' ? 'armasm64' : 'armasm',
+            '-nologo',
+            '-I@0@'.format(dav1d_src_root),
+            '-I@0@/'.format(meson.current_build_dir()),
+    ]
+    gaspp_gen = generator(gaspp,
+        output: '@BASENAME@.obj',
+        arguments: gaspp_args + [
+            '@INPUT@',
+            '-c',
+            '-o', '@OUTPUT@'
+        ])
+endif
+
+cdata.set10('ARCH_AARCH64', host_machine.cpu_family() == 'aarch64' or host_machine.cpu() == 'arm64')
+cdata.set10('ARCH_ARM',     host_machine.cpu_family().startswith('arm') and host_machine.cpu() != 'arm64')
+
+have_as_func = false
+have_as_arch = false
+aarch64_extensions = {
+    'dotprod': 'udot v0.4s, v0.16b, v0.16b',
+    'i8mm':    'usdot v0.4s, v0.16b, v0.16b',
+    'sve':     'whilelt p0.s, x0, x1',
+    'sve2':    'sqrdmulh z0.s, z0.s, z0.s',
+}
+supported_aarch64_archexts = []
+supported_aarch64_instructions = []
+if (is_asm_enabled and
+    (host_machine.cpu_family() == 'aarch64' or
+     host_machine.cpu_family().startswith('arm')))
+
+   as_func_code = '''__asm__ (
+".func meson_test"
+".endfunc"
+);
+'''
+    have_as_func = cc.compiles(as_func_code)
+
+    # fedora package build infrastructure uses a gcc specs file to enable
+    # '-fPIE' by default. The chosen way only adds '-fPIE' to the C compiler
+    # with integrated preprocessor. It is not added to the standalone
+    # preprocessor or the preprocessing stage of '.S' files. So we have to
+    # compile code to check if we have to define PIC for the arm asm to
+    # avoid absolute relocations when building for example checkasm.
+    check_pic_code = '''
+#if defined(PIC)
+#error "PIC already defined"
+#elif !(defined(__PIC__) || defined(__pic__))
+#error "no pic"
+#endif
+'''
+    if cc.compiles(check_pic_code)
+        cdata.set('PIC', '3')
+    endif
+
+    if host_machine.cpu_family() == 'aarch64'
+        have_as_arch = cc.compiles('''__asm__ (".arch armv8-a");''')
+        as_arch_str = ''
+        if have_as_arch
+            as_arch_level = 'armv8-a'
+            # Check what .arch levels are supported. In principle, we only
+            # want to detect up to armv8.2-a here (binutils requires that
+            # in order to enable i8mm). However, older Clang versions
+            # (before Clang 17, and Xcode versions up to and including 15.0)
+            # didn't support controlling dotprod/i8mm extensions via
+            # .arch_extension, therefore try to enable a high enough .arch
+            # level as well, to implicitly make them available via that.
+            foreach arch : ['armv8.2-a', 'armv8.4-a', 'armv8.6-a']
+                if cc.compiles('__asm__ (".arch ' + arch + '\\n");')
+                    as_arch_level = arch
+                endif
+            endforeach
+            # Clang versions before 17 also had a bug
+            # (https://github.com/llvm/llvm-project/issues/32220)
+            # causing a plain ".arch " to not have any effect unless it
+            # had an extra "+" included - but it was activated on the
+            # next ".arch_extension" directive instead. Check if we can include
+            # "+crc" as dummy feature to make the .arch directive behave as
+            # expected and take effect right away.
+            if cc.compiles('__asm__ (".arch ' + as_arch_level + '+crc\\n");')
+                as_arch_level = as_arch_level + '+crc'
+            endif
+            cdata.set('AS_ARCH_LEVEL', as_arch_level)
+            as_arch_str = '".arch ' + as_arch_level + '\\n"'
+        endif
+        if use_gaspp
+            python3 = import('python').find_installation()
+        endif
+        foreach name, instr : aarch64_extensions
+            if use_gaspp
+                f = configure_file(
+                    command: [python3, '-c', 'import sys; print(sys.argv[1])', '@0@'.format(instr)],
+                    output: 'test-@0@.S'.format(name),
+                    capture: true)
+                r = run_command(gaspp, gaspp_args, f, '-c', '-o', meson.current_build_dir() / 'test-' + name + '.obj', check: false)
+                message('Checking for gaspp/armasm64 ' + name.to_upper() + ': ' + (r.returncode() == 0 ? 'YES' : 'NO'))
+                if r.returncode() == 0
+                    supported_aarch64_instructions += name
+                endif
+            else
+                # Test for support for the various extensions. First test if
+                # the assembler supports the .arch_extension directive for
+                # enabling/disabling the extension, then separately check whether
+                # the instructions themselves are supported. Even if .arch_extension
+                # isn't supported, we may be able to assemble the instructions
+                # if the .arch level includes support for them.
+                code = '__asm__ (' + as_arch_str
+                code += '".arch_extension ' + name + '\\n"'
+                code += ');'
+                supports_archext = cc.compiles(code)
+                code = '__asm__ (' + as_arch_str
+                if supports_archext
+                    supported_aarch64_archexts += name
+                    code += '".arch_extension ' + name + '\\n"'
+                endif
+                code += '"' + instr + '\\n"'
+                code += ');'
+                if cc.compiles(code, name: name.to_upper())
+                    supported_aarch64_instructions += name
+                endif
+            endif
+        endforeach
+    endif
+endif
+
+cdata.set10('HAVE_AS_FUNC', have_as_func)
+cdata.set10('HAVE_AS_ARCH_DIRECTIVE', have_as_arch)
+foreach name, _ : aarch64_extensions
+    cdata.set10('HAVE_AS_ARCHEXT_' + name.to_upper() + '_DIRECTIVE', name in supported_aarch64_archexts)
+    cdata.set10('HAVE_' + name.to_upper(), name in supported_aarch64_instructions)
+endforeach
+
+cdata.set10('ARCH_X86', host_machine.cpu_family().startswith('x86'))
+cdata.set10('ARCH_X86_64', host_machine.cpu_family() == 'x86_64')
+cdata.set10('ARCH_X86_32', host_machine.cpu_family() == 'x86')
+
+if host_machine.cpu_family().startswith('x86')
+    cdata_asm.set('private_prefix', 'dav1d')
+    cdata_asm.set10('ARCH_X86_64', host_machine.cpu_family() == 'x86_64')
+    cdata_asm.set10('ARCH_X86_32', host_machine.cpu_family() == 'x86')
+    cdata_asm.set10('PIC', true)
+
+    # Convert SSE asm into (128-bit) AVX when compiler flags are set to use AVX instructions
+    cdata_asm.set10('FORCE_VEX_ENCODING', cc.get_define('__AVX__').strip() != '')
+endif
+
+cdata.set10('ARCH_PPC64LE', host_machine.cpu() == 'ppc64le')
+
+cdata.set10('ARCH_RISCV', host_machine.cpu_family().startswith('riscv'))
+cdata.set10('ARCH_RV32', host_machine.cpu_family() == 'riscv32')
+cdata.set10('ARCH_RV64', host_machine.cpu_family() == 'riscv64')
+
+cdata.set10('ARCH_LOONGARCH', host_machine.cpu_family().startswith('loongarch'))
+cdata.set10('ARCH_LOONGARCH32', host_machine.cpu_family() == 'loongarch32')
+cdata.set10('ARCH_LOONGARCH64', host_machine.cpu_family() == 'loongarch64')
+
+# meson's cc.symbols_have_underscore_prefix() is unfortunately unrelieably
+# when additional flags like '-fprofile-instr-generate' are passed via CFLAGS
+# see following meson issue https://github.com/mesonbuild/meson/issues/5482
+if (host_machine.system() in ['darwin', 'ios', 'tvos'] or
+   (host_machine.system() == 'windows' and host_machine.cpu_family() == 'x86'))
+    cdata.set10('PREFIX', true)
+    cdata_asm.set10('PREFIX', true)
+endif
+
+if is_asm_enabled and host_machine.cpu_family().startswith('x86')
+
+    # NASM compiler support
+
+    nasm = find_program('nasm')
+
+    # check NASM version
+    if nasm.found()
+        nasm_r = run_command(nasm, '-v', check: true)
+
+        out = nasm_r.stdout().strip().split()
+        if out[1].to_lower() == 'version'
+            if out[2].version_compare('<2.14')
+                error('nasm 2.14 or later is required, found nasm @0@'.format(out[2]))
+            endif
+        else
+            error('unexpected nasm version string: @0@'.format(nasm_r.stdout()))
+        endif
+    endif
+
+    # Generate config.asm
+    config_asm_target = configure_file(output: 'config.asm', output_format: 'nasm', configuration: cdata_asm)
+
+    if host_machine.system() == 'windows'
+        nasm_format = 'win'
+    elif host_machine.system() in ['darwin', 'ios', 'tvos']
+        nasm_format = 'macho'
+    else
+        nasm_format = 'elf'
+    endif
+    if host_machine.cpu_family() == 'x86_64'
+        nasm_format += '64'
+    else
+        nasm_format += '32'
+    endif
+
+    nasm_gen = generator(nasm,
+        output: '@BASENAME@.obj',
+        depfile: '@BASENAME@.obj.ndep',
+        arguments: [
+            '-f', nasm_format,
+            '-I', '@0@/src/'.format(dav1d_src_root),
+            '-I', '@0@/'.format(meson.current_build_dir()),
+            '-MQ', '@OUTPUT@', '-MF', '@DEPFILE@',
+            '@EXTRA_ARGS@',
+            '@INPUT@',
+            '-o', '@OUTPUT@'
+        ])
+endif
+
+if is_asm_enabled and host_machine.cpu_family().startswith('riscv')
+    as_option_code = '''__asm__ (
+".option arch, +v\n"
+"vsetivli zero, 0, e8, m1, ta, ma"
+);
+'''
+    if not cc.compiles(as_option_code, name : 'RISC-V Vector')
+        error('Compiler doesn\'t support \'.option arch\' asm directive. Update to binutils>=2.38 or clang>=17 or use \'-Denable_asm=false\'.')
+    endif
+endif
+
+# Generate config.h
+config_h_target = configure_file(output: 'config.h', configuration: cdata)
+
+
+
+#
+# Include subdir meson.build files
+# The order is important!
+
+subdir('include')
+
+subdir('doc')
+
+subdir('src')
+
+subdir('tools')
+
+subdir('examples')
+
+subdir('tests')
diff --git a/media/libdav1d/src/meson_options.txt b/media/libdav1d/src/meson_options.txt
new file mode 100644
index 0000000000..b0b45b474d
--- /dev/null
+++ b/media/libdav1d/src/meson_options.txt
@@ -0,0 +1,75 @@
+# General options
+
+option('bitdepths',
+    type: 'array',
+    choices: ['8', '16'],
+    description: 'Enable only specified bitdepths')
+
+option('enable_asm',
+    type: 'boolean',
+    value: true,
+    description: 'Build asm files, if available')
+
+option('enable_tools',
+    type: 'boolean',
+    value: true,
+    description: 'Build dav1d cli tools')
+
+option('enable_examples',
+    type: 'boolean',
+    value: false,
+    description: 'Build dav1d examples')
+
+option('enable_tests',
+    type: 'boolean',
+    value: true,
+    description: 'Build dav1d tests')
+
+option('enable_seek_stress',
+    type: 'boolean',
+    value: false,
+    description: 'Build seek_stress test tool')
+
+option('enable_docs',
+    type: 'boolean',
+    value: false,
+    description: 'Build dav1d documentation')
+
+option('logging',
+    type: 'boolean',
+    value: true,
+    description: 'Print error log messages using the provided callback function')
+
+option('testdata_tests',
+    type: 'boolean',
+    value: false,
+    description: 'Run tests requiring the test data repository')
+
+option('fuzzing_engine',
+    type: 'combo',
+    choices : ['none', 'libfuzzer', 'oss-fuzz'],
+    value: 'none',
+    description: 'Select the fuzzing engine')
+
+option('fuzzer_ldflags',
+    type: 'string',
+    description: 'Extra LDFLAGS used during linking of fuzzing binaries')
+
+option('stack_alignment',
+    type: 'integer',
+    value: 0)
+
+option('xxhash_muxer',
+    type : 'feature',
+    value : 'auto')
+
+option('trim_dsp',
+    type: 'combo',
+    choices: ['true', 'false', 'if-release'],
+    value: 'if-release',
+    description: 'Eliminate redundant DSP functions where possible')
+
+option('macos_kperf',
+    type: 'boolean',
+    value: false,
+    description: 'Use the private macOS kperf API for benchmarking')
diff --git a/media/libdav1d/src/package/crossfiles/aarch64-android.meson b/media/libdav1d/src/package/crossfiles/aarch64-android.meson
new file mode 100644
index 0000000000..abb64e662f
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/aarch64-android.meson
@@ -0,0 +1,15 @@
+[binaries]
+c = 'aarch64-linux-android21-clang'
+cpp = 'aarch64-linux-android21-clang++'
+ar = 'llvm-ar'
+strip = 'llvm-strip'
+pkgconfig = 'pkg-config'
+
+[properties]
+needs_exe_wrapper = true
+
+[host_machine]
+system = 'android'
+cpu_family = 'aarch64'
+cpu = 'aarch64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/aarch64-linux-clang.meson b/media/libdav1d/src/package/crossfiles/aarch64-linux-clang.meson
new file mode 100644
index 0000000000..2d218c7cb4
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/aarch64-linux-clang.meson
@@ -0,0 +1,16 @@
+[binaries]
+c = 'clang'
+cpp = 'clang++'
+ar = 'aarch64-linux-gnu-ar'
+strip = 'aarch64-linux-gnu-strip'
+exe_wrapper = 'qemu-aarch64'
+
+[properties]
+c_args = '-target aarch64-linux-gnu'
+c_link_args = '-target aarch64-linux-gnu'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'aarch64'
+cpu = 'aarch64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/aarch64-linux.meson b/media/libdav1d/src/package/crossfiles/aarch64-linux.meson
new file mode 100644
index 0000000000..7dae0fc874
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/aarch64-linux.meson
@@ -0,0 +1,12 @@
+[binaries]
+c = 'aarch64-linux-gnu-gcc'
+cpp = 'aarch64-linux-gnu-g++'
+ar = 'aarch64-linux-gnu-ar'
+strip = 'aarch64-linux-gnu-strip'
+exe_wrapper = 'qemu-aarch64'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'aarch64'
+cpu = 'aarch64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/aarch64-w64-mingw32.meson b/media/libdav1d/src/package/crossfiles/aarch64-w64-mingw32.meson
new file mode 100644
index 0000000000..23927cc634
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/aarch64-w64-mingw32.meson
@@ -0,0 +1,16 @@
+[binaries]
+c = 'aarch64-w64-mingw32-clang'
+cpp = 'aarch64-w64-mingw32-clang++'
+ar = 'aarch64-w64-mingw32-ar'
+strip = 'aarch64-w64-mingw32-strip'
+pkgconfig = 'pkg-config'
+windres = 'aarch64-w64-mingw32-windres'
+
+[properties]
+c_link_args = ['-static-libgcc']
+
+[host_machine]
+system = 'windows'
+cpu_family = 'aarch64'
+cpu = 'aarch64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/arm-android.meson b/media/libdav1d/src/package/crossfiles/arm-android.meson
new file mode 100644
index 0000000000..ed94f698ec
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/arm-android.meson
@@ -0,0 +1,15 @@
+[binaries]
+c = 'armv7a-linux-androideabi21-clang'
+cpp = 'armv7a-linux-androideabi21-clang++'
+ar = 'llvm-ar'
+strip = 'llvm-strip'
+pkgconfig = 'pkg-config'
+
+[properties]
+needs_exe_wrapper = true
+
+[host_machine]
+system = 'android'
+cpu_family = 'arm'
+cpu = 'arm'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/arm64-iPhoneOS.meson b/media/libdav1d/src/package/crossfiles/arm64-iPhoneOS.meson
new file mode 100644
index 0000000000..20312270a6
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/arm64-iPhoneOS.meson
@@ -0,0 +1,27 @@
+[binaries]
+c = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
+cpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
+objc = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
+objcpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
+ar = 'ar'
+strip = 'strip'
+
+[built-in options]
+c_args = ['-miphoneos-version-min=11.0']
+cpp_args = ['-miphoneos-version-min=11.0']
+c_link_args = ['-miphoneos-version-min=11.0']
+cpp_link_args = ['-miphoneos-version-min=11.0']
+objc_args = ['-miphoneos-version-min=11.0']
+objcpp_args = ['-miphoneos-version-min=11.0']
+
+[properties]
+root = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer'
+needs_exe_wrapper = true
+
+[host_machine]
+system = 'darwin'
+subsystem = 'ios'
+kernel = 'xnu'
+cpu_family = 'aarch64'
+cpu = 'aarch64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/armv7-w64-mingw32.meson b/media/libdav1d/src/package/crossfiles/armv7-w64-mingw32.meson
new file mode 100644
index 0000000000..191aa2efd3
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/armv7-w64-mingw32.meson
@@ -0,0 +1,16 @@
+[binaries]
+c = 'armv7-w64-mingw32-clang'
+cpp = 'armv7-w64-mingw32-clang++'
+ar = 'armv7-w64-mingw32-ar'
+strip = 'armv7-w64-mingw32-strip'
+pkgconfig = 'pkg-config'
+windres = 'armv7-w64-mingw32-windres'
+
+[properties]
+c_link_args = ['-static-libgcc']
+
+[host_machine]
+system = 'windows'
+cpu_family = 'arm'
+cpu = 'armv7'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/i686-linux32.meson b/media/libdav1d/src/package/crossfiles/i686-linux32.meson
new file mode 100644
index 0000000000..84be1b8b1d
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/i686-linux32.meson
@@ -0,0 +1,15 @@
+[binaries]
+c = 'gcc'
+cpp = 'g++'
+ar = 'ar'
+strip = 'strip'
+
+[properties]
+c_link_args = ['-m32', '-Wl,-z,text']
+c_args = ['-m32']
+
+[host_machine]
+system = 'linux'
+cpu_family = 'x86'
+cpu = 'i686'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/i686-w64-mingw32.meson b/media/libdav1d/src/package/crossfiles/i686-w64-mingw32.meson
new file mode 100644
index 0000000000..3de8afaa0d
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/i686-w64-mingw32.meson
@@ -0,0 +1,16 @@
+[binaries]
+c = 'i686-w64-mingw32-gcc'
+cpp = 'i686-w64-mingw32-g++'
+ar = 'i686-w64-mingw32-ar'
+strip = 'i686-w64-mingw32-strip'
+windres = 'i686-w64-mingw32-windres'
+exe_wrapper = 'wine'
+
+[properties]
+c_link_args = ['-static-libgcc']
+
+[host_machine]
+system = 'windows'
+cpu_family = 'x86'
+cpu = 'i686'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/loongarch64-linux.meson b/media/libdav1d/src/package/crossfiles/loongarch64-linux.meson
new file mode 100644
index 0000000000..04c29acf1c
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/loongarch64-linux.meson
@@ -0,0 +1,13 @@
+[binaries]
+c = 'loongarch64-unknown-linux-gnu-gcc'
+cpp = 'loongarch64-unknown-linux-gnu-c++'
+ar = 'loongarch64-unknown-linux-gnu-ar'
+strip = 'loongarch64-unknown-linux-gnu-strip'
+pkgconfig = 'pkg-config'
+exe_wrapper = 'qemu-loongarch64'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'loongarch64'
+cpu = 'loongarch64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/riscv64-linux-clang.meson b/media/libdav1d/src/package/crossfiles/riscv64-linux-clang.meson
new file mode 100644
index 0000000000..c16d74d0ca
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/riscv64-linux-clang.meson
@@ -0,0 +1,16 @@
+[binaries]
+c = 'clang'
+cpp = 'clang++'
+ar = 'riscv64-linux-gnu-ar'
+strip = 'riscv64-linux-gnu-strip'
+exe_wrapper = 'qemu-riscv64'
+
+[properties]
+c_args = '-target riscv64-linux-gnu'
+c_link_args = '-target riscv64-linux-gnu'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'riscv64'
+cpu = 'riscv64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/riscv64-linux.meson b/media/libdav1d/src/package/crossfiles/riscv64-linux.meson
new file mode 100644
index 0000000000..e3eda5e8bb
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/riscv64-linux.meson
@@ -0,0 +1,12 @@
+[binaries]
+c = 'riscv64-linux-gnu-gcc'
+cpp = 'riscv64-linux-gnu-g++'
+ar = 'riscv64-linux-gnu-ar'
+strip = 'riscv64-linux-gnu-strip'
+exe_wrapper = 'qemu-riscv64'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'riscv64'
+cpu = 'riscv64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/wasm32.meson b/media/libdav1d/src/package/crossfiles/wasm32.meson
new file mode 100644
index 0000000000..a34a8a14bd
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/wasm32.meson
@@ -0,0 +1,15 @@
+[binaries]
+c = 'emcc'
+cpp = 'em++'
+ar = 'emar'
+strip = 'emstrip'
+exe_wrapper = 'node'
+
+[properties]
+c_link_args = ['-sEXPORT_ALL=1']
+
+[host_machine]
+system = 'emscripten'
+cpu_family = 'wasm32'
+cpu = 'wasm32'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/wasm64.meson b/media/libdav1d/src/package/crossfiles/wasm64.meson
new file mode 100644
index 0000000000..2ababd9b4b
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/wasm64.meson
@@ -0,0 +1,15 @@
+[binaries]
+c = 'emcc'
+cpp = 'em++'
+ar = 'emar'
+strip = 'emstrip'
+exe_wrapper = 'node'
+
+[properties]
+c_link_args = ['-sEXPORT_ALL=1']
+
+[host_machine]
+system = 'emscripten'
+cpu_family = 'wasm64'
+cpu = 'wasm64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/x86-android.meson b/media/libdav1d/src/package/crossfiles/x86-android.meson
new file mode 100644
index 0000000000..62ac64c226
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/x86-android.meson
@@ -0,0 +1,15 @@
+[binaries]
+c = 'i686-linux-android19-clang'
+cpp = 'i686-linux-android19-clang++'
+ar = 'llvm-ar'
+strip = 'llvm-strip'
+pkgconfig = 'pkg-config'
+
+[properties]
+needs_exe_wrapper = true
+
+[host_machine]
+system = 'android'
+cpu_family = 'x86'
+cpu = 'i686'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/x86_64-android.meson b/media/libdav1d/src/package/crossfiles/x86_64-android.meson
new file mode 100644
index 0000000000..c70ba08f88
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/x86_64-android.meson
@@ -0,0 +1,15 @@
+[binaries]
+c = 'x86_64-linux-android21-clang'
+cpp = 'x86_64-linux-android21-clang++'
+ar = 'llvm-ar'
+strip = 'llvm-strip'
+pkgconfig = 'pkg-config'
+
+[properties]
+needs_exe_wrapper = true
+
+[host_machine]
+system = 'android'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/x86_64-iPhoneSimulator.meson b/media/libdav1d/src/package/crossfiles/x86_64-iPhoneSimulator.meson
new file mode 100644
index 0000000000..fb8a24cafc
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/x86_64-iPhoneSimulator.meson
@@ -0,0 +1,27 @@
+[binaries]
+c = ['clang', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
+cpp = ['clang++', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
+objc = ['clang', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
+objcpp = ['clang++', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
+ar = 'ar'
+strip = 'strip'
+
+[built-in options]
+c_args = ['-miphoneos-version-min=11.0']
+cpp_args = ['-miphoneos-version-min=11.0']
+c_link_args = ['-miphoneos-version-min=11.0']
+cpp_link_args = ['-miphoneos-version-min=11.0']
+objc_args = ['-miphoneos-version-min=11.0']
+objcpp_args = ['-miphoneos-version-min=11.0']
+
+[properties]
+root = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer'
+needs_exe_wrapper = true
+
+[host_machine]
+system = 'darwin'
+subsystem = 'ios-simulator'
+kernel = 'xnu'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/crossfiles/x86_64-w64-mingw32.meson b/media/libdav1d/src/package/crossfiles/x86_64-w64-mingw32.meson
new file mode 100644
index 0000000000..a7b901f7ed
--- /dev/null
+++ b/media/libdav1d/src/package/crossfiles/x86_64-w64-mingw32.meson
@@ -0,0 +1,16 @@
+[binaries]
+c = 'x86_64-w64-mingw32-gcc'
+cpp = 'x86_64-w64-mingw32-g++'
+ar = 'x86_64-w64-mingw32-ar'
+strip = 'x86_64-w64-mingw32-strip'
+windres = 'x86_64-w64-mingw32-windres'
+exe_wrapper = 'wine'
+
+[properties]
+c_link_args = ['-static-libgcc']
+
+[host_machine]
+system = 'windows'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
diff --git a/media/libdav1d/src/package/snap/snapcraft.yaml b/media/libdav1d/src/package/snap/snapcraft.yaml
new file mode 100644
index 0000000000..cecd0bd453
--- /dev/null
+++ b/media/libdav1d/src/package/snap/snapcraft.yaml
@@ -0,0 +1,24 @@
+name: dav1d
+base: core18
+version: git
+version-script: git describe HEAD --always
+summary: AV1 decoder from VideoLAN
+description: |
+  A small and fast AV1 decoder from the people who brought you VLC.
+
+grade: stable
+confinement: strict # use 'strict' once you have the right plugs and slots
+
+apps:
+  dav1d:
+    command: usr/bin/dav1d
+    plugs: [ 'home' ]
+
+parts:
+  dav1d:
+    plugin: meson
+    source: ../../
+    build-packages: [ 'nasm' ]
+    meson-parameters:
+      - --prefix=/usr
+      - --buildtype=release
diff --git a/media/libdav1d/src/src/arm/32/cdef.S b/media/libdav1d/src/src/arm/32/cdef.S
new file mode 100644
index 0000000000..4a0df6eac8
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/cdef.S
@@ -0,0 +1,540 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+#include "cdef_tmpl.S"
+
+// n1 = s0/d0
+// w1 = d0/q0
+// n2 = s4/d2
+// w2 = d2/q1
+.macro pad_top_bottom s1, s2, w, stride, n1, w1, n2, w2, align, ret
+        tst             r7,  #1 // CDEF_HAVE_LEFT
+        beq             2f
+        // CDEF_HAVE_LEFT
+        tst             r7,  #2 // CDEF_HAVE_RIGHT
+        beq             1f
+        // CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+        ldrh            r12, [\s1, #-2]
+        vldr            \n1, [\s1]
+        vdup.16         d4,  r12
+        ldrh            r12, [\s1, #\w]
+        vmov.16         d4[1], r12
+        ldrh            r12, [\s2, #-2]
+        vldr            \n2, [\s2]
+        vmov.16         d4[2], r12
+        ldrh            r12, [\s2, #\w]
+        vmovl.u8        q0,  d0
+        vmov.16         d4[3], r12
+        vmovl.u8        q1,  d2
+        vmovl.u8        q2,  d4
+        vstr            s8,  [r0, #-4]
+        vst1.16         {\w1}, [r0, :\align]
+        vstr            s9,  [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        vstr            s10, [r0, #-4]
+        vst1.16         {\w2}, [r0, :\align]
+        vstr            s11, [r0, #2*\w]
+.if \ret
+        pop             {r4-r8,pc}
+.else
+        add             r0,  r0,  #2*\stride
+        b               3f
+.endif
+
+1:
+        // CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        ldrh            r12, [\s1, #-2]
+        vldr            \n1, [\s1]
+        vdup.16         d4,  r12
+        ldrh            r12, [\s2, #-2]
+        vldr            \n2, [\s2]
+        vmovl.u8        q0,  d0
+        vmov.16         d4[1], r12
+        vmovl.u8        q1,  d2
+        vmovl.u8        q2,  d4
+        vstr            s8,  [r0, #-4]
+        vst1.16         {\w1}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        vstr            s9,  [r0, #-4]
+        vst1.16         {\w2}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+.if \ret
+        pop             {r4-r8,pc}
+.else
+        add             r0,  r0,  #2*\stride
+        b               3f
+.endif
+
+2:
+        // !CDEF_HAVE_LEFT
+        tst             r7,  #2 // CDEF_HAVE_RIGHT
+        beq             1f
+        // !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+        vldr            \n1, [\s1]
+        ldrh            r12, [\s1, #\w]
+        vldr            \n2, [\s2]
+        vdup.16         d4,  r12
+        ldrh            r12, [\s2, #\w]
+        vmovl.u8        q0,  d0
+        vmov.16         d4[1], r12
+        vmovl.u8        q1,  d2
+        vmovl.u8        q2,  d4
+        vstr            s12, [r0, #-4]
+        vst1.16         {\w1}, [r0, :\align]
+        vstr            s8,  [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        vstr            s12, [r0, #-4]
+        vst1.16         {\w2}, [r0, :\align]
+        vstr            s9,  [r0, #2*\w]
+.if \ret
+        pop             {r4-r8,pc}
+.else
+        add             r0,  r0,  #2*\stride
+        b               3f
+.endif
+
+1:
+        // !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        vldr            \n1, [\s1]
+        vldr            \n2, [\s2]
+        vmovl.u8        q0,  d0
+        vmovl.u8        q1,  d2
+        vstr            s12, [r0, #-4]
+        vst1.16         {\w1}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        vstr            s12, [r0, #-4]
+        vst1.16         {\w2}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+.if \ret
+        pop             {r4-r8,pc}
+.else
+        add             r0,  r0,  #2*\stride
+.endif
+3:
+.endm
+
+.macro load_n_incr dst, src, incr, w
+.if \w == 4
+        vld1.32         {\dst\()[0]}, [\src, :32], \incr
+.else
+        vld1.8          {\dst\()},    [\src, :64], \incr
+.endif
+.endm
+
+// void dav1d_cdef_paddingX_8bpc_neon(uint16_t *tmp, const pixel *src,
+//                                    ptrdiff_t src_stride, const pixel (*left)[2],
+//                                    const pixel *const top,
+//                                    const pixel *const bottom, int h,
+//                                    enum CdefEdgeFlags edges);
+
+// n1 = s0/d0
+// w1 = d0/q0
+// n2 = s4/d2
+// w2 = d2/q1
+.macro padding_func w, stride, n1, w1, n2, w2, align
+function cdef_padding\w\()_8bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldrd            r6,  r7,  [sp, #32]
+        cmp             r7,  #0xf // fully edged
+        beq             cdef_padding\w\()_edged_8bpc_neon
+        vmov.i16        q3,  #0x8000
+        tst             r7,  #4 // CDEF_HAVE_TOP
+        bne             1f
+        // !CDEF_HAVE_TOP
+        sub             r12, r0,  #2*(2*\stride+2)
+        vmov.i16        q2,  #0x8000
+        vst1.16         {q2,q3}, [r12]!
+.if \w == 8
+        vst1.16         {q2,q3}, [r12]!
+.endif
+        b               3f
+1:
+        // CDEF_HAVE_TOP
+        add             r8,  r4,  r2
+        sub             r0,  r0,  #2*(2*\stride)
+        pad_top_bottom  r4,  r8,  \w, \stride, \n1, \w1, \n2, \w2, \align, 0
+
+        // Middle section
+3:
+        tst             r7,  #1 // CDEF_HAVE_LEFT
+        beq             2f
+        // CDEF_HAVE_LEFT
+        tst             r7,  #2 // CDEF_HAVE_RIGHT
+        beq             1f
+        // CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+0:
+        vld1.16         {d2[]}, [r3, :16]!
+        ldrh            r12, [r1, #\w]
+        load_n_incr     d0,  r1,  r2,  \w
+        subs            r6,  r6,  #1
+        vmov.16         d2[1], r12
+        vmovl.u8        q0,  d0
+        vmovl.u8        q1,  d2
+        vstr            s4,  [r0, #-4]
+        vst1.16         {\w1}, [r0, :\align]
+        vstr            s5,  [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        bgt             0b
+        b               3f
+1:
+        // CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        vld1.16         {d2[]}, [r3, :16]!
+        load_n_incr     d0,  r1,  r2,  \w
+        subs            r6,  r6,  #1
+        vmovl.u8        q0,  d0
+        vmovl.u8        q1,  d2
+        vstr            s4,  [r0, #-4]
+        vst1.16         {\w1}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        bgt             1b
+        b               3f
+2:
+        tst             r7,  #2 // CDEF_HAVE_RIGHT
+        beq             1f
+        // !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+0:
+        ldrh            r12, [r1, #\w]
+        load_n_incr     d0,  r1,  r2,  \w
+        vdup.16         d2,  r12
+        subs            r6,  r6,  #1
+        vmovl.u8        q0,  d0
+        vmovl.u8        q1,  d2
+        vstr            s12, [r0, #-4]
+        vst1.16         {\w1}, [r0, :\align]
+        vstr            s4,  [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        bgt             0b
+        b               3f
+1:
+        // !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        load_n_incr     d0,  r1,  r2,  \w
+        subs            r6,  r6,  #1
+        vmovl.u8        q0,  d0
+        vstr            s12, [r0, #-4]
+        vst1.16         {\w1}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        bgt             1b
+
+3:
+        tst             r7,  #8 // CDEF_HAVE_BOTTOM
+        bne             1f
+        // !CDEF_HAVE_BOTTOM
+        sub             r12, r0,  #4
+        vmov.i16        q2,  #0x8000
+        vst1.16         {q2,q3}, [r12]!
+.if \w == 8
+        vst1.16         {q2,q3}, [r12]!
+.endif
+        pop             {r4-r8,pc}
+1:
+        // CDEF_HAVE_BOTTOM
+        add             r8,  r5,  r2
+        pad_top_bottom  r5,  r8,  \w, \stride, \n1, \w1, \n2, \w2, \align, 1
+endfunc
+.endm
+
+padding_func 8, 16, d0, q0, d2, q1, 128
+padding_func 4, 8,  s0, d0, s4, d2, 64
+
+// void cdef_paddingX_edged_8bpc_neon(uint16_t *tmp, const pixel *src,
+//                                    ptrdiff_t src_stride, const pixel (*left)[2],
+//                                    const pixel *const top,
+//                                    const pixel *const bottom, int h,
+//                                    enum CdefEdgeFlags edges);
+
+.macro padding_func_edged w, stride, reg, align
+function cdef_padding\w\()_edged_8bpc_neon
+        sub             r0,  r0,  #(2*\stride)
+
+        ldrh            r12, [r4, #-2]
+        vldr            \reg, [r4]
+        add             r8,  r4,  r2
+        strh            r12, [r0, #-2]
+        ldrh            r12, [r4, #\w]
+        vstr            \reg, [r0]
+        strh            r12, [r0, #\w]
+
+        ldrh            r12, [r8, #-2]
+        vldr            \reg, [r8]
+        strh            r12, [r0, #\stride-2]
+        ldrh            r12, [r8, #\w]
+        vstr            \reg, [r0, #\stride]
+        strh            r12, [r0, #\stride+\w]
+        add             r0,  r0,  #2*\stride
+
+0:
+        ldrh            r12, [r3], #2
+        vldr            \reg, [r1]
+        str             r12, [r0, #-2]
+        ldrh            r12, [r1, #\w]
+        add             r1,  r1,  r2
+        subs            r6,  r6,  #1
+        vstr            \reg, [r0]
+        str             r12, [r0, #\w]
+        add             r0,  r0,  #\stride
+        bgt             0b
+
+        ldrh            r12, [r5, #-2]
+        vldr            \reg, [r5]
+        add             r8,  r5,  r2
+        strh            r12, [r0, #-2]
+        ldrh            r12, [r5, #\w]
+        vstr            \reg, [r0]
+        strh            r12, [r0, #\w]
+
+        ldrh            r12, [r8, #-2]
+        vldr            \reg, [r8]
+        strh            r12, [r0, #\stride-2]
+        ldrh            r12, [r8, #\w]
+        vstr            \reg, [r0, #\stride]
+        strh            r12, [r0, #\stride+\w]
+
+        pop             {r4-r8,pc}
+endfunc
+.endm
+
+padding_func_edged 8, 16, d0, 64
+padding_func_edged 4, 8,  s0, 32
+
+tables
+
+filter 8, 8
+filter 4, 8
+
+find_dir 8
+
+.macro load_px_8 d11, d12, d21, d22, w
+.if \w == 8
+        add             r6,  r2,  r9         // x + off
+        sub             r9,  r2,  r9         // x - off
+        vld1.8          {\d11}, [r6]         // p0
+        add             r6,  r6,  #16        // += stride
+        vld1.8          {\d21}, [r9]         // p1
+        add             r9,  r9,  #16        // += stride
+        vld1.8          {\d12}, [r6]         // p0
+        vld1.8          {\d22}, [r9]         // p1
+.else
+        add             r6,  r2,  r9         // x + off
+        sub             r9,  r2,  r9         // x - off
+        vld1.32         {\d11[0]}, [r6]      // p0
+        add             r6,  r6,  #8         // += stride
+        vld1.32         {\d21[0]}, [r9]      // p1
+        add             r9,  r9,  #8         // += stride
+        vld1.32         {\d11[1]}, [r6]      // p0
+        add             r6,  r6,  #8         // += stride
+        vld1.32         {\d21[1]}, [r9]      // p1
+        add             r9,  r9,  #8         // += stride
+        vld1.32         {\d12[0]}, [r6]      // p0
+        add             r6,  r6,  #8         // += stride
+        vld1.32         {\d22[0]}, [r9]      // p1
+        add             r9,  r9,  #8         // += stride
+        vld1.32         {\d12[1]}, [r6]      // p0
+        vld1.32         {\d22[1]}, [r9]      // p1
+.endif
+.endm
+.macro handle_pixel_8 s1, s2, thresh_vec, shift, tap, min
+.if \min
+        vmin.u8         q3,  q3,  \s1
+        vmax.u8         q4,  q4,  \s1
+        vmin.u8         q3,  q3,  \s2
+        vmax.u8         q4,  q4,  \s2
+.endif
+        vabd.u8         q8,  q0,  \s1        // abs(diff)
+        vabd.u8         q11, q0,  \s2        // abs(diff)
+        vshl.u8         q9,  q8,  \shift     // abs(diff) >> shift
+        vshl.u8         q12, q11, \shift     // abs(diff) >> shift
+        vqsub.u8        q9,  \thresh_vec, q9 // clip = imax(0, threshold - (abs(diff) >> shift))
+        vqsub.u8        q12, \thresh_vec, q12// clip = imax(0, threshold - (abs(diff) >> shift))
+        vcgt.u8         q10, q0,  \s1        // px > p0
+        vcgt.u8         q13, q0,  \s2        // px > p1
+        vmin.u8         q9,  q9,  q8         // imin(abs(diff), clip)
+        vmin.u8         q12, q12, q11        // imin(abs(diff), clip)
+        vneg.s8         q8,  q9              // -imin()
+        vneg.s8         q11, q12             // -imin()
+        vbsl            q10, q8,  q9         // constrain() = imax(imin(diff, clip), -clip)
+        vdup.8          d18, \tap            // taps[k]
+        vbsl            q13, q11, q12        // constrain() = imax(imin(diff, clip), -clip)
+        vmlal.s8        q1,  d20, d18        // sum += taps[k] * constrain()
+        vmlal.s8        q1,  d26, d18        // sum += taps[k] * constrain()
+        vmlal.s8        q2,  d21, d18        // sum += taps[k] * constrain()
+        vmlal.s8        q2,  d27, d18        // sum += taps[k] * constrain()
+.endm
+
+// void cdef_filterX_edged_neon(pixel *dst, ptrdiff_t dst_stride,
+//                              const uint16_t *tmp, int pri_strength,
+//                              int sec_strength, int dir, int damping,
+//                              int h, size_t edges);
+.macro filter_func_8 w, pri, sec, min, suffix
+function cdef_filter\w\suffix\()_edged_neon
+.if \pri
+        movrel_local    r8,  pri_taps
+        and             r9,  r3,  #1
+        add             r8,  r8,  r9, lsl #1
+.endif
+        movrel_local    r9,  directions\w
+        add             r5,  r9,  r5, lsl #1
+        vmov.u8         d17, #7
+        vdup.8          d16, r6              // damping
+
+        vmov.8          d8[0], r3
+        vmov.8          d8[1], r4
+        vclz.i8         d8,  d8              // clz(threshold)
+        vsub.i8         d8,  d17, d8         // ulog2(threshold)
+        vqsub.u8        d8,  d16, d8         // shift = imax(0, damping - ulog2(threshold))
+        vneg.s8         d8,  d8              // -shift
+.if \sec
+        vdup.8          q6,  d8[1]
+.endif
+.if \pri
+        vdup.8          q5,  d8[0]
+.endif
+
+1:
+.if \w == 8
+        add             r12, r2,  #16
+        vld1.8          {d0},  [r2,  :64]    // px
+        vld1.8          {d1},  [r12, :64]    // px
+.else
+        add             r12, r2,  #8
+        vld1.32         {d0[0]},  [r2,  :32] // px
+        add             r9,  r2,  #2*8
+        vld1.32         {d0[1]},  [r12, :32] // px
+        add             r12, r12, #2*8
+        vld1.32         {d1[0]},  [r9,  :32] // px
+        vld1.32         {d1[1]},  [r12, :32] // px
+.endif
+
+        vmov.u8         q1,  #0              // sum
+        vmov.u8         q2,  #0              // sum
+.if \min
+        vmov.u16        q3,  q0              // min
+        vmov.u16        q4,  q0              // max
+.endif
+
+        // Instead of loading sec_taps 2, 1 from memory, just set it
+        // to 2 initially and decrease for the second round.
+        // This is also used as loop counter.
+        mov             lr,  #2              // sec_taps[0]
+
+2:
+.if \pri
+        ldrsb           r9,  [r5]            // off1
+
+        load_px_8       d28, d29, d30, d31, \w
+.endif
+
+.if \sec
+        add             r5,  r5,  #4         // +2*2
+        ldrsb           r9,  [r5]            // off2
+.endif
+
+.if \pri
+        ldrb            r12, [r8]            // *pri_taps
+        vdup.8          q7,  r3              // threshold
+
+        handle_pixel_8  q14, q15, q7,  q5,  r12, \min
+.endif
+
+.if \sec
+        load_px_8       d28, d29, d30, d31, \w
+
+        add             r5,  r5,  #8         // +2*4
+        ldrsb           r9,  [r5]            // off3
+
+        vdup.8          q7,  r4              // threshold
+
+        handle_pixel_8  q14, q15, q7,  q6,  lr, \min
+
+        load_px_8       d28, d29, d30, d31, \w
+
+        handle_pixel_8  q14, q15, q7,  q6,  lr, \min
+
+        sub             r5,  r5,  #11        // r5 -= 2*(2+4); r5 += 1;
+.else
+        add             r5,  r5,  #1         // r5 += 1
+.endif
+        subs            lr,  lr,  #1         // sec_tap-- (value)
+.if \pri
+        add             r8,  r8,  #1         // pri_taps++ (pointer)
+.endif
+        bne             2b
+
+        vshr.s16        q14, q1,  #15        // -(sum < 0)
+        vshr.s16        q15, q2,  #15        // -(sum < 0)
+        vadd.i16        q1,  q1,  q14        // sum - (sum < 0)
+        vadd.i16        q2,  q2,  q15        // sum - (sum < 0)
+        vrshr.s16       q1,  q1,  #4         // (8 + sum - (sum < 0)) >> 4
+        vrshr.s16       q2,  q2,  #4         // (8 + sum - (sum < 0)) >> 4
+        vaddw.u8        q1,  q1,  d0         // px + (8 + sum ...) >> 4
+        vaddw.u8        q2,  q2,  d1         // px + (8 + sum ...) >> 4
+        vqmovun.s16     d0,  q1
+        vqmovun.s16     d1,  q2
+.if \min
+        vmin.u8         q0,  q0,  q4
+        vmax.u8         q0,  q0,  q3         // iclip(px + .., min, max)
+.endif
+.if \w == 8
+        vst1.8          {d0}, [r0, :64], r1
+        add             r2,  r2,  #2*16      // tmp += 2*tmp_stride
+        subs            r7,  r7,  #2         // h -= 2
+        vst1.8          {d1}, [r0, :64], r1
+.else
+        vst1.32         {d0[0]}, [r0, :32], r1
+        add             r2,  r2,  #4*8       // tmp += 4*tmp_stride
+        vst1.32         {d0[1]}, [r0, :32], r1
+        subs            r7,  r7,  #4         // h -= 4
+        vst1.32         {d1[0]}, [r0, :32], r1
+        vst1.32         {d1[1]}, [r0, :32], r1
+.endif
+
+        // Reset pri_taps and directions back to the original point
+        sub             r5,  r5,  #2
+.if \pri
+        sub             r8,  r8,  #2
+.endif
+
+        bgt             1b
+        vpop            {q4-q7}
+        pop             {r4-r9,pc}
+endfunc
+.endm
+
+.macro filter_8 w
+filter_func_8 \w, pri=1, sec=0, min=0, suffix=_pri
+filter_func_8 \w, pri=0, sec=1, min=0, suffix=_sec
+filter_func_8 \w, pri=1, sec=1, min=1, suffix=_pri_sec
+.endm
+
+filter_8 8
+filter_8 4
diff --git a/media/libdav1d/src/src/arm/32/cdef16.S b/media/libdav1d/src/src/arm/32/cdef16.S
new file mode 100644
index 0000000000..d14525d720
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/cdef16.S
@@ -0,0 +1,233 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+#include "cdef_tmpl.S"
+
+// r1 = d0/q0
+// r2 = d2/q1
+.macro pad_top_bot_16 s1, s2, w, stride, r1, r2, align, ret
+        tst             r7,  #1 // CDEF_HAVE_LEFT
+        beq             2f
+        // CDEF_HAVE_LEFT
+        tst             r7,  #2 // CDEF_HAVE_RIGHT
+        beq             1f
+        // CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+        vldr            s8,  [\s1, #-4]
+        vld1.16         {\r1}, [\s1, :\align]
+        vldr            s9,  [\s1, #2*\w]
+        vldr            s10, [\s2, #-4]
+        vld1.16         {\r2}, [\s2, :\align]
+        vldr            s11, [\s2, #2*\w]
+        vstr            s8,  [r0, #-4]
+        vst1.16         {\r1}, [r0, :\align]
+        vstr            s9,  [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        vstr            s10, [r0, #-4]
+        vst1.16         {\r2}, [r0, :\align]
+        vstr            s11, [r0, #2*\w]
+.if \ret
+        pop             {r4-r8,pc}
+.else
+        add             r0,  r0,  #2*\stride
+        b               3f
+.endif
+
+1:
+        // CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        vldr            s8,  [\s1, #-4]
+        vld1.16         {\r1}, [\s1, :\align]
+        vldr            s9,  [\s2, #-4]
+        vld1.16         {\r2}, [\s2, :\align]
+        vstr            s8,  [r0, #-4]
+        vst1.16         {\r1}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        vstr            s9,  [r0, #-4]
+        vst1.16         {\r2}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+.if \ret
+        pop             {r4-r8,pc}
+.else
+        add             r0,  r0,  #2*\stride
+        b               3f
+.endif
+
+2:
+        // !CDEF_HAVE_LEFT
+        tst             r7,  #2 // CDEF_HAVE_RIGHT
+        beq             1f
+        // !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+        vld1.16         {\r1}, [\s1, :\align]
+        vldr            s8,  [\s1, #2*\w]
+        vld1.16         {\r2}, [\s2, :\align]
+        vldr            s9,  [\s2, #2*\w]
+        vstr            s12, [r0, #-4]
+        vst1.16         {\r1}, [r0, :\align]
+        vstr            s8,  [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        vstr            s12, [r0, #-4]
+        vst1.16         {\r2}, [r0, :\align]
+        vstr            s9,  [r0, #2*\w]
+.if \ret
+        pop             {r4-r8,pc}
+.else
+        add             r0,  r0,  #2*\stride
+        b               3f
+.endif
+
+1:
+        // !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        vld1.16         {\r1}, [\s1, :\align]
+        vld1.16         {\r2}, [\s2, :\align]
+        vstr            s12, [r0, #-4]
+        vst1.16         {\r1}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        vstr            s12, [r0, #-4]
+        vst1.16         {\r2}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+.if \ret
+        pop             {r4-r8,pc}
+.else
+        add             r0,  r0,  #2*\stride
+.endif
+3:
+.endm
+
+// void dav1d_cdef_paddingX_16bpc_neon(uint16_t *tmp, const pixel *src,
+//                                     ptrdiff_t src_stride, const pixel (*left)[2],
+//                                     const pixel *const top,
+//                                     const pixel *const bottom, int h,
+//                                     enum CdefEdgeFlags edges);
+
+// r1 = d0/q0
+// r2 = d2/q1
+.macro padding_func_16 w, stride, r1, r2, align
+function cdef_padding\w\()_16bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldrd            r6,  r7,  [sp, #32]
+        vmov.i16        q3,  #0x8000
+        tst             r7,  #4 // CDEF_HAVE_TOP
+        bne             1f
+        // !CDEF_HAVE_TOP
+        sub             r12, r0,  #2*(2*\stride+2)
+        vmov.i16        q2,  #0x8000
+        vst1.16         {q2,q3}, [r12]!
+.if \w == 8
+        vst1.16         {q2,q3}, [r12]!
+.endif
+        b               3f
+1:
+        // CDEF_HAVE_TOP
+        add             r8,  r4,  r2
+        sub             r0,  r0,  #2*(2*\stride)
+        pad_top_bot_16  r4,  r8,  \w, \stride, \r1, \r2, \align, 0
+
+        // Middle section
+3:
+        tst             r7,  #1 // CDEF_HAVE_LEFT
+        beq             2f
+        // CDEF_HAVE_LEFT
+        tst             r7,  #2 // CDEF_HAVE_RIGHT
+        beq             1f
+        // CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+0:
+        vld1.32         {d2[]}, [r3, :32]!
+        vldr            s5,  [r1, #2*\w]
+        vld1.16         {\r1}, [r1, :\align], r2
+        subs            r6,  r6,  #1
+        vstr            s4,  [r0, #-4]
+        vst1.16         {\r1}, [r0, :\align]
+        vstr            s5,  [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        bgt             0b
+        b               3f
+1:
+        // CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        vld1.32         {d2[]}, [r3, :32]!
+        vld1.16         {\r1}, [r1, :\align], r2
+        subs            r6,  r6,  #1
+        vstr            s4,  [r0, #-4]
+        vst1.16         {\r1}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        bgt             1b
+        b               3f
+2:
+        tst             r7,  #2 // CDEF_HAVE_RIGHT
+        beq             1f
+        // !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+0:
+        vldr            s4,  [r1, #2*\w]
+        vld1.16         {\r1}, [r1, :\align], r2
+        subs            r6,  r6,  #1
+        vstr            s12, [r0, #-4]
+        vst1.16         {\r1}, [r0, :\align]
+        vstr            s4,  [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        bgt             0b
+        b               3f
+1:
+        // !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        vld1.16         {\r1}, [r1, :\align], r2
+        subs            r6,  r6,  #1
+        vstr            s12, [r0, #-4]
+        vst1.16         {\r1}, [r0, :\align]
+        vstr            s12, [r0, #2*\w]
+        add             r0,  r0,  #2*\stride
+        bgt             1b
+
+3:
+        tst             r7,  #8 // CDEF_HAVE_BOTTOM
+        bne             1f
+        // !CDEF_HAVE_BOTTOM
+        sub             r12, r0,  #4
+        vmov.i16        q2,  #0x8000
+        vst1.16         {q2,q3}, [r12]!
+.if \w == 8
+        vst1.16         {q2,q3}, [r12]!
+.endif
+        pop             {r4-r8,pc}
+1:
+        // CDEF_HAVE_BOTTOM
+        add             r8,  r5,  r2
+        pad_top_bot_16  r5,  r8,  \w, \stride, \r1, \r2, \align, 1
+endfunc
+.endm
+
+padding_func_16 8, 16, q0, q1, 128
+padding_func_16 4, 8,  d0, d2, 64
+
+tables
+
+filter 8, 16
+filter 4, 16
+
+find_dir 16
diff --git a/media/libdav1d/src/src/arm/32/cdef_tmpl.S b/media/libdav1d/src/src/arm/32/cdef_tmpl.S
new file mode 100644
index 0000000000..33ff9e5816
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/cdef_tmpl.S
@@ -0,0 +1,515 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+.macro dir_table w, stride
+const directions\w
+        .byte           -1 * \stride + 1, -2 * \stride + 2
+        .byte            0 * \stride + 1, -1 * \stride + 2
+        .byte            0 * \stride + 1,  0 * \stride + 2
+        .byte            0 * \stride + 1,  1 * \stride + 2
+        .byte            1 * \stride + 1,  2 * \stride + 2
+        .byte            1 * \stride + 0,  2 * \stride + 1
+        .byte            1 * \stride + 0,  2 * \stride + 0
+        .byte            1 * \stride + 0,  2 * \stride - 1
+// Repeated, to avoid & 7
+        .byte           -1 * \stride + 1, -2 * \stride + 2
+        .byte            0 * \stride + 1, -1 * \stride + 2
+        .byte            0 * \stride + 1,  0 * \stride + 2
+        .byte            0 * \stride + 1,  1 * \stride + 2
+        .byte            1 * \stride + 1,  2 * \stride + 2
+        .byte            1 * \stride + 0,  2 * \stride + 1
+endconst
+.endm
+
+.macro tables
+dir_table 8, 16
+dir_table 4, 8
+
+const pri_taps
+        .byte           4, 2, 3, 3
+endconst
+.endm
+
+.macro load_px d11, d12, d21, d22, w
+.if \w == 8
+        add             r6,  r2,  r9, lsl #1 // x + off
+        sub             r9,  r2,  r9, lsl #1 // x - off
+        vld1.16         {\d11,\d12}, [r6]    // p0
+        vld1.16         {\d21,\d22}, [r9]    // p1
+.else
+        add             r6,  r2,  r9, lsl #1 // x + off
+        sub             r9,  r2,  r9, lsl #1 // x - off
+        vld1.16         {\d11}, [r6]         // p0
+        add             r6,  r6,  #2*8       // += stride
+        vld1.16         {\d21}, [r9]         // p1
+        add             r9,  r9,  #2*8       // += stride
+        vld1.16         {\d12}, [r6]         // p0
+        vld1.16         {\d22}, [r9]         // p1
+.endif
+.endm
+.macro handle_pixel s1, s2, thresh_vec, shift, tap, min
+.if \min
+        vmin.u16        q2,  q2,  \s1
+        vmax.s16        q3,  q3,  \s1
+        vmin.u16        q2,  q2,  \s2
+        vmax.s16        q3,  q3,  \s2
+.endif
+        vabd.u16        q8,  q0,  \s1        // abs(diff)
+        vabd.u16        q11, q0,  \s2        // abs(diff)
+        vshl.u16        q9,  q8,  \shift     // abs(diff) >> shift
+        vshl.u16        q12, q11, \shift     // abs(diff) >> shift
+        vqsub.u16       q9,  \thresh_vec, q9 // clip = imax(0, threshold - (abs(diff) >> shift))
+        vqsub.u16       q12, \thresh_vec, q12// clip = imax(0, threshold - (abs(diff) >> shift))
+        vsub.i16        q10, \s1, q0         // diff = p0 - px
+        vsub.i16        q13, \s2, q0         // diff = p1 - px
+        vneg.s16        q8,  q9              // -clip
+        vneg.s16        q11, q12             // -clip
+        vmin.s16        q10, q10, q9         // imin(diff, clip)
+        vmin.s16        q13, q13, q12        // imin(diff, clip)
+        vdup.16         q9,  \tap            // taps[k]
+        vmax.s16        q10, q10, q8         // constrain() = imax(imin(diff, clip), -clip)
+        vmax.s16        q13, q13, q11        // constrain() = imax(imin(diff, clip), -clip)
+        vmla.i16        q1,  q10, q9         // sum += taps[k] * constrain()
+        vmla.i16        q1,  q13, q9         // sum += taps[k] * constrain()
+.endm
+
+// void dav1d_cdef_filterX_Ybpc_neon(pixel *dst, ptrdiff_t dst_stride,
+//                                   const uint16_t *tmp, int pri_strength,
+//                                   int sec_strength, int dir, int damping,
+//                                   int h, size_t edges);
+.macro filter_func w, bpc, pri, sec, min, suffix
+function cdef_filter\w\suffix\()_\bpc\()bpc_neon
+.if \bpc == 8
+        cmp             r8,  #0xf
+        beq             cdef_filter\w\suffix\()_edged_neon
+.endif
+.if \pri
+.if \bpc == 16
+        clz             r9,  r9
+        sub             r9,  r9,  #24        // -bitdepth_min_8
+        neg             r9,  r9              // bitdepth_min_8
+.endif
+        movrel_local    r8,  pri_taps
+.if \bpc == 16
+        lsr             r9,  r3,  r9         // pri_strength >> bitdepth_min_8
+        and             r9,  r9,  #1         // (pri_strength >> bitdepth_min_8) & 1
+.else
+        and             r9,  r3,  #1
+.endif
+        add             r8,  r8,  r9, lsl #1
+.endif
+        movrel_local    r9,  directions\w
+        add             r5,  r9,  r5, lsl #1
+        vmov.u16        d17, #15
+        vdup.16         d16, r6              // damping
+
+.if \pri
+        vdup.16         q5,  r3              // threshold
+.endif
+.if \sec
+        vdup.16         q7,  r4              // threshold
+.endif
+        vmov.16         d8[0], r3
+        vmov.16         d8[1], r4
+        vclz.i16        d8,  d8              // clz(threshold)
+        vsub.i16        d8,  d17, d8         // ulog2(threshold)
+        vqsub.u16       d8,  d16, d8         // shift = imax(0, damping - ulog2(threshold))
+        vneg.s16        d8,  d8              // -shift
+.if \sec
+        vdup.16         q6,  d8[1]
+.endif
+.if \pri
+        vdup.16         q4,  d8[0]
+.endif
+
+1:
+.if \w == 8
+        vld1.16         {q0},  [r2, :128]    // px
+.else
+        add             r12, r2,  #2*8
+        vld1.16         {d0},  [r2,  :64]    // px
+        vld1.16         {d1},  [r12, :64]    // px
+.endif
+
+        vmov.u16        q1,  #0              // sum
+.if \min
+        vmov.u16        q2,  q0              // min
+        vmov.u16        q3,  q0              // max
+.endif
+
+        // Instead of loading sec_taps 2, 1 from memory, just set it
+        // to 2 initially and decrease for the second round.
+        // This is also used as loop counter.
+        mov             lr,  #2              // sec_taps[0]
+
+2:
+.if \pri
+        ldrsb           r9,  [r5]            // off1
+
+        load_px         d28, d29, d30, d31, \w
+.endif
+
+.if \sec
+        add             r5,  r5,  #4         // +2*2
+        ldrsb           r9,  [r5]            // off2
+.endif
+
+.if \pri
+        ldrb            r12, [r8]            // *pri_taps
+
+        handle_pixel    q14, q15, q5,  q4,  r12, \min
+.endif
+
+.if \sec
+        load_px         d28, d29, d30, d31, \w
+
+        add             r5,  r5,  #8         // +2*4
+        ldrsb           r9,  [r5]            // off3
+
+        handle_pixel    q14, q15, q7,  q6,  lr, \min
+
+        load_px         d28, d29, d30, d31, \w
+
+        handle_pixel    q14, q15, q7,  q6,  lr, \min
+
+        sub             r5,  r5,  #11        // r5 -= 2*(2+4); r5 += 1;
+.else
+        add             r5,  r5,  #1         // r5 += 1
+.endif
+        subs            lr,  lr,  #1         // sec_tap-- (value)
+.if \pri
+        add             r8,  r8,  #1         // pri_taps++ (pointer)
+.endif
+        bne             2b
+
+        vshr.s16        q14, q1,  #15        // -(sum < 0)
+        vadd.i16        q1,  q1,  q14        // sum - (sum < 0)
+        vrshr.s16       q1,  q1,  #4         // (8 + sum - (sum < 0)) >> 4
+        vadd.i16        q0,  q0,  q1         // px + (8 + sum ...) >> 4
+.if \min
+        vmin.s16        q0,  q0,  q3
+        vmax.s16        q0,  q0,  q2         // iclip(px + .., min, max)
+.endif
+.if \bpc == 8
+        vmovn.u16       d0,  q0
+.endif
+.if \w == 8
+        add             r2,  r2,  #2*16      // tmp += tmp_stride
+        subs            r7,  r7,  #1         // h--
+.if \bpc == 8
+        vst1.8          {d0}, [r0, :64], r1
+.else
+        vst1.16         {q0}, [r0, :128], r1
+.endif
+.else
+.if \bpc == 8
+        vst1.32         {d0[0]}, [r0, :32], r1
+.else
+        vst1.16         {d0},    [r0, :64], r1
+.endif
+        add             r2,  r2,  #2*16      // tmp += 2*tmp_stride
+        subs            r7,  r7,  #2         // h -= 2
+.if \bpc == 8
+        vst1.32         {d0[1]}, [r0, :32], r1
+.else
+        vst1.16         {d1},    [r0, :64], r1
+.endif
+.endif
+
+        // Reset pri_taps and directions back to the original point
+        sub             r5,  r5,  #2
+.if \pri
+        sub             r8,  r8,  #2
+.endif
+
+        bgt             1b
+        vpop            {q4-q7}
+        pop             {r4-r9,pc}
+endfunc
+.endm
+
+.macro filter w, bpc
+filter_func \w, \bpc, pri=1, sec=0, min=0, suffix=_pri
+filter_func \w, \bpc, pri=0, sec=1, min=0, suffix=_sec
+filter_func \w, \bpc, pri=1, sec=1, min=1, suffix=_pri_sec
+
+function cdef_filter\w\()_\bpc\()bpc_neon, export=1
+        push            {r4-r9,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #92]
+        ldrd            r6,  r7,  [sp, #100]
+.if \bpc == 16
+        ldrd            r8,  r9,  [sp, #108]
+.else
+        ldr             r8,  [sp, #108]
+.endif
+        cmp             r3,  #0 // pri_strength
+        bne             1f
+        b               cdef_filter\w\()_sec_\bpc\()bpc_neon // only sec
+1:
+        cmp             r4,  #0 // sec_strength
+        bne             1f
+        b               cdef_filter\w\()_pri_\bpc\()bpc_neon // only pri
+1:
+        b               cdef_filter\w\()_pri_sec_\bpc\()bpc_neon // both pri and sec
+endfunc
+.endm
+
+const div_table, align=4
+        .short         840, 420, 280, 210, 168, 140, 120, 105
+endconst
+
+const alt_fact, align=4
+        .short         420, 210, 140, 105, 105, 105, 105, 105, 140, 210, 420, 0
+endconst
+
+.macro cost_alt dest, s1, s2, s3, s4, s5, s6
+        vmull.s16       q1,  \s1, \s1          // sum_alt[n]*sum_alt[n]
+        vmull.s16       q2,  \s2, \s2
+        vmull.s16       q3,  \s3, \s3
+        vmull.s16       q5,  \s4, \s4          // sum_alt[n]*sum_alt[n]
+        vmull.s16       q12, \s5, \s5
+        vmull.s16       q6,  \s6, \s6          // q6 overlaps the first \s1-\s2 here
+        vmul.i32        q1,  q1,  q13          // sum_alt[n]^2*fact
+        vmla.i32        q1,  q2,  q14
+        vmla.i32        q1,  q3,  q15
+        vmul.i32        q5,  q5,  q13          // sum_alt[n]^2*fact
+        vmla.i32        q5,  q12, q14
+        vmla.i32        q5,  q6,  q15
+        vadd.i32        d2,  d2,  d3
+        vadd.i32        d3,  d10, d11
+        vpadd.i32       \dest, d2, d3          // *cost_ptr
+.endm
+
+.macro find_best s1, s2, s3
+.ifnb \s2
+        vmov.32         lr,  \s2
+.endif
+        cmp             r12, r1                // cost[n] > best_cost
+        itt             gt
+        movgt           r0,  r3                // best_dir = n
+        movgt           r1,  r12               // best_cost = cost[n]
+.ifnb \s2
+        add             r3,  r3,  #1           // n++
+        cmp             lr,  r1                // cost[n] > best_cost
+        vmov.32         r12, \s3
+        itt             gt
+        movgt           r0,  r3                // best_dir = n
+        movgt           r1,  lr                // best_cost = cost[n]
+        add             r3,  r3,  #1           // n++
+.endif
+.endm
+
+// int dav1d_cdef_find_dir_Xbpc_neon(const pixel *img, const ptrdiff_t stride,
+//                                   unsigned *const var)
+.macro find_dir bpc
+function cdef_find_dir_\bpc\()bpc_neon, export=1
+        push            {lr}
+        vpush           {q4-q7}
+.if \bpc == 16
+        clz             r3,  r3                // clz(bitdepth_max)
+        sub             lr,  r3,  #24          // -bitdepth_min_8
+.endif
+        sub             sp,  sp,  #32          // cost
+        mov             r3,  #8
+        vmov.u16        q1,  #0                // q0-q1   sum_diag[0]
+        vmov.u16        q3,  #0                // q2-q3   sum_diag[1]
+        vmov.u16        q5,  #0                // q4-q5   sum_hv[0-1]
+        vmov.u16        q8,  #0                // q6,d16  sum_alt[0]
+                                               // q7,d17  sum_alt[1]
+        vmov.u16        q9,  #0                // q9,d22  sum_alt[2]
+        vmov.u16        q11, #0
+        vmov.u16        q10, #0                // q10,d23 sum_alt[3]
+
+
+.irpc i, 01234567
+.if \bpc == 8
+        vld1.8          {d30}, [r0, :64], r1
+        vmov.u8         d31, #128
+        vsubl.u8        q15, d30, d31          // img[x] - 128
+.else
+        vld1.16         {q15}, [r0, :128], r1
+        vdup.16         q14, lr                // -bitdepth_min_8
+        vshl.u16        q15, q15, q14
+        vmov.u16        q14, #128
+        vsub.i16        q15, q15, q14          // img[x] - 128
+.endif
+        vmov.u16        q14, #0
+
+.if \i == 0
+        vmov            q0,  q15               // sum_diag[0]
+.else
+        vext.8          q12, q14, q15, #(16-2*\i)
+        vext.8          q13, q15, q14, #(16-2*\i)
+        vadd.i16        q0,  q0,  q12          // sum_diag[0]
+        vadd.i16        q1,  q1,  q13          // sum_diag[0]
+.endif
+        vrev64.16       q13, q15
+        vswp            d26, d27               // [-x]
+.if \i == 0
+        vmov            q2,  q13               // sum_diag[1]
+.else
+        vext.8          q12, q14, q13, #(16-2*\i)
+        vext.8          q13, q13, q14, #(16-2*\i)
+        vadd.i16        q2,  q2,  q12          // sum_diag[1]
+        vadd.i16        q3,  q3,  q13          // sum_diag[1]
+.endif
+
+        vpadd.u16       d26, d30, d31          // [(x >> 1)]
+        vmov.u16        d27, #0
+        vpadd.u16       d24, d26, d28
+        vpadd.u16       d24, d24, d28          // [y]
+        vmov.u16        r12, d24[0]
+        vadd.i16        q5,  q5,  q15          // sum_hv[1]
+.if \i < 4
+        vmov.16         d8[\i],   r12          // sum_hv[0]
+.else
+        vmov.16         d9[\i-4], r12          // sum_hv[0]
+.endif
+
+.if \i == 0
+        vmov.u16        q6,  q13               // sum_alt[0]
+.else
+        vext.8          q12, q14, q13, #(16-2*\i)
+        vext.8          q14, q13, q14, #(16-2*\i)
+        vadd.i16        q6,  q6,  q12          // sum_alt[0]
+        vadd.i16        d16, d16, d28          // sum_alt[0]
+.endif
+        vrev64.16       d26, d26               // [-(x >> 1)]
+        vmov.u16        q14, #0
+.if \i == 0
+        vmov            q7,  q13               // sum_alt[1]
+.else
+        vext.8          q12, q14, q13, #(16-2*\i)
+        vext.8          q13, q13, q14, #(16-2*\i)
+        vadd.i16        q7,  q7,  q12          // sum_alt[1]
+        vadd.i16        d17, d17, d26          // sum_alt[1]
+.endif
+
+.if \i < 6
+        vext.8          q12, q14, q15, #(16-2*(3-(\i/2)))
+        vext.8          q13, q15, q14, #(16-2*(3-(\i/2)))
+        vadd.i16        q9,  q9,  q12          // sum_alt[2]
+        vadd.i16        d22, d22, d26          // sum_alt[2]
+.else
+        vadd.i16        q9,  q9,  q15          // sum_alt[2]
+.endif
+.if \i == 0
+        vmov            q10, q15               // sum_alt[3]
+.elseif \i == 1
+        vadd.i16        q10, q10, q15          // sum_alt[3]
+.else
+        vext.8          q12, q14, q15, #(16-2*(\i/2))
+        vext.8          q13, q15, q14, #(16-2*(\i/2))
+        vadd.i16        q10, q10, q12          // sum_alt[3]
+        vadd.i16        d23, d23, d26          // sum_alt[3]
+.endif
+.endr
+
+        vmov.u32        q15, #105
+
+        vmull.s16       q12, d8,  d8           // sum_hv[0]*sum_hv[0]
+        vmlal.s16       q12, d9,  d9
+        vmull.s16       q13, d10, d10          // sum_hv[1]*sum_hv[1]
+        vmlal.s16       q13, d11, d11
+        vadd.s32        d8,  d24, d25
+        vadd.s32        d9,  d26, d27
+        vpadd.s32       d8,  d8,  d9           // cost[2,6] (s16, s17)
+        vmul.i32        d8,  d8,  d30          // cost[2,6] *= 105
+
+        vrev64.16       q1,  q1
+        vrev64.16       q3,  q3
+        vext.8          q1,  q1,  q1,  #10     // sum_diag[0][14-n]
+        vext.8          q3,  q3,  q3,  #10     // sum_diag[1][14-n]
+
+        vstr            s16, [sp, #2*4]        // cost[2]
+        vstr            s17, [sp, #6*4]        // cost[6]
+
+        movrel_local    r12, div_table
+        vld1.16         {q14}, [r12, :128]
+
+        vmull.s16       q5,  d0,  d0           // sum_diag[0]*sum_diag[0]
+        vmull.s16       q12, d1,  d1
+        vmlal.s16       q5,  d2,  d2
+        vmlal.s16       q12, d3,  d3
+        vmull.s16       q0,  d4,  d4           // sum_diag[1]*sum_diag[1]
+        vmull.s16       q1,  d5,  d5
+        vmlal.s16       q0,  d6,  d6
+        vmlal.s16       q1,  d7,  d7
+        vmovl.u16       q13, d28               // div_table
+        vmovl.u16       q14, d29
+        vmul.i32        q5,  q5,  q13          // cost[0]
+        vmla.i32        q5,  q12, q14
+        vmul.i32        q0,  q0,  q13          // cost[4]
+        vmla.i32        q0,  q1,  q14
+        vadd.i32        d10, d10, d11
+        vadd.i32        d0,  d0,  d1
+        vpadd.i32       d0,  d10, d0           // cost[0,4] = s0,s1
+
+        movrel_local    r12, alt_fact
+        vld1.16         {d29, d30, d31}, [r12, :64] // div_table[2*m+1] + 105
+
+        vstr            s0,  [sp, #0*4]        // cost[0]
+        vstr            s1,  [sp, #4*4]        // cost[4]
+
+        vmovl.u16       q13, d29               // div_table[2*m+1] + 105
+        vmovl.u16       q14, d30
+        vmovl.u16       q15, d31
+
+        cost_alt        d14, d12, d13, d16, d14, d15, d17 // cost[1], cost[3]
+        cost_alt        d15, d18, d19, d22, d20, d21, d23 // cost[5], cost[7]
+        vstr            s28, [sp, #1*4]        // cost[1]
+        vstr            s29, [sp, #3*4]        // cost[3]
+
+        mov             r0,  #0                // best_dir
+        vmov.32         r1,  d0[0]             // best_cost
+        mov             r3,  #1                // n
+
+        vstr            s30, [sp, #5*4]        // cost[5]
+        vstr            s31, [sp, #7*4]        // cost[7]
+
+        vmov.32         r12, d14[0]
+
+        find_best       d14[0], d8[0], d14[1]
+        find_best       d14[1], d0[1], d15[0]
+        find_best       d15[0], d8[1], d15[1]
+        find_best       d15[1]
+
+        eor             r3,  r0,  #4           // best_dir ^4
+        ldr             r12, [sp, r3, lsl #2]
+        sub             r1,  r1,  r12          // best_cost - cost[best_dir ^ 4]
+        lsr             r1,  r1,  #10
+        str             r1,  [r2]              // *var
+
+        add             sp,  sp,  #32
+        vpop            {q4-q7}
+        pop             {pc}
+endfunc
+.endm
diff --git a/media/libdav1d/src/src/arm/32/filmgrain.S b/media/libdav1d/src/src/arm/32/filmgrain.S
new file mode 100644
index 0000000000..9d59d5d5ed
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/filmgrain.S
@@ -0,0 +1,2039 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * Copyright © 2021, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+#include "src/arm/asm-offsets.h"
+
+#define GRAIN_WIDTH 82
+#define GRAIN_HEIGHT 73
+
+#define SUB_GRAIN_WIDTH 44
+#define SUB_GRAIN_HEIGHT 38
+
+.macro increment_seed steps, shift=1
+        lsr             r11, r2,  #3
+        lsr             r12, r2,  #12
+        lsr             lr,  r2,  #1
+        eor             r11, r2,  r11                     // (r >> 0) ^ (r >> 3)
+        eor             r12, r12, lr                      // (r >> 12) ^ (r >> 1)
+        eor             r11, r11, r12                     // (r >> 0) ^ (r >> 3) ^ (r >> 12) ^ (r >> 1)
+.if \shift
+        lsr             r2,  r2,  #\steps
+.endif
+        and             r11, r11, #((1 << \steps) - 1)    // bit
+.if \shift
+        orr             r2,  r2,  r11, lsl #(16 - \steps) // *state
+.else
+        orr             r2,  r2,  r11, lsl #16            // *state
+.endif
+.endm
+
+.macro read_rand dest, bits, age
+        ubfx            \dest,  r2,   #16 - \bits - \age, #\bits
+.endm
+
+.macro read_shift_rand dest, bits
+        ubfx            \dest,  r2,   #17 - \bits, #\bits
+        lsr             r2,  r2,  #1
+.endm
+
+// special calling convention:
+// r2 holds seed
+// r3 holds dav1d_gaussian_sequence
+// clobbers r11-r12
+// returns in d0-d1
+function get_gaussian_neon
+        push            {r5-r6,lr}
+        increment_seed  4
+        read_rand       r5,  11,  3
+        read_rand       r6,  11,  2
+        add             r5,  r3,  r5,  lsl #1
+        add             r6,  r3,  r6,  lsl #1
+        vld1.16         {d0[0]}, [r5]
+        read_rand       r5,  11,  1
+        vld1.16         {d0[1]}, [r6]
+        add             r5,  r3,  r5,  lsl #1
+        read_rand       r6, 11,  0
+        increment_seed  4
+        add             r6,  r3,  r6,  lsl #1
+        vld1.16         {d0[2]}, [r5]
+        read_rand       r5,  11,  3
+        vld1.16         {d0[3]}, [r6]
+        add             r5,  r3,  r5,  lsl #1
+        read_rand       r6,  11,  2
+        vld1.16         {d1[0]}, [r5]
+        add             r6,  r3,  r6,  lsl #1
+        read_rand       r5,  11,  1
+        vld1.16         {d1[1]}, [r6]
+        read_rand       r6,  11,  0
+        add             r5,  r3,  r5,  lsl #1
+        add             r6,  r3,  r6,  lsl #1
+        vld1.16         {d1[2]}, [r5]
+        vld1.16         {d1[3]}, [r6]
+        pop             {r5-r6,pc}
+endfunc
+
+.macro get_grain_row r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r0, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r1, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r2, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r3, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r4, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r5, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r6, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r7, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r8, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r9, q0
+        increment_seed  2
+        read_rand       r11, 11,  1
+        read_rand       r12, 11,  0
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d0[0]}, [r11]
+        vld1.16         {d0[1]}, [r12]
+        vrshl.s16       d0,  d0,  d30
+        vmovn.i16       \r10, q0
+.endm
+
+.macro store_grain_row r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
+        vst1.16         {\r0, \r1, \r2, \r3}, [r0]!
+        vst1.16         {\r4, \r5, \r6, \r7}, [r0]!
+        vst1.16         {\r8, \r9},           [r0]!
+        vst1.16         {\r10[0]},            [r0]!
+.endm
+
+.macro get_grain_row_44 r0, r1, r2, r3, r4, r5
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r0, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r1, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r2, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r3, q0
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        vmovn.i16       \r4, q0
+        increment_seed  4
+        read_rand       r11, 11,  3
+        read_rand       r12, 11,  2
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d0[]}, [r11]
+        read_rand       r11, 11,  1
+        vld1.16         {d0[1]}, [r12]
+        add             r11, r3,  r11, lsl #1
+        read_rand       r12, 11,  0
+        vld1.16         {d0[2]}, [r11]
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d0[3]}, [r12]
+        vrshl.s16       d0,  d0,  d30
+        vmovn.i16       \r5, q0
+.endm
+
+.macro store_grain_row_44 r0, r1, r2, r3, r4, r5
+        vst1.16         {\r0, \r1, \r2, \r3}, [r0]!
+        vst1.16         {\r4, \r5},           [r0]
+        add             r0,  r0,  #GRAIN_WIDTH-32
+.endm
+
+function get_grain_2_neon
+        push            {r11,lr}
+        increment_seed  2
+        read_rand       r11, 11,  1
+        read_rand       r12, 11,  0
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d0[0]}, [r11]
+        vld1.16         {d0[1]}, [r12]
+        vrshl.s16       d0,  d0,  d30
+        vmovn.i16       d0,  q0
+        pop             {r11,pc}
+endfunc
+
+.macro get_grain_2 dst
+        bl              get_grain_2_neon
+.ifnc \dst, d0
+        vmov            \dst, d0
+.endif
+.endm
+
+// r1 holds the number of entries to produce
+// r6, r8 and r10 hold the previous output entries
+// q0 holds the vector of produced entries
+// q1 holds the input vector of sums from above
+.macro output_lag n
+function output_lag\n\()_neon
+        push            {r0, lr}
+.if \n == 1
+        mov             lr,  #-128
+.else
+        mov             r0,  #1
+        mov             lr,  #1
+        sub             r7,  r7,  #1
+        sub             r9,  r9,  #1
+        lsl             r0,  r0,  r7
+        lsl             lr,  lr,  r9
+        add             r7,  r7,  #1
+        add             r9,  r9,  #1
+.endif
+1:
+        read_shift_rand r12, 11
+        vmov.32         r11, d2[0]
+        lsl             r12, r12, #1
+        vext.8          q0,  q0,  q0,  #1
+        ldrsh           r12, [r3, r12]
+.if \n == 1
+        mla             r11, r6,  r4,  r11        // sum (above) + *coeff * prev output
+        add             r6,  r11, r8              // 1 << (ar_coeff_shift - 1)
+        add             r12, r12, r10
+        asr             r6,  r6,  r7              // >> ar_coeff_shift
+        asr             r12, r12, r9              // >> (4 + grain_scale_shift)
+        add             r6,  r6,  r12
+        cmp             r6,  r5
+.elseif \n == 2
+        mla             r11, r8,  r4,  r11        // sum (above) + *coeff * prev output 1
+        mla             r11, r6,  r10, r11        // += *coeff * prev output 2
+        mov             r8,  r6
+        add             r6,  r11, r0              // 1 << (ar_coeff_shift - 1)
+        add             r12, r12, lr              // 1 << (4 + grain_scale_shift - 1)
+        asr             r6,  r6,  r7              // >> ar_coeff_shift
+        asr             r12, r12, r9              // >> (4 + grain_scale_shift)
+        add             r6,  r6,  r12
+        push            {lr}
+        cmp             r6,  r5
+        mov             lr,  #-128
+.else
+        push            {r1-r3}
+        sbfx            r1,  r4,  #0,  #8
+        sbfx            r2,  r4,  #8,  #8
+        sbfx            r3,  r4,  #16, #8
+        mla             r11, r10, r1,  r11        // sum (above) + *coeff * prev output 1
+        mla             r11, r8,  r2,  r11        // sum (above) + *coeff * prev output 2
+        mla             r11, r6,  r3,  r11        // += *coeff * prev output 3
+        pop             {r1-r3}
+        mov             r10, r8
+        mov             r8,  r6
+
+        add             r6,  r11, r0              // 1 << (ar_coeff_shift - 1)
+        add             r12, r12, lr              // 1 << (4 + grain_scale_shift - 1)
+        asr             r6,  r6,  r7              // >> ar_coeff_shift
+        asr             r12, r12, r9              // >> (4 + grain_scale_shift)
+        add             r6,  r6,  r12
+        push            {lr}
+        cmp             r6,  r5
+        mov             lr,  #-128
+.endif
+        it              gt
+        movgt           r6,  r5
+        cmp             r6,  lr
+        it              lt
+        movlt           r6,  lr
+.if \n >= 2
+        pop             {lr}
+.endif
+        subs            r1,  r1,  #1
+        vext.8          q1,  q1,  q1,  #4
+        vmov.8          d1[7], r6
+        bgt             1b
+        pop             {r0, pc}
+endfunc
+.endm
+
+output_lag 1
+output_lag 2
+output_lag 3
+
+
+function sum_lag1_above_neon
+        vmull.s8        q2,  d6,  d28
+        vmull.s8        q3,  d7,  d28
+        vmull.s8        q4,  d0,  d27
+        vmull.s8        q5,  d1,  d27
+
+        vaddl.s16       q0,  d4,  d8
+        vaddl.s16       q2,  d5,  d9
+        vaddl.s16       q4,  d6,  d10
+        vaddl.s16       q5,  d7,  d11
+
+        vmull.s8        q3,  d3,  d29
+        vmull.s8        q1,  d2,  d29
+
+        vaddw.s16       q4,  q4,  d6
+        vaddw.s16       q5,  q5,  d7
+        vaddw.s16       q3,  q2,  d3
+        vaddw.s16       q2,  q0,  d2
+        bx              lr
+endfunc
+
+.macro sum_lag_n_body lag, type, uv_layout, edge, elems, store, uv_coeff
+.ifc \lag\()_\edge, lag3_left
+        bl              sum_lag3_left_above_neon
+.else
+        bl              sum_\lag\()_above_neon
+.endif
+.ifc \type, uv_420
+        vpush           {q6-q7}
+        add             r12, r11, #GRAIN_WIDTH
+        vld1.16         {q0, q1}, [r11]!
+        vld1.16         {q6, q7}, [r12]!
+        vpaddl.s8       q0,  q0
+        vpaddl.s8       q1,  q1
+        vpaddl.s8       q6,  q6
+        vpaddl.s8       q7,  q7
+        vadd.i16        q0,  q0,  q6
+        vadd.i16        q1,  q1,  q7
+        vpop            {q6-q7}
+        vrshrn.s16      d0,  q0,  #2
+        vrshrn.s16      d1,  q1,  #2
+.endif
+.ifc \type, uv_422
+        vld1.8          {q0, q1}, [r11]!
+        vpaddl.s8       q0,  q0
+        vpaddl.s8       q1,  q1
+        vrshrn.s16      d0,  q0,  #1
+        vrshrn.s16      d1,  q1,  #1
+.endif
+.ifc \type, uv_444
+        vld1.8          {q0}, [r11]!
+.endif
+.if \uv_layout
+.ifnb \uv_coeff
+        vdup.8          d13, \uv_coeff
+.endif
+        vmull.s8        q1,  d0,  d13
+        vmull.s8        q0,  d1,  d13
+        vaddw.s16       q2,  q2,  d2
+        vaddw.s16       q3,  q3,  d3
+        vaddw.s16       q4,  q4,  d0
+        vaddw.s16       q5,  q5,  d1
+.endif
+.if \uv_layout && \elems == 16
+        b               sum_\lag\()_y_\edge\()_start
+.elseif \uv_layout == 444 && \elems == 15
+        b               sum_\lag\()_y_\edge\()_start
+.elseif \uv_layout == 422 && \elems == 9
+        b               sum_\lag\()_uv_420_\edge\()_start
+.else
+sum_\lag\()_\type\()_\edge\()_start:
+        push            {r11}
+.ifc \edge, left
+        increment_seed  4
+        read_rand       r11, 11,  3
+        read_rand       r12, 11,  2
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d1[1]}, [r11]
+        read_rand       r11, 11,  1
+        vld1.16         {d1[2]}, [r12]
+        add             r11, r3,  r11, lsl #1
+        vld1.16         {d1[3]}, [r11]
+        lsl             r2,  r2,  #1             // shift back the state as if we'd done increment_seed with shift=0
+        vrshl.s16       d1,  d1,  d30
+        vmovn.i16       d1,  q0
+        vext.8          q2,  q2,  q2,  #12
+.ifc \lag, lag3
+        vmov.s8         r10, d1[5]
+.endif
+.ifnc \lag, lag1
+        vmov.s8         r8,  d1[6]
+.endif
+        vmov.s8         r6,  d1[7]
+
+        vmov            q1,  q2
+        mov             r1,  #1
+        bl              output_\lag\()_neon
+.else
+        increment_seed  4, shift=0
+        vmov            q1,  q2
+        mov             r1,  #4
+        bl              output_\lag\()_neon
+.endif
+
+        increment_seed  4, shift=0
+        vmov            q1,  q3
+        mov             r1,  #4
+        bl              output_\lag\()_neon
+
+        increment_seed  4, shift=0
+        vmov            q1,  q4
+.if \elems == 9
+        mov             r1,  #1
+        bl              output_\lag\()_neon
+        lsr             r2,  r2,  #3
+
+        read_rand       r11, 11,  2
+        read_rand       r12, 11,  1
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d2[0]}, [r11]
+        read_rand       r11, 11,  0
+        vld1.16         {d2[1]}, [r12]
+        add             r11, r3,  r11, lsl #1
+        vld1.16         {d2[2]}, [r11]
+        vrshl.s16       d2,  d2,  d30
+        vmovn.i16       d2,  q1
+        vext.8          q0,  q0,  q1,  #7
+.else
+        mov             r1,  #4
+        bl              output_\lag\()_neon
+
+        increment_seed  4, shift=0
+        vmov            q1,  q5
+
+.ifc \edge, right
+        mov             r1,  #3
+        bl              output_\lag\()_neon
+        read_shift_rand r11, 11
+        add             r11, r3,  r11, lsl #1
+        vld1.16         {d2[0]}, [r11]
+        vrshl.s16       d2,  d2,  d30
+        vext.8          q0,  q0,  q1,  #1
+.else
+        mov             r1,  #4
+        bl              output_\lag\()_neon
+.endif
+.endif
+.if \store
+        vst1.8          {q0}, [r0]!
+.endif
+        pop             {r11}
+        pop             {r1, pc}
+.endif
+.endm
+
+.macro sum_lag1_func type, uv_layout, edge, elems=16
+function sum_\type\()_lag1_\edge\()_neon
+        push            {r1, lr}
+        sum_lag_n_body  lag1, \type, \uv_layout, \edge, \elems, store=0
+endfunc
+.endm
+
+sum_lag1_func y,      0,   left
+sum_lag1_func y,      0,   mid
+sum_lag1_func y,      0,   right, 15
+sum_lag1_func uv_444, 444, left
+sum_lag1_func uv_444, 444, mid
+sum_lag1_func uv_444, 444, right, 15
+sum_lag1_func uv_422, 422, left
+sum_lag1_func uv_422, 422, mid
+sum_lag1_func uv_422, 422, right, 9
+sum_lag1_func uv_420, 420, left
+sum_lag1_func uv_420, 420, mid
+sum_lag1_func uv_420, 420, right, 9
+
+.macro sum_lag1 type, dst, left, mid, right, edge=mid
+        vmov            q3,  \mid
+        vext.8          q0,  \left, \mid,   #15
+        vext.8          q1,  \mid,  \right, #1
+        bl              sum_\type\()_lag1_\edge\()_neon
+        vmov            \dst, q0
+.endm
+
+.macro sum_y_lag1 dst, left, mid, right, edge=mid
+        sum_lag1        y, \dst, \left, \mid, \right, \edge
+.endm
+
+.macro sum_uv_444_lag1 dst, left, mid, right, edge=mid
+        sum_lag1        uv_444, \dst, \left, \mid, \right, \edge
+.endm
+
+.macro sum_uv_422_lag1 dst, left, mid, right, edge=mid
+        sum_lag1        uv_422, \dst, \left, \mid, \right, \edge
+.endm
+
+.macro sum_uv_420_lag1 dst, left, mid, right, edge=mid
+        sum_lag1        uv_420, \dst, \left, \mid, \right, \edge
+.endm
+
+
+function sum_lag2_above_neon
+        push            {lr}
+        sub             r12, r0,  #2*GRAIN_WIDTH - 16
+        sub             lr,  r0,  #1*GRAIN_WIDTH - 16
+        vld1.8          {q10}, [r12] // load top right
+        vld1.8          {q13}, [lr]
+
+        vext.8          q6,  q8,  q9,  #14 // top left, top mid
+        vdup.8          d14, d28[0]
+        vext.8          q8,  q8,  q9,  #15
+        vdup.8          d15, d28[1]
+
+        vmull.s8        q0,  d12, d14
+        vmull.s8        q1,  d13, d14
+        vmull.s8        q6,  d16, d15
+        vmull.s8        q8,  d17, d15
+
+        vaddl.s16       q2,  d0,  d12
+        vaddl.s16       q3,  d1,  d13
+        vaddl.s16       q4,  d2,  d16
+        vaddl.s16       q5,  d3,  d17
+
+        vext.8          q6,  q9,  q10, #1  // top mid, top right
+        vdup.8          d14, d28[3]
+        vext.8          q8,  q9,  q10, #2
+        vdup.8          d15, d28[4]
+
+        vmull.s8        q0,  d12, d14
+        vmull.s8        q1,  d13, d14
+        vmull.s8        q6,  d16, d15
+        vmull.s8        q8,  d17, d15
+
+        vaddl.s16       q7,  d0,  d12
+        vaddl.s16       q0,  d1,  d13
+        vaddl.s16       q6,  d2,  d16
+        vaddl.s16       q1,  d3,  d17
+
+        vadd.i32        q2,  q2,  q7
+        vadd.i32        q3,  q3,  q0
+        vadd.i32        q4,  q4,  q6
+        vadd.i32        q5,  q5,  q1
+
+        vext.8          q6,  q11, q12, #14 // top left, top mid
+        vdup.8          d14, d28[5]
+        vext.8          q8,  q11, q12, #15
+        vdup.8          d15, d28[6]
+
+        vmull.s8        q0,  d12, d14
+        vmull.s8        q1,  d13, d14
+        vmull.s8        q6,  d16, d15
+        vmull.s8        q8,  d17, d15
+
+        vaddl.s16       q7,  d0,  d12
+        vaddl.s16       q0,  d1,  d13
+        vaddl.s16       q6,  d2,  d16
+        vaddl.s16       q1,  d3,  d17
+
+        vadd.i32        q2,  q2,  q7
+        vadd.i32        q3,  q3,  q0
+        vadd.i32        q4,  q4,  q6
+        vadd.i32        q5,  q5,  q1
+
+        vext.8          q6,  q12, q13, #1  // top mid, top right
+        vdup.8          d14, d29[0]
+        vext.8          q8,  q12, q13, #2
+        vdup.8          d15, d29[1]
+
+        vmull.s8        q0,  d12, d14
+        vmull.s8        q1,  d13, d14
+        vmull.s8        q6,  d16, d15
+        vmull.s8        q8,  d17, d15
+
+        vaddl.s16       q7,  d0,  d12
+        vaddl.s16       q0,  d1,  d13
+        vaddl.s16       q6,  d2,  d16
+        vaddl.s16       q1,  d3,  d17
+
+        vadd.i32        q2,  q2,  q7
+        vadd.i32        q3,  q3,  q0
+        vadd.i32        q4,  q4,  q6
+        vadd.i32        q5,  q5,  q1
+
+        vdup.8          d14, d28[2]
+        vdup.8          d15, d28[7]
+
+        vmull.s8        q0,  d18, d14
+        vmull.s8        q1,  d19, d14
+        vmull.s8        q6,  d24, d15
+        vmull.s8        q8,  d25, d15
+
+        vaddl.s16       q7,  d0,  d12
+        vaddl.s16       q0,  d1,  d13
+        vaddl.s16       q6,  d2,  d16
+        vaddl.s16       q1,  d3,  d17
+
+        vmov            q8,  q9
+        vmov            q9,  q10
+
+        vadd.i32        q2,  q2,  q7
+        vadd.i32        q3,  q3,  q0
+        vadd.i32        q4,  q4,  q6
+        vadd.i32        q5,  q5,  q1
+
+        vmov            q11, q12
+        vmov            q12, q13
+
+        pop             {pc}
+endfunc
+
+.macro sum_lag2_func type, uv_layout, edge, elems=16
+function sum_\type\()_lag2_\edge\()_neon
+        push            {r1, lr}
+.ifc \edge, left
+        sub             r12, r0,  #2*GRAIN_WIDTH
+        sub             lr,  r0,  #1*GRAIN_WIDTH
+        vld1.8          {q9},  [r12] // load the previous block right above
+        vld1.8          {q12}, [lr]
+.endif
+        sum_lag_n_body  lag2, \type, \uv_layout, \edge, \elems, store=1, uv_coeff=d29[4]
+endfunc
+.endm
+
+sum_lag2_func y,      0,   left
+sum_lag2_func y,      0,   mid
+sum_lag2_func y,      0,   right, 15
+sum_lag2_func uv_444, 444, left
+sum_lag2_func uv_444, 444, mid
+sum_lag2_func uv_444, 444, right, 15
+sum_lag2_func uv_422, 422, left
+sum_lag2_func uv_422, 422, mid
+sum_lag2_func uv_422, 422, right, 9
+sum_lag2_func uv_420, 420, left
+sum_lag2_func uv_420, 420, mid
+sum_lag2_func uv_420, 420, right, 9
+
+
+function sum_lag3_left_above_neon
+        // A separate codepath for the left edge, to avoid reading outside
+        // of the edge of the buffer.
+        sub             r12, r0,  #3*GRAIN_WIDTH
+        vld1.8          {q11, q12}, [r12]
+        vext.8          q12, q11, q12, #13
+        vext.8          q11, q11, q11, #13
+        b               sum_lag3_above_start
+endfunc
+
+function sum_lag3_above_neon
+        sub             r12, r0,  #3*GRAIN_WIDTH + 3
+        vld1.8          {q11, q12}, [r12]
+
+sum_lag3_above_start:
+        vdup.8          d20, d26[0]
+        vext.8          q9,  q11, q12, #1
+        vdup.8          d21, d26[1]
+
+        vmull.s8        q0,  d22, d20
+        vmull.s8        q1,  d23, d20
+        vmull.s8        q6,  d18, d21
+        vmull.s8        q7,  d19, d21
+
+        vext.8          q8,  q11, q12, #2
+        vdup.8          d20, d26[2]
+        vext.8          q9,  q11, q12, #3
+        vdup.8          d21, d26[3]
+
+        vaddl.s16       q2,  d0,  d12
+        vaddl.s16       q3,  d1,  d13
+        vaddl.s16       q4,  d2,  d14
+        vaddl.s16       q5,  d3,  d15
+
+        vmull.s8        q0,  d16, d20
+        vmull.s8        q1,  d17, d20
+        vmull.s8        q6,  d18, d21
+        vmull.s8        q7,  d19, d21
+
+        vaddl.s16       q8,  d0,  d12
+        vaddl.s16       q9,  d1,  d13
+        vaddl.s16       q0,  d2,  d14
+        vaddl.s16       q1,  d3,  d15
+
+        vext.8          q6,  q11, q12, #4
+        vdup.8          d20, d26[4]
+        vext.8          q7,  q11, q12, #5
+        vdup.8          d21, d26[5]
+
+        vadd.i32        q2,  q2,  q8
+        vadd.i32        q3,  q3,  q9
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d12, d20
+        vmull.s8        q1,  d13, d20
+        vmull.s8        q8,  d14, d21
+        vmull.s8        q9,  d15, d21
+
+        sub             r12, r0,  #2*GRAIN_WIDTH + 3
+
+        vaddl.s16       q6,  d0,  d16
+        vaddl.s16       q7,  d1,  d17
+        vaddl.s16       q0,  d2,  d18
+        vaddl.s16       q1,  d3,  d19
+
+        vext.8          q8,  q11, q12, #6
+        vld1.8          {q11, q12}, [r12]
+        vdup.8          d20, d26[6]
+        vdup.8          d21, d26[7]
+
+        vadd.i32        q2,  q2,  q6
+        vadd.i32        q3,  q3,  q7
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d16, d20
+        vmull.s8        q1,  d17, d20
+        vmull.s8        q6,  d22, d21
+        vmull.s8        q7,  d23, d21
+
+        vaddl.s16       q8,  d0,  d12
+        vaddl.s16       q9,  d1,  d13
+        vaddl.s16       q0,  d2,  d14
+        vaddl.s16       q1,  d3,  d15
+
+        vext.8          q6,  q11, q12, #1
+        vdup.8          d20, d27[0]
+        vext.8          q7,  q11, q12, #2
+        vdup.8          d21, d27[1]
+
+        vadd.i32        q2,  q2,  q8
+        vadd.i32        q3,  q3,  q9
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d12, d20
+        vmull.s8        q1,  d13, d20
+        vmull.s8        q8,  d14, d21
+        vmull.s8        q9,  d15, d21
+
+        vaddl.s16       q6,  d0,  d16
+        vaddl.s16       q7,  d1,  d17
+        vaddl.s16       q0,  d2,  d18
+        vaddl.s16       q1,  d3,  d19
+
+        vext.8          q8,  q11, q12, #3
+        vdup.8          d20, d27[2]
+        vext.8          q9,  q11, q12, #4
+        vdup.8          d21, d27[3]
+
+        vadd.i32        q2,  q2,  q6
+        vadd.i32        q3,  q3,  q7
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d16, d20
+        vmull.s8        q1,  d17, d20
+        vmull.s8        q6,  d18, d21
+        vmull.s8        q7,  d19, d21
+
+        sub             r12, r0,  #1*GRAIN_WIDTH + 3
+
+        vaddl.s16       q8,  d0,  d12
+        vaddl.s16       q9,  d1,  d13
+        vaddl.s16       q0,  d2,  d14
+        vaddl.s16       q1,  d3,  d15
+
+        vext.8          q6,  q11, q12, #5
+        vdup.8          d20, d27[4]
+        vext.8          q7,  q11, q12, #6
+        vdup.8          d21, d27[5]
+
+        vld1.8          {q11, q12}, [r12]
+
+        vadd.i32        q2,  q2,  q8
+        vadd.i32        q3,  q3,  q9
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d12, d20
+        vmull.s8        q1,  d13, d20
+        vmull.s8        q8,  d14, d21
+        vmull.s8        q9,  d15, d21
+
+        vaddl.s16       q6,  d0,  d16
+        vaddl.s16       q7,  d1,  d17
+        vaddl.s16       q0,  d2,  d18
+        vaddl.s16       q1,  d3,  d19
+
+        vdup.8          d20, d27[6]
+        vext.8          q9,  q11, q12, #1
+        vdup.8          d21, d27[7]
+
+        vadd.i32        q2,  q2,  q6
+        vadd.i32        q3,  q3,  q7
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d22, d20
+        vmull.s8        q1,  d23, d20
+        vmull.s8        q6,  d18, d21
+        vmull.s8        q7,  d19, d21
+
+        vaddl.s16       q8,  d0,  d12
+        vaddl.s16       q9,  d1,  d13
+        vaddl.s16       q0,  d2,  d14
+        vaddl.s16       q1,  d3,  d15
+
+        vext.8          q6,  q11, q12, #2
+        vdup.8          d20, d28[0]
+        vext.8          q7,  q11, q12, #3
+        vdup.8          d21, d28[1]
+
+        vadd.i32        q2,  q2,  q8
+        vadd.i32        q3,  q3,  q9
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d12, d20
+        vmull.s8        q1,  d13, d20
+        vmull.s8        q8,  d14, d21
+        vmull.s8        q9,  d15, d21
+
+        vaddl.s16       q6,  d0,  d16
+        vaddl.s16       q7,  d1,  d17
+        vaddl.s16       q0,  d2,  d18
+        vaddl.s16       q1,  d3,  d19
+
+        vext.8          q8,  q11, q12, #4
+        vdup.8          d20, d28[2]
+        vext.8          q9,  q11, q12, #5
+        vdup.8          d21, d28[3]
+
+        vadd.i32        q2,  q2,  q6
+        vadd.i32        q3,  q3,  q7
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d16, d20
+        vmull.s8        q1,  d17, d20
+        vmull.s8        q6,  d18, d21
+        vmull.s8        q7,  d19, d21
+
+        vaddl.s16       q8,  d0,  d12
+        vaddl.s16       q9,  d1,  d13
+        vaddl.s16       q0,  d2,  d14
+        vaddl.s16       q1,  d3,  d15
+
+        vext.8          q6,  q11, q12, #6
+        vdup.8          d20, d28[4]
+
+        vadd.i32        q2,  q2,  q8
+        vadd.i32        q3,  q3,  q9
+        vadd.i32        q4,  q4,  q0
+        vadd.i32        q5,  q5,  q1
+
+        vmull.s8        q0,  d12, d20
+        vmull.s8        q1,  d13, d20
+
+        vaddw.s16       q2,  q2,  d0
+        vaddw.s16       q3,  q3,  d1
+        vaddw.s16       q4,  q4,  d2
+        vaddw.s16       q5,  q5,  d3
+
+        bx              lr
+endfunc
+
+.macro sum_lag3_func type, uv_layout, edge, elems=16
+function sum_\type\()_lag3_\edge\()_neon
+        push            {r1, lr}
+        sum_lag_n_body  lag3, \type, \uv_layout, \edge, \elems, store=1, uv_coeff=d29[0]
+endfunc
+.endm
+
+sum_lag3_func y,      0,   left
+sum_lag3_func y,      0,   mid
+sum_lag3_func y,      0,   right, 15
+sum_lag3_func uv_444, 444, left
+sum_lag3_func uv_444, 444, mid
+sum_lag3_func uv_444, 444, right, 15
+sum_lag3_func uv_422, 422, left
+sum_lag3_func uv_422, 422, mid
+sum_lag3_func uv_422, 422, right, 9
+sum_lag3_func uv_420, 420, left
+sum_lag3_func uv_420, 420, mid
+sum_lag3_func uv_420, 420, right, 9
+
+function generate_grain_rows_neon
+        push            {r11,lr}
+1:
+        get_grain_row   d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26
+        subs            r1,  r1,  #1
+        store_grain_row d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26
+        bgt             1b
+        pop             {r11,pc}
+endfunc
+
+function generate_grain_rows_44_neon
+        push            {r11,lr}
+1:
+        get_grain_row_44 d16, d17, d18, d19, d20, d21
+        subs            r1,  r1,  #1
+        store_grain_row_44 d16, d17, d18, d19, d20, d21
+        bgt             1b
+        pop             {r11,pc}
+endfunc
+
+function gen_grain_uv_444_lag0_neon
+        vld1.8          {q3}, [r11]!
+        push            {r11,lr}
+        bl              get_gaussian_neon
+        vrshl.s16       q8,  q0,  q15
+        bl              get_gaussian_neon
+        vrshl.s16       q9,  q0,  q15
+        vqmovn.s16      d0,  q8
+        vqmovn.s16      d1,  q9
+
+        vand            q3,  q3,  q1
+        vmull.s8        q2,  d6,  d22
+        vmull.s8        q3,  d7,  d22
+        vrshl.s16       q2,  q2,  q12
+        vrshl.s16       q3,  q3,  q12
+        vaddw.s8        q2,  q2,  d0
+        vaddw.s8        q3,  q3,  d1
+        vqmovn.s16      d4,  q2
+        vqmovn.s16      d5,  q3
+        vst1.8          {q2}, [r0]!
+        pop             {r11,pc}
+endfunc
+
+function get_grain_row_44_neon
+        push            {r11,lr}
+        get_grain_row_44 d16, d17, d18, d19, d20, d21
+        pop             {r11,pc}
+endfunc
+
+function add_uv_420_coeff_lag0_neon
+        vld1.16         {q2, q3}, [r11]!
+        vld1.16         {q4, q5}, [r12]!
+        vpaddl.s8       q2,  q2
+        vpaddl.s8       q3,  q3
+        vpaddl.s8       q4,  q4
+        vpaddl.s8       q5,  q5
+        vadd.i16        q2,  q2,  q4
+        vadd.i16        q3,  q3,  q5
+        vrshrn.s16      d4,  q2,  #2
+        vrshrn.s16      d5,  q3,  #2
+        b               add_coeff_lag0_start
+endfunc
+
+function add_uv_422_coeff_lag0_neon
+        vld1.16         {q2, q3}, [r11]!
+        vpaddl.s8       q2,  q2
+        vpaddl.s8       q3,  q3
+        vrshrn.s16      d4,  q2,  #1
+        vrshrn.s16      d5,  q3,  #1
+
+add_coeff_lag0_start:
+        vand            q3,  q2,  q1
+        vmull.s8        q2,  d6,  d22
+        vmull.s8        q3,  d7,  d22
+        vrshl.s16       q2,  q2,  q12
+        vrshl.s16       q3,  q3,  q12
+        vaddw.s8        q2,  q2,  d0
+        vaddw.s8        q3,  q3,  d1
+        vqmovn.s16      d4,  q2
+        vqmovn.s16      d5,  q3
+        bx              lr
+endfunc
+
+.macro gen_grain_82 type
+function generate_grain_\type\()_8bpc_neon, export=1
+        push            {r4-r11,lr}
+
+.ifc \type, uv_444
+        mov             r12, r3
+        mov             lr,  #28
+        add             r11, r1,  #3*GRAIN_WIDTH
+        mov             r1,  r2
+        mul             r12, r12, lr
+.endif
+        movrel          r3,  X(gaussian_sequence)
+        ldr             r2,  [r1, #FGD_SEED]
+        ldr             r9,  [r1, #FGD_GRAIN_SCALE_SHIFT]
+.ifc \type, y
+        add             r4,  r1,  #FGD_AR_COEFFS_Y
+.else
+        add             r4,  r1,  #FGD_AR_COEFFS_UV
+.endif
+        adr             r5,  L(gen_grain_\type\()_tbl)
+        ldr             r6,  [r1, #FGD_AR_COEFF_LAG]
+        add             r9,  r9,  #4
+        ldr             r6,  [r5, r6, lsl #2]
+        vdup.16         q15, r9    // 4 + data->grain_scale_shift
+        add             r5,  r5,  r6
+        vneg.s16        q15, q15
+
+.ifc \type, uv_444
+        cmp             r12, #0
+        movw            r10, #0x49d8
+        movw            lr,  #0xb524
+        // Intentionally using a separate register instead of moveq with an
+        // immediate constant, to avoid armv8 deprecated it instruction forms.
+        it              eq
+        moveq           r10, lr
+        add             r4,  r4,  r12       // Add offset to ar_coeffs_uv[1]
+        eor             r2,  r2,  r10
+.endif
+
+        ldr             r7,  [r1, #FGD_AR_COEFF_SHIFT]
+        mov             r8,  #1
+        mov             r10, #1
+        lsl             r8,  r8,  r7        // 1 << ar_coeff_shift
+        lsl             r10, r10, r9        // 1 << (4 + data->grain_scale_shift)
+        lsr             r8,  r8,  #1        // 1 << (ar_coeff_shift - 1)
+        lsr             r10, r10, #1        // 1 << (4 + data->grain_scale_shift - 1)
+
+        bx              r5
+
+        .align 2
+L(gen_grain_\type\()_tbl):
+        .word L(generate_grain_\type\()_lag0) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag1) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag2) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag3) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+
+L(generate_grain_\type\()_lag0):
+.ifc \type, y
+        mov             r1,  #GRAIN_HEIGHT
+        bl              generate_grain_rows_neon
+.else
+
+        mov             r1,  #3
+        bl              generate_grain_rows_neon
+        mov             r1,  #GRAIN_HEIGHT-3
+
+        vdup.16         q12, r7
+        vld1.8          {d22[]}, [r4]       // ar_coeffs_uv[0]
+        vmov.i8         q0,  #0
+        vmov.i8         q1,  #255
+        vext.8          q13, q0,  q1,  #13
+        vext.8          q14, q1,  q0,  #1
+        vneg.s16        q12, q12
+
+1:
+        vmov            q1,  q13
+        bl              gen_grain_uv_444_lag0_neon // 16
+        vmov.i8         q1,  #255
+        bl              gen_grain_uv_444_lag0_neon // 32
+        bl              gen_grain_uv_444_lag0_neon // 48
+        bl              gen_grain_uv_444_lag0_neon // 64
+        vmov            q1,  q14
+        bl              gen_grain_uv_444_lag0_neon // 80
+        get_grain_2     d16
+        subs            r1,  r1,  #1
+        add             r11, r11, #2
+        vst1.16         {d16[0]}, [r0]!
+        bgt             1b
+.endif
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag1):
+        vpush           {q4-q7}
+        mov             r5,  #127
+        vld1.8          {d27[]}, [r4]!      // ar_coeffs_y[0]
+        vld1.8          {d28[]}, [r4]!      // ar_coeffs_y[1]
+        vld1.8          {d29[]}, [r4]       // ar_coeffs_y[2]
+.ifc \type, y
+        ldrsb           r4,  [r4, #1]       // ar_coeffs_y[3]
+.else
+        add             r4,  r4,  #2
+.endif
+
+        mov             r1,  #3
+.ifc \type, uv_444
+        vld1.8          {d13[]}, [r4]       // ar_coeffs_uv[4]
+        ldrsb           r4,  [r4, #-1]      // ar_coeffs_uv[3]
+.endif
+        bl              generate_grain_rows_neon
+
+        mov             r1,  #GRAIN_HEIGHT - 3
+1:
+        sum_\type\()_lag1 q7,  q8,  q8,  q9,  left
+        sum_\type\()_lag1 q8,  q8,  q9,  q10
+        sum_\type\()_lag1 q9,  q9,  q10, q11
+        sum_\type\()_lag1 q10, q10, q11, q12
+        sum_\type\()_lag1 q12, q11, q12, q13, right
+        get_grain_2     d26
+        subs            r1,  r1,  #1
+.ifc \type, uv_444
+        add             r11, r11, #2
+.endif
+        store_grain_row d14, d15, d16, d17, d18, d19, d20, d21, d24, d25, d26
+        vmov            q11, q10
+        vmov            q10, q9
+        vmov            q9,  q8
+        vmov            q8,  q7
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag2):
+        vpush           {q4-q7}
+        mov             r5,  #127
+        vld1.8          {d28,d29}, [r4]     // ar_coeffs_y[0-11], ar_coeffs_uv[0-12]
+
+        vmov.s8         r4,  d29[2]
+        vmov.s8         r10, d29[3]
+
+        mov             r1,  #3
+        bl              generate_grain_rows_neon
+
+        mov             r1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag2_left_neon
+        bl              sum_\type\()_lag2_mid_neon
+        bl              sum_\type\()_lag2_mid_neon
+        bl              sum_\type\()_lag2_mid_neon
+        bl              sum_\type\()_lag2_right_neon
+        get_grain_2     d16
+        subs            r1,  r1,  #1
+.ifc \type, uv_444
+        add             r11, r11, #2
+.endif
+        vst1.16         {d16[0]}, [r0]!
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag3):
+        vpush           {q4-q7}
+        mov             r5,  #127
+        vld1.8          {q13, q14}, [r4]    // ar_coeffs_y[0-23], ar_coeffs_uv[0-24]
+
+        vmov.u8         r4,  d28[5]
+        vmov.u8         r10, d28[6]
+        vmov.u8         r12, d28[7]
+
+        orr             r4,  r4,  r10, lsl #8
+        orr             r4,  r4,  r12, lsl #16
+
+        mov             r1,  #3
+        vpush           {d26}
+        bl              generate_grain_rows_neon
+        vpop            {d26}
+
+        mov             r1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag3_left_neon
+        bl              sum_\type\()_lag3_mid_neon
+        bl              sum_\type\()_lag3_mid_neon
+        bl              sum_\type\()_lag3_mid_neon
+        bl              sum_\type\()_lag3_right_neon
+        get_grain_2     d16
+        subs            r1,  r1,  #1
+.ifc \type, uv_444
+        add             r11, r11, #2
+.endif
+        vst1.16         {d16[0]}, [r0]!
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+gen_grain_82 y
+gen_grain_82 uv_444
+
+.macro set_height dst, type
+.ifc \type, uv_420
+        mov             \dst,  #SUB_GRAIN_HEIGHT-3
+.else
+        mov             \dst,  #GRAIN_HEIGHT-3
+.endif
+.endm
+
+.macro increment_y_ptr reg, type
+.ifc \type, uv_420
+        add             \reg, \reg, #2*GRAIN_WIDTH-(3*32)
+.else
+        sub             \reg, \reg, #3*32-GRAIN_WIDTH
+.endif
+.endm
+
+.macro gen_grain_44 type
+function generate_grain_\type\()_8bpc_neon, export=1
+        push            {r4-r11,lr}
+
+        mov             r12, r3
+        mov             lr,  #28
+        add             r11, r1,  #3*GRAIN_WIDTH-3
+        mov             r1,  r2
+        mul             r12, r12, lr
+
+        movrel          r3,  X(gaussian_sequence)
+        ldr             r2,  [r1, #FGD_SEED]
+        ldr             r9,  [r1, #FGD_GRAIN_SCALE_SHIFT]
+        add             r4,  r1,  #FGD_AR_COEFFS_UV
+        adr             r5,  L(gen_grain_\type\()_tbl)
+        ldr             r6,  [r1, #FGD_AR_COEFF_LAG]
+        add             r9,  r9,  #4
+        ldr             r6,  [r5, r6, lsl #2]
+        vdup.16         q15, r9    // 4 + data->grain_scale_shift
+        add             r5,  r5,  r6
+        vneg.s16        q15, q15
+
+        cmp             r12, #0
+        movw            r10, #0x49d8
+        movw            lr,  #0xb524
+        // Intentionally using a separate register instead of moveq with an
+        // immediate constant, to avoid armv8 deprecated it instruction forms.
+        it              eq
+        moveq           r10, lr
+        add             r4,  r4,  r12       // Add offset to ar_coeffs_uv[1]
+        eor             r2,  r2,  r10
+
+        ldr             r7,  [r1, #FGD_AR_COEFF_SHIFT]
+        mov             r8,  #1
+        mov             r10, #1
+        lsl             r8,  r8,  r7        // 1 << ar_coeff_shift
+        lsl             r10, r10, r9        // 1 << (4 + data->grain_scale_shift)
+        lsr             r8,  r8,  #1        // 1 << (ar_coeff_shift - 1)
+        lsr             r10, r10, #1        // 1 << (4 + data->grain_scale_shift - 1)
+        bx              r5
+
+        .align 2
+L(gen_grain_\type\()_tbl):
+        .word L(generate_grain_\type\()_lag0) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag1) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag2) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag3) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+
+L(generate_grain_\type\()_lag0):
+.ifc \type, uv_420
+        vpush           {q4-q5}
+.endif
+        mov             r1,  #3
+        bl              generate_grain_rows_44_neon
+        set_height      r1,  \type
+
+        vdup.16         q12, r7
+        vld1.8          {d22[]}, [r4]       // ar_coeffs_uv[0]
+        vmov.i8         q0,  #0
+        vmov.i8         q1,  #255
+        vext.8          q13, q0,  q1,  #13
+        vext.8          q14, q1,  q0,  #7
+        vneg.s16        q12, q12
+
+1:
+        bl              get_grain_row_44_neon
+.ifc \type, uv_420
+        add             r12, r11, #GRAIN_WIDTH
+.endif
+        vmov            q1,  q13
+        vmov            q0,  q8
+        bl              add_\type\()_coeff_lag0_neon
+        vmov.i8         q1,  #255
+        vmov            q0,  q9
+        vmov            q8,  q2
+        bl              add_\type\()_coeff_lag0_neon
+        vmov.i8         q1,  q14
+        vmov            q0,  q10
+        vmov            q9,  q2
+        bl              add_\type\()_coeff_lag0_neon
+        vmov            q10, q2
+        subs            r1,  r1,  #1
+        increment_y_ptr r11, \type
+        store_grain_row_44 d16, d17, d18, d19, d20, d21
+        bgt             1b
+
+.ifc \type, uv_420
+        vpop            {q4-q5}
+.endif
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag1):
+        vpush           {q4-q7}
+        mov             r5,  #127
+        vld1.8          {d27[]}, [r4]!      // ar_coeffs_uv[0]
+        vld1.8          {d28[]}, [r4]!      // ar_coeffs_uv[1]
+        vld1.8          {d29[]}, [r4]       // ar_coeffs_uv[2]
+        add             r4,  r4,  #2
+
+        mov             r1,  #3
+        vld1.8          {d13[]}, [r4]       // ar_coeffs_uv[4]
+        ldrsb           r4,  [r4, #-1]      // ar_coeffs_uv[3]
+        bl              generate_grain_rows_44_neon
+
+        set_height      r1,  \type
+1:
+        sum_\type\()_lag1 q7,  q8,  q8,  q9,  left
+        sum_\type\()_lag1 q8,  q8,  q9,  q10
+        sum_\type\()_lag1 q10, q9,  q10, q11, right
+        subs            r1,  r1,  #1
+        increment_y_ptr r11, \type
+        store_grain_row_44 d14, d15, d16, d17, d20, d21
+        vmov            q9,  q8
+        vmov            q8,  q7
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag2):
+        vpush           {q4-q7}
+        mov             r5,  #127
+        vld1.8          {d28,d29}, [r4]     // ar_coeffs_uv[0-12]
+
+        vmov.s8         r4,  d29[2]
+        vmov.s8         r10, d29[3]
+
+        mov             r1,  #3
+        bl              generate_grain_rows_44_neon
+
+        set_height      r1,  \type
+1:
+        bl              sum_\type\()_lag2_left_neon
+        bl              sum_\type\()_lag2_mid_neon
+        bl              sum_\type\()_lag2_right_neon
+        subs            r1,  r1,  #1
+        increment_y_ptr r11, \type
+        add             r0,  r0,  #GRAIN_WIDTH-48
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag3):
+        vpush           {q4-q7}
+        mov             r5,  #127
+        vld1.8          {q13, q14}, [r4]    // ar_coeffs_y[0-23], ar_coeffs_uv[0-24]
+
+        vmov.u8         r4,  d28[5]
+        vmov.u8         r10, d28[6]
+        vmov.u8         r12, d28[7]
+
+        orr             r4,  r4,  r10, lsl #8
+        orr             r4,  r4,  r12, lsl #16
+
+        mov             r1,  #3
+        bl              generate_grain_rows_44_neon
+
+        set_height      r1,  \type
+1:
+        bl              sum_\type\()_lag3_left_neon
+        bl              sum_\type\()_lag3_mid_neon
+        bl              sum_\type\()_lag3_right_neon
+        subs            r1,  r1,  #1
+        increment_y_ptr r11, \type
+        add             r0,  r0,  #GRAIN_WIDTH-48
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+gen_grain_44 uv_420
+gen_grain_44 uv_422
+
+.macro gather_interleaved dst1, dst2, src1, src2, off
+        vmov.u8         r11, \src1[0+\off]
+        vmov.u8         r12, \src2[0+\off]
+        add             r11, r11, r3
+        vmov.u8         lr,  \src1[2+\off]
+        add             r12, r12, r3
+        vld1.8          {\dst1[0+\off]}, [r11]
+        vmov.u8         r11, \src2[2+\off]
+        add             lr,  lr,  r3
+        vld1.8          {\dst2[0+\off]}, [r12]
+        vmov.u8         r12, \src1[4+\off]
+        add             r11, r11, r3
+        vld1.8          {\dst1[2+\off]}, [lr]
+        vmov.u8         lr,  \src2[4+\off]
+        add             r12, r12, r3
+        vld1.8          {\dst2[2+\off]}, [r11]
+        vmov.u8         r11, \src1[6+\off]
+        add             lr,  lr,  r3
+        vld1.8          {\dst1[4+\off]}, [r12]
+        vmov.u8         r12, \src2[6+\off]
+        add             r11, r11, r3
+        vld1.8          {\dst2[4+\off]}, [lr]
+        add             r12, r12, r3
+        vld1.8          {\dst1[6+\off]}, [r11]
+        vld1.8          {\dst2[6+\off]}, [r12]
+.endm
+
+.macro gather dst1, dst2, dst3, dst4, src1, src2, src3, src4
+        gather_interleaved \dst1, \dst3, \src1, \src3, 0
+        gather_interleaved \dst1, \dst3, \src1, \src3, 1
+        gather_interleaved \dst2, \dst4, \src2, \src4, 0
+        gather_interleaved \dst2, \dst4, \src2, \src4, 1
+.endm
+
+function gather32_neon
+        push            {r11-r12,lr}
+        gather          d8,  d9,  d10, d11, d0,  d1,  d2,  d3
+        pop             {r11-r12,pc}
+endfunc
+
+function gather16_neon
+        push            {r11-r12,lr}
+        gather_interleaved d8,  d9,  d0,  d1,  0
+        gather_interleaved d8,  d9,  d0,  d1,  1
+        pop             {r11-r12,pc}
+endfunc
+
+const overlap_coeffs_0, align=4
+        .byte 27, 17, 0,  0,  0,  0,  0,  0
+        .byte 17, 27, 32, 32, 32, 32, 32, 32
+endconst
+
+const overlap_coeffs_1, align=4
+        .byte 23, 0,  0,  0,  0,  0,  0,  0
+        .byte 22, 32, 32, 32, 32, 32, 32, 32
+endconst
+
+.macro calc_offset offx, offy, src, sx, sy
+        and             \offy, \src,  #0xF     // randval & 0xF
+        lsr             \offx, \src,  #4       // randval >> 4
+.if \sy == 0
+        add             \offy, \offy, \offy    // 2 * (randval & 0xF)
+.endif
+.if \sx == 0
+        add             \offx, \offx, \offx    // 2 * (randval >> 4)
+.endif
+.endm
+
+.macro add_offset dst, offx, offy, src, stride
+        mla             \dst, \stride, \offy, \src // grain_lut += grain_stride * offy
+        add             \dst, \dst, \offx          // grain_lut += offx
+.endm
+
+// void dav1d_fgy_32x32_8bpc_neon(pixel *const dst, const pixel *const src,
+//                                const ptrdiff_t stride,
+//                                const uint8_t scaling[SCALING_SIZE],
+//                                const int scaling_shift,
+//                                const entry grain_lut[][GRAIN_WIDTH],
+//                                const int offsets[][2],
+//                                const int h, const ptrdiff_t clip,
+//                                const ptrdiff_t type);
+function fgy_32x32_8bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]   // scaling_shift, grain_lut
+        ldrd            r6,  r7,  [sp, #108]   // offsets, h
+        ldr             r8,       [sp, #116]   // clip
+        mov             r9,  #GRAIN_WIDTH      // grain_lut stride
+
+        neg             r4,  r4
+        vdup.16         q13, r4                // -scaling_shift
+        cmp             r8,  #0
+
+        movrel_local    r12, overlap_coeffs_0
+
+        beq             1f
+        // clip
+        vmov.i8         q14, #16
+        vmov.i8         q15, #235
+        b               2f
+1:
+        // no clip
+        vmov.i8         q14, #0
+        vmov.i8         q15, #255
+2:
+
+        vld1.8          {d24, d25}, [r12, :128] // overlap_coeffs
+
+        add             r5,  r5,  #9           // grain_lut += 9
+        add             r5,  r5,  r9,  lsl #3  // grain_lut += 8 * grain_stride
+        add             r5,  r5,  r9           // grain_lut += grain_stride
+
+        ldr             r10, [r6, #8]          // offsets[1][0]
+        calc_offset     r10, r4,  r10, 0,   0
+        add_offset      r4,  r10, r4,  r5,  r9
+        ldr             r10, [r6, #4]          // offsets[0][1]
+        calc_offset     r10, r11, r10, 0,   0
+        add_offset      r11, r10, r11, r5,  r9
+        ldr             r10, [r6, #12]         // offsets[1][1]
+        calc_offset     r10, r8,  r10, 0,   0
+        add_offset      r8,  r10, r8,  r5,  r9
+        ldr             r6,  [r6]              // offsets[0][0]
+        calc_offset     r6,  lr,  r6,  0,   0
+        add_offset      r5,  r6,  lr,  r5,  r9
+
+        add             r4,  r4,  #32          // grain_lut += FG_BLOCK_SIZE * bx
+        add             r6,  r11, r9,  lsl #5  // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+
+        ldr             r10, [sp, #120]        // type
+        adr             r11, L(fgy_loop_tbl)
+
+        tst             r10, #1
+        ldr             r10, [r11, r10, lsl #2]
+
+        add             r8,  r8,  r9,  lsl #5  // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             r8,  r8,  #32          // grain_lut += FG_BLOCK_SIZE * bx
+
+        add             r11, r11, r10
+
+        beq             1f
+        // y overlap
+        vdup.8          d14, d24[0]
+        vdup.8          d15, d24[1]
+        mov             r10, r7                // backup actual h
+        mov             r7,  #2
+1:
+        bx              r11
+endfunc
+
+function fgy_loop_neon
+L(fgy_loop_tbl):
+        .word L(loop_00) - L(fgy_loop_tbl) + CONFIG_THUMB
+        .word L(loop_01) - L(fgy_loop_tbl) + CONFIG_THUMB
+        .word L(loop_10) - L(fgy_loop_tbl) + CONFIG_THUMB
+        .word L(loop_11) - L(fgy_loop_tbl) + CONFIG_THUMB
+
+.macro fgy ox, oy
+L(loop_\ox\oy):
+1:
+.if \ox
+        vld1.8          {d8},       [r4],       r9 // grain_lut old
+.endif
+.if \oy
+        vld1.8          {q2, q3},   [r6],       r9 // grain_lut top
+.endif
+.if \ox && \oy
+        vld1.8          {d10},      [r8],       r9 // grain_lut top old
+.endif
+        vld1.8          {q0,  q1},  [r1, :128], r2 // src
+        vld1.8          {q10, q11}, [r5],       r9 // grain_lut
+
+.if \ox
+        vmull.s8        q4,  d8,  d24
+        vmlal.s8        q4,  d20, d25
+.endif
+
+.if \oy
+.if \ox
+        vmull.s8        q5,  d10, d24
+        vmlal.s8        q5,  d4,  d25
+        vqrshrn.s16     d20, q4,  #5
+        vqrshrn.s16     d4,  q5,  #5
+.endif
+
+        vmull.s8        q4,  d20, d15
+        vmull.s8        q5,  d21, d15
+        vmull.s8        q8,  d22, d15
+        vmull.s8        q9,  d23, d15
+        vmlal.s8        q4,  d4,  d14
+        vmlal.s8        q5,  d5,  d14
+        vmlal.s8        q8,  d6,  d14
+        vmlal.s8        q9,  d7,  d14
+        vqrshrn.s16     d20, q4,  #5
+        vqrshrn.s16     d21, q5,  #5
+        vqrshrn.s16     d22, q8,  #5
+        vqrshrn.s16     d23, q9,  #5
+.elseif \ox
+        vqrshrn.s16     d20, q4,  #5
+.endif
+
+        bl              gather32_neon
+
+        vmovl.s8        q8,  d20       // grain
+        vmovl.s8        q9,  d21
+        vmovl.s8        q10, d22
+        vmovl.s8        q11, d23
+
+        vmovl.u8        q2,  d8        // scaling
+        vmovl.u8        q3,  d9
+        vmovl.u8        q4,  d10
+        vmovl.u8        q5,  d11
+
+        vmul.i16        q8,  q8,  q2   // scaling * grain
+        vmul.i16        q9,  q9,  q3
+        vmul.i16        q10, q10, q4
+        vmul.i16        q11, q11, q5
+
+        vrshl.s16       q8,  q8,  q13  // round2(scaling * grain, scaling_shift)
+        vrshl.s16       q9,  q9,  q13
+        vrshl.s16       q10, q10, q13
+        vrshl.s16       q11, q11, q13
+
+        vaddw.u8        q8,  q8,  d0   // *src + noise
+        vaddw.u8        q9,  q9,  d1
+        vaddw.u8        q10, q10, d2
+        vaddw.u8        q11, q11, d3
+
+        vqmovun.s16     d0,  q8
+        vqmovun.s16     d1,  q9
+        vqmovun.s16     d2,  q10
+        vqmovun.s16     d3,  q11
+
+        vmax.u8         q0,  q0,  q14
+        vmax.u8         q1,  q1,  q14
+        vmin.u8         q0,  q0,  q15
+        vmin.u8         q1,  q1,  q15
+
+        subs            r7,  r7,  #1
+.if \oy
+        vdup.8          d14, d25[0]
+        vdup.8          d15, d25[1]
+.endif
+        vst1.8          {q0, q1}, [r0, :128], r2 // dst
+        bgt             1b
+
+.if \oy
+        cmp             r10, #2
+        sub             r7,  r10, #2           // restore actual remaining h
+        bgt             L(loop_\ox\()0)
+.endif
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+.endm
+
+        fgy             0, 0
+        fgy             0, 1
+        fgy             1, 0
+        fgy             1, 1
+endfunc
+
+// void dav1d_fguv_32x32_420_8bpc_neon(pixel *const dst,
+//                                     const pixel *const src,
+//                                     const ptrdiff_t stride,
+//                                     const uint8_t scaling[SCALING_SIZE],
+//                                     const Dav1dFilmGrainData *const data,
+//                                     const entry grain_lut[][GRAIN_WIDTH],
+//                                     const pixel *const luma_row,
+//                                     const ptrdiff_t luma_stride,
+//                                     const int offsets[][2],
+//                                     const ptrdiff_t h, const ptrdiff_t uv,
+//                                     const ptrdiff_t is_id,
+//                                     const ptrdiff_t type);
+.macro fguv layout, sx, sy
+function fguv_32x32_\layout\()_8bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]   // data, grain_lut
+        ldrd            r6,  r7,  [sp, #108]   // luma_row, luma_stride
+        ldrd            r8,  r9,  [sp, #116]   // offsets, h
+        ldrd            r10, r11, [sp, #124]   // uv, is_id
+
+        // !csfl
+        add             r10, r4,  r10, lsl #2  // + 4*uv
+        add             r12, r10, #FGD_UV_LUMA_MULT
+        add             lr,  r10, #FGD_UV_MULT
+        add             r10, r10, #FGD_UV_OFFSET
+        vld1.16         {d4[]},  [r12]         // uv_luma_mult
+        vld1.16         {d4[2]}, [r10]         // uv_offset
+        vld1.16         {d4[1]}, [lr]          // uv_mult
+
+        ldr             lr,  [r4, #FGD_SCALING_SHIFT]
+        ldr             r12, [r4, #FGD_CLIP_TO_RESTRICTED_RANGE]
+        neg             lr,  lr                // -scaling_shift
+
+        cmp             r12, #0
+        vdup.16         q13, lr                // -scaling_shift
+
+        beq             1f
+        // clip
+        cmp             r11, #0
+        vmov.i8         q14, #16
+        vmov.i8         q15, #240
+        beq             2f
+        // is_id
+        vmov.i8         q15, #235
+        b               2f
+1:
+        // no clip
+        vmov.i8         q14, #0
+        vmov.i8         q15, #255
+2:
+
+        mov             r10, #GRAIN_WIDTH      // grain_lut stride
+
+        add             r5,  r5,  #(3 + (2 >> \sx)*3) // grain_lut += 9 or 6
+.if \sy
+        add             r5,  r5,  r10, lsl #2  // grain_lut += 4 * grain_stride
+        add             r5,  r5,  r10, lsl #1  // grain_lut += 2 * grain_stride
+.else
+        add             r5,  r5,  r10, lsl #3  // grain_lut += 8 * grain_stride
+        add             r5,  r5,  r10          // grain_lut += grain_stride
+.endif
+
+        ldr             r12, [r8, #8]          // offsets[1][0]
+        calc_offset     r12, r4,  r12, \sx, \sy
+        add_offset      r4,  r12, r4,  r5,  r10
+
+        ldr             r12, [r8, #4]          // offsets[0][1]
+        calc_offset     r12, lr,  r12, \sx, \sy
+        add_offset      lr,  r12, lr,  r5,  r10
+
+        ldr             r12, [r8, #12]         // offsets[1][1]
+        calc_offset     r12, r11, r12, \sx, \sy
+        add_offset      r11, r12, r11, r5,  r10
+
+        ldr             r8,  [r8]              // offsets[0][0]
+        calc_offset     r8,  r12, r8,  \sx, \sy
+        add_offset      r5,  r8,  r12, r5,  r10
+
+        add             r4,  r4,  #(32 >> \sx) // grain_lut += FG_BLOCK_SIZE * bx
+        add             r8,  lr,  r10, lsl #(5 - \sy) // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             r11, r11, r10, lsl #(5 - \sy) // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             r11, r11, #(32 >> \sx) // grain_lut += FG_BLOCK_SIZE * bx
+
+        movrel_local    r12, overlap_coeffs_\sx
+        ldr             lr,  [sp, #132]        // type
+
+        vld1.8          {d24, d25}, [r12, :128] // overlap_coeffs
+
+        movrel_local    r12, L(fguv_loop_sx\sx\()_tbl)
+#if CONFIG_THUMB
+        // This uses movrel_local instead of adr above, because the target
+        // can be out of range for adr. But movrel_local leaves the thumb bit
+        // set on COFF (but probably wouldn't if building for thumb on ELF),
+        // thus try to clear the bit for robustness.
+        bic             r12, r12, #1
+#endif
+
+        tst             lr,  #1
+        ldr             lr,  [r12, lr,  lsl #2]
+
+        add             r12, r12, lr
+
+        beq             1f
+        // y overlap
+        sub             lr,  r9,  #(2 >> \sy)  // backup remaining h
+        mov             r9,  #(2 >> \sy)
+
+1:
+
+.if \sy
+        vmov.i8         d6,  #23
+        vmov.i8         d7,  #22
+.else
+        vmov.i8         d6,  #27
+        vmov.i8         d7,  #17
+.endif
+
+.if \sy
+        add             r7,  r7,  r7           // luma_stride *= 2
+.endif
+
+        bx              r12
+endfunc
+.endm
+
+fguv 420, 1, 1
+fguv 422, 1, 0
+fguv 444, 0, 0
+
+function fguv_loop_sx0_neon
+L(fguv_loop_sx0_tbl):
+        .word L(fguv_loop_sx0_csfl0_00) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl0_01) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl0_10) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl0_11) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl1_00) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl1_01) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl1_10) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl1_11) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+
+.macro fguv_loop_sx0 csfl, ox, oy
+L(fguv_loop_sx0_csfl\csfl\()_\ox\oy):
+.if \oy
+        mov             r12, lr
+.endif
+1:
+.if \ox
+        vld1.8          {d8},       [r4],        r10 // grain_lut old
+.endif
+.if \oy
+        vld1.8          {q8, q9},   [r8],        r10 // grain_lut top
+.endif
+.if \ox && \oy
+        vld1.8          {d10},      [r11],       r10 // grain_lut top old
+.endif
+        vld1.8          {q0,  q1},  [r6, :128],  r7  // luma
+        vld1.8          {q10, q11}, [r5],        r10 // grain_lut
+
+.if \ox
+        vmull.s8        q4,  d8,  d24
+        vmlal.s8        q4,  d20, d25
+.endif
+
+.if \oy
+.if \ox
+        vmull.s8        q5,  d10, d24
+        vmlal.s8        q5,  d16, d25
+        vqrshrn.s16     d20, q4,  #5
+        vqrshrn.s16     d16, q5,  #5
+.endif
+
+        vmull.s8        q4,  d20, d7
+        vmull.s8        q5,  d21, d7
+        vmull.s8        q6,  d22, d7
+        vmull.s8        q7,  d23, d7
+        vmlal.s8        q4,  d16, d6
+        vmlal.s8        q5,  d17, d6
+        vmlal.s8        q6,  d18, d6
+        vmlal.s8        q7,  d19, d6
+        vqrshrn.s16     d20, q4,  #5
+        vqrshrn.s16     d21, q5,  #5
+        vqrshrn.s16     d22, q6,  #5
+        vqrshrn.s16     d23, q7,  #5
+.elseif \ox
+        vqrshrn.s16     d20, q4,  #5
+.endif
+.if !\csfl
+        vld1.8          {q8,  q9},  [r1, :128] // src
+        vmovl.u8        q4,  d0
+        vmovl.u8        q5,  d1
+        vmovl.u8        q6,  d2
+        vmovl.u8        q7,  d3
+        vmovl.u8        q0,  d16
+        vmovl.u8        q1,  d17
+        vmovl.u8        q8,  d18
+        vmovl.u8        q9,  d19
+        vmul.i16        q4,  q4,  d4[0]
+        vmul.i16        q5,  q5,  d4[0]
+        vmul.i16        q6,  q6,  d4[0]
+        vmul.i16        q7,  q7,  d4[0]
+        vmul.i16        q0,  q0,  d4[1]
+        vmul.i16        q1,  q1,  d4[1]
+        vmul.i16        q8,  q8,  d4[1]
+        vmul.i16        q9,  q9,  d4[1]
+        vqadd.s16       q4,  q4,  q0
+        vqadd.s16       q5,  q5,  q1
+        vqadd.s16       q6,  q6,  q8
+        vqadd.s16       q7,  q7,  q9
+        vdup.16         q0,  d4[2]
+        vshr.s16        q4,  q4,  #6
+        vshr.s16        q5,  q5,  #6
+        vshr.s16        q6,  q6,  #6
+        vshr.s16        q7,  q7,  #6
+        vadd.i16        q4,  q4,  q0
+        vadd.i16        q5,  q5,  q0
+        vadd.i16        q6,  q6,  q0
+        vadd.i16        q7,  q7,  q0
+        vqmovun.s16     d0,  q4
+        vqmovun.s16     d1,  q5
+        vqmovun.s16     d2,  q6
+        vqmovun.s16     d3,  q7
+.endif
+
+        bl              gather32_neon
+
+        vld1.8          {q0,  q1},  [r1, :128], r2 // src
+
+        vmovl.s8        q8,  d20       // grain
+        vmovl.s8        q9,  d21
+        vmovl.s8        q10, d22
+        vmovl.s8        q11, d23
+
+        vmovl.u8        q6,  d8        // scaling
+        vmovl.u8        q7,  d9
+        vmovl.u8        q4,  d10
+        vmovl.u8        q5,  d11
+
+        vmul.i16        q8,  q8,  q6   // scaling * grain
+        vmul.i16        q9,  q9,  q7
+        vmul.i16        q10, q10, q4
+        vmul.i16        q11, q11, q5
+
+        vrshl.s16       q8,  q8,  q13  // round2(scaling * grain, scaling_shift)
+        vrshl.s16       q9,  q9,  q13
+        vrshl.s16       q10, q10, q13
+        vrshl.s16       q11, q11, q13
+
+        vaddw.u8        q8,  q8,  d0   // *src + noise
+        vaddw.u8        q9,  q9,  d1
+        vaddw.u8        q10, q10, d2
+        vaddw.u8        q11, q11, d3
+
+        vqmovun.s16     d0,  q8
+        vqmovun.s16     d1,  q9
+        vqmovun.s16     d2,  q10
+        vqmovun.s16     d3,  q11
+
+        vmax.u8         q0,  q0,  q14
+        vmax.u8         q1,  q1,  q14
+        vmin.u8         q0,  q0,  q15
+        vmin.u8         q1,  q1,  q15
+
+        subs            r9,  r9,  #1
+.if \oy
+        vdup.8          d6,  d25[0]
+        vdup.8          d7,  d25[1]
+.endif
+
+        vst1.8          {q0, q1}, [r0, :128], r2 // dst
+        bgt             1b
+
+.if \oy
+        cmp             r12, #0
+        mov             r9,  r12               // restore actual remaining h
+        bgt             L(fguv_loop_sx0_csfl\csfl\()_\ox\()0)
+.endif
+        b               9f
+.endm
+        fguv_loop_sx0   0, 0, 0
+        fguv_loop_sx0   0, 0, 1
+        fguv_loop_sx0   0, 1, 0
+        fguv_loop_sx0   0, 1, 1
+        fguv_loop_sx0   1, 0, 0
+        fguv_loop_sx0   1, 0, 1
+        fguv_loop_sx0   1, 1, 0
+        fguv_loop_sx0   1, 1, 1
+
+9:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function fguv_loop_sx1_neon
+L(fguv_loop_sx1_tbl):
+        .word L(fguv_loop_sx1_csfl0_00) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl0_01) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl0_10) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl0_11) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl1_00) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl1_01) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl1_10) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl1_11) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+
+.macro fguv_loop_sx1 csfl, ox, oy
+L(fguv_loop_sx1_csfl\csfl\()_\ox\oy):
+.if \oy
+        mov             r12, lr
+.endif
+1:
+.if \ox
+        vld1.8          {d8},       [r4],        r10 // grain_lut old
+.endif
+.if \oy
+        vld1.8          {q8},       [r8],        r10 // grain_lut top
+.endif
+.if \ox && \oy
+        vld1.8          {d10},      [r11],       r10 // grain_lut top old
+.endif
+        vld1.8          {q0,  q1},  [r6, :128],  r7  // luma
+        vld1.8          {q10},      [r5],        r10 // grain_lut
+        vld1.8          {q11},      [r1, :128],  r2  // src
+
+.if \ox
+        vmull.s8        q4,  d8,  d24
+        vmlal.s8        q4,  d20, d25
+.endif
+
+        vpaddl.u8       q0,  q0
+        vpaddl.u8       q1,  q1
+.if \oy
+.if \ox
+        vmull.s8        q5,  d10, d24
+        vmlal.s8        q5,  d16, d25
+        vqrshrn.s16     d20, q4,  #5
+        vqrshrn.s16     d16, q5,  #5
+.endif
+
+        vmull.s8        q4,  d20, d7
+        vmull.s8        q5,  d21, d7
+        vmlal.s8        q4,  d16, d6
+        vmlal.s8        q5,  d17, d6
+        vqrshrn.s16     d20, q4,  #5
+        vqrshrn.s16     d21, q5,  #5
+.elseif \ox
+        vqrshrn.s16     d20, q4,  #5
+.endif
+.if \csfl
+        vrshrn.u16      d0,  q0,  #1
+        vrshrn.u16      d1,  q1,  #1
+.else
+        vrshr.u16       q4,  q0,  #1
+        vrshr.u16       q5,  q1,  #1
+        vmovl.u8        q0,  d22
+        vmovl.u8        q1,  d23
+        vmul.i16        q4,  q4,  d4[0]
+        vmul.i16        q5,  q5,  d4[0]
+        vmul.i16        q0,  q0,  d4[1]
+        vmul.i16        q1,  q1,  d4[1]
+        vqadd.s16       q4,  q4,  q0
+        vqadd.s16       q5,  q5,  q1
+        vdup.16         q0,  d4[2]
+        vshr.s16        q4,  q4,  #6
+        vshr.s16        q5,  q5,  #6
+        vadd.i16        q4,  q4,  q0
+        vadd.i16        q5,  q5,  q0
+        vqmovun.s16     d0,  q4
+        vqmovun.s16     d1,  q5
+.endif
+
+        bl              gather16_neon
+
+        vmovl.s8        q8,  d20       // grain
+        vmovl.s8        q9,  d21
+
+        vmovl.u8        q6,  d8        // scaling
+        vmovl.u8        q7,  d9
+
+        vmul.i16        q8,  q8,  q6   // scaling * grain
+        vmul.i16        q9,  q9,  q7
+
+        vrshl.s16       q8,  q8,  q13  // round2(scaling * grain, scaling_shift)
+        vrshl.s16       q9,  q9,  q13
+
+        vaddw.u8        q8,  q8,  d22  // *src + noise
+        vaddw.u8        q9,  q9,  d23
+
+        vqmovun.s16     d0,  q8
+        vqmovun.s16     d1,  q9
+
+        vmax.u8         q0,  q0,  q14
+        vmin.u8         q0,  q0,  q15
+
+        subs            r9,  r9,  #1
+.if \oy
+        vswp            d6,  d7
+.endif
+        vst1.8          {q0}, [r0, :128], r2 // dst
+        bgt             1b
+
+.if \oy
+        cmp             r12, #0
+        mov             r9,  r12               // restore actual remaining h
+        bgt             L(fguv_loop_sx1_csfl\csfl\()_\ox\()0)
+.endif
+
+        b               9f
+.endm
+        fguv_loop_sx1   0, 0, 0
+        fguv_loop_sx1   0, 0, 1
+        fguv_loop_sx1   0, 1, 0
+        fguv_loop_sx1   0, 1, 1
+        fguv_loop_sx1   1, 0, 0
+        fguv_loop_sx1   1, 0, 1
+        fguv_loop_sx1   1, 1, 0
+        fguv_loop_sx1   1, 1, 1
+
+9:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/filmgrain16.S b/media/libdav1d/src/src/arm/32/filmgrain16.S
new file mode 100644
index 0000000000..d10bffff2f
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/filmgrain16.S
@@ -0,0 +1,2137 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * Copyright © 2021, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+#include "src/arm/asm-offsets.h"
+
+#define GRAIN_WIDTH 82
+#define GRAIN_HEIGHT 73
+
+#define SUB_GRAIN_WIDTH 44
+#define SUB_GRAIN_HEIGHT 38
+
+.macro increment_seed steps, shift=1
+        lsr             r11, r2,  #3
+        lsr             r12, r2,  #12
+        lsr             lr,  r2,  #1
+        eor             r11, r2,  r11                     // (r >> 0) ^ (r >> 3)
+        eor             r12, r12, lr                      // (r >> 12) ^ (r >> 1)
+        eor             r11, r11, r12                     // (r >> 0) ^ (r >> 3) ^ (r >> 12) ^ (r >> 1)
+.if \shift
+        lsr             r2,  r2,  #\steps
+.endif
+        and             r11, r11, #((1 << \steps) - 1)    // bit
+.if \shift
+        orr             r2,  r2,  r11, lsl #(16 - \steps) // *state
+.else
+        orr             r2,  r2,  r11, lsl #16            // *state
+.endif
+.endm
+
+.macro read_rand dest, bits, age
+        ubfx            \dest,  r2,   #16 - \bits - \age, #\bits
+.endm
+
+.macro read_shift_rand dest, bits
+        ubfx            \dest,  r2,   #17 - \bits, #\bits
+        lsr             r2,  r2,  #1
+.endm
+
+// special calling convention:
+// r2 holds seed
+// r3 holds dav1d_gaussian_sequence
+// clobbers r11-r12
+// returns in d0-d1
+function get_gaussian_neon
+        push            {r5-r6,lr}
+        increment_seed  4
+        read_rand       r5,  11,  3
+        read_rand       r6,  11,  2
+        add             r5,  r3,  r5,  lsl #1
+        add             r6,  r3,  r6,  lsl #1
+        vld1.16         {d0[0]}, [r5]
+        read_rand       r5,  11,  1
+        vld1.16         {d0[1]}, [r6]
+        add             r5,  r3,  r5,  lsl #1
+        read_rand       r6, 11,  0
+        increment_seed  4
+        add             r6,  r3,  r6,  lsl #1
+        vld1.16         {d0[2]}, [r5]
+        read_rand       r5,  11,  3
+        vld1.16         {d0[3]}, [r6]
+        add             r5,  r3,  r5,  lsl #1
+        read_rand       r6,  11,  2
+        vld1.16         {d1[0]}, [r5]
+        add             r6,  r3,  r6,  lsl #1
+        read_rand       r5,  11,  1
+        vld1.16         {d1[1]}, [r6]
+        read_rand       r6,  11,  0
+        add             r5,  r3,  r5,  lsl #1
+        add             r6,  r3,  r6,  lsl #1
+        vld1.16         {d1[2]}, [r5]
+        vld1.16         {d1[3]}, [r6]
+        pop             {r5-r6,pc}
+endfunc
+
+function get_grain_2_neon
+        push            {r11,lr}
+        increment_seed  2
+        read_rand       r11, 11,  1
+        read_rand       r12, 11,  0
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d0[0]}, [r11]
+        vld1.16         {d0[1]}, [r12]
+        vrshl.s16       d0,  d0,  d30
+        pop             {r11,pc}
+endfunc
+
+.macro get_grain_2 dst
+        bl              get_grain_2_neon
+.ifnc \dst, d0
+        vmov            \dst, d0
+.endif
+.endm
+
+function get_grain_4_neon
+        push            {r11,lr}
+        increment_seed  4
+        read_rand       r11, 11,  3
+        read_rand       r12, 11,  2
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d0[0]}, [r11]
+        read_rand       r11, 11,  1
+        vld1.16         {d0[1]}, [r12]
+        read_rand       r12, 11,  0
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d0[2]}, [r11]
+        vld1.16         {d0[3]}, [r12]
+        vrshl.s16       d0,  d0,  d30
+        pop             {r11,pc}
+endfunc
+
+.macro get_grain_4 dst
+        bl              get_grain_4_neon
+.ifnc \dst, d0
+        vmov            \dst, d0
+.endif
+.endm
+
+// r1 holds the number of entries to produce
+// r6, r8 and r10 hold the previous output entries
+// q0 holds the vector of produced entries
+// q1 holds the input vector of sums from above
+.macro output_lag n
+function output_lag\n\()_neon
+        push            {r0, lr}
+.if \n == 1
+        mvn             lr,  r5                   // grain_min = ~grain_max
+.else
+        mov             r0,  #1
+        mov             lr,  #1
+        sub             r7,  r7,  #1
+        sub             r9,  r9,  #1
+        lsl             r0,  r0,  r7
+        lsl             lr,  lr,  r9
+        add             r7,  r7,  #1
+        add             r9,  r9,  #1
+.endif
+1:
+        read_shift_rand r12, 11
+        vmov.32         r11, d2[0]
+        lsl             r12, r12, #1
+        vext.8          q0,  q0,  q0,  #2
+        ldrsh           r12, [r3, r12]
+.if \n == 1
+        mla             r11, r6,  r4,  r11        // sum (above) + *coeff * prev output
+        add             r6,  r11, r8              // 1 << (ar_coeff_shift - 1)
+        add             r12, r12, r10
+        asr             r6,  r6,  r7              // >> ar_coeff_shift
+        asr             r12, r12, r9              // >> (4 - bitdepth_min_8 + grain_scale_shift)
+        add             r6,  r6,  r12
+        cmp             r6,  r5
+.elseif \n == 2
+        mla             r11, r8,  r4,  r11        // sum (above) + *coeff * prev output 1
+        mla             r11, r6,  r10, r11        // += *coeff * prev output 2
+        mov             r8,  r6
+        add             r6,  r11, r0              // 1 << (ar_coeff_shift - 1)
+        add             r12, r12, lr              // 1 << (4 - bitdepth_min_8 + grain_scale_shift - 1)
+        asr             r6,  r6,  r7              // >> ar_coeff_shift
+        asr             r12, r12, r9              // >> (4 - bitdepth_min_8 + grain_scale_shift)
+        add             r6,  r6,  r12
+        push            {lr}
+        cmp             r6,  r5
+        mvn             lr,  r5                   // grain_min = ~grain_max
+.else
+        push            {r1-r3}
+        sbfx            r1,  r4,  #0,  #8
+        sbfx            r2,  r4,  #8,  #8
+        sbfx            r3,  r4,  #16, #8
+        mla             r11, r10, r1,  r11        // sum (above) + *coeff * prev output 1
+        mla             r11, r8,  r2,  r11        // sum (above) + *coeff * prev output 2
+        mla             r11, r6,  r3,  r11        // += *coeff * prev output 3
+        pop             {r1-r3}
+        mov             r10, r8
+        mov             r8,  r6
+
+        add             r6,  r11, r0              // 1 << (ar_coeff_shift - 1)
+        add             r12, r12, lr              // 1 << (4 - bitdepth_min_8 + grain_scale_shift - 1)
+        asr             r6,  r6,  r7              // >> ar_coeff_shift
+        asr             r12, r12, r9              // >> (4 - bitdepth_min_8 + grain_scale_shift)
+        add             r6,  r6,  r12
+        push            {lr}
+        cmp             r6,  r5
+        mvn             lr,  r5                   // grain_min = ~grain_max
+.endif
+        it              gt
+        movgt           r6,  r5
+        cmp             r6,  lr
+        it              lt
+        movlt           r6,  lr
+.if \n >= 2
+        pop             {lr}
+.endif
+        subs            r1,  r1,  #1
+        vext.8          q1,  q1,  q1,  #4
+        vmov.16         d1[3], r6
+        bgt             1b
+        pop             {r0, pc}
+endfunc
+.endm
+
+output_lag 1
+output_lag 2
+output_lag 3
+
+
+function sum_lag1_above_neon
+        sub             r12, r0,  #1*GRAIN_WIDTH*2 - 16
+        vld1.16         {q10}, [r12] // load top right
+
+        vext.8          q0,  q8,  q9,  #14 // top left, top mid
+        vext.8          q1,  q9,  q10, #2  // top left, top mid
+
+        vmull.s16       q2,  d18, d28
+        vmlal.s16       q2,  d0,  d27
+        vmlal.s16       q2,  d2,  d29
+        vmull.s16       q3,  d19, d28
+        vmlal.s16       q3,  d1,  d27
+        vmlal.s16       q3,  d3,  d29
+
+        vmov            q8,  q9
+        vmov            q9,  q10
+
+        bx              lr
+endfunc
+
+.macro sum_lag_n_body lag, type, uv_layout, edge, elems, uv_coeff
+.ifc \lag\()_\edge, lag3_left
+        bl              sum_lag3_left_above_neon
+.else
+        bl              sum_\lag\()_above_neon
+.endif
+.ifc \type, uv_420
+        vpush           {q6-q7}
+        add             r12, r11, #GRAIN_WIDTH*2
+        vld1.16         {q0, q1}, [r11]!
+        vld1.16         {q6, q7}, [r12]!
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vpadd.i16       d12, d12, d13
+        vpadd.i16       d13, d14, d15
+        vadd.i16        q0,  q0,  q6
+        vpop            {q6-q7}
+        vrshr.s16       q0,  q0,  #2
+.endif
+.ifc \type, uv_422
+        vld1.16         {q0, q1}, [r11]!
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vrshr.s16       q0,  q0,  #1
+.endif
+.ifc \type, uv_444
+        vld1.16         {q0}, [r11]!
+.endif
+.if \uv_layout
+.ifnb \uv_coeff
+        vdup.8          d13, \uv_coeff
+        vmovl.s8        q6,  d13
+.endif
+        vmlal.s16       q2,  d0,  d13
+        vmlal.s16       q3,  d1,  d13
+.endif
+.if \uv_layout && \elems == 8
+        b               sum_\lag\()_y_\edge\()_start
+.elseif \uv_layout == 444 && \elems == 7
+        b               sum_\lag\()_y_\edge\()_start
+.elseif \uv_layout == 422 && \elems == 1
+        b               sum_\lag\()_uv_420_\edge\()_start
+.else
+sum_\lag\()_\type\()_\edge\()_start:
+        push            {r11}
+.if \elems > 4
+.ifc \edge, left
+        increment_seed  4
+        read_rand       r11, 11,  3
+        read_rand       r12, 11,  2
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d1[1]}, [r11]
+        read_rand       r11, 11,  1
+        vld1.16         {d1[2]}, [r12]
+        add             r11, r3,  r11, lsl #1
+        vld1.16         {d1[3]}, [r11]
+        lsl             r2,  r2,  #1             // shift back the state as if we'd done increment_seed with shift=0
+        vrshl.s16       d1,  d1,  d30
+        vext.8          q2,  q2,  q2,  #12
+.ifc \lag, lag3
+        vmov.s16        r10, d1[1]
+.endif
+.ifnc \lag, lag1
+        vmov.s16        r8,  d1[2]
+.endif
+        vmov.s16        r6,  d1[3]
+
+        vmov            q1,  q2
+        mov             r1,  #1
+        bl              output_\lag\()_neon
+.else
+        increment_seed  4, shift=0
+        vmov            q1,  q2
+        mov             r1,  #4
+        bl              output_\lag\()_neon
+.endif
+
+        increment_seed  4, shift=0
+        vmov            q1,  q3
+.ifc \edge, right
+        mov             r1,  #3
+        bl              output_\lag\()_neon
+        read_shift_rand r12, 11
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d2[0]}, [r12]
+        vrshl.s16       d2,  d2,  d30
+        vext.8          q0,  q0,  q1,  #2
+.else
+        mov             r1,  #4
+        bl              output_\lag\()_neon
+.endif
+.else
+        // elems == 1
+        increment_seed  4, shift=0
+        vmov            q1,  q2
+        mov             r1,  #1
+        bl              output_\lag\()_neon
+        lsr             r2,  r2,  #3
+
+        read_rand       r11, 11,  2
+        read_rand       r12, 11,  1
+        add             r11, r3,  r11, lsl #1
+        add             r12, r3,  r12, lsl #1
+        vld1.16         {d2[0]}, [r11]
+        read_rand       r11, 11,  0
+        vld1.16         {d2[1]}, [r12]
+        add             r11, r3,  r11, lsl #1
+        vld1.16         {d2[2]}, [r11]
+        vrshl.s16       d2,  d2,  d30
+        vext.8          q0,  q0,  q1,  #14
+.endif
+        vst1.16         {q0}, [r0]!
+        pop             {r11}
+        pop             {r1, pc}
+.endif
+.endm
+
+.macro sum_lag1_func type, uv_layout, edge, elems=8
+function sum_\type\()_lag1_\edge\()_neon
+        push            {r1, lr}
+.ifc \edge, left
+        sub             r12, r0,  #1*GRAIN_WIDTH*2
+        vld1.8          {q9},  [r12] // load the previous block right above
+.endif
+        sum_lag_n_body  lag1, \type, \uv_layout, \edge, \elems
+endfunc
+.endm
+
+sum_lag1_func y,      0,   left
+sum_lag1_func y,      0,   mid
+sum_lag1_func y,      0,   right, 7
+sum_lag1_func uv_444, 444, left
+sum_lag1_func uv_444, 444, mid
+sum_lag1_func uv_444, 444, right, 7
+sum_lag1_func uv_422, 422, left
+sum_lag1_func uv_422, 422, mid
+sum_lag1_func uv_422, 422, right, 1
+sum_lag1_func uv_420, 420, left
+sum_lag1_func uv_420, 420, mid
+sum_lag1_func uv_420, 420, right, 1
+
+
+function sum_lag2_above_neon
+        push            {lr}
+        sub             r12, r0,  #2*GRAIN_WIDTH*2 - 16
+        sub             lr,  r0,  #1*GRAIN_WIDTH*2 - 16
+        vld1.16         {q10}, [r12] // load top right
+        vld1.16         {q13}, [lr]
+
+        vdup.8          d10, d28[0]
+        vext.8          q0,  q8,  q9,  #12 // top left, top mid
+        vdup.8          d12, d28[1]
+        vext.8          q1,  q8,  q9,  #14
+        vdup.8          d14, d28[3]
+        vext.8          q4,  q9,  q10, #2  // top mid, top right
+        vmovl.s8        q5,  d10
+        vmovl.s8        q6,  d12
+        vmovl.s8        q7,  d14
+
+        vmull.s16       q2,  d0,  d10
+        vmlal.s16       q2,  d2,  d12
+        vmlal.s16       q2,  d8,  d14
+        vmull.s16       q3,  d1,  d10
+        vmlal.s16       q3,  d3,  d12
+        vmlal.s16       q3,  d9,  d14
+
+        vdup.8          d10, d28[4]
+        vext.8          q0,  q9,  q10, #4  // top mid, top right
+        vdup.8          d12, d28[5]
+        vext.8          q1,  q11, q12, #12 // top left, top mid
+        vdup.8          d14, d28[6]
+        vext.8          q4,  q11, q12, #14
+        vmovl.s8        q5,  d10
+        vmovl.s8        q6,  d12
+        vmovl.s8        q7,  d14
+
+        vmlal.s16       q2,  d0,  d10
+        vmlal.s16       q2,  d2,  d12
+        vmlal.s16       q2,  d8,  d14
+        vmlal.s16       q3,  d1,  d10
+        vmlal.s16       q3,  d3,  d12
+        vmlal.s16       q3,  d9,  d14
+
+        vdup.8          d10, d29[0]
+        vext.8          q0,  q12, q13, #2  // top mid, top right
+        vdup.8          d12, d29[1]
+        vext.8          q1,  q12, q13, #4
+
+        vdup.8          d14, d28[2]
+        vdup.8          d8,  d28[7]
+
+        vmovl.s8        q5,  d10
+        vmovl.s8        q6,  d12
+        vmovl.s8        q7,  d14
+        vmovl.s8        q4,  d8
+
+        vmlal.s16       q2,  d0,  d10
+        vmlal.s16       q2,  d2,  d12
+        vmlal.s16       q2,  d18, d14
+        vmlal.s16       q2,  d24, d8
+        vmlal.s16       q3,  d1,  d10
+        vmlal.s16       q3,  d3,  d12
+        vmlal.s16       q3,  d19, d14
+        vmlal.s16       q3,  d25, d8
+
+        vmov            q8,  q9
+        vmov            q9,  q10
+
+        vmov            q11, q12
+        vmov            q12, q13
+
+        pop             {pc}
+endfunc
+
+.macro sum_lag2_func type, uv_layout, edge, elems=8
+function sum_\type\()_lag2_\edge\()_neon
+        push            {r1, lr}
+.ifc \edge, left
+        sub             r12, r0,  #2*GRAIN_WIDTH*2
+        sub             lr,  r0,  #1*GRAIN_WIDTH*2
+        vld1.16         {q9},  [r12] // load the previous block right above
+        vld1.16         {q12}, [lr]
+.endif
+        sum_lag_n_body  lag2, \type, \uv_layout, \edge, \elems, uv_coeff=d29[4]
+endfunc
+.endm
+
+sum_lag2_func y,      0,   left
+sum_lag2_func y,      0,   mid
+sum_lag2_func y,      0,   right, 7
+sum_lag2_func uv_444, 444, left
+sum_lag2_func uv_444, 444, mid
+sum_lag2_func uv_444, 444, right, 7
+sum_lag2_func uv_422, 422, left
+sum_lag2_func uv_422, 422, mid
+sum_lag2_func uv_422, 422, right, 1
+sum_lag2_func uv_420, 420, left
+sum_lag2_func uv_420, 420, mid
+sum_lag2_func uv_420, 420, right, 1
+
+
+function sum_lag3_left_above_neon
+        // A separate codepath for the left edge, to avoid reading outside
+        // of the edge of the buffer.
+        sub             r12, r0,  #3*GRAIN_WIDTH*2
+        vld1.8          {q11, q12}, [r12]
+        vext.8          q12, q11, q12, #10
+        vext.8          q11, q11, q11, #10
+        b               sum_lag3_above_start
+endfunc
+
+function sum_lag3_above_neon
+        movw            r12, #(3*GRAIN_WIDTH + 3)*2
+        sub             r12, r0,  r12
+        vld1.8          {q11, q12}, [r12]
+
+sum_lag3_above_start:
+        vdup.8          d12, d26[0]
+        vext.8          q1,  q11, q12, #2
+        vdup.8          d14, d26[1]
+        vext.8          q4,  q11, q12, #4
+        vdup.8          d16, d26[2]
+        vext.8          q5,  q11, q12, #6
+        vdup.8          d18, d26[3]
+        vmovl.s8        q6,  d12
+        vmovl.s8        q7,  d14
+        vmovl.s8        q8,  d16
+        vmovl.s8        q9,  d18
+
+        movw            r12, #(2*GRAIN_WIDTH + 3)*2
+        sub             r12, r0,  r12
+
+        vmull.s16       q2,  d22, d12
+        vmlal.s16       q2,  d2,  d14
+        vmlal.s16       q2,  d8,  d16
+        vmlal.s16       q2,  d10, d18
+        vmull.s16       q3,  d23, d12
+        vmlal.s16       q3,  d3,  d14
+        vmlal.s16       q3,  d9,  d16
+        vmlal.s16       q3,  d11, d18
+
+        vdup.8          d12, d26[4]
+        vext.8          q0,  q11, q12, #8
+        vdup.8          d14, d26[5]
+        vext.8          q1,  q11, q12, #10
+        vdup.8          d16, d26[6]
+        vext.8          q4,  q11, q12, #12
+        vld1.8          {q11, q12}, [r12]
+        vdup.8          d18, d26[7]
+        vmovl.s8        q6,  d12
+        vmovl.s8        q7,  d14
+        vmovl.s8        q8,  d16
+        vmovl.s8        q9,  d18
+
+        vmlal.s16       q2,  d0,  d12
+        vmlal.s16       q2,  d2,  d14
+        vmlal.s16       q2,  d8,  d16
+        vmlal.s16       q2,  d22, d18
+        vmlal.s16       q3,  d1,  d12
+        vmlal.s16       q3,  d3,  d14
+        vmlal.s16       q3,  d9,  d16
+        vmlal.s16       q3,  d23, d18
+
+        vdup.8          d12, d27[0]
+        vext.8          q0,  q11, q12, #2
+        vdup.8          d14, d27[1]
+        vext.8          q1,  q11, q12, #4
+        vdup.8          d16, d27[2]
+        vext.8          q4,  q11, q12, #6
+        vdup.8          d18, d27[3]
+        vext.8          q5,  q11, q12, #8
+        vmovl.s8        q6,  d12
+        vmovl.s8        q7,  d14
+        vmovl.s8        q8,  d16
+        vmovl.s8        q9,  d18
+
+        sub             r12, r0,  #(1*GRAIN_WIDTH + 3)*2
+
+        vmlal.s16       q2,  d0,  d12
+        vmlal.s16       q2,  d2,  d14
+        vmlal.s16       q2,  d8,  d16
+        vmlal.s16       q2,  d10, d18
+        vmlal.s16       q3,  d1,  d12
+        vmlal.s16       q3,  d3,  d14
+        vmlal.s16       q3,  d9,  d16
+        vmlal.s16       q3,  d11, d18
+
+        vdup.8          d12, d27[4]
+        vext.8          q0,  q11, q12, #10
+        vdup.8          d14, d27[5]
+        vext.8          q1,  q11, q12, #12
+        vld1.8          {q11, q12}, [r12]
+        vdup.8          d16, d27[6]
+        vdup.8          d18, d27[7]
+        vmovl.s8        q6,  d12
+        vmovl.s8        q7,  d14
+        vext.8          q5,  q11, q12, #2
+        vmovl.s8        q8,  d16
+        vmovl.s8        q9,  d18
+
+        vmlal.s16       q2,  d0,  d12
+        vmlal.s16       q2,  d2,  d14
+        vmlal.s16       q2,  d22, d16
+        vmlal.s16       q2,  d10, d18
+        vmlal.s16       q3,  d1,  d12
+        vmlal.s16       q3,  d3,  d14
+        vmlal.s16       q3,  d23, d16
+        vmlal.s16       q3,  d11, d18
+
+        vdup.8          d12, d28[0]
+        vext.8          q0,  q11, q12, #4
+        vdup.8          d14, d28[1]
+        vext.8          q1,  q11, q12, #6
+        vdup.8          d16, d28[2]
+        vext.8          q4,  q11, q12, #8
+        vdup.8          d18, d28[3]
+        vext.8          q5,  q11, q12, #10
+        vmovl.s8        q6,  d12
+        vmovl.s8        q7,  d14
+        vmovl.s8        q8,  d16
+        vmovl.s8        q9,  d18
+
+        vmlal.s16       q2,  d0,  d12
+        vmlal.s16       q2,  d2,  d14
+        vmlal.s16       q2,  d8,  d16
+        vmlal.s16       q2,  d10, d18
+        vmlal.s16       q3,  d1,  d12
+        vmlal.s16       q3,  d3,  d14
+        vmlal.s16       q3,  d9,  d16
+        vmlal.s16       q3,  d11, d18
+
+        vdup.8          d12, d28[4]
+        vext.8          q0,  q11, q12, #12
+        vmovl.s8        q6,  d12
+
+        vmlal.s16       q2,  d0,  d12
+        vmlal.s16       q3,  d1,  d12
+
+        bx              lr
+endfunc
+
+.macro sum_lag3_func type, uv_layout, edge, elems=8
+function sum_\type\()_lag3_\edge\()_neon
+        push            {r1, lr}
+        sum_lag_n_body  lag3, \type, \uv_layout, \edge, \elems, uv_coeff=d29[0]
+endfunc
+.endm
+
+sum_lag3_func y,      0,   left
+sum_lag3_func y,      0,   mid
+sum_lag3_func y,      0,   right, 7
+sum_lag3_func uv_444, 444, left
+sum_lag3_func uv_444, 444, mid
+sum_lag3_func uv_444, 444, right, 7
+sum_lag3_func uv_422, 422, left
+sum_lag3_func uv_422, 422, mid
+sum_lag3_func uv_422, 422, right, 1
+sum_lag3_func uv_420, 420, left
+sum_lag3_func uv_420, 420, mid
+sum_lag3_func uv_420, 420, right, 1
+
+function generate_grain_rows_neon
+        push            {r10-r11,lr}
+1:
+        mov             r10, #80
+2:
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        subs            r10, r10, #8
+        vst1.16         {q0}, [r0]!
+        bgt             2b
+        get_grain_2     d0
+        subs            r1,  r1,  #1
+        vst1.32         {d0[0]}, [r0]!
+        bgt             1b
+        pop             {r10-r11,pc}
+endfunc
+
+function generate_grain_rows_44_neon
+        push            {r10-r11,lr}
+1:
+        mov             r10, #40
+2:
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+        subs            r10, r10, #8
+        vst1.16         {q0}, [r0]!
+        bgt             2b
+        get_grain_4     d0
+        subs            r1,  r1,  #1
+        vst1.16         {d0}, [r0]
+        add             r0,  r0,  #GRAIN_WIDTH*2-80
+        bgt             1b
+        pop             {r10-r11,pc}
+endfunc
+
+function gen_grain_uv_444_lag0_neon
+        vld1.16         {q3}, [r11]!
+gen_grain_uv_lag0_8_start:
+        push            {r11,lr}
+        bl              get_gaussian_neon
+        vrshl.s16       q0,  q0,  q15
+gen_grain_uv_lag0_8_add:
+        vand            q3,  q3,  q1
+        vmull.s16       q2,  d6,  d22
+        vmull.s16       q3,  d7,  d22
+        vrshl.s32       q2,  q2,  q12
+        vrshl.s32       q3,  q3,  q12
+        vqmovn.s32      d4,  q2
+        vqmovn.s32      d5,  q3
+        vqadd.s16       q2,  q2,  q0
+        vmin.s16        q2,  q2,  q9
+        vmax.s16        q2,  q2,  q10
+        vst1.16         {q2}, [r0]!
+        pop             {r11,pc}
+endfunc
+
+function gen_grain_uv_420_lag0_8_neon
+        add             r12, r11, #GRAIN_WIDTH*2
+        vld1.16         {q2,q3}, [r11]!
+        vld1.16         {q4,q5}, [r12]
+        vpadd.i16       d4,  d4,  d5
+        vpadd.i16       d5,  d6,  d7
+        vpadd.i16       d8,  d8,  d9
+        vpadd.i16       d9,  d10, d11
+        vadd.i16        q2,  q2,  q4
+        vrshr.s16       q3,  q2,  #2
+        b               gen_grain_uv_lag0_8_start
+endfunc
+
+function gen_grain_uv_422_lag0_8_neon
+        vld1.16         {q2,q3}, [r11]!
+        vpadd.i16       d4,  d4,  d5
+        vpadd.i16       d5,  d6,  d7
+        vrshr.s16       q3,  q2,  #1
+        b               gen_grain_uv_lag0_8_start
+endfunc
+
+function gen_grain_uv_420_lag0_4_neon
+        add             r12, r11, #GRAIN_WIDTH*2
+        vld1.16         {q2}, [r11]
+        vld1.16         {q0}, [r12]
+        add             r11, r11, #32
+        vpadd.i16       d4,  d4,  d5
+        vpadd.i16       d0,  d0,  d1
+        vadd.i16        d4,  d4,  d0
+        vrshr.s16       d6,  d4,  #2
+        push            {r11,lr}
+        get_grain_4     d0
+        b               gen_grain_uv_lag0_8_add
+endfunc
+
+function gen_grain_uv_422_lag0_4_neon
+        vld1.16         {q2}, [r11]
+        add             r11, r11, #32
+        vpadd.i16       d4,  d4,  d5
+        vrshr.s16       d6,  d4,  #1
+        push            {r11,lr}
+        get_grain_4     d0
+        b               gen_grain_uv_lag0_8_add
+endfunc
+
+.macro gen_grain_82 type
+function generate_grain_\type\()_16bpc_neon, export=1
+        push            {r4-r11,lr}
+
+.ifc \type, uv_444
+        ldr             r4,  [sp, #36]
+        mov             r12, r3
+        mov             lr,  #28
+        add             r11, r1,  #3*GRAIN_WIDTH*2
+        mov             r1,  r2
+        mul             r12, r12, lr
+        clz             lr,  r4
+.else
+        clz             lr,  r2
+.endif
+        movrel          r3,  X(gaussian_sequence)
+        sub             lr,  lr,  #24 // -bitdepth_min_8
+        ldr             r2,  [r1, #FGD_SEED]
+        ldr             r9,  [r1, #FGD_GRAIN_SCALE_SHIFT]
+.ifc \type, y
+        add             r4,  r1,  #FGD_AR_COEFFS_Y
+.else
+        add             r4,  r1,  #FGD_AR_COEFFS_UV
+.endif
+        add             r9,  r9,  lr // grain_scale_shift - bitdepth_min_8
+        adr             r5,  L(gen_grain_\type\()_tbl)
+        ldr             r6,  [r1, #FGD_AR_COEFF_LAG]
+        add             r9,  r9,  #4
+        ldr             r6,  [r5, r6, lsl #2]
+        vdup.16         q15, r9    // 4 - bitdepth_min_8 + data->grain_scale_shift
+        add             r5,  r5,  r6
+        vneg.s16        q15, q15
+
+.ifc \type, uv_444
+        push            {lr}
+        cmp             r12, #0
+        movw            r10, #0x49d8
+        movw            lr,  #0xb524
+        // Intentionally using a separate register instead of moveq with an
+        // immediate constant, to avoid armv8 deprecated it instruction forms.
+        it              eq
+        moveq           r10, lr
+        add             r4,  r4,  r12       // Add offset to ar_coeffs_uv[1]
+        eor             r2,  r2,  r10
+        pop             {lr}
+.endif
+
+        ldr             r7,  [r1, #FGD_AR_COEFF_SHIFT]
+        neg             lr,  lr             // bitdepth_min_8
+        mov             r8,  #1
+        mov             r10, #1
+        lsl             r8,  r8,  r7        // 1 << ar_coeff_shift
+        lsl             r10, r10, r9        // 1 << (4 + data->grain_scale_shift)
+        lsr             r8,  r8,  #1        // 1 << (ar_coeff_shift - 1)
+        lsr             r10, r10, #1        // 1 << (4 + data->grain_scale_shift - 1)
+
+        bx              r5
+
+        .align 2
+L(gen_grain_\type\()_tbl):
+        .word L(generate_grain_\type\()_lag0) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag1) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag2) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag3) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+
+L(generate_grain_\type\()_lag0):
+.ifc \type, y
+        mov             r1,  #GRAIN_HEIGHT
+        bl              generate_grain_rows_neon
+.else
+        mov             r5,  #128
+        lsl             r5,  r5,  lr        //  128 << bitdepth_min_8
+        sub             r5,  r5,  #1        // (128 << bitdepth_min_8) - 1
+        mvn             r6,  r5             // grain_min = ~grain_max
+
+        mov             r1,  #3
+        bl              generate_grain_rows_neon
+        mov             r1,  #GRAIN_HEIGHT-3
+
+        vdup.32         q12, r7
+        vld1.8          {d22[]}, [r4]       // ar_coeffs_uv[0]
+        vmov.i8         q0,  #0
+        vmov.i8         q1,  #255
+        vdup.16         q9,  r5
+        vdup.16         q10, r6
+        vext.8          q13, q0,  q1,  #10
+        vext.8          q14, q1,  q0,  #2
+        vneg.s32        q12, q12
+        vmovl.s8        q11, d22
+
+1:
+        vmov            q1,  q13
+        bl              gen_grain_uv_444_lag0_neon // 8
+        vmov.i8         q1,  #255
+        bl              gen_grain_uv_444_lag0_neon // 16
+        bl              gen_grain_uv_444_lag0_neon // 24
+        bl              gen_grain_uv_444_lag0_neon // 32
+        bl              gen_grain_uv_444_lag0_neon // 40
+        bl              gen_grain_uv_444_lag0_neon // 48
+        bl              gen_grain_uv_444_lag0_neon // 56
+        bl              gen_grain_uv_444_lag0_neon // 64
+        bl              gen_grain_uv_444_lag0_neon // 72
+        vmov            q1,  q14
+        bl              gen_grain_uv_444_lag0_neon // 80
+        get_grain_2     d16
+        subs            r1,  r1,  #1
+        add             r11, r11, #4
+        vst1.32         {d16[0]}, [r0]!
+        bgt             1b
+.endif
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag1):
+        vpush           {q4-q7}
+        mov             r5,  #128
+        lsl             r5,  r5,  lr        //  128 << bitdepth_min_8
+        sub             r5,  r5,  #1        // (128 << bitdepth_min_8) - 1
+        vld1.8          {d27[]}, [r4]!      // ar_coeffs_y[0]
+        vld1.8          {d28[]}, [r4]!      // ar_coeffs_y[1]
+        vld1.8          {d29[]}, [r4]       // ar_coeffs_y[2]
+.ifc \type, y
+        ldrsb           r4,  [r4, #1]       // ar_coeffs_y[3]
+.else
+        add             r4,  r4,  #2
+.endif
+
+        mov             r1,  #3
+.ifc \type, uv_444
+        vld1.8          {d13[]}, [r4]       // ar_coeffs_uv[4]
+        ldrsb           r4,  [r4, #-1]      // ar_coeffs_uv[3]
+.endif
+        bl              generate_grain_rows_neon
+        vmovl.s8        q13, d27
+        vmovl.s8        q12, d29
+        vmovl.s8        q14, d28
+        vmov            d29, d24
+.ifc \type, uv_444
+        vmovl.s8        q6,  d13
+.endif
+
+        mov             r1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag1_left_neon  // 8
+        bl              sum_\type\()_lag1_mid_neon   // 16
+        bl              sum_\type\()_lag1_mid_neon   // 24
+        bl              sum_\type\()_lag1_mid_neon   // 32
+        bl              sum_\type\()_lag1_mid_neon   // 40
+        bl              sum_\type\()_lag1_mid_neon   // 48
+        bl              sum_\type\()_lag1_mid_neon   // 56
+        bl              sum_\type\()_lag1_mid_neon   // 64
+        bl              sum_\type\()_lag1_mid_neon   // 72
+        bl              sum_\type\()_lag1_right_neon // 80
+        get_grain_2     d16
+        subs            r1,  r1,  #1
+.ifc \type, uv_444
+        add             r11, r11, #4
+.endif
+        vst1.32         {d16[0]}, [r0]!
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag2):
+        vpush           {q4-q7}
+        mov             r5,  #128
+        lsl             r5,  r5,  lr        //  128 << bitdepth_min_8
+        sub             r5,  r5,  #1        // (128 << bitdepth_min_8) - 1
+        vld1.8          {d28,d29}, [r4]     // ar_coeffs_y[0-11], ar_coeffs_uv[0-12]
+
+        vmov.s8         r4,  d29[2]
+        vmov.s8         r10, d29[3]
+
+        mov             r1,  #3
+        bl              generate_grain_rows_neon
+
+        mov             r1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag2_left_neon  // 8
+        bl              sum_\type\()_lag2_mid_neon   // 16
+        bl              sum_\type\()_lag2_mid_neon   // 24
+        bl              sum_\type\()_lag2_mid_neon   // 32
+        bl              sum_\type\()_lag2_mid_neon   // 40
+        bl              sum_\type\()_lag2_mid_neon   // 48
+        bl              sum_\type\()_lag2_mid_neon   // 56
+        bl              sum_\type\()_lag2_mid_neon   // 64
+        bl              sum_\type\()_lag2_mid_neon   // 72
+        bl              sum_\type\()_lag2_right_neon // 80
+        get_grain_2     d16
+        subs            r1,  r1,  #1
+.ifc \type, uv_444
+        add             r11, r11, #4
+.endif
+        vst1.32         {d16[0]}, [r0]!
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag3):
+        vpush           {q4-q7}
+        mov             r5,  #128
+        lsl             r5,  r5,  lr        //  128 << bitdepth_min_8
+        sub             r5,  r5,  #1        // (128 << bitdepth_min_8) - 1
+        vld1.8          {q13, q14}, [r4]    // ar_coeffs_y[0-23], ar_coeffs_uv[0-24]
+
+        vmov.u8         r4,  d28[5]
+        vmov.u8         r10, d28[6]
+        vmov.u8         r12, d28[7]
+
+        orr             r4,  r4,  r10, lsl #8
+        orr             r4,  r4,  r12, lsl #16
+
+        mov             r1,  #3
+        vpush           {d26}
+        bl              generate_grain_rows_neon
+        vpop            {d26}
+
+        mov             r1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag3_left_neon  // 8
+        bl              sum_\type\()_lag3_mid_neon   // 16
+        bl              sum_\type\()_lag3_mid_neon   // 24
+        bl              sum_\type\()_lag3_mid_neon   // 32
+        bl              sum_\type\()_lag3_mid_neon   // 40
+        bl              sum_\type\()_lag3_mid_neon   // 48
+        bl              sum_\type\()_lag3_mid_neon   // 56
+        bl              sum_\type\()_lag3_mid_neon   // 64
+        bl              sum_\type\()_lag3_mid_neon   // 72
+        bl              sum_\type\()_lag3_right_neon // 80
+        get_grain_2     d16
+        subs            r1,  r1,  #1
+.ifc \type, uv_444
+        add             r11, r11, #4
+.endif
+        vst1.32         {d16[0]}, [r0]!
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+gen_grain_82 y
+gen_grain_82 uv_444
+
+.macro set_height dst, type
+.ifc \type, uv_420
+        mov             \dst,  #SUB_GRAIN_HEIGHT-3
+.else
+        mov             \dst,  #GRAIN_HEIGHT-3
+.endif
+.endm
+
+.macro increment_y_ptr reg, type
+.ifc \type, uv_420
+        add             \reg, \reg, #2*GRAIN_WIDTH*2-(6*32)
+.else
+        sub             \reg, \reg, #6*32-GRAIN_WIDTH*2
+.endif
+.endm
+
+.macro gen_grain_44 type
+function generate_grain_\type\()_16bpc_neon, export=1
+        push            {r4-r11,lr}
+
+        ldr             r4,  [sp, #36]
+        mov             r12, r3
+        movw            r11, #(3*GRAIN_WIDTH-3)*2
+        mov             lr,  #28
+        add             r11, r1,  r11
+        mov             r1,  r2
+        mul             r12, r12, lr
+        clz             lr,  r4
+
+        movrel          r3,  X(gaussian_sequence)
+        sub             lr,  lr,  #24 // -bitdepth_min_8
+        ldr             r2,  [r1, #FGD_SEED]
+        ldr             r9,  [r1, #FGD_GRAIN_SCALE_SHIFT]
+        add             r4,  r1,  #FGD_AR_COEFFS_UV
+        add             r9,  r9,  lr // grain_scale_shift - bitdepth_min_8
+        adr             r5,  L(gen_grain_\type\()_tbl)
+        ldr             r6,  [r1, #FGD_AR_COEFF_LAG]
+        add             r9,  r9,  #4
+        ldr             r6,  [r5, r6, lsl #2]
+        vdup.16         q15, r9    // 4 - bitdepth_min_8 + data->grain_scale_shift
+        add             r5,  r5,  r6
+        vneg.s16        q15, q15
+
+        push            {lr}
+        cmp             r12, #0
+        movw            r10, #0x49d8
+        movw            lr,  #0xb524
+        // Intentionally using a separate register instead of moveq with an
+        // immediate constant, to avoid armv8 deprecated it instruction forms.
+        it              eq
+        moveq           r10, lr
+        add             r4,  r4,  r12       // Add offset to ar_coeffs_uv[1]
+        eor             r2,  r2,  r10
+        pop             {lr}
+
+        ldr             r7,  [r1, #FGD_AR_COEFF_SHIFT]
+        neg             lr,  lr
+        mov             r8,  #1
+        mov             r10, #1
+        lsl             r8,  r8,  r7        // 1 << ar_coeff_shift
+        lsl             r10, r10, r9        // 1 << (4 + data->grain_scale_shift)
+        lsr             r8,  r8,  #1        // 1 << (ar_coeff_shift - 1)
+        lsr             r10, r10, #1        // 1 << (4 + data->grain_scale_shift - 1)
+        bx              r5
+
+        .align 2
+L(gen_grain_\type\()_tbl):
+        .word L(generate_grain_\type\()_lag0) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag1) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag2) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+        .word L(generate_grain_\type\()_lag3) - L(gen_grain_\type\()_tbl) + CONFIG_THUMB
+
+L(generate_grain_\type\()_lag0):
+.ifc \type, uv_420
+        vpush           {q4-q5}
+.endif
+        mov             r5,  #128
+        lsl             r5,  r5,  lr        //  128 << bitdepth_min_8
+        sub             r5,  r5,  #1        // (128 << bitdepth_min_8) - 1
+        mvn             r6,  r5             // grain_min = ~grain_max
+
+        mov             r1,  #3
+        bl              generate_grain_rows_44_neon
+        set_height      r1,  \type
+
+        vdup.32         q12, r7
+        vld1.8          {d22[]}, [r4]       // ar_coeffs_uv[0]
+        vmov.i8         q0,  #0
+        vmov.i8         q1,  #255
+        vdup.16         q9,  r5
+        vdup.16         q10, r6
+        vext.8          q13, q0,  q1,  #10
+        vext.8          q14, q1,  q0,  #14
+        vneg.s32        q12, q12
+        vmovl.s8        q11, d22
+
+1:
+        vmov            q1,  q13
+        bl              gen_grain_\type\()_lag0_8_neon // 8
+        vmov.i8         q1,  #255
+        bl              gen_grain_\type\()_lag0_8_neon // 16
+        bl              gen_grain_\type\()_lag0_8_neon // 24
+        bl              gen_grain_\type\()_lag0_8_neon // 32
+        bl              gen_grain_\type\()_lag0_8_neon // 40
+        vmov            q1,  q14
+        bl              gen_grain_\type\()_lag0_4_neon // 44
+        subs            r1,  r1,  #1
+        increment_y_ptr r11, \type
+        add             r0,  r0,  #GRAIN_WIDTH*2-6*16
+        bgt             1b
+
+.ifc \type, uv_420
+        vpop            {q4-q5}
+.endif
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag1):
+        vpush           {q4-q7}
+        mov             r5,  #128
+        lsl             r5,  r5,  lr        //  128 << bitdepth_min_8
+        sub             r5,  r5,  #1        // (128 << bitdepth_min_8) - 1
+        vld1.8          {d27[]}, [r4]!      // ar_coeffs_uv[0]
+        vld1.8          {d28[]}, [r4]!      // ar_coeffs_uv[1]
+        vld1.8          {d29[]}, [r4]       // ar_coeffs_uv[2]
+        add             r4,  r4,  #2
+
+        mov             r1,  #3
+        vld1.8          {d13[]}, [r4]       // ar_coeffs_uv[4]
+        ldrsb           r4,  [r4, #-1]      // ar_coeffs_uv[3]
+        bl              generate_grain_rows_44_neon
+        vmovl.s8        q13, d27
+        vmovl.s8        q12, d29
+        vmovl.s8        q14, d28
+        vmov            d29, d24
+        vmovl.s8        q6,  d13
+
+        set_height      r1,  \type
+1:
+        bl              sum_\type\()_lag1_left_neon  // 8
+        bl              sum_\type\()_lag1_mid_neon   // 16
+        bl              sum_\type\()_lag1_mid_neon   // 24
+        bl              sum_\type\()_lag1_mid_neon   // 32
+        bl              sum_\type\()_lag1_mid_neon   // 40
+        bl              sum_\type\()_lag1_right_neon // 44
+        subs            r1,  r1,  #1
+        increment_y_ptr r11, \type
+        add             r0,  r0,  #GRAIN_WIDTH*2-6*16
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag2):
+        vpush           {q4-q7}
+        mov             r5,  #128
+        lsl             r5,  r5,  lr        //  128 << bitdepth_min_8
+        sub             r5,  r5,  #1        // (128 << bitdepth_min_8) - 1
+        vld1.8          {d28,d29}, [r4]     // ar_coeffs_uv[0-12]
+
+        vmov.s8         r4,  d29[2]
+        vmov.s8         r10, d29[3]
+
+        mov             r1,  #3
+        bl              generate_grain_rows_44_neon
+
+        set_height      r1,  \type
+1:
+        bl              sum_\type\()_lag2_left_neon  // 8
+        bl              sum_\type\()_lag2_mid_neon   // 16
+        bl              sum_\type\()_lag2_mid_neon   // 24
+        bl              sum_\type\()_lag2_mid_neon   // 32
+        bl              sum_\type\()_lag2_mid_neon   // 40
+        bl              sum_\type\()_lag2_right_neon // 44
+        subs            r1,  r1,  #1
+        increment_y_ptr r11, \type
+        add             r0,  r0,  #GRAIN_WIDTH*2-6*16
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(generate_grain_\type\()_lag3):
+        vpush           {q4-q7}
+        mov             r5,  #128
+        lsl             r5,  r5,  lr        //  128 << bitdepth_min_8
+        sub             r5,  r5,  #1        // (128 << bitdepth_min_8) - 1
+        vld1.8          {q13, q14}, [r4]    // ar_coeffs_y[0-23], ar_coeffs_uv[0-24]
+
+        vmov.u8         r4,  d28[5]
+        vmov.u8         r10, d28[6]
+        vmov.u8         r12, d28[7]
+
+        orr             r4,  r4,  r10, lsl #8
+        orr             r4,  r4,  r12, lsl #16
+
+        mov             r1,  #3
+        bl              generate_grain_rows_44_neon
+
+        set_height      r1,  \type
+1:
+        bl              sum_\type\()_lag3_left_neon  // 8
+        bl              sum_\type\()_lag3_mid_neon   // 16
+        bl              sum_\type\()_lag3_mid_neon   // 24
+        bl              sum_\type\()_lag3_mid_neon   // 32
+        bl              sum_\type\()_lag3_mid_neon   // 40
+        bl              sum_\type\()_lag3_right_neon // 44
+        subs            r1,  r1,  #1
+        increment_y_ptr r11, \type
+        add             r0,  r0,  #GRAIN_WIDTH*2-6*16
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+gen_grain_44 uv_420
+gen_grain_44 uv_422
+
+.macro gather_interleaved dst1, dst2, src1, src2, src3, src4, off
+        vmov.u16        r11, \src1[0+\off]
+        vmov.u16        r12, \src3[0+\off]
+        add             r11, r11, r3
+        vmov.u16        lr,  \src1[2+\off]
+        add             r12, r12, r3
+        vld1.8          {\dst1[0+\off]}, [r11]
+        vmov.u16        r11, \src3[2+\off]
+        add             lr,  lr,  r3
+        vld1.8          {\dst2[0+\off]}, [r12]
+        vmov.u16        r12, \src2[0+\off]
+        add             r11, r11, r3
+        vld1.8          {\dst1[2+\off]}, [lr]
+        vmov.u16        lr,  \src4[0+\off]
+        add             r12, r12, r3
+        vld1.8          {\dst2[2+\off]}, [r11]
+        vmov.u16        r11, \src2[2+\off]
+        add             lr,  lr,  r3
+        vld1.8          {\dst1[4+\off]}, [r12]
+        vmov.u16        r12, \src4[2+\off]
+        add             r11, r11, r3
+        vld1.8          {\dst2[4+\off]}, [lr]
+        add             r12, r12, r3
+        vld1.8          {\dst1[6+\off]}, [r11]
+        vld1.8          {\dst2[6+\off]}, [r12]
+.endm
+
+.macro gather dst1, dst2, dst3, dst4, src1, src2, src3, src4, src5, src6, src7, src8
+        gather_interleaved \dst1, \dst3, \src1, \src2, \src5, \src6, 0
+        gather_interleaved \dst1, \dst3, \src1, \src2, \src5, \src6, 1
+        gather_interleaved \dst2, \dst4, \src3, \src4, \src7, \src8, 0
+        gather_interleaved \dst2, \dst4, \src3, \src4, \src7, \src8, 1
+.endm
+
+function gather32_neon
+        push            {r11-r12,lr}
+        gather          d8,  d9,  d10, d11, d0,  d1,  d2,  d3,  d4,  d5,  d6,  d7
+        pop             {r11-r12,pc}
+endfunc
+
+function gather16_neon
+        push            {r11-r12,lr}
+        gather_interleaved d8,  d9,  d0,  d1,  d2,  d3,  0
+        gather_interleaved d8,  d9,  d0,  d1,  d2,  d3,  1
+        pop             {r11-r12,pc}
+endfunc
+
+const overlap_coeffs_0, align=4
+        .short 27, 17, 0,  0
+        .short 17, 27, 32, 32
+endconst
+
+const overlap_coeffs_1, align=4
+        .short 23, 0,  0,  0
+        .short 22, 32, 32, 32
+endconst
+
+.macro calc_offset offx, offy, src, sx, sy
+        and             \offy, \src,  #0xF     // randval & 0xF
+        lsr             \offx, \src,  #4       // randval >> 4
+.if \sy == 0
+        add             \offy, \offy, \offy    // 2 * (randval & 0xF)
+.endif
+.if \sx == 0
+        add             \offx, \offx, \offx    // 2 * (randval >> 4)
+.endif
+.endm
+
+.macro add_offset dst, offx, offy, src, stride
+        mla             \dst, \stride, \offy, \src // grain_lut += grain_stride * offy
+        add             \dst, \dst, \offx, lsl #1  // grain_lut += offx
+.endm
+
+// void dav1d_fgy_32x32_16bpc_neon(pixel *const dst, const pixel *const src,
+//                                 const ptrdiff_t stride,
+//                                 const uint8_t scaling[SCALING_SIZE],
+//                                 const int scaling_shift,
+//                                 const entry grain_lut[][GRAIN_WIDTH],
+//                                 const int offsets[][2],
+//                                 const int h, const ptrdiff_t clip,
+//                                 const ptrdiff_t type,
+//                                 const int bitdepth_max);
+function fgy_32x32_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]   // scaling_shift, grain_lut
+        ldrd            r6,  r7,  [sp, #108]   // offsets, h
+        ldr             r8,       [sp, #116]   // clip
+        mov             r9,  #GRAIN_WIDTH*2    // grain_lut stride
+        ldr             r10,      [sp, #124]   // bitdepth_max
+
+        eor             r4,  r4,  #15          // 15 - scaling_shift
+        vdup.16         q6,  r10               // bitdepth_max
+        clz             r10, r10
+        vdup.16         q13, r4                // 15 - scaling_shift
+        rsb             r10, r10, #24          // bitdepth_min_8
+        cmp             r8,  #0
+        vdup.16         q12, r10               // bitdepth_min_8
+
+        movrel_local    r12, overlap_coeffs_0
+
+        beq             1f
+        // clip
+        vmov.i16        q14, #16
+        vmov.i16        q15, #235
+        vshl.s16        q14, q14, q12
+        vshl.s16        q15, q15, q12
+        b               2f
+1:
+        // no clip
+        vmov.i16        q14, #0
+        vmov            q15, q6
+2:
+        vshr.u16        q6,  q6,  #1           // grain_max
+
+        vld1.16         {d24, d25}, [r12, :128] // overlap_coeffs
+
+        add             r5,  r5,  #18          // grain_lut += 9
+        add             r5,  r5,  r9,  lsl #3  // grain_lut += 8 * grain_stride
+        add             r5,  r5,  r9           // grain_lut += grain_stride
+
+        ldr             r10, [r6, #8]          // offsets[1][0]
+        calc_offset     r10, r4,  r10, 0,   0
+        add_offset      r4,  r10, r4,  r5,  r9
+        ldr             r10, [r6, #4]          // offsets[0][1]
+        calc_offset     r10, r11, r10, 0,   0
+        add_offset      r11, r10, r11, r5,  r9
+        ldr             r10, [r6, #12]         // offsets[1][1]
+        calc_offset     r10, r8,  r10, 0,   0
+        add_offset      r8,  r10, r8,  r5,  r9
+        ldr             r6,  [r6]              // offsets[0][0]
+        calc_offset     r6,  lr,  r6,  0,   0
+        add_offset      r5,  r6,  lr,  r5,  r9
+
+        add             r4,  r4,  #32*2        // grain_lut += FG_BLOCK_SIZE * bx
+        add             r6,  r11, r9,  lsl #5  // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+
+        ldr             r10, [sp, #120]        // type
+        adr             r11, L(fgy_loop_tbl)
+
+        tst             r10, #1
+        ldr             r10, [r11, r10, lsl #2]
+
+        add             r8,  r8,  r9,  lsl #5  // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             r8,  r8,  #32*2        // grain_lut += FG_BLOCK_SIZE * bx
+
+        add             r11, r11, r10
+
+        beq             1f
+        // y overlap
+        vdup.16         d14, d24[0]
+        vdup.16         d15, d24[1]
+        mov             r10, r7                // backup actual h
+        mov             r7,  #2
+1:
+        sub             r2,  r2,  #32          // src_stride   -= 32
+        sub             r9,  r9,  #32          // grain_stride -= 32
+        bx              r11
+endfunc
+
+function fgy_loop_neon
+L(fgy_loop_tbl):
+        .word L(loop_00) - L(fgy_loop_tbl) + CONFIG_THUMB
+        .word L(loop_01) - L(fgy_loop_tbl) + CONFIG_THUMB
+        .word L(loop_10) - L(fgy_loop_tbl) + CONFIG_THUMB
+        .word L(loop_11) - L(fgy_loop_tbl) + CONFIG_THUMB
+
+.macro fgy ox, oy
+L(loop_\ox\oy):
+1:
+.if \ox
+        vld1.16         {d0},       [r4],       r9 // grain_lut old
+.endif
+.if \oy
+        vld1.16         {q2,  q3},  [r6]!          // grain_lut top
+.endif
+.if \ox && \oy
+        vld1.16         {d2},       [r8],       r9 // grain_lut top old
+.endif
+.if \oy
+        vld1.16         {q4,  q5},  [r6],       r9 // grain_lut top
+.endif
+.if !\ox && !\oy
+        vld1.16         {q0,  q1},  [r1, :128]!    // src
+.endif
+        vld1.16         {q8,  q9},  [r5]!          // grain_lut
+.if !\ox && !\oy
+        vld1.16         {q2,  q3},  [r1, :128], r2 // src
+.endif
+.if !\oy
+        vmvn.i16        q5,  #0xf000               // 0x0fff
+.endif
+        vld1.16         {q10, q11}, [r5],       r9 // grain_lut
+
+.if \ox
+        add             r4,  r4,  #32
+        vmull.s16       q0,  d0,  d24
+        vmlal.s16       q0,  d16, d25
+.endif
+
+.if \oy
+.if \ox
+        add             r8,  r8,  #32
+        vmull.s16       q1,  d2,  d24
+        vmlal.s16       q1,  d4,  d25
+        vqrshrn.s32     d16, q0,  #5
+        vmvn            d0,  d12                   // grain_min
+        vqrshrn.s32     d4,  q1,  #5
+        vmin.s16        d16, d16, d12
+        vmin.s16        d4,  d4,  d12
+        vmax.s16        d16, d16, d0
+        vmax.s16        d4,  d4,  d0
+.endif
+
+        vmull.s16       q0,  d4,  d14
+        vmull.s16       q1,  d5,  d14
+        vmull.s16       q2,  d6,  d14
+        vmull.s16       q3,  d7,  d14
+        vmlal.s16       q0,  d16, d15
+        vmlal.s16       q1,  d17, d15
+        vmlal.s16       q2,  d18, d15
+        vmlal.s16       q3,  d19, d15
+        vmull.s16       q8,  d20, d15
+        vmull.s16       q9,  d21, d15
+        vmull.s16       q10, d22, d15
+        vmull.s16       q11, d23, d15
+        vmlal.s16       q8,  d8,  d14
+        vmlal.s16       q9,  d9,  d14
+        vmlal.s16       q10, d10, d14
+        vmlal.s16       q11, d11, d14
+        vmvn            q4,  q6                   // grain_min
+        vqrshrn.s32     d0,  q0,  #5
+        vqrshrn.s32     d1,  q1,  #5
+        vqrshrn.s32     d2,  q2,  #5
+        vqrshrn.s32     d3,  q3,  #5
+        vqrshrn.s32     d4,  q8,  #5
+        vqrshrn.s32     d5,  q9,  #5
+        vqrshrn.s32     d6,  q10, #5
+        vqrshrn.s32     d7,  q11, #5
+        vmin.s16        q8,  q0,  q6
+        vmin.s16        q9,  q1,  q6
+        vld1.16         {q0,  q1},  [r1, :128]!    // src
+        vmin.s16        q10, q2,  q6
+        vmin.s16        q11, q3,  q6
+        vmax.s16        q8,  q8,  q4
+        vmax.s16        q9,  q9,  q4
+        vld1.16         {q2,  q3},  [r1, :128], r2 // src
+        vmvn.i16        q5,  #0xf000               // 0x0fff
+        vmax.s16        q10, q10, q4
+        vmax.s16        q11, q11, q4
+.elseif \ox
+        vmvn            d4,  d12                   // grain_min
+        vqrshrn.s32     d16, q0,  #5
+        vld1.16         {q0,  q1},  [r1, :128]!    // src
+        vmin.s16        d16, d16, d12
+        vmax.s16        d16, d16, d4
+        vld1.16         {q2,  q3},  [r1, :128], r2 // src
+.endif
+
+        // Make sure that uninitialized pixels out of range past the right
+        // edge are in range; their actual values shouldn't matter.
+        vand            q0,  q0,  q5
+        vand            q1,  q1,  q5
+        vand            q2,  q2,  q5
+        vand            q3,  q3,  q5
+
+        bl              gather32_neon
+
+.if \ox || \oy
+        vpush           {q6-q7}
+.endif
+
+        vmovl.u8        q6,  d8        // scaling
+        vmovl.u8        q7,  d9
+        vmovl.u8        q4,  d10
+        vmovl.u8        q5,  d11
+
+        vshl.u16        q6,  q6,  q13  // scaling << (15 - scaling_shift)
+        vshl.u16        q7,  q7,  q13
+        vshl.u16        q4,  q4,  q13
+        vshl.u16        q5,  q5,  q13
+
+        vqrdmulh.s16    q8,  q8,  q6   // round2((scaling << (15 - scaling_shift) * grain, 15)
+        vqrdmulh.s16    q9,  q9,  q7
+        vqrdmulh.s16    q10, q10, q4
+        vqrdmulh.s16    q11, q11, q5
+
+.if \ox || \oy
+        vpop            {q6-q7}
+.endif
+
+        vqadd.s16       q0,  q0,  q8   // *src + noise
+        vqadd.s16       q1,  q1,  q9
+        vqadd.s16       q2,  q2,  q10
+        vqadd.s16       q3,  q3,  q11
+
+        vmax.s16        q0,  q0,  q14
+        vmax.s16        q1,  q1,  q14
+        vmax.s16        q2,  q2,  q14
+        vmax.s16        q3,  q3,  q14
+        vmin.s16        q0,  q0,  q15
+        vmin.s16        q1,  q1,  q15
+        vmin.s16        q2,  q2,  q15
+        vmin.s16        q3,  q3,  q15
+
+        vst1.16         {q0, q1}, [r0, :128]!    // dst
+        subs            r7,  r7,  #1
+.if \oy
+        vdup.16         d14, d25[0]
+        vdup.16         d15, d25[1]
+.endif
+        vst1.16         {q2, q3}, [r0, :128], r2 // dst
+        bgt             1b
+
+.if \oy
+        cmp             r10, #2
+        sub             r7,  r10, #2           // restore actual remaining h
+        bgt             L(loop_\ox\()0)
+.endif
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+.endm
+
+        fgy             0, 0
+        fgy             0, 1
+        fgy             1, 0
+        fgy             1, 1
+endfunc
+
+// void dav1d_fguv_32x32_420_16bpc_neon(pixel *const dst,
+//                                      const pixel *const src,
+//                                      const ptrdiff_t stride,
+//                                      const uint8_t scaling[SCALING_SIZE],
+//                                      const Dav1dFilmGrainData *const data,
+//                                      const entry grain_lut[][GRAIN_WIDTH],
+//                                      const pixel *const luma_row,
+//                                      const ptrdiff_t luma_stride,
+//                                      const int offsets[][2],
+//                                      const ptrdiff_t h, const ptrdiff_t uv,
+//                                      const ptrdiff_t is_id,
+//                                      const ptrdiff_t type,
+//                                      const int bitdepth_max);
+.macro fguv layout, sx, sy
+function fguv_32x32_\layout\()_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]   // data, grain_lut
+        ldrd            r10, r11, [sp, #124]   // uv, is_id
+        ldr             r6,       [sp, #136]   // bitdepth_max
+
+        clz             r7,  r6
+        rsb             r7,  r7,  #24          // bitdepth_min_8
+
+        // !csfl
+        add             r10, r4,  r10, lsl #2  // + 4*uv
+        add             r12, r10, #FGD_UV_LUMA_MULT
+        add             lr,  r10, #FGD_UV_MULT
+        ldrh            r10, [r10, #FGD_UV_OFFSET] // uv_offset
+        vld1.16         {d30[]},  [r12]        // uv_luma_mult
+        lsl             r10, r10, r7           // uv_offset << bitdepth_min_8
+        vld1.16         {d30[1]}, [lr]         // uv_mult
+
+        ldr             lr,  [r4, #FGD_SCALING_SHIFT]
+        ldr             r12, [r4, #FGD_CLIP_TO_RESTRICTED_RANGE]
+        eor             lr,  lr,  #15          // 15 - scaling_shift
+
+        vmov.16         d30[2], r10            // uv_offset << bitdepth_min_8
+
+        cmp             r12, #0
+        vdup.16         q13, lr                // 15 - scaling_shift
+
+        beq             1f
+        // clip
+        cmp             r11, #0
+        mov             r8,  #16
+        mov             r9,  #240
+        lsl             r8,  r8,  r7
+        lsl             r9,  r9,  r7
+        beq             2f
+        // is_id
+        mov             r9,  #235
+        lsl             r9,  r9,  r7
+        b               2f
+1:
+        // no clip
+        mov             r8,  #0
+        mov             r9,  r6                // bitdepth_max
+2:
+        vmov.16         d30[3], r6             // bitdepth_max
+        vdup.16         d31, r8                // clip_min
+
+        mov             r10, #GRAIN_WIDTH*2    // grain_lut stride
+
+.if \sy
+        mov             r6,  #23
+        mov             r7,  #22
+.else
+        mov             r6,  #27
+        mov             r7,  #17
+.endif
+        vmov.16         d31[1], r9             // clip_max
+
+        ldrd            r8,  r9,  [sp, #116]   // offsets, h
+
+        add             r5,  r5,  #(2*(3 + (2 >> \sx)*3)) // grain_lut += 9 or 6
+.if \sy
+        add             r5,  r5,  r10, lsl #2  // grain_lut += 4 * grain_stride
+        add             r5,  r5,  r10, lsl #1  // grain_lut += 2 * grain_stride
+.else
+        add             r5,  r5,  r10, lsl #3  // grain_lut += 8 * grain_stride
+        add             r5,  r5,  r10          // grain_lut += grain_stride
+.endif
+        vmov.16         d31[2], r6             // overlap y [0]
+
+        ldr             r12, [r8, #8]          // offsets[1][0]
+        calc_offset     r12, r4,  r12, \sx, \sy
+        add_offset      r4,  r12, r4,  r5,  r10
+
+        ldr             r12, [r8, #4]          // offsets[0][1]
+        calc_offset     r12, lr,  r12, \sx, \sy
+        add_offset      lr,  r12, lr,  r5,  r10
+
+        ldr             r12, [r8, #12]         // offsets[1][1]
+        calc_offset     r12, r11, r12, \sx, \sy
+        add_offset      r11, r12, r11, r5,  r10
+
+        ldr             r8,  [r8]              // offsets[0][0]
+        calc_offset     r8,  r12, r8,  \sx, \sy
+        add_offset      r5,  r8,  r12, r5,  r10
+
+        vmov.16         d31[3], r7             // overlap y [1]
+
+        add             r4,  r4,  #2*(32 >> \sx)      // grain_lut += FG_BLOCK_SIZE * bx
+        add             r8,  lr,  r10, lsl #(5 - \sy) // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             r11, r11, r10, lsl #(5 - \sy) // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             r11, r11, #2*(32 >> \sx)      // grain_lut += FG_BLOCK_SIZE * bx
+
+        movrel_local    r12, overlap_coeffs_\sx
+        ldr             lr,       [sp, #132]   // type
+        ldrd            r6,  r7,  [sp, #108]   // luma_row, luma_stride
+
+        vld1.16         {d24, d25}, [r12, :128] // overlap_coeffs
+
+        movrel_local    r12, L(fguv_loop_sx\sx\()_tbl)
+#if CONFIG_THUMB
+        // This uses movrel_local instead of adr above, because the target
+        // can be out of range for adr. But movrel_local leaves the thumb bit
+        // set on COFF (but probably wouldn't if building for thumb on ELF),
+        // thus try to clear the bit for robustness.
+        bic             r12, r12, #1
+#endif
+
+        tst             lr,  #1
+        ldr             lr,  [r12, lr,  lsl #2]
+
+        add             r12, r12, lr
+
+        beq             1f
+        // y overlap
+        sub             lr,  r9,  #(2 >> \sy)  // backup remaining h
+        mov             r9,  #(2 >> \sy)
+
+1:
+.if \sy
+        add             r7,  r7,  r7           // luma_stride *= 2
+.endif
+        sub             r7,  r7,  #32          // luma_stride -= 32
+
+        bx              r12
+endfunc
+.endm
+
+fguv 420, 1, 1
+fguv 422, 1, 0
+fguv 444, 0, 0
+
+function fguv_loop_sx0_neon
+L(fguv_loop_sx0_tbl):
+        .word L(fguv_loop_sx0_csfl0_00) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl0_01) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl0_10) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl0_11) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl1_00) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl1_01) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl1_10) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx0_csfl1_11) - L(fguv_loop_sx0_tbl) + CONFIG_THUMB
+
+.macro fguv_loop_sx0 csfl, ox, oy
+L(fguv_loop_sx0_csfl\csfl\()_\ox\oy):
+        sub             r2,  r2,  #32          // src_stride   -= 32
+        sub             r10, r10, #32          // grain_stride -= 32
+.if \oy
+        mov             r12, lr
+.endif
+L(fguv_loop_sx0_csfl\csfl\()_\ox\oy\()_loopstart):
+1:
+.if \ox
+        vld1.16         {d0},       [r4],       r10 // grain_lut old
+.endif
+.if \oy
+        vld1.16         {q2,  q3},  [r8]!           // grain_lut top
+.endif
+.if \ox && \oy
+        vld1.16         {d2},       [r11],      r10 // grain_lut top old
+.endif
+.if !\ox && !\oy
+        vld1.16         {q0,  q1},  [r6, :128]!     // luma
+.endif
+        vld1.16         {q8,  q9},  [r5]!           // grain_lut
+.if \oy
+        vld1.16         {q4,  q5},  [r8],       r10 // grain_lut top
+.endif
+.if !\ox && !\oy
+        vld1.16         {q2,  q3},  [r6, :128], r7  // luma
+.endif
+.if \oy
+        vdup.16         d28, d31[2]                 // overlap y coeff
+        vdup.16         d29, d31[3]                 // overlap y coeff
+.endif
+        vld1.16         {q10, q11}, [r5],       r10 // grain_lut
+
+.if \ox
+        vdup.16         q7,  d30[3]                // bitdepth_max
+        add             r4,  r4,  #32
+        vmull.s16       q0,  d0,  d24
+        vshr.u16        q7,  q7,  #1               // grain_max
+        vmlal.s16       q0,  d16, d25
+        vmvn            q6,  q7                    // grain_min
+.endif
+
+.if \oy
+.if \ox
+        add             r11, r11, #32
+        vmull.s16       q1,  d2,  d24
+        vmlal.s16       q1,  d4,  d25
+        vqrshrn.s32     d16, q0,  #5
+        vqrshrn.s32     d4,  q1,  #5
+        vmin.s16        d4,  d4,  d14
+        vmin.s16        d16, d16, d14
+        vmax.s16        d4,  d4,  d12
+        vmax.s16        d16, d16, d12
+.endif
+
+        vmull.s16       q0,  d4,  d28
+        vmull.s16       q1,  d5,  d28
+        vmull.s16       q2,  d6,  d28
+        vmull.s16       q3,  d7,  d28
+.if !\ox
+        vdup.16         q7,  d30[3]                // bitdepth_max
+.endif
+        vmlal.s16       q0,  d16, d29
+        vmlal.s16       q1,  d17, d29
+        vmlal.s16       q2,  d18, d29
+        vmlal.s16       q3,  d19, d29
+.if !\ox
+        vshr.u16        q7,  q7,  #1               // grain_max
+.endif
+        vmull.s16       q8,  d20, d29
+        vmull.s16       q9,  d21, d29
+        vmull.s16       q10, d22, d29
+        vmull.s16       q11, d23, d29
+.if !\ox
+        vmvn            q6,  q7                    // grain_min
+.endif
+        vmlal.s16       q8,  d8,  d28
+        vmlal.s16       q9,  d9,  d28
+        vmlal.s16       q10, d10, d28
+        vmlal.s16       q11, d11, d28
+        vqrshrn.s32     d0,  q0,  #5
+        vqrshrn.s32     d1,  q1,  #5
+        vqrshrn.s32     d2,  q2,  #5
+        vqrshrn.s32     d3,  q3,  #5
+        vqrshrn.s32     d4,  q8,  #5
+        vqrshrn.s32     d5,  q9,  #5
+        vqrshrn.s32     d6,  q10, #5
+        vqrshrn.s32     d7,  q11, #5
+        vmin.s16        q8,  q0,  q7
+        vmin.s16        q9,  q1,  q7
+        vld1.16         {q0,  q1},  [r6, :128]!    // luma
+        vmin.s16        q10, q2,  q7
+        vmin.s16        q11, q3,  q7
+        vmax.s16        q8,  q8,  q6
+        vmax.s16        q9,  q9,  q6
+        vld1.16         {q2,  q3},  [r6, :128], r7 // luma
+        vmax.s16        q10, q10, q6
+        vmax.s16        q11, q11, q6
+.elseif \ox
+        vqrshrn.s32     d16, q0,  #5
+        vld1.16         {q0,  q1},  [r6, :128]!    // luma
+        vmin.s16        d16, d16, d14
+        vld1.16         {q2,  q3},  [r6, :128], r7 // luma
+        vmax.s16        d16, d16, d12
+.endif
+
+.if !\csfl
+        vdup.16         d28, d30[0]   // uv_luma_mult
+        vld1.16         {q4,  q5},  [r1, :128]! // src
+        vdup.16         d29, d30[1]   // uv_mult
+        vmull.s16       q6,  d0,  d28
+        vmull.s16       q7,  d1,  d28
+        vmull.s16       q0,  d2,  d28
+        vmull.s16       q1,  d3,  d28
+        vmlal.s16       q6,  d8,  d29
+        vmlal.s16       q7,  d9,  d29
+        vmlal.s16       q0,  d10, d29
+        vmlal.s16       q1,  d11, d29
+        vld1.16         {q4,  q5},  [r1, :128]  // src
+        sub             r1,  r1,  #32
+        vshrn.s32       d12, q6,  #6
+        vshrn.s32       d13, q7,  #6
+        vshrn.s32       d14, q0,  #6
+        vshrn.s32       d15, q1,  #6
+        vmull.s16       q0,  d4,  d28
+        vmull.s16       q1,  d5,  d28
+        vmull.s16       q2,  d6,  d28
+        vmull.s16       q3,  d7,  d28
+        vmlal.s16       q0,  d8,  d29
+        vmlal.s16       q1,  d9,  d29
+        vmlal.s16       q2,  d10, d29
+        vmlal.s16       q3,  d11, d29
+        vdup.16         q14, d30[2]   // uv_offset
+        vshrn.s32       d0,  q0,  #6
+        vshrn.s32       d1,  q1,  #6
+        vshrn.s32       d2,  q2,  #6
+        vshrn.s32       d3,  q3,  #6
+        vdup.16         q4,  d30[3]   // bitdepth_max
+        vmov.i16        q5,  #0
+        vadd.i16        q6,  q6,  q14
+        vadd.i16        q7,  q7,  q14
+        vadd.i16        q2,  q0,  q14
+        vadd.i16        q3,  q1,  q14
+        vmin.s16        q0,  q6,  q4
+        vmin.s16        q1,  q7,  q4
+        vmin.s16        q2,  q2,  q4
+        vmin.s16        q3,  q3,  q4
+        vmax.s16        q0,  q0,  q5
+        vmax.s16        q1,  q1,  q5
+        vmax.s16        q2,  q2,  q5
+        vmax.s16        q3,  q3,  q5
+.else
+        vdup.16         q14, d30[3]  // bitdepth_max
+        // Make sure that uninitialized pixels out of range past the right
+        // edge are in range; their actual values shouldn't matter.
+        vand            q0,  q0,  q14
+        vand            q1,  q1,  q14
+        vand            q2,  q2,  q14
+        vand            q3,  q3,  q14
+.endif
+
+        bl              gather32_neon
+
+        vld1.16         {q0,  q1},  [r1, :128]!    // src
+
+        vmovl.u8        q6,  d8        // scaling
+        vmovl.u8        q7,  d9
+        vmovl.u8        q4,  d10
+        vmovl.u8        q5,  d11
+
+        vld1.16         {q2,  q3},  [r1, :128], r2 // src
+
+        vshl.u16        q6,  q6,  q13  // scaling << (15 - scaling_shift)
+        vshl.u16        q7,  q7,  q13
+        vshl.u16        q4,  q4,  q13
+        vshl.u16        q5,  q5,  q13
+
+        vqrdmulh.s16    q8,  q8,  q6   // round2((scaling << (15 - scaling_shift) * grain, 15)
+        vqrdmulh.s16    q9,  q9,  q7
+        vqrdmulh.s16    q10, q10, q4
+        vqrdmulh.s16    q11, q11, q5
+
+
+        vdup.16         q4,  d31[0]    // clip_min
+        vdup.16         q5,  d31[1]    // clip_max
+
+        vqadd.s16       q0,  q0,  q8   // *src + noise
+        vqadd.s16       q1,  q1,  q9
+        vqadd.s16       q2,  q2,  q10
+        vqadd.s16       q3,  q3,  q11
+
+.if \oy
+        vmov.32         lr,  d25[0] // 2 first 16 bit coeffs from overlap x
+.endif
+
+        vmax.s16        q0,  q0,  q4
+        vmax.s16        q1,  q1,  q4
+        vmax.s16        q2,  q2,  q4
+        vmax.s16        q3,  q3,  q4
+        vmin.s16        q0,  q0,  q5
+        vmin.s16        q1,  q1,  q5
+        vmin.s16        q2,  q2,  q5
+        vmin.s16        q3,  q3,  q5
+
+        vst1.16         {q0, q1}, [r0, :128]! // dst
+
+        subs            r9,  r9,  #1
+.if \oy
+        vmov.32         d31[1], lr  // new coeffs for overlap y
+.endif
+
+        vst1.16         {q2, q3}, [r0, :128], r2 // dst
+        bgt             1b
+
+.if \oy
+        cmp             r12, #0
+        mov             r9,  r12               // restore actual remaining h
+        bgt             L(fguv_loop_sx0_csfl\csfl\()_\ox\()0_loopstart)
+.endif
+        b               9f
+.endm
+        fguv_loop_sx0   0, 0, 0
+        fguv_loop_sx0   0, 0, 1
+        fguv_loop_sx0   0, 1, 0
+        fguv_loop_sx0   0, 1, 1
+        fguv_loop_sx0   1, 0, 0
+        fguv_loop_sx0   1, 0, 1
+        fguv_loop_sx0   1, 1, 0
+        fguv_loop_sx0   1, 1, 1
+
+9:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function fguv_loop_sx1_neon
+L(fguv_loop_sx1_tbl):
+        .word L(fguv_loop_sx1_csfl0_00) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl0_01) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl0_10) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl0_11) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl1_00) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl1_01) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl1_10) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+        .word L(fguv_loop_sx1_csfl1_11) - L(fguv_loop_sx1_tbl) + CONFIG_THUMB
+
+.macro fguv_loop_sx1 csfl, ox, oy
+L(fguv_loop_sx1_csfl\csfl\()_\ox\oy):
+.if \oy
+        mov             r12, lr
+.endif
+1:
+.if \ox
+        vld1.16         {d0},       [r4],       r10 // grain_lut old
+.endif
+.if \ox && \oy
+        vld1.16         {d2},       [r11],      r10 // grain_lut top old
+.endif
+.if \oy
+        vld1.16         {q2,  q3},  [r8],       r10 // grain_lut top
+.endif
+.if !\ox && !\oy
+        vld1.16         {q0,  q1},  [r6, :128]!     // luma
+.endif
+        vld1.16         {q8,  q9},  [r5],       r10 // grain_lut
+.if \oy
+        vdup.16         d28, d31[2]                 // overlap y coeff
+        vdup.16         d29, d31[3]                 // overlap y coeff
+.endif
+.if !\ox && !\oy
+        vld1.16         {q2,  q3},  [r6, :128], r7  // luma
+.endif
+
+.if \ox
+        vdup.16         q7,  d30[3]                // bitdepth_max
+        vmull.s16       q0,  d0,  d24
+        vshr.u16        q7,  q7,  #1               // grain_max
+        vmlal.s16       q0,  d16, d25
+        vmvn            q6,  q7                    // grain_min
+.endif
+
+.if \oy
+.if \ox
+        vmull.s16       q1,  d2,  d24
+        vmlal.s16       q1,  d4,  d25
+        vqrshrn.s32     d16, q0,  #5
+        vqrshrn.s32     d4,  q1,  #5
+        vmin.s16        d4,  d4,  d14
+        vmin.s16        d16, d16, d14
+        vmax.s16        d4,  d4,  d12
+        vmax.s16        d16, d16, d12
+.endif
+
+        vmull.s16       q0,  d4,  d28
+        vmull.s16       q1,  d5,  d28
+        vmull.s16       q2,  d6,  d28
+        vmull.s16       q3,  d7,  d28
+.if !\ox
+        vdup.16         q7,  d30[3]                // bitdepth_max
+.endif
+        vmlal.s16       q0,  d16, d29
+        vmlal.s16       q1,  d17, d29
+        vmlal.s16       q2,  d18, d29
+        vmlal.s16       q3,  d19, d29
+.if !\ox
+        vshr.u16        q7,  q7,  #1               // grain_max
+.endif
+        vqrshrn.s32     d16, q0,  #5
+        vqrshrn.s32     d17, q1,  #5
+        vqrshrn.s32     d18, q2,  #5
+        vqrshrn.s32     d19, q3,  #5
+.if !\ox
+        vmvn            q6,  q7                    // grain_min
+.endif
+        vld1.16         {q0,  q1},  [r6, :128]!    // luma
+        vmin.s16        q8,  q8,  q7
+        vmin.s16        q9,  q9,  q7
+        vmax.s16        q8,  q8,  q6
+        vmax.s16        q9,  q9,  q6
+        vld1.16         {q2,  q3},  [r6, :128], r7 // luma
+.elseif \ox
+        vqrshrn.s32     d16, q0,  #5
+        vld1.16         {q0,  q1},  [r6, :128]!    // luma
+        vmin.s16        d16, d16, d14
+        vld1.16         {q2,  q3},  [r6, :128], r7 // luma
+        vmax.s16        d16, d16, d12
+.endif
+
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vpadd.i16       d2,  d4,  d5
+        vpadd.i16       d3,  d6,  d7
+        vrshr.u16       q0,  q0,  #1
+        vrshr.u16       q1,  q1,  #1
+.if !\csfl
+        vdup.16         d28, d30[0]   // uv_luma_mult
+        vld1.16         {q2,  q3},  [r1, :128], r2 // src
+        vdup.16         d29, d30[1]   // uv_mult
+        vmull.s16       q6,  d0,  d28
+        vmull.s16       q7,  d1,  d28
+        vmull.s16       q0,  d2,  d28
+        vmull.s16       q1,  d3,  d28
+        vmlal.s16       q6,  d4,  d29
+        vmlal.s16       q7,  d5,  d29
+        vmlal.s16       q0,  d6,  d29
+        vmlal.s16       q1,  d7,  d29
+        vshrn.s32       d12, q6,  #6
+        vshrn.s32       d13, q7,  #6
+        vshrn.s32       d14, q0,  #6
+        vshrn.s32       d15, q1,  #6
+        vdup.16         q14, d30[2]   // uv_offset
+        vdup.16         q4,  d30[3]   // bitdepth_max
+        vmov.i16        q5,  #0
+        vadd.i16        q6,  q6,  q14
+        vadd.i16        q7,  q7,  q14
+        vmin.s16        q0,  q6,  q4
+        vmin.s16        q1,  q7,  q4
+        vmax.s16        q0,  q0,  q5
+        vmax.s16        q1,  q1,  q5
+.else
+        vdup.16         q14, d30[3]  // bitdepth_max
+        vld1.16         {q2,  q3},  [r1, :128], r2 // src
+
+        // Make sure that uninitialized pixels out of range past the right
+        // edge are in range; their actual values shouldn't matter.
+        vand            q0,  q0,  q14
+        vand            q1,  q1,  q14
+.endif
+
+        bl              gather16_neon
+
+        vmovl.u8        q6,  d8        // scaling
+        vmovl.u8        q7,  d9
+
+        vshl.u16        q6,  q6,  q13  // scaling << (15 - scaling_shift)
+        vshl.u16        q7,  q7,  q13
+
+        vqrdmulh.s16    q8,  q8,  q6   // round2((scaling << (15 - scaling_shift) * grain, 15)
+        vqrdmulh.s16    q9,  q9,  q7
+
+
+        vdup.16         q4,  d31[0]    // clip_min
+        vdup.16         q5,  d31[1]    // clip_max
+
+        vqadd.s16       q0,  q2,  q8   // *src + noise
+        vqadd.s16       q1,  q3,  q9
+
+.if \oy
+        // Swap the two last coefficients of d31, place them first in d28
+        vrev64.16       d28, d31
+.endif
+
+        vmax.s16        q0,  q0,  q4
+        vmax.s16        q1,  q1,  q4
+        vmin.s16        q0,  q0,  q5
+        vmin.s16        q1,  q1,  q5
+
+        subs            r9,  r9,  #1
+.if \oy
+        // Take the first two 16 bit coefficients of d28 and place them at the
+        // end of d31
+        vtrn.32         d31, d28
+.endif
+
+        vst1.16         {q0, q1}, [r0, :128], r2 // dst
+        bgt             1b
+
+.if \oy
+        cmp             r12, #0
+        mov             r9,  r12               // restore actual remaining h
+        bgt             L(fguv_loop_sx1_csfl\csfl\()_\ox\()0)
+.endif
+
+        b               9f
+.endm
+        fguv_loop_sx1   0, 0, 0
+        fguv_loop_sx1   0, 0, 1
+        fguv_loop_sx1   0, 1, 0
+        fguv_loop_sx1   0, 1, 1
+        fguv_loop_sx1   1, 0, 0
+        fguv_loop_sx1   1, 0, 1
+        fguv_loop_sx1   1, 1, 0
+        fguv_loop_sx1   1, 1, 1
+
+9:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/ipred.S b/media/libdav1d/src/src/arm/32/ipred.S
new file mode 100644
index 0000000000..8c6d539a47
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/ipred.S
@@ -0,0 +1,2958 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * Copyright © 2019, B Krishnan Iyer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// void ipred_dc_128_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int a,
+//                             const int max_width, const int max_height);
+function ipred_dc_128_8bpc_neon, export=1
+        push            {r4, lr}
+        ldr             r4,  [sp, #8]
+        clz             r3,  r3
+        adr             r2,  L(ipred_dc_128_tbl)
+        sub             r3,  r3,  #25
+        ldr             r3,  [r2,  r3,  lsl #2]
+        vmov.i8         q0,  #128
+        add             r2,  r2,  r3
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r2
+
+        .align 2
+L(ipred_dc_128_tbl):
+        .word 640f - L(ipred_dc_128_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_dc_128_tbl) + CONFIG_THUMB
+        .word 16f  - L(ipred_dc_128_tbl) + CONFIG_THUMB
+        .word 8f   - L(ipred_dc_128_tbl) + CONFIG_THUMB
+        .word 4f   - L(ipred_dc_128_tbl) + CONFIG_THUMB
+4:
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        subs            r4,  r4,  #4
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        bgt             4b
+        pop             {r4, pc}
+8:
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        bgt             8b
+        pop             {r4, pc}
+16:
+        vst1.8          {d0,  d1}, [r0,  :128], r1
+        vst1.8          {d0,  d1}, [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1}, [r0,  :128], r1
+        vst1.8          {d0,  d1}, [r12, :128], r1
+        bgt             16b
+        pop             {r4, pc}
+320:
+        vmov.i8         q1,  #128
+32:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             32b
+        pop             {r4, pc}
+640:
+        vmov.i8         q1,  #128
+        sub             r1,  r1,  #32
+64:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             64b
+        pop             {r4, pc}
+endfunc
+
+// void ipred_v_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                        const pixel *const topleft,
+//                        const int width, const int height, const int a,
+//                        const int max_width, const int max_height);
+function ipred_v_8bpc_neon, export=1
+        push            {r4, lr}
+        ldr             lr,  [sp, #8]
+        clz             r3,  r3
+        adr             r4,  L(ipred_v_tbl)
+        sub             r3,  r3,  #25
+        ldr             r3,  [r4,  r3,  lsl #2]
+        add             r2,  r2,  #1
+        add             r4,  r4,  r3
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r4
+
+        .align 2
+L(ipred_v_tbl):
+        .word 640f - L(ipred_v_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_v_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_v_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_v_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_v_tbl) + CONFIG_THUMB
+40:
+        vld1.32         {d0[]},   [r2]
+4:
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        subs            lr,  lr,  #4
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        bgt             4b
+        pop             {r4, pc}
+80:
+        vld1.8          {d0}, [r2]
+8:
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        subs            lr,  lr,  #4
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        bgt             8b
+        pop             {r4, pc}
+160:
+        vld1.8          {q0},  [r2]
+16:
+        vst1.8          {d0,  d1},  [r0,  :128], r1
+        vst1.8          {d0,  d1},  [r12, :128], r1
+        subs            lr,  lr,  #4
+        vst1.8          {d0,  d1},  [r0,  :128], r1
+        vst1.8          {d0,  d1},  [r12, :128], r1
+        bgt             16b
+        pop             {r4, pc}
+320:
+        vld1.8          {q0,  q1},  [r2]
+32:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            lr,  lr,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             32b
+        pop             {r4, pc}
+640:
+        vld1.8          {q0,  q1},  [r2]!
+        sub             r1,  r1,  #32
+        vld1.8          {q2,  q3},  [r2]
+64:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d4,  d5,  d6,  d7},  [r0,  :128], r1
+        vst1.8          {d4,  d5,  d6,  d7},  [r12, :128], r1
+        subs            lr,  lr,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d4,  d5,  d6,  d7},  [r0,  :128], r1
+        vst1.8          {d4,  d5,  d6,  d7},  [r12, :128], r1
+        bgt             64b
+        pop             {r4, pc}
+endfunc
+
+// void ipred_h_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                        const pixel *const topleft,
+//                        const int width, const int height, const int a,
+//                        const int max_width, const int max_height);
+function ipred_h_8bpc_neon, export=1
+        push            {r4-r5, lr}
+        ldr             r4,  [sp, #12]
+        clz             r3,  r3
+        adr             r5,  L(ipred_h_tbl)
+        sub             r3,  r3,  #25
+        ldr             r3,  [r5,  r3,  lsl #2]
+        sub             r2,  r2,  #4
+        mov             lr,  #-4
+        add             r5,  r5,  r3
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_h_tbl):
+        .word 640f - L(ipred_h_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_h_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_h_tbl) + CONFIG_THUMB
+        .word 8f   - L(ipred_h_tbl) + CONFIG_THUMB
+        .word 4f   - L(ipred_h_tbl) + CONFIG_THUMB
+4:
+        vld4.8          {d0[],  d1[],  d2[],  d3[]},  [r2, :32],  lr
+        vst1.32         {d3[0]},  [r0,  :32], r1
+        vst1.32         {d2[0]},  [r12, :32], r1
+        subs            r4,  r4,  #4
+        vst1.32         {d1[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        bgt             4b
+        pop             {r4-r5, pc}
+8:
+        vld4.8          {d0[],  d1[],  d2[],  d3[]},  [r2, :32],  lr
+        vst1.8          {d3},  [r0,  :64], r1
+        vst1.8          {d2},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d1},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        bgt             8b
+        pop             {r4-r5, pc}
+160:
+        add             r2,  r2,  #3
+        mov             lr,  #-1
+16:
+        vld1.8          {d0[],  d1[]},  [r2],  lr
+        subs            r4,  r4,  #4
+        vld1.8          {d2[],  d3[]},  [r2],  lr
+        vst1.8          {q0},  [r0,    :128],  r1
+        vld1.8          {d4[],  d5[]},  [r2],  lr
+        vst1.8          {q1},  [r12,   :128],  r1
+        vld1.8          {d6[],  d7[]},  [r2],  lr
+        vst1.8          {q2},  [r0,    :128],  r1
+        vst1.8          {q3},  [r12,   :128],  r1
+        bgt             16b
+        pop             {r4-r5, pc}
+320:
+        add             r2,  r2,  #3
+        mov             lr,  #-1
+        sub             r1,  r1,  #16
+32:
+        vld1.8          {d0[],  d1[]}, [r2],  lr
+        subs            r4,  r4,  #4
+        vld1.8          {d2[],  d3[]}, [r2],  lr
+        vst1.8          {q0},  [r0,   :128]!
+        vld1.8          {d4[],  d5[]}, [r2],  lr
+        vst1.8          {q1},  [r12,  :128]!
+        vld1.8          {d6[],  d7[]}, [r2],  lr
+        vst1.8          {q0},  [r0,   :128],  r1
+        vst1.8          {q1},  [r12,  :128],  r1
+        vst1.8          {q2},  [r0,   :128]!
+        vst1.8          {q3},  [r12,  :128]!
+        vst1.8          {q2},  [r0,   :128],  r1
+        vst1.8          {q3},  [r12,  :128],  r1
+        bgt             32b
+        pop             {r4-r5, pc}
+640:
+        add             r2,  r2,  #3
+        mov             lr,  #-1
+        sub             r1,  r1,  #48
+64:
+        vld1.8          {d0[],  d1[]},  [r2],  lr
+        subs            r4,  r4,  #4
+        vld1.8          {d2[],  d3[]},  [r2],  lr
+        vst1.8          {q0},  [r0,    :128]!
+        vld1.8          {d4[],  d5[]},  [r2],  lr
+        vst1.8          {q1},  [r12,   :128]!
+        vld1.8          {d6[],  d7[]},  [r2],  lr
+        vst1.8          {q0},  [r0,    :128]!
+        vst1.8          {q1},  [r12,   :128]!
+        vst1.8          {q0},  [r0,    :128]!
+        vst1.8          {q1},  [r12,   :128]!
+        vst1.8          {q0},  [r0,    :128],  r1
+        vst1.8          {q1},  [r12,   :128],  r1
+        vst1.8          {q2},  [r0,    :128]!
+        vst1.8          {q3},  [r12,   :128]!
+        vst1.8          {q2},  [r0,    :128]!
+        vst1.8          {q3},  [r12,   :128]!
+        vst1.8          {q2},  [r0,    :128]!
+        vst1.8          {q3},  [r12,   :128]!
+        vst1.8          {q2},  [r0,    :128],  r1
+        vst1.8          {q3},  [r12,   :128],  r1
+        bgt             64b
+        pop             {r4-r5, pc}
+endfunc
+
+// void ipred_dc_top_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int a,
+//                             const int max_width, const int max_height);
+function ipred_dc_top_8bpc_neon, export=1
+        push            {r4-r5, lr}
+        ldr             r4,  [sp, #12]
+        clz             r3,  r3
+        adr             r5,  L(ipred_dc_top_tbl)
+        sub             r3,  r3,  #25
+        ldr             r3,  [r5,  r3,  lsl #2]
+        add             r2,  r2,  #1
+        add             r5,  r5,  r3
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_dc_top_tbl):
+        .word 640f - L(ipred_dc_top_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_dc_top_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_dc_top_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_dc_top_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_dc_top_tbl) + CONFIG_THUMB
+40:
+        vld1.32         {d0[]},  [r2]
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d0,  q0,  #2
+        vdup.8          d0,  d0[0]
+4:
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        subs            r4,  r4,  #4
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        bgt             4b
+        pop             {r4-r5, pc}
+80:
+        vld1.8          {d0},  [r2]
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d0,  q0,  #3
+        vdup.8          d0,  d0[0]
+8:
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        bgt             8b
+        pop             {r4-r5, pc}
+160:
+        vld1.8          {d0,  d1},  [r2]
+        vaddl.u8        q0,  d0,  d1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d0,  q0,  #4
+        vdup.8          q0,  d0[0]
+16:
+        vst1.8          {d0,  d1},  [r0,  :128], r1
+        vst1.8          {d0,  d1},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1},  [r0,  :128], r1
+        vst1.8          {d0,  d1},  [r12, :128], r1
+        bgt             16b
+        pop             {r4-r5, pc}
+320:
+        vld1.8          {d0,  d1,  d2,  d3},  [r2]
+        vaddl.u8        q0,  d0,  d1
+        vaddl.u8        q1,  d2,  d3
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d4,  q0,  #5
+        vdup.8          q0,  d4[0]
+        vdup.8          q1,  d4[0]
+32:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             32b
+        pop             {r4-r5, pc}
+640:
+        vld1.8          {d0,  d1,  d2,  d3},  [r2]!
+        vaddl.u8        q0,  d0,  d1
+        vld1.8          {d4,  d5,  d6,  d7},  [r2]
+        vaddl.u8        q1,  d2,  d3
+        vaddl.u8        q2,  d4,  d5
+        vaddl.u8        q3,  d6,  d7
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        q1,  q2,  q3
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d18, q0,  #6
+        vdup.8          q0,  d18[0]
+        vdup.8          q1,  d18[0]
+        sub             r1,  r1,  #32
+64:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             64b
+        pop             {r4-r5, pc}
+endfunc
+
+// void ipred_dc_left_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int a,
+//                              const int max_width, const int max_height);
+function ipred_dc_left_8bpc_neon, export=1
+        push            {r4-r5, lr}
+        ldr             r4,  [sp, #12]
+        sub             r2,  r2,  r4
+        clz             r3,  r3
+        clz             lr,  r4
+        sub             lr,  lr,  #25
+        adr             r5,  L(ipred_dc_left_tbl)
+        sub             r3,  r3,  #20
+        ldr             r3,  [r5,  r3,  lsl #2]
+        ldr             lr,  [r5,  lr,  lsl #2]
+        add             r3,  r5,  r3
+        add             r5,  r5,  lr
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_dc_left_tbl):
+        .word L(ipred_dc_left_h64) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_h32) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_h16) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_h8)  - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_h4)  - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w64) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w32) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w16) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w8)  - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w4)  - L(ipred_dc_left_tbl) + CONFIG_THUMB
+
+L(ipred_dc_left_h4):
+        vld1.32         {d0[]},  [r2, :32]
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d0,  q0,  #2
+        vdup.8          q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w4):
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        subs            r4,  r4,  #4
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        bgt             L(ipred_dc_left_w4)
+        pop             {r4-r5, pc}
+L(ipred_dc_left_h8):
+        vld1.8          {d0},  [r2, :64]
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d0,  q0,  #3
+        vdup.8          q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w8):
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        bgt             L(ipred_dc_left_w8)
+        pop             {r4-r5, pc}
+L(ipred_dc_left_h16):
+        vld1.8          {d0,  d1},  [r2, :128]
+        vaddl.u8        q0,  d0,  d1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d0,  q0,  #4
+        vdup.8          q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w16):
+        vst1.8          {d0,  d1},  [r0,  :128], r1
+        vst1.8          {d0,  d1},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1},  [r0,  :128], r1
+        vst1.8          {d0,  d1},  [r12, :128], r1
+        bgt             L(ipred_dc_left_w16)
+        pop             {r4-r5, pc}
+L(ipred_dc_left_h32):
+        vld1.8          {d0,  d1,  d2,  d3},  [r2, :128]
+        vaddl.u8        q0,  d0,  d1
+        vaddl.u8        q1,  d2,  d3
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d0,  q0,  #5
+        vdup.8          q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w32):
+        vmov.8          q1,  q0
+1:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             1b
+        pop             {r4-r5, pc}
+L(ipred_dc_left_h64):
+        vld1.8          {d0,  d1,  d2,  d3},  [r2, :128]!
+        vld1.8          {d4,  d5,  d6,  d7},  [r2, :128]
+        vaddl.u8        q0,  d0,  d1
+        vaddl.u8        q1,  d2,  d3
+        vaddl.u8        q2,  d4,  d5
+        vaddl.u8        q3,  d6,  d7
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        q1,  q2,  q3
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshrn.u16      d0,  q0,  #6
+        vdup.8          q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w64):
+        vmov.8          q1,  q0
+        sub             r1,  r1,  #32
+1:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4, #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             1b
+        pop             {r4-r5, pc}
+endfunc
+
+// void ipred_dc_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const topleft,
+//                         const int width, const int height, const int a,
+//                         const int max_width, const int max_height);
+function ipred_dc_8bpc_neon, export=1
+        push            {r4-r6, lr}
+        ldr             r4,  [sp, #16]
+        sub             r2,  r2,  r4
+        add             lr,  r3,  r4        // width + height
+        clz             r3,  r3
+        clz             r12, r4
+        vdup.16         q15, lr             // width + height
+        adr             r5,  L(ipred_dc_tbl)
+        rbit            lr,  lr             // rbit(width + height)
+        sub             r3,  r3,  #20       // 25 leading bits, minus table offset 5
+        sub             r12, r12, #25
+        clz             lr,  lr             // ctz(width + height)
+        ldr             r3,  [r5,  r3,  lsl #2]
+        ldr             r12, [r5,  r12, lsl #2]
+        neg             lr,  lr             // -ctz(width + height)
+        add             r3,  r5,  r3
+        add             r5,  r5,  r12
+        vshr.u16        q15, q15, #1        // (width + height) >> 1
+        vdup.16         q14, lr             // -ctz(width + height)
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_dc_tbl):
+        .word L(ipred_dc_h64) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_h32) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_h16) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_h8)  - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_h4)  - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w64) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w32) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w16) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w8)  - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w4)  - L(ipred_dc_tbl) + CONFIG_THUMB
+
+L(ipred_dc_h4):
+        vld1.32         {d0[]},  [r2, :32]!
+        vpaddl.u8       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.u16       d0,  d0
+        bx              r3
+L(ipred_dc_w4):
+        vld1.32         {d1[]},  [r2]
+        vadd.s16        d0,  d0,  d30
+        vpaddl.u8       d1,  d1
+        vpadd.u16       d1,  d1
+        cmp             r4,  #4
+        vadd.s16        d0,  d0,  d1
+        vshl.u16        d0,  d0,  d28
+        beq             1f
+        // h = 8/16
+        movw            lr,  #(0x3334/2)
+        movw            r5,  #(0x5556/2)
+        cmp             r4,  #16
+        it              ne
+        movne           lr,  r5
+        vdup.16         d30, lr
+        vqdmulh.s16     d0,  d0,  d30
+1:
+        vdup.8          d0,  d0[0]
+2:
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        subs            r4,  r4,  #4
+        vst1.32         {d0[0]},  [r0,  :32], r1
+        vst1.32         {d0[0]},  [r12, :32], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+
+L(ipred_dc_h8):
+        vld1.8          {d0},  [r2, :64]!
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.u16       d0,  d0
+        bx              r3
+L(ipred_dc_w8):
+        vld1.8          {d2},  [r2]
+        vadd.s16        d0,  d0,  d30
+        vpaddl.u8       d2,  d2
+        vpadd.u16       d2,  d2
+        vpadd.u16       d2,  d2
+        cmp             r4,  #8
+        vadd.s16        d0,  d0,  d2
+        vshl.u16        d0,  d0,  d28
+        beq             1f
+        // h = 4/16/32
+        cmp             r4,  #32
+        movw            lr,  #(0x3334/2)
+        movw            r5,  #(0x5556/2)
+        it              ne
+        movne           lr,  r5
+        vdup.16         d24, lr
+        vqdmulh.s16     d0,  d0,  d24
+1:
+        vdup.8          d0,  d0[0]
+2:
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0},  [r0,  :64], r1
+        vst1.8          {d0},  [r12, :64], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+
+L(ipred_dc_h16):
+        vld1.8          {d0,  d1},  [r2, :128]!
+        vaddl.u8        q0,  d0,  d1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.u16       d0,  d0
+        bx              r3
+L(ipred_dc_w16):
+        vld1.8          {d2,  d3},  [r2]
+        vadd.s16        d0,  d0,  d30
+        vaddl.u8        q1,  d2,  d3
+        vadd.u16        d2,  d2,  d3
+        vpadd.u16       d2,  d2
+        vpadd.u16       d2,  d2
+        cmp             r4,  #16
+        vadd.s16        d0,  d0,  d2
+        vshl.u16        d0,  d0,  d28
+        beq             1f
+        // h = 4/8/32/64
+        tst             r4,  #(32+16+8)     // 16 added to make a consecutive bitmask
+        movw            lr,  #(0x3334/2)
+        movw            r5,  #(0x5556/2)
+        it              ne
+        movne           lr,  r5
+        vdup.16         d24, lr
+        vqdmulh.s16     d0,  d0,  d24
+1:
+        vdup.8          q0,  d0[0]
+2:
+        vst1.8          {d0,  d1},  [r0,  :128], r1
+        vst1.8          {d0,  d1},  [r12, :128], r1
+        subs            r4,  r4, #4
+        vst1.8          {d0,  d1},  [r0,  :128], r1
+        vst1.8          {d0,  d1},  [r12, :128], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+
+L(ipred_dc_h32):
+        vld1.8          {d0,  d1,  d2,  d3},  [r2, :128]!
+        vaddl.u8        q0,  d0,  d1
+        vaddl.u8        q1,  d2,  d3
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.u16       d0,  d0
+        bx              r3
+L(ipred_dc_w32):
+        vld1.8          {d2,  d3,  d4,  d5},  [r2]
+        vadd.s16        d0,  d0,  d30
+        vaddl.u8        q1,  d2,  d3
+        vaddl.u8        q2,  d4,  d5
+        vadd.u16        q1,  q1,  q2
+        vadd.u16        d2,  d2,  d3
+        vpadd.u16       d2,  d2
+        vpadd.u16       d2,  d2
+        cmp             r4,  #32
+        vadd.s16        d0,  d0,  d2
+        vshl.u16        d4,  d0,  d28
+        beq             1f
+        // h = 8/16/64
+        cmp             r4,  #8
+        movw            lr,  #(0x3334/2)
+        movw            r5,  #(0x5556/2)
+        it              ne
+        movne           lr,  r5
+        vdup.16         d24, lr
+        vqdmulh.s16     d4,  d4,  d24
+1:
+        vdup.8          q0,  d4[0]
+        vdup.8          q1,  d4[0]
+2:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+
+L(ipred_dc_h64):
+        vld1.8          {d0,  d1,  d2,  d3},  [r2, :128]!
+        vaddl.u8        q0,  d0,  d1
+        vld1.8          {d4,  d5,  d6,  d7},  [r2, :128]!
+        vaddl.u8        q1,  d2,  d3
+        vaddl.u8        q2,  d4,  d5
+        vaddl.u8        q3,  d6,  d7
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        q1,  q2,  q3
+        vadd.u16        q0,  q0,  q1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.u16       d0,  d0
+        bx              r3
+L(ipred_dc_w64):
+        vld1.8          {d2,  d3,  d4,  d5},  [r2]!
+        vadd.s16        d0,  d0,  d30
+        vaddl.u8        q2,  d4,  d5
+        vaddl.u8        q1,  d2,  d3
+        vadd.u16        d4,  d4,  d5
+        vadd.u16        d2,  d2,  d3
+        vld1.8          {d16, d17, d18, d19}, [r2]
+        vpadd.u16       d4,  d4
+        vpadd.u16       d2,  d2
+        vpadd.u16       d4,  d4
+        vpadd.u16       d2,  d2
+        vaddl.u8        q8,  d16, d17
+        vaddl.u8        q9,  d18, d19
+        vadd.u16        d16, d16, d17
+        vadd.u16        d18, d18, d19
+        vpadd.u16       d16, d16
+        vpadd.u16       d18, d18
+        vpadd.u16       d16, d16
+        vpadd.u16       d18, d18
+        vadd.u16        d2,  d2,  d4
+        vadd.u16        d3,  d16, d18
+        cmp             r4,  #64
+        vadd.s16        d0,  d0,  d2
+        vadd.s16        d0,  d0,  d3
+        vshl.u16        d18, d0,  d28
+        beq             1f
+        // h = 16/32
+        movw            lr,  #(0x5556/2)
+        movt            lr,  #(0x3334/2)
+        and             r5,  r4,  #31
+        lsr             lr,  lr,  r5
+        vdup.16         d30, lr
+        vqdmulh.s16     d18, d18, d30
+1:
+        sub             r1,  r1,  #32
+        vdup.8          q0,  d18[0]
+        vdup.8          q1,  d18[0]
+2:
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.8          {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.8          {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+endfunc
+
+// void ipred_paeth_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                            const pixel *const topleft,
+//                            const int width, const int height, const int a,
+//                            const int max_width, const int max_height);
+function ipred_paeth_8bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldr             r4,  [sp, #24]
+        clz             lr,  r3
+        adr             r5,  L(ipred_paeth_tbl)
+        sub             lr,  lr,  #25
+        ldr             lr,  [r5, lr, lsl #2]
+        vld1.8          {d4[], d5[]},  [r2]
+        add             r8,  r2,  #1
+        sub             r2,  r2,  #4
+        add             r5,  r5,  lr
+        mov             r7,  #-4
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_paeth_tbl):
+        .word 640f - L(ipred_paeth_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_paeth_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_paeth_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_paeth_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_paeth_tbl) + CONFIG_THUMB
+
+40:
+        vld1.32         {d6[], d7[]},  [r8]
+        vsubl.u8        q8,  d6,  d4  // top - topleft
+4:
+        vld4.8          {d0[], d1[], d2[], d3[]},  [r2, :32], r7
+        vzip.32         d0,  d1
+        vzip.32         d2,  d3
+        vaddw.u8        q9,  q8,  d0
+        vaddw.u8        q10, q8,  d2
+        vqmovun.s16     d18, q9       // base
+        vqmovun.s16     d19, q10
+        vmov            d1,  d2
+        vabd.u8         q10, q3,  q9  // tdiff
+        vabd.u8         q11, q2,  q9  // tldiff
+        vabd.u8         q9,  q0,  q9  // ldiff
+        vmin.u8         q12, q10, q11 // min(tdiff, tldiff)
+        vcge.u8         q10, q11, q10 // tldiff >= tdiff
+        vcge.u8         q9,  q12, q9  // min(tdiff, tldiff) >= ldiff
+        vbsl            q10, q3,  q2  // tdiff <= tldiff ? top : topleft
+        vbit            q10, q0,  q9  // ldiff <= min ? left : ...
+        vst1.32         {d21[1]}, [r0, :32], r1
+        vst1.32         {d21[0]}, [r6, :32], r1
+        subs            r4,  r4,  #4
+        vst1.32         {d20[1]}, [r0, :32], r1
+        vst1.32         {d20[0]}, [r6, :32], r1
+        bgt             4b
+        pop             {r4-r8, pc}
+80:
+        vld1.8          {d6},  [r8]
+        vsubl.u8        q8,  d6,  d4  // top - topleft
+        vmov            d7,  d6
+8:
+        vld4.8          {d0[], d1[], d2[], d3[]},  [r2, :32], r7
+        vaddw.u8        q9,  q8,  d0
+        vaddw.u8        q10, q8,  d1
+        vaddw.u8        q11, q8,  d2
+        vaddw.u8        q12, q8,  d3
+        vqmovun.s16     d18, q9       // base
+        vqmovun.s16     d19, q10
+        vqmovun.s16     d20, q11
+        vqmovun.s16     d21, q12
+        vabd.u8         q11, q3,  q9  // tdiff
+        vabd.u8         q12, q3,  q10
+        vabd.u8         q13, q2,  q9  // tldiff
+        vabd.u8         q14, q2,  q10
+        vabd.u8         q10, q1,  q10 // ldiff
+        vabd.u8         q9,  q0,  q9
+        vmin.u8         q15, q12, q14 // min(tdiff, tldiff)
+        vcge.u8         q12, q14, q12 // tldiff >= tdiff
+        vmin.u8         q14, q11, q13 // min(tdiff, tldiff)
+        vcge.u8         q11, q13, q11 // tldiff >= tdiff
+        vcge.u8         q10, q15, q10 // min(tdiff, tldiff) >= ldiff
+        vcge.u8         q9,  q14, q9
+        vbsl            q12, q3,  q2  // tdiff <= tldiff ? top : topleft
+        vbsl            q11, q3,  q2
+        vbit            q12, q1,  q10 // ldiff <= min ? left : ...
+        vbit            q11, q0,  q9
+        vst1.8          {d25}, [r0, :64], r1
+        vst1.8          {d24}, [r6, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d23}, [r0, :64], r1
+        vst1.8          {d22}, [r6, :64], r1
+        bgt             8b
+        pop             {r4-r8, pc}
+160:
+320:
+640:
+        vld1.8          {d6},  [r8]!
+        mov             r12, r3
+        // Set up pointers for four rows in parallel; r0, r6, r5, lr
+        add             r5,  r0,  r1
+        add             lr,  r6,  r1
+        lsl             r1,  r1,  #1
+        sub             r1,  r1,  r3
+1:
+        vld4.8          {d0[], d1[], d2[], d3[]},  [r2, :32], r7
+2:
+        vsubl.u8        q8,  d6,  d4  // top - topleft
+        vmov            d7,  d6
+        vaddw.u8        q9,  q8,  d0
+        vaddw.u8        q10, q8,  d1
+        vaddw.u8        q11, q8,  d2
+        vaddw.u8        q12, q8,  d3
+        vqmovun.s16     d18, q9       // base
+        vqmovun.s16     d19, q10
+        vqmovun.s16     d20, q11
+        vqmovun.s16     d21, q12
+        vabd.u8         q11, q3,  q9  // tdiff
+        vabd.u8         q12, q3,  q10
+        vabd.u8         q13, q2,  q9  // tldiff
+        vabd.u8         q14, q2,  q10
+        vabd.u8         q10, q1,  q10 // ldiff
+        vabd.u8         q9,  q0,  q9
+        vmin.u8         q15, q12, q14 // min(tdiff, tldiff)
+        vcge.u8         q12, q14, q12 // tldiff >= tdiff
+        vmin.u8         q14, q11, q13 // min(tdiff, tldiff)
+        vcge.u8         q11, q13, q11 // tldiff >= tdiff
+        vcge.u8         q10, q15, q10 // min(tdiff, tldiff) >= ldiff
+        vcge.u8         q9,  q14, q9
+        vbsl            q12, q3,  q2  // tdiff <= tldiff ? top : topleft
+        vbsl            q11, q3,  q2
+        vbit            q12, q1,  q10 // ldiff <= min ? left : ...
+        vbit            q11, q0,  q9
+        subs            r3,  r3,  #8
+        vst1.8          {d25}, [r0, :64]!
+        vst1.8          {d24}, [r6, :64]!
+        vst1.8          {d23}, [r5, :64]!
+        vst1.8          {d22}, [lr, :64]!
+        ble             8f
+        vld1.8          {d6},  [r8]!
+        b               2b
+8:
+        subs            r4,  r4,  #4
+        ble             9f
+        // End of horizontal loop, move pointers to next four rows
+        sub             r8,  r8,  r12
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        vld1.8          {d6},  [r8]!
+        add             r5,  r5,  r1
+        add             lr,  lr,  r1
+        mov             r3,  r12
+        b               1b
+9:
+        pop             {r4-r8, pc}
+endfunc
+
+// void ipred_smooth_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int a,
+//                             const int max_width, const int max_height);
+function ipred_smooth_8bpc_neon, export=1
+        push            {r4-r10, lr}
+        ldr             r4,  [sp, #32]
+        movrel          r10, X(sm_weights)
+        add             r12, r10, r4
+        add             r10, r10, r3
+        clz             r9,  r3
+        adr             r5,  L(ipred_smooth_tbl)
+        sub             lr,  r2,  r4
+        sub             r9,  r9,  #25
+        ldr             r9,  [r5, r9, lsl #2]
+        vld1.8          {d4[]},  [lr] // bottom
+        add             r8,  r2,  #1
+        add             r5,  r5,  r9
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_smooth_tbl):
+        .word 640f - L(ipred_smooth_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_smooth_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_smooth_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_smooth_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_smooth_tbl) + CONFIG_THUMB
+
+40:
+        vld1.32         {d16[]}, [r8]       // top
+        vld1.32         {d18[]}, [r10, :32] // weights_hor
+        sub             r2,  r2,  #4
+        mov             r7,  #-4
+        vdup.8          q3,  d16[3]   // right
+        vsubl.u8        q8,  d16, d4  // top-bottom
+        vmovl.u8        q9,  d18      // weights_hor
+4:
+        vld4.8          {d0[],  d1[],  d2[],  d3[]},  [r2,  :32], r7 // left
+        vld4.8          {d20[], d21[], d22[], d23[]}, [r12, :32]!    // weights_ver
+        vshll.i8        q12, d6,  #8  // right*256
+        vshll.i8        q13, d6,  #8
+        vzip.32         d1,  d0       // left, flipped
+        vzip.32         d3,  d2
+        vzip.32         d20, d21      // weights_ver
+        vzip.32         d22, d23
+        vshll.i8        q14, d4,  #8  // bottom*256
+        vshll.i8        q15, d4,  #8
+        vsubl.u8        q0,  d1,  d6  // left-right
+        vsubl.u8        q1,  d3,  d6
+        vmovl.u8        q10, d20      // weights_ver
+        vmovl.u8        q11, d22
+        vmla.i16        q12, q1,  q9  // right*256  + (left-right)*weights_hor
+        vmla.i16        q13, q0,  q9  // (left flipped)
+        vmla.i16        q14, q8,  q10 // bottom*256 + (top-bottom)*weights_ver
+        vmla.i16        q15, q8,  q11
+        vhadd.u16       q12, q12, q14
+        vhadd.u16       q13, q13, q15
+        vrshrn.i16      d24, q12, #8
+        vrshrn.i16      d25, q13, #8
+        vst1.32         {d24[0]}, [r0, :32], r1
+        vst1.32         {d24[1]}, [r6, :32], r1
+        subs            r4,  r4,  #4
+        vst1.32         {d25[0]}, [r0, :32], r1
+        vst1.32         {d25[1]}, [r6, :32], r1
+        bgt             4b
+        pop             {r4-r10, pc}
+80:
+        vld1.8          {d16}, [r8]       // top
+        vld1.8          {d18}, [r10, :64] // weights_hor
+        sub             r2,  r2,  #2
+        mov             r7,  #-2
+        vdup.8          q3,  d16[7]   // right
+        vsubl.u8        q8,  d16, d4  // top-bottom
+        vmovl.u8        q9,  d18      // weights_hor
+8:
+        vld2.8          {d0[],  d1[]},  [r2,  :16], r7 // left
+        vld2.8          {d20[], d22[]}, [r12, :16]!    // weights_ver
+        vshll.i8        q12, d6,  #8  // right*256
+        vshll.i8        q13, d6,  #8
+        vshll.i8        q14, d4,  #8  // bottom*256
+        vshll.i8        q15, d4,  #8
+        vsubl.u8        q1,  d0,  d6  // left-right (left flipped)
+        vsubl.u8        q0,  d1,  d6
+        vmovl.u8        q10, d20      // weights_ver
+        vmovl.u8        q11, d22
+        vmla.i16        q12, q0,  q9  // right*256  + (left-right)*weights_hor
+        vmla.i16        q13, q1,  q9
+        vmla.i16        q14, q8,  q10 // bottom*256 + (top-bottom)*weights_ver
+        vmla.i16        q15, q8,  q11
+        vhadd.u16       q12, q12, q14
+        vhadd.u16       q13, q13, q15
+        vrshrn.i16      d24, q12, #8
+        vrshrn.i16      d25, q13, #8
+        subs            r4,  r4,  #2
+        vst1.8          {d24}, [r0, :64], r1
+        vst1.8          {d25}, [r6, :64], r1
+        bgt             8b
+        pop             {r4-r10, pc}
+160:
+320:
+640:
+        add             lr,  r2,  r3
+        sub             r2,  r2,  #2
+        mov             r7,  #-2
+        vld1.8          {d6[], d7[]}, [lr] // right
+        sub             r1,  r1,  r3
+        mov             r9,  r3
+
+1:
+        vld2.8          {d0[],  d1[]},  [r2,  :16], r7 // left
+        vld2.8          {d20[], d22[]}, [r12, :16]!    // weights_ver
+        vsubl.u8        q1,  d0,  d6  // left-right (left flipped)
+        vsubl.u8        q0,  d1,  d6
+        vmovl.u8        q10, d20      // weights_ver
+        vmovl.u8        q11, d22
+2:
+        vld1.8          {d16}, [r8]!       // top
+        vld1.8          {d18}, [r10, :64]! // weights_hor
+        vshll.i8        q12, d6,  #8  // right*256
+        vshll.i8        q13, d6,  #8
+        vmovl.u8        q9,  d18      // weights_hor
+        vshll.i8        q14, d4,  #8  // bottom*256
+        vshll.i8        q15, d4,  #8
+        vsubl.u8        q8,  d16, d4  // top-bottom
+        vmla.i16        q12, q0,  q9  // right*256  + (left-right)*weights_hor
+        vmla.i16        q13, q1,  q9
+        vmla.i16        q14, q8,  q10 // bottom*256 + (top-bottom)*weights_ver
+        vmla.i16        q15, q8,  q11
+        vhadd.u16       q12, q12, q14
+        vhadd.u16       q13, q13, q15
+        vrshrn.i16      d24, q12, #8
+        vrshrn.i16      d25, q13, #8
+        subs            r3,  r3,  #8
+        vst1.8          {d24}, [r0, :64]!
+        vst1.8          {d25}, [r6, :64]!
+        bgt             2b
+        subs            r4,  r4,  #2
+        ble             9f
+        sub             r8,  r8,  r9
+        sub             r10, r10, r9
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        mov             r3,  r9
+        b               1b
+9:
+        pop             {r4-r10, pc}
+endfunc
+
+// void ipred_smooth_v_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height, const int a,
+//                               const int max_width, const int max_height);
+function ipred_smooth_v_8bpc_neon, export=1
+        push            {r4-r7, lr}
+        ldr             r4,  [sp, #20]
+        movrel          r7,  X(sm_weights)
+        add             r7,  r7,  r4
+        clz             lr,  r3
+        adr             r5,  L(ipred_smooth_v_tbl)
+        sub             r12, r2,  r4
+        sub             lr,  lr,  #25
+        ldr             lr,  [r5, lr, lsl #2]
+        vld1.8          {d4[]},  [r12] // bottom
+        add             r2,  r2,  #1
+        add             r5,  r5,  lr
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_smooth_v_tbl):
+        .word 640f - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+
+40:
+        vld1.32         {d6[]}, [r2]  // top
+        vsubl.u8        q3,  d6,  d4  // top-bottom
+4:
+        vld4.8          {d16[], d17[], d18[], d19[]}, [r7, :32]! // weights_ver
+        vshll.i8        q10, d4,  #8  // bottom*256
+        vshll.i8        q11, d4,  #8
+        vzip.32         d16, d17      // weights_ver
+        vzip.32         d18, d19
+        vmovl.u8        q8,  d16      // weights_ver
+        vmovl.u8        q9,  d18
+        subs            r4,  r4,  #4
+        vmla.i16        q10, q3,  q8  // bottom*256 + (top-bottom)*weights_ver
+        vmla.i16        q11, q3,  q9
+        vrshrn.i16      d20, q10, #8
+        vrshrn.i16      d21, q11, #8
+        vst1.32         {d20[0]}, [r0, :32], r1
+        vst1.32         {d20[1]}, [r6, :32], r1
+        vst1.32         {d21[0]}, [r0, :32], r1
+        vst1.32         {d21[1]}, [r6, :32], r1
+        bgt             4b
+        pop             {r4-r7, pc}
+80:
+        vld1.8          {d6}, [r2]    // top
+        vsubl.u8        q3,  d6,  d4  // top-bottom
+8:
+        vld4.8          {d16[], d18[], d20[], d22[]}, [r7, :32]! // weights_ver
+        vshll.i8        q12, d4,  #8  // bottom*256
+        vshll.i8        q13, d4,  #8
+        vshll.i8        q14, d4,  #8
+        vshll.i8        q15, d4,  #8
+        vmovl.u8        q8,  d16      // weights_ver
+        vmovl.u8        q9,  d18
+        vmovl.u8        q10, d20
+        vmovl.u8        q11, d22
+        vmla.i16        q12, q3,  q8  // bottom*256 + (top-bottom)*weights_ver
+        vmla.i16        q13, q3,  q9
+        vmla.i16        q14, q3,  q10
+        vmla.i16        q15, q3,  q11
+        vrshrn.i16      d24, q12, #8
+        vrshrn.i16      d25, q13, #8
+        vrshrn.i16      d26, q14, #8
+        vrshrn.i16      d27, q15, #8
+        vst1.8          {d24}, [r0, :64], r1
+        vst1.8          {d25}, [r6, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d26}, [r0, :64], r1
+        vst1.8          {d27}, [r6, :64], r1
+        bgt             8b
+        pop             {r4-r7, pc}
+160:
+320:
+640:
+        vpush           {q4-q7}
+        // Set up pointers for four rows in parallel; r0, r6, r5, lr
+        add             r5,  r0,  r1
+        add             lr,  r6,  r1
+        lsl             r1,  r1,  #1
+        sub             r1,  r1,  r3
+        mov             r12, r3
+
+1:
+        vld4.8          {d8[], d10[], d12[], d14[]}, [r7, :32]! // weights_ver
+        vmovl.u8        q4,  d8       // weights_ver
+        vmovl.u8        q5,  d10
+        vmovl.u8        q6,  d12
+        vmovl.u8        q7,  d14
+2:
+        vld1.8          {q3}, [r2]!   // top
+        vshll.i8        q8,  d4,  #8  // bottom*256
+        vshll.i8        q9,  d4,  #8
+        vshll.i8        q10, d4,  #8
+        vshll.i8        q11, d4,  #8
+        vsubl.u8        q0,  d6,  d4  // top-bottom
+        vsubl.u8        q1,  d7,  d4
+        vshll.i8        q12, d4,  #8
+        vshll.i8        q13, d4,  #8
+        vshll.i8        q14, d4,  #8
+        vshll.i8        q15, d4,  #8
+        vmla.i16        q8,  q0,  q4  // bottom*256 + (top-bottom)*weights_ver
+        vmla.i16        q9,  q1,  q4
+        vmla.i16        q10, q0,  q5
+        vmla.i16        q11, q1,  q5
+        vmla.i16        q12, q0,  q6  // bottom*256 + (top-bottom)*weights_ver
+        vmla.i16        q13, q1,  q6
+        vmla.i16        q14, q0,  q7
+        vmla.i16        q15, q1,  q7
+        vrshrn.i16      d16, q8,  #8
+        vrshrn.i16      d17, q9,  #8
+        vrshrn.i16      d18, q10, #8
+        vrshrn.i16      d19, q11, #8
+        vrshrn.i16      d20, q12, #8
+        vrshrn.i16      d21, q13, #8
+        vrshrn.i16      d22, q14, #8
+        vrshrn.i16      d23, q15, #8
+        subs            r3,  r3,  #16
+        vst1.8          {q8},  [r0, :128]!
+        vst1.8          {q9},  [r6, :128]!
+        vst1.8          {q10}, [r5, :128]!
+        vst1.8          {q11}, [lr, :128]!
+        bgt             2b
+        subs            r4,  r4,  #4
+        ble             9f
+        sub             r2,  r2,  r12
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        add             r5,  r5,  r1
+        add             lr,  lr,  r1
+        mov             r3,  r12
+        b               1b
+9:
+        vpop            {q4-q7}
+        pop             {r4-r7, pc}
+endfunc
+
+// void ipred_smooth_h_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height, const int a,
+//                               const int max_width, const int max_height);
+function ipred_smooth_h_8bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldr             r4,  [sp, #24]
+        movrel          r8,  X(sm_weights)
+        add             r8,  r8,  r3
+        clz             lr,  r3
+        adr             r5,  L(ipred_smooth_h_tbl)
+        add             r12, r2,  r3
+        sub             lr,  lr,  #25
+        ldr             lr,  [r5, lr, lsl #2]
+        vld1.8          {d4[]},  [r12] // right
+        add             r5,  r5,  lr
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_smooth_h_tbl):
+        .word 640f - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+
+40:
+        vld1.32         {d6[]}, [r8, :32] // weights_hor
+        sub             r2,  r2,  #4
+        mov             r7,  #-4
+        vmovl.u8        q3,  d6       // weights_hor
+4:
+        vld4.8          {d0[], d1[], d2[], d3[]},  [r2, :32], r7 // left
+        vshll.i8        q8,  d4,  #8  // right*256
+        vshll.i8        q9,  d4,  #8
+        vzip.32         d3,  d2       // left, flipped
+        vzip.32         d1,  d0
+        vsubl.u8        q1,  d3,  d4  // left-right
+        vsubl.u8        q0,  d1,  d4
+        subs            r4,  r4,  #4
+        vmla.i16        q8,  q1,  q3  // right*256  + (left-right)*weights_hor
+        vmla.i16        q9,  q0,  q3
+        vrshrn.i16      d16, q8,  #8
+        vrshrn.i16      d17, q9,  #8
+        vst1.32         {d16[0]}, [r0, :32], r1
+        vst1.32         {d16[1]}, [r6, :32], r1
+        vst1.32         {d17[0]}, [r0, :32], r1
+        vst1.32         {d17[1]}, [r6, :32], r1
+        bgt             4b
+        pop             {r4-r8, pc}
+80:
+        vld1.8          {d6}, [r8, :64] // weights_hor
+        sub             r2,  r2,  #4
+        mov             r7,  #-4
+        vmovl.u8        q3,  d6       // weights_hor
+8:
+        vld4.8          {d16[], d18[], d20[], d22[]},  [r2, :32], r7 // left
+        vshll.i8        q12, d4,  #8  // right*256
+        vshll.i8        q13, d4,  #8
+        vshll.i8        q14, d4,  #8
+        vshll.i8        q15, d4,  #8
+        vsubl.u8        q11, d22, d4  // left-right
+        vsubl.u8        q10, d20, d4
+        vsubl.u8        q9,  d18, d4
+        vsubl.u8        q8,  d16, d4
+        vmla.i16        q12, q11, q3  // right*256  + (left-right)*weights_hor
+        vmla.i16        q13, q10, q3  // (left flipped)
+        vmla.i16        q14, q9,  q3
+        vmla.i16        q15, q8,  q3
+        vrshrn.i16      d24, q12, #8
+        vrshrn.i16      d25, q13, #8
+        vrshrn.i16      d26, q14, #8
+        vrshrn.i16      d27, q15, #8
+        vst1.8          {d24}, [r0, :64], r1
+        vst1.8          {d25}, [r6, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d26}, [r0, :64], r1
+        vst1.8          {d27}, [r6, :64], r1
+        bgt             8b
+        pop             {r4-r8, pc}
+160:
+320:
+640:
+        vpush           {q4-q7}
+        sub             r2,  r2,  #4
+        mov             r7,  #-4
+        // Set up pointers for four rows in parallel; r0, r6, r5, lr
+        add             r5,  r0,  r1
+        add             lr,  r6,  r1
+        lsl             r1,  r1,  #1
+        sub             r1,  r1,  r3
+        mov             r12, r3
+
+1:
+        vld4.8          {d8[], d10[], d12[], d14[]},  [r2, :32], r7 // left
+        vsubl.u8        q4,  d8,  d4  // left-right
+        vsubl.u8        q5,  d10, d4
+        vsubl.u8        q6,  d12, d4
+        vsubl.u8        q7,  d14, d4
+2:
+        vld1.8          {q1}, [r8, :128]! // weights_hor
+        vshll.i8        q8,  d4,  #8  // right*256
+        vshll.i8        q9,  d4,  #8
+        vshll.i8        q10, d4,  #8
+        vshll.i8        q11, d4,  #8
+        vmovl.u8        q0,  d2       // weights_hor
+        vmovl.u8        q1,  d3
+        vshll.i8        q12, d4,  #8
+        vshll.i8        q13, d4,  #8
+        vshll.i8        q14, d4,  #8
+        vshll.i8        q15, d4,  #8
+        vmla.i16        q8,  q7,  q0  // right*256  + (left-right)*weights_hor
+        vmla.i16        q9,  q7,  q1  // (left flipped)
+        vmla.i16        q10, q6,  q0
+        vmla.i16        q11, q6,  q1
+        vmla.i16        q12, q5,  q0
+        vmla.i16        q13, q5,  q1
+        vmla.i16        q14, q4,  q0
+        vmla.i16        q15, q4,  q1
+        vrshrn.i16      d16, q8,  #8
+        vrshrn.i16      d17, q9,  #8
+        vrshrn.i16      d18, q10, #8
+        vrshrn.i16      d19, q11, #8
+        vrshrn.i16      d20, q12, #8
+        vrshrn.i16      d21, q13, #8
+        vrshrn.i16      d22, q14, #8
+        vrshrn.i16      d23, q15, #8
+        subs            r3,  r3,  #16
+        vst1.8          {q8},  [r0, :128]!
+        vst1.8          {q9},  [r6, :128]!
+        vst1.8          {q10}, [r5, :128]!
+        vst1.8          {q11}, [lr, :128]!
+        bgt             2b
+        subs            r4,  r4,  #4
+        ble             9f
+        sub             r8,  r8,  r12
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        add             r5,  r5,  r1
+        add             lr,  lr,  r1
+        mov             r3,  r12
+        b               1b
+9:
+        vpop            {q4-q7}
+        pop             {r4-r8, pc}
+endfunc
+
+// void ipred_filter_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int filt_idx,
+//                             const int max_width, const int max_height);
+function ipred_filter_8bpc_neon, export=1
+        push            {r4-r8, lr}
+        movw            r12, #511
+        ldrd            r4,  r5,  [sp, #24]
+        and             r5,  r5,  r12 // 511
+        movrel          r6,  X(filter_intra_taps)
+        lsl             r5,  r5,  #6
+        add             r6,  r6,  r5
+        vld1.8          {d20, d21, d22, d23}, [r6, :128]!
+        clz             lr,  r3
+        adr             r5,  L(ipred_filter_tbl)
+        vld1.8          {d27, d28, d29}, [r6, :64]
+        sub             lr,  lr,  #26
+        ldr             lr,  [r5, lr, lsl #2]
+        vmovl.s8        q8,  d20
+        vmovl.s8        q9,  d21
+        add             r5,  r5,  lr
+        vmovl.s8        q10, d22
+        vmovl.s8        q11, d23
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        vmovl.s8        q12, d27
+        vmovl.s8        q13, d28
+        vmovl.s8        q14, d29
+        add             r8,  r2,  #1
+        sub             r2,  r2,  #2
+        mov             r7,  #-2
+        bx              r5
+
+        .align 2
+L(ipred_filter_tbl):
+        .word 320f - L(ipred_filter_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_filter_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_filter_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_filter_tbl) + CONFIG_THUMB
+
+40:
+        vld1.32         {d0[]}, [r8]     // top (0-3)
+        vmovl.u8        q0,  d0          // top (0-3)
+4:
+        vld1.32         {d2[]}, [r2], r7 // left (0-1) + topleft (2)
+        vmul.i16        q2,  q9,  d0[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q2,  q10, d0[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q2,  q11, d0[2]  // p3(top[2]) * filter(3)
+        vmovl.u8        q1,  d2          // left (0-1) + topleft (2)
+        vmla.i16        q2,  q12, d0[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q2,  q8,  d2[2]  // p0(topleft) * filter(0)
+        vmla.i16        q2,  q13, d2[1]  // p5(left[0]) * filter(5)
+        vmla.i16        q2,  q14, d2[0]  // p6(left[1]) * filter(6)
+        vqrshrun.s16    d4,  q2,  #4
+        subs            r4,  r4,  #2
+        vst1.32         {d4[0]}, [r0, :32], r1
+        vmovl.u8        q0,  d4
+        vst1.32         {d4[1]}, [r6, :32], r1
+        vmov            d0,  d1          // move top from [4-7] to [0-3]
+        bgt             4b
+        pop             {r4-r8, pc}
+80:
+        vld1.8          {d0},  [r8]      // top (0-7)
+        vmovl.u8        q0,  d0          // top (0-7)
+8:
+        vld1.32         {d2[]}, [r2], r7 // left (0-1) + topleft (2)
+        vmul.i16        q2,  q9,  d0[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q2,  q10, d0[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q2,  q11, d0[2]  // p3(top[2]) * filter(3)
+        vmovl.u8        q1,  d2          // left (0-1) + topleft (2)
+        vmla.i16        q2,  q12, d0[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q2,  q8,  d2[2]  // p0(topleft) * filter(0)
+        vmla.i16        q2,  q13, d2[1]  // p5(left[0]) * filter(5)
+        vmla.i16        q2,  q14, d2[0]  // p6(left[1]) * filter(6)
+        vmul.i16        q3,  q9,  d1[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q3,  q10, d1[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q3,  q11, d1[2]  // p3(top[2]) * filter(3)
+        vqrshrun.s16    d4,  q2,  #4
+        vmovl.u8        q1,  d4          // first block, in 16 bit
+        vmla.i16        q3,  q12, d1[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q3,  q8,  d0[3]  // p0(topleft) * filter(0)
+        vmla.i16        q3,  q13, d2[3]  // p5(left[0]) * filter(5)
+        vmla.i16        q3,  q14, d3[3]  // p6(left[1]) * filter(6)
+        vqrshrun.s16    d5,  q3,  #4
+        vzip.32         d4,  d5
+        subs            r4,  r4,  #2
+        vst1.8          {d4}, [r0, :64], r1
+        vmovl.u8        q0,  d5
+        vst1.8          {d5}, [r6, :64], r1
+        bgt             8b
+        pop             {r4-r8, pc}
+160:
+320:
+        vpush           {q4-q5}
+        sub             r1,  r1,  r3
+        mov             lr,  r3
+
+1:
+        vld1.32         {d0[]}, [r2], r7 // left (0-1) + topleft (2)
+        vmovl.u8        q0,  d0          // left (0-1) + topleft (2)
+2:
+        vld1.8          {q2}, [r8]!      // top(0-15)
+        vmul.i16        q3,  q8,  d0[2]  // p0(topleft) * filter(0)
+        vmla.i16        q3,  q13, d0[1]  // p5(left[0]) * filter(5)
+        vmovl.u8        q1,  d4          // top(0-7)
+        vmovl.u8        q2,  d5          // top(8-15)
+        vmla.i16        q3,  q14, d0[0]  // p6(left[1]) * filter(6)
+        vmla.i16        q3,  q9,  d2[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q3,  q10, d2[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q3,  q11, d2[2]  // p3(top[2]) * filter(3)
+        vmla.i16        q3,  q12, d2[3]  // p4(top[3]) * filter(4)
+
+        vmul.i16        q4,  q9,  d3[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q4,  q10, d3[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q4,  q11, d3[2]  // p3(top[2]) * filter(3)
+        vqrshrun.s16    d6,  q3,  #4
+        vmovl.u8        q0,  d6          // first block, in 16 bit
+        vmla.i16        q4,  q12, d3[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q4,  q8,  d2[3]  // p0(topleft) * filter(0)
+        vmla.i16        q4,  q13, d0[3]  // p5(left[0]) * filter(5)
+        vmla.i16        q4,  q14, d1[3]  // p6(left[1]) * filter(6)
+
+        vmul.i16        q5,  q9,  d4[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q5,  q10, d4[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q5,  q11, d4[2]  // p3(top[2]) * filter(3)
+        vqrshrun.s16    d7,  q4,  #4
+        vmovl.u8        q0,  d7          // second block, in 16 bit
+        vmla.i16        q5,  q12, d4[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q5,  q8,  d3[3]  // p0(topleft) * filter(0)
+        vmla.i16        q5,  q13, d0[3]  // p5(left[0]) * filter(5)
+        vmla.i16        q5,  q14, d1[3]  // p6(left[1]) * filter(6)
+
+        vmul.i16        q15, q9,  d5[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q15, q10, d5[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q15, q11, d5[2]  // p3(top[2]) * filter(3)
+        vqrshrun.s16    d8,  q5,  #4
+        vmovl.u8        q0,  d8          // third block, in 16 bit
+        vmov.u8         r12, d5[6]
+        vmla.i16        q15, q12, d5[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q15, q8,  d4[3]  // p0(topleft) * filter(0)
+        vmla.i16        q15, q13, d0[3]  // p5(left[0]) * filter(5)
+        vmla.i16        q15, q14, d1[3]  // p6(left[1]) * filter(6)
+        vmov.8          d0[4], r12
+
+        subs            r3,  r3,  #16
+        vqrshrun.s16    d9,  q15, #4
+
+        vst4.32         {d6[0], d7[0], d8[0], d9[0]}, [r0, :128]!
+        vst4.32         {d6[1], d7[1], d8[1], d9[1]}, [r6, :128]!
+        ble             8f
+        vmov.u8         r12, d9[7]
+        vmov.8          d0[0], r12
+        vmov.u8         r12, d9[3]
+        vmov.8          d0[2], r12
+        b               2b
+8:
+        subs            r4,  r4,  #2
+
+        ble             9f
+        sub             r8,  r6,  lr
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        mov             r3,  lr
+        b               1b
+9:
+        vpop            {q4-q5}
+        pop             {r4-r8, pc}
+endfunc
+
+// void pal_pred_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const pal, const uint8_t *idx,
+//                         const int w, const int h);
+function pal_pred_8bpc_neon, export=1
+        push            {r4-r5, lr}
+        ldrd            r4,  r5,  [sp, #12]
+        vld1.8          {d0}, [r2, :64]
+        clz             lr,  r4
+        adr             r12, L(pal_pred_tbl)
+        sub             lr,  lr,  #25
+        vmov.i8         q15, #7
+        ldr             lr,  [r12, lr, lsl #2]
+        add             r12, r12, lr
+        add             r2,  r0,  r1
+        bx              r12
+
+        .align 2
+L(pal_pred_tbl):
+        .word 640f - L(pal_pred_tbl) + CONFIG_THUMB
+        .word 320f - L(pal_pred_tbl) + CONFIG_THUMB
+        .word 160f - L(pal_pred_tbl) + CONFIG_THUMB
+        .word 80f  - L(pal_pred_tbl) + CONFIG_THUMB
+        .word 40f  - L(pal_pred_tbl) + CONFIG_THUMB
+
+40:
+        lsl             r1,  r1,  #1
+4:
+        vld1.8          {d2}, [r3, :64]!
+        subs            r5,  r5,  #4
+        vshr.u8         d3,  d2,  #4
+        vand.u8         d2,  d2,  d30
+        vzip.8          d2,  d3
+        vtbl.8          d2, {d0}, d2
+        vtbl.8          d3, {d0}, d3
+        vst1.32         {d2[0]}, [r0, :32], r1
+        vst1.32         {d2[1]}, [r2, :32], r1
+        vst1.32         {d3[0]}, [r0, :32], r1
+        vst1.32         {d3[1]}, [r2, :32], r1
+        bgt             4b
+        pop             {r4-r5, pc}
+80:
+        lsl             r1,  r1,  #1
+8:
+        vld1.8          {q1}, [r3, :64]!
+        subs            r5,  r5,  #4
+        vshr.u8         q2,  q1,  #4
+        vand.u8         q1,  q1,  q15
+        vzip.8          q1,  q2
+        vtbl.8          d2, {d0}, d2
+        vtbl.8          d3, {d0}, d3
+        vst1.8          {d2}, [r0, :64], r1
+        vtbl.8          d4, {d0}, d4
+        vst1.8          {d3}, [r2, :64], r1
+        vtbl.8          d5, {d0}, d5
+        vst1.8          {d4}, [r0, :64], r1
+        vst1.8          {d5}, [r2, :64], r1
+        bgt             8b
+        pop             {r4-r5, pc}
+160:
+        lsl             r1,  r1,  #1
+16:
+        vld1.8          {q10, q11}, [r3, :64]!
+        subs            r5,  r5,  #4
+        vand.u8         q8,  q10, q15
+        vshr.u8         q9,  q10, #4
+        vand.u8         q10, q11, q15
+        vshr.u8         q11, q11, #4
+        vzip.8          q8,  q9
+        vzip.8          q10, q11
+        vtbl.8          d16, {d0}, d16
+        vtbl.8          d17, {d0}, d17
+        vtbl.8          d18, {d0}, d18
+        vtbl.8          d19, {d0}, d19
+        vtbl.8          d20, {d0}, d20
+        vtbl.8          d21, {d0}, d21
+        vst1.8          {q8},  [r0, :128], r1
+        vtbl.8          d22, {d0}, d22
+        vst1.8          {q9},  [r2, :128], r1
+        vtbl.8          d23, {d0}, d23
+        vst1.8          {q10}, [r0, :128], r1
+        vst1.8          {q11}, [r2, :128], r1
+        bgt             16b
+        pop             {r4-r5, pc}
+320:
+        lsl             r1,  r1,  #1
+32:
+        vld1.8          {q10, q11}, [r3, :64]!
+        subs            r5,  r5,  #2
+        vand.u8         q8,  q10, q15
+        vshr.u8         q9,  q10, #4
+        vand.u8         q10, q11, q15
+        vshr.u8         q11, q11, #4
+        vzip.8          q8,  q9
+        vzip.8          q10, q11
+        vtbl.8          d16, {d0}, d16
+        vtbl.8          d17, {d0}, d17
+        vtbl.8          d18, {d0}, d18
+        vtbl.8          d19, {d0}, d19
+        vtbl.8          d20, {d0}, d20
+        vtbl.8          d21, {d0}, d21
+        vst1.8          {q8,  q9},  [r0, :128], r1
+        vtbl.8          d22, {d0}, d22
+        vtbl.8          d23, {d0}, d23
+        vst1.8          {q10, q11}, [r2, :128], r1
+        bgt             32b
+        pop             {r4-r5, pc}
+640:
+        sub             r1,  r1,  #32
+64:
+        vld1.8          {q10, q11}, [r3, :64]!
+        subs            r5,  r5,  #1
+        vand.u8         q8,  q10, q15
+        vshr.u8         q9,  q10, #4
+        vand.u8         q10, q11, q15
+        vshr.u8         q11, q11, #4
+        vzip.8          q8,  q9
+        vzip.8          q10, q11
+        vtbl.8          d16, {d0}, d16
+        vtbl.8          d17, {d0}, d17
+        vtbl.8          d18, {d0}, d18
+        vtbl.8          d19, {d0}, d19
+        vtbl.8          d20, {d0}, d20
+        vtbl.8          d21, {d0}, d21
+        vst1.8          {q8,  q9},  [r0, :128]!
+        vtbl.8          d22, {d0}, d22
+        vtbl.8          d23, {d0}, d23
+        vst1.8          {q10, q11}, [r0, :128], r1
+        bgt             64b
+        pop             {r4-r5, pc}
+endfunc
+
+// void ipred_cfl_128_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height,
+//                              const int16_t *ac, const int alpha);
+function ipred_cfl_128_8bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        clz             lr,  r3
+        adr             r12, L(ipred_cfl_128_tbl)
+        sub             lr,  lr,  #26
+        ldr             lr,  [r12, lr, lsl #2]
+        vmov.i16        q0,  #128     // dc
+        vdup.i16        q1,  r6       // alpha
+        add             r12, r12, lr
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r12
+
+        .align 2
+L(ipred_cfl_128_tbl):
+L(ipred_cfl_splat_tbl):
+        .word L(ipred_cfl_splat_w16) - L(ipred_cfl_128_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_splat_w16) - L(ipred_cfl_128_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_splat_w8)  - L(ipred_cfl_128_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_splat_w4)  - L(ipred_cfl_128_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_splat_w4):
+        vld1.16         {q2, q3}, [r5, :128]!
+        vmul.i16        q2,  q2,  q1  // diff = ac * alpha
+        vmul.i16        q3,  q3,  q1
+        vshr.s16        q8,  q2,  #15 // sign = diff >> 15
+        vshr.s16        q9,  q3,  #15
+        vadd.i16        q2,  q2,  q8  // diff + sign
+        vadd.i16        q3,  q3,  q9
+        vrshr.s16       q2,  q2,  #6  // (diff + sign + 32) >> 6 = apply_sign()
+        vrshr.s16       q3,  q3,  #6
+        vadd.i16        q2,  q2,  q0  // dc + apply_sign()
+        vadd.i16        q3,  q3,  q0
+        vqmovun.s16     d4,  q2       // iclip_pixel(dc + apply_sign())
+        vqmovun.s16     d5,  q3
+        vst1.32         {d4[0]}, [r0, :32], r1
+        vst1.32         {d4[1]}, [r6, :32], r1
+        subs            r4,  r4,  #4
+        vst1.32         {d5[0]}, [r0, :32], r1
+        vst1.32         {d5[1]}, [r6, :32], r1
+        bgt             L(ipred_cfl_splat_w4)
+        pop             {r4-r8, pc}
+L(ipred_cfl_splat_w8):
+        vld1.16         {q8, q9},   [r5, :128]!
+        vld1.16         {q10, q11}, [r5, :128]!
+        vmul.i16        q8,  q8,  q1  // diff = ac * alpha
+        vmul.i16        q9,  q9,  q1
+        vmul.i16        q10, q10, q1
+        vmul.i16        q11, q11, q1
+        vshr.s16        q12, q8,  #15 // sign = diff >> 15
+        vshr.s16        q13, q9,  #15
+        vshr.s16        q14, q10, #15
+        vshr.s16        q15, q11, #15
+        vadd.i16        q8,  q8,  q12 // diff + sign
+        vadd.i16        q9,  q9,  q13
+        vadd.i16        q10, q10, q14
+        vadd.i16        q11, q11, q15
+        vrshr.s16       q8,  q8,  #6  // (diff + sign + 32) >> 6 = apply_sign()
+        vrshr.s16       q9,  q9,  #6
+        vrshr.s16       q10, q10, #6
+        vrshr.s16       q11, q11, #6
+        vadd.i16        q8,  q8,  q0  // dc + apply_sign()
+        vadd.i16        q9,  q9,  q0
+        vadd.i16        q10, q10, q0
+        vadd.i16        q11, q11, q0
+        vqmovun.s16     d16, q8       // iclip_pixel(dc + apply_sign())
+        vqmovun.s16     d17, q9
+        vqmovun.s16     d18, q10
+        vqmovun.s16     d19, q11
+        vst1.8          {d16}, [r0, :64], r1
+        vst1.8          {d17}, [r6, :64], r1
+        subs            r4,  r4,  #4
+        vst1.8          {d18}, [r0, :64], r1
+        vst1.8          {d19}, [r6, :64], r1
+        bgt             L(ipred_cfl_splat_w8)
+        pop             {r4-r8, pc}
+L(ipred_cfl_splat_w16):
+        add             r12, r5,  r3, lsl #1
+        sub             r1,  r1,  r3
+        mov             lr,  r3
+1:
+        vld1.16         {q8, q9},   [r5, :128]!
+        vmul.i16        q8,  q8,  q1  // diff = ac * alpha
+        vld1.16         {q10, q11}, [r12, :128]!
+        vmul.i16        q9,  q9,  q1
+        vmul.i16        q10, q10, q1
+        vmul.i16        q11, q11, q1
+        vshr.s16        q12, q8,  #15 // sign = diff >> 15
+        vshr.s16        q13, q9,  #15
+        vshr.s16        q14, q10, #15
+        vshr.s16        q15, q11, #15
+        vadd.i16        q8,  q8,  q12 // diff + sign
+        vadd.i16        q9,  q9,  q13
+        vadd.i16        q10, q10, q14
+        vadd.i16        q11, q11, q15
+        vrshr.s16       q8,  q8,  #6  // (diff + sign + 32) >> 6 = apply_sign()
+        vrshr.s16       q9,  q9,  #6
+        vrshr.s16       q10, q10, #6
+        vrshr.s16       q11, q11, #6
+        vadd.i16        q8,  q8,  q0  // dc + apply_sign()
+        vadd.i16        q9,  q9,  q0
+        vadd.i16        q10, q10, q0
+        vadd.i16        q11, q11, q0
+        vqmovun.s16     d16, q8       // iclip_pixel(dc + apply_sign())
+        vqmovun.s16     d17, q9
+        vqmovun.s16     d18, q10
+        vqmovun.s16     d19, q11
+        subs            r3,  r3,  #16
+        vst1.16         {q8}, [r0, :128]!
+        vst1.16         {q9}, [r6, :128]!
+        bgt             1b
+        subs            r4,  r4,  #2
+        add             r5,  r5,  lr, lsl #1
+        add             r12, r12, lr, lsl #1
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        mov             r3,  lr
+        bgt             1b
+        pop             {r4-r8, pc}
+endfunc
+
+// void ipred_cfl_top_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height,
+//                              const int16_t *ac, const int alpha);
+function ipred_cfl_top_8bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        clz             lr,  r3
+        adr             r12, L(ipred_cfl_top_tbl)
+        sub             lr,  lr,  #26
+        ldr             lr,  [r12, lr, lsl #2]
+        vdup.16         q1,  r6   // alpha
+        add             r2,  r2,  #1
+        add             r12, r12, lr
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r12
+
+        .align 2
+L(ipred_cfl_top_tbl):
+        .word 32f - L(ipred_cfl_top_tbl) + CONFIG_THUMB
+        .word 16f - L(ipred_cfl_top_tbl) + CONFIG_THUMB
+        .word 8f  - L(ipred_cfl_top_tbl) + CONFIG_THUMB
+        .word 4f  - L(ipred_cfl_top_tbl) + CONFIG_THUMB
+
+4:
+        vld1.32         {d0[]}, [r2]
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshr.u16       d0,  d0,  #2
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w4)
+8:
+        vld1.8          {d0}, [r2]
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshr.u16       d0,  d0,  #3
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w8)
+16:
+        vld1.8          {q0}, [r2]
+        vaddl.u8        q0,  d0,  d1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshr.u16       d0,  d0,  #4
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w16)
+32:
+        vld1.8          {q2, q3}, [r2]
+        vaddl.u8        q2,  d4,  d5
+        vaddl.u8        q3,  d6,  d7
+        vadd.u16        q0,  q2,  q3
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshr.u16       d0,  d0,  #5
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w16)
+endfunc
+
+// void ipred_cfl_left_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height,
+//                               const int16_t *ac, const int alpha);
+function ipred_cfl_left_8bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        sub             r2,  r2,  r4
+        clz             lr,  r3
+        clz             r8,  r4
+        adr             r12, L(ipred_cfl_splat_tbl)
+        adr             r7,  L(ipred_cfl_left_tbl)
+        sub             lr,  lr,  #26
+        sub             r8,  r8,  #26
+        ldr             lr,  [r12, lr, lsl #2]
+        ldr             r8,  [r7,  r8, lsl #2]
+        vdup.16         q1,  r6   // alpha
+        add             r12, r12, lr
+        add             r7,  r7,  r8
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r7
+
+        .align 2
+L(ipred_cfl_left_tbl):
+        .word L(ipred_cfl_left_h32) - L(ipred_cfl_left_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_left_h16) - L(ipred_cfl_left_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_left_h8)  - L(ipred_cfl_left_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_left_h4)  - L(ipred_cfl_left_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_left_h4):
+        vld1.32         {d0[]}, [r2, :32]
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshr.u16       d0,  d0,  #2
+        vdup.16         q0,  d0[0]
+        bx              r12
+
+L(ipred_cfl_left_h8):
+        vld1.8          {d0}, [r2, :64]
+        vpaddl.u8       d0,  d0
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshr.u16       d0,  d0,  #3
+        vdup.16         q0,  d0[0]
+        bx              r12
+
+L(ipred_cfl_left_h16):
+        vld1.8          {q0}, [r2, :128]
+        vaddl.u8        q0,  d0,  d1
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshr.u16       d0,  d0,  #4
+        vdup.16         q0,  d0[0]
+        bx              r12
+
+L(ipred_cfl_left_h32):
+        vld1.8          {q2, q3}, [r2, :128]
+        vaddl.u8        q2,  d4,  d5
+        vaddl.u8        q3,  d6,  d7
+        vadd.u16        q0,  q2,  q3
+        vadd.u16        d0,  d0,  d1
+        vpadd.u16       d0,  d0
+        vpadd.u16       d0,  d0
+        vrshr.u16       d0,  d0,  #5
+        vdup.16         q0,  d0[0]
+        bx              r12
+endfunc
+
+// void ipred_cfl_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                          const pixel *const topleft,
+//                          const int width, const int height,
+//                          const int16_t *ac, const int alpha);
+function ipred_cfl_8bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        sub             r2,  r2,  r4
+        add             r8,  r3,  r4  // width + height
+        vdup.16         q1,  r6       // alpha
+        clz             lr,  r3
+        clz             r6,  r4
+        vdup.16         d16, r8       // width + height
+        adr             r7,  L(ipred_cfl_tbl)
+        rbit            r8,  r8       // rbit(width + height)
+        sub             lr,  lr,  #22 // 26 leading bits, minus table offset 4
+        sub             r6,  r6,  #26
+        clz             r8,  r8       // ctz(width + height)
+        ldr             lr,  [r7, lr, lsl #2]
+        ldr             r6,  [r7, r6, lsl #2]
+        neg             r8,  r8       // -ctz(width + height)
+        add             r12, r7,  lr
+        add             r7,  r7,  r6
+        vshr.u16        d16, d16, #1  // (width + height) >> 1
+        vdup.16         d17, r8       // -ctz(width + height)
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r7
+
+        .align 2
+L(ipred_cfl_tbl):
+        .word L(ipred_cfl_h32) - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_h16) - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_h8)  - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_h4)  - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_w32) - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_w16) - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_w8)  - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_w4)  - L(ipred_cfl_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_h4):
+        vld1.32         {d0[]}, [r2, :32]!
+        vpaddl.u8       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.i16       d0,  d0
+        bx              r12
+L(ipred_cfl_w4):
+        vld1.32         {d1[]},  [r2]
+        vadd.i16        d0,  d0,  d16
+        vpaddl.u8       d1,  d1
+        vpadd.u16       d1,  d1
+        cmp             r4,  #4
+        vadd.i16        d0,  d0,  d1
+        vshl.u16        d0,  d0,  d17
+        beq             1f
+        // h = 8/16
+        movw            lr,  #(0x3334/2)
+        movw            r8,  #(0x5556/2)
+        cmp             r4,  #16
+        it              ne
+        movne           lr,  r8
+        vdup.16         d18, lr
+        vqdmulh.s16     d0,  d0,  d18
+1:
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w4)
+
+L(ipred_cfl_h8):
+        vld1.8          {d0}, [r2, :64]!
+        vpaddl.u8       d0,  d0
+        vpadd.i16       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.i16       d0,  d0
+        bx              r12
+L(ipred_cfl_w8):
+        vld1.8          {d1}, [r2]
+        vadd.i16        d0,  d0,  d16
+        vpaddl.u8       d1,  d1
+        vpadd.i16       d1,  d1
+        vpadd.i16       d1,  d1
+        cmp             r4,  #8
+        vadd.i16        d0,  d0,  d1
+        vshl.u16        d0,  d0,  d17
+        beq             1f
+        // h = 4/16/32
+        cmp             r4,  #32
+        movw            lr,  #(0x3334/2)
+        movw            r8,  #(0x5556/2)
+        it              ne
+        movne           lr,  r8
+        vdup.16         d18, lr
+        vqdmulh.s16     d0,  d0,  d18
+1:
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w8)
+
+L(ipred_cfl_h16):
+        vld1.8          {q0}, [r2, :128]!
+        vaddl.u8        q0,  d0,  d1
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.i16       d0,  d0
+        bx              r12
+L(ipred_cfl_w16):
+        vld1.8          {q2}, [r2]
+        vadd.i16        d0,  d0,  d16
+        vaddl.u8        q2,  d4,  d5
+        vadd.i16        d4,  d4,  d5
+        vpadd.i16       d4,  d4
+        vpadd.i16       d4,  d4
+        cmp             r4,  #16
+        vadd.i16        d0,  d0,  d4
+        vshl.u16        d0,  d0,  d17
+        beq             1f
+        // h = 4/8/32/64
+        tst             r4,  #(32+16+8)  // 16 added to make a consecutive bitmask
+        movw            lr,  #(0x3334/2)
+        movw            r8,  #(0x5556/2)
+        it              ne
+        movne           lr,  r8
+        vdup.16         d18, lr
+        vqdmulh.s16     d0,  d0,  d18
+1:
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w16)
+
+L(ipred_cfl_h32):
+        vld1.8          {q2, q3}, [r2, :128]!
+        vaddl.u8        q2,  d4,  d5
+        vaddl.u8        q3,  d6,  d7
+        vadd.i16        q0,  q2,  q3
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0
+        add             r2,  r2,  #1
+        vpadd.i16       d0,  d0
+        bx              r12
+L(ipred_cfl_w32):
+        vld1.8          {q2, q3},  [r2]
+        vadd.i16        d0,  d0,  d16
+        vaddl.u8        q2,  d4,  d5
+        vaddl.u8        q3,  d6,  d7
+        vadd.i16        q2,  q2,  q3
+        vadd.i16        d4,  d4,  d5
+        vpadd.i16       d4,  d4
+        vpadd.i16       d4,  d4
+        cmp             r4,  #32
+        vadd.i16        d0,  d0,  d4
+        vshl.u16        d0,  d0,  d17
+        beq             1f
+        // h = 8/16/64
+        cmp             r4,  #8
+        movw            lr,  #(0x3334/2)
+        movw            r8,  #(0x5556/2)
+        it              ne
+        movne           lr,  r8
+        vdup.16         d18, lr
+        vqdmulh.s16     d0,  d0,  d18
+1:
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w16)
+endfunc
+
+// void cfl_ac_420_8bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                           const ptrdiff_t stride, const int w_pad,
+//                           const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_420_8bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        clz             r8,  r5
+        lsl             r4,  r4,  #2
+        adr             r7,  L(ipred_cfl_ac_420_tbl)
+        sub             r8,  r8,  #27
+        ldr             r8,  [r7, r8, lsl #2]
+        vmov.i16        q8,  #0
+        vmov.i16        q9,  #0
+        vmov.i16        q10, #0
+        vmov.i16        q11, #0
+        add             r7,  r7,  r8
+        sub             r8,  r6,  r4  // height - h_pad
+        rbit            lr,  r5       // rbit(width)
+        rbit            r12, r6       // rbit(height)
+        clz             lr,  lr       // ctz(width)
+        clz             r12, r12      // ctz(height)
+        add             lr,  lr,  r12 // log2sz
+        add             r12, r1,  r2
+        vdup.32         d31, lr
+        lsl             r2,  r2,  #1
+        vneg.s32        d31, d31      // -log2sz
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_420_tbl):
+        .word L(ipred_cfl_ac_420_w16) - L(ipred_cfl_ac_420_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w8)  - L(ipred_cfl_ac_420_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w4)  - L(ipred_cfl_ac_420_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_420_w4):
+1:      // Copy and subsample input
+        vld1.8          {d0}, [r1,  :64], r2
+        vld1.8          {d2}, [r12, :64], r2
+        vld1.8          {d1}, [r1,  :64], r2
+        vld1.8          {d3}, [r12, :64], r2
+        vpaddl.u8       q0,  q0
+        vpaddl.u8       q1,  q1
+        vadd.i16        q0,  q0,  q1
+        vshl.i16        q0,  q0,  #1
+        subs            r8,  r8,  #2
+        vst1.16         {q0}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        bgt             1b
+        cmp             r4,  #0
+        vmov            d0,  d1
+        vmov            d2,  d1
+        vmov            d3,  d1
+L(ipred_cfl_ac_420_w4_hpad):
+        beq             3f // This assumes that all callers already did "cmp r4, #0"
+2:      // Vertical padding (h_pad > 0)
+        subs            r4,  r4,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q8,  q8,  q1
+        bgt             2b
+3:
+L(ipred_cfl_ac_420_w4_calc_subtract_dc):
+        // Aggregate the sums
+        vadd.i16        q0,  q8,  q9
+        vadd.i16        q1,  q10, q11
+        vpaddl.u16      q0,  q0
+        vpaddl.u16      q1,  q1
+        vadd.i32        q0,  q1
+        vadd.i32        d0,  d0,  d1
+        vpadd.i32       d0,  d0,  d0  // sum
+        sub             r0,  r0,  r6, lsl #3
+        vrshl.u32       d16, d0,  d31 // (sum + (1 << (log2sz - 1))) >>= log2sz
+        vdup.16         q8,  d16[0]
+L(ipred_cfl_ac_420_w4_subtract_dc):
+6:      // Subtract dc from ac
+        vld1.16         {q0, q1}, [r0, :128]
+        subs            r6,  r6,  #4
+        vsub.i16        q0,  q0,  q8
+        vsub.i16        q1,  q1,  q8
+        vst1.16         {q0, q1}, [r0, :128]!
+        bgt             6b
+        pop             {r4-r8, pc}
+
+L(ipred_cfl_ac_420_w8):
+        cmp             r3,  #0
+        bne             L(ipred_cfl_ac_420_w8_wpad)
+1:      // Copy and subsample input, without padding
+        vld1.8          {q0}, [r1,  :128], r2
+        vld1.8          {q1}, [r12, :128], r2
+        vld1.8          {q2}, [r1,  :128], r2
+        vpaddl.u8       q0,  q0
+        vld1.8          {q3}, [r12, :128], r2
+        vpaddl.u8       q1,  q1
+        vpaddl.u8       q2,  q2
+        vpaddl.u8       q3,  q3
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        q2,  q2,  q3
+        vshl.i16        q0,  q0,  #1
+        vshl.i16        q1,  q2,  #1
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q1
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_420_w8_wpad):
+1:      // Copy and subsample input, padding 4
+        vld1.16         {d0}, [r1,  :64], r2
+        vld1.16         {d2}, [r12, :64], r2
+        vld1.16         {d1}, [r1,  :64], r2
+        vld1.16         {d3}, [r12, :64], r2
+        vpaddl.u8       q0,  q0
+        vpaddl.u8       q1,  q1
+        vadd.i16        q0,  q0,  q1
+        vshl.i16        q0,  q0,  #1
+        vdup.16         d3,  d1[3]
+        vmov            d2,  d1
+        vdup.16         d1,  d0[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q1
+
+L(ipred_cfl_ac_420_w8_hpad):
+        beq             3f // This assumes that all callers already did "cmp r4, #0"
+2:      // Vertical padding (h_pad > 0)
+        subs            r4,  r4,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q10, q10, q0
+        vadd.i16        q11, q11, q1
+        bgt             2b
+3:
+
+        // Double the height and reuse the w4 summing/subtracting
+        lsl             r6,  r6,  #1
+        b               L(ipred_cfl_ac_420_w4_calc_subtract_dc)
+
+L(ipred_cfl_ac_420_w16):
+        adr             r7,  L(ipred_cfl_ac_420_w16_tbl)
+        ldr             r3,  [r7, r3, lsl #2]
+        add             r7,  r7,  r3
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_420_w16_tbl):
+        .word L(ipred_cfl_ac_420_w16_wpad0) - L(ipred_cfl_ac_420_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w16_wpad1) - L(ipred_cfl_ac_420_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w16_wpad2) - L(ipred_cfl_ac_420_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w16_wpad3) - L(ipred_cfl_ac_420_w16_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_420_w16_wpad0):
+1:      // Copy and subsample input, without padding
+        vld1.8          {q0, q1},   [r1,  :128], r2
+        vld1.8          {q2, q3},   [r12, :128], r2
+        vpaddl.u8       q0,  q0
+        vld1.8          {q12, q13}, [r1,  :128], r2
+        vpaddl.u8       q1,  q1
+        vpaddl.u8       q2,  q2
+        vpaddl.u8       q3,  q3
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        q1,  q1,  q3
+        vld1.8          {q2, q3},   [r12, :128], r2
+        vpaddl.u8       q12, q12
+        vpaddl.u8       q13, q13
+        vpaddl.u8       q2,  q2
+        vpaddl.u8       q3,  q3
+        vadd.i16        q12, q12, q2
+        vadd.i16        q13, q13, q3
+        vshl.i16        q0,  q0,  #1
+        vshl.i16        q1,  q1,  #1
+        vshl.i16        q2,  q12, #1
+        vshl.i16        q3,  q13, #1
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad1):
+1:      // Copy and subsample input, padding 4
+        vldr            d2,    [r1,  #16]
+        vld1.8          {q0},  [r1,  :128], r2
+        vldr            d6,    [r12, #16]
+        vld1.8          {q2},  [r12, :128], r2
+        vpaddl.u8       d2,  d2
+        vldr            d26,   [r1,  #16]
+        vpaddl.u8       q0,  q0
+        vld1.8          {q12}, [r1,  :128], r2
+        vpaddl.u8       d6,  d6
+        vldr            d30,   [r12, #16]
+        vpaddl.u8       q2,  q2
+        vld1.8          {q14}, [r12, :128], r2
+        vpaddl.u8       d26, d26
+        vpaddl.u8       q12, q12
+        vpaddl.u8       d30, d30
+        vpaddl.u8       q14, q14
+        vadd.i16        d2,  d2,  d6
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        d26, d26, d30
+        vadd.i16        q12, q12, q14
+        vshl.i16        d2,  d2,  #1
+        vshl.i16        q0,  q0,  #1
+        vshl.i16        d6,  d26, #1
+        vshl.i16        q2,  q12, #1
+        vdup.16         d3,  d2[3]
+        vdup.16         d7,  d6[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad2):
+1:      // Copy and subsample input, padding 8
+        vld1.8          {q0}, [r1,  :128], r2
+        vld1.8          {q1}, [r12, :128], r2
+        vld1.8          {q2}, [r1,  :128], r2
+        vpaddl.u8       q0,  q0
+        vld1.8          {q3}, [r12, :128], r2
+        vpaddl.u8       q1,  q1
+        vpaddl.u8       q2,  q2
+        vpaddl.u8       q3,  q3
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        q2,  q2,  q3
+        vshl.i16        q0,  q0,  #1
+        vshl.i16        q2,  q2,  #1
+        vdup.16         q1,  d1[3]
+        vdup.16         q3,  d5[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad3):
+1:      // Copy and subsample input, padding 12
+        vld1.8          {d0}, [r1,  :64], r2
+        vld1.8          {d1}, [r12, :64], r2
+        vld1.8          {d4}, [r1,  :64], r2
+        vpaddl.u8       q0,  q0
+        vld1.8          {d5}, [r12, :64], r2
+        vpaddl.u8       q2,  q2
+        vadd.i16        d0,  d0,  d1
+        vadd.i16        d4,  d4,  d5
+        vshl.i16        d0,  d0,  #1
+        vshl.i16        d4,  d4,  #1
+        vdup.16         q1,  d0[3]
+        vdup.16         q3,  d4[3]
+        vdup.16         d1,  d0[3]
+        vdup.16         d5,  d4[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_hpad):
+        beq             3f // This assumes that all callers already did "cmp r4, #0"
+2:      // Vertical padding (h_pad > 0)
+        subs            r4,  r4,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             2b
+3:
+
+        // Quadruple the height and reuse the w4 summing/subtracting
+        lsl             r6,  r6,  #2
+        b               L(ipred_cfl_ac_420_w4_calc_subtract_dc)
+endfunc
+
+// void cfl_ac_422_8bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                           const ptrdiff_t stride, const int w_pad,
+//                           const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_422_8bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        clz             r8,  r5
+        lsl             r4,  r4,  #2
+        adr             r7,  L(ipred_cfl_ac_422_tbl)
+        sub             r8,  r8,  #27
+        ldr             r8,  [r7, r8, lsl #2]
+        vmov.i16        q8,  #0
+        vmov.i16        q9,  #0
+        vmov.i16        q10, #0
+        vmov.i16        q11, #0
+        add             r7,  r7,  r8
+        sub             r8,  r6,  r4  // height - h_pad
+        rbit            lr,  r5       // rbit(width)
+        rbit            r12, r6       // rbit(height)
+        clz             lr,  lr       // ctz(width)
+        clz             r12, r12      // ctz(height)
+        add             lr,  lr,  r12 // log2sz
+        add             r12, r1,  r2
+        vdup.32         d31, lr
+        lsl             r2,  r2,  #1
+        vneg.s32        d31, d31      // -log2sz
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_422_tbl):
+        .word L(ipred_cfl_ac_422_w16) - L(ipred_cfl_ac_422_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w8) - L(ipred_cfl_ac_422_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w4) - L(ipred_cfl_ac_422_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_422_w4):
+1:      // Copy and subsample input
+        vld1.8          {d0}, [r1,  :64], r2
+        vld1.8          {d1}, [r12, :64], r2
+        vld1.8          {d2}, [r1,  :64], r2
+        vld1.8          {d3}, [r12, :64], r2
+        vpaddl.u8       q0,  q0
+        vpaddl.u8       q1,  q1
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q1,  q1,  #2
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        bgt             1b
+        cmp             r4,  #0
+        vmov            d0,  d3
+        vmov            d1,  d3
+        vmov            d2,  d3
+        b               L(ipred_cfl_ac_420_w4_hpad)
+
+L(ipred_cfl_ac_422_w8):
+        cmp             r3,  #0
+        bne             L(ipred_cfl_ac_422_w8_wpad)
+1:      // Copy and subsample input, without padding
+        vld1.8          {q0}, [r1,  :128], r2
+        vld1.8          {q1}, [r12, :128], r2
+        vld1.8          {q2}, [r1,  :128], r2
+        vpaddl.u8       q0,  q0
+        vld1.8          {q3}, [r12, :128], r2
+        vpaddl.u8       q1,  q1
+        vpaddl.u8       q2,  q2
+        vpaddl.u8       q3,  q3
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q1,  q1,  #2
+        vshl.i16        q2,  q2,  #2
+        vshl.i16        q3,  q3,  #2
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q3
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_422_w8_wpad):
+1:      // Copy and subsample input, padding 4
+        vld1.8          {d0}, [r1,  :64], r2
+        vld1.8          {d1}, [r12, :64], r2
+        vld1.8          {d2}, [r1,  :64], r2
+        vld1.8          {d3}, [r12, :64], r2
+        vpaddl.u8       q0,  q0
+        vpaddl.u8       q1,  q1
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q1,  q1,  #2
+        vdup.16         d7,  d3[3]
+        vmov            d6,  d3
+        vdup.16         d5,  d2[3]
+        vmov            d4,  d2
+        vdup.16         d3,  d1[3]
+        vmov            d2,  d1
+        vdup.16         d1,  d0[3]
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q3
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_422_w16):
+        adr             r7,  L(ipred_cfl_ac_422_w16_tbl)
+        ldr             r3,  [r7, r3, lsl #2]
+        add             r7,  r7,  r3
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_422_w16_tbl):
+        .word L(ipred_cfl_ac_422_w16_wpad0) - L(ipred_cfl_ac_422_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w16_wpad1) - L(ipred_cfl_ac_422_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w16_wpad2) - L(ipred_cfl_ac_422_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w16_wpad3) - L(ipred_cfl_ac_422_w16_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_422_w16_wpad0):
+1:      // Copy and subsample input, without padding
+        vld1.8          {q0, q1}, [r1,  :128], r2
+        vld1.8          {q2, q3}, [r12, :128], r2
+        vpaddl.u8       q0,  q0
+        vpaddl.u8       q1,  q1
+        vpaddl.u8       q2,  q2
+        vpaddl.u8       q3,  q3
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q1,  q1,  #2
+        vshl.i16        q2,  q2,  #2
+        vshl.i16        q3,  q3,  #2
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad1):
+1:      // Copy and subsample input, padding 4
+        vldr            d2,   [r1,  #16]
+        vld1.8          {q0}, [r1,  :128], r2
+        vldr            d6,   [r12, #16]
+        vld1.8          {q2}, [r12, :128], r2
+        vpaddl.u8       d2,  d2
+        vpaddl.u8       q0,  q0
+        vpaddl.u8       d6,  d6
+        vpaddl.u8       q2,  q2
+        vshl.i16        d2,  d2,  #2
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        d6,  d6,  #2
+        vshl.i16        q2,  q2,  #2
+        vdup.16         d3,  d2[3]
+        vdup.16         d7,  d6[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad2):
+1:      // Copy and subsample input, padding 8
+        vld1.8          {q0}, [r1,  :128], r2
+        vld1.8          {q2}, [r12, :128], r2
+        vpaddl.u8       q0,  q0
+        vpaddl.u8       q2,  q2
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q2,  q2,  #2
+        vdup.16         q1,  d1[3]
+        vdup.16         q3,  d5[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad3):
+1:      // Copy and subsample input, padding 12
+        vld1.8          {d0}, [r1,  :64], r2
+        vld1.8          {d1}, [r12, :64], r2
+        vpaddl.u8       q0,  q0
+        vshl.i16        q0,  q0,  #2
+        vdup.16         q3,  d1[3]
+        vdup.16         q1,  d0[3]
+        vdup.16         d5,  d1[3]
+        vmov            d4,  d1
+        vdup.16         d1,  d0[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+endfunc
+
+// void cfl_ac_444_8bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                           const ptrdiff_t stride, const int w_pad,
+//                           const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_444_8bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        clz             r8,  r5
+        lsl             r4,  r4,  #2
+        adr             r7,  L(ipred_cfl_ac_444_tbl)
+        sub             r8,  r8,  #26
+        ldr             r8,  [r7, r8, lsl #2]
+        vmov.i16        q8,  #0
+        vmov.i16        q9,  #0
+        vmov.i16        q10, #0
+        vmov.i16        q11, #0
+        add             r7,  r7,  r8
+        sub             r8,  r6,  r4  // height - h_pad
+        rbit            lr,  r5       // rbit(width)
+        rbit            r12, r6       // rbit(height)
+        clz             lr,  lr       // ctz(width)
+        clz             r12, r12      // ctz(height)
+        add             lr,  lr,  r12 // log2sz
+        add             r12, r1,  r2
+        vdup.32         d31, lr
+        lsl             r2,  r2,  #1
+        vneg.s32        d31, d31      // -log2sz
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_444_tbl):
+        .word L(ipred_cfl_ac_444_w32) - L(ipred_cfl_ac_444_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w16) - L(ipred_cfl_ac_444_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w8)  - L(ipred_cfl_ac_444_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w4)  - L(ipred_cfl_ac_444_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_444_w4):
+1:      // Copy and expand input
+        vld1.32         {d0[]},  [r1,  :32], r2
+        vld1.32         {d0[1]}, [r12, :32], r2
+        vld1.32         {d2[]},  [r1,  :32], r2
+        vld1.32         {d2[1]}, [r12, :32], r2
+        vshll.u8        q0,  d0,  #3
+        vshll.u8        q1,  d2,  #3
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        bgt             1b
+        cmp             r4,  #0
+        vmov            d0,  d3
+        vmov            d1,  d3
+        vmov            d2,  d3
+        b               L(ipred_cfl_ac_420_w4_hpad)
+
+L(ipred_cfl_ac_444_w8):
+1:      // Copy and expand input
+        vld1.16         {d0}, [r1,  :64], r2
+        vld1.16         {d2}, [r12, :64], r2
+        vld1.16         {d4}, [r1,  :64], r2
+        vshll.u8        q0,  d0,  #3
+        vld1.16         {d6}, [r12, :64], r2
+        vshll.u8        q1,  d2,  #3
+        vshll.u8        q2,  d4,  #3
+        vshll.u8        q3,  d6,  #3
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q3
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_444_w16):
+        cmp             r3,  #0
+        bne             L(ipred_cfl_ac_444_w16_wpad)
+1:      // Copy and expand input, without padding
+        vld1.8          {q1}, [r1,  :128], r2
+        vld1.8          {q3}, [r12, :128], r2
+        vshll.u8        q0,  d2,  #3
+        vshll.u8        q1,  d3,  #3
+        vshll.u8        q2,  d6,  #3
+        vshll.u8        q3,  d7,  #3
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_444_w16_wpad):
+1:      // Copy and expand input, padding 8
+        vld1.8          {d0}, [r1,  :64], r2
+        vld1.8          {d4}, [r12, :64], r2
+        vshll.u8        q0,  d0,  #3
+        vshll.u8        q2,  d4,  #3
+        vdup.16         q1,  d1[3]
+        vdup.16         q3,  d5[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vst1.16         {q2, q3}, [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_444_w32):
+        adr             r7,  L(ipred_cfl_ac_444_w32_tbl)
+        ldr             r3,  [r7, r3, lsl #1] // (w3>>1) << 2
+        add             r7,  r7,  r3
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_444_w32_tbl):
+        .word L(ipred_cfl_ac_444_w32_wpad0) - L(ipred_cfl_ac_444_w32_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w32_wpad2) - L(ipred_cfl_ac_444_w32_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w32_wpad4) - L(ipred_cfl_ac_444_w32_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w32_wpad6) - L(ipred_cfl_ac_444_w32_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_444_w32_wpad0):
+1:      // Copy and expand input, without padding
+        vld1.8          {q2, q3},   [r1,  :128], r2
+        vld1.8          {q13, q14}, [r12, :128], r2
+        vshll.u8        q0,  d4,  #3
+        vshll.u8        q1,  d5,  #3
+        vshll.u8        q2,  d6,  #3
+        vshll.u8        q3,  d7,  #3
+        vshll.u8        q12, d26, #3
+        vshll.u8        q13, d27, #3
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vshll.u8        q0,  d28, #3
+        vshll.u8        q1,  d29, #3
+        vst1.16         {q2, q3},   [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        vst1.16         {q12, q13}, [r0, :128]!
+        vadd.i16        q8,  q8,  q12
+        vadd.i16        q9,  q9,  q13
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q10, q10, q0
+        vadd.i16        q11, q11, q1
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad2):
+1:      // Copy and expand input, padding 8
+        vldr            d4,    [r1,  #16]
+        vld1.8          {q1},  [r1,  :128], r2
+        vldr            d28,   [r12, #16]
+        vld1.8          {q13}, [r12, :128], r2
+        vshll.u8        q2,  d4,  #3
+        vshll.u8        q0,  d2,  #3
+        vshll.u8        q1,  d3,  #3
+        vshll.u8        q12, d26, #3
+        vshll.u8        q13, d27, #3
+        vdup.16         q3,  d5[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vshll.u8        q0,  d28, #3
+        vst1.16         {q2, q3},   [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        vdup.16         q1,  d1[3]
+        vst1.16         {q12, q13}, [r0, :128]!
+        vadd.i16        q8,  q8,  q12
+        vadd.i16        q9,  q9,  q13
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q10, q10, q0
+        vadd.i16        q11, q11, q1
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad4):
+1:      // Copy and expand input, padding 16
+        vld1.8          {q1},  [r1,  :128], r2
+        vld1.8          {q13}, [r12, :128], r2
+        vshll.u8        q0,  d2,  #3
+        vshll.u8        q1,  d3,  #3
+        vshll.u8        q12, d26, #3
+        vshll.u8        q13, d27, #3
+        vdup.16         q2,  d3[3]
+        vdup.16         q3,  d3[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vdup.16         q0,  d27[3]
+        vdup.16         q1,  d27[3]
+        vst1.16         {q2, q3},   [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        vst1.16         {q12, q13}, [r0, :128]!
+        vadd.i16        q8,  q8,  q12
+        vadd.i16        q9,  q9,  q13
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q10, q10, q0
+        vadd.i16        q11, q11, q1
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad6):
+1:      // Copy and expand input, padding 24
+        vld1.8          {d0},  [r1,  :64], r2
+        vld1.8          {d24}, [r12, :64], r2
+        vshll.u8        q0,  d0,  #3
+        vshll.u8        q12, d24, #3
+        subs            r8,  r8,  #2
+        vdup.16         q1,  d1[3]
+        vdup.16         q2,  d1[3]
+        vdup.16         q3,  d1[3]
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q8,  q8,  q0
+        vadd.i16        q9,  q9,  q1
+        vdup.16         q13, d25[3]
+        vdup.16         q0,  d25[3]
+        vdup.16         q1,  d25[3]
+        vst1.16         {q2, q3},   [r0, :128]!
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q3
+        vst1.16         {q12, q13}, [r0, :128]!
+        vadd.i16        q8,  q8,  q12
+        vadd.i16        q9,  q9,  q13
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q10, q10, q0
+        vadd.i16        q11, q11, q1
+        bgt             1b
+        cmp             r4,  #0
+
+L(ipred_cfl_ac_444_w32_hpad):
+        beq             3f // This assumes that all callers already did "cmp r4, #0"
+2:      // Vertical padding (h_pad > 0)
+        subs            r4,  r4,  #1
+        vst1.16         {q12, q13}, [r0, :128]!
+        vadd.i16        q8,  q8,  q12
+        vadd.i16        q9,  q9,  q13
+        vst1.16         {q0, q1},   [r0, :128]!
+        vadd.i16        q10, q10, q0
+        vadd.i16        q11, q11, q1
+        bgt             2b
+3:
+
+        //  Multiply the height by eight and reuse the w4 subtracting
+        lsl             r6,  r6,  #3
+        // Aggregate the sums, with wider intermediates earlier than in
+        // ipred_cfl_ac_420_w8_calc_subtract_dc.
+        vpaddl.u16      q0,  q8
+        vpaddl.u16      q1,  q9
+        vpaddl.u16      q2,  q10
+        vpaddl.u16      q3,  q11
+        vadd.i32        q0,  q0,  q1
+        vadd.i32        q2,  q2,  q3
+        vadd.i32        q0,  q0,  q2
+        vadd.i32        d0,  d0,  d1
+        vpadd.i32       d0,  d0,  d0  // sum
+        sub             r0,  r0,  r6, lsl #3
+        vrshl.u32       d16, d0,  d31 // (sum + (1 << (log2sz - 1))) >>= log2sz
+        vdup.16         q8,  d16[0]
+        b               L(ipred_cfl_ac_420_w4_subtract_dc)
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/ipred16.S b/media/libdav1d/src/src/arm/32/ipred16.S
new file mode 100644
index 0000000000..fa78049768
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/ipred16.S
@@ -0,0 +1,3276 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, B Krishnan Iyer
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// void ipred_dc_128_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int a,
+//                              const int max_width, const int max_height,
+//                              const int bitdepth_max);
+function ipred_dc_128_16bpc_neon, export=1
+        push            {r4, lr}
+        ldr             r4,  [sp, #8]
+        ldr             r12, [sp, #24]
+        clz             r3,  r3
+        adr             r2,  L(ipred_dc_128_tbl)
+        sub             r3,  r3,  #25
+        vdup.16         q0,  r12
+        ldr             r3,  [r2,  r3,  lsl #2]
+        add             r12, r0,  r1
+        vrshr.u16       q0,  q0,  #1
+        add             r2,  r2,  r3
+        lsl             r1,  r1,  #1
+        bx              r2
+
+        .align 2
+L(ipred_dc_128_tbl):
+        .word 640f - L(ipred_dc_128_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_dc_128_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_dc_128_tbl) + CONFIG_THUMB
+        .word 8f   - L(ipred_dc_128_tbl) + CONFIG_THUMB
+        .word 4f   - L(ipred_dc_128_tbl) + CONFIG_THUMB
+4:
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        bgt             4b
+        pop             {r4, pc}
+8:
+        vst1.16         {d0,  d1}, [r0,  :128], r1
+        vst1.16         {d0,  d1}, [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1}, [r0,  :128], r1
+        vst1.16         {d0,  d1}, [r12, :128], r1
+        bgt             8b
+        pop             {r4, pc}
+160:
+        vmov            q1,  q0
+16:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             16b
+        pop             {r4, pc}
+320:
+        vmov            q1,  q0
+        sub             r1,  r1,  #32
+32:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             32b
+        pop             {r4, pc}
+640:
+        vmov            q1,  q0
+        sub             r1,  r1,  #96
+64:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        subs            r4,  r4,  #2
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             64b
+        pop             {r4, pc}
+endfunc
+
+// void ipred_v_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const topleft,
+//                         const int width, const int height, const int a,
+//                         const int max_width, const int max_height);
+function ipred_v_16bpc_neon, export=1
+        push            {r4, lr}
+        ldr             lr,  [sp, #8]
+        clz             r3,  r3
+        adr             r4,  L(ipred_v_tbl)
+        sub             r3,  r3,  #25
+        ldr             r3,  [r4,  r3,  lsl #2]
+        add             r2,  r2,  #2
+        add             r4,  r4,  r3
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r4
+
+        .align 2
+L(ipred_v_tbl):
+        .word 640f - L(ipred_v_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_v_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_v_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_v_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_v_tbl) + CONFIG_THUMB
+
+40:
+        vld1.16         {d0}, [r2]
+4:
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        subs            lr,  lr,  #4
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        bgt             4b
+        pop             {r4, pc}
+80:
+        vld1.16         {q0},  [r2]
+8:
+        vst1.16         {d0,  d1},  [r0,  :128], r1
+        vst1.16         {d0,  d1},  [r12, :128], r1
+        subs            lr,  lr,  #4
+        vst1.16         {d0,  d1},  [r0,  :128], r1
+        vst1.16         {d0,  d1},  [r12, :128], r1
+        bgt             8b
+        pop             {r4, pc}
+160:
+        vld1.16         {q0,  q1},  [r2]
+16:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            lr,  lr,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             16b
+        pop             {r4, pc}
+320:
+        vld1.16         {q0,  q1},  [r2]!
+        sub             r1,  r1,  #32
+        vld1.16         {q2,  q3},  [r2]
+32:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d4,  d5,  d6,  d7},  [r0,  :128], r1
+        vst1.16         {d4,  d5,  d6,  d7},  [r12, :128], r1
+        subs            lr,  lr,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d4,  d5,  d6,  d7},  [r0,  :128], r1
+        vst1.16         {d4,  d5,  d6,  d7},  [r12, :128], r1
+        bgt             32b
+        pop             {r4, pc}
+640:
+        vld1.16         {q0,  q1},  [r2]!
+        sub             r1,  r1,  #96
+        vld1.16         {q2,  q3},  [r2]!
+        vld1.16         {q8,  q9},  [r2]!
+        vld1.16         {q10, q11}, [r2]!
+64:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d4,  d5,  d6,  d7},  [r0,  :128]!
+        vst1.16         {d4,  d5,  d6,  d7},  [r12, :128]!
+        subs            lr,  lr,  #2
+        vst1.16         {d16, d17, d18, d19}, [r0,  :128]!
+        vst1.16         {d16, d17, d18, d19}, [r12, :128]!
+        vst1.16         {d20, d21, d22, d23}, [r0,  :128], r1
+        vst1.16         {d20, d21, d22, d23}, [r12, :128], r1
+        bgt             64b
+        pop             {r4, pc}
+endfunc
+
+// void ipred_h_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const topleft,
+//                         const int width, const int height, const int a,
+//                         const int max_width, const int max_height);
+function ipred_h_16bpc_neon, export=1
+        push            {r4-r5, lr}
+        ldr             r4,  [sp, #12]
+        clz             r3,  r3
+        adr             r5,  L(ipred_h_tbl)
+        sub             r3,  r3,  #25
+        ldr             r3,  [r5,  r3,  lsl #2]
+        sub             r2,  r2,  #2
+        mov             lr,  #-2
+        add             r5,  r5,  r3
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_h_tbl):
+        .word 640f - L(ipred_h_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_h_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_h_tbl) + CONFIG_THUMB
+        .word 8f   - L(ipred_h_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_h_tbl) + CONFIG_THUMB
+40:
+        sub             r2,  r2,  #6
+        mov             lr,  #-8
+4:
+        vld4.16         {d0[],  d1[],  d2[],  d3[]},  [r2],  lr
+        vst1.16         {d3},  [r0,  :64], r1
+        vst1.16         {d2},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d1},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        bgt             4b
+        pop             {r4-r5, pc}
+8:
+        vld1.16         {d0[],  d1[]},  [r2],  lr
+        subs            r4,  r4,  #4
+        vld1.16         {d2[],  d3[]},  [r2],  lr
+        vst1.16         {q0},  [r0,    :128],  r1
+        vld1.16         {d4[],  d5[]},  [r2],  lr
+        vst1.16         {q1},  [r12,   :128],  r1
+        vld1.16         {d6[],  d7[]},  [r2],  lr
+        vst1.16         {q2},  [r0,    :128],  r1
+        vst1.16         {q3},  [r12,   :128],  r1
+        bgt             8b
+        pop             {r4-r5, pc}
+160:
+        sub             r1,  r1,  #16
+16:
+        vld1.16         {d0[],  d1[]}, [r2],  lr
+        subs            r4,  r4,  #4
+        vld1.16         {d2[],  d3[]}, [r2],  lr
+        vst1.16         {q0},  [r0,   :128]!
+        vld1.16         {d4[],  d5[]}, [r2],  lr
+        vst1.16         {q1},  [r12,  :128]!
+        vld1.16         {d6[],  d7[]}, [r2],  lr
+        vst1.16         {q0},  [r0,   :128],  r1
+        vst1.16         {q1},  [r12,  :128],  r1
+        vst1.16         {q2},  [r0,   :128]!
+        vst1.16         {q3},  [r12,  :128]!
+        vst1.16         {q2},  [r0,   :128],  r1
+        vst1.16         {q3},  [r12,  :128],  r1
+        bgt             16b
+        pop             {r4-r5, pc}
+320:
+        sub             r1,  r1,  #48
+32:
+        vld1.16         {d0[],  d1[]},  [r2],  lr
+        subs            r4,  r4,  #4
+        vld1.16         {d2[],  d3[]},  [r2],  lr
+        vst1.16         {q0},  [r0,    :128]!
+        vld1.16         {d4[],  d5[]},  [r2],  lr
+        vst1.16         {q1},  [r12,   :128]!
+        vld1.16         {d6[],  d7[]},  [r2],  lr
+        vst1.16         {q0},  [r0,    :128]!
+        vst1.16         {q1},  [r12,   :128]!
+        vst1.16         {q0},  [r0,    :128]!
+        vst1.16         {q1},  [r12,   :128]!
+        vst1.16         {q0},  [r0,    :128],  r1
+        vst1.16         {q1},  [r12,   :128],  r1
+        vst1.16         {q2},  [r0,    :128]!
+        vst1.16         {q3},  [r12,   :128]!
+        vst1.16         {q2},  [r0,    :128]!
+        vst1.16         {q3},  [r12,   :128]!
+        vst1.16         {q2},  [r0,    :128]!
+        vst1.16         {q3},  [r12,   :128]!
+        vst1.16         {q2},  [r0,    :128],  r1
+        vst1.16         {q3},  [r12,   :128],  r1
+        bgt             32b
+        pop             {r4-r5, pc}
+640:
+        sub             r1,  r1,  #96
+64:
+        vld1.16         {d0[],  d1[]},  [r2],  lr
+        subs            r4,  r4,  #2
+        vld1.16         {d4[],  d5[]},  [r2],  lr
+        vmov            q1,  q0
+        vmov            q3,  q2
+        vst1.16         {q0, q1}, [r0,  :128]!
+        vst1.16         {q2, q3}, [r12, :128]!
+        vst1.16         {q0, q1}, [r0,  :128]!
+        vst1.16         {q2, q3}, [r12, :128]!
+        vst1.16         {q0, q1}, [r0,  :128]!
+        vst1.16         {q2, q3}, [r12, :128]!
+        vst1.16         {q0, q1}, [r0,  :128],  r1
+        vst1.16         {q2, q3}, [r12, :128],  r1
+        bgt             64b
+        pop             {r4-r5, pc}
+endfunc
+
+// void ipred_dc_top_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int a,
+//                              const int max_width, const int max_height);
+function ipred_dc_top_16bpc_neon, export=1
+        push            {r4-r5, lr}
+        ldr             r4,  [sp, #12]
+        clz             r3,  r3
+        adr             r5,  L(ipred_dc_top_tbl)
+        sub             r3,  r3,  #25
+        ldr             r3,  [r5,  r3,  lsl #2]
+        add             r2,  r2,  #2
+        add             r5,  r5,  r3
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_dc_top_tbl):
+        .word 640f - L(ipred_dc_top_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_dc_top_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_dc_top_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_dc_top_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_dc_top_tbl) + CONFIG_THUMB
+
+40:
+        vld1.16         {d0},  [r2]
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #2
+        vdup.16         d0,  d0[0]
+4:
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        bgt             4b
+        pop             {r4-r5, pc}
+80:
+        vld1.16         {d0,  d1},  [r2]
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #3
+        vdup.16         q0,  d0[0]
+8:
+        vst1.16         {d0,  d1},  [r0,  :128], r1
+        vst1.16         {d0,  d1},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1},  [r0,  :128], r1
+        vst1.16         {d0,  d1},  [r12, :128], r1
+        bgt             8b
+        pop             {r4-r5, pc}
+160:
+        vld1.16         {d0,  d1,  d2,  d3},  [r2]
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d4,  d0,  #4
+        vdup.16         q0,  d4[0]
+        vdup.16         q1,  d4[0]
+16:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             16b
+        pop             {r4-r5, pc}
+320:
+        vld1.16         {d0,  d1,  d2,  d3},  [r2]!
+        vld1.16         {d4,  d5,  d6,  d7},  [r2]
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        q2,  q2,  q3
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpaddl.u16      d0,  d0
+        vrshrn.i32      d18, q0,  #5
+        vdup.16         q0,  d18[0]
+        vdup.16         q1,  d18[0]
+        sub             r1,  r1,  #32
+32:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             32b
+        pop             {r4-r5, pc}
+640:
+        vld1.16         {d0,  d1,  d2,  d3},  [r2]!
+        vld1.16         {d4,  d5,  d6,  d7},  [r2]!
+        vadd.i16        q0,  q0,  q1
+        vld1.16         {d16, d17, d18, d19}, [r2]!
+        vadd.i16        q2,  q2,  q3
+        vld1.16         {d20, d21, d22, d23}, [r2]
+        vadd.i16        q8,  q8,  q9
+        vadd.i16        q10, q10, q11
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        q8,  q8,  q10
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        d0,  d0,  d1
+        vpaddl.u16      d0,  d0
+        vpadd.i32       d0,  d0,  d0
+        vrshrn.i32      d18, q0,  #6
+        vdup.16         q0,  d18[0]
+        vdup.16         q1,  d18[0]
+        sub             r1,  r1,  #96
+64:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        subs            r4,  r4,  #2
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             64b
+        pop             {r4-r5, pc}
+endfunc
+
+// void ipred_dc_left_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height, const int a,
+//                               const int max_width, const int max_height);
+function ipred_dc_left_16bpc_neon, export=1
+        push            {r4-r5, lr}
+        ldr             r4,  [sp, #12]
+        sub             r2,  r2,  r4,  lsl #1
+        clz             r3,  r3
+        clz             lr,  r4
+        sub             lr,  lr,  #25
+        adr             r5,  L(ipred_dc_left_tbl)
+        sub             r3,  r3,  #20
+        ldr             r3,  [r5,  r3,  lsl #2]
+        ldr             lr,  [r5,  lr,  lsl #2]
+        add             r3,  r5,  r3
+        add             r5,  r5,  lr
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_dc_left_tbl):
+        .word L(ipred_dc_left_h64) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_h32) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_h16) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_h8)  - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_h4)  - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w64) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w32) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w16) - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w8)  - L(ipred_dc_left_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_left_w4)  - L(ipred_dc_left_tbl) + CONFIG_THUMB
+
+L(ipred_dc_left_h4):
+        vld1.16         {d0},  [r2, :64]
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #2
+        vdup.16         q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w4):
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        bgt             L(ipred_dc_left_w4)
+        pop             {r4-r5, pc}
+L(ipred_dc_left_h8):
+        vld1.16         {d0,  d1},  [r2, :128]
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #3
+        vdup.16         q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w8):
+        vst1.16         {d0,  d1},  [r0,  :128], r1
+        vst1.16         {d0,  d1},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1},  [r0,  :128], r1
+        vst1.16         {d0,  d1},  [r12, :128], r1
+        bgt             L(ipred_dc_left_w8)
+        pop             {r4-r5, pc}
+L(ipred_dc_left_h16):
+        vld1.16         {d0,  d1,  d2,  d3},  [r2, :128]
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #4
+        vdup.16         q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w16):
+        vmov            q1,  q0
+1:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             1b
+        pop             {r4-r5, pc}
+L(ipred_dc_left_h32):
+        vld1.16         {d0,  d1,  d2,  d3},  [r2, :128]!
+        vld1.16         {d4,  d5,  d6,  d7},  [r2, :128]
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        q2,  q2,  q3
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpaddl.u16      d0,  d0
+        vrshrn.i32      d0,  q0,  #5
+        vdup.16         q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w32):
+        sub             r1,  r1,  #32
+        vmov            q1,  q0
+1:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             1b
+        pop             {r4-r5, pc}
+L(ipred_dc_left_h64):
+        vld1.16         {d0,  d1,  d2,  d3},  [r2, :128]!
+        vld1.16         {d4,  d5,  d6,  d7},  [r2, :128]!
+        vadd.i16        q0,  q0,  q1
+        vld1.16         {d16, d17, d18, d19}, [r2, :128]!
+        vadd.i16        q2,  q2,  q3
+        vld1.16         {d20, d21, d22, d23}, [r2, :128]
+        vadd.i16        q8,  q8,  q9
+        vadd.i16        q10, q10, q11
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        q8,  q8,  q10
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        d0,  d0,  d1
+        vpaddl.u16      d0,  d0
+        vpadd.i32       d0,  d0,  d0
+        vrshrn.i32      d0,  q0,  #6
+        vdup.16         q0,  d0[0]
+        bx              r3
+L(ipred_dc_left_w64):
+        sub             r1,  r1,  #96
+        vmov            q1,  q0
+1:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        subs            r4,  r4,  #2
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             1b
+        pop             {r4-r5, pc}
+endfunc
+
+// void ipred_dc_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                          const pixel *const topleft,
+//                          const int width, const int height, const int a,
+//                          const int max_width, const int max_height);
+function ipred_dc_16bpc_neon, export=1
+        push            {r4-r6, lr}
+        ldr             r4,  [sp, #16]
+        sub             r2,  r2,  r4,  lsl #1
+        add             lr,  r3,  r4        // width + height
+        clz             r3,  r3
+        clz             r12, r4
+        vdup.32         q15, lr             // width + height
+        adr             r5,  L(ipred_dc_tbl)
+        rbit            lr,  lr             // rbit(width + height)
+        sub             r3,  r3,  #20       // 25 leading bits, minus table offset 5
+        sub             r12, r12, #25
+        clz             lr,  lr             // ctz(width + height)
+        ldr             r3,  [r5,  r3,  lsl #2]
+        ldr             r12, [r5,  r12, lsl #2]
+        neg             lr,  lr             // -ctz(width + height)
+        add             r3,  r5,  r3
+        add             r5,  r5,  r12
+        vshr.u32        q15, q15, #1        // (width + height) >> 1
+        vdup.32         q14, lr             // -ctz(width + height)
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_dc_tbl):
+        .word L(ipred_dc_h64) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_h32) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_h16) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_h8)  - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_h4)  - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w64) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w32) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w16) - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w8)  - L(ipred_dc_tbl) + CONFIG_THUMB
+        .word L(ipred_dc_w4)  - L(ipred_dc_tbl) + CONFIG_THUMB
+
+L(ipred_dc_h4):
+        vld1.16         {d0},  [r2, :64]!
+        vpadd.i16       d0,  d0,  d0
+        add             r2,  r2,  #2
+        vpaddl.u16      d0,  d0
+        bx              r3
+L(ipred_dc_w4):
+        vld1.16         {d2},  [r2]
+        vadd.i32        d0,  d0,  d30
+        vpadd.i16       d2,  d2,  d2
+        vpaddl.u16      d2,  d2
+        cmp             r4,  #4
+        vadd.i32        d0,  d0,  d2
+        vshl.u32        d0,  d0,  d28
+        beq             1f
+        // h = 8/16
+        cmp             r4,  #16
+        movw            lr,  #0x6667
+        movw            r5,  #0xAAAB
+        it              ne
+        movne           lr,  r5
+        vdup.32         d24, lr
+        vmul.i32        d0,  d0,  d24
+        vshr.u32        d0,  d0,  #17
+1:
+        vdup.16         d0,  d0[0]
+2:
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0},  [r0,  :64], r1
+        vst1.16         {d0},  [r12, :64], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+
+L(ipred_dc_h8):
+        vld1.16         {d0,  d1},  [r2, :128]!
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        add             r2,  r2,  #2
+        vpaddl.u16      d0,  d0
+        bx              r3
+L(ipred_dc_w8):
+        vld1.16         {d2,  d3},  [r2]
+        vadd.i32        d0,  d0,  d30
+        vadd.i16        d2,  d2,  d3
+        vpadd.i16       d2,  d2,  d2
+        vpaddl.u16      d2,  d2
+        cmp             r4,  #8
+        vadd.i32        d0,  d0,  d2
+        vshl.u32        d0,  d0,  d28
+        beq             1f
+        // h = 4/16/32
+        cmp             r4,  #32
+        movw            lr,  #0x6667
+        movw            r5,  #0xAAAB
+        it              ne
+        movne           lr,  r5
+        vdup.32         d24, lr
+        vmul.i32        d0,  d0,  d24
+        vshr.u32        d0,  d0,  #17
+1:
+        vdup.16         q0,  d0[0]
+2:
+        vst1.16         {d0,  d1},  [r0,  :128], r1
+        vst1.16         {d0,  d1},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1},  [r0,  :128], r1
+        vst1.16         {d0,  d1},  [r12, :128], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+
+L(ipred_dc_h16):
+        vld1.16         {d0,  d1,  d2,  d3},  [r2, :128]!
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        add             r2,  r2,  #2
+        vpaddl.u16      d0,  d0
+        bx              r3
+L(ipred_dc_w16):
+        vld1.16         {d2,  d3,  d4,  d5},  [r2]
+        vadd.i32        d0,  d0,  d30
+        vadd.i16        q1,  q1,  q2
+        vadd.i16        d2,  d2,  d3
+        vpadd.i16       d2,  d2,  d1
+        vpaddl.u16      d2,  d2
+        cmp             r4,  #16
+        vadd.i32        d0,  d0,  d2
+        vshl.u32        d4,  d0,  d28
+        beq             1f
+        // h = 4/8/32/64
+        tst             r4,  #(32+16+8)     // 16 added to make a consecutive bitmask
+        movw            lr,  #0x6667
+        movw            r5,  #0xAAAB
+        it              ne
+        movne           lr,  r5
+        vdup.32         d24, lr
+        vmul.i32        d4,  d4,  d24
+        vshr.u32        d4,  d4,  #17
+1:
+        vdup.16         q0,  d4[0]
+        vdup.16         q1,  d4[0]
+2:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+
+L(ipred_dc_h32):
+        vld1.16         {d0,  d1,  d2,  d3},  [r2, :128]!
+        vld1.16         {d4,  d5,  d6,  d7},  [r2, :128]!
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        q2,  q2,  q3
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        add             r2,  r2,  #2
+        vpaddl.u16      d0,  d0
+        bx              r3
+L(ipred_dc_w32):
+        vld1.16         {d2,  d3,  d4,  d5},  [r2]!
+        vadd.i32        d0,  d0,  d30
+        vld1.16         {d16, d17, d18, d19}, [r2]
+        vadd.i16        q1,  q1,  q2
+        vadd.i16        q8,  q8,  q9
+        vadd.i16        q1,  q1,  q8
+        vadd.i16        d2,  d2,  d3
+        vpadd.i16       d2,  d2,  d2
+        vpaddl.u16      d2,  d2
+        cmp             r4,  #32
+        vadd.i32        d0,  d0,  d2
+        vshl.u32        d4,  d0,  d28
+        beq             1f
+        // h = 8/16/64
+        cmp             r4,  #8
+        movw            lr,  #0x6667
+        movw            r5,  #0xAAAB
+        it              ne
+        movne           lr,  r5
+        vdup.32         d24, lr
+        vmul.i32        d4,  d4,  d24
+        vshr.u32        d4,  d4,  #17
+1:
+        sub             r1,  r1,  #32
+        vdup.16         q0,  d4[0]
+        vdup.16         q1,  d4[0]
+2:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+L(ipred_dc_h64):
+        vld1.16         {d0,  d1,  d2,  d3},  [r2, :128]!
+        vld1.16         {d4,  d5,  d6,  d7},  [r2, :128]!
+        vadd.i16        q0,  q0,  q1
+        vld1.16         {d16, d17, d18, d19}, [r2, :128]!
+        vadd.i16        q2,  q2,  q3
+        vld1.16         {d20, d21, d22, d23}, [r2, :128]!
+        vadd.i16        q8,  q8,  q9
+        vadd.i16        q10, q10, q11
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        q8,  q8,  q10
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        d0,  d0,  d1
+        vpaddl.u16      d0,  d0
+        add             r2,  r2,  #2
+        vpadd.i32       d0,  d0,  d0
+        bx              r3
+L(ipred_dc_w64):
+        vld1.16         {d2,  d3,  d4,  d5},  [r2]!
+        vadd.i32        d0,  d0,  d30
+        vld1.16         {d16, d17, d18, d19}, [r2]!
+        vadd.i16        q1,  q1,  q2
+        vld1.16         {d20, d21, d22, d23}, [r2]!
+        vadd.i16        q8,  q8,  q9
+        vld1.16         {d24, d25, d26, d27}, [r2]!
+        vadd.i16        q10, q10, q11
+        vadd.i16        q12, q12, q13
+        vadd.i16        q1,  q1,  q8
+        vadd.i16        q10, q10, q12
+        vadd.i16        q1,  q1,  q10
+        vadd.i16        d2,  d2,  d3
+        vpaddl.u16      d2,  d2
+        vpadd.i32       d2,  d2,  d2
+        cmp             r4,  #64
+        vadd.i32        d0,  d0,  d2
+        vshl.u32        d4,  d0,  d28
+        beq             1f
+        // h = 16/32
+        cmp             r4,  #16
+        movw            lr,  #0x6667
+        movw            r5,  #0xAAAB
+        it              ne
+        movne           lr,  r5
+        vdup.32         d24, lr
+        vmul.i32        d4,  d4,  d24
+        vshr.u32        d4,  d4,  #17
+1:
+        sub             r1,  r1,  #96
+        vdup.16         q0,  d4[0]
+        vdup.16         q1,  d4[0]
+2:
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        subs            r4,  r4,  #2
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128]!
+        vst1.16         {d0,  d1,  d2,  d3},  [r0,  :128], r1
+        vst1.16         {d0,  d1,  d2,  d3},  [r12, :128], r1
+        bgt             2b
+        pop             {r4-r6, pc}
+endfunc
+
+// void ipred_paeth_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int a,
+//                             const int max_width, const int max_height);
+function ipred_paeth_16bpc_neon, export=1
+        push            {r4-r6, lr}
+        vpush           {q4}
+        ldr             r4,  [sp, #32]
+        clz             lr,  r3
+        adr             r12, L(ipred_paeth_tbl)
+        sub             lr,  lr,  #25
+        ldr             lr,  [r12, lr, lsl #2]
+        vld1.16         {d4[], d5[]},  [r2]
+        add             r6,  r2,  #2
+        sub             r2,  r2,  #4
+        add             r12, r12, lr
+        mov             r5,  #-4
+        add             lr,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r12
+
+        .align 2
+L(ipred_paeth_tbl):
+        .word 640f - L(ipred_paeth_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_paeth_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_paeth_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_paeth_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_paeth_tbl) + CONFIG_THUMB
+
+40:
+        sub             r2,  r2,  #4
+        mov             r5,  #-8
+        vld1.16         {d6},  [r6]
+        vsub.i16        d16, d6,  d4  // top - topleft
+        vmov            d7,  d6
+        vmov            d17, d16
+4:
+        vld4.16         {d0[], d1[], d2[], d3[]},  [r2, :64], r5
+        vadd.i16        q9,  q8,  q0  // base
+        vadd.i16        q10, q8,  q1
+        vabd.s16        q11, q3,  q9  // tdiff
+        vabd.s16        q12, q3,  q10
+        vabd.s16        q13, q2,  q9  // tldiff
+        vabd.s16        q14, q2,  q10
+        vabd.s16        q9,  q0,  q9  // ldiff
+        vabd.s16        q10, q1,  q10
+        vmin.u16        q15, q11, q13 // min(tdiff, tldiff)
+        vmin.u16        q4,  q12, q14
+        vcge.u16        q11, q13, q11 // tldiff >= tdiff
+        vcge.u16        q12, q14, q12
+        vcge.u16        q9,  q15, q9  // min(tdiff, tldiff) >= ldiff
+        vcge.u16        q10, q4,  q10
+        vbsl            q12, q3,  q2  // tdiff <= tldiff ? top : topleft
+        vbsl            q11, q3,  q2
+        vbit            q12, q1,  q10 // ldiff <= min ? left : ...
+        vbit            q11, q0,  q9
+        vst1.16         {d25}, [r0, :64], r1
+        vst1.16         {d24}, [lr, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d23}, [r0, :64], r1
+        vst1.16         {d22}, [lr, :64], r1
+        bgt             4b
+        vpop            {q4}
+        pop             {r4-r6, pc}
+80:
+160:
+320:
+640:
+        vld1.16         {q3},  [r6]!
+        mov             r12, r3
+        sub             r1,  r1,  r3, lsl #1
+1:
+        vld2.16         {d0[], d2[]},  [r2, :32], r5
+        vmov            d1,  d0
+        vmov            d3,  d2
+2:
+        vsub.i16        q8,  q3,  q2  // top - topleft
+        vadd.i16        q9,  q8,  q0  // base
+        vadd.i16        q10, q8,  q1
+        vabd.s16        q11, q3,  q9  // tdiff
+        vabd.s16        q12, q3,  q10
+        vabd.s16        q13, q2,  q9  // tldiff
+        vabd.s16        q14, q2,  q10
+        vabd.s16        q9,  q0,  q9  // ldiff
+        vabd.s16        q10, q1,  q10
+        vmin.u16        q15, q11, q13 // min(tdiff, tldiff)
+        vmin.u16        q4,  q12, q14
+        vcge.u16        q11, q13, q11 // tldiff >= tdiff
+        vcge.u16        q12, q14, q12
+        vcge.u16        q9,  q15, q9  // min(tdiff, tldiff) >= ldiff
+        vcge.u16        q10, q4,  q10
+        vbsl            q12, q3,  q2  // tdiff <= tldiff ? top : topleft
+        vbsl            q11, q3,  q2
+        vbit            q12, q1,  q10 // ldiff <= min ? left : ...
+        vbit            q11, q0,  q9
+        subs            r3,  r3,  #8
+        vst1.16         {q12}, [r0, :128]!
+        vst1.16         {q11}, [lr, :128]!
+        ble             8f
+        vld1.16         {q3},  [r6]!
+        b               2b
+8:
+        subs            r4,  r4,  #2
+        ble             9f
+        // End of horizontal loop, move pointers to next two rows
+        sub             r6,  r6,  r12, lsl #1
+        add             r0,  r0,  r1
+        add             lr,  lr,  r1
+        vld1.16         {q3},  [r6]!
+        mov             r3,  r12
+        b               1b
+9:
+        vpop            {q4}
+        pop             {r4-r6, pc}
+endfunc
+
+// void ipred_smooth_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int a,
+//                              const int max_width, const int max_height);
+function ipred_smooth_16bpc_neon, export=1
+        push            {r4-r10, lr}
+        ldr             r4,  [sp, #32]
+        movrel          r10, X(sm_weights)
+        add             r12, r10, r4
+        add             r10, r10, r3
+        clz             r9,  r3
+        adr             r5,  L(ipred_smooth_tbl)
+        sub             lr,  r2,  r4, lsl #1
+        sub             r9,  r9,  #25
+        ldr             r9,  [r5, r9, lsl #2]
+        vld1.16         {d4[], d5[]},  [lr] // bottom
+        add             r8,  r2,  #2
+        add             r5,  r5,  r9
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_smooth_tbl):
+        .word 640f - L(ipred_smooth_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_smooth_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_smooth_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_smooth_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_smooth_tbl) + CONFIG_THUMB
+
+40:
+        vld1.16         {d16},   [r8]       // top
+        vld1.32         {d18[]}, [r10, :32] // weights_hor
+        sub             r2,  r2,  #8
+        mov             r7,  #-8
+        vdup.16         q3,  d16[3]   // right
+        vsub.i16        q8,  q8,  q2  // top-bottom
+        vmovl.u8        q9,  d18      // weights_hor
+        vadd.i16        d19, d4,  d6  // bottom+right
+4:
+        vld4.16         {d0[],  d1[],  d2[],  d3[]},  [r2,  :64], r7 // left
+        vld4.8          {d20[], d21[], d22[], d23[]}, [r12, :32]!    // weights_ver
+        vshll.u16       q12, d19, #8  // (bottom+right)*256
+        vshll.u16       q13, d19, #8
+        vshll.u16       q14, d19, #8
+        vshll.u16       q15, d19, #8
+        vzip.32         d20, d21      // weights_ver
+        vzip.32         d22, d23
+        vsub.i16        q1,  q1,  q3  // left-right
+        vsub.i16        q0,  q0,  q3
+        vmovl.u8        q10, d20      // weights_ver
+        vmovl.u8        q11, d22
+        vmlal.s16       q12, d3,  d18 // += (left-right)*weights_hor
+        vmlal.s16       q13, d2,  d18 // (left flipped)
+        vmlal.s16       q14, d1,  d18
+        vmlal.s16       q15, d0,  d18
+        vmlal.s16       q12, d16, d20 // += (top-bottom)*weights_ver
+        vmlal.s16       q13, d16, d21
+        vmlal.s16       q14, d16, d22
+        vmlal.s16       q15, d16, d23
+        vrshrn.i32      d24, q12, #9
+        vrshrn.i32      d25, q13, #9
+        vrshrn.i32      d26, q14, #9
+        vrshrn.i32      d27, q15, #9
+        vst1.16         {d24}, [r0, :64], r1
+        vst1.16         {d25}, [r6, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d26}, [r0, :64], r1
+        vst1.16         {d27}, [r6, :64], r1
+        bgt             4b
+        pop             {r4-r10, pc}
+80:
+        vld1.16         {q8},  [r8]       // top
+        vld1.8          {d18}, [r10, :64] // weights_hor
+        sub             r2,  r2,  #4
+        mov             r7,  #-4
+        vdup.16         q3,  d17[3]   // right
+        vsub.i16        q8,  q8,  q2  // top-bottom
+        vmovl.u8        q9,  d18      // weights_hor
+        vadd.i16        d3,  d4,  d6  // bottom+right
+8:
+        vld2.16         {d0[],  d1[]},  [r2,  :32], r7 // left
+        vld2.8          {d20[], d22[]}, [r12, :16]!    // weights_ver
+        vshll.u16       q12, d3,  #8  // (bottom+right)*256
+        vshll.u16       q13, d3,  #8
+        vshll.u16       q14, d3,  #8
+        vshll.u16       q15, d3,  #8
+        vsub.i16        q0,  q0,  q3  // left-right
+        vmovl.u8        q10, d20      // weights_ver
+        vmovl.u8        q11, d22
+        vmlal.s16       q12, d1,  d18 // += (left-right)*weights_hor
+        vmlal.s16       q13, d1,  d19 // (left flipped)
+        vmlal.s16       q14, d0,  d18
+        vmlal.s16       q15, d0,  d19
+        vmlal.s16       q12, d16, d20 // += (top-bottom)*weights_ver
+        vmlal.s16       q13, d17, d20
+        vmlal.s16       q14, d16, d22
+        vmlal.s16       q15, d17, d22
+        vrshrn.i32      d24, q12, #9
+        vrshrn.i32      d25, q13, #9
+        vrshrn.i32      d26, q14, #9
+        vrshrn.i32      d27, q15, #9
+        subs            r4,  r4,  #2
+        vst1.16         {q12}, [r0, :128], r1
+        vst1.16         {q13}, [r6, :128], r1
+        bgt             8b
+        pop             {r4-r10, pc}
+160:
+320:
+640:
+        add             lr,  r2,  r3, lsl #1
+        sub             r2,  r2,  #4
+        mov             r7,  #-4
+        vld1.16         {d6[], d7[]}, [lr] // right
+        sub             r1,  r1,  r3, lsl #1
+        mov             r9,  r3
+        vadd.i16        d3,  d4,  d6  // bottom+right
+
+1:
+        vld2.16         {d0[],  d1[]},  [r2,  :32], r7 // left
+        vld2.8          {d20[], d22[]}, [r12, :16]!    // weights_ver
+        vsub.i16        q0,  q0,  q3  // left-right
+        vmovl.u8        q10, d20      // weights_ver
+        vmovl.u8        q11, d22
+2:
+        vld1.8          {d18}, [r10, :64]! // weights_hor
+        vld1.16         {q8},  [r8]!       // top
+        vshll.u16       q12, d3,  #8  // (bottom+right)*256
+        vshll.u16       q13, d3,  #8
+        vmovl.u8        q9,  d18      // weights_hor
+        vshll.u16       q14, d3,  #8
+        vshll.u16       q15, d3,  #8
+        vsub.i16        q8,  q8,  q2  // top-bottom
+        vmlal.s16       q12, d1,  d18 // += (left-right)*weights_hor
+        vmlal.s16       q13, d1,  d19 // (left flipped)
+        vmlal.s16       q14, d0,  d18
+        vmlal.s16       q15, d0,  d19
+        vmlal.s16       q12, d16, d20 // += (top-bottom)*weights_ver
+        vmlal.s16       q13, d17, d20
+        vmlal.s16       q14, d16, d22
+        vmlal.s16       q15, d17, d22
+        vrshrn.i32      d24, q12, #9
+        vrshrn.i32      d25, q13, #9
+        vrshrn.i32      d26, q14, #9
+        vrshrn.i32      d27, q15, #9
+        subs            r3,  r3,  #8
+        vst1.16         {q12}, [r0, :128]!
+        vst1.16         {q13}, [r6, :128]!
+        bgt             2b
+        subs            r4,  r4,  #2
+        ble             9f
+        sub             r8,  r8,  r9, lsl #1
+        sub             r10, r10, r9
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        mov             r3,  r9
+        b               1b
+9:
+        pop             {r4-r10, pc}
+endfunc
+
+// void ipred_smooth_v_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const topleft,
+//                                const int width, const int height, const int a,
+//                                const int max_width, const int max_height);
+function ipred_smooth_v_16bpc_neon, export=1
+        push            {r4-r7, lr}
+        ldr             r4,  [sp, #20]
+        movrel          r7,  X(sm_weights)
+        add             r7,  r7,  r4
+        clz             lr,  r3
+        adr             r5,  L(ipred_smooth_v_tbl)
+        sub             r12, r2,  r4,  lsl #1
+        sub             lr,  lr,  #25
+        ldr             lr,  [r5, lr, lsl #2]
+        vld1.16         {d4[], d5[]},  [r12] // bottom
+        add             r2,  r2,  #2
+        add             r5,  r5,  lr
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_smooth_v_tbl):
+        .word 640f - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_smooth_v_tbl) + CONFIG_THUMB
+
+40:
+        vld1.16         {d6}, [r2]    // top
+        vsub.i16        d6,  d6,  d4  // top-bottom
+        vmov            d7,  d6
+4:
+        vld4.8          {d16[], d17[], d18[], d19[]}, [r7, :32]! // weights_ver
+        vzip.32         d16, d17      // weights_ver
+        vzip.32         d18, d19
+        vshll.u8        q8,  d16, #7  // weights_ver << 7
+        vshll.u8        q9,  d18, #7
+        vqrdmulh.s16    q10, q3,  q8  // ((top-bottom)*weights_ver + 128) >> 8
+        vqrdmulh.s16    q11, q3,  q9
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q2
+        vst1.16         {d20}, [r0, :64], r1
+        vst1.16         {d21}, [r6, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d22}, [r0, :64], r1
+        vst1.16         {d23}, [r6, :64], r1
+        bgt             4b
+        pop             {r4-r7, pc}
+80:
+        vld1.16         {q3}, [r2]    // top
+        vsub.i16        q3,  q3,  q2  // top-bottom
+8:
+        vld4.8          {d16[], d18[], d20[], d22[]}, [r7, :32]! // weights_ver
+        vshll.u8        q8,  d16, #7  // weights_ver << 7
+        vshll.u8        q9,  d18, #7
+        vshll.u8        q10, d20, #7
+        vshll.u8        q11, d22, #7
+        vqrdmulh.s16    q8,  q3,  q8  // ((top-bottom)*weights_ver + 128) >> 8
+        vqrdmulh.s16    q9,  q3,  q9
+        vqrdmulh.s16    q10, q3,  q10
+        vqrdmulh.s16    q11, q3,  q11
+        vadd.i16        q8,  q8,  q2
+        vadd.i16        q9,  q9,  q2
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q2
+        vst1.16         {q8},  [r0, :128], r1
+        vst1.16         {q9},  [r6, :128], r1
+        subs            r4,  r4,  #4
+        vst1.16         {q10}, [r0, :128], r1
+        vst1.16         {q11}, [r6, :128], r1
+        bgt             8b
+        pop             {r4-r7, pc}
+160:
+320:
+640:
+        vpush           {q4-q7}
+        // Set up pointers for four rows in parallel; r0, r6, r5, lr
+        add             r5,  r0,  r1
+        add             lr,  r6,  r1
+        lsl             r1,  r1,  #1
+        sub             r1,  r1,  r3, lsl #1
+        mov             r12, r3
+
+1:
+        vld4.8          {d8[], d10[], d12[], d14[]}, [r7, :32]! // weights_ver
+        vshll.u8        q4,  d8,  #7  // weights_ver << 7
+        vshll.u8        q5,  d10, #7
+        vshll.u8        q6,  d12, #7
+        vshll.u8        q7,  d14, #7
+2:
+        vld1.16         {q0, q1}, [r2]!  // top
+        vsub.i16        q0,  q0,  q2  // top-bottom
+        vsub.i16        q1,  q1,  q2
+        vqrdmulh.s16    q8,  q0,  q4  // ((top-bottom)*weights_ver + 128) >> 8
+        vqrdmulh.s16    q9,  q1,  q4
+        vqrdmulh.s16    q10, q0,  q5
+        vqrdmulh.s16    q11, q1,  q5
+        vqrdmulh.s16    q12, q0,  q6
+        vqrdmulh.s16    q13, q1,  q6
+        vqrdmulh.s16    q14, q0,  q7
+        vqrdmulh.s16    q15, q1,  q7
+        vadd.i16        q8,  q8,  q2
+        vadd.i16        q9,  q9,  q2
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q2
+        vadd.i16        q12, q12, q2
+        vadd.i16        q13, q13, q2
+        vadd.i16        q14, q14, q2
+        vadd.i16        q15, q15, q2
+        subs            r3,  r3,  #16
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vst1.16         {q10, q11}, [r6, :128]!
+        vst1.16         {q12, q13}, [r5, :128]!
+        vst1.16         {q14, q15}, [lr, :128]!
+        bgt             2b
+        subs            r4,  r4,  #4
+        ble             9f
+        sub             r2,  r2,  r12, lsl #1
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        add             r5,  r5,  r1
+        add             lr,  lr,  r1
+        mov             r3,  r12
+        b               1b
+9:
+        vpop            {q4-q7}
+        pop             {r4-r7, pc}
+endfunc
+
+// void ipred_smooth_h_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const topleft,
+//                                const int width, const int height, const int a,
+//                                const int max_width, const int max_height);
+function ipred_smooth_h_16bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldr             r4,  [sp, #24]
+        movrel          r8,  X(sm_weights)
+        add             r8,  r8,  r3
+        clz             lr,  r3
+        adr             r5,  L(ipred_smooth_h_tbl)
+        add             r12, r2,  r3, lsl #1
+        sub             lr,  lr,  #25
+        ldr             lr,  [r5, lr, lsl #2]
+        vld1.16         {d4[], d5[]},  [r12] // right
+        add             r5,  r5,  lr
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r5
+
+        .align 2
+L(ipred_smooth_h_tbl):
+        .word 640f - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+        .word 320f - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_smooth_h_tbl) + CONFIG_THUMB
+
+40:
+        vld1.32         {d6[]}, [r8, :32] // weights_hor
+        sub             r2,  r2,  #8
+        mov             r7,  #-8
+        vshll.u8        q3,  d6,  #7  // weights_hor << 7
+4:
+        vld4.16         {d0[], d1[], d2[], d3[]},  [r2, :64], r7 // left
+        vsub.i16        q0,  q0,  q2  // left-right
+        vsub.i16        q1,  q1,  q2
+        subs            r4,  r4,  #4
+        vqrdmulh.s16    q8,  q1,  q3  // ((left-right)*weights_hor + 128) >> 8
+        vqrdmulh.s16    q9,  q0,  q3  // (left flipped)
+        vadd.i16        q8,  q8,  q2
+        vadd.i16        q9,  q9,  q2
+        vst1.16         {d17}, [r0, :64], r1
+        vst1.16         {d16}, [r6, :64], r1
+        vst1.16         {d19}, [r0, :64], r1
+        vst1.16         {d18}, [r6, :64], r1
+        bgt             4b
+        pop             {r4-r8, pc}
+80:
+        vld1.8          {d6}, [r8, :64] // weights_hor
+        sub             r2,  r2,  #8
+        mov             r7,  #-8
+        vshll.u8        q3,  d6,  #7  // weights_hor << 7
+8:
+        vld1.16         {d23},  [r2, :64], r7 // left
+        subs            r4,  r4,  #4
+        vsub.i16        d23, d23, d4  // left-right
+        vdup.16         q8,  d23[3]   // flip left
+        vdup.16         q9,  d23[2]
+        vdup.16         q10, d23[1]
+        vdup.16         q11, d23[0]
+        vqrdmulh.s16    q8,  q8,  q3  // ((left-right)*weights_hor + 128) >> 8
+        vqrdmulh.s16    q9,  q9,  q3
+        vqrdmulh.s16    q10, q10, q3
+        vqrdmulh.s16    q11, q11, q3
+        vadd.i16        q8,  q8,  q2
+        vadd.i16        q9,  q9,  q2
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q2
+        vst1.16         {q8},  [r0, :128], r1
+        vst1.16         {q9},  [r6, :128], r1
+        vst1.16         {q10}, [r0, :128], r1
+        vst1.16         {q11}, [r6, :128], r1
+        bgt             8b
+        pop             {r4-r8, pc}
+160:
+320:
+640:
+        vpush           {q4-q7}
+        sub             r2,  r2,  #8
+        mov             r7,  #-8
+        // Set up pointers for four rows in parallel; r0, r6, r5, lr
+        add             r5,  r0,  r1
+        add             lr,  r6,  r1
+        lsl             r1,  r1,  #1
+        sub             r1,  r1,  r3, lsl #1
+        mov             r12, r3
+
+1:
+        vld1.16         {d15},  [r2, :64], r7 // left
+        vsub.i16        d15, d15, d4  // left-right
+        vdup.16         q4,  d15[3]   // flip left
+        vdup.16         q5,  d15[2]
+        vdup.16         q6,  d15[1]
+        vdup.16         q7,  d15[0]
+2:
+        vld1.8          {q1}, [r8, :128]! // weights_hor
+        subs            r3,  r3,  #16
+        vshll.u8        q0,  d2,  #7  // weights_hor << 7
+        vshll.u8        q1,  d3,  #7
+        vqrdmulh.s16    q8,  q0,  q4  // ((left-right)*weights_hor + 128) >> 8
+        vqrdmulh.s16    q9,  q1,  q4
+        vqrdmulh.s16    q10, q0,  q5
+        vqrdmulh.s16    q11, q1,  q5
+        vqrdmulh.s16    q12, q0,  q6
+        vqrdmulh.s16    q13, q1,  q6
+        vqrdmulh.s16    q14, q0,  q7
+        vqrdmulh.s16    q15, q1,  q7
+        vadd.i16        q8,  q8,  q2
+        vadd.i16        q9,  q9,  q2
+        vadd.i16        q10, q10, q2
+        vadd.i16        q11, q11, q2
+        vadd.i16        q12, q12, q2
+        vadd.i16        q13, q13, q2
+        vadd.i16        q14, q14, q2
+        vadd.i16        q15, q15, q2
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vst1.16         {q10, q11}, [r6, :128]!
+        vst1.16         {q12, q13}, [r5, :128]!
+        vst1.16         {q14, q15}, [lr, :128]!
+        bgt             2b
+        subs            r4,  r4,  #4
+        ble             9f
+        sub             r8,  r8,  r12
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        add             r5,  r5,  r1
+        add             lr,  lr,  r1
+        mov             r3,  r12
+        b               1b
+9:
+        vpop            {q4-q7}
+        pop             {r4-r8, pc}
+endfunc
+
+// void ipred_filter_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int filt_idx,
+//                              const int max_width, const int max_height,
+//                              const int bitdepth_max);
+.macro filter_fn bpc
+function ipred_filter_\bpc\()bpc_neon, export=1
+        movw            r12, #511
+        ldrd            r4,  r5,   [sp, #88]
+        and             r5,  r5,  r12 // 511
+        movrel          r6,  X(filter_intra_taps)
+        lsl             r5,  r5,  #6
+        add             r6,  r6,  r5
+        vld1.8          {d20, d21, d22, d23}, [r6, :128]!
+        clz             lr,  r3
+        adr             r5,  L(ipred_filter\bpc\()_tbl)
+        vld1.8          {d27, d28, d29}, [r6, :64]
+        sub             lr,  lr,  #26
+        ldr             lr,  [r5, lr, lsl #2]
+        vmovl.s8        q8,  d20
+        vmovl.s8        q9,  d21
+        add             r5,  r5,  lr
+        vmovl.s8        q10, d22
+        vmovl.s8        q11, d23
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        vmovl.s8        q12, d27
+        vmovl.s8        q13, d28
+        vmovl.s8        q14, d29
+        mov             r7,  #-4
+        vdup.16         q15, r8
+        add             r8,  r2,  #2
+        sub             r2,  r2,  #4
+.if \bpc == 10
+        vmov.i16        q7,  #0
+.endif
+        bx              r5
+
+        .align 2
+L(ipred_filter\bpc\()_tbl):
+        .word 320f - L(ipred_filter\bpc\()_tbl) + CONFIG_THUMB
+        .word 160f - L(ipred_filter\bpc\()_tbl) + CONFIG_THUMB
+        .word 80f  - L(ipred_filter\bpc\()_tbl) + CONFIG_THUMB
+        .word 40f  - L(ipred_filter\bpc\()_tbl) + CONFIG_THUMB
+
+40:
+        vld1.16         {d0}, [r8]       // top (0-3)
+4:
+        vld1.16         {d2}, [r2], r7   // left (0-1) + topleft (2)
+.if \bpc == 10
+        vmul.i16        q2,  q9,  d0[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q2,  q10, d0[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q2,  q11, d0[2]  // p3(top[2]) * filter(3)
+        vmla.i16        q2,  q12, d0[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q2,  q8,  d2[2]  // p0(topleft) * filter(0)
+        vmla.i16        q2,  q13, d2[1]  // p5(left[0]) * filter(5)
+        vmla.i16        q2,  q14, d2[0]  // p6(left[1]) * filter(6)
+        vrshr.s16       q2,  q2,  #4
+        vmax.s16        q2,  q2,  q7
+.else
+        vmull.s16       q2,  d18, d0[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q2,  d20, d0[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q2,  d22, d0[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q2,  d24, d0[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q2,  d16, d2[2]  // p0(topleft) * filter(0)
+        vmlal.s16       q2,  d26, d2[1]  // p5(left[0]) * filter(5)
+        vmlal.s16       q2,  d28, d2[0]  // p6(left[1]) * filter(6)
+        vmull.s16       q3,  d19, d0[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q3,  d21, d0[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q3,  d23, d0[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q3,  d25, d0[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q3,  d17, d2[2]  // p0(topleft) * filter(0)
+        vmlal.s16       q3,  d27, d2[1]  // p5(left[0]) * filter(5)
+        vmlal.s16       q3,  d29, d2[0]  // p6(left[1]) * filter(6)
+        vqrshrun.s32    d4,  q2,  #4
+        vqrshrun.s32    d5,  q3,  #4
+.endif
+        vmin.s16        q2,  q2,  q15
+        subs            r4,  r4,  #2
+        vst1.16         {d4}, [r0, :64], r1
+        vst1.16         {d5}, [r6, :64], r1
+        vmov            d0,  d5          // move top from [4-7] to [0-3]
+        bgt             4b
+        vpop            {q4-q7}
+        pop             {r4-r8, pc}
+80:
+        vld1.16         {q0},  [r8]      // top (0-7)
+8:
+        vld1.16         {d2}, [r2], r7   // left (0-1) + topleft (2)
+.if \bpc == 10
+        vmul.i16        q2,  q9,  d0[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q2,  q10, d0[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q2,  q11, d0[2]  // p3(top[2]) * filter(3)
+        vmla.i16        q2,  q12, d0[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q2,  q8,  d2[2]  // p0(topleft) * filter(0)
+        vmla.i16        q2,  q13, d2[1]  // p5(left[0]) * filter(5)
+        vmla.i16        q2,  q14, d2[0]  // p6(left[1]) * filter(6)
+        vmul.i16        q3,  q9,  d1[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q3,  q10, d1[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q3,  q11, d1[2]  // p3(top[2]) * filter(3)
+        vrshr.s16       q2,  q2,  #4
+        vmax.s16        q2,  q2,  q7
+        vmin.s16        q2,  q2,  q15
+        vmla.i16        q3,  q12, d1[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q3,  q8,  d0[3]  // p0(topleft) * filter(0)
+        vmla.i16        q3,  q13, d4[3]  // p5(left[0]) * filter(5)
+        vmla.i16        q3,  q14, d5[3]  // p6(left[1]) * filter(6)
+        vrshr.s16       q3,  q3,  #4
+        vmax.s16        q3,  q3,  q7
+.else
+        vmull.s16       q2,  d18, d0[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q2,  d20, d0[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q2,  d22, d0[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q2,  d24, d0[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q2,  d16, d2[2]  // p0(topleft) * filter(0)
+        vmlal.s16       q2,  d26, d2[1]  // p5(left[0]) * filter(5)
+        vmlal.s16       q2,  d28, d2[0]  // p6(left[1]) * filter(6)
+        vmull.s16       q3,  d19, d0[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q3,  d21, d0[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q3,  d23, d0[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q3,  d25, d0[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q3,  d17, d2[2]  // p0(topleft) * filter(0)
+        vmlal.s16       q3,  d27, d2[1]  // p5(left[0]) * filter(5)
+        vmlal.s16       q3,  d29, d2[0]  // p6(left[1]) * filter(6)
+        vqrshrun.s32    d4,  q2,  #4
+        vmull.s16       q4,  d18, d1[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q4,  d20, d1[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q4,  d22, d1[2]  // p3(top[2]) * filter(3)
+        vqrshrun.s32    d5,  q3,  #4
+        vmin.s16        q2,  q2,  q15
+        vmlal.s16       q4,  d24, d1[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q4,  d16, d0[3]  // p0(topleft) * filter(0)
+        vmlal.s16       q4,  d26, d4[3]  // p5(left[0]) * filter(5)
+        vmlal.s16       q4,  d28, d5[3]  // p6(left[1]) * filter(6)
+        vmull.s16       q5,  d19, d1[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q5,  d21, d1[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q5,  d23, d1[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q5,  d25, d1[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q5,  d17, d0[3]  // p0(topleft) * filter(0)
+        vmlal.s16       q5,  d27, d4[3]  // p5(left[0]) * filter(5)
+        vmlal.s16       q5,  d29, d5[3]  // p6(left[1]) * filter(6)
+        vqrshrun.s32    d6,  q4,  #4
+        vqrshrun.s32    d7,  q5,  #4
+.endif
+        vmin.s16        q3,  q3,  q15
+        vswp            d5,  d6
+        subs            r4,  r4,  #2
+        vst1.16         {q2}, [r0, :128], r1
+        vmov            q0,  q3
+        vst1.16         {q3}, [r6, :128], r1
+        bgt             8b
+        vpop            {q4-q7}
+        pop             {r4-r8, pc}
+160:
+320:
+        sub             r1,  r1,  r3, lsl #1
+        mov             lr,  r3
+
+1:
+        vld1.16         {d0}, [r2], r7   // left (0-1) + topleft (2)
+2:
+        vld1.16         {q1, q2}, [r8]!  // top(0-15)
+.if \bpc == 10
+        vmul.i16        q3,  q8,  d0[2]  // p0(topleft) * filter(0)
+        vmla.i16        q3,  q13, d0[1]  // p5(left[0]) * filter(5)
+        vmla.i16        q3,  q14, d0[0]  // p6(left[1]) * filter(6)
+        vmla.i16        q3,  q9,  d2[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q3,  q10, d2[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q3,  q11, d2[2]  // p3(top[2]) * filter(3)
+        vmla.i16        q3,  q12, d2[3]  // p4(top[3]) * filter(4)
+
+        vmul.i16        q4,  q9,  d3[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q4,  q10, d3[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q4,  q11, d3[2]  // p3(top[2]) * filter(3)
+        vrshr.s16       q3,  q3,  #4
+        vmax.s16        q3,  q3,  q7
+        vmin.s16        q3,  q3,  q15
+        vmla.i16        q4,  q12, d3[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q4,  q8,  d2[3]  // p0(topleft) * filter(0)
+        vmla.i16        q4,  q13, d6[3]  // p5(left[0]) * filter(5)
+        vmla.i16        q4,  q14, d7[3]  // p6(left[1]) * filter(6)
+
+        vmul.i16        q5,  q9,  d4[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q5,  q10, d4[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q5,  q11, d4[2]  // p3(top[2]) * filter(3)
+        vrshr.s16       q4,  q4,  #4
+        vmax.s16        q4,  q4,  q7
+        vmin.s16        q4,  q4,  q15
+        vmov            q0,  q4
+        vmla.i16        q5,  q12, d4[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q5,  q8,  d3[3]  // p0(topleft) * filter(0)
+        vmla.i16        q5,  q13, d0[3]  // p5(left[0]) * filter(5)
+        vmla.i16        q5,  q14, d1[3]  // p6(left[1]) * filter(6)
+
+        vmul.i16        q6,  q9,  d5[0]  // p1(top[0]) * filter(1)
+        vmla.i16        q6,  q10, d5[1]  // p2(top[1]) * filter(2)
+        vmla.i16        q6,  q11, d5[2]  // p3(top[2]) * filter(3)
+        vrshr.s16       q5,  q5,  #4
+        vmax.s16        q5,  q5,  q7
+        vmin.s16        q5,  q5,  q15
+        vmov            q0,  q5
+        vmov.u16        r12, d5[3]
+        vmla.i16        q6,  q12, d5[3]  // p4(top[3]) * filter(4)
+        vmla.i16        q6,  q8,  d4[3]  // p0(topleft) * filter(0)
+        vmla.i16        q6,  q13, d0[3]  // p5(left[0]) * filter(5)
+        vmla.i16        q6,  q14, d1[3]  // p6(left[1]) * filter(6)
+        vmov.16         d0[2], r12
+        subs            r3,  r3,  #16
+        vrshr.s16       q6,  q6,  #4
+.else
+        vmull.s16       q3,  d16, d0[2]  // p0(topleft) * filter(0)
+        vmlal.s16       q3,  d26, d0[1]  // p5(left[0]) * filter(5)
+        vmlal.s16       q3,  d28, d0[0]  // p6(left[1]) * filter(6)
+        vmlal.s16       q3,  d18, d2[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q3,  d20, d2[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q3,  d22, d2[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q3,  d24, d2[3]  // p4(top[3]) * filter(4)
+        vmull.s16       q4,  d17, d0[2]  // p0(topleft) * filter(0)
+        vmlal.s16       q4,  d27, d0[1]  // p5(left[0]) * filter(5)
+        vmlal.s16       q4,  d29, d0[0]  // p6(left[1]) * filter(6)
+        vmlal.s16       q4,  d19, d2[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q4,  d21, d2[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q4,  d23, d2[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q4,  d25, d2[3]  // p4(top[3]) * filter(4)
+        vqrshrun.s32    d6,  q3,  #4
+        vmull.s16       q5,  d18, d3[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q5,  d20, d3[1]  // p2(top[1]) * filter(2)
+        vqrshrun.s32    d7,  q4,  #4
+        vmin.s16        q3,  q3,  q15
+        vmlal.s16       q5,  d22, d3[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q5,  d24, d3[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q5,  d16, d2[3]  // p0(topleft) * filter(0)
+        vmlal.s16       q5,  d26, d6[3]  // p5(left[0]) * filter(5)
+        vmlal.s16       q5,  d28, d7[3]  // p6(left[1]) * filter(6)
+        vmull.s16       q6,  d19, d3[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q6,  d21, d3[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q6,  d23, d3[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q6,  d25, d3[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q6,  d17, d2[3]  // p0(topleft) * filter(0)
+        vmlal.s16       q6,  d27, d6[3]  // p5(left[0]) * filter(5)
+        vmlal.s16       q6,  d29, d7[3]  // p6(left[1]) * filter(6)
+        vqrshrun.s32    d8,  q5,  #4
+        vmull.s16       q7,  d18, d4[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q7,  d20, d4[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q7,  d22, d4[2]  // p3(top[2]) * filter(3)
+        vqrshrun.s32    d9,  q6,  #4
+        vmin.s16        q0,  q4,  q15
+        vmlal.s16       q7,  d24, d4[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q7,  d16, d3[3]  // p0(topleft) * filter(0)
+        vmlal.s16       q7,  d26, d0[3]  // p5(left[0]) * filter(5)
+        vmlal.s16       q7,  d28, d1[3]  // p6(left[1]) * filter(6)
+        vmin.s16        q4,  q4,  q15
+        vmull.s16       q6,  d19, d4[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q6,  d21, d4[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q6,  d23, d4[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q6,  d25, d4[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q6,  d17, d3[3]  // p0(topleft) * filter(0)
+        vmlal.s16       q6,  d27, d0[3]  // p5(left[0]) * filter(5)
+        vmlal.s16       q6,  d29, d1[3]  // p6(left[1]) * filter(6)
+        vqrshrun.s32    d10, q7,  #4
+        vmull.s16       q1,  d18, d5[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q1,  d20, d5[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q1,  d22, d5[2]  // p3(top[2]) * filter(3)
+        vqrshrun.s32    d11, q6,  #4
+        vmin.s16        q0,  q5,  q15
+        vmlal.s16       q1,  d24, d5[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q1,  d16, d4[3]  // p0(topleft) * filter(0)
+        vmlal.s16       q1,  d26, d0[3]  // p5(left[0]) * filter(5)
+        vmlal.s16       q1,  d28, d1[3]  // p6(left[1]) * filter(6)
+        vmin.s16        q5,  q5,  q15
+        vmov.u16        r12, d5[3]
+        vmull.s16       q7,  d19, d5[0]  // p1(top[0]) * filter(1)
+        vmlal.s16       q7,  d21, d5[1]  // p2(top[1]) * filter(2)
+        vmlal.s16       q7,  d23, d5[2]  // p3(top[2]) * filter(3)
+        vmlal.s16       q7,  d25, d5[3]  // p4(top[3]) * filter(4)
+        vmlal.s16       q7,  d17, d4[3]  // p0(topleft) * filter(0)
+        vmlal.s16       q7,  d27, d0[3]  // p5(left[0]) * filter(5)
+        vmlal.s16       q7,  d29, d1[3]  // p6(left[1]) * filter(6)
+        vmov.16         d0[2], r12
+        vqrshrun.s32    d12, q1,  #4
+        subs            r3,  r3,  #16
+        vqrshrun.s32    d13, q7,  #4
+.endif
+        vswp            q4,  q5
+.if \bpc == 10
+        vmax.s16        q6,  q6,  q7
+.endif
+        vswp            d7,  d10
+        vmin.s16        q6,  q6,  q15
+
+        vswp            d9,  d12
+
+        vst1.16         {q3, q4}, [r0, :128]!
+        vst1.16         {q5, q6}, [r6, :128]!
+        ble             8f
+        vmov.u16        r12, d13[3]
+        vmov.16         d0[0], r12
+        vmov.u16        r12, d9[3]
+        vmov.16         d0[1], r12
+        b               2b
+8:
+        subs            r4,  r4,  #2
+
+        ble             9f
+        sub             r8,  r6,  lr, lsl #1
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        mov             r3,  lr
+        b               1b
+9:
+        vpop            {q4-q7}
+        pop             {r4-r8, pc}
+endfunc
+.endm
+
+filter_fn 10
+filter_fn 12
+
+function ipred_filter_16bpc_neon, export=1
+        push            {r4-r8, lr}
+        vpush           {q4-q7}
+        movw            r12, 0x3ff
+        ldr             r8, [sp, #104]
+        cmp             r8,  r12
+        ble             ipred_filter_10bpc_neon
+        b               ipred_filter_12bpc_neon
+endfunc
+
+// void pal_pred_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                          const pixel *const pal, const uint8_t *idx,
+//                          const int w, const int h);
+function pal_pred_16bpc_neon, export=1
+        push            {r4-r5, lr}
+        ldr             r4,  [sp, #12]
+        ldr             r5,  [sp, #16]
+        vld1.16         {q14}, [r2, :128]
+        clz             lr,  r4
+        adr             r12, L(pal_pred_tbl)
+        sub             lr,  lr,  #25
+        vmov.i8         q13, #7
+        ldr             lr,  [r12, lr, lsl #2]
+        vmov.i16        q15, #0x100
+        add             r12, r12, lr
+        add             r2,  r0,  r1
+        bx              r12
+
+        .align 2
+L(pal_pred_tbl):
+        .word 640f - L(pal_pred_tbl) + CONFIG_THUMB
+        .word 320f - L(pal_pred_tbl) + CONFIG_THUMB
+        .word 160f - L(pal_pred_tbl) + CONFIG_THUMB
+        .word 80f  - L(pal_pred_tbl) + CONFIG_THUMB
+        .word 40f  - L(pal_pred_tbl) + CONFIG_THUMB
+
+40:
+        lsl             r1,  r1,  #1
+4:
+        vld1.8          {d2}, [r3, :64]!
+        subs            r5,  r5,  #4
+        vshr.u8         d3,  d2,  #4
+        vand.u8         d2,  d2,  d26
+        vzip.8          d2,  d3
+        // Restructure q1 from a, b, c, ... into 2*a, 2*a+1, 2*b, 2*b+1, 2*c, 2*c+1, ...
+        vadd.i8         q0,  q1,  q1
+        vadd.i8         q1,  q1,  q1
+        vzip.8          q0,  q1
+        vadd.i16        q0,  q0,  q15
+        vadd.i16        q1,  q1,  q15
+        vtbl.8          d0, {q14}, d0
+        vtbl.8          d1, {q14}, d1
+        vst1.16         {d0}, [r0, :64], r1
+        vtbl.8          d2, {q14}, d2
+        vst1.16         {d1}, [r2, :64], r1
+        vtbl.8          d3, {q14}, d3
+        vst1.16         {d2}, [r0, :64], r1
+        vst1.16         {d3}, [r2, :64], r1
+        bgt             4b
+        pop             {r4-r5, pc}
+80:
+        lsl             r1,  r1,  #1
+8:
+        vld1.8          {q1}, [r3, :64]!
+        subs            r5,  r5,  #4
+        vshr.u8         q2,  q1,  #4
+        vand.u8         q1,  q1,  q13
+        vzip.8          q1,  q2
+        // Prefer doing the adds twice, instead of chaining a vmov after
+        // the add.
+        vadd.i8         q0,  q1,  q1
+        vadd.i8         q1,  q1,  q1
+        vadd.i8         q3,  q2,  q2
+        vadd.i8         q2,  q2,  q2
+        vzip.8          q0,  q1
+        vzip.8          q2,  q3
+        vadd.i16        q0,  q0,  q15
+        vadd.i16        q1,  q1,  q15
+        vtbl.8          d0, {q14}, d0
+        vadd.i16        q2,  q2,  q15
+        vtbl.8          d1, {q14}, d1
+        vadd.i16        q3,  q3,  q15
+        vtbl.8          d2, {q14}, d2
+        vtbl.8          d3, {q14}, d3
+        vtbl.8          d4, {q14}, d4
+        vtbl.8          d5, {q14}, d5
+        vst1.16         {q0}, [r0, :128], r1
+        vtbl.8          d6, {q14}, d6
+        vst1.16         {q1}, [r2, :128], r1
+        vtbl.8          d7, {q14}, d7
+        vst1.16         {q2}, [r0, :128], r1
+        vst1.16         {q3}, [r2, :128], r1
+        bgt             8b
+        pop             {r4-r5, pc}
+160:
+        lsl             r1,  r1,  #1
+16:
+        vld1.8          {q10, q11}, [r3, :64]!
+        subs            r5,  r5,  #4
+        vand.u8         q2,  q10, q13
+        vshr.u8         q3,  q10, #4
+        vand.u8         q10, q11, q13
+        vshr.u8         q11, q11, #4
+        vzip.8          q2,  q3
+        vzip.8          q10, q11
+        vadd.i8         q0,  q2,  q2
+        vadd.i8         q1,  q2,  q2
+        vadd.i8         q2,  q3,  q3
+        vadd.i8         q3,  q3,  q3
+        vadd.i8         q8,  q10, q10
+        vadd.i8         q9,  q10, q10
+        vadd.i8         q10, q11, q11
+        vzip.8          q0,  q1
+        vadd.i8         q11, q11, q11
+        vzip.8          q2,  q3
+        vzip.8          q8,  q9
+        vadd.i16        q0,  q0,  q15
+        vzip.8          q10, q11
+        vadd.i16        q1,  q1,  q15
+        vadd.i16        q2,  q2,  q15
+        vadd.i16        q3,  q3,  q15
+        vadd.i16        q8,  q8,  q15
+        vadd.i16        q9,  q9,  q15
+        vadd.i16        q10, q10, q15
+        vtbl.8          d0,  {q14}, d0
+        vadd.i16        q11, q11, q15
+        vtbl.8          d1,  {q14}, d1
+        vtbl.8          d2,  {q14}, d2
+        vtbl.8          d3,  {q14}, d3
+        vtbl.8          d4,  {q14}, d4
+        vtbl.8          d5,  {q14}, d5
+        vtbl.8          d6,  {q14}, d6
+        vtbl.8          d7,  {q14}, d7
+        vtbl.8          d16, {q14}, d16
+        vtbl.8          d17, {q14}, d17
+        vtbl.8          d18, {q14}, d18
+        vst1.16         {q0,  q1},  [r0, :128], r1
+        vtbl.8          d19, {q14}, d19
+        vtbl.8          d20, {q14}, d20
+        vst1.16         {q2,  q3},  [r2, :128], r1
+        vtbl.8          d21, {q14}, d21
+        vtbl.8          d22, {q14}, d22
+        vst1.16         {q8,  q9},  [r0, :128], r1
+        vtbl.8          d23, {q14}, d23
+        vst1.16         {q10, q11}, [r2, :128], r1
+        bgt             16b
+        pop             {r4-r5, pc}
+320:
+        lsl             r1,  r1,  #1
+        sub             r1,  r1,  #32
+32:
+        vld1.8          {q10, q11}, [r3, :64]!
+        subs            r5,  r5,  #2
+        vand.u8         q2,  q10, q13
+        vshr.u8         q3,  q10, #4
+        vand.u8         q10, q11, q13
+        vshr.u8         q11, q11, #4
+        vzip.8          q2,  q3
+        vzip.8          q10, q11
+        vadd.i8         q0,  q2,  q2
+        vadd.i8         q1,  q2,  q2
+        vadd.i8         q2,  q3,  q3
+        vadd.i8         q3,  q3,  q3
+        vadd.i8         q8,  q10, q10
+        vadd.i8         q9,  q10, q10
+        vadd.i8         q10, q11, q11
+        vzip.8          q0,  q1
+        vadd.i8         q11, q11, q11
+        vzip.8          q2,  q3
+        vzip.8          q8,  q9
+        vadd.i16        q0,  q0,  q15
+        vzip.8          q10, q11
+        vadd.i16        q1,  q1,  q15
+        vadd.i16        q2,  q2,  q15
+        vadd.i16        q3,  q3,  q15
+        vadd.i16        q8,  q8,  q15
+        vadd.i16        q9,  q9,  q15
+        vadd.i16        q10, q10, q15
+        vtbl.8          d0,  {q14}, d0
+        vadd.i16        q11, q11, q15
+        vtbl.8          d1,  {q14}, d1
+        vtbl.8          d2,  {q14}, d2
+        vtbl.8          d3,  {q14}, d3
+        vtbl.8          d4,  {q14}, d4
+        vtbl.8          d5,  {q14}, d5
+        vtbl.8          d6,  {q14}, d6
+        vtbl.8          d7,  {q14}, d7
+        vtbl.8          d16, {q14}, d16
+        vtbl.8          d17, {q14}, d17
+        vtbl.8          d18, {q14}, d18
+        vst1.16         {q0,  q1},  [r0, :128]!
+        vtbl.8          d19, {q14}, d19
+        vtbl.8          d20, {q14}, d20
+        vst1.16         {q2,  q3},  [r0, :128], r1
+        vtbl.8          d21, {q14}, d21
+        vtbl.8          d22, {q14}, d22
+        vst1.16         {q8,  q9},  [r2, :128]!
+        vtbl.8          d23, {q14}, d23
+        vst1.16         {q10, q11}, [r2, :128], r1
+        bgt             32b
+        pop             {r4-r5, pc}
+640:
+        sub             r1,  r1,  #96
+64:
+        vld1.8          {q10, q11}, [r3, :64]!
+        subs            r5,  r5,  #1
+        vand.u8         q2,  q10, q13
+        vshr.u8         q3,  q10, #4
+        vand.u8         q10, q11, q13
+        vshr.u8         q11, q11, #4
+        vzip.8          q2,  q3
+        vzip.8          q10, q11
+        vadd.i8         q0,  q2,  q2
+        vadd.i8         q1,  q2,  q2
+        vadd.i8         q2,  q3,  q3
+        vadd.i8         q3,  q3,  q3
+        vadd.i8         q8,  q10, q10
+        vadd.i8         q9,  q10, q10
+        vadd.i8         q10, q11, q11
+        vzip.8          q0,  q1
+        vadd.i8         q11, q11, q11
+        vzip.8          q2,  q3
+        vzip.8          q8,  q9
+        vadd.i16        q0,  q0,  q15
+        vzip.8          q10, q11
+        vadd.i16        q1,  q1,  q15
+        vadd.i16        q2,  q2,  q15
+        vadd.i16        q3,  q3,  q15
+        vadd.i16        q8,  q8,  q15
+        vadd.i16        q9,  q9,  q15
+        vadd.i16        q10, q10, q15
+        vtbl.8          d0,  {q14}, d0
+        vadd.i16        q11, q11, q15
+        vtbl.8          d1,  {q14}, d1
+        vtbl.8          d2,  {q14}, d2
+        vtbl.8          d3,  {q14}, d3
+        vtbl.8          d4,  {q14}, d4
+        vtbl.8          d5,  {q14}, d5
+        vtbl.8          d6,  {q14}, d6
+        vtbl.8          d7,  {q14}, d7
+        vtbl.8          d16, {q14}, d16
+        vtbl.8          d17, {q14}, d17
+        vtbl.8          d18, {q14}, d18
+        vst1.16         {q0,  q1},  [r0, :128]!
+        vtbl.8          d19, {q14}, d19
+        vtbl.8          d20, {q14}, d20
+        vst1.16         {q2,  q3},  [r0, :128]!
+        vtbl.8          d21, {q14}, d21
+        vtbl.8          d22, {q14}, d22
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vtbl.8          d23, {q14}, d23
+        vst1.16         {q10, q11}, [r0, :128], r1
+        bgt             64b
+        pop             {r4-r5, pc}
+endfunc
+
+// void ipred_cfl_128_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height,
+//                               const int16_t *ac, const int alpha,
+//                               const int bitdepth_max);
+function ipred_cfl_128_16bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldrd            r6,  r7,  [sp, #32]
+        clz             lr,  r3
+        vdup.16         q15, r7       // bitdepth_max
+        adr             r12, L(ipred_cfl_128_tbl)
+        sub             lr,  lr,  #26
+        ldr             lr,  [r12, lr, lsl #2]
+        vrshr.u16       q0,  q15, #1
+        vdup.16         q1,  r6       // alpha
+        add             r12, r12, lr
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        vmov.i16        q14, #0
+        bx              r12
+
+        .align 2
+L(ipred_cfl_128_tbl):
+L(ipred_cfl_splat_tbl):
+        .word L(ipred_cfl_splat_w16) - L(ipred_cfl_128_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_splat_w16) - L(ipred_cfl_128_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_splat_w8)  - L(ipred_cfl_128_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_splat_w4)  - L(ipred_cfl_128_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_splat_w4):
+        vld1.16         {q8, q9}, [r5, :128]!
+        vmull.s16       q2,  d16, d2  // diff = ac * alpha
+        vmull.s16       q3,  d17, d3
+        vmull.s16       q8,  d18, d2
+        vmull.s16       q9,  d19, d3
+        vshr.s32        q10, q2,  #31 // sign = diff >> 15
+        vshr.s32        q11, q3,  #31
+        vshr.s32        q12, q8,  #31
+        vshr.s32        q13, q9,  #31
+        vadd.i32        q2,  q2,  q10 // diff + sign
+        vadd.i32        q3,  q3,  q11
+        vadd.i32        q8,  q8,  q12
+        vadd.i32        q9,  q9,  q13
+        vrshrn.i32      d4,  q2,  #6  // (diff + sign + 32) >> 6 = apply_sign()
+        vrshrn.i32      d5,  q3,  #6
+        vrshrn.i32      d6,  q8,  #6
+        vrshrn.i32      d7,  q9,  #6
+        vadd.i16        q2,  q2,  q0  // dc + apply_sign()
+        vadd.i16        q3,  q3,  q0
+        vmax.s16        q2,  q2,  q14
+        vmax.s16        q3,  q3,  q14
+        vmin.s16        q2,  q2,  q15
+        vmin.s16        q3,  q3,  q15
+        vst1.16         {d4}, [r0, :64], r1
+        vst1.16         {d5}, [r6, :64], r1
+        subs            r4,  r4,  #4
+        vst1.16         {d6}, [r0, :64], r1
+        vst1.16         {d7}, [r6, :64], r1
+        bgt             L(ipred_cfl_splat_w4)
+        pop             {r4-r8, pc}
+L(ipred_cfl_splat_w8):
+        vld1.16         {q8, q9}, [r5, :128]!
+        subs            r4,  r4,  #2
+        vmull.s16       q2,  d16, d2  // diff = ac * alpha
+        vmull.s16       q3,  d17, d3
+        vmull.s16       q8,  d18, d2
+        vmull.s16       q9,  d19, d3
+        vshr.s32        q10, q2,  #31 // sign = diff >> 15
+        vshr.s32        q11, q3,  #31
+        vshr.s32        q12, q8,  #31
+        vshr.s32        q13, q9,  #31
+        vadd.i32        q2,  q2,  q10 // diff + sign
+        vadd.i32        q3,  q3,  q11
+        vadd.i32        q8,  q8,  q12
+        vadd.i32        q9,  q9,  q13
+        vrshrn.i32      d4,  q2,  #6  // (diff + sign + 32) >> 6 = apply_sign()
+        vrshrn.i32      d5,  q3,  #6
+        vrshrn.i32      d6,  q8,  #6
+        vrshrn.i32      d7,  q9,  #6
+        vadd.i16        q2,  q2,  q0  // dc + apply_sign()
+        vadd.i16        q3,  q3,  q0
+        vmax.s16        q2,  q2,  q14
+        vmax.s16        q3,  q3,  q14
+        vmin.s16        q2,  q2,  q15
+        vmin.s16        q3,  q3,  q15
+        vst1.16         {q2}, [r0, :128], r1
+        vst1.16         {q3}, [r6, :128], r1
+        bgt             L(ipred_cfl_splat_w8)
+        pop             {r4-r8, pc}
+L(ipred_cfl_splat_w16):
+        vpush           {q4-q7}
+        add             r12, r5,  r3, lsl #1
+        sub             r1,  r1,  r3, lsl #1
+        mov             lr,  r3
+1:
+        vld1.16         {q6, q7}, [r5, :128]!
+        vmull.s16       q2,  d12, d2  // diff = ac * alpha
+        vld1.16         {q8, q9}, [r12, :128]!
+        vmull.s16       q3,  d13, d3
+        vmull.s16       q4,  d14, d2
+        vmull.s16       q5,  d15, d3
+        vmull.s16       q6,  d16, d2
+        vmull.s16       q7,  d17, d3
+        vmull.s16       q8,  d18, d2
+        vmull.s16       q9,  d19, d3
+        vshr.s32        q10, q2,  #31 // sign = diff >> 15
+        vshr.s32        q11, q3,  #31
+        vshr.s32        q12, q4,  #31
+        vshr.s32        q13, q5,  #31
+        vadd.i32        q2,  q2,  q10 // diff + sign
+        vshr.s32        q10, q6,  #31
+        vadd.i32        q3,  q3,  q11
+        vshr.s32        q11, q7,  #31
+        vadd.i32        q4,  q4,  q12
+        vshr.s32        q12, q8,  #31
+        vadd.i32        q5,  q5,  q13
+        vshr.s32        q13, q9,  #31
+        vadd.i32        q6,  q6,  q10
+        vadd.i32        q7,  q7,  q11
+        vadd.i32        q8,  q8,  q12
+        vadd.i32        q9,  q9,  q13
+        vrshrn.i32      d4,  q2,  #6  // (diff + sign + 32) >> 6 = apply_sign()
+        vrshrn.i32      d5,  q3,  #6
+        vrshrn.i32      d6,  q4,  #6
+        vrshrn.i32      d7,  q5,  #6
+        vadd.i16        q2,  q2,  q0  // dc + apply_sign()
+        vrshrn.i32      d8,  q6,  #6
+        vrshrn.i32      d9,  q7,  #6
+        vadd.i16        q3,  q3,  q0
+        vrshrn.i32      d10, q8,  #6
+        vrshrn.i32      d11, q9,  #6
+        vadd.i16        q4,  q4,  q0
+        vadd.i16        q5,  q5,  q0
+        vmax.s16        q2,  q2,  q14
+        vmax.s16        q3,  q3,  q14
+        vmax.s16        q4,  q4,  q14
+        vmax.s16        q5,  q5,  q14
+        vmin.s16        q2,  q2,  q15
+        vmin.s16        q3,  q3,  q15
+        vmin.s16        q4,  q4,  q15
+        vmin.s16        q5,  q5,  q15
+        subs            r3,  r3,  #16
+        vst1.16         {q2, q3}, [r0, :128]!
+        vst1.16         {q4, q5}, [r6, :128]!
+        bgt             1b
+        subs            r4,  r4,  #2
+        add             r5,  r5,  lr, lsl #1
+        add             r12, r12, lr, lsl #1
+        add             r0,  r0,  r1
+        add             r6,  r6,  r1
+        mov             r3,  lr
+        bgt             1b
+        vpop            {q4-q7}
+        pop             {r4-r8, pc}
+endfunc
+
+// void ipred_cfl_top_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height,
+//                               const int16_t *ac, const int alpha,
+//                               const int bitdepth_max);
+function ipred_cfl_top_16bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldrd            r6,  r7,  [sp, #32]
+        clz             lr,  r3
+        vdup.16         q15, r7       // bitdepth_max
+        adr             r12, L(ipred_cfl_top_tbl)
+        sub             lr,  lr,  #26
+        ldr             lr,  [r12, lr, lsl #2]
+        vdup.16         q1,  r6   // alpha
+        add             r2,  r2,  #2
+        add             r12, r12, lr
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        vmov.i16        q14, #0
+        bx              r12
+
+        .align 2
+L(ipred_cfl_top_tbl):
+        .word 32f - L(ipred_cfl_top_tbl) + CONFIG_THUMB
+        .word 16f - L(ipred_cfl_top_tbl) + CONFIG_THUMB
+        .word 8f  - L(ipred_cfl_top_tbl) + CONFIG_THUMB
+        .word 4f  - L(ipred_cfl_top_tbl) + CONFIG_THUMB
+
+4:
+        vld1.16         {d0}, [r2]
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #2
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w4)
+8:
+        vld1.16         {q0}, [r2]
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #3
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w8)
+16:
+        vld1.16         {q2, q3}, [r2]
+        vadd.i16        q0,  q2,  q3
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #4
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w16)
+32:
+        vld1.16         {q8,  q9},  [r2]!
+        vld1.16         {q10, q11}, [r2]
+        vadd.i16        q8,  q8,  q9
+        vadd.i16        q10, q10, q11
+        vadd.i16        q0,  q8,  q10
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpaddl.u16      d0,  d0
+        vrshrn.i32      d0,  q0,  #5
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w16)
+endfunc
+
+// void ipred_cfl_left_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const topleft,
+//                                const int width, const int height,
+//                                const int16_t *ac, const int alpha,
+//                                const int bitdepth_max);
+function ipred_cfl_left_16bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldrd            r6,  r7,  [sp, #32]
+        sub             r2,  r2,  r4, lsl #1
+        clz             lr,  r3
+        clz             r8,  r4
+        vdup.16         q15, r7       // bitdepth_max
+        adr             r12, L(ipred_cfl_splat_tbl)
+        adr             r7,  L(ipred_cfl_left_tbl)
+        sub             lr,  lr,  #26
+        sub             r8,  r8,  #26
+        ldr             lr,  [r12, lr, lsl #2]
+        ldr             r8,  [r7,  r8, lsl #2]
+        vdup.16         q1,  r6   // alpha
+        add             r12, r12, lr
+        add             r7,  r7,  r8
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        vmov.i16        q14, #0
+        bx              r7
+
+        .align 2
+L(ipred_cfl_left_tbl):
+        .word L(ipred_cfl_left_h32) - L(ipred_cfl_left_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_left_h16) - L(ipred_cfl_left_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_left_h8)  - L(ipred_cfl_left_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_left_h4)  - L(ipred_cfl_left_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_left_h4):
+        vld1.16         {d0}, [r2, :64]
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #2
+        vdup.16         q0,  d0[0]
+        bx              r12
+
+L(ipred_cfl_left_h8):
+        vld1.16         {q0}, [r2, :128]
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #3
+        vdup.16         q0,  d0[0]
+        bx              r12
+
+L(ipred_cfl_left_h16):
+        vld1.16         {q2, q3}, [r2, :128]
+        vadd.i16        q0,  q2,  q3
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpadd.i16       d0,  d0,  d0
+        vrshr.u16       d0,  d0,  #4
+        vdup.16         q0,  d0[0]
+        bx              r12
+
+L(ipred_cfl_left_h32):
+        vld1.16         {q8,  q9},  [r2, :128]!
+        vld1.16         {q10, q11}, [r2, :128]
+        vadd.i16        q8,  q8,  q9
+        vadd.i16        q10, q10, q11
+        vadd.i16        q0,  q8,  q10
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        vpaddl.u16      d0,  d0
+        vrshrn.i32      d0,  q0,  #5
+        vdup.16         q0,  d0[0]
+        bx              r12
+endfunc
+
+// void ipred_cfl_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                           const pixel *const topleft,
+//                           const int width, const int height,
+//                           const int16_t *ac, const int alpha,
+//                           const int bitdepth_max);
+function ipred_cfl_16bpc_neon, export=1
+        push            {r4-r8, lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldrd            r6,  r7,  [sp, #32]
+        sub             r2,  r2,  r4, lsl #1
+        add             r8,  r3,  r4  // width + height
+        vdup.16         q1,  r6       // alpha
+        clz             lr,  r3
+        clz             r6,  r4
+        vdup.32         d16, r8       // width + height
+        vdup.16         q15, r7       // bitdepth_max
+        adr             r7,  L(ipred_cfl_tbl)
+        rbit            r8,  r8       // rbit(width + height)
+        sub             lr,  lr,  #22 // 26 leading bits, minus table offset 4
+        sub             r6,  r6,  #26
+        clz             r8,  r8       // ctz(width + height)
+        ldr             lr,  [r7, lr, lsl #2]
+        ldr             r6,  [r7, r6, lsl #2]
+        neg             r8,  r8       // -ctz(width + height)
+        add             r12, r7,  lr
+        add             r7,  r7,  r6
+        vshr.u32        d16, d16, #1  // (width + height) >> 1
+        vdup.32         d17, r8       // -ctz(width + height)
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        vmov.i16        q14, #0
+        bx              r7
+
+        .align 2
+L(ipred_cfl_tbl):
+        .word L(ipred_cfl_h32) - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_h16) - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_h8)  - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_h4)  - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_w32) - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_w16) - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_w8)  - L(ipred_cfl_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_w4)  - L(ipred_cfl_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_h4):
+        vld1.16         {d0}, [r2, :64]!
+        vpadd.i16       d0,  d0,  d0
+        add             r2,  r2,  #2
+        vpaddl.u16      d0,  d0
+        bx              r12
+L(ipred_cfl_w4):
+        vld1.16         {d1}, [r2]
+        vadd.i32        d0,  d0,  d16
+        vpadd.i16       d1,  d1,  d1
+        vpaddl.u16      d1,  d1
+        cmp             r4,  #4
+        vadd.i32        d0,  d0,  d1
+        vshl.u32        d0,  d0,  d17
+        beq             1f
+        // h = 8/16
+        cmp             r4,  #16
+        movw            lr,  #0x6667
+        movw            r8,  #0xAAAB
+        it              ne
+        movne           lr,  r8
+        vdup.32         d18, lr
+        vmul.i32        d0,  d0,  d18
+        vshr.u32        d0,  d0,  #17
+1:
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w4)
+
+L(ipred_cfl_h8):
+        vld1.16         {q0}, [r2, :128]!
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        add             r2,  r2,  #2
+        vpaddl.u16      d0,  d0
+        bx              r12
+L(ipred_cfl_w8):
+        vld1.16         {q2}, [r2]
+        vadd.i32        d0,  d0,  d16
+        vadd.i16        d1,  d4,  d5
+        vpadd.i16       d1,  d1,  d1
+        vpaddl.u16      d1,  d1
+        cmp             r4,  #8
+        vadd.i32        d0,  d0,  d1
+        vshl.u32        d0,  d0,  d17
+        beq             1f
+        // h = 4/16/32
+        cmp             r4,  #32
+        movw            lr,  #0x6667
+        movw            r8,  #0xAAAB
+        it              ne
+        movne           lr,  r8
+        vdup.32         d18, lr
+        vmul.i32        d0,  d0,  d18
+        vshr.u32        d0,  d0,  #17
+1:
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w8)
+
+L(ipred_cfl_h16):
+        vld1.16         {q2, q3}, [r2, :128]!
+        vadd.i16        q0,  q2,  q3
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        add             r2,  r2,  #2
+        vpaddl.u16      d0,  d0
+        bx              r12
+L(ipred_cfl_w16):
+        vld1.16         {q2, q3}, [r2]
+        vadd.i32        d0,  d0,  d16
+        vadd.i16        q2,  q2,  q3
+        vadd.i16        d1,  d4,  d5
+        vpadd.i16       d1,  d1,  d1
+        vpaddl.u16      d1,  d1
+        cmp             r4,  #16
+        vadd.i32        d0,  d0,  d1
+        vshl.u32        d0,  d0,  d17
+        beq             1f
+        // h = 4/8/32/64
+        tst             r4,  #(32+16+8)  // 16 added to make a consecutive bitmask
+        movw            lr,  #0x6667
+        movw            r8,  #0xAAAB
+        it              ne
+        movne           lr,  r8
+        vdup.32         d18, lr
+        vmul.i32        d0,  d0,  d18
+        vshr.u32        d0,  d0,  #17
+1:
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w16)
+
+L(ipred_cfl_h32):
+        vld1.16         {q2, q3},   [r2, :128]!
+        vld1.16         {q10, q11}, [r2, :128]!
+        vadd.i16        q2,  q2,  q3
+        vadd.i16        q10, q10, q11
+        vadd.i16        q0,  q2,  q10
+        vadd.i16        d0,  d0,  d1
+        vpadd.i16       d0,  d0,  d0
+        add             r2,  r2,  #2
+        vpaddl.u16      d0,  d0
+        bx              r12
+L(ipred_cfl_w32):
+        vld1.16         {q2, q3},   [r2]!
+        vadd.i32        d0,  d0,  d16
+        vld1.16         {q10, q11}, [r2]!
+        vadd.i16        q2,  q2,  q3
+        vadd.i16        q10, q10, q11
+        vadd.i16        q2,  q2,  q10
+        vadd.i16        d1,  d4,  d5
+        vpadd.i16       d1,  d1,  d1
+        vpaddl.u16      d1,  d1
+        cmp             r4,  #32
+        vadd.i32        d0,  d0,  d1
+        vshl.u32        d0,  d0,  d17
+        beq             1f
+        // h = 8/16/64
+        cmp             r4,  #8
+        movw            lr,  #0x6667
+        movw            r8,  #0xAAAB
+        it              ne
+        movne           lr,  r8
+        vdup.32         d18, lr
+        vmul.i32        d0,  d0,  d18
+        vshr.u32        d0,  d0,  #17
+1:
+        vdup.16         q0,  d0[0]
+        b               L(ipred_cfl_splat_w16)
+endfunc
+
+// void cfl_ac_420_16bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                            const ptrdiff_t stride, const int w_pad,
+//                            const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_420_16bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        clz             r8,  r5
+        lsl             r4,  r4,  #2
+        adr             r7,  L(ipred_cfl_ac_420_tbl)
+        sub             r8,  r8,  #27
+        ldr             r8,  [r7, r8, lsl #2]
+        vmov.i32        q8,  #0
+        vmov.i32        q9,  #0
+        vmov.i32        q10, #0
+        vmov.i32        q11, #0
+        add             r7,  r7,  r8
+        sub             r8,  r6,  r4  // height - h_pad
+        rbit            lr,  r5       // rbit(width)
+        rbit            r12, r6       // rbit(height)
+        clz             lr,  lr       // ctz(width)
+        clz             r12, r12      // ctz(height)
+        add             lr,  lr,  r12 // log2sz
+        add             r12, r1,  r2
+        vdup.32         d31, lr
+        lsl             r2,  r2,  #1
+        vneg.s32        d31, d31      // -log2sz
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_420_tbl):
+        .word L(ipred_cfl_ac_420_w16) - L(ipred_cfl_ac_420_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w8)  - L(ipred_cfl_ac_420_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w4)  - L(ipred_cfl_ac_420_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_420_w4):
+1:      // Copy and subsample input
+        vld1.16         {q0}, [r1,  :128], r2
+        vld1.16         {q1}, [r12, :128], r2
+        vld1.16         {q2}, [r1,  :128], r2
+        vld1.16         {q3}, [r12, :128], r2
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        q2,  q2,  q3
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d4,  d5
+        vshl.i16        q0,  q0,  #1
+        subs            r8,  r8,  #2
+        vst1.16         {q0}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        bgt             1b
+        cmp             r4,  #0
+        vmov            d0,  d1
+        vmov            d2,  d1
+        vmov            d3,  d1
+L(ipred_cfl_ac_420_w4_hpad):
+        beq             3f // This assumes that all callers already did "cmp r4, #0"
+2:      // Vertical padding (h_pad > 0)
+        subs            r4,  r4,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             2b
+3:
+L(ipred_cfl_ac_420_w4_calc_subtract_dc):
+        // Aggregate the sums
+        vadd.i32        q8,  q8,  q9
+        vadd.i32        q10, q10, q11
+        vadd.i32        q0,  q8,  q10
+        vadd.i32        d0,  d0,  d1
+        vpadd.i32       d0,  d0,  d0  // sum
+        sub             r0,  r0,  r6, lsl #3
+        vrshl.u32       d16, d0,  d31 // (sum + (1 << (log2sz - 1))) >>= log2sz
+        vdup.16         q8,  d16[0]
+6:      // Subtract dc from ac
+        vld1.16         {q0, q1}, [r0, :128]
+        subs            r6,  r6,  #4
+        vsub.i16        q0,  q0,  q8
+        vsub.i16        q1,  q1,  q8
+        vst1.16         {q0, q1}, [r0, :128]!
+        bgt             6b
+        pop             {r4-r8, pc}
+
+L(ipred_cfl_ac_420_w8):
+        cmp             r3,  #0
+        bne             L(ipred_cfl_ac_420_w8_wpad)
+1:      // Copy and subsample input, without padding
+        vld1.16         {q0,  q1},  [r1,  :128], r2
+        vld1.16         {q2,  q3},  [r12, :128], r2
+        vld1.16         {q12, q13}, [r1,  :128], r2
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        q1,  q1,  q3
+        vld1.16         {q2,  q3},  [r12, :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vadd.i16        q12, q12, q2
+        vadd.i16        q13, q13, q3
+        vpadd.i16       d2,  d24, d25
+        vpadd.i16       d3,  d26, d27
+        vshl.i16        q0,  q0,  #1
+        vshl.i16        q1,  q1,  #1
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q1
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_420_w8_wpad):
+1:      // Copy and subsample input, padding 4
+        vld1.16         {q0}, [r1,  :128], r2
+        vld1.16         {q1}, [r12, :128], r2
+        vld1.16         {q2}, [r1,  :128], r2
+        vld1.16         {q3}, [r12, :128], r2
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        q2,  q2,  q3
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d4,  d5
+        vshl.i16        q0,  q0,  #1
+        vdup.16         d3,  d1[3]
+        vmov            d2,  d1
+        vdup.16         d1,  d0[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q1
+
+L(ipred_cfl_ac_420_w8_hpad):
+        beq             3f // This assumes that all callers already did "cmp r4, #0"
+2:      // Vertical padding (h_pad > 0)
+        subs            r4,  r4,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             2b
+3:
+
+        // Double the height and reuse the w4 summing/subtracting
+        lsl             r6,  r6,  #1
+        b               L(ipred_cfl_ac_420_w4_calc_subtract_dc)
+
+L(ipred_cfl_ac_420_w16):
+        adr             r7,  L(ipred_cfl_ac_420_w16_tbl)
+        ldr             r3,  [r7, r3, lsl #2]
+        add             r7,  r7,  r3
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_420_w16_tbl):
+        .word L(ipred_cfl_ac_420_w16_wpad0) - L(ipred_cfl_ac_420_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w16_wpad1) - L(ipred_cfl_ac_420_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w16_wpad2) - L(ipred_cfl_ac_420_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_420_w16_wpad3) - L(ipred_cfl_ac_420_w16_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_420_w16_wpad0):
+        sub             r2,  r2,  #32
+1:      // Copy and subsample input, without padding
+        vld1.16         {q0,  q1},  [r1,  :128]!
+        vld1.16         {q12, q13}, [r12, :128]!
+        vld1.16         {q2,  q3},  [r1,  :128], r2
+        vadd.i16        q0,  q0,  q12
+        vadd.i16        q1,  q1,  q13
+        vld1.16         {q12, q13}, [r12, :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vadd.i16        q2,  q2,  q12
+        vadd.i16        q3,  q3,  q13
+        vpadd.i16       d2,  d4,  d5
+        vpadd.i16       d3,  d6,  d7
+        vshl.i16        q0,  q0,  #1
+        vshl.i16        q1,  q1,  #1
+        subs            r8,  r8,  #1
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad1):
+        sub             r2,  r2,  #32
+1:      // Copy and subsample input, padding 4
+        vld1.16         {q0,  q1},  [r1,  :128]!
+        vld1.16         {q12, q13}, [r12, :128]!
+        vld1.16         {q2},       [r1,  :128], r2
+        vadd.i16        q0,  q0,  q12
+        vadd.i16        q1,  q1,  q13
+        vld1.16         {q12},     [r12, :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vadd.i16        q2,  q2,  q12
+        vpadd.i16       d1,  d2,  d3
+        vpadd.i16       d2,  d4,  d5
+        vshl.i16        q0,  q0,  #1
+        vshl.i16        d2,  d2,  #1
+        subs            r8,  r8,  #1
+        vdup.16         d3,  d2[3]
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad2):
+1:      // Copy and subsample input, padding 8
+        vld1.16         {q0,  q1},  [r1,  :128], r2
+        vld1.16         {q12, q13}, [r12, :128], r2
+        vadd.i16        q0,  q0,  q12
+        vadd.i16        q1,  q1,  q13
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vshl.i16        q0,  q0,  #1
+        subs            r8,  r8,  #1
+        vdup.16         q1,  d1[3]
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad3):
+1:      // Copy and subsample input, padding 12
+        vld1.16         {q0},  [r1,  :128], r2
+        vld1.16         {q12}, [r12, :128], r2
+        vadd.i16        q0,  q0,  q12
+        vpadd.i16       d0,  d0,  d1
+        vshl.i16        d0,  d0,  #1
+        subs            r8,  r8,  #1
+        vdup.16         q1,  d0[3]
+        vdup.16         d1,  d0[3]
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_hpad):
+        beq             3f // This assumes that all callers already did "cmp r4, #0"
+2:      // Vertical padding (h_pad > 0)
+        subs            r4,  r4,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             2b
+3:
+
+        // Quadruple the height and reuse the w4 summing/subtracting
+        lsl             r6,  r6,  #2
+        b               L(ipred_cfl_ac_420_w4_calc_subtract_dc)
+endfunc
+
+// void cfl_ac_422_16bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                            const ptrdiff_t stride, const int w_pad,
+//                            const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_422_16bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        clz             r8,  r5
+        lsl             r4,  r4,  #2
+        adr             r7,  L(ipred_cfl_ac_422_tbl)
+        sub             r8,  r8,  #27
+        ldr             r8,  [r7, r8, lsl #2]
+        vmov.i16        q8,  #0
+        vmov.i16        q9,  #0
+        vmov.i16        q10, #0
+        vmov.i16        q11, #0
+        add             r7,  r7,  r8
+        sub             r8,  r6,  r4  // height - h_pad
+        rbit            lr,  r5       // rbit(width)
+        rbit            r12, r6       // rbit(height)
+        clz             lr,  lr       // ctz(width)
+        clz             r12, r12      // ctz(height)
+        add             lr,  lr,  r12 // log2sz
+        add             r12, r1,  r2
+        vdup.32         d31, lr
+        lsl             r2,  r2,  #1
+        vneg.s32        d31, d31      // -log2sz
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_422_tbl):
+        .word L(ipred_cfl_ac_422_w16) - L(ipred_cfl_ac_422_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w8) - L(ipred_cfl_ac_422_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w4) - L(ipred_cfl_ac_422_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_422_w4):
+1:      // Copy and subsample input
+        vld1.16         {q0}, [r1,  :128], r2
+        vld1.16         {q1}, [r12, :128], r2
+        vld1.16         {q2}, [r1,  :128], r2
+        vld1.16         {q3}, [r12, :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vpadd.i16       d2,  d4,  d5
+        vpadd.i16       d3,  d6,  d7
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q1,  q1,  #2
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            d0,  d3
+        vmov            d1,  d3
+        vmov            d2,  d3
+        b               L(ipred_cfl_ac_420_w4_hpad)
+
+L(ipred_cfl_ac_422_w8):
+        cmp             r3,  #0
+        bne             L(ipred_cfl_ac_422_w8_wpad)
+1:      // Copy and subsample input, without padding
+        vld1.16         {q0,  q1},  [r1,  :128], r2
+        vld1.16         {q2,  q3},  [r12, :128], r2
+        vld1.16         {q12, q13}, [r1,  :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vpadd.i16       d2,  d4,  d5
+        vpadd.i16       d3,  d6,  d7
+        vld1.16         {q2, q3}, [r12, :128], r2
+        vpadd.i16       d24, d24, d25
+        vpadd.i16       d25, d26, d27
+        vpadd.i16       d26, d4,  d5
+        vpadd.i16       d27, d6,  d7
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q1,  q1,  #2
+        vshl.i16        q2,  q12, #2
+        vshl.i16        q3,  q13, #2
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q3
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_422_w8_wpad):
+1:      // Copy and subsample input, padding 4
+        vld1.16         {q0},  [r1,  :128], r2
+        vld1.16         {q2},  [r12, :128], r2
+        vld1.16         {q12}, [r1,  :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d4,  d5
+        vld1.16         {q2, q3}, [r12, :128], r2
+        vpadd.i16       d24, d24, d25
+        vpadd.i16       d25, d4,  d5
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q12, q12, #2
+        vdup.16         d7,  d25[3]
+        vmov            d6,  d25
+        vdup.16         d5,  d24[3]
+        vmov            d4,  d24
+        vdup.16         d3,  d1[3]
+        vmov            d2,  d1
+        vdup.16         d1,  d0[3]
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q3
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_422_w16):
+        adr             r7,  L(ipred_cfl_ac_422_w16_tbl)
+        ldr             r3,  [r7, r3, lsl #2]
+        add             r7,  r7,  r3
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_422_w16_tbl):
+        .word L(ipred_cfl_ac_422_w16_wpad0) - L(ipred_cfl_ac_422_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w16_wpad1) - L(ipred_cfl_ac_422_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w16_wpad2) - L(ipred_cfl_ac_422_w16_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_422_w16_wpad3) - L(ipred_cfl_ac_422_w16_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_422_w16_wpad0):
+        sub             r2,  r2,  #32
+1:      // Copy and subsample input, without padding
+        vld1.16         {q0,  q1},  [r1,  :128]!
+        vld1.16         {q2,  q3},  [r12, :128]!
+        vld1.16         {q12, q13}, [r1,  :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vpadd.i16       d2,  d24, d25
+        vpadd.i16       d3,  d26, d27
+        vld1.16         {q12, q13}, [r12, :128], r2
+        vpadd.i16       d4,  d4,  d5
+        vpadd.i16       d5,  d6,  d7
+        vpadd.i16       d6,  d24, d25
+        vpadd.i16       d7,  d26, d27
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q1,  q1,  #2
+        vshl.i16        q2,  q2,  #2
+        vshl.i16        q3,  q3,  #2
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad1):
+        sub             r2,  r2,  #32
+1:      // Copy and subsample input, padding 4
+        vld1.16         {q0,  q1},  [r1,  :128]!
+        vld1.16         {q2,  q3},  [r12, :128]!
+        vld1.16         {q12},      [r1,  :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vpadd.i16       d2,  d24, d25
+        vld1.16         {q12},      [r12, :128], r2
+        vpadd.i16       d4,  d4,  d5
+        vpadd.i16       d5,  d6,  d7
+        vpadd.i16       d6,  d24, d25
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        d2,  d2,  #2
+        vshl.i16        q2,  q2,  #2
+        vshl.i16        d6,  d6,  #2
+        vdup.16         d3,  d2[3]
+        vdup.16         d7,  d6[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad2):
+1:      // Copy and subsample input, padding 8
+        vld1.16         {q0,  q1},  [r1,  :128], r2
+        vld1.16         {q2,  q3},  [r12, :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d2,  d3
+        vpadd.i16       d4,  d4,  d5
+        vpadd.i16       d5,  d6,  d7
+        vshl.i16        q0,  q0,  #2
+        vshl.i16        q2,  q2,  #2
+        vdup.16         q1,  d1[3]
+        vdup.16         q3,  d5[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad3):
+1:      // Copy and subsample input, padding 12
+        vld1.16         {q0}, [r1,  :128], r2
+        vld1.16         {q2}, [r12, :128], r2
+        vpadd.i16       d0,  d0,  d1
+        vpadd.i16       d1,  d4,  d5
+        vshl.i16        q0,  q0,  #2
+        vdup.16         q3,  d1[3]
+        vdup.16         q1,  d0[3]
+        vdup.16         d5,  d1[3]
+        vmov            d4,  d1
+        vdup.16         d1,  d0[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+endfunc
+
+// void cfl_ac_444_16bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                            const ptrdiff_t stride, const int w_pad,
+//                            const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_444_16bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+        ldr             r6,  [sp, #32]
+        clz             r8,  r5
+        lsl             r4,  r4,  #2
+        adr             r7,  L(ipred_cfl_ac_444_tbl)
+        sub             r8,  r8,  #26
+        ldr             r8,  [r7, r8, lsl #2]
+        vmov.i16        q8,  #0
+        vmov.i16        q9,  #0
+        vmov.i16        q10, #0
+        vmov.i16        q11, #0
+        add             r7,  r7,  r8
+        sub             r8,  r6,  r4  // height - h_pad
+        rbit            lr,  r5       // rbit(width)
+        rbit            r12, r6       // rbit(height)
+        clz             lr,  lr       // ctz(width)
+        clz             r12, r12      // ctz(height)
+        add             lr,  lr,  r12 // log2sz
+        add             r12, r1,  r2
+        vdup.32         d31, lr
+        lsl             r2,  r2,  #1
+        vneg.s32        d31, d31      // -log2sz
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_444_tbl):
+        .word L(ipred_cfl_ac_444_w32) - L(ipred_cfl_ac_444_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w16) - L(ipred_cfl_ac_444_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w8)  - L(ipred_cfl_ac_444_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w4)  - L(ipred_cfl_ac_444_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_444_w4):
+1:      // Copy and expand input
+        vld1.16         {d0}, [r1,  :64], r2
+        vld1.16         {d1}, [r12, :64], r2
+        vld1.16         {d2}, [r1,  :64], r2
+        vld1.16         {d3}, [r12, :64], r2
+        vshl.i16        q0,  q0,  #3
+        vshl.i16        q1,  q1,  #3
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        bgt             1b
+        cmp             r4,  #0
+        vmov            d0,  d3
+        vmov            d1,  d3
+        vmov            d2,  d3
+        b               L(ipred_cfl_ac_420_w4_hpad)
+
+L(ipred_cfl_ac_444_w8):
+1:      // Copy and expand input
+        vld1.16         {q0}, [r1,  :128], r2
+        vld1.16         {q1}, [r12, :128], r2
+        vld1.16         {q2}, [r1,  :128], r2
+        vld1.16         {q3}, [r12, :128], r2
+        vshl.i16        q0,  q0,  #3
+        vshl.i16        q1,  q1,  #3
+        vshl.i16        q2,  q2,  #3
+        vshl.i16        q3,  q3,  #3
+        subs            r8,  r8,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q3
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_444_w16):
+        cmp             r3,  #0
+        bne             L(ipred_cfl_ac_444_w16_wpad)
+1:      // Copy and expand input, without padding
+        vld1.16         {q0, q1}, [r1,  :128], r2
+        vld1.16         {q2, q3}, [r12, :128], r2
+        vshl.i16        q0,  q0,  #3
+        vshl.i16        q1,  q1,  #3
+        vshl.i16        q2,  q2,  #3
+        vshl.i16        q3,  q3,  #3
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_444_w16_wpad):
+1:      // Copy and expand input, padding 8
+        vld1.16         {q0}, [r1,  :128], r2
+        vld1.16         {q2}, [r12, :128], r2
+        vshl.i16        q0,  q0,  #3
+        vshl.i16        q2,  q2,  #3
+        vdup.16         q1,  d1[3]
+        vdup.16         q3,  d5[3]
+        subs            r8,  r8,  #2
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        vmov            q0,  q2
+        vmov            q1,  q3
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_444_w32):
+        adr             r7,  L(ipred_cfl_ac_444_w32_tbl)
+        ldr             r3,  [r7, r3, lsl #1] // (w3>>1) << 2
+        asr             r2,  r2,  #1
+        add             r7,  r7,  r3
+        bx              r7
+
+        .align 2
+L(ipred_cfl_ac_444_w32_tbl):
+        .word L(ipred_cfl_ac_444_w32_wpad0) - L(ipred_cfl_ac_444_w32_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w32_wpad2) - L(ipred_cfl_ac_444_w32_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w32_wpad4) - L(ipred_cfl_ac_444_w32_tbl) + CONFIG_THUMB
+        .word L(ipred_cfl_ac_444_w32_wpad6) - L(ipred_cfl_ac_444_w32_tbl) + CONFIG_THUMB
+
+L(ipred_cfl_ac_444_w32_wpad0):
+        sub             r2,  r2,  #32
+1:      // Copy and expand input, without padding
+        vld1.16         {q0, q1}, [r1, :128]!
+        vld1.16         {q2, q3}, [r1, :128], r2
+        vshl.i16        q0,  q0,  #3
+        vshl.i16        q1,  q1,  #3
+        vshl.i16        q2,  q2,  #3
+        vshl.i16        q3,  q3,  #3
+        subs            r8,  r8,  #1
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad2):
+        sub             r2,  r2,  #32
+1:      // Copy and expand input, padding 8
+        vld1.16         {q0, q1}, [r1, :128]!
+        vld1.16         {q2},     [r1, :128], r2
+        vshl.i16        q0,  q0,  #3
+        vshl.i16        q1,  q1,  #3
+        vshl.i16        q2,  q2,  #3
+        subs            r8,  r8,  #1
+        vst1.16         {q0, q1}, [r0, :128]!
+        vdup.16         q3,  d5[3]
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad4):
+1:      // Copy and expand input, padding 16
+        vld1.16         {q0, q1}, [r1, :128], r2
+        vshl.i16        q0,  q0,  #3
+        vshl.i16        q1,  q1,  #3
+        subs            r8,  r8,  #1
+        vst1.16         {q0, q1}, [r0, :128]!
+        vdup.16         q2,  d3[3]
+        vdup.16         q3,  d3[3]
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad6):
+1:      // Copy and expand input, padding 24
+        vld1.16         {q0}, [r1, :128], r2
+        vshl.i16        q0,  q0,  #3
+        subs            r8,  r8,  #1
+        vdup.16         q1,  d1[3]
+        vst1.16         {q0, q1}, [r0, :128]!
+        vdup.16         q2,  d1[3]
+        vdup.16         q3,  d1[3]
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             1b
+        cmp             r4,  #0
+
+L(ipred_cfl_ac_444_w32_hpad):
+        beq             3f // This assumes that all callers already did "cmp r4, #0"
+2:      // Vertical padding (h_pad > 0)
+        subs            r4,  r4,  #1
+        vst1.16         {q0, q1}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d0
+        vaddw.u16       q9,  q9,  d1
+        vaddw.u16       q10, q10, d2
+        vaddw.u16       q11, q11, d3
+        vst1.16         {q2, q3}, [r0, :128]!
+        vaddw.u16       q8,  q8,  d4
+        vaddw.u16       q9,  q9,  d5
+        vaddw.u16       q10, q10, d6
+        vaddw.u16       q11, q11, d7
+        bgt             2b
+3:
+
+        //  Multiply the height by eight and reuse the w4 subtracting
+        lsl             r6,  r6,  #3
+        b               L(ipred_cfl_ac_420_w4_calc_subtract_dc)
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/itx.S b/media/libdav1d/src/src/arm/32/itx.S
new file mode 100644
index 0000000000..9ba1df7a68
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/itx.S
@@ -0,0 +1,3368 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// The exported functions in this file have got the following signature:
+// void itxfm_add(pixel *dst, ptrdiff_t dst_stride, coef *coeff, int eob);
+
+// Most of the functions use the following register layout:
+// r0-r3   external parameters
+// r4      function pointer to first transform
+// r5      function pointer to second transform
+// r6      output parameter for helper function
+// r7      input parameter for helper function
+// r8      input stride for helper function
+// r9      scratch variable for helper functions
+// r10-r11 pointer to list of eob thresholds, eob threshold value,
+//         scratch variables within helper functions (backed up)
+
+// The SIMD registers most often use the following layout:
+// d0-d3   multiplication coefficients
+// d4-d7   scratch registers
+// d8-d15  unused in some transforms, used for scratch registers in others
+// d16-v31 inputs/outputs of transforms
+
+// Potential further optimizations, that are left unimplemented for now:
+// - Trying to keep multiplication coefficients in registers across multiple
+//   transform functions. (The register layout is designed to potentially
+//   allow this.)
+// - Use a simplified version of the transforms themselves for cases where
+//   we know a significant number of inputs are zero. E.g. if the eob value
+//   indicates only a quarter of input values are set, for idct16 and up,
+//   a significant amount of calculation can be skipped, at the cost of more
+//   code duplication and special casing.
+
+const idct_coeffs, align=4
+        // idct4
+        .short          2896, 2896*8, 1567, 3784
+        // idct8
+        .short          799, 4017, 3406, 2276
+        // idct16
+        .short          401, 4076, 3166, 2598
+        .short          1931, 3612, 3920, 1189
+        // idct32
+        .short          201, 4091, 3035, 2751
+        .short          1751, 3703, 3857, 1380
+        .short          995, 3973, 3513, 2106
+        .short          2440, 3290, 4052, 601
+endconst
+
+const idct64_coeffs, align=4
+        .short          101*8, 4095*8, 2967*8, -2824*8
+        .short          1660*8, 3745*8, 3822*8, -1474*8
+        .short          4076, 401, 4017, 799
+
+        .short          4036*8, -700*8, 2359*8, 3349*8
+        .short          3461*8, -2191*8, 897*8, 3996*8
+        .short          -3166, -2598, -799, -4017
+
+        .short          501*8, 4065*8, 3229*8, -2520*8
+        .short          2019*8, 3564*8, 3948*8, -1092*8
+        .short          3612, 1931, 2276, 3406
+
+        .short          4085*8, -301*8, 2675*8, 3102*8
+        .short          3659*8, -1842*8, 1285*8, 3889*8
+        .short          -3920, -1189, -3406, -2276
+endconst
+
+const iadst4_coeffs, align=4
+        // .h[4-5] can be interpreted as .s[2]
+        .short          1321, 3803, 2482, 3344, 3344, 0
+endconst
+
+const iadst8_coeffs, align=4
+        .short          4076, 401, 3612, 1931
+        .short          2598, 3166, 1189, 3920
+        // idct_coeffs
+        .short          2896, 0, 1567, 3784, 0, 0, 0, 0
+endconst
+
+const iadst16_coeffs, align=4
+        .short          4091, 201, 3973, 995
+        .short          3703, 1751, 3290, 2440
+        .short          2751, 3035, 2106, 3513
+        .short          1380, 3857, 601, 4052
+endconst
+
+.macro vmull_vmlal d0, s0, s1, c0, c1
+        vmull.s16       \d0, \s0, \c0
+        vmlal.s16       \d0, \s1, \c1
+.endm
+
+.macro vmull_vmlal_8h d0, d1, s0, s1, s2, s3, c0, c1
+        vmull.s16       \d0, \s0, \c0
+        vmlal.s16       \d0, \s2, \c1
+        vmull.s16       \d1, \s1, \c0
+        vmlal.s16       \d1, \s3, \c1
+.endm
+
+.macro vmull_vmlsl d0, s0, s1, c0, c1
+        vmull.s16       \d0, \s0, \c0
+        vmlsl.s16       \d0, \s1, \c1
+.endm
+
+.macro vmull_vmlsl_8h d0, d1, s0, s1, s2, s3, c0, c1
+        vmull.s16       \d0, \s0, \c0
+        vmlsl.s16       \d0, \s2, \c1
+        vmull.s16       \d1, \s1, \c0
+        vmlsl.s16       \d1, \s3, \c1
+.endm
+
+.macro vqrshrn_8h d0, d1, s0, s1, shift
+        vqrshrn.s32     \d0, \s0, \shift
+        vqrshrn.s32     \d1, \s1, \shift
+.endm
+
+.macro scale_input c, r0, r1, r2 r3, r4, r5, r6, r7
+        vqrdmulh.s16    \r0, \r0, \c
+        vqrdmulh.s16    \r1, \r1, \c
+.ifnb \r2
+        vqrdmulh.s16    \r2, \r2, \c
+        vqrdmulh.s16    \r3, \r3, \c
+.endif
+.ifnb \r4
+        vqrdmulh.s16    \r4, \r4, \c
+        vqrdmulh.s16    \r5, \r5, \c
+        vqrdmulh.s16    \r6, \r6, \c
+        vqrdmulh.s16    \r7, \r7, \c
+.endif
+.endm
+
+.macro load_add_store load, shift, addsrc, adddst, narrowsrc, narrowdst, store, dst, src, shiftbits=4
+.ifnb \load
+        vld1.8          {\load},  [\src, :64], r1
+.endif
+.ifnb \shift
+        vrshr.s16       \shift,  \shift,  #\shiftbits
+.endif
+.ifnb \addsrc
+        vaddw.u8        \adddst, \adddst, \addsrc
+.endif
+.ifnb \narrowsrc
+        vqmovun.s16     \narrowdst, \narrowsrc
+.endif
+.ifnb \store
+        vst1.8          {\store},  [\dst, :64], r1
+.endif
+.endm
+.macro load_add_store_8x8 dst, src, shiftbits=4
+        mov             \src, \dst
+        load_add_store  d2,  q8,    ,    ,    ,    ,    , \dst, \src, \shiftbits
+        load_add_store  d3,  q9,    ,    ,    ,    ,    , \dst, \src, \shiftbits
+        load_add_store  d4,  q10, d2,  q8,    ,    ,    , \dst, \src, \shiftbits
+        load_add_store  d5,  q11, d3,  q9,  q8,  d2,    , \dst, \src, \shiftbits
+        load_add_store  d6,  q12, d4,  q10, q9,  d3,  d2, \dst, \src, \shiftbits
+        load_add_store  d7,  q13, d5,  q11, q10, d4,  d3, \dst, \src, \shiftbits
+        load_add_store  d2,  q14, d6,  q12, q11, d5,  d4, \dst, \src, \shiftbits
+        load_add_store  d3,  q15, d7,  q13, q12, d6,  d5, \dst, \src, \shiftbits
+        load_add_store    ,     , d2,  q14, q13, d7,  d6, \dst, \src, \shiftbits
+        load_add_store    ,     , d3,  q15, q14, d2,  d7, \dst, \src, \shiftbits
+        load_add_store    ,     ,   ,     , q15, d3,  d2, \dst, \src, \shiftbits
+        load_add_store    ,     ,   ,     ,    ,   ,  d3, \dst, \src, \shiftbits
+.endm
+.macro load_add_store_8x4 dst, src
+        mov             \src, \dst
+        load_add_store  d2,  q8,    ,    ,    ,    ,    ,  \dst, \src
+        load_add_store  d3,  q9,    ,    ,    ,    ,    ,  \dst, \src
+        load_add_store  d4,  q10, d2,  q8,    ,    ,    ,  \dst, \src
+        load_add_store  d5,  q11, d3,  q9,  q8,  d2,    ,  \dst, \src
+        load_add_store    ,     , d4,  q10, q9,  d3,  d2,  \dst, \src
+        load_add_store    ,     , d5,  q11, q10, d4,  d3,  \dst, \src
+        load_add_store    ,     ,   ,     , q11, d5,  d4,  \dst, \src
+        load_add_store    ,     ,   ,     ,    ,   ,  d5,  \dst, \src
+.endm
+.macro load_add_store4 load, shift, addsrc, adddst, narrowsrc, narrowdst, store, dst, src
+.ifnb \load
+        vld1.32         {\load[0]},  [\src, :32], r1
+.endif
+.ifnb \shift
+        vrshr.s16       \shift,  \shift,  #4
+.endif
+.ifnb \load
+        vld1.32         {\load[1]},  [\src, :32], r1
+.endif
+.ifnb \addsrc
+        vaddw.u8        \adddst, \adddst, \addsrc
+.endif
+.ifnb \store
+        vst1.32         {\store[0]},  [\dst, :32], r1
+.endif
+.ifnb \narrowsrc
+        vqmovun.s16     \narrowdst, \narrowsrc
+.endif
+.ifnb \store
+        vst1.32         {\store[1]},  [\dst, :32], r1
+.endif
+.endm
+.macro load_add_store_4x16 dst, src
+        mov             \src, \dst
+        load_add_store4 d0,    ,    ,    ,    ,    ,    ,  \dst, \src
+        load_add_store4 d1,  q8,    ,    ,    ,    ,    ,  \dst, \src
+        load_add_store4 d2,  q9,  d0,  q8,    ,    ,    ,  \dst, \src
+        load_add_store4 d3,  q10, d1,  q9,  q8,  d0,    ,  \dst, \src
+        load_add_store4 d4,  q11, d2,  q10, q9,  d1,  d0,  \dst, \src
+        load_add_store4 d5,  q12, d3,  q11, q10, d2,  d1,  \dst, \src
+        load_add_store4 d6,  q13, d4,  q12, q11, d3,  d2,  \dst, \src
+        load_add_store4 d7,  q14, d5,  q13, q12, d4,  d3,  \dst, \src
+        load_add_store4   ,  q15, d6,  q14, q13, d5,  d4,  \dst, \src
+        load_add_store4   ,     , d7,  q15, q14, d6,  d5,  \dst, \src
+        load_add_store4   ,     ,   ,     , q15, d7,  d6,  \dst, \src
+        load_add_store4   ,     ,   ,     ,    ,   ,  d7,  \dst, \src
+.endm
+.macro load_add_store_4x8 dst, src
+        mov             \src, \dst
+        load_add_store4 d0,    ,    ,    ,    ,    ,    ,  \dst, \src
+        load_add_store4 d1,  q8,    ,    ,    ,    ,    ,  \dst, \src
+        load_add_store4 d2,  q9,  d0,  q8,    ,    ,    ,  \dst, \src
+        load_add_store4 d3,  q10, d1,  q9,  q8,  d0,    ,  \dst, \src
+        load_add_store4   ,  q11, d2,  q10, q9,  d1,  d0,  \dst, \src
+        load_add_store4   ,     , d3,  q11, q10, d2,  d1,  \dst, \src
+        load_add_store4   ,     ,   ,     , q11, d3,  d2,  \dst, \src
+        load_add_store4   ,     ,   ,     ,    ,   ,  d3,  \dst, \src
+.endm
+
+.macro idct_dc w, h, shift
+        cmp             r3,  #0
+        bne             1f
+        vmov.i16        d30, #0
+        movw            r12, #2896*8
+        vld1.16         {d16[]},  [r2, :16]
+        vdup.16         d0,  r12
+        vqrdmulh.s16    d16, d16, d0[0]
+        vst1.16         {d30[0]}, [r2, :16]
+.if (\w == 2*\h) || (2*\w == \h)
+        vqrdmulh.s16    d16, d16, d0[0]
+.endif
+.if \shift > 0
+        vrshr.s16       d16, d16, #\shift
+.endif
+        vqrdmulh.s16    d20, d16, d0[0]
+        mov             r3,  #\h
+        vrshr.s16       d16, d20, #4
+        vrshr.s16       d17, d20, #4
+        b               idct_dc_w\w\()_neon
+1:
+.endm
+
+function idct_dc_w4_neon
+1:
+        vld1.32         {d0[0]}, [r0, :32], r1
+        vld1.32         {d0[1]}, [r0, :32], r1
+        vld1.32         {d1[0]}, [r0, :32], r1
+        vld1.32         {d1[1]}, [r0, :32], r1
+        subs            r3,  r3,  #4
+        sub             r0,  r0,  r1, lsl #2
+        vaddw.u8        q10, q8,  d0
+        vqmovun.s16     d0,  q10
+        vaddw.u8        q11, q8,  d1
+        vst1.32         {d0[0]}, [r0, :32], r1
+        vqmovun.s16     d1,  q11
+        vst1.32         {d0[1]}, [r0, :32], r1
+        vst1.32         {d1[0]}, [r0, :32], r1
+        vst1.32         {d1[1]}, [r0, :32], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+function idct_dc_w8_neon
+1:
+        vld1.8          {d0}, [r0, :64], r1
+        vld1.8          {d1}, [r0, :64], r1
+        vld1.8          {d2}, [r0, :64], r1
+        vaddw.u8        q10, q8,  d0
+        vld1.8          {d3}, [r0, :64], r1
+        sub             r0,  r0,  r1, lsl #2
+        subs            r3,  r3,  #4
+        vaddw.u8        q11, q8,  d1
+        vqmovun.s16     d0,  q10
+        vaddw.u8        q12, q8,  d2
+        vqmovun.s16     d1,  q11
+        vaddw.u8        q13, q8,  d3
+        vst1.8          {d0}, [r0, :64], r1
+        vqmovun.s16     d2,  q12
+        vst1.8          {d1}, [r0, :64], r1
+        vqmovun.s16     d3,  q13
+        vst1.8          {d2}, [r0, :64], r1
+        vst1.8          {d3}, [r0, :64], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+function idct_dc_w16_neon
+1:
+        vld1.8          {q0}, [r0, :128], r1
+        vld1.8          {q1}, [r0, :128], r1
+        vld1.8          {q2}, [r0, :128], r1
+        subs            r3,  r3,  #4
+        vaddw.u8        q10, q8,  d0
+        vaddw.u8        q11, q8,  d1
+        vld1.8          {q3}, [r0, :128], r1
+        vaddw.u8        q12, q8,  d2
+        vaddw.u8        q13, q8,  d3
+        sub             r0,  r0,  r1, lsl #2
+        vaddw.u8        q14, q8,  d4
+        vaddw.u8        q15, q8,  d5
+        vqmovun.s16     d0,  q10
+        vqmovun.s16     d1,  q11
+        vaddw.u8        q10, q8,  d6
+        vaddw.u8        q11, q8,  d7
+        vqmovun.s16     d2,  q12
+        vqmovun.s16     d3,  q13
+        vqmovun.s16     d4,  q14
+        vqmovun.s16     d5,  q15
+        vst1.8          {q0}, [r0, :128], r1
+        vqmovun.s16     d6,  q10
+        vqmovun.s16     d7,  q11
+        vst1.8          {q1}, [r0, :128], r1
+        vst1.8          {q2}, [r0, :128], r1
+        vst1.8          {q3}, [r0, :128], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+function idct_dc_w32_neon
+1:
+        vld1.8          {q0, q1}, [r0, :128], r1
+        subs            r3,  r3,  #2
+        vld1.8          {q2, q3}, [r0, :128], r1
+        vaddw.u8        q10, q8,  d0
+        vaddw.u8        q11, q8,  d1
+        vaddw.u8        q12, q8,  d2
+        vaddw.u8        q13, q8,  d3
+        sub             r0,  r0,  r1, lsl #1
+        vaddw.u8        q14, q8,  d4
+        vaddw.u8        q15, q8,  d5
+        vqmovun.s16     d0,  q10
+        vqmovun.s16     d1,  q11
+        vaddw.u8        q10, q8,  d6
+        vaddw.u8        q11, q8,  d7
+        vqmovun.s16     d2,  q12
+        vqmovun.s16     d3,  q13
+        vqmovun.s16     d4,  q14
+        vqmovun.s16     d5,  q15
+        vst1.8          {q0, q1}, [r0, :128], r1
+        vqmovun.s16     d6,  q10
+        vqmovun.s16     d7,  q11
+        vst1.8          {q2, q3}, [r0, :128], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+function idct_dc_w64_neon
+        sub             r1,  r1,  #32
+1:
+        vld1.8          {q0, q1}, [r0, :128]!
+        subs            r3,  r3,  #1
+        vld1.8          {q2, q3}, [r0, :128]
+        vaddw.u8        q10, q8,  d0
+        vaddw.u8        q11, q8,  d1
+        vaddw.u8        q12, q8,  d2
+        vaddw.u8        q13, q8,  d3
+        sub             r0,  r0,  #32
+        vaddw.u8        q14, q8,  d4
+        vaddw.u8        q15, q8,  d5
+        vqmovun.s16     d0,  q10
+        vqmovun.s16     d1,  q11
+        vaddw.u8        q10, q8,  d6
+        vaddw.u8        q11, q8,  d7
+        vqmovun.s16     d2,  q12
+        vqmovun.s16     d3,  q13
+        vqmovun.s16     d4,  q14
+        vqmovun.s16     d5,  q15
+        vst1.8          {q0, q1}, [r0, :128]!
+        vqmovun.s16     d6,  q10
+        vqmovun.s16     d7,  q11
+        vst1.8          {q2, q3}, [r0, :128], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+.macro iwht4
+        vadd.i16        d16, d16, d17
+        vsub.i16        d21, d18, d19
+        vsub.i16        d20, d16, d21
+        vshr.s16        d20, d20, #1
+        vsub.i16        d18, d20, d17
+        vsub.i16        d17, d20, d19
+        vadd.i16        d19, d21, d18
+        vsub.i16        d16, d16, d17
+.endm
+
+.macro idct_4h_x4 r0, r1, r2, r3
+        vmull_vmlal     q3,  \r1, \r3, d0[3], d0[2]
+        vmull_vmlsl     q2,  \r1, \r3, d0[2], d0[3]
+        vmull_vmlal     q1,  \r0, \r2, d0[0], d0[0]
+        vqrshrn.s32     d6,  q3,  #12
+        vqrshrn.s32     d7,  q2,  #12
+        vmull_vmlsl     q2,  \r0, \r2, d0[0], d0[0]
+        vqrshrn.s32     d2,  q1,  #12
+        vqrshrn.s32     d3,  q2,  #12
+        vqadd.s16       \r0, d2,  d6
+        vqsub.s16       \r3, d2,  d6
+        vqadd.s16       \r1, d3,  d7
+        vqsub.s16       \r2, d3,  d7
+.endm
+
+.macro idct_8h_x4 q0, q1, q2, q3, r0, r1, r2, r3, r4, r5, r6, r7
+        vmull_vmlal_8h  q6,  q7,  \r2, \r3, \r6, \r7, d0[3], d0[2]
+        vmull_vmlsl_8h  q4,  q5,  \r2, \r3, \r6, \r7, d0[2], d0[3]
+        vmull_vmlal_8h  q2,  q3,  \r0, \r1, \r4, \r5, d0[0], d0[0]
+        vqrshrn_8h      d12, d13, q6,  q7,  #12
+        vqrshrn_8h      d14, d15, q4,  q5,  #12
+        vmull_vmlsl_8h  q4,  q5,  \r0, \r1, \r4, \r5, d0[0], d0[0]
+        vqrshrn_8h      d4,  d5,  q2,  q3,  #12
+        vqrshrn_8h      d6,  d7,  q4,  q5,  #12
+        vqadd.s16       \q0, q2,  q6
+        vqsub.s16       \q3, q2,  q6
+        vqadd.s16       \q1, q3,  q7
+        vqsub.s16       \q2, q3,  q7
+.endm
+
+function inv_dct_4h_x4_neon, export=1
+        movrel_local    r12, idct_coeffs
+        vld1.16         {d0}, [r12, :64]
+        idct_4h_x4      d16, d17, d18, d19
+        bx              lr
+endfunc
+
+function inv_dct_8h_x4_neon, export=1
+        movrel_local    r12, idct_coeffs
+        vld1.16         {d0}, [r12, :64]
+        idct_8h_x4      q8,  q9,  q10, q11, d16, d17, d18, d19, d20, d21, d22, d23
+        bx              lr
+endfunc
+
+.macro iadst_4x4 o0, o1, o2, o3
+        movrel_local    r12, iadst4_coeffs
+        vld1.16         {d0, d1}, [r12, :128]
+
+        vsubl.s16       q1,  d16, d18
+        vmull.s16       q2,  d16, d0[0]
+        vmlal.s16       q2,  d18, d0[1]
+        vmlal.s16       q2,  d19, d0[2]
+        vmull.s16       q10, d17, d0[3]
+        vaddw.s16       q1,  q1,  d19
+        vmull.s16       q3,  d16, d0[2]
+        vmlsl.s16       q3,  d18, d0[0]
+        vmlsl.s16       q3,  d19, d0[1]
+
+        vadd.s32        q11, q2,  q3
+        vmul.s32        q1,  q1,  d1[0]
+        vadd.s32        q2,  q2,  q10
+        vadd.s32        q3,  q3,  q10
+        vsub.s32        q11, q11, q10
+
+        vqrshrn.s32     \o0, q2,  #12
+        vqrshrn.s32     \o2, q1,  #12
+        vqrshrn.s32     \o1, q3,  #12
+        vqrshrn.s32     \o3, q11, #12
+.endm
+
+function inv_adst_4h_x4_neon, export=1
+        iadst_4x4       d16, d17, d18, d19
+        bx              lr
+endfunc
+
+function inv_flipadst_4h_x4_neon, export=1
+        iadst_4x4       d19, d18, d17, d16
+        bx              lr
+endfunc
+
+.macro iadst_8x4 o0, o1, o2, o3, o4, o5, o6, o7
+        movrel_local    r12, iadst4_coeffs
+        vld1.16         {d0, d1}, [r12, :128]
+
+        vsubl.s16       q2,  d16, d20
+        vsubl.s16       q3,  d17, d21
+        vmull.s16       q4,  d16, d0[0]
+        vmlal.s16       q4,  d20, d0[1]
+        vmlal.s16       q4,  d22, d0[2]
+        vmull.s16       q5,  d17, d0[0]
+        vmlal.s16       q5,  d21, d0[1]
+        vmlal.s16       q5,  d23, d0[2]
+        vaddw.s16       q2,  q2,  d22
+        vaddw.s16       q3,  q3,  d23
+        vmull.s16       q6,  d16, d0[2]
+        vmlsl.s16       q6,  d20, d0[0]
+        vmlsl.s16       q6,  d22, d0[1]
+        vmull.s16       q7,  d17, d0[2]
+        vmlsl.s16       q7,  d21, d0[0]
+        vmlsl.s16       q7,  d23, d0[1]
+
+        vmul.s32        q10, q2,  d1[0]
+        vmul.s32        q11, q3,  d1[0]
+
+        vmull.s16       q2,  d18, d0[3]
+        vmull.s16       q3,  d19, d0[3]
+
+        vadd.s32        q8,  q4,  q2 // out0
+        vadd.s32        q9,  q5,  q3
+
+        vadd.s32        q4,  q4,  q6 // out3
+        vadd.s32        q5,  q5,  q7
+
+        vadd.s32        q6,  q6,  q2 // out1
+        vadd.s32        q7,  q7,  q3
+
+        vsub.s32        q4,  q4,  q2 // out3
+        vsub.s32        q5,  q5,  q3
+
+        vqrshrn.s32     d20, q10, #12
+        vqrshrn.s32     d21, q11, #12
+
+        vqrshrn.s32     \o0, q8,  #12
+        vqrshrn.s32     \o1, q9,  #12
+
+.ifc \o4, d18
+        vmov            q9,  q10
+.endif
+
+        vqrshrn.s32     \o2, q6,  #12
+        vqrshrn.s32     \o3, q7,  #12
+
+        vqrshrn.s32     \o6, q4,  #12
+        vqrshrn.s32     \o7, q5,  #12
+.endm
+
+function inv_adst_8h_x4_neon, export=1
+        iadst_8x4       d16, d17, d18, d19, d20, d21, d22, d23
+        bx              lr
+endfunc
+
+function inv_flipadst_8h_x4_neon, export=1
+        iadst_8x4       d22, d23, d20, d21, d18, d19, d16, d17
+        bx              lr
+endfunc
+
+function inv_identity_4h_x4_neon, export=1
+        movw            r12, #(5793-4096)*8
+        vdup.16         d0,  r12
+        vqrdmulh.s16    q2,  q8,  d0[0]
+        vqrdmulh.s16    q3,  q9,  d0[0]
+        vqadd.s16       q8,  q8,  q2
+        vqadd.s16       q9,  q9,  q3
+        bx              lr
+endfunc
+
+function inv_identity_8h_x4_neon, export=1
+        movw            r12, #(5793-4096)*8
+        vdup.16         d0,  r12
+        vqrdmulh.s16    q1,  q8,  d0[0]
+        vqrdmulh.s16    q2,  q9,  d0[0]
+        vqrdmulh.s16    q3,  q10, d0[0]
+        vqadd.s16       q8,  q8,  q1
+        vqrdmulh.s16    q1,  q11, d0[0]
+        vqadd.s16       q9,  q9,  q2
+        vqadd.s16       q10, q10, q3
+        vqadd.s16       q11, q11, q1
+        bx              lr
+endfunc
+
+.macro identity_8x4_shift1 r0, r1, r2, r3, c
+.irp i, \r0, \r1, \r2, \r3
+        vqrdmulh.s16    q1,  \i,  \c
+        vrhadd.s16      \i,  \i,  q1
+.endr
+.endm
+
+function inv_txfm_add_wht_wht_4x4_8bpc_neon, export=1
+        push            {r4-r5,lr}
+        vmov.i16        q15, #0
+        vld1.16         {d16, d17, d18, d19}, [r2, :128]
+        vst1.16         {q15}, [r2, :128]!
+
+        vshr.s16        q8,  q8,  #2
+        vshr.s16        q9,  q9,  #2
+
+        iwht4
+
+        vst1.16         {q15}, [r2, :128]!
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+
+        iwht4
+
+        vld1.32         {d0[]},  [r0, :32], r1
+        vld1.32         {d0[1]}, [r0, :32], r1
+        vld1.32         {d1[]},  [r0, :32], r1
+        vld1.32         {d1[1]}, [r0, :32], r1
+
+        b               L(itx_4x4_end)
+endfunc
+
+function inv_txfm_add_4x4_neon
+        vmov.i16        q15, #0
+        vld1.16         {d16, d17, d18, d19}, [r2, :128]
+        vst1.16         {q15}, [r2, :128]!
+
+        blx             r4
+
+        vst1.16         {q15}, [r2, :128]!
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+
+        blx             r5
+
+        vld1.32         {d0[]},  [r0, :32], r1
+        vld1.32         {d0[1]}, [r0, :32], r1
+        vld1.32         {d1[]},  [r0, :32], r1
+        vld1.32         {d1[1]}, [r0, :32], r1
+        vrshr.s16       q8,  q8,  #4
+        vrshr.s16       q9,  q9,  #4
+
+L(itx_4x4_end):
+        sub             r0,  r0,  r1, lsl #2
+        vaddw.u8        q8,  q8,  d0
+        vqmovun.s16     d0,  q8
+        vaddw.u8        q9,  q9,  d1
+        vst1.32         {d0[0]}, [r0, :32], r1
+        vqmovun.s16     d1,  q9
+        vst1.32         {d0[1]}, [r0, :32], r1
+        vst1.32         {d1[0]}, [r0, :32], r1
+        vst1.32         {d1[1]}, [r0, :32], r1
+
+        pop             {r4-r5,pc}
+endfunc
+
+.macro def_fn_4x4 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_4x4_8bpc_neon, export=1
+        push            {r4-r5,lr}
+
+.ifc \txfm1\()_\txfm2, dct_dct
+        cmp             r3,  #0
+        bne             1f
+        vmov.i16        d30, #0
+        movw            r12, #2896*8
+        vld1.16         {d16[]},  [r2, :16]
+        vdup.16         d4,  r12
+        vst1.16         {d30[0]}, [r2, :16]
+        vqrdmulh.s16    d16, d16, d4[0]
+        vld1.32         {d0[0]},  [r0, :32], r1
+        vqrdmulh.s16    d20, d16, d4[0]
+        vld1.32         {d0[1]},  [r0, :32], r1
+        vrshr.s16       d16, d20, #4
+        vrshr.s16       d17, d20, #4
+        vld1.32         {d1[0]},  [r0, :32], r1
+        vmov            q9,  q8
+        vld1.32         {d1[1]}, [r0, :32], r1
+        b               L(itx_4x4_end)
+1:
+.endif
+        movrel_local    r4,  inv_\txfm1\()_4h_x4_neon
+        movrel_local    r5,  inv_\txfm2\()_4h_x4_neon
+        b               inv_txfm_add_4x4_neon
+endfunc
+.endm
+
+def_fn_4x4 dct, dct
+def_fn_4x4 identity, identity
+def_fn_4x4 dct, adst
+def_fn_4x4 dct, flipadst
+def_fn_4x4 dct, identity
+def_fn_4x4 adst, dct
+def_fn_4x4 adst, adst
+def_fn_4x4 adst, flipadst
+def_fn_4x4 flipadst, dct
+def_fn_4x4 flipadst, adst
+def_fn_4x4 flipadst, flipadst
+def_fn_4x4 identity, dct
+
+def_fn_4x4 adst, identity
+def_fn_4x4 flipadst, identity
+def_fn_4x4 identity, adst
+def_fn_4x4 identity, flipadst
+
+.macro idct_8h_x8 q0, q1, q2, q3, q4, q5, q6, q7, r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15
+        idct_8h_x4      \q0, \q2, \q4, \q6, \r0, \r1, \r4, \r5, \r8, \r9, \r12, \r13
+
+        vmull_vmlsl_8h  q2,   q3,   \r2,  \r3,  \r14, \r15, d1[0], d1[1] // -> t4a
+        vmull_vmlal_8h  q4,   q5,   \r2,  \r3,  \r14, \r15, d1[1], d1[0] // -> t7a
+        vmull_vmlsl_8h  q6,   q7,   \r10, \r11, \r6,  \r7,  d1[2], d1[3] // -> t5a
+        vqrshrn_8h      \r2,  \r3,  q2,   q3,   #12         // t4a
+        vqrshrn_8h      \r14, \r15, q4,   q5,   #12         // t7a
+        vmull_vmlal_8h  q2,   q3,   \r10, \r11, \r6,  \r7,  d1[3], d1[2] // -> t6a
+        vqrshrn_8h      \r6,  \r7,  q6,   q7,   #12         // t5a
+        vqrshrn_8h      \r10, \r11, q2,   q3,   #12         // t6a
+
+        vqadd.s16       q2,   \q1,  \q3 // t4
+        vqsub.s16       \q1,  \q1,  \q3 // t5a
+        vqadd.s16       q3,   \q7,  \q5 // t7
+        vqsub.s16       \q3,  \q7,  \q5 // t6a
+
+        vmull_vmlsl_8h  q4,   q5,   \r6,  \r7,  \r2,  \r3,  d0[0], d0[0] // -> t5
+        vmull_vmlal_8h  q6,   q7,   \r6,  \r7,  \r2,  \r3,  d0[0], d0[0] // -> t6
+        vqrshrn_8h      d8,   d9,   q4,   q5,  #12 // t5
+        vqrshrn_8h      d10,  d11,  q6,   q7,  #12 // t6
+
+        vqsub.s16       \q7,  \q0,  q3 // out7
+        vqadd.s16       \q0,  \q0,  q3 // out0
+        vqadd.s16       \q1,  \q2,  q5 // out1
+        vqsub.s16       q6,   \q2,  q5 // out6
+        vqadd.s16       \q2,  \q4,  q4 // out2
+        vqsub.s16       \q5,  \q4,  q4 // out5
+        vqadd.s16       \q3,  \q6,  q2 // out3
+        vqsub.s16       \q4,  \q6,  q2 // out4
+        vmov            \q6,  q6       // out6
+.endm
+
+.macro idct_4h_x8 r0, r1, r2, r3, r4, r5, r6, r7
+        idct_4h_x4      \r0, \r2, \r4, \r6
+
+        vmull_vmlsl     q1,   \r1,  \r7, d1[0], d1[1] // -> t4a
+        vmull_vmlal     q2,   \r1,  \r7, d1[1], d1[0] // -> t7a
+        vmull_vmlsl     q3,   \r5,  \r3, d1[2], d1[3] // -> t5a
+        vqrshrn.s32     \r1,  q1,   #12               // t4a
+        vmull_vmlal     q1,   \r5,  \r3, d1[3], d1[2] // -> t6a
+        vqrshrn.s32     \r7,  q2,   #12               // t7a
+        vqrshrn.s32     \r3,  q3,   #12               // t5a
+        vqrshrn.s32     \r5,  q1,   #12               // taa
+
+        vqadd.s16       d2,   \r1,  \r3 // t4
+        vqsub.s16       \r1,  \r1,  \r3 // t5a
+        vqadd.s16       d3,   \r7,  \r5 // t7
+        vqsub.s16       \r3,  \r7,  \r5 // t6a
+
+        vmull_vmlsl     q2,   \r3,  \r1, d0[0], d0[0] // -> t5
+        vmull_vmlal     q3,   \r3,  \r1, d0[0], d0[0] // -> t6
+        vqrshrn.s32     d4,   q2,   #12               // t5
+        vqrshrn.s32     d5,   q3,   #12               // t6
+
+        vqsub.s16       \r7,  \r0,  d3 // out7
+        vqadd.s16       \r0,  \r0,  d3 // out0
+        vqadd.s16       \r1,  \r2,  d5 // out1
+        vqsub.s16       d6,   \r2,  d5 // out6
+        vqadd.s16       \r2,  \r4,  d4 // out2
+        vqsub.s16       \r5,  \r4,  d4 // out5
+        vqadd.s16       \r3,  \r6,  d2 // out3
+        vqsub.s16       \r4,  \r6,  d2 // out4
+        vmov            \r6,  d6       // out6
+.endm
+
+function inv_dct_8h_x8_neon, export=1
+        movrel_local    r12, idct_coeffs
+        vld1.16         {q0}, [r12, :128]
+        idct_8h_x8      q8,  q9,  q10, q11, q12, q13, q14, q15, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        bx              lr
+endfunc
+
+function inv_dct_4h_x8_neon, export=1
+        movrel_local    r12, idct_coeffs
+        vld1.16         {q0}, [r12, :128]
+        idct_4h_x8      d16, d17, d18, d19, d20, d21, d22, d23
+        bx              lr
+endfunc
+
+.macro iadst_8h_x8 q0, q1, q2, q3, q4, q5, q6, q7, r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15
+        movrel_local    r12, iadst8_coeffs
+        vld1.16         {d0, d1, d2}, [r12, :64]
+
+        vmull_vmlal_8h  q2,  q3,  d30, d31, d16, d17, d0[0], d0[1]
+        vmull_vmlsl_8h  q4,  q5,  d30, d31, d16, d17, d0[1], d0[0]
+        vmull_vmlal_8h  q6,  q7,  d26, d27, d20, d21, d0[2], d0[3]
+        vqrshrn_8h      d16, d17, q2,  q3,  #12  // t0a
+        vqrshrn_8h      d30, d31, q4,  q5,  #12  // t1a
+        vmull_vmlsl_8h  q2,  q3,  d26, d27, d20, d21, d0[3], d0[2]
+        vmull_vmlal_8h  q4,  q5,  d22, d23, d24, d25, d1[0], d1[1]
+        vqrshrn_8h      d20, d21, q6,  q7,  #12  // t2a
+        vqrshrn_8h      d26, d27, q2,  q3,  #12  // t3a
+        vmull_vmlsl_8h  q6,  q7,  d22, d23, d24, d25, d1[1], d1[0]
+        vmull_vmlal_8h  q2,  q3,  d18, d19, d28, d29, d1[2], d1[3]
+        vqrshrn_8h      d24, d25, q4,  q5,  #12  // t4a
+        vqrshrn_8h      d22, d23, q6,  q7,  #12  // t5a
+        vmull_vmlsl_8h  q4,  q5,  d18, d19, d28, d29, d1[3], d1[2]
+        vqrshrn_8h      d28, d29, q2,  q3,  #12  // t6a
+        vqrshrn_8h      d18, d19, q4,  q5,  #12  // t7a
+
+        vqadd.s16       q2,  q8,  q12 // t0
+        vqsub.s16       q3,  q8,  q12 // t4
+        vqadd.s16       q4,  q15, q11 // t1
+        vqsub.s16       q5,  q15, q11 // t5
+        vqadd.s16       q6,  q10, q14 // t2
+        vqsub.s16       q7,  q10, q14 // t6
+        vqadd.s16       q10, q13, q9  // t3
+        vqsub.s16       q11, q13, q9  // t7
+
+        vmull_vmlal_8h  q8,  q9,  d6,  d7,  d10, d11, d2[3], d2[2]
+        vmull_vmlsl_8h  q12, q13, d6,  d7,  d10, d11, d2[2], d2[3]
+        vmull_vmlsl_8h  q14, q15, d22, d23, d14, d15, d2[3], d2[2]
+
+        vqrshrn_8h      d6,  d7,  q8,  q9,  #12  // t4a
+        vqrshrn_8h      d10, d11, q12, q13, #12  // t5a
+
+        vmull_vmlal_8h  q8,  q9,  d22, d23, d14, d15, d2[2], d2[3]
+
+        vqrshrn_8h      d14, d15, q14, q15, #12  // t6a
+        vqrshrn_8h      d22, d23, q8,  q9,  #12  // t7a
+
+        vqadd.s16       \q0, q2,  q6  // out0
+        vqsub.s16       q2,  q2,  q6  // t2
+        vqadd.s16       \q7, q4,  q10 // out7
+        vqsub.s16       q4,  q4,  q10 // t3
+        vqneg.s16       \q7, \q7     // out7
+
+        vqadd.s16       \q1, q3,  q7  // out1
+        vqsub.s16       q3,  q3,  q7  // t6
+        vqadd.s16       \q6, q5,  q11 // out6
+        vqsub.s16       q5,  q5,  q11 // t7
+        vqneg.s16       \q1, \q1     // out1
+
+        vmull_vmlal_8h  q10, q11, d4,  d5,  d8,  d9,  d2[0], d2[0] // -> out3 (q11 or q12)
+        vmull_vmlsl_8h  q6,  q7,  d4,  d5,  d8,  d9,  d2[0], d2[0] // -> out4 (q12 or q11)
+        vmull_vmlsl_8h  q12, q13, d6,  d7,  d10, d11, d2[0], d2[0] // -> out5 (q13 or q10)
+        vqrshrn_8h      d4,  d5,  q10, q11, #12 // out3
+        vmull_vmlal_8h  q10, q11, d6,  d7,  d10, d11, d2[0], d2[0] // -> out2 (q10 or q13)
+        vqrshrn_8h      d6,  d7,  q12, q13, #12 // out5
+        vqrshrn_8h      \r4, \r5, q10, q11, #12 // out2 (q10 or q13)
+        vqrshrn_8h      \r8, \r9, q6,  q7,  #12 // out4 (q12 or q11)
+
+        vqneg.s16       \q3, q2     // out3
+        vqneg.s16       \q5, q3     // out5
+.endm
+
+.macro iadst_4h_x8 r0, r1, r2, r3, r4, r5, r6, r7
+        movrel_local    r12, iadst8_coeffs
+        vld1.16         {d0, d1, d2}, [r12, :64]
+
+        vmull_vmlal     q2,  d23, d16, d0[0], d0[1]
+        vmull_vmlsl     q3,  d23, d16, d0[1], d0[0]
+        vmull_vmlal     q4,  d21, d18, d0[2], d0[3]
+        vqrshrn.s32     d16, q2,  #12 // t0a
+        vqrshrn.s32     d23, q3,  #12 // t1a
+        vmull_vmlsl     q5,  d21, d18, d0[3], d0[2]
+        vmull_vmlal     q6,  d19, d20, d1[0], d1[1]
+        vqrshrn.s32     d18, q4,  #12 // t2a
+        vqrshrn.s32     d21, q5,  #12 // t3a
+        vmull_vmlsl     q7,  d19, d20, d1[1], d1[0]
+        vmull_vmlal     q2,  d17, d22, d1[2], d1[3]
+        vqrshrn.s32     d20, q6,  #12 // t4a
+        vqrshrn.s32     d19, q7,  #12 // t5a
+        vmull_vmlsl     q3,  d17, d22, d1[3], d1[2]
+        vqrshrn.s32     d22, q2,  #12 // t6a
+        vqrshrn.s32     d17, q3,  #12 // t7a
+
+        vqadd.s16       d4,  d16, d20 // t0
+        vqsub.s16       d5,  d16, d20 // t4
+        vqadd.s16       d6,  d23, d19 // t1
+        vqsub.s16       d7,  d23, d19 // t5
+        vqadd.s16       d8,  d18, d22 // t2
+        vqsub.s16       d9,  d18, d22 // t6
+        vqadd.s16       d18, d21, d17 // t3
+        vqsub.s16       d19, d21, d17 // t7
+
+        vmull_vmlal     q8,  d5,  d7,  d2[3], d2[2]
+        vmull_vmlsl     q10, d5,  d7,  d2[2], d2[3]
+        vmull_vmlsl     q11, d19, d9,  d2[3], d2[2]
+
+        vqrshrn.s32     d5,  q8,  #12 // t4a
+        vqrshrn.s32     d7,  q10, #12 // t5a
+
+        vmull_vmlal     q8,  d19, d9,  d2[2], d2[3]
+
+        vqrshrn.s32     d9,  q11, #12 // t6a
+        vqrshrn.s32     d19, q8,  #12 // t7a
+
+        vqadd.s16       \r0, d4,  d8  // out0
+        vqsub.s16       d4,  d4,  d8  // t2
+        vqadd.s16       \r7, d6,  d18 // out7
+        vqsub.s16       d6,  d6,  d18 // t3
+        vqneg.s16       \r7, \r7      // out7
+
+        vqadd.s16       \r1, d5,  d9  // out1
+        vqsub.s16       d5,  d5,  d9  // t6
+        vqadd.s16       \r6, d7,  d19 // out6
+        vqsub.s16       d7,  d7,  d19 // t7
+        vqneg.s16       \r1, \r1      // out1
+
+        vmull_vmlal     q9,  d4,  d6,  d2[0], d2[0] // -> out3 (d19 or d20)
+        vmull_vmlsl     q4,  d4,  d6,  d2[0], d2[0] // -> out4 (d20 or d19)
+        vmull_vmlsl     q10, d5,  d7,  d2[0], d2[0] // -> out5 (d21 or d18)
+        vqrshrn.s32     d4,  q9,  #12 // out3
+        vmull_vmlal     q9,  d5,  d7,  d2[0], d2[0] // -> out2 (d18 or d21)
+        vqrshrn.s32     d5,  q10, #12 // out5
+        vqrshrn.s32     \r2, q9,  #12 // out2 (d18 or d21)
+        vqrshrn.s32     \r4, q4,  #12 // out4 (d20 or d19)
+
+        vqneg.s16       \r3, d4       // out3
+        vqneg.s16       \r5, d5       // out5
+.endm
+
+function inv_adst_8h_x8_neon, export=1
+        iadst_8h_x8     q8,  q9,  q10, q11, q12, q13, q14, q15, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        bx              lr
+endfunc
+
+function inv_flipadst_8h_x8_neon, export=1
+        iadst_8h_x8     q15, q14, q13, q12, q11, q10, q9,  q8,  d30, d31, d28, d29, d26, d27, d24, d25, d22, d23, d20, d21, d18, d19, d16, d17
+        bx              lr
+endfunc
+
+function inv_adst_4h_x8_neon, export=1
+        iadst_4h_x8     d16, d17, d18, d19, d20, d21, d22, d23
+        bx              lr
+endfunc
+
+function inv_flipadst_4h_x8_neon, export=1
+        iadst_4h_x8     d23, d22, d21, d20, d19, d18, d17, d16
+        bx              lr
+endfunc
+
+function inv_identity_8h_x8_neon, export=1
+        vqshl.s16       q8,  q8,  #1
+        vqshl.s16       q9,  q9,  #1
+        vqshl.s16       q10, q10, #1
+        vqshl.s16       q11, q11, #1
+        vqshl.s16       q12, q12, #1
+        vqshl.s16       q13, q13, #1
+        vqshl.s16       q14, q14, #1
+        vqshl.s16       q15, q15, #1
+        bx              lr
+endfunc
+
+function inv_identity_4h_x8_neon, export=1
+        vqshl.s16       q8,  q8,  #1
+        vqshl.s16       q9,  q9,  #1
+        vqshl.s16       q10, q10, #1
+        vqshl.s16       q11, q11, #1
+        bx              lr
+endfunc
+
+.macro def_fn_8x8_base variant
+function inv_txfm_\variant\()add_8x8_neon
+        vmov.i16        q0,  #0
+        vmov.i16        q1,  #0
+        vld1.16         {q8,  q9},  [r2, :128]
+        vst1.16         {q0,  q1},  [r2, :128]!
+        vld1.16         {q10, q11}, [r2, :128]
+        vst1.16         {q0,  q1},  [r2, :128]!
+        vld1.16         {q12, q13}, [r2, :128]
+        vst1.16         {q0,  q1},  [r2, :128]!
+        vld1.16         {q14, q15}, [r2, :128]
+        vst1.16         {q0,  q1},  [r2, :128]
+
+.ifc \variant, identity_
+        // The identity shl #1 and downshift srshr #1 cancel out
+
+        b               L(itx_8x8_epilog)
+.else
+        blx             r4
+
+        vrshr.s16       q8,  q8,  #1
+        vrshr.s16       q9,  q9,  #1
+        vrshr.s16       q10, q10, #1
+        vrshr.s16       q11, q11, #1
+        vrshr.s16       q12, q12, #1
+        vrshr.s16       q13, q13, #1
+        vrshr.s16       q14, q14, #1
+        vrshr.s16       q15, q15, #1
+
+L(itx_8x8_epilog):
+        transpose_8x8h  q8,  q9,  q10, q11, q12, q13, q14, q15, d17, d19, d21, d23, d24, d26, d28, d30
+
+        blx             r5
+
+        load_add_store_8x8 r0, r7
+        vpop            {q4-q7}
+        pop             {r4-r5,r7,pc}
+.endif
+endfunc
+.endm
+
+def_fn_8x8_base identity_
+def_fn_8x8_base
+
+.macro def_fn_8x8 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_8x8_8bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         8,   8,   1
+.endif
+        push            {r4-r5,r7,lr}
+        vpush           {q4-q7}
+        movrel_local    r5,  inv_\txfm2\()_8h_x8_neon
+.ifc \txfm1, identity
+        b               inv_txfm_identity_add_8x8_neon
+.else
+        movrel_local    r4,  inv_\txfm1\()_8h_x8_neon
+        b               inv_txfm_add_8x8_neon
+.endif
+endfunc
+.endm
+
+def_fn_8x8 dct, dct
+def_fn_8x8 identity, identity
+def_fn_8x8 dct, adst
+def_fn_8x8 dct, flipadst
+def_fn_8x8 dct, identity
+def_fn_8x8 adst, dct
+def_fn_8x8 adst, adst
+def_fn_8x8 adst, flipadst
+def_fn_8x8 flipadst, dct
+def_fn_8x8 flipadst, adst
+def_fn_8x8 flipadst, flipadst
+def_fn_8x8 identity, dct
+def_fn_8x8 adst, identity
+def_fn_8x8 flipadst, identity
+def_fn_8x8 identity, adst
+def_fn_8x8 identity, flipadst
+
+function inv_txfm_add_8x4_neon
+        vmov.i16        q14, #0
+        vmov.i16        q15, #0
+        movw            r12, #2896*8
+        vdup.16         d0,  r12
+        vld1.16         {d16, d17, d18, d19}, [r2, :128]
+        vst1.16         {q14, q15}, [r2, :128]!
+        vld1.16         {d20, d21, d22, d23}, [r2, :128]
+        vst1.16         {q14, q15}, [r2, :128]
+
+        scale_input     d0[0], q8,  q9, q10, q11
+
+        blx             r4
+
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        vswp            d17, d20
+        vswp            d19, d21
+        vswp            d18, d20
+        vswp            d21, d22
+
+        blx             r5
+
+        load_add_store_8x4 r0, r7
+        vpop            {q4-q7}
+        pop             {r4-r5,r7,pc}
+endfunc
+
+function inv_txfm_add_4x8_neon
+        vmov.i16        q14, #0
+        vmov.i16        q15, #0
+        movw            r12, #2896*8
+        vdup.16         d0,  r12
+        vld1.16         {q8,  q9},  [r2, :128]
+        vst1.16         {q14, q15}, [r2, :128]!
+        vld1.16         {q10, q11}, [r2, :128]
+        vst1.16         {q14, q15}, [r2, :128]
+
+        scale_input     d0[0], q8,  q9, q10, q11
+
+        blx             r4
+
+        transpose_4x8h  q8,  q9,  q10, q11
+        vswp            d17, d20
+        vswp            d19, d21
+        vswp            d17, d18
+        vswp            d19, d22
+
+        blx             r5
+
+        load_add_store_4x8 r0, r7
+        vpop            {q4-q7}
+        pop             {r4-r5,r7,pc}
+endfunc
+
+.macro def_fn_48 w, h, txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  0
+.endif
+        push            {r4-r5,r7,lr}
+        vpush           {q4-q7}
+        movrel_local    r4,  inv_\txfm1\()_\h\()h_x\w\()_neon
+        movrel_local    r5,  inv_\txfm2\()_\w\()h_x\h\()_neon
+        b               inv_txfm_add_\w\()x\h\()_neon
+endfunc
+.endm
+
+.macro def_fns_48 w, h
+def_fn_48 \w, \h, dct, dct
+def_fn_48 \w, \h, identity, identity
+def_fn_48 \w, \h, dct, adst
+def_fn_48 \w, \h, dct, flipadst
+def_fn_48 \w, \h, dct, identity
+def_fn_48 \w, \h, adst, dct
+def_fn_48 \w, \h, adst, adst
+def_fn_48 \w, \h, adst, flipadst
+def_fn_48 \w, \h, flipadst, dct
+def_fn_48 \w, \h, flipadst, adst
+def_fn_48 \w, \h, flipadst, flipadst
+def_fn_48 \w, \h, identity, dct
+def_fn_48 \w, \h, adst, identity
+def_fn_48 \w, \h, flipadst, identity
+def_fn_48 \w, \h, identity, adst
+def_fn_48 \w, \h, identity, flipadst
+.endm
+
+def_fns_48 4, 8
+def_fns_48 8, 4
+
+function inv_dct_4h_x16_neon, export=1
+        movrel_local    r12, idct_coeffs
+        vld1.16         {q0, q1}, [r12, :128]
+
+        vmull_vmlsl     q2,  d17, d31, d2[0], d2[1]  // -> t8a
+        vmull_vmlal     q3,  d17, d31, d2[1], d2[0]  // -> t15a
+        vmull_vmlsl     q4,  d25, d23, d2[2], d2[3]  // -> t9a
+        vqrshrn.s32     d17, q2,  #12                // t8a
+        vqrshrn.s32     d31, q3,  #12                // t15a
+        vmull_vmlal     q2,  d25, d23, d2[3], d2[2]  // -> t14a
+        vmull_vmlsl     q3,  d21, d27, d3[0], d3[1]  // -> t10a
+        vqrshrn.s32     d23, q4,  #12                // t9a
+        vqrshrn.s32     d25, q2,  #12                // t14a
+        vmull_vmlal     q4,  d21, d27, d3[1], d3[0]  // -> t13a
+        vmull_vmlsl     q2,  d29, d19, d3[2], d3[3]  // -> t11a
+        vqrshrn.s32     d21, q3,  #12                // t10a
+        vqrshrn.s32     d27, q4,  #12                // t13a
+        vmull_vmlal     q3,  d29, d19, d3[3], d3[2]  // -> t12a
+        vqrshrn.s32     d19, q2,  #12                // t11a
+        vqrshrn.s32     d29, q3,  #12                // t12a
+
+        idct_4h_x8      d16, d18, d20, d22, d24, d26, d28, d30
+
+        vqsub.s16       d4,  d17, d23  // t9
+        vqadd.s16       d17, d17, d23  // t8
+        vqsub.s16       d5,  d31, d25  // t14
+        vqadd.s16       d31, d31, d25  // t15
+        vqsub.s16       d23, d19, d21  // t10
+        vqadd.s16       d19, d19, d21  // t11
+        vqadd.s16       d25, d29, d27  // t12
+        vqsub.s16       d29, d29, d27  // t13
+
+        vmull_vmlsl     q3,  d5,  d4,  d0[2], d0[3]  // -> t9a
+        vmull_vmlal     q4,  d5,  d4,  d0[3], d0[2]  // -> t14a
+        vqrshrn.s32     d21, q3,  #12                // t9a
+        vqrshrn.s32     d27, q4,  #12                // t14a
+
+        vmull_vmlsl     q3,  d29, d23, d0[2], d0[3]  // -> t13a
+        vmull_vmlal     q4,  d29, d23, d0[3], d0[2]  // -> t10a
+        vqrshrn.s32     d29, q3,  #12                // t13a
+        vneg.s32        q4,  q4
+        vqrshrn.s32     d23, q4,  #12                // t10a
+
+        vqsub.s16       d4,  d17, d19  // t11a
+        vqadd.s16       d17, d17, d19  // t8a
+        vqsub.s16       d5,  d31, d25  // t12a
+        vqadd.s16       d31, d31, d25  // t15a
+        vqadd.s16       d19, d21, d23  // t9
+        vqsub.s16       d21, d21, d23  // t10
+        vqsub.s16       d25, d27, d29  // t13
+        vqadd.s16       d27, d27, d29  // t14
+
+        vmull_vmlsl     q3,  d5,  d4,  d0[0], d0[0]  // -> t11
+        vmull_vmlal     q4,  d5,  d4,  d0[0], d0[0]  // -> t12
+        vmull_vmlsl     q2,  d25, d21, d0[0], d0[0]  // -> t10a
+
+        vqrshrn.s32     d6,  q3,  #12  // t11
+        vqrshrn.s32     d7,  q4,  #12  // t12
+        vmull_vmlal     q4,  d25, d21, d0[0], d0[0]  // -> t13a
+        vqrshrn.s32     d4,  q2,  #12  // t10a
+        vqrshrn.s32     d5,  q4,  #12  // t13a
+
+        vqadd.s16       d8,  d16, d31  // out0
+        vqsub.s16       d31, d16, d31  // out15
+        vmov            d16, d8
+        vqadd.s16       d23, d30, d17  // out7
+        vqsub.s16       d9,  d30, d17  // out8
+        vqadd.s16       d17, d18, d27  // out1
+        vqsub.s16       d30, d18, d27  // out14
+        vqadd.s16       d18, d20, d5   // out2
+        vqsub.s16       d29, d20, d5   // out13
+        vqadd.s16       d5,  d28, d19  // out6
+        vqsub.s16       d25, d28, d19  // out9
+        vqadd.s16       d19, d22, d7   // out3
+        vqsub.s16       d28, d22, d7   // out12
+        vqadd.s16       d20, d24, d6   // out4
+        vqsub.s16       d27, d24, d6   // out11
+        vqadd.s16       d21, d26, d4   // out5
+        vqsub.s16       d26, d26, d4   // out10
+        vmov            d24, d9
+        vmov            d22, d5
+
+        bx              lr
+endfunc
+
+.macro iadst_16 o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15
+        movrel_local    r12, iadst16_coeffs
+        vld1.16         {q0, q1}, [r12, :128]
+        movrel_local    r12, idct_coeffs
+
+        vmull_vmlal     q2,  d31, d16, d0[0], d0[1] // -> t0
+        vmull_vmlsl     q3,  d31, d16, d0[1], d0[0] // -> t1
+        vmull_vmlal     q4,  d29, d18, d0[2], d0[3] // -> t2
+        vqrshrn.s32     d16, q2,  #12               // t0
+        vqrshrn.s32     d31, q3,  #12               // t1
+        vmull_vmlsl     q2,  d29, d18, d0[3], d0[2] // -> t3
+        vmull_vmlal     q3,  d27, d20, d1[0], d1[1] // -> t4
+        vqrshrn.s32     d18, q4,  #12               // t2
+        vqrshrn.s32     d29, q2,  #12               // t3
+        vmull_vmlsl     q4,  d27, d20, d1[1], d1[0] // -> t5
+        vmull_vmlal     q2,  d25, d22, d1[2], d1[3] // -> t6
+        vqrshrn.s32     d20, q3,  #12               // t4
+        vqrshrn.s32     d27, q4,  #12               // t5
+        vmull_vmlsl     q3,  d25, d22, d1[3], d1[2] // -> t7
+        vmull_vmlal     q4,  d23, d24, d2[0], d2[1] // -> t8
+        vqrshrn.s32     d22, q2,  #12               // t6
+        vqrshrn.s32     d25, q3,  #12               // t7
+        vmull_vmlsl     q2,  d23, d24, d2[1], d2[0] // -> t9
+        vmull_vmlal     q3,  d21, d26, d2[2], d2[3] // -> t10
+        vqrshrn.s32     d23, q4,  #12               // t8
+        vqrshrn.s32     d24, q2,  #12               // t9
+        vmull_vmlsl     q4,  d21, d26, d2[3], d2[2] // -> t11
+        vmull_vmlal     q2,  d19, d28, d3[0], d3[1] // -> t12
+        vqrshrn.s32     d21, q3,  #12               // t10
+        vqrshrn.s32     d26, q4,  #12               // t11
+        vmull_vmlsl     q3,  d19, d28, d3[1], d3[0] // -> t13
+        vmull_vmlal     q4,  d17, d30, d3[2], d3[3] // -> t14
+        vqrshrn.s32     d19, q2,  #12               // t12
+        vqrshrn.s32     d28, q3,  #12               // t13
+        vmull_vmlsl     q2,  d17, d30, d3[3], d3[2] // -> t15
+        vqrshrn.s32     d17, q4,  #12               // t14
+        vqrshrn.s32     d30, q2,  #12               // t15
+
+        vld1.16         {q0}, [r12, :128]
+
+        vqsub.s16       d2,  d16, d23 // t8a
+        vqadd.s16       d16, d16, d23 // t0a
+        vqsub.s16       d3,  d31, d24 // t9a
+        vqadd.s16       d31, d31, d24 // t1a
+        vqadd.s16       d23, d18, d21 // t2a
+        vqsub.s16       d18, d18, d21 // t10a
+        vqadd.s16       d24, d29, d26 // t3a
+        vqsub.s16       d29, d29, d26 // t11a
+        vqadd.s16       d21, d20, d19 // t4a
+        vqsub.s16       d20, d20, d19 // t12a
+        vqadd.s16       d26, d27, d28 // t5a
+        vqsub.s16       d27, d27, d28 // t13a
+        vqadd.s16       d19, d22, d17 // t6a
+        vqsub.s16       d22, d22, d17 // t14a
+        vqadd.s16       d28, d25, d30 // t7a
+        vqsub.s16       d25, d25, d30 // t15a
+
+        vmull_vmlal     q2,  d2,  d3,  d1[1], d1[0] // -> t8
+        vmull_vmlsl     q3,  d2,  d3,  d1[0], d1[1] // -> t9
+        vmull_vmlal     q4,  d18, d29, d1[3], d1[2] // -> t10
+        vqrshrn.s32     d17, q2,  #12               // t8
+        vqrshrn.s32     d30, q3,  #12               // t9
+        vmull_vmlsl     q2,  d18, d29, d1[2], d1[3] // -> t11
+        vmull_vmlsl     q3,  d27, d20, d1[1], d1[0] // -> t12
+        vqrshrn.s32     d18, q4,  #12               // t10
+        vqrshrn.s32     d29, q2,  #12               // t11
+        vmull_vmlal     q4,  d27, d20, d1[0], d1[1] // -> t13
+        vmull_vmlsl     q2,  d25, d22, d1[3], d1[2] // -> t14
+        vqrshrn.s32     d27, q3,  #12               // t12
+        vqrshrn.s32     d20, q4,  #12               // t13
+        vmull_vmlal     q3,  d25, d22, d1[2], d1[3] // -> t15
+        vqrshrn.s32     d25, q2,  #12               // t14
+        vqrshrn.s32     d22, q3,  #12               // t15
+
+        vqsub.s16       d2,  d16, d21 // t4
+        vqadd.s16       d16, d16, d21 // t0
+        vqsub.s16       d3,  d31, d26 // t5
+        vqadd.s16       d31, d31, d26 // t1
+        vqadd.s16       d21, d23, d19 // t2
+        vqsub.s16       d23, d23, d19 // t6
+        vqadd.s16       d26, d24, d28 // t3
+        vqsub.s16       d24, d24, d28 // t7
+        vqadd.s16       d19, d17, d27 // t8a
+        vqsub.s16       d17, d17, d27 // t12a
+        vqadd.s16       d28, d30, d20 // t9a
+        vqsub.s16       d30, d30, d20 // t13a
+        vqadd.s16       d27, d18, d25 // t10a
+        vqsub.s16       d18, d18, d25 // t14a
+        vqadd.s16       d20, d29, d22 // t11a
+        vqsub.s16       d29, d29, d22 // t15a
+
+        vmull_vmlal     q2,  d2,  d3,  d0[3], d0[2] // -> t4a
+        vmull_vmlsl     q3,  d2,  d3,  d0[2], d0[3] // -> t5a
+        vmull_vmlsl     q4,  d24, d23, d0[3], d0[2] // -> t6a
+        vqrshrn.s32     d22, q2,  #12               // t4a
+        vqrshrn.s32     d25, q3,  #12               // t5a
+        vmull_vmlal     q2,  d24, d23, d0[2], d0[3] // -> t7a
+        vmull_vmlal     q3,  d17, d30, d0[3], d0[2] // -> t12
+        vqrshrn.s32     d24, q4,  #12               // t6a
+        vqrshrn.s32     d23, q2,  #12               // t7a
+        vmull_vmlsl     q4,  d17, d30, d0[2], d0[3] // -> t13
+        vmull_vmlsl     q2,  d29, d18, d0[3], d0[2] // -> t14
+        vqrshrn.s32     d17, q3,  #12               // t12
+        vmull_vmlal     q3,  d29, d18, d0[2], d0[3] // -> t15
+        vqrshrn.s32     d29, q4,  #12               // t13
+        vqrshrn.s32     d30, q2,  #12               // t14
+        vqrshrn.s32     d18, q3,  #12               // t15
+
+        vqsub.s16       d2,  d16, d21 // t2a
+.ifc \o0, d16
+        vqadd.s16       \o0, d16, d21 // out0
+        vqsub.s16       d21, d31, d26 // t3a
+        vqadd.s16       \o15,d31, d26 // out15
+.else
+        vqadd.s16       d4,  d16, d21 // out0
+        vqsub.s16       d21, d31, d26 // t3a
+        vqadd.s16       \o15,d31, d26 // out15
+        vmov            \o0, d4
+.endif
+        vqneg.s16       \o15, \o15    // out15
+
+        vqsub.s16       d3,  d29, d18 // t15a
+        vqadd.s16       \o13,d29, d18 // out13
+        vqadd.s16       \o2, d17, d30 // out2
+        vqsub.s16       d26, d17, d30 // t14a
+        vqneg.s16       \o13,\o13     // out13
+
+        vqadd.s16       \o1, d19, d27 // out1
+        vqsub.s16       d27, d19, d27 // t10
+        vqadd.s16       \o14,d28, d20 // out14
+        vqsub.s16       d20, d28, d20 // t11
+        vqneg.s16       \o1, \o1      // out1
+
+        vqadd.s16       \o3, d22, d24 // out3
+        vqsub.s16       d22, d22, d24 // t6
+        vqadd.s16       \o12,d25, d23 // out12
+        vqsub.s16       d23, d25, d23 // t7
+        vqneg.s16       \o3, \o3      // out3
+
+        vmull_vmlsl     q12, d2,  d21, d0[0], d0[0] // -> out8 (d24 or d23)
+        vmull_vmlal     q2,  d2,  d21, d0[0], d0[0] // -> out7 (d23 or d24)
+        vmull_vmlal     q3,  d26, d3,  d0[0], d0[0] // -> out5 (d21 or d26)
+
+        vqrshrn.s32     d24, q12, #12 // out8
+        vqrshrn.s32     d4,  q2,  #12 // out7
+        vqrshrn.s32     d5,  q3,  #12 // out5
+        vmull_vmlsl     q4,  d26, d3,  d0[0], d0[0] // -> out10 (d26 or d21)
+        vmull_vmlal     q1,  d22, d23, d0[0], d0[0] // -> out4 (d20 or d27)
+        vqrshrn.s32     d26, q4,  #12 // out10
+
+        vmull_vmlsl     q4,  d22, d23, d0[0], d0[0] // -> out11 (d27 or d20)
+        vmull_vmlal     q11, d27, d20, d0[0], d0[0] // -> out6 (d22 or d25)
+        vmull_vmlsl     q3,  d27, d20, d0[0], d0[0] // -> out9 (d25 or d22)
+
+        vqrshrn.s32     \o4, q1,  #12 // out4
+        vqrshrn.s32     d7,  q3,  #12 // out9
+        vqrshrn.s32     d6,  q4,  #12 // out11
+        vqrshrn.s32     \o6, q11, #12 // out6
+
+.ifc \o8, d23
+        vmov            \o8, d24
+        vmov            \o10,d26
+.endif
+
+        vqneg.s16       \o7, d4  // out7
+        vqneg.s16       \o5, d5  // out5
+        vqneg.s16       \o11,d6  // out11
+        vqneg.s16       \o9, d7  // out9
+.endm
+
+function inv_adst_4h_x16_neon, export=1
+        iadst_16        d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        bx              lr
+endfunc
+
+function inv_flipadst_4h_x16_neon, export=1
+        iadst_16        d31, d30, d29, d28, d27, d26, d25, d24, d23, d22, d21, d20, d19, d18, d17, d16
+        bx              lr
+endfunc
+
+function inv_identity_4h_x16_neon, export=1
+        movw            r12, #2*(5793-4096)*8
+        vdup.16         d0,  r12
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vqrdmulh.s16    q1,  \i,  d0[0]
+        vqadd.s16       \i,  \i,  \i
+        vqadd.s16       \i,  \i,  q1
+.endr
+        bx              lr
+endfunc
+
+.macro identity_4x16_shift2 c
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vqrdmulh.s16    q2,  \i,  \c
+        vshr.s16        q2,  q2,  #1
+        vrhadd.s16      \i,  \i,  q2
+.endr
+.endm
+
+.macro identity_4x16_shift1 c
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vqrdmulh.s16    q2,  \i,  \c
+        vrshr.s16       q2,  q2,  #1
+        vqadd.s16       \i,  \i,  q2
+.endr
+.endm
+
+.macro identity_8x8_shift1 c
+        identity_4x16_shift1 \c
+.endm
+
+.macro identity_8x8 c
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vqrdmulh.s16    q2,  \i,  \c
+        vqadd.s16       \i,  \i,  \i
+        vqadd.s16       \i,  \i,  q2
+.endr
+.endm
+
+.macro def_horz_16 scale=0, identity=0, shift=2, suffix
+function inv_txfm_horz\suffix\()_16x4_neon
+        push            {lr}
+        vmov.i16        d7,  #0
+.if \identity
+        movw            r12, #2*(5793-4096)*8
+        vdup.16         d0,  r12
+.endif
+.if \scale
+        movw            r12, #2896*8
+        vdup.16         d1,  r12
+.endif
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64]
+        vst1.16         {d7}, [r7, :64], r8
+.endr
+.if \scale
+        scale_input     d1[0], q8,  q9, q10, q11, q12, q13, q14, q15
+.endif
+.if \identity
+.if \shift == -2
+        identity_4x16_shift2 d0[0]
+.else
+        identity_4x16_shift1 d0[0]
+.endif
+        b               L(horz_16x4_epilog)
+.else
+        blx             r4
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vrshr.s16       \i,  \i,  #\shift
+.endr
+.if \shift == 1
+        b               L(horz_16x4_epilog)
+.else
+L(horz_16x4_epilog):
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+        transpose_4x4h  q14, q15, d28, d29, d30, d31
+
+.irp i, d16, d20, d24, d28, d17, d21, d25, d29, d18, d22, d26, d30, d19, d23, d27, d31
+        vst1.16         {\i}, [r6, :64]!
+.endr
+
+        pop             {pc}
+.endif
+.endif
+endfunc
+.endm
+
+def_horz_16 scale=1, identity=1, shift=-1, suffix=_scale_identity
+def_horz_16 scale=0, identity=1, shift=-2, suffix=_identity
+def_horz_16 scale=1, identity=0, shift=1, suffix=_scale
+def_horz_16 scale=0, identity=0, shift=2
+
+function inv_txfm_add_vert_4x16_neon
+        push            {lr}
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64], r8
+.endr
+        blx             r5
+        load_add_store_4x16 r6, r7
+        pop             {pc}
+endfunc
+
+function inv_txfm_add_16x16_neon
+        sub_sp_align    512
+        ldrh            r11, [r10], #2
+.irp i, 0, 4, 8, 12
+        add             r6,  sp,  #(\i*16*2)
+.if \i > 0
+        mov             r8,  #(16 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 12
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #16*2
+        blx             r9
+.endr
+        b               3f
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #4
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+3:
+.irp i, 0, 4, 8, 12
+        add             r6,  r0,  #(\i)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #32
+        bl              inv_txfm_add_vert_4x16_neon
+.endr
+
+        add_sp_align    512
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
+
+const eob_16x16
+        .short 10, 36, 78, 256
+endconst
+
+const eob_16x16_identity
+        .short 4, 8, 12, 256
+endconst
+
+.macro def_fn_16x16 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_16x16_8bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         16,  16,  2
+.endif
+        push            {r4-r11,lr}
+        vpush           {q4}
+.ifc \txfm1, identity
+        movrel_local    r9,  inv_txfm_horz_identity_16x4_neon
+.else
+        movrel_local    r9,  inv_txfm_horz_16x4_neon
+        movrel_local    r4,  inv_\txfm1\()_4h_x16_neon
+.endif
+        movrel_local    r5,  inv_\txfm2\()_4h_x16_neon
+.ifc \txfm1, identity
+.ifc \txfm2, identity
+        movrel_local    r10, eob_16x16
+.else
+        movrel_local    r10, eob_16x16_identity
+.endif
+.else
+.ifc \txfm2, identity
+        movrel_local    r10, eob_16x16_identity
+.else
+        movrel_local    r10, eob_16x16
+.endif
+.endif
+        b               inv_txfm_add_16x16_neon
+endfunc
+.endm
+
+def_fn_16x16 dct, dct
+def_fn_16x16 identity, identity
+def_fn_16x16 dct, adst
+def_fn_16x16 dct, flipadst
+def_fn_16x16 dct, identity
+def_fn_16x16 adst, dct
+def_fn_16x16 adst, adst
+def_fn_16x16 adst, flipadst
+def_fn_16x16 flipadst, dct
+def_fn_16x16 flipadst, adst
+def_fn_16x16 flipadst, flipadst
+def_fn_16x16 identity, dct
+
+.macro def_fn_416_base variant
+function inv_txfm_\variant\()add_16x4_neon
+
+.ifc \variant, identity_
+        vmov.i16        d4,  #0
+.irp i, d16, d18, d20, d22
+        vld1.16         {\i}, [r2, :64]
+        vst1.16         {d4}, [r2, :64]!
+.endr
+.irp i, d17, d19, d21, d23
+        vld1.16         {\i}, [r2, :64]
+        vst1.16         {d4}, [r2, :64]!
+.endr
+        movw            r12, #2*(5793-4096)*8
+        vdup.16         d0,  r12
+.irp i, d24, d26, d28, d30
+        vld1.16         {\i}, [r2, :64]
+        vst1.16         {d4}, [r2, :64]!
+.endr
+.irp i, d25, d27, d29, d31
+        vld1.16         {\i}, [r2, :64]
+        vst1.16         {d4}, [r2, :64]!
+.endr
+
+        identity_4x16_shift1 d0[0]
+
+        b               L(itx_16x4_epilog)
+.else
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+        vld1.16         {d16, d17, d18, d19}, [r2, :128]
+        vst1.16         {q2,  q3}, [r2, :128]!
+        vld1.16         {d20, d21, d22, d23}, [r2, :128]
+        vst1.16         {q2,  q3}, [r2, :128]!
+        vld1.16         {d24, d25, d26, d27}, [r2, :128]
+        vst1.16         {q2,  q3}, [r2, :128]!
+        vld1.16         {d28, d29, d30, d31}, [r2, :128]
+        vst1.16         {q2,  q3}, [r2, :128]!
+
+        blx             r4
+
+        vswp            d17, d20
+        vswp            d19, d22
+        vswp            d18, d20
+        vswp            d19, d21
+        vswp            d25, d28
+        vswp            d27, d30
+        vswp            d26, d28
+        vswp            d27, d29
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vrshr.s16       \i,  \i,  #1
+.endr
+
+L(itx_16x4_epilog):
+        transpose_4x8h  q8,  q9,  q10, q11
+        blx             r5
+        mov             r6,  r0
+        load_add_store_8x4 r6, r7
+
+        vmov            q8,  q12
+        vmov            q9,  q13
+        vmov            q10, q14
+        vmov            q11, q15
+
+        transpose_4x8h  q8,  q9,  q10, q11
+        blx             r5
+        add             r6,  r0,  #8
+        load_add_store_8x4 r6, r7
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+.endif
+endfunc
+
+function inv_txfm_\variant\()add_4x16_neon
+        vmov.i16        q2,  #0
+
+        mov             r11, #32
+        cmp             r3,  r10
+        blt             1f
+
+        add             r6,  r2,  #16
+.ifc \variant, identity_
+.irp i, q12, q13, q14, q15
+        vld1.16         {\i}, [r6, :128]
+        vst1.16         {q2}, [r6, :128], r11
+.endr
+        movw            r12, #(5793-4096)*8
+        vdup.16         d0,  r12
+        identity_8x4_shift1 q12, q13, q14, q15, d0[0]
+.else
+.irp i, q8,  q9,  q10, q11
+        vld1.16         {\i}, [r6, :128]
+        vst1.16         {q2}, [r6, :128], r11
+.endr
+        blx             r4
+        vrshr.s16       q12, q8,  #1
+        vrshr.s16       q13, q9,  #1
+        vrshr.s16       q14, q10, #1
+        vrshr.s16       q15, q11, #1
+.endif
+        transpose_4x8h  q12, q13, q14, q15
+        vswp            d27, d29
+        vswp            d26, d28
+        vswp            d27, d30
+        vswp            d25, d28
+
+        b               2f
+1:
+.irp i, q12, q13, q14, q15
+        vmov.i16        \i,  #0
+.endr
+2:
+        vmov.i16        q2,  #0
+.irp i, q8,  q9,  q10, q11
+        vld1.16         {\i}, [r2, :128]
+        vst1.16         {q2}, [r2, :128], r11
+.endr
+.ifc \variant, identity_
+        movw            r12, #(5793-4096)*8
+        vdup.16         d0,  r12
+        identity_8x4_shift1 q8,  q9,  q10, q11, d0[0]
+
+        b               L(itx_4x16_epilog)
+.else
+        blx             r4
+.irp i, q8, q9, q10, q11
+        vrshr.s16       \i,  \i,  #1
+.endr
+L(itx_4x16_epilog):
+        transpose_4x8h  q8,  q9,  q10, q11
+        vswp            d19, d21
+        vswp            d18, d20
+        vswp            d19, d22
+        vswp            d17, d20
+
+        blx             r5
+
+        load_add_store_4x16 r0, r6
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+.endif
+endfunc
+.endm
+
+def_fn_416_base identity_
+def_fn_416_base
+
+.macro def_fn_416 w, h, txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  1
+.endif
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+.if \w == 4
+.ifnc \txfm1, identity
+        movrel_local    r4,  inv_\txfm1\()_8h_x\w\()_neon
+.endif
+        movrel_local    r5,  inv_\txfm2\()_4h_x\h\()_neon
+        mov             r10, #\eob_half
+.else
+.ifnc \txfm1, identity
+        movrel_local    r4,  inv_\txfm1\()_4h_x\w\()_neon
+.endif
+        movrel_local    r5,  inv_\txfm2\()_8h_x\h\()_neon
+.endif
+.ifc \txfm1, identity
+        b               inv_txfm_identity_add_\w\()x\h\()_neon
+.else
+        b               inv_txfm_add_\w\()x\h\()_neon
+.endif
+endfunc
+.endm
+
+.macro def_fns_416 w, h
+def_fn_416 \w, \h, dct, dct, 29
+def_fn_416 \w, \h, identity, identity, 29
+def_fn_416 \w, \h, dct, adst, 29
+def_fn_416 \w, \h, dct, flipadst, 29
+def_fn_416 \w, \h, dct, identity, 8
+def_fn_416 \w, \h, adst, dct, 29
+def_fn_416 \w, \h, adst, adst, 29
+def_fn_416 \w, \h, adst, flipadst, 29
+def_fn_416 \w, \h, flipadst, dct, 29
+def_fn_416 \w, \h, flipadst, adst, 29
+def_fn_416 \w, \h, flipadst, flipadst, 29
+def_fn_416 \w, \h, identity, dct, 32
+def_fn_416 \w, \h, adst, identity, 8
+def_fn_416 \w, \h, flipadst, identity, 8
+def_fn_416 \w, \h, identity, adst, 32
+def_fn_416 \w, \h, identity, flipadst, 32
+.endm
+
+def_fns_416 4, 16
+def_fns_416 16, 4
+
+function inv_txfm_add_16x8_neon
+        sub_sp_align    256
+
+.irp i, 0, 4
+        add             r6,  sp,  #(\i*16*2)
+.if \i > 0
+        cmp             r3,  r10
+        blt             1f
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #8*2
+        blx             r9
+.endr
+        b               2f
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+2:
+
+.irp i, 0, 8
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #32
+.irp j, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\j}, [r7, :128], r8
+.endr
+        blx             r5
+
+        add             r6,  r0,  #(\i)
+        load_add_store_8x8 r6, r7
+.endr
+
+        add_sp_align    256
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+.macro def_fn_816_base variant
+function inv_txfm_\variant\()add_8x16_neon
+        sub_sp_align    256
+
+.irp i, 0, 8
+        add             r6,  sp,  #(\i*8*2)
+.if \i > 0
+        cmp             r3,  r10
+        blt             1f
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #16*2
+
+        vmov.i16        q2,  #0
+        movw            r12, #2896*8
+        vdup.16         d0,  r12
+
+.irp j, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\j}, [r7, :128]
+        vst1.16         {q2}, [r7, :128], r8
+.endr
+        scale_input     d0[0], q8,  q9,  q10, q11, q12, q13, q14, q15
+.ifc \variant, identity_
+        // The identity shl #1 and downshift vrshr #1 cancel out
+.else
+        blx             r4
+.irp j, q8, q9, q10, q11, q12, q13, q14, q15
+        vrshr.s16       \j,  \j,  #1
+.endr
+.endif
+        transpose_8x8h  q8,  q9,  q10, q11, q12, q13, q14, q15, d17, d19, d21, d23, d24, d26, d28, d30
+        vst1.16         {q8,  q9},  [r6, :128]!
+        vst1.16         {q10, q11}, [r6, :128]!
+        vst1.16         {q12, q13}, [r6, :128]!
+        vst1.16         {q14, q15}, [r6, :128]!
+.endr
+        b               2f
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+2:
+
+.ifc \variant, identity_
+        b               L(itx_8x16_epilog)
+.else
+L(itx_8x16_epilog):
+.irp i, 0, 4
+        add             r6,  r0,  #(\i)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #16
+        bl              inv_txfm_add_vert_4x16_neon
+.endr
+
+        add_sp_align    256
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+.endif
+endfunc
+.endm
+
+def_fn_816_base identity_
+def_fn_816_base
+
+/* Define symbols used in .if statement */
+.equ dct, 1
+.equ identity, 2
+.equ adst, 3
+.equ flipadst, 4
+
+.macro def_fn_816 w, h, txfm1, txfm2, eob_8x8, eob_4x4
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  1
+.endif
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+.if \w == 8
+.ifnc \txfm1, identity
+        movrel_local    r4,  inv_\txfm1\()_8h_x8_neon
+.endif
+        movrel_local    r5,  inv_\txfm2\()_4h_x16_neon
+.else
+.ifc \txfm1, identity
+        movrel_local    r9,  inv_txfm_horz_scale_identity_16x4_neon
+.else
+        movrel_local    r4,  inv_\txfm1\()_4h_x16_neon
+        movrel_local    r9,  inv_txfm_horz_scale_16x4_neon
+.endif
+        movrel_local    r5,  inv_\txfm2\()_8h_x8_neon
+.endif
+.if \w == 8
+        mov             r10, #\eob_8x8
+.else
+        mov             r10, #\eob_4x4
+.endif
+.if \w == 8 && \txfm1 == identity
+        b               inv_txfm_identity_add_\w\()x\h\()_neon
+.else
+        b               inv_txfm_add_\w\()x\h\()_neon
+.endif
+endfunc
+.endm
+
+.macro def_fns_816 w, h
+def_fn_816 \w, \h, dct, dct, 43, 10
+def_fn_816 \w, \h, identity, identity, 43, 10
+def_fn_816 \w, \h, dct, adst, 43, 10
+def_fn_816 \w, \h, dct, flipadst, 43, 10
+def_fn_816 \w, \h, dct, identity, 8, 4
+def_fn_816 \w, \h, adst, dct, 43, 10
+def_fn_816 \w, \h, adst, adst, 43, 10
+def_fn_816 \w, \h, adst, flipadst, 43, 10
+def_fn_816 \w, \h, flipadst, dct, 43, 10
+def_fn_816 \w, \h, flipadst, adst, 43, 10
+def_fn_816 \w, \h, flipadst, flipadst, 43, 10
+def_fn_816 \w, \h, identity, dct, 64, 4
+def_fn_816 \w, \h, adst, identity, 8, 4
+def_fn_816 \w, \h, flipadst, identity, 8, 4
+def_fn_816 \w, \h, identity, adst, 64, 4
+def_fn_816 \w, \h, identity, flipadst, 64, 4
+.endm
+
+def_fns_816 8, 16
+def_fns_816 16, 8
+
+function inv_dct32_odd_4h_x16_neon, export=1
+        movrel_local    r12, idct_coeffs, 2*16
+        vld1.16         {q0, q1}, [r12, :128]
+        sub             r12, r12, #2*16
+
+        vmull_vmlsl     q2,  d16, d31, d0[0], d0[1] // -> t16a
+        vmull_vmlal     q3,  d16, d31, d0[1], d0[0] // -> t31a
+        vmull_vmlsl     q4,  d24, d23, d0[2], d0[3] // -> t17a
+        vqrshrn.s32     d16, q2,  #12               // t16a
+        vqrshrn.s32     d31, q3,  #12               // t31a
+        vmull_vmlal     q2,  d24, d23, d0[3], d0[2] // -> t30a
+        vmull_vmlsl     q3,  d20, d27, d1[0], d1[1] // -> t18a
+        vqrshrn.s32     d24, q4,  #12               // t17a
+        vqrshrn.s32     d23, q2,  #12               // t30a
+        vmull_vmlal     q4,  d20, d27, d1[1], d1[0] // -> t29a
+        vmull_vmlsl     q2,  d28, d19, d1[2], d1[3] // -> t19a
+        vqrshrn.s32     d20, q3,  #12               // t18a
+        vqrshrn.s32     d27, q4,  #12               // t29a
+        vmull_vmlal     q3,  d28, d19, d1[3], d1[2] // -> t28a
+        vmull_vmlsl     q4,  d18, d29, d2[0], d2[1] // -> t20a
+        vqrshrn.s32     d28, q2,  #12               // t19a
+        vqrshrn.s32     d19, q3,  #12               // t28a
+        vmull_vmlal     q2,  d18, d29, d2[1], d2[0] // -> t27a
+        vmull_vmlsl     q3,  d26, d21, d2[2], d2[3] // -> t21a
+        vqrshrn.s32     d18, q4,  #12               // t20a
+        vqrshrn.s32     d29, q2,  #12               // t27a
+        vmull_vmlal     q4,  d26, d21, d2[3], d2[2] // -> t26a
+        vmull_vmlsl     q2,  d22, d25, d3[0], d3[1] // -> t22a
+        vqrshrn.s32     d26, q3,  #12               // t21a
+        vqrshrn.s32     d21, q4,  #12               // t26a
+        vmull_vmlal     q3,  d22, d25, d3[1], d3[0] // -> t25a
+        vmull_vmlsl     q4,  d30, d17, d3[2], d3[3] // -> t23a
+        vqrshrn.s32     d22, q2,  #12               // t22a
+        vqrshrn.s32     d25, q3,  #12               // t25a
+        vmull_vmlal     q2,  d30, d17, d3[3], d3[2] // -> t24a
+        vqrshrn.s32     d30, q4,  #12               // t23a
+        vqrshrn.s32     d17, q2,  #12               // t24a
+
+        vld1.16         {q0}, [r12, :128]
+
+        vqsub.s16       d2,  d16, d24 // t17
+        vqadd.s16       d16, d16, d24 // t16
+        vqsub.s16       d3,  d31, d23 // t30
+        vqadd.s16       d31, d31, d23 // t31
+        vqsub.s16       d24, d28, d20 // t18
+        vqadd.s16       d28, d28, d20 // t19
+        vqadd.s16       d23, d18, d26 // t20
+        vqsub.s16       d18, d18, d26 // t21
+        vqsub.s16       d20, d30, d22 // t22
+        vqadd.s16       d30, d30, d22 // t23
+        vqadd.s16       d26, d17, d25 // t24
+        vqsub.s16       d17, d17, d25 // t25
+        vqsub.s16       d22, d29, d21 // t26
+        vqadd.s16       d29, d29, d21 // t27
+        vqadd.s16       d25, d19, d27 // t28
+        vqsub.s16       d19, d19, d27 // t29
+
+        vmull_vmlsl     q2,  d3,  d2,  d1[0], d1[1] // -> t17a
+        vmull_vmlal     q3,  d3,  d2,  d1[1], d1[0] // -> t30a
+        vmull_vmlal     q4,  d19, d24, d1[1], d1[0] // -> t18a
+        vqrshrn.s32     d21, q2,  #12               // t17a
+        vqrshrn.s32     d27, q3,  #12               // t30a
+        vneg.s32        q4,  q4                     // -> t18a
+        vmull_vmlsl     q1,  d19, d24, d1[0], d1[1] // -> t29a
+        vmull_vmlsl     q2,  d22, d18, d1[2], d1[3] // -> t21a
+        vqrshrn.s32     d19, q4,  #12               // t18a
+        vqrshrn.s32     d24, q1,  #12               // t29a
+        vmull_vmlal     q3,  d22, d18, d1[3], d1[2] // -> t26a
+        vmull_vmlal     q4,  d17, d20, d1[3], d1[2] // -> t22a
+        vqrshrn.s32     d22, q2,  #12               // t21a
+        vqrshrn.s32     d18, q3,  #12               // t26a
+        vneg.s32        q4,  q4                     // -> t22a
+        vmull_vmlsl     q1,  d17, d20, d1[2], d1[3] // -> t25a
+        vqrshrn.s32     d17, q4,  #12               // t22a
+        vqrshrn.s32     d20, q1,  #12               // t25a
+
+        vqsub.s16       d2,  d27, d24 // t29
+        vqadd.s16       d27, d27, d24 // t30
+        vqsub.s16       d3,  d21, d19 // t18
+        vqadd.s16       d21, d21, d19 // t17
+        vqsub.s16       d24, d16, d28 // t19a
+        vqadd.s16       d16, d16, d28 // t16a
+        vqsub.s16       d19, d30, d23 // t20a
+        vqadd.s16       d30, d30, d23 // t23a
+        vqsub.s16       d28, d17, d22 // t21
+        vqadd.s16       d17, d17, d22 // t22
+        vqadd.s16       d23, d26, d29 // t24a
+        vqsub.s16       d26, d26, d29 // t27a
+        vqadd.s16       d22, d20, d18 // t25
+        vqsub.s16       d20, d20, d18 // t26
+        vqsub.s16       d29, d31, d25 // t28a
+        vqadd.s16       d31, d31, d25 // t31a
+
+        vmull_vmlsl     q2,  d2,  d3,  d0[2], d0[3] // -> t18a
+        vmull_vmlal     q3,  d2,  d3,  d0[3], d0[2] // -> t29a
+        vmull_vmlsl     q4,  d29, d24, d0[2], d0[3] // -> t19
+        vqrshrn.s32     d18, q2,  #12               // t18a
+        vqrshrn.s32     d25, q3,  #12               // t29a
+        vmull_vmlal     q1,  d29, d24, d0[3], d0[2] // -> t28
+        vmull_vmlal     q2,  d26, d19, d0[3], d0[2] // -> t20
+        vqrshrn.s32     d29, q4,  #12               // t19
+        vqrshrn.s32     d24, q1,  #12               // t28
+        vneg.s32        q2,  q2                     // -> t20
+        vmull_vmlsl     q3,  d26, d19, d0[2], d0[3] // -> t27
+        vmull_vmlal     q4,  d20, d28, d0[3], d0[2] // -> t21a
+        vqrshrn.s32     d26, q2,  #12               // t20
+        vqrshrn.s32     d19, q3,  #12               // t27
+        vneg.s32        q4,  q4                     // -> t21a
+        vmull_vmlsl     q1,  d20, d28, d0[2], d0[3] // -> t26a
+        vqrshrn.s32     d20, q4,  #12               // t21a
+        vqrshrn.s32     d28, q1,  #12               // t26a
+
+        vqsub.s16       d2,  d16, d30 // t23
+        vqadd.s16       d16, d16, d30 // t16 = out16
+        vqsub.s16       d3,  d31, d23 // t24
+        vqadd.s16       d31, d31, d23 // t31 = out31
+        vqsub.s16       d23, d21, d17 // t22a
+        vqadd.s16       d17, d21, d17 // t17a = out17
+        vqadd.s16       d30, d27, d22 // t30a = out30
+        vqsub.s16       d21, d27, d22 // t25a
+        vqsub.s16       d27, d18, d20 // t21
+        vqadd.s16       d18, d18, d20 // t18 = out18
+        vqadd.s16       d4,  d29, d26 // t19a = out19
+        vqsub.s16       d26, d29, d26 // t20a
+        vqadd.s16       d29, d25, d28 // t29 = out29
+        vqsub.s16       d25, d25, d28 // t26
+        vqadd.s16       d28, d24, d19 // t28a = out28
+        vqsub.s16       d24, d24, d19 // t27a
+        vmov            d19, d4       // out19
+
+        vmull_vmlsl     q2,  d24, d26, d0[0], d0[0] // -> t20
+        vmull_vmlal     q3,  d24, d26, d0[0], d0[0] // -> t27
+        vqrshrn.s32     d20, q2,  #12   // t20
+        vqrshrn.s32     d22, q3,  #12   // t27
+
+        vmull_vmlal     q2,  d25, d27, d0[0], d0[0] // -> t26a
+        vmull_vmlsl     q3,  d25, d27, d0[0], d0[0] // -> t21a
+        vmov            d27, d22        // t27
+        vqrshrn.s32     d26, q2,  #12   // t26a
+
+        vmull_vmlsl     q12, d21, d23, d0[0], d0[0] // -> t22
+        vmull_vmlal     q2,  d21, d23, d0[0], d0[0] // -> t25
+        vqrshrn.s32     d21, q3,  #12   // t21a
+        vqrshrn.s32     d22, q12, #12   // t22
+        vqrshrn.s32     d25, q2,  #12   // t25
+
+        vmull_vmlsl     q2,  d3,  d2,  d0[0], d0[0] // -> t23a
+        vmull_vmlal     q3,  d3,  d2,  d0[0], d0[0] // -> t24a
+        vqrshrn.s32     d23, q2,  #12   // t23a
+        vqrshrn.s32     d24, q3,  #12   // t24a
+
+        bx              lr
+endfunc
+
+.macro def_horz_32 scale=0, shift=2, suffix
+function inv_txfm_horz\suffix\()_dct_32x4_neon
+        push            {lr}
+        vmov.i16        d7,  #0
+        lsl             r8,  r8,  #1
+.if \scale
+        movw            r12, #2896*8
+        vdup.16         d0,  r12
+.endif
+
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64]
+        vst1.16         {d7}, [r7, :64], r8
+.endr
+        sub             r7,  r7,  r8, lsl #4
+        add             r7,  r7,  r8, lsr #1
+.if \scale
+        scale_input     d0[0], q8,  q9,  q10, q11, q12, q13, q14, q15
+.endif
+        bl              inv_dct_4h_x16_neon
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+        transpose_4x4h  q14, q15, d28, d29, d30, d31
+
+.macro store1 r0, r1, r2, r3
+        vst1.16         {\r0}, [r6, :64]!
+        vst1.16         {\r1}, [r6, :64]!
+        vst1.16         {\r2}, [r6, :64]!
+        vst1.16         {\r3}, [r6, :64]!
+        add             r6,  r6,  #32
+.endm
+        store1          d16, d20, d24, d28
+        store1          d17, d21, d25, d29
+        store1          d18, d22, d26, d30
+        store1          d19, d23, d27, d31
+.purgem store1
+        sub             r6,  r6,  #64*4
+
+        vmov.i16        d7,  #0
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64]
+        vst1.16         {d7}, [r7, :64], r8
+.endr
+.if \scale
+        // This relies on the fact that the idct also leaves the right coeff in d0[1]
+        scale_input     d0[1], q8,  q9,  q10, q11, q12, q13, q14, q15
+.endif
+        bl              inv_dct32_odd_4h_x16_neon
+        transpose_4x4h  q15, q14, d31, d30, d29, d28
+        transpose_4x4h  q13, q12, d27, d26, d25, d24
+        transpose_4x4h  q11, q10, d23, d22, d21, d20
+        transpose_4x4h  q9,  q8,  d19, d18, d17, d16
+.macro store2 r0, r1, r2, r3, shift
+        vld1.16         {q0, q1}, [r6, :128]
+        vqsub.s16       d7,  d0,  \r0
+        vqadd.s16       d0,  d0,  \r0
+        vqsub.s16       d6,  d1,  \r1
+        vqadd.s16       d1,  d1,  \r1
+        vqsub.s16       d5,  d2,  \r2
+        vqadd.s16       d2,  d2,  \r2
+        vqsub.s16       d4,  d3,  \r3
+        vqadd.s16       d3,  d3,  \r3
+        vrev64.16       q2,  q2
+        vrev64.16       q3,  q3
+        vrshr.s16       q0,  q0,  #\shift
+        vrshr.s16       q1,  q1,  #\shift
+        vrshr.s16       q2,  q2,  #\shift
+        vrshr.s16       q3,  q3,  #\shift
+        vst1.16         {q0, q1}, [r6, :128]!
+        vst1.16         {q2, q3}, [r6, :128]!
+.endm
+
+        store2          d31, d27, d23, d19, \shift
+        store2          d30, d26, d22, d18, \shift
+        store2          d29, d25, d21, d17, \shift
+        store2          d28, d24, d20, d16, \shift
+.purgem store2
+        pop             {pc}
+endfunc
+.endm
+
+def_horz_32 scale=0, shift=2
+def_horz_32 scale=1, shift=1, suffix=_scale
+
+function inv_txfm_add_vert_dct_4x32_neon
+        push            {r10-r11,lr}
+        lsl             r8,  r8,  #1
+
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64], r8
+.endr
+        sub             r7,  r7,  r8, lsl #4
+
+        bl              inv_dct_4h_x16_neon
+
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vst1.16         {\i}, [r7, :64], r8
+.endr
+        sub             r7,  r7,  r8, lsl #4
+        add             r7,  r7,  r8, lsr #1
+
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64], r8
+.endr
+        sub             r7,  r7,  r8, lsl #4
+        sub             r7,  r7,  r8, lsr #1
+        bl              inv_dct32_odd_4h_x16_neon
+
+        neg             r9,  r8
+        mov             r10, r6
+.macro combine r0, r1, r2, r3, op, stride
+        vld1.16         {d4},    [r7,  :64], \stride
+        vld1.32         {d2[0]}, [r10, :32], r1
+        vld1.16         {d5},    [r7,  :64],  \stride
+        vld1.32         {d2[1]}, [r10, :32], r1
+        \op\().s16      d4,  d4,  \r0
+        vld1.16         {d6},    [r7,  :64], \stride
+        vld1.32         {d3[0]}, [r10, :32], r1
+        \op\().s16      d5,  d5,  \r1
+        vld1.32         {d3[1]}, [r10, :32], r1
+        vrshr.s16       q2,  q2,  #4
+        \op\().s16      d6,  d6,  \r2
+        vld1.16         {d7},    [r7,  :64], \stride
+        vaddw.u8        q2,  q2,  d2
+        \op\().s16      d7,  d7,  \r3
+        vqmovun.s16     d2,  q2
+        vrshr.s16       q3,  q3,  #4
+        vst1.32         {d2[0]}, [r6,  :32], r1
+        vaddw.u8        q3,  q3,  d3
+        vst1.32         {d2[1]}, [r6,  :32], r1
+        vqmovun.s16     d3,  q3
+        vst1.32         {d3[0]}, [r6,  :32], r1
+        vst1.32         {d3[1]}, [r6,  :32], r1
+.endm
+        combine         d31, d30, d29, d28, vqadd, r8
+        combine         d27, d26, d25, d24, vqadd, r8
+        combine         d23, d22, d21, d20, vqadd, r8
+        combine         d19, d18, d17, d16, vqadd, r8
+        sub             r7,  r7,  r8
+        combine         d16, d17, d18, d19, vqsub, r9
+        combine         d20, d21, d22, d23, vqsub, r9
+        combine         d24, d25, d26, d27, vqsub, r9
+        combine         d28, d29, d30, d31, vqsub, r9
+.purgem combine
+
+        pop             {r10-r11,pc}
+endfunc
+
+const eob_32x32
+        .short 10, 36, 78, 136, 210, 300, 406, 1024
+endconst
+
+const eob_16x32
+        .short 10, 36, 78, 151, 215, 279, 343, 512
+endconst
+
+const eob_16x32_shortside
+        .short 10, 36, 78, 512
+endconst
+
+const eob_8x32
+        // Contrary to the others, this one is only ever used in increments of 8x8
+        .short 43, 107, 171, 256
+endconst
+
+function inv_txfm_add_identity_identity_32x32_8bpc_neon, export=1
+        push            {r4-r7,lr}
+        vmov.i16        q0,  #0
+        movrel_local    r5,  eob_32x32, 2
+
+        mov             r6,  #2*32
+1:
+        mov             r12, #0
+        movrel_local    r4,  eob_32x32, 2
+2:
+        add             r12, r12, #8
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\i}, [r2, :128]
+        vst1.16         {q0}, [r2, :128], r6
+.endr
+        transpose_8x8h  q8,  q9,  q10, q11, q12, q13, q14, q15, d17, d19, d21, d23, d24, d26, d28, d30
+
+        load_add_store_8x8 r0, r7, shiftbits=2
+        ldrh            lr,  [r4], #4
+        sub             r0,  r0,  r1, lsl #3
+        cmp             r3,  lr
+        add             r0,  r0,  #8
+        bge             2b
+
+        ldrh            lr,  [r5], #4
+        cmp             r3,  lr
+        blt             9f
+
+        sub             r0,  r0,  r12
+        add             r0,  r0,  r1, lsl #3
+        mls             r2,  r6,  r12, r2
+        add             r2,  r2,  #2*8
+        b               1b
+9:
+        pop             {r4-r7,pc}
+endfunc
+
+.macro shift_8_regs op, shift
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        \op             \i,  \i,  #\shift
+.endr
+.endm
+
+.macro def_identity_1632 w, h, wshort, hshort
+function inv_txfm_add_identity_identity_\w\()x\h\()_8bpc_neon, export=1
+        push            {r4-r7,lr}
+        movw            r6,  #2896*8
+        movw            r7,  #2*(5793-4096)*8
+        vdup.i16        d0,  r6
+        movrel_local    r5,  eob_16x32\hshort, 2
+        vmov.16         d0[1], r7
+
+        mov             r6,  #2*\h
+1:
+        mov             r12, #0
+        movrel_local    r4,  eob_16x32\wshort, 2
+2:
+        vmov.i16        q1,  #0
+        add             r12, r12, #8
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\i}, [r2, :128]
+        vst1.16         {q1}, [r2, :128], r6
+.endr
+        scale_input     d0[0], q8,  q9, q10, q11, q12, q13, q14, q15
+
+.if \w == 16
+        // 16x32
+        identity_8x8_shift1 d0[1]
+.else
+        // 32x16
+        shift_8_regs    vqshl.s16, 1
+        identity_8x8    d0[1]
+.endif
+
+        transpose_8x8h  q8,  q9,  q10, q11, q12, q13, q14, q15, d17, d19, d21, d23, d24, d26, d28, d30
+
+.if \w == 16
+        load_add_store_8x8 r0, r7, shiftbits=2
+.else
+        load_add_store_8x8 r0, r7, shiftbits=4
+.endif
+        ldrh            lr,  [r4], #4
+        sub             r0,  r0,  r1, lsl #3
+        cmp             r3,  lr
+        add             r0,  r0,  #8
+        bge             2b
+
+        ldrh            lr,  [r5], #4
+        cmp             r3,  lr
+        blt             9f
+
+        sub             r0,  r0,  r12
+        add             r0,  r0,  r1, lsl #3
+        mls             r2,  r6,  r12, r2
+        add             r2,  r2,  #2*8
+        b               1b
+9:
+        pop             {r4-r7,pc}
+endfunc
+.endm
+
+def_identity_1632 16, 32, _shortside,
+def_identity_1632 32, 16, , _shortside
+
+.macro def_identity_832 w, h
+function inv_txfm_add_identity_identity_\w\()x\h\()_8bpc_neon, export=1
+        push            {r4-r5,lr}
+        vmov.i16        q0,  #0
+        movrel_local    r4,  eob_8x32
+
+        mov             r12, #2*\h
+1:
+        ldrh            lr,  [r4], #2
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\i}, [r2, :128]
+        vst1.16         {q0}, [r2, :128], r12
+.endr
+
+.if \w == 8
+        // 8x32
+        shift_8_regs    vrshr.s16, 1
+.endif
+
+        transpose_8x8h  q8,  q9,  q10, q11, q12, q13, q14, q15, d17, d19, d21, d23, d24, d26, d28, d30
+
+        cmp             r3,  lr
+.if \w == 8
+        load_add_store_8x8 r0, r5, shiftbits=2
+.else
+        load_add_store_8x8 r0, r5, shiftbits=3
+.endif
+
+        blt             9f
+.if \w == 8
+        sub             r2,  r2,  r12, lsl #3
+        add             r2,  r2,  #2*8
+.else
+        sub             r0,  r0,  r1, lsl #3
+        add             r0,  r0,  #8
+.endif
+        b               1b
+
+9:
+        pop             {r4-r5,pc}
+endfunc
+.endm
+
+def_identity_832 8, 32
+def_identity_832 32, 8
+
+function inv_txfm_add_dct_dct_32x32_8bpc_neon, export=1
+        idct_dc         32,  32,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4}
+        sub_sp_align    2048
+        movrel_local    r10, eob_32x32
+        ldrh            r11, [r10], #2
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  sp,  #(\i*32*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 28
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_horz_dct_32x4_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  r0,  #(\i)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_add_vert_dct_4x32_neon
+.endr
+
+        add_sp_align    2048
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_16x32_8bpc_neon, export=1
+        idct_dc         16,  32,  1
+
+        push            {r4-r11,lr}
+        vpush           {q4}
+        sub_sp_align    1024
+        movrel_local    r10, eob_16x32
+        ldrh            r11, [r10], #2
+        movrel_local    r4,  inv_dct_4h_x16_neon
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  sp,  #(\i*16*2)
+        add             r7,  r2,  #(\i*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 28
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        mov             r8,  #2*32
+        bl              inv_txfm_horz_scale_16x4_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #4
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12
+        add             r6,  r0,  #(\i)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #16*2
+        bl              inv_txfm_add_vert_dct_4x32_neon
+.endr
+
+        add_sp_align    1024
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_32x16_8bpc_neon, export=1
+        idct_dc         32,  16,  1
+
+        push            {r4-r11,lr}
+        vpush           {q4}
+        sub_sp_align    1024
+        movrel_local    r10, eob_16x32
+        ldrh            r11, [r10], #2
+        movrel_local    r5,  inv_dct_4h_x16_neon
+
+.irp i, 0, 4, 8, 12
+        add             r6,  sp,  #(\i*32*2)
+        add             r7,  r2,  #(\i*2)
+.if \i > 0
+        mov             r8,  #(16 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 12
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        mov             r8,  #2*16
+        bl              inv_txfm_horz_scale_dct_32x4_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  r0,  #(\i)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_add_vert_4x16_neon
+.endr
+
+        add_sp_align    1024
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_8x32_8bpc_neon, export=1
+        idct_dc         8,   32,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        sub_sp_align    512
+
+        movrel_local    r10, eob_8x32
+
+        mov             r8,  #2*32
+        mov             r9,  #32
+        mov             r6,  sp
+1:
+        vmov.i16        q0,  #0
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\i}, [r2, :128]
+        vst1.16         {q0}, [r2, :128], r8
+.endr
+        ldrh            r11, [r10], #2
+        sub             r2,  r2,  r8, lsl #3
+        sub             r9,  r9,  #8
+        add             r2,  r2,  #2*8
+
+        bl              inv_dct_8h_x8_neon
+
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vrshr.s16       \i,  \i,  #2
+.endr
+
+        transpose_8x8h  q8,  q9,  q10, q11, q12, q13, q14, q15, d17, d19, d21, d23, d24, d26, d28, d30
+
+        vst1.16         {q8,  q9},  [r6, :128]!
+        cmp             r3,  r11
+        vst1.16         {q10, q11}, [r6, :128]!
+        vst1.16         {q12, q13}, [r6, :128]!
+        vst1.16         {q14, q15}, [r6, :128]!
+
+        bge             1b
+        cmp             r9,  #0
+        beq             3f
+
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r9,  r9,  #8
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4
+        add             r6,  r0,  #(\i)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #8*2
+        bl              inv_txfm_add_vert_dct_4x32_neon
+.endr
+
+        add_sp_align    512
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_32x8_8bpc_neon, export=1
+        idct_dc         32,  8,   2
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        sub_sp_align    512
+
+.irp i, 0, 4
+        add             r6,  sp,  #(\i*32*2)
+        add             r7,  r2,  #(\i*2)
+.if \i > 0
+        cmp             r3,  #10
+        blt             1f
+.endif
+        mov             r8,  #8*2
+        bl              inv_txfm_horz_dct_32x4_neon
+.endr
+        b               2f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+.rept 8
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+
+2:
+        mov             r8,  #2*32
+        mov             r9,  #0
+1:
+        add             r6,  r0,  r9
+        add             r7,  sp,  r9, lsl #1 // #(\i*2)
+
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\i}, [r7, :128], r8
+.endr
+        add             r9,  r9,  #8
+
+        bl              inv_dct_8h_x8_neon
+
+        cmp             r9,  #32
+
+        load_add_store_8x8 r6, r7
+
+        blt             1b
+
+        add_sp_align    512
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_dct64_step1_neon
+        // in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+        // in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+        // in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+        // in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+
+        vld1.16         {d0, d1, d2}, [r12, :64]!
+
+        vqrdmulh.s16    d23, d16, d0[1]  // t63a
+        vqrdmulh.s16    d16, d16, d0[0]  // t32a
+        vqrdmulh.s16    d22, d17, d0[2]  // t62a
+        vqrdmulh.s16    d17, d17, d0[3]  // t33a
+        vqrdmulh.s16    d21, d18, d1[1]  // t61a
+        vqrdmulh.s16    d18, d18, d1[0]  // t34a
+        vqrdmulh.s16    d20, d19, d1[2]  // t60a
+        vqrdmulh.s16    d19, d19, d1[3]  // t35a
+
+        vqadd.s16       d24, d16, d17    // t32
+        vqsub.s16       d25, d16, d17    // t33
+        vqsub.s16       d26, d19, d18    // t34
+        vqadd.s16       d27, d19, d18    // t35
+        vqadd.s16       d28, d20, d21    // t60
+        vqsub.s16       d29, d20, d21    // t61
+        vqsub.s16       d30, d23, d22    // t62
+        vqadd.s16       d31, d23, d22    // t63
+
+        vmull_vmlal     q2,  d29, d26, d2[0], d2[1] // -> t34a
+        vmull_vmlsl     q3,  d29, d26, d2[1], d2[0] // -> t61a
+        vneg.s32        q2,  q2                     // t34a
+        vmull_vmlsl     q4,  d30, d25, d2[1], d2[0] // -> t33a
+        vqrshrn.s32     d26, q2,  #12               // t34a
+        vmull_vmlal     q2,  d30, d25, d2[0], d2[1] // -> t62a
+        vqrshrn.s32     d29, q3,  #12               // t61a
+        vqrshrn.s32     d25, q4,  #12               // t33a
+        vqrshrn.s32     d30, q2,  #12               // t62a
+
+        vqadd.s16       d16, d24, d27    // t32a
+        vqsub.s16       d19, d24, d27    // t35a
+        vqadd.s16       d17, d25, d26    // t33
+        vqsub.s16       d18, d25, d26    // t34
+        vqsub.s16       d20, d31, d28    // t60a
+        vqadd.s16       d23, d31, d28    // t63a
+        vqsub.s16       d21, d30, d29    // t61
+        vqadd.s16       d22, d30, d29    // t62
+
+        vmull_vmlal     q2,  d21, d18, d2[2], d2[3] // -> t61a
+        vmull_vmlsl     q3,  d21, d18, d2[3], d2[2] // -> t34a
+        vmull_vmlal     q4,  d20, d19, d2[2], d2[3] // -> t60
+        vqrshrn.s32     d21, q2,  #12               // t61a
+        vqrshrn.s32     d18, q3,  #12               // t34a
+        vmull_vmlsl     q2,  d20, d19, d2[3], d2[2] // -> t35
+        vqrshrn.s32     d20, q4,  #12               // t60
+        vqrshrn.s32     d19, q2,  #12               // t35
+
+        vst1.16         {d16, d17, d18, d19}, [r6, :128]!
+        vst1.16         {d20, d21, d22, d23}, [r6, :128]!
+
+        bx              lr
+endfunc
+
+function inv_dct64_step2_neon
+        movrel_local    r12, idct_coeffs
+        vld1.16         {d0}, [r12, :64]
+1:
+        // t32a/33/34a/35/60/61a/62/63a
+        // t56a/57/58a/59/36/37a/38/39a
+        // t40a/41/42a/43/52/53a/54/55a
+        // t48a/49/50a/51/44/45a/46/47a
+        vldr            d16, [r6, #2*4*0]  // t32a
+        vldr            d17, [r9, #2*4*8]  // t39a
+        vldr            d18, [r9, #2*4*0]  // t63a
+        vldr            d19, [r6, #2*4*8]  // t56a
+        vldr            d20, [r6, #2*4*16] // t40a
+        vldr            d21, [r9, #2*4*24] // t47a
+        vldr            d22, [r9, #2*4*16] // t55a
+        vldr            d23, [r6, #2*4*24] // t48a
+
+        vqadd.s16       d24, d16, d17      // t32
+        vqsub.s16       d25, d16, d17      // t39
+        vqadd.s16       d26, d18, d19      // t63
+        vqsub.s16       d27, d18, d19      // t56
+        vqsub.s16       d28, d21, d20      // t40
+        vqadd.s16       d29, d21, d20      // t47
+        vqadd.s16       d30, d23, d22      // t48
+        vqsub.s16       d31, d23, d22      // t55
+
+        vmull_vmlal     q2,  d27, d25, d0[3], d0[2] // -> t56a
+        vmull_vmlsl     q3,  d27, d25, d0[2], d0[3] // -> t39a
+        vmull_vmlal     q4,  d31, d28, d0[3], d0[2] // -> t40a
+        vqrshrn.s32     d25, q2,  #12               // t56a
+        vqrshrn.s32     d27, q3,  #12               // t39a
+        vneg.s32        q4,  q4                     // t40a
+        vmull_vmlsl     q2,  d31, d28, d0[2], d0[3] // -> t55a
+        vqrshrn.s32     d31, q4,  #12               // t40a
+        vqrshrn.s32     d28, q2,  #12               // t55a
+
+        vqadd.s16       d16, d24, d29      // t32a
+        vqsub.s16       d19, d24, d29      // t47a
+        vqadd.s16       d17, d27, d31      // t39
+        vqsub.s16       d18, d27, d31      // t40
+        vqsub.s16       d20, d26, d30      // t48a
+        vqadd.s16       d23, d26, d30      // t63a
+        vqsub.s16       d21, d25, d28      // t55
+        vqadd.s16       d22, d25, d28      // t56
+
+        vmull_vmlsl     q2,  d21, d18, d0[0], d0[0] // -> t40a
+        vmull_vmlal     q3,  d21, d18, d0[0], d0[0] // -> t55a
+        vmull_vmlsl     q4,  d20, d19, d0[0], d0[0] // -> t47
+        vqrshrn.s32     d18, q2,  #12               // t40a
+        vqrshrn.s32     d21, q3,  #12               // t55a
+        vmull_vmlal     q2,  d20, d19, d0[0], d0[0] // -> t48
+        vqrshrn.s32     d19, q4,  #12               // t47
+        vqrshrn.s32     d20, q2,  #12               // t48
+
+        vstr            d16, [r6, #2*4*0]  // t32a
+        vstr            d17, [r9, #2*4*0]  // t39
+        vstr            d18, [r6, #2*4*8]  // t40a
+        vstr            d19, [r9, #2*4*8]  // t47
+        vstr            d20, [r6, #2*4*16] // t48
+        vstr            d21, [r9, #2*4*16] // t55a
+        vstr            d22, [r6, #2*4*24] // t56
+        vstr            d23, [r9, #2*4*24] // t63a
+
+        add             r6,  r6,  #2*4
+        sub             r9,  r9,  #2*4
+        cmp             r6,  r9
+        blt             1b
+        bx              lr
+endfunc
+
+.macro load8 src, strd, zero, clear
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23
+.if \clear
+        vld1.16         {\i}, [\src, :64]
+        vst1.16         {\zero}, [\src, :64], \strd
+.else
+        vld1.16         {\i}, [\src, :64], \strd
+.endif
+.endr
+.endm
+
+.macro store16 dst
+        vst1.16         {q8,  q9},  [\dst, :128]!
+        vst1.16         {q10, q11}, [\dst, :128]!
+        vst1.16         {q12, q13}, [\dst, :128]!
+        vst1.16         {q14, q15}, [\dst, :128]!
+.endm
+
+.macro clear_upper8
+.irp i, q12, q13, q14, q15
+        vmov.i16        \i,  #0
+.endr
+.endm
+
+.macro vmov_if reg, val, cond
+.if \cond
+        vmov.i16        \reg, \val
+.endif
+.endm
+
+.macro movdup_if reg, gpr, val, cond
+.if \cond
+        movw            \gpr, \val
+        vdup.16         \reg, \gpr
+.endif
+.endm
+
+.macro vst1_if regs, dst, dstalign, cond
+.if \cond
+        vst1.16         \regs, \dst, \dstalign
+.endif
+.endm
+
+.macro scale_if cond, c, r0, r1, r2, r3, r4, r5, r6, r7
+.if \cond
+        scale_input     \c, \r0, \r1, \r2, \r3, \r4, \r5, \r6, \r7
+.endif
+.endm
+
+.macro def_dct64_func suffix, clear=0, scale=0
+function inv_txfm_dct\suffix\()_4h_x64_neon, export=1
+        mov             r6,  sp
+
+        push            {r10-r11,lr}
+
+        lsl             r8,  r8,  #2
+
+        movdup_if       d0,  r12, #2896*8, \scale
+        vmov_if         d7,  #0,  \clear
+        load8           r7,  r8,  d7,  \clear
+        clear_upper8
+        sub             r7,  r7,  r8, lsl #3
+        add             r7,  r7,  r8, lsr #1
+        scale_if        \scale, d0[0], q8, q9, q10, q11
+
+        bl              inv_dct_4h_x16_neon
+
+        store16         r6
+
+        movdup_if       d0,  r12, #2896*8, \scale
+        vmov_if         d7,  #0,  \clear
+        load8           r7,  r8,  d7,  \clear
+        clear_upper8
+        sub             r7,  r7,  r8, lsl #3
+        lsr             r8,  r8,  #1
+        sub             r7,  r7,  r8, lsr #1
+        scale_if        \scale, d0[0], q8, q9, q10, q11
+
+        bl              inv_dct32_odd_4h_x16_neon
+
+        add             r10, r6,  #8*15
+        sub             r6,  r6,  #8*16
+
+        mov             r9,  #-8
+
+.macro store_addsub r0, r1, r2, r3
+        vld1.16         {d2},  [r6, :64]!
+        vld1.16         {d3},  [r6, :64]!
+        vqadd.s16       d6,  d2,  \r0
+        vqsub.s16       \r0, d2,  \r0
+        vld1.16         {d4},  [r6, :64]!
+        vqadd.s16       d7,  d3,  \r1
+        vqsub.s16       \r1, d3,  \r1
+        vld1.16         {d5},  [r6, :64]!
+        vqadd.s16       d2,  d4,  \r2
+        sub             r6,  r6,  #8*4
+        vqsub.s16       \r2, d4,  \r2
+        vst1.16         {d6},  [r6,  :64]!
+        vst1.16         {\r0}, [r10, :64], r9
+        vqadd.s16       d3,  d5,  \r3
+        vqsub.s16       \r3, d5,  \r3
+        vst1.16         {d7},  [r6,  :64]!
+        vst1.16         {\r1}, [r10, :64], r9
+        vst1.16         {d2},  [r6,  :64]!
+        vst1.16         {\r2}, [r10, :64], r9
+        vst1.16         {d3},  [r6,  :64]!
+        vst1.16         {\r3}, [r10, :64], r9
+.endm
+        store_addsub    d31, d30, d29, d28
+        store_addsub    d27, d26, d25, d24
+        store_addsub    d23, d22, d21, d20
+        store_addsub    d19, d18, d17, d16
+.purgem store_addsub
+
+        add             r6,  r6,  #2*4*16
+
+        movrel_local    r12, idct64_coeffs
+        movdup_if       d0,  lr,  #2896*8, \scale
+        vmov_if         d7,  #0,  \clear
+        add             r9,  r7,  r8, lsl #4 // offset 16
+        add             r10, r7,  r8, lsl #3 // offset 8
+        sub             r9,  r9,  r8         // offset 15
+        sub             r11, r10, r8         // offset 7
+        vld1.16         {d16}, [r7,  :64]    // in1  (offset 0)
+        vld1.16         {d17}, [r9,  :64]    // in31 (offset 15)
+        vld1.16         {d18}, [r10, :64]    // in17 (offset 8)
+        vld1.16         {d19}, [r11, :64]    // in15 (offset 7)
+        vst1_if         {d7},  [r7,  :64], \clear
+        vst1_if         {d7},  [r9,  :64], \clear
+        vst1_if         {d7},  [r10, :64], \clear
+        vst1_if         {d7},  [r11, :64], \clear
+        scale_if        \scale, d0[0], q8, q9
+        bl              inv_dct64_step1_neon
+        movdup_if       d0,  lr,  #2896*8, \scale
+        vmov_if         d7,  #0,  \clear
+        add             r7,  r7,  r8, lsl #2 // offset 4
+        sub             r9,  r9,  r8, lsl #2 // offset 11
+        sub             r10, r7,  r8         // offset 3
+        add             r11, r9,  r8         // offset 12
+        vld1.16         {d16}, [r10, :64]    // in7  (offset 3)
+        vld1.16         {d17}, [r11, :64]    // in25 (offset 12)
+        vld1.16         {d18}, [r9,  :64]    // in23 (offset 11)
+        vld1.16         {d19}, [r7,  :64]    // in9  (offset 4)
+        vst1_if         {d7},  [r7,  :64], \clear
+        vst1_if         {d7},  [r9,  :64], \clear
+        vst1_if         {d7},  [r10, :64], \clear
+        vst1_if         {d7},  [r11, :64], \clear
+        scale_if        \scale, d0[0], q8, q9
+        bl              inv_dct64_step1_neon
+        movdup_if       d0,  lr,  #2896*8, \scale
+        vmov_if         d7,  #0,  \clear
+        sub             r10, r10, r8, lsl #1 // offset 1
+        sub             r9,  r9,  r8, lsl #1 // offset 9
+        add             r10, r10, r8         // offset 2
+        add             r9,  r9,  r8         // offset 10
+        add             r7,  r7,  r8         // offset 5
+        add             r11, r11, r8         // offset 13
+        vld1.16         d16, [r10, :64]      // in5  (offset 2)
+        vld1.16         d17, [r11, :64]      // in27 (offset 13)
+        vld1.16         d18, [r9,  :64]      // in21 (offset 10)
+        vld1.16         d19, [r7,  :64]      // in11 (offset 5)
+        vst1_if         d7,  [r10, :64], \clear
+        vst1_if         d7,  [r11, :64], \clear
+        vst1_if         d7,  [r9,  :64], \clear
+        vst1_if         d7,  [r7,  :64], \clear
+        scale_if        \scale, d0[0], q8, q9
+        bl              inv_dct64_step1_neon
+        movdup_if       d0,  lr,  #2896*8, \scale
+        vmov_if         d7,  #0,  \clear
+        sub             r10, r10, r8         // offset 1
+        sub             r9,  r9,  r8         // offset 9
+        add             r11, r11, r8         // offset 14
+        add             r7,  r7,  r8         // offset 6
+        vld1.16         d16, [r10, :64]      // in3  (offset 1)
+        vld1.16         d17, [r11, :64]      // in29 (offset 14)
+        vld1.16         d18, [r9,  :64]      // in19 (offset 9)
+        vld1.16         d19, [r7,  :64]      // in13 (offset 6)
+        vst1_if         d7,  [r10, :64], \clear
+        vst1_if         d7,  [r11, :64], \clear
+        vst1_if         d7,  [r9,  :64], \clear
+        vst1_if         d7,  [r7,  :64], \clear
+        scale_if        \scale, d0[0], q8, q9
+        bl              inv_dct64_step1_neon
+
+        sub             r6,  r6,  #2*4*32
+        add             r9,  r6,  #2*4*7
+
+        bl              inv_dct64_step2_neon
+
+        pop             {r10-r11,pc}
+endfunc
+.endm
+
+def_dct64_func
+def_dct64_func _clear, clear=1
+def_dct64_func _clear_scale, clear=1, scale=1
+
+function inv_txfm_horz_dct_64x4_neon
+        vdup.16         q3,  r9
+
+        mov             r7,  sp
+        add             r8,  sp,  #2*4*(64 - 4)
+        add             r9,  r6,  #2*56
+
+        push            {r10-r11,lr}
+
+        mov             r10, #2*64
+        mov             r11, #-2*4*4
+
+1:
+        vld1.16         {d16, d17, d18, d19}, [r7, :128]!
+        vld1.16         {d28, d29, d30, d31}, [r8, :128], r11
+        vld1.16         {d20, d21, d22, d23}, [r7, :128]!
+        vld1.16         {d24, d25, d26, d27}, [r8, :128], r11
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        transpose_4x4h  q15, q14, d31, d30, d29, d28
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        transpose_4x4h  q13, q12, d27, d26, d25, d24
+
+.macro store_addsub src0, src1, src2, src3
+        vqsub.s16       d3,  \src0,  \src1
+        vqsub.s16       d2,  \src2,  \src3
+        vqadd.s16       d0,  \src0,  \src1
+        vqadd.s16       d1,  \src2,  \src3
+        vrshl.s16       q1,  q1,  q3
+        vrshl.s16       q0,  q0,  q3
+        vrev64.16       q1,  q1
+        vst1.16         {q0},  [r6, :128], r10
+        vst1.16         {q1},  [r9, :128], r10
+.endm
+        store_addsub    d16, d31, d20, d27
+        store_addsub    d17, d30, d21, d26
+        store_addsub    d18, d29, d22, d25
+        store_addsub    d19, d28, d23, d24
+.purgem store_addsub
+        sub             r6,  r6,  r10, lsl #2
+        sub             r9,  r9,  r10, lsl #2
+        add             r6,  r6,  #16
+        sub             r9,  r9,  #16
+
+        cmp             r7,  r8
+        blt             1b
+        pop             {r10-r11,pc}
+endfunc
+
+function inv_txfm_add_vert_dct_4x64_neon
+        lsl             r8,  r8,  #1
+
+        mov             r7,  sp
+        add             r8,  sp,  #2*4*(64 - 4)
+        add             r9,  r6,  r1, lsl #6
+        sub             r9,  r9,  r1
+
+        push            {r10-r11,lr}
+
+        neg             r10, r1
+        mov             r11, #-2*4*4
+
+1:
+        vld1.16         {d16, d17, d18, d19}, [r7, :128]!
+        vld1.16         {d28, d29, d30, d31}, [r8, :128], r11
+        vld1.16         {d20, d21, d22, d23}, [r7, :128]!
+        vld1.16         {d24, d25, d26, d27}, [r8, :128], r11
+
+.macro add_dest_addsub src0, src1, src2, src3
+        vld1.32         {d0[0]}, [r6, :32], r1
+        vld1.32         {d1[0]}, [r9, :32], r10
+        vqadd.s16       d4,  \src0,  \src1
+        vld1.32         {d0[1]}, [r6, :32]
+        vqadd.s16       d5,  \src2,  \src3
+        vld1.32         {d1[1]}, [r9, :32]
+        vqsub.s16       d6,  \src0,  \src1
+        vqsub.s16       d7,  \src2,  \src3
+        sub             r6,  r6,  r1
+        sub             r9,  r9,  r10
+        vrshr.s16       q2,  q2,  #4
+        vrshr.s16       q3,  q3,  #4
+        vaddw.u8        q2,  q2,  d0
+        vaddw.u8        q3,  q3,  d1
+        vqmovun.s16     d0,  q2
+        vqmovun.s16     d1,  q3
+        vst1.32         {d0[0]}, [r6, :32], r1
+        vst1.32         {d1[0]}, [r9, :32], r10
+        vst1.32         {d0[1]}, [r6, :32], r1
+        vst1.32         {d1[1]}, [r9, :32], r10
+.endm
+        add_dest_addsub d16, d31, d17, d30
+        add_dest_addsub d18, d29, d19, d28
+        add_dest_addsub d20, d27, d21, d26
+        add_dest_addsub d22, d25, d23, d24
+.purgem add_dest_addsub
+        cmp             r7,  r8
+        blt             1b
+
+        pop             {r10-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_64x64_8bpc_neon, export=1
+        idct_dc         64,  64,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4}
+
+        sub_sp_align    64*32*2+64*4*2
+        add             r5,  sp,  #64*4*2
+
+        movrel_local    r10, eob_32x32
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  r5,  #(\i*64*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_dct_clear_4h_x64_neon
+        add             r6,  r5,  #(\i*64*2)
+        mov             r9,  #-2 // shift
+        bl              inv_txfm_horz_dct_64x4_neon
+.if \i < 28
+        ldrh            r11, [r10], #2
+.endif
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 8
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
+        add             r7,  r5,  #(\i*2)
+        mov             r8,  #64*2
+        bl              inv_txfm_dct_4h_x64_neon
+        add             r6,  r0,  #(\i)
+        bl              inv_txfm_add_vert_dct_4x64_neon
+.endr
+
+        add_sp_align    64*32*2+64*4*2
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_64x32_8bpc_neon, export=1
+        idct_dc         64,  32,  1
+
+        push            {r4-r11,lr}
+        vpush           {q4}
+
+        sub_sp_align    64*32*2+64*4*2
+        add             r5,  sp,  #64*4*2
+
+        movrel_local    r10, eob_32x32
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  r5,  #(\i*64*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_dct_clear_scale_4h_x64_neon
+        add             r6,  r5,  #(\i*64*2)
+        mov             r9,  #-1 // shift
+        bl              inv_txfm_horz_dct_64x4_neon
+.if \i < 28
+        ldrh            r11, [r10], #2
+.endif
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 8
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
+        add             r6,  r0,  #(\i)
+        add             r7,  r5,  #(\i*2)
+        mov             r8,  #64*2
+        bl              inv_txfm_add_vert_dct_4x32_neon
+.endr
+
+        add_sp_align    64*32*2+64*4*2
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_32x64_8bpc_neon, export=1
+        idct_dc         32,  64,  1
+
+        push            {r4-r11,lr}
+        vpush           {q4}
+
+        sub_sp_align    32*32*2+64*4*2
+        add             r5,  sp,  #64*4*2
+
+        movrel_local    r10, eob_32x32
+        ldrh            r11, [r10], #2
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  r5,  #(\i*32*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 28
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_horz_scale_dct_32x4_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r7,  r5,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_dct_4h_x64_neon
+        add             r6,  r0,  #(\i)
+        bl              inv_txfm_add_vert_dct_4x64_neon
+.endr
+
+        add_sp_align    32*32*2+64*4*2
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_64x16_8bpc_neon, export=1
+        idct_dc         64,  16,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4}
+
+        sub_sp_align    64*16*2+64*4*2
+        add             r4,  sp,  #64*4*2
+
+        movrel_local    r10, eob_16x32
+
+.irp i, 0, 4, 8, 12
+        add             r6,  r4,  #(\i*64*2)
+.if \i > 0
+        mov             r8,  #(16 - \i)
+        cmp             r3,  r11
+        blt             1f
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #16*2
+        bl              inv_txfm_dct_clear_4h_x64_neon
+        add             r6,  r4,  #(\i*64*2)
+        mov             r9,  #-2 // shift
+        bl              inv_txfm_horz_dct_64x4_neon
+.if \i < 12
+        ldrh            r11, [r10], #2
+.endif
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 8
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+        movrel_local    r5,  inv_dct_4h_x16_neon
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
+        add             r6,  r0,  #(\i)
+        add             r7,  r4,  #(\i*2)
+        mov             r8,  #64*2
+        bl              inv_txfm_add_vert_4x16_neon
+.endr
+
+        add_sp_align    64*16*2+64*4*2
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_16x64_8bpc_neon, export=1
+        idct_dc         16,  64,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4}
+
+        sub_sp_align    16*32*2+64*4*2
+        add             r5,  sp,  #64*4*2
+
+        movrel_local    r10, eob_16x32
+        ldrh            r11, [r10], #2
+
+        movrel_local    r4,  inv_dct_4h_x16_neon
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  r5,  #(\i*16*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 28
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_horz_16x4_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #4
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12
+        add             r7,  r5,  #(\i*2)
+        mov             r8,  #16*2
+        bl              inv_txfm_dct_4h_x64_neon
+        add             r6,  r0,  #(\i)
+        bl              inv_txfm_add_vert_dct_4x64_neon
+.endr
+
+        add_sp_align    16*32*2+64*4*2
+        vpop            {q4}
+        pop             {r4-r11,pc}
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/itx16.S b/media/libdav1d/src/src/arm/32/itx16.S
new file mode 100644
index 0000000000..7691272517
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/itx16.S
@@ -0,0 +1,3632 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// The exported functions in this file have got the following signature:
+// void itxfm_add(pixel *dst, ptrdiff_t dst_stride, coef *coeff, int eob);
+
+// Most of the functions use the following register layout:
+// r0-r3   external parameters
+// r4      function pointer to first transform
+// r5      function pointer to second transform
+// r6      output parameter for helper function
+// r7      input parameter for helper function
+// r8      input stride for helper function
+// r9      scratch variable for helper functions
+// r10-r11 pointer to list of eob thresholds, eob threshold value,
+//         scratch variables within helper functions (backed up)
+
+// The SIMD registers most often use the following layout:
+// d0-d3   multiplication coefficients
+// d4-d7   scratch registers
+// d8-d15  unused in some transforms, used for scratch registers in others
+// d16-v31 inputs/outputs of transforms
+
+// Potential further optimizations, that are left unimplemented for now:
+// - Trying to keep multiplication coefficients in registers across multiple
+//   transform functions. (The register layout is designed to potentially
+//   allow this.)
+// - Use a simplified version of the transforms themselves for cases where
+//   we know a significant number of inputs are zero. E.g. if the eob value
+//   indicates only a quarter of input values are set, for idct16 and up,
+//   a significant amount of calculation can be skipped, at the cost of more
+//   code duplication and special casing.
+
+// A macro for cases where a thumb mov can express the constant in one
+// instruction, while arm mode requires two separate movw+movt pairs.
+.macro mov_const reg, val
+#if CONFIG_THUMB
+        mov.w           \reg, #\val
+#else
+        movw            \reg, #((\val) & 0xffff)
+        movt            \reg, #(((\val) >> 16) & 0xffff)
+#endif
+.endm
+
+const idct_coeffs, align=4
+        // idct4
+        .int            2896, 2896*8*(1<<16), 1567, 3784
+        // idct8
+        .int            799, 4017, 3406, 2276
+        // idct16
+        .int            401, 4076, 3166, 2598
+        .int            1931, 3612, 3920, 1189
+        // idct32
+        .int            201, 4091, 3035, 2751
+        .int            1751, 3703, 3857, 1380
+        .int            995, 3973, 3513, 2106
+        .int            2440, 3290, 4052, 601
+endconst
+
+const idct64_coeffs, align=4
+        .int            101*8*(1<<16), 4095*8*(1<<16), 2967*8*(1<<16), -2824*8*(1<<16)
+        .int            1660*8*(1<<16), 3745*8*(1<<16), 3822*8*(1<<16), -1474*8*(1<<16)
+        .int            4076, 401, 4017, 799
+
+        .int            4036*8*(1<<16), -700*8*(1<<16), 2359*8*(1<<16), 3349*8*(1<<16)
+        .int            3461*8*(1<<16), -2191*8*(1<<16), 897*8*(1<<16), 3996*8*(1<<16)
+        .int            -3166, -2598, -799, -4017
+
+        .int            501*8*(1<<16), 4065*8*(1<<16), 3229*8*(1<<16), -2520*8*(1<<16)
+        .int            2019*8*(1<<16), 3564*8*(1<<16), 3948*8*(1<<16), -1092*8*(1<<16)
+        .int            3612, 1931, 2276, 3406
+
+        .int            4085*8*(1<<16), -301*8*(1<<16), 2675*8*(1<<16), 3102*8*(1<<16)
+        .int            3659*8*(1<<16), -1842*8*(1<<16), 1285*8*(1<<16), 3889*8*(1<<16)
+        .int            -3920, -1189, -3406, -2276
+endconst
+
+const iadst4_coeffs, align=4
+        .int            1321, 3803, 2482, 3344
+endconst
+
+const iadst8_coeffs, align=4
+        .int            4076, 401, 3612, 1931
+        .int            2598, 3166, 1189, 3920
+        // idct_coeffs
+        .int            2896, 0, 1567, 3784
+endconst
+
+const iadst16_coeffs, align=4
+        .int            4091, 201, 3973, 995
+        .int            3703, 1751, 3290, 2440
+        .int            2751, 3035, 2106, 3513
+        .int            1380, 3857, 601, 4052
+endconst
+
+.macro vmul_vmla d0, s0, s1, c0, c1
+        vmul.i32        \d0, \s0, \c0
+        vmla.i32        \d0, \s1, \c1
+.endm
+
+.macro vmul_vmls d0, s0, s1, c0, c1
+        vmul.i32        \d0, \s0, \c0
+        vmls.i32        \d0, \s1, \c1
+.endm
+
+.macro scale_input c, r0, r1, r2 r3, r4, r5, r6, r7
+        vqrdmulh.s32    \r0, \r0, \c
+        vqrdmulh.s32    \r1, \r1, \c
+.ifnb \r2
+        vqrdmulh.s32    \r2, \r2, \c
+        vqrdmulh.s32    \r3, \r3, \c
+.endif
+.ifnb \r4
+        vqrdmulh.s32    \r4, \r4, \c
+        vqrdmulh.s32    \r5, \r5, \c
+        vqrdmulh.s32    \r6, \r6, \c
+        vqrdmulh.s32    \r7, \r7, \c
+.endif
+.endm
+
+.macro load_add_store load, shift, addsrc, adddst, max, min, store, dst, src, shiftbits=4
+.ifnb \load
+        vld1.16         {\load},  [\src, :128], r1
+.endif
+.ifnb \shift
+        vrshr.s16       \shift,  \shift,  #\shiftbits
+.endif
+.ifnb \addsrc
+        vqadd.s16       \adddst, \adddst, \addsrc
+.endif
+.ifnb \max
+        vmax.s16        \max, \max, q6
+.endif
+.ifnb \min
+        vmin.s16        \min, \min, q7
+.endif
+.ifnb \store
+        vst1.16         {\store},  [\dst, :128], r1
+.endif
+.endm
+.macro load_add_store_8x8 dst, src, shiftbits=4
+        mov             \src, \dst
+        vmov.i16        q6,  #0
+        vmvn.i16        q7,  #0xfc00 // 0x3ff
+        load_add_store  q0,  q8,    ,    ,    ,    ,    ,  \dst, \src, \shiftbits
+        load_add_store  q1,  q9,    ,    ,    ,    ,    ,  \dst, \src, \shiftbits
+        load_add_store  q2,  q10, q0,  q8,    ,    ,    ,  \dst, \src, \shiftbits
+        load_add_store  q3,  q11, q1,  q9,  q8,    ,    ,  \dst, \src, \shiftbits
+        load_add_store  q4,  q12, q2,  q10, q9,  q8,    ,  \dst, \src, \shiftbits
+        load_add_store  q5,  q13, q3,  q11, q10, q9,  q8,  \dst, \src, \shiftbits
+        load_add_store  q0,  q14, q4,  q12, q11, q10, q9,  \dst, \src, \shiftbits
+        load_add_store  q1,  q15, q5,  q13, q12, q11, q10, \dst, \src, \shiftbits
+        load_add_store    ,     , q0,  q14, q13, q12, q11, \dst, \src, \shiftbits
+        load_add_store    ,     , q1,  q15, q14, q13, q12, \dst, \src, \shiftbits
+        load_add_store    ,     ,   ,     , q15, q14, q13, \dst, \src, \shiftbits
+        load_add_store    ,     ,   ,     ,    , q15, q14, \dst, \src, \shiftbits
+        load_add_store    ,     ,   ,     ,    ,    , q15, \dst, \src, \shiftbits
+.endm
+.macro load_add_store_8x4 dst, src, shiftbits=4
+        mov             \src, \dst
+        vmov.i16        q6,  #0
+        vmvn.i16        q7,  #0xfc00 // 0x3ff
+        load_add_store  q0,  q8,    ,    ,    ,    ,    ,  \dst, \src, \shiftbits
+        load_add_store  q1,  q9,    ,    ,    ,    ,    ,  \dst, \src, \shiftbits
+        load_add_store  q2,  q10, q0,  q8,    ,    ,    ,  \dst, \src, \shiftbits
+        load_add_store  q3,  q11, q1,  q9,  q8,    ,    ,  \dst, \src, \shiftbits
+        load_add_store    ,     , q2,  q10, q9,  q8,    ,  \dst, \src, \shiftbits
+        load_add_store    ,     , q3,  q11, q10, q9,  q8,  \dst, \src, \shiftbits
+        load_add_store    ,     ,   ,     , q11, q10, q9,  \dst, \src, \shiftbits
+        load_add_store    ,     ,   ,     ,    , q11, q10, \dst, \src, \shiftbits
+        load_add_store    ,     ,   ,     ,    ,    , q11, \dst, \src, \shiftbits
+.endm
+.macro load_add_store4 load1, load2, shift, addsrc, adddst, max, min, store1, store2, dst, src, shiftbits=4
+.ifnb \load1
+        vld1.16         {\load1},  [\src, :64], r1
+.endif
+.ifnb \shift
+        vrshr.s16       \shift,  \shift,  #\shiftbits
+.endif
+.ifnb \load2
+        vld1.16         {\load2},  [\src, :64], r1
+.endif
+.ifnb \addsrc
+        vqadd.s16       \adddst, \adddst, \addsrc
+.endif
+.ifnb \max
+        vmax.s16        \max, \max, q6
+.endif
+.ifnb \store1
+        vst1.16         {\store1},  [\dst, :64], r1
+.endif
+.ifnb \min
+        vmin.s16        \min, \min, q7
+.endif
+.ifnb \store2
+        vst1.16         {\store2},  [\dst, :64], r1
+.endif
+.endm
+.macro load_add_store_4x16 dst, src
+        mov             \src, \dst
+        vmov.i16        q6,  #0
+        vmvn.i16        q7,  #0xfc00 // 0x3ff
+        mov             \src, \dst
+        load_add_store4 d0,  d1,  q8,    ,    ,    ,    ,     ,    , \dst, \src
+        load_add_store4 d2,  d3,  q9,    ,    ,    ,    ,     ,    , \dst, \src
+        load_add_store4 d4,  d5,  q10, q0,  q8,    ,    ,     ,    , \dst, \src
+        load_add_store4 d6,  d7,  q11, q1,  q9,  q8,    ,     ,    , \dst, \src
+        load_add_store4 d8,  d9,  q12, q2,  q10, q9,  q8,     ,    , \dst, \src
+        load_add_store4 d10, d11, q13, q3,  q11, q10, q9,  d16, d17, \dst, \src
+        load_add_store4 d0,  d1,  q14, q4,  q12, q11, q10, d18, d19, \dst, \src
+        load_add_store4 d2,  d3,  q15, q5,  q13, q12, q11, d20, d21, \dst, \src
+        load_add_store4   ,    ,    ,  q0,  q14, q13, q12, d22, d23, \dst, \src
+        load_add_store4   ,    ,    ,  q1,  q15, q14, q13, d24, d25, \dst, \src
+        load_add_store4   ,    ,    ,    ,   ,   q15, q14, d26, d27, \dst, \src
+        load_add_store4   ,    ,    ,    ,   ,     ,  q15, d28, d29, \dst, \src
+        load_add_store4   ,    ,    ,    ,   ,     ,     , d30, d31, \dst, \src
+.endm
+.macro load_add_store_4x8 dst, src, shiftbits=4
+        mov             \src, \dst
+        vmov.i16        q6,  #0
+        vmvn.i16        q7,  #0xfc00 // 0x3ff
+        mov             \src, \dst
+        load_add_store4 d0,  d1,  q8,    ,    ,    ,    ,     ,    , \dst, \src, \shiftbits
+        load_add_store4 d2,  d3,  q9,    ,    ,    ,    ,     ,    , \dst, \src, \shiftbits
+        load_add_store4 d4,  d5,  q10, q0,  q8,    ,    ,     ,    , \dst, \src, \shiftbits
+        load_add_store4 d6,  d7,  q11, q1,  q9,  q8,    ,     ,    , \dst, \src, \shiftbits
+        load_add_store4   ,    ,     , q2,  q10, q9,  q8,     ,    , \dst, \src, \shiftbits
+        load_add_store4   ,    ,     , q3,  q11, q10, q9,  d16, d17, \dst, \src, \shiftbits
+        load_add_store4   ,    ,     ,   ,     , q11, q10, d18, d19, \dst, \src, \shiftbits
+        load_add_store4   ,    ,     ,   ,     ,    , q11, d20, d21, \dst, \src, \shiftbits
+        load_add_store4   ,    ,     ,   ,     ,    ,    , d22, d23, \dst, \src, \shiftbits
+.endm
+.macro load_add_store_4x4 dst, src, shiftbits=4
+        mov             \src, \dst
+        vmov.i16        q6,  #0
+        vmvn.i16        q7,  #0xfc00 // 0x3ff
+        mov             \src, \dst
+        load_add_store4 d0,  d1,  q8,   ,   ,   ,   ,    ,    , \dst, \src, \shiftbits
+        load_add_store4 d2,  d3,  q9, q0, q8,   ,   ,    ,    , \dst, \src, \shiftbits
+        load_add_store4   ,    ,    , q1, q9, q8,   ,    ,    , \dst, \src, \shiftbits
+        load_add_store4   ,    ,    ,   ,   , q9, q8,    ,    , \dst, \src, \shiftbits
+        load_add_store4   ,    ,    ,   ,   ,   , q9, d16, d17, \dst, \src, \shiftbits
+        load_add_store4   ,    ,    ,   ,   ,   ,   , d18, d19, \dst, \src, \shiftbits
+.endm
+
+.macro idct_dc w, h, shift
+        cmp             r3,  #0
+        bne             1f
+        vmov.i16        q14, #0
+        mov_const       r12, 2896*8*(1<<16)
+        vld1.32         {d24[], d25[]}, [r2, :32]
+        vdup.32         d0,  r12
+        vqrdmulh.s32    q13, q12, d0[0]
+        vst1.32         {d28[0]}, [r2, :32]
+.if (\w == 2*\h) || (2*\w == \h)
+        vqrdmulh.s32    q13, q13, d0[0]
+.endif
+.if \shift > 0
+        vqrshrn.s32     d24, q13, #\shift
+        vqrshrn.s32     d25, q13, #\shift
+.else
+        vqmovn.s32      d24, q13
+        vqmovn.s32      d25, q13
+.endif
+        vqrdmulh.s16    q12, q12, d0[1]
+        mov             r3,  #\h
+        vrshr.s16       q12, q12, #4
+        b               idct_dc_w\w\()_neon
+1:
+.endm
+
+function idct_dc_w4_neon
+        vmvn.i16        q15, #0xfc00 // 0x3ff
+1:
+        vld1.16         {d0}, [r0, :64], r1
+        vld1.16         {d1}, [r0, :64], r1
+        vld1.16         {d2}, [r0, :64], r1
+        vld1.16         {d3}, [r0, :64], r1
+        subs            r3,  r3,  #4
+        vqadd.s16       q0,  q0,  q12
+        sub             r0,  r0,  r1, lsl #2
+        vqadd.s16       q1,  q1,  q12
+        vmax.s16        q0,  q0,  q14
+        vmax.s16        q1,  q1,  q14
+        vmin.s16        q0,  q0,  q15
+        vst1.16         {d0}, [r0, :64], r1
+        vmin.s16        q1,  q1,  q15
+        vst1.16         {d1}, [r0, :64], r1
+        vst1.16         {d2}, [r0, :64], r1
+        vst1.16         {d3}, [r0, :64], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+function idct_dc_w8_neon
+        vmvn.i16        q15, #0xfc00 // 0x3ff
+1:
+        vld1.16         {q0}, [r0, :128], r1
+        subs            r3,  r3,  #4
+        vld1.16         {q1}, [r0, :128], r1
+        vqadd.s16       q0,  q0,  q12
+        vld1.16         {q2}, [r0, :128], r1
+        vqadd.s16       q1,  q1,  q12
+        vld1.16         {q3}, [r0, :128], r1
+        vqadd.s16       q2,  q2,  q12
+        vqadd.s16       q3,  q3,  q12
+        sub             r0,  r0,  r1, lsl #2
+        vmax.s16        q0,  q0,  q14
+        vmax.s16        q1,  q1,  q14
+        vmax.s16        q2,  q2,  q14
+        vmax.s16        q3,  q3,  q14
+        vmin.s16        q0,  q0,  q15
+        vmin.s16        q1,  q1,  q15
+        vst1.16         {q0}, [r0, :128], r1
+        vmin.s16        q2,  q2,  q15
+        vst1.16         {q1}, [r0, :128], r1
+        vmin.s16        q3,  q3,  q15
+        vst1.16         {q2}, [r0, :128], r1
+        vst1.16         {q3}, [r0, :128], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+function idct_dc_w16_neon
+        vmvn.i16        q15, #0xfc00 // 0x3ff
+1:
+        vld1.16         {q0, q1}, [r0, :128], r1
+        subs            r3,  r3,  #2
+        vld1.16         {q2, q3}, [r0, :128], r1
+        vqadd.s16       q0,  q0,  q12
+        vqadd.s16       q1,  q1,  q12
+        vqadd.s16       q2,  q2,  q12
+        vqadd.s16       q3,  q3,  q12
+        sub             r0,  r0,  r1, lsl #1
+        vmax.s16        q0,  q0,  q14
+        vmax.s16        q1,  q1,  q14
+        vmax.s16        q2,  q2,  q14
+        vmax.s16        q3,  q3,  q14
+        vmin.s16        q0,  q0,  q15
+        vmin.s16        q1,  q1,  q15
+        vmin.s16        q2,  q2,  q15
+        vst1.16         {q0, q1}, [r0, :128], r1
+        vmin.s16        q3,  q3,  q15
+        vst1.16         {q2, q3}, [r0, :128], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+function idct_dc_w32_neon
+        sub             r1,  r1,  #32
+        vmvn.i16        q15, #0xfc00 // 0x3ff
+1:
+        vld1.16         {q0, q1}, [r0, :128]!
+        subs            r3,  r3,  #1
+        vld1.16         {q2, q3}, [r0, :128]
+        vqadd.s16       q0,  q0,  q12
+        vqadd.s16       q1,  q1,  q12
+        vqadd.s16       q2,  q2,  q12
+        vqadd.s16       q3,  q3,  q12
+        sub             r0,  r0,  #32
+        vmax.s16        q0,  q0,  q14
+        vmax.s16        q1,  q1,  q14
+        vmax.s16        q2,  q2,  q14
+        vmax.s16        q3,  q3,  q14
+        vmin.s16        q0,  q0,  q15
+        vmin.s16        q1,  q1,  q15
+        vmin.s16        q2,  q2,  q15
+        vst1.16         {q0, q1}, [r0, :128]!
+        vmin.s16        q3,  q3,  q15
+        vst1.16         {q2, q3}, [r0, :128], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+function idct_dc_w64_neon
+        sub             r1,  r1,  #96
+        vmvn.i16        q15, #0xfc00 // 0x3ff
+1:
+        vld1.16         {q0,  q1},  [r0, :128]!
+        subs            r3,  r3,  #1
+        vld1.16         {q2,  q3},  [r0, :128]!
+        vqadd.s16       q0,  q0,  q12
+        vld1.16         {q8,  q9},  [r0, :128]!
+        vqadd.s16       q1,  q1,  q12
+        vld1.16         {q10, q11}, [r0, :128]
+        vqadd.s16       q2,  q2,  q12
+        vqadd.s16       q3,  q3,  q12
+        vqadd.s16       q8,  q8,  q12
+        vqadd.s16       q9,  q9,  q12
+        vqadd.s16       q10, q10, q12
+        vqadd.s16       q11, q11, q12
+        sub             r0,  r0,  #96
+        vmax.s16        q0,  q0,  q14
+        vmax.s16        q1,  q1,  q14
+        vmax.s16        q2,  q2,  q14
+        vmax.s16        q3,  q3,  q14
+        vmax.s16        q8,  q8,  q14
+        vmax.s16        q9,  q9,  q14
+        vmax.s16        q10, q10, q14
+        vmax.s16        q11, q11, q14
+        vmin.s16        q0,  q0,  q15
+        vmin.s16        q1,  q1,  q15
+        vmin.s16        q2,  q2,  q15
+        vmin.s16        q3,  q3,  q15
+        vmin.s16        q8,  q8,  q15
+        vst1.16         {q0,  q1},  [r0, :128]!
+        vmin.s16        q9,  q9,  q15
+        vst1.16         {q2,  q3},  [r0, :128]!
+        vmin.s16        q10, q10, q15
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vmin.s16        q11, q11, q15
+        vst1.16         {q10, q11}, [r0, :128], r1
+        bgt             1b
+        bx              lr
+endfunc
+
+.macro iwht4
+        vadd.i32        q8,  q8,  q9
+        vsub.i32        q13, q10, q11
+        vsub.i32        q12, q8,  q13
+        vshr.s32        q12, q12, #1
+        vsub.i32        q10, q12, q9
+        vsub.i32        q9,  q12, q11
+        vadd.i32        q11, q13, q10
+        vsub.i32        q8,  q8,  q9
+.endm
+
+.macro idct_4s_x4 r0, r1, r2, r3
+        vmul_vmla       q4,  \r1, \r3, d1[1], d1[0]
+        vmul_vmla       q2,  \r0, \r2, d0[0], d0[0]
+        vmul_vmls       q3,  \r1, \r3, d1[0], d1[1]
+        vmul_vmls       q5,  \r0, \r2, d0[0], d0[0]
+        vrshr.s32       q4,  q4,  #12
+        vrshr.s32       q2,  q2,  #12
+        vrshr.s32       q3,  q3,  #12
+        vrshr.s32       q5,  q5,  #12
+        vqadd.s32       \r0, q2,  q4
+        vqsub.s32       \r3, q2,  q4
+        vqadd.s32       \r1, q5,  q3
+        vqsub.s32       \r2, q5,  q3
+.endm
+
+.macro idct_2s_x4 r0, r1, r2, r3
+        vmul_vmla       d6,  \r1, \r3, d1[1], d1[0]
+        vmul_vmla       d4,  \r0, \r2, d0[0], d0[0]
+        vmul_vmls       d5,  \r1, \r3, d1[0], d1[1]
+        vmul_vmls       d7,  \r0, \r2, d0[0], d0[0]
+        vrshr.s32       d6,  d6,  #12
+        vrshr.s32       d4,  d4,  #12
+        vrshr.s32       d5,  d5,  #12
+        vrshr.s32       d7,  d7,  #12
+        vqadd.s32       \r0, d4,  d6
+        vqsub.s32       \r3, d4,  d6
+        vqadd.s32       \r1, d7,  d5
+        vqsub.s32       \r2, d7,  d5
+.endm
+
+function inv_dct_4s_x4_neon
+        movrel_local    r12, idct_coeffs
+        vld1.32         {d0, d1}, [r12, :128]
+        idct_4s_x4      q8,  q9,  q10, q11
+        bx              lr
+endfunc
+
+.macro iadst_4x4 o0, o1, o2, o3
+        movrel_local    r12, iadst4_coeffs
+        vld1.32         {d0, d1}, [r12, :128]
+
+        vsub.i32        q1,  q8,  q10
+        vmul.i32        q2,  q8,  d0[0]
+        vmla.i32        q2,  q10, d0[1]
+        vmla.i32        q2,  q11, d1[0]
+        vmul.i32        q4,  q9,  d1[1]
+        vadd.i32        q1,  q1,  q11
+        vmul.i32        q3,  q8,  d1[0]
+        vmls.i32        q3,  q10, d0[0]
+        vmls.i32        q3,  q11, d0[1]
+
+        vadd.i32        \o3, q2,  q3
+        vmul.i32        \o2, q1,  d1[1]
+        vadd.i32        \o0, q2,  q4
+        vadd.i32        \o1, q3,  q4
+        vsub.i32        \o3, \o3, q4
+
+        vrshr.s32       \o0, \o0, #12
+        vrshr.s32       \o2, \o2, #12
+        vrshr.s32       \o1, \o1, #12
+        vrshr.s32       \o3, \o3, #12
+.endm
+
+function inv_adst_4s_x4_neon
+        iadst_4x4       q8,  q9,  q10, q11
+        bx              lr
+endfunc
+
+function inv_flipadst_4s_x4_neon
+        iadst_4x4       q11, q10, q9,  q8
+        bx              lr
+endfunc
+
+function inv_identity_4s_x4_neon
+        mov             r12, #0
+        movt            r12, #(5793-4096)*8
+        vdup.32         d0,  r12
+        vqrdmulh.s32    q1,  q8,  d0[0]
+        vqrdmulh.s32    q2,  q9,  d0[0]
+        vqrdmulh.s32    q3,  q10, d0[0]
+        vqrdmulh.s32    q4,  q11, d0[0]
+        vqadd.s32       q8,  q8,  q1
+        vqadd.s32       q9,  q9,  q2
+        vqadd.s32       q10, q10, q3
+        vqadd.s32       q11, q11, q4
+        bx              lr
+endfunc
+
+function inv_txfm_add_wht_wht_4x4_16bpc_neon, export=1
+        push            {r4-r5,lr}
+        vpush           {q4-q5}
+        vmov.i16        q14, #0
+        vmov.i16        q15, #0
+        vld1.32         {q8,  q9},  [r2, :128]
+        vst1.32         {q14, q15}, [r2, :128]!
+        vshr.s32        q8,  q8,  #2
+        vld1.32         {q10, q11}, [r2, :128]
+        vshr.s32        q9,  q9,  #2
+        vshr.s32        q10, q10, #2
+        vshr.s32        q11, q11, #2
+
+        iwht4
+
+        vst1.32         {q14, q15}, [r2, :128]
+        transpose_4x4s  q8,  q9,  q10, q11, d16, d17, d18, d19, d20, d21, d22, d23
+
+        iwht4
+
+        vld1.16         {d0}, [r0, :64], r1
+        vqmovn.s32      d16, q8
+        vld1.16         {d1}, [r0, :64], r1
+        vqmovn.s32      d17, q9
+        vld1.16         {d2}, [r0, :64], r1
+        vqmovn.s32      d18, q10
+        vld1.16         {d3}, [r0, :64], r1
+        vqmovn.s32      d19, q11
+
+        b               L(itx_4x4_end)
+endfunc
+
+function inv_txfm_add_4x4_neon
+        vmov.i16        q14, #0
+        vmov.i16        q15, #0
+        vld1.32         {q8,  q9},  [r2, :128]
+        vst1.16         {q14, q15}, [r2, :128]!
+        vld1.32         {q10, q11}, [r2, :128]
+        vst1.16         {q14, q15}, [r2, :128]
+
+        blx             r4
+
+        vqmovn.s32      d16, q8
+        vqmovn.s32      d17, q9
+        vqmovn.s32      d18, q10
+        vqmovn.s32      d19, q11
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+
+        blx             r5
+
+        vld1.16         {d0}, [r0, :64], r1
+        vld1.16         {d1}, [r0, :64], r1
+        vrshr.s16       q8,  q8,  #4
+        vld1.16         {d2}, [r0, :64], r1
+        vrshr.s16       q9,  q9,  #4
+        vld1.16         {d3}, [r0, :64], r1
+
+L(itx_4x4_end):
+        // read bitdepth_max from the callers stack
+        ldr             r4,  [sp, #44]
+        vdup.i16        q15, r4
+        sub             r0,  r0,  r1, lsl #2
+        vqadd.s16       q8,  q8,  q0
+        vqadd.s16       q9,  q9,  q1
+        vmax.s16        q8,  q8,  q14
+        vmax.s16        q9,  q9,  q14
+        vmin.s16        q8,  q8,  q15
+        vmin.s16        q9,  q9,  q15
+        vst1.16         {d16}, [r0, :64], r1
+        vst1.16         {d17}, [r0, :64], r1
+        vst1.16         {d18}, [r0, :64], r1
+        vst1.16         {d19}, [r0, :64], r1
+
+        vpop            {q4-q5}
+        pop             {r4-r5,pc}
+endfunc
+
+.macro def_fn_4x4 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_4x4_16bpc_neon, export=1
+        push            {r4-r5,lr}
+        vpush           {q4-q5}
+
+.ifc \txfm1\()_\txfm2, dct_dct
+        cmp             r3,  #0
+        bne             1f
+        vmov.i16        q14, #0
+        mov_const       r12, 2896*8*(1<<16)
+        vld1.32         {d16[], d17[]},  [r2, :32]
+        vdup.32         d4,  r12
+        vst1.32         {d28[0]}, [r2, :32]
+        vqrdmulh.s32    q8,  q8,  d4[0]
+        vld1.16         {d0}, [r0, :64], r1
+        vqmovn.s32      d20, q8
+        vqmovn.s32      d21, q8
+        vld1.16         {d1}, [r0, :64], r1
+        vqrdmulh.s16    q10, q10, d4[1]
+        vld1.16         {d2}, [r0, :64], r1
+        vrshr.s16       q8,  q10, #4
+        vld1.16         {d3}, [r0, :64], r1
+        vrshr.s16       q9,  q10, #4
+        b               L(itx_4x4_end)
+1:
+.endif
+        movrel_local    r4,  inv_\txfm1\()_4s_x4_neon
+        movrel          r5,  X(inv_\txfm2\()_4h_x4_neon)
+        b               inv_txfm_add_4x4_neon
+endfunc
+.endm
+
+def_fn_4x4 dct, dct
+def_fn_4x4 identity, identity
+def_fn_4x4 dct, adst
+def_fn_4x4 dct, flipadst
+def_fn_4x4 dct, identity
+def_fn_4x4 adst, dct
+def_fn_4x4 adst, adst
+def_fn_4x4 adst, flipadst
+def_fn_4x4 flipadst, dct
+def_fn_4x4 flipadst, adst
+def_fn_4x4 flipadst, flipadst
+def_fn_4x4 identity, dct
+
+def_fn_4x4 adst, identity
+def_fn_4x4 flipadst, identity
+def_fn_4x4 identity, adst
+def_fn_4x4 identity, flipadst
+
+.macro idct_4s_x8 r0, r1, r2, r3, r4, r5, r6, r7
+        idct_4s_x4      \r0, \r2, \r4, \r6
+
+        vmov.i32        q5,  #0x1ffff // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vmvn.i32        q4,  #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+.irp r, \r0, \r2, \r4, \r6
+        vmin.s32        \r,  \r,  q5
+.endr
+.irp r, \r0, \r2, \r4, \r6
+        vmax.s32        \r,  \r,  q4
+.endr
+
+        vmul_vmls       q2,  \r1, \r7, d2[0], d2[1] // -> t4a
+        vmul_vmla       q3,  \r1, \r7, d2[1], d2[0] // -> t7a
+        vmul_vmls       q6,  \r5, \r3, d3[0], d3[1] // -> t5a
+        vmul_vmla       q7,  \r5, \r3, d3[1], d3[0] // -> t6a
+        vrshr.s32       \r1, q2,  #12               // t4a
+        vrshr.s32       \r7, q3,  #12               // t7a
+        vrshr.s32       \r3, q6,  #12               // t5a
+        vrshr.s32       \r5, q7,  #12               // t6a
+
+        vqadd.s32       q2,  \r1, \r3               // t4
+        vqsub.s32       \r1, \r1, \r3               // t5a
+        vqadd.s32       q3,  \r7, \r5               // t7
+        vqsub.s32       \r3, \r7, \r5               // t6a
+
+.irp r, q2, \r1, q3, \r3
+        vmin.s32        \r,  \r,  q5
+.endr
+.irp r, q2, \r1, q3, \r3
+        vmax.s32        \r,  \r,  q4
+.endr
+
+        vmul_vmls       q7,  \r3, \r1, d0[0], d0[0] // -> t5
+        vmul_vmla       q6,  \r3, \r1, d0[0], d0[0] // -> t6
+        vrshr.s32       q7,  q7,  #12               // t5
+        vrshr.s32       q5,  q6,  #12               // t6
+
+        vqsub.s32       \r7, \r0, q3  // out7
+        vqadd.s32       \r0, \r0, q3  // out0
+        vqadd.s32       \r1, \r2, q5  // out1
+        vqsub.s32       q6,  \r2, q5  // out6
+        vqadd.s32       \r2, \r4, q7  // out2
+        vqsub.s32       \r5, \r4, q7  // out5
+        vqadd.s32       \r3, \r6, q2  // out3
+        vqsub.s32       \r4, \r6, q2  // out4
+        vmov            \r6, q6       // out6
+.endm
+
+.macro idct_2s_x8 r0, r1, r2, r3, r4, r5, r6, r7
+        idct_2s_x4      \r0, \r2, \r4, \r6
+
+        vmov.i32        d9,  #0x1ffff // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vmvn.i32        d8,  #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+.irp r, \r0, \r2, \r4, \r6
+        vmin.s32        \r,  \r,  d9
+.endr
+.irp r, \r0, \r2, \r4, \r6
+        vmax.s32        \r,  \r,  d8
+.endr
+
+        vmul_vmls       d4,  \r1, \r7, d2[0], d2[1] // -> t4a
+        vmul_vmla       d5,  \r1, \r7, d2[1], d2[0] // -> t7a
+        vmul_vmls       d6,  \r5, \r3, d3[0], d3[1] // -> t5a
+        vmul_vmla       d7,  \r5, \r3, d3[1], d3[0] // -> t6a
+        vrshr.s32       \r1, d4,  #12               // t4a
+        vrshr.s32       \r7, d5,  #12               // t7a
+        vrshr.s32       \r3, d6,  #12               // t5a
+        vrshr.s32       \r5, d7,  #12               // t6a
+
+        vqadd.s32       d4,  \r1, \r3               // t4
+        vqsub.s32       \r1, \r1, \r3               // t5a
+        vqadd.s32       d5,  \r7, \r5               // t7
+        vqsub.s32       \r3, \r7, \r5               // t6a
+
+.irp r, d4, \r1, d5, \r3
+        vmin.s32        \r,  \r,  d9
+.endr
+.irp r, d4, \r1, d5, \r3
+        vmax.s32        \r,  \r,  d8
+.endr
+
+        vmul_vmls       d6,  \r3, \r1, d0[0], d0[0] // -> t5
+        vmul_vmla       d7,  \r3, \r1, d0[0], d0[0] // -> t6
+        vrshr.s32       d6,  d6,  #12               // t5
+        vrshr.s32       d7,  d7,  #12               // t6
+
+        vqsub.s32       \r7, \r0, d5  // out7
+        vqadd.s32       \r0, \r0, d5  // out0
+        vqadd.s32       \r1, \r2, d7  // out1
+        vqsub.s32       d7,  \r2, d7  // out6
+        vqadd.s32       \r2, \r4, d6  // out2
+        vqsub.s32       \r5, \r4, d6  // out5
+        vqadd.s32       \r3, \r6, d4  // out3
+        vqsub.s32       \r4, \r6, d4  // out4
+        vmov            \r6, d7       // out6
+.endm
+
+function inv_dct_4s_x8_neon
+        movrel_local    r12, idct_coeffs
+        vld1.32         {q0, q1}, [r12, :128]
+        idct_4s_x8      q8,  q9,  q10, q11, q12, q13, q14, q15
+        bx              lr
+endfunc
+
+.macro iadst_4s_x8 r0, r1, r2, r3, r4, r5, r6, r7
+        movrel_local    r12, iadst8_coeffs
+        vld1.32         {q0, q1}, [r12, :128]!
+
+        vmul_vmla       q2,  q15, q8,  d0[0], d0[1]
+        vmul_vmls       q3,  q15, q8,  d0[1], d0[0]
+        vmul_vmla       q4,  q13, q10, d1[0], d1[1]
+        vrshr.s32       q8,  q2,  #12 // t0a
+        vrshr.s32       q15, q3,  #12 // t1a
+        vmul_vmls       q5,  q13, q10, d1[1], d1[0]
+        vmul_vmla       q6,  q11, q12, d2[0], d2[1]
+        vrshr.s32       q10, q4,  #12 // t2a
+        vrshr.s32       q13, q5,  #12 // t3a
+        vmul_vmls       q7,  q11, q12, d2[1], d2[0]
+        vmul_vmla       q2,  q9,  q14, d3[0], d3[1]
+        vrshr.s32       q12, q6,  #12 // t4a
+        vrshr.s32       q11, q7,  #12 // t5a
+        vmul_vmls       q3,  q9,  q14, d3[1], d3[0]
+        vrshr.s32       q14, q2,  #12 // t6a
+        vrshr.s32       q9,  q3,  #12 // t7a
+
+        vld1.32         {q0}, [r12]
+
+        vqadd.s32       q2,  q8,  q12 // t0
+        vqsub.s32       q3,  q8,  q12 // t4
+        vmov.i32        q12, #0x1ffff // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vqadd.s32       q4,  q15, q11 // t1
+        vqsub.s32       q5,  q15, q11 // t5
+        vqadd.s32       q6,  q10, q14 // t2
+        vqsub.s32       q7,  q10, q14 // t6
+        vmvn.i32        q14, #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+        vqadd.s32       q10, q13, q9  // t3
+        vqsub.s32       q11, q13, q9  // t7
+
+.irp r, q2, q3, q4, q5, q6, q7, q10, q11
+        vmin.s32        \r,  \r,  q12
+.endr
+.irp r, q2, q3, q4, q5, q6, q7, q10, q11
+        vmax.s32        \r,  \r,  q14
+.endr
+
+        vmul_vmla       q8,  q3,  q5,  d1[1], d1[0]
+        vmul_vmls       q13, q3,  q5,  d1[0], d1[1]
+        vmul_vmls       q14, q11, q7,  d1[1], d1[0]
+
+        vrshr.s32       q3,  q8,  #12 // t4a
+        vrshr.s32       q5,  q13, #12 // t5a
+
+        vmul_vmla       q8,  q11, q7,  d1[0], d1[1]
+
+        vrshr.s32       q7,  q14, #12 // t6a
+        vrshr.s32       q11, q8,  #12 // t7a
+
+        vqadd.s32       \r0, q2,  q6  // out0
+        vqsub.s32       q2,  q2,  q6  // t2
+        vqadd.s32       \r7, q4,  q10 // out7
+        vqsub.s32       q4,  q4,  q10 // t3
+
+        vmvn.i32        q10, #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+
+        vqadd.s32       \r1, q3,  q7  // out1
+        vqsub.s32       q3,  q3,  q7  // t6
+        vqadd.s32       \r6, q5,  q11 // out6
+        vqsub.s32       q5,  q5,  q11 // t7
+
+        // Not clipping the output registers, as they will be downshifted and
+        // narrowed afterwards anyway.
+.irp r, q2, q4, q3, q5
+        vmin.s32        \r,  \r,  q12
+.endr
+.irp r, q2, q4, q3, q5
+        vmax.s32        \r,  \r,  q10
+.endr
+
+        vqneg.s32       \r7, \r7      // out7
+        vqneg.s32       \r1, \r1      // out1
+
+        vmul_vmla       q10, q2,  q4,  d0[0], d0[0] // -> out3 (q11 or q12)
+        vmul_vmls       q6,  q2,  q4,  d0[0], d0[0] // -> out4 (q12 or q11)
+        vmul_vmls       q12, q3,  q5,  d0[0], d0[0] // -> out5 (q13 or q10)
+        vrshr.s32       q2,  q10, #12 // out3
+        vmul_vmla       q10, q3,  q5,  d0[0], d0[0] // -> out2 (q10 or q13)
+        vrshr.s32       q3,  q12, #12 // out5
+        vrshr.s32       \r2, q10, #12 // out2 (q10 or q13)
+        vrshr.s32       \r4, q6,  #12 // out4 (q12 or q11)
+
+        vqneg.s32       \r3, q2       // out3
+        vqneg.s32       \r5, q3       // out5
+.endm
+
+function inv_adst_4s_x8_neon
+        iadst_4s_x8     q8,  q9,  q10, q11, q12, q13, q14, q15
+        bx              lr
+endfunc
+
+function inv_flipadst_4s_x8_neon
+        iadst_4s_x8     q15, q14, q13, q12, q11, q10, q9,  q8
+        bx              lr
+endfunc
+
+function inv_identity_4s_x8_neon
+        vqshl.s32       q8,  q8,  #1
+        vqshl.s32       q9,  q9,  #1
+        vqshl.s32       q10, q10, #1
+        vqshl.s32       q11, q11, #1
+        vqshl.s32       q12, q12, #1
+        vqshl.s32       q13, q13, #1
+        vqshl.s32       q14, q14, #1
+        vqshl.s32       q15, q15, #1
+        bx              lr
+endfunc
+
+function inv_txfm_add_8x8_neon
+        vmov.i32        q0,  #0
+        mov             r7,  #8*4
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.32         {\i},  [r2, :128]
+        vst1.32         {q0},  [r2, :128], r7
+.endr
+
+        blx             r4
+
+        vqrshrn.s32     d16, q8,  #1
+        vqrshrn.s32     d17, q12, #1
+        vqrshrn.s32     d18, q9,  #1
+        vqrshrn.s32     d19, q13, #1
+        vqrshrn.s32     d20, q10, #1
+        vqrshrn.s32     d21, q14, #1
+        vqrshrn.s32     d22, q11, #1
+        vqrshrn.s32     d23, q15, #1
+
+        cmp             r3,  r10
+        transpose_4x8h  q8,  q9,  q10, q11
+
+        blt             1f
+
+        sub             r2,  r2,  r7, lsl #3
+        vpush           {q8-q11}
+
+        add             r2,  r2,  #16
+        vmov.i32        q0,  #0
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.32         {\i},  [r2, :128]
+        vst1.32         {q0},  [r2, :128], r7
+.endr
+
+        blx             r4
+
+        vqrshrn.s32     d31, q15, #1
+        vqrshrn.s32     d30, q11, #1
+        vqrshrn.s32     d29, q14, #1
+        vqrshrn.s32     d28, q10, #1
+        vqrshrn.s32     d27, q13, #1
+        vqrshrn.s32     d26, q9,  #1
+        vqrshrn.s32     d25, q12, #1
+        vqrshrn.s32     d24, q8,  #1
+        vpop            {q8-q11}
+
+        transpose_4x8h  q12, q13, q14, q15
+
+        b               2f
+
+1:
+        vmov.i16        q12, #0
+        vmov.i16        q13, #0
+        vmov.i16        q14, #0
+        vmov.i16        q15, #0
+
+2:
+        blx             r5
+
+        load_add_store_8x8 r0, r7
+        vpop            {q4-q7}
+        pop             {r4-r5,r7,r10,pc}
+endfunc
+
+.macro def_fn_8x8 txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_8x8_16bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         8,   8,   1
+.endif
+        push            {r4-r5,r7,r10,lr}
+        vpush           {q4-q7}
+        mov             r10, #\eob_half
+        movrel_local    r4,  inv_\txfm1\()_4s_x8_neon
+        movrel          r5,  X(inv_\txfm2\()_8h_x8_neon)
+        b               inv_txfm_add_8x8_neon
+endfunc
+.endm
+
+def_fn_8x8 dct, dct, 10
+def_fn_8x8 identity, identity, 10
+def_fn_8x8 dct, adst, 10
+def_fn_8x8 dct, flipadst, 10
+def_fn_8x8 dct, identity, 4
+def_fn_8x8 adst, dct, 10
+def_fn_8x8 adst, adst, 10
+def_fn_8x8 adst, flipadst, 10
+def_fn_8x8 flipadst, dct, 10
+def_fn_8x8 flipadst, adst, 10
+def_fn_8x8 flipadst, flipadst, 10
+def_fn_8x8 identity, dct, 4
+def_fn_8x8 adst, identity, 4
+def_fn_8x8 flipadst, identity, 4
+def_fn_8x8 identity, adst, 4
+def_fn_8x8 identity, flipadst, 4
+
+function inv_txfm_add_8x4_neon
+        mov_const       r12, 2896*8*(1<<16)
+        vmov.i32        q0,  #0
+        vmov.i32        q1,  #0
+        vld1.16         {q8,  q9},  [r2, :128]
+        vst1.16         {q0,  q1},  [r2, :128]!
+        vdup.32         d4,  r12
+        vld1.16         {q10, q11}, [r2, :128]
+        vst1.16         {q0,  q1},  [r2, :128]!
+        vld1.16         {q12, q13}, [r2, :128]
+        vst1.16         {q0,  q1},  [r2, :128]!
+        vld1.16         {q14, q15}, [r2, :128]
+        vst1.16         {q0,  q1},  [r2, :128]!
+
+        scale_input     d4[0], q8,  q9, q10, q11, q12, q13, q14, q15
+
+        blx             r4
+
+        vqmovn.s32      d16, q8
+        vqmovn.s32      d17, q9
+        vqmovn.s32      d18, q10
+        vqmovn.s32      d19, q11
+        vqmovn.s32      d20, q12
+        vqmovn.s32      d21, q13
+        vqmovn.s32      d22, q14
+        vqmovn.s32      d23, q15
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        vswp            d17, d20
+        vswp            d19, d21
+        vswp            d18, d20
+        vswp            d21, d22
+
+        blx             r5
+
+        load_add_store_8x4 r0, r7
+        vpop            {q4-q7}
+        pop             {r4-r5,r7,r10,pc}
+endfunc
+
+function inv_txfm_add_4x8_neon
+        mov_const       r12, 2896*8*(1<<16)
+        vmov.i32        q0,  #0
+        cmp             r3,  r10
+        mov             r7,  #32
+        blt             1f
+
+        add             r2,  r2,  #16
+        vdup.32         d2,  r12
+.irp i, q8, q9, q10, q11
+        vld1.32         {\i},  [r2, :128]
+        vst1.32         {q0},  [r2, :128], r7
+.endr
+
+        scale_input     d2[0], q8,  q9, q10, q11
+        sub             r2,  r2,  r7, lsl #2
+
+        blx             r4
+
+        sub             r2,  r2,  #16
+
+        vqmovn.s32      d24, q8
+        vqmovn.s32      d25, q9
+        vqmovn.s32      d26, q10
+        vqmovn.s32      d27, q11
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+
+        b               2f
+
+1:
+        vmov.i16        q12, #0
+        vmov.i16        q13, #0
+
+2:
+        mov_const       r12, 2896*8*(1<<16)
+        vmov.i32        q0,  #0
+        vdup.32         d2,  r12
+.irp i, q8, q9, q10, q11
+        vld1.32         {\i},  [r2, :128]
+        vst1.32         {q0},  [r2, :128], r7
+.endr
+        scale_input     d2[0], q8,  q9, q10, q11
+        blx             r4
+
+        vqmovn.s32      d16, q8
+        vqmovn.s32      d17, q9
+        vqmovn.s32      d18, q10
+        vqmovn.s32      d19, q11
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+
+        vmov            q10, q12
+        vmov            q11, q13
+
+        blx             r5
+
+        load_add_store_4x8 r0, r7
+        vpop            {q4-q7}
+        pop             {r4-r5,r7,r10,pc}
+endfunc
+
+.macro def_fn_48 w, h, txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_16bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  0
+.endif
+        push            {r4-r5,r7,r10,lr}
+        vpush           {q4-q7}
+        movrel_local    r4,  inv_\txfm1\()_4s_x\w\()_neon
+.if \w == 4
+        mov             r10, #\eob_half
+.endif
+        movrel          r5,  X(inv_\txfm2\()_\w\()h_x\h\()_neon)
+        b               inv_txfm_add_\w\()x\h\()_neon
+endfunc
+.endm
+
+.macro def_fns_48 w, h
+def_fn_48 \w, \h, dct, dct, 13
+def_fn_48 \w, \h, identity, identity, 13
+def_fn_48 \w, \h, dct, adst, 13
+def_fn_48 \w, \h, dct, flipadst, 13
+def_fn_48 \w, \h, dct, identity, 4
+def_fn_48 \w, \h, adst, dct, 13
+def_fn_48 \w, \h, adst, adst, 13
+def_fn_48 \w, \h, adst, flipadst, 13
+def_fn_48 \w, \h, flipadst, dct, 13
+def_fn_48 \w, \h, flipadst, adst, 13
+def_fn_48 \w, \h, flipadst, flipadst, 13
+def_fn_48 \w, \h, identity, dct, 16
+def_fn_48 \w, \h, adst, identity, 4
+def_fn_48 \w, \h, flipadst, identity, 4
+def_fn_48 \w, \h, identity, adst, 16
+def_fn_48 \w, \h, identity, flipadst, 16
+.endm
+
+def_fns_48 4, 8
+def_fns_48 8, 4
+
+function inv_dct_2s_x16_neon
+        movrel_local    r12, idct_coeffs
+        vld1.32         {q0, q1}, [r12, :128]!
+
+        idct_2s_x8      d16, d18, d20, d22, d24, d26, d28, d30
+
+        // idct_8 leaves the row_clip_max/min constants in d9 and d8
+.irp r, d16, d18, d20, d22, d24, d26, d28, d30
+        vmin.s32        \r,  \r,  d9
+.endr
+.irp r, d16, d18, d20, d22, d24, d26, d28, d30
+        vmax.s32        \r,  \r,  d8
+.endr
+
+        vld1.32         {q0, q1}, [r12, :128]
+        sub             r12, r12, #32
+
+        vmul_vmls       d4,  d17, d31, d0[0], d0[1]  // -> t8a
+        vmul_vmla       d5,  d17, d31, d0[1], d0[0]  // -> t15a
+        vmul_vmls       d6,  d25, d23, d1[0], d1[1]  // -> t9a
+        vrshr.s32       d17, d4,  #12                // t8a
+        vrshr.s32       d31, d5,  #12                // t15a
+        vmul_vmla       d4,  d25, d23, d1[1], d1[0]  // -> t14a
+        vmul_vmls       d5,  d21, d27, d2[0], d2[1]  // -> t10a
+        vrshr.s32       d23, d6,  #12                // t9a
+        vrshr.s32       d25, d4,  #12                // t14a
+        vmul_vmla       d6,  d21, d27, d2[1], d2[0]  // -> t13a
+        vmul_vmls       d4,  d29, d19, d3[0], d3[1]  // -> t11a
+        vrshr.s32       d21, d5,  #12                // t10a
+        vrshr.s32       d27, d6,  #12                // t13a
+        vmul_vmla       d5,  d29, d19, d3[1], d3[0]  // -> t12a
+        vrshr.s32       d19, d4,  #12                // t11a
+        vrshr.s32       d29, d5,  #12                // t12a
+
+        vld1.32         {q0}, [r12, :128]
+
+        vqsub.s32       d4,  d17, d23  // t9
+        vqadd.s32       d17, d17, d23  // t8
+        vqsub.s32       d5,  d31, d25  // t14
+        vqadd.s32       d31, d31, d25  // t15
+        vqsub.s32       d23, d19, d21  // t10
+        vqadd.s32       d19, d19, d21  // t11
+        vqadd.s32       d25, d29, d27  // t12
+        vqsub.s32       d29, d29, d27  // t13
+
+.irp r, d4, d17, d5, d31, d23, d19, d25, d29
+        vmin.s32        \r,  \r,  d9
+.endr
+.irp r, d4, d17, d5, d31, d23, d19, d25, d29
+        vmax.s32        \r,  \r,  d8
+.endr
+
+        vmul_vmls       d6,  d5,  d4,  d1[0], d1[1]  // -> t9a
+        vmul_vmla       d7,  d5,  d4,  d1[1], d1[0]  // -> t14a
+        vrshr.s32       d21, d6,  #12                // t9a
+        vrshr.s32       d27, d7,  #12                // t14a
+
+        vmul_vmls       d6,  d29, d23, d1[0], d1[1]  // -> t13a
+        vmul_vmla       d7,  d29, d23, d1[1], d1[0]  // -> t10a
+        vrshr.s32       d29, d6,  #12                // t13a
+        vneg.s32        d7,  d7
+        vrshr.s32       d23, d7,  #12                // t10a
+
+        vqsub.s32       d4,  d17, d19  // t11a
+        vqadd.s32       d17, d17, d19  // t8a
+        vqsub.s32       d5,  d31, d25  // t12a
+        vqadd.s32       d31, d31, d25  // t15a
+        vqadd.s32       d19, d21, d23  // t9
+        vqsub.s32       d21, d21, d23  // t10
+        vqsub.s32       d25, d27, d29  // t13
+        vqadd.s32       d27, d27, d29  // t14
+
+.irp r, d4, d17, d5, d31, d19, d21, d25, d27
+        vmin.s32        \r,  \r,  d9
+.endr
+.irp r, d4, d17, d5, d31, d19, d21, d25, d27
+        vmax.s32        \r,  \r,  d8
+.endr
+
+        vmul_vmls       d6,  d5,  d4,  d0[0], d0[0]  // -> t11
+        vmul_vmla       d7,  d5,  d4,  d0[0], d0[0]  // -> t12
+        vmul_vmls       d4,  d25, d21, d0[0], d0[0]  // -> t10a
+
+        vrshr.s32       d6,  d6,  #12  // t11
+        vrshr.s32       d7,  d7,  #12  // t12
+        vmul_vmla       d5,  d25, d21, d0[0], d0[0]  // -> t13a
+        vrshr.s32       d4,  d4,  #12  // t10a
+        vrshr.s32       d5,  d5,  #12  // t13a
+
+        vqadd.s32       d8,  d16, d31  // out0
+        vqsub.s32       d31, d16, d31  // out15
+        vmov            d16, d8
+        vqadd.s32       d23, d30, d17  // out7
+        vqsub.s32       d9,  d30, d17  // out8
+        vqadd.s32       d17, d18, d27  // out1
+        vqsub.s32       d30, d18, d27  // out14
+        vqadd.s32       d18, d20, d5   // out2
+        vqsub.s32       d29, d20, d5   // out13
+        vqadd.s32       d5,  d28, d19  // out6
+        vqsub.s32       d25, d28, d19  // out9
+        vqadd.s32       d19, d22, d7   // out3
+        vqsub.s32       d28, d22, d7   // out12
+        vqadd.s32       d20, d24, d6   // out4
+        vqsub.s32       d27, d24, d6   // out11
+        vqadd.s32       d21, d26, d4   // out5
+        vqsub.s32       d26, d26, d4   // out10
+        vmov            d24, d9
+        vmov            d22, d5
+
+        bx              lr
+endfunc
+
+.macro iadst_16 o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15
+        movrel_local    r12, iadst16_coeffs
+        vld1.32         {q0, q1}, [r12, :128]!
+
+        vmul_vmla       d4,  d31, d16, d0[0], d0[1] // -> t0
+        vmul_vmls       d6,  d31, d16, d0[1], d0[0] // -> t1
+        vmul_vmla       d8,  d29, d18, d1[0], d1[1] // -> t2
+        vrshr.s32       d16, d4,  #12               // t0
+        vrshr.s32       d31, d6,  #12               // t1
+        vmul_vmls       d4,  d29, d18, d1[1], d1[0] // -> t3
+        vmul_vmla       d6,  d27, d20, d2[0], d2[1] // -> t4
+        vrshr.s32       d18, d8,  #12               // t2
+        vrshr.s32       d29, d4,  #12               // t3
+        vmul_vmls       d8,  d27, d20, d2[1], d2[0] // -> t5
+        vmul_vmla       d4,  d25, d22, d3[0], d3[1] // -> t6
+        vrshr.s32       d20, d6,  #12               // t4
+        vrshr.s32       d27, d8,  #12               // t5
+        vmul_vmls       d6,  d25, d22, d3[1], d3[0] // -> t7
+        vld1.32         {q0, q1}, [r12, :128]
+        movrel_local    r12, idct_coeffs
+        vmul_vmla       d8,  d23, d24, d0[0], d0[1] // -> t8
+        vrshr.s32       d22, d4,  #12               // t6
+        vrshr.s32       d25, d6,  #12               // t7
+        vmul_vmls       d4,  d23, d24, d0[1], d0[0] // -> t9
+        vmul_vmla       d6,  d21, d26, d1[0], d1[1] // -> t10
+        vrshr.s32       d23, d8,  #12               // t8
+        vrshr.s32       d24, d4,  #12               // t9
+        vmul_vmls       d8,  d21, d26, d1[1], d1[0] // -> t11
+        vmul_vmla       d4,  d19, d28, d2[0], d2[1] // -> t12
+        vrshr.s32       d21, d6,  #12               // t10
+        vrshr.s32       d26, d8,  #12               // t11
+        vmul_vmls       d6,  d19, d28, d2[1], d2[0] // -> t13
+        vmul_vmla       d8,  d17, d30, d3[0], d3[1] // -> t14
+        vrshr.s32       d19, d4,  #12               // t12
+        vrshr.s32       d28, d6,  #12               // t13
+        vmul_vmls       d4,  d17, d30, d3[1], d3[0] // -> t15
+        vrshr.s32       d17, d8,  #12               // t14
+        vrshr.s32       d30, d4,  #12               // t15
+
+        vld1.32         {q0, q1}, [r12, :128]
+
+        vmov.i32        d11, #0x1ffff // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vmvn.i32        d10, #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+
+        vqsub.s32       d5,  d16, d23 // t8a
+        vqadd.s32       d16, d16, d23 // t0a
+        vqsub.s32       d7,  d31, d24 // t9a
+        vqadd.s32       d31, d31, d24 // t1a
+        vqadd.s32       d23, d18, d21 // t2a
+        vqsub.s32       d18, d18, d21 // t10a
+        vqadd.s32       d24, d29, d26 // t3a
+        vqsub.s32       d29, d29, d26 // t11a
+        vqadd.s32       d21, d20, d19 // t4a
+        vqsub.s32       d20, d20, d19 // t12a
+        vqadd.s32       d26, d27, d28 // t5a
+        vqsub.s32       d27, d27, d28 // t13a
+        vqadd.s32       d19, d22, d17 // t6a
+        vqsub.s32       d22, d22, d17 // t14a
+        vqadd.s32       d28, d25, d30 // t7a
+        vqsub.s32       d25, d25, d30 // t15a
+
+.irp r, d5, d16, d7, d31, d23, d18, d24, d29, d21, d20, d26, d27, d19, d22, d28, d25
+        vmin.s32        \r,  \r,  d11
+.endr
+.irp r, d5, d16, d7, d31, d23, d18, d24, d29, d21, d20, d26, d27, d19, d22, d28, d25
+        vmax.s32        \r,  \r,  d10
+.endr
+
+        vmul_vmla       d4,  d5,  d7,  d2[1], d2[0] // -> t8
+        vmul_vmls       d6,  d5,  d7,  d2[0], d2[1] // -> t9
+        vmul_vmla       d8,  d18, d29, d3[1], d3[0] // -> t10
+        vrshr.s32       d17, d4,  #12               // t8
+        vrshr.s32       d30, d6,  #12               // t9
+        vmul_vmls       d4,  d18, d29, d3[0], d3[1] // -> t11
+        vmul_vmls       d6,  d27, d20, d2[1], d2[0] // -> t12
+        vrshr.s32       d18, d8,  #12               // t10
+        vrshr.s32       d29, d4,  #12               // t11
+        vmul_vmla       d8,  d27, d20, d2[0], d2[1] // -> t13
+        vmul_vmls       d4,  d25, d22, d3[1], d3[0] // -> t14
+        vrshr.s32       d27, d6,  #12               // t12
+        vrshr.s32       d20, d8,  #12               // t13
+        vmul_vmla       d6,  d25, d22, d3[0], d3[1] // -> t15
+        vrshr.s32       d25, d4,  #12               // t14
+        vrshr.s32       d22, d6,  #12               // t15
+
+        vqsub.s32       d2,  d16, d21 // t4
+        vqadd.s32       d16, d16, d21 // t0
+        vqsub.s32       d3,  d31, d26 // t5
+        vqadd.s32       d31, d31, d26 // t1
+        vqadd.s32       d21, d23, d19 // t2
+        vqsub.s32       d23, d23, d19 // t6
+        vqadd.s32       d26, d24, d28 // t3
+        vqsub.s32       d24, d24, d28 // t7
+        vqadd.s32       d19, d17, d27 // t8a
+        vqsub.s32       d17, d17, d27 // t12a
+        vqadd.s32       d28, d30, d20 // t9a
+        vqsub.s32       d30, d30, d20 // t13a
+        vqadd.s32       d27, d18, d25 // t10a
+        vqsub.s32       d18, d18, d25 // t14a
+        vqadd.s32       d20, d29, d22 // t11a
+        vqsub.s32       d29, d29, d22 // t15a
+
+.irp r, d2, d16, d3, d31, d21, d23, d26, d24, d19, d17, d28, d30, d27, d18, d20, d29
+        vmin.s32        \r,  \r,  d11
+.endr
+.irp r, d2, d16, d3, d31, d21, d23, d26, d24, d19, d17, d28, d30, d27, d18, d20, d29
+        vmax.s32        \r,  \r,  d10
+.endr
+
+        vmul_vmla       d4,  d2,  d3,  d1[1], d1[0] // -> t4a
+        vmul_vmls       d6,  d2,  d3,  d1[0], d1[1] // -> t5a
+        vmul_vmls       d8,  d24, d23, d1[1], d1[0] // -> t6a
+        vrshr.s32       d22, d4,  #12               // t4a
+        vrshr.s32       d25, d6,  #12               // t5a
+        vmul_vmla       d4,  d24, d23, d1[0], d1[1] // -> t7a
+        vmul_vmla       d6,  d17, d30, d1[1], d1[0] // -> t12
+        vrshr.s32       d24, d8,  #12               // t6a
+        vrshr.s32       d23, d4,  #12               // t7a
+        vmul_vmls       d8,  d17, d30, d1[0], d1[1] // -> t13
+        vmul_vmls       d4,  d29, d18, d1[1], d1[0] // -> t14
+        vrshr.s32       d17, d6,  #12               // t12
+        vmul_vmla       d6,  d29, d18, d1[0], d1[1] // -> t15
+        vrshr.s32       d29, d8,  #12               // t13
+        vrshr.s32       d30, d4,  #12               // t14
+        vrshr.s32       d18, d6,  #12               // t15
+
+        vqsub.s32       d2,  d16, d21 // t2a
+.ifc \o0, d16
+        vqadd.s32       \o0, d16, d21 // out0
+        vqsub.s32       d21, d31, d26 // t3a
+        vqadd.s32       \o15,d31, d26 // out15
+.else
+        vqadd.s32       d4,  d16, d21 // out0
+        vqsub.s32       d21, d31, d26 // t3a
+        vqadd.s32       \o15,d31, d26 // out15
+        vmov            \o0, d4
+.endif
+
+        vqsub.s32       d3,  d29, d18 // t15a
+        vqadd.s32       \o13,d29, d18 // out13
+        vqadd.s32       \o2, d17, d30 // out2
+        vqsub.s32       d26, d17, d30 // t14a
+
+        vqadd.s32       \o1, d19, d27 // out1
+        vqsub.s32       d27, d19, d27 // t10
+        vqadd.s32       \o14,d28, d20 // out14
+        vqsub.s32       d20, d28, d20 // t11
+
+        vqadd.s32       \o3, d22, d24 // out3
+        vqsub.s32       d22, d22, d24 // t6
+        vqadd.s32       \o12,d25, d23 // out12
+        vqsub.s32       d23, d25, d23 // t7
+
+        // Not clipping the output registers, as they will be downshifted and
+        // narrowed afterwards anyway.
+.irp r, d2, d21, d3, d26, d27, d20, d22, d23
+        vmin.s32        \r,  \r,  d11
+.endr
+.irp r, d2, d21, d3, d26, d27, d20, d22, d23
+        vmax.s32        \r,  \r,  d10
+.endr
+
+        vqneg.s32       \o15, \o15    // out15
+        vqneg.s32       \o13,\o13     // out13
+        vqneg.s32       \o1, \o1      // out1
+        vqneg.s32       \o3, \o3      // out3
+
+        vmul_vmls       d24, d2,  d21, d0[0], d0[0] // -> out8 (d24 or d23)
+        vmul_vmla       d4,  d2,  d21, d0[0], d0[0] // -> out7 (d23 or d24)
+        vmul_vmla       d6,  d26, d3,  d0[0], d0[0] // -> out5 (d21 or d26)
+
+        vrshr.s32       d24, d24, #12 // out8
+        vrshr.s32       d4,  d4,  #12 // out7
+        vrshr.s32       d5,  d6,  #12 // out5
+        vmul_vmls       d8,  d26, d3,  d0[0], d0[0] // -> out10 (d26 or d21)
+        vmul_vmla       d2,  d22, d23, d0[0], d0[0] // -> out4 (d20 or d27)
+        vrshr.s32       d26, d8,  #12 // out10
+
+        vmul_vmls       d8,  d22, d23, d0[0], d0[0] // -> out11 (d27 or d20)
+        vmul_vmla       d22, d27, d20, d0[0], d0[0] // -> out6 (d22 or d25)
+        vmul_vmls       d6,  d27, d20, d0[0], d0[0] // -> out9 (d25 or d22)
+
+        vrshr.s32       \o4, d2,  #12 // out4
+        vrshr.s32       d7,  d6,  #12 // out9
+        vrshr.s32       d6,  d8,  #12 // out11
+        vrshr.s32       \o6, d22, #12 // out6
+
+.ifc \o8, d23
+        vmov            \o8, d24
+        vmov            \o10,d26
+.endif
+
+        vqneg.s32       \o7, d4  // out7
+        vqneg.s32       \o5, d5  // out5
+        vqneg.s32       \o11,d6  // out11
+        vqneg.s32       \o9, d7  // out9
+.endm
+
+function inv_adst_2s_x16_neon
+        iadst_16        d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        bx              lr
+endfunc
+
+function inv_flipadst_2s_x16_neon
+        iadst_16        d31, d30, d29, d28, d27, d26, d25, d24, d23, d22, d21, d20, d19, d18, d17, d16
+        bx              lr
+endfunc
+
+function inv_identity_2s_x16_neon
+        mov             r12, #0
+        movt            r12, #2*(5793-4096)*8
+        vdup.32         d0,  r12
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vqrdmulh.s32    q1,  \i,  d0[0]
+        vqadd.s32       \i,  \i,  \i
+        vqadd.s32       \i,  \i,  q1
+.endr
+        bx              lr
+endfunc
+
+.macro identity_8x4_shift1 c
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vqrdmulh.s32    q2,  \i,  \c
+        vrshr.s32       q2,  q2,  #1
+        vqadd.s32       \i,  \i,  q2
+.endr
+.endm
+
+.macro identity_8x4 c
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vqrdmulh.s32    q2,  \i,  \c
+        vqadd.s32       \i,  \i,  \i
+        vqadd.s32       \i,  \i,  q2
+.endr
+.endm
+
+.macro def_horz_16 scale=0, shift=2, suffix
+function inv_txfm_horz\suffix\()_16x2_neon
+        push            {lr}
+        vmov.i32        d7,  #0
+.if \scale
+        mov_const       r12, 2896*8*(1<<16)
+        vdup.32         d1,  r12
+.endif
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.32         {\i}, [r7, :64]
+        vst1.32         {d7}, [r7, :64], r8
+.endr
+.if \scale
+        scale_input     d1[0], q8,  q9, q10, q11, q12, q13, q14, q15
+.endif
+        blx             r4
+        vqrshrn.s32     d16, q8,  #\shift
+        vqrshrn.s32     d17, q9,  #\shift
+        vqrshrn.s32     d18, q10, #\shift
+        vqrshrn.s32     d19, q11, #\shift
+        vqrshrn.s32     d20, q12, #\shift
+        vqrshrn.s32     d21, q13, #\shift
+        vqrshrn.s32     d22, q14, #\shift
+        vqrshrn.s32     d23, q15, #\shift
+.if \scale
+        b               L(horz_16x2_epilog)
+.else
+L(horz_16x2_epilog):
+        vuzp.16         q8,  q9
+        vuzp.16         q10, q11
+
+.irp i, q8, q10, q9, q11
+        vst1.16         {\i}, [r6, :128]!
+.endr
+
+        pop             {pc}
+.endif
+endfunc
+.endm
+
+def_horz_16 scale=1, shift=1, suffix=_scale
+def_horz_16 scale=0, shift=2
+
+function inv_txfm_add_vert_4x16_neon
+        push            {lr}
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64], r8
+.endr
+        blx             r5
+        load_add_store_4x16 r6, r7
+        pop             {pc}
+endfunc
+
+function inv_txfm_add_16x16_neon
+        sub_sp_align    512
+        ldrh            r11, [r10], #2
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14
+        add             r6,  sp,  #(\i*16*2)
+.if \i > 0
+        mov             r8,  #(16 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 14
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #16*4
+        bl              inv_txfm_horz_16x2_neon
+.endr
+        b               3f
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 2
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+3:
+.irp i, 0, 4, 8, 12
+        add             r6,  r0,  #(\i*2)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #32
+        bl              inv_txfm_add_vert_4x16_neon
+.endr
+
+        add_sp_align    512
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+const eob_16x16
+        .short 3, 10, 21, 36, 55, 78, 105, 256
+endconst
+
+const eob_16x16_identity
+        .short 2, 4, 6, 8, 10, 12, 14, 256
+endconst
+
+.macro def_fn_16x16 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_16x16_16bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         16,  16,  2
+.endif
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        movrel_local    r4,  inv_\txfm1\()_2s_x16_neon
+        movrel          r5,  X(inv_\txfm2\()_4h_x16_neon)
+.ifc \txfm1, identity
+.ifc \txfm2, identity
+        movrel_local    r10, eob_16x16
+.else
+        movrel_local    r10, eob_16x16_identity
+.endif
+.else
+.ifc \txfm2, identity
+        movrel_local    r10, eob_16x16_identity
+.else
+        movrel_local    r10, eob_16x16
+.endif
+.endif
+        b               inv_txfm_add_16x16_neon
+endfunc
+.endm
+
+def_fn_16x16 dct, dct
+def_fn_16x16 identity, identity
+def_fn_16x16 dct, adst
+def_fn_16x16 dct, flipadst
+def_fn_16x16 dct, identity
+def_fn_16x16 adst, dct
+def_fn_16x16 adst, adst
+def_fn_16x16 adst, flipadst
+def_fn_16x16 flipadst, dct
+def_fn_16x16 flipadst, adst
+def_fn_16x16 flipadst, flipadst
+def_fn_16x16 identity, dct
+
+function inv_txfm_add_16x4_neon
+        cmp             r3,  r10
+        mov             r11, #16
+        blt             1f
+
+        add             r6,  r2,  #8
+        vmov.i32        d4,  #0
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.32         {\i}, [r6, :64]
+        vst1.32         {d4}, [r6, :64], r11
+.endr
+        blx             r4
+
+        vqrshrn.s32     d16, q8,  #1
+        vqrshrn.s32     d17, q9,  #1
+        vqrshrn.s32     d18, q10, #1
+        vqrshrn.s32     d19, q11, #1
+        vqrshrn.s32     d20, q12, #1
+        vqrshrn.s32     d21, q13, #1
+        vqrshrn.s32     d22, q14, #1
+        vqrshrn.s32     d23, q15, #1
+        vuzp.16         q8,  q9
+        mov             r6,  sp
+        vuzp.16         q10, q11
+        vpush           {q8-q11}
+
+        b               2f
+
+1:
+        vmov.i16        q8,  #0
+        vmov.i16        q9,  #0
+        mov             r6,  sp
+        vpush           {q8-q9}
+        vpush           {q8-q9}
+
+2:
+        vmov.i32        d4,  #0
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.32         {\i}, [r2, :64]
+        vst1.32         {d4}, [r2, :64], r11
+.endr
+
+        blx             r4
+
+        vqrshrn.s32     d16, q8,  #1
+        vqrshrn.s32     d17, q9,  #1
+        vqrshrn.s32     d18, q10, #1
+        vqrshrn.s32     d19, q11, #1
+        vqrshrn.s32     d20, q12, #1
+        vqrshrn.s32     d21, q13, #1
+        vqrshrn.s32     d22, q14, #1
+        vqrshrn.s32     d23, q15, #1
+        vuzp.16         q8,  q9
+        mov             r6,  sp
+        vuzp.16         q10, q11
+
+        vmov            q12, q10
+        vmov            q13, q11
+
+        vpop            {q10-q11}
+        blx             r5
+        mov             r6,  r0
+        load_add_store_8x4 r6, r7
+
+        vpop            {q10-q11}
+        vmov            q8,  q12
+        vmov            q9,  q13
+        blx             r5
+        add             r6,  r0,  #16
+        load_add_store_8x4 r6, r7
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_4x16_neon
+        ldrh            r9,  [r10, #4]
+
+        mov             r11, #64
+        cmp             r3,  r9
+        ldrh            r9,  [r10, #2]
+        blt             1f
+
+        add             r6,  r2,  #48
+        vmov.i32        q2,  #0
+.irp i, q8,  q9,  q10, q11
+        vld1.32         {\i}, [r6, :128]
+        vst1.32         {q2}, [r6, :128], r11
+.endr
+        blx             r4
+        vqrshrn.s32     d28, q8,  #1
+        vqrshrn.s32     d29, q9,  #1
+        vqrshrn.s32     d30, q10, #1
+        vqrshrn.s32     d31, q11, #1
+        transpose_4x4h  q14, q15, d28, d29, d30, d31
+
+        b               2f
+1:
+        vmov.i16        q14, #0
+        vmov.i16        q15, #0
+2:
+        cmp             r3,  r9
+        ldrh            r9,  [r10]
+        blt             1f
+
+        add             r6,  r2,  #32
+        vmov.i32        q2,  #0
+.irp i, q8,  q9,  q10, q11
+        vld1.32         {\i}, [r6, :128]
+        vst1.32         {q2}, [r6, :128], r11
+.endr
+        blx             r4
+        vqrshrn.s32     d24, q8,  #1
+        vqrshrn.s32     d25, q9,  #1
+        vqrshrn.s32     d26, q10, #1
+        vqrshrn.s32     d27, q11, #1
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+
+        b               2f
+1:
+        vmov.i16        q12, #0
+        vmov.i16        q13, #0
+2:
+        cmp             r3,  r9
+        blt             1f
+
+        add             r6,  r2,  #16
+        vmov.i32        q2,  #0
+.irp i, q8,  q9,  q10, q11
+        vld1.32         {\i}, [r6, :128]
+        vst1.32         {q2}, [r6, :128], r11
+.endr
+        blx             r4
+        vqrshrn.s32     d16, q8,  #1
+        vqrshrn.s32     d17, q9,  #1
+        vqrshrn.s32     d18, q10, #1
+        vqrshrn.s32     d19, q11, #1
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+
+        b               2f
+1:
+        vmov.i16        q8,  #0
+        vmov.i16        q9,  #0
+2:
+        vmov.i16        q2,  #0
+        vpush           {q8-q9}
+.irp i, q8,  q9,  q10, q11
+        vld1.16         {\i}, [r2, :128]
+        vst1.16         {q2}, [r2, :128], r11
+.endr
+        blx             r4
+        vqrshrn.s32     d16, q8,  #1
+        vqrshrn.s32     d17, q9,  #1
+        vqrshrn.s32     d18, q10, #1
+        vqrshrn.s32     d19, q11, #1
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        vpop            {q10-q11}
+
+        blx             r5
+
+        load_add_store_4x16 r0, r6
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+const eob_4x16
+        .short 13, 29, 45, 64
+endconst
+
+const eob_4x16_identity1
+        .short 16, 32, 48, 64
+endconst
+
+const eob_4x16_identity2
+        .short 4, 8, 12, 64
+endconst
+
+.macro def_fn_416 w, h, txfm1, txfm2, eob_16x4
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_16bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  1
+.endif
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+.if \w == 4
+        movrel_local    r4,  inv_\txfm1\()_4s_x\w\()_neon
+        movrel          r5,  X(inv_\txfm2\()_4h_x\h\()_neon)
+.ifc \txfm1, identity
+.ifc \txfm2, identity
+        movrel_local    r10, eob_4x16
+.else
+        movrel_local    r10, eob_4x16_identity1
+.endif
+.else
+.ifc \txfm2, identity
+        movrel_local    r10, eob_4x16_identity2
+.else
+        movrel_local    r10, eob_4x16
+.endif
+.endif
+.else
+        mov             r10, #\eob_16x4
+        movrel_local    r4,  inv_\txfm1\()_2s_x\w\()_neon
+        movrel          r5,  X(inv_\txfm2\()_8h_x\h\()_neon)
+.endif
+        b               inv_txfm_add_\w\()x\h\()_neon
+endfunc
+.endm
+
+.macro def_fns_416 w, h
+def_fn_416 \w, \h, dct, dct, 3
+def_fn_416 \w, \h, identity, identity, 3
+def_fn_416 \w, \h, dct, adst, 3
+def_fn_416 \w, \h, dct, flipadst, 3
+def_fn_416 \w, \h, dct, identity, 2
+def_fn_416 \w, \h, adst, dct, 3
+def_fn_416 \w, \h, adst, adst, 3
+def_fn_416 \w, \h, adst, flipadst, 3
+def_fn_416 \w, \h, flipadst, dct, 3
+def_fn_416 \w, \h, flipadst, adst, 3
+def_fn_416 \w, \h, flipadst, flipadst, 3
+def_fn_416 \w, \h, identity, dct, 2
+def_fn_416 \w, \h, adst, identity, 2
+def_fn_416 \w, \h, flipadst, identity, 2
+def_fn_416 \w, \h, identity, adst, 2
+def_fn_416 \w, \h, identity, flipadst, 2
+.endm
+
+def_fns_416 4, 16
+def_fns_416 16, 4
+
+function inv_txfm_add_16x8_neon
+        sub_sp_align    256
+        ldrh            r11, [r10], #2
+
+.irp i, 0, 2, 4, 6
+        add             r6,  sp,  #(\i*16*2)
+.if \i > 0
+        mov             r8,  #(8 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 6
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #8*4
+        bl              inv_txfm_horz_scale_16x2_neon
+.endr
+        b               3f
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 2
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+3:
+
+.irp i, 0, 8
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #32
+.irp j, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\j}, [r7, :128], r8
+.endr
+        blx             r5
+
+        add             r6,  r0,  #(\i*2)
+        load_add_store_8x8 r6, r7
+.endr
+
+        add_sp_align    256
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_8x16_neon
+        add             r10, r10, #2
+        sub_sp_align    256
+        ldrh            r11, [r10], #4
+
+.irp i, 0, 4, 8, 12
+        add             r6,  sp,  #(\i*8*2)
+.if \i > 0
+        mov             r8,  #(16 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 12
+        ldrh            r11, [r10], #4
+.endif
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #16*4
+
+        mov_const       r12, 2896*8*(1<<16)
+        vmov.i32        q2,  #0
+        vdup.32         d0,  r12
+
+.irp j, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.32         {\j}, [r7, :128]
+        vst1.32         {q2}, [r7, :128], r8
+.endr
+        scale_input     d0[0], q8,  q9,  q10, q11, q12, q13, q14, q15
+        blx             r4
+        vqrshrn.s32     d16, q8,  #1
+        vqrshrn.s32     d17, q9,  #1
+        vqrshrn.s32     d18, q10, #1
+        vqrshrn.s32     d19, q11, #1
+        vqrshrn.s32     d20, q12, #1
+        vqrshrn.s32     d21, q13, #1
+        vqrshrn.s32     d22, q14, #1
+        vqrshrn.s32     d23, q15, #1
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+.irp j, d16, d20, d17, d21, d18, d22, d19, d23
+        vst1.16         {\j},  [r6, :64]!
+.endr
+.endr
+        b               3f
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #4
+.rept 2
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+3:
+
+.irp i, 0, 4
+        add             r6,  r0,  #(\i*2)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #16
+        bl              inv_txfm_add_vert_4x16_neon
+.endr
+
+        add_sp_align    256
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+const eob_8x16
+        .short 3, 10, 21, 43, 59, 75, 91, 128
+endconst
+
+const eob_8x16_identity1
+        .short 2, 4, 6, 64, 80, 96, 112, 128
+endconst
+
+const eob_8x16_identity2
+        .short 2, 4, 6, 8, 10, 12, 14, 128
+endconst
+
+.macro def_fn_816 w, h, txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_16bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  1
+.endif
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+.if \w == 8
+        movrel_local    r4,  inv_\txfm1\()_4s_x8_neon
+        movrel          r5,  X(inv_\txfm2\()_4h_x16_neon)
+.else
+        movrel_local    r4,  inv_\txfm1\()_2s_x16_neon
+        movrel          r5,  X(inv_\txfm2\()_8h_x8_neon)
+.endif
+.ifc \txfm1, identity
+.ifc \txfm2, identity
+        movrel_local    r10, eob_8x16
+.else
+        movrel_local    r10, eob_8x16_identity1
+.endif
+.else
+.ifc \txfm2, identity
+        movrel_local    r10, eob_8x16_identity2
+.else
+        movrel_local    r10, eob_8x16
+.endif
+.endif
+        b               inv_txfm_add_\w\()x\h\()_neon
+endfunc
+.endm
+
+.macro def_fns_816 w, h
+def_fn_816 \w, \h, dct, dct
+def_fn_816 \w, \h, identity, identity
+def_fn_816 \w, \h, dct, adst
+def_fn_816 \w, \h, dct, flipadst
+def_fn_816 \w, \h, dct, identity
+def_fn_816 \w, \h, adst, dct
+def_fn_816 \w, \h, adst, adst
+def_fn_816 \w, \h, adst, flipadst
+def_fn_816 \w, \h, flipadst, dct
+def_fn_816 \w, \h, flipadst, adst
+def_fn_816 \w, \h, flipadst, flipadst
+def_fn_816 \w, \h, identity, dct
+def_fn_816 \w, \h, adst, identity
+def_fn_816 \w, \h, flipadst, identity
+def_fn_816 \w, \h, identity, adst
+def_fn_816 \w, \h, identity, flipadst
+.endm
+
+def_fns_816 8, 16
+def_fns_816 16, 8
+
+function inv_dct32_odd_2s_x16_neon
+        movrel_local    r12, idct_coeffs, 4*16
+        vld1.32         {q0, q1}, [r12, :128]!
+
+        vmul_vmls       d4,  d16, d31, d0[0], d0[1] // -> t16a
+        vmul_vmla       d6,  d16, d31, d0[1], d0[0] // -> t31a
+        vmul_vmls       d8,  d24, d23, d1[0], d1[1] // -> t17a
+        vrshr.s32       d16, d4,  #12               // t16a
+        vrshr.s32       d31, d6,  #12               // t31a
+        vmul_vmla       d4,  d24, d23, d1[1], d1[0] // -> t30a
+        vmul_vmls       d6,  d20, d27, d2[0], d2[1] // -> t18a
+        vrshr.s32       d24, d8,  #12               // t17a
+        vrshr.s32       d23, d4,  #12               // t30a
+        vmul_vmla       d8,  d20, d27, d2[1], d2[0] // -> t29a
+        vmul_vmls       d4,  d28, d19, d3[0], d3[1] // -> t19a
+        vrshr.s32       d20, d6,  #12               // t18a
+        vrshr.s32       d27, d8,  #12               // t29a
+        vmul_vmla       d6,  d28, d19, d3[1], d3[0] // -> t28a
+        vld1.32         {q0, q1}, [r12, :128]
+        sub             r12, r12, #4*24
+        vmul_vmls       d8,  d18, d29, d0[0], d0[1] // -> t20a
+        vrshr.s32       d28, d4,  #12               // t19a
+        vrshr.s32       d19, d6,  #12               // t28a
+        vmul_vmla       d4,  d18, d29, d0[1], d0[0] // -> t27a
+        vmul_vmls       d6,  d26, d21, d1[0], d1[1] // -> t21a
+        vrshr.s32       d18, d8,  #12               // t20a
+        vrshr.s32       d29, d4,  #12               // t27a
+        vmul_vmla       d8,  d26, d21, d1[1], d1[0] // -> t26a
+        vmul_vmls       d4,  d22, d25, d2[0], d2[1] // -> t22a
+        vrshr.s32       d26, d6,  #12               // t21a
+        vrshr.s32       d21, d8,  #12               // t26a
+        vmul_vmla       d6,  d22, d25, d2[1], d2[0] // -> t25a
+        vmul_vmls       d8,  d30, d17, d3[0], d3[1] // -> t23a
+        vrshr.s32       d22, d4,  #12               // t22a
+        vrshr.s32       d25, d6,  #12               // t25a
+        vmul_vmla       d4,  d30, d17, d3[1], d3[0] // -> t24a
+        vrshr.s32       d30, d8,  #12               // t23a
+        vrshr.s32       d17, d4,  #12               // t24a
+
+        vld1.32         {q0, q1}, [r12, :128]
+
+        vmov.i32        d11, #0x1ffff // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vmvn.i32        d10, #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+
+        vqsub.s32       d5,  d16, d24 // t17
+        vqadd.s32       d16, d16, d24 // t16
+        vqsub.s32       d7,  d31, d23 // t30
+        vqadd.s32       d31, d31, d23 // t31
+        vqsub.s32       d24, d28, d20 // t18
+        vqadd.s32       d28, d28, d20 // t19
+        vqadd.s32       d23, d18, d26 // t20
+        vqsub.s32       d18, d18, d26 // t21
+        vqsub.s32       d20, d30, d22 // t22
+        vqadd.s32       d30, d30, d22 // t23
+        vqadd.s32       d26, d17, d25 // t24
+        vqsub.s32       d17, d17, d25 // t25
+        vqsub.s32       d22, d29, d21 // t26
+        vqadd.s32       d29, d29, d21 // t27
+        vqadd.s32       d25, d19, d27 // t28
+        vqsub.s32       d19, d19, d27 // t29
+
+.irp r, d5, d16, d7, d31, d24, d28, d23, d18, d20, d30, d26, d17, d22, d29, d25, d19
+        vmin.s32        \r,  \r,  d11
+.endr
+.irp r, d5, d16, d7, d31, d24, d28, d23, d18, d20, d30, d26, d17, d22, d29, d25, d19
+        vmax.s32        \r,  \r,  d10
+.endr
+
+        vmul_vmls       d4,  d7,  d5,  d2[0], d2[1] // -> t17a
+        vmul_vmla       d6,  d7,  d5,  d2[1], d2[0] // -> t30a
+        vmul_vmla       d8,  d19, d24, d2[1], d2[0] // -> t18a
+        vrshr.s32       d21, d4,  #12               // t17a
+        vrshr.s32       d27, d6,  #12               // t30a
+        vneg.s32        d8,  d8                     // -> t18a
+        vmul_vmls       d5,  d19, d24, d2[0], d2[1] // -> t29a
+        vmul_vmls       d4,  d22, d18, d3[0], d3[1] // -> t21a
+        vrshr.s32       d19, d8,  #12               // t18a
+        vrshr.s32       d24, d5,  #12               // t29a
+        vmul_vmla       d6,  d22, d18, d3[1], d3[0] // -> t26a
+        vmul_vmla       d8,  d17, d20, d3[1], d3[0] // -> t22a
+        vrshr.s32       d22, d4,  #12               // t21a
+        vrshr.s32       d18, d6,  #12               // t26a
+        vneg.s32        d8,  d8                     // -> t22a
+        vmul_vmls       d5,  d17, d20, d3[0], d3[1] // -> t25a
+        vrshr.s32       d17, d8,  #12               // t22a
+        vrshr.s32       d20, d5,  #12               // t25a
+
+        vqsub.s32       d2,  d27, d24 // t29
+        vqadd.s32       d27, d27, d24 // t30
+        vqsub.s32       d3,  d21, d19 // t18
+        vqadd.s32       d21, d21, d19 // t17
+        vqsub.s32       d24, d16, d28 // t19a
+        vqadd.s32       d16, d16, d28 // t16a
+        vqsub.s32       d19, d30, d23 // t20a
+        vqadd.s32       d30, d30, d23 // t23a
+        vqsub.s32       d28, d17, d22 // t21
+        vqadd.s32       d17, d17, d22 // t22
+        vqadd.s32       d23, d26, d29 // t24a
+        vqsub.s32       d26, d26, d29 // t27a
+        vqadd.s32       d22, d20, d18 // t25
+        vqsub.s32       d20, d20, d18 // t26
+        vqsub.s32       d29, d31, d25 // t28a
+        vqadd.s32       d31, d31, d25 // t31a
+
+.irp r, d2, d27, d3, d21, d24, d16, d19, d30, d28, d17, d23, d26, d22, d20, d29, d31
+        vmin.s32        \r,  \r,  d11
+.endr
+.irp r, d2, d27, d3, d21, d24, d16, d19, d30, d28, d17, d23, d26, d22, d20, d29, d31
+        vmax.s32        \r,  \r,  d10
+.endr
+
+        vmul_vmls       d4,  d2,  d3,  d1[0], d1[1] // -> t18a
+        vmul_vmla       d6,  d2,  d3,  d1[1], d1[0] // -> t29a
+        vmul_vmls       d8,  d29, d24, d1[0], d1[1] // -> t19
+        vrshr.s32       d18, d4,  #12               // t18a
+        vrshr.s32       d25, d6,  #12               // t29a
+        vmul_vmla       d5,  d29, d24, d1[1], d1[0] // -> t28
+        vmul_vmla       d4,  d26, d19, d1[1], d1[0] // -> t20
+        vrshr.s32       d29, d8,  #12               // t19
+        vrshr.s32       d24, d5,  #12               // t28
+        vneg.s32        d4,  d4                     // -> t20
+        vmul_vmls       d6,  d26, d19, d1[0], d1[1] // -> t27
+        vmul_vmla       d8,  d20, d28, d1[1], d1[0] // -> t21a
+        vrshr.s32       d26, d4,  #12               // t20
+        vrshr.s32       d19, d6,  #12               // t27
+        vneg.s32        d8,  d8                     // -> t21a
+        vmul_vmls       d5,  d20, d28, d1[0], d1[1] // -> t26a
+        vrshr.s32       d20, d8,  #12               // t21a
+        vrshr.s32       d28, d5,  #12               // t26a
+
+        vqsub.s32       d2,  d16, d30 // t23
+        vqadd.s32       d16, d16, d30 // t16 = out16
+        vqsub.s32       d3,  d31, d23 // t24
+        vqadd.s32       d31, d31, d23 // t31 = out31
+        vqsub.s32       d23, d21, d17 // t22a
+        vqadd.s32       d17, d21, d17 // t17a = out17
+        vqadd.s32       d30, d27, d22 // t30a = out30
+        vqsub.s32       d21, d27, d22 // t25a
+        vqsub.s32       d27, d18, d20 // t21
+        vqadd.s32       d18, d18, d20 // t18 = out18
+        vqadd.s32       d4,  d29, d26 // t19a = out19
+        vqsub.s32       d26, d29, d26 // t20a
+        vqadd.s32       d29, d25, d28 // t29 = out29
+        vqsub.s32       d25, d25, d28 // t26
+        vqadd.s32       d28, d24, d19 // t28a = out28
+        vqsub.s32       d24, d24, d19 // t27a
+        vmov            d19, d4       // out19
+
+.irp r, d2, d16, d3, d31, d23, d17, d30, d21, d27, d18, d19, d26, d29, d25, d28, d24
+        vmin.s32        \r,  \r,  d11
+.endr
+.irp r, d2, d16, d3, d31, d23, d17, d30, d21, d27, d18, d19, d26, d29, d25, d28, d24
+        vmax.s32        \r,  \r,  d10
+.endr
+
+        vmul_vmls       d4,  d24, d26, d0[0], d0[0] // -> t20
+        vmul_vmla       d6,  d24, d26, d0[0], d0[0] // -> t27
+        vrshr.s32       d20, d4,  #12   // t20
+        vrshr.s32       d22, d6,  #12   // t27
+
+        vmul_vmla       d4,  d25, d27, d0[0], d0[0] // -> t26a
+        vmul_vmls       d6,  d25, d27, d0[0], d0[0] // -> t21a
+        vmov            d27, d22        // t27
+        vrshr.s32       d26, d4,  #12   // t26a
+
+        vmul_vmls       d24, d21, d23, d0[0], d0[0] // -> t22
+        vmul_vmla       d4,  d21, d23, d0[0], d0[0] // -> t25
+        vrshr.s32       d21, d6,  #12   // t21a
+        vrshr.s32       d22, d24, #12   // t22
+        vrshr.s32       d25, d4,  #12   // t25
+
+        vmul_vmls       d4,  d3,  d2,  d0[0], d0[0] // -> t23a
+        vmul_vmla       d6,  d3,  d2,  d0[0], d0[0] // -> t24a
+        vrshr.s32       d23, d4,  #12   // t23a
+        vrshr.s32       d24, d6,  #12   // t24a
+
+        bx              lr
+endfunc
+
+.macro def_horz_32 scale=0, shift=2, suffix
+function inv_txfm_horz\suffix\()_dct_32x2_neon
+        push            {lr}
+        vmov.i32        d7,  #0
+        lsl             r8,  r8,  #1
+.if \scale
+        mov_const       r12, 2896*8*(1<<16)
+        vdup.32         d0,  r12
+.endif
+
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.32         {\i}, [r7, :64]
+        vst1.32         {d7}, [r7, :64], r8
+.endr
+        sub             r7,  r7,  r8, lsl #4
+        add             r7,  r7,  r8, lsr #1
+.if \scale
+        scale_input     d0[0], q8,  q9,  q10, q11, q12, q13, q14, q15
+.endif
+        bl              inv_dct_2s_x16_neon
+
+        // idct_16 leaves the row_clip_max/min constants in d9 and d8,
+        // but here we want to use full q registers for clipping.
+        vmov.i32        q3,  #0x1ffff // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vmvn.i32        q2,  #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+.irp r, q8, q9, q10, q11, q12, q13, q14, q15
+        vmin.s32        \r,  \r,  q3
+.endr
+.irp r, q8, q9, q10, q11, q12, q13, q14, q15
+        vmax.s32        \r,  \r,  q2
+.endr
+
+        vtrn.32         d16, d17
+        vtrn.32         d18, d19
+        vtrn.32         d20, d21
+        vtrn.32         d22, d23
+        vtrn.32         d24, d25
+        vtrn.32         d26, d27
+        vtrn.32         d28, d29
+        vtrn.32         d30, d31
+
+.macro store1 r0, r1, r2, r3
+        vst1.16         {\r0}, [r6, :64]!
+        vst1.16         {\r1}, [r6, :64]!
+        vst1.16         {\r2}, [r6, :64]!
+        vst1.16         {\r3}, [r6, :64]!
+.endm
+        store1          d16, d18, d20, d22
+        store1          d24, d26, d28, d30
+        store1          d17, d19, d21, d23
+        store1          d25, d27, d29, d31
+.purgem store1
+        sub             r6,  r6,  #64*2
+
+        vmov.i32        d7,  #0
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.32         {\i}, [r7, :64]
+        vst1.32         {d7}, [r7, :64], r8
+.endr
+.if \scale
+        // This relies on the fact that the idct also leaves the right coeff in d0[1]
+        scale_input     d0[1], q8,  q9,  q10, q11, q12, q13, q14, q15
+.endif
+        bl              inv_dct32_odd_2s_x16_neon
+        vtrn.32         d31, d30
+        vtrn.32         d29, d28
+        vtrn.32         d27, d26
+        vtrn.32         d25, d24
+        vtrn.32         d23, d22
+        vtrn.32         d21, d20
+        vtrn.32         d19, d18
+        vtrn.32         d17, d16
+.macro store2 r0, r1, r2, r3, r4, r5, r6, r7, shift
+        vld1.32         {q0, q1}, [r6, :128]!
+        vld1.32         {q2, q3}, [r6, :128]
+        sub             r6,  r6,  #32
+        vqsub.s32       d15, d0,  \r0
+        vqadd.s32       d0,  d0,  \r0
+        vqsub.s32       d14, d1,  \r1
+        vqadd.s32       d1,  d1,  \r1
+        vqsub.s32       d13, d2,  \r2
+        vqadd.s32       d2,  d2,  \r2
+        vqsub.s32       d12, d3,  \r3
+        vqadd.s32       d3,  d3,  \r3
+        vqsub.s32       d11, d4,  \r4
+        vqadd.s32       d4,  d4,  \r4
+        vqsub.s32       d10, d5,  \r5
+        vqadd.s32       d5,  d5,  \r5
+        vqsub.s32       d9,  d6,  \r6
+        vqadd.s32       d6,  d6,  \r6
+        vqsub.s32       d8,  d7,  \r7
+        vqadd.s32       d7,  d7,  \r7
+        vqrshrn.s32     d0,  q0,  #\shift
+        vqrshrn.s32     d1,  q1,  #\shift
+        vqrshrn.s32     d2,  q2,  #\shift
+        vqrshrn.s32     d3,  q3,  #\shift
+        vqrshrn.s32     d4,  q4,  #\shift
+        vqrshrn.s32     d5,  q5,  #\shift
+        vqrshrn.s32     d6,  q6,  #\shift
+        vqrshrn.s32     d7,  q7,  #\shift
+        vrev32.16       q2,  q2
+        vrev32.16       q3,  q3
+        vst1.16         {q0, q1}, [r6, :128]!
+        vst1.16         {q2, q3}, [r6, :128]!
+.endm
+
+        store2          d31, d29, d27, d25, d23, d21, d19, d17, \shift
+        store2          d30, d28, d26, d24, d22, d20, d18, d16, \shift
+.purgem store2
+        pop             {pc}
+endfunc
+.endm
+
+def_horz_32 scale=0, shift=2
+def_horz_32 scale=1, shift=1, suffix=_scale
+
+function inv_txfm_add_vert_dct_4x32_neon
+        push            {r10-r11,lr}
+        lsl             r8,  r8,  #1
+
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64], r8
+.endr
+        sub             r7,  r7,  r8, lsl #4
+
+        bl              X(inv_dct_4h_x16_neon)
+
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vst1.16         {\i}, [r7, :64], r8
+.endr
+        sub             r7,  r7,  r8, lsl #4
+        add             r7,  r7,  r8, lsr #1
+
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31
+        vld1.16         {\i}, [r7, :64], r8
+.endr
+        sub             r7,  r7,  r8, lsl #4
+        sub             r7,  r7,  r8, lsr #1
+        bl              X(inv_dct32_odd_4h_x16_neon)
+
+        neg             r9,  r8
+        mov             r10, r6
+        vmov.i16        q6,  #0
+        vmvn.i16        q7,  #0xfc00 // 0x3ff
+.macro combine r0, r1, r2, r3, op, stride
+        vld1.16         {d4}, [r7,  :64], \stride
+        vld1.16         {d0}, [r10, :64], r1
+        vld1.16         {d5}, [r7,  :64],  \stride
+        vld1.16         {d1}, [r10, :64], r1
+        \op\().s16      d4,  d4,  \r0
+        vld1.16         {d6}, [r7,  :64], \stride
+        vld1.16         {d2}, [r10, :64], r1
+        \op\().s16      d5,  d5,  \r1
+        vld1.16         {d3}, [r10, :64], r1
+        vrshr.s16       q2,  q2,  #4
+        \op\().s16      d6,  d6,  \r2
+        vld1.16         {d7}, [r7,  :64], \stride
+        vqadd.s16       q0,  q0,  q2
+        \op\().s16      d7,  d7,  \r3
+        vmax.s16        q0,  q0,  q6
+        vrshr.s16       q3,  q3,  #4
+        vmin.s16        q0,  q0,  q7
+        vqadd.s16       q1,  q1,  q3
+        vst1.16         {d0}, [r6,  :64], r1
+        vmax.s16        q1,  q1,  q6
+        vst1.16         {d1}, [r6,  :64], r1
+        vmin.s16        q1,  q1,  q7
+        vst1.16         {d2}, [r6,  :64], r1
+        vst1.16         {d3}, [r6,  :64], r1
+.endm
+        combine         d31, d30, d29, d28, vqadd, r8
+        combine         d27, d26, d25, d24, vqadd, r8
+        combine         d23, d22, d21, d20, vqadd, r8
+        combine         d19, d18, d17, d16, vqadd, r8
+        sub             r7,  r7,  r8
+        combine         d16, d17, d18, d19, vqsub, r9
+        combine         d20, d21, d22, d23, vqsub, r9
+        combine         d24, d25, d26, d27, vqsub, r9
+        combine         d28, d29, d30, d31, vqsub, r9
+.purgem combine
+
+        pop             {r10-r11,pc}
+endfunc
+
+const eob_32x32
+        .short 3, 10, 21, 36, 55, 78, 105, 136, 171, 210, 253, 300, 351, 406, 465, 1024
+endconst
+
+const eob_16x32
+        .short 3, 10, 21, 36, 55, 78, 105, 151, 183, 215, 247, 279, 311, 343, 375, 512
+endconst
+
+const eob_16x32_shortside
+        .short 3, 10, 21, 36, 55, 78, 105, 512
+endconst
+
+const eob_8x32
+        .short 3, 10, 21, 43, 59, 75, 91, 107, 123, 139, 155, 171, 187, 203, 219, 256
+endconst
+
+function inv_txfm_add_identity_identity_32x32_16bpc_neon, export=1
+        push            {r4-r7,lr}
+        vpush           {q6-q7}
+        movrel_local    r5,  eob_32x32, 2
+
+        mov             r6,  #4*32
+1:
+        mov             r12, #0
+        movrel_local    r4,  eob_32x32, 6
+2:
+        vmov.i32        q0,  #0
+        add             r12, r12, #8
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.32         {\i}, [r2, :128]
+        vst1.32         {q0}, [r2, :128], r6
+.endr
+        vqmovn.s32      d16, q8
+        vqmovn.s32      d17, q12
+        vqmovn.s32      d18, q9
+        vqmovn.s32      d19, q13
+        vqmovn.s32      d20, q10
+        vqmovn.s32      d21, q14
+        vqmovn.s32      d22, q11
+        vqmovn.s32      d23, q15
+        transpose_4x8h  q8,  q9,  q10, q11
+
+        load_add_store_8x4 r0, r7, shiftbits=2
+        ldrh            lr,  [r4], #8
+        sub             r0,  r0,  r1, lsl #2
+        cmp             r3,  lr
+        add             r0,  r0,  #2*8
+        bge             2b
+
+        ldrh            lr,  [r5], #4
+        cmp             r3,  lr
+        blt             9f
+
+        sub             r0,  r0,  r12, lsl #1
+        add             r0,  r0,  r1,  lsl #2
+        mls             r2,  r6,  r12, r2
+        add             r2,  r2,  #4*4
+        b               1b
+9:
+        vpop            {q6-q7}
+        pop             {r4-r7,pc}
+endfunc
+
+.macro shift_8_regs op, shift
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        \op             \i,  \i,  #\shift
+.endr
+.endm
+
+.macro def_identity_1632 w, h, wshort, hshort
+function inv_txfm_add_identity_identity_\w\()x\h\()_16bpc_neon, export=1
+        push            {r4-r9,lr}
+        vpush           {q6-q7}
+        mov             r9,  #0
+        mov_const       r8,  2896*8*(1<<16)
+        movt            r9,  #2*(5793-4096)*8
+        movrel_local    r5,  eob_16x32\hshort, 2
+
+        mov             r6,  #4*\h
+1:
+        mov             r12, #0
+        movrel_local    r4,  eob_16x32\wshort, 6
+2:
+        vdup.i32        d0,  r8
+        vmov.i32        q1,  #0
+        vmov.32         d0[1], r9
+        add             r12, r12, #8
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.32         {\i}, [r2, :128]
+        vst1.32         {q1}, [r2, :128], r6
+.endr
+        scale_input     d0[0], q8,  q9, q10, q11, q12, q13, q14, q15
+
+.if \w == 16
+        // 16x32
+        identity_8x4_shift1 d0[1]
+.else
+        // 32x16
+        shift_8_regs    vqshl.s32, 1
+        identity_8x4    d0[1]
+.endif
+        vqmovn.s32      d16, q8
+        vqmovn.s32      d17, q12
+        vqmovn.s32      d18, q9
+        vqmovn.s32      d19, q13
+        vqmovn.s32      d20, q10
+        vqmovn.s32      d21, q14
+        vqmovn.s32      d22, q11
+        vqmovn.s32      d23, q15
+        transpose_4x8h  q8,  q9,  q10, q11
+
+.if \w == 16
+        load_add_store_8x4 r0, r7, shiftbits=2
+.else
+        load_add_store_8x4 r0, r7, shiftbits=4
+.endif
+        ldrh            lr,  [r4], #8
+        sub             r0,  r0,  r1, lsl #2
+        cmp             r3,  lr
+        add             r0,  r0,  #2*8
+        bge             2b
+
+        ldrh            lr,  [r5], #4
+        cmp             r3,  lr
+        blt             9f
+
+        sub             r0,  r0,  r12, lsl #1
+        add             r0,  r0,  r1,  lsl #2
+        mls             r2,  r6,  r12, r2
+        add             r2,  r2,  #4*4
+        b               1b
+9:
+        vpop            {q6-q7}
+        pop             {r4-r9,pc}
+endfunc
+.endm
+
+def_identity_1632 16, 32, _shortside,
+def_identity_1632 32, 16, , _shortside
+
+.macro def_identity_832 w, h
+function inv_txfm_add_identity_identity_\w\()x\h\()_16bpc_neon, export=1
+        push            {r4-r5,lr}
+        vpush           {q6-q7}
+        movrel_local    r4,  eob_8x32, 2
+
+        mov             r12, #4*\h
+1:
+        ldrh            lr,  [r4], #4
+.if \w == 8
+        vmov.i32        q0,  #0
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.32         {\i}, [r2, :128]
+        vst1.32         {q0}, [r2, :128], r12
+.endr
+
+        vqrshrn.s32     d16, q8,  #1
+        vqrshrn.s32     d17, q12, #1
+        vqrshrn.s32     d18, q9,  #1
+        vqrshrn.s32     d19, q13, #1
+        vqrshrn.s32     d20, q10, #1
+        vqrshrn.s32     d21, q14, #1
+        vqrshrn.s32     d22, q11, #1
+        vqrshrn.s32     d23, q15, #1
+
+        transpose_4x8h  q8,  q9,  q10, q11
+
+        cmp             r3,  lr
+        load_add_store_8x4 r0, r5, shiftbits=2
+        blt             9f
+        sub             r2,  r2,  r12, lsl #3
+        add             r2,  r2,  #4*4
+.else
+        vmov.i32        q0,  #0
+        vmov.i32        q1,  #0
+        vld1.32         {q8,  q9},  [r2, :128]
+        vst1.32         {q0,  q1},  [r2, :128], r12
+        vld1.32         {q10, q11}, [r2, :128]
+        vst1.32         {q0,  q1},  [r2, :128], r12
+        vld1.32         {q12, q13}, [r2, :128]
+        vst1.32         {q0,  q1},  [r2, :128], r12
+        vld1.32         {q14, q15}, [r2, :128]
+        vst1.32         {q0,  q1},  [r2, :128], r12
+        vqmovn.s32      d16, q8
+        vqmovn.s32      d17, q10
+        vqmovn.s32      d20, q9
+        vqmovn.s32      d21, q11
+        vqmovn.s32      d18, q12
+        vqmovn.s32      d19, q14
+        vqmovn.s32      d22, q13
+        vqmovn.s32      d23, q15
+
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+
+        cmp             r3,  lr
+        load_add_store_4x8 r0, r5, shiftbits=3
+        blt             9f
+        sub             r0,  r0,  r1, lsl #3
+        add             r0,  r0,  #2*4
+.endif
+        b               1b
+
+9:
+        vpop            {q6-q7}
+        pop             {r4-r5,pc}
+endfunc
+.endm
+
+def_identity_832 8, 32
+def_identity_832 32, 8
+
+function inv_txfm_add_dct_dct_32x32_16bpc_neon, export=1
+        idct_dc         32,  32,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        sub_sp_align    2048
+        movrel_local    r10, eob_32x32
+        ldrh            r11, [r10], #2
+
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+        add             r6,  sp,  #(\i*32*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 30
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #32*4
+        bl              inv_txfm_horz_dct_32x2_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  r0,  #(\i*2)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_add_vert_dct_4x32_neon
+.endr
+
+        add_sp_align    2048
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_16x32_16bpc_neon, export=1
+        idct_dc         16,  32,  1
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        sub_sp_align    1024
+        movrel_local    r10, eob_16x32
+        ldrh            r11, [r10], #2
+        movrel_local    r4,  inv_dct_2s_x16_neon
+
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+        add             r6,  sp,  #(\i*16*2)
+        add             r7,  r2,  #(\i*4)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 30
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        mov             r8,  #4*32
+        bl              inv_txfm_horz_scale_16x2_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 2
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12
+        add             r6,  r0,  #(\i*2)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #16*2
+        bl              inv_txfm_add_vert_dct_4x32_neon
+.endr
+
+        add_sp_align    1024
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_32x16_16bpc_neon, export=1
+        idct_dc         32,  16,  1
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        sub_sp_align    1024
+        movrel_local    r10, eob_16x32
+        ldrh            r11, [r10], #2
+        movrel          r5,  X(inv_dct_4h_x16_neon)
+
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14
+        add             r6,  sp,  #(\i*32*2)
+        add             r7,  r2,  #(\i*4)
+.if \i > 0
+        mov             r8,  #(16 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 14
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        mov             r8,  #4*16
+        bl              inv_txfm_horz_scale_dct_32x2_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r6,  r0,  #(\i*2)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #32*2
+        bl              inv_txfm_add_vert_4x16_neon
+.endr
+
+        add_sp_align    1024
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_8x32_16bpc_neon, export=1
+        idct_dc         8,   32,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        sub_sp_align    512
+
+        movrel_local    r10, eob_8x32, 2
+
+        mov             r8,  #4*32
+        mov             r9,  #32
+        mov             r6,  sp
+1:
+        vmov.i32        q0,  #0
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.32         {\i}, [r2, :128]
+        vst1.32         {q0}, [r2, :128], r8
+.endr
+        ldrh            r11, [r10], #4
+        sub             r2,  r2,  r8, lsl #3
+        sub             r9,  r9,  #4
+        add             r2,  r2,  #4*4
+
+        bl              inv_dct_4s_x8_neon
+
+        vqrshrn.s32     d16, q8,  #2
+        vqrshrn.s32     d18, q9,  #2
+        vqrshrn.s32     d20, q10, #2
+        vqrshrn.s32     d22, q11, #2
+        vqrshrn.s32     d17, q12, #2
+        vqrshrn.s32     d19, q13, #2
+        vqrshrn.s32     d21, q14, #2
+        vqrshrn.s32     d23, q15, #2
+
+        transpose_4x8h  q8,  q9,  q10, q11
+
+        vst1.16         {q8,  q9},  [r6, :128]!
+        cmp             r3,  r11
+        vst1.16         {q10, q11}, [r6, :128]!
+
+        bge             1b
+        cmp             r9,  #0
+        beq             3f
+
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r9,  r9,  #4
+.rept 2
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4
+        add             r6,  r0,  #(\i*2)
+        add             r7,  sp,  #(\i*2)
+        mov             r8,  #8*2
+        bl              inv_txfm_add_vert_dct_4x32_neon
+.endr
+
+        add_sp_align    512
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_32x8_16bpc_neon, export=1
+        idct_dc         32,  8,   2
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        movrel_local    r10, eob_8x32
+        sub_sp_align    512
+        ldrh            r11, [r10], #2
+
+.irp i, 0, 2, 4, 6
+        add             r6,  sp,  #(\i*32*2)
+        add             r7,  r2,  #(\i*4)
+.if \i > 0
+        cmp             r3,  r11
+        mov             r8,  #(8 - \i)
+        blt             1f
+.if \i < 6
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        mov             r8,  #8*4
+        bl              inv_txfm_horz_dct_32x2_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+        mov             r8,  #2*32
+        mov             r9,  #0
+1:
+        add             r6,  r0,  r9, lsl #1
+        add             r7,  sp,  r9, lsl #1 // #(\i*2)
+
+.irp i, q8, q9, q10, q11, q12, q13, q14, q15
+        vld1.16         {\i}, [r7, :128], r8
+.endr
+        add             r9,  r9,  #8
+
+        bl              X(inv_dct_8h_x8_neon)
+
+        cmp             r9,  #32
+
+        load_add_store_8x8 r6, r7
+
+        blt             1b
+
+        add_sp_align    512
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_dct64_step1_neon
+        // in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+        // in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+        // in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+        // in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+
+        vld1.32         {q0, q1}, [r12, :128]!
+
+        vqrdmulh.s32    d23, d16, d0[1]  // t63a
+        vqrdmulh.s32    d16, d16, d0[0]  // t32a
+        vqrdmulh.s32    d22, d17, d1[0]  // t62a
+        vqrdmulh.s32    d17, d17, d1[1]  // t33a
+        vqrdmulh.s32    d21, d18, d2[1]  // t61a
+        vqrdmulh.s32    d18, d18, d2[0]  // t34a
+        vqrdmulh.s32    d20, d19, d3[0]  // t60a
+        vqrdmulh.s32    d19, d19, d3[1]  // t35a
+
+        vld1.32         {q0}, [r12, :128]!
+
+        vqadd.s32       d24, d16, d17    // t32
+        vqsub.s32       d25, d16, d17    // t33
+        vqsub.s32       d26, d19, d18    // t34
+        vqadd.s32       d27, d19, d18    // t35
+        vqadd.s32       d28, d20, d21    // t60
+        vqsub.s32       d29, d20, d21    // t61
+        vqsub.s32       d30, d23, d22    // t62
+        vqadd.s32       d31, d23, d22    // t63
+
+.irp r, q12, q13, q14, q15
+        vmin.s32        \r,  \r,  q5
+.endr
+.irp r, q12, q13, q14, q15
+        vmax.s32        \r,  \r,  q4
+.endr
+
+        vmul_vmla       d4,  d29, d26, d0[0], d0[1] // -> t34a
+        vmul_vmls       d6,  d29, d26, d0[1], d0[0] // -> t61a
+        vneg.s32        d4,  d4                     // t34a
+        vmul_vmls       d7,  d30, d25, d0[1], d0[0] // -> t33a
+        vrshr.s32       d26, d4,  #12               // t34a
+        vmul_vmla       d4,  d30, d25, d0[0], d0[1] // -> t62a
+        vrshr.s32       d29, d6,  #12               // t61a
+        vrshr.s32       d25, d7,  #12               // t33a
+        vrshr.s32       d30, d4,  #12               // t62a
+
+        vqadd.s32       d16, d24, d27    // t32a
+        vqsub.s32       d19, d24, d27    // t35a
+        vqadd.s32       d17, d25, d26    // t33
+        vqsub.s32       d18, d25, d26    // t34
+        vqsub.s32       d20, d31, d28    // t60a
+        vqadd.s32       d23, d31, d28    // t63a
+        vqsub.s32       d21, d30, d29    // t61
+        vqadd.s32       d22, d30, d29    // t62
+
+.irp r, q8, q9, q10, q11
+        vmin.s32        \r,  \r,  q5
+.endr
+.irp r, q8, q9, q10, q11
+        vmax.s32        \r,  \r,  q4
+.endr
+
+        vmul_vmla       d4,  d21, d18, d1[0], d1[1] // -> t61a
+        vmul_vmls       d6,  d21, d18, d1[1], d1[0] // -> t34a
+        vmul_vmla       d7,  d20, d19, d1[0], d1[1] // -> t60
+        vrshr.s32       d21, d4,  #12               // t61a
+        vrshr.s32       d18, d6,  #12               // t34a
+        vmul_vmls       d4,  d20, d19, d1[1], d1[0] // -> t35
+        vrshr.s32       d20, d7,  #12               // t60
+        vrshr.s32       d19, d4,  #12               // t35
+
+        vst1.32         {d16, d17, d18, d19}, [r6, :128]!
+        vst1.32         {d20, d21, d22, d23}, [r6, :128]!
+
+        bx              lr
+endfunc
+
+function inv_dct64_step2_neon
+        movrel_local    r12, idct_coeffs
+        vld1.32         {q0}, [r12, :128]
+1:
+        // t32a/33/34a/35/60/61a/62/63a
+        // t56a/57/58a/59/36/37a/38/39a
+        // t40a/41/42a/43/52/53a/54/55a
+        // t48a/49/50a/51/44/45a/46/47a
+        vldr            d16, [r6, #4*2*0]  // t32a
+        vldr            d17, [r9, #4*2*8]  // t39a
+        vldr            d18, [r9, #4*2*0]  // t63a
+        vldr            d19, [r6, #4*2*8]  // t56a
+        vldr            d20, [r6, #4*2*16] // t40a
+        vldr            d21, [r9, #4*2*24] // t47a
+        vldr            d22, [r9, #4*2*16] // t55a
+        vldr            d23, [r6, #4*2*24] // t48a
+
+        vqadd.s32       d24, d16, d17      // t32
+        vqsub.s32       d25, d16, d17      // t39
+        vqadd.s32       d26, d18, d19      // t63
+        vqsub.s32       d27, d18, d19      // t56
+        vqsub.s32       d28, d21, d20      // t40
+        vqadd.s32       d29, d21, d20      // t47
+        vqadd.s32       d30, d23, d22      // t48
+        vqsub.s32       d31, d23, d22      // t55
+
+.irp r, q12, q13, q14, q15
+        vmin.s32        \r,  \r,  q5
+.endr
+.irp r, q12, q13, q14, q15
+        vmax.s32        \r,  \r,  q4
+.endr
+
+        vmul_vmla       d4,  d27, d25, d1[1], d1[0] // -> t56a
+        vmul_vmls       d6,  d27, d25, d1[0], d1[1] // -> t39a
+        vmul_vmla       d7,  d31, d28, d1[1], d1[0] // -> t40a
+        vrshr.s32       d25, d4,  #12               // t56a
+        vrshr.s32       d27, d6,  #12               // t39a
+        vneg.s32        d7,  d7                     // t40a
+        vmul_vmls       d4,  d31, d28, d1[0], d1[1] // -> t55a
+        vrshr.s32       d31, d7,  #12               // t40a
+        vrshr.s32       d28, d4,  #12               // t55a
+
+        vqadd.s32       d16, d24, d29      // t32a
+        vqsub.s32       d19, d24, d29      // t47a
+        vqadd.s32       d17, d27, d31      // t39
+        vqsub.s32       d18, d27, d31      // t40
+        vqsub.s32       d20, d26, d30      // t48a
+        vqadd.s32       d23, d26, d30      // t63a
+        vqsub.s32       d21, d25, d28      // t55
+        vqadd.s32       d22, d25, d28      // t56
+
+.irp r, q8, q9, q10, q11
+        vmin.s32        \r,  \r,  q5
+.endr
+.irp r, q8, q9, q10, q11
+        vmax.s32        \r,  \r,  q4
+.endr
+
+        vmul_vmls       d4,  d21, d18, d0[0], d0[0] // -> t40a
+        vmul_vmla       d6,  d21, d18, d0[0], d0[0] // -> t55a
+        vmul_vmls       d7,  d20, d19, d0[0], d0[0] // -> t47
+        vrshr.s32       d18, d4,  #12               // t40a
+        vrshr.s32       d21, d6,  #12               // t55a
+        vmul_vmla       d4,  d20, d19, d0[0], d0[0] // -> t48
+        vrshr.s32       d19, d7,  #12               // t47
+        vrshr.s32       d20, d4,  #12               // t48
+
+        vstr            d16, [r6, #4*2*0]  // t32a
+        vstr            d17, [r9, #4*2*0]  // t39
+        vstr            d18, [r6, #4*2*8]  // t40a
+        vstr            d19, [r9, #4*2*8]  // t47
+        vstr            d20, [r6, #4*2*16] // t48
+        vstr            d21, [r9, #4*2*16] // t55a
+        vstr            d22, [r6, #4*2*24] // t56
+        vstr            d23, [r9, #4*2*24] // t63a
+
+        add             r6,  r6,  #4*2
+        sub             r9,  r9,  #4*2
+        cmp             r6,  r9
+        blt             1b
+        bx              lr
+endfunc
+
+.macro load8 src, strd, zero, clear
+.irp i, d16, d17, d18, d19, d20, d21, d22, d23
+.if \clear
+        vld1.32         {\i}, [\src, :64]
+        vst1.32         {\zero}, [\src, :64], \strd
+.else
+        vld1.32         {\i}, [\src, :64], \strd
+.endif
+.endr
+.endm
+
+.macro store16 dst
+        vst1.32         {q8,  q9},  [\dst, :128]!
+        vst1.32         {q10, q11}, [\dst, :128]!
+        vst1.32         {q12, q13}, [\dst, :128]!
+        vst1.32         {q14, q15}, [\dst, :128]!
+.endm
+
+.macro clear_upper8
+.irp i, q12, q13, q14, q15
+        vmov.i32        \i,  #0
+.endr
+.endm
+
+.macro vmov_if reg, val, cond
+.if \cond
+        vmov.i32        \reg, \val
+.endif
+.endm
+
+.macro movdup_if reg, gpr, val, cond
+.if \cond
+        mov_const       \gpr, \val
+        vdup.32         \reg, \gpr
+.endif
+.endm
+
+.macro vst1_if regs, dst, dstalign, cond
+.if \cond
+        vst1.32         \regs, \dst, \dstalign
+.endif
+.endm
+
+.macro scale_if cond, c, r0, r1, r2, r3, r4, r5, r6, r7
+.if \cond
+        scale_input     \c, \r0, \r1, \r2, \r3, \r4, \r5, \r6, \r7
+.endif
+.endm
+
+.macro def_dct64_func suffix, clear=0, scale=0
+function inv_txfm_dct\suffix\()_2s_x64_neon
+        mov             r6,  sp
+
+        push            {r10-r11,lr}
+
+        lsl             r8,  r8,  #2
+
+        movdup_if       d0,  r12, 2896*8*(1<<16), \scale
+        vmov_if         d7,  #0,  \clear
+        load8           r7,  r8,  d7,  \clear
+        clear_upper8
+        sub             r7,  r7,  r8, lsl #3
+        add             r7,  r7,  r8, lsr #1
+        scale_if        \scale, d0[0], q8, q9, q10, q11
+
+        bl              inv_dct_2s_x16_neon
+
+        // idct_16 leaves the row_clip_max/min constants in d9 and d8,
+        // but here we want to use full q registers for clipping.
+        vmov.i32        q3,  #0x1ffff // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vmvn.i32        q2,  #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+.irp r, q8, q9, q10, q11, q12, q13, q14, q15
+        vmin.s32        \r,  \r,  q3
+.endr
+.irp r, q8, q9, q10, q11, q12, q13, q14, q15
+        vmax.s32        \r,  \r,  q2
+.endr
+
+        store16         r6
+
+        movdup_if       d0,  r12, 2896*8*(1<<16), \scale
+        vmov_if         d7,  #0,  \clear
+        load8           r7,  r8,  d7,  \clear
+        clear_upper8
+        sub             r7,  r7,  r8, lsl #3
+        lsr             r8,  r8,  #1
+        sub             r7,  r7,  r8, lsr #1
+        scale_if        \scale, d0[0], q8, q9, q10, q11
+
+        bl              inv_dct32_odd_2s_x16_neon
+
+        add             r10, r6,  #8*15
+        sub             r6,  r6,  #8*16
+
+        mov             r9,  #-8
+
+        vmov.i32        d1,  #0x1ffff // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vmvn.i32        d0,  #0x1ffff // row_clip_min = (~bdmax << 7), 0xfffe0000
+.macro store_addsub r0, r1, r2, r3
+        vld1.32         {d2},  [r6, :64]!
+        vld1.32         {d3},  [r6, :64]!
+        vqadd.s32       d6,  d2,  \r0
+        vqsub.s32       \r0, d2,  \r0
+        vld1.32         {d4},  [r6, :64]!
+        vqadd.s32       d7,  d3,  \r1
+        vqsub.s32       \r1, d3,  \r1
+        vmin.s32        d6,  d6,  d1
+        vmin.s32        \r0, \r0, d1
+        vld1.32         {d5},  [r6, :64]!
+        vqadd.s32       d2,  d4,  \r2
+        sub             r6,  r6,  #8*4
+        vmax.s32        d6,  d6,  d0
+        vmax.s32        \r0, \r0, d0
+        vqsub.s32       \r2, d4,  \r2
+        vmin.s32        d7,  d7,  d1
+        vmin.s32        \r1, \r1, d1
+        vst1.32         {d6},  [r6,  :64]!
+        vst1.32         {\r0}, [r10, :64], r9
+        vmin.s32        d2,  d2,  d1
+        vmin.s32        \r2, \r2, d1
+        vmax.s32        d7,  d7,  d0
+        vmax.s32        \r1, \r1, d0
+        vqadd.s32       d3,  d5,  \r3
+        vqsub.s32       \r3, d5,  \r3
+        vmax.s32        d2,  d2,  d0
+        vmax.s32        \r2, \r2, d0
+        vmin.s32        d3,  d3,  d1
+        vmin.s32        \r3, \r3, d1
+        vst1.32         {d7},  [r6,  :64]!
+        vst1.32         {\r1}, [r10, :64], r9
+        vmax.s32        d3,  d3,  d0
+        vmax.s32        \r3, \r3, d0
+        vst1.32         {d2},  [r6,  :64]!
+        vst1.32         {\r2}, [r10, :64], r9
+        vst1.32         {d3},  [r6,  :64]!
+        vst1.32         {\r3}, [r10, :64], r9
+.endm
+        store_addsub    d31, d30, d29, d28
+        store_addsub    d27, d26, d25, d24
+        store_addsub    d23, d22, d21, d20
+        store_addsub    d19, d18, d17, d16
+.purgem store_addsub
+
+        add             r6,  r6,  #2*4*16
+
+        movrel_local    r12, idct64_coeffs
+        vmov.i32        q5,  #0x1ffff        // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        vmvn.i32        q4,  #0x1ffff        // row_clip_min = (~bdmax << 7), 0xfffe0000
+        movdup_if       d0,  lr,  2896*8*(1<<16), \scale
+        vmov_if         d7,  #0,  \clear
+        add             r9,  r7,  r8, lsl #4 // offset 16
+        add             r10, r7,  r8, lsl #3 // offset 8
+        sub             r9,  r9,  r8         // offset 15
+        sub             r11, r10, r8         // offset 7
+        vld1.32         {d16}, [r7,  :64]    // in1  (offset 0)
+        vld1.32         {d17}, [r9,  :64]    // in31 (offset 15)
+        vld1.32         {d18}, [r10, :64]    // in17 (offset 8)
+        vld1.32         {d19}, [r11, :64]    // in15 (offset 7)
+        vst1_if         {d7},  [r7,  :64], \clear
+        vst1_if         {d7},  [r9,  :64], \clear
+        vst1_if         {d7},  [r10, :64], \clear
+        vst1_if         {d7},  [r11, :64], \clear
+        scale_if        \scale, d0[0], q8, q9
+        bl              inv_dct64_step1_neon
+        movdup_if       d0,  lr,  2896*8*(1<<16), \scale
+        vmov_if         d7,  #0,  \clear
+        add             r7,  r7,  r8, lsl #2 // offset 4
+        sub             r9,  r9,  r8, lsl #2 // offset 11
+        sub             r10, r7,  r8         // offset 3
+        add             r11, r9,  r8         // offset 12
+        vld1.32         {d16}, [r10, :64]    // in7  (offset 3)
+        vld1.32         {d17}, [r11, :64]    // in25 (offset 12)
+        vld1.32         {d18}, [r9,  :64]    // in23 (offset 11)
+        vld1.32         {d19}, [r7,  :64]    // in9  (offset 4)
+        vst1_if         {d7},  [r7,  :64], \clear
+        vst1_if         {d7},  [r9,  :64], \clear
+        vst1_if         {d7},  [r10, :64], \clear
+        vst1_if         {d7},  [r11, :64], \clear
+        scale_if        \scale, d0[0], q8, q9
+        bl              inv_dct64_step1_neon
+        movdup_if       d0,  lr,  2896*8*(1<<16), \scale
+        vmov_if         d7,  #0,  \clear
+        sub             r10, r10, r8, lsl #1 // offset 1
+        sub             r9,  r9,  r8, lsl #1 // offset 9
+        add             r10, r10, r8         // offset 2
+        add             r9,  r9,  r8         // offset 10
+        add             r7,  r7,  r8         // offset 5
+        add             r11, r11, r8         // offset 13
+        vld1.32         d16, [r10, :64]      // in5  (offset 2)
+        vld1.32         d17, [r11, :64]      // in27 (offset 13)
+        vld1.32         d18, [r9,  :64]      // in21 (offset 10)
+        vld1.32         d19, [r7,  :64]      // in11 (offset 5)
+        vst1_if         d7,  [r10, :64], \clear
+        vst1_if         d7,  [r11, :64], \clear
+        vst1_if         d7,  [r9,  :64], \clear
+        vst1_if         d7,  [r7,  :64], \clear
+        scale_if        \scale, d0[0], q8, q9
+        bl              inv_dct64_step1_neon
+        movdup_if       d0,  lr,  2896*8*(1<<16), \scale
+        vmov_if         d7,  #0,  \clear
+        sub             r10, r10, r8         // offset 1
+        sub             r9,  r9,  r8         // offset 9
+        add             r11, r11, r8         // offset 14
+        add             r7,  r7,  r8         // offset 6
+        vld1.32         d16, [r10, :64]      // in3  (offset 1)
+        vld1.32         d17, [r11, :64]      // in29 (offset 14)
+        vld1.32         d18, [r9,  :64]      // in19 (offset 9)
+        vld1.32         d19, [r7,  :64]      // in13 (offset 6)
+        vst1_if         d7,  [r10, :64], \clear
+        vst1_if         d7,  [r11, :64], \clear
+        vst1_if         d7,  [r9,  :64], \clear
+        vst1_if         d7,  [r7,  :64], \clear
+        scale_if        \scale, d0[0], q8, q9
+        bl              inv_dct64_step1_neon
+
+        sub             r6,  r6,  #2*4*32
+        add             r9,  r6,  #2*4*7
+
+        bl              inv_dct64_step2_neon
+
+        pop             {r10-r11,pc}
+endfunc
+.endm
+
+def_dct64_func _clear, clear=1
+def_dct64_func _clear_scale, clear=1, scale=1
+
+function inv_txfm_horz_dct_64x2_neon
+        vdup.32         q4,  r9
+
+        mov             r7,  sp
+        add             r8,  sp,  #2*4*(64 - 4)
+        add             r9,  r6,  #2*56
+
+        push            {r10-r11,lr}
+
+        mov             r10, #2*64
+        mov             r11, #-2*4*4
+
+1:
+        vld1.32         {d16, d17, d18, d19}, [r7, :128]!
+        vld1.32         {d28, d29, d30, d31}, [r8, :128], r11
+        vld1.32         {d20, d21, d22, d23}, [r7, :128]!
+        vld1.32         {d24, d25, d26, d27}, [r8, :128], r11
+        vtrn.32         d16, d17
+        vtrn.32         d18, d19
+        vtrn.32         d20, d21
+        vtrn.32         d22, d23
+        vtrn.32         d31, d30
+        vtrn.32         d29, d28
+        vtrn.32         d27, d26
+        vtrn.32         d25, d24
+
+.macro store_addsub src0, src1, src2, src3, src4, src5, src6, src7
+        vqsub.s32       d7,  \src0,  \src1
+        vqsub.s32       d6,  \src2,  \src3
+        vqsub.s32       d5,  \src4,  \src5
+        vqsub.s32       d4,  \src6,  \src7
+        vqadd.s32       d0,  \src0,  \src1
+        vqadd.s32       d1,  \src2,  \src3
+        vqadd.s32       d2,  \src4,  \src5
+        vqadd.s32       d3,  \src6,  \src7
+        vrshl.s32       q3,  q3,  q4
+        vrshl.s32       q2,  q2,  q4
+        vrshl.s32       q0,  q0,  q4
+        vrshl.s32       q1,  q1,  q4
+        vqmovn.s32      d7,  q3
+        vqmovn.s32      d6,  q2
+        vqmovn.s32      d0,  q0
+        vqmovn.s32      d1,  q1
+        vrev32.16       q3,  q3
+        vst1.16         {q0},  [r6, :128], r10
+        vst1.16         {q3},  [r9, :128], r10
+.endm
+        store_addsub    d16, d31, d18, d29, d20, d27, d22, d25
+        store_addsub    d17, d30, d19, d28, d21, d26, d23, d24
+.purgem store_addsub
+        sub             r6,  r6,  r10, lsl #1
+        sub             r9,  r9,  r10, lsl #1
+        add             r6,  r6,  #16
+        sub             r9,  r9,  #16
+
+        cmp             r7,  r8
+        blt             1b
+        pop             {r10-r11,pc}
+endfunc
+
+function inv_txfm_add_vert_dct_4x64_neon
+        lsl             r8,  r8,  #1
+
+        mov             r7,  sp
+        add             r8,  sp,  #2*4*(64 - 4)
+        add             r9,  r6,  r1, lsl #6
+        sub             r9,  r9,  r1
+
+        push            {r10-r11,lr}
+
+        neg             r10, r1
+        mov             r11, #-2*4*4
+
+1:
+        vld1.16         {d16, d17, d18, d19}, [r7, :128]!
+        vld1.16         {d28, d29, d30, d31}, [r8, :128], r11
+        vld1.16         {d20, d21, d22, d23}, [r7, :128]!
+        vld1.16         {d24, d25, d26, d27}, [r8, :128], r11
+
+        vmov.i16        q6,  #0
+        vmvn.i16        q7,  #0xfc00 // 0x3ff
+.macro add_dest_addsub src0, src1, src2, src3
+        vld1.16         {d0}, [r6, :64], r1
+        vld1.16         {d1}, [r9, :64], r10
+        vqadd.s16       d4,  \src0,  \src1
+        vld1.16         {d2}, [r6, :64]
+        vqsub.s16       d5,  \src0,  \src1
+        vld1.16         {d3}, [r9, :64]
+        vqadd.s16       d6,  \src2,  \src3
+        vqsub.s16       d7,  \src2,  \src3
+        sub             r6,  r6,  r1
+        sub             r9,  r9,  r10
+        vrshr.s16       q2,  q2,  #4
+        vrshr.s16       q3,  q3,  #4
+        vqadd.s16       q2,  q2,  q0
+        vqadd.s16       q3,  q3,  q1
+        vmax.s16        q2,  q2,  q6
+        vmax.s16        q3,  q3,  q6
+        vmin.s16        q2,  q2,  q7
+        vmin.s16        q3,  q3,  q7
+        vst1.16         {d4}, [r6, :64], r1
+        vst1.16         {d5}, [r9, :64], r10
+        vst1.16         {d6}, [r6, :64], r1
+        vst1.16         {d7}, [r9, :64], r10
+.endm
+        add_dest_addsub d16, d31, d17, d30
+        add_dest_addsub d18, d29, d19, d28
+        add_dest_addsub d20, d27, d21, d26
+        add_dest_addsub d22, d25, d23, d24
+.purgem add_dest_addsub
+        cmp             r7,  r8
+        blt             1b
+
+        pop             {r10-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_64x64_16bpc_neon, export=1
+        idct_dc         64,  64,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+
+        sub_sp_align    64*32*2+64*4*2
+        add             r5,  sp,  #64*4*2
+
+        movrel_local    r10, eob_32x32
+
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+        add             r6,  r5,  #(\i*64*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #32*4
+        bl              inv_txfm_dct_clear_2s_x64_neon
+        add             r6,  r5,  #(\i*64*2)
+        mov             r9,  #-2 // shift
+        bl              inv_txfm_horz_dct_64x2_neon
+.if \i < 30
+        ldrh            r11, [r10], #2
+.endif
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 8
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
+        add             r7,  r5,  #(\i*2)
+        mov             r8,  #64*2
+        bl              X(inv_txfm_dct_4h_x64_neon)
+        add             r6,  r0,  #(\i*2)
+        bl              inv_txfm_add_vert_dct_4x64_neon
+.endr
+
+        add_sp_align    64*32*2+64*4*2
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_64x32_16bpc_neon, export=1
+        idct_dc         64,  32,  1
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+
+        sub_sp_align    64*32*2+64*4*2
+        add             r5,  sp,  #64*4*2
+
+        movrel_local    r10, eob_32x32
+
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+        add             r6,  r5,  #(\i*64*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #32*4
+        bl              inv_txfm_dct_clear_scale_2s_x64_neon
+        add             r6,  r5,  #(\i*64*2)
+        mov             r9,  #-1 // shift
+        bl              inv_txfm_horz_dct_64x2_neon
+.if \i < 30
+        ldrh            r11, [r10], #2
+.endif
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 8
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
+        add             r6,  r0,  #(\i*2)
+        add             r7,  r5,  #(\i*2)
+        mov             r8,  #64*2
+        bl              inv_txfm_add_vert_dct_4x32_neon
+.endr
+
+        add_sp_align    64*32*2+64*4*2
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_32x64_16bpc_neon, export=1
+        idct_dc         32,  64,  1
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+
+        sub_sp_align    32*32*2+64*4*2
+        add             r5,  sp,  #64*4*2
+
+        movrel_local    r10, eob_32x32
+        ldrh            r11, [r10], #2
+
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+        add             r6,  r5,  #(\i*32*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 30
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #32*4
+        bl              inv_txfm_horz_scale_dct_32x2_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 4
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             r7,  r5,  #(\i*2)
+        mov             r8,  #32*2
+        bl              X(inv_txfm_dct_4h_x64_neon)
+        add             r6,  r0,  #(\i*2)
+        bl              inv_txfm_add_vert_dct_4x64_neon
+.endr
+
+        add_sp_align    32*32*2+64*4*2
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_64x16_16bpc_neon, export=1
+        idct_dc         64,  16,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+
+        sub_sp_align    64*16*2+64*4*2
+        add             r4,  sp,  #64*4*2
+
+        movrel_local    r10, eob_16x32
+
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14
+        add             r6,  r4,  #(\i*64*2)
+.if \i > 0
+        mov             r8,  #(16 - \i)
+        cmp             r3,  r11
+        blt             1f
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #16*4
+        bl              inv_txfm_dct_clear_2s_x64_neon
+        add             r6,  r4,  #(\i*64*2)
+        mov             r9,  #-2 // shift
+        bl              inv_txfm_horz_dct_64x2_neon
+.if \i < 8
+        ldrh            r11, [r10], #2
+.endif
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 8
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+        movrel          r5,  X(inv_dct_4h_x16_neon)
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
+        add             r6,  r0,  #(\i*2)
+        add             r7,  r4,  #(\i*2)
+        mov             r8,  #64*2
+        bl              inv_txfm_add_vert_4x16_neon
+.endr
+
+        add_sp_align    64*16*2+64*4*2
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+function inv_txfm_add_dct_dct_16x64_16bpc_neon, export=1
+        idct_dc         16,  64,  2
+
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+
+        sub_sp_align    16*32*2+64*4*2
+        add             r5,  sp,  #64*4*2
+
+        movrel_local    r10, eob_16x32
+        ldrh            r11, [r10], #2
+
+        movrel_local    r4,  inv_dct_2s_x16_neon
+.irp i, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+        add             r6,  r5,  #(\i*16*2)
+.if \i > 0
+        mov             r8,  #(32 - \i)
+        cmp             r3,  r11
+        blt             1f
+.if \i < 30
+        ldrh            r11, [r10], #2
+.endif
+.endif
+        add             r7,  r2,  #(\i*4)
+        mov             r8,  #32*4
+        bl              inv_txfm_horz_16x2_neon
+.endr
+        b               3f
+
+1:
+        vmov.i16        q2,  #0
+        vmov.i16        q3,  #0
+2:
+        subs            r8,  r8,  #2
+.rept 2
+        vst1.16         {q2, q3}, [r6, :128]!
+.endr
+        bgt             2b
+
+3:
+.irp i, 0, 4, 8, 12
+        add             r7,  r5,  #(\i*2)
+        mov             r8,  #16*2
+        bl              X(inv_txfm_dct_4h_x64_neon)
+        add             r6,  r0,  #(\i*2)
+        bl              inv_txfm_add_vert_dct_4x64_neon
+.endr
+
+        add_sp_align    16*32*2+64*4*2
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/loopfilter.S b/media/libdav1d/src/src/arm/32/loopfilter.S
new file mode 100644
index 0000000000..97b960534f
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/loopfilter.S
@@ -0,0 +1,868 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+.macro loop_filter wd
+function lpf_8_wd\wd\()_neon
+        vabd.u8         d0,  d22, d23 // abs(p1 - p0)
+        vabd.u8         d1,  d25, d24 // abs(q1 - q0)
+        vabd.u8         d2,  d23, d24 // abs(p0 - q0)
+        vabd.u8         d3,  d22, d25 // abs(p1 - q1)
+.if \wd >= 6
+        vabd.u8         d4,  d21, d22 // abs(p2 - p1)
+        vabd.u8         d5,  d26, d25 // abs(q2 - q1)
+.endif
+.if \wd >= 8
+        vabd.u8         d6,  d20, d21 // abs(p3 - p2)
+        vabd.u8         d7,  d27, d26 // abs(q3 - q3)
+.endif
+.if \wd >= 6
+        vmax.u8         d4,  d4,  d5
+.endif
+        vqadd.u8        d2,  d2,  d2  // abs(p0 - q0) * 2
+.if \wd >= 8
+        vmax.u8         d6,  d6,  d7
+.endif
+        vshr.u8         d3,  d3,  #1
+.if \wd >= 8
+        vmax.u8         d4,  d4,  d6
+.endif
+.if \wd >= 6
+        vand            d4,  d4,  d14
+.endif
+        vmax.u8         d0,  d0,  d1  // max(abs(p1 - p0), abs(q1 - q0))
+        vqadd.u8        d2,  d2,  d3  // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
+.if \wd >= 6
+        vmax.u8         d4,  d0,  d4
+        vcge.u8         d1,  d11, d4  // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
+.else
+        vcge.u8         d1,  d11, d0  // max(abs(p1 - p0), abs(q1 - q0)) <= I
+.endif
+        vcge.u8         d2,  d10, d2  // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
+        vand            d1,  d1,  d2  // fm
+        vand            d1,  d1,  d13 // fm && wd >= 4
+.if \wd >= 6
+        vand            d14, d14, d1  // fm && wd > 4
+.endif
+.if \wd >= 16
+        vand            d15, d15, d1  // fm && wd == 16
+.endif
+
+        vmov            r10, r11, d1
+        orrs            r10, r10, r11
+        beq             9f            // if (!fm || wd < 4) return;
+
+.if \wd >= 6
+        vmov.i8         d10, #1
+        vabd.u8         d2,  d21, d23 // abs(p2 - p0)
+        vabd.u8         d3,  d22, d23 // abs(p1 - p0)
+        vabd.u8         d4,  d25, d24 // abs(q1 - q0)
+        vabd.u8         d5,  d26, d24 // abs(q2 - q0)
+.if \wd >= 8
+        vabd.u8         d6,  d20, d23 // abs(p3 - p0)
+        vabd.u8         d7,  d27, d24 // abs(q3 - q0)
+.endif
+        vmax.u8         d2,  d2,  d3
+        vmax.u8         d4,  d4,  d5
+.if \wd >= 8
+        vmax.u8         d6,  d6,  d7
+.endif
+        vmax.u8         d2,  d2,  d4
+.if \wd >= 8
+        vmax.u8         d2,  d2,  d6
+.endif
+
+.if \wd == 16
+        vabd.u8         d3,  d17, d23 // abs(p6 - p0)
+        vabd.u8         d4,  d18, d23 // abs(p5 - p0)
+        vabd.u8         d5,  d19, d23 // abs(p4 - p0)
+.endif
+        vcge.u8         d2,  d10, d2  // flat8in
+.if \wd == 16
+        vabd.u8         d6,  d28, d24 // abs(q4 - q0)
+        vabd.u8         d7,  d29, d24 // abs(q5 - q0)
+        vabd.u8         d8,  d30, d24 // abs(q6 - q0)
+.endif
+        vand            d14, d2,  d14 // flat8in && fm && wd > 4
+        vbic            d1,  d1,  d14 // fm && wd >= 4 && !flat8in
+.if \wd == 16
+        vmax.u8         d3,  d3,  d4
+        vmax.u8         d5,  d5,  d6
+.endif
+        vmov            r10, r11, d1
+.if \wd == 16
+        vmax.u8         d7,  d7,  d8
+        vmax.u8         d3,  d3,  d5
+        vmax.u8         d3,  d3,  d7
+        vcge.u8         d3,  d10, d3  // flat8out
+.endif
+        orrs            r10, r10, r11
+.if \wd == 16
+        vand            d15, d15, d3  // flat8out && fm && wd == 16
+        vand            d15, d15, d14 // flat8out && flat8in && fm && wd == 16
+        vbic            d14, d14, d15 // flat8in && fm && wd >= 4 && !flat8out
+.endif
+        beq             1f            // skip wd == 4 case
+.endif
+
+        vsubl.u8        q1,  d22, d25 // p1 - q1
+        vcgt.u8         d0,  d0,  d12 // hev
+        vqmovn.s16      d2,  q1
+        vand            d4,  d2,  d0  // if (hev) iclip_diff(p1 - q1)
+        vbic            d0,  d1,  d0  // (fm && wd >= 4 && !hev)
+        vsubl.u8        q1,  d24, d23
+        vmov.i16        q3,  #3
+        vmul.i16        q1,  q1,  q3
+        vmov.i8         d6,  #4
+        vaddw.s8        q1,  q1,  d4
+        vmov.i8         d7,  #3
+        vqmovn.s16      d2,  q1       // f
+        vqadd.s8        d4,  d6,  d2  // imin(f + 4, 127)
+        vqadd.s8        d5,  d7,  d2  // imin(f + 3, 127)
+        vshr.s8         d4,  d4,  #3  // f1
+        vshr.s8         d5,  d5,  #3  // f2
+        vmovl.u8        q1,  d23      // p0
+        vmovl.u8        q3,  d24      // q0
+        vaddw.s8        q1,  q1,  d5
+        vsubw.s8        q3,  q3,  d4
+        vrshr.s8        d4,  d4,  #1  // (f1 + 1) >> 1
+        vqmovun.s16     d2,  q1       // out p0
+        vqmovun.s16     d6,  q3       // out q0
+        vbit            d23, d2,  d1  // if (fm && wd >= 4)
+        vmovl.u8        q1,  d22      // p1
+        vbit            d24, d6,  d1  // if (fm && wd >= 4)
+        vmovl.u8        q3,  d25      // q1
+        vaddw.s8        q1,  q1,  d4
+        vsubw.s8        q3,  q3,  d4
+        vqmovun.s16     d2,  q1       // out p1
+        vqmovun.s16     d6,  q3       // out q1
+        vbit            d22, d2,  d0  // if (fm && wd >= 4 && !hev)
+        vbit            d25, d6,  d0  // if (fm && wd >= 4 && !hev)
+1:
+
+.if \wd == 6
+        vmov            r10, r11, d14
+        orrs            r10, r10, r11
+        beq             2f            // skip if there's no flat8in
+
+        vaddl.u8        q0,  d21, d21 // p2 * 2
+        vaddl.u8        q1,  d21, d22 // p2 + p1
+        vaddl.u8        q2,  d22, d23 // p1 + p0
+        vaddl.u8        q3,  d23, d24 // p0 + q0
+        vadd.i16        q4,  q0,  q1
+        vadd.i16        q5,  q2,  q3
+        vaddl.u8        q6,  d24, d25 // q0 + q1
+        vadd.i16        q4,  q4,  q5
+        vsub.i16        q6,  q6,  q0
+        vaddl.u8        q5,  d25, d26 // q1 + q2
+        vrshrn.i16      d0,  q4,  #3  // out p1
+
+        vadd.i16        q4,  q4,  q6
+        vsub.i16        q5,  q5,  q1
+        vaddl.u8        q6,  d26, d26 // q2 + q2
+        vrshrn.i16      d1,  q4,  #3  // out p0
+
+        vadd.i16        q4,  q4,  q5
+        vsub.i16        q6,  q6,  q2
+        vrshrn.i16      d2,  q4,  #3  // out q0
+
+        vbit            d22, d0,  d14 // p1 if (flat8in)
+        vadd.i16        q4,  q4,  q6
+        vbit            d23, d1,  d14 // p0 if (flat8in)
+        vrshrn.i16      d3,  q4,  #3  // out q1
+        vbit            d24, d2,  d14 // q0 if (flat8in)
+        vbit            d25, d3,  d14 // q1 if (flat8in)
+.elseif \wd >= 8
+        vmov            r10, r11, d14
+        orrs            r10, r10, r11
+.if \wd == 8
+        beq             8f            // skip if there's no flat8in
+.else
+        beq             2f            // skip if there's no flat8in
+.endif
+
+        vaddl.u8        q0,  d20, d21 // p3 + p2
+        vaddl.u8        q1,  d22, d25 // p1 + q1
+        vaddl.u8        q2,  d20, d22 // p3 + p1
+        vaddl.u8        q3,  d23, d26 // p0 + q2
+        vadd.i16        q4,  q0,  q0  // 2 * (p3 + p2)
+        vaddw.u8        q4,  q4,  d23 // + p0
+        vaddw.u8        q4,  q4,  d24 // + q0
+        vadd.i16        q4,  q4,  q2  // + p3 + p1
+        vsub.i16        q1,  q1,  q0  // p1 + q1 - p3 - p2
+        vsub.i16        q3,  q3,  q2  // p0 + q2 - p3 - p1
+        vrshrn.i16      d10, q4,  #3  // out p2
+
+        vadd.i16        q4,  q4,  q1
+        vaddl.u8        q0,  d20, d23 // p3 + p0
+        vaddl.u8        q1,  d24, d27 // q0 + q3
+        vrshrn.i16      d11, q4,  #3  // out p1
+
+        vadd.i16        q4,  q4,  q3
+        vsub.i16        q1,  q1,  q0  // q0 + q3 - p3 - p0
+        vaddl.u8        q2,  d21, d24 // p2 + q0
+        vaddl.u8        q3,  d25, d27 // q1 + q3
+        vrshrn.i16      d12, q4,  #3  // out p0
+
+        vadd.i16        q4,  q4,  q1
+        vsub.i16        q3,  q3,  q2  // q1 + q3 - p2 - q0
+        vaddl.u8        q0,  d22, d25 // p1 + q1
+        vaddl.u8        q1,  d26, d27 // q2 + q3
+        vrshrn.i16      d13, q4,  #3  // out q0
+
+        vadd.i16        q4,  q4,  q3
+        vsub.i16        q1,  q1,  q0  // q2 + q3 - p1 - q1
+        vrshrn.i16      d0,  q4,  #3  // out q1
+
+        vadd.i16        q4,  q4,  q1
+
+        vbit            d21, d10, d14
+        vbit            d22, d11, d14
+        vbit            d23, d12, d14
+        vrshrn.i16      d1,  q4,  #3  // out q2
+        vbit            d24, d13, d14
+        vbit            d25, d0,  d14
+        vbit            d26, d1,  d14
+.endif
+2:
+.if \wd == 16
+        vmov            r10, r11, d15
+        orrs            r10, r10, r11
+        bne             1f            // check if flat8out is needed
+        vmov            r10, r11, d14
+        orrs            r10, r10, r11
+        beq             8f            // if there was no flat8in, just write the inner 4 pixels
+        b               7f            // if flat8in was used, write the inner 6 pixels
+1:
+
+        vaddl.u8        q1,  d17, d17 // p6 + p6
+        vaddl.u8        q2,  d17, d18 // p6 + p5
+        vaddl.u8        q3,  d17, d19 // p6 + p4
+        vaddl.u8        q4,  d17, d20 // p6 + p3
+        vadd.i16        q6,  q1,  q2
+        vadd.i16        q5,  q3,  q4
+        vaddl.u8        q3,  d17, d21 // p6 + p2
+        vadd.i16        q6,  q6,  q5
+        vaddl.u8        q4,  d17, d22 // p6 + p1
+        vaddl.u8        q5,  d18, d23 // p5 + p0
+        vadd.i16        q3,  q3,  q4
+        vaddl.u8        q4,  d19, d24 // p4 + q0
+        vadd.i16        q6,  q6,  q3
+        vadd.i16        q5,  q5,  q4
+        vaddl.u8        q3,  d20, d25 // p3 + q1
+        vadd.i16        q6,  q6,  q5
+        vsub.i16        q3,  q3,  q1
+        vaddl.u8        q1,  d21, d26 // p2 + q2
+        vrshrn.i16      d0,  q6,  #4  // out p5
+        vadd.i16        q6,  q6,  q3  // - (p6 + p6) + (p3 + q1)
+        vsub.i16        q1,  q1,  q2
+        vaddl.u8        q2,  d22, d27 // p1 + q3
+        vaddl.u8        q3,  d17, d19 // p6 + p4
+        vrshrn.i16      d1,  q6,  #4  // out p4
+        vadd.i16        q6,  q6,  q1  // - (p6 + p5) + (p2 + q2)
+        vsub.i16        q2,  q2,  q3
+        vaddl.u8        q3,  d23, d28 // p0 + q4
+        vaddl.u8        q4,  d17, d20 // p6 + p3
+        vrshrn.i16      d2,  q6,  #4  // out p3
+        vadd.i16        q6,  q6,  q2  // - (p6 + p4) + (p1 + q3)
+        vsub.i16        q3,  q3,  q4
+        vaddl.u8        q4,  d24, d29 // q0 + q5
+        vaddl.u8        q2,  d17, d21 // p6 + p2
+        vrshrn.i16      d3,  q6,  #4  // out p2
+        vadd.i16        q6,  q6,  q3  // - (p6 + p3) + (p0 + q4)
+        vsub.i16        q4,  q4,  q2
+        vaddl.u8        q3,  d25, d30 // q1 + q6
+        vaddl.u8        q5,  d17, d22 // p6 + p1
+        vrshrn.i16      d4,  q6,  #4  // out p1
+        vadd.i16        q6,  q6,  q4  // - (p6 + p2) + (q0 + q5)
+        vsub.i16        q3,  q3,  q5
+        vaddl.u8        q4,  d26, d30 // q2 + q6
+        vbif            d0,  d18, d15 // out p5
+        vaddl.u8        q5,  d18, d23 // p5 + p0
+        vrshrn.i16      d5,  q6,  #4  // out p0
+        vadd.i16        q6,  q6,  q3  // - (p6 + p1) + (q1 + q6)
+        vsub.i16        q4,  q4,  q5
+        vaddl.u8        q5,  d27, d30 // q3 + q6
+        vbif            d1,  d19, d15 // out p4
+        vaddl.u8        q9,  d19, d24 // p4 + q0
+        vrshrn.i16      d6,  q6,  #4  // out q0
+        vadd.i16        q6,  q6,  q4  // - (p5 + p0) + (q2 + q6)
+        vsub.i16        q5,  q5,  q9
+        vaddl.u8        q4,  d28, d30 // q4 + q6
+        vbif            d2,  d20, d15 // out p3
+        vaddl.u8        q9,  d20, d25 // p3 + q1
+        vrshrn.i16      d7,  q6,  #4  // out q1
+        vadd.i16        q6,  q6,  q5  // - (p4 + q0) + (q3 + q6)
+        vsub.i16        q9,  q4,  q9
+        vaddl.u8        q5,  d29, d30 // q5 + q6
+        vbif            d3,  d21, d15 // out p2
+        vaddl.u8        q10, d21, d26 // p2 + q2
+        vrshrn.i16      d8,  q6,  #4  // out q2
+        vadd.i16        q6,  q6,  q9  // - (p3 + q1) + (q4 + q6)
+        vsub.i16        q5,  q5,  q10
+        vaddl.u8        q9,  d30, d30 // q6 + q6
+        vbif            d4,  d22, d15 // out p1
+        vaddl.u8        q10, d22, d27 // p1 + q3
+        vrshrn.i16      d9,  q6,  #4  // out q3
+        vadd.i16        q6,  q6,  q5  // - (p2 + q2) + (q5 + q6)
+        vsub.i16        q9,  q9,  q10
+        vbif            d5,  d23, d15 // out p0
+        vrshrn.i16      d10, q6,  #4  // out q4
+        vadd.i16        q6,  q6,  q9  // - (p1 + q3) + (q6 + q6)
+        vrshrn.i16      d11, q6,  #4  // out q5
+        vbif            d6,  d24, d15 // out q0
+        vbif            d7,  d25, d15 // out q1
+        vbif            d8,  d26, d15 // out q2
+        vbif            d9,  d27, d15 // out q3
+        vbif            d10, d28, d15 // out q4
+        vbif            d11, d29, d15 // out q5
+.endif
+
+        bx              lr
+.if \wd == 16
+7:
+        // Return to a shorter epilogue, writing only the inner 6 pixels
+        bx              r8
+.endif
+.if \wd >= 8
+8:
+        // Return to a shorter epilogue, writing only the inner 4 pixels
+        bx              r9
+.endif
+9:
+        // Return directly without writing back any pixels
+        bx              r12
+endfunc
+.endm
+
+loop_filter 16
+loop_filter 8
+loop_filter 6
+loop_filter 4
+
+.macro lpf_8_wd16
+        adr             r8,  7f + CONFIG_THUMB
+        adr             r9,  8f + CONFIG_THUMB
+        bl              lpf_8_wd16_neon
+.endm
+
+.macro lpf_8_wd8
+        adr             r9,  8f + CONFIG_THUMB
+        bl              lpf_8_wd8_neon
+.endm
+
+.macro lpf_8_wd6
+        bl              lpf_8_wd6_neon
+.endm
+
+.macro lpf_8_wd4
+        bl              lpf_8_wd4_neon
+.endm
+
+function lpf_v_4_8_neon
+        mov             r12, lr
+        sub             r10, r0,  r1, lsl #1
+        vld1.8          {d22}, [r10, :64], r1 // p1
+        vld1.8          {d24}, [r0,  :64], r1 // q0
+        vld1.8          {d23}, [r10, :64], r1 // p0
+        vld1.8          {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+
+        lpf_8_wd4
+
+        sub             r10, r0,  r1, lsl #1
+        vst1.8          {d22}, [r10, :64], r1 // p1
+        vst1.8          {d24}, [r0,  :64], r1 // q0
+        vst1.8          {d23}, [r10, :64], r1 // p0
+        vst1.8          {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+endfunc
+
+function lpf_h_4_8_neon
+        mov             r12, lr
+        sub             r10, r0,  #2
+        add             r0,  r10, r1, lsl #2
+        vld1.32         {d22[0]}, [r10], r1
+        vld1.32         {d22[1]}, [r0],  r1
+        vld1.32         {d23[0]}, [r10], r1
+        vld1.32         {d23[1]}, [r0],  r1
+        vld1.32         {d24[0]}, [r10], r1
+        vld1.32         {d24[1]}, [r0],  r1
+        vld1.32         {d25[0]}, [r10], r1
+        vld1.32         {d25[1]}, [r0],  r1
+        add             r0,  r0,  #2
+
+        transpose_4x8b  q11, q12, d22, d23, d24, d25
+
+        lpf_8_wd4
+
+        sub             r10, r0,  r1, lsl #3
+        sub             r10, r10, #2
+        transpose_4x8b  q11, q12, d22, d23, d24, d25
+        add             r0,  r10, r1, lsl #2
+
+        vst1.32         {d22[0]}, [r10], r1
+        vst1.32         {d22[1]}, [r0],  r1
+        vst1.32         {d23[0]}, [r10], r1
+        vst1.32         {d23[1]}, [r0],  r1
+        vst1.32         {d24[0]}, [r10], r1
+        vst1.32         {d24[1]}, [r0],  r1
+        vst1.32         {d25[0]}, [r10], r1
+        vst1.32         {d25[1]}, [r0],  r1
+        add             r0,  r0,  #2
+        bx              r12
+endfunc
+
+function lpf_v_6_8_neon
+        mov             r12, lr
+        sub             r10, r0,  r1, lsl #1
+        sub             r10, r10, r1
+        vld1.8          {d21}, [r10, :64], r1 // p2
+        vld1.8          {d24}, [r0,  :64], r1 // q0
+        vld1.8          {d22}, [r10, :64], r1 // p1
+        vld1.8          {d25}, [r0,  :64], r1 // q1
+        vld1.8          {d23}, [r10, :64], r1 // p0
+        vld1.8          {d26}, [r0,  :64], r1 // q2
+        sub             r0,  r0,  r1, lsl #1
+        sub             r0,  r0,  r1
+
+        lpf_8_wd6
+
+        sub             r10, r0,  r1, lsl #1
+        vst1.8          {d22}, [r10, :64], r1 // p1
+        vst1.8          {d24}, [r0,  :64], r1 // q0
+        vst1.8          {d23}, [r10, :64], r1 // p0
+        vst1.8          {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+endfunc
+
+function lpf_h_6_8_neon
+        mov             r12, lr
+        sub             r10, r0,  #4
+        add             r0,  r10, r1, lsl #2
+        vld1.8          {d20}, [r10], r1
+        vld1.8          {d24}, [r0],  r1
+        vld1.8          {d21}, [r10], r1
+        vld1.8          {d25}, [r0],  r1
+        vld1.8          {d22}, [r10], r1
+        vld1.8          {d26}, [r0],  r1
+        vld1.8          {d23}, [r10], r1
+        vld1.8          {d27}, [r0],  r1
+        add             r0,  r0,  #4
+
+        transpose_8x8b  q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
+
+        lpf_8_wd6
+
+        sub             r10, r0,  r1, lsl #3
+        sub             r10, r10, #2
+        transpose_4x8b  q11, q12, d22, d23, d24, d25
+        add             r0,  r10, r1, lsl #2
+
+        vst1.32         {d22[0]}, [r10], r1
+        vst1.32         {d22[1]}, [r0],  r1
+        vst1.32         {d23[0]}, [r10], r1
+        vst1.32         {d23[1]}, [r0],  r1
+        vst1.32         {d24[0]}, [r10], r1
+        vst1.32         {d24[1]}, [r0],  r1
+        vst1.32         {d25[0]}, [r10], r1
+        vst1.32         {d25[1]}, [r0],  r1
+        add             r0,  r0,  #2
+        bx              r12
+endfunc
+
+function lpf_v_8_8_neon
+        mov             r12, lr
+        sub             r10, r0,  r1, lsl #2
+        vld1.8          {d20}, [r10, :64], r1 // p3
+        vld1.8          {d24}, [r0,  :64], r1 // q0
+        vld1.8          {d21}, [r10, :64], r1 // p2
+        vld1.8          {d25}, [r0,  :64], r1 // q1
+        vld1.8          {d22}, [r10, :64], r1 // p1
+        vld1.8          {d26}, [r0,  :64], r1 // q2
+        vld1.8          {d23}, [r10, :64], r1 // p0
+        vld1.8          {d27}, [r0,  :64], r1 // q3
+        sub             r0,  r0,  r1, lsl #2
+
+        lpf_8_wd8
+
+        sub             r10, r0,  r1, lsl #1
+        sub             r10, r10, r1
+        vst1.8          {d21}, [r10, :64], r1 // p2
+        vst1.8          {d24}, [r0,  :64], r1 // q0
+        vst1.8          {d22}, [r10, :64], r1 // p1
+        vst1.8          {d25}, [r0,  :64], r1 // q1
+        vst1.8          {d23}, [r10, :64], r1 // p0
+        vst1.8          {d26}, [r0,  :64], r1 // q2
+        sub             r0,  r0,  r1, lsl #1
+        sub             r0,  r0,  r1
+        bx              r12
+
+8:
+        sub             r10, r0,  r1, lsl #1
+        vst1.8          {d22}, [r10, :64], r1 // p1
+        vst1.8          {d24}, [r0,  :64], r1 // q0
+        vst1.8          {d23}, [r10, :64], r1 // p0
+        vst1.8          {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+endfunc
+
+function lpf_h_8_8_neon
+        mov             r12, lr
+        sub             r10, r0,  #4
+        add             r0,  r10, r1, lsl #2
+        vld1.8          {d20}, [r10], r1
+        vld1.8          {d24}, [r0],  r1
+        vld1.8          {d21}, [r10], r1
+        vld1.8          {d25}, [r0],  r1
+        vld1.8          {d22}, [r10], r1
+        vld1.8          {d26}, [r0],  r1
+        vld1.8          {d23}, [r10], r1
+        vld1.8          {d27}, [r0],  r1
+        add             r0,  r0,  #4
+
+        transpose_8x8b  q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
+
+        lpf_8_wd8
+
+        sub             r10, r0,  r1, lsl #3
+        sub             r10, r10, #4
+        transpose_8x8b  q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
+        add             r0,  r10, r1, lsl #2
+
+        vst1.8          {d20}, [r10], r1
+        vst1.8          {d24}, [r0],  r1
+        vst1.8          {d21}, [r10], r1
+        vst1.8          {d25}, [r0],  r1
+        vst1.8          {d22}, [r10], r1
+        vst1.8          {d26}, [r0],  r1
+        vst1.8          {d23}, [r10], r1
+        vst1.8          {d27}, [r0],  r1
+        add             r0,  r0,  #4
+        bx              r12
+8:
+        sub             r10, r0,  r1, lsl #3
+        sub             r10, r10, #2
+        transpose_4x8b  q11, q12, d22, d23, d24, d25
+        add             r0,  r10, r1, lsl #2
+
+        vst1.32         {d22[0]}, [r10], r1
+        vst1.32         {d22[1]}, [r0],  r1
+        vst1.32         {d23[0]}, [r10], r1
+        vst1.32         {d23[1]}, [r0],  r1
+        vst1.32         {d24[0]}, [r10], r1
+        vst1.32         {d24[1]}, [r0],  r1
+        vst1.32         {d25[0]}, [r10], r1
+        vst1.32         {d25[1]}, [r0],  r1
+        add             r0,  r0,  #2
+        bx              r12
+endfunc
+
+function lpf_v_16_8_neon
+        mov             r12, lr
+
+        sub             r10, r0,  r1, lsl #3
+        add             r10, r10, r1
+        vld1.8          {d17}, [r10, :64], r1 // p6
+        vld1.8          {d24}, [r0,  :64], r1 // q0
+        vld1.8          {d18}, [r10, :64], r1 // p5
+        vld1.8          {d25}, [r0,  :64], r1 // q1
+        vld1.8          {d19}, [r10, :64], r1 // p4
+        vld1.8          {d26}, [r0,  :64], r1 // q2
+        vld1.8          {d20}, [r10, :64], r1 // p3
+        vld1.8          {d27}, [r0,  :64], r1 // q3
+        vld1.8          {d21}, [r10, :64], r1 // p2
+        vld1.8          {d28}, [r0,  :64], r1 // q4
+        vld1.8          {d22}, [r10, :64], r1 // p1
+        vld1.8          {d29}, [r0,  :64], r1 // q5
+        vld1.8          {d23}, [r10, :64], r1 // p0
+        vld1.8          {d30}, [r0,  :64], r1 // q6
+        sub             r0,  r0,  r1, lsl #3
+        add             r0,  r0,  r1
+
+        lpf_8_wd16
+
+        sub             r10, r0,  r1, lsl #2
+        sub             r10, r10, r1, lsl #1
+        vst1.8          {d0},  [r10, :64], r1 // p5
+        vst1.8          {d6},  [r0,  :64], r1 // q0
+        vst1.8          {d1},  [r10, :64], r1 // p4
+        vst1.8          {d7},  [r0,  :64], r1 // q1
+        vst1.8          {d2},  [r10, :64], r1 // p3
+        vst1.8          {d8},  [r0,  :64], r1 // q2
+        vst1.8          {d3},  [r10, :64], r1 // p2
+        vst1.8          {d9},  [r0,  :64], r1 // q3
+        vst1.8          {d4},  [r10, :64], r1 // p1
+        vst1.8          {d10}, [r0,  :64], r1 // q4
+        vst1.8          {d5},  [r10, :64], r1 // p0
+        vst1.8          {d11}, [r0,  :64], r1 // q5
+        sub             r0,  r0,  r1, lsl #2
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+7:
+        sub             r10, r0,  r1
+        sub             r10, r10, r1, lsl #1
+        vst1.8          {d21}, [r10, :64], r1 // p2
+        vst1.8          {d24}, [r0,  :64], r1 // q0
+        vst1.8          {d22}, [r10, :64], r1 // p1
+        vst1.8          {d25}, [r0,  :64], r1 // q1
+        vst1.8          {d23}, [r10, :64], r1 // p0
+        vst1.8          {d26}, [r0,  :64], r1 // q2
+        sub             r0,  r0,  r1, lsl #1
+        sub             r0,  r0,  r1
+        bx              r12
+
+8:
+        sub             r10, r0,  r1, lsl #1
+        vst1.8          {d22}, [r10, :64], r1 // p1
+        vst1.8          {d24}, [r0,  :64], r1 // q0
+        vst1.8          {d23}, [r10, :64], r1 // p0
+        vst1.8          {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+endfunc
+
+function lpf_h_16_8_neon
+        mov             r12, lr
+        sub             r10, r0,  #8
+        vld1.8          {d16}, [r10, :64], r1
+        vld1.8          {d24}, [r0,  :64], r1
+        vld1.8          {d17}, [r10, :64], r1
+        vld1.8          {d25}, [r0,  :64], r1
+        vld1.8          {d18}, [r10, :64], r1
+        vld1.8          {d26}, [r0,  :64], r1
+        vld1.8          {d19}, [r10, :64], r1
+        vld1.8          {d27}, [r0,  :64], r1
+        vld1.8          {d20}, [r10, :64], r1
+        vld1.8          {d28}, [r0,  :64], r1
+        vld1.8          {d21}, [r10, :64], r1
+        vld1.8          {d29}, [r0,  :64], r1
+        vld1.8          {d22}, [r10, :64], r1
+        vld1.8          {d30}, [r0,  :64], r1
+        vld1.8          {d23}, [r10, :64], r1
+        vld1.8          {d31}, [r0,  :64], r1
+
+        transpose_8x8b  q8,  q9,  q10, q11, d16, d17, d18, d19, d20, d21, d22, d23
+        transpose_8x8b  q12, q13, q14, q15, d24, d25, d26, d27, d28, d29, d30, d31
+
+        lpf_8_wd16
+
+        sub             r0,  r0,  r1, lsl #3
+        sub             r10, r0,  #8
+
+        transpose_8x8b  q8,  q0,  q1,  q2,  d16, d17, d0,  d1,  d2,  d3,  d4,  d5
+        transpose_8x8b  q3,  q4,  q5,  q15, d6,  d7,  d8,  d9,  d10, d11, d30, d31
+
+        vst1.8          {d16}, [r10, :64], r1
+        vst1.8          {d6},  [r0,  :64], r1
+        vst1.8          {d17}, [r10, :64], r1
+        vst1.8          {d7},  [r0,  :64], r1
+        vst1.8          {d0},  [r10, :64], r1
+        vst1.8          {d8},  [r0,  :64], r1
+        vst1.8          {d1},  [r10, :64], r1
+        vst1.8          {d9},  [r0,  :64], r1
+        vst1.8          {d2},  [r10, :64], r1
+        vst1.8          {d10}, [r0,  :64], r1
+        vst1.8          {d3},  [r10, :64], r1
+        vst1.8          {d11}, [r0,  :64], r1
+        vst1.8          {d4},  [r10, :64], r1
+        vst1.8          {d30}, [r0,  :64], r1
+        vst1.8          {d5},  [r10, :64], r1
+        vst1.8          {d31}, [r0,  :64], r1
+        bx              r12
+
+7:
+        sub             r10, r0,  r1, lsl #3
+        sub             r10, r10, #4
+        transpose_8x8b  q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
+        add             r0,  r10, r1, lsl #2
+
+        vst1.8          {d20}, [r10], r1
+        vst1.8          {d24}, [r0],  r1
+        vst1.8          {d21}, [r10], r1
+        vst1.8          {d25}, [r0],  r1
+        vst1.8          {d22}, [r10], r1
+        vst1.8          {d26}, [r0],  r1
+        vst1.8          {d23}, [r10], r1
+        vst1.8          {d27}, [r0],  r1
+        add             r0,  r0,  #4
+        bx              r12
+8:
+        sub             r10, r0,  r1, lsl #3
+        sub             r10, r10, #2
+        transpose_4x8b  q11, q12, d22, d23, d24, d25
+        add             r0,  r10, r1, lsl #2
+
+        vst1.32         {d22[0]}, [r10], r1
+        vst1.32         {d22[1]}, [r0],  r1
+        vst1.32         {d23[0]}, [r10], r1
+        vst1.32         {d23[1]}, [r0],  r1
+        vst1.32         {d24[0]}, [r10], r1
+        vst1.32         {d24[1]}, [r0],  r1
+        vst1.32         {d25[0]}, [r10], r1
+        vst1.32         {d25[1]}, [r0],  r1
+        add             r0,  r0,  #2
+        bx              r12
+endfunc
+
+// void dav1d_lpf_v_sb_y_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                 const uint32_t *const vmask,
+//                                 const uint8_t (*l)[4], ptrdiff_t b4_stride,
+//                                 const Av1FilterLUT *lut, const int w)
+
+.macro lpf_func dir, type
+function lpf_\dir\()_sb_\type\()_8bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]
+        ldrd            r6,  r7,  [r2] // vmask[0], vmask[1]
+.ifc \type, y
+        ldr             r2,  [r2, #8]  // vmask[2]
+.endif
+        add             r5,  r5,  #128 // Move to sharp part of lut
+.ifc \type, y
+        orr             r7,  r7,  r2   // vmask[1] |= vmask[2]
+.endif
+.ifc \dir, v
+        sub             r4,  r3,  r4, lsl #2
+.else
+        sub             r3,  r3,  #4
+        lsl             r4,  r4,  #2
+.endif
+        orr             r6,  r6,  r7   // vmask[0] |= vmask[1]
+
+1:
+        tst             r6,  #0x03
+.ifc \dir, v
+        vld1.8          {d0}, [r4]!
+        vld1.8          {d1}, [r3]!
+.else
+        vld2.32         {d0[0], d1[0]}, [r3], r4
+        vld2.32         {d0[1], d1[1]}, [r3], r4
+.endif
+        beq             7f             // if (!(vm & bits)) continue;
+
+        vld1.8          {d5[]}, [r5]   // sharp[0]
+        add             r5,  r5,  #8
+        vmov.i32        d2,  #0xff
+        vdup.32         d13, r6        // vmask[0]
+
+        vand            d0,  d0,  d2   // Keep only lowest byte in each 32 bit word
+        vand            d1,  d1,  d2
+        vtst.8          d3,  d1,  d2   // Check for nonzero values in l[0][0]
+        vmov.i8         d4,  #1
+        vld1.8          {d6[]}, [r5]   // sharp[1]
+        sub             r5,  r5,  #8
+        vbif            d1,  d0,  d3   // if (!l[0][0]) L = l[offset][0]
+        vtst.32         d2,  d1,  d2   // L != 0
+        vmul.i32        d1,  d1,  d4   // L
+.ifc \type, y
+        vdup.32         d15, r2        // vmask[2]
+.endif
+        vdup.32         d14, r7        // vmask[1]
+        vmov            r10, r11, d2
+        orrs            r10, r10, r11
+        beq             7f             // if (!L) continue;
+        vneg.s8         d5,  d5        // -sharp[0]
+        movrel_local    r10, word_12
+        vshr.u8         d12, d1,  #4   // H
+        vld1.32         {d16}, [r10, :64]
+        vshl.s8         d3,  d1,  d5   // L >> sharp[0]
+.ifc \type, y
+        vtst.32         d15, d15, d16  // if (vmask[2] & bits)
+.endif
+        vmov.i8         d7,  #2
+        vmin.u8         d3,  d3,  d6   // imin(L >> sharp[0], sharp[1])
+        vadd.i8         d0,  d1,  d7   // L + 2
+        vmax.u8         d11, d3,  d4   // imax(imin(), 1) = limit = I
+        vadd.u8         d0,  d0,  d0   // 2*(L + 2)
+        vtst.32         d14, d14, d16  // if (vmask[1] & bits)
+        vadd.i8         d10, d0,  d11  // 2*(L + 2) + limit = E
+        vtst.32         d13, d13, d16  // if (vmask[0] & bits)
+        vand            d13, d13, d2   // vmask[0] &= L != 0
+
+.ifc \type, y
+        tst             r2,  #0x03
+        beq             2f
+        // wd16
+        bl              lpf_\dir\()_16_8_neon
+        b               8f
+2:
+.endif
+        tst             r7,  #0x03
+        beq             3f
+.ifc \type, y
+        // wd8
+        bl              lpf_\dir\()_8_8_neon
+.else
+        // wd6
+        bl              lpf_\dir\()_6_8_neon
+.endif
+        b               8f
+3:
+        // wd4
+        bl              lpf_\dir\()_4_8_neon
+.ifc \dir, h
+        b               8f
+7:
+        // For dir h, the functions above increment r0.
+        // If the whole function is skipped, increment it here instead.
+        add             r0,  r0,  r1,  lsl #3
+.else
+7:
+.endif
+8:
+        lsrs            r6,  r6,  #2   // vmask[0] >>= 2
+        lsr             r7,  r7,  #2   // vmask[1] >>= 2
+.ifc \type, y
+        lsr             r2,  r2,  #2   // vmask[2] >>= 2
+.endif
+.ifc \dir, v
+        add             r0,  r0,  #8
+.else
+        // For dir h, r0 is returned incremented
+.endif
+        bne             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+lpf_func v, y
+lpf_func h, y
+lpf_func v, uv
+lpf_func h, uv
+
+const word_12, align=4
+        .word 1, 2
+endconst
diff --git a/media/libdav1d/src/src/arm/32/loopfilter16.S b/media/libdav1d/src/src/arm/32/loopfilter16.S
new file mode 100644
index 0000000000..d7daf21f1a
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/loopfilter16.S
@@ -0,0 +1,859 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+.macro loop_filter wd
+function lpf_4_wd\wd\()_neon
+        vabd.u16        d0,  d22, d23 // abs(p1 - p0)
+        vabd.u16        d1,  d25, d24 // abs(q1 - q0)
+        vabd.u16        d2,  d23, d24 // abs(p0 - q0)
+        vabd.u16        d3,  d22, d25 // abs(p1 - q1)
+.if \wd >= 6
+        vabd.u16        d4,  d21, d22 // abs(p2 - p1)
+        vabd.u16        d5,  d26, d25 // abs(q2 - q1)
+.endif
+.if \wd >= 8
+        vabd.u16        d6,  d20, d21 // abs(p3 - p2)
+        vabd.u16        d7,  d27, d26 // abs(q3 - q3)
+.endif
+.if \wd >= 6
+        vmax.u16        d4,  d4,  d5
+.endif
+        vqadd.u16       d2,  d2,  d2  // abs(p0 - q0) * 2
+.if \wd >= 8
+        vmax.u16        d6,  d6,  d7
+.endif
+        vshr.u16        d3,  d3,  #1
+.if \wd >= 8
+        vmax.u16        d4,  d4,  d6
+.endif
+        vmax.u16        d0,  d0,  d1  // max(abs(p1 - p0), abs(q1 - q0))
+        vqadd.u16       d2,  d2,  d3  // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
+.if \wd >= 6
+        vmax.u16        d4,  d0,  d4
+        vcge.u16        d1,  d11, d4  // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
+.else
+        vcge.u16        d1,  d11, d0  // max(abs(p1 - p0), abs(q1 - q0)) <= I
+.endif
+        vcge.u16        d2,  d10, d2  // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
+        vand            d1,  d1,  d2  // fm && wd >= 4 (implicit)
+.if \wd >= 6
+        vmov            d14, d1       // fm && wd > 4 (implicit)
+.endif
+.if \wd >= 16
+        vmov            d15, d1       // fm && wd == 16 (implicit)
+.endif
+
+        vmov            r10, r11, d1
+        orrs            r10, r10, r11
+        beq             9f            // if (!fm || wd < 4) return;
+
+.if \wd >= 6
+        vmov.i16        d10, #1
+        vabd.u16        d2,  d21, d23 // abs(p2 - p0)
+        vabd.u16        d3,  d22, d23 // abs(p1 - p0)
+        vabd.u16        d4,  d25, d24 // abs(q1 - q0)
+        vabd.u16        d5,  d26, d24 // abs(q2 - q0)
+        vdup.16         d9,  r9       // bitdepth_min_8
+.if \wd >= 8
+        vabd.u16        d6,  d20, d23 // abs(p3 - p0)
+        vabd.u16        d7,  d27, d24 // abs(q3 - q0)
+.endif
+        vmax.u16        d2,  d2,  d3
+        vmax.u16        d4,  d4,  d5
+.if \wd >= 8
+        vmax.u16        d6,  d6,  d7
+.endif
+        vmax.u16        d2,  d2,  d4
+        vshl.u16        d10, d10, d9  // F = 1 << bitdepth_min_8
+.if \wd >= 8
+        vmax.u16        d2,  d2,  d6
+.endif
+
+.if \wd == 16
+        vabd.u16        d3,  d17, d23 // abs(p6 - p0)
+        vabd.u16        d4,  d18, d23 // abs(p5 - p0)
+        vabd.u16        d5,  d19, d23 // abs(p4 - p0)
+.endif
+        vcge.u16        d2,  d10, d2  // flat8in
+.if \wd == 16
+        vabd.u16        d6,  d28, d24 // abs(q4 - q0)
+        vabd.u16        d7,  d29, d24 // abs(q5 - q0)
+        vabd.u16        d8,  d30, d24 // abs(q6 - q0)
+.endif
+        vand            d14, d2,  d14 // flat8in && fm && wd > 4
+        vbic            d1,  d1,  d14 // fm && wd >= 4 && !flat8in
+.if \wd == 16
+        vmax.u16        d3,  d3,  d4
+        vmax.u16        d5,  d5,  d6
+.endif
+        vmov            r10, r11, d1
+.if \wd == 16
+        vmax.u16        d7,  d7,  d8
+        vmax.u16        d3,  d3,  d5
+        vmax.u16        d3,  d3,  d7
+        vcge.u16        d3,  d10, d3  // flat8out
+.endif
+        orrs            r10, r10, r11
+.if \wd == 16
+        vand            d15, d15, d3  // flat8out && fm && wd == 16
+        vand            d15, d15, d14 // flat8out && flat8in && fm && wd == 16
+        vbic            d14, d14, d15 // flat8in && fm && wd >= 4 && !flat8out
+.endif
+        beq             1f            // skip wd == 4 case
+.endif
+
+        vdup.16         d3,  r8       // bitdepth_max
+        vsub.u16        d2,  d22, d25 // p1 - q1
+        vshr.u16        d3,  d3,  #1  // 128 << bitdepth_min_8 - 1
+        vcgt.u16        d0,  d0,  d12 // hev
+        vmvn            d9,  d3       // - 128 * (1 << bitdepth_min_8)
+        vmin.s16        d2,  d2,  d3  // iclip_diff(p1 - q1)
+        vmax.s16        d2,  d2,  d9  // iclip_diff(p1 - q1)
+        vand            d4,  d2,  d0  // if (hev) iclip_diff(p1 - q1)
+        vsub.u16        d2,  d24, d23
+        vmov.i16        d6,  #3
+        vbic            d0,  d1,  d0  // (fm && wd >= 4 && !hev)
+        vmul.i16        d2,  d2,  d6
+        vmov.i16        d7,  #4
+        vadd.i16        d2,  d2,  d4
+        vmin.s16        d2,  d2,  d3  // f = iclip_diff()
+        vmax.s16        d2,  d2,  d9  // f = iclip_diff()
+        vqadd.s16       d4,  d7,  d2  // f + 4
+        vqadd.s16       d5,  d6,  d2  // f + 3
+        vmin.s16        d4,  d4,  d3  // imin(f + 4, 128 << bitdepth_min_8 - 1)
+        vmin.s16        d5,  d5,  d3  // imin(f + 3, 128 << bitdepth_min_8 - 1)
+        vshr.s16        d4,  d4,  #3  // f1
+        vshr.s16        d5,  d5,  #3  // f2
+        vmov.i16        d9,  #0
+        vdup.16         d3,  r8       // bitdepth_max
+        vqadd.s16       d2,  d23, d5  // p0 + f2
+        vqsub.s16       d6,  d24, d4  // q0 - f1
+        vrshr.s16       d4,  d4,  #1  // (f1 + 1) >> 1
+        vmin.s16        d2,  d2,  d3  // out p0 = iclip_pixel()
+        vmin.s16        d6,  d6,  d3  // out q0 = iclip_pixel()
+        vmax.s16        d2,  d2,  d9  // out p0 = iclip_pixel()
+        vmax.s16        d6,  d6,  d9  // out q0 = iclip_pixel()
+        vbit            d23, d2,  d1  // if (fm && wd >= 4)
+        vbit            d24, d6,  d1  // if (fm && wd >= 4)
+        vqadd.s16       d2,  d22, d4  // p1 + f
+        vqsub.s16       d6,  d25, d4  // q1 - f
+        vmin.s16        d2,  d2,  d3  // out p1 = iclip_pixel()
+        vmin.s16        d6,  d6,  d3  // out q1 = iclip_pixel()
+        vmax.s16        d2,  d2,  d9  // out p1 = iclip_pixel()
+        vmax.s16        d6,  d6,  d9  // out q1 = iclip_pixel()
+        vbit            d22, d2,  d0  // if (fm && wd >= 4 && !hev)
+        vbit            d25, d6,  d0  // if (fm && wd >= 4 && !hev)
+1:
+
+.if \wd == 6
+        vmov            r10, r11, d14
+        orrs            r10, r10, r11
+        beq             2f            // skip if there's no flat8in
+
+        vadd.i16        d0,  d21, d21 // p2 * 2
+        vadd.i16        d2,  d21, d22 // p2 + p1
+        vadd.i16        d4,  d22, d23 // p1 + p0
+        vadd.i16        d6,  d23, d24 // p0 + q0
+        vadd.i16        d8,  d0,  d2
+        vadd.i16        d10, d4,  d6
+        vadd.i16        d12, d24, d25 // q0 + q1
+        vadd.i16        d8,  d8,  d10
+        vsub.i16        d12, d12, d0
+        vadd.i16        d10, d25, d26 // q1 + q2
+        vrshr.u16       d0,  d8,  #3  // out p1
+
+        vadd.i16        d8,  d8,  d12
+        vsub.i16        d10, d10, d2
+        vadd.i16        d12, d26, d26 // q2 + q2
+        vrshr.u16       d1,  d8,  #3  // out p0
+
+        vadd.i16        d8,  d8,  d10
+        vsub.i16        d12, d12, d4
+        vrshr.u16       d2,  d8,  #3  // out q0
+
+        vbit            d22, d0,  d14 // p1 if (flat8in)
+        vadd.i16        d8,  d8,  d12
+        vbit            d23, d1,  d14 // p0 if (flat8in)
+        vrshr.u16       d3,  d8,  #3  // out q1
+        vbit            d24, d2,  d14 // q0 if (flat8in)
+        vbit            d25, d3,  d14 // q1 if (flat8in)
+.elseif \wd >= 8
+        vmov            r10, r11, d14
+        orrs            r10, r10, r11
+.if \wd == 8
+        beq             8f            // skip if there's no flat8in
+.else
+        beq             2f            // skip if there's no flat8in
+.endif
+
+        vadd.i16        d0,  d20, d21 // p3 + p2
+        vadd.i16        d2,  d22, d25 // p1 + q1
+        vadd.i16        d4,  d20, d22 // p3 + p1
+        vadd.i16        d6,  d23, d26 // p0 + q2
+        vadd.i16        d8,  d0,  d0  // 2 * (p3 + p2)
+        vadd.i16        d9,  d23, d24 // p0 + q0
+        vadd.i16        d8,  d8,  d4  // + p3 + p1
+        vsub.i16        d2,  d2,  d0  // p1 + q1 - p3 - p2
+        vadd.i16        d8,  d8,  d9  // + p0 + q0
+        vsub.i16        d6,  d6,  d4  // p0 + q2 - p3 - p1
+        vrshr.u16       d10, d8,  #3  // out p2
+
+        vadd.i16        d8,  d8,  d2
+        vadd.i16        d0,  d20, d23 // p3 + p0
+        vadd.i16        d2,  d24, d27 // q0 + q3
+        vrshr.u16       d11, d8,  #3  // out p1
+
+        vadd.i16        d8,  d8,  d6
+        vsub.i16        d2,  d2,  d0  // q0 + q3 - p3 - p0
+        vadd.i16        d4,  d21, d24 // p2 + q0
+        vadd.i16        d6,  d25, d27 // q1 + q3
+        vrshr.u16       d12, d8,  #3  // out p0
+
+        vadd.i16        d8,  d8,  d2
+        vsub.i16        d6,  d6,  d4  // q1 + q3 - p2 - q0
+        vadd.i16        d0,  d22, d25 // p1 + q1
+        vadd.i16        d2,  d26, d27 // q2 + q3
+        vrshr.u16       d13, d8,  #3  // out q0
+
+        vadd.i16        d8,  d8,  d6
+        vsub.i16        d2,  d2,  d0  // q2 + q3 - p1 - q1
+        vrshr.u16       d0,  d8,  #3  // out q1
+
+        vadd.i16        d8,  d8,  d2
+
+        vbit            d21, d10, d14
+        vbit            d22, d11, d14
+        vbit            d23, d12, d14
+        vrshr.u16       d1,  d8,  #3  // out q2
+        vbit            d24, d13, d14
+        vbit            d25, d0,  d14
+        vbit            d26, d1,  d14
+.endif
+2:
+.if \wd == 16
+        vmov            r10, r11, d15
+        orrs            r10, r10, r11
+        bne             1f            // check if flat8out is needed
+        vmov            r10, r11, d14
+        orrs            r10, r10, r11
+        beq             8f            // if there was no flat8in, just write the inner 4 pixels
+        b               7f            // if flat8in was used, write the inner 6 pixels
+1:
+
+        vadd.i16        d2,  d17, d17 // p6 + p6
+        vadd.i16        d4,  d17, d18 // p6 + p5
+        vadd.i16        d6,  d17, d19 // p6 + p4
+        vadd.i16        d8,  d17, d20 // p6 + p3
+        vadd.i16        d12, d2,  d4
+        vadd.i16        d10, d6,  d8
+        vadd.i16        d6,  d17, d21 // p6 + p2
+        vadd.i16        d12, d12, d10
+        vadd.i16        d8,  d17, d22 // p6 + p1
+        vadd.i16        d10, d18, d23 // p5 + p0
+        vadd.i16        d6,  d6,  d8
+        vadd.i16        d8,  d19, d24 // p4 + q0
+        vadd.i16        d12, d12, d6
+        vadd.i16        d10, d10, d8
+        vadd.i16        d6,  d20, d25 // p3 + q1
+        vadd.i16        d12, d12, d10
+        vsub.i16        d6,  d6,  d2
+        vadd.i16        d2,  d21, d26 // p2 + q2
+        vrshr.u16       d0,  d12, #4  // out p5
+        vadd.i16        d12, d12, d6  // - (p6 + p6) + (p3 + q1)
+        vsub.i16        d2,  d2,  d4
+        vadd.i16        d4,  d22, d27 // p1 + q3
+        vadd.i16        d6,  d17, d19 // p6 + p4
+        vrshr.u16       d1,  d12, #4  // out p4
+        vadd.i16        d12, d12, d2  // - (p6 + p5) + (p2 + q2)
+        vsub.i16        d4,  d4,  d6
+        vadd.i16        d6,  d23, d28 // p0 + q4
+        vadd.i16        d8,  d17, d20 // p6 + p3
+        vrshr.u16       d2,  d12, #4  // out p3
+        vadd.i16        d12, d12, d4  // - (p6 + p4) + (p1 + q3)
+        vsub.i16        d6,  d6,  d8
+        vadd.i16        d8,  d24, d29 // q0 + q5
+        vadd.i16        d4,  d17, d21 // p6 + p2
+        vrshr.u16       d3,  d12, #4  // out p2
+        vadd.i16        d12, d12, d6  // - (p6 + p3) + (p0 + q4)
+        vsub.i16        d8,  d8,  d4
+        vadd.i16        d6,  d25, d30 // q1 + q6
+        vadd.i16        d10, d17, d22 // p6 + p1
+        vrshr.u16       d4,  d12, #4  // out p1
+        vadd.i16        d12, d12, d8  // - (p6 + p2) + (q0 + q5)
+        vsub.i16        d6,  d6,  d10
+        vadd.i16        d8,  d26, d30 // q2 + q6
+        vbif            d0,  d18, d15 // out p5
+        vadd.i16        d10, d18, d23 // p5 + p0
+        vrshr.u16       d5,  d12, #4  // out p0
+        vadd.i16        d12, d12, d6  // - (p6 + p1) + (q1 + q6)
+        vsub.i16        d8,  d8,  d10
+        vadd.i16        d10, d27, d30 // q3 + q6
+        vbif            d1,  d19, d15 // out p4
+        vadd.i16        d18, d19, d24 // p4 + q0
+        vrshr.u16       d6,  d12, #4  // out q0
+        vadd.i16        d12, d12, d8  // - (p5 + p0) + (q2 + q6)
+        vsub.i16        d10, d10, d18
+        vadd.i16        d8,  d28, d30 // q4 + q6
+        vbif            d2,  d20, d15 // out p3
+        vadd.i16        d18, d20, d25 // p3 + q1
+        vrshr.u16       d7,  d12, #4  // out q1
+        vadd.i16        d12, d12, d10 // - (p4 + q0) + (q3 + q6)
+        vsub.i16        d18, d8,  d18
+        vadd.i16        d10, d29, d30 // q5 + q6
+        vbif            d3,  d21, d15 // out p2
+        vadd.i16        d20, d21, d26 // p2 + q2
+        vrshr.u16       d8,  d12, #4  // out q2
+        vadd.i16        d12, d12, d18 // - (p3 + q1) + (q4 + q6)
+        vsub.i16        d10, d10, d20
+        vadd.i16        d18, d30, d30 // q6 + q6
+        vbif            d4,  d22, d15 // out p1
+        vadd.i16        d20, d22, d27 // p1 + q3
+        vrshr.u16       d9,  d12, #4  // out q3
+        vadd.i16        d12, d12, d10 // - (p2 + q2) + (q5 + q6)
+        vsub.i16        d18, d18, d20
+        vbif            d5,  d23, d15 // out p0
+        vrshr.u16       d10, d12, #4  // out q4
+        vadd.i16        d12, d12, d18 // - (p1 + q3) + (q6 + q6)
+        vrshr.u16       d11, d12, #4  // out q5
+        vbif            d6,  d24, d15 // out q0
+        vbif            d7,  d25, d15 // out q1
+        vbif            d8,  d26, d15 // out q2
+        vbif            d9,  d27, d15 // out q3
+        vbif            d10, d28, d15 // out q4
+        vbif            d11, d29, d15 // out q5
+.endif
+
+        bx              lr
+.if \wd == 16
+7:
+        // Return to a shorter epilogue, writing only the inner 6 pixels
+        bx              r6
+.endif
+.if \wd >= 8
+8:
+        // Return to a shorter epilogue, writing only the inner 4 pixels
+        bx              r7
+.endif
+9:
+        // Return directly without writing back any pixels
+        bx              r12
+endfunc
+.endm
+
+loop_filter 16
+loop_filter 8
+loop_filter 6
+loop_filter 4
+
+.macro lpf_4_wd16
+        adr             r6,  7f + CONFIG_THUMB
+        adr             r7,  8f + CONFIG_THUMB
+        bl              lpf_4_wd16_neon
+.endm
+
+.macro lpf_4_wd8
+        adr             r7,  8f + CONFIG_THUMB
+        bl              lpf_4_wd8_neon
+.endm
+
+.macro lpf_4_wd6
+        bl              lpf_4_wd6_neon
+.endm
+
+.macro lpf_4_wd4
+        bl              lpf_4_wd4_neon
+.endm
+
+function lpf_v_4_4_neon
+        mov             r12, lr
+        sub             r10, r0,  r1, lsl #1
+        vld1.16         {d22}, [r10, :64], r1 // p1
+        vld1.16         {d24}, [r0,  :64], r1 // q0
+        vld1.16         {d23}, [r10, :64], r1 // p0
+        vld1.16         {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+
+        lpf_4_wd4
+
+        sub             r10, r0,  r1, lsl #1
+        vst1.16         {d22}, [r10, :64], r1 // p1
+        vst1.16         {d24}, [r0,  :64], r1 // q0
+        vst1.16         {d23}, [r10, :64], r1 // p0
+        vst1.16         {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+endfunc
+
+function lpf_h_4_4_neon
+        mov             r12, lr
+        sub             r10, r0,  #4
+        add             r0,  r10, r1, lsl #1
+        vld1.16         {d22}, [r10], r1
+        vld1.16         {d24}, [r0],  r1
+        vld1.16         {d23}, [r10], r1
+        vld1.16         {d25}, [r0],  r1
+        add             r0,  r0,  #4
+
+        transpose_4x4h  q11, q12, d22, d23, d24, d25
+
+        lpf_4_wd4
+
+        sub             r10, r0,  r1, lsl #2
+        sub             r10, r10, #4
+        transpose_4x4h  q11, q12, d22, d23, d24, d25
+        add             r0,  r10, r1, lsl #1
+
+        vst1.16         {d22}, [r10], r1
+        vst1.16         {d24}, [r0],  r1
+        vst1.16         {d23}, [r10], r1
+        vst1.16         {d25}, [r0],  r1
+        add             r0,  r0,  #4
+        bx              r12
+endfunc
+
+function lpf_v_6_4_neon
+        mov             r12, lr
+        sub             r10, r0,  r1, lsl #1
+        sub             r10, r10, r1
+        vld1.16         {d21}, [r10, :64], r1 // p2
+        vld1.16         {d24}, [r0,  :64], r1 // q0
+        vld1.16         {d22}, [r10, :64], r1 // p1
+        vld1.16         {d25}, [r0,  :64], r1 // q1
+        vld1.16         {d23}, [r10, :64], r1 // p0
+        vld1.16         {d26}, [r0,  :64], r1 // q2
+        sub             r0,  r0,  r1, lsl #1
+        sub             r0,  r0,  r1
+
+        lpf_4_wd6
+
+        sub             r10, r0,  r1, lsl #1
+        vst1.16         {d22}, [r10, :64], r1 // p1
+        vst1.16         {d24}, [r0,  :64], r1 // q0
+        vst1.16         {d23}, [r10, :64], r1 // p0
+        vst1.16         {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+endfunc
+
+function lpf_h_6_4_neon
+        mov             r12, lr
+        sub             r10, r0,  #8
+        vld1.16         {d20}, [r10, :64], r1
+        vld1.16         {d24}, [r0,  :64], r1
+        vld1.16         {d21}, [r10, :64], r1
+        vld1.16         {d25}, [r0,  :64], r1
+        vld1.16         {d22}, [r10, :64], r1
+        vld1.16         {d26}, [r0,  :64], r1
+        vld1.16         {d23}, [r10, :64], r1
+        vld1.16         {d27}, [r0,  :64], r1
+
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+
+        lpf_4_wd6
+
+        sub             r0,  r0,  #4
+        transpose_4x4h  q11, q12, d22, d23, d24, d25
+        sub             r10, r0,  r1, lsl #2
+        sub             r0,  r0,  r1, lsl #1
+
+        vst1.16         {d22}, [r10], r1
+        vst1.16         {d24}, [r0],  r1
+        vst1.16         {d23}, [r10], r1
+        vst1.16         {d25}, [r0],  r1
+        add             r0,  r0,  #4
+        bx              r12
+endfunc
+
+function lpf_v_8_4_neon
+        mov             r12, lr
+        sub             r10, r0,  r1, lsl #2
+        vld1.16         {d20}, [r10, :64], r1 // p3
+        vld1.16         {d24}, [r0,  :64], r1 // q0
+        vld1.16         {d21}, [r10, :64], r1 // p2
+        vld1.16         {d25}, [r0,  :64], r1 // q1
+        vld1.16         {d22}, [r10, :64], r1 // p1
+        vld1.16         {d26}, [r0,  :64], r1 // q2
+        vld1.16         {d23}, [r10, :64], r1 // p0
+        vld1.16         {d27}, [r0,  :64], r1 // q3
+        sub             r0,  r0,  r1, lsl #2
+
+        lpf_4_wd8
+
+        sub             r10, r0,  r1, lsl #1
+        sub             r10, r10, r1
+        vst1.16         {d21}, [r10, :64], r1 // p2
+        vst1.16         {d24}, [r0,  :64], r1 // q0
+        vst1.16         {d22}, [r10, :64], r1 // p1
+        vst1.16         {d25}, [r0,  :64], r1 // q1
+        vst1.16         {d23}, [r10, :64], r1 // p0
+        vst1.16         {d26}, [r0,  :64], r1 // q2
+        sub             r0,  r0,  r1, lsl #1
+        sub             r0,  r0,  r1
+        bx              r12
+
+8:
+        sub             r10, r0,  r1, lsl #1
+        vst1.16         {d22}, [r10, :64], r1 // p1
+        vst1.16         {d24}, [r0,  :64], r1 // q0
+        vst1.16         {d23}, [r10, :64], r1 // p0
+        vst1.16         {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+endfunc
+
+function lpf_h_8_4_neon
+        mov             r12, lr
+        sub             r10, r0,  #8
+        vld1.16         {d20}, [r10, :64], r1
+        vld1.16         {d24}, [r0,  :64], r1
+        vld1.16         {d21}, [r10, :64], r1
+        vld1.16         {d25}, [r0,  :64], r1
+        vld1.16         {d22}, [r10, :64], r1
+        vld1.16         {d26}, [r0,  :64], r1
+        vld1.16         {d23}, [r10, :64], r1
+        vld1.16         {d27}, [r0,  :64], r1
+
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+
+        lpf_4_wd8
+
+        sub             r0,  r0,  r1, lsl #2
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+        sub             r10, r0,  #8
+
+        vst1.16         {d20}, [r10, :64], r1
+        vst1.16         {d24}, [r0,  :64], r1
+        vst1.16         {d21}, [r10, :64], r1
+        vst1.16         {d25}, [r0,  :64], r1
+        vst1.16         {d22}, [r10, :64], r1
+        vst1.16         {d26}, [r0,  :64], r1
+        vst1.16         {d23}, [r10, :64], r1
+        vst1.16         {d27}, [r0,  :64], r1
+        bx              r12
+8:
+        sub             r0,  r0,  #4
+        transpose_4x4h  q11, q12, d22, d23, d24, d25
+        sub             r10, r0,  r1, lsl #2
+        sub             r0,  r0,  r1, lsl #1
+
+        vst1.16         {d22}, [r10], r1
+        vst1.16         {d24}, [r0],  r1
+        vst1.16         {d23}, [r10], r1
+        vst1.16         {d25}, [r0],  r1
+        add             r0,  r0,  #4
+        bx              r12
+endfunc
+
+function lpf_v_16_4_neon
+        mov             r12, lr
+
+        sub             r10, r0,  r1, lsl #3
+        add             r10, r10, r1
+        vld1.16         {d17}, [r10, :64], r1 // p6
+        vld1.16         {d24}, [r0,  :64], r1 // q0
+        vld1.16         {d18}, [r10, :64], r1 // p5
+        vld1.16         {d25}, [r0,  :64], r1 // q1
+        vld1.16         {d19}, [r10, :64], r1 // p4
+        vld1.16         {d26}, [r0,  :64], r1 // q2
+        vld1.16         {d20}, [r10, :64], r1 // p3
+        vld1.16         {d27}, [r0,  :64], r1 // q3
+        vld1.16         {d21}, [r10, :64], r1 // p2
+        vld1.16         {d28}, [r0,  :64], r1 // q4
+        vld1.16         {d22}, [r10, :64], r1 // p1
+        vld1.16         {d29}, [r0,  :64], r1 // q5
+        vld1.16         {d23}, [r10, :64], r1 // p0
+        vld1.16         {d30}, [r0,  :64], r1 // q6
+        sub             r0,  r0,  r1, lsl #3
+        add             r0,  r0,  r1
+
+        lpf_4_wd16
+
+        sub             r10, r0,  r1, lsl #2
+        sub             r10, r10, r1, lsl #1
+        vst1.16         {d0},  [r10, :64], r1 // p5
+        vst1.16         {d6},  [r0,  :64], r1 // q0
+        vst1.16         {d1},  [r10, :64], r1 // p4
+        vst1.16         {d7},  [r0,  :64], r1 // q1
+        vst1.16         {d2},  [r10, :64], r1 // p3
+        vst1.16         {d8},  [r0,  :64], r1 // q2
+        vst1.16         {d3},  [r10, :64], r1 // p2
+        vst1.16         {d9},  [r0,  :64], r1 // q3
+        vst1.16         {d4},  [r10, :64], r1 // p1
+        vst1.16         {d10}, [r0,  :64], r1 // q4
+        vst1.16         {d5},  [r10, :64], r1 // p0
+        vst1.16         {d11}, [r0,  :64], r1 // q5
+        sub             r0,  r0,  r1, lsl #2
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+7:
+        sub             r10, r0,  r1
+        sub             r10, r10, r1, lsl #1
+        vst1.16         {d21}, [r10, :64], r1 // p2
+        vst1.16         {d24}, [r0,  :64], r1 // q0
+        vst1.16         {d22}, [r10, :64], r1 // p1
+        vst1.16         {d25}, [r0,  :64], r1 // q1
+        vst1.16         {d23}, [r10, :64], r1 // p0
+        vst1.16         {d26}, [r0,  :64], r1 // q2
+        sub             r0,  r0,  r1, lsl #1
+        sub             r0,  r0,  r1
+        bx              r12
+
+8:
+        sub             r10, r0,  r1, lsl #1
+        vst1.16         {d22}, [r10, :64], r1 // p1
+        vst1.16         {d24}, [r0,  :64], r1 // q0
+        vst1.16         {d23}, [r10, :64], r1 // p0
+        vst1.16         {d25}, [r0,  :64], r1 // q1
+        sub             r0,  r0,  r1, lsl #1
+        bx              r12
+endfunc
+
+function lpf_h_16_4_neon
+        mov             r12, lr
+        sub             r10, r0,  #16
+        sub             r0,  r0,  #8
+        vld1.16         {d16}, [r10, :64], r1
+        vld1.16         {d20}, [r0,  :64], r1
+        vld1.16         {d17}, [r10, :64], r1
+        vld1.16         {d21}, [r0,  :64], r1
+        vld1.16         {d18}, [r10, :64], r1
+        vld1.16         {d22}, [r0,  :64], r1
+        vld1.16         {d19}, [r10, :64], r1
+        vld1.16         {d23}, [r0,  :64], r1
+        sub             r10, r10, r1, lsl #2
+        sub             r0,  r0,  r1, lsl #2
+        add             r10, r10, #16
+        add             r0,  r0,  #16
+        vld1.16         {d24}, [r10, :64], r1
+        vld1.16         {d28}, [r0,  :64], r1
+        vld1.16         {d25}, [r10, :64], r1
+        vld1.16         {d29}, [r0,  :64], r1
+        vld1.16         {d26}, [r10, :64], r1
+        vld1.16         {d30}, [r0,  :64], r1
+        vld1.16         {d27}, [r10, :64], r1
+        vld1.16         {d31}, [r0,  :64], r1
+        sub             r0,  r0,  #8
+
+        transpose_4x4h  q8,  q9,  d16, d17, d18, d19
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+        transpose_4x4h  q14, q15, d28, d29, d30, d31
+
+        lpf_4_wd16
+
+        sub             r0,  r0,  r1, lsl #2
+        transpose_4x4h  q8,  q0,  d16, d17, d0,  d1
+        transpose_4x4h  q1,  q2,  d2,  d3,  d4,  d5
+        transpose_4x4h  q3,  q4,  d6,  d7,  d8,  d9
+        transpose_4x4h  q5,  q15, d10, d11, d30, d31
+        sub             r10, r0,  #16
+        sub             r0,  r0,  #8
+
+        vst1.16         {d16}, [r10, :64], r1
+        vst1.16         {d2},  [r0,  :64], r1
+        vst1.16         {d17}, [r10, :64], r1
+        vst1.16         {d3},  [r0,  :64], r1
+        vst1.16         {d0},  [r10, :64], r1
+        vst1.16         {d4},  [r0,  :64], r1
+        vst1.16         {d1},  [r10, :64], r1
+        vst1.16         {d5},  [r0,  :64], r1
+        sub             r10, r10, r1, lsl #2
+        sub             r0,  r0,  r1, lsl #2
+        add             r10, r10, #16
+        add             r0,  r0,  #16
+        vst1.16         {d6},  [r10, :64], r1
+        vst1.16         {d10}, [r0,  :64], r1
+        vst1.16         {d7},  [r10, :64], r1
+        vst1.16         {d11}, [r0,  :64], r1
+        vst1.16         {d8},  [r10, :64], r1
+        vst1.16         {d30}, [r0,  :64], r1
+        vst1.16         {d9},  [r10, :64], r1
+        vst1.16         {d31}, [r0,  :64], r1
+        sub             r0,  r0,  #8
+
+        bx              r12
+
+7:
+        sub             r0,  r0,  r1, lsl #2
+        transpose_4x4h  q10, q11, d20, d21, d22, d23
+        transpose_4x4h  q12, q13, d24, d25, d26, d27
+        sub             r10, r0,  #8
+
+        vst1.16         {d20}, [r10, :64], r1
+        vst1.16         {d24}, [r0,  :64], r1
+        vst1.16         {d21}, [r10, :64], r1
+        vst1.16         {d25}, [r0,  :64], r1
+        vst1.16         {d22}, [r10, :64], r1
+        vst1.16         {d26}, [r0,  :64], r1
+        vst1.16         {d23}, [r10, :64], r1
+        vst1.16         {d27}, [r0,  :64], r1
+        bx              r12
+8:
+        sub             r0,  r0,  #4
+        transpose_4x4h  q11, q12, d22, d23, d24, d25
+        sub             r10, r0,  r1, lsl #2
+        sub             r0,  r0,  r1, lsl #1
+
+        vst1.16         {d22}, [r10], r1
+        vst1.16         {d24}, [r0],  r1
+        vst1.16         {d23}, [r10], r1
+        vst1.16         {d25}, [r0],  r1
+        add             r0,  r0,  #4
+        bx              r12
+endfunc
+
+// void dav1d_lpf_v_sb_y_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                  const uint32_t *const vmask,
+//                                  const uint8_t (*l)[4], ptrdiff_t b4_stride,
+//                                  const Av1FilterLUT *lut, const int w,
+//                                  const int bitdepth_max)
+
+.macro lpf_func dir, type
+function lpf_\dir\()_sb_\type\()_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]
+        ldr             r8,  [sp,  #112] // bitdepth_max; the 'w' parameter isn't loaded
+        sub             sp,  sp,  #8
+        clz             r9,  r8
+        rsb             r9,  r9,  #24  // bitdepth_min_8
+        ldrd            r6,  r7,  [r2] // vmask[0], vmask[1]
+.ifc \type, y
+        ldr             r2,  [r2, #8]  // vmask[2]
+.endif
+        add             r5,  r5,  #128 // Move to sharp part of lut
+.ifc \type, y
+        orr             r7,  r7,  r2   // vmask[1] |= vmask[2]
+.endif
+.ifc \dir, v
+        sub             r4,  r3,  r4, lsl #2
+.else
+        sub             r3,  r3,  #4
+        lsl             r4,  r4,  #2
+.endif
+        orr             r6,  r6,  r7   // vmask[0] |= vmask[1]
+
+1:
+        tst             r6,  #0x01
+        strd            r6,  r7,  [sp]
+.ifc \dir, v
+        ldrb            r10, [r4], #4
+        ldrb            r11, [r3], #4
+.else
+        ldrb            r10, [r3]
+        ldrb            r11, [r3, #4]
+        add             r3,  r3,  r4
+.endif
+        beq             7f             // if (!(vm & bits)) continue;
+
+        orrs            r12, r10, r11
+        vdup.16         d31, r9        // bitdepth_min_8
+        beq             7f             // if (!(l[0][0] | l[offset][0])) continue;
+        cmp             r11, #0        // Check for nonzero values in l[0][0]
+        ldrb            r6,  [r5], #8  // sharp[0]
+        it              eq
+        moveq           r11, r10       // if (!l[0][0]) L = l[offset][0]
+        ldrb            r12, [r5]      // sharp[1]
+        lsr             r6,  r11, r6   // L >> sharp[0]
+        sub             r5,  r5,  #8
+        cmp             r12, r6
+        lsr             r10, r11, #4   // H
+        add             r11, r11, #2   // L + 2
+        it              lt
+        movlt           r6,  r12       // imin(L >> sharp[0], sharp[1])
+        add             r11, r11, r11  // 2*(L + 2)
+        cmp             r6,  #1
+        lsl             r10, r10, r9   // H << bitdepth_min_8
+        it              lt
+        movlt           r6,  #1        // imax(imin(), 1) = limit = I
+        vdup.16         d12, r10       // H << bitdepth_min_8
+        add             r11, r11, r6   // 2*(L + 2) + limit = E
+        lsl             r6,  r6,  r9   // I << bitdepth_min_8
+        lsl             r11, r11, r9   // E << bitdepth_min_8
+        vdup.16         d11, r6        // I << bitdepth_min_8
+        vdup.16         d10, r11       // E << bitdepth_min_8
+
+.ifc \type, y
+        tst             r2,  #0x01
+        beq             2f
+        // wd16
+        bl              lpf_\dir\()_16_4_neon
+        b               8f
+2:
+.endif
+        tst             r7,  #0x01
+        beq             3f
+.ifc \type, y
+        // wd8
+        bl              lpf_\dir\()_8_4_neon
+.else
+        // wd6
+        bl              lpf_\dir\()_6_4_neon
+.endif
+        b               8f
+3:
+        // wd4
+        bl              lpf_\dir\()_4_4_neon
+.ifc \dir, h
+        b               8f
+7:
+        // For dir h, the functions above increment r0.
+        // If the whole function is skipped, increment it here instead.
+        add             r0,  r0,  r1,  lsl #2
+.else
+7:
+.endif
+8:
+        ldrd            r6,  r7,  [sp]
+.ifc \type, y
+        lsr             r2,  r2,  #1   // vmask[2] >>= 1
+.endif
+.ifc \dir, v
+        add             r0,  r0,  #8
+.else
+        // For dir h, r0 is returned incremented
+.endif
+        lsrs            r6,  r6,  #1   // vmask[0] >>= 1
+        lsr             r7,  r7,  #1   // vmask[1] >>= 1
+        bne             1b
+
+        add             sp,  sp,  #8
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+lpf_func v, y
+lpf_func h, y
+lpf_func v, uv
+lpf_func h, uv
diff --git a/media/libdav1d/src/src/arm/32/looprestoration.S b/media/libdav1d/src/src/arm/32/looprestoration.S
new file mode 100644
index 0000000000..0a09e981ed
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/looprestoration.S
@@ -0,0 +1,729 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+const right_ext_mask_buf
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+right_ext_mask:
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+endconst
+
+// void dav1d_wiener_filter_h_8bpc_neon(int16_t *dst, const pixel (*left)[4],
+//                                      const pixel *src, const int16_t fh[8],
+//                                      const int w,
+//                                      const enum LrEdgeFlags edges);
+function wiener_filter_h_8bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldrd            r4,  r5,  [sp, #12]
+        vld1.16         {q0},  [r3, :128]
+        movw            r12, #(1 << 14) - (1 << 2)
+        vdup.16         q14, r12
+        vmov.s16        q15, #2048
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             r5,  #1 // LR_HAVE_LEFT
+        beq             1f
+        // LR_HAVE_LEFT
+        cmp             r1,  #0
+        bne             0f
+        // left == NULL
+        sub             r2,  r2,  #3
+        vld1.8          {q2},  [r2]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.8          {q2},  [r2]!
+        vld1.32         {d3[1]},  [r1]
+        // Move r2 back to account for the last 3 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             r2,  r2,  #3
+        vext.8          q2,  q1,  q2,  #13
+        b               2f
+
+1:
+        vld1.8          {q2},  [r2]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost byte
+        // and shift q2 to have 3x the first byte at the front.
+        vdup.8          q1,  d4[0]
+        // Move r2 back to account for the last 3 bytes we loaded before,
+        // which we shifted out.
+        sub             r2,  r2,  #3
+        vext.8          q2,  q1,  q2,  #13
+
+2:
+        vmovl.u8        q1,  d4
+        vmovl.u8        q2,  d5
+
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        bne             4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r4,  #11
+        bge             4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+3 pixels valid in q1-q2. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is q1/2.h[w+2]. r2 points at the next input, ie
+        // q1/2.h[16]. Thus read from r2[w-14] to find the padding pixel.
+        sub             r12, r4,  #14
+        // Insert padding in q1/2.h[w+3] onwards; fuse the +3 (*2) into the
+        // buffer pointer.
+        movrel_local    r3,  right_ext_mask, -6
+        ldrb            r12, [r2, r12]
+        sub             r3,  r3,  r4,  lsl #1
+        vdup.16         q13, r12
+        vld1.8          {q10, q11}, [r3]
+
+        vbit            q1,  q13, q10
+        vbit            q2,  q13, q11
+
+4:      // Loop horizontally
+        vext.8          q10, q1,  q2,  #4
+        vext.8          q11, q1,  q2,  #8
+        vext.8          q9,  q1,  q2,  #2
+        vext.8          q12, q1,  q2,  #10
+        vext.8          q13, q1,  q2,  #12
+        vext.8          q8,  q1,  q2,  #6
+        vadd.i16        q10, q10, q11
+        vadd.i16        q9,  q9,  q12
+        vadd.i16        q13, q13, q1
+        vshl.s16        q1,  q8,  #7
+        vmul.s16        q3,  q8,  d0[3]
+        vmla.s16        q3,  q10, d1[0]
+        vmla.s16        q3,  q9,  d1[1]
+        vmla.s16        q3,  q13, d1[2]
+
+        vsub.s16        q1,  q1,  q14
+        vqadd.s16       q3,  q3,  q1
+        vshr.s16        q3,  q3,  #3
+        vadd.s16        q3,  q3,  q15
+        subs            r4,  r4,  #8
+        vst1.16         {q3},  [r0,  :128]!
+
+        ble             9f
+        vmov            q1,  q2
+        vld1.8          {d4},  [r2]!
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        vmovl.u8        q2,  d4
+        bne             4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        pop             {r4-r5,pc}
+endfunc
+
+// void dav1d_wiener_filter_v_8bpc_neon(pixel *dst, int16_t **ptrs,
+//                                      const int16_t fv[8], const int w);
+function wiener_filter_v_8bpc_neon, export=1
+        push            {r4-r9,lr}
+        vpush           {q4-q6}
+
+        vld1.16         {q0},  [r2, :128]
+
+        ldrd            r4,  r5,  [r1]
+        ldrd            r6,  r7,  [r1, #8]
+        ldrd            r8,  r9,  [r1, #16]
+
+1:
+        vld1.16         {q1,  q2},  [r4, :128]!
+        vld1.16         {q8,  q9},  [r9, :128]!
+
+        vld1.16         {q5,  q6},  [r5, :128]!
+
+        vld1.16         {q10, q11}, [r6, :128]!
+        vld1.16         {q12, q13}, [r8, :128]!
+
+        vld1.16         {q14, q15}, [r7, :128]!
+
+        subs            r3,  r3,  #16
+
+        vadd.i16        q1,  q1,  q8
+        vadd.i16        q2,  q2,  q9
+
+        vadd.i16        q5,  q5,  q8
+        vadd.i16        q6,  q6,  q9
+
+        vadd.i16        q10, q10, q12
+        vadd.i16        q11, q11, q13
+
+        vmull.s16       q3,  d28, d0[3]
+        vmlal.s16       q3,  d2,  d0[0]
+        vmlal.s16       q3,  d10, d0[1]
+        vmlal.s16       q3,  d20, d0[2]
+
+        vmull.s16       q4,  d29, d0[3]
+        vmlal.s16       q4,  d3,  d0[0]
+        vmlal.s16       q4,  d11, d0[1]
+        vmlal.s16       q4,  d21, d0[2]
+
+        vmull.s16       q8,  d30, d0[3]
+        vmlal.s16       q8,  d4,  d0[0]
+        vmlal.s16       q8,  d12, d0[1]
+        vmlal.s16       q8,  d22, d0[2]
+
+        vmull.s16       q9,  d31, d0[3]
+        vmlal.s16       q9,  d5,  d0[0]
+        vmlal.s16       q9,  d13, d0[1]
+        vmlal.s16       q9,  d23, d0[2]
+
+        vqrshrun.s32    d6,  q3,  #11
+        vqrshrun.s32    d7,  q4,  #11
+        vqrshrun.s32    d16, q8,  #11
+        vqrshrun.s32    d17, q9,  #11
+        vqmovun.s16     d6,  q3
+        vqmovun.s16     d7,  q8
+        vst1.8          {q3}, [r0, :128]!
+        bgt             1b
+
+        // Shift the pointers, but only update the first 5; the 6th pointer is
+        // kept as it was before (and the 7th is implicitly identical to the
+        // 6th).
+        ldrd            r4,  r5,  [r1, #4]
+        ldrd            r6,  r7,  [r1, #12]
+        ldr             r8,       [r1, #20]
+        strd            r4,  r5,  [r1]
+        strd            r6,  r7,  [r1, #8]
+        str             r8,       [r1, #16]
+
+        vpop            {q4-q6}
+        pop             {r4-r9,pc}
+endfunc
+
+// void dav1d_wiener_filter_hv_8bpc_neon(pixel *dst, const pixel (*left)[4],
+//                                       const pixel *src,
+//                                       const int16_t filter[2][8],
+//                                       const int w,
+//                                       const enum LrEdgeFlags edges,
+//                                       int16_t **ptrs);
+function wiener_filter_hv_8bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]
+        ldr             lr,       [sp, #108]
+        vld1.16         {q0, q1}, [r3, :128]
+        movw            r12, #(1 << 14) - (1 << 2)
+        vdup.16         q14, r12
+        vmov.s16        q15, #2048
+
+        ldrd            r6,  r7,  [lr]
+        ldrd            r8,  r9,  [lr, #8]
+        ldrd            r10, r11, [lr, #16]
+        ldr             r12,      [lr, #24]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             r5,  #1 // LR_HAVE_LEFT
+        beq             1f
+        // LR_HAVE_LEFT
+        cmp             r1,  #0
+        bne             0f
+        // left == NULL
+        sub             r2,  r2,  #3
+        vld1.8          {q2},  [r2]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.8          {q2},  [r2]!
+        vld1.32         {d3[1]},  [r1]
+        // Move r2 back to account for the last 3 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             r2,  r2,  #3
+        vext.8          q2,  q1,  q2,  #13
+        b               2f
+
+1:
+        vld1.8          {q2},  [r2]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost byte
+        // and shift q2 to have 3x the first byte at the front.
+        vdup.8          q3,  d4[0]
+        // Move r2 back to account for the last 3 bytes we loaded before,
+        // which we shifted out.
+        sub             r2,  r2,  #3
+        vext.8          q2,  q3,  q2,  #13
+
+2:
+        vmovl.u8        q3,  d5
+        vmovl.u8        q2,  d4
+
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        bne             4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r4,  #11
+        bge             4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+3 pixels valid in q1-q2. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is q1/2.h[w+2]. r2 points at the next input, ie
+        // q1/2.h[16]. Thus read from r2[w-14] to find the padding pixel.
+        sub             lr,  r4,  #14
+        // Insert padding in q1/2.h[w+3] onwards; fuse the +3 (*2) into the
+        // buffer pointer.
+        movrel_local    r3,  right_ext_mask, -6
+        ldrb            lr,  [r2, lr]
+        sub             r3,  r3,  r4,  lsl #1
+        vdup.16         q13, lr
+        vld1.8          {q10, q11}, [r3]
+
+        vbit            q2,  q13, q10
+        vbit            q3,  q13, q11
+
+4:      // Loop horizontally
+        vext.8          q10, q2,  q3,  #4
+        vext.8          q11, q2,  q3,  #8
+        vext.8          q9,  q2,  q3,  #2
+        vext.8          q12, q2,  q3,  #10
+        vext.8          q13, q2,  q3,  #12
+        vext.8          q8,  q2,  q3,  #6
+        vadd.i16        q10, q10, q11
+        vadd.i16        q9,  q9,  q12
+        vadd.i16        q13, q13, q2
+        vld1.16         {q6},   [r7,  :128]!
+        vshl.s16        q2,  q8,  #7
+        vld1.16         {q11},  [r11, :128]!
+        vsub.s16        q2,  q2,  q14
+        vld1.16         {q7},   [r8,  :128]!
+        vmul.s16        q4,  q8,  d0[3]
+        vmla.s16        q4,  q10, d1[0]
+        vmla.s16        q4,  q9,  d1[1]
+        vmla.s16        q4,  q13, d1[2]
+
+        vld1.16         {q10},  [r10, :128]!
+        vqadd.s16       q4,  q4,  q2
+
+        vld1.16         {q9},   [r9,  :128]!
+        vshr.s16        q4,  q4,  #3
+        vld1.16         {q5},   [r6,  :128]!
+        vadd.s16        q4,  q4,  q15
+
+        vadd.s16        q6,  q6,  q11
+        vadd.s16        q7,  q7,  q10
+        vadd.s16        q5,  q5,  q4
+
+        vmull.s16       q8,  d18, d2[3]
+        vmlal.s16       q8,  d12, d2[1]
+        vmlal.s16       q8,  d14, d2[2]
+        vmlal.s16       q8,  d10, d2[0]
+
+        vmull.s16       q9,  d19, d2[3]
+        vmlal.s16       q9,  d13, d2[1]
+        vmlal.s16       q9,  d15, d2[2]
+        vmlal.s16       q9,  d11, d2[0]
+
+        vqrshrun.s32    d16, q8,  #11
+        vqrshrun.s32    d17, q9,  #11
+        vst1.16         {q4},  [r12, :128]!
+        vqmovun.s16     d16, q8
+        subs            r4,  r4,  #8
+        vst1.8          {d16}, [r0, :64]!
+
+        ble             9f
+        vmov            q2,  q3
+        vld1.8          {d6},  [r2]!
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        vmovl.u8        q3,  d6
+        bne             4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        // Reload ptrs from arguments on the stack
+        ldr             lr,       [sp, #108]
+        // Rotate the window of pointers. Shift the 6 pointers downwards one step.
+        ldrd            r6,  r7,  [lr, #4]
+        ldrd            r8,  r9,  [lr, #12]
+        ldrd            r10, r11, [lr, #20]
+
+        strd            r6,  r7,  [lr]
+        strd            r8,  r9,  [lr, #8]
+        strd            r10, r11, [lr, #16]
+        // The topmost pointer, ptrs[6], which isn't used as input, is set to
+        // ptrs[0], which will be used as output for the next _hv call.
+        // At the start of the filtering, the caller may set ptrs[6] to the
+        // right next buffer to fill in, instead.
+        str             r6,       [lr, #24]
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+#include "looprestoration_tmpl.S"
+
+// void dav1d_sgr_box3_row_h_8bpc_neon(int32_t *sumsq, int16_t *sum,
+//                                     const pixel (*left)[4],
+//                                     const pixel *src, const int w,
+//                                     const enum LrEdgeFlags edges);
+function sgr_box3_row_h_8bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldrd            r4,  r5,  [sp, #12]
+        add             r4,  r4,  #2 // w += 2
+
+        tst             r5,  #1 // LR_HAVE_LEFT
+        beq             1f
+        cmp             r2,  #0
+        bne             0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             r3,  r3,  #2
+        vld1.8          {q0}, [r3]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.8          {q0},   [r3]!
+        vld1.32         {d3[]}, [r2]
+        // Move r3 back to account for the last 2 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             r3,  r3,  #2
+        vext.8          q0,  q1,  q0,  #14
+        b               2f
+
+1:
+        vld1.8          {q0},   [r3]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost byte
+        // and shift q0 to have 2x the first byte at the front.
+        vdup.8          q1,  d0[0]
+        // Move r3 back to account for the last 2 bytes we loaded before,
+        // which we shifted out.
+        sub             r3,  r3,  #2
+        vext.8          q0,  q1,  q0,  #14
+
+2:
+        vmull.u8        q1,  d0,  d0
+        vmull.u8        q2,  d1,  d1
+
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        bne             4f
+        // If we'll need to pad the right edge, load that byte to pad with
+        // here since we can find it pretty easily from here.
+        sub             lr,  r4,  #(2 + 16 - 2 + 1)
+        ldrb            lr,  [r3,  lr]
+        // Fill q14 with the right padding pixel
+        vdup.8          q14, lr
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r4,  #10
+        bge             4f   // If w >= 10, all used input pixels are valid
+
+        // 1 <= w < 10, w pixels valid in q0. For w=9, this ends up called
+        // again; it's not strictly needed in those cases (we pad enough here),
+        // but keeping the code as simple as possible.
+
+        // Insert padding in q0.b[w] onwards
+        movrel_local    lr,  right_ext_mask
+        sub             lr,  lr,  r4
+        vld1.8          {q13}, [lr]
+
+        vbit            q0,  q14, q13
+
+        // Update the precalculated squares
+        vmull.u8        q1,  d0,  d0
+        vmull.u8        q2,  d1,  d1
+
+4:      // Loop horizontally
+        vext.8          d16, d0,  d1,  #1
+        vext.8          d17, d0,  d1,  #2
+        vaddl.u8        q3,  d0,  d16
+        vext.8          q9,  q1,  q2,  #2
+        vaddw.u8        q3,  q3,  d17
+
+        vext.8          q10, q1,  q2,  #4
+
+        vaddl.u16       q12, d2,  d18
+        vaddl.u16       q13, d3,  d19
+        vaddw.u16       q12, q12, d20
+        vaddw.u16       q13, q13, d21
+
+        subs            r4,  r4,  #8
+        vst1.16         {q3},       [r1,  :128]!
+        vst1.32         {q12, q13}, [r0,  :128]!
+
+        ble             9f
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        vld1.8          {d6},  [r3]!
+        vmov            q1,  q2
+        vext.8          q0,  q0,  q3,  #8
+        vmull.u8        q2,  d6,  d6
+
+        bne             4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        pop             {r4-r5,pc}
+endfunc
+
+// void dav1d_sgr_box5_row_h_8bpc_neon(int32_t *sumsq, int16_t *sum,
+//                                     const pixel (*left)[4],
+//                                     const pixel *src, const int w,
+//                                     const enum LrEdgeFlags edges);
+function sgr_box5_row_h_8bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldrd            r4,  r5,  [sp, #12]
+        add             r4,  r4,  #2 // w += 2
+
+        tst             r5,  #1 // LR_HAVE_LEFT
+        beq             1f
+        cmp             r2,  #0
+        bne             0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             r3,  r3,  #3
+        vld1.8          {q0}, [r3]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.8          {q0},   [r3]!
+        vld1.32         {d3[]}, [r2]
+        // Move r3 back to account for the last 3 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             r3,  r3,  #3
+        vext.8          q0,  q1,  q0,  #13
+        b               2f
+
+1:
+        vld1.8          {q0},   [r3]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost byte
+        // and shift q0 to have 3x the first byte at the front.
+        vdup.8          q1,  d0[0]
+        // Move r3 back to account for the last 3 bytes we loaded before,
+        // which we shifted out.
+        sub             r3,  r3,  #3
+        vext.8          q0,  q1,  q0,  #13
+
+2:
+        vmull.u8        q1,  d0,  d0
+        vmull.u8        q2,  d1,  d1
+
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        bne             4f
+        // If we'll need to pad the right edge, load that byte to pad with
+        // here since we can find it pretty easily from here.
+        sub             lr,  r4,  #(2 + 16 - 3 + 1)
+        ldrb            lr,  [r3,  lr]
+        // Fill q14 with the right padding pixel
+        vdup.8          q14, lr
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r4,  #11
+        bge             4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+1 pixels valid in q0. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // Insert padding in q0.b[w+1] onwards; fuse the +1 into the
+        // buffer pointer.
+        movrel_local    lr,  right_ext_mask, -1
+        sub             lr,  lr,  r4
+        vld1.8          {q13}, [lr]
+
+        vbit            q0,  q14, q13
+
+        // Update the precalculated squares
+        vmull.u8        q1,  d0,  d0
+        vmull.u8        q2,  d1,  d1
+
+4:      // Loop horizontally
+        vext.8          d16, d0,  d1,  #1
+        vext.8          d17, d0,  d1,  #2
+        vext.8          d18, d0,  d1,  #3
+        vext.8          d19, d0,  d1,  #4
+        vaddl.u8        q3,  d0,  d16
+        vaddl.u8        q12, d17, d18
+        vaddw.u8        q3,  q3,  d19
+        vadd.u16        q3,  q3,  q12
+
+        vext.8          q8,  q1,  q2,  #2
+        vext.8          q9,  q1,  q2,  #4
+        vext.8          q10, q1,  q2,  #6
+        vext.8          q11, q1,  q2,  #8
+        vaddl.u16       q12, d2,  d16
+        vaddl.u16       q13, d3,  d17
+        vaddl.u16       q8,  d18, d20
+        vaddl.u16       q9,  d19, d21
+        vaddw.u16       q12, q12, d22
+        vaddw.u16       q13, q13, d23
+        vadd.i32        q12, q12, q8
+        vadd.i32        q13, q13, q9
+
+        subs            r4,  r4,  #8
+        vst1.16         {q3},       [r1,  :128]!
+        vst1.32         {q12, q13}, [r0,  :128]!
+
+        ble             9f
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        vld1.8          {d6},  [r3]!
+        vmov            q1,  q2
+        vext.8          q0,  q0,  q3,  #8
+        vmull.u8        q2,  d6,  d6
+        bne             4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        pop             {r4-r5,pc}
+endfunc
+
+// void dav1d_sgr_box35_row_h_8bpc_neon(int32_t *sumsq3, int16_t *sum3,
+//                                      int32_t *sumsq5, int16_t *sum5,
+//                                      const pixel (*left)[4],
+//                                      const pixel *src, const int w,
+//                                      const enum LrEdgeFlags edges);
+function sgr_box35_row_h_8bpc_neon, export=1
+        push            {r4-r7,lr}
+        ldrd            r4,  r5,  [sp, #20]
+        ldrd            r6,  r7,  [sp, #28]
+        add             r6,  r6,  #2 // w += 2
+
+        tst             r7,  #1 // LR_HAVE_LEFT
+        beq             1f
+        cmp             r4,  #0
+        bne             0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             r5,  r5,  #3
+        vld1.8          {q0}, [r5]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.8          {q0},   [r5]!
+        vld1.32         {d3[]}, [r4]
+        // Move r3 back to account for the last 3 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             r5,  r5,  #3
+        vext.8          q0,  q1,  q0,  #13
+        b               2f
+
+1:
+        vld1.8          {q0},   [r5]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost byte
+        // and shift q0 to have 3x the first byte at the front.
+        vdup.8          q1,  d0[0]
+        // Move r3 back to account for the last 3 bytes we loaded before,
+        // which we shifted out.
+        sub             r5,  r5,  #3
+        vext.8          q0,  q1,  q0,  #13
+
+2:
+        vmull.u8        q1,  d0,  d0
+        vmull.u8        q2,  d1,  d1
+
+        tst             r7,  #2 // LR_HAVE_RIGHT
+        bne             4f
+        // If we'll need to pad the right edge, load that byte to pad with
+        // here since we can find it pretty easily from here.
+        sub             lr,  r6,  #(2 + 16 - 3 + 1)
+        ldrb            lr,  [r5,  lr]
+        // Fill q14 with the right padding pixel
+        vdup.8          q14, lr
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r6,  #11
+        bge             4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+1 pixels valid in q0. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // Insert padding in q0.b[w+1] onwards; fuse the +1 into the
+        // buffer pointer.
+        movrel_local    lr,  right_ext_mask, -1
+        sub             lr,  lr,  r6
+        vld1.8          {q13}, [lr]
+
+        vbit            q0,  q14, q13
+
+        // Update the precalculated squares
+        vmull.u8        q1,  d0,  d0
+        vmull.u8        q2,  d1,  d1
+
+4:      // Loop horizontally
+        vext.8          d16, d0,  d1,  #1
+        vext.8          d17, d0,  d1,  #2
+        vext.8          d18, d0,  d1,  #3
+        vext.8          d19, d0,  d1,  #4
+        vaddl.u8        q3,  d16, d17
+        vaddl.u8        q12, d0,  d19
+        vaddw.u8        q3,  q3,  d18
+
+        vext.8          q8,  q1,  q2,  #2
+        vext.8          q9,  q1,  q2,  #4
+        vext.8          q10, q1,  q2,  #6
+        vext.8          q11, q1,  q2,  #8
+
+        vst1.16         {q3},       [r1,  :128]!
+        vadd.u16        q3,  q3,  q12
+
+        vaddl.u16       q12, d16, d18
+        vaddl.u16       q13, d17, d19
+        vaddl.u16       q8,  d2,  d22
+        vaddl.u16       q9,  d3,  d23
+        vaddw.u16       q12, q12, d20
+        vaddw.u16       q13, q13, d21
+
+        vst1.32         {q12, q13}, [r0,  :128]!
+        vadd.i32        q12, q12, q8
+        vadd.i32        q13, q13, q9
+
+        subs            r6,  r6,  #8
+        vst1.16         {q3},       [r3,  :128]!
+        vst1.32         {q12, q13}, [r2,  :128]!
+
+        ble             9f
+        tst             r7,  #2 // LR_HAVE_RIGHT
+        vld1.8          {d6},  [r5]!
+        vmov            q1,  q2
+        vext.8          q0,  q0,  q3,  #8
+        vmull.u8        q2,  d6,  d6
+        bne             4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        pop             {r4-r7,pc}
+endfunc
+
+sgr_funcs 8
diff --git a/media/libdav1d/src/src/arm/32/looprestoration16.S b/media/libdav1d/src/src/arm/32/looprestoration16.S
new file mode 100644
index 0000000000..f254ffd298
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/looprestoration16.S
@@ -0,0 +1,757 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+const right_ext_mask_buf
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+right_ext_mask:
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+endconst
+
+// void dav1d_wiener_filter_h_16bpc_neon(int16_t *dst, const pixel (*left)[4],
+//                                       const pixel *src, const int16_t fh[8],
+//                                       const int w,
+//                                       enum LrEdgeFlags edges,
+//                                       const int bitdepth_max);
+function wiener_filter_h_16bpc_neon, export=1
+        push            {r4-r6,lr}
+        ldrd            r4,  r5,  [sp, #16]
+        ldr             r6,       [sp, #24] // bitdepth_max
+        vld1.16         {q0}, [r3, :128]
+        clz             r6,  r6
+        vmov.i32        q14, #1
+        sub             r12, r6,  #38  // -(bitdepth + 6)
+        sub             r6,  r6,  #25  // -round_bits_h
+        neg             r12, r12       // bitdepth + 6
+        vdup.32         q1,  r12
+        vdup.32         q13, r6        // -round_bits_h
+        vmov.i16        q15, #8192
+        vshl.u32        q14, q14, q1   // 1 << (bitdepth + 6)
+        vmvn.i16        q12, #0x8000   // 0x7fff = (1 << 15) - 1
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             r5,  #1 // LR_HAVE_LEFT
+        beq             1f
+        // LR_HAVE_LEFT
+        cmp             r1,  #0
+        bne             0f
+        // left == NULL
+        sub             r2,  r2,  #6
+        vld1.16         {q2, q3}, [r2]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.16         {q2, q3}, [r2]!
+        vld1.16         {d3},  [r1]!
+        // Move r2 back to account for the last 3 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             r2,  r2,  #6
+        vext.8          q3,  q2,  q3,  #10
+        vext.8          q2,  q1,  q2,  #10
+        b               2f
+1:
+        vld1.16         {q2, q3}, [r2]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost pixel
+        // and shift q2/q3 to have 3x the first pixel at the front.
+        vdup.16         q1,  d4[0]
+        // Move r2 back to account for the last 3 pixels we loaded before,
+        // which we shifted out.
+        sub             r2,  r2,  #6
+        vext.8          q3,  q2,  q3,  #10
+        vext.8          q2,  q1,  q2,  #10
+
+2:
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        bne             4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r4,  #11
+        bge             4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+3 pixels valid in q2-q3. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is q1/2.h[w+2]. r2 points at the next input, ie
+        // q1/2.h[16]. Thus read from r2[w-14] to find the padding pixel.
+        sub             r12, r4,  #14
+        lsl             r12, r12, #1
+        // Insert padding in q2/3.h[w+3] onwards; fuse the +3 (*2) into the
+        // buffer pointer.
+        movrel_local    r3,  right_ext_mask, -6
+        ldrh            r12, [r2, r12]
+        sub             r3,  r3,  r4,  lsl #1
+        vdup.16         q11, r12
+        vld1.8          {q9, q10}, [r3]
+
+        vbit            q2,  q11, q9
+        vbit            q3,  q11, q10
+
+4:      // Loop horizontally
+        vext.8          q9,  q2,  q3,  #4
+        vext.8          q10, q2,  q3,  #8
+        vext.8          q8,  q2,  q3,  #2
+        vext.8          q11, q2,  q3,  #10
+        vadd.i16        q10, q10, q9
+        vadd.i16        q11, q11, q8
+        vext.8          q8,  q2,  q3,  #12
+        vext.8          q9,  q2,  q3,  #6
+        vadd.i16        q2,  q2,  q8
+        vmull.s16       q8,  d18, d0[3]
+        vmlal.s16       q8,  d20, d1[0]
+        vmlal.s16       q8,  d22, d1[1]
+        vmlal.s16       q8,  d4,  d1[2]
+        vmull.s16       q9,  d19, d0[3]
+        vmlal.s16       q9,  d21, d1[0]
+        vmlal.s16       q9,  d23, d1[1]
+        vmlal.s16       q9,  d5,  d1[2]
+
+        vadd.i32        q8,  q8,  q14
+        vadd.i32        q9,  q9,  q14
+        vrshl.s32       q8,  q8,  q13
+        vrshl.s32       q9,  q9,  q13
+        vqmovun.s32     d16, q8
+        vqmovun.s32     d17, q9
+        vmin.u16        q8,  q8,  q12
+        vsub.i16        q8,  q8,  q15
+        subs            r4,  r4,  #8
+        vst1.16         {q8}, [r0,  :128]!
+
+        ble             9f
+        vmov            q2,  q3
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        vld1.16         {q3}, [r2]!
+        bne             4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        pop             {r4-r6,pc}
+endfunc
+
+// void dav1d_wiener_filter_v_16bpc_neon(pixel *dst, int16_t **ptrs,
+//                                       const int16_t fv[8], const int w,
+//                                       const int bitdepth_max);
+function wiener_filter_v_16bpc_neon, export=1
+        push            {r4-r9,lr}
+        vpush           {q4-q7}
+
+        ldr             lr,  [sp, #92]  // bitdepth_max
+        vld1.16         {q0},  [r2, :128]
+        vdup.16         q2,  lr
+        clz             lr,  lr
+        sub             lr,  lr,  #11   // round_bits_v
+
+        vdup.32         q1,  lr
+
+        ldrd            r4,  r5,  [r1]
+        ldrd            r6,  r7,  [r1, #8]
+        ldrd            r8,  r9,  [r1, #16]
+
+        vneg.s32        q1,  q1         // -round_bits_v
+
+1:
+        vld1.16         {q4,  q5},  [r4, :128]!
+        vld1.16         {q6,  q7},  [r5, :128]!
+        vld1.16         {q8,  q9},  [r6, :128]!
+        vld1.16         {q10, q11}, [r7, :128]!
+        vld1.16         {q12, q13}, [r8, :128]!
+        vld1.16         {q14, q15}, [r9, :128]!
+
+        subs            r3,  r3,  #16
+
+        vmull.s16       q3,  d8,  d0[0]
+        vmlal.s16       q3,  d12, d0[1]
+        vmlal.s16       q3,  d16, d0[2]
+        vmlal.s16       q3,  d20, d0[3]
+        vmlal.s16       q3,  d24, d1[0]
+        vmlal.s16       q3,  d28, d1[1]
+        vmlal.s16       q3,  d28, d1[2]
+        vmull.s16       q4,  d9,  d0[0]
+        vmlal.s16       q4,  d13, d0[1]
+        vmlal.s16       q4,  d17, d0[2]
+        vmlal.s16       q4,  d21, d0[3]
+        vmlal.s16       q4,  d25, d1[0]
+        vmlal.s16       q4,  d29, d1[1]
+        vmlal.s16       q4,  d29, d1[2]
+
+        vmull.s16       q6,  d10, d0[0]
+        vmlal.s16       q6,  d14, d0[1]
+        vmlal.s16       q6,  d18, d0[2]
+        vmlal.s16       q6,  d22, d0[3]
+        vmlal.s16       q6,  d26, d1[0]
+        vmlal.s16       q6,  d30, d1[1]
+        vmlal.s16       q6,  d30, d1[2]
+        vmull.s16       q5,  d11, d0[0]
+        vmlal.s16       q5,  d15, d0[1]
+        vmlal.s16       q5,  d19, d0[2]
+        vmlal.s16       q5,  d23, d0[3]
+        vmlal.s16       q5,  d27, d1[0]
+        vmlal.s16       q5,  d31, d1[1]
+        vmlal.s16       q5,  d31, d1[2]
+
+        vrshl.s32       q3,  q3,  q1    // round_bits_v
+        vrshl.s32       q4,  q4,  q1
+        vrshl.s32       q6,  q6,  q1
+        vrshl.s32       q5,  q5,  q1
+        vqmovun.s32     d6,  q3
+        vqmovun.s32     d7,  q4
+        vqmovun.s32     d8,  q6
+        vqmovun.s32     d9,  q5
+        vmin.u16        q3,  q3,  q2    // bitdepth_max
+        vmin.u16        q4,  q4,  q2
+        vst1.16         {q3, q4}, [r0, :128]!
+        bgt             1b
+
+        // Shift the pointers, but only update the first 5; the 6th pointer is
+        // kept as it was before (and the 7th is implicitly identical to the
+        // 6th).
+        ldrd            r4,  r5,  [r1, #4]
+        ldrd            r6,  r7,  [r1, #12]
+        ldr             r8,       [r1, #20]
+        strd            r4,  r5,  [r1]
+        strd            r6,  r7,  [r1, #8]
+        str             r8,       [r1, #16]
+
+        vpop            {q4-q7}
+        pop             {r4-r9,pc}
+endfunc
+
+// void dav1d_wiener_filter_hv_16bpc_neon(pixel *dst, const pixel (*left)[4],
+//                                        const pixel *src,
+//                                        const int16_t filter[2][8],
+//                                        const int w,
+//                                        const enum LrEdgeFlags edges,
+//                                        int16_t **ptrs,
+//                                        const int bitdepth_max);
+function wiener_filter_hv_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]
+        ldrd            r6,  r7,  [sp, #108]
+        vld1.16         {q0, q1}, [r3, :128]
+        vdup.16         q11, r7        // bitdepth_max
+        clz             r7,  r7
+        vmov.i32        q14, #1
+        sub             r12, r7,  #38  // -(bitdepth + 6)
+        sub             lr,  r7,  #11  // round_bits_v
+        sub             r7,  r7,  #25  // -round_bits_h
+        neg             r12, r12       // bitdepth + 6
+        vdup.32         q2,  r12
+        vdup.32         q13, r7        // -round_bits_h
+        vdup.32         q10, lr        // round_bits_v
+        mov             lr,  r6
+        vmov.i16        q15, #8192
+        vshl.u32        q14, q14, q2   // 1 << (bitdepth + 6)
+        vneg.s32        q10, q10       // -round_bits_v
+
+        ldrd            r6,  r7,  [lr]
+        ldrd            r8,  r9,  [lr, #8]
+        ldrd            r10, r11, [lr, #16]
+        ldr             r12,      [lr, #24]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             r5,  #1 // LR_HAVE_LEFT
+        beq             1f
+        // LR_HAVE_LEFT
+        cmp             r1,  #0
+        bne             0f
+        // left == NULL
+        sub             r2,  r2,  #6
+        vld1.16         {q2, q3}, [r2]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.16         {q2, q3}, [r2]!
+        vld1.16         {d9},  [r1]!
+        // Move r2 back to account for the last 3 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             r2,  r2,  #6
+        vext.8          q3,  q2,  q3,  #10
+        vext.8          q2,  q4,  q2,  #10
+        b               2f
+1:
+        vld1.16         {q2, q3}, [r2]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost pixel
+        // and shift q2/q3 to have 3x the first pixel at the front.
+        vdup.16         q4,  d4[0]
+        // Move r2 back to account for the last 3 pixels we loaded before,
+        // which we shifted out.
+        sub             r2,  r2,  #6
+        vext.8          q3,  q2,  q3,  #10
+        vext.8          q2,  q4,  q2,  #10
+
+2:
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        bne             4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r4,  #11
+        bge             4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+3 pixels valid in q2-q3. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is q1/2.h[w+2]. r2 points at the next input, ie
+        // q1/2.h[16]. Thus read from r2[w-14] to find the padding pixel.
+        sub             lr,  r4,  #14
+        lsl             lr,  lr,  #1
+        // Insert padding in q2/3.h[w+3] onwards; fuse the +3 (*2) into the
+        // buffer pointer.
+        movrel_local    r3,  right_ext_mask, -6
+        ldrh            lr,  [r2, lr]
+        sub             r3,  r3,  r4,  lsl #1
+        vdup.16         q4,  lr
+        vld1.8          {q8, q9}, [r3]
+
+        vbit            q2,  q4,  q8
+        vbit            q3,  q4,  q9
+
+4:      // Loop horizontally
+        vext.8          q5,  q2,  q3,  #4
+        vext.8          q6,  q2,  q3,  #8
+        vext.8          q4,  q2,  q3,  #2
+        vext.8          q7,  q2,  q3,  #10
+        vadd.i16        q6,  q6,  q5
+        vadd.i16        q7,  q7,  q4
+        vext.8          q4,  q2,  q3,  #12
+        vext.8          q5,  q2,  q3,  #6
+        vadd.i16        q2,  q2,  q4
+        vld1.16         {q4},  [r6,  :128]!
+        vmull.s16       q8,  d10, d0[3]
+        vmlal.s16       q8,  d12, d1[0]
+        vmlal.s16       q8,  d14, d1[1]
+        vmlal.s16       q8,  d4,  d1[2]
+        vmull.s16       q9,  d11, d0[3]
+        vmlal.s16       q9,  d13, d1[0]
+        vmlal.s16       q9,  d15, d1[1]
+        vmlal.s16       q9,  d5,  d1[2]
+        vld1.16         {q5},  [r7,  :128]!
+
+        vmvn.i16        q12, #0x8000   // 0x7fff = (1 << 15) - 1
+
+        vadd.i32        q8,  q8,  q14
+        vadd.i32        q9,  q9,  q14
+        vld1.16         {q6},  [r8,  :128]!
+        vrshl.s32       q8,  q8,  q13
+        vrshl.s32       q9,  q9,  q13
+        vqmovun.s32     d16, q8
+        vqmovun.s32     d17, q9
+        vld1.16         {q7},  [r9,  :128]!
+        vmin.u16        q8,  q8,  q12
+        vld1.16         {q9},  [r10, :128]!
+        vsub.i16        q8,  q8,  q15
+
+        vld1.16         {q2},  [r11, :128]!
+
+        vmull.s16       q12, d8,  d2[0]
+        vmlal.s16       q12, d10, d2[1]
+        vmlal.s16       q12, d12, d2[2]
+        vmlal.s16       q12, d14, d2[3]
+        vmlal.s16       q12, d18, d3[0]
+        vmlal.s16       q12, d4,  d3[1]
+        vmlal.s16       q12, d16, d3[2]
+        vmull.s16       q4,  d9,  d2[0]
+        vmlal.s16       q4,  d11, d2[1]
+        vmlal.s16       q4,  d13, d2[2]
+        vmlal.s16       q4,  d15, d2[3]
+        vmlal.s16       q4,  d19, d3[0]
+        vmlal.s16       q4,  d5,  d3[1]
+        vmlal.s16       q4,  d17, d3[2]
+
+        vrshl.s32       q12, q12, q10   // round_bits_v
+        vrshl.s32       q4,  q4,  q10
+        vqmovun.s32     d24, q12
+        vqmovun.s32     d25, q4
+        vst1.16         {q8},  [r12, :128]!
+        vmin.u16        q12, q12, q11   // bitdepth_max
+        subs            r4,  r4,  #8
+        vst1.16         {q12}, [r0, :128]!
+
+        ble             9f
+        vmov            q2,  q3
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        vld1.16         {q3}, [r2]!
+        bne             4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        // Reload ptrs from arguments on the stack
+        ldr             lr,       [sp, #108]
+        // Rotate the window of pointers. Shift the 6 pointers downwards one step.
+        ldrd            r6,  r7,  [lr, #4]
+        ldrd            r8,  r9,  [lr, #12]
+        ldrd            r10, r11, [lr, #20]
+
+        strd            r6,  r7,  [lr]
+        strd            r8,  r9,  [lr, #8]
+        strd            r10, r11, [lr, #16]
+        // The topmost pointer, ptrs[6], which isn't used as input, is set to
+        // ptrs[0], which will be used as output for the next _hv call.
+        // At the start of the filtering, the caller may set ptrs[6] to the
+        // right next buffer to fill in, instead.
+        str             r6,       [lr, #24]
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+#include "looprestoration_tmpl.S"
+
+// void dav1d_sgr_box3_row_h_16bpc_neon(int32_t *sumsq, int16_t *sum,
+//                                      const pixel (*left)[4],
+//                                      const pixel *src, const int w,
+//                                      const enum LrEdgeFlags edges);
+function sgr_box3_row_h_16bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldrd            r4,  r5,  [sp, #12]
+        add             r4,  r4,  #2 // w += 2
+
+        tst             r5,  #1 // LR_HAVE_LEFT
+        beq             1f
+        cmp             r2,  #0
+        bne             0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             r3,  r3,  #4
+        vld1.8          {q0, q1}, [r3]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.8          {q0, q1}, [r3]!
+        vld1.16         {d5},     [r2]
+        // Move r3 back to account for the last 2 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             r3,  r3,  #4
+        vext.8          q1,  q0,  q1,  #12
+        vext.8          q0,  q2,  q0,  #12
+        b               2f
+
+1:
+        vld1.8          {q0, q1}, [r3]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost pixel
+        // and shift q0/q1 to have 2x the first pixel at the front.
+        vdup.16         q2,  d0[0]
+        // Move r3 back to account for the last 2 pixels we loaded before,
+        // which we shifted out.
+        sub             r3,  r3,  #4
+        vext.8          q1,  q0,  q1,  #12
+        vext.8          q0,  q2,  q0,  #12
+
+2:
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        bne             4f
+        // If we'll need to pad the right edge, load that pixel to pad with
+        // here since we can find it pretty easily from here.
+        sub             lr,  r4,  #(2 + 16 - 2 + 1)
+        lsl             lr,  lr,  #1
+        ldrh            lr,  [r3,  lr]
+        // Fill q14 with the right padding pixel
+        vdup.16         q14, lr
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r4,  #10
+        bge             4f   // If w >= 10, all used input pixels are valid
+
+        // 1 <= w < 10, w pixels valid in q0-q1. For w=9, this ends up called
+        // again; it's not strictly needed in those cases (we pad enough here),
+        // but keeping the code as simple as possible.
+
+        // Insert padding in q0.h[w] onwards
+        movrel_local    lr,  right_ext_mask
+        sub             lr,  lr,  r4,  lsl #1
+        vld1.8          {q12, q13}, [lr]
+
+        vbit            q0,  q14, q12
+        vbit            q1,  q14, q13
+
+4:      // Loop horizontally
+        vext.8          q8,  q0,  q1,  #2
+        vext.8          q9,  q0,  q1,  #4
+
+        vadd.i16        q2,  q0,  q8
+        vmull.u16       q12, d0,  d0
+        vmlal.u16       q12, d16, d16
+        vmlal.u16       q12, d18, d18
+        vadd.i16        q2,  q2,  q9
+        vmull.u16       q13, d1,  d1
+        vmlal.u16       q13, d17, d17
+        vmlal.u16       q13, d19, d19
+        subs            r4,  r4,  #8
+        vst1.16         {q2},       [r1,  :128]!
+        vst1.32         {q12, q13}, [r0,  :128]!
+
+        ble             9f
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        vmov            q0,  q1
+        vld1.16         {q1}, [r3]!
+
+        bne             4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        pop             {r4-r5,pc}
+endfunc
+
+// void dav1d_sgr_box5_row_h_16bpc_neon(int32_t *sumsq, int16_t *sum,
+//                                      const pixel (*left)[4],
+//                                      const pixel *src, const int w,
+//                                      const enum LrEdgeFlags edges);
+function sgr_box5_row_h_16bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldrd            r4,  r5,  [sp, #12]
+        add             r4,  r4,  #2 // w += 2
+
+        tst             r5,  #1 // LR_HAVE_LEFT
+        beq             1f
+        cmp             r2,  #0
+        bne             0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             r3,  r3,  #6
+        vld1.8          {q0, q1}, [r3]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.8          {q0, q1}, [r3]!
+        vld1.16         {d5},     [r2]
+        // Move r3 back to account for the last 2 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             r3,  r3,  #6
+        vext.8          q1,  q0,  q1,  #10
+        vext.8          q0,  q2,  q0,  #10
+        b               2f
+
+1:
+        vld1.8          {q0, q1}, [r3]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost pixel
+        // and shift q0/q1 to have 3x the first pixel at the front.
+        vdup.16         q2,  d0[0]
+        // Move r3 back to account for the last 3 pixels we loaded before,
+        // which we shifted out.
+        sub             r3,  r3,  #6
+        vext.8          q1,  q0,  q1,  #10
+        vext.8          q0,  q2,  q0,  #10
+
+2:
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        bne             4f
+        // If we'll need to pad the right edge, load that pixel to pad with
+        // here since we can find it pretty easily from here.
+        sub             lr,  r4,  #(2 + 16 - 3 + 1)
+        lsl             lr,  lr,  #1
+        ldrh            lr,  [r3,  lr]
+        // Fill q14 with the right padding pixel
+        vdup.16         q14, lr
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r4,  #11
+        bge             4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+1 pixels valid in q0-q1. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // Insert padding in q0.h[w+1] onwards; fuse the +1 into the
+        // buffer pointer.
+        movrel_local    lr,  right_ext_mask, -2
+        sub             lr,  lr,  r4,  lsl #1
+        vld1.8          {q12, q13}, [lr]
+
+        vbit            q0,  q14, q12
+        vbit            q1,  q14, q13
+
+4:      // Loop horizontally
+        vext.8          q8,  q0,  q1,  #2
+        vext.8          q9,  q0,  q1,  #4
+
+        vadd.i16        q2,  q0,  q8
+        vmull.u16       q12, d0,  d0
+        vmlal.u16       q12, d16, d16
+        vmlal.u16       q12, d18, d18
+        vadd.i16        q2,  q2,  q9
+        vmull.u16       q13, d1,  d1
+        vmlal.u16       q13, d17, d17
+        vmlal.u16       q13, d19, d19
+
+        vext.8          q8,  q0,  q1,  #6
+        vext.8          q9,  q0,  q1,  #8
+
+        vadd.i16        q2,  q2,  q8
+        vmlal.u16       q12, d16, d16
+        vmlal.u16       q12, d1,  d1
+        vadd.i16        q2,  q2,  q9
+        vmlal.u16       q13, d17, d17
+        vmlal.u16       q13, d19, d19
+
+        subs            r4,  r4,  #8
+        vst1.16         {q2},       [r1,  :128]!
+        vst1.32         {q12, q13}, [r0,  :128]!
+
+        ble             9f
+        tst             r5,  #2 // LR_HAVE_RIGHT
+        vmov            q0,  q1
+        vld1.16         {q1}, [r3]!
+        bne             4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        pop             {r4-r5,pc}
+endfunc
+
+// void dav1d_sgr_box35_row_h_16bpc_neon(int32_t *sumsq3, int16_t *sum3,
+//                                       int32_t *sumsq5, int16_t *sum5,
+//                                       const pixel (*left)[4],
+//                                       const pixel *src, const int w,
+//                                       const enum LrEdgeFlags edges);
+function sgr_box35_row_h_16bpc_neon, export=1
+        push            {r4-r7,lr}
+        ldrd            r4,  r5,  [sp, #20]
+        ldrd            r6,  r7,  [sp, #28]
+        add             r6,  r6,  #2 // w += 2
+
+        tst             r7,  #1 // LR_HAVE_LEFT
+        beq             1f
+        cmp             r4,  #0
+        bne             0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             r5,  r5,  #6
+        vld1.8          {q0, q1}, [r5]!
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        vld1.8          {q0, q1}, [r5]!
+        vld1.16         {d5},     [r4]
+        // Move r3 back to account for the last 2 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             r5,  r5,  #6
+        vext.8          q1,  q0,  q1,  #10
+        vext.8          q0,  q2,  q0,  #10
+        b               2f
+
+1:
+        vld1.8          {q0, q1}, [r5]!
+        // !LR_HAVE_LEFT, fill q1 with the leftmost pixel
+        // and shift q0/q1 to have 3x the first pixel at the front.
+        vdup.16         q2,  d0[0]
+        // Move r3 back to account for the last 3 pixels we loaded before,
+        // which we shifted out.
+        sub             r5,  r5,  #6
+        vext.8          q1,  q0,  q1,  #10
+        vext.8          q0,  q2,  q0,  #10
+
+2:
+        tst             r7,  #2 // LR_HAVE_RIGHT
+        bne             4f
+        // If we'll need to pad the right edge, load that pixel to pad with
+        // here since we can find it pretty easily from here.
+        sub             lr,  r6,  #(2 + 16 - 3 + 1)
+        lsl             lr,  lr,  #1
+        ldrh            lr,  [r5,  lr]
+        // Fill q14 with the right padding pixel
+        vdup.16         q14, lr
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             r6,  #11
+        bge             4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+1 pixels valid in q0-q1. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // Insert padding in q0.h[w+1] onwards; fuse the +1 into the
+        // buffer pointer.
+        movrel_local    lr,  right_ext_mask, -2
+        sub             lr,  lr,  r6,  lsl #1
+        vld1.8          {q12, q13}, [lr]
+
+        vbit            q0,  q14, q12
+        vbit            q1,  q14, q13
+
+4:      // Loop horizontally
+        vext.8          q8,  q0,  q1,  #2
+        vext.8          q9,  q0,  q1,  #4
+        vext.8          q10, q0,  q1,  #6
+        vext.8          q11, q0,  q1,  #8
+
+        vadd.i16        q2,  q8,  q9
+        vadd.i16        q3,  q0,  q11
+        vadd.i16        q2,  q2,  q10
+
+        vmull.u16       q12, d16, d16
+        vmlal.u16       q12, d18, d18
+        vmlal.u16       q12, d20, d20
+        vmull.u16       q13, d17, d17
+        vmlal.u16       q13, d19, d19
+        vmlal.u16       q13, d21, d21
+
+        vadd.i16        q3,  q3,  q2
+        vst1.16         {q2},       [r1,  :128]!
+        vst1.32         {q12, q13}, [r0,  :128]!
+
+        vmlal.u16       q12, d0,  d0
+        vmlal.u16       q12, d22, d22
+        vmlal.u16       q13, d1,  d1
+        vmlal.u16       q13, d23, d23
+
+        subs            r6,  r6,  #8
+        vst1.16         {q3},       [r3,  :128]!
+        vst1.32         {q12, q13}, [r2,  :128]!
+
+        ble             9f
+        tst             r7,  #2 // LR_HAVE_RIGHT
+        vmov            q0,  q1
+        vld1.16         {q1}, [r5]!
+        bne             4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        pop             {r4-r7,pc}
+endfunc
+
+sgr_funcs 16
diff --git a/media/libdav1d/src/src/arm/32/looprestoration_common.S b/media/libdav1d/src/src/arm/32/looprestoration_common.S
new file mode 100644
index 0000000000..417103957f
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/looprestoration_common.S
@@ -0,0 +1,216 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// void dav1d_sgr_box3_row_v_neon(int32_t **sumsq, int16_t **sum,
+//                                int32_t *sumsq_out, int16_t *sum_out,
+//                                const int w);
+function sgr_box3_row_v_neon, export=1
+        push            {r4-r9,lr}
+        ldr             r4,  [sp, #28]
+        ldrd            r6,  r7,  [r0]
+        ldr             r0,       [r0, #8]
+        add             r4,  r4,  #2
+        ldrd            r8,  r9,  [r1]
+        ldr             r1,       [r1, #8]
+
+1:
+        vld1.32         {q8,  q9},  [r6]!
+        vld1.32         {q10, q11}, [r7]!
+        vld1.16         {q14},      [r8]!
+        vld1.16         {q15},      [r9]!
+        subs            r4,  r4,  #8
+
+        vadd.i32        q8, q8, q10
+        vadd.i32        q9, q9, q11
+
+        vld1.32         {q12, q13}, [r0]!
+
+        vadd.i16        q14, q14, q15
+
+        vld1.16         {q15},      [r1]!
+        vadd.i32        q8,  q8,  q12
+        vadd.i32        q9,  q9,  q13
+        vadd.i16        q14, q14, q15
+
+        vst1.32         {q8,  q9},  [r2]!
+        vst1.16         {q14},      [r3]!
+
+        bgt             1b
+        pop             {r4-r9,pc}
+endfunc
+
+// void dav1d_sgr_box5_row_v_neon(int32_t **sumsq, int16_t **sum,
+//                                int32_t *sumsq_out, int16_t *sum_out,
+//                                const int w);
+function sgr_box5_row_v_neon, export=1
+        push            {r4-r11,lr}
+        ldr             lr,  [sp, #36]
+
+        ldrd            r4,  r5,  [r0]
+        ldrd            r6,  r7,  [r0, #8]
+        ldr             r0,       [r0, #16]
+        add             lr,  lr,  #2
+        ldrd            r8,  r9,  [r1]
+        ldrd            r10, r11, [r1, #8]
+        ldr             r1,       [r1, #16]
+
+1:
+        vld1.32         {q8,  q9},  [r4]!
+        vld1.32         {q10, q11}, [r5]!
+        vld1.32         {q12, q13}, [r6]!
+        vld1.32         {q14, q15}, [r7]!
+        vld1.16         {q0},       [r8]!
+        vld1.16         {q1},       [r9]!
+        vld1.16         {q2},       [r10]!
+        vld1.16         {q3},       [r11]!
+        subs            lr,  lr,  #8
+
+        vadd.i32        q8,  q8,  q10
+        vadd.i32        q9,  q9,  q11
+        vadd.i32        q12, q12, q14
+        vadd.i32        q13, q13, q15
+
+        vld1.32         {q14, q15}, [r0]!
+
+        vadd.i16        q0,  q0,  q1
+        vadd.i16        q2,  q2,  q3
+
+        vld1.16         {q3},       [r1]!
+        vadd.i32        q8,  q8,  q12
+        vadd.i32        q9,  q9,  q13
+        vadd.i16        q0,  q0,  q2
+
+        vadd.i32        q8,  q8,  q14
+        vadd.i32        q9,  q9,  q15
+        vadd.i16        q0,  q0,  q3
+
+        vst1.32         {q8,  q9},  [r2]!
+        vst1.16         {q0},       [r3]!
+
+        bgt             1b
+        pop             {r4-r11,pc}
+endfunc
+
+// void dav1d_sgr_calc_row_ab1_neon(int32_t *a, int16_t *b,
+//                                  const int w, const int strength,
+//                                  const int bitdepth_max);
+// void dav1d_sgr_calc_row_ab2_neon(int32_t *a, int16_t *b,
+//                                  const int w, const int strength,
+//                                  const int bitdepth_max);
+function sgr_calc_row_ab1_neon, export=1
+        push            {r4-r7,lr}
+        vpush           {q4-q7}
+        ldr             r4,  [sp, #84]
+        clz             r6,  r4
+        vmov.i32        q15, #9        // n
+        movw            r5,  #455
+        b               sgr_calc_ab_neon
+endfunc
+
+function sgr_calc_row_ab2_neon, export=1
+        push            {r4-r7,lr}
+        vpush           {q4-q7}
+        ldr             r4,  [sp, #84]
+        clz             r6,  r4
+        vmov.i32        q15, #25       // n
+        mov             r5,  #164
+endfunc
+
+function sgr_calc_ab_neon
+        movrel          r12, X(sgr_x_by_x)
+        sub             r6,  r6,  #24  // -bitdepth_min_8
+        vld1.8          {q8, q9}, [r12, :128]!
+        add             r7,  r6,  r6   // -2*bitdepth_min_8
+        vmov.i8         q11, #5
+        vmov.i8         d10, #55       // idx of last 5
+        vld1.8          {q10},    [r12, :128]
+        vmov.i8         d11, #72       // idx of last 4
+        vmov.i8         d12, #101      // idx of last 3
+        vmov.i8         d13, #169      // idx of last 2
+        vmov.i8         d14, #254      // idx of last 1
+        vmov.i8         d15, #32       // elements consumed in first vtbl
+        add             r2,  r2,  #2   // w += 2
+        vdup.32         q12, r3
+        vsub.i8         q8,  q8,  q11
+        vsub.i8         q9,  q9,  q11
+        vsub.i8         q10, q10, q11
+        vdup.32         q13, r7        // -2*bitdepth_min_8
+1:
+        vld1.32         {q0, q1}, [r0, :128] // a
+        vld1.16         {q2},     [r1, :128] // b
+        vdup.16         q14, r6        // -bitdepth_min_8
+        subs            r2,  r2,  #8
+        vrshl.s32       q0,  q0,  q13
+        vrshl.s32       q1,  q1,  q13
+        vrshl.s16       q4,  q2,  q14
+        vmul.i32        q0,  q0,  q15  // a * n
+        vmul.i32        q1,  q1,  q15  // a * n
+        vmull.u16       q3,  d8,  d8   // b * b
+        vmull.u16       q4,  d9,  d9   // b * b
+        vqsub.u32       q0,  q0,  q3   // imax(a * n - b * b, 0)
+        vqsub.u32       q1,  q1,  q4   // imax(a * n - b * b, 0)
+        vmul.i32        q0,  q0,  q12  // p * s
+        vmul.i32        q1,  q1,  q12  // p * s
+        vqshrn.u32      d0,  q0,  #16
+        vqshrn.u32      d1,  q1,  #16
+        vqrshrn.u16     d0,  q0,  #4   // imin(z, 255)
+
+        vcgt.u8         d2,  d0,  d10  // = -1 if sgr_x_by_x[d0] < 5
+        vcgt.u8         d3,  d0,  d11  // = -1 if sgr_x_by_x[d0] < 4
+        vtbl.8          d1,  {q8, q9}, d0
+        vcgt.u8         d6,  d0,  d12  // = -1 if sgr_x_by_x[d0] < 3
+        vsub.i8         d9,  d0,  d15  // indices for vtbx
+        vcgt.u8         d7,  d0,  d13  // = -1 if sgr_x_by_x[d0] < 2
+        vadd.i8         d2,  d2,  d3
+        vtbx.8          d1,  {q10}, d9
+        vcgt.u8         d8,  d0,  d14  // = -1 if sgr_x_by_x[d0] < 1
+        vadd.i8         d6,  d6,  d7
+        vadd.i8         d8,  d8,  d22
+        vadd.i8         d2,  d2,  d6
+        vadd.i8         d1,  d1,  d8
+        vadd.i8         d1,  d1,  d2
+        vmovl.u8        q0,  d1        // x
+
+        vdup.32         q14, r5        // one_by_x
+
+        vmull.u16       q1,  d0,  d4   // x * BB[i]
+        vmull.u16       q2,  d1,  d5   // x * BB[i]
+        vmul.i32        q1,  q1,  q14  // x * BB[i] * sgr_one_by_x
+        vmul.i32        q2,  q2,  q14  // x * BB[i] * sgr_one_by_x
+        vrshr.s32       q1,  q1,  #12  // AA[i]
+        vrshr.s32       q2,  q2,  #12  // AA[i]
+
+        vst1.32         {q1, q2}, [r0, :128]!
+        vst1.16         {q0},     [r1, :128]!
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r7,pc}
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/looprestoration_tmpl.S b/media/libdav1d/src/src/arm/32/looprestoration_tmpl.S
new file mode 100644
index 0000000000..cd2b38350d
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/looprestoration_tmpl.S
@@ -0,0 +1,410 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+
+#define FILTER_OUT_STRIDE 384
+
+.macro sgr_funcs bpc
+// void dav1d_sgr_finish_filter_row1_Xbpc_neon(int16_t *tmp,
+//                                             const pixel *src,
+//                                             const int32_t **a, const int16_t **b,
+//                                             const int w);
+function sgr_finish_filter_row1_\bpc\()bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldr             r4,  [sp, #100]
+        ldrd            r6,  r7,  [r2]
+        ldr             r2,       [r2, #8]
+        ldrd            r8,  r9,  [r3]
+        ldr             r3,       [r3, #8]
+        vmov.i16        q14, #3
+        vmov.i32        q15, #3
+1:
+        vld1.16         {q0},       [r8,  :128]!
+        vld1.16         {q1},       [r9,  :128]!
+        vld1.16         {q2},       [r3,  :128]!
+        vld1.32         {q8,  q9},  [r6,  :128]!
+        vld1.32         {q10, q11}, [r7,  :128]!
+        vld1.32         {q12, q13}, [r2,  :128]!
+
+2:
+        subs            r4,  r4,  #4
+        vext.8          d6,  d0,  d1,  #2  // -stride
+        vext.8          d7,  d2,  d3,  #2  // 0
+        vext.8          d8,  d4,  d5,  #2  // +stride
+        vext.8          d9,  d0,  d1,  #4  // +1-stride
+        vext.8          d10, d2,  d3,  #4  // +1
+        vext.8          d11, d4,  d5,  #4  // +1+stride
+        vadd.i16        d2,  d2,  d6       // -1, -stride
+        vadd.i16        d7,  d7,  d8       // 0, +stride
+        vadd.i16        d0,  d0,  d9       // -1-stride, +1-stride
+        vadd.i16        d2,  d2,  d7
+        vadd.i16        d4,  d4,  d11      // -1+stride, +1+stride
+        vadd.i16        d2,  d2,  d10      // +1
+        vadd.i16        d0,  d0,  d4
+
+        vext.8          q3,  q8,  q9,  #4  // -stride
+        vshl.i16        d2,  d2,  #2
+        vext.8          q4,  q8,  q9,  #8  // +1-stride
+        vext.8          q5,  q10, q11, #4  // 0
+        vext.8          q6,  q10, q11, #8  // +1
+        vmla.i16        d2,  d0,  d28      // * 3 -> a
+        vadd.i32        q3,  q3,  q10      // -stride, -1
+        vadd.i32        q8,  q8,  q4       // -1-stride, +1-stride
+        vadd.i32        q5,  q5,  q6       // 0, +1
+        vadd.i32        q8,  q8,  q12      // -1+stride
+        vadd.i32        q3,  q3,  q5
+        vext.8          q7,  q12, q13, #4  // +stride
+        vext.8          q10, q12, q13, #8  // +1+stride
+.if \bpc == 8
+        vld1.32         {d24[0]}, [r1, :32]! // src
+.else
+        vld1.16         {d24}, [r1, :64]!    // src
+.endif
+        vadd.i32        q3,  q3,  q7       // +stride
+        vadd.i32        q8,  q8,  q10      // +1+stride
+        vshl.i32        q3,  q3,  #2
+        vmla.i32        q3,  q8,  q15      // * 3 -> b
+.if \bpc == 8
+        vmovl.u8        q12, d24           // src
+.endif
+        vmov            d0,  d1
+        vmlsl.u16       q3,  d2,  d24      // b - a * src
+        vmov            d2,  d3
+        vrshrn.i32      d6,  q3,  #9
+        vmov            d4,  d5
+        vst1.16         {d6}, [r0]!
+
+        ble             3f
+        vmov            q8,  q9
+        vmov            q10, q11
+        vmov            q12, q13
+        vld1.16         {d1},  [r8,  :64]!
+        vld1.16         {d3},  [r9,  :64]!
+        vld1.16         {d5},  [r3,  :64]!
+        vld1.32         {q9},  [r6,  :128]!
+        vld1.32         {q11}, [r7,  :128]!
+        vld1.32         {q13}, [r2,  :128]!
+        b               2b
+
+3:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+// void dav1d_sgr_finish_filter2_2rows_Xbpc_neon(int16_t *tmp,
+//                                               const pixel *src, const ptrdiff_t stride,
+//                                               const int32_t **a, const int16_t **b,
+//                                               const int w, const int h);
+function sgr_finish_filter2_2rows_\bpc\()bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]
+        ldr             r6,  [sp, #108]
+        ldrd            r8,  r9,  [r3]
+        ldrd            r10, r11, [r4]
+        mov             r7,  #2*FILTER_OUT_STRIDE
+        add             r2,  r1,  r2
+        add             r7,  r7,  r0
+        mov             lr,  r5
+
+1:
+        vld1.16         {q0,  q1},  [r10, :128]!
+        vld1.16         {q2,  q3},  [r11, :128]!
+        vld1.32         {q8,  q9},  [r8,  :128]!
+        vld1.32         {q11, q12}, [r9,  :128]!
+        vld1.32         {q10},      [r8,  :128]!
+        vld1.32         {q13},      [r9,  :128]!
+
+2:
+        vmov.i16        q14, #5
+        vmov.i16        q15, #6
+        subs            r5,  r5,  #8
+        vext.8          q4,  q0,  q1,  #4  // +1-stride
+        vext.8          q5,  q2,  q3,  #4  // +1+stride
+        vext.8          q6,  q0,  q1,  #2  // -stride
+        vext.8          q7,  q2,  q3,  #2  // +stride
+        vadd.i16        q0,  q0,  q4       // -1-stride, +1-stride
+        vadd.i16        q5,  q2,  q5       // -1+stride, +1+stride
+        vadd.i16        q2,  q6,  q7       // -stride, +stride
+        vadd.i16        q0,  q0,  q5
+
+        vext.8          q4,  q8,  q9,  #8  // +1-stride
+        vext.8          q5,  q9,  q10, #8
+        vext.8          q6,  q11, q12, #8  // +1+stride
+        vext.8          q7,  q12, q13, #8
+        vmul.i16        q0,  q0,  q14      // * 5
+        vmla.i16        q0,  q2,  q15      // * 6
+        vadd.i32        q4,  q4,  q8       // -1-stride, +1-stride
+        vadd.i32        q5,  q5,  q9
+        vadd.i32        q6,  q6,  q11      // -1+stride, +1+stride
+        vadd.i32        q7,  q7,  q12
+        vadd.i32        q4,  q4,  q6
+        vadd.i32        q5,  q5,  q7
+        vext.8          q6,  q8,  q9,  #4  // -stride
+        vext.8          q7,  q9,  q10, #4
+        vext.8          q8,  q11, q12, #4  // +stride
+        vext.8          q11, q12, q13, #4
+
+.if \bpc == 8
+        vld1.8          {d4}, [r1, :64]!
+.else
+        vld1.8          {q2}, [r1, :128]!
+.endif
+
+        vmov.i32        q14, #5
+        vmov.i32        q15, #6
+
+        vadd.i32        q6,  q6,  q8       // -stride, +stride
+        vadd.i32        q7,  q7,  q11
+        vmul.i32        q4,  q4,  q14      // * 5
+        vmla.i32        q4,  q6,  q15      // * 6
+        vmul.i32        q5,  q5,  q14      // * 5
+        vmla.i32        q5,  q7,  q15      // * 6
+
+.if \bpc == 8
+        vmovl.u8        q2,  d4
+.endif
+        vmlsl.u16       q4,  d0,  d4       // b - a * src
+        vmlsl.u16       q5,  d1,  d5       // b - a * src
+        vmov            q0,  q1
+        vrshrn.i32      d8,  q4,  #9
+        vrshrn.i32      d9,  q5,  #9
+        vmov            q2,  q3
+        vst1.16         {q4}, [r0, :128]!
+
+        ble             3f
+        vmov            q8,  q10
+        vmov            q11, q13
+        vld1.16         {q1},       [r10, :128]!
+        vld1.16         {q3},       [r11, :128]!
+        vld1.32         {q9,  q10}, [r8,  :128]!
+        vld1.32         {q12, q13}, [r9,  :128]!
+        b               2b
+
+3:
+        subs            r6,  r6,  #1
+        ble             0f
+        mov             r5,  lr
+        ldrd            r8,  r9,  [r3]
+        ldrd            r10, r11, [r4]
+        mov             r0,  r7
+        mov             r1,  r2
+
+        vld1.32         {q8, q9}, [r9,  :128]!
+        vld1.16         {q0, q1}, [r11, :128]!
+        vld1.32         {q10},    [r9,  :128]!
+
+        vmov.i16        q12, #5
+        vmov.i16        q13, #6
+
+4:
+        subs            r5,  r5,  #8
+        vext.8          q3,  q0,  q1,  #4  // +1
+        vext.8          q2,  q0,  q1,  #2  // 0
+        vadd.i16        q0,  q0,  q3       // -1, +1
+
+        vext.8          q4,  q8,  q9,  #4  // 0
+        vext.8          q5,  q9,  q10, #4
+        vext.8          q6,  q8,  q9,  #8  // +1
+        vext.8          q7,  q9,  q10, #8
+        vmul.i16        q2,  q2,  q13      // * 6
+        vmla.i16        q2,  q0,  q12      // * 5 -> a
+.if \bpc == 8
+        vld1.8          {d22}, [r1, :64]!
+.else
+        vld1.16         {q11}, [r1, :128]!
+.endif
+        vadd.i32        q8,  q8,  q6       // -1, +1
+        vadd.i32        q9,  q9,  q7
+.if \bpc == 8
+        vmovl.u8        q11, d22
+.endif
+        vmul.i32        q4,  q4,  q15      // * 6
+        vmla.i32        q4,  q8,  q14      // * 5 -> b
+        vmul.i32        q5,  q5,  q15      // * 6
+        vmla.i32        q5,  q9,  q14      // * 5 -> b
+
+        vmlsl.u16       q4,  d4,  d22      // b - a * src
+        vmlsl.u16       q5,  d5,  d23
+        vmov            q0,  q1
+        vrshrn.i32      d8,  q4,  #8
+        vrshrn.i32      d9,  q5,  #8
+        vmov            q8,  q10
+        vst1.16         {q4}, [r0, :128]!
+
+        ble             5f
+        vld1.16         {q1},      [r11, :128]!
+        vld1.32         {q9, q10}, [r9,  :128]!
+        b               4b
+
+5:
+0:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+
+// void dav1d_sgr_weighted_row1_Xbpc_neon(pixel *dst,
+//                                        const int16_t *t1, const int w,
+//                                        const int w1, const int bitdepth_max);
+function sgr_weighted_row1_\bpc\()bpc_neon, export=1
+        push            {lr}
+.if \bpc == 16
+        ldr             lr,  [sp, #4]
+.endif
+        vdup.16         d31, r3
+.if \bpc == 16
+        vmov.i16        q13, #0
+        vdup.16         q14, lr
+.endif
+
+1:
+.if \bpc == 8
+        vld1.8          {d0}, [r0, :64]
+.else
+        vld1.16         {q0}, [r0, :128]
+.endif
+        vld1.16         {q1}, [r1, :128]!
+        subs            r2,  r2,  #8
+        vmull.s16       q2,  d2,  d31    // v
+        vmull.s16       q3,  d3,  d31    // v
+        vrshrn.i32      d4,  q2,  #11
+        vrshrn.i32      d5,  q3,  #11
+.if \bpc == 8
+        vaddw.u8        q2,  q2,  d0
+        vqmovun.s16     d2,  q2
+        vst1.8          {d2}, [r0, :64]!
+.else
+        vadd.i16        q2,  q2,  q0
+        vmax.s16        q2,  q2,  q13
+        vmin.u16        q2,  q2,  q14
+        vst1.16         {q2}, [r0, :128]!
+.endif
+        bgt             1b
+0:
+        pop             {pc}
+endfunc
+
+// void dav1d_sgr_weighted2_Xbpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                    const int16_t *t1, const int16_t *t2,
+//                                    const int w, const int h,
+//                                    const int16_t wt[2], const int bitdepth_max);
+function sgr_weighted2_\bpc\()bpc_neon, export=1
+        push            {r4-r8,lr}
+        ldrd            r4,  r5,  [sp, #24]
+.if \bpc == 8
+        ldr             r6,  [sp, #32]
+.else
+        ldrd            r6,  r7,  [sp, #32]
+.endif
+        cmp             r5,  #2
+        add             r8,  r0,  r1
+        add             r12, r2,  #2*FILTER_OUT_STRIDE
+        add             lr,  r3,  #2*FILTER_OUT_STRIDE
+        vld2.16         {d30[], d31[]}, [r6] // wt[0], wt[1]
+.if \bpc == 16
+        vdup.16         q14, r7
+.endif
+        blt             2f
+1:
+.if \bpc == 8
+        vld1.8          {d0},  [r0,  :64]
+        vld1.8          {d16}, [r8,  :64]
+.else
+        vld1.16         {q0},  [r0,  :128]
+        vld1.16         {q8},  [r8,  :128]
+.endif
+        vld1.16         {q1},  [r2,  :128]!
+        vld1.16         {q9},  [r12, :128]!
+        vld1.16         {q2},  [r3,  :128]!
+        vld1.16         {q10}, [lr,  :128]!
+        subs            r4,  r4,  #8
+        vmull.s16       q3,  d2,  d30    // wt[0] * t1
+        vmlal.s16       q3,  d4,  d31    // wt[1] * t2
+        vmull.s16       q12, d3,  d30    // wt[0] * t1
+        vmlal.s16       q12, d5,  d31    // wt[1] * t2
+        vmull.s16       q11, d18, d30    // wt[0] * t1
+        vmlal.s16       q11, d20, d31    // wt[1] * t2
+        vmull.s16       q13, d19, d30    // wt[0] * t1
+        vmlal.s16       q13, d21, d31    // wt[1] * t2
+        vrshrn.i32      d6,  q3,  #11
+        vrshrn.i32      d7,  q12, #11
+        vrshrn.i32      d22, q11, #11
+        vrshrn.i32      d23, q13, #11
+.if \bpc == 8
+        vaddw.u8        q3,  q3,  d0
+        vaddw.u8        q11, q11, d16
+        vqmovun.s16     d6,  q3
+        vqmovun.s16     d22, q11
+        vst1.8          {d6},  [r0,  :64]!
+        vst1.8          {d22}, [r8,  :64]!
+.else
+        vmov.i16        q13, #0
+        vadd.i16        q3,  q3,  q0
+        vadd.i16        q11, q11, q8
+        vmax.s16        q3,  q3,  q13
+        vmax.s16        q11, q11, q13
+        vmin.u16        q3,  q3,  q14
+        vmin.u16        q11, q11, q14
+        vst1.16         {q3},  [r0,  :128]!
+        vst1.16         {q11}, [r8,  :128]!
+.endif
+        bgt             1b
+        b               0f
+
+2:
+.if \bpc == 8
+        vld1.8          {d0}, [r0, :64]
+.else
+        vld1.16         {q0}, [r0, :128]
+.endif
+        vld1.16         {q1}, [r2, :128]!
+        vld1.16         {q2}, [r3, :128]!
+        subs            r4,  r4,  #8
+        vmull.s16       q3,  d2,  d30    // wt[0] * t1
+        vmlal.s16       q3,  d4,  d31    // wt[1] * t2
+        vmull.s16       q11, d3,  d30    // wt[0] * t1
+        vmlal.s16       q11, d5,  d31    // wt[1] * t2
+        vrshrn.i32      d6,  q3,  #11
+        vrshrn.i32      d7,  q11, #11
+.if \bpc == 8
+        vaddw.u8        q3,  q3,  d0
+        vqmovun.s16     d6,  q3
+        vst1.8          {d6}, [r0, :64]!
+.else
+        vmov.i16        q13, #0
+        vadd.i16        q3,  q3,  q0
+        vmax.s16        q3,  q3,  q13
+        vmin.u16        q3,  q3,  q14
+        vst1.16         {q3}, [r0, :128]!
+.endif
+        bgt             2b
+0:
+        pop             {r4-r8,pc}
+endfunc
+.endm
diff --git a/media/libdav1d/src/src/arm/32/mc.S b/media/libdav1d/src/src/arm/32/mc.S
new file mode 100644
index 0000000000..1b60a7bdb3
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/mc.S
@@ -0,0 +1,3340 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * Copyright © 2018, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+.macro avg dst0, dst1, t0, t1, t2, t3
+        vld1.16         {\t0,\t1},   [r2, :128]!
+        vld1.16         {\t2,\t3},   [r3, :128]!
+        vadd.i16        \t0,   \t0,  \t2
+        vadd.i16        \t1,   \t1,  \t3
+        vqrshrun.s16    \dst0, \t0,  #5
+        vqrshrun.s16    \dst1, \t1,  #5
+.endm
+
+.macro w_avg dst0, dst1, t0, t1, t2, t3
+        vld1.16         {\t0,\t1},   [r2, :128]!
+        vld1.16         {\t2,\t3},   [r3, :128]!
+        vsub.i16        \t0,   \t2,  \t0
+        vsub.i16        \t1,   \t3,  \t1
+        vqdmulh.s16     \t0,   \t0,  q15
+        vqdmulh.s16     \t1,   \t1,  q15
+        vadd.i16        \t0,   \t2,  \t0
+        vadd.i16        \t1,   \t3,  \t1
+        vqrshrun.s16    \dst0, \t0,  #4
+        vqrshrun.s16    \dst1, \t1,  #4
+.endm
+
+.macro mask dst0, dst1, t0, t1, t2, t3
+        vld1.8          {q14}, [lr, :128]!
+        vld1.16         {\t0,\t1},   [r2, :128]!
+        vmul.i8         q14,   q14,  q15
+        vld1.16         {\t2,\t3},   [r3, :128]!
+        vshll.i8        q13,   d28,  #8
+        vshll.i8        q14,   d29,  #8
+        vsub.i16        \t0,   \t2,  \t0
+        vsub.i16        \t1,   \t3,  \t1
+        vqdmulh.s16     \t0,   \t0,  q13
+        vqdmulh.s16     \t1,   \t1,  q14
+        vadd.i16        \t0,   \t2,  \t0
+        vadd.i16        \t1,   \t3,  \t1
+        vqrshrun.s16    \dst0, \t0,  #4
+        vqrshrun.s16    \dst1, \t1,  #4
+.endm
+
+.macro bidir_fn type
+function \type\()_8bpc_neon, export=1
+        push            {r4-r6,lr}
+        ldrd            r4,  r5,  [sp, #16]
+        clz             r4,  r4
+.ifnc \type, avg
+        ldr             lr, [sp, #24]
+.endif
+.ifc \type, w_avg
+        vdup.s16        q15, lr
+        vneg.s16        q15, q15
+        vshl.i16        q15, q15, #11
+.endif
+.ifc \type, mask
+        vmov.i8         q15, #256-2
+.endif
+        adr             r12, L(\type\()_tbl)
+        sub             r4,  r4,  #24
+        ldr             r4,  [r12, r4, lsl #2]
+        \type           d16, d17, q0,  q1,  q2,  q3
+        add             r12, r12, r4
+        bx              r12
+
+        .align 2
+L(\type\()_tbl):
+        .word 1280f - L(\type\()_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_tbl) + CONFIG_THUMB
+        .word 4f    - L(\type\()_tbl) + CONFIG_THUMB
+
+4:
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+        cmp             r5,  #4
+        vst1.32         {d16[0]},  [r0, :32], r1
+        vst1.32         {d16[1]},  [r6, :32], r1
+        vst1.32         {d17[0]},  [r0, :32], r1
+        vst1.32         {d17[1]},  [r6, :32], r1
+        beq             0f
+        \type           d18, d19,  q0,  q1,  q2,  q3
+        cmp             r5,  #8
+        vst1.32         {d18[0]},  [r0, :32], r1
+        vst1.32         {d18[1]},  [r6, :32], r1
+        vst1.32         {d19[0]},  [r0, :32], r1
+        vst1.32         {d19[1]},  [r6, :32], r1
+        beq             0f
+        \type           d16, d17, q0,  q1,  q2,  q3
+        vst1.32         {d16[0]},  [r0, :32], r1
+        vst1.32         {d16[1]},  [r6, :32], r1
+        \type           d18, d19,  q0,  q1,  q2,  q3
+        vst1.32         {d17[0]},  [r0, :32], r1
+        vst1.32         {d17[1]},  [r6, :32], r1
+        vst1.32         {d18[0]},  [r0, :32], r1
+        vst1.32         {d18[1]},  [r6, :32], r1
+        vst1.32         {d19[0]},  [r0, :32], r1
+        vst1.32         {d19[1]},  [r6, :32], r1
+        pop             {r4-r6,pc}
+80:
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+8:
+        vst1.8          {d16},  [r0, :64], r1
+        \type           d18, d19, q0,  q1,  q2,  q3
+        vst1.8          {d17},  [r6, :64], r1
+        vst1.8          {d18},  [r0, :64], r1
+        subs            r5,  r5,  #4
+        vst1.8          {d19},  [r6, :64], r1
+        ble             0f
+        \type           d16, d17, q0,  q1,  q2,  q3
+        b               8b
+160:
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+16:
+        \type           d18, d19, q0, q1, q2, q3
+        vst1.8          {q8},  [r0, :128], r1
+        \type           d20, d21, q0, q1, q2, q3
+        vst1.8          {q9},  [r6, :128], r1
+        \type           d22, d23, q0, q1, q2, q3
+        vst1.8          {q10}, [r0, :128], r1
+        subs            r5,  r5,  #4
+        vst1.8          {q11}, [r6, :128], r1
+        ble             0f
+        \type           d16, d17, q0, q1, q2, q3
+        b               16b
+320:
+        add             r6,  r0,  r1
+        lsl             r1,  r1,  #1
+32:
+        \type           d18, d19, q0, q1, q2, q3
+        \type           d20, d21, q0, q1, q2, q3
+        vst1.8          {q8,  q9},  [r0, :128], r1
+        \type           d22, d23, q0, q1, q2, q3
+        subs            r5,  r5,  #2
+        vst1.8          {q10, q11}, [r6, :128], r1
+        ble             0f
+        \type           d16, d17, q0, q1, q2, q3
+        b               32b
+640:
+        add             r6,  r0,  #32
+64:
+        \type           d18, d19, q0, q1, q2, q3
+        \type           d20, d21, q0, q1, q2, q3
+        \type           d22, d23, q0, q1, q2, q3
+        vst1.8          {q8,  q9},  [r0, :128], r1
+        \type           d16, d17, q0, q1, q2, q3
+        vst1.8          {q10, q11}, [r6, :128], r1
+        \type           d18, d19, q0, q1, q2, q3
+        \type           d20, d21, q0, q1, q2, q3
+        vst1.8          {q8,  q9},  [r0, :128], r1
+        \type           d22, d23, q0, q1, q2, q3
+        subs            r5,  r5,  #2
+        vst1.8          {q10, q11}, [r6, :128], r1
+        ble             0f
+        \type           d16, d17, q0, q1, q2, q3
+        b               64b
+1280:
+        sub             r1,  r1,  #32
+        add             r6,  r0,  #64
+128:
+        \type           d18, d19, q0, q1, q2, q3
+        \type           d20, d21, q0, q1, q2, q3
+        \type           d22, d23, q0, q1, q2, q3
+        vst1.8          {q8,  q9},  [r0, :128]!
+        \type           d16, d17, q0, q1, q2, q3
+        vst1.8          {q10, q11}, [r0, :128], r1
+        \type           d18, d19, q0, q1, q2, q3
+        \type           d20, d21, q0, q1, q2, q3
+        vst1.8          {q8,  q9},  [r6, :128]!
+        \type           d22, d23, q0, q1, q2, q3
+        subs            r5,  r5,  #1
+        vst1.8          {q10, q11}, [r6, :128], r1
+        ble             0f
+        \type           d16, d17, q0, q1, q2, q3
+        b               128b
+
+0:
+        pop             {r4-r6,pc}
+endfunc
+.endm
+
+bidir_fn avg
+bidir_fn w_avg
+bidir_fn mask
+
+
+.macro w_mask_fn type
+function w_mask_\type\()_8bpc_neon, export=1
+        push            {r4-r9,lr}
+        ldrd            r4,  r5,  [sp, #28]
+        ldrd            r6,  r7,  [sp, #36]
+        clz             r8,  r4
+        adr             r9,  L(w_mask_\type\()_tbl)
+        sub             r8,  r8,  #24
+        ldr             r8,  [r9,  r8,  lsl #2]
+        add             r9,  r9,  r8
+        movw            r12, #6903
+        vdup.16         q14, r12
+.if \type == 444
+        vmov.i8         q15, #64
+.elseif \type == 422
+        vdup.8          d0,  r7         // d0[] <- sign
+        vmov.i8         d30, #129
+        vsub.i8         d30, d30, d0    // 129 - sign
+.elseif \type == 420
+        vdup.16         q0,  r7         // d0[] <- sign
+        vmov.i16        q15, #256
+        vsub.i16        q15, q15, q0    // 256 - sign
+.endif
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        bx              r9
+
+        .align 2
+L(w_mask_\type\()_tbl):
+        .word 1280f  - L(w_mask_\type\()_tbl) + CONFIG_THUMB
+        .word 640f   - L(w_mask_\type\()_tbl) + CONFIG_THUMB
+        .word 320f   - L(w_mask_\type\()_tbl) + CONFIG_THUMB
+        .word 160f   - L(w_mask_\type\()_tbl) + CONFIG_THUMB
+        .word 8f     - L(w_mask_\type\()_tbl) + CONFIG_THUMB
+        .word 4f     - L(w_mask_\type\()_tbl) + CONFIG_THUMB
+
+4:
+        vld1.16         {d0,  d1,  d2,  d3},  [r2,  :128]! // tmp1 (four rows at once)
+        vld1.16         {d4,  d5,  d6,  d7},  [r3,  :128]! // tmp2 (four rows at once)
+        subs            r5,  r5,  #4
+        vsub.i16        q8,  q2,  q0    // tmp2-tmp1
+        vsub.i16        q9,  q3,  q1
+        vabd.s16        q10, q0,  q2    // (abs(tmp1[x] - tmp2[x]))
+        vabd.s16        q11, q1,  q3
+        vqsub.u16       q10, q14, q10   // 6903 - abs ()
+        vqsub.u16       q11, q14, q11
+        vshr.s16        q10, q10, #8    // 64-m = (6903 - abs()) >> 8
+        vshr.s16        q11, q11, #8
+        vshl.s16        q12, q10, #9    // (64-m)<<9
+        vshl.s16        q13, q11, #9
+        vqdmulh.s16     q12, q12, q8    // ((tmp2-tmp1)*(64-m)<<9)>>15
+        vqdmulh.s16     q13, q13, q9
+        vadd.i16        q12, q12, q0    // (((tmp2-tmp1)*(64-m)<<9)>>15) + tmp1
+        vadd.i16        q13, q13, q1
+        vqrshrun.s16    d24, q12, #4    // (((((tmp2-tmp1)*(64-m)<<9)>>15) + tmp1) + 8) >> 4
+        vqrshrun.s16    d25, q13, #4
+.if \type == 444
+        vmovn.u16       d20, q10        // 64 - m
+        vmovn.u16       d21, q11
+        vsub.i8         q10, q15, q10   // m
+        vst1.8          {d20, d21}, [r6,  :128]!
+.elseif \type == 422
+        vpadd.s16       d20, d20, d21   // (64 - m) + (64 - n) (column wise addition)
+        vpadd.s16       d21, d22, d23
+        vmovn.s16       d6,  q10
+        vhsub.u8        d6,  d30, d6    // ((129 - sign) - ((64 - m) + (64 - n))) >> 1
+        vst1.8          {d6},  [r6,  :64]!
+.elseif \type == 420
+        vadd.s16        d20, d20, d21   // (64 - my1) + (64 - my2) (row wise addition)
+        vadd.s16        d21, d22, d23
+        vpadd.s16       d20, d20, d21   // (128 - m) + (128 - n) (column wise addition)
+        vsub.s16        d20, d30, d20   // (256 - sign) - ((128 - m) + (128 - n))
+        vrshrn.u16      d20, q10,  #2   // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        vst1.32         {d20[0]}, [r6,  :32]!
+.endif
+        vst1.32         {d24[0]}, [r0,  :32], r1
+        vst1.32         {d24[1]}, [r12, :32], r1
+        vst1.32         {d25[0]}, [r0,  :32], r1
+        vst1.32         {d25[1]}, [r12, :32], r1
+        bgt             4b
+        pop             {r4-r9,pc}
+8:
+        vld1.16         {d0,  d1,  d2,  d3},  [r2,  :128]! // tmp1y1, tmp1y2
+        vld1.16         {d4,  d5,  d6,  d7},  [r3,  :128]! // tmp2y1, tmp2y2
+        subs            r5,  r5,  #2
+        vsub.i16        q8,  q2,  q0    // tmp2y1 - tmp1y1
+        vsub.i16        q9,  q3,  q1    // tmp2y2 - tmp1y2
+        vabd.s16        q10, q0,  q2    // abs(tmp1y1 - tmp2y1)
+        vabd.s16        q11, q1,  q3    // abs(tmp1y2 - tmp2y2)
+        vqsub.u16       q10, q14, q10   // 6903 - abs(tmp1y1 - tmp2y1)
+        vqsub.u16       q11, q14, q11   // 6903 - abs(tmp1y2 - tmp2y2)
+        vshr.s16        q10, q10, #8    // 64 - my1 = 6903 - abs(tmp1y1 - tmp2y1) >> 8
+        vshr.s16        q11, q11, #8    // 64 - my2 = 6903 - abs(tmp1y2 - tmp2y2) >> 8
+        vshl.s16        q12, q10, #9    // (64 - my1) << 9
+        vshl.s16        q13, q11, #9    // (64 - my2) << 9
+        vqdmulh.s16     q12, q12, q8    // ((tmp2y1 - tmp1y1) * (64 - my1) << 9) >> 15
+        vqdmulh.s16     q13, q13, q9    // ((tmp2y2 - tmp1y2) * (64 - my2) << 9) >> 15
+        vadd.s16        q12, q12, q0    // (((tmp2y1 - tmp1y1) * (64 - my1) << 9) >> 15) + tmp1y1
+        vadd.s16        q13, q13, q1    // (((tmp2y2 - tmp1y2) * (64 - my2) << 9) >> 15) + tmp1y2
+        vqrshrun.s16    d24, q12, #4    // (((((tmp2y1 - tmp1y1) * (64 - my1) << 9) >> 15) + tmp1y1) + 8) >> 4
+        vqrshrun.s16    d25, q13, #4    // (((((tmp2y2 - tmp1y2) * (64 - my2) << 9) >> 15) + tmp1y2) + 8) >> 4
+.if \type == 444
+        vmovn.u16       d20, q10        // 64 - m
+        vmovn.u16       d21, q11
+        vsub.i8         q10, q15, q10   // m
+        vst1.8          {d20, d21}, [r6,  :128]!
+.elseif \type == 422
+        vpadd.s16       d20, d20, d21   // (64 - my1) + (64 - ny1) (column wise addition)
+        vpadd.s16       d21, d22, d23   // (64 - my2) + (64 - ny2)
+        vmovn.s16       d20, q10
+        vhsub.u8        d20, d30, d20   // ((129 - sign) - ((64 - my1/y2) + (64 - ny1/y2))) >> 1
+        vst1.8          {d20}, [r6,  :64]!
+.elseif \type == 420
+        vadd.s16        q10, q10, q11   // (64 - my1) + (64 - my2) (row wise addition)
+        vpadd.s16       d20, d20, d21   // (128 - m) + (128 - n) (column wise addition)
+        vsub.s16        d20, d30, d20   // (256 - sign) - ((128 - m) + (128 - n))
+        vrshrn.u16      d20, q10, #2    // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        vst1.32         {d20[0]}, [r6,  :32]!
+.endif
+        vst1.16         {d24}, [r0,  :64], r1
+        vst1.16         {d25}, [r12, :64], r1
+        bgt             8b
+        pop             {r4-r9,pc}
+1280:
+640:
+320:
+160:
+        sub             r1,  r1,  r4
+.if \type == 444
+        add             lr,  r6,  r4
+.elseif \type == 422
+        add             lr,  r6,  r4,  lsr #1
+.endif
+        add             r9,  r3,  r4,  lsl #1
+        add             r7,  r2,  r4,  lsl #1
+161:
+        mov             r8,  r4
+16:
+        vld1.16         {d0,  d1,  d2,  d3},  [r2,  :128]! // tmp1y1
+        vld1.16         {d4,  d5,  d6,  d7},  [r3,  :128]! // tmp2y1
+        vld1.16         {d16, d17, d18, d19}, [r7,  :128]! // tmp1y2
+        subs            r8,  r8,  #16
+        vsub.i16        q2,  q2,  q0    // tmp2y1 - tmp1y1
+        vsub.i16        q3,  q3,  q1
+        vabs.s16        q10, q2         // abs(tm2y1 - tmp1y1)
+        vabs.s16        q11, q3
+        vqsub.u16       q10, q14, q10   // 6903 - abs(tmp1y1 - tmp2y1)
+        vqsub.u16       q11, q14, q11
+        vshr.s16        q10, q10, #8    // 64 - my1 = 6903 - abs(tmp1y1 - tmp2y1) >> 8
+        vshr.s16        q11, q11, #8
+        vshl.s16        q12, q10, #9    // (64 - my1) << 9
+        vshl.s16        q13, q11, #9
+        vqdmulh.s16     q12, q12, q2    // ((tmp2y1 - tmp1y1) * (64 - my1) << 9) >> 15
+        vqdmulh.s16     q13, q13, q3
+        vadd.i16        q12, q12, q0    // (((tmp2y1 - tmp1y1) * (64 - my1) << 9) >> 15) + tmp1y1
+        vadd.i16        q13, q13, q1
+        vld1.16         {d0,  d1,  d2,  d3},  [r9,  :128]! // tmp2h2
+.if \type == 444
+        vmovn.u16       d20, q10        // 64 - my1
+        vmovn.u16       d21, q11
+        vsub.i8         q10, q15, q10   // my1
+        vst1.8          {d20, d21}, [r6,  :128]!
+.elseif \type == 422
+        vpadd.s16       d20, d20, d21   // (64 - my1) + (64 - ny1) (column wise addition)
+        vpadd.s16       d21, d22, d23
+        vmovn.s16       d20, q10
+        vhsub.u8        d20, d30, d20   // ((129 - sign) - ((64 - my1) + (64 - ny1))) >> 1
+        vst1.8          {d20}, [r6,  :64]!
+.endif
+        vqrshrun.s16    d24, q12, #4    // (((((tmp2y1 - tmp1y1)*(64 - my1) << 9) >> 15) + tmp1y1) + 8) >> 4
+        vqrshrun.s16    d25, q13, #4
+        vsub.i16        q0,  q0,  q8    // tmp2y2 - tmp1y2
+        vsub.i16        q1,  q1,  q9
+        vst1.16         {d24, d25}, [r0,  :128]!    // store dsty1
+        vabs.s16        q2,  q0         // abs(tmp2y2 - tmp1y2)
+        vabs.s16        q3,  q1
+        vqsub.u16       q2,  q14, q2    // 6903 - abs(tmp2y2 - tmp1y2)
+        vqsub.u16       q3,  q14, q3
+        vshr.s16        q2,  q2,  #8    // (6903 - abs(tmp2y2 - tmp1y2)) >> 8
+        vshr.s16        q3,  q3,  #8
+        vshl.s16        q12, q2,  #9    // (64 - my2) << 9
+        vshl.s16        q13, q3,  #9
+.if \type == 444
+        vmovn.u16       d4,  q2         // 64 - my2
+        vmovn.u16       d5,  q3
+        vsub.i8         q2,  q15, q2    // my2
+        vst1.8          {d4,  d5},  [lr,  :128]!
+.elseif \type == 422
+        vpadd.s16       d4,  d4,  d5    // (64 - my2) + (64 - ny2) (column wise addition)
+        vpadd.s16       d5,  d6,  d7
+        vmovn.s16       d4,  q2
+        vhsub.u8        d4,  d30, d4    // ((129 - sign) - ((64 - my2) + (64 - ny2))) >> 1
+        vst1.8          {d4},  [lr,  :64]!
+.elseif \type == 420
+        vadd.s16        q10, q10, q2    // (64 - my1) + (64 - my2) (row wise addition)
+        vadd.s16        q11, q11, q3
+        vpadd.s16       d20, d20, d21   // (128 - m) + (128 - n) (column wise addition)
+        vpadd.s16       d21, d22, d23
+        vsub.s16        q10, q15, q10   // (256 - sign) - ((128 - m) + (128 - n))
+        vrshrn.u16      d20, q10, #2    // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        vst1.8          {d20}, [r6,  :64]!
+.endif
+        vqdmulh.s16     q12, q12, q0    // ((tmp2y2 - tmp1y2) * (64 - my2) << 9) >> 15
+        vqdmulh.s16     q13, q13, q1
+        vadd.i16        q12, q12, q8    // (((tmp2y2 - tmp1y2) * (64 - my2) << 9) >> 15) + tmp1y2
+        vadd.i16        q13, q13, q9
+        vqrshrun.s16    d24, q12, #4    // (((((tmp2y2 - tmp1y2)*(64 - my2) << 9) >> 15) + tmp1y2) + 8) >> 4
+        vqrshrun.s16    d25, q13, #4
+        vst1.16         {d24, d25}, [r12, :128]!   // store dsty2
+        bgt             16b
+        subs            r5,  r5,  #2
+        add             r2,  r2,  r4,  lsl #1
+        add             r3,  r3,  r4,  lsl #1
+        add             r7,  r7,  r4,  lsl #1
+        add             r9,  r9,  r4,  lsl #1
+.if \type == 444
+        add             r6,  r6,  r4
+        add             lr,  lr,  r4
+.elseif \type == 422
+        add             r6,  r6,  r4,  lsr #1
+        add             lr,  lr,  r4,  lsr #1
+.endif
+        add             r0,  r0,  r1
+        add             r12, r12, r1
+        bgt             161b
+        pop             {r4-r9,pc}
+endfunc
+.endm
+
+w_mask_fn 444
+w_mask_fn 422
+w_mask_fn 420
+
+
+function blend_8bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldrd            r4,  r5,  [sp, #12]
+        clz             lr,  r3
+        adr             r3,  L(blend_tbl)
+        sub             lr,  lr,  #26
+        ldr             lr,  [r3, lr, lsl #2]
+        add             r3,  r3,  lr
+        bx              r3
+
+        .align 2
+L(blend_tbl):
+        .word 320f  - L(blend_tbl) + CONFIG_THUMB
+        .word 160f  - L(blend_tbl) + CONFIG_THUMB
+        .word 80f   - L(blend_tbl) + CONFIG_THUMB
+        .word 40f   - L(blend_tbl) + CONFIG_THUMB
+
+40:
+        vmov.i8         d22, #64
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+4:
+        vld1.u8         {d2},     [r5,  :64]!
+        vld1.u8         {d1},     [r2,  :64]!
+        vld1.32         {d0[]},   [r0,  :32]
+        subs            r4,  r4,  #2
+        vld1.32         {d0[1]},  [r12, :32]
+        vsub.i8         d3,  d22, d2
+        vmull.u8        q8,  d1,  d2
+        vmlal.u8        q8,  d0,  d3
+        vrshrn.i16      d20, q8,  #6
+        vst1.32         {d20[0]}, [r0,  :32], r1
+        vst1.32         {d20[1]}, [r12, :32], r1
+        bgt             4b
+        pop             {r4-r5,pc}
+80:
+        vmov.i8         d16, #64
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+8:
+        vld1.u8         {q1},  [r5,  :128]!
+        vld1.u8         {q2},  [r2,  :128]!
+        vld1.u8         {d0},  [r0,  :64]
+        vsub.i8         d17, d16, d2
+        vld1.u8         {d1},  [r12, :64]
+        subs            r4,  r4,  #2
+        vsub.i8         d18, d16, d3
+        vmull.u8        q3,  d2,  d4
+        vmlal.u8        q3,  d0,  d17
+        vmull.u8        q10, d3,  d5
+        vmlal.u8        q10, d1,  d18
+        vrshrn.i16      d22, q3,  #6
+        vrshrn.i16      d23, q10, #6
+        vst1.u8         {d22}, [r0,  :64], r1
+        vst1.u8         {d23}, [r12, :64], r1
+        bgt             8b
+        pop             {r4-r5,pc}
+160:
+        vmov.i8         q12, #64
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+16:
+        vld1.u8         {q1,  q2},  [r5,  :128]!
+        vld1.u8         {q8,  q9},  [r2,  :128]!
+        vld1.u8         {q0},  [r0,  :128]
+        subs            r4,  r4,  #2
+        vsub.i8         q15, q12, q1
+        vld1.u8         {q13}, [r12, :128]
+        vmull.u8        q3,  d16, d2
+        vmlal.u8        q3,  d0,  d30
+        vmull.u8        q14, d17, d3
+        vmlal.u8        q14, d1,  d31
+        vsub.i8         q15, q12, q2
+        vrshrn.i16      d20, q3,  #6
+        vrshrn.i16      d21, q14, #6
+        vmull.u8        q3,  d18, d4
+        vmlal.u8        q3,  d26, d30
+        vmull.u8        q14, d19, d5
+        vmlal.u8        q14, d27, d31
+        vrshrn.i16      d22, q3,  #6
+        vrshrn.i16      d23, q14, #6
+        vst1.u8         {q10}, [r0,  :128], r1
+        vst1.u8         {q11}, [r12, :128], r1
+        bgt             16b
+        pop             {r4-r5,pc}
+320:
+        vmov.i8         q10, #64
+32:
+        vld1.u8         {q2,  q3},  [r5,  :128]!
+        vld1.u8         {q8,  q9},  [r2,  :128]!
+        vld1.u8         {q0,  q1},  [r0,  :128]
+        subs            r4,  r4,  #1
+        vsub.i8         q11, q10, q2
+        vmull.u8        q15, d16, d4
+        vmlal.u8        q15, d0,  d22
+        vmull.u8        q14, d17, d5
+        vmlal.u8        q14, d1,  d23
+        vsub.i8         q11, q10, q3
+        vrshrn.i16      d24, q15, #6
+        vrshrn.i16      d25, q14, #6
+        vmull.u8        q15, d18, d6
+        vmlal.u8        q15, d2,  d22
+        vmull.u8        q14, d19, d7
+        vmlal.u8        q14, d3,  d23
+        vrshrn.i16      d26, q15, #6
+        vrshrn.i16      d27, q14, #6
+        vst1.u8         {q12, q13}, [r0,  :128],  r1
+        bgt             32b
+        pop             {r4-r5,pc}
+endfunc
+
+function blend_h_8bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldr             r4,  [sp, #12]
+        movrel          r5,  X(obmc_masks)
+        add             r5,  r5,  r4
+        sub             r4,  r4,  r4,  lsr #2
+        clz             lr,  r3
+        adr             r12, L(blend_h_tbl)
+        sub             lr,  lr,  #24
+        ldr             lr,  [r12, lr, lsl #2]
+        add             r12, r12, lr
+        bx              r12
+
+        .align 2
+L(blend_h_tbl):
+        .word 1280f  - L(blend_h_tbl) + CONFIG_THUMB
+        .word 640f   - L(blend_h_tbl) + CONFIG_THUMB
+        .word 320f   - L(blend_h_tbl) + CONFIG_THUMB
+        .word 160f   - L(blend_h_tbl) + CONFIG_THUMB
+        .word 80f    - L(blend_h_tbl) + CONFIG_THUMB
+        .word 40f    - L(blend_h_tbl) + CONFIG_THUMB
+        .word 20f    - L(blend_h_tbl) + CONFIG_THUMB
+
+20:
+        vmov.i8         d22, #64
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+2:
+        vld1.16         {d2[], d3[]},  [r5,  :16]!
+        vld1.32         {d1[]},  [r2,  :32]!
+        subs            r4,  r4,  #2
+        vld1.16         {d0[]},   [r0,  :16]
+        vzip.8          d2,  d3
+        vsub.i8         d4,  d22, d2
+        vld1.16         {d0[1]},  [r12, :16]
+        vmull.u8        q8,  d1,  d2
+        vmlal.u8        q8,  d0,  d4
+        vrshrn.i16      d20, q8,  #6
+        vst1.16         {d20[0]}, [r0,  :16], r1
+        vst1.16         {d20[1]}, [r12, :16], r1
+        bgt             2b
+        pop             {r4-r5,pc}
+40:
+        vmov.i8         d22, #64
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+4:
+        vld2.u8         {d2[],  d3[]},   [r5,  :16]!
+        vld1.u8         {d1},     [r2,  :64]!
+        subs            r4,  r4,  #2
+        vext.u8         d2,  d2,  d3,   #4
+        vld1.32         {d0[]},   [r0,  :32]
+        vsub.i8         d6,  d22, d2
+        vld1.32         {d0[1]},  [r12, :32]
+        vmull.u8        q8,  d1,  d2
+        vmlal.u8        q8,  d0,  d6
+        vrshrn.i16      d20, q8,  #6
+        vst1.32         {d20[0]}, [r0,  :32], r1
+        vst1.32         {d20[1]}, [r12, :32], r1
+        bgt             4b
+        pop             {r4-r5,pc}
+80:
+        vmov.i8         q8, #64
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+8:
+        vld2.u8         {d2[],  d3[]},  [r5,  :16]!
+        vld1.u8         {d4,  d5},  [r2,  :128]!
+        vld1.u8         {d0},   [r0,  :64]
+        vsub.i8         q9,  q8,  q1
+        vld1.u8         {d1},   [r12, :64]
+        subs            r4,  r4,  #2
+        vmull.u8        q3,  d2,  d4
+        vmlal.u8        q3,  d0,  d18
+        vmull.u8        q10, d3,  d5
+        vmlal.u8        q10, d1,  d19
+        vrshrn.i16      d22, q3,  #6
+        vrshrn.i16      d23, q10, #6
+        vst1.u8         {d22}, [r0,  :64], r1
+        vst1.u8         {d23}, [r12, :64], r1
+        bgt             8b
+        pop             {r4-r5,pc}
+160:
+        vmov.i8         q12, #64
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+16:
+        vld2.u8         {d28[], d29[]}, [r5,  :16]!
+        vld1.u8         {d2,  d3,  d4,  d5},  [r2,  :128]!
+        vsub.i8         q15, q12, q14
+        vld1.u8         {q0},  [r0,  :128]
+        subs            r4,  r4,  #2
+        vld1.u8         {q13}, [r12, :128]
+        vmull.u8        q3,  d2,  d28
+        vmlal.u8        q3,  d0,  d30
+        vmull.u8        q8,  d3,  d28
+        vmlal.u8        q8,  d1,  d30
+        vrshrn.i16      d18, q3,  #6
+        vrshrn.i16      d19, q8,  #6
+        vmull.u8        q3,  d4,  d29
+        vmlal.u8        q3,  d26, d31
+        vmull.u8        q8,  d5,  d29
+        vmlal.u8        q8,  d27, d31
+        vrshrn.i16      d20, q3,  #6
+        vrshrn.i16      d21, q8,  #6
+        vst1.u8         {q9},  [r0,  :128], r1
+        vst1.u8         {q10}, [r12, :128], r1
+        bgt             16b
+        pop             {r4-r5,pc}
+320:
+640:
+1280:
+        vmov.i8         d20, #64
+        sub             r1,  r1,  r3
+321:
+        vld1.u8         {d6[]},  [r5]!
+        vsub.i8         d7,  d20, d6
+        mov             r12, r3
+32:
+        vld1.u8         {q8,  q9},  [r2,  :128]!
+        vld1.u8         {q0,  q1},  [r0,  :128]
+        vmull.u8        q15, d16, d6
+        vmlal.u8        q15, d0,  d7
+        vmull.u8        q14, d17, d6
+        vmlal.u8        q14, d1,  d7
+        vrshrn.i16      d0,  q15, #6
+        vrshrn.i16      d1,  q14, #6
+        vmull.u8        q15, d18, d6
+        vmlal.u8        q15, d2,  d7
+        vmull.u8        q14, d19, d6
+        vmlal.u8        q14, d3,  d7
+        vrshrn.i16      d2,  q15, #6
+        vrshrn.i16      d3,  q14, #6
+        subs            r12, r12, #32
+        vst1.u8         {q0,  q1},  [r0,  :128]!
+        bgt             32b
+        add             r0,  r0,  r1
+        subs            r4,  r4,  #1
+        bgt             321b
+        pop             {r4-r5,pc}
+endfunc
+
+function blend_v_8bpc_neon, export=1
+        push            {r4,lr}
+        ldr             r4,  [sp, #8]
+        movrel          lr,  X(obmc_masks)
+        add             lr,  lr,  r3
+        clz             r12, r3
+        adr             r3,  L(blend_v_tbl)
+        sub             r12, r12, #26
+        ldr             r12, [r3, r12, lsl #2]
+        add             r3,  r3,  r12
+        bx              r3
+
+        .align 2
+L(blend_v_tbl):
+        .word 320f  - L(blend_v_tbl) + CONFIG_THUMB
+        .word 160f  - L(blend_v_tbl) + CONFIG_THUMB
+        .word 80f   - L(blend_v_tbl) + CONFIG_THUMB
+        .word 40f   - L(blend_v_tbl) + CONFIG_THUMB
+        .word 20f   - L(blend_v_tbl) + CONFIG_THUMB
+
+20:
+        vmov.i8         d22, #64
+        vld1.8          {d2[]},   [lr]
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        vsub.i8         d3,  d22, d2
+2:
+        vld1.16         {d1[0]},  [r2,  :16]!
+        vld1.8          {d0[]},   [r0]
+        subs            r4,  r4,  #2
+        vld1.8          {d1[1]},  [r2]
+        vld1.8          {d0[1]},  [r12]
+        vmull.u8        q2,  d1,  d2
+        vmlal.u8        q2,  d0,  d3
+        vrshrn.i16      d6,  q2,  #6
+        add             r2,  r2,  #2
+        vst1.8          {d6[0]},  [r0],  r1
+        vst1.8          {d6[1]},  [r12], r1
+        bgt             2b
+        pop             {r4,pc}
+40:
+        vmov.i8         d22, #64
+        vld1.32         {d4[]},   [lr,  :32]
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        vsub.i8         d5,  d22, d4
+        sub             r1,  r1,  #2
+4:
+        vld1.u8         {d2},     [r2,  :64]!
+        vld1.32         {d0[]},   [r0,  :32]
+        vld1.32         {d0[1]},  [r12, :32]
+        subs            r4,  r4,  #2
+        vmull.u8        q3,  d2,  d4
+        vmlal.u8        q3,  d0,  d5
+        vrshrn.i16      d20, q3,  #6
+        vst1.16         {d20[0]}, [r0,  :16]!
+        vst1.16         {d20[2]}, [r12, :16]!
+        vst1.8          {d20[2]}, [r0],  r1
+        vst1.8          {d20[6]}, [r12], r1
+        bgt             4b
+        pop             {r4,pc}
+80:
+        vmov.i8         d16, #64
+        vld1.u8         {d2},  [lr,  :64]
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        vsub.i8         d17, d16, d2
+        sub             r1,  r1,  #4
+8:
+        vld1.u8         {d4,  d5},  [r2,  :128]!
+        vld1.u8         {d0},  [r0,  :64]
+        vld1.u8         {d1},  [r12, :64]
+        subs            r4,  r4,  #2
+        vmull.u8        q3,  d2,  d4
+        vmlal.u8        q3,  d0,  d17
+        vmull.u8        q10, d2,  d5
+        vmlal.u8        q10, d1,  d17
+        vrshrn.i16      d22, q3,  #6
+        vrshrn.i16      d23, q10, #6
+        vst1.32         {d22[0]}, [r0,  :32]!
+        vst1.32         {d23[0]}, [r12, :32]!
+        vst1.16         {d22[2]}, [r0,  :16], r1
+        vst1.16         {d23[2]}, [r12, :16], r1
+        bgt             8b
+        pop             {r4,pc}
+160:
+        vmov.i8         q12, #64
+        vld1.u8         {q14}, [lr,  :128]
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        vsub.i8         q11, q12, q14
+        sub             r1,  r1,  #8
+16:
+        vld1.u8         {q1,  q2},  [r2,  :128]!
+        vld1.u8         {q0},  [r0,  :128]
+        subs            r4,  r4,  #2
+        vld1.u8         {q13}, [r12, :128]
+        vmull.u8        q3,  d2,  d28
+        vmlal.u8        q3,  d0,  d22
+        vmull.u8        q8,  d3,  d29
+        vmlal.u8        q8,  d1,  d23
+        vrshrn.i16      d18, q3,  #6
+        vrshrn.i16      d19, q8,  #6
+        vmull.u8        q3,  d4,  d28
+        vmlal.u8        q3,  d26, d22
+        vmull.u8        q8,  d5,  d29
+        vmlal.u8        q8,  d27, d23
+        vrshrn.i16      d20, q3,  #6
+        vrshrn.i16      d21, q8,  #6
+        vst1.u8         {d18},    [r0,  :64]!
+        vst1.u8         {d20},    [r12, :64]!
+        vst1.32         {d19[0]}, [r0,  :32], r1
+        vst1.32         {d21[0]}, [r12, :32], r1
+        bgt             16b
+        pop             {r4,pc}
+320:
+        vmov.i8         q10, #64
+        vld1.u8         {q2,  q3},  [lr,  :128]
+        vsub.i8         q11, q10, q2
+        vsub.i8         d24, d20, d6
+32:
+        vld1.u8         {q8,  q9},  [r2,  :128]!
+        vld1.u8         {d0,  d1,  d2},  [r0,  :64]
+        subs            r4,  r4,  #1
+        vmull.u8        q15, d16, d4
+        vmlal.u8        q15, d0,  d22
+        vmull.u8        q14, d17, d5
+        vmlal.u8        q14, d1,  d23
+        vrshrn.i16      d0,  q15, #6
+        vrshrn.i16      d1,  q14, #6
+        vmull.u8        q15, d18, d6
+        vmlal.u8        q15, d2,  d24
+        vrshrn.i16      d2,  q15, #6
+        vst1.u8         {d0,  d1,  d2},  [r0,  :64],  r1
+        bgt             32b
+        pop             {r4,pc}
+endfunc
+
+
+// This has got the same signature as the put_8tap functions,
+// assumes that the caller has loaded the h argument into r5,
+// and assumes that r8 is set to (clz(w)-24).
+function put_neon
+        adr             r9,  L(put_tbl)
+        ldr             r8,  [r9, r8, lsl #2]
+        add             r9,  r9,  r8
+        bx              r9
+
+        .align 2
+L(put_tbl):
+        .word 1280f - L(put_tbl) + CONFIG_THUMB
+        .word 640f  - L(put_tbl) + CONFIG_THUMB
+        .word 32f   - L(put_tbl) + CONFIG_THUMB
+        .word 160f  - L(put_tbl) + CONFIG_THUMB
+        .word 8f    - L(put_tbl) + CONFIG_THUMB
+        .word 4f    - L(put_tbl) + CONFIG_THUMB
+        .word 2f    - L(put_tbl) + CONFIG_THUMB
+
+2:
+        vld1.16         {d0[]}, [r2], r3
+        vld1.16         {d1[]}, [r2], r3
+        subs            r5,  r5,  #2
+        vst1.16         {d0[0]}, [r0, :16], r1
+        vst1.16         {d1[0]}, [r0, :16], r1
+        bgt             2b
+        pop             {r4-r11,pc}
+4:
+        vld1.32         {d0[]}, [r2], r3
+        vld1.32         {d1[]}, [r2], r3
+        subs            r5,  r5,  #2
+        vst1.32         {d0[0]}, [r0, :32], r1
+        vst1.32         {d1[0]}, [r0, :32], r1
+        bgt             4b
+        pop             {r4-r11,pc}
+8:
+        vld1.8          {d0}, [r2], r3
+        vld1.8          {d1}, [r2], r3
+        subs            r5,  r5,  #2
+        vst1.8          {d0}, [r0, :64], r1
+        vst1.8          {d1}, [r0, :64], r1
+        bgt             8b
+        pop             {r4-r11,pc}
+160:
+        add             r8,  r0,  r1
+        lsl             r1,  r1,  #1
+        add             r9,  r2,  r3
+        lsl             r3,  r3,  #1
+16:
+        vld1.8          {q0}, [r2], r3
+        vld1.8          {q1}, [r9], r3
+        subs            r5,  r5,  #2
+        vst1.8          {q0}, [r0, :128], r1
+        vst1.8          {q1}, [r8, :128], r1
+        bgt             16b
+        pop             {r4-r11,pc}
+32:
+        vld1.8          {q0,  q1},  [r2], r3
+        subs            r5,  r5,  #1
+        vst1.8          {q0,  q1},  [r0, :128], r1
+        bgt             32b
+        pop             {r4-r11,pc}
+640:
+        sub             r1,  r1,  #32
+        sub             r3,  r3,  #32
+64:
+        vld1.8          {q0,  q1},  [r2]!
+        vst1.8          {q0,  q1},  [r0, :128]!
+        vld1.8          {q2,  q3},  [r2], r3
+        subs            r5,  r5,  #1
+        vst1.8          {q2,  q3},  [r0, :128], r1
+        bgt             64b
+        pop             {r4-r11,pc}
+1280:
+        sub             r1,  r1,  #96
+        sub             r3,  r3,  #96
+128:
+        vld1.8          {q8,  q9},  [r2]!
+        vst1.8          {q8,  q9},  [r0, :128]!
+        vld1.8          {q10, q11}, [r2]!
+        vst1.8          {q10, q11}, [r0, :128]!
+        vld1.8          {q12, q13}, [r2]!
+        vst1.8          {q12, q13}, [r0, :128]!
+        vld1.8          {q14, q15}, [r2], r3
+        subs            r5,  r5,  #1
+        vst1.8          {q14, q15}, [r0, :128], r1
+        bgt             128b
+        pop             {r4-r11,pc}
+endfunc
+
+
+// This has got the same signature as the put_8tap functions,
+// assumes that the caller has loaded the h argument into r4,
+// and assumes that r8 is set to (clz(w)-24), and r7 to w*2.
+function prep_neon
+        adr             r9,  L(prep_tbl)
+        ldr             r8,  [r9, r8, lsl #2]
+        add             r9,  r9,  r8
+        bx              r9
+
+        .align 2
+L(prep_tbl):
+        .word 1280f - L(prep_tbl) + CONFIG_THUMB
+        .word 640f  - L(prep_tbl) + CONFIG_THUMB
+        .word 320f  - L(prep_tbl) + CONFIG_THUMB
+        .word 160f  - L(prep_tbl) + CONFIG_THUMB
+        .word 8f    - L(prep_tbl) + CONFIG_THUMB
+        .word 4f    - L(prep_tbl) + CONFIG_THUMB
+
+4:
+        vld1.32         {d0[]}, [r1], r2
+        vld1.32         {d2[]}, [r1], r2
+        subs            r4,  r4,  #2
+        vshll.u8        q0,  d0,  #4
+        vshll.u8        q1,  d2,  #4
+        vst1.16         {d1, d2}, [r0, :64]!
+        bgt             4b
+        pop             {r4-r11,pc}
+8:
+        vld1.8          {d0}, [r1], r2
+        vld1.8          {d2}, [r1], r2
+        subs            r4,  r4,  #2
+        vshll.u8        q0,  d0,  #4
+        vshll.u8        q1,  d2,  #4
+        vst1.16         {q0, q1}, [r0, :128]!
+        bgt             8b
+        pop             {r4-r11,pc}
+160:
+        add             r9,  r1,  r2
+        lsl             r2,  r2,  #1
+        add             r8,  r0,  r7
+        lsl             r7,  r7,  #1
+16:
+        vld1.8          {q2}, [r1], r2
+        vld1.8          {q3}, [r9], r2
+        subs            r4,  r4,  #2
+        vshll.u8        q0,  d4,  #4
+        vshll.u8        q1,  d5,  #4
+        vshll.u8        q2,  d6,  #4
+        vshll.u8        q3,  d7,  #4
+        vst1.16         {q0, q1}, [r0, :128], r7
+        vst1.16         {q2, q3}, [r8, :128], r7
+        bgt             16b
+        pop             {r4-r11,pc}
+320:
+        add             r8,  r0,  r3
+32:
+        vld1.8          {q0,  q1},  [r1], r2
+        subs            r4,  r4,  #2
+        vshll.u8        q8,  d0,  #4
+        vshll.u8        q9,  d1,  #4
+        vld1.8          {q2,  q3},  [r1], r2
+        vshll.u8        q10, d2,  #4
+        vshll.u8        q11, d3,  #4
+        vshll.u8        q12, d4,  #4
+        vst1.16         {q8,  q9},  [r0, :128], r7
+        vshll.u8        q13, d5,  #4
+        vst1.16         {q10, q11}, [r8, :128], r7
+        vshll.u8        q14, d6,  #4
+        vst1.16         {q12, q13}, [r0, :128], r7
+        vshll.u8        q15, d7,  #4
+        vst1.16         {q14, q15}, [r8, :128], r7
+        bgt             32b
+        pop             {r4-r11,pc}
+640:
+        sub             r2,  r2,  #32
+        add             r8,  r0,  #32
+        mov             r6,  #64
+64:
+        vld1.8          {q0,  q1},  [r1]!
+        subs            r4,  r4,  #1
+        vshll.u8        q8,  d0,  #4
+        vshll.u8        q9,  d1,  #4
+        vld1.8          {q2,  q3},  [r1], r2
+        vshll.u8        q10, d2,  #4
+        vshll.u8        q11, d3,  #4
+        vshll.u8        q12, d4,  #4
+        vst1.16         {q8,  q9},  [r0, :128], r6
+        vshll.u8        q13, d5,  #4
+        vshll.u8        q14, d6,  #4
+        vst1.16         {q10, q11}, [r8, :128], r6
+        vshll.u8        q15, d7,  #4
+        vst1.16         {q12, q13}, [r0, :128], r6
+        vst1.16         {q14, q15}, [r8, :128], r6
+        bgt             64b
+        pop             {r4-r11,pc}
+1280:
+        sub             r2,  r2,  #96
+        add             r8,  r0,  #32
+        mov             r6,  #64
+128:
+        vld1.8          {q0,  q1},  [r1]!
+        vld1.8          {q2,  q3},  [r1]!
+        vshll.u8        q10, d0,  #4
+        vshll.u8        q11, d1,  #4
+        vshll.u8        q12, d2,  #4
+        vshll.u8        q13, d3,  #4
+        vshll.u8        q14, d4,  #4
+        vshll.u8        q15, d5,  #4
+        vld1.8          {q8,  q9},  [r1]!
+        vst1.16         {q10, q11}, [r0, :128], r6
+        vst1.16         {q12, q13}, [r8, :128], r6
+        vshll.u8        q0,  d6,  #4
+        vshll.u8        q1,  d7,  #4
+        vshll.u8        q2,  d16, #4
+        vshll.u8        q3,  d17, #4
+        vshll.u8        q8,  d18, #4
+        vshll.u8        q9,  d19, #4
+        vld1.8          {q10, q11}, [r1], r2
+        vst1.16         {q14, q15}, [r0, :128], r6
+        vst1.16         {q0,  q1},  [r8, :128], r6
+        vshll.u8        q12, d20, #4
+        vshll.u8        q13, d21, #4
+        vshll.u8        q14, d22, #4
+        vshll.u8        q15, d23, #4
+        subs            r4,  r4,  #1
+        vst1.16         {q2,  q3},  [r0, :128], r6
+        vst1.16         {q8,  q9},  [r8, :128], r6
+        vst1.16         {q12, q13}, [r0, :128], r6
+        vst1.16         {q14, q15}, [r8, :128], r6
+        bgt             128b
+        pop             {r4-r11,pc}
+endfunc
+
+
+.macro load_slice s0, s1, strd, wd, d0, d1, d2, d3, d4, d5, d6
+        vld1.\wd        {\d0[]}, [\s0], \strd
+        vld1.\wd        {\d1[]}, [\s1], \strd
+.ifnb \d2
+        vld1.\wd        {\d2[]}, [\s0], \strd
+        vld1.\wd        {\d3[]}, [\s1], \strd
+.endif
+.ifnb \d4
+        vld1.\wd        {\d4[]}, [\s0], \strd
+.endif
+.ifnb \d5
+        vld1.\wd        {\d5[]}, [\s1], \strd
+.endif
+.ifnb \d6
+        vld1.\wd        {\d6[]}, [\s0], \strd
+.endif
+.endm
+.macro load_reg s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        vld1.8          {\d0}, [\s0], \strd
+        vld1.8          {\d1}, [\s1], \strd
+.ifnb \d2
+        vld1.8          {\d2}, [\s0], \strd
+        vld1.8          {\d3}, [\s1], \strd
+.endif
+.ifnb \d4
+        vld1.8          {\d4}, [\s0], \strd
+.endif
+.ifnb \d5
+        vld1.8          {\d5}, [\s1], \strd
+.endif
+.ifnb \d6
+        vld1.8          {\d6}, [\s0], \strd
+.endif
+.endm
+.macro load_16 s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_slice      \s0, \s1, \strd, 16, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro load_32 s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_slice      \s0, \s1, \strd, 32, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro interleave_1_16 r0, r1, r2, r3, r4
+        vext.8          \r0, \r0, \r1, #6
+        vext.8          \r1, \r1, \r2, #6
+.ifnb \r3
+        vext.8          \r2, \r2, \r3, #6
+        vext.8          \r3, \r3, \r4, #6
+.endif
+.endm
+.macro interleave_1_32 r0, r1, r2, r3, r4
+        vext.8          \r0, \r0, \r1, #4
+        vext.8          \r1, \r1, \r2, #4
+.ifnb \r3
+        vext.8          \r2, \r2, \r3, #4
+        vext.8          \r3, \r3, \r4, #4
+.endif
+.endm
+.macro vmovl_u8 q0, d0, q1, d1, q2, d2, q3, d3, q4, d4, q5, d5, q6, d6
+        vmovl.u8        \q0, \d0
+        vmovl.u8        \q1, \d1
+.ifnb \q2
+        vmovl.u8        \q2, \d2
+        vmovl.u8        \q3, \d3
+.endif
+.ifnb \q4
+        vmovl.u8        \q4, \d4
+.endif
+.ifnb \q5
+        vmovl.u8        \q5, \d5
+.endif
+.ifnb \q6
+        vmovl.u8        \q6, \d6
+.endif
+.endm
+.macro mul_mla_4 d, s0, s1, s2, s3
+        vmul.s16        \d,  \s0,  d0[0]
+        vmla.s16        \d,  \s1,  d0[1]
+        vmla.s16        \d,  \s2,  d0[2]
+        vmla.s16        \d,  \s3,  d0[3]
+.endm
+.macro mul_mla_8_0 d0, s0, s1, s2, s3, s4, s5, s6, s7
+        vmul.s16        \d0, \s0,  d0[0]
+        vmla.s16        \d0, \s1,  d0[1]
+        vmla.s16        \d0, \s2,  d0[2]
+        vmla.s16        \d0, \s3,  d0[3]
+        vmla.s16        \d0, \s4,  d1[0]
+        vmla.s16        \d0, \s5,  d1[1]
+        vmla.s16        \d0, \s6,  d1[2]
+        vmla.s16        \d0, \s7,  d1[3]
+.endm
+.macro mul_mla_8_1 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8
+        vmul.s16        \d0, \s0, d0[0]
+        vmla.s16        \d0, \s1, d0[1]
+        vmla.s16        \d0, \s2, d0[2]
+        vmla.s16        \d0, \s3, d0[3]
+        vmla.s16        \d0, \s4, d1[0]
+        vmla.s16        \d0, \s5, d1[1]
+        vmla.s16        \d0, \s6, d1[2]
+        vmla.s16        \d0, \s7, d1[3]
+        vmul.s16        \d1, \s1, d0[0]
+        vmla.s16        \d1, \s2, d0[1]
+        vmla.s16        \d1, \s3, d0[2]
+        vmla.s16        \d1, \s4, d0[3]
+        vmla.s16        \d1, \s5, d1[0]
+        vmla.s16        \d1, \s6, d1[1]
+        vmla.s16        \d1, \s7, d1[2]
+        vmla.s16        \d1, \s8, d1[3]
+.endm
+.macro mul_mla_8_2 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9
+        vmul.s16        \d0, \s0, d0[0]
+        vmla.s16        \d0, \s1, d0[1]
+        vmla.s16        \d0, \s2, d0[2]
+        vmla.s16        \d0, \s3, d0[3]
+        vmla.s16        \d0, \s4, d1[0]
+        vmla.s16        \d0, \s5, d1[1]
+        vmla.s16        \d0, \s6, d1[2]
+        vmla.s16        \d0, \s7, d1[3]
+        vmul.s16        \d1, \s2, d0[0]
+        vmla.s16        \d1, \s3, d0[1]
+        vmla.s16        \d1, \s4, d0[2]
+        vmla.s16        \d1, \s5, d0[3]
+        vmla.s16        \d1, \s6, d1[0]
+        vmla.s16        \d1, \s7, d1[1]
+        vmla.s16        \d1, \s8, d1[2]
+        vmla.s16        \d1, \s9, d1[3]
+.endm
+.macro vqrshrun_s16 shift, q0, d0, q1, d1, q2, d2, q3, d3
+        vqrshrun.s16    \d0, \q0, #\shift
+.ifnb \q1
+        vqrshrun.s16    \d1, \q1, #\shift
+.endif
+.ifnb \q2
+        vqrshrun.s16    \d2, \q2, #\shift
+        vqrshrun.s16    \d3, \q3, #\shift
+.endif
+.endm
+.macro vrshr_s16 shift, r0, r1, r2, r3
+        vrshr.s16       \r0, \r0, #\shift
+.ifnb \r1
+        vrshr.s16       \r1, \r1, #\shift
+.endif
+.ifnb \r2
+        vrshr.s16       \r2, \r2, #\shift
+        vrshr.s16       \r3, \r3, #\shift
+.endif
+.endm
+.macro st_16 strd, reg, lanes
+        vst1.16         {\reg[0]}, [r0, :16], \strd
+        vst1.16         {\reg[1]}, [r8, :16], \strd
+.if \lanes > 2
+        vst1.16         {\reg[2]}, [r0, :16], \strd
+        vst1.16         {\reg[3]}, [r8, :16], \strd
+.endif
+.endm
+.macro st_32 strd, r0, r1
+        vst1.32         {\r0[0]}, [r0, :32], \strd
+        vst1.32         {\r0[1]}, [r8, :32], \strd
+.ifnb \r1
+        vst1.32         {\r1[0]}, [r0, :32], \strd
+        vst1.32         {\r1[1]}, [r8, :32], \strd
+.endif
+.endm
+.macro st_reg strd, align, r0, r1, r2, r3, r4, r5, r6, r7
+        vst1.8          {\r0}, [r0, \align], \strd
+        vst1.8          {\r1}, [r8, \align], \strd
+.ifnb \r2
+        vst1.8          {\r2}, [r0, \align], \strd
+        vst1.8          {\r3}, [r8, \align], \strd
+.endif
+.ifnb \r4
+        vst1.8          {\r4}, [r0, \align], \strd
+        vst1.8          {\r5}, [r8, \align], \strd
+        vst1.8          {\r6}, [r0, \align], \strd
+        vst1.8          {\r7}, [r8, \align], \strd
+.endif
+.endm
+.macro shift_store_4 type, strd, q0, d0, d1, q1, d2, d3
+.ifc \type, put
+        vqrshrun_s16    6,     \q0, \d0, \q1, \d2
+        st_32           \strd, \d0, \d2
+.else
+        vrshr_s16       2,          \q0, \q1
+        st_reg          \strd, :64, \d0, \d1, \d2, \d3
+.endif
+.endm
+.macro shift_store_8 type, strd, q0, d0, q1, d1, q2, d2, q3, d3
+.ifc \type, put
+        vqrshrun_s16    6,          \q0, \d0, \q1, \d1, \q2, \d2, \q3, \d3
+        st_reg          \strd, :64, \d0, \d1, \d2, \d3
+.else
+        vrshr_s16       2,          \q0, \q1, \q2, \q3
+        st_reg          \strd, :128,\q0, \q1, \q2, \q3
+.endif
+.endm
+.macro shift_store_16 type, strd, q0, d0, d1, q1, q2, d4, d5, q3
+.ifc \type, put
+        vqrshrun.s16    \d0,   \q0, #6
+        vqrshrun.s16    \d1,   \q1, #6
+        vqrshrun.s16    \d4,   \q2, #6
+        vqrshrun.s16    \d5,   \q3, #6
+        st_reg          \strd, :128, \q0, \q2
+.else
+        vrshr_s16       2,     \q0, \q1, \q2, \q3
+        vst1.16         {\q0, \q1}, [r0, :128], \strd
+        vst1.16         {\q2, \q3}, [r8, :128], \strd
+.endif
+.endm
+
+.macro make_8tap_fn op, type, type_h, type_v
+function \op\()_8tap_\type\()_8bpc_neon, export=1
+        push            {r4-r11,lr}
+        movw            r8,  \type_h
+        movw            r9,  \type_v
+        b               \op\()_8tap_neon
+endfunc
+.endm
+
+// No spaces in these expressions, due to gas-preprocessor.
+#define REGULAR ((0*15<<7)|3*15)
+#define SMOOTH  ((1*15<<7)|4*15)
+#define SHARP   ((2*15<<7)|3*15)
+
+.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, my, ds2, sr2, shift_hv
+make_8tap_fn \type, regular,        REGULAR, REGULAR
+make_8tap_fn \type, regular_smooth, REGULAR, SMOOTH
+make_8tap_fn \type, regular_sharp,  REGULAR, SHARP
+make_8tap_fn \type, smooth,         SMOOTH,  SMOOTH
+make_8tap_fn \type, smooth_regular, SMOOTH,  REGULAR
+make_8tap_fn \type, smooth_sharp,   SMOOTH,  SHARP
+make_8tap_fn \type, sharp,          SHARP,   SHARP
+make_8tap_fn \type, sharp_regular,  SHARP,   REGULAR
+make_8tap_fn \type, sharp_smooth,   SHARP,   SMOOTH
+
+function \type\()_8tap_neon
+        ldrd            r4,  r5,  [sp, #36]
+        ldrd            r6,  r7,  [sp, #44]
+        movw            r10,  #0x4081  // (1 << 14) | (1 << 7) | (1 << 0)
+        mul             \mx,  \mx, r10
+        mul             \my,  \my, r10
+        add             \mx,  \mx, r8 // mx, 8tap_h, 4tap_h
+        add             \my,  \my, r9 // my, 8tap_v, 4tap_v
+.ifc \type, prep
+        lsl             \d_strd, \w, #1
+.endif
+
+        clz             r8,  \w
+        tst             \mx, #(0x7f << 14)
+        sub             r8,  r8,  #24
+        movrel          r10, X(mc_subpel_filters), -8
+        bne             L(\type\()_8tap_h)
+        tst             \my, #(0x7f << 14)
+        bne             L(\type\()_8tap_v)
+        b               \type\()_neon
+
+L(\type\()_8tap_h):
+        cmp             \w,  #4
+        ubfx            r9,  \mx, #7, #7
+        and             \mx, \mx, #0x7f
+        it              gt
+        movgt           \mx,  r9
+        tst             \my,  #(0x7f << 14)
+        add             \mx, r10, \mx, lsl #3
+        bne             L(\type\()_8tap_hv)
+
+        adr             r9,  L(\type\()_8tap_h_tbl)
+        ldr             r8,  [r9, r8, lsl #2]
+        add             r9,  r9,  r8
+        bx              r9
+
+        .align 2
+L(\type\()_8tap_h_tbl):
+        .word 1280f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+
+20:     // 2xN h
+.ifc \type, put
+        add             \mx,  \mx,  #2
+        vld1.32         {d0[]}, [\mx]
+        sub             \src,  \src,  #1
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+2:
+        vld1.8          {d4},  [\src], \s_strd
+        vld1.8          {d6},  [\sr2], \s_strd
+        vmovl.u8        q2,  d4
+        vmovl.u8        q3,  d6
+        vext.8          d5,  d4,  d5,  #2
+        vext.8          d7,  d6,  d7,  #2
+        subs            \h,  \h,  #2
+        vtrn.32         d4,  d6
+        vtrn.32         d5,  d7
+        vmul.s16        d2,  d4,  d0[0]
+        vmla.s16        d2,  d5,  d0[1]
+        vmla.s16        d2,  d6,  d0[2]
+        vmla.s16        d2,  d7,  d0[3]
+        vrshr.s16       d2,  d2,  #2
+        vqrshrun.s16    d2,  q1,  #4
+        vst1.16         {d2[0]}, [\dst, :16], \d_strd
+        vst1.16         {d2[1]}, [\ds2, :16], \d_strd
+        bgt             2b
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN h
+        add             \mx,  \mx,  #2
+        vld1.32         {d0[]}, [\mx]
+        sub             \src,  \src,  #1
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+4:
+        vld1.8          {d16}, [\src], \s_strd
+        vld1.8          {d24}, [\sr2], \s_strd
+        vmovl.u8        q8,  d16
+        vmovl.u8        q12, d24
+        vext.8          d18, d16, d17, #2
+        vext.8          d20, d16, d17, #4
+        vext.8          d22, d16, d17, #6
+        vext.8          d26, d24, d25, #2
+        vext.8          d28, d24, d25, #4
+        vext.8          d30, d24, d25, #6
+        subs            \h,  \h,  #2
+        vmul.s16        d4,  d16, d0[0]
+        vmla.s16        d4,  d18, d0[1]
+        vmla.s16        d4,  d20, d0[2]
+        vmla.s16        d4,  d22, d0[3]
+        vmul.s16        d5,  d24, d0[0]
+        vmla.s16        d5,  d26, d0[1]
+        vmla.s16        d5,  d28, d0[2]
+        vmla.s16        d5,  d30, d0[3]
+        vrshr.s16       q2,  q2,  #2
+.ifc \type, put
+        vqrshrun.s16    d4,  q2,  #4
+        vst1.32         {d4[0]}, [\dst, :32], \d_strd
+        vst1.32         {d4[1]}, [\ds2, :32], \d_strd
+.else
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d5}, [\ds2, :64], \d_strd
+.endif
+        bgt             4b
+        pop             {r4-r11,pc}
+
+80:     // 8xN h
+        vld1.8          {d0}, [\mx, :64]
+        sub             \src,  \src,  #3
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+8:
+        vld1.8          {q8},  [\src], \s_strd
+        vld1.8          {q12}, [\sr2], \s_strd
+        vmovl.u8        q9,  d17
+        vmovl.u8        q8,  d16
+        vmovl.u8        q13, d25
+        vmovl.u8        q12, d24
+
+        vmul.s16        q10, q8,  d0[0]
+        vmul.s16        q14, q12, d0[0]
+.irpc i, 1234567
+        vext.8          q11, q8,  q9,  #(2*\i)
+        vext.8          q15, q12, q13, #(2*\i)
+.if \i < 4
+        vmla.s16        q10, q11, d0[\i]
+        vmla.s16        q14, q15, d0[\i]
+.else
+        vmla.s16        q10, q11, d1[\i-4]
+        vmla.s16        q14, q15, d1[\i-4]
+.endif
+.endr
+        subs            \h,  \h,  #2
+        vrshr.s16       q10, q10, #2
+        vrshr.s16       q14, q14, #2
+.ifc \type, put
+        vqrshrun.s16    d20, q10, #4
+        vqrshrun.s16    d28, q14, #4
+        vst1.8          {d20}, [\dst, :64], \d_strd
+        vst1.8          {d28}, [\ds2, :64], \d_strd
+.else
+        vst1.16         {q10}, [\dst, :128], \d_strd
+        vst1.16         {q14}, [\ds2, :128], \d_strd
+.endif
+        bgt             8b
+        pop             {r4-r11,pc}
+
+160:
+320:
+640:
+1280:   // 16xN, 32xN, ... h
+        // This could be done without touching q4-q6, by using only
+        // one temporary for vext in the loop. That's slower on A7 and A53,
+        // (but surprisingly, marginally faster on A8 and A73).
+        vpush           {q4-q6}
+        vld1.8          {d0}, [\mx, :64]
+        sub             \src,  \src,  #3
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+
+        sub             \s_strd,  \s_strd,  \w
+        sub             \s_strd,  \s_strd,  #8
+.ifc \type, put
+        lsl             \d_strd,  \d_strd,  #1
+        sub             \d_strd,  \d_strd,  \w
+.endif
+161:
+        vld1.8          {d16, d17, d18},  [\src]!
+        vld1.8          {d24, d25, d26},  [\sr2]!
+        mov             \mx, \w
+        vmovl.u8        q10, d18
+        vmovl.u8        q9,  d17
+        vmovl.u8        q8,  d16
+        vmovl.u8        q14, d26
+        vmovl.u8        q13, d25
+        vmovl.u8        q12, d24
+
+16:
+        vmul.s16        q1,  q8,  d0[0]
+        vmul.s16        q2,  q9,  d0[0]
+        vmul.s16        q3,  q12, d0[0]
+        vmul.s16        q4,  q13, d0[0]
+.irpc i, 1234567
+        vext.8          q5,  q8,  q9,  #(2*\i)
+        vext.8          q6,  q9,  q10, #(2*\i)
+        vext.8          q11, q12, q13, #(2*\i)
+        vext.8          q15, q13, q14, #(2*\i)
+.if \i < 4
+        vmla.s16        q1,  q5,  d0[\i]
+        vmla.s16        q2,  q6,  d0[\i]
+        vmla.s16        q3,  q11, d0[\i]
+        vmla.s16        q4,  q15, d0[\i]
+.else
+        vmla.s16        q1,  q5,  d1[\i-4]
+        vmla.s16        q2,  q6,  d1[\i-4]
+        vmla.s16        q3,  q11, d1[\i-4]
+        vmla.s16        q4,  q15, d1[\i-4]
+.endif
+.endr
+        vrshr.s16       q1,  q1,  #2
+        vrshr.s16       q2,  q2,  #2
+        vrshr.s16       q3,  q3,  #2
+        vrshr.s16       q4,  q4,  #2
+        subs            \mx, \mx, #16
+.ifc \type, put
+        vqrshrun.s16    d2,  q1,  #4
+        vqrshrun.s16    d3,  q2,  #4
+        vqrshrun.s16    d4,  q3,  #4
+        vqrshrun.s16    d5,  q4,  #4
+        vst1.8          {q1}, [\dst, :128]!
+        vst1.8          {q2}, [\ds2, :128]!
+.else
+        vst1.16         {q1, q2}, [\dst, :128]!
+        vst1.16         {q3, q4}, [\ds2, :128]!
+.endif
+        ble             9f
+
+        vmov            q8,  q10
+        vmov            q12, q14
+        vld1.8          {d18, d19}, [\src]!
+        vld1.8          {d26, d27}, [\sr2]!
+        vmovl.u8        q10, d19
+        vmovl.u8        q9,  d18
+        vmovl.u8        q14, d27
+        vmovl.u8        q13, d26
+        b               16b
+
+9:
+        add             \dst,  \dst,  \d_strd
+        add             \ds2,  \ds2,  \d_strd
+        add             \src,  \src,  \s_strd
+        add             \sr2,  \sr2,  \s_strd
+
+        subs            \h,  \h,  #2
+        bgt             161b
+        vpop            {q4-q6}
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_v):
+        cmp             \h,  #4
+        ubfx            r9,  \my, #7, #7
+        and             \my, \my, #0x7f
+        it              gt
+        movgt           \my, r9
+        add             \my, r10, \my, lsl #3
+
+        adr             r9,  L(\type\()_8tap_v_tbl)
+        ldr             r8,  [r9, r8, lsl #2]
+        add             r9,  r9,  r8
+        bx              r9
+
+        .align 2
+L(\type\()_8tap_v_tbl):
+        .word 1280f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+
+20:     // 2xN v
+.ifc \type, put
+        bgt             28f
+
+        cmp             \h,  #2
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src,  \src,  \s_strd
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        vmovl.s8        q0,  d0
+
+        // 2x2 v
+        load_16         \src, \sr2, \s_strd, d1, d2, d3, d4, d5
+        interleave_1_16 d1, d2, d3, d4, d5
+        bgt             24f
+        vmovl_u8        q8, d1, q9, d2, q10, d3, q11, d4
+        mul_mla_4       d6, d16, d18, d20, d22
+        vqrshrun_s16    6,   q3,  d6
+        st_16           \d_strd, d6, 2
+        pop             {r4-r11,pc}
+
+24:     // 2x4 v
+        load_16         \sr2, \src, \s_strd, d6, d7
+        interleave_1_16 d5, d6, d7
+        vmovl_u8        q8, d1, q9, d2, q10, d3, q11, d4, q12, d5, q13, d6
+        vmov            d17, d20
+        vmov            d19, d22
+        vmov            d21, d24
+        vmov            d23, d26
+        mul_mla_4       q3, q8, q9, q10, q11
+        vqrshrun_s16    6,   q3,  d6
+        st_16           \d_strd, d6, 4
+        pop             {r4-r11,pc}
+
+28:     // 2x6, 2x8, 2x12, 2x16 v
+        vpush           {q4-q7}
+        vld1.8          {d0}, [\my, :64]
+        sub             \sr2,  \src,  \s_strd, lsl #1
+        add             \ds2,  \dst,  \d_strd
+        sub             \src,  \sr2,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+
+        load_16         \src, \sr2, \s_strd, d2,  d4,  d6,  d8,  d10, d12, d14
+        interleave_1_16 d2,  d4,  d6,  d8,  d10
+        interleave_1_16 d10, d12, d14
+        vmovl_u8        q1,  d2,  q2,  d4,  q3,  d6,  q4,  d8,  q5,  d10, q6,  d12
+        vmov            d3,  d6
+        vmov            d5,  d8
+        vmov            d7,  d10
+        vmov            d9,  d12
+216:
+        subs            \h,  \h,  #4
+        load_16         \sr2, \src, \s_strd, d16, d18, d20, d22
+        interleave_1_16 d14, d16, d18, d20, d22
+        vmovl_u8        q7,  d14, q8,  d16, q9,  d18, q10, d20
+        vmov            d11, d14
+        vmov            d13, d16
+        vmov            d15, d18
+        vmov            d17, d20
+        mul_mla_8_0     q1,  q1,  q2,  q3,  q4,  q5,  q6,  q7, q8
+        vqrshrun_s16    6,   q1,  d2
+        st_16           \d_strd, d2, 4
+        ble             0f
+        cmp             \h,  #2
+        vmov            q1,  q5
+        vmov            q2,  q6
+        vmov            q3,  q7
+        vmov            q4,  q8
+        vmov            q5,  q9
+        vmov            q6,  q10
+        vmov            d14, d22
+        beq             26f
+        b               216b
+26:
+        load_16         \sr2, \src, \s_strd, d16, d18
+        interleave_1_16 d14, d16, d18
+        vmovl_u8        q7,  d14, q8,  d16
+        vmov            d11, d14
+        vmov            d13, d16
+        mul_mla_8_0     d2,  d2,  d4,  d6,  d8,  d10, d12, d14, d16
+        vqrshrun_s16    6,   q1,  d2
+        st_16           \d_strd, d2, 2
+0:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+.endif
+
+40:
+        bgt            480f
+
+        // 4x2, 4x4 v
+        cmp             \h,  #2
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+
+        load_32         \src, \sr2, \s_strd, d1, d2, d3, d4, d5
+        interleave_1_32 d1,  d2,  d3,  d4,  d5
+        vmovl_u8        q8,  d1,  q9,  d2,  q10, d3,  q11, d4
+        mul_mla_4       q3,  q8,  q9,  q10, q11
+        shift_store_4   \type, \d_strd, q3, d6, d7
+        ble             0f
+        load_32         \sr2, \src, \s_strd, d6, d7
+        interleave_1_32 d5,  d6,  d7
+        vmovl_u8        q12, d5,  q13, d6
+        mul_mla_4       q3,  q10, q11, q12, q13
+        shift_store_4   \type, \d_strd, q3, d6, d7
+0:
+        pop             {r4-r11,pc}
+
+480:    // 4x6, 4x8, 4x12, 4x16 v
+        vpush           {q4}
+        vld1.8          {d0}, [\my, :64]
+        sub             \sr2, \src, \s_strd, lsl #1
+        add             \ds2, \dst, \d_strd
+        sub             \src, \sr2, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+
+        load_32         \src, \sr2, \s_strd, d2,  d4,  d6,  d8,  d16, d18, d20
+        interleave_1_32 d2,  d4,  d6
+        interleave_1_32 d6,  d8,  d16, d18, d20
+        vmovl_u8        q1,  d2,  q2,  d4,  q3,  d6,  q4,  d8,  q8,  d16, q9,  d18
+
+48:
+        subs            \h,  \h,  #4
+        load_32         \sr2, \src, \s_strd, d22, d24, d26, d28
+        interleave_1_32 d20, d22, d24, d26, d28
+        vmovl_u8        q10, d20, q11, d22, q12, d24, q13, d26
+        mul_mla_8_2     q1,  q2,  q1,  q2,  q3,  q4,  q8,  q9,  q10, q11, q12, q13
+        shift_store_4   \type, \d_strd, q1,  d2,  d3,  q2,  d4,  d5
+        ble             0f
+        load_32         \sr2,  \src, \s_strd, d30, d2
+        subs            \h,  \h,  #2
+        interleave_1_32 d28, d30, d2
+        vmovl_u8        q14, d28, q15, d30
+        mul_mla_8_0     q8,  q8,  q9,  q10, q11, q12, q13, q14, q15
+        shift_store_4   \type, \d_strd, q8,  d16, d17
+        ble             0f
+        load_32         \sr2,  \src, \s_strd, d4,  d6
+        subs            \h,  \h,  #2
+        interleave_1_32 d2,  d4,  d6
+        vmovl_u8        q1,  d2,  q2,  d4
+        mul_mla_8_0     q9,  q10, q11, q12, q13, q14, q15, q1,  q2
+        shift_store_4   \type, \d_strd, q9,  d18, d19
+        ble             0f
+        subs            \h,  \h,  #4
+        load_32         \sr2, \src, \s_strd, d8,  d16, d18, d20
+        interleave_1_32 d6,  d8,  d16, d18, d20
+        vmovl_u8        q3,  d6,  q4,  d8,  q8,  d16, q9, d18
+        mul_mla_8_2     q12, q13, q12, q13, q14, q15, q1,  q2,  q3,  q4,  q8,  q9
+        shift_store_4   \type, \d_strd, q12, d24, d25, q13, d26, d27
+        bgt             48b
+0:
+        vpop            {q4}
+        pop             {r4-r11,pc}
+
+80:
+        bgt             880f
+
+        // 8x2, 8x4 v
+        cmp             \h,  #2
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+
+        load_reg        \src, \sr2, \s_strd, d1, d2, d3, d4, d5
+        vmovl_u8        q8,  d1,  q9,  d2,  q10, d3,  q11, d4,  q12, d5
+        mul_mla_4       q1,  q8,  q9,  q10, q11
+        mul_mla_4       q2,  q9,  q10, q11, q12
+        shift_store_8   \type, \d_strd, q1, d2, q2, d4
+        ble             0f
+        load_reg        \sr2, \src, \s_strd, d6, d7
+        vmovl_u8        q13, d6,  q14, d7
+        mul_mla_4       q1,  q10, q11, q12, q13
+        mul_mla_4       q2,  q11, q12, q13, q14
+        shift_store_8   \type, \d_strd, q1, d2, q2, d4
+0:
+        pop             {r4-r11,pc}
+
+880:    // 8x6, 8x8, 8x16, 8x32 v
+1680:   // 16x8, 16x16, ...
+320:    // 32x8, 32x16, ...
+640:
+1280:
+        vpush           {q4}
+        vld1.8          {d0}, [\my, :64]
+        sub             \src, \src, \s_strd
+        sub             \src, \src, \s_strd, lsl #1
+        vmovl.s8        q0,  d0
+        mov             \my, \h
+168:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        load_reg        \src, \sr2, \s_strd, d2,  d4,  d6,  d8,  d16, d18, d20
+        vmovl_u8        q1,  d2,  q2,  d4,  q3,  d6,  q4,  d8,  q8,  d16, q9,  d18, q10, d20
+
+88:
+        subs            \h,  \h,  #2
+        load_reg        \sr2, \src, \s_strd, d22, d24
+        vmovl_u8        q11, d22, q12, d24
+        mul_mla_8_1     q1,  q2,  q1,  q2,  q3,  q4,  q8,  q9,  q10,  q11, q12
+        shift_store_8   \type, \d_strd, q1,  d2,  q2,  d4
+        ble             9f
+        subs            \h,  \h,  #2
+        load_reg        \sr2, \src, \s_strd, d26, d28
+        vmovl_u8        q13, d26, q14, d28
+        mul_mla_8_1     q3,  q4,  q3,  q4,  q8,  q9,  q10, q11, q12, q13, q14
+        shift_store_8   \type, \d_strd, q3,  d6,  q4,  d8
+        ble             9f
+        subs            \h,  \h,  #2
+        load_reg        \sr2, \src, \s_strd, d30, d2
+        vmovl_u8        q15, d30, q1,  d2
+        mul_mla_8_1     q8,  q9,  q8,  q9,  q10, q11, q12, q13, q14, q15, q1
+        shift_store_8   \type, \d_strd, q8,  d16, q9,  d18
+        ble             9f
+        subs            \h,  \h,  #2
+        load_reg        \sr2, \src, \s_strd, d4,  d6
+        vmovl_u8        q2,  d4,  q3,  d6
+        mul_mla_8_1     q10, q11, q10, q11, q12, q13, q14, q15, q1,  q2,  q3
+        shift_store_8   \type, \d_strd, q10, d20, q11, d22
+        ble             9f
+        subs            \h,  \h,  #4
+        load_reg        \sr2, \src, \s_strd, d8,  d16, d18, d20
+        vmovl_u8        q4,  d8,  q8,  d16, q9,  d18, q10, d20
+        mul_mla_8_1     q12, q13, q12, q13, q14, q15, q1,  q2,  q3,  q4,  q8
+        mul_mla_8_1     q14, q15, q14, q15, q1,  q2,  q3,  q4,  q8,  q9,  q10
+        shift_store_8   \type, \d_strd, q12, d24, q13, d26, q14, d28, q15, d30
+        bgt             88b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        mls             \src, \s_strd, \my, \src
+        mls             \dst, \d_strd, \my, \dst
+        sub             \src, \src, \s_strd, lsl #3
+        mov             \h,  \my
+        add             \src, \src, #8
+.ifc \type, put
+        add             \dst, \dst, #8
+.else
+        add             \dst, \dst, #16
+.endif
+        b               168b
+0:
+        vpop            {q4}
+        pop             {r4-r11,pc}
+
+160:
+        bgt             1680b
+
+        // 16x2, 16x4 v
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+
+        cmp             \h,  #2
+        load_reg        \src, \sr2, \s_strd, q11, q12, q13, q14, q15
+        vmovl.u8        q1,  d22
+        vmovl.u8        q2,  d24
+        vmovl.u8        q3,  d26
+        vmovl.u8        q8,  d28
+        vmovl.u8        q9,  d30
+        vmovl.u8        q11, d23
+        vmovl.u8        q12, d25
+        vmovl.u8        q13, d27
+        vmovl.u8        q14, d29
+        vmovl.u8        q15, d31
+        mul_mla_4       q1,  q1,  q2,  q3,  q8
+        mul_mla_4       q10, q2,  q3,  q8,  q9
+        mul_mla_4       q2,  q11, q12, q13, q14
+        mul_mla_4       q11, q12, q13, q14, q15
+        shift_store_16  \type, \d_strd, q1, d2, d3, q2, q10, d20, d21, q11
+        ble             0f
+        load_reg        \sr2, \src, \s_strd, q10, q11
+        vmovl.u8        q1,  d20
+        vmovl.u8        q10, d21
+        vmovl.u8        q12, d22
+        vmovl.u8        q11, d23
+        mul_mla_4       q2,  q3,  q8,  q9,  q1
+        mul_mla_4       q3,  q13, q14, q15, q10
+        mul_mla_4       q13, q8,  q9,  q1,  q12
+        mul_mla_4       q14, q14, q15, q10, q11
+        shift_store_16  \type, \d_strd, q2, d4, d5, q3, q13, d26, d27, q14
+0:
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_hv):
+        cmp             \h,  #4
+        ubfx            r9,  \my, #7, #7
+        and             \my, \my, #0x7f
+        it              gt
+        movgt           \my, r9
+        add             \my,  r10, \my, lsl #3
+
+        adr             r9,  L(\type\()_8tap_hv_tbl)
+        ldr             r8,  [r9, r8, lsl #2]
+        add             r9,  r9,  r8
+        bx              r9
+
+        .align 2
+L(\type\()_8tap_hv_tbl):
+        .word 1280f - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+
+20:
+.ifc \type, put
+        add             \mx,  \mx,  #2
+        vld1.32         {d0[]},  [\mx]
+        bgt             280f
+        add             \my,  \my,  #2
+        vld1.32         {d2[]},  [\my]
+
+        // 2x2, 2x4 hv
+        sub             \sr2, \src, #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+
+        vld1.8          {d26}, [\src], \s_strd
+        vmovl.u8        q13, d26
+        vext.8          q14, q13, q13, #2
+        vmul.s16        d26, d26, d0
+        vmul.s16        d28, d28, d0
+        vpadd.s16       d26, d26, d28
+        vpadd.s16       d26, d26, d26
+        vrshr.s16       d16, d26, #2
+        bl              L(\type\()_8tap_filter_2)
+
+        vext.8          d16, d16, d16, #4
+        vmov            d17, d26
+        vext.8          d16, d16, d26, #4
+
+2:
+        bl              L(\type\()_8tap_filter_2)
+
+        vext.8          d18, d17, d26, #4
+        vmull.s16       q2,  d16, d2[0]
+        vmlal.s16       q2,  d17, d2[1]
+        vmlal.s16       q2,  d18, d2[2]
+        vmlal.s16       q2,  d26, d2[3]
+
+        vqrshrn.s32     d4,  q2,  #\shift_hv
+        vqmovun.s16     d4,  q2
+        subs            \h,  \h,  #2
+        vst1.16         {d4[0]}, [\dst, :16], \d_strd
+        vst1.16         {d4[1]}, [\ds2, :16], \d_strd
+        ble             0f
+        vmov            d16, d18
+        vmov            d17, d26
+        b               2b
+
+280:    // 2x8, 2x16, 2x32 hv
+        vld1.8          {d2},  [\my, :64]
+        sub             \src, \src, #1
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        vld1.8          {d26}, [\src], \s_strd
+        vmovl.u8        q13, d26
+        vext.8          q14, q13, q13, #2
+        vmul.s16        d26, d26, d0
+        vmul.s16        d28, d28, d0
+        vpadd.s16       d26, d26, d28
+        vpadd.s16       d26, d26, d26
+        vrshr.s16       d16, d26, #2
+
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d16, d16, d16, #4
+        vmov            d17, d26
+        vext.8          d16, d16, d26, #4
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d18, d17, d26, #4
+        vmov            d19, d26
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d20, d19, d26, #4
+        vmov            d21, d26
+
+28:
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d22, d21, d26, #4
+        vmull.s16       q2,  d16, d2[0]
+        vmlal.s16       q2,  d17, d2[1]
+        vmlal.s16       q2,  d18, d2[2]
+        vmlal.s16       q2,  d19, d2[3]
+        vmlal.s16       q2,  d20, d3[0]
+        vmlal.s16       q2,  d21, d3[1]
+        vmlal.s16       q2,  d22, d3[2]
+        vmlal.s16       q2,  d26, d3[3]
+
+        vqrshrn.s32     d4,  q2,  #\shift_hv
+        vqmovun.s16     d4,  q2
+        subs            \h,  \h,  #2
+        vst1.16         {d4[0]}, [\dst, :16], \d_strd
+        vst1.16         {d4[1]}, [\ds2, :16], \d_strd
+        ble             0f
+        vmov            d16, d18
+        vmov            d17, d19
+        vmov            d18, d20
+        vmov            d19, d21
+        vmov            d20, d22
+        vmov            d21, d26
+        b               28b
+
+0:
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_2):
+        vld1.8          {d28},  [\sr2], \s_strd
+        vld1.8          {d30},  [\src], \s_strd
+        vext.8          d29, d28, d28, #1
+        vext.8          d31, d30, d30, #1
+        vmovl.u8        q13, d28
+        vmovl.u8        q14, d29
+        vmov            d27, d28
+        vmovl.u8        q14, d30
+        vmovl.u8        q15, d31
+        vtrn.32         d26, d28
+        vtrn.32         d27, d30
+        vmul.s16        d26, d26, d0[0]
+        vmla.s16        d26, d27, d0[1]
+        vmla.s16        d26, d28, d0[2]
+        vmla.s16        d26, d30, d0[3]
+        vrshr.s16       d26, d26, #2
+        vext.8          d27, d26, d26, #4
+        bx              lr
+.endif
+
+40:
+        add             \mx, \mx, #2
+        vld1.32         {d0[]},  [\mx]
+        bgt             480f
+        add             \my, \my,  #2
+        vld1.32         {d2[]},  [\my]
+        sub             \sr2, \src, #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        // 4x2, 4x4 hv
+        vld1.8          {d30}, [\src], \s_strd
+        vmovl.u8        q14, d30
+        vext.8          d27, d28, d29, #2
+        vext.8          d30, d28, d29, #4
+        vext.8          d31, d28, d29, #6
+        vmul.s16        d26, d28, d0[0]
+        vmla.s16        d26, d27, d0[1]
+        vmla.s16        d26, d30, d0[2]
+        vmla.s16        d26, d31, d0[3]
+        vrshr.s16       d16, d26, #2
+
+        bl              L(\type\()_8tap_filter_4)
+        vmov            d17, d26
+        vmov            d18, d27
+
+4:
+        bl              L(\type\()_8tap_filter_4)
+        vmull.s16       q2,  d16, d2[0]
+        vmlal.s16       q2,  d17, d2[1]
+        vmlal.s16       q2,  d18, d2[2]
+        vmlal.s16       q2,  d26, d2[3]
+        vmull.s16       q3,  d17, d2[0]
+        vmlal.s16       q3,  d18, d2[1]
+        vmlal.s16       q3,  d26, d2[2]
+        vmlal.s16       q3,  d27, d2[3]
+        vqrshrn.s32     d4,  q2,  #\shift_hv
+        vqrshrn.s32     d6,  q3,  #\shift_hv
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqmovun.s16     d4,  q2
+        vqmovun.s16     d6,  q3
+        vst1.32         {d4[0]}, [\dst, :32], \d_strd
+        vst1.32         {d6[0]}, [\ds2, :32], \d_strd
+.else
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d6}, [\ds2, :64], \d_strd
+.endif
+        ble             0f
+        vmov            d16, d18
+        vmov            d17, d26
+        vmov            d18, d27
+        b               4b
+
+480:    // 4x8, 4x16, 4x32 hv
+        vld1.8          {d2},  [\my, :64]
+        sub             \src, \src, #1
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        vld1.8          {d30}, [\src], \s_strd
+        vmovl.u8        q14, d30
+        vext.8          d27, d28, d29, #2
+        vext.8          d30, d28, d29, #4
+        vext.8          d31, d28, d29, #6
+        vmul.s16        d26, d28, d0[0]
+        vmla.s16        d26, d27, d0[1]
+        vmla.s16        d26, d30, d0[2]
+        vmla.s16        d26, d31, d0[3]
+        vrshr.s16       d16, d26, #2
+
+        bl              L(\type\()_8tap_filter_4)
+        vmov            d17, d26
+        vmov            d18, d27
+        bl              L(\type\()_8tap_filter_4)
+        vmov            d19, d26
+        vmov            d20, d27
+        bl              L(\type\()_8tap_filter_4)
+        vmov            d21, d26
+        vmov            d22, d27
+
+48:
+        bl              L(\type\()_8tap_filter_4)
+        vmull.s16       q2,  d16, d2[0]
+        vmlal.s16       q2,  d17, d2[1]
+        vmlal.s16       q2,  d18, d2[2]
+        vmlal.s16       q2,  d19, d2[3]
+        vmlal.s16       q2,  d20, d3[0]
+        vmlal.s16       q2,  d21, d3[1]
+        vmlal.s16       q2,  d22, d3[2]
+        vmlal.s16       q2,  d26, d3[3]
+        vmull.s16       q3,  d17, d2[0]
+        vmlal.s16       q3,  d18, d2[1]
+        vmlal.s16       q3,  d19, d2[2]
+        vmlal.s16       q3,  d20, d2[3]
+        vmlal.s16       q3,  d21, d3[0]
+        vmlal.s16       q3,  d22, d3[1]
+        vmlal.s16       q3,  d26, d3[2]
+        vmlal.s16       q3,  d27, d3[3]
+        vqrshrn.s32     d4,  q2,  #\shift_hv
+        vqrshrn.s32     d6,  q3,  #\shift_hv
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqmovun.s16     d4,  q2
+        vqmovun.s16     d6,  q3
+        vst1.32         {d4[0]}, [\dst, :32], \d_strd
+        vst1.32         {d6[0]}, [\ds2, :32], \d_strd
+.else
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d6}, [\ds2, :64], \d_strd
+.endif
+        ble             0f
+        vmov            d16, d18
+        vmov            d17, d19
+        vmov            d18, d20
+        vmov            d19, d21
+        vmov            d20, d22
+        vmov            d21, d26
+        vmov            d22, d27
+        b               48b
+0:
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_4):
+        vld1.8          {d30}, [\sr2], \s_strd
+        vld1.8          {d31}, [\src], \s_strd
+        vmovl.u8        q14, d30
+        vext.8          d27, d28, d29, #2
+        vext.8          d30, d28, d29, #4
+        vext.8          d1,  d28, d29, #6
+        vmul.s16        d26, d28, d0[0]
+        vmla.s16        d26, d27, d0[1]
+        vmla.s16        d26, d30, d0[2]
+        vmla.s16        d26, d1,  d0[3]
+
+        vmovl.u8        q14, d31
+        vext.8          d30, d28, d29, #2
+        vext.8          d31, d28, d29, #4
+        vext.8          d1,  d28, d29, #6
+        vmul.s16        d27, d28, d0[0]
+        vmla.s16        d27, d30, d0[1]
+        vmla.s16        d27, d31, d0[2]
+        vmla.s16        d27, d1,  d0[3]
+        vrshr.s16       d26, d26, #2
+        vrshr.s16       d27, d27, #2
+        bx              lr
+
+80:
+160:
+320:
+        bgt             880f
+        vpush           {q4-q7}
+        add             \my,  \my,  #2
+        vld1.8          {d0},  [\mx, :64]
+        vld1.32         {d2[]},  [\my]
+        sub             \src,  \src,  #3
+        sub             \src,  \src,  \s_strd
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+        mov             \my, \h
+
+164:    // 8x2, 8x4, 16x2, 16x4, 32x2, 32x4 hv
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        vld1.8          {q14},  [\src], \s_strd
+        vmovl.u8        q12, d28
+        vmovl.u8        q13, d29
+        vmul.s16        q10, q12, d0[0]
+.irpc i, 123
+        vext.8          q14, q12, q13, #(2*\i)
+        vmla.s16        q10, q14, d0[\i]
+.endr
+.irpc i, 4567
+        vext.8          q14, q12, q13, #(2*\i)
+        vmla.s16        q10, q14, d1[\i-4]
+.endr
+        vrshr.s16       q3,  q10, #2
+
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q4,  q10
+        vmov            q5,  q11
+
+8:
+        bl              L(\type\()_8tap_filter_8)
+        vmull.s16       q12, d6,  d2[0]
+        vmull.s16       q13, d7,  d2[0]
+        vmull.s16       q14, d8,  d2[0]
+        vmull.s16       q15, d9,  d2[0]
+        vmlal.s16       q12, d8,  d2[1]
+        vmlal.s16       q13, d9,  d2[1]
+        vmlal.s16       q14, d10, d2[1]
+        vmlal.s16       q15, d11, d2[1]
+        vmlal.s16       q12, d10, d2[2]
+        vmlal.s16       q13, d11, d2[2]
+        vmlal.s16       q14, d20, d2[2]
+        vmlal.s16       q15, d21, d2[2]
+        vmlal.s16       q12, d20, d2[3]
+        vmlal.s16       q13, d21, d2[3]
+        vmlal.s16       q14, d22, d2[3]
+        vmlal.s16       q15, d23, d2[3]
+        vqrshrn.s32     d24, q12, #\shift_hv
+        vqrshrn.s32     d25, q13, #\shift_hv
+        vqrshrn.s32     d28, q14, #\shift_hv
+        vqrshrn.s32     d29, q15, #\shift_hv
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqmovun.s16     d24, q12
+        vqmovun.s16     d28, q14
+        vst1.8          {d24}, [\dst, :64], \d_strd
+        vst1.8          {d28}, [\ds2, :64], \d_strd
+.else
+        vst1.16         {q12}, [\dst, :128], \d_strd
+        vst1.16         {q14}, [\ds2, :128], \d_strd
+.endif
+        ble             9f
+        vmov            q3,  q5
+        vmov            q4,  q10
+        vmov            q5,  q11
+        b               8b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #2
+        mov             \h,  \my
+        add             \src,  \src,  #8
+.ifc \type, put
+        add             \dst,  \dst,  #8
+.else
+        add             \dst,  \dst,  #16
+.endif
+        b               164b
+
+880:    // 8x8, 8x16, ..., 16x8, ..., 32x8, ... hv
+640:
+1280:
+        vpush           {q4-q7}
+        vld1.8          {d0},  [\mx, :64]
+        vld1.8          {d2},  [\my, :64]
+        sub             \src,  \src,  #3
+        sub             \src,  \src,  \s_strd
+        sub             \src,  \src,  \s_strd, lsl #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+        mov             \my, \h
+
+168:
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        vld1.8          {q14},  [\src], \s_strd
+        vmovl.u8        q12, d28
+        vmovl.u8        q13, d29
+        vmul.s16        q10, q12, d0[0]
+.irpc i, 123
+        vext.8          q14, q12, q13, #(2*\i)
+        vmla.s16        q10, q14, d0[\i]
+.endr
+.irpc i, 4567
+        vext.8          q14, q12, q13, #(2*\i)
+        vmla.s16        q10, q14, d1[\i-4]
+.endr
+        vrshr.s16       q3,  q10, #2
+
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q4,  q10
+        vmov            q5,  q11
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q6,  q10
+        vmov            q7,  q11
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q8,  q10
+        vmov            q9,  q11
+
+88:
+        bl              L(\type\()_8tap_filter_8)
+        vmull.s16       q12, d6,  d2[0]
+        vmull.s16       q13, d7,  d2[0]
+        vmull.s16       q14, d8,  d2[0]
+        vmull.s16       q15, d9,  d2[0]
+        vmlal.s16       q12, d8,  d2[1]
+        vmlal.s16       q13, d9,  d2[1]
+        vmlal.s16       q14, d10, d2[1]
+        vmlal.s16       q15, d11, d2[1]
+        vmlal.s16       q12, d10, d2[2]
+        vmlal.s16       q13, d11, d2[2]
+        vmlal.s16       q14, d12, d2[2]
+        vmlal.s16       q15, d13, d2[2]
+        vmlal.s16       q12, d12, d2[3]
+        vmlal.s16       q13, d13, d2[3]
+        vmlal.s16       q14, d14, d2[3]
+        vmlal.s16       q15, d15, d2[3]
+        vmlal.s16       q12, d14, d3[0]
+        vmlal.s16       q13, d15, d3[0]
+        vmlal.s16       q14, d16, d3[0]
+        vmlal.s16       q15, d17, d3[0]
+        vmlal.s16       q12, d16, d3[1]
+        vmlal.s16       q13, d17, d3[1]
+        vmlal.s16       q14, d18, d3[1]
+        vmlal.s16       q15, d19, d3[1]
+        vmlal.s16       q12, d18, d3[2]
+        vmlal.s16       q13, d19, d3[2]
+        vmlal.s16       q14, d20, d3[2]
+        vmlal.s16       q15, d21, d3[2]
+        vmlal.s16       q12, d20, d3[3]
+        vmlal.s16       q13, d21, d3[3]
+        vmlal.s16       q14, d22, d3[3]
+        vmlal.s16       q15, d23, d3[3]
+        vqrshrn.s32     d24, q12, #\shift_hv
+        vqrshrn.s32     d25, q13, #\shift_hv
+        vqrshrn.s32     d28, q14, #\shift_hv
+        vqrshrn.s32     d29, q15, #\shift_hv
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqmovun.s16     d24, q12
+        vqmovun.s16     d28, q14
+        vst1.8          {d24}, [\dst, :64], \d_strd
+        vst1.8          {d28}, [\ds2, :64], \d_strd
+.else
+        vst1.16         {q12}, [\dst, :128], \d_strd
+        vst1.16         {q14}, [\ds2, :128], \d_strd
+.endif
+        ble             9f
+        vmov            q3,  q5
+        vmov            q4,  q6
+        vmov            q5,  q7
+        vmov            q6,  q8
+        vmov            q7,  q9
+        vmov            q8,  q10
+        vmov            q9,  q11
+        b               88b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #3
+        mov             \h,  \my
+        add             \src,  \src,  #8
+.ifc \type, put
+        add             \dst,  \dst,  #8
+.else
+        add             \dst,  \dst,  #16
+.endif
+        b               168b
+0:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_8):
+        vld1.8          {q14},  [\sr2], \s_strd
+        vld1.8          {q15},  [\src], \s_strd
+        vmovl.u8        q12, d28
+        vmovl.u8        q13, d29
+        vmul.s16        q10, q12, d0[0]
+.irpc i, 123
+        vext.8          q14, q12, q13, #(2*\i)
+        vmla.s16        q10, q14, d0[\i]
+.endr
+.irpc i, 4567
+        vext.8          q14, q12, q13, #(2*\i)
+        vmla.s16        q10, q14, d1[\i-4]
+.endr
+        vmovl.u8        q12, d30
+        vmovl.u8        q13, d31
+        vmul.s16        q11, q12, d0[0]
+.irpc i, 123
+        vext.8          q14, q12, q13, #(2*\i)
+        vmla.s16        q11, q14, d0[\i]
+.endr
+.irpc i, 4567
+        vext.8          q14, q12, q13, #(2*\i)
+        vmla.s16        q11, q14, d1[\i-4]
+.endr
+        vrshr.s16       q10, q10, #2
+        vrshr.s16       q11, q11, #2
+        bx              lr
+endfunc
+
+
+function \type\()_bilin_8bpc_neon, export=1
+        push            {r4-r11,lr}
+        ldrd            r4,  r5,  [sp, #36]
+        ldrd            r6,  r7,  [sp, #44]
+        vdup.8          d1,  \mx
+        vdup.8          d3,  \my
+        rsb             r8,  \mx, #16
+        rsb             r9,  \my, #16
+        vdup.8          d0,  r8
+        vdup.8          d2,  r9
+.ifc \type, prep
+        lsl             \d_strd, \w, #1
+.endif
+        clz             r8,  \w
+        cmp             \mx, #0
+        sub             r8,  r8,  #24
+        bne             L(\type\()_bilin_h)
+        cmp             \my, #0
+        bne             L(\type\()_bilin_v)
+        b               \type\()_neon
+
+L(\type\()_bilin_h):
+        cmp             \my, #0
+        bne             L(\type\()_bilin_hv)
+
+        adr             r9,  L(\type\()_bilin_h_tbl)
+        ldr             r8,  [r9, r8, lsl #2]
+        add             r9,  r9,  r8
+        bx              r9
+
+        .align 2
+L(\type\()_bilin_h_tbl):
+        .word 1280f - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+
+20:     // 2xN h
+.ifc \type, put
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+2:
+        vld1.32         {d4[]},  [\src], \s_strd
+        vld1.32         {d6[]},  [\sr2], \s_strd
+        vext.8          d5,  d4,  d4, #1
+        vext.8          d7,  d6,  d6, #1
+        vtrn.16         q2,  q3
+        subs            \h,  \h,  #2
+        vmull.u8        q3,  d4,  d0
+        vmlal.u8        q3,  d5,  d1
+        vqrshrn.u16     d4,  q3,  #4
+        vst1.16         {d4[0]}, [\dst, :16], \d_strd
+        vst1.16         {d4[1]}, [\ds2, :16], \d_strd
+        bgt             2b
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN h
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+4:
+        vld1.8          {d4}, [\src], \s_strd
+        vld1.8          {d6}, [\sr2], \s_strd
+        vext.8          d5,  d4,  d4, #1
+        vext.8          d7,  d6,  d6, #1
+        vtrn.32         q2,  q3
+        subs            \h,  \h,  #2
+        vmull.u8        q3,  d4,  d0
+        vmlal.u8        q3,  d5,  d1
+.ifc \type, put
+        vqrshrn.u16     d4,  q3,  #4
+        vst1.32         {d4[0]}, [\dst, :32], \d_strd
+        vst1.32         {d4[1]}, [\ds2, :32], \d_strd
+.else
+        vst1.16         {d6}, [\dst, :64], \d_strd
+        vst1.16         {d7}, [\ds2, :64], \d_strd
+.endif
+        bgt             4b
+        pop             {r4-r11,pc}
+
+80:     // 8xN h
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+8:
+        vld1.8          {q8},  [\src], \s_strd
+        vld1.8          {q10}, [\sr2], \s_strd
+        vext.8          q9,  q8,  q8,  #1
+        vext.8          q11, q10, q10, #1
+        subs            \h,  \h,  #2
+        vmull.u8        q8,  d16, d0
+        vmull.u8        q10, d20, d0
+        vmlal.u8        q8,  d18, d1
+        vmlal.u8        q10, d22, d1
+.ifc \type, put
+        vqrshrn.u16     d16,  q8,  #4
+        vqrshrn.u16     d18,  q10, #4
+        vst1.8          {d16}, [\dst, :64], \d_strd
+        vst1.8          {d18}, [\ds2, :64], \d_strd
+.else
+        vst1.16         {q8},  [\dst, :128], \d_strd
+        vst1.16         {q10}, [\ds2, :128], \d_strd
+.endif
+        bgt             8b
+        pop             {r4-r11,pc}
+160:
+320:
+640:
+1280:   // 16xN, 32xN, ... h
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+
+        sub             \s_strd,  \s_strd,  \w
+        sub             \s_strd,  \s_strd,  #8
+.ifc \type, put
+        lsl             \d_strd,  \d_strd,  #1
+        sub             \d_strd,  \d_strd,  \w
+.endif
+161:
+        vld1.8          {d16},  [\src]!
+        vld1.8          {d22},  [\sr2]!
+        mov             \mx, \w
+
+16:
+        vld1.8          {d17,d18},  [\src]!
+        vld1.8          {d23,d24},  [\sr2]!
+        vext.8          q10, q8,  q9,  #1
+        vext.8          q13, q11, q12, #1
+        vmull.u8        q2,  d16, d0
+        vmull.u8        q3,  d17, d0
+        vmull.u8        q14, d22, d0
+        vmull.u8        q15, d23, d0
+        vmlal.u8        q2,  d20, d1
+        vmlal.u8        q3,  d21, d1
+        vmlal.u8        q14, d26, d1
+        vmlal.u8        q15, d27, d1
+        subs            \mx, \mx, #16
+.ifc \type, put
+        vqrshrn.u16     d4,  q2,  #4
+        vqrshrn.u16     d5,  q3,  #4
+        vqrshrn.u16     d28, q14, #4
+        vqrshrn.u16     d29, q15, #4
+        vst1.8          {q2},  [\dst, :128]!
+        vst1.8          {q14}, [\ds2, :128]!
+.else
+        vst1.16         {q2,  q3},  [\dst, :128]!
+        vst1.16         {q14, q15}, [\ds2, :128]!
+.endif
+        ble             9f
+
+        vmov            d16, d18
+        vmov            d22, d24
+        b               16b
+
+9:
+        add             \dst,  \dst,  \d_strd
+        add             \ds2,  \ds2,  \d_strd
+        add             \src,  \src,  \s_strd
+        add             \sr2,  \sr2,  \s_strd
+
+        subs            \h,  \h,  #2
+        bgt             161b
+        pop             {r4-r11,pc}
+
+L(\type\()_bilin_v):
+        cmp             \h,  #4
+        adr             r9,  L(\type\()_bilin_v_tbl)
+        ldr             r8,  [r9, r8, lsl #2]
+        add             r9,  r9,  r8
+        bx              r9
+
+        .align 2
+L(\type\()_bilin_v_tbl):
+        .word 1280f - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+
+20:     // 2xN v
+.ifc \type, put
+        cmp             \h,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+
+        // 2x2 v
+        vld1.16         {d16[]}, [\src], \s_strd
+        bgt             24f
+22:
+        vld1.16         {d17[]}, [\sr2], \s_strd
+        vld1.16         {d18[]}, [\src], \s_strd
+        vext.8          d16, d16, d17, #6
+        vext.8          d17, d17, d18, #6
+        vmull.u8        q2,  d16, d2
+        vmlal.u8        q2,  d17, d3
+        vqrshrn.u16     d4,  q2,  #4
+        vst1.16         {d4[0]}, [\dst, :16]
+        vst1.16         {d4[1]}, [\ds2, :16]
+        pop             {r4-r11,pc}
+24:     // 2x4, 2x6, 2x8, ... v
+        vld1.16         {d17[]}, [\sr2], \s_strd
+        vld1.16         {d18[]}, [\src], \s_strd
+        vld1.16         {d19[]}, [\sr2], \s_strd
+        vld1.16         {d20[]}, [\src], \s_strd
+        sub             \h,  \h,  #4
+        vext.8          d16, d16, d17, #6
+        vext.8          d17, d17, d18, #6
+        vext.8          d18, d18, d19, #6
+        vext.8          d19, d19, d20, #6
+        vtrn.32         d16, d18
+        vtrn.32         d17, d19
+        vmull.u8        q2,  d16, d2
+        vmlal.u8        q2,  d17, d3
+        cmp             \h,  #2
+        vqrshrn.u16     d4,  q2,  #4
+        vst1.16         {d4[0]}, [\dst, :16], \d_strd
+        vst1.16         {d4[1]}, [\ds2, :16], \d_strd
+        vst1.16         {d4[2]}, [\dst, :16], \d_strd
+        vst1.16         {d4[3]}, [\ds2, :16], \d_strd
+        blt             0f
+        vmov            d16, d20
+        beq             22b
+        b               24b
+0:
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN v
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        vld1.32         {d16[]}, [\src], \s_strd
+4:
+        vld1.32         {d17[]}, [\sr2], \s_strd
+        vld1.32         {d18[]}, [\src], \s_strd
+        vext.8          d16, d16, d17, #4
+        vext.8          d17, d17, d18, #4
+        vmull.u8        q2,  d16, d2
+        vmlal.u8        q2,  d17, d3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqrshrn.u16     d4,  q2,  #4
+        vst1.32         {d4[0]}, [\dst, :32], \d_strd
+        vst1.32         {d4[1]}, [\ds2, :32], \d_strd
+.else
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d5}, [\ds2, :64], \d_strd
+.endif
+        ble             0f
+        vmov            d16,  d18
+        b               4b
+0:
+        pop             {r4-r11,pc}
+
+80:     // 8xN v
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        vld1.8          {d16}, [\src], \s_strd
+8:
+        vld1.8          {d17}, [\sr2], \s_strd
+        vld1.8          {d18}, [\src], \s_strd
+        vmull.u8        q2,  d16, d2
+        vmull.u8        q3,  d17, d2
+        vmlal.u8        q2,  d17, d3
+        vmlal.u8        q3,  d18, d3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqrshrn.u16     d4,  q2,  #4
+        vqrshrn.u16     d6,  q3,  #4
+        vst1.8          {d4}, [\dst, :64], \d_strd
+        vst1.8          {d6}, [\ds2, :64], \d_strd
+.else
+        vst1.16         {q2}, [\dst, :128], \d_strd
+        vst1.16         {q3}, [\ds2, :128], \d_strd
+.endif
+        ble             0f
+        vmov            d16, d18
+        b               8b
+0:
+        pop             {r4-r11,pc}
+
+160:    // 16xN, 32xN, ...
+320:
+640:
+1280:
+        mov             \my, \h
+1:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.8          {q8},  [\src], \s_strd
+2:
+        vld1.8          {q9},  [\sr2], \s_strd
+        vld1.8          {q10}, [\src], \s_strd
+        vmull.u8        q12, d16, d2
+        vmull.u8        q13, d17, d2
+        vmull.u8        q14, d18, d2
+        vmull.u8        q15, d19, d2
+        vmlal.u8        q12, d18, d3
+        vmlal.u8        q13, d19, d3
+        vmlal.u8        q14, d20, d3
+        vmlal.u8        q15, d21, d3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqrshrn.u16     d24, q12, #4
+        vqrshrn.u16     d25, q13, #4
+        vqrshrn.u16     d28, q14, #4
+        vqrshrn.u16     d29, q15, #4
+        vst1.8          {q12}, [\dst, :128], \d_strd
+        vst1.8          {q14}, [\ds2, :128], \d_strd
+.else
+        vst1.16         {q12, q13}, [\dst, :128], \d_strd
+        vst1.16         {q14, q15}, [\ds2, :128], \d_strd
+.endif
+        ble             9f
+        vmov            q8,  q10
+        b               2b
+9:
+        subs            \w,  \w,  #16
+        ble             0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        mls             \src, \s_strd, \my, \src
+        mls             \dst, \d_strd, \my, \dst
+        sub             \src, \src, \s_strd, lsl #1
+        mov             \h,  \my
+        add             \src, \src, #16
+.ifc \type, put
+        add             \dst, \dst, #16
+.else
+        add             \dst, \dst, #32
+.endif
+        b               1b
+0:
+        pop             {r4-r11,pc}
+
+L(\type\()_bilin_hv):
+        vmovl.u8        q2,  d2
+        vmovl.u8        q3,  d3
+        adr             r9,  L(\type\()_bilin_hv_tbl)
+        ldr             r8,  [r9, r8, lsl #2]
+        add             r9,  r9,  r8
+        bx              r9
+
+        .align 2
+L(\type\()_bilin_hv_tbl):
+        .word 1280f - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+
+20:     // 2xN hv
+.ifc \type, put
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.32         {d28[]},  [\src], \s_strd
+        vext.8          d29, d28, d28, #1
+        vmull.u8        q8,  d28, d0
+        vmlal.u8        q8,  d29, d1
+
+2:
+        vld1.32         {d28[]},  [\sr2], \s_strd
+        vld1.32         {d30[]},  [\src], \s_strd
+        vext.8          d29, d28, d28, #1
+        vext.8          d31, d30, d30, #1
+        vtrn.16         d28, d30
+        vtrn.16         d29, d31
+        vmull.u8        q9,  d28, d0
+        vmlal.u8        q9,  d29, d1
+
+        vtrn.32         d16, d18
+
+        vmul.u16        d20, d16, d4
+        vmla.u16        d20, d19, d6
+        vqrshrn.u16     d20, q10, #8
+        subs            \h,  \h,  #2
+        vst1.16         {d20[0]}, [\dst, :16], \d_strd
+        vst1.16         {d20[1]}, [\ds2, :16], \d_strd
+        ble             0f
+        vtrn.32         d19, d16
+        b               2b
+0:
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN hv
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.8          {d28},  [\src], \s_strd
+        vext.8          d29, d28, d28, #1
+        vmull.u8        q8,  d28, d0
+        vmlal.u8        q8,  d29, d1
+
+4:
+        vld1.8          {d28},  [\sr2], \s_strd
+        vld1.8          {d30},  [\src], \s_strd
+        vext.8          d29, d28, d28, #1
+        vext.8          d31, d30, d30, #1
+        vtrn.32         d28, d30
+        vtrn.32         d29, d31
+        vmull.u8        q9,  d28, d0
+        vmlal.u8        q9,  d29, d1
+
+        vmov            d17, d18
+
+        vmul.u16        q10, q8, q2
+        vmla.u16        q10, q9, q3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqrshrn.u16     d20, q10, #8
+        vst1.32         {d20[0]}, [\dst, :32], \d_strd
+        vst1.32         {d20[1]}, [\ds2, :32], \d_strd
+.else
+        vrshr.u16       q10, q10, #4
+        vst1.16         {d20}, [\dst, :64], \d_strd
+        vst1.16         {d21}, [\ds2, :64], \d_strd
+.endif
+        ble             0f
+        vmov            d16, d19
+        b               4b
+0:
+        pop             {r4-r11,pc}
+
+80:     // 8xN, 16xN, ... hv
+160:
+320:
+640:
+1280:
+        mov             \my, \h
+
+1:
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.8          {q12},  [\src], \s_strd
+        vext.8          q13, q12, q12, #1
+        vmull.u8        q8,  d24, d0
+        vmlal.u8        q8,  d26, d1
+
+2:
+        vld1.8          {q12},  [\sr2], \s_strd
+        vld1.8          {q14},  [\src], \s_strd
+        vext.8          q13, q12, q12, #1
+        vext.8          q15, q14, q14, #1
+        vmull.u8        q9,  d24, d0
+        vmlal.u8        q9,  d26, d1
+        vmull.u8        q10, d28, d0
+        vmlal.u8        q10, d30, d1
+
+        vmul.u16        q8,  q8,  q2
+        vmla.u16        q8,  q9,  q3
+        vmul.u16        q9,  q9,  q2
+        vmla.u16        q9,  q10, q3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vqrshrn.u16     d16, q8,  #8
+        vqrshrn.u16     d18, q9,  #8
+        vst1.8          {d16}, [\dst, :64], \d_strd
+        vst1.8          {d18}, [\ds2, :64], \d_strd
+.else
+        vrshr.u16       q8,  q8,  #4
+        vrshr.u16       q9,  q9,  #4
+        vst1.16         {q8}, [\dst, :128], \d_strd
+        vst1.16         {q9}, [\ds2, :128], \d_strd
+.endif
+        ble             9f
+        vmov            q8,  q10
+        b               2b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #1
+        mov             \h,  \my
+        add             \src,  \src,  #8
+.ifc \type, put
+        add             \dst,  \dst,  #8
+.else
+        add             \dst,  \dst,  #16
+.endif
+        b               1b
+0:
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+filter_fn put,  r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, 10
+filter_fn prep, r0, r7, r1, r2, r3, r4, r5, r6, r8, r9, 6
+
+.macro load_filter_ptr src
+        asr             r12, \src, #10
+        add             r12, r11, r12, lsl #3
+.endm
+
+.macro load_filter_coef dst, src, inc
+        add             \src, \src, \inc
+        vld1.8          {\dst}, [r12, :64]
+.endm
+
+.macro load_filter_row dst, src, inc
+        load_filter_ptr \src
+        load_filter_coef \dst, \src, \inc
+.endm
+
+function warp_filter_horz_neon
+        load_filter_ptr r5                  // filter 0
+        vld1.16         {q7}, [r2], r3
+        vmov.i8         q6,  #128
+
+        load_filter_coef d0, r5,  r7        // filter 0
+        load_filter_row d1,  r5,  r7        // filter 1
+        load_filter_row d2,  r5,  r7        // filter 2
+        load_filter_ptr r5                  // filter 3
+        veor            q7,  q7,  q6        // subtract by 128 to allow using vmull
+        load_filter_coef d3, r5,  r7        // filter 3
+        vext.8          d12, d14, d15, #1   // filter 1 pixels
+        vext.8          d13, d14, d15, #2   // filter 2 pixels
+        load_filter_ptr r5                  // filter 4
+        vmull.s8        q2,  d14, d0        // filter 0 output
+        vmull.s8        q3,  d12, d1        // filter 1 output
+        load_filter_coef d0, r5,  r7        // filter 4
+        load_filter_ptr r5                  // filter 5
+        vext.8          d12, d14, d15, #3   // filter 3 pixels
+        vmull.s8        q4,  d13, d2        // filter 2 output
+        vext.8          d13, d14, d15, #4   // filter 4 pixels
+        vpadd.i16       d4,  d4,  d5        // pixel 0 (4x16)
+        vpadd.i16       d5,  d6,  d7        // pixel 1 (4x16)
+        load_filter_coef d1, r5,  r7        // filter 5
+        load_filter_ptr r5                  // filter 6
+        vmull.s8        q5,  d12, d3        // filter 3 output
+        vext.8          d12, d14, d15, #5   // filter 5 pixels
+        vmull.s8        q3,  d13, d0        // filter 4 output
+        load_filter_coef d0, r5,  r7        // filter 6
+        vext.8          d13, d14, d15, #6   // filter 6 pixels
+        load_filter_ptr r5                  // filter 7
+        vpadd.i16       d8,  d8,  d9        // pixel 2 (4x16)
+        vpadd.i16       d9,  d10, d11       // pixel 3 (4x16)
+        vmull.s8        q5,  d12, d1        // filter 5 output
+        load_filter_coef d1, r5,  r7        // filter 7
+        vext.8          d14, d14, d15, #7   // filter 7 pixels
+        vpadd.i16       d6,  d6,  d7        // pixel 4 (4x16)
+        vpadd.i16       d10, d10, d11       // pixel 5 (4x16)
+        vmull.s8        q6,  d13, d0        // filter 6 output
+        vmull.s8        q7,  d14, d1        // filter 7 output
+
+        sub             r5,  r5,  r7, lsl #3
+
+        vpadd.i16       d4,  d4,  d5        // pixel 0,1 (2x16)
+        vpadd.i16       d5,  d8,  d9        // pixel 2,3 (2x16)
+        vpadd.i16       d12, d12, d13       // pixel 6 (4x16)
+        vpadd.i16       d14, d14, d15       // pixel 7 (4x16)
+        vpadd.i16       d6,  d6,  d10       // pixel 4,5 (2x16)
+        vpadd.i16       d10, d12, d14       // pixel 6,7 (2x16)
+        vpadd.i16       d4,  d4,  d5        // pixel 0-3
+        vpadd.i16       d5,  d6,  d10       // pixel 4-7
+
+        add             r5,  r5,  r8
+
+        bx              lr
+endfunc
+
+// void dav1d_warp_affine_8x8_8bpc_neon(
+//         pixel *dst, const ptrdiff_t dst_stride,
+//         const pixel *src, const ptrdiff_t src_stride,
+//         const int16_t *const abcd, int mx, int my)
+.macro warp t, shift
+function warp_affine_8x8\t\()_8bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]
+        ldr             r6,  [sp, #108]
+        ldrd            r8,  r9,  [r4]
+        sxth            r7,  r8
+        asr             r8,  r8, #16
+        asr             r4,  r9, #16
+        sxth            r9,  r9
+        mov             r10, #8
+        sub             r2,  r2,  r3, lsl #1
+        sub             r2,  r2,  r3
+        sub             r2,  r2,  #3
+        movrel          r11, X(mc_warp_filter), 64*8
+.ifnb \t
+        lsl             r1,  r1,  #1
+.endif
+        add             r5,  r5,  #512
+        add             r6,  r6,  #512
+
+        bl              warp_filter_horz_neon
+        vrshr.s16       q8,  q2,  #3
+        bl              warp_filter_horz_neon
+        vrshr.s16       q9,  q2,  #3
+        bl              warp_filter_horz_neon
+        vrshr.s16       q10, q2,  #3
+        bl              warp_filter_horz_neon
+        vrshr.s16       q11, q2,  #3
+        bl              warp_filter_horz_neon
+        vrshr.s16       q12, q2,  #3
+        bl              warp_filter_horz_neon
+        vrshr.s16       q13, q2,  #3
+        bl              warp_filter_horz_neon
+        vrshr.s16       q14, q2,  #3
+
+1:
+        bl              warp_filter_horz_neon
+        vrshr.s16       q15, q2,  #3
+
+        load_filter_row d8,  r6,  r9
+        load_filter_row d9,  r6,  r9
+        load_filter_row d10, r6,  r9
+        load_filter_row d11, r6,  r9
+        load_filter_row d12, r6,  r9
+        load_filter_row d13, r6,  r9
+        load_filter_row d14, r6,  r9
+        load_filter_row d15, r6,  r9
+        transpose_8x8b  q4,  q5,  q6,  q7,  d8,  d9,  d10, d11, d12, d13, d14, d15
+        vmovl.s8        q1,  d8
+        vmovl.s8        q2,  d9
+        vmovl.s8        q3,  d10
+        vmovl.s8        q4,  d11
+        vmovl.s8        q5,  d12
+        vmovl.s8        q6,  d13
+
+        sub             r6,  r6,  r9, lsl #3
+
+        // This ordering of vmull/vmlal is highly beneficial for
+        // Cortex A8/A9/A53 here, but harmful for Cortex A7.
+        vmull.s16       q0,  d16,  d2
+        vmlal.s16       q0,  d18,  d4
+        vmlal.s16       q0,  d20,  d6
+        vmlal.s16       q0,  d22,  d8
+        vmlal.s16       q0,  d24,  d10
+        vmlal.s16       q0,  d26,  d12
+        vmull.s16       q1,  d17,  d3
+        vmlal.s16       q1,  d19,  d5
+        vmlal.s16       q1,  d21,  d7
+        vmlal.s16       q1,  d23,  d9
+        vmlal.s16       q1,  d25,  d11
+        vmlal.s16       q1,  d27,  d13
+
+        vmovl.s8        q2,  d14
+        vmovl.s8        q3,  d15
+
+        vmlal.s16       q0,  d28,  d4
+        vmlal.s16       q0,  d30,  d6
+        vmlal.s16       q1,  d29,  d5
+        vmlal.s16       q1,  d31,  d7
+
+.ifb \t
+        vmov.i16        q7,  #128
+.else
+        vmov.i16        q7,  #0x800
+.endif
+
+        vmov            q8,  q9
+        vmov            q9,  q10
+        vqrshrn.s32     d0,  q0,  #\shift
+        vmov            q10, q11
+        vqrshrn.s32     d1,  q1,  #\shift
+        vmov            q11, q12
+        vadd.i16        q0,  q0,  q7
+        vmov            q12, q13
+.ifb \t
+        vqmovun.s16     d0,  q0
+.endif
+        vmov            q13, q14
+        vmov            q14, q15
+        subs            r10, r10, #1
+.ifnb \t
+        vst1.16         {q0}, [r0, :128], r1
+.else
+        vst1.8          {d0}, [r0, :64], r1
+.endif
+
+        add             r6,  r6,  r4
+        bgt             1b
+
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+warp  , 11
+warp t, 7
+
+// void dav1d_emu_edge_8bpc_neon(
+//         const intptr_t bw, const intptr_t bh,
+//         const intptr_t iw, const intptr_t ih,
+//         const intptr_t x, const intptr_t y,
+//         pixel *dst, const ptrdiff_t dst_stride,
+//         const pixel *ref, const ptrdiff_t ref_stride)
+function emu_edge_8bpc_neon, export=1
+        push            {r4-r11,lr}
+        ldrd            r4,  r5,  [sp, #36]
+        ldrd            r6,  r7,  [sp, #44]
+        ldrd            r8,  r9,  [sp, #52]
+
+        // ref += iclip(y, 0, ih - 1) * PXSTRIDE(ref_stride)
+        // ref += iclip(x, 0, iw - 1)
+        sub             r12, r3,  #1           // ih - 1
+        cmp             r5,  r3
+        sub             lr,  r2,  #1           // iw - 1
+        it              lt
+        movlt           r12, r5                // min(y, ih - 1)
+        cmp             r4,  r2
+        bic             r12, r12, r12, asr #31 // max(min(y, ih - 1), 0)
+        it              lt
+        movlt           lr,  r4                // min(x, iw - 1)
+        bic             lr,  lr,  lr,  asr #31 // max(min(x, iw - 1), 0)
+        mla             r8,  r12, r9,  r8      // ref += iclip() * stride
+        add             r8,  r8,  lr           // ref += iclip()
+
+        // bottom_ext = iclip(y + bh - ih, 0, bh - 1)
+        // top_ext = iclip(-y, 0, bh - 1)
+        add             r10, r5,  r1           // y + bh
+        neg             r5,  r5                // -y
+        sub             r10, r10, r3           // y + bh - ih
+        sub             r12, r1,  #1           // bh - 1
+        cmp             r10, r1
+        bic             r5,  r5,  r5,  asr #31 // max(-y, 0)
+        it              ge
+        movge           r10, r12               // min(y + bh - ih, bh-1)
+        cmp             r5,  r1
+        bic             r10, r10, r10, asr #31 // max(min(y + bh - ih, bh-1), 0)
+        it              ge
+        movge           r5,  r12               // min(max(-y, 0), bh-1)
+
+        // right_ext = iclip(x + bw - iw, 0, bw - 1)
+        // left_ext = iclip(-x, 0, bw - 1)
+        add             r11, r4,  r0           // x + bw
+        neg             r4,  r4                // -x
+        sub             r11, r11, r2           // x + bw - iw
+        sub             lr,  r0,  #1           // bw - 1
+        cmp             r11, r0
+        bic             r4,  r4,  r4,  asr #31 // max(-x, 0)
+        it              ge
+        movge           r11, lr                // min(x + bw - iw, bw-1)
+        cmp             r4,  r0
+        bic             r11, r11, r11, asr #31 // max(min(x + bw - iw, bw-1), 0)
+        it              ge
+        movge           r4,  lr                // min(max(-x, 0), bw - 1)
+
+        // center_h = bh - top_ext - bottom_ext
+        // dst += top_ext * PXSTRIDE(dst_stride)
+        // center_w = bw - left_ext - right_ext
+        sub             r1,  r1,  r5           // bh - top_ext
+        mla             r6,  r5,  r7,  r6
+        sub             r2,  r0,  r4           // bw - left_ext
+        sub             r1,  r1,  r10          // center_h = bh - top_ext - bottom_ext
+        sub             r2,  r2,  r11          // center_w = bw - left_ext - right_ext
+
+        mov             r0,  r6                // backup of dst
+
+.macro v_loop need_left, need_right
+0:
+.if \need_left
+        vld1.8          {d0[], d1[]}, [r8]
+        mov             r12, r6                // out = dst
+        mov             r3,  r4
+1:
+        subs            r3,  r3,  #16
+        vst1.8          {q0}, [r12, :128]!
+        bgt             1b
+.endif
+        mov             lr,  r8
+        add             r12, r6,  r4           // out = dst + left_ext
+        mov             r3,  r2
+1:
+        vld1.8          {q0, q1}, [lr]!
+        subs            r3,  r3,  #32
+.if \need_left
+        vst1.8          {q0, q1}, [r12]!
+.else
+        vst1.8          {q0, q1}, [r12, :128]!
+.endif
+        bgt             1b
+.if \need_right
+        add             r3,  r8,  r2           // in + center_w
+        sub             r3,  r3,  #1           // in + center_w - 1
+        add             r12, r6,  r4           // dst + left_ext
+        vld1.8          {d0[], d1[]}, [r3]
+        add             r12, r12, r2           // out = dst + left_ext + center_w
+        mov             r3,  r11
+1:
+        subs            r3,  r3,  #16
+        vst1.8          {q0}, [r12]!
+        bgt             1b
+.endif
+
+        subs            r1,  r1,  #1           // center_h--
+        add             r6,  r6,  r7
+        add             r8,  r8,  r9
+        bgt             0b
+.endm
+
+        cmp             r4,  #0
+        beq             2f
+        // need_left
+        cmp             r11, #0
+        beq             3f
+        // need_left + need_right
+        v_loop          1,   1
+        b               5f
+
+2:
+        // !need_left
+        cmp             r11, #0
+        beq             4f
+        // !need_left + need_right
+        v_loop          0,   1
+        b               5f
+
+3:
+        // need_left + !need_right
+        v_loop          1,   0
+        b               5f
+
+4:
+        // !need_left + !need_right
+        v_loop          0,   0
+
+5:
+        cmp             r10, #0
+        // Storing the original dst in r0 overwrote bw, recalculate it here
+        add             r2,  r2,  r4           // center_w + left_ext
+        add             r2,  r2,  r11          // bw = center_w + left_ext + right_ext
+
+        beq             3f
+        // need_bottom
+        sub             r8,  r6,  r7           // ref = dst - stride
+        mov             r4,  r2
+1:
+        vld1.8          {q0, q1}, [r8, :128]!
+        mov             r3,  r10
+2:
+        subs            r3,  r3,  #1
+        vst1.8          {q0, q1}, [r6, :128], r7
+        bgt             2b
+        mls             r6,  r7,  r10,  r6     // dst -= bottom_ext * stride
+        subs            r4,  r4,  #32          // bw -= 32
+        add             r6,  r6,  #32          // dst += 32
+        bgt             1b
+
+3:
+        cmp             r5,  #0
+        beq             3f
+        // need_top
+        mls             r6,  r7,  r5,  r0      // dst = stored_dst - top_ext * stride
+1:
+        vld1.8          {q0, q1}, [r0, :128]!
+        mov             r3,  r5
+2:
+        subs            r3,  r3,  #1
+        vst1.8          {q0, q1}, [r6, :128], r7
+        bgt             2b
+        mls             r6,  r7,  r5,  r6      // dst -= top_ext * stride
+        subs            r2,  r2,  #32          // bw -= 32
+        add             r6,  r6,  #32          // dst += 32
+        bgt             1b
+
+3:
+        pop             {r4-r11,pc}
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/mc16.S b/media/libdav1d/src/src/arm/32/mc16.S
new file mode 100644
index 0000000000..b7d845e219
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/mc16.S
@@ -0,0 +1,3658 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+#define PREP_BIAS 8192
+
+.macro avg d0, d00, d01, d1, d10, d11
+        vld1.16         {q0, q1}, [r2, :128]!
+        vld1.16         {q2, q3}, [r3, :128]!
+        vqadd.s16       q0,  q0,  q2
+        vqadd.s16       q1,  q1,  q3
+        vmax.s16        q0,  q0,  q12 // -2*PREP_BIAS - 1 << intermediate_bits
+        vmax.s16        q1,  q1,  q12 // -2*PREP_BIAS - 1 << intermediate_bits
+        vqsub.s16       q0,  q0,  q12 // -2*PREP_BIAS - 1 << intermediate_bits
+        vqsub.s16       q1,  q1,  q12 // -2*PREP_BIAS - 1 << intermediate_bits
+        vshl.s16        \d0, q0,  q13 // -(intermediate_bits+1)
+        vshl.s16        \d1, q1,  q13 // -(intermediate_bits+1)
+.endm
+
+.macro w_avg d0, d00, d01, d1, d10, d11
+        vld1.16         {q0, q1}, [r2, :128]!
+        vld1.16         {q2, q3}, [r3, :128]!
+        // This difference requires a 17 bit range, and all bits are
+        // significant for the following multiplication.
+        vsubl.s16       \d0, d4,  d0
+        vsubl.s16       q0,  d5,  d1
+        vsubl.s16       \d1, d6,  d2
+        vsubl.s16       q1,  d7,  d3
+        vmul.s32        \d0, \d0, q4
+        vmul.s32        q0,  q0,  q4
+        vmul.s32        \d1, \d1, q4
+        vmul.s32        q1,  q1,  q4
+        vshr.s32        \d0, \d0, #4
+        vshr.s32        q0,  q0,  #4
+        vshr.s32        \d1, \d1, #4
+        vshr.s32        q1,  q1,  #4
+        vaddw.s16       \d0, \d0, d4
+        vaddw.s16       q0,  q0,  d5
+        vaddw.s16       \d1, \d1, d6
+        vaddw.s16       q1,  q1,  d7
+        vmovn.i32       \d00, \d0
+        vmovn.i32       \d01, q0
+        vmovn.i32       \d10, \d1
+        vmovn.i32       \d11, q1
+        vrshl.s16       \d0, \d0, q13 // -intermediate_bits
+        vrshl.s16       \d1, \d1, q13 // -intermediate_bits
+        vadd.s16        \d0, \d0, q12 // PREP_BIAS >> intermediate_bits
+        vadd.s16        \d1, \d1, q12 // PREP_BIAS >> intermediate_bits
+        vmin.s16        \d0, \d0, q15 // bitdepth_max
+        vmin.s16        \d1, \d1, q15 // bitdepth_max
+        vmax.s16        \d0, \d0, q14 // 0
+        vmax.s16        \d1, \d1, q14 // 0
+.endm
+
+.macro mask d0, d00, d01, d1, d10, d11
+        vld1.8          {q7},     [r6, :128]!
+        vld1.16         {q0, q1}, [r2, :128]!
+        vneg.s8         q7,  q7
+        vld1.16         {q2, q3}, [r3, :128]!
+        vmovl.s8        q6,  d14
+        vmovl.s8        q7,  d15
+        vmovl.s16       q4,  d12
+        vmovl.s16       q5,  d13
+        vmovl.s16       q6,  d14
+        vmovl.s16       q7,  d15
+        vsubl.s16       \d0, d4,  d0
+        vsubl.s16       q0,  d5,  d1
+        vsubl.s16       \d1, d6,  d2
+        vsubl.s16       q1,  d7,  d3
+        vmul.s32        \d0, \d0, q4
+        vmul.s32        q0,  q0,  q5
+        vmul.s32        \d1, \d1, q6
+        vmul.s32        q1,  q1,  q7
+        vshr.s32        \d0, \d0, #6
+        vshr.s32        q0,  q0,  #6
+        vshr.s32        \d1, \d1, #6
+        vshr.s32        q1,  q1,  #6
+        vaddw.s16       \d0, \d0, d4
+        vaddw.s16       q0,  q0,  d5
+        vaddw.s16       \d1, \d1, d6
+        vaddw.s16       q1,  q1,  d7
+        vmovn.i32       \d00, \d0
+        vmovn.i32       \d01, q0
+        vmovn.i32       \d10, \d1
+        vmovn.i32       \d11, q1
+        vrshl.s16       \d0, \d0, q13 // -intermediate_bits
+        vrshl.s16       \d1, \d1, q13 // -intermediate_bits
+        vadd.s16        \d0, \d0, q12 // PREP_BIAS >> intermediate_bits
+        vadd.s16        \d1, \d1, q12 // PREP_BIAS >> intermediate_bits
+        vmin.s16        \d0, \d0, q15 // bitdepth_max
+        vmin.s16        \d1, \d1, q15 // bitdepth_max
+        vmax.s16        \d0, \d0, q14 // 0
+        vmax.s16        \d1, \d1, q14 // 0
+.endm
+
+.macro bidir_fn type, bdmax
+function \type\()_16bpc_neon, export=1
+        push            {r4-r7,lr}
+        ldrd            r4,  r5,  [sp, #20]
+        ldr             r6,  [sp, #28]
+        clz             r4,  r4
+.ifnc \type, avg
+        ldr             r7,  [sp, #32]
+        vmov.i16        q14, #0
+        vdup.16         q15, r7         // bitdepth_max
+.endif
+.ifc \type, w_avg
+        vpush           {q4}
+.endif
+.ifc \type, mask
+        vpush           {q4-q7}
+.endif
+        clz             r7,  \bdmax
+        sub             r7,  r7,  #18   // intermediate_bits = clz(bitdepth_max) - 18
+.ifc \type, avg
+        mov             lr,  #1
+        movw            r12, #2*PREP_BIAS
+        lsl             lr,  lr,  r7    // 1 << intermediate_bits
+        neg             r12, r12         // -2*PREP_BIAS
+        add             r7,  r7,  #1
+        sub             r12, r12, lr    // -2*PREP_BIAS - 1 << intermediate_bits
+        neg             r7,  r7         // -(intermediate_bits+1)
+        vdup.16         q12, r12         // -2*PREP_BIAS - 1 << intermediate_bits
+        vdup.16         q13, r7         // -(intermediate_bits+1)
+.else
+        mov             r12, #PREP_BIAS
+        lsr             r12, r12, r7    // PREP_BIAS >> intermediate_bits
+        neg             r7,  r7         // -intermediate_bits
+        vdup.16         q12, r12         // PREP_BIAS >> intermediate_bits
+        vdup.16         q13, r7         // -intermediate_bits
+.endif
+.ifc \type, w_avg
+        vdup.32         q4,  r6
+        vneg.s32        q4,  q4
+.endif
+        adr             r7,  L(\type\()_tbl)
+        sub             r4,  r4,  #24
+        \type           q8,  d16, d17, q9,  d18, d19
+        ldr             r4,  [r7, r4, lsl #2]
+        add             r7,  r7,  r4
+        bx              r7
+
+        .align 2
+L(\type\()_tbl):
+        .word 1280f - L(\type\()_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_tbl) + CONFIG_THUMB
+
+40:
+        add             r7,  r0,  r1
+        lsl             r1,  r1,  #1
+4:
+        subs            r5,  r5,  #4
+        vst1.16         {d16},  [r0, :64], r1
+        vst1.16         {d17},  [r7, :64], r1
+        vst1.16         {d18},  [r0, :64], r1
+        vst1.16         {d19},  [r7, :64], r1
+        ble             0f
+        \type           q8,  d16, d17, q9,  d18, d19
+        b               4b
+80:
+        add             r7,  r0,  r1
+        lsl             r1,  r1,  #1
+8:
+        vst1.16         {q8},  [r0, :128], r1
+        subs            r5,  r5,  #2
+        vst1.16         {q9},  [r7, :128], r1
+        ble             0f
+        \type           q8,  d16, d17, q9,  d18, d19
+        b               8b
+160:
+16:
+        \type           q10, d20, d21, q11, d22, d23
+        vst1.16         {q8,  q9},  [r0, :128], r1
+        subs            r5,  r5,  #2
+        vst1.16         {q10, q11}, [r0, :128], r1
+        ble             0f
+        \type           q8,  d16, d17, q9,  d18, d19
+        b               16b
+320:
+        add             r7,  r0,  #32
+32:
+        \type           q10, d20, d21, q11, d22, d23
+        vst1.16         {q8,  q9},  [r0, :128], r1
+        subs            r5,  r5,  #1
+        vst1.16         {q10, q11}, [r7, :128], r1
+        ble             0f
+        \type           q8,  d16, d17, q9,  d18, d19
+        b               32b
+640:
+        add             r7,  r0,  #32
+        mov             r12, #64
+        sub             r1,  r1,  #64
+64:
+        \type           q10, d20, d21, q11, d22, d23
+        vst1.16         {q8,  q9},  [r0, :128], r12
+        \type           q8,  d16, d17, q9,  d18, d19
+        vst1.16         {q10, q11}, [r7, :128], r12
+        \type           q10, d20, d21, q11, d22, d23
+        vst1.16         {q8,  q9},  [r0, :128], r1
+        subs            r5,  r5,  #1
+        vst1.16         {q10, q11}, [r7, :128], r1
+        ble             0f
+        \type           q8,  d16, d17, q9,  d18, d19
+        b               64b
+1280:
+        add             r7,  r0,  #32
+        mov             r12, #64
+        sub             r1,  r1,  #192
+128:
+        \type           q10, d20, d21, q11, d22, d23
+        vst1.16         {q8,  q9},  [r0, :128], r12
+        \type           q8,  d16, d17, q9,  d18, d19
+        vst1.16         {q10, q11}, [r7, :128], r12
+        \type           q10, d20, d21, q11, d22, d23
+        vst1.16         {q8,  q9},  [r0, :128], r12
+        \type           q8,  d16, d17, q9,  d18, d19
+        vst1.16         {q10, q11}, [r7, :128], r12
+        \type           q10, d20, d21, q11, d22, d23
+        vst1.16         {q8,  q9},  [r0, :128], r12
+        \type           q8,  d16, d17, q9,  d18, d19
+        vst1.16         {q10, q11}, [r7, :128], r12
+        \type           q10, d20, d21, q11, d22, d23
+        vst1.16         {q8,  q9},  [r0, :128], r1
+        subs            r5,  r5,  #1
+        vst1.16         {q10, q11}, [r7, :128], r1
+        ble             0f
+        \type           q8,  d16, d17, q9,  d18, d19
+        b               128b
+0:
+.ifc \type, mask
+        vpop            {q4-q7}
+.endif
+.ifc \type, w_avg
+        vpop            {q4}
+.endif
+        pop             {r4-r7,pc}
+endfunc
+.endm
+
+bidir_fn avg, r6
+bidir_fn w_avg, r7
+bidir_fn mask, r7
+
+
+.macro w_mask_fn type
+function w_mask_\type\()_16bpc_neon, export=1
+        push            {r4-r10,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #96]
+        ldrd            r6,  r7,  [sp, #104]
+        ldr             r8,  [sp, #112]
+        clz             r9,  r4
+        adr             lr,  L(w_mask_\type\()_tbl)
+        vdup.16         q15, r8       // bitdepth_max
+        sub             r9,  r9,  #24
+        clz             r8,  r8       // clz(bitdepth_max)
+        ldr             r9,  [lr,  r9,  lsl #2]
+        add             r9,  lr,  r9
+        sub             r8,  r8,  #12 // sh = intermediate_bits + 6 = clz(bitdepth_max) - 12
+        mov             r10, #PREP_BIAS*64
+        neg             r8,  r8       // -sh
+        movw            r12, #27615   // (64 + 1 - 38)<> mask_sh
+        vshr.u16        q7,  q7,  #10
+        vadd.i32        q2,  q2,  q13  // += PREP_BIAS*64
+        vadd.i32        q3,  q3,  q13
+        vadd.i32        q4,  q4,  q13
+        vadd.i32        q5,  q5,  q13
+        vmovl.u16       q12, d12
+        vmovl.u16       q13, d13
+        vmla.i32        q2,  q8,  q12  // (tmp2-tmp1)*(64-m)
+        vmovl.u16       q12, d14
+        vmla.i32        q3,  q9,  q13
+        vmovl.u16       q13, d15
+        vmla.i32        q4,  q10, q12
+        vmla.i32        q5,  q11, q13
+        vrshl.s32       q2,  q2,  q14  // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
+        vrshl.s32       q3,  q3,  q14
+        vrshl.s32       q4,  q4,  q14
+        vrshl.s32       q5,  q5,  q14
+        vqmovun.s32     d4,  q2        // iclip_pixel
+        vqmovun.s32     d5,  q3
+        vqmovun.s32     d6,  q4
+        vqmovun.s32     d7,  q5
+        vmin.u16        q2,  q2,  q15  // iclip_pixel
+        vmin.u16        q3,  q3,  q15  // iclip_pixel
+.if \type == 444
+        vmovn.i16       d12, q6        // 64 - m
+        vmovn.i16       d13, q7
+        vsub.i16        q6,  q1,  q6   // m
+        vst1.8          {q6}, [r6, :128]!
+.elseif \type == 422
+        vpadd.i16       d12, d12, d13  // (64 - m) + (64 - n) (column wise addition)
+        vpadd.i16       d13, d14, d15
+        vmovn.i16       d12, q6
+        vhsub.u8        d12, d2,  d12  // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
+        vst1.8          {d12}, [r6, :64]!
+.elseif \type == 420
+        vadd.i16        d12, d12, d13  // (64 - my1) + (64 - my2) (row wise addition)
+        vadd.i16        d13, d14, d15
+        vpadd.i16       d12, d12, d13  // (128 - m) + (128 - n) (column wise addition)
+        vsub.i16        d12, d2,  d12  // (256 - sign) - ((128 - m) + (128 - n))
+        vrshrn.i16      d12, q6,  #2   // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        vst1.32         {d12[0]}, [r6, :32]!
+.endif
+        vst1.16         {d4}, [r0,  :64], r1
+        vst1.16         {d5}, [r12, :64], r1
+        vst1.16         {d6}, [r0,  :64], r1
+        vst1.16         {d7}, [r12, :64], r1
+        bgt             4b
+        vpop            {q4-q7}
+        pop             {r4-r10,pc}
+8:
+        vld1.16         {q2, q3}, [r2, :128]! // tmp1
+        vld1.16         {q4, q5}, [r3, :128]! // tmp2
+        subs            r5,  r5,  #2
+        vdup.32         q13, r10       // PREP_BIAS*64
+        vabd.s16        q6,  q2,  q4   // abs(tmp1 - tmp2)
+        vabd.s16        q7,  q3,  q5
+        vsubl.s16       q8,  d8,  d4   // tmp2 - tmp1 (requires 17 bit)
+        vsubl.s16       q9,  d9,  d5
+        vsubl.s16       q10, d10, d6
+        vsubl.s16       q11, d11, d7
+        vqsub.u16       q6,  q0,  q6   // 27615 - abs()
+        vqsub.u16       q7,  q0,  q7
+        vshll.s16       q5,  d7,  #6   // tmp1 << 6
+        vshll.s16       q4,  d6,  #6
+        vshll.s16       q3,  d5,  #6
+        vshll.s16       q2,  d4,  #6
+        vshr.u16        q6,  q6,  #10  // 64-m = (27615 - abs()) >> mask_sh
+        vshr.u16        q7,  q7,  #10
+        vadd.i32        q2,  q2,  q13  // += PREP_BIAS*64
+        vadd.i32        q3,  q3,  q13
+        vadd.i32        q4,  q4,  q13
+        vadd.i32        q5,  q5,  q13
+        vmovl.u16       q12, d12
+        vmovl.u16       q13, d13
+        vmla.i32        q2,  q8,  q12  // (tmp2-tmp1)*(64-m)
+        vmovl.u16       q12, d14
+        vmla.i32        q3,  q9,  q13
+        vmovl.u16       q13, d15
+        vmla.i32        q4,  q10, q12
+        vmla.i32        q5,  q11, q13
+        vrshl.s32       q2,  q2,  q14  // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
+        vrshl.s32       q3,  q3,  q14
+        vrshl.s32       q4,  q4,  q14
+        vrshl.s32       q5,  q5,  q14
+        vqmovun.s32     d4,  q2        // iclip_pixel
+        vqmovun.s32     d5,  q3
+        vqmovun.s32     d6,  q4
+        vqmovun.s32     d7,  q5
+        vmin.u16        q2,  q2,  q15  // iclip_pixel
+        vmin.u16        q3,  q3,  q15  // iclip_pixel
+.if \type == 444
+        vmovn.i16       d12, q6        // 64 - m
+        vmovn.i16       d13, q7
+        vsub.i16        q6,  q1,  q6   // m
+        vst1.8          {q6}, [r6, :128]!
+.elseif \type == 422
+        vpadd.i16       d12, d12, d13  // (64 - m) + (64 - n) (column wise addition)
+        vpadd.i16       d13, d14, d15
+        vmovn.i16       d12, q6
+        vhsub.u8        d12, d2,  d12  // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
+        vst1.8          {d12}, [r6, :64]!
+.elseif \type == 420
+        vadd.i16        q6,  q6,  q7   // (64 - my1) + (64 - my2) (row wise addition)
+        vpadd.i16       d12, d12, d13  // (128 - m) + (128 - n) (column wise addition)
+        vsub.i16        d12, d2,  d12  // (256 - sign) - ((128 - m) + (128 - n))
+        vrshrn.i16      d12, q6,  #2   // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        vst1.32         {d12[0]}, [r6, :32]!
+.endif
+        vst1.16         {q2}, [r0,  :128], r1
+        vst1.16         {q3}, [r12, :128], r1
+        bgt             8b
+        vpop            {q4-q7}
+        pop             {r4-r10,pc}
+1280:
+640:
+320:
+160:
+        sub             r1,  r1,  r4,  lsl #1
+.if \type == 444
+        add             lr,  r6,  r4
+.elseif \type == 422
+        add             lr,  r6,  r4,  lsr #1
+.endif
+        add             r7,  r2,  r4,  lsl #1
+        add             r9,  r3,  r4,  lsl #1
+161:
+        mov             r8,  r4
+16:
+        vld1.16         {q2}, [r2, :128]! // tmp1
+        vld1.16         {q4}, [r3, :128]! // tmp2
+        vld1.16         {q3}, [r7, :128]!
+        vld1.16         {q5}, [r9, :128]!
+        subs            r8,  r8,  #8
+        vdup.32         q13, r10       // PREP_BIAS*64
+        vabd.s16        q6,  q2,  q4   // abs(tmp1 - tmp2)
+        vabd.s16        q7,  q3,  q5
+        vsubl.s16       q8,  d8,  d4   // tmp2 - tmp1 (requires 17 bit)
+        vsubl.s16       q9,  d9,  d5
+        vsubl.s16       q10, d10, d6
+        vsubl.s16       q11, d11, d7
+        vqsub.u16       q6,  q0,  q6   // 27615 - abs()
+        vqsub.u16       q7,  q0,  q7
+        vshll.s16       q5,  d7,  #6   // tmp1 << 6
+        vshll.s16       q4,  d6,  #6
+        vshll.s16       q3,  d5,  #6
+        vshll.s16       q2,  d4,  #6
+        vshr.u16        q6,  q6,  #10  // 64-m = (27615 - abs()) >> mask_sh
+        vshr.u16        q7,  q7,  #10
+        vadd.i32        q2,  q2,  q13  // += PREP_BIAS*64
+        vadd.i32        q3,  q3,  q13
+        vadd.i32        q4,  q4,  q13
+        vadd.i32        q5,  q5,  q13
+        vmovl.u16       q12, d12
+        vmovl.u16       q13, d13
+        vmla.i32        q2,  q8,  q12  // (tmp2-tmp1)*(64-m)
+        vmovl.u16       q12, d14
+        vmla.i32        q3,  q9,  q13
+        vmovl.u16       q13, d15
+        vmla.i32        q4,  q10, q12
+        vmla.i32        q5,  q11, q13
+        vrshl.s32       q2,  q2,  q14  // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
+        vrshl.s32       q3,  q3,  q14
+        vrshl.s32       q4,  q4,  q14
+        vrshl.s32       q5,  q5,  q14
+        vqmovun.s32     d4,  q2        // iclip_pixel
+        vqmovun.s32     d5,  q3
+        vqmovun.s32     d6,  q4
+        vqmovun.s32     d7,  q5
+        vmin.u16        q2,  q2,  q15  // iclip_pixel
+        vmin.u16        q3,  q3,  q15  // iclip_pixel
+.if \type == 444
+        vmovn.i16       d12, q6        // 64 - m
+        vmovn.i16       d13, q7
+        vsub.i16        q6,  q1,  q6   // m
+        vst1.8          {d12}, [r6, :64]!
+        vst1.8          {d13}, [lr, :64]!
+.elseif \type == 422
+        vpadd.i16       d12, d12, d13  // (64 - m) + (64 - n) (column wise addition)
+        vpadd.i16       d13, d14, d15
+        vmovn.i16       d12, q6
+        vhsub.u8        d12, d2,  d12  // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
+        vst1.32         {d12[0]}, [r6, :32]!
+        vst1.32         {d12[1]}, [lr, :32]!
+.elseif \type == 420
+        vadd.i16        q6,  q6,  q7   // (64 - my1) + (64 - my2) (row wise addition)
+        vpadd.i16       d12, d12, d13  // (128 - m) + (128 - n) (column wise addition)
+        vsub.i16        d12, d2,  d12  // (256 - sign) - ((128 - m) + (128 - n))
+        vrshrn.i16      d12, q6,  #2   // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        vst1.32         {d12[0]}, [r6, :32]!
+.endif
+        vst1.16         {q2}, [r0,  :128]!
+        vst1.16         {q3}, [r12, :128]!
+        bgt             16b
+        subs            r5,  r5,  #2
+        add             r2,  r2,  r4,  lsl #1
+        add             r3,  r3,  r4,  lsl #1
+        add             r7,  r7,  r4,  lsl #1
+        add             r9,  r9,  r4,  lsl #1
+.if \type == 444
+        add             r6,  r6,  r4
+        add             lr,  lr,  r4
+.elseif \type == 422
+        add             r6,  r6,  r4,  lsr #1
+        add             lr,  lr,  r4,  lsr #1
+.endif
+        add             r0,  r0,  r1
+        add             r12, r12, r1
+        bgt             161b
+        vpop            {q4-q7}
+        pop             {r4-r10,pc}
+endfunc
+.endm
+
+w_mask_fn 444
+w_mask_fn 422
+w_mask_fn 420
+
+function blend_16bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldrd            r4,  r5,  [sp, #12]
+        clz             lr,  r3
+        adr             r3,  L(blend_tbl)
+        sub             lr,  lr,  #26
+        ldr             lr,  [r3,  lr,  lsl #2]
+        add             r3,  r3,  lr
+        bx              r3
+
+        .align 2
+L(blend_tbl):
+        .word 320f - L(blend_tbl) + CONFIG_THUMB
+        .word 160f - L(blend_tbl) + CONFIG_THUMB
+        .word 80f  - L(blend_tbl) + CONFIG_THUMB
+        .word 40f  - L(blend_tbl) + CONFIG_THUMB
+
+40:
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+4:
+        vld1.8          {d4}, [r5, :64]!
+        vld1.16         {q1}, [r2, :128]!
+        vld1.16         {d0}, [r0, :64]
+        vneg.s8         d4,  d4       // -m
+        subs            r4,  r4,  #2
+        vld1.16         {d1}, [r12, :64]
+        vmovl.s8        q2,  d4
+        vshl.i16        q2,  q2,  #9  // -m << 9
+        vsub.i16        q1,  q0,  q1  // a - b
+        vqrdmulh.s16    q1,  q1,  q2  // ((a-b)*-m + 32) >> 6
+        vadd.i16        q0,  q0,  q1
+        vst1.16         {d0}, [r0,  :64], r1
+        vst1.16         {d1}, [r12, :64], r1
+        bgt             4b
+        pop             {r4-r5,pc}
+80:
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+8:
+        vld1.8          {q8},     [r5, :128]!
+        vld1.16         {q2, q3}, [r2, :128]!
+        vneg.s8         q9,  q8       // -m
+        vld1.16         {q0},     [r0,  :128]
+        vld1.16         {q1},     [r12, :128]
+        vmovl.s8        q8,  d18
+        vmovl.s8        q9,  d19
+        vshl.i16        q8,  q8,  #9  // -m << 9
+        vshl.i16        q9,  q9,  #9
+        vsub.i16        q2,  q0,  q2  // a - b
+        vsub.i16        q3,  q1,  q3
+        subs            r4,  r4,  #2
+        vqrdmulh.s16    q2,  q2,  q8  // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    q3,  q3,  q9
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        q1,  q1,  q3
+        vst1.16         {q0}, [r0,  :128], r1
+        vst1.16         {q1}, [r12, :128], r1
+        bgt             8b
+        pop             {r4-r5,pc}
+160:
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+16:
+        vld1.8          {q12, q13}, [r5, :128]!
+        vld1.16         {q8,  q9},  [r2, :128]!
+        subs            r4,  r4,  #2
+        vneg.s8         q14, q12      // -m
+        vld1.16         {q0,  q1},  [r0, :128]
+        vneg.s8         q15, q13
+        vld1.16         {q10, q11}, [r2, :128]!
+        vmovl.s8        q12, d28
+        vmovl.s8        q13, d29
+        vmovl.s8        q14, d30
+        vmovl.s8        q15, d31
+        vld1.16         {q2,  q3},  [r12, :128]
+        vshl.i16        q12, q12, #9  // -m << 9
+        vshl.i16        q13, q13, #9
+        vshl.i16        q14, q14, #9
+        vshl.i16        q15, q15, #9
+        vsub.i16        q8,  q0,  q8  // a - b
+        vsub.i16        q9,  q1,  q9
+        vsub.i16        q10, q2,  q10
+        vsub.i16        q11, q3,  q11
+        vqrdmulh.s16    q8,  q8,  q12 // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    q9,  q9,  q13
+        vqrdmulh.s16    q10, q10, q14
+        vqrdmulh.s16    q11, q11, q15
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        q1,  q1,  q9
+        vadd.i16        q2,  q2,  q10
+        vst1.16         {q0, q1}, [r0,  :128], r1
+        vadd.i16        q3,  q3,  q11
+        vst1.16         {q2, q3}, [r12, :128], r1
+        bgt             16b
+        pop             {r4-r5,pc}
+320:
+        add             r12, r0,  #32
+32:
+        vld1.8          {q12, q13}, [r5, :128]!
+        vld1.16         {q8,  q9},  [r2, :128]!
+        subs            r4,  r4,  #1
+        vneg.s8         q14, q12      // -m
+        vld1.16         {q0,  q1},  [r0, :128]
+        vneg.s8         q15, q13
+        vld1.16         {q10, q11}, [r2, :128]!
+        vmovl.s8        q12, d28
+        vmovl.s8        q13, d29
+        vmovl.s8        q14, d30
+        vmovl.s8        q15, d31
+        vld1.16         {q2,  q3},  [r12, :128]
+        vshl.i16        q12, q12, #9  // -m << 9
+        vshl.i16        q13, q13, #9
+        vshl.i16        q14, q14, #9
+        vshl.i16        q15, q15, #9
+        vsub.i16        q8,  q0,  q8  // a - b
+        vsub.i16        q9,  q1,  q9
+        vsub.i16        q10, q2,  q10
+        vsub.i16        q11, q3,  q11
+        vqrdmulh.s16    q8,  q8,  q12 // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    q9,  q9,  q13
+        vqrdmulh.s16    q10, q10, q14
+        vqrdmulh.s16    q11, q11, q15
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        q1,  q1,  q9
+        vadd.i16        q2,  q2,  q10
+        vst1.16         {q0, q1}, [r0,  :128], r1
+        vadd.i16        q3,  q3,  q11
+        vst1.16         {q2, q3}, [r12, :128], r1
+        bgt             32b
+        pop             {r4-r5,pc}
+endfunc
+
+function blend_h_16bpc_neon, export=1
+        push            {r4-r5,lr}
+        ldr             r4,  [sp, #12]
+        movrel          r5,  X(obmc_masks)
+        add             r5,  r5,  r4
+        sub             r4,  r4,  r4,  lsr #2
+        clz             lr,  r3
+        adr             r12, L(blend_h_tbl)
+        sub             lr,  lr,  #24
+        ldr             lr,  [r12, lr,  lsl #2]
+        add             r12, r12, lr
+        bx              r12
+
+        .align 2
+L(blend_h_tbl):
+        .word 1280f - L(blend_h_tbl) + CONFIG_THUMB
+        .word 640f  - L(blend_h_tbl) + CONFIG_THUMB
+        .word 320f  - L(blend_h_tbl) + CONFIG_THUMB
+        .word 160f  - L(blend_h_tbl) + CONFIG_THUMB
+        .word 80f   - L(blend_h_tbl) + CONFIG_THUMB
+        .word 40f   - L(blend_h_tbl) + CONFIG_THUMB
+        .word 20f   - L(blend_h_tbl) + CONFIG_THUMB
+
+20:
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+2:
+        vld2.8          {d4[], d5[]}, [r5, :16]!
+        vld1.16         {d2},         [r2, :64]!
+        vext.8          d4,  d4,  d5,  #6
+        subs            r4,  r4,  #2
+        vneg.s8         d4,  d4       // -m
+        vld1.32         {d0[]},  [r0, :32]
+        vld1.32         {d0[1]}, [r12, :32]
+        vmovl.s8        q2,  d4
+        vshl.i16        d4,  d4,  #9  // -m << 9
+        vsub.i16        d2,  d0,  d2  // a - b
+        vqrdmulh.s16    d2,  d2,  d4  // ((a-b)*-m + 32) >> 6
+        vadd.i16        d0,  d0,  d2
+        vst1.32         {d0[0]}, [r0,  :32], r1
+        vst1.32         {d0[1]}, [r12, :32], r1
+        bgt             2b
+        pop             {r4-r5,pc}
+40:
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+4:
+        vld2.8          {d4[], d5[]}, [r5, :16]!
+        vld1.16         {q1},         [r2, :128]!
+        vext.8          d4,  d4,  d5,  #4
+        subs            r4,  r4,  #2
+        vneg.s8         d4,  d4       // -m
+        vld1.16         {d0}, [r0,  :64]
+        vld1.16         {d1}, [r12, :64]
+        vmovl.s8        q2,  d4
+        vshl.i16        q2,  q2,  #9  // -m << 9
+        vsub.i16        q1,  q0,  q1  // a - b
+        vqrdmulh.s16    q1,  q1,  q2  // ((a-b)*-m + 32) >> 6
+        vadd.i16        q0,  q0,  q1
+        vst1.16         {d0}, [r0,  :64], r1
+        vst1.16         {d1}, [r12, :64], r1
+        bgt             4b
+        pop             {r4-r5,pc}
+80:
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+8:
+        vld2.8          {d16[], d17[]}, [r5, :16]!
+        vld1.16         {q2, q3},       [r2, :128]!
+        vneg.s8         q9,  q8      // -m
+        vld1.16         {q0}, [r0, :128]
+        subs            r4,  r4,  #2
+        vmovl.s8        q8,  d18
+        vmovl.s8        q9,  d19
+        vld1.16         {q1}, [r12, :128]
+        vshl.i16        q8,  q8,  #9  // -m << 9
+        vshl.i16        q9,  q9,  #9
+        vsub.i16        q2,  q0,  q2  // a - b
+        vsub.i16        q3,  q1,  q3
+        vqrdmulh.s16    q2,  q2,  q8  // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    q3,  q3,  q9
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        q1,  q1,  q3
+        vst1.16         {q0}, [r0,  :128], r1
+        vst1.16         {q1}, [r12, :128], r1
+        bgt             8b
+        pop             {r4-r5,pc}
+160:
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+16:
+        vld2.8          {d24[], d25[]}, [r5, :16]!
+        vld1.16         {q8,  q9},  [r2, :128]!
+        subs            r4,  r4,  #2
+        vneg.s8         q13, q12      // -m
+        vld1.16         {q0,  q1},  [r0, :128]
+        vmovl.s8        q12, d26
+        vld1.16         {q10, q11}, [r2, :128]!
+        vmovl.s8        q13, d27
+        vld1.16         {q2,  q3},  [r12, :128]
+        vshl.i16        q12, q12, #9  // -m << 9
+        vshl.i16        q13, q13, #9
+        vsub.i16        q8,  q0,  q8  // a - b
+        vsub.i16        q9,  q1,  q9
+        vsub.i16        q10, q2,  q10
+        vsub.i16        q11, q3,  q11
+        vqrdmulh.s16    q8,  q8,  q12 // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    q9,  q9,  q12
+        vqrdmulh.s16    q10, q10, q13
+        vqrdmulh.s16    q11, q11, q13
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        q1,  q1,  q9
+        vadd.i16        q2,  q2,  q10
+        vadd.i16        q3,  q3,  q11
+        vst1.16         {q0, q1}, [r0,  :128], r1
+        vst1.16         {q2, q3}, [r12, :128], r1
+        bgt             16b
+        pop             {r4-r5,pc}
+1280:
+640:
+320:
+        sub             r1,  r1,  r3,  lsl #1
+321:
+        vld1.8          {d24[]}, [r5]!
+        mov             r12, r3
+        vneg.s8         d24, d24      // -m
+        vmovl.s8        q12, d24
+        vshl.i16        q12, q12, #9  // -m << 9
+32:
+        vld1.16         {q8,  q9},  [r2, :128]!
+        vld1.16         {q0,  q1},  [r0, :128]!
+        subs            r12, r12, #32
+        vld1.16         {q10, q11}, [r2, :128]!
+        vld1.16         {q2,  q3},  [r0, :128]
+        vsub.i16        q8,  q0,  q8  // a - b
+        vsub.i16        q9,  q1,  q9
+        vsub.i16        q10, q2,  q10
+        vsub.i16        q11, q3,  q11
+        sub             r0,  r0,  #32
+        vqrdmulh.s16    q8,  q8,  q12 // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    q9,  q9,  q12
+        vqrdmulh.s16    q10, q10, q12
+        vqrdmulh.s16    q11, q11, q12
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        q1,  q1,  q9
+        vadd.i16        q2,  q2,  q10
+        vst1.16         {q0, q1}, [r0, :128]!
+        vadd.i16        q3,  q3,  q11
+        vst1.16         {q2, q3}, [r0, :128]!
+        bgt             32b
+        subs            r4,  r4,  #1
+        add             r0,  r0,  r1
+        bgt             321b
+        pop             {r4-r5,pc}
+endfunc
+
+function blend_v_16bpc_neon, export=1
+        push            {r4,lr}
+        ldr             r4,  [sp, #8]
+        movrel          lr,  X(obmc_masks)
+        add             lr,  lr,  r3
+        clz             r12, r3
+        adr             r3,  L(blend_v_tbl)
+        sub             r12, r12, #26
+        ldr             r12, [r3,  r12, lsl #2]
+        add             r3,  r3,  r12
+        bx              r3
+
+        .align 2
+L(blend_v_tbl):
+        .word 320f - L(blend_v_tbl) + CONFIG_THUMB
+        .word 160f - L(blend_v_tbl) + CONFIG_THUMB
+        .word 80f  - L(blend_v_tbl) + CONFIG_THUMB
+        .word 40f  - L(blend_v_tbl) + CONFIG_THUMB
+        .word 20f  - L(blend_v_tbl) + CONFIG_THUMB
+
+20:
+        add             r12, r0,  r1
+        lsl             r1,  r1,  #1
+        vld1.8          {d4[]}, [lr]
+        vneg.s8         d4,  d4       // -m
+        vmovl.s8        q2,  d4
+        vshl.i16        d4,  d4,  #9  // -m << 9
+2:
+        vld1.32         {d2[]},  [r2, :32]!
+        vld1.16         {d0[]},  [r0, :16]
+        subs            r4,  r4,  #2
+        vld1.16         {d2[1]}, [r2,  :16]
+        vld1.16         {d0[1]}, [r12, :16]
+        add             r2,  r2,  #4
+        vsub.i16        d2,  d0,  d2  // a - b
+        vqrdmulh.s16    d2,  d2,  d4  // ((a-b)*-m + 32) >> 6
+        vadd.i16        d0,  d0,  d2
+        vst1.16         {d0[0]}, [r0,  :16], r1
+        vst1.16         {d0[1]}, [r12, :16], r1
+        bgt             2b
+        pop             {r4,pc}
+40:
+        vld1.32         {d4[]}, [lr, :32]
+        add             r12, r0,  r1
+        vneg.s8         d4,  d4       // -m
+        lsl             r1,  r1,  #1
+        vmovl.s8        q2,  d4
+        sub             r1,  r1,  #4
+        vshl.i16        q2,  q2,  #9  // -m << 9
+4:
+        vld1.16         {q1}, [r2, :128]!
+        vld1.16         {d0}, [r0,  :64]
+        vld1.16         {d1}, [r12, :64]
+        subs            r4,  r4,  #2
+        vsub.i16        q1,  q0,  q1  // a - b
+        vqrdmulh.s16    q1,  q1,  q2  // ((a-b)*-m + 32) >> 6
+        vadd.i16        q0,  q0,  q1
+        vst1.32         {d0[0]}, [r0,  :32]!
+        vst1.32         {d1[0]}, [r12, :32]!
+        vst1.16         {d0[2]}, [r0,  :16], r1
+        vst1.16         {d1[2]}, [r12, :16], r1
+        bgt             4b
+        pop             {r4,pc}
+80:
+        vld1.8          {d16}, [lr, :64]
+        add             r12, r0,  r1
+        vneg.s8         d16, d16      // -m
+        lsl             r1,  r1,  #1
+        vmovl.s8        q8,  d16
+        sub             r1,  r1,  #8
+        vshl.i16        q8,  q8,  #9  // -m << 9
+8:
+        vld1.16         {q2, q3}, [r2,  :128]!
+        vld1.16         {q0},     [r0,  :128]
+        vld1.16         {q1},     [r12, :128]
+        subs            r4,  r4,  #2
+        vsub.i16        q2,  q0,  q2  // a - b
+        vsub.i16        q3,  q1,  q3
+        vqrdmulh.s16    q2,  q2,  q8  // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    q3,  q3,  q8
+        vadd.i16        q0,  q0,  q2
+        vadd.i16        q1,  q1,  q3
+        vst1.16         {d0},    [r0,  :64]!
+        vst1.16         {d2},    [r12, :64]!
+        vst1.32         {d1[0]}, [r0,  :32], r1
+        vst1.32         {d3[0]}, [r12, :32], r1
+        bgt             8b
+        pop             {r4,pc}
+160:
+        vld1.8          {q12}, [lr, :128]
+        add             r12, r0,  r1
+        vneg.s8         q13, q12      // -m
+        lsl             r1,  r1,  #1
+        vmovl.s8        q12, d26
+        vmovl.s8        q13, d27
+        vshl.i16        q12, q12, #9  // -m << 9
+        vshl.i16        d26, d26, #9
+16:
+        vld1.16         {q8,  q9},      [r2,  :128]!
+        vld1.16         {d0,  d1,  d2}, [r0,  :64]
+        subs            r4,  r4,  #2
+        vld1.16         {q10, q11},     [r2,  :128]!
+        vsub.i16        q8,  q0,  q8  // a - b
+        vld1.16         {d4,  d5,  d6}, [r12, :64]
+        vsub.i16        d18, d2,  d18
+        vsub.i16        q10, q2,  q10
+        vsub.i16        d22, d6,  d22
+        vqrdmulh.s16    q8,  q8,  q12  // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    d18, d18, d26
+        vqrdmulh.s16    q10, q10, q12
+        vqrdmulh.s16    d22, d22, d26
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        d2,  d2,  d18
+        vadd.i16        q2,  q2,  q10
+        vst1.16         {d0,  d1,  d2}, [r0,  :64], r1
+        vadd.i16        d6,  d6,  d22
+        vst1.16         {d4,  d5,  d6}, [r12, :64], r1
+        bgt             16b
+        pop             {r4,pc}
+320:
+        vld1.8          {d24, d25, d26}, [lr, :64]
+        vneg.s8         q14, q12      // -m
+        vneg.s8         d30, d26
+        vmovl.s8        q12, d28
+        vmovl.s8        q13, d29
+        vmovl.s8        q14, d30
+        sub             r1,  r1,  #32
+        vshl.i16        q12, q12, #9  // -m << 9
+        vshl.i16        q13, q13, #9
+        vshl.i16        q14, q14, #9
+32:
+        vld1.16         {q8,  q9},  [r2, :128]!
+        vld1.16         {q0,  q1},  [r0, :128]!
+        subs            r4,  r4,  #1
+        vld1.16         {q10},      [r2, :128]
+        vsub.i16        q8,  q0,  q8  // a - b
+        vld1.16         {q2},       [r0, :128]
+        sub             r0,  r0,  #32
+        vsub.i16        q9,  q1,  q9
+        vsub.i16        q10, q2,  q10
+        vqrdmulh.s16    q8,  q8,  q12  // ((a-b)*-m + 32) >> 6
+        vqrdmulh.s16    q9,  q9,  q13
+        vqrdmulh.s16    q10, q10, q14
+        vadd.i16        q0,  q0,  q8
+        vadd.i16        q1,  q1,  q9
+        vadd.i16        q2,  q2,  q10
+        vst1.16         {q0, q1}, [r0, :128]!
+        add             r2,  r2,  #32
+        vst1.16         {q2},     [r0, :128], r1
+        bgt             32b
+        pop             {r4,pc}
+endfunc
+
+// This has got the same signature as the put_8tap functions,
+// and assumes that r9 is set to (clz(w)-24).
+function put_neon
+        adr             r10, L(put_tbl)
+        ldr             r9,  [r10, r9, lsl #2]
+        add             r10, r10, r9
+        bx              r10
+
+        .align 2
+L(put_tbl):
+        .word 1280f - L(put_tbl) + CONFIG_THUMB
+        .word 640f  - L(put_tbl) + CONFIG_THUMB
+        .word 320f  - L(put_tbl) + CONFIG_THUMB
+        .word 16f   - L(put_tbl) + CONFIG_THUMB
+        .word 80f   - L(put_tbl) + CONFIG_THUMB
+        .word 4f    - L(put_tbl) + CONFIG_THUMB
+        .word 2f    - L(put_tbl) + CONFIG_THUMB
+
+2:
+        vld1.32         {d0[]}, [r2], r3
+        vld1.32         {d1[]}, [r2], r3
+        subs            r5,  r5,  #2
+        vst1.32         {d0[0]}, [r0, :32], r1
+        vst1.32         {d1[1]}, [r0, :32], r1
+        bgt             2b
+        pop             {r4-r11,pc}
+4:
+        vld1.16         {d0}, [r2], r3
+        vld1.16         {d1}, [r2], r3
+        subs            r5,  r5,  #2
+        vst1.16         {d0}, [r0, :64], r1
+        vst1.16         {d1}, [r0, :64], r1
+        bgt             4b
+        pop             {r4-r11,pc}
+80:
+        add             r8,  r0,  r1
+        lsl             r1,  r1,  #1
+        add             r9,  r2,  r3
+        lsl             r3,  r3,  #1
+8:
+        vld1.16         {q0}, [r2], r3
+        vld1.16         {q1}, [r9], r3
+        subs            r5,  r5,  #2
+        vst1.16         {q0}, [r0, :128], r1
+        vst1.16         {q1}, [r8, :128], r1
+        bgt             8b
+        pop             {r4-r11,pc}
+16:
+        vld1.16         {q0,  q1},  [r2], r3
+        subs            r5,  r5,  #1
+        vst1.16         {q0,  q1},  [r0, :128], r1
+        bgt             16b
+        pop             {r4-r11,pc}
+320:
+        sub             r1,  r1,  #32
+        sub             r3,  r3,  #32
+32:
+        vld1.16         {q0,  q1},  [r2]!
+        vst1.16         {q0,  q1},  [r0, :128]!
+        vld1.16         {q2,  q3},  [r2], r3
+        subs            r5,  r5,  #1
+        vst1.16         {q2,  q3},  [r0, :128], r1
+        bgt             32b
+        pop             {r4-r11,pc}
+640:
+        sub             r1,  r1,  #96
+        sub             r3,  r3,  #96
+64:
+        vld1.16         {q8,  q9},  [r2]!
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vld1.16         {q10, q11}, [r2]!
+        vst1.16         {q10, q11}, [r0, :128]!
+        vld1.16         {q12, q13}, [r2]!
+        vst1.16         {q12, q13}, [r0, :128]!
+        vld1.16         {q14, q15}, [r2], r3
+        subs            r5,  r5,  #1
+        vst1.16         {q14, q15}, [r0, :128], r1
+        bgt             64b
+        pop             {r4-r11,pc}
+1280:
+        sub             r1,  r1,  #224
+        sub             r3,  r3,  #224
+128:
+        vld1.16         {q8,  q9},  [r2]!
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vld1.16         {q10, q11}, [r2]!
+        vst1.16         {q10, q11}, [r0, :128]!
+        vld1.16         {q12, q13}, [r2]!
+        vst1.16         {q12, q13}, [r0, :128]!
+        vld1.16         {q14, q15}, [r2]!
+        vst1.16         {q14, q15}, [r0, :128]!
+        vld1.16         {q8,  q9},  [r2]!
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vld1.16         {q10, q11}, [r2]!
+        vst1.16         {q10, q11}, [r0, :128]!
+        vld1.16         {q12, q13}, [r2]!
+        vst1.16         {q12, q13}, [r0, :128]!
+        vld1.16         {q14, q15}, [r2], r3
+        subs            r5,  r5,  #1
+        vst1.16         {q14, q15}, [r0, :128], r1
+        bgt             128b
+        pop             {r4-r11,pc}
+endfunc
+
+// This has got the same signature as the prep_8tap functions,
+// and assumes that r9 is set to (clz(w)-24), r7 to intermediate_bits and
+// r8 to w*2.
+function prep_neon
+        adr             r10, L(prep_tbl)
+        ldr             r9,  [r10, r9, lsl #2]
+        vdup.16         q15, r7   // intermediate_bits
+        vmov.i16        q14, #PREP_BIAS
+        add             r10, r10, r9
+        bx              r10
+
+        .align 2
+L(prep_tbl):
+        .word 1280f - L(prep_tbl) + CONFIG_THUMB
+        .word 640f  - L(prep_tbl) + CONFIG_THUMB
+        .word 320f  - L(prep_tbl) + CONFIG_THUMB
+        .word 16f   - L(prep_tbl) + CONFIG_THUMB
+        .word 80f   - L(prep_tbl) + CONFIG_THUMB
+        .word 40f   - L(prep_tbl) + CONFIG_THUMB
+
+40:
+        add             r9,  r1,  r2
+        lsl             r2,  r2,  #1
+4:
+        vld1.16         {d0}, [r1], r2
+        vld1.16         {d1}, [r9], r2
+        subs            r4,  r4,  #2
+        vshl.s16        q0,  q0,  q15
+        vsub.i16        q0,  q0,  q14
+        vst1.16         {q0}, [r0, :128]!
+        bgt             4b
+        pop             {r4-r11,pc}
+80:
+        add             r9,  r1,  r2
+        lsl             r2,  r2,  #1
+8:
+        vld1.16         {q0}, [r1], r2
+        vld1.16         {q1}, [r9], r2
+        subs            r4,  r4,  #2
+        vshl.s16        q0,  q0,  q15
+        vshl.s16        q1,  q1,  q15
+        vsub.i16        q0,  q0,  q14
+        vsub.i16        q1,  q1,  q14
+        vst1.16         {q0, q1}, [r0, :128]!
+        bgt             8b
+        pop             {r4-r11,pc}
+16:
+        vld1.16         {q0, q1}, [r1], r2
+        vshl.s16        q0,  q0,  q15
+        vld1.16         {q2, q3}, [r1], r2
+        subs            r4,  r4,  #2
+        vshl.s16        q1,  q1,  q15
+        vshl.s16        q2,  q2,  q15
+        vshl.s16        q3,  q3,  q15
+        vsub.i16        q0,  q0,  q14
+        vsub.i16        q1,  q1,  q14
+        vsub.i16        q2,  q2,  q14
+        vst1.16         {q0, q1}, [r0, :128]!
+        vsub.i16        q3,  q3,  q14
+        vst1.16         {q2, q3}, [r0, :128]!
+        bgt             16b
+        pop             {r4-r11,pc}
+320:
+        sub             r2,  r2,  #32
+32:
+        vld1.16         {q0, q1}, [r1]!
+        subs            r4,  r4,  #1
+        vshl.s16        q0,  q0,  q15
+        vld1.16         {q2, q3}, [r1], r2
+        vshl.s16        q1,  q1,  q15
+        vshl.s16        q2,  q2,  q15
+        vshl.s16        q3,  q3,  q15
+        vsub.i16        q0,  q0,  q14
+        vsub.i16        q1,  q1,  q14
+        vsub.i16        q2,  q2,  q14
+        vst1.16         {q0, q1}, [r0, :128]!
+        vsub.i16        q3,  q3,  q14
+        vst1.16         {q2, q3}, [r0, :128]!
+        bgt             32b
+        pop             {r4-r11,pc}
+640:
+        sub             r2,  r2,  #96
+64:
+        vld1.16         {q0,  q1},  [r1]!
+        subs            r4,  r4,  #1
+        vshl.s16        q0,  q0,  q15
+        vld1.16         {q2,  q3},  [r1]!
+        vshl.s16        q1,  q1,  q15
+        vld1.16         {q8,  q9},  [r1]!
+        vshl.s16        q2,  q2,  q15
+        vld1.16         {q10, q11}, [r1], r2
+        vshl.s16        q3,  q3,  q15
+        vshl.s16        q8,  q8,  q15
+        vshl.s16        q9,  q9,  q15
+        vshl.s16        q10, q10, q15
+        vshl.s16        q11, q11, q15
+        vsub.i16        q0,  q0,  q14
+        vsub.i16        q1,  q1,  q14
+        vsub.i16        q2,  q2,  q14
+        vsub.i16        q3,  q3,  q14
+        vsub.i16        q8,  q8,  q14
+        vst1.16         {q0,  q1},  [r0, :128]!
+        vsub.i16        q9,  q9,  q14
+        vst1.16         {q2,  q3},  [r0, :128]!
+        vsub.i16        q10, q10, q14
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vsub.i16        q11, q11, q14
+        vst1.16         {q10, q11}, [r0, :128]!
+        bgt             64b
+        pop             {r4-r11,pc}
+1280:
+        sub             r2,  r2,  #224
+128:
+        vld1.16         {q0,  q1},  [r1]!
+        subs            r4,  r4,  #1
+        vshl.s16        q0,  q0,  q15
+        vld1.16         {q2,  q3},  [r1]!
+        vshl.s16        q1,  q1,  q15
+        vld1.16         {q8,  q9},  [r1]!
+        vshl.s16        q2,  q2,  q15
+        vld1.16         {q10, q11}, [r1]!
+        vshl.s16        q3,  q3,  q15
+        vshl.s16        q8,  q8,  q15
+        vshl.s16        q9,  q9,  q15
+        vshl.s16        q10, q10, q15
+        vshl.s16        q11, q11, q15
+        vsub.i16        q0,  q0,  q14
+        vsub.i16        q1,  q1,  q14
+        vsub.i16        q2,  q2,  q14
+        vsub.i16        q3,  q3,  q14
+        vsub.i16        q8,  q8,  q14
+        vst1.16         {q0,  q1},  [r0, :128]!
+        vld1.16         {q0,  q1},  [r1]!
+        vsub.i16        q9,  q9,  q14
+        vsub.i16        q10, q10, q14
+        vst1.16         {q2,  q3},  [r0, :128]!
+        vld1.16         {q2,  q3},  [r1]!
+        vsub.i16        q11, q11, q14
+        vshl.s16        q0,  q0,  q15
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vld1.16         {q8,  q9},  [r1]!
+        vshl.s16        q1,  q1,  q15
+        vshl.s16        q2,  q2,  q15
+        vst1.16         {q10, q11}, [r0, :128]!
+        vld1.16         {q10, q11}, [r1], r2
+        vshl.s16        q3,  q3,  q15
+        vshl.s16        q8,  q8,  q15
+        vshl.s16        q9,  q9,  q15
+        vshl.s16        q10, q10, q15
+        vshl.s16        q11, q11, q15
+        vsub.i16        q0,  q0,  q14
+        vsub.i16        q1,  q1,  q14
+        vsub.i16        q2,  q2,  q14
+        vsub.i16        q3,  q3,  q14
+        vsub.i16        q8,  q8,  q14
+        vst1.16         {q0,  q1},  [r0, :128]!
+        vsub.i16        q9,  q9,  q14
+        vst1.16         {q2,  q3},  [r0, :128]!
+        vsub.i16        q10, q10, q14
+        vst1.16         {q8,  q9},  [r0, :128]!
+        vsub.i16        q11, q11, q14
+        vst1.16         {q10, q11}, [r0, :128]!
+        bgt             128b
+        pop             {r4-r11,pc}
+endfunc
+
+.macro load_slice s0, s1, strd, wd, d0, d1, d2, d3, d4, d5, d6
+        vld1.\wd        {\d0[]}, [\s0], \strd
+        vld1.\wd        {\d1[]}, [\s1], \strd
+.ifnb \d2
+        vld1.\wd        {\d2[]}, [\s0], \strd
+        vld1.\wd        {\d3[]}, [\s1], \strd
+.endif
+.ifnb \d4
+        vld1.\wd        {\d4[]}, [\s0], \strd
+.endif
+.ifnb \d5
+        vld1.\wd        {\d5[]}, [\s1], \strd
+.endif
+.ifnb \d6
+        vld1.\wd        {\d6[]}, [\s0], \strd
+.endif
+.endm
+.macro load_reg s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        vld1.16         {\d0}, [\s0], \strd
+        vld1.16         {\d1}, [\s1], \strd
+.ifnb \d2
+        vld1.16         {\d2}, [\s0], \strd
+        vld1.16         {\d3}, [\s1], \strd
+.endif
+.ifnb \d4
+        vld1.16         {\d4}, [\s0], \strd
+.endif
+.ifnb \d5
+        vld1.16         {\d5}, [\s1], \strd
+.endif
+.ifnb \d6
+        vld1.16         {\d6}, [\s0], \strd
+.endif
+.endm
+.macro load_regpair s0, s1, strd, d0, d1, d2, d3, d4, d5
+        vld1.16         {\d0, \d1}, [\s0], \strd
+.ifnb \d2
+        vld1.16         {\d2, \d3}, [\s1], \strd
+.endif
+.ifnb \d4
+        vld1.16         {\d4, \d5}, [\s0], \strd
+.endif
+.endm
+.macro load_32 s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_slice      \s0, \s1, \strd, 32, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro load_16s16 s0, s1, strd, d0, d1, d2, d3, d4, d5
+        load_regpair    \s0, \s1, \strd, \d0, \d1, \d2, \d3, \d4, \d5
+.endm
+.macro interleave_1_32 r0, r1, r2, r3, r4
+        vext.8          \r0, \r0, \r1, #4
+        vext.8          \r1, \r1, \r2, #4
+.ifnb \r3
+        vext.8          \r2, \r2, \r3, #4
+        vext.8          \r3, \r3, \r4, #4
+.endif
+.endm
+.macro vmin_u16 c, r0, r1, r2, r3
+        vmin.u16        \r0, \r0, \c
+.ifnb \r1
+        vmin.u16        \r1, \r1, \c
+.endif
+.ifnb \r2
+        vmin.u16        \r2, \r2, \c
+        vmin.u16        \r3, \r3, \c
+.endif
+.endm
+.macro vsub_i16 c, r0, r1, r2, r3
+        vsub.i16        \r0, \r0, \c
+.ifnb \r1
+        vsub.i16        \r1, \r1, \c
+.endif
+.ifnb \r2
+        vsub.i16        \r2, \r2, \c
+        vsub.i16        \r3, \r3, \c
+.endif
+.endm
+.macro vmull_vmlal_4 d, s0, s1, s2, s3
+        vmull.s16       \d,  \s0, d0[0]
+        vmlal.s16       \d,  \s1, d0[1]
+        vmlal.s16       \d,  \s2, d0[2]
+        vmlal.s16       \d,  \s3, d0[3]
+.endm
+.macro vmull_vmlal_8 d, s0, s1, s2, s3, s4, s5, s6, s7
+        vmull.s16       \d,  \s0, d0[0]
+        vmlal.s16       \d,  \s1, d0[1]
+        vmlal.s16       \d,  \s2, d0[2]
+        vmlal.s16       \d,  \s3, d0[3]
+        vmlal.s16       \d,  \s4, d1[0]
+        vmlal.s16       \d,  \s5, d1[1]
+        vmlal.s16       \d,  \s6, d1[2]
+        vmlal.s16       \d,  \s7, d1[3]
+.endm
+.macro vqrshrun_s32 shift, q0, d0, q1, d1, q2, d2, q3, d3
+        vqrshrun.s32    \d0, \q0, #\shift
+.ifnb \q1
+        vqrshrun.s32    \d1, \q1, #\shift
+.endif
+.ifnb \q2
+        vqrshrun.s32    \d2, \q2, #\shift
+        vqrshrun.s32    \d3, \q3, #\shift
+.endif
+.endm
+.macro vmovn_i32 q0, d0, q1, d1, q2, d2, q3, d3
+        vmovn.i32       \d0, \q0
+.ifnb \q1
+        vmovn.i32       \d1, \q1
+.endif
+.ifnb \q2
+        vmovn.i32       \d2, \q2
+        vmovn.i32       \d3, \q3
+.endif
+.endm
+.macro vrshl_s32 shift, r0, r1, r2, r3
+        vrshl.s32       \r0, \r0, \shift
+        vrshl.s32       \r1, \r1, \shift
+.ifnb \r2
+        vrshl.s32       \r2, \r2, \shift
+        vrshl.s32       \r3, \r3, \shift
+.endif
+.endm
+.macro vst1_32 strd, r0, r1
+        vst1.32         {\r0[0]}, [r0, :32], \strd
+        vst1.32         {\r0[1]}, [r9, :32], \strd
+.ifnb \r1
+        vst1.32         {\r1[0]}, [r0, :32], \strd
+        vst1.32         {\r1[1]}, [r9, :32], \strd
+.endif
+.endm
+.macro vst1_reg strd, align, r0, r1, r2, r3, r4, r5, r6, r7
+        vst1.16         {\r0}, [r0, \align], \strd
+        vst1.16         {\r1}, [r9, \align], \strd
+.ifnb \r2
+        vst1.16         {\r2}, [r0, \align], \strd
+        vst1.16         {\r3}, [r9, \align], \strd
+.endif
+.ifnb \r4
+        vst1.16         {\r4}, [r0, \align], \strd
+        vst1.16         {\r5}, [r9, \align], \strd
+        vst1.16         {\r6}, [r0, \align], \strd
+        vst1.16         {\r7}, [r9, \align], \strd
+.endif
+.endm
+.macro finalize type, q0, q1, d0, d1, q2, q3, d2, d3
+.ifc \type, put
+        vqrshrun_s32    6,   \q0, \d0, \q1, \d1, \q2, \d2, \q3, \d3
+        vmin_u16        q15, \q0, \q1
+.else
+        vrshl_s32       q14, \q0, \q1, \q2, \q3 // -(6-intermediate_bits)
+        vmovn_i32       \q0, \d0, \q1, \d1, \q2, \d2, \q3, \d3
+        vsub_i16        q15, \q0, \q1           // PREP_BIAS
+.endif
+.endm
+.macro shift_store_4 type, strd, q0, q1, d0, d1, q2, q3, d2, d3
+        finalize        \type, \q0, \q1, \d0, \d1, \q2, \q3, \d2, \d3
+        vst1_reg        \strd, :64, \d0, \d1, \d2, \d3
+.endm
+.macro shift_store_8 type, strd, q0, q1, d0, d1, q2, q3, d2, d3
+        finalize        \type, \q0, \q1, \d0, \d1, \q2, \q3, \d2, \d3
+        vst1_reg        \strd, :128, \q0, \q1
+.endm
+.macro shift_store_16 type, strd, q0, q1, d0, d1, q2, q3, d2, d3
+        finalize        \type, \q0, \q1, \d0, \d1, \q2, \q3, \d2, \d3
+        vst1.16         {\q0, \q1}, [r0, :128], \strd
+.endm
+
+.macro make_8tap_fn op, type, type_h, type_v
+function \op\()_8tap_\type\()_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        movw            r9,  \type_h
+        movw            r10, \type_v
+        b               \op\()_8tap_neon
+endfunc
+.endm
+
+// No spaces in these expressions, due to gas-preprocessor.
+#define REGULAR ((0*15<<7)|3*15)
+#define SMOOTH  ((1*15<<7)|4*15)
+#define SHARP   ((2*15<<7)|3*15)
+
+.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, my, bdmax, ds2, sr2
+make_8tap_fn \type, regular,        REGULAR, REGULAR
+make_8tap_fn \type, regular_smooth, REGULAR, SMOOTH
+make_8tap_fn \type, regular_sharp,  REGULAR, SHARP
+make_8tap_fn \type, smooth,         SMOOTH,  SMOOTH
+make_8tap_fn \type, smooth_regular, SMOOTH,  REGULAR
+make_8tap_fn \type, smooth_sharp,   SMOOTH,  SHARP
+make_8tap_fn \type, sharp,          SHARP,   SHARP
+make_8tap_fn \type, sharp_regular,  SHARP,   REGULAR
+make_8tap_fn \type, sharp_smooth,   SHARP,   SMOOTH
+
+function \type\()_8tap_neon
+        ldrd            r4,  r5,  [sp, #36]
+        ldrd            r6,  r7,  [sp, #44]
+.ifc \bdmax, r8
+        ldr             r8,  [sp, #52]
+.endif
+        movw            r11, #0x4081  // (1 << 14) | (1 << 7) | (1 << 0)
+        mul             \mx, \mx, r11
+        mul             \my, \my, r11
+        add             \mx, \mx, r9  // mx, 8tap_h, 4tap_h
+        add             \my, \my, r10 // my, 8tap_v, 4tap_v
+
+.ifc \type, prep
+        lsl             \d_strd, \w, #1
+.endif
+
+        vdup.16         q15, \bdmax            // bitdepth_max
+        clz             \bdmax,  \bdmax
+        clz             r9,  \w
+        sub             \bdmax,  \bdmax,  #18  // intermediate_bits = clz(bitdepth_max) - 18
+        tst             \mx, #(0x7f << 14)
+        sub             r9,  r9,  #24
+        add             lr,  \bdmax, #6        // 6 + intermediate_bits
+        rsb             r12, \bdmax, #6        // 6 - intermediate_bits
+        movrel          r11, X(mc_subpel_filters), -8
+        bne             L(\type\()_8tap_h)
+        tst             \my, #(0x7f << 14)
+        bne             L(\type\()_8tap_v)
+        b               \type\()_neon
+
+L(\type\()_8tap_h):
+        cmp             \w,  #4
+        ubfx            r10, \mx, #7,  #7
+        and             \mx, \mx, #0x7f
+        it              gt
+        movgt           \mx, r10
+        tst             \my, #(0x7f << 14)
+        add             \mx, r11, \mx, lsl #3
+        bne             L(\type\()_8tap_hv)
+
+        adr             r10, L(\type\()_8tap_h_tbl)
+        vdup.32         q14, r12           // 6 - intermediate_bits
+        ldr             r9,  [r10, r9, lsl #2]
+        vneg.s32        q14, q14           // -(6-intermediate_bits)
+.ifc \type, put
+        vdup.16         q13, \bdmax        // intermediate_bits
+.else
+        vmov.i16        q13, #PREP_BIAS
+.endif
+        add             r10, r10, r9
+.ifc \type, put
+        vneg.s16        q13, q13           // -intermediate_bits
+.endif
+        bx              r10
+
+        .align 2
+L(\type\()_8tap_h_tbl):
+        .word 1280f - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_8tap_h_tbl) + CONFIG_THUMB
+
+20:     // 2xN h
+.ifc \type, put
+        add             \mx, \mx, #2
+        vld1.32         {d0[]}, [\mx]
+        sub             \src,  \src,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+2:
+        vld1.16         {q2}, [\src], \s_strd
+        vld1.16         {q3}, [\sr2], \s_strd
+        vext.8          d5,  d4,  d5,  #2
+        vext.8          d7,  d6,  d7,  #2
+        subs            \h,  \h,  #2
+        vtrn.32         d4,  d6
+        vtrn.32         d5,  d7
+        vmull.s16       q1,  d4,  d0[0]
+        vmlal.s16       q1,  d5,  d0[1]
+        vmlal.s16       q1,  d6,  d0[2]
+        vmlal.s16       q1,  d7,  d0[3]
+        vrshl.s32       q1,  q1,  q14 // -(6-intermediate_bits)
+        vqmovun.s32     d2,  q1
+        vrshl.s16       d2,  d2,  d26 // -intermediate_bits
+        vmin.u16        d2,  d2,  d30
+        vst1.32         {d2[0]}, [\dst, :32], \d_strd
+        vst1.32         {d2[1]}, [\ds2, :32], \d_strd
+        bgt             2b
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN h
+        add             \mx, \mx, #2
+        vld1.32         {d0[]}, [\mx]
+        sub             \src,  \src,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+4:
+        vld1.16         {q8},  [\src], \s_strd
+        vld1.16         {q11}, [\sr2], \s_strd
+        vext.8          d18, d16, d17, #2
+        vext.8          d19, d16, d17, #4
+        vext.8          d20, d16, d17, #6
+        vext.8          d24, d22, d23, #2
+        vext.8          d25, d22, d23, #4
+        vext.8          d21, d22, d23, #6
+        subs            \h,  \h,  #2
+        vmull.s16       q2,  d16, d0[0]
+        vmlal.s16       q2,  d18, d0[1]
+        vmlal.s16       q2,  d19, d0[2]
+        vmlal.s16       q2,  d20, d0[3]
+        vmull.s16       q3,  d22, d0[0]
+        vmlal.s16       q3,  d24, d0[1]
+        vmlal.s16       q3,  d25, d0[2]
+        vmlal.s16       q3,  d21, d0[3]
+        vrshl.s32       q2,  q2,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+.ifc \type, put
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vrshl.s16       q2,  q2,  q13 // -intermediate_bits
+        vmin.u16        q2,  q2,  q15
+.else
+        vmovn.s32       d4,  q2
+        vmovn.s32       d5,  q3
+        vsub.i16        q2,  q2,  q13 // PREP_BIAS
+.endif
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d5}, [\ds2, :64], \d_strd
+        bgt             4b
+        pop             {r4-r11,pc}
+
+80:
+160:
+320:
+640:
+1280:   // 8xN, 16xN, 32xN, ... h
+        vpush           {q4-q5}
+        vld1.8          {d0}, [\mx, :64]
+        sub             \src,  \src,  #6
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+
+        sub             \s_strd,  \s_strd,  \w, lsl #1
+        sub             \s_strd,  \s_strd,  #16
+.ifc \type, put
+        lsl             \d_strd,  \d_strd,  #1
+        sub             \d_strd,  \d_strd,  \w, lsl #1
+.endif
+81:
+        vld1.16         {q8,  q9},  [\src]!
+        vld1.16         {q10, q11}, [\sr2]!
+        mov             \mx, \w
+
+8:
+        vmull.s16       q1,  d16, d0[0]
+        vmull.s16       q2,  d17, d0[0]
+        vmull.s16       q3,  d20, d0[0]
+        vmull.s16       q4,  d21, d0[0]
+.irpc i, 1234567
+        vext.8          q12, q8,  q9,  #(2*\i)
+        vext.8          q5,  q10, q11, #(2*\i)
+.if \i < 4
+        vmlal.s16       q1,  d24, d0[\i]
+        vmlal.s16       q2,  d25, d0[\i]
+        vmlal.s16       q3,  d10, d0[\i]
+        vmlal.s16       q4,  d11, d0[\i]
+.else
+        vmlal.s16       q1,  d24, d1[\i-4]
+        vmlal.s16       q2,  d25, d1[\i-4]
+        vmlal.s16       q3,  d10, d1[\i-4]
+        vmlal.s16       q4,  d11, d1[\i-4]
+.endif
+.endr
+        subs            \mx, \mx, #8
+        vrshl.s32       q1,  q1,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q2,  q2,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q4,  q4,  q14 // -(6-intermediate_bits)
+.ifc \type, put
+        vqmovun.s32     d2,  q1
+        vqmovun.s32     d3,  q2
+        vqmovun.s32     d4,  q3
+        vqmovun.s32     d5,  q4
+        vrshl.s16       q1,  q1,  q13 // -intermediate_bits
+        vrshl.s16       q2,  q2,  q13 // -intermediate_bits
+        vmin.u16        q1,  q1,  q15
+        vmin.u16        q2,  q2,  q15
+.else
+        vmovn.s32       d2,  q1
+        vmovn.s32       d3,  q2
+        vmovn.s32       d4,  q3
+        vmovn.s32       d5,  q4
+        vsub.i16        q1,  q1,  q13 // PREP_BIAS
+        vsub.i16        q2,  q2,  q13 // PREP_BIAS
+.endif
+        vst1.16         {q1}, [\dst, :128]!
+        vst1.16         {q2}, [\ds2, :128]!
+        ble             9f
+
+        vmov            q8,  q9
+        vmov            q10, q11
+        vld1.16         {q9},  [\src]!
+        vld1.16         {q11}, [\sr2]!
+        b               8b
+
+9:
+        add             \dst,  \dst,  \d_strd
+        add             \ds2,  \ds2,  \d_strd
+        add             \src,  \src,  \s_strd
+        add             \sr2,  \sr2,  \s_strd
+
+        subs            \h,  \h,  #2
+        bgt             81b
+        vpop            {q4-q5}
+        pop             {r4-r11,pc}
+
+
+L(\type\()_8tap_v):
+        cmp             \h,  #4
+        ubfx            r10, \my, #7,  #7
+        and             \my, \my, #0x7f
+        it              gt
+        movgt           \my, r10
+        add             \my, r11, \my, lsl #3
+
+.ifc \type, prep
+        vdup.32         q14, r12        // 6 - intermediate_bits
+        vmov.i16        q15, #PREP_BIAS
+.endif
+        adr             r10, L(\type\()_8tap_v_tbl)
+        ldr             r9,  [r10, r9, lsl #2]
+.ifc \type, prep
+        vneg.s32        q14, q14        // -(6-intermediate_bits)
+.endif
+        add             r10, r10, r9
+        bx              r10
+
+        .align 2
+L(\type\()_8tap_v_tbl):
+        .word 1280f - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_8tap_v_tbl) + CONFIG_THUMB
+
+20:     // 2xN v
+.ifc \type, put
+        bgt             28f
+
+        cmp             \h,  #2
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src,  \src,  \s_strd
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        vmovl.s8        q0,  d0
+
+        // 2x2 v
+        load_32         \src, \sr2, \s_strd, d1, d2, d3, d4, d5
+        interleave_1_32 d1,  d2,  d3,  d4,  d5
+        bgt             24f
+        vmull_vmlal_4   q8,  d1,  d2,  d3,  d4
+        vqrshrun_s32    6,   q8,  d16
+        vmin_u16        d30, d16
+        vst1_32         \d_strd,  d16
+        pop             {r4-r11,pc}
+
+24:     // 2x4 v
+        load_32         \sr2, \src, \s_strd, d6, d7
+        interleave_1_32 d5,  d6,  d7
+        vmull_vmlal_4   q8,  d1,  d2,  d3,  d4
+        vmull_vmlal_4   q9,  d3,  d4,  d5,  d6
+        vqrshrun_s32    6,   q8,  d16, q9,  d17
+        vmin_u16        q15, q8
+        vst1_32         \d_strd,  d16, d17
+        pop             {r4-r11,pc}
+
+28:     // 2x6, 2x8, 2x12, 2x16 v
+        vld1.8          {d0}, [\my, :64]
+        sub             \sr2,  \src,  \s_strd, lsl #1
+        add             \ds2,  \dst,  \d_strd
+        sub             \src,  \sr2,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        vmovl.s8        q0,  d0
+
+        load_32         \src, \sr2, \s_strd, d2, d3, d4, d5, d6, d7, d16
+        interleave_1_32 d2,  d3,  d4,  d5,  d6
+        interleave_1_32 d6,  d7,  d16
+216:
+        subs            \h,  \h,  #4
+        load_32         \sr2, \src, \s_strd, d17, d18, d19, d20
+        interleave_1_32 d16, d17, d18, d19, d20
+        vmull_vmlal_8   q13, d2,  d3,  d4,  d5,  d6,  d7,  d16, d17
+        vmull_vmlal_8   q1,  d4,  d5,  d6,  d7,  d16, d17, d18, d19
+        vqrshrun_s32    6,   q13, d26, q1,  d27
+        vmin_u16        q15, q13
+        vst1_32         \d_strd,  d26, d27
+        ble             0f
+        cmp             \h,  #2
+        vmov            q1,  q3
+        vmov            q2,  q8
+        vmov            q3,  q9
+        vmov            d16, d20
+        beq             26f
+        b               216b
+26:
+        load_32         \sr2, \src, \s_strd, d17, d18
+        interleave_1_32 d16, d17, d18
+        vmull_vmlal_8   q13, d2,  d3,  d4,  d5,  d6,  d7,  d16, d17
+        vqrshrun_s32    6,   q13, d26
+        vmin_u16        d30, d26
+        vst1_32         \d_strd,  d26
+0:
+        pop             {r4-r11,pc}
+.endif
+
+40:
+        bgt             480f
+
+        // 4x2, 4x4 v
+        cmp             \h,  #2
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+
+        load_reg        \src, \sr2, \s_strd, d1, d2, d3, d4, d5
+        vmull_vmlal_4   q8,  d1,  d2,  d3,  d4
+        vmull_vmlal_4   q9,  d2,  d3,  d4,  d5
+        shift_store_4   \type, \d_strd, q8, q9, d16, d17
+        ble             0f
+        load_reg        \sr2, \src, \s_strd, d6, d7
+        vmull_vmlal_4   q8,  d3,  d4,  d5,  d6
+        vmull_vmlal_4   q9,  d4,  d5,  d6,  d7
+        shift_store_4   \type, \d_strd, q8, q9, d16, d17
+0:
+        pop             {r4-r11,pc}
+
+480:    // 4x6, 4x8, 4x12, 4x16 v
+        vld1.8          {d0}, [\my, :64]
+        sub             \sr2, \src, \s_strd, lsl #1
+        add             \ds2, \dst, \d_strd
+        sub             \src, \sr2, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+
+        load_reg        \src, \sr2, \s_strd, d16, d17, d18, d19, d20, d21, d22
+
+48:
+        subs            \h,  \h,  #4
+        load_reg        \sr2, \src, \s_strd, d23, d24, d25, d26
+        vmull_vmlal_8   q1,  d16, d17, d18, d19, d20, d21, d22, d23
+        vmull_vmlal_8   q2,  d17, d18, d19, d20, d21, d22, d23, d24
+        vmull_vmlal_8   q3,  d18, d19, d20, d21, d22, d23, d24, d25
+        vmull_vmlal_8   q8,  d19, d20, d21, d22, d23, d24, d25, d26
+        shift_store_4   \type, \d_strd, q1, q2, d2, d3, q3, q8, d4, d5
+        ble             0f
+        cmp             \h,  #2
+        vmov            q8,  q10
+        vmov            q9,  q11
+        vmov            q10, q12
+        vmov            d22, d26
+        beq             46f
+        b               48b
+46:
+        load_reg        \sr2, \src, \s_strd, d23, d24
+        vmull_vmlal_8   q1,  d16, d17, d18, d19, d20, d21, d22, d23
+        vmull_vmlal_8   q2,  d17, d18, d19, d20, d21, d22, d23, d24
+        shift_store_4   \type, \d_strd, q1, q2, d2, d3
+0:
+        pop             {r4-r11,pc}
+
+80:
+        bgt             880f
+
+        // 8x2, 8x4 v
+        cmp             \h,  #2
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+
+        load_reg        \src, \sr2, \s_strd, q1, q2, q3, q8, q9
+        vmull_vmlal_4   q10, d2,  d4,  d6,  d16
+        vmull_vmlal_4   q11, d3,  d5,  d7,  d17
+        vmull_vmlal_4   q12, d4,  d6,  d16, d18
+        vmull_vmlal_4   q13, d5,  d7,  d17, d19
+        shift_store_8   \type, \d_strd, q10, q11, d20, d21, q12, q13, d22, d23
+        ble             0f
+        load_reg        \sr2, \src, \s_strd, q10, q11
+        vmull_vmlal_4   q1,  d6,  d16, d18, d20
+        vmull_vmlal_4   q2,  d7,  d17, d19, d21
+        vmull_vmlal_4   q12, d16, d18, d20, d22
+        vmull_vmlal_4   q13, d17, d19, d21, d23
+        shift_store_8   \type, \d_strd, q1, q2, d2, d3, q12, q13, d4, d5
+0:
+        pop             {r4-r11,pc}
+
+880:    // 8x6, 8x8, 8x16, 8x32 v
+1680:   // 16x8, 16x16, ...
+320:    // 32x8, 32x16, ...
+640:
+1280:
+        vpush           {q4-q7}
+        vld1.8          {d0}, [\my, :64]
+        sub             \src, \src, \s_strd
+        sub             \src, \src, \s_strd, lsl #1
+        vmovl.s8        q0,  d0
+        mov             \my, \h
+168:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        load_reg        \src, \sr2, \s_strd, q5, q6, q7, q8, q9, q10, q11
+
+88:
+        subs            \h,  \h,  #2
+        load_reg        \sr2, \src, \s_strd, q12, q13
+        vmull_vmlal_8   q1,  d10, d12, d14, d16, d18, d20, d22, d24
+        vmull_vmlal_8   q2,  d11, d13, d15, d17, d19, d21, d23, d25
+        vmull_vmlal_8   q3,  d12, d14, d16, d18, d20, d22, d24, d26
+        vmull_vmlal_8   q4,  d13, d15, d17, d19, d21, d23, d25, d27
+        shift_store_8   \type, \d_strd, q1, q2,  d2,  d3,  q3,  q4,  d4,  d5
+        ble             9f
+        subs            \h,  \h,  #2
+        load_reg        \sr2, \src, \s_strd, q1,  q2
+        vmull_vmlal_8   q3,  d14, d16, d18, d20, d22, d24, d26, d2
+        vmull_vmlal_8   q4,  d15, d17, d19, d21, d23, d25, d27, d3
+        vmull_vmlal_8   q5,  d16, d18, d20, d22, d24, d26, d2,  d4
+        vmull_vmlal_8   q6,  d17, d19, d21, d23, d25, d27, d3,  d5
+        shift_store_8   \type, \d_strd, q3, q4,  d6,  d7,  q5,  q6,  d8,  d9
+        ble             9f
+        vmov            q5,  q9
+        vmov            q6,  q10
+        vmov            q7,  q11
+        vmov            q8,  q12
+        vmov            q9,  q13
+        vmov            q10, q1
+        vmov            q11, q2
+        b               88b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        mls             \src, \s_strd, \my, \src
+        mls             \dst, \d_strd, \my, \dst
+        sub             \src, \src, \s_strd, lsl #3
+        mov             \h,  \my
+        add             \src, \src, #16
+        add             \dst, \dst, #16
+        b               168b
+0:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+160:
+        bgt             1680b
+
+        // 16x2, 16x4 v
+        vpush           {q6-q7}
+        add             \my, \my, #2
+        vld1.32         {d0[]}, [\my]
+        sub             \src, \src, \s_strd
+        vmovl.s8        q0,  d0
+
+        load_16s16      \src, \src, \s_strd, q6,  q7,  q8,  q9, q10, q11
+16:
+        load_16s16      \src, \src, \s_strd, q12, q13
+        subs            \h,  \h,  #1
+        vmull_vmlal_4   q1,  d12, d16, d20, d24
+        vmull_vmlal_4   q2,  d13, d17, d21, d25
+        vmull_vmlal_4   q3,  d14, d18, d22, d26
+        vmull_vmlal_4   q6,  d15, d19, d23, d27
+        shift_store_16  \type, \d_strd, q1, q2, d2, d3, q3, q6, d4, d5
+        ble             0f
+        vmov            q6,  q8
+        vmov            q7,  q9
+        vmov            q8,  q10
+        vmov            q9,  q11
+        vmov            q10, q12
+        vmov            q11, q13
+        b               16b
+0:
+        vpop            {q6-q7}
+        pop             {r4-r11,pc}
+
+
+L(\type\()_8tap_hv):
+        cmp             \h,  #4
+        ubfx            r10, \my, #7,  #7
+        and             \my, \my, #0x7f
+        it              gt
+        movgt           \my, r10
+4:
+        add             \my, r11, \my, lsl #3
+
+        adr             r10, L(\type\()_8tap_hv_tbl)
+        neg             r12, r12           // -(6-intermediate_bits)
+        ldr             r9,  [r10, r9, lsl #2]
+        vdup.32         q14, r12           // -(6-intermediate_bits)
+.ifc \type, put
+        neg             r8,  lr            // -(6+intermeidate_bits)
+.else
+        vmov.i16        q13, #PREP_BIAS
+.endif
+        add             r10, r10, r9
+.ifc \type, put
+        vdup.32         q13, r8            // -(6+intermediate_bits)
+.endif
+        bx              r10
+
+        .align 2
+L(\type\()_8tap_hv_tbl):
+        .word 1280f - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_8tap_hv_tbl) + CONFIG_THUMB
+
+20:
+.ifc \type, put
+        add             \mx, \mx, #2
+        vld1.32         {d0[]}, [\mx]
+        bgt             280f
+        add             \my, \my, #2
+        vld1.32         {d2[]}, [\my]
+
+        // 2x2, 2x4 hv
+        sub             \sr2, \src, #2
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d22, d23, #2
+        vmull.s16       q11, d22, d0
+        vmull.s16       q12, d24, d0
+        vpadd.s32       d22, d22, d23
+        vpadd.s32       d23, d24, d25
+        vpadd.s32       d22, d22, d23
+        vrshl.s32       d16, d22, d28 // -(6-intermediate_bits)
+        vmovn.i32       d16, q8
+        bl              L(\type\()_8tap_filter_2)
+
+        vext.8          d16, d16, d16, #4
+        vext.8          d16, d16, d24, #4
+        vmov            d17, d24
+
+2:
+        bl              L(\type\()_8tap_filter_2)
+
+        vext.8          d18, d17, d24, #4
+        vmull.s16       q2,  d16, d2[0]
+        vmlal.s16       q2,  d17, d2[1]
+        vmlal.s16       q2,  d18, d2[2]
+        vmlal.s16       q2,  d24, d2[3]
+
+        vrshl.s32       q2,  q2,  q13 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vmin.u16        d4,  d4,  d30
+        subs            \h,  \h,  #2
+        vst1.32         {d4[0]}, [\dst, :32], \d_strd
+        vst1.32         {d4[1]}, [\ds2, :32], \d_strd
+        ble             0f
+        vmov            d16, d18
+        vmov            d17, d24
+        b               2b
+
+280:    // 2x8, 2x16, 2x32 hv
+        vld1.8          {d2},  [\my, :64]
+        sub             \src, \src, #2
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d22, d23, #2
+        vmull.s16       q11, d22, d0
+        vmull.s16       q12, d24, d0
+        vpadd.s32       d22, d22, d23
+        vpadd.s32       d23, d24, d25
+        vpadd.s32       d22, d22, d23
+        vrshl.s32       d16, d22, d28 // -(6-intermediate_bits)
+        vmovn.i32       d16, q8
+
+        bl              L(\type\()_8tap_filter_2)
+
+        vext.8          d16, d16, d16, #4
+        vext.8          d16, d16, d24, #4
+        vmov            d17, d24
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d18, d17, d24, #4
+        vmov            d19, d24
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d20, d19, d24, #4
+        vmov            d21, d24
+
+28:
+        bl              L(\type\()_8tap_filter_2)
+        vext.8          d22, d21, d24, #4
+        vmull.s16       q3,  d16, d2[0]
+        vmlal.s16       q3,  d17, d2[1]
+        vmlal.s16       q3,  d18, d2[2]
+        vmlal.s16       q3,  d19, d2[3]
+        vmlal.s16       q3,  d20, d3[0]
+        vmlal.s16       q3,  d21, d3[1]
+        vmlal.s16       q3,  d22, d3[2]
+        vmlal.s16       q3,  d24, d3[3]
+
+        vrshl.s32       q3,  q3,  q13 // -(6+intermediate_bits)
+        vqmovun.s32     d6,  q3
+        vmin.u16        d6,  d6,  d30
+        subs            \h,  \h,  #2
+        vst1.32         {d6[0]}, [\dst, :32], \d_strd
+        vst1.32         {d6[1]}, [\ds2, :32], \d_strd
+        ble             0f
+        vmov            q8,  q9
+        vmov            q9,  q10
+        vmov            d20, d22
+        vmov            d21, d24
+        b               28b
+0:
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_2):
+        vld1.16         {q11}, [\sr2], \s_strd
+        vld1.16         {q12}, [\src], \s_strd
+        vext.8          d23, d22, d23, #2
+        vext.8          d25, d24, d25, #2
+        vtrn.32         q11, q12
+        vmull.s16       q3,  d22, d0[0]
+        vmlal.s16       q3,  d23, d0[1]
+        vmlal.s16       q3,  d24, d0[2]
+        vmlal.s16       q3,  d25, d0[3]
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vmovn.i32       d24, q3
+        bx              lr
+.endif
+
+40:
+        add             \mx, \mx, #2
+        vld1.32         {d0[]}, [\mx]
+        bgt             480f
+        add             \my, \my, #2
+        vld1.32         {d2[]}, [\my]
+        sub             \sr2, \src, #2
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        // 4x2, 4x4 hv
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d22, d23, #2
+        vext.8          d25, d22, d23, #4
+        vext.8          d23, d22, d23, #6
+        vmull.s16       q10, d22, d0[0]
+        vmlal.s16       q10, d24, d0[1]
+        vmlal.s16       q10, d25, d0[2]
+        vmlal.s16       q10, d23, d0[3]
+        vrshl.s32       q10, q10, q14 // -(6-intermediate_bits)
+        vmovn.i32       d17, q10
+
+        bl              L(\type\()_8tap_filter_4)
+        vmov            q9,  q12
+
+4:
+        bl              L(\type\()_8tap_filter_4)
+        vmull.s16       q2,  d17, d2[0]
+        vmlal.s16       q2,  d18, d2[1]
+        vmlal.s16       q2,  d19, d2[2]
+        vmlal.s16       q2,  d24, d2[3]
+        vmull.s16       q3,  d18, d2[0]
+        vmlal.s16       q3,  d19, d2[1]
+        vmlal.s16       q3,  d24, d2[2]
+        vmlal.s16       q3,  d25, d2[3]
+.ifc \type, put
+        vrshl.s32       q2,  q2,  q13 // -(6+intermediate_bits)
+        vrshl.s32       q3,  q3,  q13 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vmin.u16        q2,  q2,  q15
+.else
+        vrshrn.i32      d4,  q2,  #6
+        vrshrn.i32      d5,  q3,  #6
+        vsub.i16        q2,  q2,  q13 // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d5}, [\ds2, :64], \d_strd
+        ble             0f
+        vmov            d17, d19
+        vmov            q9,  q12
+        b               4b
+0:
+        pop             {r4-r11,pc}
+
+480:    // 4x8, 4x16, 4x32 hv
+        vpush           {d13-d15}
+        vld1.8          {d2},  [\my, :64]
+        sub             \src, \src, #2
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d22, d23, #2
+        vext.8          d25, d22, d23, #4
+        vext.8          d23, d22, d23, #6
+        vmull.s16       q10, d22, d0[0]
+        vmlal.s16       q10, d24, d0[1]
+        vmlal.s16       q10, d25, d0[2]
+        vmlal.s16       q10, d23, d0[3]
+        vrshl.s32       q10, q10, q14 // -(6-intermediate_bits)
+        vmovn.i32       d13, q10
+
+        bl              L(\type\()_8tap_filter_4)
+        vmov            q7,  q12
+        bl              L(\type\()_8tap_filter_4)
+        vmov            q8,  q12
+        bl              L(\type\()_8tap_filter_4)
+        vmov            q9,  q12
+
+48:
+        bl              L(\type\()_8tap_filter_4)
+        vmull.s16       q2,  d13, d2[0]
+        vmlal.s16       q2,  d14, d2[1]
+        vmlal.s16       q2,  d15, d2[2]
+        vmlal.s16       q2,  d16, d2[3]
+        vmlal.s16       q2,  d17, d3[0]
+        vmlal.s16       q2,  d18, d3[1]
+        vmlal.s16       q2,  d19, d3[2]
+        vmlal.s16       q2,  d24, d3[3]
+        vmull.s16       q3,  d14, d2[0]
+        vmlal.s16       q3,  d15, d2[1]
+        vmlal.s16       q3,  d16, d2[2]
+        vmlal.s16       q3,  d17, d2[3]
+        vmlal.s16       q3,  d18, d3[0]
+        vmlal.s16       q3,  d19, d3[1]
+        vmlal.s16       q3,  d24, d3[2]
+        vmlal.s16       q3,  d25, d3[3]
+.ifc \type, put
+        vrshl.s32       q2,  q2,  q13 // -(6+intermediate_bits)
+        vrshl.s32       q3,  q3,  q13 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vmin.u16        q2,  q2,  q15
+.else
+        vrshrn.i32      d4,  q2,  #6
+        vrshrn.i32      d5,  q3,  #6
+        vsub.i16        q2,  q2,  q13 // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {d4}, [\dst, :64], \d_strd
+        vst1.16         {d5}, [\ds2, :64], \d_strd
+        ble             0f
+        vmov            d13, d15
+        vmov            q7,  q8
+        vmov            q8,  q9
+        vmov            q9,  q12
+        b               48b
+0:
+        vpop            {d13-d15}
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_4):
+        vld1.16         {q10}, [\sr2], \s_strd
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d24, d20, d21, #2
+        vext.8          d25, d20, d21, #4
+        vext.8          d21, d20, d21, #6
+        vmull.s16       q3,  d20, d0[0]
+        vmlal.s16       q3,  d24, d0[1]
+        vmlal.s16       q3,  d25, d0[2]
+        vmlal.s16       q3,  d21, d0[3]
+        vext.8          d24, d22, d23, #2
+        vext.8          d25, d22, d23, #4
+        vext.8          d23, d22, d23, #6
+        vmull.s16       q10, d22, d0[0]
+        vmlal.s16       q10, d24, d0[1]
+        vmlal.s16       q10, d25, d0[2]
+        vmlal.s16       q10, d23, d0[3]
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q10, q10, q14 // -(6-intermediate_bits)
+        vmovn.i32       d24, q3
+        vmovn.i32       d25, q10
+        bx              lr
+
+80:
+160:
+320:
+        bgt             880f
+        add             \my, \my, #2
+        vld1.8          {d0},  [\mx, :64]
+        vld1.32         {d2[]}, [\my]
+        sub             \src,  \src,  #6
+        sub             \src,  \src,  \s_strd
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+        mov             \my, \h
+
+164:    // 8x2, 8x4, 16x2, 16x4, 32x2, 32x4 hv
+        add             \ds2, \dst, \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        vld1.16         {q11, q12}, [\src], \s_strd
+        vmull.s16       q2,  d22, d0[0]
+        vmull.s16       q3,  d23, d0[0]
+        vdup.32         q14, r12      // -(6-intermediate_bits)
+.irpc i, 1234567
+        vext.8          q10, q11, q12, #(2*\i)
+.if \i < 4
+        vmlal.s16       q2,  d20, d0[\i]
+        vmlal.s16       q3,  d21, d0[\i]
+.else
+        vmlal.s16       q2,  d20, d1[\i - 4]
+        vmlal.s16       q3,  d21, d1[\i - 4]
+.endif
+.endr
+        vrshl.s32       q2,  q2,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vmovn.i32       d16, q2
+        vmovn.i32       d17, q3
+
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q9,  q11
+        vmov            q10, q12
+
+8:
+        bl              L(\type\()_8tap_filter_8)
+        vmull.s16       q2,  d16, d2[0]
+        vmull.s16       q3,  d17, d2[0]
+        vmull.s16       q13, d18, d2[0]
+        vmull.s16       q14, d19, d2[0]
+.ifc \type, put
+        vdup.32         q8,  r8      // -(6+intermediate_bits)
+.endif
+        vmlal.s16       q2,  d18, d2[1]
+        vmlal.s16       q3,  d19, d2[1]
+        vmlal.s16       q13, d20, d2[1]
+        vmlal.s16       q14, d21, d2[1]
+        vmlal.s16       q2,  d20, d2[2]
+        vmlal.s16       q3,  d21, d2[2]
+        vmlal.s16       q13, d22, d2[2]
+        vmlal.s16       q14, d23, d2[2]
+        vmlal.s16       q2,  d22, d2[3]
+        vmlal.s16       q3,  d23, d2[3]
+        vmlal.s16       q13, d24, d2[3]
+        vmlal.s16       q14, d25, d2[3]
+.ifc \type, put
+        vdup.16         q9,  \bdmax  // bitdepth_max
+        vrshl.s32       q2,  q2,  q8 // -(6+intermediate_bits)
+        vrshl.s32       q3,  q3,  q8 // -(6+intermediate_bits)
+        vrshl.s32       q13, q13, q8 // -(6+intermediate_bits)
+        vrshl.s32       q14, q14, q8 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vqmovun.s32     d6,  q13
+        vqmovun.s32     d7,  q14
+        vmin.u16        q2,  q2,  q15
+        vmin.u16        q3,  q3,  q15
+.else
+        vmov.i16        q9,  #PREP_BIAS
+        vrshrn.i32      d4,  q2,  #6
+        vrshrn.i32      d5,  q3,  #6
+        vrshrn.i32      d6,  q13, #6
+        vrshrn.i32      d7,  q14, #6
+        vsub.i16        q2,  q2,  q9 // PREP_BIAS
+        vsub.i16        q3,  q3,  q9 // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {q2}, [\dst, :128], \d_strd
+        vst1.16         {q3}, [\ds2, :128], \d_strd
+        ble             9f
+        vmov            q8,  q10
+        vmov            q9,  q11
+        vmov            q10, q12
+        b               8b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #2
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+        b               164b
+0:
+        pop             {r4-r11,pc}
+
+880:    // 8x8, 8x16, ..., 16x8, ..., 32x8, ... hv
+640:
+1280:
+        vpush           {q4-q7}
+        vld1.8          {d0}, [\mx, :64]
+        vld1.8          {d2}, [\my, :64]
+        sub             \src,  \src,  #6
+        sub             \src,  \src,  \s_strd
+        sub             \src,  \src,  \s_strd, lsl #1
+        vmovl.s8        q0,  d0
+        vmovl.s8        q1,  d2
+        mov             \my, \h
+
+168:
+        add             \ds2, \dst, \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        vld1.16         {q11, q12}, [\src], \s_strd
+        vmull.s16       q2,  d22, d0[0]
+        vmull.s16       q3,  d23, d0[0]
+        vdup.32         q14, r12      // -(6-intermediate_bits)
+.irpc i, 1234567
+        vext.8          q10, q11, q12, #(2*\i)
+.if \i < 4
+        vmlal.s16       q2,  d20, d0[\i]
+        vmlal.s16       q3,  d21, d0[\i]
+.else
+        vmlal.s16       q2,  d20, d1[\i - 4]
+        vmlal.s16       q3,  d21, d1[\i - 4]
+.endif
+.endr
+        vrshl.s32       q2,  q2,  q14 // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q14 // -(6-intermediate_bits)
+        vmovn.i32       d8,  q2
+        vmovn.i32       d9,  q3
+
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q5,  q11
+        vmov            q6,  q12
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q7,  q11
+        vmov            q8,  q12
+        bl              L(\type\()_8tap_filter_8)
+        vmov            q9,  q11
+        vmov            q10, q12
+
+88:
+        bl              L(\type\()_8tap_filter_8)
+        vmull.s16       q2,  d8,  d2[0]
+        vmull.s16       q3,  d9,  d2[0]
+        vmull.s16       q13, d10, d2[0]
+        vmull.s16       q14, d11, d2[0]
+.ifc \type, put
+        vdup.32         q4,  r8      // -(6+intermediate_bits)
+.endif
+        vmlal.s16       q2,  d10, d2[1]
+        vmlal.s16       q3,  d11, d2[1]
+        vmlal.s16       q13, d12, d2[1]
+        vmlal.s16       q14, d13, d2[1]
+        vmlal.s16       q2,  d12, d2[2]
+        vmlal.s16       q3,  d13, d2[2]
+        vmlal.s16       q13, d14, d2[2]
+        vmlal.s16       q14, d15, d2[2]
+        vmlal.s16       q2,  d14, d2[3]
+        vmlal.s16       q3,  d15, d2[3]
+        vmlal.s16       q13, d16, d2[3]
+        vmlal.s16       q14, d17, d2[3]
+        vmlal.s16       q2,  d16, d3[0]
+        vmlal.s16       q3,  d17, d3[0]
+        vmlal.s16       q13, d18, d3[0]
+        vmlal.s16       q14, d19, d3[0]
+        vmlal.s16       q2,  d18, d3[1]
+        vmlal.s16       q3,  d19, d3[1]
+        vmlal.s16       q13, d20, d3[1]
+        vmlal.s16       q14, d21, d3[1]
+        vmlal.s16       q2,  d20, d3[2]
+        vmlal.s16       q3,  d21, d3[2]
+        vmlal.s16       q13, d22, d3[2]
+        vmlal.s16       q14, d23, d3[2]
+        vmlal.s16       q2,  d22, d3[3]
+        vmlal.s16       q3,  d23, d3[3]
+        vmlal.s16       q13, d24, d3[3]
+        vmlal.s16       q14, d25, d3[3]
+.ifc \type, put
+        vrshl.s32       q2,  q2,  q4 // -(6+intermediate_bits)
+        vrshl.s32       q3,  q3,  q4 // -(6+intermediate_bits)
+        vrshl.s32       q13, q13, q4 // -(6+intermediate_bits)
+        vrshl.s32       q14, q14, q4 // -(6+intermediate_bits)
+        vqmovun.s32     d4,  q2
+        vqmovun.s32     d5,  q3
+        vqmovun.s32     d6,  q13
+        vqmovun.s32     d7,  q14
+        vmin.u16        q2,  q2,  q15
+        vmin.u16        q3,  q3,  q15
+.else
+        vmov.i16        q5,  #PREP_BIAS
+        vrshrn.i32      d4,  q2,  #6
+        vrshrn.i32      d5,  q3,  #6
+        vrshrn.i32      d6,  q13, #6
+        vrshrn.i32      d7,  q14, #6
+        vsub.i16        q2,  q2,  q5 // PREP_BIAS
+        vsub.i16        q3,  q3,  q5 // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {q2}, [\dst, :128], \d_strd
+        vst1.16         {q3}, [\ds2, :128], \d_strd
+        ble             9f
+        vmov            q4,  q6
+        vmov            q5,  q7
+        vmov            q6,  q8
+        vmov            q7,  q9
+        vmov            q8,  q10
+        vmov            q9,  q11
+        vmov            q10, q12
+        b               88b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #3
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+        b               168b
+0:
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+L(\type\()_8tap_filter_8):
+        vld1.16         {q13, q14}, [\sr2], \s_strd
+        vmull.s16       q2,  d26, d0[0]
+        vmull.s16       q3,  d27, d0[0]
+.irpc i, 1234567
+        vext.8          q12, q13, q14, #(2*\i)
+.if \i < 4
+        vmlal.s16       q2,  d24, d0[\i]
+        vmlal.s16       q3,  d25, d0[\i]
+.else
+        vmlal.s16       q2,  d24, d1[\i - 4]
+        vmlal.s16       q3,  d25, d1[\i - 4]
+.endif
+.endr
+        vdup.32         q12, r12      // -(6-intermediate_bits)
+        vld1.16         {q13, q14}, [\src], \s_strd
+        vrshl.s32       q2,  q2,  q12 // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q12 // -(6-intermediate_bits)
+        vmovn.i32       d4,  q2
+        vmovn.i32       d5,  q3
+
+        vmull.s16       q3,  d26, d0[0]
+        vmull.s16       q11, d27, d0[0]
+.irpc i, 1234567
+        vext.8          q12, q13, q14, #(2*\i)
+.if \i < 4
+        vmlal.s16       q3,  d24, d0[\i]
+        vmlal.s16       q11, d25, d0[\i]
+.else
+        vmlal.s16       q3,  d24, d1[\i - 4]
+        vmlal.s16       q11, d25, d1[\i - 4]
+.endif
+.endr
+        vdup.32         q13, r12      // -(6-intermediate_bits)
+        vrshl.s32       q3,  q3,  q13 // -(6-intermediate_bits)
+        vrshl.s32       q11, q11, q13 // -(6-intermediate_bits)
+
+        vmovn.i32       d24, q3
+        vmovn.i32       d25, q11
+        vmov            q11, q2
+        bx              lr
+endfunc
+
+function \type\()_bilin_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        ldrd            r4,  r5,  [sp, #36]
+        ldrd            r6,  r7,  [sp, #44]
+.ifc \bdmax, r8
+        ldr             r8,  [sp, #52]
+.endif
+        vdup.16         q1,  \mx
+        vdup.16         q3,  \my
+        rsb             r9,  \mx, #16
+        rsb             r10, \my, #16
+        vdup.16         q0,  r9
+        vdup.16         q2,  r10
+.ifc \type, prep
+        lsl             \d_strd, \w, #1
+.endif
+        clz             \bdmax,   \bdmax       // bitdepth_max
+        clz             r9,  \w
+        sub             \bdmax,   \bdmax,  #18 // intermediate_bits = clz(bitdepth_max) - 18
+        cmp             \mx, #0
+        sub             r9,  r9,  #24
+        rsb             r11, \bdmax, #4        // 4 - intermediate_bits
+        add             r12, \bdmax, #4        // 4 + intermediate_bits
+        bne             L(\type\()_bilin_h)
+        cmp             \my, #0
+        bne             L(\type\()_bilin_v)
+        b               \type\()_neon
+
+L(\type\()_bilin_h):
+        cmp             \my, #0
+        bne             L(\type\()_bilin_hv)
+
+        adr             r10, L(\type\()_bilin_h_tbl)
+        vdup.16         q15, r11               // 4 - intermediate_bits
+        ldr             r9,  [r10, r9, lsl #2]
+        vneg.s16        q15, q15               // -(4-intermediate_bits)
+.ifc \type, put
+        vdup.16         q14, \bdmax            // intermediate_bits
+.else
+        vmov.i16        q14, #PREP_BIAS
+.endif
+        add             r10, r10, r9
+.ifc \type, put
+        vneg.s16        q14, q14               // -intermediate_bits
+.endif
+        bx              r10
+
+        .align 2
+L(\type\()_bilin_h_tbl):
+        .word 1280f - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_h_tbl) + CONFIG_THUMB
+
+20:     // 2xN h
+.ifc \type, put
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+2:
+        vld1.16         {d16}, [\src], \s_strd
+        vld1.16         {d18}, [\sr2], \s_strd
+        vext.8          d17, d16, d16, #2
+        vext.8          d19, d18, d18, #2
+        vtrn.32         d16, d18
+        vtrn.32         d17, d19
+        subs            \h,  \h,  #2
+        vmul.i16        d16, d16, d0
+        vmla.i16        d16, d17, d2
+        vrshl.u16       d16, d16, d30
+        vrshl.u16       d16, d16, d28
+        vst1.32         {d16[0]}, [\dst, :32], \d_strd
+        vst1.32         {d16[1]}, [\ds2, :32], \d_strd
+        bgt             2b
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN h
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+4:
+        vld1.16         {q8},  [\src], \s_strd
+        vld1.16         {q10}, [\sr2], \s_strd
+        vext.8          q9,  q8,  q8,  #2
+        vext.8          q11, q10, q10, #2
+        vmov            d17, d20
+        vmov            d19, d22
+        subs            \h,  \h,  #2
+        vmul.i16        q8,  q8,  q0
+        vmla.i16        q8,  q9,  q1
+        vrshl.u16       q8,  q8,  q15
+.ifc \type, put
+        vrshl.u16       q8,  q8,  q14
+.else
+        vsub.i16        q8,  q8,  q14
+.endif
+        vst1.16         {d16}, [\dst, :64], \d_strd
+        vst1.16         {d17}, [\ds2, :64], \d_strd
+        bgt             4b
+        pop             {r4-r11,pc}
+
+80:     // 8xN h
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+8:
+        vld1.16         {d16, d17, d18}, [\src], \s_strd
+        vld1.16         {d20, d21, d22}, [\sr2], \s_strd
+        vext.8          q9,  q8,  q9,  #2
+        vext.8          q11, q10, q11, #2
+        subs            \h,  \h,  #2
+        vmul.i16        q8,  q8,  q0
+        vmla.i16        q8,  q9,  q1
+        vmul.i16        q10, q10, q0
+        vmla.i16        q10, q11, q1
+        vrshl.u16       q8,  q8,  q15
+        vrshl.u16       q10, q10, q15
+.ifc \type, put
+        vrshl.u16       q8,  q8,  q14
+        vrshl.u16       q10, q10, q14
+.else
+        vsub.i16        q8,  q8,  q14
+        vsub.i16        q10, q10, q14
+.endif
+        vst1.16         {q8},  [\dst, :128], \d_strd
+        vst1.16         {q10}, [\ds2, :128], \d_strd
+        bgt             8b
+        pop             {r4-r11,pc}
+160:
+320:
+640:
+1280:   // 16xN, 32xN, ... h
+        vpush           {q4-q7}
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+
+        sub             \s_strd,  \s_strd,  \w, lsl #1
+        sub             \s_strd,  \s_strd,  #16
+.ifc \type, put
+        lsl             \d_strd,  \d_strd,  #1
+        sub             \d_strd,  \d_strd,  \w, lsl #1
+.endif
+161:
+        vld1.16         {q4}, [\src]!
+        vld1.16         {q9}, [\sr2]!
+        mov             \mx, \w
+
+16:
+        vld1.16         {q5,  q6},  [\src]!
+        vld1.16         {q10, q11}, [\sr2]!
+        vext.8          q7,  q4,  q5,  #2
+        vext.8          q8,  q5,  q6,  #2
+        vext.8          q12, q9,  q10, #2
+        vext.8          q13, q10, q11, #2
+        vmul.i16        q4,  q4,  q0
+        vmla.i16        q4,  q7,  q1
+        vmul.i16        q5,  q5,  q0
+        vmla.i16        q5,  q8,  q1
+        vmul.i16        q9,  q9,  q0
+        vmla.i16        q9,  q12, q1
+        vmul.i16        q10, q10, q0
+        vmla.i16        q10, q13, q1
+        vrshl.u16       q4,  q4,  q15
+        vrshl.u16       q5,  q5,  q15
+        vrshl.u16       q9,  q9,  q15
+        vrshl.u16       q10, q10, q15
+        subs            \mx, \mx, #16
+.ifc \type, put
+        vrshl.u16       q4,  q4,  q14
+        vrshl.u16       q5,  q5,  q14
+        vrshl.u16       q9,  q9,  q14
+        vrshl.u16       q10, q10, q14
+.else
+        vsub.i16        q4,  q4,  q14
+        vsub.i16        q5,  q5,  q14
+        vsub.i16        q9,  q9,  q14
+        vsub.i16        q10, q10, q14
+.endif
+        vst1.16         {q4, q5},  [\dst, :128]!
+        vst1.16         {q9, q10}, [\ds2, :128]!
+        ble             9f
+
+        vmov            q4,  q6
+        vmov            q9,  q11
+        b               16b
+
+9:
+        add             \dst,  \dst,  \d_strd
+        add             \ds2,  \ds2,  \d_strd
+        add             \src,  \src,  \s_strd
+        add             \sr2,  \sr2,  \s_strd
+
+        subs            \h,  \h,  #2
+        bgt             161b
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+
+
+L(\type\()_bilin_v):
+        cmp             \h,  #4
+        adr             r10, L(\type\()_bilin_v_tbl)
+.ifc \type, prep
+        vdup.16         q15, r11      // 4 - intermediate_bits
+.endif
+        ldr             r9,  [r10, r9, lsl #2]
+.ifc \type, prep
+        vmov.i16        q14, #PREP_BIAS
+        vneg.s16        q15, q15      // -(4-intermediate_bits)
+.endif
+        add             r10, r10, r9
+        bx              r10
+
+        .align 2
+L(\type\()_bilin_v_tbl):
+        .word 1280f - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_v_tbl) + CONFIG_THUMB
+
+20:     // 2xN v
+.ifc \type, put
+        cmp             \h,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+
+        // 2x2 v
+        vld1.32         {d16[]}, [\src], \s_strd
+        bgt             24f
+22:
+        vld1.32         {d17[]}, [\sr2], \s_strd
+        vld1.32         {d18[]}, [\src], \s_strd
+        vext.8          d16, d16, d17, #4
+        vext.8          d17, d17, d18, #4
+        vmul.i16        d16, d16, d4
+        vmla.i16        d16, d17, d6
+        vrshr.u16       d16, d16, #4
+        vst1.32         {d16[0]}, [\dst, :32]
+        vst1.32         {d16[1]}, [\ds2, :32]
+        pop             {r4-r11,pc}
+24:     // 2x4, 2x6, 2x8, ... v
+        vld1.32         {d17[]}, [\sr2], \s_strd
+        vld1.32         {d18[]}, [\src], \s_strd
+        vld1.32         {d19[]}, [\sr2], \s_strd
+        vld1.32         {d20[]}, [\src], \s_strd
+        subs            \h,  \h,  #4
+        vext.8          d16, d16, d17, #4
+        vext.8          d17, d17, d18, #4
+        vext.8          d18, d18, d19, #4
+        vext.8          d19, d19, d20, #4
+        vswp            d17, d18
+        vmul.i16        q8,  q8,  q2
+        vmla.i16        q8,  q9,  q3
+        cmp             \h,  #2
+        vrshr.u16       q8,  q8,  #4
+        vst1.32         {d16[0]}, [\dst, :32], \d_strd
+        vst1.32         {d16[1]}, [\ds2, :32], \d_strd
+        vst1.32         {d17[0]}, [\dst, :32], \d_strd
+        vst1.32         {d17[1]}, [\ds2, :32], \d_strd
+        blt             0f
+        vmov            d16, d20
+        beq             22b
+        b               24b
+0:
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN v
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        vld1.16         {d16}, [\src], \s_strd
+4:
+        vld1.16         {d17}, [\sr2], \s_strd
+        vld1.16         {d19}, [\src], \s_strd
+        vmov            d18, d17
+        vmul.i16        q8,  q8,  q2
+        vmla.i16        q8,  q9,  q3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vrshr.u16       q8,  q8,  #4
+.else
+        vrshl.u16       q8,  q8,  q15
+        vsub.i16        q8,  q8,  q14
+.endif
+        vst1.16         {d16}, [\dst, :64], \d_strd
+        vst1.16         {d17}, [\ds2, :64], \d_strd
+        ble             0f
+        vmov            d16, d19
+        b               4b
+0:
+        pop             {r4-r11,pc}
+
+80:     // 8xN v
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        vld1.16         {q8},  [\src], \s_strd
+8:
+        vld1.16         {q9},  [\sr2], \s_strd
+        vld1.16         {q10}, [\src], \s_strd
+        vmul.i16        q8,  q8,  q2
+        vmla.i16        q8,  q9,  q3
+        vmul.i16        q9,  q9,  q2
+        vmla.i16        q9,  q10, q3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vrshr.u16       q8,  q8,  #4
+        vrshr.u16       q9,  q9,  #4
+.else
+        vrshl.u16       q8,  q8,  q15
+        vrshl.u16       q9,  q9,  q15
+        vsub.i16        q8,  q8,  q14
+        vsub.i16        q9,  q9,  q14
+.endif
+        vst1.16         {q8}, [\dst, :128], \d_strd
+        vst1.16         {q9}, [\ds2, :128], \d_strd
+        ble             0f
+        vmov            q8,  q10
+        b               8b
+0:
+        pop             {r4-r11,pc}
+
+160:    // 16xN, 32xN, ...
+320:
+640:
+1280:
+        mov             \my, \h
+1:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.16         {q8,  q9},  [\src], \s_strd
+2:
+        vld1.16         {q10, q11}, [\sr2], \s_strd
+        vld1.16         {q12, q13}, [\src], \s_strd
+        vmul.i16        q8,  q8,  q2
+        vmla.i16        q8,  q10, q3
+        vmul.i16        q9,  q9,  q2
+        vmla.i16        q9,  q11, q3
+        vmul.i16        q10, q10, q2
+        vmla.i16        q10, q12, q3
+        vmul.i16        q11, q11, q2
+        vmla.i16        q11, q13, q3
+        subs            \h,  \h,  #2
+.ifc \type, put
+        vrshr.u16       q8,  q8,  #4
+        vrshr.u16       q9,  q9,  #4
+        vrshr.u16       q10, q10, #4
+        vrshr.u16       q11, q11, #4
+.else
+        vrshl.u16       q8,  q8,  q15
+        vrshl.u16       q9,  q9,  q15
+        vrshl.u16       q10, q10, q15
+        vrshl.u16       q11, q11, q15
+        vsub.i16        q8,  q8,  q14
+        vsub.i16        q9,  q9,  q14
+        vsub.i16        q10, q10, q14
+        vsub.i16        q11, q11, q14
+.endif
+        vst1.16         {q8,  q9},  [\dst, :128], \d_strd
+        vst1.16         {q10, q11}, [\ds2, :128], \d_strd
+        ble             9f
+        vmov            q8,  q12
+        vmov            q9,  q13
+        b               2b
+9:
+        subs            \w,  \w,  #16
+        ble             0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        mls             \src, \s_strd, \my, \src
+        mls             \dst, \d_strd, \my, \dst
+        sub             \src, \src, \s_strd, lsl #1
+        mov             \h,  \my
+        add             \src, \src, #32
+        add             \dst, \dst, #32
+        b               1b
+0:
+        pop             {r4-r11,pc}
+
+L(\type\()_bilin_hv):
+        adr             r10, L(\type\()_bilin_hv_tbl)
+        vdup.16         q15, r11          // 4 - intermediate_bits
+        ldr             r9,  [r10, r9, lsl #2]
+        vneg.s16        q15, q15          // -(4-intermediate_bits)
+.ifc \type, put
+        vdup.32         q14, r12          // 4 + intermediate_bits
+.else
+        vmov.i16        q14, #PREP_BIAS
+.endif
+        add             r10, r10, r9
+.ifc \type, put
+        vneg.s32        q14, q14          // -(4+intermediate_bits)
+.endif
+        bx              r10
+
+        .align 2
+L(\type\()_bilin_hv_tbl):
+        .word 1280f - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 640f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 320f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 160f  - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 80f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 40f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+        .word 20f   - L(\type\()_bilin_hv_tbl) + CONFIG_THUMB
+
+20:     // 2xN hv
+.ifc \type, put
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.16         {d20}, [\src], \s_strd
+        vext.8          d21, d20, d20, #2
+        vmul.i16        d16, d20, d0
+        vmla.i16        d16, d21, d2
+        vrshl.u16       d16, d16, d30
+        vext.8          d16, d16, d16, #4
+
+2:
+        vld1.16         {d20}, [\sr2], \s_strd
+        vld1.16         {d22}, [\src], \s_strd
+        vext.8          d21, d20, d20, #2
+        vext.8          d23, d22, d22, #2
+        vtrn.32         d20, d22
+        vtrn.32         d21, d23
+        vmul.i16        d18, d20, d0
+        vmla.i16        d18, d21, d2
+        vrshl.u16       d18, d18, d30
+
+        vext.8          d16, d16, d18, #4
+
+        vmull.u16       q8,  d16, d4
+        vmlal.u16       q8,  d18, d6
+        vrshl.u32       q8,  q8,  q14
+        vmovn.i32       d16, q8
+        subs            \h,  \h,  #2
+        vst1.32         {d16[0]}, [\dst, :32], \d_strd
+        vst1.32         {d16[1]}, [\ds2, :32], \d_strd
+        ble             0f
+        vmov            d16, d18
+        b               2b
+0:
+        pop             {r4-r11,pc}
+.endif
+
+40:     // 4xN hv
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.16         {q10}, [\src], \s_strd
+        vext.8          d21, d20, d21, #2
+        vmul.i16        d16, d20, d0
+        vmla.i16        d16, d21, d2
+        vrshl.u16       d16, d16, d30
+
+4:
+        vld1.16         {q10}, [\sr2], \s_strd
+        vld1.16         {q11}, [\src], \s_strd
+        vext.8          d21, d20, d21, #2
+        vext.8          d23, d22, d23, #2
+        vswp            d21, d22
+        vmul.i16        q9,  q10, q0
+        vmla.i16        q9,  q11, q1
+        vrshl.u16       q9,  q9,  q15
+
+        vmull.u16       q10, d16, d4
+        vmlal.u16       q10, d18, d6
+        vmull.u16       q11, d18, d4
+        vmlal.u16       q11, d19, d6
+.ifc \type, put
+        vrshl.u32       q10, q10, q14
+        vrshl.u32       q11, q11, q14
+        vmovn.i32       d20, q10
+        vmovn.i32       d21, q11
+.else
+        vrshrn.i32      d20, q10, #4
+        vrshrn.i32      d21, q11, #4
+        vsub.i16        q10, q10, q14
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {d20}, [\dst, :64], \d_strd
+        vst1.16         {d21}, [\ds2, :64], \d_strd
+        ble             0f
+        vmov            d16, d19
+        b               4b
+0:
+        pop             {r4-r11,pc}
+
+80:     // 8xN, 16xN, ... hv
+160:
+320:
+640:
+1280:
+        mov             \my, \h
+
+1:
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        vld1.16         {d20, d21, d22}, [\src], \s_strd
+        vext.8          q11, q10, q11, #2
+        vmul.i16        q8,  q10, q0
+        vmla.i16        q8,  q11, q1
+        vrshl.u16       q8,  q8,  q15
+
+2:
+        vld1.16         {d20, d21, d22}, [\sr2], \s_strd
+        vld1.16         {d24, d25, d26}, [\src], \s_strd
+        vext.8          q11, q10, q11, #2
+        vext.8          q13, q12, q13, #2
+        vmul.i16        q9,  q10, q0
+        vmla.i16        q9,  q11, q1
+        vmul.i16        q10, q12, q0
+        vmla.i16        q10, q13, q1
+        vrshl.u16       q9,  q9,  q15
+        vrshl.u16       q10, q10, q15
+
+        vmull.u16       q11, d16, d4
+        vmlal.u16       q11, d18, d6
+        vmull.u16       q12, d17, d4
+        vmlal.u16       q12, d19, d6
+        vmull.u16       q8,  d18, d4
+        vmlal.u16       q8,  d20, d6
+        vmull.u16       q9,  d19, d4
+        vmlal.u16       q9,  d21, d6
+.ifc \type, put
+        vrshl.u32       q11, q11, q14
+        vrshl.u32       q12, q12, q14
+        vrshl.u32       q8,  q8,  q14
+        vrshl.u32       q9,  q9,  q14
+        vmovn.i32       d22, q11
+        vmovn.i32       d23, q12
+        vmovn.i32       d16, q8
+        vmovn.i32       d17, q9
+.else
+        vrshrn.i32      d22, q11, #4
+        vrshrn.i32      d23, q12, #4
+        vrshrn.i32      d16, q8,  #4
+        vrshrn.i32      d17, q9,  #4
+        vsub.i16        q11, q11, q14
+        vsub.i16        q8,  q8,  q14
+.endif
+        subs            \h,  \h,  #2
+        vst1.16         {q11}, [\dst, :128], \d_strd
+        vst1.16         {q8},  [\ds2, :128], \d_strd
+        ble             9f
+        vmov            q8,  q10
+        b               2b
+9:
+        subs            \w,  \w,  #8
+        ble             0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        mls             \src,  \s_strd,  \my,  \src
+        mls             \dst,  \d_strd,  \my,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #1
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+        b               1b
+0:
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+filter_fn put,  r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
+filter_fn prep, r0, r8, r1, r2, r3, r4, r5, r6, r7, r9, r10
+
+.macro load_filter_ptr src
+        asr             r12, \src, #10
+        add             r12, r11, r12, lsl #3
+.endm
+
+.macro load_filter_coef dst, src, inc
+        add             \src, \src, \inc
+        vld1.8          {\dst}, [r12, :64]
+.endm
+
+.macro load_filter_row dst, src, inc
+        load_filter_ptr \src
+        load_filter_coef \dst, \src, \inc
+.endm
+
+function warp_filter_horz_neon
+        load_filter_ptr r5                  // filter 0
+        vld1.16         {q6,q7}, [r2], r3
+
+        load_filter_coef d0, r5,  r7        // filter 0
+        load_filter_row d2,  r5,  r7        // filter 1
+        vmovl.s8        q0,  d0             // filter 0
+        vext.8          q3,  q6,  q7,  #2*1 // filter 1 pixels
+        vmovl.s8        q1,  d2             // filter 1
+
+        vmull.s16       q4,  d12, d0        // filter 0 output (0-3)
+        vmull.s16       q5,  d13, d1        // filter 0 output (4-7)
+
+        load_filter_ptr r5                  // filter 2
+
+        vmull.s16       q2,  d6,  d2        // filter 1 output (0-3)
+        vmull.s16       q3,  d7,  d3        // filter 1 output (4-7)
+
+        load_filter_coef d0, r5,  r7        // filter 2
+
+        vpadd.i32       d8,  d8,  d9        // half pixel 0 (2x32)
+        vpadd.i32       d9,  d10, d11       // half pixel 0 (2x32)
+
+        load_filter_ptr r5                  // filter 3
+
+        vpadd.i32       d4,  d4,  d5        // half pixel 1 (2x32)
+        vpadd.i32       d5,  d6,  d7        // half pixel 1 (2x32)
+
+        vmovl.s8        q0,  d0             // filter 2
+        vext.8          q3,  q6,  q7,  #2*2 // filter 2 pixels
+
+        vpadd.i32       d8,  d8,  d9        // pixel 0 (2x32)
+        vpadd.i32       d9,  d4,  d5        // pixel 1 (2x32)
+
+        load_filter_coef d2, r5,  r7        // filter 3
+
+        vmull.s16       q2,  d6,  d0        // filter 2 output (0-3)
+        vmull.s16       q3,  d7,  d1        // filter 2 output (4-7)
+
+        load_filter_ptr r5                  // filter 4
+
+        vpadd.i32       d8,  d8,  d9        // pixel 0,1
+
+        vpadd.i32       d9,  d4,  d5        // half pixel 2 (2x32)
+        vpadd.i32       d10, d6,  d7        // half pixel 2 (2x32)
+
+        vmovl.s8        q1,  d2             // filter 3
+        vext.8          q3,  q6,  q7,  #2*3 // filter 3 pixels
+
+        load_filter_coef d0, r5,  r7        // filter 4
+
+        vpadd.i32       d9,  d9,  d10       // pixel 2 (2x32)
+
+        vmull.s16       q2,  d6,  d2        // filter 3 output (0-3)
+        vmull.s16       q3,  d7,  d3        // filter 3 output (4-7)
+
+        vmovl.s8        q0,  d0             // filter 4
+        load_filter_ptr r5                  // filter 5
+
+        vpadd.i32       d10, d4,  d5        // half pixel 3 (2x32)
+        vpadd.i32       d11, d6,  d7        // half pixel 3 (2x32)
+
+        vext.8          q3,  q6,  q7,  #2*4 // filter 4 pixels
+        load_filter_coef d2, r5,  r7        // filter 5
+
+        vpadd.i32       d10, d10, d11       // pixel 3 (2x32)
+
+        vpadd.i32       d9,  d9,  d10       // pixel 2,3
+
+        vmull.s16       q2,  d6,  d0        // filter 4 output (0-3)
+        vmull.s16       q3,  d7,  d1        // filter 4 output (4-7)
+
+        vmovl.s8        q1,  d2             // filter 5
+        load_filter_ptr r5                  // filter 6
+
+        vpadd.i32       d10, d4,  d5        // half pixel 4 (2x32)
+        vpadd.i32       d11, d6,  d7        // half pixel 4 (2x32)
+
+        vext.8          q3,  q6,  q7,  #2*5 // filter 5 pixels
+        load_filter_coef d0, r5,  r7        // filter 6
+
+        vpadd.i32       d10, d10, d11       // pixel 4 (2x32)
+
+        vmull.s16       q2,  d6,  d2        // filter 5 output (0-3)
+        vmull.s16       q3,  d7,  d3        // filter 5 output (4-7)
+
+        vmovl.s8        q0,  d0             // filter 6
+        load_filter_ptr r5                  // filter 7
+
+        vpadd.i32       d4,  d4,  d5        // half pixel 5 (2x32)
+        vpadd.i32       d5,  d6,  d7        // half pixel 5 (2x32)
+
+        vext.8          q3,  q6,  q7,  #2*6 // filter 6 pixels
+        load_filter_coef d2, r5,  r7        // filter 7
+
+        vpadd.i32       d11, d4,  d5        // pixel 5 (2x32)
+
+        vmull.s16       q2,  d6,  d0        // filter 6 output (0-3)
+        vmull.s16       q3,  d7,  d1        // filter 6 output (4-7)
+
+        vmovl.s8        q1,  d2             // filter 7
+
+        vpadd.i32       d10, d10, d11       // pixel 4,5
+
+        vpadd.i32       d4,  d4,  d5        // half pixel 6 (2x32)
+        vpadd.i32       d5,  d6,  d7        // half pixel 6 (2x32)
+
+        vext.8          q3,  q6,  q7,  #2*7 // filter 7 pixels
+
+        vpadd.i32       d11, d4,  d5        // pixel 6 (2x32)
+
+        vmull.s16       q2,  d6,  d2        // filter 7 output (0-3)
+        vmull.s16       q3,  d7,  d3        // filter 7 output (4-7)
+
+        vld1.32         {d14[],d15[]}, [sp] // -(7 - intermediate_bits)
+
+        vpadd.i32       d4,  d4,  d5        // half pixel 7 (2x32)
+        vpadd.i32       d5,  d6,  d7        // half pixel 7 (2x32)
+
+        sub             r5,  r5,  r7, lsl #3
+
+        vpadd.i32       d4,  d4,  d5        // pixel 7 (2x32)
+
+        add             r5,  r5,  r8
+
+        vpadd.i32       d11, d11, d4        // pixel 6,7
+
+        vrshl.s32       q4,  q4,  q7        // -(7 - intermediate_bits)
+        vrshl.s32       q5,  q5,  q7        // -(7 - intermediate_bits)
+
+        bx              lr
+endfunc
+
+// void dav1d_warp_affine_8x8_16bpc_neon(
+//         pixel *dst, const ptrdiff_t dst_stride,
+//         const pixel *src, const ptrdiff_t src_stride,
+//         const int16_t *const abcd, int mx, int my,
+//         const int bitdepth_max)
+.macro warp t
+function warp_affine_8x8\t\()_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        vpush           {q4-q7}
+        ldrd            r4,  r5,  [sp, #100]
+        ldrd            r6,  r7,  [sp, #108]
+        sub             sp,  sp,  #8
+
+        clz             r7,  r7
+                                      // intermediate_bits = clz(bitdepth_max) - 18
+.ifb \t
+        sub             r8,  r7,  #11 // 7 + intermediate_bits = clz(bitdepth_max) - 18 + 7
+.endif
+        sub             r7,  r7,  #25 // -(7 - intermediate_bits)
+.ifb \t
+        neg             r8,  r8       // -(7 + intermediate_bits)
+.endif
+        str             r7,  [sp]     // spill -(7 - intermediate_bits) on stack
+.ifb \t
+        str             r8,  [sp, #4] // spill -(7 + intermediate_bits) on stack
+.endif
+
+        ldrd            r8,  r9,  [r4]
+        sxth            r7,  r8
+        asr             r8,  r8,  #16
+        asr             r4,  r9,  #16
+        sxth            r9,  r9
+        mov             r10, #8
+        sub             r2,  r2,  r3, lsl #1
+        sub             r2,  r2,  r3
+        sub             r2,  r2,  #6
+        movrel          r11, X(mc_warp_filter), 64*8
+.ifnb \t
+        lsl             r1,  r1,  #1
+.endif
+        add             r5,  r5,  #512
+        add             r6,  r6,  #512
+
+        bl              warp_filter_horz_neon
+        vmovn.i32       d16, q4
+        vmovn.i32       d17, q5
+        bl              warp_filter_horz_neon
+        vmovn.i32       d18, q4
+        vmovn.i32       d19, q5
+        bl              warp_filter_horz_neon
+        vmovn.i32       d20, q4
+        vmovn.i32       d21, q5
+        bl              warp_filter_horz_neon
+        vmovn.i32       d22, q4
+        vmovn.i32       d23, q5
+        bl              warp_filter_horz_neon
+        vmovn.i32       d24, q4
+        vmovn.i32       d25, q5
+        bl              warp_filter_horz_neon
+        vmovn.i32       d26, q4
+        vmovn.i32       d27, q5
+        bl              warp_filter_horz_neon
+        vmovn.i32       d28, q4
+        vmovn.i32       d29, q5
+
+1:
+        bl              warp_filter_horz_neon
+        vmovn.i32       d30, q4
+        vmovn.i32       d31, q5
+
+        load_filter_row d8,  r6,  r9
+        load_filter_row d9,  r6,  r9
+        load_filter_row d10, r6,  r9
+        load_filter_row d11, r6,  r9
+        load_filter_row d12, r6,  r9
+        load_filter_row d13, r6,  r9
+        load_filter_row d14, r6,  r9
+        load_filter_row d15, r6,  r9
+        transpose_8x8b  q4,  q5,  q6,  q7,  d8,  d9,  d10, d11, d12, d13, d14, d15
+        vmovl.s8        q1,  d8
+        vmovl.s8        q2,  d9
+        vmovl.s8        q3,  d10
+        vmovl.s8        q4,  d11
+        vmovl.s8        q5,  d12
+        vmovl.s8        q6,  d13
+
+        sub             r6,  r6,  r9, lsl #3
+
+        // This ordering of vmull/vmlal is highly beneficial for
+        // Cortex A8/A9/A53 here, but harmful for Cortex A7.
+        vmull.s16       q0,  d16, d2
+        vmlal.s16       q0,  d18, d4
+        vmlal.s16       q0,  d20, d6
+        vmlal.s16       q0,  d22, d8
+        vmlal.s16       q0,  d24, d10
+        vmlal.s16       q0,  d26, d12
+        vmull.s16       q1,  d17, d3
+        vmlal.s16       q1,  d19, d5
+        vmlal.s16       q1,  d21, d7
+        vmlal.s16       q1,  d23, d9
+        vmlal.s16       q1,  d25, d11
+        vmlal.s16       q1,  d27, d13
+
+        vmovl.s8        q2,  d14
+        vmovl.s8        q3,  d15
+
+        vmlal.s16       q0,  d28, d4
+        vmlal.s16       q0,  d30, d6
+        vmlal.s16       q1,  d29, d5
+        vmlal.s16       q1,  d31, d7
+
+.ifb \t
+        ldr             lr,  [sp, #4]   // -(7 + intermediate_bits)
+        ldr             r12, [sp, #120] // bitdepth_max
+        vdup.32         q2,  lr         // -(7 + intermediate_bits)
+        vdup.16         q3,  r12        // bitdepth_max
+.endif
+
+        vmov            q8,  q9
+        vmov            q9,  q10
+.ifb \t
+        vrshl.s32       q0,  q0,  q2    // -(7 + intermediate_bits)
+        vrshl.s32       q1,  q1,  q2    // -(7 + intermediate_bits)
+.else
+        vrshrn.s32      d0,  q0,  #7
+        vrshrn.s32      d1,  q1,  #7
+        vmov.i16        q3,  #PREP_BIAS
+.endif
+        vmov            q10, q11
+.ifb \t
+        vqmovun.s32     d0,  q0
+        vqmovun.s32     d1,  q1
+.else
+        vsub.i16        q0,  q0,  q3    // PREP_BIAS
+.endif
+        vmov            q11, q12
+        vmov            q12, q13
+.ifb \t
+        vmin.u16        q0,  q0,  q3    // bitdepth_max
+.endif
+        vmov            q13, q14
+        vmov            q14, q15
+        subs            r10, r10, #1
+        vst1.16         {q0}, [r0, :128], r1
+
+        add             r6,  r6,  r4
+        bgt             1b
+
+        add             sp,  sp,  #8
+        vpop            {q4-q7}
+        pop             {r4-r11,pc}
+endfunc
+.endm
+
+warp
+warp t
+
+// void dav1d_emu_edge_16bpc_neon(
+//         const intptr_t bw, const intptr_t bh,
+//         const intptr_t iw, const intptr_t ih,
+//         const intptr_t x, const intptr_t y,
+//         pixel *dst, const ptrdiff_t dst_stride,
+//         const pixel *ref, const ptrdiff_t ref_stride)
+function emu_edge_16bpc_neon, export=1
+        push            {r4-r11,lr}
+        ldrd            r4,  r5,  [sp, #36]
+        ldrd            r6,  r7,  [sp, #44]
+        ldrd            r8,  r9,  [sp, #52]
+
+        // ref += iclip(y, 0, ih - 1) * PXSTRIDE(ref_stride)
+        // ref += iclip(x, 0, iw - 1)
+        sub             r12, r3,  #1           // ih - 1
+        cmp             r5,  r3
+        sub             lr,  r2,  #1           // iw - 1
+        it              lt
+        movlt           r12, r5                // min(y, ih - 1)
+        cmp             r4,  r2
+        bic             r12, r12, r12, asr #31 // max(min(y, ih - 1), 0)
+        it              lt
+        movlt           lr,  r4                // min(x, iw - 1)
+        bic             lr,  lr,  lr,  asr #31 // max(min(x, iw - 1), 0)
+        mla             r8,  r12, r9,  r8      // ref += iclip() * stride
+        add             r8,  r8,  lr,  lsl #1  // ref += iclip()
+
+        // bottom_ext = iclip(y + bh - ih, 0, bh - 1)
+        // top_ext = iclip(-y, 0, bh - 1)
+        add             r10, r5,  r1           // y + bh
+        neg             r5,  r5                // -y
+        sub             r10, r10, r3           // y + bh - ih
+        sub             r12, r1,  #1           // bh - 1
+        cmp             r10, r1
+        bic             r5,  r5,  r5,  asr #31 // max(-y, 0)
+        it              ge
+        movge           r10, r12               // min(y + bh - ih, bh-1)
+        cmp             r5,  r1
+        bic             r10, r10, r10, asr #31 // max(min(y + bh - ih, bh-1), 0)
+        it              ge
+        movge           r5,  r12               // min(max(-y, 0), bh-1)
+
+        // right_ext = iclip(x + bw - iw, 0, bw - 1)
+        // left_ext = iclip(-x, 0, bw - 1)
+        add             r11, r4,  r0           // x + bw
+        neg             r4,  r4                // -x
+        sub             r11, r11, r2           // x + bw - iw
+        sub             lr,  r0,  #1           // bw - 1
+        cmp             r11, r0
+        bic             r4,  r4,  r4,  asr #31 // max(-x, 0)
+        it              ge
+        movge           r11, lr                // min(x + bw - iw, bw-1)
+        cmp             r4,  r0
+        bic             r11, r11, r11, asr #31 // max(min(x + bw - iw, bw-1), 0)
+        it              ge
+        movge           r4,  lr                // min(max(-x, 0), bw - 1)
+
+        // center_h = bh - top_ext - bottom_ext
+        // dst += top_ext * PXSTRIDE(dst_stride)
+        // center_w = bw - left_ext - right_ext
+        sub             r1,  r1,  r5           // bh - top_ext
+        mla             r6,  r5,  r7,  r6
+        sub             r2,  r0,  r4           // bw - left_ext
+        sub             r1,  r1,  r10          // center_h = bh - top_ext - bottom_ext
+        sub             r2,  r2,  r11          // center_w = bw - left_ext - right_ext
+
+        mov             r0,  r6                // backup of dst
+
+.macro v_loop need_left, need_right
+0:
+.if \need_left
+        vld1.16         {d0[], d1[]}, [r8]
+        mov             r12, r6                // out = dst
+        mov             r3,  r4
+        vmov            q1,  q0
+1:
+        subs            r3,  r3,  #16
+        vst1.16         {q0, q1}, [r12, :128]!
+        bgt             1b
+.endif
+        mov             lr,  r8
+        add             r12, r6,  r4,  lsl #1  // out = dst + left_ext
+        mov             r3,  r2
+1:
+        vld1.16         {q0, q1}, [lr]!
+        subs            r3,  r3,  #32
+        vld1.16         {q2, q3}, [lr]!
+.if \need_left
+        vst1.16         {q0, q1}, [r12]!
+        vst1.16         {q2, q3}, [r12]!
+.else
+        vst1.16         {q0, q1}, [r12, :128]!
+        vst1.16         {q2, q3}, [r12, :128]!
+.endif
+        bgt             1b
+.if \need_right
+        add             r3,  r8,  r2,  lsl #1  // in + center_w
+        sub             r3,  r3,  #2           // in + center_w - 1
+        add             r12, r6,  r4,  lsl #1  // dst + left_ext
+        vld1.16         {d0[], d1[]}, [r3]
+        add             r12, r12, r2,  lsl #1  // out = dst + left_ext + center_w
+        mov             r3,  r11
+        vmov            q1,  q0
+1:
+        subs            r3,  r3,  #16
+        vst1.16         {q0, q1}, [r12]!
+        bgt             1b
+.endif
+
+        subs            r1,  r1,  #1           // center_h--
+        add             r6,  r6,  r7
+        add             r8,  r8,  r9
+        bgt             0b
+.endm
+
+        cmp             r4,  #0
+        beq             2f
+        // need_left
+        cmp             r11, #0
+        beq             3f
+        // need_left + need_right
+        v_loop          1,   1
+        b               5f
+
+2:
+        // !need_left
+        cmp             r11, #0
+        beq             4f
+        // !need_left + need_right
+        v_loop          0,   1
+        b               5f
+
+3:
+        // need_left + !need_right
+        v_loop          1,   0
+        b               5f
+
+4:
+        // !need_left + !need_right
+        v_loop          0,   0
+
+5:
+        cmp             r10, #0
+        // Storing the original dst in r0 overwrote bw, recalculate it here
+        add             r2,  r2,  r4           // center_w + left_ext
+        add             r2,  r2,  r11          // bw = center_w + left_ext + right_ext
+
+        beq             3f
+        // need_bottom
+        sub             r8,  r6,  r7           // ref = dst - stride
+        mov             r4,  r2
+        sub             r12, r7,  #32
+1:
+        vld1.16         {q0, q1}, [r8, :128]!
+        mov             r3,  r10
+        vld1.16         {q2, q3}, [r8, :128]!
+2:
+        vst1.16         {q0, q1}, [r6, :128]!
+        subs            r3,  r3,  #1
+        vst1.16         {q2, q3}, [r6, :128], r12
+        bgt             2b
+        mls             r6,  r7,  r10, r6      // dst -= bottom_ext * stride
+        subs            r4,  r4,  #32          // bw -= 32
+        add             r6,  r6,  #64          // dst += 32
+        bgt             1b
+
+3:
+        cmp             r5,  #0
+        beq             3f
+        // need_top
+        mls             r6,  r7,  r5,  r0      // dst = stored_dst - top_ext * stride
+        sub             r12, r7,  #32
+1:
+        vld1.16         {q0, q1}, [r0, :128]!
+        mov             r3,  r5
+        vld1.16         {q2, q3}, [r0, :128]!
+2:
+        vst1.16         {q0, q1}, [r6, :128]!
+        subs            r3,  r3,  #1
+        vst1.16         {q2, q3}, [r6, :128], r12
+        bgt             2b
+        mls             r6,  r7,  r5,  r6      // dst -= top_ext * stride
+        subs            r2,  r2,  #32          // bw -= 32
+        add             r6,  r6,  #64          // dst += 32
+        bgt             1b
+
+3:
+        pop             {r4-r11,pc}
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/msac.S b/media/libdav1d/src/src/arm/32/msac.S
new file mode 100644
index 0000000000..b16957fb7e
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/msac.S
@@ -0,0 +1,588 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+#define BUF_POS 0
+#define BUF_END 4
+#define DIF 8
+#define RNG 12
+#define CNT 16
+#define ALLOW_UPDATE_CDF 20
+
+const coeffs
+        .short 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0
+        .short 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0
+endconst
+
+const bits, align=4
+        .short   0x1,   0x2,   0x4,   0x8,   0x10,   0x20,   0x40,   0x80
+        .short 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000
+endconst
+
+.macro vld1_align_n d0, q0, q1, src, n
+.if \n == 4
+        vld1.16         {\d0},  [\src, :64]
+.elseif \n == 8
+        vld1.16         {\q0},  [\src, :128]
+.else
+        vld1.16         {\q0, \q1},  [\src, :128]
+.endif
+.endm
+
+.macro vld1_n d0, q0, q1, src, n
+.if \n == 4
+        vld1.16         {\d0},  [\src]
+.elseif \n == 8
+        vld1.16         {\q0},  [\src]
+.else
+        vld1.16         {\q0, \q1},  [\src]
+.endif
+.endm
+
+.macro vst1_align_n d0, q0, q1, src, n
+.if \n == 4
+        vst1.16         {\d0},  [\src, :64]
+.elseif \n == 8
+        vst1.16         {\q0},  [\src, :128]
+.else
+        vst1.16         {\q0, \q1},  [\src, :128]
+.endif
+.endm
+
+.macro vst1_n d0, q0, q1, src, n
+.if \n == 4
+        vst1.16         {\d0},  [\src]
+.elseif \n == 8
+        vst1.16         {\q0},  [\src]
+.else
+        vst1.16         {\q0, \q1},  [\src]
+.endif
+.endm
+
+.macro vshr_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
+.if \n == 4
+        vshr.u16        \d0,  \s0,  \s3
+.else
+        vshr.u16        \d1,  \s1,  \s4
+.if \n == 16
+        vshr.u16        \d2,  \s2,  \s5
+.endif
+.endif
+.endm
+
+.macro vadd_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
+.if \n == 4
+        vadd.i16        \d0,  \s0,  \s3
+.else
+        vadd.i16        \d1,  \s1,  \s4
+.if \n == 16
+        vadd.i16        \d2,  \s2,  \s5
+.endif
+.endif
+.endm
+
+.macro vsub_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
+.if \n == 4
+        vsub.i16        \d0,  \s0,  \s3
+.else
+        vsub.i16        \d1,  \s1,  \s4
+.if \n == 16
+        vsub.i16        \d2,  \s2,  \s5
+.endif
+.endif
+.endm
+
+.macro vand_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
+.if \n == 4
+        vand            \d0,  \s0,  \s3
+.else
+        vand            \d1,  \s1,  \s4
+.if \n == 16
+        vand            \d2,  \s2,  \s5
+.endif
+.endif
+.endm
+
+.macro vcge_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
+.if \n == 4
+        vcge.u16        \d0,  \s0,  \s3
+.else
+        vcge.u16        \d1,  \s1,  \s4
+.if \n == 16
+        vcge.u16        \d2,  \s2,  \s5
+.endif
+.endif
+.endm
+
+.macro vrhadd_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
+.if \n == 4
+        vrhadd.u16      \d0,  \s0,  \s3
+.else
+        vrhadd.u16      \d1,  \s1,  \s4
+.if \n == 16
+        vrhadd.u16      \d2,  \s2,  \s5
+.endif
+.endif
+.endm
+
+.macro vshl_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
+.if \n == 4
+        vshl.s16        \d0,  \s0,  \s3
+.else
+        vshl.s16        \d1,  \s1,  \s4
+.if \n == 16
+        vshl.s16        \d2,  \s2,  \s5
+.endif
+.endif
+.endm
+
+.macro vqdmulh_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
+.if \n == 4
+        vqdmulh.s16     \d0,  \s0,  \s3
+.else
+        vqdmulh.s16     \d1,  \s1,  \s4
+.if \n == 16
+        vqdmulh.s16     \d2,  \s2,  \s5
+.endif
+.endif
+.endm
+
+// unsigned dav1d_msac_decode_symbol_adapt4_neon(MsacContext *s, uint16_t *cdf,
+//                                               size_t n_symbols);
+
+function msac_decode_symbol_adapt4_neon, export=1
+.macro decode_update n
+        push            {r4-r10,lr}
+        sub             sp,  sp,  #48
+        add             r8,  r0,  #RNG
+
+        vld1_align_n    d0,  q0,  q1,  r1,  \n                         // cdf
+        vld1.16         {d16[]}, [r8, :16]                             // rng
+        movrel_local    r9,  coeffs, 30
+        vmov.i16        d30, #0x7f00                                   // 0x7f00
+        sub             r9,  r9,  r2, lsl #1
+        vmvn.i16        q14, #0x3f                                     // 0xffc0
+        add             r8,  sp,  #14
+        vand            d22, d16, d30                                  // rng & 0x7f00
+        vst1.16         {d16[0]}, [r8, :16]                            // store original u = s->rng
+        vand_n          d4,  q2,  q3,  d0,  q0,  q1, d28, q14, q14, \n // cdf & 0xffc0
+.if \n > 4
+        vmov            d23, d22
+.endif
+
+        vld1_n          d16, q8,  q9,  r9,  \n                          // EC_MIN_PROB * (n_symbols - ret)
+        vqdmulh_n       d20, q10, q11, d4,  q2,  q3,  d22, q11, q11, \n // ((cdf >> EC_PROB_SHIFT) * (r - 128)) >> 1
+        add             r8,  r0,  #DIF + 2
+
+        vadd_n          d16, q8,  q9,  d4,  q2,  q3,  d16, q8,  q9,  \n // v = cdf + EC_MIN_PROB * (n_symbols - ret)
+.if \n == 4
+        vmov.i16        d17, #0
+.endif
+        vadd_n          d16, q8,  q9,  d20, q10, q11, d16, q8,  q9,  \n // v = ((cdf >> EC_PROB_SHIFT) * r) >> 1 + EC_MIN_PROB * (n_symbols - ret)
+
+        add             r9,  sp,  #16
+        vld1.16         {d20[]}, [r8, :16]                              // dif >> (EC_WIN_SIZE - 16)
+        movrel_local    r8,  bits
+        vst1_n          q8,  q8,  q9,  r9,  \n                          // store v values to allow indexed access
+
+        vmov            d21, d20
+        vld1_align_n    q12, q12, q13, r8,  \n
+.if \n == 16
+        vmov            q11, q10
+.endif
+
+        vcge_n          q2,  q2,  q3,  q10, q10, q11, q8,  q8,  q9,  \n // c >= v
+
+        vand_n          q10, q10, q11, q2,  q2,  q3,  q12, q12, q13, \n // One bit per halfword set in the mask
+.if \n == 16
+        vadd.i16        q10, q10, q11
+.endif
+        vadd.i16        d20, d20, d21                                   // Aggregate mask bits
+        ldr             r4,  [r0, #ALLOW_UPDATE_CDF]
+        vpadd.i16       d20, d20, d20
+        lsl             r10, r2,  #1
+        vpadd.i16       d20, d20, d20
+        vmov.u16        r3,  d20[0]
+        cmp             r4,  #0
+        rbit            r3,  r3
+        clz             lr,  r3                                         // ret
+
+        beq             L(renorm)
+        // update_cdf
+        ldrh            r3,  [r1, r10]                                  // count = cdf[n_symbols]
+        vmov.i8         q10, #0xff
+.if \n == 16
+        mov             r4,  #-5
+.else
+        mvn             r12, r2
+        mov             r4,  #-4
+        cmn             r12, #3                                         // set C if n_symbols <= 2
+.endif
+        vrhadd_n        d16, q8,  q9,  d20, q10, q10, d4,  q2,  q3,  \n // i >= val ? -1 : 32768
+.if \n == 16
+        sub             r4,  r4,  r3, lsr #4                            // -((count >> 4) + 5)
+.else
+        lsr             r12, r3,  #4                                    // count >> 4
+        sbc             r4,  r4,  r12                                   // -((count >> 4) + (n_symbols > 2) + 4)
+.endif
+        vsub_n          d16, q8,  q9,  d16, q8,  q9,  d0,  q0,  q1,  \n // (32768 - cdf[i]) or (-1 - cdf[i])
+.if \n == 4
+        vdup.16         d20, r4                                         // -rate
+.else
+        vdup.16         q10, r4                                         // -rate
+.endif
+
+        sub             r3,  r3,  r3, lsr #5                            // count - (count == 32)
+        vsub_n          d0,  q0,  q1,  d0,  q0,  q1,  d4,  q2,  q3,  \n // cdf + (i >= val ? 1 : 0)
+        vshl_n          d16, q8,  q9,  d16, q8,  q9,  d20, q10, q10, \n // ({32768,-1} - cdf[i]) >> rate
+        add             r3,  r3,  #1                                    // count + (count < 32)
+        vadd_n          d0,  q0,  q1,  d0,  q0,  q1,  d16, q8,  q9,  \n // cdf + (32768 - cdf[i]) >> rate
+        vst1_align_n    d0,  q0,  q1,  r1,  \n
+        strh            r3,  [r1, r10]
+.endm
+
+        decode_update   4
+
+L(renorm):
+        add             r8,  sp,  #16
+        add             r8,  r8,  lr, lsl #1
+        ldrh            r3,  [r8]              // v
+        ldrh            r4,  [r8, #-2]         // u
+        ldr             r6,  [r0, #CNT]
+        ldr             r7,  [r0, #DIF]
+        sub             r4,  r4,  r3           // rng = u - v
+        clz             r5,  r4                // clz(rng)
+        eor             r5,  r5,  #16          // d = clz(rng) ^ 16
+        sub             r7,  r7,  r3, lsl #16  // dif - (v << 16)
+L(renorm2):
+        lsl             r4,  r4,  r5           // rng << d
+        subs            r6,  r6,  r5           // cnt -= d
+        lsl             r7,  r7,  r5           // (dif - (v << 16)) << d
+        str             r4,  [r0, #RNG]
+        bhs             4f
+
+        // refill
+        ldr             r3,  [r0, #BUF_POS]    // BUF_POS
+        ldr             r4,  [r0, #BUF_END]    // BUF_END
+        add             r5,  r3,  #4
+        subs            r5,  r5,  r4
+        bhi             6f
+
+        ldr             r8,  [r3]              // next_bits
+        rsb             r5,  r6,  #16
+        add             r4,  r6,  #16          // shift_bits = cnt + 16
+        mvn             r8,  r8
+        lsr             r5,  r5,  #3           // num_bytes_read
+        rev             r8,  r8                // next_bits = bswap(next_bits)
+        lsr             r8,  r8,  r4           // next_bits >>= shift_bits
+
+2:      // refill_end
+        add             r3,  r3,  r5
+        add             r6,  r6,  r5, lsl #3   // cnt += num_bits_read
+        str             r3,  [r0, #BUF_POS]
+
+3:      // refill_end2
+        orr             r7,  r7,  r8           // dif |= next_bits
+
+4:      // end
+        str             r6,  [r0, #CNT]
+        str             r7,  [r0, #DIF]
+        mov             r0,  lr
+        add             sp,  sp,  #48
+        pop             {r4-r10,pc}
+
+5:      // pad_with_ones
+        add             r8,  r6,  #-240
+        lsr             r8,  r8,  r8
+        b               3b
+
+6:      // refill_eob
+        cmp             r3,  r4
+        bhs             5b
+
+        ldr             r8,  [r4, #-4]
+        lsl             r5,  r5,  #3
+        lsr             r8,  r8,  r5
+        add             r5,  r6,  #16
+        mvn             r8,  r8
+        sub             r4,  r4,  r3           // num_bytes_left
+        rev             r8,  r8
+        lsr             r8,  r8,  r5
+        rsb             r5,  r6,  #16
+        lsr             r5,  r5,  #3
+        cmp             r5,  r4
+        it              hs
+        movhs           r5,  r4
+        b               2b
+endfunc
+
+function msac_decode_symbol_adapt8_neon, export=1
+        decode_update   8
+        b               L(renorm)
+endfunc
+
+function msac_decode_symbol_adapt16_neon, export=1
+        decode_update   16
+        b               L(renorm)
+endfunc
+
+function msac_decode_hi_tok_neon, export=1
+        push            {r4-r10,lr}
+        vld1.16         {d0},  [r1, :64]       // cdf
+        add             r4,  r0,  #RNG
+        vmov.i16        d31, #0x7f00           // 0x7f00
+        movrel_local    r5,  coeffs, 30-2*3
+        vmvn.i16        d30, #0x3f             // 0xffc0
+        ldrh            r9,  [r1, #6]          // count = cdf[n_symbols]
+        vld1.16         {d1[]},  [r4, :16]     // rng
+        movrel_local    r4,  bits
+        vld1.16         {d29}, [r5]            // EC_MIN_PROB * (n_symbols - ret)
+        add             r5,  r0,  #DIF + 2
+        vld1.16         {q8}, [r4, :128]
+        mov             r2,  #-24
+        vand            d20, d0, d30           // cdf & 0xffc0
+        ldr             r10, [r0, #ALLOW_UPDATE_CDF]
+        vld1.16         {d2[]}, [r5, :16]      // dif >> (EC_WIN_SIZE - 16)
+        sub             sp,  sp,  #48
+        ldr             r6,  [r0, #CNT]
+        ldr             r7,  [r0, #DIF]
+        vmov            d3,  d2
+1:
+        vand            d23, d1,  d31          // rng & 0x7f00
+        vqdmulh.s16     d18, d20, d23          // ((cdf >> EC_PROB_SHIFT) * (r - 128)) >> 1
+        add             r12, sp,  #14
+        vadd.i16        d6,  d20, d29          // v = cdf + EC_MIN_PROB * (n_symbols - ret)
+        vadd.i16        d6,  d18, d6           // v = ((cdf >> EC_PROB_SHIFT) * r) >> 1 + EC_MIN_PROB * (n_symbols - ret)
+        vmov.i16        d7,  #0
+        vst1.16         {d1[0]}, [r12, :16]    // store original u = s->rng
+        add             r12, sp,  #16
+        vcge.u16        q2,  q1,  q3           // c >= v
+        vst1.16         {q3},  [r12]           // store v values to allow indexed access
+        vand            q9,  q2,  q8           // One bit per halfword set in the mask
+
+        vadd.i16        d18, d18, d19          // Aggregate mask bits
+        vpadd.i16       d18, d18, d18
+        vpadd.i16       d18, d18, d18
+        vmov.u16        r3,  d18[0]
+        cmp             r10, #0
+        add             r2,  r2,  #5
+        rbit            r3,  r3
+        add             r8,  sp,  #16
+        clz             lr,  r3                // ret
+
+        beq             2f
+        // update_cdf
+        vmov.i8         d22, #0xff
+        mov             r4,  #-5
+        vrhadd.u16      d6,  d22, d4           // i >= val ? -1 : 32768
+        sub             r4,  r4,  r9, lsr #4   // -((count >> 4) + 5)
+        vsub.i16        d6,  d6,  d0           // (32768 - cdf[i]) or (-1 - cdf[i])
+        vdup.16         d18, r4                // -rate
+
+        sub             r9,  r9,  r9, lsr #5   // count - (count == 32)
+        vsub.i16        d0,  d0,  d4           // cdf + (i >= val ? 1 : 0)
+        vshl.s16        d6,  d6,  d18          // ({32768,-1} - cdf[i]) >> rate
+        add             r9,  r9,  #1           // count + (count < 32)
+        vadd.i16        d0,  d0,  d6           // cdf + (32768 - cdf[i]) >> rate
+        vst1.16         {d0},  [r1, :64]
+        vand            d20, d0,  d30          // cdf & 0xffc0
+        strh            r9,  [r1, #6]
+
+2:
+        add             r8,  r8,  lr, lsl #1
+        ldrh            r3,  [r8]              // v
+        ldrh            r4,  [r8, #-2]         // u
+        sub             r4,  r4,  r3           // rng = u - v
+        clz             r5,  r4                // clz(rng)
+        eor             r5,  r5,  #16          // d = clz(rng) ^ 16
+        sub             r7,  r7,  r3, lsl #16  // dif - (v << 16)
+        lsl             r4,  r4,  r5           // rng << d
+        subs            r6,  r6,  r5           // cnt -= d
+        lsl             r7,  r7,  r5           // (dif - (v << 16)) << d
+        str             r4,  [r0, #RNG]
+        vdup.16         d1,  r4
+        bhs             5f
+
+        // refill
+        ldr             r3,  [r0, #BUF_POS]    // BUF_POS
+        ldr             r4,  [r0, #BUF_END]    // BUF_END
+        add             r5,  r3,  #4
+        subs            r5,  r5,  r4
+        bhi             7f
+
+        ldr             r8,  [r3]              // next_bits
+        rsb             r5,  r6,  #16
+        add             r4,  r6,  #16          // shift_bits = cnt + 16
+        mvn             r8,  r8
+        lsr             r5,  r5,  #3           // num_bytes_read
+        rev             r8,  r8                // next_bits = bswap(next_bits)
+        lsr             r8,  r8,  r4           // next_bits >>= shift_bits
+
+3:      // refill_end
+        add             r3,  r3,  r5
+        add             r6,  r6,  r5, lsl #3   // cnt += num_bits_read
+        str             r3,  [r0, #BUF_POS]
+
+4:      // refill_end2
+        orr             r7,  r7,  r8           // dif |= next_bits
+
+5:      // end
+        lsl             lr,  lr,  #1
+        sub             lr,  lr,  #5
+        lsr             r12, r7,  #16
+        adds            r2,  r2,  lr           // carry = tok_br < 3 || tok == 15
+        vdup.16         q1,  r12
+        bcc             1b                     // loop if !carry
+        add             r2,  r2,  #30
+        str             r6,  [r0, #CNT]
+        add             sp,  sp,  #48
+        str             r7,  [r0, #DIF]
+        lsr             r0,  r2,  #1
+        pop             {r4-r10,pc}
+
+6:      // pad_with_ones
+        add             r8,  r6,  #-240
+        lsr             r8,  r8,  r8
+        b               4b
+
+7:      // refill_eob
+        cmp             r3,  r4
+        bhs             6b
+
+        ldr             r8,  [r4, #-4]
+        lsl             r5,  r5,  #3
+        lsr             r8,  r8,  r5
+        add             r5,  r6,  #16
+        mvn             r8,  r8
+        sub             r4,  r4,  r3           // num_bytes_left
+        rev             r8,  r8
+        lsr             r8,  r8,  r5
+        rsb             r5,  r6,  #16
+        lsr             r5,  r5,  #3
+        cmp             r5,  r4
+        it              hs
+        movhs           r5,  r4
+        b               3b
+endfunc
+
+function msac_decode_bool_equi_neon, export=1
+        push            {r4-r10,lr}
+        ldr             r5,  [r0, #RNG]
+        ldr             r6,  [r0, #CNT]
+        sub             sp,  sp,  #48
+        ldr             r7,  [r0, #DIF]
+        bic             r4,  r5,  #0xff        // r &= 0xff00
+        add             r4,  r4,  #8
+        mov             r2,  #0
+        subs            r8,  r7,  r4, lsl #15  // dif - vw
+        lsr             r4,  r4,  #1           // v
+        sub             r5,  r5,  r4           // r - v
+        itee            lo
+        movlo           r2,  #1
+        movhs           r4,  r5                // if (ret) v = r - v;
+        movhs           r7,  r8                // if (ret) dif = dif - vw;
+
+        clz             r5,  r4                // clz(rng)
+        eor             r5,  r5,  #16          // d = clz(rng) ^ 16
+        mov             lr,  r2
+        b               L(renorm2)
+endfunc
+
+function msac_decode_bool_neon, export=1
+        push            {r4-r10,lr}
+        ldr             r5,  [r0, #RNG]
+        ldr             r6,  [r0, #CNT]
+        sub             sp,  sp,  #48
+        ldr             r7,  [r0, #DIF]
+        lsr             r4,  r5,  #8           // r >> 8
+        bic             r1,  r1,  #0x3f        // f &= ~63
+        mul             r4,  r4,  r1
+        mov             r2,  #0
+        lsr             r4,  r4,  #7
+        add             r4,  r4,  #4           // v
+        subs            r8,  r7,  r4, lsl #16  // dif - vw
+        sub             r5,  r5,  r4           // r - v
+        itee            lo
+        movlo           r2,  #1
+        movhs           r4,  r5                // if (ret) v = r - v;
+        movhs           r7,  r8                // if (ret) dif = dif - vw;
+
+        clz             r5,  r4                // clz(rng)
+        eor             r5,  r5,  #16          // d = clz(rng) ^ 16
+        mov             lr,  r2
+        b               L(renorm2)
+endfunc
+
+function msac_decode_bool_adapt_neon, export=1
+        push            {r4-r10,lr}
+        ldr             r9,  [r1]              // cdf[0-1]
+        ldr             r5,  [r0, #RNG]
+        movw            lr,  #0xffc0
+        ldr             r6,  [r0, #CNT]
+        sub             sp,  sp,  #48
+        ldr             r7,  [r0, #DIF]
+        lsr             r4,  r5,  #8           // r >> 8
+        and             r2,  r9,  lr           // f &= ~63
+        mul             r4,  r4,  r2
+        mov             r2,  #0
+        lsr             r4,  r4,  #7
+        add             r4,  r4,  #4           // v
+        subs            r8,  r7,  r4, lsl #16  // dif - vw
+        sub             r5,  r5,  r4           // r - v
+        ldr             r10, [r0, #ALLOW_UPDATE_CDF]
+        itee            lo
+        movlo           r2,  #1
+        movhs           r4,  r5                // if (ret) v = r - v;
+        movhs           r7,  r8                // if (ret) dif = dif - vw;
+
+        cmp             r10, #0
+        clz             r5,  r4                // clz(rng)
+        eor             r5,  r5,  #16          // d = clz(rng) ^ 16
+        mov             lr,  r2
+
+        beq             L(renorm2)
+
+        lsr             r2,  r9,  #16          // count = cdf[1]
+        uxth            r9,  r9                // cdf[0]
+
+        sub             r3,  r2,  r2,  lsr #5  // count - (count >= 32)
+        lsr             r2,  r2,  #4           // count >> 4
+        add             r10, r3,  #1           // count + (count < 32)
+        add             r2,  r2,  #4           // rate = (count >> 4) | 4
+
+        sub             r9,  r9,  lr           // cdf[0] -= bit
+        sub             r3,  r9,  lr,  lsl #15 // {cdf[0], cdf[0] - 32769}
+        asr             r3,  r3,  r2           // {cdf[0], cdf[0] - 32769} >> rate
+        sub             r9,  r9,  r3           // cdf[0]
+
+        strh            r9,  [r1]
+        strh            r10, [r1, #2]
+
+        b               L(renorm2)
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/refmvs.S b/media/libdav1d/src/src/arm/32/refmvs.S
new file mode 100644
index 0000000000..7f31db11eb
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/refmvs.S
@@ -0,0 +1,303 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * Copyright © 2021, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// void dav1d_splat_mv_neon(refmvs_block **rr, const refmvs_block *rmv,
+//                          int bx4, int bw4, int bh4)
+
+function splat_mv_neon, export=1
+        push            {r4, lr}
+        vld1.8          {q3},  [r1]
+        ldr             r4,  [sp, #8]
+        clz             r3,  r3
+        adr             lr,  L(splat_tbl)
+        sub             r3,  r3,  #26
+        vext.8          q2,  q3,  q3,  #12
+        ldr             r3,  [lr, r3, lsl #2]
+        add             r2,  r2,  r2,  lsl #1
+        vext.8          q0,  q2,  q3,  #4
+        add             r3,  lr,  r3
+        vext.8          q1,  q2,  q3,  #8
+        lsl             r2,  r2,  #2
+        vext.8          q2,  q2,  q3,  #12
+        vmov            q3,  q0
+1:
+        ldr             r1,  [r0],  #4
+        subs            r4,  r4,  #1
+        add             r1,  r1,  r2
+        bx              r3
+
+        .align 2
+L(splat_tbl):
+        .word 320f - L(splat_tbl) + CONFIG_THUMB
+        .word 160f - L(splat_tbl) + CONFIG_THUMB
+        .word 80f  - L(splat_tbl) + CONFIG_THUMB
+        .word 40f  - L(splat_tbl) + CONFIG_THUMB
+        .word 20f  - L(splat_tbl) + CONFIG_THUMB
+        .word 10f  - L(splat_tbl) + CONFIG_THUMB
+
+10:
+        vst1.8          {d0}, [r1]
+        vstr            s2,  [r1, #8]
+        bgt             1b
+        pop             {r4, pc}
+20:
+        vst1.8          {q0}, [r1]
+        vstr            d2,  [r1, #16]
+        bgt             1b
+        pop             {r4, pc}
+40:
+        vst1.8          {q0, q1}, [r1]!
+        vst1.8          {q2},     [r1]
+        bgt             1b
+        pop             {r4, pc}
+320:
+        vst1.8          {q0, q1}, [r1]!
+        vst1.8          {q2, q3}, [r1]!
+        vst1.8          {q1, q2}, [r1]!
+        vst1.8          {q0, q1}, [r1]!
+        vst1.8          {q2, q3}, [r1]!
+        vst1.8          {q1, q2}, [r1]!
+160:
+        vst1.8          {q0, q1}, [r1]!
+        vst1.8          {q2, q3}, [r1]!
+        vst1.8          {q1, q2}, [r1]!
+80:
+        vst1.8          {q0, q1}, [r1]!
+        vst1.8          {q2, q3}, [r1]!
+        vst1.8          {q1, q2}, [r1]
+        bgt             1b
+        pop             {r4, pc}
+endfunc
+
+const mv_tbls, align=4
+        .byte           255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+        .byte           0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0
+        .byte           4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
+        .byte           4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
+endconst
+
+const mask_mult, align=4
+        .byte           1, 2, 1, 2, 0, 0, 0, 0
+endconst
+
+// void dav1d_save_tmvs_neon(refmvs_temporal_block *rp, ptrdiff_t stride,
+//                           refmvs_block **rr, const uint8_t *ref_sign,
+//                           int col_end8, int row_end8,
+//                           int col_start8, int row_start8)
+function save_tmvs_neon, export=1
+        push            {r4-r11,lr}
+        ldrd            r4,  r5,  [sp, #36]
+        ldrd            r6,  r7,  [sp, #44]
+
+        vmov.i8         d30, #0
+        vld1.8          {d31}, [r3]
+        adr             r8,  L(save_tmvs_tbl)
+        movrel_local    lr,  mask_mult
+        movrel_local    r12, mv_tbls
+        vld1.8          {d29}, [lr]
+        vext.8          d31, d30, d31, #7         // [0, ref_sign]
+        mov             r3,  #5
+        mul             r1,  r1,  r3              // stride *= 5
+        sub             r5,  r5,  r7              // h = row_end8 - row_start8
+        lsl             r7,  r7,  #1              // row_start8 <<= 1
+1:
+        mov             r3,  #5
+        mov             r11, #12*2
+        and             r9,  r7,  #30             // (y & 15) * 2
+        ldr             r9,  [r2, r9, lsl #2]     // b = rr[(y & 15) * 2]
+        add             r9,  r9,  #12             // &b[... + 1]
+        mla             r10, r4,  r11,  r9        // end_cand_b = &b[col_end8*2 + 1]
+        mla             r9,  r6,  r11,  r9        // cand_b = &b[x*2 + 1]
+
+        mla             r3,  r6,  r3,   r0        // &rp[x]
+
+        push            {r2,r4,r6}
+
+2:
+        ldrb            r11, [r9, #10]            // cand_b->bs
+        add             lr,  r9,  #8
+        vld1.8          {d0, d1}, [r9]            // cand_b->mv
+        add             r11, r8,  r11, lsl #3
+        vld1.16         {d2[]},  [lr]             // cand_b->ref
+        ldrh            lr,  [r11]                // bw8
+        mov             r2,  r8
+        add             r9,  r9,  lr,  lsl #1     // cand_b += bw8*2
+        cmp             r9,  r10
+        vmov            d4,  d0
+        bge             3f
+
+        ldrb            r2,  [r9, #10]            // cand_b->bs
+        add             lr,  r9,  #8
+        vld1.8          {d6, d7}, [r9]            // cand_b->mv
+        add             r2,  r8,  r2,  lsl #3
+        vld1.16         {d2[1]},  [lr]            // cand_b->ref
+        ldrh            lr,  [r2]                 // bw8
+        add             r9,  r9,  lr,  lsl #1     // cand_b += bw8*2
+        vmov            d5,  d6
+
+3:
+        vabs.s16        q2,  q2                   // abs(mv[].xy)
+        vtbl.8          d2,  {d31}, d2            // ref_sign[ref]
+        vshr.u16        q2,  q2,  #12             // abs(mv[].xy) >> 12
+        vmull.u8        q1,  d2,  d29             // ref_sign[ref] * {1, 2}
+        vceq.i32        q2,  q2,  #0              // abs(mv[].xy) <= 4096
+        vmovn.i32       d4,  q2                   // abs() condition to 16 bit
+        vand            d2,  d2,  d4              // h[0-3] contains conditions for mv[0-1]
+        vpadd.i16       d2,  d2,  d2              // Combine condition for [1] and [0]
+        vmov.u16        r4,  d2[0]                // Extract case for first block
+        vmov.u16        r6,  d2[1]
+        ldr             r11, [r11, #4]            // Fetch jump table entry
+        ldr             r2,  [r2,  #4]
+        add             r4,  r12,  r4,  lsl #4
+        add             r6,  r12,  r6,  lsl #4
+        vld1.8          {d2, d3}, [r4]            // Load permutation table base on case
+        vld1.8          {d4, d5}, [r6]
+        add             r11, r8,  r11             // Find jump table target
+        add             r2,  r8,  r2
+        vtbl.8          d16, {d0, d1}, d2         // Permute cand_b to output refmvs_temporal_block
+        vtbl.8          d17, {d0, d1}, d3
+        vtbl.8          d18, {d6, d7}, d4
+        vtbl.8          d19, {d6, d7}, d5
+        vmov            q0,  q8
+
+        // q1 follows on q0 (q8), with another 3 full repetitions of the pattern.
+        vext.8          q1,  q8,  q8,  #1
+        vext.8          q10, q9,  q9,  #1
+        // q2 ends with 3 complete repetitions of the pattern.
+        vext.8          q2,  q8,  q1,  #4
+        vext.8          q11, q9,  q10, #4
+
+        blx             r11
+        bge             4f  // if (cand_b >= end)
+        vmov            q0,  q9
+        vmov            q1,  q10
+        vmov            q2,  q11
+        cmp             r9,  r10
+        blx             r2
+        blt             2b  // if (cand_b < end)
+
+4:
+        pop             {r2,r4,r6}
+
+        subs            r5,  r5,  #1              // h--
+        add             r7,  r7,  #2              // y += 2
+        add             r0,  r0,  r1              // rp += stride
+        bgt             1b
+
+        pop             {r4-r11,pc}
+
+        .align 2
+L(save_tmvs_tbl):
+        .word 16 * 12
+        .word 160f - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 16 * 12
+        .word 160f - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 8 * 12
+        .word 80f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 8 * 12
+        .word 80f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 8 * 12
+        .word 80f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 8 * 12
+        .word 80f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 4 * 12
+        .word 40f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 4 * 12
+        .word 40f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 4 * 12
+        .word 40f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 4 * 12
+        .word 40f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 2 * 12
+        .word 20f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 2 * 12
+        .word 20f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 2 * 12
+        .word 20f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 2 * 12
+        .word 20f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 2 * 12
+        .word 20f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 1 * 12
+        .word 10f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 1 * 12
+        .word 10f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 1 * 12
+        .word 10f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 1 * 12
+        .word 10f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 1 * 12
+        .word 10f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 1 * 12
+        .word 10f  - L(save_tmvs_tbl) + CONFIG_THUMB
+        .word 1 * 12
+        .word 10f  - L(save_tmvs_tbl) + CONFIG_THUMB
+
+10:
+        add             r4,  r3,  #4
+        vst1.32         {d0[0]}, [r3]
+        vst1.8          {d0[4]}, [r4]
+        add             r3,  r3,  #5
+        bx              lr
+20:
+        add             r4,  r3,  #8
+        vst1.8          {d0}, [r3]
+        vst1.16         {d1[0]}, [r4]
+        add             r3,  r3,  #2*5
+        bx              lr
+40:
+        add             r4,  r3,  #16
+        vst1.8          {q0}, [r3]
+        vst1.32         {d2[0]}, [r4]
+        add             r3,  r3,  #4*5
+        bx              lr
+80:
+        add             r4,  r3,  #(8*5-16)
+        // This writes 6 full entries plus 2 extra bytes
+        vst1.8          {q0, q1}, [r3]
+        // Write the last few, overlapping with the first write.
+        vst1.8          {q2}, [r4]
+        add             r3,  r3,  #8*5
+        bx              lr
+160:
+        add             r4,  r3,  #6*5
+        add             r6,  r3,  #12*5
+        // This writes 6 full entries plus 2 extra bytes
+        vst1.8          {q0, q1}, [r3]
+        // Write another 6 full entries, slightly overlapping with the first set
+        vst1.8          {q0, q1}, [r4]
+        add             r4,  r3,  #(16*5-16)
+        // Write 8 bytes (one full entry) after the first 12
+        vst1.8          {d0}, [r6]
+        // Write the last 3 entries
+        vst1.8          {q2}, [r4]
+        add             r3,  r3,  #16*5
+        bx              lr
+endfunc
diff --git a/media/libdav1d/src/src/arm/32/util.S b/media/libdav1d/src/src/arm/32/util.S
new file mode 100644
index 0000000000..38d63f855d
--- /dev/null
+++ b/media/libdav1d/src/src/arm/32/util.S
@@ -0,0 +1,202 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2015 Martin Storsjo
+ * Copyright © 2015 Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef DAV1D_SRC_ARM_32_UTIL_S
+#define DAV1D_SRC_ARM_32_UTIL_S
+
+#include "config.h"
+#include "src/arm/asm.S"
+#include "src/arm/arm-arch.h"
+
+.macro v4bx rd
+#if __ARM_ARCH >= 5 || defined(__ARM_ARCH_4T__)
+        bx              \rd
+#else
+        mov             pc, \rd
+#endif
+.endm
+
+.macro v4blx rd
+#if __ARM_ARCH >= 5
+        blx             \rd
+#else
+        mov             lr,  pc
+        v4bx            \rd
+#endif
+.endm
+
+.macro movrel_local rd, val, offset=0
+#if (__ARM_ARCH >= 7 || defined(__ARM_ARCH_6T2__)) && !defined(PIC)
+        movw            \rd, #:lower16:\val+\offset
+        movt            \rd, #:upper16:\val+\offset
+#else
+        ldr             \rd,  90001f
+        b               90002f
+90001:
+        .word           \val + \offset - (90002f + 8 - 4 * CONFIG_THUMB)
+90002:
+        add             \rd,  \rd,  pc
+#endif
+.endm
+
+.macro movrel rd, val, offset=0
+#if defined(PIC) && defined(__APPLE__)
+        ldr             \rd,  1f
+        b               2f
+1:
+        .word           3f - (2f + 8 - 4 * CONFIG_THUMB)
+2:
+        ldr             \rd,  [pc, \rd]
+.if \offset < 0
+        sub             \rd,  \rd,  #-(\offset)
+.elseif \offset > 0
+        add             \rd,  \rd,  #\offset
+.endif
+        .non_lazy_symbol_pointer
+3:
+        .indirect_symbol \val
+        .word       0
+        .text
+#else
+        movrel_local    \rd, \val, \offset
+#endif
+.endm
+
+// This macro clobbers r7 (and r12 on windows) and stores data at the
+// bottom of the stack; sp is the start of the space allocated that
+// the caller can use.
+.macro sub_sp_align space
+#if CONFIG_THUMB
+        mov             r7,  sp
+        and             r7,  r7,  #15
+#else
+        and             r7,  sp,  #15
+#endif
+        sub             sp,  sp,  r7
+        // Now the stack is aligned, store the amount of adjustment back
+        // on the stack, as we don't want to waste a register as frame
+        // pointer.
+        str             r7,  [sp, #-16]!
+#ifdef _WIN32
+.if \space > 8192
+        // Here, we'd need to touch two (or more) pages while decrementing
+        // the stack pointer.
+        .error          "sub_sp_align doesn't support values over 8K at the moment"
+.elseif \space > 4096
+        sub             r7,  sp,  #4096
+        ldr             r12, [r7]
+        sub             r7,  r7,  #(\space - 4096)
+        mov             sp,  r7
+.else
+        sub             sp,  sp,  #\space
+.endif
+#else
+.if \space >= 4096
+        sub             sp,  sp,  #(\space)/4096*4096
+.endif
+.if (\space % 4096) != 0
+        sub             sp,  sp,  #(\space)%4096
+.endif
+#endif
+.endm
+
+.macro add_sp_align space
+.if \space >= 4096
+        add             sp,  sp,  #(\space)/4096*4096
+.endif
+.if (\space % 4096) != 0
+        add             sp,  sp,  #(\space)%4096
+.endif
+        ldr             r7,  [sp], #16
+        // Add back the original stack adjustment
+        add             sp,  sp,  r7
+.endm
+
+.macro transpose_8x8b q0, q1, q2, q3, r0, r1, r2, r3, r4, r5, r6, r7
+        vtrn.32         \q0,  \q2
+        vtrn.32         \q1,  \q3
+
+        vtrn.16         \r0,  \r2
+        vtrn.16         \r1,  \r3
+        vtrn.16         \r4,  \r6
+        vtrn.16         \r5,  \r7
+
+        vtrn.8          \r0,  \r1
+        vtrn.8          \r2,  \r3
+        vtrn.8          \r4,  \r5
+        vtrn.8          \r6,  \r7
+.endm
+
+.macro transpose_8x8h r0, r1, r2, r3, r4, r5, r6, r7, d0, d1, d2, d3, d4, d5, d6, d7
+        vswp            \d0,  \d4
+        vswp            \d1,  \d5
+        vswp            \d2,  \d6
+        vswp            \d3,  \d7
+
+        vtrn.32         \r0,  \r2
+        vtrn.32         \r1,  \r3
+        vtrn.32         \r4,  \r6
+        vtrn.32         \r5,  \r7
+
+        vtrn.16         \r0,  \r1
+        vtrn.16         \r2,  \r3
+        vtrn.16         \r4,  \r5
+        vtrn.16         \r6,  \r7
+.endm
+
+.macro transpose_4x8b q0, q1, r0, r1, r2, r3
+        vtrn.16         \q0,  \q1
+
+        vtrn.8          \r0,  \r1
+        vtrn.8          \r2,  \r3
+.endm
+
+.macro transpose_4x4s q0, q1, q2, q3, r0, r1, r2, r3, r4, r5, r6, r7
+        vswp            \r1,  \r4 // vtrn.64 \q0, \q2
+        vswp            \r3,  \r6 // vtrn.64 \q1, \q3
+
+        vtrn.32         \q0,  \q1
+        vtrn.32         \q2,  \q3
+.endm
+
+.macro transpose_4x4h q0, q1, r0, r1, r2, r3
+        vtrn.32         \q0,  \q1
+
+        vtrn.16         \r0,  \r1
+        vtrn.16         \r2,  \r3
+.endm
+
+.macro transpose_4x8h r0, r1, r2, r3
+        vtrn.32         \r0,  \r2
+        vtrn.32         \r1,  \r3
+
+        vtrn.16         \r0,  \r1
+        vtrn.16         \r2,  \r3
+.endm
+
+#endif /* DAV1D_SRC_ARM_32_UTIL_S */
diff --git a/media/libdav1d/src/src/arm/64/cdef.S b/media/libdav1d/src/src/arm/64/cdef.S
new file mode 100644
index 0000000000..32b258aba8
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/cdef.S
@@ -0,0 +1,520 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+#include "cdef_tmpl.S"
+
+.macro pad_top_bottom s1, s2, w, stride, rn, rw, ret
+        tst             w7,  #1 // CDEF_HAVE_LEFT
+        b.eq            2f
+        // CDEF_HAVE_LEFT
+        sub             \s1,  \s1,  #2
+        sub             \s2,  \s2,  #2
+        tst             w7,  #2 // CDEF_HAVE_RIGHT
+        b.eq            1f
+        // CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+        ldr             \rn\()0, [\s1]
+        ldr             s1,      [\s1, #\w]
+        ldr             \rn\()2, [\s2]
+        ldr             s3,      [\s2, #\w]
+        uxtl            v0.8h,   v0.8b
+        uxtl            v1.8h,   v1.8b
+        uxtl            v2.8h,   v2.8b
+        uxtl            v3.8h,   v3.8b
+        str             \rw\()0, [x0]
+        str             d1,      [x0, #2*\w]
+        add             x0,  x0,  #2*\stride
+        str             \rw\()2, [x0]
+        str             d3,      [x0, #2*\w]
+.if \ret
+        ret
+.else
+        add             x0,  x0,  #2*\stride
+        b               3f
+.endif
+
+1:
+        // CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        ldr             \rn\()0, [\s1]
+        ldr             h1,      [\s1, #\w]
+        ldr             \rn\()2, [\s2]
+        ldr             h3,      [\s2, #\w]
+        uxtl            v0.8h,   v0.8b
+        uxtl            v1.8h,   v1.8b
+        uxtl            v2.8h,   v2.8b
+        uxtl            v3.8h,   v3.8b
+        str             \rw\()0, [x0]
+        str             s1,      [x0, #2*\w]
+        str             s31,     [x0, #2*\w+4]
+        add             x0,  x0,  #2*\stride
+        str             \rw\()2, [x0]
+        str             s3,      [x0, #2*\w]
+        str             s31,     [x0, #2*\w+4]
+.if \ret
+        ret
+.else
+        add             x0,  x0,  #2*\stride
+        b               3f
+.endif
+
+2:
+        // !CDEF_HAVE_LEFT
+        tst             w7,  #2 // CDEF_HAVE_RIGHT
+        b.eq            1f
+        // !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+        ldr             \rn\()0, [\s1]
+        ldr             h1,      [\s1, #\w]
+        ldr             \rn\()2, [\s2]
+        ldr             h3,      [\s2, #\w]
+        uxtl            v0.8h,  v0.8b
+        uxtl            v1.8h,  v1.8b
+        uxtl            v2.8h,  v2.8b
+        uxtl            v3.8h,  v3.8b
+        str             s31, [x0]
+        stur            \rw\()0, [x0, #4]
+        str             s1,      [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        str             s31, [x0]
+        stur            \rw\()2, [x0, #4]
+        str             s3,      [x0, #4+2*\w]
+.if \ret
+        ret
+.else
+        add             x0,  x0,  #2*\stride
+        b               3f
+.endif
+
+1:
+        // !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        ldr             \rn\()0, [\s1]
+        ldr             \rn\()1, [\s2]
+        uxtl            v0.8h,  v0.8b
+        uxtl            v1.8h,  v1.8b
+        str             s31,     [x0]
+        stur            \rw\()0, [x0, #4]
+        str             s31,     [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        str             s31,     [x0]
+        stur            \rw\()1, [x0, #4]
+        str             s31,     [x0, #4+2*\w]
+.if \ret
+        ret
+.else
+        add             x0,  x0,  #2*\stride
+.endif
+3:
+.endm
+
+.macro load_n_incr dst, src, incr, w
+.if \w == 4
+        ld1             {\dst\().s}[0], [\src], \incr
+.else
+        ld1             {\dst\().8b},   [\src], \incr
+.endif
+.endm
+
+// void dav1d_cdef_paddingX_8bpc_neon(uint16_t *tmp, const pixel *src,
+//                                    ptrdiff_t src_stride, const pixel (*left)[2],
+//                                    const pixel *const top,
+//                                    const pixel *const bottom, int h,
+//                                    enum CdefEdgeFlags edges);
+
+.macro padding_func w, stride, rn, rw
+function cdef_padding\w\()_8bpc_neon, export=1
+        cmp             w7,  #0xf // fully edged
+        b.eq            cdef_padding\w\()_edged_8bpc_neon
+        movi            v30.8h,  #0x80, lsl #8
+        mov             v31.16b, v30.16b
+        sub             x0,  x0,  #2*(2*\stride+2)
+        tst             w7,  #4 // CDEF_HAVE_TOP
+        b.ne            1f
+        // !CDEF_HAVE_TOP
+        st1             {v30.8h, v31.8h}, [x0], #32
+.if \w == 8
+        st1             {v30.8h, v31.8h}, [x0], #32
+.endif
+        b               3f
+1:
+        // CDEF_HAVE_TOP
+        add             x9,  x4,  x2
+        pad_top_bottom  x4,  x9, \w, \stride, \rn, \rw, 0
+
+        // Middle section
+3:
+        tst             w7,  #1 // CDEF_HAVE_LEFT
+        b.eq            2f
+        // CDEF_HAVE_LEFT
+        tst             w7,  #2 // CDEF_HAVE_RIGHT
+        b.eq            1f
+        // CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+0:
+        ld1             {v0.h}[0], [x3], #2
+        ldr             h2,      [x1, #\w]
+        load_n_incr     v1,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        uxtl            v0.8h,  v0.8b
+        uxtl            v1.8h,  v1.8b
+        uxtl            v2.8h,  v2.8b
+        str             s0,      [x0]
+        stur            \rw\()1, [x0, #4]
+        str             s2,      [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        b.gt            0b
+        b               3f
+1:
+        // CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        ld1             {v0.h}[0], [x3], #2
+        load_n_incr     v1,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        uxtl            v0.8h,  v0.8b
+        uxtl            v1.8h,  v1.8b
+        str             s0,      [x0]
+        stur            \rw\()1, [x0, #4]
+        str             s31,     [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        b.gt            1b
+        b               3f
+2:
+        tst             w7,  #2 // CDEF_HAVE_RIGHT
+        b.eq            1f
+        // !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+0:
+        ldr             h1,      [x1, #\w]
+        load_n_incr     v0,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        uxtl            v0.8h,  v0.8b
+        uxtl            v1.8h,  v1.8b
+        str             s31,     [x0]
+        stur            \rw\()0, [x0, #4]
+        str             s1,      [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        b.gt            0b
+        b               3f
+1:
+        // !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        load_n_incr     v0,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        uxtl            v0.8h,  v0.8b
+        str             s31,     [x0]
+        stur            \rw\()0, [x0, #4]
+        str             s31,     [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        b.gt            1b
+
+3:
+        tst             w7,  #8 // CDEF_HAVE_BOTTOM
+        b.ne            1f
+        // !CDEF_HAVE_BOTTOM
+        st1             {v30.8h, v31.8h}, [x0], #32
+.if \w == 8
+        st1             {v30.8h, v31.8h}, [x0], #32
+.endif
+        ret
+1:
+        // CDEF_HAVE_BOTTOM
+        add             x9,  x5,  x2
+        pad_top_bottom  x5,  x9, \w, \stride, \rn, \rw, 1
+endfunc
+.endm
+
+padding_func 8, 16, d, q
+padding_func 4, 8,  s, d
+
+// void cdef_paddingX_edged_8bpc_neon(uint8_t *tmp, const pixel *src,
+//                                    ptrdiff_t src_stride, const pixel (*left)[2],
+//                                    const pixel *const top,
+//                                    const pixel *const bottom, int h,
+//                                    enum CdefEdgeFlags edges);
+
+.macro padding_func_edged w, stride, reg
+function cdef_padding\w\()_edged_8bpc_neon, export=1
+        sub             x4,  x4,  #2
+        sub             x5,  x5,  #2
+        sub             x0,  x0,  #(2*\stride+2)
+
+.if \w == 4
+        ldr             d0, [x4]
+        ldr             d1, [x4, x2]
+        st1             {v0.8b, v1.8b}, [x0], #16
+.else
+        add             x9,  x4,  x2
+        ldr             d0, [x4]
+        ldr             s1, [x4, #8]
+        ldr             d2, [x9]
+        ldr             s3, [x9, #8]
+        str             d0, [x0]
+        str             s1, [x0, #8]
+        str             d2, [x0, #\stride]
+        str             s3, [x0, #\stride+8]
+        add             x0,  x0,  #2*\stride
+.endif
+
+0:
+        ld1             {v0.h}[0], [x3], #2
+        ldr             h2,      [x1, #\w]
+        load_n_incr     v1,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        str             h0,      [x0]
+        stur            \reg\()1, [x0, #2]
+        str             h2,      [x0, #2+\w]
+        add             x0,  x0,  #\stride
+        b.gt            0b
+
+.if \w == 4
+        ldr             d0, [x5]
+        ldr             d1, [x5, x2]
+        st1             {v0.8b, v1.8b}, [x0], #16
+.else
+        add             x9,  x5,  x2
+        ldr             d0, [x5]
+        ldr             s1, [x5, #8]
+        ldr             d2, [x9]
+        ldr             s3, [x9, #8]
+        str             d0, [x0]
+        str             s1, [x0, #8]
+        str             d2, [x0, #\stride]
+        str             s3, [x0, #\stride+8]
+.endif
+        ret
+endfunc
+.endm
+
+padding_func_edged 8, 16, d
+padding_func_edged 4, 8,  s
+
+tables
+
+filter 8, 8
+filter 4, 8
+
+find_dir 8
+
+.macro load_px_8 d1, d2, w
+.if \w == 8
+        add             x6,  x2,  w9, sxtb          // x + off
+        sub             x9,  x2,  w9, sxtb          // x - off
+        ld1             {\d1\().d}[0], [x6]         // p0
+        add             x6,  x6,  #16               // += stride
+        ld1             {\d2\().d}[0], [x9]         // p1
+        add             x9,  x9,  #16               // += stride
+        ld1             {\d1\().d}[1], [x6]         // p0
+        ld1             {\d2\().d}[1], [x9]         // p0
+.else
+        add             x6,  x2,  w9, sxtb          // x + off
+        sub             x9,  x2,  w9, sxtb          // x - off
+        ld1             {\d1\().s}[0], [x6]         // p0
+        add             x6,  x6,  #8                // += stride
+        ld1             {\d2\().s}[0], [x9]         // p1
+        add             x9,  x9,  #8                // += stride
+        ld1             {\d1\().s}[1], [x6]         // p0
+        add             x6,  x6,  #8                // += stride
+        ld1             {\d2\().s}[1], [x9]         // p1
+        add             x9,  x9,  #8                // += stride
+        ld1             {\d1\().s}[2], [x6]         // p0
+        add             x6,  x6,  #8                // += stride
+        ld1             {\d2\().s}[2], [x9]         // p1
+        add             x9,  x9,  #8                // += stride
+        ld1             {\d1\().s}[3], [x6]         // p0
+        ld1             {\d2\().s}[3], [x9]         // p1
+.endif
+.endm
+.macro handle_pixel_8 s1, s2, thresh_vec, shift, tap, min
+.if \min
+        umin            v3.16b,  v3.16b,  \s1\().16b
+        umax            v4.16b,  v4.16b,  \s1\().16b
+        umin            v3.16b,  v3.16b,  \s2\().16b
+        umax            v4.16b,  v4.16b,  \s2\().16b
+.endif
+        uabd            v16.16b, v0.16b,  \s1\().16b  // abs(diff)
+        uabd            v20.16b, v0.16b,  \s2\().16b  // abs(diff)
+        ushl            v17.16b, v16.16b, \shift      // abs(diff) >> shift
+        ushl            v21.16b, v20.16b, \shift      // abs(diff) >> shift
+        uqsub           v17.16b, \thresh_vec, v17.16b // clip = imax(0, threshold - (abs(diff) >> shift))
+        uqsub           v21.16b, \thresh_vec, v21.16b // clip = imax(0, threshold - (abs(diff) >> shift))
+        cmhi            v18.16b, v0.16b,  \s1\().16b  // px > p0
+        cmhi            v22.16b, v0.16b,  \s2\().16b  // px > p1
+        umin            v17.16b, v17.16b, v16.16b     // imin(abs(diff), clip)
+        umin            v21.16b, v21.16b, v20.16b     // imin(abs(diff), clip)
+        dup             v19.16b, \tap                 // taps[k]
+        neg             v16.16b, v17.16b              // -imin()
+        neg             v20.16b, v21.16b              // -imin()
+        bsl             v18.16b, v16.16b, v17.16b     // constrain() = apply_sign()
+        bsl             v22.16b, v20.16b, v21.16b     // constrain() = apply_sign()
+        mla             v1.16b,  v18.16b, v19.16b     // sum += taps[k] * constrain()
+        mla             v2.16b,  v22.16b, v19.16b     // sum += taps[k] * constrain()
+.endm
+
+// void cdef_filterX_edged_8bpc_neon(pixel *dst, ptrdiff_t dst_stride,
+//                                   const uint8_t *tmp, int pri_strength,
+//                                   int sec_strength, int dir, int damping,
+//                                   int h);
+.macro filter_func_8 w, pri, sec, min, suffix
+function cdef_filter\w\suffix\()_edged_8bpc_neon
+.if \pri
+        movrel          x8,  pri_taps
+        and             w9,  w3,  #1
+        add             x8,  x8,  w9, uxtw #1
+.endif
+        movrel          x9,  directions\w
+        add             x5,  x9,  w5, uxtw #1
+        movi            v30.8b,  #7
+        dup             v28.8b,  w6                 // damping
+
+.if \pri
+        dup             v25.16b, w3                 // threshold
+.endif
+.if \sec
+        dup             v27.16b, w4                 // threshold
+.endif
+        trn1            v24.8b,  v25.8b, v27.8b
+        clz             v24.8b,  v24.8b             // clz(threshold)
+        sub             v24.8b,  v30.8b, v24.8b     // ulog2(threshold)
+        uqsub           v24.8b,  v28.8b, v24.8b     // shift = imax(0, damping - ulog2(threshold))
+        neg             v24.8b,  v24.8b             // -shift
+.if \sec
+        dup             v26.16b, v24.b[1]
+.endif
+.if \pri
+        dup             v24.16b, v24.b[0]
+.endif
+
+1:
+.if \w == 8
+        add             x12, x2,  #16
+        ld1             {v0.d}[0], [x2]             // px
+        ld1             {v0.d}[1], [x12]            // px
+.else
+        add             x12, x2,  #1*8
+        add             x13, x2,  #2*8
+        add             x14, x2,  #3*8
+        ld1             {v0.s}[0], [x2]             // px
+        ld1             {v0.s}[1], [x12]            // px
+        ld1             {v0.s}[2], [x13]            // px
+        ld1             {v0.s}[3], [x14]            // px
+.endif
+
+        // We need 9-bits or two 8-bit accululators to fit the sum.
+        // Max of |sum| > 15*2*6(pri) + 4*4*3(sec) = 228.
+        // Start sum at -1 instead of 0 to help handle rounding later.
+        movi            v1.16b, #255                // sum
+        movi            v2.16b, #0                  // sum
+.if \min
+        mov             v3.16b, v0.16b              // min
+        mov             v4.16b, v0.16b              // max
+.endif
+
+        // Instead of loading sec_taps 2, 1 from memory, just set it
+        // to 2 initially and decrease for the second round.
+        // This is also used as loop counter.
+        mov             w11, #2                     // sec_taps[0]
+
+2:
+.if \pri
+        ldrb            w9,  [x5]                   // off1
+
+        load_px_8       v5,  v6, \w
+.endif
+
+.if \sec
+        add             x5,  x5,  #4                // +2*2
+        ldrb            w9,  [x5]                   // off2
+        load_px_8       v28, v29, \w
+.endif
+
+.if \pri
+        ldrb            w10, [x8]                   // *pri_taps
+
+        handle_pixel_8  v5,  v6,  v25.16b, v24.16b, w10, \min
+.endif
+
+.if \sec
+        add             x5,  x5,  #8                // +2*4
+        ldrb            w9,  [x5]                   // off3
+        load_px_8       v5,  v6,  \w
+
+        handle_pixel_8  v28, v29, v27.16b, v26.16b, w11, \min
+
+        handle_pixel_8  v5,  v6,  v27.16b, v26.16b, w11, \min
+
+        sub             x5,  x5,  #11               // x5 -= 2*(2+4); x5 += 1;
+.else
+        add             x5,  x5,  #1                // x5 += 1
+.endif
+        subs            w11, w11, #1                // sec_tap-- (value)
+.if \pri
+        add             x8,  x8,  #1                // pri_taps++ (pointer)
+.endif
+        b.ne            2b
+
+        // Perform halving adds since the value won't fit otherwise.
+        // To handle the offset for negative values, use both halving w/ and w/o rounding.
+        srhadd          v5.16b,  v1.16b,  v2.16b    // sum >> 1
+        shadd           v6.16b,  v1.16b,  v2.16b    // (sum - 1) >> 1
+        cmlt            v1.16b,  v5.16b,  #0        // sum < 0
+        bsl             v1.16b,  v6.16b,  v5.16b    // (sum - (sum < 0)) >> 1
+
+        srshr           v1.16b,  v1.16b,  #3        // (8 + sum - (sum < 0)) >> 4
+
+        usqadd          v0.16b,  v1.16b             // px + (8 + sum ...) >> 4
+.if \min
+        umin            v0.16b,  v0.16b,  v4.16b
+        umax            v0.16b,  v0.16b,  v3.16b    // iclip(px + .., min, max)
+.endif
+.if \w == 8
+        st1             {v0.d}[0], [x0], x1
+        add             x2,  x2,  #2*16             // tmp += 2*tmp_stride
+        subs            w7,  w7,  #2                // h -= 2
+        st1             {v0.d}[1], [x0], x1
+.else
+        st1             {v0.s}[0], [x0], x1
+        add             x2,  x2,  #4*8              // tmp += 4*tmp_stride
+        st1             {v0.s}[1], [x0], x1
+        subs            w7,  w7,  #4                // h -= 4
+        st1             {v0.s}[2], [x0], x1
+        st1             {v0.s}[3], [x0], x1
+.endif
+
+        // Reset pri_taps and directions back to the original point
+        sub             x5,  x5,  #2
+.if \pri
+        sub             x8,  x8,  #2
+.endif
+
+        b.gt            1b
+        ret
+endfunc
+.endm
+
+.macro filter_8 w
+filter_func_8 \w, pri=1, sec=0, min=0, suffix=_pri
+filter_func_8 \w, pri=0, sec=1, min=0, suffix=_sec
+filter_func_8 \w, pri=1, sec=1, min=1, suffix=_pri_sec
+.endm
+
+filter_8 8
+filter_8 4
diff --git a/media/libdav1d/src/src/arm/64/cdef16.S b/media/libdav1d/src/src/arm/64/cdef16.S
new file mode 100644
index 0000000000..ecf864a26d
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/cdef16.S
@@ -0,0 +1,229 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+#include "cdef_tmpl.S"
+
+.macro pad_top_bot_16 s1, s2, w, stride, reg, ret
+        tst             w7,  #1 // CDEF_HAVE_LEFT
+        b.eq            2f
+        // CDEF_HAVE_LEFT
+        sub             \s1,  \s1,  #4
+        sub             \s2,  \s2,  #4
+        tst             w7,  #2 // CDEF_HAVE_RIGHT
+        b.eq            1f
+        // CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+        ldr             \reg\()0, [\s1]
+        ldr             d1,       [\s1, #2*\w]
+        ldr             \reg\()2, [\s2]
+        ldr             d3,       [\s2, #2*\w]
+        str             \reg\()0, [x0]
+        str             d1,       [x0, #2*\w]
+        add             x0,  x0,  #2*\stride
+        str             \reg\()2, [x0]
+        str             d3,       [x0, #2*\w]
+.if \ret
+        ret
+.else
+        add             x0,  x0,  #2*\stride
+        b               3f
+.endif
+
+1:
+        // CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        ldr             \reg\()0, [\s1]
+        ldr             s1,       [\s1, #2*\w]
+        ldr             \reg\()2, [\s2]
+        ldr             s3,       [\s2, #2*\w]
+        str             \reg\()0, [x0]
+        str             s1,       [x0, #2*\w]
+        str             s31,      [x0, #2*\w+4]
+        add             x0,  x0,  #2*\stride
+        str             \reg\()2, [x0]
+        str             s3,       [x0, #2*\w]
+        str             s31,      [x0, #2*\w+4]
+.if \ret
+        ret
+.else
+        add             x0,  x0,  #2*\stride
+        b               3f
+.endif
+
+2:
+        // !CDEF_HAVE_LEFT
+        tst             w7,  #2 // CDEF_HAVE_RIGHT
+        b.eq            1f
+        // !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+        ldr             \reg\()0, [\s1]
+        ldr             s1,       [\s1, #2*\w]
+        ldr             \reg\()2, [\s2]
+        ldr             s3,       [\s2, #2*\w]
+        str             s31, [x0]
+        stur            \reg\()0, [x0, #4]
+        str             s1,       [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        str             s31, [x0]
+        stur            \reg\()2, [x0, #4]
+        str             s3,       [x0, #4+2*\w]
+.if \ret
+        ret
+.else
+        add             x0,  x0,  #2*\stride
+        b               3f
+.endif
+
+1:
+        // !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        ldr             \reg\()0, [\s1]
+        ldr             \reg\()1, [\s2]
+        str             s31,      [x0]
+        stur            \reg\()0, [x0, #4]
+        str             s31,      [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        str             s31,      [x0]
+        stur            \reg\()1, [x0, #4]
+        str             s31,      [x0, #4+2*\w]
+.if \ret
+        ret
+.else
+        add             x0,  x0,  #2*\stride
+.endif
+3:
+.endm
+
+.macro load_n_incr_16 dst, src, incr, w
+.if \w == 4
+        ld1             {\dst\().4h}, [\src], \incr
+.else
+        ld1             {\dst\().8h}, [\src], \incr
+.endif
+.endm
+
+// void dav1d_cdef_paddingX_16bpc_neon(uint16_t *tmp, const pixel *src,
+//                                     ptrdiff_t src_stride, const pixel (*left)[2],
+//                                     const pixel *const top,
+//                                     const pixel *const bottom, int h,
+//                                     enum CdefEdgeFlags edges);
+
+.macro padding_func_16 w, stride, reg
+function cdef_padding\w\()_16bpc_neon, export=1
+        movi            v30.8h,  #0x80, lsl #8
+        mov             v31.16b, v30.16b
+        sub             x0,  x0,  #2*(2*\stride+2)
+        tst             w7,  #4 // CDEF_HAVE_TOP
+        b.ne            1f
+        // !CDEF_HAVE_TOP
+        st1             {v30.8h, v31.8h}, [x0], #32
+.if \w == 8
+        st1             {v30.8h, v31.8h}, [x0], #32
+.endif
+        b               3f
+1:
+        // CDEF_HAVE_TOP
+        add             x9,  x4,  x2
+        pad_top_bot_16  x4,  x9, \w, \stride, \reg, 0
+
+        // Middle section
+3:
+        tst             w7,  #1 // CDEF_HAVE_LEFT
+        b.eq            2f
+        // CDEF_HAVE_LEFT
+        tst             w7,  #2 // CDEF_HAVE_RIGHT
+        b.eq            1f
+        // CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+0:
+        ld1             {v0.s}[0], [x3], #4
+        ldr             s2,       [x1, #2*\w]
+        load_n_incr_16  v1,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        str             s0,       [x0]
+        stur            \reg\()1, [x0, #4]
+        str             s2,       [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        b.gt            0b
+        b               3f
+1:
+        // CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        ld1             {v0.s}[0], [x3], #4
+        load_n_incr_16  v1,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        str             s0,       [x0]
+        stur            \reg\()1, [x0, #4]
+        str             s31,      [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        b.gt            1b
+        b               3f
+2:
+        tst             w7,  #2 // CDEF_HAVE_RIGHT
+        b.eq            1f
+        // !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
+0:
+        ldr             s1,       [x1, #2*\w]
+        load_n_incr_16  v0,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        str             s31,      [x0]
+        stur            \reg\()0, [x0, #4]
+        str             s1,       [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        b.gt            0b
+        b               3f
+1:
+        // !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
+        load_n_incr_16  v0,  x1,  x2,  \w
+        subs            w6,  w6,  #1
+        str             s31,      [x0]
+        stur            \reg\()0, [x0, #4]
+        str             s31,      [x0, #4+2*\w]
+        add             x0,  x0,  #2*\stride
+        b.gt            1b
+
+3:
+        tst             w7,  #8 // CDEF_HAVE_BOTTOM
+        b.ne            1f
+        // !CDEF_HAVE_BOTTOM
+        st1             {v30.8h, v31.8h}, [x0], #32
+.if \w == 8
+        st1             {v30.8h, v31.8h}, [x0], #32
+.endif
+        ret
+1:
+        // CDEF_HAVE_BOTTOM
+        add             x9,  x5,  x2
+        pad_top_bot_16  x5,  x9, \w, \stride, \reg, 1
+endfunc
+.endm
+
+padding_func_16 8, 16, q
+padding_func_16 4, 8,  d
+
+tables
+
+filter 8, 16
+filter 4, 16
+
+find_dir 16
diff --git a/media/libdav1d/src/src/arm/64/cdef_tmpl.S b/media/libdav1d/src/src/arm/64/cdef_tmpl.S
new file mode 100644
index 0000000000..d35d7a09ba
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/cdef_tmpl.S
@@ -0,0 +1,511 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+.macro dir_table w, stride
+const directions\w
+        .byte           -1 * \stride + 1, -2 * \stride + 2
+        .byte            0 * \stride + 1, -1 * \stride + 2
+        .byte            0 * \stride + 1,  0 * \stride + 2
+        .byte            0 * \stride + 1,  1 * \stride + 2
+        .byte            1 * \stride + 1,  2 * \stride + 2
+        .byte            1 * \stride + 0,  2 * \stride + 1
+        .byte            1 * \stride + 0,  2 * \stride + 0
+        .byte            1 * \stride + 0,  2 * \stride - 1
+// Repeated, to avoid & 7
+        .byte           -1 * \stride + 1, -2 * \stride + 2
+        .byte            0 * \stride + 1, -1 * \stride + 2
+        .byte            0 * \stride + 1,  0 * \stride + 2
+        .byte            0 * \stride + 1,  1 * \stride + 2
+        .byte            1 * \stride + 1,  2 * \stride + 2
+        .byte            1 * \stride + 0,  2 * \stride + 1
+endconst
+.endm
+
+.macro tables
+dir_table 8, 16
+dir_table 4, 8
+
+const pri_taps
+        .byte           4, 2, 3, 3
+endconst
+.endm
+
+.macro load_px d1, d2, w
+.if \w == 8
+        add             x6,  x2,  w9, sxtb #1       // x + off
+        sub             x9,  x2,  w9, sxtb #1       // x - off
+        ld1             {\d1\().8h}, [x6]           // p0
+        ld1             {\d2\().8h}, [x9]           // p1
+.else
+        add             x6,  x2,  w9, sxtb #1       // x + off
+        sub             x9,  x2,  w9, sxtb #1       // x - off
+        ld1             {\d1\().4h}, [x6]           // p0
+        add             x6,  x6,  #2*8              // += stride
+        ld1             {\d2\().4h}, [x9]           // p1
+        add             x9,  x9,  #2*8              // += stride
+        ld1             {\d1\().d}[1], [x6]         // p0
+        ld1             {\d2\().d}[1], [x9]         // p1
+.endif
+.endm
+.macro handle_pixel s1, s2, thresh_vec, shift, tap, min
+.if \min
+        umin            v2.8h,   v2.8h,  \s1\().8h
+        smax            v3.8h,   v3.8h,  \s1\().8h
+        umin            v2.8h,   v2.8h,  \s2\().8h
+        smax            v3.8h,   v3.8h,  \s2\().8h
+.endif
+        uabd            v16.8h, v0.8h,  \s1\().8h   // abs(diff)
+        uabd            v20.8h, v0.8h,  \s2\().8h   // abs(diff)
+        ushl            v17.8h, v16.8h, \shift      // abs(diff) >> shift
+        ushl            v21.8h, v20.8h, \shift      // abs(diff) >> shift
+        uqsub           v17.8h, \thresh_vec, v17.8h // clip = imax(0, threshold - (abs(diff) >> shift))
+        uqsub           v21.8h, \thresh_vec, v21.8h // clip = imax(0, threshold - (abs(diff) >> shift))
+        sub             v18.8h, \s1\().8h,  v0.8h   // diff = p0 - px
+        sub             v22.8h, \s2\().8h,  v0.8h   // diff = p1 - px
+        neg             v16.8h, v17.8h              // -clip
+        neg             v20.8h, v21.8h              // -clip
+        smin            v18.8h, v18.8h, v17.8h      // imin(diff, clip)
+        smin            v22.8h, v22.8h, v21.8h      // imin(diff, clip)
+        dup             v19.8h, \tap                // taps[k]
+        smax            v18.8h, v18.8h, v16.8h      // constrain() = imax(imin(diff, clip), -clip)
+        smax            v22.8h, v22.8h, v20.8h      // constrain() = imax(imin(diff, clip), -clip)
+        mla             v1.8h,  v18.8h, v19.8h      // sum += taps[k] * constrain()
+        mla             v1.8h,  v22.8h, v19.8h      // sum += taps[k] * constrain()
+.endm
+
+// void dav1d_cdef_filterX_Ybpc_neon(pixel *dst, ptrdiff_t dst_stride,
+//                                   const uint16_t *tmp, int pri_strength,
+//                                   int sec_strength, int dir, int damping,
+//                                   int h, size_t edges);
+.macro filter_func w, bpc, pri, sec, min, suffix
+function cdef_filter\w\suffix\()_\bpc\()bpc_neon
+.if \bpc == 8
+        ldr             w8,  [sp]                   // edges
+        cmp             w8,  #0xf
+        b.eq            cdef_filter\w\suffix\()_edged_8bpc_neon
+.endif
+.if \pri
+.if \bpc == 16
+        ldr             w9,  [sp, #8]               // bitdepth_max
+        clz             w9,  w9
+        sub             w9,  w9,  #24               // -bitdepth_min_8
+        neg             w9,  w9                     // bitdepth_min_8
+.endif
+        movrel          x8,  pri_taps
+.if \bpc == 16
+        lsr             w9,  w3,  w9                // pri_strength >> bitdepth_min_8
+        and             w9,  w9,  #1                // (pri_strength >> bitdepth_min_8) & 1
+.else
+        and             w9,  w3,  #1
+.endif
+        add             x8,  x8,  w9, uxtw #1
+.endif
+        movrel          x9,  directions\w
+        add             x5,  x9,  w5, uxtw #1
+        movi            v30.4h,   #15
+        dup             v28.4h,   w6                // damping
+
+.if \pri
+        dup             v25.8h, w3                  // threshold
+.endif
+.if \sec
+        dup             v27.8h, w4                  // threshold
+.endif
+        trn1            v24.4h, v25.4h, v27.4h
+        clz             v24.4h, v24.4h              // clz(threshold)
+        sub             v24.4h, v30.4h, v24.4h      // ulog2(threshold)
+        uqsub           v24.4h, v28.4h, v24.4h      // shift = imax(0, damping - ulog2(threshold))
+        neg             v24.4h, v24.4h              // -shift
+.if \sec
+        dup             v26.8h, v24.h[1]
+.endif
+.if \pri
+        dup             v24.8h, v24.h[0]
+.endif
+
+1:
+.if \w == 8
+        ld1             {v0.8h}, [x2]               // px
+.else
+        add             x12, x2,  #2*8
+        ld1             {v0.4h},   [x2]             // px
+        ld1             {v0.d}[1], [x12]            // px
+.endif
+
+        movi            v1.8h,  #0                  // sum
+.if \min
+        mov             v2.16b, v0.16b              // min
+        mov             v3.16b, v0.16b              // max
+.endif
+
+        // Instead of loading sec_taps 2, 1 from memory, just set it
+        // to 2 initially and decrease for the second round.
+        // This is also used as loop counter.
+        mov             w11, #2                     // sec_taps[0]
+
+2:
+.if \pri
+        ldrb            w9,  [x5]                   // off1
+
+        load_px         v4,  v5, \w
+.endif
+
+.if \sec
+        add             x5,  x5,  #4                // +2*2
+        ldrb            w9,  [x5]                   // off2
+        load_px         v6,  v7,  \w
+.endif
+
+.if \pri
+        ldrb            w10, [x8]                   // *pri_taps
+
+        handle_pixel    v4,  v5,  v25.8h, v24.8h, w10, \min
+.endif
+
+.if \sec
+        add             x5,  x5,  #8                // +2*4
+        ldrb            w9,  [x5]                   // off3
+        load_px         v4,  v5,  \w
+
+        handle_pixel    v6,  v7,  v27.8h, v26.8h, w11, \min
+
+        handle_pixel    v4,  v5,  v27.8h, v26.8h, w11, \min
+
+        sub             x5,  x5,  #11               // x5 -= 2*(2+4); x5 += 1;
+.else
+        add             x5,  x5,  #1                // x5 += 1
+.endif
+        subs            w11, w11, #1                // sec_tap-- (value)
+.if \pri
+        add             x8,  x8,  #1                // pri_taps++ (pointer)
+.endif
+        b.ne            2b
+
+        cmlt            v4.8h,  v1.8h,  #0          // -(sum < 0)
+        add             v1.8h,  v1.8h,  v4.8h       // sum - (sum < 0)
+        srshr           v1.8h,  v1.8h,  #4          // (8 + sum - (sum < 0)) >> 4
+        add             v0.8h,  v0.8h,  v1.8h       // px + (8 + sum ...) >> 4
+.if \min
+        smin            v0.8h,  v0.8h,  v3.8h
+        smax            v0.8h,  v0.8h,  v2.8h       // iclip(px + .., min, max)
+.endif
+.if \bpc == 8
+        xtn             v0.8b,  v0.8h
+.endif
+.if \w == 8
+        add             x2,  x2,  #2*16             // tmp += tmp_stride
+        subs            w7,  w7,  #1                // h--
+.if \bpc == 8
+        st1             {v0.8b}, [x0], x1
+.else
+        st1             {v0.8h}, [x0], x1
+.endif
+.else
+.if \bpc == 8
+        st1             {v0.s}[0], [x0], x1
+.else
+        st1             {v0.d}[0], [x0], x1
+.endif
+        add             x2,  x2,  #2*16             // tmp += 2*tmp_stride
+        subs            w7,  w7,  #2                // h -= 2
+.if \bpc == 8
+        st1             {v0.s}[1], [x0], x1
+.else
+        st1             {v0.d}[1], [x0], x1
+.endif
+.endif
+
+        // Reset pri_taps and directions back to the original point
+        sub             x5,  x5,  #2
+.if \pri
+        sub             x8,  x8,  #2
+.endif
+
+        b.gt            1b
+        ret
+endfunc
+.endm
+
+.macro filter w, bpc
+filter_func \w, \bpc, pri=1, sec=0, min=0, suffix=_pri
+filter_func \w, \bpc, pri=0, sec=1, min=0, suffix=_sec
+filter_func \w, \bpc, pri=1, sec=1, min=1, suffix=_pri_sec
+
+function cdef_filter\w\()_\bpc\()bpc_neon, export=1
+        cbnz            w3,  1f // pri_strength
+        b               cdef_filter\w\()_sec_\bpc\()bpc_neon     // only sec
+1:
+        cbnz            w4,  1f // sec_strength
+        b               cdef_filter\w\()_pri_\bpc\()bpc_neon     // only pri
+1:
+        b               cdef_filter\w\()_pri_sec_\bpc\()bpc_neon // both pri and sec
+endfunc
+.endm
+
+const div_table
+        .short         840, 420, 280, 210, 168, 140, 120, 105
+endconst
+
+const alt_fact
+        .short         420, 210, 140, 105, 105, 105, 105, 105, 140, 210, 420, 0
+endconst
+
+.macro cost_alt d1, d2, s1, s2, s3, s4
+        smull           v22.4s,  \s1\().4h, \s1\().4h // sum_alt[n]*sum_alt[n]
+        smull2          v23.4s,  \s1\().8h, \s1\().8h
+        smull           v24.4s,  \s2\().4h, \s2\().4h
+        smull           v25.4s,  \s3\().4h, \s3\().4h // sum_alt[n]*sum_alt[n]
+        smull2          v26.4s,  \s3\().8h, \s3\().8h
+        smull           v27.4s,  \s4\().4h, \s4\().4h
+        mul             v22.4s,  v22.4s,  v29.4s      // sum_alt[n]^2*fact
+        mla             v22.4s,  v23.4s,  v30.4s
+        mla             v22.4s,  v24.4s,  v31.4s
+        mul             v25.4s,  v25.4s,  v29.4s      // sum_alt[n]^2*fact
+        mla             v25.4s,  v26.4s,  v30.4s
+        mla             v25.4s,  v27.4s,  v31.4s
+        addv            \d1, v22.4s                   // *cost_ptr
+        addv            \d2, v25.4s                   // *cost_ptr
+.endm
+
+.macro find_best s1, s2, s3
+.ifnb \s2
+        mov             w5,  \s2\().s[0]
+.endif
+        cmp             w4,  w1                       // cost[n] > best_cost
+        csel            w0,  w3,  w0,  gt             // best_dir = n
+        csel            w1,  w4,  w1,  gt             // best_cost = cost[n]
+.ifnb \s2
+        add             w3,  w3,  #1                  // n++
+        cmp             w5,  w1                       // cost[n] > best_cost
+        mov             w4,  \s3\().s[0]
+        csel            w0,  w3,  w0,  gt             // best_dir = n
+        csel            w1,  w5,  w1,  gt             // best_cost = cost[n]
+        add             w3,  w3,  #1                  // n++
+.endif
+.endm
+
+// Steps for loading and preparing each row
+.macro dir_load_step1 s1, bpc
+.if \bpc == 8
+        ld1             {\s1\().8b}, [x0], x1
+.else
+        ld1             {\s1\().8h}, [x0], x1
+.endif
+.endm
+
+.macro dir_load_step2 s1, bpc
+.if \bpc == 8
+        usubl           \s1\().8h,  \s1\().8b, v31.8b
+.else
+        ushl            \s1\().8h,  \s1\().8h, v8.8h
+.endif
+.endm
+
+.macro dir_load_step3 s1, bpc
+// Nothing for \bpc == 8
+.if \bpc != 8
+        sub             \s1\().8h,  \s1\().8h, v31.8h
+.endif
+.endm
+
+// int dav1d_cdef_find_dir_Xbpc_neon(const pixel *img, const ptrdiff_t stride,
+//                                   unsigned *const var)
+.macro find_dir bpc
+function cdef_find_dir_\bpc\()bpc_neon, export=1
+.if \bpc == 16
+        str             d8,  [sp, #-0x10]!
+        clz             w3,  w3                       // clz(bitdepth_max)
+        sub             w3,  w3,  #24                 // -bitdepth_min_8
+        dup             v8.8h,   w3
+.endif
+        sub             sp,  sp,  #32 // cost
+        mov             w3,  #8
+.if \bpc == 8
+        movi            v31.16b, #128
+.else
+        movi            v31.8h,  #128
+.endif
+        movi            v30.16b, #0
+        movi            v1.8h,   #0 // v0-v1 sum_diag[0]
+        movi            v3.8h,   #0 // v2-v3 sum_diag[1]
+        movi            v5.8h,   #0 // v4-v5 sum_hv[0-1]
+        movi            v7.8h,   #0 // v6-v7 sum_alt[0]
+        dir_load_step1  v26, \bpc       // Setup first row early
+        movi            v17.8h,  #0 // v16-v17 sum_alt[1]
+        movi            v18.8h,  #0 // v18-v19 sum_alt[2]
+        dir_load_step2  v26, \bpc
+        movi            v19.8h,  #0
+        dir_load_step3  v26, \bpc
+        movi            v21.8h,  #0 // v20-v21 sum_alt[3]
+
+.irpc i, 01234567
+        addv            h25,     v26.8h               // [y]
+        rev64           v27.8h,  v26.8h
+        addp            v28.8h,  v26.8h,  v30.8h      // [(x >> 1)]
+        add             v5.8h,   v5.8h,   v26.8h      // sum_hv[1]
+        ext             v27.16b, v27.16b, v27.16b, #8 // [-x]
+        rev64           v29.4h,  v28.4h               // [-(x >> 1)]
+        ins             v4.h[\i], v25.h[0]            // sum_hv[0]
+.if \i < 6
+        ext             v22.16b, v30.16b, v26.16b, #(16-2*(3-(\i/2)))
+        ext             v23.16b, v26.16b, v30.16b, #(16-2*(3-(\i/2)))
+        add             v18.8h,  v18.8h,  v22.8h      // sum_alt[2]
+        add             v19.4h,  v19.4h,  v23.4h      // sum_alt[2]
+.else
+        add             v18.8h,  v18.8h,  v26.8h      // sum_alt[2]
+.endif
+.if \i == 0
+        mov             v20.16b, v26.16b              // sum_alt[3]
+.elseif \i == 1
+        add             v20.8h,  v20.8h,  v26.8h      // sum_alt[3]
+.else
+        ext             v24.16b, v30.16b, v26.16b, #(16-2*(\i/2))
+        ext             v25.16b, v26.16b, v30.16b, #(16-2*(\i/2))
+        add             v20.8h,  v20.8h,  v24.8h      // sum_alt[3]
+        add             v21.4h,  v21.4h,  v25.4h      // sum_alt[3]
+.endif
+.if \i == 0
+        mov             v0.16b,  v26.16b              // sum_diag[0]
+        dir_load_step1  v26, \bpc
+        mov             v2.16b,  v27.16b              // sum_diag[1]
+        dir_load_step2  v26, \bpc
+        mov             v6.16b,  v28.16b              // sum_alt[0]
+        dir_load_step3  v26, \bpc
+        mov             v16.16b, v29.16b              // sum_alt[1]
+.else
+        ext             v22.16b, v30.16b, v26.16b, #(16-2*\i)
+        ext             v23.16b, v26.16b, v30.16b, #(16-2*\i)
+        ext             v24.16b, v30.16b, v27.16b, #(16-2*\i)
+        ext             v25.16b, v27.16b, v30.16b, #(16-2*\i)
+.if \i != 7 // Nothing to load for the final row
+        dir_load_step1  v26, \bpc // Start setting up the next row early.
+.endif
+        add             v0.8h,   v0.8h,   v22.8h      // sum_diag[0]
+        add             v1.8h,   v1.8h,   v23.8h      // sum_diag[0]
+        add             v2.8h,   v2.8h,   v24.8h      // sum_diag[1]
+        add             v3.8h,   v3.8h,   v25.8h      // sum_diag[1]
+.if \i != 7
+        dir_load_step2  v26, \bpc
+.endif
+        ext             v22.16b, v30.16b, v28.16b, #(16-2*\i)
+        ext             v23.16b, v28.16b, v30.16b, #(16-2*\i)
+        ext             v24.16b, v30.16b, v29.16b, #(16-2*\i)
+        ext             v25.16b, v29.16b, v30.16b, #(16-2*\i)
+.if \i != 7
+        dir_load_step3  v26, \bpc
+.endif
+        add             v6.8h,   v6.8h,   v22.8h      // sum_alt[0]
+        add             v7.4h,   v7.4h,   v23.4h      // sum_alt[0]
+        add             v16.8h,  v16.8h,  v24.8h      // sum_alt[1]
+        add             v17.4h,  v17.4h,  v25.4h      // sum_alt[1]
+.endif
+.endr
+
+        movi            v31.4s,  #105
+
+        smull           v26.4s,  v4.4h,   v4.4h       // sum_hv[0]*sum_hv[0]
+        smlal2          v26.4s,  v4.8h,   v4.8h
+        smull           v27.4s,  v5.4h,   v5.4h       // sum_hv[1]*sum_hv[1]
+        smlal2          v27.4s,  v5.8h,   v5.8h
+        mul             v26.4s,  v26.4s,  v31.4s      // cost[2] *= 105
+        mul             v27.4s,  v27.4s,  v31.4s      // cost[6] *= 105
+        addv            s4,  v26.4s                   // cost[2]
+        addv            s5,  v27.4s                   // cost[6]
+
+        rev64           v1.8h,   v1.8h
+        rev64           v3.8h,   v3.8h
+        ext             v1.16b,  v1.16b,  v1.16b, #10 // sum_diag[0][14-n]
+        ext             v3.16b,  v3.16b,  v3.16b, #10 // sum_diag[1][14-n]
+
+        str             s4,  [sp, #2*4]               // cost[2]
+        str             s5,  [sp, #6*4]               // cost[6]
+
+        movrel          x4,  div_table
+        ld1             {v31.8h}, [x4]
+
+        smull           v22.4s,  v0.4h,   v0.4h       // sum_diag[0]*sum_diag[0]
+        smull2          v23.4s,  v0.8h,   v0.8h
+        smlal           v22.4s,  v1.4h,   v1.4h
+        smlal2          v23.4s,  v1.8h,   v1.8h
+        smull           v24.4s,  v2.4h,   v2.4h       // sum_diag[1]*sum_diag[1]
+        smull2          v25.4s,  v2.8h,   v2.8h
+        smlal           v24.4s,  v3.4h,   v3.4h
+        smlal2          v25.4s,  v3.8h,   v3.8h
+        uxtl            v30.4s,  v31.4h               // div_table
+        uxtl2           v31.4s,  v31.8h
+        mul             v22.4s,  v22.4s,  v30.4s      // cost[0]
+        mla             v22.4s,  v23.4s,  v31.4s      // cost[0]
+        mul             v24.4s,  v24.4s,  v30.4s      // cost[4]
+        mla             v24.4s,  v25.4s,  v31.4s      // cost[4]
+        addv            s0,  v22.4s                   // cost[0]
+        addv            s2,  v24.4s                   // cost[4]
+
+        movrel          x5,  alt_fact
+        ld1             {v29.4h, v30.4h, v31.4h}, [x5]// div_table[2*m+1] + 105
+
+        str             s0,  [sp, #0*4]               // cost[0]
+        str             s2,  [sp, #4*4]               // cost[4]
+
+        uxtl            v29.4s,  v29.4h               // div_table[2*m+1] + 105
+        uxtl            v30.4s,  v30.4h
+        uxtl            v31.4s,  v31.4h
+
+        cost_alt        s6,  s16, v6,  v7,  v16, v17  // cost[1], cost[3]
+        cost_alt        s18, s20, v18, v19, v20, v21  // cost[5], cost[7]
+        str             s6,  [sp, #1*4]               // cost[1]
+        str             s16, [sp, #3*4]               // cost[3]
+
+        mov             w0,  #0                       // best_dir
+        mov             w1,  v0.s[0]                  // best_cost
+        mov             w3,  #1                       // n
+
+        str             s18, [sp, #5*4]               // cost[5]
+        str             s20, [sp, #7*4]               // cost[7]
+
+        mov             w4,  v6.s[0]
+
+        find_best       v6,  v4, v16
+        find_best       v16, v2, v18
+        find_best       v18, v5, v20
+        find_best       v20
+
+        eor             w3,  w0,  #4                  // best_dir ^4
+        ldr             w4,  [sp, w3, uxtw #2]
+        sub             w1,  w1,  w4                  // best_cost - cost[best_dir ^ 4]
+        lsr             w1,  w1,  #10
+        str             w1,  [x2]                     // *var
+
+        add             sp,  sp,  #32
+.if \bpc == 16
+        ldr             d8,  [sp], 0x10
+.endif
+        ret
+endfunc
+.endm
diff --git a/media/libdav1d/src/src/arm/64/filmgrain.S b/media/libdav1d/src/src/arm/64/filmgrain.S
new file mode 100644
index 0000000000..864ceba974
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/filmgrain.S
@@ -0,0 +1,2015 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * Copyright © 2021, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+#include "src/arm/asm-offsets.h"
+
+#define GRAIN_WIDTH 82
+#define GRAIN_HEIGHT 73
+
+#define SUB_GRAIN_WIDTH 44
+#define SUB_GRAIN_HEIGHT 38
+
+.macro increment_seed steps, shift=1
+        lsr             w11, w2,  #3
+        lsr             w12, w2,  #12
+        lsr             w13, w2,  #1
+        eor             w11, w2,  w11                     // (r >> 0) ^ (r >> 3)
+        eor             w12, w12, w13                     // (r >> 12) ^ (r >> 1)
+        eor             w11, w11, w12                     // (r >> 0) ^ (r >> 3) ^ (r >> 12) ^ (r >> 1)
+.if \shift
+        lsr             w2,  w2,  #\steps
+.endif
+        and             w11, w11, #((1 << \steps) - 1)    // bit
+.if \shift
+        orr             w2,  w2,  w11, lsl #(16 - \steps) // *state
+.else
+        orr             w2,  w2,  w11, lsl #16            // *state
+.endif
+.endm
+
+.macro read_rand dest, bits, age
+        ubfx            \dest,  x2,   #16 - \bits - \age, #\bits
+.endm
+
+.macro read_shift_rand dest, bits
+        ubfx            \dest,  x2,   #17 - \bits, #\bits
+        lsr             w2,  w2,  #1
+.endm
+
+// special calling convention:
+// w2 holds seed
+// x3 holds dav1d_gaussian_sequence
+// clobbers x11-x15
+// returns in v0.8h
+function get_gaussian_neon
+        increment_seed  4
+        read_rand       x14, 11,  3
+        read_rand       x15, 11,  2
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[0], [x14]
+        read_rand       x14, 11,  1
+        ld1             {v0.h}[1], [x15]
+        add             x14, x3,  x14, lsl #1
+        read_rand       x15, 11,  0
+        increment_seed  4
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[2], [x14]
+        read_rand       x14, 11,  3
+        ld1             {v0.h}[3], [x15]
+        add             x14, x3,  x14, lsl #1
+        read_rand       x15, 11,  2
+        ld1             {v0.h}[4], [x14]
+        add             x15, x3,  x15, lsl #1
+        read_rand       x14, 11,  1
+        ld1             {v0.h}[5], [x15]
+        read_rand       x15, 11,  0
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[6], [x14]
+        ld1             {v0.h}[7], [x15]
+        ret
+endfunc
+
+.macro get_grain_row r0, r1, r2, r3, r4, r5
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn             \r0\().8b,  \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn2            \r0\().16b, \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn             \r1\().8b,  \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn2            \r1\().16b, \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn             \r2\().8b,  \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn2            \r2\().16b, \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn             \r3\().8b,  \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn2            \r3\().16b, \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn             \r4\().8b,  \r5\().8h
+        bl              get_gaussian_neon
+        srshl           \r5\().8h,  v0.8h,  v31.8h
+        xtn2            \r4\().16b, \r5\().8h
+        increment_seed  2
+        read_rand       x14, 11,  1
+        read_rand       x15, 11,  0
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {\r5\().h}[0], [x14]
+        ld1             {\r5\().h}[1], [x15]
+        srshl           v0.4h,      \r5\().4h,  v31.4h
+        xtn             \r5\().8b,  v0.8h
+.endm
+
+.macro store_grain_row r0, r1, r2, r3, r4, r5
+        st1             {\r0\().16b,\r1\().16b}, [x0], #32
+        st1             {\r2\().16b,\r3\().16b}, [x0], #32
+        st1             {\r4\().16b},  [x0], #16
+        st1             {\r5\().h}[0], [x0], #2
+.endm
+
+.macro get_grain_row_44 r0, r1, r2
+        bl              get_gaussian_neon
+        srshl           \r2\().8h,  v0.8h,  v31.8h
+        xtn             \r0\().8b,  \r2\().8h
+        bl              get_gaussian_neon
+        srshl           \r2\().8h,  v0.8h,  v31.8h
+        xtn2            \r0\().16b, \r2\().8h
+        bl              get_gaussian_neon
+        srshl           \r2\().8h,  v0.8h,  v31.8h
+        xtn             \r1\().8b,  \r2\().8h
+        bl              get_gaussian_neon
+        srshl           \r2\().8h,  v0.8h,  v31.8h
+        xtn2            \r1\().16b, \r2\().8h
+        bl              get_gaussian_neon
+        srshl           \r2\().8h,  v0.8h,  v31.8h
+        xtn             \r2\().8b,  \r2\().8h
+
+        increment_seed  4
+        read_rand       x14, 11,  3
+        read_rand       x15, 11,  2
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[0], [x14]
+        read_rand       x14, 11,  1
+        ld1             {v0.h}[1], [x15]
+        read_rand       x15, 11,  0
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[2], [x14]
+        ld1             {v0.h}[3], [x15]
+        srshl           v0.4h,      v0.4h,  v31.4h
+        xtn2            \r2\().16b, v0.8h
+.endm
+
+.macro store_grain_row_44 r0, r1, r2
+        st1             {\r0\().16b,\r1\().16b}, [x0], #32
+        st1             {\r2\().16b},  [x0]
+        add             x0,  x0,  #GRAIN_WIDTH-32
+.endm
+
+function get_grain_2_neon
+        increment_seed  2
+        read_rand       x14, 11,  1
+        read_rand       x15, 11,  0
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[0], [x14]
+        ld1             {v0.h}[1], [x15]
+        srshl           v0.4h,   v0.4h,   v31.4h
+        xtn             v0.8b,   v0.8h
+        ret
+endfunc
+
+.macro get_grain_2 dst
+        bl              get_grain_2_neon
+.ifnc \dst, v0
+        mov             \dst\().8b, v0.8b
+.endif
+.endm
+
+// w15 holds the number of entries to produce
+// w14, w16 and w17 hold the previous output entries
+// v0 holds the vector of produced entries
+// v1 holds the input vector of sums from above
+.macro output_lag n
+function output_lag\n\()_neon
+1:
+        read_shift_rand x13, 11
+        mov             w11, v1.s[0]
+        ldrsh           w12, [x3, x13, lsl #1]
+        ext             v0.16b,  v0.16b,  v0.16b,  #1
+.if \n == 1
+        madd            w11, w14, w4,  w11        // sum (above) + *coeff * prev output
+.elseif \n == 2
+        madd            w11, w16, w4,  w11        // sum (above) + *coeff * prev output 1
+        madd            w11, w14, w17, w11        // += *coeff * prev output 2
+        mov             w16, w14
+.else
+        madd            w11, w17, w4,  w11        // sum (above) + *coeff * prev output 1
+        madd            w11, w16, w20, w11        // sum (above) + *coeff * prev output 2
+        madd            w11, w14, w21, w11        // += *coeff * prev output 3
+        mov             w17, w16
+        mov             w16, w14
+.endif
+        add             w14, w11, w8              // 1 << (ar_coeff_shift - 1)
+        add             w12, w12, w10             // 1 << (4 + grain_scale_shift - 1)
+        asr             w14, w14, w7              // >> ar_coeff_shift
+        asr             w12, w12, w9              // >> (4 + grain_scale_shift)
+        add             w14, w14, w12
+        cmp             w14, w5
+        csel            w14, w14, w5,  le
+        cmp             w14, w6
+        csel            w14, w14, w6,  ge
+        subs            w15, w15, #1
+        ext             v1.16b,  v1.16b,  v1.16b,  #4
+        ins             v0.b[15], w14
+        b.gt            1b
+        ret
+endfunc
+.endm
+
+output_lag 1
+output_lag 2
+output_lag 3
+
+
+function sum_lag1_above_neon
+        smull           v2.8h,   v3.8b,   v28.8b
+        smull2          v3.8h,   v3.16b,  v28.16b
+        smull           v4.8h,   v0.8b,   v27.8b
+        smull2          v5.8h,   v0.16b,  v27.16b
+        smull           v6.8h,   v1.8b,   v29.8b
+        smull2          v7.8h,   v1.16b,  v29.16b
+        saddl           v0.4s,   v2.4h,   v4.4h
+        saddl2          v1.4s,   v2.8h,   v4.8h
+        saddl           v2.4s,   v3.4h,   v5.4h
+        saddl2          v3.4s,   v3.8h,   v5.8h
+        saddw           v4.4s,   v0.4s,   v6.4h
+        saddw2          v5.4s,   v1.4s,   v6.8h
+        saddw           v6.4s,   v2.4s,   v7.4h
+        saddw2          v7.4s,   v3.4s,   v7.8h
+        ret
+endfunc
+
+.macro sum_lag_n_body lag, type, uv_layout, edge, elems, store, uv_coeff
+        bl              sum_\lag\()_above_neon
+.ifc \type, uv_420
+        add             x12, x19, #GRAIN_WIDTH
+        ld1             {v22.16b, v23.16b}, [x19], #32
+        ld1             {v24.16b, v25.16b}, [x12]
+        saddlp          v22.8h,  v22.16b
+        saddlp          v23.8h,  v23.16b
+        saddlp          v24.8h,  v24.16b
+        saddlp          v25.8h,  v25.16b
+        add             v22.8h,  v22.8h,  v24.8h
+        add             v23.8h,  v23.8h,  v25.8h
+        rshrn           v0.8b,   v22.8h,  #2
+        rshrn2          v0.16b,  v23.8h,  #2
+.endif
+.ifc \type, uv_422
+        ld1             {v22.16b, v23.16b}, [x19], #32
+        saddlp          v22.8h,  v22.16b
+        saddlp          v23.8h,  v23.16b
+        rshrn           v0.8b,   v22.8h,  #1
+        rshrn2          v0.16b,  v23.8h,  #1
+.endif
+.ifc \type, uv_444
+        ld1             {v0.16b}, [x19], #16
+.endif
+.if \uv_layout
+.ifnb \uv_coeff
+        dup             v1.16b,  \uv_coeff
+        smull           v2.8h,   v0.8b,   v1.8b
+        smull2          v3.8h,   v0.16b,  v1.16b
+.else
+        smull           v2.8h,   v0.8b,   v30.8b
+        smull2          v3.8h,   v0.16b,  v30.16b
+.endif
+        saddw           v4.4s,   v4.4s,   v2.4h
+        saddw2          v5.4s,   v5.4s,   v2.8h
+        saddw           v6.4s,   v6.4s,   v3.4h
+        saddw2          v7.4s,   v7.4s,   v3.8h
+.endif
+.if \uv_layout && \elems == 16
+        b               sum_\lag\()_y_\edge\()_start
+.elseif \uv_layout == 444 && \elems == 15
+        b               sum_\lag\()_y_\edge\()_start
+.elseif \uv_layout == 422 && \elems == 9
+        b               sum_\lag\()_uv_420_\edge\()_start
+.else
+sum_\lag\()_\type\()_\edge\()_start:
+.ifc \edge, left
+        increment_seed  4
+        read_rand       x12, 11,  3
+        read_rand       x13, 11,  2
+        read_rand       x14, 11,  1
+        add             x12, x3,  x12, lsl #1
+        add             x13, x3,  x13, lsl #1
+        add             x14, x3,  x14, lsl #1
+        ld1             {v0.h}[5], [x12]
+        ld1             {v0.h}[6], [x13]
+        ld1             {v0.h}[7], [x14]
+        lsl             x2,  x2,  #1             // shift back the state as if we'd done increment_seed with shift=0
+        srshl           v0.8h,   v0.8h,   v31.8h
+        xtn2            v0.16b,  v0.8h
+        ext             v4.16b,  v4.16b,  v4.16b,  #12
+.ifc \lag, lag3
+        smov            w17, v0.b[13]
+.endif
+.ifnc \lag, lag1
+        smov            w16, v0.b[14]
+.endif
+        smov            w14, v0.b[15]
+
+        mov             v1.16b,  v4.16b
+        mov             w15, #1
+        bl              output_\lag\()_neon
+.else
+        increment_seed  4, shift=0
+        mov             v1.16b,  v4.16b
+        mov             w15, #4
+        bl              output_\lag\()_neon
+.endif
+
+        increment_seed  4, shift=0
+        mov             v1.16b,  v5.16b
+        mov             w15, #4
+        bl              output_\lag\()_neon
+
+        increment_seed  4, shift=0
+        mov             v1.16b,  v6.16b
+.if \elems == 9
+        mov             w15, #1
+        bl              output_\lag\()_neon
+        lsr             w2,  w2,  #3
+
+        read_rand       x12, 11,  2
+        read_rand       x13, 11,  1
+        read_rand       x14, 11,  0
+        add             x12, x3,  x12, lsl #1
+        add             x13, x3,  x13, lsl #1
+        add             x14, x3,  x14, lsl #1
+        ld1             {v1.h}[0], [x12]
+        ld1             {v1.h}[1], [x13]
+        ld1             {v1.h}[2], [x14]
+        srshl           v1.4h,   v1.4h,   v31.4h
+        xtn             v1.8b,   v1.8h
+        ext             v0.16b,  v0.16b,  v1.16b,  #7
+.else
+        mov             w15, #4
+        bl              output_\lag\()_neon
+
+        increment_seed  4, shift=0
+        mov             v1.16b,  v7.16b
+
+.ifc \edge, right
+        mov             w15, #3
+        bl              output_\lag\()_neon
+        read_shift_rand x15, 11
+        add             x15, x3,  x15, lsl #1
+        ld1             {v1.h}[0], [x15]
+        srshl           v1.4h,   v1.4h,   v31.4h
+        ext             v0.16b,  v0.16b,  v1.16b,  #1
+.else
+        mov             w15, #4
+        bl              output_\lag\()_neon
+.endif
+.endif
+.if \store
+        st1             {v0.16b}, [x0], #16
+.endif
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+.endif
+.endm
+
+.macro sum_lag1_func type, uv_layout, edge, elems=16
+function sum_\type\()_lag1_\edge\()_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+        sum_lag_n_body  lag1, \type, \uv_layout, \edge, \elems, store=0
+endfunc
+.endm
+
+sum_lag1_func y,      0,   left
+sum_lag1_func y,      0,   mid
+sum_lag1_func y,      0,   right, 15
+sum_lag1_func uv_444, 444, left
+sum_lag1_func uv_444, 444, mid
+sum_lag1_func uv_444, 444, right, 15
+sum_lag1_func uv_422, 422, left
+sum_lag1_func uv_422, 422, mid
+sum_lag1_func uv_422, 422, right, 9
+sum_lag1_func uv_420, 420, left
+sum_lag1_func uv_420, 420, mid
+sum_lag1_func uv_420, 420, right, 9
+
+.macro sum_lag1 type, dst, left, mid, right, edge=mid
+        mov             v3.16b,  \mid\().16b
+        ext             v0.16b,  \left\().16b, \mid\().16b,   #15
+        ext             v1.16b,  \mid\().16b,  \right\().16b, #1
+        bl              sum_\type\()_lag1_\edge\()_neon
+        mov             \dst\().16b, v0.16b
+.endm
+
+.macro sum_y_lag1 dst, left, mid, right, edge=mid
+        sum_lag1        y, \dst, \left, \mid, \right, \edge
+.endm
+
+.macro sum_uv_444_lag1 dst, left, mid, right, edge=mid
+        sum_lag1        uv_444, \dst, \left, \mid, \right, \edge
+.endm
+
+.macro sum_uv_422_lag1 dst, left, mid, right, edge=mid
+        sum_lag1        uv_422, \dst, \left, \mid, \right, \edge
+.endm
+
+.macro sum_uv_420_lag1 dst, left, mid, right, edge=mid
+        sum_lag1        uv_420, \dst, \left, \mid, \right, \edge
+.endm
+
+
+function sum_lag2_above_neon
+        sub             x12, x0,  #2*GRAIN_WIDTH - 16
+        sub             x13, x0,  #1*GRAIN_WIDTH - 16
+        ld1             {v18.16b}, [x12] // load top right
+        ld1             {v21.16b}, [x13]
+
+        ext             v22.16b, v16.16b, v17.16b, #14 // top left, top mid
+        dup             v26.16b, v30.b[0]
+        ext             v23.16b, v16.16b, v17.16b, #15
+        dup             v27.16b, v30.b[1]
+        ext             v0.16b,  v17.16b, v18.16b, #1  // top mid, top right
+        dup             v28.16b, v30.b[3]
+        ext             v1.16b,  v17.16b, v18.16b, #2
+        dup             v29.16b, v30.b[4]
+
+        smull           v2.8h,   v22.8b,  v26.8b
+        smull2          v3.8h,   v22.16b, v26.16b
+        smull           v4.8h,   v23.8b,  v27.8b
+        smull2          v5.8h,   v23.16b, v27.16b
+        smull           v6.8h,   v0.8b,   v28.8b
+        smull2          v7.8h,   v0.16b,  v28.16b
+        smull           v0.8h,   v1.8b,   v29.8b
+        smull2          v1.8h,   v1.16b,  v29.16b
+        saddl           v22.4s,  v2.4h,   v4.4h
+        saddl2          v23.4s,  v2.8h,   v4.8h
+        saddl           v26.4s,  v3.4h,   v5.4h
+        saddl2          v27.4s,  v3.8h,   v5.8h
+        saddl           v2.4s,   v0.4h,   v6.4h
+        saddl2          v3.4s,   v0.8h,   v6.8h
+        saddl           v6.4s,   v1.4h,   v7.4h
+        saddl2          v7.4s,   v1.8h,   v7.8h
+        add             v4.4s,   v22.4s,  v2.4s
+        add             v5.4s,   v23.4s,  v3.4s
+        add             v6.4s,   v26.4s,  v6.4s
+        add             v7.4s,   v27.4s,  v7.4s
+
+        ext             v22.16b, v19.16b, v20.16b, #14 // top left, top mid
+        dup             v26.16b, v30.b[5]
+        ext             v23.16b, v19.16b, v20.16b, #15
+        dup             v27.16b, v30.b[6]
+        ext             v0.16b,  v20.16b, v21.16b, #1  // top mid, top right
+        dup             v28.16b, v30.b[8]
+        ext             v1.16b,  v20.16b, v21.16b, #2
+        dup             v29.16b, v30.b[9]
+
+        smull           v2.8h,   v22.8b,  v26.8b
+        smull2          v3.8h,   v22.16b, v26.16b
+        smull           v22.8h,  v23.8b,  v27.8b
+        smull2          v23.8h,  v23.16b, v27.16b
+        smull           v26.8h,  v0.8b,   v28.8b
+        smull2          v27.8h,  v0.16b,  v28.16b
+        smull           v28.8h,  v1.8b,   v29.8b
+        smull2          v29.8h,  v1.16b,  v29.16b
+        saddl           v0.4s,   v2.4h,   v22.4h
+        saddl2          v1.4s,   v2.8h,   v22.8h
+        saddl           v2.4s,   v3.4h,   v23.4h
+        saddl2          v3.4s,   v3.8h,   v23.8h
+        saddl           v22.4s,  v26.4h,  v28.4h
+        saddl2          v23.4s,  v26.8h,  v28.8h
+        saddl           v26.4s,  v27.4h,  v29.4h
+        saddl2          v27.4s,  v27.8h,  v29.8h
+        add             v0.4s,   v0.4s,   v22.4s
+        add             v1.4s,   v1.4s,   v23.4s
+        add             v2.4s,   v2.4s,   v26.4s
+        add             v3.4s,   v3.4s,   v27.4s
+        dup             v26.16b, v30.b[2]
+        dup             v27.16b, v30.b[7]
+        smull           v22.8h,  v17.8b,  v26.8b
+        smull2          v23.8h,  v17.16b, v26.16b
+        smull           v24.8h,  v20.8b,  v27.8b
+        smull2          v25.8h,  v20.16b, v27.16b
+        add             v4.4s,   v4.4s,   v0.4s
+        add             v5.4s,   v5.4s,   v1.4s
+        add             v6.4s,   v6.4s,   v2.4s
+        add             v7.4s,   v7.4s,   v3.4s
+
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+
+        saddl           v0.4s,   v22.4h,  v24.4h
+        saddl2          v1.4s,   v22.8h,  v24.8h
+        saddl           v2.4s,   v23.4h,  v25.4h
+        saddl2          v3.4s,   v23.8h,  v25.8h
+        mov             v19.16b, v20.16b
+        mov             v20.16b, v21.16b
+        add             v4.4s,   v4.4s,   v0.4s
+        add             v5.4s,   v5.4s,   v1.4s
+        add             v6.4s,   v6.4s,   v2.4s
+        add             v7.4s,   v7.4s,   v3.4s
+        ret
+endfunc
+
+.macro sum_lag2_func type, uv_layout, edge, elems=16
+function sum_\type\()_lag2_\edge\()_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+.ifc \edge, left
+        sub             x12, x0,  #2*GRAIN_WIDTH
+        sub             x13, x0,  #1*GRAIN_WIDTH
+        ld1             {v17.16b}, [x12] // load the previous block right above
+        ld1             {v20.16b}, [x13]
+.endif
+        sum_lag_n_body  lag2, \type, \uv_layout, \edge, \elems, store=1, uv_coeff=v30.b[12]
+endfunc
+.endm
+
+sum_lag2_func y,      0,   left
+sum_lag2_func y,      0,   mid
+sum_lag2_func y,      0,   right, 15
+sum_lag2_func uv_444, 444, left
+sum_lag2_func uv_444, 444, mid
+sum_lag2_func uv_444, 444, right, 15
+sum_lag2_func uv_422, 422, left
+sum_lag2_func uv_422, 422, mid
+sum_lag2_func uv_422, 422, right, 9
+sum_lag2_func uv_420, 420, left
+sum_lag2_func uv_420, 420, mid
+sum_lag2_func uv_420, 420, right, 9
+
+
+function sum_lag3_above_neon
+        sub             x11, x0,  #3*GRAIN_WIDTH - 16
+        sub             x12, x0,  #2*GRAIN_WIDTH - 16
+        sub             x13, x0,  #1*GRAIN_WIDTH - 16
+        ld1             {v15.16b}, [x11] // load top right
+        ld1             {v18.16b}, [x12]
+        ld1             {v21.16b}, [x13]
+
+        ext             v8.16b,  v13.16b, v14.16b, #13 // top left, top mid
+        dup             v22.16b, v29.b[0]
+        ext             v9.16b,  v13.16b, v14.16b, #14
+        dup             v23.16b, v29.b[1]
+        ext             v10.16b, v13.16b, v14.16b, #15
+        dup             v24.16b, v29.b[2]
+        dup             v25.16b, v29.b[3]
+        ext             v11.16b, v14.16b, v15.16b, #1  // top mid, top right
+        dup             v26.16b, v29.b[4]
+        ext             v12.16b, v14.16b, v15.16b, #2
+        dup             v27.16b, v29.b[5]
+        ext             v13.16b, v14.16b, v15.16b, #3
+        dup             v28.16b, v29.b[6]
+
+        smull           v0.8h,   v8.8b,   v22.8b
+        smull2          v1.8h,   v8.16b,  v22.16b
+        smull           v2.8h,   v9.8b,   v23.8b
+        smull2          v3.8h,   v9.16b,  v23.16b
+        smull           v8.8h,   v10.8b,  v24.8b
+        smull2          v9.8h,   v10.16b, v24.16b
+        smull           v10.8h,  v11.8b,  v26.8b
+        smull2          v11.8h,  v11.16b, v26.16b
+        saddl           v22.4s,  v0.4h,   v2.4h
+        saddl2          v23.4s,  v0.8h,   v2.8h
+        saddl           v24.4s,  v1.4h,   v3.4h
+        saddl2          v26.4s,  v1.8h,   v3.8h
+        saddl           v0.4s,   v8.4h,   v10.4h
+        saddl2          v1.4s,   v8.8h,   v10.8h
+        saddl           v2.4s,   v9.4h,   v11.4h
+        saddl2          v3.4s,   v9.8h,   v11.8h
+        smull           v8.8h,   v12.8b,  v27.8b
+        smull2          v9.8h,   v12.16b, v27.16b
+        smull           v10.8h,  v13.8b,  v28.8b
+        smull2          v11.8h,  v13.16b, v28.16b
+        smull           v12.8h,  v14.8b,  v25.8b
+        smull2          v13.8h,  v14.16b, v25.16b
+        add             v4.4s,   v22.4s,  v0.4s
+        add             v5.4s,   v23.4s,  v1.4s
+        add             v6.4s,   v24.4s,  v2.4s
+        add             v7.4s,   v26.4s,  v3.4s
+        saddl           v0.4s,   v8.4h,   v10.4h
+        saddl2          v1.4s,   v8.8h,   v10.8h
+        saddl           v2.4s,   v9.4h,   v11.4h
+        saddl2          v3.4s,   v9.8h,   v11.8h
+        add             v4.4s,   v4.4s,   v0.4s
+        add             v5.4s,   v5.4s,   v1.4s
+        add             v6.4s,   v6.4s,   v2.4s
+        add             v7.4s,   v7.4s,   v3.4s
+        saddw           v4.4s,   v4.4s,   v12.4h
+        saddw2          v5.4s,   v5.4s,   v12.8h
+        saddw           v6.4s,   v6.4s,   v13.4h
+        saddw2          v7.4s,   v7.4s,   v13.8h
+
+        ext             v8.16b,  v16.16b, v17.16b, #13 // top left, top mid
+        dup             v22.16b, v29.b[7]
+        ext             v9.16b,  v16.16b, v17.16b, #14
+        dup             v23.16b, v29.b[8]
+        ext             v10.16b, v16.16b, v17.16b, #15
+        dup             v24.16b, v29.b[9]
+        dup             v25.16b, v29.b[10]
+        ext             v11.16b, v17.16b, v18.16b, #1  // top mid, top right
+        dup             v26.16b, v29.b[11]
+        ext             v12.16b, v17.16b, v18.16b, #2
+        dup             v27.16b, v29.b[12]
+        ext             v13.16b, v17.16b, v18.16b, #3
+        dup             v28.16b, v29.b[13]
+
+        smull           v0.8h,   v8.8b,   v22.8b
+        smull2          v1.8h,   v8.16b,  v22.16b
+        smull           v2.8h,   v9.8b,   v23.8b
+        smull2          v3.8h,   v9.16b,  v23.16b
+        smull           v8.8h,   v10.8b,  v24.8b
+        smull2          v9.8h,   v10.16b, v24.16b
+        smull           v10.8h,  v11.8b,  v26.8b
+        smull2          v11.8h,  v11.16b, v26.16b
+        saddl           v22.4s,  v0.4h,   v2.4h
+        saddl2          v23.4s,  v0.8h,   v2.8h
+        saddl           v24.4s,  v1.4h,   v3.4h
+        saddl2          v26.4s,  v1.8h,   v3.8h
+        saddl           v0.4s,   v8.4h,   v10.4h
+        saddl2          v1.4s,   v8.8h,   v10.8h
+        saddl           v2.4s,   v9.4h,   v11.4h
+        saddl2          v3.4s,   v9.8h,   v11.8h
+        smull           v8.8h,   v12.8b,  v27.8b
+        smull2          v9.8h,   v12.16b, v27.16b
+        smull           v10.8h,  v13.8b,  v28.8b
+        smull2          v11.8h,  v13.16b, v28.16b
+        smull           v12.8h,  v17.8b,  v25.8b
+        smull2          v13.8h,  v17.16b, v25.16b
+        add             v22.4s,  v22.4s,  v0.4s
+        add             v23.4s,  v23.4s,  v1.4s
+        add             v24.4s,  v24.4s,  v2.4s
+        add             v26.4s,  v26.4s,  v3.4s
+        saddl           v0.4s,   v8.4h,   v10.4h
+        saddl2          v1.4s,   v8.8h,   v10.8h
+        saddl           v2.4s,   v9.4h,   v11.4h
+        saddl2          v3.4s,   v9.8h,   v11.8h
+        add             v4.4s,   v4.4s,   v22.4s
+        add             v5.4s,   v5.4s,   v23.4s
+        add             v6.4s,   v6.4s,   v24.4s
+        add             v7.4s,   v7.4s,   v26.4s
+        add             v4.4s,   v4.4s,   v0.4s
+        add             v5.4s,   v5.4s,   v1.4s
+        add             v6.4s,   v6.4s,   v2.4s
+        add             v7.4s,   v7.4s,   v3.4s
+        saddw           v4.4s,   v4.4s,   v12.4h
+        saddw2          v5.4s,   v5.4s,   v12.8h
+        saddw           v6.4s,   v6.4s,   v13.4h
+        saddw2          v7.4s,   v7.4s,   v13.8h
+
+        ext             v8.16b,  v19.16b, v20.16b, #13 // top left, top mid
+        dup             v22.16b, v29.b[14]
+        ext             v9.16b,  v19.16b, v20.16b, #14
+        dup             v23.16b, v29.b[15]
+        ext             v10.16b, v19.16b, v20.16b, #15
+        dup             v24.16b, v30.b[0]
+        dup             v25.16b, v30.b[1]
+        ext             v11.16b, v20.16b, v21.16b, #1  // top mid, top right
+        dup             v26.16b, v30.b[2]
+        ext             v12.16b, v20.16b, v21.16b, #2
+        dup             v27.16b, v30.b[3]
+        ext             v13.16b, v20.16b, v21.16b, #3
+        dup             v28.16b, v30.b[4]
+
+        smull           v0.8h,   v8.8b,   v22.8b
+        smull2          v1.8h,   v8.16b,  v22.16b
+        smull           v2.8h,   v9.8b,   v23.8b
+        smull2          v3.8h,   v9.16b,  v23.16b
+        smull           v8.8h,   v10.8b,  v24.8b
+        smull2          v9.8h,   v10.16b, v24.16b
+        smull           v10.8h,  v11.8b,  v26.8b
+        smull2          v11.8h,  v11.16b, v26.16b
+        saddl           v22.4s,  v0.4h,   v2.4h
+        saddl2          v23.4s,  v0.8h,   v2.8h
+        saddl           v24.4s,  v1.4h,   v3.4h
+        saddl2          v26.4s,  v1.8h,   v3.8h
+        saddl           v0.4s,   v8.4h,   v10.4h
+        saddl2          v1.4s,   v8.8h,   v10.8h
+        saddl           v2.4s,   v9.4h,   v11.4h
+        saddl2          v3.4s,   v9.8h,   v11.8h
+        smull           v8.8h,   v12.8b,  v27.8b
+        smull2          v9.8h,   v12.16b, v27.16b
+        smull           v10.8h,  v13.8b,  v28.8b
+        smull2          v11.8h,  v13.16b, v28.16b
+        smull           v12.8h,  v20.8b,  v25.8b
+        smull2          v19.8h,  v20.16b, v25.16b
+        add             v22.4s,  v22.4s,  v0.4s
+        add             v23.4s,  v23.4s,  v1.4s
+        add             v24.4s,  v24.4s,  v2.4s
+        add             v26.4s,  v26.4s,  v3.4s
+        saddl           v0.4s,   v8.4h,   v10.4h
+        saddl2          v1.4s,   v8.8h,   v10.8h
+        saddl           v2.4s,   v9.4h,   v11.4h
+        saddl2          v3.4s,   v9.8h,   v11.8h
+        add             v4.4s,   v4.4s,   v22.4s
+        add             v5.4s,   v5.4s,   v23.4s
+        add             v6.4s,   v6.4s,   v24.4s
+        add             v7.4s,   v7.4s,   v26.4s
+        mov             v13.16b, v14.16b
+        mov             v14.16b, v15.16b
+        add             v4.4s,   v4.4s,   v0.4s
+        add             v5.4s,   v5.4s,   v1.4s
+        add             v6.4s,   v6.4s,   v2.4s
+        add             v7.4s,   v7.4s,   v3.4s
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+        saddw           v4.4s,   v4.4s,   v12.4h
+        saddw2          v5.4s,   v5.4s,   v12.8h
+        saddw           v6.4s,   v6.4s,   v19.4h
+        saddw2          v7.4s,   v7.4s,   v19.8h
+
+        mov             v19.16b, v20.16b
+        mov             v20.16b, v21.16b
+        ret
+endfunc
+
+.macro sum_lag3_func type, uv_layout, edge, elems=16
+function sum_\type\()_lag3_\edge\()_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+.ifc \edge, left
+        sub             x11, x0,  #3*GRAIN_WIDTH
+        sub             x12, x0,  #2*GRAIN_WIDTH
+        sub             x13, x0,  #1*GRAIN_WIDTH
+        ld1             {v14.16b}, [x11] // load the previous block right above
+        ld1             {v17.16b}, [x12]
+        ld1             {v20.16b}, [x13]
+.endif
+        sum_lag_n_body  lag3, \type, \uv_layout, \edge, \elems, store=1, uv_coeff=v30.b[8]
+endfunc
+.endm
+
+sum_lag3_func y,      0,   left
+sum_lag3_func y,      0,   mid
+sum_lag3_func y,      0,   right, 15
+sum_lag3_func uv_444, 444, left
+sum_lag3_func uv_444, 444, mid
+sum_lag3_func uv_444, 444, right, 15
+sum_lag3_func uv_422, 422, left
+sum_lag3_func uv_422, 422, mid
+sum_lag3_func uv_422, 422, right, 9
+sum_lag3_func uv_420, 420, left
+sum_lag3_func uv_420, 420, mid
+sum_lag3_func uv_420, 420, right, 9
+
+function generate_grain_rows_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+1:
+        get_grain_row   v16, v17, v18, v19, v20, v21
+        subs            w1,  w1,  #1
+        store_grain_row v16, v17, v18, v19, v20, v21
+        b.gt            1b
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+function generate_grain_rows_44_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+1:
+        get_grain_row_44 v16, v17, v18
+        subs            w1,  w1,  #1
+        store_grain_row_44 v16, v17, v18
+        b.gt            1b
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+function get_grain_row_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+        get_grain_row   v16, v17, v18, v19, v20, v21
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+function get_grain_row_44_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+        get_grain_row_44 v16, v17, v18
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+function add_uv_444_coeff_lag0_neon
+add_coeff_lag0_start:
+        smull           v2.8h,   v0.8b,   v27.8b
+        smull2          v3.8h,   v0.16b,  v27.16b
+        srshl           v2.8h,   v2.8h,   v28.8h
+        srshl           v3.8h,   v3.8h,   v28.8h
+        saddw           v2.8h,   v2.8h,   v1.8b
+        saddw2          v3.8h,   v3.8h,   v1.16b
+        sqxtn           v2.8b,   v2.8h
+        sqxtn2          v2.16b,  v3.8h
+        ret
+endfunc
+
+function add_uv_420_coeff_lag0_neon
+        ld1             {v4.16b, v5.16b}, [x19], #32
+        ld1             {v6.16b, v7.16b}, [x12], #32
+        saddlp          v4.8h,   v4.16b
+        saddlp          v5.8h,   v5.16b
+        saddlp          v6.8h,   v6.16b
+        saddlp          v7.8h,   v7.16b
+        add             v4.8h,   v4.8h,   v6.8h
+        add             v5.8h,   v5.8h,   v7.8h
+        rshrn           v4.8b,   v4.8h,   #2
+        rshrn2          v4.16b,  v5.8h,   #2
+        and             v0.16b,  v4.16b,  v0.16b
+        b               add_coeff_lag0_start
+endfunc
+
+function add_uv_422_coeff_lag0_neon
+        ld1             {v4.16b, v5.16b}, [x19], #32
+        saddlp          v4.8h,   v4.16b
+        saddlp          v5.8h,   v5.16b
+        rshrn           v4.8b,   v4.8h,   #1
+        rshrn2          v4.16b,  v5.8h,   #1
+        and             v0.16b,  v4.16b,  v0.16b
+        b               add_coeff_lag0_start
+endfunc
+
+.macro gen_grain_82 type
+function generate_grain_\type\()_8bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x30, x19, [sp, #-96]!
+
+.ifc \type, uv_444
+        mov             w13, w3
+        mov             w14, #28
+        add             x19, x1,  #3*GRAIN_WIDTH
+        mov             x1,  x2
+        mul             w13, w13, w14
+.endif
+        movrel          x3,  X(gaussian_sequence)
+        ldr             w2,  [x1, #FGD_SEED]
+        ldr             w9,  [x1, #FGD_GRAIN_SCALE_SHIFT]
+.ifc \type, y
+        add             x4,  x1,  #FGD_AR_COEFFS_Y
+.else
+        add             x4,  x1,  #FGD_AR_COEFFS_UV
+.endif
+        movrel          x16, gen_grain_\type\()_tbl
+        ldr             w17, [x1, #FGD_AR_COEFF_LAG]
+        add             w9,  w9,  #4
+        ldrsw           x17, [x16, w17, uxtw #2]
+        dup             v31.8h,  w9    // 4 + data->grain_scale_shift
+        add             x16, x16, x17
+        neg             v31.8h,  v31.8h
+
+.ifc \type, uv_444
+        cmp             w13, #0
+        mov             w11, #0x49d8
+        mov             w14, #0xb524
+        add             x4,  x4,  w13, uxtw // Add offset to ar_coeffs_uv[1]
+        csel            w11, w11, w14, ne
+.endif
+
+        ldr             w7,  [x1, #FGD_AR_COEFF_SHIFT]
+        mov             w8,  #1
+        mov             w10, #1
+        lsl             w8,  w8,  w7        // 1 << ar_coeff_shift
+        lsl             w10, w10, w9        // 1 << (4 + data->grain_scale_shift)
+        lsr             w8,  w8,  #1        // 1 << (ar_coeff_shift - 1)
+        lsr             w10, w10, #1        // 1 << (4 + data->grain_scale_shift - 1)
+        mov             w5,  #127
+        mov             w6,  #-128
+
+.ifc \type, uv_444
+        eor             w2,  w2,  w11
+.endif
+
+        br              x16
+
+L(generate_grain_\type\()_lag0):
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, y
+        mov             w1,  #GRAIN_HEIGHT
+        bl              generate_grain_rows_neon
+.else
+        dup             v28.8h,  w7
+        ld1r            {v27.16b}, [x4]     // ar_coeffs_uv[0]
+        movi            v0.16b,  #0
+        movi            v1.16b,  #255
+        ext             v29.16b, v0.16b,  v1.16b,  #13
+        ext             v30.16b, v1.16b,  v0.16b,  #1
+        neg             v28.8h,  v28.8h
+
+        mov             w1,  #3
+        bl              generate_grain_rows_neon
+        mov             w1,  #GRAIN_HEIGHT-3
+1:
+        ld1             {v22.16b, v23.16b, v24.16b, v25.16b}, [x19], #64
+        bl              get_grain_row_neon
+        and             v0.16b,  v22.16b, v29.16b
+        mov             v1.16b,  v16.16b
+        bl              add_uv_444_coeff_lag0_neon
+        mov             v0.16b,  v23.16b
+        mov             v1.16b,  v17.16b
+        mov             v16.16b, v2.16b
+        bl              add_uv_444_coeff_lag0_neon
+        ld1             {v26.16b}, [x19], #16
+        mov             v0.16b,  v24.16b
+        mov             v1.16b,  v18.16b
+        mov             v17.16b, v2.16b
+        bl              add_uv_444_coeff_lag0_neon
+        add             x19, x19, #2
+        mov             v0.16b,  v25.16b
+        mov             v1.16b,  v19.16b
+        mov             v18.16b, v2.16b
+        bl              add_uv_444_coeff_lag0_neon
+        and             v0.16b,  v26.16b, v30.16b
+        mov             v1.16b,  v20.16b
+        mov             v19.16b, v2.16b
+        bl              add_uv_444_coeff_lag0_neon
+        mov             v20.16b, v2.16b
+        subs            w1,  w1,  #1
+        store_grain_row v16, v17, v18, v19, v20, v21
+        b.gt            1b
+.endif
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag1):
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v27.16b}, [x4], #1 // ar_coeffs_y[0]
+        ld1r            {v28.16b}, [x4], #1 // ar_coeffs_y[1]
+        ld1r            {v29.16b}, [x4]     // ar_coeffs_y[2]
+.ifc \type, y
+        ldrsb           w4,  [x4, #1]       // ar_coeffs_y[3]
+.else
+        add             x4,  x4,  #2
+.endif
+
+        mov             w1,  #3
+.ifc \type, uv_444
+        ld1r            {v30.16b}, [x4]     // ar_coeffs_uv[4]
+        ldursb          w4,  [x4, #-1]      // ar_coeffs_uv[3]
+.endif
+        bl              generate_grain_rows_neon
+
+        mov             w1,  #GRAIN_HEIGHT - 3
+1:
+        sum_\type\()_lag1 v22, v16, v16, v17, left
+        sum_\type\()_lag1 v23, v16, v17, v18
+        sum_\type\()_lag1 v24, v17, v18, v19
+        sum_\type\()_lag1 v25, v18, v19, v20
+        sum_\type\()_lag1 v20, v19, v20, v21, right
+        get_grain_2     v21
+        subs            w1,  w1,  #1
+.ifc \type, uv_444
+        add             x19, x19, #2
+.endif
+        store_grain_row v22, v23, v24, v25, v20, v21
+        mov             v16.16b, v22.16b
+        mov             v17.16b, v23.16b
+        mov             v18.16b, v24.16b
+        mov             v19.16b, v25.16b
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag2):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v30.16b}, [x4]     // ar_coeffs_y[0-11], ar_coeffs_uv[0-12]
+
+        smov            w4,  v30.b[10]
+        smov            w17, v30.b[11]
+
+        mov             w1,  #3
+        bl              generate_grain_rows_neon
+
+        mov             w1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag2_left_neon
+        bl              sum_\type\()_lag2_mid_neon
+        bl              sum_\type\()_lag2_mid_neon
+        bl              sum_\type\()_lag2_mid_neon
+        bl              sum_\type\()_lag2_right_neon
+        get_grain_2     v16
+        subs            w1,  w1,  #1
+.ifc \type, uv_444
+        add             x19, x19, #2
+.endif
+        st1             {v16.h}[0], [x0], #2
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag3):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v29.16b, v30.16b}, [x4] // ar_coeffs_y[0-23], ar_coeffs_uv[0-24]
+        stp             d8,  d9,  [sp, #16]
+        stp             d10, d11, [sp, #32]
+        stp             d12, d13, [sp, #48]
+        stp             d14, d15, [sp, #64]
+        stp             x20, x21, [sp, #80]
+
+        smov            w4,  v30.b[5]
+        smov            w20, v30.b[6]
+        smov            w21, v30.b[7]
+
+        mov             w1,  #3
+        bl              generate_grain_rows_neon
+
+        mov             w1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag3_left_neon
+        bl              sum_\type\()_lag3_mid_neon
+        bl              sum_\type\()_lag3_mid_neon
+        bl              sum_\type\()_lag3_mid_neon
+        bl              sum_\type\()_lag3_right_neon
+        get_grain_2     v16
+        subs            w1,  w1,  #1
+.ifc \type, uv_444
+        add             x19, x19, #2
+.endif
+        st1             {v16.h}[0], [x0], #2
+        b.gt            1b
+
+        ldp             x20, x21, [sp, #80]
+        ldp             d14, d15, [sp, #64]
+        ldp             d12, d13, [sp, #48]
+        ldp             d10, d11, [sp, #32]
+        ldp             d8,  d9,  [sp, #16]
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+jumptable gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag0) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag1) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag2) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag3) - gen_grain_\type\()_tbl
+endjumptable
+.endm
+
+gen_grain_82 y
+gen_grain_82 uv_444
+
+.macro set_height dst, type
+.ifc \type, uv_420
+        mov             \dst,  #SUB_GRAIN_HEIGHT-3
+.else
+        mov             \dst,  #GRAIN_HEIGHT-3
+.endif
+.endm
+
+.macro increment_y_ptr reg, type
+.ifc \type, uv_420
+        add             \reg, \reg, #2*GRAIN_WIDTH-(3*32)
+.else
+        sub             \reg, \reg, #3*32-GRAIN_WIDTH
+.endif
+.endm
+
+.macro gen_grain_44 type
+function generate_grain_\type\()_8bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x30, x19, [sp, #-96]!
+
+        mov             w13, w3
+        mov             w14, #28
+        add             x19, x1,  #3*GRAIN_WIDTH-3
+        mov             x1,  x2
+        mul             w13, w13, w14
+
+        movrel          x3,  X(gaussian_sequence)
+        ldr             w2,  [x1, #FGD_SEED]
+        ldr             w9,  [x1, #FGD_GRAIN_SCALE_SHIFT]
+        add             x4,  x1,  #FGD_AR_COEFFS_UV
+        movrel          x16, gen_grain_\type\()_tbl
+        ldr             w17, [x1, #FGD_AR_COEFF_LAG]
+        add             w9,  w9,  #4
+        ldrsw           x17, [x16, w17, uxtw #2]
+        dup             v31.8h,  w9    // 4 + data->grain_scale_shift
+        add             x16, x16, x17
+        neg             v31.8h,  v31.8h
+
+        cmp             w13, #0
+        mov             w11, #0x49d8
+        mov             w14, #0xb524
+        add             x4,  x4,  w13, uxtw // Add offset to ar_coeffs_uv[1]
+        csel            w11, w11, w14, ne
+
+        ldr             w7,  [x1, #FGD_AR_COEFF_SHIFT]
+        mov             w8,  #1
+        mov             w10, #1
+        lsl             w8,  w8,  w7        // 1 << ar_coeff_shift
+        lsl             w10, w10, w9        // 1 << (4 + data->grain_scale_shift)
+        lsr             w8,  w8,  #1        // 1 << (ar_coeff_shift - 1)
+        lsr             w10, w10, #1        // 1 << (4 + data->grain_scale_shift - 1)
+        mov             w5,  #127
+        mov             w6,  #-128
+
+        eor             w2,  w2,  w11
+
+        br              x16
+
+L(generate_grain_\type\()_lag0):
+        AARCH64_VALID_JUMP_TARGET
+        dup             v28.8h,  w7
+        ld1r            {v27.16b}, [x4]     // ar_coeffs_uv[0]
+        movi            v0.16b,  #0
+        movi            v1.16b,  #255
+        ext             v29.16b, v0.16b,  v1.16b,  #13
+        ext             v30.16b, v1.16b,  v0.16b,  #7
+        neg             v28.8h,  v28.8h
+
+        mov             w1,  #3
+        bl              generate_grain_rows_44_neon
+        set_height      w1,  \type
+1:
+        bl              get_grain_row_44_neon
+.ifc \type, uv_420
+        add             x12, x19, #GRAIN_WIDTH
+.endif
+        mov             v0.16b,  v29.16b
+        mov             v1.16b,  v16.16b
+        bl              add_\type\()_coeff_lag0_neon
+        movi            v0.16b,  #255
+        mov             v1.16b,  v17.16b
+        mov             v16.16b, v2.16b
+        bl              add_\type\()_coeff_lag0_neon
+        mov             v0.16b,  v30.16b
+        mov             v1.16b,  v18.16b
+        mov             v17.16b, v2.16b
+        bl              add_\type\()_coeff_lag0_neon
+        mov             v18.16b, v2.16b
+        subs            w1,  w1,  #1
+        increment_y_ptr x19, \type
+        store_grain_row_44 v16, v17, v18
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag1):
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v27.16b}, [x4], #1 // ar_coeffs_uv[0]
+        ld1r            {v28.16b}, [x4], #1 // ar_coeffs_uv[1]
+        ld1r            {v29.16b}, [x4]     // ar_coeffs_uv[2]
+        add             x4,  x4,  #2
+
+        mov             w1,  #3
+        ld1r            {v30.16b}, [x4]     // ar_coeffs_u4[4]
+        ldursb          w4,  [x4, #-1]      // ar_coeffs_uv[3]
+        bl              generate_grain_rows_44_neon
+
+        set_height      w1,  \type
+1:
+        sum_\type\()_lag1 v20, v16, v16, v17, left
+        sum_\type\()_lag1 v21, v16, v17, v18
+        sum_\type\()_lag1 v18, v17, v18, v18, right
+        subs            w1,  w1,  #1
+        increment_y_ptr x19, \type
+        store_grain_row_44 v20, v21, v18
+        mov             v16.16b, v20.16b
+        mov             v17.16b, v21.16b
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag2):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v30.16b}, [x4]     // ar_coeffs_uv[0-12]
+
+        smov            w4,  v30.b[10]
+        smov            w17, v30.b[11]
+
+        mov             w1,  #3
+        bl              generate_grain_rows_44_neon
+
+        set_height      w1,  \type
+1:
+        bl              sum_\type\()_lag2_left_neon
+        bl              sum_\type\()_lag2_mid_neon
+        bl              sum_\type\()_lag2_right_neon
+        subs            w1,  w1,  #1
+        increment_y_ptr x19, \type
+        add             x0,  x0,  #GRAIN_WIDTH-48
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag3):
+        AARCH64_VALID_JUMP_TARGET
+        ldr             q29,      [x4]      // ar_coeffs_uv[0-15]
+        ldr             q30,      [x4, #16] // ar_coeffs_uv[16-24]
+        stp             d8,  d9,  [sp, #16]
+        stp             d10, d11, [sp, #32]
+        stp             d12, d13, [sp, #48]
+        stp             d14, d15, [sp, #64]
+        stp             x20, x21, [sp, #80]
+
+        smov            w4,  v30.b[5]
+        smov            w20, v30.b[6]
+        smov            w21, v30.b[7]
+
+        mov             w1,  #3
+        bl              generate_grain_rows_44_neon
+
+        set_height      w1,  \type
+1:
+        bl              sum_\type\()_lag3_left_neon
+        bl              sum_\type\()_lag3_mid_neon
+        bl              sum_\type\()_lag3_right_neon
+        subs            w1,  w1,  #1
+        increment_y_ptr x19, \type
+        add             x0,  x0,  #GRAIN_WIDTH-48
+        b.gt            1b
+
+        ldp             x20, x21, [sp, #80]
+        ldp             d14, d15, [sp, #64]
+        ldp             d12, d13, [sp, #48]
+        ldp             d10, d11, [sp, #32]
+        ldp             d8,  d9,  [sp, #16]
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+jumptable gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag0) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag1) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag2) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag3) - gen_grain_\type\()_tbl
+endjumptable
+.endm
+
+gen_grain_44 uv_420
+gen_grain_44 uv_422
+
+.macro gather_interleaved dst1, dst2, src1, src2, off
+        umov            w14, \src1[0+\off]
+        umov            w15, \src2[8+\off]
+        umov            w16, \src1[2+\off]
+        add             x14, x14, x3
+        umov            w17, \src2[10+\off]
+        add             x15, x15, x3
+        ld1             {\dst1}[0+\off],  [x14]
+        umov            w14, \src1[4+\off]
+        add             x16, x16, x3
+        ld1             {\dst2}[8+\off],  [x15]
+        umov            w15, \src2[12+\off]
+        add             x17, x17, x3
+        ld1             {\dst1}[2+\off],  [x16]
+        umov            w16, \src1[6+\off]
+        add             x14, x14, x3
+        ld1             {\dst2}[10+\off], [x17]
+        umov            w17, \src2[14+\off]
+        add             x15, x15, x3
+        ld1             {\dst1}[4+\off],  [x14]
+        add             x16, x16, x3
+        ld1             {\dst2}[12+\off], [x15]
+        add             x17, x17, x3
+        ld1             {\dst1}[6+\off],  [x16]
+        ld1             {\dst2}[14+\off], [x17]
+.endm
+
+.macro gather dst1, dst2, src1, src2
+        gather_interleaved \dst1, \dst2, \src1, \src2, 0
+        gather_interleaved \dst2, \dst1, \src2, \src1, 0
+        gather_interleaved \dst1, \dst2, \src1, \src2, 1
+        gather_interleaved \dst2, \dst1, \src2, \src1, 1
+.endm
+
+function gather32_neon
+        gather          v4.b, v5.b, v0.b, v1.b
+        ret
+endfunc
+
+function gather16_neon
+        gather_interleaved v4.b, v5.b, v0.b, v0.b, 0
+        gather_interleaved v4.b, v5.b, v0.b, v0.b, 1
+        ins             v4.d[1], v5.d[1]
+        ret
+endfunc
+
+const overlap_coeffs_0, align=4
+        .byte 27, 17, 0,  0,  0,  0,  0,  0
+        .byte 17, 27, 32, 32, 32, 32, 32, 32
+endconst
+
+const overlap_coeffs_1, align=4
+        .byte 23, 0,  0,  0,  0,  0,  0,  0
+        .byte 22, 32, 32, 32, 32, 32, 32, 32
+endconst
+
+.macro calc_offset offx, offy, src, sx, sy
+        and             \offy, \src,  #0xF     // randval & 0xF
+        lsr             \offx, \src,  #4       // randval >> 4
+.if \sy == 0
+        add             \offy, \offy, \offy    // 2 * (randval & 0xF)
+.endif
+.if \sx == 0
+        add             \offx, \offx, \offx    // 2 * (randval >> 4)
+.endif
+.endm
+
+.macro add_offset dst, offx, offy, src, stride
+        madd            \dst, \stride, \offy, \src // grain_lut += grain_stride * offy
+        add             \dst, \dst, \offx, uxtw // grain_lut += offx
+.endm
+
+// void dav1d_fgy_32x32_8bpc_neon(pixel *const dst, const pixel *const src,
+//                                const ptrdiff_t stride,
+//                                const uint8_t scaling[SCALING_SIZE],
+//                                const int scaling_shift,
+//                                const entry grain_lut[][GRAIN_WIDTH],
+//                                const int offsets[][2],
+//                                const int h, const ptrdiff_t clip,
+//                                const ptrdiff_t type);
+function fgy_32x32_8bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+        ldr             w11, [x6, #8]          // offsets[1][0]
+        ldr             w13, [x6, #4]          // offsets[0][1]
+        ldr             w15, [x6, #12]         // offsets[1][1]
+        ldr             w6,  [x6]              // offsets[0][0]
+        ldr             w8,  [sp, #16]         // clip
+        mov             x9,  #GRAIN_WIDTH      // grain_lut stride
+
+        neg             w4,  w4
+        dup             v29.8h,  w4            // -scaling_shift
+
+        movrel          x16, overlap_coeffs_0
+
+        cbz             w8,  1f
+        // clip
+        movi            v30.16b, #16
+        movi            v31.16b, #235
+        b               2f
+1:
+        // no clip
+        movi            v30.16b, #0
+        movi            v31.16b, #255
+2:
+
+        ld1             {v27.8b, v28.8b}, [x16] // overlap_coeffs
+
+        add             x5,  x5,  #9           // grain_lut += 9
+        add             x5,  x5,  x9,  lsl #3  // grain_lut += 8 * grain_stride
+        add             x5,  x5,  x9           // grain_lut += grain_stride
+
+        calc_offset     w11, w12, w11, 0,  0
+        calc_offset     w13, w14, w13, 0,  0
+        calc_offset     w15, w16, w15, 0,  0
+        calc_offset     w6,  w10, w6,  0,  0
+
+        add_offset      x12, w11, x12, x5,  x9
+        add_offset      x14, w13, x14, x5,  x9
+        add_offset      x16, w15, x16, x5,  x9
+        add_offset      x5,  w6,  x10, x5,  x9
+
+        ldr             w11, [sp, #24]         // type
+        movrel          x13, fgy_loop_tbl
+
+        add             x4,  x12, #32          // grain_lut += FG_BLOCK_SIZE * bx
+        add             x6,  x14, x9,  lsl #5  // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+
+        tst             w11, #1
+        ldrsw           x11, [x13, w11, uxtw #2]
+
+        add             x8,  x16, x9,  lsl #5  // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             x8,  x8,  #32          // grain_lut += FG_BLOCK_SIZE * bx
+
+        add             x11, x13, x11
+
+        b.eq            1f
+        // y overlap
+        dup             v6.16b,  v27.b[0]
+        dup             v7.16b,  v27.b[1]
+        mov             w10, w7                // backup actual h
+        mov             w7,  #2
+1:
+        br              x11
+endfunc
+
+function fgy_loop_neon
+.macro fgy ox, oy
+L(loop_\ox\oy):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        ld1             {v0.16b,  v1.16b},  [x1],  x2 // src
+.if \ox
+        ld1             {v20.8b},           [x4],  x9 // grain_lut old
+.endif
+.if \oy
+        ld1             {v22.16b, v23.16b}, [x6],  x9 // grain_lut top
+.endif
+.if \ox && \oy
+        ld1             {v21.8b},           [x8],  x9 // grain_lut top old
+.endif
+        ld1             {v18.16b, v19.16b}, [x5],  x9 // grain_lut
+
+        bl              gather32_neon
+
+.if \ox
+        smull           v20.8h,  v20.8b,  v27.8b
+        smlal           v20.8h,  v18.8b,  v28.8b
+.endif
+
+.if \oy
+.if \ox
+        smull           v21.8h,  v21.8b,  v27.8b
+        smlal           v21.8h,  v22.8b,  v28.8b
+        sqrshrn         v20.8b,  v20.8h,  #5
+        sqrshrn         v21.8b,  v21.8h,  #5
+.endif
+
+.if \ox
+        smull           v16.8h,  v20.8b,  v7.8b
+.else
+        smull           v16.8h,  v18.8b,  v7.8b
+.endif
+        smull2          v17.8h,  v18.16b, v7.16b
+        smull           v18.8h,  v19.8b,  v7.8b
+        smull2          v19.8h,  v19.16b, v7.16b
+.if \ox
+        smlal           v16.8h,  v21.8b,  v6.8b
+.else
+        smlal           v16.8h,  v22.8b,  v6.8b
+.endif
+        smlal2          v17.8h,  v22.16b, v6.16b
+        smlal           v18.8h,  v23.8b,  v6.8b
+        smlal2          v19.8h,  v23.16b, v6.16b
+        sqrshrn         v22.8b,  v16.8h,  #5
+        sqrshrn2        v22.16b, v17.8h,  #5
+        sqrshrn         v23.8b,  v18.8h,  #5
+        sqrshrn2        v23.16b, v19.8h,  #5
+.endif
+
+        // sxtl of grain
+.if \oy
+        sxtl            v16.8h,  v22.8b
+        sxtl2           v17.8h,  v22.16b
+        sxtl            v18.8h,  v23.8b
+        sxtl2           v19.8h,  v23.16b
+.elseif \ox
+        sqrshrn         v20.8b,  v20.8h,  #5
+        sxtl2           v17.8h,  v18.16b
+        sxtl            v18.8h,  v19.8b
+        sxtl2           v19.8h,  v19.16b
+        sxtl            v16.8h,  v20.8b
+.else
+        sxtl            v16.8h,  v18.8b
+        sxtl2           v17.8h,  v18.16b
+        sxtl            v18.8h,  v19.8b
+        sxtl2           v19.8h,  v19.16b
+.endif
+
+        uxtl            v2.8h,   v4.8b   // scaling
+        uxtl2           v3.8h,   v4.16b
+        uxtl            v4.8h,   v5.8b
+        uxtl2           v5.8h,   v5.16b
+
+        mul             v16.8h,  v16.8h,  v2.8h   // scaling * grain
+        mul             v17.8h,  v17.8h,  v3.8h
+        mul             v18.8h,  v18.8h,  v4.8h
+        mul             v19.8h,  v19.8h,  v5.8h
+
+        srshl           v16.8h,  v16.8h,  v29.8h  // round2(scaling * grain, scaling_shift)
+        srshl           v17.8h,  v17.8h,  v29.8h
+        srshl           v18.8h,  v18.8h,  v29.8h
+        srshl           v19.8h,  v19.8h,  v29.8h
+
+        uaddw           v16.8h,  v16.8h,  v0.8b   // *src + noise
+        uaddw2          v17.8h,  v17.8h,  v0.16b
+        uaddw           v18.8h,  v18.8h,  v1.8b
+        uaddw2          v19.8h,  v19.8h,  v1.16b
+
+        sqxtun          v0.8b,   v16.8h
+        sqxtun2         v0.16b,  v17.8h
+        sqxtun          v1.8b,   v18.8h
+        sqxtun2         v1.16b,  v19.8h
+
+        umax            v0.16b,  v0.16b,  v30.16b
+        umax            v1.16b,  v1.16b,  v30.16b
+        umin            v0.16b,  v0.16b,  v31.16b
+        umin            v1.16b,  v1.16b,  v31.16b
+
+        subs            w7,  w7,  #1
+.if \oy
+        dup             v6.16b,  v28.b[0]
+        dup             v7.16b,  v28.b[1]
+.endif
+        st1             {v0.16b,  v1.16b},  [x0], x2 // dst
+        b.gt            1b
+
+.if \oy
+        cmp             w10, #2
+        sub             w7,  w10, #2           // restore actual remaining h
+        b.gt            L(loop_\ox\()0)
+.endif
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+.endm
+
+        fgy             0, 0
+        fgy             0, 1
+        fgy             1, 0
+        fgy             1, 1
+endfunc
+
+jumptable fgy_loop_tbl
+        .word L(loop_00) - fgy_loop_tbl
+        .word L(loop_01) - fgy_loop_tbl
+        .word L(loop_10) - fgy_loop_tbl
+        .word L(loop_11) - fgy_loop_tbl
+endjumptable
+
+// void dav1d_fguv_32x32_420_8bpc_neon(pixel *const dst,
+//                                     const pixel *const src,
+//                                     const ptrdiff_t stride,
+//                                     const uint8_t scaling[SCALING_SIZE],
+//                                     const Dav1dFilmGrainData *const data,
+//                                     const entry grain_lut[][GRAIN_WIDTH],
+//                                     const pixel *const luma_row,
+//                                     const ptrdiff_t luma_stride,
+//                                     const int offsets[][2],
+//                                     const ptrdiff_t h, const ptrdiff_t uv,
+//                                     const ptrdiff_t is_id,
+//                                     const ptrdiff_t type);
+.macro fguv layout, sx, sy
+function fguv_32x32_\layout\()_8bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30,      [sp, #-32]!
+        str             d8,       [sp, #16]
+        ldp             x8,  x9,  [sp, #32]    // offsets, h
+        ldp             x10, x11, [sp, #48]    // uv, is_id
+
+        ldr             w13, [x4, #FGD_SCALING_SHIFT]
+        ldr             w12, [x4, #FGD_CLIP_TO_RESTRICTED_RANGE]
+        neg             w13, w13               // -scaling_shift
+
+        // !csfl
+        add             x10, x4,  x10, lsl #2  // + 4*uv
+        add             x14, x10, #FGD_UV_LUMA_MULT
+        add             x15, x10, #FGD_UV_MULT
+        add             x10, x10, #FGD_UV_OFFSET
+        ld1             {v8.h}[0], [x14]       // uv_luma_mult
+        ld1r            {v24.8h},  [x10]       // uv_offset
+        ld1             {v8.h}[1], [x15]       // uv_mult
+
+        dup             v29.8h,  w13           // -scaling_shift
+
+        cbz             w12, 1f
+        // clip
+        movi            v30.16b, #16
+        movi            v31.16b, #240
+        cbz             w11, 2f
+        // is_id
+        movi            v31.16b, #235
+        b               2f
+1:
+        // no clip
+        movi            v30.16b, #0
+        movi            v31.16b, #255
+2:
+
+        ldr             w12, [x8, #8]          // offsets[1][0]
+        ldr             w14, [x8, #4]          // offsets[0][1]
+        ldr             w16, [x8, #12]         // offsets[1][1]
+        ldr             w8,  [x8]              // offsets[0][0]
+
+        mov             x10, #GRAIN_WIDTH      // grain_lut stride
+
+        add             x5,  x5,  #(3 + (2 >> \sx)*3) // grain_lut += 9 or 6
+.if \sy
+        add             x5,  x5,  x10, lsl #2  // grain_lut += 4 * grain_stride
+        add             x5,  x5,  x10, lsl #1  // grain_lut += 2 * grain_stride
+.else
+        add             x5,  x5,  x10, lsl #3  // grain_lut += 8 * grain_stride
+        add             x5,  x5,  x10          // grain_lut += grain_stride
+.endif
+
+        calc_offset     w12, w13, w12, \sx, \sy
+        calc_offset     w14, w15, w14, \sx, \sy
+        calc_offset     w16, w17, w16, \sx, \sy
+        calc_offset     w8,  w11, w8,  \sx, \sy
+
+        add_offset      x13, w12, x13, x5,  x10
+        add_offset      x15, w14, x15, x5,  x10
+        add_offset      x17, w16, x17, x5,  x10
+        add_offset      x5,  w8,  x11, x5,  x10
+
+        add             x4,  x13, #(32 >> \sx) // grain_lut += FG_BLOCK_SIZE * bx
+        add             x8,  x15, x10, lsl #(5 - \sy) // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             x11, x17, x10, lsl #(5 - \sy) // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             x11, x11, #(32 >> \sx) // grain_lut += FG_BLOCK_SIZE * bx
+
+        ldr             w13, [sp, #64]         // type
+
+        movrel          x16, overlap_coeffs_\sx
+        movrel          x14, fguv_loop_sx\sx\()_tbl
+
+        ld1             {v27.8b, v28.8b}, [x16] // overlap_coeffs
+        tst             w13, #1
+        ldrsw           x13, [x14, w13, uxtw #2]
+
+        b.eq            1f
+        // y overlap
+        sub             w12, w9,  #(2 >> \sy)  // backup remaining h
+        mov             w9,  #(2 >> \sy)
+
+1:
+        add             x13, x14, x13
+
+.if \sy
+        movi            v25.16b, #23
+        movi            v26.16b, #22
+.else
+        movi            v25.16b, #27
+        movi            v26.16b, #17
+.endif
+
+.if \sy
+        add             x7,  x7,  x7           // luma_stride *= 2
+.endif
+
+        br              x13
+endfunc
+.endm
+
+fguv 420, 1, 1
+fguv 422, 1, 0
+fguv 444, 0, 0
+
+function fguv_loop_sx0_neon
+.macro fguv_loop_sx0 csfl, ox, oy
+L(fguv_loop_sx0_csfl\csfl\()_\ox\oy):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        ld1             {v0.16b,  v1.16b},  [x6],  x7  // luma
+        ld1             {v6.16b,  v7.16b},  [x1],  x2  // src
+.if \ox
+        ld1             {v20.8b},           [x4],  x10 // grain_lut old
+.endif
+.if \oy
+        ld1             {v22.16b, v23.16b}, [x8],  x10 // grain_lut top
+.endif
+.if \ox && \oy
+        ld1             {v21.8b},           [x11], x10 // grain_lut top old
+.endif
+        ld1             {v18.16b, v19.16b}, [x5],  x10 // grain_lut
+
+.if !\csfl
+        uxtl            v2.8h,   v0.8b
+        uxtl2           v3.8h,   v0.16b
+        uxtl            v4.8h,   v1.8b
+        uxtl2           v5.8h,   v1.16b
+        uxtl            v0.8h,   v6.8b
+        uxtl2           v1.8h,   v6.16b
+        uxtl            v16.8h,  v7.8b
+        uxtl2           v17.8h,  v7.16b
+        mul             v2.8h,   v2.8h,   v8.h[0]
+        mul             v3.8h,   v3.8h,   v8.h[0]
+        mul             v4.8h,   v4.8h,   v8.h[0]
+        mul             v5.8h,   v5.8h,   v8.h[0]
+        mul             v0.8h,   v0.8h,   v8.h[1]
+        mul             v1.8h,   v1.8h,   v8.h[1]
+        mul             v16.8h,  v16.8h,  v8.h[1]
+        mul             v17.8h,  v17.8h,  v8.h[1]
+        sqadd           v2.8h,   v2.8h,   v0.8h
+        sqadd           v3.8h,   v3.8h,   v1.8h
+        sqadd           v4.8h,   v4.8h,   v16.8h
+        sqadd           v5.8h,   v5.8h,   v17.8h
+        sshr            v2.8h,   v2.8h,   #6
+        sshr            v3.8h,   v3.8h,   #6
+        sshr            v4.8h,   v4.8h,   #6
+        sshr            v5.8h,   v5.8h,   #6
+        add             v2.8h,   v2.8h,   v24.8h
+        add             v3.8h,   v3.8h,   v24.8h
+        add             v4.8h,   v4.8h,   v24.8h
+        add             v5.8h,   v5.8h,   v24.8h
+        sqxtun          v0.8b,   v2.8h
+        sqxtun2         v0.16b,  v3.8h
+        sqxtun          v1.8b,   v4.8h
+        sqxtun2         v1.16b,  v5.8h
+.endif
+
+        bl              gather32_neon
+
+.if \ox
+        smull           v20.8h,  v20.8b,  v27.8b
+        smlal           v20.8h,  v18.8b,  v28.8b
+.endif
+
+.if \oy
+.if \ox
+        smull           v21.8h,  v21.8b,  v27.8b
+        smlal           v21.8h,  v22.8b,  v28.8b
+        sqrshrn         v20.8b,  v20.8h,  #5
+        sqrshrn         v21.8b,  v21.8h,  #5
+.endif
+
+.if \ox
+        smull           v16.8h,  v20.8b,  v26.8b
+.else
+        smull           v16.8h,  v18.8b,  v26.8b
+.endif
+        smull2          v17.8h,  v18.16b, v26.16b
+        smull           v18.8h,  v19.8b,  v26.8b
+        smull2          v19.8h,  v19.16b, v26.16b
+.if \ox
+        smlal           v16.8h,  v21.8b,  v25.8b
+.else
+        smlal           v16.8h,  v22.8b,  v25.8b
+.endif
+        smlal2          v17.8h,  v22.16b, v25.16b
+        smlal           v18.8h,  v23.8b,  v25.8b
+        smlal2          v19.8h,  v23.16b, v25.16b
+        sqrshrn         v22.8b,  v16.8h,  #5
+        sqrshrn2        v22.16b, v17.8h,  #5
+        sqrshrn         v23.8b,  v18.8h,  #5
+        sqrshrn2        v23.16b, v19.8h,  #5
+.endif
+
+        // sxtl of grain
+.if \oy
+        sxtl            v16.8h,  v22.8b
+        sxtl2           v17.8h,  v22.16b
+        sxtl            v18.8h,  v23.8b
+        sxtl2           v19.8h,  v23.16b
+.elseif \ox
+        sqrshrn         v20.8b,  v20.8h,  #5
+        sxtl2           v17.8h,  v18.16b
+        sxtl            v18.8h,  v19.8b
+        sxtl2           v19.8h,  v19.16b
+        sxtl            v16.8h,  v20.8b
+.else
+        sxtl            v16.8h,  v18.8b
+        sxtl2           v17.8h,  v18.16b
+        sxtl            v18.8h,  v19.8b
+        sxtl2           v19.8h,  v19.16b
+.endif
+
+        uxtl            v2.8h,   v4.8b   // scaling
+        uxtl2           v3.8h,   v4.16b
+        uxtl            v4.8h,   v5.8b
+        uxtl2           v5.8h,   v5.16b
+
+        mul             v16.8h,  v16.8h,  v2.8h   // scaling * grain
+        mul             v17.8h,  v17.8h,  v3.8h
+        mul             v18.8h,  v18.8h,  v4.8h
+        mul             v19.8h,  v19.8h,  v5.8h
+
+        srshl           v16.8h,  v16.8h,  v29.8h  // round2(scaling * grain, scaling_shift)
+        srshl           v17.8h,  v17.8h,  v29.8h
+        srshl           v18.8h,  v18.8h,  v29.8h
+        srshl           v19.8h,  v19.8h,  v29.8h
+
+        uaddw           v16.8h,  v16.8h,  v6.8b   // *src + noise
+        uaddw2          v17.8h,  v17.8h,  v6.16b
+        uaddw           v18.8h,  v18.8h,  v7.8b
+        uaddw2          v19.8h,  v19.8h,  v7.16b
+
+        sqxtun          v0.8b,   v16.8h
+        sqxtun2         v0.16b,  v17.8h
+        sqxtun          v1.8b,   v18.8h
+        sqxtun2         v1.16b,  v19.8h
+
+        umax            v0.16b,  v0.16b,  v30.16b
+        umax            v1.16b,  v1.16b,  v30.16b
+        umin            v0.16b,  v0.16b,  v31.16b
+        umin            v1.16b,  v1.16b,  v31.16b
+
+        subs            w9,  w9,  #1
+.if \oy
+        dup             v25.16b, v28.b[0]
+        dup             v26.16b, v28.b[1]
+.endif
+        st1             {v0.16b,  v1.16b},  [x0], x2 // dst
+        b.gt            1b
+
+.if \oy
+        cmp             w12, #0
+        mov             w9,  w12               // restore actual remaining h
+        b.gt            L(fguv_loop_sx0_csfl\csfl\()_\ox\()0)
+.endif
+        b               9f
+.endm
+        fguv_loop_sx0   0, 0, 0
+        fguv_loop_sx0   0, 0, 1
+        fguv_loop_sx0   0, 1, 0
+        fguv_loop_sx0   0, 1, 1
+        fguv_loop_sx0   1, 0, 0
+        fguv_loop_sx0   1, 0, 1
+        fguv_loop_sx0   1, 1, 0
+        fguv_loop_sx0   1, 1, 1
+
+9:
+        ldr             d8,       [sp, #16]
+        ldr             x30,      [sp], #32
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+jumptable fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl0_00) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl0_01) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl0_10) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl0_11) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl1_00) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl1_01) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl1_10) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl1_11) - fguv_loop_sx0_tbl
+endjumptable
+
+function fguv_loop_sx1_neon
+.macro fguv_loop_sx1 csfl, ox, oy
+L(fguv_loop_sx1_csfl\csfl\()_\ox\oy):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        ld1             {v0.16b, v1.16b},  [x6],  x7  // luma
+        ld1             {v6.16b},          [x1],  x2  // src
+.if \ox
+        ld1             {v20.8b},          [x4],  x10 // grain_lut old
+.endif
+.if \oy
+        ld1             {v22.16b},         [x8],  x10 // grain_lut top
+.endif
+.if \ox && \oy
+        ld1             {v21.8b},          [x11], x10 // grain_lut top old
+.endif
+        ld1             {v18.16b},         [x5],  x10 // grain_lut
+
+        uaddlp          v2.8h,   v0.16b
+        uaddlp          v3.8h,   v1.16b
+.if \csfl
+        rshrn           v0.8b,   v2.8h,   #1
+        rshrn2          v0.16b,  v3.8h,   #1
+.else
+        urshr           v2.8h,   v2.8h,   #1
+        urshr           v3.8h,   v3.8h,   #1
+        uxtl            v0.8h,   v6.8b
+        uxtl2           v1.8h,   v6.16b
+        mul             v2.8h,   v2.8h,   v8.h[0]
+        mul             v3.8h,   v3.8h,   v8.h[0]
+        mul             v0.8h,   v0.8h,   v8.h[1]
+        mul             v1.8h,   v1.8h,   v8.h[1]
+        sqadd           v2.8h,   v2.8h,   v0.8h
+        sqadd           v3.8h,   v3.8h,   v1.8h
+        sshr            v2.8h,   v2.8h,   #6
+        sshr            v3.8h,   v3.8h,   #6
+        add             v2.8h,   v2.8h,   v24.8h
+        add             v3.8h,   v3.8h,   v24.8h
+        sqxtun          v0.8b,   v2.8h
+        sqxtun2         v0.16b,  v3.8h
+.endif
+
+        bl              gather16_neon
+
+.if \ox
+        smull           v20.8h,  v20.8b,  v27.8b
+        smlal           v20.8h,  v18.8b,  v28.8b
+.endif
+
+.if \oy
+.if \ox
+        smull           v21.8h,  v21.8b,  v27.8b
+        smlal           v21.8h,  v22.8b,  v28.8b
+        sqrshrn         v20.8b,  v20.8h,  #5
+        sqrshrn         v21.8b,  v21.8h,  #5
+.endif
+
+.if \ox
+        smull           v16.8h,  v20.8b,  v26.8b
+.else
+        smull           v16.8h,  v18.8b,  v26.8b
+.endif
+        smull2          v17.8h,  v18.16b, v26.16b
+.if \ox
+        smlal           v16.8h,  v21.8b,  v25.8b
+.else
+        smlal           v16.8h,  v22.8b,  v25.8b
+.endif
+        smlal2          v17.8h,  v22.16b, v25.16b
+        sqrshrn         v22.8b,  v16.8h,  #5
+        sqrshrn2        v22.16b, v17.8h,  #5
+.endif
+
+        // sxtl of grain
+.if \oy
+        sxtl            v16.8h,  v22.8b
+        sxtl2           v17.8h,  v22.16b
+.elseif \ox
+        sqrshrn         v20.8b,  v20.8h,  #5
+        sxtl2           v17.8h,  v18.16b
+        sxtl            v16.8h,  v20.8b
+.else
+        sxtl            v16.8h,  v18.8b
+        sxtl2           v17.8h,  v18.16b
+.endif
+
+        uxtl            v2.8h,   v4.8b   // scaling
+        uxtl2           v3.8h,   v4.16b
+
+        mul             v16.8h,  v16.8h,  v2.8h   // scaling * grain
+        mul             v17.8h,  v17.8h,  v3.8h
+
+        srshl           v16.8h,  v16.8h,  v29.8h  // round2(scaling * grain, scaling_shift)
+        srshl           v17.8h,  v17.8h,  v29.8h
+
+        uaddw           v16.8h,  v16.8h,  v6.8b   // *src + noise
+        uaddw2          v17.8h,  v17.8h,  v6.16b
+
+        sqxtun          v0.8b,   v16.8h
+        sqxtun2         v0.16b,  v17.8h
+
+        umax            v0.16b,  v0.16b,  v30.16b
+        umin            v0.16b,  v0.16b,  v31.16b
+
+.if \oy
+        mov             v16.16b, v25.16b
+.endif
+        subs            w9,  w9,  #1
+.if \oy
+        mov             v25.16b, v26.16b
+        mov             v26.16b, v16.16b
+.endif
+        st1             {v0.16b},  [x0], x2 // dst
+        b.gt            1b
+
+.if \oy
+        cmp             w12, #0
+        mov             w9,  w12               // restore actual remaining h
+        b.gt            L(fguv_loop_sx1_csfl\csfl\()_\ox\()0)
+.endif
+
+        b               9f
+.endm
+        fguv_loop_sx1   0, 0, 0
+        fguv_loop_sx1   0, 0, 1
+        fguv_loop_sx1   0, 1, 0
+        fguv_loop_sx1   0, 1, 1
+        fguv_loop_sx1   1, 0, 0
+        fguv_loop_sx1   1, 0, 1
+        fguv_loop_sx1   1, 1, 0
+        fguv_loop_sx1   1, 1, 1
+
+9:
+        ldr             d8,       [sp, #16]
+        ldr             x30,      [sp], #32
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+jumptable fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl0_00) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl0_01) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl0_10) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl0_11) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl1_00) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl1_01) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl1_10) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl1_11) - fguv_loop_sx1_tbl
+endjumptable
diff --git a/media/libdav1d/src/src/arm/64/filmgrain16.S b/media/libdav1d/src/src/arm/64/filmgrain16.S
new file mode 100644
index 0000000000..aa6b75b171
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/filmgrain16.S
@@ -0,0 +1,2002 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * Copyright © 2021, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+#include "src/arm/asm-offsets.h"
+
+#define GRAIN_WIDTH 82
+#define GRAIN_HEIGHT 73
+
+#define SUB_GRAIN_WIDTH 44
+#define SUB_GRAIN_HEIGHT 38
+
+.macro increment_seed steps, shift=1
+        lsr             w11, w2,  #3
+        lsr             w12, w2,  #12
+        lsr             w13, w2,  #1
+        eor             w11, w2,  w11                     // (r >> 0) ^ (r >> 3)
+        eor             w12, w12, w13                     // (r >> 12) ^ (r >> 1)
+        eor             w11, w11, w12                     // (r >> 0) ^ (r >> 3) ^ (r >> 12) ^ (r >> 1)
+.if \shift
+        lsr             w2,  w2,  #\steps
+.endif
+        and             w11, w11, #((1 << \steps) - 1)    // bit
+.if \shift
+        orr             w2,  w2,  w11, lsl #(16 - \steps) // *state
+.else
+        orr             w2,  w2,  w11, lsl #16            // *state
+.endif
+.endm
+
+.macro read_rand dest, bits, age
+        ubfx            \dest,  x2,   #16 - \bits - \age, #\bits
+.endm
+
+.macro read_shift_rand dest, bits
+        ubfx            \dest,  x2,   #17 - \bits, #\bits
+        lsr             w2,  w2,  #1
+.endm
+
+// special calling convention:
+// w2 holds seed
+// x3 holds dav1d_gaussian_sequence
+// clobbers x11-x15
+// returns in v0.8h
+function get_gaussian_neon
+        increment_seed  4
+        read_rand       x14, 11,  3
+        read_rand       x15, 11,  2
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[0], [x14]
+        read_rand       x14, 11,  1
+        ld1             {v0.h}[1], [x15]
+        add             x14, x3,  x14, lsl #1
+        read_rand       x15, 11,  0
+        increment_seed  4
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[2], [x14]
+        read_rand       x14, 11,  3
+        ld1             {v0.h}[3], [x15]
+        add             x14, x3,  x14, lsl #1
+        read_rand       x15, 11,  2
+        ld1             {v0.h}[4], [x14]
+        add             x15, x3,  x15, lsl #1
+        read_rand       x14, 11,  1
+        ld1             {v0.h}[5], [x15]
+        read_rand       x15, 11,  0
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[6], [x14]
+        ld1             {v0.h}[7], [x15]
+        ret
+endfunc
+
+.macro store_grain_row r0, r1, r2, r3, r4, r5
+        st1             {\r0\().16b,\r1\().16b}, [x0], #32
+        st1             {\r2\().16b,\r3\().16b}, [x0], #32
+        st1             {\r4\().16b},  [x0], #16
+        st1             {\r5\().h}[0], [x0], #2
+.endm
+
+function get_grain_2_neon
+        increment_seed  2
+        read_rand       x14, 11,  1
+        read_rand       x15, 11,  0
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[0], [x14]
+        ld1             {v0.h}[1], [x15]
+        srshl           v0.4h,   v0.4h,   v31.4h
+        ret
+endfunc
+
+.macro get_grain_2 dst
+        bl              get_grain_2_neon
+.ifnc \dst, v0
+        mov             \dst\().8b, v0.8b
+.endif
+.endm
+
+function get_grain_4_neon
+        increment_seed  4
+        read_rand       x14, 11,  3
+        read_rand       x15, 11,  2
+        add             x14, x3,  x14, lsl #1
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[0], [x14]
+        read_rand       x14, 11,  1
+        ld1             {v0.h}[1], [x15]
+        add             x14, x3,  x14, lsl #1
+        read_rand       x15, 11,  0
+        add             x15, x3,  x15, lsl #1
+        ld1             {v0.h}[2], [x14]
+        ld1             {v0.h}[3], [x15]
+        srshl           v0.4h,   v0.4h,   v31.4h
+        ret
+endfunc
+
+.macro get_grain_4 dst
+        bl              get_grain_4_neon
+.ifnc \dst, v0
+        mov             \dst\().8b, v0.8b
+.endif
+.endm
+
+// w15 holds the number of entries to produce
+// w14, w16 and w17 hold the previous output entries
+// v0 holds the vector of produced entries
+// v1 holds the input vector of sums from above
+.macro output_lag n
+function output_lag\n\()_neon
+1:
+        read_shift_rand x13, 11
+        mov             w11, v1.s[0]
+        ldrsh           w12, [x3, x13, lsl #1]
+        ext             v0.16b,  v0.16b,  v0.16b,  #2
+.if \n == 1
+        madd            w11, w14, w4,  w11        // sum (above) + *coeff * prev output
+.elseif \n == 2
+        madd            w11, w16, w4,  w11        // sum (above) + *coeff * prev output 1
+        madd            w11, w14, w17, w11        // += *coeff * prev output 2
+        mov             w16, w14
+.else
+        madd            w11, w17, w4,  w11        // sum (above) + *coeff * prev output 1
+        madd            w11, w16, w20, w11        // sum (above) + *coeff * prev output 2
+        madd            w11, w14, w21, w11        // += *coeff * prev output 3
+        mov             w17, w16
+        mov             w16, w14
+.endif
+        add             w14, w11, w8              // 1 << (ar_coeff_shift - 1)
+        add             w12, w12, w10             // 1 << (4 - bitdepth_min_8 + grain_scale_shift - 1)
+        asr             w14, w14, w7              // >> ar_coeff_shift
+        asr             w12, w12, w9              // >> (4 - bitdepth_min_8 + grain_scale_shift)
+        add             w14, w14, w12
+        cmp             w14, w5
+        csel            w14, w14, w5,  le
+        cmp             w14, w6
+        csel            w14, w14, w6,  ge
+        subs            w15, w15, #1
+        ext             v1.16b,  v1.16b,  v1.16b,  #4
+        ins             v0.h[7], w14
+        b.gt            1b
+        ret
+endfunc
+.endm
+
+output_lag 1
+output_lag 2
+output_lag 3
+
+
+function sum_lag1_above_neon
+        sub             x12, x0,  #1*GRAIN_WIDTH*2 - 16
+        ld1             {v18.8h}, [x12] // load top right
+
+        ext             v0.16b,  v16.16b, v17.16b, #14 // top left, top mid
+        ext             v1.16b,  v17.16b, v18.16b, #2  // top mid, top right
+
+        smull           v4.4s,   v17.4h,  v28.4h
+        smlal           v4.4s,   v0.4h,   v27.4h
+        smlal           v4.4s,   v1.4h,   v29.4h
+        smull2          v5.4s,   v17.8h,  v28.8h
+        smlal2          v5.4s,   v0.8h,   v27.8h
+        smlal2          v5.4s,   v1.8h,   v29.8h
+
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+
+        ret
+endfunc
+
+.macro sum_lag_n_body lag, type, uv_layout, edge, elems, uv_coeff
+        bl              sum_\lag\()_above_neon
+.ifc \type, uv_420
+        add             x12, x19, #GRAIN_WIDTH*2
+        ld1             {v22.8h, v23.8h}, [x19], #32
+        ld1             {v24.8h, v25.8h}, [x12]
+        addp            v22.8h,  v22.8h,  v23.8h
+        addp            v23.8h,  v24.8h,  v25.8h
+        add             v22.8h,  v22.8h,  v23.8h
+        srshr           v0.8h,   v22.8h,  #2
+.endif
+.ifc \type, uv_422
+        ld1             {v22.8h, v23.8h}, [x19], #32
+        addp            v22.8h,  v22.8h,  v23.8h
+        srshr           v0.8h,   v22.8h,  #1
+.endif
+.ifc \type, uv_444
+        ld1             {v0.8h}, [x19], #16
+.endif
+.if \uv_layout
+.ifnb \uv_coeff
+        dup             v1.8b,   \uv_coeff
+        sxtl            v1.8h,   v1.8b
+        smlal           v4.4s,   v0.4h,   v1.4h
+        smlal2          v5.4s,   v0.8h,   v1.8h
+.else
+        smlal           v4.4s,   v0.4h,   v30.4h
+        smlal2          v5.4s,   v0.8h,   v30.8h
+.endif
+.endif
+.if \uv_layout && \elems == 8
+        b               sum_\lag\()_y_\edge\()_start
+.elseif \uv_layout == 444 && \elems == 7
+        b               sum_\lag\()_y_\edge\()_start
+.elseif \uv_layout == 422 && \elems == 1
+        b               sum_\lag\()_uv_420_\edge\()_start
+.else
+sum_\lag\()_\type\()_\edge\()_start:
+.if \elems > 4
+.ifc \edge, left
+        increment_seed  4
+        read_rand       x12, 11,  3
+        read_rand       x13, 11,  2
+        read_rand       x14, 11,  1
+        add             x12, x3,  x12, lsl #1
+        add             x13, x3,  x13, lsl #1
+        add             x14, x3,  x14, lsl #1
+        ld1             {v0.h}[5], [x12]
+        ld1             {v0.h}[6], [x13]
+        ld1             {v0.h}[7], [x14]
+        lsl             x2,  x2,  #1             // shift back the state as if we'd done increment_seed with shift=0
+        srshl           v0.8h,   v0.8h,   v31.8h
+        ext             v4.16b,  v4.16b,  v4.16b,  #12
+.ifc \lag, lag3
+        smov            w17, v0.h[5]
+.endif
+.ifnc \lag, lag1
+        smov            w16, v0.h[6]
+.endif
+        smov            w14, v0.h[7]
+
+        mov             v1.16b,  v4.16b
+        mov             w15, #1
+        bl              output_\lag\()_neon
+.else
+        increment_seed  4, shift=0
+        mov             v1.16b,  v4.16b
+        mov             w15, #4
+        bl              output_\lag\()_neon
+.endif
+
+        increment_seed  4, shift=0
+        mov             v1.16b,  v5.16b
+.ifc \edge, right
+        mov             w15, #3
+        bl              output_\lag\()_neon
+        read_shift_rand x15, 11
+        add             x15, x3,  x15, lsl #1
+        ld1             {v1.h}[0], [x15]
+        srshl           v1.4h,   v1.4h,   v31.4h
+        ext             v0.16b,  v0.16b,  v1.16b,  #2
+.else
+        mov             w15, #4
+        bl              output_\lag\()_neon
+.endif
+.else
+        // elems == 1
+        increment_seed  4, shift=0
+        mov             v1.16b,  v4.16b
+        mov             w15, #1
+        bl              output_\lag\()_neon
+        lsr             w2,  w2,  #3
+
+        read_rand       x12, 11,  2
+        read_rand       x13, 11,  1
+        read_rand       x14, 11,  0
+        add             x12, x3,  x12, lsl #1
+        add             x13, x3,  x13, lsl #1
+        add             x14, x3,  x14, lsl #1
+        ld1             {v1.h}[0], [x12]
+        ld1             {v1.h}[1], [x13]
+        ld1             {v1.h}[2], [x14]
+        srshl           v1.4h,   v1.4h,   v31.4h
+        ext             v0.16b,  v0.16b,  v1.16b,  #14
+.endif
+        st1             {v0.8h}, [x0], #16
+        ldr             x30,     [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+.endif
+.endm
+
+.macro sum_lag1_func type, uv_layout, edge, elems=8
+function sum_\type\()_lag1_\edge\()_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+.ifc \edge, left
+        sub             x12, x0,  #1*GRAIN_WIDTH*2
+        ld1             {v17.8h}, [x12] // load the previous block right above
+.endif
+        sum_lag_n_body  lag1, \type, \uv_layout, \edge, \elems
+endfunc
+.endm
+
+sum_lag1_func y,      0,   left
+sum_lag1_func y,      0,   mid
+sum_lag1_func y,      0,   right, 7
+sum_lag1_func uv_444, 444, left
+sum_lag1_func uv_444, 444, mid
+sum_lag1_func uv_444, 444, right, 7
+sum_lag1_func uv_422, 422, left
+sum_lag1_func uv_422, 422, mid
+sum_lag1_func uv_422, 422, right, 1
+sum_lag1_func uv_420, 420, left
+sum_lag1_func uv_420, 420, mid
+sum_lag1_func uv_420, 420, right, 1
+
+
+function sum_lag2_above_neon
+        sub             x12, x0,  #2*GRAIN_WIDTH*2 - 16
+        sub             x13, x0,  #1*GRAIN_WIDTH*2 - 16
+        ld1             {v18.8h}, [x12] // load top right
+        ld1             {v21.8h}, [x13]
+
+        dup             v26.8b,  v30.b[0]
+        ext             v22.16b, v16.16b, v17.16b, #12 // top left, top mid
+        dup             v27.8b,  v30.b[1]
+        ext             v23.16b, v16.16b, v17.16b, #14
+        sxtl            v26.8h,  v26.8b
+        dup             v28.8b,  v30.b[3]
+        ext             v0.16b,  v17.16b, v18.16b, #2  // top mid, top right
+        sxtl            v27.8h,  v27.8b
+        dup             v29.8b,  v30.b[4]
+        ext             v1.16b,  v17.16b, v18.16b, #4
+        sxtl            v28.8h,  v28.8b
+        sxtl            v29.8h,  v29.8b
+
+        smull           v4.4s,   v22.4h,  v26.4h
+        smlal           v4.4s,   v23.4h,  v27.4h
+        smlal           v4.4s,   v0.4h,   v28.4h
+        smlal           v4.4s,   v1.4h,   v29.4h
+        smull2          v5.4s,   v22.8h,  v26.8h
+        smlal2          v5.4s,   v23.8h,  v27.8h
+        smlal2          v5.4s,   v0.8h,   v28.8h
+        smlal2          v5.4s,   v1.8h,   v29.8h
+
+        dup             v26.16b, v30.b[5]
+        ext             v22.16b, v19.16b, v20.16b, #12 // top left, top mid
+        dup             v27.16b, v30.b[6]
+        ext             v23.16b, v19.16b, v20.16b, #14
+        sxtl            v26.8h,  v26.8b
+        dup             v28.16b, v30.b[8]
+        ext             v0.16b,  v20.16b, v21.16b, #2  // top mid, top right
+        sxtl            v27.8h,  v27.8b
+        dup             v29.16b, v30.b[9]
+        ext             v1.16b,  v20.16b, v21.16b, #4
+        sxtl            v28.8h,  v28.8b
+        sxtl            v29.8h,  v29.8b
+
+        smlal           v4.4s,   v22.4h,  v26.4h
+        smlal           v4.4s,   v23.4h,  v27.4h
+        smlal           v4.4s,   v0.4h,   v28.4h
+        smlal           v4.4s,   v1.4h,   v29.4h
+        smlal2          v5.4s,   v22.8h,  v26.8h
+        smlal2          v5.4s,   v23.8h,  v27.8h
+        smlal2          v5.4s,   v0.8h,   v28.8h
+        smlal2          v5.4s,   v1.8h,   v29.8h
+
+        dup             v26.16b, v30.b[2]
+        dup             v27.16b, v30.b[7]
+        sxtl            v26.8h,  v26.8b
+        sxtl            v27.8h,  v27.8b
+
+        smlal           v4.4s,   v17.4h,  v26.4h
+        smlal           v4.4s,   v20.4h,  v27.4h
+        smlal2          v5.4s,   v17.8h,  v26.8h
+        smlal2          v5.4s,   v20.8h,  v27.8h
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+
+        mov             v19.16b, v20.16b
+        mov             v20.16b, v21.16b
+        ret
+endfunc
+
+.macro sum_lag2_func type, uv_layout, edge, elems=8
+function sum_\type\()_lag2_\edge\()_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+.ifc \edge, left
+        sub             x12, x0,  #2*GRAIN_WIDTH*2
+        sub             x13, x0,  #1*GRAIN_WIDTH*2
+        ld1             {v17.8h}, [x12] // load the previous block right above
+        ld1             {v20.8h}, [x13]
+.endif
+        sum_lag_n_body  lag2, \type, \uv_layout, \edge, \elems, v30.b[12]
+endfunc
+.endm
+
+sum_lag2_func y,      0,   left
+sum_lag2_func y,      0,   mid
+sum_lag2_func y,      0,   right, 7
+sum_lag2_func uv_444, 444, left
+sum_lag2_func uv_444, 444, mid
+sum_lag2_func uv_444, 444, right, 7
+sum_lag2_func uv_422, 422, left
+sum_lag2_func uv_422, 422, mid
+sum_lag2_func uv_422, 422, right, 1
+sum_lag2_func uv_420, 420, left
+sum_lag2_func uv_420, 420, mid
+sum_lag2_func uv_420, 420, right, 1
+
+
+function sum_lag3_above_neon
+        sub             x11, x0,  #3*GRAIN_WIDTH*2 - 16
+        sub             x12, x0,  #2*GRAIN_WIDTH*2 - 16
+        sub             x13, x0,  #1*GRAIN_WIDTH*2 - 16
+        ld1             {v15.8h}, [x11] // load top right
+        ld1             {v18.8h}, [x12]
+        ld1             {v21.8h}, [x13]
+
+        dup             v22.8b,  v29.b[0]
+        ext             v8.16b,  v13.16b, v14.16b, #10 // top left, top mid
+        dup             v23.8b,  v29.b[1]
+        ext             v9.16b,  v13.16b, v14.16b, #12
+        sxtl            v22.8h,  v22.8b
+        dup             v24.8b,  v29.b[2]
+        sxtl            v23.8h,  v23.8b
+        dup             v25.8b,  v29.b[3]
+        ext             v10.16b, v13.16b, v14.16b, #14
+        sxtl            v24.8h,  v24.8b
+        dup             v26.8b,  v29.b[4]
+        ext             v11.16b, v14.16b, v15.16b, #2  // top mid, top right
+        sxtl            v25.8h,  v25.8b
+        dup             v27.8b,  v29.b[5]
+        ext             v12.16b, v14.16b, v15.16b, #4
+        sxtl            v26.8h,  v26.8b
+        dup             v28.8b,  v29.b[6]
+        ext             v13.16b, v14.16b, v15.16b, #6
+        sxtl            v27.8h,  v27.8b
+        sxtl            v28.8h,  v28.8b
+
+        smull           v4.4s,   v8.4h,   v22.4h
+        smlal           v4.4s,   v9.4h,   v23.4h
+        smlal           v4.4s,   v10.4h,  v24.4h
+        smlal           v4.4s,   v11.4h,  v26.4h
+        smlal           v4.4s,   v12.4h,  v27.4h
+        smlal           v4.4s,   v13.4h,  v28.4h
+        smlal           v4.4s,   v14.4h,  v25.4h
+        smull2          v5.4s,   v8.8h,   v22.8h
+        smlal2          v5.4s,   v9.8h,   v23.8h
+        smlal2          v5.4s,   v10.8h,  v24.8h
+        smlal2          v5.4s,   v11.8h,  v26.8h
+        smlal2          v5.4s,   v12.8h,  v27.8h
+        smlal2          v5.4s,   v13.8h,  v28.8h
+        smlal2          v5.4s,   v14.8h,  v25.8h
+
+        dup             v22.8b,  v29.b[7]
+        ext             v8.16b,  v16.16b, v17.16b, #10 // top left, top mid
+        dup             v23.8b,  v29.b[8]
+        ext             v9.16b,  v16.16b, v17.16b, #12
+        sxtl            v22.8h,  v22.8b
+        dup             v24.8b,  v29.b[9]
+        sxtl            v23.8h,  v23.8b
+        dup             v25.8b,  v29.b[10]
+        ext             v10.16b, v16.16b, v17.16b, #14
+        sxtl            v24.8h,  v24.8b
+        dup             v26.8b,  v29.b[11]
+        ext             v11.16b, v17.16b, v18.16b, #2  // top mid, top right
+        sxtl            v25.8h,  v25.8b
+        dup             v27.8b,  v29.b[12]
+        ext             v12.16b, v17.16b, v18.16b, #4
+        sxtl            v26.8h,  v26.8b
+        dup             v28.8b,  v29.b[13]
+        ext             v13.16b, v17.16b, v18.16b, #6
+        sxtl            v27.8h,  v27.8b
+        sxtl            v28.8h,  v28.8b
+
+        smlal           v4.4s,   v8.4h,   v22.4h
+        smlal           v4.4s,   v9.4h,   v23.4h
+        smlal           v4.4s,   v10.4h,  v24.4h
+        smlal           v4.4s,   v11.4h,  v26.4h
+        smlal           v4.4s,   v12.4h,  v27.4h
+        smlal           v4.4s,   v13.4h,  v28.4h
+        smlal           v4.4s,   v17.4h,  v25.4h
+        smlal2          v5.4s,   v8.8h,   v22.8h
+        smlal2          v5.4s,   v9.8h,   v23.8h
+        smlal2          v5.4s,   v10.8h,  v24.8h
+        smlal2          v5.4s,   v11.8h,  v26.8h
+        smlal2          v5.4s,   v12.8h,  v27.8h
+        smlal2          v5.4s,   v13.8h,  v28.8h
+        smlal2          v5.4s,   v17.8h,  v25.8h
+
+        dup             v22.8b,  v29.b[14]
+        ext             v8.16b,  v19.16b, v20.16b, #10 // top left, top mid
+        dup             v23.8b,  v29.b[15]
+        ext             v9.16b,  v19.16b, v20.16b, #12
+        sxtl            v22.8h,  v22.8b
+        dup             v24.8b,  v30.b[0]
+        sxtl            v23.8h,  v23.8b
+        dup             v25.8b,  v30.b[1]
+        ext             v10.16b, v19.16b, v20.16b, #14
+        sxtl            v24.8h,  v24.8b
+        dup             v26.8b,  v30.b[2]
+        ext             v11.16b, v20.16b, v21.16b, #2  // top mid, top right
+        sxtl            v25.8h,  v25.8b
+        dup             v27.8b,  v30.b[3]
+        ext             v12.16b, v20.16b, v21.16b, #4
+        sxtl            v26.8h,  v26.8b
+        dup             v28.8b,  v30.b[4]
+        ext             v13.16b, v20.16b, v21.16b, #6
+        sxtl            v27.8h,  v27.8b
+        sxtl            v28.8h,  v28.8b
+
+        smlal           v4.4s,   v8.4h,   v22.4h
+        smlal           v4.4s,   v9.4h,   v23.4h
+        smlal           v4.4s,   v10.4h,  v24.4h
+        smlal           v4.4s,   v11.4h,  v26.4h
+        smlal           v4.4s,   v12.4h,  v27.4h
+        smlal           v4.4s,   v13.4h,  v28.4h
+        smlal           v4.4s,   v20.4h,  v25.4h
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+        smlal2          v5.4s,   v8.8h,   v22.8h
+        smlal2          v5.4s,   v9.8h,   v23.8h
+        smlal2          v5.4s,   v10.8h,  v24.8h
+        smlal2          v5.4s,   v11.8h,  v26.8h
+        smlal2          v5.4s,   v12.8h,  v27.8h
+        smlal2          v5.4s,   v13.8h,  v28.8h
+        smlal2          v5.4s,   v20.8h,  v25.8h
+
+        mov             v13.16b, v14.16b
+        mov             v14.16b, v15.16b
+
+        mov             v19.16b, v20.16b
+        mov             v20.16b, v21.16b
+        ret
+endfunc
+
+.macro sum_lag3_func type, uv_layout, edge, elems=8
+function sum_\type\()_lag3_\edge\()_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+.ifc \edge, left
+        sub             x11, x0,  #3*GRAIN_WIDTH*2
+        sub             x12, x0,  #2*GRAIN_WIDTH*2
+        sub             x13, x0,  #1*GRAIN_WIDTH*2
+        ld1             {v14.8h}, [x11] // load the previous block right above
+        ld1             {v17.8h}, [x12]
+        ld1             {v20.8h}, [x13]
+.endif
+        sum_lag_n_body  lag3, \type, \uv_layout, \edge, \elems, v30.b[8]
+endfunc
+.endm
+
+sum_lag3_func y,      0,   left
+sum_lag3_func y,      0,   mid
+sum_lag3_func y,      0,   right, 7
+sum_lag3_func uv_444, 444, left
+sum_lag3_func uv_444, 444, mid
+sum_lag3_func uv_444, 444, right, 7
+sum_lag3_func uv_422, 422, left
+sum_lag3_func uv_422, 422, mid
+sum_lag3_func uv_422, 422, right, 1
+sum_lag3_func uv_420, 420, left
+sum_lag3_func uv_420, 420, mid
+sum_lag3_func uv_420, 420, right, 1
+
+function generate_grain_rows_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+1:
+        mov             w16, #80
+2:
+        bl              get_gaussian_neon
+        srshl           v0.8h,   v0.8h,   v31.8h
+        subs            w16, w16, #8
+        st1             {v0.8h}, [x0], #16
+        b.gt            2b
+        get_grain_2     v0
+        subs            w1,  w1,  #1
+        st1             {v0.s}[0], [x0], #4
+        b.gt            1b
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+function generate_grain_rows_44_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+1:
+        mov             w16, #40
+2:
+        bl              get_gaussian_neon
+        srshl           v0.8h,   v0.8h,   v31.8h
+        subs            w16, w16, #8
+        st1             {v0.8h}, [x0], #16
+        b.gt            2b
+        get_grain_4     v0
+        subs            w1,  w1,  #1
+        st1             {v0.4h}, [x0]
+        add             x0,  x0,  #GRAIN_WIDTH*2-80
+        b.gt            1b
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+function gen_grain_uv_444_lag0_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+        ld1             {v4.8h}, [x19], #16
+gen_grain_uv_lag0_8_start:
+        bl              get_gaussian_neon
+        srshl           v0.8h,   v0.8h,   v31.8h
+gen_grain_uv_lag0_8_add:
+        and             v4.16b,  v4.16b,  v1.16b
+        smull           v2.4s,   v4.4h,   v27.4h
+        smull2          v3.4s,   v4.8h,   v27.8h
+        srshl           v2.4s,   v2.4s,   v28.4s
+        srshl           v3.4s,   v3.4s,   v28.4s
+        sqxtn           v2.4h,   v2.4s
+        sqxtn2          v2.8h,   v3.4s
+        sqadd           v2.8h,   v2.8h,   v0.8h
+        smin            v2.8h,   v2.8h,   v25.8h
+        smax            v2.8h,   v2.8h,   v26.8h
+        st1             {v2.8h}, [x0], #16
+        ldr             x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+function gen_grain_uv_420_lag0_8_neon
+        AARCH64_SIGN_LINK_REGISTER
+        add             x12, x19, #GRAIN_WIDTH*2
+        str             x30, [sp, #-16]!
+        ld1             {v16.8h, v17.8h}, [x19], #32
+        ld1             {v18.8h, v19.8h}, [x12]
+        addp            v16.8h,  v16.8h,  v17.8h
+        addp            v17.8h,  v18.8h,  v19.8h
+        add             v16.8h,  v16.8h,  v17.8h
+        srshr           v4.8h,   v16.8h,  #2
+        b               gen_grain_uv_lag0_8_start
+endfunc
+
+function gen_grain_uv_422_lag0_8_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+        ld1             {v16.8h, v17.8h}, [x19], #32
+        addp            v16.8h,  v16.8h,  v17.8h
+        srshr           v4.8h,   v16.8h,  #1
+        b               gen_grain_uv_lag0_8_start
+endfunc
+
+function gen_grain_uv_420_lag0_4_neon
+        add             x12, x19, #GRAIN_WIDTH*2
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+        ld1             {v16.4h, v17.4h}, [x19]
+        ld1             {v18.4h, v19.4h}, [x12]
+        add             x19,  x19,  #32
+        addp            v16.4h,  v16.4h,  v17.4h
+        addp            v17.4h,  v18.4h,  v19.4h
+        add             v16.4h,  v16.4h,  v17.4h
+        srshr           v4.4h,   v16.4h,  #2
+        get_grain_4     v0
+        b               gen_grain_uv_lag0_8_add
+endfunc
+
+function gen_grain_uv_422_lag0_4_neon
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-16]!
+        ld1             {v16.4h, v17.4h}, [x19]
+        add             x19,  x19,  #32
+        addp            v16.4h,  v16.4h,  v17.4h
+        srshr           v4.4h,   v16.4h,  #1
+        get_grain_4     v0
+        b               gen_grain_uv_lag0_8_add
+endfunc
+
+.macro gen_grain_82 type
+function generate_grain_\type\()_16bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x30, x19, [sp, #-96]!
+
+.ifc \type, uv_444
+        mov             w13, w3
+        mov             w14, #28
+        add             x19, x1,  #3*GRAIN_WIDTH*2
+        mov             x1,  x2
+        mul             w13, w13, w14
+        clz             w15, w4
+.else
+        clz             w15, w2
+.endif
+        movrel          x3,  X(gaussian_sequence)
+        sub             w15, w15, #24 // -bitdepth_min_8
+        ldr             w2,  [x1, #FGD_SEED]
+        ldr             w9,  [x1, #FGD_GRAIN_SCALE_SHIFT]
+.ifc \type, y
+        add             x4,  x1,  #FGD_AR_COEFFS_Y
+.else
+        add             x4,  x1,  #FGD_AR_COEFFS_UV
+.endif
+        add             w9,  w9,  w15 // grain_scale_shift - bitdepth_min_8
+        movrel          x16, gen_grain_\type\()_tbl
+        ldr             w17, [x1, #FGD_AR_COEFF_LAG]
+        add             w9,  w9,  #4
+        ldrsw           x17, [x16, w17, uxtw #2]
+        dup             v31.8h,  w9    // 4 - bitdepth_min_8 + data->grain_scale_shift
+        add             x16, x16, x17
+        neg             v31.8h,  v31.8h
+
+.ifc \type, uv_444
+        cmp             w13, #0
+        mov             w11, #0x49d8
+        mov             w14, #0xb524
+        add             x4,  x4,  w13, uxtw // Add offset to ar_coeffs_uv[1]
+        csel            w11, w11, w14, ne
+.endif
+
+        ldr             w7,  [x1, #FGD_AR_COEFF_SHIFT]
+        neg             w15, w15            // bitdepth_min_8
+        mov             w8,  #1
+        mov             w10, #1
+        lsl             w8,  w8,  w7        // 1 << ar_coeff_shift
+        lsl             w10, w10, w9        // 1 << (4 + data->grain_scale_shift)
+        lsr             w8,  w8,  #1        // 1 << (ar_coeff_shift - 1)
+        lsr             w10, w10, #1        // 1 << (4 + data->grain_scale_shift - 1)
+        mov             w5,  #128
+        lsl             w5,  w5,  w15       //   128 << bitdepth_min_8
+        neg             w6,  w5             // -(128 << bitpdeth_min_8)
+        sub             w5,  w5,  #1        //  (128 << bitdepth_min_8) - 1
+
+.ifc \type, uv_444
+        eor             w2,  w2,  w11
+.endif
+
+        br              x16
+
+L(generate_grain_\type\()_lag0):
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, y
+        mov             w1,  #GRAIN_HEIGHT
+        bl              generate_grain_rows_neon
+.else
+        dup             v28.4s,  w7
+        ld1r            {v27.8b}, [x4]      // ar_coeffs_uv[0]
+        movi            v0.16b,  #0
+        movi            v1.16b,  #255
+        dup             v25.8h,  w5
+        dup             v26.8h,  w6
+        ext             v29.16b, v0.16b,  v1.16b,  #10
+        ext             v30.16b, v1.16b,  v0.16b,  #2
+        neg             v28.4s,  v28.4s
+        sxtl            v27.8h,  v27.8b
+
+        mov             w1,  #3
+        bl              generate_grain_rows_neon
+        mov             w1,  #GRAIN_HEIGHT-3
+1:
+        mov             v1.16b,  v29.16b
+        bl              gen_grain_uv_444_lag0_neon // 8
+        movi            v1.16b,  #255
+        bl              gen_grain_uv_444_lag0_neon // 16
+        bl              gen_grain_uv_444_lag0_neon // 24
+        bl              gen_grain_uv_444_lag0_neon // 32
+        bl              gen_grain_uv_444_lag0_neon // 40
+        bl              gen_grain_uv_444_lag0_neon // 48
+        bl              gen_grain_uv_444_lag0_neon // 56
+        bl              gen_grain_uv_444_lag0_neon // 64
+        bl              gen_grain_uv_444_lag0_neon // 72
+        mov             v1.16b,  v30.16b
+        bl              gen_grain_uv_444_lag0_neon // 80
+        get_grain_2     v16
+        subs            w1,  w1,  #1
+        add             x19, x19, #4
+        st1             {v16.s}[0], [x0], #4
+        b.gt            1b
+.endif
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag1):
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v27.8b}, [x4], #1  // ar_coeffs_y[0]
+        ld1r            {v28.8b}, [x4], #1  // ar_coeffs_y[1]
+        ld1r            {v29.8b}, [x4]      // ar_coeffs_y[2]
+.ifc \type, y
+        ldrsb           w4,  [x4, #1]       // ar_coeffs_y[3]
+.else
+        add             x4,  x4,  #2
+.endif
+
+        mov             w1,  #3
+.ifc \type, uv_444
+        ld1r            {v30.8b}, [x4]      // ar_coeffs_uv[4]
+        ldursb          w4,  [x4, #-1]      // ar_coeffs_uv[3]
+.endif
+        bl              generate_grain_rows_neon
+        sxtl            v27.8h,  v27.8b
+        sxtl            v28.8h,  v28.8b
+        sxtl            v29.8h,  v29.8b
+.ifc \type, uv_444
+        sxtl            v30.8h,  v30.8b
+.endif
+
+        mov             w1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag1_left_neon  // 8
+        bl              sum_\type\()_lag1_mid_neon   // 16
+        bl              sum_\type\()_lag1_mid_neon   // 24
+        bl              sum_\type\()_lag1_mid_neon   // 32
+        bl              sum_\type\()_lag1_mid_neon   // 40
+        bl              sum_\type\()_lag1_mid_neon   // 48
+        bl              sum_\type\()_lag1_mid_neon   // 56
+        bl              sum_\type\()_lag1_mid_neon   // 64
+        bl              sum_\type\()_lag1_mid_neon   // 72
+        bl              sum_\type\()_lag1_right_neon // 80
+        get_grain_2     v16
+        subs            w1,  w1,  #1
+.ifc \type, uv_444
+        add             x19, x19, #4
+.endif
+        st1             {v16.s}[0], [x0], #4
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag2):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v30.16b}, [x4]     // ar_coeffs_y[0-11], ar_coeffs_uv[0-12]
+
+        smov            w4,  v30.b[10]
+        smov            w17, v30.b[11]
+
+        mov             w1,  #3
+        bl              generate_grain_rows_neon
+
+        mov             w1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag2_left_neon  // 8
+        bl              sum_\type\()_lag2_mid_neon   // 16
+        bl              sum_\type\()_lag2_mid_neon   // 24
+        bl              sum_\type\()_lag2_mid_neon   // 32
+        bl              sum_\type\()_lag2_mid_neon   // 40
+        bl              sum_\type\()_lag2_mid_neon   // 48
+        bl              sum_\type\()_lag2_mid_neon   // 56
+        bl              sum_\type\()_lag2_mid_neon   // 64
+        bl              sum_\type\()_lag2_mid_neon   // 72
+        bl              sum_\type\()_lag2_right_neon // 80
+        get_grain_2     v16
+        subs            w1,  w1,  #1
+.ifc \type, uv_444
+        add             x19, x19, #4
+.endif
+        st1             {v16.s}[0], [x0], #4
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag3):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v29.16b, v30.16b}, [x4] // ar_coeffs_y[0-23], ar_coeffs_uv[0-24]
+        stp             d8,  d9,  [sp, #16]
+        stp             d10, d11, [sp, #32]
+        stp             d12, d13, [sp, #48]
+        stp             d14, d15, [sp, #64]
+        stp             x20, x21, [sp, #80]
+
+        smov            w4,  v30.b[5]
+        smov            w20, v30.b[6]
+        smov            w21, v30.b[7]
+
+        mov             w1,  #3
+        bl              generate_grain_rows_neon
+
+        mov             w1,  #GRAIN_HEIGHT - 3
+1:
+        bl              sum_\type\()_lag3_left_neon  // 8
+        bl              sum_\type\()_lag3_mid_neon   // 16
+        bl              sum_\type\()_lag3_mid_neon   // 24
+        bl              sum_\type\()_lag3_mid_neon   // 32
+        bl              sum_\type\()_lag3_mid_neon   // 40
+        bl              sum_\type\()_lag3_mid_neon   // 48
+        bl              sum_\type\()_lag3_mid_neon   // 56
+        bl              sum_\type\()_lag3_mid_neon   // 64
+        bl              sum_\type\()_lag3_mid_neon   // 72
+        bl              sum_\type\()_lag3_right_neon // 80
+        get_grain_2     v16
+        subs            w1,  w1,  #1
+.ifc \type, uv_444
+        add             x19, x19, #4
+.endif
+        st1             {v16.s}[0], [x0], #4
+        b.gt            1b
+
+        ldp             x20, x21, [sp, #80]
+        ldp             d14, d15, [sp, #64]
+        ldp             d12, d13, [sp, #48]
+        ldp             d10, d11, [sp, #32]
+        ldp             d8,  d9,  [sp, #16]
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+jumptable gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag0) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag1) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag2) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag3) - gen_grain_\type\()_tbl
+endjumptable
+.endm
+
+gen_grain_82 y
+gen_grain_82 uv_444
+
+.macro set_height dst, type
+.ifc \type, uv_420
+        mov             \dst,  #SUB_GRAIN_HEIGHT-3
+.else
+        mov             \dst,  #GRAIN_HEIGHT-3
+.endif
+.endm
+
+.macro increment_y_ptr reg, type
+.ifc \type, uv_420
+        add             \reg, \reg, #2*GRAIN_WIDTH*2-(6*32)
+.else
+        sub             \reg, \reg, #6*32-GRAIN_WIDTH*2
+.endif
+.endm
+
+.macro gen_grain_44 type
+function generate_grain_\type\()_16bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x30, x19, [sp, #-96]!
+
+        mov             w13, w3
+        mov             w14, #28
+        add             x19, x1,  #(3*GRAIN_WIDTH-3)*2
+        mov             x1,  x2
+        mul             w13, w13, w14
+        clz             w15, w4
+
+        movrel          x3,  X(gaussian_sequence)
+        sub             w15, w15, #24 // -bitdepth_min_8
+        ldr             w2,  [x1, #FGD_SEED]
+        ldr             w9,  [x1, #FGD_GRAIN_SCALE_SHIFT]
+        add             x4,  x1,  #FGD_AR_COEFFS_UV
+        add             w9,  w9,  w15 // grain_scale_shift - bitdepth_min_8
+        movrel          x16, gen_grain_\type\()_tbl
+        ldr             w17, [x1, #FGD_AR_COEFF_LAG]
+        add             w9,  w9,  #4
+        ldrsw           x17, [x16, w17, uxtw #2]
+        dup             v31.8h,  w9    // 4 - bitdepth_min_8 + data->grain_scale_shift
+        add             x16, x16, x17
+        neg             v31.8h,  v31.8h
+
+        cmp             w13, #0
+        mov             w11, #0x49d8
+        mov             w14, #0xb524
+        add             x4,  x4,  w13, uxtw // Add offset to ar_coeffs_uv[1]
+        csel            w11, w11, w14, ne
+
+        ldr             w7,  [x1, #FGD_AR_COEFF_SHIFT]
+        neg             w15, w15            // bitdepth_min_8
+        mov             w8,  #1
+        mov             w10, #1
+        lsl             w8,  w8,  w7        // 1 << ar_coeff_shift
+        lsl             w10, w10, w9        // 1 << (4 + data->grain_scale_shift)
+        lsr             w8,  w8,  #1        // 1 << (ar_coeff_shift - 1)
+        lsr             w10, w10, #1        // 1 << (4 + data->grain_scale_shift - 1)
+        mov             w5,  #128
+        lsl             w5,  w5,  w15       //   128 << bitdepth_min_8
+        neg             w6,  w5             // -(128 << bitpdeth_min_8)
+        sub             w5,  w5,  #1        //  (128 << bitdepth_min_8) - 1
+
+        eor             w2,  w2,  w11
+
+        br              x16
+
+L(generate_grain_\type\()_lag0):
+        AARCH64_VALID_JUMP_TARGET
+        dup             v28.4s,  w7
+        ld1r            {v27.8b}, [x4]      // ar_coeffs_uv[0]
+        movi            v0.16b,  #0
+        movi            v1.16b,  #255
+        dup             v25.8h,  w5
+        dup             v26.8h,  w6
+        ext             v29.16b, v0.16b,  v1.16b,  #10
+        ext             v30.16b, v1.16b,  v0.16b,  #14
+        neg             v28.4s,  v28.4s
+        sxtl            v27.8h,  v27.8b
+
+        mov             w1,  #3
+        bl              generate_grain_rows_44_neon
+        set_height      w1,  \type
+1:
+        mov             v1.16b,  v29.16b
+        bl              gen_grain_\type\()_lag0_8_neon // 8
+        movi            v1.16b,  #255
+        bl              gen_grain_\type\()_lag0_8_neon // 16
+        bl              gen_grain_\type\()_lag0_8_neon // 24
+        bl              gen_grain_\type\()_lag0_8_neon // 32
+        bl              gen_grain_\type\()_lag0_8_neon // 40
+        mov             v1.16b,  v30.16b
+        bl              gen_grain_\type\()_lag0_4_neon // 44
+        subs            w1,  w1,  #1
+        increment_y_ptr x19, \type
+        add             x0,  x0,  #GRAIN_WIDTH*2-6*16
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag1):
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v27.8b}, [x4], #1  // ar_coeffs_uv[0]
+        ld1r            {v28.8b}, [x4], #1  // ar_coeffs_uv[1]
+        ld1r            {v29.8b}, [x4]      // ar_coeffs_uv[2]
+        add             x4,  x4,  #2
+
+        mov             w1,  #3
+        ld1r            {v30.8b}, [x4]      // ar_coeffs_u4[4]
+        ldursb          w4,  [x4, #-1]      // ar_coeffs_uv[3]
+        bl              generate_grain_rows_44_neon
+
+        sxtl            v27.8h,  v27.8b
+        sxtl            v28.8h,  v28.8b
+        sxtl            v29.8h,  v29.8b
+        sxtl            v30.8h,  v30.8b
+        set_height      w1,  \type
+1:
+        bl              sum_\type\()_lag1_left_neon  // 8
+        bl              sum_\type\()_lag1_mid_neon   // 16
+        bl              sum_\type\()_lag1_mid_neon   // 24
+        bl              sum_\type\()_lag1_mid_neon   // 32
+        bl              sum_\type\()_lag1_mid_neon   // 40
+        bl              sum_\type\()_lag1_right_neon // 44
+        subs            w1,  w1,  #1
+        increment_y_ptr x19, \type
+        add             x0,  x0,  #GRAIN_WIDTH*2-6*16
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag2):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v30.16b}, [x4]     // ar_coeffs_uv[0-12]
+
+        smov            w4,  v30.b[10]
+        smov            w17, v30.b[11]
+
+        mov             w1,  #3
+        bl              generate_grain_rows_44_neon
+
+        set_height      w1,  \type
+1:
+        bl              sum_\type\()_lag2_left_neon  // 8
+        bl              sum_\type\()_lag2_mid_neon   // 16
+        bl              sum_\type\()_lag2_mid_neon   // 24
+        bl              sum_\type\()_lag2_mid_neon   // 32
+        bl              sum_\type\()_lag2_mid_neon   // 40
+        bl              sum_\type\()_lag2_right_neon // 44
+        subs            w1,  w1,  #1
+        increment_y_ptr x19, \type
+        add             x0,  x0,  #GRAIN_WIDTH*2-6*16
+        b.gt            1b
+
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(generate_grain_\type\()_lag3):
+        AARCH64_VALID_JUMP_TARGET
+        ldr             q29,      [x4]      // ar_coeffs_uv[0-15]
+        ldr             q30,      [x4, #16] // ar_coeffs_uv[16-24]
+        stp             d8,  d9,  [sp, #16]
+        stp             d10, d11, [sp, #32]
+        stp             d12, d13, [sp, #48]
+        stp             d14, d15, [sp, #64]
+        stp             x20, x21, [sp, #80]
+
+        smov            w4,  v30.b[5]
+        smov            w20, v30.b[6]
+        smov            w21, v30.b[7]
+
+        mov             w1,  #3
+        bl              generate_grain_rows_44_neon
+
+        set_height      w1,  \type
+1:
+        bl              sum_\type\()_lag3_left_neon  // 8
+        bl              sum_\type\()_lag3_mid_neon   // 16
+        bl              sum_\type\()_lag3_mid_neon   // 24
+        bl              sum_\type\()_lag3_mid_neon   // 32
+        bl              sum_\type\()_lag3_mid_neon   // 40
+        bl              sum_\type\()_lag3_right_neon // 44
+        subs            w1,  w1,  #1
+        increment_y_ptr x19, \type
+        add             x0,  x0,  #GRAIN_WIDTH*2-6*16
+        b.gt            1b
+
+        ldp             x20, x21, [sp, #80]
+        ldp             d14, d15, [sp, #64]
+        ldp             d12, d13, [sp, #48]
+        ldp             d10, d11, [sp, #32]
+        ldp             d8,  d9,  [sp, #16]
+        ldp             x30, x19, [sp], #96
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+jumptable gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag0) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag1) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag2) - gen_grain_\type\()_tbl
+        .word L(generate_grain_\type\()_lag3) - gen_grain_\type\()_tbl
+endjumptable
+.endm
+
+gen_grain_44 uv_420
+gen_grain_44 uv_422
+
+.macro gather_interleaved dst1, dst2, src1, src2, off
+        umov            w14, \src1[0]
+        umov            w15, \src2[1]
+        umov            w16, \src1[2]
+        add             x14, x14, x3
+        umov            w17, \src2[3]
+        add             x15, x15, x3
+        ld1             {\dst1}[0+\off], [x14]
+        umov            w14, \src1[4]
+        add             x16, x16, x3
+        ld1             {\dst2}[1+\off], [x15]
+        umov            w15, \src2[5]
+        add             x17, x17, x3
+        ld1             {\dst1}[2+\off], [x16]
+        umov            w16, \src1[6]
+        add             x14, x14, x3
+        ld1             {\dst2}[3+\off], [x17]
+        umov            w17, \src2[7]
+        add             x15, x15, x3
+        ld1             {\dst1}[4+\off], [x14]
+        add             x16, x16, x3
+        ld1             {\dst2}[5+\off], [x15]
+        add             x17, x17, x3
+        ld1             {\dst1}[6+\off], [x16]
+        ld1             {\dst2}[7+\off], [x17]
+.endm
+
+.macro gather dst1, dst2, src1, src2, src3, src4
+        gather_interleaved \dst1, \dst2, \src1, \src3, 0
+        gather_interleaved \dst2, \dst1, \src3, \src1, 0
+        gather_interleaved \dst1, \dst2, \src2, \src4, 8
+        gather_interleaved \dst2, \dst1, \src4, \src2, 8
+.endm
+
+function gather32_neon
+        gather          v6.b, v7.b, v0.h, v1.h, v2.h, v3.h
+        ret
+endfunc
+
+function gather16_neon
+        gather_interleaved v6.b, v7.b, v0.h, v1.h, 0
+        gather_interleaved v7.b, v6.b, v1.h, v0.h, 0
+        ins             v6.d[1], v7.d[0]
+        ret
+endfunc
+
+const overlap_coeffs_0, align=4
+        .short 27, 17, 0,  0
+        .short 17, 27, 32, 32
+endconst
+
+const overlap_coeffs_1, align=4
+        .short 23, 0,  0,  0
+        .short 22, 32, 32, 32
+endconst
+
+.macro calc_offset offx, offy, src, sx, sy
+        and             \offy, \src,  #0xF     // randval & 0xF
+        lsr             \offx, \src,  #4       // randval >> 4
+.if \sy == 0
+        add             \offy, \offy, \offy    // 2 * (randval & 0xF)
+.endif
+.if \sx == 0
+        add             \offx, \offx, \offx    // 2 * (randval >> 4)
+.endif
+.endm
+
+.macro add_offset dst, offx, offy, src, stride
+        madd            \dst, \stride, \offy, \src // grain_lut += grain_stride * offy
+        add             \dst, \dst, \offx, uxtw #1 // grain_lut += offx
+.endm
+
+// void dav1d_fgy_32x32_16bpc_neon(pixel *const dst, const pixel *const src,
+//                                 const ptrdiff_t stride,
+//                                 const uint8_t scaling[SCALING_SIZE],
+//                                 const int scaling_shift,
+//                                 const entry grain_lut[][GRAIN_WIDTH],
+//                                 const int offsets[][2],
+//                                 const int h, const ptrdiff_t clip,
+//                                 const ptrdiff_t type,
+//                                 const int bitdepth_max);
+function fgy_32x32_16bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30, [sp, #-80]!
+        stp             d8,  d9,  [sp, #16]
+        stp             d10, d11, [sp, #32]
+        stp             d12, d13, [sp, #48]
+        str             d14,      [sp, #64]
+        eor             w4,  w4,  #15          // 15 - scaling_shift
+        ldr             w11, [x6, #8]          // offsets[1][0]
+        ldr             w13, [x6, #4]          // offsets[0][1]
+        ldr             w15, [x6, #12]         // offsets[1][1]
+        ldr             w10, [sp, #96]         // bitdepth_max
+        ldr             w6,  [x6]              // offsets[0][0]
+        dup             v26.8h,  w10           // bitdepth_max
+        clz             w10, w10
+        ldr             w8,  [sp, #80]         // clip
+        sub             w10, w10, #24          // -bitdepth_min_8
+        mov             x9,  #GRAIN_WIDTH*2    // grain_lut stride
+        neg             w10, w10               // bitdepth_min_8
+
+        dup             v29.8h,  w4            // 15 - scaling_shift
+        dup             v27.8h,  w10           // bitdepth_min_8
+
+        movrel          x16, overlap_coeffs_0
+
+        cbz             w8,  1f
+        // clip
+        movi            v30.8h,  #16
+        movi            v31.8h,  #235
+        sshl            v30.8h,  v30.8h,  v27.8h
+        sshl            v31.8h,  v31.8h,  v27.8h
+        b               2f
+1:
+        // no clip
+        movi            v30.8h,  #0
+        mov             v31.16b, v26.16b       // bitdepth_max
+2:
+
+        ushr            v26.8h,  v26.8h,  #1   // grain_max
+        not             v25.16b, v26.16b       // grain_min
+
+        ld1             {v27.4h, v28.4h}, [x16] // overlap_coeffs
+
+        add             x5,  x5,  #18          // grain_lut += 9
+        add             x5,  x5,  x9,  lsl #3  // grain_lut += 8 * grain_stride
+        add             x5,  x5,  x9           // grain_lut += grain_stride
+
+        calc_offset     w11, w12, w11, 0,  0
+        calc_offset     w13, w14, w13, 0,  0
+        calc_offset     w15, w16, w15, 0,  0
+        calc_offset     w6,  w10, w6,  0,  0
+
+        add_offset      x12, w11, x12, x5,  x9
+        add_offset      x14, w13, x14, x5,  x9
+        add_offset      x16, w15, x16, x5,  x9
+        add_offset      x5,  w6,  x10, x5,  x9
+
+        ldr             w11, [sp, #88]         // type
+        movrel          x13, fgy_loop_tbl
+
+        add             x4,  x12, #32*2        // grain_lut += FG_BLOCK_SIZE * bx
+        add             x6,  x14, x9,  lsl #5  // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+
+        tst             w11, #1
+        ldrsw           x11, [x13, w11, uxtw #2]
+
+        add             x8,  x16, x9,  lsl #5  // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             x8,  x8,  #32*2        // grain_lut += FG_BLOCK_SIZE * bx
+
+        add             x11, x13, x11
+
+        b.eq            1f
+        // y overlap
+        dup             v8.8h,   v27.h[0]
+        dup             v9.8h,   v27.h[1]
+        mov             w10, w7                // backup actual h
+        mov             w7,  #2
+1:
+        br              x11
+endfunc
+
+function fgy_loop_neon
+.macro fgy ox, oy
+L(loop_\ox\oy):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        ld1             {v0.8h,  v1.8h,  v2.8h,  v3.8h},  [x1],  x2 // src
+.if \ox
+        ld1             {v20.4h},                         [x4],  x9 // grain_lut old
+.endif
+.if \oy
+        ld1             {v21.8h, v22.8h, v23.8h, v24.8h}, [x6],  x9 // grain_lut top
+.endif
+.if \ox && \oy
+        ld1             {v14.4h},                         [x8],  x9 // grain_lut top old
+.endif
+        mvni            v4.8h,   #0xf0, lsl #8 // 0x0fff
+        ld1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x5],  x9 // grain_lut
+
+        // Make sure that uninitialized pixels out of range past the right
+        // edge are in range; their actual values shouldn't matter.
+        and             v0.16b,  v0.16b,  v4.16b
+        and             v1.16b,  v1.16b,  v4.16b
+        and             v2.16b,  v2.16b,  v4.16b
+        and             v3.16b,  v3.16b,  v4.16b
+        bl              gather32_neon
+
+.if \ox
+        smull           v20.4s,  v20.4h,  v27.4h
+        smlal           v20.4s,  v16.4h,  v28.4h
+.endif
+
+.if \oy
+.if \ox
+        smull           v14.4s,  v14.4h,  v27.4h
+        smlal           v14.4s,  v21.4h,  v28.4h
+        sqrshrn         v20.4h,  v20.4s,  #5
+        sqrshrn         v14.4h,  v14.4s,  #5
+        smin            v20.4h,  v20.4h,  v26.4h
+        smin            v14.4h,  v14.4h,  v26.4h
+        smax            v20.4h,  v20.4h,  v25.4h
+        smax            v14.4h,  v14.4h,  v25.4h
+.endif
+
+.if \ox
+        smull           v10.4s,  v20.4h,  v9.4h
+.else
+        smull           v10.4s,  v16.4h,  v9.4h
+.endif
+        smull2          v11.4s,  v16.8h,  v9.8h
+        smull           v12.4s,  v17.4h,  v9.4h
+        smull2          v13.4s,  v17.8h,  v9.8h
+        smull           v16.4s,  v18.4h,  v9.4h
+        smull2          v17.4s,  v18.8h,  v9.8h
+        smull           v18.4s,  v19.4h,  v9.4h
+        smull2          v19.4s,  v19.8h,  v9.8h
+.if \ox
+        smlal           v10.4s,  v14.4h,  v8.4h
+.else
+        smlal           v10.4s,  v21.4h,  v8.4h
+.endif
+        smlal2          v11.4s,  v21.8h,  v8.8h
+        smlal           v12.4s,  v22.4h,  v8.4h
+        smlal2          v13.4s,  v22.8h,  v8.8h
+        smlal           v16.4s,  v23.4h,  v8.4h
+        smlal2          v17.4s,  v23.8h,  v8.8h
+        smlal           v18.4s,  v24.4h,  v8.4h
+        smlal2          v19.4s,  v24.8h,  v8.8h
+        sqrshrn         v10.4h,  v10.4s,  #5
+        sqrshrn2        v10.8h,  v11.4s,  #5
+        sqrshrn         v11.4h,  v12.4s,  #5
+        sqrshrn2        v11.8h,  v13.4s,  #5
+        sqrshrn         v12.4h,  v16.4s,  #5
+        sqrshrn2        v12.8h,  v17.4s,  #5
+        sqrshrn         v13.4h,  v18.4s,  #5
+        sqrshrn2        v13.8h,  v19.4s,  #5
+        smin            v16.8h,  v10.8h,  v26.8h
+        smin            v17.8h,  v11.8h,  v26.8h
+        smin            v18.8h,  v12.8h,  v26.8h
+        smin            v19.8h,  v13.8h,  v26.8h
+        smax            v16.8h,  v16.8h,  v25.8h
+        smax            v17.8h,  v17.8h,  v25.8h
+        smax            v18.8h,  v18.8h,  v25.8h
+        smax            v19.8h,  v19.8h,  v25.8h
+.endif
+
+        uxtl            v4.8h,   v6.8b            // scaling
+.if \ox && !\oy
+        sqrshrn         v20.4h,  v20.4s,  #5
+.endif
+        uxtl2           v5.8h,   v6.16b
+.if \ox && !\oy
+        smin            v20.4h,  v20.4h,  v26.4h
+.endif
+        uxtl            v6.8h,   v7.8b
+.if \ox && !\oy
+        smax            v20.4h,  v20.4h,  v25.4h
+.endif
+        uxtl2           v7.8h,   v7.16b
+.if \ox && !\oy
+        ins             v16.d[0], v20.d[0]
+.endif
+        ushl            v4.8h,   v4.8h,   v29.8h  // scaling << (15 - scaling_shift)
+        ushl            v5.8h,   v5.8h,   v29.8h
+        ushl            v6.8h,   v6.8h,   v29.8h
+        ushl            v7.8h,   v7.8h,   v29.8h
+
+        sqrdmulh        v20.8h,  v16.8h,  v4.8h   // round2((scaling << (15 - scaling_shift) * grain, 15)
+        sqrdmulh        v21.8h,  v17.8h,  v5.8h
+        sqrdmulh        v22.8h,  v18.8h,  v6.8h
+        sqrdmulh        v23.8h,  v19.8h,  v7.8h
+
+        usqadd          v0.8h,   v20.8h           // *src + noise
+        usqadd          v1.8h,   v21.8h
+        usqadd          v2.8h,   v22.8h
+        usqadd          v3.8h,   v23.8h
+
+        umax            v0.8h,   v0.8h,   v30.8h
+        umax            v1.8h,   v1.8h,   v30.8h
+        umax            v2.8h,   v2.8h,   v30.8h
+        umax            v3.8h,   v3.8h,   v30.8h
+        umin            v0.8h,   v0.8h,   v31.8h
+        umin            v1.8h,   v1.8h,   v31.8h
+        umin            v2.8h,   v2.8h,   v31.8h
+        umin            v3.8h,   v3.8h,   v31.8h
+
+        subs            w7,  w7,  #1
+.if \oy
+        dup             v8.8h,   v28.h[0]
+        dup             v9.8h,   v28.h[1]
+.endif
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h},  [x0], x2 // dst
+        b.gt            1b
+
+.if \oy
+        cmp             w10, #2
+        sub             w7,  w10, #2           // restore actual remaining h
+        b.gt            L(loop_\ox\()0)
+.endif
+        ldr             d14,      [sp, #64]
+        ldp             d12, d13, [sp, #48]
+        ldp             d10, d11, [sp, #32]
+        ldp             d8,  d9,  [sp, #16]
+        ldr             x30, [sp], #80
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+.endm
+
+        fgy             0, 0
+        fgy             0, 1
+        fgy             1, 0
+        fgy             1, 1
+endfunc
+
+jumptable fgy_loop_tbl
+        .word L(loop_00) - fgy_loop_tbl
+        .word L(loop_01) - fgy_loop_tbl
+        .word L(loop_10) - fgy_loop_tbl
+        .word L(loop_11) - fgy_loop_tbl
+endjumptable
+
+// void dav1d_fguv_32x32_420_16bpc_neon(pixel *const dst,
+//                                      const pixel *const src,
+//                                      const ptrdiff_t stride,
+//                                      const uint8_t scaling[SCALING_SIZE],
+//                                      const Dav1dFilmGrainData *const data,
+//                                      const entry grain_lut[][GRAIN_WIDTH],
+//                                      const pixel *const luma_row,
+//                                      const ptrdiff_t luma_stride,
+//                                      const int offsets[][2],
+//                                      const ptrdiff_t h, const ptrdiff_t uv,
+//                                      const ptrdiff_t is_id,
+//                                      const ptrdiff_t type,
+//                                      const int bitdepth_max);
+.macro fguv layout, sx, sy
+function fguv_32x32_\layout\()_16bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        str             x30,      [sp, #-80]!
+        stp             d8,  d9,  [sp, #16]
+        stp             d10, d11, [sp, #32]
+        stp             d12, d13, [sp, #48]
+        stp             d14, d15, [sp, #64]
+
+        ldp             x8,  x9,  [sp, #80]    // offsets, h
+        ldp             x10, x11, [sp, #96]    // uv, is_id
+        ldr             w16,      [sp, #120]   // bitdepth_max
+
+        ldr             w13, [x4, #FGD_SCALING_SHIFT]
+        ldr             w12, [x4, #FGD_CLIP_TO_RESTRICTED_RANGE]
+        dup             v23.8h,  w16           // bitdepth_max
+        clz             w16, w16
+        eor             w13, w13, #15          // 15 - scaling_shift
+        sub             w16, w16, #24          // -bitdepth_min_8
+
+        // !csfl
+        add             x10, x4,  x10, lsl #2  // + 4*uv
+        add             x14, x10, #FGD_UV_LUMA_MULT
+        add             x15, x10, #FGD_UV_MULT
+        add             x10, x10, #FGD_UV_OFFSET
+        neg             w16, w16               // bitdepth_min_8
+        ld1r            {v8.8h},  [x14]        // uv_luma_mult
+        ld1r            {v24.8h}, [x10]        // uv_offset
+        ld1r            {v9.8h},  [x15]        // uv_mult
+
+        dup             v29.8h,  w13           // 15 - scaling_shift
+        dup             v27.8h,  w16           // bitdepth_min_8
+
+        cbz             w12, 1f
+        // clip
+        movi            v30.8h,  #16
+        movi            v31.8h,  #240
+        sshl            v30.8h,  v30.8h,  v27.8h
+        sshl            v31.8h,  v31.8h,  v27.8h
+        cbz             w11, 2f
+        // is_id
+        movi            v31.8h,  #235
+        sshl            v31.8h,  v31.8h,  v27.8h
+        b               2f
+1:
+        // no clip
+        movi            v30.8h,  #0
+        mov             v31.16b, v23.16b       // bitdepth_max
+2:
+
+        ushr            v15.8h,  v23.8h,  #1   // grain_max
+        sshl            v24.8h,  v24.8h,  v27.8h // uv_offset << bitdepth_min_8
+        not             v14.16b, v15.16b       // grain_min
+
+        ldr             w12, [x8, #8]          // offsets[1][0]
+        ldr             w14, [x8, #4]          // offsets[0][1]
+        ldr             w16, [x8, #12]         // offsets[1][1]
+        ldr             w8,  [x8]              // offsets[0][0]
+
+        mov             x10, #GRAIN_WIDTH*2    // grain_lut stride
+
+        add             x5,  x5,  #(2*(3 + (2 >> \sx)*3)) // grain_lut += 9 or 6
+.if \sy
+        add             x5,  x5,  x10, lsl #2  // grain_lut += 4 * grain_stride
+        add             x5,  x5,  x10, lsl #1  // grain_lut += 2 * grain_stride
+.else
+        add             x5,  x5,  x10, lsl #3  // grain_lut += 8 * grain_stride
+        add             x5,  x5,  x10          // grain_lut += grain_stride
+.endif
+
+        calc_offset     w12, w13, w12, \sx, \sy
+        calc_offset     w14, w15, w14, \sx, \sy
+        calc_offset     w16, w17, w16, \sx, \sy
+        calc_offset     w8,  w11, w8,  \sx, \sy
+
+        add_offset      x13, w12, x13, x5,  x10
+        add_offset      x15, w14, x15, x5,  x10
+        add_offset      x17, w16, x17, x5,  x10
+        add_offset      x5,  w8,  x11, x5,  x10
+
+        add             x4,  x13, #2*(32 >> \sx)      // grain_lut += FG_BLOCK_SIZE * bx
+        add             x8,  x15, x10, lsl #(5 - \sy) // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             x11, x17, x10, lsl #(5 - \sy) // grain_lut += grain_stride * FG_BLOCK_SIZE * by
+        add             x11, x11, #2*(32 >> \sx)      // grain_lut += FG_BLOCK_SIZE * bx
+
+        ldr             w13, [sp, #112]        // type
+
+        movrel          x16, overlap_coeffs_\sx
+        movrel          x14, fguv_loop_sx\sx\()_tbl
+
+        ld1             {v27.4h, v28.4h}, [x16] // overlap_coeffs
+        tst             w13, #1
+        ldrsw           x13, [x14, w13, uxtw #2]
+
+        b.eq            1f
+        // y overlap
+        sub             w12, w9,  #(2 >> \sy)  // backup remaining h
+        mov             w9,  #(2 >> \sy)
+
+1:
+        add             x13, x14, x13
+
+.if \sy
+        movi            v25.8h,  #23
+        movi            v26.8h,  #22
+.else
+        movi            v25.8h,  #27
+        movi            v26.8h,  #17
+.endif
+
+.if \sy
+        add             x7,  x7,  x7           // luma_stride *= 2
+.endif
+
+        br              x13
+endfunc
+.endm
+
+fguv 420, 1, 1
+fguv 422, 1, 0
+fguv 444, 0, 0
+
+function fguv_loop_sx0_neon
+.macro fguv_loop_sx0 csfl, ox, oy
+L(fguv_loop_sx0_csfl\csfl\()_\ox\oy):
+        AARCH64_VALID_JUMP_TARGET
+1:
+.if \ox
+        ld1             {v4.4h}, [x4],  x10  // grain_lut old
+.endif
+.if \oy
+        ld1             {v0.8h,  v1.8h,  v2.8h,  v3.8h},  [x8],  x10 // grain_lut top
+.endif
+.if \ox && \oy
+        ld1             {v5.4h}, [x11], x10  // grain_lut top old
+.endif
+        ld1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x5],  x10 // grain_lut
+
+.if \ox
+        smull           v4.4s,   v4.4h,   v27.4h
+        smlal           v4.4s,   v16.4h,  v28.4h
+.endif
+
+.if \oy
+.if \ox
+        smull           v5.4s,   v5.4h,   v27.4h
+        smlal           v5.4s,   v0.4h,   v28.4h
+        sqrshrn         v4.4h,   v4.4s,   #5
+        sqrshrn         v5.4h,   v5.4s,   #5
+        smin            v4.4h,   v4.4h,   v15.4h
+        smin            v5.4h,   v5.4h,   v15.4h
+        smax            v4.4h,   v4.4h,   v14.4h
+        smax            v5.4h,   v5.4h,   v14.4h
+        ins             v16.d[0], v4.d[0]
+        ins             v0.d[0],  v5.d[0]
+.endif
+
+        smull           v6.4s,   v16.4h,  v26.4h
+        smull2          v7.4s,   v16.8h,  v26.8h
+        smull           v10.4s,  v17.4h,  v26.4h
+        smull2          v11.4s,  v17.8h,  v26.8h
+        smull           v16.4s,  v18.4h,  v26.4h
+        smull2          v17.4s,  v18.8h,  v26.8h
+        smull           v18.4s,  v19.4h,  v26.4h
+        smull2          v19.4s,  v19.8h,  v26.8h
+        smlal           v6.4s,   v0.4h,   v25.4h
+        smlal2          v7.4s,   v0.8h,   v25.8h
+        smlal           v10.4s,  v1.4h,   v25.4h
+        smlal2          v11.4s,  v1.8h,   v25.8h
+        smlal           v16.4s,  v2.4h,   v25.4h
+        smlal2          v17.4s,  v2.8h,   v25.8h
+        smlal           v18.4s,  v3.4h,   v25.4h
+        smlal2          v19.4s,  v3.8h,   v25.8h
+        sqrshrn         v6.4h,   v6.4s,   #5
+        sqrshrn2        v6.8h,   v7.4s,   #5
+        sqrshrn         v7.4h,   v10.4s,  #5
+        sqrshrn2        v7.8h,   v11.4s,  #5
+        sqrshrn         v10.4h,  v16.4s,  #5
+        sqrshrn2        v10.8h,  v17.4s,  #5
+        sqrshrn         v11.4h,  v18.4s,  #5
+        sqrshrn2        v11.8h,  v19.4s,  #5
+.endif
+
+.if \ox && !\oy
+        sqrshrn         v4.4h,   v4.4s,   #5
+        smin            v4.4h,   v4.4h,   v15.4h
+.endif
+        ld1             {v0.8h,  v1.8h,  v2.8h,  v3.8h},  [x6],  x7 // luma
+.if \oy
+        smin            v16.8h,  v6.8h,   v15.8h
+        smin            v17.8h,  v7.8h,   v15.8h
+        smin            v18.8h,  v10.8h,  v15.8h
+        smin            v19.8h,  v11.8h,  v15.8h
+        smax            v16.8h,  v16.8h,  v14.8h
+        smax            v17.8h,  v17.8h,  v14.8h
+        smax            v18.8h,  v18.8h,  v14.8h
+        smax            v19.8h,  v19.8h,  v14.8h
+.endif
+
+.if \ox && !\oy
+        smax            v4.4h,   v4.4h,   v14.4h
+.endif
+        ld1             {v10.8h, v11.8h, v12.8h, v13.8h}, [x1],  x2 // src
+.if \ox && !\oy
+        ins             v16.d[0], v4.d[0]
+.endif
+
+.if !\csfl
+        smull           v4.4s,   v0.4h,   v8.4h
+        smull2          v5.4s,   v0.8h,   v8.8h
+        smull           v6.4s,   v1.4h,   v8.4h
+        smull2          v7.4s,   v1.8h,   v8.8h
+        smull           v0.4s,   v2.4h,   v8.4h
+        smull2          v1.4s,   v2.8h,   v8.8h
+        smull           v2.4s,   v3.4h,   v8.4h
+        smull2          v3.4s,   v3.8h,   v8.8h
+        smlal           v4.4s,   v10.4h,  v9.4h
+        smlal2          v5.4s,   v10.8h,  v9.8h
+        smlal           v6.4s,   v11.4h,  v9.4h
+        smlal2          v7.4s,   v11.8h,  v9.8h
+        smlal           v0.4s,   v12.4h,  v9.4h
+        smlal2          v1.4s,   v12.8h,  v9.8h
+        smlal           v2.4s,   v13.4h,  v9.4h
+        smlal2          v3.4s,   v13.8h,  v9.8h
+        shrn            v4.4h,   v4.4s,   #6
+        shrn2           v4.8h,   v5.4s,   #6
+        shrn            v5.4h,   v6.4s,   #6
+        shrn2           v5.8h,   v7.4s,   #6
+        shrn            v6.4h,   v0.4s,   #6
+        shrn2           v6.8h,   v1.4s,   #6
+        shrn            v7.4h,   v2.4s,   #6
+        shrn2           v7.8h,   v3.4s,   #6
+        add             v0.8h,   v4.8h,   v24.8h
+        add             v1.8h,   v5.8h,   v24.8h
+        add             v2.8h,   v6.8h,   v24.8h
+        add             v3.8h,   v7.8h,   v24.8h
+        movi            v20.8h,  #0
+        smin            v0.8h,   v0.8h,   v23.8h
+        smin            v1.8h,   v1.8h,   v23.8h
+        smin            v2.8h,   v2.8h,   v23.8h
+        smin            v3.8h,   v3.8h,   v23.8h
+        smax            v0.8h,   v0.8h,   v20.8h
+        smax            v1.8h,   v1.8h,   v20.8h
+        smax            v2.8h,   v2.8h,   v20.8h
+        smax            v3.8h,   v3.8h,   v20.8h
+.else
+        // Make sure that uninitialized pixels out of range past the right
+        // edge are in range; their actual values shouldn't matter.
+        and             v0.16b,  v0.16b,  v23.16b
+        and             v1.16b,  v1.16b,  v23.16b
+        and             v2.16b,  v2.16b,  v23.16b
+        and             v3.16b,  v3.16b,  v23.16b
+.endif
+
+        bl              gather32_neon
+
+        uxtl            v4.8h,   v6.8b            // scaling
+        uxtl2           v5.8h,   v6.16b
+        uxtl            v6.8h,   v7.8b
+        uxtl2           v7.8h,   v7.16b
+
+        ushl            v4.8h,   v4.8h,   v29.8h  // scaling << (15 - scaling_shift)
+        ushl            v5.8h,   v5.8h,   v29.8h
+        ushl            v6.8h,   v6.8h,   v29.8h
+        ushl            v7.8h,   v7.8h,   v29.8h
+
+        sqrdmulh        v16.8h,  v16.8h,  v4.8h   // round2((scaling << (15 - scaling_shift) * grain, 15)
+        sqrdmulh        v17.8h,  v17.8h,  v5.8h
+        sqrdmulh        v18.8h,  v18.8h,  v6.8h
+        sqrdmulh        v19.8h,  v19.8h,  v7.8h
+
+        usqadd          v10.8h,  v16.8h           // *src + noise
+        usqadd          v11.8h,  v17.8h
+        usqadd          v12.8h,  v18.8h
+        usqadd          v13.8h,  v19.8h
+
+        umax            v0.8h,   v10.8h,  v30.8h
+        umax            v1.8h,   v11.8h,  v30.8h
+        umax            v2.8h,   v12.8h,  v30.8h
+        umax            v3.8h,   v13.8h,  v30.8h
+        umin            v0.8h,   v0.8h,   v31.8h
+        umin            v1.8h,   v1.8h,   v31.8h
+        umin            v2.8h,   v2.8h,   v31.8h
+        umin            v3.8h,   v3.8h,   v31.8h
+
+        subs            w9,  w9,  #1
+.if \oy
+        dup             v25.8h,  v28.h[0]
+        dup             v26.8h,  v28.h[1]
+.endif
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h},  [x0], x2 // dst
+        b.gt            1b
+
+.if \oy
+        cmp             w12, #0
+        mov             w9,  w12               // restore actual remaining h
+        b.gt            L(fguv_loop_sx0_csfl\csfl\()_\ox\()0)
+.endif
+        b               9f
+.endm
+        fguv_loop_sx0   0, 0, 0
+        fguv_loop_sx0   0, 0, 1
+        fguv_loop_sx0   0, 1, 0
+        fguv_loop_sx0   0, 1, 1
+        fguv_loop_sx0   1, 0, 0
+        fguv_loop_sx0   1, 0, 1
+        fguv_loop_sx0   1, 1, 0
+        fguv_loop_sx0   1, 1, 1
+
+9:
+        ldp             d14, d15, [sp, #64]
+        ldp             d12, d13, [sp, #48]
+        ldp             d10, d11, [sp, #32]
+        ldp             d8,  d9,  [sp, #16]
+        ldr             x30,      [sp], #80
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+jumptable fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl0_00) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl0_01) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl0_10) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl0_11) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl1_00) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl1_01) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl1_10) - fguv_loop_sx0_tbl
+        .word L(fguv_loop_sx0_csfl1_11) - fguv_loop_sx0_tbl
+endjumptable
+
+function fguv_loop_sx1_neon
+.macro fguv_loop_sx1 csfl, ox, oy
+L(fguv_loop_sx1_csfl\csfl\()_\ox\oy):
+        AARCH64_VALID_JUMP_TARGET
+1:
+.if \ox
+        ld1             {v18.4h}, [x4],  x10  // grain_lut old
+.endif
+.if \oy
+        ld1             {v20.8h, v21.8h},  [x8],  x10 // grain_lut top
+.endif
+.if \ox && \oy
+        ld1             {v19.4h}, [x11], x10  // grain_lut top old
+.endif
+        ld1             {v16.8h, v17.8h}, [x5],  x10 // grain_lut
+
+.if \ox
+        smull           v18.4s,  v18.4h,  v27.4h
+        smlal           v18.4s,  v16.4h,  v28.4h
+.endif
+
+.if \oy
+.if \ox
+        smull           v19.4s,  v19.4h,  v27.4h
+        smlal           v19.4s,  v20.4h,  v28.4h
+        sqrshrn         v18.4h,  v18.4s,  #5
+        sqrshrn         v19.4h,  v19.4s,  #5
+        smin            v18.4h,  v18.4h,  v15.4h
+        smin            v19.4h,  v19.4h,  v15.4h
+        smax            v18.4h,  v18.4h,  v14.4h
+        smax            v19.4h,  v19.4h,  v14.4h
+        ins             v16.d[0], v18.d[0]
+        ins             v20.d[0], v19.d[0]
+.endif
+
+        smull           v0.4s,   v16.4h,  v26.4h
+        smull2          v1.4s,   v16.8h,  v26.8h
+        smull           v2.4s,   v17.4h,  v26.4h
+        smull2          v3.4s,   v17.8h,  v26.8h
+        smlal           v0.4s,   v20.4h,  v25.4h
+        smlal2          v1.4s,   v20.8h,  v25.8h
+        smlal           v2.4s,   v21.4h,  v25.4h
+        smlal2          v3.4s,   v21.8h,  v25.8h
+        sqrshrn         v16.4h,  v0.4s,   #5
+        sqrshrn2        v16.8h,  v1.4s,   #5
+        sqrshrn         v17.4h,  v2.4s,   #5
+        sqrshrn2        v17.8h,  v3.4s,   #5
+.endif
+
+.if \ox && !\oy
+        sqrshrn         v18.4h,  v18.4s,  #5
+        smin            v18.4h,  v18.4h,  v15.4h
+.endif
+        ld1             {v0.8h,  v1.8h,  v2.8h,  v3.8h},  [x6],  x7 // luma
+.if \oy
+        smin            v16.8h,  v16.8h,  v15.8h
+        smin            v17.8h,  v17.8h,  v15.8h
+        smax            v16.8h,  v16.8h,  v14.8h
+        smax            v17.8h,  v17.8h,  v14.8h
+.endif
+
+.if \ox && !\oy
+        smax            v18.4h,  v18.4h,  v14.4h
+.endif
+        ld1             {v10.8h, v11.8h},  [x1],  x2 // src
+.if \ox && !\oy
+        ins             v16.d[0], v18.d[0]
+.endif
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v1.8h,   v2.8h,   v3.8h
+        urshr           v0.8h,   v0.8h,   #1
+        urshr           v1.8h,   v1.8h,   #1
+.if !\csfl
+        smull           v2.4s,   v0.4h,   v8.4h
+        smull2          v3.4s,   v0.8h,   v8.8h
+        smull           v0.4s,   v1.4h,   v8.4h
+        smull2          v1.4s,   v1.8h,   v8.8h
+        smlal           v2.4s,   v10.4h,  v9.4h
+        smlal2          v3.4s,   v10.8h,  v9.8h
+        smlal           v0.4s,   v11.4h,  v9.4h
+        smlal2          v1.4s,   v11.8h,  v9.8h
+        shrn            v2.4h,   v2.4s,   #6
+        shrn2           v2.8h,   v3.4s,   #6
+        shrn            v3.4h,   v0.4s,   #6
+        shrn2           v3.8h,   v1.4s,   #6
+        add             v0.8h,   v2.8h,   v24.8h
+        add             v1.8h,   v3.8h,   v24.8h
+        movi            v2.8h,   #0
+        smin            v0.8h,   v0.8h,   v23.8h
+        smin            v1.8h,   v1.8h,   v23.8h
+        smax            v0.8h,   v0.8h,   v2.8h
+        smax            v1.8h,   v1.8h,   v2.8h
+.else
+        // Make sure that uninitialized pixels out of range past the right
+        // edge are in range; their actual values shouldn't matter.
+        and             v0.16b,  v0.16b,  v23.16b
+        and             v1.16b,  v1.16b,  v23.16b
+.endif
+
+        bl              gather16_neon
+
+        uxtl            v4.8h,   v6.8b            // scaling
+        uxtl2           v5.8h,   v6.16b
+
+        ushl            v4.8h,   v4.8h,   v29.8h  // scaling << (15 - scaling_shift)
+        ushl            v5.8h,   v5.8h,   v29.8h
+
+        sqrdmulh        v16.8h,  v16.8h,  v4.8h   // round2((scaling << (15 - scaling_shift) * grain, 15)
+        sqrdmulh        v17.8h,  v17.8h,  v5.8h
+
+        usqadd          v10.8h,  v16.8h           // *src + noise
+        usqadd          v11.8h,  v17.8h
+
+        umax            v0.8h,   v10.8h,  v30.8h
+        umax            v1.8h,   v11.8h,  v30.8h
+        umin            v0.8h,   v0.8h,   v31.8h
+        umin            v1.8h,   v1.8h,   v31.8h
+
+.if \oy
+        mov             v16.16b, v25.16b
+.endif
+        subs            w9,  w9,  #1
+.if \oy
+        mov             v25.16b, v26.16b
+        mov             v26.16b, v16.16b
+.endif
+        st1             {v0.8h, v1.8h},  [x0], x2 // dst
+        b.gt            1b
+
+.if \oy
+        cmp             w12, #0
+        mov             w9,  w12               // restore actual remaining h
+        b.gt            L(fguv_loop_sx1_csfl\csfl\()_\ox\()0)
+.endif
+
+        b               9f
+.endm
+        fguv_loop_sx1   0, 0, 0
+        fguv_loop_sx1   0, 0, 1
+        fguv_loop_sx1   0, 1, 0
+        fguv_loop_sx1   0, 1, 1
+        fguv_loop_sx1   1, 0, 0
+        fguv_loop_sx1   1, 0, 1
+        fguv_loop_sx1   1, 1, 0
+        fguv_loop_sx1   1, 1, 1
+
+9:
+        ldp             d14, d15, [sp, #64]
+        ldp             d12, d13, [sp, #48]
+        ldp             d10, d11, [sp, #32]
+        ldp             d8,  d9,  [sp, #16]
+        ldr             x30,      [sp], #80
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+endfunc
+
+jumptable fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl0_00) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl0_01) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl0_10) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl0_11) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl1_00) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl1_01) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl1_10) - fguv_loop_sx1_tbl
+        .word L(fguv_loop_sx1_csfl1_11) - fguv_loop_sx1_tbl
+endjumptable
diff --git a/media/libdav1d/src/src/arm/64/ipred.S b/media/libdav1d/src/src/arm/64/ipred.S
new file mode 100644
index 0000000000..5a375d8dca
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/ipred.S
@@ -0,0 +1,5342 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// void ipred_dc_128_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int a,
+//                             const int max_width, const int max_height);
+function ipred_dc_128_8bpc_neon, export=1
+        clz             w3,  w3
+        movrel          x5,  ipred_dc_128_tbl
+        sub             w3,  w3,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        movi            v0.16b,  #128
+        add             x5,  x5,  x3
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        movi            v1.16b,  #128
+32:
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+        movi            v1.16b,  #128
+        movi            v2.16b,  #128
+        movi            v3.16b,  #128
+64:
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable ipred_dc_128_tbl
+        .word 640b - ipred_dc_128_tbl
+        .word 320b - ipred_dc_128_tbl
+        .word 160b - ipred_dc_128_tbl
+        .word 80b  - ipred_dc_128_tbl
+        .word 40b  - ipred_dc_128_tbl
+endjumptable
+
+// void ipred_v_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                        const pixel *const topleft,
+//                        const int width, const int height, const int a,
+//                        const int max_width, const int max_height);
+function ipred_v_8bpc_neon, export=1
+        clz             w3,  w3
+        movrel          x5,  ipred_v_tbl
+        sub             w3,  w3,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        add             x2,  x2,  #1
+        add             x5,  x5,  x3
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.s}[0],  [x2]
+4:
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [x2]
+8:
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b}, [x2]
+16:
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b, v1.16b}, [x2]
+32:
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x2]
+64:
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable ipred_v_tbl
+        .word 640b - ipred_v_tbl
+        .word 320b - ipred_v_tbl
+        .word 160b - ipred_v_tbl
+        .word 80b  - ipred_v_tbl
+        .word 40b  - ipred_v_tbl
+endjumptable
+
+// void ipred_h_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                        const pixel *const topleft,
+//                        const int width, const int height, const int a,
+//                        const int max_width, const int max_height);
+function ipred_h_8bpc_neon, export=1
+        clz             w3,  w3
+        movrel          x5,  ipred_h_tbl
+        sub             w3,  w3,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        sub             x2,  x2,  #4
+        add             x5,  x5,  x3
+        mov             x7,  #-4
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},  [x2], x7
+        st1             {v3.s}[0],  [x0], x1
+        st1             {v2.s}[0],  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v1.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},  [x2], x7
+        st1             {v3.8b},  [x0], x1
+        st1             {v2.8b},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v1.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ld4r            {v0.16b, v1.16b, v2.16b, v3.16b},  [x2], x7
+        st1             {v3.16b}, [x0], x1
+        st1             {v2.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v1.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ld4r            {v0.16b, v1.16b, v2.16b, v3.16b},  [x2], x7
+        str             q3,  [x0, #16]
+        str             q2,  [x6, #16]
+        st1             {v3.16b}, [x0], x1
+        st1             {v2.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        str             q1,  [x0, #16]
+        str             q0,  [x6, #16]
+        st1             {v1.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+64:
+        ld4r            {v0.16b, v1.16b, v2.16b, v3.16b},  [x2], x7
+        str             q3,  [x0, #16]
+        str             q2,  [x6, #16]
+        stp             q3,  q3,  [x0, #32]
+        stp             q2,  q2,  [x6, #32]
+        st1             {v3.16b}, [x0], x1
+        st1             {v2.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        str             q1,  [x0, #16]
+        str             q0,  [x6, #16]
+        stp             q1,  q1,  [x0, #32]
+        stp             q0,  q0,  [x6, #32]
+        st1             {v1.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable ipred_h_tbl
+        .word 640b - ipred_h_tbl
+        .word 320b - ipred_h_tbl
+        .word 160b - ipred_h_tbl
+        .word 80b  - ipred_h_tbl
+        .word 40b  - ipred_h_tbl
+endjumptable
+
+// void ipred_dc_top_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int a,
+//                             const int max_width, const int max_height);
+function ipred_dc_top_8bpc_neon, export=1
+        clz             w3,  w3
+        movrel          x5,  ipred_dc_top_tbl
+        sub             w3,  w3,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        add             x2,  x2,  #1
+        add             x5,  x5,  x3
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v0.2s},  [x2]
+        uaddlv          h0,      v0.8b
+        rshrn           v0.8b,   v0.8h,   #3
+        dup             v0.8b,   v0.b[0]
+4:
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [x2]
+        uaddlv          h0,      v0.8b
+        rshrn           v0.8b,   v0.8h,   #3
+        dup             v0.8b,   v0.b[0]
+8:
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b}, [x2]
+        uaddlv          h0,      v0.16b
+        rshrn           v0.8b,   v0.8h,   #4
+        dup             v0.16b,  v0.b[0]
+16:
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b, v1.16b}, [x2]
+        uaddlv          h0,      v0.16b
+        uaddlv          h1,      v1.16b
+        add             v2.4h,   v0.4h,   v1.4h
+        rshrn           v2.8b,   v2.8h,   #5
+        dup             v0.16b,  v2.b[0]
+        dup             v1.16b,  v2.b[0]
+32:
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x2]
+        uaddlv          h0,      v0.16b
+        uaddlv          h1,      v1.16b
+        uaddlv          h2,      v2.16b
+        uaddlv          h3,      v3.16b
+        add             v4.4h,   v0.4h,   v1.4h
+        add             v5.4h,   v2.4h,   v3.4h
+        add             v4.4h,   v4.4h,   v5.4h
+        rshrn           v4.8b,   v4.8h,   #6
+        dup             v0.16b,  v4.b[0]
+        dup             v1.16b,  v4.b[0]
+        dup             v2.16b,  v4.b[0]
+        dup             v3.16b,  v4.b[0]
+64:
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable ipred_dc_top_tbl
+        .word 640b - ipred_dc_top_tbl
+        .word 320b - ipred_dc_top_tbl
+        .word 160b - ipred_dc_top_tbl
+        .word 80b  - ipred_dc_top_tbl
+        .word 40b  - ipred_dc_top_tbl
+endjumptable
+
+// void ipred_dc_left_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int a,
+//                              const int max_width, const int max_height);
+function ipred_dc_left_8bpc_neon, export=1
+        sub             x2,  x2,  w4, uxtw
+        clz             w3,  w3
+        clz             w7,  w4
+        movrel          x5,  ipred_dc_left_tbl
+        sub             w3,  w3,  #20 // 25 leading bits, minus table offset 5
+        sub             w7,  w7,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        ldrsw           x7,  [x5, w7, uxtw #2]
+        add             x3,  x5,  x3
+        add             x5,  x5,  x7
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+
+L(ipred_dc_left_h4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v0.2s},  [x2]
+        uaddlv          h0,      v0.8b
+        rshrn           v0.8b,   v0.8h,   #3
+        dup             v0.16b,  v0.b[0]
+        br              x3
+L(ipred_dc_left_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        b.gt            1b
+        ret
+
+L(ipred_dc_left_h8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [x2]
+        uaddlv          h0,      v0.8b
+        rshrn           v0.8b,   v0.8h,   #3
+        dup             v0.16b,  v0.b[0]
+        br              x3
+L(ipred_dc_left_w8):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        b.gt            1b
+        ret
+
+L(ipred_dc_left_h16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b}, [x2]
+        uaddlv          h0,      v0.16b
+        rshrn           v0.8b,   v0.8h,   #4
+        dup             v0.16b,  v0.b[0]
+        br              x3
+L(ipred_dc_left_w16):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        b.gt            1b
+        ret
+
+L(ipred_dc_left_h32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b, v1.16b}, [x2]
+        uaddlv          h0,      v0.16b
+        uaddlv          h1,      v1.16b
+        add             v0.4h,   v0.4h,   v1.4h
+        rshrn           v0.8b,   v0.8h,   #5
+        dup             v0.16b,  v0.b[0]
+        br              x3
+L(ipred_dc_left_w32):
+        AARCH64_VALID_JUMP_TARGET
+        mov             v1.16b,  v0.16b
+1:
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        b.gt            1b
+        ret
+
+L(ipred_dc_left_h64):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x2]
+        uaddlv          h0,      v0.16b
+        uaddlv          h1,      v1.16b
+        uaddlv          h2,      v2.16b
+        uaddlv          h3,      v3.16b
+        add             v0.4h,   v0.4h,   v1.4h
+        add             v2.4h,   v2.4h,   v3.4h
+        add             v0.4h,   v0.4h,   v2.4h
+        rshrn           v0.8b,   v0.8h,   #6
+        dup             v0.16b,  v0.b[0]
+        br              x3
+L(ipred_dc_left_w64):
+        AARCH64_VALID_JUMP_TARGET
+        mov             v1.16b,  v0.16b
+        mov             v2.16b,  v0.16b
+        mov             v3.16b,  v0.16b
+1:
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        b.gt            1b
+        ret
+endfunc
+
+jumptable ipred_dc_left_tbl
+        .word L(ipred_dc_left_h64) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_h32) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_h16) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_h8)  - ipred_dc_left_tbl
+        .word L(ipred_dc_left_h4)  - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w64) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w32) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w16) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w8)  - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w4)  - ipred_dc_left_tbl
+endjumptable
+
+// void ipred_dc_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const topleft,
+//                         const int width, const int height, const int a,
+//                         const int max_width, const int max_height);
+function ipred_dc_8bpc_neon, export=1
+        sub             x2,  x2,  w4, uxtw
+        add             w7,  w3,  w4             // width + height
+        clz             w3,  w3
+        clz             w6,  w4
+        dup             v16.8h, w7               // width + height
+        movrel          x5,  ipred_dc_tbl
+        rbit            w7,  w7                  // rbit(width + height)
+        sub             w3,  w3,  #20            // 25 leading bits, minus table offset 5
+        sub             w6,  w6,  #25
+        clz             w7,  w7                  // ctz(width + height)
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        ldrsw           x6,  [x5, w6, uxtw #2]
+        neg             w7,  w7                  // -ctz(width + height)
+        add             x3,  x5,  x3
+        add             x5,  x5,  x6
+        ushr            v16.8h,  v16.8h,  #1     // (width + height) >> 1
+        dup             v17.8h,  w7              // -ctz(width + height)
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+
+L(ipred_dc_h4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.s}[0],  [x2], #4
+        ins             v0.s[1], wzr
+        uaddlv          h0,      v0.8b
+        add             x2,  x2,  #1
+        br              x3
+L(ipred_dc_w4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.s}[0],  [x2]
+        ins             v1.s[1], wzr
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h1,      v1.8b
+        cmp             w4,  #4
+        add             v0.4h,   v0.4h,   v1.4h
+        ushl            v0.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 8/16
+        mov             w16, #(0x3334/2)
+        movk            w16, #(0x5556/2), lsl #16
+        add             w17, w4,  w4  // w17 = 2*h = 16 or 32
+        lsr             w16, w16, w17
+        dup             v16.4h,  w16
+        sqdmulh         v0.4h,   v0.4h,   v16.4h
+1:
+        dup             v0.8b,   v0.b[0]
+2:
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.s}[0],  [x0], x1
+        st1             {v0.s}[0],  [x6], x1
+        b.gt            2b
+        ret
+
+L(ipred_dc_h8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [x2], #8
+        uaddlv          h0,      v0.8b
+        add             x2,  x2,  #1
+        br              x3
+L(ipred_dc_w8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.8b},  [x2]
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h1,      v1.8b
+        cmp             w4,  #8
+        add             v0.4h,   v0.4h,   v1.4h
+        ushl            v0.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 4/16/32
+        cmp             w4,  #32
+        mov             w16, #(0x3334/2)
+        mov             w17, #(0x5556/2)
+        csel            w16, w16, w17, eq
+        dup             v16.4h,  w16
+        sqdmulh         v0.4h,   v0.4h,   v16.4h
+1:
+        dup             v0.8b,   v0.b[0]
+2:
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8b},  [x0], x1
+        st1             {v0.8b},  [x6], x1
+        b.gt            2b
+        ret
+
+L(ipred_dc_h16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b}, [x2], #16
+        uaddlv          h0,      v0.16b
+        add             x2,  x2,  #1
+        br              x3
+L(ipred_dc_w16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.16b}, [x2]
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h1,      v1.16b
+        cmp             w4,  #16
+        add             v0.4h,   v0.4h,   v1.4h
+        ushl            v0.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 4/8/32/64
+        tst             w4,  #(32+16+8) // 16 added to make a consecutive bitmask
+        mov             w16, #(0x3334/2)
+        mov             w17, #(0x5556/2)
+        csel            w16, w16, w17, eq
+        dup             v16.4h,  w16
+        sqdmulh         v0.4h,   v0.4h,   v16.4h
+1:
+        dup             v0.16b,  v0.b[0]
+2:
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b}, [x0], x1
+        st1             {v0.16b}, [x6], x1
+        b.gt            2b
+        ret
+
+L(ipred_dc_h32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b, v1.16b}, [x2], #32
+        uaddlv          h0,      v0.16b
+        uaddlv          h1,      v1.16b
+        add             x2,  x2,  #1
+        add             v0.4h,   v0.4h,   v1.4h
+        br              x3
+L(ipred_dc_w32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.16b, v2.16b}, [x2]
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h1,      v1.16b
+        uaddlv          h2,      v2.16b
+        cmp             w4,  #32
+        add             v0.4h,   v0.4h,   v1.4h
+        add             v0.4h,   v0.4h,   v2.4h
+        ushl            v4.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 8/16/64
+        cmp             w4,  #8
+        mov             w16, #(0x3334/2)
+        mov             w17, #(0x5556/2)
+        csel            w16, w16, w17, eq
+        dup             v16.4h,  w16
+        sqdmulh         v4.4h,   v4.4h,   v16.4h
+1:
+        dup             v0.16b,  v4.b[0]
+        dup             v1.16b,  v4.b[0]
+2:
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b}, [x0], x1
+        st1             {v0.16b, v1.16b}, [x6], x1
+        b.gt            2b
+        ret
+
+L(ipred_dc_h64):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x2], #64
+        uaddlv          h0,      v0.16b
+        uaddlv          h1,      v1.16b
+        uaddlv          h2,      v2.16b
+        uaddlv          h3,      v3.16b
+        add             v0.4h,   v0.4h,   v1.4h
+        add             v2.4h,   v2.4h,   v3.4h
+        add             x2,  x2,  #1
+        add             v0.4h,   v0.4h,   v2.4h
+        br              x3
+L(ipred_dc_w64):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.16b, v2.16b, v3.16b, v4.16b}, [x2]
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h1,      v1.16b
+        uaddlv          h2,      v2.16b
+        uaddlv          h3,      v3.16b
+        uaddlv          h4,      v4.16b
+        add             v1.4h,   v1.4h,   v2.4h
+        add             v3.4h,   v3.4h,   v4.4h
+        cmp             w4,  #64
+        add             v0.4h,   v0.4h,   v1.4h
+        add             v0.4h,   v0.4h,   v3.4h
+        ushl            v4.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 16/32
+        mov             w16, #(0x5556/2)
+        movk            w16, #(0x3334/2), lsl #16
+        lsr             w16, w16, w4
+        dup             v16.4h,  w16
+        sqdmulh         v4.4h,   v4.4h,   v16.4h
+1:
+        dup             v0.16b,  v4.b[0]
+        dup             v1.16b,  v4.b[0]
+        dup             v2.16b,  v4.b[0]
+        dup             v3.16b,  v4.b[0]
+2:
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x6], x1
+        b.gt            2b
+        ret
+endfunc
+
+jumptable ipred_dc_tbl
+        .word L(ipred_dc_h64) - ipred_dc_tbl
+        .word L(ipred_dc_h32) - ipred_dc_tbl
+        .word L(ipred_dc_h16) - ipred_dc_tbl
+        .word L(ipred_dc_h8)  - ipred_dc_tbl
+        .word L(ipred_dc_h4)  - ipred_dc_tbl
+        .word L(ipred_dc_w64) - ipred_dc_tbl
+        .word L(ipred_dc_w32) - ipred_dc_tbl
+        .word L(ipred_dc_w16) - ipred_dc_tbl
+        .word L(ipred_dc_w8)  - ipred_dc_tbl
+        .word L(ipred_dc_w4)  - ipred_dc_tbl
+endjumptable
+
+// void ipred_paeth_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                            const pixel *const topleft,
+//                            const int width, const int height, const int a,
+//                            const int max_width, const int max_height);
+function ipred_paeth_8bpc_neon, export=1
+        clz             w9,  w3
+        movrel          x5,  ipred_paeth_tbl
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        ld1r            {v4.16b},  [x2]
+        add             x8,  x2,  #1
+        sub             x2,  x2,  #4
+        add             x5,  x5,  x9
+        mov             x7,  #-4
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v5.4s},  [x8]
+        usubl           v6.8h,   v5.8b,   v4.8b   // top - topleft
+4:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},  [x2], x7
+        zip1            v0.2s,   v0.2s,   v1.2s
+        zip1            v2.2s,   v2.2s,   v3.2s
+        uaddw           v16.8h,  v6.8h,   v0.8b
+        uaddw           v17.8h,  v6.8h,   v2.8b
+        sqxtun          v16.8b,  v16.8h           // base
+        sqxtun2         v16.16b, v17.8h
+        zip1            v0.2d,   v0.2d,   v2.2d
+        uabd            v20.16b, v5.16b,  v16.16b // tdiff
+        uabd            v22.16b, v4.16b,  v16.16b // tldiff
+        uabd            v16.16b, v0.16b,  v16.16b // ldiff
+        umin            v18.16b, v20.16b, v22.16b // min(tdiff, tldiff)
+        cmhs            v20.16b, v22.16b, v20.16b // tldiff >= tdiff
+        cmhs            v16.16b, v18.16b, v16.16b // min(tdiff, tldiff) >= ldiff
+        bsl             v20.16b, v5.16b,  v4.16b  // tdiff <= tldiff ? top : topleft
+        bit             v20.16b, v0.16b,  v16.16b // ldiff <= min ? left : ...
+        st1             {v20.s}[3], [x0], x1
+        st1             {v20.s}[2], [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v20.s}[1], [x0], x1
+        st1             {v20.s}[0], [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v5.2d},  [x8]
+        usubl           v6.8h,   v5.8b,   v4.8b   // top - topleft
+8:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},  [x2], x7
+        uaddw           v16.8h,  v6.8h,   v0.8b
+        uaddw           v17.8h,  v6.8h,   v1.8b
+        uaddw           v18.8h,  v6.8h,   v2.8b
+        uaddw           v19.8h,  v6.8h,   v3.8b
+        sqxtun          v16.8b,  v16.8h           // base
+        sqxtun2         v16.16b, v17.8h
+        sqxtun          v18.8b,  v18.8h
+        sqxtun2         v18.16b, v19.8h
+        zip1            v2.2d,   v2.2d,   v3.2d
+        zip1            v0.2d,   v0.2d,   v1.2d
+        uabd            v21.16b, v5.16b,  v18.16b // tdiff
+        uabd            v20.16b, v5.16b,  v16.16b
+        uabd            v23.16b, v4.16b,  v18.16b // tldiff
+        uabd            v22.16b, v4.16b,  v16.16b
+        uabd            v17.16b, v2.16b,  v18.16b // ldiff
+        uabd            v16.16b, v0.16b,  v16.16b
+        umin            v19.16b, v21.16b, v23.16b // min(tdiff, tldiff)
+        umin            v18.16b, v20.16b, v22.16b
+        cmhs            v21.16b, v23.16b, v21.16b // tldiff >= tdiff
+        cmhs            v20.16b, v22.16b, v20.16b
+        cmhs            v17.16b, v19.16b, v17.16b // min(tdiff, tldiff) >= ldiff
+        cmhs            v16.16b, v18.16b, v16.16b
+        bsl             v21.16b, v5.16b,  v4.16b  // tdiff <= tldiff ? top : topleft
+        bsl             v20.16b, v5.16b,  v4.16b
+        bit             v21.16b, v2.16b,  v17.16b // ldiff <= min ? left : ...
+        bit             v20.16b, v0.16b,  v16.16b
+        st1             {v21.d}[1], [x0], x1
+        st1             {v21.d}[0], [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v20.d}[1], [x0], x1
+        st1             {v20.d}[0], [x6], x1
+        b.gt            8b
+        ret
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v5.16b},  [x8], #16
+        mov             w9,  w3
+        // Set up pointers for four rows in parallel; x0, x6, x5, x10
+        add             x5,  x0,  x1
+        add             x10, x6,  x1
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3, uxtw
+1:
+        ld4r            {v0.16b, v1.16b, v2.16b, v3.16b},  [x2], x7
+2:
+        usubl           v6.8h,   v5.8b,   v4.8b   // top - topleft
+        usubl2          v7.8h,   v5.16b,  v4.16b
+        uaddw           v24.8h,  v6.8h,   v0.8b
+        uaddw           v25.8h,  v7.8h,   v0.8b
+        uaddw           v26.8h,  v6.8h,   v1.8b
+        uaddw           v27.8h,  v7.8h,   v1.8b
+        uaddw           v28.8h,  v6.8h,   v2.8b
+        uaddw           v29.8h,  v7.8h,   v2.8b
+        uaddw           v30.8h,  v6.8h,   v3.8b
+        uaddw           v31.8h,  v7.8h,   v3.8b
+        sqxtun          v17.8b,  v26.8h           // base
+        sqxtun2         v17.16b, v27.8h
+        sqxtun          v16.8b,  v24.8h
+        sqxtun2         v16.16b, v25.8h
+        sqxtun          v19.8b,  v30.8h
+        sqxtun2         v19.16b, v31.8h
+        sqxtun          v18.8b,  v28.8h
+        sqxtun2         v18.16b, v29.8h
+        uabd            v23.16b, v5.16b,  v19.16b // tdiff
+        uabd            v22.16b, v5.16b,  v18.16b
+        uabd            v21.16b, v5.16b,  v17.16b
+        uabd            v20.16b, v5.16b,  v16.16b
+        uabd            v27.16b, v4.16b,  v19.16b // tldiff
+        uabd            v26.16b, v4.16b,  v18.16b
+        uabd            v25.16b, v4.16b,  v17.16b
+        uabd            v24.16b, v4.16b,  v16.16b
+        uabd            v19.16b, v3.16b,  v19.16b // ldiff
+        uabd            v18.16b, v2.16b,  v18.16b
+        uabd            v17.16b, v1.16b,  v17.16b
+        uabd            v16.16b, v0.16b,  v16.16b
+        umin            v31.16b, v23.16b, v27.16b // min(tdiff, tldiff)
+        umin            v30.16b, v22.16b, v26.16b
+        umin            v29.16b, v21.16b, v25.16b
+        umin            v28.16b, v20.16b, v24.16b
+        cmhs            v23.16b, v27.16b, v23.16b // tldiff >= tdiff
+        cmhs            v22.16b, v26.16b, v22.16b
+        cmhs            v21.16b, v25.16b, v21.16b
+        cmhs            v20.16b, v24.16b, v20.16b
+        cmhs            v19.16b, v31.16b, v19.16b // min(tdiff, tldiff) >= ldiff
+        cmhs            v18.16b, v30.16b, v18.16b
+        cmhs            v17.16b, v29.16b, v17.16b
+        cmhs            v16.16b, v28.16b, v16.16b
+        bsl             v23.16b, v5.16b,  v4.16b  // tdiff <= tldiff ? top : topleft
+        bsl             v22.16b, v5.16b,  v4.16b
+        bsl             v21.16b, v5.16b,  v4.16b
+        bsl             v20.16b, v5.16b,  v4.16b
+        bit             v23.16b, v3.16b,  v19.16b // ldiff <= min ? left : ...
+        bit             v22.16b, v2.16b,  v18.16b
+        bit             v21.16b, v1.16b,  v17.16b
+        bit             v20.16b, v0.16b,  v16.16b
+        subs            w3,  w3,  #16
+        st1             {v23.16b}, [x0],  #16
+        st1             {v22.16b}, [x6],  #16
+        st1             {v21.16b}, [x5],  #16
+        st1             {v20.16b}, [x10], #16
+        b.le            8f
+        ld1             {v5.16b},  [x8], #16
+        b               2b
+8:
+        subs            w4,  w4,  #4
+        b.le            9f
+        // End of horizontal loop, move pointers to next four rows
+        sub             x8,  x8,  w9, uxtw
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        // Load the top row as early as possible
+        ld1             {v5.16b},  [x8], #16
+        add             x5,  x5,  x1
+        add             x10, x10, x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_paeth_tbl
+        .word 640b - ipred_paeth_tbl
+        .word 320b - ipred_paeth_tbl
+        .word 160b - ipred_paeth_tbl
+        .word 80b  - ipred_paeth_tbl
+        .word 40b  - ipred_paeth_tbl
+endjumptable
+
+// void ipred_smooth_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int a,
+//                             const int max_width, const int max_height);
+function ipred_smooth_8bpc_neon, export=1
+        movrel          x10, X(sm_weights)
+        add             x11, x10, w4, uxtw
+        add             x10, x10, w3, uxtw
+        clz             w9,  w3
+        movrel          x5,  ipred_smooth_tbl
+        sub             x12, x2,  w4, uxtw
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        ld1r            {v4.16b},  [x12] // bottom
+        add             x8,  x2,  #1
+        add             x5,  x5,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v6.2s}, [x8]             // top
+        ld1r            {v7.2s}, [x10]            // weights_hor
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+        dup             v5.16b,  v6.b[3]          // right
+        usubl           v6.8h,   v6.8b,   v4.8b   // top-bottom
+        uxtl            v7.8h,   v7.8b            // weights_hor
+4:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},  [x2], x7 // left
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b},  [x11], #4 // weights_ver
+        shll            v20.8h,  v5.8b,   #8      // right*256
+        shll            v21.8h,  v5.8b,   #8
+        zip1            v1.2s,   v1.2s,   v0.2s   // left, flipped
+        zip1            v0.2s,   v3.2s,   v2.2s
+        zip1            v16.2s,  v16.2s,  v17.2s  // weights_ver
+        zip1            v18.2s,  v18.2s,  v19.2s
+        shll            v22.8h,  v4.8b,   #8      // bottom*256
+        shll            v23.8h,  v4.8b,   #8
+        usubl           v0.8h,   v0.8b,   v5.8b   // left-right
+        usubl           v1.8h,   v1.8b,   v5.8b
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v18.8h,  v18.8b
+        mla             v20.8h,  v0.8h,   v7.8h   // right*256  + (left-right)*weights_hor
+        mla             v21.8h,  v1.8h,   v7.8h
+        mla             v22.8h,  v6.8h,   v16.8h  // bottom*256 + (top-bottom)*weights_ver
+        mla             v23.8h,  v6.8h,   v18.8h
+        uhadd           v20.8h,  v20.8h,  v22.8h
+        uhadd           v21.8h,  v21.8h,  v23.8h
+        rshrn           v20.8b,  v20.8h,  #8
+        rshrn           v21.8b,  v21.8h,  #8
+        st1             {v20.s}[0], [x0], x1
+        st1             {v20.s}[1], [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v21.s}[0], [x0], x1
+        st1             {v21.s}[1], [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v6.8b}, [x8]             // top
+        ld1             {v7.8b}, [x10]            // weights_hor
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+        dup             v5.16b,  v6.b[7]          // right
+        usubl           v6.8h,   v6.8b,   v4.8b   // top-bottom
+        uxtl            v7.8h,   v7.8b            // weights_hor
+8:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},  [x2], x7 // left
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b},  [x11], #4 // weights_ver
+        shll            v20.8h,  v5.8b,   #8      // right*256
+        shll            v21.8h,  v5.8b,   #8
+        shll            v22.8h,  v5.8b,   #8
+        shll            v23.8h,  v5.8b,   #8
+        usubl           v0.8h,   v0.8b,   v5.8b   // left-right
+        usubl           v1.8h,   v1.8b,   v5.8b
+        usubl           v2.8h,   v2.8b,   v5.8b
+        usubl           v3.8h,   v3.8b,   v5.8b
+        shll            v24.8h,  v4.8b,   #8      // bottom*256
+        shll            v25.8h,  v4.8b,   #8
+        shll            v26.8h,  v4.8b,   #8
+        shll            v27.8h,  v4.8b,   #8
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v17.8h,  v17.8b
+        uxtl            v18.8h,  v18.8b
+        uxtl            v19.8h,  v19.8b
+        mla             v20.8h,  v3.8h,   v7.8h   // right*256  + (left-right)*weights_hor
+        mla             v21.8h,  v2.8h,   v7.8h   // (left flipped)
+        mla             v22.8h,  v1.8h,   v7.8h
+        mla             v23.8h,  v0.8h,   v7.8h
+        mla             v24.8h,  v6.8h,   v16.8h  // bottom*256 + (top-bottom)*weights_ver
+        mla             v25.8h,  v6.8h,   v17.8h
+        mla             v26.8h,  v6.8h,   v18.8h
+        mla             v27.8h,  v6.8h,   v19.8h
+        uhadd           v20.8h,  v20.8h,  v24.8h
+        uhadd           v21.8h,  v21.8h,  v25.8h
+        uhadd           v22.8h,  v22.8h,  v26.8h
+        uhadd           v23.8h,  v23.8h,  v27.8h
+        rshrn           v20.8b,  v20.8h,  #8
+        rshrn           v21.8b,  v21.8h,  #8
+        rshrn           v22.8b,  v22.8h,  #8
+        rshrn           v23.8b,  v23.8h,  #8
+        st1             {v20.8b}, [x0], x1
+        st1             {v21.8b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v22.8b}, [x0], x1
+        st1             {v23.8b}, [x6], x1
+        b.gt            8b
+        ret
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        add             x12, x2,  w3, uxtw
+        sub             x2,  x2,  #2
+        mov             x7,  #-2
+        ld1r            {v5.16b}, [x12]           // right
+        sub             x1,  x1,  w3, uxtw
+        mov             w9,  w3
+
+1:
+        ld2r            {v0.8b, v1.8b},   [x2],  x7 // left
+        ld2r            {v16.8b, v17.8b}, [x11], #2 // weights_ver
+        usubl           v0.8h,   v0.8b,   v5.8b   // left-right
+        usubl           v1.8h,   v1.8b,   v5.8b
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v17.8h,  v17.8b
+2:
+        ld1             {v7.16b}, [x10],  #16     // weights_hor
+        ld1             {v3.16b}, [x8],   #16     // top
+        shll            v20.8h,  v5.8b,   #8      // right*256
+        shll            v21.8h,  v5.8b,   #8
+        shll            v22.8h,  v5.8b,   #8
+        shll            v23.8h,  v5.8b,   #8
+        uxtl            v6.8h,   v7.8b            // weights_hor
+        uxtl2           v7.8h,   v7.16b
+        usubl           v2.8h,   v3.8b,   v4.8b   // top-bottom
+        usubl2          v3.8h,   v3.16b,  v4.16b
+        mla             v20.8h,  v1.8h,   v6.8h   // right*256  + (left-right)*weights_hor
+        mla             v21.8h,  v1.8h,   v7.8h   // (left flipped)
+        mla             v22.8h,  v0.8h,   v6.8h
+        mla             v23.8h,  v0.8h,   v7.8h
+        shll            v24.8h,  v4.8b,   #8      // bottom*256
+        shll            v25.8h,  v4.8b,   #8
+        shll            v26.8h,  v4.8b,   #8
+        shll            v27.8h,  v4.8b,   #8
+        mla             v24.8h,  v2.8h,   v16.8h  // bottom*256 + (top-bottom)*weights_ver
+        mla             v25.8h,  v3.8h,   v16.8h
+        mla             v26.8h,  v2.8h,   v17.8h
+        mla             v27.8h,  v3.8h,   v17.8h
+        uhadd           v20.8h,  v20.8h,  v24.8h
+        uhadd           v21.8h,  v21.8h,  v25.8h
+        uhadd           v22.8h,  v22.8h,  v26.8h
+        uhadd           v23.8h,  v23.8h,  v27.8h
+        rshrn           v20.8b,  v20.8h,  #8
+        rshrn2          v20.16b, v21.8h,  #8
+        rshrn           v22.8b,  v22.8h,  #8
+        rshrn2          v22.16b, v23.8h,  #8
+        subs            w3,  w3,  #16
+        st1             {v20.16b}, [x0],  #16
+        st1             {v22.16b}, [x6],  #16
+        b.gt            2b
+        subs            w4,  w4,  #2
+        b.le            9f
+        sub             x8,  x8,  w9, uxtw
+        sub             x10, x10, w9, uxtw
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_smooth_tbl
+        .word 640b - ipred_smooth_tbl
+        .word 320b - ipred_smooth_tbl
+        .word 160b - ipred_smooth_tbl
+        .word 80b  - ipred_smooth_tbl
+        .word 40b  - ipred_smooth_tbl
+endjumptable
+
+// void ipred_smooth_v_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height, const int a,
+//                               const int max_width, const int max_height);
+function ipred_smooth_v_8bpc_neon, export=1
+        movrel          x7,  X(sm_weights)
+        add             x7,  x7,  w4, uxtw
+        clz             w9,  w3
+        movrel          x5,  ipred_smooth_v_tbl
+        sub             x8,  x2,  w4, uxtw
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        ld1r            {v4.16b},  [x8] // bottom
+        add             x2,  x2,  #1
+        add             x5,  x5,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v6.2s}, [x2]             // top
+        usubl           v6.8h,   v6.8b,   v4.8b   // top-bottom
+4:
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b},  [x7], #4 // weights_ver
+        shll            v22.8h,  v4.8b,   #8      // bottom*256
+        shll            v23.8h,  v4.8b,   #8
+        zip1            v16.2s,  v16.2s,  v17.2s  // weights_ver
+        zip1            v18.2s,  v18.2s,  v19.2s
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v18.8h,  v18.8b
+        mla             v22.8h,  v6.8h,   v16.8h  // bottom*256 + (top-bottom)*weights_ver
+        mla             v23.8h,  v6.8h,   v18.8h
+        rshrn           v22.8b,  v22.8h,  #8
+        rshrn           v23.8b,  v23.8h,  #8
+        st1             {v22.s}[0], [x0], x1
+        st1             {v22.s}[1], [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v23.s}[0], [x0], x1
+        st1             {v23.s}[1], [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v6.8b}, [x2]             // top
+        usubl           v6.8h,   v6.8b,   v4.8b   // top-bottom
+8:
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b},  [x7], #4 // weights_ver
+        shll            v24.8h,  v4.8b,   #8      // bottom*256
+        shll            v25.8h,  v4.8b,   #8
+        shll            v26.8h,  v4.8b,   #8
+        shll            v27.8h,  v4.8b,   #8
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v17.8h,  v17.8b
+        uxtl            v18.8h,  v18.8b
+        uxtl            v19.8h,  v19.8b
+        mla             v24.8h,  v6.8h,   v16.8h  // bottom*256 + (top-bottom)*weights_ver
+        mla             v25.8h,  v6.8h,   v17.8h
+        mla             v26.8h,  v6.8h,   v18.8h
+        mla             v27.8h,  v6.8h,   v19.8h
+        rshrn           v24.8b,  v24.8h,  #8
+        rshrn           v25.8b,  v25.8h,  #8
+        rshrn           v26.8b,  v26.8h,  #8
+        rshrn           v27.8b,  v27.8h,  #8
+        st1             {v24.8b}, [x0], x1
+        st1             {v25.8b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v26.8b}, [x0], x1
+        st1             {v27.8b}, [x6], x1
+        b.gt            8b
+        ret
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        // Set up pointers for four rows in parallel; x0, x6, x5, x8
+        add             x5,  x0,  x1
+        add             x8,  x6,  x1
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3, uxtw
+        mov             w9,  w3
+
+1:
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b}, [x7], #4 // weights_ver
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v17.8h,  v17.8b
+        uxtl            v18.8h,  v18.8b
+        uxtl            v19.8h,  v19.8b
+2:
+        ld1             {v3.16b}, [x2],   #16     // top
+        shll            v20.8h,  v4.8b,   #8      // bottom*256
+        shll            v21.8h,  v4.8b,   #8
+        shll            v22.8h,  v4.8b,   #8
+        shll            v23.8h,  v4.8b,   #8
+        shll            v24.8h,  v4.8b,   #8
+        shll            v25.8h,  v4.8b,   #8
+        shll            v26.8h,  v4.8b,   #8
+        shll            v27.8h,  v4.8b,   #8
+        usubl           v2.8h,   v3.8b,   v4.8b   // top-bottom
+        usubl2          v3.8h,   v3.16b,  v4.16b
+        mla             v20.8h,  v2.8h,   v16.8h  // bottom*256 + (top-bottom)*weights_ver
+        mla             v21.8h,  v3.8h,   v16.8h
+        mla             v22.8h,  v2.8h,   v17.8h
+        mla             v23.8h,  v3.8h,   v17.8h
+        mla             v24.8h,  v2.8h,   v18.8h
+        mla             v25.8h,  v3.8h,   v18.8h
+        mla             v26.8h,  v2.8h,   v19.8h
+        mla             v27.8h,  v3.8h,   v19.8h
+        rshrn           v20.8b,  v20.8h,  #8
+        rshrn2          v20.16b, v21.8h,  #8
+        rshrn           v22.8b,  v22.8h,  #8
+        rshrn2          v22.16b, v23.8h,  #8
+        rshrn           v24.8b,  v24.8h,  #8
+        rshrn2          v24.16b, v25.8h,  #8
+        rshrn           v26.8b,  v26.8h,  #8
+        rshrn2          v26.16b, v27.8h,  #8
+        subs            w3,  w3,  #16
+        st1             {v20.16b}, [x0],  #16
+        st1             {v22.16b}, [x6],  #16
+        st1             {v24.16b}, [x5],  #16
+        st1             {v26.16b}, [x8],  #16
+        b.gt            2b
+        subs            w4,  w4,  #4
+        b.le            9f
+        sub             x2,  x2,  w9, uxtw
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        add             x5,  x5,  x1
+        add             x8,  x8,  x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_smooth_v_tbl
+        .word 640b - ipred_smooth_v_tbl
+        .word 320b - ipred_smooth_v_tbl
+        .word 160b - ipred_smooth_v_tbl
+        .word 80b  - ipred_smooth_v_tbl
+        .word 40b  - ipred_smooth_v_tbl
+endjumptable
+
+// void ipred_smooth_h_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height, const int a,
+//                               const int max_width, const int max_height);
+function ipred_smooth_h_8bpc_neon, export=1
+        movrel          x8,  X(sm_weights)
+        add             x8,  x8,  w3, uxtw
+        clz             w9,  w3
+        movrel          x5,  ipred_smooth_h_tbl
+        add             x12, x2,  w3, uxtw
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        ld1r            {v5.16b},  [x12] // right
+        add             x5,  x5,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v7.2s}, [x8]             // weights_hor
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+        uxtl            v7.8h,   v7.8b            // weights_hor
+4:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},  [x2], x7 // left
+        shll            v20.8h,  v5.8b,   #8      // right*256
+        shll            v21.8h,  v5.8b,   #8
+        zip1            v1.2s,   v1.2s,   v0.2s   // left, flipped
+        zip1            v0.2s,   v3.2s,   v2.2s
+        usubl           v0.8h,   v0.8b,   v5.8b   // left-right
+        usubl           v1.8h,   v1.8b,   v5.8b
+        mla             v20.8h,  v0.8h,   v7.8h   // right*256  + (left-right)*weights_hor
+        mla             v21.8h,  v1.8h,   v7.8h
+        rshrn           v20.8b,  v20.8h,  #8
+        rshrn           v21.8b,  v21.8h,  #8
+        st1             {v20.s}[0], [x0], x1
+        st1             {v20.s}[1], [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v21.s}[0], [x0], x1
+        st1             {v21.s}[1], [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v7.8b}, [x8]             // weights_hor
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+        uxtl            v7.8h,   v7.8b            // weights_hor
+8:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},  [x2], x7 // left
+        shll            v20.8h,  v5.8b,   #8      // right*256
+        shll            v21.8h,  v5.8b,   #8
+        shll            v22.8h,  v5.8b,   #8
+        shll            v23.8h,  v5.8b,   #8
+        usubl           v3.8h,   v3.8b,   v5.8b   // left-right
+        usubl           v2.8h,   v2.8b,   v5.8b
+        usubl           v1.8h,   v1.8b,   v5.8b
+        usubl           v0.8h,   v0.8b,   v5.8b
+        mla             v20.8h,  v3.8h,   v7.8h   // right*256  + (left-right)*weights_hor
+        mla             v21.8h,  v2.8h,   v7.8h   // (left flipped)
+        mla             v22.8h,  v1.8h,   v7.8h
+        mla             v23.8h,  v0.8h,   v7.8h
+        rshrn           v20.8b,  v20.8h,  #8
+        rshrn           v21.8b,  v21.8h,  #8
+        rshrn           v22.8b,  v22.8h,  #8
+        rshrn           v23.8b,  v23.8h,  #8
+        st1             {v20.8b}, [x0], x1
+        st1             {v21.8b}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v22.8b}, [x0], x1
+        st1             {v23.8b}, [x6], x1
+        b.gt            8b
+        ret
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+        // Set up pointers for four rows in parallel; x0, x6, x5, x10
+        add             x5,  x0,  x1
+        add             x10, x6,  x1
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3, uxtw
+        mov             w9,  w3
+
+1:
+        ld4r            {v0.8b, v1.8b, v2.8b, v3.8b},   [x2],  x7 // left
+        usubl           v0.8h,   v0.8b,   v5.8b   // left-right
+        usubl           v1.8h,   v1.8b,   v5.8b
+        usubl           v2.8h,   v2.8b,   v5.8b
+        usubl           v3.8h,   v3.8b,   v5.8b
+2:
+        ld1             {v7.16b}, [x8],   #16     // weights_hor
+        shll            v20.8h,  v5.8b,   #8      // right*256
+        shll            v21.8h,  v5.8b,   #8
+        shll            v22.8h,  v5.8b,   #8
+        shll            v23.8h,  v5.8b,   #8
+        shll            v24.8h,  v5.8b,   #8
+        shll            v25.8h,  v5.8b,   #8
+        shll            v26.8h,  v5.8b,   #8
+        shll            v27.8h,  v5.8b,   #8
+        uxtl            v6.8h,   v7.8b            // weights_hor
+        uxtl2           v7.8h,   v7.16b
+        mla             v20.8h,  v3.8h,   v6.8h   // right*256  + (left-right)*weights_hor
+        mla             v21.8h,  v3.8h,   v7.8h   // (left flipped)
+        mla             v22.8h,  v2.8h,   v6.8h
+        mla             v23.8h,  v2.8h,   v7.8h
+        mla             v24.8h,  v1.8h,   v6.8h
+        mla             v25.8h,  v1.8h,   v7.8h
+        mla             v26.8h,  v0.8h,   v6.8h
+        mla             v27.8h,  v0.8h,   v7.8h
+        rshrn           v20.8b,  v20.8h,  #8
+        rshrn2          v20.16b, v21.8h,  #8
+        rshrn           v22.8b,  v22.8h,  #8
+        rshrn2          v22.16b, v23.8h,  #8
+        rshrn           v24.8b,  v24.8h,  #8
+        rshrn2          v24.16b, v25.8h,  #8
+        rshrn           v26.8b,  v26.8h,  #8
+        rshrn2          v26.16b, v27.8h,  #8
+        subs            w3,  w3,  #16
+        st1             {v20.16b}, [x0],  #16
+        st1             {v22.16b}, [x6],  #16
+        st1             {v24.16b}, [x5],  #16
+        st1             {v26.16b}, [x10], #16
+        b.gt            2b
+        subs            w4,  w4,  #4
+        b.le            9f
+        sub             x8,  x8,  w9, uxtw
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        add             x5,  x5,  x1
+        add             x10, x10, x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_smooth_h_tbl
+        .word 640b - ipred_smooth_h_tbl
+        .word 320b - ipred_smooth_h_tbl
+        .word 160b - ipred_smooth_h_tbl
+        .word 80b  - ipred_smooth_h_tbl
+        .word 40b  - ipred_smooth_h_tbl
+endjumptable
+
+const padding_mask_buf
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+padding_mask:
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+endconst
+
+// void ipred_z1_upsample_edge_8bpc_neon(pixel *out, const int hsz,
+//                                       const pixel *const in, const int end);
+function ipred_z1_upsample_edge_8bpc_neon, export=1
+        movrel          x4,  padding_mask
+        ld1             {v0.16b},  [x2]           // in[]
+        add             x5,  x2,  w3,  uxtw       // in[end]
+        sub             x4,  x4,  w3,  uxtw
+
+        ld1r            {v1.16b},  [x5]           // padding
+        ld1             {v3.16b},  [x4]           // padding_mask
+
+        movi            v31.8h,  #9
+
+        bit             v0.16b,  v1.16b,  v3.16b  // padded in[]
+
+        ext             v4.16b,  v0.16b,  v1.16b,  #1
+        ext             v5.16b,  v0.16b,  v1.16b,  #2
+        ext             v6.16b,  v0.16b,  v1.16b,  #3
+
+        uaddl           v16.8h,  v4.8b,   v5.8b   // in[i+1] + in[i+2]
+        uaddl2          v17.8h,  v4.16b,  v5.16b
+        uaddl           v18.8h,  v0.8b,   v6.8b   // in[i+0] + in[i+3]
+        uaddl2          v19.8h,  v0.16b,  v6.16b
+        mul             v16.8h,  v16.8h,  v31.8h  // 9*(in[i+1] + in[i+2])
+        mul             v17.8h,  v17.8h,  v31.8h
+        sub             v16.8h,  v16.8h,  v18.8h
+        sub             v17.8h,  v17.8h,  v19.8h
+
+        sqrshrun        v16.8b,  v16.8h,  #4
+        sqrshrun2       v16.16b, v17.8h,  #4
+
+        zip1            v0.16b,  v4.16b,  v16.16b
+        zip2            v1.16b,  v4.16b,  v16.16b
+
+        st1             {v0.16b, v1.16b}, [x0]
+
+        ret
+endfunc
+
+// void ipred_z2_upsample_edge_8bpc_neon(pixel *out, const int sz,
+//                                       const pixel *const in);
+function ipred_z2_upsample_edge_8bpc_neon, export=1
+        // Here, sz is 4 or 8, and we produce 2*sz+1 output elements.
+        movrel          x4,  padding_mask
+        ld1             {v0.16b},  [x2]           // in[]
+        add             x5,  x2,  w1,  uxtw       // in[sz]
+        sub             x4,  x4,  w1,  uxtw
+
+        ld1r            {v2.16b},  [x2]           // in[0] for padding
+        ld1r            {v1.16b},  [x5]           // padding
+        ld1             {v3.16b},  [x4]           // padding_mask
+
+        movi            v31.8h,  #9
+
+        bit             v0.16b,  v1.16b,  v3.16b  // padded in[]
+
+        ext             v4.16b,  v2.16b,  v0.16b,  #15
+        ext             v5.16b,  v0.16b,  v1.16b,  #1
+        ext             v6.16b,  v0.16b,  v1.16b,  #2
+
+        uaddl           v16.8h,  v0.8b,   v5.8b   // in[i+0] + in[i+1]
+        uaddl           v18.8h,  v4.8b,   v6.8b   // in[i-1] + in[i+2]
+        mul             v16.8h,  v16.8h,  v31.8h  // 9*(in[i+1] + in[i+2])
+        sub             v16.8h,  v16.8h,  v18.8h
+
+        sqrshrun        v16.8b,  v16.8h,  #4
+
+        add             x5,  x0,  #16
+
+        zip1            v2.16b,  v0.16b,  v16.16b
+
+        st1             {v1.b}[0], [x5]
+        // In case sz=8, output one single pixel in out[16].
+        st1             {v2.16b}, [x0]
+
+        ret
+endfunc
+
+const edge_filter
+        .byte 0, 4, 8, 0
+        .byte 0, 5, 6, 0
+// Leaving out the coeffs for strength=3
+//      .byte 2, 4, 4, 0
+endconst
+
+// void ipred_z1_filter_edge_8bpc_neon(pixel *out, const int sz,
+//                                     const pixel *const in, const int end,
+//                                     const int strength);
+function ipred_z1_filter_edge_8bpc_neon, export=1
+        cmp             w4, #3
+        b.eq            L(fivetap)                // if (strength == 3) goto fivetap
+
+        movrel          x5,  edge_filter, -3
+        add             x5,  x5,  w4,  uxtw #2    // edge_filter + (strength - 1)*4 + 1
+
+        ld1             {v31.h}[0], [x5]          // kernel[1-2]
+
+        ld1             {v0.16b}, [x2], #16
+
+        dup             v30.16b, v31.b[0]
+        dup             v31.16b, v31.b[1]
+1:
+        // in[end], is the last valid pixel. We produce 16 pixels out by
+        // using 18 pixels in - the last pixel used is [17] of the ones
+        // read/buffered.
+        cmp             w3,  #17
+        ld1             {v1.16b}, [x2], #16
+        b.lt            2f
+        ext             v2.16b,  v0.16b,  v1.16b,  #1
+        ext             v3.16b,  v0.16b,  v1.16b,  #2
+        umull           v4.8h,   v0.8b,   v30.8b
+        umlal           v4.8h,   v2.8b,   v31.8b
+        umlal           v4.8h,   v3.8b,   v30.8b
+        umull2          v5.8h,   v0.16b,  v30.16b
+        umlal2          v5.8h,   v2.16b,  v31.16b
+        umlal2          v5.8h,   v3.16b,  v30.16b
+        subs            w1,  w1,  #16
+        mov             v0.16b,  v1.16b
+        rshrn           v4.8b,   v4.8h,   #4
+        rshrn2          v4.16b,  v5.8h,   #4
+        sub             w3,  w3,  #16
+        st1             {v4.16b}, [x0], #16
+        b.gt            1b
+        ret
+2:
+        // Right padding
+
+        // x2[w3-32] is the padding pixel (x2 points 32 bytes ahead)
+        movrel          x5,  padding_mask
+        sub             w6,  w3,  #32
+        sub             x5,  x5,  w3,  uxtw
+        add             x6,  x2,  w6,  sxtw
+
+        ld1             {v2.16b}, [x5]            // padding_mask
+
+        ld1r            {v1.16b}, [x6]
+        bit             v0.16b,  v1.16b,  v2.16b  // Pad v0-v1
+
+        // Filter one block
+        ext             v2.16b,  v0.16b,  v1.16b,  #1
+        ext             v3.16b,  v0.16b,  v1.16b,  #2
+        umull           v4.8h,   v0.8b,   v30.8b
+        umlal           v4.8h,   v2.8b,   v31.8b
+        umlal           v4.8h,   v3.8b,   v30.8b
+        umull2          v5.8h,   v0.16b,  v30.16b
+        umlal2          v5.8h,   v2.16b,  v31.16b
+        umlal2          v5.8h,   v3.16b,  v30.16b
+        subs            w1,  w1,  #16
+        rshrn           v4.8b,   v4.8h,   #4
+        rshrn2          v4.16b,  v5.8h,   #4
+        st1             {v4.16b}, [x0], #16
+        b.le            9f
+5:
+        // After one block, any remaining output would only be filtering
+        // padding - thus just store the padding.
+        subs            w1,  w1,  #16
+        st1             {v1.16b}, [x0], #16
+        b.gt            5b
+9:
+        ret
+
+L(fivetap):
+        sub             x2,  x2,  #1              // topleft -= 1
+        movi            v29.16b, #2
+        ld1             {v0.16b}, [x2], #16
+        movi            v30.16b, #4
+        movi            v31.16b, #4
+        ins             v0.b[0], v0.b[1]
+1:
+        // in[end+1], is the last valid pixel. We produce 16 pixels out by
+        // using 20 pixels in - the last pixel used is [19] of the ones
+        // read/buffered.
+        cmp             w3,  #18
+        ld1             {v1.16b}, [x2], #16
+        b.lt            2f                        // if (end + 1 < 19)
+        ext             v2.16b,  v0.16b,  v1.16b,  #1
+        ext             v3.16b,  v0.16b,  v1.16b,  #2
+        ext             v4.16b,  v0.16b,  v1.16b,  #3
+        ext             v5.16b,  v0.16b,  v1.16b,  #4
+        umull           v6.8h,   v0.8b,   v29.8b
+        umlal           v6.8h,   v2.8b,   v30.8b
+        umlal           v6.8h,   v3.8b,   v31.8b
+        umlal           v6.8h,   v4.8b,   v30.8b
+        umlal           v6.8h,   v5.8b,   v29.8b
+        umull2          v7.8h,   v0.16b,  v29.16b
+        umlal2          v7.8h,   v2.16b,  v30.16b
+        umlal2          v7.8h,   v3.16b,  v31.16b
+        umlal2          v7.8h,   v4.16b,  v30.16b
+        umlal2          v7.8h,   v5.16b,  v29.16b
+        subs            w1,  w1,  #16
+        mov             v0.16b,  v1.16b
+        rshrn           v6.8b,   v6.8h,   #4
+        rshrn2          v6.16b,  v7.8h,   #4
+        sub             w3,  w3,  #16
+        st1             {v6.16b}, [x0], #16
+        b.gt            1b
+        ret
+2:
+        // Right padding
+
+        // x2[w3+1-32] is the padding pixel (x2 points 32 bytes ahead)
+        movrel          x5,  padding_mask, -1
+        sub             w6,  w3,  #31
+        sub             x5,  x5,  w3,  uxtw
+        add             x6,  x2,  w6,  sxtw
+
+        ld1             {v2.16b, v3.16b}, [x5]    // padding_mask
+
+        ld1r            {v28.16b}, [x6]
+        bit             v0.16b,  v28.16b, v2.16b  // Pad v0-v1
+        bit             v1.16b,  v28.16b, v3.16b
+4:
+        // Filter one block
+        ext             v2.16b,  v0.16b,  v1.16b,  #1
+        ext             v3.16b,  v0.16b,  v1.16b,  #2
+        ext             v4.16b,  v0.16b,  v1.16b,  #3
+        ext             v5.16b,  v0.16b,  v1.16b,  #4
+        umull           v6.8h,   v0.8b,   v29.8b
+        umlal           v6.8h,   v2.8b,   v30.8b
+        umlal           v6.8h,   v3.8b,   v31.8b
+        umlal           v6.8h,   v4.8b,   v30.8b
+        umlal           v6.8h,   v5.8b,   v29.8b
+        umull2          v7.8h,   v0.16b,  v29.16b
+        umlal2          v7.8h,   v2.16b,  v30.16b
+        umlal2          v7.8h,   v3.16b,  v31.16b
+        umlal2          v7.8h,   v4.16b,  v30.16b
+        umlal2          v7.8h,   v5.16b,  v29.16b
+        subs            w1,  w1,  #16
+        mov             v0.16b,  v1.16b
+        mov             v1.16b,  v28.16b
+        rshrn           v6.8b,   v6.8h,   #4
+        rshrn2          v6.16b,  v7.8h,   #4
+        sub             w3,  w3,  #16
+        st1             {v6.16b}, [x0], #16
+        b.le            9f
+        // v0-v1[w3+1] is the last valid pixel; if (w3 + 1 > 0) we need to
+        // filter properly once more - aka (w3 >= 0).
+        cmp             w3,  #0
+        b.ge            4b
+5:
+        // When w3 <= 0, all remaining pixels in v0-v1 are equal to the
+        // last valid pixel - thus just output that without filtering.
+        subs            w1,  w1,  #16
+        st1             {v1.16b}, [x0], #16
+        b.gt            5b
+9:
+        ret
+endfunc
+
+// void ipred_pixel_set_8bpc_neon(pixel *out, const pixel px,
+//                                const int n);
+function ipred_pixel_set_8bpc_neon, export=1
+        dup             v0.16b,  w1
+1:
+        subs            w2,  w2,  #16
+        st1             {v0.16b}, [x0], #16
+        b.gt            1b
+        ret
+endfunc
+
+// void ipred_z1_fill1_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const top,
+//                               const int width, const int height,
+//                               const int dx, const int max_base_x);
+function ipred_z1_fill1_8bpc_neon, export=1
+        clz             w9,  w3
+        movrel          x8,  ipred_z1_fill1_tbl
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x8, w9, uxtw #2]
+        add             x10, x2,  w6,  uxtw       // top[max_base_x]
+        add             x8,  x8,  x9
+        ld1r            {v31.16b}, [x10]          // padding
+        mov             w7,  w5
+        mov             w15, #64
+        br              x8
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            49f
+        ldr             d0,  [x2, w8, uxtw]       // top[base]
+        ldr             d2,  [x2, w10, uxtw]
+        dup             v4.4h,   w9               // frac
+        dup             v5.4h,   w11
+        ext             v1.8b,   v0.8b,   v0.8b,   #1 // top[base+1]
+        ext             v3.8b,   v2.8b,   v2.8b,   #1
+        usubl           v6.8h,   v1.8b,   v0.8b   // top[base+1]-top[base]
+        usubl           v7.8h,   v3.8b,   v2.8b
+        ushll           v16.8h,  v0.8b,   #6      // top[base]*64
+        ushll           v17.8h,  v2.8b,   #6
+        mla             v16.4h,  v6.4h,   v4.4h   // + top[base+1]*frac
+        mla             v17.4h,  v7.4h,   v5.4h
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v17.8b,  v17.8h,  #6
+        st1             {v16.s}[0], [x0], x1
+        add             w7,  w7,  w5              // xpos += dx
+        subs            w4,  w4,  #2
+        st1             {v17.s}[0], [x0], x1
+        b.gt            4b
+        ret
+
+49:
+        st1             {v31.s}[0], [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v31.s}[0], [x0], x1
+        b.gt            49b
+        ret
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            89f
+        ldr             q0,  [x2, w8, uxtw]       // top[base]
+        ldr             q2,  [x2, w10, uxtw]
+        dup             v4.8b,   w9               // frac
+        dup             v5.8b,   w11
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        dup             v6.8b,   w9               // 64 - frac
+        dup             v7.8b,   w11
+        ext             v1.16b,  v0.16b,  v0.16b,  #1 // top[base+1]
+        ext             v3.16b,  v2.16b,  v2.16b,  #1
+        umull           v16.8h,  v0.8b,   v6.8b   // top[base]*(64-frac)
+        umlal           v16.8h,  v1.8b,   v4.8b   // + top[base+1]*frac
+        umull           v17.8h,  v2.8b,   v7.8b
+        umlal           v17.8h,  v3.8b,   v5.8b
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v17.8b,  v17.8h,  #6
+        st1             {v16.8b}, [x0], x1
+        add             w7,  w7,  w5              // xpos += dx
+        subs            w4,  w4,  #2
+        st1             {v17.8b}, [x0], x1
+        b.gt            8b
+        ret
+
+89:
+        st1             {v31.8b}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v31.8b}, [x0], x1
+        b.gt            89b
+        ret
+
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+
+        mov             w12, w3
+
+        add             x13, x0,  x1
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3,  uxtw
+1:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            169f
+        add             x8,  x2,  w8,  uxtw
+        add             x10, x2,  w10, uxtw
+        dup             v4.16b,  w9               // frac
+        dup             v5.16b,  w11
+        ld1             {v0.16b, v1.16b}, [x8],  #32 // top[base]
+        ld1             {v2.16b, v3.16b}, [x10], #32
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        dup             v6.16b,  w9               // 64 - frac
+        dup             v7.16b,  w11
+        add             w7,  w7,  w5              // xpos += dx
+2:
+        ext             v16.16b, v0.16b,  v1.16b,  #1 // top[base+1]
+        ext             v17.16b, v2.16b,  v3.16b,  #1
+        subs            w3,  w3,  #16
+        umull           v18.8h,  v0.8b,   v6.8b   // top[base]*(64-frac)
+        umlal           v18.8h,  v16.8b,  v4.8b   // + top[base+1]*frac
+        umull2          v19.8h,  v0.16b,  v6.16b
+        umlal2          v19.8h,  v16.16b, v4.16b
+        umull           v20.8h,  v2.8b,   v7.8b
+        umlal           v20.8h,  v17.8b,  v5.8b
+        umull2          v21.8h,  v2.16b,  v7.16b
+        umlal2          v21.8h,  v17.16b, v5.16b
+        rshrn           v16.8b,  v18.8h,  #6
+        rshrn2          v16.16b, v19.8h,  #6
+        rshrn           v17.8b,  v20.8h,  #6
+        rshrn2          v17.16b, v21.8h,  #6
+        st1             {v16.16b}, [x0],  #16
+        st1             {v17.16b}, [x13], #16
+        b.le            3f
+        mov             v0.16b,  v1.16b
+        ld1             {v1.16b}, [x8],  #16 // top[base]
+        mov             v2.16b,  v3.16b
+        ld1             {v3.16b}, [x10], #16
+        b               2b
+
+3:
+        subs            w4,  w4,  #2
+        b.le            9f
+        add             x0,  x0,  x1
+        add             x13, x13, x1
+        mov             w3,  w12
+        b               1b
+9:
+        ret
+
+169:
+        st1             {v31.16b}, [x0],  #16
+        subs            w3,  w3,  #16
+        st1             {v31.16b}, [x13], #16
+        b.gt            169b
+        subs            w4,  w4,  #2
+        b.le            9b
+        add             x0,  x0,  x1
+        add             x13, x13, x1
+        mov             w3,  w12
+        b               169b
+endfunc
+
+jumptable ipred_z1_fill1_tbl
+        .word 640b - ipred_z1_fill1_tbl
+        .word 320b - ipred_z1_fill1_tbl
+        .word 160b - ipred_z1_fill1_tbl
+        .word 80b  - ipred_z1_fill1_tbl
+        .word 40b  - ipred_z1_fill1_tbl
+endjumptable
+
+function ipred_z1_fill2_8bpc_neon, export=1
+        cmp             w3,  #8
+        add             x10, x2,  w6,  uxtw       // top[max_base_x]
+        ld1r            {v31.16b}, [x10]          // padding
+        mov             w7,  w5
+        mov             w15, #64
+        b.eq            8f
+
+4:      // w == 4
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            49f
+        ldr             d0,  [x2, w8, uxtw]       // top[base]
+        ldr             d2,  [x2, w10, uxtw]
+        dup             v4.4h,   w9               // frac
+        dup             v5.4h,   w11
+        uzp2            v1.8b,   v0.8b,   v0.8b   // top[base+1]
+        uzp1            v0.8b,   v0.8b,   v0.8b   // top[base]
+        uzp2            v3.8b,   v2.8b,   v2.8b
+        uzp1            v2.8b,   v2.8b,   v2.8b
+        usubl           v6.8h,   v1.8b,   v0.8b   // top[base+1]-top[base]
+        usubl           v7.8h,   v3.8b,   v2.8b
+        ushll           v16.8h,  v0.8b,   #6      // top[base]*64
+        ushll           v17.8h,  v2.8b,   #6
+        mla             v16.4h,  v6.4h,   v4.4h   // + top[base+1]*frac
+        mla             v17.4h,  v7.4h,   v5.4h
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v17.8b,  v17.8h,  #6
+        st1             {v16.s}[0], [x0], x1
+        add             w7,  w7,  w5              // xpos += dx
+        subs            w4,  w4,  #2
+        st1             {v17.s}[0], [x0], x1
+        b.gt            4b
+        ret
+
+49:
+        st1             {v31.s}[0], [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v31.s}[0], [x0], x1
+        b.gt            49b
+        ret
+
+8:      // w == 8
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            89f
+        ldr             q0,  [x2, w8, uxtw]       // top[base]
+        ldr             q2,  [x2, w10, uxtw]
+        dup             v4.8b,   w9               // frac
+        dup             v5.8b,   w11
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        dup             v6.8b,   w9               // 64 - frac
+        dup             v7.8b,   w11
+        uzp2            v1.16b,  v0.16b,  v0.16b  // top[base+1]
+        uzp1            v0.16b,  v0.16b,  v0.16b  // top[base]
+        uzp2            v3.16b,  v2.16b,  v2.16b
+        uzp1            v2.16b,  v2.16b,  v2.16b
+        umull           v16.8h,  v1.8b,   v4.8b   // top[base+1]*frac
+        umlal           v16.8h,  v0.8b,   v6.8b   // + top[base]*(64-frac)
+        umull           v17.8h,  v3.8b,   v5.8b
+        umlal           v17.8h,  v2.8b,   v7.8b
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v17.8b,  v17.8h,  #6
+        st1             {v16.8b}, [x0], x1
+        add             w7,  w7,  w5              // xpos += dx
+        subs            w4,  w4,  #2
+        st1             {v17.8b}, [x0], x1
+        b.gt            8b
+        ret
+
+89:
+        st1             {v31.8b}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v31.8b}, [x0], x1
+        b.gt            89b
+        ret
+endfunc
+
+// void ipred_reverse_8bpc_neon(pixel *dst, const pixel *const src,
+//                              const int n);
+function ipred_reverse_8bpc_neon, export=1
+        sub             x1,  x1,  #16
+        add             x3,  x0,  #8
+        mov             x4,  #16
+1:
+        ld1             {v0.16b}, [x1]
+        subs            w2,  w2,  #16
+        rev64           v0.16b,  v0.16b
+        sub             x1,  x1,  #16
+        st1             {v0.d}[1], [x0], x4
+        st1             {v0.d}[0], [x3], x4
+        b.gt            1b
+        ret
+endfunc
+
+const increments
+        .short          0,  1,  2,  3,  4,  5,  6,  7
+        .short          8,  9,  10, 11, 12, 13, 14, 15
+endconst
+
+// void ipred_z2_fill1_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const top,
+//                               const pixel *const left,
+//                               const int width, const int height,
+//                               const int dx, const int dy);
+function ipred_z2_fill1_8bpc_neon, export=1
+        clz             w10, w4
+        movrel          x9,  ipred_z2_fill1_tbl
+        sub             w10, w10, #25
+        ldrsw           x10, [x9, w10, uxtw #2]
+        mov             w8,  #(1 << 6)            // xpos = 1 << 6
+        add             x9,  x9,  x10
+        sub             w8,  w8,  w6              // xpos -= dx
+
+        movrel          x11, increments
+        ld1             {v31.8h},  [x11]          // increments
+        neg             w7,  w7                   // -dy
+
+        br              x9
+40:
+        AARCH64_VALID_JUMP_TARGET
+
+        dup             v30.4h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.4h,  v31.4h,  v30.4h  // {0,1,2,3}* -dy
+        movi            v25.16b, #0x3e
+        add             v30.4h,  v16.4h,  v30.4h  // -= dy
+
+        xtn             v31.8b,  v31.8h           // {0,1,2,3}
+
+        // Worst case height for w=4 is 16, but we need at least h+1 elements
+        ld1             {v0.16b, v1.16b}, [x3]    // left[]
+
+        movi            v26.16b, #64
+        movi            v19.16b, #2
+
+        xtn             v27.8b,  v30.8h           // (uint8_t)ypos
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v27.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v17.8b  // base_y = (ypos >> 6) + 1
+
+        add             v30.8b,  v29.8b,  v17.8b  // base_y + 1
+        add             v28.8b,  v29.8b,  v19.8b  // base_y + 2
+
+        tbl             v16.8b, {v0.16b}, v29.8b  // left[base_y]
+
+        trn1            v30.2s,  v30.2s,  v28.2s  // base_y + 1, base_y + 2
+
+        sub             v28.8b,  v26.8b,  v27.8b  // 64 - frac_y
+
+        trn1            v31.2s,  v31.2s,  v31.2s  // {0,1,2,3,0,1,2,3}
+
+        trn1            v27.2s,  v27.2s,  v27.2s  // frac_y
+        trn1            v28.2s,  v28.2s,  v28.2s  // 64 - frac_y
+
+        movi            v29.8b,  #2
+4:
+        asr             w9,  w8,  #6              // base_x
+        dup             v6.4h,   w8               // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-4                  // base_x <= -4
+        asr             w11, w8,  #6              // base_x
+        b.le            49f
+
+        dup             v7.4h,   w8               // xpos
+
+        ldr             d2,  [x2, w9, sxtw]       // top[base_x]
+        ldr             d4,  [x2, w11, sxtw]
+
+        trn1            v6.2d,   v6.2d,   v7.2d   // xpos
+
+        // Cut corners here; only doing tbl over v0 here; we only
+        // seem to need the last pixel, from v1, after skipping to the
+        // left-only codepath below.
+        tbl             v17.8b, {v0.16b}, v30.8b  // left[base_y+1], left[base_y+2]
+
+        shrn            v20.8b,  v6.8h,   #6      // first base_x for each row
+        xtn             v6.8b,   v6.8h            // (uint8_t)xpos
+
+        ext             v3.8b,   v2.8b,   v2.8b,   #1 // top[base_x+1]
+        ext             v5.8b,   v4.8b,   v4.8b,   #1
+
+        and             v6.8b,   v6.8b,   v25.8b  // frac_x
+
+        trn1            v16.2s,  v16.2s,  v17.2s  // left[base_y], left[base_y+1]
+
+        trn1            v2.2s,   v2.2s,   v4.2s   // top[base_x]
+        trn1            v3.2s,   v3.2s,   v5.2s   // top[base_x+1]
+
+        sub             v7.8b,   v26.8b,  v6.8b   // 64 - frac_x
+
+        add             v20.8b,  v20.8b,  v31.8b  // actual base_x
+
+        umull           v16.8h,  v16.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v16.8h,  v17.8b,  v27.8b  // + left[base_y+1]*frac_y
+
+        umull           v22.8h,  v2.8b,   v7.8b   // top[base_x]-*(64-frac_x)
+        umlal           v22.8h,  v3.8b,   v6.8b   // + top[base_x+1]*frac_x
+
+        cmge            v20.8b,  v20.8b,  #0
+
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v22.8b,  v22.8h,  #6
+
+        bit             v16.8b,  v22.8b,  v20.8b
+
+        st1             {v16.s}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v16.s}[1], [x0], x1
+        b.le            9f
+
+        ext             v16.8b,  v17.8b,  v17.8b, #4
+        add             v30.8b,  v30.8b,  v29.8b  // base_y += 2
+        b               4b
+
+49:
+        tbl             v17.8b, {v0.16b, v1.16b}, v30.8b // left[base_y+1], left[base_y+2]
+
+        trn1            v16.2s,  v16.2s,  v17.2s  // left[base_y], left[base_y+1]
+
+        umull           v18.8h,  v16.8b,  v28.8b  // left[base_y]*(64-frac_t)
+        umlal           v18.8h,  v17.8b,  v27.8b  // + left[base_y+1]*frac_y
+        rshrn           v18.8b,  v18.8h,  #6
+
+        st1             {v18.s}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v18.s}[1], [x0], x1
+        b.le            9f
+
+        ext             v16.8b,  v17.8b,  v17.8b, #4
+        add             v30.8b,  v30.8b,  v29.8b  // base_y += 2
+        b               49b
+
+9:
+        ret
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+
+        dup             v30.8h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.8h,  v31.8h,  v30.8h  // {0,1,2,3,4,5,6,7}* -dy
+        movi            v25.16b, #0x3e
+        add             v30.8h,  v16.8h,  v30.8h  // -= dy
+
+        xtn             v31.8b,  v31.8h           // {0,1,2,3,4,5,6,7}
+
+        // Worst case height for w=8 is 32, but we need at least h+1 elements
+        ld1             {v0.16b, v1.16b, v2.16b}, [x3]    // left[]
+
+        movi            v26.16b, #64
+        movi            v19.16b, #2
+
+        xtn             v27.8b,  v30.8h           // (uint8_t)ypos
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v27.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v17.8b  // base_y = (ypos >> 6) + 1
+
+        // Cut corners here; for the first row we don't expect to need to
+        // read outside of v0.
+        tbl             v18.8b, {v0.16b}, v29.8b  // left[base_y]
+
+        add             v30.8b,  v29.8b,  v19.8b  // base_y + 2
+        add             v29.8b,  v29.8b,  v17.8b  // base_y + 1
+
+        sub             v28.8b,  v26.8b,  v27.8b  // 64 - frac_y
+
+        trn1            v31.2d,  v31.2d,  v31.2d  // {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7}
+
+        movi            v24.8b,  #2               // 2
+8:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-8                  // base_x <= -8
+        asr             w11, w8,  #6              // base_x
+        b.le            89f
+
+        dup             v17.8h,   w8              // xpos
+
+        ldr             q4,  [x2, w9, sxtw]       // top[base_x]
+        ldr             q6,  [x2, w11, sxtw]
+
+        // Cut corners here; only doing tbl over v0-v1 here; we only
+        // seem to need the last pixel, from v2, after skipping to the
+        // left-only codepath below.
+        tbl             v19.8b, {v0.16b, v1.16b}, v29.8b // left[base_y+1]
+
+        shrn            v21.8b,  v16.8h,  #6      // first base_x
+        shrn2           v21.16b, v17.8h,  #6
+        xtn             v16.8b,  v16.8h           // (uint8_t)xpos
+        xtn2            v16.16b, v17.8h
+
+        tbl             v20.8b, {v0.16b, v1.16b}, v30.8b // left[base_y+2]
+
+        ext             v5.16b,  v4.16b,  v4.16b,  #1 // top[base_x+1]
+        ext             v7.16b,  v6.16b,  v6.16b,  #1
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+
+        trn1            v4.2d,   v4.2d,   v6.2d   // top[base_x]
+        trn1            v5.2d,   v5.2d,   v7.2d   // top[base_x+1]
+
+        sub             v7.16b,  v26.16b, v16.16b // 64 - frac_x
+
+        add             v21.16b, v21.16b, v31.16b // actual base_x
+
+        umull           v6.8h,   v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v6.8h,   v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull           v17.8h,  v19.8b,  v28.8b
+        umlal           v17.8h,  v20.8b,  v27.8b
+
+        umull           v22.8h,  v4.8b,   v7.8b   // top[base_x]-*(64-frac_x)
+        umlal           v22.8h,  v5.8b,   v16.8b  // + top[base_x+1]*frac_x
+        umull2          v23.8h,  v4.16b,  v7.16b
+        umlal2          v23.8h,  v5.16b,  v16.16b
+
+        cmge            v21.16b, v21.16b, #0
+
+        rshrn           v6.8b,   v6.8h,   #6
+        rshrn2          v6.16b,  v17.8h,  #6
+        rshrn           v22.8b,  v22.8h,  #6
+        rshrn2          v22.16b, v23.8h,  #6
+
+        bit             v6.16b,  v22.16b, v21.16b
+
+        st1             {v6.d}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v6.d}[1], [x0], x1
+        b.le            9f
+
+        mov             v18.8b,  v20.8b
+        add             v29.8b,  v29.8b,  v24.8b  // base_y += 2
+        add             v30.8b,  v30.8b,  v24.8b  // base_y += 2
+        b               8b
+
+89:
+        tbl             v19.8b, {v0.16b, v1.16b, v2.16b}, v29.8b // left[base_y+1]
+        tbl             v20.8b, {v0.16b, v1.16b, v2.16b}, v30.8b // left[base_y+2]
+
+        umull           v6.8h,   v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v6.8h,   v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull           v17.8h,  v19.8b,  v28.8b
+        umlal           v17.8h,  v20.8b,  v27.8b
+
+        rshrn           v6.8b,   v6.8h,   #6
+        rshrn2          v6.16b,  v17.8h,  #6
+
+        st1             {v6.d}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v6.d}[1], [x0], x1
+        b.le            9f
+
+        mov             v18.8b,  v20.8b
+        add             v29.8b,  v29.8b,  v24.8b  // base_y += 2
+        add             v30.8b,  v30.8b,  v24.8b  // base_y += 2
+        b               89b
+
+9:
+        ret
+
+160:
+        AARCH64_VALID_JUMP_TARGET
+
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        add             x11, x11, #16             // increments
+
+        dup             v18.8h,  w7               // -dy
+        movi            v17.16b, #1
+        add             x3,  x3,  #1              // Skip past left[0]
+
+        ld1             {v14.8h}, [x11]           // {8,9,10,11,12,13,14,15}
+
+        mul             v16.8h,  v31.8h,  v18.8h  // {0,1,2,3,4,5,6,7}* -dy
+        mul             v19.8h,  v14.8h,  v18.8h  // {8,9,10,11,12,13,14,15}* -dy
+        movi            v25.16b, #0x3e
+        add             v16.8h,  v16.8h,  v18.8h  // -= dy
+        add             v18.8h,  v19.8h,  v18.8h
+
+        xtn             v31.8b,  v31.8h           // {0,1,2,3,4,5,6,7}
+        xtn2            v31.16b, v14.8h           // {8,9,10,11,12,13,14,15}
+
+        // Worst case height is 64.
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x3] // left[]
+        ld1r            {v15.16b}, [x2]           // left[0] == top[0]
+
+        movi            v26.16b, #64
+        movi            v19.16b, #2
+
+        xtn             v27.8b,  v16.8h           // (uint8_t)ypos
+        xtn2            v27.16b, v18.8h
+        shrn            v29.8b,  v16.8h,  #6      // ypos >> 6
+        shrn2           v29.16b, v18.8h,  #6
+        mov             v18.16b, v15.16b          // left[0]
+        and             v27.16b, v27.16b, v25.16b // frac_y
+
+        // Cut corners here; for the first row we don't expect to need to
+        // read outside of v0.
+        tbx             v18.16b, {v0.16b}, v29.16b // left[base_y]
+
+        add             v30.16b, v29.16b, v19.16b // base_y + 2
+        add             v29.16b, v29.16b, v17.16b // base_y + 1
+
+        sub             v28.16b, v26.16b, v27.16b // 64 - frac_y
+
+        movi            v24.16b, #2               // 2
+16:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-16                 // base_x <= -16
+        asr             w11, w8,  #6              // base_x
+        b.le            169f
+
+        dup             v17.8h,   w8              // xpos
+
+        add             x9,  x2,  w9,  sxtw
+        add             x11, x2,  w11, sxtw
+
+        ld1             {v4.16b, v5.16b}, [x9]    // top[base_x]
+        mov             v19.16b, v15.16b          // left[0]
+        ld1             {v6.16b, v7.16b}, [x11]
+
+        tbx             v19.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+1]
+
+        mov             v20.16b, v15.16b          // left[0]
+
+        shrn            v21.8b,  v16.8h,  #6      // first base_x
+        shrn            v22.8b,  v17.8h,  #6
+        xtn             v16.8b,  v16.8h           // (uint8_t)xpos
+        xtn             v17.8b,  v17.8h
+
+        tbx             v20.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v30.16b // left[base_y+2]
+
+        trn1            v21.2d,  v21.2d,  v21.2d  // first base_x
+        trn1            v22.2d,  v22.2d,  v22.2d
+        trn1            v16.2d,  v16.2d,  v16.2d  // (uint8_t)xpos
+        trn1            v17.2d,  v17.2d,  v17.2d
+
+        ext             v5.16b,  v4.16b,  v5.16b,  #1 // top[base_x+1]
+        ext             v7.16b,  v6.16b,  v7.16b,  #1
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+        and             v17.16b, v17.16b, v25.16b
+
+        umull           v10.8h,  v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v10.8h,  v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+
+        sub             v8.16b,  v26.16b, v16.16b // 64 - frac_x
+        sub             v9.16b,  v26.16b, v17.16b
+
+        umull2          v11.8h,  v18.16b, v28.16b
+        umlal2          v11.8h,  v19.16b, v27.16b
+
+        add             v21.16b, v21.16b, v31.16b // actual base_x
+        add             v22.16b, v22.16b, v31.16b
+
+        umull           v12.8h,  v19.8b,  v28.8b
+        umlal           v12.8h,  v20.8b,  v27.8b
+        umull2          v13.8h,  v19.16b, v28.16b
+        umlal2          v13.8h,  v20.16b, v27.16b
+
+        rshrn           v10.8b,  v10.8h,  #6
+        rshrn2          v10.16b, v11.8h,  #6
+        rshrn           v11.8b,  v12.8h,  #6
+        rshrn2          v11.16b, v13.8h,  #6
+
+        umull           v12.8h,  v4.8b,   v8.8b   // top[base_x]-*(64-frac_x)
+        umlal           v12.8h,  v5.8b,   v16.8b  // + top[base_x+1]*frac_x
+        umull2          v13.8h,  v4.16b,  v8.16b
+        umlal2          v13.8h,  v5.16b,  v16.16b
+        umull           v14.8h,  v6.8b,   v9.8b
+        umlal           v14.8h,  v7.8b,   v17.8b
+        umull2          v18.8h,  v6.16b,  v9.16b
+        umlal2          v18.8h,  v7.16b,  v17.16b
+
+        cmge            v21.16b, v21.16b, #0
+        cmge            v22.16b, v22.16b, #0
+
+        rshrn           v12.8b,  v12.8h,  #6
+        rshrn2          v12.16b, v13.8h,  #6
+        rshrn           v13.8b,  v14.8h,  #6
+        rshrn2          v13.16b, v18.8h,  #6
+
+        bit             v10.16b, v12.16b, v21.16b
+        bit             v11.16b, v13.16b, v22.16b
+
+        st1             {v10.16b}, [x0], x1
+        subs            w5,  w5,  #2
+        sub             w8,  w8,  w6              // xpos -= dx
+        st1             {v11.16b}, [x0], x1
+        b.le            9f
+
+        mov             v18.16b, v20.16b
+        add             v29.16b, v29.16b, v24.16b // base_y += 2
+        add             v30.16b, v30.16b, v24.16b // base_y += 2
+        b               16b
+
+169:
+        mov             v19.16b, v15.16b
+        mov             v20.16b, v15.16b
+        tbx             v19.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+1]
+        tbx             v20.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v30.16b // left[base_y+2]
+
+        umull           v4.8h,   v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v4.8h,   v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull2          v5.8h,   v18.16b, v28.16b
+        umlal2          v5.8h,   v19.16b, v27.16b
+        umull           v6.8h,   v19.8b,  v28.8b
+        umlal           v6.8h,   v20.8b,  v27.8b
+        umull2          v7.8h,   v19.16b, v28.16b
+        umlal2          v7.8h,   v20.16b, v27.16b
+
+        rshrn           v4.8b,   v4.8h,   #6
+        rshrn2          v4.16b,  v5.8h,   #6
+        rshrn           v5.8b,   v6.8h,   #6
+        rshrn2          v5.16b,  v7.8h,   #6
+
+        st1             {v4.16b}, [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v5.16b}, [x0], x1
+        b.le            9f
+
+        mov             v18.16b, v20.16b
+        add             v29.16b, v29.16b, v24.16b // base_y += 2
+        add             v30.16b, v30.16b, v24.16b // base_y += 2
+        b               169b
+
+9:
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        add             x11, x11, #16             // increments
+
+        dup             v25.8h,  w7               // -dy
+        add             x3,  x3,  #1              // Skip past left[0]
+
+        ld1             {v14.8h}, [x11]           // {8,9,10,11,12,13,14,15}
+
+        add             x13, x0,  x1              // alternating row
+        lsl             x1,  x1,  #1              // stride *= 2
+        sub             x1,  x1,  w4,  uxtw       // stride -= width
+
+        movi            v11.8h,  #8
+        mul             v26.8h,  v31.8h,  v25.8h  // {0,1,2,3,4,5,6,7}* -dy
+        add             v26.8h,  v26.8h,  v25.8h  // -= dy
+        mul             v25.8h,  v25.8h,  v11.8h  // -8*dy
+
+        xtn             v31.8b,  v31.8h           // {0,1,2,3,4,5,6,7}
+        xtn2            v31.16b, v14.8h           // {8,9,10,11,12,13,14,15}
+
+        // Worst case height is 64.
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x3] // left[]
+        ld1r            {v15.16b}, [x2]           // left[0] == top[0]
+
+        mov             w12, w4                   // orig w
+        neg             w14, w4                   // -w
+
+1:
+        mov             v23.16b, v26.16b          // reset ypos
+
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  w14                  // base_x <= -w
+        asr             w11, w8,  #6              // base_x
+        b.le            329f
+
+        dup             v17.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+
+        add             x9,  x2,  w9,  sxtw
+        add             x11, x2,  w11, sxtw
+
+        sqshrn          v21.8b,  v16.8h,  #6      // first base_x
+        sqshrn          v22.8b,  v17.8h,  #6
+        xtn             v16.8b,  v16.8h           // (uint8_t)xpos
+        xtn             v17.8b,  v17.8h
+
+        ld1             {v4.16b}, [x9], #16       // top[base_x]
+        ld1             {v6.16b}, [x11], #16
+
+        trn1            v21.2d,  v21.2d,  v21.2d  // first base_x
+        trn1            v22.2d,  v22.2d,  v22.2d
+        trn1            v16.2d,  v16.2d,  v16.2d  // (uint8_t)xpos
+        trn1            v17.2d,  v17.2d,  v17.2d
+
+        movi            v10.16b, #0x3e
+        movi            v11.16b, #64
+
+        and             v16.16b, v16.16b, v10.16b // frac_x
+        and             v17.16b, v17.16b, v10.16b
+
+        sub             v8.16b,  v11.16b, v16.16b // 64 - frac_x
+        sub             v9.16b,  v11.16b, v17.16b
+
+        add             v21.16b, v21.16b, v31.16b // actual base_x
+        add             v22.16b, v22.16b, v31.16b
+
+2:
+        add             v13.8h,  v23.8h,  v25.8h  // ypos -= 8*dy
+        movi            v12.16b, #64
+        movi            v20.16b, #2
+        movi            v10.16b, #0x3e
+
+        smov            w10,     v22.b[0]
+
+        xtn             v27.8b,  v23.8h           // (uint8_t)ypos
+        xtn2            v27.16b, v13.8h
+        shrn            v29.8b,  v23.8h,  #6      // ypos >> 6
+        shrn2           v29.16b, v13.8h,  #6
+        cmp             w10, #0                   // base_x (bottom left) >= 0
+        and             v27.16b, v27.16b, v10.16b // frac_y
+
+        mov             v18.16b, v15.16b          // left[0]
+
+        b.ge            4f
+
+        add             v23.8h,  v13.8h,  v25.8h  // ypos -= 8*dy
+        movi            v13.16b, #1
+
+        tbx             v18.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y]
+        add             v29.16b, v29.16b, v13.16b // base_y + 1
+        mov             v19.16b, v15.16b          // left[0]
+
+        sub             v28.16b, v12.16b, v27.16b // 64 - frac_y
+
+        ld1             {v5.16b}, [x9], #16       // top[base_x]
+        ld1             {v7.16b}, [x11], #16
+
+        tbx             v19.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+1]
+        add             v29.16b, v29.16b, v13.16b // base_y + 2
+
+        mov             v20.16b, v15.16b          // left[0]
+        tbx             v20.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+2]
+
+        umull           v10.8h,  v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v10.8h,  v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull2          v11.8h,  v18.16b, v28.16b
+        umlal2          v11.8h,  v19.16b, v27.16b
+        umull           v12.8h,  v19.8b,  v28.8b
+        umlal           v12.8h,  v20.8b,  v27.8b
+        umull2          v13.8h,  v19.16b, v28.16b
+        umlal2          v13.8h,  v20.16b, v27.16b
+
+        ext             v18.16b, v4.16b,  v5.16b,  #1 // top[base_x+1]
+        ext             v19.16b, v6.16b,  v7.16b,  #1
+
+        rshrn           v10.8b,  v10.8h,  #6
+        rshrn2          v10.16b, v11.8h,  #6
+        rshrn           v11.8b,  v12.8h,  #6
+        rshrn2          v11.16b, v13.8h,  #6
+
+        umull           v12.8h,  v4.8b,   v8.8b   // top[base_x]-*(64-frac_x)
+        umlal           v12.8h,  v18.8b,  v16.8b  // + top[base_x+1]*frac_x
+        umull2          v13.8h,  v4.16b,  v8.16b
+        umlal2          v13.8h,  v18.16b, v16.16b
+        umull           v14.8h,  v6.8b,   v9.8b
+        umlal           v14.8h,  v19.8b,  v17.8b
+        umull2          v20.8h,  v6.16b,  v9.16b
+        umlal2          v20.8h,  v19.16b, v17.16b
+
+        cmge            v18.16b, v21.16b, #0
+        cmge            v19.16b, v22.16b, #0
+
+        rshrn           v12.8b,  v12.8h,  #6
+        rshrn2          v12.16b, v13.8h,  #6
+        rshrn           v13.8b,  v14.8h,  #6
+        rshrn2          v13.16b, v20.8h,  #6
+
+        bit             v10.16b, v12.16b, v18.16b
+        bit             v11.16b, v13.16b, v19.16b
+
+        st1             {v10.16b}, [x0], #16
+        subs            w4,  w4,  #16
+        st1             {v11.16b}, [x13], #16
+        b.le            3f
+
+        movi            v10.16b, #16
+        mov             v4.16b,  v5.16b
+        mov             v6.16b,  v7.16b
+        add             v21.16b, v21.16b, v10.16b // base_x += 16
+        add             v22.16b, v22.16b, v10.16b
+        b               2b
+
+3:
+        subs            w5,  w5,  #2
+        b.le            9f
+        movi            v10.8h, #128
+        add             x0,  x0,  x1
+        add             x13, x13, x1
+        mov             w4,  w12                  // reset w
+        add             v26.8h,  v26.8h,  v10.8h  // ypos += 2*(1<<6)
+        b               1b
+
+4:      // The rest of the row only predicted from top[]
+        ld1             {v5.16b}, [x9], #16       // top[base_x]
+        ld1             {v7.16b}, [x11], #16
+
+        ext             v18.16b, v4.16b,  v5.16b,  #1 // top[base_x+1]
+        ext             v19.16b, v6.16b,  v7.16b,  #1
+
+        umull           v12.8h,  v4.8b,   v8.8b   // top[base_x]-*(64-frac_x)
+        umlal           v12.8h,  v18.8b,  v16.8b  // + top[base_x+1]*frac_x
+        umull2          v13.8h,  v4.16b,  v8.16b
+        umlal2          v13.8h,  v18.16b, v16.16b
+        umull           v14.8h,  v6.8b,   v9.8b
+        umlal           v14.8h,  v19.8b,  v17.8b
+        umull2          v20.8h,  v6.16b,  v9.16b
+        umlal2          v20.8h,  v19.16b, v17.16b
+
+        rshrn           v12.8b,  v12.8h,  #6
+        rshrn2          v12.16b, v13.8h,  #6
+        rshrn           v13.8b,  v14.8h,  #6
+        rshrn2          v13.16b, v20.8h,  #6
+
+        st1             {v12.16b}, [x0], #16
+        subs            w4,  w4,  #16
+        st1             {v13.16b}, [x13], #16
+        b.le            3b
+
+        mov             v4.16b,  v5.16b
+        mov             v6.16b,  v7.16b
+        b               4b
+
+329:    // The rest of the block only predicted from left[]
+        add             x1,  x1,  w4,  uxtw       // restore stride
+        mov             w12, w5                   // orig remaining h
+1:
+        add             v13.8h,  v23.8h,  v25.8h  // ypos -= 8*dy
+        movi            v12.16b, #64
+        movi            v10.16b, #0x3e
+
+        xtn             v27.8b,  v23.8h           // (uint8_t)ypos
+        xtn2            v27.16b, v13.8h
+        shrn            v29.8b,  v23.8h,  #6      // ypos >> 6
+        shrn2           v29.16b, v13.8h,  #6
+        and             v27.16b, v27.16b, v10.16b // frac_y
+
+        mov             v18.16b, v15.16b          // left[0]
+        add             v23.8h,  v13.8h,  v25.8h  // ypos -= 8*dy
+        movi            v21.16b, #1
+
+        tbx             v18.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y]
+        add             v29.16b, v29.16b, v21.16b // base_y + 1
+
+        sub             v28.16b, v12.16b, v27.16b // 64 - frac_y
+2:
+        mov             v19.16b, v15.16b          // left[0]
+        tbx             v19.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+1]
+        add             v29.16b, v29.16b, v21.16b // base_y + 2
+        mov             v20.16b, v15.16b          // left[0]
+        tbx             v20.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+2]
+        add             v29.16b, v29.16b, v21.16b // next base_y
+
+        umull           v10.8h,  v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v10.8h,  v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull2          v11.8h,  v18.16b, v28.16b
+        umlal2          v11.8h,  v19.16b, v27.16b
+        umull           v12.8h,  v19.8b,  v28.8b
+        umlal           v12.8h,  v20.8b,  v27.8b
+        umull2          v13.8h,  v19.16b, v28.16b
+        umlal2          v13.8h,  v20.16b, v27.16b
+
+        rshrn           v10.8b,  v10.8h,  #6
+        rshrn2          v10.16b, v11.8h,  #6
+        rshrn           v11.8b,  v12.8h,  #6
+        rshrn2          v11.16b, v13.8h,  #6
+
+        st1             {v10.16b}, [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v11.16b}, [x13], x1
+        b.le            3f
+        mov             v18.16b, v20.16b
+        b               2b
+
+3:
+        subs            w4,  w4,  #16
+        b.le            9f
+
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #16
+        add             x13, x13, #16
+        mov             w5,  w12                  // reset h
+        b               1b
+
+9:
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+endfunc
+
+jumptable ipred_z2_fill1_tbl
+        .word 640b - ipred_z2_fill1_tbl
+        .word 320b - ipred_z2_fill1_tbl
+        .word 160b - ipred_z2_fill1_tbl
+        .word 80b  - ipred_z2_fill1_tbl
+        .word 40b  - ipred_z2_fill1_tbl
+endjumptable
+
+function ipred_z2_fill2_8bpc_neon, export=1
+        cmp             w4,  #8
+        mov             w8,  #(2 << 6)            // xpos = 2 << 6
+        sub             w8,  w8,  w6              // xpos -= dx
+
+        movrel          x11, increments
+        ld1             {v31.8h},  [x11]          // increments
+        neg             w7,  w7                   // -dy
+        b.eq            80f
+
+40:
+        dup             v30.4h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.4h,  v31.4h,  v30.4h  // {0,1,2,3}* -dy
+        movi            v25.16b, #0x3e
+        add             v30.4h,  v16.4h,  v30.4h  // -= dy
+
+        xtn             v31.8b,  v31.8h           // {0,1,2,3}
+
+        // For upsample_top, w <= 8 and h <= 8; we may need up to h+1 elements
+        // from left.
+        ld1             {v0.16b}, [x3]            // left[]
+
+        movi            v26.16b, #64
+        movi            v19.16b, #2
+
+        xtn             v27.8b,  v30.8h           // (uint8_t)ypos
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v27.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v17.8b  // base_y = (ypos >> 6) + 1
+
+        add             v30.8b,  v29.8b,  v17.8b  // base_y + 1
+        add             v28.8b,  v29.8b,  v19.8b  // base_y + 2
+
+        tbl             v16.8b, {v0.16b}, v29.8b  // left[base_y]
+
+        trn1            v30.2s,  v30.2s,  v28.2s  // base_y + 1, base_y + 2
+
+        sub             v28.8b,  v26.8b,  v27.8b  // 64 - frac_y
+
+        trn1            v31.2s,  v31.2s,  v31.2s  // {0,1,2,3,0,1,2,3}
+
+        trn1            v27.2s,  v27.2s,  v27.2s  // frac_y
+        trn1            v28.2s,  v28.2s,  v28.2s  // 64 - frac_y
+
+        movi            v29.8b,  #2
+        add             v31.8b,  v31.8b,  v31.8b  // {0,2,4,6,0,2,4,6}
+4:
+        asr             w9,  w8,  #6              // base_x
+        dup             v6.4h,   w8               // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-8                  // base_x <= -8
+        asr             w11, w8,  #6              // base_x
+        b.le            49f
+
+        dup             v7.4h,   w8               // xpos
+
+        ldr             d2,  [x2, w9, sxtw]       // top[base_x]
+        ldr             d4,  [x2, w11, sxtw]
+
+        trn1            v6.2d,   v6.2d,   v7.2d   // xpos
+
+        tbl             v17.8b, {v0.16b}, v30.8b  // left[base_y+1], left[base_y+2]
+
+        shrn            v20.8b,  v6.8h,   #6      // first base_x for each row
+        xtn             v6.8b,   v6.8h            // (uint8_t)xpos
+
+        uzp2            v3.8b,   v2.8b,   v4.8b   // top[base_x+1]
+        uzp1            v2.8b,   v2.8b,   v4.8b   // top[base_x]
+
+        and             v6.8b,   v6.8b,   v25.8b  // frac_x
+
+        trn1            v16.2s,  v16.2s,  v17.2s  // left[base_y], left[base_y+1]
+
+        sub             v7.8b,   v26.8b,  v6.8b   // 64 - frac_x
+
+        add             v20.8b,  v20.8b,  v31.8b  // actual base_x
+
+        umull           v16.8h,  v16.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v16.8h,  v17.8b,  v27.8b  // + left[base_y+1]*frac_y
+
+        umull           v22.8h,  v2.8b,   v7.8b   // top[base_x]-*(64-frac_x)
+        umlal           v22.8h,  v3.8b,   v6.8b   // + top[base_x+1]*frac_x
+
+        cmge            v20.8b,  v20.8b,  #0
+
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v22.8b,  v22.8h,  #6
+
+        bit             v16.8b,  v22.8b,  v20.8b
+
+        st1             {v16.s}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v16.s}[1], [x0], x1
+        b.le            9f
+
+        ext             v16.8b,  v17.8b,  v17.8b, #4
+        add             v30.8b,  v30.8b,  v29.8b  // base_y += 2
+        b               4b
+
+49:
+        tbl             v17.8b, {v0.16b}, v30.8b  // left[base_y+1], left[base_y+2]
+
+        trn1            v16.2s,  v16.2s,  v17.2s  // left[base_y], left[base_y+1]
+
+        umull           v18.8h,  v16.8b,  v28.8b  // left[base_y]*(64-frac_t)
+        umlal           v18.8h,  v17.8b,  v27.8b  // + left[base_y+1]*frac_y
+        rshrn           v18.8b,  v18.8h,  #6
+
+        st1             {v18.s}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v18.s}[1], [x0], x1
+        b.le            9f
+
+        ext             v16.8b,  v17.8b,  v17.8b, #4
+        add             v30.8b,  v30.8b,  v29.8b  // base_y += 2
+        b               49b
+
+9:
+        ret
+
+80:
+        dup             v30.8h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.8h,  v31.8h,  v30.8h  // {0,1,2,3,4,5,6,7}* -dy
+        movi            v25.16b, #0x3e
+        add             v30.8h,  v16.8h,  v30.8h  // -= dy
+
+        xtn             v31.8b,  v31.8h           // {0,1,2,3,4,5,6,7}
+
+        // For upsample_top, w <= 8 and h <= 8; we may need up to h+1 elements
+        // from left.
+        ld1             {v0.16b}, [x3]    // left[]
+
+        movi            v26.16b, #64
+        movi            v19.16b, #2
+
+        xtn             v27.8b,  v30.8h           // (uint8_t)ypos
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v27.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v17.8b  // base_y = (ypos >> 6) + 1
+
+        tbl             v18.8b, {v0.16b}, v29.8b  // left[base_y]
+
+        add             v30.8b,  v29.8b,  v19.8b  // base_y + 2
+        add             v29.8b,  v29.8b,  v17.8b  // base_y + 1
+
+        sub             v28.8b,  v26.8b,  v27.8b  // 64 - frac_y
+
+        trn1            v31.2d,  v31.2d,  v31.2d  // {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7}
+
+        movi            v24.8b,  #2               // 2
+        add             v31.16b, v31.16b, v31.16b // {0,2,4,6,8,10,12,14,0,2,4,6,8,10,12,14}
+8:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-16                 // base_x <= -16
+        asr             w11, w8,  #6              // base_x
+        b.le            89f
+
+        dup             v17.8h,   w8              // xpos
+
+        ldr             q4,  [x2, w9, sxtw]       // top[base_x]
+        ldr             q6,  [x2, w11, sxtw]
+
+        tbl             v19.8b, {v0.16b}, v29.8b  // left[base_y+1]
+
+        shrn            v21.8b,  v16.8h,  #6      // first base_x
+        shrn2           v21.16b, v17.8h,  #6
+        xtn             v16.8b,  v16.8h           // (uint8_t)xpos
+        xtn2            v16.16b, v17.8h
+
+        tbl             v20.8b, {v0.16b}, v30.8b  // left[base_y+2]
+
+        uzp2            v5.16b,  v4.16b,  v6.16b  // top[base_x+1]
+        uzp1            v4.16b,  v4.16b,  v6.16b  // top[base_x]
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+
+        sub             v7.16b,  v26.16b, v16.16b // 64 - frac_x
+
+        add             v21.16b, v21.16b, v31.16b // actual base_x
+
+        umull           v6.8h,   v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v6.8h,   v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull           v17.8h,  v19.8b,  v28.8b
+        umlal           v17.8h,  v20.8b,  v27.8b
+
+        umull           v22.8h,  v4.8b,   v7.8b   // top[base_x]-*(64-frac_x)
+        umlal           v22.8h,  v5.8b,   v16.8b  // + top[base_x+1]*frac_x
+        umull2          v23.8h,  v4.16b,  v7.16b
+        umlal2          v23.8h,  v5.16b,  v16.16b
+
+        cmge            v21.16b, v21.16b, #0
+
+        rshrn           v6.8b,   v6.8h,   #6
+        rshrn2          v6.16b,  v17.8h,  #6
+        rshrn           v22.8b,  v22.8h,  #6
+        rshrn2          v22.16b, v23.8h,  #6
+
+        bit             v6.16b,  v22.16b, v21.16b
+
+        st1             {v6.d}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v6.d}[1], [x0], x1
+        b.le            9f
+
+        mov             v18.8b,  v20.8b
+        add             v29.8b,  v29.8b,  v24.8b  // base_y += 2
+        add             v30.8b,  v30.8b,  v24.8b  // base_y += 2
+        b               8b
+
+89:
+        tbl             v19.8b, {v0.16b}, v29.8b  // left[base_y+1]
+        tbl             v20.8b, {v0.16b}, v30.8b  // left[base_y+2]
+
+        umull           v6.8h,   v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v6.8h,   v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull           v17.8h,  v19.8b,  v28.8b
+        umlal           v17.8h,  v20.8b,  v27.8b
+
+        rshrn           v6.8b,   v6.8h,   #6
+        rshrn2          v6.16b,  v17.8h,  #6
+
+        st1             {v6.d}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v6.d}[1], [x0], x1
+        b.le            9f
+
+        mov             v18.8b,  v20.8b
+        add             v29.8b,  v29.8b,  v24.8b  // base_y += 2
+        add             v30.8b,  v30.8b,  v24.8b  // base_y += 2
+        b               89b
+
+9:
+        ret
+endfunc
+
+function ipred_z2_fill3_8bpc_neon, export=1
+        cmp             w4,  #8
+        mov             w8,  #(1 << 6)            // xpos = 1 << 6
+        sub             w8,  w8,  w6              // xpos -= dx
+
+        movrel          x11, increments
+        ld1             {v31.8h},  [x11]          // increments
+        neg             w7,  w7                   // -dy
+        b.eq            80f
+
+40:
+        dup             v30.4h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.4h,  v31.4h,  v30.4h  // {0,1,2,3}* -dy
+        movi            v25.16b, #0x3e
+        add             v30.4h,  v16.4h,  v30.4h  // -= dy
+
+        xtn             v31.8b,  v31.8h           // {0,1,2,3}
+
+        // For upsample_left, w <= 8 and h <= 8; we may need up to 2*h+1 elements.
+        ld1             {v0.16b, v1.16b}, [x3]    // left[]
+
+        movi            v26.16b, #64
+        movi            v19.16b, #2
+
+        xtn             v27.8b,  v30.8h           // (uint8_t)ypos
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v27.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v19.8b  // base_y = (ypos >> 6) + 2
+
+        add             v30.8b,  v29.8b,  v17.8b  // base_y + 1
+        add             v28.8b,  v29.8b,  v19.8b  // base_y + 2
+
+        trn1            v31.2s,  v31.2s,  v31.2s  // {0,1,2,3,0,1,2,3}
+
+        add             v24.8b,  v30.8b,  v19.8b  // base_y + 3
+
+        trn1            v29.2s,  v29.2s,  v28.2s  // base_y + 0, base_y + 2
+        trn1            v30.2s,  v30.2s,  v24.2s  // base_y + 1, base_y + 3
+
+        sub             v28.8b,  v26.8b,  v27.8b  // 64 - frac_y
+
+        trn1            v27.2s,  v27.2s,  v27.2s  // frac_y
+        trn1            v28.2s,  v28.2s,  v28.2s  // 64 - frac_y
+
+        movi            v24.8b,  #4
+4:
+        asr             w9,  w8,  #6              // base_x
+        dup             v6.4h,   w8               // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-4                  // base_x <= -4
+        asr             w11, w8,  #6              // base_x
+        b.le            49f
+
+        dup             v7.4h,   w8               // xpos
+
+        ldr             d2,  [x2, w9, sxtw]       // top[base_x]
+        ldr             d4,  [x2, w11, sxtw]
+
+        trn1            v6.2d,   v6.2d,   v7.2d   // xpos
+
+        tbl             v16.8b, {v0.16b, v1.16b}, v29.8b // left[base_y+0], left[base_y+2]
+        tbl             v17.8b, {v0.16b, v1.16b}, v30.8b // left[base_y+1], left[base_y+3]
+
+        shrn            v20.8b,  v6.8h,   #6      // first base_x for each row
+        xtn             v6.8b,   v6.8h            // (uint8_t)xpos
+
+        ext             v3.8b,   v2.8b,   v2.8b,   #1 // top[base_x+1]
+        ext             v5.8b,   v4.8b,   v4.8b,   #1
+
+        and             v6.8b,   v6.8b,   v25.8b  // frac_x
+
+        trn1            v2.2s,   v2.2s,   v4.2s   // top[base_x]
+        trn1            v3.2s,   v3.2s,   v5.2s   // top[base_x+1]
+
+        sub             v7.8b,   v26.8b,  v6.8b   // 64 - frac_x
+
+        add             v20.8b,  v20.8b,  v31.8b  // actual base_x
+
+        umull           v16.8h,  v16.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v16.8h,  v17.8b,  v27.8b  // + left[base_y+1]*frac_y
+
+        umull           v22.8h,  v2.8b,   v7.8b   // top[base_x]-*(64-frac_x)
+        umlal           v22.8h,  v3.8b,   v6.8b   // + top[base_x+1]*frac_x
+
+        cmge            v20.8b,  v20.8b,  #0
+
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v22.8b,  v22.8h,  #6
+
+        bit             v16.8b,  v22.8b,  v20.8b
+
+        st1             {v16.s}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v16.s}[1], [x0], x1
+        b.le            9f
+
+        add             v29.8b,  v29.8b,  v24.8b  // base_y += 4
+        add             v30.8b,  v30.8b,  v24.8b  // base_y += 4
+        b               4b
+
+49:
+        tbl             v16.8b, {v0.16b, v1.16b}, v29.8b // left[base_y+0], left[base_y+2]
+        tbl             v17.8b, {v0.16b, v1.16b}, v30.8b // left[base_y+1], left[base_y+3]
+
+        umull           v18.8h,  v16.8b,  v28.8b  // left[base_y]*(64-frac_t)
+        umlal           v18.8h,  v17.8b,  v27.8b  // + left[base_y+1]*frac_y
+        rshrn           v18.8b,  v18.8h,  #6
+
+        st1             {v18.s}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v18.s}[1], [x0], x1
+        b.le            9f
+
+        add             v29.8b,  v29.8b,  v24.8b  // base_y += 4
+        add             v30.8b,  v30.8b,  v24.8b  // base_y += 4
+        b               49b
+
+9:
+        ret
+
+80:
+        dup             v30.8h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.8h,  v31.8h,  v30.8h  // {0,1,2,3,4,5,6,7}* -dy
+        movi            v25.16b, #0x3e
+        add             v30.8h,  v16.8h,  v30.8h  // -= dy
+
+        xtn             v31.8b,  v31.8h           // {0,1,2,3,4,5,6,7}
+
+        // For upsample_left, w <= 8 and h <= 8; we may need up to 2*h+1 elements.
+        ld1             {v0.16b, v1.16b, v2.16b}, [x3]    // left[]
+
+        movi            v26.16b, #64
+        movi            v19.16b, #2
+
+        xtn             v27.8b,  v30.8h           // (uint8_t)ypos
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v27.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v19.8b  // base_y = (ypos >> 6) + 2
+
+        add             v28.8b,  v29.8b,  v17.8b  // base_y + 1
+        add             v30.8b,  v29.8b,  v19.8b  // base_y + 2
+
+        trn1            v31.2d,  v31.2d,  v31.2d  // {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7}
+        add             v24.8b,  v28.8b,  v19.8b  // base_y + 3
+
+        trn1            v29.2d,  v29.2d,  v30.2d  // base_y + 0, base_y + 2
+        trn1            v30.2d,  v28.2d,  v24.2d  // base_y + 1, base_y + 3
+
+        sub             v28.8b,  v26.8b,  v27.8b  // 64 - frac_y
+
+        movi            v24.16b, #4
+
+        trn1            v27.2d,  v27.2d,  v27.2d  // frac_y
+        trn1            v28.2d,  v28.2d,  v28.2d  // 64 - frac_y
+8:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-8                  // base_x <= -8
+        asr             w11, w8,  #6              // base_x
+        b.le            89f
+
+        dup             v17.8h,   w8              // xpos
+
+        ldr             q4,  [x2, w9, sxtw]       // top[base_x]
+        ldr             q6,  [x2, w11, sxtw]
+
+        tbl             v18.16b, {v0.16b, v1.16b, v2.16b}, v29.16b // left[base_y+0], left[base_y+2]
+        tbl             v19.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+1], left[base_y+3]
+
+        shrn            v21.8b,  v16.8h,  #6      // first base_x
+        shrn2           v21.16b, v17.8h,  #6
+        xtn             v16.8b,  v16.8h           // (uint8_t)xpos
+        xtn2            v16.16b, v17.8h
+
+        ext             v5.16b,  v4.16b,  v4.16b,  #1 // top[base_x+1]
+        ext             v7.16b,  v6.16b,  v6.16b,  #1
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+
+        trn1            v4.2d,   v4.2d,   v6.2d   // top[base_x]
+        trn1            v5.2d,   v5.2d,   v7.2d   // top[base_x+1]
+
+        sub             v7.16b,  v26.16b, v16.16b // 64 - frac_x
+
+        add             v21.16b, v21.16b, v31.16b // actual base_x
+
+        umull           v6.8h,   v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v6.8h,   v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull2          v17.8h,  v18.16b, v28.16b
+        umlal2          v17.8h,  v19.16b, v27.16b
+
+        umull           v22.8h,  v4.8b,   v7.8b   // top[base_x]-*(64-frac_x)
+        umlal           v22.8h,  v5.8b,   v16.8b  // + top[base_x+1]*frac_x
+        umull2          v23.8h,  v4.16b,  v7.16b
+        umlal2          v23.8h,  v5.16b,  v16.16b
+
+        cmge            v21.16b, v21.16b, #0
+
+        rshrn           v6.8b,   v6.8h,   #6
+        rshrn2          v6.16b,  v17.8h,  #6
+        rshrn           v22.8b,  v22.8h,  #6
+        rshrn2          v22.16b, v23.8h,  #6
+
+        bit             v6.16b,  v22.16b, v21.16b
+
+        st1             {v6.d}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v6.d}[1], [x0], x1
+        b.le            9f
+
+        add             v29.16b, v29.16b, v24.16b // base_y += 4
+        add             v30.16b, v30.16b, v24.16b // base_y += 4
+        b               8b
+
+89:
+        tbl             v18.16b, {v0.16b, v1.16b, v2.16b}, v29.16b // left[base_y+0], left[base_y+2]
+        tbl             v19.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+1], left[base_y+3]
+
+        umull           v6.8h,   v18.8b,  v28.8b  // left[base_y]*(64-frac_y)
+        umlal           v6.8h,   v19.8b,  v27.8b  // + left[base_y+1]*frac_y
+        umull2          v17.8h,  v18.16b, v28.16b
+        umlal2          v17.8h,  v19.16b, v27.16b
+
+        rshrn           v6.8b,   v6.8h,   #6
+        rshrn2          v6.16b,  v17.8h,  #6
+
+        st1             {v6.d}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v6.d}[1], [x0], x1
+        b.le            9f
+
+        add             v29.16b, v29.16b, v24.16b // base_y += 4
+        add             v30.16b, v30.16b, v24.16b // base_y += 4
+        b               89b
+
+9:
+        ret
+endfunc
+
+
+// void ipred_z3_fill1_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const left,
+//                               const int width, const int height,
+//                               const int dy, const int max_base_y);
+function ipred_z3_fill1_8bpc_neon, export=1
+        cmp             w6,  #64
+        clz             w9,  w3
+        movrel          x8,  ipred_z3_fill1_tbl
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x8, w9, uxtw #2]
+        add             x10, x2,  w6,  uxtw       // left[max_base_y]
+        add             x8,  x8,  x9
+        movrel          x11, increments
+        ld1r            {v31.16b}, [x10]          // padding
+        ld1             {v30.8h},  [x11]          // increments
+        mov             w7,  w5
+        b.gt            L(ipred_z3_fill1_large_h16)
+        br              x8
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+        dup             v29.4h,  w5               // dy
+
+        mul             v30.4h,  v30.4h,  v29.4h  // {0,1,2,3,4,5,6,7}*dy
+        movi            v23.16b, #0x3e
+
+        // Worst case max_base_y is width+height-1, for w=4, h=16, <= 32
+        ld1             {v0.16b, v1.16b}, [x2] // left[]
+        add             v30.4h,  v29.4h,  v30.4h  // ypos
+
+        movi            v22.16b, #64
+        movi            v20.16b, #1
+        movi            v21.16b, #2
+
+        xtn             v24.8b,  v30.8h           // (uint8_t)ypos
+        uqshrn          v26.8b,  v30.8h,  #6      // base
+        and             v24.8b,  v24.8b,  v23.8b  // frac
+
+        mov             v4.8b,   v31.8b
+        uqadd           v27.8b,  v26.8b,  v20.8b  // base + 1
+        uqadd           v28.8b,  v26.8b,  v21.8b  // base + 2
+        sub             v25.8b,  v22.8b,  v24.8b  // 64 - frac
+
+        tbx             v4.8b, {v0.16b, v1.16b}, v26.8b // left[base]
+
+        trn1            v27.2s,  v27.2s,  v28.2s  // base + 1, base + 2
+        trn1            v24.2s,  v24.2s,  v24.2s  // frac
+        trn1            v25.2s,  v25.2s,  v25.2s  // 64 - frac
+1:
+        mov             v5.8b,   v31.8b
+        tbx             v5.8b, {v0.16b, v1.16b}, v27.8b // left[base+1], left[base+2]
+
+        trn1            v4.2s,   v4.2s,   v5.2s   // left[base], left[base+1]
+
+        umull           v16.8h,  v4.8b,   v25.8b  // left[base]*(64-frac)
+        umlal           v16.8h,  v5.8b,   v24.8b  // + left[base+1]*frac
+        rshrn           v16.8b,  v16.8h,  #6
+        st1             {v16.s}[0], [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v16.s}[1], [x0], x1
+        b.le            9f
+
+        ext             v4.8b,   v5.8b,   v5.8b,  #4
+        uqadd           v27.8b,  v27.8b,  v21.8b  // base += 2
+        b               1b
+
+9:
+        ret
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+        dup             v29.8h,  w5               // dy
+
+        mul             v30.8h,  v30.8h,  v29.8h  // {0,1,2,3,4,5,6,7}*dy
+        movi            v23.16b, #0x3e
+
+        // Worst case max_base_y is width+height-1, for w=8, h=32, <= 48
+        ld1             {v0.16b, v1.16b, v2.16b}, [x2] // left[]
+        add             v30.8h,  v29.8h,  v30.8h  // ypos
+
+        movi            v22.16b, #64
+        movi            v20.16b, #1
+        movi            v21.16b, #2
+
+        xtn             v24.8b,  v30.8h           // (uint8_t)ypos
+        uqshrn          v26.8b,  v30.8h,  #6      // base
+        and             v24.8b,  v24.8b,  v23.8b  // frac
+
+        mov             v4.8b,   v31.8b
+        uqadd           v27.8b,  v26.8b,  v20.8b  // base + 1
+        uqadd           v28.8b,  v26.8b,  v21.8b  // base + 2
+        sub             v25.8b,  v22.8b,  v24.8b  // 64 - frac
+
+        tbx             v4.8b, {v0.16b, v1.16b, v2.16b}, v26.8b // left[base]
+1:
+        mov             v5.8b,   v31.8b
+        mov             v6.8b,   v31.8b
+        tbx             v5.8b, {v0.16b, v1.16b, v2.16b}, v27.8b // left[base+1]
+        tbx             v6.8b, {v0.16b, v1.16b, v2.16b}, v28.8b // left[base+2]
+
+        umull           v16.8h,  v4.8b,   v25.8b  // left[base]*(64-frac)
+        umlal           v16.8h,  v5.8b,   v24.8b  // + left[base+1]*frac
+        umull           v17.8h,  v5.8b,   v25.8b
+        umlal           v17.8h,  v6.8b,   v24.8b
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v17.8b,  v17.8h,  #6
+        st1             {v16.8b}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v17.8b}, [x0], x1
+        b.le            9f
+
+        mov             v4.8b,   v6.8b
+        uqadd           v27.8b,  v27.8b,  v21.8b  // base += 2
+        uqadd           v28.8b,  v28.8b,  v21.8b  // base += 2
+        b               1b
+
+9:
+        ret
+
+160:
+        AARCH64_VALID_JUMP_TARGET
+        dup             v28.8h,  w5               // dy
+
+        shl             v29.8h,  v28.8h,  #3      // 8*dy
+        mul             v30.8h,  v30.8h,  v28.8h  // {0,1,2,3,4,5,6,7}*dy
+        movi            v23.16b, #0x3e
+
+        // This is only executed if we've checked that max_base_y <= 64.
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x2] // left[]
+        add             v28.8h,  v28.8h,  v30.8h  // ypos
+
+        movi            v22.16b, #64
+        movi            v20.16b, #1
+        movi            v21.16b, #2
+
+        add             v29.8h,  v28.8h,  v29.8h  // ypos + 8*dy
+
+        xtn             v24.8b,  v28.8h           // (uint8_t)ypos
+        xtn2            v24.16b, v29.8h
+        uqshrn          v26.8b,  v28.8h,  #6      // base
+        uqshrn2         v26.16b, v29.8h,  #6
+        and             v24.16b, v24.16b, v23.16b // frac
+
+        mov             v4.16b,  v31.16b
+        uqadd           v27.16b, v26.16b, v20.16b // base + 1
+        uqadd           v28.16b, v26.16b, v21.16b // base + 2
+        sub             v25.16b, v22.16b, v24.16b // 64 - frac
+
+        tbx             v4.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v26.16b // left[base]
+1:
+        mov             v5.16b,  v31.16b
+        mov             v6.16b,  v31.16b
+        tbx             v5.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v27.16b // left[base+1]
+        tbx             v6.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v28.16b // left[base+2]
+
+        umull           v16.8h,  v4.8b,   v25.8b  // left[base]*(64-frac)
+        umlal           v16.8h,  v5.8b,   v24.8b  // + left[base+1]*frac
+        umull2          v17.8h,  v4.16b,  v25.16b
+        umlal2          v17.8h,  v5.16b,  v24.16b
+        umull           v18.8h,  v5.8b,   v25.8b
+        umlal           v18.8h,  v6.8b,   v24.8b
+        umull2          v19.8h,  v5.16b,  v25.16b
+        umlal2          v19.8h,  v6.16b,  v24.16b
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn2          v16.16b, v17.8h,  #6
+        rshrn           v17.8b,  v18.8h,  #6
+        rshrn2          v17.16b, v19.8h,  #6
+        st1             {v16.16b}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v17.16b}, [x0], x1
+        b.le            9f
+
+        mov             v4.16b,  v6.16b
+        uqadd           v27.16b, v27.16b, v21.16b // base += 2
+        uqadd           v28.16b, v28.16b, v21.16b // base += 2
+        b               1b
+
+9:
+        ret
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        dup             v28.8h,  w5               // dy
+        mov             w12, w3
+
+        add             x13, x0,  x1
+
+        shl             v29.8h,  v28.8h,  #3      // 8*dy
+        mul             v30.8h,  v30.8h,  v28.8h  // {0,1,2,3,4,5,6,7}*dy
+        movi            v23.16b, #0x3e
+
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3,  uxtw
+        add             v30.8h,  v28.8h,  v30.8h  // ypos
+
+        // This is only executed if we've checked that max_base_y <= 64.
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b}, [x2] // left[]
+
+        movi            v22.16b, #64
+        movi            v20.16b, #1
+        movi            v21.16b, #2
+
+1:
+        mov             v26.16b,  v30.16b         // reset ypos
+
+2:
+        add             v27.8h,  v26.8h,  v29.8h  // ypos + 8*dy
+        uqshrn          v16.8b,  v26.8h,  #6      // base
+        uqshrn2         v16.16b, v27.8h,  #6
+        xtn             v24.8b,  v26.8h           // (uint8_t)ypos
+        xtn2            v24.16b, v27.8h
+        umov            w14,     v16.b[0]
+        and             v24.16b, v24.16b, v23.16b // frac
+
+        uqadd           v17.16b, v16.16b, v20.16b // base + 1
+        cmp             w14, w6                   // base >= max_base_y
+        uqadd           v18.16b, v16.16b, v21.16b // base + 2
+        sub             v25.16b, v22.16b, v24.16b // 64 - frac
+
+        b.ge            4f
+
+        mov             v4.16b,  v31.16b
+        mov             v5.16b,  v31.16b
+        mov             v6.16b,  v31.16b
+        tbx             v4.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v16.16b // left[base]
+        tbx             v5.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v17.16b // left[base+1]
+        tbx             v6.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v18.16b // left[base+2]
+
+        subs            w3,  w3,  #16
+        umull           v16.8h,  v4.8b,   v25.8b  // left[base]*(64-frac)
+        umlal           v16.8h,  v5.8b,   v24.8b  // + left[base+1]*frac
+        umull2          v17.8h,  v4.16b,  v25.16b
+        umlal2          v17.8h,  v5.16b,  v24.16b
+        umull           v18.8h,  v5.8b,   v25.8b
+        umlal           v18.8h,  v6.8b,   v24.8b
+        umull2          v19.8h,  v5.16b,  v25.16b
+        umlal2          v19.8h,  v6.16b,  v24.16b
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn2          v16.16b, v17.8h,  #6
+        rshrn           v17.8b,  v18.8h,  #6
+        rshrn2          v17.16b, v19.8h,  #6
+        st1             {v16.16b}, [x0],  #16
+        st1             {v17.16b}, [x13], #16
+        b.le            3f
+        add             v26.8h,  v27.8h,  v29.8h  // ypos += 16*dy
+        b               2b
+
+3:
+        subs            w4,  w4,  #2
+        b.le            9f
+        movi            v16.8h,  #128
+        add             x0,  x0,  x1
+        add             x13, x13, x1
+        add             v30.8h,  v30.8h,  v16.8h  // ypos = dy + y*(1<<6)*2
+        mov             w3,  w12
+        b               1b
+
+4:
+        subs            w3,  w3,  #16
+        st1             {v31.16b}, [x0],  #16
+        st1             {v31.16b}, [x13], #16
+        b.gt            4b
+        b               3b
+
+9:
+        ret
+
+L(ipred_z3_fill1_large_h16):
+        // Fallback case for max_base_y > 64; similar to the z1
+        // implementation. This does the filtering vertically, filling out
+        // a 2x pixel column at a time.
+        mov             w15, #64
+        add             x13, x0,  x1
+        lsl             x1,  x1,  #1
+
+        mov             w12, w4
+1:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // ypos += dy
+        cmp             w8,  w6                   // base >= max_base_y
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            ipred_z3_fill_padding_neon
+        add             x8,  x2,  w8,  uxtw
+        add             x10, x2,  w10, uxtw
+        dup             v4.16b,  w9               // frac
+        dup             v5.16b,  w11
+        ld1             {v0.16b, v1.16b}, [x8],  #32 // left[base]
+        ld1             {v2.16b, v3.16b}, [x10], #32
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        dup             v6.16b,  w9               // 64 - frac
+        dup             v7.16b,  w11
+        add             w7,  w7,  w5              // ypos += dy
+2:
+        ext             v16.16b, v0.16b,  v1.16b,  #1 // left[base+1]
+        ext             v17.16b, v2.16b,  v3.16b,  #1
+        subs            w4,  w4,  #16
+        umull           v18.8h,  v16.8b,  v4.8b   // left[base+1]*frac
+        umlal           v18.8h,  v0.8b,   v6.8b   // + left[base]*(64-frac)
+        umull2          v19.8h,  v16.16b, v4.16b
+        umlal2          v19.8h,  v0.16b,  v6.16b
+        umull           v20.8h,  v17.8b,  v5.8b
+        umlal           v20.8h,  v2.8b,   v7.8b
+        umull2          v21.8h,  v17.16b, v5.16b
+        umlal2          v21.8h,  v2.16b,  v7.16b
+        rshrn           v16.8b,  v18.8h,  #6
+        rshrn2          v16.16b, v19.8h,  #6
+        rshrn           v17.8b,  v20.8h,  #6
+        rshrn2          v17.16b, v21.8h,  #6
+        zip1            v18.16b, v16.16b, v17.16b
+        zip2            v19.16b, v16.16b, v17.16b
+        st1             {v18.h}[0], [x0],  x1
+        st1             {v18.h}[1], [x13], x1
+        st1             {v18.h}[2], [x0],  x1
+        st1             {v18.h}[3], [x13], x1
+        st1             {v18.h}[4], [x0],  x1
+        st1             {v18.h}[5], [x13], x1
+        st1             {v18.h}[6], [x0],  x1
+        st1             {v18.h}[7], [x13], x1
+        st1             {v19.h}[0], [x0],  x1
+        st1             {v19.h}[1], [x13], x1
+        st1             {v19.h}[2], [x0],  x1
+        st1             {v19.h}[3], [x13], x1
+        st1             {v19.h}[4], [x0],  x1
+        st1             {v19.h}[5], [x13], x1
+        st1             {v19.h}[6], [x0],  x1
+        st1             {v19.h}[7], [x13], x1
+        b.le            3f
+        mov             v0.16b,  v1.16b
+        ld1             {v1.16b}, [x8],  #16      // left[base]
+        mov             v2.16b,  v3.16b
+        ld1             {v3.16b}, [x10], #16
+        b               2b
+
+3:
+        subs            w3,  w3,  #2
+        b.le            9f
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #2
+        add             x13, x13, #2
+        mov             w4,  w12
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_z3_fill1_tbl
+        .word 640b - ipred_z3_fill1_tbl
+        .word 320b - ipred_z3_fill1_tbl
+        .word 160b - ipred_z3_fill1_tbl
+        .word 80b  - ipred_z3_fill1_tbl
+        .word 40b  - ipred_z3_fill1_tbl
+endjumptable
+
+function ipred_z3_fill_padding_neon, export=0
+        cmp             w3,  #16
+        movrel          x8,  ipred_z3_fill_padding_tbl
+        b.gt            ipred_z3_fill_padding_wide
+        // w3 = remaining width, w4 = constant height
+        mov             w12, w4
+
+1:
+        // Fill a WxH rectangle with padding. W can be any number;
+        // this fills the exact width by filling in the largest
+        // power of two in the remaining width, and repeating.
+        clz             w9,  w3
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x8, w9, uxtw #2]
+        add             x9,  x8,  x9
+        br              x9
+
+20:
+        AARCH64_VALID_JUMP_TARGET
+2:
+        st1             {v31.h}[0], [x0],  x1
+        subs            w4,  w4,  #4
+        st1             {v31.h}[0], [x13], x1
+        st1             {v31.h}[0], [x0],  x1
+        st1             {v31.h}[0], [x13], x1
+        b.gt            2b
+        subs            w3,  w3,  #2
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        b.le            9f
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #2
+        add             x13, x13, #2
+        mov             w4,  w12
+        b               1b
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        st1             {v31.s}[0], [x0],  x1
+        subs            w4,  w4,  #4
+        st1             {v31.s}[0], [x13], x1
+        st1             {v31.s}[0], [x0],  x1
+        st1             {v31.s}[0], [x13], x1
+        b.gt            4b
+        subs            w3,  w3,  #4
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        b.le            9f
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #4
+        add             x13, x13, #4
+        mov             w4,  w12
+        b               1b
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        st1             {v31.8b}, [x0],  x1
+        subs            w4,  w4,  #4
+        st1             {v31.8b}, [x13], x1
+        st1             {v31.8b}, [x0],  x1
+        st1             {v31.8b}, [x13], x1
+        b.gt            8b
+        subs            w3,  w3,  #8
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        b.le            9f
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #8
+        add             x13, x13, #8
+        mov             w4,  w12
+        b               1b
+
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        st1             {v31.16b}, [x0],  x1
+        subs            w4,  w4,  #4
+        st1             {v31.16b}, [x13], x1
+        st1             {v31.16b}, [x0],  x1
+        st1             {v31.16b}, [x13], x1
+        b.gt            16b
+        subs            w3,  w3,  #16
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        b.le            9f
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #16
+        add             x13, x13, #16
+        mov             w4,  w12
+        b               1b
+
+9:
+        ret
+endfunc
+
+jumptable ipred_z3_fill_padding_tbl
+        .word 640b - ipred_z3_fill_padding_tbl
+        .word 320b - ipred_z3_fill_padding_tbl
+        .word 160b - ipred_z3_fill_padding_tbl
+        .word 80b  - ipred_z3_fill_padding_tbl
+        .word 40b  - ipred_z3_fill_padding_tbl
+        .word 20b  - ipred_z3_fill_padding_tbl
+endjumptable
+
+function ipred_z3_fill_padding_wide
+        // Fill a WxH rectangle with padding, with W > 16.
+        lsr             x1,  x1,  #1
+        mov             w12, w3
+        sub             x1,  x1,  w3,  uxtw
+1:
+        ands            w5,  w3,  #15
+        b.eq            2f
+        // If the width isn't aligned to 16, first do one 16 byte write
+        // and align the start pointer.
+        sub             w3,  w3,  w5
+        st1             {v31.16b}, [x0]
+        add             x0,  x0,  w5,  uxtw
+2:
+        // Fill the rest of the line with aligned 16 byte writes.
+        subs            w3,  w3,  #16
+        st1             {v31.16b}, [x0], #16
+        b.gt            2b
+        subs            w4,  w4,  #1
+        add             x0,  x0,  x1
+        b.le            9f
+        mov             w3,  w12
+        b               1b
+9:
+        ret
+endfunc
+
+function ipred_z3_fill2_8bpc_neon, export=1
+        cmp             w3,  #8
+        add             x10, x2,  w6,  uxtw       // left[max_base_y]
+        movrel          x11, increments
+        ld1r            {v31.16b}, [x10]          // padding
+        ld1             {v30.8h},  [x11]          // increments
+        b.eq            80f
+
+40:     // w == 4
+        dup             v29.4h,  w5               // dy
+
+        mul             v30.4h,  v30.4h,  v29.4h  // {0,1,2,3,4,5,6,7}*dy
+        movi            v23.16b, #0x3e
+
+        // Worst case max_base_y is 2*(width+height)-2, but width+height <= 16,
+        // so max_base_y <= 32.
+        ld1             {v0.16b, v1.16b}, [x2] // left[]
+        add             v30.4h,  v29.4h,  v30.4h  // ypos
+
+        movi            v22.16b, #64
+        movi            v20.16b, #1
+        movi            v21.16b, #2
+
+        xtn             v24.8b,  v30.8h           // (uint8_t)ypos
+        uqshrn          v26.8b,  v30.8h,  #6      // base
+        and             v24.8b,  v24.8b,  v23.8b  // frac
+
+        uqadd           v27.8b,  v26.8b,  v20.8b  // base + 1
+        uqadd           v28.8b,  v26.8b,  v21.8b  // base + 2
+        sub             v25.8b,  v22.8b,  v24.8b  // 64 - frac
+        uqadd           v29.8b,  v27.8b,  v21.8b  // base + 3
+
+        trn1            v24.2s,  v24.2s,  v24.2s  // frac
+        trn1            v26.2s,  v26.2s,  v28.2s  // base + 0, base + 2
+        trn1            v27.2s,  v27.2s,  v29.2s  // base + 1, base + 3
+        trn1            v25.2s,  v25.2s,  v25.2s  // 64 - frac
+
+        movi            v21.16b, #4
+1:
+        mov             v4.8b,   v31.8b
+        mov             v5.8b,   v31.8b
+        tbx             v4.8b, {v0.16b, v1.16b}, v26.8b // left[base], left[base+2]
+        tbx             v5.8b, {v0.16b, v1.16b}, v27.8b // left[base+1], left[base+3]
+
+        umull           v16.8h,  v4.8b,   v25.8b  // left[base]*(64-frac)
+        umlal           v16.8h,  v5.8b,   v24.8b  // + left[base+1]*frac
+        rshrn           v16.8b,  v16.8h,  #6
+        st1             {v16.s}[0], [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v16.s}[1], [x0], x1
+        b.le            9f
+
+        uqadd           v26.8b,  v26.8b,  v21.8b  // base += 4
+        uqadd           v27.8b,  v27.8b,  v21.8b  // base += 4
+        b               1b
+
+9:
+        ret
+
+80:     // w == 8
+        dup             v29.8h,  w5               // dy
+
+        mul             v30.8h,  v30.8h,  v29.8h  // {0,1,2,3,4,5,6,7}*dy
+        movi            v23.16b, #0x3e
+
+        // Worst case max_base_y is 2*(width+height)-2, but width+height <= 16,
+        // so max_base_y <= 32.
+        ld1             {v0.16b, v1.16b}, [x2] // left[]
+        add             v30.8h,  v29.8h,  v30.8h  // ypos
+
+        movi            v22.16b, #64
+        movi            v20.16b, #1
+        movi            v21.16b, #2
+
+        xtn             v24.8b,  v30.8h           // (uint8_t)ypos
+        uqshrn          v26.8b,  v30.8h,  #6      // base
+        and             v24.8b,  v24.8b,  v23.8b  // frac
+
+        uqadd           v27.8b,  v26.8b,  v20.8b  // base + 1
+        uqadd           v28.8b,  v26.8b,  v21.8b  // base + 2
+        sub             v25.8b,  v22.8b,  v24.8b  // 64 - frac
+        uqadd           v29.8b,  v27.8b,  v21.8b  // base + 3
+
+        trn1            v24.2d,  v24.2d,  v24.2d  // frac
+        trn1            v26.2d,  v26.2d,  v28.2d  // base + 0, base + 2
+        trn1            v27.2d,  v27.2d,  v29.2d  // base + 1, base + 3
+        trn1            v25.2d,  v25.2d,  v25.2d  // 64 - frac
+
+        movi            v21.16b, #4
+1:
+        mov             v4.16b,  v31.16b
+        mov             v5.16b,  v31.16b
+        tbx             v4.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v26.16b // left[base], left[base+2]
+        tbx             v5.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v27.16b // left[base+1], left[base+3]
+
+        umull           v16.8h,  v4.8b,   v25.8b  // left[base]*(64-frac)
+        umlal           v16.8h,  v5.8b,   v24.8b  // + left[base+1]*frac
+        umull2          v17.8h,  v4.16b,  v25.16b
+        umlal2          v17.8h,  v5.16b,  v24.16b
+        rshrn           v16.8b,  v16.8h,  #6
+        rshrn           v17.8b,  v17.8h,  #6
+        st1             {v16.8b}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v17.8b}, [x0], x1
+        b.le            9f
+
+        uqadd           v26.16b, v26.16b, v21.16b // base += 4
+        uqadd           v27.16b, v27.16b, v21.16b // base += 4
+        b               1b
+
+9:
+        ret
+endfunc
+
+
+// void ipred_filter_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int filt_idx,
+//                             const int max_width, const int max_height);
+function ipred_filter_8bpc_neon, export=1
+        and             w5,  w5,  #511
+        movrel          x6,  X(filter_intra_taps)
+        lsl             w5,  w5,  #6
+        add             x6,  x6,  w5, uxtw
+        ld1             {v16.8b, v17.8b, v18.8b, v19.8b}, [x6], #32
+        clz             w9,  w3
+        movrel          x5,  ipred_filter_tbl
+        ld1             {v20.8b, v21.8b, v22.8b}, [x6]
+        sub             w9,  w9,  #26
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        sxtl            v16.8h,  v16.8b
+        sxtl            v17.8h,  v17.8b
+        add             x5,  x5,  x9
+        sxtl            v18.8h,  v18.8b
+        sxtl            v19.8h,  v19.8b
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        sxtl            v20.8h,  v20.8b
+        sxtl            v21.8h,  v21.8b
+        sxtl            v22.8h,  v22.8b
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ldur            s0,  [x2, #1]             // top (0-3)
+        sub             x2,  x2,  #2
+        mov             x7,  #-2
+        uxtl            v0.8h,   v0.8b            // top (0-3)
+4:
+        ld1             {v1.s}[0], [x2], x7       // left (0-1) + topleft (2)
+        mul             v2.8h,   v17.8h,  v0.h[0] // p1(top[0]) * filter(1)
+        mla             v2.8h,   v18.8h,  v0.h[1] // p2(top[1]) * filter(2)
+        mla             v2.8h,   v19.8h,  v0.h[2] // p3(top[2]) * filter(3)
+        uxtl            v1.8h,   v1.8b            // left (0-1) + topleft (2)
+        mla             v2.8h,   v20.8h,  v0.h[3] // p4(top[3]) * filter(4)
+        mla             v2.8h,   v16.8h,  v1.h[2] // p0(topleft) * filter(0)
+        mla             v2.8h,   v21.8h,  v1.h[1] // p5(left[0]) * filter(5)
+        mla             v2.8h,   v22.8h,  v1.h[0] // p6(left[1]) * filter(6)
+        sqrshrun        v2.8b,   v2.8h,   #4
+        subs            w4,  w4,  #2
+        st1             {v2.s}[0], [x0], x1
+        uxtl            v0.8h,   v2.8b
+        st1             {v2.s}[1], [x6], x1
+        ext             v0.16b,  v0.16b,  v0.16b, #8 // move top from [4-7] to [0-3]
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ldur            d0,  [x2, #1]             // top (0-7)
+        sub             x2,  x2,  #2
+        mov             x7,  #-2
+        uxtl            v0.8h,   v0.8b            // top (0-7)
+8:
+        ld1             {v1.s}[0], [x2], x7       // left (0-1) + topleft (2)
+        mul             v2.8h,   v17.8h,  v0.h[0] // p1(top[0]) * filter(1)
+        mla             v2.8h,   v18.8h,  v0.h[1] // p2(top[1]) * filter(2)
+        mla             v2.8h,   v19.8h,  v0.h[2] // p3(top[2]) * filter(3)
+        uxtl            v1.8h,   v1.8b            // left (0-1) + topleft (2)
+        mla             v2.8h,   v20.8h,  v0.h[3] // p4(top[3]) * filter(4)
+        mla             v2.8h,   v16.8h,  v1.h[2] // p0(topleft) * filter(0)
+        mla             v2.8h,   v21.8h,  v1.h[1] // p5(left[0]) * filter(5)
+        mla             v2.8h,   v22.8h,  v1.h[0] // p6(left[1]) * filter(6)
+        mul             v3.8h,   v17.8h,  v0.h[4] // p1(top[0]) * filter(1)
+        mla             v3.8h,   v18.8h,  v0.h[5] // p2(top[1]) * filter(2)
+        mla             v3.8h,   v19.8h,  v0.h[6] // p3(top[2]) * filter(3)
+        sqrshrun        v2.8b,   v2.8h,   #4
+        uxtl            v1.8h,   v2.8b            // first block, in 16 bit
+        mla             v3.8h,   v20.8h,  v0.h[7] // p4(top[3]) * filter(4)
+        mla             v3.8h,   v16.8h,  v0.h[3] // p0(topleft) * filter(0)
+        mla             v3.8h,   v21.8h,  v1.h[3] // p5(left[0]) * filter(5)
+        mla             v3.8h,   v22.8h,  v1.h[7] // p6(left[1]) * filter(6)
+        sqrshrun        v3.8b,   v3.8h,   #4
+        subs            w4,  w4,  #2
+        st2             {v2.s, v3.s}[0], [x0], x1
+        zip2            v0.2s,   v2.2s,   v3.2s
+        st2             {v2.s, v3.s}[1], [x6], x1
+        uxtl            v0.8h,   v0.8b
+        b.gt            8b
+        ret
+160:
+320:
+        AARCH64_VALID_JUMP_TARGET
+        add             x8,  x2,  #1
+        sub             x2,  x2,  #2
+        mov             x7,  #-2
+        sub             x1,  x1,  w3, uxtw
+        mov             w9,  w3
+
+1:
+        ld1             {v0.s}[0], [x2], x7       // left (0-1) + topleft (2)
+        uxtl            v0.8h,   v0.8b            // left (0-1) + topleft (2)
+2:
+        ld1             {v2.16b}, [x8],   #16     // top(0-15)
+        mul             v3.8h,   v16.8h,  v0.h[2] // p0(topleft) * filter(0)
+        mla             v3.8h,   v21.8h,  v0.h[1] // p5(left[0]) * filter(5)
+        uxtl            v1.8h,   v2.8b            // top(0-7)
+        uxtl2           v2.8h,   v2.16b           // top(8-15)
+        mla             v3.8h,   v22.8h,  v0.h[0] // p6(left[1]) * filter(6)
+        mla             v3.8h,   v17.8h,  v1.h[0] // p1(top[0]) * filter(1)
+        mla             v3.8h,   v18.8h,  v1.h[1] // p2(top[1]) * filter(2)
+        mla             v3.8h,   v19.8h,  v1.h[2] // p3(top[2]) * filter(3)
+        mla             v3.8h,   v20.8h,  v1.h[3] // p4(top[3]) * filter(4)
+
+        mul             v4.8h,   v17.8h,  v1.h[4] // p1(top[0]) * filter(1)
+        mla             v4.8h,   v18.8h,  v1.h[5] // p2(top[1]) * filter(2)
+        mla             v4.8h,   v19.8h,  v1.h[6] // p3(top[2]) * filter(3)
+        sqrshrun        v3.8b,   v3.8h,   #4
+        uxtl            v0.8h,   v3.8b            // first block, in 16 bit
+        mla             v4.8h,   v20.8h,  v1.h[7] // p4(top[3]) * filter(4)
+        mla             v4.8h,   v16.8h,  v1.h[3] // p0(topleft) * filter(0)
+        mla             v4.8h,   v21.8h,  v0.h[3] // p5(left[0]) * filter(5)
+        mla             v4.8h,   v22.8h,  v0.h[7] // p6(left[1]) * filter(6)
+
+        mul             v5.8h,   v17.8h,  v2.h[0] // p1(top[0]) * filter(1)
+        mla             v5.8h,   v18.8h,  v2.h[1] // p2(top[1]) * filter(2)
+        mla             v5.8h,   v19.8h,  v2.h[2] // p3(top[2]) * filter(3)
+        sqrshrun        v4.8b,   v4.8h,   #4
+        uxtl            v0.8h,   v4.8b            // second block, in 16 bit
+        mla             v5.8h,   v20.8h,  v2.h[3] // p4(top[3]) * filter(4)
+        mla             v5.8h,   v16.8h,  v1.h[7] // p0(topleft) * filter(0)
+        mla             v5.8h,   v21.8h,  v0.h[3] // p5(left[0]) * filter(5)
+        mla             v5.8h,   v22.8h,  v0.h[7] // p6(left[1]) * filter(6)
+
+        mul             v6.8h,   v17.8h,  v2.h[4] // p1(top[0]) * filter(1)
+        mla             v6.8h,   v18.8h,  v2.h[5] // p2(top[1]) * filter(2)
+        mla             v6.8h,   v19.8h,  v2.h[6] // p3(top[2]) * filter(3)
+        sqrshrun        v5.8b,   v5.8h,   #4
+        uxtl            v0.8h,   v5.8b            // third block, in 16 bit
+        mla             v6.8h,   v20.8h,  v2.h[7] // p4(top[3]) * filter(4)
+        mla             v6.8h,   v16.8h,  v2.h[3] // p0(topleft) * filter(0)
+        mla             v6.8h,   v21.8h,  v0.h[3] // p5(left[0]) * filter(5)
+        mla             v6.8h,   v22.8h,  v0.h[7] // p6(left[1]) * filter(6)
+
+        subs            w3,  w3,  #16
+        sqrshrun        v6.8b,   v6.8h,   #4
+
+        st4             {v3.s, v4.s, v5.s, v6.s}[0], [x0], #16
+        st4             {v3.s, v4.s, v5.s, v6.s}[1], [x6], #16
+        b.le            8f
+        ins             v0.h[2], v2.h[7]
+        ins             v0.b[0], v6.b[7]
+        ins             v0.b[2], v6.b[3]
+        b               2b
+8:
+        subs            w4,  w4,  #2
+        b.le            9f
+        sub             x8,  x6,  w9, uxtw
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_filter_tbl
+        .word 320b - ipred_filter_tbl
+        .word 160b - ipred_filter_tbl
+        .word 80b  - ipred_filter_tbl
+        .word 40b  - ipred_filter_tbl
+endjumptable
+
+// void pal_pred_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const pal, const uint8_t *idx,
+//                         const int w, const int h);
+function pal_pred_8bpc_neon, export=1
+        ld1             {v0.8b}, [x2]
+        clz             w9,  w4
+        movrel          x6,  pal_pred_tbl
+        sub             w9,  w9,  #25
+        movi            v31.16b, #7
+        ldrsw           x9,  [x6, w9, uxtw #2]
+        add             x6,  x6,  x9
+        add             x2,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x6
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ld1             {v1.8b}, [x3], #8
+        subs            w5,  w5,  #4
+        ushr            v3.8b,   v1.8b,   #4
+        and             v2.8b,   v1.8b,   v31.8b
+        zip1            v1.16b,  v2.16b,  v3.16b
+        tbl             v1.16b, {v0.16b}, v1.16b
+        st1             {v1.s}[0], [x0], x1
+        st1             {v1.s}[1], [x2], x1
+        st1             {v1.s}[2], [x0], x1
+        st1             {v1.s}[3], [x2], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ld1             {v1.16b}, [x3], #16
+        subs            w5,  w5,  #4
+        ushr            v4.16b,  v1.16b,  #4
+        and             v3.16b,  v1.16b,  v31.16b
+        zip1            v1.16b,  v3.16b,  v4.16b
+        zip2            v2.16b,  v3.16b,  v4.16b
+        tbl             v1.16b, {v0.16b}, v1.16b
+        st1             {v1.d}[0], [x0], x1
+        tbl             v2.16b, {v0.16b}, v2.16b
+        st1             {v1.d}[1], [x2], x1
+        st1             {v2.d}[0], [x0], x1
+        st1             {v2.d}[1], [x2], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ld1             {v1.16b, v2.16b}, [x3], #32
+        subs            w5,  w5,  #4
+        ushr            v5.16b,  v1.16b,  #4
+        and             v4.16b,  v1.16b,  v31.16b
+        ushr            v7.16b,  v2.16b,  #4
+        and             v6.16b,  v2.16b,  v31.16b
+        zip1            v1.16b,  v4.16b,  v5.16b
+        zip2            v2.16b,  v4.16b,  v5.16b
+        zip1            v3.16b,  v6.16b,  v7.16b
+        tbl             v1.16b, {v0.16b}, v1.16b
+        zip2            v4.16b,  v6.16b,  v7.16b
+        tbl             v2.16b, {v0.16b}, v2.16b
+        st1             {v1.16b}, [x0], x1
+        tbl             v3.16b, {v0.16b}, v3.16b
+        st1             {v2.16b}, [x2], x1
+        tbl             v4.16b, {v0.16b}, v4.16b
+        st1             {v3.16b}, [x0], x1
+        st1             {v4.16b}, [x2], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ld1             {v16.16b, v17.16b, v18.16b, v19.16b}, [x3], #64
+        subs            w5,  w5,  #4
+        ushr            v21.16b, v16.16b, #4
+        and             v20.16b, v16.16b, v31.16b
+        ushr            v23.16b, v17.16b, #4
+        and             v22.16b, v17.16b, v31.16b
+        ushr            v25.16b, v18.16b, #4
+        and             v24.16b, v18.16b, v31.16b
+        ushr            v27.16b, v19.16b, #4
+        and             v26.16b, v19.16b, v31.16b
+        zip1            v16.16b, v20.16b, v21.16b
+        zip2            v17.16b, v20.16b, v21.16b
+        zip1            v18.16b, v22.16b, v23.16b
+        zip2            v19.16b, v22.16b, v23.16b
+        zip1            v20.16b, v24.16b, v25.16b
+        zip2            v21.16b, v24.16b, v25.16b
+        tbl             v16.16b, {v0.16b}, v16.16b
+        zip1            v22.16b, v26.16b, v27.16b
+        tbl             v17.16b, {v0.16b}, v17.16b
+        zip2            v23.16b, v26.16b, v27.16b
+        tbl             v18.16b, {v0.16b}, v18.16b
+        tbl             v19.16b, {v0.16b}, v19.16b
+        tbl             v20.16b, {v0.16b}, v20.16b
+        st1             {v16.16b, v17.16b}, [x0], x1
+        tbl             v21.16b, {v0.16b}, v21.16b
+        st1             {v18.16b, v19.16b}, [x2], x1
+        tbl             v22.16b, {v0.16b}, v22.16b
+        st1             {v20.16b, v21.16b}, [x0], x1
+        tbl             v23.16b, {v0.16b}, v23.16b
+        st1             {v22.16b, v23.16b}, [x2], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+64:
+        ld1             {v16.16b, v17.16b, v18.16b, v19.16b}, [x3], #64
+        subs            w5,  w5,  #2
+        ushr            v21.16b, v16.16b, #4
+        and             v20.16b, v16.16b, v31.16b
+        ushr            v23.16b, v17.16b, #4
+        and             v22.16b, v17.16b, v31.16b
+        ushr            v25.16b, v18.16b, #4
+        and             v24.16b, v18.16b, v31.16b
+        ushr            v27.16b, v19.16b, #4
+        and             v26.16b, v19.16b, v31.16b
+        zip1            v16.16b, v20.16b, v21.16b
+        zip2            v17.16b, v20.16b, v21.16b
+        zip1            v18.16b, v22.16b, v23.16b
+        zip2            v19.16b, v22.16b, v23.16b
+        zip1            v20.16b, v24.16b, v25.16b
+        zip2            v21.16b, v24.16b, v25.16b
+        tbl             v16.16b, {v0.16b}, v16.16b
+        zip1            v22.16b, v26.16b, v27.16b
+        tbl             v17.16b, {v0.16b}, v17.16b
+        zip2            v23.16b, v26.16b, v27.16b
+        tbl             v18.16b, {v0.16b}, v18.16b
+        tbl             v19.16b, {v0.16b}, v19.16b
+        st1             {v16.16b, v17.16b, v18.16b, v19.16b}, [x0], x1
+        tbl             v20.16b, {v0.16b}, v20.16b
+        tbl             v21.16b, {v0.16b}, v21.16b
+        tbl             v22.16b, {v0.16b}, v22.16b
+        tbl             v23.16b, {v0.16b}, v23.16b
+        st1             {v20.16b, v21.16b, v22.16b, v23.16b}, [x2], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable pal_pred_tbl
+        .word 640b - pal_pred_tbl
+        .word 320b - pal_pred_tbl
+        .word 160b - pal_pred_tbl
+        .word 80b  - pal_pred_tbl
+        .word 40b  - pal_pred_tbl
+endjumptable
+
+// void ipred_cfl_128_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height,
+//                              const int16_t *ac, const int alpha);
+function ipred_cfl_128_8bpc_neon, export=1
+        clz             w9,  w3
+        movrel          x7,  ipred_cfl_128_tbl
+        sub             w9,  w9,  #26
+        ldrsw           x9,  [x7, w9, uxtw #2]
+        movi            v0.8h,   #128 // dc
+        dup             v1.8h,   w6   // alpha
+        add             x7,  x7,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x7
+L(ipred_cfl_splat_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        ld1             {v2.8h, v3.8h}, [x5], #32
+        mul             v2.8h,   v2.8h,   v1.8h  // diff = ac * alpha
+        mul             v3.8h,   v3.8h,   v1.8h
+        cmlt            v4.8h,   v2.8h,   #0     // sign
+        cmlt            v5.8h,   v3.8h,   #0
+        add             v2.8h,   v2.8h,   v4.8h  // diff + sign
+        add             v3.8h,   v3.8h,   v5.8h
+        srshr           v2.8h,   v2.8h,   #6     // (diff + sign + 32) >> 6 = apply_sign()
+        srshr           v3.8h,   v3.8h,   #6
+        add             v2.8h,   v2.8h,   v0.8h  // dc + apply_sign()
+        add             v3.8h,   v3.8h,   v0.8h
+        sqxtun          v2.8b,   v2.8h           // iclip_pixel(dc + apply_sign())
+        sqxtun          v3.8b,   v3.8h
+        st1             {v2.s}[0],  [x0], x1
+        st1             {v2.s}[1],  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v3.s}[0],  [x0], x1
+        st1             {v3.s}[1],  [x6], x1
+        b.gt            1b
+        ret
+L(ipred_cfl_splat_w8):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        ld1             {v2.8h, v3.8h, v4.8h, v5.8h}, [x5], #64
+        mul             v2.8h,   v2.8h,   v1.8h  // diff = ac * alpha
+        mul             v3.8h,   v3.8h,   v1.8h
+        mul             v4.8h,   v4.8h,   v1.8h
+        mul             v5.8h,   v5.8h,   v1.8h
+        cmlt            v16.8h,  v2.8h,   #0     // sign
+        cmlt            v17.8h,  v3.8h,   #0
+        cmlt            v18.8h,  v4.8h,   #0
+        cmlt            v19.8h,  v5.8h,   #0
+        add             v2.8h,   v2.8h,   v16.8h // diff + sign
+        add             v3.8h,   v3.8h,   v17.8h
+        add             v4.8h,   v4.8h,   v18.8h
+        add             v5.8h,   v5.8h,   v19.8h
+        srshr           v2.8h,   v2.8h,   #6     // (diff + sign + 32) >> 6 = apply_sign()
+        srshr           v3.8h,   v3.8h,   #6
+        srshr           v4.8h,   v4.8h,   #6
+        srshr           v5.8h,   v5.8h,   #6
+        add             v2.8h,   v2.8h,   v0.8h  // dc + apply_sign()
+        add             v3.8h,   v3.8h,   v0.8h
+        add             v4.8h,   v4.8h,   v0.8h
+        add             v5.8h,   v5.8h,   v0.8h
+        sqxtun          v2.8b,   v2.8h           // iclip_pixel(dc + apply_sign())
+        sqxtun          v3.8b,   v3.8h
+        sqxtun          v4.8b,   v4.8h
+        sqxtun          v5.8b,   v5.8h
+        st1             {v2.8b},  [x0], x1
+        st1             {v3.8b},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v4.8b},  [x0], x1
+        st1             {v5.8b},  [x6], x1
+        b.gt            1b
+        ret
+L(ipred_cfl_splat_w16):
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x5,  w3, uxtw #1
+        sub             x1,  x1,  w3, uxtw
+        mov             w9,  w3
+1:
+        ld1             {v2.8h, v3.8h}, [x5], #32
+        ld1             {v4.8h, v5.8h}, [x7], #32
+        mul             v2.8h,   v2.8h,   v1.8h  // diff = ac * alpha
+        mul             v3.8h,   v3.8h,   v1.8h
+        mul             v4.8h,   v4.8h,   v1.8h
+        mul             v5.8h,   v5.8h,   v1.8h
+        cmlt            v16.8h,  v2.8h,   #0     // sign
+        cmlt            v17.8h,  v3.8h,   #0
+        cmlt            v18.8h,  v4.8h,   #0
+        cmlt            v19.8h,  v5.8h,   #0
+        add             v2.8h,   v2.8h,   v16.8h // diff + sign
+        add             v3.8h,   v3.8h,   v17.8h
+        add             v4.8h,   v4.8h,   v18.8h
+        add             v5.8h,   v5.8h,   v19.8h
+        srshr           v2.8h,   v2.8h,   #6     // (diff + sign + 32) >> 6 = apply_sign()
+        srshr           v3.8h,   v3.8h,   #6
+        srshr           v4.8h,   v4.8h,   #6
+        srshr           v5.8h,   v5.8h,   #6
+        add             v2.8h,   v2.8h,   v0.8h  // dc + apply_sign()
+        add             v3.8h,   v3.8h,   v0.8h
+        add             v4.8h,   v4.8h,   v0.8h
+        add             v5.8h,   v5.8h,   v0.8h
+        sqxtun          v2.8b,   v2.8h           // iclip_pixel(dc + apply_sign())
+        sqxtun          v3.8b,   v3.8h
+        sqxtun          v4.8b,   v4.8h
+        sqxtun          v5.8b,   v5.8h
+        subs            w3,  w3,  #16
+        st1             {v2.8b, v3.8b},  [x0], #16
+        st1             {v4.8b, v5.8b},  [x6], #16
+        b.gt            1b
+        subs            w4,  w4,  #2
+        add             x5,  x5,  w9, uxtw #1
+        add             x7,  x7,  w9, uxtw #1
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        mov             w3,  w9
+        b.gt            1b
+        ret
+endfunc
+
+jumptable ipred_cfl_128_tbl
+ipred_cfl_splat_tbl:
+        .word L(ipred_cfl_splat_w16) - ipred_cfl_128_tbl
+        .word L(ipred_cfl_splat_w16) - ipred_cfl_128_tbl
+        .word L(ipred_cfl_splat_w8)  - ipred_cfl_128_tbl
+        .word L(ipred_cfl_splat_w4)  - ipred_cfl_128_tbl
+endjumptable
+
+// void ipred_cfl_top_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height,
+//                              const int16_t *ac, const int alpha);
+function ipred_cfl_top_8bpc_neon, export=1
+        clz             w9,  w3
+        movrel          x7,  ipred_cfl_top_tbl
+        sub             w9,  w9,  #26
+        ldrsw           x9,  [x7, w9, uxtw #2]
+        dup             v1.8h,   w6   // alpha
+        add             x2,  x2,  #1
+        add             x7,  x7,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x7
+4:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v0.2s},  [x2]
+        uaddlv          h0,      v0.8b
+        urshr           v0.4h,   v0.4h,   #3
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w4)
+8:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [x2]
+        uaddlv          h0,      v0.8b
+        urshr           v0.4h,   v0.4h,   #3
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w8)
+16:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b}, [x2]
+        uaddlv          h0,      v0.16b
+        urshr           v0.4h,   v0.4h,   #4
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w16)
+32:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.16b, v3.16b}, [x2]
+        uaddlv          h2,      v2.16b
+        uaddlv          h3,      v3.16b
+        add             v2.4h,   v2.4h,   v3.4h
+        urshr           v2.4h,   v2.4h,   #5
+        dup             v0.8h,   v2.h[0]
+        b               L(ipred_cfl_splat_w16)
+endfunc
+
+jumptable ipred_cfl_top_tbl
+        .word 32b - ipred_cfl_top_tbl
+        .word 16b - ipred_cfl_top_tbl
+        .word 8b  - ipred_cfl_top_tbl
+        .word 4b  - ipred_cfl_top_tbl
+endjumptable
+
+// void ipred_cfl_left_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height,
+//                               const int16_t *ac, const int alpha);
+function ipred_cfl_left_8bpc_neon, export=1
+        sub             x2,  x2,  w4, uxtw
+        clz             w9,  w3
+        clz             w8,  w4
+        movrel          x10, ipred_cfl_splat_tbl
+        movrel          x7,  ipred_cfl_left_tbl
+        sub             w9,  w9,  #26
+        sub             w8,  w8,  #26
+        ldrsw           x9,  [x10, w9, uxtw #2]
+        ldrsw           x8,  [x7,  w8, uxtw #2]
+        dup             v1.8h,   w6   // alpha
+        add             x9,  x10, x9
+        add             x7,  x7,  x8
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x7
+
+L(ipred_cfl_left_h4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v0.2s},  [x2]
+        uaddlv          h0,      v0.8b
+        urshr           v0.4h,   v0.4h,   #3
+        dup             v0.8h,   v0.h[0]
+        br              x9
+
+L(ipred_cfl_left_h8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [x2]
+        uaddlv          h0,      v0.8b
+        urshr           v0.4h,   v0.4h,   #3
+        dup             v0.8h,   v0.h[0]
+        br              x9
+
+L(ipred_cfl_left_h16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b}, [x2]
+        uaddlv          h0,      v0.16b
+        urshr           v0.4h,   v0.4h,   #4
+        dup             v0.8h,   v0.h[0]
+        br              x9
+
+L(ipred_cfl_left_h32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.16b, v3.16b}, [x2]
+        uaddlv          h2,      v2.16b
+        uaddlv          h3,      v3.16b
+        add             v2.4h,   v2.4h,   v3.4h
+        urshr           v2.4h,   v2.4h,   #5
+        dup             v0.8h,   v2.h[0]
+        br              x9
+endfunc
+
+jumptable ipred_cfl_left_tbl
+        .word L(ipred_cfl_left_h32) - ipred_cfl_left_tbl
+        .word L(ipred_cfl_left_h16) - ipred_cfl_left_tbl
+        .word L(ipred_cfl_left_h8)  - ipred_cfl_left_tbl
+        .word L(ipred_cfl_left_h4)  - ipred_cfl_left_tbl
+endjumptable
+
+// void ipred_cfl_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                          const pixel *const topleft,
+//                          const int width, const int height,
+//                          const int16_t *ac, const int alpha);
+function ipred_cfl_8bpc_neon, export=1
+        sub             x2,  x2,  w4, uxtw
+        add             w8,  w3,  w4             // width + height
+        dup             v1.8h,   w6              // alpha
+        clz             w9,  w3
+        clz             w6,  w4
+        dup             v16.8h, w8               // width + height
+        movrel          x7,  ipred_cfl_tbl
+        rbit            w8,  w8                  // rbit(width + height)
+        sub             w9,  w9,  #22            // 26 leading bits, minus table offset 4
+        sub             w6,  w6,  #26
+        clz             w8,  w8                  // ctz(width + height)
+        ldrsw           x9,  [x7, w9, uxtw #2]
+        ldrsw           x6,  [x7, w6, uxtw #2]
+        neg             w8,  w8                  // -ctz(width + height)
+        add             x9,  x7,  x9
+        add             x7,  x7,  x6
+        ushr            v16.8h,  v16.8h,  #1     // (width + height) >> 1
+        dup             v17.8h,  w8              // -ctz(width + height)
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x7
+
+L(ipred_cfl_h4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.s}[0],  [x2], #4
+        ins             v0.s[1], wzr
+        add             x2,  x2,  #1
+        uaddlv          h0,      v0.8b
+        br              x9
+L(ipred_cfl_w4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.s}[0],  [x2]
+        ins             v2.s[1], wzr
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h2,      v2.8b
+        cmp             w4,  #4
+        add             v0.4h,   v0.4h,   v2.4h
+        ushl            v0.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 8/16
+        mov             w16, #(0x3334/2)
+        movk            w16, #(0x5556/2), lsl #16
+        add             w17, w4,  w4  // w17 = 2*h = 16 or 32
+        lsr             w16, w16, w17
+        dup             v16.4h,  w16
+        sqdmulh         v0.4h,   v0.4h,   v16.4h
+1:
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w4)
+
+L(ipred_cfl_h8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [x2], #8
+        uaddlv          h0,      v0.8b
+        add             x2,  x2,  #1
+        br              x9
+L(ipred_cfl_w8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8b},  [x2]
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h2,      v2.8b
+        cmp             w4,  #8
+        add             v0.4h,   v0.4h,   v2.4h
+        ushl            v0.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 4/16/32
+        cmp             w4,  #32
+        mov             w16, #(0x3334/2)
+        mov             w17, #(0x5556/2)
+        csel            w16, w16, w17, eq
+        dup             v16.4h,  w16
+        sqdmulh         v0.4h,   v0.4h,   v16.4h
+1:
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w8)
+
+L(ipred_cfl_h16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b}, [x2], #16
+        uaddlv          h0,      v0.16b
+        add             x2,  x2,  #1
+        br              x9
+L(ipred_cfl_w16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.16b}, [x2]
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h2,      v2.16b
+        cmp             w4,  #16
+        add             v0.4h,   v0.4h,   v2.4h
+        ushl            v0.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 4/8/32
+        cmp             w4,  #4
+        mov             w16, #(0x3334/2)
+        mov             w17, #(0x5556/2)
+        csel            w16, w16, w17, eq
+        dup             v16.4h,  w16
+        sqdmulh         v0.4h,   v0.4h,   v16.4h
+1:
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w16)
+
+L(ipred_cfl_h32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.16b, v3.16b}, [x2], #32
+        uaddlv          h2,      v2.16b
+        uaddlv          h3,      v3.16b
+        add             x2,  x2,  #1
+        add             v0.4h,   v2.4h,   v3.4h
+        br              x9
+L(ipred_cfl_w32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.16b, v3.16b}, [x2]
+        add             v0.4h,   v0.4h,   v16.4h
+        uaddlv          h2,      v2.16b
+        uaddlv          h3,      v3.16b
+        cmp             w4,  #32
+        add             v0.4h,   v0.4h,   v2.4h
+        add             v0.4h,   v0.4h,   v3.4h
+        ushl            v0.4h,   v0.4h,   v17.4h
+        b.eq            1f
+        // h = 8/16
+        mov             w16, #(0x5556/2)
+        movk            w16, #(0x3334/2), lsl #16
+        add             w17, w4,  w4  // w17 = 2*h = 16 or 32
+        lsr             w16, w16, w17
+        dup             v16.4h,  w16
+        sqdmulh         v0.4h,   v0.4h,   v16.4h
+1:
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w16)
+endfunc
+
+jumptable ipred_cfl_tbl
+        .word L(ipred_cfl_h32) - ipred_cfl_tbl
+        .word L(ipred_cfl_h16) - ipred_cfl_tbl
+        .word L(ipred_cfl_h8)  - ipred_cfl_tbl
+        .word L(ipred_cfl_h4)  - ipred_cfl_tbl
+        .word L(ipred_cfl_w32) - ipred_cfl_tbl
+        .word L(ipred_cfl_w16) - ipred_cfl_tbl
+        .word L(ipred_cfl_w8)  - ipred_cfl_tbl
+        .word L(ipred_cfl_w4)  - ipred_cfl_tbl
+endjumptable
+
+// void cfl_ac_420_8bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                           const ptrdiff_t stride, const int w_pad,
+//                           const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_420_8bpc_neon, export=1
+        clz             w8,  w5
+        lsl             w4,  w4,  #2
+        movrel          x7,  ipred_cfl_ac_420_tbl
+        sub             w8,  w8,  #27
+        ldrsw           x8,  [x7, w8, uxtw #2]
+        movi            v16.8h,  #0
+        movi            v17.8h,  #0
+        movi            v18.8h,  #0
+        movi            v19.8h,  #0
+        add             x7,  x7,  x8
+        sub             w8,  w6,  w4         // height - h_pad
+        rbit            w9,  w5              // rbit(width)
+        rbit            w10, w6              // rbit(height)
+        clz             w9,  w9              // ctz(width)
+        clz             w10, w10             // ctz(height)
+        add             w9,  w9,  w10        // log2sz
+        add             x10, x1,  x2
+        dup             v31.4s,  w9
+        lsl             x2,  x2,  #1
+        neg             v31.4s,  v31.4s      // -log2sz
+        br              x7
+
+L(ipred_cfl_ac_420_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input
+        ld1             {v0.8b},   [x1],  x2
+        ld1             {v1.8b},   [x10], x2
+        ld1             {v0.d}[1], [x1],  x2
+        ld1             {v1.d}[1], [x10], x2
+        uaddlp          v0.8h,   v0.16b
+        uaddlp          v1.8h,   v1.16b
+        add             v0.8h,   v0.8h,   v1.8h
+        shl             v0.8h,   v0.8h,   #1
+        subs            w8,  w8,  #2
+        st1             {v0.8h}, [x0], #16
+        add             v16.8h,  v16.8h,  v0.8h
+        b.gt            1b
+        trn2            v1.2d,   v0.2d,   v0.2d
+        trn2            v0.2d,   v0.2d,   v0.2d
+L(ipred_cfl_ac_420_w4_hpad):
+        cbz             w4,  3f
+2:      // Vertical padding (h_pad > 0)
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], #32
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        b.gt            2b
+3:
+        // Aggregate the sums
+        add             v0.8h,   v16.8h,  v17.8h
+        uaddlv          s0,  v0.8h                // sum
+        sub             x0,  x0,  w6, uxtw #3
+        urshl           v4.2s,   v0.2s,   v31.2s  // (sum + (1 << (log2sz - 1))) >>= log2sz
+        dup             v4.8h,   v4.h[0]
+6:      // Subtract dc from ac
+        ld1             {v0.8h, v1.8h}, [x0]
+        subs            w6,  w6,  #4
+        sub             v0.8h,   v0.8h,   v4.8h
+        sub             v1.8h,   v1.8h,   v4.8h
+        st1             {v0.8h, v1.8h}, [x0], #32
+        b.gt            6b
+        ret
+
+L(ipred_cfl_ac_420_w8):
+        AARCH64_VALID_JUMP_TARGET
+        cbnz            w3,  L(ipred_cfl_ac_420_w8_wpad)
+1:      // Copy and subsample input, without padding
+        ld1             {v0.16b}, [x1],  x2
+        ld1             {v1.16b}, [x10], x2
+        ld1             {v2.16b}, [x1],  x2
+        uaddlp          v0.8h,   v0.16b
+        ld1             {v3.16b}, [x10], x2
+        uaddlp          v1.8h,   v1.16b
+        uaddlp          v2.8h,   v2.16b
+        uaddlp          v3.8h,   v3.16b
+        add             v0.8h,   v0.8h,   v1.8h
+        add             v2.8h,   v2.8h,   v3.8h
+        shl             v0.8h,   v0.8h,   #1
+        shl             v1.8h,   v2.8h,   #1
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h}, [x0], #32
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        b.gt            1b
+        mov             v0.16b,  v1.16b
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_420_w8_wpad):
+1:      // Copy and subsample input, padding 4
+        ld1             {v0.8b},   [x1],  x2
+        ld1             {v1.8b},   [x10], x2
+        ld1             {v0.d}[1], [x1],  x2
+        ld1             {v1.d}[1], [x10], x2
+        uaddlp          v0.8h,   v0.16b
+        uaddlp          v1.8h,   v1.16b
+        add             v0.8h,   v0.8h,   v1.8h
+        shl             v0.8h,   v0.8h,   #1
+        dup             v1.4h,   v0.h[3]
+        dup             v3.4h,   v0.h[7]
+        trn2            v2.2d,   v0.2d,   v0.2d
+        subs            w8,  w8,  #2
+        st1             {v0.4h, v1.4h, v2.4h, v3.4h}, [x0], #32
+        add             v16.4h,  v16.4h,  v0.4h
+        add             v17.4h,  v17.4h,  v1.4h
+        add             v18.4h,  v18.4h,  v2.4h
+        add             v19.4h,  v19.4h,  v3.4h
+        b.gt            1b
+        trn1            v0.2d,   v2.2d,   v3.2d
+        trn1            v1.2d,   v2.2d,   v3.2d
+
+L(ipred_cfl_ac_420_w8_hpad):
+        cbz             w4,  3f
+2:      // Vertical padding (h_pad > 0)
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], #32
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        st1             {v0.8h, v1.8h}, [x0], #32
+        add             v18.8h,  v18.8h,  v0.8h
+        add             v19.8h,  v19.8h,  v1.8h
+        b.gt            2b
+3:
+
+L(ipred_cfl_ac_420_w8_calc_subtract_dc):
+        // Aggregate the sums
+        add             v0.8h,   v16.8h,  v17.8h
+        add             v2.8h,   v18.8h,  v19.8h
+        uaddlp          v0.4s,   v0.8h
+        uaddlp          v2.4s,   v2.8h
+        add             v0.4s,   v0.4s,   v2.4s
+        addv            s0,  v0.4s                // sum
+        sub             x0,  x0,  w6, uxtw #4
+        urshl           v4.2s,   v0.2s,   v31.2s  // (sum + (1 << (log2sz - 1))) >>= log2sz
+        dup             v4.8h,   v4.h[0]
+L(ipred_cfl_ac_420_w8_subtract_dc):
+6:      // Subtract dc from ac
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0]
+        subs            w6,  w6,  #4
+        sub             v0.8h,   v0.8h,   v4.8h
+        sub             v1.8h,   v1.8h,   v4.8h
+        sub             v2.8h,   v2.8h,   v4.8h
+        sub             v3.8h,   v3.8h,   v4.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        b.gt            6b
+        ret
+
+L(ipred_cfl_ac_420_w16):
+        AARCH64_VALID_JUMP_TARGET
+        movrel          x7,  ipred_cfl_ac_420_w16_tbl
+        ldrsw           x3,  [x7, w3, uxtw #2]
+        add             x7,  x7,  x3
+        br              x7
+
+L(ipred_cfl_ac_420_w16_wpad0):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, without padding
+        ld1             {v0.16b, v1.16b}, [x1],  x2
+        ld1             {v2.16b, v3.16b}, [x10], x2
+        uaddlp          v0.8h,   v0.16b
+        ld1             {v4.16b, v5.16b}, [x1],  x2
+        uaddlp          v1.8h,   v1.16b
+        ld1             {v6.16b, v7.16b}, [x10], x2
+        uaddlp          v2.8h,   v2.16b
+        uaddlp          v3.8h,   v3.16b
+        uaddlp          v4.8h,   v4.16b
+        uaddlp          v5.8h,   v5.16b
+        uaddlp          v6.8h,   v6.16b
+        uaddlp          v7.8h,   v7.16b
+        add             v0.8h,   v0.8h,   v2.8h
+        add             v1.8h,   v1.8h,   v3.8h
+        add             v4.8h,   v4.8h,   v6.8h
+        add             v5.8h,   v5.8h,   v7.8h
+        shl             v0.8h,   v0.8h,   #1
+        shl             v1.8h,   v1.8h,   #1
+        shl             v2.8h,   v4.8h,   #1
+        shl             v3.8h,   v5.8h,   #1
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad1):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 4
+        ldr             d1,  [x1,  #16]
+        ld1             {v0.16b}, [x1],  x2
+        ldr             d3,  [x10, #16]
+        ld1             {v2.16b}, [x10], x2
+        uaddlp          v1.4h,   v1.8b
+        ldr             d5,  [x1,  #16]
+        uaddlp          v0.8h,   v0.16b
+        ld1             {v4.16b}, [x1],  x2
+        uaddlp          v3.4h,   v3.8b
+        ldr             d7,  [x10, #16]
+        uaddlp          v2.8h,   v2.16b
+        ld1             {v6.16b}, [x10], x2
+        uaddlp          v5.4h,   v5.8b
+        uaddlp          v4.8h,   v4.16b
+        uaddlp          v7.4h,   v7.8b
+        uaddlp          v6.8h,   v6.16b
+        add             v1.4h,   v1.4h,   v3.4h
+        add             v0.8h,   v0.8h,   v2.8h
+        add             v5.4h,   v5.4h,   v7.4h
+        add             v4.8h,   v4.8h,   v6.8h
+        shl             v1.4h,   v1.4h,   #1
+        shl             v0.8h,   v0.8h,   #1
+        shl             v3.4h,   v5.4h,   #1
+        shl             v2.8h,   v4.8h,   #1
+        dup             v4.4h,   v1.h[3]
+        dup             v5.4h,   v3.h[3]
+        trn1            v1.2d,   v1.2d,   v4.2d
+        trn1            v3.2d,   v3.2d,   v5.2d
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad2):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 8
+        ld1             {v0.16b}, [x1],  x2
+        ld1             {v2.16b}, [x10], x2
+        ld1             {v4.16b}, [x1],  x2
+        uaddlp          v0.8h,   v0.16b
+        ld1             {v6.16b}, [x10], x2
+        uaddlp          v2.8h,   v2.16b
+        uaddlp          v4.8h,   v4.16b
+        uaddlp          v6.8h,   v6.16b
+        add             v0.8h,   v0.8h,   v2.8h
+        add             v4.8h,   v4.8h,   v6.8h
+        shl             v0.8h,   v0.8h,   #1
+        shl             v2.8h,   v4.8h,   #1
+        dup             v1.8h,   v0.h[7]
+        dup             v3.8h,   v2.h[7]
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad3):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 12
+        ld1             {v0.8b}, [x1],  x2
+        ld1             {v2.8b}, [x10], x2
+        ld1             {v4.8b}, [x1],  x2
+        uaddlp          v0.4h,   v0.8b
+        ld1             {v6.8b}, [x10], x2
+        uaddlp          v2.4h,   v2.8b
+        uaddlp          v4.4h,   v4.8b
+        uaddlp          v6.4h,   v6.8b
+        add             v0.4h,   v0.4h,   v2.4h
+        add             v4.4h,   v4.4h,   v6.4h
+        shl             v0.4h,   v0.4h,   #1
+        shl             v2.4h,   v4.4h,   #1
+        dup             v1.8h,   v0.h[3]
+        dup             v3.8h,   v2.h[3]
+        trn1            v0.2d,   v0.2d,   v1.2d
+        trn1            v2.2d,   v2.2d,   v3.2d
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+
+L(ipred_cfl_ac_420_w16_hpad):
+        cbz             w4,  3f
+2:      // Vertical padding (h_pad > 0)
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            2b
+3:
+
+        // Double the height and reuse the w8 summing/subtracting
+        lsl             w6,  w6,  #1
+        b               L(ipred_cfl_ac_420_w8_calc_subtract_dc)
+endfunc
+
+jumptable ipred_cfl_ac_420_tbl
+        .word L(ipred_cfl_ac_420_w16) - ipred_cfl_ac_420_tbl
+        .word L(ipred_cfl_ac_420_w8)  - ipred_cfl_ac_420_tbl
+        .word L(ipred_cfl_ac_420_w4)  - ipred_cfl_ac_420_tbl
+endjumptable
+
+jumptable ipred_cfl_ac_420_w16_tbl
+        .word L(ipred_cfl_ac_420_w16_wpad0) - ipred_cfl_ac_420_w16_tbl
+        .word L(ipred_cfl_ac_420_w16_wpad1) - ipred_cfl_ac_420_w16_tbl
+        .word L(ipred_cfl_ac_420_w16_wpad2) - ipred_cfl_ac_420_w16_tbl
+        .word L(ipred_cfl_ac_420_w16_wpad3) - ipred_cfl_ac_420_w16_tbl
+endjumptable
+
+// void cfl_ac_422_8bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                           const ptrdiff_t stride, const int w_pad,
+//                           const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_422_8bpc_neon, export=1
+        clz             w8,  w5
+        lsl             w4,  w4,  #2
+        movrel          x7,  ipred_cfl_ac_422_tbl
+        sub             w8,  w8,  #27
+        ldrsw           x8,  [x7, w8, uxtw #2]
+        movi            v16.8h,  #0
+        movi            v17.8h,  #0
+        movi            v18.8h,  #0
+        movi            v19.8h,  #0
+        add             x7,  x7,  x8
+        sub             w8,  w6,  w4         // height - h_pad
+        rbit            w9,  w5              // rbit(width)
+        rbit            w10, w6              // rbit(height)
+        clz             w9,  w9              // ctz(width)
+        clz             w10, w10             // ctz(height)
+        add             w9,  w9,  w10        // log2sz
+        add             x10, x1,  x2
+        dup             v31.4s,  w9
+        lsl             x2,  x2,  #1
+        neg             v31.4s,  v31.4s      // -log2sz
+        br              x7
+
+L(ipred_cfl_ac_422_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input
+        ld1             {v0.8b},   [x1],  x2
+        ld1             {v0.d}[1], [x10], x2
+        ld1             {v1.8b},   [x1],  x2
+        ld1             {v1.d}[1], [x10], x2
+        uaddlp          v0.8h,   v0.16b
+        uaddlp          v1.8h,   v1.16b
+        shl             v0.8h,   v0.8h,   #2
+        shl             v1.8h,   v1.8h,   #2
+        subs            w8,  w8,  #4
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        st1             {v0.8h, v1.8h}, [x0], #32
+        b.gt            1b
+        trn2            v0.2d,   v1.2d,   v1.2d
+        trn2            v1.2d,   v1.2d,   v1.2d
+        b               L(ipred_cfl_ac_420_w4_hpad)
+
+L(ipred_cfl_ac_422_w8):
+        AARCH64_VALID_JUMP_TARGET
+        cbnz            w3,  L(ipred_cfl_ac_422_w8_wpad)
+1:      // Copy and subsample input, without padding
+        ld1             {v0.16b}, [x1],  x2
+        ld1             {v1.16b}, [x10], x2
+        ld1             {v2.16b}, [x1],  x2
+        uaddlp          v0.8h,   v0.16b
+        ld1             {v3.16b}, [x10], x2
+        uaddlp          v1.8h,   v1.16b
+        uaddlp          v2.8h,   v2.16b
+        uaddlp          v3.8h,   v3.16b
+        shl             v0.8h,   v0.8h,   #2
+        shl             v1.8h,   v1.8h,   #2
+        shl             v2.8h,   v2.8h,   #2
+        shl             v3.8h,   v3.8h,   #2
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v3.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_422_w8_wpad):
+1:      // Copy and subsample input, padding 4
+        ld1             {v0.8b},   [x1],  x2
+        ld1             {v0.d}[1], [x10], x2
+        ld1             {v2.8b},   [x1],  x2
+        ld1             {v2.d}[1], [x10], x2
+        uaddlp          v0.8h,   v0.16b
+        uaddlp          v2.8h,   v2.16b
+        shl             v0.8h,   v0.8h,   #2
+        shl             v2.8h,   v2.8h,   #2
+        dup             v4.4h,   v0.h[3]
+        dup             v5.8h,   v0.h[7]
+        dup             v6.4h,   v2.h[3]
+        dup             v7.8h,   v2.h[7]
+        trn2            v1.2d,   v0.2d,   v5.2d
+        trn1            v0.2d,   v0.2d,   v4.2d
+        trn2            v3.2d,   v2.2d,   v7.2d
+        trn1            v2.2d,   v2.2d,   v6.2d
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v3.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_422_w16):
+        AARCH64_VALID_JUMP_TARGET
+        movrel          x7,  ipred_cfl_ac_422_w16_tbl
+        ldrsw           x3,  [x7, w3, uxtw #2]
+        add             x7,  x7,  x3
+        br              x7
+
+L(ipred_cfl_ac_422_w16_wpad0):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, without padding
+        ld1             {v0.16b, v1.16b}, [x1],  x2
+        ld1             {v2.16b, v3.16b}, [x10], x2
+        uaddlp          v0.8h,   v0.16b
+        uaddlp          v1.8h,   v1.16b
+        uaddlp          v2.8h,   v2.16b
+        uaddlp          v3.8h,   v3.16b
+        shl             v0.8h,   v0.8h,   #2
+        shl             v1.8h,   v1.8h,   #2
+        shl             v2.8h,   v2.8h,   #2
+        shl             v3.8h,   v3.8h,   #2
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad1):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 4
+        ldr             d1,  [x1,  #16]
+        ld1             {v0.16b}, [x1],  x2
+        ldr             d3,  [x10, #16]
+        ld1             {v2.16b}, [x10], x2
+        uaddlp          v1.4h,   v1.8b
+        uaddlp          v0.8h,   v0.16b
+        uaddlp          v3.4h,   v3.8b
+        uaddlp          v2.8h,   v2.16b
+        shl             v1.4h,   v1.4h,   #2
+        shl             v0.8h,   v0.8h,   #2
+        shl             v3.4h,   v3.4h,   #2
+        shl             v2.8h,   v2.8h,   #2
+        dup             v4.4h,   v1.h[3]
+        dup             v5.4h,   v3.h[3]
+        trn1            v1.2d,   v1.2d,   v4.2d
+        trn1            v3.2d,   v3.2d,   v5.2d
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad2):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 8
+        ld1             {v0.16b}, [x1],  x2
+        ld1             {v2.16b}, [x10], x2
+        uaddlp          v0.8h,   v0.16b
+        uaddlp          v2.8h,   v2.16b
+        shl             v0.8h,   v0.8h,   #2
+        shl             v2.8h,   v2.8h,   #2
+        dup             v1.8h,   v0.h[7]
+        dup             v3.8h,   v2.h[7]
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad3):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 12
+        ld1             {v0.8b}, [x1],  x2
+        ld1             {v2.8b}, [x10], x2
+        uaddlp          v0.4h,   v0.8b
+        uaddlp          v2.4h,   v2.8b
+        shl             v0.4h,   v0.4h,   #2
+        shl             v2.4h,   v2.4h,   #2
+        dup             v1.8h,   v0.h[3]
+        dup             v3.8h,   v2.h[3]
+        trn1            v0.2d,   v0.2d,   v1.2d
+        trn1            v2.2d,   v2.2d,   v3.2d
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+endfunc
+
+jumptable ipred_cfl_ac_422_tbl
+        .word L(ipred_cfl_ac_422_w16) - ipred_cfl_ac_422_tbl
+        .word L(ipred_cfl_ac_422_w8) - ipred_cfl_ac_422_tbl
+        .word L(ipred_cfl_ac_422_w4) - ipred_cfl_ac_422_tbl
+endjumptable
+
+jumptable ipred_cfl_ac_422_w16_tbl
+        .word L(ipred_cfl_ac_422_w16_wpad0) - ipred_cfl_ac_422_w16_tbl
+        .word L(ipred_cfl_ac_422_w16_wpad1) - ipred_cfl_ac_422_w16_tbl
+        .word L(ipred_cfl_ac_422_w16_wpad2) - ipred_cfl_ac_422_w16_tbl
+        .word L(ipred_cfl_ac_422_w16_wpad3) - ipred_cfl_ac_422_w16_tbl
+endjumptable
+
+// void cfl_ac_444_8bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                           const ptrdiff_t stride, const int w_pad,
+//                           const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_444_8bpc_neon, export=1
+        clz             w8,  w5
+        lsl             w4,  w4,  #2
+        movrel          x7,  ipred_cfl_ac_444_tbl
+        sub             w8,  w8,  #26
+        ldrsw           x8,  [x7, w8, uxtw #2]
+        movi            v16.8h,  #0
+        movi            v17.8h,  #0
+        movi            v18.8h,  #0
+        movi            v19.8h,  #0
+        add             x7,  x7,  x8
+        sub             w8,  w6,  w4         // height - h_pad
+        rbit            w9,  w5              // rbit(width)
+        rbit            w10, w6              // rbit(height)
+        clz             w9,  w9              // ctz(width)
+        clz             w10, w10             // ctz(height)
+        add             w9,  w9,  w10        // log2sz
+        add             x10, x1,  x2
+        dup             v31.4s,  w9
+        lsl             x2,  x2,  #1
+        neg             v31.4s,  v31.4s      // -log2sz
+        br              x7
+
+L(ipred_cfl_ac_444_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input
+        ld1             {v0.s}[0], [x1],  x2
+        ld1             {v0.s}[1], [x10], x2
+        ld1             {v1.s}[0], [x1],  x2
+        ld1             {v1.s}[1], [x10], x2
+        ushll           v0.8h,   v0.8b,   #3
+        ushll           v1.8h,   v1.8b,   #3
+        subs            w8,  w8,  #4
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        st1             {v0.8h, v1.8h}, [x0], #32
+        b.gt            1b
+        trn2            v0.2d,   v1.2d,   v1.2d
+        trn2            v1.2d,   v1.2d,   v1.2d
+        b               L(ipred_cfl_ac_420_w4_hpad)
+
+L(ipred_cfl_ac_444_w8):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input
+        ld1             {v0.8b}, [x1],  x2
+        ld1             {v1.8b}, [x10], x2
+        ld1             {v2.8b}, [x1],  x2
+        ushll           v0.8h,   v0.8b,   #3
+        ld1             {v3.8b}, [x10], x2
+        ushll           v1.8h,   v1.8b,   #3
+        ushll           v2.8h,   v2.8b,   #3
+        ushll           v3.8h,   v3.8b,   #3
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v3.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_444_w16):
+        AARCH64_VALID_JUMP_TARGET
+        cbnz            w3,  L(ipred_cfl_ac_444_w16_wpad)
+1:      // Copy and expand input, without padding
+        ld1             {v0.16b}, [x1],  x2
+        ld1             {v2.16b}, [x10], x2
+        ld1             {v4.16b}, [x1],  x2
+        ushll2          v1.8h,   v0.16b,  #3
+        ushll           v0.8h,   v0.8b,   #3
+        ld1             {v6.16b}, [x10], x2
+        ushll2          v3.8h,   v2.16b,  #3
+        ushll           v2.8h,   v2.8b,   #3
+        ushll2          v5.8h,   v4.16b,  #3
+        ushll           v4.8h,   v4.8b,   #3
+        ushll2          v7.8h,   v6.16b,  #3
+        ushll           v6.8h,   v6.8b,   #3
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v4.8h
+        add             v17.8h,  v17.8h,  v5.8h
+        add             v18.8h,  v18.8h,  v6.8h
+        add             v19.8h,  v19.8h,  v7.8h
+        b.gt            1b
+        mov             v0.16b,  v6.16b
+        mov             v1.16b,  v7.16b
+        mov             v2.16b,  v6.16b
+        mov             v3.16b,  v7.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_444_w16_wpad):
+1:      // Copy and expand input, padding 8
+        ld1             {v0.8b}, [x1],  x2
+        ld1             {v2.8b}, [x10], x2
+        ld1             {v4.8b}, [x1],  x2
+        ld1             {v6.8b}, [x10], x2
+        ushll           v0.8h,   v0.8b,   #3
+        ushll           v2.8h,   v2.8b,   #3
+        ushll           v4.8h,   v4.8b,   #3
+        ushll           v6.8h,   v6.8b,   #3
+        dup             v1.8h,   v0.h[7]
+        dup             v3.8h,   v2.h[7]
+        dup             v5.8h,   v4.h[7]
+        dup             v7.8h,   v6.h[7]
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v4.8h
+        add             v17.8h,  v17.8h,  v5.8h
+        add             v18.8h,  v18.8h,  v6.8h
+        add             v19.8h,  v19.8h,  v7.8h
+        b.gt            1b
+        mov             v0.16b,  v6.16b
+        mov             v1.16b,  v7.16b
+        mov             v2.16b,  v6.16b
+        mov             v3.16b,  v7.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_444_w32):
+        AARCH64_VALID_JUMP_TARGET
+        movrel          x7,  ipred_cfl_ac_444_w32_tbl
+        lsr             w3,  w3,  #1
+        ldrsw           x3,  [x7, w3, uxtw #2]
+        add             x7,  x7,  x3
+        br              x7
+
+L(ipred_cfl_ac_444_w32_wpad0):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input, without padding
+        ld1             {v2.16b, v3.16b}, [x1],  x2
+        ld1             {v6.16b, v7.16b}, [x10], x2
+        ushll           v0.8h,   v2.8b,   #3
+        ushll2          v1.8h,   v2.16b,  #3
+        ushll           v2.8h,   v3.8b,   #3
+        ushll2          v3.8h,   v3.16b,  #3
+        ushll           v4.8h,   v6.8b,   #3
+        ushll2          v5.8h,   v6.16b,  #3
+        ushll           v6.8h,   v7.8b,   #3
+        ushll2          v7.8h,   v7.16b,  #3
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v4.8h
+        add             v17.8h,  v17.8h,  v5.8h
+        add             v18.8h,  v18.8h,  v6.8h
+        add             v19.8h,  v19.8h,  v7.8h
+        b.gt            1b
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad2):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input, padding 8
+        ldr             d2,  [x1,  #16]
+        ld1             {v1.16b}, [x1],  x2
+        ldr             d6,  [x10, #16]
+        ld1             {v5.16b}, [x10], x2
+        ushll           v2.8h,   v2.8b,   #3
+        ushll           v0.8h,   v1.8b,   #3
+        ushll2          v1.8h,   v1.16b,  #3
+        ushll           v6.8h,   v6.8b,   #3
+        ushll           v4.8h,   v5.8b,   #3
+        ushll2          v5.8h,   v5.16b,  #3
+        dup             v3.8h,   v2.h[7]
+        dup             v7.8h,   v6.h[7]
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v4.8h
+        add             v17.8h,  v17.8h,  v5.8h
+        add             v18.8h,  v18.8h,  v6.8h
+        add             v19.8h,  v19.8h,  v7.8h
+        b.gt            1b
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad4):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input, padding 16
+        ld1             {v1.16b}, [x1],  x2
+        ld1             {v5.16b}, [x10], x2
+        ushll           v0.8h,   v1.8b,   #3
+        ushll2          v1.8h,   v1.16b,  #3
+        ushll           v4.8h,   v5.8b,   #3
+        ushll2          v5.8h,   v5.16b,  #3
+        dup             v2.8h,   v1.h[7]
+        dup             v3.8h,   v1.h[7]
+        dup             v6.8h,   v5.h[7]
+        dup             v7.8h,   v5.h[7]
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v4.8h
+        add             v17.8h,  v17.8h,  v5.8h
+        add             v18.8h,  v18.8h,  v6.8h
+        add             v19.8h,  v19.8h,  v7.8h
+        b.gt            1b
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad6):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input, padding 24
+        ld1             {v0.8b}, [x1],  x2
+        ld1             {v4.8b}, [x10], x2
+        ushll           v0.8h,   v0.8b,   #3
+        ushll           v4.8h,   v4.8b,   #3
+        dup             v1.8h,   v0.h[7]
+        dup             v2.8h,   v0.h[7]
+        dup             v3.8h,   v0.h[7]
+        dup             v5.8h,   v4.h[7]
+        dup             v6.8h,   v4.h[7]
+        dup             v7.8h,   v4.h[7]
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v0.8h
+        add             v17.8h,  v17.8h,  v1.8h
+        add             v18.8h,  v18.8h,  v2.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v4.8h
+        add             v17.8h,  v17.8h,  v5.8h
+        add             v18.8h,  v18.8h,  v6.8h
+        add             v19.8h,  v19.8h,  v7.8h
+        b.gt            1b
+
+L(ipred_cfl_ac_444_w32_hpad):
+        cbz             w4,  3f
+2:      // Vertical padding (h_pad > 0)
+        subs            w4,  w4,  #2
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v4.8h
+        add             v17.8h,  v17.8h,  v5.8h
+        add             v18.8h,  v18.8h,  v6.8h
+        add             v19.8h,  v19.8h,  v7.8h
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], #64
+        add             v16.8h,  v16.8h,  v4.8h
+        add             v17.8h,  v17.8h,  v5.8h
+        add             v18.8h,  v18.8h,  v6.8h
+        add             v19.8h,  v19.8h,  v7.8h
+        b.gt            2b
+3:
+
+        // Quadruple the height and reuse the w8 subtracting
+        lsl             w6,  w6,  #2
+        // Aggregate the sums, with wider intermediates earlier than in
+        // ipred_cfl_ac_420_w8_calc_subtract_dc.
+        uaddlp          v0.4s,   v16.8h
+        uaddlp          v1.4s,   v17.8h
+        uaddlp          v2.4s,   v18.8h
+        uaddlp          v3.4s,   v19.8h
+        add             v0.4s,   v0.4s,   v1.4s
+        add             v2.4s,   v2.4s,   v3.4s
+        add             v0.4s,   v0.4s,   v2.4s
+        addv            s0,  v0.4s                // sum
+        sub             x0,  x0,  w6, uxtw #4
+        urshl           v4.2s,   v0.2s,   v31.2s  // (sum + (1 << (log2sz - 1))) >>= log2sz
+        dup             v4.8h,   v4.h[0]
+        b               L(ipred_cfl_ac_420_w8_subtract_dc)
+endfunc
+
+jumptable ipred_cfl_ac_444_tbl
+        .word L(ipred_cfl_ac_444_w32) - ipred_cfl_ac_444_tbl
+        .word L(ipred_cfl_ac_444_w16) - ipred_cfl_ac_444_tbl
+        .word L(ipred_cfl_ac_444_w8)  - ipred_cfl_ac_444_tbl
+        .word L(ipred_cfl_ac_444_w4)  - ipred_cfl_ac_444_tbl
+endjumptable
+
+jumptable ipred_cfl_ac_444_w32_tbl
+        .word L(ipred_cfl_ac_444_w32_wpad0) - ipred_cfl_ac_444_w32_tbl
+        .word L(ipred_cfl_ac_444_w32_wpad2) - ipred_cfl_ac_444_w32_tbl
+        .word L(ipred_cfl_ac_444_w32_wpad4) - ipred_cfl_ac_444_w32_tbl
+        .word L(ipred_cfl_ac_444_w32_wpad6) - ipred_cfl_ac_444_w32_tbl
+endjumptable
diff --git a/media/libdav1d/src/src/arm/64/ipred16.S b/media/libdav1d/src/src/arm/64/ipred16.S
new file mode 100644
index 0000000000..2292a85565
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/ipred16.S
@@ -0,0 +1,5714 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// void ipred_dc_128_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int a,
+//                              const int max_width, const int max_height,
+//                              const int bitdepth_max);
+function ipred_dc_128_16bpc_neon, export=1
+        ldr             w8,  [sp]
+        clz             w3,  w3
+        movrel          x5,  ipred_dc_128_tbl
+        sub             w3,  w3,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        dup             v0.8h,   w8
+        add             x5,  x5,  x3
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        urshr           v0.8h,   v0.8h,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        mov             v1.16b,  v0.16b
+16:
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        mov             v1.16b,  v0.16b
+        mov             v2.16b,  v0.16b
+        mov             v3.16b,  v0.16b
+32:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+        mov             v1.16b,  v0.16b
+        mov             v2.16b,  v0.16b
+        mov             v3.16b,  v0.16b
+        sub             x1,  x1,  #64
+64:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable ipred_dc_128_tbl
+        .word 640b - ipred_dc_128_tbl
+        .word 320b - ipred_dc_128_tbl
+        .word 160b - ipred_dc_128_tbl
+        .word 80b  - ipred_dc_128_tbl
+        .word 40b  - ipred_dc_128_tbl
+endjumptable
+
+// void ipred_v_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const topleft,
+//                         const int width, const int height, const int a,
+//                         const int max_width, const int max_height);
+function ipred_v_16bpc_neon, export=1
+        clz             w3,  w3
+        movrel          x5,  ipred_v_tbl
+        sub             w3,  w3,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        add             x2,  x2,  #2
+        add             x5,  x5,  x3
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.4h},  [x2]
+4:
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h},  [x2]
+8:
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h}, [x2]
+16:
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x2]
+32:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x2], #64
+        sub             x1,  x1,  #64
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2]
+64:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], x1
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], x1
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable ipred_v_tbl
+        .word 640b - ipred_v_tbl
+        .word 320b - ipred_v_tbl
+        .word 160b - ipred_v_tbl
+        .word 80b  - ipred_v_tbl
+        .word 40b  - ipred_v_tbl
+endjumptable
+
+// void ipred_h_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const topleft,
+//                         const int width, const int height, const int a,
+//                         const int max_width, const int max_height);
+function ipred_h_16bpc_neon, export=1
+        clz             w3,  w3
+        movrel          x5,  ipred_h_tbl
+        sub             w3,  w3,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        sub             x2,  x2,  #8
+        add             x5,  x5,  x3
+        mov             x7,  #-8
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},  [x2], x7
+        st1             {v3.4h},  [x0], x1
+        st1             {v2.4h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v1.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},  [x2], x7
+        st1             {v3.8h},  [x0], x1
+        st1             {v2.8h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v1.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},  [x2], x7
+        str             q3,  [x0, #16]
+        str             q2,  [x6, #16]
+        st1             {v3.8h}, [x0], x1
+        st1             {v2.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        str             q1,  [x0, #16]
+        str             q0,  [x6, #16]
+        st1             {v1.8h}, [x0], x1
+        st1             {v0.8h}, [x6], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},  [x2], x7
+        str             q3,  [x0, #16]
+        str             q2,  [x6, #16]
+        stp             q3,  q3,  [x0, #32]
+        stp             q2,  q2,  [x6, #32]
+        st1             {v3.8h}, [x0], x1
+        st1             {v2.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        str             q1,  [x0, #16]
+        str             q0,  [x6, #16]
+        stp             q1,  q1,  [x0, #32]
+        stp             q0,  q0,  [x6, #32]
+        st1             {v1.8h}, [x0], x1
+        st1             {v0.8h}, [x6], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+64:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},  [x2], x7
+        str             q3,  [x0, #16]
+        str             q2,  [x6, #16]
+        stp             q3,  q3,  [x0, #32]
+        stp             q2,  q2,  [x6, #32]
+        stp             q3,  q3,  [x0, #64]
+        stp             q2,  q2,  [x6, #64]
+        stp             q3,  q3,  [x0, #96]
+        stp             q2,  q2,  [x6, #96]
+        st1             {v3.8h}, [x0], x1
+        st1             {v2.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        str             q1,  [x0, #16]
+        str             q0,  [x6, #16]
+        stp             q1,  q1,  [x0, #32]
+        stp             q0,  q0,  [x6, #32]
+        stp             q1,  q1,  [x0, #64]
+        stp             q0,  q0,  [x6, #64]
+        stp             q1,  q1,  [x0, #96]
+        stp             q0,  q0,  [x6, #96]
+        st1             {v1.8h}, [x0], x1
+        st1             {v0.8h}, [x6], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable ipred_h_tbl
+        .word 640b - ipred_h_tbl
+        .word 320b - ipred_h_tbl
+        .word 160b - ipred_h_tbl
+        .word 80b  - ipred_h_tbl
+        .word 40b  - ipred_h_tbl
+endjumptable
+
+// void ipred_dc_top_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int a,
+//                              const int max_width, const int max_height);
+function ipred_dc_top_16bpc_neon, export=1
+        clz             w3,  w3
+        movrel          x5,  ipred_dc_top_tbl
+        sub             w3,  w3,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        add             x2,  x2,  #2
+        add             x5,  x5,  x3
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.4h},  [x2]
+        addv            h0,      v0.4h
+        urshr           v0.4h,   v0.4h,   #2
+        dup             v0.4h,   v0.h[0]
+4:
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h},  [x2]
+        addv            h0,      v0.8h
+        urshr           v0.4h,   v0.4h,   #3
+        dup             v0.8h,   v0.h[0]
+8:
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h}, [x2]
+        addp            v0.8h,   v0.8h,   v1.8h
+        addv            h0,      v0.8h
+        urshr           v2.4h,   v0.4h,   #4
+        dup             v0.8h,   v2.h[0]
+        dup             v1.8h,   v2.h[0]
+16:
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x2]
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v0.8h,   v0.8h,   v2.8h
+        uaddlv          s0,      v0.8h
+        rshrn           v4.4h,   v0.4s,   #5
+        dup             v0.8h,   v4.h[0]
+        dup             v1.8h,   v4.h[0]
+        dup             v2.8h,   v4.h[0]
+        dup             v3.8h,   v4.h[0]
+32:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x2], #64
+        addp            v0.8h,   v0.8h,   v1.8h
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2]
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+        addp            v0.8h,   v0.8h,   v2.8h
+        addp            v4.8h,   v4.8h,   v6.8h
+        addp            v0.8h,   v0.8h,   v4.8h
+        uaddlv          s0,      v0.8h
+        rshrn           v4.4h,   v0.4s,   #6
+        sub             x1,  x1,  #64
+        dup             v0.8h,   v4.h[0]
+        dup             v1.8h,   v4.h[0]
+        dup             v2.8h,   v4.h[0]
+        dup             v3.8h,   v4.h[0]
+64:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable ipred_dc_top_tbl
+        .word 640b - ipred_dc_top_tbl
+        .word 320b - ipred_dc_top_tbl
+        .word 160b - ipred_dc_top_tbl
+        .word 80b  - ipred_dc_top_tbl
+        .word 40b  - ipred_dc_top_tbl
+endjumptable
+
+// void ipred_dc_left_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height, const int a,
+//                               const int max_width, const int max_height);
+function ipred_dc_left_16bpc_neon, export=1
+        sub             x2,  x2,  w4, uxtw #1
+        clz             w3,  w3
+        clz             w7,  w4
+        movrel          x5,  ipred_dc_left_tbl
+        sub             w3,  w3,  #20 // 25 leading bits, minus table offset 5
+        sub             w7,  w7,  #25
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        ldrsw           x7,  [x5, w7, uxtw #2]
+        add             x3,  x5,  x3
+        add             x5,  x5,  x7
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+
+L(ipred_dc_left_h4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.4h},  [x2]
+        addv            h0,      v0.4h
+        urshr           v0.4h,   v0.4h,   #2
+        dup             v0.8h,   v0.h[0]
+        br              x3
+L(ipred_dc_left_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        b.gt            1b
+        ret
+
+L(ipred_dc_left_h8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h},  [x2]
+        addv            h0,      v0.8h
+        urshr           v0.4h,   v0.4h,   #3
+        dup             v0.8h,   v0.h[0]
+        br              x3
+L(ipred_dc_left_w8):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        b.gt            1b
+        ret
+
+L(ipred_dc_left_h16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h}, [x2]
+        addp            v0.8h,   v0.8h,   v1.8h
+        addv            h0,      v0.8h
+        urshr           v2.4h,   v0.4h,   #4
+        dup             v0.8h,   v2.h[0]
+        dup             v1.8h,   v2.h[0]
+        br              x3
+L(ipred_dc_left_w16):
+        AARCH64_VALID_JUMP_TARGET
+        mov             v1.16b,  v0.16b
+1:
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        b.gt            1b
+        ret
+
+L(ipred_dc_left_h32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x2]
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v0.8h,   v0.8h,   v2.8h
+        uaddlp          v0.4s,   v0.8h
+        addv            s0,      v0.4s
+        rshrn           v4.4h,   v0.4s,   #5
+        dup             v0.8h,   v4.h[0]
+        br              x3
+L(ipred_dc_left_w32):
+        AARCH64_VALID_JUMP_TARGET
+        mov             v1.16b,  v0.16b
+        mov             v2.16b,  v0.16b
+        mov             v3.16b,  v0.16b
+1:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            1b
+        ret
+
+L(ipred_dc_left_h64):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x2], #64
+        addp            v0.8h,   v0.8h,   v1.8h
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2]
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+        addp            v0.8h,   v0.8h,   v2.8h
+        addp            v4.8h,   v4.8h,   v6.8h
+        addp            v0.8h,   v0.8h,   v4.8h
+        uaddlv          s0,      v0.8h
+        rshrn           v4.4h,   v0.4s,   #6
+        dup             v0.8h,   v4.h[0]
+        br              x3
+L(ipred_dc_left_w64):
+        AARCH64_VALID_JUMP_TARGET
+        mov             v1.16b,  v0.16b
+        mov             v2.16b,  v0.16b
+        mov             v3.16b,  v0.16b
+        sub             x1,  x1,  #64
+1:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            1b
+        ret
+endfunc
+
+jumptable ipred_dc_left_tbl
+        .word L(ipred_dc_left_h64) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_h32) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_h16) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_h8)  - ipred_dc_left_tbl
+        .word L(ipred_dc_left_h4)  - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w64) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w32) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w16) - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w8)  - ipred_dc_left_tbl
+        .word L(ipred_dc_left_w4)  - ipred_dc_left_tbl
+endjumptable
+
+// void ipred_dc_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                          const pixel *const topleft,
+//                          const int width, const int height, const int a,
+//                          const int max_width, const int max_height);
+function ipred_dc_16bpc_neon, export=1
+        sub             x2,  x2,  w4, uxtw #1
+        add             w7,  w3,  w4             // width + height
+        clz             w3,  w3
+        clz             w6,  w4
+        dup             v16.4s, w7               // width + height
+        movrel          x5,  ipred_dc_tbl
+        rbit            w7,  w7                  // rbit(width + height)
+        sub             w3,  w3,  #20            // 25 leading bits, minus table offset 5
+        sub             w6,  w6,  #25
+        clz             w7,  w7                  // ctz(width + height)
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        ldrsw           x6,  [x5, w6, uxtw #2]
+        neg             w7,  w7                  // -ctz(width + height)
+        add             x3,  x5,  x3
+        add             x5,  x5,  x6
+        ushr            v16.4s,  v16.4s,  #1     // (width + height) >> 1
+        dup             v17.4s,  w7              // -ctz(width + height)
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+
+L(ipred_dc_h4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.4h},  [x2], #8
+        uaddlv          s0,      v0.4h
+        add             x2,  x2,  #2
+        br              x3
+L(ipred_dc_w4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.4h},  [x2]
+        add             v0.2s,   v0.2s,   v16.2s
+        uaddlv          s1,      v1.4h
+        cmp             w4,  #4
+        add             v0.2s,   v0.2s,   v1.2s
+        ushl            v0.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 8/16
+        cmp             w4,  #16
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v0.2s,   v0.2s,   v16.2s
+        ushr            v0.2s,   v0.2s,   #17
+1:
+        dup             v0.4h,   v0.h[0]
+2:
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.4h},  [x0], x1
+        st1             {v0.4h},  [x6], x1
+        b.gt            2b
+        ret
+
+L(ipred_dc_h8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h},  [x2], #16
+        uaddlv          s0,      v0.8h
+        add             x2,  x2,  #2
+        br              x3
+L(ipred_dc_w8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.8h},  [x2]
+        add             v0.2s,   v0.2s,   v16.2s
+        uaddlv          s1,      v1.8h
+        cmp             w4,  #8
+        add             v0.2s,   v0.2s,   v1.2s
+        ushl            v0.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 4/16/32
+        cmp             w4,  #32
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v0.2s,   v0.2s,   v16.2s
+        ushr            v0.2s,   v0.2s,   #17
+1:
+        dup             v0.8h,   v0.h[0]
+2:
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h},  [x0], x1
+        st1             {v0.8h},  [x6], x1
+        b.gt            2b
+        ret
+
+L(ipred_dc_h16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h}, [x2], #32
+        addp            v0.8h,   v0.8h,   v1.8h
+        add             x2,  x2,  #2
+        uaddlv          s0,      v0.8h
+        br              x3
+L(ipred_dc_w16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.8h, v2.8h}, [x2]
+        add             v0.2s,   v0.2s,   v16.2s
+        addp            v1.8h,   v1.8h,   v2.8h
+        uaddlv          s1,      v1.8h
+        cmp             w4,  #16
+        add             v0.2s,   v0.2s,   v1.2s
+        ushl            v4.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 4/8/32/64
+        tst             w4,  #(32+16+8) // 16 added to make a consecutive bitmask
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v4.2s,   v4.2s,   v16.2s
+        ushr            v4.2s,   v4.2s,   #17
+1:
+        dup             v0.8h,   v4.h[0]
+        dup             v1.8h,   v4.h[0]
+2:
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v0.8h, v1.8h}, [x6], x1
+        b.gt            2b
+        ret
+
+L(ipred_dc_h32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x2], #64
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v0.8h,   v0.8h,   v2.8h
+        add             x2,  x2,  #2
+        uaddlv          s0,      v0.8h
+        br              x3
+L(ipred_dc_w32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.8h, v2.8h, v3.8h, v4.8h}, [x2]
+        add             v0.2s,   v0.2s,   v16.2s
+        addp            v1.8h,   v1.8h,   v2.8h
+        addp            v3.8h,   v3.8h,   v4.8h
+        addp            v1.8h,   v1.8h,   v3.8h
+        uaddlv          s1,      v1.8h
+        cmp             w4,  #32
+        add             v0.2s,   v0.2s,   v1.2s
+        ushl            v4.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 8/16/64
+        cmp             w4,  #8
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v4.2s,   v4.2s,   v16.2s
+        ushr            v4.2s,   v4.2s,   #17
+1:
+        dup             v0.8h,   v4.h[0]
+        dup             v1.8h,   v4.h[0]
+        dup             v2.8h,   v4.h[0]
+        dup             v3.8h,   v4.h[0]
+2:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            2b
+        ret
+
+L(ipred_dc_h64):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x2], #64
+        addp            v0.8h,   v0.8h,   v1.8h
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2], #64
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+        addp            v0.8h,   v0.8h,   v2.8h
+        addp            v4.8h,   v4.8h,   v6.8h
+        addp            v0.8h,   v0.8h,   v4.8h
+        add             x2,  x2,  #2
+        uaddlv          s0,      v0.8h
+        br              x3
+L(ipred_dc_w64):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v1.8h, v2.8h, v3.8h, v4.8h}, [x2], #64
+        add             v0.2s,   v0.2s,   v16.2s
+        addp            v1.8h,   v1.8h,   v2.8h
+        ld1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x2]
+        addp            v3.8h,   v3.8h,   v4.8h
+        addp            v20.8h,  v20.8h,  v21.8h
+        addp            v22.8h,  v22.8h,  v23.8h
+        addp            v1.8h,   v1.8h,   v3.8h
+        addp            v20.8h,  v20.8h,  v22.8h
+        addp            v1.8h,   v1.8h,   v20.8h
+        uaddlv          s1,      v1.8h
+        cmp             w4,  #64
+        add             v0.2s,   v0.2s,   v1.2s
+        ushl            v4.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 16/32
+        cmp             w4,  #16
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v4.2s,   v4.2s,   v16.2s
+        ushr            v4.2s,   v4.2s,   #17
+1:
+        sub             x1,  x1,  #64
+        dup             v0.8h,   v4.h[0]
+        dup             v1.8h,   v4.h[0]
+        dup             v2.8h,   v4.h[0]
+        dup             v3.8h,   v4.h[0]
+2:
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], #64
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x1
+        b.gt            2b
+        ret
+endfunc
+
+jumptable ipred_dc_tbl
+        .word L(ipred_dc_h64) - ipred_dc_tbl
+        .word L(ipred_dc_h32) - ipred_dc_tbl
+        .word L(ipred_dc_h16) - ipred_dc_tbl
+        .word L(ipred_dc_h8)  - ipred_dc_tbl
+        .word L(ipred_dc_h4)  - ipred_dc_tbl
+        .word L(ipred_dc_w64) - ipred_dc_tbl
+        .word L(ipred_dc_w32) - ipred_dc_tbl
+        .word L(ipred_dc_w16) - ipred_dc_tbl
+        .word L(ipred_dc_w8)  - ipred_dc_tbl
+        .word L(ipred_dc_w4)  - ipred_dc_tbl
+endjumptable
+
+// void ipred_paeth_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                             const pixel *const topleft,
+//                             const int width, const int height, const int a,
+//                             const int max_width, const int max_height);
+function ipred_paeth_16bpc_neon, export=1
+        clz             w9,  w3
+        movrel          x5,  ipred_paeth_tbl
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        ld1r            {v4.8h},  [x2]
+        add             x8,  x2,  #2
+        sub             x2,  x2,  #8
+        add             x5,  x5,  x9
+        mov             x7,  #-8
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v5.2d},  [x8]
+        sub             v6.8h,   v5.8h,   v4.8h   // top - topleft
+4:
+        ld4r            {v0.4h, v1.4h, v2.4h, v3.4h},  [x2], x7
+        zip1            v0.2d,   v0.2d,   v1.2d
+        zip1            v2.2d,   v2.2d,   v3.2d
+        add             v16.8h,  v6.8h,   v0.8h   // base
+        add             v17.8h,  v6.8h,   v2.8h
+        sabd            v20.8h,  v5.8h,   v16.8h  // tdiff
+        sabd            v21.8h,  v5.8h,   v17.8h
+        sabd            v22.8h,  v4.8h,   v16.8h  // tldiff
+        sabd            v23.8h,  v4.8h,   v17.8h
+        sabd            v16.8h,  v0.8h,   v16.8h  // ldiff
+        sabd            v17.8h,  v2.8h,   v17.8h
+        umin            v18.8h,  v20.8h,  v22.8h  // min(tdiff, tldiff)
+        umin            v19.8h,  v21.8h,  v23.8h
+        cmge            v20.8h,  v22.8h,  v20.8h  // tldiff >= tdiff
+        cmge            v21.8h,  v23.8h,  v21.8h
+        cmge            v16.8h,  v18.8h,  v16.8h  // min(tdiff, tldiff) >= ldiff
+        cmge            v17.8h,  v19.8h,  v17.8h
+        bsl             v21.16b, v5.16b,  v4.16b  // tdiff <= tldiff ? top : topleft
+        bsl             v20.16b, v5.16b,  v4.16b
+        bit             v21.16b, v2.16b,  v17.16b // ldiff <= min ? left : ...
+        bit             v20.16b, v0.16b,  v16.16b
+        st1             {v21.d}[1], [x0], x1
+        st1             {v21.d}[0], [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v20.d}[1], [x0], x1
+        st1             {v20.d}[0], [x6], x1
+        b.gt            4b
+        ret
+80:
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v5.8h},  [x8], #16
+        mov             w9,  w3
+        // Set up pointers for four rows in parallel; x0, x6, x5, x10
+        add             x5,  x0,  x1
+        add             x10, x6,  x1
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3, uxtw #1
+1:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},  [x2], x7
+2:
+        sub             v6.8h,   v5.8h,   v4.8h   // top - topleft
+        add             v16.8h,  v6.8h,   v0.8h   // base
+        add             v17.8h,  v6.8h,   v1.8h
+        add             v18.8h,  v6.8h,   v2.8h
+        add             v19.8h,  v6.8h,   v3.8h
+        sabd            v20.8h,  v5.8h,   v16.8h  // tdiff
+        sabd            v21.8h,  v5.8h,   v17.8h
+        sabd            v22.8h,  v5.8h,   v18.8h
+        sabd            v23.8h,  v5.8h,   v19.8h
+        sabd            v24.8h,  v4.8h,   v16.8h  // tldiff
+        sabd            v25.8h,  v4.8h,   v17.8h
+        sabd            v26.8h,  v4.8h,   v18.8h
+        sabd            v27.8h,  v4.8h,   v19.8h
+        sabd            v16.8h,  v0.8h,   v16.8h  // ldiff
+        sabd            v17.8h,  v1.8h,   v17.8h
+        sabd            v18.8h,  v2.8h,   v18.8h
+        sabd            v19.8h,  v3.8h,   v19.8h
+        umin            v28.8h,  v20.8h,  v24.8h  // min(tdiff, tldiff)
+        umin            v29.8h,  v21.8h,  v25.8h
+        umin            v30.8h,  v22.8h,  v26.8h
+        umin            v31.8h,  v23.8h,  v27.8h
+        cmge            v20.8h,  v24.8h,  v20.8h  // tldiff >= tdiff
+        cmge            v21.8h,  v25.8h,  v21.8h
+        cmge            v22.8h,  v26.8h,  v22.8h
+        cmge            v23.8h,  v27.8h,  v23.8h
+        cmge            v16.8h,  v28.8h,  v16.8h  // min(tdiff, tldiff) >= ldiff
+        cmge            v17.8h,  v29.8h,  v17.8h
+        cmge            v18.8h,  v30.8h,  v18.8h
+        cmge            v19.8h,  v31.8h,  v19.8h
+        bsl             v23.16b, v5.16b,  v4.16b  // tdiff <= tldiff ? top : topleft
+        bsl             v22.16b, v5.16b,  v4.16b
+        bsl             v21.16b, v5.16b,  v4.16b
+        bsl             v20.16b, v5.16b,  v4.16b
+        bit             v23.16b, v3.16b,  v19.16b // ldiff <= min ? left : ...
+        bit             v22.16b, v2.16b,  v18.16b
+        bit             v21.16b, v1.16b,  v17.16b
+        bit             v20.16b, v0.16b,  v16.16b
+        st1             {v23.8h}, [x0], #16
+        st1             {v22.8h}, [x6], #16
+        subs            w3,  w3,  #8
+        st1             {v21.8h}, [x5], #16
+        st1             {v20.8h}, [x10], #16
+        b.le            8f
+        ld1             {v5.8h},  [x8], #16
+        b               2b
+8:
+        subs            w4,  w4,  #4
+        b.le            9f
+        // End of horizontal loop, move pointers to next four rows
+        sub             x8,  x8,  w9, uxtw #1
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        // Load the top row as early as possible
+        ld1             {v5.8h},  [x8], #16
+        add             x5,  x5,  x1
+        add             x10, x10, x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_paeth_tbl
+        .word 640b - ipred_paeth_tbl
+        .word 320b - ipred_paeth_tbl
+        .word 160b - ipred_paeth_tbl
+        .word 80b  - ipred_paeth_tbl
+        .word 40b  - ipred_paeth_tbl
+endjumptable
+
+// void ipred_smooth_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int a,
+//                              const int max_width, const int max_height);
+function ipred_smooth_16bpc_neon, export=1
+        movrel          x10, X(sm_weights)
+        add             x11, x10, w4, uxtw
+        add             x10, x10, w3, uxtw
+        clz             w9,  w3
+        movrel          x5,  ipred_smooth_tbl
+        sub             x12, x2,  w4, uxtw #1
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        ld1r            {v4.8h},  [x12] // bottom
+        add             x8,  x2,  #2
+        add             x5,  x5,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v6.2d}, [x8]             // top
+        ld1r            {v7.2s}, [x10]            // weights_hor
+        sub             x2,  x2,  #8
+        mov             x7,  #-8
+        dup             v5.8h,   v6.h[3]          // right
+        sub             v6.8h,   v6.8h,   v4.8h   // top-bottom
+        uxtl            v7.8h,   v7.8b            // weights_hor
+        add             v31.4h,  v4.4h,   v5.4h   // bottom+right
+4:
+        ld4r            {v0.4h, v1.4h, v2.4h, v3.4h},  [x2], x7 // left
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b},  [x11], #4 // weights_ver
+        ushll           v20.4s,  v31.4h,  #8      // (bottom+right)*256
+        ushll           v21.4s,  v31.4h,  #8
+        ushll           v22.4s,  v31.4h,  #8
+        ushll           v23.4s,  v31.4h,  #8
+        zip1            v1.2d,   v1.2d,   v0.2d   // left, flipped
+        zip1            v0.2d,   v3.2d,   v2.2d
+        zip1            v16.2s,  v16.2s,  v17.2s  // weights_ver
+        zip1            v18.2s,  v18.2s,  v19.2s
+        sub             v0.8h,   v0.8h,   v5.8h   // left-right
+        sub             v1.8h,   v1.8h,   v5.8h
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v18.8h,  v18.8b
+        smlal           v20.4s,  v0.4h,   v7.4h   // += (left-right)*weights_hor
+        smlal2          v21.4s,  v0.8h,   v7.8h
+        smlal           v22.4s,  v1.4h,   v7.4h
+        smlal2          v23.4s,  v1.8h,   v7.8h
+        smlal           v20.4s,  v6.4h,   v16.4h  // += (top-bottom)*weights_ver
+        smlal2          v21.4s,  v6.8h,   v16.8h
+        smlal           v22.4s,  v6.4h,   v18.4h
+        smlal2          v23.4s,  v6.8h,   v18.8h
+        rshrn           v20.4h,  v20.4s,  #9
+        rshrn           v21.4h,  v21.4s,  #9
+        rshrn           v22.4h,  v22.4s,  #9
+        rshrn           v23.4h,  v23.4s,  #9
+        st1             {v20.4h}, [x0], x1
+        st1             {v21.4h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v22.4h}, [x0], x1
+        st1             {v23.4h}, [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v6.8h}, [x8]             // top
+        ld1             {v7.8b}, [x10]            // weights_hor
+        sub             x2,  x2,  #8
+        mov             x7,  #-8
+        dup             v5.8h,   v6.h[7]          // right
+        sub             v6.8h,   v6.8h,   v4.8h   // top-bottom
+        uxtl            v7.8h,   v7.8b            // weights_hor
+        add             v31.4h,  v4.4h,   v5.4h   // bottom+right
+8:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},  [x2], x7 // left
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b},  [x11], #4 // weights_ver
+        ushll           v20.4s,  v31.4h,  #8      // (bottom+right)*256
+        ushll           v21.4s,  v31.4h,  #8
+        ushll           v22.4s,  v31.4h,  #8
+        ushll           v23.4s,  v31.4h,  #8
+        ushll           v24.4s,  v31.4h,  #8
+        ushll           v25.4s,  v31.4h,  #8
+        ushll           v26.4s,  v31.4h,  #8
+        ushll           v27.4s,  v31.4h,  #8
+        sub             v0.8h,   v0.8h,   v5.8h   // left-right
+        sub             v1.8h,   v1.8h,   v5.8h
+        sub             v2.8h,   v2.8h,   v5.8h
+        sub             v3.8h,   v3.8h,   v5.8h
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v17.8h,  v17.8b
+        uxtl            v18.8h,  v18.8b
+        uxtl            v19.8h,  v19.8b
+        smlal           v20.4s,  v3.4h,   v7.4h   // += (left-right)*weights_hor
+        smlal2          v21.4s,  v3.8h,   v7.8h   // (left flipped)
+        smlal           v22.4s,  v2.4h,   v7.4h
+        smlal2          v23.4s,  v2.8h,   v7.8h
+        smlal           v24.4s,  v1.4h,   v7.4h
+        smlal2          v25.4s,  v1.8h,   v7.8h
+        smlal           v26.4s,  v0.4h,   v7.4h
+        smlal2          v27.4s,  v0.8h,   v7.8h
+        smlal           v20.4s,  v6.4h,   v16.4h  // += (top-bottom)*weights_ver
+        smlal2          v21.4s,  v6.8h,   v16.8h
+        smlal           v22.4s,  v6.4h,   v17.4h
+        smlal2          v23.4s,  v6.8h,   v17.8h
+        smlal           v24.4s,  v6.4h,   v18.4h
+        smlal2          v25.4s,  v6.8h,   v18.8h
+        smlal           v26.4s,  v6.4h,   v19.4h
+        smlal2          v27.4s,  v6.8h,   v19.8h
+        rshrn           v20.4h,  v20.4s,  #9
+        rshrn2          v20.8h,  v21.4s,  #9
+        rshrn           v21.4h,  v22.4s,  #9
+        rshrn2          v21.8h,  v23.4s,  #9
+        rshrn           v22.4h,  v24.4s,  #9
+        rshrn2          v22.8h,  v25.4s,  #9
+        rshrn           v23.4h,  v26.4s,  #9
+        rshrn2          v23.8h,  v27.4s,  #9
+        st1             {v20.8h}, [x0], x1
+        st1             {v21.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v22.8h}, [x0], x1
+        st1             {v23.8h}, [x6], x1
+        b.gt            8b
+        ret
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        add             x12, x2,  w3, uxtw #1
+        sub             x1,  x1,  w3, uxtw #1
+        ld1r            {v5.8h}, [x12]            // right
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+        mov             w9,  w3
+        add             v31.4h,  v4.4h,   v5.4h   // bottom+right
+
+1:
+        ld2r            {v0.8h, v1.8h},   [x2],  x7 // left
+        ld2r            {v16.8b, v17.8b}, [x11], #2 // weights_ver
+        sub             v0.8h,   v0.8h,   v5.8h   // left-right
+        sub             v1.8h,   v1.8h,   v5.8h
+        uxtl            v16.8h,  v16.8b           // weights_ver
+        uxtl            v17.8h,  v17.8b
+2:
+        ld1             {v7.16b}, [x10],  #16     // weights_hor
+        ld1             {v2.8h, v3.8h}, [x8], #32 // top
+        ushll           v20.4s,  v31.4h,  #8      // (bottom+right)*256
+        ushll           v21.4s,  v31.4h,  #8
+        ushll           v22.4s,  v31.4h,  #8
+        ushll           v23.4s,  v31.4h,  #8
+        ushll           v24.4s,  v31.4h,  #8
+        ushll           v25.4s,  v31.4h,  #8
+        ushll           v26.4s,  v31.4h,  #8
+        ushll           v27.4s,  v31.4h,  #8
+        uxtl            v6.8h,   v7.8b            // weights_hor
+        uxtl2           v7.8h,   v7.16b
+        sub             v2.8h,   v2.8h,   v4.8h   // top-bottom
+        sub             v3.8h,   v3.8h,   v4.8h
+        smlal           v20.4s,  v1.4h,   v6.4h   // += (left-right)*weights_hor
+        smlal2          v21.4s,  v1.8h,   v6.8h   // (left flipped)
+        smlal           v22.4s,  v1.4h,   v7.4h
+        smlal2          v23.4s,  v1.8h,   v7.8h
+        smlal           v24.4s,  v0.4h,   v6.4h
+        smlal2          v25.4s,  v0.8h,   v6.8h
+        smlal           v26.4s,  v0.4h,   v7.4h
+        smlal2          v27.4s,  v0.8h,   v7.8h
+        smlal           v20.4s,  v2.4h,   v16.4h  // += (top-bottom)*weights_ver
+        smlal2          v21.4s,  v2.8h,   v16.8h
+        smlal           v22.4s,  v3.4h,   v16.4h
+        smlal2          v23.4s,  v3.8h,   v16.8h
+        smlal           v24.4s,  v2.4h,   v17.4h
+        smlal2          v25.4s,  v2.8h,   v17.8h
+        smlal           v26.4s,  v3.4h,   v17.4h
+        smlal2          v27.4s,  v3.8h,   v17.8h
+        rshrn           v20.4h,  v20.4s,  #9
+        rshrn2          v20.8h,  v21.4s,  #9
+        rshrn           v21.4h,  v22.4s,  #9
+        rshrn2          v21.8h,  v23.4s,  #9
+        rshrn           v22.4h,  v24.4s,  #9
+        rshrn2          v22.8h,  v25.4s,  #9
+        rshrn           v23.4h,  v26.4s,  #9
+        rshrn2          v23.8h,  v27.4s,  #9
+        subs            w3,  w3,  #16
+        st1             {v20.8h, v21.8h}, [x0], #32
+        st1             {v22.8h, v23.8h}, [x6], #32
+        b.gt            2b
+        subs            w4,  w4,  #2
+        b.le            9f
+        sub             x8,  x8,  w9, uxtw #1
+        sub             x10, x10, w9, uxtw
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_smooth_tbl
+        .word 640b - ipred_smooth_tbl
+        .word 320b - ipred_smooth_tbl
+        .word 160b - ipred_smooth_tbl
+        .word 80b  - ipred_smooth_tbl
+        .word 40b  - ipred_smooth_tbl
+endjumptable
+
+// void ipred_smooth_v_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const topleft,
+//                                const int width, const int height, const int a,
+//                                const int max_width, const int max_height);
+function ipred_smooth_v_16bpc_neon, export=1
+        movrel          x7,  X(sm_weights)
+        add             x7,  x7,  w4, uxtw
+        clz             w9,  w3
+        movrel          x5,  ipred_smooth_v_tbl
+        sub             x8,  x2,  w4, uxtw #1
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        ld1r            {v4.8h},  [x8] // bottom
+        add             x2,  x2,  #2
+        add             x5,  x5,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v6.2d}, [x2]             // top
+        sub             v6.8h,   v6.8h,   v4.8h   // top-bottom
+4:
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b},  [x7], #4 // weights_ver
+        zip1            v16.2s,  v16.2s,  v17.2s  // weights_ver
+        zip1            v18.2s,  v18.2s,  v19.2s
+        ushll           v16.8h,  v16.8b,  #7      // weights_ver << 7
+        ushll           v18.8h,  v18.8b,  #7
+        sqrdmulh        v20.8h,  v6.8h,   v16.8h  // ((top-bottom)*weights_ver + 128) >> 8
+        sqrdmulh        v21.8h,  v6.8h,   v18.8h
+        add             v20.8h,  v20.8h,  v4.8h
+        add             v21.8h,  v21.8h,  v4.8h
+        st1             {v20.d}[0], [x0], x1
+        st1             {v20.d}[1], [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v21.d}[0], [x0], x1
+        st1             {v21.d}[1], [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v6.8h}, [x2]             // top
+        sub             v6.8h,   v6.8h,   v4.8h   // top-bottom
+8:
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b},  [x7], #4 // weights_ver
+        ushll           v16.8h,  v16.8b,  #7      // weights_ver << 7
+        ushll           v17.8h,  v17.8b,  #7
+        ushll           v18.8h,  v18.8b,  #7
+        ushll           v19.8h,  v19.8b,  #7
+        sqrdmulh        v20.8h,  v6.8h,   v16.8h  // ((top-bottom)*weights_ver + 128) >> 8
+        sqrdmulh        v21.8h,  v6.8h,   v17.8h
+        sqrdmulh        v22.8h,  v6.8h,   v18.8h
+        sqrdmulh        v23.8h,  v6.8h,   v19.8h
+        add             v20.8h,  v20.8h,  v4.8h
+        add             v21.8h,  v21.8h,  v4.8h
+        add             v22.8h,  v22.8h,  v4.8h
+        add             v23.8h,  v23.8h,  v4.8h
+        st1             {v20.8h}, [x0], x1
+        st1             {v21.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v22.8h}, [x0], x1
+        st1             {v23.8h}, [x6], x1
+        b.gt            8b
+        ret
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        // Set up pointers for four rows in parallel; x0, x6, x5, x8
+        add             x5,  x0,  x1
+        add             x8,  x6,  x1
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3, uxtw #1
+        mov             w9,  w3
+
+1:
+        ld4r            {v16.8b, v17.8b, v18.8b, v19.8b}, [x7], #4 // weights_ver
+        ushll           v16.8h,  v16.8b,  #7      // weights_ver << 7
+        ushll           v17.8h,  v17.8b,  #7
+        ushll           v18.8h,  v18.8b,  #7
+        ushll           v19.8h,  v19.8b,  #7
+2:
+        ld1             {v2.8h, v3.8h}, [x2], #32 // top
+        sub             v2.8h,   v2.8h,   v4.8h   // top-bottom
+        sub             v3.8h,   v3.8h,   v4.8h
+        sqrdmulh        v20.8h,  v2.8h,   v16.8h  // ((top-bottom)*weights_ver + 128) >> 8
+        sqrdmulh        v21.8h,  v3.8h,   v16.8h
+        sqrdmulh        v22.8h,  v2.8h,   v17.8h
+        sqrdmulh        v23.8h,  v3.8h,   v17.8h
+        sqrdmulh        v24.8h,  v2.8h,   v18.8h
+        sqrdmulh        v25.8h,  v3.8h,   v18.8h
+        sqrdmulh        v26.8h,  v2.8h,   v19.8h
+        sqrdmulh        v27.8h,  v3.8h,   v19.8h
+        add             v20.8h,  v20.8h,  v4.8h
+        add             v21.8h,  v21.8h,  v4.8h
+        add             v22.8h,  v22.8h,  v4.8h
+        add             v23.8h,  v23.8h,  v4.8h
+        add             v24.8h,  v24.8h,  v4.8h
+        add             v25.8h,  v25.8h,  v4.8h
+        add             v26.8h,  v26.8h,  v4.8h
+        add             v27.8h,  v27.8h,  v4.8h
+        subs            w3,  w3,  #16
+        st1             {v20.8h, v21.8h}, [x0], #32
+        st1             {v22.8h, v23.8h}, [x6], #32
+        st1             {v24.8h, v25.8h}, [x5], #32
+        st1             {v26.8h, v27.8h}, [x8], #32
+        b.gt            2b
+        subs            w4,  w4,  #4
+        b.le            9f
+        sub             x2,  x2,  w9, uxtw #1
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        add             x5,  x5,  x1
+        add             x8,  x8,  x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_smooth_v_tbl
+        .word 640b - ipred_smooth_v_tbl
+        .word 320b - ipred_smooth_v_tbl
+        .word 160b - ipred_smooth_v_tbl
+        .word 80b  - ipred_smooth_v_tbl
+        .word 40b  - ipred_smooth_v_tbl
+endjumptable
+
+// void ipred_smooth_h_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const topleft,
+//                                const int width, const int height, const int a,
+//                                const int max_width, const int max_height);
+function ipred_smooth_h_16bpc_neon, export=1
+        movrel          x8,  X(sm_weights)
+        add             x8,  x8,  w3, uxtw
+        clz             w9,  w3
+        movrel          x5,  ipred_smooth_h_tbl
+        add             x12, x2,  w3, uxtw #1
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        ld1r            {v5.8h},  [x12] // right
+        add             x5,  x5,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v7.2s}, [x8]             // weights_hor
+        sub             x2,  x2,  #8
+        mov             x7,  #-8
+        ushll           v7.8h,   v7.8b,   #7      // weights_hor << 7
+4:
+        ld4r            {v0.4h, v1.4h, v2.4h, v3.4h},  [x2], x7 // left
+        zip1            v1.2d,   v1.2d,   v0.2d   // left, flipped
+        zip1            v0.2d,   v3.2d,   v2.2d
+        sub             v0.8h,   v0.8h,   v5.8h   // left-right
+        sub             v1.8h,   v1.8h,   v5.8h
+        sqrdmulh        v20.8h,  v0.8h,   v7.8h   // ((left-right)*weights_hor + 128) >> 8
+        sqrdmulh        v21.8h,  v1.8h,   v7.8h
+        add             v20.8h,  v20.8h,  v5.8h
+        add             v21.8h,  v21.8h,  v5.8h
+        st1             {v20.d}[0], [x0], x1
+        st1             {v20.d}[1], [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v21.d}[0], [x0], x1
+        st1             {v21.d}[1], [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v7.8b}, [x8]             // weights_hor
+        sub             x2,  x2,  #8
+        mov             x7,  #-8
+        ushll           v7.8h,   v7.8b,   #7      // weights_hor << 7
+8:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},  [x2], x7 // left
+        sub             v3.8h,   v3.8h,   v5.8h   // left-right
+        sub             v2.8h,   v2.8h,   v5.8h
+        sub             v1.8h,   v1.8h,   v5.8h
+        sub             v0.8h,   v0.8h,   v5.8h
+        sqrdmulh        v20.8h,  v3.8h,   v7.8h   // ((left-right)*weights_hor + 128) >> 8
+        sqrdmulh        v21.8h,  v2.8h,   v7.8h   // (left flipped)
+        sqrdmulh        v22.8h,  v1.8h,   v7.8h
+        sqrdmulh        v23.8h,  v0.8h,   v7.8h
+        add             v20.8h,  v20.8h,  v5.8h
+        add             v21.8h,  v21.8h,  v5.8h
+        add             v22.8h,  v22.8h,  v5.8h
+        add             v23.8h,  v23.8h,  v5.8h
+        st1             {v20.8h}, [x0], x1
+        st1             {v21.8h}, [x6], x1
+        subs            w4,  w4,  #4
+        st1             {v22.8h}, [x0], x1
+        st1             {v23.8h}, [x6], x1
+        b.gt            8b
+        ret
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        sub             x2,  x2,  #8
+        mov             x7,  #-8
+        // Set up pointers for four rows in parallel; x0, x6, x5, x10
+        add             x5,  x0,  x1
+        add             x10, x6,  x1
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3, uxtw #1
+        mov             w9,  w3
+
+1:
+        ld4r            {v0.8h, v1.8h, v2.8h, v3.8h},   [x2],  x7 // left
+        sub             v0.8h,   v0.8h,   v5.8h   // left-right
+        sub             v1.8h,   v1.8h,   v5.8h
+        sub             v2.8h,   v2.8h,   v5.8h
+        sub             v3.8h,   v3.8h,   v5.8h
+2:
+        ld1             {v7.16b}, [x8],   #16     // weights_hor
+        ushll           v6.8h,   v7.8b,   #7      // weights_hor << 7
+        ushll2          v7.8h,   v7.16b,  #7
+        sqrdmulh        v20.8h,  v3.8h,   v6.8h   // ((left-right)*weights_hor + 128) >> 8
+        sqrdmulh        v21.8h,  v3.8h,   v7.8h   // (left flipped)
+        sqrdmulh        v22.8h,  v2.8h,   v6.8h
+        sqrdmulh        v23.8h,  v2.8h,   v7.8h
+        sqrdmulh        v24.8h,  v1.8h,   v6.8h
+        sqrdmulh        v25.8h,  v1.8h,   v7.8h
+        sqrdmulh        v26.8h,  v0.8h,   v6.8h
+        sqrdmulh        v27.8h,  v0.8h,   v7.8h
+        add             v20.8h,  v20.8h,  v5.8h
+        add             v21.8h,  v21.8h,  v5.8h
+        add             v22.8h,  v22.8h,  v5.8h
+        add             v23.8h,  v23.8h,  v5.8h
+        add             v24.8h,  v24.8h,  v5.8h
+        add             v25.8h,  v25.8h,  v5.8h
+        add             v26.8h,  v26.8h,  v5.8h
+        add             v27.8h,  v27.8h,  v5.8h
+        subs            w3,  w3,  #16
+        st1             {v20.8h, v21.8h}, [x0],  #32
+        st1             {v22.8h, v23.8h}, [x6],  #32
+        st1             {v24.8h, v25.8h}, [x5],  #32
+        st1             {v26.8h, v27.8h}, [x10], #32
+        b.gt            2b
+        subs            w4,  w4,  #4
+        b.le            9f
+        sub             x8,  x8,  w9, uxtw
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        add             x5,  x5,  x1
+        add             x10, x10, x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_smooth_h_tbl
+        .word 640b - ipred_smooth_h_tbl
+        .word 320b - ipred_smooth_h_tbl
+        .word 160b - ipred_smooth_h_tbl
+        .word 80b  - ipred_smooth_h_tbl
+        .word 40b  - ipred_smooth_h_tbl
+endjumptable
+
+const padding_mask_buf
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+padding_mask:
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+endconst
+
+// void ipred_z1_upsample_edge_16bpc_neon(pixel *out, const int hsz,
+//                                        const pixel *const in, const int end,
+//                                        const int bitdepth_max);
+function ipred_z1_upsample_edge_16bpc_neon, export=1
+        dup             v30.8h,  w4               // bitdepth_max
+        movrel          x4,  padding_mask
+        ld1             {v0.8h, v1.8h},  [x2]     // in[]
+        add             x5,  x2,  w3,  uxtw #1    // in[end]
+        sub             x4,  x4,  w3,  uxtw #1
+
+        ld1r            {v2.8h},  [x5]            // padding
+        ld1             {v3.8h, v4.8h}, [x4]      // padding_mask
+
+        movi            v31.8h,  #9
+
+        bit             v0.16b,  v2.16b,  v3.16b  // padded in[]
+        bit             v1.16b,  v2.16b,  v4.16b
+
+        ext             v4.16b,  v0.16b,  v1.16b,  #2
+        ext             v5.16b,  v1.16b,  v2.16b,  #2
+        ext             v6.16b,  v0.16b,  v1.16b,  #4
+        ext             v7.16b,  v1.16b,  v2.16b,  #4
+        ext             v16.16b, v0.16b,  v1.16b,  #6
+        ext             v17.16b, v1.16b,  v2.16b,  #6
+
+        add             v18.8h,  v4.8h,   v6.8h   // in[i+1] + in[i+2]
+        add             v19.8h,  v5.8h,   v7.8h
+        add             v20.8h,  v0.8h,   v16.8h
+        add             v21.8h,  v1.8h,   v17.8h
+        umull           v22.4s,  v18.4h,  v31.4h  // 9*(in[i+1] + in[i+2])
+        umull2          v23.4s,  v18.8h,  v31.8h
+        umull           v24.4s,  v19.4h,  v31.4h
+        umull2          v25.4s,  v19.8h,  v31.8h
+        usubw           v22.4s,  v22.4s,  v20.4h
+        usubw2          v23.4s,  v23.4s,  v20.8h
+        usubw           v24.4s,  v24.4s,  v21.4h
+        usubw2          v25.4s,  v25.4s,  v21.8h
+
+        sqrshrun        v16.4h,  v22.4s,  #4
+        sqrshrun2       v16.8h,  v23.4s,  #4
+        sqrshrun        v17.4h,  v24.4s,  #4
+        sqrshrun2       v17.8h,  v25.4s,  #4
+
+        smin            v16.8h,  v16.8h,  v30.8h
+        smin            v17.8h,  v17.8h,  v30.8h
+
+        zip1            v0.8h,   v4.8h,   v16.8h
+        zip2            v1.8h,   v4.8h,   v16.8h
+        zip1            v2.8h,   v5.8h,   v17.8h
+        zip2            v3.8h,   v5.8h,   v17.8h
+
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0]
+
+        ret
+endfunc
+
+// void ipred_z2_upsample_edge_16bpc_neon(pixel *out, const int sz,
+//                                        const pixel *const in,
+//                                        const int bitdepth_max);
+function ipred_z2_upsample_edge_16bpc_neon, export=1
+        dup             v30.8h,  w3               // bitdepth_max
+        // Here, sz is 4 or 8, and we produce 2*sz+1 output elements.
+        movrel          x4,  padding_mask
+        ld1             {v0.8h, v1.8h}, [x2]      // in[]
+        add             x5,  x2,  w1,  uxtw #1    // in[sz]
+        sub             x4,  x4,  w1,  uxtw #1
+
+        ld1r            {v3.8h},  [x2]            // in[0] for padding
+        ld1r            {v2.8h},  [x5]            // padding
+        ld1             {v4.8h, v5.8h}, [x4]      // padding_mask
+
+        movi            v31.8h,  #9
+
+        bit             v0.16b,  v2.16b,  v4.16b  // padded in[]
+        bit             v1.16b,  v2.16b,  v5.16b
+
+        ext             v4.16b,  v3.16b,  v0.16b,  #14
+        ext             v5.16b,  v0.16b,  v1.16b,  #2
+        ext             v6.16b,  v0.16b,  v1.16b,  #4
+
+        add             v16.8h,  v0.8h,   v5.8h   // in[i+0] + in[i+1]
+        add             v17.8h,  v4.8h,   v6.8h   // in[i-1] + in[i+2]
+        umull           v18.4s,  v16.4h,  v31.4h  // 9*(in[i+1] + in[i+2])
+        umull2          v19.4s,  v16.8h,  v31.8h
+        usubw           v18.4s,  v18.4s,  v17.4h
+        usubw2          v19.4s,  v19.4s,  v17.8h
+
+        sqrshrun        v16.4h,  v18.4s,  #4
+        sqrshrun2       v16.8h,  v19.4s,  #4
+
+        add             x5,  x0,  #2*16
+
+        smin            v16.8h,  v16.8h,  v30.8h
+
+        zip1            v4.8h,   v0.8h,   v16.8h
+        zip2            v5.8h,   v0.8h,   v16.8h
+
+        st1             {v2.h}[0], [x5]
+        // In case sz=8, output one single pixel in out[16].
+        st1             {v4.8h, v5.8h}, [x0]
+
+        ret
+endfunc
+
+const edge_filter
+        .short 0, 4, 8, 0
+        .short 0, 5, 6, 0
+// Leaving out the coeffs for strength=3
+//      .byte 2, 4, 4, 0
+endconst
+
+// void ipred_z1_filter_edge_16bpc_neon(pixel *out, const int sz,
+//                                      const pixel *const in, const int end,
+//                                      const int strength);
+function ipred_z1_filter_edge_16bpc_neon, export=1
+        cmp             w4, #3
+        b.eq            L(fivetap)                // if (strength == 3) goto fivetap
+
+        movrel          x5,  edge_filter, -6
+        add             x5,  x5,  w4,  uxtw #3    // edge_filter + 2*((strength - 1)*4 + 1)
+
+        ld1             {v31.s}[0], [x5]          // kernel[1-2]
+
+        ld1             {v0.8h}, [x2], #16
+
+        dup             v30.8h, v31.h[0]
+        dup             v31.8h, v31.h[1]
+1:
+        // in[end], is the last valid pixel. We produce 16 pixels out by
+        // using 18 pixels in - the last pixel used is [17] of the ones
+        // read/buffered.
+        cmp             w3,  #17
+        ld1             {v1.8h, v2.8h}, [x2], #32
+        b.lt            2f
+        ext             v3.16b,  v0.16b,  v1.16b,  #2
+        ext             v4.16b,  v1.16b,  v2.16b,  #2
+        ext             v5.16b,  v0.16b,  v1.16b,  #4
+        ext             v6.16b,  v1.16b,  v2.16b,  #4
+        mul             v16.8h,  v0.8h,   v30.8h
+        mla             v16.8h,  v3.8h,   v31.8h
+        mla             v16.8h,  v5.8h,   v30.8h
+        mul             v17.8h,  v1.8h,   v30.8h
+        mla             v17.8h,  v4.8h,   v31.8h
+        mla             v17.8h,  v6.8h,   v30.8h
+        subs            w1,  w1,  #16
+        mov             v0.16b,  v2.16b
+        urshr           v16.8h,  v16.8h,  #4
+        urshr           v17.8h,  v17.8h,  #4
+        sub             w3,  w3,  #16
+        st1             {v16.8h, v17.8h}, [x0], #32
+        b.gt            1b
+        ret
+2:
+        // Right padding
+
+        // x2[w3-24] is the padding pixel (x2 points 24 pixels ahead)
+        movrel          x5,  padding_mask
+        sub             w6,  w3,  #24
+        sub             x5,  x5,  w3,  uxtw #1
+        add             x6,  x2,  w6,  sxtw #1
+
+        ld1             {v3.8h, v4.8h}, [x5] // padding_mask
+
+        ld1r            {v2.8h}, [x6]
+        bit             v0.16b,  v2.16b,  v3.16b  // Pad v0-v1
+        bit             v1.16b,  v2.16b,  v4.16b
+
+        // Filter one block
+        ext             v3.16b,  v0.16b,  v1.16b,  #2
+        ext             v4.16b,  v1.16b,  v2.16b,  #2
+        ext             v5.16b,  v0.16b,  v1.16b,  #4
+        ext             v6.16b,  v1.16b,  v2.16b,  #4
+        mul             v16.8h,  v0.8h,   v30.8h
+        mla             v16.8h,  v3.8h,   v31.8h
+        mla             v16.8h,  v5.8h,   v30.8h
+        mul             v17.8h,  v1.8h,   v30.8h
+        mla             v17.8h,  v4.8h,   v31.8h
+        mla             v17.8h,  v6.8h,   v30.8h
+        subs            w1,  w1,  #16
+        urshr           v16.8h,  v16.8h,  #4
+        urshr           v17.8h,  v17.8h,  #4
+        st1             {v16.8h, v17.8h}, [x0], #32
+        b.le            9f
+5:
+        // After one block, any remaining output would only be filtering
+        // padding - thus just store the padding.
+        subs            w1,  w1,  #16
+        st1             {v2.16b}, [x0], #16
+        b.gt            5b
+9:
+        ret
+
+L(fivetap):
+        sub             x2,  x2,  #2              // topleft -= 1 pixel
+        movi            v29.8h, #2
+        ld1             {v0.8h}, [x2], #16
+        movi            v30.8h, #4
+        movi            v31.8h, #4
+        ins             v0.h[0], v0.h[1]
+1:
+        // in[end+1], is the last valid pixel. We produce 16 pixels out by
+        // using 20 pixels in - the last pixel used is [19] of the ones
+        // read/buffered.
+        cmp             w3,  #18
+        ld1             {v1.8h, v2.8h}, [x2], #32
+        b.lt            2f                        // if (end + 1 < 19)
+        ext             v3.16b,  v0.16b,  v1.16b,  #2
+        ext             v4.16b,  v1.16b,  v2.16b,  #2
+        ext             v5.16b,  v0.16b,  v1.16b,  #4
+        ext             v6.16b,  v1.16b,  v2.16b,  #4
+        ext             v16.16b, v0.16b,  v1.16b,  #6
+        ext             v17.16b, v1.16b,  v2.16b,  #6
+        ext             v18.16b, v0.16b,  v1.16b,  #8
+        ext             v19.16b, v1.16b,  v2.16b,  #8
+        mul             v20.8h,  v0.8h,   v29.8h
+        mla             v20.8h,  v3.8h,   v30.8h
+        mla             v20.8h,  v5.8h,   v31.8h
+        mla             v20.8h,  v16.8h,  v30.8h
+        mla             v20.8h,  v18.8h,  v29.8h
+        mul             v21.8h,  v1.8h,   v29.8h
+        mla             v21.8h,  v4.8h,   v30.8h
+        mla             v21.8h,  v6.8h,   v31.8h
+        mla             v21.8h,  v17.8h,  v30.8h
+        mla             v21.8h,  v19.8h,  v29.8h
+        subs            w1,  w1,  #16
+        mov             v0.16b,  v2.16b
+        urshr           v20.8h,  v20.8h,  #4
+        urshr           v21.8h,  v21.8h,  #4
+        sub             w3,  w3,  #16
+        st1             {v20.8h, v21.8h}, [x0], #32
+        b.gt            1b
+        ret
+2:
+        // Right padding
+
+        // x2[w3+1-24] is the padding pixel (x2 points 24 pixels ahead)
+        movrel          x5,  padding_mask, -2
+        sub             w6,  w3,  #23
+        sub             x5,  x5,  w3,  uxtw #1
+        add             x6,  x2,  w6,  sxtw #1
+
+        ld1             {v3.8h, v4.8h, v5.8h}, [x5] // padding_mask
+
+        ld1r            {v28.8h}, [x6]
+        bit             v0.16b,  v28.16b, v3.16b  // Pad v0-v2
+        bit             v1.16b,  v28.16b, v4.16b
+        bit             v2.16b,  v28.16b, v5.16b
+4:
+        // Filter one block
+        ext             v3.16b,  v0.16b,  v1.16b,  #2
+        ext             v4.16b,  v1.16b,  v2.16b,  #2
+        ext             v5.16b,  v0.16b,  v1.16b,  #4
+        ext             v6.16b,  v1.16b,  v2.16b,  #4
+        ext             v16.16b, v0.16b,  v1.16b,  #6
+        ext             v17.16b, v1.16b,  v2.16b,  #6
+        ext             v18.16b, v0.16b,  v1.16b,  #8
+        ext             v19.16b, v1.16b,  v2.16b,  #8
+        mul             v20.8h,  v0.8h,   v29.8h
+        mla             v20.8h,  v3.8h,   v30.8h
+        mla             v20.8h,  v5.8h,   v31.8h
+        mla             v20.8h,  v16.8h,  v30.8h
+        mla             v20.8h,  v18.8h,  v29.8h
+        mul             v21.8h,  v1.8h,   v29.8h
+        mla             v21.8h,  v4.8h,   v30.8h
+        mla             v21.8h,  v6.8h,   v31.8h
+        mla             v21.8h,  v17.8h,  v30.8h
+        mla             v21.8h,  v19.8h,  v29.8h
+        subs            w1,  w1,  #16
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v28.16b
+        mov             v2.16b,  v28.16b
+        urshr           v20.8h,  v20.8h,  #4
+        urshr           v21.8h,  v21.8h,  #4
+        sub             w3,  w3,  #16
+        st1             {v20.8h, v21.8h}, [x0], #32
+        b.le            9f
+        // v0-v1[w3+1] is the last valid pixel; if (w3 + 1 > 0) we need to
+        // filter properly once more - aka (w3 >= 0).
+        cmp             w3,  #0
+        b.ge            4b
+5:
+        // When w3 <= 0, all remaining pixels in v0-v1 are equal to the
+        // last valid pixel - thus just output that without filtering.
+        subs            w1,  w1,  #8
+        st1             {v28.8h}, [x0], #16
+        b.gt            5b
+9:
+        ret
+endfunc
+
+// void ipred_pixel_set_16bpc_neon(pixel *out, const pixel px,
+//                                 const int n);
+function ipred_pixel_set_16bpc_neon, export=1
+        dup             v0.8h,   w1
+1:
+        subs            w2,  w2,  #8
+        st1             {v0.8h}, [x0], #16
+        b.gt            1b
+        ret
+endfunc
+
+// void ipred_z1_fill1_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const top,
+//                                const int width, const int height,
+//                                const int dx, const int max_base_x);
+function ipred_z1_fill1_16bpc_neon, export=1
+        clz             w9,  w3
+        movrel          x8,  ipred_z1_fill1_tbl
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x8, w9, uxtw #2]
+        add             x10, x2,  w6,  uxtw #1    // top[max_base_x]
+        add             x8,  x8,  x9
+        ld1r            {v31.8h}, [x10]           // padding
+        mov             w7,  w5
+        mov             w15, #64
+        br              x8
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            49f
+        lsl             w8,  w8,  #1
+        lsl             w10, w10, #1
+        ldr             q0,  [x2, w8, uxtw]       // top[base]
+        ldr             q2,  [x2, w10, uxtw]
+        dup             v4.4h,   w9               // frac
+        dup             v5.4h,   w11
+        ext             v1.16b,  v0.16b,  v0.16b,  #2 // top[base+1]
+        ext             v3.16b,  v2.16b,  v2.16b,  #2
+        sub             v6.4h,   v1.4h,   v0.4h   // top[base+1]-top[base]
+        sub             v7.4h,   v3.4h,   v2.4h
+        ushll           v16.4s,  v0.4h,   #6      // top[base]*64
+        ushll           v17.4s,  v2.4h,   #6
+        smlal           v16.4s,  v6.4h,   v4.4h   // + top[base+1]*frac
+        smlal           v17.4s,  v7.4h,   v5.4h
+        rshrn           v16.4h,  v16.4s,  #6
+        rshrn           v17.4h,  v17.4s,  #6
+        st1             {v16.4h}, [x0], x1
+        add             w7,  w7,  w5              // xpos += dx
+        subs            w4,  w4,  #2
+        st1             {v17.4h}, [x0], x1
+        b.gt            4b
+        ret
+
+49:
+        st1             {v31.4h}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v31.4h}, [x0], x1
+        b.gt            49b
+        ret
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            89f
+        add             x8,  x2,  w8,  uxtw #1
+        add             x10, x2,  w10, uxtw #1
+        dup             v4.8h,   w9               // frac
+        dup             v5.8h,   w11
+        ld1             {v0.8h},  [x8]            // top[base]
+        ld1             {v2.8h},  [x10]
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        ldr             h1, [x8, #16]
+        ldr             h3, [x10, #16]
+        dup             v6.8h,   w9               // 64 - frac
+        dup             v7.8h,   w11
+        ext             v1.16b,  v0.16b,  v1.16b,  #2 // top[base+1]
+        ext             v3.16b,  v2.16b,  v3.16b,  #2
+        umull           v16.4s,  v0.4h,   v6.4h   // top[base]*(64-frac)
+        umlal           v16.4s,  v1.4h,   v4.4h   // + top[base+1]*frac
+        umull2          v17.4s,  v0.8h,   v6.8h
+        umlal2          v17.4s,  v1.8h,   v4.8h
+        umull           v18.4s,  v2.4h,   v7.4h
+        umlal           v18.4s,  v3.4h,   v5.4h
+        umull2          v19.4s,  v2.8h,   v7.8h
+        umlal2          v19.4s,  v3.8h,   v5.8h
+        rshrn           v16.4h,  v16.4s,  #6
+        rshrn2          v16.8h,  v17.4s,  #6
+        rshrn           v17.4h,  v18.4s,  #6
+        rshrn2          v17.8h,  v19.4s,  #6
+        st1             {v16.8h}, [x0], x1
+        add             w7,  w7,  w5              // xpos += dx
+        subs            w4,  w4,  #2
+        st1             {v17.8h}, [x0], x1
+        b.gt            8b
+        ret
+
+89:
+        st1             {v31.8h}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v31.8h}, [x0], x1
+        b.gt            89b
+        ret
+
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+
+        mov             w12, w3
+
+        add             x13, x0,  x1
+        lsl             x1,  x1,  #1
+        sub             x1,  x1,  w3,  uxtw #1
+1:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            169f
+        add             x8,  x2,  w8,  uxtw #1
+        add             x10, x2,  w10, uxtw #1
+        dup             v6.8h,   w9               // frac
+        dup             v7.8h,   w11
+        ld1             {v0.8h, v1.8h, v2.8h}, [x8],  #48 // top[base]
+        ld1             {v3.8h, v4.8h, v5.8h}, [x10], #48
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        dup             v16.8h,  w9               // 64 - frac
+        dup             v17.8h,  w11
+        add             w7,  w7,  w5              // xpos += dx
+2:
+        ext             v18.16b, v0.16b,  v1.16b,  #2 // top[base+1]
+        ext             v19.16b, v1.16b,  v2.16b,  #2
+        ext             v20.16b, v3.16b,  v4.16b,  #2
+        ext             v21.16b, v4.16b,  v5.16b,  #2
+        subs            w3,  w3,  #16
+        umull           v22.4s,  v0.4h,   v16.4h  // top[base]*(64-frac)
+        umlal           v22.4s,  v18.4h,  v6.4h   // + top[base+1]*frac
+        umull2          v23.4s,  v0.8h,   v16.8h
+        umlal2          v23.4s,  v18.8h,  v6.8h
+        umull           v24.4s,  v1.4h,   v16.4h
+        umlal           v24.4s,  v19.4h,  v6.4h
+        umull2          v25.4s,  v1.8h,   v16.8h
+        umlal2          v25.4s,  v19.8h,  v6.8h
+        umull           v26.4s,  v3.4h,   v17.4h
+        umlal           v26.4s,  v20.4h,  v7.4h
+        umull2          v27.4s,  v3.8h,   v17.8h
+        umlal2          v27.4s,  v20.8h,  v7.8h
+        umull           v28.4s,  v4.4h,   v17.4h
+        umlal           v28.4s,  v21.4h,  v7.4h
+        umull2          v29.4s,  v4.8h,   v17.8h
+        umlal2          v29.4s,  v21.8h,  v7.8h
+        rshrn           v22.4h,  v22.4s,  #6
+        rshrn2          v22.8h,  v23.4s,  #6
+        rshrn           v23.4h,  v24.4s,  #6
+        rshrn2          v23.8h,  v25.4s,  #6
+        rshrn           v24.4h,  v26.4s,  #6
+        rshrn2          v24.8h,  v27.4s,  #6
+        rshrn           v25.4h,  v28.4s,  #6
+        rshrn2          v25.8h,  v29.4s,  #6
+        st1             {v22.8h, v23.8h}, [x0],  #32
+        st1             {v24.8h, v25.8h}, [x13], #32
+        b.le            3f
+        mov             v0.16b,  v2.16b
+        ld1             {v1.8h, v2.8h}, [x8],  #32 // top[base]
+        mov             v3.16b,  v5.16b
+        ld1             {v4.8h, v5.8h}, [x10], #32
+        b               2b
+
+3:
+        subs            w4,  w4,  #2
+        b.le            9f
+        add             x0,  x0,  x1
+        add             x13, x13, x1
+        mov             w3,  w12
+        b               1b
+9:
+        ret
+
+169:
+        st1             {v31.8h}, [x0],  #16
+        subs            w3,  w3,  #8
+        st1             {v31.8h}, [x13], #16
+        b.gt            169b
+        subs            w4,  w4,  #2
+        b.le            9b
+        add             x0,  x0,  x1
+        add             x13, x13, x1
+        mov             w3,  w12
+        b               169b
+endfunc
+
+jumptable ipred_z1_fill1_tbl
+        .word 640b - ipred_z1_fill1_tbl
+        .word 320b - ipred_z1_fill1_tbl
+        .word 160b - ipred_z1_fill1_tbl
+        .word 80b  - ipred_z1_fill1_tbl
+        .word 40b  - ipred_z1_fill1_tbl
+endjumptable
+
+function ipred_z1_fill2_16bpc_neon, export=1
+        cmp             w3,  #8
+        add             x10, x2,  w6,  uxtw       // top[max_base_x]
+        ld1r            {v31.16b}, [x10]          // padding
+        mov             w7,  w5
+        mov             w15, #64
+        b.eq            8f
+
+4:      // w == 4
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            49f
+        lsl             w8,  w8,  #1
+        lsl             w10, w10, #1
+        ldr             q0,  [x2, w8, uxtw]       // top[base]
+        ldr             q2,  [x2, w10, uxtw]
+        dup             v4.4h,   w9               // frac
+        dup             v5.4h,   w11
+        uzp2            v1.8h,   v0.8h,   v0.8h   // top[base+1]
+        uzp1            v0.8h,   v0.8h,   v0.8h   // top[base]
+        uzp2            v3.8h,   v2.8h,   v2.8h
+        uzp1            v2.8h,   v2.8h,   v2.8h
+        sub             v6.4h,   v1.4h,   v0.4h   // top[base+1]-top[base]
+        sub             v7.4h,   v3.4h,   v2.4h
+        ushll           v16.4s,  v0.4h,   #6      // top[base]*64
+        ushll           v17.4s,  v2.4h,   #6
+        smlal           v16.4s,  v6.4h,   v4.4h   // + top[base+1]*frac
+        smlal           v17.4s,  v7.4h,   v5.4h
+        rshrn           v16.4h,  v16.4s,  #6
+        rshrn           v17.4h,  v17.4s,  #6
+        st1             {v16.4h}, [x0], x1
+        add             w7,  w7,  w5              // xpos += dx
+        subs            w4,  w4,  #2
+        st1             {v17.4h}, [x0], x1
+        b.gt            4b
+        ret
+
+49:
+        st1             {v31.4h}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v31.4h}, [x0], x1
+        b.gt            49b
+        ret
+
+8:      // w == 8
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            89f
+        add             x8,  x2,  w8,  uxtw #1
+        add             x10, x2,  w10, uxtw #1
+        dup             v4.8h,   w9               // frac
+        dup             v5.8h,   w11
+        ld1             {v0.8h, v1.8h},  [x8]     // top[base]
+        ld1             {v2.8h, v3.8h},  [x10]
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        dup             v6.8h,   w9               // 64 - frac
+        dup             v7.8h,   w11
+        uzp2            v20.8h,  v0.8h,   v1.8h   // top[base+1]
+        uzp1            v0.8h,   v0.8h,   v1.8h   // top[base]
+        uzp2            v21.8h,  v2.8h,   v3.8h
+        uzp1            v2.8h,   v2.8h,   v3.8h
+        umull           v16.4s,  v0.4h,   v6.4h   // top[base]*(64-frac)
+        umlal           v16.4s,  v20.4h,  v4.4h   // + top[base+1]*frac
+        umull2          v17.4s,  v0.8h,   v6.8h
+        umlal2          v17.4s,  v20.8h,  v4.8h
+        umull           v18.4s,  v2.4h,   v7.4h
+        umlal           v18.4s,  v21.4h,  v5.4h
+        umull2          v19.4s,  v2.8h,   v7.8h
+        umlal2          v19.4s,  v21.8h,  v5.8h
+        rshrn           v16.4h,  v16.4s,  #6
+        rshrn2          v16.8h,  v17.4s,  #6
+        rshrn           v17.4h,  v18.4s,  #6
+        rshrn2          v17.8h,  v19.4s,  #6
+        st1             {v16.8h}, [x0], x1
+        add             w7,  w7,  w5              // xpos += dx
+        subs            w4,  w4,  #2
+        st1             {v17.8h}, [x0], x1
+        b.gt            8b
+        ret
+
+89:
+        st1             {v31.8h}, [x0], x1
+        subs            w4,  w4,  #2
+        st1             {v31.8h}, [x0], x1
+        b.gt            89b
+        ret
+endfunc
+
+// void ipred_reverse_16bpc_neon(pixel *dst, const pixel *const src,
+//                               const int n);
+function ipred_reverse_16bpc_neon, export=1
+        sub             x1,  x1,  #16
+        add             x3,  x0,  #8
+        mov             x4,  #16
+1:
+        ld1             {v0.8h}, [x1]
+        subs            w2,  w2,  #8
+        rev64           v0.8h,  v0.8h
+        sub             x1,  x1,  #16
+        st1             {v0.d}[1], [x0], x4
+        st1             {v0.d}[0], [x3], x4
+        b.gt            1b
+        ret
+endfunc
+
+const increments
+        .short          0,  1,  2,  3,  4,  5,  6,  7
+endconst
+
+// void ipred_z2_fill1_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const top,
+//                                const pixel *const left,
+//                                const int width, const int height,
+//                                const int dx, const int dy);
+function ipred_z2_fill1_16bpc_neon, export=1
+        clz             w10, w4
+        movrel          x9,  ipred_z2_fill1_tbl
+        sub             w10, w10, #25
+        ldrsw           x10, [x9, w10, uxtw #2]
+        mov             w8,  #(1 << 6)            // xpos = 1 << 6
+        add             x9,  x9,  x10
+        sub             w8,  w8,  w6              // xpos -= dx
+
+        movrel          x11, increments
+        ld1             {v31.8h},  [x11]          // increments
+        neg             w7,  w7                   // -dy
+
+        br              x9
+40:
+        AARCH64_VALID_JUMP_TARGET
+
+        dup             v30.4h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.4h,  v31.4h,  v30.4h  // {0,1,2,3}* -dy
+        movi            v25.8h,  #0x3e
+        add             v30.4h,  v16.4h,  v30.4h  // -= dy
+
+        // Worst case height for w=4 is 16, but we need at least h+1 elements
+        ld1             {v0.8h, v1.8h, v2.8h}, [x3]    // left[]
+
+        movi            v26.8h,  #64
+        movi            v19.16b, #4
+
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v30.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v17.8b  // base_y = (ypos >> 6) + 1
+
+        movi            v23.4h,  #1, lsl #8
+        shl             v29.8b,  v29.8b,  #1      // 2*base_y
+        zip1            v29.8b,  v29.8b,  v29.8b  // duplicate elements
+        movi            v17.8b,  #2
+        add             v29.8b,  v29.8b,  v23.8b  // 2*base, 2*base+1, ...
+
+        add             v30.8b,  v29.8b,  v17.8b  // base_y + 1 (*2)
+        add             v28.8b,  v29.8b,  v19.8b  // base_y + 2 (*2)
+
+        tbl             v18.8b, {v0.16b}, v29.8b  // left[base_y]
+
+        trn1            v30.2d,  v30.2d,  v28.2d  // base_y + 1, base_y + 2
+
+        sub             v28.4h,  v26.4h,  v27.4h  // 64 - frac_y
+
+        trn1            v31.2d,  v31.2d,  v31.2d  // {0,1,2,3,0,1,2,3}
+
+        trn1            v27.2d,  v27.2d,  v27.2d  // frac_y
+        trn1            v28.2d,  v28.2d,  v28.2d  // 64 - frac_y
+
+        movi            v29.16b, #4
+4:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.4h,  w8               // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-4                  // base_x <= -4
+        asr             w11, w8,  #6              // base_x
+        b.le            49f
+
+        lsl             w9,  w9,  #1
+        lsl             w11, w11, #1
+
+        dup             v17.4h,  w8               // xpos
+
+        ldr             q4,  [x2, w9, sxtw]       // top[base_x]
+        ldr             q6,  [x2, w11, sxtw]
+
+        trn1            v16.2d,  v16.2d,  v17.2d  // xpos
+
+        // Cut corners here; only doing tbl over v0-v1 here; we only
+        // seem to need the last pixel, from v2, after skipping to the
+        // left-only codepath below.
+        tbl             v19.16b, {v0.16b, v1.16b}, v30.16b // left[base_y+1], left[base_y+2]
+
+        sshr            v20.8h,  v16.8h,  #6      // first base_x for each row
+
+        ext             v5.16b,  v4.16b,  v4.16b,  #2 // top[base_x+1]
+        ext             v7.16b,  v6.16b,  v6.16b,  #2
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+
+        trn1            v18.2d,  v18.2d,  v19.2d  // left[base_y], left[base_y+1]
+
+        trn1            v4.2d,   v4.2d,   v6.2d   // top[base_x]
+        trn1            v5.2d,   v5.2d,   v7.2d   // top[base_x+1]
+
+        sub             v17.8h,  v26.8h,  v16.8h  // 64 - frac_x
+
+        add             v20.8h,  v20.8h,  v31.8h  // actual base_x
+
+        umull           v21.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v21.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v22.4s,  v18.8h,  v28.8h
+        umlal2          v22.4s,  v19.8h,  v27.8h
+
+        umull           v23.4s,  v4.4h,   v17.4h  // top[base_x]-*(64-frac_x)
+        umlal           v23.4s,  v5.4h,   v16.4h  // + top[base_x+1]*frac_x
+        umull2          v24.4s,  v4.8h,   v17.8h
+        umlal2          v24.4s,  v5.8h,   v16.8h
+
+        cmge            v20.8h,  v20.8h,  #0
+
+        rshrn           v21.4h,  v21.4s,  #6
+        rshrn2          v21.8h,  v22.4s,  #6
+        rshrn           v22.4h,  v23.4s,  #6
+        rshrn2          v22.8h,  v24.4s,  #6
+
+        bit             v21.16b, v22.16b, v20.16b
+
+        st1             {v21.d}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v21.d}[1], [x0], x1
+        b.le            9f
+
+        ext             v18.16b, v19.16b, v19.16b, #8
+        add             v30.16b, v30.16b, v29.16b // base_y += 2 (*2)
+        b               4b
+
+49:
+        tbl             v19.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+1], left[base_y+2]
+
+        trn1            v18.2d,  v18.2d,  v19.2d  // left[base_y], left[base_y+1]
+
+        umull           v20.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v20.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v21.4s,  v18.8h,  v28.8h
+        umlal2          v21.4s,  v19.8h,  v27.8h
+
+        rshrn           v20.4h,  v20.4s,  #6
+        rshrn2          v20.8h,  v21.4s,  #6
+
+        st1             {v20.d}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v20.d}[1], [x0], x1
+        b.le            9f
+
+        ext             v18.16b, v19.16b, v19.16b, #8
+        add             v30.16b, v30.16b, v29.16b // base_y += 2 (*2)
+        b               49b
+
+9:
+        ret
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        dup             v18.8h,  w7               // -dy
+        add             x3,  x3,  #2              // Skip past left[0]
+
+        mul             v16.8h,  v31.8h,  v18.8h  // {0,1,2,3,4,5,6,7}* -dy
+        movi            v25.8h,  #0x3e
+        add             v16.8h,  v16.8h,  v18.8h  // -= dy
+
+        // Worst case height for w=8 is 32.
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x3] // left[]
+        ld1r            {v15.8h}, [x2]            // left[0] == top[0]
+
+        movi            v26.8h,  #64
+        movi            v19.16b, #4
+
+        shrn            v29.8b,  v16.8h,  #6      // ypos >> 6
+        and             v27.16b, v16.16b, v25.16b // frac_y
+
+        movi            v23.8h,  #1, lsl #8
+        shl             v29.8b,  v29.8b,  #1      // 2*base_y
+        mov             v18.16b, v15.16b          // left[0]
+        zip1            v29.16b, v29.16b, v29.16b // duplicate elements
+        movi            v17.16b, #2
+        add             v29.16b, v29.16b, v23.16b // 2*base, 2*base+1, ...
+
+        // Cut corners here; for the first row we don't expect to need to
+        // read outside of v0.
+        tbx             v18.16b, {v0.16b}, v29.16b // left[base_y]
+
+        add             v30.16b, v29.16b, v19.16b // base_y + 2 (*2)
+        add             v29.16b, v29.16b, v17.16b // base_y + 1 (*2)
+
+        sub             v28.8h,  v26.8h,  v27.8h  // 64 - frac_y
+
+        movi            v24.16b, #4
+8:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-16                 // base_x <= -16
+        asr             w11, w8,  #6              // base_x
+        b.le            89f
+
+        dup             v17.8h,   w8              // xpos
+
+        add             x9,  x2,  w9,  sxtw #1
+        add             x11, x2,  w11, sxtw #1
+
+        ld1             {v4.8h, v5.8h}, [x9]      // top[base_x]
+        mov             v19.16b, v15.16b          // left[0]
+        ld1             {v6.8h, v7.8h}, [x11]
+
+        tbx             v19.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+1]
+
+        mov             v20.16b, v15.16b          // left[0]
+
+        sshr            v21.8h,  v16.8h,  #6      // first base_x
+        sshr            v22.8h,  v17.8h,  #6
+
+        tbx             v20.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v30.16b // left[base_y+2]
+
+        ext             v5.16b,  v4.16b,  v5.16b,  #2 // top[base_x+1]
+        ext             v7.16b,  v6.16b,  v7.16b,  #2
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+        and             v17.16b, v17.16b, v25.16b
+
+        umull           v10.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v10.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+
+        sub             v8.8h,   v26.8h,  v16.8h  // 64 - frac_x
+        sub             v9.8h,   v26.8h,  v17.8h
+
+        umull2          v11.4s,  v18.8h,  v28.8h
+        umlal2          v11.4s,  v19.8h,  v27.8h
+
+        add             v21.8h,  v21.8h,  v31.8h  // actual base_x
+        add             v22.8h,  v22.8h,  v31.8h
+
+        umull           v12.4s,  v19.4h,  v28.4h
+        umlal           v12.4s,  v20.4h,  v27.4h
+        umull2          v13.4s,  v19.8h,  v28.8h
+        umlal2          v13.4s,  v20.8h,  v27.8h
+
+        rshrn           v10.4h,  v10.4s,  #6
+        rshrn2          v10.8h,  v11.4s,  #6
+        rshrn           v11.4h,  v12.4s,  #6
+        rshrn2          v11.8h,  v13.4s,  #6
+
+        umull           v12.4s,  v4.4h,   v8.4h   // top[base_x]-*(64-frac_x)
+        umlal           v12.4s,  v5.4h,   v16.4h  // + top[base_x+1]*frac_x
+        umull2          v13.4s,  v4.8h,   v8.8h
+        umlal2          v13.4s,  v5.8h,   v16.8h
+        umull           v14.4s,  v6.4h,   v9.4h
+        umlal           v14.4s,  v7.4h,   v17.4h
+        umull2          v18.4s,  v6.8h,   v9.8h
+        umlal2          v18.4s,  v7.8h,   v17.8h
+
+        cmge            v21.8h,  v21.8h,  #0
+        cmge            v22.8h,  v22.8h,  #0
+
+        rshrn           v12.4h,  v12.4s,  #6
+        rshrn2          v12.8h,  v13.4s,  #6
+        rshrn           v13.4h,  v14.4s,  #6
+        rshrn2          v13.8h,  v18.4s,  #6
+
+        bit             v10.16b, v12.16b, v21.16b
+        bit             v11.16b, v13.16b, v22.16b
+
+        st1             {v10.8h}, [x0], x1
+        subs            w5,  w5,  #2
+        sub             w8,  w8,  w6              // xpos -= dx
+        st1             {v11.8h}, [x0], x1
+        b.le            9f
+
+        mov             v18.16b, v20.16b
+        add             v29.16b, v29.16b, v24.16b // base_y += 2 (*2)
+        add             v30.16b, v30.16b, v24.16b // base_y += 2 (*2)
+        b               8b
+
+89:
+        mov             v19.16b, v15.16b
+        mov             v20.16b, v15.16b
+        tbx             v19.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+1]
+        tbx             v20.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v30.16b // left[base_y+2]
+
+        umull           v4.4s,   v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v4.4s,   v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v5.4s,   v18.8h,  v28.8h
+        umlal2          v5.4s,   v19.8h,  v27.8h
+        umull           v6.4s,   v19.4h,  v28.4h
+        umlal           v6.4s,   v20.4h,  v27.4h
+        umull2          v7.4s,   v19.8h,  v28.8h
+        umlal2          v7.4s,   v20.8h,  v27.8h
+
+        rshrn           v4.4h,   v4.4s,   #6
+        rshrn2          v4.8h,   v5.4s,   #6
+        rshrn           v5.4h,   v6.4s,   #6
+        rshrn2          v5.8h,   v7.4s,   #6
+
+        st1             {v4.8h}, [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v5.8h}, [x0], x1
+        b.le            9f
+
+        mov             v18.16b, v20.16b
+        add             v29.16b, v29.16b, v24.16b // base_y += 2 (*2)
+        add             v30.16b, v30.16b, v24.16b // base_y += 2 (*2)
+        b               89b
+
+9:
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        dup             v25.8h,  w7               // -dy
+        add             x3,  x3,  #2              // Skip past left[0]
+
+        add             x13, x0,  x1              // alternating row
+        lsl             x1,  x1,  #1              // stride *= 2
+        sub             x1,  x1,  w4,  uxtw #1    // stride -= width
+
+        movi            v11.8h,  #8
+        mul             v26.8h,  v31.8h,  v25.8h  // {0,1,2,3,4,5,6,7}* -dy
+        add             v26.8h,  v26.8h,  v25.8h  // -= dy
+        mul             v25.8h,  v25.8h,  v11.8h  // -8*dy
+
+        // Worst case height is 64, but we can only fit 32 pixels into
+        // v0-v3 usable within one tbx instruction. As long as base_y is
+        // up to 32, we use tbx.
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x3] // left[]
+        ld1r            {v15.8h}, [x2]            // left[0] == top[0]
+
+        mov             w12, w4                   // orig w
+        neg             w14, w4                   // -w
+
+1:
+        mov             v23.16b, v26.16b          // reset ypos
+
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  w14                  // base_x <= -2*w
+        asr             w11, w8,  #6              // base_x
+        b.le            169f
+
+        dup             v17.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+
+        add             x9,  x2,  w9,  sxtw #1
+        add             x11, x2,  w11, sxtw #1
+
+        sshr            v21.8h,  v16.8h,  #6      // first base_x
+        sshr            v22.8h,  v17.8h,  #6
+
+        ld1             {v4.8h}, [x9], #16        // top[base_x]
+        ld1             {v6.8h}, [x11], #16
+
+        movi            v10.8h,  #0x3e
+        movi            v11.8h,  #64
+
+        and             v16.16b, v16.16b, v10.16b // frac_x
+        and             v17.16b, v17.16b, v10.16b
+
+        sub             v8.8h,   v11.8h,  v16.8h  // 64 - frac_x
+        sub             v9.8h,   v11.8h,  v17.8h
+
+        add             v21.8h,  v21.8h,  v31.8h  // actual base_x
+        add             v22.8h,  v22.8h,  v31.8h
+
+2:
+        smov            w10,     v22.h[0]
+
+        shrn            v29.8b,  v23.8h,  #6      // ypos >> 6
+        movi            v12.8h,  #64
+        cmp             w10, #0                   // base_x (bottom left) >= 0
+        smov            w10,     v29.b[0]         // base_y[0]
+        movi            v10.8h,  #0x3e
+
+        b.ge            4f
+        and             v27.16b, v23.16b, v10.16b // frac_y
+        cmp             w10,     #(32-3)
+
+        mov             v18.16b, v15.16b          // left[0]
+        sub             v28.8h,  v12.8h,  v27.8h  // 64 - frac_y
+        b.gt            22f
+
+21:
+        // base_y < 32, using tbx
+        shl             v29.8b,  v29.8b,  #1      // 2*base_y
+        movi            v11.8h,  #1, lsl #8
+        zip1            v29.16b, v29.16b, v29.16b // duplicate elements
+        add             v29.16b, v29.16b, v11.16b // 2*base, 2*base+1, ...
+
+        movi            v13.16b, #2
+
+        tbx             v18.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y]
+
+        add             v29.16b, v29.16b, v13.16b // base_y + 1 (*2)
+        mov             v19.16b, v15.16b          // left[0]
+
+        tbx             v19.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+1]
+
+        add             v29.16b, v29.16b, v13.16b // base_y + 2 (*2)
+        mov             v20.16b, v15.16b          // left[0]
+
+        tbx             v20.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+2]
+
+        b               23f
+
+22:
+        // base_y >= 32, using separate loads.
+        smov            w15,     v29.b[1]
+        smov            w16,     v29.b[2]
+        add             x10, x3,  w10, sxtw #1
+        smov            w17,     v29.b[3]
+        add             x15, x3,  w15, sxtw #1
+        ld3             {v18.h, v19.h, v20.h}[0], [x10]
+        smov            w10,     v29.b[4]
+        add             x16, x3,  w16, sxtw #1
+        ld3             {v18.h, v19.h, v20.h}[1], [x15]
+        smov            w15,     v29.b[5]
+        add             x17, x3,  w17, sxtw #1
+        ld3             {v18.h, v19.h, v20.h}[2], [x16]
+        smov            w16,     v29.b[6]
+        add             x10, x3,  w10, sxtw #1
+        ld3             {v18.h, v19.h, v20.h}[3], [x17]
+        smov            w17,     v29.b[7]
+        add             x15, x3,  w15, sxtw #1
+        add             x16, x3,  w16, sxtw #1
+        ld3             {v18.h, v19.h, v20.h}[4], [x10]
+        add             x17, x3,  w17, sxtw #1
+        ld3             {v18.h, v19.h, v20.h}[5], [x15]
+        ld3             {v18.h, v19.h, v20.h}[6], [x16]
+        ld3             {v18.h, v19.h, v20.h}[7], [x17]
+
+23:
+
+        ld1             {v5.8h}, [x9], #16        // top[base_x]
+        ld1             {v7.8h}, [x11], #16
+
+        add             v23.8h,  v23.8h,  v25.8h  // ypos -= 8*dy
+
+        umull           v10.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v10.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v11.4s,  v18.8h,  v28.8h
+        umlal2          v11.4s,  v19.8h,  v27.8h
+        umull           v12.4s,  v19.4h,  v28.4h
+        umlal           v12.4s,  v20.4h,  v27.4h
+        umull2          v13.4s,  v19.8h,  v28.8h
+        umlal2          v13.4s,  v20.8h,  v27.8h
+
+        ext             v18.16b, v4.16b,  v5.16b,  #2 // top[base_x+1]
+        ext             v19.16b, v6.16b,  v7.16b,  #2
+
+        rshrn           v10.4h,  v10.4s,  #6
+        rshrn2          v10.8h,  v11.4s,  #6
+        rshrn           v11.4h,  v12.4s,  #6
+        rshrn2          v11.8h,  v13.4s,  #6
+
+        umull           v12.4s,  v4.4h,   v8.4h   // top[base_x]-*(64-frac_x)
+        umlal           v12.4s,  v18.4h,  v16.4h  // + top[base_x+1]*frac_x
+        umull2          v13.4s,  v4.8h,   v8.8h
+        umlal2          v13.4s,  v18.8h,  v16.8h
+        umull           v14.4s,  v6.4h,   v9.4h
+        umlal           v14.4s,  v19.4h,  v17.4h
+        umull2          v20.4s,  v6.8h,   v9.8h
+        umlal2          v20.4s,  v19.8h,  v17.8h
+
+        cmge            v18.8h,  v21.8h,  #0
+        cmge            v19.8h,  v22.8h,  #0
+
+        rshrn           v12.4h,  v12.4s,  #6
+        rshrn2          v12.8h,  v13.4s,  #6
+        rshrn           v13.4h,  v14.4s,  #6
+        rshrn2          v13.8h,  v20.4s,  #6
+
+        bit             v10.16b, v12.16b, v18.16b
+        bit             v11.16b, v13.16b, v19.16b
+
+        st1             {v10.8h}, [x0], #16
+        subs            w4,  w4,  #8
+        st1             {v11.8h}, [x13], #16
+        b.le            3f
+
+        movi            v10.8h,  #8
+        mov             v4.16b,  v5.16b
+        mov             v6.16b,  v7.16b
+        add             v21.8h,  v21.8h,  v10.8h  // base_x += 8
+        add             v22.8h,  v22.8h,  v10.8h
+        b               2b
+
+3:
+        subs            w5,  w5,  #2
+        b.le            9f
+        movi            v10.8h, #128
+        add             x0,  x0,  x1
+        add             x13, x13, x1
+        mov             w4,  w12                  // reset w
+        add             v26.8h,  v26.8h,  v10.8h  // ypos += 2*(1<<6)
+        b               1b
+
+4:      // The rest of the row only predicted from top[]
+        ld1             {v5.8h}, [x9], #16        // top[base_x]
+        ld1             {v7.8h}, [x11], #16
+
+        ext             v18.16b, v4.16b,  v5.16b,  #2 // top[base_x+1]
+        ext             v19.16b, v6.16b,  v7.16b,  #2
+
+        umull           v12.4s,  v4.4h,   v8.4h   // top[base_x]-*(64-frac_x)
+        umlal           v12.4s,  v18.4h,  v16.4h  // + top[base_x+1]*frac_x
+        umull2          v13.4s,  v4.8h,   v8.8h
+        umlal2          v13.4s,  v18.8h,  v16.8h
+        umull           v14.4s,  v6.4h,   v9.4h
+        umlal           v14.4s,  v19.4h,  v17.4h
+        umull2          v20.4s,  v6.8h,   v9.8h
+        umlal2          v20.4s,  v19.8h,  v17.8h
+
+        rshrn           v12.4h,  v12.4s,  #6
+        rshrn2          v12.8h,  v13.4s,  #6
+        rshrn           v13.4h,  v14.4s,  #6
+        rshrn2          v13.8h,  v20.4s,  #6
+
+        st1             {v12.8h}, [x0], #16
+        subs            w4,  w4,  #8
+        st1             {v13.8h}, [x13], #16
+        b.le            3b
+
+        mov             v4.16b,  v5.16b
+        mov             v6.16b,  v7.16b
+        b               4b
+
+169:    // The rest of the block only predicted from left[]
+        add             x1,  x1,  w4,  uxtw #1    // restore stride
+        mov             w12, w5                   // orig remaining h
+1:
+        movi            v12.8h,  #64
+        movi            v10.8h,  #0x3e
+
+        shrn            v29.8b,  v23.8h,  #6      // ypos >> 6
+        and             v27.16b, v23.16b, v10.16b // frac_y
+
+        smov            w10,     v29.b[0]         // base_y[0]
+
+        shl             v29.8b,  v29.8b,  #1      // 2*base_y
+        movi            v11.8h,  #1, lsl #8
+        zip1            v29.16b, v29.16b, v29.16b // duplicate elements
+        add             v23.8h,  v23.8h,  v25.8h  // ypos -= 8*dy
+        add             v29.16b, v29.16b, v11.16b // 2*base, 2*base+1, ...
+
+        cmp             w10,     #(32-1)
+
+        mov             v18.16b, v15.16b          // left[0]
+        movi            v21.16b, #2
+
+        sub             v28.8h,  v12.8h,  v27.8h  // 64 - frac_y
+
+        b.gt            31f
+
+        tbx             v18.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y]
+        add             v29.16b, v29.16b, v21.16b // base_y + 1 (*2)
+
+2:
+        // base_y < 32, using tbx.
+        smov            w10,     v29.b[0]         // base_y[0]
+        mov             v19.16b, v15.16b          // left[0]
+        cmp             w10,     #(64-4)
+        b.gt            32f
+        tbx             v19.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+1]
+        add             v29.16b, v29.16b, v21.16b // base_y + 2 (*2)
+        mov             v20.16b, v15.16b          // left[0]
+        tbx             v20.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v29.16b // left[base_y+2]
+        add             v29.16b, v29.16b, v21.16b // next base_y
+
+        umull           v10.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v10.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v11.4s,  v18.8h,  v28.8h
+        umlal2          v11.4s,  v19.8h,  v27.8h
+        umull           v12.4s,  v19.4h,  v28.4h
+        umlal           v12.4s,  v20.4h,  v27.4h
+        umull2          v13.4s,  v19.8h,  v28.8h
+        umlal2          v13.4s,  v20.8h,  v27.8h
+
+        rshrn           v10.4h,  v10.4s,  #6
+        rshrn2          v10.8h,  v11.4s,  #6
+        rshrn           v11.4h,  v12.4s,  #6
+        rshrn2          v11.8h,  v13.4s,  #6
+
+        st1             {v10.8h}, [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v11.8h}, [x13], x1
+        b.le            4f
+        mov             v18.16b, v20.16b
+        b               2b
+
+31:     // base_y >= 32, using separate loads, loading v18 if we had to bail
+        // in the prologue.
+        smov            w10,     v29.b[0]
+        smov            w15,     v29.b[2]
+        movi            v21.16b, #2
+        smov            w16,     v29.b[4]
+        add             x10, x3,  w10, sxtw
+        smov            w17,     v29.b[6]
+        add             x15, x3,  w15, sxtw
+        ld1             {v18.h}[0], [x10]
+        smov            w10,     v29.b[8]
+        add             x16, x3,  w16, sxtw
+        ld1             {v18.h}[1], [x15]
+        smov            w15,     v29.b[10]
+        add             x17, x3,  w17, sxtw
+        ld1             {v18.h}[2], [x16]
+        smov            w16,     v29.b[12]
+        add             x10, x3,  w10, sxtw
+        ld1             {v18.h}[3], [x17]
+        smov            w17,     v29.b[14]
+        add             x15, x3,  w15, sxtw
+        add             x16, x3,  w16, sxtw
+        ld1             {v18.h}[4], [x10]
+        add             x17, x3,  w17, sxtw
+        ld1             {v18.h}[5], [x15]
+        add             v29.16b, v29.16b, v21.16b // next base_y
+        ld1             {v18.h}[6], [x16]
+        ld1             {v18.h}[7], [x17]
+
+32:     // base_y >= 32, using separate loads.
+        cmp             w5,  #4
+        b.lt            34f
+33:     // h >= 4, preserving v18 from the previous round, loading v19-v22.
+        smov            w10,     v29.b[0]
+        subs            w5,  w5,  #4
+        smov            w15,     v29.b[2]
+        movi            v10.16b, #8
+        smov            w16,     v29.b[4]
+        add             x10, x3,  w10, sxtw
+        smov            w17,     v29.b[6]
+        add             x15, x3,  w15, sxtw
+        ld4             {v19.h, v20.h, v21.h, v22.h}[0], [x10]
+        smov            w10,     v29.b[8]
+        add             x16, x3,  w16, sxtw
+        ld4             {v19.h, v20.h, v21.h, v22.h}[1], [x15]
+        smov            w15,     v29.b[10]
+        add             x17, x3,  w17, sxtw
+        ld4             {v19.h, v20.h, v21.h, v22.h}[2], [x16]
+        smov            w16,     v29.b[12]
+        add             x10, x3,  w10, sxtw
+        ld4             {v19.h, v20.h, v21.h, v22.h}[3], [x17]
+        smov            w17,     v29.b[14]
+        add             x15, x3,  w15, sxtw
+        add             x16, x3,  w16, sxtw
+        ld4             {v19.h, v20.h, v21.h, v22.h}[4], [x10]
+        add             x17, x3,  w17, sxtw
+        ld4             {v19.h, v20.h, v21.h, v22.h}[5], [x15]
+        ld4             {v19.h, v20.h, v21.h, v22.h}[6], [x16]
+        add             v29.16b, v29.16b, v10.16b // next base_y
+        ld4             {v19.h, v20.h, v21.h, v22.h}[7], [x17]
+
+        umull           v10.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v10.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v11.4s,  v18.8h,  v28.8h
+        umlal2          v11.4s,  v19.8h,  v27.8h
+        umull           v12.4s,  v19.4h,  v28.4h
+        umlal           v12.4s,  v20.4h,  v27.4h
+        umull2          v13.4s,  v19.8h,  v28.8h
+        umlal2          v13.4s,  v20.8h,  v27.8h
+
+        rshrn           v10.4h,  v10.4s,  #6
+        rshrn2          v10.8h,  v11.4s,  #6
+        rshrn           v11.4h,  v12.4s,  #6
+        rshrn2          v11.8h,  v13.4s,  #6
+
+        umull           v12.4s,  v20.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v12.4s,  v21.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v13.4s,  v20.8h,  v28.8h
+        umlal2          v13.4s,  v21.8h,  v27.8h
+        umull           v14.4s,  v21.4h,  v28.4h
+        umlal           v14.4s,  v22.4h,  v27.4h
+        umull2          v18.4s,  v21.8h,  v28.8h
+        umlal2          v18.4s,  v22.8h,  v27.8h
+
+        rshrn           v12.4h,  v12.4s,  #6
+        rshrn2          v12.8h,  v13.4s,  #6
+        rshrn           v13.4h,  v14.4s,  #6
+        rshrn2          v13.8h,  v18.4s,  #6
+
+        st1             {v10.8h}, [x0],  x1
+        cmp             w5,  #2
+        st1             {v11.8h}, [x13], x1
+        st1             {v12.8h}, [x0],  x1
+        st1             {v13.8h}, [x13], x1
+        b.lt            4f
+        mov             v18.16b, v22.16b
+        b.gt            33b
+
+34:     // h == 2, preserving v18 from the previous round, loading v19-v20.
+        smov            w10,     v29.b[0]
+        smov            w15,     v29.b[2]
+        movi            v21.16b, #4
+        smov            w16,     v29.b[4]
+        add             x10, x3,  w10, sxtw
+        smov            w17,     v29.b[6]
+        add             x15, x3,  w15, sxtw
+        ld2             {v19.h, v20.h}[0], [x10]
+        smov            w10,     v29.b[8]
+        add             x16, x3,  w16, sxtw
+        ld2             {v19.h, v20.h}[1], [x15]
+        smov            w15,     v29.b[10]
+        add             x17, x3,  w17, sxtw
+        ld2             {v19.h, v20.h}[2], [x16]
+        smov            w16,     v29.b[12]
+        add             x10, x3,  w10, sxtw
+        ld2             {v19.h, v20.h}[3], [x17]
+        smov            w17,     v29.b[14]
+        add             x15, x3,  w15, sxtw
+        add             x16, x3,  w16, sxtw
+        ld2             {v19.h, v20.h}[4], [x10]
+        add             x17, x3,  w17, sxtw
+        ld2             {v19.h, v20.h}[5], [x15]
+        ld2             {v19.h, v20.h}[6], [x16]
+        add             v29.16b, v29.16b, v21.16b // next base_y
+        ld2             {v19.h, v20.h}[7], [x17]
+
+        umull           v10.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v10.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v11.4s,  v18.8h,  v28.8h
+        umlal2          v11.4s,  v19.8h,  v27.8h
+        umull           v12.4s,  v19.4h,  v28.4h
+        umlal           v12.4s,  v20.4h,  v27.4h
+        umull2          v13.4s,  v19.8h,  v28.8h
+        umlal2          v13.4s,  v20.8h,  v27.8h
+
+        rshrn           v10.4h,  v10.4s,  #6
+        rshrn2          v10.8h,  v11.4s,  #6
+        rshrn           v11.4h,  v12.4s,  #6
+        rshrn2          v11.8h,  v13.4s,  #6
+
+        st1             {v10.8h}, [x0], x1
+        st1             {v11.8h}, [x13], x1
+        // The h==2 case only happens once at the end, if at all.
+
+4:
+        subs            w4,  w4,  #8
+        b.le            9f
+
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #16
+        add             x13, x13, #16
+        mov             w5,  w12                  // reset h
+        b               1b
+
+9:
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+endfunc
+
+jumptable ipred_z2_fill1_tbl
+        .word 640b - ipred_z2_fill1_tbl
+        .word 320b - ipred_z2_fill1_tbl
+        .word 160b - ipred_z2_fill1_tbl
+        .word 80b  - ipred_z2_fill1_tbl
+        .word 40b  - ipred_z2_fill1_tbl
+endjumptable
+
+function ipred_z2_fill2_16bpc_neon, export=1
+        cmp             w4,  #8
+        mov             w8,  #(2 << 6)            // xpos = 2 << 6
+        sub             w8,  w8,  w6              // xpos -= dx
+
+        movrel          x11, increments
+        ld1             {v31.8h},  [x11]          // increments
+        neg             w7,  w7                   // -dy
+        b.eq            80f
+
+40:
+        dup             v30.4h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.4h,  v31.4h,  v30.4h  // {0,1,2,3}* -dy
+        movi            v25.8h,  #0x3e
+        add             v30.4h,  v16.4h,  v30.4h  // -= dy
+
+        // For upsample_top, w <= 8 and h <= 8; we may need up to h+1 elements
+        // from left.
+        ld1             {v0.8h, v1.8h}, [x3]      // left[]
+
+        movi            v26.8h,  #64
+        movi            v19.16b, #4
+
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v30.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v17.8b  // base_y = (ypos >> 6) + 1
+
+        movi            v23.4h,  #1, lsl #8
+        shl             v29.8b,  v29.8b,  #1      // 2*base_y
+        zip1            v29.8b,  v29.8b,  v29.8b  // duplicate elements
+        movi            v17.8b,  #2
+        add             v29.8b,  v29.8b,  v23.8b  // 2*base, 2*base+1, ...
+
+        add             v30.8b,  v29.8b,  v17.8b  // base_y + 1 (*2)
+        add             v28.8b,  v29.8b,  v19.8b  // base_y + 2 (*2)
+
+        tbl             v18.8b, {v0.16b}, v29.8b  // left[base_y]
+
+        trn1            v30.2d,  v30.2d,  v28.2d  // base_y + 1, base_y + 2
+
+        sub             v28.4h,  v26.4h,  v27.4h  // 64 - frac_y
+
+        trn1            v31.2d,  v31.2d,  v31.2d  // {0,1,2,3,0,1,2,3}
+
+        trn1            v27.2d,  v27.2d,  v27.2d  // frac_y
+        trn1            v28.2d,  v28.2d,  v28.2d  // 64 - frac_y
+
+        movi            v29.16b, #4
+        add             v31.8h,  v31.8h,  v31.8h  // {0,2,4,6,0,2,4,6}
+4:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.4h,  w8               // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-8                  // base_x <= -8
+        asr             w11, w8,  #6              // base_x
+        b.le            49f
+
+        lsl             w9,  w9,  #1
+        lsl             w11, w11, #1
+
+        dup             v17.4h,  w8               // xpos
+
+        ldr             q4,  [x2, w9, sxtw]       // top[base_x]
+        ldr             q6,  [x2, w11, sxtw]
+
+        trn1            v16.2d,  v16.2d,  v17.2d  // xpos
+
+        tbl             v19.16b, {v0.16b, v1.16b}, v30.16b // left[base_y+1], left[base_y+2]
+
+        sshr            v20.8h,  v16.8h,  #6      // first base_x for each row
+
+        uzp2            v5.8h,   v4.8h,   v6.8h   // top[base_x+1]
+        uzp1            v4.8h,   v4.8h,   v6.8h   // top[base_x]
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+
+        trn1            v18.2d,  v18.2d,  v19.2d  // left[base_y], left[base_y+1]
+
+        sub             v17.8h,  v26.8h,  v16.8h  // 64 - frac_x
+
+        add             v20.8h,  v20.8h,  v31.8h  // actual base_x
+
+        umull           v21.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v21.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v22.4s,  v18.8h,  v28.8h
+        umlal2          v22.4s,  v19.8h,  v27.8h
+
+        umull           v23.4s,  v4.4h,   v17.4h  // top[base_x]-*(64-frac_x)
+        umlal           v23.4s,  v5.4h,   v16.4h  // + top[base_x+1]*frac_x
+        umull2          v24.4s,  v4.8h,   v17.8h
+        umlal2          v24.4s,  v5.8h,   v16.8h
+
+        cmge            v20.8h,  v20.8h,  #0
+
+        rshrn           v21.4h,  v21.4s,  #6
+        rshrn2          v21.8h,  v22.4s,  #6
+        rshrn           v22.4h,  v23.4s,  #6
+        rshrn2          v22.8h,  v24.4s,  #6
+
+        bit             v21.16b, v22.16b, v20.16b
+
+        st1             {v21.d}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v21.d}[1], [x0], x1
+        b.le            9f
+
+        ext             v18.16b, v19.16b, v19.16b, #8
+        add             v30.16b, v30.16b, v29.16b // base_y += 2 (*2)
+        b               4b
+
+49:
+        tbl             v19.16b, {v0.16b, v1.16b}, v30.16b // left[base_y+1], left[base_y+2]
+
+        trn1            v18.2d,  v18.2d,  v19.2d  // left[base_y], left[base_y+1]
+
+        umull           v20.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v20.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v21.4s,  v18.8h,  v28.8h
+        umlal2          v21.4s,  v19.8h,  v27.8h
+
+        rshrn           v20.4h,  v20.4s,  #6
+        rshrn2          v20.8h,  v21.4s,  #6
+
+        st1             {v20.d}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v20.d}[1], [x0], x1
+        b.le            9f
+
+        ext             v18.16b, v19.16b, v19.16b, #8
+        add             v30.16b, v30.16b, v29.16b // base_y += 2 (*2)
+        b               49b
+
+9:
+        ret
+
+80:
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        dup             v18.8h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.8h,  v31.8h,  v18.8h  // {0,1,2,3,4,5,6,7}* -dy
+        movi            v25.8h,  #0x3e
+        add             v16.8h,  v16.8h,  v18.8h  // -= dy
+
+        // For upsample_top, w <= 8 and h <= 8; we may need up to h+1 elements
+        // from left.
+        ld1             {v0.8h, v1.8h}, [x3]      // left[]
+
+        movi            v26.8h,  #64
+        movi            v19.16b, #4
+
+        shrn            v29.8b,  v16.8h,  #6      // ypos >> 6
+        and             v27.16b, v16.16b, v25.16b // frac_y
+
+        add             v29.8b,  v29.8b,  v17.8b  // base_y = (ypos >> 6) + 1
+
+        movi            v23.8h,  #1, lsl #8
+        shl             v29.8b,  v29.8b,  #1      // 2*base_y
+        zip1            v29.16b, v29.16b, v29.16b // duplicate elements
+        movi            v17.16b, #2
+        add             v29.16b, v29.16b, v23.16b // 2*base, 2*base+1, ...
+
+        // Cut corners here; for the first row we don't expect to need to
+        // read outside of v0.
+        tbl             v18.16b, {v0.16b}, v29.16b // left[base_y]
+
+        add             v30.16b, v29.16b, v19.16b // base_y + 2 (*2)
+        add             v29.16b, v29.16b, v17.16b // base_y + 1 (*2)
+
+        sub             v28.8h,  v26.8h,  v27.8h  // 64 - frac_y
+
+        movi            v24.16b, #4
+        add             v31.16b, v31.16b, v31.16b // {0,2,4,6,8,10,12,14,0,2,4,6,8,10,12,14}
+8:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-16                 // base_x <= -16
+        asr             w11, w8,  #6              // base_x
+        b.le            89f
+
+        dup             v17.8h,   w8              // xpos
+
+        add             x9,  x2,  w9,  sxtw #1
+        add             x11, x2,  w11, sxtw #1
+
+        ld1             {v4.8h, v5.8h}, [x9]      // top[base_x]
+        ld1             {v6.8h, v7.8h}, [x11]
+
+        tbl             v19.16b, {v0.16b, v1.16b}, v29.16b // left[base_y+1]
+
+        sshr            v21.8h,  v16.8h,  #6      // first base_x
+        sshr            v22.8h,  v17.8h,  #6
+
+        tbl             v20.16b, {v0.16b, v1.16b}, v30.16b // left[base_y+2]
+
+        uzp2            v2.8h,   v4.8h,   v5.8h   // top[base_x+1]
+        uzp1            v4.8h,   v4.8h,   v5.8h   // top[base_x]
+        uzp2            v3.8h,   v6.8h,   v7.8h
+        uzp1            v6.8h,   v6.8h,   v7.8h
+        mov             v5.16b,  v2.16b
+        mov             v7.16b,  v3.16b
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+        and             v17.16b, v17.16b, v25.16b
+
+        umull           v10.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v10.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+
+        sub             v8.8h,   v26.8h,  v16.8h  // 64 - frac_x
+        sub             v9.8h,   v26.8h,  v17.8h
+
+        umull2          v11.4s,  v18.8h,  v28.8h
+        umlal2          v11.4s,  v19.8h,  v27.8h
+
+        add             v21.8h,  v21.8h,  v31.8h  // actual base_x
+        add             v22.8h,  v22.8h,  v31.8h
+
+        umull           v12.4s,  v19.4h,  v28.4h
+        umlal           v12.4s,  v20.4h,  v27.4h
+        umull2          v13.4s,  v19.8h,  v28.8h
+        umlal2          v13.4s,  v20.8h,  v27.8h
+
+        rshrn           v10.4h,  v10.4s,  #6
+        rshrn2          v10.8h,  v11.4s,  #6
+        rshrn           v11.4h,  v12.4s,  #6
+        rshrn2          v11.8h,  v13.4s,  #6
+
+        umull           v12.4s,  v4.4h,   v8.4h   // top[base_x]-*(64-frac_x)
+        umlal           v12.4s,  v5.4h,   v16.4h  // + top[base_x+1]*frac_x
+        umull2          v13.4s,  v4.8h,   v8.8h
+        umlal2          v13.4s,  v5.8h,   v16.8h
+        umull           v14.4s,  v6.4h,   v9.4h
+        umlal           v14.4s,  v7.4h,   v17.4h
+        umull2          v18.4s,  v6.8h,   v9.8h
+        umlal2          v18.4s,  v7.8h,   v17.8h
+
+        cmge            v21.8h,  v21.8h,  #0
+        cmge            v22.8h,  v22.8h,  #0
+
+        rshrn           v12.4h,  v12.4s,  #6
+        rshrn2          v12.8h,  v13.4s,  #6
+        rshrn           v13.4h,  v14.4s,  #6
+        rshrn2          v13.8h,  v18.4s,  #6
+
+        bit             v10.16b, v12.16b, v21.16b
+        bit             v11.16b, v13.16b, v22.16b
+
+        st1             {v10.8h}, [x0], x1
+        subs            w5,  w5,  #2
+        sub             w8,  w8,  w6              // xpos -= dx
+        st1             {v11.8h}, [x0], x1
+        b.le            9f
+
+        mov             v18.16b, v20.16b
+        add             v29.16b, v29.16b, v24.16b // base_y += 2 (*2)
+        add             v30.16b, v30.16b, v24.16b // base_y += 2 (*2)
+        b               8b
+
+89:
+        tbl             v19.16b, {v0.16b, v1.16b}, v29.16b // left[base_y+1]
+        tbl             v20.16b, {v0.16b, v1.16b}, v30.16b // left[base_y+2]
+
+        umull           v4.4s,   v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v4.4s,   v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v5.4s,   v18.8h,  v28.8h
+        umlal2          v5.4s,   v19.8h,  v27.8h
+        umull           v6.4s,   v19.4h,  v28.4h
+        umlal           v6.4s,   v20.4h,  v27.4h
+        umull2          v7.4s,   v19.8h,  v28.8h
+        umlal2          v7.4s,   v20.8h,  v27.8h
+
+        rshrn           v4.4h,   v4.4s,   #6
+        rshrn2          v4.8h,   v5.4s,   #6
+        rshrn           v5.4h,   v6.4s,   #6
+        rshrn2          v5.8h,   v7.4s,   #6
+
+        st1             {v4.8h}, [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v5.8h}, [x0], x1
+        b.le            9f
+
+        mov             v18.16b, v20.16b
+        add             v29.16b, v29.16b, v24.16b // base_y += 2 (*2)
+        add             v30.16b, v30.16b, v24.16b // base_y += 2 (*2)
+        b               89b
+
+9:
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+endfunc
+
+function ipred_z2_fill3_16bpc_neon, export=1
+        cmp             w4,  #8
+        mov             w8,  #(1 << 6)            // xpos = 1 << 6
+        sub             w8,  w8,  w6              // xpos -= dx
+
+        movrel          x11, increments
+        ld1             {v31.8h},  [x11]          // increments
+        neg             w7,  w7                   // -dy
+        b.eq            80f
+
+40:
+        dup             v30.4h,  w7               // -dy
+        movi            v17.8b,  #1
+
+        mul             v16.4h,  v31.4h,  v30.4h  // {0,1,2,3}* -dy
+        movi            v25.8h,  #0x3e
+        add             v30.4h,  v16.4h,  v30.4h  // -= dy
+
+        // For upsample_left, w <= 8 and h <= 8; we may need up to 2*h+1 elements.
+        ld1             {v0.8h, v1.8h, v2.8h}, [x3]    // left[]
+
+        movi            v26.8h,  #64
+        movi            v19.16b, #2
+
+        shrn            v29.8b,  v30.8h,  #6      // ypos >> 6
+        and             v27.8b,  v30.8b,  v25.8b  // frac_y
+
+        add             v29.8b,  v29.8b,  v19.8b  // base_y = (ypos >> 6) + 2
+
+        movi            v23.4h,  #1, lsl #8
+        shl             v29.8b,  v29.8b,  #1      // 2*base_y
+        movi            v19.16b, #4
+        zip1            v29.8b,  v29.8b,  v29.8b  // duplicate elements
+        movi            v17.8b,  #2
+        add             v29.8b,  v29.8b,  v23.8b  // 2*base, 2*base+1, ...
+
+        add             v30.8b,  v29.8b,  v17.8b  // base_y + 1 (*2)
+        add             v28.8b,  v29.8b,  v19.8b  // base_y + 2 (*2)
+
+        trn1            v31.2d,  v31.2d,  v31.2d  // {0,1,2,3,0,1,2,3}
+
+        add             v24.8b,  v30.8b,  v19.8b  // base_y + 3 (*2)
+
+        trn1            v29.2d,  v29.2d,  v28.2d  // base_y + 0, base_y + 2
+        trn1            v30.2d,  v30.2d,  v24.2d  // base_y + 1, base_y + 3
+
+        sub             v28.4h,  v26.4h,  v27.4h  // 64 - frac_y
+
+        trn1            v27.2d,  v27.2d,  v27.2d  // frac_y
+        trn1            v28.2d,  v28.2d,  v28.2d  // 64 - frac_y
+
+        movi            v24.16b, #8
+4:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.4h,  w8               // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-4                  // base_x <= -4
+        asr             w11, w8,  #6              // base_x
+        b.le            49f
+
+        lsl             w9,  w9,  #1
+        lsl             w11, w11, #1
+
+        dup             v17.4h,  w8               // xpos
+
+        ldr             q4,  [x2, w9, sxtw]       // top[base_x]
+        ldr             q6,  [x2, w11, sxtw]
+
+        trn1            v16.2d,  v16.2d,  v17.2d  // xpos
+
+        tbl             v18.16b, {v0.16b, v1.16b, v2.16b}, v29.16b // left[base_y+0], left[base_y+2]
+        tbl             v19.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+1], left[base_y+3]
+
+        sshr            v20.8h,  v16.8h,  #6      // first base_x for each row
+
+        ext             v5.16b,  v4.16b,  v4.16b,  #2 // top[base_x+1]
+        ext             v7.16b,  v6.16b,  v6.16b,  #2
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+
+        trn1            v4.2d,   v4.2d,   v6.2d   // top[base_x]
+        trn1            v5.2d,   v5.2d,   v7.2d   // top[base_x+1]
+
+        sub             v17.8h,  v26.8h,  v16.8h  // 64 - frac_x
+
+        add             v20.8h,  v20.8h,  v31.8h  // actual base_x
+
+        umull           v21.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v21.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v22.4s,  v18.8h,  v28.8h
+        umlal2          v22.4s,  v19.8h,  v27.8h
+
+        umull           v23.4s,  v4.4h,   v17.4h  // top[base_x]-*(64-frac_x)
+        umlal           v23.4s,  v5.4h,   v16.4h  // + top[base_x+1]*frac_x
+        umull2          v24.4s,  v4.8h,   v17.8h
+        umlal2          v24.4s,  v5.8h,   v16.8h
+
+        cmge            v20.8h,  v20.8h,  #0
+
+        rshrn           v21.4h,  v21.4s,  #6
+        rshrn2          v21.8h,  v22.4s,  #6
+        rshrn           v22.4h,  v23.4s,  #6
+        rshrn2          v22.8h,  v24.4s,  #6
+
+        movi            v24.16b, #8
+
+        bit             v21.16b, v22.16b, v20.16b
+
+        st1             {v21.d}[0], [x0], x1
+        sub             w8,  w8,  w6              // xpos -= dx
+        subs            w5,  w5,  #2
+        st1             {v21.d}[1], [x0], x1
+        b.le            9f
+
+        add             v29.16b, v29.16b, v24.16b // base_y += 4 (*2)
+        add             v30.16b, v30.16b, v24.16b // base_y += 4 (*2)
+        b               4b
+
+49:
+        tbl             v18.16b, {v0.16b, v1.16b, v2.16b}, v29.16b // left[base_y+0], left[base_y+2]
+        tbl             v19.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+1], left[base_y+3]
+
+        umull           v20.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v20.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v21.4s,  v18.8h,  v28.8h
+        umlal2          v21.4s,  v19.8h,  v27.8h
+
+        rshrn           v20.4h,  v20.4s,  #6
+        rshrn2          v20.8h,  v21.4s,  #6
+
+        st1             {v20.d}[0], [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v20.d}[1], [x0], x1
+        b.le            9f
+
+        add             v29.16b, v29.16b, v24.16b // base_y += 4 (*2)
+        add             v30.16b, v30.16b, v24.16b // base_y += 4 (*2)
+        b               49b
+
+9:
+        ret
+
+80:
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        dup             v18.8h,  w7               // -dy
+        movi            v17.16b, #2
+
+        mul             v16.8h,  v31.8h,  v18.8h  // {0,1,2,3,4,5,6,7}* -dy
+        movi            v25.8h,  #0x3e
+        add             v16.8h,  v16.8h,  v18.8h  // -= dy
+
+        // For upsample_left, w <= 8 and h <= 8; we may need up to 2*h+1 elements.
+        ld1             {v0.8h, v1.8h, v2.8h}, [x3]    // left[]
+
+        movi            v26.8h,  #64
+        movi            v19.16b, #4
+
+        shrn            v29.8b,  v16.8h,  #6      // ypos >> 6
+        and             v27.16b, v16.16b, v25.16b // frac_y
+
+        add             v29.8b,  v29.8b,  v17.8b  // base_y = (ypos >> 6) + 2
+
+        movi            v23.8h,  #1, lsl #8
+        shl             v29.8b,  v29.8b,  #1      // 2*base_y
+        mov             v18.16b, v15.16b          // left[0]
+        zip1            v29.16b, v29.16b, v29.16b // duplicate elements
+        add             v29.16b, v29.16b, v23.16b // 2*base, 2*base+1, ...
+
+        add             v30.16b, v29.16b, v17.16b // base_y + 1 (*2)
+
+        sub             v28.8h,  v26.8h,  v27.8h  // 64 - frac_y
+
+        movi            v24.16b, #4
+8:
+        asr             w9,  w8,  #6              // base_x
+        dup             v16.8h,   w8              // xpos
+        sub             w8,  w8,  w6              // xpos -= dx
+        cmp             w9,  #-16                 // base_x <= -16
+        asr             w11, w8,  #6              // base_x
+        b.le            89f
+
+        dup             v17.8h,   w8              // xpos
+
+        add             x9,  x2,  w9,  sxtw #1
+        add             x11, x2,  w11, sxtw #1
+
+        ld1             {v4.8h, v5.8h}, [x9]      // top[base_x]
+        ld1             {v6.8h, v7.8h}, [x11]
+
+        tbl             v18.16b, {v0.16b, v1.16b, v2.16b}, v29.16b // left[base_y+0]
+        add             v29.16b, v29.16b, v24.16b // base_y += 2 (*2)
+        tbl             v19.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+1]
+        add             v30.16b, v30.16b, v24.16b
+
+        sshr            v22.8h,  v16.8h,  #6      // first base_x
+        tbl             v20.16b, {v0.16b, v1.16b, v2.16b}, v29.16b // left[base_y+2]
+        sshr            v23.8h,  v17.8h,  #6
+        tbl             v21.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+3]
+
+        ext             v5.16b,  v4.16b,  v5.16b,  #2 // top[base_x+1]
+        ext             v7.16b,  v6.16b,  v7.16b,  #2
+
+        and             v16.16b, v16.16b, v25.16b // frac_x
+        and             v17.16b, v17.16b, v25.16b
+
+        umull           v10.4s,  v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v10.4s,  v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+
+        sub             v8.8h,   v26.8h,  v16.8h  // 64 - frac_x
+        sub             v9.8h,   v26.8h,  v17.8h
+
+        umull2          v11.4s,  v18.8h,  v28.8h
+        umlal2          v11.4s,  v19.8h,  v27.8h
+
+        add             v22.8h,  v22.8h,  v31.8h  // actual base_x
+        add             v23.8h,  v23.8h,  v31.8h
+
+        umull           v12.4s,  v20.4h,  v28.4h
+        umlal           v12.4s,  v21.4h,  v27.4h
+        umull2          v13.4s,  v20.8h,  v28.8h
+        umlal2          v13.4s,  v21.8h,  v27.8h
+
+        rshrn           v10.4h,  v10.4s,  #6
+        rshrn2          v10.8h,  v11.4s,  #6
+        rshrn           v11.4h,  v12.4s,  #6
+        rshrn2          v11.8h,  v13.4s,  #6
+
+        umull           v12.4s,  v4.4h,   v8.4h   // top[base_x]-*(64-frac_x)
+        umlal           v12.4s,  v5.4h,   v16.4h  // + top[base_x+1]*frac_x
+        umull2          v13.4s,  v4.8h,   v8.8h
+        umlal2          v13.4s,  v5.8h,   v16.8h
+        umull           v14.4s,  v6.4h,   v9.4h
+        umlal           v14.4s,  v7.4h,   v17.4h
+        umull2          v18.4s,  v6.8h,   v9.8h
+        umlal2          v18.4s,  v7.8h,   v17.8h
+
+        cmge            v22.8h,  v22.8h,  #0
+        cmge            v23.8h,  v23.8h,  #0
+
+        rshrn           v12.4h,  v12.4s,  #6
+        rshrn2          v12.8h,  v13.4s,  #6
+        rshrn           v13.4h,  v14.4s,  #6
+        rshrn2          v13.8h,  v18.4s,  #6
+
+        bit             v10.16b, v12.16b, v22.16b
+        bit             v11.16b, v13.16b, v23.16b
+
+        st1             {v10.8h}, [x0], x1
+        subs            w5,  w5,  #2
+        sub             w8,  w8,  w6              // xpos -= dx
+        st1             {v11.8h}, [x0], x1
+        b.le            9f
+
+        add             v29.16b, v29.16b, v24.16b // base_y += 2 (*2)
+        add             v30.16b, v30.16b, v24.16b
+        b               8b
+
+89:
+        tbl             v18.16b, {v0.16b, v1.16b, v2.16b}, v29.16b // left[base_y+0]
+        add             v29.16b, v29.16b, v24.16b // base_y += 2 (*2)
+        tbl             v19.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+1]
+        add             v30.16b, v30.16b, v24.16b
+        tbl             v20.16b, {v0.16b, v1.16b, v2.16b}, v29.16b // left[base_y+2]
+        tbl             v21.16b, {v0.16b, v1.16b, v2.16b}, v30.16b // left[base_y+3]
+
+        umull           v4.4s,   v18.4h,  v28.4h  // left[base_y]*(64-frac_y)
+        umlal           v4.4s,   v19.4h,  v27.4h  // + left[base_y+1]*frac_y
+        umull2          v5.4s,   v18.8h,  v28.8h
+        umlal2          v5.4s,   v19.8h,  v27.8h
+        umull           v6.4s,   v20.4h,  v28.4h
+        umlal           v6.4s,   v21.4h,  v27.4h
+        umull2          v7.4s,   v20.8h,  v28.8h
+        umlal2          v7.4s,   v21.8h,  v27.8h
+
+        rshrn           v4.4h,   v4.4s,   #6
+        rshrn2          v4.8h,   v5.4s,   #6
+        rshrn           v5.4h,   v6.4s,   #6
+        rshrn2          v5.8h,   v7.4s,   #6
+
+        st1             {v4.8h}, [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v5.8h}, [x0], x1
+        b.le            9f
+
+        add             v29.16b, v29.16b, v24.16b // base_y += 2 (*2)
+        add             v30.16b, v30.16b, v24.16b
+        b               89b
+
+9:
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+endfunc
+
+// void ipred_z3_fill1_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const left,
+//                                const int width, const int height,
+//                                const int dy, const int max_base_y);
+function ipred_z3_fill1_16bpc_neon, export=1
+        clz             w9,  w4
+        movrel          x8,  ipred_z3_fill1_tbl
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x8, w9, uxtw #2]
+        add             x10, x2,  w6,  uxtw #1    // left[max_base_y]
+        add             x8,  x8,  x9
+        ld1r            {v31.8h}, [x10]           // padding
+        mov             w7,  w5
+        mov             w15, #64
+        add             x13, x0,  x1
+        lsl             x1,  x1,  #1
+        br              x8
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            ipred_z3_fill_padding_neon
+        lsl             w8,  w8,  #1
+        lsl             w10, w10, #1
+        ldr             q0,  [x2, w8, uxtw]       // left[base]
+        ldr             q2,  [x2, w10, uxtw]
+        dup             v4.8h,   w9               // frac
+        dup             v5.8h,   w11
+        ext             v1.16b,  v0.16b,  v0.16b,  #2 // left[base+1]
+        ext             v3.16b,  v2.16b,  v2.16b,  #2
+        sub             v6.4h,   v1.4h,   v0.4h   // top[base+1]-top[base]
+        sub             v7.4h,   v3.4h,   v2.4h
+        ushll           v16.4s,  v0.4h,   #6      // top[base]*64
+        ushll           v17.4s,  v2.4h,   #6
+        smlal           v16.4s,  v6.4h,   v4.4h   // + top[base+1]*frac
+        smlal           v17.4s,  v7.4h,   v5.4h
+        rshrn           v16.4h,  v16.4s,  #6
+        rshrn           v17.4h,  v17.4s,  #6
+        subs            w3,  w3,  #2
+        zip1            v18.8h,  v16.8h,  v17.8h
+        st1             {v18.s}[0], [x0],  x1
+        st1             {v18.s}[1], [x13], x1
+        add             w7,  w7,  w5              // xpos += dx
+        st1             {v18.s}[2], [x0]
+        st1             {v18.s}[3], [x13]
+        b.le            9f
+        sub             x0,  x0,  x1              // ptr -= 4 * (2*stride)
+        sub             x13, x13, x1
+        add             x0,  x0,  #4
+        add             x13, x13, #4
+        b               4b
+9:
+        ret
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            ipred_z3_fill_padding_neon
+        add             x8,  x2,  w8,  uxtw #1
+        add             x10, x2,  w10, uxtw #1
+        dup             v4.8h,   w9               // frac
+        dup             v5.8h,   w11
+        ld1             {v0.8h},  [x8]            // left[base]
+        ld1             {v2.8h},  [x10]
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        ldr             h1, [x8, #16]
+        ldr             h3, [x10, #16]
+        dup             v6.8h,   w9               // 64 - frac
+        dup             v7.8h,   w11
+        ext             v1.16b,  v0.16b,  v1.16b,  #2 // left[base+1]
+        ext             v3.16b,  v2.16b,  v3.16b,  #2
+        umull           v16.4s,  v0.4h,   v6.4h   // left[base]*(64-frac)
+        umlal           v16.4s,  v1.4h,   v4.4h   // + left[base+1]*frac
+        umull2          v17.4s,  v0.8h,   v6.8h
+        umlal2          v17.4s,  v1.8h,   v4.8h
+        umull           v18.4s,  v2.4h,   v7.4h
+        umlal           v18.4s,  v3.4h,   v5.4h
+        umull2          v19.4s,  v2.8h,   v7.8h
+        umlal2          v19.4s,  v3.8h,   v5.8h
+        rshrn           v16.4h,  v16.4s,  #6
+        rshrn2          v16.8h,  v17.4s,  #6
+        rshrn           v17.4h,  v18.4s,  #6
+        rshrn2          v17.8h,  v19.4s,  #6
+        subs            w3,  w3,  #2
+        zip1            v18.8h,  v16.8h,  v17.8h
+        zip2            v19.8h,  v16.8h,  v17.8h
+        add             w7,  w7,  w5              // xpos += dx
+        st1             {v18.s}[0], [x0],  x1
+        st1             {v18.s}[1], [x13], x1
+        st1             {v18.s}[2], [x0],  x1
+        st1             {v18.s}[3], [x13], x1
+        st1             {v19.s}[0], [x0],  x1
+        st1             {v19.s}[1], [x13], x1
+        st1             {v19.s}[2], [x0],  x1
+        st1             {v19.s}[3], [x13], x1
+        b.le            9f
+        sub             x0,  x0,  x1, lsl #2      // ptr -= 4 * (2*stride)
+        sub             x13, x13, x1, lsl #2
+        add             x0,  x0,  #4
+        add             x13, x13, #4
+        b               8b
+9:
+        ret
+
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+        mov             w12, w4
+1:
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // ypos += dy
+        cmp             w8,  w6                   // base >= max_base_y
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            ipred_z3_fill_padding_neon
+        add             x8,  x2,  w8,  uxtw #1
+        add             x10, x2,  w10, uxtw #1
+        dup             v6.8h,   w9               // frac
+        dup             v7.8h,   w11
+        ld1             {v0.8h, v1.8h, v2.8h}, [x8],  #48 // left[base]
+        ld1             {v3.8h, v4.8h, v5.8h}, [x10], #48
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        dup             v16.8h,  w9               // 64 - frac
+        dup             v17.8h,  w11
+        add             w7,  w7,  w5              // ypos += dy
+2:
+        ext             v18.16b, v0.16b,  v1.16b,  #2 // left[base+1]
+        ext             v19.16b, v1.16b,  v2.16b,  #2
+        ext             v20.16b, v3.16b,  v4.16b,  #2
+        ext             v21.16b, v4.16b,  v5.16b,  #2
+        subs            w4,  w4,  #16
+        umull           v22.4s,  v0.4h,   v16.4h  // left[base]*(64-frac)
+        umlal           v22.4s,  v18.4h,  v6.4h   // + left[base+1]*frac
+        umull2          v23.4s,  v0.8h,   v16.8h
+        umlal2          v23.4s,  v18.8h,  v6.8h
+        umull           v24.4s,  v1.4h,   v16.4h
+        umlal           v24.4s,  v19.4h,  v6.4h
+        umull2          v25.4s,  v1.8h,   v16.8h
+        umlal2          v25.4s,  v19.8h,  v6.8h
+        umull           v26.4s,  v3.4h,   v17.4h
+        umlal           v26.4s,  v20.4h,  v7.4h
+        umull2          v27.4s,  v3.8h,   v17.8h
+        umlal2          v27.4s,  v20.8h,  v7.8h
+        umull           v28.4s,  v4.4h,   v17.4h
+        umlal           v28.4s,  v21.4h,  v7.4h
+        umull2          v29.4s,  v4.8h,   v17.8h
+        umlal2          v29.4s,  v21.8h,  v7.8h
+        rshrn           v22.4h,  v22.4s,  #6
+        rshrn2          v22.8h,  v23.4s,  #6
+        rshrn           v23.4h,  v24.4s,  #6
+        rshrn2          v23.8h,  v25.4s,  #6
+        rshrn           v24.4h,  v26.4s,  #6
+        rshrn2          v24.8h,  v27.4s,  #6
+        rshrn           v25.4h,  v28.4s,  #6
+        rshrn2          v25.8h,  v29.4s,  #6
+        zip1            v18.8h,  v22.8h,  v24.8h
+        zip2            v19.8h,  v22.8h,  v24.8h
+        zip1            v20.8h,  v23.8h,  v25.8h
+        zip2            v21.8h,  v23.8h,  v25.8h
+        st1             {v18.s}[0], [x0],  x1
+        st1             {v18.s}[1], [x13], x1
+        st1             {v18.s}[2], [x0],  x1
+        st1             {v18.s}[3], [x13], x1
+        st1             {v19.s}[0], [x0],  x1
+        st1             {v19.s}[1], [x13], x1
+        st1             {v19.s}[2], [x0],  x1
+        st1             {v19.s}[3], [x13], x1
+        st1             {v20.s}[0], [x0],  x1
+        st1             {v20.s}[1], [x13], x1
+        st1             {v20.s}[2], [x0],  x1
+        st1             {v20.s}[3], [x13], x1
+        st1             {v21.s}[0], [x0],  x1
+        st1             {v21.s}[1], [x13], x1
+        st1             {v21.s}[2], [x0],  x1
+        st1             {v21.s}[3], [x13], x1
+        b.le            3f
+        mov             v0.16b,  v2.16b
+        ld1             {v1.8h, v2.8h}, [x8],  #32      // left[base]
+        mov             v3.16b,  v5.16b
+        ld1             {v4.8h, v5.8h}, [x10], #32
+        b               2b
+
+3:
+        subs            w3,  w3,  #2
+        b.le            9f
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #4
+        add             x13, x13, #4
+        mov             w4,  w12
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_z3_fill1_tbl
+        .word 640b - ipred_z3_fill1_tbl
+        .word 320b - ipred_z3_fill1_tbl
+        .word 160b - ipred_z3_fill1_tbl
+        .word 80b  - ipred_z3_fill1_tbl
+        .word 40b  - ipred_z3_fill1_tbl
+endjumptable
+
+function ipred_z3_fill_padding_neon, export=0
+        cmp             w3,  #8
+        movrel          x8,  ipred_z3_fill_padding_tbl
+        b.gt            ipred_z3_fill_padding_wide
+        // w3 = remaining width, w4 = constant height
+        mov             w12, w4
+
+1:
+        // Fill a WxH rectangle with padding. W can be any number;
+        // this fills the exact width by filling in the largest
+        // power of two in the remaining width, and repeating.
+        clz             w9,  w3
+        sub             w9,  w9,  #25
+        ldrsw           x9,  [x8, w9, uxtw #2]
+        add             x9,  x8,  x9
+        br              x9
+
+20:
+        AARCH64_VALID_JUMP_TARGET
+2:
+        st1             {v31.s}[0], [x0],  x1
+        subs            w4,  w4,  #4
+        st1             {v31.s}[0], [x13], x1
+        st1             {v31.s}[0], [x0],  x1
+        st1             {v31.s}[0], [x13], x1
+        b.gt            2b
+        subs            w3,  w3,  #2
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        b.le            9f
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #4
+        add             x13, x13, #4
+        mov             w4,  w12
+        b               1b
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        st1             {v31.4h}, [x0],  x1
+        subs            w4,  w4,  #4
+        st1             {v31.4h}, [x13], x1
+        st1             {v31.4h}, [x0],  x1
+        st1             {v31.4h}, [x13], x1
+        b.gt            4b
+        subs            w3,  w3,  #4
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        b.le            9f
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #8
+        add             x13, x13, #8
+        mov             w4,  w12
+        b               1b
+
+80:
+160:
+320:
+640:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        st1             {v31.8h}, [x0],  x1
+        subs            w4,  w4,  #4
+        st1             {v31.8h}, [x13], x1
+        st1             {v31.8h}, [x0],  x1
+        st1             {v31.8h}, [x13], x1
+        b.gt            8b
+        subs            w3,  w3,  #8
+        lsr             x1,  x1,  #1
+        msub            x0,  x1,  x12, x0         // ptr -= h * stride
+        msub            x13, x1,  x12, x13
+        b.le            9f
+        lsl             x1,  x1,  #1
+        add             x0,  x0,  #16
+        add             x13, x13, #16
+        mov             w4,  w12
+        b               1b
+
+9:
+        ret
+endfunc
+
+jumptable ipred_z3_fill_padding_tbl
+        .word 640b - ipred_z3_fill_padding_tbl
+        .word 320b - ipred_z3_fill_padding_tbl
+        .word 160b - ipred_z3_fill_padding_tbl
+        .word 80b  - ipred_z3_fill_padding_tbl
+        .word 40b  - ipred_z3_fill_padding_tbl
+        .word 20b  - ipred_z3_fill_padding_tbl
+endjumptable
+
+function ipred_z3_fill_padding_wide
+        // Fill a WxH rectangle with padding, with W > 8.
+        lsr             x1,  x1,  #1
+        mov             w12, w3
+        sub             x1,  x1,  w3,  uxtw #1
+1:
+        ands            w5,  w3,  #7
+        b.eq            2f
+        // If the width isn't aligned to 8, first do one 8 pixel write
+        // and align the start pointer.
+        sub             w3,  w3,  w5
+        st1             {v31.8h}, [x0]
+        add             x0,  x0,  w5,  uxtw #1
+2:
+        // Fill the rest of the line with aligned 8 pixel writes.
+        subs            w3,  w3,  #8
+        st1             {v31.8h}, [x0], #16
+        b.gt            2b
+        subs            w4,  w4,  #1
+        add             x0,  x0,  x1
+        b.le            9f
+        mov             w3,  w12
+        b               1b
+9:
+        ret
+endfunc
+
+function ipred_z3_fill2_16bpc_neon, export=1
+        cmp             w4,  #8
+        add             x10, x2,  w6,  uxtw       // left[max_base_y]
+        ld1r            {v31.16b}, [x10]          // padding
+        mov             w7,  w5
+        mov             w15, #64
+        add             x13, x0,  x1
+        lsl             x1,  x1,  #1
+        b.eq            8f
+
+4:      // h == 4
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            ipred_z3_fill_padding_neon
+        lsl             w8,  w8,  #1
+        lsl             w10, w10, #1
+        ldr             q0,  [x2, w8, uxtw]       // top[base]
+        ldr             q2,  [x2, w10, uxtw]
+        dup             v4.4h,   w9               // frac
+        dup             v5.4h,   w11
+        uzp2            v1.8h,   v0.8h,   v0.8h   // top[base+1]
+        uzp1            v0.8h,   v0.8h,   v0.8h   // top[base]
+        uzp2            v3.8h,   v2.8h,   v2.8h
+        uzp1            v2.8h,   v2.8h,   v2.8h
+        sub             v6.4h,   v1.4h,   v0.4h   // top[base+1]-top[base]
+        sub             v7.4h,   v3.4h,   v2.4h
+        ushll           v16.4s,  v0.4h,   #6      // top[base]*64
+        ushll           v17.4s,  v2.4h,   #6
+        smlal           v16.4s,  v6.4h,   v4.4h   // + top[base+1]*frac
+        smlal           v17.4s,  v7.4h,   v5.4h
+        rshrn           v16.4h,  v16.4s,  #6
+        rshrn           v17.4h,  v17.4s,  #6
+        subs            w3,  w3,  #2
+        zip1            v18.8h,  v16.8h,  v17.8h
+        st1             {v18.s}[0], [x0],  x1
+        st1             {v18.s}[1], [x13], x1
+        add             w7,  w7,  w5              // xpos += dx
+        st1             {v18.s}[2], [x0]
+        st1             {v18.s}[3], [x13]
+        b.le            9f
+        sub             x0,  x0,  x1              // ptr -= 4 * (2*stride)
+        sub             x13, x13, x1
+        add             x0,  x0,  #4
+        add             x13, x13, #4
+        b               4b
+9:
+        ret
+
+8:      // h == 8
+        lsr             w8,  w7,  #6              // base
+        and             w9,  w7,  #0x3e           // frac
+        add             w7,  w7,  w5              // xpos += dx
+        cmp             w8,  w6                   // base >= max_base_x
+        lsr             w10, w7,  #6              // base
+        and             w11, w7,  #0x3e           // frac
+        b.ge            ipred_z3_fill_padding_neon
+        add             x8,  x2,  w8,  uxtw #1
+        add             x10, x2,  w10, uxtw #1
+        dup             v4.8h,   w9               // frac
+        dup             v5.8h,   w11
+        ld1             {v0.8h, v1.8h},  [x8]     // top[base]
+        ld1             {v2.8h, v3.8h},  [x10]
+        sub             w9,  w15, w9              // 64 - frac
+        sub             w11, w15, w11
+        dup             v6.8h,   w9               // 64 - frac
+        dup             v7.8h,   w11
+        uzp2            v20.8h,  v0.8h,   v1.8h   // top[base+1]
+        uzp1            v0.8h,   v0.8h,   v1.8h   // top[base]
+        uzp2            v21.8h,  v2.8h,   v3.8h
+        uzp1            v2.8h,   v2.8h,   v3.8h
+        umull           v16.4s,  v0.4h,   v6.4h   // top[base]*(64-frac)
+        umlal           v16.4s,  v20.4h,  v4.4h   // + top[base+1]*frac
+        umull2          v17.4s,  v0.8h,   v6.8h
+        umlal2          v17.4s,  v20.8h,  v4.8h
+        umull           v18.4s,  v2.4h,   v7.4h
+        umlal           v18.4s,  v21.4h,  v5.4h
+        umull2          v19.4s,  v2.8h,   v7.8h
+        umlal2          v19.4s,  v21.8h,  v5.8h
+        rshrn           v16.4h,  v16.4s,  #6
+        rshrn2          v16.8h,  v17.4s,  #6
+        rshrn           v17.4h,  v18.4s,  #6
+        rshrn2          v17.8h,  v19.4s,  #6
+        subs            w3,  w3,  #2
+        zip1            v18.8h,  v16.8h,  v17.8h
+        zip2            v19.8h,  v16.8h,  v17.8h
+        add             w7,  w7,  w5              // xpos += dx
+        st1             {v18.s}[0], [x0],  x1
+        st1             {v18.s}[1], [x13], x1
+        st1             {v18.s}[2], [x0],  x1
+        st1             {v18.s}[3], [x13], x1
+        st1             {v19.s}[0], [x0],  x1
+        st1             {v19.s}[1], [x13], x1
+        st1             {v19.s}[2], [x0],  x1
+        st1             {v19.s}[3], [x13], x1
+        b.le            9f
+        sub             x0,  x0,  x1, lsl #2      // ptr -= 4 * (2*stride)
+        sub             x13, x13, x1, lsl #2
+        add             x0,  x0,  #4
+        add             x13, x13, #4
+        b               8b
+9:
+        ret
+endfunc
+
+
+// void ipred_filter_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                              const pixel *const topleft,
+//                              const int width, const int height, const int filt_idx,
+//                              const int max_width, const int max_height,
+//                              const int bitdepth_max);
+.macro filter_fn bpc
+function ipred_filter_\bpc\()bpc_neon
+        and             w5,  w5,  #511
+        movrel          x6,  X(filter_intra_taps)
+        lsl             w5,  w5,  #6
+        add             x6,  x6,  w5, uxtw
+        ld1             {v16.8b, v17.8b, v18.8b, v19.8b}, [x6], #32
+        clz             w9,  w3
+        movrel          x5,  ipred_filter\bpc\()_tbl
+        ld1             {v20.8b, v21.8b, v22.8b}, [x6]
+        sub             w9,  w9,  #26
+        ldrsw           x9,  [x5, w9, uxtw #2]
+        sxtl            v16.8h,  v16.8b
+        sxtl            v17.8h,  v17.8b
+        add             x5,  x5,  x9
+        sxtl            v18.8h,  v18.8b
+        sxtl            v19.8h,  v19.8b
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        sxtl            v20.8h,  v20.8b
+        sxtl            v21.8h,  v21.8b
+        sxtl            v22.8h,  v22.8b
+        dup             v31.8h,  w8
+.if \bpc == 10
+        movi            v30.8h,  #0
+.endif
+        br              x5
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ldur            d0,  [x2, #2]             // top (0-3)
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+4:
+        ld1             {v1.4h}, [x2], x7         // left (0-1) + topleft (2)
+.if \bpc == 10
+        mul             v2.8h,   v17.8h,  v0.h[0] // p1(top[0]) * filter(1)
+        mla             v2.8h,   v18.8h,  v0.h[1] // p2(top[1]) * filter(2)
+        mla             v2.8h,   v19.8h,  v0.h[2] // p3(top[2]) * filter(3)
+        mla             v2.8h,   v20.8h,  v0.h[3] // p4(top[3]) * filter(4)
+        mla             v2.8h,   v16.8h,  v1.h[2] // p0(topleft) * filter(0)
+        mla             v2.8h,   v21.8h,  v1.h[1] // p5(left[0]) * filter(5)
+        mla             v2.8h,   v22.8h,  v1.h[0] // p6(left[1]) * filter(6)
+        srshr           v2.8h,   v2.8h,   #4
+        smax            v2.8h,   v2.8h,   v30.8h
+.else
+        smull           v2.4s,   v17.4h,  v0.h[0] // p1(top[0]) * filter(1)
+        smlal           v2.4s,   v18.4h,  v0.h[1] // p2(top[1]) * filter(2)
+        smlal           v2.4s,   v19.4h,  v0.h[2] // p3(top[2]) * filter(3)
+        smlal           v2.4s,   v20.4h,  v0.h[3] // p4(top[3]) * filter(4)
+        smlal           v2.4s,   v16.4h,  v1.h[2] // p0(topleft) * filter(0)
+        smlal           v2.4s,   v21.4h,  v1.h[1] // p5(left[0]) * filter(5)
+        smlal           v2.4s,   v22.4h,  v1.h[0] // p6(left[1]) * filter(6)
+        smull2          v3.4s,   v17.8h,  v0.h[0] // p1(top[0]) * filter(1)
+        smlal2          v3.4s,   v18.8h,  v0.h[1] // p2(top[1]) * filter(2)
+        smlal2          v3.4s,   v19.8h,  v0.h[2] // p3(top[2]) * filter(3)
+        smlal2          v3.4s,   v20.8h,  v0.h[3] // p4(top[3]) * filter(4)
+        smlal2          v3.4s,   v16.8h,  v1.h[2] // p0(topleft) * filter(0)
+        smlal2          v3.4s,   v21.8h,  v1.h[1] // p5(left[0]) * filter(5)
+        smlal2          v3.4s,   v22.8h,  v1.h[0] // p6(left[1]) * filter(6)
+        sqrshrun        v2.4h,   v2.4s,   #4
+        sqrshrun2       v2.8h,   v3.4s,   #4
+.endif
+        smin            v2.8h,   v2.8h,   v31.8h
+        subs            w4,  w4,  #2
+        st1             {v2.d}[0], [x0], x1
+        ext             v0.16b,  v2.16b,  v2.16b, #8 // move top from [4-7] to [0-3]
+        st1             {v2.d}[1], [x6], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ldur            q0,  [x2, #2]             // top (0-7)
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+8:
+        ld1             {v1.4h}, [x2], x7         // left (0-1) + topleft (2)
+.if \bpc == 10
+        mul             v2.8h,   v17.8h,  v0.h[0] // p1(top[0]) * filter(1)
+        mla             v2.8h,   v18.8h,  v0.h[1] // p2(top[1]) * filter(2)
+        mla             v2.8h,   v19.8h,  v0.h[2] // p3(top[2]) * filter(3)
+        mla             v2.8h,   v20.8h,  v0.h[3] // p4(top[3]) * filter(4)
+        mla             v2.8h,   v16.8h,  v1.h[2] // p0(topleft) * filter(0)
+        mla             v2.8h,   v21.8h,  v1.h[1] // p5(left[0]) * filter(5)
+        mla             v2.8h,   v22.8h,  v1.h[0] // p6(left[1]) * filter(6)
+        mul             v3.8h,   v17.8h,  v0.h[4] // p1(top[0]) * filter(1)
+        mla             v3.8h,   v18.8h,  v0.h[5] // p2(top[1]) * filter(2)
+        mla             v3.8h,   v19.8h,  v0.h[6] // p3(top[2]) * filter(3)
+        srshr           v2.8h,   v2.8h,   #4
+        smax            v2.8h,   v2.8h,   v30.8h
+        smin            v2.8h,   v2.8h,   v31.8h
+        mla             v3.8h,   v20.8h,  v0.h[7] // p4(top[3]) * filter(4)
+        mla             v3.8h,   v16.8h,  v0.h[3] // p0(topleft) * filter(0)
+        mla             v3.8h,   v21.8h,  v2.h[3] // p5(left[0]) * filter(5)
+        mla             v3.8h,   v22.8h,  v2.h[7] // p6(left[1]) * filter(6)
+        srshr           v3.8h,   v3.8h,   #4
+        smax            v3.8h,   v3.8h,   v30.8h
+.else
+        smull           v2.4s,   v17.4h,  v0.h[0] // p1(top[0]) * filter(1)
+        smlal           v2.4s,   v18.4h,  v0.h[1] // p2(top[1]) * filter(2)
+        smlal           v2.4s,   v19.4h,  v0.h[2] // p3(top[2]) * filter(3)
+        smlal           v2.4s,   v20.4h,  v0.h[3] // p4(top[3]) * filter(4)
+        smlal           v2.4s,   v16.4h,  v1.h[2] // p0(topleft) * filter(0)
+        smlal           v2.4s,   v21.4h,  v1.h[1] // p5(left[0]) * filter(5)
+        smlal           v2.4s,   v22.4h,  v1.h[0] // p6(left[1]) * filter(6)
+        smull2          v3.4s,   v17.8h,  v0.h[0] // p1(top[0]) * filter(1)
+        smlal2          v3.4s,   v18.8h,  v0.h[1] // p2(top[1]) * filter(2)
+        smlal2          v3.4s,   v19.8h,  v0.h[2] // p3(top[2]) * filter(3)
+        smlal2          v3.4s,   v20.8h,  v0.h[3] // p4(top[3]) * filter(4)
+        smlal2          v3.4s,   v16.8h,  v1.h[2] // p0(topleft) * filter(0)
+        smlal2          v3.4s,   v21.8h,  v1.h[1] // p5(left[0]) * filter(5)
+        smlal2          v3.4s,   v22.8h,  v1.h[0] // p6(left[1]) * filter(6)
+        smull           v4.4s,   v17.4h,  v0.h[4] // p1(top[0]) * filter(1)
+        smlal           v4.4s,   v18.4h,  v0.h[5] // p2(top[1]) * filter(2)
+        smlal           v4.4s,   v19.4h,  v0.h[6] // p3(top[2]) * filter(3)
+        sqrshrun        v2.4h,   v2.4s,   #4
+        sqrshrun2       v2.8h,   v3.4s,   #4
+        smin            v2.8h,   v2.8h,   v31.8h
+        smlal           v4.4s,   v20.4h,  v0.h[7] // p4(top[3]) * filter(4)
+        smlal           v4.4s,   v16.4h,  v0.h[3] // p0(topleft) * filter(0)
+        smlal           v4.4s,   v21.4h,  v2.h[3] // p5(left[0]) * filter(5)
+        smlal           v4.4s,   v22.4h,  v2.h[7] // p6(left[1]) * filter(6)
+        smull2          v5.4s,   v17.8h,  v0.h[4] // p1(top[0]) * filter(1)
+        smlal2          v5.4s,   v18.8h,  v0.h[5] // p2(top[1]) * filter(2)
+        smlal2          v5.4s,   v19.8h,  v0.h[6] // p3(top[2]) * filter(3)
+        smlal2          v5.4s,   v20.8h,  v0.h[7] // p4(top[3]) * filter(4)
+        smlal2          v5.4s,   v16.8h,  v0.h[3] // p0(topleft) * filter(0)
+        smlal2          v5.4s,   v21.8h,  v2.h[3] // p5(left[0]) * filter(5)
+        smlal2          v5.4s,   v22.8h,  v2.h[7] // p6(left[1]) * filter(6)
+        sqrshrun        v3.4h,   v4.4s,   #4
+        sqrshrun2       v3.8h,   v5.4s,   #4
+.endif
+        smin            v3.8h,   v3.8h,   v31.8h
+        subs            w4,  w4,  #2
+        st2             {v2.d, v3.d}[0], [x0], x1
+        zip2            v0.2d,   v2.2d,   v3.2d
+        st2             {v2.d, v3.d}[1], [x6], x1
+        b.gt            8b
+        ret
+160:
+320:
+        AARCH64_VALID_JUMP_TARGET
+        add             x8,  x2,  #2
+        sub             x2,  x2,  #4
+        mov             x7,  #-4
+        sub             x1,  x1,  w3, uxtw #1
+        mov             w9,  w3
+
+1:
+        ld1             {v0.4h}, [x2], x7         // left (0-1) + topleft (2)
+2:
+        ld1             {v1.8h, v2.8h}, [x8], #32 // top(0-15)
+.if \bpc == 10
+        mul             v3.8h,   v16.8h,  v0.h[2] // p0(topleft) * filter(0)
+        mla             v3.8h,   v21.8h,  v0.h[1] // p5(left[0]) * filter(5)
+        mla             v3.8h,   v22.8h,  v0.h[0] // p6(left[1]) * filter(6)
+        mla             v3.8h,   v17.8h,  v1.h[0] // p1(top[0]) * filter(1)
+        mla             v3.8h,   v18.8h,  v1.h[1] // p2(top[1]) * filter(2)
+        mla             v3.8h,   v19.8h,  v1.h[2] // p3(top[2]) * filter(3)
+        mla             v3.8h,   v20.8h,  v1.h[3] // p4(top[3]) * filter(4)
+
+        mul             v4.8h,   v17.8h,  v1.h[4] // p1(top[0]) * filter(1)
+        mla             v4.8h,   v18.8h,  v1.h[5] // p2(top[1]) * filter(2)
+        mla             v4.8h,   v19.8h,  v1.h[6] // p3(top[2]) * filter(3)
+        srshr           v3.8h,   v3.8h,   #4
+        smax            v3.8h,   v3.8h,   v30.8h
+        smin            v3.8h,   v3.8h,   v31.8h
+        mla             v4.8h,   v20.8h,  v1.h[7] // p4(top[3]) * filter(4)
+        mla             v4.8h,   v16.8h,  v1.h[3] // p0(topleft) * filter(0)
+        mla             v4.8h,   v21.8h,  v3.h[3] // p5(left[0]) * filter(5)
+        mla             v4.8h,   v22.8h,  v3.h[7] // p6(left[1]) * filter(6)
+
+        mul             v5.8h,   v17.8h,  v2.h[0] // p1(top[0]) * filter(1)
+        mla             v5.8h,   v18.8h,  v2.h[1] // p2(top[1]) * filter(2)
+        mla             v5.8h,   v19.8h,  v2.h[2] // p3(top[2]) * filter(3)
+        srshr           v4.8h,   v4.8h,   #4
+        smax            v4.8h,   v4.8h,   v30.8h
+        smin            v4.8h,   v4.8h,   v31.8h
+        mla             v5.8h,   v20.8h,  v2.h[3] // p4(top[3]) * filter(4)
+        mla             v5.8h,   v16.8h,  v1.h[7] // p0(topleft) * filter(0)
+        mla             v5.8h,   v21.8h,  v4.h[3] // p5(left[0]) * filter(5)
+        mla             v5.8h,   v22.8h,  v4.h[7] // p6(left[1]) * filter(6)
+
+        mul             v6.8h,   v17.8h,  v2.h[4] // p1(top[0]) * filter(1)
+        mla             v6.8h,   v18.8h,  v2.h[5] // p2(top[1]) * filter(2)
+        mla             v6.8h,   v19.8h,  v2.h[6] // p3(top[2]) * filter(3)
+        srshr           v5.8h,   v5.8h,   #4
+        smax            v5.8h,   v5.8h,   v30.8h
+        smin            v5.8h,   v5.8h,   v31.8h
+        mla             v6.8h,   v20.8h,  v2.h[7] // p4(top[3]) * filter(4)
+        mla             v6.8h,   v16.8h,  v2.h[3] // p0(topleft) * filter(0)
+        mla             v6.8h,   v21.8h,  v5.h[3] // p5(left[0]) * filter(5)
+        mla             v6.8h,   v22.8h,  v5.h[7] // p6(left[1]) * filter(6)
+
+        subs            w3,  w3,  #16
+        srshr           v6.8h,   v6.8h,   #4
+        smax            v6.8h,   v6.8h,   v30.8h
+.else
+        smull           v3.4s,   v16.4h,  v0.h[2] // p0(topleft) * filter(0)
+        smlal           v3.4s,   v21.4h,  v0.h[1] // p5(left[0]) * filter(5)
+        smlal           v3.4s,   v22.4h,  v0.h[0] // p6(left[1]) * filter(6)
+        smlal           v3.4s,   v17.4h,  v1.h[0] // p1(top[0]) * filter(1)
+        smlal           v3.4s,   v18.4h,  v1.h[1] // p2(top[1]) * filter(2)
+        smlal           v3.4s,   v19.4h,  v1.h[2] // p3(top[2]) * filter(3)
+        smlal           v3.4s,   v20.4h,  v1.h[3] // p4(top[3]) * filter(4)
+        smull2          v4.4s,   v16.8h,  v0.h[2] // p0(topleft) * filter(0)
+        smlal2          v4.4s,   v21.8h,  v0.h[1] // p5(left[0]) * filter(5)
+        smlal2          v4.4s,   v22.8h,  v0.h[0] // p6(left[1]) * filter(6)
+        smlal2          v4.4s,   v17.8h,  v1.h[0] // p1(top[0]) * filter(1)
+        smlal2          v4.4s,   v18.8h,  v1.h[1] // p2(top[1]) * filter(2)
+        smlal2          v4.4s,   v19.8h,  v1.h[2] // p3(top[2]) * filter(3)
+        smlal2          v4.4s,   v20.8h,  v1.h[3] // p4(top[3]) * filter(4)
+
+        smull           v5.4s,   v17.4h,  v1.h[4] // p1(top[0]) * filter(1)
+        smlal           v5.4s,   v18.4h,  v1.h[5] // p2(top[1]) * filter(2)
+        smlal           v5.4s,   v19.4h,  v1.h[6] // p3(top[2]) * filter(3)
+        sqrshrun        v3.4h,   v3.4s,   #4
+        sqrshrun2       v3.8h,   v4.4s,   #4
+        smin            v3.8h,   v3.8h,   v31.8h
+        smlal           v5.4s,   v20.4h,  v1.h[7] // p4(top[3]) * filter(4)
+        smlal           v5.4s,   v16.4h,  v1.h[3] // p0(topleft) * filter(0)
+        smlal           v5.4s,   v21.4h,  v3.h[3] // p5(left[0]) * filter(5)
+        smlal           v5.4s,   v22.4h,  v3.h[7] // p6(left[1]) * filter(6)
+        smull2          v6.4s,   v17.8h,  v1.h[4] // p1(top[0]) * filter(1)
+        smlal2          v6.4s,   v18.8h,  v1.h[5] // p2(top[1]) * filter(2)
+        smlal2          v6.4s,   v19.8h,  v1.h[6] // p3(top[2]) * filter(3)
+        smlal2          v6.4s,   v20.8h,  v1.h[7] // p4(top[3]) * filter(4)
+        smlal2          v6.4s,   v16.8h,  v1.h[3] // p0(topleft) * filter(0)
+        smlal2          v6.4s,   v21.8h,  v3.h[3] // p5(left[0]) * filter(5)
+        smlal2          v6.4s,   v22.8h,  v3.h[7] // p6(left[1]) * filter(6)
+
+        smull           v24.4s,  v17.4h,  v2.h[0] // p1(top[0]) * filter(1)
+        smlal           v24.4s,  v18.4h,  v2.h[1] // p2(top[1]) * filter(2)
+        smlal           v24.4s,  v19.4h,  v2.h[2] // p3(top[2]) * filter(3)
+        sqrshrun        v4.4h,   v5.4s,   #4
+        sqrshrun2       v4.8h,   v6.4s,   #4
+        smin            v4.8h,   v4.8h,   v31.8h
+        smlal           v24.4s,  v20.4h,  v2.h[3] // p4(top[3]) * filter(4)
+        smlal           v24.4s,  v16.4h,  v1.h[7] // p0(topleft) * filter(0)
+        smlal           v24.4s,  v21.4h,  v4.h[3] // p5(left[0]) * filter(5)
+        smlal           v24.4s,  v22.4h,  v4.h[7] // p6(left[1]) * filter(6)
+        smull2          v25.4s,  v17.8h,  v2.h[0] // p1(top[0]) * filter(1)
+        smlal2          v25.4s,  v18.8h,  v2.h[1] // p2(top[1]) * filter(2)
+        smlal2          v25.4s,  v19.8h,  v2.h[2] // p3(top[2]) * filter(3)
+        smlal2          v25.4s,  v20.8h,  v2.h[3] // p4(top[3]) * filter(4)
+        smlal2          v25.4s,  v16.8h,  v1.h[7] // p0(topleft) * filter(0)
+        smlal2          v25.4s,  v21.8h,  v4.h[3] // p5(left[0]) * filter(5)
+        smlal2          v25.4s,  v22.8h,  v4.h[7] // p6(left[1]) * filter(6)
+
+        smull           v26.4s,  v17.4h,  v2.h[4] // p1(top[0]) * filter(1)
+        smlal           v26.4s,  v18.4h,  v2.h[5] // p2(top[1]) * filter(2)
+        smlal           v26.4s,  v19.4h,  v2.h[6] // p3(top[2]) * filter(3)
+        sqrshrun        v5.4h,   v24.4s,  #4
+        sqrshrun2       v5.8h,   v25.4s,  #4
+        smin            v5.8h,   v5.8h,   v31.8h
+        smlal           v26.4s,  v20.4h,  v2.h[7] // p4(top[3]) * filter(4)
+        smlal           v26.4s,  v16.4h,  v2.h[3] // p0(topleft) * filter(0)
+        smlal           v26.4s,  v21.4h,  v5.h[3] // p5(left[0]) * filter(5)
+        smlal           v26.4s,  v22.4h,  v5.h[7] // p6(left[1]) * filter(6)
+        smull2          v27.4s,  v17.8h,  v2.h[4] // p1(top[0]) * filter(1)
+        smlal2          v27.4s,  v18.8h,  v2.h[5] // p2(top[1]) * filter(2)
+        smlal2          v27.4s,  v19.8h,  v2.h[6] // p3(top[2]) * filter(3)
+        smlal2          v27.4s,  v20.8h,  v2.h[7] // p4(top[3]) * filter(4)
+        smlal2          v27.4s,  v16.8h,  v2.h[3] // p0(topleft) * filter(0)
+        smlal2          v27.4s,  v21.8h,  v5.h[3] // p5(left[0]) * filter(5)
+        smlal2          v27.4s,  v22.8h,  v5.h[7] // p6(left[1]) * filter(6)
+
+        subs            w3,  w3,  #16
+        sqrshrun        v6.4h,   v26.4s,  #4
+        sqrshrun2       v6.8h,   v27.4s,  #4
+.endif
+        smin            v6.8h,   v6.8h,   v31.8h
+
+        ins             v0.h[2], v2.h[7]
+        st4             {v3.d, v4.d, v5.d, v6.d}[0], [x0], #32
+        ins             v0.h[0], v6.h[7]
+        st4             {v3.d, v4.d, v5.d, v6.d}[1], [x6], #32
+        ins             v0.h[1], v6.h[3]
+        b.gt            2b
+        subs            w4,  w4,  #2
+        b.le            9f
+        sub             x8,  x6,  w9, uxtw #1
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        mov             w3,  w9
+        b               1b
+9:
+        ret
+endfunc
+
+jumptable ipred_filter\bpc\()_tbl
+        .word 320b - ipred_filter\bpc\()_tbl
+        .word 160b - ipred_filter\bpc\()_tbl
+        .word 80b  - ipred_filter\bpc\()_tbl
+        .word 40b  - ipred_filter\bpc\()_tbl
+endjumptable
+.endm
+
+filter_fn 10
+filter_fn 12
+
+function ipred_filter_16bpc_neon, export=1
+        ldr             w8,  [sp]
+        cmp             w8,  0x3ff
+        b.le            ipred_filter_10bpc_neon
+        b               ipred_filter_12bpc_neon
+endfunc
+
+// void pal_pred_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                          const pixel *const pal, const uint8_t *idx,
+//                          const int w, const int h);
+function pal_pred_16bpc_neon, export=1
+        ld1             {v30.8h}, [x2]
+        clz             w9,  w4
+        movrel          x6,  pal_pred_tbl
+        sub             w9,  w9,  #25
+        movi            v29.16b, #7
+        ldrsw           x9,  [x6, w9, uxtw #2]
+        movi            v31.8h,  #1, lsl #8
+        add             x6,  x6,  x9
+        br              x6
+40:
+        AARCH64_VALID_JUMP_TARGET
+        add             x2,  x0,  x1
+        lsl             x1,  x1,  #1
+4:
+        ld1             {v1.8b}, [x3], #8
+        subs            w5,  w5,  #4
+        ushr            v3.8b,   v1.8b,   #4
+        and             v2.8b,   v1.8b,   v29.8b
+        zip1            v1.16b,  v2.16b,  v3.16b
+        // Restructure v1 from a, b, c, ... into 2*a, 2*a+1, 2*b, 2*b+1, 2*c, 2*c+1, ...
+        add             v1.16b,  v1.16b,  v1.16b
+        zip1            v0.16b,  v1.16b,  v1.16b
+        zip2            v1.16b,  v1.16b,  v1.16b
+        add             v0.8h,   v0.8h,   v31.8h
+        add             v1.8h,   v1.8h,   v31.8h
+        tbl             v0.16b, {v30.16b}, v0.16b
+        st1             {v0.d}[0], [x0], x1
+        tbl             v1.16b, {v30.16b}, v1.16b
+        st1             {v0.d}[1], [x2], x1
+        st1             {v1.d}[0], [x0], x1
+        st1             {v1.d}[1], [x2], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        add             x2,  x0,  x1
+        lsl             x1,  x1,  #1
+8:
+        ld1             {v2.16b}, [x3], #16
+        subs            w5,  w5,  #4
+        ushr            v4.16b,  v2.16b,  #4
+        and             v3.16b,  v2.16b,  v29.16b
+        zip1            v2.16b,  v3.16b,  v4.16b
+        zip2            v3.16b,  v3.16b,  v4.16b
+        add             v2.16b,  v2.16b,  v2.16b
+        add             v3.16b,  v3.16b,  v3.16b
+        zip1            v0.16b,  v2.16b,  v2.16b
+        zip2            v1.16b,  v2.16b,  v2.16b
+        zip1            v2.16b,  v3.16b,  v3.16b
+        zip2            v3.16b,  v3.16b,  v3.16b
+        add             v0.8h,   v0.8h,   v31.8h
+        add             v1.8h,   v1.8h,   v31.8h
+        add             v2.8h,   v2.8h,   v31.8h
+        add             v3.8h,   v3.8h,   v31.8h
+        tbl             v0.16b, {v30.16b}, v0.16b
+        tbl             v1.16b, {v30.16b}, v1.16b
+        st1             {v0.8h}, [x0], x1
+        tbl             v2.16b, {v30.16b}, v2.16b
+        st1             {v1.8h}, [x2], x1
+        tbl             v3.16b, {v30.16b}, v3.16b
+        st1             {v2.8h}, [x0], x1
+        st1             {v3.8h}, [x2], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        add             x2,  x0,  x1
+        lsl             x1,  x1,  #1
+16:
+        ld1             {v4.16b, v5.16b}, [x3], #32
+        subs            w5,  w5,  #4
+        ushr            v7.16b,  v4.16b,  #4
+        and             v6.16b,  v4.16b,  v29.16b
+        ushr            v3.16b,  v5.16b,  #4
+        and             v2.16b,  v5.16b,  v29.16b
+        zip1            v4.16b,  v6.16b,  v7.16b
+        zip2            v5.16b,  v6.16b,  v7.16b
+        zip1            v6.16b,  v2.16b,  v3.16b
+        zip2            v7.16b,  v2.16b,  v3.16b
+        add             v4.16b,  v4.16b,  v4.16b
+        add             v5.16b,  v5.16b,  v5.16b
+        add             v6.16b,  v6.16b,  v6.16b
+        add             v7.16b,  v7.16b,  v7.16b
+        zip1            v0.16b,  v4.16b,  v4.16b
+        zip2            v1.16b,  v4.16b,  v4.16b
+        zip1            v2.16b,  v5.16b,  v5.16b
+        zip2            v3.16b,  v5.16b,  v5.16b
+        zip1            v4.16b,  v6.16b,  v6.16b
+        zip2            v5.16b,  v6.16b,  v6.16b
+        zip1            v6.16b,  v7.16b,  v7.16b
+        zip2            v7.16b,  v7.16b,  v7.16b
+        add             v0.8h,   v0.8h,   v31.8h
+        add             v1.8h,   v1.8h,   v31.8h
+        add             v2.8h,   v2.8h,   v31.8h
+        add             v3.8h,   v3.8h,   v31.8h
+        add             v4.8h,   v4.8h,   v31.8h
+        tbl             v0.16b, {v30.16b}, v0.16b
+        add             v5.8h,   v5.8h,   v31.8h
+        tbl             v1.16b, {v30.16b}, v1.16b
+        add             v6.8h,   v6.8h,   v31.8h
+        tbl             v2.16b, {v30.16b}, v2.16b
+        add             v7.8h,   v7.8h,   v31.8h
+        tbl             v3.16b, {v30.16b}, v3.16b
+        tbl             v4.16b, {v30.16b}, v4.16b
+        tbl             v5.16b, {v30.16b}, v5.16b
+        st1             {v0.8h, v1.8h}, [x0], x1
+        tbl             v6.16b, {v30.16b}, v6.16b
+        st1             {v2.8h, v3.8h}, [x2], x1
+        tbl             v7.16b, {v30.16b}, v7.16b
+        st1             {v4.8h, v5.8h}, [x0], x1
+        st1             {v6.8h, v7.8h}, [x2], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        add             x2,  x0,  x1
+        lsl             x1,  x1,  #1
+32:
+        ld1             {v4.16b, v5.16b}, [x3], #32
+        subs            w5,  w5,  #2
+        ushr            v7.16b,  v4.16b,  #4
+        and             v6.16b,  v4.16b,  v29.16b
+        ushr            v3.16b,  v5.16b,  #4
+        and             v2.16b,  v5.16b,  v29.16b
+        zip1            v4.16b,  v6.16b,  v7.16b
+        zip2            v5.16b,  v6.16b,  v7.16b
+        zip1            v6.16b,  v2.16b,  v3.16b
+        zip2            v7.16b,  v2.16b,  v3.16b
+        add             v4.16b,  v4.16b,  v4.16b
+        add             v5.16b,  v5.16b,  v5.16b
+        add             v6.16b,  v6.16b,  v6.16b
+        add             v7.16b,  v7.16b,  v7.16b
+        zip1            v0.16b,  v4.16b,  v4.16b
+        zip2            v1.16b,  v4.16b,  v4.16b
+        zip1            v2.16b,  v5.16b,  v5.16b
+        zip2            v3.16b,  v5.16b,  v5.16b
+        zip1            v4.16b,  v6.16b,  v6.16b
+        zip2            v5.16b,  v6.16b,  v6.16b
+        zip1            v6.16b,  v7.16b,  v7.16b
+        zip2            v7.16b,  v7.16b,  v7.16b
+        add             v0.8h,   v0.8h,   v31.8h
+        add             v1.8h,   v1.8h,   v31.8h
+        add             v2.8h,   v2.8h,   v31.8h
+        add             v3.8h,   v3.8h,   v31.8h
+        add             v4.8h,   v4.8h,   v31.8h
+        tbl             v0.16b, {v30.16b}, v0.16b
+        add             v5.8h,   v5.8h,   v31.8h
+        tbl             v1.16b, {v30.16b}, v1.16b
+        add             v6.8h,   v6.8h,   v31.8h
+        tbl             v2.16b, {v30.16b}, v2.16b
+        add             v7.8h,   v7.8h,   v31.8h
+        tbl             v3.16b, {v30.16b}, v3.16b
+        tbl             v4.16b, {v30.16b}, v4.16b
+        tbl             v5.16b, {v30.16b}, v5.16b
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        tbl             v6.16b, {v30.16b}, v6.16b
+        tbl             v7.16b, {v30.16b}, v7.16b
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2], x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+        add             x2,  x0,  #64
+64:
+        ld1             {v4.16b, v5.16b}, [x3], #32
+        subs            w5,  w5,  #1
+        ushr            v7.16b,  v4.16b,  #4
+        and             v6.16b,  v4.16b,  v29.16b
+        ushr            v3.16b,  v5.16b,  #4
+        and             v2.16b,  v5.16b,  v29.16b
+        zip1            v4.16b,  v6.16b,  v7.16b
+        zip2            v5.16b,  v6.16b,  v7.16b
+        zip1            v6.16b,  v2.16b,  v3.16b
+        zip2            v7.16b,  v2.16b,  v3.16b
+        add             v4.16b,  v4.16b,  v4.16b
+        add             v5.16b,  v5.16b,  v5.16b
+        add             v6.16b,  v6.16b,  v6.16b
+        add             v7.16b,  v7.16b,  v7.16b
+        zip1            v0.16b,  v4.16b,  v4.16b
+        zip2            v1.16b,  v4.16b,  v4.16b
+        zip1            v2.16b,  v5.16b,  v5.16b
+        zip2            v3.16b,  v5.16b,  v5.16b
+        zip1            v4.16b,  v6.16b,  v6.16b
+        zip2            v5.16b,  v6.16b,  v6.16b
+        zip1            v6.16b,  v7.16b,  v7.16b
+        zip2            v7.16b,  v7.16b,  v7.16b
+        add             v0.8h,   v0.8h,   v31.8h
+        add             v1.8h,   v1.8h,   v31.8h
+        add             v2.8h,   v2.8h,   v31.8h
+        add             v3.8h,   v3.8h,   v31.8h
+        add             v4.8h,   v4.8h,   v31.8h
+        tbl             v0.16b, {v30.16b}, v0.16b
+        add             v5.8h,   v5.8h,   v31.8h
+        tbl             v1.16b, {v30.16b}, v1.16b
+        add             v6.8h,   v6.8h,   v31.8h
+        tbl             v2.16b, {v30.16b}, v2.16b
+        add             v7.8h,   v7.8h,   v31.8h
+        tbl             v3.16b, {v30.16b}, v3.16b
+        tbl             v4.16b, {v30.16b}, v4.16b
+        tbl             v5.16b, {v30.16b}, v5.16b
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        tbl             v6.16b, {v30.16b}, v6.16b
+        tbl             v7.16b, {v30.16b}, v7.16b
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2], x1
+        b.gt            64b
+        ret
+endfunc
+
+jumptable pal_pred_tbl
+        .word 640b - pal_pred_tbl
+        .word 320b - pal_pred_tbl
+        .word 160b - pal_pred_tbl
+        .word 80b  - pal_pred_tbl
+        .word 40b  - pal_pred_tbl
+endjumptable
+
+// void ipred_cfl_128_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height,
+//                               const int16_t *ac, const int alpha,
+//                               const int bitdepth_max);
+function ipred_cfl_128_16bpc_neon, export=1
+        dup             v31.8h,  w7   // bitdepth_max
+        clz             w9,  w3
+        movrel          x7,  ipred_cfl_128_tbl
+        sub             w9,  w9,  #26
+        ldrsw           x9,  [x7, w9, uxtw #2]
+        urshr           v0.8h,   v31.8h,  #1
+        dup             v1.8h,   w6   // alpha
+        add             x7,  x7,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        movi            v30.8h,  #0
+        br              x7
+L(ipred_cfl_splat_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        ld1             {v4.8h, v5.8h}, [x5], #32
+        subs            w4,  w4,  #4
+        smull           v2.4s,   v4.4h,   v1.4h  // diff = ac * alpha
+        smull2          v3.4s,   v4.8h,   v1.8h
+        smull           v4.4s,   v5.4h,   v1.4h
+        smull2          v5.4s,   v5.8h,   v1.8h
+        cmlt            v16.4s,  v2.4s,   #0     // sign
+        cmlt            v17.4s,  v3.4s,   #0
+        cmlt            v18.4s,  v4.4s,   #0
+        cmlt            v19.4s,  v5.4s,   #0
+        add             v2.4s,   v2.4s,   v16.4s // diff + sign
+        add             v3.4s,   v3.4s,   v17.4s
+        add             v4.4s,   v4.4s,   v18.4s
+        add             v5.4s,   v5.4s,   v19.4s
+        rshrn           v2.4h,   v2.4s,   #6     // (diff + sign + 32) >> 6 = apply_sign()
+        rshrn2          v2.8h,   v3.4s,   #6
+        rshrn           v3.4h,   v4.4s,   #6
+        rshrn2          v3.8h,   v5.4s,   #6
+        add             v2.8h,   v2.8h,   v0.8h  // dc + apply_sign()
+        add             v3.8h,   v3.8h,   v0.8h
+        smax            v2.8h,   v2.8h,   v30.8h
+        smax            v3.8h,   v3.8h,   v30.8h
+        smin            v2.8h,   v2.8h,   v31.8h
+        smin            v3.8h,   v3.8h,   v31.8h
+        st1             {v2.d}[0],  [x0], x1
+        st1             {v2.d}[1],  [x6], x1
+        st1             {v3.d}[0],  [x0], x1
+        st1             {v3.d}[1],  [x6], x1
+        b.gt            1b
+        ret
+L(ipred_cfl_splat_w8):
+        AARCH64_VALID_JUMP_TARGET
+1:
+        ld1             {v4.8h, v5.8h}, [x5], #32
+        subs            w4,  w4,  #2
+        smull           v2.4s,   v4.4h,   v1.4h  // diff = ac * alpha
+        smull2          v3.4s,   v4.8h,   v1.8h
+        smull           v4.4s,   v5.4h,   v1.4h
+        smull2          v5.4s,   v5.8h,   v1.8h
+        cmlt            v16.4s,  v2.4s,   #0     // sign
+        cmlt            v17.4s,  v3.4s,   #0
+        cmlt            v18.4s,  v4.4s,   #0
+        cmlt            v19.4s,  v5.4s,   #0
+        add             v2.4s,   v2.4s,   v16.4s // diff + sign
+        add             v3.4s,   v3.4s,   v17.4s
+        add             v4.4s,   v4.4s,   v18.4s
+        add             v5.4s,   v5.4s,   v19.4s
+        rshrn           v2.4h,   v2.4s,   #6     // (diff + sign + 32) >> 6 = apply_sign()
+        rshrn2          v2.8h,   v3.4s,   #6
+        rshrn           v3.4h,   v4.4s,   #6
+        rshrn2          v3.8h,   v5.4s,   #6
+        add             v2.8h,   v2.8h,   v0.8h  // dc + apply_sign()
+        add             v3.8h,   v3.8h,   v0.8h
+        smax            v2.8h,   v2.8h,   v30.8h
+        smax            v3.8h,   v3.8h,   v30.8h
+        smin            v2.8h,   v2.8h,   v31.8h
+        smin            v3.8h,   v3.8h,   v31.8h
+        st1             {v2.8h},  [x0], x1
+        st1             {v3.8h},  [x6], x1
+        b.gt            1b
+        ret
+L(ipred_cfl_splat_w16):
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x5,  w3, uxtw #1
+        sub             x1,  x1,  w3, uxtw #1
+        mov             w9,  w3
+1:
+        ld1             {v2.8h, v3.8h}, [x5], #32
+        ld1             {v4.8h, v5.8h}, [x7], #32
+        subs            w3,  w3,  #16
+        smull           v16.4s,  v2.4h,   v1.4h  // diff = ac * alpha
+        smull2          v17.4s,  v2.8h,   v1.8h
+        smull           v18.4s,  v3.4h,   v1.4h
+        smull2          v19.4s,  v3.8h,   v1.8h
+        smull           v2.4s,   v4.4h,   v1.4h
+        smull2          v3.4s,   v4.8h,   v1.8h
+        smull           v4.4s,   v5.4h,   v1.4h
+        smull2          v5.4s,   v5.8h,   v1.8h
+        cmlt            v20.4s,  v16.4s,  #0     // sign
+        cmlt            v21.4s,  v17.4s,  #0
+        cmlt            v22.4s,  v18.4s,  #0
+        cmlt            v23.4s,  v19.4s,  #0
+        cmlt            v24.4s,  v2.4s,   #0
+        cmlt            v25.4s,  v3.4s,   #0
+        cmlt            v26.4s,  v4.4s,   #0
+        cmlt            v27.4s,  v5.4s,   #0
+        add             v16.4s,  v16.4s,  v20.4s // diff + sign
+        add             v17.4s,  v17.4s,  v21.4s
+        add             v18.4s,  v18.4s,  v22.4s
+        add             v19.4s,  v19.4s,  v23.4s
+        add             v2.4s,   v2.4s,   v24.4s
+        add             v3.4s,   v3.4s,   v25.4s
+        add             v4.4s,   v4.4s,   v26.4s
+        add             v5.4s,   v5.4s,   v27.4s
+        rshrn           v16.4h,  v16.4s,  #6     // (diff + sign + 32) >> 6 = apply_sign()
+        rshrn2          v16.8h,  v17.4s,  #6
+        rshrn           v17.4h,  v18.4s,  #6
+        rshrn2          v17.8h,  v19.4s,  #6
+        rshrn           v6.4h,   v2.4s,   #6
+        rshrn2          v6.8h,   v3.4s,   #6
+        rshrn           v7.4h,   v4.4s,   #6
+        rshrn2          v7.8h,   v5.4s,   #6
+        add             v2.8h,   v16.8h,  v0.8h  // dc + apply_sign()
+        add             v3.8h,   v17.8h,  v0.8h
+        add             v4.8h,   v6.8h,   v0.8h
+        add             v5.8h,   v7.8h,   v0.8h
+        smax            v2.8h,   v2.8h,   v30.8h
+        smax            v3.8h,   v3.8h,   v30.8h
+        smax            v4.8h,   v4.8h,   v30.8h
+        smax            v5.8h,   v5.8h,   v30.8h
+        smin            v2.8h,   v2.8h,   v31.8h
+        smin            v3.8h,   v3.8h,   v31.8h
+        smin            v4.8h,   v4.8h,   v31.8h
+        smin            v5.8h,   v5.8h,   v31.8h
+        st1             {v2.8h, v3.8h},  [x0], #32
+        st1             {v4.8h, v5.8h},  [x6], #32
+        b.gt            1b
+        subs            w4,  w4,  #2
+        add             x5,  x5,  w9, uxtw #1
+        add             x7,  x7,  w9, uxtw #1
+        add             x0,  x0,  x1
+        add             x6,  x6,  x1
+        mov             w3,  w9
+        b.gt            1b
+        ret
+endfunc
+
+jumptable ipred_cfl_128_tbl
+ipred_cfl_splat_tbl:
+        .word L(ipred_cfl_splat_w16) - ipred_cfl_128_tbl
+        .word L(ipred_cfl_splat_w16) - ipred_cfl_128_tbl
+        .word L(ipred_cfl_splat_w8) - ipred_cfl_128_tbl
+        .word L(ipred_cfl_splat_w4) - ipred_cfl_128_tbl
+endjumptable
+
+// void ipred_cfl_top_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                               const pixel *const topleft,
+//                               const int width, const int height,
+//                               const int16_t *ac, const int alpha,
+//                               const int bitdepth_max);
+function ipred_cfl_top_16bpc_neon, export=1
+        dup             v31.8h,  w7   // bitdepth_max
+        clz             w9,  w3
+        movrel          x7,  ipred_cfl_top_tbl
+        sub             w9,  w9,  #26
+        ldrsw           x9,  [x7, w9, uxtw #2]
+        dup             v1.8h,   w6   // alpha
+        add             x2,  x2,  #2
+        add             x7,  x7,  x9
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        movi            v30.8h,  #0
+        br              x7
+4:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.4h},  [x2]
+        addv            h0,      v0.4h
+        urshr           v0.4h,   v0.4h,   #2
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w4)
+8:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h},  [x2]
+        addv            h0,      v0.8h
+        urshr           v0.4h,   v0.4h,   #3
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w8)
+16:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h, v3.8h}, [x2]
+        addp            v0.8h,   v2.8h,   v3.8h
+        addv            h0,      v0.8h
+        urshr           v0.4h,   v0.4h,   #4
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w16)
+32:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h, v3.8h, v4.8h, v5.8h}, [x2]
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v0.8h,   v2.8h,   v4.8h
+        uaddlv          s0,      v0.8h
+        rshrn           v0.4h,   v0.4s,   #5
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w16)
+endfunc
+
+jumptable ipred_cfl_top_tbl
+        .word 32b - ipred_cfl_top_tbl
+        .word 16b - ipred_cfl_top_tbl
+        .word 8b  - ipred_cfl_top_tbl
+        .word 4b  - ipred_cfl_top_tbl
+endjumptable
+
+// void ipred_cfl_left_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                const pixel *const topleft,
+//                                const int width, const int height,
+//                                const int16_t *ac, const int alpha,
+//                                const int bitdepth_max);
+function ipred_cfl_left_16bpc_neon, export=1
+        dup             v31.8h,  w7   // bitdepth_max
+        sub             x2,  x2,  w4, uxtw #1
+        clz             w9,  w3
+        clz             w8,  w4
+        movrel          x10, ipred_cfl_splat_tbl
+        movrel          x7,  ipred_cfl_left_tbl
+        sub             w9,  w9,  #26
+        sub             w8,  w8,  #26
+        ldrsw           x9,  [x10, w9, uxtw #2]
+        ldrsw           x8,  [x7,  w8, uxtw #2]
+        dup             v1.8h,   w6   // alpha
+        add             x9,  x10, x9
+        add             x7,  x7,  x8
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        movi            v30.8h,  #0
+        br              x7
+
+L(ipred_cfl_left_h4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.4h},  [x2]
+        addv            h0,      v0.4h
+        urshr           v0.4h,   v0.4h,   #2
+        dup             v0.8h,   v0.h[0]
+        br              x9
+
+L(ipred_cfl_left_h8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h},  [x2]
+        addv            h0,      v0.8h
+        urshr           v0.4h,   v0.4h,   #3
+        dup             v0.8h,   v0.h[0]
+        br              x9
+
+L(ipred_cfl_left_h16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h, v3.8h}, [x2]
+        addp            v0.8h,   v2.8h,   v3.8h
+        addv            h0,      v0.8h
+        urshr           v0.4h,   v0.4h,   #4
+        dup             v0.8h,   v0.h[0]
+        br              x9
+
+L(ipred_cfl_left_h32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h, v3.8h, v4.8h, v5.8h}, [x2]
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v0.8h,   v2.8h,   v4.8h
+        uaddlv          s0,      v0.8h
+        rshrn           v0.4h,   v0.4s,   #5
+        dup             v0.8h,   v0.h[0]
+        br              x9
+endfunc
+
+jumptable ipred_cfl_left_tbl
+        .word L(ipred_cfl_left_h32) - ipred_cfl_left_tbl
+        .word L(ipred_cfl_left_h16) - ipred_cfl_left_tbl
+        .word L(ipred_cfl_left_h8)  - ipred_cfl_left_tbl
+        .word L(ipred_cfl_left_h4)  - ipred_cfl_left_tbl
+endjumptable
+
+// void ipred_cfl_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                           const pixel *const topleft,
+//                           const int width, const int height,
+//                           const int16_t *ac, const int alpha,
+//                           const int bitdepth_max);
+function ipred_cfl_16bpc_neon, export=1
+        dup             v31.8h,  w7              // bitdepth_max
+        sub             x2,  x2,  w4, uxtw #1
+        add             w8,  w3,  w4             // width + height
+        dup             v1.8h,   w6              // alpha
+        clz             w9,  w3
+        clz             w6,  w4
+        dup             v16.4s, w8               // width + height
+        movrel          x7,  ipred_cfl_tbl
+        rbit            w8,  w8                  // rbit(width + height)
+        sub             w9,  w9,  #22            // 26 leading bits, minus table offset 4
+        sub             w6,  w6,  #26
+        clz             w8,  w8                  // ctz(width + height)
+        ldrsw           x9,  [x7, w9, uxtw #2]
+        ldrsw           x6,  [x7, w6, uxtw #2]
+        neg             w8,  w8                  // -ctz(width + height)
+        add             x9,  x7,  x9
+        add             x7,  x7,  x6
+        ushr            v16.4s,  v16.4s,  #1     // (width + height) >> 1
+        dup             v17.4s,  w8              // -ctz(width + height)
+        add             x6,  x0,  x1
+        lsl             x1,  x1,  #1
+        movi            v30.8h,  #0
+        br              x7
+
+L(ipred_cfl_h4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.4h},  [x2], #8
+        uaddlv          s0,      v0.4h
+        add             x2,  x2,  #2
+        br              x9
+L(ipred_cfl_w4):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.4h},  [x2]
+        add             v0.2s,   v0.2s,   v16.2s
+        uaddlv          s2,      v2.4h
+        cmp             w4,  #4
+        add             v0.2s,   v0.2s,   v2.2s
+        ushl            v0.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 8/16
+        cmp             w4,  #16
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v0.2s,   v0.2s,   v16.2s
+        ushr            v0.2s,   v0.2s,   #17
+1:
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w4)
+
+L(ipred_cfl_h8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8h},  [x2], #16
+        uaddlv          s0,      v0.8h
+        add             x2,  x2,  #2
+        br              x9
+L(ipred_cfl_w8):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h},  [x2]
+        add             v0.2s,   v0.2s,   v16.2s
+        uaddlv          s2,      v2.8h
+        cmp             w4,  #8
+        add             v0.2s,   v0.2s,   v2.2s
+        ushl            v0.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 4/16/32
+        cmp             w4,  #32
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v0.2s,   v0.2s,   v16.2s
+        ushr            v0.2s,   v0.2s,   #17
+1:
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w8)
+
+L(ipred_cfl_h16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h, v3.8h}, [x2], #32
+        addp            v0.8h,   v2.8h,   v3.8h
+        add             x2,  x2,  #2
+        uaddlv          s0,      v0.8h
+        br              x9
+L(ipred_cfl_w16):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h, v3.8h}, [x2]
+        add             v0.2s,   v0.2s,   v16.2s
+        addp            v2.8h,   v2.8h,   v3.8h
+        uaddlv          s2,      v2.8h
+        cmp             w4,  #16
+        add             v0.2s,   v0.2s,   v2.2s
+        ushl            v0.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 4/8/32
+        tst             w4,  #(32+16+8) // 16 added to make a consecutive bitmask
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v0.2s,   v0.2s,   v16.2s
+        ushr            v0.2s,   v0.2s,   #17
+1:
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w16)
+
+L(ipred_cfl_h32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h, v3.8h, v4.8h, v5.8h}, [x2], #64
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v0.8h,   v2.8h,   v4.8h
+        add             x2,  x2,  #2
+        uaddlv          s0,      v0.8h
+        br              x9
+L(ipred_cfl_w32):
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v2.8h, v3.8h, v4.8h, v5.8h}, [x2]
+        add             v0.4s,   v0.4s,   v16.4s
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v2.8h,   v2.8h,   v4.8h
+        cmp             w4,  #32
+        uaddlv          s2,      v2.8h
+        add             v0.2s,   v0.2s,   v2.2s
+        ushl            v0.2s,   v0.2s,   v17.2s
+        b.eq            1f
+        // h = 8/16
+        cmp             w4,  #8
+        mov             w16, #0x6667
+        mov             w17, #0xAAAB
+        csel            w16, w16, w17, eq
+        dup             v16.2s,  w16
+        mul             v0.2s,   v0.2s,   v16.2s
+        ushr            v0.2s,   v0.2s,   #17
+1:
+        dup             v0.8h,   v0.h[0]
+        b               L(ipred_cfl_splat_w16)
+endfunc
+
+jumptable ipred_cfl_tbl
+        .word L(ipred_cfl_h32) - ipred_cfl_tbl
+        .word L(ipred_cfl_h16) - ipred_cfl_tbl
+        .word L(ipred_cfl_h8)  - ipred_cfl_tbl
+        .word L(ipred_cfl_h4)  - ipred_cfl_tbl
+        .word L(ipred_cfl_w32) - ipred_cfl_tbl
+        .word L(ipred_cfl_w16) - ipred_cfl_tbl
+        .word L(ipred_cfl_w8)  - ipred_cfl_tbl
+        .word L(ipred_cfl_w4)  - ipred_cfl_tbl
+endjumptable
+
+// void cfl_ac_420_16bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                            const ptrdiff_t stride, const int w_pad,
+//                            const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_420_16bpc_neon, export=1
+        clz             w8,  w5
+        lsl             w4,  w4,  #2
+        movrel          x7,  ipred_cfl_ac_420_tbl
+        sub             w8,  w8,  #27
+        ldrsw           x8,  [x7, w8, uxtw #2]
+        movi            v24.4s,  #0
+        movi            v25.4s,  #0
+        movi            v26.4s,  #0
+        movi            v27.4s,  #0
+        add             x7,  x7,  x8
+        sub             w8,  w6,  w4         // height - h_pad
+        rbit            w9,  w5              // rbit(width)
+        rbit            w10, w6              // rbit(height)
+        clz             w9,  w9              // ctz(width)
+        clz             w10, w10             // ctz(height)
+        add             w9,  w9,  w10        // log2sz
+        add             x10, x1,  x2
+        dup             v31.4s,  w9
+        lsl             x2,  x2,  #1
+        neg             v31.4s,  v31.4s      // -log2sz
+        br              x7
+
+L(ipred_cfl_ac_420_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input
+        ld1             {v0.8h}, [x1],  x2
+        ld1             {v1.8h}, [x10], x2
+        ld1             {v2.8h}, [x1],  x2
+        ld1             {v3.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v2.8h
+        addp            v1.8h,   v1.8h,   v3.8h
+        add             v0.8h,   v0.8h,   v1.8h
+        shl             v0.8h,   v0.8h,   #1
+        subs            w8,  w8,  #2
+        st1             {v0.8h}, [x0], #16
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        b.gt            1b
+        trn2            v1.2d,   v0.2d,   v0.2d
+        trn2            v0.2d,   v0.2d,   v0.2d
+L(ipred_cfl_ac_420_w4_hpad):
+        cbz             w4,  3f
+2:      // Vertical padding (h_pad > 0)
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], #32
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        b.gt            2b
+3:
+L(ipred_cfl_ac_420_w4_calc_subtract_dc):
+        // Aggregate the sums
+        add             v24.4s,  v24.4s,  v25.4s
+        add             v26.4s,  v26.4s,  v27.4s
+        add             v0.4s,   v24.4s,  v26.4s
+        addv            s0,  v0.4s                // sum
+        sub             x0,  x0,  w6, uxtw #3
+        urshl           v4.2s,   v0.2s,   v31.2s  // (sum + (1 << (log2sz - 1)))  >>= log2sz
+        dup             v4.8h,   v4.h[0]
+6:      // Subtract dc from ac
+        ld1             {v0.8h, v1.8h}, [x0]
+        subs            w6,  w6,  #4
+        sub             v0.8h,   v0.8h,   v4.8h
+        sub             v1.8h,   v1.8h,   v4.8h
+        st1             {v0.8h, v1.8h}, [x0], #32
+        b.gt            6b
+        ret
+
+L(ipred_cfl_ac_420_w8):
+        AARCH64_VALID_JUMP_TARGET
+        cbnz            w3,  L(ipred_cfl_ac_420_w8_wpad)
+1:      // Copy and subsample input, without padding
+        ld1             {v0.8h, v1.8h}, [x1],  x2
+        ld1             {v2.8h, v3.8h}, [x10], x2
+        ld1             {v4.8h, v5.8h}, [x1],  x2
+        addp            v0.8h,   v0.8h,   v1.8h
+        ld1             {v6.8h, v7.8h}, [x10], x2
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+        add             v0.8h,   v0.8h,   v2.8h
+        add             v4.8h,   v4.8h,   v6.8h
+        shl             v0.8h,   v0.8h,   #1
+        shl             v1.8h,   v4.8h,   #1
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h}, [x0], #32
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        b.gt            1b
+        mov             v0.16b,  v1.16b
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_420_w8_wpad):
+1:      // Copy and subsample input, padding 4
+        ld1             {v0.8h}, [x1],  x2
+        ld1             {v1.8h}, [x10], x2
+        ld1             {v2.8h}, [x1],  x2
+        ld1             {v3.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v2.8h
+        addp            v1.8h,   v1.8h,   v3.8h
+        add             v0.8h,   v0.8h,   v1.8h
+        shl             v0.8h,   v0.8h,   #1
+        dup             v1.4h,   v0.h[3]
+        dup             v3.4h,   v0.h[7]
+        trn2            v2.2d,   v0.2d,   v0.2d
+        subs            w8,  w8,  #2
+        st1             {v0.4h, v1.4h, v2.4h, v3.4h}, [x0], #32
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw           v25.4s,  v25.4s,  v1.4h
+        uaddw           v26.4s,  v26.4s,  v2.4h
+        uaddw           v27.4s,  v27.4s,  v3.4h
+        b.gt            1b
+        trn1            v0.2d,   v2.2d,   v3.2d
+        trn1            v1.2d,   v2.2d,   v3.2d
+
+L(ipred_cfl_ac_420_w8_hpad):
+        cbz             w4,  3f
+2:      // Vertical padding (h_pad > 0)
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h}, [x0], #32
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        st1             {v0.8h, v1.8h}, [x0], #32
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        b.gt            2b
+3:
+
+        // Double the height and reuse the w4 summing/subtracting
+        lsl             w6,  w6,  #1
+        b               L(ipred_cfl_ac_420_w4_calc_subtract_dc)
+
+L(ipred_cfl_ac_420_w16):
+        AARCH64_VALID_JUMP_TARGET
+        movrel          x7,  ipred_cfl_ac_420_w16_tbl
+        ldrsw           x3,  [x7, w3, uxtw #2]
+        add             x7,  x7,  x3
+        br              x7
+
+L(ipred_cfl_ac_420_w16_wpad0):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, without padding
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x1],  x2
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+        ld1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x1],  x2
+        add             v0.8h,   v0.8h,   v4.8h
+        ld1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x10], x2
+        add             v2.8h,   v2.8h,   v6.8h
+        addp            v16.8h,  v16.8h,  v17.8h
+        addp            v18.8h,  v18.8h,  v19.8h
+        addp            v20.8h,  v20.8h,  v21.8h
+        addp            v22.8h,  v22.8h,  v23.8h
+        add             v16.8h,  v16.8h,  v20.8h
+        add             v18.8h,  v18.8h,  v22.8h
+        shl             v0.8h,   v0.8h,   #1
+        shl             v1.8h,   v2.8h,   #1
+        shl             v2.8h,   v16.8h,  #1
+        shl             v3.8h,   v18.8h,  #1
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad1):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 4
+        ldr             q2,  [x1,  #32]
+        ld1             {v0.8h, v1.8h}, [x1],  x2
+        ldr             q5,  [x10, #32]
+        ld1             {v3.8h, v4.8h}, [x10], x2
+        addp            v2.8h,   v2.8h,   v2.8h
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v5.8h,   v5.8h,   v5.8h
+        addp            v3.8h,   v3.8h,   v4.8h
+        ldr             q18, [x1,  #32]
+        add             v2.4h,   v2.4h,   v5.4h
+        ld1             {v16.8h, v17.8h}, [x1],  x2
+        add             v0.8h,   v0.8h,   v3.8h
+        ldr             q21, [x10, #32]
+        ld1             {v19.8h, v20.8h}, [x10], x2
+        addp            v18.8h,  v18.8h,  v18.8h
+        addp            v16.8h,  v16.8h,  v17.8h
+        addp            v21.8h,  v21.8h,  v21.8h
+        addp            v19.8h,  v19.8h,  v20.8h
+        add             v18.4h,  v18.4h,  v21.4h
+        add             v16.8h,  v16.8h,  v19.8h
+        shl             v1.4h,   v2.4h,   #1
+        shl             v0.8h,   v0.8h,   #1
+        shl             v3.4h,   v18.4h,  #1
+        shl             v2.8h,   v16.8h,  #1
+        dup             v4.4h,   v1.h[3]
+        dup             v5.4h,   v3.h[3]
+        trn1            v1.2d,   v1.2d,   v4.2d
+        trn1            v3.2d,   v3.2d,   v5.2d
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad2):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 8
+        ld1             {v0.8h, v1.8h}, [x1],  x2
+        ld1             {v2.8h, v3.8h}, [x10], x2
+        ld1             {v4.8h, v5.8h}, [x1],  x2
+        addp            v0.8h,   v0.8h,   v1.8h
+        ld1             {v6.8h, v7.8h}, [x10], x2
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+        add             v0.8h,   v0.8h,   v2.8h
+        add             v4.8h,   v4.8h,   v6.8h
+        shl             v0.8h,   v0.8h,   #1
+        shl             v2.8h,   v4.8h,   #1
+        dup             v1.8h,   v0.h[7]
+        dup             v3.8h,   v2.h[7]
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_420_w16_wpad3):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 12
+        ld1             {v0.8h}, [x1],  x2
+        ld1             {v2.8h}, [x10], x2
+        ld1             {v4.8h}, [x1],  x2
+        ld1             {v6.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v4.8h
+        addp            v2.8h,   v2.8h,   v6.8h
+        add             v0.8h,   v0.8h,   v2.8h
+        shl             v0.8h,   v0.8h,   #1
+        dup             v1.8h,   v0.h[3]
+        dup             v3.8h,   v0.h[7]
+        trn2            v2.2d,   v0.2d,   v3.2d
+        trn1            v0.2d,   v0.2d,   v1.2d
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+
+L(ipred_cfl_ac_420_w16_hpad):
+        cbz             w4,  3f
+2:      // Vertical padding (h_pad > 0)
+        subs            w4,  w4,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            2b
+3:
+
+        // Quadruple the height and reuse the w4 summing/subtracting
+        lsl             w6,  w6,  #2
+        b               L(ipred_cfl_ac_420_w4_calc_subtract_dc)
+endfunc
+
+jumptable ipred_cfl_ac_420_tbl
+        .word L(ipred_cfl_ac_420_w16) - ipred_cfl_ac_420_tbl
+        .word L(ipred_cfl_ac_420_w8)  - ipred_cfl_ac_420_tbl
+        .word L(ipred_cfl_ac_420_w4)  - ipred_cfl_ac_420_tbl
+endjumptable
+
+jumptable ipred_cfl_ac_420_w16_tbl
+        .word L(ipred_cfl_ac_420_w16_wpad0) - ipred_cfl_ac_420_w16_tbl
+        .word L(ipred_cfl_ac_420_w16_wpad1) - ipred_cfl_ac_420_w16_tbl
+        .word L(ipred_cfl_ac_420_w16_wpad2) - ipred_cfl_ac_420_w16_tbl
+        .word L(ipred_cfl_ac_420_w16_wpad3) - ipred_cfl_ac_420_w16_tbl
+endjumptable
+
+// void cfl_ac_422_16bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                            const ptrdiff_t stride, const int w_pad,
+//                            const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_422_16bpc_neon, export=1
+        clz             w8,  w5
+        lsl             w4,  w4,  #2
+        movrel          x7,  ipred_cfl_ac_422_tbl
+        sub             w8,  w8,  #27
+        ldrsw           x8,  [x7, w8, uxtw #2]
+        movi            v24.4s,  #0
+        movi            v25.4s,  #0
+        movi            v26.4s,  #0
+        movi            v27.4s,  #0
+        add             x7,  x7,  x8
+        sub             w8,  w6,  w4         // height - h_pad
+        rbit            w9,  w5              // rbit(width)
+        rbit            w10, w6              // rbit(height)
+        clz             w9,  w9              // ctz(width)
+        clz             w10, w10             // ctz(height)
+        add             w9,  w9,  w10        // log2sz
+        add             x10, x1,  x2
+        dup             v31.4s,  w9
+        lsl             x2,  x2,  #1
+        neg             v31.4s,  v31.4s      // -log2sz
+        br              x7
+
+L(ipred_cfl_ac_422_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input
+        ld1             {v0.8h}, [x1],  x2
+        ld1             {v1.8h}, [x10], x2
+        ld1             {v2.8h}, [x1],  x2
+        ld1             {v3.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        shl             v0.8h,   v0.8h,   #2
+        shl             v1.8h,   v2.8h,   #2
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h}, [x0], #32
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        b.gt            1b
+        trn2            v0.2d,   v1.2d,   v1.2d
+        trn2            v1.2d,   v1.2d,   v1.2d
+        b               L(ipred_cfl_ac_420_w4_hpad)
+
+L(ipred_cfl_ac_422_w8):
+        AARCH64_VALID_JUMP_TARGET
+        cbnz            w3,  L(ipred_cfl_ac_422_w8_wpad)
+1:      // Copy and subsample input, without padding
+        ld1             {v0.8h, v1.8h}, [x1],  x2
+        ld1             {v2.8h, v3.8h}, [x10], x2
+        ld1             {v4.8h, v5.8h}, [x1],  x2
+        addp            v0.8h,   v0.8h,   v1.8h
+        ld1             {v6.8h, v7.8h}, [x10], x2
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+        shl             v0.8h,   v0.8h,   #2
+        shl             v1.8h,   v2.8h,   #2
+        shl             v2.8h,   v4.8h,   #2
+        shl             v3.8h,   v6.8h,   #2
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v3.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_422_w8_wpad):
+1:      // Copy and subsample input, padding 4
+        ld1             {v0.8h}, [x1],  x2
+        ld1             {v1.8h}, [x10], x2
+        ld1             {v2.8h}, [x1],  x2
+        ld1             {v3.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        shl             v0.8h,   v0.8h,   #2
+        shl             v2.8h,   v2.8h,   #2
+        dup             v4.4h,   v0.h[3]
+        dup             v5.8h,   v0.h[7]
+        dup             v6.4h,   v2.h[3]
+        dup             v7.8h,   v2.h[7]
+        trn2            v1.2d,   v0.2d,   v5.2d
+        trn1            v0.2d,   v0.2d,   v4.2d
+        trn2            v3.2d,   v2.2d,   v7.2d
+        trn1            v2.2d,   v2.2d,   v6.2d
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v3.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_422_w16):
+        AARCH64_VALID_JUMP_TARGET
+        movrel          x7,  ipred_cfl_ac_422_w16_tbl
+        ldrsw           x3,  [x7, w3, uxtw #2]
+        add             x7,  x7,  x3
+        br              x7
+
+L(ipred_cfl_ac_422_w16_wpad0):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, without padding
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x1],  x2
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+        shl             v0.8h,   v0.8h,   #2
+        shl             v1.8h,   v2.8h,   #2
+        shl             v2.8h,   v4.8h,   #2
+        shl             v3.8h,   v6.8h,   #2
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad1):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 4
+        ldr             q2,  [x1,  #32]
+        ld1             {v0.8h, v1.8h}, [x1],  x2
+        ldr             q6,  [x10, #32]
+        ld1             {v4.8h, v5.8h}, [x10], x2
+        addp            v2.8h,   v2.8h,   v2.8h
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v6.8h,   v6.8h,   v6.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        shl             v1.4h,   v2.4h,   #2
+        shl             v0.8h,   v0.8h,   #2
+        shl             v3.4h,   v6.4h,   #2
+        shl             v2.8h,   v4.8h,   #2
+        dup             v4.4h,   v1.h[3]
+        dup             v5.4h,   v3.h[3]
+        trn1            v1.2d,   v1.2d,   v4.2d
+        trn1            v3.2d,   v3.2d,   v5.2d
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad2):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 8
+        ld1             {v0.8h, v1.8h}, [x1],  x2
+        ld1             {v2.8h, v3.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        shl             v0.8h,   v0.8h,   #2
+        shl             v2.8h,   v2.8h,   #2
+        dup             v1.8h,   v0.h[7]
+        dup             v3.8h,   v2.h[7]
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_422_w16_wpad3):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and subsample input, padding 12
+        ld1             {v0.8h}, [x1],  x2
+        ld1             {v2.8h}, [x10], x2
+        addp            v0.8h,   v0.8h,   v0.8h
+        addp            v2.8h,   v2.8h,   v2.8h
+        shl             v0.4h,   v0.4h,   #2
+        shl             v2.4h,   v2.4h,   #2
+        dup             v1.8h,   v0.h[3]
+        dup             v3.8h,   v2.h[3]
+        trn1            v0.2d,   v0.2d,   v1.2d
+        trn1            v2.2d,   v2.2d,   v3.2d
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+endfunc
+
+jumptable ipred_cfl_ac_422_tbl
+        .word L(ipred_cfl_ac_422_w16) - ipred_cfl_ac_422_tbl
+        .word L(ipred_cfl_ac_422_w8)  - ipred_cfl_ac_422_tbl
+        .word L(ipred_cfl_ac_422_w4)  - ipred_cfl_ac_422_tbl
+endjumptable
+
+jumptable ipred_cfl_ac_422_w16_tbl
+        .word L(ipred_cfl_ac_422_w16_wpad0) - ipred_cfl_ac_422_w16_tbl
+        .word L(ipred_cfl_ac_422_w16_wpad1) - ipred_cfl_ac_422_w16_tbl
+        .word L(ipred_cfl_ac_422_w16_wpad2) - ipred_cfl_ac_422_w16_tbl
+        .word L(ipred_cfl_ac_422_w16_wpad3) - ipred_cfl_ac_422_w16_tbl
+endjumptable
+
+// void cfl_ac_444_16bpc_neon(int16_t *const ac, const pixel *const ypx,
+//                            const ptrdiff_t stride, const int w_pad,
+//                            const int h_pad, const int cw, const int ch);
+function ipred_cfl_ac_444_16bpc_neon, export=1
+        clz             w8,  w5
+        lsl             w4,  w4,  #2
+        movrel          x7,  ipred_cfl_ac_444_tbl
+        sub             w8,  w8,  #26
+        ldrsw           x8,  [x7, w8, uxtw #2]
+        movi            v24.4s,  #0
+        movi            v25.4s,  #0
+        movi            v26.4s,  #0
+        movi            v27.4s,  #0
+        add             x7,  x7,  x8
+        sub             w8,  w6,  w4         // height - h_pad
+        rbit            w9,  w5              // rbit(width)
+        rbit            w10, w6              // rbit(height)
+        clz             w9,  w9              // ctz(width)
+        clz             w10, w10             // ctz(height)
+        add             w9,  w9,  w10        // log2sz
+        add             x10, x1,  x2
+        dup             v31.4s,  w9
+        lsl             x2,  x2,  #1
+        neg             v31.4s,  v31.4s      // -log2sz
+        br              x7
+
+L(ipred_cfl_ac_444_w4):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input
+        ld1             {v0.4h},   [x1],  x2
+        ld1             {v0.d}[1], [x10], x2
+        ld1             {v1.4h},   [x1],  x2
+        ld1             {v1.d}[1], [x10], x2
+        shl             v0.8h,   v0.8h,   #3
+        shl             v1.8h,   v1.8h,   #3
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h}, [x0], #32
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        b.gt            1b
+        trn2            v0.2d,   v1.2d,   v1.2d
+        trn2            v1.2d,   v1.2d,   v1.2d
+        b               L(ipred_cfl_ac_420_w4_hpad)
+
+L(ipred_cfl_ac_444_w8):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input
+        ld1             {v0.8h}, [x1],  x2
+        ld1             {v1.8h}, [x10], x2
+        ld1             {v2.8h}, [x1],  x2
+        shl             v0.8h,   v0.8h,   #3
+        ld1             {v3.8h}, [x10], x2
+        shl             v1.8h,   v1.8h,   #3
+        shl             v2.8h,   v2.8h,   #3
+        shl             v3.8h,   v3.8h,   #3
+        subs            w8,  w8,  #4
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v3.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w8_hpad)
+
+L(ipred_cfl_ac_444_w16):
+        AARCH64_VALID_JUMP_TARGET
+        cbnz            w3,  L(ipred_cfl_ac_444_w16_wpad)
+1:      // Copy and expand input, without padding
+        ld1             {v0.8h, v1.8h}, [x1],  x2
+        ld1             {v2.8h, v3.8h}, [x10], x2
+        shl             v0.8h,   v0.8h,   #3
+        shl             v1.8h,   v1.8h,   #3
+        shl             v2.8h,   v2.8h,   #3
+        shl             v3.8h,   v3.8h,   #3
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_444_w16_wpad):
+1:      // Copy and expand input, padding 8
+        ld1             {v0.8h}, [x1],  x2
+        ld1             {v2.8h}, [x10], x2
+        shl             v0.8h,   v0.8h,   #3
+        shl             v2.8h,   v2.8h,   #3
+        dup             v1.8h,   v0.h[7]
+        dup             v3.8h,   v2.h[7]
+        subs            w8,  w8,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        mov             v0.16b,  v2.16b
+        mov             v1.16b,  v3.16b
+        b               L(ipred_cfl_ac_420_w16_hpad)
+
+L(ipred_cfl_ac_444_w32):
+        AARCH64_VALID_JUMP_TARGET
+        movrel          x7,  ipred_cfl_ac_444_w32_tbl
+        lsr             w3,  w3,  #1
+        ldrsw           x3,  [x7, w3, uxtw #2]
+        lsr             x2,  x2,  #1 // Restore the stride to one line increments
+        add             x7,  x7,  x3
+        br              x7
+
+L(ipred_cfl_ac_444_w32_wpad0):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input, without padding
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x1],  x2
+        shl             v0.8h,   v0.8h,   #3
+        shl             v1.8h,   v1.8h,   #3
+        shl             v2.8h,   v2.8h,   #3
+        shl             v3.8h,   v3.8h,   #3
+        subs            w8,  w8,  #1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad2):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input, padding 8
+        ld1             {v0.8h, v1.8h, v2.8h}, [x1],  x2
+        shl             v2.8h,   v2.8h,   #3
+        shl             v0.8h,   v0.8h,   #3
+        shl             v1.8h,   v1.8h,   #3
+        dup             v3.8h,   v2.h[7]
+        subs            w8,  w8,  #1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad4):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input, padding 16
+        ld1             {v0.8h, v1.8h}, [x1],  x2
+        shl             v1.8h,   v1.8h,   #3
+        shl             v0.8h,   v0.8h,   #3
+        dup             v2.8h,   v1.h[7]
+        dup             v3.8h,   v1.h[7]
+        subs            w8,  w8,  #1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+        b               L(ipred_cfl_ac_444_w32_hpad)
+
+L(ipred_cfl_ac_444_w32_wpad6):
+        AARCH64_VALID_JUMP_TARGET
+1:      // Copy and expand input, padding 24
+        ld1             {v0.8h}, [x1],  x2
+        shl             v0.8h,   v0.8h,   #3
+        dup             v1.8h,   v0.h[7]
+        dup             v2.8h,   v0.h[7]
+        dup             v3.8h,   v0.h[7]
+        subs            w8,  w8,  #1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            1b
+
+L(ipred_cfl_ac_444_w32_hpad):
+        cbz             w4,  3f
+2:      // Vertical padding (h_pad > 0)
+        subs            w4,  w4,  #2
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        uaddw           v24.4s,  v24.4s,  v0.4h
+        uaddw2          v25.4s,  v25.4s,  v0.8h
+        uaddw           v26.4s,  v26.4s,  v1.4h
+        uaddw2          v27.4s,  v27.4s,  v1.8h
+        uaddw           v24.4s,  v24.4s,  v2.4h
+        uaddw2          v25.4s,  v25.4s,  v2.8h
+        uaddw           v26.4s,  v26.4s,  v3.4h
+        uaddw2          v27.4s,  v27.4s,  v3.8h
+        b.gt            2b
+3:
+
+        //  Multiply the height by eight and reuse the w4 subtracting
+        lsl             w6,  w6,  #3
+        b               L(ipred_cfl_ac_420_w4_calc_subtract_dc)
+endfunc
+
+jumptable ipred_cfl_ac_444_tbl
+        .word L(ipred_cfl_ac_444_w32) - ipred_cfl_ac_444_tbl
+        .word L(ipred_cfl_ac_444_w16) - ipred_cfl_ac_444_tbl
+        .word L(ipred_cfl_ac_444_w8)  - ipred_cfl_ac_444_tbl
+        .word L(ipred_cfl_ac_444_w4)  - ipred_cfl_ac_444_tbl
+endjumptable
+
+jumptable ipred_cfl_ac_444_w32_tbl
+        .word L(ipred_cfl_ac_444_w32_wpad0) - ipred_cfl_ac_444_w32_tbl
+        .word L(ipred_cfl_ac_444_w32_wpad2) - ipred_cfl_ac_444_w32_tbl
+        .word L(ipred_cfl_ac_444_w32_wpad4) - ipred_cfl_ac_444_w32_tbl
+        .word L(ipred_cfl_ac_444_w32_wpad6) - ipred_cfl_ac_444_w32_tbl
+endjumptable
diff --git a/media/libdav1d/src/src/arm/64/itx.S b/media/libdav1d/src/src/arm/64/itx.S
new file mode 100644
index 0000000000..7063cbde1d
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/itx.S
@@ -0,0 +1,3270 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// The exported functions in this file have got the following signature:
+// void itxfm_add(pixel *dst, ptrdiff_t dst_stride, coef *coeff, int eob);
+
+// Most of the functions use the following register layout:
+// x0-x3  external parameters
+// x4     function pointer to first transform
+// x5     function pointer to second transform
+// x6     output parameter for helper function
+// x7     input parameter for helper function
+// x8     input stride for helper function
+// x9-x12 scratch variables for helper functions
+// x13    pointer to list of eob thresholds
+// x14    return pointer for helper function
+// x15    return pointer for main function
+
+// The SIMD registers most often use the following layout:
+// v0-v1   multiplication coefficients
+// v2-v7   scratch registers
+// v8-v15  unused
+// v16-v31 inputs/outputs of transforms
+
+// Potential further optimizations, that are left unimplemented for now:
+// - Trying to keep multiplication coefficients in registers across multiple
+//   transform functions. (The register layout is designed to potentially
+//   allow this.)
+// - Use a simplified version of the transforms themselves for cases where
+//   we know a significant number of inputs are zero. E.g. if the eob value
+//   indicates only a quarter of input values are set, for idct16 and up,
+//   a significant amount of calculation can be skipped, at the cost of more
+//   code duplication and special casing.
+
+const idct_coeffs, align=4
+        // idct4
+        .short          2896, 2896*8, 1567, 3784
+        // idct8
+        .short          799, 4017, 3406, 2276
+        // idct16
+        .short          401, 4076, 3166, 2598
+        .short          1931, 3612, 3920, 1189
+        // idct32
+        .short          201, 4091, 3035, 2751
+        .short          1751, 3703, 3857, 1380
+        .short          995, 3973, 3513, 2106
+        .short          2440, 3290, 4052, 601
+endconst
+
+const idct64_coeffs, align=4
+        .short          101*8, 4095*8, 2967*8, -2824*8
+        .short          1660*8, 3745*8, 3822*8, -1474*8
+        .short          4076, 401, 4017, 799
+        .short          0, 0, 0, 0
+
+        .short          4036*8, -700*8, 2359*8, 3349*8
+        .short          3461*8, -2191*8, 897*8, 3996*8
+        .short          -3166, -2598, -799, -4017
+        .short          0, 0, 0, 0
+
+        .short          501*8, 4065*8, 3229*8, -2520*8
+        .short          2019*8, 3564*8, 3948*8, -1092*8
+        .short          3612, 1931, 2276, 3406
+        .short          0, 0, 0, 0
+
+        .short          4085*8, -301*8, 2675*8, 3102*8
+        .short          3659*8, -1842*8, 1285*8, 3889*8
+        .short          -3920, -1189, -3406, -2276
+        .short          0, 0, 0, 0
+endconst
+
+const iadst4_coeffs, align=4
+        // .h[4-5] can be interpreted as .s[2]
+        .short          1321, 3803, 2482, 3344, 3344, 0
+endconst
+
+const iadst8_coeffs, align=4
+        .short          4076, 401, 3612, 1931
+        .short          2598, 3166, 1189, 3920
+        // idct_coeffs
+        .short          2896, 0, 1567, 3784, 0, 0, 0, 0
+endconst
+
+const iadst16_coeffs, align=4
+        .short          4091, 201, 3973, 995
+        .short          3703, 1751, 3290, 2440
+        .short          2751, 3035, 2106, 3513
+        .short          1380, 3857, 601, 4052
+endconst
+
+.macro smull_smlal d0, d1, s0, s1, c0, c1, sz
+        smull           \d0\().4s, \s0\().4h, \c0
+        smlal           \d0\().4s, \s1\().4h, \c1
+.ifc \sz, .8h
+        smull2          \d1\().4s, \s0\().8h, \c0
+        smlal2          \d1\().4s, \s1\().8h, \c1
+.endif
+.endm
+
+.macro smull_smlsl d0, d1, s0, s1, c0, c1, sz
+        smull           \d0\().4s, \s0\().4h, \c0
+        smlsl           \d0\().4s, \s1\().4h, \c1
+.ifc \sz, .8h
+        smull2          \d1\().4s, \s0\().8h, \c0
+        smlsl2          \d1\().4s, \s1\().8h, \c1
+.endif
+.endm
+
+.macro sqrshrn_sz d0, s0, s1, shift, sz
+        sqrshrn         \d0\().4h, \s0\().4s, \shift
+.ifc \sz, .8h
+        sqrshrn2        \d0\().8h, \s1\().4s, \shift
+.endif
+.endm
+
+.macro scale_input sz, c, r0, r1, r2 r3, r4, r5, r6, r7
+        sqrdmulh        \r0\sz,  \r0\sz,  \c
+        sqrdmulh        \r1\sz,  \r1\sz,  \c
+        sqrdmulh        \r2\sz,  \r2\sz,  \c
+        sqrdmulh        \r3\sz,  \r3\sz,  \c
+.ifnb \r4
+        sqrdmulh        \r4\sz,  \r4\sz,  \c
+        sqrdmulh        \r5\sz,  \r5\sz,  \c
+        sqrdmulh        \r6\sz,  \r6\sz,  \c
+        sqrdmulh        \r7\sz,  \r7\sz,  \c
+.endif
+.endm
+
+.macro load_add_store load, shift, addsrc, adddst, narrowsrc, narrowdst, store, dst, src, shiftbits=4
+.ifnb \load
+        ld1             {\load},  [\src], x1
+.endif
+.ifnb \shift
+        srshr           \shift,  \shift,  #\shiftbits
+.endif
+.ifnb \addsrc
+        uaddw           \adddst, \adddst, \addsrc
+.endif
+.ifnb \narrowsrc
+        sqxtun          \narrowdst, \narrowsrc
+.endif
+.ifnb \store
+        st1             {\store},  [\dst], x1
+.endif
+.endm
+.macro load_add_store_8x16 dst, src
+        mov             \src, \dst
+        load_add_store  v2.8b, v16.8h,      ,       ,       ,      ,      , \dst, \src
+        load_add_store  v3.8b, v17.8h,      ,       ,       ,      ,      , \dst, \src
+        load_add_store  v4.8b, v18.8h, v2.8b, v16.8h,       ,      ,      , \dst, \src
+        load_add_store  v5.8b, v19.8h, v3.8b, v17.8h, v16.8h, v2.8b,      , \dst, \src
+        load_add_store  v6.8b, v20.8h, v4.8b, v18.8h, v17.8h, v3.8b, v2.8b, \dst, \src
+        load_add_store  v7.8b, v21.8h, v5.8b, v19.8h, v18.8h, v4.8b, v3.8b, \dst, \src
+        load_add_store  v2.8b, v22.8h, v6.8b, v20.8h, v19.8h, v5.8b, v4.8b, \dst, \src
+        load_add_store  v3.8b, v23.8h, v7.8b, v21.8h, v20.8h, v6.8b, v5.8b, \dst, \src
+        load_add_store  v4.8b, v24.8h, v2.8b, v22.8h, v21.8h, v7.8b, v6.8b, \dst, \src
+        load_add_store  v5.8b, v25.8h, v3.8b, v23.8h, v22.8h, v2.8b, v7.8b, \dst, \src
+        load_add_store  v6.8b, v26.8h, v4.8b, v24.8h, v23.8h, v3.8b, v2.8b, \dst, \src
+        load_add_store  v7.8b, v27.8h, v5.8b, v25.8h, v24.8h, v4.8b, v3.8b, \dst, \src
+        load_add_store  v2.8b, v28.8h, v6.8b, v26.8h, v25.8h, v5.8b, v4.8b, \dst, \src
+        load_add_store  v3.8b, v29.8h, v7.8b, v27.8h, v26.8h, v6.8b, v5.8b, \dst, \src
+        load_add_store  v4.8b, v30.8h, v2.8b, v28.8h, v27.8h, v7.8b, v6.8b, \dst, \src
+        load_add_store  v5.8b, v31.8h, v3.8b, v29.8h, v28.8h, v2.8b, v7.8b, \dst, \src
+        load_add_store       ,       , v4.8b, v30.8h, v29.8h, v3.8b, v2.8b, \dst, \src
+        load_add_store       ,       , v5.8b, v31.8h, v30.8h, v4.8b, v3.8b, \dst, \src
+        load_add_store       ,       ,      ,       , v31.8h, v5.8b, v4.8b, \dst, \src
+        load_add_store       ,       ,      ,       ,       ,      , v5.8b, \dst, \src
+.endm
+.macro load_add_store_8x8 dst, src, shiftbits=4
+        mov             \src, \dst
+        load_add_store  v2.8b, v16.8h,      ,       ,       ,      ,      , \dst, \src, \shiftbits
+        load_add_store  v3.8b, v17.8h,      ,       ,       ,      ,      , \dst, \src, \shiftbits
+        load_add_store  v4.8b, v18.8h, v2.8b, v16.8h,       ,      ,      , \dst, \src, \shiftbits
+        load_add_store  v5.8b, v19.8h, v3.8b, v17.8h, v16.8h, v2.8b,      , \dst, \src, \shiftbits
+        load_add_store  v6.8b, v20.8h, v4.8b, v18.8h, v17.8h, v3.8b, v2.8b, \dst, \src, \shiftbits
+        load_add_store  v7.8b, v21.8h, v5.8b, v19.8h, v18.8h, v4.8b, v3.8b, \dst, \src, \shiftbits
+        load_add_store  v2.8b, v22.8h, v6.8b, v20.8h, v19.8h, v5.8b, v4.8b, \dst, \src, \shiftbits
+        load_add_store  v3.8b, v23.8h, v7.8b, v21.8h, v20.8h, v6.8b, v5.8b, \dst, \src, \shiftbits
+        load_add_store       ,       , v2.8b, v22.8h, v21.8h, v7.8b, v6.8b, \dst, \src, \shiftbits
+        load_add_store       ,       , v3.8b, v23.8h, v22.8h, v2.8b, v7.8b, \dst, \src, \shiftbits
+        load_add_store       ,       ,      ,       , v23.8h, v3.8b, v2.8b, \dst, \src, \shiftbits
+        load_add_store       ,       ,      ,       ,       ,      , v3.8b, \dst, \src, \shiftbits
+.endm
+.macro load_add_store_8x4 dst, src
+        mov             \src, \dst
+        load_add_store  v2.8b, v16.8h,      ,       ,       ,      ,      , \dst, \src
+        load_add_store  v3.8b, v17.8h,      ,       ,       ,      ,      , \dst, \src
+        load_add_store  v4.8b, v18.8h, v2.8b, v16.8h,       ,      ,      , \dst, \src
+        load_add_store  v5.8b, v19.8h, v3.8b, v17.8h, v16.8h, v2.8b,      , \dst, \src
+        load_add_store       ,       , v4.8b, v18.8h, v17.8h, v3.8b, v2.8b, \dst, \src
+        load_add_store       ,       , v5.8b, v19.8h, v18.8h, v4.8b, v3.8b, \dst, \src
+        load_add_store       ,       ,      ,       , v19.8h, v5.8b, v4.8b, \dst, \src
+        load_add_store       ,       ,      ,       ,       ,      , v5.8b, \dst, \src
+.endm
+.macro load_add_store4 load, inssrc, insdst, shift, addsrc, adddst, narrowsrc, narrowdst, store, dst, src
+.ifnb \load
+        ld1             {\load}[0],  [\src], x1
+.endif
+.ifnb \inssrc
+        ins             \insdst\().d[1],   \inssrc\().d[0]
+.endif
+.ifnb \shift
+        srshr           \shift,  \shift,  #4
+.endif
+.ifnb \load
+        ld1             {\load}[1],  [\src], x1
+.endif
+.ifnb \addsrc
+        uaddw           \adddst, \adddst, \addsrc
+.endif
+.ifnb \store
+        st1             {\store}[0],  [\dst], x1
+.endif
+.ifnb \narrowsrc
+        sqxtun          \narrowdst, \narrowsrc
+.endif
+.ifnb \store
+        st1             {\store}[1],  [\dst], x1
+.endif
+.endm
+.macro load_add_store_4x16 dst, src
+        mov             \src, \dst
+        load_add_store4 v0.s, v17, v16,       ,      ,       ,       ,      ,     , \dst, \src
+        load_add_store4 v1.s, v19, v18,       ,      ,       ,       ,      ,     , \dst, \src
+        load_add_store4 v2.s, v21, v20, v16.8h,      ,       ,       ,      ,     , \dst, \src
+        load_add_store4 v3.s, v23, v22, v18.8h, v0.8b, v16.8h,       ,      ,     , \dst, \src
+        load_add_store4 v4.s, v25, v24, v20.8h, v1.8b, v18.8h, v16.8h, v0.8b,     , \dst, \src
+        load_add_store4 v5.s, v27, v26, v22.8h, v2.8b, v20.8h, v18.8h, v1.8b, v0.s, \dst, \src
+        load_add_store4 v6.s, v29, v28, v24.8h, v3.8b, v22.8h, v20.8h, v2.8b, v1.s, \dst, \src
+        load_add_store4 v7.s, v31, v30, v26.8h, v4.8b, v24.8h, v22.8h, v3.8b, v2.s, \dst, \src
+        load_add_store4     ,    ,    , v28.8h, v5.8b, v26.8h, v24.8h, v4.8b, v3.s, \dst, \src
+        load_add_store4     ,    ,    , v30.8h, v6.8b, v28.8h, v26.8h, v5.8b, v4.s, \dst, \src
+        load_add_store4     ,    ,    ,       , v7.8b, v30.8h, v28.8h, v6.8b, v5.s, \dst, \src
+        load_add_store4     ,    ,    ,       ,      ,       , v30.8h, v7.8b, v6.s, \dst, \src
+        load_add_store4     ,    ,    ,       ,      ,       ,       ,      , v7.s, \dst, \src
+.endm
+.macro load_add_store_4x8 dst, src
+        mov             \src, \dst
+        load_add_store4 v0.s, v17, v16,       ,      ,       ,       ,      ,     , \dst, \src
+        load_add_store4 v1.s, v19, v18,       ,      ,       ,       ,      ,     , \dst, \src
+        load_add_store4 v2.s, v21, v20, v16.8h,      ,       ,       ,      ,     , \dst, \src
+        load_add_store4 v3.s, v23, v22, v18.8h, v0.8b, v16.8h,       ,      ,     , \dst, \src
+        load_add_store4     ,    ,    , v20.8h, v1.8b, v18.8h, v16.8h, v0.8b,     , \dst, \src
+        load_add_store4     ,    ,    , v22.8h, v2.8b, v20.8h, v18.8h, v1.8b, v0.s, \dst, \src
+        load_add_store4     ,    ,    ,       , v3.8b, v22.8h, v20.8h, v2.8b, v1.s, \dst, \src
+        load_add_store4     ,    ,    ,       ,      ,       , v22.8h, v3.8b, v2.s, \dst, \src
+        load_add_store4     ,    ,    ,       ,      ,       ,       ,      , v3.s, \dst, \src
+.endm
+
+.macro idct_dc w, h, shift
+        cbnz            w3,  1f
+        mov             w16, #2896*8
+        ld1r            {v16.8h}, [x2]
+        dup             v0.4h,   w16
+        sqrdmulh        v16.8h,  v16.8h,  v0.h[0]
+        strh            wzr, [x2]
+.if (\w == 2*\h) || (2*\w == \h)
+        sqrdmulh        v16.8h,  v16.8h,  v0.h[0]
+.endif
+.if \shift > 0
+        srshr           v16.8h,  v16.8h,  #\shift
+.endif
+        sqrdmulh        v16.8h,  v16.8h,  v0.h[0]
+        srshr           v16.8h,  v16.8h,  #4
+        mov             w4,  #\h
+        b               idct_dc_w\w\()_neon
+1:
+.endm
+
+function idct_dc_w4_neon
+1:
+        ld1             {v0.s}[0], [x0], x1
+        ld1             {v0.s}[1], [x0], x1
+        ld1             {v1.s}[0], [x0], x1
+        ld1             {v1.s}[1], [x0], x1
+        subs            w4,  w4,  #4
+        sub             x0,  x0,  x1, lsl #2
+        uaddw           v0.8h,   v16.8h,  v0.8b
+        sqxtun          v0.8b,   v0.8h
+        uaddw           v1.8h,   v16.8h,  v1.8b
+        st1             {v0.s}[0], [x0], x1
+        sqxtun          v1.8b,   v1.8h
+        st1             {v0.s}[1], [x0], x1
+        st1             {v1.s}[0], [x0], x1
+        st1             {v1.s}[1], [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+function idct_dc_w8_neon
+1:
+        ld1             {v0.8b}, [x0], x1
+        ld1             {v1.8b}, [x0], x1
+        ld1             {v2.8b}, [x0], x1
+        uaddw           v20.8h,  v16.8h, v0.8b
+        ld1             {v3.8b}, [x0], x1
+        sub             x0,  x0,  x1, lsl #2
+        subs            w4,  w4,  #4
+        uaddw           v21.8h,  v16.8h, v1.8b
+        sqxtun          v0.8b,   v20.8h
+        uaddw           v22.8h,  v16.8h, v2.8b
+        sqxtun          v1.8b,   v21.8h
+        uaddw           v23.8h,  v16.8h, v3.8b
+        st1             {v0.8b}, [x0], x1
+        sqxtun          v2.8b,   v22.8h
+        st1             {v1.8b}, [x0], x1
+        sqxtun          v3.8b,   v23.8h
+        st1             {v2.8b}, [x0], x1
+        st1             {v3.8b}, [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+function idct_dc_w16_neon
+1:
+        ld1             {v0.16b}, [x0], x1
+        ld1             {v1.16b}, [x0], x1
+        ld1             {v2.16b}, [x0], x1
+        subs            w4,  w4,  #4
+        uaddw           v20.8h,  v16.8h, v0.8b
+        uaddw2          v21.8h,  v16.8h, v0.16b
+        ld1             {v3.16b}, [x0], x1
+        uaddw           v22.8h,  v16.8h, v1.8b
+        uaddw2          v23.8h,  v16.8h, v1.16b
+        sub             x0,  x0,  x1, lsl #2
+        uaddw           v24.8h,  v16.8h, v2.8b
+        uaddw2          v25.8h,  v16.8h, v2.16b
+        sqxtun          v0.8b,   v20.8h
+        sqxtun2         v0.16b,  v21.8h
+        uaddw           v26.8h,  v16.8h, v3.8b
+        uaddw2          v27.8h,  v16.8h, v3.16b
+        sqxtun          v1.8b,   v22.8h
+        sqxtun2         v1.16b,  v23.8h
+        sqxtun          v2.8b,   v24.8h
+        sqxtun2         v2.16b,  v25.8h
+        st1             {v0.16b}, [x0], x1
+        sqxtun          v3.8b,   v26.8h
+        sqxtun2         v3.16b,  v27.8h
+        st1             {v1.16b}, [x0], x1
+        st1             {v2.16b}, [x0], x1
+        st1             {v3.16b}, [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+function idct_dc_w32_neon
+1:
+        ld1             {v0.16b, v1.16b},  [x0], x1
+        subs            w4,  w4,  #2
+        uaddw           v20.8h,  v16.8h, v0.8b
+        uaddw2          v21.8h,  v16.8h, v0.16b
+        ld1             {v2.16b, v3.16b},  [x0]
+        uaddw           v22.8h,  v16.8h, v1.8b
+        uaddw2          v23.8h,  v16.8h, v1.16b
+        sub             x0,  x0,  x1
+        uaddw           v24.8h,  v16.8h, v2.8b
+        uaddw2          v25.8h,  v16.8h, v2.16b
+        sqxtun          v0.8b,   v20.8h
+        sqxtun2         v0.16b,  v21.8h
+        uaddw           v26.8h,  v16.8h, v3.8b
+        uaddw2          v27.8h,  v16.8h, v3.16b
+        sqxtun          v1.8b,   v22.8h
+        sqxtun2         v1.16b,  v23.8h
+        sqxtun          v2.8b,   v24.8h
+        sqxtun2         v2.16b,  v25.8h
+        st1             {v0.16b, v1.16b},  [x0], x1
+        sqxtun          v3.8b,   v26.8h
+        sqxtun2         v3.16b,  v27.8h
+        st1             {v2.16b, v3.16b},  [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+function idct_dc_w64_neon
+1:
+        ld1             {v0.16b, v1.16b, v2.16b, v3.16b},  [x0]
+        subs            w4,  w4,  #1
+        uaddw           v20.8h,  v16.8h, v0.8b
+        uaddw2          v21.8h,  v16.8h, v0.16b
+        uaddw           v22.8h,  v16.8h, v1.8b
+        uaddw2          v23.8h,  v16.8h, v1.16b
+        uaddw           v24.8h,  v16.8h, v2.8b
+        uaddw2          v25.8h,  v16.8h, v2.16b
+        sqxtun          v0.8b,   v20.8h
+        sqxtun2         v0.16b,  v21.8h
+        uaddw           v26.8h,  v16.8h, v3.8b
+        uaddw2          v27.8h,  v16.8h, v3.16b
+        sqxtun          v1.8b,   v22.8h
+        sqxtun2         v1.16b,  v23.8h
+        sqxtun          v2.8b,   v24.8h
+        sqxtun2         v2.16b,  v25.8h
+        sqxtun          v3.8b,   v26.8h
+        sqxtun2         v3.16b,  v27.8h
+        st1             {v0.16b, v1.16b, v2.16b, v3.16b},  [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+.macro iwht4
+        add             v16.4h,  v16.4h,  v17.4h
+        sub             v21.4h,  v18.4h,  v19.4h
+        sub             v20.4h,  v16.4h,  v21.4h
+        sshr            v20.4h,  v20.4h,  #1
+        sub             v18.4h,  v20.4h,  v17.4h
+        sub             v17.4h,  v20.4h,  v19.4h
+        add             v19.4h,  v21.4h,  v18.4h
+        sub             v16.4h,  v16.4h,  v17.4h
+.endm
+
+.macro idct_4 r0, r1, r2, r3, sz
+        smull_smlal     v6,  v7,  \r1, \r3, v0.h[3], v0.h[2], \sz
+        smull_smlsl     v4,  v5,  \r1, \r3, v0.h[2], v0.h[3], \sz
+        smull_smlal     v2,  v3,  \r0, \r2, v0.h[0], v0.h[0], \sz
+        sqrshrn_sz      v6,  v6,  v7,  #12, \sz
+        sqrshrn_sz      v7,  v4,  v5,  #12, \sz
+        smull_smlsl     v4,  v5,  \r0, \r2, v0.h[0], v0.h[0], \sz
+        sqrshrn_sz      v2,  v2,  v3,  #12, \sz
+        sqrshrn_sz      v3,  v4,  v5,  #12, \sz
+        sqadd           \r0\sz,  v2\sz,   v6\sz
+        sqsub           \r3\sz,  v2\sz,   v6\sz
+        sqadd           \r1\sz,  v3\sz,   v7\sz
+        sqsub           \r2\sz,  v3\sz,   v7\sz
+.endm
+
+function inv_dct_4h_x4_neon, export=1
+        movrel          x16, idct_coeffs
+        ld1             {v0.4h}, [x16]
+        idct_4          v16, v17, v18, v19, .4h
+        ret
+endfunc
+
+function inv_dct_8h_x4_neon, export=1
+        movrel          x16, idct_coeffs
+        ld1             {v0.4h}, [x16]
+        idct_4          v16, v17, v18, v19, .8h
+        ret
+endfunc
+
+.macro iadst_4x4 o0, o1, o2, o3
+        movrel          x16, iadst4_coeffs
+        ld1             {v0.8h}, [x16]
+
+        ssubl           v3.4s,   v16.4h,  v18.4h
+        smull           v4.4s,   v16.4h,  v0.h[0]
+        smlal           v4.4s,   v18.4h,  v0.h[1]
+        smlal           v4.4s,   v19.4h,  v0.h[2]
+        smull           v7.4s,   v17.4h,  v0.h[3]
+        saddw           v3.4s,   v3.4s,   v19.4h
+        smull           v5.4s,   v16.4h,  v0.h[2]
+        smlsl           v5.4s,   v18.4h,  v0.h[0]
+        smlsl           v5.4s,   v19.4h,  v0.h[1]
+
+        add             \o3\().4s, v4.4s,     v5.4s
+        mul             \o2\().4s, v3.4s,     v0.s[2]
+        add             \o0\().4s, v4.4s,     v7.4s
+        add             \o1\().4s, v5.4s,     v7.4s
+        sub             \o3\().4s, \o3\().4s, v7.4s
+
+        sqrshrn         \o0\().4h, \o0\().4s, #12
+        sqrshrn         \o2\().4h, \o2\().4s, #12
+        sqrshrn         \o1\().4h, \o1\().4s, #12
+        sqrshrn         \o3\().4h, \o3\().4s, #12
+.endm
+
+function inv_adst_4h_x4_neon, export=1
+        iadst_4x4       v16, v17, v18, v19
+        ret
+endfunc
+
+function inv_flipadst_4h_x4_neon, export=1
+        iadst_4x4       v19, v18, v17, v16
+        ret
+endfunc
+
+.macro iadst_8x4 o0, o1, o2, o3
+        movrel          x16, iadst4_coeffs
+        ld1             {v0.8h}, [x16]
+
+        ssubl           v2.4s,   v16.4h,  v18.4h
+        ssubl2          v3.4s,   v16.8h,  v18.8h
+        smull           v4.4s,   v16.4h,  v0.h[0]
+        smlal           v4.4s,   v18.4h,  v0.h[1]
+        smlal           v4.4s,   v19.4h,  v0.h[2]
+        smull2          v5.4s,   v16.8h,  v0.h[0]
+        smlal2          v5.4s,   v18.8h,  v0.h[1]
+        smlal2          v5.4s,   v19.8h,  v0.h[2]
+        saddw           v2.4s,   v2.4s,   v19.4h
+        saddw2          v3.4s,   v3.4s,   v19.8h
+        smull           v6.4s,   v16.4h,  v0.h[2]
+        smlsl           v6.4s,   v18.4h,  v0.h[0]
+        smlsl           v6.4s,   v19.4h,  v0.h[1]
+        smull2          v7.4s,   v16.8h,  v0.h[2]
+        smlsl2          v7.4s,   v18.8h,  v0.h[0]
+        smlsl2          v7.4s,   v19.8h,  v0.h[1]
+
+        mul             v18.4s,  v2.4s,   v0.s[2]
+        mul             v19.4s,  v3.4s,   v0.s[2]
+
+        smull           v2.4s,   v17.4h,  v0.h[3]
+        smull2          v3.4s,   v17.8h,  v0.h[3]
+
+        add             v16.4s,  v4.4s,   v2.4s // out0
+        add             v17.4s,  v5.4s,   v3.4s
+
+        add             v4.4s,   v4.4s,   v6.4s // out3
+        add             v5.4s,   v5.4s,   v7.4s
+
+        add             v6.4s,   v6.4s,   v2.4s // out1
+        add             v7.4s,   v7.4s,   v3.4s
+
+        sub             v4.4s,   v4.4s,   v2.4s // out3
+        sub             v5.4s,   v5.4s,   v3.4s
+
+        sqrshrn         v18.4h,  v18.4s, #12
+        sqrshrn2        v18.8h,  v19.4s, #12
+
+        sqrshrn         \o0\().4h, v16.4s, #12
+        sqrshrn2        \o0\().8h, v17.4s, #12
+
+.ifc \o2, v17
+        mov             v17.16b,   v18.16b
+.endif
+
+        sqrshrn         \o1\().4h, v6.4s,  #12
+        sqrshrn2        \o1\().8h, v7.4s,  #12
+
+        sqrshrn         \o3\().4h, v4.4s,  #12
+        sqrshrn2        \o3\().8h, v5.4s,  #12
+.endm
+
+function inv_adst_8h_x4_neon, export=1
+        iadst_8x4       v16, v17, v18, v19
+        ret
+endfunc
+
+function inv_flipadst_8h_x4_neon, export=1
+        iadst_8x4       v19, v18, v17, v16
+        ret
+endfunc
+
+function inv_identity_4h_x4_neon, export=1
+        mov             w16, #(5793-4096)*8
+        dup             v0.4h,   w16
+        sqrdmulh        v4.4h,   v16.4h,  v0.h[0]
+        sqrdmulh        v5.4h,   v17.4h,  v0.h[0]
+        sqrdmulh        v6.4h,   v18.4h,  v0.h[0]
+        sqrdmulh        v7.4h,   v19.4h,  v0.h[0]
+        sqadd           v16.4h,  v16.4h,  v4.4h
+        sqadd           v17.4h,  v17.4h,  v5.4h
+        sqadd           v18.4h,  v18.4h,  v6.4h
+        sqadd           v19.4h,  v19.4h,  v7.4h
+        ret
+endfunc
+
+function inv_identity_8h_x4_neon, export=1
+        mov             w16, #(5793-4096)*8
+        dup             v0.4h,   w16
+        sqrdmulh        v4.8h,   v16.8h,  v0.h[0]
+        sqrdmulh        v5.8h,   v17.8h,  v0.h[0]
+        sqrdmulh        v6.8h,   v18.8h,  v0.h[0]
+        sqrdmulh        v7.8h,   v19.8h,  v0.h[0]
+        sqadd           v16.8h,  v16.8h,  v4.8h
+        sqadd           v17.8h,  v17.8h,  v5.8h
+        sqadd           v18.8h,  v18.8h,  v6.8h
+        sqadd           v19.8h,  v19.8h,  v7.8h
+        ret
+endfunc
+
+.macro identity_8x4_shift1 r0, r1, r2, r3, c
+.irp i, \r0\().8h, \r1\().8h, \r2\().8h, \r3\().8h
+        sqrdmulh        v2.8h,  \i,  \c
+        srhadd          \i,     \i,  v2.8h
+.endr
+.endm
+
+function inv_txfm_add_wht_wht_4x4_8bpc_neon, export=1
+        mov             x15, x30
+        movi            v31.8h,  #0
+        ld1             {v16.4h,v17.4h,v18.4h,v19.4h}, [x2]
+        st1             {v31.8h}, [x2], #16
+
+        sshr            v16.4h,  v16.4h,  #2
+        sshr            v17.4h,  v17.4h,  #2
+        sshr            v18.4h,  v18.4h,  #2
+        sshr            v19.4h,  v19.4h,  #2
+
+        iwht4
+
+        st1             {v31.8h}, [x2], #16
+        transpose_4x4h  v16, v17, v18, v19, v20, v21, v22, v23
+
+        iwht4
+
+        ld1             {v0.s}[0], [x0], x1
+        ld1             {v0.s}[1], [x0], x1
+        ins             v16.d[1], v17.d[0]
+        ins             v18.d[1], v19.d[0]
+        ld1             {v1.s}[0], [x0], x1
+        ld1             {v1.s}[1], [x0], x1
+
+        b               L(itx_4x4_end)
+endfunc
+
+function inv_txfm_add_4x4_neon
+        movi            v31.8h,  #0
+        ld1             {v16.4h,v17.4h,v18.4h,v19.4h}, [x2]
+        st1             {v31.8h}, [x2], #16
+
+        blr             x4
+
+        st1             {v31.8h}, [x2], #16
+        transpose_4x4h  v16, v17, v18, v19, v20, v21, v22, v23
+
+        blr             x5
+
+        ld1             {v0.s}[0], [x0], x1
+        ld1             {v0.s}[1], [x0], x1
+        ins             v16.d[1], v17.d[0]
+        ins             v18.d[1], v19.d[0]
+        ld1             {v1.s}[0], [x0], x1
+        ld1             {v1.s}[1], [x0], x1
+        srshr           v16.8h,  v16.8h,  #4
+        srshr           v18.8h,  v18.8h,  #4
+
+L(itx_4x4_end):
+        sub             x0,  x0,  x1, lsl #2
+        uaddw           v16.8h,  v16.8h,  v0.8b
+        sqxtun          v0.8b,   v16.8h
+        uaddw           v18.8h,  v18.8h,  v1.8b
+        st1             {v0.s}[0], [x0], x1
+        sqxtun          v1.8b,   v18.8h
+        st1             {v0.s}[1], [x0], x1
+        st1             {v1.s}[0], [x0], x1
+        st1             {v1.s}[1], [x0], x1
+
+        ret             x15
+endfunc
+
+.macro def_fn_4x4 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_4x4_8bpc_neon, export=1
+        mov             x15, x30
+
+.ifc \txfm1\()_\txfm2, dct_dct
+        cbnz            w3,  1f
+        mov             w16, #2896*8
+        ld1r            {v16.8h}, [x2]
+        dup             v4.8h,   w16
+        strh            wzr, [x2]
+        sqrdmulh        v16.8h,  v16.8h,  v4.h[0]
+        ld1             {v0.s}[0], [x0], x1
+        sqrdmulh        v20.8h,  v16.8h,  v4.h[0]
+        ld1             {v0.s}[1], [x0], x1
+        srshr           v16.8h,  v20.8h,  #4
+        ld1             {v1.s}[0], [x0], x1
+        srshr           v18.8h,  v20.8h,  #4
+        ld1             {v1.s}[1], [x0], x1
+        b               L(itx_4x4_end)
+1:
+.endif
+        adr             x4,  inv_\txfm1\()_4h_x4_neon
+        adr             x5,  inv_\txfm2\()_4h_x4_neon
+        b               inv_txfm_add_4x4_neon
+endfunc
+.endm
+
+def_fn_4x4 dct, dct
+def_fn_4x4 identity, identity
+def_fn_4x4 dct, adst
+def_fn_4x4 dct, flipadst
+def_fn_4x4 dct, identity
+def_fn_4x4 adst, dct
+def_fn_4x4 adst, adst
+def_fn_4x4 adst, flipadst
+def_fn_4x4 flipadst, dct
+def_fn_4x4 flipadst, adst
+def_fn_4x4 flipadst, flipadst
+def_fn_4x4 identity, dct
+
+def_fn_4x4 adst, identity
+def_fn_4x4 flipadst, identity
+def_fn_4x4 identity, adst
+def_fn_4x4 identity, flipadst
+
+.macro idct_8 r0, r1, r2, r3, r4, r5, r6, r7, sz, szb
+        idct_4          \r0, \r2, \r4, \r6, \sz
+
+        smull_smlsl     v2,  v3,  \r1, \r7, v0.h[4], v0.h[5], \sz // -> t4a
+        smull_smlal     v4,  v5,  \r1, \r7, v0.h[5], v0.h[4], \sz // -> t7a
+        smull_smlsl     v6,  v7,  \r5, \r3, v0.h[6], v0.h[7], \sz // -> t5a
+        sqrshrn_sz      \r1, v2,  v3,  #12, \sz                   // t4a
+        sqrshrn_sz      \r7, v4,  v5,  #12, \sz                   // t7a
+        smull_smlal     v2,  v3,  \r5, \r3, v0.h[7], v0.h[6], \sz // -> t6a
+        sqrshrn_sz      \r3, v6,  v7,  #12, \sz                   // t5a
+        sqrshrn_sz      \r5, v2,  v3,  #12, \sz                   // t6a
+
+        sqadd           v2\sz,   \r1\sz,  \r3\sz // t4
+        sqsub           \r1\sz,  \r1\sz,  \r3\sz // t5a
+        sqadd           v3\sz,   \r7\sz,  \r5\sz // t7
+        sqsub           \r3\sz,  \r7\sz,  \r5\sz // t6a
+
+        smull_smlsl     v4,  v5,  \r3, \r1, v0.h[0], v0.h[0], \sz // -> t5
+        smull_smlal     v6,  v7,  \r3, \r1, v0.h[0], v0.h[0], \sz // -> t6
+        sqrshrn_sz      v4,  v4,  v5,  #12, \sz // t5
+        sqrshrn_sz      v5,  v6,  v7,  #12, \sz // t6
+
+        sqsub           \r7\sz,  \r0\sz,  v3\sz // out7
+        sqadd           \r0\sz,  \r0\sz,  v3\sz // out0
+        sqadd           \r1\sz,  \r2\sz,  v5\sz // out1
+        sqsub           v6\sz,   \r2\sz,  v5\sz // out6
+        sqadd           \r2\sz,  \r4\sz,  v4\sz // out2
+        sqsub           \r5\sz,  \r4\sz,  v4\sz // out5
+        sqadd           \r3\sz,  \r6\sz,  v2\sz // out3
+        sqsub           \r4\sz,  \r6\sz,  v2\sz // out4
+        mov             \r6\szb, v6\szb         // out6
+.endm
+
+function inv_dct_8h_x8_neon, export=1
+        movrel          x16, idct_coeffs
+        ld1             {v0.8h}, [x16]
+        idct_8          v16, v17, v18, v19, v20, v21, v22, v23, .8h, .16b
+        ret
+endfunc
+
+function inv_dct_4h_x8_neon, export=1
+        movrel          x16, idct_coeffs
+        ld1             {v0.8h}, [x16]
+        idct_8          v16, v17, v18, v19, v20, v21, v22, v23, .4h, .8b
+        ret
+endfunc
+
+.macro iadst_8 o0, o1, o2, o3, o4, o5, o6, o7, sz
+        movrel          x16, iadst8_coeffs
+        ld1             {v0.8h, v1.8h}, [x16]
+
+        smull_smlal     v2,  v3,  v23, v16, v0.h[0], v0.h[1], \sz
+        smull_smlsl     v4,  v5,  v23, v16, v0.h[1], v0.h[0], \sz
+        smull_smlal     v6,  v7,  v21, v18, v0.h[2], v0.h[3], \sz
+        sqrshrn_sz      v16, v2,  v3,  #12, \sz  // t0a
+        sqrshrn_sz      v23, v4,  v5,  #12, \sz  // t1a
+        smull_smlsl     v2,  v3,  v21, v18, v0.h[3], v0.h[2], \sz
+        smull_smlal     v4,  v5,  v19, v20, v0.h[4], v0.h[5], \sz
+        sqrshrn_sz      v18, v6,  v7,  #12, \sz  // t2a
+        sqrshrn_sz      v21, v2,  v3,  #12, \sz  // t3a
+        smull_smlsl     v6,  v7,  v19, v20, v0.h[5], v0.h[4], \sz
+        smull_smlal     v2,  v3,  v17, v22, v0.h[6], v0.h[7], \sz
+        sqrshrn_sz      v20, v4,  v5,  #12, \sz  // t4a
+        sqrshrn_sz      v19, v6,  v7,  #12, \sz  // t5a
+        smull_smlsl     v4,  v5,  v17, v22, v0.h[7], v0.h[6], \sz
+        sqrshrn_sz      v22, v2,  v3,  #12, \sz  // t6a
+        sqrshrn_sz      v17, v4,  v5,  #12, \sz  // t7a
+
+        sqadd           v2\sz,   v16\sz,  v20\sz // t0
+        sqsub           v3\sz,   v16\sz,  v20\sz // t4
+        sqadd           v4\sz,   v23\sz,  v19\sz // t1
+        sqsub           v5\sz,   v23\sz,  v19\sz // t5
+        sqadd           v6\sz,   v18\sz,  v22\sz // t2
+        sqsub           v7\sz,   v18\sz,  v22\sz // t6
+        sqadd           v18\sz,  v21\sz,  v17\sz // t3
+        sqsub           v19\sz,  v21\sz,  v17\sz // t7
+
+        smull_smlal     v16, v17, v3,  v5,  v1.h[3], v1.h[2], \sz
+        smull_smlsl     v20, v21, v3,  v5,  v1.h[2], v1.h[3], \sz
+        smull_smlsl     v22, v23, v19, v7,  v1.h[3], v1.h[2], \sz
+
+        sqrshrn_sz      v3,  v16, v17, #12, \sz  // t4a
+        sqrshrn_sz      v5,  v20, v21, #12, \sz  // t5a
+
+        smull_smlal     v16, v17, v19, v7,  v1.h[2], v1.h[3], \sz
+
+        sqrshrn_sz      v7,  v22, v23, #12, \sz  // t6a
+        sqrshrn_sz      v19, v16, v17, #12, \sz  // t7a
+
+        sqadd           \o0\()\sz, v2\sz, v6\sz  // out0
+        sqsub           v2\sz,     v2\sz, v6\sz  // t2
+        sqadd           \o7\()\sz, v4\sz, v18\sz // out7
+        sqsub           v4\sz,     v4\sz, v18\sz // t3
+        sqneg           \o7\()\sz, \o7\()\sz     // out7
+
+        sqadd           \o1\()\sz, v3\sz, v7\sz  // out1
+        sqsub           v3\sz,     v3\sz, v7\sz  // t6
+        sqadd           \o6\()\sz, v5\sz, v19\sz // out6
+        sqsub           v5\sz,     v5\sz, v19\sz // t7
+        sqneg           \o1\()\sz, \o1\()\sz     // out1
+
+        smull_smlal     v18, v19, v2,  v4,  v1.h[0], v1.h[0], \sz // -> out3 (v19 or v20)
+        smull_smlsl     v6,  v7,  v2,  v4,  v1.h[0], v1.h[0], \sz // -> out4 (v20 or v19)
+        smull_smlsl     v20, v21, v3,  v5,  v1.h[0], v1.h[0], \sz // -> out5 (v21 or v18)
+        sqrshrn_sz      v2,  v18, v19, #12, \sz // out3
+        smull_smlal     v18, v19, v3,  v5,  v1.h[0], v1.h[0], \sz // -> out2 (v18 or v21)
+        sqrshrn_sz      v3,  v20, v21, #12, \sz // out5
+        sqrshrn_sz      \o2, v18, v19, #12, \sz // out2 (v18 or v21)
+        sqrshrn_sz      \o4, v6,  v7,  #12, \sz // out4 (v20 or v19)
+
+        sqneg           \o3\()\sz, v2\sz     // out3
+        sqneg           \o5\()\sz, v3\sz     // out5
+.endm
+
+function inv_adst_8h_x8_neon, export=1
+        iadst_8         v16, v17, v18, v19, v20, v21, v22, v23, .8h
+        ret
+endfunc
+
+function inv_flipadst_8h_x8_neon, export=1
+        iadst_8         v23, v22, v21, v20, v19, v18, v17, v16, .8h
+        ret
+endfunc
+
+function inv_adst_4h_x8_neon, export=1
+        iadst_8         v16, v17, v18, v19, v20, v21, v22, v23, .4h
+        ret
+endfunc
+
+function inv_flipadst_4h_x8_neon, export=1
+        iadst_8         v23, v22, v21, v20, v19, v18, v17, v16, .4h
+        ret
+endfunc
+
+function inv_identity_8h_x8_neon, export=1
+        sqshl           v16.8h,  v16.8h,  #1
+        sqshl           v17.8h,  v17.8h,  #1
+        sqshl           v18.8h,  v18.8h,  #1
+        sqshl           v19.8h,  v19.8h,  #1
+        sqshl           v20.8h,  v20.8h,  #1
+        sqshl           v21.8h,  v21.8h,  #1
+        sqshl           v22.8h,  v22.8h,  #1
+        sqshl           v23.8h,  v23.8h,  #1
+        ret
+endfunc
+
+function inv_identity_4h_x8_neon, export=1
+        sqshl           v16.4h,  v16.4h,  #1
+        sqshl           v17.4h,  v17.4h,  #1
+        sqshl           v18.4h,  v18.4h,  #1
+        sqshl           v19.4h,  v19.4h,  #1
+        sqshl           v20.4h,  v20.4h,  #1
+        sqshl           v21.4h,  v21.4h,  #1
+        sqshl           v22.4h,  v22.4h,  #1
+        sqshl           v23.4h,  v23.4h,  #1
+        ret
+endfunc
+
+.macro def_fn_8x8_base variant
+function inv_txfm_\variant\()add_8x8_neon
+        movi            v28.8h,  #0
+        movi            v29.8h,  #0
+        movi            v30.8h,  #0
+        movi            v31.8h,  #0
+        ld1             {v16.8h,v17.8h,v18.8h,v19.8h}, [x2]
+        st1             {v28.8h,v29.8h,v30.8h,v31.8h}, [x2], #64
+        ld1             {v20.8h,v21.8h,v22.8h,v23.8h}, [x2]
+        st1             {v28.8h,v29.8h,v30.8h,v31.8h}, [x2]
+
+.ifc \variant, identity_
+        // The identity shl #1 and downshift srshr #1 cancel out
+
+        b               L(itx_8x8_epilog)
+.else
+        blr             x4
+
+        srshr           v16.8h,  v16.8h,  #1
+        srshr           v17.8h,  v17.8h,  #1
+        srshr           v18.8h,  v18.8h,  #1
+        srshr           v19.8h,  v19.8h,  #1
+        srshr           v20.8h,  v20.8h,  #1
+        srshr           v21.8h,  v21.8h,  #1
+        srshr           v22.8h,  v22.8h,  #1
+        srshr           v23.8h,  v23.8h,  #1
+
+L(itx_8x8_epilog):
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v24, v25
+
+        blr             x5
+
+        load_add_store_8x8 x0, x7
+        ret             x15
+.endif
+endfunc
+.endm
+
+def_fn_8x8_base identity_
+def_fn_8x8_base
+
+.macro def_fn_8x8 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_8x8_8bpc_neon, export=1
+        mov             x15, x30
+
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         8,   8,   1
+.endif
+        adr             x5,  inv_\txfm2\()_8h_x8_neon
+.ifc \txfm1, identity
+        b               inv_txfm_identity_add_8x8_neon
+.else
+        adr             x4,  inv_\txfm1\()_8h_x8_neon
+        b               inv_txfm_add_8x8_neon
+.endif
+endfunc
+.endm
+
+def_fn_8x8 dct, dct
+def_fn_8x8 identity, identity
+def_fn_8x8 dct, adst
+def_fn_8x8 dct, flipadst
+def_fn_8x8 dct, identity
+def_fn_8x8 adst, dct
+def_fn_8x8 adst, adst
+def_fn_8x8 adst, flipadst
+def_fn_8x8 flipadst, dct
+def_fn_8x8 flipadst, adst
+def_fn_8x8 flipadst, flipadst
+def_fn_8x8 identity, dct
+def_fn_8x8 adst, identity
+def_fn_8x8 flipadst, identity
+def_fn_8x8 identity, adst
+def_fn_8x8 identity, flipadst
+
+function inv_txfm_add_8x4_neon
+        movi            v30.8h,  #0
+        movi            v31.8h,  #0
+        mov             w16, #2896*8
+        dup             v0.4h,   w16
+        ld1             {v16.4h,v17.4h,v18.4h,v19.4h}, [x2]
+        st1             {v30.8h,v31.8h}, [x2], #32
+        ld1             {v20.4h,v21.4h,v22.4h,v23.4h}, [x2]
+        st1             {v30.8h,v31.8h}, [x2]
+
+        scale_input     .4h, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+
+        blr             x4
+
+        transpose_4x4h  v16, v17, v18, v19, v4,  v5,  v6,  v7
+        transpose_4x4h  v20, v21, v22, v23, v4,  v5,  v6,  v7
+        ins             v16.d[1], v20.d[0]
+        ins             v17.d[1], v21.d[0]
+        ins             v18.d[1], v22.d[0]
+        ins             v19.d[1], v23.d[0]
+
+        blr             x5
+
+        load_add_store_8x4 x0, x7
+        ret             x15
+endfunc
+
+function inv_txfm_add_4x8_neon
+        movi            v28.8h,  #0
+        movi            v29.8h,  #0
+        movi            v30.8h,  #0
+        movi            v31.8h,  #0
+        mov             w16, #2896*8
+        dup             v0.4h,   w16
+        ld1             {v16.8h,v17.8h,v18.8h,v19.8h}, [x2]
+        st1             {v28.8h,v29.8h,v30.8h,v31.8h}, [x2]
+
+        scale_input     .8h, v0.h[0], v16, v17, v18, v19
+
+        blr             x4
+
+        transpose_4x8h  v16, v17, v18, v19, v4,  v5,  v6,  v7
+        ins             v20.d[0], v16.d[1]
+        ins             v21.d[0], v17.d[1]
+        ins             v22.d[0], v18.d[1]
+        ins             v23.d[0], v19.d[1]
+
+        blr             x5
+
+        load_add_store_4x8 x0, x7
+        ret             x15
+endfunc
+
+.macro def_fn_48 w, h, txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1
+        mov             x15, x30
+
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  0
+.endif
+        adr             x4,  inv_\txfm1\()_\h\()h_x\w\()_neon
+        adr             x5,  inv_\txfm2\()_\w\()h_x\h\()_neon
+        b               inv_txfm_add_\w\()x\h\()_neon
+endfunc
+.endm
+
+.macro def_fns_48 w, h
+def_fn_48 \w, \h, dct, dct
+def_fn_48 \w, \h, identity, identity
+def_fn_48 \w, \h, dct, adst
+def_fn_48 \w, \h, dct, flipadst
+def_fn_48 \w, \h, dct, identity
+def_fn_48 \w, \h, adst, dct
+def_fn_48 \w, \h, adst, adst
+def_fn_48 \w, \h, adst, flipadst
+def_fn_48 \w, \h, flipadst, dct
+def_fn_48 \w, \h, flipadst, adst
+def_fn_48 \w, \h, flipadst, flipadst
+def_fn_48 \w, \h, identity, dct
+def_fn_48 \w, \h, adst, identity
+def_fn_48 \w, \h, flipadst, identity
+def_fn_48 \w, \h, identity, adst
+def_fn_48 \w, \h, identity, flipadst
+.endm
+
+def_fns_48 4, 8
+def_fns_48 8, 4
+
+
+.macro idct_16 sz, szb
+        idct_8          v16, v18, v20, v22, v24, v26, v28, v30, \sz, \szb
+
+        smull_smlsl     v2,  v3,  v17, v31, v1.h[0], v1.h[1], \sz // -> t8a
+        smull_smlal     v4,  v5,  v17, v31, v1.h[1], v1.h[0], \sz // -> t15a
+        smull_smlsl     v6,  v7,  v25, v23, v1.h[2], v1.h[3], \sz // -> t9a
+        sqrshrn_sz      v17, v2,  v3,  #12, \sz                   // t8a
+        sqrshrn_sz      v31, v4,  v5,  #12, \sz                   // t15a
+        smull_smlal     v2,  v3,  v25, v23, v1.h[3], v1.h[2], \sz // -> t14a
+        smull_smlsl     v4,  v5,  v21, v27, v1.h[4], v1.h[5], \sz // -> t10a
+        sqrshrn_sz      v23, v6,  v7,  #12, \sz                   // t9a
+        sqrshrn_sz      v25, v2,  v3,  #12, \sz                   // t14a
+        smull_smlal     v6,  v7,  v21, v27, v1.h[5], v1.h[4], \sz // -> t13a
+        smull_smlsl     v2,  v3,  v29, v19, v1.h[6], v1.h[7], \sz // -> t11a
+        sqrshrn_sz      v21, v4,  v5,  #12, \sz                   // t10a
+        sqrshrn_sz      v27, v6,  v7,  #12, \sz                   // t13a
+        smull_smlal     v4,  v5,  v29, v19, v1.h[7], v1.h[6], \sz // -> t12a
+        sqrshrn_sz      v19, v2,  v3,  #12, \sz                   // t11a
+        sqrshrn_sz      v29, v4,  v5,  #12, \sz                   // t12a
+
+        sqsub           v2\sz,   v17\sz,  v23\sz  // t9
+        sqadd           v17\sz,  v17\sz,  v23\sz  // t8
+        sqsub           v3\sz,   v31\sz,  v25\sz  // t14
+        sqadd           v31\sz,  v31\sz,  v25\sz  // t15
+        sqsub           v23\sz,  v19\sz,  v21\sz  // t10
+        sqadd           v19\sz,  v19\sz,  v21\sz  // t11
+        sqadd           v25\sz,  v29\sz,  v27\sz  // t12
+        sqsub           v29\sz,  v29\sz,  v27\sz  // t13
+
+        smull_smlsl     v4,  v5,  v3,  v2,  v0.h[2], v0.h[3], \sz // -> t9a
+        smull_smlal     v6,  v7,  v3,  v2,  v0.h[3], v0.h[2], \sz // -> t14a
+        sqrshrn_sz      v21, v4,  v5,  #12, \sz                   // t9a
+        sqrshrn_sz      v27, v6,  v7,  #12, \sz                   // t14a
+
+        smull_smlsl     v4,  v5,  v29, v23, v0.h[2], v0.h[3], \sz // -> t13a
+        smull_smlal     v6,  v7,  v29, v23, v0.h[3], v0.h[2], \sz // -> t10a
+        sqrshrn_sz      v29, v4,  v5,  #12, \sz                   // t13a
+        neg             v6.4s,   v6.4s
+.ifc \sz, .8h
+        neg             v7.4s,   v7.4s
+.endif
+        sqrshrn_sz      v23, v6,  v7,  #12, \sz                   // t10a
+
+        sqsub           v2\sz,   v17\sz,  v19\sz  // t11a
+        sqadd           v17\sz,  v17\sz,  v19\sz  // t8a
+        sqsub           v3\sz,   v31\sz,  v25\sz  // t12a
+        sqadd           v31\sz,  v31\sz,  v25\sz  // t15a
+        sqadd           v19\sz,  v21\sz,  v23\sz  // t9
+        sqsub           v21\sz,  v21\sz,  v23\sz  // t10
+        sqsub           v25\sz,  v27\sz,  v29\sz  // t13
+        sqadd           v27\sz,  v27\sz,  v29\sz  // t14
+
+        smull_smlsl     v4,  v5,  v3,  v2,  v0.h[0], v0.h[0], \sz // -> t11
+        smull_smlal     v6,  v7,  v3,  v2,  v0.h[0], v0.h[0], \sz // -> t12
+        smull_smlsl     v2,  v3,  v25, v21, v0.h[0], v0.h[0], \sz // -> t10a
+
+        sqrshrn_sz      v4,  v4,  v5,  #12, \sz   // t11
+        sqrshrn_sz      v5,  v6,  v7,  #12, \sz   // t12
+        smull_smlal     v6,  v7,  v25, v21, v0.h[0], v0.h[0], \sz // -> t13a
+        sqrshrn_sz      v2,  v2,  v3,  #12, \sz   // t10a
+        sqrshrn_sz      v3,  v6,  v7,  #12, \sz   // t13a
+
+        sqadd           v6\sz,   v16\sz,  v31\sz  // out0
+        sqsub           v31\sz,  v16\sz,  v31\sz  // out15
+        mov             v16\szb, v6\szb
+        sqadd           v23\sz,  v30\sz,  v17\sz  // out7
+        sqsub           v7\sz,   v30\sz,  v17\sz  // out8
+        sqadd           v17\sz,  v18\sz,  v27\sz  // out1
+        sqsub           v30\sz,  v18\sz,  v27\sz  // out14
+        sqadd           v18\sz,  v20\sz,  v3\sz   // out2
+        sqsub           v29\sz,  v20\sz,  v3\sz   // out13
+        sqadd           v3\sz,   v28\sz,  v19\sz  // out6
+        sqsub           v25\sz,  v28\sz,  v19\sz  // out9
+        sqadd           v19\sz,  v22\sz,  v5\sz   // out3
+        sqsub           v28\sz,  v22\sz,  v5\sz   // out12
+        sqadd           v20\sz,  v24\sz,  v4\sz   // out4
+        sqsub           v27\sz,  v24\sz,  v4\sz   // out11
+        sqadd           v21\sz,  v26\sz,  v2\sz   // out5
+        sqsub           v26\sz,  v26\sz,  v2\sz   // out10
+        mov             v24\szb, v7\szb
+        mov             v22\szb, v3\szb
+.endm
+
+function inv_dct_8h_x16_neon, export=1
+        movrel          x16, idct_coeffs
+        ld1             {v0.8h, v1.8h}, [x16]
+        idct_16         .8h, .16b
+        ret
+endfunc
+
+function inv_dct_4h_x16_neon, export=1
+        movrel          x16, idct_coeffs
+        ld1             {v0.8h, v1.8h}, [x16]
+        idct_16         .4h, .8b
+        ret
+endfunc
+
+.macro iadst_16 o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, sz, szb
+        movrel          x16, iadst16_coeffs
+        ld1             {v0.8h, v1.8h}, [x16]
+        movrel          x16, idct_coeffs
+
+        smull_smlal     v2,  v3,  v31, v16, v0.h[0], v0.h[1], \sz // -> t0
+        smull_smlsl     v4,  v5,  v31, v16, v0.h[1], v0.h[0], \sz // -> t1
+        smull_smlal     v6,  v7,  v29, v18, v0.h[2], v0.h[3], \sz // -> t2
+        sqrshrn_sz      v16, v2,  v3,  #12, \sz   // t0
+        sqrshrn_sz      v31, v4,  v5,  #12, \sz   // t1
+        smull_smlsl     v2,  v3,  v29, v18, v0.h[3], v0.h[2], \sz // -> t3
+        smull_smlal     v4,  v5,  v27, v20, v0.h[4], v0.h[5], \sz // -> t4
+        sqrshrn_sz      v18, v6,  v7,  #12, \sz   // t2
+        sqrshrn_sz      v29, v2,  v3,  #12, \sz   // t3
+        smull_smlsl     v6,  v7,  v27, v20, v0.h[5], v0.h[4], \sz // -> t5
+        smull_smlal     v2,  v3,  v25, v22, v0.h[6], v0.h[7], \sz // -> t6
+        sqrshrn_sz      v20, v4,  v5,  #12, \sz   // t4
+        sqrshrn_sz      v27, v6,  v7,  #12, \sz   // t5
+        smull_smlsl     v4,  v5,  v25, v22, v0.h[7], v0.h[6], \sz // -> t7
+        smull_smlal     v6,  v7,  v23, v24, v1.h[0], v1.h[1], \sz // -> t8
+        sqrshrn_sz      v22, v2,  v3,  #12, \sz   // t6
+        sqrshrn_sz      v25, v4,  v5,  #12, \sz   // t7
+        smull_smlsl     v2,  v3,  v23, v24, v1.h[1], v1.h[0], \sz // -> t9
+        smull_smlal     v4,  v5,  v21, v26, v1.h[2], v1.h[3], \sz // -> t10
+        sqrshrn_sz      v23, v6,  v7,  #12, \sz   // t8
+        sqrshrn_sz      v24, v2,  v3,  #12, \sz   // t9
+        smull_smlsl     v6,  v7,  v21, v26, v1.h[3], v1.h[2], \sz // -> t11
+        smull_smlal     v2,  v3,  v19, v28, v1.h[4], v1.h[5], \sz // -> t12
+        sqrshrn_sz      v21, v4,  v5,  #12, \sz   // t10
+        sqrshrn_sz      v26, v6,  v7,  #12, \sz   // t11
+        smull_smlsl     v4,  v5,  v19, v28, v1.h[5], v1.h[4], \sz // -> t13
+        smull_smlal     v6,  v7,  v17, v30, v1.h[6], v1.h[7], \sz // -> t14
+        sqrshrn_sz      v19, v2,  v3,  #12, \sz   // t12
+        sqrshrn_sz      v28, v4,  v5,  #12, \sz   // t13
+        smull_smlsl     v2,  v3,  v17, v30, v1.h[7], v1.h[6], \sz // -> t15
+        sqrshrn_sz      v17, v6,  v7,  #12, \sz   // t14
+        sqrshrn_sz      v30, v2,  v3,  #12, \sz   // t15
+
+        ld1             {v0.8h}, [x16]
+
+        sqsub           v2\sz,   v16\sz,  v23\sz // t8a
+        sqadd           v16\sz,  v16\sz,  v23\sz // t0a
+        sqsub           v3\sz,   v31\sz,  v24\sz // t9a
+        sqadd           v31\sz,  v31\sz,  v24\sz // t1a
+        sqadd           v23\sz,  v18\sz,  v21\sz // t2a
+        sqsub           v18\sz,  v18\sz,  v21\sz // t10a
+        sqadd           v24\sz,  v29\sz,  v26\sz // t3a
+        sqsub           v29\sz,  v29\sz,  v26\sz // t11a
+        sqadd           v21\sz,  v20\sz,  v19\sz // t4a
+        sqsub           v20\sz,  v20\sz,  v19\sz // t12a
+        sqadd           v26\sz,  v27\sz,  v28\sz // t5a
+        sqsub           v27\sz,  v27\sz,  v28\sz // t13a
+        sqadd           v19\sz,  v22\sz,  v17\sz // t6a
+        sqsub           v22\sz,  v22\sz,  v17\sz // t14a
+        sqadd           v28\sz,  v25\sz,  v30\sz // t7a
+        sqsub           v25\sz,  v25\sz,  v30\sz // t15a
+
+        smull_smlal     v4,  v5,  v2,  v3,  v0.h[5], v0.h[4], \sz // -> t8
+        smull_smlsl     v6,  v7,  v2,  v3,  v0.h[4], v0.h[5], \sz // -> t9
+        smull_smlal     v2,  v3,  v18, v29, v0.h[7], v0.h[6], \sz // -> t10
+        sqrshrn_sz      v17, v4,  v5,  #12, \sz  // t8
+        sqrshrn_sz      v30, v6,  v7,  #12, \sz  // t9
+        smull_smlsl     v4,  v5,  v18, v29, v0.h[6], v0.h[7], \sz // -> t11
+        smull_smlsl     v6,  v7,  v27, v20, v0.h[5], v0.h[4], \sz // -> t12
+        sqrshrn_sz      v18, v2,  v3,  #12, \sz  // t10
+        sqrshrn_sz      v29, v4,  v5,  #12, \sz  // t11
+        smull_smlal     v2,  v3,  v27, v20, v0.h[4], v0.h[5], \sz // -> t13
+        smull_smlsl     v4,  v5,  v25, v22, v0.h[7], v0.h[6], \sz // -> t14
+        sqrshrn_sz      v27, v6,  v7,  #12, \sz  // t12
+        sqrshrn_sz      v20, v2,  v3,  #12, \sz  // t13
+        smull_smlal     v6,  v7,  v25, v22, v0.h[6], v0.h[7], \sz // -> t15
+        sqrshrn_sz      v25, v4,  v5,  #12, \sz  // t14
+        sqrshrn_sz      v22, v6,  v7,  #12, \sz  // t15
+
+        sqsub           v2\sz,   v16\sz,  v21\sz // t4
+        sqadd           v16\sz,  v16\sz,  v21\sz // t0
+        sqsub           v3\sz,   v31\sz,  v26\sz // t5
+        sqadd           v31\sz,  v31\sz,  v26\sz // t1
+        sqadd           v21\sz,  v23\sz,  v19\sz // t2
+        sqsub           v23\sz,  v23\sz,  v19\sz // t6
+        sqadd           v26\sz,  v24\sz,  v28\sz // t3
+        sqsub           v24\sz,  v24\sz,  v28\sz // t7
+        sqadd           v19\sz,  v17\sz,  v27\sz // t8a
+        sqsub           v17\sz,  v17\sz,  v27\sz // t12a
+        sqadd           v28\sz,  v30\sz,  v20\sz // t9a
+        sqsub           v30\sz,  v30\sz,  v20\sz // t13a
+        sqadd           v27\sz,  v18\sz,  v25\sz // t10a
+        sqsub           v18\sz,  v18\sz,  v25\sz // t14a
+        sqadd           v20\sz,  v29\sz,  v22\sz // t11a
+        sqsub           v29\sz,  v29\sz,  v22\sz // t15a
+
+        smull_smlal     v4,  v5,  v2,  v3,  v0.h[3], v0.h[2], \sz // -> t4a
+        smull_smlsl     v6,  v7,  v2,  v3,  v0.h[2], v0.h[3], \sz // -> t5a
+        smull_smlsl     v2,  v3,  v24, v23, v0.h[3], v0.h[2], \sz // -> t6a
+        sqrshrn_sz      v22, v4,  v5,  #12, \sz // t4a
+        sqrshrn_sz      v25, v6,  v7,  #12, \sz // t5a
+        smull_smlal     v4,  v5,  v24, v23, v0.h[2], v0.h[3], \sz // -> t7a
+        smull_smlal     v6,  v7,  v17, v30, v0.h[3], v0.h[2], \sz // -> t12
+        sqrshrn_sz      v24, v2,  v3,  #12, \sz // t6a
+        sqrshrn_sz      v23, v4,  v5,  #12, \sz // t7a
+        smull_smlsl     v2,  v3,  v17, v30, v0.h[2], v0.h[3], \sz // -> t13
+        smull_smlsl     v4,  v5,  v29, v18, v0.h[3], v0.h[2], \sz // -> t14
+        sqrshrn_sz      v17, v6,  v7,  #12, \sz // t12
+        smull_smlal     v6,  v7,  v29, v18, v0.h[2], v0.h[3], \sz // -> t15
+        sqrshrn_sz      v29, v2,  v3,  #12, \sz // t13
+        sqrshrn_sz      v30, v4,  v5,  #12, \sz // t14
+        sqrshrn_sz      v18, v6,  v7,  #12, \sz // t15
+
+        sqsub           v2\sz,   v16\sz,  v21\sz // t2a
+.ifc \o0, v16
+        sqadd           \o0\sz,  v16\sz,  v21\sz // out0
+        sqsub           v21\sz,  v31\sz,  v26\sz // t3a
+        sqadd           \o15\sz, v31\sz,  v26\sz // out15
+.else
+        sqadd           v4\sz,   v16\sz,  v21\sz // out0
+        sqsub           v21\sz,  v31\sz,  v26\sz // t3a
+        sqadd           \o15\sz, v31\sz,  v26\sz // out15
+        mov             \o0\szb, v4\szb
+.endif
+        sqneg           \o15\sz, \o15\sz         // out15
+
+        sqsub           v3\sz,   v29\sz,  v18\sz // t15a
+        sqadd           \o13\sz, v29\sz,  v18\sz // out13
+        sqadd           \o2\sz,  v17\sz,  v30\sz // out2
+        sqsub           v26\sz,  v17\sz,  v30\sz // t14a
+        sqneg           \o13\sz, \o13\sz         // out13
+
+        sqadd           \o1\sz,  v19\sz,  v27\sz // out1
+        sqsub           v27\sz,  v19\sz,  v27\sz // t10
+        sqadd           \o14\sz, v28\sz,  v20\sz // out14
+        sqsub           v20\sz,  v28\sz,  v20\sz // t11
+        sqneg           \o1\sz,  \o1\sz          // out1
+
+        sqadd           \o3\sz,  v22\sz,  v24\sz // out3
+        sqsub           v22\sz,  v22\sz,  v24\sz // t6
+        sqadd           \o12\sz, v25\sz,  v23\sz // out12
+        sqsub           v23\sz,  v25\sz,  v23\sz // t7
+        sqneg           \o3\sz,  \o3\sz          // out3
+
+        smull_smlsl     v24, v25, v2,  v21, v0.h[0], v0.h[0], \sz // -> out8 (v24 or v23)
+        smull_smlal     v4,  v5,  v2,  v21, v0.h[0], v0.h[0], \sz // -> out7 (v23 or v24)
+        smull_smlal     v6,  v7,  v26, v3,  v0.h[0], v0.h[0], \sz // -> out5 (v21 or v26)
+
+        sqrshrn_sz      v24, v24, v25, #12, \sz // out8
+        sqrshrn_sz      v4,  v4,  v5,  #12, \sz // out7
+        sqrshrn_sz      v5,  v6,  v7,  #12, \sz // out5
+        smull_smlsl     v6,  v7,  v26, v3,  v0.h[0], v0.h[0], \sz // -> out10 (v26 or v21)
+        smull_smlal     v2,  v3,  v22, v23, v0.h[0], v0.h[0], \sz // -> out4 (v20 or v27)
+        sqrshrn_sz      v26, v6,  v7,  #12, \sz // out10
+
+        smull_smlsl     v6,  v7,  v22, v23, v0.h[0], v0.h[0], \sz // -> out11 (v27 or v20)
+        smull_smlal     v22, v23, v27, v20, v0.h[0], v0.h[0], \sz // -> out6 (v22 or v25)
+        smull_smlsl     v21, v25, v27, v20, v0.h[0], v0.h[0], \sz // -> out9 (v25 or v22)
+
+        sqrshrn_sz      \o4, v2,  v3,  #12, \sz // out4
+        sqrshrn_sz      v6,  v6,  v7,  #12, \sz // out11
+        sqrshrn_sz      v7,  v21, v25, #12, \sz // out9
+        sqrshrn_sz      \o6, v22, v23, #12, \sz // out6
+
+.ifc \o8, v23
+        mov             \o8\szb,  v24\szb
+        mov             \o10\szb, v26\szb
+.endif
+
+        sqneg           \o7\sz,  v4\sz // out7
+        sqneg           \o5\sz,  v5\sz // out5
+        sqneg           \o11\sz, v6\sz // out11
+        sqneg           \o9\sz,  v7\sz // out9
+.endm
+
+function inv_adst_8h_x16_neon, export=1
+        iadst_16        v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, .8h, .16b
+        ret
+endfunc
+
+function inv_flipadst_8h_x16_neon, export=1
+        iadst_16        v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16, .8h, .16b
+        ret
+endfunc
+
+function inv_adst_4h_x16_neon, export=1
+        iadst_16        v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, .4h, .8b
+        ret
+endfunc
+
+function inv_flipadst_4h_x16_neon, export=1
+        iadst_16        v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16, .4h, .8b
+        ret
+endfunc
+
+function inv_identity_8h_x16_neon, export=1
+        mov             w16, #2*(5793-4096)*8
+        dup             v0.4h,   w16
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        sqrdmulh        v2.8h,      v\i\().8h,  v0.h[0]
+        sqadd           v\i\().8h,  v\i\().8h,  v\i\().8h
+        sqadd           v\i\().8h,  v\i\().8h,  v2.8h
+.endr
+        ret
+endfunc
+
+function inv_identity_4h_x16_neon, export=1
+        mov             w16, #2*(5793-4096)*8
+        dup             v0.4h,   w16
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        sqrdmulh        v2.4h,      v\i\().4h,  v0.h[0]
+        sqadd           v\i\().4h,  v\i\().4h,  v\i\().4h
+        sqadd           v\i\().4h,  v\i\().4h,  v2.4h
+.endr
+        ret
+endfunc
+
+.macro identity_8x16_shift2 c
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        sqrdmulh        v2.8h,   \i,      \c
+        sshr            v2.8h,   v2.8h,   #1
+        srhadd          \i,      \i,      v2.8h
+.endr
+.endm
+
+.macro identity_8x16_shift1 c
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        sqrdmulh        v2.8h,   \i,      \c
+        srshr           v2.8h,   v2.8h,   #1
+        sqadd           \i,      \i,      v2.8h
+.endr
+.endm
+
+.macro identity_8x8_shift1 c
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+        sqrdmulh        v2.8h,   \i,      \c
+        srshr           v2.8h,   v2.8h,   #1
+        sqadd           \i,      \i,      v2.8h
+.endr
+.endm
+
+.macro identity_8x8 c
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+        sqrdmulh        v2.8h,   \i,      \c
+        sqadd           \i,      \i,      \i
+        sqadd           \i,      \i,      v2.8h
+.endr
+.endm
+
+.macro def_horz_16 scale=0, identity=0, shift=2, suffix
+function inv_txfm_horz\suffix\()_16x8_neon
+        AARCH64_VALID_CALL_TARGET
+        mov             x14, x30
+        movi            v7.8h,  #0
+.if \identity
+        mov             w16, #2*(5793-4096)*8
+        dup             v0.4h,   w16
+.elseif \scale
+        mov             w16, #2896*8
+        dup             v0.4h,   w16
+.endif
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        ld1             {\i}, [x7]
+        st1             {v7.8h}, [x7], x8
+.endr
+.if \scale
+        scale_input     .8h, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .8h, v0.h[0], v24, v25, v26, v27, v28, v29, v30, v31
+.endif
+.if \identity
+        identity_8x16_shift2 v0.h[0]
+        b               L(horz_16x8_epilog)
+.else
+        blr             x4
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        srshr           \i,  \i,  #\shift
+.endr
+.if \shift == 1
+        b               L(horz_16x8_epilog)
+.else
+L(horz_16x8_epilog):
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+        transpose_8x8h  v24, v25, v26, v27, v28, v29, v30, v31, v4, v5
+
+.irp i, v16.8h, v24.8h, v17.8h, v25.8h, v18.8h, v26.8h, v19.8h, v27.8h, v20.8h, v28.8h, v21.8h, v29.8h, v22.8h, v30.8h, v23.8h, v31.8h
+        st1             {\i}, [x6], #16
+.endr
+
+        ret             x14
+.endif
+.endif
+endfunc
+.endm
+
+def_horz_16 scale=1, identity=0, shift=1, suffix=_scale
+def_horz_16 scale=0, identity=1, shift=0, suffix=_identity
+def_horz_16 scale=0, identity=0, shift=2
+
+function inv_txfm_add_vert_8x16_neon
+        mov             x14, x30
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        ld1             {v\i\().8h}, [x7], x8
+.endr
+        blr             x5
+        load_add_store_8x16 x6, x7
+        ret             x14
+endfunc
+
+function inv_txfm_add_16x16_neon
+        mov             x15, x30
+        sub             sp,  sp,  #512
+        mov             x8,  #16*2
+.irp i, 0, 8
+        add             x6,  sp,  #(\i*16*2)
+.if \i == 8
+        cmp             w3,  w13
+        b.lt            1f
+.endif
+        add             x7,  x2,  #(\i*2)
+        blr             x9
+.endr
+        b               2f
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+2:
+.irp i, 0, 8
+        add             x6,  x0,  #(\i)
+        add             x7,  sp,  #(\i*2)
+        bl              inv_txfm_add_vert_8x16_neon
+.endr
+
+        add             sp,  sp,  #512
+        ret             x15
+endfunc
+
+.macro def_fn_16x16 txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_16x16_8bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         16,  16,  2
+.endif
+.ifc \txfm1, identity
+        adr             x9,  inv_txfm_horz_identity_16x8_neon
+.else
+        adr             x9,  inv_txfm_horz_16x8_neon
+        adr             x4,  inv_\txfm1\()_8h_x16_neon
+.endif
+        adr             x5,  inv_\txfm2\()_8h_x16_neon
+        mov             x13, #\eob_half
+        b               inv_txfm_add_16x16_neon
+endfunc
+.endm
+
+def_fn_16x16 dct, dct, 36
+def_fn_16x16 identity, identity, 36
+def_fn_16x16 dct, adst, 36
+def_fn_16x16 dct, flipadst, 36
+def_fn_16x16 dct, identity, 8
+def_fn_16x16 adst, dct, 36
+def_fn_16x16 adst, adst, 36
+def_fn_16x16 adst, flipadst, 36
+def_fn_16x16 flipadst, dct, 36
+def_fn_16x16 flipadst, adst, 36
+def_fn_16x16 flipadst, flipadst, 36
+def_fn_16x16 identity, dct, 8
+
+.macro def_fn_416_base variant
+function inv_txfm_\variant\()add_16x4_neon
+        mov             x15, x30
+        movi            v4.8h,  #0
+
+.ifc \variant, identity_
+.irp i, v16.4h, v17.4h, v18.4h, v19.4h
+        ld1             {\i},    [x2]
+        st1             {v4.4h}, [x2], #8
+.endr
+.irp i, v16.d, v17.d, v18.d, v19.d
+        ld1             {\i}[1], [x2]
+        st1             {v4.4h}, [x2], #8
+.endr
+        mov             w16, #2*(5793-4096)*8
+        dup             v0.4h,   w16
+.irp i, v20.4h, v21.4h, v22.4h, v23.4h
+        ld1             {\i},    [x2]
+        st1             {v4.4h}, [x2], #8
+.endr
+.irp i, v20.d, v21.d, v22.d, v23.d
+        ld1             {\i}[1], [x2]
+        st1             {v4.4h}, [x2], #8
+.endr
+
+        identity_8x16_shift1 v0.h[0]
+
+        b               L(itx_16x4_epilog)
+.else
+.irp i, v16.4h, v17.4h, v18.4h, v19.4h, v20.4h, v21.4h, v22.4h, v23.4h, v24.4h, v25.4h, v26.4h, v27.4h, v28.4h, v29.4h, v30.4h, v31.4h
+        ld1             {\i},    [x2]
+        st1             {v4.4h}, [x2], #8
+.endr
+
+        blr             x4
+
+        ins             v16.d[1], v20.d[0]
+        ins             v17.d[1], v21.d[0]
+        ins             v18.d[1], v22.d[0]
+        ins             v19.d[1], v23.d[0]
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h
+        srshr           \i,  \i,  #1
+.endr
+
+        ins             v24.d[1], v28.d[0]
+        ins             v25.d[1], v29.d[0]
+        ins             v26.d[1], v30.d[0]
+        ins             v27.d[1], v31.d[0]
+        srshr           v20.8h,  v24.8h,  #1
+        srshr           v21.8h,  v25.8h,  #1
+        srshr           v22.8h,  v26.8h,  #1
+        srshr           v23.8h,  v27.8h,  #1
+
+L(itx_16x4_epilog):
+        transpose_4x8h  v16, v17, v18, v19, v2,  v3,  v4,  v5
+        blr             x5
+        mov             x6,  x0
+        load_add_store_8x4 x6, x7
+
+        transpose_4x8h_mov v20, v21, v22, v23, v2,  v3,  v4,  v5, v16, v17, v18, v19
+        blr             x5
+        add             x6,  x0,  #8
+        load_add_store_8x4 x6, x7
+
+        ret             x15
+.endif
+endfunc
+
+function inv_txfm_\variant\()add_4x16_neon
+        mov             x15, x30
+        movi            v2.8h,   #0
+
+        mov             x11, #32
+        cmp             w3,  w13
+        b.lt            1f
+
+        add             x6,  x2,  #16
+.ifc \variant, identity_
+.irp i, v24.8h, v25.8h, v26.8h, v27.8h
+        ld1             {\i},    [x6]
+        st1             {v2.8h}, [x6], x11
+.endr
+        mov             w16, #(5793-4096)*8
+        dup             v0.4h,   w16
+        identity_8x4_shift1 v24, v25, v26, v27, v0.h[0]
+.else
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h
+        ld1             {\i},    [x6]
+        st1             {v2.8h}, [x6], x11
+.endr
+        blr             x4
+        srshr           v24.8h,  v16.8h,  #1
+        srshr           v25.8h,  v17.8h,  #1
+        srshr           v26.8h,  v18.8h,  #1
+        srshr           v27.8h,  v19.8h,  #1
+.endif
+        transpose_4x8h  v24, v25, v26, v27, v4,  v5,  v6,  v7
+        ins             v28.d[0], v24.d[1]
+        ins             v29.d[0], v25.d[1]
+        ins             v30.d[0], v26.d[1]
+        ins             v31.d[0], v27.d[1]
+
+        b               2f
+1:
+.irp i, v24.4h, v25.4h, v26.4h, v27.4h, v28.4h, v29.4h, v30.4h, v31.4h
+        movi            \i,  #0
+.endr
+2:
+        movi            v2.8h,   #0
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h
+        ld1             {\i},    [x2]
+        st1             {v2.8h}, [x2], x11
+.endr
+.ifc \variant, identity_
+        mov             w16, #(5793-4096)*8
+        dup             v0.4h,   w16
+        identity_8x4_shift1 v16, v17, v18, v19, v0.h[0]
+
+        b               L(itx_4x16_epilog)
+.else
+        blr             x4
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h
+        srshr           \i,  \i,  #1
+.endr
+L(itx_4x16_epilog):
+        transpose_4x8h  v16, v17, v18, v19, v4,  v5,  v6,  v7
+        ins             v20.d[0], v16.d[1]
+        ins             v21.d[0], v17.d[1]
+        ins             v22.d[0], v18.d[1]
+        ins             v23.d[0], v19.d[1]
+
+        blr             x5
+
+        load_add_store_4x16 x0, x6
+
+        ret             x15
+.endif
+endfunc
+.endm
+
+def_fn_416_base identity_
+def_fn_416_base
+
+.macro def_fn_416 w, h, txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  1
+.endif
+.if \w == 4
+.ifnc \txfm1, identity
+        adr             x4,  inv_\txfm1\()_8h_x\w\()_neon
+.endif
+        adr             x5,  inv_\txfm2\()_4h_x\h\()_neon
+        mov             w13, #\eob_half
+.else
+.ifnc \txfm1, identity
+        adr             x4,  inv_\txfm1\()_4h_x\w\()_neon
+.endif
+        adr             x5,  inv_\txfm2\()_8h_x\h\()_neon
+.endif
+.ifc \txfm1, identity
+        b               inv_txfm_identity_add_\w\()x\h\()_neon
+.else
+        b               inv_txfm_add_\w\()x\h\()_neon
+.endif
+endfunc
+.endm
+
+.macro def_fns_416 w, h
+def_fn_416 \w, \h, dct, dct, 29
+def_fn_416 \w, \h, identity, identity, 29
+def_fn_416 \w, \h, dct, adst, 29
+def_fn_416 \w, \h, dct, flipadst, 29
+def_fn_416 \w, \h, dct, identity, 8
+def_fn_416 \w, \h, adst, dct, 29
+def_fn_416 \w, \h, adst, adst, 29
+def_fn_416 \w, \h, adst, flipadst, 29
+def_fn_416 \w, \h, flipadst, dct, 29
+def_fn_416 \w, \h, flipadst, adst, 29
+def_fn_416 \w, \h, flipadst, flipadst, 29
+def_fn_416 \w, \h, identity, dct, 32
+def_fn_416 \w, \h, adst, identity, 8
+def_fn_416 \w, \h, flipadst, identity, 8
+def_fn_416 \w, \h, identity, adst, 32
+def_fn_416 \w, \h, identity, flipadst, 32
+.endm
+
+def_fns_416 4, 16
+def_fns_416 16, 4
+
+
+.macro def_fn_816_base variant
+function inv_txfm_\variant\()add_16x8_neon
+        mov             x15, x30
+        movi            v4.8h,  #0
+        mov             w16, #2896*8
+        dup             v0.4h,   w16
+
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        ld1             {\i},    [x2]
+        st1             {v4.8h}, [x2], #16
+.endr
+
+        scale_input     .8h, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .8h, v0.h[0], v24, v25, v26, v27, v28, v29, v30, v31
+.ifc \variant, identity_
+        mov             w16, #2*(5793-4096)*8
+        dup             v0.4h,   w16
+        identity_8x16_shift1 v0.h[0]
+
+        b               L(itx_16x8_epilog)
+.else
+        blr             x4
+
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        srshr           \i,  \i,  #1
+.endr
+
+L(itx_16x8_epilog):
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v2, v3
+
+        blr             x5
+
+        mov             x6,  x0
+        load_add_store_8x8 x6, x7
+
+        transpose_8x8h_mov v24, v25, v26, v27, v28, v29, v30, v31, v2, v3, v16, v17, v18, v19, v20, v21, v22, v23
+
+        blr             x5
+
+        add             x0,  x0,  #8
+        load_add_store_8x8 x0, x7
+
+        ret             x15
+.endif
+endfunc
+
+function inv_txfm_\variant\()add_8x16_neon
+        mov             x15, x30
+        movi            v4.8h,   #0
+        mov             w16, #2896*8
+        dup             v0.4h,   w16
+        mov             x11, #32
+
+        cmp             w3,  w13
+        b.lt            1f
+
+        add             x6,  x2,  #16
+.ifc \variant, identity_
+.irp i, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        ld1             {\i},    [x6]
+        st1             {v4.8h}, [x6], x11
+.endr
+        scale_input     .8h, v0.h[0], v24, v25, v26, v27, v28, v29, v30, v31
+        // The identity shl #1 and downshift srshr #1 cancel out
+.else
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+        ld1             {\i},    [x6]
+        st1             {v4.8h}, [x6], x11
+.endr
+        scale_input     .8h, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+        blr             x4
+
+        srshr           v24.8h,  v16.8h,  #1
+        srshr           v25.8h,  v17.8h,  #1
+        srshr           v26.8h,  v18.8h,  #1
+        srshr           v27.8h,  v19.8h,  #1
+        srshr           v28.8h,  v20.8h,  #1
+        srshr           v29.8h,  v21.8h,  #1
+        srshr           v30.8h,  v22.8h,  #1
+        srshr           v31.8h,  v23.8h,  #1
+.endif
+        transpose_8x8h  v24, v25, v26, v27, v28, v29, v30, v31, v2, v3
+
+        b               2f
+
+1:
+.irp i, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        movi            \i,  #0
+.endr
+
+2:
+        movi            v4.8h,   #0
+        mov             w16, #2896*8
+        dup             v0.4h,   w16
+
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+        ld1             {\i},    [x2]
+        st1             {v4.8h}, [x2], x11
+.endr
+        scale_input     .8h, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+.ifc \variant, identity_
+        // The identity shl #1 and downshift srshr #1 cancel out
+
+        b               L(itx_8x16_epilog)
+.else
+        blr             x4
+
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+        srshr           \i,  \i,  #1
+.endr
+
+L(itx_8x16_epilog):
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v2, v3
+
+        blr             x5
+
+        load_add_store_8x16 x0, x6
+
+        ret             x15
+.endif
+endfunc
+.endm
+
+def_fn_816_base identity_
+def_fn_816_base
+
+.macro def_fn_816 w, h, txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  1
+.endif
+.ifnc \txfm1, identity
+        adr             x4,  inv_\txfm1\()_8h_x\w\()_neon
+.endif
+        adr             x5,  inv_\txfm2\()_8h_x\h\()_neon
+.if \w == 8
+        mov             x13, #\eob_half
+.endif
+.ifc \txfm1, identity
+        b               inv_txfm_identity_add_\w\()x\h\()_neon
+.else
+        b               inv_txfm_add_\w\()x\h\()_neon
+.endif
+endfunc
+.endm
+
+.macro def_fns_816 w, h
+def_fn_816 \w, \h, dct, dct, 43
+def_fn_816 \w, \h, identity, identity, 43
+def_fn_816 \w, \h, dct, adst, 43
+def_fn_816 \w, \h, dct, flipadst, 43
+def_fn_816 \w, \h, dct, identity, 8
+def_fn_816 \w, \h, adst, dct, 43
+def_fn_816 \w, \h, adst, adst, 43
+def_fn_816 \w, \h, adst, flipadst, 43
+def_fn_816 \w, \h, flipadst, dct, 43
+def_fn_816 \w, \h, flipadst, adst, 43
+def_fn_816 \w, \h, flipadst, flipadst, 43
+def_fn_816 \w, \h, identity, dct, 64
+def_fn_816 \w, \h, adst, identity, 8
+def_fn_816 \w, \h, flipadst, identity, 8
+def_fn_816 \w, \h, identity, adst, 64
+def_fn_816 \w, \h, identity, flipadst, 64
+.endm
+
+def_fns_816 8, 16
+def_fns_816 16, 8
+
+function inv_dct32_odd_8h_x16_neon, export=1
+        movrel          x16, idct_coeffs, 2*16
+        ld1             {v0.8h, v1.8h}, [x16]
+        sub             x16, x16, #2*16
+
+        smull_smlsl     v2,  v3,  v16, v31, v0.h[0], v0.h[1], .8h // -> t16a
+        smull_smlal     v4,  v5,  v16, v31, v0.h[1], v0.h[0], .8h // -> t31a
+        smull_smlsl     v6,  v7,  v24, v23, v0.h[2], v0.h[3], .8h // -> t17a
+        sqrshrn_sz      v16, v2,  v3,  #12, .8h                   // t16a
+        sqrshrn_sz      v31, v4,  v5,  #12, .8h                   // t31a
+        smull_smlal     v2,  v3,  v24, v23, v0.h[3], v0.h[2], .8h // -> t30a
+        smull_smlsl     v4,  v5,  v20, v27, v0.h[4], v0.h[5], .8h // -> t18a
+        sqrshrn_sz      v24, v6,  v7,  #12, .8h                   // t17a
+        sqrshrn_sz      v23, v2,  v3,  #12, .8h                   // t30a
+        smull_smlal     v6,  v7,  v20, v27, v0.h[5], v0.h[4], .8h // -> t29a
+        smull_smlsl     v2,  v3,  v28, v19, v0.h[6], v0.h[7], .8h // -> t19a
+        sqrshrn_sz      v20, v4,  v5,  #12, .8h                   // t18a
+        sqrshrn_sz      v27, v6,  v7,  #12, .8h                   // t29a
+        smull_smlal     v4,  v5,  v28, v19, v0.h[7], v0.h[6], .8h // -> t28a
+        smull_smlsl     v6,  v7,  v18, v29, v1.h[0], v1.h[1], .8h // -> t20a
+        sqrshrn_sz      v28, v2,  v3,  #12, .8h                   // t19a
+        sqrshrn_sz      v19, v4,  v5,  #12, .8h                   // t28a
+        smull_smlal     v2,  v3,  v18, v29, v1.h[1], v1.h[0], .8h // -> t27a
+        smull_smlsl     v4,  v5,  v26, v21, v1.h[2], v1.h[3], .8h // -> t21a
+        sqrshrn_sz      v18, v6,  v7,  #12, .8h                   // t20a
+        sqrshrn_sz      v29, v2,  v3,  #12, .8h                   // t27a
+        smull_smlal     v6,  v7,  v26, v21, v1.h[3], v1.h[2], .8h // -> t26a
+        smull_smlsl     v2,  v3,  v22, v25, v1.h[4], v1.h[5], .8h // -> t22a
+        sqrshrn_sz      v26, v4,  v5,  #12, .8h                   // t21a
+        sqrshrn_sz      v21, v6,  v7,  #12, .8h                   // t26a
+        smull_smlal     v4,  v5,  v22, v25, v1.h[5], v1.h[4], .8h // -> t25a
+        smull_smlsl     v6,  v7,  v30, v17, v1.h[6], v1.h[7], .8h // -> t23a
+        sqrshrn_sz      v22, v2,  v3,  #12, .8h                   // t22a
+        sqrshrn_sz      v25, v4,  v5,  #12, .8h                   // t25a
+        smull_smlal     v2,  v3,  v30, v17, v1.h[7], v1.h[6], .8h // -> t24a
+        sqrshrn_sz      v30, v6,  v7,  #12, .8h                   // t23a
+        sqrshrn_sz      v17, v2,  v3,  #12, .8h                   // t24a
+
+        ld1             {v0.8h}, [x16]
+
+        sqsub           v2.8h,   v16.8h,  v24.8h // t17
+        sqadd           v16.8h,  v16.8h,  v24.8h // t16
+        sqsub           v3.8h,   v31.8h,  v23.8h // t30
+        sqadd           v31.8h,  v31.8h,  v23.8h // t31
+        sqsub           v24.8h,  v28.8h,  v20.8h // t18
+        sqadd           v28.8h,  v28.8h,  v20.8h // t19
+        sqadd           v23.8h,  v18.8h,  v26.8h // t20
+        sqsub           v18.8h,  v18.8h,  v26.8h // t21
+        sqsub           v20.8h,  v30.8h,  v22.8h // t22
+        sqadd           v30.8h,  v30.8h,  v22.8h // t23
+        sqadd           v26.8h,  v17.8h,  v25.8h // t24
+        sqsub           v17.8h,  v17.8h,  v25.8h // t25
+        sqsub           v22.8h,  v29.8h,  v21.8h // t26
+        sqadd           v29.8h,  v29.8h,  v21.8h // t27
+        sqadd           v25.8h,  v19.8h,  v27.8h // t28
+        sqsub           v19.8h,  v19.8h,  v27.8h // t29
+
+        smull_smlsl     v4,  v5,  v3,  v2,  v0.h[4], v0.h[5], .8h // -> t17a
+        smull_smlal     v6,  v7,  v3,  v2,  v0.h[5], v0.h[4], .8h // -> t30a
+        smull_smlal     v2,  v3,  v19, v24, v0.h[5], v0.h[4], .8h // -> t18a
+        sqrshrn_sz      v21, v4,  v5,  #12, .8h                   // t17a
+        sqrshrn_sz      v27, v6,  v7,  #12, .8h                   // t30a
+        neg             v2.4s,   v2.4s                            // -> t18a
+        neg             v3.4s,   v3.4s                            // -> t18a
+        smull_smlsl     v4,  v5,  v19, v24, v0.h[4], v0.h[5], .8h // -> t29a
+        smull_smlsl     v6,  v7,  v22, v18, v0.h[6], v0.h[7], .8h // -> t21a
+        sqrshrn_sz      v19, v2,  v3,  #12, .8h                   // t18a
+        sqrshrn_sz      v24, v4,  v5,  #12, .8h                   // t29a
+        smull_smlal     v2,  v3,  v22, v18, v0.h[7], v0.h[6], .8h // -> t26a
+        smull_smlal     v4,  v5,  v17, v20, v0.h[7], v0.h[6], .8h // -> t22a
+        sqrshrn_sz      v22, v6,  v7,  #12, .8h                   // t21a
+        sqrshrn_sz      v18, v2,  v3,  #12, .8h                   // t26a
+        neg             v4.4s,   v4.4s                            // -> t22a
+        neg             v5.4s,   v5.4s                            // -> t22a
+        smull_smlsl     v6,  v7,  v17, v20, v0.h[6], v0.h[7], .8h // -> t25a
+        sqrshrn_sz      v17, v4,  v5,  #12, .8h                   // t22a
+        sqrshrn_sz      v20, v6,  v7,  #12, .8h                   // t25a
+
+        sqsub           v2.8h,   v27.8h,  v24.8h // t29
+        sqadd           v27.8h,  v27.8h,  v24.8h // t30
+        sqsub           v3.8h,   v21.8h,  v19.8h // t18
+        sqadd           v21.8h,  v21.8h,  v19.8h // t17
+        sqsub           v24.8h,  v16.8h,  v28.8h // t19a
+        sqadd           v16.8h,  v16.8h,  v28.8h // t16a
+        sqsub           v19.8h,  v30.8h,  v23.8h // t20a
+        sqadd           v30.8h,  v30.8h,  v23.8h // t23a
+        sqsub           v28.8h,  v17.8h,  v22.8h // t21
+        sqadd           v17.8h,  v17.8h,  v22.8h // t22
+        sqadd           v23.8h,  v26.8h,  v29.8h // t24a
+        sqsub           v26.8h,  v26.8h,  v29.8h // t27a
+        sqadd           v22.8h,  v20.8h,  v18.8h // t25
+        sqsub           v20.8h,  v20.8h,  v18.8h // t26
+        sqsub           v29.8h,  v31.8h,  v25.8h // t28a
+        sqadd           v31.8h,  v31.8h,  v25.8h // t31a
+
+        smull_smlsl     v4,  v5,  v2,  v3,  v0.h[2], v0.h[3], .8h // -> t18a
+        smull_smlal     v6,  v7,  v2,  v3,  v0.h[3], v0.h[2], .8h // -> t29a
+        smull_smlsl     v2,  v3,  v29, v24, v0.h[2], v0.h[3], .8h // -> t19
+        sqrshrn_sz      v18, v4,  v5,  #12, .8h                   // t18a
+        sqrshrn_sz      v25, v6,  v7,  #12, .8h                   // t29a
+        smull_smlal     v4,  v5,  v29, v24, v0.h[3], v0.h[2], .8h // -> t28
+        smull_smlal     v6,  v7,  v26, v19, v0.h[3], v0.h[2], .8h // -> t20
+        sqrshrn_sz      v29, v2,  v3,  #12, .8h                   // t19
+        sqrshrn_sz      v24, v4,  v5,  #12, .8h                   // t28
+        neg             v6.4s,   v6.4s                            // -> t20
+        neg             v7.4s,   v7.4s                            // -> t20
+        smull_smlsl     v2,  v3,  v26, v19, v0.h[2], v0.h[3], .8h // -> t27
+        smull_smlal     v4,  v5,  v20, v28, v0.h[3], v0.h[2], .8h // -> t21a
+        sqrshrn_sz      v26, v6,  v7,  #12, .8h                   // t20
+        sqrshrn_sz      v19, v2,  v3,  #12, .8h                   // t27
+        neg             v4.4s,   v4.4s                            // -> t21a
+        neg             v5.4s,   v5.4s                            // -> t21a
+        smull_smlsl     v6,  v7,  v20, v28, v0.h[2], v0.h[3], .8h // -> t26a
+        sqrshrn_sz      v20, v4,  v5,  #12, .8h                   // t21a
+        sqrshrn_sz      v28, v6,  v7,  #12, .8h                   // t26a
+
+        sqsub           v2.8h,   v16.8h,  v30.8h // t23
+        sqadd           v16.8h,  v16.8h,  v30.8h // t16 = out16
+        sqsub           v3.8h,   v31.8h,  v23.8h // t24
+        sqadd           v31.8h,  v31.8h,  v23.8h // t31 = out31
+        sqsub           v23.8h,  v21.8h,  v17.8h // t22a
+        sqadd           v17.8h,  v21.8h,  v17.8h // t17a = out17
+        sqadd           v30.8h,  v27.8h,  v22.8h // t30a = out30
+        sqsub           v21.8h,  v27.8h,  v22.8h // t25a
+        sqsub           v27.8h,  v18.8h,  v20.8h // t21
+        sqadd           v18.8h,  v18.8h,  v20.8h // t18 = out18
+        sqadd           v4.8h,   v29.8h,  v26.8h // t19a = out19
+        sqsub           v26.8h,  v29.8h,  v26.8h // t20a
+        sqadd           v29.8h,  v25.8h,  v28.8h // t29 = out29
+        sqsub           v25.8h,  v25.8h,  v28.8h // t26
+        sqadd           v28.8h,  v24.8h,  v19.8h // t28a = out28
+        sqsub           v24.8h,  v24.8h,  v19.8h // t27a
+        mov             v19.16b, v4.16b          // out19
+
+        smull_smlsl     v4,  v5,  v24, v26, v0.h[0], v0.h[0], .8h // -> t20
+        smull_smlal     v6,  v7,  v24, v26, v0.h[0], v0.h[0], .8h // -> t27
+        sqrshrn_sz      v20, v4,  v5,  #12, .8h   // t20
+        sqrshrn_sz      v22, v6,  v7,  #12, .8h   // t27
+
+        smull_smlal     v4,  v5,  v25, v27, v0.h[0], v0.h[0], .8h // -> t26a
+        smull_smlsl     v6,  v7,  v25, v27, v0.h[0], v0.h[0], .8h // -> t21a
+        mov             v27.16b,  v22.16b         // t27
+        sqrshrn_sz      v26, v4,  v5,  #12, .8h   // t26a
+
+        smull_smlsl     v24, v25, v21, v23, v0.h[0], v0.h[0], .8h // -> t22
+        smull_smlal     v4,  v5,  v21, v23, v0.h[0], v0.h[0], .8h // -> t25
+        sqrshrn_sz      v21, v6,  v7,  #12, .8h   // t21a
+        sqrshrn_sz      v22, v24, v25, #12, .8h   // t22
+        sqrshrn_sz      v25, v4,  v5,  #12, .8h   // t25
+
+        smull_smlsl     v4,  v5,  v3,  v2,  v0.h[0], v0.h[0], .8h // -> t23a
+        smull_smlal     v6,  v7,  v3,  v2,  v0.h[0], v0.h[0], .8h // -> t24a
+        sqrshrn_sz      v23, v4,  v5,  #12, .8h   // t23a
+        sqrshrn_sz      v24, v6,  v7,  #12, .8h   // t24a
+
+        ret
+endfunc
+
+.macro def_horz_32 scale=0, shift=2, suffix
+function inv_txfm_horz\suffix\()_dct_32x8_neon
+        mov             x14, x30
+        movi            v7.8h,  #0
+        lsl             x8,  x8,  #1
+.if \scale
+        mov             w16, #2896*8
+        dup             v0.4h,   w16
+.endif
+
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        ld1             {\i}, [x7]
+        st1             {v7.8h}, [x7], x8
+.endr
+        sub             x7,  x7,  x8, lsl #4
+        add             x7,  x7,  x8, lsr #1
+.if \scale
+        scale_input     .8h, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .8h, v0.h[0], v24, v25, v26, v27, v28, v29, v30, v31
+.endif
+        bl              inv_dct_8h_x16_neon
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+        transpose_8x8h  v24, v25, v26, v27, v28, v29, v30, v31, v4, v5
+
+.macro store1 r0, r1
+        st1             {\r0}, [x6], #16
+        st1             {\r1}, [x6], #16
+        add             x6,  x6,  #32
+.endm
+        store1          v16.8h,  v24.8h
+        store1          v17.8h,  v25.8h
+        store1          v18.8h,  v26.8h
+        store1          v19.8h,  v27.8h
+        store1          v20.8h,  v28.8h
+        store1          v21.8h,  v29.8h
+        store1          v22.8h,  v30.8h
+        store1          v23.8h,  v31.8h
+.purgem store1
+        sub             x6,  x6,  #64*8
+
+        movi            v7.8h,  #0
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        ld1             {\i}, [x7]
+        st1             {v7.8h}, [x7], x8
+.endr
+.if \scale
+        // This relies on the fact that the idct also leaves the right coeff in v0.h[1]
+        scale_input     .8h, v0.h[1], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .8h, v0.h[1], v24, v25, v26, v27, v28, v29, v30, v31
+.endif
+        bl              inv_dct32_odd_8h_x16_neon
+        transpose_8x8h  v31, v30, v29, v28, v27, v26, v25, v24, v4, v5
+        transpose_8x8h  v23, v22, v21, v20, v19, v18, v17, v16, v4, v5
+.macro store2 r0, r1, shift
+        ld1             {v4.8h, v5.8h}, [x6]
+        sqsub           v7.8h,   v4.8h,   \r0
+        sqsub           v6.8h,   v5.8h,   \r1
+        sqadd           v4.8h,   v4.8h,   \r0
+        sqadd           v5.8h,   v5.8h,   \r1
+        rev64           v6.8h,   v6.8h
+        rev64           v7.8h,   v7.8h
+        srshr           v4.8h,   v4.8h,   #\shift
+        srshr           v5.8h,   v5.8h,   #\shift
+        srshr           v6.8h,   v6.8h,   #\shift
+        srshr           v7.8h,   v7.8h,   #\shift
+        ext             v6.16b,  v6.16b,  v6.16b,  #8
+        st1             {v4.8h, v5.8h}, [x6], #32
+        ext             v7.16b,  v7.16b,  v7.16b,  #8
+        st1             {v6.8h, v7.8h}, [x6], #32
+.endm
+
+        store2          v31.8h,  v23.8h, \shift
+        store2          v30.8h,  v22.8h, \shift
+        store2          v29.8h,  v21.8h, \shift
+        store2          v28.8h,  v20.8h, \shift
+        store2          v27.8h,  v19.8h, \shift
+        store2          v26.8h,  v18.8h, \shift
+        store2          v25.8h,  v17.8h, \shift
+        store2          v24.8h,  v16.8h, \shift
+.purgem store2
+        ret             x14
+endfunc
+.endm
+
+def_horz_32 scale=0, shift=2
+def_horz_32 scale=1, shift=1, suffix=_scale
+
+function inv_txfm_add_vert_dct_8x32_neon
+        mov             x14, x30
+        lsl             x8,  x8,  #1
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        ld1             {v\i\().8h}, [x7], x8
+.endr
+        sub             x7,  x7,  x8, lsl #4
+
+        bl              inv_dct_8h_x16_neon
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        st1             {v\i\().8h}, [x7], x8
+.endr
+        sub             x7,  x7,  x8, lsl #4
+        add             x7,  x7,  x8, lsr #1
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        ld1             {v\i\().8h}, [x7], x8
+.endr
+        sub             x7,  x7,  x8, lsl #4
+        sub             x7,  x7,  x8, lsr #1
+        bl              inv_dct32_odd_8h_x16_neon
+
+        neg             x9,  x8
+        mov             x10, x6
+.macro combine r0, r1, r2, r3, op, stride
+        ld1             {v5.8h}, [x7],    \stride
+        ld1             {v2.8b}, [x10],   x1
+        ld1             {v6.8h}, [x7],    \stride
+        ld1             {v3.8b}, [x10],   x1
+        \op             v5.8h,   v5.8h,   \r0
+        ld1             {v7.8h}, [x7],    \stride
+        ld1             {v4.8b}, [x10],   x1
+        srshr           v5.8h,   v5.8h,   #4
+        \op             v6.8h,   v6.8h,   \r1
+        uaddw           v5.8h,   v5.8h,   v2.8b
+        srshr           v6.8h,   v6.8h,   #4
+        \op             v7.8h,   v7.8h,   \r2
+        sqxtun          v2.8b,   v5.8h
+        ld1             {v5.8h}, [x7],    \stride
+        uaddw           v6.8h,   v6.8h,   v3.8b
+        srshr           v7.8h,   v7.8h,   #4
+        \op             v5.8h,   v5.8h,   \r3
+        st1             {v2.8b}, [x6],    x1
+        ld1             {v2.8b}, [x10],   x1
+        sqxtun          v3.8b,   v6.8h
+        uaddw           v7.8h,   v7.8h,   v4.8b
+        srshr           v5.8h,   v5.8h,   #4
+        st1             {v3.8b}, [x6],    x1
+        sqxtun          v4.8b,   v7.8h
+        uaddw           v5.8h,   v5.8h,   v2.8b
+        st1             {v4.8b}, [x6],    x1
+        sqxtun          v2.8b,   v5.8h
+        st1             {v2.8b}, [x6],    x1
+.endm
+        combine         v31.8h, v30.8h, v29.8h, v28.8h, sqadd, x8
+        combine         v27.8h, v26.8h, v25.8h, v24.8h, sqadd, x8
+        combine         v23.8h, v22.8h, v21.8h, v20.8h, sqadd, x8
+        combine         v19.8h, v18.8h, v17.8h, v16.8h, sqadd, x8
+        sub             x7,  x7,  x8
+        combine         v16.8h, v17.8h, v18.8h, v19.8h, sqsub, x9
+        combine         v20.8h, v21.8h, v22.8h, v23.8h, sqsub, x9
+        combine         v24.8h, v25.8h, v26.8h, v27.8h, sqsub, x9
+        combine         v28.8h, v29.8h, v30.8h, v31.8h, sqsub, x9
+.purgem combine
+
+        ret             x14
+endfunc
+
+const eob_32x32
+        .short 36, 136, 300, 1024
+endconst
+
+const eob_16x32
+        .short 36, 151, 279, 512
+endconst
+
+const eob_16x32_shortside
+        .short 36, 512
+endconst
+
+const eob_8x32
+        .short 43, 107, 171, 256
+endconst
+
+function inv_txfm_add_identity_identity_32x32_8bpc_neon, export=1
+        movi            v0.8h,  #0
+        movrel          x13, eob_32x32
+
+        mov             x8,  #2*32
+1:
+        mov             w9,  #0
+        movrel          x12, eob_32x32
+2:
+        add             w9,  w9,  #8
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23
+        ld1             {v\i\().8h}, [x2]
+        st1             {v0.8h}, [x2], x8
+.endr
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+
+        load_add_store_8x8 x0, x7, shiftbits=2
+        ldrh            w11, [x12], #2
+        sub             x0,  x0,  x1, lsl #3
+        add             x0,  x0,  #8
+        cmp             w3,  w11
+        b.ge            2b
+
+        ldrh            w11, [x13], #2
+        cmp             w3,  w11
+        b.lt            9f
+
+        sub             x0,  x0,  w9, uxtw
+        add             x0,  x0,  x1, lsl #3
+        msub            x2,  x8,  x9,  x2
+        add             x2,  x2,  #2*8
+        b               1b
+9:
+        ret
+endfunc
+
+.macro shift_8_regs op, shift
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+        \op             \i,  \i,  #\shift
+.endr
+.endm
+
+.macro def_identity_1632 w, h, wshort, hshort
+function inv_txfm_add_identity_identity_\w\()x\h\()_8bpc_neon, export=1
+        mov             w16, #2896*8
+        mov             w17, #2*(5793-4096)*8
+        dup             v1.4h,   w16
+        movi            v0.8h,   #0
+        mov             v1.h[1], w17
+        movrel          x13, eob_16x32\hshort
+
+        mov             x8,  #2*\h
+1:
+        mov             w9,  #0
+        movrel          x12, eob_16x32\wshort
+2:
+        add             w9,  w9,  #8
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+        ld1             {\i}, [x2]
+        st1             {v0.8h}, [x2], x8
+.endr
+        scale_input     .8h, v1.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+
+.if \w == 16
+        // 16x32
+        identity_8x8_shift1 v1.h[1]
+.else
+        // 32x16
+        shift_8_regs    sqshl, 1
+        identity_8x8    v1.h[1]
+.endif
+
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+
+.if \w == 16
+        load_add_store_8x8 x0, x7, shiftbits=2
+.else
+        load_add_store_8x8 x0, x7, shiftbits=4
+.endif
+        ldrh            w11, [x12], #2
+        sub             x0,  x0,  x1, lsl #3
+        add             x0,  x0,  #8
+        cmp             w3,  w11
+        b.ge            2b
+
+        ldrh            w11, [x13], #2
+        cmp             w3,  w11
+        b.lt            9f
+
+        sub             x0,  x0,  w9, uxtw
+        add             x0,  x0,  x1, lsl #3
+        msub            x2,  x8,  x9,  x2
+        add             x2,  x2,  #2*8
+        b               1b
+9:
+        ret
+endfunc
+.endm
+
+def_identity_1632 16, 32, _shortside,
+def_identity_1632 32, 16, , _shortside
+
+.macro def_identity_832 w, h
+function inv_txfm_add_identity_identity_\w\()x\h\()_8bpc_neon, export=1
+        movi            v0.8h,  #0
+        movrel          x13, eob_8x32
+
+        mov             w8,  #2*\h
+1:
+        ldrh            w12, [x13], #2
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+        ld1             {\i}, [x2]
+        st1             {v0.8h}, [x2], x8
+.endr
+
+.if \w == 8
+        // 8x32
+        shift_8_regs    srshr, 1
+.endif
+
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+
+        cmp             w3,  w12
+.if \w == 8
+        load_add_store_8x8 x0, x7, shiftbits=2
+.else
+        load_add_store_8x8 x0, x7, shiftbits=3
+.endif
+
+        b.lt            9f
+.if \w == 8
+        sub             x2,  x2,  x8, lsl #3
+        add             x2,  x2,  #2*8
+.else
+        sub             x0,  x0,  x1, lsl #3
+        add             x0,  x0,  #8
+.endif
+        b               1b
+
+9:
+        ret
+endfunc
+.endm
+
+def_identity_832 8, 32
+def_identity_832 32, 8
+
+function inv_txfm_add_dct_dct_32x32_8bpc_neon, export=1
+        idct_dc         32,  32,  2
+
+        mov             x15, x30
+        sub             sp,  sp,  #2048
+        movrel          x13, eob_32x32
+        ldrh            w12, [x13], #2
+
+.irp i, 0, 8, 16, 24
+        add             x6,  sp,  #(\i*32*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 24
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        add             x7,  x2,  #(\i*2)
+        mov             x8,  #32*2
+        bl              inv_txfm_horz_dct_32x8_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24
+        add             x6,  x0,  #(\i)
+        add             x7,  sp,  #(\i*2)
+        mov             x8,  #32*2
+        bl              inv_txfm_add_vert_dct_8x32_neon
+.endr
+
+        add             sp,  sp,  #2048
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_16x32_8bpc_neon, export=1
+        idct_dc         16,  32,  1
+
+        mov             x15, x30
+        sub             sp,  sp,  #1024
+        movrel          x13, eob_16x32
+        ldrh            w12, [x13], #2
+        adr             x4,  inv_dct_8h_x16_neon
+
+.irp i, 0, 8, 16, 24
+        add             x6,  sp,  #(\i*16*2)
+        add             x7,  x2,  #(\i*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 24
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        mov             x8,  #2*32
+        bl              inv_txfm_horz_scale_16x8_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #8
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8
+        add             x6,  x0,  #(\i)
+        add             x7,  sp,  #(\i*2)
+        mov             x8,  #16*2
+        bl              inv_txfm_add_vert_dct_8x32_neon
+.endr
+
+        add             sp,  sp,  #1024
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_32x16_8bpc_neon, export=1
+        idct_dc         32,  16,  1
+
+        mov             x15, x30
+        sub             sp,  sp,  #1024
+
+        adr             x5,  inv_dct_8h_x16_neon
+
+.irp i, 0, 8
+        add             x6,  sp,  #(\i*32*2)
+        add             x7,  x2,  #(\i*2)
+.if \i > 0
+        mov             w8,  #(16 - \i)
+        cmp             w3,  #36
+        b.lt            1f
+.endif
+        mov             x8,  #2*16
+        bl              inv_txfm_horz_scale_dct_32x8_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+        mov             x8,  #32*2
+.irp i, 0, 8, 16, 24
+        add             x6,  x0,  #(\i)
+        add             x7,  sp,  #(\i*2)
+        bl              inv_txfm_add_vert_8x16_neon
+.endr
+
+        add             sp,  sp,  #1024
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_8x32_8bpc_neon, export=1
+        idct_dc         8,   32, 2
+
+        mov             x15, x30
+        sub             sp,  sp,  #512
+
+        movrel          x13, eob_8x32
+
+        movi            v28.8h,  #0
+        mov             x8,  #2*32
+        mov             w9,  #32
+        mov             x6,  sp
+1:
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23
+        ld1             {v\i\().8h}, [x2]
+        st1             {v28.8h}, [x2], x8
+.endr
+        ldrh            w12, [x13], #2
+        sub             x2,  x2,  x8, lsl #3
+        sub             w9,  w9,  #8
+        add             x2,  x2,  #2*8
+
+        bl              inv_dct_8h_x8_neon
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23
+        srshr           v\i\().8h,  v\i\().8h,  #2
+.endr
+
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v24, v25
+
+        st1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x6], #64
+        cmp             w3,  w12
+        st1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x6], #64
+
+        b.ge            1b
+        cbz             w9,  3f
+
+        movi            v29.8h,  #0
+        movi            v30.8h,  #0
+        movi            v31.8h,  #0
+2:
+        subs            w9,  w9,  #8
+.rept 2
+        st1             {v28.8h,v29.8h,v30.8h,v31.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+        mov             x6,  x0
+        mov             x7,  sp
+        mov             x8,  #8*2
+        bl              inv_txfm_add_vert_dct_8x32_neon
+
+        add             sp,  sp,  #512
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_32x8_8bpc_neon, export=1
+        idct_dc         32,  8,   2
+
+        mov             x15, x30
+        sub             sp,  sp,  #512
+
+        mov             x6,  sp
+        mov             x7,  x2
+        mov             x8,  #8*2
+        bl              inv_txfm_horz_dct_32x8_neon
+
+        mov             x8,  #2*32
+        mov             w9,  #0
+1:
+        add             x6,  x0,  x9
+        add             x7,  sp,  x9, lsl #1 // #(\i*2)
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23
+        ld1             {v\i\().8h}, [x7], x8
+.endr
+        add             w9,  w9,  #8
+
+        bl              inv_dct_8h_x8_neon
+
+        cmp             w9,  #32
+
+        load_add_store_8x8 x6, x7
+
+        b.lt            1b
+
+        add             sp,  sp,  #512
+        ret             x15
+endfunc
+
+function inv_dct64_step1_neon
+        // in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+        // in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+        // in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+        // in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+
+        ld1             {v0.8h, v1.8h}, [x17], #32
+
+        sqrdmulh        v23.8h,  v16.8h,  v0.h[1]   // t63a
+        sqrdmulh        v16.8h,  v16.8h,  v0.h[0]   // t32a
+        sqrdmulh        v22.8h,  v17.8h,  v0.h[2]   // t62a
+        sqrdmulh        v17.8h,  v17.8h,  v0.h[3]   // t33a
+        sqrdmulh        v21.8h,  v18.8h,  v0.h[5]   // t61a
+        sqrdmulh        v18.8h,  v18.8h,  v0.h[4]   // t34a
+        sqrdmulh        v20.8h,  v19.8h,  v0.h[6]   // t60a
+        sqrdmulh        v19.8h,  v19.8h,  v0.h[7]   // t35a
+
+        sqadd           v24.8h,  v16.8h,  v17.8h    // t32
+        sqsub           v25.8h,  v16.8h,  v17.8h    // t33
+        sqsub           v26.8h,  v19.8h,  v18.8h    // t34
+        sqadd           v27.8h,  v19.8h,  v18.8h    // t35
+        sqadd           v28.8h,  v20.8h,  v21.8h    // t60
+        sqsub           v29.8h,  v20.8h,  v21.8h    // t61
+        sqsub           v30.8h,  v23.8h,  v22.8h    // t62
+        sqadd           v31.8h,  v23.8h,  v22.8h    // t63
+
+        smull_smlal     v2,  v3,  v29, v26, v1.h[0], v1.h[1], .8h // -> t34a
+        smull_smlsl     v4,  v5,  v29, v26, v1.h[1], v1.h[0], .8h // -> t61a
+        neg             v2.4s,   v2.4s              // t34a
+        neg             v3.4s,   v3.4s              // t34a
+        smull_smlsl     v6,  v7,  v30, v25, v1.h[1], v1.h[0], .8h // -> t33a
+        sqrshrn_sz      v26, v2,  v3,  #12, .8h     // t34a
+        smull_smlal     v2,  v3,  v30, v25, v1.h[0], v1.h[1], .8h // -> t62a
+        sqrshrn_sz      v29, v4,  v5,  #12, .8h     // t61a
+        sqrshrn_sz      v25, v6,  v7,  #12, .8h     // t33a
+        sqrshrn_sz      v30, v2,  v3,  #12, .8h     // t62a
+
+        sqadd           v16.8h,  v24.8h,  v27.8h    // t32a
+        sqsub           v19.8h,  v24.8h,  v27.8h    // t35a
+        sqadd           v17.8h,  v25.8h,  v26.8h    // t33
+        sqsub           v18.8h,  v25.8h,  v26.8h    // t34
+        sqsub           v20.8h,  v31.8h,  v28.8h    // t60a
+        sqadd           v23.8h,  v31.8h,  v28.8h    // t63a
+        sqsub           v21.8h,  v30.8h,  v29.8h    // t61
+        sqadd           v22.8h,  v30.8h,  v29.8h    // t62
+
+        smull_smlal     v2,  v3,  v21, v18, v1.h[2], v1.h[3], .8h // -> t61a
+        smull_smlsl     v4,  v5,  v21, v18, v1.h[3], v1.h[2], .8h // -> t34a
+        smull_smlal     v6,  v7,  v20, v19, v1.h[2], v1.h[3], .8h // -> t60
+        sqrshrn_sz      v21, v2,  v3,  #12, .8h     // t61a
+        sqrshrn_sz      v18, v4,  v5,  #12, .8h     // t34a
+        smull_smlsl     v2,  v3,  v20, v19, v1.h[3], v1.h[2], .8h // -> t35
+        sqrshrn_sz      v20, v6,  v7,  #12, .8h     // t60
+        sqrshrn_sz      v19, v2,  v3,  #12, .8h     // t35
+
+        st1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x6], #64
+        st1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x6], #64
+
+        ret
+endfunc
+
+function inv_dct64_step2_neon
+        movrel          x16, idct_coeffs
+        ld1             {v0.4h}, [x16]
+1:
+        // t32a/33/34a/35/60/61a/62/63a
+        // t56a/57/58a/59/36/37a/38/39a
+        // t40a/41/42a/43/52/53a/54/55a
+        // t48a/49/50a/51/44/45a/46/47a
+        ldr             q16, [x6, #2*8*0]  // t32a
+        ldr             q17, [x9, #2*8*8]  // t39a
+        ldr             q18, [x9, #2*8*0]  // t63a
+        ldr             q19, [x6, #2*8*8]  // t56a
+        ldr             q20, [x6, #2*8*16] // t40a
+        ldr             q21, [x9, #2*8*24] // t47a
+        ldr             q22, [x9, #2*8*16] // t55a
+        ldr             q23, [x6, #2*8*24] // t48a
+
+        sqadd           v24.8h,  v16.8h, v17.8h // t32
+        sqsub           v25.8h,  v16.8h, v17.8h // t39
+        sqadd           v26.8h,  v18.8h, v19.8h // t63
+        sqsub           v27.8h,  v18.8h, v19.8h // t56
+        sqsub           v28.8h,  v21.8h, v20.8h // t40
+        sqadd           v29.8h,  v21.8h, v20.8h // t47
+        sqadd           v30.8h,  v23.8h, v22.8h // t48
+        sqsub           v31.8h,  v23.8h, v22.8h // t55
+
+        smull_smlal     v2,  v3,  v27, v25, v0.h[3], v0.h[2], .8h // -> t56a
+        smull_smlsl     v4,  v5,  v27, v25, v0.h[2], v0.h[3], .8h // -> t39a
+        smull_smlal     v6,  v7,  v31, v28, v0.h[3], v0.h[2], .8h // -> t40a
+        sqrshrn_sz      v25, v2,  v3,  #12, .8h     // t56a
+        sqrshrn_sz      v27, v4,  v5,  #12, .8h     // t39a
+        neg             v6.4s,   v6.4s              // t40a
+        neg             v7.4s,   v7.4s              // t40a
+        smull_smlsl     v2,  v3,  v31, v28, v0.h[2], v0.h[3], .8h // -> t55a
+        sqrshrn_sz      v31, v6,  v7,  #12, .8h     // t40a
+        sqrshrn_sz      v28, v2,  v3,  #12, .8h     // t55a
+
+        sqadd           v16.8h,  v24.8h,  v29.8h    // t32a
+        sqsub           v19.8h,  v24.8h,  v29.8h    // t47a
+        sqadd           v17.8h,  v27.8h,  v31.8h    // t39
+        sqsub           v18.8h,  v27.8h,  v31.8h    // t40
+        sqsub           v20.8h,  v26.8h,  v30.8h    // t48a
+        sqadd           v23.8h,  v26.8h,  v30.8h    // t63a
+        sqsub           v21.8h,  v25.8h,  v28.8h    // t55
+        sqadd           v22.8h,  v25.8h,  v28.8h    // t56
+
+        smull_smlsl     v2,  v3,  v21, v18, v0.h[0], v0.h[0], .8h // -> t40a
+        smull_smlal     v4,  v5,  v21, v18, v0.h[0], v0.h[0], .8h // -> t55a
+        smull_smlsl     v6,  v7,  v20, v19, v0.h[0], v0.h[0], .8h // -> t47
+        sqrshrn_sz      v18, v2,  v3,  #12, .8h     // t40a
+        sqrshrn_sz      v21, v4,  v5,  #12, .8h     // t55a
+        smull_smlal     v2,  v3,  v20, v19, v0.h[0], v0.h[0], .8h // -> t48
+        sqrshrn_sz      v19, v6,  v7,  #12, .8h     // t47
+        sqrshrn_sz      v20, v2,  v3,  #12, .8h     // t48
+
+        str             q16, [x6, #2*8*0]  // t32a
+        str             q17, [x9, #2*8*0]  // t39
+        str             q18, [x6, #2*8*8]  // t40a
+        str             q19, [x9, #2*8*8]  // t47
+        str             q20, [x6, #2*8*16] // t48
+        str             q21, [x9, #2*8*16] // t55a
+        str             q22, [x6, #2*8*24] // t56
+        str             q23, [x9, #2*8*24] // t63a
+
+        add             x6,  x6,  #2*8
+        sub             x9,  x9,  #2*8
+        cmp             x6,  x9
+        b.lt            1b
+        ret
+endfunc
+
+.macro load8 src, strd, zero, clear
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h
+.if \clear
+        ld1             {\i}, [\src]
+        st1             {\zero}, [\src], \strd
+.else
+        ld1             {\i}, [\src], \strd
+.endif
+.endr
+.endm
+
+.macro store16 dst
+.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        st1             {\i}, [\dst], #16
+.endr
+.endm
+
+.macro clear_upper8
+.irp i, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h
+        movi            \i,  #0
+.endr
+.endm
+
+.macro movi_if reg, val, cond
+.if \cond
+        movi            \reg, \val
+.endif
+.endm
+
+.macro movdup_if reg, gpr, val, cond
+.if \cond
+        mov             \gpr, \val
+        dup             \reg, \gpr
+.endif
+.endm
+
+.macro st1_if regs, dst, cond
+.if \cond
+        st1             \regs, \dst
+.endif
+.endm
+
+.macro str_if reg, dst, cond
+.if \cond
+        str             \reg, \dst
+.endif
+.endm
+
+.macro stroff_if reg, dst, dstoff, cond
+.if \cond
+        str             \reg, \dst, \dstoff
+.endif
+.endm
+
+.macro scale_if cond, c, r0, r1, r2, r3, r4, r5, r6, r7
+.if \cond
+        scale_input     .8h, \c, \r0, \r1, \r2, \r3, \r4, \r5, \r6, \r7
+.endif
+.endm
+
+.macro def_dct64_func suffix, clear=0, scale=0
+function inv_txfm_dct\suffix\()_8h_x64_neon, export=1
+        mov             x14, x30
+        mov             x6,  sp
+        lsl             x8,  x8,  #2
+
+        movdup_if       v0.4h, w16, #2896*8, \scale
+        movi_if         v7.8h,  #0, \clear
+        load8           x7,  x8,  v7.8h, \clear
+        clear_upper8
+        sub             x7,  x7,  x8, lsl #3
+        add             x7,  x7,  x8, lsr #1
+        scale_if        \scale, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+
+        bl              inv_dct_8h_x16_neon
+
+        store16         x6
+
+        movdup_if       v0.4h, w16, #2896*8, \scale
+        movi_if         v7.8h,  #0, \clear
+        load8           x7,  x8,  v7.8h, \clear
+        clear_upper8
+        sub             x7,  x7,  x8, lsl #3
+        lsr             x8,  x8,  #1
+        sub             x7,  x7,  x8, lsr #1
+        scale_if        \scale, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23
+
+        bl              inv_dct32_odd_8h_x16_neon
+
+        add             x10, x6,  #16*15
+        sub             x6,  x6,  #16*16
+
+        mov             x9,  #-16
+
+.macro store_addsub r0, r1, r2, r3
+        ld1             {v2.8h}, [x6], #16
+        ld1             {v3.8h}, [x6], #16
+        sqadd           v6.8h,  v2.8h,  \r0
+        sqsub           \r0,    v2.8h,  \r0
+        ld1             {v4.8h}, [x6], #16
+        sqadd           v7.8h,  v3.8h,  \r1
+        sqsub           \r1,    v3.8h,  \r1
+        ld1             {v5.8h}, [x6], #16
+        sqadd           v2.8h,  v4.8h,  \r2
+        sub             x6,  x6,  #16*4
+        sqsub           \r2,    v4.8h,  \r2
+        st1             {v6.8h}, [x6], #16
+        st1             {\r0},   [x10], x9
+        sqadd           v3.8h,  v5.8h,  \r3
+        sqsub           \r3,    v5.8h,  \r3
+        st1             {v7.8h}, [x6], #16
+        st1             {\r1},   [x10], x9
+        st1             {v2.8h}, [x6], #16
+        st1             {\r2},   [x10], x9
+        st1             {v3.8h}, [x6], #16
+        st1             {\r3},   [x10], x9
+.endm
+        store_addsub    v31.8h, v30.8h, v29.8h, v28.8h
+        store_addsub    v27.8h, v26.8h, v25.8h, v24.8h
+        store_addsub    v23.8h, v22.8h, v21.8h, v20.8h
+        store_addsub    v19.8h, v18.8h, v17.8h, v16.8h
+.purgem store_addsub
+
+        add             x6,  x6,  #2*8*16
+
+        movrel          x17, idct64_coeffs
+        movdup_if       v0.4h, w16, #2896*8, \scale
+        movi_if         v7.8h,  #0, \clear
+        add             x9,  x7,  x8, lsl #4 // offset 16
+        add             x10, x7,  x8, lsl #3 // offset 8
+        sub             x9,  x9,  x8         // offset 15
+        sub             x11, x10, x8         // offset 7
+        ld1             {v16.8h}, [x7]  // in1  (offset 0)
+        ld1             {v17.8h}, [x9]  // in31 (offset 15)
+        ld1             {v18.8h}, [x10] // in17 (offset 8)
+        ld1             {v19.8h}, [x11] // in15 (offset 7)
+        st1_if          {v7.8h}, [x7],  \clear
+        st1_if          {v7.8h}, [x9],  \clear
+        st1_if          {v7.8h}, [x10], \clear
+        st1_if          {v7.8h}, [x11], \clear
+        scale_if        \scale, v0.h[0], v16, v17, v18, v19
+        bl              inv_dct64_step1_neon
+        movdup_if       v0.4h, w16, #2896*8, \scale
+        movi_if         v7.8h,  #0, \clear
+        add             x7,  x7,  x8, lsl #2 // offset 4
+        sub             x9,  x9,  x8, lsl #2 // offset 11
+        sub             x10, x7,  x8         // offset 3
+        add             x11, x9,  x8         // offset 12
+        ld1             {v16.8h}, [x10] // in7  (offset 3)
+        ld1             {v17.8h}, [x11] // in25 (offset 12)
+        ld1             {v18.8h}, [x9]  // in23 (offset 11)
+        ld1             {v19.8h}, [x7]  // in9  (offset 4)
+        st1_if          {v7.8h}, [x7],  \clear
+        st1_if          {v7.8h}, [x9],  \clear
+        st1_if          {v7.8h}, [x10], \clear
+        st1_if          {v7.8h}, [x11], \clear
+        scale_if        \scale, v0.h[0], v16, v17, v18, v19
+        bl              inv_dct64_step1_neon
+        movdup_if       v0.4h, w16, #2896*8, \scale
+        movi_if         v7.8h,  #0, \clear
+        sub             x10, x10, x8, lsl #1 // offset 1
+        sub             x9,  x9,  x8, lsl #1 // offset 9
+        add             x7,  x7,  x8         // offset 5
+        add             x11, x11, x8         // offset 13
+        ldr             q16, [x10, x8] // in5  (offset 2)
+        ldr             q17, [x11]     // in27 (offset 13)
+        ldr             q18, [x9,  x8] // in21 (offset 10)
+        ldr             q19, [x7]      // in11 (offset 5)
+        stroff_if       q7,  [x10, x8], \clear
+        str_if          q7,  [x11],     \clear
+        stroff_if       q7,  [x9,  x8], \clear
+        str_if          q7,  [x7],      \clear
+        scale_if        \scale, v0.h[0], v16, v17, v18, v19
+        bl              inv_dct64_step1_neon
+        movdup_if       v0.4h, w16, #2896*8, \scale
+        movi_if         v7.8h,  #0, \clear
+        ldr             q16, [x10]     // in3  (offset 1)
+        ldr             q17, [x11, x8] // in29 (offset 14)
+        ldr             q18, [x9]      // in19 (offset 9)
+        ldr             q19, [x7,  x8] // in13 (offset 6)
+        str_if          q7,  [x10],     \clear
+        stroff_if       q7,  [x11, x8], \clear
+        str_if          q7,  [x9],      \clear
+        stroff_if       q7,  [x7,  x8], \clear
+        scale_if        \scale, v0.h[0], v16, v17, v18, v19
+        bl              inv_dct64_step1_neon
+
+        sub             x6,  x6,  #2*8*32
+        add             x9,  x6,  #2*8*7
+
+        bl              inv_dct64_step2_neon
+
+        ret             x14
+endfunc
+.endm
+
+def_dct64_func
+def_dct64_func _clear, clear=1
+def_dct64_func _clear_scale, clear=1, scale=1
+
+
+function inv_txfm_horz_dct_64x8_neon
+        mov             x14, x30
+
+        mov             x7,  sp
+        add             x8,  sp,  #2*8*(64 - 4)
+        add             x9,  x6,  #2*56
+        mov             x10, #2*64
+        mov             x11, #-2*8*4
+
+        dup             v7.8h,  w12
+1:
+        ld1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x7], #64
+        ld1             {v28.8h, v29.8h, v30.8h, v31.8h}, [x8], x11
+        ld1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x7], #64
+        ld1             {v24.8h, v25.8h, v26.8h, v27.8h}, [x8], x11
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+        transpose_8x8h  v31, v30, v29, v28, v27, v26, v25, v24, v4, v5
+
+.macro store_addsub src0, src1, src2, src3
+        sqsub           v1.8h,   \src0,   \src1
+        sqadd           v0.8h,   \src0,   \src1
+        sqsub           v3.8h,   \src2,   \src3
+        srshl           v1.8h,   v1.8h,   v7.8h
+        sqadd           v2.8h,   \src2,   \src3
+        srshl           v0.8h,   v0.8h,   v7.8h
+        srshl           v3.8h,   v3.8h,   v7.8h
+        rev64           v1.8h,   v1.8h
+        srshl           v2.8h,   v2.8h,   v7.8h
+        rev64           v3.8h,   v3.8h
+        ext             v1.16b,  v1.16b,  v1.16b,  #8
+        st1             {v0.8h},  [x6], x10
+        ext             v3.16b,  v3.16b,  v3.16b,  #8
+        st1             {v1.8h},  [x9], x10
+        st1             {v2.8h},  [x6], x10
+        st1             {v3.8h},  [x9], x10
+.endm
+        store_addsub    v16.8h,  v31.8h,  v17.8h,  v30.8h
+        store_addsub    v18.8h,  v29.8h,  v19.8h,  v28.8h
+        store_addsub    v20.8h,  v27.8h,  v21.8h,  v26.8h
+        store_addsub    v22.8h,  v25.8h,  v23.8h,  v24.8h
+.purgem store_addsub
+        sub             x6,  x6,  x10, lsl #3
+        sub             x9,  x9,  x10, lsl #3
+        add             x6,  x6,  #16
+        sub             x9,  x9,  #16
+
+        cmp             x7,  x8
+        b.lt            1b
+        ret             x14
+endfunc
+
+function inv_txfm_add_vert_dct_8x64_neon
+        mov             x14, x30
+        lsl             x8,  x8,  #1
+
+        mov             x7,  sp
+        add             x8,  sp,  #2*8*(64 - 4)
+        add             x9,  x6,  x1, lsl #6
+        sub             x9,  x9,  x1
+        neg             x10, x1
+        mov             x11, #-2*8*4
+
+1:
+        ld1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x7], #64
+        ld1             {v28.8h, v29.8h, v30.8h, v31.8h}, [x8], x11
+        ld1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x7], #64
+        ld1             {v24.8h, v25.8h, v26.8h, v27.8h}, [x8], x11
+
+.macro add_dest_addsub src0, src1, src2, src3
+        ld1             {v0.8b}, [x6], x1
+        ld1             {v1.8b}, [x9], x10
+        sqadd           v4.8h,   \src0,   \src1
+        ld1             {v2.8b}, [x6]
+        sqsub           v5.8h,   \src0,   \src1
+        ld1             {v3.8b}, [x9]
+        sqadd           v6.8h,   \src2,   \src3
+        sqsub           v7.8h,   \src2,   \src3
+        sub             x6,  x6,  x1
+        sub             x9,  x9,  x10
+        srshr           v4.8h,   v4.8h,   #4
+        srshr           v5.8h,   v5.8h,   #4
+        srshr           v6.8h,   v6.8h,   #4
+        uaddw           v4.8h,   v4.8h,   v0.8b
+        srshr           v7.8h,   v7.8h,   #4
+        uaddw           v5.8h,   v5.8h,   v1.8b
+        uaddw           v6.8h,   v6.8h,   v2.8b
+        sqxtun          v0.8b,   v4.8h
+        uaddw           v7.8h,   v7.8h,   v3.8b
+        sqxtun          v1.8b,   v5.8h
+        st1             {v0.8b}, [x6], x1
+        sqxtun          v2.8b,   v6.8h
+        st1             {v1.8b}, [x9], x10
+        sqxtun          v3.8b,   v7.8h
+        st1             {v2.8b}, [x6], x1
+        st1             {v3.8b}, [x9], x10
+.endm
+        add_dest_addsub v16.8h,  v31.8h,  v17.8h,  v30.8h
+        add_dest_addsub v18.8h,  v29.8h,  v19.8h,  v28.8h
+        add_dest_addsub v20.8h,  v27.8h,  v21.8h,  v26.8h
+        add_dest_addsub v22.8h,  v25.8h,  v23.8h,  v24.8h
+.purgem add_dest_addsub
+        cmp             x7,  x8
+        b.lt            1b
+
+        ret             x14
+endfunc
+
+function inv_txfm_add_dct_dct_64x64_8bpc_neon, export=1
+        idct_dc         64,  64,  2
+
+        mov             x15, x30
+
+        sub_sp          64*32*2+64*8*2
+        add             x5,  sp, #64*8*2
+
+        movrel          x13, eob_32x32
+
+.irp i, 0, 8, 16, 24
+        add             x6,  x5,  #(\i*64*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.endif
+        add             x7,  x2,  #(\i*2)
+        mov             x8,  #32*2
+        mov             x12, #-2 // shift
+        bl              inv_txfm_dct_clear_8h_x64_neon
+        add             x6,  x5,  #(\i*64*2)
+        bl              inv_txfm_horz_dct_64x8_neon
+.if \i < 24
+        ldrh            w12, [x13], #2
+.endif
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #2
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24, 32, 40, 48, 56
+        add             x7,  x5,  #(\i*2)
+        mov             x8,  #64*2
+        bl              inv_txfm_dct_8h_x64_neon
+        add             x6,  x0,  #(\i)
+        bl              inv_txfm_add_vert_dct_8x64_neon
+.endr
+
+        add             sp,  x5,  #64*32*2
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_64x32_8bpc_neon, export=1
+        idct_dc         64,  32,  1
+
+        mov             x15, x30
+
+        sub_sp          64*32*2+64*8*2
+        add             x5,  sp, #64*8*2
+
+        movrel          x13, eob_32x32
+
+.irp i, 0, 8, 16, 24
+        add             x6,  x5,  #(\i*64*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.endif
+        add             x7,  x2,  #(\i*2)
+        mov             x8,  #32*2
+        mov             x12, #-1 // shift
+        bl              inv_txfm_dct_clear_scale_8h_x64_neon
+        add             x6,  x5,  #(\i*64*2)
+        bl              inv_txfm_horz_dct_64x8_neon
+.if \i < 24
+        ldrh            w12, [x13], #2
+.endif
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #2
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24, 32, 40, 48, 56
+        add             x6,  x0,  #(\i)
+        add             x7,  x5,  #(\i*2)
+        mov             x8,  #64*2
+        bl              inv_txfm_add_vert_dct_8x32_neon
+.endr
+
+        add             sp,  x5,  #64*32*2
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_32x64_8bpc_neon, export=1
+        idct_dc         32,  64,  1
+
+        mov             x15, x30
+
+        sub_sp          32*32*2+64*8*2
+        add             x5,  sp, #64*8*2
+
+        movrel          x13, eob_32x32
+        ldrh            w12, [x13], #2
+
+.irp i, 0, 8, 16, 24
+        add             x6,  x5,  #(\i*32*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 24
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        add             x7,  x2,  #(\i*2)
+        mov             x8,  #32*2
+        bl              inv_txfm_horz_scale_dct_32x8_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24
+        add             x7,  x5,  #(\i*2)
+        mov             x8,  #32*2
+        bl              inv_txfm_dct_8h_x64_neon
+        add             x6,  x0,  #(\i)
+        bl              inv_txfm_add_vert_dct_8x64_neon
+.endr
+
+        add             sp,  x5,  #32*32*2
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_64x16_8bpc_neon, export=1
+        idct_dc         64,  16,  2
+
+        mov             x15, x30
+
+        sub_sp          64*16*2+64*8*2
+        add             x4,  sp, #64*8*2
+
+        movrel          x13, eob_16x32
+
+.irp i, 0, 8
+        add             x6,  x4,  #(\i*64*2)
+.if \i > 0
+        mov             w8,  #(16 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.endif
+        add             x7,  x2,  #(\i*2)
+        mov             x8,  #16*2
+        mov             x12, #-2 // shift
+        bl              inv_txfm_dct_clear_8h_x64_neon
+        add             x6,  x4,  #(\i*64*2)
+        bl              inv_txfm_horz_dct_64x8_neon
+.if \i < 8
+        ldrh            w12, [x13], #2
+.endif
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #2
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+        adr             x5,  inv_dct_8h_x16_neon
+        mov             x8,  #64*2
+.irp i, 0, 8, 16, 24, 32, 40, 48, 56
+        add             x6,  x0,  #(\i)
+        add             x7,  x4,  #(\i*2)
+        bl              inv_txfm_add_vert_8x16_neon
+.endr
+
+        add             sp,  x4,  #64*16*2
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_16x64_8bpc_neon, export=1
+        idct_dc         16,  64,  2
+
+        mov             x15, x30
+
+        sub_sp          16*32*2+64*8*2
+        add             x5,  sp, #64*8*2
+
+        movrel          x13, eob_16x32
+        ldrh            w12, [x13], #2
+
+        adr             x4,  inv_dct_8h_x16_neon
+.irp i, 0, 8, 16, 24
+        add             x6,  x5,  #(\i*16*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 24
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        add             x7,  x2,  #(\i*2)
+        mov             x8,  #32*2
+        bl              inv_txfm_horz_16x8_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #8
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8
+        add             x7,  x5,  #(\i*2)
+        mov             x8,  #16*2
+        bl              inv_txfm_dct_8h_x64_neon
+        add             x6,  x0,  #(\i)
+        bl              inv_txfm_add_vert_dct_8x64_neon
+.endr
+
+        add             sp,  x5,  #16*32*2
+        ret             x15
+endfunc
diff --git a/media/libdav1d/src/src/arm/64/itx16.S b/media/libdav1d/src/src/arm/64/itx16.S
new file mode 100644
index 0000000000..31ee9be1b4
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/itx16.S
@@ -0,0 +1,3657 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// The exported functions in this file have got the following signature:
+// void itxfm_add(pixel *dst, ptrdiff_t dst_stride, coef *coeff, int eob,
+//                int bitdepth_max);
+
+// Most of the functions use the following register layout:
+// x0-x3  external parameters
+// x4     function pointer to first transform
+// x5     function pointer to second transform
+// x6     output parameter for helper function
+// x7     input parameter for helper function
+// x8     input stride for helper function
+// x9-x12 scratch variables for helper functions
+// x13    pointer to list of eob thresholds
+// x14    return pointer for helper function
+// x15    return pointer for main function
+
+// The SIMD registers most often use the following layout:
+// v0-v1   multiplication coefficients
+// v2-v7   scratch registers
+// v8-v15  unused
+// v16-v31 inputs/outputs of transforms
+
+const idct_coeffs, align=4
+        // idct4
+        .int            2896, 2896*8*(1<<16), 1567, 3784
+        // idct8
+        .int            799, 4017, 3406, 2276
+        // idct16
+        .int            401, 4076, 3166, 2598
+        .int            1931, 3612, 3920, 1189
+        // idct32
+        .int            201, 4091, 3035, 2751
+        .int            1751, 3703, 3857, 1380
+        .int            995, 3973, 3513, 2106
+        .int            2440, 3290, 4052, 601
+endconst
+
+const idct64_coeffs, align=4
+        .int            101*8*(1<<16), 4095*8*(1<<16), 2967*8*(1<<16), -2824*8*(1<<16)
+        .int            1660*8*(1<<16), 3745*8*(1<<16), 3822*8*(1<<16), -1474*8*(1<<16)
+        .int            4076, 401, 4017, 799
+
+        .int            4036*8*(1<<16), -700*8*(1<<16), 2359*8*(1<<16), 3349*8*(1<<16)
+        .int            3461*8*(1<<16), -2191*8*(1<<16), 897*8*(1<<16), 3996*8*(1<<16)
+        .int            -3166, -2598, -799, -4017
+
+        .int            501*8*(1<<16), 4065*8*(1<<16), 3229*8*(1<<16), -2520*8*(1<<16)
+        .int            2019*8*(1<<16), 3564*8*(1<<16), 3948*8*(1<<16), -1092*8*(1<<16)
+        .int            3612, 1931, 2276, 3406
+
+        .int            4085*8*(1<<16), -301*8*(1<<16), 2675*8*(1<<16), 3102*8*(1<<16)
+        .int            3659*8*(1<<16), -1842*8*(1<<16), 1285*8*(1<<16), 3889*8*(1<<16)
+        .int            -3920, -1189, -3406, -2276
+endconst
+
+const iadst4_coeffs, align=4
+        .int            1321, 3803, 2482, 3344
+endconst
+
+const iadst8_coeffs, align=4
+        .int            4076, 401, 3612, 1931
+        .int            2598, 3166, 1189, 3920
+        // idct_coeffs
+        .int            2896, 0, 1567, 3784
+endconst
+
+const iadst16_coeffs, align=4
+        .int            4091, 201, 3973, 995
+        .int            3703, 1751, 3290, 2440
+        .int            2751, 3035, 2106, 3513
+        .int            1380, 3857, 601, 4052
+endconst
+
+.macro mul_mla d, s0, s1, c0, c1
+        mul             \d\().4s, \s0\().4s, \c0
+        mla             \d\().4s, \s1\().4s, \c1
+.endm
+
+.macro mul_mls d, s0, s1, c0, c1
+        mul             \d\().4s, \s0\().4s, \c0
+        mls             \d\().4s, \s1\().4s, \c1
+.endm
+
+.macro scale_input sz, c, r0, r1, r2 r3, r4, r5, r6, r7
+        sqrdmulh        \r0\sz,  \r0\sz,  \c
+        sqrdmulh        \r1\sz,  \r1\sz,  \c
+        sqrdmulh        \r2\sz,  \r2\sz,  \c
+        sqrdmulh        \r3\sz,  \r3\sz,  \c
+.ifnb \r4
+        sqrdmulh        \r4\sz,  \r4\sz,  \c
+        sqrdmulh        \r5\sz,  \r5\sz,  \c
+        sqrdmulh        \r6\sz,  \r6\sz,  \c
+        sqrdmulh        \r7\sz,  \r7\sz,  \c
+.endif
+.endm
+
+.macro smin_4s r0, r1, r2
+        smin            \r0\().4s, \r1\().4s, \r2\().4s
+.endm
+.macro smax_4s r0, r1, r2
+        smax            \r0\().4s, \r1\().4s, \r2\().4s
+.endm
+
+.macro load_add_store load, shift, addsrc, adddst, min, store, dst, src, shiftbits=4
+.ifnb \load
+        ld1             {\load},  [\src], x1
+.endif
+.ifnb \shift
+        srshr           \shift,  \shift,  #\shiftbits
+.endif
+.ifnb \addsrc
+        usqadd          \adddst, \addsrc
+.endif
+.ifnb \min
+        smin            \min,  \min,  v7.8h
+.endif
+.ifnb \store
+        st1             {\store},  [\dst], x1
+.endif
+.endm
+.macro load_add_store_8x16 dst, src
+        mov             \src, \dst
+        mvni            v7.8h,   #0xfc, lsl #8 // 0x3ff
+        load_add_store  v2.8h,  v16.8h,       ,      ,       ,       ,  \dst, \src
+        load_add_store  v3.8h,  v17.8h,       ,      ,       ,       ,  \dst, \src
+        load_add_store  v4.8h,  v18.8h, v16.8h, v2.8h,       ,       ,  \dst, \src
+        load_add_store  v5.8h,  v19.8h, v17.8h, v3.8h,  v2.8h,       ,  \dst, \src
+        load_add_store  v16.8h, v20.8h, v18.8h, v4.8h,  v3.8h,  v2.8h,  \dst, \src
+        load_add_store  v17.8h, v21.8h, v19.8h, v5.8h,  v4.8h,  v3.8h,  \dst, \src
+        load_add_store  v18.8h, v22.8h, v20.8h, v16.8h, v5.8h,  v4.8h,  \dst, \src
+        load_add_store  v19.8h, v23.8h, v21.8h, v17.8h, v16.8h, v5.8h,  \dst, \src
+        load_add_store  v20.8h, v24.8h, v22.8h, v18.8h, v17.8h, v16.8h, \dst, \src
+        load_add_store  v21.8h, v25.8h, v23.8h, v19.8h, v18.8h, v17.8h, \dst, \src
+        load_add_store  v22.8h, v26.8h, v24.8h, v20.8h, v19.8h, v18.8h, \dst, \src
+        load_add_store  v23.8h, v27.8h, v25.8h, v21.8h, v20.8h, v19.8h, \dst, \src
+        load_add_store  v24.8h, v28.8h, v26.8h, v22.8h, v21.8h, v20.8h, \dst, \src
+        load_add_store  v25.8h, v29.8h, v27.8h, v23.8h, v22.8h, v21.8h, \dst, \src
+        load_add_store  v26.8h, v30.8h, v28.8h, v24.8h, v23.8h, v22.8h, \dst, \src
+        load_add_store  v27.8h, v31.8h, v29.8h, v25.8h, v24.8h, v23.8h, \dst, \src
+        load_add_store        ,       , v30.8h, v26.8h, v25.8h, v24.8h, \dst, \src
+        load_add_store        ,       , v31.8h, v27.8h, v26.8h, v25.8h, \dst, \src
+        load_add_store        ,       ,       ,       , v27.8h, v26.8h, \dst, \src
+        load_add_store        ,       ,       ,       ,       , v27.8h, \dst, \src
+.endm
+.macro load_add_store_8x8 dst, src, shiftbits=4
+        mov             \src, \dst
+        mvni            v7.8h,   #0xfc, lsl #8 // 0x3ff
+        load_add_store  v2.8h,  v16.8h,       ,      ,       ,       ,  \dst, \src, \shiftbits
+        load_add_store  v3.8h,  v17.8h,       ,      ,       ,       ,  \dst, \src, \shiftbits
+        load_add_store  v4.8h,  v18.8h, v16.8h, v2.8h,       ,       ,  \dst, \src, \shiftbits
+        load_add_store  v5.8h,  v19.8h, v17.8h, v3.8h,  v2.8h,       ,  \dst, \src, \shiftbits
+        load_add_store  v16.8h, v20.8h, v18.8h, v4.8h,  v3.8h,  v2.8h,  \dst, \src, \shiftbits
+        load_add_store  v17.8h, v21.8h, v19.8h, v5.8h,  v4.8h,  v3.8h,  \dst, \src, \shiftbits
+        load_add_store  v18.8h, v22.8h, v20.8h, v16.8h, v5.8h,  v4.8h,  \dst, \src, \shiftbits
+        load_add_store  v19.8h, v23.8h, v21.8h, v17.8h, v16.8h, v5.8h,  \dst, \src, \shiftbits
+        load_add_store        ,       , v22.8h, v18.8h, v17.8h, v16.8h, \dst, \src, \shiftbits
+        load_add_store        ,       , v23.8h, v19.8h, v18.8h, v17.8h, \dst, \src, \shiftbits
+        load_add_store        ,       ,       ,       , v19.8h, v18.8h, \dst, \src, \shiftbits
+        load_add_store        ,       ,       ,       ,       , v19.8h, \dst, \src, \shiftbits
+.endm
+.macro load_add_store_8x4 dst, src, shiftbits=4
+        mov             \src, \dst
+        mvni            v7.8h,   #0xfc, lsl #8 // 0x3ff
+        load_add_store  v2.8h, v16.8h,       ,      ,      ,      , \dst, \src, \shiftbits
+        load_add_store  v3.8h, v17.8h,       ,      ,      ,      , \dst, \src, \shiftbits
+        load_add_store  v4.8h, v18.8h, v16.8h, v2.8h,      ,      , \dst, \src, \shiftbits
+        load_add_store  v5.8h, v19.8h, v17.8h, v3.8h, v2.8h,      , \dst, \src, \shiftbits
+        load_add_store       ,       , v18.8h, v4.8h, v3.8h, v2.8h, \dst, \src, \shiftbits
+        load_add_store       ,       , v19.8h, v5.8h, v4.8h, v3.8h, \dst, \src, \shiftbits
+        load_add_store       ,       ,       ,      , v5.8h, v4.8h, \dst, \src, \shiftbits
+        load_add_store       ,       ,       ,      ,      , v5.8h, \dst, \src, \shiftbits
+.endm
+.macro load_add_store4 load, inssrc, insdst, shift, addsrc, adddst, min, store, dst, src
+.ifnb \load
+        ld1             {\load}[0],  [\src], x1
+.endif
+.ifnb \inssrc
+        ins             \insdst\().d[1],   \inssrc\().d[0]
+.endif
+.ifnb \shift
+        srshr           \shift,  \shift,  #4
+.endif
+.ifnb \load
+        ld1             {\load}[1],  [\src], x1
+.endif
+.ifnb \addsrc
+        usqadd          \adddst, \addsrc
+.endif
+.ifnb \store
+        st1             {\store}[0],  [\dst], x1
+.endif
+.ifnb \min
+        smin            \min,  \min,  v7.8h
+.endif
+.ifnb \store
+        st1             {\store}[1],  [\dst], x1
+.endif
+.endm
+.macro load_add_store_4x16 dst, src
+        mov             \src, \dst
+        mvni            v7.8h,   #0xfc, lsl #8 // 0x3ff
+        load_add_store4 v0.d,  v17, v16,       ,       ,      ,       ,      ,  \dst, \src
+        load_add_store4 v1.d,  v19, v18,       ,       ,      ,       ,      ,  \dst, \src
+        load_add_store4 v2.d,  v21, v20, v16.8h,       ,      ,       ,      ,  \dst, \src
+        load_add_store4 v3.d,  v23, v22, v18.8h, v16.8h, v0.8h,       ,      ,  \dst, \src
+        load_add_store4 v17.d, v25, v24, v20.8h, v18.8h, v1.8h,  v0.8h,      ,  \dst, \src
+        load_add_store4 v19.d, v27, v26, v22.8h, v20.8h, v2.8h,  v1.8h,  v0.d,  \dst, \src
+        load_add_store4 v21.d, v29, v28, v24.8h, v22.8h, v3.8h,  v2.8h,  v1.d,  \dst, \src
+        load_add_store4 v23.d, v31, v30, v26.8h, v24.8h, v17.8h, v3.8h,  v2.d,  \dst, \src
+        load_add_store4      ,    ,    , v28.8h, v26.8h, v19.8h, v17.8h, v3.d,  \dst, \src
+        load_add_store4      ,    ,    , v30.8h, v28.8h, v21.8h, v19.8h, v17.d, \dst, \src
+        load_add_store4      ,    ,    ,       , v30.8h, v23.8h, v21.8h, v19.d, \dst, \src
+        load_add_store4      ,    ,    ,       ,      ,        , v23.8h, v21.d, \dst, \src
+        load_add_store4      ,    ,    ,       ,      ,        ,       , v23.d, \dst, \src
+.endm
+.macro load_add_store_4x8 dst, src
+        mov             \src, \dst
+        mvni            v7.8h,   #0xfc, lsl #8 // 0x3ff
+        load_add_store4 v0.d, v17, v16,       ,       ,      ,      ,     , \dst, \src
+        load_add_store4 v1.d, v19, v18,       ,       ,      ,      ,     , \dst, \src
+        load_add_store4 v2.d, v21, v20, v16.8h,       ,      ,      ,     , \dst, \src
+        load_add_store4 v3.d, v23, v22, v18.8h, v16.8h, v0.8h,      ,     , \dst, \src
+        load_add_store4     ,    ,    , v20.8h, v18.8h, v1.8h, v0.8h,     , \dst, \src
+        load_add_store4     ,    ,    , v22.8h, v20.8h, v2.8h, v1.8h, v0.d, \dst, \src
+        load_add_store4     ,    ,    ,       , v22.8h, v3.8h, v2.8h, v1.d, \dst, \src
+        load_add_store4     ,    ,    ,       ,       ,      , v3.8h, v2.d, \dst, \src
+        load_add_store4     ,    ,    ,       ,       ,      ,      , v3.d, \dst, \src
+.endm
+
+.macro idct_dc w, h, shift
+        cbnz            w3,  1f
+        movz            w16, #2896*8, lsl #16
+        ld1r            {v16.4s}, [x2]
+        dup             v0.2s,   w16
+        sqrdmulh        v20.4s,  v16.4s,  v0.s[0]
+        str             wzr, [x2]
+.if (\w == 2*\h) || (2*\w == \h)
+        sqrdmulh        v20.4s,  v20.4s,  v0.s[0]
+.endif
+.if \shift > 0
+        sqrshrn         v16.4h,  v20.4s,  #\shift
+        sqrshrn2        v16.8h,  v20.4s,  #\shift
+.else
+        sqxtn           v16.4h,  v20.4s
+        sqxtn2          v16.8h,  v20.4s
+.endif
+        sqrdmulh        v16.8h,  v16.8h,  v0.h[1]
+        srshr           v16.8h,  v16.8h,  #4
+        mov             w4,  #\h
+        b               idct_dc_w\w\()_neon
+1:
+.endm
+
+function idct_dc_w4_neon
+        mvni            v31.8h,  #0xfc, lsl #8 // 0x3ff
+1:
+        ld1             {v0.d}[0], [x0], x1
+        ld1             {v0.d}[1], [x0], x1
+        ld1             {v1.d}[0], [x0], x1
+        subs            w4,  w4,  #4
+        ld1             {v1.d}[1], [x0], x1
+        usqadd          v0.8h,   v16.8h
+        sub             x0,  x0,  x1, lsl #2
+        usqadd          v1.8h,   v16.8h
+        smin            v0.8h,   v0.8h,   v31.8h
+        st1             {v0.d}[0], [x0], x1
+        smin            v1.8h,   v1.8h,   v31.8h
+        st1             {v0.d}[1], [x0], x1
+        st1             {v1.d}[0], [x0], x1
+        st1             {v1.d}[1], [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+function idct_dc_w8_neon
+        mvni            v31.8h,  #0xfc, lsl #8 // 0x3ff
+1:
+        ld1             {v0.8h}, [x0], x1
+        subs            w4,  w4,  #4
+        ld1             {v1.8h}, [x0], x1
+        usqadd          v0.8h,   v16.8h
+        ld1             {v2.8h}, [x0], x1
+        usqadd          v1.8h,   v16.8h
+        ld1             {v3.8h}, [x0], x1
+        usqadd          v2.8h,   v16.8h
+        usqadd          v3.8h,   v16.8h
+        sub             x0,  x0,  x1, lsl #2
+        smin            v0.8h,   v0.8h,   v31.8h
+        smin            v1.8h,   v1.8h,   v31.8h
+        st1             {v0.8h}, [x0], x1
+        smin            v2.8h,   v2.8h,   v31.8h
+        st1             {v1.8h}, [x0], x1
+        smin            v3.8h,   v3.8h,   v31.8h
+        st1             {v2.8h}, [x0], x1
+        st1             {v3.8h}, [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+function idct_dc_w16_neon
+        mvni            v31.8h,  #0xfc, lsl #8 // 0x3ff
+1:
+        ld1             {v0.8h, v1.8h}, [x0], x1
+        subs            w4,  w4,  #2
+        ld1             {v2.8h, v3.8h}, [x0], x1
+        usqadd          v0.8h,   v16.8h
+        usqadd          v1.8h,   v16.8h
+        sub             x0,  x0,  x1, lsl #1
+        usqadd          v2.8h,   v16.8h
+        usqadd          v3.8h,   v16.8h
+        smin            v0.8h,   v0.8h,   v31.8h
+        smin            v1.8h,   v1.8h,   v31.8h
+        smin            v2.8h,   v2.8h,   v31.8h
+        st1             {v0.8h, v1.8h}, [x0], x1
+        smin            v3.8h,   v3.8h,   v31.8h
+        st1             {v2.8h, v3.8h}, [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+function idct_dc_w32_neon
+        mvni            v31.8h,  #0xfc, lsl #8 // 0x3ff
+1:
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0]
+        subs            w4,  w4,  #1
+        usqadd          v0.8h,   v16.8h
+        usqadd          v1.8h,   v16.8h
+        usqadd          v2.8h,   v16.8h
+        usqadd          v3.8h,   v16.8h
+        smin            v0.8h,   v0.8h,   v31.8h
+        smin            v1.8h,   v1.8h,   v31.8h
+        smin            v2.8h,   v2.8h,   v31.8h
+        smin            v3.8h,   v3.8h,   v31.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+function idct_dc_w64_neon
+        mvni            v31.8h,  #0xfc, lsl #8 // 0x3ff
+        sub             x1,  x1,  #64
+1:
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        subs            w4,  w4,  #1
+        usqadd          v0.8h,   v16.8h
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0]
+        usqadd          v1.8h,   v16.8h
+        sub             x0,  x0,  #64
+        usqadd          v2.8h,   v16.8h
+        usqadd          v3.8h,   v16.8h
+        usqadd          v4.8h,   v16.8h
+        usqadd          v5.8h,   v16.8h
+        usqadd          v6.8h,   v16.8h
+        usqadd          v7.8h,   v16.8h
+        smin            v0.8h,   v0.8h,   v31.8h
+        smin            v1.8h,   v1.8h,   v31.8h
+        smin            v2.8h,   v2.8h,   v31.8h
+        smin            v3.8h,   v3.8h,   v31.8h
+        smin            v4.8h,   v4.8h,   v31.8h
+        smin            v5.8h,   v5.8h,   v31.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        smin            v6.8h,   v6.8h,   v31.8h
+        smin            v7.8h,   v7.8h,   v31.8h
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x0], x1
+        b.gt            1b
+        ret
+endfunc
+
+.macro iwht4
+        add             v16.4s,  v16.4s,  v17.4s
+        sub             v21.4s,  v18.4s,  v19.4s
+        sub             v20.4s,  v16.4s,  v21.4s
+        sshr            v20.4s,  v20.4s,  #1
+        sub             v18.4s,  v20.4s,  v17.4s
+        sub             v17.4s,  v20.4s,  v19.4s
+        add             v19.4s,  v21.4s,  v18.4s
+        sub             v16.4s,  v16.4s,  v17.4s
+.endm
+
+.macro idct_4 r0, r1, r2, r3
+        mul_mla         v6,  \r1, \r3, v0.s[3], v0.s[2]
+        mul_mla         v2,  \r0, \r2, v0.s[0], v0.s[0]
+        mul_mls         v4,  \r1, \r3, v0.s[2], v0.s[3]
+        mul_mls         v3,  \r0, \r2, v0.s[0], v0.s[0]
+        srshr           v6.4s,  v6.4s,  #12
+        srshr           v2.4s,  v2.4s,  #12
+        srshr           v7.4s,  v4.4s,  #12
+        srshr           v3.4s,  v3.4s,  #12
+        sqadd           \r0\().4s,  v2.4s,   v6.4s
+        sqsub           \r3\().4s,  v2.4s,   v6.4s
+        sqadd           \r1\().4s,  v3.4s,   v7.4s
+        sqsub           \r2\().4s,  v3.4s,   v7.4s
+.endm
+
+function inv_dct_4s_x4_neon
+        AARCH64_VALID_CALL_TARGET
+        movrel          x16, idct_coeffs
+        ld1             {v0.4s}, [x16]
+        idct_4          v16, v17, v18, v19
+        ret
+endfunc
+
+.macro iadst_4x4 o0, o1, o2, o3
+        movrel          x16, iadst4_coeffs
+        ld1             {v0.4s}, [x16]
+
+        sub             v3.4s,   v16.4s,  v18.4s
+        mul             v4.4s,   v16.4s,  v0.s[0]
+        mla             v4.4s,   v18.4s,  v0.s[1]
+        mla             v4.4s,   v19.4s,  v0.s[2]
+        mul             v7.4s,   v17.4s,  v0.s[3]
+        add             v3.4s,   v3.4s,   v19.4s
+        mul             v5.4s,   v16.4s,  v0.s[2]
+        mls             v5.4s,   v18.4s,  v0.s[0]
+        mls             v5.4s,   v19.4s,  v0.s[1]
+
+        add             \o3\().4s, v4.4s,     v5.4s
+        mul             \o2\().4s, v3.4s,     v0.s[3]
+        add             \o0\().4s, v4.4s,     v7.4s
+        add             \o1\().4s, v5.4s,     v7.4s
+        sub             \o3\().4s, \o3\().4s, v7.4s
+
+        srshr           \o0\().4s, \o0\().4s, #12
+        srshr           \o2\().4s, \o2\().4s, #12
+        srshr           \o1\().4s, \o1\().4s, #12
+        srshr           \o3\().4s, \o3\().4s, #12
+.endm
+
+function inv_adst_4s_x4_neon
+        AARCH64_VALID_CALL_TARGET
+        iadst_4x4       v16, v17, v18, v19
+        ret
+endfunc
+
+function inv_flipadst_4s_x4_neon
+        AARCH64_VALID_CALL_TARGET
+        iadst_4x4       v19, v18, v17, v16
+        ret
+endfunc
+
+function inv_identity_4s_x4_neon
+        AARCH64_VALID_CALL_TARGET
+        movz            w16, #(5793-4096)*8, lsl #16
+        dup             v0.2s,   w16
+        sqrdmulh        v4.4s,   v16.4s,  v0.s[0]
+        sqrdmulh        v5.4s,   v17.4s,  v0.s[0]
+        sqrdmulh        v6.4s,   v18.4s,  v0.s[0]
+        sqrdmulh        v7.4s,   v19.4s,  v0.s[0]
+        sqadd           v16.4s,  v16.4s,  v4.4s
+        sqadd           v17.4s,  v17.4s,  v5.4s
+        sqadd           v18.4s,  v18.4s,  v6.4s
+        sqadd           v19.4s,  v19.4s,  v7.4s
+        ret
+endfunc
+
+function inv_txfm_add_wht_wht_4x4_16bpc_neon, export=1
+        mov             x15, x30
+        movi            v30.4s,  #0
+        movi            v31.4s,  #0
+        ld1             {v16.4s,v17.4s,v18.4s,v19.4s}, [x2]
+        st1             {v30.4s, v31.4s}, [x2], #32
+
+        sshr            v16.4s,  v16.4s,  #2
+        sshr            v17.4s,  v17.4s,  #2
+        sshr            v18.4s,  v18.4s,  #2
+        sshr            v19.4s,  v19.4s,  #2
+
+        iwht4
+
+        st1             {v30.4s, v31.4s}, [x2], #32
+        transpose_4x4s  v16, v17, v18, v19, v20, v21, v22, v23
+
+        iwht4
+
+        ld1             {v0.d}[0], [x0], x1
+        sqxtn           v16.4h,  v16.4s
+        ld1             {v0.d}[1], [x0], x1
+        sqxtn2          v16.8h,  v17.4s
+        ld1             {v1.d}[0], [x0], x1
+        sqxtn           v18.4h,  v18.4s
+        ld1             {v1.d}[1], [x0], x1
+        sqxtn2          v18.8h,  v19.4s
+
+        b               L(itx_4x4_end)
+endfunc
+
+// HBD inv_txfm_add_4x4_neon deviates from the common pattern with registers
+// x0-x4  external parameters
+// x5     function pointer to first transform
+// x6     function pointer to second transform
+function inv_txfm_add_4x4_neon
+        movi            v30.4s,  #0
+        movi            v31.4s,  #0
+        ld1             {v16.4s,v17.4s,v18.4s,v19.4s}, [x2]
+        st1             {v30.4s, v31.4s}, [x2], #32
+
+        blr             x5
+
+        st1             {v30.4s, v31.4s}, [x2], #32
+        sqxtn           v16.4h,  v16.4s
+        sqxtn           v17.4h,  v17.4s
+        sqxtn           v18.4h,  v18.4s
+        sqxtn           v19.4h,  v19.4s
+        transpose_4x4h  v16, v17, v18, v19, v20, v21, v22, v23
+
+        blr             x6
+
+        ld1             {v0.d}[0], [x0], x1
+        ld1             {v0.d}[1], [x0], x1
+        ins             v16.d[1], v17.d[0]
+        ins             v18.d[1], v19.d[0]
+        ld1             {v1.d}[0], [x0], x1
+        ld1             {v1.d}[1], [x0], x1
+        srshr           v16.8h,  v16.8h,  #4
+        srshr           v18.8h,  v18.8h,  #4
+
+L(itx_4x4_end):
+        dup             v31.8h,  w4
+        sub             x0,  x0,  x1, lsl #2
+        usqadd          v0.8h,   v16.8h
+        usqadd          v1.8h,   v18.8h
+        smin            v0.8h,   v0.8h,   v31.8h
+        st1             {v0.d}[0], [x0], x1
+        smin            v1.8h,   v1.8h,   v31.8h
+        st1             {v0.d}[1], [x0], x1
+        st1             {v1.d}[0], [x0], x1
+        st1             {v1.d}[1], [x0], x1
+
+        ret             x15
+endfunc
+
+.macro def_fn_4x4 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_4x4_16bpc_neon, export=1
+        mov             x15, x30
+
+.ifc \txfm1\()_\txfm2, dct_dct
+        cbnz            w3,  1f
+        movz            w16, #2896*8, lsl #16
+        ld1r            {v16.4s}, [x2]
+        dup             v4.2s,   w16
+        str             wzr, [x2]
+        sqrdmulh        v16.4s,  v16.4s,  v4.s[0]
+        ld1             {v0.d}[0], [x0], x1
+        sqxtn           v20.4h,  v16.4s
+        sqxtn2          v20.8h,  v16.4s
+        ld1             {v0.d}[1], [x0], x1
+        sqrdmulh        v20.8h,  v20.8h,  v4.h[1]
+        ld1             {v1.d}[0], [x0], x1
+        srshr           v16.8h,  v20.8h,  #4
+        ld1             {v1.d}[1], [x0], x1
+        srshr           v18.8h,  v20.8h,  #4
+        movi            v30.8h,  #0
+        b               L(itx_4x4_end)
+1:
+.endif
+        adr             x5,  inv_\txfm1\()_4s_x4_neon
+        movrel          x6,  X(inv_\txfm2\()_4h_x4_neon)
+        b               inv_txfm_add_4x4_neon
+endfunc
+.endm
+
+def_fn_4x4 dct, dct
+def_fn_4x4 identity, identity
+def_fn_4x4 dct, adst
+def_fn_4x4 dct, flipadst
+def_fn_4x4 dct, identity
+def_fn_4x4 adst, dct
+def_fn_4x4 adst, adst
+def_fn_4x4 adst, flipadst
+def_fn_4x4 flipadst, dct
+def_fn_4x4 flipadst, adst
+def_fn_4x4 flipadst, flipadst
+def_fn_4x4 identity, dct
+
+def_fn_4x4 adst, identity
+def_fn_4x4 flipadst, identity
+def_fn_4x4 identity, adst
+def_fn_4x4 identity, flipadst
+
+.macro idct_8 r0, r1, r2, r3, r4, r5, r6, r7
+        idct_4          \r0, \r2, \r4, \r6
+
+        movi            v5.4s,  #1, msl #16 // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        mvni            v4.4s,  #1, msl #16 // row_clip_min = (~bdmax << 7), 0xfffe0000
+.irp r, \r0, \r2, \r4, \r6
+        smin_4s         \r, \r, v5
+.endr
+.irp r, \r0, \r2, \r4, \r6
+        smax_4s         \r, \r, v4
+.endr
+
+        mul_mls         v2,  \r1, \r7, v1.s[0], v1.s[1]  // -> t4a
+        mul_mla         v3,  \r1, \r7, v1.s[1], v1.s[0]  // -> t7a
+        mul_mls         v6,  \r5, \r3, v1.s[2], v1.s[3]  // -> t5a
+        mul_mla         v7,  \r5, \r3, v1.s[3], v1.s[2]  // -> t6a
+        srshr           \r1\().4s, v2.4s,  #12           // t4a
+        srshr           \r7\().4s, v3.4s,  #12           // t7a
+        srshr           \r3\().4s, v6.4s,  #12           // t5a
+        srshr           \r5\().4s, v7.4s,  #12           // t6a
+
+        sqadd           v2.4s,     \r1\().4s,  \r3\().4s // t4
+        sqsub           \r1\().4s, \r1\().4s,  \r3\().4s // t5a
+        sqadd           v3.4s,     \r7\().4s,  \r5\().4s // t7
+        sqsub           \r3\().4s, \r7\().4s,  \r5\().4s // t6a
+
+.irp r, v2, \r1, v3, \r3
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v2, \r1, v3, \r3
+        smax_4s         \r, \r, v4
+.endr
+
+        mul_mls         v7,  \r3, \r1, v0.s[0], v0.s[0]  // -> t5
+        mul_mla         v6,  \r3, \r1, v0.s[0], v0.s[0]  // -> t6
+        srshr           v7.4s,  v7.4s,  #12              // t5
+        srshr           v6.4s,  v6.4s,  #12              // t6
+
+        sqsub           \r7\().4s,  \r0\().4s,  v3.4s    // out7
+        sqadd           \r0\().4s,  \r0\().4s,  v3.4s    // out0
+        sqadd           \r1\().4s,  \r2\().4s,  v6.4s    // out1
+        sqsub           v6.4s,      \r2\().4s,  v6.4s    // out6
+        sqadd           \r2\().4s,  \r4\().4s,  v7.4s    // out2
+        sqsub           \r5\().4s,  \r4\().4s,  v7.4s    // out5
+        sqadd           \r3\().4s,  \r6\().4s,  v2.4s    // out3
+        sqsub           \r4\().4s,  \r6\().4s,  v2.4s    // out4
+        mov             \r6\().16b, v6.16b               // out6
+.endm
+
+function inv_dct_4s_x8_neon
+        AARCH64_VALID_CALL_TARGET
+        movrel          x16, idct_coeffs
+        ld1             {v0.4s, v1.4s}, [x16]
+        idct_8          v16, v17, v18, v19, v20, v21, v22, v23
+        ret
+endfunc
+
+.macro iadst_8 o0, o1, o2, o3, o4, o5, o6, o7
+        movrel          x16, iadst8_coeffs
+        ld1             {v0.4s, v1.4s}, [x16], #32
+
+        mul_mla         v2,  v23, v16, v0.s[0], v0.s[1]
+        mul_mls         v4,  v23, v16, v0.s[1], v0.s[0]
+        mul_mla         v6,  v21, v18, v0.s[2], v0.s[3]
+        srshr           v16.4s, v2.4s,  #12  // t0a
+        srshr           v23.4s, v4.4s,  #12  // t1a
+        mul_mls         v2,  v21, v18, v0.s[3], v0.s[2]
+        mul_mla         v4,  v19, v20, v1.s[0], v1.s[1]
+        srshr           v18.4s, v6.4s,  #12  // t2a
+        srshr           v21.4s, v2.4s,  #12  // t3a
+        mul_mls         v6,  v19, v20, v1.s[1], v1.s[0]
+        mul_mla         v2,  v17, v22, v1.s[2], v1.s[3]
+        srshr           v20.4s, v4.4s,  #12  // t4a
+        srshr           v19.4s, v6.4s,  #12  // t5a
+        mul_mls         v4,  v17, v22, v1.s[3], v1.s[2]
+        srshr           v22.4s, v2.4s,  #12  // t6a
+        srshr           v17.4s, v4.4s,  #12  // t7a
+
+        ld1             {v0.4s}, [x16]
+
+        movi            v1.4s,   #1, msl #16     // row_clip_max = ~(~bdmax << 7), 0x1ffff
+
+        sqadd           v2.4s,   v16.4s,  v20.4s // t0
+        sqsub           v3.4s,   v16.4s,  v20.4s // t4
+        mvni            v20.4s,  #1, msl #16     // row_clip_min = (~bdmax << 7), 0xfffe0000
+        sqadd           v4.4s,   v23.4s,  v19.4s // t1
+        sqsub           v5.4s,   v23.4s,  v19.4s // t5
+        sqadd           v6.4s,   v18.4s,  v22.4s // t2
+        sqsub           v7.4s,   v18.4s,  v22.4s // t6
+        sqadd           v18.4s,  v21.4s,  v17.4s // t3
+        sqsub           v19.4s,  v21.4s,  v17.4s // t7
+
+.irp r, v2, v3, v4, v5, v6, v7, v18, v19
+        smin_4s         \r, \r, v1
+.endr
+.irp r, v2, v3, v4, v5, v6, v7, v18, v19
+        smax_4s         \r, \r, v20
+.endr
+
+        mul_mla         v16, v3,  v5,  v0.s[3], v0.s[2]
+        mul_mls         v20, v3,  v5,  v0.s[2], v0.s[3]
+        mul_mls         v22, v19, v7,  v0.s[3], v0.s[2]
+
+        srshr           v3.4s,  v16.4s, #12  // t4a
+        srshr           v5.4s,  v20.4s, #12  // t5a
+
+        mul_mla         v16, v19, v7,  v0.s[2], v0.s[3]
+
+        srshr           v7.4s,  v22.4s, #12  // t6a
+        srshr           v19.4s, v16.4s, #12  // t7a
+
+        sqadd           \o0\().4s, v2.4s, v6.4s  // out0
+        sqsub           v2.4s,     v2.4s, v6.4s  // t2
+        sqadd           \o7\().4s, v4.4s, v18.4s // out7
+        sqsub           v4.4s,     v4.4s, v18.4s // t3
+
+        mvni            v18.4s,  #1, msl #16     // row_clip_min = (~bdmax << 7), 0xfffe0000
+
+        sqadd           \o1\().4s, v3.4s, v7.4s  // out1
+        sqsub           v3.4s,     v3.4s, v7.4s  // t6
+        sqadd           \o6\().4s, v5.4s, v19.4s // out6
+        sqsub           v5.4s,     v5.4s, v19.4s // t7
+
+        // Not clipping the output registers, as they will be downshifted and
+        // narrowed afterwards anyway.
+.irp r, v2, v4, v3, v5
+        smin_4s         \r, \r, v1
+.endr
+.irp r, v2, v4, v3, v5
+        smax_4s         \r, \r, v18
+.endr
+
+        sqneg           \o7\().4s, \o7\().4s     // out7
+        sqneg           \o1\().4s, \o1\().4s     // out1
+
+        mul_mla         v18, v2,  v4,  v0.s[0], v0.s[0] // -> out3 (v19 or v20)
+        mul_mls         v6,  v2,  v4,  v0.s[0], v0.s[0] // -> out4 (v20 or v19)
+        mul_mls         v20, v3,  v5,  v0.s[0], v0.s[0] // -> out5 (v21 or v18)
+        srshr           v2.4s,  v18.4s, #12 // out3
+        mul_mla         v18, v3,  v5,  v0.s[0], v0.s[0] // -> out2 (v18 or v21)
+        srshr           v3.4s,  v20.4s, #12 // out5
+        srshr           \o2\().4s, v18.4s, #12 // out2 (v18 or v21)
+        srshr           \o4\().4s, v6.4s,  #12 // out4 (v20 or v19)
+
+        sqneg           \o3\().4s, v2.4s     // out3
+        sqneg           \o5\().4s, v3.4s     // out5
+.endm
+
+function inv_adst_4s_x8_neon
+        AARCH64_VALID_CALL_TARGET
+        iadst_8         v16, v17, v18, v19, v20, v21, v22, v23
+        ret
+endfunc
+
+function inv_flipadst_4s_x8_neon
+        AARCH64_VALID_CALL_TARGET
+        iadst_8         v23, v22, v21, v20, v19, v18, v17, v16
+        ret
+endfunc
+
+function inv_identity_4s_x8_neon
+        AARCH64_VALID_CALL_TARGET
+        sqshl           v16.4s,  v16.4s,  #1
+        sqshl           v17.4s,  v17.4s,  #1
+        sqshl           v18.4s,  v18.4s,  #1
+        sqshl           v19.4s,  v19.4s,  #1
+        sqshl           v20.4s,  v20.4s,  #1
+        sqshl           v21.4s,  v21.4s,  #1
+        sqshl           v22.4s,  v22.4s,  #1
+        sqshl           v23.4s,  v23.4s,  #1
+        ret
+endfunc
+
+function inv_txfm_add_8x8_neon
+        movi            v31.4s,  #0
+
+        cmp             w3,  w13
+        mov             x11, #32
+        b.lt            1f
+
+        add             x6,  x2,  #16
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s
+        ld1             {\i},     [x6]
+        st1             {v31.4s}, [x6], x11
+.endr
+
+        blr             x4
+
+        sqrshrn         v24.4h,  v16.4s,  #1
+        sqrshrn         v25.4h,  v17.4s,  #1
+        sqrshrn         v26.4h,  v18.4s,  #1
+        sqrshrn         v27.4h,  v19.4s,  #1
+        sqrshrn2        v24.8h,  v20.4s,  #1
+        sqrshrn2        v25.8h,  v21.4s,  #1
+        sqrshrn2        v26.8h,  v22.4s,  #1
+        sqrshrn2        v27.8h,  v23.4s,  #1
+
+        transpose_4x8h  v24, v25, v26, v27, v2, v3, v4, v5
+
+        b               2f
+
+1:
+.irp i, v24.8h, v25.8h, v26.8h, v27.8h
+        movi            \i,  #0
+.endr
+
+2:
+
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s
+        ld1             {\i},     [x2]
+        st1             {v31.4s}, [x2], x11
+.endr
+
+        blr             x4
+
+        sqrshrn         v16.4h,  v16.4s,  #1
+        sqrshrn         v17.4h,  v17.4s,  #1
+        sqrshrn         v18.4h,  v18.4s,  #1
+        sqrshrn         v19.4h,  v19.4s,  #1
+        sqrshrn2        v16.8h,  v20.4s,  #1
+        sqrshrn2        v17.8h,  v21.4s,  #1
+        sqrshrn2        v18.8h,  v22.4s,  #1
+        sqrshrn2        v19.8h,  v23.4s,  #1
+
+        transpose_4x8h  v16, v17, v18, v19, v20, v21, v22, v23
+
+        mov             v20.16b, v24.16b
+        mov             v21.16b, v25.16b
+        mov             v22.16b, v26.16b
+        mov             v23.16b, v27.16b
+
+        blr             x5
+
+        load_add_store_8x8 x0, x7
+        ret             x15
+endfunc
+
+.macro def_fn_8x8 txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_8x8_16bpc_neon, export=1
+        mov             x15, x30
+
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         8,   8,   1
+.endif
+        movrel          x5,  X(inv_\txfm2\()_8h_x8_neon)
+        mov             w13, #\eob_half
+        adr             x4,  inv_\txfm1\()_4s_x8_neon
+        b               inv_txfm_add_8x8_neon
+endfunc
+.endm
+
+def_fn_8x8 dct, dct, 10
+def_fn_8x8 identity, identity, 10
+def_fn_8x8 dct, adst, 10
+def_fn_8x8 dct, flipadst, 10
+def_fn_8x8 dct, identity, 4
+def_fn_8x8 adst, dct, 10
+def_fn_8x8 adst, adst, 10
+def_fn_8x8 adst, flipadst, 10
+def_fn_8x8 flipadst, dct, 10
+def_fn_8x8 flipadst, adst, 10
+def_fn_8x8 flipadst, flipadst, 10
+def_fn_8x8 identity, dct, 4
+def_fn_8x8 adst, identity, 4
+def_fn_8x8 flipadst, identity, 4
+def_fn_8x8 identity, adst, 4
+def_fn_8x8 identity, flipadst, 4
+
+function inv_txfm_add_8x4_neon
+        movi            v28.4s,  #0
+        movi            v29.4s,  #0
+        movi            v30.4s,  #0
+        movi            v31.4s,  #0
+        ld1             {v16.4s,v17.4s,v18.4s,v19.4s}, [x2]
+        st1             {v28.4s,v29.4s,v30.4s,v31.4s}, [x2], #64
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+        ld1             {v20.4s,v21.4s,v22.4s,v23.4s}, [x2]
+        st1             {v28.4s,v29.4s,v30.4s,v31.4s}, [x2]
+
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+
+        blr             x4
+
+        sqxtn           v16.4h,  v16.4s
+        sqxtn           v17.4h,  v17.4s
+        sqxtn           v18.4h,  v18.4s
+        sqxtn           v19.4h,  v19.4s
+        sqxtn           v20.4h,  v20.4s
+        sqxtn           v21.4h,  v21.4s
+        sqxtn           v22.4h,  v22.4s
+        sqxtn           v23.4h,  v23.4s
+
+        transpose_4x4h  v16, v17, v18, v19, v4,  v5,  v6,  v7
+        transpose_4x4h  v20, v21, v22, v23, v4,  v5,  v6,  v7
+        ins             v16.d[1], v20.d[0]
+        ins             v17.d[1], v21.d[0]
+        ins             v18.d[1], v22.d[0]
+        ins             v19.d[1], v23.d[0]
+
+        blr             x5
+
+        load_add_store_8x4 x0, x7
+        ret             x15
+endfunc
+
+function inv_txfm_add_4x8_neon
+        movz            w16, #2896*8, lsl #16
+        movi            v31.4s,  #0
+        dup             v30.2s,  w16
+
+        cmp             w3,  w13
+        mov             x11, #32
+        b.lt            1f
+
+        add             x6,  x2,  #16
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s
+        ld1             {\i},     [x6]
+        st1             {v31.4s}, [x6], x11
+.endr
+        scale_input     .4s, v30.s[0], v16, v17, v18, v19
+        blr             x4
+        sqxtn           v20.4h,  v16.4s
+        sqxtn           v21.4h,  v17.4s
+        sqxtn           v22.4h,  v18.4s
+        sqxtn           v23.4h,  v19.4s
+        transpose_4x4h  v20, v21, v22, v23, v4,  v5,  v6,  v7
+
+        b               2f
+
+1:
+.irp i, v20, v21, v22, v23
+        movi            \i\().4h, #0
+.endr
+
+2:
+
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s
+        ld1             {\i},     [x2]
+        st1             {v31.4s}, [x2], x11
+.endr
+        scale_input     .4s, v30.s[0], v16, v17, v18, v19
+        blr             x4
+        sqxtn           v16.4h,  v16.4s
+        sqxtn           v17.4h,  v17.4s
+        sqxtn           v18.4h,  v18.4s
+        sqxtn           v19.4h,  v19.4s
+        transpose_4x4h  v16, v17, v18, v19, v4,  v5,  v6,  v7
+
+        blr             x5
+
+        load_add_store_4x8 x0, x7
+        ret             x15
+endfunc
+
+.macro def_fn_48 w, h, txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_16bpc_neon, export=1
+        mov             x15, x30
+
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  0
+.endif
+        adr             x4,  inv_\txfm1\()_4s_x\w\()_neon
+.if \w == 4
+        mov             w13, #\eob_half
+.endif
+        movrel          x5,  X(inv_\txfm2\()_\w\()h_x\h\()_neon)
+        b               inv_txfm_add_\w\()x\h\()_neon
+endfunc
+.endm
+
+.macro def_fns_48 w, h
+def_fn_48 \w, \h, dct, dct, 13
+def_fn_48 \w, \h, identity, identity, 13
+def_fn_48 \w, \h, dct, adst, 13
+def_fn_48 \w, \h, dct, flipadst, 13
+def_fn_48 \w, \h, dct, identity, 4
+def_fn_48 \w, \h, adst, dct, 13
+def_fn_48 \w, \h, adst, adst, 13
+def_fn_48 \w, \h, adst, flipadst, 13
+def_fn_48 \w, \h, flipadst, dct, 13
+def_fn_48 \w, \h, flipadst, adst, 13
+def_fn_48 \w, \h, flipadst, flipadst, 13
+def_fn_48 \w, \h, identity, dct, 16
+def_fn_48 \w, \h, adst, identity, 4
+def_fn_48 \w, \h, flipadst, identity, 4
+def_fn_48 \w, \h, identity, adst, 16
+def_fn_48 \w, \h, identity, flipadst, 16
+.endm
+
+def_fns_48 4, 8
+def_fns_48 8, 4
+
+
+function inv_dct_4s_x16_neon
+        AARCH64_VALID_CALL_TARGET
+        movrel          x16, idct_coeffs
+        ld1             {v0.4s, v1.4s}, [x16], #32
+
+        idct_8          v16, v18, v20, v22, v24, v26, v28, v30
+
+        // idct_8 leaves the row_clip_max/min constants in v5 and v4
+.irp r, v16, v18, v20, v22, v24, v26, v28, v30
+        smin            \r\().4s,  \r\().4s,  v5.4s
+.endr
+.irp r, v16, v18, v20, v22, v24, v26, v28, v30
+        smax            \r\().4s,  \r\().4s,  v4.4s
+.endr
+
+        ld1             {v0.4s, v1.4s}, [x16]
+        sub             x16, x16, #32
+
+        mul_mls         v2,  v17, v31, v0.s[0], v0.s[1] // -> t8a
+        mul_mla         v3,  v17, v31, v0.s[1], v0.s[0] // -> t15a
+        mul_mls         v6,  v25, v23, v0.s[2], v0.s[3] // -> t9a
+        srshr           v17.4s, v2.4s,  #12             // t8a
+        srshr           v31.4s, v3.4s,  #12             // t15a
+        mul_mla         v2,  v25, v23, v0.s[3], v0.s[2] // -> t14a
+        mul_mls         v3,  v21, v27, v1.s[0], v1.s[1] // -> t10a
+        srshr           v23.4s, v6.4s,  #12             // t9a
+        srshr           v25.4s, v2.4s,  #12             // t14a
+        mul_mla         v6,  v21, v27, v1.s[1], v1.s[0] // -> t13a
+        mul_mls         v2,  v29, v19, v1.s[2], v1.s[3] // -> t11a
+        srshr           v21.4s, v3.4s,  #12             // t10a
+        srshr           v27.4s, v6.4s,  #12             // t13a
+        mul_mla         v3,  v29, v19, v1.s[3], v1.s[2] // -> t12a
+        srshr           v19.4s, v2.4s,  #12             // t11a
+        srshr           v29.4s, v3.4s,  #12             // t12a
+
+        ld1             {v0.4s}, [x16]
+
+        sqsub           v2.4s,   v17.4s,  v23.4s  // t9
+        sqadd           v17.4s,  v17.4s,  v23.4s  // t8
+        sqsub           v3.4s,   v31.4s,  v25.4s  // t14
+        sqadd           v31.4s,  v31.4s,  v25.4s  // t15
+        sqsub           v23.4s,  v19.4s,  v21.4s  // t10
+        sqadd           v19.4s,  v19.4s,  v21.4s  // t11
+        sqadd           v25.4s,  v29.4s,  v27.4s  // t12
+        sqsub           v29.4s,  v29.4s,  v27.4s  // t13
+
+.irp r, v2, v17, v3, v31, v23, v19, v25, v29
+        smin            \r\().4s,  \r\().4s,  v5.4s
+.endr
+.irp r, v2, v17, v3, v31, v23, v19, v25, v29
+        smax            \r\().4s,  \r\().4s,  v4.4s
+.endr
+
+        mul_mls         v7,  v3,  v2,  v0.s[2], v0.s[3] // -> t9a
+        mul_mla         v6,  v3,  v2,  v0.s[3], v0.s[2] // -> t14a
+        srshr           v21.4s, v7.4s,  #12             // t9a
+        srshr           v27.4s, v6.4s,  #12             // t14a
+
+        mul_mls         v7,  v29, v23, v0.s[2], v0.s[3] // -> t13a
+        mul_mla         v6,  v29, v23, v0.s[3], v0.s[2] // -> t10a
+        srshr           v29.4s, v7.4s,  #12             // t13a
+        neg             v6.4s,   v6.4s
+        srshr           v23.4s, v6.4s,  #12             // t10a
+
+        sqsub           v2.4s,   v17.4s,  v19.4s  // t11a
+        sqadd           v17.4s,  v17.4s,  v19.4s  // t8a
+        sqsub           v3.4s,   v31.4s,  v25.4s  // t12a
+        sqadd           v31.4s,  v31.4s,  v25.4s  // t15a
+        sqadd           v19.4s,  v21.4s,  v23.4s  // t9
+        sqsub           v21.4s,  v21.4s,  v23.4s  // t10
+        sqsub           v25.4s,  v27.4s,  v29.4s  // t13
+        sqadd           v27.4s,  v27.4s,  v29.4s  // t14
+
+.irp r, v2, v17, v3, v31, v19, v21, v25, v27
+        smin            \r\().4s,  \r\().4s,  v5.4s
+.endr
+.irp r, v2, v17, v3, v31, v19, v21, v25, v27
+        smax            \r\().4s,  \r\().4s,  v4.4s
+.endr
+
+        mul_mls         v7,  v3,  v2,  v0.s[0], v0.s[0] // -> t11
+        mul_mla         v6,  v3,  v2,  v0.s[0], v0.s[0] // -> t12
+        mul_mls         v2,  v25, v21, v0.s[0], v0.s[0] // -> t10a
+
+        srshr           v7.4s,  v7.4s,  #12   // t11
+        srshr           v6.4s,  v6.4s,  #12   // t12
+        mul_mla         v3,  v25, v21, v0.s[0], v0.s[0] // -> t13a
+        srshr           v2.4s,  v2.4s,  #12   // t10a
+        srshr           v3.4s,  v3.4s,  #12   // t13a
+
+        sqadd           v1.4s,   v16.4s,  v31.4s  // out0
+        sqsub           v31.4s,  v16.4s,  v31.4s  // out15
+        mov             v16.16b, v1.16b
+        sqadd           v23.4s,  v30.4s,  v17.4s  // out7
+        sqsub           v1.4s,   v30.4s,  v17.4s  // out8
+        sqadd           v17.4s,  v18.4s,  v27.4s  // out1
+        sqsub           v30.4s,  v18.4s,  v27.4s  // out14
+        sqadd           v18.4s,  v20.4s,  v3.4s   // out2
+        sqsub           v29.4s,  v20.4s,  v3.4s   // out13
+        sqadd           v3.4s,   v28.4s,  v19.4s  // out6
+        sqsub           v25.4s,  v28.4s,  v19.4s  // out9
+        sqadd           v19.4s,  v22.4s,  v6.4s   // out3
+        sqsub           v28.4s,  v22.4s,  v6.4s   // out12
+        sqadd           v20.4s,  v24.4s,  v7.4s   // out4
+        sqsub           v27.4s,  v24.4s,  v7.4s   // out11
+        sqadd           v21.4s,  v26.4s,  v2.4s   // out5
+        sqsub           v26.4s,  v26.4s,  v2.4s   // out10
+        mov             v24.16b, v1.16b
+        mov             v22.16b, v3.16b
+
+        ret
+endfunc
+
+.macro iadst_16 o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15
+        movrel          x16, iadst16_coeffs
+        ld1             {v0.4s, v1.4s}, [x16], #32
+
+        mul_mla         v2,  v31, v16, v0.s[0], v0.s[1] // -> t0
+        mul_mls         v4,  v31, v16, v0.s[1], v0.s[0] // -> t1
+        mul_mla         v6,  v29, v18, v0.s[2], v0.s[3] // -> t2
+        srshr           v16.4s, v2.4s,  #12             // t0
+        srshr           v31.4s, v4.4s,  #12             // t1
+        mul_mls         v2,  v29, v18, v0.s[3], v0.s[2] // -> t3
+        mul_mla         v4,  v27, v20, v1.s[0], v1.s[1] // -> t4
+        srshr           v18.4s, v6.4s,  #12             // t2
+        srshr           v29.4s, v2.4s,  #12             // t3
+        mul_mls         v6,  v27, v20, v1.s[1], v1.s[0] // -> t5
+        mul_mla         v2,  v25, v22, v1.s[2], v1.s[3] // -> t6
+        srshr           v20.4s, v4.4s,  #12             // t4
+        srshr           v27.4s, v6.4s,  #12             // t5
+        mul_mls         v4,  v25, v22, v1.s[3], v1.s[2] // -> t7
+        ld1             {v0.4s, v1.4s}, [x16]
+        movrel          x16, idct_coeffs
+        mul_mla         v6,  v23, v24, v0.s[0], v0.s[1] // -> t8
+        srshr           v22.4s, v2.4s,  #12             // t6
+        srshr           v25.4s, v4.4s,  #12             // t7
+        mul_mls         v2,  v23, v24, v0.s[1], v0.s[0] // -> t9
+        mul_mla         v4,  v21, v26, v0.s[2], v0.s[3] // -> t10
+        srshr           v23.4s, v6.4s,  #12             // t8
+        srshr           v24.4s, v2.4s,  #12             // t9
+        mul_mls         v6,  v21, v26, v0.s[3], v0.s[2] // -> t11
+        mul_mla         v2,  v19, v28, v1.s[0], v1.s[1] // -> t12
+        srshr           v21.4s, v4.4s,  #12             // t10
+        srshr           v26.4s, v6.4s,  #12             // t11
+        mul_mls         v4,  v19, v28, v1.s[1], v1.s[0] // -> t13
+        mul_mla         v6,  v17, v30, v1.s[2], v1.s[3] // -> t14
+        srshr           v19.4s, v2.4s,  #12             // t12
+        srshr           v28.4s, v4.4s,  #12             // t13
+        mul_mls         v2,  v17, v30, v1.s[3], v1.s[2] // -> t15
+        srshr           v17.4s, v6.4s,  #12             // t14
+        srshr           v30.4s, v2.4s,  #12             // t15
+
+        ld1             {v0.4s, v1.4s}, [x16]
+
+        movi            v5.4s,   #1, msl #16     // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        mvni            v7.4s,   #1, msl #16     // row_clip_min = (~bdmax << 7), 0xfffe0000
+
+        sqsub           v2.4s,   v16.4s,  v23.4s // t8a
+        sqadd           v16.4s,  v16.4s,  v23.4s // t0a
+        sqsub           v3.4s,   v31.4s,  v24.4s // t9a
+        sqadd           v31.4s,  v31.4s,  v24.4s // t1a
+        sqadd           v23.4s,  v18.4s,  v21.4s // t2a
+        sqsub           v18.4s,  v18.4s,  v21.4s // t10a
+        sqadd           v24.4s,  v29.4s,  v26.4s // t3a
+        sqsub           v29.4s,  v29.4s,  v26.4s // t11a
+        sqadd           v21.4s,  v20.4s,  v19.4s // t4a
+        sqsub           v20.4s,  v20.4s,  v19.4s // t12a
+        sqadd           v26.4s,  v27.4s,  v28.4s // t5a
+        sqsub           v27.4s,  v27.4s,  v28.4s // t13a
+        sqadd           v19.4s,  v22.4s,  v17.4s // t6a
+        sqsub           v22.4s,  v22.4s,  v17.4s // t14a
+        sqadd           v28.4s,  v25.4s,  v30.4s // t7a
+        sqsub           v25.4s,  v25.4s,  v30.4s // t15a
+
+.irp r, v2, v16, v3, v31, v23, v18, v24, v29, v21, v20, v26, v27, v19, v22, v28, v25
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v2, v16, v3, v31, v23, v18, v24, v29, v21, v20, v26, v27, v19, v22, v28, v25
+        smax_4s         \r, \r, v7
+.endr
+
+        mul_mla         v4,  v2,  v3,  v1.s[1], v1.s[0] // -> t8
+        mul_mls         v6,  v2,  v3,  v1.s[0], v1.s[1] // -> t9
+        mul_mla         v2,  v18, v29, v1.s[3], v1.s[2] // -> t10
+        srshr           v17.4s, v4.4s,  #12             // t8
+        srshr           v30.4s, v6.4s,  #12             // t9
+        mul_mls         v4,  v18, v29, v1.s[2], v1.s[3] // -> t11
+        mul_mls         v6,  v27, v20, v1.s[1], v1.s[0] // -> t12
+        srshr           v18.4s, v2.4s,  #12             // t10
+        srshr           v29.4s, v4.4s,  #12             // t11
+        mul_mla         v2,  v27, v20, v1.s[0], v1.s[1] // -> t13
+        mul_mls         v4,  v25, v22, v1.s[3], v1.s[2] // -> t14
+        srshr           v27.4s, v6.4s,  #12             // t12
+        srshr           v20.4s, v2.4s,  #12             // t13
+        mul_mla         v6,  v25, v22, v1.s[2], v1.s[3] // -> t15
+        srshr           v25.4s, v4.4s,  #12             // t14
+        srshr           v22.4s, v6.4s,  #12             // t15
+
+        sqsub           v2.4s,   v16.4s,  v21.4s // t4
+        sqadd           v16.4s,  v16.4s,  v21.4s // t0
+        sqsub           v3.4s,   v31.4s,  v26.4s // t5
+        sqadd           v31.4s,  v31.4s,  v26.4s // t1
+        sqadd           v21.4s,  v23.4s,  v19.4s // t2
+        sqsub           v23.4s,  v23.4s,  v19.4s // t6
+        sqadd           v26.4s,  v24.4s,  v28.4s // t3
+        sqsub           v24.4s,  v24.4s,  v28.4s // t7
+        sqadd           v19.4s,  v17.4s,  v27.4s // t8a
+        sqsub           v17.4s,  v17.4s,  v27.4s // t12a
+        sqadd           v28.4s,  v30.4s,  v20.4s // t9a
+        sqsub           v30.4s,  v30.4s,  v20.4s // t13a
+        sqadd           v27.4s,  v18.4s,  v25.4s // t10a
+        sqsub           v18.4s,  v18.4s,  v25.4s // t14a
+        sqadd           v20.4s,  v29.4s,  v22.4s // t11a
+        sqsub           v29.4s,  v29.4s,  v22.4s // t15a
+
+.irp r, v2, v16, v3, v31, v21, v23, v26, v24, v19, v17, v28, v30, v27, v18, v20, v29
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v2, v16, v3, v31, v21, v23, v26, v24, v19, v17, v28, v30, v27, v18, v20, v29
+        smax_4s         \r, \r, v7
+.endr
+
+        mul_mla         v4,  v2,  v3,  v0.s[3], v0.s[2] // -> t4a
+        mul_mls         v6,  v2,  v3,  v0.s[2], v0.s[3] // -> t5a
+        mul_mls         v2,  v24, v23, v0.s[3], v0.s[2] // -> t6a
+        srshr           v22.4s, v4.4s,  #12             // t4a
+        srshr           v25.4s, v6.4s,  #12             // t5a
+        mul_mla         v4,  v24, v23, v0.s[2], v0.s[3] // -> t7a
+        mul_mla         v6,  v17, v30, v0.s[3], v0.s[2] // -> t12
+        srshr           v24.4s, v2.4s,  #12             // t6a
+        srshr           v23.4s, v4.4s,  #12             // t7a
+        mul_mls         v2,  v17, v30, v0.s[2], v0.s[3] // -> t13
+        mul_mls         v4,  v29, v18, v0.s[3], v0.s[2] // -> t14
+        srshr           v17.4s, v6.4s,  #12             // t12
+        mul_mla         v6,  v29, v18, v0.s[2], v0.s[3] // -> t15
+        srshr           v29.4s, v2.4s,  #12             // t13
+        srshr           v30.4s, v4.4s,  #12             // t14
+        srshr           v18.4s, v6.4s,  #12             // t15
+
+        sqsub           v2.4s,   v16.4s,  v21.4s // t2a
+.ifc \o0, v16
+        sqadd           \o0\().4s,  v16.4s,  v21.4s // out0
+        sqsub           v21.4s,     v31.4s,  v26.4s // t3a
+        sqadd           \o15\().4s, v31.4s,  v26.4s // out15
+.else
+        sqadd           v4.4s,      v16.4s,  v21.4s // out0
+        sqsub           v21.4s,     v31.4s,  v26.4s // t3a
+        sqadd           \o15\().4s, v31.4s,  v26.4s // out15
+        mov             \o0\().16b, v4.16b
+.endif
+
+        sqsub           v3.4s,      v29.4s,  v18.4s // t15a
+        sqadd           \o13\().4s, v29.4s,  v18.4s // out13
+        sqadd           \o2\().4s,  v17.4s,  v30.4s // out2
+        sqsub           v26.4s,     v17.4s,  v30.4s // t14a
+
+        sqadd           \o1\().4s,  v19.4s,  v27.4s // out1
+        sqsub           v27.4s,     v19.4s,  v27.4s // t10
+        sqadd           \o14\().4s, v28.4s,  v20.4s // out14
+        sqsub           v20.4s,     v28.4s,  v20.4s // t11
+
+        sqadd           \o3\().4s,  v22.4s,  v24.4s // out3
+        sqsub           v22.4s,     v22.4s,  v24.4s // t6
+        sqadd           \o12\().4s, v25.4s,  v23.4s // out12
+        sqsub           v23.4s,     v25.4s,  v23.4s // t7
+
+        // Not clipping the output registers, as they will be downshifted and
+        // narrowed afterwards anyway.
+.irp r, v2, v21, v3, v26, v27, v20, v22, v23
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v2, v21, v3, v26, v27, v20, v22, v23
+        smax_4s         \r, \r, v7
+.endr
+
+        sqneg           \o15\().4s, \o15\().4s      // out15
+        sqneg           \o13\().4s, \o13\().4s      // out13
+        sqneg           \o1\().4s,  \o1\().4s       // out1
+        sqneg           \o3\().4s,  \o3\().4s       // out3
+
+        mul_mls         v24, v2,  v21, v0.s[0], v0.s[0] // -> out8 (v24 or v23)
+        mul_mla         v4,  v2,  v21, v0.s[0], v0.s[0] // -> out7 (v23 or v24)
+        mul_mla         v6,  v26, v3,  v0.s[0], v0.s[0] // -> out5 (v21 or v26)
+
+        srshr           v24.4s, v24.4s, #12             // out8
+        srshr           v4.4s,  v4.4s,  #12             // out7
+        srshr           v5.4s,  v6.4s,  #12             // out5
+        mul_mls         v6,  v26, v3,  v0.s[0], v0.s[0] // -> out10 (v26 or v21)
+        mul_mla         v2,  v22, v23, v0.s[0], v0.s[0] // -> out4 (v20 or v27)
+        srshr           v26.4s, v6.4s,  #12             // out10
+
+        mul_mls         v6,  v22, v23, v0.s[0], v0.s[0] // -> out11 (v27 or v20)
+        mul_mla         v22, v27, v20, v0.s[0], v0.s[0] // -> out6 (v22 or v25)
+        mul_mls         v21, v27, v20, v0.s[0], v0.s[0] // -> out9 (v25 or v22)
+
+        srshr           \o4\().4s,   v2.4s,  #12        // out4
+        srshr           v6.4s,       v6.4s,  #12        // out11
+        srshr           v7.4s,       v21.4s, #12        // out9
+        srshr           \o6\().4s,   v22.4s, #12        // out6
+
+.ifc \o8, v23
+        mov             \o8\().16b,  v24.16b
+        mov             \o10\().16b, v26.16b
+.endif
+
+        sqneg           \o7\().4s,   v4.4s // out7
+        sqneg           \o5\().4s,   v5.4s // out5
+        sqneg           \o11\().4s,  v6.4s // out11
+        sqneg           \o9\().4s,   v7.4s // out9
+.endm
+
+function inv_adst_4s_x16_neon
+        AARCH64_VALID_CALL_TARGET
+        iadst_16        v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31
+        ret
+endfunc
+
+function inv_flipadst_4s_x16_neon
+        AARCH64_VALID_CALL_TARGET
+        iadst_16        v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16
+        ret
+endfunc
+
+function inv_identity_4s_x16_neon
+        AARCH64_VALID_CALL_TARGET
+        movz            w16, #2*(5793-4096)*8, lsl #16
+        dup             v0.2s,   w16
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        sqrdmulh        v2.4s,      v\i\().4s,  v0.s[0]
+        sqadd           v\i\().4s,  v\i\().4s,  v\i\().4s
+        sqadd           v\i\().4s,  v\i\().4s,  v2.4s
+.endr
+        ret
+endfunc
+
+.macro identity_4x16_shift1 c
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        sqrdmulh        v3.4s,   \i,      \c
+        srshr           v3.4s,   v3.4s,   #1
+        sqadd           \i,      \i,      v3.4s
+.endr
+.endm
+
+.macro identity_4x16 c
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        sqrdmulh        v3.4s,   \i,      \c
+        sqadd           \i,      \i,      \i
+        sqadd           \i,      \i,      v3.4s
+.endr
+.endm
+
+.macro def_horz_16 scale=0, shift=2, suffix
+function inv_txfm_horz\suffix\()_16x4_neon
+        mov             x14, x30
+        movi            v7.4s,  #0
+.if \scale
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+.endif
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        ld1             {\i}, [x7]
+        st1             {v7.4s}, [x7], x8
+.endr
+.if \scale
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .4s, v0.s[0], v24, v25, v26, v27, v28, v29, v30, v31
+.endif
+        blr             x4
+        sqrshrn         v16.4h,  v16.4s,  #\shift
+        sqrshrn         v17.4h,  v17.4s,  #\shift
+        sqrshrn         v18.4h,  v18.4s,  #\shift
+        sqrshrn         v19.4h,  v19.4s,  #\shift
+        sqrshrn2        v16.8h,  v20.4s,  #\shift
+        sqrshrn2        v17.8h,  v21.4s,  #\shift
+        sqrshrn2        v18.8h,  v22.4s,  #\shift
+        sqrshrn2        v19.8h,  v23.4s,  #\shift
+        sqrshrn         v20.4h,  v24.4s,  #\shift
+        sqrshrn         v21.4h,  v25.4s,  #\shift
+        sqrshrn         v22.4h,  v26.4s,  #\shift
+        sqrshrn         v23.4h,  v27.4s,  #\shift
+        sqrshrn2        v20.8h,  v28.4s,  #\shift
+        sqrshrn2        v21.8h,  v29.4s,  #\shift
+        sqrshrn2        v22.8h,  v30.4s,  #\shift
+        sqrshrn2        v23.8h,  v31.4s,  #\shift
+.if \scale
+        b               L(horz_16x4_epilog)
+.else
+L(horz_16x4_epilog):
+        transpose_4x8h  v16, v17, v18, v19, v4,  v5,  v6,  v7
+        transpose_4x8h  v20, v21, v22, v23, v4,  v5,  v6,  v7
+
+.irp i, v16.8h, v20.8h, v17.8h, v21.8h, v18.8h, v22.8h, v19.8h, v23.8h
+        st1             {\i}, [x6], #16
+.endr
+
+        ret             x14
+.endif
+endfunc
+.endm
+
+def_horz_16 scale=1, shift=1, suffix=_scale
+def_horz_16 scale=0, shift=2
+
+function inv_txfm_add_vert_8x16_neon
+        mov             x14, x30
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        ld1             {v\i\().8h}, [x7], x8
+.endr
+        blr             x5
+        load_add_store_8x16 x6, x7
+        ret             x14
+endfunc
+
+function inv_txfm_add_16x16_neon
+        mov             x15, x30
+        sub             sp,  sp,  #512
+        ldrh            w12, [x13], #2
+.irp i, 0, 4, 8, 12
+        add             x6,  sp,  #(\i*16*2)
+.if \i > 0
+        mov             w8,  #(16 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 12
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        add             x7,  x2,  #(\i*4)
+        mov             x8,  #16*4
+        bl              inv_txfm_horz_16x4_neon
+.endr
+        b               3f
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 2
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+3:
+.irp i, 0, 8
+        add             x6,  x0,  #(\i*2)
+        add             x7,  sp,  #(\i*2)
+        mov             x8,  #32
+        bl              inv_txfm_add_vert_8x16_neon
+.endr
+
+        add             sp,  sp,  #512
+        ret             x15
+endfunc
+
+const eob_16x16
+        .short 10, 36, 78, 256
+endconst
+
+const eob_16x16_identity
+        .short 4, 8, 12, 256
+endconst
+
+.macro def_fn_16x16 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_16x16_16bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         16,  16,  2
+.endif
+        adr             x4,  inv_\txfm1\()_4s_x16_neon
+        movrel          x5,  X(inv_\txfm2\()_8h_x16_neon)
+.ifc \txfm1, identity
+.ifc \txfm2, identity
+        movrel          x13, eob_16x16
+.else
+        movrel          x13, eob_16x16_identity
+.endif
+.else
+.ifc \txfm2, identity
+        movrel          x13, eob_16x16_identity
+.else
+        movrel          x13, eob_16x16
+.endif
+.endif
+        b               inv_txfm_add_16x16_neon
+endfunc
+.endm
+
+def_fn_16x16 dct, dct
+def_fn_16x16 identity, identity
+def_fn_16x16 dct, adst
+def_fn_16x16 dct, flipadst
+def_fn_16x16 dct, identity
+def_fn_16x16 adst, dct
+def_fn_16x16 adst, adst
+def_fn_16x16 adst, flipadst
+def_fn_16x16 flipadst, dct
+def_fn_16x16 flipadst, adst
+def_fn_16x16 flipadst, flipadst
+def_fn_16x16 identity, dct
+
+function inv_txfm_add_16x4_neon
+        mov             x15, x30
+        movi            v4.4s,  #0
+
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        ld1             {\i},    [x2]
+        st1             {v4.4s}, [x2], #16
+.endr
+
+        blr             x4
+
+        sqrshrn         v16.4h,  v16.4s,  #1
+        sqrshrn         v17.4h,  v17.4s,  #1
+        sqrshrn         v18.4h,  v18.4s,  #1
+        sqrshrn         v19.4h,  v19.4s,  #1
+        sqrshrn2        v16.8h,  v20.4s,  #1
+        sqrshrn2        v17.8h,  v21.4s,  #1
+        sqrshrn2        v18.8h,  v22.4s,  #1
+        sqrshrn2        v19.8h,  v23.4s,  #1
+        transpose_4x8h  v16, v17, v18, v19, v2,  v3,  v4,  v5
+        blr             x5
+        mov             x6,  x0
+        load_add_store_8x4 x6, x7
+
+        sqrshrn         v16.4h,  v24.4s,  #1
+        sqrshrn         v17.4h,  v25.4s,  #1
+        sqrshrn         v18.4h,  v26.4s,  #1
+        sqrshrn         v19.4h,  v27.4s,  #1
+        sqrshrn2        v16.8h,  v28.4s,  #1
+        sqrshrn2        v17.8h,  v29.4s,  #1
+        sqrshrn2        v18.8h,  v30.4s,  #1
+        sqrshrn2        v19.8h,  v31.4s,  #1
+        transpose_4x8h  v16, v17, v18, v19, v2,  v3,  v4,  v5
+        blr             x5
+        add             x6,  x0,  #16
+        load_add_store_8x4 x6, x7
+
+        ret             x15
+endfunc
+
+function inv_txfm_add_4x16_neon
+        ldrh            w12, [x13, #4]
+        mov             x15, x30
+
+        mov             x11, #64
+
+        cmp             w3,  w12
+        ldrh            w12, [x13, #2]
+        b.lt            1f
+
+        add             x6,  x2,  #48
+        movi            v2.4s,   #0
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s
+        ld1             {\i},    [x6]
+        st1             {v2.4s}, [x6], x11
+.endr
+        blr             x4
+        sqrshrn         v28.4h,  v16.4s,  #1
+        sqrshrn         v29.4h,  v17.4s,  #1
+        sqrshrn         v30.4h,  v18.4s,  #1
+        sqrshrn         v31.4h,  v19.4s,  #1
+        transpose_4x4h  v28, v29, v30, v31, v4,  v5,  v6,  v7
+
+        b               2f
+1:
+.irp i, v28.4h, v29.4h, v30.4h, v31.4h
+        movi            \i,  #0
+.endr
+2:
+        cmp             w3,  w12
+        ldrh            w12, [x13, #0]
+        b.lt            1f
+
+        add             x6,  x2,  #32
+        movi            v2.4s,   #0
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s
+        ld1             {\i},    [x6]
+        st1             {v2.4s}, [x6], x11
+.endr
+        blr             x4
+        sqrshrn         v24.4h,  v16.4s,  #1
+        sqrshrn         v25.4h,  v17.4s,  #1
+        sqrshrn         v26.4h,  v18.4s,  #1
+        sqrshrn         v27.4h,  v19.4s,  #1
+        transpose_4x4h  v24, v25, v26, v27, v4,  v5,  v6,  v7
+
+        b               2f
+1:
+.irp i, v24.4h, v25.4h, v26.4h, v27.4h
+        movi            \i,  #0
+.endr
+2:
+        cmp             w3,  w12
+        b.lt            1f
+
+        add             x6,  x2,  #16
+        movi            v2.4s,   #0
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s
+        ld1             {\i},    [x6]
+        st1             {v2.4s}, [x6], x11
+.endr
+        blr             x4
+        sqrshrn         v20.4h,  v16.4s,  #1
+        sqrshrn         v21.4h,  v17.4s,  #1
+        sqrshrn         v22.4h,  v18.4s,  #1
+        sqrshrn         v23.4h,  v19.4s,  #1
+        transpose_4x4h  v20, v21, v22, v23, v4,  v5,  v6,  v7
+
+        b               2f
+1:
+.irp i, v20.4h, v21.4h, v22.4h, v23.4h
+        movi            \i,  #0
+.endr
+2:
+
+        movi            v2.4s,   #0
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s
+        ld1             {\i},    [x2]
+        st1             {v2.4s}, [x2], x11
+.endr
+        blr             x4
+        sqrshrn         v16.4h,  v16.4s,  #1
+        sqrshrn         v17.4h,  v17.4s,  #1
+        sqrshrn         v18.4h,  v18.4s,  #1
+        sqrshrn         v19.4h,  v19.4s,  #1
+        transpose_4x8h  v16, v17, v18, v19, v4,  v5,  v6,  v7
+
+        blr             x5
+
+        load_add_store_4x16 x0, x6
+
+        ret             x15
+endfunc
+
+const eob_4x16
+        .short 13, 29, 45, 64
+endconst
+
+const eob_4x16_identity1
+        .short 16, 32, 48, 64
+endconst
+
+const eob_4x16_identity2
+        .short 4, 8, 12, 64
+endconst
+
+.macro def_fn_416 w, h, txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_16bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  1
+.endif
+.if \w == 4
+        adr             x4,  inv_\txfm1\()_4s_x\w\()_neon
+        movrel          x5,  X(inv_\txfm2\()_4h_x\h\()_neon)
+.ifc \txfm1, identity
+.ifc \txfm2, identity
+        movrel          x13, eob_4x16
+.else
+        movrel          x13, eob_4x16_identity1
+.endif
+.else
+.ifc \txfm2, identity
+        movrel          x13, eob_4x16_identity2
+.else
+        movrel          x13, eob_4x16
+.endif
+.endif
+.else
+        adr             x4,  inv_\txfm1\()_4s_x\w\()_neon
+        movrel          x5,  X(inv_\txfm2\()_8h_x\h\()_neon)
+.endif
+        b               inv_txfm_add_\w\()x\h\()_neon
+endfunc
+.endm
+
+.macro def_fns_416 w, h
+def_fn_416 \w, \h, dct, dct
+def_fn_416 \w, \h, identity, identity
+def_fn_416 \w, \h, dct, adst
+def_fn_416 \w, \h, dct, flipadst
+def_fn_416 \w, \h, dct, identity
+def_fn_416 \w, \h, adst, dct
+def_fn_416 \w, \h, adst, adst
+def_fn_416 \w, \h, adst, flipadst
+def_fn_416 \w, \h, flipadst, dct
+def_fn_416 \w, \h, flipadst, adst
+def_fn_416 \w, \h, flipadst, flipadst
+def_fn_416 \w, \h, identity, dct
+def_fn_416 \w, \h, adst, identity
+def_fn_416 \w, \h, flipadst, identity
+def_fn_416 \w, \h, identity, adst
+def_fn_416 \w, \h, identity, flipadst
+.endm
+
+def_fns_416 4, 16
+def_fns_416 16, 4
+
+
+function inv_txfm_add_16x8_neon
+        mov             x15, x30
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        cmp             w3,  w13
+        mov             x11, #32
+        b.lt            1f
+
+        movi            v4.4s,  #0
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+
+        add             x6,  x2,  #16
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        ld1             {\i},    [x6]
+        st1             {v4.4s}, [x6], x11
+.endr
+
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .4s, v0.s[0], v24, v25, v26, v27, v28, v29, v30, v31
+        blr             x4
+
+        sqrshrn         v8.4h,   v16.4s,  #1
+        sqrshrn         v9.4h,   v17.4s,  #1
+        sqrshrn         v10.4h,  v18.4s,  #1
+        sqrshrn         v11.4h,  v19.4s,  #1
+        sqrshrn2        v8.8h,   v20.4s,  #1
+        sqrshrn2        v9.8h,   v21.4s,  #1
+        sqrshrn2        v10.8h,  v22.4s,  #1
+        sqrshrn2        v11.8h,  v23.4s,  #1
+        sqrshrn         v12.4h,  v24.4s,  #1
+        sqrshrn         v13.4h,  v25.4s,  #1
+        sqrshrn         v14.4h,  v26.4s,  #1
+        sqrshrn         v15.4h,  v27.4s,  #1
+        sqrshrn2        v12.8h,  v28.4s,  #1
+        sqrshrn2        v13.8h,  v29.4s,  #1
+        sqrshrn2        v14.8h,  v30.4s,  #1
+        sqrshrn2        v15.8h,  v31.4s,  #1
+
+        transpose_4x8h  v8,  v9,  v10, v11, v2,  v3,  v4,  v5
+        transpose_4x8h  v12, v13, v14, v15, v2,  v3,  v4,  v5
+
+        b               2f
+1:
+.irp i, v8.8h, v9.8h, v10.8h, v11.8h, v12.8h, v13.8h, v14.8h, v15.8h
+        movi            \i,  #0
+.endr
+2:
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+
+        movi            v4.4s,  #0
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        ld1             {\i},    [x2]
+        st1             {v4.4s}, [x2], x11
+.endr
+
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .4s, v0.s[0], v24, v25, v26, v27, v28, v29, v30, v31
+        blr             x4
+
+        sqrshrn         v16.4h,  v16.4s,  #1
+        sqrshrn         v17.4h,  v17.4s,  #1
+        sqrshrn         v18.4h,  v18.4s,  #1
+        sqrshrn         v19.4h,  v19.4s,  #1
+        sqrshrn2        v16.8h,  v20.4s,  #1
+        sqrshrn2        v17.8h,  v21.4s,  #1
+        sqrshrn2        v18.8h,  v22.4s,  #1
+        sqrshrn2        v19.8h,  v23.4s,  #1
+
+        mov             v20.16b, v8.16b
+        mov             v21.16b, v9.16b
+        mov             v22.16b, v10.16b
+        mov             v23.16b, v11.16b
+
+        transpose_4x8h  v16, v17, v18, v19, v2,  v3,  v4,  v5
+
+        sqrshrn         v8.4h,   v24.4s,  #1
+        sqrshrn         v9.4h,   v25.4s,  #1
+        sqrshrn         v10.4h,  v26.4s,  #1
+        sqrshrn         v11.4h,  v27.4s,  #1
+        sqrshrn2        v8.8h,   v28.4s,  #1
+        sqrshrn2        v9.8h,   v29.4s,  #1
+        sqrshrn2        v10.8h,  v30.4s,  #1
+        sqrshrn2        v11.8h,  v31.4s,  #1
+
+        transpose_4x8h  v8,  v9, v10, v11, v2,  v3,  v4,  v5
+
+        blr             x5
+
+        mov             x6,  x0
+        load_add_store_8x8 x6, x7
+
+        mov             v16.16b, v8.16b
+        mov             v17.16b, v9.16b
+        mov             v18.16b, v10.16b
+        mov             v19.16b, v11.16b
+        mov             v20.16b, v12.16b
+        mov             v21.16b, v13.16b
+        mov             v22.16b, v14.16b
+        mov             v23.16b, v15.16b
+
+        blr             x5
+
+        add             x0,  x0,  #16
+        load_add_store_8x8 x0, x7
+
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret             x15
+endfunc
+
+function inv_txfm_add_8x16_neon
+        mov             x15, x30
+        stp             d8,  d9,  [sp, #-0x20]!
+        stp             d10, d11, [sp, #0x10]
+        ldrh            w12, [x13, #4]
+
+        mov             x11, #64
+
+        cmp             w3,  w12
+        ldrh            w12, [x13, #2]
+        b.lt            1f
+
+        add             x6,  x2,  #48
+        movi            v4.4s,   #0
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s
+        ld1             {\i},    [x6]
+        st1             {v4.4s}, [x6], x11
+.endr
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        blr             x4
+
+        sqrshrn         v28.4h,  v16.4s,  #1
+        sqrshrn         v29.4h,  v17.4s,  #1
+        sqrshrn         v30.4h,  v18.4s,  #1
+        sqrshrn         v31.4h,  v19.4s,  #1
+        sqrshrn2        v28.8h,  v20.4s,  #1
+        sqrshrn2        v29.8h,  v21.4s,  #1
+        sqrshrn2        v30.8h,  v22.4s,  #1
+        sqrshrn2        v31.8h,  v23.4s,  #1
+        transpose_4x8h  v28, v29, v30, v31, v2, v3, v4, v5
+
+        b               2f
+
+1:
+.irp i, v28.8h, v29.8h, v30.8h, v31.8h
+        movi            \i,  #0
+.endr
+
+2:
+        cmp             w3,  w12
+        ldrh            w12, [x13, #0]
+        b.lt            1f
+
+        add             x6,  x2,  #32
+        movi            v4.4s,   #0
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s
+        ld1             {\i},    [x6]
+        st1             {v4.4s}, [x6], x11
+.endr
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        blr             x4
+
+        sqrshrn         v24.4h,  v16.4s,  #1
+        sqrshrn         v25.4h,  v17.4s,  #1
+        sqrshrn         v26.4h,  v18.4s,  #1
+        sqrshrn         v27.4h,  v19.4s,  #1
+        sqrshrn2        v24.8h,  v20.4s,  #1
+        sqrshrn2        v25.8h,  v21.4s,  #1
+        sqrshrn2        v26.8h,  v22.4s,  #1
+        sqrshrn2        v27.8h,  v23.4s,  #1
+        transpose_4x8h  v24, v25, v26, v27, v2, v3, v4, v5
+
+        b               2f
+
+1:
+.irp i, v24.8h, v25.8h, v26.8h, v27.8h
+        movi            \i,  #0
+.endr
+
+2:
+        cmp             w3,  w12
+        b.lt            1f
+
+        add             x6,  x2,  #16
+        movi            v4.4s,   #0
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s
+        ld1             {\i},    [x6]
+        st1             {v4.4s}, [x6], x11
+.endr
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        blr             x4
+
+        sqrshrn         v8.4h,   v16.4s,  #1
+        sqrshrn         v9.4h,   v17.4s,  #1
+        sqrshrn         v10.4h,  v18.4s,  #1
+        sqrshrn         v11.4h,  v19.4s,  #1
+        sqrshrn2        v8.8h,   v20.4s,  #1
+        sqrshrn2        v9.8h,   v21.4s,  #1
+        sqrshrn2        v10.8h,  v22.4s,  #1
+        sqrshrn2        v11.8h,  v23.4s,  #1
+        transpose_4x8h  v8,  v9,  v10, v11, v2, v3, v4, v5
+
+        b               2f
+
+1:
+.irp i, v8.8h, v9.8h, v10.8h, v11.8h
+        movi            \i,  #0
+.endr
+
+2:
+        movi            v4.4s,   #0
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s
+        ld1             {\i},    [x2]
+        st1             {v4.4s}, [x2], x11
+.endr
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        blr             x4
+
+        sqrshrn         v16.4h,  v16.4s,  #1
+        sqrshrn         v17.4h,  v17.4s,  #1
+        sqrshrn         v18.4h,  v18.4s,  #1
+        sqrshrn         v19.4h,  v19.4s,  #1
+        sqrshrn2        v16.8h,  v20.4s,  #1
+        sqrshrn2        v17.8h,  v21.4s,  #1
+        sqrshrn2        v18.8h,  v22.4s,  #1
+        sqrshrn2        v19.8h,  v23.4s,  #1
+        transpose_4x8h  v16, v17, v18, v19, v2, v3, v4, v5
+
+        mov             v20.16b, v8.16b
+        mov             v21.16b, v9.16b
+        mov             v22.16b, v10.16b
+        mov             v23.16b, v11.16b
+
+        blr             x5
+
+        load_add_store_8x16 x0, x6
+
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x20
+
+        ret             x15
+endfunc
+
+const eob_8x16
+        .short 10, 43, 75, 128
+endconst
+
+const eob_8x16_identity1
+        .short 4, 64, 96, 128
+endconst
+
+const eob_8x16_identity2
+        .short 4, 8, 12, 128
+endconst
+
+.macro def_fn_816 w, h, txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_16bpc_neon, export=1
+.ifc \txfm1\()_\txfm2, dct_dct
+        idct_dc         \w,  \h,  1
+.endif
+        adr             x4,  inv_\txfm1\()_4s_x\w\()_neon
+        movrel          x5,  X(inv_\txfm2\()_8h_x\h\()_neon)
+.ifc \txfm1, identity
+.ifc \txfm2, identity
+        movrel          x13, eob_8x16
+.else
+        movrel          x13, eob_8x16_identity1
+.endif
+.else
+.ifc \txfm2, identity
+        movrel          x13, eob_8x16_identity2
+.else
+        movrel          x13, eob_8x16
+.endif
+.endif
+.if \h == 8
+        ldrh            w13, [x13]
+.endif
+        b               inv_txfm_add_\w\()x\h\()_neon
+endfunc
+.endm
+
+.macro def_fns_816 w, h
+def_fn_816 \w, \h, dct, dct
+def_fn_816 \w, \h, identity, identity
+def_fn_816 \w, \h, dct, adst
+def_fn_816 \w, \h, dct, flipadst
+def_fn_816 \w, \h, dct, identity
+def_fn_816 \w, \h, adst, dct
+def_fn_816 \w, \h, adst, adst
+def_fn_816 \w, \h, adst, flipadst
+def_fn_816 \w, \h, flipadst, dct
+def_fn_816 \w, \h, flipadst, adst
+def_fn_816 \w, \h, flipadst, flipadst
+def_fn_816 \w, \h, identity, dct
+def_fn_816 \w, \h, adst, identity
+def_fn_816 \w, \h, flipadst, identity
+def_fn_816 \w, \h, identity, adst
+def_fn_816 \w, \h, identity, flipadst
+.endm
+
+def_fns_816 8, 16
+def_fns_816 16, 8
+
+function inv_dct32_odd_4s_x16_neon
+        movrel          x16, idct_coeffs, 4*16
+        ld1             {v0.4s, v1.4s}, [x16], #32
+
+        mul_mls         v2,  v16, v31, v0.s[0], v0.s[1] // -> t16a
+        mul_mla         v4,  v16, v31, v0.s[1], v0.s[0] // -> t31a
+        mul_mls         v6,  v24, v23, v0.s[2], v0.s[3] // -> t17a
+        srshr           v16.4s, v2.4s,  #12             // t16a
+        srshr           v31.4s, v4.4s,  #12             // t31a
+        mul_mla         v2,  v24, v23, v0.s[3], v0.s[2] // -> t30a
+        mul_mls         v4,  v20, v27, v1.s[0], v1.s[1] // -> t18a
+        srshr           v24.4s, v6.4s,  #12             // t17a
+        srshr           v23.4s, v2.4s,  #12             // t30a
+        mul_mla         v6,  v20, v27, v1.s[1], v1.s[0] // -> t29a
+        mul_mls         v2,  v28, v19, v1.s[2], v1.s[3] // -> t19a
+        srshr           v20.4s, v4.4s,  #12             // t18a
+        srshr           v27.4s, v6.4s,  #12             // t29a
+        mul_mla         v4,  v28, v19, v1.s[3], v1.s[2] // -> t28a
+        ld1             {v0.4s, v1.4s}, [x16]
+        sub             x16, x16, #4*24
+        mul_mls         v6,  v18, v29, v0.s[0], v0.s[1] // -> t20a
+        srshr           v28.4s, v2.4s,  #12             // t19a
+        srshr           v19.4s, v4.4s,  #12             // t28a
+        mul_mla         v2,  v18, v29, v0.s[1], v0.s[0] // -> t27a
+        mul_mls         v4,  v26, v21, v0.s[2], v0.s[3] // -> t21a
+        srshr           v18.4s, v6.4s,  #12             // t20a
+        srshr           v29.4s, v2.4s,  #12             // t27a
+        mul_mla         v6,  v26, v21, v0.s[3], v0.s[2] // -> t26a
+        mul_mls         v2,  v22, v25, v1.s[0], v1.s[1] // -> t22a
+        srshr           v26.4s, v4.4s,  #12             // t21a
+        srshr           v21.4s, v6.4s,  #12             // t26a
+        mul_mla         v4,  v22, v25, v1.s[1], v1.s[0] // -> t25a
+        mul_mls         v6,  v30, v17, v1.s[2], v1.s[3] // -> t23a
+        srshr           v22.4s, v2.4s,  #12             // t22a
+        srshr           v25.4s, v4.4s,  #12             // t25a
+        mul_mla         v2,  v30, v17, v1.s[3], v1.s[2] // -> t24a
+        srshr           v30.4s, v6.4s,  #12             // t23a
+        srshr           v17.4s, v2.4s,  #12             // t24a
+
+        ld1             {v0.4s, v1.4s}, [x16]
+
+        movi            v5.4s,   #1, msl #16     // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        mvni            v4.4s,   #1, msl #16     // row_clip_min = (~bdmax << 7), 0xfffe0000
+
+        sqsub           v2.4s,   v16.4s,  v24.4s // t17
+        sqadd           v16.4s,  v16.4s,  v24.4s // t16
+        sqsub           v3.4s,   v31.4s,  v23.4s // t30
+        sqadd           v31.4s,  v31.4s,  v23.4s // t31
+        sqsub           v24.4s,  v28.4s,  v20.4s // t18
+        sqadd           v28.4s,  v28.4s,  v20.4s // t19
+        sqadd           v23.4s,  v18.4s,  v26.4s // t20
+        sqsub           v18.4s,  v18.4s,  v26.4s // t21
+        sqsub           v20.4s,  v30.4s,  v22.4s // t22
+        sqadd           v30.4s,  v30.4s,  v22.4s // t23
+        sqadd           v26.4s,  v17.4s,  v25.4s // t24
+        sqsub           v17.4s,  v17.4s,  v25.4s // t25
+        sqsub           v22.4s,  v29.4s,  v21.4s // t26
+        sqadd           v29.4s,  v29.4s,  v21.4s // t27
+        sqadd           v25.4s,  v19.4s,  v27.4s // t28
+        sqsub           v19.4s,  v19.4s,  v27.4s // t29
+
+.irp r, v2, v16, v3, v31, v24, v28, v23, v18, v20, v30, v26, v17, v22, v29, v25, v19
+        smin            \r\().4s, \r\().4s, v5.4s
+.endr
+.irp r, v2, v16, v3, v31, v24, v28, v23, v18, v20, v30, v26, v17, v22, v29, v25, v19
+        smax            \r\().4s, \r\().4s, v4.4s
+.endr
+
+        mul_mls         v7,  v3,  v2,  v1.s[0], v1.s[1] // -> t17a
+        mul_mla         v6,  v3,  v2,  v1.s[1], v1.s[0] // -> t30a
+        mul_mla         v2,  v19, v24, v1.s[1], v1.s[0] // -> t18a
+        srshr           v21.4s, v7.4s,  #12             // t17a
+        srshr           v27.4s, v6.4s,  #12             // t30a
+        neg             v2.4s,   v2.4s                  // -> t18a
+        mul_mls         v7,  v19, v24, v1.s[0], v1.s[1] // -> t29a
+        mul_mls         v6,  v22, v18, v1.s[2], v1.s[3] // -> t21a
+        srshr           v19.4s, v2.4s,  #12             // t18a
+        srshr           v24.4s, v7.4s,  #12             // t29a
+        mul_mla         v2,  v22, v18, v1.s[3], v1.s[2] // -> t26a
+        mul_mla         v7,  v17, v20, v1.s[3], v1.s[2] // -> t22a
+        srshr           v22.4s, v6.4s,  #12             // t21a
+        srshr           v18.4s, v2.4s,  #12             // t26a
+        neg             v7.4s,   v7.4s                  // -> t22a
+        mul_mls         v6,  v17, v20, v1.s[2], v1.s[3] // -> t25a
+        srshr           v17.4s, v7.4s,  #12             // t22a
+        srshr           v20.4s, v6.4s,  #12             // t25a
+
+        sqsub           v2.4s,   v27.4s,  v24.4s // t29
+        sqadd           v27.4s,  v27.4s,  v24.4s // t30
+        sqsub           v3.4s,   v21.4s,  v19.4s // t18
+        sqadd           v21.4s,  v21.4s,  v19.4s // t17
+        sqsub           v24.4s,  v16.4s,  v28.4s // t19a
+        sqadd           v16.4s,  v16.4s,  v28.4s // t16a
+        sqsub           v19.4s,  v30.4s,  v23.4s // t20a
+        sqadd           v30.4s,  v30.4s,  v23.4s // t23a
+        sqsub           v28.4s,  v17.4s,  v22.4s // t21
+        sqadd           v17.4s,  v17.4s,  v22.4s // t22
+        sqadd           v23.4s,  v26.4s,  v29.4s // t24a
+        sqsub           v26.4s,  v26.4s,  v29.4s // t27a
+        sqadd           v22.4s,  v20.4s,  v18.4s // t25
+        sqsub           v20.4s,  v20.4s,  v18.4s // t26
+        sqsub           v29.4s,  v31.4s,  v25.4s // t28a
+        sqadd           v31.4s,  v31.4s,  v25.4s // t31a
+
+.irp r, v2, v27, v3, v21, v24, v16, v19, v30, v28, v17, v23, v26, v22, v20, v29, v31
+        smin            \r\().4s, \r\().4s, v5.4s
+.endr
+.irp r, v2, v27, v3, v21, v24, v16, v19, v30, v28, v17, v23, v26, v22, v20, v29, v31
+        smax            \r\().4s, \r\().4s, v4.4s
+.endr
+
+        mul_mls         v7,  v2,  v3,  v0.s[2], v0.s[3] // -> t18a
+        mul_mla         v6,  v2,  v3,  v0.s[3], v0.s[2] // -> t29a
+        mul_mls         v2,  v29, v24, v0.s[2], v0.s[3] // -> t19
+        srshr           v18.4s, v7.4s,  #12             // t18a
+        srshr           v25.4s, v6.4s,  #12             // t29a
+        mul_mla         v7,  v29, v24, v0.s[3], v0.s[2] // -> t28
+        mul_mla         v6,  v26, v19, v0.s[3], v0.s[2] // -> t20
+        srshr           v29.4s, v2.4s,  #12             // t19
+        srshr           v24.4s, v7.4s,  #12             // t28
+        neg             v6.4s,   v6.4s                  // -> t20
+        mul_mls         v2,  v26, v19, v0.s[2], v0.s[3] // -> t27
+        mul_mla         v7,  v20, v28, v0.s[3], v0.s[2] // -> t21a
+        srshr           v26.4s, v6.4s,  #12             // t20
+        srshr           v19.4s, v2.4s,  #12             // t27
+        neg             v7.4s,   v7.4s                  // -> t21a
+        mul_mls         v6,  v20, v28, v0.s[2], v0.s[3] // -> t26a
+        srshr           v20.4s, v7.4s,  #12             // t21a
+        srshr           v28.4s, v6.4s,  #12             // t26a
+
+        sqsub           v2.4s,   v16.4s,  v30.4s // t23
+        sqadd           v16.4s,  v16.4s,  v30.4s // t16 = out16
+        sqsub           v3.4s,   v31.4s,  v23.4s // t24
+        sqadd           v31.4s,  v31.4s,  v23.4s // t31 = out31
+        sqsub           v23.4s,  v21.4s,  v17.4s // t22a
+        sqadd           v17.4s,  v21.4s,  v17.4s // t17a = out17
+        sqadd           v30.4s,  v27.4s,  v22.4s // t30a = out30
+        sqsub           v21.4s,  v27.4s,  v22.4s // t25a
+        sqsub           v27.4s,  v18.4s,  v20.4s // t21
+        sqadd           v18.4s,  v18.4s,  v20.4s // t18 = out18
+        sqadd           v7.4s,   v29.4s,  v26.4s // t19a = out19
+        sqsub           v26.4s,  v29.4s,  v26.4s // t20a
+        sqadd           v29.4s,  v25.4s,  v28.4s // t29 = out29
+        sqsub           v25.4s,  v25.4s,  v28.4s // t26
+        sqadd           v28.4s,  v24.4s,  v19.4s // t28a = out28
+        sqsub           v24.4s,  v24.4s,  v19.4s // t27a
+        mov             v19.16b, v7.16b          // out19
+
+.irp r, v2, v16, v3, v31, v23, v17, v30, v21, v27, v18, v19, v26, v29, v25, v28, v24
+        smin            \r\().4s, \r\().4s, v5.4s
+.endr
+.irp r, v2, v16, v3, v31, v23, v17, v30, v21, v27, v18, v19, v26, v29, v25, v28, v24
+        smax            \r\().4s, \r\().4s, v4.4s
+.endr
+
+        mul_mls         v7,  v24, v26, v0.s[0], v0.s[0] // -> t20
+        mul_mla         v6,  v24, v26, v0.s[0], v0.s[0] // -> t27
+        srshr           v20.4s, v7.4s,  #12             // t20
+        srshr           v22.4s, v6.4s,  #12             // t27
+
+        mul_mla         v7,  v25, v27, v0.s[0], v0.s[0] // -> t26a
+        mul_mls         v6,  v25, v27, v0.s[0], v0.s[0] // -> t21a
+        mov             v27.16b,  v22.16b               // t27
+        srshr           v26.4s, v7.4s,  #12             // t26a
+
+        mul_mls         v24, v21, v23, v0.s[0], v0.s[0] // -> t22
+        mul_mla         v7,  v21, v23, v0.s[0], v0.s[0] // -> t25
+        srshr           v21.4s, v6.4s,  #12             // t21a
+        srshr           v22.4s, v24.4s, #12             // t22
+        srshr           v25.4s, v7.4s,  #12             // t25
+
+        mul_mls         v7,  v3,  v2,  v0.s[0], v0.s[0] // -> t23a
+        mul_mla         v6,  v3,  v2,  v0.s[0], v0.s[0] // -> t24a
+        srshr           v23.4s, v7.4s,  #12             // t23a
+        srshr           v24.4s, v6.4s,  #12             // t24a
+
+        ret
+endfunc
+
+.macro def_horz_32 scale=0, shift=2, suffix
+function inv_txfm_horz\suffix\()_dct_32x4_neon
+        mov             x14, x30
+        movi            v7.4s,  #0
+        lsl             x8,  x8,  #1
+.if \scale
+        movz            w16, #2896*8, lsl #16
+        dup             v0.2s,   w16
+.endif
+
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        ld1             {\i}, [x7]
+        st1             {v7.4s}, [x7], x8
+.endr
+        sub             x7,  x7,  x8, lsl #4
+        add             x7,  x7,  x8, lsr #1
+.if \scale
+        scale_input     .4s, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .4s, v0.s[0], v24, v25, v26, v27, v28, v29, v30, v31
+.endif
+        bl              inv_dct_4s_x16_neon
+
+        // idct_16 leaves the row_clip_max/min constants in v5 and v4
+.irp r, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31
+        smax_4s         \r, \r, v4
+.endr
+
+        transpose_4x4s  v16, v17, v18, v19, v2,  v3,  v4,  v5
+        transpose_4x4s  v20, v21, v22, v23, v2,  v3,  v4,  v5
+        transpose_4x4s  v24, v25, v26, v27, v2,  v3,  v4,  v5
+        transpose_4x4s  v28, v29, v30, v31, v2,  v3,  v4,  v5
+
+.macro store1 r0, r1, r2, r3
+        st1             {\r0}, [x6], #16
+        st1             {\r1}, [x6], #16
+        st1             {\r2}, [x6], #16
+        st1             {\r3}, [x6], #16
+.endm
+        store1          v16.4s,  v20.4s,  v24.4s,  v28.4s
+        store1          v17.4s,  v21.4s,  v25.4s,  v29.4s
+        store1          v18.4s,  v22.4s,  v26.4s,  v30.4s
+        store1          v19.4s,  v23.4s,  v27.4s,  v31.4s
+.purgem store1
+        sub             x6,  x6,  #64*4
+
+        movi            v7.4s,  #0
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        ld1             {\i}, [x7]
+        st1             {v7.4s}, [x7], x8
+.endr
+.if \scale
+        // This relies on the fact that the idct also leaves the right coeff in v0.s[1]
+        scale_input     .4s, v0.s[1], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .4s, v0.s[1], v24, v25, v26, v27, v28, v29, v30, v31
+.endif
+        bl              inv_dct32_odd_4s_x16_neon
+        transpose_4x4s  v31, v30, v29, v28, v2,  v3,  v4,  v5
+        transpose_4x4s  v27, v26, v25, v24, v2,  v3,  v4,  v5
+        transpose_4x4s  v23, v22, v21, v20, v2,  v3,  v4,  v5
+        transpose_4x4s  v19, v18, v17, v16, v2,  v3,  v4,  v5
+.macro store2 r0, r1, r2, r3, shift
+        ld1             {v0.4s, v1.4s, v2.4s, v3.4s}, [x6]
+        sqsub           v4.4s,   v0.4s,   \r0
+        sqadd           v0.4s,   v0.4s,   \r0
+        sqsub           v5.4s,   v1.4s,   \r1
+        sqadd           v1.4s,   v1.4s,   \r1
+        sqsub           v6.4s,   v2.4s,   \r2
+        sqadd           v2.4s,   v2.4s,   \r2
+        sqsub           v7.4s,   v3.4s,   \r3
+        sqadd           v3.4s,   v3.4s,   \r3
+        sqrshrn         v0.4h,   v0.4s,   #\shift
+        sqrshrn2        v0.8h,   v1.4s,   #\shift
+        sqrshrn         v1.4h,   v2.4s,   #\shift
+        sqrshrn2        v1.8h,   v3.4s,   #\shift
+        sqrshrn         v2.4h,   v7.4s,   #\shift
+        sqrshrn2        v2.8h,   v6.4s,   #\shift
+        sqrshrn         v3.4h,   v5.4s,   #\shift
+        sqrshrn2        v3.8h,   v4.4s,   #\shift
+        st1             {v0.8h, v1.8h}, [x6], #32
+        rev64           v2.8h,   v2.8h
+        rev64           v3.8h,   v3.8h
+        st1             {v2.8h, v3.8h}, [x6], #32
+.endm
+
+        store2          v31.4s,  v27.4s,  v23.4s,  v19.4s,  \shift
+        store2          v30.4s,  v26.4s,  v22.4s,  v18.4s,  \shift
+        store2          v29.4s,  v25.4s,  v21.4s,  v17.4s,  \shift
+        store2          v28.4s,  v24.4s,  v20.4s,  v16.4s,  \shift
+.purgem store2
+        ret             x14
+endfunc
+.endm
+
+def_horz_32 scale=0, shift=2
+def_horz_32 scale=1, shift=1, suffix=_scale
+
+function inv_txfm_add_vert_dct_8x32_neon
+        mov             x14, x30
+        lsl             x8,  x8,  #1
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        ld1             {v\i\().8h}, [x7], x8
+.endr
+        sub             x7,  x7,  x8, lsl #4
+
+        bl              X(inv_dct_8h_x16_neon)
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        st1             {v\i\().8h}, [x7], x8
+.endr
+        sub             x7,  x7,  x8, lsl #4
+        add             x7,  x7,  x8, lsr #1
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+        ld1             {v\i\().8h}, [x7], x8
+.endr
+        sub             x7,  x7,  x8, lsl #4
+        sub             x7,  x7,  x8, lsr #1
+        bl              X(inv_dct32_odd_8h_x16_neon)
+
+        neg             x9,  x8
+        mov             x10, x6
+        mvni            v1.8h,   #0xfc, lsl #8 // 0x3ff
+.macro combine r0, r1, r2, r3, op, stride
+        ld1             {v5.8h}, [x7],    \stride
+        ld1             {v2.8h}, [x10],   x1
+        ld1             {v6.8h}, [x7],    \stride
+        ld1             {v3.8h}, [x10],   x1
+        \op             v5.8h,   v5.8h,   \r0
+        ld1             {v7.8h}, [x7],    \stride
+        ld1             {v4.8h}, [x10],   x1
+        srshr           v5.8h,   v5.8h,   #4
+        \op             v6.8h,   v6.8h,   \r1
+        usqadd          v2.8h,   v5.8h
+        srshr           v6.8h,   v6.8h,   #4
+        \op             v7.8h,   v7.8h,   \r2
+        ld1             {v5.8h}, [x7],    \stride
+        usqadd          v3.8h,   v6.8h
+        smin            v2.8h,   v2.8h,   v1.8h
+        srshr           v7.8h,   v7.8h,   #4
+        \op             v5.8h,   v5.8h,   \r3
+        st1             {v2.8h}, [x6],    x1
+        ld1             {v2.8h}, [x10],   x1
+        usqadd          v4.8h,   v7.8h
+        smin            v3.8h,   v3.8h,   v1.8h
+        srshr           v5.8h,   v5.8h,   #4
+        st1             {v3.8h}, [x6],    x1
+        usqadd          v2.8h,   v5.8h
+        smin            v4.8h,   v4.8h,   v1.8h
+        st1             {v4.8h}, [x6],    x1
+        smin            v2.8h,   v2.8h,   v1.8h
+        st1             {v2.8h}, [x6],    x1
+.endm
+        combine         v31.8h, v30.8h, v29.8h, v28.8h, sqadd, x8
+        combine         v27.8h, v26.8h, v25.8h, v24.8h, sqadd, x8
+        combine         v23.8h, v22.8h, v21.8h, v20.8h, sqadd, x8
+        combine         v19.8h, v18.8h, v17.8h, v16.8h, sqadd, x8
+        sub             x7,  x7,  x8
+        combine         v16.8h, v17.8h, v18.8h, v19.8h, sqsub, x9
+        combine         v20.8h, v21.8h, v22.8h, v23.8h, sqsub, x9
+        combine         v24.8h, v25.8h, v26.8h, v27.8h, sqsub, x9
+        combine         v28.8h, v29.8h, v30.8h, v31.8h, sqsub, x9
+.purgem combine
+
+        ret             x14
+endfunc
+
+const eob_32x32
+        .short 10, 36, 78, 136, 210, 300, 406, 1024
+endconst
+
+const eob_16x32
+        .short 10, 36, 78, 151, 215, 279, 343, 512
+endconst
+
+const eob_16x32_shortside
+        .short 10, 36, 78, 512
+endconst
+
+const eob_8x32
+        .short 10, 43, 75, 107, 139, 171, 203, 256
+endconst
+
+function inv_txfm_add_identity_identity_32x32_16bpc_neon, export=1
+        movi            v0.8h,  #0
+        movi            v1.8h,  #0
+        movrel          x13, eob_32x32, 2
+
+        mov             x8,  #4*32
+1:
+        mov             w9,  #0
+        movrel          x12, eob_32x32, 2
+2:
+        add             w9,  w9,  #8
+        ld1             {v16.4s, v17.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v18.4s, v19.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v20.4s, v21.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v22.4s, v23.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v24.4s, v25.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v26.4s, v27.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v28.4s, v29.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v30.4s, v31.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        sqxtn           v16.4h,  v16.4s
+        sqxtn2          v16.8h,  v17.4s
+        sqxtn           v17.4h,  v18.4s
+        sqxtn2          v17.8h,  v19.4s
+        sqxtn           v18.4h,  v20.4s
+        sqxtn2          v18.8h,  v21.4s
+        sqxtn           v19.4h,  v22.4s
+        sqxtn2          v19.8h,  v23.4s
+        sqxtn           v20.4h,  v24.4s
+        sqxtn2          v20.8h,  v25.4s
+        sqxtn           v21.4h,  v26.4s
+        sqxtn2          v21.8h,  v27.4s
+        sqxtn           v22.4h,  v28.4s
+        sqxtn2          v22.8h,  v29.4s
+        sqxtn           v23.4h,  v30.4s
+        sqxtn2          v23.8h,  v31.4s
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+
+        load_add_store_8x8 x0, x7, shiftbits=2
+        ldrh            w11, [x12], #4
+        sub             x0,  x0,  x1, lsl #3
+        add             x0,  x0,  #2*8
+        cmp             w3,  w11
+        b.ge            2b
+
+        ldrh            w11, [x13], #4
+        cmp             w3,  w11
+        b.lt            9f
+
+        sub             x0,  x0,  w9, uxtw #1
+        add             x0,  x0,  x1, lsl #3
+        msub            x2,  x8,  x9,  x2
+        add             x2,  x2,  #4*8
+        b               1b
+9:
+        ret
+endfunc
+
+.macro shift_16_regs op, shift
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        \op             \i,  \i,  #\shift
+.endr
+.endm
+
+.macro def_identity_1632 w, h, wshort, hshort
+function inv_txfm_add_identity_identity_\w\()x\h\()_16bpc_neon, export=1
+        movz            w16, #2896*8, lsl #16
+        movz            w17, #2*(5793-4096)*8, lsl #16
+        movi            v0.4s,   #0
+        movi            v1.4s,   #0
+        movrel          x13, eob_16x32\hshort, 2
+
+        mov             x8,  #4*\h
+1:
+        mov             w9,  #0
+        movrel          x12, eob_16x32\wshort, 2
+2:
+        add             w9,  w9,  #8
+        ld1             {v16.4s, v17.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        dup             v2.2s,   w16
+        ld1             {v18.4s, v19.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        mov             v2.s[1], w17
+        ld1             {v20.4s, v21.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v22.4s, v23.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v24.4s, v25.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v26.4s, v27.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v28.4s, v29.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v30.4s, v31.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        scale_input     .4s, v2.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+        scale_input     .4s, v2.s[0], v24, v25, v26, v27, v28, v29, v30, v31
+
+.if \w == 16
+        // 16x32
+        identity_4x16_shift1 v2.s[1]
+.else
+        // 32x16
+        shift_16_regs   sqshl, 1
+        identity_4x16   v2.s[1]
+.endif
+        sqxtn           v16.4h,  v16.4s
+        sqxtn2          v16.8h,  v17.4s
+        sqxtn           v17.4h,  v18.4s
+        sqxtn2          v17.8h,  v19.4s
+        sqxtn           v18.4h,  v20.4s
+        sqxtn2          v18.8h,  v21.4s
+        sqxtn           v19.4h,  v22.4s
+        sqxtn2          v19.8h,  v23.4s
+        sqxtn           v20.4h,  v24.4s
+        sqxtn2          v20.8h,  v25.4s
+        sqxtn           v21.4h,  v26.4s
+        sqxtn2          v21.8h,  v27.4s
+        sqxtn           v22.4h,  v28.4s
+        sqxtn2          v22.8h,  v29.4s
+        sqxtn           v23.4h,  v30.4s
+        sqxtn2          v23.8h,  v31.4s
+
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+
+.if \w == 16
+        load_add_store_8x8 x0, x7, shiftbits=2
+.else
+        load_add_store_8x8 x0, x7, shiftbits=4
+.endif
+        ldrh            w11, [x12], #4
+        sub             x0,  x0,  x1, lsl #3
+        add             x0,  x0,  #16
+        cmp             w3,  w11
+        b.ge            2b
+
+        ldrh            w11, [x13], #4
+        cmp             w3,  w11
+        b.lt            9f
+
+        sub             x0,  x0,  w9, uxtw #1
+        add             x0,  x0,  x1, lsl #3
+        msub            x2,  x8,  x9,  x2
+        add             x2,  x2,  #4*8
+        b               1b
+9:
+        ret
+endfunc
+.endm
+
+def_identity_1632 16, 32, _shortside,
+def_identity_1632 32, 16, , _shortside
+
+.macro def_identity_832 w, h
+function inv_txfm_add_identity_identity_\w\()x\h\()_16bpc_neon, export=1
+        movi            v0.4s,  #0
+        movi            v1.4s,  #0
+        // Working on 8x8 blocks, read every other entry from eob_8x32
+        movrel          x13, eob_8x32, 2
+
+        mov             w8,  #4*\h
+1:
+        // Working on 8x8 blocks, read every other entry from eob_8x32
+        ldrh            w12, [x13], #4
+        ld1             {v16.4s, v17.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v18.4s, v19.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v20.4s, v21.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v22.4s, v23.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v24.4s, v25.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v26.4s, v27.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v28.4s, v29.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+        ld1             {v30.4s, v31.4s}, [x2]
+        st1             {v0.4s, v1.4s},   [x2], x8
+
+.if \w == 8
+        sqrshrn         v16.4h,  v16.4s,  #1
+        sqrshrn2        v16.8h,  v17.4s,  #1
+        sqrshrn         v17.4h,  v18.4s,  #1
+        sqrshrn2        v17.8h,  v19.4s,  #1
+        sqrshrn         v18.4h,  v20.4s,  #1
+        sqrshrn2        v18.8h,  v21.4s,  #1
+        sqrshrn         v19.4h,  v22.4s,  #1
+        sqrshrn2        v19.8h,  v23.4s,  #1
+        sqrshrn         v20.4h,  v24.4s,  #1
+        sqrshrn2        v20.8h,  v25.4s,  #1
+        sqrshrn         v21.4h,  v26.4s,  #1
+        sqrshrn2        v21.8h,  v27.4s,  #1
+        sqrshrn         v22.4h,  v28.4s,  #1
+        sqrshrn2        v22.8h,  v29.4s,  #1
+        sqrshrn         v23.4h,  v30.4s,  #1
+        sqrshrn2        v23.8h,  v31.4s,  #1
+.else
+        sqxtn           v16.4h,  v16.4s
+        sqxtn2          v16.8h,  v17.4s
+        sqxtn           v17.4h,  v18.4s
+        sqxtn2          v17.8h,  v19.4s
+        sqxtn           v18.4h,  v20.4s
+        sqxtn2          v18.8h,  v21.4s
+        sqxtn           v19.4h,  v22.4s
+        sqxtn2          v19.8h,  v23.4s
+        sqxtn           v20.4h,  v24.4s
+        sqxtn2          v20.8h,  v25.4s
+        sqxtn           v21.4h,  v26.4s
+        sqxtn2          v21.8h,  v27.4s
+        sqxtn           v22.4h,  v28.4s
+        sqxtn2          v22.8h,  v29.4s
+        sqxtn           v23.4h,  v30.4s
+        sqxtn2          v23.8h,  v31.4s
+.endif
+
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v4, v5
+
+
+        cmp             w3,  w12
+.if \w == 8
+        load_add_store_8x8 x0, x7, shiftbits=2
+.else
+        load_add_store_8x8 x0, x7, shiftbits=3
+.endif
+
+        b.lt            9f
+.if \w == 8
+        sub             x2,  x2,  x8, lsl #3
+        add             x2,  x2,  #4*8
+.else
+        sub             x0,  x0,  x1, lsl #3
+        add             x0,  x0,  #2*8
+.endif
+        b               1b
+
+9:
+        ret
+endfunc
+.endm
+
+def_identity_832 8, 32
+def_identity_832 32, 8
+
+function inv_txfm_add_dct_dct_32x32_16bpc_neon, export=1
+        idct_dc         32,  32,  2
+
+        mov             x15, x30
+        sub             sp,  sp,  #2048
+        movrel          x13, eob_32x32
+        ldrh            w12, [x13], #2
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             x6,  sp,  #(\i*32*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 28
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        add             x7,  x2,  #(\i*4)
+        mov             x8,  #32*4
+        bl              inv_txfm_horz_dct_32x4_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24
+        add             x6,  x0,  #(\i*2)
+        add             x7,  sp,  #(\i*2)
+        mov             x8,  #32*2
+        bl              inv_txfm_add_vert_dct_8x32_neon
+.endr
+
+        add             sp,  sp,  #2048
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_16x32_16bpc_neon, export=1
+        idct_dc         16,  32,  1
+
+        mov             x15, x30
+        sub             sp,  sp,  #1024
+        movrel          x13, eob_16x32
+        ldrh            w12, [x13], #2
+        adr             x4,  inv_dct_4s_x16_neon
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             x6,  sp,  #(\i*16*2)
+        add             x7,  x2,  #(\i*4)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 28
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        mov             x8,  #4*32
+        bl              inv_txfm_horz_scale_16x4_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 2
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8
+        add             x6,  x0,  #(\i*2)
+        add             x7,  sp,  #(\i*2)
+        mov             x8,  #16*2
+        bl              inv_txfm_add_vert_dct_8x32_neon
+.endr
+
+        add             sp,  sp,  #1024
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_32x16_16bpc_neon, export=1
+        idct_dc         32,  16,  1
+
+        mov             x15, x30
+        sub             sp,  sp,  #1024
+
+        movrel          x13, eob_16x32
+        movrel          x5,  X(inv_dct_8h_x16_neon)
+        ldrh            w12, [x13], #2
+
+.irp i, 0, 4, 8, 12
+        add             x6,  sp,  #(\i*32*2)
+        add             x7,  x2,  #(\i*4)
+.if \i > 0
+        mov             w8,  #(16 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 12
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        mov             x8,  #4*16
+        bl              inv_txfm_horz_scale_dct_32x4_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24
+        add             x6,  x0,  #(\i*2)
+        add             x7,  sp,  #(\i*2)
+        mov             x8,  #32*2
+        bl              inv_txfm_add_vert_8x16_neon
+.endr
+
+        add             sp,  sp,  #1024
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_8x32_16bpc_neon, export=1
+        idct_dc         8,   32, 2
+
+        mov             x15, x30
+        sub             sp,  sp,  #512
+
+        movrel          x13, eob_8x32
+
+        movi            v28.4s,  #0
+        mov             x8,  #4*32
+        mov             w9,  #32
+        mov             x6,  sp
+        mov             x7,  x2
+1:
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23
+        ld1             {v\i\().4s}, [x7]
+        st1             {v28.4s}, [x7], x8
+.endr
+        ldrh            w12, [x13], #2
+        sub             w9,  w9,  #4
+        sub             x7,  x7,  x8, lsl #3
+        add             x7,  x7,  #4*4
+
+        bl              inv_dct_4s_x8_neon
+
+        sqrshrn         v16.4h,  v16.4s,  #2
+        sqrshrn         v17.4h,  v17.4s,  #2
+        sqrshrn         v18.4h,  v18.4s,  #2
+        sqrshrn         v19.4h,  v19.4s,  #2
+        sqrshrn2        v16.8h,  v20.4s,  #2
+        sqrshrn2        v17.8h,  v21.4s,  #2
+        sqrshrn2        v18.8h,  v22.4s,  #2
+        sqrshrn2        v19.8h,  v23.4s,  #2
+
+        transpose_4x8h  v16, v17, v18, v19, v2,  v3,  v4,  v5
+
+        cmp             w3,  w12
+        st1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x6], #64
+
+        b.ge            1b
+        cbz             w9,  3f
+
+        movi            v29.8h,  #0
+        movi            v30.8h,  #0
+        movi            v31.8h,  #0
+2:
+        subs            w9,  w9,  #4
+        st1             {v28.8h,v29.8h,v30.8h,v31.8h}, [x6], #64
+        b.gt            2b
+
+3:
+        mov             x6,  x0
+        mov             x7,  sp
+        mov             x8,  #8*2
+        bl              inv_txfm_add_vert_dct_8x32_neon
+
+        add             sp,  sp,  #512
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_32x8_16bpc_neon, export=1
+        idct_dc         32,  8,   2
+
+        mov             x15, x30
+        sub             sp,  sp,  #512
+
+.irp i, 0, 4
+        add             x6,  sp,  #(\i*32*2)
+        add             x7,  x2,  #(\i*4)
+.if \i > 0
+        cmp             w3,  #10
+        b.lt            1f
+.endif
+        mov             x8,  #8*4
+        bl              inv_txfm_horz_dct_32x4_neon
+.endr
+        b               2f
+
+1:
+        movi            v4.8h,   #0
+        movi            v5.8h,   #0
+        movi            v6.8h,   #0
+        movi            v7.8h,   #0
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+
+2:
+        mov             x8,  #2*32
+        mov             w9,  #0
+1:
+        add             x6,  x0,  x9, lsl #1
+        add             x7,  sp,  x9, lsl #1 // #(\i*2)
+
+.irp i, 16, 17, 18, 19, 20, 21, 22, 23
+        ld1             {v\i\().8h}, [x7], x8
+.endr
+        add             w9,  w9,  #8
+
+        bl              X(inv_dct_8h_x8_neon)
+
+        cmp             w9,  #32
+
+        load_add_store_8x8 x6, x7
+
+        b.lt            1b
+
+        add             sp,  sp,  #512
+        ret             x15
+endfunc
+
+function inv_dct64_step1_neon
+        // in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+        // in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+        // in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+        // in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+
+        ld1             {v0.4s, v1.4s}, [x17], #32
+
+        sqrdmulh        v23.4s,  v16.4s,  v0.s[1]       // t63a
+        sqrdmulh        v16.4s,  v16.4s,  v0.s[0]       // t32a
+        sqrdmulh        v22.4s,  v17.4s,  v0.s[2]       // t62a
+        sqrdmulh        v17.4s,  v17.4s,  v0.s[3]       // t33a
+        sqrdmulh        v21.4s,  v18.4s,  v1.s[1]       // t61a
+        sqrdmulh        v18.4s,  v18.4s,  v1.s[0]       // t34a
+        sqrdmulh        v20.4s,  v19.4s,  v1.s[2]       // t60a
+        sqrdmulh        v19.4s,  v19.4s,  v1.s[3]       // t35a
+
+        ld1             {v0.4s}, [x17], #16
+
+        sqadd           v24.4s,  v16.4s,  v17.4s        // t32
+        sqsub           v25.4s,  v16.4s,  v17.4s        // t33
+        sqsub           v26.4s,  v19.4s,  v18.4s        // t34
+        sqadd           v27.4s,  v19.4s,  v18.4s        // t35
+        sqadd           v28.4s,  v20.4s,  v21.4s        // t60
+        sqsub           v29.4s,  v20.4s,  v21.4s        // t61
+        sqsub           v30.4s,  v23.4s,  v22.4s        // t62
+        sqadd           v31.4s,  v23.4s,  v22.4s        // t63
+
+.irp r, v24, v25, v26, v27, v28, v29, v30, v31
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v24, v25, v26, v27, v28, v29, v30, v31
+        smax_4s         \r, \r, v4
+.endr
+
+        mul_mla         v2,  v29, v26, v0.s[0], v0.s[1] // -> t34a
+        mul_mls         v7,  v29, v26, v0.s[1], v0.s[0] // -> t61a
+        neg             v2.4s,   v2.4s                  // t34a
+        mul_mls         v6,  v30, v25, v0.s[1], v0.s[0] // -> t33a
+        srshr           v26.4s, v2.4s,  #12             // t34a
+        mul_mla         v2,  v30, v25, v0.s[0], v0.s[1] // -> t62a
+        srshr           v29.4s, v7.4s,  #12             // t61a
+        srshr           v25.4s, v6.4s,  #12             // t33a
+        srshr           v30.4s, v2.4s,  #12             // t62a
+
+        sqadd           v16.4s,  v24.4s,  v27.4s        // t32a
+        sqsub           v19.4s,  v24.4s,  v27.4s        // t35a
+        sqadd           v17.4s,  v25.4s,  v26.4s        // t33
+        sqsub           v18.4s,  v25.4s,  v26.4s        // t34
+        sqsub           v20.4s,  v31.4s,  v28.4s        // t60a
+        sqadd           v23.4s,  v31.4s,  v28.4s        // t63a
+        sqsub           v21.4s,  v30.4s,  v29.4s        // t61
+        sqadd           v22.4s,  v30.4s,  v29.4s        // t62
+
+.irp r, v16, v19, v17, v18, v20, v23, v21, v22
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v16, v19, v17, v18, v20, v23, v21, v22
+        smax_4s         \r, \r, v4
+.endr
+
+        mul_mla         v2,  v21, v18, v0.s[2], v0.s[3] // -> t61a
+        mul_mls         v7,  v21, v18, v0.s[3], v0.s[2] // -> t34a
+        mul_mla         v6,  v20, v19, v0.s[2], v0.s[3] // -> t60
+        srshr           v21.4s, v2.4s,  #12             // t61a
+        srshr           v18.4s, v7.4s,  #12             // t34a
+        mul_mls         v2,  v20, v19, v0.s[3], v0.s[2] // -> t35
+        srshr           v20.4s, v6.4s,  #12             // t60
+        srshr           v19.4s, v2.4s,  #12             // t35
+
+        st1             {v16.4s, v17.4s, v18.4s, v19.4s}, [x6], #64
+        st1             {v20.4s, v21.4s, v22.4s, v23.4s}, [x6], #64
+
+        ret
+endfunc
+
+function inv_dct64_step2_neon
+        movrel          x16, idct_coeffs
+        ld1             {v0.4s}, [x16]
+1:
+        // t32a/33/34a/35/60/61a/62/63a
+        // t56a/57/58a/59/36/37a/38/39a
+        // t40a/41/42a/43/52/53a/54/55a
+        // t48a/49/50a/51/44/45a/46/47a
+        ldr             q16, [x6, #4*4*0]  // t32a
+        ldr             q17, [x9, #4*4*8]  // t39a
+        ldr             q18, [x9, #4*4*0]  // t63a
+        ldr             q19, [x6, #4*4*8]  // t56a
+        ldr             q20, [x6, #4*4*16] // t40a
+        ldr             q21, [x9, #4*4*24] // t47a
+        ldr             q22, [x9, #4*4*16] // t55a
+        ldr             q23, [x6, #4*4*24] // t48a
+
+        sqadd           v24.4s,  v16.4s, v17.4s         // t32
+        sqsub           v25.4s,  v16.4s, v17.4s         // t39
+        sqadd           v26.4s,  v18.4s, v19.4s         // t63
+        sqsub           v27.4s,  v18.4s, v19.4s         // t56
+        sqsub           v28.4s,  v21.4s, v20.4s         // t40
+        sqadd           v29.4s,  v21.4s, v20.4s         // t47
+        sqadd           v30.4s,  v23.4s, v22.4s         // t48
+        sqsub           v31.4s,  v23.4s, v22.4s         // t55
+
+.irp r, v24, v25, v26, v27, v28, v29, v30, v31
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v24, v25, v26, v27, v28, v29, v30, v31
+        smax_4s         \r, \r, v4
+.endr
+
+        mul_mla         v2,  v27, v25, v0.s[3], v0.s[2] // -> t56a
+        mul_mls         v7,  v27, v25, v0.s[2], v0.s[3] // -> t39a
+        mul_mla         v6,  v31, v28, v0.s[3], v0.s[2] // -> t40a
+        srshr           v25.4s, v2.4s,  #12             // t56a
+        srshr           v27.4s, v7.4s,  #12             // t39a
+        neg             v6.4s,   v6.4s                  // t40a
+        mul_mls         v2,  v31, v28, v0.s[2], v0.s[3] // -> t55a
+        srshr           v31.4s, v6.4s,  #12             // t40a
+        srshr           v28.4s, v2.4s,  #12             // t55a
+
+        sqadd           v16.4s,  v24.4s,  v29.4s        // t32a
+        sqsub           v19.4s,  v24.4s,  v29.4s        // t47a
+        sqadd           v17.4s,  v27.4s,  v31.4s        // t39
+        sqsub           v18.4s,  v27.4s,  v31.4s        // t40
+        sqsub           v20.4s,  v26.4s,  v30.4s        // t48a
+        sqadd           v23.4s,  v26.4s,  v30.4s        // t63a
+        sqsub           v21.4s,  v25.4s,  v28.4s        // t55
+        sqadd           v22.4s,  v25.4s,  v28.4s        // t56
+
+.irp r, v16, v19, v17, v18, v20, v23, v21, v22
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v16, v19, v17, v18, v20, v23, v21, v22
+        smax_4s         \r, \r, v4
+.endr
+
+        mul_mls         v2,  v21, v18, v0.s[0], v0.s[0] // -> t40a
+        mul_mla         v7,  v21, v18, v0.s[0], v0.s[0] // -> t55a
+        mul_mls         v6,  v20, v19, v0.s[0], v0.s[0] // -> t47
+        srshr           v18.4s, v2.4s,  #12             // t40a
+        srshr           v21.4s, v7.4s,  #12             // t55a
+        mul_mla         v2,  v20, v19, v0.s[0], v0.s[0] // -> t48
+        srshr           v19.4s, v6.4s,  #12             // t47
+        srshr           v20.4s, v2.4s,  #12             // t48
+
+        str             q16, [x6, #4*4*0]  // t32a
+        str             q17, [x9, #4*4*0]  // t39
+        str             q18, [x6, #4*4*8]  // t40a
+        str             q19, [x9, #4*4*8]  // t47
+        str             q20, [x6, #4*4*16] // t48
+        str             q21, [x9, #4*4*16] // t55a
+        str             q22, [x6, #4*4*24] // t56
+        str             q23, [x9, #4*4*24] // t63a
+
+        add             x6,  x6,  #4*4
+        sub             x9,  x9,  #4*4
+        cmp             x6,  x9
+        b.lt            1b
+        ret
+endfunc
+
+.macro load8 src, strd, zero, clear
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s
+.if \clear
+        ld1             {\i}, [\src]
+        st1             {\zero}, [\src], \strd
+.else
+        ld1             {\i}, [\src], \strd
+.endif
+.endr
+.endm
+
+.macro store16 dst
+.irp i, v16.4s, v17.4s, v18.4s, v19.4s, v20.4s, v21.4s, v22.4s, v23.4s, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        st1             {\i}, [\dst], #16
+.endr
+.endm
+
+.macro clear_upper8
+.irp i, v24.4s, v25.4s, v26.4s, v27.4s, v28.4s, v29.4s, v30.4s, v31.4s
+        movi            \i,  #0
+.endr
+.endm
+
+.macro movi_if reg, val, cond
+.if \cond
+        movi            \reg, \val
+.endif
+.endm
+
+.macro movz16dup_if reg, gpr, val, cond
+.if \cond
+        movz            \gpr, \val, lsl #16
+        dup             \reg, \gpr
+.endif
+.endm
+
+.macro st1_if regs, dst, cond
+.if \cond
+        st1             \regs, \dst
+.endif
+.endm
+
+.macro str_if reg, dst, cond
+.if \cond
+        str             \reg, \dst
+.endif
+.endm
+
+.macro stroff_if reg, dst, dstoff, cond
+.if \cond
+        str             \reg, \dst, \dstoff
+.endif
+.endm
+
+.macro scale_if cond, c, r0, r1, r2, r3, r4, r5, r6, r7
+.if \cond
+        scale_input     .4s, \c, \r0, \r1, \r2, \r3, \r4, \r5, \r6, \r7
+.endif
+.endm
+
+.macro def_dct64_func suffix, clear=0, scale=0
+function inv_txfm_dct\suffix\()_4s_x64_neon
+        mov             x14, x30
+        mov             x6,  sp
+        lsl             x8,  x8,  #2
+
+        movz16dup_if    v0.2s, w16, #2896*8, \scale
+        movi_if         v7.4s,  #0, \clear
+        load8           x7,  x8,  v7.4s, \clear
+        clear_upper8
+        sub             x7,  x7,  x8, lsl #3
+        add             x7,  x7,  x8, lsr #1
+        scale_if        \scale, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+
+        bl              inv_dct_4s_x16_neon
+
+        // idct_16 leaves the row_clip_max/min constants in v5 and v4
+.irp r, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31
+        smin_4s         \r, \r, v5
+.endr
+.irp r, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31
+        smax_4s         \r, \r, v4
+.endr
+
+        store16         x6
+
+        movz16dup_if    v0.2s, w16, #2896*8, \scale
+        movi_if         v7.8h,  #0, \clear
+        load8           x7,  x8,  v7.4s, \clear
+        clear_upper8
+        sub             x7,  x7,  x8, lsl #3
+        lsr             x8,  x8,  #1
+        sub             x7,  x7,  x8, lsr #1
+        scale_if        \scale, v0.s[0], v16, v17, v18, v19, v20, v21, v22, v23
+
+        bl              inv_dct32_odd_4s_x16_neon
+
+        add             x10, x6,  #16*15
+        sub             x6,  x6,  #16*16
+
+        mov             x9,  #-16
+
+        movi            v1.4s,  #1, msl #16 // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        mvni            v0.4s,  #1, msl #16 // row_clip_min = (~bdmax << 7), 0xfffe0000
+
+.macro store_addsub r0, r1, r2, r3
+        ld1             {v2.4s}, [x6], #16
+        ld1             {v3.4s}, [x6], #16
+        sqadd           v6.4s,  v2.4s,  \r0
+        sqsub           \r0,    v2.4s,  \r0
+        ld1             {v4.4s}, [x6], #16
+        sqadd           v7.4s,  v3.4s,  \r1
+        sqsub           \r1,    v3.4s,  \r1
+        smin            v6.4s,  v6.4s,  v1.4s
+        smin            \r0,    \r0,    v1.4s
+        ld1             {v5.4s}, [x6], #16
+        sqadd           v2.4s,  v4.4s,  \r2
+        sub             x6,  x6,  #16*4
+        smax            v6.4s,  v6.4s,  v0.4s
+        smax            \r0,    \r0,    v0.4s
+        sqsub           \r2,    v4.4s,  \r2
+        smin            v7.4s,  v7.4s,  v1.4s
+        smin            \r1,    \r1,    v1.4s
+        st1             {v6.4s}, [x6], #16
+        st1             {\r0},   [x10], x9
+        smin            v2.4s,  v2.4s,  v1.4s
+        smin            \r2,    \r2,    v1.4s
+        smax            v7.4s,  v7.4s,  v0.4s
+        smax            \r1,    \r1,    v0.4s
+        sqadd           v3.4s,  v5.4s,  \r3
+        sqsub           \r3,    v5.4s,  \r3
+        smax            v2.4s,  v2.4s,  v0.4s
+        smax            \r2,    \r2,    v0.4s
+        smin            v3.4s,  v3.4s,  v1.4s
+        smin            \r3,    \r3,    v1.4s
+        st1             {v7.4s}, [x6], #16
+        st1             {\r1},   [x10], x9
+        smax            v3.4s,  v3.4s,  v0.4s
+        smax            \r3,    \r3,    v0.4s
+        st1             {v2.4s}, [x6], #16
+        st1             {\r2},   [x10], x9
+        st1             {v3.4s}, [x6], #16
+        st1             {\r3},   [x10], x9
+.endm
+        store_addsub    v31.4s, v30.4s, v29.4s, v28.4s
+        store_addsub    v27.4s, v26.4s, v25.4s, v24.4s
+        store_addsub    v23.4s, v22.4s, v21.4s, v20.4s
+        store_addsub    v19.4s, v18.4s, v17.4s, v16.4s
+.purgem store_addsub
+
+        add             x6,  x6,  #4*4*16
+
+        movrel          x17, idct64_coeffs
+        movi            v5.4s,  #1, msl #16  // row_clip_max = ~(~bdmax << 7), 0x1ffff
+        mvni            v4.4s,  #1, msl #16  // row_clip_min = (~bdmax << 7), 0xfffe0000
+        movz16dup_if    v0.2s, w16, #2896*8, \scale
+        movi_if         v7.4s,  #0, \clear
+        add             x9,  x7,  x8, lsl #4 // offset 16
+        add             x10, x7,  x8, lsl #3 // offset 8
+        sub             x9,  x9,  x8         // offset 15
+        sub             x11, x10, x8         // offset 7
+        ld1             {v16.4s}, [x7]  // in1  (offset 0)
+        ld1             {v17.4s}, [x9]  // in31 (offset 15)
+        ld1             {v18.4s}, [x10] // in17 (offset 8)
+        ld1             {v19.4s}, [x11] // in15 (offset 7)
+        st1_if          {v7.4s}, [x7],  \clear
+        st1_if          {v7.4s}, [x9],  \clear
+        st1_if          {v7.4s}, [x10], \clear
+        st1_if          {v7.4s}, [x11], \clear
+        scale_if        \scale, v0.s[0], v16, v17, v18, v19
+        bl              inv_dct64_step1_neon
+        movz16dup_if    v0.2s, w16, #2896*8, \scale
+        movi_if         v7.4s,  #0, \clear
+        add             x7,  x7,  x8, lsl #2 // offset 4
+        sub             x9,  x9,  x8, lsl #2 // offset 11
+        sub             x10, x7,  x8         // offset 3
+        add             x11, x9,  x8         // offset 12
+        ld1             {v16.4s}, [x10] // in7  (offset 3)
+        ld1             {v17.4s}, [x11] // in25 (offset 12)
+        ld1             {v18.4s}, [x9]  // in23 (offset 11)
+        ld1             {v19.4s}, [x7]  // in9  (offset 4)
+        st1_if          {v7.4s}, [x7],  \clear
+        st1_if          {v7.4s}, [x9],  \clear
+        st1_if          {v7.4s}, [x10], \clear
+        st1_if          {v7.4s}, [x11], \clear
+        scale_if        \scale, v0.s[0], v16, v17, v18, v19
+        bl              inv_dct64_step1_neon
+        movz16dup_if    v0.2s, w16, #2896*8, \scale
+        movi_if         v7.4s,  #0, \clear
+        sub             x10, x10, x8, lsl #1 // offset 1
+        sub             x9,  x9,  x8, lsl #1 // offset 9
+        add             x7,  x7,  x8         // offset 5
+        add             x11, x11, x8         // offset 13
+        ldr             q16, [x10, x8] // in5  (offset 2)
+        ldr             q17, [x11]     // in27 (offset 13)
+        ldr             q18, [x9,  x8] // in21 (offset 10)
+        ldr             q19, [x7]      // in11 (offset 5)
+        stroff_if       q7,  [x10, x8], \clear
+        str_if          q7,  [x11],     \clear
+        stroff_if       q7,  [x9,  x8], \clear
+        str_if          q7,  [x7],      \clear
+        scale_if        \scale, v0.s[0], v16, v17, v18, v19
+        bl              inv_dct64_step1_neon
+        movz16dup_if    v0.2s, w16, #2896*8, \scale
+        movi_if         v7.4s,  #0, \clear
+        ldr             q16, [x10]     // in3  (offset 1)
+        ldr             q17, [x11, x8] // in29 (offset 14)
+        ldr             q18, [x9]      // in19 (offset 9)
+        ldr             q19, [x7,  x8] // in13 (offset 6)
+        str_if          q7,  [x10],     \clear
+        stroff_if       q7,  [x11, x8], \clear
+        str_if          q7,  [x9],      \clear
+        stroff_if       q7,  [x7,  x8], \clear
+        scale_if        \scale, v0.s[0], v16, v17, v18, v19
+        bl              inv_dct64_step1_neon
+
+        sub             x6,  x6,  #4*4*32
+        add             x9,  x6,  #4*4*7
+
+        bl              inv_dct64_step2_neon
+
+        ret             x14
+endfunc
+.endm
+
+def_dct64_func _clear, clear=1
+def_dct64_func _clear_scale, clear=1, scale=1
+
+
+function inv_txfm_horz_dct_64x4_neon
+        mov             x14, x30
+
+        mov             x7,  sp
+        add             x8,  sp,  #4*4*(64 - 4)
+        add             x9,  x6,  #2*56
+        mov             x10, #2*64
+        mov             x11, #-4*4*4
+
+        dup             v7.4s,  w12
+1:
+        ld1             {v16.4s, v17.4s, v18.4s, v19.4s}, [x7], #64
+        ld1             {v28.4s, v29.4s, v30.4s, v31.4s}, [x8], x11
+        ld1             {v20.4s, v21.4s, v22.4s, v23.4s}, [x7], #64
+        ld1             {v24.4s, v25.4s, v26.4s, v27.4s}, [x8], x11
+        transpose_4x4s  v16, v17, v18, v19, v2,  v3,  v4,  v5
+        transpose_4x4s  v20, v21, v22, v23, v2,  v3,  v4,  v5
+        transpose_4x4s  v31, v30, v29, v28, v2,  v3,  v4,  v5
+        transpose_4x4s  v27, v26, v25, v24, v2,  v3,  v4,  v5
+
+.macro store_addsub src0, src1, src2, src3
+        sqsub           v1.4s,   \src0,   \src1
+        sqadd           v0.4s,   \src0,   \src1
+        sqsub           v3.4s,   \src2,   \src3
+        srshl           v1.4s,   v1.4s,   v7.4s
+        sqadd           v2.4s,   \src2,   \src3
+        srshl           v3.4s,   v3.4s,   v7.4s
+        srshl           v0.4s,   v0.4s,   v7.4s
+        srshl           v2.4s,   v2.4s,   v7.4s
+        sqxtn           v3.4h,   v3.4s
+        sqxtn2          v3.8h,   v1.4s
+        sqxtn           v0.4h,   v0.4s
+        sqxtn2          v0.8h,   v2.4s
+        rev64           v3.8h,   v3.8h
+        st1             {v0.8h},  [x6], x10
+        st1             {v3.8h},  [x9], x10
+.endm
+        store_addsub    v16.4s,  v31.4s,  v20.4s,  v27.4s
+        store_addsub    v17.4s,  v30.4s,  v21.4s,  v26.4s
+        store_addsub    v18.4s,  v29.4s,  v22.4s,  v25.4s
+        store_addsub    v19.4s,  v28.4s,  v23.4s,  v24.4s
+.purgem store_addsub
+        sub             x6,  x6,  x10, lsl #2
+        sub             x9,  x9,  x10, lsl #2
+        add             x6,  x6,  #16
+        sub             x9,  x9,  #16
+
+        cmp             x7,  x8
+        b.lt            1b
+        ret             x14
+endfunc
+
+function inv_txfm_add_vert_dct_8x64_neon
+        mov             x14, x30
+        lsl             x8,  x8,  #1
+
+        mov             x7,  sp
+        add             x8,  sp,  #2*8*(64 - 4)
+        add             x9,  x6,  x1, lsl #6
+        sub             x9,  x9,  x1
+        neg             x10, x1
+        mov             x11, #-2*8*4
+
+1:
+        ld1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x7], #64
+        ld1             {v28.8h, v29.8h, v30.8h, v31.8h}, [x8], x11
+        ld1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x7], #64
+        ld1             {v24.8h, v25.8h, v26.8h, v27.8h}, [x8], x11
+
+        mvni            v7.8h,   #0xfc, lsl #8 // 0x3ff
+.macro add_dest_addsub src0, src1, src2, src3
+        ld1             {v0.8h}, [x6], x1
+        ld1             {v1.8h}, [x9], x10
+        sqadd           v4.8h,   \src0,   \src1
+        ld1             {v2.8h}, [x6]
+        sqsub           \src0,   \src0,   \src1
+        ld1             {v3.8h}, [x9]
+        sqadd           v5.8h,   \src2,   \src3
+        sqsub           \src2,   \src2,   \src3
+        sub             x6,  x6,  x1
+        sub             x9,  x9,  x10
+        srshr           v4.8h,   v4.8h,   #4
+        srshr           v5.8h,   v5.8h,   #4
+        srshr           \src0,   \src0,   #4
+        usqadd          v0.8h,   v4.8h
+        srshr           \src2,   \src2,   #4
+        usqadd          v1.8h,   \src0
+        usqadd          v2.8h,   v5.8h
+        smin            v0.8h,   v0.8h,   v7.8h
+        usqadd          v3.8h,   \src2
+        smin            v1.8h,   v1.8h,   v7.8h
+        st1             {v0.8h}, [x6], x1
+        smin            v2.8h,   v2.8h,   v7.8h
+        st1             {v1.8h}, [x9], x10
+        smin            v3.8h,   v3.8h,   v7.8h
+        st1             {v2.8h}, [x6], x1
+        st1             {v3.8h}, [x9], x10
+.endm
+        add_dest_addsub v16.8h,  v31.8h,  v17.8h,  v30.8h
+        add_dest_addsub v18.8h,  v29.8h,  v19.8h,  v28.8h
+        add_dest_addsub v20.8h,  v27.8h,  v21.8h,  v26.8h
+        add_dest_addsub v22.8h,  v25.8h,  v23.8h,  v24.8h
+.purgem add_dest_addsub
+        cmp             x7,  x8
+        b.lt            1b
+
+        ret             x14
+endfunc
+
+function inv_txfm_add_dct_dct_64x64_16bpc_neon, export=1
+        idct_dc         64,  64,  2
+
+        mov             x15, x30
+
+        sub_sp          64*32*2+64*4*4
+        add             x5,  sp, #64*4*4
+
+        movrel          x13, eob_32x32
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             x6,  x5,  #(\i*64*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.endif
+        add             x7,  x2,  #(\i*4)
+        mov             x8,  #32*4
+        mov             x12, #-2 // shift
+        bl              inv_txfm_dct_clear_4s_x64_neon
+        add             x6,  x5,  #(\i*64*2)
+        bl              inv_txfm_horz_dct_64x4_neon
+.if \i < 28
+        ldrh            w12, [x13], #2
+.endif
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #2
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24, 32, 40, 48, 56
+        add             x7,  x5,  #(\i*2)
+        mov             x8,  #64*2
+        bl              X(inv_txfm_dct_8h_x64_neon)
+        add             x6,  x0,  #(\i*2)
+        bl              inv_txfm_add_vert_dct_8x64_neon
+.endr
+
+        add             sp,  x5,  #64*32*2
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_64x32_16bpc_neon, export=1
+        idct_dc         64,  32,  1
+
+        mov             x15, x30
+
+        sub_sp          64*32*2+64*4*4
+        add             x5,  sp, #64*4*4
+
+        movrel          x13, eob_32x32
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             x6,  x5,  #(\i*64*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.endif
+        add             x7,  x2,  #(\i*4)
+        mov             x8,  #32*4
+        mov             x12, #-1 // shift
+        bl              inv_txfm_dct_clear_scale_4s_x64_neon
+        add             x6,  x5,  #(\i*64*2)
+        bl              inv_txfm_horz_dct_64x4_neon
+.if \i < 28
+        ldrh            w12, [x13], #2
+.endif
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #2
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24, 32, 40, 48, 56
+        add             x6,  x0,  #(\i*2)
+        add             x7,  x5,  #(\i*2)
+        mov             x8,  #64*2
+        bl              inv_txfm_add_vert_dct_8x32_neon
+.endr
+
+        add             sp,  x5,  #64*32*2
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_32x64_16bpc_neon, export=1
+        idct_dc         32,  64,  1
+
+        mov             x15, x30
+
+        sub_sp          32*32*2+64*8*2
+        add             x5,  sp, #64*8*2
+
+        movrel          x13, eob_32x32
+        ldrh            w12, [x13], #2
+
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             x6,  x5,  #(\i*32*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+        ldrh            w12, [x13], #2
+.endif
+        add             x7,  x2,  #(\i*4)
+        mov             x8,  #32*4
+        bl              inv_txfm_horz_scale_dct_32x4_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8, 16, 24
+        add             x7,  x5,  #(\i*2)
+        mov             x8,  #32*2
+        bl              X(inv_txfm_dct_8h_x64_neon)
+        add             x6,  x0,  #(\i*2)
+        bl              inv_txfm_add_vert_dct_8x64_neon
+.endr
+
+        add             sp,  x5,  #32*32*2
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_64x16_16bpc_neon, export=1
+        idct_dc         64,  16,  2
+
+        mov             x15, x30
+
+        sub_sp          64*16*2+64*4*4
+        add             x4,  sp, #64*4*4
+
+        movrel          x13, eob_16x32
+
+.irp i, 0, 4, 8, 12
+        add             x6,  x4,  #(\i*64*2)
+.if \i > 0
+        mov             w8,  #(16 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.endif
+        add             x7,  x2,  #(\i*4)
+        mov             x8,  #16*4
+        mov             x12, #-2 // shift
+        bl              inv_txfm_dct_clear_4s_x64_neon
+        add             x6,  x4,  #(\i*64*2)
+        bl              inv_txfm_horz_dct_64x4_neon
+.if \i < 12
+        ldrh            w12, [x13], #2
+.endif
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #2
+.rept 4
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+        movrel          x5,  X(inv_dct_8h_x16_neon)
+.irp i, 0, 8, 16, 24, 32, 40, 48, 56
+        add             x6,  x0,  #(\i*2)
+        add             x7,  x4,  #(\i*2)
+        mov             x8,  #64*2
+        bl              inv_txfm_add_vert_8x16_neon
+.endr
+
+        add             sp,  x4,  #64*16*2
+        ret             x15
+endfunc
+
+function inv_txfm_add_dct_dct_16x64_16bpc_neon, export=1
+        idct_dc         16,  64,  2
+
+        mov             x15, x30
+
+        sub_sp          16*32*2+64*8*2
+        add             x5,  sp, #64*8*2
+
+        movrel          x13, eob_16x32
+        ldrh            w12, [x13], #2
+
+        adr             x4,  inv_dct_4s_x16_neon
+.irp i, 0, 4, 8, 12, 16, 20, 24, 28
+        add             x6,  x5,  #(\i*16*2)
+.if \i > 0
+        mov             w8,  #(32 - \i)
+        cmp             w3,  w12
+        b.lt            1f
+.if \i < 28
+        ldrh            w12, [x13], #2
+.endif
+.endif
+        add             x7,  x2,  #(\i*4)
+        mov             x8,  #32*4
+        bl              inv_txfm_horz_16x4_neon
+.endr
+        b               3f
+
+1:
+        movi            v4.8h,  #0
+        movi            v5.8h,  #0
+        movi            v6.8h,  #0
+        movi            v7.8h,  #0
+2:
+        subs            w8,  w8,  #4
+.rept 2
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x6], #64
+.endr
+        b.gt            2b
+
+3:
+.irp i, 0, 8
+        add             x7,  x5,  #(\i*2)
+        mov             x8,  #16*2
+        bl              X(inv_txfm_dct_8h_x64_neon)
+        add             x6,  x0,  #(\i*2)
+        bl              inv_txfm_add_vert_dct_8x64_neon
+.endr
+
+        add             sp,  x5,  #16*32*2
+        ret             x15
+endfunc
diff --git a/media/libdav1d/src/src/arm/64/loopfilter.S b/media/libdav1d/src/src/arm/64/loopfilter.S
new file mode 100644
index 0000000000..63d5de10ad
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/loopfilter.S
@@ -0,0 +1,1129 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// depending on how many pixels need to be stored, returns:
+// x14 = (1 << 0) : 0 pixels
+// x14 = (1 << 4) : inner 4 pixels
+// x14 = (1 << 6) : inner 6 pixels
+// x14 = 0 : all pixels
+.macro loop_filter wd
+function lpf_16_wd\wd\()_neon
+        uabd            v0.16b,  v22.16b, v23.16b // abs(p1 - p0)
+        uabd            v1.16b,  v25.16b, v24.16b // abs(q1 - q0)
+        uabd            v2.16b,  v23.16b, v24.16b // abs(p0 - q0)
+        uabd            v3.16b,  v22.16b, v25.16b // abs(p1 - q1)
+.if \wd >= 6
+        uabd            v4.16b,  v21.16b, v22.16b // abs(p2 - p1)
+        uabd            v5.16b,  v26.16b, v25.16b // abs(q2 - q1)
+.endif
+.if \wd >= 8
+        uabd            v6.16b,  v20.16b, v21.16b // abs(p3 - p2)
+        uabd            v7.16b,  v27.16b, v26.16b // abs(q3 - q3)
+.endif
+.if \wd >= 6
+        umax            v4.16b,  v4.16b,  v5.16b
+.endif
+        uqadd           v2.16b,  v2.16b,  v2.16b  // abs(p0 - q0) * 2
+.if \wd >= 8
+        umax            v6.16b,  v6.16b,  v7.16b
+.endif
+        ushr            v3.16b,  v3.16b,  #1
+.if \wd >= 8
+        umax            v4.16b,  v4.16b,  v6.16b
+.endif
+.if \wd >= 6
+        and             v4.16b,  v4.16b,  v14.16b
+.endif
+        umax            v0.16b,  v0.16b,  v1.16b  // max(abs(p1 - p0), abs(q1 - q0))
+        uqadd           v2.16b,  v2.16b,  v3.16b  // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
+.if \wd >= 6
+        umax            v4.16b,  v0.16b,  v4.16b
+        cmhs            v1.16b,  v11.16b, v4.16b  // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
+.else
+        cmhs            v1.16b,  v11.16b, v0.16b  // max(abs(p1 - p0), abs(q1 - q0)) <= I
+.endif
+        cmhs            v2.16b,  v10.16b, v2.16b  // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
+        and             v1.16b,  v1.16b,  v2.16b  // fm
+        and             v1.16b,  v1.16b,  v13.16b // fm && wd >= 4
+.if \wd >= 6
+        and             v14.16b, v14.16b, v1.16b  // fm && wd > 4
+.endif
+.if \wd >= 16
+        and             v15.16b, v15.16b, v1.16b  // fm && wd == 16
+.endif
+
+        mov             x16, v1.d[0]
+        mov             x17, v1.d[1]
+        adds            x16, x16, x17
+        b.ne            9f                        // if (!fm || wd < 4) return;
+        mov             x14, #(1 << 0)
+        ret
+9:
+.if \wd >= 6
+        movi            v10.16b, #1
+        uabd            v2.16b,  v21.16b, v23.16b // abs(p2 - p0)
+        uabd            v3.16b,  v22.16b, v23.16b // abs(p1 - p0)
+        uabd            v4.16b,  v25.16b, v24.16b // abs(q1 - q0)
+        uabd            v5.16b,  v26.16b, v24.16b // abs(q2 - q0)
+.if \wd >= 8
+        uabd            v6.16b,  v20.16b, v23.16b // abs(p3 - p0)
+        uabd            v7.16b,  v27.16b, v24.16b // abs(q3 - q0)
+.endif
+        umax            v2.16b,  v2.16b,  v3.16b
+        umax            v4.16b,  v4.16b,  v5.16b
+.if \wd >= 8
+        umax            v6.16b,  v6.16b,  v7.16b
+.endif
+        umax            v2.16b,  v2.16b,  v4.16b
+.if \wd >= 8
+        umax            v2.16b,  v2.16b,  v6.16b
+.endif
+
+.if \wd == 16
+        uabd            v3.16b,  v17.16b, v23.16b // abs(p6 - p0)
+        uabd            v4.16b,  v18.16b, v23.16b // abs(p5 - p0)
+        uabd            v5.16b,  v19.16b, v23.16b // abs(p4 - p0)
+.endif
+        cmhs            v2.16b,  v10.16b, v2.16b  // flat8in
+.if \wd == 16
+        uabd            v6.16b,  v28.16b, v24.16b // abs(q4 - q0)
+        uabd            v7.16b,  v29.16b, v24.16b // abs(q5 - q0)
+        uabd            v8.16b,  v30.16b, v24.16b // abs(q6 - q0)
+.endif
+        and             v14.16b, v2.16b,  v14.16b // flat8in && fm && wd > 4
+        bic             v1.16b,  v1.16b,  v14.16b // fm && wd >= 4 && !flat8in
+.if \wd == 16
+        umax            v3.16b,  v3.16b,  v4.16b
+        umax            v5.16b,  v5.16b,  v6.16b
+.endif
+        mov             x16, v1.d[0]
+        mov             x17, v1.d[1]
+.if \wd == 16
+        umax            v7.16b,  v7.16b,  v8.16b
+        umax            v3.16b,  v3.16b,  v5.16b
+        umax            v3.16b,  v3.16b,  v7.16b
+        cmhs            v3.16b,  v10.16b, v3.16b  // flat8out
+.endif
+        adds            x16, x16, x17
+.if \wd == 16
+        and             v15.16b, v15.16b, v3.16b  // flat8out && fm && wd == 16
+        and             v15.16b, v15.16b, v14.16b // flat8out && flat8in && fm && wd == 16
+        bic             v14.16b, v14.16b, v15.16b // flat8in && fm && wd >= 4 && !flat8out
+.endif
+        b.eq            1f                        // skip wd == 4 case
+.endif
+        movi            v3.16b,  #128
+        eor             v2.16b,  v22.16b, v3.16b  // p1 - 128
+        eor             v3.16b,  v25.16b, v3.16b  // q1 - 128
+        cmhi            v0.16b,  v0.16b,  v12.16b // hev
+        sqsub           v2.16b,  v2.16b,  v3.16b  // iclip_diff(p1 - q1)
+        and             v4.16b,  v2.16b,  v0.16b  // if (hev) iclip_diff(p1 - q1)
+        bic             v0.16b,  v1.16b,  v0.16b  // (fm && wd >= 4 && !hev)
+        usubl           v2.8h,   v24.8b,  v23.8b
+        movi            v5.8h,   #3
+        usubl2          v3.8h,   v24.16b, v23.16b
+        mul             v2.8h,   v2.8h,   v5.8h
+        mul             v3.8h,   v3.8h,   v5.8h
+        movi            v6.16b,  #4
+        saddw           v2.8h,   v2.8h,   v4.8b
+        saddw2          v3.8h,   v3.8h,   v4.16b
+        movi            v7.16b,  #3
+        sqxtn           v2.8b,   v2.8h            // f
+        sqxtn2          v2.16b,  v3.8h
+        sqadd           v4.16b,  v6.16b,  v2.16b  // imin(f + 4, 127)
+        sqadd           v5.16b,  v7.16b,  v2.16b  // imin(f + 3, 127)
+        sshr            v4.16b,  v4.16b,  #3      // f1
+        sshr            v5.16b,  v5.16b,  #3      // f2
+        mov             v2.16b,  v23.16b          // p0
+        mov             v3.16b,  v24.16b          // q0
+        neg             v6.16b,  v4.16b           // -f1
+        srshr           v4.16b,  v4.16b,  #1      // (f1 + 1) >> 1
+        // p0 + f2, q0 - f1
+        usqadd          v2.16b,  v5.16b           // out p0
+        usqadd          v3.16b,  v6.16b           // out q0
+        neg             v6.16b,  v4.16b           // -((f1 + 1) >> 1)
+        bit             v23.16b, v2.16b,  v1.16b  // if (fm && wd >= 4)
+        bit             v24.16b, v3.16b,  v1.16b  // if (fm && wd >= 4)
+        mov             v2.16b,  v22.16b          // p1
+        mov             v3.16b,  v25.16b          // q1
+        // p1 + ((f1 + 1) >> 1), q1 - ((f1 + 1) >> 1)
+        usqadd          v2.16b,  v4.16b           // out p1
+        usqadd          v3.16b,  v6.16b           // out q1
+        bit             v22.16b, v2.16b,  v0.16b  // if (fm && wd >= 4 && !hev)
+        bit             v25.16b, v3.16b,  v0.16b  // if (fm && wd >= 4 && !hev)
+1:
+
+.if \wd == 6
+        mov             x16, v14.d[0]
+        mov             x17, v14.d[1]
+        adds            x16, x16, x17
+        b.eq            2f                        // skip if there's no flat8in
+
+        uaddl           v0.8h,   v21.8b,  v21.8b  // p2 * 2
+        uaddl2          v1.8h,   v21.16b, v21.16b
+        uaddl           v2.8h,   v21.8b,  v22.8b  // p2 + p1
+        uaddl2          v3.8h,   v21.16b, v22.16b
+        uaddl           v4.8h,   v22.8b,  v23.8b  // p1 + p0
+        uaddl2          v5.8h,   v22.16b, v23.16b
+        uaddl           v6.8h,   v23.8b,  v24.8b  // p0 + q0
+        uaddl2          v7.8h,   v23.16b, v24.16b
+        add             v8.8h,   v0.8h,   v2.8h
+        add             v9.8h,   v1.8h,   v3.8h
+        add             v10.8h,  v4.8h,   v6.8h
+        add             v11.8h,  v5.8h,   v7.8h
+        uaddl           v12.8h,  v24.8b,  v25.8b  // q0 + q1
+        uaddl2          v13.8h,  v24.16b, v25.16b
+        add             v8.8h,   v8.8h,   v10.8h
+        add             v9.8h,   v9.8h,   v11.8h
+        sub             v12.8h,  v12.8h,  v0.8h
+        sub             v13.8h,  v13.8h,  v1.8h
+        uaddl           v10.8h,  v25.8b,  v26.8b  // q1 + q2
+        uaddl2          v11.8h,  v25.16b, v26.16b
+        rshrn           v0.8b,   v8.8h,   #3      // out p1
+        rshrn2          v0.16b,  v9.8h,   #3
+
+        add             v8.8h,   v8.8h,   v12.8h
+        add             v9.8h,   v9.8h,   v13.8h
+        sub             v10.8h,  v10.8h,  v2.8h
+        sub             v11.8h,  v11.8h,  v3.8h
+        uaddl           v12.8h,  v26.8b,  v26.8b  // q2 + q2
+        uaddl2          v13.8h,  v26.16b, v26.16b
+        rshrn           v1.8b,   v8.8h,   #3      // out p0
+        rshrn2          v1.16b,  v9.8h,   #3
+
+        add             v8.8h,   v8.8h,   v10.8h
+        add             v9.8h,   v9.8h,   v11.8h
+        sub             v12.8h,  v12.8h,  v4.8h
+        sub             v13.8h,  v13.8h,  v5.8h
+        rshrn           v2.8b,   v8.8h,   #3      // out q0
+        rshrn2          v2.16b,  v9.8h,   #3
+
+        bit             v22.16b, v0.16b,  v14.16b // p1 if (flat8in)
+        add             v8.8h,   v8.8h,   v12.8h
+        add             v9.8h,   v9.8h,   v13.8h
+        bit             v23.16b, v1.16b,  v14.16b // p0 if (flat8in)
+        rshrn           v3.8b,   v8.8h,   #3      // out q1
+        rshrn2          v3.16b,  v9.8h,   #3
+        bit             v24.16b, v2.16b,  v14.16b // q0 if (flat8in)
+        bit             v25.16b, v3.16b,  v14.16b // q1 if (flat8in)
+.elseif \wd >= 8
+        mov             x16, v14.d[0]
+        mov             x17, v14.d[1]
+        adds            x16, x16, x17
+.if \wd == 8
+        b.eq            8f                        // skip if there's no flat8in
+.else
+        b.eq            2f                        // skip if there's no flat8in
+.endif
+
+        uaddl           v0.8h,   v20.8b,  v21.8b  // p3 + p2
+        uaddl2          v1.8h,   v20.16b, v21.16b
+        uaddl           v2.8h,   v22.8b,  v25.8b  // p1 + q1
+        uaddl2          v3.8h,   v22.16b, v25.16b
+        uaddl           v4.8h,   v20.8b,  v22.8b  // p3 + p1
+        uaddl2          v5.8h,   v20.16b, v22.16b
+        uaddl           v6.8h,   v23.8b,  v26.8b  // p0 + q2
+        uaddl2          v7.8h,   v23.16b, v26.16b
+        add             v8.8h,   v0.8h,   v0.8h   // 2 * (p3 + p2)
+        add             v9.8h,   v1.8h,   v1.8h
+        uaddw           v8.8h,   v8.8h,   v23.8b  // + p0
+        uaddw2          v9.8h,   v9.8h,   v23.16b
+        uaddw           v8.8h,   v8.8h,   v24.8b  // + q0
+        uaddw2          v9.8h,   v9.8h,   v24.16b
+        add             v8.8h,   v8.8h,   v4.8h
+        add             v9.8h,   v9.8h,   v5.8h   // + p3 + p1
+        sub             v2.8h,   v2.8h,   v0.8h   // p1 + q1 - p3 - p2
+        sub             v3.8h,   v3.8h,   v1.8h
+        sub             v6.8h,   v6.8h,   v4.8h   // p0 + q2 - p3 - p1
+        sub             v7.8h,   v7.8h,   v5.8h
+        rshrn           v10.8b,  v8.8h,   #3      // out p2
+        rshrn2          v10.16b, v9.8h,   #3
+
+        add             v8.8h,   v8.8h,   v2.8h
+        add             v9.8h,   v9.8h,   v3.8h
+        uaddl           v0.8h,   v20.8b,  v23.8b  // p3 + p0
+        uaddl2          v1.8h,   v20.16b, v23.16b
+        uaddl           v2.8h,   v24.8b,  v27.8b  // q0 + q3
+        uaddl2          v3.8h,   v24.16b, v27.16b
+        rshrn           v11.8b,  v8.8h,   #3      // out p1
+        rshrn2          v11.16b, v9.8h,   #3
+
+        add             v8.8h,   v8.8h,   v6.8h
+        add             v9.8h,   v9.8h,   v7.8h
+        sub             v2.8h,   v2.8h,   v0.8h   // q0 + q3 - p3 - p0
+        sub             v3.8h,   v3.8h,   v1.8h
+        uaddl           v4.8h,   v21.8b,  v24.8b  // p2 + q0
+        uaddl2          v5.8h,   v21.16b, v24.16b
+        uaddl           v6.8h,   v25.8b,  v27.8b  // q1 + q3
+        uaddl2          v7.8h,   v25.16b, v27.16b
+        rshrn           v12.8b,  v8.8h,   #3      // out p0
+        rshrn2          v12.16b, v9.8h,   #3
+
+        add             v8.8h,   v8.8h,   v2.8h
+        add             v9.8h,   v9.8h,   v3.8h
+        sub             v6.8h,   v6.8h,   v4.8h   // q1 + q3 - p2 - q0
+        sub             v7.8h,   v7.8h,   v5.8h
+        uaddl           v0.8h,   v22.8b,  v25.8b  // p1 + q1
+        uaddl2          v1.8h,   v22.16b, v25.16b
+        uaddl           v2.8h,   v26.8b,  v27.8b  // q2 + q3
+        uaddl2          v3.8h,   v26.16b, v27.16b
+        rshrn           v13.8b,  v8.8h,   #3      // out q0
+        rshrn2          v13.16b, v9.8h,   #3
+
+        add             v8.8h,   v8.8h,   v6.8h
+        add             v9.8h,   v9.8h,   v7.8h
+        sub             v2.8h,   v2.8h,   v0.8h   // q2 + q3 - p1 - q1
+        sub             v3.8h,   v3.8h,   v1.8h
+        rshrn           v0.8b,   v8.8h,   #3      // out q1
+        rshrn2          v0.16b,  v9.8h,   #3
+
+        add             v8.8h,   v8.8h,   v2.8h
+        add             v9.8h ,  v9.8h,   v3.8h
+
+        bit             v21.16b, v10.16b, v14.16b
+        bit             v22.16b, v11.16b, v14.16b
+        bit             v23.16b, v12.16b, v14.16b
+        rshrn           v1.8b,   v8.8h,   #3      // out q2
+        rshrn2          v1.16b,  v9.8h,   #3
+        bit             v24.16b, v13.16b, v14.16b
+        bit             v25.16b, v0.16b,  v14.16b
+        bit             v26.16b, v1.16b,  v14.16b
+.endif
+2:
+.if \wd == 16
+        mov             x16, v15.d[0]
+        mov             x17, v15.d[1]
+        adds            x16, x16, x17
+        b.ne            1f                        // check if flat8out is needed
+        mov             x16, v14.d[0]
+        mov             x17, v14.d[1]
+        adds            x16, x16, x17
+        b.eq            8f                        // if there was no flat8in, just write the inner 4 pixels
+        b               7f                        // if flat8in was used, write the inner 6 pixels
+1:
+
+        uaddl           v2.8h,   v17.8b,  v17.8b  // p6 + p6
+        uaddl2          v3.8h,   v17.16b, v17.16b
+        uaddl           v4.8h,   v17.8b,  v18.8b  // p6 + p5
+        uaddl2          v5.8h,   v17.16b, v18.16b
+        uaddl           v6.8h,   v17.8b,  v19.8b  // p6 + p4
+        uaddl2          v7.8h,   v17.16b, v19.16b
+        uaddl           v8.8h,   v17.8b,  v20.8b  // p6 + p3
+        uaddl2          v9.8h,   v17.16b, v20.16b
+        add             v12.8h,  v2.8h,   v4.8h
+        add             v13.8h,  v3.8h,   v5.8h
+        add             v10.8h,  v6.8h,   v8.8h
+        add             v11.8h,  v7.8h,   v9.8h
+        uaddl           v6.8h,   v17.8b,  v21.8b  // p6 + p2
+        uaddl2          v7.8h,   v17.16b, v21.16b
+        add             v12.8h,  v12.8h,  v10.8h
+        add             v13.8h,  v13.8h,  v11.8h
+        uaddl           v8.8h,   v17.8b,  v22.8b  // p6 + p1
+        uaddl2          v9.8h,   v17.16b, v22.16b
+        uaddl           v10.8h,  v18.8b,  v23.8b  // p5 + p0
+        uaddl2          v11.8h,  v18.16b, v23.16b
+        add             v6.8h,   v6.8h,   v8.8h
+        add             v7.8h,   v7.8h,   v9.8h
+        uaddl           v8.8h,   v19.8b,  v24.8b  // p4 + q0
+        uaddl2          v9.8h,   v19.16b, v24.16b
+        add             v12.8h,  v12.8h,  v6.8h
+        add             v13.8h,  v13.8h,  v7.8h
+        add             v10.8h,  v10.8h,  v8.8h
+        add             v11.8h,  v11.8h,  v9.8h
+        uaddl           v6.8h,   v20.8b,  v25.8b  // p3 + q1
+        uaddl2          v7.8h,   v20.16b, v25.16b
+        add             v12.8h,  v12.8h,  v10.8h
+        add             v13.8h,  v13.8h,  v11.8h
+        sub             v6.8h,   v6.8h,   v2.8h
+        sub             v7.8h,   v7.8h,   v3.8h
+        uaddl           v2.8h,   v21.8b,  v26.8b  // p2 + q2
+        uaddl2          v3.8h,   v21.16b, v26.16b
+        rshrn           v0.8b,   v12.8h,  #4      // out p5
+        rshrn2          v0.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v6.8h   // - (p6 + p6) + (p3 + q1)
+        add             v13.8h,  v13.8h,  v7.8h
+        sub             v2.8h,   v2.8h,   v4.8h
+        sub             v3.8h,   v3.8h,   v5.8h
+        uaddl           v4.8h,   v22.8b,  v27.8b  // p1 + q3
+        uaddl2          v5.8h,   v22.16b, v27.16b
+        uaddl           v6.8h,   v17.8b,  v19.8b  // p6 + p4
+        uaddl2          v7.8h,   v17.16b, v19.16b
+        rshrn           v1.8b,   v12.8h,  #4      // out p4
+        rshrn2          v1.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v2.8h   // - (p6 + p5) + (p2 + q2)
+        add             v13.8h,  v13.8h,  v3.8h
+        sub             v4.8h,   v4.8h,   v6.8h
+        sub             v5.8h,   v5.8h,   v7.8h
+        uaddl           v6.8h,   v23.8b,  v28.8b  // p0 + q4
+        uaddl2          v7.8h,   v23.16b, v28.16b
+        uaddl           v8.8h,   v17.8b,  v20.8b  // p6 + p3
+        uaddl2          v9.8h,   v17.16b, v20.16b
+        rshrn           v2.8b,   v12.8h,  #4      // out p3
+        rshrn2          v2.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v4.8h   // - (p6 + p4) + (p1 + q3)
+        add             v13.8h,  v13.8h,  v5.8h
+        sub             v6.8h,   v6.8h,   v8.8h
+        sub             v7.8h,   v7.8h,   v9.8h
+        uaddl           v8.8h,   v24.8b,  v29.8b  // q0 + q5
+        uaddl2          v9.8h,   v24.16b, v29.16b
+        uaddl           v4.8h,   v17.8b,  v21.8b  // p6 + p2
+        uaddl2          v5.8h,   v17.16b, v21.16b
+        rshrn           v3.8b,   v12.8h,  #4      // out p2
+        rshrn2          v3.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v6.8h   // - (p6 + p3) + (p0 + q4)
+        add             v13.8h,  v13.8h,  v7.8h
+        sub             v8.8h,   v8.8h,   v4.8h
+        sub             v9.8h,   v9.8h,   v5.8h
+        uaddl           v6.8h,   v25.8b,  v30.8b  // q1 + q6
+        uaddl2          v7.8h,   v25.16b, v30.16b
+        uaddl           v10.8h,  v17.8b,  v22.8b  // p6 + p1
+        uaddl2          v11.8h,  v17.16b, v22.16b
+        rshrn           v4.8b,   v12.8h,  #4      // out p1
+        rshrn2          v4.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v8.8h   // - (p6 + p2) + (q0 + q5)
+        add             v13.8h,  v13.8h,  v9.8h
+        sub             v6.8h,   v6.8h,   v10.8h
+        sub             v7.8h,   v7.8h,   v11.8h
+        uaddl           v8.8h,   v26.8b,  v30.8b  // q2 + q6
+        uaddl2          v9.8h,   v26.16b, v30.16b
+        bif             v0.16b,  v18.16b, v15.16b // out p5
+        uaddl           v10.8h,  v18.8b,  v23.8b  // p5 + p0
+        uaddl2          v11.8h,  v18.16b, v23.16b
+        rshrn           v5.8b,   v12.8h,  #4      // out p0
+        rshrn2          v5.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v6.8h   // - (p6 + p1) + (q1 + q6)
+        add             v13.8h,  v13.8h,  v7.8h
+        sub             v8.8h,   v8.8h,   v10.8h
+        sub             v9.8h,   v9.8h,   v11.8h
+        uaddl           v10.8h,  v27.8b,  v30.8b  // q3 + q6
+        uaddl2          v11.8h,  v27.16b, v30.16b
+        bif             v1.16b,  v19.16b, v15.16b // out p4
+        uaddl           v18.8h,  v19.8b,  v24.8b  // p4 + q0
+        uaddl2          v19.8h,  v19.16b, v24.16b
+        rshrn           v6.8b,   v12.8h,  #4      // out q0
+        rshrn2          v6.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v8.8h   // - (p5 + p0) + (q2 + q6)
+        add             v13.8h,  v13.8h,  v9.8h
+        sub             v10.8h,  v10.8h,  v18.8h
+        sub             v11.8h,  v11.8h,  v19.8h
+        uaddl           v8.8h,   v28.8b,  v30.8b  // q4 + q6
+        uaddl2          v9.8h,   v28.16b, v30.16b
+        bif             v2.16b,  v20.16b, v15.16b // out p3
+        uaddl           v18.8h,  v20.8b,  v25.8b  // p3 + q1
+        uaddl2          v19.8h,  v20.16b, v25.16b
+        rshrn           v7.8b,   v12.8h,  #4      // out q1
+        rshrn2          v7.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v10.8h  // - (p4 + q0) + (q3 + q6)
+        add             v13.8h,  v13.8h,  v11.8h
+        sub             v18.8h,  v8.8h,   v18.8h
+        sub             v19.8h,  v9.8h,   v19.8h
+        uaddl           v10.8h,  v29.8b,  v30.8b  // q5 + q6
+        uaddl2          v11.8h,  v29.16b, v30.16b
+        bif             v3.16b,  v21.16b, v15.16b // out p2
+        uaddl           v20.8h,  v21.8b,  v26.8b  // p2 + q2
+        uaddl2          v21.8h,  v21.16b, v26.16b
+        rshrn           v8.8b,   v12.8h,  #4      // out q2
+        rshrn2          v8.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v18.8h  // - (p3 + q1) + (q4 + q6)
+        add             v13.8h,  v13.8h,  v19.8h
+        sub             v10.8h,  v10.8h,  v20.8h
+        sub             v11.8h,  v11.8h,  v21.8h
+        uaddl           v18.8h,  v30.8b,  v30.8b  // q6 + q6
+        uaddl2          v19.8h,  v30.16b, v30.16b
+        bif             v4.16b,  v22.16b, v15.16b // out p1
+        uaddl           v20.8h,  v22.8b,  v27.8b  // p1 + q3
+        uaddl2          v21.8h,  v22.16b, v27.16b
+        rshrn           v9.8b,   v12.8h,  #4      // out q3
+        rshrn2          v9.16b,  v13.8h,  #4
+        add             v12.8h,  v12.8h,  v10.8h  // - (p2 + q2) + (q5 + q6)
+        add             v13.8h,  v13.8h,  v11.8h
+        sub             v18.8h,  v18.8h,  v20.8h
+        sub             v19.8h,  v19.8h,  v21.8h
+        bif             v5.16b,  v23.16b, v15.16b // out p0
+        rshrn           v10.8b,  v12.8h,  #4      // out q4
+        rshrn2          v10.16b, v13.8h,  #4
+        add             v12.8h,  v12.8h,  v18.8h  // - (p1 + q3) + (q6 + q6)
+        add             v13.8h,  v13.8h,  v19.8h
+        rshrn           v11.8b,  v12.8h,  #4      // out q5
+        rshrn2          v11.16b, v13.8h,  #4
+        bif             v6.16b,  v24.16b, v15.16b // out q0
+        bif             v7.16b,  v25.16b, v15.16b // out q1
+        bif             v8.16b,  v26.16b, v15.16b // out q2
+        bif             v9.16b,  v27.16b, v15.16b // out q3
+        bif             v10.16b, v28.16b, v15.16b // out q4
+        bif             v11.16b, v29.16b, v15.16b // out q5
+.endif
+
+        mov             x14, #0
+        ret
+.if \wd == 16
+7:
+        // Return to a shorter epilogue, writing only the inner 6 pixels
+        mov             x14, #(1 << 6)
+        ret
+.endif
+.if \wd >= 8
+8:
+        // Return to a shorter epilogue, writing only the inner 4 pixels
+        mov             x14, #(1 << 4)
+        ret
+.endif
+endfunc
+.endm
+
+loop_filter 16
+loop_filter 8
+loop_filter 6
+loop_filter 4
+
+.macro lpf_16_wd16
+        bl              lpf_16_wd16_neon
+        cbz             x14, 1f
+        tbnz            x14, #6, 7f
+        tbnz            x14, #4, 8f
+        ret             x15
+1:
+.endm
+
+.macro lpf_16_wd8
+        bl              lpf_16_wd8_neon
+        cbz             x14, 1f
+        tbnz            x14, #4, 8f
+        ret             x15
+1:
+.endm
+
+.macro lpf_16_wd6
+        bl              lpf_16_wd6_neon
+        cbz             x14, 1f
+        ret             x15
+1:
+.endm
+
+.macro lpf_16_wd4
+        bl              lpf_16_wd4_neon
+        cbz             x14, 1f
+        ret             x15
+1:
+.endm
+
+function lpf_v_4_16_neon
+        mov             x15, x30
+        sub             x16, x0,  x1, lsl #1
+        ld1             {v22.16b}, [x16], x1 // p1
+        ld1             {v24.16b}, [x0],  x1 // q0
+        ld1             {v23.16b}, [x16], x1 // p0
+        ld1             {v25.16b}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+
+        lpf_16_wd4
+
+        sub             x16, x0,  x1, lsl #1
+        st1             {v22.16b}, [x16], x1 // p1
+        st1             {v24.16b}, [x0],  x1 // q0
+        st1             {v23.16b}, [x16], x1 // p0
+        st1             {v25.16b}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+endfunc
+
+function lpf_h_4_16_neon
+        mov             x15, x30
+        sub             x16, x0,  #2
+        add             x0,  x16, x1, lsl #3
+        ld1             {v22.s}[0], [x16], x1
+        ld1             {v22.s}[2], [x0],  x1
+        ld1             {v23.s}[0], [x16], x1
+        ld1             {v23.s}[2], [x0],  x1
+        ld1             {v24.s}[0], [x16], x1
+        ld1             {v24.s}[2], [x0],  x1
+        ld1             {v25.s}[0], [x16], x1
+        ld1             {v25.s}[2], [x0],  x1
+        ld1             {v22.s}[1], [x16], x1
+        ld1             {v22.s}[3], [x0],  x1
+        ld1             {v23.s}[1], [x16], x1
+        ld1             {v23.s}[3], [x0],  x1
+        ld1             {v24.s}[1], [x16], x1
+        ld1             {v24.s}[3], [x0],  x1
+        ld1             {v25.s}[1], [x16], x1
+        ld1             {v25.s}[3], [x0],  x1
+        add             x0,  x0,  #2
+
+        transpose_4x16b v22, v23, v24, v25, v26, v27, v28, v29
+
+        lpf_16_wd4
+
+        sub             x16, x0,  x1, lsl #4
+        sub             x16, x16, #2
+        transpose_4x16b v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #3
+
+        st1             {v22.s}[0], [x16], x1
+        st1             {v22.s}[2], [x0],  x1
+        st1             {v23.s}[0], [x16], x1
+        st1             {v23.s}[2], [x0],  x1
+        st1             {v24.s}[0], [x16], x1
+        st1             {v24.s}[2], [x0],  x1
+        st1             {v25.s}[0], [x16], x1
+        st1             {v25.s}[2], [x0],  x1
+        st1             {v22.s}[1], [x16], x1
+        st1             {v22.s}[3], [x0],  x1
+        st1             {v23.s}[1], [x16], x1
+        st1             {v23.s}[3], [x0],  x1
+        st1             {v24.s}[1], [x16], x1
+        st1             {v24.s}[3], [x0],  x1
+        st1             {v25.s}[1], [x16], x1
+        st1             {v25.s}[3], [x0],  x1
+        add             x0,  x0,  #2
+        ret             x15
+endfunc
+
+function lpf_v_6_16_neon
+        mov             x15, x30
+        sub             x16, x0,  x1, lsl #1
+        sub             x16, x16, x1
+        ld1             {v21.16b}, [x16], x1 // p2
+        ld1             {v24.16b}, [x0],  x1 // q0
+        ld1             {v22.16b}, [x16], x1 // p1
+        ld1             {v25.16b}, [x0],  x1 // q1
+        ld1             {v23.16b}, [x16], x1 // p0
+        ld1             {v26.16b}, [x0],  x1 // q2
+        sub             x0,  x0,  x1, lsl #1
+        sub             x0,  x0,  x1
+
+        lpf_16_wd6
+
+        sub             x16, x0,  x1, lsl #1
+        st1             {v22.16b}, [x16], x1 // p1
+        st1             {v24.16b}, [x0],  x1 // q0
+        st1             {v23.16b}, [x16], x1 // p0
+        st1             {v25.16b}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+endfunc
+
+function lpf_h_6_16_neon
+        mov             x15, x30
+        sub             x16, x0,  #4
+        add             x0,  x16, x1, lsl #3
+        ld1             {v20.d}[0], [x16], x1
+        ld1             {v20.d}[1], [x0],  x1
+        ld1             {v21.d}[0], [x16], x1
+        ld1             {v21.d}[1], [x0],  x1
+        ld1             {v22.d}[0], [x16], x1
+        ld1             {v22.d}[1], [x0],  x1
+        ld1             {v23.d}[0], [x16], x1
+        ld1             {v23.d}[1], [x0],  x1
+        ld1             {v24.d}[0], [x16], x1
+        ld1             {v24.d}[1], [x0],  x1
+        ld1             {v25.d}[0], [x16], x1
+        ld1             {v25.d}[1], [x0],  x1
+        ld1             {v26.d}[0], [x16], x1
+        ld1             {v26.d}[1], [x0],  x1
+        ld1             {v27.d}[0], [x16], x1
+        ld1             {v27.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+
+        transpose_8x16b v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
+
+        lpf_16_wd6
+
+        sub             x16, x0,  x1, lsl #4
+        sub             x16, x16, #2
+        transpose_4x16b v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #3
+
+        st1             {v22.s}[0], [x16], x1
+        st1             {v22.s}[2], [x0],  x1
+        st1             {v23.s}[0], [x16], x1
+        st1             {v23.s}[2], [x0],  x1
+        st1             {v24.s}[0], [x16], x1
+        st1             {v24.s}[2], [x0],  x1
+        st1             {v25.s}[0], [x16], x1
+        st1             {v25.s}[2], [x0],  x1
+        st1             {v22.s}[1], [x16], x1
+        st1             {v22.s}[3], [x0],  x1
+        st1             {v23.s}[1], [x16], x1
+        st1             {v23.s}[3], [x0],  x1
+        st1             {v24.s}[1], [x16], x1
+        st1             {v24.s}[3], [x0],  x1
+        st1             {v25.s}[1], [x16], x1
+        st1             {v25.s}[3], [x0],  x1
+        add             x0,  x0,  #2
+        ret             x15
+endfunc
+
+function lpf_v_8_16_neon
+        mov             x15, x30
+        sub             x16, x0,  x1, lsl #2
+        ld1             {v20.16b}, [x16], x1 // p3
+        ld1             {v24.16b}, [x0],  x1 // q0
+        ld1             {v21.16b}, [x16], x1 // p2
+        ld1             {v25.16b}, [x0],  x1 // q1
+        ld1             {v22.16b}, [x16], x1 // p1
+        ld1             {v26.16b}, [x0],  x1 // q2
+        ld1             {v23.16b}, [x16], x1 // p0
+        ld1             {v27.16b}, [x0],  x1 // q3
+        sub             x0,  x0,  x1, lsl #2
+
+        lpf_16_wd8
+
+        sub             x16, x0,  x1, lsl #1
+        sub             x16, x16,  x1
+        st1             {v21.16b}, [x16], x1 // p2
+        st1             {v24.16b}, [x0],  x1 // q0
+        st1             {v22.16b}, [x16], x1 // p1
+        st1             {v25.16b}, [x0],  x1 // q1
+        st1             {v23.16b}, [x16], x1 // p0
+        st1             {v26.16b}, [x0],  x1 // q2
+        sub             x0,  x0,  x1, lsl #1
+        sub             x0,  x0,  x1
+        ret             x15
+
+8:
+        sub             x16, x0,  x1, lsl #1
+        st1             {v22.16b}, [x16], x1 // p1
+        st1             {v24.16b}, [x0],  x1 // q0
+        st1             {v23.16b}, [x16], x1 // p0
+        st1             {v25.16b}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+endfunc
+
+function lpf_h_8_16_neon
+        mov             x15, x30
+        sub             x16, x0,  #4
+        add             x0,  x16, x1, lsl #3
+        ld1             {v20.d}[0], [x16], x1
+        ld1             {v20.d}[1], [x0],  x1
+        ld1             {v21.d}[0], [x16], x1
+        ld1             {v21.d}[1], [x0],  x1
+        ld1             {v22.d}[0], [x16], x1
+        ld1             {v22.d}[1], [x0],  x1
+        ld1             {v23.d}[0], [x16], x1
+        ld1             {v23.d}[1], [x0],  x1
+        ld1             {v24.d}[0], [x16], x1
+        ld1             {v24.d}[1], [x0],  x1
+        ld1             {v25.d}[0], [x16], x1
+        ld1             {v25.d}[1], [x0],  x1
+        ld1             {v26.d}[0], [x16], x1
+        ld1             {v26.d}[1], [x0],  x1
+        ld1             {v27.d}[0], [x16], x1
+        ld1             {v27.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+
+        transpose_8x16b v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
+
+        lpf_16_wd8
+
+        sub             x16, x0,  x1, lsl #4
+        sub             x16, x16, #4
+        transpose_8x16b v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #3
+
+        st1             {v20.d}[0], [x16], x1
+        st1             {v20.d}[1], [x0],  x1
+        st1             {v21.d}[0], [x16], x1
+        st1             {v21.d}[1], [x0],  x1
+        st1             {v22.d}[0], [x16], x1
+        st1             {v22.d}[1], [x0],  x1
+        st1             {v23.d}[0], [x16], x1
+        st1             {v23.d}[1], [x0],  x1
+        st1             {v24.d}[0], [x16], x1
+        st1             {v24.d}[1], [x0],  x1
+        st1             {v25.d}[0], [x16], x1
+        st1             {v25.d}[1], [x0],  x1
+        st1             {v26.d}[0], [x16], x1
+        st1             {v26.d}[1], [x0],  x1
+        st1             {v27.d}[0], [x16], x1
+        st1             {v27.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+        ret             x15
+8:
+        sub             x16, x0,  x1, lsl #4
+        sub             x16, x16, #2
+        transpose_4x16b v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #3
+
+        st1             {v22.s}[0], [x16], x1
+        st1             {v22.s}[2], [x0],  x1
+        st1             {v23.s}[0], [x16], x1
+        st1             {v23.s}[2], [x0],  x1
+        st1             {v24.s}[0], [x16], x1
+        st1             {v24.s}[2], [x0],  x1
+        st1             {v25.s}[0], [x16], x1
+        st1             {v25.s}[2], [x0],  x1
+        st1             {v22.s}[1], [x16], x1
+        st1             {v22.s}[3], [x0],  x1
+        st1             {v23.s}[1], [x16], x1
+        st1             {v23.s}[3], [x0],  x1
+        st1             {v24.s}[1], [x16], x1
+        st1             {v24.s}[3], [x0],  x1
+        st1             {v25.s}[1], [x16], x1
+        st1             {v25.s}[3], [x0],  x1
+        add             x0,  x0,  #2
+        ret             x15
+endfunc
+
+function lpf_v_16_16_neon
+        mov             x15, x30
+
+        sub             x16, x0,  x1, lsl #3
+        add             x16, x16, x1
+        ld1             {v17.16b}, [x16], x1 // p6
+        ld1             {v24.16b}, [x0],  x1 // q0
+        ld1             {v18.16b}, [x16], x1 // p5
+        ld1             {v25.16b}, [x0],  x1 // q1
+        ld1             {v19.16b}, [x16], x1 // p4
+        ld1             {v26.16b}, [x0],  x1 // q2
+        ld1             {v20.16b}, [x16], x1 // p3
+        ld1             {v27.16b}, [x0],  x1 // q3
+        ld1             {v21.16b}, [x16], x1 // p2
+        ld1             {v28.16b}, [x0],  x1 // q4
+        ld1             {v22.16b}, [x16], x1 // p1
+        ld1             {v29.16b}, [x0],  x1 // q5
+        ld1             {v23.16b}, [x16], x1 // p0
+        ld1             {v30.16b}, [x0],  x1 // q6
+        sub             x0,  x0,  x1, lsl #3
+        add             x0,  x0,  x1
+
+        lpf_16_wd16
+
+        sub             x16, x0,  x1, lsl #2
+        sub             x16, x16,  x1, lsl #1
+        st1             {v0.16b},  [x16], x1 // p5
+        st1             {v6.16b},  [x0],  x1 // q0
+        st1             {v1.16b},  [x16], x1 // p4
+        st1             {v7.16b},  [x0],  x1 // q1
+        st1             {v2.16b},  [x16], x1 // p3
+        st1             {v8.16b},  [x0],  x1 // q2
+        st1             {v3.16b},  [x16], x1 // p2
+        st1             {v9.16b},  [x0],  x1 // q3
+        st1             {v4.16b},  [x16], x1 // p1
+        st1             {v10.16b}, [x0],  x1 // q4
+        st1             {v5.16b},  [x16], x1 // p0
+        st1             {v11.16b}, [x0],  x1 // q5
+        sub             x0,  x0,  x1, lsl #2
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+7:
+        sub             x16, x0,  x1
+        sub             x16, x16, x1, lsl #1
+        st1             {v21.16b}, [x16], x1 // p2
+        st1             {v24.16b}, [x0],  x1 // q0
+        st1             {v22.16b}, [x16], x1 // p1
+        st1             {v25.16b}, [x0],  x1 // q1
+        st1             {v23.16b}, [x16], x1 // p0
+        st1             {v26.16b}, [x0],  x1 // q2
+        sub             x0,  x0,  x1, lsl #1
+        sub             x0,  x0,  x1
+        ret             x15
+
+8:
+        sub             x16, x0,  x1, lsl #1
+        st1             {v22.16b}, [x16], x1 // p1
+        st1             {v24.16b}, [x0],  x1 // q0
+        st1             {v23.16b}, [x16], x1 // p0
+        st1             {v25.16b}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+endfunc
+
+function lpf_h_16_16_neon
+        mov             x15, x30
+        sub             x16, x0,  #8
+        ld1             {v16.d}[0], [x16], x1
+        ld1             {v24.d}[0], [x0],  x1
+        ld1             {v17.d}[0], [x16], x1
+        ld1             {v25.d}[0], [x0],  x1
+        ld1             {v18.d}[0], [x16], x1
+        ld1             {v26.d}[0], [x0],  x1
+        ld1             {v19.d}[0], [x16], x1
+        ld1             {v27.d}[0], [x0],  x1
+        ld1             {v20.d}[0], [x16], x1
+        ld1             {v28.d}[0], [x0],  x1
+        ld1             {v21.d}[0], [x16], x1
+        ld1             {v29.d}[0], [x0],  x1
+        ld1             {v22.d}[0], [x16], x1
+        ld1             {v30.d}[0], [x0],  x1
+        ld1             {v23.d}[0], [x16], x1
+        ld1             {v31.d}[0], [x0],  x1
+        ld1             {v16.d}[1], [x16], x1
+        ld1             {v24.d}[1], [x0],  x1
+        ld1             {v17.d}[1], [x16], x1
+        ld1             {v25.d}[1], [x0],  x1
+        ld1             {v18.d}[1], [x16], x1
+        ld1             {v26.d}[1], [x0],  x1
+        ld1             {v19.d}[1], [x16], x1
+        ld1             {v27.d}[1], [x0],  x1
+        ld1             {v20.d}[1], [x16], x1
+        ld1             {v28.d}[1], [x0],  x1
+        ld1             {v21.d}[1], [x16], x1
+        ld1             {v29.d}[1], [x0],  x1
+        ld1             {v22.d}[1], [x16], x1
+        ld1             {v30.d}[1], [x0],  x1
+        ld1             {v23.d}[1], [x16], x1
+        ld1             {v31.d}[1], [x0],  x1
+
+        transpose_8x16b v16, v17, v18, v19, v20, v21, v22, v23, v0,  v1
+        transpose_8x16b v24, v25, v26, v27, v28, v29, v30, v31, v0,  v1
+
+        lpf_16_wd16
+
+        sub             x0,  x0,  x1, lsl #4
+        sub             x16, x0,  #8
+
+        transpose_8x16b v16, v17, v0,  v1,  v2,  v3,  v4,  v5,  v18, v19
+        transpose_8x16b v6,  v7,  v8,  v9,  v10, v11, v30, v31, v18, v19
+
+        st1             {v16.d}[0], [x16], x1
+        st1             {v6.d}[0],  [x0],  x1
+        st1             {v17.d}[0], [x16], x1
+        st1             {v7.d}[0],  [x0],  x1
+        st1             {v0.d}[0],  [x16], x1
+        st1             {v8.d}[0],  [x0],  x1
+        st1             {v1.d}[0],  [x16], x1
+        st1             {v9.d}[0],  [x0],  x1
+        st1             {v2.d}[0],  [x16], x1
+        st1             {v10.d}[0], [x0],  x1
+        st1             {v3.d}[0],  [x16], x1
+        st1             {v11.d}[0], [x0],  x1
+        st1             {v4.d}[0],  [x16], x1
+        st1             {v30.d}[0], [x0],  x1
+        st1             {v5.d}[0],  [x16], x1
+        st1             {v31.d}[0], [x0],  x1
+        st1             {v16.d}[1], [x16], x1
+        st1             {v6.d}[1],  [x0],  x1
+        st1             {v17.d}[1], [x16], x1
+        st1             {v7.d}[1],  [x0],  x1
+        st1             {v0.d}[1],  [x16], x1
+        st1             {v8.d}[1],  [x0],  x1
+        st1             {v1.d}[1],  [x16], x1
+        st1             {v9.d}[1],  [x0],  x1
+        st1             {v2.d}[1],  [x16], x1
+        st1             {v10.d}[1], [x0],  x1
+        st1             {v3.d}[1],  [x16], x1
+        st1             {v11.d}[1], [x0],  x1
+        st1             {v4.d}[1],  [x16], x1
+        st1             {v30.d}[1], [x0],  x1
+        st1             {v5.d}[1],  [x16], x1
+        st1             {v31.d}[1], [x0],  x1
+        ret             x15
+
+7:
+        sub             x16, x0,  x1, lsl #4
+        sub             x16, x16, #4
+        transpose_8x16b v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #3
+
+        st1             {v20.d}[0], [x16], x1
+        st1             {v20.d}[1], [x0],  x1
+        st1             {v21.d}[0], [x16], x1
+        st1             {v21.d}[1], [x0],  x1
+        st1             {v22.d}[0], [x16], x1
+        st1             {v22.d}[1], [x0],  x1
+        st1             {v23.d}[0], [x16], x1
+        st1             {v23.d}[1], [x0],  x1
+        st1             {v24.d}[0], [x16], x1
+        st1             {v24.d}[1], [x0],  x1
+        st1             {v25.d}[0], [x16], x1
+        st1             {v25.d}[1], [x0],  x1
+        st1             {v26.d}[0], [x16], x1
+        st1             {v26.d}[1], [x0],  x1
+        st1             {v27.d}[0], [x16], x1
+        st1             {v27.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+        ret             x15
+8:
+        sub             x16, x0,  x1, lsl #4
+        sub             x16, x16, #2
+        transpose_4x16b v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #3
+
+        st1             {v22.s}[0], [x16], x1
+        st1             {v22.s}[2], [x0],  x1
+        st1             {v23.s}[0], [x16], x1
+        st1             {v23.s}[2], [x0],  x1
+        st1             {v24.s}[0], [x16], x1
+        st1             {v24.s}[2], [x0],  x1
+        st1             {v25.s}[0], [x16], x1
+        st1             {v25.s}[2], [x0],  x1
+        st1             {v22.s}[1], [x16], x1
+        st1             {v22.s}[3], [x0],  x1
+        st1             {v23.s}[1], [x16], x1
+        st1             {v23.s}[3], [x0],  x1
+        st1             {v24.s}[1], [x16], x1
+        st1             {v24.s}[3], [x0],  x1
+        st1             {v25.s}[1], [x16], x1
+        st1             {v25.s}[3], [x0],  x1
+        add             x0,  x0,  #2
+        ret             x15
+endfunc
+
+// void dav1d_lpf_v_sb_y_8bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                 const uint32_t *const vmask,
+//                                 const uint8_t (*l)[4], ptrdiff_t b4_stride,
+//                                 const Av1FilterLUT *lut, const int w)
+
+.macro lpf_func dir, type
+function lpf_\dir\()_sb_\type\()_8bpc_neon, export=1
+        mov             x11, x30
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+        ldp             w6,  w7,  [x2]           // vmask[0], vmask[1]
+.ifc \type, y
+        ldr             w2,  [x2, #8]            // vmask[2]
+.endif
+        add             x5,  x5,  #128           // Move to sharp part of lut
+.ifc \type, y
+        orr             w7,  w7,  w2             // vmask[1] |= vmask[2]
+.endif
+.ifc \dir, v
+        sub             x4,  x3,  x4, lsl #2
+.else
+        sub             x3,  x3,  #4
+        lsl             x4,  x4,  #2
+.endif
+        orr             w6,  w6,  w7             // vmask[0] |= vmask[1]
+
+1:
+        tst             w6,  #0x0f
+.ifc \dir, v
+        ld1             {v0.16b}, [x4], #16
+        ld1             {v1.16b}, [x3], #16
+.else
+        ld2             {v0.s,v1.s}[0], [x3], x4
+        ld2             {v0.s,v1.s}[1], [x3], x4
+        ld2             {v0.s,v1.s}[2], [x3], x4
+        ld2             {v0.s,v1.s}[3], [x3], x4
+.endif
+        b.eq            7f                        // if (!(vm & bits)) continue;
+
+        ld1r            {v5.16b}, [x5]            // sharp[0]
+        add             x5,  x5,  #8
+        movi            v2.4s,   #0xff
+        dup             v13.4s,  w6               // vmask[0]
+
+        and             v0.16b,  v0.16b,  v2.16b  // Keep only lowest byte in each 32 bit word
+        and             v1.16b,  v1.16b,  v2.16b
+        cmtst           v3.16b,  v1.16b,  v2.16b  // Check for nonzero values in l[0][0]
+        movi            v4.16b,  #1
+        ld1r            {v6.16b}, [x5]            // sharp[1]
+        sub             x5,  x5,  #8
+        bif             v1.16b,  v0.16b,  v3.16b  // if (!l[0][0]) L = l[offset][0]
+        cmtst           v2.4s,   v1.4s,   v2.4s   // L != 0
+        mul             v1.4s,   v1.4s,   v4.4s   // L
+.ifc \type, y
+        dup             v15.4s,  w2               // vmask[2]
+.endif
+        dup             v14.4s,  w7               // vmask[1]
+        mov             x16, v2.d[0]
+        mov             x17, v2.d[1]
+        adds            x16, x16, x17
+        b.eq            7f                        // if (!L) continue;
+        neg             v5.16b,  v5.16b           // -sharp[0]
+        movrel          x16,  word_1248
+        ushr            v12.16b, v1.16b,  #4      // H
+        ld1             {v16.4s}, [x16]
+        sshl            v3.16b,  v1.16b,  v5.16b  // L >> sharp[0]
+.ifc \type, y
+        cmtst           v15.4s,  v15.4s,  v16.4s  // if (vmask[2] & bits)
+.endif
+        movi            v7.16b,  #2
+        umin            v3.16b,  v3.16b,  v6.16b  // imin(L >> sharp[0], sharp[1])
+        add             v0.16b,  v1.16b,  v7.16b  // L + 2
+        umax            v11.16b, v3.16b,  v4.16b  // imax(imin(), 1) = limit = I
+        add             v0.16b,  v0.16b,  v0.16b  // 2*(L + 2)
+        cmtst           v14.4s,  v14.4s,  v16.4s  // if (vmask[1] & bits)
+        add             v10.16b, v0.16b,  v11.16b // 2*(L + 2) + limit = E
+        cmtst           v13.4s,  v13.4s,  v16.4s  // if (vmask[0] & bits)
+        and             v13.16b, v13.16b, v2.16b  // vmask[0] &= L != 0
+
+.ifc \type, y
+        tst             w2,  #0x0f
+        b.eq            2f
+        // wd16
+        bl              lpf_\dir\()_16_16_neon
+        b               8f
+2:
+.endif
+        tst             w7,  #0x0f
+        b.eq            3f
+.ifc \type, y
+        // wd8
+        bl              lpf_\dir\()_8_16_neon
+.else
+        // wd6
+        bl              lpf_\dir\()_6_16_neon
+.endif
+        b               8f
+3:
+        // wd4
+        bl              lpf_\dir\()_4_16_neon
+.ifc \dir, h
+        b               8f
+7:
+        // For dir h, the functions above increment x0.
+        // If the whole function is skipped, increment it here instead.
+        add             x0,  x0,  x1,  lsl #4
+.else
+7:
+.endif
+8:
+        lsr             w6,  w6,  #4              // vmask[0] >>= 4
+        lsr             w7,  w7,  #4              // vmask[1] >>= 4
+.ifc \type, y
+        lsr             w2,  w2,  #4              // vmask[2] >>= 4
+.endif
+.ifc \dir, v
+        add             x0,  x0,  #16
+.else
+        // For dir h, x0 is returned incremented
+.endif
+        cbnz            w6,  1b
+
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret             x11
+endfunc
+.endm
+
+lpf_func v, y
+lpf_func h, y
+lpf_func v, uv
+lpf_func h, uv
+
+const word_1248
+        .word 1, 2, 4, 8
+endconst
diff --git a/media/libdav1d/src/src/arm/64/loopfilter16.S b/media/libdav1d/src/src/arm/64/loopfilter16.S
new file mode 100644
index 0000000000..d181a3e623
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/loopfilter16.S
@@ -0,0 +1,925 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// depending on how many pixels need to be stored, returns:
+// x14 = (1 << 0) : 0 pixels
+// x14 = (1 << 4) : inner 4 pixels
+// x14 = (1 << 6) : inner 6 pixels
+// x14 = 0 : all pixels
+.macro loop_filter wd
+function lpf_8_wd\wd\()_neon
+        uabd            v0.8h,   v22.8h,  v23.8h  // abs(p1 - p0)
+        uabd            v1.8h,   v25.8h,  v24.8h  // abs(q1 - q0)
+        uabd            v2.8h,   v23.8h,  v24.8h  // abs(p0 - q0)
+        uabd            v3.8h,   v22.8h,  v25.8h  // abs(p1 - q1)
+.if \wd >= 6
+        uabd            v4.8h,   v21.8h,  v22.8h  // abs(p2 - p1)
+        uabd            v5.8h,   v26.8h,  v25.8h  // abs(q2 - q1)
+.endif
+.if \wd >= 8
+        uabd            v6.8h,   v20.8h,  v21.8h  // abs(p3 - p2)
+        uabd            v7.8h,   v27.8h,  v26.8h  // abs(q3 - q3)
+.endif
+.if \wd >= 6
+        umax            v4.8h,   v4.8h,   v5.8h
+.endif
+        uqadd           v2.8h,   v2.8h,   v2.8h   // abs(p0 - q0) * 2
+.if \wd >= 8
+        umax            v6.8h,   v6.8h,   v7.8h
+.endif
+        ushr            v3.8h,   v3.8h,   #1
+.if \wd >= 8
+        umax            v4.8h,   v4.8h,   v6.8h
+.endif
+.if \wd >= 6
+        and             v4.16b,  v4.16b,  v14.16b
+.endif
+        umax            v0.8h,   v0.8h,   v1.8h   // max(abs(p1 - p0), abs(q1 - q0))
+        uqadd           v2.8h,   v2.8h,   v3.8h   // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
+.if \wd >= 6
+        umax            v4.8h,   v0.8h,   v4.8h
+        cmhs            v1.8h,   v11.8h,  v4.8h   // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
+.else
+        cmhs            v1.8h,   v11.8h,  v0.8h   // max(abs(p1 - p0), abs(q1 - q0)) <= I
+.endif
+        cmhs            v2.8h,   v10.8h,  v2.8h   // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
+        and             v1.16b,  v1.16b,  v2.16b  // fm
+        and             v1.16b,  v1.16b,  v13.16b // fm && wd >= 4
+.if \wd >= 6
+        and             v14.16b, v14.16b, v1.16b  // fm && wd > 4
+.endif
+.if \wd >= 16
+        and             v15.16b, v15.16b, v1.16b  // fm && wd == 16
+.endif
+
+        mov             x16, v1.d[0]
+        mov             x17, v1.d[1]
+        adds            x16, x16, x17
+        b.ne            9f                        // if (!fm || wd < 4) return;
+        mov             x14, #(1 << 0)
+        ret
+9:
+.if \wd >= 6
+        movi            v10.8h,  #1
+        uabd            v2.8h,   v21.8h,  v23.8h  // abs(p2 - p0)
+        uabd            v3.8h,   v22.8h,  v23.8h  // abs(p1 - p0)
+        uabd            v4.8h,   v25.8h,  v24.8h  // abs(q1 - q0)
+        uabd            v5.8h,   v26.8h,  v24.8h  // abs(q2 - q0)
+        dup             v9.8h,   w9               // bitdepth_min_8
+.if \wd >= 8
+        uabd            v6.8h,   v20.8h,  v23.8h  // abs(p3 - p0)
+        uabd            v7.8h,   v27.8h,  v24.8h  // abs(q3 - q0)
+.endif
+        umax            v2.8h,   v2.8h,   v3.8h
+        umax            v4.8h,   v4.8h,   v5.8h
+.if \wd >= 8
+        umax            v6.8h,   v6.8h,   v7.8h
+.endif
+        umax            v2.8h,   v2.8h,   v4.8h
+        ushl            v10.8h,  v10.8h,  v9.8h   // F = 1 << bitdepth_min_8
+.if \wd >= 8
+        umax            v2.8h,   v2.8h,   v6.8h
+.endif
+
+.if \wd == 16
+        uabd            v3.8h,   v17.8h,  v23.8h  // abs(p6 - p0)
+        uabd            v4.8h,   v18.8h,  v23.8h  // abs(p5 - p0)
+        uabd            v5.8h,   v19.8h,  v23.8h  // abs(p4 - p0)
+.endif
+        cmhs            v2.8h,   v10.8h,  v2.8h   // flat8in
+.if \wd == 16
+        uabd            v6.8h,   v28.8h,  v24.8h  // abs(q4 - q0)
+        uabd            v7.8h,   v29.8h,  v24.8h  // abs(q5 - q0)
+        uabd            v8.8h,   v30.8h,  v24.8h  // abs(q6 - q0)
+.endif
+        and             v14.16b, v2.16b,  v14.16b // flat8in && fm && wd > 4
+        bic             v1.16b,  v1.16b,  v14.16b // fm && wd >= 4 && !flat8in
+.if \wd == 16
+        umax            v3.8h,   v3.8h,   v4.8h
+        umax            v5.8h,   v5.8h,   v6.8h
+.endif
+        mov             x16, v1.d[0]
+        mov             x17, v1.d[1]
+.if \wd == 16
+        umax            v7.8h,   v7.8h,   v8.8h
+        umax            v3.8h,   v3.8h,   v5.8h
+        umax            v3.8h,   v3.8h,   v7.8h
+        cmhs            v3.8h,   v10.8h,  v3.8h   // flat8out
+.endif
+        adds            x16, x16, x17
+.if \wd == 16
+        and             v15.16b, v15.16b, v3.16b  // flat8out && fm && wd == 16
+        and             v15.16b, v15.16b, v14.16b // flat8out && flat8in && fm && wd == 16
+        bic             v14.16b, v14.16b, v15.16b // flat8in && fm && wd >= 4 && !flat8out
+.endif
+        b.eq            1f                        // skip wd == 4 case
+.endif
+
+        dup             v3.8h,   w8               // bitdepth_max
+        sub             v2.8h,   v22.8h,  v25.8h  // p1 - q1
+        ushr            v3.8h,   v3.8h,   #1      // 128 << bitdepth_min_8 - 1
+        cmhi            v0.8h,   v0.8h,   v12.8h  // hev
+        not             v9.16b,  v3.16b           // - 128 * (1 << bitdepth_min_8)
+        smin            v2.8h,   v2.8h,   v3.8h   // iclip_diff(p1 - q1)
+        smax            v2.8h,   v2.8h,   v9.8h   // iclip_diff(p1 - q1)
+        and             v4.16b,  v2.16b,  v0.16b  // if (hev) iclip_diff(p1 - q1)
+        sub             v2.8h,   v24.8h,  v23.8h
+        movi            v5.8h,   #3
+        bic             v0.16b,  v1.16b,  v0.16b  // (fm && wd >= 4 && !hev)
+        mul             v2.8h,   v2.8h,   v5.8h
+        movi            v6.8h,   #4
+        add             v2.8h,   v2.8h,   v4.8h
+        smin            v2.8h,   v2.8h,   v3.8h   // f = iclip_diff()
+        smax            v2.8h,   v2.8h,   v9.8h   // f = iclip_diff()
+        sqadd           v4.8h,   v6.8h,   v2.8h   // f + 4
+        sqadd           v5.8h,   v5.8h,   v2.8h   // f + 3
+        smin            v4.8h,   v4.8h,   v3.8h   // imin(f + 4, 128 << bitdepth_min_8 - 1)
+        smin            v5.8h,   v5.8h,   v3.8h   // imin(f + 3, 128 << bitdepth_min_8 - 1)
+        sshr            v4.8h,   v4.8h,   #3      // f1
+        sshr            v5.8h,   v5.8h,   #3      // f2
+        movi            v9.8h,   #0
+        dup             v3.8h,   w8               // bitdepth_max
+        sqadd           v2.8h,   v23.8h,  v5.8h   // p0 + f2
+        sqsub           v6.8h,   v24.8h,  v4.8h   // q0 - f1
+        srshr           v4.8h,   v4.8h,   #1      // (f1 + 1) >> 1
+        smin            v2.8h,   v2.8h,   v3.8h   // out p0 = iclip_pixel()
+        smin            v6.8h,   v6.8h,   v3.8h   // out q0 = iclip_pixel()
+        smax            v2.8h,   v2.8h,   v9.8h   // out p0 = iclip_pixel()
+        smax            v6.8h,   v6.8h,   v9.8h   // out q0 = iclip_pixel()
+        bit             v23.16b, v2.16b,  v1.16b  // if (fm && wd >= 4)
+        bit             v24.16b, v6.16b,  v1.16b  // if (fm && wd >= 4)
+        sqadd           v2.8h,   v22.8h,  v4.8h   // p1 + f
+        sqsub           v6.8h,   v25.8h,  v4.8h   // q1 - f
+        smin            v2.8h,   v2.8h,   v3.8h   // out p1 = iclip_pixel()
+        smin            v6.8h,   v6.8h,   v3.8h   // out q1 = iclip_pixel()
+        smax            v2.8h,   v2.8h,   v9.8h   // out p1 = iclip_pixel()
+        smax            v6.8h,   v6.8h,   v9.8h   // out q1 = iclip_pixel()
+        bit             v22.16b, v2.16b,  v0.16b  // if (fm && wd >= 4 && !hev)
+        bit             v25.16b, v6.16b,  v0.16b  // if (fm && wd >= 4 && !hev)
+1:
+
+.if \wd == 6
+        mov             x16, v14.d[0]
+        mov             x17, v14.d[1]
+        adds            x16, x16, x17
+        b.eq            2f                        // skip if there's no flat8in
+
+        add             v0.8h,   v21.8h,  v21.8h  // p2 * 2
+        add             v2.8h,   v21.8h,  v22.8h  // p2 + p1
+        add             v4.8h,   v22.8h,  v23.8h  // p1 + p0
+        add             v6.8h,   v23.8h,  v24.8h  // p0 + q0
+        add             v8.8h,   v0.8h,   v2.8h
+        add             v10.8h,  v4.8h,   v6.8h
+        add             v12.8h,  v24.8h,  v25.8h  // q0 + q1
+        add             v8.8h,   v8.8h,   v10.8h
+        sub             v12.8h,  v12.8h,  v0.8h
+        add             v10.8h,  v25.8h,  v26.8h  // q1 + q2
+        urshr           v0.8h,   v8.8h,   #3      // out p1
+
+        add             v8.8h,   v8.8h,   v12.8h
+        sub             v10.8h,  v10.8h,  v2.8h
+        add             v12.8h,  v26.8h,  v26.8h  // q2 + q2
+        urshr           v1.8h,   v8.8h,   #3      // out p0
+
+        add             v8.8h,   v8.8h,   v10.8h
+        sub             v12.8h,  v12.8h,  v4.8h
+        urshr           v2.8h,   v8.8h,   #3      // out q0
+
+        bit             v22.16b, v0.16b,  v14.16b // p1 if (flat8in)
+        add             v8.8h,   v8.8h,   v12.8h
+        bit             v23.16b, v1.16b,  v14.16b // p0 if (flat8in)
+        urshr           v3.8h,   v8.8h,   #3      // out q1
+        bit             v24.16b, v2.16b,  v14.16b // q0 if (flat8in)
+        bit             v25.16b, v3.16b,  v14.16b // q1 if (flat8in)
+.elseif \wd >= 8
+        mov             x16, v14.d[0]
+        mov             x17, v14.d[1]
+        adds            x16, x16, x17
+.if \wd == 8
+        b.eq            8f                        // skip if there's no flat8in
+.else
+        b.eq            2f                        // skip if there's no flat8in
+.endif
+
+        add             v0.8h,   v20.8h,  v21.8h  // p3 + p2
+        add             v2.8h,   v22.8h,  v25.8h  // p1 + q1
+        add             v4.8h,   v20.8h,  v22.8h  // p3 + p1
+        add             v6.8h,   v23.8h,  v26.8h  // p0 + q2
+        add             v8.8h,   v0.8h,   v0.8h   // 2 * (p3 + p2)
+        add             v9.8h,   v23.8h,  v24.8h  // p0 + q0
+        add             v8.8h,   v8.8h,   v4.8h   // + p3 + p1
+        sub             v2.8h,   v2.8h,   v0.8h   // p1 + q1 - p3 - p2
+        add             v8.8h,   v8.8h,   v9.8h   // + p0 + q0
+        sub             v6.8h,   v6.8h,   v4.8h   // p0 + q2 - p3 - p1
+        urshr           v10.8h,  v8.8h,   #3      // out p2
+
+        add             v8.8h,   v8.8h,   v2.8h
+        add             v0.8h,   v20.8h,  v23.8h  // p3 + p0
+        add             v2.8h,   v24.8h,  v27.8h  // q0 + q3
+        urshr           v11.8h,  v8.8h,   #3      // out p1
+
+        add             v8.8h,   v8.8h,   v6.8h
+        sub             v2.8h,   v2.8h,   v0.8h   // q0 + q3 - p3 - p0
+        add             v4.8h,   v21.8h,  v24.8h  // p2 + q0
+        add             v6.8h,   v25.8h,  v27.8h  // q1 + q3
+        urshr           v12.8h,  v8.8h,   #3      // out p0
+
+        add             v8.8h,   v8.8h,   v2.8h
+        sub             v6.8h,   v6.8h,   v4.8h   // q1 + q3 - p2 - q0
+        add             v0.8h,   v22.8h,  v25.8h  // p1 + q1
+        add             v2.8h,   v26.8h,  v27.8h  // q2 + q3
+        urshr           v13.8h,  v8.8h,   #3      // out q0
+
+        add             v8.8h,   v8.8h,   v6.8h
+        sub             v2.8h,   v2.8h,   v0.8h   // q2 + q3 - p1 - q1
+        urshr           v0.8h,   v8.8h,   #3      // out q1
+
+        add             v8.8h,   v8.8h,   v2.8h
+
+        bit             v21.16b, v10.16b, v14.16b
+        bit             v22.16b, v11.16b, v14.16b
+        bit             v23.16b, v12.16b, v14.16b
+        urshr           v1.8h,   v8.8h,   #3      // out q2
+        bit             v24.16b, v13.16b, v14.16b
+        bit             v25.16b, v0.16b,  v14.16b
+        bit             v26.16b, v1.16b,  v14.16b
+.endif
+2:
+.if \wd == 16
+        mov             x16, v15.d[0]
+        mov             x17, v15.d[1]
+        adds            x16, x16, x17
+        b.ne            1f                        // check if flat8out is needed
+        mov             x16, v14.d[0]
+        mov             x17, v14.d[1]
+        adds            x16, x16, x17
+        b.eq            8f                        // if there was no flat8in, just write the inner 4 pixels
+        b               7f                        // if flat8in was used, write the inner 6 pixels
+1:
+
+        add             v2.8h,   v17.8h,  v17.8h  // p6 + p6
+        add             v4.8h,   v17.8h,  v18.8h  // p6 + p5
+        add             v6.8h,   v17.8h,  v19.8h  // p6 + p4
+        add             v8.8h,   v17.8h,  v20.8h  // p6 + p3
+        add             v12.8h,  v2.8h,   v4.8h
+        add             v10.8h,  v6.8h,   v8.8h
+        add             v6.8h,   v17.8h,  v21.8h  // p6 + p2
+        add             v12.8h,  v12.8h,  v10.8h
+        add             v8.8h,   v17.8h,  v22.8h  // p6 + p1
+        add             v10.8h,  v18.8h,  v23.8h  // p5 + p0
+        add             v6.8h,   v6.8h,   v8.8h
+        add             v8.8h,   v19.8h,  v24.8h  // p4 + q0
+        add             v12.8h,  v12.8h,  v6.8h
+        add             v10.8h,  v10.8h,  v8.8h
+        add             v6.8h,   v20.8h,  v25.8h  // p3 + q1
+        add             v12.8h,  v12.8h,  v10.8h
+        sub             v6.8h,   v6.8h,   v2.8h
+        add             v2.8h,   v21.8h,  v26.8h  // p2 + q2
+        urshr           v0.8h,   v12.8h,  #4      // out p5
+        add             v12.8h,  v12.8h,  v6.8h   // - (p6 + p6) + (p3 + q1)
+        sub             v2.8h,   v2.8h,   v4.8h
+        add             v4.8h,   v22.8h,  v27.8h  // p1 + q3
+        add             v6.8h,   v17.8h,  v19.8h  // p6 + p4
+        urshr           v1.8h,   v12.8h,  #4      // out p4
+        add             v12.8h,  v12.8h,  v2.8h   // - (p6 + p5) + (p2 + q2)
+        sub             v4.8h,   v4.8h,   v6.8h
+        add             v6.8h,   v23.8h,  v28.8h  // p0 + q4
+        add             v8.8h,   v17.8h,  v20.8h  // p6 + p3
+        urshr           v2.8h,   v12.8h,  #4      // out p3
+        add             v12.8h,  v12.8h,  v4.8h   // - (p6 + p4) + (p1 + q3)
+        sub             v6.8h,   v6.8h,   v8.8h
+        add             v8.8h,   v24.8h,  v29.8h  // q0 + q5
+        add             v4.8h,   v17.8h,  v21.8h  // p6 + p2
+        urshr           v3.8h,   v12.8h,  #4      // out p2
+        add             v12.8h,  v12.8h,  v6.8h   // - (p6 + p3) + (p0 + q4)
+        sub             v8.8h,   v8.8h,   v4.8h
+        add             v6.8h,   v25.8h,  v30.8h  // q1 + q6
+        add             v10.8h,  v17.8h,  v22.8h  // p6 + p1
+        urshr           v4.8h,   v12.8h,  #4      // out p1
+        add             v12.8h,  v12.8h,  v8.8h   // - (p6 + p2) + (q0 + q5)
+        sub             v6.8h,   v6.8h,   v10.8h
+        add             v8.8h,   v26.8h,  v30.8h  // q2 + q6
+        bif             v0.16b,  v18.16b, v15.16b // out p5
+        add             v10.8h,  v18.8h,  v23.8h  // p5 + p0
+        urshr           v5.8h,   v12.8h,  #4      // out p0
+        add             v12.8h,  v12.8h,  v6.8h   // - (p6 + p1) + (q1 + q6)
+        sub             v8.8h,   v8.8h,   v10.8h
+        add             v10.8h,  v27.8h,  v30.8h  // q3 + q6
+        bif             v1.16b,  v19.16b, v15.16b // out p4
+        add             v18.8h,  v19.8h,  v24.8h  // p4 + q0
+        urshr           v6.8h,   v12.8h,  #4      // out q0
+        add             v12.8h,  v12.8h,  v8.8h   // - (p5 + p0) + (q2 + q6)
+        sub             v10.8h,  v10.8h,  v18.8h
+        add             v8.8h,   v28.8h,  v30.8h  // q4 + q6
+        bif             v2.16b,  v20.16b, v15.16b // out p3
+        add             v18.8h,  v20.8h,  v25.8h  // p3 + q1
+        urshr           v7.8h,   v12.8h,  #4      // out q1
+        add             v12.8h,  v12.8h,  v10.8h  // - (p4 + q0) + (q3 + q6)
+        sub             v18.8h,  v8.8h,   v18.8h
+        add             v10.8h,  v29.8h,  v30.8h  // q5 + q6
+        bif             v3.16b,  v21.16b, v15.16b // out p2
+        add             v20.8h,  v21.8h,  v26.8h  // p2 + q2
+        urshr           v8.8h,   v12.8h,  #4      // out q2
+        add             v12.8h,  v12.8h,  v18.8h  // - (p3 + q1) + (q4 + q6)
+        sub             v10.8h,  v10.8h,  v20.8h
+        add             v18.8h,  v30.8h,  v30.8h  // q6 + q6
+        bif             v4.16b,  v22.16b, v15.16b // out p1
+        add             v20.8h,  v22.8h,  v27.8h  // p1 + q3
+        urshr           v9.8h,   v12.8h,  #4      // out q3
+        add             v12.8h,  v12.8h,  v10.8h  // - (p2 + q2) + (q5 + q6)
+        sub             v18.8h,  v18.8h,  v20.8h
+        bif             v5.16b,  v23.16b, v15.16b // out p0
+        urshr           v10.8h,  v12.8h,  #4      // out q4
+        add             v12.8h,  v12.8h,  v18.8h  // - (p1 + q3) + (q6 + q6)
+        urshr           v11.8h,  v12.8h,  #4      // out q5
+        bif             v6.16b,  v24.16b, v15.16b // out q0
+        bif             v7.16b,  v25.16b, v15.16b // out q1
+        bif             v8.16b,  v26.16b, v15.16b // out q2
+        bif             v9.16b,  v27.16b, v15.16b // out q3
+        bif             v10.16b, v28.16b, v15.16b // out q4
+        bif             v11.16b, v29.16b, v15.16b // out q5
+.endif
+
+        mov             x14, #0
+        ret
+.if \wd == 16
+7:
+        // Return to a shorter epilogue, writing only the inner 6 pixels
+        mov             x14, #(1 << 6)
+        ret
+.endif
+.if \wd >= 8
+8:
+        // Return to a shorter epilogue, writing only the inner 4 pixels
+        mov             x14, #(1 << 4)
+        ret
+.endif
+endfunc
+.endm
+
+loop_filter 16
+loop_filter 8
+loop_filter 6
+loop_filter 4
+
+.macro lpf_8_wd16
+        bl              lpf_8_wd16_neon
+        cbz             x14, 1f
+        tbnz            x14, #6, 7f
+        tbnz            x14, #4, 8f
+        ret             x15
+1:
+.endm
+
+.macro lpf_8_wd8
+        bl              lpf_8_wd8_neon
+        cbz             x14, 1f
+        tbnz            x14, #4, 8f
+        ret             x15
+1:
+.endm
+
+.macro lpf_8_wd6
+        bl              lpf_8_wd6_neon
+        cbz             x14, 1f
+        ret             x15
+1:
+.endm
+
+.macro lpf_8_wd4
+        bl              lpf_8_wd4_neon
+        cbz             x14, 1f
+        ret             x15
+1:
+.endm
+
+function lpf_v_4_8_neon
+        mov             x15, x30
+        sub             x16, x0,  x1, lsl #1
+        ld1             {v22.8h}, [x16], x1 // p1
+        ld1             {v24.8h}, [x0],  x1 // q0
+        ld1             {v23.8h}, [x16], x1 // p0
+        ld1             {v25.8h}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+
+        lpf_8_wd4
+
+        sub             x16, x0,  x1, lsl #1
+        st1             {v22.8h}, [x16], x1 // p1
+        st1             {v24.8h}, [x0],  x1 // q0
+        st1             {v23.8h}, [x16], x1 // p0
+        st1             {v25.8h}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+endfunc
+
+function lpf_h_4_8_neon
+        mov             x15, x30
+        sub             x16, x0,  #4
+        add             x0,  x16, x1, lsl #2
+        ld1             {v22.d}[0], [x16], x1
+        ld1             {v22.d}[1], [x0],  x1
+        ld1             {v23.d}[0], [x16], x1
+        ld1             {v23.d}[1], [x0],  x1
+        ld1             {v24.d}[0], [x16], x1
+        ld1             {v24.d}[1], [x0],  x1
+        ld1             {v25.d}[0], [x16], x1
+        ld1             {v25.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+
+        transpose_4x8h  v22, v23, v24, v25, v26, v27, v28, v29
+
+        lpf_8_wd4
+
+        sub             x16, x0,  x1, lsl #3
+        sub             x16, x16, #4
+        transpose_4x8h  v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #2
+
+        st1             {v22.d}[0], [x16], x1
+        st1             {v22.d}[1], [x0],  x1
+        st1             {v23.d}[0], [x16], x1
+        st1             {v23.d}[1], [x0],  x1
+        st1             {v24.d}[0], [x16], x1
+        st1             {v24.d}[1], [x0],  x1
+        st1             {v25.d}[0], [x16], x1
+        st1             {v25.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+        ret             x15
+endfunc
+
+function lpf_v_6_8_neon
+        mov             x15, x30
+        sub             x16, x0,  x1, lsl #1
+        sub             x16, x16, x1
+        ld1             {v21.8h}, [x16], x1 // p2
+        ld1             {v24.8h}, [x0],  x1 // q0
+        ld1             {v22.8h}, [x16], x1 // p1
+        ld1             {v25.8h}, [x0],  x1 // q1
+        ld1             {v23.8h}, [x16], x1 // p0
+        ld1             {v26.8h}, [x0],  x1 // q2
+        sub             x0,  x0,  x1, lsl #1
+        sub             x0,  x0,  x1
+
+        lpf_8_wd6
+
+        sub             x16, x0,  x1, lsl #1
+        st1             {v22.8h}, [x16], x1 // p1
+        st1             {v24.8h}, [x0],  x1 // q0
+        st1             {v23.8h}, [x16], x1 // p0
+        st1             {v25.8h}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+endfunc
+
+function lpf_h_6_8_neon
+        mov             x15, x30
+        sub             x16, x0,  #8
+        add             x0,  x16, x1, lsl #2
+        ld1             {v20.8h}, [x16], x1
+        ld1             {v24.8h}, [x0],  x1
+        ld1             {v21.8h}, [x16], x1
+        ld1             {v25.8h}, [x0],  x1
+        ld1             {v22.8h}, [x16], x1
+        ld1             {v26.8h}, [x0],  x1
+        ld1             {v23.8h}, [x16], x1
+        ld1             {v27.8h}, [x0],  x1
+        add             x0,  x0,  #8
+
+        transpose_8x8h  v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
+
+        lpf_8_wd6
+
+        sub             x16, x0,  x1, lsl #3
+        sub             x16, x16, #4
+        transpose_4x8h  v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #2
+
+        st1             {v22.d}[0], [x16], x1
+        st1             {v22.d}[1], [x0],  x1
+        st1             {v23.d}[0], [x16], x1
+        st1             {v23.d}[1], [x0],  x1
+        st1             {v24.d}[0], [x16], x1
+        st1             {v24.d}[1], [x0],  x1
+        st1             {v25.d}[0], [x16], x1
+        st1             {v25.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+        ret             x15
+endfunc
+
+function lpf_v_8_8_neon
+        mov             x15, x30
+        sub             x16, x0,  x1, lsl #2
+        ld1             {v20.8h}, [x16], x1 // p3
+        ld1             {v24.8h}, [x0],  x1 // q0
+        ld1             {v21.8h}, [x16], x1 // p2
+        ld1             {v25.8h}, [x0],  x1 // q1
+        ld1             {v22.8h}, [x16], x1 // p1
+        ld1             {v26.8h}, [x0],  x1 // q2
+        ld1             {v23.8h}, [x16], x1 // p0
+        ld1             {v27.8h}, [x0],  x1 // q3
+        sub             x0,  x0,  x1, lsl #2
+
+        lpf_8_wd8
+
+        sub             x16, x0,  x1, lsl #1
+        sub             x16, x16,  x1
+        st1             {v21.8h}, [x16], x1 // p2
+        st1             {v24.8h}, [x0],  x1 // q0
+        st1             {v22.8h}, [x16], x1 // p1
+        st1             {v25.8h}, [x0],  x1 // q1
+        st1             {v23.8h}, [x16], x1 // p0
+        st1             {v26.8h}, [x0],  x1 // q2
+        sub             x0,  x0,  x1, lsl #1
+        sub             x0,  x0,  x1
+        ret             x15
+
+8:
+        sub             x16, x0,  x1, lsl #1
+        st1             {v22.8h}, [x16], x1 // p1
+        st1             {v24.8h}, [x0],  x1 // q0
+        st1             {v23.8h}, [x16], x1 // p0
+        st1             {v25.8h}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+endfunc
+
+function lpf_h_8_8_neon
+        mov             x15, x30
+        sub             x16, x0,  #8
+        add             x0,  x16, x1, lsl #2
+        ld1             {v20.8h}, [x16], x1
+        ld1             {v24.8h}, [x0],  x1
+        ld1             {v21.8h}, [x16], x1
+        ld1             {v25.8h}, [x0],  x1
+        ld1             {v22.8h}, [x16], x1
+        ld1             {v26.8h}, [x0],  x1
+        ld1             {v23.8h}, [x16], x1
+        ld1             {v27.8h}, [x0],  x1
+        add             x0,  x0,  #8
+
+        transpose_8x8h  v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
+
+        lpf_8_wd8
+
+        sub             x16, x0,  x1, lsl #3
+        sub             x16, x16, #8
+        transpose_8x8h  v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #2
+
+        st1             {v20.8h}, [x16], x1
+        st1             {v24.8h}, [x0],  x1
+        st1             {v21.8h}, [x16], x1
+        st1             {v25.8h}, [x0],  x1
+        st1             {v22.8h}, [x16], x1
+        st1             {v26.8h}, [x0],  x1
+        st1             {v23.8h}, [x16], x1
+        st1             {v27.8h}, [x0],  x1
+        add             x0,  x0,  #8
+        ret             x15
+8:
+        sub             x16, x0,  x1, lsl #3
+        sub             x16, x16, #4
+        transpose_4x8h  v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #2
+
+        st1             {v22.d}[0], [x16], x1
+        st1             {v22.d}[1], [x0],  x1
+        st1             {v23.d}[0], [x16], x1
+        st1             {v23.d}[1], [x0],  x1
+        st1             {v24.d}[0], [x16], x1
+        st1             {v24.d}[1], [x0],  x1
+        st1             {v25.d}[0], [x16], x1
+        st1             {v25.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+        ret             x15
+endfunc
+
+function lpf_v_16_8_neon
+        mov             x15, x30
+
+        sub             x16, x0,  x1, lsl #3
+        add             x16, x16, x1
+        ld1             {v17.8h}, [x16], x1 // p6
+        ld1             {v24.8h}, [x0],  x1 // q0
+        ld1             {v18.8h}, [x16], x1 // p5
+        ld1             {v25.8h}, [x0],  x1 // q1
+        ld1             {v19.8h}, [x16], x1 // p4
+        ld1             {v26.8h}, [x0],  x1 // q2
+        ld1             {v20.8h}, [x16], x1 // p3
+        ld1             {v27.8h}, [x0],  x1 // q3
+        ld1             {v21.8h}, [x16], x1 // p2
+        ld1             {v28.8h}, [x0],  x1 // q4
+        ld1             {v22.8h}, [x16], x1 // p1
+        ld1             {v29.8h}, [x0],  x1 // q5
+        ld1             {v23.8h}, [x16], x1 // p0
+        ld1             {v30.8h}, [x0],  x1 // q6
+        sub             x0,  x0,  x1, lsl #3
+        add             x0,  x0,  x1
+
+        lpf_8_wd16
+
+        sub             x16, x0,  x1, lsl #2
+        sub             x16, x16, x1, lsl #1
+        st1             {v0.8h},  [x16], x1 // p5
+        st1             {v6.8h},  [x0],  x1 // q0
+        st1             {v1.8h},  [x16], x1 // p4
+        st1             {v7.8h},  [x0],  x1 // q1
+        st1             {v2.8h},  [x16], x1 // p3
+        st1             {v8.8h},  [x0],  x1 // q2
+        st1             {v3.8h},  [x16], x1 // p2
+        st1             {v9.8h},  [x0],  x1 // q3
+        st1             {v4.8h},  [x16], x1 // p1
+        st1             {v10.8h}, [x0],  x1 // q4
+        st1             {v5.8h},  [x16], x1 // p0
+        st1             {v11.8h}, [x0],  x1 // q5
+        sub             x0,  x0,  x1, lsl #2
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+7:
+        sub             x16, x0,  x1
+        sub             x16, x16, x1, lsl #1
+        st1             {v21.8h}, [x16], x1 // p2
+        st1             {v24.8h}, [x0],  x1 // q0
+        st1             {v22.8h}, [x16], x1 // p1
+        st1             {v25.8h}, [x0],  x1 // q1
+        st1             {v23.8h}, [x16], x1 // p0
+        st1             {v26.8h}, [x0],  x1 // q2
+        sub             x0,  x0,  x1, lsl #1
+        sub             x0,  x0,  x1
+        ret             x15
+
+8:
+        sub             x16, x0,  x1, lsl #1
+        st1             {v22.8h}, [x16], x1 // p1
+        st1             {v24.8h}, [x0],  x1 // q0
+        st1             {v23.8h}, [x16], x1 // p0
+        st1             {v25.8h}, [x0],  x1 // q1
+        sub             x0,  x0,  x1, lsl #1
+        ret             x15
+endfunc
+
+function lpf_h_16_8_neon
+        mov             x15, x30
+        sub             x16, x0,  #16
+        ld1             {v16.8h}, [x16], x1
+        ld1             {v24.8h}, [x0],  x1
+        ld1             {v17.8h}, [x16], x1
+        ld1             {v25.8h}, [x0],  x1
+        ld1             {v18.8h}, [x16], x1
+        ld1             {v26.8h}, [x0],  x1
+        ld1             {v19.8h}, [x16], x1
+        ld1             {v27.8h}, [x0],  x1
+        ld1             {v20.8h}, [x16], x1
+        ld1             {v28.8h}, [x0],  x1
+        ld1             {v21.8h}, [x16], x1
+        ld1             {v29.8h}, [x0],  x1
+        ld1             {v22.8h}, [x16], x1
+        ld1             {v30.8h}, [x0],  x1
+        ld1             {v23.8h}, [x16], x1
+        ld1             {v31.8h}, [x0],  x1
+
+        transpose_8x8h  v16, v17, v18, v19, v20, v21, v22, v23, v0,  v1
+        transpose_8x8h  v24, v25, v26, v27, v28, v29, v30, v31, v0,  v1
+
+        lpf_8_wd16
+
+        sub             x0,  x0,  x1, lsl #3
+        sub             x16, x0,  #16
+
+        transpose_8x8h  v16, v17, v0,  v1,  v2,  v3,  v4,  v5,  v18, v19
+        transpose_8x8h  v6,  v7,  v8,  v9,  v10, v11, v30, v31, v18, v19
+
+        st1             {v16.8h}, [x16], x1
+        st1             {v6.8h},  [x0],  x1
+        st1             {v17.8h}, [x16], x1
+        st1             {v7.8h},  [x0],  x1
+        st1             {v0.8h},  [x16], x1
+        st1             {v8.8h},  [x0],  x1
+        st1             {v1.8h},  [x16], x1
+        st1             {v9.8h},  [x0],  x1
+        st1             {v2.8h},  [x16], x1
+        st1             {v10.8h}, [x0],  x1
+        st1             {v3.8h},  [x16], x1
+        st1             {v11.8h}, [x0],  x1
+        st1             {v4.8h},  [x16], x1
+        st1             {v30.8h}, [x0],  x1
+        st1             {v5.8h},  [x16], x1
+        st1             {v31.8h}, [x0],  x1
+        ret             x15
+
+7:
+        sub             x16, x0,  x1, lsl #3
+        sub             x16, x16, #8
+        transpose_8x8h  v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #2
+
+        st1             {v20.8h}, [x16], x1
+        st1             {v24.8h}, [x0],  x1
+        st1             {v21.8h}, [x16], x1
+        st1             {v25.8h}, [x0],  x1
+        st1             {v22.8h}, [x16], x1
+        st1             {v26.8h}, [x0],  x1
+        st1             {v23.8h}, [x16], x1
+        st1             {v27.8h}, [x0],  x1
+        add             x0,  x0,  #8
+        ret             x15
+8:
+        sub             x16, x0,  x1, lsl #3
+        sub             x16, x16, #4
+        transpose_4x8h  v22, v23, v24, v25, v26, v27, v28, v29
+        add             x0,  x16, x1, lsl #2
+
+        st1             {v22.d}[0], [x16], x1
+        st1             {v22.d}[1], [x0],  x1
+        st1             {v23.d}[0], [x16], x1
+        st1             {v23.d}[1], [x0],  x1
+        st1             {v24.d}[0], [x16], x1
+        st1             {v24.d}[1], [x0],  x1
+        st1             {v25.d}[0], [x16], x1
+        st1             {v25.d}[1], [x0],  x1
+        add             x0,  x0,  #4
+        ret             x15
+endfunc
+
+// void dav1d_lpf_v_sb_y_16bpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                  const uint32_t *const vmask,
+//                                  const uint8_t (*l)[4], ptrdiff_t b4_stride,
+//                                  const Av1FilterLUT *lut, const int w,
+//                                  const int bitdepth_max)
+
+.macro lpf_func dir, type
+function lpf_\dir\()_sb_\type\()_16bpc_neon, export=1
+        mov             x11, x30
+        mov             w8,  w7  // bitdepth_max
+        clz             w9,  w8
+        mov             w10, #24
+        sub             w9,  w10,  w9 // bitdepth_min_8
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+        ldp             w6,  w7,  [x2]           // vmask[0], vmask[1]
+.ifc \type, y
+        ldr             w2,  [x2, #8]            // vmask[2]
+.endif
+        add             x5,  x5,  #128           // Move to sharp part of lut
+.ifc \type, y
+        orr             w7,  w7,  w2             // vmask[1] |= vmask[2]
+.endif
+.ifc \dir, v
+        sub             x4,  x3,  x4, lsl #2
+.else
+        sub             x3,  x3,  #4
+        lsl             x4,  x4,  #2
+.endif
+        orr             w6,  w6,  w7             // vmask[0] |= vmask[1]
+
+1:
+        tst             w6,  #0x03
+.ifc \dir, v
+        ld1             {v0.8b}, [x4], #8
+        ld1             {v1.8b}, [x3], #8
+.else
+        ld2             {v0.s,v1.s}[0], [x3], x4
+        ld2             {v0.s,v1.s}[1], [x3], x4
+.endif
+        b.eq            7f                        // if (!(vm & bits)) continue;
+
+        ld1r            {v5.8b}, [x5]             // sharp[0]
+        add             x5,  x5,  #8
+        movi            v2.2s,   #0xff
+        dup             v13.2s,  w6               // vmask[0]
+        dup             v31.8h,  w9               // bitdepth_min_8
+
+        and             v0.8b,   v0.8b,   v2.8b   // Keep only lowest byte in each 32 bit word
+        and             v1.8b,   v1.8b,   v2.8b
+        cmtst           v3.8b,   v1.8b,   v2.8b   // Check for nonzero values in l[0][0]
+        movi            v4.8b,   #1
+        ld1r            {v6.8b}, [x5]             // sharp[1]
+        sub             x5,  x5,  #8
+        bif             v1.8b,   v0.8b,   v3.8b   // if (!l[0][0]) L = l[offset][0]
+        cmtst           v2.2s,   v1.2s,   v2.2s   // L != 0
+        mul             v1.2s,   v1.2s,   v4.2s   // L
+.ifc \type, y
+        dup             v15.2s,  w2               // vmask[2]
+.endif
+        dup             v14.2s,  w7               // vmask[1]
+        mov             x16, v2.d[0]
+        cmp             x16, #0
+        b.eq            7f                        // if (!L) continue;
+        neg             v5.8b,   v5.8b            // -sharp[0]
+        movrel          x16,  word_12
+        ushr            v12.8b,  v1.8b,   #4      // H
+        ld1             {v16.2s}, [x16]
+        sshl            v3.8b,   v1.8b,   v5.8b   // L >> sharp[0]
+.ifc \type, y
+        cmtst           v15.2s,  v15.2s,  v16.2s  // if (vmask[2] & bits)
+.endif
+        movi            v7.8b,   #2
+        umin            v3.8b,   v3.8b,   v6.8b   // imin(L >> sharp[0], sharp[1])
+        add             v0.8b,   v1.8b,   v7.8b   // L + 2
+        umax            v11.8b,  v3.8b,   v4.8b   // imax(imin(), 1) = limit = I
+        add             v0.8b,   v0.8b,   v0.8b   // 2*(L + 2)
+        cmtst           v14.2s,  v14.2s,  v16.2s  // if (vmask[1] & bits)
+        uxtl            v12.8h,  v12.8b
+        add             v10.8b,  v0.8b,   v11.8b  // 2*(L + 2) + limit = E
+        cmtst           v13.2s,  v13.2s,  v16.2s  // if (vmask[0] & bits)
+        uxtl            v11.8h,  v11.8b
+        uxtl            v10.8h,  v10.8b
+        and             v13.8b,  v13.8b,  v2.8b   // vmask[0] &= L != 0
+        sxtl            v14.8h,  v14.8b
+        sxtl            v13.8h,  v13.8b
+.ifc \type, y
+        sxtl            v15.8h,  v15.8b
+.endif
+        ushl            v12.8h,  v12.8h,  v31.8h
+        ushl            v11.8h,  v11.8h,  v31.8h
+        ushl            v10.8h,  v10.8h,  v31.8h
+
+.ifc \type, y
+        tst             w2,  #0x03
+        b.eq            2f
+        // wd16
+        bl              lpf_\dir\()_16_8_neon
+        b               8f
+2:
+.endif
+        tst             w7,  #0x03
+        b.eq            3f
+.ifc \type, y
+        // wd8
+        bl              lpf_\dir\()_8_8_neon
+.else
+        // wd6
+        bl              lpf_\dir\()_6_8_neon
+.endif
+        b               8f
+3:
+        // wd4
+        bl              lpf_\dir\()_4_8_neon
+.ifc \dir, h
+        b               8f
+7:
+        // For dir h, the functions above increment x0.
+        // If the whole function is skipped, increment it here instead.
+        add             x0,  x0,  x1,  lsl #3
+.else
+7:
+.endif
+8:
+        lsr             w6,  w6,  #2              // vmask[0] >>= 2
+        lsr             w7,  w7,  #2              // vmask[1] >>= 2
+.ifc \type, y
+        lsr             w2,  w2,  #2              // vmask[2] >>= 2
+.endif
+.ifc \dir, v
+        add             x0,  x0,  #16
+.else
+        // For dir h, x0 is returned incremented
+.endif
+        cbnz            w6,  1b
+
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret             x11
+endfunc
+.endm
+
+lpf_func v, y
+lpf_func h, y
+lpf_func v, uv
+lpf_func h, uv
+
+const word_12
+        .word 1, 2
+endconst
diff --git a/media/libdav1d/src/src/arm/64/looprestoration.S b/media/libdav1d/src/src/arm/64/looprestoration.S
new file mode 100644
index 0000000000..f8dc0df4d8
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/looprestoration.S
@@ -0,0 +1,1303 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+const right_ext_mask_buf
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+right_ext_mask:
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+endconst
+
+// void dav1d_wiener_filter7_8bpc_neon(pixel *p, const ptrdiff_t stride,
+//                                     const pixel (*left)[4], const pixel *lpf,
+//                                     const int w, int h,
+//                                     const int16_t filter[2][8],
+//                                     const enum LrEdgeFlags edges);
+function wiener_filter7_8bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x29, x30, [sp, #-16]!
+        mov             x29, sp
+        ld1             {v0.8h, v1.8h},  [x6]
+        tst             w7,  #4               // LR_HAVE_TOP
+        sub_sp          384*2*6
+
+        mov             w17, #(1 << 14) - (1 << 2)
+        dup             v30.8h,  w17
+        movi            v31.8h,  #8, lsl #8
+
+        // x9  - t6
+        // x10 - t5
+        // x11 - t4
+        // x12 - t3
+        // x13 - t2
+        // x14 - t1
+        // x15 - t0
+        mov             x14, sp               // t1
+        b.eq            L(no_top_7)
+
+        mov             x16, x2               // backup left
+        mov             x2,  #0
+        bl              wiener_filter7_h_8bpc_neon
+        add             x3,  x3,  x1          // lpf += stride
+        mov             x9,  x14              // t6
+        mov             x10, x14              // t5
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_8bpc_neon
+        add             x3,  x3,  x1,  lsl #2
+        add             x3,  x3,  x1          // lpf += stride*5
+        mov             x11, x14              // t4
+        add             x14, x14, #384*2      // t1 += 384*2
+        mov             x2,  x16              // left
+        mov             x16, x3               // backup lpf
+        mov             x3,  x0               // lpf = p
+        bl              wiener_filter7_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x12, x14              // t3
+        mov             x13, x14              // t2
+        b.eq            L(v1_7)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_8bpc_neon
+        mov             x13, x14              // t2
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v2_7)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v3_7)
+        add             x3,  x3,  x1          // src += stride
+
+L(main_7):
+        add             x15, x14, #384*2      // t0 = t1 + 384*2
+L(main_loop_7):
+        bl              wiener_filter7_hv_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.ne            L(main_loop_7)
+        tst             w7,  #8 // LR_HAVE_BOTTOM
+        b.eq            L(v3_7)
+
+        mov             x3,  x16              // restore lpf
+        mov             x2,  #0               // left = NULL
+        bl              wiener_filter7_hv_8bpc_neon
+        bl              wiener_filter7_hv_8bpc_neon
+L(v1_7):
+        bl              wiener_filter7_v_8bpc_neon
+
+        mov             sp,  x29
+        ldp             x29, x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(no_top_7):
+        add             x3,  x3,  x1,  lsl #2
+        add             x16, x3,  x1,  lsl #1 // lpf += stride*6, backup
+        mov             x3,  x0               // lpf = p
+
+        bl              wiener_filter7_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x9,  x14              // t6
+        mov             x10, x14              // t5
+        mov             x11, x14              // t4
+        mov             x12, x14              // t3
+        mov             x13, x14              // t2
+        b.eq            L(v1_7)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x13, x14              // t2
+        b.eq            L(v2_7)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v3_7)
+        add             x3,  x3,  x1          // src += stride
+        add             x15, x14, #384*2      // t0 = t1 + 384*2
+        bl              wiener_filter7_hv_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v3_7)
+        add             x15, x15, #384*2*4    // t0 += 384*2*4
+        bl              wiener_filter7_hv_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.ne            L(main_7)
+L(v3_7):
+        bl              wiener_filter7_v_8bpc_neon
+L(v2_7):
+        bl              wiener_filter7_v_8bpc_neon
+        b               L(v1_7)
+endfunc
+
+
+function wiener_filter7_h_8bpc_neon
+        stp             x3,  x4,  [sp, #-32]!
+        str             x14,      [sp, #16]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        // LR_HAVE_LEFT
+        cbnz            x2,  0f
+        // left == NULL
+        sub             x3,  x3,  #3
+        ld1             {v3.16b}, [x3], #16
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v3.16b},  [x3], #16
+        ld1             {v2.s}[3], [x2], #4
+        // Move x3 back to account for the last 3 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #3
+        ext             v3.16b,  v2.16b,  v3.16b, #13
+        b               2f
+
+1:
+        ld1             {v3.16b}, [x3], #16
+        // !LR_HAVE_LEFT, fill v2 with the leftmost byte
+        // and shift v3 to have 3x the first byte at the front.
+        dup             v2.16b,  v3.b[0]
+        // Move x3 back to account for the last 3 bytes we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #3
+        ext             v3.16b,  v2.16b,  v3.16b, #13
+
+2:
+        ld1             {v4.8b}, [x3], #8
+        uxtl            v2.8h,   v3.8b
+        uxtl2           v3.8h,   v3.16b
+        uxtl            v4.8h,   v4.8b
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #19
+        b.ge            4f   // If w >= 19, all used input pixels are valid
+
+        // 1 <= w < 19, w+3 pixels valid in v2-v4. For w>=9,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is v2/3/4.h[w+2]. x3 points at the next input, ie
+        // v2/3/4.h[24]. Thus read from x3[w-22] to find the padding pixel.
+        sub             w17, w4,  #22
+        // Insert padding in v2/3/4.h[w+3] onwards; fuse the +3 (*2) into the
+        // buffer pointer.
+        movrel          x6,  right_ext_mask, -6
+        ldr             b28, [x3,  w17, sxtw]
+        sub             x6,  x6,  w4,  uxtw #1
+        dup             v28.8h,  v28.h[0]
+        ld1             {v25.16b, v26.16b, v27.16b}, [x6]
+
+        bit             v2.16b,  v28.16b, v25.16b
+        bit             v3.16b,  v28.16b, v26.16b
+        bit             v4.16b,  v28.16b, v27.16b
+
+4:      // Loop horizontally
+        // Interleaving the mul/mla chains actually hurts performance
+        // significantly on Cortex A53, thus keeping mul/mla tightly
+        // chained like this.
+        ext             v17.16b, v2.16b,  v3.16b, #4
+        ext             v19.16b, v2.16b,  v3.16b, #8
+        ext             v16.16b, v2.16b,  v3.16b, #2
+        ext             v20.16b, v2.16b,  v3.16b, #10
+        ext             v21.16b, v2.16b,  v3.16b, #12
+        ext             v18.16b, v2.16b,  v3.16b, #6
+        add             v19.8h,  v19.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v16.8h
+        add             v21.8h,  v21.8h,  v2.8h
+        shl             v22.8h,  v18.8h,  #7
+        mul             v6.8h,   v18.8h,  v0.h[3]
+        mla             v6.8h,   v19.8h,  v0.h[4]
+        mla             v6.8h,   v20.8h,  v0.h[5]
+        mla             v6.8h,   v21.8h,  v0.h[6]
+
+        ext             v17.16b, v3.16b,  v4.16b, #4
+        ext             v19.16b, v3.16b,  v4.16b, #8
+        ext             v16.16b, v3.16b,  v4.16b, #2
+        ext             v20.16b, v3.16b,  v4.16b, #10
+        ext             v21.16b, v3.16b,  v4.16b, #12
+        ext             v18.16b, v3.16b,  v4.16b, #6
+
+        add             v19.8h,  v19.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v16.8h
+        add             v21.8h,  v21.8h,  v3.8h
+        shl             v23.8h,  v18.8h,  #7
+        mul             v7.8h,   v18.8h,  v0.h[3]
+        mla             v7.8h,   v19.8h,  v0.h[4]
+        mla             v7.8h,   v20.8h,  v0.h[5]
+        mla             v7.8h,   v21.8h,  v0.h[6]
+
+        sub             v22.8h,  v22.8h,  v30.8h
+        sub             v23.8h,  v23.8h,  v30.8h
+        sqadd           v6.8h,   v6.8h,   v22.8h
+        sqadd           v7.8h,   v7.8h,   v23.8h
+        sshr            v6.8h,   v6.8h,   #3
+        sshr            v7.8h,   v7.8h,   #3
+        add             v6.8h,   v6.8h,   v31.8h
+        add             v7.8h,   v7.8h,   v31.8h
+
+        subs            w4,  w4,  #16
+
+        st1             {v6.8h, v7.8h}, [x14], #32
+
+        b.le            0f
+        mov             v2.16b,  v4.16b
+        ld1             {v4.16b}, [x3], #16
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        uxtl            v3.8h,   v4.8b
+        uxtl2           v4.8h,   v4.16b
+        b.ne            4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+0:
+        ldr             x14,      [sp, #16]
+        ldp             x3,  x4,  [sp], #32
+        ret
+endfunc
+
+function wiener_filter7_v_8bpc_neon
+        // Backing up/restoring registers shifted, so that x9 gets the value
+        // of x10, etc, afterwards.
+        stp             x10, x11, [sp, #-64]!
+        stp             x12, x13, [sp, #16]
+        stp             x14, x14, [sp, #32]
+        stp             x0,  x4,  [sp, #48]
+1:
+        ld1             {v20.8h, v21.8h}, [x11], #32
+        ld1             {v24.8h, v25.8h}, [x13], #32
+
+        ld1             {v18.8h, v19.8h}, [x10], #32
+        add             v24.8h,  v24.8h,  v20.8h
+        ld1             {v26.8h, v27.8h}, [x14], #32
+
+        ld1             {v16.8h, v17.8h}, [x9],  #32
+        add             v28.8h,  v26.8h,  v18.8h
+        ld1             {v22.8h, v23.8h}, [x12], #32
+
+        add             v16.8h,  v26.8h,  v16.8h
+        add             v25.8h,  v25.8h,  v21.8h
+
+        smull           v2.4s,   v22.4h,  v1.h[3]
+        smlal           v2.4s,   v24.4h,  v1.h[4]
+        smlal           v2.4s,   v28.4h,  v1.h[5]
+        smlal           v2.4s,   v16.4h,  v1.h[6]
+        add             v29.8h,  v27.8h,  v19.8h
+        smull2          v3.4s,   v22.8h,  v1.h[3]
+        smlal2          v3.4s,   v24.8h,  v1.h[4]
+        smlal2          v3.4s,   v28.8h,  v1.h[5]
+        smlal2          v3.4s,   v16.8h,  v1.h[6]
+        add             v17.8h,  v27.8h,  v17.8h
+        smull           v4.4s,   v23.4h,  v1.h[3]
+        smlal           v4.4s,   v25.4h,  v1.h[4]
+        smlal           v4.4s,   v29.4h,  v1.h[5]
+        smlal           v4.4s,   v17.4h,  v1.h[6]
+        smull2          v5.4s,   v23.8h,  v1.h[3]
+        smlal2          v5.4s,   v25.8h,  v1.h[4]
+        smlal2          v5.4s,   v29.8h,  v1.h[5]
+        smlal2          v5.4s,   v17.8h,  v1.h[6]
+        sqrshrun        v2.4h,   v2.4s,   #11
+        sqrshrun2       v2.8h,   v3.4s,   #11
+        sqrshrun        v3.4h,   v4.4s,   #11
+        sqrshrun2       v3.8h,   v5.4s,   #11
+        sqxtun          v2.8b,   v2.8h
+        sqxtun2         v2.16b,  v3.8h
+        subs            w4,  w4,  #16
+        st1             {v2.16b}, [x0], #16
+        b.gt            1b
+
+        ldp             x0,  x4,  [sp, #48]
+        ldp             x13, x14, [sp, #32]
+        ldp             x11, x12, [sp, #16]
+        ldp             x9,  x10, [sp], #64
+
+        add             x0,  x0,  x1
+        ret
+endfunc
+
+function wiener_filter7_hv_8bpc_neon
+        // Backing up/restoring registers shifted, so that x9 gets the value
+        // of x10, etc, and x15==x9, afterwards.
+        stp             x10, x11, [sp, #-80]!
+        stp             x12, x13, [sp, #16]
+        stp             x14, x15, [sp, #32]
+        stp             x10, x0,  [sp, #48]
+        stp             x3,  x4,  [sp, #64]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        // LR_HAVE_LEFT
+        cbnz            x2,  0f
+        // left == NULL
+        sub             x3,  x3,  #3
+        ld1             {v3.16b}, [x3], #16
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v3.16b},  [x3], #16
+        ld1             {v2.s}[3], [x2], #4
+        // Move x3 back to account for the last 3 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #3
+        ext             v3.16b,  v2.16b,  v3.16b, #13
+        b               2f
+1:
+        ld1             {v3.16b}, [x3], #16
+        // !LR_HAVE_LEFT, fill v2 with the leftmost byte
+        // and shift v3 to have 3x the first byte at the front.
+        dup             v2.16b,  v3.b[0]
+        // Move x3 back to account for the last 3 bytes we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #3
+        ext             v3.16b,  v2.16b,  v3.16b, #13
+
+2:
+        ld1             {v4.8b}, [x3], #8
+        uxtl            v2.8h,   v3.8b
+        uxtl2           v3.8h,   v3.16b
+        uxtl            v4.8h,   v4.8b
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #19
+        b.ge            4f   // If w >= 19, all used input pixels are valid
+
+        // 1 <= w < 19, w+3 pixels valid in v2-v4. For w>=9,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is v2/3/4.h[w+2]. x3 points at the next input, ie
+        // v2/3/4.h[24]. Thus read from x3[w-22] to find the padding pixel.
+        sub             w17, w4,  #22
+        // Insert padding in v2/3/4.h[w+3] onwards; fuse the +3 (*2) into the
+        // buffer pointer.
+        movrel          x6,  right_ext_mask, -6
+        ldr             b28, [x3,  w17, sxtw]
+        sub             x6,  x6,  w4,  uxtw #1
+        dup             v28.8h,  v28.h[0]
+        ld1             {v25.16b, v26.16b, v27.16b}, [x6]
+
+        bit             v2.16b,  v28.16b, v25.16b
+        bit             v3.16b,  v28.16b, v26.16b
+        bit             v4.16b,  v28.16b, v27.16b
+
+4:      // Loop horizontally
+        ext             v17.16b, v2.16b,  v3.16b, #4
+        ext             v19.16b, v2.16b,  v3.16b, #8
+        ext             v16.16b, v2.16b,  v3.16b, #2
+        ext             v20.16b, v2.16b,  v3.16b, #10
+        ext             v21.16b, v2.16b,  v3.16b, #12
+        ext             v18.16b, v2.16b,  v3.16b, #6
+        add             v19.8h,  v19.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v16.8h
+        add             v21.8h,  v21.8h,  v2.8h
+        shl             v22.8h,  v18.8h,  #7
+        mul             v6.8h,   v18.8h,  v0.h[3]
+        mla             v6.8h,   v19.8h,  v0.h[4]
+        mla             v6.8h,   v20.8h,  v0.h[5]
+        mla             v6.8h,   v21.8h,  v0.h[6]
+
+        ext             v17.16b, v3.16b,  v4.16b, #4
+        ext             v19.16b, v3.16b,  v4.16b, #8
+        ext             v16.16b, v3.16b,  v4.16b, #2
+        ext             v20.16b, v3.16b,  v4.16b, #10
+        ext             v21.16b, v3.16b,  v4.16b, #12
+        ext             v18.16b, v3.16b,  v4.16b, #6
+
+        add             v19.8h,  v19.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v16.8h
+        add             v21.8h,  v21.8h,  v3.8h
+        shl             v23.8h,  v18.8h,  #7
+        mul             v7.8h,   v18.8h,  v0.h[3]
+        mla             v7.8h,   v19.8h,  v0.h[4]
+        mla             v7.8h,   v20.8h,  v0.h[5]
+        mla             v7.8h,   v21.8h,  v0.h[6]
+
+        ld1             {v20.8h, v21.8h}, [x11], #32
+
+        sub             v22.8h,  v22.8h,  v30.8h
+        sub             v23.8h,  v23.8h,  v30.8h
+        ld1             {v26.8h, v27.8h}, [x13], #32
+        sqadd           v6.8h,   v6.8h,   v22.8h
+        sqadd           v7.8h,   v7.8h,   v23.8h
+        ld1             {v18.8h, v19.8h}, [x10], #32
+        sshr            v6.8h,   v6.8h,   #3
+        sshr            v7.8h,   v7.8h,   #3
+        ld1             {v28.8h, v29.8h}, [x14], #32
+        add             v6.8h,   v6.8h,   v31.8h
+        add             v7.8h,   v7.8h,   v31.8h
+
+        ld1             {v16.8h, v17.8h}, [x9],  #32
+        add             v26.8h,  v20.8h,  v26.8h
+
+        ld1             {v24.8h, v25.8h}, [x12], #32
+        add             v28.8h,  v18.8h,  v28.8h
+
+        add             v16.8h,  v16.8h,  v6.8h
+        add             v27.8h,  v21.8h,  v27.8h
+
+        smull           v18.4s,  v24.4h,  v1.h[3]
+        smlal           v18.4s,  v26.4h,  v1.h[4]
+        smlal           v18.4s,  v28.4h,  v1.h[5]
+        smlal           v18.4s,  v16.4h,  v1.h[6]
+        add             v29.8h,  v19.8h,  v29.8h
+        smull2          v19.4s,  v24.8h,  v1.h[3]
+        smlal2          v19.4s,  v26.8h,  v1.h[4]
+        smlal2          v19.4s,  v28.8h,  v1.h[5]
+        smlal2          v19.4s,  v16.8h,  v1.h[6]
+        add             v17.8h,  v17.8h,  v7.8h
+        smull           v20.4s,  v25.4h,  v1.h[3]
+        smlal           v20.4s,  v27.4h,  v1.h[4]
+        smlal           v20.4s,  v29.4h,  v1.h[5]
+        smlal           v20.4s,  v17.4h,  v1.h[6]
+        smull2          v21.4s,  v25.8h,  v1.h[3]
+        smlal2          v21.4s,  v27.8h,  v1.h[4]
+        smlal2          v21.4s,  v29.8h,  v1.h[5]
+        smlal2          v21.4s,  v17.8h,  v1.h[6]
+        sqrshrun        v18.4h,  v18.4s,  #11
+        sqrshrun2       v18.8h,  v19.4s,  #11
+        sqrshrun        v19.4h,  v20.4s,  #11
+        sqrshrun2       v19.8h,  v21.4s,  #11
+        st1             {v6.8h, v7.8h}, [x15], #32
+        sqxtun          v18.8b,  v18.8h
+        sqxtun2         v18.16b, v19.8h
+        subs            w4,  w4,  #16
+
+        st1             {v18.16b}, [x0], #16
+
+        b.le            0f
+        mov             v2.16b,  v4.16b
+        ld1             {v4.16b}, [x3], #16
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        uxtl            v3.8h,   v4.8b
+        uxtl2           v4.8h,   v4.16b
+        b.ne            4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+0:
+        ldp             x3,  x4,  [sp, #64]
+        ldp             x15, x0,  [sp, #48]
+        ldp             x13, x14, [sp, #32]
+        ldp             x11, x12, [sp, #16]
+        ldp             x9,  x10, [sp], #80
+
+        add             x3,  x3,  x1
+        add             x0,  x0,  x1
+
+        ret
+endfunc
+
+// void dav1d_wiener_filter5_8bpc_neon(pixel *p, const ptrdiff_t stride,
+//                                     const pixel (*left)[4], const pixel *lpf,
+//                                     const int w, int h,
+//                                     const int16_t filter[2][8],
+//                                     const enum LrEdgeFlags edges);
+function wiener_filter5_8bpc_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x29, x30, [sp, #-16]!
+        mov             x29, sp
+        ld1             {v0.8h, v1.8h},  [x6]
+        tst             w7,  #4               // LR_HAVE_TOP
+        sub_sp          384*2*4
+
+        mov             w17, #(1 << 14) - (1 << 2)
+        dup             v30.8h,  w17
+        movi            v31.8h,  #8, lsl #8
+
+        // x11 - t4
+        // x12 - t3
+        // x13 - t2
+        // x14 - t1
+        // x15 - t0
+        mov             x14, sp               // t1
+        b.eq            L(no_top_5)
+
+        mov             x16, x2               // backup left
+        mov             x2,  #0
+        bl              wiener_filter5_h_8bpc_neon
+        add             x3,  x3,  x1          // lpf += stride
+        mov             x11, x14              // t4
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter5_h_8bpc_neon
+        add             x3,  x3,  x1,  lsl #2
+        add             x3,  x3,  x1          // lpf += stride*5
+        mov             x12, x14              // t3
+        add             x14, x14, #384*2      // t1 += 384*2
+        mov             x2,  x16              // left
+        mov             x16, x3               // backup lpf
+        mov             x3,  x0               // lpf = p
+        bl              wiener_filter5_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x13, x14              // t2
+        b.eq            L(v1_5)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter5_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v2_5)
+        add             x3,  x3,  x1          // src += stride
+
+L(main_5):
+        mov             x15, x11              // t0 = t4
+L(main_loop_5):
+        bl              wiener_filter5_hv_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.ne            L(main_loop_5)
+        tst             w7,  #8 // LR_HAVE_BOTTOM
+        b.eq            L(v2_5)
+
+        mov             x3,  x16              // restore lpf
+        mov             x2,  #0               // left = NULL
+        bl              wiener_filter5_hv_8bpc_neon
+        bl              wiener_filter5_hv_8bpc_neon
+L(end_5):
+
+        mov             sp,  x29
+        ldp             x29, x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(no_top_5):
+        add             x3,  x3,  x1,  lsl #2
+        add             x16, x3,  x1,  lsl #1 // lpf += stride*6, backup
+        mov             x3,  x0               // lpf = p
+
+        bl              wiener_filter5_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x11, x14              // t4
+        mov             x12, x14              // t3
+        mov             x13, x14              // t2
+        b.eq            L(v1_5)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter5_h_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v2_5)
+        add             x3,  x3,  x1          // src += stride
+        add             x15, x14, #384*2      // t0 = t1 + 384*2
+        bl              wiener_filter5_hv_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v2_5)
+        add             x15, x15, #384*2*3    // t0 += 384*2*3
+        bl              wiener_filter5_hv_8bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.ne            L(main_5)
+L(v2_5):
+        bl              wiener_filter5_v_8bpc_neon
+        add             x0,  x0,  x1
+        mov             x11, x12
+        mov             x12, x13
+        mov             x13, x14
+L(v1_5):
+        bl              wiener_filter5_v_8bpc_neon
+        b               L(end_5)
+endfunc
+
+
+function wiener_filter5_h_8bpc_neon
+        stp             x3,  x4,  [sp, #-32]!
+        str             x14,      [sp, #16]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        // LR_HAVE_LEFT
+        cbnz            x2,  0f
+        // left == NULL
+        sub             x3,  x3,  #2
+        ld1             {v3.16b}, [x3], #16
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v3.16b},  [x3], #16
+        ld1             {v2.s}[3], [x2], #4
+        // Move x3 back to account for the last 2 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #2
+        ext             v3.16b,  v2.16b,  v3.16b, #14
+        b               2f
+
+1:
+        ld1             {v3.16b}, [x3], #16
+        // !LR_HAVE_LEFT, fill v2 with the leftmost byte
+        // and shift v3 to have 3x the first byte at the front.
+        dup             v2.16b,  v3.b[0]
+        // Move x3 back to account for the last 2 bytes we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #2
+        ext             v3.16b,  v2.16b,  v3.16b, #14
+
+2:
+        ld1             {v4.8b}, [x3], #8
+        uxtl            v2.8h,   v3.8b
+        uxtl2           v3.8h,   v3.16b
+        uxtl            v4.8h,   v4.8b
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #18
+        b.ge            4f   // If w >= 18, all used input pixels are valid
+
+        // 1 <= w < 18, w+2 pixels valid in v2-v4. For w>=9,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is v2/3/4.h[w+2]. x3 points at the next input, ie
+        // v2/3/4.h[24]. Thus read from x3[w-23] to find the padding pixel.
+        sub             w17, w4,  #23
+        // Insert padding in v2/3/4.h[w+2] onwards; fuse the +2 (*2) into the
+        // buffer pointer.
+        movrel          x6,  right_ext_mask, -4
+        ldr             b28, [x3,  w17, sxtw]
+        sub             x6,  x6,  w4,  uxtw #1
+        dup             v28.8h,  v28.h[0]
+        ld1             {v25.16b, v26.16b, v27.16b}, [x6]
+
+        bit             v2.16b,  v28.16b, v25.16b
+        bit             v3.16b,  v28.16b, v26.16b
+        bit             v4.16b,  v28.16b, v27.16b
+
+4:      // Loop horizontally
+        // Interleaving the mul/mla chains actually hurts performance
+        // significantly on Cortex A53, thus keeping mul/mla tightly
+        // chained like this.
+        ext             v16.16b, v2.16b,  v3.16b, #2
+        ext             v18.16b, v2.16b,  v3.16b, #6
+        ext             v19.16b, v2.16b,  v3.16b, #8
+        ext             v17.16b, v2.16b,  v3.16b, #4
+        add             v18.8h,  v18.8h,  v16.8h
+        add             v19.8h,  v19.8h,  v2.8h
+        shl             v22.8h,  v17.8h,  #7
+        mul             v6.8h,   v17.8h,  v0.h[3]
+        mla             v6.8h,   v18.8h,  v0.h[4]
+        mla             v6.8h,   v19.8h,  v0.h[5]
+
+        ext             v16.16b, v3.16b,  v4.16b, #2
+        ext             v18.16b, v3.16b,  v4.16b, #6
+        ext             v19.16b, v3.16b,  v4.16b, #8
+        ext             v17.16b, v3.16b,  v4.16b, #4
+        add             v18.8h,  v18.8h,  v16.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        shl             v23.8h,  v17.8h,  #7
+        mul             v7.8h,   v17.8h,  v0.h[3]
+        mla             v7.8h,   v18.8h,  v0.h[4]
+        mla             v7.8h,   v19.8h,  v0.h[5]
+
+        sub             v22.8h,  v22.8h,  v30.8h
+        sub             v23.8h,  v23.8h,  v30.8h
+        sqadd           v6.8h,   v6.8h,   v22.8h
+        sqadd           v7.8h,   v7.8h,   v23.8h
+        sshr            v6.8h,   v6.8h,   #3
+        sshr            v7.8h,   v7.8h,   #3
+        add             v6.8h,   v6.8h,   v31.8h
+        add             v7.8h,   v7.8h,   v31.8h
+
+        subs            w4,  w4,  #16
+
+        st1             {v6.8h, v7.8h}, [x14], #32
+
+        b.le            0f
+        mov             v2.16b,  v4.16b
+        ld1             {v4.16b}, [x3], #16
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        uxtl            v3.8h,   v4.8b
+        uxtl2           v4.8h,   v4.16b
+        b.ne            4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+0:
+        ldr             x14,      [sp, #16]
+        ldp             x3,  x4,  [sp], #32
+        ret
+endfunc
+
+function wiener_filter5_v_8bpc_neon
+        stp             x11, x12, [sp, #-48]!
+        stp             x13, x14, [sp, #16]
+        stp             x0,  x4,  [sp, #32]
+1:
+        ld1             {v18.8h, v19.8h}, [x12], #32
+        ld1             {v22.8h, v23.8h}, [x14], #32
+        ld1             {v16.8h, v17.8h}, [x11], #32
+
+        add             v24.8h,  v22.8h,  v18.8h
+        ld1             {v20.8h, v21.8h}, [x13], #32
+        add             v16.8h,  v22.8h,  v16.8h
+        add             v25.8h,  v23.8h,  v19.8h
+
+        smull           v2.4s,   v20.4h,  v1.h[3]
+        smlal           v2.4s,   v24.4h,  v1.h[4]
+        smlal           v2.4s,   v16.4h,  v1.h[5]
+        add             v17.8h,  v23.8h,  v17.8h
+        smull2          v3.4s,   v20.8h,  v1.h[3]
+        smlal2          v3.4s,   v24.8h,  v1.h[4]
+        smlal2          v3.4s,   v16.8h,  v1.h[5]
+        smull           v4.4s,   v21.4h,  v1.h[3]
+        smlal           v4.4s,   v25.4h,  v1.h[4]
+        smlal           v4.4s,   v17.4h,  v1.h[5]
+        smull2          v5.4s,   v21.8h,  v1.h[3]
+        smlal2          v5.4s,   v25.8h,  v1.h[4]
+        smlal2          v5.4s,   v17.8h,  v1.h[5]
+        sqrshrun        v2.4h,   v2.4s,   #11
+        sqrshrun2       v2.8h,   v3.4s,   #11
+        sqrshrun        v3.4h,   v4.4s,   #11
+        sqrshrun2       v3.8h,   v5.4s,   #11
+        sqxtun          v2.8b,   v2.8h
+        sqxtun2         v2.16b,  v3.8h
+        subs            w4,  w4,  #16
+        st1             {v2.16b}, [x0], #16
+        b.gt            1b
+
+        ldp             x0,  x4,  [sp, #32]
+        ldp             x13, x14, [sp, #16]
+        ldp             x11, x12, [sp], #48
+
+        ret
+endfunc
+
+function wiener_filter5_hv_8bpc_neon
+        // Backing up/restoring registers shifted, so that x11 gets the value
+        // of x12, etc, and x15==x11, afterwards.
+        stp             x12, x13, [sp, #-64]!
+        stp             x14, x15, [sp, #16]
+        stp             x12, x0,  [sp, #32]
+        stp             x3,  x4,  [sp, #48]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        // LR_HAVE_LEFT
+        cbnz            x2,  0f
+        // left == NULL
+        sub             x3,  x3,  #2
+        ld1             {v3.16b}, [x3], #16
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v3.16b},  [x3], #16
+        ld1             {v2.s}[3], [x2], #4
+        // Move x3 back to account for the last 2 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #2
+        ext             v3.16b,  v2.16b,  v3.16b, #14
+        b               2f
+1:
+        ld1             {v3.16b}, [x3], #16
+        // !LR_HAVE_LEFT, fill v2 with the leftmost byte
+        // and shift v3 to have 2x the first byte at the front.
+        dup             v2.16b,  v3.b[0]
+        // Move x3 back to account for the last 2 bytes we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #2
+        ext             v3.16b, v2.16b, v3.16b, #14
+
+2:
+        ld1             {v4.8b}, [x3], #8
+        uxtl            v2.8h,  v3.8b
+        uxtl2           v3.8h,  v3.16b
+        uxtl            v4.8h,  v4.8b
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #18
+        b.ge            4f   // If w >= 18, all used input pixels are valid
+
+        // 1 <= w < 18, w+2 pixels valid in v2-v4. For w>=9,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is v2/3/4.h[w+1]. x3 points at the next input, ie
+        // v2/3/4.h[24]. Thus read from x3[w-23] to find the padding pixel.
+        sub             w17, w4,  #23
+        // Insert padding in v2/3/4.h[w+2] onwards; fuse the +2 (*2) into the
+        // buffer pointer.
+        movrel          x6,  right_ext_mask, -4
+        ldr             b28, [x3,  w17, sxtw]
+        sub             x6,  x6,  w4,  uxtw #1
+        dup             v28.8h,  v28.h[0]
+        ld1             {v25.16b, v26.16b, v27.16b}, [x6]
+
+        bit             v2.16b,  v28.16b, v25.16b
+        bit             v3.16b,  v28.16b, v26.16b
+        bit             v4.16b,  v28.16b, v27.16b
+
+4:      // Loop horizontally
+
+        ext             v16.16b, v2.16b,  v3.16b, #2
+        ext             v18.16b, v2.16b,  v3.16b, #6
+        ext             v19.16b, v2.16b,  v3.16b, #8
+        ext             v17.16b, v2.16b,  v3.16b, #4
+        add             v18.8h,  v18.8h,  v16.8h
+        add             v19.8h,  v19.8h,  v2.8h
+        shl             v22.8h,  v17.8h,  #7
+        mul             v6.8h,   v17.8h,  v0.h[3]
+        mla             v6.8h,   v18.8h,  v0.h[4]
+        mla             v6.8h,   v19.8h,  v0.h[5]
+
+        ext             v16.16b, v3.16b,  v4.16b, #2
+        ext             v18.16b, v3.16b,  v4.16b, #6
+        ext             v19.16b, v3.16b,  v4.16b, #8
+        ext             v17.16b, v3.16b,  v4.16b, #4
+        add             v18.8h,  v18.8h,  v16.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        shl             v23.8h,  v17.8h,  #7
+        mul             v7.8h,   v17.8h,  v0.h[3]
+        mla             v7.8h,   v18.8h,  v0.h[4]
+        mla             v7.8h,   v19.8h,  v0.h[5]
+
+        ld1             {v18.8h, v19.8h}, [x12], #32
+
+        sub             v22.8h,  v22.8h,  v30.8h
+        sub             v23.8h,  v23.8h,  v30.8h
+        ld1             {v24.8h, v25.8h}, [x14], #32
+        sqadd           v6.8h,   v6.8h,   v22.8h
+        sqadd           v7.8h,   v7.8h,   v23.8h
+        ld1             {v16.8h, v17.8h}, [x11], #32
+        sshr            v6.8h,   v6.8h,   #3
+        sshr            v7.8h,   v7.8h,   #3
+        ld1             {v20.8h, v21.8h}, [x13], #32
+        add             v6.8h,   v6.8h,   v31.8h
+        add             v7.8h,   v7.8h,   v31.8h
+
+        add             v24.8h,  v24.8h,  v18.8h
+        add             v16.8h,  v16.8h,  v6.8h
+
+        smull           v18.4s,  v20.4h,  v1.h[3]
+        smlal           v18.4s,  v24.4h,  v1.h[4]
+        smlal           v18.4s,  v16.4h,  v1.h[5]
+        add             v25.8h,  v25.8h,  v19.8h
+        smull2          v19.4s,  v20.8h,  v1.h[3]
+        smlal2          v19.4s,  v24.8h,  v1.h[4]
+        smlal2          v19.4s,  v16.8h,  v1.h[5]
+        add             v17.8h,  v17.8h,  v7.8h
+        smull           v20.4s,  v21.4h,  v1.h[3]
+        smlal           v20.4s,  v25.4h,  v1.h[4]
+        smlal           v20.4s,  v17.4h,  v1.h[5]
+        smull2          v21.4s,  v21.8h,  v1.h[3]
+        smlal2          v21.4s,  v25.8h,  v1.h[4]
+        smlal2          v21.4s,  v17.8h,  v1.h[5]
+        sqrshrun        v18.4h,  v18.4s,  #11
+        sqrshrun2       v18.8h,  v19.4s,  #11
+        sqrshrun        v19.4h,  v20.4s,  #11
+        sqrshrun2       v19.8h,  v21.4s,  #11
+        st1             {v6.8h, v7.8h}, [x15], #32
+        sqxtun          v18.8b,  v18.8h
+        sqxtun2         v18.16b, v19.8h
+        subs            w4,  w4,  #16
+
+        st1             {v18.16b}, [x0], #16
+
+        b.le            0f
+        mov             v2.16b,  v4.16b
+        ld1             {v4.16b}, [x3], #16
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        uxtl            v3.8h,   v4.8b
+        uxtl2           v4.8h,   v4.16b
+        b.ne            4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+0:
+        ldp             x3,  x4,  [sp, #48]
+        ldp             x15, x0,  [sp, #32]
+        ldp             x13, x14, [sp, #16]
+        ldp             x11, x12, [sp], #64
+
+        add             x3,  x3,  x1
+        add             x0,  x0,  x1
+
+        ret
+endfunc
+
+#include "looprestoration_tmpl.S"
+
+// void dav1d_sgr_box3_row_h_8bpc_neon(int32_t *sumsq, int16_t *sum,
+//                                     const pixel (*left)[4],
+//                                     const pixel *src, const int w,
+//                                     const enum LrEdgeFlags edges);
+function sgr_box3_row_h_8bpc_neon, export=1
+        add             w4,  w4,  #2 // w += 2
+
+        tst             w5,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        cbnz            x2,  0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             x3,  x3,  #2
+        ld1             {v0.16b}, [x3], #16
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v0.16b},  [x3], #16
+        ld1             {v1.s}[3], [x2]
+        // Move x3 back to account for the last 2 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #2
+        ext             v0.16b, v1.16b, v0.16b, #14
+        b               2f
+
+1:
+        ld1             {v0.16b}, [x3], #16
+        // !LR_HAVE_LEFT, fill v1 with the leftmost byte
+        // and shift v0 to have 2x the first byte at the front.
+        dup             v1.16b, v0.b[0]
+        // Move x3 back to account for the last 2 bytes we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #2
+        ext             v0.16b, v1.16b, v0.16b, #14
+
+2:
+        umull           v1.8h,   v0.8b,   v0.8b
+        umull2          v2.8h,   v0.16b,  v0.16b
+
+        tst             w5,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+        // If we'll need to pad the right edge, load that byte to pad with
+        // here since we can find it pretty easily from here.
+        sub             w13, w4, #(2 + 16 - 2 + 1)
+        ldr             b30, [x3,  w13, sxtw]
+        // Fill v30 with the right padding pixel
+        dup             v30.16b, v30.b[0]
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #10
+        b.ge            4f   // If w >= 10, all used input pixels are valid
+
+        // 1 <= w < 10, w pixels valid in v0. For w=9, this ends up called
+        // again; it's not strictly needed in those cases (we pad enough here),
+        // but keeping the code as simple as possible.
+
+        // Insert padding in v0.b[w] onwards
+        movrel          x13, right_ext_mask
+        sub             x13, x13, w4,  uxtw
+        ld1             {v29.16b}, [x13]
+
+        bit             v0.16b,  v30.16b, v29.16b
+
+        // Update the precalculated squares
+        umull           v1.8h,   v0.8b,   v0.8b
+        umull2          v2.8h,   v0.16b,  v0.16b
+
+4:      // Loop horizontally
+        ext             v16.16b, v0.16b,  v0.16b, #1
+        ext             v17.16b, v0.16b,  v0.16b, #2
+        uaddl           v3.8h,   v0.8b,   v16.8b
+        ext             v20.16b, v1.16b,  v2.16b, #2
+        uaddw           v3.8h,   v3.8h,   v17.8b
+
+        ext             v21.16b, v1.16b,  v2.16b, #4
+
+        uaddl           v26.4s,  v1.4h,   v20.4h
+        uaddl2          v27.4s,  v1.8h,   v20.8h
+        uaddw           v26.4s,  v26.4s,  v21.4h
+        uaddw2          v27.4s,  v27.4s,  v21.8h
+
+        subs            w4,  w4,  #8
+
+        st1             {v3.8h},         [x1],  #16
+        st1             {v26.4s,v27.4s}, [x0],  #32
+
+        b.le            9f
+        tst             w5,  #2 // LR_HAVE_RIGHT
+        ld1             {v3.8b},  [x3],  #8
+        mov             v1.16b,  v2.16b
+        ext             v0.16b,  v0.16b,  v3.16b, #8
+        umull           v2.8h,   v3.8b,   v3.8b
+
+        b.ne            4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        ret
+endfunc
+
+// void dav1d_sgr_box5_row_h_8bpc_neon(int32_t *sumsq, int16_t *sum,
+//                                     const pixel (*left)[4],
+//                                     const pixel *src, const int w,
+//                                     const enum LrEdgeFlags edges);
+function sgr_box5_row_h_8bpc_neon, export=1
+        add             w4,  w4,  #2 // w += 2
+
+        tst             w5,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        cbnz            x2,  0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             x3,  x3,  #3
+        ld1             {v0.16b}, [x3], #16
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v0.16b},  [x3], #16
+        ld1             {v1.s}[3], [x2], #4
+        // Move x3 back to account for the last 3 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #3
+        ext             v0.16b, v1.16b, v0.16b, #13
+        b               2f
+
+1:
+        ld1             {v0.16b}, [x3], #16
+        // !LR_HAVE_LEFT, fill v1 with the leftmost byte
+        // and shift v0 to have 3x the first byte at the front.
+        dup             v1.16b, v0.b[0]
+        // Move x3 back to account for the last 3 bytes we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #3
+        ext             v0.16b, v1.16b, v0.16b, #13
+
+2:
+        umull           v1.8h,   v0.8b,   v0.8b
+        umull2          v2.8h,   v0.16b,  v0.16b
+
+        tst             w5,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+        // If we'll need to pad the right edge, load that byte to pad with
+        // here since we can find it pretty easily from here.
+        sub             w13, w4, #(2 + 16 - 3 + 1)
+        ldr             b30, [x3,  w13, sxtw]
+        // Fill v30 with the right padding pixel
+        dup             v30.16b, v30.b[0]
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #11
+        b.ge            4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+1 pixels valid in v0. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // Insert padding in v0.b[w+1] onwards; fuse the +1 into the
+        // buffer pointer.
+        movrel          x13, right_ext_mask, -1
+        sub             x13, x13, w4,  uxtw
+        ld1             {v29.16b}, [x13]
+
+        bit             v0.16b,  v30.16b, v29.16b
+
+        // Update the precalculated squares
+        umull           v1.8h,   v0.8b,   v0.8b
+        umull2          v2.8h,   v0.16b,  v0.16b
+
+4:      // Loop horizontally
+        ext             v16.16b, v0.16b,  v0.16b, #1
+        ext             v17.16b, v0.16b,  v0.16b, #2
+        ext             v18.16b, v0.16b,  v0.16b, #3
+        ext             v19.16b, v0.16b,  v0.16b, #4
+        uaddl           v3.8h,   v0.8b,   v16.8b
+        uaddl           v24.8h,  v17.8b,  v18.8b
+        uaddw           v3.8h,   v3.8h,   v19.8b
+        add             v3.8h,   v3.8h,   v24.8h
+
+        ext             v16.16b, v1.16b,  v2.16b, #2
+        ext             v17.16b, v1.16b,  v2.16b, #4
+        ext             v18.16b, v1.16b,  v2.16b, #6
+        ext             v19.16b, v1.16b,  v2.16b, #8
+
+        uaddl           v26.4s,  v1.4h,   v16.4h
+        uaddl2          v27.4s,  v1.8h,   v16.8h
+        uaddl           v16.4s,  v17.4h,  v18.4h
+        uaddl2          v17.4s,  v17.8h,  v18.8h
+        uaddw           v26.4s,  v26.4s,  v19.4h
+        uaddw2          v27.4s,  v27.4s,  v19.8h
+        add             v26.4s,  v26.4s,  v16.4s
+        add             v27.4s,  v27.4s,  v17.4s
+
+        subs            w4,  w4,  #8
+
+        st1             {v3.8h},         [x1],  #16
+        st1             {v26.4s,v27.4s}, [x0],  #32
+
+        b.le            9f
+        tst             w5,  #2 // LR_HAVE_RIGHT
+        ld1             {v3.8b},  [x3],  #8
+        mov             v1.16b,  v2.16b
+        ext             v0.16b,  v0.16b,  v3.16b, #8
+        umull           v2.8h,   v3.8b,   v3.8b
+
+        b.ne            4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        ret
+endfunc
+
+// void dav1d_sgr_box35_row_h_8bpc_neon(int32_t *sumsq3, int16_t *sum3,
+//                                      int32_t *sumsq5, int16_t *sum5,
+//                                      const pixel (*left)[4],
+//                                      const pixel *src, const int w,
+//                                      const enum LrEdgeFlags edges);
+function sgr_box35_row_h_8bpc_neon, export=1
+        add             w6,  w6,  #2 // w += 2
+
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        cbnz            x4,  0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             x5,  x5,  #3
+        ld1             {v0.16b},  [x5], #16
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v0.16b},  [x5], #16
+        ld1             {v1.s}[3], [x4], #4
+        // Move x3 back to account for the last 3 bytes we loaded earlier,
+        // which we'll shift out.
+        sub             x5,  x5,  #3
+        ext             v0.16b, v1.16b, v0.16b, #13
+        b               2f
+
+1:
+        ld1             {v0.16b}, [x5], #16
+        // !LR_HAVE_LEFT, fill v1 with the leftmost byte
+        // and shift v0 to have 3x the first byte at the front.
+        dup             v1.16b, v0.b[0]
+        // Move x3 back to account for the last 3 bytes we loaded before,
+        // which we shifted out.
+        sub             x5,  x5,  #3
+        ext             v0.16b, v1.16b, v0.16b, #13
+
+2:
+        umull           v1.8h,   v0.8b,   v0.8b
+        umull2          v2.8h,   v0.16b,  v0.16b
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+        // If we'll need to pad the right edge, load that byte to pad with
+        // here since we can find it pretty easily from here.
+        sub             w13, w6, #(2 + 16 - 3 + 1)
+        ldr             b30, [x5,  w13, sxtw]
+        // Fill v30 with the right padding pixel
+        dup             v30.16b, v30.b[0]
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w6,  #11
+        b.ge            4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+1 pixels valid in v0. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // Insert padding in v0.b[w+1] onwards; fuse the +1 into the
+        // buffer pointer.
+        movrel          x13, right_ext_mask, -1
+        sub             x13, x13, w6,  uxtw
+        ld1             {v29.16b}, [x13]
+
+        bit             v0.16b,  v30.16b, v29.16b
+
+        // Update the precalculated squares
+        umull           v1.8h,   v0.8b,   v0.8b
+        umull2          v2.8h,   v0.16b,  v0.16b
+
+4:      // Loop horizontally
+        ext             v16.16b, v0.16b,  v0.16b, #1
+        ext             v17.16b, v0.16b,  v0.16b, #2
+        ext             v19.16b, v0.16b,  v0.16b, #4
+        ext             v18.16b, v0.16b,  v0.16b, #3
+        uaddl           v3.8h,   v16.8b,  v17.8b
+        uaddl           v24.8h,  v0.8b,   v19.8b
+        uaddw           v3.8h,   v3.8h,   v18.8b
+
+        ext             v16.16b, v1.16b,  v2.16b, #2
+        ext             v17.16b, v1.16b,  v2.16b, #4
+        ext             v19.16b, v1.16b,  v2.16b, #8
+        ext             v18.16b, v1.16b,  v2.16b, #6
+
+        st1             {v3.8h},         [x1], #16
+        add             v3.8h,   v3.8h,   v24.8h
+
+        uaddl           v26.4s,  v16.4h,  v17.4h
+        uaddl2          v27.4s,  v16.8h,  v17.8h
+        uaddl           v16.4s,  v1.4h,   v19.4h
+        uaddl2          v17.4s,  v1.8h,   v19.8h
+        uaddw           v26.4s,  v26.4s,  v18.4h
+        uaddw2          v27.4s,  v27.4s,  v18.8h
+
+        st1             {v26.4s,v27.4s}, [x0], #32
+        add             v26.4s,  v26.4s,  v16.4s
+        add             v27.4s,  v27.4s,  v17.4s
+
+        subs            w6,  w6,  #8
+
+        st1             {v3.8h},         [x3], #16
+        st1             {v26.4s,v27.4s}, [x2], #32
+
+        b.le            9f
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        ld1             {v3.8b},  [x5],  #8
+        mov             v1.16b,  v2.16b
+        ext             v0.16b,  v0.16b,  v3.16b, #8
+        umull           v2.8h,   v3.8b,   v3.8b
+
+        b.ne            4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        ret
+endfunc
+
+sgr_funcs 8
diff --git a/media/libdav1d/src/src/arm/64/looprestoration16.S b/media/libdav1d/src/src/arm/64/looprestoration16.S
new file mode 100644
index 0000000000..4b62a95710
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/looprestoration16.S
@@ -0,0 +1,1388 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+const right_ext_mask_buf
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+right_ext_mask:
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+endconst
+
+// void dav1d_wiener_filter7_16bpc_neon(pixel *p, const ptrdiff_t p_stride,
+//                                      const pixel (*left)[4], const pixel *lpf,
+//                                      const int w, int h,
+//                                      const int16_t filter[2][8],
+//                                      const enum LrEdgeFlags edges,
+//                                      const int bitdepth_max);
+function wiener_filter7_16bpc_neon, export=1
+        ldr             w8,  [sp]
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x29, x30, [sp, #-32]!
+        stp             d8,  d9,  [sp, #16]
+        mov             x29, sp
+        ld1             {v0.8h, v1.8h},  [x6]
+        tst             w7,  #4               // LR_HAVE_TOP
+        sub_sp          384*2*6
+
+        dup             v28.8h,  w8           // bitdepth_max
+        clz             w8,  w8
+        movi            v30.4s,  #1
+        sub             w10, w8,  #38         // -(bitdepth + 6)
+        sub             w11, w8,  #11         // round_bits_v
+        sub             w8,  w8,  #25         // -round_bits_h
+        neg             w10, w10              // bitdepth + 6
+        neg             w11, w11              // -round_bits_v
+        dup             v2.4s,   w10
+        dup             v29.4s,  w8           // -round_bits_h
+        dup             v27.4s,  w11          // -round_bits_v
+        movi            v31.8h,  #0x20, lsl #8  // 1 << 13 = 8192
+        ushl            v30.4s,  v30.4s,  v2.4s // 1 << (bitdepth + 6)
+
+        zip1            v0.2d,   v0.2d,   v1.2d // move vertical coeffs to v0.h[4-7], freeing up v1
+
+        // x9  - t6
+        // x10 - t5
+        // x11 - t4
+        // x12 - t3
+        // x13 - t2
+        // x14 - t1
+        // x15 - t0
+        mov             x14, sp               // t1
+        b.eq            L(no_top_7)
+
+        mov             x16, x2               // backup left
+        mov             x2,  #0
+        bl              wiener_filter7_h_16bpc_neon
+        add             x3,  x3,  x1          // lpf += stride
+        mov             x9,  x14              // t6
+        mov             x10, x14              // t5
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_16bpc_neon
+        add             x3,  x3,  x1,  lsl #2
+        add             x3,  x3,  x1          // lpf += stride*5
+        mov             x11, x14              // t4
+        add             x14, x14, #384*2      // t1 += 384*2
+        mov             x2,  x16              // left
+        mov             x16, x3               // backup lpf
+        mov             x3,  x0               // lpf = p
+        bl              wiener_filter7_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x12, x14              // t3
+        mov             x13, x14              // t2
+        b.eq            L(v1_7)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_16bpc_neon
+        mov             x13, x14              // t2
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v2_7)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v3_7)
+        add             x3,  x3,  x1          // src += stride
+
+L(main_7):
+        add             x15, x14, #384*2      // t0 = t1 + 384*2
+L(main_loop_7):
+        bl              wiener_filter7_hv_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.ne            L(main_loop_7)
+        tst             w7,  #8 // LR_HAVE_BOTTOM
+        b.eq            L(v3_7)
+
+        mov             x3,  x16              // restore lpf
+        mov             x2,  #0               // left = NULL
+        bl              wiener_filter7_hv_16bpc_neon
+        bl              wiener_filter7_hv_16bpc_neon
+L(v1_7):
+        bl              wiener_filter7_v_16bpc_neon
+
+        mov             sp,  x29
+        ldp             d8,  d9,  [sp, #16]
+        ldp             x29, x30, [sp], #32
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(no_top_7):
+        add             x3,  x3,  x1,  lsl #2
+        add             x16, x3,  x1,  lsl #1 // lpf += stride*6, backup
+        mov             x3,  x0               // lpf = p
+
+        bl              wiener_filter7_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x9,  x14              // t6
+        mov             x10, x14              // t5
+        mov             x11, x14              // t4
+        mov             x12, x14              // t3
+        mov             x13, x14              // t2
+        b.eq            L(v1_7)
+        add             x3,  x3,  x1          // src += p_stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x13, x14              // t2
+        b.eq            L(v2_7)
+        add             x3,  x3,  x1          // src += p_stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter7_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v3_7)
+        add             x3,  x3,  x1          // src += p_stride
+        add             x15, x14, #384*2      // t0 = t1 + 384*2
+        bl              wiener_filter7_hv_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v3_7)
+        add             x15, x15, #384*2*4    // t0 += 384*2*4
+        bl              wiener_filter7_hv_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.ne            L(main_7)
+L(v3_7):
+        bl              wiener_filter7_v_16bpc_neon
+L(v2_7):
+        bl              wiener_filter7_v_16bpc_neon
+        b               L(v1_7)
+endfunc
+
+
+function wiener_filter7_h_16bpc_neon
+        stp             x3,  x4,  [sp, #-32]!
+        str             x14,      [sp, #16]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        // LR_HAVE_LEFT
+        cbnz            x2,  0f
+        // left == NULL
+        sub             x3,  x3,  #6
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        ld1             {v4.d}[1], [x2], #8
+        // Move x3 back to account for the last 3 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #6
+        ext             v3.16b,  v2.16b,  v3.16b,  #10
+        ext             v2.16b,  v4.16b,  v2.16b,  #10
+        b               2f
+
+1:
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        // !LR_HAVE_LEFT, fill v4 with the leftmost pixel
+        // and shift v3 to have 3x the first pixel at the front.
+        dup             v4.8h,  v2.h[0]
+        // Move x3 back to account for the last 3 pixels we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #6
+        ext             v3.16b,  v2.16b,  v3.16b,  #10
+        ext             v2.16b,  v4.16b,  v2.16b,  #10
+
+2:
+        ld1             {v4.8h}, [x3], #16
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #19
+        b.ge            4f   // If w >= 19, all used input pixels are valid
+
+        // 1 <= w < 19, w+3 pixels valid in v2-v4. For w>=9,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is v2/3/4.h[w+2]. x3 points at the next input, ie
+        // v2/3/4.h[24]. Thus read from x3[w-22] to find the padding pixel.
+        sub             w17, w4,  #22
+        // Insert padding in v2/3/4.h[w+3] onwards; fuse the +3 (*2) into the
+        // buffer pointer.
+        movrel          x6,  right_ext_mask, -6
+        ldr             h26, [x3,  w17, sxtw #1]
+        sub             x6,  x6,  w4,  uxtw #1
+        dup             v26.8h,  v26.h[0]
+        ld1             {v23.16b, v24.16b, v25.16b}, [x6]
+
+        bit             v2.16b,  v26.16b, v23.16b
+        bit             v3.16b,  v26.16b, v24.16b
+        bit             v4.16b,  v26.16b, v25.16b
+
+4:      // Loop horizontally
+        // Interleaving the mul/mla chains actually hurts performance
+        // significantly on Cortex A53, thus keeping mul/mla tightly
+        // chained like this.
+        ext             v17.16b, v2.16b,  v3.16b, #4
+        ext             v19.16b, v2.16b,  v3.16b, #8
+        ext             v16.16b, v2.16b,  v3.16b, #2
+        ext             v20.16b, v2.16b,  v3.16b, #10
+        ext             v21.16b, v2.16b,  v3.16b, #12
+        ext             v18.16b, v2.16b,  v3.16b, #6
+        add             v19.8h,  v19.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v16.8h
+        add             v21.8h,  v21.8h,  v2.8h
+        smull           v6.4s,   v18.4h,  v0.h[3]
+        smlal           v6.4s,   v19.4h,  v0.h[2]
+        smlal           v6.4s,   v20.4h,  v0.h[1]
+        smlal           v6.4s,   v21.4h,  v0.h[0]
+        smull2          v7.4s,   v18.8h,  v0.h[3]
+        smlal2          v7.4s,   v19.8h,  v0.h[2]
+        smlal2          v7.4s,   v20.8h,  v0.h[1]
+        smlal2          v7.4s,   v21.8h,  v0.h[0]
+
+        ext             v17.16b, v3.16b,  v4.16b, #4
+        ext             v19.16b, v3.16b,  v4.16b, #8
+        ext             v16.16b, v3.16b,  v4.16b, #2
+        ext             v20.16b, v3.16b,  v4.16b, #10
+        ext             v21.16b, v3.16b,  v4.16b, #12
+        ext             v18.16b, v3.16b,  v4.16b, #6
+
+        add             v19.8h,  v19.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v16.8h
+        add             v21.8h,  v21.8h,  v3.8h
+        smull           v16.4s,  v18.4h,  v0.h[3]
+        smlal           v16.4s,  v19.4h,  v0.h[2]
+        smlal           v16.4s,  v20.4h,  v0.h[1]
+        smlal           v16.4s,  v21.4h,  v0.h[0]
+        smull2          v17.4s,  v18.8h,  v0.h[3]
+        smlal2          v17.4s,  v19.8h,  v0.h[2]
+        smlal2          v17.4s,  v20.8h,  v0.h[1]
+        smlal2          v17.4s,  v21.8h,  v0.h[0]
+
+        mvni            v24.8h,  #0x80, lsl #8 // 0x7fff = (1 << 15) - 1
+        add             v6.4s,   v6.4s,   v30.4s
+        add             v7.4s,   v7.4s,   v30.4s
+        add             v16.4s,  v16.4s,  v30.4s
+        add             v17.4s,  v17.4s,  v30.4s
+        srshl           v6.4s,   v6.4s,   v29.4s
+        srshl           v7.4s,   v7.4s,   v29.4s
+        srshl           v16.4s,  v16.4s,  v29.4s
+        srshl           v17.4s,  v17.4s,  v29.4s
+        sqxtun          v6.4h,   v6.4s
+        sqxtun2         v6.8h,   v7.4s
+        sqxtun          v7.4h,   v16.4s
+        sqxtun2         v7.8h,   v17.4s
+        umin            v6.8h,   v6.8h,   v24.8h
+        umin            v7.8h,   v7.8h,   v24.8h
+        sub             v6.8h,   v6.8h,   v31.8h
+        sub             v7.8h,   v7.8h,   v31.8h
+
+        subs            w4,  w4,  #16
+
+        st1             {v6.8h, v7.8h}, [x14], #32
+
+        b.le            0f
+        mov             v2.16b,  v4.16b
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        ld1             {v3.8h, v4.8h}, [x3], #32
+        b.ne            4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+0:
+        ldr             x14,      [sp, #16]
+        ldp             x3,  x4,  [sp], #32
+        ret
+endfunc
+
+function wiener_filter7_v_16bpc_neon
+        // Backing up/restoring registers shifted, so that x9 gets the value
+        // of x10, etc, afterwards.
+        stp             x10, x11, [sp, #-64]!
+        stp             x12, x13, [sp, #16]
+        stp             x14, x14, [sp, #32]
+        stp             x0,  x4,  [sp, #48]
+1:
+        ld1             {v16.8h, v17.8h}, [x9],  #32
+        ld1             {v18.8h, v19.8h}, [x10], #32
+        ld1             {v20.8h, v21.8h}, [x11], #32
+        ld1             {v22.8h, v23.8h}, [x12], #32
+        ld1             {v24.8h, v25.8h}, [x13], #32
+        ld1             {v6.8h,  v7.8h},  [x14], #32
+
+        smull           v2.4s,   v16.4h,  v0.h[4]
+        smlal           v2.4s,   v18.4h,  v0.h[5]
+        smlal           v2.4s,   v20.4h,  v0.h[6]
+        smlal           v2.4s,   v22.4h,  v0.h[7]
+        smlal           v2.4s,   v24.4h,  v0.h[6]
+        smlal           v2.4s,   v6.4h,   v0.h[5]
+        smlal           v2.4s,   v6.4h,   v0.h[4]
+        smull2          v3.4s,   v16.8h,  v0.h[4]
+        smlal2          v3.4s,   v18.8h,  v0.h[5]
+        smlal2          v3.4s,   v20.8h,  v0.h[6]
+        smlal2          v3.4s,   v22.8h,  v0.h[7]
+        smlal2          v3.4s,   v24.8h,  v0.h[6]
+        smlal2          v3.4s,   v6.8h,   v0.h[5]
+        smlal2          v3.4s,   v6.8h,   v0.h[4]
+        smull           v4.4s,   v17.4h,  v0.h[4]
+        smlal           v4.4s,   v19.4h,  v0.h[5]
+        smlal           v4.4s,   v21.4h,  v0.h[6]
+        smlal           v4.4s,   v23.4h,  v0.h[7]
+        smlal           v4.4s,   v25.4h,  v0.h[6]
+        smlal           v4.4s,   v7.4h,   v0.h[5]
+        smlal           v4.4s,   v7.4h,   v0.h[4]
+        smull2          v5.4s,   v17.8h,  v0.h[4]
+        smlal2          v5.4s,   v19.8h,  v0.h[5]
+        smlal2          v5.4s,   v21.8h,  v0.h[6]
+        smlal2          v5.4s,   v23.8h,  v0.h[7]
+        smlal2          v5.4s,   v25.8h,  v0.h[6]
+        smlal2          v5.4s,   v7.8h,   v0.h[5]
+        smlal2          v5.4s,   v7.8h,   v0.h[4]
+        srshl           v2.4s,   v2.4s,   v27.4s  // -round_bits_v
+        srshl           v3.4s,   v3.4s,   v27.4s
+        srshl           v4.4s,   v4.4s,   v27.4s
+        srshl           v5.4s,   v5.4s,   v27.4s
+        sqxtun          v2.4h,   v2.4s
+        sqxtun2         v2.8h,   v3.4s
+        sqxtun          v3.4h,   v4.4s
+        sqxtun2         v3.8h,   v5.4s
+        umin            v2.8h,   v2.8h,   v28.8h  // bitdepth_max
+        umin            v3.8h,   v3.8h,   v28.8h
+        subs            w4,  w4,  #16
+        st1             {v2.8h, v3.8h}, [x0], #32
+        b.gt            1b
+
+        ldp             x0,  x4,  [sp, #48]
+        ldp             x13, x14, [sp, #32]
+        ldp             x11, x12, [sp, #16]
+        ldp             x9,  x10, [sp], #64
+
+        add             x0,  x0,  x1
+        ret
+endfunc
+
+function wiener_filter7_hv_16bpc_neon
+        // Backing up/restoring registers shifted, so that x9 gets the value
+        // of x10, etc, and x15==x9, afterwards.
+        stp             x10, x11, [sp, #-80]!
+        stp             x12, x13, [sp, #16]
+        stp             x14, x15, [sp, #32]
+        stp             x10, x0,  [sp, #48]
+        stp             x3,  x4,  [sp, #64]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        // LR_HAVE_LEFT
+        cbnz            x2,  0f
+        // left == NULL
+        sub             x3,  x3,  #6
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        ld1             {v4.d}[1], [x2], #8
+        // Move x3 back to account for the last 3 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #6
+        ext             v3.16b,  v2.16b,  v3.16b,  #10
+        ext             v2.16b,  v4.16b,  v2.16b,  #10
+        b               2f
+1:
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        // !LR_HAVE_LEFT, fill v4 with the leftmost pixel
+        // and shift v3 to have 3x the first pixel at the front.
+        dup             v4.8h,  v2.h[0]
+        // Move x3 back to account for the last 3 pixels we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #6
+        ext             v3.16b,  v2.16b,  v3.16b,  #10
+        ext             v2.16b,  v4.16b,  v2.16b,  #10
+
+2:
+        ld1             {v4.8h}, [x3], #16
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #19
+        b.ge            4f   // If w >= 19, all used input pixels are valid
+
+        // 1 <= w < 19, w+3 pixels valid in v2-v4. For w>=9,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is v2/3/4.h[w+2]. x3 points at the next input, ie
+        // v2/3/4.h[24]. Thus read from x3[w-22] to find the padding pixel.
+        sub             w17, w4,  #22
+        // Insert padding in v2/3/4.h[w+3] onwards; fuse the +3 (*2) into the
+        // buffer pointer.
+        movrel          x6,  right_ext_mask, -6
+        ldr             h26, [x3,  w17, sxtw #1]
+        sub             x6,  x6,  w4,  uxtw #1
+        dup             v26.8h,  v26.h[0]
+        ld1             {v23.16b, v24.16b, v25.16b}, [x6]
+
+        bit             v2.16b,  v26.16b, v23.16b
+        bit             v3.16b,  v26.16b, v24.16b
+        bit             v4.16b,  v26.16b, v25.16b
+
+4:      // Loop horizontally
+        ext             v17.16b, v2.16b,  v3.16b, #4
+        ext             v19.16b, v2.16b,  v3.16b, #8
+        ext             v16.16b, v2.16b,  v3.16b, #2
+        ext             v20.16b, v2.16b,  v3.16b, #10
+        ext             v21.16b, v2.16b,  v3.16b, #12
+        ext             v18.16b, v2.16b,  v3.16b, #6
+        add             v19.8h,  v19.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v16.8h
+        add             v21.8h,  v21.8h,  v2.8h
+        smull           v6.4s,   v18.4h,  v0.h[3]
+        smlal           v6.4s,   v19.4h,  v0.h[2]
+        smlal           v6.4s,   v20.4h,  v0.h[1]
+        smlal           v6.4s,   v21.4h,  v0.h[0]
+        smull2          v7.4s,   v18.8h,  v0.h[3]
+        smlal2          v7.4s,   v19.8h,  v0.h[2]
+        smlal2          v7.4s,   v20.8h,  v0.h[1]
+        smlal2          v7.4s,   v21.8h,  v0.h[0]
+
+        ext             v17.16b, v3.16b,  v4.16b, #4
+        ext             v19.16b, v3.16b,  v4.16b, #8
+        ext             v16.16b, v3.16b,  v4.16b, #2
+        ext             v20.16b, v3.16b,  v4.16b, #10
+        ext             v21.16b, v3.16b,  v4.16b, #12
+        ext             v18.16b, v3.16b,  v4.16b, #6
+
+        add             v19.8h,  v19.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v16.8h
+        add             v21.8h,  v21.8h,  v3.8h
+        smull           v24.4s,  v18.4h,  v0.h[3]
+        smlal           v24.4s,  v19.4h,  v0.h[2]
+        smlal           v24.4s,  v20.4h,  v0.h[1]
+        smlal           v24.4s,  v21.4h,  v0.h[0]
+        smull2          v25.4s,  v18.8h,  v0.h[3]
+        smlal2          v25.4s,  v19.8h,  v0.h[2]
+        smlal2          v25.4s,  v20.8h,  v0.h[1]
+        smlal2          v25.4s,  v21.8h,  v0.h[0]
+
+        ld1             {v16.8h, v17.8h}, [x9],  #32
+
+        mvni            v26.8h,  #0x80, lsl #8 // 0x7fff = (1 << 15) - 1
+        add             v6.4s,   v6.4s,   v30.4s
+        add             v7.4s,   v7.4s,   v30.4s
+        add             v24.4s,  v24.4s,  v30.4s
+        add             v25.4s,  v25.4s,  v30.4s
+        ld1             {v18.8h, v19.8h}, [x10], #32
+        srshl           v6.4s,   v6.4s,   v29.4s
+        srshl           v7.4s,   v7.4s,   v29.4s
+        srshl           v24.4s,  v24.4s,  v29.4s
+        srshl           v25.4s,  v25.4s,  v29.4s
+        ld1             {v20.8h, v21.8h}, [x11], #32
+        sqxtun          v6.4h,   v6.4s
+        sqxtun2         v6.8h,   v7.4s
+        sqxtun          v7.4h,   v24.4s
+        sqxtun2         v7.8h,   v25.4s
+        ld1             {v22.8h, v23.8h}, [x12], #32
+        umin            v6.8h,   v6.8h,   v26.8h
+        umin            v7.8h,   v7.8h,   v26.8h
+        ld1             {v24.8h, v25.8h}, [x13], #32
+        sub             v6.8h,   v6.8h,   v31.8h
+        sub             v7.8h,   v7.8h,   v31.8h
+
+        ld1             {v8.8h,  v9.8h},  [x14], #32
+
+        smull           v1.4s,   v16.4h,  v0.h[4]
+        smlal           v1.4s,   v18.4h,  v0.h[5]
+        smlal           v1.4s,   v20.4h,  v0.h[6]
+        smlal           v1.4s,   v22.4h,  v0.h[7]
+        smlal           v1.4s,   v24.4h,  v0.h[6]
+        smlal           v1.4s,   v8.4h,   v0.h[5]
+        smlal           v1.4s,   v6.4h,   v0.h[4]
+        smull2          v5.4s,   v16.8h,  v0.h[4]
+        smlal2          v5.4s,   v18.8h,  v0.h[5]
+        smlal2          v5.4s,   v20.8h,  v0.h[6]
+        smlal2          v5.4s,   v22.8h,  v0.h[7]
+        smlal2          v5.4s,   v24.8h,  v0.h[6]
+        smlal2          v5.4s,   v8.8h,   v0.h[5]
+        smlal2          v5.4s,   v6.8h,   v0.h[4]
+        smull           v26.4s,  v17.4h,  v0.h[4]
+        smlal           v26.4s,  v19.4h,  v0.h[5]
+        smlal           v26.4s,  v21.4h,  v0.h[6]
+        smlal           v26.4s,  v23.4h,  v0.h[7]
+        smlal           v26.4s,  v25.4h,  v0.h[6]
+        smlal           v26.4s,  v9.4h,   v0.h[5]
+        smlal           v26.4s,  v7.4h,   v0.h[4]
+        smull2          v16.4s,  v17.8h,  v0.h[4]
+        smlal2          v16.4s,  v19.8h,  v0.h[5]
+        smlal2          v16.4s,  v21.8h,  v0.h[6]
+        smlal2          v16.4s,  v23.8h,  v0.h[7]
+        smlal2          v16.4s,  v25.8h,  v0.h[6]
+        smlal2          v16.4s,  v9.8h,   v0.h[5]
+        smlal2          v16.4s,  v7.8h,   v0.h[4]
+        srshl           v1.4s,   v1.4s,   v27.4s  // -round_bits_v
+        srshl           v5.4s,   v5.4s,   v27.4s
+        srshl           v26.4s,  v26.4s,  v27.4s
+        srshl           v16.4s,  v16.4s,  v27.4s
+        sqxtun          v18.4h,  v1.4s
+        sqxtun2         v18.8h,  v5.4s
+        sqxtun          v19.4h,  v26.4s
+        sqxtun2         v19.8h,  v16.4s
+        st1             {v6.8h, v7.8h}, [x15], #32
+        umin            v18.8h,  v18.8h,  v28.8h  // bitdepth_max
+        umin            v19.8h,  v19.8h,  v28.8h
+        subs            w4,  w4,  #16
+
+        st1             {v18.8h, v19.8h}, [x0], #32
+
+        b.le            0f
+        mov             v2.16b,  v4.16b
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        ld1             {v3.8h, v4.8h}, [x3], #32
+        b.ne            4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+0:
+        ldp             x3,  x4,  [sp, #64]
+        ldp             x15, x0,  [sp, #48]
+        ldp             x13, x14, [sp, #32]
+        ldp             x11, x12, [sp, #16]
+        ldp             x9,  x10, [sp], #80
+
+        add             x3,  x3,  x1
+        add             x0,  x0,  x1
+
+        ret
+endfunc
+
+// void dav1d_wiener_filter5_16bpc_neon(pixel *p, const ptrdiff_t p_stride,
+//                                      const pixel (*left)[4], const pixel *lpf,
+//                                      const int w, int h,
+//                                      const int16_t filter[2][8],
+//                                      const enum LrEdgeFlags edges,
+//                                      const int bitdepth_max);
+function wiener_filter5_16bpc_neon, export=1
+        ldr             w8,  [sp]
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x29, x30, [sp, #-32]!
+        stp             d8,  d9,  [sp, #16]
+        mov             x29, sp
+        ld1             {v0.8h, v1.8h},  [x6]
+        tst             w7,  #4               // LR_HAVE_TOP
+        sub_sp          384*2*4
+
+        dup             v28.8h,  w8           // bitdepth_max
+        clz             w8,  w8
+        movi            v30.4s,  #1
+        sub             w10, w8,  #38         // -(bitdepth + 6)
+        sub             w11, w8,  #11         // round_bits_v
+        sub             w8,  w8,  #25         // -round_bits_h
+        neg             w10, w10              // bitdepth + 6
+        neg             w11, w11              // -round_bits_v
+        dup             v2.4s,   w10
+        dup             v29.4s,  w8           // -round_bits_h
+        dup             v27.4s,  w11          // -round_bits_v
+        movi            v31.8h,  #0x20, lsl #8  // 1 << 13 = 8192
+        ushl            v30.4s,  v30.4s,  v2.4s // 1 << (bitdepth + 6)
+
+        zip1            v0.2d,   v0.2d,   v1.2d // move vertical coeffs to v0.h[4-7], freeing up v1
+
+        // x11 - t4
+        // x12 - t3
+        // x13 - t2
+        // x14 - t1
+        // x15 - t0
+        mov             x14, sp               // t1
+        b.eq            L(no_top_5)
+
+        mov             x16, x2               // backup left
+        mov             x2,  #0
+        bl              wiener_filter5_h_16bpc_neon
+        add             x3,  x3,  x1          // lpf += stride
+        mov             x11, x14              // t4
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter5_h_16bpc_neon
+        add             x3,  x3,  x1,  lsl #2
+        add             x3,  x3,  x1          // lpf += stride*5
+        mov             x12, x14              // t3
+        add             x14, x14, #384*2      // t1 += 384*2
+        mov             x2,  x16              // left
+        mov             x16, x3               // backup lpf
+        mov             x3,  x0               // lpf = p
+        bl              wiener_filter5_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x13, x14              // t2
+        b.eq            L(v1_5)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter5_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v2_5)
+        add             x3,  x3,  x1          // src += stride
+
+L(main_5):
+        mov             x15, x11              // t0 = t4
+L(main_loop_5):
+        bl              wiener_filter5_hv_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.ne            L(main_loop_5)
+        tst             w7,  #8 // LR_HAVE_BOTTOM
+        b.eq            L(v2_5)
+
+        mov             x3,  x16              // restore lpf
+        mov             x2,  #0               // left = NULL
+        bl              wiener_filter5_hv_16bpc_neon
+        bl              wiener_filter5_hv_16bpc_neon
+L(end_5):
+
+        mov             sp,  x29
+        ldp             d8,  d9,  [sp, #16]
+        ldp             x29, x30, [sp], #32
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+L(no_top_5):
+        add             x3,  x3,  x1,  lsl #2
+        add             x16, x3,  x1,  lsl #1 // lpf += stride*6, backup
+        mov             x3,  x0               // lpf = p
+
+        bl              wiener_filter5_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        mov             x11, x14              // t4
+        mov             x12, x14              // t3
+        mov             x13, x14              // t2
+        b.eq            L(v1_5)
+        add             x3,  x3,  x1          // src += stride
+        add             x14, x14, #384*2      // t1 += 384*2
+        bl              wiener_filter5_h_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v2_5)
+        add             x3,  x3,  x1          // src += stride
+        add             x15, x14, #384*2      // t0 = t1 + 384*2
+        bl              wiener_filter5_hv_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.eq            L(v2_5)
+        add             x15, x15, #384*2*3    // t0 += 384*2*3
+        bl              wiener_filter5_hv_16bpc_neon
+        subs            w5,  w5,  #1          // h--
+        b.ne            L(main_5)
+L(v2_5):
+        bl              wiener_filter5_v_16bpc_neon
+        add             x0,  x0,  x1
+        mov             x11, x12
+        mov             x12, x13
+        mov             x13, x14
+L(v1_5):
+        bl              wiener_filter5_v_16bpc_neon
+        b               L(end_5)
+endfunc
+
+
+function wiener_filter5_h_16bpc_neon
+        stp             x3,  x4,  [sp, #-32]!
+        str             x14,      [sp, #16]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        // LR_HAVE_LEFT
+        cbnz            x2,  0f
+        // left == NULL
+        sub             x3,  x3,  #4
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        ld1             {v4.d}[1], [x2], #8
+        // Move x3 back to account for the last 2 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #4
+        ext             v3.16b,  v2.16b,  v3.16b,  #12
+        ext             v2.16b,  v4.16b,  v2.16b,  #12
+        b               2f
+
+1:
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        // !LR_HAVE_LEFT, fill v2 with the leftmost pixel
+        // and shift v3 to have 3x the first pixel at the front.
+        dup             v4.8h,  v2.h[0]
+        // Move x3 back to account for the last 2 pixels we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #4
+        ext             v3.16b,  v2.16b,  v3.16b,  #12
+        ext             v2.16b,  v4.16b,  v2.16b,  #12
+
+2:
+        ld1             {v4.8h}, [x3], #16
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #18
+        b.ge            4f   // If w >= 18, all used input pixels are valid
+
+        // 1 <= w < 18, w+2 pixels valid in v2-v4. For w>=9,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is v2/3/4.h[w+2]. x3 points at the next input, ie
+        // v2/3/4.h[24]. Thus read from x3[w-23] to find the padding pixel.
+        sub             w17, w4,  #23
+        // Insert padding in v2/3/4.h[w+2] onwards; fuse the +2 (*2) into the
+        // buffer pointer.
+        movrel          x6,  right_ext_mask, -4
+        ldr             h26, [x3,  w17, sxtw #1]
+        sub             x6,  x6,  w4,  uxtw #1
+        dup             v26.8h,  v26.h[0]
+        ld1             {v23.16b, v24.16b, v25.16b}, [x6]
+
+        bit             v2.16b,  v26.16b, v23.16b
+        bit             v3.16b,  v26.16b, v24.16b
+        bit             v4.16b,  v26.16b, v25.16b
+
+4:      // Loop horizontally
+        // Interleaving the mul/mla chains actually hurts performance
+        // significantly on Cortex A53, thus keeping mul/mla tightly
+        // chained like this.
+        ext             v16.16b, v2.16b,  v3.16b, #2
+        ext             v18.16b, v2.16b,  v3.16b, #6
+        ext             v19.16b, v2.16b,  v3.16b, #8
+        ext             v17.16b, v2.16b,  v3.16b, #4
+        add             v18.8h,  v18.8h,  v16.8h
+        add             v19.8h,  v19.8h,  v2.8h
+        smull           v6.4s,   v17.4h,  v0.h[3]
+        smlal           v6.4s,   v18.4h,  v0.h[2]
+        smlal           v6.4s,   v19.4h,  v0.h[1]
+        smull2          v7.4s,   v17.8h,  v0.h[3]
+        smlal2          v7.4s,   v18.8h,  v0.h[2]
+        smlal2          v7.4s,   v19.8h,  v0.h[1]
+
+        ext             v16.16b, v3.16b,  v4.16b, #2
+        ext             v18.16b, v3.16b,  v4.16b, #6
+        ext             v19.16b, v3.16b,  v4.16b, #8
+        ext             v17.16b, v3.16b,  v4.16b, #4
+        add             v18.8h,  v18.8h,  v16.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        smull           v16.4s,  v17.4h,  v0.h[3]
+        smlal           v16.4s,  v18.4h,  v0.h[2]
+        smlal           v16.4s,  v19.4h,  v0.h[1]
+        smull2          v17.4s,  v17.8h,  v0.h[3]
+        smlal2          v17.4s,  v18.8h,  v0.h[2]
+        smlal2          v17.4s,  v19.8h,  v0.h[1]
+
+        mvni            v24.8h,  #0x80, lsl #8 // 0x7fff = (1 << 15) - 1
+        add             v6.4s,   v6.4s,   v30.4s
+        add             v7.4s,   v7.4s,   v30.4s
+        add             v16.4s,  v16.4s,  v30.4s
+        add             v17.4s,  v17.4s,  v30.4s
+        srshl           v6.4s,   v6.4s,   v29.4s
+        srshl           v7.4s,   v7.4s,   v29.4s
+        srshl           v16.4s,  v16.4s,  v29.4s
+        srshl           v17.4s,  v17.4s,  v29.4s
+        sqxtun          v6.4h,   v6.4s
+        sqxtun2         v6.8h,   v7.4s
+        sqxtun          v7.4h,   v16.4s
+        sqxtun2         v7.8h,   v17.4s
+        umin            v6.8h,   v6.8h,   v24.8h
+        umin            v7.8h,   v7.8h,   v24.8h
+        sub             v6.8h,   v6.8h,   v31.8h
+        sub             v7.8h,   v7.8h,   v31.8h
+
+        subs            w4,  w4,  #16
+
+        st1             {v6.8h, v7.8h}, [x14], #32
+
+        b.le            0f
+        mov             v2.16b,  v4.16b
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        ld1             {v3.8h, v4.8h}, [x3], #32
+        b.ne            4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+0:
+        ldr             x14,      [sp, #16]
+        ldp             x3,  x4,  [sp], #32
+        ret
+endfunc
+
+function wiener_filter5_v_16bpc_neon
+        stp             x11, x12, [sp, #-48]!
+        stp             x13, x14, [sp, #16]
+        stp             x0,  x4,  [sp, #32]
+1:
+        ld1             {v16.8h, v17.8h}, [x11], #32
+        ld1             {v18.8h, v19.8h}, [x12], #32
+        ld1             {v20.8h, v21.8h}, [x13], #32
+        ld1             {v22.8h, v23.8h}, [x14], #32
+
+        smull           v2.4s,   v16.4h,  v0.h[5]
+        smlal           v2.4s,   v18.4h,  v0.h[6]
+        smlal           v2.4s,   v20.4h,  v0.h[7]
+        smlal           v2.4s,   v22.4h,  v0.h[6]
+        smlal           v2.4s,   v22.4h,  v0.h[5]
+        smull2          v3.4s,   v16.8h,  v0.h[5]
+        smlal2          v3.4s,   v18.8h,  v0.h[6]
+        smlal2          v3.4s,   v20.8h,  v0.h[7]
+        smlal2          v3.4s,   v22.8h,  v0.h[6]
+        smlal2          v3.4s,   v22.8h,  v0.h[5]
+        smull           v4.4s,   v17.4h,  v0.h[5]
+        smlal           v4.4s,   v19.4h,  v0.h[6]
+        smlal           v4.4s,   v21.4h,  v0.h[7]
+        smlal           v4.4s,   v23.4h,  v0.h[6]
+        smlal           v4.4s,   v23.4h,  v0.h[5]
+        smull2          v5.4s,   v17.8h,  v0.h[5]
+        smlal2          v5.4s,   v19.8h,  v0.h[6]
+        smlal2          v5.4s,   v21.8h,  v0.h[7]
+        smlal2          v5.4s,   v23.8h,  v0.h[6]
+        smlal2          v5.4s,   v23.8h,  v0.h[5]
+        srshl           v2.4s,   v2.4s,   v27.4s  // -round_bits_v
+        srshl           v3.4s,   v3.4s,   v27.4s
+        srshl           v4.4s,   v4.4s,   v27.4s
+        srshl           v5.4s,   v5.4s,   v27.4s
+        sqxtun          v2.4h,   v2.4s
+        sqxtun2         v2.8h,   v3.4s
+        sqxtun          v3.4h,   v4.4s
+        sqxtun2         v3.8h,   v5.4s
+        umin            v2.8h,   v2.8h,   v28.8h  // bitdepth_max
+        umin            v3.8h,   v3.8h,   v28.8h
+
+        subs            w4,  w4,  #16
+        st1             {v2.8h, v3.8h}, [x0], #32
+        b.gt            1b
+
+        ldp             x0,  x4,  [sp, #32]
+        ldp             x13, x14, [sp, #16]
+        ldp             x11, x12, [sp], #48
+
+        ret
+endfunc
+
+function wiener_filter5_hv_16bpc_neon
+        // Backing up/restoring registers shifted, so that x11 gets the value
+        // of x12, etc, and x15==x11, afterwards.
+        stp             x12, x13, [sp, #-64]!
+        stp             x14, x15, [sp, #16]
+        stp             x12, x0,  [sp, #32]
+        stp             x3,  x4,  [sp, #48]
+
+        // Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        // LR_HAVE_LEFT
+        cbnz            x2,  0f
+        // left == NULL
+        sub             x3,  x3,  #4
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        ld1             {v4.d}[1], [x2], #8
+        // Move x3 back to account for the last 2 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #4
+        ext             v3.16b,  v2.16b,  v3.16b,  #12
+        ext             v2.16b,  v4.16b,  v2.16b,  #12
+        b               2f
+1:
+        ld1             {v2.8h, v3.8h}, [x3], #32
+        // !LR_HAVE_LEFT, fill v2 with the leftmost pixel
+        // and shift v3 to have 2x the first pixel at the front.
+        dup             v4.8h,   v2.h[0]
+        // Move x3 back to account for the last 2 pixels we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #4
+        ext             v3.16b,  v2.16b,  v3.16b,  #12
+        ext             v2.16b,  v4.16b,  v2.16b,  #12
+
+2:
+        ld1             {v4.8h}, [x3], #16
+
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #18
+        b.ge            4f   // If w >= 18, all used input pixels are valid
+
+        // 1 <= w < 18, w+2 pixels valid in v2-v4. For w>=9,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // The padding pixel is v2/3/4.h[w+1]. x3 points at the next input, ie
+        // v2/3/4.h[24]. Thus read from x3[w-23] to find the padding pixel.
+        sub             w17, w4,  #23
+        // Insert padding in v2/3/4.h[w+2] onwards; fuse the +2 (*2) into the
+        // buffer pointer.
+        movrel          x6,  right_ext_mask, -4
+        ldr             h26, [x3,  w17, sxtw #1]
+        sub             x6,  x6,  w4,  uxtw #1
+        dup             v26.8h,  v26.h[0]
+        ld1             {v23.16b, v24.16b, v25.16b}, [x6]
+
+        bit             v2.16b,  v26.16b, v23.16b
+        bit             v3.16b,  v26.16b, v24.16b
+        bit             v4.16b,  v26.16b, v25.16b
+
+4:      // Loop horizontally
+        ext             v16.16b, v2.16b,  v3.16b, #2
+        ext             v18.16b, v2.16b,  v3.16b, #6
+        ext             v19.16b, v2.16b,  v3.16b, #8
+        ext             v17.16b, v2.16b,  v3.16b, #4
+        add             v18.8h,  v18.8h,  v16.8h
+        add             v19.8h,  v19.8h,  v2.8h
+        smull           v6.4s,   v17.4h,  v0.h[3]
+        smlal           v6.4s,   v18.4h,  v0.h[2]
+        smlal           v6.4s,   v19.4h,  v0.h[1]
+        smull2          v7.4s,   v17.8h,  v0.h[3]
+        smlal2          v7.4s,   v18.8h,  v0.h[2]
+        smlal2          v7.4s,   v19.8h,  v0.h[1]
+
+        ext             v16.16b, v3.16b,  v4.16b, #2
+        ext             v18.16b, v3.16b,  v4.16b, #6
+        ext             v19.16b, v3.16b,  v4.16b, #8
+        ext             v17.16b, v3.16b,  v4.16b, #4
+        add             v18.8h,  v18.8h,  v16.8h
+        add             v19.8h,  v19.8h,  v3.8h
+        smull           v24.4s,  v17.4h,  v0.h[3]
+        smlal           v24.4s,  v18.4h,  v0.h[2]
+        smlal           v24.4s,  v19.4h,  v0.h[1]
+        smull2          v25.4s,  v17.8h,  v0.h[3]
+        smlal2          v25.4s,  v18.8h,  v0.h[2]
+        smlal2          v25.4s,  v19.8h,  v0.h[1]
+
+        ld1             {v16.8h, v17.8h}, [x11], #32
+        mvni            v26.8h,  #0x80, lsl #8 // 0x7fff = (1 << 15) - 1
+        add             v6.4s,   v6.4s,   v30.4s
+        add             v7.4s,   v7.4s,   v30.4s
+        add             v24.4s,  v24.4s,  v30.4s
+        add             v25.4s,  v25.4s,  v30.4s
+        ld1             {v18.8h, v19.8h}, [x12], #32
+        srshl           v6.4s,   v6.4s,   v29.4s
+        srshl           v7.4s,   v7.4s,   v29.4s
+        srshl           v24.4s,  v24.4s,  v29.4s
+        srshl           v25.4s,  v25.4s,  v29.4s
+        ld1             {v20.8h, v21.8h}, [x13], #32
+        sqxtun          v6.4h,   v6.4s
+        sqxtun2         v6.8h,   v7.4s
+        sqxtun          v7.4h,   v24.4s
+        sqxtun2         v7.8h,   v25.4s
+        ld1             {v22.8h, v23.8h}, [x14], #32
+        umin            v6.8h,   v6.8h,   v26.8h
+        umin            v7.8h,   v7.8h,   v26.8h
+        sub             v6.8h,   v6.8h,   v31.8h
+        sub             v7.8h,   v7.8h,   v31.8h
+
+        smull           v8.4s,   v16.4h,  v0.h[5]
+        smlal           v8.4s,   v18.4h,  v0.h[6]
+        smlal           v8.4s,   v20.4h,  v0.h[7]
+        smlal           v8.4s,   v22.4h,  v0.h[6]
+        smlal           v8.4s,   v6.4h,   v0.h[5]
+        smull2          v9.4s,   v16.8h,  v0.h[5]
+        smlal2          v9.4s,   v18.8h,  v0.h[6]
+        smlal2          v9.4s,   v20.8h,  v0.h[7]
+        smlal2          v9.4s,   v22.8h,  v0.h[6]
+        smlal2          v9.4s,   v6.8h,   v0.h[5]
+        smull           v1.4s,   v17.4h,  v0.h[5]
+        smlal           v1.4s,   v19.4h,  v0.h[6]
+        smlal           v1.4s,   v21.4h,  v0.h[7]
+        smlal           v1.4s,   v23.4h,  v0.h[6]
+        smlal           v1.4s,   v7.4h,   v0.h[5]
+        smull2          v5.4s,   v17.8h,  v0.h[5]
+        smlal2          v5.4s,   v19.8h,  v0.h[6]
+        smlal2          v5.4s,   v21.8h,  v0.h[7]
+        smlal2          v5.4s,   v23.8h,  v0.h[6]
+        smlal2          v5.4s,   v7.8h,   v0.h[5]
+        srshl           v8.4s,   v8.4s,   v27.4s  // -round_bits_v
+        srshl           v9.4s,   v9.4s,   v27.4s
+        srshl           v1.4s,   v1.4s,   v27.4s
+        srshl           v5.4s,   v5.4s,   v27.4s
+        sqxtun          v8.4h,   v8.4s
+        sqxtun2         v8.8h,   v9.4s
+        sqxtun          v9.4h,   v1.4s
+        sqxtun2         v9.8h,   v5.4s
+        st1             {v6.8h, v7.8h}, [x15], #32
+        umin            v8.8h,   v8.8h,   v28.8h  // bitdepth_max
+        umin            v9.8h,   v9.8h,   v28.8h
+
+        subs            w4,  w4,  #16
+
+        st1             {v8.8h, v9.8h}, [x0], #32
+
+        b.le            0f
+        mov             v2.16b,  v4.16b
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        ld1             {v3.8h, v4.8h}, [x3], #32
+        b.ne            4b // If we don't need to pad, just keep filtering.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+0:
+        ldp             x3,  x4,  [sp, #48]
+        ldp             x15, x0,  [sp, #32]
+        ldp             x13, x14, [sp, #16]
+        ldp             x11, x12, [sp], #64
+
+        add             x3,  x3,  x1
+        add             x0,  x0,  x1
+
+        ret
+endfunc
+
+#include "looprestoration_tmpl.S"
+
+// void dav1d_sgr_box3_row_h_16bpc_neon(int32_t *sumsq, int16_t *sum,
+//                                      const pixel (*left)[4],
+//                                      const pixel *src, const int w,
+//                                      const enum LrEdgeFlags edges);
+function sgr_box3_row_h_16bpc_neon, export=1
+        add             w4,  w4,  #2 // w += 2
+
+        tst             w5,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        cbnz            x2,  0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             x3,  x3,  #4
+        ld1             {v0.8h, v1.8h}, [x3], #32
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v0.8h, v1.8h}, [x3], #32
+        ld1             {v2.d}[1], [x2]
+        // Move x3 back to account for the last 2 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #4
+        ext             v1.16b, v0.16b, v1.16b, #12
+        ext             v0.16b, v2.16b, v0.16b, #12
+        b               2f
+
+1:
+        ld1             {v0.8h, v1.8h}, [x3], #32
+        // !LR_HAVE_LEFT, fill v2 with the leftmost pixel
+        // and shift v0/v1 to have 2x the first pixel at the front.
+        dup             v2.8h, v0.h[0]
+        // Move x3 back to account for the last 2 pixels we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #4
+        ext             v1.16b, v0.16b, v1.16b, #12
+        ext             v0.16b, v2.16b, v0.16b, #12
+
+2:
+        tst             w5,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+        // If we'll need to pad the right edge, load that pixel to pad with
+        // here since we can find it pretty easily from here.
+        sub             w13, w4, #(2 + 16 - 2 + 1)
+        ldr             h30, [x3,  w13, sxtw #1]
+        // Fill v30 with the right padding pixel
+        dup             v30.8h,  v30.h[0]
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #10
+        b.ge            4f   // If w >= 10, all used input pixels are valid
+
+        // 1 <= w < 10, w pixels valid in v0. For w=9, this ends up called
+        // again; it's not strictly needed in those cases (we pad enough here),
+        // but keeping the code as simple as possible.
+
+        // Insert padding in v0.h[w] onwards
+        movrel          x13, right_ext_mask
+        sub             x13, x13, w4,  uxtw #1
+        ld1             {v28.16b, v29.16b}, [x13]
+
+        bit             v0.16b,  v30.16b, v28.16b
+        bit             v1.16b,  v30.16b, v29.16b
+
+4:      // Loop horizontally
+        ext             v26.16b, v0.16b,  v1.16b,  #2
+        ext             v27.16b, v0.16b,  v1.16b,  #4
+
+        add             v6.8h,   v0.8h,   v26.8h
+        umull           v22.4s,  v0.4h,   v0.4h
+        umlal           v22.4s,  v26.4h,  v26.4h
+        umlal           v22.4s,  v27.4h,  v27.4h
+        add             v6.8h,   v6.8h,   v27.8h
+        umull2          v23.4s,  v0.8h,   v0.8h
+        umlal2          v23.4s,  v26.8h,  v26.8h
+        umlal2          v23.4s,  v27.8h,  v27.8h
+
+        subs            w4,  w4,  #8
+
+        st1             {v6.8h},         [x1],  #16
+        st1             {v22.4s,v23.4s}, [x0],  #32
+
+        b.le            9f
+        tst             w5,  #2 // LR_HAVE_RIGHT
+        mov             v0.16b,  v1.16b
+        ld1             {v1.8h},  [x3],  #16
+
+        b.ne            4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        ret
+endfunc
+
+// void dav1d_sgr_box5_row_h_16bpc_neon(int32_t *sumsq, int16_t *sum,
+//                                      const pixel (*left)[4],
+//                                      const pixel *src, const int w,
+//                                      const enum LrEdgeFlags edges);
+function sgr_box5_row_h_16bpc_neon, export=1
+        add             w4,  w4,  #2 // w += 2
+
+        tst             w5,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        cbnz            x2,  0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             x3,  x3,  #6
+        ld1             {v0.8h, v1.8h}, [x3], #32
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v0.8h, v1.8h}, [x3], #32
+        ld1             {v2.d}[1], [x2], #8
+        // Move x3 back to account for the last 3 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             x3,  x3,  #6
+        ext             v1.16b,  v0.16b,  v1.16b,  #10
+        ext             v0.16b,  v2.16b,  v0.16b,  #10
+        b               2f
+
+1:
+        ld1             {v0.8h, v1.8h}, [x3], #32
+        // !LR_HAVE_LEFT, fill v2 with the leftmost pixel
+        // and shift v0/v1 to have 3x the first pixel at the front.
+        dup             v2.8h,  v0.h[0]
+        // Move x3 back to account for the last 3 pixels we loaded before,
+        // which we shifted out.
+        sub             x3,  x3,  #6
+        ext             v1.16b,  v0.16b,  v1.16b,  #10
+        ext             v0.16b,  v2.16b,  v0.16b,  #10
+
+2:
+        tst             w5,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+        // If we'll need to pad the right edge, load that pixel to pad with
+        // here since we can find it pretty easily from here.
+        sub             w13, w4, #(2 + 16 - 3 + 1)
+        ldr             h30, [x3,  w13, sxtw #1]
+        // Fill v30 with the right padding pixel
+        dup             v30.8h,  v30.h[0]
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w4,  #11
+        b.ge            4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+1 pixels valid in v0. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // Insert padding in v0.h[w+1] onwards; fuse the +1 into the
+        // buffer pointer.
+        movrel          x13, right_ext_mask, -1
+        sub             x13, x13, w4,  uxtw #1
+        ld1             {v28.16b, v29.16b}, [x13]
+
+        bit             v0.16b,  v30.16b, v28.16b
+        bit             v1.16b,  v30.16b, v29.16b
+
+4:      // Loop horizontally
+        ext             v26.16b, v0.16b,  v1.16b,  #2
+        ext             v27.16b, v0.16b,  v1.16b,  #4
+
+        add             v6.8h,   v0.8h,   v26.8h
+        umull           v22.4s,  v0.4h,   v0.4h
+        umlal           v22.4s,  v26.4h,  v26.4h
+        umlal           v22.4s,  v27.4h,  v27.4h
+        add             v6.8h,   v6.8h,   v27.8h
+        umull2          v23.4s,  v0.8h,   v0.8h
+        umlal2          v23.4s,  v26.8h,  v26.8h
+        umlal2          v23.4s,  v27.8h,  v27.8h
+
+        ext             v26.16b, v0.16b,  v1.16b,  #6
+        ext             v27.16b, v0.16b,  v1.16b,  #8
+
+        add             v6.8h,   v6.8h,   v26.8h
+        umlal           v22.4s,  v26.4h,  v26.4h
+        umlal           v22.4s,  v27.4h,  v27.4h
+        add             v6.8h,   v6.8h,   v27.8h
+        umlal2          v23.4s,  v26.8h,  v26.8h
+        umlal2          v23.4s,  v27.8h,  v27.8h
+
+        subs            w4,  w4,  #8
+
+        st1             {v6.8h},         [x1],  #16
+        st1             {v22.4s,v23.4s}, [x0],  #32
+
+        b.le            9f
+        tst             w5,  #2 // LR_HAVE_RIGHT
+        mov             v0.16b,  v1.16b
+        ld1             {v1.8h}, [x3], #16
+
+        b.ne            4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        ret
+endfunc
+
+// void dav1d_sgr_box35_row_h_16bpc_neon(int32_t *sumsq3, int16_t *sum3,
+//                                       int32_t *sumsq5, int16_t *sum5,
+//                                       const pixel (*left)[4],
+//                                       const pixel *src, const int w,
+//                                       const enum LrEdgeFlags edges);
+function sgr_box35_row_h_16bpc_neon, export=1
+        add             w6,  w6,  #2 // w += 2
+
+        tst             w7,  #1 // LR_HAVE_LEFT
+        b.eq            1f
+        cbnz            x4,  0f
+
+        // LR_HAVE_LEFT && left == NULL
+        sub             x5,  x5,  #6
+        ld1             {v0.8h, v1.8h}, [x5], #32
+        b               2f
+
+0:
+        // LR_HAVE_LEFT, left != NULL
+        ld1             {v0.8h, v1.8h}, [x5], #32
+        ld1             {v2.d}[1], [x4], #8
+        // Move x3 back to account for the last 3 pixels we loaded earlier,
+        // which we'll shift out.
+        sub             x5,  x5,  #6
+        ext             v1.16b,  v0.16b,  v1.16b,  #10
+        ext             v0.16b,  v2.16b,  v0.16b,  #10
+        b               2f
+
+1:
+        ld1             {v0.8h, v1.8h}, [x5], #32
+        // !LR_HAVE_LEFT, fill v2 with the leftmost pixel
+        // and shift v0/v1 to have 3x the first pixel at the front.
+        dup             v2.8h,  v0.h[0]
+        // Move x5 back to account for the last 3 pixels we loaded before,
+        // which we shifted out.
+        sub             x5,  x5,  #6
+        ext             v1.16b,  v0.16b,  v1.16b,  #10
+        ext             v0.16b,  v2.16b,  v0.16b,  #10
+
+2:
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        b.ne            4f
+        // If we'll need to pad the right edge, load that pixel to pad with
+        // here since we can find it pretty easily from here.
+        sub             w13, w6, #(2 + 16 - 3 + 1)
+        ldr             h30, [x5,  w13, sxtw #1]
+        // Fill v30 with the right padding pixel
+        dup             v30.8h,  v30.h[0]
+3:      // !LR_HAVE_RIGHT
+
+        // Check whether we need to pad the right edge
+        cmp             w6,  #11
+        b.ge            4f   // If w >= 11, all used input pixels are valid
+
+        // 1 <= w < 11, w+1 pixels valid in v0. For w=9 or w=10,
+        // this ends up called again; it's not strictly needed in those
+        // cases (we pad enough here), but keeping the code as simple as possible.
+
+        // Insert padding in v0.b[w+1] onwards; fuse the +1 into the
+        // buffer pointer.
+        movrel          x13, right_ext_mask, -1
+        sub             x13, x13, w6,  uxtw #1
+        ld1             {v28.16b, v29.16b}, [x13]
+
+        bit             v0.16b,  v30.16b, v28.16b
+        bit             v1.16b,  v30.16b, v29.16b
+
+4:      // Loop horizontally
+        ext             v16.16b, v0.16b,  v1.16b,  #2
+        ext             v17.16b, v0.16b,  v1.16b,  #4
+        ext             v19.16b, v0.16b,  v1.16b,  #8
+        ext             v18.16b, v0.16b,  v1.16b,  #6
+
+        add             v20.8h,  v16.8h,  v17.8h
+        add             v21.8h,  v0.8h,   v19.8h
+        add             v20.8h,  v20.8h,  v18.8h
+
+        umull           v22.4s,  v16.4h,  v16.4h
+        umlal           v22.4s,  v17.4h,  v17.4h
+        umlal           v22.4s,  v18.4h,  v18.4h
+
+        umull2          v23.4s,  v16.8h,  v16.8h
+        umlal2          v23.4s,  v17.8h,  v17.8h
+        umlal2          v23.4s,  v18.8h,  v18.8h
+
+        add             v21.8h,  v21.8h,  v20.8h
+        st1             {v20.8h},        [x1], #16
+        st1             {v22.4s,v23.4s}, [x0], #32
+
+        umlal           v22.4s,  v0.4h,   v0.4h
+        umlal           v22.4s,  v19.4h,  v19.4h
+
+        umlal2          v23.4s,  v0.8h,   v0.8h
+        umlal2          v23.4s,  v19.8h,  v19.8h
+
+        subs            w6,  w6,  #8
+
+        st1             {v21.8h},        [x3], #16
+        st1             {v22.4s,v23.4s}, [x2], #32
+
+        b.le            9f
+        tst             w7,  #2 // LR_HAVE_RIGHT
+        mov             v0.16b,  v1.16b
+        ld1             {v1.8h}, [x5], #16
+
+        b.ne            4b // If we don't need to pad, just keep summing.
+        b               3b // If we need to pad, check how many pixels we have left.
+
+9:
+        ret
+endfunc
+
+sgr_funcs 16
diff --git a/media/libdav1d/src/src/arm/64/looprestoration_common.S b/media/libdav1d/src/src/arm/64/looprestoration_common.S
new file mode 100644
index 0000000000..13c2fd5362
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/looprestoration_common.S
@@ -0,0 +1,334 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+// Series of LUTs for efficiently computing sgr's 1 - x/(x+1) table.
+// In the comments, let RefTable denote the original, reference table.
+const x_by_x_tables
+// RangeMins
+//
+// Min(RefTable[i*8:i*8+8])
+// First two values are zeroed.
+//
+// Lookup using RangeMins[(x >> 3)]
+        .byte 0,  0, 11,  8,  6,  5,  5,  4,  4,  3,  3,  3,  2,  2,  2,  2
+        .byte 2,  2,  2,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0
+
+// DiffMasks
+//
+// This contains a bit pattern, indicating at which index positions the value of RefTable changes. For each range
+// in the RangeMins table (covering 8 RefTable entries), we have one byte; each bit indicates whether the value of
+// RefTable changes at that particular index.
+// Using popcount, we can integrate the diff bit field. By shifting away bits in a byte, we can refine the range of
+// the integral. Finally, adding the integral to RangeMins[(x>>3)] reconstructs RefTable (for x > 15).
+//
+// Lookup using DiffMasks[(x >> 3)]
+        .byte 0x00, 0x00, 0xD4, 0x44
+        .byte 0x42, 0x04, 0x00, 0x00
+        .byte 0x00, 0x80, 0x00, 0x00
+        .byte 0x04, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x40, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x00
+        .byte 0x00, 0x00, 0x00, 0x02
+// Binary form:
+// 0b00000000, 0b00000000, 0b11010100, 0b01000100
+// 0b01000010, 0b00000100, 0b00000000, 0b00000000
+// 0b00000000, 0b10000000, 0b00000000, 0b00000000
+// 0b00000100, 0b00000000, 0b00000000, 0b00000000
+// 0b00000000, 0b00000000, 0b00000000, 0b00000000
+// 0b00000000, 0b01000000, 0b00000000, 0b00000000
+// 0b00000000, 0b00000000, 0b00000000, 0b00000000
+// 0b00000000, 0b00000000, 0b00000000, 0b00000010
+
+// RefLo
+//
+// RefTable[0:16]
+//      i.e. First 16 elements of the original table.
+// Add to the sum obtained in the rest of the other lut logic to include the first 16 bytes of RefTable.
+//
+// Lookup using RangeMins[x] (tbl will replace x > 15 with 0)
+        .byte 255, 128,  85,  64,  51,  43,  37,  32, 28,  26,  23,  21,  20,  18,  17,  16
+
+// Pseudo assembly
+//
+// hi_bits = x >> 3
+// tbl             ref,    {RefLo}, x
+// tbl             diffs,  {DiffMasks[0:16], DiffMasks[16:32]}, hi_bits
+// tbl             min,    {RangeMins[0:16], RangeMins[16:32]}, hi_bits
+// lo_bits = x & 0x7
+// diffs = diffs << lo_bits
+// ref = ref + min
+// integral = popcnt(diffs)
+// ref = ref + integral
+// return ref
+endconst
+
+// void dav1d_sgr_box3_vert_neon(int32_t **sumsq, int16_t **sum,
+//                               int32_t *AA, int16_t *BB,
+//                               const int w, const int s,
+//                               const int bitdepth_max);
+function sgr_box3_vert_neon, export=1
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        add             w4,  w4,  #2
+        clz             w9,  w6        // bitdepth_max
+        dup             v28.4s,   w5   // strength
+
+        ldp             x5,  x6,  [x0]
+        ldr             x0,       [x0, #16]
+        ldp             x7,  x8,  [x1]
+        ldr             x1,       [x1, #16]
+
+        movi            v31.4s,   #9   // n
+
+        sub             w9,  w9,  #24  // -bitdepth_min_8
+        movrel          x12, x_by_x_tables
+        mov             w13, #455      // one_by_x
+        ld1             {v24.16b, v25.16b, v26.16b, v27.16b}, [x12] // RangeMins, DiffMasks
+        movi            v22.16b, #0x7
+        ldr             q23, [x12, #64] //RefLo
+        dup             v6.8h,    w9   // -bitdepth_min_8
+        saddl           v7.4s,    v6.4h,   v6.4h  // -2*bitdepth_min_8
+        dup             v30.4s,   w13  // one_by_x
+
+        ld1             {v8.4s,  v9.4s,  v10.4s, v11.4s}, [x5], #64
+        ld1             {v12.4s, v13.4s, v14.4s, v15.4s}, [x6], #64
+        ld1             {v16.4s, v17.4s, v18.4s, v19.4s}, [x0], #64
+        ld1             {v20.8h, v21.8h}, [x8], #32
+        ld1             {v0.8h,  v1.8h},  [x7], #32
+1:
+        ld1             {v2.8h,  v3.8h},   [x1], #32
+        add             v8.4s,   v8.4s,   v12.4s
+        add             v9.4s,   v9.4s,   v13.4s
+        add             v10.4s,  v10.4s,  v14.4s
+        add             v11.4s,  v11.4s,  v15.4s
+        add             v0.8h,   v0.8h,   v20.8h
+        add             v1.8h,   v1.8h,   v21.8h
+
+        add             v16.4s,  v16.4s,  v8.4s
+        add             v17.4s,  v17.4s,  v9.4s
+        add             v18.4s,  v18.4s,  v10.4s
+        add             v19.4s,  v19.4s,  v11.4s
+        add             v4.8h,   v2.8h,   v0.8h
+        add             v5.8h,   v3.8h,   v1.8h
+
+        srshl           v16.4s,  v16.4s,  v7.4s
+        srshl           v17.4s,  v17.4s,  v7.4s
+        srshl           v18.4s,  v18.4s,  v7.4s
+        srshl           v19.4s,  v19.4s,  v7.4s
+        srshl           v9.8h,   v4.8h,   v6.8h
+        srshl           v13.8h,  v5.8h,   v6.8h
+        mul             v16.4s,  v16.4s,  v31.4s // a * n
+        mul             v17.4s,  v17.4s,  v31.4s // a * n
+        mul             v18.4s,  v18.4s,  v31.4s // a * n
+        mul             v19.4s,  v19.4s,  v31.4s // a * n
+        umull           v8.4s,   v9.4h,   v9.4h  // b * b
+        umull2          v9.4s,   v9.8h,   v9.8h  // b * b
+        umull           v12.4s,  v13.4h,  v13.4h // b * b
+        umull2          v13.4s,  v13.8h,  v13.8h // b * b
+        uqsub           v16.4s,  v16.4s,  v8.4s  // imax(a * n - b * b, 0)
+        uqsub           v17.4s,  v17.4s,  v9.4s  // imax(a * n - b * b, 0)
+        uqsub           v18.4s,  v18.4s,  v12.4s // imax(a * n - b * b, 0)
+        uqsub           v19.4s,  v19.4s,  v13.4s // imax(a * n - b * b, 0)
+        mul             v16.4s,  v16.4s,  v28.4s // p * s
+        mul             v17.4s,  v17.4s,  v28.4s // p * s
+        mul             v18.4s,  v18.4s,  v28.4s // p * s
+        mul             v19.4s,  v19.4s,  v28.4s // p * s
+        uqshrn          v16.4h,  v16.4s,  #16
+        uqshrn2         v16.8h,  v17.4s,  #16
+        uqshrn          v18.4h,  v18.4s,  #16
+        uqshrn2         v18.8h,  v19.4s,  #16
+        uqrshrn         v1.8b,   v16.8h,  #4     // imin(z, 255)
+        uqrshrn2        v1.16b,  v18.8h,  #4     // imin(z, 255)
+
+        ld1             {v16.4s, v17.4s}, [x0], #32
+        subs            w4,  w4,  #16
+
+        ushr            v0.16b,  v1.16b,  #3
+        ld1             {v8.4s,  v9.4s}, [x5], #32
+        tbl             v2.16b,  {v26.16b, v27.16b}, v0.16b // RangeMins
+        tbl             v0.16b,  {v24.16b, v25.16b}, v0.16b // DiffMasks
+        tbl             v3.16b,  {v23.16b}, v1.16b          // RefLo
+        and             v1.16b,  v1.16b,   v22.16b
+        ld1             {v12.4s, v13.4s}, [x6], #32
+        ushl            v1.16b,  v2.16b,  v1.16b
+        ld1             {v20.8h, v21.8h}, [x8], #32
+        add             v3.16b,  v3.16b,  v0.16b
+        cnt             v1.16b,  v1.16b
+        ld1             {v18.4s, v19.4s}, [x0], #32
+        add             v3.16b,  v3.16b,  v1.16b
+        ld1             {v10.4s, v11.4s}, [x5], #32
+        uxtl            v0.8h,   v3.8b           // x
+        uxtl2           v1.8h,   v3.16b          // x
+
+        ld1             {v14.4s, v15.4s}, [x6], #32
+
+        umull           v2.4s,   v0.4h,   v4.4h // x * BB[i]
+        umull2          v3.4s,   v0.8h,   v4.8h // x * BB[i]
+        umull           v4.4s,   v1.4h,   v5.4h // x * BB[i]
+        umull2          v5.4s,   v1.8h,   v5.8h // x * BB[i]
+        mul             v2.4s,   v2.4s,  v30.4s // x * BB[i] * sgr_one_by_x
+        mul             v3.4s,   v3.4s,  v30.4s // x * BB[i] * sgr_one_by_x
+        mul             v4.4s,   v4.4s,  v30.4s // x * BB[i] * sgr_one_by_x
+        mul             v5.4s,   v5.4s,  v30.4s // x * BB[i] * sgr_one_by_x
+        st1             {v0.8h, v1.8h}, [x3], #32
+        ld1             {v0.8h, v1.8h}, [x7], #32
+        srshr           v2.4s,   v2.4s,  #12    // AA[i]
+        srshr           v3.4s,   v3.4s,  #12    // AA[i]
+        srshr           v4.4s,   v4.4s,  #12    // AA[i]
+        srshr           v5.4s,   v5.4s,  #12    // AA[i]
+
+        st1             {v2.4s, v3.4s, v4.4s, v5.4s}, [x2], #64
+        b.gt            1b
+
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+endfunc
+
+// void dav1d_sgr_box5_vert_neon(int32_t **sumsq, int16_t **sum,
+//                               int32_t *AA, int16_t *BB,
+//                               const int w, const int s,
+//                               const int bitdepth_max);
+function sgr_box5_vert_neon, export=1
+        stp             d8,  d9,  [sp, #-0x30]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+
+        add             w4,  w4,  #2
+        clz             w15, w6        // bitdepth_max
+        dup             v28.4s,   w5   // strength
+
+        ldp             x5,  x6,  [x0]
+        ldp             x7,  x8,  [x0, #16]
+        ldr             x0,       [x0, #32]
+        ldp             x9,  x10, [x1]
+        ldp             x11, x12, [x1, #16]
+        ldr             x1,       [x1, #32]
+
+        movi            v31.4s,   #25   // n
+
+        sub             w15, w15, #24  // -bitdepth_min_8
+        movrel          x13, x_by_x_tables
+        movi            v30.4s,  #164
+        ld1             {v24.16b, v25.16b, v26.16b, v27.16b}, [x13] // RangeMins, DiffMasks
+        dup             v6.8h,   w15  // -bitdepth_min_8
+        movi            v19.8b,  #0x7
+        ldr             q18, [x13, #64] // RefLo
+        saddl           v7.4s,   v6.4h,   v6.4h  // -2*bitdepth_min_8
+
+        ld1             {v8.4s,  v9.4s},  [x5], #32
+        ld1             {v10.4s, v11.4s}, [x6], #32
+        ld1             {v12.4s, v13.4s}, [x7], #32
+        ld1             {v16.4s, v17.4s}, [x8], #32
+        ld1             {v20.8h},         [x9], #16
+        ld1             {v21.8h},         [x10], #16
+        ld1             {v22.8h},         [x11], #16
+        ld1             {v23.8h},         [x12], #16
+        ld1             {v0.4s,  v1.4s},  [x0], #32
+        ld1             {v2.8h},          [x1], #16
+
+1:
+        add             v8.4s,   v8.4s,   v10.4s
+        add             v9.4s,   v9.4s,   v11.4s
+        add             v12.4s,  v12.4s,  v16.4s
+        add             v13.4s,  v13.4s,  v17.4s
+
+        add             v20.8h,  v20.8h,  v21.8h
+        add             v22.8h,  v22.8h,  v23.8h
+
+        add             v0.4s,   v0.4s,   v8.4s
+        add             v1.4s,   v1.4s,   v9.4s
+        add             v2.8h,   v2.8h,   v20.8h
+
+        add             v0.4s,   v0.4s,   v12.4s
+        add             v1.4s,   v1.4s,   v13.4s
+        add             v2.8h,   v2.8h,   v22.8h
+
+        subs            w4,  w4,  #8
+
+        srshl           v0.4s,   v0.4s,   v7.4s
+        srshl           v1.4s,   v1.4s,   v7.4s
+        srshl           v4.8h,   v2.8h,   v6.8h
+        mul             v0.4s,   v0.4s,   v31.4s // a * n
+        mul             v1.4s,   v1.4s,   v31.4s // a * n
+        umull           v3.4s,   v4.4h,   v4.4h  // b * b
+        umull2          v4.4s,   v4.8h,   v4.8h  // b * b
+        uqsub           v0.4s,   v0.4s,   v3.4s  // imax(a * n - b * b, 0)
+        uqsub           v1.4s,   v1.4s,   v4.4s  // imax(a * n - b * b, 0)
+        mul             v0.4s,   v0.4s,   v28.4s // p * s
+        mul             v1.4s,   v1.4s,   v28.4s // p * s
+        ld1             {v8.4s,  v9.4s},  [x5], #32
+        uqshrn          v0.4h,   v0.4s,   #16
+        uqshrn2         v0.8h,   v1.4s,   #16
+        ld1             {v10.4s, v11.4s}, [x6], #32
+        uqrshrn         v0.8b,   v0.8h,   #4     // imin(z, 255)
+
+        ld1             {v12.4s, v13.4s}, [x7], #32
+
+        ushr            v1.8b,   v0.8b,  #3
+        ld1             {v16.4s, v17.4s}, [x8], #32
+        tbl             v5.8b,   {v26.16b, v27.16b}, v1.8b // RangeMins
+        tbl             v1.8b,   {v24.16b, v25.16b}, v1.8b // DiffMasks
+        tbl             v4.8b,   {v18.16b}, v0.8b          // RefLo
+        and             v0.8b,   v0.8b,  v19.8b
+        ld1             {v20.8h},         [x9], #16
+        ushl            v5.8b,   v5.8b,  v0.8b
+        add             v4.8b,   v4.8b,  v1.8b
+        ld1             {v21.8h},         [x10], #16
+        cnt             v5.8b,   v5.8b
+        ld1             {v22.8h},         [x11], #16
+        add             v5.8b,   v4.8b,  v5.8b
+        ld1             {v23.8h},         [x12], #16
+        uxtl            v5.8h,   v5.8b           // x
+
+        ld1             {v0.4s,  v1.4s},  [x0], #32
+        umull           v3.4s,   v5.4h,   v2.4h  // x * BB[i]
+        umull2          v4.4s,   v5.8h,   v2.8h  // x * BB[i]
+        mul             v3.4s,   v3.4s,   v30.4s // x * BB[i] * sgr_one_by_x
+        mul             v4.4s,   v4.4s,   v30.4s // x * BB[i] * sgr_one_by_x
+        srshr           v3.4s,   v3.4s,   #12    // AA[i]
+        srshr           v4.4s,   v4.4s,   #12    // AA[i]
+        ld1             {v2.8h},          [x1], #16
+
+        st1             {v3.4s, v4.4s}, [x2], #32
+        st1             {v5.8h}, [x3], #16
+        b.gt            1b
+
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x30
+        ret
+endfunc
diff --git a/media/libdav1d/src/src/arm/64/looprestoration_tmpl.S b/media/libdav1d/src/src/arm/64/looprestoration_tmpl.S
new file mode 100644
index 0000000000..96c60f7aa2
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/looprestoration_tmpl.S
@@ -0,0 +1,704 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+
+#define FILTER_OUT_STRIDE 384
+
+.macro sgr_funcs bpc
+// void dav1d_sgr_finish_filter1_2rows_Xbpc_neon(int16_t *tmp,
+//                                               const pixel *src,
+//                                               const ptrdiff_t src_stride,
+//                                               const int32_t **a,
+//                                               const int16_t **b,
+//                                               const int w, const int h);
+function sgr_finish_filter1_2rows_\bpc\()bpc_neon, export=1
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        ldp             x7,  x8,  [x3]
+        ldp             x9,  x3,  [x3, #16]
+        ldp             x10, x11, [x4]
+        ldp             x12, x4,  [x4, #16]
+
+        mov             x13, #FILTER_OUT_STRIDE
+        cmp             w6,  #1
+        add             x2,  x1,  x2 // src + stride
+        csel            x2,  x1,  x2,  le // if (h <= 1) x2 = x1
+        add             x13, x0,  x13, lsl #1
+
+        movi            v30.8h, #3
+        movi            v31.4s, #3
+1:
+        ld1             {v0.8h, v1.8h}, [x10], #32
+        ld1             {v2.8h, v3.8h}, [x11], #32
+        ld1             {v4.8h, v5.8h}, [x12], #32
+        ld1             {v6.8h, v7.8h}, [x4],  #32
+        ld1             {v16.4s, v17.4s, v18.4s}, [x7], #48
+        ld1             {v19.4s, v20.4s, v21.4s}, [x8], #48
+        ld1             {v22.4s, v23.4s, v24.4s}, [x9], #48
+        ld1             {v25.4s, v26.4s, v27.4s}, [x3], #48
+
+2:
+        ext             v8.16b,  v0.16b,  v1.16b, #2  // [0][1]
+        ext             v9.16b,  v2.16b,  v3.16b, #2  // [1][1]
+        ext             v10.16b, v4.16b,  v5.16b, #2  // [2][1]
+        ext             v11.16b, v0.16b,  v1.16b, #4  // [0][2]
+        ext             v12.16b, v2.16b,  v3.16b, #4  // [1][2]
+        ext             v13.16b, v4.16b,  v5.16b, #4  // [2][2]
+
+        add             v14.8h,  v2.8h,   v8.8h       // [1][0] + [0][1]
+        add             v15.8h,  v9.8h,   v10.8h      // [1][1] + [2][1]
+
+        add             v28.8h,  v0.8h,   v11.8h      // [0][0] + [0][2]
+        add             v14.8h,  v14.8h,  v12.8h      // () + [1][2]
+        add             v29.8h,  v4.8h,   v13.8h      // [2][0] + [2][2]
+
+        ext             v8.16b,  v6.16b,  v7.16b, #2  // [3][1]
+        ext             v11.16b, v6.16b,  v7.16b, #4  // [3][2]
+
+        add             v14.8h,  v14.8h,  v15.8h      // mid
+        add             v15.8h,  v28.8h,  v29.8h      // corners
+
+        add             v28.8h,  v4.8h,   v9.8h       // [2][0] + [1][1]
+        add             v29.8h,  v10.8h,  v8.8h       // [2][1] + [3][1]
+
+        add             v2.8h,   v2.8h,   v12.8h      // [1][0] + [1][2]
+        add             v28.8h,  v28.8h,  v13.8h      // () + [2][2]
+        add             v4.8h,   v6.8h,   v11.8h      // [3][0] + [3][2]
+
+        add             v0.8h,   v28.8h,  v29.8h      // mid
+        add             v2.8h,   v2.8h,   v4.8h       // corners
+
+        shl             v4.8h,   v14.8h,  #2
+        mla             v4.8h,   v15.8h,  v30.8h      // * 3 -> a
+
+        shl             v0.8h,   v0.8h,   #2
+        mla             v0.8h,   v2.8h,   v30.8h      // * 3 -> a
+
+        ext             v8.16b,  v16.16b, v17.16b, #4 // [0][1]
+        ext             v9.16b,  v17.16b, v18.16b, #4
+        ext             v10.16b, v16.16b, v17.16b, #8 // [0][2]
+        ext             v11.16b, v17.16b, v18.16b, #8
+        ext             v12.16b, v19.16b, v20.16b, #4 // [1][1]
+        ext             v13.16b, v20.16b, v21.16b, #4
+        add             v8.4s,   v8.4s,   v19.4s      // [0][1] + [1][0]
+        add             v9.4s,   v9.4s,   v20.4s
+        add             v16.4s,  v16.4s,  v10.4s      // [0][0] + [0][2]
+        add             v17.4s,  v17.4s,  v11.4s
+        ext             v14.16b, v19.16b, v20.16b, #8 // [1][2]
+        ext             v15.16b, v20.16b, v21.16b, #8
+        add             v16.4s,  v16.4s,  v22.4s      // () + [2][0]
+        add             v17.4s,  v17.4s,  v23.4s
+        add             v28.4s,  v12.4s,  v14.4s      // [1][1] + [1][2]
+        add             v29.4s,  v13.4s,  v15.4s
+        ext             v10.16b, v22.16b, v23.16b, #4 // [2][1]
+        ext             v11.16b, v23.16b, v24.16b, #4
+        add             v8.4s,   v8.4s,   v28.4s      // mid (incomplete)
+        add             v9.4s,   v9.4s,   v29.4s
+
+        add             v19.4s,  v19.4s,  v14.4s      // [1][0] + [1][2]
+        add             v20.4s,  v20.4s,  v15.4s
+        add             v14.4s,  v22.4s,  v12.4s      // [2][0] + [1][1]
+        add             v15.4s,  v23.4s,  v13.4s
+
+        ext             v12.16b, v22.16b, v23.16b, #8 // [2][2]
+        ext             v13.16b, v23.16b, v24.16b, #8
+        ext             v28.16b, v25.16b, v26.16b, #4 // [3][1]
+        ext             v29.16b, v26.16b, v27.16b, #4
+        add             v8.4s,   v8.4s,   v10.4s      // () + [2][1] = mid
+        add             v9.4s,   v9.4s,   v11.4s
+        add             v14.4s,  v14.4s,  v10.4s      // () + [2][1]
+        add             v15.4s,  v15.4s,  v11.4s
+        ext             v10.16b, v25.16b, v26.16b, #8 // [3][2]
+        ext             v11.16b, v26.16b, v27.16b, #8
+        add             v16.4s,  v16.4s,  v12.4s      // () + [2][2] = corner
+        add             v17.4s,  v17.4s,  v13.4s
+
+        add             v12.4s,  v12.4s,  v28.4s      // [2][2] + [3][1]
+        add             v13.4s,  v13.4s,  v29.4s
+        add             v25.4s,  v25.4s,  v10.4s      // [3][0] + [3][2]
+        add             v26.4s,  v26.4s,  v11.4s
+
+        add             v14.4s,  v14.4s,  v12.4s      // mid
+        add             v15.4s,  v15.4s,  v13.4s
+        add             v19.4s,  v19.4s,  v25.4s      // corner
+        add             v20.4s,  v20.4s,  v26.4s
+
+.if \bpc == 8
+        ld1             {v25.8b}, [x1], #8            // src
+        ld1             {v26.8b}, [x2], #8
+.else
+        ld1             {v25.8h}, [x1], #16           // src
+        ld1             {v26.8h}, [x2], #16
+.endif
+
+        shl             v8.4s,   v8.4s,   #2
+        shl             v9.4s,   v9.4s,   #2
+        mla             v8.4s,   v16.4s,  v31.4s      // * 3 -> b
+        mla             v9.4s,   v17.4s,  v31.4s
+
+.if \bpc == 8
+        uxtl            v25.8h,  v25.8b               // src
+        uxtl            v26.8h,  v26.8b
+.endif
+
+        shl             v14.4s,  v14.4s,  #2
+        shl             v15.4s,  v15.4s,  #2
+        mla             v14.4s,  v19.4s,  v31.4s      // * 3 -> b
+        mla             v15.4s,  v20.4s,  v31.4s
+
+        umlsl           v8.4s,   v4.4h,   v25.4h      // b - a * src
+        umlsl2          v9.4s,   v4.8h,   v25.8h
+        umlsl           v14.4s,  v0.4h,   v26.4h      // b - a * src
+        umlsl2          v15.4s,  v0.8h,   v26.8h
+        mov             v0.16b,  v1.16b
+        rshrn           v8.4h,   v8.4s,   #9
+        rshrn2          v8.8h,   v9.4s,   #9
+        mov             v2.16b,  v3.16b
+        rshrn           v14.4h,  v14.4s,  #9
+        rshrn2          v14.8h,  v15.4s,  #9
+        subs            w5,  w5,  #8
+        mov             v4.16b,  v5.16b
+        st1             {v8.8h},  [x0],  #16
+        mov             v6.16b,  v7.16b
+        st1             {v14.8h}, [x13], #16
+
+        b.le            3f
+        mov             v16.16b, v18.16b
+        mov             v19.16b, v21.16b
+        mov             v22.16b, v24.16b
+        mov             v25.16b, v27.16b
+        ld1             {v1.8h}, [x10], #16
+        ld1             {v3.8h}, [x11], #16
+        ld1             {v5.8h}, [x12], #16
+        ld1             {v7.8h}, [x4],  #16
+        ld1             {v17.4s, v18.4s}, [x7], #32
+        ld1             {v20.4s, v21.4s}, [x8], #32
+        ld1             {v23.4s, v24.4s}, [x9], #32
+        ld1             {v26.4s, v27.4s}, [x3], #32
+        b               2b
+
+3:
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+endfunc
+
+// void dav1d_sgr_finish_weighted1_Xbpc_neon(pixel *dst,
+//                                           const int32_t **a, const int16_t **b,
+//                                           const int w, const int w1,
+//                                           const int bitdepth_max);
+function sgr_finish_weighted1_\bpc\()bpc_neon, export=1
+        ldp             x7,  x8,  [x1]
+        ldr             x1,       [x1, #16]
+        ldp             x9,  x10, [x2]
+        ldr             x2,       [x2, #16]
+
+        dup             v31.8h, w4
+        dup             v30.8h, w5
+
+        movi            v6.8h,  #3
+        movi            v7.4s,  #3
+1:
+        ld1             {v0.8h, v1.8h}, [x9],  #32
+        ld1             {v2.8h, v3.8h}, [x10], #32
+        ld1             {v4.8h, v5.8h}, [x2],  #32
+        ld1             {v16.4s, v17.4s, v18.4s}, [x7], #48
+        ld1             {v19.4s, v20.4s, v21.4s}, [x8], #48
+        ld1             {v22.4s, v23.4s, v24.4s}, [x1], #48
+
+2:
+        ext             v25.16b, v0.16b,  v1.16b, #2  // -stride
+        ext             v26.16b, v2.16b,  v3.16b, #2  // 0
+        ext             v27.16b, v4.16b,  v5.16b, #2  // +stride
+        ext             v28.16b, v0.16b,  v1.16b, #4  // +1-stride
+        ext             v29.16b, v2.16b,  v3.16b, #4  // +1
+        add             v2.8h,   v2.8h,   v25.8h      // -1, -stride
+        ext             v25.16b, v4.16b,  v5.16b, #4  // +1+stride
+        add             v26.8h,  v26.8h,  v27.8h      // 0, +stride
+        add             v0.8h,   v0.8h,   v28.8h      // -1-stride, +1-stride
+        add             v2.8h,   v2.8h,   v26.8h
+        add             v4.8h,   v4.8h,   v25.8h      // -1+stride, +1+stride
+        add             v2.8h,   v2.8h,   v29.8h      // +1
+        add             v0.8h,   v0.8h,   v4.8h
+
+        ext             v25.16b, v16.16b, v17.16b, #4 // -stride
+        ext             v26.16b, v17.16b, v18.16b, #4
+        shl             v2.8h,   v2.8h,   #2
+        ext             v27.16b, v16.16b, v17.16b, #8 // +1-stride
+        ext             v28.16b, v17.16b, v18.16b, #8
+        ext             v29.16b, v19.16b, v20.16b, #4 // 0
+        ext             v4.16b,  v20.16b, v21.16b, #4
+        mla             v2.8h,   v0.8h,   v6.8h       // * 3 -> a
+        add             v25.4s,  v25.4s,  v19.4s      // -stride, -1
+        add             v26.4s,  v26.4s,  v20.4s
+        add             v16.4s,  v16.4s,  v27.4s      // -1-stride, +1-stride
+        add             v17.4s,  v17.4s,  v28.4s
+        ext             v27.16b, v19.16b, v20.16b, #8 // +1
+        ext             v28.16b, v20.16b, v21.16b, #8
+        add             v16.4s,  v16.4s,  v22.4s      // -1+stride
+        add             v17.4s,  v17.4s,  v23.4s
+        add             v29.4s,  v29.4s,  v27.4s      // 0, +1
+        add             v4.4s,   v4.4s,   v28.4s
+        add             v25.4s,  v25.4s,  v29.4s
+        add             v26.4s,  v26.4s,  v4.4s
+        ext             v27.16b, v22.16b, v23.16b, #4 // +stride
+        ext             v28.16b, v23.16b, v24.16b, #4
+        ext             v29.16b, v22.16b, v23.16b, #8 // +1+stride
+        ext             v4.16b,  v23.16b, v24.16b, #8
+.if \bpc == 8
+        ld1             {v19.8b}, [x0]                // src
+.else
+        ld1             {v19.8h}, [x0]                // src
+.endif
+        add             v25.4s,  v25.4s,  v27.4s      // +stride
+        add             v26.4s,  v26.4s,  v28.4s
+        add             v16.4s,  v16.4s,  v29.4s      // +1+stride
+        add             v17.4s,  v17.4s,  v4.4s
+        shl             v25.4s,  v25.4s,  #2
+        shl             v26.4s,  v26.4s,  #2
+        mla             v25.4s,  v16.4s,  v7.4s       // * 3 -> b
+        mla             v26.4s,  v17.4s,  v7.4s
+.if \bpc == 8
+        uxtl            v19.8h,  v19.8b               // src
+.endif
+        mov             v0.16b,  v1.16b
+        umlsl           v25.4s,  v2.4h,   v19.4h      // b - a * src
+        umlsl2          v26.4s,  v2.8h,   v19.8h
+        mov             v2.16b,  v3.16b
+        rshrn           v25.4h,  v25.4s,  #9
+        rshrn2          v25.8h,  v26.4s,  #9
+
+        subs            w3,  w3,  #8
+
+        // weighted1
+        mov             v4.16b,  v5.16b
+
+        ld1             {v1.8h}, [x9],  #16
+        ld1             {v3.8h}, [x10], #16
+        smull           v26.4s,  v25.4h,  v31.4h // v = t1 * w1
+        smull2          v27.4s,  v25.8h,  v31.8h
+        ld1             {v5.8h}, [x2],  #16
+        rshrn           v26.4h,  v26.4s,  #11
+        rshrn2          v26.8h,  v27.4s,  #11
+        usqadd          v19.8h,  v26.8h
+.if \bpc == 8
+        mov             v16.16b, v18.16b
+        sqxtun          v26.8b,  v19.8h
+        mov             v19.16b, v21.16b
+        mov             v22.16b, v24.16b
+        st1             {v26.8b}, [x0], #8
+.else
+        mov             v16.16b, v18.16b
+        umin            v26.8h,  v19.8h,  v30.8h
+        mov             v19.16b, v21.16b
+        mov             v22.16b, v24.16b
+        st1             {v26.8h}, [x0], #16
+.endif
+
+        b.le            3f
+        ld1             {v17.4s, v18.4s}, [x7], #32
+        ld1             {v20.4s, v21.4s}, [x8], #32
+        ld1             {v23.4s, v24.4s}, [x1], #32
+        b               2b
+
+3:
+        ret
+endfunc
+
+// void dav1d_sgr_finish_filter2_2rows_Xbpc_neon(int16_t *tmp,
+//                                               const pixel *src,
+//                                               const ptrdiff_t stride,
+//                                               const int32_t **a,
+//                                               const int16_t **b,
+//                                               const int w, const int h);
+function sgr_finish_filter2_2rows_\bpc\()bpc_neon, export=1
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+        ldp             x3,  x7,  [x3]
+        ldp             x4,  x8,  [x4]
+        mov             x10, #FILTER_OUT_STRIDE
+        cmp             w6,  #1
+        add             x2,  x1,  x2 // src + stride
+        csel            x2,  x1,  x2,  le // if (h <= 1) x2 = x1
+        add             x10, x0,  x10, lsl #1
+        movi            v4.8h,  #5
+        movi            v5.4s,  #5
+        movi            v6.8h,  #6
+        movi            v7.4s,  #6
+1:
+        ld1             {v0.8h, v1.8h}, [x4], #32
+        ld1             {v2.8h, v3.8h}, [x8], #32
+        ld1             {v16.4s, v17.4s, v18.4s}, [x3], #48
+        ld1             {v19.4s, v20.4s, v21.4s}, [x7], #48
+
+2:
+        ext             v24.16b, v0.16b,  v1.16b, #4  // +1-stride
+        ext             v25.16b, v2.16b,  v3.16b, #4  // +1+stride
+        ext             v22.16b, v0.16b,  v1.16b, #2  // -stride
+        ext             v23.16b, v2.16b,  v3.16b, #2  // +stride
+        add             v0.8h,   v0.8h,   v24.8h      // -1-stride, +1-stride
+        add             v25.8h,  v2.8h,   v25.8h      // -1+stride, +1+stride
+        add             v2.8h,   v22.8h,  v23.8h      // -stride, +stride
+        add             v0.8h,   v0.8h,   v25.8h
+
+        mul             v8.8h,   v25.8h,  v4.8h       // * 5
+        mla             v8.8h,   v23.8h,  v6.8h       // * 6
+
+        ext             v22.16b, v16.16b, v17.16b, #4 // -stride
+        ext             v23.16b, v17.16b, v18.16b, #4
+        ext             v24.16b, v19.16b, v20.16b, #4 // +stride
+        ext             v25.16b, v20.16b, v21.16b, #4
+        ext             v26.16b, v16.16b, v17.16b, #8 // +1-stride
+        ext             v27.16b, v17.16b, v18.16b, #8
+        ext             v28.16b, v19.16b, v20.16b, #8 // +1+stride
+        ext             v29.16b, v20.16b, v21.16b, #8
+        mul             v0.8h,   v0.8h,   v4.8h       // * 5
+        mla             v0.8h,   v2.8h,   v6.8h       // * 6
+.if \bpc == 8
+        ld1             {v31.8b}, [x1], #8
+        ld1             {v30.8b}, [x2], #8
+.else
+        ld1             {v31.8h}, [x1], #16
+        ld1             {v30.8h}, [x2], #16
+.endif
+        add             v16.4s,  v16.4s,  v26.4s      // -1-stride, +1-stride
+        add             v17.4s,  v17.4s,  v27.4s
+        add             v19.4s,  v19.4s,  v28.4s      // -1+stride, +1+stride
+        add             v20.4s,  v20.4s,  v29.4s
+        add             v16.4s,  v16.4s,  v19.4s
+        add             v17.4s,  v17.4s,  v20.4s
+
+        mul             v9.4s,   v19.4s,  v5.4s       // * 5
+        mla             v9.4s,   v24.4s,  v7.4s       // * 6
+        mul             v10.4s,  v20.4s,  v5.4s       // * 5
+        mla             v10.4s,  v25.4s,  v7.4s       // * 6
+
+        add             v22.4s,  v22.4s,  v24.4s      // -stride, +stride
+        add             v23.4s,  v23.4s,  v25.4s
+        // This is, surprisingly, faster than other variants where the
+        // mul+mla pairs are further apart, on Cortex A53.
+        mul             v16.4s,  v16.4s,  v5.4s       // * 5
+        mla             v16.4s,  v22.4s,  v7.4s       // * 6
+        mul             v17.4s,  v17.4s,  v5.4s       // * 5
+        mla             v17.4s,  v23.4s,  v7.4s       // * 6
+
+.if \bpc == 8
+        uxtl            v31.8h,  v31.8b
+        uxtl            v30.8h,  v30.8b
+.endif
+        umlsl           v16.4s,  v0.4h,   v31.4h      // b - a * src
+        umlsl2          v17.4s,  v0.8h,   v31.8h
+        umlsl           v9.4s,   v8.4h,   v30.4h      // b - a * src
+        umlsl2          v10.4s,  v8.8h,   v30.8h
+        mov             v0.16b,  v1.16b
+        rshrn           v16.4h,  v16.4s,  #9
+        rshrn2          v16.8h,  v17.4s,  #9
+        rshrn           v9.4h,   v9.4s,   #8
+        rshrn2          v9.8h,   v10.4s,  #8
+        subs            w5,  w5,  #8
+        mov             v2.16b,  v3.16b
+        st1             {v16.8h}, [x0],  #16
+        st1             {v9.8h},  [x10], #16
+
+        b.le            9f
+        mov             v16.16b, v18.16b
+        mov             v19.16b, v21.16b
+        ld1             {v1.8h}, [x4], #16
+        ld1             {v3.8h}, [x8], #16
+        ld1             {v17.4s, v18.4s}, [x3], #32
+        ld1             {v20.4s, v21.4s}, [x7], #32
+        b               2b
+
+9:
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+        ret
+endfunc
+
+// void dav1d_sgr_finish_weighted2_Xbpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                           const int32_t **a,
+//                                           const int16_t **b,
+//                                           const int w, const int h,
+//                                           const int w1,
+//                                           const int bitdepth_max);
+function sgr_finish_weighted2_\bpc\()bpc_neon, export=1
+        stp             d8,  d9,  [sp, #-0x30]!
+        str             d10,      [sp, #0x10]
+        stp             d14, d15, [sp, #0x20]
+
+        dup             v14.8h, w6
+        dup             v15.8h, w7
+
+        ldp             x2,  x7,  [x2]
+        ldp             x3,  x8,  [x3]
+        cmp             w5,  #1
+        add             x1,  x0,  x1 // src + stride
+        // if (h <= 1), set the pointer to the second row to any dummy buffer
+        // we can clobber (x2 in this case)
+        csel            x1,  x2,  x1,  le
+        movi            v4.8h,  #5
+        movi            v5.4s,  #5
+        movi            v6.8h,  #6
+        movi            v7.4s,  #6
+1:
+        ld1             {v0.8h, v1.8h}, [x3], #32
+        ld1             {v2.8h, v3.8h}, [x8], #32
+        ld1             {v16.4s, v17.4s, v18.4s}, [x2], #48
+        ld1             {v19.4s, v20.4s, v21.4s}, [x7], #48
+
+2:
+        ext             v24.16b, v0.16b,  v1.16b, #4  // +1-stride
+        ext             v25.16b, v2.16b,  v3.16b, #4  // +1+stride
+        ext             v22.16b, v0.16b,  v1.16b, #2  // -stride
+        ext             v23.16b, v2.16b,  v3.16b, #2  // +stride
+        add             v0.8h,   v0.8h,   v24.8h      // -1-stride, +1-stride
+        add             v25.8h,  v2.8h,   v25.8h      // -1+stride, +1+stride
+        add             v2.8h,   v22.8h,  v23.8h      // -stride, +stride
+        add             v0.8h,   v0.8h,   v25.8h
+
+        mul             v8.8h,   v25.8h,  v4.8h       // * 5
+        mla             v8.8h,   v23.8h,  v6.8h       // * 6
+
+        ext             v22.16b, v16.16b, v17.16b, #4 // -stride
+        ext             v23.16b, v17.16b, v18.16b, #4
+        ext             v24.16b, v19.16b, v20.16b, #4 // +stride
+        ext             v25.16b, v20.16b, v21.16b, #4
+        ext             v26.16b, v16.16b, v17.16b, #8 // +1-stride
+        ext             v27.16b, v17.16b, v18.16b, #8
+        ext             v28.16b, v19.16b, v20.16b, #8 // +1+stride
+        ext             v29.16b, v20.16b, v21.16b, #8
+        mul             v0.8h,   v0.8h,   v4.8h       // * 5
+        mla             v0.8h,   v2.8h,   v6.8h       // * 6
+.if \bpc == 8
+        ld1             {v31.8b}, [x0]
+        ld1             {v30.8b}, [x1]
+.else
+        ld1             {v31.8h}, [x0]
+        ld1             {v30.8h}, [x1]
+.endif
+        add             v16.4s,  v16.4s,  v26.4s      // -1-stride, +1-stride
+        add             v17.4s,  v17.4s,  v27.4s
+        add             v19.4s,  v19.4s,  v28.4s      // -1+stride, +1+stride
+        add             v20.4s,  v20.4s,  v29.4s
+        add             v16.4s,  v16.4s,  v19.4s
+        add             v17.4s,  v17.4s,  v20.4s
+
+        mul             v9.4s,   v19.4s,  v5.4s       // * 5
+        mla             v9.4s,   v24.4s,  v7.4s       // * 6
+        mul             v10.4s,  v20.4s,  v5.4s       // * 5
+        mla             v10.4s,  v25.4s,  v7.4s       // * 6
+
+        add             v22.4s,  v22.4s,  v24.4s      // -stride, +stride
+        add             v23.4s,  v23.4s,  v25.4s
+        // This is, surprisingly, faster than other variants where the
+        // mul+mla pairs are further apart, on Cortex A53.
+        mul             v16.4s,  v16.4s,  v5.4s       // * 5
+        mla             v16.4s,  v22.4s,  v7.4s       // * 6
+        mul             v17.4s,  v17.4s,  v5.4s       // * 5
+        mla             v17.4s,  v23.4s,  v7.4s       // * 6
+
+.if \bpc == 8
+        uxtl            v31.8h,  v31.8b
+        uxtl            v30.8h,  v30.8b
+.endif
+        umlsl           v16.4s,  v0.4h,   v31.4h      // b - a * src
+        umlsl2          v17.4s,  v0.8h,   v31.8h
+        umlsl           v9.4s,   v8.4h,   v30.4h      // b - a * src
+        umlsl2          v10.4s,  v8.8h,   v30.8h
+        mov             v0.16b,  v1.16b
+        rshrn           v16.4h,  v16.4s,  #9
+        rshrn2          v16.8h,  v17.4s,  #9
+        rshrn           v9.4h,   v9.4s,   #8
+        rshrn2          v9.8h,   v10.4s,  #8
+
+        subs            w4,  w4,  #8
+
+        // weighted1
+        mov             v2.16b,  v3.16b
+
+        ld1             {v1.8h}, [x3], #16
+        ld1             {v3.8h}, [x8], #16
+        smull           v22.4s,  v16.4h,  v14.4h // v
+        smull2          v23.4s,  v16.8h,  v14.8h
+        mov             v16.16b, v18.16b
+        smull           v24.4s,  v9.4h,   v14.4h
+        smull2          v25.4s,  v9.8h,   v14.8h
+        mov             v19.16b, v21.16b
+        rshrn           v22.4h,  v22.4s,  #11
+        rshrn2          v22.8h,  v23.4s,  #11
+        rshrn           v23.4h,  v24.4s,  #11
+        rshrn2          v23.8h,  v25.4s,  #11
+        usqadd          v31.8h,  v22.8h
+        usqadd          v30.8h,  v23.8h
+.if \bpc == 8
+        sqxtun          v22.8b,  v31.8h
+        sqxtun          v23.8b,  v30.8h
+        st1             {v22.8b}, [x0], #8
+        st1             {v23.8b}, [x1], #8
+.else
+        umin            v22.8h,  v31.8h,  v15.8h
+        umin            v23.8h,  v30.8h,  v15.8h
+        st1             {v22.8h}, [x0], #16
+        st1             {v23.8h}, [x1], #16
+.endif
+
+        b.le            3f
+        ld1             {v17.4s, v18.4s}, [x2], #32
+        ld1             {v20.4s, v21.4s}, [x7], #32
+        b               2b
+
+3:
+        ldp             d14, d15, [sp, #0x20]
+        ldr             d10,      [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x30
+        ret
+endfunc
+
+// void dav1d_sgr_weighted2_Xbpc_neon(pixel *dst, const ptrdiff_t stride,
+//                                    const int16_t *t1, const int16_t *t2,
+//                                    const int w, const int h,
+//                                    const int16_t wt[2], const int bitdepth_max);
+function sgr_weighted2_\bpc\()bpc_neon, export=1
+        cmp             w5,  #2
+        add             x10, x0,  x1
+        add             x12, x2,  #2*FILTER_OUT_STRIDE
+        add             x13, x3,  #2*FILTER_OUT_STRIDE
+        ld2r            {v30.8h, v31.8h}, [x6] // wt[0], wt[1]
+.if \bpc == 16
+        dup             v29.8h,  w7
+.endif
+        mov             x8,  #4*FILTER_OUT_STRIDE
+        lsl             x1,  x1,  #1
+        add             w9,  w4,  #7
+        bic             x9,  x9,  #7 // Aligned width
+.if \bpc == 8
+        sub             x1,  x1,  x9
+.else
+        sub             x1,  x1,  x9, lsl #1
+.endif
+        sub             x8,  x8,  x9, lsl #1
+        mov             w9,  w4
+        b.lt            2f
+1:
+.if \bpc == 8
+        ld1             {v0.8b},  [x0]
+        ld1             {v16.8b}, [x10]
+.else
+        ld1             {v0.8h},  [x0]
+        ld1             {v16.8h}, [x10]
+.endif
+        ld1             {v1.8h},  [x2],  #16
+        ld1             {v17.8h}, [x12], #16
+        ld1             {v2.8h},  [x3],  #16
+        ld1             {v18.8h}, [x13], #16
+        subs            w4,  w4,  #8
+.if \bpc == 8
+        uxtl            v0.8h,  v0.8b
+        uxtl            v16.8h, v16.8b
+.endif
+        smull           v3.4s,  v1.4h,  v30.4h // wt[0] * t1
+        smlal           v3.4s,  v2.4h,  v31.4h // wt[1] * t2
+        smull2          v4.4s,  v1.8h,  v30.8h // wt[0] * t1
+        smlal2          v4.4s,  v2.8h,  v31.8h // wt[1] * t2
+        smull           v19.4s, v17.4h, v30.4h // wt[0] * t1
+        smlal           v19.4s, v18.4h, v31.4h // wt[1] * t2
+        smull2          v20.4s, v17.8h, v30.8h // wt[0] * t1
+        smlal2          v20.4s, v18.8h, v31.8h // wt[1] * t2
+        rshrn           v3.4h,  v3.4s,  #11
+        rshrn2          v3.8h,  v4.4s,  #11
+        rshrn           v19.4h, v19.4s, #11
+        rshrn2          v19.8h, v20.4s, #11
+        usqadd          v0.8h,  v3.8h
+        usqadd          v16.8h, v19.8h
+.if \bpc == 8
+        sqxtun          v3.8b,  v0.8h
+        sqxtun          v19.8b, v16.8h
+        st1             {v3.8b},  [x0],  #8
+        st1             {v19.8b}, [x10], #8
+.else
+        umin            v3.8h,  v0.8h,  v29.8h
+        umin            v19.8h, v16.8h, v29.8h
+        st1             {v3.8h},  [x0],  #16
+        st1             {v19.8h}, [x10], #16
+.endif
+        b.gt            1b
+
+        subs            w5,  w5,  #2
+        cmp             w5,  #1
+        b.lt            0f
+        mov             w4,  w9
+        add             x0,  x0,  x1
+        add             x10, x10, x1
+        add             x2,  x2,  x8
+        add             x12, x12, x8
+        add             x3,  x3,  x8
+        add             x13, x13, x8
+        b.eq            2f
+        b               1b
+
+2:
+.if \bpc == 8
+        ld1             {v0.8b}, [x0]
+.else
+        ld1             {v0.8h}, [x0]
+.endif
+        ld1             {v1.8h}, [x2], #16
+        ld1             {v2.8h}, [x3], #16
+        subs            w4,  w4,  #8
+.if \bpc == 8
+        uxtl            v0.8h,  v0.8b
+.endif
+        smull           v3.4s,  v1.4h,  v30.4h // wt[0] * t1
+        smlal           v3.4s,  v2.4h,  v31.4h // wt[1] * t2
+        smull2          v4.4s,  v1.8h,  v30.8h // wt[0] * t1
+        smlal2          v4.4s,  v2.8h,  v31.8h // wt[1] * t2
+        rshrn           v3.4h,  v3.4s,  #11
+        rshrn2          v3.8h,  v4.4s,  #11
+        usqadd          v0.8h,  v3.8h
+.if \bpc == 8
+        sqxtun          v3.8b,  v0.8h
+        st1             {v3.8b}, [x0], #8
+.else
+        umin            v3.8h,  v0.8h,  v29.8h
+        st1             {v3.8h}, [x0], #16
+.endif
+        b.gt            2b
+0:
+        ret
+endfunc
+.endm
diff --git a/media/libdav1d/src/src/arm/64/mc.S b/media/libdav1d/src/src/arm/64/mc.S
new file mode 100644
index 0000000000..24ef4d298a
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/mc.S
@@ -0,0 +1,3574 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * Copyright © 2018, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+.macro avg dst, t0, t1, t2, t3
+        ld1             {\t0\().8h,\t1\().8h},   [x2],  32
+        ld1             {\t2\().8h,\t3\().8h},   [x3],  32
+        add             \t0\().8h,   \t0\().8h,   \t2\().8h
+        add             \t1\().8h,   \t1\().8h,   \t3\().8h
+        sqrshrun        \dst\().8b,  \t0\().8h,   #5
+        sqrshrun2       \dst\().16b, \t1\().8h,   #5
+.endm
+
+.macro w_avg dst, t0, t1, t2, t3
+        ld1             {\t0\().8h,\t1\().8h},   [x2],  32
+        ld1             {\t2\().8h,\t3\().8h},   [x3],  32
+        sub             \t0\().8h,   \t2\().8h,   \t0\().8h
+        sub             \t1\().8h,   \t3\().8h,   \t1\().8h
+        sqdmulh         \t0\().8h,   \t0\().8h,   v30.8h
+        sqdmulh         \t1\().8h,   \t1\().8h,   v30.8h
+        add             \t0\().8h,   \t2\().8h,   \t0\().8h
+        add             \t1\().8h,   \t3\().8h,   \t1\().8h
+        sqrshrun        \dst\().8b,  \t0\().8h,   #4
+        sqrshrun2       \dst\().16b, \t1\().8h,   #4
+.endm
+
+.macro mask dst, t0, t1, t2, t3
+        ld1             {v30.16b}, [x6],  16
+        ld1             {\t0\().8h,\t1\().8h},   [x2],  32
+        mul             v30.16b, v30.16b, v31.16b
+        ld1             {\t2\().8h,\t3\().8h},   [x3],  32
+        shll            v28.8h, v30.8b,  #8
+        shll2           v29.8h, v30.16b, #8
+        sub             \t0\().8h,   \t2\().8h,   \t0\().8h
+        sub             \t1\().8h,   \t3\().8h,   \t1\().8h
+        sqdmulh         \t0\().8h,   \t0\().8h,   v28.8h
+        sqdmulh         \t1\().8h,   \t1\().8h,   v29.8h
+        add             \t0\().8h,   \t2\().8h,   \t0\().8h
+        add             \t1\().8h,   \t3\().8h,   \t1\().8h
+        sqrshrun        \dst\().8b,  \t0\().8h,   #4
+        sqrshrun2       \dst\().16b, \t1\().8h,   #4
+.endm
+
+.macro bidir_fn type
+function \type\()_8bpc_neon, export=1
+        clz             w4,  w4
+.ifc \type, w_avg
+        dup             v30.8h, w6
+        neg             v30.8h, v30.8h
+        shl             v30.8h, v30.8h, #11
+.endif
+.ifc \type, mask
+        movi            v31.16b, #256-2
+.endif
+        movrel          x7,  \type\()_tbl
+        sub             w4,  w4,  #24
+        ldrsw           x4,  [x7, x4, lsl #2]
+        \type           v4,  v0,  v1,  v2,  v3
+        add             x7,  x7,  x4
+        br              x7
+40:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  x1
+        lsl             x1,  x1,  #1
+4:
+        cmp             w5,  #4
+        st1             {v4.s}[0],  [x0], x1
+        st1             {v4.s}[1],  [x7], x1
+        st1             {v4.s}[2],  [x0], x1
+        st1             {v4.s}[3],  [x7], x1
+        b.eq            0f
+        \type           v5,  v0,  v1,  v2,  v3
+        cmp             w5,  #8
+        st1             {v5.s}[0],  [x0], x1
+        st1             {v5.s}[1],  [x7], x1
+        st1             {v5.s}[2],  [x0], x1
+        st1             {v5.s}[3],  [x7], x1
+        b.eq            0f
+        \type           v4,  v0,  v1,  v2,  v3
+        st1             {v4.s}[0],  [x0], x1
+        st1             {v4.s}[1],  [x7], x1
+        \type           v5,  v0,  v1,  v2,  v3
+        st1             {v4.s}[2],  [x0], x1
+        st1             {v4.s}[3],  [x7], x1
+        st1             {v5.s}[0],  [x0], x1
+        st1             {v5.s}[1],  [x7], x1
+        st1             {v5.s}[2],  [x0], x1
+        st1             {v5.s}[3],  [x7], x1
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  x1
+        lsl             x1,  x1,  #1
+8:
+        st1             {v4.8b},    [x0], x1
+        \type           v5,  v0,  v1,  v2,  v3
+        st1             {v4.d}[1],  [x7], x1
+        st1             {v5.8b},    [x0], x1
+        subs            w5,  w5,  #4
+        st1             {v5.d}[1],  [x7], x1
+        b.le            0f
+        \type           v4,  v0,  v1,  v2,  v3
+        b               8b
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        \type           v5,  v0,  v1,  v2,  v3
+        st1             {v4.16b}, [x0], x1
+        \type           v6,  v0,  v1,  v2,  v3
+        st1             {v5.16b}, [x0], x1
+        \type           v7,  v0,  v1,  v2,  v3
+        st1             {v6.16b}, [x0], x1
+        subs            w5,  w5,  #4
+        st1             {v7.16b}, [x0], x1
+        b.le            0f
+        \type           v4,  v0,  v1,  v2,  v3
+        b               16b
+320:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  x1
+        lsl             x1,  x1,  #1
+32:
+        \type           v5,  v0,  v1,  v2,  v3
+        \type           v6,  v0,  v1,  v2,  v3
+        st1             {v4.16b,v5.16b}, [x0], x1
+        \type           v7,  v0,  v1,  v2,  v3
+        subs            w5,  w5,  #2
+        st1             {v6.16b,v7.16b}, [x7], x1
+        b.le            0f
+        \type           v4,  v0,  v1,  v2,  v3
+        b               32b
+640:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  x1
+        lsl             x1,  x1,  #1
+64:
+        \type           v5,  v0,  v1,  v2,  v3
+        \type           v6,  v0,  v1,  v2,  v3
+        \type           v7,  v0,  v1,  v2,  v3
+        \type           v16, v0,  v1,  v2,  v3
+        \type           v17, v0,  v1,  v2,  v3
+        st1             {v4.16b,v5.16b,v6.16b,v7.16b}, [x0], x1
+        \type           v18, v0,  v1,  v2,  v3
+        \type           v19, v0,  v1,  v2,  v3
+        subs            w5,  w5,  #2
+        st1             {v16.16b,v17.16b,v18.16b,v19.16b}, [x7], x1
+        b.le            0f
+        \type           v4, v0,  v1,  v2,  v3
+        b               64b
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  #64
+128:
+        \type           v5,  v0,  v1,  v2,  v3
+        \type           v6,  v0,  v1,  v2,  v3
+        \type           v7,  v0,  v1,  v2,  v3
+        \type           v16, v0,  v1,  v2,  v3
+        \type           v17, v0,  v1,  v2,  v3
+        st1             {v4.16b,v5.16b,v6.16b,v7.16b}, [x0], x1
+        \type           v18, v0,  v1,  v2,  v3
+        \type           v19, v0,  v1,  v2,  v3
+        subs            w5,  w5,  #1
+        st1             {v16.16b,v17.16b,v18.16b,v19.16b}, [x7], x1
+        b.le            0f
+        \type           v4, v0,  v1,  v2,  v3
+        b               128b
+0:
+        ret
+endfunc
+
+jumptable \type\()_tbl
+        .word 1280b - \type\()_tbl
+        .word 640b  - \type\()_tbl
+        .word 320b  - \type\()_tbl
+        .word 160b  - \type\()_tbl
+        .word 80b   - \type\()_tbl
+        .word 40b   - \type\()_tbl
+endjumptable
+.endm
+
+bidir_fn avg
+bidir_fn w_avg
+bidir_fn mask
+
+
+.macro w_mask_fn type
+function w_mask_\type\()_8bpc_neon, export=1
+        clz             w8,  w4
+        movrel          x9,  w_mask_\type\()_tbl
+        sub             w8,  w8,  #24
+        ldrsw           x8,  [x9,  x8,  lsl #2]
+        add             x9,  x9,  x8
+        mov             w10, #6903
+        dup             v0.8h,   w10
+.if \type == 444
+        movi            v1.16b,  #64
+.elseif \type == 422
+        dup             v2.8b,   w7
+        movi            v3.8b,   #129
+        sub             v3.8b,   v3.8b,   v2.8b
+.elseif \type == 420
+        dup             v2.8h,   w7
+        movi            v3.8h,   #1, lsl #8
+        sub             v3.8h,   v3.8h,   v2.8h
+.endif
+        add             x12,  x0,  x1
+        lsl             x1,   x1,  #1
+        br              x9
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ld1             {v4.8h,   v5.8h},   [x2],  #32  // tmp1 (four rows at once)
+        ld1             {v6.8h,   v7.8h},   [x3],  #32  // tmp2 (four rows at once)
+        subs            w5,  w5,  #4
+        sub             v16.8h,  v6.8h,   v4.8h
+        sub             v17.8h,  v7.8h,   v5.8h
+        sabd            v18.8h,  v4.8h,   v6.8h
+        sabd            v19.8h,  v5.8h,   v7.8h
+        uqsub           v18.8h,  v0.8h,   v18.8h
+        uqsub           v19.8h,  v0.8h,   v19.8h
+        ushr            v18.8h,  v18.8h,  #8
+        ushr            v19.8h,  v19.8h,  #8
+        shl             v20.8h,  v18.8h,  #9
+        shl             v21.8h,  v19.8h,  #9
+        sqdmulh         v20.8h,  v20.8h,  v16.8h
+        sqdmulh         v21.8h,  v21.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v4.8h
+        add             v21.8h,  v21.8h,  v5.8h
+        sqrshrun        v22.8b,  v20.8h,  #4
+        sqrshrun        v23.8b,  v21.8h,  #4
+.if \type == 444
+        uzp1            v18.16b,  v18.16b, v19.16b      // Same as xtn, xtn2
+        sub             v18.16b,  v1.16b,  v18.16b
+        st1             {v18.16b}, [x6],  #16
+.elseif \type == 422
+        addp            v18.8h,   v18.8h,  v19.8h
+        xtn             v18.8b,   v18.8h
+        uhsub           v18.8b,   v3.8b,   v18.8b
+        st1             {v18.8b},  [x6],  #8
+.elseif \type == 420
+        trn1            v24.2d,   v18.2d,  v19.2d
+        trn2            v25.2d,   v18.2d,  v19.2d
+        add             v24.8h,   v24.8h,  v25.8h
+        addp            v18.8h,   v24.8h,  v24.8h
+        sub             v18.4h,   v3.4h,   v18.4h
+        rshrn           v18.8b,   v18.8h,  #2
+        str             s18,         [x6],  #4
+.endif
+        st1             {v22.s}[0],  [x0],  x1
+        st1             {v22.s}[1],  [x12], x1
+        st1             {v23.s}[0],  [x0],  x1
+        st1             {v23.s}[1],  [x12], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ld1             {v4.8h,   v5.8h},   [x2],  #32
+        ld1             {v6.8h,   v7.8h},   [x3],  #32
+        subs            w5,  w5,  #2
+        sub             v16.8h,  v6.8h,   v4.8h
+        sub             v17.8h,  v7.8h,   v5.8h
+        sabd            v18.8h,  v4.8h,   v6.8h
+        sabd            v19.8h,  v5.8h,   v7.8h
+        uqsub           v18.8h,  v0.8h,   v18.8h
+        uqsub           v19.8h,  v0.8h,   v19.8h
+        ushr            v18.8h,  v18.8h,  #8
+        ushr            v19.8h,  v19.8h,  #8
+        shl             v20.8h,  v18.8h,  #9
+        shl             v21.8h,  v19.8h,  #9
+        sqdmulh         v20.8h,  v20.8h,  v16.8h
+        sqdmulh         v21.8h,  v21.8h,  v17.8h
+        add             v20.8h,  v20.8h,  v4.8h
+        add             v21.8h,  v21.8h,  v5.8h
+        sqrshrun        v22.8b,  v20.8h,  #4
+        sqrshrun        v23.8b,  v21.8h,  #4
+.if \type == 444
+        uzp1            v18.16b, v18.16b, v19.16b       // Same as xtn, xtn2
+        sub             v18.16b, v1.16b,  v18.16b
+        st1             {v18.16b}, [x6],  #16
+.elseif \type == 422
+        addp            v18.8h,  v18.8h,  v19.8h
+        xtn             v18.8b,  v18.8h
+        uhsub           v18.8b,  v3.8b,   v18.8b
+        st1             {v18.8b},  [x6],  #8
+.elseif \type == 420
+        add             v18.8h,  v18.8h,  v19.8h
+        addp            v18.8h,  v18.8h,  v18.8h
+        sub             v18.4h,  v3.4h,   v18.4h
+        rshrn           v18.8b,  v18.8h,  #2
+        str             s18,       [x6],  #4
+.endif
+        st1             {v22.8b},  [x0],  x1
+        st1             {v23.8b},  [x12], x1
+        b.gt            8b
+        ret
+1280:
+640:
+320:
+160:
+        AARCH64_VALID_JUMP_TARGET
+        mov             w11, w4
+        sub             x1,  x1,  w4,  uxtw
+.if \type == 444
+        add             x10, x6,  w4,  uxtw
+.elseif \type == 422
+        add             x10, x6,  x11, lsr #1
+.endif
+        add             x9,  x3,  w4,  uxtw #1
+        add             x7,  x2,  w4,  uxtw #1
+161:
+        mov             w8,  w4
+16:
+        ld1             {v4.8h,   v5.8h},   [x2],  #32
+        ld1             {v6.8h,   v7.8h},   [x3],  #32
+        ld1             {v16.8h,  v17.8h},  [x7],  #32
+        ld1             {v18.8h,  v19.8h},  [x9],  #32
+        subs            w8,  w8,  #16
+        sub             v6.8h,   v6.8h,   v4.8h
+        sub             v7.8h,   v7.8h,   v5.8h
+        sub             v18.8h,  v18.8h,  v16.8h
+        sub             v19.8h,  v19.8h,  v17.8h
+        abs             v20.8h,  v6.8h
+        abs             v21.8h,  v7.8h
+        abs             v22.8h,  v18.8h
+        abs             v23.8h,  v19.8h
+        uqsub           v20.8h,  v0.8h,   v20.8h
+        uqsub           v21.8h,  v0.8h,   v21.8h
+        uqsub           v22.8h,  v0.8h,   v22.8h
+        uqsub           v23.8h,  v0.8h,   v23.8h
+        ushr            v20.8h,  v20.8h,  #8
+        ushr            v21.8h,  v21.8h,  #8
+        ushr            v22.8h,  v22.8h,  #8
+        ushr            v23.8h,  v23.8h,  #8
+        shl             v24.8h,  v20.8h,  #9
+        shl             v25.8h,  v21.8h,  #9
+        shl             v26.8h,  v22.8h,  #9
+        shl             v27.8h,  v23.8h,  #9
+        sqdmulh         v24.8h,  v24.8h,  v6.8h
+        sqdmulh         v25.8h,  v25.8h,  v7.8h
+        sqdmulh         v26.8h,  v26.8h,  v18.8h
+        sqdmulh         v27.8h,  v27.8h,  v19.8h
+        add             v24.8h,  v24.8h,  v4.8h
+        add             v25.8h,  v25.8h,  v5.8h
+        add             v26.8h,  v26.8h,  v16.8h
+        add             v27.8h,  v27.8h,  v17.8h
+        sqrshrun        v24.8b,  v24.8h,  #4
+        sqrshrun        v25.8b,  v25.8h,  #4
+        sqrshrun        v26.8b,  v26.8h,  #4
+        sqrshrun        v27.8b,  v27.8h,  #4
+.if \type == 444
+        uzp1            v20.16b, v20.16b, v21.16b       // Same as xtn, xtn2
+        uzp1            v21.16b, v22.16b, v23.16b       // Ditto
+        sub             v20.16b, v1.16b,  v20.16b
+        sub             v21.16b, v1.16b,  v21.16b
+        st1             {v20.16b}, [x6],  #16
+        st1             {v21.16b}, [x10], #16
+.elseif \type == 422
+        addp            v20.8h,  v20.8h,  v21.8h
+        addp            v21.8h,  v22.8h,  v23.8h
+        xtn             v20.8b,  v20.8h
+        xtn             v21.8b,  v21.8h
+        uhsub           v20.8b,  v3.8b,   v20.8b
+        uhsub           v21.8b,  v3.8b,   v21.8b
+        st1             {v20.8b},  [x6],  #8
+        st1             {v21.8b},  [x10], #8
+.elseif \type == 420
+        add             v20.8h,  v20.8h,  v22.8h
+        add             v21.8h,  v21.8h,  v23.8h
+        addp            v20.8h,  v20.8h,  v21.8h
+        sub             v20.8h,  v3.8h,   v20.8h
+        rshrn           v20.8b,  v20.8h,  #2
+        st1             {v20.8b},  [x6],  #8
+.endif
+        st1             {v24.8b,  v25.8b},  [x0],  #16
+        st1             {v26.8b,  v27.8b},  [x12], #16
+        b.gt            16b
+        subs            w5,  w5,  #2
+        add             x2,  x2,  w4,  uxtw #1
+        add             x3,  x3,  w4,  uxtw #1
+        add             x7,  x7,  w4,  uxtw #1
+        add             x9,  x9,  w4,  uxtw #1
+.if \type == 444
+        add             x6,  x6,  w4,  uxtw
+        add             x10, x10, w4,  uxtw
+.elseif \type == 422
+        add             x6,  x6,  x11, lsr #1
+        add             x10, x10, x11, lsr #1
+.endif
+        add             x0,  x0,  x1
+        add             x12, x12, x1
+        b.gt            161b
+        ret
+endfunc
+
+jumptable w_mask_\type\()_tbl
+        .word 1280b - w_mask_\type\()_tbl
+        .word 640b  - w_mask_\type\()_tbl
+        .word 320b  - w_mask_\type\()_tbl
+        .word 160b  - w_mask_\type\()_tbl
+        .word 80b   - w_mask_\type\()_tbl
+        .word 40b   - w_mask_\type\()_tbl
+endjumptable
+.endm
+
+w_mask_fn 444
+w_mask_fn 422
+w_mask_fn 420
+
+
+function blend_8bpc_neon, export=1
+        movrel          x6,  blend_tbl
+        clz             w3,  w3
+        sub             w3,  w3,  #26
+        ldrsw           x3,  [x6,  x3,  lsl #2]
+        add             x6,  x6,  x3
+        movi            v4.16b,  #64
+        add             x8,  x0,  x1
+        lsl             x1,  x1,  #1
+        br              x6
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ld1             {v2.8b},  [x5],  #8
+        ldr             d1,       [x2],  #8
+        ldr             s0,       [x0]
+        subs            w4,  w4,  #2
+        ld1             {v0.s}[1],   [x8]
+        sub             v3.8b,   v4.8b,   v2.8b
+        umull           v5.8h,   v1.8b,   v2.8b
+        umlal           v5.8h,   v0.8b,   v3.8b
+        rshrn           v6.8b,   v5.8h,   #6
+        st1             {v6.s}[0],   [x0],  x1
+        st1             {v6.s}[1],   [x8],  x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ld1             {v2.16b},  [x5],  #16
+        ld1             {v1.16b},  [x2],  #16
+        ldr             d0,        [x0]
+        ld1             {v0.d}[1], [x8]
+        sub             v3.16b,  v4.16b,  v2.16b
+        subs            w4,  w4,  #2
+        umull           v5.8h,   v1.8b,   v2.8b
+        umlal           v5.8h,   v0.8b,   v3.8b
+        umull2          v6.8h,   v1.16b,  v2.16b
+        umlal2          v6.8h,   v0.16b,  v3.16b
+        rshrn           v7.8b,   v5.8h,   #6
+        rshrn           v16.8b,  v6.8h,   #6
+        st1             {v7.8b},   [x0],  x1
+        st1             {v16.8b},  [x8],  x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ld1             {v1.16b,  v2.16b},  [x5],  #32
+        ld1             {v5.16b,  v6.16b},  [x2],  #32
+        ld1             {v0.16b},  [x0]
+        subs            w4,  w4,  #2
+        sub             v7.16b,  v4.16b,  v1.16b
+        sub             v20.16b, v4.16b,  v2.16b
+        ld1             {v3.16b},  [x8]
+        umull           v16.8h,  v5.8b,   v1.8b
+        umlal           v16.8h,  v0.8b,   v7.8b
+        umull2          v17.8h,  v5.16b,  v1.16b
+        umlal2          v17.8h,  v0.16b,  v7.16b
+        umull           v21.8h,  v6.8b,   v2.8b
+        umlal           v21.8h,  v3.8b,   v20.8b
+        umull2          v22.8h,  v6.16b,  v2.16b
+        umlal2          v22.8h,  v3.16b,  v20.16b
+        rshrn           v18.8b,  v16.8h,  #6
+        rshrn2          v18.16b, v17.8h,  #6
+        rshrn           v19.8b,  v21.8h,  #6
+        rshrn2          v19.16b, v22.8h,  #6
+        st1             {v18.16b}, [x0],  x1
+        st1             {v19.16b}, [x8],  x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ld1             {v0.16b,  v1.16b,  v2.16b,  v3.16b},  [x5],  #64
+        ld1             {v16.16b, v17.16b, v18.16b, v19.16b}, [x2],  #64
+        ld1             {v20.16b, v21.16b}, [x0]
+        subs            w4,  w4,  #2
+        ld1             {v22.16b, v23.16b}, [x8]
+        sub             v5.16b,  v4.16b,  v0.16b
+        sub             v6.16b,  v4.16b,  v1.16b
+        sub             v30.16b, v4.16b,  v2.16b
+        sub             v31.16b, v4.16b,  v3.16b
+        umull           v24.8h,  v16.8b,  v0.8b
+        umlal           v24.8h,  v20.8b,  v5.8b
+        umull2          v26.8h,  v16.16b, v0.16b
+        umlal2          v26.8h,  v20.16b, v5.16b
+        umull           v28.8h,  v17.8b,  v1.8b
+        umlal           v28.8h,  v21.8b,  v6.8b
+        umull2          v7.8h,   v17.16b, v1.16b
+        umlal2          v7.8h,   v21.16b, v6.16b
+        umull           v27.8h,  v18.8b,  v2.8b
+        umlal           v27.8h,  v22.8b,  v30.8b
+        umull2          v1.8h,   v18.16b, v2.16b
+        umlal2          v1.8h,   v22.16b, v30.16b
+        umull           v29.8h,  v19.8b,  v3.8b
+        umlal           v29.8h,  v23.8b,  v31.8b
+        umull2          v21.8h,  v19.16b, v3.16b
+        umlal2          v21.8h,  v23.16b, v31.16b
+        rshrn           v24.8b,  v24.8h,  #6
+        rshrn2          v24.16b, v26.8h,  #6
+        rshrn           v25.8b,  v28.8h,  #6
+        rshrn2          v25.16b, v7.8h,   #6
+        rshrn           v27.8b,  v27.8h,  #6
+        rshrn2          v27.16b, v1.8h,   #6
+        rshrn           v28.8b,  v29.8h,  #6
+        rshrn2          v28.16b, v21.8h,  #6
+        st1             {v24.16b, v25.16b}, [x0],  x1
+        st1             {v27.16b, v28.16b}, [x8],  x1
+        b.gt            32b
+        ret
+endfunc
+
+jumptable blend_tbl
+        .word 320b - blend_tbl
+        .word 160b - blend_tbl
+        .word 80b  - blend_tbl
+        .word 40b  - blend_tbl
+endjumptable
+
+function blend_h_8bpc_neon, export=1
+        movrel          x6,  blend_h_tbl
+        movrel          x5,  X(obmc_masks)
+        add             x5,  x5,  w4,  uxtw
+        sub             w4,  w4,  w4,  lsr #2
+        clz             w7,  w3
+        movi            v4.16b,  #64
+        add             x8,  x0,  x1
+        lsl             x1,  x1,  #1
+        sub             w7,  w7,  #24
+        ldrsw           x7,  [x6,  x7,  lsl #2]
+        add             x6,  x6,  x7
+        br              x6
+20:
+        AARCH64_VALID_JUMP_TARGET
+2:
+        ldr             h0,  [x5],  #2
+        ldr             s1,  [x2],  #4
+        subs            w4,  w4,  #2
+        ldr             h2,  [x0]
+        zip1            v0.8b,   v0.8b,   v0.8b
+        sub             v3.8b,   v4.8b,   v0.8b
+        ld1             {v2.h}[1],   [x8]
+        umull           v5.8h,   v1.8b,   v0.8b
+        umlal           v5.8h,   v2.8b,   v3.8b
+        rshrn           v5.8b,   v5.8h,   #6
+        st1             {v5.h}[0],   [x0],  x1
+        st1             {v5.h}[1],   [x8],  x1
+        b.gt            2b
+        ret
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ld2r            {v0.8b,   v1.8b},   [x5],  #2
+        ld1             {v2.8b},   [x2],  #8
+        subs            w4,  w4,  #2
+        ext             v0.8b,   v0.8b,   v1.8b,   #4
+        ldr             s3,          [x0]
+        sub             v5.8b,   v4.8b,   v0.8b
+        ld1             {v3.s}[1],   [x8]
+        umull           v6.8h,   v2.8b,   v0.8b
+        umlal           v6.8h,   v3.8b,   v5.8b
+        rshrn           v6.8b,   v6.8h,   #6
+        st1             {v6.s}[0],   [x0],  x1
+        st1             {v6.s}[1],   [x8],  x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ld2r            {v0.16b,  v1.16b},  [x5],  #2
+        ld1             {v2.16b},  [x2],  #16
+        ldr             d3,        [x0]
+        ext             v0.16b,  v0.16b,  v1.16b,  #8
+        sub             v5.16b,  v4.16b,  v0.16b
+        ld1             {v3.d}[1], [x8]
+        subs            w4,  w4,  #2
+        umull           v6.8h,   v0.8b,   v2.8b
+        umlal           v6.8h,   v3.8b,   v5.8b
+        umull2          v7.8h,   v0.16b,  v2.16b
+        umlal2          v7.8h,   v3.16b,  v5.16b
+        rshrn           v16.8b,  v6.8h,   #6
+        rshrn           v17.8b,  v7.8h,   #6
+        st1             {v16.8b},  [x0],  x1
+        st1             {v17.8b},  [x8],  x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ld2r            {v0.16b,  v1.16b},  [x5],  #2
+        ld1             {v2.16b,  v3.16b},  [x2],  #32
+        ld1             {v5.16b},  [x0]
+        sub             v7.16b,  v4.16b,  v0.16b
+        sub             v16.16b, v4.16b,  v1.16b
+        ld1             {v6.16b},  [x8]
+        subs            w4,  w4,  #2
+        umull           v17.8h,  v0.8b,   v2.8b
+        umlal           v17.8h,  v5.8b,   v7.8b
+        umull2          v18.8h,  v0.16b,  v2.16b
+        umlal2          v18.8h,  v5.16b,  v7.16b
+        umull           v19.8h,  v1.8b,   v3.8b
+        umlal           v19.8h,  v6.8b,   v16.8b
+        umull2          v20.8h,  v1.16b,  v3.16b
+        umlal2          v20.8h,  v6.16b,  v16.16b
+        rshrn           v21.8b,  v17.8h,  #6
+        rshrn2          v21.16b, v18.8h,  #6
+        rshrn           v22.8b,  v19.8h,  #6
+        rshrn2          v22.16b, v20.8h,  #6
+        st1             {v21.16b}, [x0],  x1
+        st1             {v22.16b}, [x8],  x1
+        b.gt            16b
+        ret
+1280:
+640:
+320:
+        AARCH64_VALID_JUMP_TARGET
+        sub             x1,  x1,  w3,  uxtw
+        add             x7,  x2,  w3,  uxtw
+321:
+        ld2r            {v0.16b,  v1.16b},  [x5],  #2
+        mov             w6,  w3
+        sub             v20.16b, v4.16b,  v0.16b
+        sub             v21.16b, v4.16b,  v1.16b
+32:
+        ld1             {v16.16b, v17.16b}, [x2],  #32
+        ld1             {v2.16b,  v3.16b},  [x0]
+        subs            w6,  w6,  #32
+        umull           v23.8h,  v0.8b,   v16.8b
+        umlal           v23.8h,  v2.8b,   v20.8b
+        ld1             {v18.16b, v19.16b}, [x7],  #32
+        umull2          v27.8h,  v0.16b,  v16.16b
+        umlal2          v27.8h,  v2.16b,  v20.16b
+        ld1             {v6.16b,  v7.16b},  [x8]
+        umull           v24.8h,  v0.8b,   v17.8b
+        umlal           v24.8h,  v3.8b,   v20.8b
+        umull2          v28.8h,  v0.16b,  v17.16b
+        umlal2          v28.8h,  v3.16b,  v20.16b
+        umull           v25.8h,  v1.8b,   v18.8b
+        umlal           v25.8h,  v6.8b,   v21.8b
+        umull2          v5.8h,   v1.16b,  v18.16b
+        umlal2          v5.8h,   v6.16b,  v21.16b
+        rshrn           v29.8b,  v23.8h,  #6
+        rshrn2          v29.16b, v27.8h,  #6
+        umull           v26.8h,  v1.8b,   v19.8b
+        umlal           v26.8h,  v7.8b,   v21.8b
+        umull2          v31.8h,  v1.16b,  v19.16b
+        umlal2          v31.8h,  v7.16b,  v21.16b
+        rshrn           v30.8b,  v24.8h,  #6
+        rshrn2          v30.16b, v28.8h,  #6
+        rshrn           v23.8b,  v25.8h,  #6
+        rshrn2          v23.16b, v5.8h,   #6
+        rshrn           v24.8b,  v26.8h,  #6
+        st1             {v29.16b, v30.16b}, [x0],  #32
+        rshrn2          v24.16b, v31.8h,  #6
+        st1             {v23.16b, v24.16b}, [x8],  #32
+        b.gt            32b
+        subs            w4,  w4,  #2
+        add             x0,  x0,  x1
+        add             x8,  x8,  x1
+        add             x2,  x2,  w3,  uxtw
+        add             x7,  x7,  w3,  uxtw
+        b.gt            321b
+        ret
+endfunc
+
+jumptable blend_h_tbl
+        .word 1280b - blend_h_tbl
+        .word 640b  - blend_h_tbl
+        .word 320b  - blend_h_tbl
+        .word 160b  - blend_h_tbl
+        .word 80b   - blend_h_tbl
+        .word 40b   - blend_h_tbl
+        .word 20b   - blend_h_tbl
+endjumptable
+
+function blend_v_8bpc_neon, export=1
+        movrel          x6,  blend_v_tbl
+        movrel          x5,  X(obmc_masks)
+        add             x5,  x5,  w3,  uxtw
+        clz             w3,  w3
+        movi            v4.16b,  #64
+        add             x8,  x0,  x1
+        lsl             x1,  x1,  #1
+        sub             w3,  w3,  #26
+        ldrsw           x3,  [x6,  x3,  lsl #2]
+        add             x6,  x6,  x3
+        br              x6
+20:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v0.8b},   [x5]
+        sub             v1.8b,   v4.8b,   v0.8b
+2:
+        ldr             h2,          [x2],  #2
+        ldr             b3,          [x0]
+        subs            w4,  w4,  #2
+        ld1             {v2.b}[1],   [x2]
+        ld1             {v3.b}[1],   [x8]
+        umull           v5.8h,   v2.8b,   v0.8b
+        umlal           v5.8h,   v3.8b,   v1.8b
+        rshrn           v5.8b,   v5.8h,   #6
+        add             x2,  x2,  #2
+        st1             {v5.b}[0],   [x0],  x1
+        st1             {v5.b}[1],   [x8],  x1
+        b.gt            2b
+        ret
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v0.2s},   [x5]
+        sub             x1,  x1,  #2
+        sub             v1.8b,   v4.8b,   v0.8b
+4:
+        ld1             {v2.8b},   [x2],  #8
+        ldr             s3,          [x0]
+        ld1             {v3.s}[1],   [x8]
+        subs            w4,  w4,  #2
+        umull           v5.8h,   v2.8b,   v0.8b
+        umlal           v5.8h,   v3.8b,   v1.8b
+        rshrn           v5.8b,   v5.8h,   #6
+        str             h5,          [x0],  #2
+        st1             {v5.h}[2],   [x8],  #2
+        st1             {v5.b}[2],   [x0],  x1
+        st1             {v5.b}[6],   [x8],  x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v0.2d},   [x5]
+        sub             x1,  x1,  #4
+        sub             v1.16b,  v4.16b,  v0.16b
+        zip2            v16.2d,  v1.2d,   v1.2d
+8:
+        ld1             {v2.16b},  [x2],  #16
+        ldr             d3,          [x0]
+        ldr             d4,          [x8]
+        subs            w4,  w4,  #2
+        umull           v5.8h,  v0.8b,  v2.8b
+        umlal           v5.8h,  v3.8b,  v1.8b
+        umull2          v6.8h,  v0.16b, v2.16b
+        umlal           v6.8h,  v4.8b,  v16.8b
+        rshrn           v7.8b,  v5.8h,  #6
+        rshrn           v17.8b, v6.8h,  #6
+        str             s7,          [x0],  #4
+        str             s17,         [x8],  #4
+        st1             {v7.h}[2],   [x0],  x1
+        st1             {v17.h}[2],  [x8],  x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b},  [x5]
+        sub             x1,  x1,  #8
+        sub             v2.16b,  v4.16b,  v0.16b
+16:
+        ld1             {v5.16b,  v6.16b},  [x2],  #32
+        ld1             {v7.16b},  [x0]
+        subs            w4,  w4,  #2
+        ld1             {v16.16b}, [x8]
+        umull           v17.8h,  v5.8b,   v0.8b
+        umlal           v17.8h,  v7.8b,   v2.8b
+        umull2          v18.8h,  v5.16b,  v0.16b
+        umlal2          v18.8h,  v7.16b,  v2.16b
+        umull           v20.8h,  v6.8b,   v0.8b
+        umlal           v20.8h,  v16.8b,  v2.8b
+        umull2          v21.8h,  v6.16b,  v0.16b
+        umlal2          v21.8h,  v16.16b, v2.16b
+        rshrn           v19.8b,  v17.8h,  #6
+        rshrn2          v19.16b, v18.8h,  #6
+        rshrn           v22.8b,  v20.8h,  #6
+        rshrn2          v22.16b, v21.8h,  #6
+        st1             {v19.8b},  [x0],  #8
+        st1             {v22.8b},  [x8],  #8
+        st1             {v19.s}[2],  [x0],  x1
+        st1             {v22.s}[2],  [x8],  x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.16b,  v1.16b},  [x5]
+        sub             x1,  x1,  #16
+        sub             v2.16b,  v4.16b,  v0.16b
+        sub             v3.8b,   v4.8b,   v1.8b
+32:
+        ld1             {v16.16b, v17.16b, v18.16b, v19.16b}, [x2],  #64
+        ld1             {v5.16b,  v6.16b},  [x0]
+        subs            w4,  w4,  #2
+        ld1             {v20.16b, v21.16b}, [x8]
+        umull           v22.8h,  v16.8b,  v0.8b
+        umlal           v22.8h,  v5.8b,   v2.8b
+        umull2          v23.8h,  v16.16b, v0.16b
+        umlal2          v23.8h,  v5.16b,  v2.16b
+        umull           v28.8h,  v17.8b,  v1.8b
+        umlal           v28.8h,  v6.8b,   v3.8b
+        umull           v30.8h,  v18.8b,  v0.8b
+        umlal           v30.8h,  v20.8b,  v2.8b
+        umull2          v31.8h,  v18.16b, v0.16b
+        umlal2          v31.8h,  v20.16b, v2.16b
+        umull           v25.8h,  v19.8b,  v1.8b
+        umlal           v25.8h,  v21.8b,  v3.8b
+        rshrn           v24.8b,  v22.8h,  #6
+        rshrn2          v24.16b, v23.8h,  #6
+        rshrn           v28.8b,  v28.8h,  #6
+        rshrn           v30.8b,  v30.8h,  #6
+        rshrn2          v30.16b, v31.8h,  #6
+        rshrn           v27.8b,  v25.8h,  #6
+        st1             {v24.16b}, [x0],  #16
+        st1             {v30.16b}, [x8],  #16
+        st1             {v28.8b},  [x0],  x1
+        st1             {v27.8b},  [x8],  x1
+        b.gt            32b
+        ret
+endfunc
+
+jumptable blend_v_tbl
+        .word 320b - blend_v_tbl
+        .word 160b - blend_v_tbl
+        .word 80b  - blend_v_tbl
+        .word 40b  - blend_v_tbl
+        .word 20b  - blend_v_tbl
+endjumptable
+
+
+// This has got the same signature as the put_8tap functions,
+// and assumes that x8 is set to (clz(w)-24).
+function put_neon, export=1
+        movrel          x9,  put_tbl
+        ldrsw           x8,  [x9, x8, lsl #2]
+        add             x9,  x9,  x8
+        br              x9
+
+20:
+        AARCH64_VALID_JUMP_TARGET
+2:
+        ldrh            w9, [x2]
+        ldrh            w10, [x2, x3]
+        add             x2, x2, x3, lsl #1
+        subs            w5, w5, #2
+        strh            w9, [x0]
+        strh            w10, [x0, x1]
+        add             x0, x0, x1, lsl #1
+        b.gt            2b
+        ret
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ldr             w9, [x2]
+        ldr             w10, [x2, x3]
+        add             x2, x2, x3, lsl #1
+        subs            w5, w5, #2
+        str             w9, [x0]
+        str             w10, [x0, x1]
+        add             x0, x0, x1, lsl #1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ldr             x9, [x2]
+        ldr             x10, [x2, x3]
+        add             x2, x2, x3, lsl #1
+        subs            w5, w5, #2
+        str             x9, [x0]
+        str             x10, [x0, x1]
+        add             x0, x0, x1, lsl #1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ldr             q0, [x2]
+        ldr             q1, [x2, x3]
+        add             x2, x2, x3, lsl #1
+        subs            w5, w5, #2
+        str             q0, [x0]
+        str             q1, [x0, x1]
+        add             x0, x0, x1, lsl #1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ldp             q0, q1, [x2]
+        add             x2, x2, x3
+        stp             q0, q1, [x0]
+        add             x0, x0, x1
+        ldp             q2, q3, [x2]
+        add             x2, x2, x3
+        stp             q2, q3, [x0]
+        subs            w5, w5, #2
+        add             x0, x0, x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+64:
+        ldp             q0, q1, [x2]
+        stp             q0, q1, [x0]
+        ldp             q2, q3, [x2, #32]
+        add             x2, x2, x3
+        stp             q2, q3, [x0, #32]
+        subs            w5, w5, #1
+        add             x0, x0, x1
+        b.gt            64b
+        ret
+1280:
+        AARCH64_VALID_JUMP_TARGET
+128:
+        ldp             q0, q1, [x2]
+        stp             q0, q1, [x0]
+        ldp             q2, q3, [x2, #32]
+        stp             q2, q3, [x0, #32]
+        ldp             q4, q5, [x2, #64]
+        stp             q4, q5, [x0, #64]
+        ldp             q6, q7, [x2, #96]
+        add             x2, x2, x3
+        stp             q6, q7, [x0, #96]
+        subs            w5, w5, #1
+        add             x0, x0, x1
+        b.gt            128b
+        ret
+endfunc
+
+jumptable put_tbl
+        .word 1280b - put_tbl
+        .word 640b  - put_tbl
+        .word 320b  - put_tbl
+        .word 160b  - put_tbl
+        .word 80b   - put_tbl
+        .word 40b   - put_tbl
+        .word 20b   - put_tbl
+endjumptable
+
+
+// This has got the same signature as the prep_8tap functions,
+// and assumes that x8 is set to (clz(w)-24), and x7 to w*2.
+function prep_neon, export=1
+        movrel          x9,  prep_tbl
+        ldrsw           x8,  [x9, x8, lsl #2]
+        movi            v24.16b, #16
+        add             x9,  x9,  x8
+        br              x9
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ldr             s0, [x1]
+        ldr             s2, [x1, x2]
+        add             x1, x1, x2, lsl #1
+        ldr             s1, [x1]
+        ldr             s3, [x1, x2]
+        add             x1, x1, x2, lsl #1
+        mov             v0.s[1], v2.s[0]
+        mov             v1.s[1], v3.s[0]
+        ushll           v0.8h, v0.8b, #4
+        ushll           v1.8h, v1.8b, #4
+        subs            w4, w4, #4
+        stp             q0, q1, [x0], #32
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ldr             d0, [x1]
+        ldr             d1, [x1, x2]
+        add             x1, x1, x2, lsl #1
+        ldr             d2, [x1]
+        ldr             d3, [x1, x2]
+        add             x1, x1, x2, lsl #1
+        ushll           v0.8h, v0.8b, #4
+        ushll           v1.8h, v1.8b, #4
+        umull           v2.8h, v2.8b, v24.8b
+        umull           v3.8h, v3.8b, v24.8b
+        subs            w4, w4, #4
+        stp             q0, q1, [x0]
+        stp             q2, q3, [x0, #32]
+        add             x0, x0, #64
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ldr             q1, [x1]
+        ldr             q3, [x1, x2]
+        add             x1, x1, x2, lsl #1
+        ushll           v0.8h, v1.8b, #4
+        ushll2          v1.8h, v1.16b, #4
+        ldr             q5, [x1]
+        ldr             q7, [x1, x2]
+        add             x1, x1, x2, lsl #1
+        umull           v2.8h, v3.8b, v24.8b
+        umull2          v3.8h, v3.16b, v24.16b
+        ushll           v4.8h, v5.8b, #4
+        ushll2          v5.8h, v5.16b, #4
+        umull           v6.8h, v7.8b, v24.8b
+        umull2          v7.8h, v7.16b, v24.16b
+        subs            w4, w4, #4
+        stp             q0, q1, [x0]
+        stp             q2, q3, [x0, #32]
+        stp             q4, q5, [x0, #64]
+        stp             q6, q7, [x0, #96]
+        add             x0, x0, #128
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ldp             q4, q5, [x1]
+        add             x1, x1, x2
+        ldp             q6, q7, [x1]
+        add             x1, x1, x2
+        ushll           v0.8h, v4.8b, #4
+        ushll2          v1.8h, v4.16b, #4
+        umull           v2.8h, v5.8b, v24.8b
+        umull2          v3.8h, v5.16b, v24.16b
+        ushll           v4.8h, v6.8b, #4
+        ushll2          v5.8h, v6.16b, #4
+        umull           v6.8h, v7.8b, v24.8b
+        umull2          v7.8h, v7.16b, v24.16b
+        subs            w4, w4, #2
+        stp             q0, q1, [x0]
+        stp             q2, q3, [x0, #32]
+        stp             q4, q5, [x0, #64]
+        stp             q6, q7, [x0, #96]
+        add             x0, x0, #128
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+64:
+        ldp             q4, q5, [x1]
+        ldp             q6, q7, [x1, #32]
+        add             x1, x1, x2
+        ushll           v0.8h, v4.8b, #4
+        ushll2          v1.8h, v4.16b, #4
+        umull           v2.8h, v5.8b, v24.8b
+        umull2          v3.8h, v5.16b, v24.16b
+        ushll           v4.8h, v6.8b, #4
+        ushll2          v5.8h, v6.16b, #4
+        umull           v6.8h, v7.8b, v24.8b
+        umull2          v7.8h, v7.16b, v24.16b
+        subs            w4, w4, #1
+        stp             q0, q1, [x0]
+        stp             q2, q3, [x0, #32]
+        stp             q4, q5, [x0, #64]
+        stp             q6, q7, [x0, #96]
+        add             x0, x0, #128
+        b.gt            64b
+        ret
+1280:
+        AARCH64_VALID_JUMP_TARGET
+128:
+        ldp             q28, q29, [x1]
+        ldp             q30, q31, [x1, #32]
+        ushll           v16.8h, v28.8b, #4
+        ushll2          v17.8h, v28.16b, #4
+        umull           v18.8h, v29.8b, v24.8b
+        umull2          v19.8h, v29.16b, v24.16b
+        ushll           v20.8h, v30.8b, #4
+        ushll2          v21.8h, v30.16b, #4
+        umull           v22.8h, v31.8b, v24.8b
+        umull2          v23.8h, v31.16b, v24.16b
+        ldp             q28, q29, [x1, #64]
+        ldp             q30, q31, [x1, #96]
+        add             x1, x1, x2
+        stp             q16, q17, [x0]
+        stp             q18, q19, [x0, #32]
+        stp             q20, q21, [x0, #64]
+        stp             q22, q23, [x0, #96]
+        ushll           v16.8h, v28.8b, #4
+        ushll2          v17.8h, v28.16b, #4
+        umull           v18.8h, v29.8b, v24.8b
+        umull2          v19.8h, v29.16b, v24.16b
+        ushll           v20.8h, v30.8b, #4
+        ushll2          v21.8h, v30.16b, #4
+        umull           v22.8h, v31.8b, v24.8b
+        umull2          v23.8h, v31.16b, v24.16b
+        subs            w4, w4, #1
+        stp             q16, q17, [x0, #128]
+        stp             q18, q19, [x0, #160]
+        stp             q20, q21, [x0, #192]
+        stp             q22, q23, [x0, #224]
+        add             x0, x0, #256
+        b.gt            128b
+        ret
+endfunc
+
+jumptable prep_tbl
+        .word 1280b - prep_tbl
+        .word 640b  - prep_tbl
+        .word 320b  - prep_tbl
+        .word 160b  - prep_tbl
+        .word 80b   - prep_tbl
+        .word 40b   - prep_tbl
+endjumptable
+
+
+.macro load_slice s0, s1, strd, wd, d0, d1, d2, d3, d4, d5, d6
+        ld1             {\d0\wd}[0], [\s0], \strd
+        ld1             {\d1\wd}[0], [\s1], \strd
+.ifnb \d2
+        ld1             {\d2\wd}[0], [\s0], \strd
+        ld1             {\d3\wd}[0], [\s1], \strd
+.endif
+.ifnb \d4
+        ld1             {\d4\wd}[0], [\s0], \strd
+.endif
+.ifnb \d5
+        ld1             {\d5\wd}[0], [\s1], \strd
+.endif
+.ifnb \d6
+        ld1             {\d6\wd}[0], [\s0], \strd
+.endif
+.endm
+.macro load_reg s0, s1, strd, wd, d0, d1, d2, d3, d4, d5, d6
+        ld1             {\d0\wd}, [\s0], \strd
+        ld1             {\d1\wd}, [\s1], \strd
+.ifnb \d2
+        ld1             {\d2\wd}, [\s0], \strd
+        ld1             {\d3\wd}, [\s1], \strd
+.endif
+.ifnb \d4
+        ld1             {\d4\wd}, [\s0], \strd
+.endif
+.ifnb \d5
+        ld1             {\d5\wd}, [\s1], \strd
+.endif
+.ifnb \d6
+        ld1             {\d6\wd}, [\s0], \strd
+.endif
+.endm
+.macro load_h s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_slice      \s0, \s1, \strd, .h, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro load_s s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_slice      \s0, \s1, \strd, .s, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro load_8b s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_reg        \s0, \s1, \strd, .8b, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro load_16b s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_reg        \s0, \s1, \strd, .16b, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro interleave_1 wd, r0, r1, r2, r3, r4
+        trn1            \r0\wd, \r0\wd, \r1\wd
+        trn1            \r1\wd, \r1\wd, \r2\wd
+.ifnb \r3
+        trn1            \r2\wd, \r2\wd, \r3\wd
+        trn1            \r3\wd, \r3\wd, \r4\wd
+.endif
+.endm
+.macro interleave_1_h r0, r1, r2, r3, r4
+        interleave_1    .4h, \r0, \r1, \r2, \r3, \r4
+.endm
+.macro interleave_1_s r0, r1, r2, r3, r4
+        interleave_1    .2s, \r0, \r1, \r2, \r3, \r4
+.endm
+.macro interleave_2 wd, r0, r1, r2, r3, r4, r5
+        trn1            \r0\wd,  \r0\wd, \r2\wd
+        trn1            \r1\wd,  \r1\wd, \r3\wd
+        trn1            \r2\wd,  \r2\wd, \r4\wd
+        trn1            \r3\wd,  \r3\wd, \r5\wd
+.endm
+.macro interleave_2_s r0, r1, r2, r3, r4, r5
+        interleave_2    .2s, \r0, \r1, \r2, \r3, \r4, \r5
+.endm
+.macro uxtl_b r0, r1, r2, r3, r4, r5, r6
+        uxtl            \r0\().8h, \r0\().8b
+        uxtl            \r1\().8h, \r1\().8b
+.ifnb \r2
+        uxtl            \r2\().8h, \r2\().8b
+        uxtl            \r3\().8h, \r3\().8b
+.endif
+.ifnb \r4
+        uxtl            \r4\().8h, \r4\().8b
+.endif
+.ifnb \r5
+        uxtl            \r5\().8h, \r5\().8b
+.endif
+.ifnb \r6
+        uxtl            \r6\().8h, \r6\().8b
+.endif
+.endm
+.macro mul_mla_4tap d, s0, s1, s2, s3, wd
+        mul             \d\wd,  \s0\wd,  v0.h[0]
+        mla             \d\wd,  \s1\wd,  v0.h[1]
+        mla             \d\wd,  \s2\wd,  v0.h[2]
+        mla             \d\wd,  \s3\wd,  v0.h[3]
+.endm
+// Interleaving the mul/mla chains actually hurts performance
+// significantly on Cortex A53, thus keeping mul/mla tightly
+// chained like this.
+.macro mul_mla_6tap_0_4h d0, s0, s1, s2, s3, s4, s5, s6, s7
+        mul             \d0\().4h, \s1\().4h, v0.h[1]
+        mla             \d0\().4h, \s2\().4h, v0.h[2]
+        mla             \d0\().4h, \s3\().4h, v0.h[3]
+        mla             \d0\().4h, \s4\().4h, v0.h[4]
+        mla             \d0\().4h, \s5\().4h, v0.h[5]
+        mla             \d0\().4h, \s6\().4h, v0.h[6]
+.endm
+.macro mul_mla_6tap_0 d0, s0, s1, s2, s3, s4, s5, s6, s7
+        mul             \d0\().8h, \s1\().8h, v0.h[1]
+        mla             \d0\().8h, \s2\().8h, v0.h[2]
+        mla             \d0\().8h, \s3\().8h, v0.h[3]
+        mla             \d0\().8h, \s4\().8h, v0.h[4]
+        mla             \d0\().8h, \s5\().8h, v0.h[5]
+        mla             \d0\().8h, \s6\().8h, v0.h[6]
+.endm
+.macro mul_mla_6tap_1 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8
+        mul             \d0\().8h, \s1\().8h, v0.h[1]
+        mla             \d0\().8h, \s2\().8h, v0.h[2]
+        mla             \d0\().8h, \s3\().8h, v0.h[3]
+        mla             \d0\().8h, \s4\().8h, v0.h[4]
+        mla             \d0\().8h, \s5\().8h, v0.h[5]
+        mla             \d0\().8h, \s6\().8h, v0.h[6]
+        mul             \d1\().8h, \s2\().8h, v0.h[1]
+        mla             \d1\().8h, \s3\().8h, v0.h[2]
+        mla             \d1\().8h, \s4\().8h, v0.h[3]
+        mla             \d1\().8h, \s5\().8h, v0.h[4]
+        mla             \d1\().8h, \s6\().8h, v0.h[5]
+        mla             \d1\().8h, \s7\().8h, v0.h[6]
+.endm
+.macro mul_mla_6tap_2 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9
+        mul             \d0\().8h, \s1\().8h, v0.h[1]
+        mla             \d0\().8h, \s2\().8h, v0.h[2]
+        mla             \d0\().8h, \s3\().8h, v0.h[3]
+        mla             \d0\().8h, \s4\().8h, v0.h[4]
+        mla             \d0\().8h, \s5\().8h, v0.h[5]
+        mla             \d0\().8h, \s6\().8h, v0.h[6]
+        mul             \d1\().8h, \s3\().8h, v0.h[1]
+        mla             \d1\().8h, \s4\().8h, v0.h[2]
+        mla             \d1\().8h, \s5\().8h, v0.h[3]
+        mla             \d1\().8h, \s6\().8h, v0.h[4]
+        mla             \d1\().8h, \s7\().8h, v0.h[5]
+        mla             \d1\().8h, \s8\().8h, v0.h[6]
+.endm
+.macro mul_mla_8tap_0_4h d0, s0, s1, s2, s3, s4, s5, s6, s7
+        mul             \d0\().4h, \s0\().4h, v0.h[0]
+        mla             \d0\().4h, \s1\().4h, v0.h[1]
+        mla             \d0\().4h, \s2\().4h, v0.h[2]
+        mla             \d0\().4h, \s3\().4h, v0.h[3]
+        mla             \d0\().4h, \s4\().4h, v0.h[4]
+        mla             \d0\().4h, \s5\().4h, v0.h[5]
+        mla             \d0\().4h, \s6\().4h, v0.h[6]
+        mla             \d0\().4h, \s7\().4h, v0.h[7]
+.endm
+.macro mul_mla_8tap_0 d0, s0, s1, s2, s3, s4, s5, s6, s7
+        mul             \d0\().8h, \s0\().8h, v0.h[0]
+        mla             \d0\().8h, \s1\().8h, v0.h[1]
+        mla             \d0\().8h, \s2\().8h, v0.h[2]
+        mla             \d0\().8h, \s3\().8h, v0.h[3]
+        mla             \d0\().8h, \s4\().8h, v0.h[4]
+        mla             \d0\().8h, \s5\().8h, v0.h[5]
+        mla             \d0\().8h, \s6\().8h, v0.h[6]
+        mla             \d0\().8h, \s7\().8h, v0.h[7]
+.endm
+.macro mul_mla_8tap_1 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8
+        mul             \d0\().8h, \s0\().8h, v0.h[0]
+        mla             \d0\().8h, \s1\().8h, v0.h[1]
+        mla             \d0\().8h, \s2\().8h, v0.h[2]
+        mla             \d0\().8h, \s3\().8h, v0.h[3]
+        mla             \d0\().8h, \s4\().8h, v0.h[4]
+        mla             \d0\().8h, \s5\().8h, v0.h[5]
+        mla             \d0\().8h, \s6\().8h, v0.h[6]
+        mla             \d0\().8h, \s7\().8h, v0.h[7]
+        mul             \d1\().8h, \s1\().8h, v0.h[0]
+        mla             \d1\().8h, \s2\().8h, v0.h[1]
+        mla             \d1\().8h, \s3\().8h, v0.h[2]
+        mla             \d1\().8h, \s4\().8h, v0.h[3]
+        mla             \d1\().8h, \s5\().8h, v0.h[4]
+        mla             \d1\().8h, \s6\().8h, v0.h[5]
+        mla             \d1\().8h, \s7\().8h, v0.h[6]
+        mla             \d1\().8h, \s8\().8h, v0.h[7]
+.endm
+.macro mul_mla_8tap_2 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9
+        mul             \d0\().8h, \s0\().8h, v0.h[0]
+        mla             \d0\().8h, \s1\().8h, v0.h[1]
+        mla             \d0\().8h, \s2\().8h, v0.h[2]
+        mla             \d0\().8h, \s3\().8h, v0.h[3]
+        mla             \d0\().8h, \s4\().8h, v0.h[4]
+        mla             \d0\().8h, \s5\().8h, v0.h[5]
+        mla             \d0\().8h, \s6\().8h, v0.h[6]
+        mla             \d0\().8h, \s7\().8h, v0.h[7]
+        mul             \d1\().8h, \s2\().8h, v0.h[0]
+        mla             \d1\().8h, \s3\().8h, v0.h[1]
+        mla             \d1\().8h, \s4\().8h, v0.h[2]
+        mla             \d1\().8h, \s5\().8h, v0.h[3]
+        mla             \d1\().8h, \s6\().8h, v0.h[4]
+        mla             \d1\().8h, \s7\().8h, v0.h[5]
+        mla             \d1\().8h, \s8\().8h, v0.h[6]
+        mla             \d1\().8h, \s9\().8h, v0.h[7]
+.endm
+.macro sqrshrun_b shift, r0, r1, r2, r3
+        sqrshrun        \r0\().8b, \r0\().8h,  #\shift
+.ifnb \r1
+        sqrshrun        \r1\().8b, \r1\().8h,  #\shift
+.endif
+.ifnb \r2
+        sqrshrun        \r2\().8b, \r2\().8h,  #\shift
+        sqrshrun        \r3\().8b, \r3\().8h,  #\shift
+.endif
+.endm
+.macro srshr_h shift, r0, r1, r2, r3
+        srshr           \r0\().8h, \r0\().8h,  #\shift
+.ifnb \r1
+        srshr           \r1\().8h, \r1\().8h,  #\shift
+.endif
+.ifnb \r2
+        srshr           \r2\().8h, \r2\().8h,  #\shift
+        srshr           \r3\().8h, \r3\().8h,  #\shift
+.endif
+.endm
+.macro st_h strd, reg, lanes
+        st1             {\reg\().h}[0], [x0], \strd
+        st1             {\reg\().h}[1], [x8], \strd
+.if \lanes > 2
+        st1             {\reg\().h}[2], [x0], \strd
+        st1             {\reg\().h}[3], [x8], \strd
+.endif
+.endm
+.macro st_s strd, r0, r1
+        st1             {\r0\().s}[0], [x0], \strd
+        st1             {\r0\().s}[1], [x8], \strd
+.ifnb \r1
+        st1             {\r1\().s}[0], [x0], \strd
+        st1             {\r1\().s}[1], [x8], \strd
+.endif
+.endm
+.macro st_d strd, r0, r1
+        st1             {\r0\().8b},   [x0], \strd
+        st1             {\r0\().d}[1], [x8], \strd
+.ifnb \r1
+        st1             {\r1\().8b},   [x0], \strd
+        st1             {\r1\().d}[1], [x8], \strd
+.endif
+.endm
+.macro shift_store_4 type, strd, r0, r1
+.ifc \type, put
+        sqrshrun_b      6,     \r0, \r1
+        st_s            \strd, \r0, \r1
+.else
+        srshr_h         2,     \r0, \r1
+        st_d            \strd, \r0, \r1
+.endif
+.endm
+.macro st_reg strd, wd, r0, r1, r2, r3, r4, r5, r6, r7
+        st1             {\r0\wd}, [x0], \strd
+        st1             {\r1\wd}, [x8], \strd
+.ifnb \r2
+        st1             {\r2\wd}, [x0], \strd
+        st1             {\r3\wd}, [x8], \strd
+.endif
+.ifnb \r4
+        st1             {\r4\wd}, [x0], \strd
+        st1             {\r5\wd}, [x8], \strd
+        st1             {\r6\wd}, [x0], \strd
+        st1             {\r7\wd}, [x8], \strd
+.endif
+.endm
+.macro st_8b strd, r0, r1, r2, r3, r4, r5, r6, r7
+        st_reg          \strd, .8b,  \r0, \r1, \r2, \r3, \r4, \r5, \r6, \r7
+.endm
+.macro st_16b strd, r0, r1, r2, r3, r4, r5, r6, r7
+        st_reg          \strd, .16b, \r0, \r1, \r2, \r3, \r4, \r5, \r6, \r7
+.endm
+.macro shift_store_8 type, strd, r0, r1, r2, r3
+.ifc \type, put
+        sqrshrun_b      6,     \r0, \r1, \r2, \r3
+        st_8b           \strd, \r0, \r1, \r2, \r3
+.else
+        srshr_h         2,     \r0, \r1, \r2, \r3
+        st_16b          \strd, \r0, \r1, \r2, \r3
+.endif
+.endm
+.macro shift_store_16 type, strd, r0, r1, r2, r3
+.ifc \type, put
+        sqrshrun        \r0\().8b,  \r0\().8h, #6
+        sqrshrun2       \r0\().16b, \r1\().8h, #6
+        sqrshrun        \r2\().8b,  \r2\().8h, #6
+        sqrshrun2       \r2\().16b, \r3\().8h, #6
+        st_16b          \strd, \r0, \r2
+.else
+        srshr_h         2,     \r0, \r1, \r2, \r3
+        st1             {\r0\().8h, \r1\().8h}, [x0], \strd
+        st1             {\r2\().8h, \r3\().8h}, [x8], \strd
+.endif
+.endm
+
+.macro make_8tap_fn op, type, type_h, type_v, taps
+function \op\()_8tap_\type\()_8bpc_neon, export=1
+        mov             x8,  \type_h
+        mov             x9,  \type_v
+        b               \op\()_\taps\()_neon
+endfunc
+.endm
+
+// No spaces in these expressions, due to gas-preprocessor.
+#define REGULAR ((0*15<<7)|3*15)
+#define SMOOTH  ((1*15<<7)|4*15)
+#define SHARP   ((2*15<<7)|3*15)
+
+.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, ds2, sr2, shift_hv, taps
+function \type\()_\taps\()_neon
+        mov             w10,  #0x4081  // (1 << 14) | (1 << 7) | (1 << 0)
+        mul             \mx,  \mx, w10
+        mul             \my,  \my, w10
+        add             \mx,  \mx, w8 // mx, 8tap_h, 4tap_h
+        add             \my,  \my, w9 // my, 8tap_v, 4tap_v
+.ifc \type, prep
+        uxtw            \d_strd, \w
+        lsl             \d_strd, \d_strd, #1
+.endif
+
+        clz             w8,  \w
+        tst             \mx, #(0x7f << 14)
+        sub             w8,  w8,  #24
+        movrel          x10, X(mc_subpel_filters), -8
+        b.ne            L(\type\()_\taps\()_h)
+        tst             \my, #(0x7f << 14)
+        b.ne            L(\type\()_\taps\()_v)
+        b               \type\()_neon
+
+L(\type\()_\taps\()_h):
+        cmp             \w,  #4
+        ubfx            w9,  \mx, #7, #7
+        and             \mx, \mx, #0x7f
+        b.le            4f
+        mov             \mx,  w9
+4:
+        tst             \my,  #(0x7f << 14)
+        add             \xmx, x10, \mx, uxtw #3
+        b.ne            L(\type\()_\taps\()_hv)
+
+        movrel          x9,  \type\()_\taps\()_h_tbl
+        ldrsw           x8,  [x9, x8, lsl #2]
+        add             x9,  x9,  x8
+        br              x9
+
+20:     // 2xN h
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        ldur            s0,  [\xmx, #2]
+        sub             \src,  \src,  #1
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h,  v0.8b
+2:
+        ld1             {v4.8b},  [\src], \s_strd
+        ld1             {v6.8b},  [\sr2], \s_strd
+        uxtl            v4.8h,  v4.8b
+        uxtl            v6.8h,  v6.8b
+        ext             v5.16b, v4.16b, v4.16b, #2
+        ext             v7.16b, v6.16b, v6.16b, #2
+        subs            \h,  \h,  #2
+        trn1            v3.2s,  v4.2s,  v6.2s
+        trn2            v6.2s,  v4.2s,  v6.2s
+        trn1            v4.2s,  v5.2s,  v7.2s
+        trn2            v7.2s,  v5.2s,  v7.2s
+        mul             v3.4h,  v3.4h,  v0.h[0]
+        mla             v3.4h,  v4.4h,  v0.h[1]
+        mla             v3.4h,  v6.4h,  v0.h[2]
+        mla             v3.4h,  v7.4h,  v0.h[3]
+        srshr           v3.4h,  v3.4h,  #2
+        sqrshrun        v3.8b,  v3.8h,  #4
+        st1             {v3.h}[0], [\dst], \d_strd
+        st1             {v3.h}[1], [\ds2], \d_strd
+        b.gt            2b
+        ret
+.endif
+
+40:     // 4xN h
+        AARCH64_VALID_JUMP_TARGET
+        ldur            s0,  [\xmx, #2]
+        sub             \src,  \src,  #1
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h,  v0.8b
+4:
+        ld1             {v16.8b}, [\src], \s_strd
+        ld1             {v20.8b}, [\sr2], \s_strd
+        uxtl            v16.8h,  v16.8b
+        uxtl            v20.8h,  v20.8b
+        ext             v17.16b, v16.16b, v16.16b, #2
+        ext             v18.16b, v16.16b, v16.16b, #4
+        ext             v19.16b, v16.16b, v16.16b, #6
+        ext             v21.16b, v20.16b, v20.16b, #2
+        ext             v22.16b, v20.16b, v20.16b, #4
+        ext             v23.16b, v20.16b, v20.16b, #6
+        subs            \h,  \h,  #2
+        mul             v16.4h,  v16.4h,  v0.h[0]
+        mla             v16.4h,  v17.4h,  v0.h[1]
+        mla             v16.4h,  v18.4h,  v0.h[2]
+        mla             v16.4h,  v19.4h,  v0.h[3]
+        mul             v20.4h,  v20.4h,  v0.h[0]
+        mla             v20.4h,  v21.4h,  v0.h[1]
+        mla             v20.4h,  v22.4h,  v0.h[2]
+        mla             v20.4h,  v23.4h,  v0.h[3]
+        srshr           v16.4h,  v16.4h,  #2
+        srshr           v20.4h,  v20.4h,  #2
+.ifc \type, put
+        sqrshrun        v16.8b,  v16.8h,  #4
+        sqrshrun        v20.8b,  v20.8h,  #4
+        str             s16,  [\dst]
+        str             s20,  [\ds2]
+        add             \dst, \dst, \d_strd
+        add             \ds2, \ds2, \d_strd
+.else
+        st1             {v16.4h}, [\dst], \d_strd
+        st1             {v20.4h}, [\ds2], \d_strd
+.endif
+        b.gt            4b
+        ret
+
+80:     // 8xN h
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b}, [\xmx]
+.ifc \taps, 6tap
+        sub             \src,  \src,  #2
+.else
+        sub             \src,  \src,  #3
+.endif
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h, v0.8b
+8:
+        ld1             {v16.8b, v17.8b},  [\src], \s_strd
+        ld1             {v20.8b, v21.8b},  [\sr2], \s_strd
+        uxtl            v16.8h,  v16.8b
+        uxtl            v17.8h,  v17.8b
+        uxtl            v20.8h,  v20.8b
+        uxtl            v21.8h,  v21.8b
+
+.ifc \taps, 6tap
+        mul             v18.8h,  v16.8h,  v0.h[1]
+        mul             v22.8h,  v20.8h,  v0.h[1]
+    .irpc i, 23456
+        ext             v19.16b, v16.16b, v17.16b, #(2*\i-2)
+        ext             v23.16b, v20.16b, v21.16b, #(2*\i-2)
+        mla             v18.8h,  v19.8h,  v0.h[\i]
+        mla             v22.8h,  v23.8h,  v0.h[\i]
+    .endr
+.else   // 8tap
+        mul             v18.8h,  v16.8h,  v0.h[0]
+        mul             v22.8h,  v20.8h,  v0.h[0]
+    .irpc i, 1234567
+        ext             v19.16b, v16.16b, v17.16b, #(2*\i)
+        ext             v23.16b, v20.16b, v21.16b, #(2*\i)
+        mla             v18.8h,  v19.8h,  v0.h[\i]
+        mla             v22.8h,  v23.8h,  v0.h[\i]
+    .endr
+.endif
+        subs            \h,  \h,  #2
+        srshr           v18.8h,  v18.8h, #2
+        srshr           v22.8h,  v22.8h, #2
+.ifc \type, put
+        sqrshrun        v18.8b,  v18.8h, #4
+        sqrshrun        v22.8b,  v22.8h, #4
+        st1             {v18.8b}, [\dst], \d_strd
+        st1             {v22.8b}, [\ds2], \d_strd
+.else
+        st1             {v18.8h}, [\dst], \d_strd
+        st1             {v22.8h}, [\ds2], \d_strd
+.endif
+        b.gt            8b
+        ret
+160:
+320:
+640:
+1280:   // 16xN, 32xN, ... h
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b}, [\xmx]
+.ifc \taps, 6tap
+        sub             \src,  \src,  #2
+.else
+        sub             \src,  \src,  #3
+.endif
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h, v0.8b
+
+        sub             \s_strd,  \s_strd,  \w, uxtw
+        sub             \s_strd,  \s_strd,  #8
+.ifc \type, put
+        lsl             \d_strd,  \d_strd,  #1
+        sub             \d_strd,  \d_strd,  \w, uxtw
+.endif
+161:
+        ld1             {v16.8b, v17.8b, v18.8b},  [\src], #24
+        ld1             {v20.8b, v21.8b, v22.8b},  [\sr2], #24
+        mov             \mx, \w
+        uxtl            v16.8h,  v16.8b
+        uxtl            v17.8h,  v17.8b
+        uxtl            v18.8h,  v18.8b
+        uxtl            v20.8h,  v20.8b
+        uxtl            v21.8h,  v21.8b
+        uxtl            v22.8h,  v22.8b
+
+16:
+.ifc \taps, 6tap
+        mul             v24.8h,  v16.8h,  v0.h[1]
+        mul             v25.8h,  v17.8h,  v0.h[1]
+        mul             v26.8h,  v20.8h,  v0.h[1]
+        mul             v27.8h,  v21.8h,  v0.h[1]
+    .irpc i, 23456
+        ext             v28.16b, v16.16b, v17.16b, #(2*\i-2)
+        ext             v29.16b, v17.16b, v18.16b, #(2*\i-2)
+        ext             v30.16b, v20.16b, v21.16b, #(2*\i-2)
+        ext             v31.16b, v21.16b, v22.16b, #(2*\i-2)
+        mla             v24.8h,  v28.8h,  v0.h[\i]
+        mla             v25.8h,  v29.8h,  v0.h[\i]
+        mla             v26.8h,  v30.8h,  v0.h[\i]
+        mla             v27.8h,  v31.8h,  v0.h[\i]
+    .endr
+.else   // 8tap
+        mul             v24.8h,  v16.8h,  v0.h[0]
+        mul             v25.8h,  v17.8h,  v0.h[0]
+        mul             v26.8h,  v20.8h,  v0.h[0]
+        mul             v27.8h,  v21.8h,  v0.h[0]
+    .irpc i, 1234567
+        ext             v28.16b, v16.16b, v17.16b, #(2*\i)
+        ext             v29.16b, v17.16b, v18.16b, #(2*\i)
+        ext             v30.16b, v20.16b, v21.16b, #(2*\i)
+        ext             v31.16b, v21.16b, v22.16b, #(2*\i)
+        mla             v24.8h,  v28.8h,  v0.h[\i]
+        mla             v25.8h,  v29.8h,  v0.h[\i]
+        mla             v26.8h,  v30.8h,  v0.h[\i]
+        mla             v27.8h,  v31.8h,  v0.h[\i]
+    .endr
+.endif
+        srshr           v24.8h,  v24.8h, #2
+        srshr           v25.8h,  v25.8h, #2
+        srshr           v26.8h,  v26.8h, #2
+        srshr           v27.8h,  v27.8h, #2
+        subs            \mx, \mx, #16
+.ifc \type, put
+        sqrshrun        v24.8b,  v24.8h, #4
+        sqrshrun2       v24.16b, v25.8h, #4
+        sqrshrun        v26.8b,  v26.8h, #4
+        sqrshrun2       v26.16b, v27.8h, #4
+        st1             {v24.16b}, [\dst], #16
+        st1             {v26.16b}, [\ds2], #16
+.else
+        st1             {v24.8h, v25.8h}, [\dst], #32
+        st1             {v26.8h, v27.8h}, [\ds2], #32
+.endif
+        b.le            9f
+
+        mov             v16.16b, v18.16b
+        mov             v20.16b, v22.16b
+        ld1             {v17.8b, v18.8b}, [\src], #16
+        ld1             {v21.8b, v22.8b}, [\sr2], #16
+        uxtl            v17.8h,  v17.8b
+        uxtl            v18.8h,  v18.8b
+        uxtl            v21.8h,  v21.8b
+        uxtl            v22.8h,  v22.8b
+        b               16b
+
+9:
+        add             \dst,  \dst,  \d_strd
+        add             \ds2,  \ds2,  \d_strd
+        add             \src,  \src,  \s_strd
+        add             \sr2,  \sr2,  \s_strd
+
+        subs            \h,  \h,  #2
+        b.gt            161b
+        ret
+endfunc
+
+jumptable \type\()_\taps\()_h_tbl
+        .word 1280b - \type\()_\taps\()_h_tbl
+        .word 640b  - \type\()_\taps\()_h_tbl
+        .word 320b  - \type\()_\taps\()_h_tbl
+        .word 160b  - \type\()_\taps\()_h_tbl
+        .word 80b   - \type\()_\taps\()_h_tbl
+        .word 40b   - \type\()_\taps\()_h_tbl
+        .word 20b   - \type\()_\taps\()_h_tbl
+endjumptable
+
+function L(\type\()_\taps\()_v)
+        cmp             \h,  #4
+        ubfx            w9,  \my, #7, #7
+        and             \my, \my, #0x7f
+        b.le            4f
+        mov             \my, w9
+4:
+        add             \xmy, x10, \my, uxtw #3
+
+        movrel          x9,  \type\()_\taps\()_v_tbl
+        ldrsw           x8,  [x9, x8, lsl #2]
+        add             x9,  x9,  x8
+        br              x9
+
+20:     // 2xN v
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        b.gt            28f
+
+        cmp             \h,  #2
+        ldur            s0,  [\xmy, #2]
+        sub             \src,  \src,  \s_strd
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        sxtl            v0.8h, v0.8b
+
+        // 2x2 v
+        load_h          \src, \sr2, \s_strd, v1, v2, v3, v4, v5
+        interleave_1_h  v1, v2, v3, v4, v5
+        b.gt            24f
+        uxtl_b          v1, v2, v3, v4
+        mul_mla_4tap    v6, v1, v2, v3, v4, .4h
+        sqrshrun_b      6,  v6
+        st_h            \d_strd, v6, 2
+        ret
+
+24:     // 2x4 v
+        load_h          \sr2, \src, \s_strd, v6, v7
+        interleave_1_h  v5, v6, v7
+        interleave_2_s  v1, v2, v3, v4, v5, v6
+        uxtl_b          v1, v2, v3, v4
+        mul_mla_4tap    v6, v1, v2, v3, v4, .8h
+        sqrshrun_b      6,  v6
+        st_h            \d_strd, v6, 4
+        ret
+
+28:     // 2x6, 2x8, 2x12, 2x16 v
+        ld1             {v0.8b}, [\xmy]
+        sub             \sr2,  \src,  \s_strd, lsl #1
+        add             \ds2,  \dst,  \d_strd
+        sub             \src,  \sr2,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h, v0.8b
+
+        load_h          \src, \sr2, \s_strd, v1,  v2,  v3,  v4, v5, v6, v7
+        interleave_1_h  v1,  v2,  v3,  v4,  v5
+        interleave_1_h  v5,  v6,  v7
+        interleave_2_s  v1,  v2,  v3,  v4,  v5,  v6
+        uxtl_b          v1,  v2,  v3,  v4
+216:
+        subs            \h,  \h,  #4
+        load_h          \sr2, \src, \s_strd, v16, v17, v18, v19
+        interleave_1_h  v7,  v16, v17, v18, v19
+        interleave_2_s  v5,  v6,  v7,  v16, v17, v18
+        uxtl_b          v5,  v6,  v7,  v16
+        mul_mla_\taps\()_0 v30, v1, v2, v3, v4, v5, v6, v7, v16
+        sqrshrun_b      6,   v30
+        st_h            \d_strd, v30, 4
+        b.le            0f
+        cmp             \h,  #2
+        mov             v1.16b,  v5.16b
+        mov             v2.16b,  v6.16b
+        mov             v3.16b,  v7.16b
+        mov             v4.16b,  v16.16b
+        mov             v5.16b,  v17.16b
+        mov             v6.16b,  v18.16b
+        mov             v7.16b,  v19.16b
+        b.eq            26f
+        b               216b
+26:
+        load_h          \sr2, \src, \s_strd, v16, v17
+        interleave_1_h  v7,  v16, v17
+        uxtl_b          v5,  v6,  v7,  v16
+        mul_mla_\taps\()_0_4h v30, v1, v2, v3, v4, v5, v6, v7, v16
+        sqrshrun_b      6,   v30
+        st_h            \d_strd, v30, 2
+0:
+        ret
+.endif
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+        b.gt            480f
+
+        // 4x2, 4x4 v
+        cmp             \h,  #2
+        ldur            s0,  [\xmy, #2]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h, v0.8b
+
+        load_s          \src, \sr2, \s_strd, v1, v2, v3, v4, v5
+        interleave_1_s  v1, v2, v3, v4, v5
+        uxtl_b          v1, v2, v3, v4
+        mul_mla_4tap    v6, v1, v2, v3, v4, .8h
+        shift_store_4   \type, \d_strd, v6
+        b.le            0f
+        load_s          \sr2, \src, \s_strd, v6, v7
+        interleave_1_s  v5, v6, v7
+        uxtl_b          v5, v6
+        mul_mla_4tap    v7, v3, v4, v5, v6, .8h
+        shift_store_4   \type, \d_strd, v7
+0:
+        ret
+
+480:    // 4x6, 4x8, 4x12, 4x16 v
+        ld1             {v0.8b}, [\xmy]
+        sub             \sr2, \src, \s_strd, lsl #1
+        add             \ds2, \dst, \d_strd
+        sub             \src, \sr2, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h, v0.8b
+
+        load_s          \src, \sr2, \s_strd, v16, v17, v18, v19, v20, v21, v22
+        interleave_1_s  v16, v17, v18
+        interleave_1_s  v18, v19, v20, v21, v22
+        uxtl_b          v16, v17
+        uxtl_b          v18, v19, v20, v21
+
+48:
+        subs            \h,  \h,  #4
+        load_s          \sr2, \src, \s_strd, v23, v24, v25, v26
+        interleave_1_s  v22, v23, v24, v25, v26
+        uxtl_b          v22, v23, v24, v25
+        mul_mla_\taps\()_2 v1, v2, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25
+        shift_store_4   \type, \d_strd, v1, v2
+        b.le            0f
+        load_s          \sr2,  \src, \s_strd, v27, v16
+        subs            \h,  \h,  #2
+        interleave_1_s  v26, v27, v16
+        uxtl_b          v26, v27
+        mul_mla_\taps\()_0 v1, v20, v21, v22, v23, v24, v25, v26, v27
+        shift_store_4   \type, \d_strd, v1
+        b.le            0f
+        load_s          \sr2,  \src, \s_strd, v17, v18
+        subs            \h,  \h,  #2
+        interleave_1_s  v16, v17, v18
+        uxtl_b          v16, v17
+        mul_mla_\taps\()_0 v2, v22, v23, v24, v25, v26, v27, v16, v17
+        shift_store_4   \type, \d_strd, v2
+        b.le            0f
+        subs            \h,  \h,  #4
+        load_s          \sr2, \src, \s_strd, v19, v20, v21, v22
+        interleave_1_s  v18, v19, v20, v21, v22
+        uxtl_b          v18, v19, v20, v21
+        mul_mla_\taps\()_2 v1, v2, v24, v25, v26, v27, v16, v17, v18, v19, v20, v21
+        shift_store_4   \type, \d_strd, v1, v2
+        b.gt            48b
+0:
+        ret
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+        b.gt            880f
+
+        // 8x2, 8x4 v
+        cmp             \h,  #2
+        ldur            s0,  [\xmy, #2]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h, v0.8b
+
+        load_8b         \src, \sr2, \s_strd, v1, v2, v3, v4, v5
+        uxtl_b          v1, v2, v3, v4, v5
+        mul_mla_4tap    v6, v1, v2, v3, v4, .8h
+        mul_mla_4tap    v7, v2, v3, v4, v5, .8h
+        shift_store_8   \type, \d_strd, v6, v7
+        b.le            0f
+        load_8b         \sr2, \src, \s_strd, v6, v7
+        uxtl_b          v6, v7
+        mul_mla_4tap    v1, v3, v4, v5, v6, .8h
+        mul_mla_4tap    v2, v4, v5, v6, v7, .8h
+        shift_store_8   \type, \d_strd, v1, v2
+0:
+        ret
+
+880:    // 8x6, 8x8, 8x16, 8x32 v
+1680:   // 16x8, 16x16, ...
+320:    // 32x8, 32x16, ...
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b}, [\xmy]
+        sub             \src, \src, \s_strd
+        sub             \src, \src, \s_strd, lsl #1
+        sxtl            v0.8h, v0.8b
+        mov             \my,  \h
+168:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        load_8b         \src, \sr2, \s_strd, v16, v17, v18, v19, v20, v21, v22
+        uxtl_b          v16, v17, v18, v19, v20, v21, v22
+
+88:
+        subs            \h,  \h,  #2
+        load_8b         \sr2, \src, \s_strd, v23, v24
+        uxtl_b          v23, v24
+        mul_mla_\taps\()_1 v1, v2, v16, v17, v18, v19, v20, v21, v22, v23, v24
+        shift_store_8   \type, \d_strd, v1, v2
+        b.le            9f
+        subs            \h,  \h,  #2
+        load_8b         \sr2, \src, \s_strd, v25, v26
+        uxtl_b          v25, v26
+        mul_mla_\taps\()_1 v3, v4, v18, v19, v20, v21, v22, v23, v24, v25, v26
+        shift_store_8   \type, \d_strd, v3, v4
+        b.le            9f
+        subs            \h,  \h,  #2
+        load_8b         \sr2, \src, \s_strd, v27, v16
+        uxtl_b          v27, v16
+        mul_mla_\taps\()_1 v1, v2, v20, v21, v22, v23, v24, v25, v26, v27, v16
+        shift_store_8   \type, \d_strd, v1, v2
+        b.le            9f
+        subs            \h,  \h,  #2
+        load_8b         \sr2, \src, \s_strd, v17, v18
+        uxtl_b          v17, v18
+        mul_mla_\taps\()_1 v3, v4, v22, v23, v24, v25, v26, v27, v16, v17, v18
+        shift_store_8   \type, \d_strd, v3, v4
+        b.le            9f
+        subs            \h,  \h,  #4
+        load_8b         \sr2, \src, \s_strd, v19, v20, v21, v22
+        uxtl_b          v19, v20, v21, v22
+        mul_mla_\taps\()_1 v1, v2, v24, v25, v26, v27, v16, v17, v18, v19, v20
+        mul_mla_\taps\()_1 v3, v4, v26, v27, v16, v17, v18, v19, v20, v21, v22
+        shift_store_8   \type, \d_strd, v1, v2, v3, v4
+        b.gt            88b
+9:
+        subs            \w,  \w,  #8
+        b.le            0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        msub            \src, \s_strd, \xmy, \src
+        msub            \dst, \d_strd, \xmy, \dst
+        sub             \src, \src, \s_strd, lsl #3
+        mov             \h,  \my
+        add             \src, \src, #8
+.ifc \type, put
+        add             \dst, \dst, #8
+.else
+        add             \dst, \dst, #16
+.endif
+        b               168b
+0:
+        ret
+
+160:
+        AARCH64_VALID_JUMP_TARGET
+        b.gt            1680b
+
+        // 16x2, 16x4 v
+        ldur            s0,  [\xmy, #2]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h, v0.8b
+
+        cmp             \h,  #2
+        load_16b        \src, \sr2, \s_strd, v1,  v2,  v3,  v4,  v5
+        uxtl            v16.8h, v1.8b
+        uxtl            v17.8h, v2.8b
+        uxtl            v18.8h, v3.8b
+        uxtl            v19.8h, v4.8b
+        uxtl            v20.8h, v5.8b
+        uxtl2           v23.8h, v1.16b
+        uxtl2           v24.8h, v2.16b
+        uxtl2           v25.8h, v3.16b
+        uxtl2           v26.8h, v4.16b
+        uxtl2           v27.8h, v5.16b
+        mul_mla_4tap    v1,  v16, v17, v18, v19, .8h
+        mul_mla_4tap    v16, v17, v18, v19, v20, .8h
+        mul_mla_4tap    v2,  v23, v24, v25, v26, .8h
+        mul_mla_4tap    v17, v24, v25, v26, v27, .8h
+        shift_store_16  \type, \d_strd, v1, v2, v16, v17
+        b.le            0f
+        load_16b        \sr2, \src, \s_strd, v6,  v7
+        uxtl            v21.8h, v6.8b
+        uxtl            v22.8h, v7.8b
+        uxtl2           v28.8h, v6.16b
+        uxtl2           v29.8h, v7.16b
+        mul_mla_4tap    v1,  v18, v19, v20, v21, .8h
+        mul_mla_4tap    v3,  v19, v20, v21, v22, .8h
+        mul_mla_4tap    v2,  v25, v26, v27, v28, .8h
+        mul_mla_4tap    v4,  v26, v27, v28, v29, .8h
+        shift_store_16  \type, \d_strd, v1, v2, v3, v4
+0:
+        ret
+endfunc
+
+jumptable \type\()_\taps\()_v_tbl
+        .word 1280b - \type\()_\taps\()_v_tbl
+        .word 640b  - \type\()_\taps\()_v_tbl
+        .word 320b  - \type\()_\taps\()_v_tbl
+        .word 160b  - \type\()_\taps\()_v_tbl
+        .word 80b   - \type\()_\taps\()_v_tbl
+        .word 40b   - \type\()_\taps\()_v_tbl
+        .word 20b   - \type\()_\taps\()_v_tbl
+endjumptable
+
+function L(\type\()_\taps\()_hv)
+        cmp             \h,  #4
+        ubfx            w9,  \my, #7, #7
+        and             \my, \my, #0x7f
+        b.le            4f
+        mov             \my,  w9
+4:
+        add             \xmy,  x10, \my, uxtw #3
+
+        movrel          x9,  \type\()_\taps\()_hv_tbl
+        ldrsw           x8,  [x9, x8, lsl #2]
+        add             x9,  x9,  x8
+        br              x9
+
+20:
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        ldur            s0,  [\xmx, #2]
+        b.gt            280f
+        ldur            s1,  [\xmy, #2]
+
+        // 2x2, 2x4 hv
+        sub             \sr2, \src, #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,  v0.8b
+        sxtl            v1.8h,  v1.8b
+        mov             x15, x30
+
+        ld1             {v28.8b}, [\src], \s_strd
+        uxtl            v28.8h,  v28.8b
+        ext             v29.16b, v28.16b, v28.16b, #2
+        mul             v28.4h,  v28.4h,  v0.4h
+        mul             v29.4h,  v29.4h,  v0.4h
+        addp            v28.4h,  v28.4h,  v29.4h
+        addp            v16.4h,  v28.4h,  v28.4h
+        srshr           v16.4h,  v16.4h,  #2
+        bl              L(\type\()_\taps\()_filter_2)
+
+        trn1            v16.2s, v16.2s, v28.2s
+        mov             v17.8b, v28.8b
+
+2:
+        bl              L(\type\()_\taps\()_filter_2)
+
+        ext             v18.8b, v17.8b, v28.8b, #4
+        smull           v2.4s,  v16.4h, v1.h[0]
+        smlal           v2.4s,  v17.4h, v1.h[1]
+        smlal           v2.4s,  v18.4h, v1.h[2]
+        smlal           v2.4s,  v28.4h, v1.h[3]
+
+        sqrshrn         v2.4h,  v2.4s,  #\shift_hv
+        sqxtun          v2.8b,  v2.8h
+        subs            \h,  \h,  #2
+        st1             {v2.h}[0], [\dst], \d_strd
+        st1             {v2.h}[1], [\ds2], \d_strd
+        b.le            0f
+        mov             v16.8b, v18.8b
+        mov             v17.8b, v28.8b
+        b               2b
+
+280:    // 2x8, 2x16, 2x32 hv
+        ld1             {v1.8b},  [\xmy]
+        sub             \src, \src, #1
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,  v0.8b
+        sxtl            v1.8h,  v1.8b
+        mov             x15, x30
+
+        ld1             {v28.8b}, [\src], \s_strd
+        uxtl            v28.8h,  v28.8b
+        ext             v29.16b, v28.16b, v28.16b, #2
+        mul             v28.4h,  v28.4h,  v0.4h
+        mul             v29.4h,  v29.4h,  v0.4h
+        addp            v28.4h,  v28.4h,  v29.4h
+        addp            v16.4h,  v28.4h,  v28.4h
+        srshr           v16.4h,  v16.4h,  #2
+
+        bl              L(\type\()_\taps\()_filter_2)
+        trn1            v16.2s, v16.2s, v28.2s
+        mov             v17.8b, v28.8b
+        bl              L(\type\()_\taps\()_filter_2)
+        ext             v18.8b, v17.8b, v28.8b, #4
+        mov             v19.8b, v28.8b
+        bl              L(\type\()_\taps\()_filter_2)
+        ext             v20.8b, v19.8b, v28.8b, #4
+        mov             v21.8b, v28.8b
+
+28:
+        bl              L(\type\()_\taps\()_filter_2)
+        ext             v22.8b, v21.8b, v28.8b, #4
+.ifc \taps, 6tap
+        smull           v2.4s,  v17.4h, v1.h[1]
+        smlal           v2.4s,  v18.4h, v1.h[2]
+        smlal           v2.4s,  v19.4h, v1.h[3]
+        smlal           v2.4s,  v20.4h, v1.h[4]
+        smlal           v2.4s,  v21.4h, v1.h[5]
+        smlal           v2.4s,  v22.4h, v1.h[6]
+.else   // 8tap
+        smull           v2.4s,  v16.4h, v1.h[0]
+        smlal           v2.4s,  v17.4h, v1.h[1]
+        smlal           v2.4s,  v18.4h, v1.h[2]
+        smlal           v2.4s,  v19.4h, v1.h[3]
+        smlal           v2.4s,  v20.4h, v1.h[4]
+        smlal           v2.4s,  v21.4h, v1.h[5]
+        smlal           v2.4s,  v22.4h, v1.h[6]
+        smlal           v2.4s,  v28.4h, v1.h[7]
+.endif
+
+        sqrshrn         v2.4h,  v2.4s,  #\shift_hv
+        sqxtun          v2.8b,  v2.8h
+        subs            \h,  \h,  #2
+        st1             {v2.h}[0], [\dst], \d_strd
+        st1             {v2.h}[1], [\ds2], \d_strd
+        b.le            0f
+        mov             v16.8b, v18.8b
+        mov             v17.8b, v19.8b
+        mov             v18.8b, v20.8b
+        mov             v19.8b, v21.8b
+        mov             v20.8b, v22.8b
+        mov             v21.8b, v28.8b
+        b               28b
+
+0:
+        ret             x15
+
+L(\type\()_\taps\()_filter_2):
+        ld1             {v28.8b},  [\sr2], \s_strd
+        ld1             {v30.8b},  [\src], \s_strd
+        uxtl            v28.8h,  v28.8b
+        uxtl            v30.8h,  v30.8b
+        ext             v29.16b, v28.16b, v28.16b, #2
+        ext             v31.16b, v30.16b, v30.16b, #2
+        trn1            v27.2s,  v28.2s,  v30.2s
+        trn2            v30.2s,  v28.2s,  v30.2s
+        trn1            v28.2s,  v29.2s,  v31.2s
+        trn2            v31.2s,  v29.2s,  v31.2s
+        mul             v27.4h,  v27.4h,  v0.h[0]
+        mla             v27.4h,  v28.4h,  v0.h[1]
+        mla             v27.4h,  v30.4h,  v0.h[2]
+        mla             v27.4h,  v31.4h,  v0.h[3]
+        srshr           v28.4h,  v27.4h,  #2
+        ret
+.endif
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ldur            s0,  [\xmx, #2]
+        b.gt            480f
+        ldur            s1,  [\xmy, #2]
+        sub             \sr2, \src, #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,  v0.8b
+        sxtl            v1.8h,  v1.8b
+        mov             x15, x30
+
+        // 4x2, 4x4 hv
+        ld1             {v26.8b}, [\src], \s_strd
+        uxtl            v26.8h,  v26.8b
+        ext             v28.16b, v26.16b, v26.16b, #2
+        ext             v29.16b, v26.16b, v26.16b, #4
+        ext             v30.16b, v26.16b, v26.16b, #6
+        mul             v31.4h,  v26.4h,  v0.h[0]
+        mla             v31.4h,  v28.4h,  v0.h[1]
+        mla             v31.4h,  v29.4h,  v0.h[2]
+        mla             v31.4h,  v30.4h,  v0.h[3]
+        srshr           v16.4h,  v31.4h,  #2
+
+        bl              L(\type\()_\taps\()_filter_4)
+        mov             v17.8b, v28.8b
+        mov             v18.8b, v29.8b
+
+4:
+        bl              L(\type\()_\taps\()_filter_4)
+        // Interleaving the mul/mla chains actually hurts performance
+        // significantly on Cortex A53, thus keeping mul/mla tightly
+        // chained like this.
+        smull           v2.4s,  v16.4h, v1.h[0]
+        smlal           v2.4s,  v17.4h, v1.h[1]
+        smlal           v2.4s,  v18.4h, v1.h[2]
+        smlal           v2.4s,  v28.4h, v1.h[3]
+        smull           v3.4s,  v17.4h, v1.h[0]
+        smlal           v3.4s,  v18.4h, v1.h[1]
+        smlal           v3.4s,  v28.4h, v1.h[2]
+        smlal           v3.4s,  v29.4h, v1.h[3]
+        sqrshrn         v2.4h,  v2.4s,  #\shift_hv
+        sqrshrn         v3.4h,  v3.4s,  #\shift_hv
+        subs            \h,  \h,  #2
+.ifc \type, put
+        sqxtun          v2.8b,  v2.8h
+        sqxtun          v3.8b,  v3.8h
+        str             s2,  [\dst]
+        str             s3,  [\ds2]
+        add             \dst, \dst, \d_strd
+        add             \ds2, \ds2, \d_strd
+.else
+        st1             {v2.4h}, [\dst], \d_strd
+        st1             {v3.4h}, [\ds2], \d_strd
+.endif
+        b.le            0f
+        mov             v16.8b,  v18.8b
+        mov             v17.8b,  v28.8b
+        mov             v18.8b,  v29.8b
+        b               4b
+
+480:    // 4x8, 4x16, 4x32 hv
+        ld1             {v1.8b},  [\xmy]
+        sub             \src, \src, #1
+.ifc \taps, 6tap
+        sub             \sr2, \src, \s_strd
+        sub             \src, \src, \s_strd, lsl #1
+.else
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+.endif
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,  v0.8b
+        sxtl            v1.8h,  v1.8b
+        mov             x15, x30
+
+        ld1             {v26.8b}, [\src], \s_strd
+        uxtl            v26.8h,  v26.8b
+        ext             v28.16b, v26.16b, v26.16b, #2
+        ext             v29.16b, v26.16b, v26.16b, #4
+        ext             v30.16b, v26.16b, v26.16b, #6
+        mul             v31.4h,  v26.4h,  v0.h[0]
+        mla             v31.4h,  v28.4h,  v0.h[1]
+        mla             v31.4h,  v29.4h,  v0.h[2]
+        mla             v31.4h,  v30.4h,  v0.h[3]
+.ifc \taps, 6tap
+        srshr           v18.4h,  v31.4h,  #2
+.else
+        srshr           v16.4h,  v31.4h,  #2
+
+        bl              L(\type\()_\taps\()_filter_4)
+        mov             v17.8b, v28.8b
+        mov             v18.8b, v29.8b
+.endif
+        bl              L(\type\()_\taps\()_filter_4)
+        mov             v19.8b, v28.8b
+        mov             v20.8b, v29.8b
+        bl              L(\type\()_\taps\()_filter_4)
+        mov             v21.8b, v28.8b
+        mov             v22.8b, v29.8b
+
+48:
+        bl              L(\type\()_\taps\()_filter_4)
+.ifc \taps, 6tap
+        smull           v2.4s,  v18.4h, v1.h[1]
+        smlal           v2.4s,  v19.4h, v1.h[2]
+        smlal           v2.4s,  v20.4h, v1.h[3]
+        smlal           v2.4s,  v21.4h, v1.h[4]
+        smlal           v2.4s,  v22.4h, v1.h[5]
+        smlal           v2.4s,  v28.4h, v1.h[6]
+        smull           v3.4s,  v19.4h, v1.h[1]
+        smlal           v3.4s,  v20.4h, v1.h[2]
+        smlal           v3.4s,  v21.4h, v1.h[3]
+        smlal           v3.4s,  v22.4h, v1.h[4]
+        smlal           v3.4s,  v28.4h, v1.h[5]
+        smlal           v3.4s,  v29.4h, v1.h[6]
+.else   // 8tap
+        smull           v2.4s,  v16.4h, v1.h[0]
+        smlal           v2.4s,  v17.4h, v1.h[1]
+        smlal           v2.4s,  v18.4h, v1.h[2]
+        smlal           v2.4s,  v19.4h, v1.h[3]
+        smlal           v2.4s,  v20.4h, v1.h[4]
+        smlal           v2.4s,  v21.4h, v1.h[5]
+        smlal           v2.4s,  v22.4h, v1.h[6]
+        smlal           v2.4s,  v28.4h, v1.h[7]
+        smull           v3.4s,  v17.4h, v1.h[0]
+        smlal           v3.4s,  v18.4h, v1.h[1]
+        smlal           v3.4s,  v19.4h, v1.h[2]
+        smlal           v3.4s,  v20.4h, v1.h[3]
+        smlal           v3.4s,  v21.4h, v1.h[4]
+        smlal           v3.4s,  v22.4h, v1.h[5]
+        smlal           v3.4s,  v28.4h, v1.h[6]
+        smlal           v3.4s,  v29.4h, v1.h[7]
+.endif
+        sqrshrn         v2.4h,  v2.4s,  #\shift_hv
+        sqrshrn         v3.4h,  v3.4s,  #\shift_hv
+        subs            \h,  \h,  #2
+.ifc \type, put
+        sqxtun          v2.8b,  v2.8h
+        sqxtun          v3.8b,  v3.8h
+        str             s2,  [\dst]
+        str             s3,  [\ds2]
+        add             \dst, \dst, \d_strd
+        add             \ds2, \ds2, \d_strd
+.else
+        st1             {v2.4h}, [\dst], \d_strd
+        st1             {v3.4h}, [\ds2], \d_strd
+.endif
+        b.le            0f
+.ifc \taps, 8tap
+        mov             v16.8b,  v18.8b
+        mov             v17.8b,  v19.8b
+.endif
+        mov             v18.8b,  v20.8b
+        mov             v19.8b,  v21.8b
+        mov             v20.8b,  v22.8b
+        mov             v21.8b,  v28.8b
+        mov             v22.8b,  v29.8b
+        b               48b
+0:
+        ret             x15
+
+L(\type\()_\taps\()_filter_4):
+        ld1             {v26.8b}, [\sr2], \s_strd
+        ld1             {v27.8b}, [\src], \s_strd
+        uxtl            v26.8h,  v26.8b
+        uxtl            v27.8h,  v27.8b
+        ext             v28.16b, v26.16b, v26.16b, #2
+        ext             v29.16b, v26.16b, v26.16b, #4
+        ext             v30.16b, v26.16b, v26.16b, #6
+        mul             v31.4h,  v26.4h,  v0.h[0]
+        mla             v31.4h,  v28.4h,  v0.h[1]
+        mla             v31.4h,  v29.4h,  v0.h[2]
+        mla             v31.4h,  v30.4h,  v0.h[3]
+        ext             v28.16b, v27.16b, v27.16b, #2
+        ext             v29.16b, v27.16b, v27.16b, #4
+        ext             v30.16b, v27.16b, v27.16b, #6
+        mul             v27.4h,  v27.4h,  v0.h[0]
+        mla             v27.4h,  v28.4h,  v0.h[1]
+        mla             v27.4h,  v29.4h,  v0.h[2]
+        mla             v27.4h,  v30.4h,  v0.h[3]
+        srshr           v28.4h,  v31.4h,  #2
+        srshr           v29.4h,  v27.4h,  #2
+        ret
+
+80:
+160:
+320:
+        AARCH64_VALID_JUMP_TARGET
+        b.gt            880f
+        ld1             {v0.8b},  [\xmx]
+        ldur            s1,  [\xmy, #2]
+.ifc \taps, 6tap
+        sub             \src,  \src,  #2
+.else
+        sub             \src,  \src,  #3
+.endif
+        sub             \src,  \src,  \s_strd
+        sxtl            v0.8h,  v0.8b
+        sxtl            v1.8h,  v1.8b
+        mov             x15, x30
+        mov             \my,  \h
+
+164:    // 8x2, 8x4, 16x2, 16x4, 32x2, 32x4 hv
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        bl              L(\type\()_\taps\()_filter_8_first)
+        bl              L(\type\()_\taps\()_filter_8)
+        mov             v17.16b, v24.16b
+        mov             v18.16b, v25.16b
+
+8:
+        smull           v2.4s,  v16.4h, v1.h[0]
+        smull2          v3.4s,  v16.8h, v1.h[0]
+        bl              L(\type\()_\taps\()_filter_8)
+        smull           v4.4s,  v17.4h, v1.h[0]
+        smull2          v5.4s,  v17.8h, v1.h[0]
+        smlal           v2.4s,  v17.4h, v1.h[1]
+        smlal2          v3.4s,  v17.8h, v1.h[1]
+        smlal           v4.4s,  v18.4h, v1.h[1]
+        smlal2          v5.4s,  v18.8h, v1.h[1]
+        smlal           v2.4s,  v18.4h, v1.h[2]
+        smlal2          v3.4s,  v18.8h, v1.h[2]
+        smlal           v4.4s,  v24.4h, v1.h[2]
+        smlal2          v5.4s,  v24.8h, v1.h[2]
+        smlal           v2.4s,  v24.4h, v1.h[3]
+        smlal2          v3.4s,  v24.8h, v1.h[3]
+        smlal           v4.4s,  v25.4h, v1.h[3]
+        smlal2          v5.4s,  v25.8h, v1.h[3]
+        sqrshrn         v2.4h,  v2.4s,  #\shift_hv
+        sqrshrn2        v2.8h,  v3.4s,  #\shift_hv
+        sqrshrn         v4.4h,  v4.4s,  #\shift_hv
+        sqrshrn2        v4.8h,  v5.4s,  #\shift_hv
+        subs            \h,  \h,  #2
+.ifc \type, put
+        sqxtun          v2.8b,  v2.8h
+        sqxtun          v4.8b,  v4.8h
+        st1             {v2.8b}, [\dst], \d_strd
+        st1             {v4.8b}, [\ds2], \d_strd
+.else
+        st1             {v2.8h}, [\dst], \d_strd
+        st1             {v4.8h}, [\ds2], \d_strd
+.endif
+        b.le            9f
+        mov             v16.16b, v18.16b
+        mov             v17.16b, v24.16b
+        mov             v18.16b, v25.16b
+        b               8b
+9:
+        subs            \w,  \w,  #8
+        b.le            0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        msub            \src,  \s_strd,  \xmy,  \src
+        msub            \dst,  \d_strd,  \xmy,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #2
+        mov             \h,  \my
+        add             \src,  \src,  #8
+.ifc \type, put
+        add             \dst,  \dst,  #8
+.else
+        add             \dst,  \dst,  #16
+.endif
+        b               164b
+
+880:    // 8x8, 8x16, ..., 16x8, ..., 32x8, ... hv
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [\xmx]
+        ld1             {v1.8b},  [\xmy]
+.ifc \taps, 6tap
+        sub             \src,  \src,  #2
+.else
+        sub             \src,  \src,  #3
+        sub             \src,  \src,  \s_strd
+.endif
+        sub             \src,  \src,  \s_strd, lsl #1
+        sxtl            v0.8h,  v0.8b
+        sxtl            v1.8h,  v1.8b
+        mov             x15, x30
+        mov             \my,  \h
+
+168:
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        bl              L(\type\()_\taps\()_filter_8_first)
+.ifc \taps, 6tap
+        mov             v18.16b, v16.16b
+.else
+        bl              L(\type\()_\taps\()_filter_8)
+        mov             v17.16b, v24.16b
+        mov             v18.16b, v25.16b
+.endif
+        bl              L(\type\()_\taps\()_filter_8)
+        mov             v19.16b, v24.16b
+        mov             v20.16b, v25.16b
+        bl              L(\type\()_\taps\()_filter_8)
+        mov             v21.16b, v24.16b
+        mov             v22.16b, v25.16b
+
+88:
+.ifc \taps, 6tap
+        smull           v2.4s,  v18.4h, v1.h[1]
+        smull2          v3.4s,  v18.8h, v1.h[1]
+        bl              L(\type\()_\taps\()_filter_8)
+        smull           v4.4s,  v19.4h, v1.h[1]
+        smull2          v5.4s,  v19.8h, v1.h[1]
+        smlal           v2.4s,  v19.4h, v1.h[2]
+        smlal2          v3.4s,  v19.8h, v1.h[2]
+        smlal           v4.4s,  v20.4h, v1.h[2]
+        smlal2          v5.4s,  v20.8h, v1.h[2]
+        smlal           v2.4s,  v20.4h, v1.h[3]
+        smlal2          v3.4s,  v20.8h, v1.h[3]
+        smlal           v4.4s,  v21.4h, v1.h[3]
+        smlal2          v5.4s,  v21.8h, v1.h[3]
+        smlal           v2.4s,  v21.4h, v1.h[4]
+        smlal2          v3.4s,  v21.8h, v1.h[4]
+        smlal           v4.4s,  v22.4h, v1.h[4]
+        smlal2          v5.4s,  v22.8h, v1.h[4]
+        smlal           v2.4s,  v22.4h, v1.h[5]
+        smlal2          v3.4s,  v22.8h, v1.h[5]
+        smlal           v4.4s,  v24.4h, v1.h[5]
+        smlal2          v5.4s,  v24.8h, v1.h[5]
+        smlal           v2.4s,  v24.4h, v1.h[6]
+        smlal2          v3.4s,  v24.8h, v1.h[6]
+        smlal           v4.4s,  v25.4h, v1.h[6]
+        smlal2          v5.4s,  v25.8h, v1.h[6]
+.else   // 8tap
+        smull           v2.4s,  v16.4h, v1.h[0]
+        smull2          v3.4s,  v16.8h, v1.h[0]
+        bl              L(\type\()_\taps\()_filter_8)
+        smull           v4.4s,  v17.4h, v1.h[0]
+        smull2          v5.4s,  v17.8h, v1.h[0]
+        smlal           v2.4s,  v17.4h, v1.h[1]
+        smlal2          v3.4s,  v17.8h, v1.h[1]
+        smlal           v4.4s,  v18.4h, v1.h[1]
+        smlal2          v5.4s,  v18.8h, v1.h[1]
+        smlal           v2.4s,  v18.4h, v1.h[2]
+        smlal2          v3.4s,  v18.8h, v1.h[2]
+        smlal           v4.4s,  v19.4h, v1.h[2]
+        smlal2          v5.4s,  v19.8h, v1.h[2]
+        smlal           v2.4s,  v19.4h, v1.h[3]
+        smlal2          v3.4s,  v19.8h, v1.h[3]
+        smlal           v4.4s,  v20.4h, v1.h[3]
+        smlal2          v5.4s,  v20.8h, v1.h[3]
+        smlal           v2.4s,  v20.4h, v1.h[4]
+        smlal2          v3.4s,  v20.8h, v1.h[4]
+        smlal           v4.4s,  v21.4h, v1.h[4]
+        smlal2          v5.4s,  v21.8h, v1.h[4]
+        smlal           v2.4s,  v21.4h, v1.h[5]
+        smlal2          v3.4s,  v21.8h, v1.h[5]
+        smlal           v4.4s,  v22.4h, v1.h[5]
+        smlal2          v5.4s,  v22.8h, v1.h[5]
+        smlal           v2.4s,  v22.4h, v1.h[6]
+        smlal2          v3.4s,  v22.8h, v1.h[6]
+        smlal           v4.4s,  v24.4h, v1.h[6]
+        smlal2          v5.4s,  v24.8h, v1.h[6]
+        smlal           v2.4s,  v24.4h, v1.h[7]
+        smlal2          v3.4s,  v24.8h, v1.h[7]
+        smlal           v4.4s,  v25.4h, v1.h[7]
+        smlal2          v5.4s,  v25.8h, v1.h[7]
+.endif
+        sqrshrn         v2.4h,  v2.4s,  #\shift_hv
+        sqrshrn2        v2.8h,  v3.4s,  #\shift_hv
+        sqrshrn         v4.4h,  v4.4s,  #\shift_hv
+        sqrshrn2        v4.8h,  v5.4s,  #\shift_hv
+        subs            \h,  \h,  #2
+.ifc \type, put
+        sqxtun          v2.8b,  v2.8h
+        sqxtun          v4.8b,  v4.8h
+        st1             {v2.8b}, [\dst], \d_strd
+        st1             {v4.8b}, [\ds2], \d_strd
+.else
+        st1             {v2.8h}, [\dst], \d_strd
+        st1             {v4.8h}, [\ds2], \d_strd
+.endif
+        b.le            9f
+.ifc \taps, 8tap
+        mov             v16.16b, v18.16b
+        mov             v17.16b, v19.16b
+.endif
+        mov             v18.16b, v20.16b
+        mov             v19.16b, v21.16b
+        mov             v20.16b, v22.16b
+        mov             v21.16b, v24.16b
+        mov             v22.16b, v25.16b
+        b               88b
+9:
+        subs            \w,  \w,  #8
+        b.le            0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        msub            \src,  \s_strd,  \xmy,  \src
+        msub            \dst,  \d_strd,  \xmy,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #3
+        mov             \h,  \my
+        add             \src,  \src,  #8
+.ifc \type, put
+        add             \dst,  \dst,  #8
+.else
+        add             \dst,  \dst,  #16
+.endif
+.ifc \taps, 6tap
+        add             \src,  \src,  \s_strd,  lsl #1
+.endif
+        b               168b
+0:
+        ret             x15
+
+L(\type\()_\taps\()_filter_8_first):
+        ld1             {v28.8b, v29.8b},  [\src], \s_strd
+        uxtl            v28.8h,  v28.8b
+        uxtl            v29.8h,  v29.8b
+.ifc \taps, 6tap
+        mul             v16.8h,  v28.8h,  v0.h[1]
+        ext             v25.16b, v28.16b, v29.16b, #(2*1)
+        ext             v26.16b, v28.16b, v29.16b, #(2*2)
+        ext             v27.16b, v28.16b, v29.16b, #(2*3)
+        mla             v16.8h,  v25.8h,  v0.h[2]
+        mla             v16.8h,  v26.8h,  v0.h[3]
+        mla             v16.8h,  v27.8h,  v0.h[4]
+        ext             v24.16b, v28.16b, v29.16b, #(2*4)
+        ext             v25.16b, v28.16b, v29.16b, #(2*5)
+        mla             v16.8h,  v24.8h,  v0.h[5]
+        mla             v16.8h,  v25.8h,  v0.h[6]
+.else   // 8tap
+        mul             v16.8h,  v28.8h,  v0.h[0]
+        ext             v24.16b, v28.16b, v29.16b, #(2*1)
+        ext             v25.16b, v28.16b, v29.16b, #(2*2)
+        ext             v26.16b, v28.16b, v29.16b, #(2*3)
+        ext             v27.16b, v28.16b, v29.16b, #(2*4)
+        mla             v16.8h,  v24.8h,  v0.h[1]
+        mla             v16.8h,  v25.8h,  v0.h[2]
+        mla             v16.8h,  v26.8h,  v0.h[3]
+        mla             v16.8h,  v27.8h,  v0.h[4]
+        ext             v24.16b, v28.16b, v29.16b, #(2*5)
+        ext             v25.16b, v28.16b, v29.16b, #(2*6)
+        ext             v26.16b, v28.16b, v29.16b, #(2*7)
+        mla             v16.8h,  v24.8h,  v0.h[5]
+        mla             v16.8h,  v25.8h,  v0.h[6]
+        mla             v16.8h,  v26.8h,  v0.h[7]
+.endif
+        srshr           v16.8h,  v16.8h,  #2
+        ret
+
+L(\type\()_\taps\()_filter_8):
+        ld1             {v28.8b, v29.8b},  [\sr2], \s_strd
+        ld1             {v30.8b, v31.8b},  [\src], \s_strd
+        uxtl            v28.8h,  v28.8b
+        uxtl            v29.8h,  v29.8b
+        uxtl            v30.8h,  v30.8b
+        uxtl            v31.8h,  v31.8b
+.ifc \taps, 6tap
+        mul             v24.8h,  v28.8h,  v0.h[1]
+        mul             v25.8h,  v30.8h,  v0.h[1]
+    .irpc i, 23456
+        ext             v26.16b, v28.16b, v29.16b, #(2*\i-2)
+        ext             v27.16b, v30.16b, v31.16b, #(2*\i-2)
+        mla             v24.8h,  v26.8h,  v0.h[\i]
+        mla             v25.8h,  v27.8h,  v0.h[\i]
+    .endr
+.else   // 8tap
+        mul             v24.8h,  v28.8h,  v0.h[0]
+        mul             v25.8h,  v30.8h,  v0.h[0]
+    .irpc i, 1234567
+        ext             v26.16b, v28.16b, v29.16b, #(2*\i)
+        ext             v27.16b, v30.16b, v31.16b, #(2*\i)
+        mla             v24.8h,  v26.8h,  v0.h[\i]
+        mla             v25.8h,  v27.8h,  v0.h[\i]
+    .endr
+.endif
+        srshr           v24.8h,  v24.8h, #2
+        srshr           v25.8h,  v25.8h, #2
+        ret
+endfunc
+
+jumptable \type\()_\taps\()_hv_tbl
+        .word 1280b - \type\()_\taps\()_hv_tbl
+        .word 640b  - \type\()_\taps\()_hv_tbl
+        .word 320b  - \type\()_\taps\()_hv_tbl
+        .word 160b  - \type\()_\taps\()_hv_tbl
+        .word 80b   - \type\()_\taps\()_hv_tbl
+        .word 40b   - \type\()_\taps\()_hv_tbl
+        .word 20b   - \type\()_\taps\()_hv_tbl
+endjumptable
+.endm
+
+
+.macro filter_bilin_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, ds2, sr2, shift_hv
+function \type\()_bilin_8bpc_neon, export=1
+        dup             v1.16b, \mx
+        dup             v3.16b, \my
+        mov             w9,  #16
+        sub             w8, w9, \mx
+        sub             w9, w9, \my
+        dup             v0.16b, w8
+        dup             v2.16b, w9
+.ifc \type, prep
+        uxtw            \d_strd, \w
+        lsl             \d_strd, \d_strd, #1
+.endif
+
+        clz             w8,  \w
+        sub             w8,  w8,  #24
+        cbnz            \mx, L(\type\()_bilin_h)
+        cbnz            \my, L(\type\()_bilin_v)
+        b               \type\()_neon
+
+L(\type\()_bilin_h):
+        cbnz            \my, L(\type\()_bilin_hv)
+
+        movrel          x9,  \type\()_bilin_h_tbl
+        ldrsw           x8,  [x9, x8, lsl #2]
+        add             x9,  x9,  x8
+        br              x9
+
+20:     // 2xN h
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+2:
+        ld1r            {v4.4s},  [\src], \s_strd
+        ld1r            {v6.4s},  [\sr2], \s_strd
+        ext             v5.8b,  v4.8b,  v4.8b, #1
+        ext             v7.8b,  v6.8b,  v6.8b, #1
+        trn1            v4.4h,  v4.4h,  v6.4h
+        trn1            v5.4h,  v5.4h,  v7.4h
+        subs            \h,  \h,  #2
+        umull           v4.8h,  v4.8b,  v0.8b
+        umlal           v4.8h,  v5.8b,  v1.8b
+        uqrshrn         v4.8b,  v4.8h,  #4
+        st1             {v4.h}[0], [\dst], \d_strd
+        st1             {v4.h}[1], [\ds2], \d_strd
+        b.gt            2b
+        ret
+.endif
+
+40:     // 4xN h
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+4:
+        ld1             {v4.8b}, [\src], \s_strd
+        ld1             {v6.8b}, [\sr2], \s_strd
+        ext             v5.8b,  v4.8b,  v4.8b, #1
+        ext             v7.8b,  v6.8b,  v6.8b, #1
+        trn1            v4.2s,  v4.2s,  v6.2s
+        trn1            v5.2s,  v5.2s,  v7.2s
+        subs            \h,  \h,  #2
+        umull           v4.8h,  v4.8b,  v0.8b
+        umlal           v4.8h,  v5.8b,  v1.8b
+.ifc \type, put
+        uqrshrn         v4.8b,  v4.8h,  #4
+        st1             {v4.s}[0], [\dst], \d_strd
+        st1             {v4.s}[1], [\ds2], \d_strd
+.else
+        st1             {v4.8b},   [\dst], \d_strd
+        st1             {v4.d}[1], [\ds2], \d_strd
+.endif
+        b.gt            4b
+        ret
+
+80:     // 8xN h
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+8:
+        ld1             {v4.16b}, [\src], \s_strd
+        ld1             {v6.16b}, [\sr2], \s_strd
+        ext             v5.16b, v4.16b, v4.16b, #1
+        ext             v7.16b, v6.16b, v6.16b, #1
+        subs            \h,  \h,  #2
+        umull           v4.8h,  v4.8b,  v0.8b
+        umull           v6.8h,  v6.8b,  v0.8b
+        umlal           v4.8h,  v5.8b,  v1.8b
+        umlal           v6.8h,  v7.8b,  v1.8b
+.ifc \type, put
+        uqrshrn         v4.8b,  v4.8h,  #4
+        uqrshrn         v6.8b,  v6.8h,  #4
+        st1             {v4.8b}, [\dst], \d_strd
+        st1             {v6.8b}, [\ds2], \d_strd
+.else
+        st1             {v4.8h}, [\dst], \d_strd
+        st1             {v6.8h}, [\ds2], \d_strd
+.endif
+        b.gt            8b
+        ret
+160:
+320:
+640:
+1280:   // 16xN, 32xN, ... h
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+
+        sub             \s_strd,  \s_strd,  \w, uxtw
+        sub             \s_strd,  \s_strd,  #8
+.ifc \type, put
+        lsl             \d_strd,  \d_strd,  #1
+        sub             \d_strd,  \d_strd,  \w, uxtw
+.endif
+161:
+        ld1             {v16.d}[1],  [\src], #8
+        ld1             {v20.d}[1],  [\sr2], #8
+        mov             \mx, \w
+
+16:
+        ld1             {v18.16b},  [\src], #16
+        ld1             {v22.16b},  [\sr2], #16
+        ext             v17.16b, v16.16b, v18.16b, #8
+        ext             v19.16b, v16.16b, v18.16b, #9
+        ext             v21.16b, v20.16b, v22.16b, #8
+        ext             v23.16b, v20.16b, v22.16b, #9
+        umull           v16.8h,  v17.8b,  v0.8b
+        umull2          v17.8h,  v17.16b, v0.16b
+        umull           v20.8h,  v21.8b,  v0.8b
+        umull2          v21.8h,  v21.16b, v0.16b
+        umlal           v16.8h,  v19.8b,  v1.8b
+        umlal2          v17.8h,  v19.16b, v1.16b
+        umlal           v20.8h,  v23.8b,  v1.8b
+        umlal2          v21.8h,  v23.16b, v1.16b
+        subs            \mx, \mx, #16
+.ifc \type, put
+        uqrshrn         v16.8b,  v16.8h, #4
+        uqrshrn2        v16.16b, v17.8h, #4
+        uqrshrn         v20.8b,  v20.8h, #4
+        uqrshrn2        v20.16b, v21.8h, #4
+        st1             {v16.16b}, [\dst], #16
+        st1             {v20.16b}, [\ds2], #16
+.else
+        st1             {v16.8h, v17.8h}, [\dst], #32
+        st1             {v20.8h, v21.8h}, [\ds2], #32
+.endif
+        b.le            9f
+
+        mov             v16.16b, v18.16b
+        mov             v20.16b, v22.16b
+        b               16b
+
+9:
+        add             \dst,  \dst,  \d_strd
+        add             \ds2,  \ds2,  \d_strd
+        add             \src,  \src,  \s_strd
+        add             \sr2,  \sr2,  \s_strd
+
+        subs            \h,  \h,  #2
+        b.gt            161b
+        ret
+endfunc
+
+jumptable \type\()_bilin_h_tbl
+        .word 1280b - \type\()_bilin_h_tbl
+        .word 640b  - \type\()_bilin_h_tbl
+        .word 320b  - \type\()_bilin_h_tbl
+        .word 160b  - \type\()_bilin_h_tbl
+        .word 80b   - \type\()_bilin_h_tbl
+        .word 40b   - \type\()_bilin_h_tbl
+        .word 20b   - \type\()_bilin_h_tbl
+endjumptable
+
+
+function L(\type\()_bilin_v)
+        cmp             \h,  #4
+        movrel          x9,  \type\()_bilin_v_tbl
+        ldrsw           x8,  [x9, x8, lsl #2]
+        add             x9,  x9,  x8
+        br              x9
+
+20:     // 2xN v
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        cmp             \h,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+
+        // 2x2 v
+        ld1r            {v16.8h}, [\src], \s_strd
+        b.gt            24f
+22:
+        ld1r            {v17.8h}, [\sr2], \s_strd
+        ld1r            {v18.8h}, [\src], \s_strd
+        trn1            v16.4h, v16.4h, v17.4h
+        trn1            v17.4h, v17.4h, v18.4h
+        umull           v4.8h,  v16.8b,  v2.8b
+        umlal           v4.8h,  v17.8b,  v3.8b
+        uqrshrn         v4.8b,  v4.8h,  #4
+        str             h4,        [\dst]
+        st1             {v4.h}[1], [\ds2]
+        ret
+24:     // 2x4, 2x6, 2x8, ... v
+        ld1r            {v17.8h}, [\sr2], \s_strd
+        ld1r            {v18.8h}, [\src], \s_strd
+        ld1r            {v19.8h}, [\sr2], \s_strd
+        ld1r            {v20.8h}, [\src], \s_strd
+        sub             \h,  \h,  #4
+        trn1            v16.4h, v16.4h, v17.4h
+        trn1            v17.4h, v17.4h, v18.4h
+        trn1            v18.4h, v18.4h, v19.4h
+        trn1            v19.4h, v19.4h, v20.4h
+        trn1            v16.2s, v16.2s, v18.2s
+        trn1            v17.2s, v17.2s, v19.2s
+        umull           v4.8h,  v16.8b,  v2.8b
+        umlal           v4.8h,  v17.8b,  v3.8b
+        cmp             \h,  #2
+        uqrshrn         v4.8b,  v4.8h,  #4
+        st1             {v4.h}[0], [\dst], \d_strd
+        st1             {v4.h}[1], [\ds2], \d_strd
+        st1             {v4.h}[2], [\dst], \d_strd
+        st1             {v4.h}[3], [\ds2], \d_strd
+        b.lt            0f
+        mov             v16.8b, v20.8b
+        b.eq            22b
+        b               24b
+0:
+        ret
+.endif
+
+40:     // 4xN v
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        ld1r            {v16.4s}, [\src], \s_strd
+4:
+        ld1r            {v17.4s}, [\sr2], \s_strd
+        ld1r            {v18.4s}, [\src], \s_strd
+        trn1            v16.2s, v16.2s, v17.2s
+        trn1            v17.2s, v17.2s, v18.2s
+        umull           v4.8h,  v16.8b,  v2.8b
+        umlal           v4.8h,  v17.8b,  v3.8b
+        subs            \h,  \h,  #2
+.ifc \type, put
+        uqrshrn         v4.8b,  v4.8h,  #4
+        st1             {v4.s}[0], [\dst], \d_strd
+        st1             {v4.s}[1], [\ds2], \d_strd
+.else
+        st1             {v4.8b},   [\dst], \d_strd
+        st1             {v4.d}[1], [\ds2], \d_strd
+.endif
+        b.le            0f
+        mov             v16.8b, v18.8b
+        b               4b
+0:
+        ret
+
+80:     // 8xN v
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        ld1             {v16.8b}, [\src], \s_strd
+8:
+        ld1             {v17.8b}, [\sr2], \s_strd
+        ld1             {v18.8b}, [\src], \s_strd
+        umull           v4.8h,  v16.8b,  v2.8b
+        umull           v5.8h,  v17.8b,  v2.8b
+        umlal           v4.8h,  v17.8b,  v3.8b
+        umlal           v5.8h,  v18.8b,  v3.8b
+        subs            \h,  \h,  #2
+.ifc \type, put
+        uqrshrn         v4.8b,  v4.8h,  #4
+        uqrshrn         v5.8b,  v5.8h,  #4
+        st1             {v4.8b}, [\dst], \d_strd
+        st1             {v5.8b}, [\ds2], \d_strd
+.else
+        st1             {v4.8h}, [\dst], \d_strd
+        st1             {v5.8h}, [\ds2], \d_strd
+.endif
+        b.le            0f
+        mov             v16.8b, v18.8b
+        b               8b
+0:
+        ret
+
+160:    // 16xN, 32xN, ...
+320:
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        mov             \my,  \h
+1:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        ld1             {v16.16b}, [\src], \s_strd
+2:
+        ld1             {v17.16b}, [\sr2], \s_strd
+        ld1             {v18.16b}, [\src], \s_strd
+        umull           v4.8h,  v16.8b,  v2.8b
+        umull2          v5.8h,  v16.16b, v2.16b
+        umull           v6.8h,  v17.8b,  v2.8b
+        umull2          v7.8h,  v17.16b, v2.16b
+        umlal           v4.8h,  v17.8b,  v3.8b
+        umlal2          v5.8h,  v17.16b, v3.16b
+        umlal           v6.8h,  v18.8b,  v3.8b
+        umlal2          v7.8h,  v18.16b, v3.16b
+        subs            \h,  \h,  #2
+.ifc \type, put
+        uqrshrn         v4.8b,  v4.8h,  #4
+        uqrshrn2        v4.16b, v5.8h,  #4
+        uqrshrn         v6.8b,  v6.8h,  #4
+        uqrshrn2        v6.16b, v7.8h,  #4
+        st1             {v4.16b}, [\dst], \d_strd
+        st1             {v6.16b}, [\ds2], \d_strd
+.else
+        st1             {v4.8h, v5.8h}, [\dst], \d_strd
+        st1             {v6.8h, v7.8h}, [\ds2], \d_strd
+.endif
+        b.le            9f
+        mov             v16.16b, v18.16b
+        b               2b
+9:
+        subs            \w,  \w,  #16
+        b.le            0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        msub            \src, \s_strd, \xmy, \src
+        msub            \dst, \d_strd, \xmy, \dst
+        sub             \src, \src, \s_strd, lsl #1
+        mov             \h,  \my
+        add             \src, \src, #16
+.ifc \type, put
+        add             \dst, \dst, #16
+.else
+        add             \dst, \dst, #32
+.endif
+        b               1b
+0:
+        ret
+endfunc
+
+jumptable \type\()_bilin_v_tbl
+        .word 1280b - \type\()_bilin_v_tbl
+        .word 640b  - \type\()_bilin_v_tbl
+        .word 320b  - \type\()_bilin_v_tbl
+        .word 160b  - \type\()_bilin_v_tbl
+        .word 80b   - \type\()_bilin_v_tbl
+        .word 40b   - \type\()_bilin_v_tbl
+        .word 20b   - \type\()_bilin_v_tbl
+endjumptable
+
+function L(\type\()_bilin_hv)
+        uxtl            v2.8h, v2.8b
+        uxtl            v3.8h, v3.8b
+        movrel          x9,  \type\()_bilin_hv_tbl
+        ldrsw           x8,  [x9, x8, lsl #2]
+        add             x9,  x9,  x8
+        br              x9
+
+20:     // 2xN hv
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        ld1r            {v28.4s},  [\src], \s_strd
+        ext             v29.8b, v28.8b, v28.8b, #1
+        umull           v16.8h, v28.8b, v0.8b
+        umlal           v16.8h, v29.8b, v1.8b
+
+2:
+        ld1r            {v28.4s},  [\sr2], \s_strd
+        ld1r            {v30.4s},  [\src], \s_strd
+        ext             v29.8b, v28.8b, v28.8b, #1
+        ext             v31.8b, v30.8b, v30.8b, #1
+        trn1            v28.4h, v28.4h, v30.4h
+        trn1            v29.4h, v29.4h, v31.4h
+        umull           v17.8h, v28.8b, v0.8b
+        umlal           v17.8h, v29.8b, v1.8b
+
+        trn1            v16.2s, v16.2s, v17.2s
+
+        mul             v4.4h,  v16.4h, v2.4h
+        mla             v4.4h,  v17.4h, v3.4h
+        uqrshrn         v4.8b,  v4.8h,  #8
+        subs            \h,  \h,  #2
+        st1             {v4.h}[0], [\dst], \d_strd
+        st1             {v4.h}[1], [\ds2], \d_strd
+        b.le            0f
+        trn2            v16.2s, v17.2s, v17.2s
+        b               2b
+0:
+        ret
+.endif
+
+40:     // 4xN hv
+        AARCH64_VALID_JUMP_TARGET
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        ld1             {v28.8b},  [\src], \s_strd
+        ext             v29.8b, v28.8b, v28.8b, #1
+        umull           v16.8h, v28.8b, v0.8b
+        umlal           v16.8h, v29.8b, v1.8b
+
+4:
+        ld1             {v28.8b},  [\sr2], \s_strd
+        ld1             {v30.8b},  [\src], \s_strd
+        ext             v29.8b, v28.8b, v28.8b, #1
+        ext             v31.8b, v30.8b, v30.8b, #1
+        trn1            v28.2s, v28.2s, v30.2s
+        trn1            v29.2s, v29.2s, v31.2s
+        umull           v17.8h, v28.8b, v0.8b
+        umlal           v17.8h, v29.8b, v1.8b
+
+        trn1            v16.2d, v16.2d, v17.2d
+
+        mul             v4.8h,  v16.8h, v2.8h
+        mla             v4.8h,  v17.8h, v3.8h
+        subs            \h,  \h,  #2
+.ifc \type, put
+        uqrshrn         v4.8b,  v4.8h,  #8
+        st1             {v4.s}[0], [\dst], \d_strd
+        st1             {v4.s}[1], [\ds2], \d_strd
+.else
+        urshr           v4.8h,  v4.8h,  #4
+        st1             {v4.8b},   [\dst], \d_strd
+        st1             {v4.d}[1], [\ds2], \d_strd
+.endif
+        b.le            0f
+        trn2            v16.2d, v17.2d, v17.2d
+        b               4b
+0:
+        ret
+
+80:     // 8xN, 16xN, ... hv
+160:
+320:
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        mov             \my,  \h
+
+1:
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        ld1             {v28.16b},  [\src], \s_strd
+        ext             v29.16b, v28.16b, v28.16b, #1
+        umull           v16.8h, v28.8b, v0.8b
+        umlal           v16.8h, v29.8b, v1.8b
+
+2:
+        ld1             {v28.16b},  [\sr2], \s_strd
+        ld1             {v30.16b},  [\src], \s_strd
+        ext             v29.16b, v28.16b, v28.16b, #1
+        ext             v31.16b, v30.16b, v30.16b, #1
+        umull           v17.8h, v28.8b, v0.8b
+        umlal           v17.8h, v29.8b, v1.8b
+        umull           v18.8h, v30.8b, v0.8b
+        umlal           v18.8h, v31.8b, v1.8b
+
+        mul             v4.8h,  v16.8h, v2.8h
+        mla             v4.8h,  v17.8h, v3.8h
+        mul             v5.8h,  v17.8h, v2.8h
+        mla             v5.8h,  v18.8h, v3.8h
+        subs            \h,  \h,  #2
+.ifc \type, put
+        uqrshrn         v4.8b,  v4.8h,  #8
+        uqrshrn         v5.8b,  v5.8h,  #8
+        st1             {v4.8b}, [\dst], \d_strd
+        st1             {v5.8b}, [\ds2], \d_strd
+.else
+        urshr           v4.8h,  v4.8h,  #4
+        urshr           v5.8h,  v5.8h,  #4
+        st1             {v4.8h}, [\dst], \d_strd
+        st1             {v5.8h}, [\ds2], \d_strd
+.endif
+        b.le            9f
+        mov             v16.16b, v18.16b
+        b               2b
+9:
+        subs            \w,  \w,  #8
+        b.le            0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        msub            \src,  \s_strd,  \xmy,  \src
+        msub            \dst,  \d_strd,  \xmy,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #1
+        mov             \h,  \my
+        add             \src,  \src,  #8
+.ifc \type, put
+        add             \dst,  \dst,  #8
+.else
+        add             \dst,  \dst,  #16
+.endif
+        b               1b
+0:
+        ret
+endfunc
+
+jumptable \type\()_bilin_hv_tbl
+        .word 1280b - \type\()_bilin_hv_tbl
+        .word 640b  - \type\()_bilin_hv_tbl
+        .word 320b  - \type\()_bilin_hv_tbl
+        .word 160b  - \type\()_bilin_hv_tbl
+        .word 80b   - \type\()_bilin_hv_tbl
+        .word 40b   - \type\()_bilin_hv_tbl
+        .word 20b   - \type\()_bilin_hv_tbl
+endjumptable
+.endm
+
+make_8tap_fn    put,  regular_sharp,  REGULAR, SHARP,   8tap
+make_8tap_fn    put,  smooth_sharp,   SMOOTH,  SHARP,   8tap
+make_8tap_fn    put,  sharp,          SHARP,   SHARP,   8tap
+make_8tap_fn    put,  sharp_regular,  SHARP,   REGULAR, 8tap
+make_8tap_fn    put,  sharp_smooth,   SHARP,   SMOOTH,  8tap
+filter_fn       put,  x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, x8, x9, 10, 8tap
+
+make_8tap_fn    put,  regular,        REGULAR, REGULAR, 6tap
+make_8tap_fn    put,  regular_smooth, REGULAR, SMOOTH,  6tap
+make_8tap_fn    put,  smooth,         SMOOTH,  SMOOTH,  6tap
+make_8tap_fn    put,  smooth_regular, SMOOTH,  REGULAR, 6tap
+filter_fn       put,  x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, x8, x9, 10, 6tap
+filter_bilin_fn put,  x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, x8, x9, 10
+
+make_8tap_fn    prep, regular_sharp,  REGULAR, SHARP,   8tap
+make_8tap_fn    prep, smooth_sharp,   SMOOTH,  SHARP,   8tap
+make_8tap_fn    prep, sharp,          SHARP,   SHARP,   8tap
+make_8tap_fn    prep, sharp_regular,  SHARP,   REGULAR, 8tap
+make_8tap_fn    prep, sharp_smooth,   SHARP,   SMOOTH,  8tap
+filter_fn       prep, x0, x7, x1, x2, w3, w4, w5, x5, w6, x6, x8, x9, 6,  8tap
+
+make_8tap_fn    prep, regular,        REGULAR, REGULAR, 6tap
+make_8tap_fn    prep, regular_smooth, REGULAR, SMOOTH,  6tap
+make_8tap_fn    prep, smooth,         SMOOTH,  SMOOTH,  6tap
+make_8tap_fn    prep, smooth_regular, SMOOTH,  REGULAR, 6tap
+filter_fn       prep, x0, x7, x1, x2, w3, w4, w5, x5, w6, x6, x8, x9, 6,  6tap
+filter_bilin_fn prep, x0, x7, x1, x2, w3, w4, w5, x5, w6, x6, x8, x9, 6
+
+
+.macro load_filter_row dst, src, inc
+        asr             w13, \src, #10
+        add             \src, \src, \inc
+        ldr             \dst, [x11, w13, sxtw #3]
+.endm
+
+function warp_filter_horz_neon
+        add             w12, w5,  #512
+
+        ld1             {v16.8b, v17.8b}, [x2], x3
+
+        load_filter_row d0, w12, w7
+        load_filter_row d1, w12, w7
+        load_filter_row d2, w12, w7
+        load_filter_row d3, w12, w7
+        load_filter_row d4, w12, w7
+        load_filter_row d5, w12, w7
+        load_filter_row d6, w12, w7
+        // subtract by 128 to allow using smull
+        eor             v16.8b,  v16.8b,  v22.8b
+        eor             v17.8b,  v17.8b,  v22.8b
+        load_filter_row d7, w12, w7
+
+        ext             v18.8b,  v16.8b,  v17.8b,  #1
+        ext             v19.8b,  v16.8b,  v17.8b,  #2
+        smull           v0.8h,   v0.8b,   v16.8b
+        smull           v1.8h,   v1.8b,   v18.8b
+        ext             v18.8b,  v16.8b,  v17.8b,  #3
+        ext             v20.8b,  v16.8b,  v17.8b,  #4
+        smull           v2.8h,   v2.8b,   v19.8b
+        smull           v3.8h,   v3.8b,   v18.8b
+        ext             v18.8b,  v16.8b,  v17.8b,  #5
+        ext             v19.8b,  v16.8b,  v17.8b,  #6
+        smull           v4.8h,   v4.8b,   v20.8b
+        smull           v5.8h,   v5.8b,   v18.8b
+        ext             v18.8b,  v16.8b,  v17.8b,  #7
+        smull           v6.8h,   v6.8b,   v19.8b
+        smull           v7.8h,   v7.8b,   v18.8b
+
+        addp            v0.8h,   v0.8h,   v1.8h
+        addp            v2.8h,   v2.8h,   v3.8h
+        addp            v4.8h,   v4.8h,   v5.8h
+        addp            v6.8h,   v6.8h,   v7.8h
+
+        addp            v0.8h,   v0.8h,   v2.8h
+        addp            v4.8h,   v4.8h,   v6.8h
+
+        addp            v0.8h,   v0.8h,   v4.8h
+
+        add             w5,  w5,  w8
+
+        ret
+endfunc
+
+// void dav1d_warp_affine_8x8_8bpc_neon(
+//         pixel *dst, const ptrdiff_t dst_stride,
+//         const pixel *src, const ptrdiff_t src_stride,
+//         const int16_t *const abcd, int mx, int my)
+.macro warp t, shift
+function warp_affine_8x8\t\()_8bpc_neon, export=1
+        ldr             x4,  [x4]
+        sbfx            x7,  x4, #0,  #16
+        sbfx            x8,  x4, #16, #16
+        sbfx            x9,  x4, #32, #16
+        sbfx            x4,  x4, #48, #16
+        mov             w10, #8
+        sub             x2,  x2,  x3, lsl #1
+        sub             x2,  x2,  x3
+        sub             x2,  x2,  #3
+        movrel          x11, X(mc_warp_filter), 64*8
+        mov             x15, x30
+.ifnb \t
+        lsl             x1,  x1,  #1
+.endif
+
+        movi            v22.8b,  #128
+.ifb \t
+        movi            v23.8h,  #128
+.else
+        movi            v23.8h,  #8, lsl #8
+.endif
+
+        bl              warp_filter_horz_neon
+        srshr           v24.8h,  v0.8h,  #3
+        bl              warp_filter_horz_neon
+        srshr           v25.8h,  v0.8h,  #3
+        bl              warp_filter_horz_neon
+        srshr           v26.8h,  v0.8h,  #3
+        bl              warp_filter_horz_neon
+        srshr           v27.8h,  v0.8h,  #3
+        bl              warp_filter_horz_neon
+        srshr           v28.8h,  v0.8h,  #3
+        bl              warp_filter_horz_neon
+        srshr           v29.8h,  v0.8h,  #3
+        bl              warp_filter_horz_neon
+        srshr           v30.8h,  v0.8h,  #3
+
+1:
+        add             w14, w6,  #512
+        bl              warp_filter_horz_neon
+        srshr           v31.8h,  v0.8h,  #3
+
+        load_filter_row d0, w14, w9
+        load_filter_row d1, w14, w9
+        load_filter_row d2, w14, w9
+        load_filter_row d3, w14, w9
+        load_filter_row d4, w14, w9
+        load_filter_row d5, w14, w9
+        load_filter_row d6, w14, w9
+        load_filter_row d7, w14, w9
+        transpose_8x8b_xtl v0, v1, v2, v3, v4, v5, v6, v7, sxtl
+
+        // This ordering of smull/smlal/smull2/smlal2 is highly
+        // beneficial for Cortex A53 here.
+        smull           v16.4s,  v24.4h,  v0.4h
+        smlal           v16.4s,  v25.4h,  v1.4h
+        smlal           v16.4s,  v26.4h,  v2.4h
+        smlal           v16.4s,  v27.4h,  v3.4h
+        smlal           v16.4s,  v28.4h,  v4.4h
+        smlal           v16.4s,  v29.4h,  v5.4h
+        smlal           v16.4s,  v30.4h,  v6.4h
+        smlal           v16.4s,  v31.4h,  v7.4h
+        smull2          v17.4s,  v24.8h,  v0.8h
+        smlal2          v17.4s,  v25.8h,  v1.8h
+        smlal2          v17.4s,  v26.8h,  v2.8h
+        smlal2          v17.4s,  v27.8h,  v3.8h
+        smlal2          v17.4s,  v28.8h,  v4.8h
+        smlal2          v17.4s,  v29.8h,  v5.8h
+        smlal2          v17.4s,  v30.8h,  v6.8h
+        smlal2          v17.4s,  v31.8h,  v7.8h
+
+        mov             v24.16b, v25.16b
+        mov             v25.16b, v26.16b
+        sqrshrn         v16.4h,  v16.4s,  #\shift
+        mov             v26.16b, v27.16b
+        sqrshrn2        v16.8h,  v17.4s,  #\shift
+        mov             v27.16b, v28.16b
+        mov             v28.16b, v29.16b
+        add             v16.8h,  v16.8h,  v23.8h
+.ifb \t
+        sqxtun          v16.8b,  v16.8h
+.endif
+        mov             v29.16b, v30.16b
+        mov             v30.16b, v31.16b
+        subs            w10, w10, #1
+.ifnb \t
+        st1             {v16.8h}, [x0], x1
+.else
+        st1             {v16.8b}, [x0], x1
+.endif
+
+        add             w6,  w6,  w4
+        b.gt            1b
+
+        ret             x15
+endfunc
+.endm
+
+warp  , 11
+warp t, 7
+
+// void dav1d_emu_edge_8bpc_neon(
+//         const intptr_t bw, const intptr_t bh,
+//         const intptr_t iw, const intptr_t ih,
+//         const intptr_t x, const intptr_t y,
+//         pixel *dst, const ptrdiff_t dst_stride,
+//         const pixel *ref, const ptrdiff_t ref_stride)
+function emu_edge_8bpc_neon, export=1
+        ldp             x8,  x9,  [sp]
+
+        // ref += iclip(y, 0, ih - 1) * PXSTRIDE(ref_stride)
+        // ref += iclip(x, 0, iw - 1)
+        sub             x12, x3,  #1           // ih - 1
+        cmp             x5,  x3
+        sub             x13, x2,  #1           // iw - 1
+        csel            x12, x12, x5,  ge      // min(y, ih - 1)
+        cmp             x4,  x2
+        bic             x12, x12, x12, asr #63 // max(min(y, ih - 1), 0)
+        csel            x13, x13, x4,  ge      // min(x, iw - 1)
+        bic             x13, x13, x13, asr #63 // max(min(x, iw - 1), 0)
+        madd            x8,  x12, x9,  x8      // ref += iclip() * stride
+        add             x8,  x8,  x13          // ref += iclip()
+
+        // bottom_ext = iclip(y + bh - ih, 0, bh - 1)
+        // top_ext = iclip(-y, 0, bh - 1)
+        add             x10, x5,  x1           // y + bh
+        neg             x5,  x5                // -y
+        sub             x10, x10, x3           // y + bh - ih
+        sub             x12, x1,  #1           // bh - 1
+        cmp             x10, x1
+        bic             x5,  x5,  x5,  asr #63 // max(-y, 0)
+        csel            x10, x10, x12, lt      // min(y + bh - ih, bh-1)
+        cmp             x5,  x1
+        bic             x10, x10, x10, asr #63 // max(min(y + bh - ih, bh-1), 0)
+        csel            x5,  x5,  x12, lt      // min(max(-y, 0), bh-1)
+
+        // right_ext = iclip(x + bw - iw, 0, bw - 1)
+        // left_ext = iclip(-x, 0, bw - 1)
+        add             x11, x4,  x0           // x + bw
+        neg             x4,  x4                // -x
+        sub             x11, x11, x2           // x + bw - iw
+        sub             x13, x0,  #1           // bw - 1
+        cmp             x11, x0
+        bic             x4,  x4,  x4,  asr #63 // max(-x, 0)
+        csel            x11, x11, x13, lt      // min(x + bw - iw, bw-1)
+        cmp             x4,  x0
+        bic             x11, x11, x11, asr #63 // max(min(x + bw - iw, bw-1), 0)
+        csel            x4,  x4,  x13, lt      // min(max(-x, 0), bw - 1)
+
+        // center_h = bh - top_ext - bottom_ext
+        // dst += top_ext * PXSTRIDE(dst_stride)
+        // center_w = bw - left_ext - right_ext
+        sub             x1,  x1,  x5           // bh - top_ext
+        madd            x6,  x5,  x7,  x6
+        sub             x2,  x0,  x4           // bw - left_ext
+        sub             x1,  x1,  x10          // center_h = bh - top_ext - bottom_ext
+        sub             x2,  x2,  x11          // center_w = bw - left_ext - right_ext
+
+        mov             x14, x6                // backup of dst
+
+.macro v_loop need_left, need_right
+0:
+.if \need_left
+        ld1r            {v0.16b}, [x8]
+        mov             x12, x6                // out = dst
+        mov             x3,  x4
+1:
+        subs            x3,  x3,  #16
+        st1             {v0.16b}, [x12], #16
+        b.gt            1b
+.endif
+        mov             x13, x8
+        add             x12, x6,  x4           // out = dst + left_ext
+        mov             x3,  x2
+1:
+        ld1             {v0.16b, v1.16b}, [x13], #32
+        subs            x3,  x3,  #32
+        st1             {v0.16b, v1.16b}, [x12], #32
+        b.gt            1b
+.if \need_right
+        add             x3,  x8,  x2           // in + center_w
+        sub             x3,  x3,  #1           // in + center_w - 1
+        add             x12, x6,  x4           // dst + left_ext
+        ld1r            {v0.16b}, [x3]
+        add             x12, x12, x2           // out = dst + left_ext + center_w
+        mov             x3,  x11
+1:
+        subs            x3,  x3,  #16
+        st1             {v0.16b}, [x12], #16
+        b.gt            1b
+.endif
+
+        subs            x1,  x1,  #1           // center_h--
+        add             x6,  x6,  x7
+        add             x8,  x8,  x9
+        b.gt            0b
+.endm
+
+        cbz             x4,  2f
+        // need_left
+        cbz             x11, 3f
+        // need_left + need_right
+        v_loop          1,   1
+        b               5f
+
+2:
+        // !need_left
+        cbz             x11, 4f
+        // !need_left + need_right
+        v_loop          0,   1
+        b               5f
+
+3:
+        // need_left + !need_right
+        v_loop          1,   0
+        b               5f
+
+4:
+        // !need_left + !need_right
+        v_loop          0,   0
+
+5:
+
+        cbz             x10, 3f
+        // need_bottom
+        sub             x8,  x6,  x7           // ref = dst - stride
+        mov             x4,  x0
+1:
+        ld1             {v0.16b, v1.16b}, [x8], #32
+        mov             x3,  x10
+2:
+        subs            x3,  x3,  #1
+        st1             {v0.16b, v1.16b}, [x6], x7
+        b.gt            2b
+        msub            x6,  x7,  x10,  x6     // dst -= bottom_ext * stride
+        subs            x4,  x4,  #32          // bw -= 32
+        add             x6,  x6,  #32          // dst += 32
+        b.gt            1b
+
+3:
+        cbz             x5,  3f
+        // need_top
+        msub            x6,  x7,  x5,  x14     // dst = stored_dst - top_ext * stride
+1:
+        ld1             {v0.16b, v1.16b}, [x14], #32
+        mov             x3,  x5
+2:
+        subs            x3,  x3,  #1
+        st1             {v0.16b, v1.16b}, [x6], x7
+        b.gt            2b
+        msub            x6,  x7,  x5,  x6      // dst -= top_ext * stride
+        subs            x0,  x0,  #32          // bw -= 32
+        add             x6,  x6,  #32          // dst += 32
+        b.gt            1b
+
+3:
+        ret
+endfunc
diff --git a/media/libdav1d/src/src/arm/64/mc16.S b/media/libdav1d/src/src/arm/64/mc16.S
new file mode 100644
index 0000000000..66cdfff744
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/mc16.S
@@ -0,0 +1,3833 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * Copyright © 2020, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+#define PREP_BIAS 8192
+
+.macro avg d0, d1, t0, t1, t2, t3
+        ld1             {\t0\().8h,\t1\().8h},  [x2],  32
+        ld1             {\t2\().8h,\t3\().8h},  [x3],  32
+        sqadd           \t0\().8h,  \t0\().8h,  \t2\().8h
+        sqadd           \t1\().8h,  \t1\().8h,  \t3\().8h
+        smax            \t0\().8h,  \t0\().8h,  v28.8h // -2*PREP_BIAS - 1 << intermediate_bits
+        smax            \t1\().8h,  \t1\().8h,  v28.8h // -2*PREP_BIAS - 1 << intermediate_bits
+        sqsub           \t0\().8h,  \t0\().8h,  v28.8h // -2*PREP_BIAS - 1 << intermediate_bits
+        sqsub           \t1\().8h,  \t1\().8h,  v28.8h // -2*PREP_BIAS - 1 << intermediate_bits
+        sshl            \d0\().8h,  \t0\().8h,  v29.8h // -(intermediate_bits+1)
+        sshl            \d1\().8h,  \t1\().8h,  v29.8h // -(intermediate_bits+1)
+.endm
+
+.macro w_avg d0, d1, t0, t1, t2, t3
+        ld1             {\t0\().8h,\t1\().8h},  [x2],  32
+        ld1             {\t2\().8h,\t3\().8h},  [x3],  32
+        // This difference requires a 17 bit range, and all bits are
+        // significant for the following multiplication.
+        ssubl           \d0\().4s,  \t2\().4h,  \t0\().4h
+        ssubl2          \t0\().4s,  \t2\().8h,  \t0\().8h
+        ssubl           \d1\().4s,  \t3\().4h,  \t1\().4h
+        ssubl2          \t1\().4s,  \t3\().8h,  \t1\().8h
+        mul             \d0\().4s,  \d0\().4s,  v27.4s
+        mul             \t0\().4s,  \t0\().4s,  v27.4s
+        mul             \d1\().4s,  \d1\().4s,  v27.4s
+        mul             \t1\().4s,  \t1\().4s,  v27.4s
+        sshr            \d0\().4s,  \d0\().4s,  #4
+        sshr            \t0\().4s,  \t0\().4s,  #4
+        sshr            \d1\().4s,  \d1\().4s,  #4
+        sshr            \t1\().4s,  \t1\().4s,  #4
+        saddw           \d0\().4s,  \d0\().4s,  \t2\().4h
+        saddw2          \t0\().4s,  \t0\().4s,  \t2\().8h
+        saddw           \d1\().4s,  \d1\().4s,  \t3\().4h
+        saddw2          \t1\().4s,  \t1\().4s,  \t3\().8h
+        uzp1            \d0\().8h,  \d0\().8h,  \t0\().8h // Same as xtn, xtn2
+        uzp1            \d1\().8h,  \d1\().8h,  \t1\().8h // Ditto
+        srshl           \d0\().8h,  \d0\().8h,  v29.8h // -intermediate_bits
+        srshl           \d1\().8h,  \d1\().8h,  v29.8h // -intermediate_bits
+        add             \d0\().8h,  \d0\().8h,  v28.8h // PREP_BIAS >> intermediate_bits
+        add             \d1\().8h,  \d1\().8h,  v28.8h // PREP_BIAS >> intermediate_bits
+        smin            \d0\().8h,  \d0\().8h,  v31.8h // bitdepth_max
+        smin            \d1\().8h,  \d1\().8h,  v31.8h // bitdepth_max
+        smax            \d0\().8h,  \d0\().8h,  v30.8h // 0
+        smax            \d1\().8h,  \d1\().8h,  v30.8h // 0
+.endm
+
+.macro mask d0, d1, t0, t1, t2, t3
+        ld1             {v27.16b}, [x6],  16
+        ld1             {\t0\().8h,\t1\().8h},  [x2],  32
+        neg             v27.16b, v27.16b
+        ld1             {\t2\().8h,\t3\().8h},  [x3],  32
+        sxtl            v26.8h,  v27.8b
+        sxtl2           v27.8h,  v27.16b
+        sxtl            v24.4s,  v26.4h
+        sxtl2           v25.4s,  v26.8h
+        sxtl            v26.4s,  v27.4h
+        sxtl2           v27.4s,  v27.8h
+        ssubl           \d0\().4s,  \t2\().4h,  \t0\().4h
+        ssubl2          \t0\().4s,  \t2\().8h,  \t0\().8h
+        ssubl           \d1\().4s,  \t3\().4h,  \t1\().4h
+        ssubl2          \t1\().4s,  \t3\().8h,  \t1\().8h
+        mul             \d0\().4s,  \d0\().4s,  v24.4s
+        mul             \t0\().4s,  \t0\().4s,  v25.4s
+        mul             \d1\().4s,  \d1\().4s,  v26.4s
+        mul             \t1\().4s,  \t1\().4s,  v27.4s
+        sshr            \d0\().4s,  \d0\().4s,  #6
+        sshr            \t0\().4s,  \t0\().4s,  #6
+        sshr            \d1\().4s,  \d1\().4s,  #6
+        sshr            \t1\().4s,  \t1\().4s,  #6
+        saddw           \d0\().4s,  \d0\().4s,  \t2\().4h
+        saddw2          \t0\().4s,  \t0\().4s,  \t2\().8h
+        saddw           \d1\().4s,  \d1\().4s,  \t3\().4h
+        saddw2          \t1\().4s,  \t1\().4s,  \t3\().8h
+        uzp1            \d0\().8h,  \d0\().8h,  \t0\().8h  // Same as xtn, xtn2
+        uzp1            \d1\().8h,  \d1\().8h,  \t1\().8h  // Ditto
+        srshl           \d0\().8h,  \d0\().8h,  v29.8h // -intermediate_bits
+        srshl           \d1\().8h,  \d1\().8h,  v29.8h // -intermediate_bits
+        add             \d0\().8h,  \d0\().8h,  v28.8h // PREP_BIAS >> intermediate_bits
+        add             \d1\().8h,  \d1\().8h,  v28.8h // PREP_BIAS >> intermediate_bits
+        smin            \d0\().8h,  \d0\().8h,  v31.8h // bitdepth_max
+        smin            \d1\().8h,  \d1\().8h,  v31.8h // bitdepth_max
+        smax            \d0\().8h,  \d0\().8h,  v30.8h // 0
+        smax            \d1\().8h,  \d1\().8h,  v30.8h // 0
+.endm
+
+.macro bidir_fn type, bdmax
+function \type\()_16bpc_neon, export=1
+        clz             w4,  w4
+.ifnc \type, avg
+        dup             v31.8h,  \bdmax // bitdepth_max
+        movi            v30.8h,  #0
+.endif
+        clz             w7,  \bdmax
+        sub             w7,  w7,  #18   // intermediate_bits = clz(bitdepth_max) - 18
+.ifc \type, avg
+        mov             w9,  #1
+        mov             w8,  #-2*PREP_BIAS
+        lsl             w9,  w9,  w7    // 1 << intermediate_bits
+        add             w7,  w7,  #1
+        sub             w8,  w8,  w9    // -2*PREP_BIAS - 1 << intermediate_bits
+        neg             w7,  w7         // -(intermediate_bits+1)
+        dup             v28.8h,   w8    // -2*PREP_BIAS - 1 << intermediate_bits
+        dup             v29.8h,   w7    // -(intermediate_bits+1)
+.else
+        mov             w8,  #PREP_BIAS
+        lsr             w8,  w8,  w7    // PREP_BIAS >> intermediate_bits
+        neg             w7,  w7         // -intermediate_bits
+        dup             v28.8h,  w8     // PREP_BIAS >> intermediate_bits
+        dup             v29.8h,  w7     // -intermediate_bits
+.endif
+.ifc \type, w_avg
+        dup             v27.4s,  w6
+        neg             v27.4s,  v27.4s
+.endif
+        movrel          x7,  \type\()_tbl
+        sub             w4,  w4,  #24
+        \type           v4,  v5,  v0,  v1,  v2,  v3
+        ldrsw           x4,  [x7, x4, lsl #2]
+        add             x7,  x7,  x4
+        br              x7
+40:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  x1
+        lsl             x1,  x1,  #1
+4:
+        subs            w5,  w5,  #4
+        st1             {v4.8b},    [x0], x1
+        st1             {v4.d}[1],  [x7], x1
+        st1             {v5.8b},    [x0], x1
+        st1             {v5.d}[1],  [x7], x1
+        b.le            0f
+        \type           v4,  v5,  v0,  v1,  v2,  v3
+        b               4b
+80:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  x1
+        lsl             x1,  x1,  #1
+8:
+        st1             {v4.8h},  [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v5.8h},  [x7], x1
+        b.le            0f
+        \type           v4,  v5,  v0,  v1,  v2,  v3
+        b               8b
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        \type           v6,  v7,  v0,  v1,  v2,  v3
+        st1             {v4.8h, v5.8h}, [x0], x1
+        subs            w5,  w5,  #2
+        st1             {v6.8h, v7.8h}, [x0], x1
+        b.le            0f
+        \type           v4,  v5,  v0,  v1,  v2,  v3
+        b               16b
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        \type           v6,  v7,  v0,  v1,  v2,  v3
+        subs            w5,  w5,  #1
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h},  [x0], x1
+        b.le            0f
+        \type           v4,  v5,  v0,  v1,  v2,  v3
+        b               32b
+640:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  #64
+64:
+        \type           v6,  v7,  v0,  v1,  v2,  v3
+        \type           v16, v17, v0,  v1,  v2,  v3
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h},  [x0], x1
+        \type           v18, v19, v0,  v1,  v2,  v3
+        subs            w5,  w5,  #1
+        st1             {v16.8h,v17.8h,v18.8h,v19.8h}, [x7], x1
+        b.le            0f
+        \type           v4,  v5,  v0,  v1,  v2,  v3
+        b               64b
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        add             x7,  x0,  #64
+        mov             x8,  #128
+        sub             x1,  x1,  #128
+128:
+        \type           v6,  v7,  v0,  v1,  v2,  v3
+        \type           v16, v17, v0,  v1,  v2,  v3
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h},  [x0], x8
+        \type           v18, v19, v0,  v1,  v2,  v3
+        st1             {v16.8h,v17.8h,v18.8h,v19.8h}, [x7], x8
+        \type           v4,  v5,  v0,  v1,  v2,  v3
+        \type           v6,  v7,  v0,  v1,  v2,  v3
+        \type           v16, v17, v0,  v1,  v2,  v3
+        subs            w5,  w5,  #1
+        st1             {v4.8h, v5.8h, v6.8h, v7.8h},  [x0], x1
+        \type           v18, v19, v0,  v1,  v2,  v3
+        st1             {v16.8h,v17.8h,v18.8h,v19.8h}, [x7], x1
+        b.le            0f
+        \type           v4,  v5,  v0,  v1,  v2,  v3
+        b               128b
+0:
+        ret
+endfunc
+
+jumptable \type\()_tbl
+        .word 1280b - \type\()_tbl
+        .word 640b  - \type\()_tbl
+        .word 320b  - \type\()_tbl
+        .word 160b  - \type\()_tbl
+        .word 80b   - \type\()_tbl
+        .word 40b   - \type\()_tbl
+endjumptable
+.endm
+
+bidir_fn avg, w6
+bidir_fn w_avg, w7
+bidir_fn mask, w7
+
+
+.macro w_mask_fn type
+function w_mask_\type\()_16bpc_neon, export=1
+        ldr             w8,  [sp]
+        clz             w9,  w4
+        movrel          x10, w_mask_\type\()_tbl
+        dup             v31.8h,  w8   // bitdepth_max
+        sub             w9,  w9,  #24
+        clz             w8,  w8       // clz(bitdepth_max)
+        ldrsw           x9,  [x10,  x9,  lsl #2]
+        add             x10, x10, x9
+        sub             w8,  w8,  #12 // sh = intermediate_bits + 6 = clz(bitdepth_max) - 12
+        mov             w9,  #PREP_BIAS*64
+        neg             w8,  w8       // -sh
+        mov             w11, #27615   // (64 + 1 - 38)<> mask_sh
+        ushr            v21.8h,  v21.8h,  #10
+        add             v4.4s,   v4.4s,   v30.4s  // += PREP_BIAS*64
+        add             v5.4s,   v5.4s,   v30.4s
+        add             v6.4s,   v6.4s,   v30.4s
+        add             v7.4s,   v7.4s,   v30.4s
+        uxtl            v22.4s,  v20.4h
+        uxtl2           v23.4s,  v20.8h
+        uxtl            v24.4s,  v21.4h
+        uxtl2           v25.4s,  v21.8h
+        mla             v4.4s,   v16.4s,  v22.4s  // (tmp2-tmp1)*(64-m)
+        mla             v5.4s,   v17.4s,  v23.4s
+        mla             v6.4s,   v18.4s,  v24.4s
+        mla             v7.4s,   v19.4s,  v25.4s
+        srshl           v4.4s,   v4.4s,   v29.4s  // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
+        srshl           v5.4s,   v5.4s,   v29.4s
+        srshl           v6.4s,   v6.4s,   v29.4s
+        srshl           v7.4s,   v7.4s,   v29.4s
+        sqxtun          v4.4h,   v4.4s            // iclip_pixel
+        sqxtun2         v4.8h,   v5.4s
+        sqxtun          v5.4h,   v6.4s
+        sqxtun2         v5.8h,   v7.4s
+        umin            v4.8h,   v4.8h,   v31.8h  // iclip_pixel
+        umin            v5.8h,   v5.8h,   v31.8h
+.if \type == 444
+        uzp1            v20.16b, v20.16b, v21.16b // 64 - m
+        sub             v20.16b, v1.16b,  v20.16b // m
+        st1             {v20.16b}, [x6], #16
+.elseif \type == 422
+        addp            v20.8h,  v20.8h,  v21.8h  // (64 - m) + (64 - n) (column wise addition)
+        xtn             v20.8b,  v20.8h
+        uhsub           v20.8b,  v3.8b,   v20.8b  // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
+        st1             {v20.8b}, [x6], #8
+.elseif \type == 420
+        trn1            v24.2d,  v20.2d,  v21.2d
+        trn2            v25.2d,  v20.2d,  v21.2d
+        add             v24.8h,  v24.8h,  v25.8h  // (64 - my1) + (64 - my2) (row wise addition)
+        addp            v20.8h,  v24.8h,  v24.8h  // (128 - m) + (128 - n) (column wise addition)
+        sub             v20.4h,  v3.4h,   v20.4h  // (256 - sign) - ((128 - m) + (128 - n))
+        rshrn           v20.8b,  v20.8h,  #2      // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        str             s20,        [x6],  #4
+.endif
+        st1             {v4.8b},    [x0],  x1
+        st1             {v4.d}[1],  [x12], x1
+        st1             {v5.8b},    [x0],  x1
+        st1             {v5.d}[1],  [x12], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ld1             {v4.8h, v5.8h}, [x2], #32 // tmp1
+        ld1             {v6.8h, v7.8h}, [x3], #32 // tmp2
+        subs            w5,  w5,  #2
+        sabd            v20.8h,  v4.8h,   v6.8h   // abs(tmp1 - tmp2)
+        sabd            v21.8h,  v5.8h,   v7.8h
+        ssubl           v16.4s,  v6.4h,   v4.4h   // tmp2 - tmp1 (requires 17 bit)
+        ssubl2          v17.4s,  v6.8h,   v4.8h
+        ssubl           v18.4s,  v7.4h,   v5.4h
+        ssubl2          v19.4s,  v7.8h,   v5.8h
+        uqsub           v20.8h,  v0.8h,   v20.8h  // 27615 - abs()
+        uqsub           v21.8h,  v0.8h,   v21.8h
+        sshll2          v7.4s,   v5.8h,   #6      // tmp1 << 6
+        sshll           v6.4s,   v5.4h,   #6
+        sshll2          v5.4s,   v4.8h,   #6
+        sshll           v4.4s,   v4.4h,   #6
+        ushr            v20.8h,  v20.8h,  #10     // 64-m = (27615 - abs()) >> mask_sh
+        ushr            v21.8h,  v21.8h,  #10
+        add             v4.4s,   v4.4s,   v30.4s  // += PREP_BIAS*64
+        add             v5.4s,   v5.4s,   v30.4s
+        add             v6.4s,   v6.4s,   v30.4s
+        add             v7.4s,   v7.4s,   v30.4s
+        uxtl            v22.4s,  v20.4h
+        uxtl2           v23.4s,  v20.8h
+        uxtl            v24.4s,  v21.4h
+        uxtl2           v25.4s,  v21.8h
+        mla             v4.4s,   v16.4s,  v22.4s  // (tmp2-tmp1)*(64-m)
+        mla             v5.4s,   v17.4s,  v23.4s
+        mla             v6.4s,   v18.4s,  v24.4s
+        mla             v7.4s,   v19.4s,  v25.4s
+        srshl           v4.4s,   v4.4s,   v29.4s  // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
+        srshl           v5.4s,   v5.4s,   v29.4s
+        srshl           v6.4s,   v6.4s,   v29.4s
+        srshl           v7.4s,   v7.4s,   v29.4s
+        sqxtun          v4.4h,   v4.4s            // iclip_pixel
+        sqxtun2         v4.8h,   v5.4s
+        sqxtun          v5.4h,   v6.4s
+        sqxtun2         v5.8h,   v7.4s
+        umin            v4.8h,   v4.8h,   v31.8h  // iclip_pixel
+        umin            v5.8h,   v5.8h,   v31.8h
+.if \type == 444
+        uzp1            v20.16b, v20.16b, v21.16b // 64 - m
+        sub             v20.16b, v1.16b,  v20.16b // m
+        st1             {v20.16b}, [x6], #16
+.elseif \type == 422
+        addp            v20.8h,  v20.8h,  v21.8h  // (64 - m) + (64 - n) (column wise addition)
+        xtn             v20.8b,  v20.8h
+        uhsub           v20.8b,  v3.8b,   v20.8b  // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
+        st1             {v20.8b}, [x6], #8
+.elseif \type == 420
+        add             v20.8h,  v20.8h,  v21.8h  // (64 - my1) + (64 - my2) (row wise addition)
+        addp            v20.8h,  v20.8h,  v20.8h  // (128 - m) + (128 - n) (column wise addition)
+        sub             v20.4h,  v3.4h,   v20.4h  // (256 - sign) - ((128 - m) + (128 - n))
+        rshrn           v20.8b,  v20.8h,  #2      // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        str             s20,     [x6],  #4
+.endif
+        st1             {v4.8h}, [x0],  x1
+        st1             {v5.8h}, [x12], x1
+        b.gt            8b
+        ret
+1280:
+640:
+320:
+160:
+        AARCH64_VALID_JUMP_TARGET
+        mov             w11, w4
+        sub             x1,  x1,  w4,  uxtw #1
+.if \type == 444
+        add             x10, x6,  w4,  uxtw
+.elseif \type == 422
+        add             x10, x6,  x11, lsr #1
+.endif
+        add             x9,  x3,  w4,  uxtw #1
+        add             x7,  x2,  w4,  uxtw #1
+161:
+        mov             w8,  w4
+16:
+        ld1             {v4.8h,   v5.8h},  [x2], #32 // tmp1
+        ld1             {v16.8h,  v17.8h}, [x3], #32 // tmp2
+        ld1             {v6.8h,   v7.8h},  [x7], #32
+        ld1             {v18.8h,  v19.8h}, [x9], #32
+        subs            w8,  w8,  #16
+        sabd            v20.8h,  v4.8h,   v16.8h  // abs(tmp1 - tmp2)
+        sabd            v21.8h,  v5.8h,   v17.8h
+        ssubl           v22.4s,  v16.4h,  v4.4h   // tmp2 - tmp1 (requires 17 bit)
+        ssubl2          v23.4s,  v16.8h,  v4.8h
+        ssubl           v24.4s,  v17.4h,  v5.4h
+        ssubl2          v25.4s,  v17.8h,  v5.8h
+        uqsub           v20.8h,  v0.8h,   v20.8h  // 27615 - abs()
+        uqsub           v21.8h,  v0.8h,   v21.8h
+        sshll2          v27.4s,  v5.8h,   #6      // tmp1 << 6
+        sshll           v26.4s,  v5.4h,   #6
+        sshll2          v5.4s,   v4.8h,   #6
+        sshll           v4.4s,   v4.4h,   #6
+        ushr            v20.8h,  v20.8h,  #10     // 64-m = (27615 - abs()) >> mask_sh
+        ushr            v21.8h,  v21.8h,  #10
+        add             v4.4s,   v4.4s,   v30.4s  // += PREP_BIAS*64
+        add             v5.4s,   v5.4s,   v30.4s
+        add             v26.4s,  v26.4s,  v30.4s
+        add             v27.4s,  v27.4s,  v30.4s
+        uxtl            v16.4s,  v20.4h
+        uxtl2           v17.4s,  v20.8h
+        uxtl            v28.4s,  v21.4h
+        mla             v4.4s,   v22.4s,  v16.4s  // (tmp2-tmp1)*(64-m)
+        uxtl2           v16.4s,  v21.8h
+        mla             v5.4s,   v23.4s,  v17.4s
+        mla             v26.4s,  v24.4s,  v28.4s
+        mla             v27.4s,  v25.4s,  v16.4s
+        srshl           v4.4s,   v4.4s,   v29.4s  // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
+        srshl           v5.4s,   v5.4s,   v29.4s
+        srshl           v26.4s,  v26.4s,  v29.4s
+        srshl           v27.4s,  v27.4s,  v29.4s
+        sqxtun          v4.4h,   v4.4s            // iclip_pixel
+        sqxtun2         v4.8h,   v5.4s
+        sqxtun          v5.4h,   v26.4s
+        sqxtun2         v5.8h,   v27.4s
+
+        // Start of other half
+        sabd            v22.8h,  v6.8h,   v18.8h  // abs(tmp1 - tmp2)
+        sabd            v23.8h,  v7.8h,   v19.8h
+
+        umin            v4.8h,   v4.8h,   v31.8h  // iclip_pixel
+        umin            v5.8h,   v5.8h,   v31.8h
+
+        ssubl           v16.4s,  v18.4h,  v6.4h   // tmp2 - tmp1 (requires 17 bit)
+        ssubl2          v17.4s,  v18.8h,  v6.8h
+        ssubl           v18.4s,  v19.4h,  v7.4h
+        ssubl2          v19.4s,  v19.8h,  v7.8h
+        uqsub           v22.8h,  v0.8h,   v22.8h  // 27615 - abs()
+        uqsub           v23.8h,  v0.8h,   v23.8h
+        sshll           v24.4s,  v6.4h,   #6      // tmp1 << 6
+        sshll2          v25.4s,  v6.8h,   #6
+        sshll           v26.4s,  v7.4h,   #6
+        sshll2          v27.4s,  v7.8h,   #6
+        ushr            v22.8h,  v22.8h,  #10     // 64-m = (27615 - abs()) >> mask_sh
+        ushr            v23.8h,  v23.8h,  #10
+        add             v24.4s,  v24.4s,  v30.4s  // += PREP_BIAS*64
+        add             v25.4s,  v25.4s,  v30.4s
+        add             v26.4s,  v26.4s,  v30.4s
+        add             v27.4s,  v27.4s,  v30.4s
+        uxtl            v6.4s,   v22.4h
+        uxtl2           v7.4s,   v22.8h
+        uxtl            v28.4s,  v23.4h
+        mla             v24.4s,  v16.4s,  v6.4s   // (tmp2-tmp1)*(64-m)
+        uxtl2           v6.4s,   v23.8h
+        mla             v25.4s,  v17.4s,  v7.4s
+        mla             v26.4s,  v18.4s,  v28.4s
+        mla             v27.4s,  v19.4s,  v6.4s
+        srshl           v24.4s,  v24.4s,  v29.4s  // (tmp1<<6 + (tmp2-tmp1)*(64-m) + (1 << (sh-1)) + PREP_BIAS*64) >> sh
+        srshl           v25.4s,  v25.4s,  v29.4s
+        srshl           v26.4s,  v26.4s,  v29.4s
+        srshl           v27.4s,  v27.4s,  v29.4s
+        sqxtun          v6.4h,   v24.4s           // iclip_pixel
+        sqxtun2         v6.8h,   v25.4s
+        sqxtun          v7.4h,   v26.4s
+        sqxtun2         v7.8h,   v27.4s
+        umin            v6.8h,   v6.8h,   v31.8h  // iclip_pixel
+        umin            v7.8h,   v7.8h,   v31.8h
+.if \type == 444
+        uzp1            v20.16b, v20.16b, v21.16b // 64 - m
+        uzp1            v21.16b, v22.16b, v23.16b
+        sub             v20.16b, v1.16b,  v20.16b // m
+        sub             v21.16b, v1.16b,  v21.16b
+        st1             {v20.16b}, [x6],  #16
+        st1             {v21.16b}, [x10], #16
+.elseif \type == 422
+        addp            v20.8h,  v20.8h,  v21.8h  // (64 - m) + (64 - n) (column wise addition)
+        addp            v21.8h,  v22.8h,  v23.8h
+        xtn             v20.8b,  v20.8h
+        xtn             v21.8b,  v21.8h
+        uhsub           v20.8b,  v3.8b,   v20.8b  // ((129 - sign) - ((64 - m) + (64 - n)) >> 1
+        uhsub           v21.8b,  v3.8b,   v21.8b
+        st1             {v20.8b}, [x6],  #8
+        st1             {v21.8b}, [x10], #8
+.elseif \type == 420
+        add             v20.8h,  v20.8h,  v22.8h  // (64 - my1) + (64 - my2) (row wise addition)
+        add             v21.8h,  v21.8h,  v23.8h
+        addp            v20.8h,  v20.8h,  v21.8h  // (128 - m) + (128 - n) (column wise addition)
+        sub             v20.8h,  v3.8h,   v20.8h  // (256 - sign) - ((128 - m) + (128 - n))
+        rshrn           v20.8b,  v20.8h,  #2      // ((256 - sign) - ((128 - m) + (128 - n)) + 2) >> 2
+        st1             {v20.8b}, [x6], #8
+.endif
+        st1             {v4.8h, v5.8h}, [x0],  #32
+        st1             {v6.8h, v7.8h}, [x12], #32
+        b.gt            16b
+        subs            w5,  w5,  #2
+        add             x2,  x2,  w4,  uxtw #1
+        add             x3,  x3,  w4,  uxtw #1
+        add             x7,  x7,  w4,  uxtw #1
+        add             x9,  x9,  w4,  uxtw #1
+.if \type == 444
+        add             x6,  x6,  w4,  uxtw
+        add             x10, x10, w4,  uxtw
+.elseif \type == 422
+        add             x6,  x6,  x11, lsr #1
+        add             x10, x10, x11, lsr #1
+.endif
+        add             x0,  x0,  x1
+        add             x12, x12, x1
+        b.gt            161b
+        ret
+endfunc
+
+jumptable w_mask_\type\()_tbl
+        .word 1280b - w_mask_\type\()_tbl
+        .word 640b  - w_mask_\type\()_tbl
+        .word 320b  - w_mask_\type\()_tbl
+        .word 160b  - w_mask_\type\()_tbl
+        .word 80b   - w_mask_\type\()_tbl
+        .word 40b   - w_mask_\type\()_tbl
+endjumptable
+.endm
+
+w_mask_fn 444
+w_mask_fn 422
+w_mask_fn 420
+
+
+function blend_16bpc_neon, export=1
+        movrel          x6,  blend_tbl
+        clz             w3,  w3
+        sub             w3,  w3,  #26
+        ldrsw           x3,  [x6,  x3,  lsl #2]
+        add             x6,  x6,  x3
+        add             x8,  x0,  x1
+        br              x6
+40:
+        AARCH64_VALID_JUMP_TARGET
+        lsl             x1,  x1,  #1
+4:
+        ld1             {v2.8b},   [x5], #8
+        ld1             {v1.8h},   [x2], #16
+        ldr             d0,        [x0]
+        neg             v2.8b,   v2.8b            // -m
+        subs            w4,  w4,  #2
+        ld1             {v0.d}[1], [x8]
+        sxtl            v2.8h,   v2.8b
+        shl             v2.8h,   v2.8h,   #9      // -m << 9
+        sub             v1.8h,   v0.8h,   v1.8h   // a - b
+        sqrdmulh        v1.8h,   v1.8h,   v2.8h   // ((a-b)*-m + 32) >> 6
+        add             v0.8h,   v0.8h,   v1.8h
+        st1             {v0.8b},   [x0], x1
+        st1             {v0.d}[1], [x8], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        lsl             x1,  x1,  #1
+8:
+        ld1             {v4.16b},       [x5], #16
+        ld1             {v2.8h, v3.8h}, [x2], #32
+        neg             v5.16b,  v4.16b           // -m
+        ld1             {v0.8h},   [x0]
+        ld1             {v1.8h},   [x8]
+        sxtl            v4.8h,   v5.8b
+        sxtl2           v5.8h,   v5.16b
+        shl             v4.8h,   v4.8h,   #9      // -m << 9
+        shl             v5.8h,   v5.8h,   #9
+        sub             v2.8h,   v0.8h,   v2.8h   // a - b
+        sub             v3.8h,   v1.8h,   v3.8h
+        subs            w4,  w4,  #2
+        sqrdmulh        v2.8h,   v2.8h,   v4.8h   // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v3.8h,   v3.8h,   v5.8h
+        add             v0.8h,   v0.8h,   v2.8h
+        add             v1.8h,   v1.8h,   v3.8h
+        st1             {v0.8h}, [x0], x1
+        st1             {v1.8h}, [x8], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        lsl             x1,  x1,  #1
+16:
+        ld1             {v16.16b, v17.16b},           [x5], #32
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2], #64
+        subs            w4,  w4,  #2
+        neg             v18.16b, v16.16b          // -m
+        neg             v19.16b, v17.16b
+        ld1             {v0.8h, v1.8h}, [x0]
+        sxtl            v16.8h,  v18.8b
+        sxtl2           v17.8h,  v18.16b
+        sxtl            v18.8h,  v19.8b
+        sxtl2           v19.8h,  v19.16b
+        ld1             {v2.8h, v3.8h}, [x8]
+        shl             v16.8h,  v16.8h,  #9      // -m << 9
+        shl             v17.8h,  v17.8h,  #9
+        shl             v18.8h,  v18.8h,  #9
+        shl             v19.8h,  v19.8h,  #9
+        sub             v4.8h,   v0.8h,   v4.8h   // a - b
+        sub             v5.8h,   v1.8h,   v5.8h
+        sub             v6.8h,   v2.8h,   v6.8h
+        sub             v7.8h,   v3.8h,   v7.8h
+        sqrdmulh        v4.8h,   v4.8h,   v16.8h  // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v5.8h,   v5.8h,   v17.8h
+        sqrdmulh        v6.8h,   v6.8h,   v18.8h
+        sqrdmulh        v7.8h,   v7.8h,   v19.8h
+        add             v0.8h,   v0.8h,   v4.8h
+        add             v1.8h,   v1.8h,   v5.8h
+        add             v2.8h,   v2.8h,   v6.8h
+        add             v3.8h,   v3.8h,   v7.8h
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v2.8h, v3.8h}, [x8], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ld1             {v16.16b, v17.16b},           [x5], #32
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2], #64
+        subs            w4,  w4,  #1
+        neg             v18.16b, v16.16b          // -m
+        neg             v19.16b, v17.16b
+        sxtl            v16.8h,  v18.8b
+        sxtl2           v17.8h,  v18.16b
+        sxtl            v18.8h,  v19.8b
+        sxtl2           v19.8h,  v19.16b
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0]
+        shl             v16.8h,  v16.8h,  #9      // -m << 9
+        shl             v17.8h,  v17.8h,  #9
+        shl             v18.8h,  v18.8h,  #9
+        shl             v19.8h,  v19.8h,  #9
+        sub             v4.8h,   v0.8h,   v4.8h   // a - b
+        sub             v5.8h,   v1.8h,   v5.8h
+        sub             v6.8h,   v2.8h,   v6.8h
+        sub             v7.8h,   v3.8h,   v7.8h
+        sqrdmulh        v4.8h,   v4.8h,   v16.8h  // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v5.8h,   v5.8h,   v17.8h
+        sqrdmulh        v6.8h,   v6.8h,   v18.8h
+        sqrdmulh        v7.8h,   v7.8h,   v19.8h
+        add             v0.8h,   v0.8h,   v4.8h
+        add             v1.8h,   v1.8h,   v5.8h
+        add             v2.8h,   v2.8h,   v6.8h
+        add             v3.8h,   v3.8h,   v7.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], x1
+        b.gt            32b
+        ret
+endfunc
+
+jumptable blend_tbl
+        .word 320b - blend_tbl
+        .word 160b - blend_tbl
+        .word 80b  - blend_tbl
+        .word 40b  - blend_tbl
+endjumptable
+
+function blend_h_16bpc_neon, export=1
+        movrel          x6,  blend_h_tbl
+        movrel          x5,  X(obmc_masks)
+        add             x5,  x5,  w4,  uxtw
+        sub             w4,  w4,  w4,  lsr #2
+        clz             w7,  w3
+        add             x8,  x0,  x1
+        lsl             x1,  x1,  #1
+        sub             w7,  w7,  #24
+        ldrsw           x7,  [x6,  x7,  lsl #2]
+        add             x6,  x6,  x7
+        br              x6
+20:
+        AARCH64_VALID_JUMP_TARGET
+2:
+        ld2r            {v2.8b, v3.8b}, [x5], #2
+        ld1             {v1.4h},        [x2], #8
+        ext             v2.8b,   v2.8b,   v3.8b,   #6
+        subs            w4,  w4,  #2
+        neg             v2.8b,   v2.8b            // -m
+        ldr             s0,        [x0]
+        ld1             {v0.s}[1], [x8]
+        sxtl            v2.8h,   v2.8b
+        shl             v2.4h,   v2.4h,   #9      // -m << 9
+        sub             v1.4h,   v0.4h,   v1.4h   // a - b
+        sqrdmulh        v1.4h,   v1.4h,   v2.4h   // ((a-b)*-m + 32) >> 6
+        add             v0.4h,   v0.4h,   v1.4h
+        st1             {v0.s}[0], [x0], x1
+        st1             {v0.s}[1], [x8], x1
+        b.gt            2b
+        ret
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ld2r            {v2.8b, v3.8b}, [x5], #2
+        ld1             {v1.8h},        [x2], #16
+        ext             v2.8b,   v2.8b,   v3.8b,   #4
+        subs            w4,  w4,  #2
+        neg             v2.8b,   v2.8b            // -m
+        ldr             d0,          [x0]
+        ld1             {v0.d}[1],   [x8]
+        sxtl            v2.8h,   v2.8b
+        shl             v2.8h,   v2.8h,   #9      // -m << 9
+        sub             v1.8h,   v0.8h,   v1.8h   // a - b
+        sqrdmulh        v1.8h,   v1.8h,   v2.8h   // ((a-b)*-m + 32) >> 6
+        add             v0.8h,   v0.8h,   v1.8h
+        st1             {v0.8b},   [x0], x1
+        st1             {v0.d}[1], [x8], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+8:
+        ld2r            {v4.8b, v5.8b}, [x5], #2
+        ld1             {v2.8h, v3.8h}, [x2], #32
+        neg             v4.8b,   v4.8b            // -m
+        neg             v5.8b,   v5.8b
+        ld1             {v0.8h}, [x0]
+        subs            w4,  w4,  #2
+        sxtl            v4.8h,   v4.8b
+        sxtl            v5.8h,   v5.8b
+        ld1             {v1.8h}, [x8]
+        shl             v4.8h,   v4.8h,   #9      // -m << 9
+        shl             v5.8h,   v5.8h,   #9
+        sub             v2.8h,   v0.8h,   v2.8h   // a - b
+        sub             v3.8h,   v1.8h,   v3.8h
+        sqrdmulh        v2.8h,   v2.8h,   v4.8h   // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v3.8h,   v3.8h,   v5.8h
+        add             v0.8h,   v0.8h,   v2.8h
+        add             v1.8h,   v1.8h,   v3.8h
+        st1             {v0.8h}, [x0], x1
+        st1             {v1.8h}, [x8], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ld2r            {v16.8b, v17.8b}, [x5], #2
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2], #64
+        neg             v16.8b,  v16.8b           // -m
+        neg             v17.8b,  v17.8b
+        ld1             {v0.8h, v1.8h},  [x0]
+        ld1             {v2.8h, v3.8h},  [x8]
+        subs            w4,  w4,  #2
+        sxtl            v16.8h,  v16.8b
+        sxtl            v17.8h,  v17.8b
+        shl             v16.8h,  v16.8h,  #9      // -m << 9
+        shl             v17.8h,  v17.8h,  #9
+        sub             v4.8h,   v0.8h,   v4.8h   // a - b
+        sub             v5.8h,   v1.8h,   v5.8h
+        sub             v6.8h,   v2.8h,   v6.8h
+        sub             v7.8h,   v3.8h,   v7.8h
+        sqrdmulh        v4.8h,   v4.8h,   v16.8h  // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v5.8h,   v5.8h,   v16.8h
+        sqrdmulh        v6.8h,   v6.8h,   v17.8h
+        sqrdmulh        v7.8h,   v7.8h,   v17.8h
+        add             v0.8h,   v0.8h,   v4.8h
+        add             v1.8h,   v1.8h,   v5.8h
+        add             v2.8h,   v2.8h,   v6.8h
+        add             v3.8h,   v3.8h,   v7.8h
+        st1             {v0.8h, v1.8h}, [x0], x1
+        st1             {v2.8h, v3.8h}, [x8], x1
+        b.gt            16b
+        ret
+1280:
+640:
+320:
+        AARCH64_VALID_JUMP_TARGET
+        sub             x1,  x1,  w3,  uxtw #1
+        add             x7,  x2,  w3,  uxtw #1
+321:
+        ld2r            {v24.8b, v25.8b}, [x5], #2
+        mov             w6,  w3
+        neg             v24.8b,  v24.8b           // -m
+        neg             v25.8b,  v25.8b
+        sxtl            v24.8h,  v24.8b
+        sxtl            v25.8h,  v25.8b
+        shl             v24.8h,  v24.8h,  #9      // -m << 9
+        shl             v25.8h,  v25.8h,  #9
+32:
+        ld1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x2], #64
+        ld1             {v0.8h,  v1.8h,  v2.8h,  v3.8h},  [x0]
+        subs            w6,  w6,  #32
+        sub             v16.8h,  v0.8h,   v16.8h  // a - b
+        sub             v17.8h,  v1.8h,   v17.8h
+        sub             v18.8h,  v2.8h,   v18.8h
+        sub             v19.8h,  v3.8h,   v19.8h
+        ld1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x7], #64
+        ld1             {v4.8h,  v5.8h,  v6.8h,  v7.8h},  [x8]
+        sqrdmulh        v16.8h,  v16.8h,  v24.8h  // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v17.8h,  v17.8h,  v24.8h
+        sqrdmulh        v18.8h,  v18.8h,  v24.8h
+        sqrdmulh        v19.8h,  v19.8h,  v24.8h
+        sub             v20.8h,  v4.8h,   v20.8h  // a - b
+        sub             v21.8h,  v5.8h,   v21.8h
+        sub             v22.8h,  v6.8h,   v22.8h
+        sub             v23.8h,  v7.8h,   v23.8h
+        add             v0.8h,   v0.8h,   v16.8h
+        add             v1.8h,   v1.8h,   v17.8h
+        add             v2.8h,   v2.8h,   v18.8h
+        add             v3.8h,   v3.8h,   v19.8h
+        sqrdmulh        v20.8h,  v20.8h,  v25.8h  // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v21.8h,  v21.8h,  v25.8h
+        sqrdmulh        v22.8h,  v22.8h,  v25.8h
+        sqrdmulh        v23.8h,  v23.8h,  v25.8h
+        st1             {v0.8h,  v1.8h,  v2.8h,  v3.8h},  [x0], #64
+        add             v4.8h,   v4.8h,   v20.8h
+        add             v5.8h,   v5.8h,   v21.8h
+        add             v6.8h,   v6.8h,   v22.8h
+        add             v7.8h,   v7.8h,   v23.8h
+        st1             {v4.8h,  v5.8h,  v6.8h,  v7.8h},  [x8], #64
+        b.gt            32b
+        subs            w4,  w4,  #2
+        add             x0,  x0,  x1
+        add             x8,  x8,  x1
+        add             x2,  x2,  w3,  uxtw #1
+        add             x7,  x7,  w3,  uxtw #1
+        b.gt            321b
+        ret
+endfunc
+
+jumptable blend_h_tbl
+        .word 1280b - blend_h_tbl
+        .word 640b  - blend_h_tbl
+        .word 320b  - blend_h_tbl
+        .word 160b  - blend_h_tbl
+        .word 80b   - blend_h_tbl
+        .word 40b   - blend_h_tbl
+        .word 20b   - blend_h_tbl
+endjumptable
+
+function blend_v_16bpc_neon, export=1
+        movrel          x6,  blend_v_tbl
+        movrel          x5,  X(obmc_masks)
+        add             x5,  x5,  w3,  uxtw
+        clz             w3,  w3
+        add             x8,  x0,  x1
+        lsl             x1,  x1,  #1
+        sub             w3,  w3,  #26
+        ldrsw           x3,  [x6,  x3,  lsl #2]
+        add             x6,  x6,  x3
+        br              x6
+20:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v2.8b}, [x5]
+        neg             v2.8b,   v2.8b            // -m
+        sxtl            v2.8h,   v2.8b
+        shl             v2.4h,   v2.4h,   #9      // -m << 9
+2:
+        ldr             s1,  [x2],  #4
+        ldr             h0,  [x0]
+        subs            w4,  w4,  #2
+        ld1             {v1.h}[1], [x2]
+        ld1             {v0.h}[1], [x8]
+        add             x2,  x2,  #4
+        sub             v1.4h,   v0.4h,   v1.4h   // a - b
+        sqrdmulh        v1.4h,   v1.4h,   v2.4h   // ((a-b)*-m + 32) >> 6
+        add             v0.4h,   v0.4h,   v1.4h
+        st1             {v0.h}[0], [x0],  x1
+        st1             {v0.h}[1], [x8],  x1
+        b.gt            2b
+        ret
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ld1r            {v2.2s}, [x5]
+        sub             x1,  x1,  #4
+        neg             v2.8b,   v2.8b            // -m
+        sxtl            v2.8h,   v2.8b
+        shl             v2.8h,   v2.8h,   #9      // -m << 9
+4:
+        ld1             {v1.8h},   [x2], #16
+        ldr             d0,        [x0]
+        ld1             {v0.d}[1], [x8]
+        subs            w4,  w4,  #2
+        sub             v1.8h,   v0.8h,   v1.8h   // a - b
+        sqrdmulh        v1.8h,   v1.8h,   v2.8h   // ((a-b)*-m + 32) >> 6
+        add             v0.8h,   v0.8h,   v1.8h
+        str             s0,        [x0], #4
+        st1             {v0.s}[2], [x8], #4
+        st1             {v0.h}[2], [x0], x1
+        st1             {v0.h}[6], [x8], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v4.8b}, [x5]
+        sub             x1,  x1,  #8
+        neg             v4.8b,   v4.8b            // -m
+        sxtl            v4.8h,   v4.8b
+        shl             v4.8h,   v4.8h,   #9      // -m << 9
+8:
+        ld1             {v2.8h, v3.8h}, [x2], #32
+        ld1             {v0.8h}, [x0]
+        ld1             {v1.8h}, [x8]
+        subs            w4,  w4,  #2
+        sub             v2.8h,   v0.8h,   v2.8h   // a - b
+        sub             v3.8h,   v1.8h,   v3.8h
+        sqrdmulh        v2.8h,   v2.8h,   v4.8h   // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v3.8h,   v3.8h,   v4.8h
+        add             v0.8h,   v0.8h,   v2.8h
+        add             v1.8h,   v1.8h,   v3.8h
+        str             d0,        [x0], #8
+        str             d1,        [x8], #8
+        st1             {v0.s}[2], [x0], x1
+        st1             {v1.s}[2], [x8], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v16.16b}, [x5]
+        sub             x1,  x1,  #16
+        neg             v17.16b, v16.16b          // -m
+        sxtl            v16.8h,  v17.8b
+        sxtl2           v17.8h,  v17.16b
+        shl             v16.8h,  v16.8h,  #9      // -m << 9
+        shl             v17.4h,  v17.4h,  #9
+16:
+        ld1             {v4.8h, v5.8h, v6.8h, v7.8h}, [x2], #64
+        ld1             {v0.8h, v1.8h}, [x0]
+        subs            w4,  w4,  #2
+        ld1             {v2.8h, v3.8h}, [x8]
+        sub             v4.8h,   v0.8h,   v4.8h   // a - b
+        sub             v5.4h,   v1.4h,   v5.4h
+        sub             v6.8h,   v2.8h,   v6.8h
+        sub             v7.4h,   v3.4h,   v7.4h
+        sqrdmulh        v4.8h,   v4.8h,   v16.8h  // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v5.4h,   v5.4h,   v17.4h
+        sqrdmulh        v6.8h,   v6.8h,   v16.8h
+        sqrdmulh        v7.4h,   v7.4h,   v17.4h
+        add             v0.8h,   v0.8h,   v4.8h
+        add             v1.4h,   v1.4h,   v5.4h
+        add             v2.8h,   v2.8h,   v6.8h
+        add             v3.4h,   v3.4h,   v7.4h
+        st1             {v0.8h}, [x0], #16
+        st1             {v2.8h}, [x8], #16
+        st1             {v1.4h}, [x0], x1
+        st1             {v3.4h}, [x8], x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v24.16b, v25.16b},  [x5]
+        neg             v26.16b, v24.16b          // -m
+        neg             v27.8b,  v25.8b
+        sxtl            v24.8h,  v26.8b
+        sxtl2           v25.8h,  v26.16b
+        sxtl            v26.8h,  v27.8b
+        shl             v24.8h,  v24.8h,  #9      // -m << 9
+        shl             v25.8h,  v25.8h,  #9
+        shl             v26.8h,  v26.8h,  #9
+32:
+        ld1             {v16.8h, v17.8h, v18.8h, v19.8h}, [x2], #64
+        ld1             {v0.8h, v1.8h, v2.8h}, [x0]
+        ld1             {v20.8h, v21.8h, v22.8h, v23.8h}, [x2], #64
+        ld1             {v4.8h, v5.8h, v6.8h}, [x8]
+        subs            w4,  w4,  #2
+        sub             v16.8h,  v0.8h,   v16.8h  // a - b
+        sub             v17.8h,  v1.8h,   v17.8h
+        sub             v18.8h,  v2.8h,   v18.8h
+        sub             v20.8h,  v4.8h,   v20.8h
+        sub             v21.8h,  v5.8h,   v21.8h
+        sub             v22.8h,  v6.8h,   v22.8h
+        sqrdmulh        v16.8h,  v16.8h,  v24.8h  // ((a-b)*-m + 32) >> 6
+        sqrdmulh        v17.8h,  v17.8h,  v25.8h
+        sqrdmulh        v18.8h,  v18.8h,  v26.8h
+        sqrdmulh        v20.8h,  v20.8h,  v24.8h
+        sqrdmulh        v21.8h,  v21.8h,  v25.8h
+        sqrdmulh        v22.8h,  v22.8h,  v26.8h
+        add             v0.8h,   v0.8h,   v16.8h
+        add             v1.8h,   v1.8h,   v17.8h
+        add             v2.8h,   v2.8h,   v18.8h
+        add             v4.8h,   v4.8h,   v20.8h
+        add             v5.8h,   v5.8h,   v21.8h
+        add             v6.8h,   v6.8h,   v22.8h
+        st1             {v0.8h, v1.8h, v2.8h}, [x0], x1
+        st1             {v4.8h, v5.8h, v6.8h}, [x8], x1
+        b.gt            32b
+        ret
+endfunc
+
+jumptable blend_v_tbl
+        .word 320b - blend_v_tbl
+        .word 160b - blend_v_tbl
+        .word 80b  - blend_v_tbl
+        .word 40b  - blend_v_tbl
+        .word 20b  - blend_v_tbl
+endjumptable
+
+
+// This has got the same signature as the put_8tap functions,
+// and assumes that x9 is set to (clz(w)-24).
+function put_16bpc_neon, export=1
+        movrel          x10, put_16bpc_tbl
+        ldrsw           x9, [x10, x9, lsl #2]
+        add             x10, x10, x9
+        br              x10
+
+20:
+        AARCH64_VALID_JUMP_TARGET
+2:
+        ld1r            {v0.4s},   [x2], x3
+        ld1r            {v1.4s},   [x2], x3
+        subs            w5,  w5,  #2
+        st1             {v0.s}[0], [x0], x1
+        st1             {v1.s}[0], [x0], x1
+        b.gt            2b
+        ret
+40:
+        AARCH64_VALID_JUMP_TARGET
+4:
+        ld1             {v0.4h}, [x2], x3
+        ld1             {v1.4h}, [x2], x3
+        subs            w5,  w5,  #2
+        st1             {v0.4h}, [x0], x1
+        st1             {v1.4h}, [x0], x1
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        add             x8,  x0,  x1
+        lsl             x1,  x1,  #1
+        add             x9,  x2,  x3
+        lsl             x3,  x3,  #1
+8:
+        ld1             {v0.8h}, [x2], x3
+        ld1             {v1.8h}, [x9], x3
+        subs            w5,  w5,  #2
+        st1             {v0.8h}, [x0], x1
+        st1             {v1.8h}, [x8], x1
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ldp             x6,  x7,  [x2]
+        ldp             x8,  x9,  [x2, #16]
+        stp             x6,  x7,  [x0]
+        subs            w5,  w5,  #1
+        stp             x8,  x9,  [x0, #16]
+        add             x2,  x2,  x3
+        add             x0,  x0,  x1
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ldp             x6,  x7,  [x2]
+        ldp             x8,  x9,  [x2, #16]
+        stp             x6,  x7,  [x0]
+        ldp             x10, x11, [x2, #32]
+        stp             x8,  x9,  [x0, #16]
+        subs            w5,  w5,  #1
+        ldp             x12, x13, [x2, #48]
+        stp             x10, x11, [x0, #32]
+        stp             x12, x13, [x0, #48]
+        add             x2,  x2,  x3
+        add             x0,  x0,  x1
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+64:
+        ldp             q0,  q1,  [x2]
+        ldp             q2,  q3,  [x2, #32]
+        stp             q0,  q1,  [x0]
+        ldp             q4,  q5,  [x2, #64]
+        stp             q2,  q3,  [x0, #32]
+        ldp             q6,  q7,  [x2, #96]
+        subs            w5,  w5,  #1
+        stp             q4,  q5,  [x0, #64]
+        stp             q6,  q7,  [x0, #96]
+        add             x2,  x2,  x3
+        add             x0,  x0,  x1
+        b.gt            64b
+        ret
+1280:
+        AARCH64_VALID_JUMP_TARGET
+128:
+        ldp             q0,  q1,  [x2]
+        ldp             q2,  q3,  [x2, #32]
+        stp             q0,  q1,  [x0]
+        ldp             q4,  q5,  [x2, #64]
+        stp             q2,  q3,  [x0, #32]
+        ldp             q6,  q7,  [x2, #96]
+        subs            w5,  w5,  #1
+        stp             q4,  q5,  [x0, #64]
+        ldp             q16, q17, [x2, #128]
+        stp             q6,  q7,  [x0, #96]
+        ldp             q18, q19, [x2, #160]
+        stp             q16, q17, [x0, #128]
+        ldp             q20, q21, [x2, #192]
+        stp             q18, q19, [x0, #160]
+        ldp             q22, q23, [x2, #224]
+        stp             q20, q21, [x0, #192]
+        stp             q22, q23, [x0, #224]
+        add             x2,  x2,  x3
+        add             x0,  x0,  x1
+        b.gt            128b
+        ret
+endfunc
+
+jumptable put_16bpc_tbl
+        .word 1280b - put_16bpc_tbl
+        .word 640b  - put_16bpc_tbl
+        .word 320b  - put_16bpc_tbl
+        .word 160b  - put_16bpc_tbl
+        .word 80b   - put_16bpc_tbl
+        .word 40b   - put_16bpc_tbl
+        .word 20b   - put_16bpc_tbl
+endjumptable
+
+
+// This has got the same signature as the prep_8tap functions,
+// and assumes that x9 is set to (clz(w)-24), w7 to intermediate_bits and
+// x8 to w*2.
+function prep_16bpc_neon
+        movrel          x10, prep_16bpc_tbl
+        ldrsw           x9, [x10, x9, lsl #2]
+        dup             v31.8h,  w7   // intermediate_bits
+        movi            v30.8h,  #(PREP_BIAS >> 8), lsl #8
+        add             x10, x10, x9
+        br              x10
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+        add             x9,  x1,  x2
+        lsl             x2,  x2,  #1
+4:
+        ld1             {v0.8b},   [x1], x2
+        ld1             {v0.d}[1], [x9], x2
+        subs            w4,  w4,  #2
+        sshl            v0.8h,   v0.8h,   v31.8h
+        sub             v0.8h,   v0.8h,   v30.8h
+        st1             {v0.8h}, [x0], #16
+        b.gt            4b
+        ret
+80:
+        AARCH64_VALID_JUMP_TARGET
+        add             x9,  x1,  x2
+        lsl             x2,  x2,  #1
+8:
+        ld1             {v0.8h}, [x1], x2
+        ld1             {v1.8h}, [x9], x2
+        subs            w4,  w4,  #2
+        sshl            v0.8h,   v0.8h,   v31.8h
+        sshl            v1.8h,   v1.8h,   v31.8h
+        sub             v0.8h,   v0.8h,   v30.8h
+        sub             v1.8h,   v1.8h,   v30.8h
+        st1             {v0.8h, v1.8h}, [x0], #32
+        b.gt            8b
+        ret
+160:
+        AARCH64_VALID_JUMP_TARGET
+16:
+        ldp             q0,  q1,  [x1]
+        add             x1,  x1,  x2
+        sshl            v0.8h,   v0.8h,   v31.8h
+        ldp             q2,  q3,  [x1]
+        add             x1,  x1,  x2
+        subs            w4,  w4,  #2
+        sshl            v1.8h,   v1.8h,   v31.8h
+        sshl            v2.8h,   v2.8h,   v31.8h
+        sshl            v3.8h,   v3.8h,   v31.8h
+        sub             v0.8h,   v0.8h,   v30.8h
+        sub             v1.8h,   v1.8h,   v30.8h
+        sub             v2.8h,   v2.8h,   v30.8h
+        sub             v3.8h,   v3.8h,   v30.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        b.gt            16b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+32:
+        ldp             q0,  q1,  [x1]
+        sshl            v0.8h,   v0.8h,   v31.8h
+        ldp             q2,  q3,  [x1, #32]
+        add             x1,  x1,  x2
+        sshl            v1.8h,   v1.8h,   v31.8h
+        sshl            v2.8h,   v2.8h,   v31.8h
+        sshl            v3.8h,   v3.8h,   v31.8h
+        subs            w4,  w4,  #1
+        sub             v0.8h,   v0.8h,   v30.8h
+        sub             v1.8h,   v1.8h,   v30.8h
+        sub             v2.8h,   v2.8h,   v30.8h
+        sub             v3.8h,   v3.8h,   v30.8h
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x0], #64
+        b.gt            32b
+        ret
+640:
+        AARCH64_VALID_JUMP_TARGET
+64:
+        ldp             q0,  q1,  [x1]
+        subs            w4,  w4,  #1
+        sshl            v0.8h,   v0.8h,   v31.8h
+        ldp             q2,  q3,  [x1, #32]
+        sshl            v1.8h,   v1.8h,   v31.8h
+        ldp             q4,  q5,  [x1, #64]
+        sshl            v2.8h,   v2.8h,   v31.8h
+        sshl            v3.8h,   v3.8h,   v31.8h
+        ldp             q6,  q7,  [x1, #96]
+        add             x1,  x1,  x2
+        sshl            v4.8h,   v4.8h,   v31.8h
+        sshl            v5.8h,   v5.8h,   v31.8h
+        sshl            v6.8h,   v6.8h,   v31.8h
+        sshl            v7.8h,   v7.8h,   v31.8h
+        sub             v0.8h,   v0.8h,   v30.8h
+        sub             v1.8h,   v1.8h,   v30.8h
+        sub             v2.8h,   v2.8h,   v30.8h
+        sub             v3.8h,   v3.8h,   v30.8h
+        stp             q0,  q1,  [x0]
+        sub             v4.8h,   v4.8h,   v30.8h
+        sub             v5.8h,   v5.8h,   v30.8h
+        stp             q2,  q3,  [x0, #32]
+        sub             v6.8h,   v6.8h,   v30.8h
+        sub             v7.8h,   v7.8h,   v30.8h
+        stp             q4,  q5,  [x0, #64]
+        stp             q6,  q7,  [x0, #96]
+        add             x0,  x0,  x8
+        b.gt            64b
+        ret
+1280:
+        AARCH64_VALID_JUMP_TARGET
+128:
+        ldp             q0,  q1,  [x1]
+        subs            w4,  w4,  #1
+        sshl            v0.8h,   v0.8h,   v31.8h
+        ldp             q2,  q3,  [x1, #32]
+        sshl            v1.8h,   v1.8h,   v31.8h
+        ldp             q4,  q5,  [x1, #64]
+        sshl            v2.8h,   v2.8h,   v31.8h
+        sshl            v3.8h,   v3.8h,   v31.8h
+        ldp             q6,  q7,  [x1, #96]
+        sshl            v4.8h,   v4.8h,   v31.8h
+        sshl            v5.8h,   v5.8h,   v31.8h
+        ldp             q16, q17, [x1, #128]
+        sshl            v6.8h,   v6.8h,   v31.8h
+        sshl            v7.8h,   v7.8h,   v31.8h
+        ldp             q18, q19, [x1, #160]
+        sshl            v16.8h,  v16.8h,  v31.8h
+        sshl            v17.8h,  v17.8h,  v31.8h
+        ldp             q20, q21, [x1, #192]
+        sshl            v18.8h,  v18.8h,  v31.8h
+        sshl            v19.8h,  v19.8h,  v31.8h
+        ldp             q22, q23, [x1, #224]
+        add             x1,  x1,  x2
+        sshl            v20.8h,  v20.8h,  v31.8h
+        sshl            v21.8h,  v21.8h,  v31.8h
+        sshl            v22.8h,  v22.8h,  v31.8h
+        sshl            v23.8h,  v23.8h,  v31.8h
+        sub             v0.8h,   v0.8h,   v30.8h
+        sub             v1.8h,   v1.8h,   v30.8h
+        sub             v2.8h,   v2.8h,   v30.8h
+        sub             v3.8h,   v3.8h,   v30.8h
+        stp             q0,  q1,  [x0]
+        sub             v4.8h,   v4.8h,   v30.8h
+        sub             v5.8h,   v5.8h,   v30.8h
+        stp             q2,  q3,  [x0, #32]
+        sub             v6.8h,   v6.8h,   v30.8h
+        sub             v7.8h,   v7.8h,   v30.8h
+        stp             q4,  q5,  [x0, #64]
+        sub             v16.8h,  v16.8h,  v30.8h
+        sub             v17.8h,  v17.8h,  v30.8h
+        stp             q6,  q7,  [x0, #96]
+        sub             v18.8h,  v18.8h,  v30.8h
+        sub             v19.8h,  v19.8h,  v30.8h
+        stp             q16, q17, [x0, #128]
+        sub             v20.8h,  v20.8h,  v30.8h
+        sub             v21.8h,  v21.8h,  v30.8h
+        stp             q18, q19, [x0, #160]
+        sub             v22.8h,  v22.8h,  v30.8h
+        sub             v23.8h,  v23.8h,  v30.8h
+        stp             q20, q21, [x0, #192]
+        stp             q22, q23, [x0, #224]
+        add             x0,  x0,  x8
+        b.gt            128b
+        ret
+endfunc
+
+jumptable prep_16bpc_tbl
+        .word 1280b - prep_16bpc_tbl
+        .word 640b  - prep_16bpc_tbl
+        .word 320b  - prep_16bpc_tbl
+        .word 160b  - prep_16bpc_tbl
+        .word 80b   - prep_16bpc_tbl
+        .word 40b   - prep_16bpc_tbl
+endjumptable
+
+
+.macro load_slice s0, s1, strd, wd, d0, d1, d2, d3, d4, d5, d6
+        ld1             {\d0\wd}[0], [\s0], \strd
+        ld1             {\d1\wd}[0], [\s1], \strd
+.ifnb \d2
+        ld1             {\d2\wd}[0], [\s0], \strd
+        ld1             {\d3\wd}[0], [\s1], \strd
+.endif
+.ifnb \d4
+        ld1             {\d4\wd}[0], [\s0], \strd
+.endif
+.ifnb \d5
+        ld1             {\d5\wd}[0], [\s1], \strd
+.endif
+.ifnb \d6
+        ld1             {\d6\wd}[0], [\s0], \strd
+.endif
+.endm
+.macro load_reg s0, s1, strd, wd, d0, d1, d2, d3, d4, d5, d6
+        ld1             {\d0\wd}, [\s0], \strd
+        ld1             {\d1\wd}, [\s1], \strd
+.ifnb \d2
+        ld1             {\d2\wd}, [\s0], \strd
+        ld1             {\d3\wd}, [\s1], \strd
+.endif
+.ifnb \d4
+        ld1             {\d4\wd}, [\s0], \strd
+.endif
+.ifnb \d5
+        ld1             {\d5\wd}, [\s1], \strd
+.endif
+.ifnb \d6
+        ld1             {\d6\wd}, [\s0], \strd
+.endif
+.endm
+.macro load_regpair s0, s1, strd, wd, d0, d1, d2, d3, d4, d5
+        ld1             {\d0\wd, \d1\wd}, [\s0], \strd
+.ifnb \d2
+        ld1             {\d2\wd, \d3\wd}, [\s1], \strd
+.endif
+.ifnb \d4
+        ld1             {\d4\wd, \d5\wd}, [\s0], \strd
+.endif
+.endm
+.macro load_s s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_slice      \s0, \s1, \strd, .s, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro load_4h s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_reg        \s0, \s1, \strd, .4h, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro load_8h s0, s1, strd, d0, d1, d2, d3, d4, d5, d6
+        load_reg        \s0, \s1, \strd, .8h, \d0, \d1, \d2, \d3, \d4, \d5, \d6
+.endm
+.macro load_16h s0, s1, strd, d0, d1, d2, d3, d4, d5
+        load_regpair    \s0, \s1, \strd, .8h, \d0, \d1, \d2, \d3, \d4, \d5
+.endm
+.macro interleave_1 wd, r0, r1, r2, r3, r4
+        trn1            \r0\wd, \r0\wd, \r1\wd
+        trn1            \r1\wd, \r1\wd, \r2\wd
+.ifnb \r3
+        trn1            \r2\wd, \r2\wd, \r3\wd
+        trn1            \r3\wd, \r3\wd, \r4\wd
+.endif
+.endm
+.macro interleave_1_s r0, r1, r2, r3, r4
+        interleave_1    .2s, \r0, \r1, \r2, \r3, \r4
+.endm
+.macro umin_h c, wd, r0, r1, r2, r3
+        umin            \r0\wd,  \r0\wd,  \c\wd
+.ifnb \r1
+        umin            \r1\wd,  \r1\wd,  \c\wd
+.endif
+.ifnb \r2
+        umin            \r2\wd,  \r2\wd,  \c\wd
+        umin            \r3\wd,  \r3\wd,  \c\wd
+.endif
+.endm
+.macro sub_h c, wd, r0, r1, r2, r3
+        sub             \r0\wd,  \r0\wd,  \c\wd
+.ifnb \r1
+        sub             \r1\wd,  \r1\wd,  \c\wd
+.endif
+.ifnb \r2
+        sub             \r2\wd,  \r2\wd,  \c\wd
+        sub             \r3\wd,  \r3\wd,  \c\wd
+.endif
+.endm
+.macro smull_smlal_4tap d, s0, s1, s2, s3
+        smull           \d\().4s,  \s0\().4h,  v0.h[0]
+        smlal           \d\().4s,  \s1\().4h,  v0.h[1]
+        smlal           \d\().4s,  \s2\().4h,  v0.h[2]
+        smlal           \d\().4s,  \s3\().4h,  v0.h[3]
+.endm
+.macro smull2_smlal2_4tap d, s0, s1, s2, s3
+        smull2          \d\().4s,  \s0\().8h,  v0.h[0]
+        smlal2          \d\().4s,  \s1\().8h,  v0.h[1]
+        smlal2          \d\().4s,  \s2\().8h,  v0.h[2]
+        smlal2          \d\().4s,  \s3\().8h,  v0.h[3]
+.endm
+.macro smull_smlal_6tap d, s0, s1, s2, s3, s4, s5, s6, s7
+        smull           \d\().4s,  \s1\().4h,  v0.h[1]
+        smlal           \d\().4s,  \s2\().4h,  v0.h[2]
+        smlal           \d\().4s,  \s3\().4h,  v0.h[3]
+        smlal           \d\().4s,  \s4\().4h,  v0.h[4]
+        smlal           \d\().4s,  \s5\().4h,  v0.h[5]
+        smlal           \d\().4s,  \s6\().4h,  v0.h[6]
+.endm
+.macro smull2_smlal2_6tap d, s0, s1, s2, s3, s4, s5, s6, s7
+        smull2          \d\().4s,  \s1\().8h,  v0.h[1]
+        smlal2          \d\().4s,  \s2\().8h,  v0.h[2]
+        smlal2          \d\().4s,  \s3\().8h,  v0.h[3]
+        smlal2          \d\().4s,  \s4\().8h,  v0.h[4]
+        smlal2          \d\().4s,  \s5\().8h,  v0.h[5]
+        smlal2          \d\().4s,  \s6\().8h,  v0.h[6]
+.endm
+.macro smull_smlal_8tap d, s0, s1, s2, s3, s4, s5, s6, s7
+        smull           \d\().4s,  \s0\().4h,  v0.h[0]
+        smlal           \d\().4s,  \s1\().4h,  v0.h[1]
+        smlal           \d\().4s,  \s2\().4h,  v0.h[2]
+        smlal           \d\().4s,  \s3\().4h,  v0.h[3]
+        smlal           \d\().4s,  \s4\().4h,  v0.h[4]
+        smlal           \d\().4s,  \s5\().4h,  v0.h[5]
+        smlal           \d\().4s,  \s6\().4h,  v0.h[6]
+        smlal           \d\().4s,  \s7\().4h,  v0.h[7]
+.endm
+.macro smull2_smlal2_8tap d, s0, s1, s2, s3, s4, s5, s6, s7
+        smull2          \d\().4s,  \s0\().8h,  v0.h[0]
+        smlal2          \d\().4s,  \s1\().8h,  v0.h[1]
+        smlal2          \d\().4s,  \s2\().8h,  v0.h[2]
+        smlal2          \d\().4s,  \s3\().8h,  v0.h[3]
+        smlal2          \d\().4s,  \s4\().8h,  v0.h[4]
+        smlal2          \d\().4s,  \s5\().8h,  v0.h[5]
+        smlal2          \d\().4s,  \s6\().8h,  v0.h[6]
+        smlal2          \d\().4s,  \s7\().8h,  v0.h[7]
+.endm
+.macro sqrshrun_h shift, r0, r1, r2, r3
+        sqrshrun        \r0\().4h, \r0\().4s,  #\shift
+.ifnb \r1
+        sqrshrun2       \r0\().8h, \r1\().4s,  #\shift
+.endif
+.ifnb \r2
+        sqrshrun        \r2\().4h, \r2\().4s,  #\shift
+        sqrshrun2       \r2\().8h, \r3\().4s,  #\shift
+.endif
+.endm
+.macro xtn_h r0, r1, r2, r3
+        uzp1            \r0\().8h,  \r0\().8h,  \r1\().8h // Same as xtn, xtn2
+.ifnb \r2
+        uzp1            \r2\().8h,  \r2\().8h,  \r3\().8h // Ditto
+.endif
+.endm
+.macro srshl_s shift, r0, r1, r2, r3
+        srshl           \r0\().4s,  \r0\().4s,  \shift\().4s
+        srshl           \r1\().4s,  \r1\().4s,  \shift\().4s
+.ifnb \r2
+        srshl           \r2\().4s,  \r2\().4s,  \shift\().4s
+        srshl           \r3\().4s,  \r3\().4s,  \shift\().4s
+.endif
+.endm
+.macro st_s strd, reg, lanes
+        st1             {\reg\().s}[0], [x0], \strd
+        st1             {\reg\().s}[1], [x9], \strd
+.if \lanes > 2
+        st1             {\reg\().s}[2], [x0], \strd
+        st1             {\reg\().s}[3], [x9], \strd
+.endif
+.endm
+.macro st_d strd, r0, r1
+        st1             {\r0\().8b},   [x0], \strd
+        st1             {\r0\().d}[1], [x9], \strd
+.ifnb \r1
+        st1             {\r1\().8b},   [x0], \strd
+        st1             {\r1\().d}[1], [x9], \strd
+.endif
+.endm
+.macro shift_store_4 type, strd, r0, r1, r2, r3
+.ifc \type, put
+        sqrshrun_h      6,   \r0, \r1, \r2, \r3
+        umin_h          v31, .8h, \r0, \r2
+.else
+        srshl_s         v30, \r0, \r1, \r2, \r3  // -(6-intermediate_bits)
+        xtn_h           \r0, \r1, \r2, \r3
+        sub_h           v29, .8h, \r0, \r2       // PREP_BIAS
+.endif
+        st_d            \strd, \r0, \r2
+.endm
+.macro st_reg strd, wd, r0, r1, r2, r3, r4, r5, r6, r7
+        st1             {\r0\wd}, [x0], \strd
+        st1             {\r1\wd}, [x9], \strd
+.ifnb \r2
+        st1             {\r2\wd}, [x0], \strd
+        st1             {\r3\wd}, [x9], \strd
+.endif
+.ifnb \r4
+        st1             {\r4\wd}, [x0], \strd
+        st1             {\r5\wd}, [x9], \strd
+        st1             {\r6\wd}, [x0], \strd
+        st1             {\r7\wd}, [x9], \strd
+.endif
+.endm
+.macro st_8h strd, r0, r1, r2, r3, r4, r5, r6, r7
+        st_reg          \strd, .8h, \r0, \r1, \r2, \r3, \r4, \r5, \r6, \r7
+.endm
+.macro shift_store_8 type, strd, r0, r1, r2, r3
+.ifc \type, put
+        sqrshrun_h      6,   \r0, \r1, \r2, \r3
+        umin_h          v31, .8h, \r0, \r2
+.else
+        srshl_s         v30, \r0, \r1, \r2, \r3  // -(6-intermediate_bits)
+        xtn_h           \r0, \r1, \r2, \r3
+        sub_h           v29, .8h, \r0, \r2       // PREP_BIAS
+.endif
+        st_8h           \strd, \r0, \r2
+.endm
+.macro shift_store_16 type, strd, dst, r0, r1, r2, r3
+.ifc \type, put
+        sqrshrun_h      6,   \r0, \r1, \r2, \r3
+        umin            \r0\().8h, \r0\().8h, v31.8h
+        umin            \r1\().8h, \r2\().8h, v31.8h
+.else
+        srshl_s         v30, \r0, \r1, \r2, \r3  // -(6-intermediate_bits)
+        xtn_h           \r0, \r1, \r2, \r3
+        sub             \r0\().8h, \r0\().8h, v29.8h
+        sub             \r1\().8h, \r2\().8h, v29.8h
+.endif
+        st1             {\r0\().8h, \r1\().8h}, [\dst], \strd
+.endm
+
+.macro make_8tap_fn op, type, type_h, type_v, taps
+function \op\()_8tap_\type\()_16bpc_neon, export=1
+        mov             w9,  \type_h
+        mov             w10, \type_v
+        b               \op\()_\taps\()_neon
+endfunc
+.endm
+
+// No spaces in these expressions, due to gas-preprocessor.
+#define REGULAR ((0*15<<7)|3*15)
+#define SMOOTH  ((1*15<<7)|4*15)
+#define SHARP   ((2*15<<7)|3*15)
+
+.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, bdmax, ds2, sr2, taps
+function \type\()_\taps\()_neon
+.ifc \bdmax, w8
+        ldr             w8,  [sp]
+.endif
+        mov             w11,  #0x4081  // (1 << 14) | (1 << 7) | (1 << 0)
+        mul             \mx,  \mx, w11
+        mul             \my,  \my, w11
+        add             \mx,  \mx, w9  // mx, 8tap_h, 4tap_h
+        add             \my,  \my, w10 // my, 8tap_v, 4tap_v
+.ifc \type, prep
+        uxtw            \d_strd, \w
+        lsl             \d_strd, \d_strd, #1
+.endif
+
+        dup             v31.8h,  \bdmax        // bitdepth_max
+        clz             \bdmax,  \bdmax
+        clz             w9,  \w
+        sub             \bdmax,  \bdmax,  #18  // intermediate_bits = clz(bitdepth_max) - 18
+        mov             w12, #6
+        tst             \mx, #(0x7f << 14)
+        sub             w9,  w9,  #24
+        add             w13, w12, \bdmax       // 6 + intermediate_bits
+        sub             w12, w12, \bdmax       // 6 - intermediate_bits
+        movrel          x11, X(mc_subpel_filters), -8
+        b.ne            L(\type\()_\taps\()_h)
+        tst             \my, #(0x7f << 14)
+        b.ne            L(\type\()_\taps\()_v)
+        b               \type\()_16bpc_neon
+
+L(\type\()_\taps\()_h):
+        cmp             \w,   #4
+        ubfx            w10,  \mx, #7, #7
+        and             \mx,  \mx, #0x7f
+        b.le            4f
+        mov             \mx,  w10
+4:
+        tst             \my,  #(0x7f << 14)
+        add             \xmx, x11, \mx, uxtw #3
+        b.ne            L(\type\()_\taps\()_hv)
+
+        movrel          x10, \type\()_\taps\()_h_tbl
+        ldrsw           x9,  [x10, x9, lsl #2]
+.ifc \type, put
+        mov             w12,  #34              // rounding for 10-bit
+        mov             w13,  #40              // rounding for 12-bit
+        cmp             \bdmax, #2             // 10-bit: 4, 12-bit: 2
+        csel            w12,  w12,  w13,  ne   // select rounding based on \bdmax
+.else
+        neg             w12,  w12              // -(6 - intermediate_bits)
+        movi            v28.8h,  #(PREP_BIAS >> 8), lsl #8
+.endif
+        add             x10, x10, x9
+        dup             v30.4s,  w12           // rounding or shift amount
+        br              x10
+
+20:     // 2xN h
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        ldur            s0,  [\xmx, #2]
+        sub             \src,  \src,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h,   v0.8b
+2:
+        ld1             {v4.8h},  [\src], \s_strd
+        ld1             {v6.8h},  [\sr2], \s_strd
+        mov             v2.16b,  v30.16b
+        ext             v5.16b,  v4.16b,  v4.16b,  #2
+        ext             v7.16b,  v6.16b,  v6.16b,  #2
+        subs            \h,  \h,  #2
+        trn1            v3.2s,   v4.2s,   v6.2s
+        trn2            v6.2s,   v4.2s,   v6.2s
+        trn1            v4.2s,   v5.2s,   v7.2s
+        trn2            v7.2s,   v5.2s,   v7.2s
+        smlal           v2.4s,   v3.4h,   v0.h[0]
+        smlal           v2.4s,   v4.4h,   v0.h[1]
+        smlal           v2.4s,   v6.4h,   v0.h[2]
+        smlal           v2.4s,   v7.4h,   v0.h[3]
+        sqshrun         v2.4h,   v2.4s,   #6
+        umin            v2.4h,   v2.4h,   v31.4h
+        st1             {v2.s}[0], [\dst], \d_strd
+        st1             {v2.s}[1], [\ds2], \d_strd
+        b.gt            2b
+        ret
+.endif
+
+40:     // 4xN h
+        AARCH64_VALID_JUMP_TARGET
+        ldur            s0,  [\xmx, #2]
+        sub             \src,  \src,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h,   v0.8b
+4:
+        ld1             {v16.8h}, [\src], \s_strd
+        ld1             {v20.8h}, [\sr2], \s_strd
+.ifc \type, put
+        mov             v2.16b,  v30.16b
+        mov             v3.16b,  v30.16b
+.endif
+        ext             v17.16b, v16.16b, v16.16b, #2
+        ext             v18.16b, v16.16b, v16.16b, #4
+        ext             v19.16b, v16.16b, v16.16b, #6
+        ext             v21.16b, v20.16b, v20.16b, #2
+        ext             v22.16b, v20.16b, v20.16b, #4
+        ext             v23.16b, v20.16b, v20.16b, #6
+        subs            \h,  \h,  #2
+.ifc \type, put
+        smlal           v2.4s,   v16.4h,  v0.h[0]
+.else
+        smull           v2.4s,   v16.4h,  v0.h[0]
+.endif
+        smlal           v2.4s,   v17.4h,  v0.h[1]
+        smlal           v2.4s,   v18.4h,  v0.h[2]
+        smlal           v2.4s,   v19.4h,  v0.h[3]
+.ifc \type, put
+        smlal           v3.4s,   v20.4h,  v0.h[0]
+.else
+        smull           v3.4s,   v20.4h,  v0.h[0]
+.endif
+        smlal           v3.4s,   v21.4h,  v0.h[1]
+        smlal           v3.4s,   v22.4h,  v0.h[2]
+        smlal           v3.4s,   v23.4h,  v0.h[3]
+.ifc \type, put
+        sqshrun         v16.4h,  v2.4s,   #6
+        sqshrun2        v16.8h,  v3.4s,   #6
+        umin            v16.8h,  v16.8h,  v31.8h
+.else
+        srshl           v16.4s,  v2.4s,   v30.4s // -(6-intermediate_bits)
+        srshl           v20.4s,  v3.4s,   v30.4s // -(6-intermediate_bits)
+        uzp1            v16.8h,  v16.8h,  v20.8h // Same as xtn, xtn2
+        sub             v16.8h,  v16.8h,  v28.8h // PREP_BIAS
+.endif
+        st1             {v16.8b},   [\dst], \d_strd
+        st1             {v16.d}[1], [\ds2], \d_strd
+        b.gt            4b
+        ret
+
+80:
+160:
+320:
+640:
+1280:   // 8xN, 16xN, 32xN, ... h
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b}, [\xmx]
+.ifc \taps, 6tap
+        sub             \src,  \src,  #4
+.else
+        sub             \src,  \src,  #6
+.endif
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h,   v0.8b
+
+        sub             \s_strd,  \s_strd,  \w, uxtw #1
+        sub             \s_strd,  \s_strd,  #16
+.ifc \type, put
+        lsl             \d_strd,  \d_strd,  #1
+        sub             \d_strd,  \d_strd,  \w, uxtw #1
+.endif
+81:
+        ld1             {v16.8h, v17.8h},  [\src], #32
+        ld1             {v20.8h, v21.8h},  [\sr2], #32
+        mov             \mx, \w
+
+8:
+.ifc \taps, 6tap
+    .ifc \type, put
+        mov             v18.16b, v30.16b
+        mov             v19.16b, v30.16b
+        smlal           v18.4s,  v16.4h,  v0.h[1]
+        smlal2          v19.4s,  v16.8h,  v0.h[1]
+        mov             v22.16b, v30.16b
+        mov             v23.16b, v30.16b
+        smlal           v22.4s,  v20.4h,  v0.h[1]
+        smlal2          v23.4s,  v20.8h,  v0.h[1]
+    .else
+        smull           v18.4s,  v16.4h,  v0.h[1]
+        smull2          v19.4s,  v16.8h,  v0.h[1]
+        smull           v22.4s,  v20.4h,  v0.h[1]
+        smull2          v23.4s,  v20.8h,  v0.h[1]
+    .endif
+    .irpc i, 23456
+        ext             v24.16b, v16.16b, v17.16b, #(2*\i-2)
+        ext             v25.16b, v20.16b, v21.16b, #(2*\i-2)
+        smlal           v18.4s,  v24.4h,  v0.h[\i]
+        smlal2          v19.4s,  v24.8h,  v0.h[\i]
+        smlal           v22.4s,  v25.4h,  v0.h[\i]
+        smlal2          v23.4s,  v25.8h,  v0.h[\i]
+    .endr
+.else   // 8tap
+    .ifc \type, put
+        mov             v18.16b, v30.16b
+        mov             v19.16b, v30.16b
+        smlal           v18.4s,  v16.4h,  v0.h[0]
+        smlal2          v19.4s,  v16.8h,  v0.h[0]
+        mov             v22.16b, v30.16b
+        mov             v23.16b, v30.16b
+        smlal           v22.4s,  v20.4h,  v0.h[0]
+        smlal2          v23.4s,  v20.8h,  v0.h[0]
+    .else
+        smull           v18.4s,  v16.4h,  v0.h[0]
+        smull2          v19.4s,  v16.8h,  v0.h[0]
+        smull           v22.4s,  v20.4h,  v0.h[0]
+        smull2          v23.4s,  v20.8h,  v0.h[0]
+    .endif
+    .irpc i, 1234567
+        ext             v24.16b, v16.16b, v17.16b, #(2*\i)
+        ext             v25.16b, v20.16b, v21.16b, #(2*\i)
+        smlal           v18.4s,  v24.4h,  v0.h[\i]
+        smlal2          v19.4s,  v24.8h,  v0.h[\i]
+        smlal           v22.4s,  v25.4h,  v0.h[\i]
+        smlal2          v23.4s,  v25.8h,  v0.h[\i]
+    .endr
+.endif
+        subs            \mx, \mx, #8
+.ifc \type, put
+        sqshrun         v18.4h,  v18.4s,  #6
+        sqshrun2        v18.8h,  v19.4s,  #6
+        sqshrun         v22.4h,  v22.4s,  #6
+        sqshrun2        v22.8h,  v23.4s,  #6
+        umin            v18.8h,  v18.8h,  v31.8h
+        umin            v22.8h,  v22.8h,  v31.8h
+.else
+        srshl           v18.4s,  v18.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v19.4s,  v19.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v22.4s,  v22.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v23.4s,  v23.4s,  v30.4s // -(6-intermediate_bits)
+        uzp1            v18.8h,  v18.8h,  v19.8h // Same as xtn, xtn2
+        uzp1            v22.8h,  v22.8h,  v23.8h // Ditto
+        sub             v18.8h,  v18.8h,  v28.8h // PREP_BIAS
+        sub             v22.8h,  v22.8h,  v28.8h // PREP_BIAS
+.endif
+        st1             {v18.8h}, [\dst], #16
+        st1             {v22.8h}, [\ds2], #16
+        b.le            9f
+
+        mov             v16.16b, v17.16b
+        mov             v20.16b, v21.16b
+        ld1             {v17.8h}, [\src], #16
+        ld1             {v21.8h}, [\sr2], #16
+        b               8b
+
+9:
+        add             \dst,  \dst,  \d_strd
+        add             \ds2,  \ds2,  \d_strd
+        add             \src,  \src,  \s_strd
+        add             \sr2,  \sr2,  \s_strd
+
+        subs            \h,  \h,  #2
+        b.gt            81b
+        ret
+endfunc
+
+jumptable \type\()_\taps\()_h_tbl
+        .word 1280b - \type\()_\taps\()_h_tbl
+        .word 640b  - \type\()_\taps\()_h_tbl
+        .word 320b  - \type\()_\taps\()_h_tbl
+        .word 160b  - \type\()_\taps\()_h_tbl
+        .word 80b   - \type\()_\taps\()_h_tbl
+        .word 40b   - \type\()_\taps\()_h_tbl
+        .word 20b   - \type\()_\taps\()_h_tbl
+endjumptable
+
+
+function L(\type\()_\taps\()_v)
+        cmp             \h,  #4
+        ubfx            w10, \my, #7, #7
+        and             \my, \my, #0x7f
+        b.le            4f
+        mov             \my, w10
+4:
+        add             \xmy, x11, \my, uxtw #3
+
+.ifc \type, prep
+        dup             v30.4s,  w12           // 6 - intermediate_bits
+        movi            v29.8h,  #(PREP_BIAS >> 8), lsl #8
+.endif
+        movrel          x10, \type\()_\taps\()_v_tbl
+        ldrsw           x9,  [x10, x9, lsl #2]
+.ifc \type, prep
+        neg             v30.4s,  v30.4s        // -(6-intermediate_bits)
+.endif
+        add             x10, x10, x9
+        br              x10
+
+20:     // 2xN v
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        b.gt            28f
+
+        cmp             \h,  #2
+        ldur            s0,  [\xmy, #2]
+        sub             \src,  \src,  \s_strd
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        sxtl            v0.8h,   v0.8b
+
+        // 2x2 v
+        load_s          \src, \sr2, \s_strd, v1, v2, v3, v4, v5
+        interleave_1_s  v1,  v2,  v3,  v4,  v5
+        b.gt            24f
+        smull_smlal_4tap v6, v1,  v2,  v3,  v4
+        sqrshrun_h      6,   v6
+        umin_h          v31, .8h, v6
+        st_s            \d_strd, v6, 2
+        ret
+
+24:     // 2x4 v
+        load_s          \sr2, \src, \s_strd, v6, v7
+        interleave_1_s  v5,  v6,  v7
+        smull_smlal_4tap v16, v1, v2, v3, v4
+        smull_smlal_4tap v17, v3, v4, v5, v6
+        sqrshrun_h      6,   v16, v17
+        umin_h          v31, .8h, v16
+        st_s            \d_strd, v16, 4
+        ret
+
+28:     // 2x6, 2x8, 2x12, 2x16 v
+        ld1             {v0.8b}, [\xmy]
+        sub             \sr2,  \src,  \s_strd, lsl #1
+        add             \ds2,  \dst,  \d_strd
+        sub             \src,  \sr2,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+        sxtl            v0.8h,   v0.8b
+
+        load_s          \src, \sr2, \s_strd, v1,  v2,  v3,  v4, v5, v6, v7
+        interleave_1_s  v1,  v2,  v3,  v4,  v5
+        interleave_1_s  v5,  v6,  v7
+216:
+        subs            \h,  \h,  #4
+        load_s          \sr2, \src, \s_strd, v16, v17, v18, v19
+        interleave_1_s  v7,  v16, v17, v18, v19
+        smull_smlal_\taps v24, v1,  v2,  v3,  v4,  v5,  v6,  v7, v16
+        smull_smlal_\taps v25, v3,  v4,  v5,  v6,  v7, v16, v17, v18
+        sqrshrun_h      6,   v24, v25
+        umin_h          v31, .8h, v24
+        st_s            \d_strd, v24, 4
+        b.le            0f
+        cmp             \h,  #2
+        mov             v1.16b,  v5.16b
+        mov             v2.16b,  v6.16b
+        mov             v3.16b,  v7.16b
+        mov             v4.16b,  v16.16b
+        mov             v5.16b,  v17.16b
+        mov             v6.16b,  v18.16b
+        mov             v7.16b,  v19.16b
+        b.eq            26f
+        b               216b
+26:
+        load_s          \sr2, \src, \s_strd, v16, v17
+        interleave_1_s  v7,  v16, v17
+        smull_smlal_\taps v24, v1, v2,  v3,  v4,  v5,  v6,  v7, v16
+        sqrshrun_h      6,   v24
+        umin_h          v31, .4h, v24
+        st_s            \d_strd, v24, 2
+0:
+        ret
+.endif
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+        b.gt            480f
+
+        // 4x2, 4x4 v
+        cmp             \h,  #2
+        ldur            s0,  [\xmy, #2]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,   v0.8b
+
+        load_4h         \src, \sr2, \s_strd, v1, v2, v3, v4, v5
+        smull_smlal_4tap v6,  v1,  v2,  v3,  v4
+        smull_smlal_4tap v7,  v2,  v3,  v4,  v5
+        shift_store_4   \type, \d_strd, v6, v7
+        b.le            0f
+        load_4h         \sr2, \src, \s_strd, v6, v7
+        smull_smlal_4tap v1,  v3,  v4,  v5,  v6
+        smull_smlal_4tap v2,  v4,  v5,  v6,  v7
+        shift_store_4   \type, \d_strd, v1, v2
+0:
+        ret
+
+480:    // 4x6, 4x8, 4x12, 4x16 v
+        ld1             {v0.8b}, [\xmy]
+        sub             \sr2, \src, \s_strd, lsl #1
+        add             \ds2, \dst, \d_strd
+        sub             \src, \sr2, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,   v0.8b
+
+        load_4h         \src, \sr2, \s_strd, v16, v17, v18, v19, v20, v21, v22
+
+48:
+        subs            \h,  \h,  #4
+        load_4h         \sr2, \src, \s_strd, v23, v24, v25, v26
+        smull_smlal_\taps v1, v16, v17, v18, v19, v20, v21, v22, v23
+        smull_smlal_\taps v2, v17, v18, v19, v20, v21, v22, v23, v24
+        smull_smlal_\taps v3, v18, v19, v20, v21, v22, v23, v24, v25
+        smull_smlal_\taps v4, v19, v20, v21, v22, v23, v24, v25, v26
+        shift_store_4   \type, \d_strd, v1, v2, v3, v4
+        b.le            0f
+        cmp             \h,  #2
+        mov             v16.8b,  v20.8b
+        mov             v17.8b,  v21.8b
+        mov             v18.8b,  v22.8b
+        mov             v19.8b,  v23.8b
+        mov             v20.8b,  v24.8b
+        mov             v21.8b,  v25.8b
+        mov             v22.8b,  v26.8b
+        b.eq            46f
+        b               48b
+46:
+        load_4h         \sr2, \src, \s_strd, v23, v24
+        smull_smlal_\taps v1, v16, v17, v18, v19, v20, v21, v22, v23
+        smull_smlal_\taps v2, v17, v18, v19, v20, v21, v22, v23, v24
+        shift_store_4   \type, \d_strd, v1, v2
+0:
+        ret
+
+80:
+        AARCH64_VALID_JUMP_TARGET
+        b.gt            880f
+
+        // 8x2, 8x4 v
+        cmp             \h,  #2
+        ldur            s0,  [\xmy, #2]
+        sub             \src, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,   v0.8b
+
+        load_8h         \src, \sr2, \s_strd, v1, v2, v3, v4, v5
+        smull_smlal_4tap   v16, v1,  v2,  v3,  v4
+        smull2_smlal2_4tap v17, v1,  v2,  v3,  v4
+        smull_smlal_4tap   v18, v2,  v3,  v4,  v5
+        smull2_smlal2_4tap v19, v2,  v3,  v4,  v5
+        shift_store_8   \type, \d_strd, v16, v17, v18, v19
+        b.le            0f
+        load_8h         \sr2, \src, \s_strd, v6, v7
+        smull_smlal_4tap   v16, v3,  v4,  v5,  v6
+        smull2_smlal2_4tap v17, v3,  v4,  v5,  v6
+        smull_smlal_4tap   v18, v4,  v5,  v6,  v7
+        smull2_smlal2_4tap v19, v4,  v5,  v6,  v7
+        shift_store_8   \type, \d_strd, v16, v17, v18, v19
+0:
+        ret
+
+880:    // 8x6, 8x8, 8x16, 8x32 v
+1680:   // 16x8, 16x16, ...
+320:    // 32x8, 32x16, ...
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b}, [\xmy]
+        sub             \src, \src, \s_strd
+        sub             \src, \src, \s_strd, lsl #1
+        sxtl            v0.8h,   v0.8b
+        mov             \my,  \h
+168:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        load_8h         \src, \sr2, \s_strd, v16, v17, v18, v19, v20, v21, v22
+
+88:
+        subs            \h,  \h,  #2
+        load_8h         \sr2, \src, \s_strd, v23, v24
+        smull_smlal_\taps   v1, v16, v17, v18, v19, v20, v21, v22, v23
+        smull2_smlal2_\taps v2, v16, v17, v18, v19, v20, v21, v22, v23
+        smull_smlal_\taps   v3, v17, v18, v19, v20, v21, v22, v23, v24
+        smull2_smlal2_\taps v4, v17, v18, v19, v20, v21, v22, v23, v24
+        shift_store_8   \type, \d_strd, v1, v2, v3, v4
+        b.le            9f
+        subs            \h,  \h,  #2
+        load_8h         \sr2, \src, \s_strd, v25, v26
+        smull_smlal_\taps   v1, v18, v19, v20, v21, v22, v23, v24, v25
+        smull2_smlal2_\taps v2, v18, v19, v20, v21, v22, v23, v24, v25
+        smull_smlal_\taps   v3, v19, v20, v21, v22, v23, v24, v25, v26
+        smull2_smlal2_\taps v4, v19, v20, v21, v22, v23, v24, v25, v26
+        shift_store_8   \type, \d_strd, v1, v2, v3, v4
+        b.le            9f
+        mov             v16.16b, v20.16b
+        mov             v17.16b, v21.16b
+        mov             v18.16b, v22.16b
+        mov             v19.16b, v23.16b
+        mov             v20.16b, v24.16b
+        mov             v21.16b, v25.16b
+        mov             v22.16b, v26.16b
+        b               88b
+9:
+        subs            \w,  \w,  #8
+        b.le            0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        msub            \src, \s_strd, \xmy, \src
+        msub            \dst, \d_strd, \xmy, \dst
+        sub             \src, \src, \s_strd, lsl #3
+        mov             \h,  \my
+        add             \src, \src, #16
+        add             \dst, \dst, #16
+        b               168b
+0:
+        ret
+
+160:
+        AARCH64_VALID_JUMP_TARGET
+        b.gt            1680b
+
+        // 16x2, 16x4 v
+        ldur            s0,  [\xmy, #2]
+        sub             \src, \src, \s_strd
+        sxtl            v0.8h,   v0.8b
+
+        load_16h        \src, \src, \s_strd, v16, v17, v18, v19, v20, v21
+16:
+        load_16h        \src, \src, \s_strd, v22, v23
+        subs            \h,  \h,  #1
+        smull_smlal_4tap   v1, v16, v18, v20, v22
+        smull2_smlal2_4tap v2, v16, v18, v20, v22
+        smull_smlal_4tap   v3, v17, v19, v21, v23
+        smull2_smlal2_4tap v4, v17, v19, v21, v23
+        shift_store_16  \type, \d_strd, x0, v1, v2, v3, v4
+        b.le            0f
+        mov             v16.16b, v18.16b
+        mov             v17.16b, v19.16b
+        mov             v18.16b, v20.16b
+        mov             v19.16b, v21.16b
+        mov             v20.16b, v22.16b
+        mov             v21.16b, v23.16b
+        b               16b
+0:
+        ret
+endfunc
+
+jumptable \type\()_\taps\()_v_tbl
+        .word 1280b - \type\()_\taps\()_v_tbl
+        .word 640b  - \type\()_\taps\()_v_tbl
+        .word 320b  - \type\()_\taps\()_v_tbl
+        .word 160b  - \type\()_\taps\()_v_tbl
+        .word 80b   - \type\()_\taps\()_v_tbl
+        .word 40b   - \type\()_\taps\()_v_tbl
+        .word 20b   - \type\()_\taps\()_v_tbl
+endjumptable
+
+function L(\type\()_\taps\()_hv)
+        cmp             \h,  #4
+        ubfx            w10, \my, #7, #7
+        and             \my, \my, #0x7f
+        b.le            4f
+        mov             \my,  w10
+4:
+        add             \xmy, x11, \my, uxtw #3
+
+        movrel          x10, \type\()_\taps\()_hv_tbl
+        dup             v30.4s,  w12           // 6 - intermediate_bits
+        ldrsw           x9,  [x10, x9, lsl #2]
+        neg             v30.4s,  v30.4s        // -(6-intermediate_bits)
+.ifc \type, put
+        dup             v29.4s,  w13           // 6 + intermediate_bits
+.else
+        movi            v29.8h,  #(PREP_BIAS >> 8), lsl #8
+.endif
+        add             x10, x10, x9
+.ifc \type, put
+        neg             v29.4s,  v29.4s        // -(6+intermediate_bits)
+.endif
+        br              x10
+
+20:
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        ldur            s0,  [\xmx, #2]
+        b.gt            280f
+        ldur            s1,  [\xmy, #2]
+
+        // 2x2, 2x4 hv
+        sub             \sr2, \src, #2
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,   v0.8b
+        sxtl            v1.8h,   v1.8b
+        mov             x15, x30
+
+        ld1             {v27.8h}, [\src], \s_strd
+        ext             v28.16b, v27.16b, v27.16b, #2
+        smull           v27.4s,  v27.4h,  v0.4h
+        smull           v28.4s,  v28.4h,  v0.4h
+        addp            v27.4s,  v27.4s,  v28.4s
+        addp            v16.4s,  v27.4s,  v27.4s
+        srshl           v16.2s,  v16.2s,  v30.2s // -(6-intermediate_bits)
+        bl              L(\type\()_\taps\()_filter_2)
+        // The intermediates from the horizontal pass fit in 16 bit without
+        // any bias; we could just as well keep them as .4s, but narrowing
+        // them to .4h gives a significant speedup on out of order cores
+        // (at the cost of a smaller slowdown on in-order cores such as A53).
+        xtn             v16.4h,  v16.4s
+
+        trn1            v16.2s,  v16.2s,  v24.2s
+        mov             v17.8b,  v24.8b
+
+2:
+        bl              L(\type\()_\taps\()_filter_2)
+
+        ext             v18.8b,  v17.8b,  v24.8b,  #4
+        smull           v2.4s,   v16.4h,  v1.h[0]
+        smlal           v2.4s,   v17.4h,  v1.h[1]
+        smlal           v2.4s,   v18.4h,  v1.h[2]
+        smlal           v2.4s,   v24.4h,  v1.h[3]
+
+        srshl           v2.4s,   v2.4s,   v29.4s // -(6+intermediate_bits)
+        sqxtun          v2.4h,   v2.4s
+        umin            v2.4h,   v2.4h,   v31.4h
+        subs            \h,  \h,  #2
+        st1             {v2.s}[0], [\dst], \d_strd
+        st1             {v2.s}[1], [\ds2], \d_strd
+        b.le            0f
+        mov             v16.8b,  v18.8b
+        mov             v17.8b,  v24.8b
+        b               2b
+
+280:    // 2x8, 2x16, 2x32 hv
+        ld1             {v1.8b},  [\xmy]
+        sub             \src, \src, #2
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,   v0.8b
+        sxtl            v1.8h,   v1.8b
+        mov             x15, x30
+
+        ld1             {v27.8h}, [\src], \s_strd
+        ext             v28.16b, v27.16b, v27.16b, #2
+        smull           v27.4s,  v27.4h,  v0.4h
+        smull           v28.4s,  v28.4h,  v0.4h
+        addp            v27.4s,  v27.4s,  v28.4s
+        addp            v16.4s,  v27.4s,  v27.4s
+        srshl           v16.2s,  v16.2s,  v30.2s // -(6-intermediate_bits)
+        // The intermediates from the horizontal pass fit in 16 bit without
+        // any bias; we could just as well keep them as .4s, but narrowing
+        // them to .4h gives a significant speedup on out of order cores
+        // (at the cost of a smaller slowdown on in-order cores such as A53).
+
+        bl              L(\type\()_\taps\()_filter_2)
+        xtn             v16.4h,  v16.4s
+        trn1            v16.2s,  v16.2s,  v24.2s
+        mov             v17.8b,  v24.8b
+        bl              L(\type\()_\taps\()_filter_2)
+        ext             v18.8b,  v17.8b,  v24.8b,  #4
+        mov             v19.8b,  v24.8b
+        bl              L(\type\()_\taps\()_filter_2)
+        ext             v20.8b,  v19.8b,  v24.8b,  #4
+        mov             v21.8b,  v24.8b
+
+28:
+        bl              L(\type\()_\taps\()_filter_2)
+        ext             v22.8b,  v21.8b,  v24.8b,  #4
+.ifc \taps, 6tap
+        smull           v3.4s,   v17.4h,  v1.h[1]
+        smlal           v3.4s,   v18.4h,  v1.h[2]
+        smlal           v3.4s,   v19.4h,  v1.h[3]
+        smlal           v3.4s,   v20.4h,  v1.h[4]
+        smlal           v3.4s,   v21.4h,  v1.h[5]
+        smlal           v3.4s,   v22.4h,  v1.h[6]
+.else   // 8tap
+        smull           v3.4s,   v16.4h,  v1.h[0]
+        smlal           v3.4s,   v17.4h,  v1.h[1]
+        smlal           v3.4s,   v18.4h,  v1.h[2]
+        smlal           v3.4s,   v19.4h,  v1.h[3]
+        smlal           v3.4s,   v20.4h,  v1.h[4]
+        smlal           v3.4s,   v21.4h,  v1.h[5]
+        smlal           v3.4s,   v22.4h,  v1.h[6]
+        smlal           v3.4s,   v24.4h,  v1.h[7]
+.endif
+
+        srshl           v3.4s,   v3.4s,   v29.4s // -(6+intermediate_bits)
+        sqxtun          v3.4h,   v3.4s
+        umin            v3.4h,   v3.4h,   v31.4h
+        subs            \h,  \h,  #2
+        st1             {v3.s}[0], [\dst], \d_strd
+        st1             {v3.s}[1], [\ds2], \d_strd
+        b.le            0f
+        mov             v16.8b,  v18.8b
+        mov             v17.8b,  v19.8b
+        mov             v18.8b,  v20.8b
+        mov             v19.8b,  v21.8b
+        mov             v20.8b,  v22.8b
+        mov             v21.8b,  v24.8b
+        b               28b
+
+0:
+        ret             x15
+
+L(\type\()_\taps\()_filter_2):
+        ld1             {v25.8h},  [\sr2], \s_strd
+        ld1             {v27.8h},  [\src], \s_strd
+        ext             v26.16b, v25.16b, v25.16b, #2
+        ext             v28.16b, v27.16b, v27.16b, #2
+        trn1            v24.2s,  v25.2s,  v27.2s
+        trn2            v27.2s,  v25.2s,  v27.2s
+        trn1            v25.2s,  v26.2s,  v28.2s
+        trn2            v28.2s,  v26.2s,  v28.2s
+        smull           v24.4s,  v24.4h,  v0.h[0]
+        smlal           v24.4s,  v25.4h,  v0.h[1]
+        smlal           v24.4s,  v27.4h,  v0.h[2]
+        smlal           v24.4s,  v28.4h,  v0.h[3]
+        srshl           v24.4s,  v24.4s,  v30.4s // -(6-intermediate_bits)
+        xtn             v24.4h,  v24.4s
+        ret
+.endif
+
+40:
+        AARCH64_VALID_JUMP_TARGET
+        ldur            s0,  [\xmx, #2]
+        b.gt            480f
+        ldur            s1,  [\xmy, #2]
+        sub             \sr2, \src, #2
+        sub             \src, \sr2, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,   v0.8b
+        sxtl            v1.8h,   v1.8b
+        mov             x15, x30
+
+        // 4x2, 4x4 hv
+        ld1             {v25.8h}, [\src], \s_strd
+        ext             v26.16b, v25.16b, v25.16b, #2
+        ext             v27.16b, v25.16b, v25.16b, #4
+        ext             v28.16b, v25.16b, v25.16b, #6
+        smull           v25.4s,  v25.4h,  v0.h[0]
+        smlal           v25.4s,  v26.4h,  v0.h[1]
+        smlal           v25.4s,  v27.4h,  v0.h[2]
+        smlal           v25.4s,  v28.4h,  v0.h[3]
+        srshl           v16.4s,  v25.4s,  v30.4s // -(6-intermediate_bits)
+        // The intermediates from the horizontal pass fit in 16 bit without
+        // any bias; we could just as well keep them as .4s, but narrowing
+        // them to .4h gives a significant speedup on out of order cores
+        // (at the cost of a smaller slowdown on in-order cores such as A53).
+        xtn             v16.4h,  v16.4s
+
+        bl              L(\type\()_\taps\()_filter_4)
+        mov             v17.8b,  v24.8b
+        mov             v18.8b,  v25.8b
+
+4:
+        bl              L(\type\()_\taps\()_filter_4)
+        smull           v2.4s,   v16.4h,  v1.h[0]
+        smlal           v2.4s,   v17.4h,  v1.h[1]
+        smlal           v2.4s,   v18.4h,  v1.h[2]
+        smlal           v2.4s,   v24.4h,  v1.h[3]
+        smull           v3.4s,   v17.4h,  v1.h[0]
+        smlal           v3.4s,   v18.4h,  v1.h[1]
+        smlal           v3.4s,   v24.4h,  v1.h[2]
+        smlal           v3.4s,   v25.4h,  v1.h[3]
+.ifc \type, put
+        srshl           v2.4s,   v2.4s,   v29.4s // -(6+intermediate_bits)
+        srshl           v3.4s,   v3.4s,   v29.4s // -(6+intermediate_bits)
+        sqxtun          v2.4h,   v2.4s
+        sqxtun2         v2.8h,   v3.4s
+        umin            v2.8h,   v2.8h,   v31.8h
+.else
+        rshrn           v2.4h,   v2.4s,   #6
+        rshrn2          v2.8h,   v3.4s,   #6
+        sub             v2.8h,   v2.8h,   v29.8h // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+
+        st1             {v2.8b},   [\dst], \d_strd
+        st1             {v2.d}[1], [\ds2], \d_strd
+        b.le            0f
+        mov             v16.8b,  v18.8b
+        mov             v17.8b,  v24.8b
+        mov             v18.8b,  v25.8b
+        b               4b
+
+480:    // 4x8, 4x16, 4x32 hv
+        ld1             {v1.8b},  [\xmy]
+        sub             \src, \src, #2
+.ifc \taps, 6tap
+        sub             \sr2, \src, \s_strd
+        sub             \src, \src, \s_strd, lsl #1
+.else
+        sub             \sr2, \src, \s_strd, lsl #1
+        sub             \src, \sr2, \s_strd
+.endif
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+        sxtl            v0.8h,   v0.8b
+        sxtl            v1.8h,   v1.8b
+        mov             x15, x30
+
+        ld1             {v25.8h}, [\src], \s_strd
+        ext             v26.16b, v25.16b, v25.16b, #2
+        ext             v27.16b, v25.16b, v25.16b, #4
+        ext             v28.16b, v25.16b, v25.16b, #6
+        smull           v25.4s,  v25.4h,  v0.h[0]
+        smlal           v25.4s,  v26.4h,  v0.h[1]
+        smlal           v25.4s,  v27.4h,  v0.h[2]
+        smlal           v25.4s,  v28.4h,  v0.h[3]
+        srshl           v16.4s,  v25.4s,  v30.4s // -(6-intermediate_bits)
+        // The intermediates from the horizontal pass fit in 16 bit without
+        // any bias; we could just as well keep them as .4s, but narrowing
+        // them to .4h gives a significant speedup on out of order cores
+        // (at the cost of a smaller slowdown on in-order cores such as A53).
+.ifc \taps, 6tap
+        xtn             v18.4h,  v16.4s
+.else
+        xtn             v16.4h,  v16.4s
+
+        bl              L(\type\()_\taps\()_filter_4)
+        mov             v17.8b,  v24.8b
+        mov             v18.8b,  v25.8b
+.endif
+        bl              L(\type\()_\taps\()_filter_4)
+        mov             v19.8b,  v24.8b
+        mov             v20.8b,  v25.8b
+        bl              L(\type\()_\taps\()_filter_4)
+        mov             v21.8b,  v24.8b
+        mov             v22.8b,  v25.8b
+
+48:
+        bl              L(\type\()_\taps\()_filter_4)
+.ifc \taps, 6tap
+        smull           v3.4s,   v18.4h,  v1.h[1]
+        smlal           v3.4s,   v19.4h,  v1.h[2]
+        smlal           v3.4s,   v20.4h,  v1.h[3]
+        smlal           v3.4s,   v21.4h,  v1.h[4]
+        smlal           v3.4s,   v22.4h,  v1.h[5]
+        smlal           v3.4s,   v24.4h,  v1.h[6]
+        smull           v4.4s,   v19.4h,  v1.h[1]
+        smlal           v4.4s,   v20.4h,  v1.h[2]
+        smlal           v4.4s,   v21.4h,  v1.h[3]
+        smlal           v4.4s,   v22.4h,  v1.h[4]
+        smlal           v4.4s,   v24.4h,  v1.h[5]
+        smlal           v4.4s,   v25.4h,  v1.h[6]
+.else   // 8tap
+        smull           v3.4s,   v16.4h,  v1.h[0]
+        smlal           v3.4s,   v17.4h,  v1.h[1]
+        smlal           v3.4s,   v18.4h,  v1.h[2]
+        smlal           v3.4s,   v19.4h,  v1.h[3]
+        smlal           v3.4s,   v20.4h,  v1.h[4]
+        smlal           v3.4s,   v21.4h,  v1.h[5]
+        smlal           v3.4s,   v22.4h,  v1.h[6]
+        smlal           v3.4s,   v24.4h,  v1.h[7]
+        smull           v4.4s,   v17.4h,  v1.h[0]
+        smlal           v4.4s,   v18.4h,  v1.h[1]
+        smlal           v4.4s,   v19.4h,  v1.h[2]
+        smlal           v4.4s,   v20.4h,  v1.h[3]
+        smlal           v4.4s,   v21.4h,  v1.h[4]
+        smlal           v4.4s,   v22.4h,  v1.h[5]
+        smlal           v4.4s,   v24.4h,  v1.h[6]
+        smlal           v4.4s,   v25.4h,  v1.h[7]
+.endif
+.ifc \type, put
+        srshl           v3.4s,   v3.4s,   v29.4s // -(6+intermediate_bits)
+        srshl           v4.4s,   v4.4s,   v29.4s // -(6+intermediate_bits)
+        sqxtun          v3.4h,   v3.4s
+        sqxtun2         v3.8h,   v4.4s
+        umin            v3.8h,   v3.8h,   v31.8h
+.else
+        rshrn           v3.4h,   v3.4s,   #6
+        rshrn2          v3.8h,   v4.4s,   #6
+        sub             v3.8h,   v3.8h,   v29.8h // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        st1             {v3.8b},   [\dst], \d_strd
+        st1             {v3.d}[1], [\ds2], \d_strd
+        b.le            0f
+.ifc \taps, 8tap
+        mov             v16.8b,  v18.8b
+        mov             v17.8b,  v19.8b
+.endif
+        mov             v18.8b,  v20.8b
+        mov             v19.8b,  v21.8b
+        mov             v20.8b,  v22.8b
+        mov             v21.8b,  v24.8b
+        mov             v22.8b,  v25.8b
+        b               48b
+0:
+        ret             x15
+
+L(\type\()_\taps\()_filter_4):
+        ld1             {v24.8h}, [\sr2], \s_strd
+        ld1             {v25.8h}, [\src], \s_strd
+        ext             v26.16b, v24.16b, v24.16b, #2
+        ext             v27.16b, v24.16b, v24.16b, #4
+        ext             v28.16b, v24.16b, v24.16b, #6
+        smull           v24.4s,  v24.4h,  v0.h[0]
+        smlal           v24.4s,  v26.4h,  v0.h[1]
+        smlal           v24.4s,  v27.4h,  v0.h[2]
+        smlal           v24.4s,  v28.4h,  v0.h[3]
+        ext             v26.16b, v25.16b, v25.16b, #2
+        ext             v27.16b, v25.16b, v25.16b, #4
+        ext             v28.16b, v25.16b, v25.16b, #6
+        smull           v25.4s,  v25.4h,  v0.h[0]
+        smlal           v25.4s,  v26.4h,  v0.h[1]
+        smlal           v25.4s,  v27.4h,  v0.h[2]
+        smlal           v25.4s,  v28.4h,  v0.h[3]
+        srshl           v24.4s,  v24.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v25.4s,  v25.4s,  v30.4s // -(6-intermediate_bits)
+        xtn             v24.4h,  v24.4s
+        xtn             v25.4h,  v25.4s
+        ret
+
+80:
+160:
+320:
+        AARCH64_VALID_JUMP_TARGET
+        b.gt            880f
+        ld1             {v0.8b},  [\xmx]
+        ldur            s1,  [\xmy, #2]
+.ifc \taps, 6tap
+        sub             \src,  \src,  #4
+.else
+        sub             \src,  \src,  #6
+.endif
+        sub             \src,  \src,  \s_strd
+        sxtl            v0.8h,   v0.8b
+        sxtl            v1.8h,   v1.8b
+        mov             x15, x30
+        mov             \my, \h
+
+164:    // 8x2, 8x4, 16x2, 16x4, 32x2, 32x4 hv
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        ld1             {v27.8h, v28.8h},  [\src], \s_strd
+.ifc \taps, 6tap
+        smull           v24.4s,  v27.4h,  v0.h[1]
+        smull2          v25.4s,  v27.8h,  v0.h[1]
+    .irpc i, 23456
+        ext             v26.16b, v27.16b, v28.16b, #(2*\i-2)
+        smlal           v24.4s,  v26.4h,  v0.h[\i]
+        smlal2          v25.4s,  v26.8h,  v0.h[\i]
+    .endr
+.else
+        smull           v24.4s,  v27.4h,  v0.h[0]
+        smull2          v25.4s,  v27.8h,  v0.h[0]
+    .irpc i, 1234567
+        ext             v26.16b, v27.16b, v28.16b, #(2*\i)
+        smlal           v24.4s,  v26.4h,  v0.h[\i]
+        smlal2          v25.4s,  v26.8h,  v0.h[\i]
+    .endr
+.endif
+        srshl           v24.4s,  v24.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v25.4s,  v25.4s,  v30.4s // -(6-intermediate_bits)
+        // The intermediates from the horizontal pass fit in 16 bit without
+        // any bias; we could just as well keep them as .4s, but narrowing
+        // them to .4h gives a significant speedup on out of order cores
+        // (at the cost of a smaller slowdown on in-order cores such as A53),
+        // and conserves register space (no need to clobber v8-v15).
+        uzp1            v16.8h,  v24.8h,  v25.8h // Same as xtn, xtn2
+
+        bl              L(\type\()_\taps\()_filter_8)
+        mov             v17.16b, v23.16b
+        mov             v18.16b, v24.16b
+
+8:
+        smull           v2.4s,   v16.4h,  v1.h[0]
+        smull2          v3.4s,   v16.8h,  v1.h[0]
+        bl              L(\type\()_\taps\()_filter_8)
+        smull           v4.4s,   v17.4h,  v1.h[0]
+        smull2          v5.4s,   v17.8h,  v1.h[0]
+        smlal           v2.4s,   v17.4h,  v1.h[1]
+        smlal2          v3.4s,   v17.8h,  v1.h[1]
+        smlal           v4.4s,   v18.4h,  v1.h[1]
+        smlal2          v5.4s,   v18.8h,  v1.h[1]
+        smlal           v2.4s,   v18.4h,  v1.h[2]
+        smlal2          v3.4s,   v18.8h,  v1.h[2]
+        smlal           v4.4s,   v23.4h,  v1.h[2]
+        smlal2          v5.4s,   v23.8h,  v1.h[2]
+        smlal           v2.4s,   v23.4h,  v1.h[3]
+        smlal2          v3.4s,   v23.8h,  v1.h[3]
+        smlal           v4.4s,   v24.4h,  v1.h[3]
+        smlal2          v5.4s,   v24.8h,  v1.h[3]
+.ifc \type, put
+        srshl           v2.4s,   v2.4s,   v29.4s // -(6+intermediate_bits)
+        srshl           v3.4s,   v3.4s,   v29.4s // -(6+intermediate_bits)
+        srshl           v4.4s,   v4.4s,   v29.4s // -(6+intermediate_bits)
+        srshl           v5.4s,   v5.4s,   v29.4s // -(6+intermediate_bits)
+        sqxtun          v2.4h,   v2.4s
+        sqxtun2         v2.8h,   v3.4s
+        sqxtun          v3.4h,   v4.4s
+        sqxtun2         v3.8h,   v5.4s
+        umin            v2.8h,   v2.8h,   v31.8h
+        umin            v3.8h,   v3.8h,   v31.8h
+.else
+        rshrn           v2.4h,   v2.4s,   #6
+        rshrn2          v2.8h,   v3.4s,   #6
+        rshrn           v3.4h,   v4.4s,   #6
+        rshrn2          v3.8h,   v5.4s,   #6
+        sub             v2.8h,   v2.8h,   v29.8h // PREP_BIAS
+        sub             v3.8h,   v3.8h,   v29.8h // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        st1             {v2.8h}, [\dst], \d_strd
+        st1             {v3.8h}, [\ds2], \d_strd
+        b.le            9f
+        mov             v16.16b, v18.16b
+        mov             v17.16b, v23.16b
+        mov             v18.16b, v24.16b
+        b               8b
+9:
+        subs            \w,  \w,  #8
+        b.le            0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        msub            \src,  \s_strd,  \xmy,  \src
+        msub            \dst,  \d_strd,  \xmy,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #2
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+        b               164b
+
+880:    // 8x8, 8x16, ..., 16x8, ..., 32x8, ... hv
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        ld1             {v0.8b},  [\xmx]
+        ld1             {v1.8b},  [\xmy]
+.ifc \taps, 6tap
+        sub             \src,  \src,  #4
+.else
+        sub             \src,  \src,  #6
+        sub             \src,  \src,  \s_strd
+.endif
+        sub             \src,  \src,  \s_strd, lsl #1
+        sxtl            v0.8h,   v0.8b
+        sxtl            v1.8h,   v1.8b
+        mov             x15, x30
+        mov             \my, \h
+
+168:
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd, \d_strd, #1
+        lsl             \s_strd, \s_strd, #1
+
+        ld1             {v27.8h, v28.8h},  [\src], \s_strd
+.ifc \taps, 6tap
+        smull           v24.4s,  v27.4h,  v0.h[1]
+        smull2          v25.4s,  v27.8h,  v0.h[1]
+    .irpc i, 23456
+        ext             v26.16b, v27.16b, v28.16b, #(2*\i-2)
+        smlal           v24.4s,  v26.4h,  v0.h[\i]
+        smlal2          v25.4s,  v26.8h,  v0.h[\i]
+    .endr
+.else   // 8tap
+        smull           v24.4s,  v27.4h,  v0.h[0]
+        smull2          v25.4s,  v27.8h,  v0.h[0]
+    .irpc i, 1234567
+        ext             v26.16b, v27.16b, v28.16b, #(2*\i)
+        smlal           v24.4s,  v26.4h,  v0.h[\i]
+        smlal2          v25.4s,  v26.8h,  v0.h[\i]
+    .endr
+.endif
+        srshl           v24.4s,  v24.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v25.4s,  v25.4s,  v30.4s // -(6-intermediate_bits)
+        // The intermediates from the horizontal pass fit in 16 bit without
+        // any bias; we could just as well keep them as .4s, but narrowing
+        // them to .4h gives a significant speedup on out of order cores
+        // (at the cost of a smaller slowdown on in-order cores such as A53),
+        // and conserves register space (no need to clobber v8-v15).
+.ifc \taps, 6tap
+        uzp1            v18.8h,  v24.8h,  v25.8h // Same as xtn, xtn2
+.else
+        uzp1            v16.8h,  v24.8h,  v25.8h // Same as xtn, xtn2
+
+        bl              L(\type\()_\taps\()_filter_8)
+        mov             v17.16b, v23.16b
+        mov             v18.16b, v24.16b
+.endif
+        bl              L(\type\()_\taps\()_filter_8)
+        mov             v19.16b, v23.16b
+        mov             v20.16b, v24.16b
+        bl              L(\type\()_\taps\()_filter_8)
+        mov             v21.16b, v23.16b
+        mov             v22.16b, v24.16b
+
+88:
+.ifc \taps, 6tap
+        smull           v2.4s,   v18.4h,  v1.h[1]
+        smull2          v3.4s,   v18.8h,  v1.h[1]
+        bl              L(\type\()_\taps\()_filter_8)
+        smull           v4.4s,   v19.4h,  v1.h[1]
+        smull2          v5.4s,   v19.8h,  v1.h[1]
+        smlal           v2.4s,   v19.4h,  v1.h[2]
+        smlal2          v3.4s,   v19.8h,  v1.h[2]
+        smlal           v4.4s,   v20.4h,  v1.h[2]
+        smlal2          v5.4s,   v20.8h,  v1.h[2]
+        smlal           v2.4s,   v20.4h,  v1.h[3]
+        smlal2          v3.4s,   v20.8h,  v1.h[3]
+        smlal           v4.4s,   v21.4h,  v1.h[3]
+        smlal2          v5.4s,   v21.8h,  v1.h[3]
+        smlal           v2.4s,   v21.4h,  v1.h[4]
+        smlal2          v3.4s,   v21.8h,  v1.h[4]
+        smlal           v4.4s,   v22.4h,  v1.h[4]
+        smlal2          v5.4s,   v22.8h,  v1.h[4]
+        smlal           v2.4s,   v22.4h,  v1.h[5]
+        smlal2          v3.4s,   v22.8h,  v1.h[5]
+        smlal           v4.4s,   v23.4h,  v1.h[5]
+        smlal2          v5.4s,   v23.8h,  v1.h[5]
+        smlal           v2.4s,   v23.4h,  v1.h[6]
+        smlal2          v3.4s,   v23.8h,  v1.h[6]
+        smlal           v4.4s,   v24.4h,  v1.h[6]
+        smlal2          v5.4s,   v24.8h,  v1.h[6]
+.else   // 8tap
+        smull           v2.4s,   v16.4h,  v1.h[0]
+        smull2          v3.4s,   v16.8h,  v1.h[0]
+        bl              L(\type\()_\taps\()_filter_8)
+        smull           v4.4s,   v17.4h,  v1.h[0]
+        smull2          v5.4s,   v17.8h,  v1.h[0]
+        smlal           v2.4s,   v17.4h,  v1.h[1]
+        smlal2          v3.4s,   v17.8h,  v1.h[1]
+        smlal           v4.4s,   v18.4h,  v1.h[1]
+        smlal2          v5.4s,   v18.8h,  v1.h[1]
+        smlal           v2.4s,   v18.4h,  v1.h[2]
+        smlal2          v3.4s,   v18.8h,  v1.h[2]
+        smlal           v4.4s,   v19.4h,  v1.h[2]
+        smlal2          v5.4s,   v19.8h,  v1.h[2]
+        smlal           v2.4s,   v19.4h,  v1.h[3]
+        smlal2          v3.4s,   v19.8h,  v1.h[3]
+        smlal           v4.4s,   v20.4h,  v1.h[3]
+        smlal2          v5.4s,   v20.8h,  v1.h[3]
+        smlal           v2.4s,   v20.4h,  v1.h[4]
+        smlal2          v3.4s,   v20.8h,  v1.h[4]
+        smlal           v4.4s,   v21.4h,  v1.h[4]
+        smlal2          v5.4s,   v21.8h,  v1.h[4]
+        smlal           v2.4s,   v21.4h,  v1.h[5]
+        smlal2          v3.4s,   v21.8h,  v1.h[5]
+        smlal           v4.4s,   v22.4h,  v1.h[5]
+        smlal2          v5.4s,   v22.8h,  v1.h[5]
+        smlal           v2.4s,   v22.4h,  v1.h[6]
+        smlal2          v3.4s,   v22.8h,  v1.h[6]
+        smlal           v4.4s,   v23.4h,  v1.h[6]
+        smlal2          v5.4s,   v23.8h,  v1.h[6]
+        smlal           v2.4s,   v23.4h,  v1.h[7]
+        smlal2          v3.4s,   v23.8h,  v1.h[7]
+        smlal           v4.4s,   v24.4h,  v1.h[7]
+        smlal2          v5.4s,   v24.8h,  v1.h[7]
+.endif
+.ifc \type, put
+        srshl           v2.4s,   v2.4s,   v29.4s // -(6+intermediate_bits)
+        srshl           v3.4s,   v3.4s,   v29.4s // -(6+intermediate_bits)
+        srshl           v4.4s,   v4.4s,   v29.4s // -(6+intermediate_bits)
+        srshl           v5.4s,   v5.4s,   v29.4s // -(6+intermediate_bits)
+        sqxtun          v2.4h,   v2.4s
+        sqxtun2         v2.8h,   v3.4s
+        sqxtun          v3.4h,   v4.4s
+        sqxtun2         v3.8h,   v5.4s
+        umin            v2.8h,   v2.8h,   v31.8h
+        umin            v3.8h,   v3.8h,   v31.8h
+.else
+        rshrn           v2.4h,   v2.4s,   #6
+        rshrn2          v2.8h,   v3.4s,   #6
+        rshrn           v3.4h,   v4.4s,   #6
+        rshrn2          v3.8h,   v5.4s,   #6
+        sub             v2.8h,   v2.8h,   v29.8h // PREP_BIAS
+        sub             v3.8h,   v3.8h,   v29.8h // PREP_BIAS
+.endif
+        subs            \h,  \h,  #2
+        st1             {v2.8h}, [\dst], \d_strd
+        st1             {v3.8h}, [\ds2], \d_strd
+        b.le            9f
+.ifc \taps, 8tap
+        mov             v16.16b, v18.16b
+        mov             v17.16b, v19.16b
+.endif
+        mov             v18.16b, v20.16b
+        mov             v19.16b, v21.16b
+        mov             v20.16b, v22.16b
+        mov             v21.16b, v23.16b
+        mov             v22.16b, v24.16b
+        b               88b
+9:
+        subs            \w,  \w,  #8
+        b.le            0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        msub            \src,  \s_strd,  \xmy,  \src
+        msub            \dst,  \d_strd,  \xmy,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #3
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+.ifc \taps, 6tap
+        add             \src,  \src,  \s_strd,  lsl #1
+.endif
+        b               168b
+0:
+        ret             x15
+
+L(\type\()_\taps\()_filter_8):
+        ld1             {v4.8h, v5.8h},  [\sr2], \s_strd
+        ld1             {v6.8h, v7.8h},  [\src], \s_strd
+.ifc \taps, 6tap
+        smull           v25.4s,  v4.4h,   v0.h[1]
+        smull2          v26.4s,  v4.8h,   v0.h[1]
+        smull           v27.4s,  v6.4h,   v0.h[1]
+        smull2          v28.4s,  v6.8h,   v0.h[1]
+.irpc i, 23456
+        ext             v23.16b, v4.16b,  v5.16b,  #(2*\i-2)
+        ext             v24.16b, v6.16b,  v7.16b,  #(2*\i-2)
+        smlal           v25.4s,  v23.4h,  v0.h[\i]
+        smlal2          v26.4s,  v23.8h,  v0.h[\i]
+        smlal           v27.4s,  v24.4h,  v0.h[\i]
+        smlal2          v28.4s,  v24.8h,  v0.h[\i]
+.endr
+.else   // 8tap
+        smull           v25.4s,  v4.4h,   v0.h[0]
+        smull2          v26.4s,  v4.8h,   v0.h[0]
+        smull           v27.4s,  v6.4h,   v0.h[0]
+        smull2          v28.4s,  v6.8h,   v0.h[0]
+.irpc i, 1234567
+        ext             v23.16b, v4.16b,  v5.16b,  #(2*\i)
+        ext             v24.16b, v6.16b,  v7.16b,  #(2*\i)
+        smlal           v25.4s,  v23.4h,  v0.h[\i]
+        smlal2          v26.4s,  v23.8h,  v0.h[\i]
+        smlal           v27.4s,  v24.4h,  v0.h[\i]
+        smlal2          v28.4s,  v24.8h,  v0.h[\i]
+.endr
+.endif
+        srshl           v25.4s,  v25.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v26.4s,  v26.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v27.4s,  v27.4s,  v30.4s // -(6-intermediate_bits)
+        srshl           v28.4s,  v28.4s,  v30.4s // -(6-intermediate_bits)
+        uzp1            v23.8h,  v25.8h,  v26.8h // Same as xtn, xtn2
+        uzp1            v24.8h,  v27.8h,  v28.8h // Ditto
+        ret
+endfunc
+
+jumptable \type\()_\taps\()_hv_tbl
+        .word 1280b - \type\()_\taps\()_hv_tbl
+        .word 640b  - \type\()_\taps\()_hv_tbl
+        .word 320b  - \type\()_\taps\()_hv_tbl
+        .word 160b  - \type\()_\taps\()_hv_tbl
+        .word 80b   - \type\()_\taps\()_hv_tbl
+        .word 40b   - \type\()_\taps\()_hv_tbl
+        .word 20b   - \type\()_\taps\()_hv_tbl
+endjumptable
+.endm
+
+
+.macro filter_bilin_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, bdmax, ds2, sr2
+function \type\()_bilin_16bpc_neon, export=1
+.ifc \bdmax, w8
+        ldr             w8,  [sp]
+.endif
+        dup             v1.8h,   \mx
+        dup             v3.8h,   \my
+        mov             w10, #16
+        sub             w9,  w10, \mx
+        sub             w10, w10, \my
+        dup             v0.8h,   w9
+        dup             v2.8h,   w10
+.ifc \type, prep
+        uxtw            \d_strd, \w
+        lsl             \d_strd, \d_strd, #1
+.endif
+
+        clz             \bdmax,   \bdmax       // bitdepth_max
+        clz             w9,  \w
+        sub             \bdmax,   \bdmax,  #18 // intermediate_bits = clz(bitdepth_max) - 18
+        mov             w11, #4
+        sub             w9,  w9,  #24
+        sub             w11, w11, \bdmax  // 4 - intermediate_bits
+        add             w12, \bdmax, #4   // 4 + intermediate_bits
+        cbnz            \mx, L(\type\()_bilin_h)
+        cbnz            \my, L(\type\()_bilin_v)
+        b               \type\()_16bpc_neon
+
+L(\type\()_bilin_h):
+        cbnz            \my, L(\type\()_bilin_hv)
+
+        movrel          x10, \type\()_bilin_h_tbl
+        dup             v31.8h,  w11      // 4 - intermediate_bits
+        ldrsw           x9,  [x10, x9, lsl #2]
+        neg             v31.8h,  v31.8h   // -(4-intermediate_bits)
+.ifc \type, put
+        dup             v30.8h,  \bdmax   // intermediate_bits
+.else
+        movi            v29.8h,  #(PREP_BIAS >> 8), lsl #8
+.endif
+        add             x10, x10, x9
+.ifc \type, put
+        neg             v30.8h,  v30.8h   // -intermediate_bits
+.endif
+        br              x10
+
+20:     // 2xN h
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+2:
+        ld1             {v4.4h},  [\src], \s_strd
+        ld1             {v6.4h},  [\sr2], \s_strd
+        ext             v5.8b,   v4.8b,   v4.8b,   #2
+        ext             v7.8b,   v6.8b,   v6.8b,   #2
+        trn1            v4.2s,   v4.2s,   v6.2s
+        trn1            v5.2s,   v5.2s,   v7.2s
+        subs            \h,  \h,  #2
+        mul             v4.4h,   v4.4h,   v0.4h
+        mla             v4.4h,   v5.4h,   v1.4h
+        urshl           v4.4h,   v4.4h,   v31.4h
+        urshl           v4.4h,   v4.4h,   v30.4h
+        st1             {v4.s}[0], [\dst], \d_strd
+        st1             {v4.s}[1], [\ds2], \d_strd
+        b.gt            2b
+        ret
+.endif
+
+40:     // 4xN h
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+4:
+        ld1             {v4.8h}, [\src], \s_strd
+        ld1             {v6.8h}, [\sr2], \s_strd
+        ext             v5.16b,  v4.16b,  v4.16b,  #2
+        ext             v7.16b,  v6.16b,  v6.16b,  #2
+        trn1            v4.2d,   v4.2d,   v6.2d
+        trn1            v5.2d,   v5.2d,   v7.2d
+        subs            \h,  \h,  #2
+        mul             v4.8h,   v4.8h,   v0.8h
+        mla             v4.8h,   v5.8h,   v1.8h
+        urshl           v4.8h,   v4.8h,   v31.8h
+.ifc \type, put
+        urshl           v4.8h,   v4.8h,   v30.8h
+.else
+        sub             v4.8h,   v4.8h,   v29.8h
+.endif
+        st1             {v4.8b},   [\dst], \d_strd
+        st1             {v4.d}[1], [\ds2], \d_strd
+        b.gt            4b
+        ret
+
+80:     // 8xN h
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \d_strd,  \d_strd,  #1
+        lsl             \s_strd,  \s_strd,  #1
+8:
+        ldr             h5,  [\src, #16]
+        ldr             h7,  [\sr2, #16]
+        ld1             {v4.8h}, [\src], \s_strd
+        ld1             {v6.8h}, [\sr2], \s_strd
+        ext             v5.16b,  v4.16b,  v5.16b,  #2
+        ext             v7.16b,  v6.16b,  v7.16b,  #2
+        subs            \h,  \h,  #2
+        mul             v4.8h,   v4.8h,   v0.8h
+        mla             v4.8h,   v5.8h,   v1.8h
+        mul             v6.8h,   v6.8h,   v0.8h
+        mla             v6.8h,   v7.8h,   v1.8h
+        urshl           v4.8h,   v4.8h,   v31.8h
+        urshl           v6.8h,   v6.8h,   v31.8h
+.ifc \type, put
+        urshl           v4.8h,   v4.8h,   v30.8h
+        urshl           v6.8h,   v6.8h,   v30.8h
+.else
+        sub             v4.8h,   v4.8h,   v29.8h
+        sub             v6.8h,   v6.8h,   v29.8h
+.endif
+        st1             {v4.8h}, [\dst], \d_strd
+        st1             {v6.8h}, [\ds2], \d_strd
+        b.gt            8b
+        ret
+160:
+320:
+640:
+1280:   // 16xN, 32xN, ... h
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+
+        sub             \s_strd,  \s_strd,  \w, uxtw #1
+        sub             \s_strd,  \s_strd,  #16
+.ifc \type, put
+        lsl             \d_strd,  \d_strd,  #1
+        sub             \d_strd,  \d_strd,  \w, uxtw #1
+.endif
+161:
+        ld1             {v16.8h},  [\src], #16
+        ld1             {v21.8h},  [\sr2], #16
+        mov             \mx, \w
+
+16:
+        ld1             {v17.8h, v18.8h},  [\src], #32
+        ld1             {v22.8h, v23.8h},  [\sr2], #32
+        ext             v19.16b, v16.16b, v17.16b, #2
+        ext             v20.16b, v17.16b, v18.16b, #2
+        ext             v24.16b, v21.16b, v22.16b, #2
+        ext             v25.16b, v22.16b, v23.16b, #2
+        mul             v16.8h,  v16.8h,  v0.8h
+        mla             v16.8h,  v19.8h,  v1.8h
+        mul             v17.8h,  v17.8h,  v0.8h
+        mla             v17.8h,  v20.8h,  v1.8h
+        mul             v21.8h,  v21.8h,  v0.8h
+        mla             v21.8h,  v24.8h,  v1.8h
+        mul             v22.8h,  v22.8h,  v0.8h
+        mla             v22.8h,  v25.8h,  v1.8h
+        urshl           v16.8h,  v16.8h,  v31.8h
+        urshl           v17.8h,  v17.8h,  v31.8h
+        urshl           v21.8h,  v21.8h,  v31.8h
+        urshl           v22.8h,  v22.8h,  v31.8h
+        subs            \mx, \mx, #16
+.ifc \type, put
+        urshl           v16.8h,  v16.8h,  v30.8h
+        urshl           v17.8h,  v17.8h,  v30.8h
+        urshl           v21.8h,  v21.8h,  v30.8h
+        urshl           v22.8h,  v22.8h,  v30.8h
+.else
+        sub             v16.8h,  v16.8h,  v29.8h
+        sub             v17.8h,  v17.8h,  v29.8h
+        sub             v21.8h,  v21.8h,  v29.8h
+        sub             v22.8h,  v22.8h,  v29.8h
+.endif
+        st1             {v16.8h, v17.8h}, [\dst], #32
+        st1             {v21.8h, v22.8h}, [\ds2], #32
+        b.le            9f
+
+        mov             v16.16b, v18.16b
+        mov             v21.16b, v23.16b
+        b               16b
+
+9:
+        add             \dst,  \dst,  \d_strd
+        add             \ds2,  \ds2,  \d_strd
+        add             \src,  \src,  \s_strd
+        add             \sr2,  \sr2,  \s_strd
+
+        subs            \h,  \h,  #2
+        b.gt            161b
+        ret
+endfunc
+
+jumptable \type\()_bilin_h_tbl
+        .word 1280b - \type\()_bilin_h_tbl
+        .word 640b  - \type\()_bilin_h_tbl
+        .word 320b  - \type\()_bilin_h_tbl
+        .word 160b  - \type\()_bilin_h_tbl
+        .word 80b   - \type\()_bilin_h_tbl
+        .word 40b   - \type\()_bilin_h_tbl
+        .word 20b   - \type\()_bilin_h_tbl
+endjumptable
+
+
+function L(\type\()_bilin_v)
+        cmp             \h,  #4
+        movrel          x10, \type\()_bilin_v_tbl
+.ifc \type, prep
+        dup             v31.8h,  w11      // 4 - intermediate_bits
+.endif
+        ldrsw           x9,  [x10, x9, lsl #2]
+.ifc \type, prep
+        movi            v29.8h,  #(PREP_BIAS >> 8), lsl #8
+        neg             v31.8h,  v31.8h   // -(4-intermediate_bits)
+.endif
+        add             x10, x10, x9
+        br              x10
+
+20:     // 2xN v
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        cmp             \h,  #2
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+
+        // 2x2 v
+        ld1r            {v16.4s}, [\src], \s_strd
+        b.gt            24f
+22:
+        ld1r            {v17.4s}, [\sr2], \s_strd
+        ld1r            {v18.4s}, [\src], \s_strd
+        trn1            v16.2s,  v16.2s,  v17.2s
+        trn1            v17.2s,  v17.2s,  v18.2s
+        mul             v4.4h,   v16.4h,  v2.4h
+        mla             v4.4h,   v17.4h,  v3.4h
+        urshr           v4.8h,   v4.8h,   #4
+        str             s4,        [\dst]
+        st1             {v4.s}[1], [\ds2]
+        ret
+24:     // 2x4, 2x6, 2x8, ... v
+        ld1r            {v17.4s}, [\sr2], \s_strd
+        ld1r            {v18.4s}, [\src], \s_strd
+        ld1r            {v19.4s}, [\sr2], \s_strd
+        ld1r            {v20.4s}, [\src], \s_strd
+        sub             \h,  \h,  #4
+        trn1            v16.2s,  v16.2s,  v17.2s
+        trn1            v17.2s,  v17.2s,  v18.2s
+        trn1            v18.2s,  v18.2s,  v19.2s
+        trn1            v19.2s,  v19.2s,  v20.2s
+        trn1            v16.2d,  v16.2d,  v18.2d
+        trn1            v17.2d,  v17.2d,  v19.2d
+        mul             v4.8h,   v16.8h,  v2.8h
+        mla             v4.8h,   v17.8h,  v3.8h
+        cmp             \h,  #2
+        urshr           v4.8h,   v4.8h,   #4
+        st1             {v4.s}[0], [\dst], \d_strd
+        st1             {v4.s}[1], [\ds2], \d_strd
+        st1             {v4.s}[2], [\dst], \d_strd
+        st1             {v4.s}[3], [\ds2], \d_strd
+        b.lt            0f
+        mov             v16.8b,  v20.8b
+        b.eq            22b
+        b               24b
+0:
+        ret
+.endif
+
+40:     // 4xN v
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        ld1             {v16.4h}, [\src], \s_strd
+4:
+        ld1             {v17.4h}, [\sr2], \s_strd
+        ld1             {v18.4h}, [\src], \s_strd
+        trn1            v16.2d,  v16.2d,  v17.2d
+        trn1            v17.2d,  v17.2d,  v18.2d
+        mul             v4.8h,   v16.8h,  v2.8h
+        mla             v4.8h,   v17.8h,  v3.8h
+        subs            \h,  \h,  #2
+.ifc \type, put
+        urshr           v4.8h,   v4.8h,   #4
+.else
+        urshl           v4.8h,   v4.8h,   v31.8h
+        sub             v4.8h,   v4.8h,   v29.8h
+.endif
+        st1             {v4.8b},   [\dst], \d_strd
+        st1             {v4.d}[1], [\ds2], \d_strd
+        b.le            0f
+        mov             v16.8b,  v18.8b
+        b               4b
+0:
+        ret
+
+80:     // 8xN v
+        AARCH64_VALID_JUMP_TARGET
+        add             \ds2,  \dst,  \d_strd
+        add             \sr2,  \src,  \s_strd
+        lsl             \s_strd,  \s_strd,  #1
+        lsl             \d_strd,  \d_strd,  #1
+        ld1             {v16.8h}, [\src], \s_strd
+8:
+        ld1             {v17.8h}, [\sr2], \s_strd
+        ld1             {v18.8h}, [\src], \s_strd
+        mul             v4.8h,   v16.8h,  v2.8h
+        mla             v4.8h,   v17.8h,  v3.8h
+        mul             v5.8h,   v17.8h,  v2.8h
+        mla             v5.8h,   v18.8h,  v3.8h
+        subs            \h,  \h,  #2
+.ifc \type, put
+        urshr           v4.8h,   v4.8h,   #4
+        urshr           v5.8h,   v5.8h,   #4
+.else
+        urshl           v4.8h,   v4.8h,   v31.8h
+        urshl           v5.8h,   v5.8h,   v31.8h
+        sub             v4.8h,   v4.8h,   v29.8h
+        sub             v5.8h,   v5.8h,   v29.8h
+.endif
+        st1             {v4.8h}, [\dst], \d_strd
+        st1             {v5.8h}, [\ds2], \d_strd
+        b.le            0f
+        mov             v16.16b, v18.16b
+        b               8b
+0:
+        ret
+
+160:    // 16xN, 32xN, ...
+320:
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        mov             \my, \h
+1:
+        add             \ds2, \dst, \d_strd
+        add             \sr2, \src, \s_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        ld1             {v16.8h, v17.8h}, [\src], \s_strd
+2:
+        ld1             {v18.8h, v19.8h}, [\sr2], \s_strd
+        ld1             {v20.8h, v21.8h}, [\src], \s_strd
+        mul             v4.8h,   v16.8h,  v2.8h
+        mla             v4.8h,   v18.8h,  v3.8h
+        mul             v5.8h,   v17.8h,  v2.8h
+        mla             v5.8h,   v19.8h,  v3.8h
+        mul             v6.8h,   v18.8h,  v2.8h
+        mla             v6.8h,   v20.8h,  v3.8h
+        mul             v7.8h,   v19.8h,  v2.8h
+        mla             v7.8h,   v21.8h,  v3.8h
+        subs            \h,  \h,  #2
+.ifc \type, put
+        urshr           v4.8h,   v4.8h,   #4
+        urshr           v5.8h,   v5.8h,   #4
+        urshr           v6.8h,   v6.8h,   #4
+        urshr           v7.8h,   v7.8h,   #4
+.else
+        urshl           v4.8h,   v4.8h,   v31.8h
+        urshl           v5.8h,   v5.8h,   v31.8h
+        urshl           v6.8h,   v6.8h,   v31.8h
+        urshl           v7.8h,   v7.8h,   v31.8h
+        sub             v4.8h,   v4.8h,   v29.8h
+        sub             v5.8h,   v5.8h,   v29.8h
+        sub             v6.8h,   v6.8h,   v29.8h
+        sub             v7.8h,   v7.8h,   v29.8h
+.endif
+        st1             {v4.8h, v5.8h}, [\dst], \d_strd
+        st1             {v6.8h, v7.8h}, [\ds2], \d_strd
+        b.le            9f
+        mov             v16.16b, v20.16b
+        mov             v17.16b, v21.16b
+        b               2b
+9:
+        subs            \w,  \w,  #16
+        b.le            0f
+        asr             \s_strd, \s_strd, #1
+        asr             \d_strd, \d_strd, #1
+        msub            \src, \s_strd, \xmy, \src
+        msub            \dst, \d_strd, \xmy, \dst
+        sub             \src, \src, \s_strd, lsl #1
+        mov             \h,  \my
+        add             \src, \src, #32
+        add             \dst, \dst, #32
+        b               1b
+0:
+        ret
+endfunc
+
+jumptable \type\()_bilin_v_tbl
+        .word 1280b - \type\()_bilin_v_tbl
+        .word 640b  - \type\()_bilin_v_tbl
+        .word 320b  - \type\()_bilin_v_tbl
+        .word 160b  - \type\()_bilin_v_tbl
+        .word 80b   - \type\()_bilin_v_tbl
+        .word 40b   - \type\()_bilin_v_tbl
+        .word 20b   - \type\()_bilin_v_tbl
+endjumptable
+
+function L(\type\()_bilin_hv)
+        movrel          x10, \type\()_bilin_hv_tbl
+        dup             v31.8h,  w11      // 4 - intermediate_bits
+        ldrsw           x9,  [x10, x9, lsl #2]
+        neg             v31.8h,  v31.8h   // -(4-intermediate_bits)
+.ifc \type, put
+        dup             v30.4s,  w12      // 4 + intermediate_bits
+.else
+        movi            v29.8h,  #(PREP_BIAS >> 8), lsl #8
+.endif
+        add             x10, x10, x9
+.ifc \type, put
+        neg             v30.4s,  v30.4s   // -(4+intermediate_bits)
+.endif
+        br              x10
+
+20:     // 2xN hv
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        ld1             {v20.4h},  [\src], \s_strd
+        ext             v21.8b,  v20.8b,  v20.8b,  #2
+        mul             v16.4h,  v20.4h,  v0.4h
+        mla             v16.4h,  v21.4h,  v1.4h
+        urshl           v16.4h,  v16.4h,  v31.4h
+
+2:
+        ld1             {v22.4h},  [\sr2], \s_strd
+        ld1             {v24.4h},  [\src], \s_strd
+        ext             v23.8b,  v22.8b,  v22.8b,  #2
+        ext             v25.8b,  v24.8b,  v24.8b,  #2
+        trn1            v22.2s,  v22.2s,  v24.2s
+        trn1            v23.2s,  v23.2s,  v25.2s
+        mul             v17.4h,  v22.4h,  v0.4h
+        mla             v17.4h,  v23.4h,  v1.4h
+        urshl           v17.4h,  v17.4h,  v31.4h
+
+        trn1            v16.2s,  v16.2s,  v17.2s
+
+        umull           v4.4s,   v16.4h,  v2.4h
+        umlal           v4.4s,   v17.4h,  v3.4h
+        urshl           v4.4s,   v4.4s,   v30.4s
+        xtn             v4.4h,   v4.4s
+        subs            \h,  \h,  #2
+        st1             {v4.s}[0], [\dst], \d_strd
+        st1             {v4.s}[1], [\ds2], \d_strd
+        b.le            0f
+        trn2            v16.2s,  v17.2s,  v17.2s
+        b               2b
+0:
+        ret
+.endif
+
+40:     // 4xN hv
+        AARCH64_VALID_JUMP_TARGET
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        ld1             {v20.8h},  [\src], \s_strd
+        ext             v21.16b, v20.16b, v20.16b, #2
+        mul             v16.4h,  v20.4h,  v0.4h
+        mla             v16.4h,  v21.4h,  v1.4h
+        urshl           v16.4h,  v16.4h,  v31.4h
+
+4:
+        ld1             {v22.8h},  [\sr2], \s_strd
+        ld1             {v24.8h},  [\src], \s_strd
+        ext             v23.16b, v22.16b, v22.16b, #2
+        ext             v25.16b, v24.16b, v24.16b, #2
+        trn1            v22.2d,  v22.2d,  v24.2d
+        trn1            v23.2d,  v23.2d,  v25.2d
+        mul             v17.8h,  v22.8h,  v0.8h
+        mla             v17.8h,  v23.8h,  v1.8h
+        urshl           v17.8h,  v17.8h,  v31.8h
+
+        trn1            v16.2d,  v16.2d,  v17.2d
+
+        umull           v4.4s,   v16.4h,  v2.4h
+        umlal           v4.4s,   v17.4h,  v3.4h
+        umull2          v5.4s,   v16.8h,  v2.8h
+        umlal2          v5.4s,   v17.8h,  v3.8h
+.ifc \type, put
+        urshl           v4.4s,   v4.4s,   v30.4s
+        urshl           v5.4s,   v5.4s,   v30.4s
+        uzp1            v4.8h,   v4.8h,   v5.8h  // Same as xtn, xtn2
+.else
+        rshrn           v4.4h,   v4.4s,   #4
+        rshrn2          v4.8h,   v5.4s,   #4
+        sub             v4.8h,   v4.8h,   v29.8h
+.endif
+        subs            \h,  \h,  #2
+        st1             {v4.8b},   [\dst], \d_strd
+        st1             {v4.d}[1], [\ds2], \d_strd
+        b.le            0f
+        trn2            v16.2d,  v17.2d,  v17.2d
+        b               4b
+0:
+        ret
+
+80:     // 8xN, 16xN, ... hv
+160:
+320:
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        mov             \my, \h
+
+1:
+        add             \sr2, \src, \s_strd
+        add             \ds2, \dst, \d_strd
+        lsl             \s_strd, \s_strd, #1
+        lsl             \d_strd, \d_strd, #1
+
+        ldr             h21, [\src, #16]
+        ld1             {v20.8h},  [\src], \s_strd
+        ext             v21.16b, v20.16b, v21.16b, #2
+        mul             v16.8h,  v20.8h,  v0.8h
+        mla             v16.8h,  v21.8h,  v1.8h
+        urshl           v16.8h,  v16.8h,  v31.8h
+
+2:
+        ldr             h23, [\sr2, #16]
+        ld1             {v22.8h},  [\sr2], \s_strd
+        ldr             h25, [\src, #16]
+        ld1             {v24.8h},  [\src], \s_strd
+        ext             v23.16b, v22.16b, v23.16b, #2
+        ext             v25.16b, v24.16b, v25.16b, #2
+        mul             v17.8h,  v22.8h,  v0.8h
+        mla             v17.8h,  v23.8h,  v1.8h
+        mul             v18.8h,  v24.8h,  v0.8h
+        mla             v18.8h,  v25.8h,  v1.8h
+        urshl           v17.8h,  v17.8h,  v31.8h
+        urshl           v18.8h,  v18.8h,  v31.8h
+
+        umull           v4.4s,   v16.4h,  v2.4h
+        umlal           v4.4s,   v17.4h,  v3.4h
+        umull2          v5.4s,   v16.8h,  v2.8h
+        umlal2          v5.4s,   v17.8h,  v3.8h
+        umull           v6.4s,   v17.4h,  v2.4h
+        umlal           v6.4s,   v18.4h,  v3.4h
+        umull2          v7.4s,   v17.8h,  v2.8h
+        umlal2          v7.4s,   v18.8h,  v3.8h
+.ifc \type, put
+        urshl           v4.4s,   v4.4s,   v30.4s
+        urshl           v5.4s,   v5.4s,   v30.4s
+        urshl           v6.4s,   v6.4s,   v30.4s
+        urshl           v7.4s,   v7.4s,   v30.4s
+        uzp1            v4.8h,   v4.8h,   v5.8h  // Same as xtn, xtn2
+        uzp1            v5.8h,   v6.8h,   v7.8h  // Ditto
+.else
+        rshrn           v4.4h,   v4.4s,   #4
+        rshrn2          v4.8h,   v5.4s,   #4
+        rshrn           v5.4h,   v6.4s,   #4
+        rshrn2          v5.8h,   v7.4s,   #4
+        sub             v4.8h,   v4.8h,   v29.8h
+        sub             v5.8h,   v5.8h,   v29.8h
+.endif
+        subs            \h,  \h,  #2
+        st1             {v4.8h}, [\dst], \d_strd
+        st1             {v5.8h}, [\ds2], \d_strd
+        b.le            9f
+        mov             v16.16b, v18.16b
+        b               2b
+9:
+        subs            \w,  \w,  #8
+        b.le            0f
+        asr             \s_strd,  \s_strd,  #1
+        asr             \d_strd,  \d_strd,  #1
+        msub            \src,  \s_strd,  \xmy,  \src
+        msub            \dst,  \d_strd,  \xmy,  \dst
+        sub             \src,  \src,  \s_strd,  lsl #1
+        mov             \h,  \my
+        add             \src,  \src,  #16
+        add             \dst,  \dst,  #16
+        b               1b
+0:
+        ret
+endfunc
+
+jumptable \type\()_bilin_hv_tbl
+        .word 1280b - \type\()_bilin_hv_tbl
+        .word 640b  - \type\()_bilin_hv_tbl
+        .word 320b  - \type\()_bilin_hv_tbl
+        .word 160b  - \type\()_bilin_hv_tbl
+        .word 80b   - \type\()_bilin_hv_tbl
+        .word 40b   - \type\()_bilin_hv_tbl
+        .word 20b   - \type\()_bilin_hv_tbl
+endjumptable
+.endm
+
+make_8tap_fn    put,  regular_sharp,  REGULAR, SHARP,   8tap
+make_8tap_fn    put,  smooth_sharp,   SMOOTH,  SHARP,   8tap
+make_8tap_fn    put,  sharp,          SHARP,   SHARP,   8tap
+make_8tap_fn    put,  sharp_regular,  SHARP,   REGULAR, 8tap
+make_8tap_fn    put,  sharp_smooth,   SHARP,   SMOOTH,  8tap
+filter_fn       put,  x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, w8, x9, x10, 8tap
+
+make_8tap_fn    put,  regular,        REGULAR, REGULAR, 6tap
+make_8tap_fn    put,  regular_smooth, REGULAR, SMOOTH,  6tap
+make_8tap_fn    put,  smooth,         SMOOTH,  SMOOTH,  6tap
+make_8tap_fn    put,  smooth_regular, SMOOTH,  REGULAR, 6tap
+filter_fn       put,  x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, w8, x9, x10, 6tap
+filter_bilin_fn put,  x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, w8, x9, x10
+
+make_8tap_fn    prep,  regular_sharp,  REGULAR, SHARP,   8tap
+make_8tap_fn    prep,  smooth_sharp,   SMOOTH,  SHARP,   8tap
+make_8tap_fn    prep,  sharp,          SHARP,   SHARP,   8tap
+make_8tap_fn    prep,  sharp_regular,  SHARP,   REGULAR, 8tap
+make_8tap_fn    prep,  sharp_smooth,   SHARP,   SMOOTH,  8tap
+filter_fn       prep, x0, x8, x1, x2, w3, w4, w5, x5, w6, x6, w7, x9, x10, 8tap
+
+make_8tap_fn    prep,  regular,        REGULAR, REGULAR, 6tap
+make_8tap_fn    prep,  regular_smooth, REGULAR, SMOOTH,  6tap
+make_8tap_fn    prep,  smooth,         SMOOTH,  SMOOTH,  6tap
+make_8tap_fn    prep,  smooth_regular, SMOOTH,  REGULAR, 6tap
+filter_fn       prep, x0, x8, x1, x2, w3, w4, w5, x5, w6, x6, w7, x9, x10, 6tap
+filter_bilin_fn prep, x0, x8, x1, x2, w3, w4, w5, x5, w6, x6, w7, x9, x10
+
+
+.macro load_filter_row dst, src, inc
+        asr             w13, \src, #10
+        add             \src, \src, \inc
+        ldr             \dst, [x11, w13, sxtw #3]
+.endm
+
+function warp_filter_horz_neon
+        add             w12, w5,  #512
+
+        ld1             {v16.8h, v17.8h}, [x2], x3
+
+        load_filter_row d0, w12, w7
+        load_filter_row d1, w12, w7
+        load_filter_row d2, w12, w7
+        sxtl            v0.8h,   v0.8b
+        load_filter_row d3, w12, w7
+        sxtl            v1.8h,   v1.8b
+        load_filter_row d4, w12, w7
+        sxtl            v2.8h,   v2.8b
+        load_filter_row d5, w12, w7
+        sxtl            v3.8h,   v3.8b
+        load_filter_row d6, w12, w7
+        sxtl            v4.8h,   v4.8b
+        load_filter_row d7, w12, w7
+        sxtl            v5.8h,   v5.8b
+        ext             v18.16b, v16.16b, v17.16b, #2*1
+        smull           v8.4s,   v16.4h,  v0.4h
+        smull2          v9.4s,   v16.8h,  v0.8h
+        sxtl            v6.8h,   v6.8b
+        ext             v19.16b, v16.16b, v17.16b, #2*2
+        smull           v10.4s,  v18.4h,  v1.4h
+        smull2          v11.4s,  v18.8h,  v1.8h
+        sxtl            v7.8h,   v7.8b
+        ext             v20.16b, v16.16b, v17.16b, #2*3
+        smull           v0.4s,   v19.4h,  v2.4h
+        smull2          v1.4s,   v19.8h,  v2.8h
+        ext             v21.16b, v16.16b, v17.16b, #2*4
+        addp            v8.4s,   v8.4s,   v9.4s
+        smull           v2.4s,   v20.4h,  v3.4h
+        smull2          v3.4s,   v20.8h,  v3.8h
+        ext             v22.16b, v16.16b, v17.16b, #2*5
+        addp            v9.4s,   v10.4s,  v11.4s
+        smull           v10.4s,  v21.4h,  v4.4h
+        smull2          v11.4s,  v21.8h,  v4.8h
+        ext             v23.16b, v16.16b, v17.16b, #2*6
+        addp            v0.4s,   v0.4s,   v1.4s
+        smull           v18.4s,  v22.4h,  v5.4h
+        smull2          v19.4s,  v22.8h,  v5.8h
+        ext             v16.16b, v16.16b, v17.16b, #2*7
+        addp            v1.4s,   v2.4s,   v3.4s
+        addp            v2.4s,   v10.4s,  v11.4s
+        smull           v20.4s,  v23.4h,  v6.4h
+        smull2          v21.4s,  v23.8h,  v6.8h
+        addp            v3.4s,   v18.4s,  v19.4s
+        smull           v22.4s,  v16.4h,  v7.4h
+        smull2          v23.4s,  v16.8h,  v7.8h
+        addp            v4.4s,   v20.4s,  v21.4s
+        addp            v5.4s,   v22.4s,  v23.4s
+
+        addp            v8.4s,   v8.4s,   v9.4s
+        addp            v0.4s,   v0.4s,   v1.4s
+        addp            v2.4s,   v2.4s,   v3.4s
+        addp            v4.4s,   v4.4s,   v5.4s
+
+        addp            v16.4s,  v8.4s,   v0.4s
+        addp            v17.4s,  v2.4s,   v4.4s
+
+        add             w5,  w5,  w8
+
+        srshl           v16.4s,  v16.4s,  v14.4s // -(7 - intermediate_bits)
+        srshl           v17.4s,  v17.4s,  v14.4s // -(7 - intermediate_bits)
+
+        ret
+endfunc
+
+// void dav1d_warp_affine_8x8_16bpc_neon(
+//         pixel *dst, const ptrdiff_t dst_stride,
+//         const pixel *src, const ptrdiff_t src_stride,
+//         const int16_t *const abcd, int mx, int my,
+//         const int bitdepth_max)
+.macro warp t
+function warp_affine_8x8\t\()_16bpc_neon, export=1
+        stp             d8,  d9,  [sp, #-0x40]!
+        stp             d10, d11, [sp, #0x10]
+        stp             d12, d13, [sp, #0x20]
+        stp             d14, d15, [sp, #0x30]
+
+.ifb \t
+        dup             v15.8h,  w7        // bitdepth_max
+.else
+        movi            v15.8h,  #(PREP_BIAS >> 8), lsl #8
+.endif
+        clz             w7,  w7
+                                           // intermediate_bits = clz(bitdepth_max) - 18
+.ifb \t
+        sub             w8,  w7,  #11      // 7 + intermediate_bits = clz(bitdepth_max) - 18 + 7
+.endif
+        sub             w7,  w7,  #25      // -(7 - intermediate_bits)
+.ifb \t
+        neg             w8,  w8            // -(7 + intermediate_bits)
+.endif
+        dup             v14.4s,  w7        // -(7 - intermediate_bits)
+.ifb \t
+        dup             v13.4s,  w8        // -(7 + intermediate_bits)
+.endif
+
+        ldr             x4,  [x4]
+        sbfx            x7,  x4, #0,  #16
+        sbfx            x8,  x4, #16, #16
+        sbfx            x9,  x4, #32, #16
+        sbfx            x4,  x4, #48, #16
+        mov             w10, #8
+        sub             x2,  x2,  x3, lsl #1
+        sub             x2,  x2,  x3
+        sub             x2,  x2,  #6
+        movrel          x11, X(mc_warp_filter), 64*8
+        mov             x15, x30
+.ifnb \t
+        lsl             x1,  x1,  #1
+.endif
+
+        bl              warp_filter_horz_neon
+        uzp1            v24.8h,  v16.8h,  v17.8h // Same as xtn, xtn2
+        bl              warp_filter_horz_neon
+        uzp1            v25.8h,  v16.8h,  v17.8h // Ditto
+        bl              warp_filter_horz_neon
+        uzp1            v26.8h,  v16.8h,  v17.8h // Ditto
+        bl              warp_filter_horz_neon
+        uzp1            v27.8h,  v16.8h,  v17.8h // Ditto
+        bl              warp_filter_horz_neon
+        uzp1            v28.8h,  v16.8h,  v17.8h // Ditto
+        bl              warp_filter_horz_neon
+        uzp1            v29.8h,  v16.8h,  v17.8h // Ditto
+        bl              warp_filter_horz_neon
+        uzp1            v30.8h,  v16.8h,  v17.8h // Ditto
+
+1:
+        add             w14, w6,  #512
+        bl              warp_filter_horz_neon
+        uzp1            v31.8h,  v16.8h,  v17.8h // Same as xtn, xtn2
+
+        load_filter_row d0, w14, w9
+        load_filter_row d1, w14, w9
+        load_filter_row d2, w14, w9
+        load_filter_row d3, w14, w9
+        load_filter_row d4, w14, w9
+        load_filter_row d5, w14, w9
+        load_filter_row d6, w14, w9
+        load_filter_row d7, w14, w9
+        transpose_8x8b_xtl v0, v1, v2, v3, v4, v5, v6, v7, sxtl
+
+        // This ordering of smull/smlal/smull2/smlal2 is highly
+        // beneficial for Cortex A53 here.
+        smull           v16.4s,  v24.4h,  v0.4h
+        smlal           v16.4s,  v25.4h,  v1.4h
+        smlal           v16.4s,  v26.4h,  v2.4h
+        smlal           v16.4s,  v27.4h,  v3.4h
+        smlal           v16.4s,  v28.4h,  v4.4h
+        smlal           v16.4s,  v29.4h,  v5.4h
+        smlal           v16.4s,  v30.4h,  v6.4h
+        smlal           v16.4s,  v31.4h,  v7.4h
+        smull2          v17.4s,  v24.8h,  v0.8h
+        smlal2          v17.4s,  v25.8h,  v1.8h
+        smlal2          v17.4s,  v26.8h,  v2.8h
+        smlal2          v17.4s,  v27.8h,  v3.8h
+        smlal2          v17.4s,  v28.8h,  v4.8h
+        smlal2          v17.4s,  v29.8h,  v5.8h
+        smlal2          v17.4s,  v30.8h,  v6.8h
+        smlal2          v17.4s,  v31.8h,  v7.8h
+
+        mov             v24.16b, v25.16b
+        mov             v25.16b, v26.16b
+.ifb \t
+        srshl           v16.4s,  v16.4s,  v13.4s // -(7 + intermediate_bits)
+        srshl           v17.4s,  v17.4s,  v13.4s // -(7 + intermediate_bits)
+.else
+        rshrn           v16.4h,  v16.4s,  #7
+        rshrn2          v16.8h,  v17.4s,  #7
+.endif
+        mov             v26.16b, v27.16b
+.ifb \t
+        sqxtun          v16.4h,  v16.4s
+        sqxtun2         v16.8h,  v17.4s
+.else
+        sub             v16.8h,  v16.8h,  v15.8h // PREP_BIAS
+.endif
+        mov             v27.16b, v28.16b
+        mov             v28.16b, v29.16b
+.ifb \t
+        umin            v16.8h,  v16.8h,  v15.8h // bitdepth_max
+.endif
+        mov             v29.16b, v30.16b
+        mov             v30.16b, v31.16b
+        subs            w10, w10, #1
+        st1             {v16.8h}, [x0], x1
+
+        add             w6,  w6,  w4
+        b.gt            1b
+
+        ldp             d14, d15, [sp, #0x30]
+        ldp             d12, d13, [sp, #0x20]
+        ldp             d10, d11, [sp, #0x10]
+        ldp             d8,  d9,  [sp], 0x40
+
+        ret             x15
+endfunc
+.endm
+
+warp
+warp t
+
+// void dav1d_emu_edge_16bpc_neon(
+//         const intptr_t bw, const intptr_t bh,
+//         const intptr_t iw, const intptr_t ih,
+//         const intptr_t x, const intptr_t y,
+//         pixel *dst, const ptrdiff_t dst_stride,
+//         const pixel *ref, const ptrdiff_t ref_stride)
+function emu_edge_16bpc_neon, export=1
+        ldp             x8,  x9,  [sp]
+
+        // ref += iclip(y, 0, ih - 1) * PXSTRIDE(ref_stride)
+        // ref += iclip(x, 0, iw - 1)
+        sub             x12, x3,  #1           // ih - 1
+        cmp             x5,  x3
+        sub             x13, x2,  #1           // iw - 1
+        csel            x12, x12, x5,  ge      // min(y, ih - 1)
+        cmp             x4,  x2
+        bic             x12, x12, x12, asr #63 // max(min(y, ih - 1), 0)
+        csel            x13, x13, x4,  ge      // min(x, iw - 1)
+        bic             x13, x13, x13, asr #63 // max(min(x, iw - 1), 0)
+        madd            x8,  x12, x9,  x8      // ref += iclip() * stride
+        add             x8,  x8,  x13, lsl #1  // ref += iclip()
+
+        // bottom_ext = iclip(y + bh - ih, 0, bh - 1)
+        // top_ext = iclip(-y, 0, bh - 1)
+        add             x10, x5,  x1           // y + bh
+        neg             x5,  x5                // -y
+        sub             x10, x10, x3           // y + bh - ih
+        sub             x12, x1,  #1           // bh - 1
+        cmp             x10, x1
+        bic             x5,  x5,  x5,  asr #63 // max(-y, 0)
+        csel            x10, x10, x12, lt      // min(y + bh - ih, bh-1)
+        cmp             x5,  x1
+        bic             x10, x10, x10, asr #63 // max(min(y + bh - ih, bh-1), 0)
+        csel            x5,  x5,  x12, lt      // min(max(-y, 0), bh-1)
+
+        // right_ext = iclip(x + bw - iw, 0, bw - 1)
+        // left_ext = iclip(-x, 0, bw - 1)
+        add             x11, x4,  x0           // x + bw
+        neg             x4,  x4                // -x
+        sub             x11, x11, x2           // x + bw - iw
+        sub             x13, x0,  #1           // bw - 1
+        cmp             x11, x0
+        bic             x4,  x4,  x4,  asr #63 // max(-x, 0)
+        csel            x11, x11, x13, lt      // min(x + bw - iw, bw-1)
+        cmp             x4,  x0
+        bic             x11, x11, x11, asr #63 // max(min(x + bw - iw, bw-1), 0)
+        csel            x4,  x4,  x13, lt      // min(max(-x, 0), bw - 1)
+
+        // center_h = bh - top_ext - bottom_ext
+        // dst += top_ext * PXSTRIDE(dst_stride)
+        // center_w = bw - left_ext - right_ext
+        sub             x1,  x1,  x5           // bh - top_ext
+        madd            x6,  x5,  x7,  x6
+        sub             x2,  x0,  x4           // bw - left_ext
+        sub             x1,  x1,  x10          // center_h = bh - top_ext - bottom_ext
+        sub             x2,  x2,  x11          // center_w = bw - left_ext - right_ext
+
+        mov             x14, x6                // backup of dst
+
+.macro v_loop need_left, need_right
+0:
+.if \need_left
+        ld1r            {v0.8h}, [x8]
+        mov             x12, x6                // out = dst
+        mov             x3,  x4
+        mov             v1.16b,  v0.16b
+1:
+        subs            x3,  x3,  #16
+        st1             {v0.8h, v1.8h}, [x12], #32
+        b.gt            1b
+.endif
+        mov             x13, x8
+        add             x12, x6,  x4, lsl #1   // out = dst + left_ext
+        mov             x3,  x2
+1:
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x13], #64
+        subs            x3,  x3,  #32
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x12], #64
+        b.gt            1b
+.if \need_right
+        add             x3,  x8,  x2, lsl #1   // in + center_w
+        sub             x3,  x3,  #2           // in + center_w - 1
+        add             x12, x6,  x4, lsl #1   // dst + left_ext
+        ld1r            {v0.8h}, [x3]
+        add             x12, x12, x2, lsl #1   // out = dst + left_ext + center_w
+        mov             x3,  x11
+        mov             v1.16b,  v0.16b
+1:
+        subs            x3,  x3,  #16
+        st1             {v0.8h, v1.8h}, [x12], #32
+        b.gt            1b
+.endif
+
+        subs            x1,  x1,  #1           // center_h--
+        add             x6,  x6,  x7
+        add             x8,  x8,  x9
+        b.gt            0b
+.endm
+
+        cbz             x4,  2f
+        // need_left
+        cbz             x11, 3f
+        // need_left + need_right
+        v_loop          1,   1
+        b               5f
+
+2:
+        // !need_left
+        cbz             x11, 4f
+        // !need_left + need_right
+        v_loop          0,   1
+        b               5f
+
+3:
+        // need_left + !need_right
+        v_loop          1,   0
+        b               5f
+
+4:
+        // !need_left + !need_right
+        v_loop          0,   0
+
+5:
+
+        cbz             x10, 3f
+        // need_bottom
+        sub             x8,  x6,  x7           // ref = dst - stride
+        mov             x4,  x0
+1:
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x8], #64
+        mov             x3,  x10
+2:
+        subs            x3,  x3,  #1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x7
+        b.gt            2b
+        msub            x6,  x7,  x10,  x6     // dst -= bottom_ext * stride
+        subs            x4,  x4,  #32          // bw -= 32
+        add             x6,  x6,  #64          // dst += 32
+        b.gt            1b
+
+3:
+        cbz             x5,  3f
+        // need_top
+        msub            x6,  x7,  x5,  x14     // dst = stored_dst - top_ext * stride
+1:
+        ld1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x14], #64
+        mov             x3,  x5
+2:
+        subs            x3,  x3,  #1
+        st1             {v0.8h, v1.8h, v2.8h, v3.8h}, [x6], x7
+        b.gt            2b
+        msub            x6,  x7,  x5,  x6      // dst -= top_ext * stride
+        subs            x0,  x0,  #32          // bw -= 32
+        add             x6,  x6,  #64          // dst += 32
+        b.gt            1b
+
+3:
+        ret
+endfunc
diff --git a/media/libdav1d/src/src/arm/64/mc16_sve.S b/media/libdav1d/src/src/arm/64/mc16_sve.S
new file mode 100644
index 0000000000..9ebdb2187e
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/mc16_sve.S
@@ -0,0 +1,1649 @@
+/*
+ * Copyright © 2024, Arm Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+#define PREP_BIAS 32, lsl #8        // 8192
+#define PREP_BIAS_NEG 224, lsl #8   // -8192
+
+#if HAVE_SVE2
+ENABLE_SVE
+ENABLE_SVE2
+
+// No spaces in these expressions, due to gas-preprocessor. It is translated by
+// -1 to save the negative offset when getting the address of `mc_subpel_filters`.
+#define REGULAR1        (((0*15-1)<<7)|(3*15-1))
+#define SMOOTH1         (((1*15-1)<<7)|(4*15-1))
+#define SHARP1          (((2*15-1)<<7)|(3*15-1))
+
+#define FUNC_ALIGN      2
+#define JUMP_ALIGN      2
+#define LOOP_ALIGN      2
+
+
+// Shuffle indices to permute horizontal samples in preparation for input to
+// 16-bit SDOT instructions. The 8-tap horizontal convolution uses sample
+// indices in the interval of [-3, 4] relative to the current sample position.
+const h_tbl_sve, align=4
+        .byte  0,  1,  2,  3,  4,  5,  6,  7,   2,  3,  4,  5,  6,  7,  8,  9
+        .byte  4,  5,  6,  7,  8,  9, 10, 11,   6,  7,  8,  9, 10, 11, 12, 13
+endconst
+
+// Vertical convolutions also use 16-bit SDOT instructions, where two 128-bit
+// registers contain a transposed 4x4 matrix of values. Subsequent iterations
+// of the vertical convolution can reuse the 3x4 sub-matrix from the previous
+// loop iteration. These shuffle indices shift and merge this 4x4 matrix with
+// the values of a new line.
+const v_tbl_sve, align=4
+        .byte  2,  3,  4,  5,  6,  7, 16, 17,  10, 11, 12, 13, 14, 15, 24, 25
+        .byte  2,  3,  4,  5,  6,  7, 16, 17,  10, 11, 12, 13, 14, 15, 18, 19
+        .byte  2,  3,  4,  5,  6,  7, 20, 21,  10, 11, 12, 13, 14, 15, 22, 23
+        .byte  2,  3,  4,  5,  6,  7, 24, 25,  10, 11, 12, 13, 14, 15, 26, 27
+        .byte  2,  3,  4,  5,  6,  7, 28, 29,  10, 11, 12, 13, 14, 15, 30, 31
+endconst
+
+
+.macro make_8tap_fn op, type, type_h, type_v, isa, jump=1
+function \op\()_8tap_\type\()_16bpc_\isa, export=1, align=FUNC_ALIGN
+        mov             x9,  \type_h
+        mov             x10, \type_v
+    .if \jump
+        b               \op\()_8tap_\isa
+    .endif
+endfunc
+.endm
+
+.macro filter_8tap_fn type, isa, dst, d_strd, src, s_strd, w, h, mx, my, bdmax, xmx, xmy, ldst, lsrc, wd_strd, ws_strd
+make_8tap_fn \type, sharp,          SHARP1,   SHARP1,   \isa
+make_8tap_fn \type, sharp_smooth,   SHARP1,   SMOOTH1,  \isa
+make_8tap_fn \type, sharp_regular,  SHARP1,   REGULAR1, \isa
+make_8tap_fn \type, smooth_sharp,   SMOOTH1,  SHARP1,   \isa
+make_8tap_fn \type, smooth,         SMOOTH1,  SMOOTH1,  \isa
+make_8tap_fn \type, smooth_regular, SMOOTH1,  REGULAR1, \isa
+make_8tap_fn \type, regular_sharp,  REGULAR1, SHARP1,   \isa
+make_8tap_fn \type, regular_smooth, REGULAR1, SMOOTH1,  \isa
+make_8tap_fn \type, regular,        REGULAR1, REGULAR1, \isa, jump=0
+
+function \type\()_8tap_\isa, align=FUNC_ALIGN
+        clz             w8, \w
+        mov             w11, #0x4081                    // (1<<14) | (1<<7) | 1
+        ptrue           p0.b, vl16
+        sub             w8, w8, #24                     // for jump tables
+        movrel          x12, X(mc_subpel_filters)
+        cbnz            \mx, L(\type\()_8tap_h_hv_\isa)
+.ifc \type, prep
+        cbz             \my, prep_sve
+.else   // put
+        cbnz            \my, L(\type\()_8tap_v_\isa)
+        mov             w9, w8
+        b               X(put_16bpc_neon)
+
+        .align JUMP_ALIGN
+.endif
+
+L(\type\()_8tap_v_\isa):
+        madd            \my, \my, w11, w10
+        movrel          x13, v_tbl_sve
+.ifc \bdmax, w8                                         // put case, but skip
+        ld1r            {v5.8h}, [sp]                   // loading into w8
+.endif
+        sub             \src, \src, \s_strd             // src - s_strd
+        ubfx            w11, \my, #7, #7
+        and             \my, \my, #0x7F
+        ldr             q6, [x13]
+        cmp             \h, #4
+        csel            \my, \my, w11, le
+        sub             \src, \src, \s_strd, lsl #1     // src - 3 * s_strd
+        add             \xmy, x12, \xmy, lsl #3         // subpel V filter address
+        ldp             q28, q29, [x13, #16]
+        ld1sb           {z7.h}, p0/z, [\xmy]
+.ifc \type, prep
+        clz             \bdmax, \bdmax
+        sub             \bdmax, \bdmax, #24
+        dup             v5.4s, \bdmax
+.endif
+        cmp             \w, #8
+        b.lt            40f
+
+        // .align JUMP_ALIGN   // fallthrough
+80:     // V - 8xN+
+        ldp             q30, q31, [x13, #48]
+.ifc \type, prep
+        add             \wd_strd, \w, \w                // d_strd = 2 * w
+.endif
+        .align LOOP_ALIGN
+81:
+        add             \lsrc, \src, \s_strd, lsl #1
+
+        ldr             q16, [\src]
+        ldr             q17, [\src, \s_strd]
+        ldr             q18, [\lsrc]
+        ldr             q19, [\lsrc, \s_strd]
+        add             \lsrc, \lsrc, \s_strd, lsl #1
+        mov             \ldst, \dst
+
+        ldr             q20, [\lsrc]
+        ldr             q21, [\lsrc, \s_strd]
+        add             \lsrc, \lsrc, \s_strd, lsl #1
+        ldr             q22, [\lsrc]
+        ldr             q23, [\lsrc, \s_strd]
+        add             \lsrc, \lsrc, \s_strd, lsl #1
+        sub             w8, \h, #1
+
+        zip1            v0.8h, v16.8h, v17.8h
+        zip2            v1.8h, v16.8h, v17.8h
+        zip1            v2.8h, v18.8h, v19.8h
+        zip2            v3.8h, v18.8h, v19.8h
+
+        zip1            v18.8h, v20.8h, v21.8h
+        zip2            v21.8h, v20.8h, v21.8h
+        zip1            v24.8h, v22.8h, v23.8h
+        zip2            v27.8h, v22.8h, v23.8h
+
+        zip1            v16.4s, v0.4s, v2.4s
+        zip2            v19.4s, v0.4s, v2.4s
+        zip1            v22.4s, v1.4s, v3.4s
+        zip2            v25.4s, v1.4s, v3.4s
+
+        zip1            v17.4s, v18.4s, v24.4s
+        zip2            v20.4s, v18.4s, v24.4s
+        zip1            v23.4s, v21.4s, v27.4s
+        zip2            v26.4s, v21.4s, v27.4s
+
+        .align LOOP_ALIGN
+8:
+        ld1             {v18.16b}, [\lsrc], \s_strd
+
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+        mov             v21.16b, v18.16b
+        mov             v24.16b, v18.16b
+        mov             v27.16b, v18.16b
+
+        sdot            z0.d, z16.h, z7.h[0]
+        tbl             v16.16b, {v16.16b, v17.16b}, v6.16b
+        sdot            z1.d, z19.h, z7.h[0]
+        tbl             v19.16b, {v19.16b, v20.16b}, v6.16b
+        sdot            z2.d, z22.h, z7.h[0]
+        tbl             v22.16b, {v22.16b, v23.16b}, v6.16b
+        subs            w8, w8, #1
+        sdot            z3.d, z25.h, z7.h[0]
+        tbl             v25.16b, {v25.16b, v26.16b}, v6.16b
+
+        sdot            z0.d, z17.h, z7.h[1]
+        tbl             v17.16b, {v17.16b, v18.16b}, v28.16b
+        sdot            z1.d, z20.h, z7.h[1]
+        tbl             v20.16b, {v20.16b, v21.16b}, v29.16b
+        sdot            z2.d, z23.h, z7.h[1]
+        tbl             v23.16b, {v23.16b, v24.16b}, v30.16b
+        sdot            z3.d, z26.h, z7.h[1]
+        tbl             v26.16b, {v26.16b, v27.16b}, v31.16b
+
+        uzp1            v0.4s, v0.4s, v1.4s
+        uzp1            v1.4s, v2.4s, v3.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v1.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+.else   // put
+        sqrshrun        v0.4h, v0.4s, #6
+        sqrshrun2       v0.8h, v1.4s, #6
+        umin            v0.8h, v0.8h, v5.8h
+.endif
+        st1             {v0.16b}, [\ldst], \d_strd
+        b.gt            8b
+
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+
+        sdot            z0.d, z16.h, z7.h[0]
+        sdot            z1.d, z19.h, z7.h[0]
+        sdot            z2.d, z22.h, z7.h[0]
+        sdot            z3.d, z25.h, z7.h[0]
+
+        sdot            z0.d, z17.h, z7.h[1]
+        sdot            z1.d, z20.h, z7.h[1]
+        sdot            z2.d, z23.h, z7.h[1]
+        sdot            z3.d, z26.h, z7.h[1]
+        subs            \w, \w, #8
+
+        uzp1            v0.4s, v0.4s, v1.4s
+        uzp1            v1.4s, v2.4s, v3.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v1.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+.else   // put
+        sqrshrun        v0.4h, v0.4s, #6
+        sqrshrun2       v0.8h, v1.4s, #6
+        umin            v0.8h, v0.8h, v5.8h
+.endif
+        str             q0, [\ldst]
+
+        add             \dst, \dst, #16
+        add             \src, \src, #16
+        b.gt            81b
+        ret
+
+        .align JUMP_ALIGN
+40:     // V - 4xN, put only: 2xN
+.ifc \type, put
+        lsr             \d_strd, \d_strd, #1        // hword index for `st1h`
+        whilelt         p1.h, wzr, \w               // masking for writes
+.endif
+        cmp             \h, #4
+        b.le            44f
+
+        ldr             d16, [\src]
+        ldr             d17, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             d18, [\src]
+        ldr             d19, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+
+        ldr             d20, [\src]
+        ldr             d21, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             d22, [\src]
+        ldr             d23, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        sub             \h, \h, #2
+
+        zip1            v0.8h, v16.8h, v17.8h
+        zip1            v2.8h, v18.8h, v19.8h
+        zip1            v18.8h, v20.8h, v21.8h
+        zip1            v24.8h, v22.8h, v23.8h
+
+        zip1            v16.4s, v0.4s, v2.4s
+        zip2            v19.4s, v0.4s, v2.4s
+        zip1            v17.4s, v18.4s, v24.4s
+        zip2            v20.4s, v18.4s, v24.4s
+
+        .align LOOP_ALIGN
+4:
+        ldr             d18, [\src]
+        ldr             d24, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+        mov             v21.16b, v18.16b
+        mov             v27.16b, v24.16b
+
+        sdot            z0.d, z16.h, z7.h[0]
+        tbl             v22.16b, {v16.16b, v17.16b}, v6.16b
+        sdot            z1.d, z19.h, z7.h[0]
+        tbl             v25.16b, {v19.16b, v20.16b}, v6.16b
+        sdot            z0.d, z17.h, z7.h[1]
+        tbl             v23.16b, {v17.16b, v18.16b}, v28.16b
+        sdot            z1.d, z20.h, z7.h[1]
+        tbl             v26.16b, {v20.16b, v21.16b}, v29.16b
+        subs            \h, \h, #2
+
+        sdot            z2.d, z22.h, z7.h[0]
+        tbl             v16.16b, {v22.16b, v23.16b}, v6.16b
+        sdot            z3.d, z25.h, z7.h[0]
+        tbl             v19.16b, {v25.16b, v26.16b}, v6.16b
+        sdot            z2.d, z23.h, z7.h[1]
+        tbl             v17.16b, {v23.16b, v24.16b}, v28.16b
+        sdot            z3.d, z26.h, z7.h[1]
+        tbl             v20.16b, {v26.16b, v27.16b}, v29.16b
+
+        uzp1            v0.4s, v0.4s, v1.4s
+        uzp1            v1.4s, v2.4s, v3.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v1.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+        str             q0, [\dst], #16
+.else   // put
+        sqrshrun        v0.4h, v0.4s, #6
+        sqrshrun        v1.4h, v1.4s, #6
+        umin            v0.4h, v0.4h, v5.4h
+        umin            v1.4h, v1.4h, v5.4h
+        st1h            {z0.h}, p1, [\dst]
+        st1h            {z1.h}, p1, [\dst, \d_strd, lsl #1]
+        add             \dst, \dst, \d_strd, lsl #2
+.endif
+        b.gt            4b
+
+        ldr             d18, [\src]
+
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+        mov             v21.16b, v18.16b
+
+        sdot            z0.d, z16.h, z7.h[0]
+        tbl             v22.16b, {v16.16b, v17.16b}, v6.16b
+        sdot            z1.d, z19.h, z7.h[0]
+        tbl             v25.16b, {v19.16b, v20.16b}, v6.16b
+        sdot            z0.d, z17.h, z7.h[1]
+        tbl             v23.16b, {v17.16b, v18.16b}, v28.16b
+        sdot            z1.d, z20.h, z7.h[1]
+        tbl             v26.16b, {v20.16b, v21.16b}, v29.16b
+
+        sdot            z2.d, z22.h, z7.h[0]
+        sdot            z3.d, z25.h, z7.h[0]
+        sdot            z2.d, z23.h, z7.h[1]
+        sdot            z3.d, z26.h, z7.h[1]
+
+        uzp1            v0.4s, v0.4s, v1.4s
+        uzp1            v1.4s, v2.4s, v3.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v1.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+        str             q0, [\dst]
+.else   // put
+        sqrshrun        v0.4h, v0.4s, #6
+        sqrshrun        v1.4h, v1.4s, #6
+        umin            v0.4h, v0.4h, v5.4h
+        umin            v1.4h, v1.4h, v5.4h
+        st1h            {z0.h}, p1, [\dst]
+        st1h            {z1.h}, p1, [\dst, \d_strd, lsl #1]
+.endif
+        ret
+
+        .align JUMP_ALIGN
+44:     // V - 4x4, put only: 4x2, 2x4, 2x2
+        add             \src, \src, \s_strd, lsl #1     // src - s_strd
+        subs            \h, \h, #2
+
+        ldr             d16, [\src]
+        ldr             d17, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             d18, [\src]
+        ldr             d19, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+
+        ext             v7.16b, v7.16b, v7.16b, #4      // [\xmy + 2 * 2]
+
+        zip1            v0.8h, v16.8h, v17.8h
+        zip1            v2.8h, v18.8h, v19.8h
+        zip1            v16.4s, v0.4s, v2.4s
+        zip2            v19.4s, v0.4s, v2.4s
+
+.ifc \type, put
+        b.eq            42f
+.endif
+        ldr             d17, [\src]
+        ldr             d23, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+        mov             v20.16b, v17.16b
+        mov             v26.16b, v23.16b
+
+        sdot            z0.d, z16.h, z7.h[0]
+        tbl             v22.16b, {v16.16b, v17.16b}, v28.16b
+        sdot            z1.d, z19.h, z7.h[0]
+        tbl             v25.16b, {v19.16b, v20.16b}, v29.16b
+        sdot            z2.d, z22.h, z7.h[0]
+        tbl             v16.16b, {v22.16b, v23.16b}, v28.16b
+        sdot            z3.d, z25.h, z7.h[0]
+        tbl             v19.16b, {v25.16b, v26.16b}, v29.16b
+
+        uzp1            v0.4s, v0.4s, v1.4s
+        uzp1            v1.4s, v2.4s, v3.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v1.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+        str             q0, [\dst], #16
+.else   // put
+        sqrshrun        v0.4h, v0.4s, #6
+        sqrshrun        v1.4h, v1.4s, #6
+        umin            v0.4h, v0.4h, v5.4h
+        umin            v1.4h, v1.4h, v5.4h
+        st1h            {z0.h}, p1, [\dst]
+        st1h            {z1.h}, p1, [\dst, \d_strd, lsl #1]
+        add             \dst, \dst, \d_strd, lsl #2
+.endif
+
+.ifc \type, put
+        .align JUMP_ALIGN
+42:
+.endif
+        ldr             d17, [\src]
+
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+        mov             v20.16b, v17.16b
+
+        sdot            z0.d, z16.h, z7.h[0]
+        tbl             v22.16b, {v16.16b, v17.16b}, v28.16b
+        sdot            z1.d, z19.h, z7.h[0]
+        tbl             v25.16b, {v19.16b, v20.16b}, v29.16b
+
+        sdot            z2.d, z22.h, z7.h[0]
+        sdot            z3.d, z25.h, z7.h[0]
+
+        uzp1            v0.4s, v0.4s, v1.4s
+        uzp1            v1.4s, v2.4s, v3.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v1.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+        str             q0, [\dst]
+.else   // put
+        sqrshrun        v0.4h, v0.4s, #6
+        sqrshrun        v1.4h, v1.4s, #6
+        umin            v0.4h, v0.4h, v5.4h
+        umin            v1.4h, v1.4h, v5.4h
+        st1h            {z0.h}, p1, [\dst]
+        st1h            {z1.h}, p1, [\dst, \d_strd, lsl #1]
+.endif
+        ret
+
+        .align JUMP_ALIGN
+L(\type\()_8tap_h_hv_\isa):
+        madd            \mx, \mx, w11, w9
+        movrel          x13, h_tbl_sve
+        sub             \src, \src, #6              // src - 3 * 2
+        ubfx            w9, \mx, #7, #7
+        and             \mx, \mx, #0x7F
+        cmp             \w, #4
+        csel            \mx, \mx, w9, le
+        ldp             q30, q31, [x13]
+        add             \xmx, x12, \xmx, lsl #3     // subpel H filter address
+        cbz             \my, L(\type\()_8tap_h_\isa)
+
+        // HV cases
+        madd            w14, \my, w11, w10
+.ifc \bdmax, w8
+        ldr             \bdmax, [sp]
+.endif
+        ubfx            w11, w14, #7, #7
+        and             w14, w14, #0x7F
+        ld1sb           {z4.h}, p0/z, [\xmx]
+        cmp             \h, #4
+        csel            w14, w14, w11, le
+.ifc \type, put
+        dup             v29.8h, \bdmax
+.endif
+        clz             \bdmax, \bdmax
+        add             \xmy, x12, x14, lsl #3      // subpel V filter address
+        ld1sb           {z7.h}, p0/z, [\xmy]
+.ifc \type, put
+        mov             w9, #12
+        sub             w9, w9, \bdmax
+        dup             v6.4s, w9
+.endif
+        sub             \bdmax, \bdmax, #24
+        mov             x15, x30
+        sub             \src, \src, \s_strd         // src - s_strd - 3 * 2
+        dup             v5.4s, \bdmax
+        cmp             w10, SHARP1
+        b.ne            L(\type\()_6tap_hv_\isa)    // vertical != SHARP1
+
+        // HV 8-tap cases
+        cmp             \w, #4
+        b.le            40f
+
+        // .align JUMP_ALIGN    // fallthrough
+80:     // HV8 - 8xN+
+.ifc \type, prep
+        add             \wd_strd, \w, \w                // d_strd = 2 * w
+.endif
+        cmp             \h, #4
+        b.le            84f
+        sub             \src, \src, \s_strd, lsl #1     // src - 3 * s_strd - 3 * 2
+
+        .align LOOP_ALIGN
+81:
+        mov             \lsrc, \src
+        mov             \ldst, \dst
+        mov             w8, \h
+
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v16.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v17.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v18.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v19.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v20.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v21.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v22.8h, v23.8h, v24.8h
+
+        .align LOOP_ALIGN
+8:
+        ldp             q24, q28, [\lsrc]
+        smull           v0.4s, v16.4h, v7.h[0]
+        smull2          v1.4s, v16.8h, v7.h[0]
+        mov             v16.16b, v17.16b
+
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+        tbl             v23.16b, {v24.16b}, v30.16b
+        tbl             v24.16b, {v24.16b}, v31.16b
+
+        ldur            q26, [\lsrc, #8]
+        smlal           v0.4s, v17.4h, v7.h[1]
+        smlal2          v1.4s, v17.8h, v7.h[1]
+        mov             v17.16b, v18.16b
+        add             \lsrc, \lsrc, \s_strd
+
+        sdot            z2.d, z23.h, z4.h[0]
+        sdot            z3.d, z24.h, z4.h[0]
+        movi            v23.2d, #0
+        movi            v24.2d, #0
+        tbl             v25.16b, {v26.16b}, v30.16b
+        tbl             v26.16b, {v26.16b}, v31.16b
+        smlal           v0.4s, v18.4h, v7.h[2]
+        smlal2          v1.4s, v18.8h, v7.h[2]
+        mov             v18.16b, v19.16b
+
+        sdot            z23.d, z25.h, z4.h[0]
+        sdot            z24.d, z26.h, z4.h[0]
+        tbl             v27.16b, {v28.16b}, v30.16b
+        tbl             v28.16b, {v28.16b}, v31.16b
+        smlal           v0.4s, v19.4h, v7.h[3]
+        smlal2          v1.4s, v19.8h, v7.h[3]
+        mov             v19.16b, v20.16b
+
+        subs            w8, w8, #1
+        sdot            z2.d, z25.h, z4.h[1]
+        sdot            z3.d, z26.h, z4.h[1]
+        sdot            z23.d, z27.h, z4.h[1]
+        sdot            z24.d, z28.h, z4.h[1]
+
+        smlal           v0.4s, v20.4h, v7.h[4]
+        smlal2          v1.4s, v20.8h, v7.h[4]
+        mov             v20.16b, v21.16b
+
+        uzp1            v3.4s, v2.4s, v3.4s
+        uzp1            v24.4s, v23.4s, v24.4s
+        smlal           v0.4s, v21.4h, v7.h[5]
+        smlal2          v1.4s, v21.8h, v7.h[5]
+        mov             v21.16b, v22.16b
+
+        srshl           v23.4s, v3.4s, v5.4s
+        srshl           v24.4s, v24.4s, v5.4s
+        smlal           v0.4s, v22.4h, v7.h[6]
+        smlal2          v1.4s, v22.8h, v7.h[6]
+
+        uzp1            v22.8h, v23.8h, v24.8h
+        smlal           v0.4s, v22.4h, v7.h[7]
+        smlal2          v1.4s, v22.8h, v7.h[7]
+
+.ifc \type, prep
+        rshrn           v0.4h, v0.4s, #6
+        rshrn2          v0.8h, v1.4s, #6
+        sub             z0.h, z0.h, #PREP_BIAS
+.else   // put
+        srshl           v0.4s, v0.4s, v6.4s
+        srshl           v1.4s, v1.4s, v6.4s
+        sqxtun          v0.4h, v0.4s
+        sqxtun2         v0.8h, v1.4s
+        umin            v0.8h, v0.8h, v29.8h
+.endif
+        st1             {v0.8h}, [\ldst], \d_strd
+        b.gt            8b
+
+        subs            \w, \w, #8
+        add             \src, \src, #16
+        add             \dst, \dst, #16
+        b.gt            81b
+        ret             x15
+
+        .align JUMP_ALIGN
+40:     // HV8 - 4xN, put only: 2xN
+.ifc \type, put
+        lsr             \d_strd, \d_strd, #1        // hword index for `st1h`
+        whilelt         p1.h, wzr, \w               // masking for writes
+.endif
+        ext             v4.16b, v4.16b, v4.16b, #4  // [\xmy + 2 * 2]
+        add             \src, \src, #4
+
+        cmp             \h, #4
+        b.le            44f
+
+        sub             \src, \src, \s_strd, lsl #1 // src - 3 * s_strd - 3 * 2
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v16.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v17.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v18.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v19.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v20.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v21.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v22.4h, v0.4s
+
+        .align LOOP_ALIGN
+4:
+        ld1             {v3.16b}, [\src], \s_strd
+
+        smull           v24.4s, v16.4h, v7.h[0]
+        smlal           v24.4s, v17.4h, v7.h[1]
+        tbl             v2.16b, {v3.16b}, v30.16b
+        tbl             v3.16b, {v3.16b}, v31.16b
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+
+        smlal           v24.4s, v18.4h, v7.h[2]
+        smlal           v24.4s, v19.4h, v7.h[3]
+        sdot            z0.d, z2.h, z4.h[0]
+        sdot            z1.d, z3.h, z4.h[0]
+        mov             v18.16b, v19.16b
+        mov             v19.16b, v20.16b
+        uzp1            v0.4s, v0.4s, v1.4s
+
+        smlal           v24.4s, v20.4h, v7.h[4]
+        smlal           v24.4s, v21.4h, v7.h[5]
+        srshl           v0.4s, v0.4s, v5.4s
+        mov             v20.16b, v21.16b
+        mov             v21.16b, v22.16b
+
+        subs            \h, \h, #1
+        smlal           v24.4s, v22.4h, v7.h[6]
+        xtn             v22.4h, v0.4s
+        smlal           v24.4s, v22.4h, v7.h[7]
+
+.ifc \type, prep
+        rshrn           v0.4h, v24.4s, #6
+        sub             z0.h, z0.h, #PREP_BIAS
+        str             d0, [\dst], #8
+.else   // put
+        srshl           v0.4s, v24.4s, v6.4s
+        sqxtun          v0.4h, v0.4s
+        umin            v0.4h, v0.4h, v29.4h
+        st1h            {z0.h}, p1, [\dst]
+        add             \dst, \dst, \d_strd, lsl #1
+.endif
+        b.gt            4b
+        ret             x15
+
+        .align JUMP_ALIGN
+L(\type\()_6tap_hv_\isa):
+        cmp             \w, #4
+        b.le            46f
+
+        // .align JUMP_ALIGN    // fallthrough
+80:     // HV6 - 8xN+
+.ifc \type, prep
+        add             \wd_strd, \w, \w        // d_strd = 2 * w
+.endif
+        cmp             \h, #4
+        b.le            84f
+        sub             \src, \src, \s_strd     // src - 2 * s_strd - 3 * 2
+
+        .align LOOP_ALIGN
+81:
+        mov             \lsrc, \src
+        mov             \ldst, \dst
+        mov             w8, \h
+
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v16.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v17.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v18.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v19.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v20.8h, v23.8h, v24.8h
+
+        .align LOOP_ALIGN
+8:
+        ldp             q24, q28, [\lsrc]
+
+        smull           v0.4s, v16.4h, v7.h[1]
+        smull2          v1.4s, v16.8h, v7.h[1]
+        mov             v16.16b, v17.16b
+
+        tbl             v23.16b, {v24.16b}, v30.16b
+        tbl             v24.16b, {v24.16b}, v31.16b
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+
+        ldur            q26, [\lsrc, #8]
+        add             \lsrc, \lsrc, \s_strd
+
+        sdot            z2.d, z23.h, z4.h[0]
+        sdot            z3.d, z24.h, z4.h[0]
+        tbl             v25.16b, {v26.16b}, v30.16b
+        tbl             v26.16b, {v26.16b}, v31.16b
+        movi            v23.2d, #0
+        movi            v24.2d, #0
+
+        sdot            z23.d, z25.h, z4.h[0]
+        sdot            z24.d, z26.h, z4.h[0]
+        tbl             v27.16b, {v28.16b}, v30.16b
+        tbl             v28.16b, {v28.16b}, v31.16b
+        smlal           v0.4s, v17.4h, v7.h[2]
+        smlal2          v1.4s, v17.8h, v7.h[2]
+        mov             v17.16b, v18.16b
+
+        sdot            z2.d, z25.h, z4.h[1]
+        sdot            z3.d, z26.h, z4.h[1]
+        sdot            z23.d, z27.h, z4.h[1]
+        sdot            z24.d, z28.h, z4.h[1]
+
+        smlal           v0.4s, v18.4h, v7.h[3]
+        smlal2          v1.4s, v18.8h, v7.h[3]
+        mov             v18.16b, v19.16b
+
+        uzp1            v3.4s, v2.4s, v3.4s
+        uzp1            v24.4s, v23.4s, v24.4s
+        smlal           v0.4s, v19.4h, v7.h[4]
+        smlal2          v1.4s, v19.8h, v7.h[4]
+        mov             v19.16b, v20.16b
+
+        srshl           v23.4s, v3.4s, v5.4s
+        srshl           v24.4s, v24.4s, v5.4s
+        smlal           v0.4s, v20.4h, v7.h[5]
+        smlal2          v1.4s, v20.8h, v7.h[5]
+
+        subs            w8, w8, #1
+        uzp1            v20.8h, v23.8h, v24.8h
+        smlal           v0.4s, v20.4h, v7.h[6]
+        smlal2          v1.4s, v20.8h, v7.h[6]
+
+.ifc \type, prep
+        rshrn           v0.4h, v0.4s, #6
+        rshrn2          v0.8h, v1.4s, #6
+        sub             z0.h, z0.h, #PREP_BIAS
+.else   // put
+        srshl           v0.4s, v0.4s, v6.4s
+        srshl           v1.4s, v1.4s, v6.4s
+        sqxtun          v0.4h, v0.4s
+        sqxtun2         v0.8h, v1.4s
+        umin            v0.8h, v0.8h, v29.8h
+.endif
+        st1             {v0.8h}, [\ldst], \d_strd
+        b.gt            8b
+
+        add             \dst, \dst, #16
+        subs            \w, \w, #8
+        add             \src, \src, #16
+        b.gt            81b
+        ret             x15
+
+        .align LOOP_ALIGN
+84:     // HV4 - 8x4, 8x2
+        mov             \lsrc, \src
+        mov             \ldst, \dst
+        mov             w8, \h
+
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v17.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v18.8h, v23.8h, v24.8h
+        bl              L(\type\()_hv_filter8_\isa)
+        uzp1            v19.8h, v23.8h, v24.8h
+
+        .align LOOP_ALIGN
+81:
+        ldp             q24, q28, [\lsrc]
+        ldur            q26, [\lsrc, #8]
+        add             \lsrc, \lsrc, \s_strd
+
+        tbl             v23.16b, {v24.16b}, v30.16b
+        tbl             v24.16b, {v24.16b}, v31.16b
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+        sdot            z2.d, z23.h, z4.h[0]
+        sdot            z3.d, z24.h, z4.h[0]
+
+        tbl             v25.16b, {v26.16b}, v30.16b
+        tbl             v26.16b, {v26.16b}, v31.16b
+        movi            v23.2d, #0
+        movi            v24.2d, #0
+        sdot            z23.d, z25.h, z4.h[0]
+        sdot            z24.d, z26.h, z4.h[0]
+
+        tbl             v27.16b, {v28.16b}, v30.16b
+        tbl             v28.16b, {v28.16b}, v31.16b
+        sdot            z2.d, z25.h, z4.h[1]
+        sdot            z3.d, z26.h, z4.h[1]
+        sdot            z23.d, z27.h, z4.h[1]
+        sdot            z24.d, z28.h, z4.h[1]
+
+        smull           v0.4s, v17.4h, v7.h[2]
+        smull2          v1.4s, v17.8h, v7.h[2]
+        mov             v17.16b, v18.16b
+
+        subs            w8, w8, #1
+        uzp1            v3.4s, v2.4s, v3.4s
+        uzp1            v24.4s, v23.4s, v24.4s
+        smlal           v0.4s, v18.4h, v7.h[3]
+        smlal2          v1.4s, v18.8h, v7.h[3]
+        mov             v18.16b, v19.16b
+
+        srshl           v23.4s, v3.4s, v5.4s
+        srshl           v24.4s, v24.4s, v5.4s
+        smlal           v0.4s, v19.4h, v7.h[4]
+        smlal2          v1.4s, v19.8h, v7.h[4]
+
+        uzp1            v19.8h, v23.8h, v24.8h
+        smlal           v0.4s, v19.4h, v7.h[5]
+        smlal2          v1.4s, v19.8h, v7.h[5]
+
+.ifc \type, prep
+        rshrn           v0.4h, v0.4s, #6
+        rshrn2          v0.8h, v1.4s, #6
+        sub             z0.h, z0.h, #PREP_BIAS
+.else   // put
+        srshl           v0.4s, v0.4s, v6.4s
+        srshl           v1.4s, v1.4s, v6.4s
+        sqxtun          v0.4h, v0.4s
+        sqxtun2         v0.8h, v1.4s
+        umin            v0.8h, v0.8h, v29.8h
+.endif
+        st1             {v0.8h}, [\ldst], \d_strd
+        b.gt            81b
+
+        subs            \w, \w, #8
+        add             \dst, \dst, #16
+        add             \src, \src, #16
+        b.gt            84b
+        ret             x15
+
+        .align FUNC_ALIGN
+L(\type\()_hv_filter8_\isa):
+        ldp             q24, q28, [\lsrc]
+        ldur            q26, [\lsrc, #8]
+        add             \lsrc, \lsrc, \s_strd
+
+        tbl             v23.16b, {v24.16b}, v30.16b
+        tbl             v24.16b, {v24.16b}, v31.16b
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+        sdot            z2.d, z23.h, z4.h[0]
+        sdot            z3.d, z24.h, z4.h[0]
+
+        tbl             v25.16b, {v26.16b}, v30.16b
+        tbl             v26.16b, {v26.16b}, v31.16b
+        movi            v23.2d, #0
+        movi            v24.2d, #0
+        sdot            z23.d, z25.h, z4.h[0]
+        sdot            z24.d, z26.h, z4.h[0]
+
+        tbl             v27.16b, {v28.16b}, v30.16b
+        tbl             v28.16b, {v28.16b}, v31.16b
+        sdot            z2.d, z25.h, z4.h[1]
+        sdot            z3.d, z26.h, z4.h[1]
+        sdot            z23.d, z27.h, z4.h[1]
+        sdot            z24.d, z28.h, z4.h[1]
+
+        uzp1            v3.4s, v2.4s, v3.4s
+        uzp1            v24.4s, v23.4s, v24.4s
+        srshl           v23.4s, v3.4s, v5.4s
+        srshl           v24.4s, v24.4s, v5.4s
+        ret
+
+        .align FUNC_ALIGN
+L(\type\()_hv_filter4_\isa):
+        ld1             {v3.16b}, [\src], \s_strd
+
+        tbl             v2.16b, {v3.16b}, v30.16b
+        tbl             v3.16b, {v3.16b}, v31.16b
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        sdot            z0.d, z2.h, z4.h[0]
+        sdot            z1.d, z3.h, z4.h[0]
+
+        uzp1            v0.4s, v0.4s, v1.4s
+        srshl           v0.4s, v0.4s, v5.4s
+        ret
+
+        .align JUMP_ALIGN
+46:     // H4V6 - 4xN, put only: 2xN
+.ifc \type, put
+        lsr             \d_strd, \d_strd, #1        // hword index for `st1h`
+        whilelt         p1.h, wzr, \w               // masking for writes
+.endif
+        ext             v4.16b, v4.16b, v4.16b, #4  // [\xmy + 2 * 2]
+        add             \src, \src, #4
+
+        cmp             \h, #4
+        b.le            44f
+
+        sub             \src, \src, \s_strd         // src - 2 * s_strd - 3 * 2
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v16.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v17.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v18.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v19.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v20.4h, v0.4s
+
+        .align LOOP_ALIGN
+4:
+        ld1             {v3.16b}, [\src], \s_strd
+        smull           v24.4s, v16.4h, v7.h[1]
+        smlal           v24.4s, v17.4h, v7.h[2]
+
+        tbl             v2.16b, {v3.16b}, v30.16b
+        tbl             v3.16b, {v3.16b}, v31.16b
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        sdot            z0.d, z2.h, z4.h[0]
+        sdot            z1.d, z3.h, z4.h[0]
+
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+        smlal           v24.4s, v18.4h, v7.h[3]
+        smlal           v24.4s, v19.4h, v7.h[4]
+        uzp1            v0.4s, v0.4s, v1.4s
+
+        mov             v18.16b, v19.16b
+        mov             v19.16b, v20.16b
+        subs            \h, \h, #1
+        srshl           v0.4s, v0.4s, v5.4s
+        smlal           v24.4s, v20.4h, v7.h[5]
+        xtn             v20.4h, v0.4s
+        smlal           v24.4s, v20.4h, v7.h[6]
+
+.ifc \type, prep
+        rshrn           v0.4h, v24.4s, #6
+        sub             z0.h, z0.h, #PREP_BIAS
+        str             d0, [\dst], #8
+.else   // put
+        srshl           v0.4s, v24.4s, v6.4s
+        sqxtun          v0.4h, v0.4s
+        umin            v0.4h, v0.4h, v29.4h
+        st1h            {z0.h}, p1, [\dst]
+        add             \dst, \dst, \d_strd, lsl #1
+.endif
+        b.gt            4b
+        ret             x15
+
+        .align JUMP_ALIGN
+44:     // H4V4 - 4x4, put only: 4x2, 2x4, 2x2
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v17.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v18.4h, v0.4s
+        bl              L(\type\()_hv_filter4_\isa)
+        xtn             v19.4h, v0.4s
+
+        .align LOOP_ALIGN
+4:
+        ld1             {v3.16b}, [\src], \s_strd
+        smull           v24.4s, v17.4h, v7.h[2]
+        smlal           v24.4s, v18.4h, v7.h[3]
+
+        tbl             v2.16b, {v3.16b}, v30.16b
+        tbl             v3.16b, {v3.16b}, v31.16b
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        sdot            z0.d, z2.h, z4.h[0]
+        sdot            z1.d, z3.h, z4.h[0]
+        uzp1            v0.4s, v0.4s, v1.4s
+
+        mov             v17.16b, v18.16b
+        mov             v18.16b, v19.16b
+        subs            \h, \h, #1
+        srshl           v0.4s, v0.4s, v5.4s
+        smlal           v24.4s, v19.4h, v7.h[4]
+        xtn             v19.4h, v0.4s
+        smlal           v24.4s, v19.4h, v7.h[5]
+
+.ifc \type, prep
+        rshrn           v0.4h, v24.4s, #6
+        sub             z0.h, z0.h, #PREP_BIAS
+        str             d0, [\dst], #8
+.else   // put
+        srshl           v0.4s, v24.4s, v6.4s
+        sqxtun          v0.4h, v0.4s
+        umin            v0.4h, v0.4h, v29.4h
+        st1h            {z0.h}, p1, [\dst]
+        add             \dst, \dst, \d_strd, lsl #1
+.endif
+        b.gt            4b
+        ret             x15
+
+        .align JUMP_ALIGN
+L(\type\()_8tap_h_\isa):
+        movrel          x11, \type\()_8tap_h_\isa\()_tbl
+        ldrsw           x12, [x11, x8, lsl #2]
+.ifc \bdmax, w8
+        ldr             \bdmax, [sp]
+.endif
+.ifc \type, prep
+        clz             \bdmax, \bdmax
+        sub             \bdmax, \bdmax, #24
+        dup             v5.4s, \bdmax
+.else   // put
+        mov             w9, #34             // rounding for 10-bit case
+        mov             w10, #40            // rounding for 12-bit case
+        cmp             \bdmax, #0xFFF
+        csel            w9, w9, w10, ne     // select rounding based on \bdmax
+        dup             v5.8h, \bdmax
+        dup             v6.2d, x9
+.endif
+        add             x11, x11, x12
+        ld1sb           {z4.h}, p0/z, [\xmx]
+        br              x11
+
+        .align JUMP_ALIGN
+20:     // H - 4xN, put only: 2xN
+40:
+        AARCH64_VALID_JUMP_TARGET
+        add             \src, \src, #4              // src - 1 * 2
+        ext             v4.16b, v4.16b, v4.16b, #4  // [\xmy + 2 * 2]
+.ifc \type, put
+        lsr             \d_strd, \d_strd, #1        // hword index for `st1h`
+        whilelt         p1.h, wzr, \w               // masking for writes
+.endif
+        .align LOOP_ALIGN
+4:
+        ldr             q17, [\src]
+        ldr             q19, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+
+.ifc \type, prep
+        movi            v0.2d, #0
+        movi            v1.2d, #0
+        movi            v2.2d, #0
+        movi            v3.2d, #0
+.else
+        mov             v0.16b, v6.16b
+        mov             v1.16b, v6.16b
+        mov             v2.16b, v6.16b
+        mov             v3.16b, v6.16b
+.endif
+        tbl             v16.16b, {v17.16b}, v30.16b
+        tbl             v17.16b, {v17.16b}, v31.16b
+        sdot            z0.d, z16.h, z4.h[0]
+        sdot            z1.d, z17.h, z4.h[0]
+        subs            \h, \h, #2
+        tbl             v18.16b, {v19.16b}, v30.16b
+        tbl             v19.16b, {v19.16b}, v31.16b
+        sdot            z2.d, z18.h, z4.h[0]
+        sdot            z3.d, z19.h, z4.h[0]
+
+        uzp1            v0.4s, v0.4s, v1.4s
+        uzp1            v1.4s, v2.4s, v3.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v1.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+        str             q0, [\dst], #16
+.else   // put
+        sqshrun         v0.4h, v0.4s, #6
+        sqshrun         v1.4h, v1.4s, #6
+        umin            v0.4h, v0.4h, v5.4h
+        umin            v1.4h, v1.4h, v5.4h
+        st1h            {z0.h}, p1, [\dst]
+        st1h            {z1.h}, p1, [\dst, \d_strd, lsl #1]
+        add             \dst, \dst, \d_strd, lsl #2
+.endif
+        b.gt            4b
+        ret
+
+        .align JUMP_ALIGN
+80:     // H - 8xN
+        AARCH64_VALID_JUMP_TARGET
+
+        .align LOOP_ALIGN
+8:
+        ldp             q17, q21, [\src]
+        ldur            q19, [\src, #8]
+
+.ifc \type, prep
+        movi            v0.2d, #0
+        movi            v2.2d, #0
+.else
+        mov             v0.16b, v6.16b
+        mov             v2.16b, v6.16b
+.endif
+        tbl             v16.16b, {v17.16b}, v30.16b
+        tbl             v17.16b, {v17.16b}, v31.16b
+        add             \src, \src, \s_strd
+        sdot            z0.d, z16.h, z4.h[0]
+        sdot            z2.d, z17.h, z4.h[0]
+
+        tbl             v18.16b, {v19.16b}, v30.16b
+        tbl             v19.16b, {v19.16b}, v31.16b
+.ifc \type, prep
+        movi            v16.2d, #0
+        movi            v17.2d, #0
+.else
+        mov             v16.16b, v6.16b
+        mov             v17.16b, v6.16b
+.endif
+        ldp             q23, q27, [\src]
+        ldur            q25, [\src, #8]
+
+        sdot            z16.d, z18.h, z4.h[0]
+        sdot            z17.d, z19.h, z4.h[0]
+
+        tbl             v22.16b, {v23.16b}, v30.16b
+        tbl             v23.16b, {v23.16b}, v31.16b
+.ifc \type, prep
+        movi            v1.2d, #0
+        movi            v3.2d, #0
+.else
+        mov             v1.16b, v6.16b
+        mov             v3.16b, v6.16b
+.endif
+        add             \src, \src, \s_strd
+        sdot            z1.d, z22.h, z4.h[0]
+        sdot            z3.d, z23.h, z4.h[0]
+
+        tbl             v24.16b, {v25.16b}, v30.16b
+        tbl             v25.16b, {v25.16b}, v31.16b
+.ifc \type, prep
+        movi            v22.2d, #0
+        movi            v23.2d, #0
+.else
+        mov             v22.16b, v6.16b
+        mov             v23.16b, v6.16b
+.endif
+        sdot            z22.d, z24.h, z4.h[0]
+        sdot            z23.d, z25.h, z4.h[0]
+
+        tbl             v20.16b, {v21.16b}, v30.16b
+        tbl             v21.16b, {v21.16b}, v31.16b
+        sdot            z0.d, z18.h, z4.h[1]
+        sdot            z2.d, z19.h, z4.h[1]
+        tbl             v26.16b, {v27.16b}, v30.16b
+        tbl             v27.16b, {v27.16b}, v31.16b
+        sdot            z16.d, z20.h, z4.h[1]
+        sdot            z17.d, z21.h, z4.h[1]
+
+        sdot            z1.d, z24.h, z4.h[1]
+        sdot            z3.d, z25.h, z4.h[1]
+
+        sdot            z22.d, z26.h, z4.h[1]
+        sdot            z23.d, z27.h, z4.h[1]
+
+        subs            \h, \h, #2
+        uzp1            v0.4s, v0.4s, v2.4s
+        uzp1            v2.4s, v16.4s, v17.4s
+        uzp1            v1.4s, v1.4s, v3.4s
+        uzp1            v3.4s, v22.4s, v23.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v2.4s, v2.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        srshl           v3.4s, v3.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v2.8h
+        uzp1            v1.8h, v1.8h, v3.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+        sub             z1.h, z1.h, #PREP_BIAS
+        stp             q0, q1, [\dst], #32
+.else   // put
+        sqshrun         v0.4h, v0.4s, #6
+        sqshrun2        v0.8h, v2.4s, #6
+        sqshrun         v1.4h, v1.4s, #6
+        sqshrun2        v1.8h, v3.4s, #6
+        umin            v0.8h, v0.8h, v5.8h
+        umin            v1.8h, v1.8h, v5.8h
+        st1             {v0.16b}, [\dst], \d_strd
+        st1             {v1.16b}, [\dst], \d_strd
+.endif
+        b.gt            8b
+        ret
+
+        .align JUMP_ALIGN
+160:    // H - 16xN
+        AARCH64_VALID_JUMP_TARGET
+
+        .align LOOP_ALIGN
+16:
+        ldp             q17, q21, [\src]
+        ldur            q19, [\src, #8]
+
+.ifc \type, prep
+        movi            v0.2d, #0
+        movi            v2.2d, #0
+.else
+        mov             v0.16b, v6.16b
+        mov             v2.16b, v6.16b
+.endif
+        tbl             v16.16b, {v17.16b}, v30.16b
+        tbl             v17.16b, {v17.16b}, v31.16b
+        sdot            z0.d, z16.h, z4.h[0]
+        sdot            z2.d, z17.h, z4.h[0]
+
+        tbl             v18.16b, {v19.16b}, v30.16b
+        tbl             v19.16b, {v19.16b}, v31.16b
+.ifc \type, prep
+        movi            v16.2d, #0
+        movi            v17.2d, #0
+.else
+        mov             v16.16b, v6.16b
+        mov             v17.16b, v6.16b
+.endif
+        ldur            q25, [\src, #24]
+        ldr             q27, [\src, #32]
+
+        sdot            z16.d, z18.h, z4.h[0]
+        sdot            z17.d, z19.h, z4.h[0]
+
+        tbl             v22.16b, {v21.16b}, v30.16b
+        tbl             v23.16b, {v21.16b}, v31.16b
+.ifc \type, prep
+        movi            v1.2d, #0
+        movi            v3.2d, #0
+.else
+        mov             v1.16b, v6.16b
+        mov             v3.16b, v6.16b
+.endif
+        add             \src, \src, \s_strd
+        sdot            z1.d, z22.h, z4.h[0]
+        sdot            z3.d, z23.h, z4.h[0]
+
+        tbl             v24.16b, {v25.16b}, v30.16b
+        tbl             v25.16b, {v25.16b}, v31.16b
+.ifc \type, prep
+        movi            v22.2d, #0
+        movi            v23.2d, #0
+.else
+        mov             v22.16b, v6.16b
+        mov             v23.16b, v6.16b
+.endif
+        sdot            z22.d, z24.h, z4.h[0]
+        sdot            z23.d, z25.h, z4.h[0]
+
+        tbl             v20.16b, {v21.16b}, v30.16b
+        tbl             v21.16b, {v21.16b}, v31.16b
+        sdot            z0.d, z18.h, z4.h[1]
+        sdot            z2.d, z19.h, z4.h[1]
+        tbl             v26.16b, {v27.16b}, v30.16b
+        tbl             v27.16b, {v27.16b}, v31.16b
+        sdot            z16.d, z20.h, z4.h[1]
+        sdot            z17.d, z21.h, z4.h[1]
+
+        sdot            z1.d, z24.h, z4.h[1]
+        sdot            z3.d, z25.h, z4.h[1]
+
+        sdot            z22.d, z26.h, z4.h[1]
+        sdot            z23.d, z27.h, z4.h[1]
+
+        subs            \h, \h, #1
+        uzp1            v0.4s, v0.4s, v2.4s
+        uzp1            v2.4s, v16.4s, v17.4s
+        uzp1            v1.4s, v1.4s, v3.4s
+        uzp1            v3.4s, v22.4s, v23.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v2.4s, v2.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        srshl           v3.4s, v3.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v2.8h
+        uzp1            v1.8h, v1.8h, v3.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+        sub             z1.h, z1.h, #PREP_BIAS
+        stp             q0, q1, [\dst], #32
+.else   // put
+        sqshrun         v0.4h, v0.4s, #6
+        sqshrun2        v0.8h, v2.4s, #6
+        sqshrun         v1.4h, v1.4s, #6
+        sqshrun2        v1.8h, v3.4s, #6
+        umin            v0.8h, v0.8h, v5.8h
+        umin            v1.8h, v1.8h, v5.8h
+        st1             {v0.16b, v1.16b}, [\dst], \d_strd
+.endif
+        b.gt            16b
+        ret
+
+        .align JUMP_ALIGN
+320:    // H - 32xN+
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+.ifc \type, put
+        sub             \d_strd, \d_strd, \w, uxtw #1
+.endif
+        sub             \s_strd, \s_strd, \w, uxtw #1
+        mov             w8, \w
+
+        .align LOOP_ALIGN
+32:
+        ldp             q17, q21, [\src]
+        ldur            q19, [\src, #8]
+
+.ifc \type, prep
+        movi            v0.2d, #0
+        movi            v2.2d, #0
+.else
+        mov             v0.16b, v6.16b
+        mov             v2.16b, v6.16b
+.endif
+        tbl             v16.16b, {v17.16b}, v30.16b
+        tbl             v17.16b, {v17.16b}, v31.16b
+        sdot            z0.d, z16.h, z4.h[0]
+        sdot            z2.d, z17.h, z4.h[0]
+
+        tbl             v18.16b, {v19.16b}, v30.16b
+        tbl             v19.16b, {v19.16b}, v31.16b
+.ifc \type, prep
+        movi            v16.2d, #0
+        movi            v17.2d, #0
+.else
+        mov             v16.16b, v6.16b
+        mov             v17.16b, v6.16b
+.endif
+        ldur            q25, [\src, #24]
+
+        sdot            z16.d, z18.h, z4.h[0]
+        sdot            z17.d, z19.h, z4.h[0]
+
+        ldr             q27, [\src, #32]!
+
+        tbl             v22.16b, {v21.16b}, v30.16b
+        tbl             v23.16b, {v21.16b}, v31.16b
+.ifc \type, prep
+        movi            v1.2d, #0
+        movi            v3.2d, #0
+.else
+        mov             v1.16b, v6.16b
+        mov             v3.16b, v6.16b
+.endif
+        sdot            z1.d, z22.h, z4.h[0]
+        sdot            z3.d, z23.h, z4.h[0]
+
+        tbl             v24.16b, {v25.16b}, v30.16b
+        tbl             v25.16b, {v25.16b}, v31.16b
+.ifc \type, prep
+        movi            v22.2d, #0
+        movi            v23.2d, #0
+.else
+        mov             v22.16b, v6.16b
+        mov             v23.16b, v6.16b
+.endif
+        sdot            z22.d, z24.h, z4.h[0]
+        sdot            z23.d, z25.h, z4.h[0]
+
+        tbl             v20.16b, {v21.16b}, v30.16b
+        tbl             v21.16b, {v21.16b}, v31.16b
+        sdot            z0.d, z18.h, z4.h[1]
+        sdot            z2.d, z19.h, z4.h[1]
+        tbl             v26.16b, {v27.16b}, v30.16b
+        tbl             v27.16b, {v27.16b}, v31.16b
+        sdot            z16.d, z20.h, z4.h[1]
+        sdot            z17.d, z21.h, z4.h[1]
+
+        sdot            z1.d, z24.h, z4.h[1]
+        sdot            z3.d, z25.h, z4.h[1]
+
+        sdot            z22.d, z26.h, z4.h[1]
+        sdot            z23.d, z27.h, z4.h[1]
+
+        subs            w8, w8, #16
+        uzp1            v0.4s, v0.4s, v2.4s
+        uzp1            v2.4s, v16.4s, v17.4s
+        uzp1            v1.4s, v1.4s, v3.4s
+        uzp1            v3.4s, v22.4s, v23.4s
+.ifc \type, prep
+        srshl           v0.4s, v0.4s, v5.4s
+        srshl           v2.4s, v2.4s, v5.4s
+        srshl           v1.4s, v1.4s, v5.4s
+        srshl           v3.4s, v3.4s, v5.4s
+        uzp1            v0.8h, v0.8h, v2.8h
+        uzp1            v1.8h, v1.8h, v3.8h
+        sub             z0.h, z0.h, #PREP_BIAS
+        sub             z1.h, z1.h, #PREP_BIAS
+.else   // put
+        sqshrun         v0.4h, v0.4s, #6
+        sqshrun2        v0.8h, v2.4s, #6
+        sqshrun         v1.4h, v1.4s, #6
+        sqshrun2        v1.8h, v3.4s, #6
+        umin            v0.8h, v0.8h, v5.8h
+        umin            v1.8h, v1.8h, v5.8h
+.endif
+        stp             q0, q1, [\dst], #32
+        b.gt            32b
+
+        add             \src, \src, \s_strd
+.ifc \type, put
+        add             \dst, \dst, \d_strd
+.endif
+        subs            \h, \h, #1
+        mov             w8, \w
+        b.gt            32b
+        ret
+endfunc
+
+jumptable \type\()_8tap_h_\isa\()_tbl
+        .word 1280b - \type\()_8tap_h_\isa\()_tbl
+        .word 640b  - \type\()_8tap_h_\isa\()_tbl
+        .word 320b  - \type\()_8tap_h_\isa\()_tbl
+        .word 160b  - \type\()_8tap_h_\isa\()_tbl
+        .word 80b   - \type\()_8tap_h_\isa\()_tbl
+        .word 40b   - \type\()_8tap_h_\isa\()_tbl
+.ifc \type, put
+        .word 20b   - \type\()_8tap_h_\isa\()_tbl
+.endif
+endjumptable
+.endm
+
+
+function prep_sve
+        movrel          x9, prep_tbl
+        mov             w6, #19
+        ldrsw           x8, [x9, x8, lsl #2]
+        sub             w6, w6, w7, lsr #8          // 19 - bdmax / 256
+        add             x9, x9, x8
+        movi            v30.8h, #PREP_BIAS_NEG
+        dup             v29.8h, w6                  // 10b: 1 << 4, 12b: 1 << 2
+        br              x9
+
+        .align JUMP_ALIGN
+40:     // prep - 4xN
+        AARCH64_VALID_JUMP_TARGET
+
+        .align LOOP_ALIGN
+4:
+        ldr             d0, [x1]
+        ldr             d1, [x1, x2]
+        add             x1, x1, x2, lsl #1
+        subs            w4, w4, #2
+        mad             z0.h, p0/m, z29.h, z30.h
+        mad             z1.h, p0/m, z29.h, z30.h
+        stp             d0, d1, [x0], #16
+        b.gt            4b
+        ret
+
+        .align JUMP_ALIGN
+80:     // prep - 8xN
+        AARCH64_VALID_JUMP_TARGET
+
+        .align LOOP_ALIGN
+8:
+        ld1             {v0.8h}, [x1], x2
+        ld1             {v1.8h}, [x1], x2
+        subs            w4, w4, #2
+        mad             z0.h, p0/m, z29.h, z30.h
+        mad             z1.h, p0/m, z29.h, z30.h
+        stp             q0, q1, [x0], #32
+        b.gt            8b
+        ret
+
+        .align JUMP_ALIGN
+160:    // prep - 16xN
+        AARCH64_VALID_JUMP_TARGET
+
+        .align LOOP_ALIGN
+16:
+        ld1             {v0.8h, v1.8h}, [x1], x2
+        mad             z0.h, p0/m, z29.h, z30.h
+        mad             z1.h, p0/m, z29.h, z30.h
+        subs            w4, w4, #2
+        ld1             {v2.8h, v3.8h}, [x1], x2
+        mad             z2.h, p0/m, z29.h, z30.h
+        mad             z3.h, p0/m, z29.h, z30.h
+        stp             q0, q1, [x0]
+        stp             q2, q3, [x0, #32]
+        add             x0, x0, #64
+        b.gt            16b
+        ret
+
+        .align JUMP_ALIGN
+320:    // prep - 32xN
+        AARCH64_VALID_JUMP_TARGET
+
+        .align LOOP_ALIGN
+32:
+        ldp             q0, q1, [x1]
+        mad             z0.h, p0/m, z29.h, z30.h
+        mad             z1.h, p0/m, z29.h, z30.h
+        ldp             q2, q3, [x1, #32]
+        subs            w4, w4, #1
+        mad             z2.h, p0/m, z29.h, z30.h
+        mad             z3.h, p0/m, z29.h, z30.h
+        add             x1, x1, x2
+        stp             q0, q1, [x0]
+        stp             q2, q3, [x0, #32]
+        add             x0, x0, #64
+        b.gt            32b
+        ret
+
+        .align JUMP_ALIGN
+640:    // prep - 64xN
+        AARCH64_VALID_JUMP_TARGET
+
+        .align LOOP_ALIGN
+64:
+        ldp             q0, q1, [x1]
+        mad             z0.h, p0/m, z29.h, z30.h
+        mad             z1.h, p0/m, z29.h, z30.h
+        ldp             q2, q3, [x1, #32]
+        mad             z2.h, p0/m, z29.h, z30.h
+        mad             z3.h, p0/m, z29.h, z30.h
+        ldp             q4, q5, [x1, #64]
+        mad             z4.h, p0/m, z29.h, z30.h
+        mad             z5.h, p0/m, z29.h, z30.h
+        ldp             q6, q7, [x1, #96]
+        add             x1, x1, x2
+        subs            w4, w4, #1
+        mad             z6.h, p0/m, z29.h, z30.h
+        mad             z7.h, p0/m, z29.h, z30.h
+        stp             q0, q1, [x0]
+        stp             q2, q3, [x0, #32]
+        stp             q4, q5, [x0, #64]
+        stp             q6, q7, [x0, #96]
+        add             x0, x0, #128
+        b.gt            64b
+        ret
+
+        .align JUMP_ALIGN
+1280:   // prep - 128xN
+        AARCH64_VALID_JUMP_TARGET
+
+        .align LOOP_ALIGN
+128:
+        ldp             q0, q1, [x1]
+        mad             z0.h, p0/m, z29.h, z30.h
+        mad             z1.h, p0/m, z29.h, z30.h
+        ldp             q2, q3, [x1, #32]
+        mad             z2.h, p0/m, z29.h, z30.h
+        mad             z3.h, p0/m, z29.h, z30.h
+        ldp             q4, q5, [x1, #64]
+        mad             z4.h, p0/m, z29.h, z30.h
+        mad             z5.h, p0/m, z29.h, z30.h
+        ldp             q6, q7, [x1, #96]
+        mad             z6.h, p0/m, z29.h, z30.h
+        mad             z7.h, p0/m, z29.h, z30.h
+        ldp             q16, q17, [x1, #128]
+        mad             z16.h, p0/m, z29.h, z30.h
+        mad             z17.h, p0/m, z29.h, z30.h
+        ldp             q18, q19, [x1, #160]
+        mad             z18.h, p0/m, z29.h, z30.h
+        mad             z19.h, p0/m, z29.h, z30.h
+        ldp             q20, q21, [x1, #192]
+        mad             z20.h, p0/m, z29.h, z30.h
+        mad             z21.h, p0/m, z29.h, z30.h
+        ldp             q22, q23, [x1, #224]
+        add             x1, x1, x2
+        mad             z22.h, p0/m, z29.h, z30.h
+        mad             z23.h, p0/m, z29.h, z30.h
+        subs            w4, w4, #1
+        stp             q0, q1, [x0]
+        stp             q2, q3, [x0, #32]
+        stp             q4, q5, [x0, #64]
+        stp             q6, q7, [x0, #96]
+        stp             q16, q17, [x0, #128]
+        stp             q18, q19, [x0, #160]
+        stp             q20, q21, [x0, #192]
+        stp             q22, q23, [x0, #224]
+        add             x0, x0, #256
+        b.gt            128b
+        ret
+endfunc
+
+jumptable prep_tbl
+        .word 1280b - prep_tbl
+        .word 640b  - prep_tbl
+        .word 320b  - prep_tbl
+        .word 160b  - prep_tbl
+        .word 80b   - prep_tbl
+        .word 40b   - prep_tbl
+endjumptable
+
+
+// dst(x0), d_strd(x9), src(x1), s_strd(x2), w(w3), h(w4), mx(w5), my(w6), bdmax(w7)
+// xmx(x5), xmy(x6), ldst(x5), lsrc(x6), wd_strd(w9), ws_strd(w2)
+filter_8tap_fn prep, sve2, x0, x9, x1, x2, w3, w4, w5, w6, w7, x5, x6, x5, x6, w9, w2
+
+// dst(x0) d_strd(x1) src(x2) s_strd(x3) w(w4) h(w5) mx(w6) my(w7), bdmax(w8)
+// xmx(x6), xmy(x7), ldst(x6), lsrc(x7), wd_strd(w1), ws_strd(w3)
+filter_8tap_fn  put, sve2, x0, x1, x2, x3, w4, w5, w6, w7, w8, x6, x7, x6, x7, w1, w3
+
+DISABLE_SVE2
+DISABLE_SVE
+#endif  // HAVE_SVE2
diff --git a/media/libdav1d/src/src/arm/64/mc_dotprod.S b/media/libdav1d/src/src/arm/64/mc_dotprod.S
new file mode 100644
index 0000000000..079ff9eb7a
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/mc_dotprod.S
@@ -0,0 +1,1880 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Janne Grunau
+ * Copyright © 2024, Martin Storsjo
+ * Copyright © 2024, Arm Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+
+#if HAVE_DOTPROD
+ENABLE_DOTPROD
+
+// No spaces in these expressions, due to gas-preprocessor. It is translated by
+// -1 to save the negative offset at getting the address of `mc_subpel_filters`.
+#define REGULAR1        (((0*15-1)<<7)|(3*15-1))
+#define SMOOTH1         (((1*15-1)<<7)|(4*15-1))
+#define SHARP1          (((2*15-1)<<7)|(3*15-1))
+
+#define FUNC_ALIGN      2
+#define JUMP_ALIGN      2
+#define LOOP_ALIGN      2
+
+
+const h_tbl_neon_dotprod, align=4
+        // Shuffle indices to permute horizontal samples in preparation for
+        // input to SDOT instructions. The 8-tap horizontal convolution uses
+        // sample indices in the interval of [-3, 4] relative to the current
+        // sample position.
+        .byte  0,  1,  2,  3,   1,  2,  3,  4,   2,  3,  4,  5,   3,  4,  5,  6
+        .byte  4,  5,  6,  7,   5,  6,  7,  8,   6,  7,  8,  9,   7,  8,  9, 10
+        .byte  8,  9, 10, 11,   9, 10, 11, 12,  10, 11, 12, 13,  11, 12, 13, 14
+
+        // Shuffle indices to permute horizontal samples in preparation for
+        // input to USMMLA instructions.
+#define OFFSET_USMMLA 48
+        .byte  0,  1,  2,  3,   4,  5,  6,  7,   2,  3,  4,  5,   6,  7,  8,  9
+        .byte  4,  5,  6,  7,   8,  9, 10, 11,   6,  7,  8,  9,  10, 11, 12, 13
+
+        // Lookup table used to help conversion of shifted 32-bit values to 8-bit.
+#define OFFSET_CVT_32_8 80
+        .byte  1,  2,  5,  6,   9, 10, 13, 14,  17, 18, 21, 22,  25, 26, 29, 30
+endconst
+
+const v_tbl_neon_dotprod, align=4
+        // Vertical convolutions are also using SDOT instructions, where a
+        // 128-bit register contains a transposed 4x4 matrix of values.
+        // Subsequent iterations of the vertical convolution can reuse the
+        // 3x4 sub-matrix from the previous loop iteration. These shuffle
+        // indices shift and merge this 4x4 matrix with the values of a new
+        // line.
+        .byte  1,  2,  3, 16,   5,  6,  7, 20,   9, 10, 11, 24,  13, 14, 15, 28
+        .byte  1,  2,  3, 16,   5,  6,  7, 17,   9, 10, 11, 18,  13, 14, 15, 19
+        .byte  1,  2,  3, 20,   5,  6,  7, 21,   9, 10, 11, 22,  13, 14, 15, 23
+        .byte  1,  2,  3, 24,   5,  6,  7, 25,   9, 10, 11, 26,  13, 14, 15, 27
+        .byte  1,  2,  3, 28,   5,  6,  7, 29,   9, 10, 11, 30,  13, 14, 15, 31
+endconst
+
+
+.macro make_8tap_fn op, type, type_h, type_v, isa, jump=1
+function \op\()_8tap_\type\()_8bpc_\isa, export=1, align=FUNC_ALIGN
+        mov             x9,  \type_h
+        mov             x10, \type_v
+    .if \jump
+        b               \op\()_8tap_\isa
+    .endif
+endfunc
+.endm
+
+.macro filter_8tap_fn type, dot, isa, dst, d_strd, src, s_strd, w, h, mx, my, xmx, xmy, ldst, lsrc, wd_strd
+make_8tap_fn \type, sharp,          SHARP1,   SHARP1,   \isa
+make_8tap_fn \type, sharp_smooth,   SHARP1,   SMOOTH1,  \isa
+make_8tap_fn \type, sharp_regular,  SHARP1,   REGULAR1, \isa
+make_8tap_fn \type, smooth_sharp,   SMOOTH1,  SHARP1,   \isa
+make_8tap_fn \type, smooth,         SMOOTH1,  SMOOTH1,  \isa
+make_8tap_fn \type, smooth_regular, SMOOTH1,  REGULAR1, \isa
+make_8tap_fn \type, regular_sharp,  REGULAR1, SHARP1,   \isa
+make_8tap_fn \type, regular_smooth, REGULAR1, SMOOTH1,  \isa
+make_8tap_fn \type, regular,        REGULAR1, REGULAR1, \isa, jump=0
+
+function \type\()_8tap_\isa, align=FUNC_ALIGN
+        clz             w8, \w
+        mov             w11,  #0x4081   // (1 << 14) | (1 << 7) | (1 << 0)
+        sub             w8, w8, #24     // for jump tables
+        movrel          x12, X(mc_subpel_filters)
+        cbnz            \mx, L(\type\()_8tap_h_hv_\isa)
+        cbnz            \my, L(\type\()_8tap_v_\isa)
+.ifc \type, prep
+        add             \wd_strd, \w, \w    // prep_neon needs w * 2 as stride
+.endif
+        b               X(\type\()_neon)
+
+        .align JUMP_ALIGN
+L(\type\()_8tap_v_\isa):
+        madd            \my, \my, w11, w10
+        movrel          x13, v_tbl_neon_dotprod
+        sub             \src, \src, \s_strd
+.ifc \isa, neon_dotprod
+    .ifc \type, prep
+        mov             w8, #0x2002         // FILTER_WEIGHT * 128 + rounding
+        dup             v4.4s, w8
+    .else
+        movi            v4.4s, #32, lsl #8  // FILTER_WEIGHT * 128, bias for SDOT
+    .endif
+.endif
+        ubfx            w11, \my, #7, #7
+        and             \my, \my, #0x7F
+        ldp             q6, q28, [x13]
+        cmp             \h, #4
+        csel            \my, \my, w11, le
+        sub             \src, \src, \s_strd, lsl #1     // src - s_strd * 3
+        add             \xmy, x12, \xmy, lsl #3         // subpel V filter address
+        ldr             q29, [x13, #32]
+.ifc \isa, neon_dotprod
+        movi            v5.16b, #128
+.endif
+        ldr             d7, [\xmy]
+        cmp             \w, #8
+        b.eq            80f
+        b.lt            40f
+
+        // .align JUMP_ALIGN    // fallthrough
+160:    // V - 16xN+
+        ldp             q30, q31, [x13, #48]
+.ifc \type, prep
+        add             \wd_strd, \w, \w
+.endif
+        .align LOOP_ALIGN
+161:
+        mov             \lsrc, \src
+        mov             \ldst, \dst
+        sub             w8, \h, #1
+
+        ldr             q16, [\lsrc]
+        ldr             q17, [\lsrc, \s_strd]
+        add             \lsrc, \lsrc, \s_strd, lsl #1
+        ldr             q18, [\lsrc]
+        ldr             q19, [\lsrc, \s_strd]
+        add             \lsrc, \lsrc, \s_strd, lsl #1
+
+        zip1            v0.16b, v16.16b, v17.16b
+        zip2            v1.16b, v16.16b, v17.16b
+        zip1            v2.16b, v18.16b, v19.16b
+        zip2            v3.16b, v18.16b, v19.16b
+
+        ldr             q20, [\lsrc]
+        ldr             q21, [\lsrc, \s_strd]
+        add             \lsrc, \lsrc, \s_strd, lsl #1
+        ldr             q22, [\lsrc]
+        ldr             q23, [\lsrc, \s_strd]
+        add             \lsrc, \lsrc, \s_strd, lsl #1
+
+        zip1            v18.16b, v20.16b, v21.16b
+        zip2            v21.16b, v20.16b, v21.16b
+        zip1            v24.16b, v22.16b, v23.16b
+        zip2            v27.16b, v22.16b, v23.16b
+
+        zip1            v16.8h, v0.8h, v2.8h
+        zip2            v19.8h, v0.8h, v2.8h
+        zip1            v22.8h, v1.8h, v3.8h
+        zip2            v25.8h, v1.8h, v3.8h
+
+        zip1            v17.8h, v18.8h, v24.8h
+        zip2            v20.8h, v18.8h, v24.8h
+        zip1            v23.8h, v21.8h, v27.8h
+        zip2            v26.8h, v21.8h, v27.8h
+.ifc \isa, neon_dotprod
+        sub             v16.16b, v16.16b, v5.16b
+        sub             v19.16b, v19.16b, v5.16b
+        sub             v22.16b, v22.16b, v5.16b
+        sub             v25.16b, v25.16b, v5.16b
+
+        sub             v17.16b, v17.16b, v5.16b
+        sub             v20.16b, v20.16b, v5.16b
+        sub             v23.16b, v23.16b, v5.16b
+        sub             v26.16b, v26.16b, v5.16b
+.endif
+        .align LOOP_ALIGN
+16:
+.ifc \isa, neon_i8mm
+        ld1             {v18.16b}, [\lsrc], \s_strd
+        movi            v0.4s, #0
+        movi            v1.4s, #0
+        movi            v2.4s, #0
+        movi            v3.4s, #0
+        mov             v21.16b, v18.16b
+        mov             v24.16b, v18.16b
+        mov             v27.16b, v18.16b
+.else   // neon_dotprod
+        ld1             {v27.16b}, [\lsrc], \s_strd
+        mov             v0.16b, v4.16b
+        mov             v1.16b, v4.16b
+        mov             v2.16b, v4.16b
+        mov             v3.16b, v4.16b
+        sub             v18.16b, v27.16b, v5.16b
+        sub             v21.16b, v27.16b, v5.16b
+        sub             v24.16b, v27.16b, v5.16b
+        sub             v27.16b, v27.16b, v5.16b
+.endif
+        \dot            v0.4s, v16.16b, v7.4b[0]
+        \dot            v1.4s, v19.16b, v7.4b[0]
+        \dot            v2.4s, v22.16b, v7.4b[0]
+        \dot            v3.4s, v25.16b, v7.4b[0]
+
+        tbl             v16.16b, {v16.16b, v17.16b}, v6.16b
+        tbl             v19.16b, {v19.16b, v20.16b}, v6.16b
+        tbl             v22.16b, {v22.16b, v23.16b}, v6.16b
+        tbl             v25.16b, {v25.16b, v26.16b}, v6.16b
+
+        \dot            v0.4s, v17.16b, v7.4b[1]
+        \dot            v1.4s, v20.16b, v7.4b[1]
+        \dot            v2.4s, v23.16b, v7.4b[1]
+        \dot            v3.4s, v26.16b, v7.4b[1]
+
+        tbl             v17.16b, {v17.16b, v18.16b}, v28.16b
+        tbl             v20.16b, {v20.16b, v21.16b}, v29.16b
+        tbl             v23.16b, {v23.16b, v24.16b}, v30.16b
+        tbl             v26.16b, {v26.16b, v27.16b}, v31.16b
+
+        subs            w8, w8, #1
+        uzp1            v0.8h, v0.8h, v1.8h
+        uzp1            v2.8h, v2.8h, v3.8h
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        srshr           v0.8h, v0.8h, #2
+        srshr           v1.8h, v2.8h, #2
+    .else
+        sshr            v0.8h, v0.8h, #2
+        sshr            v1.8h, v2.8h, #2
+    .endif
+        st1             {v0.8h, v1.8h}, [\ldst], \d_strd
+.else   // put
+        sqrshrun        v0.8b, v0.8h, #6
+        sqrshrun2       v0.16b, v2.8h, #6
+        st1             {v0.16b}, [\ldst], \d_strd
+.endif
+        b.gt            16b
+
+.ifc \isa, neon_i8mm
+        movi            v0.4s, #0
+        movi            v1.4s, #0
+        movi            v2.4s, #0
+        movi            v3.4s, #0
+.else   // neon_dotprod
+        mov             v0.16b, v4.16b
+        mov             v1.16b, v4.16b
+        mov             v2.16b, v4.16b
+        mov             v3.16b, v4.16b
+.endif
+        \dot            v0.4s, v16.16b, v7.4b[0]
+        \dot            v1.4s, v19.16b, v7.4b[0]
+        \dot            v2.4s, v22.16b, v7.4b[0]
+        \dot            v3.4s, v25.16b, v7.4b[0]
+
+        \dot            v0.4s, v17.16b, v7.4b[1]
+        \dot            v1.4s, v20.16b, v7.4b[1]
+        \dot            v2.4s, v23.16b, v7.4b[1]
+        \dot            v3.4s, v26.16b, v7.4b[1]
+
+        subs            \w, \w, #16
+        uzp1            v0.8h, v0.8h, v1.8h
+        uzp1            v2.8h, v2.8h, v3.8h
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        srshr           v0.8h, v0.8h, #2
+        srshr           v1.8h, v2.8h, #2
+    .else
+        sshr            v0.8h, v0.8h, #2
+        sshr            v1.8h, v2.8h, #2
+    .endif
+        stp             q0, q1, [\ldst]
+        add             \dst, \dst, #32
+.else   // put
+        sqrshrun        v0.8b, v0.8h, #6
+        sqrshrun2       v0.16b, v2.8h, #6
+        str             q0, [\ldst]
+        add             \dst, \dst, #16
+.endif
+        add             \src, \src, #16
+        b.gt            161b
+        ret
+
+        .align JUMP_ALIGN
+80:     // V - 8xN
+        ldr             d16, [\src]
+        ldr             d17, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             d18, [\src]
+        ldr             d19, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+
+        ldr             d20, [\src]
+        ldr             d21, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             d22, [\src]
+        ldr             d23, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        subs            \h, \h, #2  // for prep: sub is enough
+
+        zip1            v0.16b, v16.16b, v17.16b
+        zip1            v2.16b, v18.16b, v19.16b
+        zip1            v18.16b, v20.16b, v21.16b
+        zip1            v24.16b, v22.16b, v23.16b
+
+        zip1            v16.8h,  v0.8h,  v2.8h
+        zip2            v19.8h,  v0.8h,  v2.8h
+        zip1            v17.8h, v18.8h, v24.8h
+        zip2            v20.8h, v18.8h, v24.8h
+.ifc \isa, neon_dotprod
+        sub             v16.16b, v16.16b, v5.16b
+        sub             v19.16b, v19.16b, v5.16b
+        sub             v17.16b, v17.16b, v5.16b
+        sub             v20.16b, v20.16b, v5.16b
+.endif
+.ifc \type, put
+        b.eq            82f
+.endif
+        .align LOOP_ALIGN
+8:
+.ifc \isa, neon_i8mm
+        ldr             d18, [\src]
+        movi            v0.4s, #0
+        movi            v1.4s, #0
+        ldr             d24, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        movi            v2.4s, #0
+        movi            v3.4s, #0
+        mov             v21.8b, v18.8b
+        mov             v27.8b, v24.8b
+.else   // neon_dotprod
+        ldr             d21, [\src]
+        ldr             d27, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        mov             v0.16b, v4.16b
+        mov             v1.16b, v4.16b
+        mov             v2.16b, v4.16b
+        mov             v3.16b, v4.16b
+        sub             v18.16b, v21.16b, v5.16b
+        sub             v21.16b, v21.16b, v5.16b
+        sub             v24.16b, v27.16b, v5.16b
+        sub             v27.16b, v27.16b, v5.16b
+.endif
+        tbl             v22.16b, {v16.16b, v17.16b}, v6.16b
+        tbl             v25.16b, {v19.16b, v20.16b}, v6.16b
+        tbl             v23.16b, {v17.16b, v18.16b}, v28.16b
+        tbl             v26.16b, {v20.16b, v21.16b}, v29.16b
+
+        \dot            v0.4s, v16.16b, v7.4b[0]
+        \dot            v0.4s, v17.16b, v7.4b[1]
+        \dot            v1.4s, v19.16b, v7.4b[0]
+        \dot            v1.4s, v20.16b, v7.4b[1]
+
+        tbl             v16.16b, {v22.16b, v23.16b}, v6.16b
+        tbl             v19.16b, {v25.16b, v26.16b}, v6.16b
+        tbl             v17.16b, {v23.16b, v24.16b}, v28.16b
+        tbl             v20.16b, {v26.16b, v27.16b}, v29.16b
+
+        \dot            v2.4s, v22.16b, v7.4b[0]
+        \dot            v2.4s, v23.16b, v7.4b[1]
+        \dot            v3.4s, v25.16b, v7.4b[0]
+        \dot            v3.4s, v26.16b, v7.4b[1]
+
+        subs            \h, \h, #2
+        uzp1            v0.8h, v0.8h, v1.8h
+        uzp1            v2.8h, v2.8h, v3.8h
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        srshr           v0.8h, v0.8h, #2
+        srshr           v1.8h, v2.8h, #2
+    .else
+        sshr            v0.8h, v0.8h, #2
+        sshr            v1.8h, v2.8h, #2
+    .endif
+        stp             q0, q1, [\dst], #32
+.else   // put
+        sqrshrun        v0.8b, v0.8h, #6
+        sqrshrun        v1.8b, v2.8h, #6
+        str             d0, [\dst]
+        str             d1, [\dst, \d_strd]
+        add             \dst, \dst, \d_strd, lsl #1
+.endif
+        b.gt            8b
+
+.ifc \type, put
+        .align JUMP_ALIGN
+82:
+.endif
+.ifc \isa, neon_i8mm
+        ldr             d18, [\src]
+        movi            v0.4s, #0
+        movi            v1.4s, #0
+        movi            v2.4s, #0
+        movi            v3.4s, #0
+        mov             v21.8b, v18.8b
+.else   // neon_dotprod
+        ldr             d21, [\src]
+        mov             v0.16b, v4.16b
+        mov             v1.16b, v4.16b
+        mov             v2.16b, v4.16b
+        mov             v3.16b, v4.16b
+        sub             v18.16b, v21.16b, v5.16b
+        sub             v21.16b, v21.16b, v5.16b
+.endif
+        tbl             v22.16b, {v16.16b, v17.16b}, v6.16b
+        tbl             v25.16b, {v19.16b, v20.16b}, v6.16b
+        tbl             v23.16b, {v17.16b, v18.16b}, v28.16b
+        tbl             v26.16b, {v20.16b, v21.16b}, v29.16b
+
+        \dot            v0.4s, v16.16b, v7.4b[0]
+        \dot            v0.4s, v17.16b, v7.4b[1]
+        \dot            v1.4s, v19.16b, v7.4b[0]
+        \dot            v1.4s, v20.16b, v7.4b[1]
+
+        \dot            v2.4s, v22.16b, v7.4b[0]
+        \dot            v2.4s, v23.16b, v7.4b[1]
+        \dot            v3.4s, v25.16b, v7.4b[0]
+        \dot            v3.4s, v26.16b, v7.4b[1]
+
+        uzp1            v0.8h, v0.8h, v1.8h
+        uzp1            v2.8h, v2.8h, v3.8h
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        srshr           v0.8h, v0.8h, #2
+        srshr           v1.8h, v2.8h, #2
+    .else
+        sshr            v0.8h, v0.8h, #2
+        sshr            v1.8h, v2.8h, #2
+    .endif
+        stp             q0, q1, [\dst]
+.else   // put
+        sqrshrun        v0.8b, v0.8h, #6
+        sqrshrun        v1.8b, v2.8h, #6
+        str             d0, [\dst]
+        str             d1, [\dst, \d_strd]
+.endif
+        ret
+
+        .align JUMP_ALIGN
+40:     // V - 4xN or 2xN (put only)
+.ifc \type, put
+        cmp             \w, #2
+        b.eq            20f
+.endif
+        ldr             s16, [\src]
+        ldr             s17, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             s18, [\src]
+        ldr             s19, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+
+        ldr             s20, [\src]
+        ldr             s21, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             s22, [\src]
+        ldr             s23, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        subs            \h, \h, #2  // for prep: sub is enough
+
+        zip1            v0.8b, v16.8b, v17.8b
+        zip1            v2.8b, v18.8b, v19.8b
+        zip1            v18.8b, v20.8b, v21.8b
+        zip1            v24.8b, v22.8b, v23.8b
+
+        zip1            v16.8h, v0.8h, v2.8h
+        zip1            v17.8h, v18.8h, v24.8h
+.ifc \isa, neon_dotprod
+        sub             v16.16b, v16.16b, v5.16b
+        sub             v17.16b, v17.16b, v5.16b
+.endif
+.ifc \type, put
+        b.eq            42f
+.endif
+        .align LOOP_ALIGN
+4:
+        ldr             s18, [\src]
+        ldr             s21, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+.ifc \isa, neon_i8mm
+        movi            v0.4s, #0
+        movi            v1.4s, #0
+.else   // neon_dotprod
+        mov             v0.16b, v4.16b
+        mov             v1.16b, v4.16b
+        sub             v18.16b, v18.16b, v5.16b
+        sub             v21.16b, v21.16b, v5.16b
+.endif
+        tbl             v19.16b, {v16.16b, v17.16b}, v6.16b
+        tbl             v20.16b, {v17.16b, v18.16b}, v28.16b
+
+        \dot            v0.4s, v16.16b, v7.4b[0]
+        \dot            v0.4s, v17.16b, v7.4b[1]
+
+        tbl             v16.16b, {v19.16b, v20.16b}, v6.16b
+        tbl             v17.16b, {v20.16b, v21.16b}, v28.16b
+
+        \dot            v1.4s, v19.16b, v7.4b[0]
+        \dot            v1.4s, v20.16b, v7.4b[1]
+.ifc \type, prep
+        subs            \h, \h, #2
+    .ifc \isa, neon_i8mm
+        rshrn           v0.4h, v0.4s, #2
+        rshrn2          v0.8h, v1.4s, #2
+    .else
+        shrn            v0.4h, v0.4s, #2
+        shrn2           v0.8h, v1.4s, #2
+    .endif
+        str             q0, [\dst], #16
+.else
+        uzp1            v0.8h, v0.8h, v1.8h
+        sqrshrun        v0.8b, v0.8h, #6
+        subs            \h, \h, #2
+        fmov            x8, d0
+        lsr             x9, x8, #32
+        str             w8, [\dst]
+        str             w9, [\dst, \d_strd]
+        add             \dst, \dst, \d_strd, lsl #1
+.endif
+        b.gt            4b
+
+.ifc \type, put
+        .align JUMP_ALIGN
+42:
+.endif
+        ldr             s18, [\src]
+.ifc \isa, neon_i8mm
+        movi            v0.4s, #0
+        movi            v1.4s, #0
+.else   // neon_dotprod
+        mov             v0.16b, v4.16b
+        mov             v1.16b, v4.16b
+        sub             v18.16b, v18.16b, v5.16b
+.endif
+        tbl             v19.16b, {v16.16b, v17.16b}, v6.16b
+        tbl             v20.16b, {v17.16b, v18.16b}, v28.16b
+
+        \dot            v0.4s, v16.16b, v7.4b[0]
+        \dot            v0.4s, v17.16b, v7.4b[1]
+
+        \dot            v1.4s, v19.16b, v7.4b[0]
+        \dot            v1.4s, v20.16b, v7.4b[1]
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        rshrn           v0.4h, v0.4s, #2
+        rshrn2          v0.8h, v1.4s, #2
+    .else
+        shrn            v0.4h, v0.4s, #2
+        shrn2           v0.8h, v1.4s, #2
+    .endif
+        str             q0, [\dst]
+.else
+        uzp1            v0.8h, v0.8h, v1.8h
+        sqrshrun        v0.8b, v0.8h, #6
+        fmov            x8, d0
+        lsr             x9, x8, #32
+        str             w8, [\dst]
+        str             w9, [\dst, \d_strd]
+.endif
+        ret
+
+.ifc \type, put
+        .align JUMP_ALIGN
+20:     // V - 2xN
+        ldr             h16, [\src]
+        ldr             h17, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             h18, [\src]
+        ldr             h19, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+
+        ldr             h20, [\src]
+        ldr             h21, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        ldr             h22, [\src]
+        ldr             h23, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+        subs            \h, \h, #2
+
+        zip1            v0.8b, v16.8b, v17.8b
+        zip1            v2.8b, v18.8b, v19.8b
+        zip1            v18.8b, v20.8b, v21.8b
+        zip1            v24.8b, v22.8b, v23.8b
+
+        zip1            v16.4h, v0.4h, v2.4h
+        zip1            v17.4h, v18.4h, v24.4h
+    .ifc \isa, neon_dotprod
+        sub             v16.8b, v16.8b, v5.8b
+        sub             v17.8b, v17.8b, v5.8b
+    .endif
+        b.eq            22f
+
+        .align LOOP_ALIGN
+2:
+        ldr             h18, [\src]
+        ldr             h21, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+    .ifc \isa, neon_i8mm
+        movi            v0.4s, #0
+        movi            v1.4s, #0
+    .else   // put
+        mov             v0.16b, v4.16b
+        mov             v1.16b, v4.16b
+        sub             v18.8b, v18.8b, v5.8b
+        sub             v21.8b, v21.8b, v5.8b
+    .endif
+        tbl             v19.16b, {v16.16b, v17.16b}, v6.16b
+        tbl             v20.16b, {v17.16b, v18.16b}, v28.16b
+
+        \dot            v0.4s, v16.16b, v7.4b[0]
+        \dot            v0.4s, v17.16b, v7.4b[1]
+
+        tbl             v16.16b, {v19.16b, v20.16b}, v6.16b
+        tbl             v17.16b, {v20.16b, v21.16b}, v28.16b
+
+        \dot            v1.4s, v19.16b, v7.4b[0]
+        \dot            v1.4s, v20.16b, v7.4b[1]
+
+        uzp1            v0.8h, v0.8h, v1.8h
+        sqrshrun        v0.8b, v0.8h, #6
+
+        subs            \h, \h, #2
+        fmov            x8, d0
+        lsr             x9, x8, #32
+        strh            w8, [\dst]
+        strh            w9, [\dst, \d_strd]
+        add             \dst, \dst, \d_strd, lsl #1
+        b.gt            2b
+
+        .align JUMP_ALIGN
+22:
+        ldr             h18, [\src]
+    .ifc \isa, neon_i8mm
+        movi            v0.4s, #0
+        movi            v1.4s, #0
+    .else   // put
+        mov             v0.16b, v4.16b
+        mov             v1.16b, v4.16b
+        sub             v18.8b, v18.8b, v5.8b
+    .endif
+        tbl             v19.16b, {v16.16b, v17.16b}, v6.16b
+        tbl             v20.16b, {v17.16b, v18.16b}, v28.16b
+
+        \dot            v0.4s, v16.16b, v7.4b[0]
+        \dot            v0.4s, v17.16b, v7.4b[1]
+
+        \dot            v1.4s, v19.16b, v7.4b[0]
+        \dot            v1.4s, v20.16b, v7.4b[1]
+
+        uzp1            v0.8h, v0.8h, v1.8h
+        sqrshrun        v0.8b, v0.8h, #6
+
+        fmov            x8, d0
+        lsr             x9, x8, #32
+        strh            w8, [\dst]
+        strh            w9, [\dst, \d_strd]
+        ret
+.endif
+
+        .align JUMP_ALIGN
+L(\type\()_8tap_h_hv_\isa):
+        madd            \mx, \mx, w11, w9
+        madd            w14, \my, w11, w10      // for HV
+.ifc \isa, neon_dotprod
+        mov             w13, #0x2002            // FILTER_WEIGHT * 128 + rounding
+        dup             v27.4s, w13             // put H overrides this
+.endif
+        movrel          x13, h_tbl_neon_dotprod
+        sub             \src, \src, #3          // src - 3
+        ldr             q28, [x13]              // for 4-tap & 8-tap H filters
+        ubfx            w15, \mx, #7, #7
+        and             \mx, \mx, #0x7F
+        ubfx            w11, w14, #7, #7        // for HV
+        and             w14, w14, #0x7F         // for HV
+        cmp             \w, #4
+        csel            \mx, \mx, w15, le
+        add             \xmx, x12, \xmx, lsl #3 // subpel H filter address
+.ifc \isa, neon_dotprod
+        movi            v24.16b, #128
+.endif
+        cbz             \my, L(\type\()_8tap_h_\isa)
+
+        // HV cases
+        cmp             \h, #4
+        csel            w14, w14, w11, le
+        sub             \src, \src, \s_strd, lsl #1 // src - s_strd * 2 - 3
+        add             \xmy, x12, x14, lsl #3      // subpel V filter address
+        mov             x15, x30
+        ldr             d7, [\xmy]
+.ifc \type, put
+        ldr             q25, [x13, #(OFFSET_CVT_32_8)] // LUT to help conversion
+.endif                                                 // of 32b values to 8b
+        sxtl            v7.8h, v7.8b
+        cmp             w10, #SHARP1
+        b.ne            L(\type\()_6tap_hv_\isa)    // vertical != SHARP1
+
+        // HV 8-tap cases
+        sub             \src, \src, \s_strd         // src - s_strd * 3 - 3
+        cmp             \w, #4
+        b.eq            40f
+.ifc \type, put
+        b.lt            20f
+.endif
+
+        // .align JUMP_ALIGN    // fallthrough
+80:     // HV8 - 8xN+
+        ldp             q29, q30, [x13, #16]
+        ldr             d26, [\xmx]
+.ifc \type, prep
+        add             \wd_strd, \w, \w
+.endif
+        .align LOOP_ALIGN
+81:
+        mov             \lsrc, \src
+        mov             \ldst, \dst
+        mov             w8, \h
+.ifc \isa, neon_i8mm
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v16.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v17.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v18.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v19.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v20.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v21.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v22.8h, v22.8h, #2
+.else
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v16.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v17.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v18.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v19.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v20.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v21.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v22.8h, v22.8h, #2
+.endif
+        .align LOOP_ALIGN
+8:
+        ldr             q23, [\lsrc]
+        add             \lsrc, \lsrc, \s_strd
+
+        smull           v0.4s, v16.4h, v7.h[0]
+        smull2          v1.4s, v16.8h, v7.h[0]
+        mov             v16.16b, v17.16b
+.ifc \isa, neon_i8mm
+        movi            v5.4s, #0
+        movi            v6.4s, #0
+        tbl             v2.16b, {v23.16b}, v28.16b
+        tbl             v3.16b, {v23.16b}, v29.16b
+.else   // neon_dotprod
+        sub             v23.16b, v23.16b, v24.16b
+        mov             v5.16b, v27.16b
+        mov             v6.16b, v27.16b
+.endif
+        smlal           v0.4s, v17.4h, v7.h[1]
+        smlal2          v1.4s, v17.8h, v7.h[1]
+.ifc \isa, neon_i8mm
+        tbl             v4.16b, {v23.16b}, v30.16b
+        mov             v17.16b, v18.16b
+.else   // neon_dotprod
+        mov             v17.16b, v18.16b
+        tbl             v2.16b, {v23.16b}, v28.16b
+        tbl             v3.16b, {v23.16b}, v29.16b
+        tbl             v4.16b, {v23.16b}, v30.16b
+.endif
+        smlal           v0.4s, v18.4h, v7.h[2]
+        smlal2          v1.4s, v18.8h, v7.h[2]
+        mov             v18.16b, v19.16b
+
+        \dot            v5.4s, v2.16b, v26.4b[0]
+        \dot            v6.4s, v3.16b, v26.4b[0]
+
+        smlal           v0.4s, v19.4h, v7.h[3]
+        smlal2          v1.4s, v19.8h, v7.h[3]
+        mov             v19.16b, v20.16b
+
+        \dot            v5.4s, v3.16b, v26.4b[1]
+        \dot            v6.4s, v4.16b, v26.4b[1]
+
+        smlal           v0.4s, v20.4h, v7.h[4]
+        smlal2          v1.4s, v20.8h, v7.h[4]
+        mov             v20.16b, v21.16b
+
+        smlal           v0.4s, v21.4h, v7.h[5]
+        smlal2          v1.4s, v21.8h, v7.h[5]
+.ifc \type, prep
+        uzp1            v23.8h, v5.8h, v6.8h
+.endif
+        mov             v21.16b, v22.16b
+        smlal           v0.4s, v22.4h, v7.h[6]
+        smlal2          v1.4s, v22.8h, v7.h[6]
+.ifc \isa, neon_i8mm
+        subs            w8, w8, #1
+.endif
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        srshr           v22.8h, v23.8h, #2
+    .else
+        sshr            v22.8h, v23.8h, #2
+    .endif
+        smlal           v0.4s, v22.4h, v7.h[7]
+        smlal2          v1.4s, v22.8h, v7.h[7]
+        rshrn           v0.4h, v0.4s, #6
+        rshrn2          v0.8h, v1.4s, #6
+.else   // put
+    .ifc \isa, neon_i8mm
+        rshrn           v22.4h, v5.4s, #2
+        rshrn2          v22.8h, v6.4s, #2
+    .else
+        shrn            v22.4h, v5.4s, #2
+        shrn2           v22.8h, v6.4s, #2
+    .endif
+        smlal           v0.4s, v22.4h, v7.h[7]
+        smlal2          v1.4s, v22.8h, v7.h[7]
+        tbl             v0.16b, {v0.16b, v1.16b}, v25.16b
+        sqrshrun        v0.8b, v0.8h, #2
+.endif
+.ifc \isa, neon_dotprod
+        subs            w8, w8, #1
+.endif
+.ifc \type, prep
+        st1             {v0.8h}, [\ldst], \d_strd
+        b.gt            8b
+        add             \dst, \dst, #16
+.else
+        st1             {v0.8b}, [\ldst], \d_strd
+        b.gt            8b
+        add             \dst, \dst, #8
+.endif
+        add             \src, \src, #8
+        subs            \w, \w, #8
+        b.gt            81b
+        ret             x15
+
+        .align JUMP_ALIGN
+40:     // HV8 - 4xN
+        ldur            s26, [\xmx, #2]
+        add             \src, \src, #2
+
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v16.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v17.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v18.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v19.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v20.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v21.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v22.4h, v22.4s, #2
+
+        .align LOOP_ALIGN
+4:
+        ld1             {v4.8b}, [\src], \s_strd
+
+        smull           v0.4s, v16.4h, v7.h[0]
+        smlal           v0.4s, v17.4h, v7.h[1]
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+.ifc \isa, neon_dotprod
+        sub             v4.16b, v4.16b, v24.16b
+.endif
+        smlal           v0.4s, v18.4h, v7.h[2]
+        smlal           v0.4s, v19.4h, v7.h[3]
+        tbl             v2.16b, {v4.16b}, v28.16b
+.ifc \isa, neon_i8mm
+        movi            v5.4s, #0
+.else
+        mov             v5.16b, v27.16b
+.endif
+        mov             v18.16b, v19.16b
+        mov             v19.16b, v20.16b
+
+        smlal           v0.4s, v20.4h, v7.h[4]
+        smlal           v0.4s, v21.4h, v7.h[5]
+
+        \dot            v5.4s, v2.16b, v26.4b[0]
+        mov             v20.16b, v21.16b
+        mov             v21.16b, v22.16b
+        smlal           v0.4s, v22.4h, v7.h[6]
+.ifc \isa, neon_i8mm
+        rshrn           v22.4h, v5.4s, #2
+.else
+        shrn            v22.4h, v5.4s, #2
+.endif
+        smlal           v0.4s, v22.4h, v7.h[7]
+.ifc \type, prep
+        rshrn           v0.4h, v0.4s, #6
+        str             d0, [\dst], #8
+        subs            \h, \h, #1
+.else
+        subs            \h, \h, #1
+        tbl             v0.8b, {v0.16b}, v25.8b
+        sqrshrun        v0.8b, v0.8h, #2
+        str             s0, [\dst]
+        add             \dst, \dst, \d_strd
+.endif
+        b.gt            4b
+        ret             x15
+
+.ifc \type, put
+        .align JUMP_ALIGN
+20:     // HV8 - 2xN
+        ldur            s26, [\xmx, #2]
+        add             \src, \src, #2
+
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v16.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v17.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v18.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v19.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v20.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v21.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v22.4h, v22.4s, #2
+
+        .align LOOP_ALIGN
+2:
+        ld1             {v4.8b}, [\src], \s_strd
+
+        smull           v0.4s, v16.4h, v7.h[0]
+        smlal           v0.4s, v17.4h, v7.h[1]
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+    .ifc \isa, neon_dotprod
+        sub             v4.16b, v4.16b, v24.16b
+    .endif
+        smlal           v0.4s, v18.4h, v7.h[2]
+        smlal           v0.4s, v19.4h, v7.h[3]
+        tbl             v2.16b, {v4.16b}, v28.16b
+    .ifc \isa, neon_i8mm
+        movi            v5.4s, #0
+    .else
+        mov             v5.16b, v27.16b
+    .endif
+        mov             v18.16b, v19.16b
+        mov             v19.16b, v20.16b
+
+        smlal           v0.4s, v20.4h, v7.h[4]
+        smlal           v0.4s, v21.4h, v7.h[5]
+
+        \dot            v5.4s, v2.16b, v26.4b[0]
+        mov             v20.16b, v21.16b
+        mov             v21.16b, v22.16b
+
+        smlal           v0.4s, v22.4h, v7.h[6]
+    .ifc \isa, neon_i8mm
+        rshrn           v22.4h, v5.4s, #2
+    .else
+        shrn            v22.4h, v5.4s, #2
+    .endif
+        smlal           v0.4s, v22.4h, v7.h[7]
+        subs            \h, \h, #1
+
+        tbl             v0.8b, {v0.16b}, v25.8b
+        sqrshrun        v0.8b, v0.8h, #2
+
+        str             h0, [\dst]
+        add             \dst, \dst, \d_strd
+        b.gt            2b
+        ret             x15
+.endif
+
+        .align JUMP_ALIGN
+L(\type\()_6tap_hv_\isa):
+        cmp             \w, #4
+        b.eq            40f
+.ifc \type, put
+        b.lt            20f
+.endif
+
+        // .align JUMP_ALIGN    // fallthrough
+80:     // HV6 - 8xN+
+        ldr             d26, [\xmx]
+.ifc \type, prep
+        add             \wd_strd, \w, \w
+.endif
+.ifc \isa, neon_i8mm
+        cmp             w9, #SHARP1
+        b.eq            88f             // horizontal == SHARP1
+
+        ldp             q29, q30, [x13, #(OFFSET_USMMLA)]
+        ext             v0.8b, v26.8b, v26.8b, #7
+        ins             v26.d[1], v0.d[0]
+
+        .align LOOP_ALIGN
+81:
+        mov             \lsrc, \src
+        mov             \ldst, \dst
+        mov             w8, \h
+
+        bl              L(\type\()_hv_filter6_neon_i8mm)
+        srshr           v16.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter6_neon_i8mm)
+        srshr           v17.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter6_neon_i8mm)
+        srshr           v18.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter6_neon_i8mm)
+        srshr           v19.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter6_neon_i8mm)
+        srshr           v20.8h, v22.8h, #2
+
+        .align LOOP_ALIGN
+8:
+        ld1             {v23.16b}, [\lsrc], \s_strd
+
+        smull           v0.4s, v16.4h, v7.h[1]
+        smull2          v1.4s, v16.8h, v7.h[1]
+        mov             v16.16b, v17.16b
+        movi            v5.4s, #0
+        movi            v6.4s, #0
+        tbl             v2.16b, {v23.16b}, v29.16b
+        tbl             v3.16b, {v23.16b}, v30.16b
+
+        smlal           v0.4s, v17.4h, v7.h[2]
+        smlal2          v1.4s, v17.8h, v7.h[2]
+        mov             v17.16b, v18.16b
+
+        usmmla          v5.4s, v2.16b, v26.16b
+        usmmla          v6.4s, v3.16b, v26.16b
+
+        smlal           v0.4s, v18.4h, v7.h[3]
+        smlal2          v1.4s, v18.8h, v7.h[3]
+        mov             v18.16b, v19.16b
+        subs            w8, w8, #1
+
+        smlal           v0.4s, v19.4h, v7.h[4]
+        smlal2          v1.4s, v19.8h, v7.h[4]
+        uzp1            v23.8h, v5.8h, v6.8h
+        mov             v19.16b, v20.16b
+
+        smlal           v0.4s, v20.4h, v7.h[5]
+        smlal2          v1.4s, v20.8h, v7.h[5]
+        srshr           v20.8h, v23.8h, #2
+        smlal           v0.4s, v20.4h, v7.h[6]
+        smlal2          v1.4s, v20.8h, v7.h[6]
+    .ifc \type, prep
+        rshrn           v0.4h, v0.4s, #6
+        rshrn2          v0.8h, v1.4s, #6
+        st1             {v0.8h}, [\ldst], \d_strd
+        b.gt            8b
+        add             \dst, \dst, #16
+    .else
+        tbl             v0.16b, {v0.16b, v1.16b}, v25.16b
+        sqrshrun        v0.8b, v0.8h, #2
+        st1             {v0.8b}, [\ldst], \d_strd
+        b.gt            8b
+        add             \dst, \dst, #8
+    .endif
+        add             \src, \src, #8
+        subs            \w, \w, #8
+        b.gt            81b
+        ret             x15
+
+        .align JUMP_ALIGN
+88:
+.endif  // neon_i8mm
+        ldp             q29, q30, [x13, #16]
+
+        .align LOOP_ALIGN
+81:
+        mov             \lsrc, \src
+        mov             \ldst, \dst
+        mov             w8, \h
+.ifc \isa, neon_i8mm
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v16.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v17.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v18.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v19.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        srshr           v20.8h, v22.8h, #2
+.else
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v16.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v17.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v18.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v19.8h, v22.8h, #2
+        bl              L(\type\()_hv_filter8_\isa)
+        sshr            v20.8h, v22.8h, #2
+.endif
+        .align LOOP_ALIGN
+8:
+        ldr             q23, [\lsrc]
+        add             \lsrc, \lsrc, \s_strd
+
+        smull           v0.4s, v16.4h, v7.h[1]
+        smull2          v1.4s, v16.8h, v7.h[1]
+.ifc \isa, neon_dotprod
+        sub             v23.16b, v23.16b, v24.16b
+.endif
+        mov             v16.16b, v17.16b
+.ifc \isa, neon_i8mm
+        movi            v5.4s, #0
+        movi            v6.4s, #0
+.else
+        mov             v5.16b, v27.16b
+        mov             v6.16b, v27.16b
+.endif
+        tbl             v2.16b, {v23.16b}, v28.16b
+        tbl             v3.16b, {v23.16b}, v29.16b
+
+        smlal           v0.4s, v17.4h, v7.h[2]
+        smlal2          v1.4s, v17.8h, v7.h[2]
+        tbl             v4.16b, {v23.16b}, v30.16b
+        mov             v17.16b, v18.16b
+
+        \dot            v5.4s, v2.16b, v26.4b[0]
+        \dot            v6.4s, v3.16b, v26.4b[0]
+
+        smlal           v0.4s, v18.4h, v7.h[3]
+        smlal2          v1.4s, v18.8h, v7.h[3]
+        mov             v18.16b, v19.16b
+
+        \dot            v5.4s, v3.16b, v26.4b[1]
+        \dot            v6.4s, v4.16b, v26.4b[1]
+
+        smlal           v0.4s, v19.4h, v7.h[4]
+        smlal2          v1.4s, v19.8h, v7.h[4]
+        mov             v19.16b, v20.16b
+        uzp1            v23.8h, v5.8h, v6.8h
+
+        smlal           v0.4s, v20.4h, v7.h[5]
+        smlal2          v1.4s, v20.8h, v7.h[5]
+.ifc \isa, neon_i8mm
+        srshr           v20.8h, v23.8h, #2
+.else
+        sshr            v20.8h, v23.8h, #2
+.endif
+        subs            w8, w8, #1
+        smlal           v0.4s, v20.4h, v7.h[6]
+        smlal2          v1.4s, v20.8h, v7.h[6]
+.ifc \type, prep
+        rshrn           v0.4h, v0.4s, #6
+        rshrn2          v0.8h, v1.4s, #6
+        st1             {v0.8h}, [\ldst], \d_strd
+        b.gt            8b
+        add             \dst, \dst, #16
+.else
+        tbl             v0.16b, {v0.16b, v1.16b}, v25.16b
+        sqrshrun        v0.8b, v0.8h, #2
+        st1             {v0.8b}, [\ldst], \d_strd
+        b.gt            8b
+        add             \dst, \dst, #8
+.endif
+        add             \src, \src, #8
+        subs            \w, \w, #8
+        b.gt            81b
+        ret             x15
+
+        .align FUNC_ALIGN
+L(\type\()_hv_filter8_\isa):
+        ld1             {v4.16b}, [\lsrc], \s_strd
+.ifc \isa, neon_i8mm
+        movi            v22.4s, #0
+        movi            v23.4s, #0
+.else   // neon_dotprod
+        sub             v4.16b, v4.16b, v24.16b
+        mov             v22.16b, v27.16b
+        mov             v23.16b, v27.16b
+.endif
+        tbl             v2.16b, {v4.16b}, v28.16b
+        tbl             v3.16b, {v4.16b}, v29.16b
+        tbl             v4.16b, {v4.16b}, v30.16b
+        \dot            v22.4s, v2.16b, v26.4b[0]
+        \dot            v23.4s, v3.16b, v26.4b[0]
+        \dot            v22.4s, v3.16b, v26.4b[1]
+        \dot            v23.4s, v4.16b, v26.4b[1]
+        uzp1            v22.8h, v22.8h, v23.8h
+        ret
+
+.ifc \isa, neon_i8mm
+        .align FUNC_ALIGN
+L(\type\()_hv_filter6_neon_i8mm):
+        ld1             {v4.16b}, [\lsrc], \s_strd
+        movi            v22.4s, #0
+        movi            v23.4s, #0
+        tbl             v2.16b, {v4.16b}, v29.16b
+        tbl             v3.16b, {v4.16b}, v30.16b
+        usmmla          v22.4s, v2.16b, v26.16b
+        usmmla          v23.4s, v3.16b, v26.16b
+        uzp1            v22.8h, v22.8h, v23.8h
+        ret
+.endif
+
+        .align FUNC_ALIGN
+L(\type\()_hv_filter4_\isa):
+        ld1             {v4.8b}, [\src], \s_strd
+.ifc \isa, neon_i8mm
+        movi            v22.4s, #2
+.else
+        mov             v22.16b, v27.16b
+        sub             v4.16b, v4.16b, v24.16b
+.endif
+        tbl             v2.16b, {v4.16b}, v28.16b
+        \dot            v22.4s, v2.16b, v26.4b[0]
+        ret
+
+        .align JUMP_ALIGN
+40:     // HV6 - 4xN
+        ldur            s26, [\xmx, #2]
+        add             \src, \src, #2
+
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v16.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v17.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v18.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v19.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v20.4h, v22.4s, #2
+
+        .align LOOP_ALIGN
+4:
+        ld1             {v4.8b}, [\src], \s_strd
+
+        smull           v0.4s, v16.4h, v7.h[1]
+        smlal           v0.4s, v17.4h, v7.h[2]
+.ifc \isa, neon_dotprod
+        sub             v4.16b, v4.16b, v24.16b
+.endif
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+
+        smlal           v0.4s, v18.4h, v7.h[3]
+        smlal           v0.4s, v19.4h, v7.h[4]
+        tbl             v2.16b, {v4.16b}, v28.16b
+.ifc \isa, neon_i8mm
+        movi            v5.4s, #0
+.else
+        mov             v5.16b, v27.16b
+.endif
+        mov             v18.16b, v19.16b
+        mov             v19.16b, v20.16b
+        \dot            v5.4s, v2.16b, v26.4b[0]
+
+        smlal           v0.4s, v20.4h, v7.h[5]
+.ifc \isa, neon_i8mm
+        rshrn           v20.4h, v5.4s, #2
+.else
+        shrn            v20.4h, v5.4s, #2
+.endif
+        subs            \h, \h, #1
+        smlal           v0.4s, v20.4h, v7.h[6]
+.ifc \type, prep
+        rshrn           v0.4h, v0.4s, #6
+        str             d0, [\dst], #8
+.else
+        tbl             v0.8b, {v0.16b}, v25.8b
+        sqrshrun        v0.8b, v0.8h, #2
+        str             s0, [\dst]
+        add             \dst, \dst, \d_strd
+.endif
+        b.gt            4b
+        ret             x15
+
+.ifc \type, put
+        .align JUMP_ALIGN
+20:     // HV6 - 2xN
+        ldur            s26, [\xmx, #2]
+        add             \src, \src, #2
+
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v16.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v17.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v18.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v19.4h, v22.4s, #2
+        bl              L(\type\()_hv_filter4_\isa)
+        shrn            v20.4h, v22.4s, #2
+
+        .align LOOP_ALIGN
+2:
+        ld1             {v4.8b}, [\src], \s_strd
+
+        smull           v0.4s, v16.4h, v7.h[1]
+        smlal           v0.4s, v17.4h, v7.h[2]
+    .ifc \isa, neon_dotprod
+        sub             v4.16b, v4.16b, v24.16b
+    .endif
+        mov             v16.16b, v17.16b
+        mov             v17.16b, v18.16b
+
+        smlal           v0.4s, v18.4h, v7.h[3]
+        smlal           v0.4s, v19.4h, v7.h[4]
+        tbl             v2.16b, {v4.16b}, v28.16b
+    .ifc \isa, neon_i8mm
+        movi            v5.4s, #0
+    .else
+        mov             v5.16b, v27.16b
+    .endif
+
+        mov             v18.16b, v19.16b
+        mov             v19.16b, v20.16b
+        \dot            v5.4s, v2.16b, v26.4b[0]
+
+        smlal           v0.4s, v20.4h, v7.h[5]
+    .ifc \isa, neon_i8mm
+        rshrn           v20.4h, v5.4s, #2
+    .else
+        shrn            v20.4h, v5.4s, #2
+    .endif
+
+        subs            \h, \h, #1
+        smlal           v0.4s, v20.4h, v7.h[6]
+
+        tbl             v0.8b, {v0.16b}, v25.8b
+        sqrshrun        v0.8b, v0.8h, #2
+
+        str             h0, [\dst]
+        add             \dst, \dst, \d_strd
+        b.gt            2b
+        ret             x15
+.endif
+
+        .align JUMP_ALIGN
+L(\type\()_8tap_h_\isa):
+        movrel          x11, \type\()_8tap_h_\isa\()_tbl
+        ldrsw           x8, [x11, x8, lsl #2]
+.ifc \type, put
+    .ifc \isa, neon_i8mm
+        movi            v27.4s, #34     // special rounding
+    .else
+        mov             w10, #0x2022    // 64 * 128 + 34, bias and rounding for SDOT
+        dup             v27.4s, w10
+    .endif
+.endif
+        add             x11, x11, x8
+        br              x11
+
+.ifc \type, put
+        .align JUMP_ALIGN
+20:     // H - 2xN
+        AARCH64_VALID_JUMP_TARGET
+        add             \src, \src, #2
+        ldur            s26, [\xmx, #2]
+
+        .align LOOP_ALIGN
+2:
+        ldr             d0, [\src]
+        ldr             d1, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+    .ifc \isa, neon_dotprod
+        sub             v0.8b, v0.8b, v24.8b
+        sub             v1.8b, v1.8b, v24.8b
+    .endif
+        mov             v4.16b, v27.16b
+        mov             v5.16b, v27.16b
+
+        tbl             v2.16b, {v0.16b}, v28.16b
+        tbl             v3.16b, {v1.16b}, v28.16b
+
+        \dot            v4.4s, v2.16b, v26.4b[0]
+        \dot            v5.4s, v3.16b, v26.4b[0]
+
+        uzp1            v4.8h, v4.8h, v5.8h
+        sqshrun         v4.8b, v4.8h, #6
+
+        subs            \h, \h, #2
+        fmov            x8, d4
+        lsr             x9, x8, #32
+        strh            w8, [\dst]
+        strh            w9, [\dst, \d_strd]
+        add             \dst, \dst, \d_strd, lsl #1
+        b.gt            2b
+        ret
+.endif
+
+        .align JUMP_ALIGN
+40:     // H - 4xN
+        AARCH64_VALID_JUMP_TARGET
+        add             \src, \src, #2
+        ldur            s26, [\xmx, #2]
+
+        .align LOOP_ALIGN
+4:
+        ldr             d0, [\src]
+        ldr             d1, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+.ifc \type\()_\isa, prep_neon_i8mm
+        movi            v4.4s, #0
+        movi            v5.4s, #0
+.else
+    .ifc \isa, neon_dotprod
+        sub             v0.8b, v0.8b, v24.8b
+        sub             v1.8b, v1.8b, v24.8b
+    .endif
+        mov             v4.16b, v27.16b
+        mov             v5.16b, v27.16b
+.endif
+        tbl             v2.16b, {v0.16b}, v28.16b
+        tbl             v3.16b, {v1.16b}, v28.16b
+
+        \dot            v4.4s, v2.16b, v26.4b[0]
+        \dot            v5.4s, v3.16b, v26.4b[0]
+.ifc \type, prep
+        subs            \h, \h, #2
+    .ifc \isa, neon_i8mm
+        uzp1            v4.8h, v4.8h, v5.8h
+        srshr           v4.8h, v4.8h, #2
+    .else
+        shrn            v4.4h, v4.4s, #2
+        shrn2           v4.8h, v5.4s, #2
+    .endif
+        str             q4, [\dst], #16
+.else   // put
+        uzp1            v4.8h, v4.8h, v5.8h
+        sqshrun         v4.8b, v4.8h, #6
+        subs            \h, \h, #2
+        fmov            x8, d4
+        lsr             x9, x8, #32
+        str             w8, [\dst]
+        str             w9, [\dst, \d_strd]
+        add             \dst, \dst, \d_strd, lsl #1
+.endif
+        b.gt            4b
+        ret
+
+        .align JUMP_ALIGN
+80:     // H - 8xN
+        AARCH64_VALID_JUMP_TARGET
+        ldr             d26, [\xmx]
+.ifc \isa, neon_i8mm
+        cmp             w9, #SHARP1
+        b.eq            88f             // horizontal == SHARP1
+
+        ldp             q29, q30, [x13, #(OFFSET_USMMLA)]
+        ext             v0.8b, v26.8b, v26.8b, #7
+        ins             v26.d[1], v0.d[0]
+
+        .align LOOP_ALIGN
+8:
+        ldr             q0, [\src]
+        ldr             q16, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+    .ifc \type, prep
+        movi            v4.4s, #0
+        movi            v5.4s, #0
+        movi            v20.4s, #0
+        movi            v21.4s, #0
+    .else
+        mov             v4.16b, v27.16b
+        mov             v5.16b, v27.16b
+        mov             v20.16b, v27.16b
+        mov             v21.16b, v27.16b
+    .endif
+        tbl             v1.16b, {v0.16b}, v29.16b
+        tbl             v2.16b, {v0.16b}, v30.16b
+        tbl             v17.16b, {v16.16b}, v29.16b
+        tbl             v18.16b, {v16.16b}, v30.16b
+
+        usmmla          v4.4s, v1.16b, v26.16b
+        usmmla          v5.4s, v2.16b, v26.16b
+        usmmla          v20.4s, v17.16b, v26.16b
+        usmmla          v21.4s, v18.16b, v26.16b
+
+        uzp1            v4.8h, v4.8h, v5.8h
+        uzp1            v20.8h, v20.8h, v21.8h
+    .ifc \type, prep
+        srshr           v4.8h, v4.8h, #2
+        srshr           v20.8h, v20.8h, #2
+        subs            \h, \h, #2
+        stp             q4, q20, [\dst], #32
+    .else   // put
+        sqshrun         v4.8b, v4.8h, #6
+        sqshrun         v20.8b, v20.8h, #6
+        subs            \h, \h, #2
+        str             d4, [\dst]
+        str             d20, [\dst, \d_strd]
+        add             \dst, \dst, \d_strd, lsl #1
+    .endif
+        b.gt            8b
+        ret
+
+        .align JUMP_ALIGN
+88:
+.endif  // neon_i8mm
+        ldp             q29, q30, [x13, #16]
+
+        .align LOOP_ALIGN
+8:
+        ldr             q0, [\src]
+        ldr             q16, [\src, \s_strd]
+        add             \src, \src, \s_strd, lsl #1
+.ifc \type\()_\isa, prep_neon_i8mm
+        movi            v4.4s, #0
+        movi            v5.4s, #0
+        movi            v20.4s, #0
+        movi            v21.4s, #0
+.else
+    .ifc \isa, neon_dotprod
+        sub             v0.16b, v0.16b, v24.16b
+        sub             v16.16b, v16.16b, v24.16b
+    .endif
+        mov             v4.16b, v27.16b
+        mov             v5.16b, v27.16b
+        mov             v20.16b, v27.16b
+        mov             v21.16b, v27.16b
+.endif
+        tbl             v1.16b, {v0.16b}, v28.16b
+        tbl             v2.16b, {v0.16b}, v29.16b
+        tbl             v3.16b, {v0.16b}, v30.16b
+        tbl             v17.16b, {v16.16b}, v28.16b
+        tbl             v18.16b, {v16.16b}, v29.16b
+        tbl             v19.16b, {v16.16b}, v30.16b
+
+        \dot            v4.4s, v1.16b, v26.4b[0]
+        \dot            v5.4s, v2.16b, v26.4b[0]
+        \dot            v20.4s, v17.16b, v26.4b[0]
+        \dot            v21.4s, v18.16b, v26.4b[0]
+        \dot            v4.4s, v2.16b, v26.4b[1]
+        \dot            v5.4s, v3.16b, v26.4b[1]
+        \dot            v20.4s, v18.16b, v26.4b[1]
+        \dot            v21.4s, v19.16b, v26.4b[1]
+
+        uzp1            v4.8h, v4.8h, v5.8h
+        uzp1            v20.8h, v20.8h, v21.8h
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        srshr           v4.8h, v4.8h, #2
+        srshr           v20.8h, v20.8h, #2
+    .else
+        sshr            v4.8h, v4.8h, #2
+        sshr            v20.8h, v20.8h, #2
+    .endif
+        subs            \h, \h, #2
+        stp             q4, q20, [\dst], #32
+.else   // put
+        sqshrun         v4.8b, v4.8h, #6
+        sqshrun         v20.8b, v20.8h, #6
+        subs            \h, \h, #2
+        str             d4, [\dst]
+        str             d20, [\dst, \d_strd]
+        add             \dst, \dst, \d_strd, lsl #1
+.endif
+        b.gt            8b
+        ret
+
+        .align JUMP_ALIGN
+160:    // H - 16xN
+        AARCH64_VALID_JUMP_TARGET
+        ldr             d26, [\xmx]
+.ifc \isa, neon_i8mm
+        cmp             w9, #SHARP1
+        b.eq            168f            // horizontal == SHARP1
+
+        ldp             q29, q30, [x13, #(OFFSET_USMMLA)]
+        ext             v0.8b, v26.8b, v26.8b, #7
+        ins             v26.d[1], v0.d[0]
+
+        .align LOOP_ALIGN
+16:
+        ldr             q16, [\src]
+        ldur            q17, [\src, #8] // avoid 2 register TBL for small cores
+        add             \src, \src, \s_strd
+    .ifc \type, prep
+        movi            v6.4s, #0
+        movi            v7.4s, #0
+        movi            v22.4s, #0
+        movi            v23.4s, #0
+    .else
+        mov             v6.16b, v27.16b
+        mov             v7.16b, v27.16b
+        mov             v22.16b, v27.16b
+        mov             v23.16b, v27.16b
+    .endif
+        tbl             v0.16b, {v16.16b}, v29.16b
+        tbl             v1.16b, {v16.16b}, v30.16b
+        tbl             v2.16b, {v17.16b}, v29.16b
+        tbl             v3.16b, {v17.16b}, v30.16b
+
+        usmmla          v6.4s, v0.16b, v26.16b
+        usmmla          v7.4s, v1.16b, v26.16b
+        usmmla          v22.4s, v2.16b, v26.16b
+        usmmla          v23.4s, v3.16b, v26.16b
+
+        uzp1            v6.8h, v6.8h, v7.8h
+        uzp1            v22.8h, v22.8h, v23.8h
+    .ifc \type, prep
+        srshr           v6.8h, v6.8h, #2
+        srshr           v22.8h, v22.8h, #2
+        subs            \h, \h, #1
+        stp             q6, q22, [\dst], #32
+    .else   // put
+        sqshrun         v6.8b, v6.8h, #6
+        sqshrun2        v6.16b, v22.8h, #6
+        subs            \h, \h, #1
+        st1             {v6.16b}, [\dst], \d_strd
+    .endif
+        b.gt            16b
+        ret
+
+        .align JUMP_ALIGN
+168:
+.endif  // neon_i8mm
+        ldp             q29, q30, [x13, #16]
+
+        .align LOOP_ALIGN
+16:
+        ldr             q16, [\src]
+        ldur            q17, [\src, #12]  // avoid 2 register TBL for small cores
+        add             \src, \src, \s_strd
+.ifc \type\()_\isa, prep_neon_i8mm
+        movi            v6.4s, #0
+        movi            v7.4s, #0
+        movi            v22.4s, #0
+        movi            v23.4s, #0
+.else
+    .ifc \isa, neon_dotprod
+        sub             v16.16b, v16.16b, v24.16b
+        sub             v17.16b, v17.16b, v24.16b
+    .endif
+        mov             v6.16b, v27.16b
+        mov             v7.16b, v27.16b
+        mov             v22.16b, v27.16b
+        mov             v23.16b, v27.16b
+.endif
+        tbl             v0.16b, {v16.16b}, v28.16b
+        tbl             v1.16b, {v16.16b}, v29.16b
+        tbl             v2.16b, {v16.16b}, v30.16b
+        tbl             v3.16b, {v17.16b}, v28.16b
+        tbl             v4.16b, {v17.16b}, v29.16b
+
+        \dot            v6.4s, v0.16b, v26.4b[0]
+        \dot            v7.4s, v1.16b, v26.4b[0]
+        \dot            v22.4s, v2.16b, v26.4b[0]
+        \dot            v23.4s, v3.16b, v26.4b[0]
+        \dot            v6.4s, v1.16b, v26.4b[1]
+        \dot            v7.4s, v2.16b, v26.4b[1]
+        \dot            v22.4s, v3.16b, v26.4b[1]
+        \dot            v23.4s, v4.16b, v26.4b[1]
+
+        uzp1            v6.8h, v6.8h, v7.8h
+        uzp1            v22.8h, v22.8h, v23.8h
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        srshr           v6.8h, v6.8h, #2
+        srshr           v22.8h, v22.8h, #2
+    .else
+        sshr            v6.8h, v6.8h, #2
+        sshr            v22.8h, v22.8h, #2
+    .endif
+        subs            \h, \h, #1
+        stp             q6, q22, [\dst], #32
+.else   // put
+        sqshrun         v6.8b, v6.8h, #6
+        sqshrun2        v6.16b, v22.8h, #6
+        subs            \h, \h, #1
+        st1             {v6.16b}, [\dst], \d_strd
+.endif
+        b.gt            16b
+        ret
+
+        .align JUMP_ALIGN
+320:    // H - 32xN+
+640:
+1280:
+        AARCH64_VALID_JUMP_TARGET
+        ldr             d26, [\xmx]
+.ifc \type, put
+        sub             \d_strd, \d_strd, \w, uxtw
+.endif
+        sub             \s_strd, \s_strd, \w, uxtw
+        mov             w8, \w
+
+.ifc \isa, neon_i8mm
+        cmp             w9, #SHARP1
+        b.eq            328f            // horizontal == SHARP1
+
+        ldp             q29, q30, [x13, #(OFFSET_USMMLA)]
+        ext             v0.8b, v26.8b, v26.8b, #7
+        ins             v26.d[1], v0.d[0]
+
+        .align LOOP_ALIGN
+32:
+        ldr             q16, [\src]
+        ldur            q17, [\src, #8] // avoid 2 register TBL for small cores
+        add             \src, \src, #16
+    .ifc \type, prep
+        movi            v6.4s, #0
+        movi            v7.4s, #0
+        movi            v22.4s, #0
+        movi            v23.4s, #0
+    .else
+        mov             v6.16b, v27.16b
+        mov             v7.16b, v27.16b
+        mov             v22.16b, v27.16b
+        mov             v23.16b, v27.16b
+    .endif
+        tbl             v0.16b, {v16.16b}, v29.16b
+        tbl             v1.16b, {v16.16b}, v30.16b
+        tbl             v2.16b, {v17.16b}, v29.16b
+        tbl             v3.16b, {v17.16b}, v30.16b
+
+        usmmla          v6.4s, v0.16b, v26.16b
+        usmmla          v7.4s, v1.16b, v26.16b
+        usmmla          v22.4s, v2.16b, v26.16b
+        usmmla          v23.4s, v3.16b, v26.16b
+
+        uzp1            v6.8h, v6.8h, v7.8h
+        uzp1            v22.8h, v22.8h, v23.8h
+    .ifc \type, prep
+        srshr           v6.8h, v6.8h, #2
+        srshr           v22.8h, v22.8h, #2
+        subs            w8, w8, #16
+        stp             q6, q22, [\dst], #32
+    .else   // put
+        sqshrun         v6.8b, v6.8h, #6
+        sqshrun2        v6.16b, v22.8h, #6
+        subs            w8, w8, #16
+        str             q6, [\dst], #16
+    .endif
+        b.gt            32b
+
+        add             \src, \src, \s_strd
+    .ifc \type, put
+        add             \dst, \dst, \d_strd
+    .endif
+        mov             w8, \w
+        subs            \h, \h, #1
+        b.gt            32b
+        ret
+
+        .align JUMP_ALIGN
+328:
+.endif  // neon_i8mm
+        ldp             q29, q30, [x13, #16]
+
+        .align LOOP_ALIGN
+32:
+        ldr             q16, [\src]
+        ldur            q17, [\src, #12]  // avoid 2 register TBL for small cores
+        add             \src, \src, #16
+.ifc \type\()_\isa, prep_neon_i8mm
+        movi            v6.4s, #0
+        movi            v7.4s, #0
+        movi            v22.4s, #0
+        movi            v23.4s, #0
+.else
+    .ifc \isa, neon_dotprod
+        sub             v16.16b, v16.16b, v24.16b
+        sub             v17.16b, v17.16b, v24.16b
+    .endif
+        mov             v6.16b, v27.16b
+        mov             v7.16b, v27.16b
+        mov             v22.16b, v27.16b
+        mov             v23.16b, v27.16b
+.endif
+        tbl             v0.16b, {v16.16b}, v28.16b
+        tbl             v1.16b, {v16.16b}, v29.16b
+        tbl             v2.16b, {v16.16b}, v30.16b
+        tbl             v3.16b, {v17.16b}, v28.16b
+        tbl             v4.16b, {v17.16b}, v29.16b
+
+        \dot            v6.4s, v0.16b, v26.4b[0]
+        \dot            v7.4s, v1.16b, v26.4b[0]
+        \dot            v22.4s, v2.16b, v26.4b[0]
+        \dot            v23.4s, v3.16b, v26.4b[0]
+        \dot            v6.4s, v1.16b, v26.4b[1]
+        \dot            v7.4s, v2.16b, v26.4b[1]
+        \dot            v22.4s, v3.16b, v26.4b[1]
+        \dot            v23.4s, v4.16b, v26.4b[1]
+
+        uzp1            v6.8h, v6.8h, v7.8h
+        uzp1            v22.8h, v22.8h, v23.8h
+.ifc \type, prep
+    .ifc \isa, neon_i8mm
+        srshr           v6.8h, v6.8h, #2
+        srshr           v22.8h, v22.8h, #2
+    .else
+        sshr            v6.8h, v6.8h, #2
+        sshr            v22.8h, v22.8h, #2
+    .endif
+        subs            w8, w8, #16
+        stp             q6, q22, [\dst], #32
+.else   // put
+        sqshrun         v6.8b, v6.8h, #6
+        sqshrun2        v6.16b, v22.8h, #6
+        subs            w8, w8, #16
+        str             q6, [\dst], #16
+.endif
+        b.gt            32b
+
+        add             \src, \src, \s_strd
+.ifc \type, put
+        add             \dst, \dst, \d_strd
+.endif
+        mov             w8, \w
+        subs            \h, \h, #1
+        b.gt            32b
+        ret
+endfunc
+
+jumptable \type\()_8tap_h_\isa\()_tbl
+        .word 1280b - \type\()_8tap_h_\isa\()_tbl
+        .word 640b  - \type\()_8tap_h_\isa\()_tbl
+        .word 320b  - \type\()_8tap_h_\isa\()_tbl
+        .word 160b  - \type\()_8tap_h_\isa\()_tbl
+        .word 80b   - \type\()_8tap_h_\isa\()_tbl
+        .word 40b   - \type\()_8tap_h_\isa\()_tbl
+.ifc \type, put
+        .word 20b   - \type\()_8tap_h_\isa\()_tbl
+.endif
+endjumptable
+.endm
+
+// dst(x0), d_strd(x7), src(x1), s_strd(x2), w(w3), h(w4), mx(w5), my(w6)
+// xmx(x5), xmy(x6), ldst(x5), lsrc(x6), wd_strd(w7)
+filter_8tap_fn prep, sdot, neon_dotprod, x0, x7, x1, x2, w3, w4, w5, w6, x5, x6, x5, x6, w7
+
+// dst(x0) d_strd(x1) src(x2) s_strd(x3) w(w4) h(w5) mx(w6) my(w7)
+// xmx(x6), xmy(x7), ldst(x6), lsrc(x7), wd_strd(w1)
+filter_8tap_fn  put, sdot, neon_dotprod, x0, x1, x2, x3, w4, w5, w6, w7, x6, x7, x6, x7, w1
+
+#if HAVE_I8MM
+ENABLE_I8MM
+
+// dst(x0), d_strd(x7), src(x1), s_strd(x2), w(w3), h(w4), mx(w5), my(w6)
+// xmx(x5), xmy(x6), ldst(x5), lsrc(x6), wd_strd(w7)
+filter_8tap_fn prep, usdot, neon_i8mm, x0, x7, x1, x2, w3, w4, w5, w6, x5, x6, x5, x6, w7
+
+// dst(x0) d_strd(x1) src(x2) s_strd(x3) w(w4) h(w5) mx(w6) my(w7)
+// xmx(x6), xmy(x7), ldst(x6), lsrc(x7), wd_strd(w1)
+filter_8tap_fn  put, usdot, neon_i8mm, x0, x1, x2, x3, w4, w5, w6, w7, x6, x7, x6, x7, w1
+
+DISABLE_I8MM
+#endif  // HAVE_I8MM
+
+DISABLE_DOTPROD
+#endif  // HAVE_DOTPROD
diff --git a/media/libdav1d/src/src/arm/64/msac.S b/media/libdav1d/src/src/arm/64/msac.S
new file mode 100644
index 0000000000..a1a8c92e79
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/msac.S
@@ -0,0 +1,595 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm.S"
+#include "util.S"
+
+#define BUF_POS 0
+#define BUF_END 8
+#define DIF 16
+#define RNG 24
+#define CNT 28
+#define ALLOW_UPDATE_CDF 32
+
+#define COEFFS_BASE_OFFSET 30
+#define MASKS8_OFFSET (64-COEFFS_BASE_OFFSET)
+
+const coeffs
+        .short 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0
+        .short 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0
+        // masks8
+        .short -0x202, -0x202, -0x202, -0x202, -0x202, -0x202, -0x202, 0xF0E
+endconst
+
+.macro ld1_n d0, d1, src, sz, n
+.if \n <= 8
+        ld1             {\d0\sz},  [\src]
+.else
+        ld1             {\d0\sz, \d1\sz},  [\src]
+.endif
+.endm
+
+.macro st1_n s0, s1, dst, sz, n
+.if \n <= 8
+        st1             {\s0\sz},  [\dst]
+.else
+        st1             {\s0\sz, \s1\sz},  [\dst]
+.endif
+.endm
+
+.macro ushr_n d0, d1, s0, s1, shift, sz, n
+        ushr            \d0\sz,  \s0\sz,  \shift
+.if \n == 16
+        ushr            \d1\sz,  \s1\sz,  \shift
+.endif
+.endm
+
+.macro add_n d0, d1, s0, s1, s2, s3, sz, n
+        add             \d0\sz,  \s0\sz,  \s2\sz
+.if \n == 16
+        add             \d1\sz,  \s1\sz,  \s3\sz
+.endif
+.endm
+
+.macro sub_n d0, d1, s0, s1, s2, s3, sz, n
+        sub             \d0\sz,  \s0\sz,  \s2\sz
+.if \n == 16
+        sub             \d1\sz,  \s1\sz,  \s3\sz
+.endif
+.endm
+
+.macro and_n d0, d1, s0, s1, s2, s3, sz, n
+        and             \d0\sz,  \s0\sz,  \s2\sz
+.if \n == 16
+        and             \d1\sz,  \s1\sz,  \s3\sz
+.endif
+.endm
+
+.macro cmhs_n d0, d1, s0, s1, s2, s3, sz, n
+        cmhs            \d0\sz,  \s0\sz,  \s2\sz
+.if \n == 16
+        cmhs            \d1\sz,  \s1\sz,  \s3\sz
+.endif
+.endm
+
+.macro sshl_n d0, d1, s0, s1, s2, s3, sz, n
+        sshl            \d0\sz,  \s0\sz,  \s2\sz
+.if \n == 16
+        sshl            \d1\sz,  \s1\sz,  \s3\sz
+.endif
+.endm
+
+.macro sqdmulh_n d0, d1, s0, s1, s2, s3, sz, n
+        sqdmulh         \d0\sz,  \s0\sz,  \s2\sz
+.if \n == 16
+        sqdmulh         \d1\sz,  \s1\sz,  \s3\sz
+.endif
+.endm
+
+.macro str_n            idx0, idx1, dstreg, dstoff, n
+        str             \idx0,  [\dstreg, \dstoff]
+.if \n == 16
+        str             \idx1,  [\dstreg, \dstoff + 16]
+.endif
+.endm
+
+// unsigned dav1d_msac_decode_symbol_adapt4_neon(MsacContext *s, uint16_t *cdf,
+//                                               size_t n_symbols);
+
+function msac_decode_symbol_adapt4_neon, export=1
+.macro decode_update sz, szb, n
+.if \n == 16
+        sub             sp,  sp,  #48
+.endif
+        add             x8,  x0,  #RNG
+        ld1_n           v0,  v1,  x1,  \sz, \n                    // cdf
+        ld1r            {v29\sz}, [x8]                            // rng
+        movrel          x9,  coeffs, COEFFS_BASE_OFFSET
+        movi            v31\sz, #0x7f, lsl #8                     // 0x7f00
+        sub             x10, x9,  x2, lsl #1
+        mvni            v30\sz, #0x3f                             // 0xffc0
+        and             v7\szb, v29\szb, v31\szb                  // rng & 0x7f00
+.if \n == 16
+        str             h29, [sp, #14]                            // store original u = s->rng
+.endif
+        and_n           v2,  v3,  v0,  v1,  v30, v30, \szb, \n    // cdf & 0xffc0
+
+        ld1_n           v4,  v5,  x10, \sz, \n                    // EC_MIN_PROB * (n_symbols - ret)
+        sqdmulh_n       v6,  v7,  v2,  v3,  v7,  v7,  \sz, \n     // ((cdf >> EC_PROB_SHIFT) * (r - 128)) >> 1
+        ldr             d28, [x0, #DIF]
+
+        add_n           v4,  v5,  v2,  v3,  v4,  v5,  \sz, \n     // v = cdf + EC_MIN_PROB * (n_symbols - ret)
+        add_n           v4,  v5,  v6,  v7,  v4,  v5,  \sz, \n     // v = ((cdf >> EC_PROB_SHIFT) * r) >> 1 + EC_MIN_PROB * (n_symbols - ret)
+
+        dup             v30\sz, v28.h[3]                          // dif >> (EC_WIN_SIZE - 16)
+.if \n == 8
+        ldur            q31, [x9, #MASKS8_OFFSET]
+.elseif \n == 16
+        str_n           q4,  q5,  sp, #16, \n                     // store v values to allow indexed access
+.endif
+
+        // After the condition starts being true it continues, such that the vector looks like:
+        //   0, 0, 0 ... -1, -1
+        cmhs_n          v2,  v3,  v30, v30, v4,  v5,  \sz,  \n    // c >= v
+.if \n == 4
+        ext             v29\szb, v29\szb, v4\szb, #6              // u
+        umov            x15, v2.d[0]
+        ldr             w4,  [x0, #ALLOW_UPDATE_CDF]
+        rev             x15, x15
+        sub             v29\sz, v29\sz, v4\sz                     // rng = u-v
+        // rev + clz = count trailing zeros
+        clz             x15, x15                                  // 16*ret
+.elseif \n == 8
+        // The final short of the compare is always set.
+        // Using addv, subtract -0x202*ret from this value to create a lookup table for a short.
+        //  For n == 8:
+        // -0x202 + -0x202 + ... + 0xF0E
+        //                    (0x202*7) | (1 << 8)
+        //                                    ^-------offset for second byte of the short
+        and             v31\szb, v31\szb, v2\szb
+        ext             v29\szb, v29\szb, v4\szb, #14             // u
+        addv            h31, v31\sz                               // ((2*ret + 1) << 8) | (2*ret)
+        ldr             w4,  [x0, #ALLOW_UPDATE_CDF]
+        sub             v30\sz, v30\sz, v4\sz                     // (dif >> 48) - v
+        smov            w15, v31.b[0]                             // 2*ret
+        sub             v29\sz, v29\sz, v4\sz                     // rng = u-v
+.elseif \n == 16
+        add             v6\sz,  v2\sz,  v3\sz
+        addv            h31, v6\sz                                // -n + ret
+        ldr             w4,  [x0, #ALLOW_UPDATE_CDF]
+        smov            w15, v31.h[0]
+.endif
+
+        cbz             w4,  0f
+
+        // update_cdf
+        ldrh            w3,  [x1, x2, lsl #1]                     // count = cdf[n_symbols]
+.if \n == 16
+        // 16 case has a lower bound that guarantees n_symbols > 2
+        mov             w4,  #-5
+.elseif \n == 8
+        mvn             w14, w2
+        mov             w4,  #-4
+        cmn             w14, #3                                   // set C if n_symbols <= 2
+.else
+        // if n_symbols < 4 (or < 6 even) then
+        //   (1 + n_symbols) >> 2 == n_symbols > 2
+        add             w14, w2,  #17                             // (1 + n_symbols) + (4 << 2)
+.endif
+        sub_n           v16, v17, v0,  v1,  v2,  v3,  \sz, \n     // cdf + (i >= val ? 1 : 0)
+        orr             v2\sz, #0x80, lsl #8
+.if \n == 16
+        orr             v3\sz, #0x80, lsl #8
+.endif
+.if \n == 16
+        sub             w4,  w4,  w3, lsr #4                      // -((count >> 4) + 5)
+.elseif \n == 8
+        lsr             w14, w3,  #4                              // count >> 4
+        sbc             w4,  w4,  w14                             // -((count >> 4) + (n_symbols > 2) + 4)
+.else
+        neg             w4, w14, lsr #2                           // -((n_symbols > 2) + 4)
+        sub             w4,  w4,  w3,  lsr #4                     // -((count >> 4) + (n_symbols > 2) + 4)
+.endif
+        sub_n           v2,  v3,  v2,  v3,  v0,  v1,  \sz, \n     // (32768 - cdf[i]) or (-1 - cdf[i])
+        dup             v6\sz,    w4                              // -rate
+
+        sub             w3,  w3,  w3, lsr #5                      // count - (count == 32)
+        sshl_n          v2,  v3,  v2,  v3,  v6,  v6,  \sz, \n     // ({32768,-1} - cdf[i]) >> rate
+        add             w3,  w3,  #1                              // count + (count < 32)
+        add_n           v0,  v1,  v16, v17, v2,  v3,  \sz, \n     // cdf + (32768 - cdf[i]) >> rate
+        st1_n           v0,  v1,  x1,  \sz, \n
+        strh            w3,  [x1, x2, lsl #1]
+
+0:
+        // renorm
+.if \n == 4
+        ldr             w6,  [x0, #CNT]
+        ldr             x7,  [x0, #DIF]
+        mov             x4,  v29.d[0]          // rng (packed)
+        mov             x3,  v4.d[0]           // v (packed)
+
+        // Shift 'v'/'rng' for ret into the 16 least sig bits. There is
+        //  garbage in the remaining bits, but we can work around this.
+        lsr             x4,  x4,  x15          // rng
+        lsr             x3,  x3,  x15          // v
+        lsl             w5,  w4,  #16          // rng << 16
+        sub             x7,  x7,  x3, lsl #48  // dif - (v << 48)
+        clz             w5,  w5                // d = clz(rng << 16)
+        lsl             w4,  w4,  w5           // rng << d
+        subs            w6,  w6,  w5           // cnt -= d
+        lsl             x7,  x7,  x5           // (dif - (v << 48)) << d
+        strh            w4,  [x0, #RNG]
+        b.lo            1f
+        str             w6,  [x0, #CNT]
+        str             x7,  [x0, #DIF]
+        lsr             w0,  w15, #4
+        ret
+1:
+        lsr             w15, w15, #4
+        b L(refill)
+.elseif \n == 8
+        ldr             w6,  [x0, #CNT]
+        tbl             v30.8b, {v30.16b}, v31.8b
+        tbl             v29.8b, {v29.16b}, v31.8b
+        ins             v28.h[3], v30.h[0]     // dif - (v << 48)
+        clz             v0.4h,  v29.4h         // d = clz(rng)
+        umov            w5,  v0.h[0]
+        ushl            v29.4h, v29.4h, v0.4h  // rng << d
+
+        // The vec for clz(rng) is filled with garbage after the first short,
+        //  but ushl/sshl conveniently uses only the first byte for the shift
+        //  amount.
+        ushl            d28, d28, d0           // (dif - (v << 48)) << d
+
+        subs            w6,  w6,  w5           // cnt -= d
+        str             h29, [x0, #RNG]
+        b.lo            1f
+        str             w6,  [x0, #CNT]
+        str             d28, [x0, #DIF]
+        lsr             w0,  w15, #1           // ret
+        ret
+1:
+        lsr             w15, w15, #1           // ret
+        mov             x7, v28.d[0]
+        b L(refill)
+.elseif \n == 16
+        add             x8,  sp,  w15, sxtw #1
+        ldrh            w3,  [x8, #48]         // v
+        ldurh           w4,  [x8, #46]         // u
+        ldr             w6,  [x0, #CNT]
+        ldr             x7,  [x0, #DIF]
+        sub             w4,  w4,  w3           // rng = u - v
+        clz             w5,  w4                // clz(rng)
+        eor             w5,  w5,  #16          // d = clz(rng) ^ 16
+        sub             x7,  x7,  x3, lsl #48  // dif - (v << 48)
+        lsl             w4,  w4,  w5           // rng << d
+        subs            w6,  w6,  w5           // cnt -= d
+        lsl             x7,  x7,  x5           // (dif - (v << 48)) << d
+        str             w4,  [x0, #RNG]
+        add             sp,  sp,  #48
+        b.lo            1f
+        str             w6,  [x0, #CNT]
+        str             x7,  [x0, #DIF]
+        add             w0,  w15, #\n          // ret
+        ret
+1:
+        add             w15, w15, #\n          // ret
+        b L(refill)
+.endif
+.endm
+
+        decode_update   .4h, .8b, 4
+
+L(refill):
+        // refill
+        ldp             x3,  x4,  [x0]         // BUF_POS, BUF_END
+        add             x5,  x3,  #8
+        subs            x5,  x5,  x4
+        b.hi            6f
+
+        ldr             x8,  [x3]              // next_bits
+        add             w4,  w6,  #-48         // shift_bits = cnt + 16 (- 64)
+        mvn             x8,  x8
+        neg             w5,  w4
+        rev             x8,  x8                // next_bits = bswap(next_bits)
+        lsr             w5,  w5,  #3           // num_bytes_read
+        lsr             x8,  x8,  x4           // next_bits >>= (shift_bits & 63)
+
+2:      // refill_end
+        add             x3,  x3,  x5
+        add             w6,  w6,  w5, lsl #3   // cnt += num_bits_read
+        str             x3,  [x0, #BUF_POS]
+
+3:      // refill_end2
+        orr             x7,  x7,  x8           // dif |= next_bits
+
+4:      // end
+        str             w6,  [x0, #CNT]
+        str             x7,  [x0, #DIF]
+
+        mov             w0,  w15
+        ret
+
+5:      // pad_with_ones
+        add             w8,  w6,  #-16
+        ror             x8,  x8,  x8
+        b               3b
+
+6:      // refill_eob
+        cmp             x3,  x4
+        b.hs            5b
+
+        ldr             x8,  [x4, #-8]
+        lsl             w5,  w5,  #3
+        lsr             x8,  x8,  x5
+        add             w5,  w6,  #-48
+        mvn             x8,  x8
+        sub             w4,  w4,  w3           // num_bytes_left
+        rev             x8,  x8
+        lsr             x8,  x8,  x5
+        neg             w5,  w5
+        lsr             w5,  w5,  #3
+        cmp             w5,  w4
+        csel            w5,  w5,  w4,  lo      // num_bytes_read
+        b               2b
+endfunc
+
+function msac_decode_symbol_adapt8_neon, export=1
+        decode_update   .8h, .16b, 8
+endfunc
+
+function msac_decode_symbol_adapt16_neon, export=1
+        decode_update   .8h, .16b, 16
+endfunc
+
+function msac_decode_hi_tok_neon, export=1
+        ld1             {v0.4h},  [x1]            // cdf
+        add             x16, x0,  #RNG
+        movi            v31.4h, #0x7f, lsl #8     // 0x7f00
+        movrel          x17, coeffs, COEFFS_BASE_OFFSET-2*3
+        mvni            v30.4h, #0x3f             // 0xffc0
+        ldrh            w9,  [x1, #6]             // count = cdf[n_symbols]
+        ld1r            {v3.4h},  [x16]           // rng
+        ld1             {v29.4h}, [x17]           // EC_MIN_PROB * (n_symbols - ret)
+        add             x17, x0,  #DIF + 6
+        mov             w13, #-24*8
+        and             v17.8b,  v0.8b,   v30.8b  // cdf & 0xffc0
+        ldr             w10, [x0, #ALLOW_UPDATE_CDF]
+        ld1r            {v1.8h},  [x17]           // dif >> (EC_WIN_SIZE - 16)
+        ldr             w6,  [x0, #CNT]
+        ldr             x7,  [x0, #DIF]
+1:
+        and             v7.8b,   v3.8b,   v31.8b  // rng & 0x7f00
+        sqdmulh         v6.4h,   v17.4h,  v7.4h   // ((cdf >> EC_PROB_SHIFT) * (r - 128)) >> 1
+        add             v4.4h,   v17.4h,  v29.4h  // v = cdf + EC_MIN_PROB * (n_symbols - ret)
+        add             v4.4h,   v6.4h,   v4.4h   // v = ((cdf >> EC_PROB_SHIFT) * r) >> 1 + EC_MIN_PROB * (n_symbols - ret)
+        cmhs            v2.4h,   v1.4h,   v4.4h   // c >= v
+        add             w13, w13, #5*8
+        ext             v18.8b, v3.8b,  v4.8b, #6 // u
+        umov            x15, v2.d[0]
+        rev             x15, x15
+        sub             v18.4h, v18.4h, v4.4h     // rng = u-v
+        // rev + clz = count trailing zeros
+        clz             x15, x15                  // 16*ret
+
+        cbz             w10, 2f
+        // update_cdf
+        sub             v5.4h,   v0.4h,   v2.4h   // cdf[i] + (i >= val ? 1 : 0)
+        mov             w4,  #-5
+        orr             v2.4h, #0x80, lsl #8      // i >= val ? -1 : 32768
+        sub             w4,  w4,  w9, lsr #4      // -((count >> 4) + 5)
+        sub             v2.4h,   v2.4h,   v0.4h   // (32768 - cdf[i]) or (-1 - cdf[i])
+        dup             v6.4h,    w4              // -rate
+
+        sub             w9,  w9,  w9, lsr #5      // count - (count == 32)
+        sshl            v2.4h,   v2.4h,   v6.4h   // ({32768,-1} - cdf[i]) >> rate
+        add             w9,  w9,  #1              // count + (count < 32)
+        add             v0.4h,   v5.4h,   v2.4h   // cdf[i] + (32768 - cdf[i]) >> rate
+        st1             {v0.4h},  [x1]
+        and             v17.8b,  v0.8b,   v30.8b  // cdf & 0xffc0
+        strh            w9,  [x1, #6]
+
+2:
+        mov             x4,  v18.d[0]          // rng (packed)
+        mov             x3,  v4.d[0]           // v (packed)
+
+        // Shift 'v'/'rng' for ret into the 16 least sig bits. There is
+        //  garbage in the remaining bits, but we can work around this.
+        lsr             x4,  x4,  x15          // rng
+        lsr             x3,  x3,  x15          // v
+        lsl             w5,  w4,  #16          // rng << 16
+        sub             x7,  x7,  x3, lsl #48  // dif - (v << 48)
+        clz             w5,  w5                // d = clz(rng << 16)
+        lsl             w4,  w4,  w5           // rng << d
+        subs            w6,  w6,  w5           // cnt -= d
+        lsl             x7,  x7,  x5           // (dif - (v << 48)) << d
+        strh            w4,  [x0, #RNG]
+        dup             v3.4h,   w4
+        b.hs            5f
+
+        // refill
+        ldp             x3,  x4,  [x0]         // BUF_POS, BUF_END
+        add             x5,  x3,  #8
+        subs            x5,  x5,  x4
+        b.hi            7f
+
+        ldr             x8,  [x3]              // next_bits
+        add             w4,  w6,  #-48         // shift_bits = cnt + 16 (- 64)
+        mvn             x8,  x8
+        neg             w5,  w4
+        rev             x8,  x8                // next_bits = bswap(next_bits)
+        lsr             w5,  w5,  #3           // num_bytes_read
+        lsr             x8,  x8,  x4           // next_bits >>= (shift_bits & 63)
+
+3:      // refill_end
+        add             x3,  x3,  x5
+        add             w6,  w6,  w5, lsl #3   // cnt += num_bits_read
+        str             x3,  [x0, #BUF_POS]
+
+4:      // refill_end2
+        orr             x7,  x7,  x8           // dif |= next_bits
+
+5:      // end
+        sub             w15, w15, #5*8
+        lsr             x12, x7,  #48
+        adds            w13, w13, w15          // carry = tok_br < 3 || tok == 15
+        dup             v1.8h,   w12
+        b.cc            1b                     // loop if !carry
+        add             w13, w13, #30*8
+        str             w6,  [x0, #CNT]
+        str             x7,  [x0, #DIF]
+        lsr             w0,  w13, #4
+        ret
+
+6:      // pad_with_ones
+        add             w8,  w6,  #-16
+        ror             x8,  x8,  x8
+        b               4b
+
+7:      // refill_eob
+        cmp             x3,  x4
+        b.hs            6b
+
+        ldr             x8,  [x4, #-8]
+        lsl             w5,  w5,  #3
+        lsr             x8,  x8,  x5
+        add             w5,  w6,  #-48
+        mvn             x8,  x8
+        sub             w4,  w4,  w3           // num_bytes_left
+        rev             x8,  x8
+        lsr             x8,  x8,  x5
+        neg             w5,  w5
+        lsr             w5,  w5,  #3
+        cmp             w5,  w4
+        csel            w5,  w5,  w4,  lo      // num_bytes_read
+        b               3b
+endfunc
+
+function msac_decode_bool_equi_neon, export=1
+        ldp             w5,  w6,  [x0, #RNG]   // + CNT
+        ldr             x7,  [x0, #DIF]
+        bic             w4,  w5,  #0xff        // r &= 0xff00
+        add             w4,  w4,  #8
+        subs            x8,  x7,  x4, lsl #47  // dif - vw
+        lsr             w4,  w4,  #1           // v
+        sub             w5,  w5,  w4           // r - v
+        cset            w15, lo
+        csel            w4,  w5,  w4,  hs      // if (ret) v = r - v;
+        csel            x7,  x8,  x7,  hs      // if (ret) dif = dif - vw;
+
+        clz             w5,  w4                // clz(rng)
+        eor             w5,  w5,  #16          // d = clz(rng) ^ 16
+        lsl             w4,  w4,  w5           // rng << d
+        subs            w6,  w6,  w5           // cnt -= d
+        lsl             x7,  x7,  x5           // (dif - (v << 48)) << d
+        str             w4,  [x0, #RNG]
+        b.lo            L(refill)
+
+        str             w6,  [x0, #CNT]
+        str             x7,  [x0, #DIF]
+        mov             w0,  w15
+        ret
+endfunc
+
+function msac_decode_bool_neon, export=1
+        ldp             w5,  w6,  [x0, #RNG]   // + CNT
+        ldr             x7,  [x0, #DIF]
+        lsr             w4,  w5,  #8           // r >> 8
+        bic             w1,  w1,  #0x3f        // f &= ~63
+        mul             w4,  w4,  w1
+        lsr             w4,  w4,  #7
+        add             w4,  w4,  #4           // v
+        subs            x8,  x7,  x4, lsl #48  // dif - vw
+        sub             w5,  w5,  w4           // r - v
+        cset            w15, lo
+        csel            w4,  w5,  w4,  hs      // if (ret) v = r - v;
+        csel            x7,  x8,  x7,  hs      // if (ret) dif = dif - vw;
+
+        clz             w5,  w4                // clz(rng)
+        eor             w5,  w5,  #16          // d = clz(rng) ^ 16
+        lsl             w4,  w4,  w5           // rng << d
+        subs            w6,  w6,  w5           // cnt -= d
+        lsl             x7,  x7,  x5           // (dif - (v << 48)) << d
+        str             w4,  [x0, #RNG]
+        b.lo            L(refill)
+
+        str             w6,  [x0, #CNT]
+        str             x7,  [x0, #DIF]
+        mov             w0,  w15
+        ret
+endfunc
+
+function msac_decode_bool_adapt_neon, export=1
+        ldr             w9,  [x1]              // cdf[0-1]
+        ldp             w5,  w6,  [x0, #RNG]   // + CNT
+        ldr             x7,  [x0, #DIF]
+        lsr             w4,  w5,  #8           // r >> 8
+        and             w2,  w9,  #0xffc0      // f &= ~63
+        mul             w4,  w4,  w2
+        lsr             w4,  w4,  #7
+        add             w4,  w4,  #4           // v
+        subs            x8,  x7,  x4, lsl #48  // dif - vw
+        sub             w5,  w5,  w4           // r - v
+        cset            w15, lo
+        csel            w4,  w5,  w4,  hs      // if (ret) v = r - v;
+        csel            x7,  x8,  x7,  hs      // if (ret) dif = dif - vw;
+
+        ldr             w10, [x0, #ALLOW_UPDATE_CDF]
+
+        clz             w5,  w4                // clz(rng)
+        eor             w5,  w5,  #16          // d = clz(rng) ^ 16
+
+        cbz             w10, 1f
+
+        lsr             w2,  w9,  #16          // count = cdf[1]
+        and             w9,  w9,  #0xffff      // cdf[0]
+
+        sub             w3,  w2,  w2, lsr #5   // count - (count >= 32)
+        lsr             w2,  w2,  #4           // count >> 4
+        add             w10, w3,  #1           // count + (count < 32)
+        add             w2,  w2,  #4           // rate = (count >> 4) | 4
+
+        sub             w9,  w9,  w15          // cdf[0] -= bit
+        sub             w11, w9,  w15, lsl #15 // {cdf[0], cdf[0] - 32769}
+        asr             w11, w11, w2           // {cdf[0], cdf[0] - 32769} >> rate
+        sub             w9,  w9,  w11          // cdf[0]
+
+        strh            w9,  [x1]
+        strh            w10, [x1, #2]
+
+1:
+        lsl             w4,  w4,  w5           // rng << d
+        subs            w6,  w6,  w5           // cnt -= d
+        lsl             x7,  x7,  x5           // (dif - (v << 48)) << d
+        str             w4,  [x0, #RNG]
+        b.lo            L(refill)
+
+        str             w6,  [x0, #CNT]
+        str             x7,  [x0, #DIF]
+        mov             w0,  w15
+        ret
+endfunc
diff --git a/media/libdav1d/src/src/arm/64/refmvs.S b/media/libdav1d/src/src/arm/64/refmvs.S
new file mode 100644
index 0000000000..0638cf4566
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/refmvs.S
@@ -0,0 +1,546 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * Copyright © 2021, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm-offsets.h"
+#include "src/arm/asm.S"
+#include "util.S"
+
+#define INVALID_MV 0x80008000
+
+// void dav1d_splat_mv_neon(refmvs_block **rr, const refmvs_block *rmv,
+//                          int bx4, int bw4, int bh4)
+
+function splat_mv_neon, export=1
+        ld1             {v3.16b},  [x1]
+        clz             w3,  w3
+        movrel          x5,  splat_tbl
+        sub             w3,  w3,  #26
+        ext             v2.16b,  v3.16b,  v3.16b,  #12
+        ldrsw           x3,  [x5, w3, uxtw #2]
+        add             w2,  w2,  w2,  lsl #1
+        ext             v0.16b,  v2.16b,  v3.16b,  #4
+        add             x3,  x5,  x3
+        ext             v1.16b,  v2.16b,  v3.16b,  #8
+        lsl             w2,  w2,  #2
+        ext             v2.16b,  v2.16b,  v3.16b,  #12
+1:
+        ldr             x1,  [x0],  #8
+        subs            w4,  w4,  #1
+        add             x1,  x1,  x2
+        br              x3
+
+10:
+        AARCH64_VALID_JUMP_TARGET
+        st1             {v0.8b}, [x1]
+        str             s2,  [x1, #8]
+        b.gt            1b
+        ret
+20:
+        AARCH64_VALID_JUMP_TARGET
+        st1             {v0.16b}, [x1]
+        str             d1,  [x1, #16]
+        b.gt            1b
+        ret
+320:
+        AARCH64_VALID_JUMP_TARGET
+        st1             {v0.16b, v1.16b, v2.16b}, [x1], #48
+        st1             {v0.16b, v1.16b, v2.16b}, [x1], #48
+        st1             {v0.16b, v1.16b, v2.16b}, [x1], #48
+        st1             {v0.16b, v1.16b, v2.16b}, [x1], #48
+160:
+        AARCH64_VALID_JUMP_TARGET
+        st1             {v0.16b, v1.16b, v2.16b}, [x1], #48
+        st1             {v0.16b, v1.16b, v2.16b}, [x1], #48
+80:
+        AARCH64_VALID_JUMP_TARGET
+        st1             {v0.16b, v1.16b, v2.16b}, [x1], #48
+40:
+        AARCH64_VALID_JUMP_TARGET
+        st1             {v0.16b, v1.16b, v2.16b}, [x1]
+        b.gt            1b
+        ret
+endfunc
+
+jumptable splat_tbl
+        .word 320b  - splat_tbl
+        .word 160b  - splat_tbl
+        .word 80b   - splat_tbl
+        .word 40b   - splat_tbl
+        .word 20b   - splat_tbl
+        .word 10b   - splat_tbl
+endjumptable
+
+const mv_tbls, align=4
+        .byte           255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+        .byte           0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0
+        .byte           4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
+        .byte           4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
+endconst
+
+const mask_mult, align=4
+        .byte           1, 2, 1, 2, 0, 0, 0, 0
+endconst
+
+// void dav1d_save_tmvs_neon(refmvs_temporal_block *rp, ptrdiff_t stride,
+//                           refmvs_block **rr, const uint8_t *ref_sign,
+//                           int col_end8, int row_end8,
+//                           int col_start8, int row_start8)
+function save_tmvs_neon, export=1
+        AARCH64_SIGN_LINK_REGISTER
+        stp             x29, x30, [sp, #-16]!
+        mov             x29, sp
+
+        movi            v30.8b,  #0
+        ld1             {v31.8b}, [x3]
+        movrel          x8,  save_tmvs_tbl
+        movrel          x16, mask_mult
+        movrel          x13, mv_tbls
+        ld1             {v29.8b}, [x16]
+        ext             v31.8b,  v30.8b,  v31.8b,  #7 // [0, ref_sign]
+        mov             w15, #5
+        mov             w14, #12*2
+        sxtw            x4,  w4
+        sxtw            x6,  w6
+        mul             w1,  w1,  w15             // stride *= 5
+        sub             w5,  w5,  w7              // h = row_end8 - row_start8
+        lsl             w7,  w7,  #1              // row_start8 <<= 1
+1:
+        mov             w15, #5
+        and             w9,  w7,  #30             // (y & 15) * 2
+        ldr             x9,  [x2, w9, uxtw #3]    // b = rr[(y & 15) * 2]
+        add             x9,  x9,  #12             // &b[... + 1]
+        madd            x10, x4,  x14,  x9        // end_cand_b = &b[col_end8*2 + 1]
+        madd            x9,  x6,  x14,  x9        // cand_b = &b[x*2 + 1]
+
+        madd            x3,  x6,  x15,  x0        // &rp[x]
+
+2:
+        ldrb            w11, [x9, #10]            // cand_b->bs
+        ld1             {v0.16b}, [x9]            // cand_b->mv
+        add             x11, x8,  w11, uxtw #3
+        ldr             h1,  [x9, #8]             // cand_b->ref
+        ldr             w12, [x11]                // bw8
+        mov             x15, x8
+        add             x9,  x9,  w12, uxtw #1    // cand_b += bw8*2
+        cmp             x9,  x10
+        mov             v2.8b,   v0.8b
+        b.ge            3f
+
+        ldrb            w15, [x9, #10]            // cand_b->bs
+        add             x16, x9,  #8
+        ld1             {v4.16b}, [x9]            // cand_b->mv
+        add             x15, x8,  w15, uxtw #3
+        ld1             {v1.h}[1], [x16]          // cand_b->ref
+        ldr             w12, [x15]                // bw8
+        add             x9,  x9,  w12, uxtw #1    // cand_b += bw8*2
+        trn1            v2.2d,   v0.2d,   v4.2d
+
+3:
+        abs             v2.8h,   v2.8h            // abs(mv[].xy)
+        tbl             v1.8b, {v31.16b}, v1.8b   // ref_sign[ref]
+        ushr            v2.8h,   v2.8h,   #12     // abs(mv[].xy) >> 12
+        umull           v1.8h,   v1.8b,   v29.8b  // ref_sign[ref] * {1, 2}
+        cmeq            v2.4s,   v2.4s,   #0      // abs(mv[].xy) <= 4096
+        xtn             v2.4h,   v2.4s            // abs() condition to 16 bit
+        and             v1.8b,   v1.8b,   v2.8b   // h[0-3] contains conditions for mv[0-1]
+        addp            v1.4h,   v1.4h,   v1.4h   // Combine condition for [1] and [0]
+        umov            w16, v1.h[0]              // Extract case for first block
+        umov            w17, v1.h[1]
+        ldrsw           x11, [x11, #4]            // Fetch jump table entry
+        ldrsw           x15, [x15, #4]
+        ldr             q1, [x13, w16, uxtw #4]   // Load permutation table base on case
+        ldr             q5, [x13, w17, uxtw #4]
+        add             x11, x8,  x11             // Find jump table target
+        add             x15, x8,  x15
+        tbl             v0.16b, {v0.16b}, v1.16b  // Permute cand_b to output refmvs_temporal_block
+        tbl             v4.16b, {v4.16b}, v5.16b
+
+        // v1 follows on v0, with another 3 full repetitions of the pattern.
+        ext             v1.16b,  v0.16b,  v0.16b,  #1
+        ext             v5.16b,  v4.16b,  v4.16b,  #1
+        // v2 ends with 3 complete repetitions of the pattern.
+        ext             v2.16b,  v0.16b,  v1.16b,  #4
+        ext             v6.16b,  v4.16b,  v5.16b,  #4
+
+        blr             x11
+        b.ge            4f  // if (cand_b >= end)
+        mov             v0.16b,  v4.16b
+        mov             v1.16b,  v5.16b
+        mov             v2.16b,  v6.16b
+        cmp             x9,  x10
+        blr             x15
+        b.lt            2b  // if (cand_b < end)
+
+4:
+        subs            w5,  w5,  #1              // h--
+        add             w7,  w7,  #2              // y += 2
+        add             x0,  x0,  x1              // rp += stride
+        b.gt            1b
+
+        ldp             x29, x30, [sp], #16
+        AARCH64_VALIDATE_LINK_REGISTER
+        ret
+
+10:
+        AARCH64_VALID_CALL_TARGET
+        add             x16, x3,  #4
+        st1             {v0.s}[0], [x3]
+        st1             {v0.b}[4], [x16]
+        add             x3,  x3,  #5
+        ret
+20:
+        AARCH64_VALID_CALL_TARGET
+        add             x16, x3,  #8
+        st1             {v0.d}[0], [x3]
+        st1             {v0.h}[4], [x16]
+        add             x3,  x3,  #2*5
+        ret
+40:
+        AARCH64_VALID_CALL_TARGET
+        st1             {v0.16b}, [x3]
+        str             s1, [x3, #16]
+        add             x3,  x3,  #4*5
+        ret
+80:
+        AARCH64_VALID_CALL_TARGET
+        // This writes 6 full entries plus 2 extra bytes
+        st1             {v0.16b, v1.16b}, [x3]
+        // Write the last few, overlapping with the first write.
+        stur            q2, [x3, #(8*5-16)]
+        add             x3,  x3,  #8*5
+        ret
+160:
+        AARCH64_VALID_CALL_TARGET
+        add             x16, x3,  #6*5
+        add             x17, x3,  #12*5
+        // This writes 6 full entries plus 2 extra bytes
+        st1             {v0.16b, v1.16b}, [x3]
+        // Write another 6 full entries, slightly overlapping with the first set
+        st1             {v0.16b, v1.16b}, [x16]
+        // Write 8 bytes (one full entry) after the first 12
+        st1             {v0.8b}, [x17]
+        // Write the last 3 entries
+        str             q2, [x3, #(16*5-16)]
+        add             x3,  x3,  #16*5
+        ret
+endfunc
+
+jumptable save_tmvs_tbl
+        .word 16 * 12
+        .word 160b - save_tmvs_tbl
+        .word 16 * 12
+        .word 160b - save_tmvs_tbl
+        .word 8 * 12
+        .word 80b  - save_tmvs_tbl
+        .word 8 * 12
+        .word 80b  - save_tmvs_tbl
+        .word 8 * 12
+        .word 80b  - save_tmvs_tbl
+        .word 8 * 12
+        .word 80b  - save_tmvs_tbl
+        .word 4 * 12
+        .word 40b  - save_tmvs_tbl
+        .word 4 * 12
+        .word 40b  - save_tmvs_tbl
+        .word 4 * 12
+        .word 40b  - save_tmvs_tbl
+        .word 4 * 12
+        .word 40b  - save_tmvs_tbl
+        .word 2 * 12
+        .word 20b  - save_tmvs_tbl
+        .word 2 * 12
+        .word 20b  - save_tmvs_tbl
+        .word 2 * 12
+        .word 20b  - save_tmvs_tbl
+        .word 2 * 12
+        .word 20b  - save_tmvs_tbl
+        .word 2 * 12
+        .word 20b  - save_tmvs_tbl
+        .word 1 * 12
+        .word 10b  - save_tmvs_tbl
+        .word 1 * 12
+        .word 10b  - save_tmvs_tbl
+        .word 1 * 12
+        .word 10b  - save_tmvs_tbl
+        .word 1 * 12
+        .word 10b  - save_tmvs_tbl
+        .word 1 * 12
+        .word 10b  - save_tmvs_tbl
+        .word 1 * 12
+        .word 10b  - save_tmvs_tbl
+        .word 1 * 12
+        .word 10b  - save_tmvs_tbl
+endjumptable
+
+// void dav1d_load_tmvs_neon(const refmvs_frame *const rf, int tile_row_idx,
+//                           const int col_start8, const int col_end8,
+//                           const int row_start8, int row_end8)
+function load_tmvs_neon, export=1
+        rf              .req x0
+        tile_row_idx    .req w1
+        col_start8      .req w2
+        col_end8        .req w3
+        row_start8      .req w4
+        row_end8        .req w5
+        col_start8i     .req w6
+        col_end8i       .req w7
+        rp_proj         .req x8
+        stride5         .req x9
+        wstride5        .req w9
+        stp             x28, x27, [sp, #-96]!
+        stp             x26, x25, [sp, #16]
+        stp             x24, x23, [sp, #32]
+        stp             x22, x21, [sp, #48]
+        stp             x20, x19, [sp, #64]
+        stp             x29, x30, [sp, #80]
+
+        ldr             w15, [rf, #RMVSF_N_TILE_THREADS]
+        ldp             w16, w17, [rf, #RMVSF_IW8]          // include rf->ih8 too
+        sub             col_start8i, col_start8, #8         // col_start8 - 8
+        add             col_end8i, col_end8, #8             // col_end8 + 8
+        ldr             wstride5, [rf, #RMVSF_RP_STRIDE]
+        ldr             rp_proj, [rf, #RMVSF_RP_PROJ]
+
+        cmp             w15, #1
+        csel            tile_row_idx, wzr, tile_row_idx, eq // if (rf->n_tile_threads == 1) tile_row_idx = 0
+
+        bic             col_start8i, col_start8i, col_start8i, asr #31  // imax(col_start8 - 8, 0)
+        cmp             col_end8i, w16
+        csel            col_end8i, col_end8i, w16, lt       // imin(col_end8 + 8, rf->iw8)
+
+        lsl             tile_row_idx, tile_row_idx, #4      // 16 * tile_row_idx
+
+        cmp             row_end8, w17
+        csel            row_end8, row_end8, w17, lt         // imin(row_end8, rf->ih8)
+
+        add             wstride5, wstride5, wstride5, lsl #2    // stride * sizeof(refmvs_temporal_block)
+        and             w15, row_start8, #15                // row_start8 & 15
+        add             w10, col_start8, col_start8, lsl #2 // col_start8 * sizeof(refmvs_temporal_block)
+        smaddl          rp_proj, tile_row_idx, wstride5, rp_proj    // &rf->rp_proj[16 * stride * tile_row_idx]
+        smaddl          x10, w15, wstride5, x10             // ((row_start8 & 15) * stride + col_start8) * sizeof(refmvs_temporal_block)
+        mov             w15, #INVALID_MV
+        sub             w11, col_end8, col_start8           // xfill loop count
+        add             x10, x10, rp_proj                   // &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride + col_start8]
+        add             x15, x15, x15, lsl #40              // first 64b of 4 [INVALID_MV, 0]... patterns
+        mov             w17, #(INVALID_MV >> 8)             // last 32b of 4 patterns
+        sub             w12, row_end8, row_start8           // yfill loop count
+        ror             x16, x15, #48                       // second 64b of 4 patterns
+        ldr             w19, [rf, #RMVSF_N_MFMVS]
+
+5:      // yfill loop
+        and             w13, w11, #-4           // xfill 4x count by patterns
+        mov             x14, x10                // fill_ptr = row_ptr
+        add             x10, x10, stride5       // row_ptr += stride
+        sub             w12, w12, #1            // y--
+
+        cbz             w13, 3f
+
+4:      // xfill loop 4x
+        sub             w13, w13, #4            // xfill 4x count -= 4
+        stp             x15, x16, [x14]
+        str             w17, [x14, #16]
+        add             x14, x14, #20           // fill_ptr += 4 * sizeof(refmvs_temporal_block)
+        cbnz            w13, 4b
+
+3:      // up to 3 residuals
+        tbz             w11, #1, 1f
+        str             x15, [x14]
+        strh            w16, [x14, #8]
+        add             x14, x14, #10           // fill_ptr += 2 * sizeof(refmvs_temporal_block)
+
+1:      // up to 1 residual
+        tbz             w11, #0, 2f
+        str             w15, [x14]
+2:
+        cbnz            w12, 5b                 // yfill loop
+
+        cbz             w19, 11f                // if (!rf->n_mfmvs) skip nloop
+
+        add             x29, rf, #RMVSF_MFMV_REF2CUR
+        mov             w10, #0                 // n = 0
+        movi            v3.2s, #255             // 0x3FFF >> 6, for MV clamp
+        movrel          x1, div_mult_tbl
+
+10:     // nloop
+        ldrsb           w16, [x29, x10]         // ref2cur = rf->mfmv_ref2cur[n]
+        cmp             w16, #-32
+        b.eq            9f                      // if (ref2cur == INVALID_REF2CUR) continue
+
+        add             x17, x10, #(RMVSF_MFMV_REF - RMVSF_MFMV_REF2CUR)    // n - (&rf->mfmv_ref - &rf->mfmv_ref2cur)
+        mov             x20, #4
+        ldrb            w17, [x29, x17]         // ref = rf->mfmv_ref[n]
+        ldr             x13, [x29, #(RMVSF_RP_REF - RMVSF_MFMV_REF2CUR)]
+        sub             x21, x10, x10, lsl #3   // -(n * 7)
+        smaddl          x20, row_start8, wstride5, x20  // row_start8 * stride * sizeof(refmvs_temporal_block) + 4
+        mov             w12, row_start8         // y = row_start8
+        add             x28, x29, #(RMVSF_MFMV_REF2REF - RMVSF_MFMV_REF2CUR - 1)    // &rf->mfmv_ref2ref - 1
+        ldr             x13, [x13, x17, lsl #3] // rf->rp_ref[ref]
+        sub             x28, x28, x21           // rf->mfmv_ref2ref[n] - 1
+        sub             w17, w17, #4            // ref_sign = ref - 4
+        add             x13, x13, x20           // r = &rf->rp_ref[ref][row_start8 * stride].ref
+        dup             v0.2s, w17              // ref_sign
+
+5:      // yloop
+        and             w14, w12, #-8           // y_sb_align = y & ~7
+        mov             w11, col_start8i        // x = col_start8i
+        add             w15, w14, #8            // y_sb_align + 8
+        cmp             w14, row_start8
+        csel            w14, w14, row_start8, gt    // imax(y_sb_align, row_start8)
+        cmp             w15, row_end8
+        csel            w15, w15, row_end8, lt  // imin(y_sb_align + 8, row_end8)
+
+4:      // xloop
+        add             x23, x13, x11, lsl #2   // partial &r[x] address
+        ldrb            w22, [x23, x11]         // b_ref = rb->ref
+        cbz             w22, 6f                 // if (!b_ref) continue
+
+        ldrb            w24, [x28, x22]         // ref2ref = rf->mfmv_ref2ref[n][b_ref - 1]
+        cbz             w24, 6f                 // if (!ref2ref) continue
+
+        ldrh            w20, [x1, x24, lsl #1]  // div_mult[ref2ref]
+        add             x23, x23, x11           // &r[x]
+        mul             w20, w20, w16           // frac = ref2cur * div_mult[ref2ref]
+
+        ldur            s1, [x23, #-4]          // mv{y, x} = rb->mv
+        fmov            s2, w20                 // frac
+        sxtl            v1.4s, v1.4h
+        mul             v1.2s, v1.2s, v2.s[0]   // offset{y, x} = frac * mv{y, x}
+
+        ssra            v1.2s, v1.2s, #31       // offset{y, x} + (offset{y, x} >> 31)
+        ldur            w25, [x23, #-4]         // b_mv = rb->mv
+        srshr           v1.2s, v1.2s, #14       // (offset{y, x} + (offset{y, x} >> 31) + 8192) >> 14
+
+        abs             v2.2s, v1.2s            // abs(offset{y, x})
+        eor             v1.8b, v1.8b, v0.8b     // offset{y, x} ^ ref_sign
+
+        sshr            v2.2s, v2.2s, #6        // abs(offset{y, x}) >> 6
+        cmlt            v1.2s, v1.2s, #0        // sign(offset{y, x} ^ ref_sign): -1 or 0
+        umin            v2.2s, v2.2s, v3.2s     // iclip(abs(offset{y, x}) >> 6, 0, 0x3FFF >> 6)
+
+        neg             v4.2s, v2.2s
+        bsl             v1.8b, v4.8b, v2.8b     // apply_sign(iclip(abs(offset{y, x}) >> 6, 0, 0x3FFF >> 6))
+        fmov            x20, d1                 // offset{y, x}
+
+        add             w21, w12, w20           // pos_y = y + offset.y
+        cmp             w21, w14                // pos_y >= y_proj_start
+        b.lt            1f
+        cmp             w21, w15                // pos_y < y_proj_end
+        b.ge            1f
+        add             x26, x11, x20, asr #32  // pos_x = x + offset.x
+        and             w27, w21, #15           // pos_y & 15
+        add             x21, x26, x26, lsl #2   // pos_x * sizeof(refmvs_temporal_block)
+        umaddl          x27, w27, wstride5, rp_proj // &rp_proj[(pos_y & 15) * stride]
+        add             x27, x27, x21           // &rp_proj[(pos_y & 15) * stride + pos_x]
+
+3:      // copy loop
+        and             w20, w11, #-8           // x_sb_align = x & ~7
+        sub             w21, w20, #8            // x_sb_align - 8
+        cmp             w21, col_start8
+        csel            w21, w21, col_start8, gt    // imax(x_sb_align - 8, col_start8)
+        cmp             w26, w21                // pos_x >= imax(x_sb_align - 8, col_start8)
+        b.lt            2f
+        add             w20, w20, #16           // x_sb_align + 16
+        cmp             w20, col_end8
+        csel            w20, w20, col_end8, lt  // imin(x_sb_align + 16, col_end8)
+        cmp             w26, w20                // pos_x < imin(x_sb_align + 16, col_end8)
+        b.ge            2f
+        str             w25, [x27]              // rp_proj[pos + pos_x].mv = rb->mv (b_mv)
+        strb            w24, [x27, #4]          // rp_proj[pos + pos_x].ref = ref2ref
+
+2:      // search part of copy loop
+        add             w11, w11, #1            // x++
+        cmp             w11, col_end8i          // if (++x >= col_end8i) break xloop
+        b.ge            8f
+
+        ldrb            w20, [x23, #5]!         // rb++; rb->ref
+        cmp             w20, w22                // if (rb->ref != b_ref) break
+        b.ne            7f
+
+        ldur            w21, [x23, #-4]         // rb->mv.n
+        cmp             w21, w25                // if (rb->mv.n != b_mv.n) break
+        b.ne            7f
+
+        add             w26, w26, #1            // pos_x++
+        add             x27, x27, #5            // advance &rp_proj[(pos_y & 15) * stride + pos_x]
+        b               3b                      // copy loop
+
+1:      // search loop
+        add             w11, w11, #1            // x++
+        cmp             w11, col_end8i          // if (++x >= col_end8i) break xloop
+        b.ge            8f
+
+        ldrb            w20, [x23, #5]!         // rb++; rb->ref
+        cmp             w20, w22                // if (rb->ref != b_ref) break
+        b.ne            7f
+
+        ldur            w21, [x23, #-4]         // rb->mv.n
+        cmp             w21, w25                // if (rb->mv.n == b_mv.n) continue
+        b.eq            1b                      // search loop
+7:
+        cmp             w11, col_end8i          // x < col_end8i
+        b.lt            4b                      // xloop
+
+6:      // continue case of xloop
+        add             w11, w11, #1            // x++
+        cmp             w11, col_end8i          // x < col_end8i
+        b.lt            4b                      // xloop
+8:
+        add             w12, w12, #1            // y++
+        add             x13, x13, stride5       // r += stride
+        cmp             w12, row_end8           // y < row_end8
+        b.lt            5b                      // yloop
+9:
+        add             w10, w10, #1
+        cmp             w10, w19                // n < rf->n_mfmvs
+        b.lt            10b                     // nloop
+11:
+        ldp             x29, x30, [sp, #80]
+        ldp             x20, x19, [sp, #64]
+        ldp             x22, x21, [sp, #48]
+        ldp             x24, x23, [sp, #32]
+        ldp             x26, x25, [sp, #16]
+        ldp             x28, x27, [sp], #96
+        ret
+        .unreq          rf
+        .unreq          tile_row_idx
+        .unreq          col_start8
+        .unreq          col_end8
+        .unreq          row_start8
+        .unreq          row_end8
+        .unreq          col_start8i
+        .unreq          col_end8i
+        .unreq          rp_proj
+        .unreq          stride5
+        .unreq          wstride5
+endfunc
+
+const div_mult_tbl
+        .hword             0, 16384, 8192, 5461, 4096, 3276, 2730, 2340
+        .hword          2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092
+        .hword          1024,   963,  910,  862,  819,  780,  744,  712
+        .hword           682,   655,  630,  606,  585,  564,  546,  528
+endconst
diff --git a/media/libdav1d/src/src/arm/64/util.S b/media/libdav1d/src/src/arm/64/util.S
new file mode 100644
index 0000000000..1b3f319ce5
--- /dev/null
+++ b/media/libdav1d/src/src/arm/64/util.S
@@ -0,0 +1,278 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2015 Martin Storsjo
+ * Copyright © 2015 Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef DAV1D_SRC_ARM_64_UTIL_S
+#define DAV1D_SRC_ARM_64_UTIL_S
+
+#include "config.h"
+#include "src/arm/asm.S"
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+.macro  movrel rd, val, offset=0
+#if defined(__APPLE__)
+  .if \offset < 0
+        adrp            \rd, \val@PAGE
+        add             \rd, \rd, \val@PAGEOFF
+        sub             \rd, \rd, -(\offset)
+  .else
+        adrp            \rd, \val+(\offset)@PAGE
+        add             \rd, \rd, \val+(\offset)@PAGEOFF
+  .endif
+#elif defined(PIC) && defined(_WIN32)
+  .if \offset < 0
+        adrp            \rd, \val
+        add             \rd, \rd, :lo12:\val
+        sub             \rd, \rd, -(\offset)
+  .else
+        adrp            \rd, \val+(\offset)
+        add             \rd, \rd, :lo12:\val+(\offset)
+  .endif
+#elif __has_feature(hwaddress_sanitizer)
+        adrp            \rd, :pg_hi21_nc:\val+(\offset)
+        movk            \rd, #:prel_g3:\val+0x100000000
+        add             \rd, \rd, :lo12:\val+(\offset)
+#elif defined(PIC)
+        adrp            \rd, \val+(\offset)
+        add             \rd, \rd, :lo12:\val+(\offset)
+#else
+        ldr             \rd, =\val+\offset
+#endif
+.endm
+
+.macro sub_sp space
+#ifdef _WIN32
+.if \space > 8192
+        // Here, we'd need to touch two (or more) pages while decrementing
+        // the stack pointer.
+        .error          "sub_sp_align doesn't support values over 8K at the moment"
+.elseif \space > 4096
+        sub             x16, sp,  #4096
+        ldr             xzr, [x16]
+        sub             sp,  x16, #(\space - 4096)
+.else
+        sub             sp,  sp,  #\space
+.endif
+#else
+.if \space >= 4096
+        sub             sp,  sp,  #(\space)/4096*4096
+.endif
+.if (\space % 4096) != 0
+        sub             sp,  sp,  #(\space)%4096
+.endif
+#endif
+.endm
+
+.macro transpose_8x8b_xtl r0, r1, r2, r3, r4, r5, r6, r7, xtl
+        // a0 b0 a1 b1 a2 b2 a3 b3 a4 b4 a5 b5 a6 b6 a7 b7
+        zip1            \r0\().16b, \r0\().16b, \r1\().16b
+        // c0 d0 c1 d1 c2 d2 d3 d3 c4 d4 c5 d5 c6 d6 d7 d7
+        zip1            \r2\().16b, \r2\().16b, \r3\().16b
+        // e0 f0 e1 f1 e2 f2 e3 f3 e4 f4 e5 f5 e6 f6 e7 f7
+        zip1            \r4\().16b, \r4\().16b, \r5\().16b
+        // g0 h0 g1 h1 g2 h2 h3 h3 g4 h4 g5 h5 g6 h6 h7 h7
+        zip1            \r6\().16b, \r6\().16b, \r7\().16b
+
+        // a0 b0 c0 d0 a2 b2 c2 d2 a4 b4 c4 d4 a6 b6 c6 d6
+        trn1            \r1\().8h,  \r0\().8h,  \r2\().8h
+        // a1 b1 c1 d1 a3 b3 c3 d3 a5 b5 c5 d5 a7 b7 c7 d7
+        trn2            \r3\().8h,  \r0\().8h,  \r2\().8h
+        // e0 f0 g0 h0 e2 f2 g2 h2 e4 f4 g4 h4 e6 f6 g6 h6
+        trn1            \r5\().8h,  \r4\().8h,  \r6\().8h
+        // e1 f1 g1 h1 e3 f3 g3 h3 e5 f5 g5 h5 e7 f7 g7 h7
+        trn2            \r7\().8h,  \r4\().8h,  \r6\().8h
+
+        // a0 b0 c0 d0 e0 f0 g0 h0 a4 b4 c4 d4 e4 f4 g4 h4
+        trn1            \r0\().4s,  \r1\().4s,  \r5\().4s
+        // a2 b2 c2 d2 e2 f2 g2 h2 a6 b6 c6 d6 e6 f6 g6 h6
+        trn2            \r2\().4s,  \r1\().4s,  \r5\().4s
+        // a1 b1 c1 d1 e1 f1 g1 h1 a5 b5 c5 d5 e5 f5 g5 h5
+        trn1            \r1\().4s,  \r3\().4s,  \r7\().4s
+        // a3 b3 c3 d3 e3 f3 g3 h3 a7 b7 c7 d7 e7 f7 g7 h7
+        trn2            \r3\().4s,  \r3\().4s,  \r7\().4s
+
+        \xtl\()2        \r4\().8h,  \r0\().16b
+        \xtl            \r0\().8h,  \r0\().8b
+        \xtl\()2        \r6\().8h,  \r2\().16b
+        \xtl            \r2\().8h,  \r2\().8b
+        \xtl\()2        \r5\().8h,  \r1\().16b
+        \xtl            \r1\().8h,  \r1\().8b
+        \xtl\()2        \r7\().8h,  \r3\().16b
+        \xtl            \r3\().8h,  \r3\().8b
+.endm
+
+.macro transpose_8x8h r0, r1, r2, r3, r4, r5, r6, r7, t8, t9
+        trn1            \t8\().8h,  \r0\().8h,  \r1\().8h
+        trn2            \t9\().8h,  \r0\().8h,  \r1\().8h
+        trn1            \r1\().8h,  \r2\().8h,  \r3\().8h
+        trn2            \r3\().8h,  \r2\().8h,  \r3\().8h
+        trn1            \r0\().8h,  \r4\().8h,  \r5\().8h
+        trn2            \r5\().8h,  \r4\().8h,  \r5\().8h
+        trn1            \r2\().8h,  \r6\().8h,  \r7\().8h
+        trn2            \r7\().8h,  \r6\().8h,  \r7\().8h
+
+        trn1            \r4\().4s,  \r0\().4s,  \r2\().4s
+        trn2            \r2\().4s,  \r0\().4s,  \r2\().4s
+        trn1            \r6\().4s,  \r5\().4s,  \r7\().4s
+        trn2            \r7\().4s,  \r5\().4s,  \r7\().4s
+        trn1            \r5\().4s,  \t9\().4s,  \r3\().4s
+        trn2            \t9\().4s,  \t9\().4s,  \r3\().4s
+        trn1            \r3\().4s,  \t8\().4s,  \r1\().4s
+        trn2            \t8\().4s,  \t8\().4s,  \r1\().4s
+
+        trn1            \r0\().2d,  \r3\().2d,  \r4\().2d
+        trn2            \r4\().2d,  \r3\().2d,  \r4\().2d
+        trn1            \r1\().2d,  \r5\().2d,  \r6\().2d
+        trn2            \r5\().2d,  \r5\().2d,  \r6\().2d
+        trn2            \r6\().2d,  \t8\().2d,  \r2\().2d
+        trn1            \r2\().2d,  \t8\().2d,  \r2\().2d
+        trn1            \r3\().2d,  \t9\().2d,  \r7\().2d
+        trn2            \r7\().2d,  \t9\().2d,  \r7\().2d
+.endm
+
+.macro transpose_8x8h_mov r0, r1, r2, r3, r4, r5, r6, r7, t8, t9, o0, o1, o2, o3, o4, o5, o6, o7
+        trn1            \t8\().8h,  \r0\().8h,  \r1\().8h
+        trn2            \t9\().8h,  \r0\().8h,  \r1\().8h
+        trn1            \r1\().8h,  \r2\().8h,  \r3\().8h
+        trn2            \r3\().8h,  \r2\().8h,  \r3\().8h
+        trn1            \r0\().8h,  \r4\().8h,  \r5\().8h
+        trn2            \r5\().8h,  \r4\().8h,  \r5\().8h
+        trn1            \r2\().8h,  \r6\().8h,  \r7\().8h
+        trn2            \r7\().8h,  \r6\().8h,  \r7\().8h
+
+        trn1            \r4\().4s,  \r0\().4s,  \r2\().4s
+        trn2            \r2\().4s,  \r0\().4s,  \r2\().4s
+        trn1            \r6\().4s,  \r5\().4s,  \r7\().4s
+        trn2            \r7\().4s,  \r5\().4s,  \r7\().4s
+        trn1            \r5\().4s,  \t9\().4s,  \r3\().4s
+        trn2            \t9\().4s,  \t9\().4s,  \r3\().4s
+        trn1            \r3\().4s,  \t8\().4s,  \r1\().4s
+        trn2            \t8\().4s,  \t8\().4s,  \r1\().4s
+
+        trn1            \o0\().2d,  \r3\().2d,  \r4\().2d
+        trn2            \o4\().2d,  \r3\().2d,  \r4\().2d
+        trn1            \o1\().2d,  \r5\().2d,  \r6\().2d
+        trn2            \o5\().2d,  \r5\().2d,  \r6\().2d
+        trn2            \o6\().2d,  \t8\().2d,  \r2\().2d
+        trn1            \o2\().2d,  \t8\().2d,  \r2\().2d
+        trn1            \o3\().2d,  \t9\().2d,  \r7\().2d
+        trn2            \o7\().2d,  \t9\().2d,  \r7\().2d
+.endm
+
+.macro transpose_8x16b r0, r1, r2, r3, r4, r5, r6, r7, t8, t9
+        trn1            \t8\().16b, \r0\().16b, \r1\().16b
+        trn2            \t9\().16b, \r0\().16b, \r1\().16b
+        trn1            \r1\().16b, \r2\().16b, \r3\().16b
+        trn2            \r3\().16b, \r2\().16b, \r3\().16b
+        trn1            \r0\().16b, \r4\().16b, \r5\().16b
+        trn2            \r5\().16b, \r4\().16b, \r5\().16b
+        trn1            \r2\().16b, \r6\().16b, \r7\().16b
+        trn2            \r7\().16b, \r6\().16b, \r7\().16b
+
+        trn1            \r4\().8h,  \r0\().8h,  \r2\().8h
+        trn2            \r2\().8h,  \r0\().8h,  \r2\().8h
+        trn1            \r6\().8h,  \r5\().8h,  \r7\().8h
+        trn2            \r7\().8h,  \r5\().8h,  \r7\().8h
+        trn1            \r5\().8h,  \t9\().8h,  \r3\().8h
+        trn2            \t9\().8h,  \t9\().8h,  \r3\().8h
+        trn1            \r3\().8h,  \t8\().8h,  \r1\().8h
+        trn2            \t8\().8h,  \t8\().8h,  \r1\().8h
+
+        trn1            \r0\().4s,  \r3\().4s,  \r4\().4s
+        trn2            \r4\().4s,  \r3\().4s,  \r4\().4s
+        trn1            \r1\().4s,  \r5\().4s,  \r6\().4s
+        trn2            \r5\().4s,  \r5\().4s,  \r6\().4s
+        trn2            \r6\().4s,  \t8\().4s,  \r2\().4s
+        trn1            \r2\().4s,  \t8\().4s,  \r2\().4s
+        trn1            \r3\().4s,  \t9\().4s,  \r7\().4s
+        trn2            \r7\().4s,  \t9\().4s,  \r7\().4s
+.endm
+
+.macro  transpose_4x16b r0, r1, r2, r3, t4, t5, t6, t7
+        trn1            \t4\().16b, \r0\().16b, \r1\().16b
+        trn2            \t5\().16b, \r0\().16b, \r1\().16b
+        trn1            \t6\().16b, \r2\().16b, \r3\().16b
+        trn2            \t7\().16b, \r2\().16b, \r3\().16b
+
+        trn1            \r0\().8h,  \t4\().8h,  \t6\().8h
+        trn2            \r2\().8h,  \t4\().8h,  \t6\().8h
+        trn1            \r1\().8h,  \t5\().8h,  \t7\().8h
+        trn2            \r3\().8h,  \t5\().8h,  \t7\().8h
+.endm
+
+.macro  transpose_4x4h  r0, r1, r2, r3, t4, t5, t6, t7
+        trn1            \t4\().4h,  \r0\().4h,  \r1\().4h
+        trn2            \t5\().4h,  \r0\().4h,  \r1\().4h
+        trn1            \t6\().4h,  \r2\().4h,  \r3\().4h
+        trn2            \t7\().4h,  \r2\().4h,  \r3\().4h
+
+        trn1            \r0\().2s,  \t4\().2s,  \t6\().2s
+        trn2            \r2\().2s,  \t4\().2s,  \t6\().2s
+        trn1            \r1\().2s,  \t5\().2s,  \t7\().2s
+        trn2            \r3\().2s,  \t5\().2s,  \t7\().2s
+.endm
+
+.macro  transpose_4x4s  r0, r1, r2, r3, t4, t5, t6, t7
+        trn1            \t4\().4s,  \r0\().4s,  \r1\().4s
+        trn2            \t5\().4s,  \r0\().4s,  \r1\().4s
+        trn1            \t6\().4s,  \r2\().4s,  \r3\().4s
+        trn2            \t7\().4s,  \r2\().4s,  \r3\().4s
+
+        trn1            \r0\().2d,  \t4\().2d,  \t6\().2d
+        trn2            \r2\().2d,  \t4\().2d,  \t6\().2d
+        trn1            \r1\().2d,  \t5\().2d,  \t7\().2d
+        trn2            \r3\().2d,  \t5\().2d,  \t7\().2d
+.endm
+
+.macro  transpose_4x8h  r0, r1, r2, r3, t4, t5, t6, t7
+        trn1            \t4\().8h,  \r0\().8h,  \r1\().8h
+        trn2            \t5\().8h,  \r0\().8h,  \r1\().8h
+        trn1            \t6\().8h,  \r2\().8h,  \r3\().8h
+        trn2            \t7\().8h,  \r2\().8h,  \r3\().8h
+
+        trn1            \r0\().4s,  \t4\().4s,  \t6\().4s
+        trn2            \r2\().4s,  \t4\().4s,  \t6\().4s
+        trn1            \r1\().4s,  \t5\().4s,  \t7\().4s
+        trn2            \r3\().4s,  \t5\().4s,  \t7\().4s
+.endm
+
+.macro  transpose_4x8h_mov r0, r1, r2, r3, t4, t5, t6, t7, o0, o1, o2, o3
+        trn1            \t4\().8h,  \r0\().8h,  \r1\().8h
+        trn2            \t5\().8h,  \r0\().8h,  \r1\().8h
+        trn1            \t6\().8h,  \r2\().8h,  \r3\().8h
+        trn2            \t7\().8h,  \r2\().8h,  \r3\().8h
+
+        trn1            \o0\().4s,  \t4\().4s,  \t6\().4s
+        trn2            \o2\().4s,  \t4\().4s,  \t6\().4s
+        trn1            \o1\().4s,  \t5\().4s,  \t7\().4s
+        trn2            \o3\().4s,  \t5\().4s,  \t7\().4s
+.endm
+
+#endif /* DAV1D_SRC_ARM_64_UTIL_S */
diff --git a/media/libdav1d/src/src/arm/arm-arch.h b/media/libdav1d/src/src/arm/arm-arch.h
new file mode 100644
index 0000000000..f00b9b2fce
--- /dev/null
+++ b/media/libdav1d/src/src/arm/arm-arch.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ARM_ARM_ARCH_H
+#define ARM_ARM_ARCH_H
+
+/* Compatibility header to define __ARM_ARCH with older compilers */
+#ifndef __ARM_ARCH
+
+#ifdef _M_ARM
+#define __ARM_ARCH _M_ARM
+
+#elif defined(__ARM_ARCH_8A__) || defined(_M_ARM64)
+#define __ARM_ARCH 8
+
+#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
+      defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || \
+      defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
+#define __ARM_ARCH 7
+
+#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+      defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || \
+      defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
+#define __ARM_ARCH 6
+
+#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
+      defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__)
+#define __ARM_ARCH 5
+
+#elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
+#define __ARM_ARCH 4
+
+#elif defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__)
+#define __ARM_ARCH 3
+
+#elif defined(__ARM_ARCH_2__)
+#define __ARM_ARCH 2
+
+#else
+#error Unknown ARM architecture version
+#endif
+
+#endif /* !__ARM_ARCH */
+
+#endif /* ARM_ARM_ARCH_H */
diff --git a/media/libdav1d/src/src/arm/asm-offsets.h b/media/libdav1d/src/src/arm/asm-offsets.h
new file mode 100644
index 0000000000..595ac6900d
--- /dev/null
+++ b/media/libdav1d/src/src/arm/asm-offsets.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ARM_ASM_OFFSETS_H
+#define ARM_ASM_OFFSETS_H
+
+#include "config.h"
+
+#define FGD_SEED                         0
+#define FGD_AR_COEFF_LAG                 92
+#define FGD_AR_COEFFS_Y                  96
+#define FGD_AR_COEFFS_UV                 120
+#define FGD_AR_COEFF_SHIFT               176
+#define FGD_GRAIN_SCALE_SHIFT            184
+
+#define FGD_SCALING_SHIFT                88
+#define FGD_UV_MULT                      188
+#define FGD_UV_LUMA_MULT                 196
+#define FGD_UV_OFFSET                    204
+#define FGD_CLIP_TO_RESTRICTED_RANGE     216
+
+#if ARCH_AARCH64
+#define RMVSF_IW8                        16
+#define RMVSF_IH8                        20
+#define RMVSF_MFMV_REF                   53
+#define RMVSF_MFMV_REF2CUR               56
+#define RMVSF_MFMV_REF2REF               59
+#define RMVSF_N_MFMVS                    80
+#define RMVSF_RP_REF                     96
+#define RMVSF_RP_PROJ                    104
+#define RMVSF_RP_STRIDE                  112
+#define RMVSF_N_TILE_THREADS             128
+#endif
+
+#endif /* ARM_ASM_OFFSETS_H */
diff --git a/media/libdav1d/src/src/arm/asm.S b/media/libdav1d/src/src/arm/asm.S
new file mode 100644
index 0000000000..e3731fe732
--- /dev/null
+++ b/media/libdav1d/src/src/arm/asm.S
@@ -0,0 +1,361 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_ARM_ASM_S
+#define DAV1D_SRC_ARM_ASM_S
+
+#include "config.h"
+
+#if ARCH_AARCH64
+#define x18 do_not_use_x18
+#define w18 do_not_use_w18
+
+#if HAVE_AS_ARCH_DIRECTIVE
+        .arch AS_ARCH_LEVEL
+#endif
+
+#if HAVE_AS_ARCHEXT_DOTPROD_DIRECTIVE
+#define ENABLE_DOTPROD  .arch_extension dotprod
+#define DISABLE_DOTPROD .arch_extension nodotprod
+#else
+#define ENABLE_DOTPROD
+#define DISABLE_DOTPROD
+#endif
+#if HAVE_AS_ARCHEXT_I8MM_DIRECTIVE
+#define ENABLE_I8MM  .arch_extension i8mm
+#define DISABLE_I8MM .arch_extension noi8mm
+#else
+#define ENABLE_I8MM
+#define DISABLE_I8MM
+#endif
+#if HAVE_AS_ARCHEXT_SVE_DIRECTIVE
+#define ENABLE_SVE  .arch_extension sve
+#define DISABLE_SVE .arch_extension nosve
+#else
+#define ENABLE_SVE
+#define DISABLE_SVE
+#endif
+#if HAVE_AS_ARCHEXT_SVE2_DIRECTIVE
+#define ENABLE_SVE2  .arch_extension sve2
+#define DISABLE_SVE2 .arch_extension nosve2
+#else
+#define ENABLE_SVE2
+#define DISABLE_SVE2
+#endif
+
+/* If we do support the .arch_extension directives, disable support for all
+ * the extensions that we may use, in case they were implicitly enabled by
+ * the .arch level. This makes it clear if we try to assemble an instruction
+ * from an unintended extension set; we only allow assmbling such instructions
+ * within regions where we explicitly enable those extensions. */
+DISABLE_DOTPROD
+DISABLE_I8MM
+DISABLE_SVE
+DISABLE_SVE2
+
+
+/* Support macros for
+ *   - Armv8.3-A Pointer Authentication and
+ *   - Armv8.5-A Branch Target Identification
+ * features which require emitting a .note.gnu.property section with the
+ * appropriate architecture-dependent feature bits set.
+ *
+ * |AARCH64_SIGN_LINK_REGISTER| and |AARCH64_VALIDATE_LINK_REGISTER| expand to
+ * PACIxSP and AUTIxSP, respectively. |AARCH64_SIGN_LINK_REGISTER| should be
+ * used immediately before saving the LR register (x30) to the stack.
+ * |AARCH64_VALIDATE_LINK_REGISTER| should be used immediately after restoring
+ * it. Note |AARCH64_SIGN_LINK_REGISTER|'s modifications to LR must be undone
+ * with |AARCH64_VALIDATE_LINK_REGISTER| before RET. The SP register must also
+ * have the same value at the two points. For example:
+ *
+ *   .global f
+ *   f:
+ *     AARCH64_SIGN_LINK_REGISTER
+ *     stp x29, x30, [sp, #-96]!
+ *     mov x29, sp
+ *     ...
+ *     ldp x29, x30, [sp], #96
+ *     AARCH64_VALIDATE_LINK_REGISTER
+ *     ret
+ *
+ * |AARCH64_VALID_CALL_TARGET| expands to BTI 'c'. Either it, or
+ * |AARCH64_SIGN_LINK_REGISTER|, must be used at every point that may be an
+ * indirect call target. In particular, all symbols exported from a file must
+ * begin with one of these macros. For example, a leaf function that does not
+ * save LR can instead use |AARCH64_VALID_CALL_TARGET|:
+ *
+ *   .globl return_zero
+ *   return_zero:
+ *     AARCH64_VALID_CALL_TARGET
+ *     mov x0, #0
+ *     ret
+ *
+ * A non-leaf function which does not immediately save LR may need both macros
+ * because |AARCH64_SIGN_LINK_REGISTER| appears late. For example, the function
+ * may jump to an alternate implementation before setting up the stack:
+ *
+ *   .globl with_early_jump
+ *   with_early_jump:
+ *     AARCH64_VALID_CALL_TARGET
+ *     cmp x0, #128
+ *     b.lt .Lwith_early_jump_128
+ *     AARCH64_SIGN_LINK_REGISTER
+ *     stp x29, x30, [sp, #-96]!
+ *     mov x29, sp
+ *     ...
+ *     ldp x29, x30, [sp], #96
+ *     AARCH64_VALIDATE_LINK_REGISTER
+ *     ret
+ *
+ *  .Lwith_early_jump_128:
+ *     ...
+ *     ret
+ *
+ * These annotations are only required with indirect calls. Private symbols that
+ * are only the target of direct calls do not require annotations. Also note
+ * that |AARCH64_VALID_CALL_TARGET| is only valid for indirect calls (BLR), not
+ * indirect jumps (BR). Indirect jumps in assembly are supported through
+ * |AARCH64_VALID_JUMP_TARGET|. Landing Pads which shall serve for jumps and
+ * calls can be created using |AARCH64_VALID_JUMP_CALL_TARGET|.
+ *
+ * Although not necessary, it is safe to use these macros in 32-bit ARM
+ * assembly. This may be used to simplify dual 32-bit and 64-bit files.
+ *
+ * References:
+ * - "ELF for the Arm® 64-bit Architecture"
+ *   https: *github.com/ARM-software/abi-aa/blob/master/aaelf64/aaelf64.rst
+ * - "Providing protection for complex software"
+ *   https://developer.arm.com/architectures/learn-the-architecture/providing-protection-for-complex-software
+ */
+#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT == 1)
+#define GNU_PROPERTY_AARCH64_BTI (1 << 0)   // Has Branch Target Identification
+#define AARCH64_VALID_JUMP_CALL_TARGET hint #38  // BTI 'jc'
+#define AARCH64_VALID_CALL_TARGET      hint #34  // BTI 'c'
+#define AARCH64_VALID_JUMP_TARGET      hint #36  // BTI 'j'
+#else
+#define GNU_PROPERTY_AARCH64_BTI 0          // No Branch Target Identification
+#define AARCH64_VALID_JUMP_CALL_TARGET
+#define AARCH64_VALID_CALL_TARGET
+#define AARCH64_VALID_JUMP_TARGET
+#endif
+
+#if defined(__ARM_FEATURE_PAC_DEFAULT)
+
+#if ((__ARM_FEATURE_PAC_DEFAULT & (1 << 0)) != 0) // authentication using key A
+#define AARCH64_SIGN_LINK_REGISTER      paciasp
+#define AARCH64_VALIDATE_LINK_REGISTER  autiasp
+#elif ((__ARM_FEATURE_PAC_DEFAULT & (1 << 1)) != 0) // authentication using key B
+#define AARCH64_SIGN_LINK_REGISTER      pacibsp
+#define AARCH64_VALIDATE_LINK_REGISTER  autibsp
+#else
+#error Pointer authentication defines no valid key!
+#endif
+#if ((__ARM_FEATURE_PAC_DEFAULT & (1 << 2)) != 0) // authentication of leaf functions
+#error Authentication of leaf functions is enabled but not supported in dav1d!
+#endif
+#define GNU_PROPERTY_AARCH64_PAC (1 << 1)
+
+#elif defined(__APPLE__) && defined(__arm64e__)
+
+#define GNU_PROPERTY_AARCH64_PAC 0
+#define AARCH64_SIGN_LINK_REGISTER      pacibsp
+#define AARCH64_VALIDATE_LINK_REGISTER  autibsp
+
+#else /* __ARM_FEATURE_PAC_DEFAULT */
+
+#define GNU_PROPERTY_AARCH64_PAC 0
+#define AARCH64_SIGN_LINK_REGISTER
+#define AARCH64_VALIDATE_LINK_REGISTER
+
+#endif /* !__ARM_FEATURE_PAC_DEFAULT */
+
+
+#if (GNU_PROPERTY_AARCH64_BTI != 0 || GNU_PROPERTY_AARCH64_PAC != 0) && defined(__ELF__)
+        .pushsection .note.gnu.property, "a"
+        .balign 8
+        .long 4
+        .long 0x10
+        .long 0x5
+        .asciz "GNU"
+        .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+        .long 4
+        .long (GNU_PROPERTY_AARCH64_BTI | GNU_PROPERTY_AARCH64_PAC)
+        .long 0
+        .popsection
+#endif /* (GNU_PROPERTY_AARCH64_BTI != 0 || GNU_PROPERTY_AARCH64_PAC != 0) && defined(__ELF__) */
+#endif /* ARCH_AARCH64 */
+
+#if ARCH_ARM
+        .syntax unified
+#ifdef __ELF__
+        .arch armv7-a
+        .fpu neon
+        .eabi_attribute 10, 0           // suppress Tag_FP_arch
+        .eabi_attribute 12, 0           // suppress Tag_Advanced_SIMD_arch
+        .section .note.GNU-stack,"",%progbits // Mark stack as non-executable
+#endif /* __ELF__ */
+
+#ifdef _WIN32
+#define CONFIG_THUMB 1
+#else
+#define CONFIG_THUMB 0
+#endif
+
+#if CONFIG_THUMB
+        .thumb
+#define A @
+#define T
+#else
+#define A
+#define T @
+#endif /* CONFIG_THUMB */
+#endif /* ARCH_ARM */
+
+#if !defined(PIC)
+#if defined(__PIC__)
+#define PIC __PIC__
+#elif defined(__pic__)
+#define PIC __pic__
+#endif
+#endif
+
+#ifndef PRIVATE_PREFIX
+#define PRIVATE_PREFIX dav1d_
+#endif
+
+#define PASTE(a,b) a ## b
+#define CONCAT(a,b) PASTE(a,b)
+
+#ifdef PREFIX
+#define EXTERN CONCAT(_,PRIVATE_PREFIX)
+#else
+#define EXTERN PRIVATE_PREFIX
+#endif
+
+.macro function name, export=0, align=2
+    .macro endfunc
+#ifdef __ELF__
+        .size   \name, . - \name
+#endif
+#if HAVE_AS_FUNC
+        .endfunc
+#endif
+        .purgem endfunc
+    .endm
+        .text
+        .align \align
+    .if \export
+        .global EXTERN\name
+#ifdef __ELF__
+        .type   EXTERN\name, %function
+        .hidden EXTERN\name
+#elif defined(__MACH__)
+        .private_extern EXTERN\name
+#endif
+#if HAVE_AS_FUNC
+        .func   EXTERN\name
+#endif
+EXTERN\name:
+    .else
+#ifdef __ELF__
+        .type \name, %function
+#endif
+#if HAVE_AS_FUNC
+        .func \name
+#endif
+    .endif
+\name:
+#if ARCH_AARCH64
+    .if \export
+         AARCH64_VALID_CALL_TARGET
+    .endif
+#endif
+.endm
+
+.macro  const   name, export=0, align=2
+    .macro endconst
+#ifdef __ELF__
+        .size   \name, . - \name
+#endif
+        .purgem endconst
+    .endm
+#if defined(_WIN32)
+        .section        .rdata
+#elif !defined(__MACH__)
+        .section        .rodata
+#else
+        .const_data
+#endif
+        .align          \align
+    .if \export
+        .global EXTERN\name
+#ifdef __ELF__
+        .hidden EXTERN\name
+#elif defined(__MACH__)
+        .private_extern EXTERN\name
+#endif
+EXTERN\name:
+    .endif
+\name:
+.endm
+
+.macro jumptable name
+#ifdef _WIN32
+// MS armasm64 doesn't seem to be able to create relocations for subtraction
+// of labels in different sections; for armasm64 (and all of Windows for
+// simplicity), write the jump table in the text section, to allow calculating
+// differences at assembly time. See
+// https://developercommunity.visualstudio.com/t/armasm64-unable-to-create-cross-section/10722340
+// for reference. (LLVM can create such relocations, but checking for _WIN32
+// for simplicity, as execute-only memory isn't relevant on Windows at the
+// moment.)
+        function \name
+#else
+// For other platforms, write jump tables in a const data section, to allow
+// working in environments where executable memory isn't readable.
+        const \name
+#endif
+.endm
+
+.macro endjumptable
+#ifdef _WIN32
+        endfunc
+#else
+        endconst
+#endif
+.endm
+
+#ifdef __APPLE__
+#define L(x) L ## x
+#else
+#define L(x) .L ## x
+#endif
+
+#define X(x) CONCAT(EXTERN, x)
+
+
+#endif /* DAV1D_SRC_ARM_ASM_S */
diff --git a/media/libdav1d/src/src/arm/cdef.h b/media/libdav1d/src/src/arm/cdef.h
new file mode 100644
index 0000000000..2e8c8ab6fb
--- /dev/null
+++ b/media/libdav1d/src/src/arm/cdef.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/cdef.h"
+
+decl_cdef_dir_fn(BF(dav1d_cdef_find_dir, neon));
+
+void BF(dav1d_cdef_padding4, neon)(uint16_t *tmp, const pixel *src,
+                                   ptrdiff_t src_stride, const pixel (*left)[2],
+                                   const pixel *const top,
+                                   const pixel *const bottom, int h,
+                                   enum CdefEdgeFlags edges);
+void BF(dav1d_cdef_padding8, neon)(uint16_t *tmp, const pixel *src,
+                                   ptrdiff_t src_stride, const pixel (*left)[2],
+                                   const pixel *const top,
+                                   const pixel *const bottom, int h,
+                                   enum CdefEdgeFlags edges);
+
+// Passing edges to this function, to allow it to switch to a more
+// optimized version for fully edged cases. Using size_t for edges,
+// to avoid ABI differences for passing more than one argument on the stack.
+void BF(dav1d_cdef_filter4, neon)(pixel *dst, ptrdiff_t dst_stride,
+                                  const uint16_t *tmp, int pri_strength,
+                                  int sec_strength, int dir, int damping, int h,
+                                  size_t edges HIGHBD_DECL_SUFFIX);
+void BF(dav1d_cdef_filter8, neon)(pixel *dst, ptrdiff_t dst_stride,
+                                  const uint16_t *tmp, int pri_strength,
+                                  int sec_strength, int dir, int damping, int h,
+                                  size_t edges HIGHBD_DECL_SUFFIX);
+
+#define DEFINE_FILTER(w, h, tmp_stride)                                      \
+static void                                                                  \
+cdef_filter_##w##x##h##_neon(pixel *dst, const ptrdiff_t stride,             \
+                             const pixel (*left)[2],                         \
+                             const pixel *const top,                         \
+                             const pixel *const bottom,                      \
+                             const int pri_strength, const int sec_strength, \
+                             const int dir, const int damping,               \
+                             const enum CdefEdgeFlags edges                  \
+                             HIGHBD_DECL_SUFFIX)                             \
+{                                                                            \
+    ALIGN_STK_16(uint16_t, tmp_buf, 12 * tmp_stride + 8,);                   \
+    uint16_t *tmp = tmp_buf + 2 * tmp_stride + 8;                            \
+    BF(dav1d_cdef_padding##w, neon)(tmp, dst, stride,                        \
+                                    left, top, bottom, h, edges);            \
+    BF(dav1d_cdef_filter##w, neon)(dst, stride, tmp, pri_strength,           \
+                                   sec_strength, dir, damping, h, edges      \
+                                   HIGHBD_TAIL_SUFFIX);                      \
+}
+
+DEFINE_FILTER(8, 8, 16)
+DEFINE_FILTER(4, 8, 8)
+DEFINE_FILTER(4, 4, 8)
+
+static ALWAYS_INLINE void cdef_dsp_init_arm(Dav1dCdefDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
+
+    c->dir = BF(dav1d_cdef_find_dir, neon);
+    c->fb[0] = cdef_filter_8x8_neon;
+    c->fb[1] = cdef_filter_4x8_neon;
+    c->fb[2] = cdef_filter_4x4_neon;
+}
diff --git a/media/libdav1d/src/src/arm/cpu.c b/media/libdav1d/src/src/arm/cpu.c
new file mode 100644
index 0000000000..6c3986728e
--- /dev/null
+++ b/media/libdav1d/src/src/arm/cpu.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "common/attributes.h"
+
+#include "src/cpu.h"
+#include "src/arm/cpu.h"
+
+#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO
+#include 
+
+#if ARCH_AARCH64
+
+#define HWCAP_AARCH64_ASIMDDP (1 << 20)
+#define HWCAP_AARCH64_SVE     (1 << 22)
+#define HWCAP2_AARCH64_SVE2   (1 << 1)
+#define HWCAP2_AARCH64_I8MM   (1 << 13)
+
+COLD unsigned dav1d_get_cpu_flags_arm(void) {
+    unsigned long hw_cap = dav1d_getauxval(AT_HWCAP);
+    unsigned long hw_cap2 = dav1d_getauxval(AT_HWCAP2);
+
+    unsigned flags = dav1d_get_default_cpu_flags();
+    flags |= (hw_cap & HWCAP_AARCH64_ASIMDDP) ? DAV1D_ARM_CPU_FLAG_DOTPROD : 0;
+    flags |= (hw_cap2 & HWCAP2_AARCH64_I8MM) ? DAV1D_ARM_CPU_FLAG_I8MM : 0;
+    flags |= (hw_cap & HWCAP_AARCH64_SVE) ? DAV1D_ARM_CPU_FLAG_SVE : 0;
+    flags |= (hw_cap2 & HWCAP2_AARCH64_SVE2) ? DAV1D_ARM_CPU_FLAG_SVE2 : 0;
+    return flags;
+}
+#else  /* !ARCH_AARCH64 */
+
+#ifndef HWCAP_ARM_NEON
+#define HWCAP_ARM_NEON    (1 << 12)
+#endif
+#define HWCAP_ARM_ASIMDDP (1 << 24)
+#define HWCAP_ARM_I8MM    (1 << 27)
+
+COLD unsigned dav1d_get_cpu_flags_arm(void) {
+    unsigned long hw_cap = dav1d_getauxval(AT_HWCAP);
+
+    unsigned flags = dav1d_get_default_cpu_flags();
+    flags |= (hw_cap & HWCAP_ARM_NEON) ? DAV1D_ARM_CPU_FLAG_NEON : 0;
+    flags |= (hw_cap & HWCAP_ARM_ASIMDDP) ? DAV1D_ARM_CPU_FLAG_DOTPROD : 0;
+    flags |= (hw_cap & HWCAP_ARM_I8MM) ? DAV1D_ARM_CPU_FLAG_I8MM : 0;
+    return flags;
+}
+#endif /* ARCH_AARCH64 */
+
+#elif defined(__APPLE__)
+#include 
+
+static int have_feature(const char *feature) {
+    int supported = 0;
+    size_t size = sizeof(supported);
+    if (sysctlbyname(feature, &supported, &size, NULL, 0) != 0) {
+        return 0;
+    }
+    return supported;
+}
+
+COLD unsigned dav1d_get_cpu_flags_arm(void) {
+    unsigned flags = dav1d_get_default_cpu_flags();
+    if (have_feature("hw.optional.arm.FEAT_DotProd"))
+        flags |= DAV1D_ARM_CPU_FLAG_DOTPROD;
+    if (have_feature("hw.optional.arm.FEAT_I8MM"))
+        flags |= DAV1D_ARM_CPU_FLAG_I8MM;
+    /* No SVE and SVE2 feature detection available on Apple platforms. */
+    return flags;
+}
+
+#elif defined(__OpenBSD__) && ARCH_AARCH64
+#include 
+#include 
+#include 
+#include 
+
+COLD unsigned dav1d_get_cpu_flags_arm(void) {
+     unsigned flags = dav1d_get_default_cpu_flags();
+
+#ifdef CPU_ID_AA64ISAR0
+     int mib[2];
+     uint64_t isar0;
+     uint64_t isar1;
+     size_t len;
+
+     mib[0] = CTL_MACHDEP;
+     mib[1] = CPU_ID_AA64ISAR0;
+     len = sizeof(isar0);
+     if (sysctl(mib, 2, &isar0, &len, NULL, 0) != -1) {
+         if (ID_AA64ISAR0_DP(isar0) >= ID_AA64ISAR0_DP_IMPL)
+             flags |= DAV1D_ARM_CPU_FLAG_DOTPROD;
+     }
+
+     mib[0] = CTL_MACHDEP;
+     mib[1] = CPU_ID_AA64ISAR1;
+     len = sizeof(isar1);
+     if (sysctl(mib, 2, &isar1, &len, NULL, 0) != -1) {
+#ifdef ID_AA64ISAR1_I8MM_IMPL
+         if (ID_AA64ISAR1_I8MM(isar1) >= ID_AA64ISAR1_I8MM_IMPL)
+             flags |= DAV1D_ARM_CPU_FLAG_I8MM;
+#endif
+     }
+#endif
+
+     return flags;
+}
+
+#elif defined(_WIN32)
+#include 
+
+COLD unsigned dav1d_get_cpu_flags_arm(void) {
+    unsigned flags = dav1d_get_default_cpu_flags();
+#ifdef PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE))
+        flags |= DAV1D_ARM_CPU_FLAG_DOTPROD;
+#endif
+#ifdef PF_ARM_SVE_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE))
+        flags |= DAV1D_ARM_CPU_FLAG_SVE;
+#endif
+#ifdef PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE))
+        flags |= DAV1D_ARM_CPU_FLAG_SVE2;
+#endif
+#ifdef PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE
+    /* There's no PF_* flag that indicates whether plain I8MM is available
+     * or not. But if SVE_I8MM is available, that also implies that
+     * regular I8MM is available. */
+    if (IsProcessorFeaturePresent(PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE))
+        flags |= DAV1D_ARM_CPU_FLAG_I8MM;
+#endif
+    return flags;
+}
+
+#elif defined(__ANDROID__) || defined(__linux__)
+#include 
+#include 
+#include 
+
+static unsigned parse_proc_cpuinfo(const char *flag) {
+    FILE *file = fopen("/proc/cpuinfo", "r");
+    if (!file)
+        return 0;
+
+    char line_buffer[120];
+    const char *line;
+
+    size_t flaglen = strlen(flag);
+    while ((line = fgets(line_buffer, sizeof(line_buffer), file))) {
+        // check all occurances as whole words
+        const char *found = line;
+        while ((found = strstr(found, flag))) {
+            if ((found == line_buffer || !isgraph(found[-1])) &&
+                (isspace(found[flaglen]) || feof(file))) {
+                fclose(file);
+                return 1;
+            }
+            found += flaglen;
+        }
+        // if line is incomplete seek back to avoid splitting the search
+        // string into two buffers
+        if (!strchr(line, '\n') && strlen(line) > flaglen) {
+            // use fseek since the 64 bit fseeko is only available since
+            // Android API level 24 and meson defines _FILE_OFFSET_BITS
+            // by default 64
+            if (fseek(file, -flaglen, SEEK_CUR))
+                break;
+        }
+    }
+
+    fclose(file);
+
+    return 0;
+}
+
+COLD unsigned dav1d_get_cpu_flags_arm(void) {
+    unsigned flags = dav1d_get_default_cpu_flags();
+    flags |= parse_proc_cpuinfo("neon") ? DAV1D_ARM_CPU_FLAG_NEON : 0;
+    flags |= parse_proc_cpuinfo("asimd") ? DAV1D_ARM_CPU_FLAG_NEON : 0;
+    flags |= parse_proc_cpuinfo("asimddp") ? DAV1D_ARM_CPU_FLAG_DOTPROD : 0;
+    flags |= parse_proc_cpuinfo("i8mm") ? DAV1D_ARM_CPU_FLAG_I8MM : 0;
+#if ARCH_AARCH64
+    flags |= parse_proc_cpuinfo("sve") ? DAV1D_ARM_CPU_FLAG_SVE : 0;
+    flags |= parse_proc_cpuinfo("sve2") ? DAV1D_ARM_CPU_FLAG_SVE2 : 0;
+#endif /* ARCH_AARCH64 */
+    return flags;
+}
+
+#else  /* Unsupported OS */
+
+COLD unsigned dav1d_get_cpu_flags_arm(void) {
+    return dav1d_get_default_cpu_flags();
+}
+
+#endif
diff --git a/media/libdav1d/src/src/arm/cpu.h b/media/libdav1d/src/src/arm/cpu.h
new file mode 100644
index 0000000000..de9bde6ccf
--- /dev/null
+++ b/media/libdav1d/src/src/arm/cpu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_ARM_CPU_H
+#define DAV1D_SRC_ARM_CPU_H
+
+enum CpuFlags {
+    DAV1D_ARM_CPU_FLAG_NEON = 1 << 0,
+    DAV1D_ARM_CPU_FLAG_DOTPROD = 1 << 1,
+    DAV1D_ARM_CPU_FLAG_I8MM = 1 << 2,
+    DAV1D_ARM_CPU_FLAG_SVE = 1 << 3,
+    DAV1D_ARM_CPU_FLAG_SVE2 = 1 << 4,
+};
+
+unsigned dav1d_get_cpu_flags_arm(void);
+
+#endif /* DAV1D_SRC_ARM_CPU_H */
diff --git a/media/libdav1d/src/src/arm/filmgrain.h b/media/libdav1d/src/src/arm/filmgrain.h
new file mode 100644
index 0000000000..9f51b0310f
--- /dev/null
+++ b/media/libdav1d/src/src/arm/filmgrain.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 2018, Niklas Haas
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * Copyright © 2021, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/filmgrain.h"
+#include "asm-offsets.h"
+
+CHECK_OFFSET(Dav1dFilmGrainData, seed, FGD_SEED);
+CHECK_OFFSET(Dav1dFilmGrainData, ar_coeff_lag, FGD_AR_COEFF_LAG);
+CHECK_OFFSET(Dav1dFilmGrainData, ar_coeffs_y, FGD_AR_COEFFS_Y);
+CHECK_OFFSET(Dav1dFilmGrainData, ar_coeffs_uv, FGD_AR_COEFFS_UV);
+CHECK_OFFSET(Dav1dFilmGrainData, ar_coeff_shift, FGD_AR_COEFF_SHIFT);
+CHECK_OFFSET(Dav1dFilmGrainData, grain_scale_shift, FGD_GRAIN_SCALE_SHIFT);
+
+CHECK_OFFSET(Dav1dFilmGrainData, scaling_shift, FGD_SCALING_SHIFT);
+CHECK_OFFSET(Dav1dFilmGrainData, uv_mult, FGD_UV_MULT);
+CHECK_OFFSET(Dav1dFilmGrainData, uv_luma_mult, FGD_UV_LUMA_MULT);
+CHECK_OFFSET(Dav1dFilmGrainData, uv_offset, FGD_UV_OFFSET);
+CHECK_OFFSET(Dav1dFilmGrainData, clip_to_restricted_range, FGD_CLIP_TO_RESTRICTED_RANGE);
+
+void BF(dav1d_generate_grain_y, neon)(entry buf[][GRAIN_WIDTH],
+                                      const Dav1dFilmGrainData *const data
+                                      HIGHBD_DECL_SUFFIX);
+
+#define GEN_GRAIN_UV(suff) \
+void BF(dav1d_generate_grain_uv_ ## suff, neon)(entry buf[][GRAIN_WIDTH], \
+                                                const entry buf_y[][GRAIN_WIDTH], \
+                                                const Dav1dFilmGrainData *const data, \
+                                                const intptr_t uv \
+                                                HIGHBD_DECL_SUFFIX)
+
+GEN_GRAIN_UV(420);
+GEN_GRAIN_UV(422);
+GEN_GRAIN_UV(444);
+
+// Use ptrdiff_t instead of int for the last few parameters, to get the
+// same layout of parameters on the stack across platforms.
+void BF(dav1d_fgy_32x32, neon)(pixel *const dst,
+                               const pixel *const src,
+                               const ptrdiff_t stride,
+                               const uint8_t scaling[SCALING_SIZE],
+                               const int scaling_shift,
+                               const entry grain_lut[][GRAIN_WIDTH],
+                               const int offsets[][2],
+                               const int h, const ptrdiff_t clip,
+                               const ptrdiff_t type
+                               HIGHBD_DECL_SUFFIX);
+
+static void fgy_32x32xn_neon(pixel *const dst_row, const pixel *const src_row,
+                             const ptrdiff_t stride,
+                             const Dav1dFilmGrainData *const data, const size_t pw,
+                             const uint8_t scaling[SCALING_SIZE],
+                             const entry grain_lut[][GRAIN_WIDTH],
+                             const int bh, const int row_num HIGHBD_DECL_SUFFIX)
+{
+    const int rows = 1 + (data->overlap_flag && row_num > 0);
+
+    // seed[0] contains the current row, seed[1] contains the previous
+    unsigned seed[2];
+    for (int i = 0; i < rows; i++) {
+        seed[i] = data->seed;
+        seed[i] ^= (((row_num - i) * 37  + 178) & 0xFF) << 8;
+        seed[i] ^= (((row_num - i) * 173 + 105) & 0xFF);
+    }
+
+    int offsets[2 /* col offset */][2 /* row offset */];
+
+    // process this row in FG_BLOCK_SIZE^2 blocks
+    for (unsigned bx = 0; bx < pw; bx += FG_BLOCK_SIZE) {
+
+        if (data->overlap_flag && bx) {
+            // shift previous offsets left
+            for (int i = 0; i < rows; i++)
+                offsets[1][i] = offsets[0][i];
+        }
+
+        // update current offsets
+        for (int i = 0; i < rows; i++)
+            offsets[0][i] = get_random_number(8, &seed[i]);
+
+        int type = 0;
+        if (data->overlap_flag && row_num)
+            type |= 1; /* overlap y */
+        if (data->overlap_flag && bx)
+            type |= 2; /* overlap x */
+
+        BF(dav1d_fgy_32x32, neon)(dst_row + bx, src_row + bx, stride,
+                                  scaling, data->scaling_shift,
+                                  grain_lut, offsets, bh,
+                                  data->clip_to_restricted_range, type
+                                  HIGHBD_TAIL_SUFFIX);
+    }
+}
+
+// Use ptrdiff_t instead of int for the last few parameters, to get the
+// parameters on the stack with the same layout across platforms.
+#define FGUV(nm, sx, sy) \
+void BF(dav1d_fguv_32x32_##nm, neon)(pixel *const dst, \
+                                     const pixel *const src, \
+                                     const ptrdiff_t stride, \
+                                     const uint8_t scaling[SCALING_SIZE], \
+                                     const Dav1dFilmGrainData *const data, \
+                                     const entry grain_lut[][GRAIN_WIDTH], \
+                                     const pixel *const luma_row, \
+                                     const ptrdiff_t luma_stride, \
+                                     const int offsets[][2], \
+                                     const ptrdiff_t h, const ptrdiff_t uv, \
+                                     const ptrdiff_t is_id, \
+                                     const ptrdiff_t type \
+                                     HIGHBD_DECL_SUFFIX); \
+static void \
+fguv_32x32xn_##nm##_neon(pixel *const dst_row, const pixel *const src_row, \
+                  const ptrdiff_t stride, const Dav1dFilmGrainData *const data, \
+                  const size_t pw, const uint8_t scaling[SCALING_SIZE], \
+                  const entry grain_lut[][GRAIN_WIDTH], const int bh, \
+                  const int row_num, const pixel *const luma_row, \
+                  const ptrdiff_t luma_stride, const int uv, const int is_id \
+                  HIGHBD_DECL_SUFFIX) \
+{ \
+    const int rows = 1 + (data->overlap_flag && row_num > 0); \
+ \
+    /* seed[0] contains the current row, seed[1] contains the previous */ \
+    unsigned seed[2]; \
+    for (int i = 0; i < rows; i++) { \
+        seed[i] = data->seed; \
+        seed[i] ^= (((row_num - i) * 37  + 178) & 0xFF) << 8; \
+        seed[i] ^= (((row_num - i) * 173 + 105) & 0xFF); \
+    } \
+ \
+    int offsets[2 /* col offset */][2 /* row offset */]; \
+ \
+    /* process this row in FG_BLOCK_SIZE^2 blocks (subsampled) */ \
+    for (unsigned bx = 0; bx < pw; bx += FG_BLOCK_SIZE >> sx) { \
+        if (data->overlap_flag && bx) { \
+            /* shift previous offsets left */ \
+            for (int i = 0; i < rows; i++) \
+                offsets[1][i] = offsets[0][i]; \
+        } \
+ \
+        /* update current offsets */ \
+        for (int i = 0; i < rows; i++) \
+            offsets[0][i] = get_random_number(8, &seed[i]); \
+ \
+        int type = 0; \
+        if (data->overlap_flag && row_num) \
+            type |= 1; /* overlap y */ \
+        if (data->overlap_flag && bx) \
+            type |= 2; /* overlap x */ \
+        if (data->chroma_scaling_from_luma) \
+            type |= 4; \
+ \
+        BF(dav1d_fguv_32x32_##nm, neon)(dst_row + bx, src_row + bx, stride, \
+                                        scaling, data, grain_lut, \
+                                        luma_row + (bx << sx), luma_stride, \
+                                        offsets, bh, uv, is_id, type \
+                                        HIGHBD_TAIL_SUFFIX); \
+    } \
+}
+
+FGUV(420, 1, 1);
+FGUV(422, 1, 0);
+FGUV(444, 0, 0);
+
+static ALWAYS_INLINE void film_grain_dsp_init_arm(Dav1dFilmGrainDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
+
+    c->generate_grain_y = BF(dav1d_generate_grain_y, neon);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I420 - 1] = BF(dav1d_generate_grain_uv_420, neon);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I422 - 1] = BF(dav1d_generate_grain_uv_422, neon);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I444 - 1] = BF(dav1d_generate_grain_uv_444, neon);
+
+    c->fgy_32x32xn = fgy_32x32xn_neon;
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I420 - 1] = fguv_32x32xn_420_neon;
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I422 - 1] = fguv_32x32xn_422_neon;
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I444 - 1] = fguv_32x32xn_444_neon;
+}
diff --git a/media/libdav1d/src/src/arm/ipred.h b/media/libdav1d/src/src/arm/ipred.h
new file mode 100644
index 0000000000..9c2aae748d
--- /dev/null
+++ b/media/libdav1d/src/src/arm/ipred.h
@@ -0,0 +1,326 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/ipred.h"
+
+decl_angular_ipred_fn(BF(dav1d_ipred_dc, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_dc_128, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_dc_top, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_dc_left, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_h, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_v, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_paeth, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth_v, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth_h, neon));
+decl_angular_ipred_fn(BF(dav1d_ipred_filter, neon));
+
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl, neon));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_128, neon));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_top, neon));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_left, neon));
+
+decl_cfl_ac_fn(BF(dav1d_ipred_cfl_ac_420, neon));
+decl_cfl_ac_fn(BF(dav1d_ipred_cfl_ac_422, neon));
+decl_cfl_ac_fn(BF(dav1d_ipred_cfl_ac_444, neon));
+
+decl_pal_pred_fn(BF(dav1d_pal_pred, neon));
+
+#if ARCH_AARCH64
+void BF(dav1d_ipred_z1_upsample_edge, neon)(pixel *out, const int hsz,
+                                            const pixel *const in,
+                                            const int end HIGHBD_DECL_SUFFIX);
+void BF(dav1d_ipred_z1_filter_edge, neon)(pixel *out, const int sz,
+                                          const pixel *const in,
+                                          const int end, const int strength);
+void BF(dav1d_ipred_pixel_set, neon)(pixel *out, const pixel px,
+                                     const int n);
+void BF(dav1d_ipred_z1_fill1, neon)(pixel *dst, ptrdiff_t stride,
+                                    const pixel *const top, const int width,
+                                    const int height, const int dx,
+                                    const int max_base_x);
+void BF(dav1d_ipred_z1_fill2, neon)(pixel *dst, ptrdiff_t stride,
+                                    const pixel *const top, const int width,
+                                    const int height, const int dx,
+                                    const int max_base_x);
+
+static void ipred_z1_neon(pixel *dst, const ptrdiff_t stride,
+                          const pixel *const topleft_in,
+                          const int width, const int height, int angle,
+                          const int max_width, const int max_height
+                          HIGHBD_DECL_SUFFIX)
+{
+    const int is_sm = (angle >> 9) & 0x1;
+    const int enable_intra_edge_filter = angle >> 10;
+    angle &= 511;
+    int dx = dav1d_dr_intra_derivative[angle >> 1];
+    pixel top_out[64 + 64 + (64+15)*2 + 16];
+    int max_base_x;
+    const int upsample_above = enable_intra_edge_filter ?
+        get_upsample(width + height, 90 - angle, is_sm) : 0;
+    if (upsample_above) {
+        BF(dav1d_ipred_z1_upsample_edge, neon)(top_out, width + height,
+                                               topleft_in,
+                                               width + imin(width, height)
+                                               HIGHBD_TAIL_SUFFIX);
+        max_base_x = 2 * (width + height) - 2;
+        dx <<= 1;
+    } else {
+        const int filter_strength = enable_intra_edge_filter ?
+            get_filter_strength(width + height, 90 - angle, is_sm) : 0;
+        if (filter_strength) {
+            BF(dav1d_ipred_z1_filter_edge, neon)(top_out, width + height,
+                                                 topleft_in,
+                                                 width + imin(width, height),
+                                                 filter_strength);
+            max_base_x = width + height - 1;
+        } else {
+            max_base_x = width + imin(width, height) - 1;
+            memcpy(top_out, &topleft_in[1], (max_base_x + 1) * sizeof(pixel));
+        }
+    }
+    const int base_inc = 1 + upsample_above;
+    int pad_pixels = width + 15; // max(dx >> 6) == 15
+    BF(dav1d_ipred_pixel_set, neon)(&top_out[max_base_x + 1],
+                                    top_out[max_base_x], pad_pixels * base_inc);
+    if (upsample_above)
+        BF(dav1d_ipred_z1_fill2, neon)(dst, stride, top_out, width, height,
+                                       dx, max_base_x);
+    else
+        BF(dav1d_ipred_z1_fill1, neon)(dst, stride, top_out, width, height,
+                                       dx, max_base_x);
+}
+
+void BF(dav1d_ipred_reverse, neon)(pixel *dst, const pixel *const src,
+                                   const int n);
+
+void BF(dav1d_ipred_z2_upsample_edge, neon)(pixel *out, const int sz,
+                                            const pixel *const in
+                                            HIGHBD_DECL_SUFFIX);
+
+void BF(dav1d_ipred_z2_fill1, neon)(pixel *dst, ptrdiff_t stride,
+                                    const pixel *const top,
+                                    const pixel *const left,
+                                    const int width, const int height,
+                                    const int dx, const int dy);
+void BF(dav1d_ipred_z2_fill2, neon)(pixel *dst, ptrdiff_t stride,
+                                    const pixel *const top,
+                                    const pixel *const left,
+                                    const int width, const int height,
+                                    const int dx, const int dy);
+void BF(dav1d_ipred_z2_fill3, neon)(pixel *dst, ptrdiff_t stride,
+                                    const pixel *const top,
+                                    const pixel *const left,
+                                    const int width, const int height,
+                                    const int dx, const int dy);
+
+static void ipred_z2_neon(pixel *dst, const ptrdiff_t stride,
+                          const pixel *const topleft_in,
+                          const int width, const int height, int angle,
+                          const int max_width, const int max_height
+                          HIGHBD_DECL_SUFFIX)
+{
+    const int is_sm = (angle >> 9) & 0x1;
+    const int enable_intra_edge_filter = angle >> 10;
+    angle &= 511;
+    assert(angle > 90 && angle < 180);
+    int dy = dav1d_dr_intra_derivative[(angle - 90) >> 1];
+    int dx = dav1d_dr_intra_derivative[(180 - angle) >> 1];
+    const int upsample_left = enable_intra_edge_filter ?
+        get_upsample(width + height, 180 - angle, is_sm) : 0;
+    const int upsample_above = enable_intra_edge_filter ?
+        get_upsample(width + height, angle - 90, is_sm) : 0;
+    pixel buf[3*(64+1)];
+    pixel *left = &buf[2*(64+1)];
+    // The asm can underread below the start of top[] and left[]; to avoid
+    // surprising behaviour, make sure this is within the allocated stack space.
+    pixel *top = &buf[1*(64+1)];
+    pixel *flipped = &buf[0*(64+1)];
+
+    if (upsample_above) {
+        BF(dav1d_ipred_z2_upsample_edge, neon)(top, width, topleft_in
+                                               HIGHBD_TAIL_SUFFIX);
+        dx <<= 1;
+    } else {
+        const int filter_strength = enable_intra_edge_filter ?
+            get_filter_strength(width + height, angle - 90, is_sm) : 0;
+
+        if (filter_strength) {
+            BF(dav1d_ipred_z1_filter_edge, neon)(&top[1], imin(max_width, width),
+                                                 topleft_in, width,
+                                                 filter_strength);
+            if (max_width < width)
+                memcpy(&top[1 + max_width], &topleft_in[1 + max_width],
+                       (width - max_width) * sizeof(pixel));
+        } else {
+            pixel_copy(&top[1], &topleft_in[1], width);
+        }
+    }
+    if (upsample_left) {
+        flipped[0] = topleft_in[0];
+        BF(dav1d_ipred_reverse, neon)(&flipped[1], &topleft_in[0],
+                                      height);
+        BF(dav1d_ipred_z2_upsample_edge, neon)(left, height, flipped
+                                               HIGHBD_TAIL_SUFFIX);
+        dy <<= 1;
+    } else {
+        const int filter_strength = enable_intra_edge_filter ?
+            get_filter_strength(width + height, 180 - angle, is_sm) : 0;
+
+        if (filter_strength) {
+            flipped[0] = topleft_in[0];
+            BF(dav1d_ipred_reverse, neon)(&flipped[1], &topleft_in[0],
+                                          height);
+            BF(dav1d_ipred_z1_filter_edge, neon)(&left[1], imin(max_height, height),
+                                                 flipped, height,
+                                                 filter_strength);
+            if (max_height < height)
+                memcpy(&left[1 + max_height], &flipped[1 + max_height],
+                       (height - max_height) * sizeof(pixel));
+        } else {
+            BF(dav1d_ipred_reverse, neon)(&left[1], &topleft_in[0],
+                                          height);
+        }
+    }
+    top[0] = left[0] = *topleft_in;
+
+    assert(!(upsample_above && upsample_left));
+    if (!upsample_above && !upsample_left) {
+        BF(dav1d_ipred_z2_fill1, neon)(dst, stride, top, left, width, height,
+                                       dx, dy);
+    } else if (upsample_above) {
+        BF(dav1d_ipred_z2_fill2, neon)(dst, stride, top, left, width, height,
+                                       dx, dy);
+    } else /*if (upsample_left)*/ {
+        BF(dav1d_ipred_z2_fill3, neon)(dst, stride, top, left, width, height,
+                                       dx, dy);
+    }
+}
+
+void BF(dav1d_ipred_z3_fill1, neon)(pixel *dst, ptrdiff_t stride,
+                                    const pixel *const left, const int width,
+                                    const int height, const int dy,
+                                    const int max_base_y);
+void BF(dav1d_ipred_z3_fill2, neon)(pixel *dst, ptrdiff_t stride,
+                                    const pixel *const left, const int width,
+                                    const int height, const int dy,
+                                    const int max_base_y);
+
+static void ipred_z3_neon(pixel *dst, const ptrdiff_t stride,
+                          const pixel *const topleft_in,
+                          const int width, const int height, int angle,
+                          const int max_width, const int max_height
+                          HIGHBD_DECL_SUFFIX)
+{
+    const int is_sm = (angle >> 9) & 0x1;
+    const int enable_intra_edge_filter = angle >> 10;
+    angle &= 511;
+    assert(angle > 180);
+    int dy = dav1d_dr_intra_derivative[(270 - angle) >> 1];
+    pixel flipped[64 + 64 + 16];
+    pixel left_out[64 + 64 + (64+15)*2];
+    int max_base_y;
+    const int upsample_left = enable_intra_edge_filter ?
+        get_upsample(width + height, angle - 180, is_sm) : 0;
+    if (upsample_left) {
+        flipped[0] = topleft_in[0];
+        BF(dav1d_ipred_reverse, neon)(&flipped[1], &topleft_in[0],
+                                      height + imax(width, height));
+        BF(dav1d_ipred_z1_upsample_edge, neon)(left_out, width + height,
+                                               flipped,
+                                               height + imin(width, height)
+                                               HIGHBD_TAIL_SUFFIX);
+        max_base_y = 2 * (width + height) - 2;
+        dy <<= 1;
+    } else {
+        const int filter_strength = enable_intra_edge_filter ?
+            get_filter_strength(width + height, angle - 180, is_sm) : 0;
+
+        if (filter_strength) {
+            flipped[0] = topleft_in[0];
+            BF(dav1d_ipred_reverse, neon)(&flipped[1], &topleft_in[0],
+                                          height + imax(width, height));
+            BF(dav1d_ipred_z1_filter_edge, neon)(left_out, width + height,
+                                                 flipped,
+                                                 height + imin(width, height),
+                                                 filter_strength);
+            max_base_y = width + height - 1;
+        } else {
+            BF(dav1d_ipred_reverse, neon)(left_out, &topleft_in[0],
+                                          height + imin(width, height));
+            max_base_y = height + imin(width, height) - 1;
+        }
+    }
+    const int base_inc = 1 + upsample_left;
+    // The tbx based implementation needs left[] to have 64 bytes intitialized,
+    // the other implementation can read height + max(dy >> 6) past the end.
+    int pad_pixels = imax(64 - max_base_y - 1, height + 15);
+
+    BF(dav1d_ipred_pixel_set, neon)(&left_out[max_base_y + 1],
+                                    left_out[max_base_y], pad_pixels * base_inc);
+    if (upsample_left)
+        BF(dav1d_ipred_z3_fill2, neon)(dst, stride, left_out, width, height,
+                                       dy, max_base_y);
+    else
+        BF(dav1d_ipred_z3_fill1, neon)(dst, stride, left_out, width, height,
+                                       dy, max_base_y);
+}
+#endif
+
+static ALWAYS_INLINE void intra_pred_dsp_init_arm(Dav1dIntraPredDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
+
+    c->intra_pred[DC_PRED]       = BF(dav1d_ipred_dc, neon);
+    c->intra_pred[DC_128_PRED]   = BF(dav1d_ipred_dc_128, neon);
+    c->intra_pred[TOP_DC_PRED]   = BF(dav1d_ipred_dc_top, neon);
+    c->intra_pred[LEFT_DC_PRED]  = BF(dav1d_ipred_dc_left, neon);
+    c->intra_pred[HOR_PRED]      = BF(dav1d_ipred_h, neon);
+    c->intra_pred[VERT_PRED]     = BF(dav1d_ipred_v, neon);
+    c->intra_pred[PAETH_PRED]    = BF(dav1d_ipred_paeth, neon);
+    c->intra_pred[SMOOTH_PRED]   = BF(dav1d_ipred_smooth, neon);
+    c->intra_pred[SMOOTH_V_PRED] = BF(dav1d_ipred_smooth_v, neon);
+    c->intra_pred[SMOOTH_H_PRED] = BF(dav1d_ipred_smooth_h, neon);
+#if ARCH_AARCH64
+    c->intra_pred[Z1_PRED]       = ipred_z1_neon;
+    c->intra_pred[Z2_PRED]       = ipred_z2_neon;
+    c->intra_pred[Z3_PRED]       = ipred_z3_neon;
+#endif
+    c->intra_pred[FILTER_PRED]   = BF(dav1d_ipred_filter, neon);
+
+    c->cfl_pred[DC_PRED]         = BF(dav1d_ipred_cfl, neon);
+    c->cfl_pred[DC_128_PRED]     = BF(dav1d_ipred_cfl_128, neon);
+    c->cfl_pred[TOP_DC_PRED]     = BF(dav1d_ipred_cfl_top, neon);
+    c->cfl_pred[LEFT_DC_PRED]    = BF(dav1d_ipred_cfl_left, neon);
+
+    c->cfl_ac[DAV1D_PIXEL_LAYOUT_I420 - 1] = BF(dav1d_ipred_cfl_ac_420, neon);
+    c->cfl_ac[DAV1D_PIXEL_LAYOUT_I422 - 1] = BF(dav1d_ipred_cfl_ac_422, neon);
+    c->cfl_ac[DAV1D_PIXEL_LAYOUT_I444 - 1] = BF(dav1d_ipred_cfl_ac_444, neon);
+
+    c->pal_pred                  = BF(dav1d_pal_pred, neon);
+}
diff --git a/media/libdav1d/src/src/arm/itx.h b/media/libdav1d/src/src/arm/itx.h
new file mode 100644
index 0000000000..657f85e613
--- /dev/null
+++ b/media/libdav1d/src/src/arm/itx.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2019, Martin Storsjo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/itx.h"
+
+decl_itx17_fns( 4,  4, neon);
+decl_itx16_fns( 4,  8, neon);
+decl_itx16_fns( 4, 16, neon);
+decl_itx16_fns( 8,  4, neon);
+decl_itx16_fns( 8,  8, neon);
+decl_itx16_fns( 8, 16, neon);
+decl_itx2_fns ( 8, 32, neon);
+decl_itx16_fns(16,  4, neon);
+decl_itx16_fns(16,  8, neon);
+decl_itx12_fns(16, 16, neon);
+decl_itx2_fns (16, 32, neon);
+decl_itx2_fns (32,  8, neon);
+decl_itx2_fns (32, 16, neon);
+decl_itx2_fns (32, 32, neon);
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_16x64, neon));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_32x64, neon));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x16, neon));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x32, neon));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x64, neon));
+
+static ALWAYS_INLINE void itx_dsp_init_arm(Dav1dInvTxfmDSPContext *const c, int bpc,
+                                           int *const all_simd)
+{
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
+
+    assign_itx_fn( , 4, 4, wht_wht,           WHT_WHT,           neon);
+
+    if (BITDEPTH == 16 && bpc != 10) return;
+
+    assign_itx16_fn( ,  4,  4, neon);
+    assign_itx16_fn(R,  4,  8, neon);
+    assign_itx16_fn(R,  4, 16, neon);
+    assign_itx16_fn(R,  8,  4, neon);
+    assign_itx16_fn( ,  8,  8, neon);
+    assign_itx16_fn(R,  8, 16, neon);
+    assign_itx2_fn (R,  8, 32, neon);
+    assign_itx16_fn(R, 16,  4, neon);
+    assign_itx16_fn(R, 16,  8, neon);
+    assign_itx12_fn( , 16, 16, neon);
+    assign_itx2_fn (R, 16, 32, neon);
+    assign_itx1_fn (R, 16, 64, neon);
+    assign_itx2_fn (R, 32,  8, neon);
+    assign_itx2_fn (R, 32, 16, neon);
+    assign_itx2_fn ( , 32, 32, neon);
+    assign_itx1_fn (R, 32, 64, neon);
+    assign_itx1_fn (R, 64, 16, neon);
+    assign_itx1_fn (R, 64, 32, neon);
+    assign_itx1_fn ( , 64, 64, neon);
+    *all_simd = 1;
+}
diff --git a/media/libdav1d/src/src/arm/loopfilter.h b/media/libdav1d/src/src/arm/loopfilter.h
new file mode 100644
index 0000000000..9ac08d94d2
--- /dev/null
+++ b/media/libdav1d/src/src/arm/loopfilter.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/loopfilter.h"
+
+decl_loopfilter_sb_fn(BF(dav1d_lpf_h_sb_y, neon));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_v_sb_y, neon));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_h_sb_uv, neon));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_v_sb_uv, neon));
+
+static ALWAYS_INLINE void loop_filter_dsp_init_arm(Dav1dLoopFilterDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
+
+    c->loop_filter_sb[0][0] = BF(dav1d_lpf_h_sb_y, neon);
+    c->loop_filter_sb[0][1] = BF(dav1d_lpf_v_sb_y, neon);
+    c->loop_filter_sb[1][0] = BF(dav1d_lpf_h_sb_uv, neon);
+    c->loop_filter_sb[1][1] = BF(dav1d_lpf_v_sb_uv, neon);
+}
diff --git a/media/libdav1d/src/src/arm/looprestoration.h b/media/libdav1d/src/src/arm/looprestoration.h
new file mode 100644
index 0000000000..896c174870
--- /dev/null
+++ b/media/libdav1d/src/src/arm/looprestoration.h
@@ -0,0 +1,1131 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/looprestoration.h"
+
+#if ARCH_AARCH64
+void BF(dav1d_wiener_filter7, neon)(pixel *p, const ptrdiff_t stride,
+                                    const pixel (*left)[4], const pixel *lpf,
+                                    const int w, int h,
+                                    const LooprestorationParams *const params,
+                                    const enum LrEdgeFlags edges
+                                    HIGHBD_DECL_SUFFIX);
+void BF(dav1d_wiener_filter5, neon)(pixel *p, const ptrdiff_t stride,
+                                    const pixel (*left)[4], const pixel *lpf,
+                                    const int w, int h,
+                                    const LooprestorationParams *const params,
+                                    const enum LrEdgeFlags edges
+                                    HIGHBD_DECL_SUFFIX);
+#else
+
+// The 8bpc version calculates things slightly differently than the reference
+// C version. That version calculates roughly this:
+// int16_t sum = 0;
+// for (int i = 0; i < 7; i++)
+//     sum += src[idx] * fh[i];
+// int16_t sum2 = (src[x] << 7) - (1 << (bitdepth + 6)) + rounding_off_h;
+// sum = iclip(sum + sum2, INT16_MIN, INT16_MAX) >> round_bits_h;
+// sum += 1 << (bitdepth + 6 - round_bits_h);
+// Compared to the reference C version, this is the output of the first pass
+// _subtracted_ by 1 << (bitdepth + 6 - round_bits_h) = 2048, i.e.
+// with round_offset precompensated.
+// The 16bpc version calculates things pretty much the same way as the
+// reference C version, but with the end result subtracted by
+// 1 << (bitdepth + 6 - round_bits_h).
+void BF(dav1d_wiener_filter_h, neon)(int16_t *dst, const pixel (*left)[4],
+                                     const pixel *src, const int16_t fh[8],
+                                     const int w, const enum LrEdgeFlags edges
+                                     HIGHBD_DECL_SUFFIX);
+// This calculates things slightly differently than the reference C version.
+// This version calculates roughly this:
+// int32_t sum = 0;
+// for (int i = 0; i < 7; i++)
+//     sum += mid[idx] * fv[i];
+// sum = (sum + rounding_off_v) >> round_bits_v;
+// This function assumes that the width is a multiple of 8.
+void BF(dav1d_wiener_filter_v, neon)(pixel *dst, int16_t **ptrs,
+                                     const int16_t fv[8], const int w
+                                     HIGHBD_DECL_SUFFIX);
+
+void BF(dav1d_wiener_filter_hv, neon)(pixel *dst, const pixel (*left)[4],
+                                      const pixel *src,
+                                      const int16_t filter[2][8],
+                                      const int w, const enum LrEdgeFlags edges,
+                                      int16_t **ptrs
+                                      HIGHBD_DECL_SUFFIX);
+
+static void wiener_filter_neon(pixel *p, const ptrdiff_t stride,
+                               const pixel (*left)[4], const pixel *lpf,
+                               const int w, int h,
+                               const LooprestorationParams *const params,
+                               const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(int16_t, hor, 6 * 384,);
+    int16_t *ptrs[7], *rows[6];
+    for (int i = 0; i < 6; i++)
+        rows[i] = &hor[i * 384];
+    const int16_t (*const filter)[8] = params->filter;
+    const int16_t *fh = params->filter[0];
+    const int16_t *fv = params->filter[1];
+    const pixel *lpf_bottom = lpf + 6*PXSTRIDE(stride);
+
+    const pixel *src = p;
+    if (edges & LR_HAVE_TOP) {
+        ptrs[0] = rows[0];
+        ptrs[1] = rows[0];
+        ptrs[2] = rows[1];
+        ptrs[3] = rows[2];
+        ptrs[4] = rows[2];
+        ptrs[5] = rows[2];
+
+        BF(dav1d_wiener_filter_h, neon)(rows[0], NULL, lpf, fh, w, edges
+                                        HIGHBD_TAIL_SUFFIX);
+        lpf += PXSTRIDE(stride);
+        BF(dav1d_wiener_filter_h, neon)(rows[1], NULL, lpf, fh, w, edges
+                                        HIGHBD_TAIL_SUFFIX);
+
+        BF(dav1d_wiener_filter_h, neon)(rows[2], left, src, fh, w, edges
+                                        HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v1;
+
+        ptrs[4] = ptrs[5] = rows[3];
+        BF(dav1d_wiener_filter_h, neon)(rows[3], left, src, fh, w, edges
+                                        HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v2;
+
+        ptrs[5] = rows[4];
+        BF(dav1d_wiener_filter_h, neon)(rows[4], left, src, fh, w, edges
+                                        HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v3;
+    } else {
+        ptrs[0] = rows[0];
+        ptrs[1] = rows[0];
+        ptrs[2] = rows[0];
+        ptrs[3] = rows[0];
+        ptrs[4] = rows[0];
+        ptrs[5] = rows[0];
+
+        BF(dav1d_wiener_filter_h, neon)(rows[0], left, src, fh, w, edges
+                                        HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v1;
+
+        ptrs[4] = ptrs[5] = rows[1];
+        BF(dav1d_wiener_filter_h, neon)(rows[1], left, src, fh, w, edges
+                                        HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v2;
+
+        ptrs[5] = rows[2];
+        BF(dav1d_wiener_filter_h, neon)(rows[2], left, src, fh, w, edges
+                                        HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v3;
+
+        ptrs[6] = rows[3];
+        BF(dav1d_wiener_filter_hv, neon)(p, left, src, filter, w, edges, ptrs
+                                         HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+        p += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v3;
+
+        ptrs[6] = rows[4];
+        BF(dav1d_wiener_filter_hv, neon)(p, left, src, filter, w, edges, ptrs
+                                         HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+        p += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v3;
+    }
+
+    ptrs[6] = ptrs[5] + 384;
+    do {
+        BF(dav1d_wiener_filter_hv, neon)(p, left, src, filter, w, edges, ptrs
+                                         HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+        p += PXSTRIDE(stride);
+    } while (--h > 0);
+
+    if (!(edges & LR_HAVE_BOTTOM))
+        goto v3;
+
+    BF(dav1d_wiener_filter_hv, neon)(p, NULL, lpf_bottom, filter, w, edges, ptrs
+                                     HIGHBD_TAIL_SUFFIX);
+    lpf_bottom += PXSTRIDE(stride);
+    p += PXSTRIDE(stride);
+
+    BF(dav1d_wiener_filter_hv, neon)(p, NULL, lpf_bottom, filter, w, edges, ptrs
+                                     HIGHBD_TAIL_SUFFIX);
+    p += PXSTRIDE(stride);
+v1:
+    BF(dav1d_wiener_filter_v, neon)(p, ptrs, fv, w HIGHBD_TAIL_SUFFIX);
+
+    return;
+
+v3:
+    BF(dav1d_wiener_filter_v, neon)(p, ptrs, fv, w HIGHBD_TAIL_SUFFIX);
+    p += PXSTRIDE(stride);
+v2:
+    BF(dav1d_wiener_filter_v, neon)(p, ptrs, fv, w HIGHBD_TAIL_SUFFIX);
+    p += PXSTRIDE(stride);
+    goto v1;
+}
+#endif
+
+static void rotate_neon(int32_t **sumsq_ptrs, int16_t **sum_ptrs, int n) {
+    int32_t *tmp32 = sumsq_ptrs[0];
+    int16_t *tmp16 = sum_ptrs[0];
+    for (int i = 0; i < n - 1; i++) {
+        sumsq_ptrs[i] = sumsq_ptrs[i + 1];
+        sum_ptrs[i] = sum_ptrs[i + 1];
+    }
+    sumsq_ptrs[n - 1] = tmp32;
+    sum_ptrs[n - 1] = tmp16;
+}
+static void rotate5_x2_neon(int32_t **sumsq_ptrs, int16_t **sum_ptrs) {
+    int32_t *tmp32[2];
+    int16_t *tmp16[2];
+    for (int i = 0; i < 2; i++) {
+        tmp32[i] = sumsq_ptrs[i];
+        tmp16[i] = sum_ptrs[i];
+    }
+    for (int i = 0; i < 3; i++) {
+        sumsq_ptrs[i] = sumsq_ptrs[i + 2];
+        sum_ptrs[i] = sum_ptrs[i + 2];
+    }
+    for (int i = 0; i < 2; i++) {
+        sumsq_ptrs[3 + i] = tmp32[i];
+        sum_ptrs[3 + i] = tmp16[i];
+    }
+}
+
+void BF(dav1d_sgr_box3_row_h, neon)(int32_t *sumsq, int16_t *sum,
+                                    const pixel (*left)[4],
+                                    const pixel *src, const int w,
+                                    const enum LrEdgeFlags edges);
+void BF(dav1d_sgr_box5_row_h, neon)(int32_t *sumsq, int16_t *sum,
+                                    const pixel (*left)[4],
+                                    const pixel *src, const int w,
+                                    const enum LrEdgeFlags edges);
+void BF(dav1d_sgr_box35_row_h, neon)(int32_t *sumsq3, int16_t *sum3,
+                                     int32_t *sumsq5, int16_t *sum5,
+                                     const pixel (*left)[4],
+                                     const pixel *src, const int w,
+                                     const enum LrEdgeFlags edges);
+
+#if ARCH_ARM
+void dav1d_sgr_box3_row_v_neon(int32_t **sumsq, int16_t **sum,
+                               int32_t *sumsq_out, int16_t *sum_out,
+                               const int w);
+void dav1d_sgr_box5_row_v_neon(int32_t **sumsq, int16_t **sum,
+                               int32_t *sumsq_out, int16_t *sum_out,
+                               const int w);
+void dav1d_sgr_calc_row_ab1_neon(int32_t *AA, int16_t *BB, int w, int s,
+                                 int bitdepth_max);
+void dav1d_sgr_calc_row_ab2_neon(int32_t *AA, int16_t *BB, int w, int s,
+                                 int bitdepth_max);
+void BF(dav1d_sgr_finish_filter_row1, neon)(int16_t *tmp, const pixel *src,
+                                            int32_t **A_ptrs, int16_t **B_ptrs,
+                                            const int w);
+void BF(dav1d_sgr_weighted_row1, neon)(pixel *dst, const int16_t *t1,
+                                       const int w, const int wt
+                                       HIGHBD_DECL_SUFFIX);
+#else
+void dav1d_sgr_box3_vert_neon(int32_t **sumsq, int16_t **sum,
+                              int32_t *AA, int16_t *BB,
+                              const int w, const int s,
+                              const int bitdepth_max);
+void dav1d_sgr_box5_vert_neon(int32_t **sumsq, int16_t **sum,
+                              int32_t *AA, int16_t *BB,
+                              const int w, const int s,
+                              const int bitdepth_max);
+
+void BF(dav1d_sgr_finish_weighted1, neon)(pixel *dst,
+                                          int32_t **A_ptrs, int16_t **B_ptrs,
+                                          const int w, const int w1
+                                          HIGHBD_DECL_SUFFIX);
+void BF(dav1d_sgr_finish_weighted2, neon)(pixel *dst, const ptrdiff_t stride,
+                                          int32_t **A_ptrs, int16_t **B_ptrs,
+                                          const int w, const int h,
+                                          const int w1 HIGHBD_DECL_SUFFIX);
+
+void BF(dav1d_sgr_finish_filter1_2rows, neon)(int16_t *tmp, const pixel *src,
+                                              const ptrdiff_t src_stride,
+                                              int32_t **A_ptrs,
+                                              int16_t **B_ptrs,
+                                              const int w, const int h);
+#endif
+void BF(dav1d_sgr_finish_filter2_2rows, neon)(int16_t *tmp, const pixel *src,
+                                              const ptrdiff_t src_stride,
+                                              int32_t **A_ptrs, int16_t **B_ptrs,
+                                              const int w, const int h);
+void BF(dav1d_sgr_weighted2, neon)(pixel *dst, const ptrdiff_t dst_stride,
+                                   const int16_t *t1, const int16_t *t2,
+                                   const int w, const int h,
+                                   const int16_t wt[2] HIGHBD_DECL_SUFFIX);
+
+static void sgr_box3_vert_neon(int32_t **sumsq, int16_t **sum,
+                               int32_t *sumsq_out, int16_t *sum_out,
+                               const int w, const int s, const int bitdepth_max) {
+#if ARCH_ARM
+    dav1d_sgr_box3_row_v_neon(sumsq, sum, sumsq_out, sum_out, w);
+    dav1d_sgr_calc_row_ab1_neon(sumsq_out, sum_out, w, s, bitdepth_max);
+#else
+    // box3_v + calc_ab1
+    dav1d_sgr_box3_vert_neon(sumsq, sum, sumsq_out, sum_out, w, s, bitdepth_max);
+#endif
+    rotate_neon(sumsq, sum, 3);
+}
+
+static void sgr_box5_vert_neon(int32_t **sumsq, int16_t **sum,
+                               int32_t *sumsq_out, int16_t *sum_out,
+                               const int w, const int s, const int bitdepth_max) {
+#if ARCH_ARM
+    dav1d_sgr_box5_row_v_neon(sumsq, sum, sumsq_out, sum_out, w);
+    dav1d_sgr_calc_row_ab2_neon(sumsq_out, sum_out, w, s, bitdepth_max);
+#else
+    // box5_v + calc_ab2
+    dav1d_sgr_box5_vert_neon(sumsq, sum, sumsq_out, sum_out, w, s, bitdepth_max);
+#endif
+    rotate5_x2_neon(sumsq, sum);
+}
+
+static void sgr_box3_hv_neon(int32_t **sumsq, int16_t **sum,
+                             int32_t *AA, int16_t *BB,
+                             const pixel (*left)[4],
+                             const pixel *src, const int w,
+                             const int s,
+                             const enum LrEdgeFlags edges,
+                             const int bitdepth_max) {
+    BF(dav1d_sgr_box3_row_h, neon)(sumsq[2], sum[2], left, src, w, edges);
+    sgr_box3_vert_neon(sumsq, sum, AA, BB, w, s, bitdepth_max);
+}
+
+
+static void sgr_finish1_neon(pixel **dst, const ptrdiff_t stride,
+                             int32_t **A_ptrs, int16_t **B_ptrs, const int w,
+                             const int w1 HIGHBD_DECL_SUFFIX) {
+#if ARCH_ARM
+    ALIGN_STK_16(int16_t, tmp, 384,);
+
+    BF(dav1d_sgr_finish_filter_row1, neon)(tmp, *dst, A_ptrs, B_ptrs, w);
+    BF(dav1d_sgr_weighted_row1, neon)(*dst, tmp, w, w1 HIGHBD_TAIL_SUFFIX);
+#else
+    BF(dav1d_sgr_finish_weighted1, neon)(*dst, A_ptrs, B_ptrs,
+                                         w, w1 HIGHBD_TAIL_SUFFIX);
+#endif
+    *dst += PXSTRIDE(stride);
+    rotate_neon(A_ptrs, B_ptrs, 3);
+}
+
+#define ARM_FILTER_OUT_STRIDE 384
+
+static void sgr_finish2_neon(pixel **dst, const ptrdiff_t stride,
+                             int32_t **A_ptrs, int16_t **B_ptrs,
+                             const int w, const int h, const int w1
+                             HIGHBD_DECL_SUFFIX) {
+#if ARCH_ARM
+    ALIGN_STK_16(int16_t, tmp, 2*ARM_FILTER_OUT_STRIDE,);
+
+    BF(dav1d_sgr_finish_filter2_2rows, neon)(tmp, *dst, stride, A_ptrs, B_ptrs, w, h);
+    BF(dav1d_sgr_weighted_row1, neon)(*dst, tmp, w, w1 HIGHBD_TAIL_SUFFIX);
+    *dst += PXSTRIDE(stride);
+    if (h > 1) {
+        BF(dav1d_sgr_weighted_row1, neon)(*dst, tmp + FILTER_OUT_STRIDE, w, w1 HIGHBD_TAIL_SUFFIX);
+        *dst += PXSTRIDE(stride);
+    }
+#else
+    BF(dav1d_sgr_finish_weighted2, neon)(*dst, stride, A_ptrs, B_ptrs,
+                                         w, h, w1 HIGHBD_TAIL_SUFFIX);
+    *dst += 2*PXSTRIDE(stride);
+#endif
+    rotate_neon(A_ptrs, B_ptrs, 2);
+}
+
+static void sgr_finish_mix_neon(pixel **dst, const ptrdiff_t stride,
+                                int32_t **A5_ptrs, int16_t **B5_ptrs,
+                                int32_t **A3_ptrs, int16_t **B3_ptrs,
+                                const int w, const int h,
+                                const int w0, const int w1 HIGHBD_DECL_SUFFIX) {
+    ALIGN_STK_16(int16_t, tmp5, 2*ARM_FILTER_OUT_STRIDE,);
+    ALIGN_STK_16(int16_t, tmp3, 2*ARM_FILTER_OUT_STRIDE,);
+
+    BF(dav1d_sgr_finish_filter2_2rows, neon)(tmp5, *dst, stride,
+                                             A5_ptrs, B5_ptrs, w, h);
+#if ARCH_ARM
+    BF(dav1d_sgr_finish_filter_row1, neon)(tmp3, *dst, A3_ptrs, B3_ptrs, w);
+    BF(dav1d_sgr_finish_filter_row1, neon)(tmp3 + FILTER_OUT_STRIDE,
+                                           *dst + PXSTRIDE(stride),
+                                           &A3_ptrs[1], &B3_ptrs[1], w);
+#else
+    BF(dav1d_sgr_finish_filter1_2rows, neon)(tmp3, *dst, stride,
+                                             A3_ptrs, B3_ptrs, w, h);
+#endif
+    const int16_t wt[2] = { w0, w1 };
+    BF(dav1d_sgr_weighted2, neon)(*dst, stride,
+                                  tmp5, tmp3, w, h, wt HIGHBD_TAIL_SUFFIX);
+    *dst += h*PXSTRIDE(stride);
+    rotate_neon(A5_ptrs, B5_ptrs, 2);
+    rotate_neon(A3_ptrs, B3_ptrs, 4);
+}
+
+
+static void sgr_filter_3x3_neon(pixel *dst, const ptrdiff_t stride,
+                                const pixel (*left)[4], const pixel *lpf,
+                                const int w, int h,
+                                const LooprestorationParams *const params,
+                                const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+#define ARM_BUF_STRIDE (384 + 16)
+    ALIGN_STK_16(int32_t, sumsq_buf, ARM_BUF_STRIDE * 3 + 16,);
+    ALIGN_STK_16(int16_t, sum_buf, ARM_BUF_STRIDE * 3 + 16,);
+    int32_t *sumsq_ptrs[3], *sumsq_rows[3];
+    int16_t *sum_ptrs[3], *sum_rows[3];
+    for (int i = 0; i < 3; i++) {
+        sumsq_rows[i] = &sumsq_buf[i * ARM_BUF_STRIDE];
+        sum_rows[i] = &sum_buf[i * ARM_BUF_STRIDE];
+    }
+
+    ALIGN_STK_16(int32_t, A_buf, ARM_BUF_STRIDE * 3 + 16,);
+    ALIGN_STK_16(int16_t, B_buf, ARM_BUF_STRIDE * 3 + 16,);
+    int32_t *A_ptrs[3];
+    int16_t *B_ptrs[3];
+    for (int i = 0; i < 3; i++) {
+        A_ptrs[i] = &A_buf[i * ARM_BUF_STRIDE];
+        B_ptrs[i] = &B_buf[i * ARM_BUF_STRIDE];
+    }
+    const pixel *src = dst;
+    const pixel *lpf_bottom = lpf + 6*PXSTRIDE(stride);
+
+    if (edges & LR_HAVE_TOP) {
+        sumsq_ptrs[0] = sumsq_rows[0];
+        sumsq_ptrs[1] = sumsq_rows[1];
+        sumsq_ptrs[2] = sumsq_rows[2];
+        sum_ptrs[0] = sum_rows[0];
+        sum_ptrs[1] = sum_rows[1];
+        sum_ptrs[2] = sum_rows[2];
+
+        BF(dav1d_sgr_box3_row_h, neon)(sumsq_rows[0], sum_rows[0],
+                                       NULL, lpf, w, edges);
+        lpf += PXSTRIDE(stride);
+        BF(dav1d_sgr_box3_row_h, neon)(sumsq_rows[1], sum_rows[1],
+                                       NULL, lpf, w, edges);
+
+        sgr_box3_hv_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                         left, src, w, params->sgr.s1, edges, BITDEPTH_MAX);
+        left++;
+        src += PXSTRIDE(stride);
+        rotate_neon(A_ptrs, B_ptrs, 3);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sgr_box3_hv_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                         left, src, w, params->sgr.s1, edges, BITDEPTH_MAX);
+        left++;
+        src += PXSTRIDE(stride);
+        rotate_neon(A_ptrs, B_ptrs, 3);
+
+        if (--h <= 0)
+            goto vert_2;
+    } else {
+        sumsq_ptrs[0] = sumsq_rows[0];
+        sumsq_ptrs[1] = sumsq_rows[0];
+        sumsq_ptrs[2] = sumsq_rows[0];
+        sum_ptrs[0] = sum_rows[0];
+        sum_ptrs[1] = sum_rows[0];
+        sum_ptrs[2] = sum_rows[0];
+
+        BF(dav1d_sgr_box3_row_h, neon)(sumsq_rows[0], sum_rows[0],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        rotate_neon(A_ptrs, B_ptrs, 3);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sumsq_ptrs[2] = sumsq_rows[1];
+        sum_ptrs[2] = sum_rows[1];
+
+        sgr_box3_hv_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                         left, src, w, params->sgr.s1, edges, BITDEPTH_MAX);
+        left++;
+        src += PXSTRIDE(stride);
+        rotate_neon(A_ptrs, B_ptrs, 3);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        sumsq_ptrs[2] = sumsq_rows[2];
+        sum_ptrs[2] = sum_rows[2];
+    }
+
+    do {
+        sgr_box3_hv_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                         left, src, w, params->sgr.s1, edges, BITDEPTH_MAX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_finish1_neon(&dst, stride, A_ptrs, B_ptrs,
+                         w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+    } while (--h > 0);
+
+    if (!(edges & LR_HAVE_BOTTOM))
+        goto vert_2;
+
+    sgr_box3_hv_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                     NULL, lpf_bottom, w, params->sgr.s1, edges, BITDEPTH_MAX);
+    lpf_bottom += PXSTRIDE(stride);
+
+    sgr_finish1_neon(&dst, stride, A_ptrs, B_ptrs,
+                     w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+
+    sgr_box3_hv_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                     NULL, lpf_bottom, w, params->sgr.s1, edges, BITDEPTH_MAX);
+
+    sgr_finish1_neon(&dst, stride, A_ptrs, B_ptrs,
+                     w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_2:
+    sumsq_ptrs[2] = sumsq_ptrs[1];
+    sum_ptrs[2] = sum_ptrs[1];
+    sgr_box3_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+
+    sgr_finish1_neon(&dst, stride, A_ptrs, B_ptrs,
+                     w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+
+output_1:
+    sumsq_ptrs[2] = sumsq_ptrs[1];
+    sum_ptrs[2] = sum_ptrs[1];
+    sgr_box3_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+
+    sgr_finish1_neon(&dst, stride, A_ptrs, B_ptrs,
+                     w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_1:
+    sumsq_ptrs[2] = sumsq_ptrs[1];
+    sum_ptrs[2] = sum_ptrs[1];
+    sgr_box3_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+    rotate_neon(A_ptrs, B_ptrs, 3);
+    goto output_1;
+}
+
+static void sgr_filter_5x5_neon(pixel *dst, const ptrdiff_t stride,
+                                const pixel (*left)[4], const pixel *lpf,
+                                const int w, int h,
+                                const LooprestorationParams *const params,
+                                const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(int32_t, sumsq_buf, ARM_BUF_STRIDE * 5 + 16,);
+    ALIGN_STK_16(int16_t, sum_buf, ARM_BUF_STRIDE * 5 + 16,);
+    int32_t *sumsq_ptrs[5], *sumsq_rows[5];
+    int16_t *sum_ptrs[5], *sum_rows[5];
+    for (int i = 0; i < 5; i++) {
+        sumsq_rows[i] = &sumsq_buf[i * ARM_BUF_STRIDE];
+        sum_rows[i] = &sum_buf[i * ARM_BUF_STRIDE];
+    }
+
+    ALIGN_STK_16(int32_t, A_buf, ARM_BUF_STRIDE * 2 + 16,);
+    ALIGN_STK_16(int16_t, B_buf, ARM_BUF_STRIDE * 2 + 16,);
+    int32_t *A_ptrs[2];
+    int16_t *B_ptrs[2];
+    for (int i = 0; i < 2; i++) {
+        A_ptrs[i] = &A_buf[i * ARM_BUF_STRIDE];
+        B_ptrs[i] = &B_buf[i * ARM_BUF_STRIDE];
+    }
+    const pixel *src = dst;
+    const pixel *lpf_bottom = lpf + 6*PXSTRIDE(stride);
+
+    if (edges & LR_HAVE_TOP) {
+        sumsq_ptrs[0] = sumsq_rows[0];
+        sumsq_ptrs[1] = sumsq_rows[0];
+        sumsq_ptrs[2] = sumsq_rows[1];
+        sumsq_ptrs[3] = sumsq_rows[2];
+        sumsq_ptrs[4] = sumsq_rows[3];
+        sum_ptrs[0] = sum_rows[0];
+        sum_ptrs[1] = sum_rows[0];
+        sum_ptrs[2] = sum_rows[1];
+        sum_ptrs[3] = sum_rows[2];
+        sum_ptrs[4] = sum_rows[3];
+
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_rows[0], sum_rows[0],
+                                       NULL, lpf, w, edges);
+        lpf += PXSTRIDE(stride);
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_rows[1], sum_rows[1],
+                                       NULL, lpf, w, edges);
+
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_rows[2], sum_rows[2],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_rows[3], sum_rows[3],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+        sgr_box5_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                           w, params->sgr.s0, BITDEPTH_MAX);
+        rotate_neon(A_ptrs, B_ptrs, 2);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        // ptrs are rotated by 2; both [3] and [4] now point at rows[0]; set
+        // one of them to point at the previously unused rows[4].
+        sumsq_ptrs[3] = sumsq_rows[4];
+        sum_ptrs[3] = sum_rows[4];
+    } else {
+        sumsq_ptrs[0] = sumsq_rows[0];
+        sumsq_ptrs[1] = sumsq_rows[0];
+        sumsq_ptrs[2] = sumsq_rows[0];
+        sumsq_ptrs[3] = sumsq_rows[0];
+        sumsq_ptrs[4] = sumsq_rows[0];
+        sum_ptrs[0] = sum_rows[0];
+        sum_ptrs[1] = sum_rows[0];
+        sum_ptrs[2] = sum_rows[0];
+        sum_ptrs[3] = sum_rows[0];
+        sum_ptrs[4] = sum_rows[0];
+
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_rows[0], sum_rows[0],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sumsq_ptrs[4] = sumsq_rows[1];
+        sum_ptrs[4] = sum_rows[1];
+
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_rows[1], sum_rows[1],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                           w, params->sgr.s0, BITDEPTH_MAX);
+        rotate_neon(A_ptrs, B_ptrs, 2);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        sumsq_ptrs[3] = sumsq_rows[2];
+        sumsq_ptrs[4] = sumsq_rows[3];
+        sum_ptrs[3] = sum_rows[2];
+        sum_ptrs[4] = sum_rows[3];
+
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_rows[2], sum_rows[2],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto odd;
+
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_rows[3], sum_rows[3],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                           w, params->sgr.s0, BITDEPTH_MAX);
+        sgr_finish2_neon(&dst, stride, A_ptrs, B_ptrs,
+                         w, 2, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        // ptrs are rotated by 2; both [3] and [4] now point at rows[0]; set
+        // one of them to point at the previously unused rows[4].
+        sumsq_ptrs[3] = sumsq_rows[4];
+        sum_ptrs[3] = sum_rows[4];
+    }
+
+    do {
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_ptrs[3], sum_ptrs[3],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto odd;
+
+        BF(dav1d_sgr_box5_row_h, neon)(sumsq_ptrs[4], sum_ptrs[4],
+                                       left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                           w, params->sgr.s0, BITDEPTH_MAX);
+        sgr_finish2_neon(&dst, stride, A_ptrs, B_ptrs,
+                         w, 2, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+    } while (--h > 0);
+
+    if (!(edges & LR_HAVE_BOTTOM))
+        goto vert_2;
+
+    BF(dav1d_sgr_box5_row_h, neon)(sumsq_ptrs[3], sum_ptrs[3],
+                                   NULL, lpf_bottom, w, edges);
+    lpf_bottom += PXSTRIDE(stride);
+    BF(dav1d_sgr_box5_row_h, neon)(sumsq_ptrs[4], sum_ptrs[4],
+                                   NULL, lpf_bottom, w, edges);
+
+output_2:
+    sgr_box5_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                       w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_finish2_neon(&dst, stride, A_ptrs, B_ptrs,
+                     w, 2, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_2:
+    // Duplicate the last row twice more
+    sumsq_ptrs[3] = sumsq_ptrs[2];
+    sumsq_ptrs[4] = sumsq_ptrs[2];
+    sum_ptrs[3] = sum_ptrs[2];
+    sum_ptrs[4] = sum_ptrs[2];
+    goto output_2;
+
+odd:
+    // Copy the last row as padding once
+    sumsq_ptrs[4] = sumsq_ptrs[3];
+    sum_ptrs[4] = sum_ptrs[3];
+
+    sgr_box5_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                       w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_finish2_neon(&dst, stride, A_ptrs, B_ptrs,
+                     w, 2, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+
+output_1:
+    // Duplicate the last row twice more
+    sumsq_ptrs[3] = sumsq_ptrs[2];
+    sumsq_ptrs[4] = sumsq_ptrs[2];
+    sum_ptrs[3] = sum_ptrs[2];
+    sum_ptrs[4] = sum_ptrs[2];
+
+    sgr_box5_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                       w, params->sgr.s0, BITDEPTH_MAX);
+    // Output only one row
+    sgr_finish2_neon(&dst, stride, A_ptrs, B_ptrs,
+                     w, 1, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_1:
+    // Copy the last row as padding once
+    sumsq_ptrs[4] = sumsq_ptrs[3];
+    sum_ptrs[4] = sum_ptrs[3];
+
+    sgr_box5_vert_neon(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                       w, params->sgr.s0, BITDEPTH_MAX);
+    rotate_neon(A_ptrs, B_ptrs, 2);
+
+    goto output_1;
+}
+
+static void sgr_filter_mix_neon(pixel *dst, const ptrdiff_t stride,
+                                const pixel (*left)[4], const pixel *lpf,
+                                const int w, int h,
+                                const LooprestorationParams *const params,
+                                const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(int32_t, sumsq5_buf, ARM_BUF_STRIDE * 5 + 16,);
+    ALIGN_STK_16(int16_t, sum5_buf, ARM_BUF_STRIDE * 5 + 16,);
+    int32_t *sumsq5_ptrs[5], *sumsq5_rows[5];
+    int16_t *sum5_ptrs[5], *sum5_rows[5];
+    for (int i = 0; i < 5; i++) {
+        sumsq5_rows[i] = &sumsq5_buf[i * ARM_BUF_STRIDE];
+        sum5_rows[i] = &sum5_buf[i * ARM_BUF_STRIDE];
+    }
+    ALIGN_STK_16(int32_t, sumsq3_buf, ARM_BUF_STRIDE * 3 + 16,);
+    ALIGN_STK_16(int16_t, sum3_buf, ARM_BUF_STRIDE * 3 + 16,);
+    int32_t *sumsq3_ptrs[3], *sumsq3_rows[3];
+    int16_t *sum3_ptrs[3], *sum3_rows[3];
+    for (int i = 0; i < 3; i++) {
+        sumsq3_rows[i] = &sumsq3_buf[i * ARM_BUF_STRIDE];
+        sum3_rows[i] = &sum3_buf[i * ARM_BUF_STRIDE];
+    }
+
+    ALIGN_STK_16(int32_t, A5_buf, ARM_BUF_STRIDE * 2 + 16,);
+    ALIGN_STK_16(int16_t, B5_buf, ARM_BUF_STRIDE * 2 + 16,);
+    int32_t *A5_ptrs[2];
+    int16_t *B5_ptrs[2];
+    for (int i = 0; i < 2; i++) {
+        A5_ptrs[i] = &A5_buf[i * ARM_BUF_STRIDE];
+        B5_ptrs[i] = &B5_buf[i * ARM_BUF_STRIDE];
+    }
+    ALIGN_STK_16(int32_t, A3_buf, ARM_BUF_STRIDE * 4 + 16,);
+    ALIGN_STK_16(int16_t, B3_buf, ARM_BUF_STRIDE * 4 + 16,);
+    int32_t *A3_ptrs[4];
+    int16_t *B3_ptrs[4];
+    for (int i = 0; i < 4; i++) {
+        A3_ptrs[i] = &A3_buf[i * ARM_BUF_STRIDE];
+        B3_ptrs[i] = &B3_buf[i * ARM_BUF_STRIDE];
+    }
+    const pixel *src = dst;
+    const pixel *lpf_bottom = lpf + 6*PXSTRIDE(stride);
+
+    if (edges & LR_HAVE_TOP) {
+        sumsq5_ptrs[0] = sumsq5_rows[0];
+        sumsq5_ptrs[1] = sumsq5_rows[0];
+        sumsq5_ptrs[2] = sumsq5_rows[1];
+        sumsq5_ptrs[3] = sumsq5_rows[2];
+        sumsq5_ptrs[4] = sumsq5_rows[3];
+        sum5_ptrs[0] = sum5_rows[0];
+        sum5_ptrs[1] = sum5_rows[0];
+        sum5_ptrs[2] = sum5_rows[1];
+        sum5_ptrs[3] = sum5_rows[2];
+        sum5_ptrs[4] = sum5_rows[3];
+
+        sumsq3_ptrs[0] = sumsq3_rows[0];
+        sumsq3_ptrs[1] = sumsq3_rows[1];
+        sumsq3_ptrs[2] = sumsq3_rows[2];
+        sum3_ptrs[0] = sum3_rows[0];
+        sum3_ptrs[1] = sum3_rows[1];
+        sum3_ptrs[2] = sum3_rows[2];
+
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_rows[0], sum3_rows[0],
+                                        sumsq5_rows[0], sum5_rows[0],
+                                        NULL, lpf, w, edges);
+        lpf += PXSTRIDE(stride);
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_rows[1], sum3_rows[1],
+                                        sumsq5_rows[1], sum5_rows[1],
+                                        NULL, lpf, w, edges);
+
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_rows[2], sum3_rows[2],
+                                        sumsq5_rows[2], sum5_rows[2],
+                                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_ptrs[2], sum3_ptrs[2],
+                                        sumsq5_rows[3], sum5_rows[3],
+                                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+        sgr_box5_vert_neon(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                           w, params->sgr.s0, BITDEPTH_MAX);
+        rotate_neon(A5_ptrs, B5_ptrs, 2);
+        sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        // ptrs are rotated by 2; both [3] and [4] now point at rows[0]; set
+        // one of them to point at the previously unused rows[4].
+        sumsq5_ptrs[3] = sumsq5_rows[4];
+        sum5_ptrs[3] = sum5_rows[4];
+    } else {
+        sumsq5_ptrs[0] = sumsq5_rows[0];
+        sumsq5_ptrs[1] = sumsq5_rows[0];
+        sumsq5_ptrs[2] = sumsq5_rows[0];
+        sumsq5_ptrs[3] = sumsq5_rows[0];
+        sumsq5_ptrs[4] = sumsq5_rows[0];
+        sum5_ptrs[0] = sum5_rows[0];
+        sum5_ptrs[1] = sum5_rows[0];
+        sum5_ptrs[2] = sum5_rows[0];
+        sum5_ptrs[3] = sum5_rows[0];
+        sum5_ptrs[4] = sum5_rows[0];
+
+        sumsq3_ptrs[0] = sumsq3_rows[0];
+        sumsq3_ptrs[1] = sumsq3_rows[0];
+        sumsq3_ptrs[2] = sumsq3_rows[0];
+        sum3_ptrs[0] = sum3_rows[0];
+        sum3_ptrs[1] = sum3_rows[0];
+        sum3_ptrs[2] = sum3_rows[0];
+
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_rows[0], sum3_rows[0],
+                                        sumsq5_rows[0], sum5_rows[0],
+                                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sumsq5_ptrs[4] = sumsq5_rows[1];
+        sum5_ptrs[4] = sum5_rows[1];
+
+        sumsq3_ptrs[2] = sumsq3_rows[1];
+        sum3_ptrs[2] = sum3_rows[1];
+
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_rows[1], sum3_rows[1],
+                                        sumsq5_rows[1], sum5_rows[1],
+                                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert_neon(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                           w, params->sgr.s0, BITDEPTH_MAX);
+        rotate_neon(A5_ptrs, B5_ptrs, 2);
+        sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        sumsq5_ptrs[3] = sumsq5_rows[2];
+        sumsq5_ptrs[4] = sumsq5_rows[3];
+        sum5_ptrs[3] = sum5_rows[2];
+        sum5_ptrs[4] = sum5_rows[3];
+
+        sumsq3_ptrs[2] = sumsq3_rows[2];
+        sum3_ptrs[2] = sum3_rows[2];
+
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_rows[2], sum3_rows[2],
+                                        sumsq5_rows[2], sum5_rows[2],
+                                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto odd;
+
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_ptrs[2], sum3_ptrs[2],
+                                        sumsq5_rows[3], sum5_rows[3],
+                                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert_neon(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                           w, params->sgr.s0, BITDEPTH_MAX);
+        sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        sgr_finish_mix_neon(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                            w, 2, params->sgr.w0, params->sgr.w1
+                            HIGHBD_TAIL_SUFFIX);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        // ptrs are rotated by 2; both [3] and [4] now point at rows[0]; set
+        // one of them to point at the previously unused rows[4].
+        sumsq5_ptrs[3] = sumsq5_rows[4];
+        sum5_ptrs[3] = sum5_rows[4];
+    }
+
+    do {
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_ptrs[2], sum3_ptrs[2],
+                                        sumsq5_ptrs[3], sum5_ptrs[3],
+                                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto odd;
+
+        BF(dav1d_sgr_box35_row_h, neon)(sumsq3_ptrs[2], sum3_ptrs[2],
+                                        sumsq5_ptrs[4], sum5_ptrs[4],
+                                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert_neon(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                           w, params->sgr.s0, BITDEPTH_MAX);
+        sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                           w, params->sgr.s1, BITDEPTH_MAX);
+        sgr_finish_mix_neon(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                            w, 2, params->sgr.w0, params->sgr.w1
+                            HIGHBD_TAIL_SUFFIX);
+    } while (--h > 0);
+
+    if (!(edges & LR_HAVE_BOTTOM))
+        goto vert_2;
+
+    BF(dav1d_sgr_box35_row_h, neon)(sumsq3_ptrs[2], sum3_ptrs[2],
+                                    sumsq5_ptrs[3], sum5_ptrs[3],
+                                    NULL, lpf_bottom, w, edges);
+    lpf_bottom += PXSTRIDE(stride);
+    sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+    rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+    BF(dav1d_sgr_box35_row_h, neon)(sumsq3_ptrs[2], sum3_ptrs[2],
+                                    sumsq5_ptrs[4], sum5_ptrs[4],
+                                    NULL, lpf_bottom, w, edges);
+
+output_2:
+    sgr_box5_vert_neon(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                       w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+    sgr_finish_mix_neon(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                        w, 2, params->sgr.w0, params->sgr.w1
+                        HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_2:
+    // Duplicate the last row twice more
+    sumsq5_ptrs[3] = sumsq5_ptrs[2];
+    sumsq5_ptrs[4] = sumsq5_ptrs[2];
+    sum5_ptrs[3] = sum5_ptrs[2];
+    sum5_ptrs[4] = sum5_ptrs[2];
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+    sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+    rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+
+    goto output_2;
+
+odd:
+    // Copy the last row as padding once
+    sumsq5_ptrs[4] = sumsq5_ptrs[3];
+    sum5_ptrs[4] = sum5_ptrs[3];
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+
+    sgr_box5_vert_neon(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                       w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+    sgr_finish_mix_neon(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                        w, 2, params->sgr.w0, params->sgr.w1
+                        HIGHBD_TAIL_SUFFIX);
+
+output_1:
+    // Duplicate the last row twice more
+    sumsq5_ptrs[3] = sumsq5_ptrs[2];
+    sumsq5_ptrs[4] = sumsq5_ptrs[2];
+    sum5_ptrs[3] = sum5_ptrs[2];
+    sum5_ptrs[4] = sum5_ptrs[2];
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+
+    sgr_box5_vert_neon(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                       w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+    rotate_neon(A3_ptrs, B3_ptrs, 4);
+    // Output only one row
+    sgr_finish_mix_neon(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                        w, 1, params->sgr.w0, params->sgr.w1
+                        HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_1:
+    // Copy the last row as padding once
+    sumsq5_ptrs[4] = sumsq5_ptrs[3];
+    sum5_ptrs[4] = sum5_ptrs[3];
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+
+    sgr_box5_vert_neon(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                       w, params->sgr.s0, BITDEPTH_MAX);
+    rotate_neon(A5_ptrs, B5_ptrs, 2);
+    sgr_box3_vert_neon(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                       w, params->sgr.s1, BITDEPTH_MAX);
+    rotate_neon(A3_ptrs, B3_ptrs, 4);
+
+    goto output_1;
+}
+
+
+static ALWAYS_INLINE void loop_restoration_dsp_init_arm(Dav1dLoopRestorationDSPContext *const c, int bpc) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
+
+#if ARCH_AARCH64
+    c->wiener[0] = BF(dav1d_wiener_filter7, neon);
+    c->wiener[1] = BF(dav1d_wiener_filter5, neon);
+#else
+    c->wiener[0] = c->wiener[1] = wiener_filter_neon;
+#endif
+    if (BITDEPTH == 8 || bpc == 10) {
+        c->sgr[0] = sgr_filter_5x5_neon;
+        c->sgr[1] = sgr_filter_3x3_neon;
+        c->sgr[2] = sgr_filter_mix_neon;
+    }
+}
diff --git a/media/libdav1d/src/src/arm/mc.h b/media/libdav1d/src/src/arm/mc.h
new file mode 100644
index 0000000000..a00dbdbd8f
--- /dev/null
+++ b/media/libdav1d/src/src/arm/mc.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "src/mc.h"
+#include "src/cpu.h"
+
+decl_8tap_fns(neon);
+decl_8tap_fns(neon_dotprod);
+decl_8tap_fns(neon_i8mm);
+decl_8tap_fns(sve2);
+
+decl_mc_fn(BF(dav1d_put_bilin, neon));
+decl_mct_fn(BF(dav1d_prep_bilin, neon));
+
+decl_avg_fn(BF(dav1d_avg, neon));
+decl_w_avg_fn(BF(dav1d_w_avg, neon));
+decl_mask_fn(BF(dav1d_mask, neon));
+decl_blend_fn(BF(dav1d_blend, neon));
+decl_blend_dir_fn(BF(dav1d_blend_h, neon));
+decl_blend_dir_fn(BF(dav1d_blend_v, neon));
+
+decl_w_mask_fn(BF(dav1d_w_mask_444, neon));
+decl_w_mask_fn(BF(dav1d_w_mask_422, neon));
+decl_w_mask_fn(BF(dav1d_w_mask_420, neon));
+
+decl_warp8x8_fn(BF(dav1d_warp_affine_8x8, neon));
+decl_warp8x8t_fn(BF(dav1d_warp_affine_8x8t, neon));
+
+decl_emu_edge_fn(BF(dav1d_emu_edge, neon));
+
+static ALWAYS_INLINE void mc_dsp_init_arm(Dav1dMCDSPContext *const c) {
+#define init_mc_fn(type, name, suffix) \
+    c->mc[type] = BF(dav1d_put_##name, suffix)
+#define init_mct_fn(type, name, suffix) \
+    c->mct[type] = BF(dav1d_prep_##name, suffix)
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
+
+    init_8tap_fns(neon);
+
+    init_mc_fn (FILTER_2D_BILINEAR, bilin, neon);
+    init_mct_fn(FILTER_2D_BILINEAR, bilin, neon);
+
+    c->avg = BF(dav1d_avg, neon);
+    c->w_avg = BF(dav1d_w_avg, neon);
+    c->mask = BF(dav1d_mask, neon);
+    c->blend = BF(dav1d_blend, neon);
+    c->blend_h = BF(dav1d_blend_h, neon);
+    c->blend_v = BF(dav1d_blend_v, neon);
+    c->w_mask[0] = BF(dav1d_w_mask_444, neon);
+    c->w_mask[1] = BF(dav1d_w_mask_422, neon);
+    c->w_mask[2] = BF(dav1d_w_mask_420, neon);
+    c->warp8x8 = BF(dav1d_warp_affine_8x8, neon);
+    c->warp8x8t = BF(dav1d_warp_affine_8x8t, neon);
+    c->emu_edge = BF(dav1d_emu_edge, neon);
+
+#if ARCH_AARCH64
+#if BITDEPTH == 8
+#if HAVE_DOTPROD
+    if (flags & DAV1D_ARM_CPU_FLAG_DOTPROD) {
+        init_8tap_fns(neon_dotprod);
+    }
+#endif  // HAVE_DOTPROD
+
+#if HAVE_I8MM
+    if (flags & DAV1D_ARM_CPU_FLAG_I8MM) {
+        init_8tap_fns(neon_i8mm);
+    }
+#endif  // HAVE_I8MM
+#endif  // BITDEPTH == 8
+
+#if BITDEPTH == 16
+#if HAVE_SVE2
+    if (flags & DAV1D_ARM_CPU_FLAG_SVE2) {
+        init_8tap_fns(sve2);
+    }
+#endif  // HAVE_SVE2
+#endif  // BITDEPTH == 16
+#endif  // ARCH_AARCH64
+}
diff --git a/media/libdav1d/src/src/arm/msac.h b/media/libdav1d/src/src/arm/msac.h
new file mode 100644
index 0000000000..6eee0da424
--- /dev/null
+++ b/media/libdav1d/src/src/arm/msac.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_ARM_MSAC_H
+#define DAV1D_SRC_ARM_MSAC_H
+
+unsigned dav1d_msac_decode_symbol_adapt4_neon(MsacContext *s, uint16_t *cdf,
+                                              size_t n_symbols);
+unsigned dav1d_msac_decode_symbol_adapt8_neon(MsacContext *s, uint16_t *cdf,
+                                              size_t n_symbols);
+unsigned dav1d_msac_decode_symbol_adapt16_neon(MsacContext *s, uint16_t *cdf,
+                                               size_t n_symbols);
+unsigned dav1d_msac_decode_hi_tok_neon(MsacContext *s, uint16_t *cdf);
+unsigned dav1d_msac_decode_bool_adapt_neon(MsacContext *s, uint16_t *cdf);
+unsigned dav1d_msac_decode_bool_equi_neon(MsacContext *s);
+unsigned dav1d_msac_decode_bool_neon(MsacContext *s, unsigned f);
+
+#if defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32) || ARCH_AARCH64
+#define dav1d_msac_decode_symbol_adapt4  dav1d_msac_decode_symbol_adapt4_neon
+#define dav1d_msac_decode_symbol_adapt8  dav1d_msac_decode_symbol_adapt8_neon
+#define dav1d_msac_decode_symbol_adapt16 dav1d_msac_decode_symbol_adapt16_neon
+#define dav1d_msac_decode_hi_tok         dav1d_msac_decode_hi_tok_neon
+#define dav1d_msac_decode_bool_adapt     dav1d_msac_decode_bool_adapt_neon
+#define dav1d_msac_decode_bool_equi      dav1d_msac_decode_bool_equi_neon
+#define dav1d_msac_decode_bool           dav1d_msac_decode_bool_neon
+#endif
+
+#endif /* DAV1D_SRC_ARM_MSAC_H */
diff --git a/media/libdav1d/src/src/arm/refmvs.h b/media/libdav1d/src/src/arm/refmvs.h
new file mode 100644
index 0000000000..82195d3d37
--- /dev/null
+++ b/media/libdav1d/src/src/arm/refmvs.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * Copyright © 2021, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/arm/asm-offsets.h"
+#include "src/cpu.h"
+#include "src/refmvs.h"
+
+#if ARCH_AARCH64
+CHECK_OFFSET(refmvs_frame, iw8, RMVSF_IW8);
+CHECK_OFFSET(refmvs_frame, ih8, RMVSF_IH8);
+CHECK_OFFSET(refmvs_frame, mfmv_ref, RMVSF_MFMV_REF);
+CHECK_OFFSET(refmvs_frame, mfmv_ref2cur, RMVSF_MFMV_REF2CUR);
+CHECK_OFFSET(refmvs_frame, mfmv_ref2ref, RMVSF_MFMV_REF2REF);
+CHECK_OFFSET(refmvs_frame, n_mfmvs, RMVSF_N_MFMVS);
+CHECK_OFFSET(refmvs_frame, rp_ref, RMVSF_RP_REF);
+CHECK_OFFSET(refmvs_frame, rp_proj, RMVSF_RP_PROJ);
+CHECK_OFFSET(refmvs_frame, rp_stride, RMVSF_RP_STRIDE);
+CHECK_OFFSET(refmvs_frame, n_tile_threads, RMVSF_N_TILE_THREADS);
+#endif
+
+decl_load_tmvs_fn(dav1d_load_tmvs_neon);
+decl_save_tmvs_fn(dav1d_save_tmvs_neon);
+decl_splat_mv_fn(dav1d_splat_mv_neon);
+
+static ALWAYS_INLINE void refmvs_dsp_init_arm(Dav1dRefmvsDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return;
+
+#if ARCH_AARCH64
+    c->load_tmvs = dav1d_load_tmvs_neon;
+#endif
+    c->save_tmvs = dav1d_save_tmvs_neon;
+    c->splat_mv = dav1d_splat_mv_neon;
+}
diff --git a/media/libdav1d/src/src/cdef.h b/media/libdav1d/src/src/cdef.h
new file mode 100644
index 0000000000..07c84d9ff5
--- /dev/null
+++ b/media/libdav1d/src/src/cdef.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_CDEF_H
+#define DAV1D_SRC_CDEF_H
+
+#include 
+#include 
+
+#include "common/bitdepth.h"
+
+enum CdefEdgeFlags {
+    CDEF_HAVE_LEFT = 1 << 0,
+    CDEF_HAVE_RIGHT = 1 << 1,
+    CDEF_HAVE_TOP = 1 << 2,
+    CDEF_HAVE_BOTTOM = 1 << 3,
+};
+
+#ifdef BITDEPTH
+typedef const pixel (*const_left_pixel_row_2px)[2];
+#else
+typedef const void *const_left_pixel_row_2px;
+#endif
+
+// CDEF operates entirely on pre-filter data; if bottom/right edges are
+// present (according to $edges), then the pre-filter data is located in
+// $dst. However, the edge pixels above $dst may be post-filter, so in
+// order to get access to pre-filter top pixels, use $top.
+#define decl_cdef_fn(name) \
+void (name)(pixel *dst, ptrdiff_t stride, const_left_pixel_row_2px left, \
+            const pixel *top, const pixel *bottom, \
+            int pri_strength, int sec_strength, \
+            int dir, int damping, enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX)
+typedef decl_cdef_fn(*cdef_fn);
+
+#define decl_cdef_dir_fn(name) \
+int (name)(const pixel *dst, ptrdiff_t dst_stride, unsigned *var HIGHBD_DECL_SUFFIX)
+typedef decl_cdef_dir_fn(*cdef_dir_fn);
+
+typedef struct Dav1dCdefDSPContext {
+    cdef_dir_fn dir;
+    cdef_fn fb[3 /* 444/luma, 422, 420 */];
+} Dav1dCdefDSPContext;
+
+bitfn_decls(void dav1d_cdef_dsp_init, Dav1dCdefDSPContext *c);
+
+#endif /* DAV1D_SRC_CDEF_H */
diff --git a/media/libdav1d/src/src/cdef_apply.h b/media/libdav1d/src/src/cdef_apply.h
new file mode 100644
index 0000000000..a9748ee4f6
--- /dev/null
+++ b/media/libdav1d/src/src/cdef_apply.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_CDEF_APPLY_H
+#define DAV1D_SRC_CDEF_APPLY_H
+
+#include "common/bitdepth.h"
+
+#include "src/internal.h"
+
+void bytefn(dav1d_cdef_brow)(Dav1dTaskContext *tc, pixel *const p[3],
+                             const Av1Filter *lflvl, int by_start, int by_end,
+                             int sbrow_start, int sby);
+
+#endif /* DAV1D_SRC_CDEF_APPLY_H */
diff --git a/media/libdav1d/src/src/cdef_apply_tmpl.c b/media/libdav1d/src/src/cdef_apply_tmpl.c
new file mode 100644
index 0000000000..9b09f19cc6
--- /dev/null
+++ b/media/libdav1d/src/src/cdef_apply_tmpl.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/cdef_apply.h"
+
+enum Backup2x8Flags {
+    BACKUP_2X8_Y = 1 << 0,
+    BACKUP_2X8_UV = 1 << 1,
+};
+
+static void backup2lines(pixel *const dst[3], /*const*/ pixel *const src[3],
+                         const ptrdiff_t stride[2],
+                         const enum Dav1dPixelLayout layout)
+{
+    const ptrdiff_t y_stride = PXSTRIDE(stride[0]);
+    if (y_stride < 0)
+        pixel_copy(dst[0] + y_stride, src[0] + 7 * y_stride, -2 * y_stride);
+    else
+        pixel_copy(dst[0], src[0] + 6 * y_stride, 2 * y_stride);
+
+    if (layout != DAV1D_PIXEL_LAYOUT_I400) {
+        const ptrdiff_t uv_stride = PXSTRIDE(stride[1]);
+        if (uv_stride < 0) {
+            const int uv_off = layout == DAV1D_PIXEL_LAYOUT_I420 ? 3 : 7;
+            pixel_copy(dst[1] + uv_stride, src[1] + uv_off * uv_stride, -2 * uv_stride);
+            pixel_copy(dst[2] + uv_stride, src[2] + uv_off * uv_stride, -2 * uv_stride);
+        } else {
+            const int uv_off = layout == DAV1D_PIXEL_LAYOUT_I420 ? 2 : 6;
+            pixel_copy(dst[1], src[1] + uv_off * uv_stride, 2 * uv_stride);
+            pixel_copy(dst[2], src[2] + uv_off * uv_stride, 2 * uv_stride);
+        }
+    }
+}
+
+static void backup2x8(pixel dst[3][8][2],
+                      /*const*/ pixel *const src[3],
+                      const ptrdiff_t src_stride[2], int x_off,
+                      const enum Dav1dPixelLayout layout,
+                      const enum Backup2x8Flags flag)
+{
+    ptrdiff_t y_off = 0;
+    if (flag & BACKUP_2X8_Y) {
+        for (int y = 0; y < 8; y++, y_off += PXSTRIDE(src_stride[0]))
+            pixel_copy(dst[0][y], &src[0][y_off + x_off - 2], 2);
+    }
+
+    if (layout == DAV1D_PIXEL_LAYOUT_I400 || !(flag & BACKUP_2X8_UV))
+        return;
+
+    const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
+
+    x_off >>= ss_hor;
+    y_off = 0;
+    for (int y = 0; y < (8 >> ss_ver); y++, y_off += PXSTRIDE(src_stride[1])) {
+        pixel_copy(dst[1][y], &src[1][y_off + x_off - 2], 2);
+        pixel_copy(dst[2][y], &src[2][y_off + x_off - 2], 2);
+    }
+}
+
+static int adjust_strength(const int strength, const unsigned var) {
+    if (!var) return 0;
+    const int i = var >> 6 ? imin(ulog2(var >> 6), 12) : 0;
+    return (strength * (4 + i) + 8) >> 4;
+}
+
+void bytefn(dav1d_cdef_brow)(Dav1dTaskContext *const tc,
+                             pixel *const p[3],
+                             const Av1Filter *const lflvl,
+                             const int by_start, const int by_end,
+                             const int sbrow_start, const int sby)
+{
+    Dav1dFrameContext *const f = (Dav1dFrameContext *)tc->f;
+    const int bitdepth_min_8 = BITDEPTH == 8 ? 0 : f->cur.p.bpc - 8;
+    const Dav1dDSPContext *const dsp = f->dsp;
+    enum CdefEdgeFlags edges = CDEF_HAVE_BOTTOM | (by_start > 0 ? CDEF_HAVE_TOP : 0);
+    pixel *ptrs[3] = { p[0], p[1], p[2] };
+    const int sbsz = 16;
+    const int sb64w = f->sb128w << 1;
+    const int damping = f->frame_hdr->cdef.damping + bitdepth_min_8;
+    const enum Dav1dPixelLayout layout = f->cur.p.layout;
+    const int uv_idx = DAV1D_PIXEL_LAYOUT_I444 - layout;
+    const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
+    static const uint8_t uv_dirs[2][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 },
+                                           { 7, 0, 2, 4, 5, 6, 6, 6 } };
+    const uint8_t *uv_dir = uv_dirs[layout == DAV1D_PIXEL_LAYOUT_I422];
+    const int have_tt = f->c->n_tc > 1;
+    const int sb128 = f->seq_hdr->sb128;
+    const int resize = f->frame_hdr->width[0] != f->frame_hdr->width[1];
+    const ptrdiff_t y_stride = PXSTRIDE(f->cur.stride[0]);
+    const ptrdiff_t uv_stride = PXSTRIDE(f->cur.stride[1]);
+
+    for (int bit = 0, by = by_start; by < by_end; by += 2, edges |= CDEF_HAVE_TOP) {
+        const int tf = tc->top_pre_cdef_toggle;
+        const int by_idx = (by & 30) >> 1;
+        if (by + 2 >= f->bh) edges &= ~CDEF_HAVE_BOTTOM;
+
+        if ((!have_tt || sbrow_start || by + 2 < by_end) &&
+            edges & CDEF_HAVE_BOTTOM)
+        {
+            // backup pre-filter data for next iteration
+            pixel *const cdef_top_bak[3] = {
+                f->lf.cdef_line[!tf][0] + have_tt * sby * 4 * y_stride,
+                f->lf.cdef_line[!tf][1] + have_tt * sby * 8 * uv_stride,
+                f->lf.cdef_line[!tf][2] + have_tt * sby * 8 * uv_stride
+            };
+            backup2lines(cdef_top_bak, ptrs, f->cur.stride, layout);
+        }
+
+        ALIGN_STK_16(pixel, lr_bak, 2 /* idx */, [3 /* plane */][8 /* y */][2 /* x */]);
+        pixel *iptrs[3] = { ptrs[0], ptrs[1], ptrs[2] };
+        edges &= ~CDEF_HAVE_LEFT;
+        edges |= CDEF_HAVE_RIGHT;
+        enum Backup2x8Flags prev_flag = 0;
+        for (int sbx = 0; sbx < sb64w; sbx++, edges |= CDEF_HAVE_LEFT) {
+            const int sb128x = sbx >> 1;
+            const int sb64_idx = ((by & sbsz) >> 3) + (sbx & 1);
+            const int cdef_idx = lflvl[sb128x].cdef_idx[sb64_idx];
+            if (cdef_idx == -1 ||
+                (!f->frame_hdr->cdef.y_strength[cdef_idx] &&
+                 !f->frame_hdr->cdef.uv_strength[cdef_idx]))
+            {
+                prev_flag = 0;
+                goto next_sb;
+            }
+
+            // Create a complete 32-bit mask for the sb row ahead of time.
+            const uint16_t (*noskip_row)[2] = &lflvl[sb128x].noskip_mask[by_idx];
+            const unsigned noskip_mask = (unsigned) noskip_row[0][1] << 16 |
+                                                    noskip_row[0][0];
+
+            const int y_lvl = f->frame_hdr->cdef.y_strength[cdef_idx];
+            const int uv_lvl = f->frame_hdr->cdef.uv_strength[cdef_idx];
+            const enum Backup2x8Flags flag = !!y_lvl + (!!uv_lvl << 1);
+
+            const int y_pri_lvl = (y_lvl >> 2) << bitdepth_min_8;
+            int y_sec_lvl = y_lvl & 3;
+            y_sec_lvl += y_sec_lvl == 3;
+            y_sec_lvl <<= bitdepth_min_8;
+
+            const int uv_pri_lvl = (uv_lvl >> 2) << bitdepth_min_8;
+            int uv_sec_lvl = uv_lvl & 3;
+            uv_sec_lvl += uv_sec_lvl == 3;
+            uv_sec_lvl <<= bitdepth_min_8;
+
+            pixel *bptrs[3] = { iptrs[0], iptrs[1], iptrs[2] };
+            for (int bx = sbx * sbsz; bx < imin((sbx + 1) * sbsz, f->bw);
+                 bx += 2, edges |= CDEF_HAVE_LEFT)
+            {
+                if (bx + 2 >= f->bw) edges &= ~CDEF_HAVE_RIGHT;
+
+                // check if this 8x8 block had any coded coefficients; if not,
+                // go to the next block
+                const uint32_t bx_mask = 3U << (bx & 30);
+                if (!(noskip_mask & bx_mask)) {
+                    prev_flag = 0;
+                    goto next_b;
+                }
+                const enum Backup2x8Flags do_left = (prev_flag ^ flag) & flag;
+                prev_flag = flag;
+                if (do_left && edges & CDEF_HAVE_LEFT) {
+                    // we didn't backup the prefilter data because it wasn't
+                    // there, so do it here instead
+                    backup2x8(lr_bak[bit], bptrs, f->cur.stride, 0, layout, do_left);
+                }
+                if (edges & CDEF_HAVE_RIGHT) {
+                    // backup pre-filter data for next iteration
+                    backup2x8(lr_bak[!bit], bptrs, f->cur.stride, 8, layout, flag);
+                }
+
+                int dir;
+                unsigned variance;
+                if (y_pri_lvl || uv_pri_lvl)
+                    dir = dsp->cdef.dir(bptrs[0], f->cur.stride[0],
+                                        &variance HIGHBD_CALL_SUFFIX);
+
+                const pixel *top, *bot;
+                ptrdiff_t offset;
+
+                if (!have_tt) goto st_y;
+                if (sbrow_start && by == by_start) {
+                    if (resize) {
+                        offset = (sby - 1) * 4 * y_stride + bx * 4;
+                        top = &f->lf.cdef_lpf_line[0][offset];
+                    } else {
+                        offset = (sby * (4 << sb128) - 4) * y_stride + bx * 4;
+                        top = &f->lf.lr_lpf_line[0][offset];
+                    }
+                    bot = bptrs[0] + 8 * y_stride;
+                } else if (!sbrow_start && by + 2 >= by_end) {
+                    top = &f->lf.cdef_line[tf][0][sby * 4 * y_stride + bx * 4];
+                    if (resize) {
+                        offset = (sby * 4 + 2) * y_stride + bx * 4;
+                        bot = &f->lf.cdef_lpf_line[0][offset];
+                    } else {
+                        const int line = sby * (4 << sb128) + 4 * sb128 + 2;
+                        offset = line * y_stride + bx * 4;
+                        bot = &f->lf.lr_lpf_line[0][offset];
+                    }
+                } else {
+            st_y:;
+                    offset = sby * 4 * y_stride;
+                    top = &f->lf.cdef_line[tf][0][have_tt * offset + bx * 4];
+                    bot = bptrs[0] + 8 * y_stride;
+                }
+                if (y_pri_lvl) {
+                    const int adj_y_pri_lvl = adjust_strength(y_pri_lvl, variance);
+                    if (adj_y_pri_lvl || y_sec_lvl)
+                        dsp->cdef.fb[0](bptrs[0], f->cur.stride[0], lr_bak[bit][0],
+                                        top, bot, adj_y_pri_lvl, y_sec_lvl,
+                                        dir, damping, edges HIGHBD_CALL_SUFFIX);
+                } else if (y_sec_lvl)
+                    dsp->cdef.fb[0](bptrs[0], f->cur.stride[0], lr_bak[bit][0],
+                                    top, bot, 0, y_sec_lvl, 0, damping,
+                                    edges HIGHBD_CALL_SUFFIX);
+
+                if (!uv_lvl) goto skip_uv;
+                assert(layout != DAV1D_PIXEL_LAYOUT_I400);
+
+                const int uvdir = uv_pri_lvl ? uv_dir[dir] : 0;
+                for (int pl = 1; pl <= 2; pl++) {
+                    if (!have_tt) goto st_uv;
+                    if (sbrow_start && by == by_start) {
+                        if (resize) {
+                            offset = (sby - 1) * 4 * uv_stride + (bx * 4 >> ss_hor);
+                            top = &f->lf.cdef_lpf_line[pl][offset];
+                        } else {
+                            const int line = sby * (4 << sb128) - 4;
+                            offset = line * uv_stride + (bx * 4 >> ss_hor);
+                            top = &f->lf.lr_lpf_line[pl][offset];
+                        }
+                        bot = bptrs[pl] + (8 >> ss_ver) * uv_stride;
+                    } else if (!sbrow_start && by + 2 >= by_end) {
+                        const ptrdiff_t top_offset = sby * 8 * uv_stride +
+                                                     (bx * 4 >> ss_hor);
+                        top = &f->lf.cdef_line[tf][pl][top_offset];
+                        if (resize) {
+                            offset = (sby * 4 + 2) * uv_stride + (bx * 4 >> ss_hor);
+                            bot = &f->lf.cdef_lpf_line[pl][offset];
+                        } else {
+                            const int line = sby * (4 << sb128) + 4 * sb128 + 2;
+                            offset = line * uv_stride + (bx * 4 >> ss_hor);
+                            bot = &f->lf.lr_lpf_line[pl][offset];
+                        }
+                    } else {
+                st_uv:;
+                        const ptrdiff_t offset = sby * 8 * uv_stride;
+                        top = &f->lf.cdef_line[tf][pl][have_tt * offset + (bx * 4 >> ss_hor)];
+                        bot = bptrs[pl] + (8 >> ss_ver) * uv_stride;
+                    }
+                    dsp->cdef.fb[uv_idx](bptrs[pl], f->cur.stride[1],
+                                         lr_bak[bit][pl], top, bot,
+                                         uv_pri_lvl, uv_sec_lvl, uvdir,
+                                         damping - 1, edges HIGHBD_CALL_SUFFIX);
+                }
+
+            skip_uv:
+                bit ^= 1;
+
+            next_b:
+                bptrs[0] += 8;
+                bptrs[1] += 8 >> ss_hor;
+                bptrs[2] += 8 >> ss_hor;
+            }
+
+        next_sb:
+            iptrs[0] += sbsz * 4;
+            iptrs[1] += sbsz * 4 >> ss_hor;
+            iptrs[2] += sbsz * 4 >> ss_hor;
+        }
+
+        ptrs[0] += 8 * PXSTRIDE(f->cur.stride[0]);
+        ptrs[1] += 8 * PXSTRIDE(f->cur.stride[1]) >> ss_ver;
+        ptrs[2] += 8 * PXSTRIDE(f->cur.stride[1]) >> ss_ver;
+        tc->top_pre_cdef_toggle ^= 1;
+    }
+}
diff --git a/media/libdav1d/src/src/cdef_tmpl.c b/media/libdav1d/src/src/cdef_tmpl.c
new file mode 100644
index 0000000000..4efea4505a
--- /dev/null
+++ b/media/libdav1d/src/src/cdef_tmpl.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/cdef.h"
+#include "src/tables.h"
+
+static inline int constrain(const int diff, const int threshold,
+                            const int shift)
+{
+    const int adiff = abs(diff);
+    return apply_sign(imin(adiff, imax(0, threshold - (adiff >> shift))), diff);
+}
+
+static inline void fill(int16_t *tmp, const ptrdiff_t stride,
+                        const int w, const int h)
+{
+    /* Use a value that's a large positive number when interpreted as unsigned,
+     * and a large negative number when interpreted as signed. */
+    for (int y = 0; y < h; y++) {
+        for (int x = 0; x < w; x++)
+            tmp[x] = INT16_MIN;
+        tmp += stride;
+    }
+}
+
+static void padding(int16_t *tmp, const ptrdiff_t tmp_stride,
+                    const pixel *src, const ptrdiff_t src_stride,
+                    const pixel (*left)[2],
+                    const pixel *top, const pixel *bottom,
+                    const int w, const int h, const enum CdefEdgeFlags edges)
+{
+    // fill extended input buffer
+    int x_start = -2, x_end = w + 2, y_start = -2, y_end = h + 2;
+    if (!(edges & CDEF_HAVE_TOP)) {
+        fill(tmp - 2 - 2 * tmp_stride, tmp_stride, w + 4, 2);
+        y_start = 0;
+    }
+    if (!(edges & CDEF_HAVE_BOTTOM)) {
+        fill(tmp + h * tmp_stride - 2, tmp_stride, w + 4, 2);
+        y_end -= 2;
+    }
+    if (!(edges & CDEF_HAVE_LEFT)) {
+        fill(tmp + y_start * tmp_stride - 2, tmp_stride, 2, y_end - y_start);
+        x_start = 0;
+    }
+    if (!(edges & CDEF_HAVE_RIGHT)) {
+        fill(tmp + y_start * tmp_stride + w, tmp_stride, 2, y_end - y_start);
+        x_end -= 2;
+    }
+
+    for (int y = y_start; y < 0; y++) {
+        for (int x = x_start; x < x_end; x++)
+            tmp[x + y * tmp_stride] = top[x];
+        top += PXSTRIDE(src_stride);
+    }
+    for (int y = 0; y < h; y++)
+        for (int x = x_start; x < 0; x++)
+            tmp[x + y * tmp_stride] = left[y][2 + x];
+    for (int y = 0; y < h; y++) {
+        for (int x = (y < h) ? 0 : x_start; x < x_end; x++)
+            tmp[x] = src[x];
+        src += PXSTRIDE(src_stride);
+        tmp += tmp_stride;
+    }
+    for (int y = h; y < y_end; y++) {
+        for (int x = x_start; x < x_end; x++)
+            tmp[x] = bottom[x];
+        bottom += PXSTRIDE(src_stride);
+        tmp += tmp_stride;
+    }
+
+}
+
+static NOINLINE void
+cdef_filter_block_c(pixel *dst, const ptrdiff_t dst_stride,
+                    const pixel (*left)[2],
+                    const pixel *const top, const pixel *const bottom,
+                    const int pri_strength, const int sec_strength,
+                    const int dir, const int damping, const int w, int h,
+                    const enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    const ptrdiff_t tmp_stride = 12;
+    assert((w == 4 || w == 8) && (h == 4 || h == 8));
+    int16_t tmp_buf[144]; // 12*12 is the maximum value of tmp_stride * (h + 4)
+    int16_t *tmp = tmp_buf + 2 * tmp_stride + 2;
+
+    padding(tmp, tmp_stride, dst, dst_stride, left, top, bottom, w, h, edges);
+
+    if (pri_strength) {
+        const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+        const int pri_tap = 4 - ((pri_strength >> bitdepth_min_8) & 1);
+        const int pri_shift = imax(0, damping - ulog2(pri_strength));
+        if (sec_strength) {
+            const int sec_shift = damping - ulog2(sec_strength);
+            do {
+                for (int x = 0; x < w; x++) {
+                    const int px = dst[x];
+                    int sum = 0;
+                    int max = px, min = px;
+                    int pri_tap_k = pri_tap;
+                    for (int k = 0; k < 2; k++) {
+                        const int off1 = dav1d_cdef_directions[dir + 2][k]; // dir
+                        const int p0 = tmp[x + off1];
+                        const int p1 = tmp[x - off1];
+                        sum += pri_tap_k * constrain(p0 - px, pri_strength, pri_shift);
+                        sum += pri_tap_k * constrain(p1 - px, pri_strength, pri_shift);
+                        // if pri_tap_k == 4 then it becomes 2 else it remains 3
+                        pri_tap_k = (pri_tap_k & 3) | 2;
+                        min = umin(p0, min);
+                        max = imax(p0, max);
+                        min = umin(p1, min);
+                        max = imax(p1, max);
+                        const int off2 = dav1d_cdef_directions[dir + 4][k]; // dir + 2
+                        const int off3 = dav1d_cdef_directions[dir + 0][k]; // dir - 2
+                        const int s0 = tmp[x + off2];
+                        const int s1 = tmp[x - off2];
+                        const int s2 = tmp[x + off3];
+                        const int s3 = tmp[x - off3];
+                        // sec_tap starts at 2 and becomes 1
+                        const int sec_tap = 2 - k;
+                        sum += sec_tap * constrain(s0 - px, sec_strength, sec_shift);
+                        sum += sec_tap * constrain(s1 - px, sec_strength, sec_shift);
+                        sum += sec_tap * constrain(s2 - px, sec_strength, sec_shift);
+                        sum += sec_tap * constrain(s3 - px, sec_strength, sec_shift);
+                        min = umin(s0, min);
+                        max = imax(s0, max);
+                        min = umin(s1, min);
+                        max = imax(s1, max);
+                        min = umin(s2, min);
+                        max = imax(s2, max);
+                        min = umin(s3, min);
+                        max = imax(s3, max);
+                    }
+                    dst[x] = iclip(px + ((sum - (sum < 0) + 8) >> 4), min, max);
+                }
+                dst += PXSTRIDE(dst_stride);
+                tmp += tmp_stride;
+            } while (--h);
+        } else { // pri_strength only
+            do {
+                for (int x = 0; x < w; x++) {
+                    const int px = dst[x];
+                    int sum = 0;
+                    int pri_tap_k = pri_tap;
+                    for (int k = 0; k < 2; k++) {
+                        const int off = dav1d_cdef_directions[dir + 2][k]; // dir
+                        const int p0 = tmp[x + off];
+                        const int p1 = tmp[x - off];
+                        sum += pri_tap_k * constrain(p0 - px, pri_strength, pri_shift);
+                        sum += pri_tap_k * constrain(p1 - px, pri_strength, pri_shift);
+                        pri_tap_k = (pri_tap_k & 3) | 2;
+                    }
+                    dst[x] = px + ((sum - (sum < 0) + 8) >> 4);
+                }
+                dst += PXSTRIDE(dst_stride);
+                tmp += tmp_stride;
+            } while (--h);
+        }
+    } else { // sec_strength only
+        assert(sec_strength);
+        const int sec_shift = damping - ulog2(sec_strength);
+        do {
+            for (int x = 0; x < w; x++) {
+                const int px = dst[x];
+                int sum = 0;
+                for (int k = 0; k < 2; k++) {
+                    const int off1 = dav1d_cdef_directions[dir + 4][k]; // dir + 2
+                    const int off2 = dav1d_cdef_directions[dir + 0][k]; // dir - 2
+                    const int s0 = tmp[x + off1];
+                    const int s1 = tmp[x - off1];
+                    const int s2 = tmp[x + off2];
+                    const int s3 = tmp[x - off2];
+                    const int sec_tap = 2 - k;
+                    sum += sec_tap * constrain(s0 - px, sec_strength, sec_shift);
+                    sum += sec_tap * constrain(s1 - px, sec_strength, sec_shift);
+                    sum += sec_tap * constrain(s2 - px, sec_strength, sec_shift);
+                    sum += sec_tap * constrain(s3 - px, sec_strength, sec_shift);
+                }
+                dst[x] = px + ((sum - (sum < 0) + 8) >> 4);
+            }
+            dst += PXSTRIDE(dst_stride);
+            tmp += tmp_stride;
+        } while (--h);
+    }
+}
+
+#define cdef_fn(w, h) \
+static void cdef_filter_block_##w##x##h##_c(pixel *const dst, \
+                                            const ptrdiff_t stride, \
+                                            const pixel (*left)[2], \
+                                            const pixel *const top, \
+                                            const pixel *const bottom, \
+                                            const int pri_strength, \
+                                            const int sec_strength, \
+                                            const int dir, \
+                                            const int damping, \
+                                            const enum CdefEdgeFlags edges \
+                                            HIGHBD_DECL_SUFFIX) \
+{ \
+    cdef_filter_block_c(dst, stride, left, top, bottom, \
+                        pri_strength, sec_strength, dir, damping, w, h, edges HIGHBD_TAIL_SUFFIX); \
+}
+
+cdef_fn(4, 4);
+cdef_fn(4, 8);
+cdef_fn(8, 8);
+
+static int cdef_find_dir_c(const pixel *img, const ptrdiff_t stride,
+                           unsigned *const var HIGHBD_DECL_SUFFIX)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    int partial_sum_hv[2][8] = { { 0 } };
+    int partial_sum_diag[2][15] = { { 0 } };
+    int partial_sum_alt[4][11] = { { 0 } };
+
+    for (int y = 0; y < 8; y++) {
+        for (int x = 0; x < 8; x++) {
+            const int px = (img[x] >> bitdepth_min_8) - 128;
+
+            partial_sum_diag[0][     y       +  x      ] += px;
+            partial_sum_alt [0][     y       + (x >> 1)] += px;
+            partial_sum_hv  [0][     y                 ] += px;
+            partial_sum_alt [1][3 +  y       - (x >> 1)] += px;
+            partial_sum_diag[1][7 +  y       -  x      ] += px;
+            partial_sum_alt [2][3 - (y >> 1) +  x      ] += px;
+            partial_sum_hv  [1][                x      ] += px;
+            partial_sum_alt [3][    (y >> 1) +  x      ] += px;
+        }
+        img += PXSTRIDE(stride);
+    }
+
+    unsigned cost[8] = { 0 };
+    for (int n = 0; n < 8; n++) {
+        cost[2] += partial_sum_hv[0][n] * partial_sum_hv[0][n];
+        cost[6] += partial_sum_hv[1][n] * partial_sum_hv[1][n];
+    }
+    cost[2] *= 105;
+    cost[6] *= 105;
+
+    static const uint16_t div_table[7] = { 840, 420, 280, 210, 168, 140, 120 };
+    for (int n = 0; n < 7; n++) {
+        const int d = div_table[n];
+        cost[0] += (partial_sum_diag[0][n]      * partial_sum_diag[0][n] +
+                    partial_sum_diag[0][14 - n] * partial_sum_diag[0][14 - n]) * d;
+        cost[4] += (partial_sum_diag[1][n]      * partial_sum_diag[1][n] +
+                    partial_sum_diag[1][14 - n] * partial_sum_diag[1][14 - n]) * d;
+    }
+    cost[0] += partial_sum_diag[0][7] * partial_sum_diag[0][7] * 105;
+    cost[4] += partial_sum_diag[1][7] * partial_sum_diag[1][7] * 105;
+
+    for (int n = 0; n < 4; n++) {
+        unsigned *const cost_ptr = &cost[n * 2 + 1];
+        for (int m = 0; m < 5; m++)
+            *cost_ptr += partial_sum_alt[n][3 + m] * partial_sum_alt[n][3 + m];
+        *cost_ptr *= 105;
+        for (int m = 0; m < 3; m++) {
+            const int d = div_table[2 * m + 1];
+            *cost_ptr += (partial_sum_alt[n][m]      * partial_sum_alt[n][m] +
+                          partial_sum_alt[n][10 - m] * partial_sum_alt[n][10 - m]) * d;
+        }
+    }
+
+    int best_dir = 0;
+    unsigned best_cost = cost[0];
+    for (int n = 1; n < 8; n++) {
+        if (cost[n] > best_cost) {
+            best_cost = cost[n];
+            best_dir = n;
+        }
+    }
+
+    *var = (best_cost - (cost[best_dir ^ 4])) >> 10;
+    return best_dir;
+}
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/cdef.h"
+#elif ARCH_PPC64LE
+#include "src/ppc/cdef.h"
+#elif ARCH_RISCV
+#include "src/riscv/cdef.h"
+#elif ARCH_X86
+#include "src/x86/cdef.h"
+#elif ARCH_LOONGARCH64
+#include "src/loongarch/cdef.h"
+#endif
+#endif
+
+COLD void bitfn(dav1d_cdef_dsp_init)(Dav1dCdefDSPContext *const c) {
+    c->dir = cdef_find_dir_c;
+    c->fb[0] = cdef_filter_block_8x8_c;
+    c->fb[1] = cdef_filter_block_4x8_c;
+    c->fb[2] = cdef_filter_block_4x4_c;
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+    cdef_dsp_init_arm(c);
+#elif ARCH_PPC64LE
+    cdef_dsp_init_ppc(c);
+#elif ARCH_RISCV
+    cdef_dsp_init_riscv(c);
+#elif ARCH_X86
+    cdef_dsp_init_x86(c);
+#elif ARCH_LOONGARCH64
+    cdef_dsp_init_loongarch(c);
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/cdf.c b/media/libdav1d/src/src/cdf.c
new file mode 100644
index 0000000000..b17b8dfc95
--- /dev/null
+++ b/media/libdav1d/src/src/cdf.c
@@ -0,0 +1,4065 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/frame.h"
+
+#include "src/internal.h"
+#include "src/tables.h"
+
+#define CDF1(x) (32768-(x))
+
+#define CDF2(a,b) \
+    CDF1(a), CDF1(b)
+#define CDF3(a,b,c) \
+    CDF1(a), CDF2(b,c)
+#define CDF4(a,b,c,d) \
+    CDF1(a), CDF3(b,c,d)
+#define CDF5(a,b,c,d,e) \
+    CDF1(a), CDF4(b,c,d,e)
+#define CDF6(a,b,c,d,e,f) \
+    CDF1(a), CDF5(b,c,d,e,f)
+#define CDF7(a,b,c,d,e,f,g) \
+    CDF1(a), CDF6(b,c,d,e,f,g)
+#define CDF8(a,b,c,d,e,f,g,h) \
+    CDF1(a), CDF7(b,c,d,e,f,g,h)
+#define CDF9(a,b,c,d,e,f,g,h,i) \
+    CDF1(a), CDF8(b,c,d,e,f,g,h,i)
+#define CDF10(a,b,c,d,e,f,g,h,i,j) \
+    CDF1(a), CDF9(b,c,d,e,f,g,h,i,j)
+#define CDF11(a,b,c,d,e,f,g,h,i,j,k) \
+    CDF1(a), CDF10(b,c,d,e,f,g,h,i,j,k)
+#define CDF12(a,b,c,d,e,f,g,h,i,j,k,l) \
+    CDF1(a), CDF11(b,c,d,e,f,g,h,i,j,k,l)
+#define CDF13(a,b,c,d,e,f,g,h,i,j,k,l,m) \
+    CDF1(a), CDF12(b,c,d,e,f,g,h,i,j,k,l,m)
+#define CDF14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) \
+    CDF1(a), CDF13(b,c,d,e,f,g,h,i,j,k,l,m,n)
+#define CDF15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) \
+    CDF1(a), CDF14(b,c,d,e,f,g,h,i,j,k,l,m,n,o)
+
+typedef struct CdfDefaultContext {
+    CdfModeContext m;
+    struct {
+        CdfMvComponent comp;
+        ALIGN(uint16_t joint[N_MV_JOINTS], 8);
+    } mv;
+    ALIGN(uint16_t kfym[5][5][N_INTRA_PRED_MODES + 3], 32);
+} CdfDefaultContext;
+
+static const CdfDefaultContext default_cdf = {
+    .m  = {
+        .y_mode = {
+            { CDF12(22801, 23489, 24293, 24756, 25601, 26123,
+                    26606, 27418, 27945, 29228, 29685, 30349) },
+            { CDF12(18673, 19845, 22631, 23318, 23950, 24649,
+                    25527, 27364, 28152, 29701, 29984, 30852) },
+            { CDF12(19770, 20979, 23396, 23939, 24241, 24654,
+                    25136, 27073, 27830, 29360, 29730, 30659) },
+            { CDF12(20155, 21301, 22838, 23178, 23261, 23533,
+                    23703, 24804, 25352, 26575, 27016, 28049) },
+        }, .use_filter_intra = {
+            [BS_4x4]     = { CDF1( 4621) },
+            [BS_4x8]     = { CDF1( 6743) },
+            [BS_8x4]     = { CDF1( 5893) },
+            [BS_8x8]     = { CDF1( 7866) },
+            [BS_8x16]    = { CDF1(12551) },
+            [BS_16x8]    = { CDF1( 9394) },
+            [BS_16x16]   = { CDF1(12408) },
+            [BS_16x32]   = { CDF1(14301) },
+            [BS_32x16]   = { CDF1(12756) },
+            [BS_32x32]   = { CDF1(22343) },
+            [BS_32x64]   = { CDF1(16384) },
+            [BS_64x32]   = { CDF1(16384) },
+            [BS_64x64]   = { CDF1(16384) },
+            [BS_64x128]  = { CDF1(16384) },
+            [BS_128x64]  = { CDF1(16384) },
+            [BS_128x128] = { CDF1(16384) },
+            [BS_4x16]    = { CDF1(12770) },
+            [BS_16x4]    = { CDF1(10368) },
+            [BS_8x32]    = { CDF1(20229) },
+            [BS_32x8]    = { CDF1(18101) },
+            [BS_16x64]   = { CDF1(16384) },
+            [BS_64x16]   = { CDF1(16384) },
+        }, .filter_intra = {
+            CDF4(8949, 12776, 17211, 29558),
+        }, .uv_mode = {
+            {
+                { CDF12(22631, 24152, 25378, 25661, 25986, 26520,
+                        27055, 27923, 28244, 30059, 30941, 31961) },
+                { CDF12( 9513, 26881, 26973, 27046, 27118, 27664,
+                        27739, 27824, 28359, 29505, 29800, 31796) },
+                { CDF12( 9845,  9915, 28663, 28704, 28757, 28780,
+                        29198, 29822, 29854, 30764, 31777, 32029) },
+                { CDF12(13639, 13897, 14171, 25331, 25606, 25727,
+                        25953, 27148, 28577, 30612, 31355, 32493) },
+                { CDF12( 9764,  9835,  9930,  9954, 25386, 27053,
+                        27958, 28148, 28243, 31101, 31744, 32363) },
+                { CDF12(11825, 13589, 13677, 13720, 15048, 29213,
+                        29301, 29458, 29711, 31161, 31441, 32550) },
+                { CDF12(14175, 14399, 16608, 16821, 17718, 17775,
+                        28551, 30200, 30245, 31837, 32342, 32667) },
+                { CDF12(12885, 13038, 14978, 15590, 15673, 15748,
+                        16176, 29128, 29267, 30643, 31961, 32461) },
+                { CDF12(12026, 13661, 13874, 15305, 15490, 15726,
+                        15995, 16273, 28443, 30388, 30767, 32416) },
+                { CDF12(19052, 19840, 20579, 20916, 21150, 21467,
+                        21885, 22719, 23174, 28861, 30379, 32175) },
+                { CDF12(18627, 19649, 20974, 21219, 21492, 21816,
+                        22199, 23119, 23527, 27053, 31397, 32148) },
+                { CDF12(17026, 19004, 19997, 20339, 20586, 21103,
+                        21349, 21907, 22482, 25896, 26541, 31819) },
+                { CDF12(12124, 13759, 14959, 14992, 15007, 15051,
+                        15078, 15166, 15255, 15753, 16039, 16606) },
+            }, {
+                { CDF13(10407, 11208, 12900, 13181, 13823, 14175, 14899,
+                        15656, 15986, 20086, 20995, 22455, 24212) },
+                { CDF13( 4532, 19780, 20057, 20215, 20428, 21071, 21199,
+                        21451, 22099, 24228, 24693, 27032, 29472) },
+                { CDF13( 5273,  5379, 20177, 20270, 20385, 20439, 20949,
+                        21695, 21774, 23138, 24256, 24703, 26679) },
+                { CDF13( 6740,  7167,  7662, 14152, 14536, 14785, 15034,
+                        16741, 18371, 21520, 22206, 23389, 24182) },
+                { CDF13( 4987,  5368,  5928,  6068, 19114, 20315, 21857,
+                        22253, 22411, 24911, 25380, 26027, 26376) },
+                { CDF13( 5370,  6889,  7247,  7393,  9498, 21114, 21402,
+                        21753, 21981, 24780, 25386, 26517, 27176) },
+                { CDF13( 4816,  4961,  7204,  7326,  8765,  8930, 20169,
+                        20682, 20803, 23188, 23763, 24455, 24940) },
+                { CDF13( 6608,  6740,  8529,  9049,  9257,  9356,  9735,
+                        18827, 19059, 22336, 23204, 23964, 24793) },
+                { CDF13( 5998,  7419,  7781,  8933,  9255,  9549,  9753,
+                        10417, 18898, 22494, 23139, 24764, 25989) },
+                { CDF13(10660, 11298, 12550, 12957, 13322, 13624, 14040,
+                        15004, 15534, 20714, 21789, 23443, 24861) },
+                { CDF13(10522, 11530, 12552, 12963, 13378, 13779, 14245,
+                        15235, 15902, 20102, 22696, 23774, 25838) },
+                { CDF13(10099, 10691, 12639, 13049, 13386, 13665, 14125,
+                        15163, 15636, 19676, 20474, 23519, 25208) },
+                { CDF13( 3144,  5087,  7382,  7504,  7593,  7690,  7801,
+                         8064,  8232,  9248,  9875, 10521, 29048) },
+            },
+        }, .angle_delta = {
+            { CDF6( 2180,  5032,  7567, 22776, 26989, 30217) },
+            { CDF6( 2301,  5608,  8801, 23487, 26974, 30330) },
+            { CDF6( 3780, 11018, 13699, 19354, 23083, 31286) },
+            { CDF6( 4581, 11226, 15147, 17138, 21834, 28397) },
+            { CDF6( 1737, 10927, 14509, 19588, 22745, 28823) },
+            { CDF6( 2664, 10176, 12485, 17650, 21600, 30495) },
+            { CDF6( 2240, 11096, 15453, 20341, 22561, 28917) },
+            { CDF6( 3605, 10428, 12459, 17676, 21244, 30655) },
+        }, .filter = {
+            {
+                { CDF2(31935, 32720) }, { CDF2( 5568, 32719) },
+                { CDF2(  422,  2938) }, { CDF2(28244, 32608) },
+                { CDF2(31206, 31953) }, { CDF2( 4862, 32121) },
+                { CDF2(  770,  1152) }, { CDF2(20889, 25637) },
+            }, {
+                { CDF2(31910, 32724) }, { CDF2( 4120, 32712) },
+                { CDF2(  305,  2247) }, { CDF2(27403, 32636) },
+                { CDF2(31022, 32009) }, { CDF2( 2963, 32093) },
+                { CDF2(  601,   943) }, { CDF2(14969, 21398) },
+            },
+        }, .newmv_mode = {
+            { CDF1(24035) }, { CDF1(16630) }, { CDF1(15339) },
+            { CDF1( 8386) }, { CDF1(12222) }, { CDF1( 4676) },
+        }, .globalmv_mode = {
+            { CDF1( 2175) }, { CDF1( 1054) },
+        }, .refmv_mode = {
+            { CDF1(23974) }, { CDF1(24188) }, { CDF1(17848) },
+            { CDF1(28622) }, { CDF1(24312) }, { CDF1(19923) },
+        }, .drl_bit = {
+            { CDF1(13104) }, { CDF1(24560) }, { CDF1(18945) },
+        }, .comp_inter_mode = {
+            { CDF7( 7760, 13823, 15808, 17641, 19156, 20666, 26891) },
+            { CDF7(10730, 19452, 21145, 22749, 24039, 25131, 28724) },
+            { CDF7(10664, 20221, 21588, 22906, 24295, 25387, 28436) },
+            { CDF7(13298, 16984, 20471, 24182, 25067, 25736, 26422) },
+            { CDF7(18904, 23325, 25242, 27432, 27898, 28258, 30758) },
+            { CDF7(10725, 17454, 20124, 22820, 24195, 25168, 26046) },
+            { CDF7(17125, 24273, 25814, 27492, 28214, 28704, 30592) },
+            { CDF7(13046, 23214, 24505, 25942, 27435, 28442, 29330) },
+        }, .intra = {
+            { CDF1(  806) }, { CDF1(16662) }, { CDF1(20186) },
+            { CDF1(26538) },
+        }, .comp = {
+            { CDF1(26828) }, { CDF1(24035) }, { CDF1(12031) },
+            { CDF1(10640) }, { CDF1( 2901) },
+        }, .comp_dir = {
+            { CDF1( 1198) }, { CDF1( 2070) }, { CDF1( 9166) },
+            { CDF1( 7499) }, { CDF1(22475) },
+        }, .jnt_comp = {
+            { CDF1(18244) }, { CDF1(12865) }, { CDF1( 7053) },
+            { CDF1(13259) }, { CDF1( 9334) }, { CDF1( 4644) },
+        }, .mask_comp = {
+            { CDF1(26607) }, { CDF1(22891) }, { CDF1(18840) },
+            { CDF1(24594) }, { CDF1(19934) }, { CDF1(22674) },
+        }, .wedge_comp = {
+            { CDF1(23431) }, { CDF1(13171) }, { CDF1(11470) },
+            { CDF1( 9770) }, { CDF1( 9100) }, { CDF1( 8233) },
+            { CDF1( 6172) }, { CDF1(11820) }, { CDF1( 7701) },
+        }, .wedge_idx = {
+            { CDF15( 2438,  4440,  6599,  8663, 11005, 12874, 15751, 18094,
+                    20359, 22362, 24127, 25702, 27752, 29450, 31171) },
+            { CDF15(  806,  3266,  6005,  6738,  7218,  7367,  7771, 14588,
+                    16323, 17367, 18452, 19422, 22839, 26127, 29629) },
+            { CDF15( 2779,  3738,  4683,  7213,  7775,  8017,  8655, 14357,
+                    17939, 21332, 24520, 27470, 29456, 30529, 31656) },
+            { CDF15( 1684,  3625,  5675,  7108,  9302, 11274, 14429, 17144,
+                    19163, 20961, 22884, 24471, 26719, 28714, 30877) },
+            { CDF15( 1142,  3491,  6277,  7314,  8089,  8355,  9023, 13624,
+                    15369, 16730, 18114, 19313, 22521, 26012, 29550) },
+            { CDF15( 2742,  4195,  5727,  8035,  8980,  9336, 10146, 14124,
+                    17270, 20533, 23434, 25972, 27944, 29570, 31416) },
+            { CDF15( 1727,  3948,  6101,  7796,  9841, 12344, 15766, 18944,
+                    20638, 22038, 23963, 25311, 26988, 28766, 31012) },
+            { CDF15(  154,   987,  1925,  2051,  2088,  2111,  2151, 23033,
+                    23703, 24284, 24985, 25684, 27259, 28883, 30911) },
+            { CDF15( 1135,  1322,  1493,  2635,  2696,  2737,  2770, 21016,
+                    22935, 25057, 27251, 29173, 30089, 30960, 31933) },
+        }, .interintra = {
+            { CDF1(16384) }, { CDF1(26887) }, { CDF1(27597) },
+            { CDF1(30237) },
+        }, .interintra_mode = {
+            { CDF3(8192, 16384, 24576) },
+            { CDF3(1875, 11082, 27332) },
+            { CDF3(2473,  9996, 26388) },
+            { CDF3(4238, 11537, 25926) },
+        }, .interintra_wedge = {
+            { CDF1(20036) }, { CDF1(24957) }, { CDF1(26704) },
+            { CDF1(27530) }, { CDF1(29564) }, { CDF1(29444) },
+            { CDF1(26872) },
+        }, .ref = {
+            { { CDF1( 4897) }, { CDF1(16973) }, { CDF1(29744) } },
+            { { CDF1( 1555) }, { CDF1(16751) }, { CDF1(30279) } },
+            { { CDF1( 4236) }, { CDF1(19647) }, { CDF1(31194) } },
+            { { CDF1( 8650) }, { CDF1(24773) }, { CDF1(31895) } },
+            { { CDF1(  904) }, { CDF1(11014) }, { CDF1(26875) } },
+            { { CDF1( 1444) }, { CDF1(15087) }, { CDF1(30304) } },
+        }, .comp_fwd_ref = {
+            { { CDF1( 4946) }, { CDF1(19891) }, { CDF1(30731) } },
+            { { CDF1( 9468) }, { CDF1(22441) }, { CDF1(31059) } },
+            { { CDF1( 1503) }, { CDF1(15160) }, { CDF1(27544) } },
+        }, .comp_bwd_ref = {
+            { { CDF1( 2235) }, { CDF1(17182) }, { CDF1(30606) } },
+            { { CDF1( 1423) }, { CDF1(15175) }, { CDF1(30489) } },
+        }, .comp_uni_ref = {
+            { { CDF1( 5284) }, { CDF1(23152) }, { CDF1(31774) } },
+            { { CDF1( 3865) }, { CDF1(14173) }, { CDF1(25120) } },
+            { { CDF1( 3128) }, { CDF1(15270) }, { CDF1(26710) } },
+        }, .txsz = {
+            {
+                { CDF1(19968) }, { CDF1(19968) }, { CDF1(24320) },
+            }, {
+                { CDF2(12272, 30172) }, { CDF2(12272, 30172) },
+                { CDF2(18677, 30848) },
+            }, {
+                { CDF2(12986, 15180) }, { CDF2(12986, 15180) },
+                { CDF2(24302, 25602) },
+            }, {
+                { CDF2( 5782, 11475) }, { CDF2( 5782, 11475) },
+                { CDF2(16803, 22759) },
+            },
+        }, .txpart = {
+            { { CDF1(28581) }, { CDF1(23846) }, { CDF1(20847) } },
+            { { CDF1(24315) }, { CDF1(18196) }, { CDF1(12133) } },
+            { { CDF1(18791) }, { CDF1(10887) }, { CDF1(11005) } },
+            { { CDF1(27179) }, { CDF1(20004) }, { CDF1(11281) } },
+            { { CDF1(26549) }, { CDF1(19308) }, { CDF1(14224) } },
+            { { CDF1(28015) }, { CDF1(21546) }, { CDF1(14400) } },
+            { { CDF1(28165) }, { CDF1(22401) }, { CDF1(16088) } },
+        }, .txtp_inter1 = {
+            { CDF15( 4458,  5560,  7695,  9709, 13330, 14789, 17537, 20266,
+                    21504, 22848, 23934, 25474, 27727, 28915, 30631) },
+            { CDF15( 1645,  2573,  4778,  5711,  7807,  8622, 10522, 15357,
+                    17674, 20408, 22517, 25010, 27116, 28856, 30749) },
+        }, .txtp_inter2 = {
+            CDF11(  770,  2421,  5225, 12907, 15819, 18927,
+                  21561, 24089, 26595, 28526, 30529)
+        }, .txtp_inter3 = {
+            { CDF1(16384) }, { CDF1( 4167) }, { CDF1( 1998) }, { CDF1(  748) },
+        }, .txtp_intra1 = {
+            {
+                { CDF6( 1535,  8035,  9461, 12751, 23467, 27825) },
+                { CDF6(  564,  3335,  9709, 10870, 18143, 28094) },
+                { CDF6(  672,  3247,  3676, 11982, 19415, 23127) },
+                { CDF6( 5279, 13885, 15487, 18044, 23527, 30252) },
+                { CDF6( 4423,  6074,  7985, 10416, 25693, 29298) },
+                { CDF6( 1486,  4241,  9460, 10662, 16456, 27694) },
+                { CDF6(  439,  2838,  3522,  6737, 18058, 23754) },
+                { CDF6( 1190,  4233,  4855, 11670, 20281, 24377) },
+                { CDF6( 1045,  4312,  8647, 10159, 18644, 29335) },
+                { CDF6(  202,  3734,  4747,  7298, 17127, 24016) },
+                { CDF6(  447,  4312,  6819,  8884, 16010, 23858) },
+                { CDF6(  277,  4369,  5255,  8905, 16465, 22271) },
+                { CDF6( 3409,  5436, 10599, 15599, 19687, 24040) },
+            }, {
+                { CDF6( 1870, 13742, 14530, 16498, 23770, 27698) },
+                { CDF6(  326,  8796, 14632, 15079, 19272, 27486) },
+                { CDF6(  484,  7576,  7712, 14443, 19159, 22591) },
+                { CDF6( 1126, 15340, 15895, 17023, 20896, 30279) },
+                { CDF6(  655,  4854,  5249,  5913, 22099, 27138) },
+                { CDF6( 1299,  6458,  8885,  9290, 14851, 25497) },
+                { CDF6(  311,  5295,  5552,  6885, 16107, 22672) },
+                { CDF6(  883,  8059,  8270, 11258, 17289, 21549) },
+                { CDF6(  741,  7580,  9318, 10345, 16688, 29046) },
+                { CDF6(  110,  7406,  7915,  9195, 16041, 23329) },
+                { CDF6(  363,  7974,  9357, 10673, 15629, 24474) },
+                { CDF6(  153,  7647,  8112,  9936, 15307, 19996) },
+                { CDF6( 3511,  6332, 11165, 15335, 19323, 23594) },
+            },
+        }, .txtp_intra2 = {
+            {
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+            }, {
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+                { CDF4( 6554, 13107, 19661, 26214) },
+            }, {
+                { CDF4( 1127, 12814, 22772, 27483) },
+                { CDF4(  145,  6761, 11980, 26667) },
+                { CDF4(  362,  5887, 11678, 16725) },
+                { CDF4(  385, 15213, 18587, 30693) },
+                { CDF4(   25,  2914, 23134, 27903) },
+                { CDF4(   60,  4470, 11749, 23991) },
+                { CDF4(   37,  3332, 14511, 21448) },
+                { CDF4(  157,  6320, 13036, 17439) },
+                { CDF4(  119,  6719, 12906, 29396) },
+                { CDF4(   47,  5537, 12576, 21499) },
+                { CDF4(  269,  6076, 11258, 23115) },
+                { CDF4(   83,  5615, 12001, 17228) },
+                { CDF4( 1968,  5556, 12023, 18547) },
+            },
+        }, .skip = {
+            { CDF1(31671) }, { CDF1(16515) }, { CDF1( 4576) },
+        }, .skip_mode = {
+            { CDF1(32621) }, { CDF1(20708) }, { CDF1( 8127) },
+        }, .partition = {
+            {
+                // 128x128 -> 64x64
+                { CDF7(27899, 28219, 28529, 32484, 32539, 32619, 32639) },
+                { CDF7( 6607,  6990,  8268, 32060, 32219, 32338, 32371) },
+                { CDF7( 5429,  6676,  7122, 32027, 32227, 32531, 32582) },
+                { CDF7(  711,   966,  1172, 32448, 32538, 32617, 32664) },
+            }, {
+                // 64x64 -> 32x32
+                { CDF9(20137, 21547, 23078, 29566, 29837,
+                       30261, 30524, 30892, 31724) },
+                { CDF9( 6732,  7490,  9497, 27944, 28250,
+                       28515, 28969, 29630, 30104) },
+                { CDF9( 5945,  7663,  8348, 28683, 29117,
+                       29749, 30064, 30298, 32238) },
+                { CDF9(  870,  1212,  1487, 31198, 31394,
+                       31574, 31743, 31881, 32332) },
+            }, {
+                // 32x32 -> 16x16
+                { CDF9(18462, 20920, 23124, 27647, 28227,
+                       29049, 29519, 30178, 31544) },
+                { CDF9( 7689,  9060, 12056, 24992, 25660,
+                       26182, 26951, 28041, 29052) },
+                { CDF9( 6015,  9009, 10062, 24544, 25409,
+                       26545, 27071, 27526, 32047) },
+                { CDF9( 1394,  2208,  2796, 28614, 29061,
+                       29466, 29840, 30185, 31899) },
+            }, {
+                // 16x16 -> 8x8
+                { CDF9(15597, 20929, 24571, 26706, 27664,
+                       28821, 29601, 30571, 31902) },
+                { CDF9( 7925, 11043, 16785, 22470, 23971,
+                       25043, 26651, 28701, 29834) },
+                { CDF9( 5414, 13269, 15111, 20488, 22360,
+                       24500, 25537, 26336, 32117) },
+                { CDF9( 2662,  6362,  8614, 20860, 23053,
+                       24778, 26436, 27829, 31171) },
+            }, {
+                // 8x8 -> 4x4 only supports the four legacy partition types
+                { CDF3(19132, 25510, 30392) },
+                { CDF3(13928, 19855, 28540) },
+                { CDF3(12522, 23679, 28629) },
+                { CDF3( 9896, 18783, 25853) },
+            },
+        }, .seg_pred = {
+            { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+        }, .seg_id = {
+            { CDF7( 5622,  7893, 16093, 18233, 27809, 28373, 32533) },
+            { CDF7(14274, 18230, 22557, 24935, 29980, 30851, 32344) },
+            { CDF7(27527, 28487, 28723, 28890, 32397, 32647, 32679) },
+        }, .cfl_sign = {
+            CDF7( 1418,  2123, 13340, 18405, 26972, 28343, 32294)
+        }, .cfl_alpha = {
+            { CDF15( 7637, 20719, 31401, 32481, 32657, 32688, 32692, 32696,
+                    32700, 32704, 32708, 32712, 32716, 32720, 32724) },
+            { CDF15(14365, 23603, 28135, 31168, 32167, 32395, 32487, 32573,
+                    32620, 32647, 32668, 32672, 32676, 32680, 32684) },
+            { CDF15(11532, 22380, 28445, 31360, 32349, 32523, 32584, 32649,
+                    32673, 32677, 32681, 32685, 32689, 32693, 32697) },
+            { CDF15(26990, 31402, 32282, 32571, 32692, 32696, 32700, 32704,
+                    32708, 32712, 32716, 32720, 32724, 32728, 32732) },
+            { CDF15(17248, 26058, 28904, 30608, 31305, 31877, 32126, 32321,
+                    32394, 32464, 32516, 32560, 32576, 32593, 32622) },
+            { CDF15(14738, 21678, 25779, 27901, 29024, 30302, 30980, 31843,
+                    32144, 32413, 32520, 32594, 32622, 32656, 32660) },
+        }, .restore_wiener = {
+            CDF1(11570)
+        }, .restore_sgrproj = {
+            CDF1(16855)
+        }, .restore_switchable = {
+            CDF2( 9413, 22581)
+        }, .delta_q = {
+            CDF3(28160, 32120, 32677)
+        }, .delta_lf = {
+            { CDF3(28160, 32120, 32677) },
+            { CDF3(28160, 32120, 32677) },
+            { CDF3(28160, 32120, 32677) },
+            { CDF3(28160, 32120, 32677) },
+            { CDF3(28160, 32120, 32677) },
+        }, .motion_mode = {
+            [BS_8x8]     = { CDF2( 7651, 24760) },
+            [BS_8x16]    = { CDF2( 4738, 24765) },
+            [BS_8x32]    = { CDF2(28799, 31390) },
+            [BS_16x8]    = { CDF2( 5391, 25528) },
+            [BS_16x16]   = { CDF2(19419, 26810) },
+            [BS_16x32]   = { CDF2( 5123, 23606) },
+            [BS_16x64]   = { CDF2(28973, 31594) },
+            [BS_32x8]    = { CDF2(26431, 30774) },
+            [BS_32x16]   = { CDF2(11606, 24308) },
+            [BS_32x32]   = { CDF2(26260, 29116) },
+            [BS_32x64]   = { CDF2(20360, 28062) },
+            [BS_64x16]   = { CDF2(29742, 31203) },
+            [BS_64x32]   = { CDF2(21679, 26830) },
+            [BS_64x64]   = { CDF2(29516, 30701) },
+            [BS_64x128]  = { CDF2(28898, 30397) },
+            [BS_128x64]  = { CDF2(30878, 31335) },
+            [BS_128x128] = { CDF2(32507, 32558) },
+        }, .obmc = {
+            [BS_8x8]     = { CDF1(10437) },
+            [BS_8x16]    = { CDF1( 9371) },
+            [BS_8x32]    = { CDF1(23664) },
+            [BS_16x8]    = { CDF1( 9301) },
+            [BS_16x16]   = { CDF1(17432) },
+            [BS_16x32]   = { CDF1(14423) },
+            [BS_16x64]   = { CDF1(24008) },
+            [BS_32x8]    = { CDF1(20901) },
+            [BS_32x16]   = { CDF1(15142) },
+            [BS_32x32]   = { CDF1(25817) },
+            [BS_32x64]   = { CDF1(22823) },
+            [BS_64x16]   = { CDF1(26879) },
+            [BS_64x32]   = { CDF1(22083) },
+            [BS_64x64]   = { CDF1(30128) },
+            [BS_64x128]  = { CDF1(31014) },
+            [BS_128x64]  = { CDF1(31560) },
+            [BS_128x128] = { CDF1(32638) },
+        }, .pal_y = {
+            { { CDF1(31676) }, { CDF1( 3419) }, { CDF1( 1261) } },
+            { { CDF1(31912) }, { CDF1( 2859) }, { CDF1(  980) } },
+            { { CDF1(31823) }, { CDF1( 3400) }, { CDF1(  781) } },
+            { { CDF1(32030) }, { CDF1( 3561) }, { CDF1(  904) } },
+            { { CDF1(32309) }, { CDF1( 7337) }, { CDF1( 1462) } },
+            { { CDF1(32265) }, { CDF1( 4015) }, { CDF1( 1521) } },
+            { { CDF1(32450) }, { CDF1( 7946) }, { CDF1(  129) } },
+        }, .pal_sz = {
+            {
+                { CDF6( 7952, 13000, 18149, 21478, 25527, 29241) },
+                { CDF6( 7139, 11421, 16195, 19544, 23666, 28073) },
+                { CDF6( 7788, 12741, 17325, 20500, 24315, 28530) },
+                { CDF6( 8271, 14064, 18246, 21564, 25071, 28533) },
+                { CDF6(12725, 19180, 21863, 24839, 27535, 30120) },
+                { CDF6( 9711, 14888, 16923, 21052, 25661, 27875) },
+                { CDF6(14940, 20797, 21678, 24186, 27033, 28999) },
+            }, {
+                { CDF6( 8713, 19979, 27128, 29609, 31331, 32272) },
+                { CDF6( 5839, 15573, 23581, 26947, 29848, 31700) },
+                { CDF6( 4426, 11260, 17999, 21483, 25863, 29430) },
+                { CDF6( 3228,  9464, 14993, 18089, 22523, 27420) },
+                { CDF6( 3768,  8886, 13091, 17852, 22495, 27207) },
+                { CDF6( 2464,  8451, 12861, 21632, 25525, 28555) },
+                { CDF6( 1269,  5435, 10433, 18963, 21700, 25865) },
+            },
+        }, .pal_uv = {
+            { CDF1(32461) }, { CDF1(21488) },
+        }, .color_map = {
+            { /* y */
+                {
+                    { CDF1(28710) }, { CDF1(16384) }, { CDF1(10553) },
+                    { CDF1(27036) }, { CDF1(31603) },
+                }, {
+                    { CDF2(27877, 30490) }, { CDF2(11532, 25697) },
+                    { CDF2( 6544, 30234) }, { CDF2(23018, 28072) },
+                    { CDF2(31915, 32385) },
+                }, {
+                    { CDF3(25572, 28046, 30045) },
+                    { CDF3( 9478, 21590, 27256) },
+                    { CDF3( 7248, 26837, 29824) },
+                    { CDF3(19167, 24486, 28349) },
+                    { CDF3(31400, 31825, 32250) },
+                }, {
+                    { CDF4(24779, 26955, 28576, 30282) },
+                    { CDF4( 8669, 20364, 24073, 28093) },
+                    { CDF4( 4255, 27565, 29377, 31067) },
+                    { CDF4(19864, 23674, 26716, 29530) },
+                    { CDF4(31646, 31893, 32147, 32426) },
+                }, {
+                    { CDF5(23132, 25407, 26970, 28435, 30073) },
+                    { CDF5( 7443, 17242, 20717, 24762, 27982) },
+                    { CDF5( 6300, 24862, 26944, 28784, 30671) },
+                    { CDF5(18916, 22895, 25267, 27435, 29652) },
+                    { CDF5(31270, 31550, 31808, 32059, 32353) },
+                }, {
+                    { CDF6(23105, 25199, 26464, 27684, 28931, 30318) },
+                    { CDF6( 6950, 15447, 18952, 22681, 25567, 28563) },
+                    { CDF6( 7560, 23474, 25490, 27203, 28921, 30708) },
+                    { CDF6(18544, 22373, 24457, 26195, 28119, 30045) },
+                    { CDF6(31198, 31451, 31670, 31882, 32123, 32391) },
+                }, {
+                    { CDF7(21689, 23883, 25163, 26352, 27506, 28827, 30195) },
+                    { CDF7( 6892, 15385, 17840, 21606, 24287, 26753, 29204) },
+                    { CDF7( 5651, 23182, 25042, 26518, 27982, 29392, 30900) },
+                    { CDF7(19349, 22578, 24418, 25994, 27524, 29031, 30448) },
+                    { CDF7(31028, 31270, 31504, 31705, 31927, 32153, 32392) },
+                },
+            }, { /* uv */
+                {
+                    { CDF1(29089) }, { CDF1(16384) }, { CDF1( 8713) },
+                    { CDF1(29257) }, { CDF1(31610) },
+                }, {
+                    { CDF2(25257, 29145) }, { CDF2(12287, 27293) },
+                    { CDF2( 7033, 27960) }, { CDF2(20145, 25405) },
+                    { CDF2(30608, 31639) },
+                }, {
+                    { CDF3(24210, 27175, 29903) },
+                    { CDF3( 9888, 22386, 27214) },
+                    { CDF3( 5901, 26053, 29293) },
+                    { CDF3(18318, 22152, 28333) },
+                    { CDF3(30459, 31136, 31926) },
+                }, {
+                    { CDF4(22980, 25479, 27781, 29986) },
+                    { CDF4( 8413, 21408, 24859, 28874) },
+                    { CDF4( 2257, 29449, 30594, 31598) },
+                    { CDF4(19189, 21202, 25915, 28620) },
+                    { CDF4(31844, 32044, 32281, 32518) },
+                }, {
+                    { CDF5(22217, 24567, 26637, 28683, 30548) },
+                    { CDF5( 7307, 16406, 19636, 24632, 28424) },
+                    { CDF5( 4441, 25064, 26879, 28942, 30919) },
+                    { CDF5(17210, 20528, 23319, 26750, 29582) },
+                    { CDF5(30674, 30953, 31396, 31735, 32207) },
+                }, {
+                    { CDF6(21239, 23168, 25044, 26962, 28705, 30506) },
+                    { CDF6( 6545, 15012, 18004, 21817, 25503, 28701) },
+                    { CDF6( 3448, 26295, 27437, 28704, 30126, 31442) },
+                    { CDF6(15889, 18323, 21704, 24698, 26976, 29690) },
+                    { CDF6(30988, 31204, 31479, 31734, 31983, 32325) },
+                }, {
+                    { CDF7(21442, 23288, 24758, 26246, 27649, 28980, 30563) },
+                    { CDF7( 5863, 14933, 17552, 20668, 23683, 26411, 29273) },
+                    { CDF7( 3415, 25810, 26877, 27990, 29223, 30394, 31618) },
+                    { CDF7(17965, 20084, 22232, 23974, 26274, 28402, 30390) },
+                    { CDF7(31190, 31329, 31516, 31679, 31825, 32026, 32322) },
+                },
+            },
+        }, .intrabc = {
+            CDF1(30531)
+        },
+    }, .mv = {
+        .comp = {
+            .classes = {
+                CDF10(28672, 30976, 31858, 32320, 32551,
+                      32656, 32740, 32757, 32762, 32767)
+            }, .class0 = {
+                CDF1(27648)
+            }, .classN = {
+                { CDF1(17408) }, { CDF1(17920) }, { CDF1(18944) },
+                { CDF1(20480) }, { CDF1(22528) }, { CDF1(24576) },
+                { CDF1(28672) }, { CDF1(29952) }, { CDF1(29952) },
+                { CDF1(30720) },
+            }, .class0_fp = {
+                { CDF3(16384, 24576, 26624) },
+                { CDF3(12288, 21248, 24128) },
+            }, .classN_fp = {
+                CDF3( 8192, 17408, 21248)
+            }, .class0_hp = {
+                CDF1(20480)
+            }, .classN_hp = {
+                CDF1(16384)
+            }, .sign = {
+                CDF1(16384)
+            },
+        }, .joint = {
+            CDF3( 4096, 11264, 19328)
+        },
+    }, .kfym = {
+        {
+            { CDF12(15588, 17027, 19338, 20218, 20682, 21110,
+                    21825, 23244, 24189, 28165, 29093, 30466) },
+            { CDF12(12016, 18066, 19516, 20303, 20719, 21444,
+                    21888, 23032, 24434, 28658, 30172, 31409) },
+            { CDF12(10052, 10771, 22296, 22788, 23055, 23239,
+                    24133, 25620, 26160, 29336, 29929, 31567) },
+            { CDF12(14091, 15406, 16442, 18808, 19136, 19546,
+                    19998, 22096, 24746, 29585, 30958, 32462) },
+            { CDF12(12122, 13265, 15603, 16501, 18609, 20033,
+                    22391, 25583, 26437, 30261, 31073, 32475) },
+        }, {
+            { CDF12(10023, 19585, 20848, 21440, 21832, 22760,
+                    23089, 24023, 25381, 29014, 30482, 31436) },
+            { CDF12( 5983, 24099, 24560, 24886, 25066, 25795,
+                    25913, 26423, 27610, 29905, 31276, 31794) },
+            { CDF12( 7444, 12781, 20177, 20728, 21077, 21607,
+                    22170, 23405, 24469, 27915, 29090, 30492) },
+            { CDF12( 8537, 14689, 15432, 17087, 17408, 18172,
+                    18408, 19825, 24649, 29153, 31096, 32210) },
+            { CDF12( 7543, 14231, 15496, 16195, 17905, 20717,
+                    21984, 24516, 26001, 29675, 30981, 31994) },
+        }, {
+            { CDF12(12613, 13591, 21383, 22004, 22312, 22577,
+                    23401, 25055, 25729, 29538, 30305, 32077) },
+            { CDF12( 9687, 13470, 18506, 19230, 19604, 20147,
+                    20695, 22062, 23219, 27743, 29211, 30907) },
+            { CDF12( 6183,  6505, 26024, 26252, 26366, 26434,
+                    27082, 28354, 28555, 30467, 30794, 32086) },
+            { CDF12(10718, 11734, 14954, 17224, 17565, 17924,
+                    18561, 21523, 23878, 28975, 30287, 32252) },
+            { CDF12( 9194,  9858, 16501, 17263, 18424, 19171,
+                    21563, 25961, 26561, 30072, 30737, 32463) },
+        }, {
+            { CDF12(12602, 14399, 15488, 18381, 18778, 19315,
+                    19724, 21419, 25060, 29696, 30917, 32409) },
+            { CDF12( 8203, 13821, 14524, 17105, 17439, 18131,
+                    18404, 19468, 25225, 29485, 31158, 32342) },
+            { CDF12( 8451,  9731, 15004, 17643, 18012, 18425,
+                    19070, 21538, 24605, 29118, 30078, 32018) },
+            { CDF12( 7714,  9048,  9516, 16667, 16817, 16994,
+                    17153, 18767, 26743, 30389, 31536, 32528) },
+            { CDF12( 8843, 10280, 11496, 15317, 16652, 17943,
+                    19108, 22718, 25769, 29953, 30983, 32485) },
+        }, {
+            { CDF12(12578, 13671, 15979, 16834, 19075, 20913,
+                    22989, 25449, 26219, 30214, 31150, 32477) },
+            { CDF12( 9563, 13626, 15080, 15892, 17756, 20863,
+                    22207, 24236, 25380, 29653, 31143, 32277) },
+            { CDF12( 8356,  8901, 17616, 18256, 19350, 20106,
+                    22598, 25947, 26466, 29900, 30523, 32261) },
+            { CDF12(10835, 11815, 13124, 16042, 17018, 18039,
+                    18947, 22753, 24615, 29489, 30883, 32482) },
+            { CDF12( 7618,  8288,  9859, 10509, 15386, 18657,
+                    22903, 28776, 29180, 31355, 31802, 32593) },
+        },
+    },
+};
+
+static const CdfCoefContext default_coef_cdf[4] = {
+    [0] = {
+        .skip = {
+            {
+                { CDF1(31849) }, { CDF1( 5892) }, { CDF1(12112) },
+                { CDF1(21935) }, { CDF1(20289) }, { CDF1(27473) },
+                { CDF1(32487) }, { CDF1( 7654) }, { CDF1(19473) },
+                { CDF1(29984) }, { CDF1( 9961) }, { CDF1(30242) },
+                { CDF1(32117) },
+            }, {
+                { CDF1(31548) }, { CDF1( 1549) }, { CDF1(10130) },
+                { CDF1(16656) }, { CDF1(18591) }, { CDF1(26308) },
+                { CDF1(32537) }, { CDF1( 5403) }, { CDF1(18096) },
+                { CDF1(30003) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(29957) }, { CDF1( 5391) }, { CDF1(18039) },
+                { CDF1(23566) }, { CDF1(22431) }, { CDF1(25822) },
+                { CDF1(32197) }, { CDF1( 3778) }, { CDF1(15336) },
+                { CDF1(28981) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(17920) }, { CDF1( 1818) }, { CDF1( 7282) },
+                { CDF1(25273) }, { CDF1(10923) }, { CDF1(31554) },
+                { CDF1(32624) }, { CDF1( 1366) }, { CDF1(15628) },
+                { CDF1(30462) }, { CDF1(  146) }, { CDF1( 5132) },
+                { CDF1(31657) },
+            }, {
+                { CDF1( 6308) }, { CDF1(  117) }, { CDF1( 1638) },
+                { CDF1( 2161) }, { CDF1(16384) }, { CDF1(10923) },
+                { CDF1(30247) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            },
+        }, .eob_bin_16 = {
+            {
+                { CDF4(  840,  1039,  1980,  4895) },
+                { CDF4(  370,   671,  1883,  4471) },
+            }, {
+                { CDF4( 3247,  4950,  9688, 14563) },
+                { CDF4( 1904,  3354,  7763, 14647) },
+            },
+        }, .eob_bin_32 = {
+            {
+                { CDF5(  400,   520,   977,  2102,  6542) },
+                { CDF5(  210,   405,  1315,  3326,  7537) },
+            }, {
+                { CDF5( 2636,  4273,  7588, 11794, 20401) },
+                { CDF5( 1786,  3179,  6902, 11357, 19054) },
+            },
+        }, .eob_bin_64 = {
+            {
+                { CDF6(  329,   498,  1101,  1784,  3265,  7758) },
+                { CDF6(  335,   730,  1459,  5494,  8755, 12997) },
+            }, {
+                { CDF6( 3505,  5304, 10086, 13814, 17684, 23370) },
+                { CDF6( 1563,  2700,  4876, 10911, 14706, 22480) },
+            },
+        }, .eob_bin_128 = {
+            {
+                { CDF7(  219,   482,  1140,  2091,  3680,  6028, 12586) },
+                { CDF7(  371,   699,  1254,  4830,  9479, 12562, 17497) },
+            }, {
+                { CDF7( 5245,  7456, 12880, 15852, 20033, 23932, 27608) },
+                { CDF7( 2054,  3472,  5869, 14232, 18242, 20590, 26752) },
+            },
+        }, .eob_bin_256 = {
+            {
+                { CDF8(  310,   584,  1887,  3589,
+                        6168,  8611, 11352, 15652) },
+                { CDF8(  998,  1850,  2998,  5604,
+                       17341, 19888, 22899, 25583) },
+            }, {
+                { CDF8( 2520,  3240,  5952,  8870,
+                       12577, 17558, 19954, 24168) },
+                { CDF8( 2203,  4130,  7435, 10739,
+                       20652, 23681, 25609, 27261) },
+            },
+        }, .eob_bin_512 = {
+            { CDF9(  641,   983,  3707,  5430, 10234,
+                   14958, 18788, 23412, 26061) },
+            { CDF9( 5095,  6446,  9996, 13354, 16017,
+                   17986, 20919, 26129, 29140) },
+        }, .eob_bin_1024 = {
+            { CDF10(  393,   421,   751,  1623,  3160,
+                     6352, 13345, 18047, 22571, 25830) },
+            { CDF10( 1865,  1988,  2930,  4242, 10533,
+                    16538, 21354, 27255, 28546, 31784) },
+        }, .eob_hi_bit = {
+            {
+                {
+                    { CDF1(16961) }, { CDF1(17223) }, { CDF1( 7621) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(19069) }, { CDF1(22525) }, { CDF1(13377) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(20401) }, { CDF1(17025) }, { CDF1(12845) },
+                    { CDF1(12873) }, { CDF1(14094) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(20681) }, { CDF1(20701) }, { CDF1(15250) },
+                    { CDF1(15017) }, { CDF1(14928) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(23905) }, { CDF1(17194) }, { CDF1(16170) },
+                    { CDF1(17695) }, { CDF1(13826) }, { CDF1(15810) },
+                    { CDF1(12036) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(23959) }, { CDF1(20799) }, { CDF1(19021) },
+                    { CDF1(16203) }, { CDF1(17886) }, { CDF1(14144) },
+                    { CDF1(12010) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(27399) }, { CDF1(16327) }, { CDF1(18071) },
+                    { CDF1(19584) }, { CDF1(20721) }, { CDF1(18432) },
+                    { CDF1(19560) }, { CDF1(10150) }, { CDF1( 8805) },
+                }, {
+                    { CDF1(24932) }, { CDF1(20833) }, { CDF1(12027) },
+                    { CDF1(16670) }, { CDF1(19914) }, { CDF1(15106) },
+                    { CDF1(17662) }, { CDF1(13783) }, { CDF1(28756) },
+                },
+            }, {
+                {
+                    { CDF1(23406) }, { CDF1(21845) }, { CDF1(18432) },
+                    { CDF1(16384) }, { CDF1(17096) }, { CDF1(12561) },
+                    { CDF1(17320) }, { CDF1(22395) }, { CDF1(21370) },
+                }, {
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            },
+        }, .eob_base_tok = {
+            {
+                {
+                    { CDF2(17837, 29055) }, { CDF2(29600, 31446) },
+                    { CDF2(30844, 31878) }, { CDF2(24926, 28948) },
+                }, {
+                    { CDF2(21365, 30026) }, { CDF2(30512, 32423) },
+                    { CDF2(31658, 32621) }, { CDF2(29630, 31881) },
+                },
+            }, {
+                {
+                    { CDF2( 5717, 26477) }, { CDF2(30491, 31703) },
+                    { CDF2(31550, 32158) }, { CDF2(29648, 31491) },
+                }, {
+                    { CDF2(12608, 27820) }, { CDF2(30680, 32225) },
+                    { CDF2(30809, 32335) }, { CDF2(31299, 32423) },
+                },
+            }, {
+                {
+                    { CDF2( 1786, 12612) }, { CDF2(30663, 31625) },
+                    { CDF2(32339, 32468) }, { CDF2(31148, 31833) },
+                }, {
+                    { CDF2(18857, 23865) }, { CDF2(31428, 32428) },
+                    { CDF2(31744, 32373) }, { CDF2(31775, 32526) },
+                },
+            }, {
+                {
+                    { CDF2( 1787,  2532) }, { CDF2(30832, 31662) },
+                    { CDF2(31824, 32682) }, { CDF2(32133, 32569) },
+                }, {
+                    { CDF2(13751, 22235) }, { CDF2(32089, 32409) },
+                    { CDF2(27084, 27920) }, { CDF2(29291, 32594) },
+                },
+            }, {
+                {
+                    { CDF2( 1725,  3449) }, { CDF2(31102, 31935) },
+                    { CDF2(32457, 32613) }, { CDF2(32412, 32649) },
+                }, {
+                    { CDF2(10923, 21845) }, { CDF2(10923, 21845) },
+                    { CDF2(10923, 21845) }, { CDF2(10923, 21845) },
+                },
+            },
+        }, .base_tok = {
+            {
+                {
+                    { CDF3( 4034,  8930, 12727) },
+                    { CDF3(18082, 29741, 31877) },
+                    { CDF3(12596, 26124, 30493) },
+                    { CDF3( 9446, 21118, 27005) },
+                    { CDF3( 6308, 15141, 21279) },
+                    { CDF3( 2463,  6357,  9783) },
+                    { CDF3(20667, 30546, 31929) },
+                    { CDF3(13043, 26123, 30134) },
+                    { CDF3( 8151, 18757, 24778) },
+                    { CDF3( 5255, 12839, 18632) },
+                    { CDF3( 2820,  7206, 11161) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3(15736, 27553, 30604) },
+                    { CDF3(11210, 23794, 28787) },
+                    { CDF3( 5947, 13874, 19701) },
+                    { CDF3( 4215,  9323, 13891) },
+                    { CDF3( 2833,  6462, 10059) },
+                    { CDF3(19605, 30393, 31582) },
+                    { CDF3(13523, 26252, 30248) },
+                    { CDF3( 8446, 18622, 24512) },
+                    { CDF3( 3818, 10343, 15974) },
+                    { CDF3( 1481,  4117,  6796) },
+                    { CDF3(22649, 31302, 32190) },
+                    { CDF3(14829, 27127, 30449) },
+                    { CDF3( 8313, 17702, 23304) },
+                    { CDF3( 3022,  8301, 12786) },
+                    { CDF3( 1536,  4412,  7184) },
+                    { CDF3(22354, 29774, 31372) },
+                    { CDF3(14723, 25472, 29214) },
+                    { CDF3( 6673, 13745, 18662) },
+                    { CDF3( 2068,  5766,  9322) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 6302, 16444, 21761) },
+                    { CDF3(23040, 31538, 32475) },
+                    { CDF3(15196, 28452, 31496) },
+                    { CDF3(10020, 22946, 28514) },
+                    { CDF3( 6533, 16862, 23501) },
+                    { CDF3( 3538,  9816, 15076) },
+                    { CDF3(24444, 31875, 32525) },
+                    { CDF3(15881, 28924, 31635) },
+                    { CDF3( 9922, 22873, 28466) },
+                    { CDF3( 6527, 16966, 23691) },
+                    { CDF3( 4114, 11303, 17220) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3(20201, 30770, 32209) },
+                    { CDF3(14754, 28071, 31258) },
+                    { CDF3( 8378, 20186, 26517) },
+                    { CDF3( 5916, 15299, 21978) },
+                    { CDF3( 4268, 11583, 17901) },
+                    { CDF3(24361, 32025, 32581) },
+                    { CDF3(18673, 30105, 31943) },
+                    { CDF3(10196, 22244, 27576) },
+                    { CDF3( 5495, 14349, 20417) },
+                    { CDF3( 2676,  7415, 11498) },
+                    { CDF3(24678, 31958, 32585) },
+                    { CDF3(18629, 29906, 31831) },
+                    { CDF3( 9364, 20724, 26315) },
+                    { CDF3( 4641, 12318, 18094) },
+                    { CDF3( 2758,  7387, 11579) },
+                    { CDF3(25433, 31842, 32469) },
+                    { CDF3(18795, 29289, 31411) },
+                    { CDF3( 7644, 17584, 23592) },
+                    { CDF3( 3408,  9014, 15047) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            }, {
+                {
+                    { CDF3( 4536, 10072, 14001) },
+                    { CDF3(25459, 31416, 32206) },
+                    { CDF3(16605, 28048, 30818) },
+                    { CDF3(11008, 22857, 27719) },
+                    { CDF3( 6915, 16268, 22315) },
+                    { CDF3( 2625,  6812, 10537) },
+                    { CDF3(24257, 31788, 32499) },
+                    { CDF3(16880, 29454, 31879) },
+                    { CDF3(11958, 25054, 29778) },
+                    { CDF3( 7916, 18718, 25084) },
+                    { CDF3( 3383,  8777, 13446) },
+                    { CDF3(22720, 31603, 32393) },
+                    { CDF3(14960, 28125, 31335) },
+                    { CDF3( 9731, 22210, 27928) },
+                    { CDF3( 6304, 15832, 22277) },
+                    { CDF3( 2910,  7818, 12166) },
+                    { CDF3(20375, 30627, 32131) },
+                    { CDF3(13904, 27284, 30887) },
+                    { CDF3( 9368, 21558, 27144) },
+                    { CDF3( 5937, 14966, 21119) },
+                    { CDF3( 2667,  7225, 11319) },
+                    { CDF3(23970, 31470, 32378) },
+                    { CDF3(17173, 29734, 32018) },
+                    { CDF3(12795, 25441, 29965) },
+                    { CDF3( 8981, 19680, 25893) },
+                    { CDF3( 4728, 11372, 16902) },
+                    { CDF3(24287, 31797, 32439) },
+                    { CDF3(16703, 29145, 31696) },
+                    { CDF3(10833, 23554, 28725) },
+                    { CDF3( 6468, 16566, 23057) },
+                    { CDF3( 2415,  6562, 10278) },
+                    { CDF3(26610, 32395, 32659) },
+                    { CDF3(18590, 30498, 32117) },
+                    { CDF3(12420, 25756, 29950) },
+                    { CDF3( 7639, 18746, 24710) },
+                    { CDF3( 3001,  8086, 12347) },
+                    { CDF3(25076, 32064, 32580) },
+                    { CDF3(17946, 30128, 32028) },
+                    { CDF3(12024, 24985, 29378) },
+                    { CDF3( 7517, 18390, 24304) },
+                    { CDF3( 3243,  8781, 13331) },
+                }, {
+                    { CDF3( 6037, 16771, 21957) },
+                    { CDF3(24774, 31704, 32426) },
+                    { CDF3(16830, 28589, 31056) },
+                    { CDF3(10602, 22828, 27760) },
+                    { CDF3( 6733, 16829, 23071) },
+                    { CDF3( 3250,  8914, 13556) },
+                    { CDF3(25582, 32220, 32668) },
+                    { CDF3(18659, 30342, 32223) },
+                    { CDF3(12546, 26149, 30515) },
+                    { CDF3( 8420, 20451, 26801) },
+                    { CDF3( 4636, 12420, 18344) },
+                    { CDF3(27581, 32362, 32639) },
+                    { CDF3(18987, 30083, 31978) },
+                    { CDF3(11327, 24248, 29084) },
+                    { CDF3( 7264, 17719, 24120) },
+                    { CDF3( 3995, 10768, 16169) },
+                    { CDF3(25893, 31831, 32487) },
+                    { CDF3(16577, 28587, 31379) },
+                    { CDF3(10189, 22748, 28182) },
+                    { CDF3( 6832, 17094, 23556) },
+                    { CDF3( 3708, 10110, 15334) },
+                    { CDF3(25904, 32282, 32656) },
+                    { CDF3(19721, 30792, 32276) },
+                    { CDF3(12819, 26243, 30411) },
+                    { CDF3( 8572, 20614, 26891) },
+                    { CDF3( 5364, 14059, 20467) },
+                    { CDF3(26580, 32438, 32677) },
+                    { CDF3(20852, 31225, 32340) },
+                    { CDF3(12435, 25700, 29967) },
+                    { CDF3( 8691, 20825, 26976) },
+                    { CDF3( 4446, 12209, 17269) },
+                    { CDF3(27350, 32429, 32696) },
+                    { CDF3(21372, 30977, 32272) },
+                    { CDF3(12673, 25270, 29853) },
+                    { CDF3( 9208, 20925, 26640) },
+                    { CDF3( 5018, 13351, 18732) },
+                    { CDF3(27351, 32479, 32713) },
+                    { CDF3(21398, 31209, 32387) },
+                    { CDF3(12162, 25047, 29842) },
+                    { CDF3( 7896, 18691, 25319) },
+                    { CDF3( 4670, 12882, 18881) },
+                },
+            }, {
+                {
+                    { CDF3( 5487, 10460, 13708) },
+                    { CDF3(21597, 28303, 30674) },
+                    { CDF3(11037, 21953, 26476) },
+                    { CDF3( 8147, 17962, 22952) },
+                    { CDF3( 5242, 13061, 18532) },
+                    { CDF3( 1889,  5208,  8182) },
+                    { CDF3(26774, 32133, 32590) },
+                    { CDF3(17844, 29564, 31767) },
+                    { CDF3(11690, 24438, 29171) },
+                    { CDF3( 7542, 18215, 24459) },
+                    { CDF3( 2993,  8050, 12319) },
+                    { CDF3(28023, 32328, 32591) },
+                    { CDF3(18651, 30126, 31954) },
+                    { CDF3(12164, 25146, 29589) },
+                    { CDF3( 7762, 18530, 24771) },
+                    { CDF3( 3492,  9183, 13920) },
+                    { CDF3(27591, 32008, 32491) },
+                    { CDF3(17149, 28853, 31510) },
+                    { CDF3(11485, 24003, 28860) },
+                    { CDF3( 7697, 18086, 24210) },
+                    { CDF3( 3075,  7999, 12218) },
+                    { CDF3(28268, 32482, 32654) },
+                    { CDF3(19631, 31051, 32404) },
+                    { CDF3(13860, 27260, 31020) },
+                    { CDF3( 9605, 21613, 27594) },
+                    { CDF3( 4876, 12162, 17908) },
+                    { CDF3(27248, 32316, 32576) },
+                    { CDF3(18955, 30457, 32075) },
+                    { CDF3(11824, 23997, 28795) },
+                    { CDF3( 7346, 18196, 24647) },
+                    { CDF3( 3403,  9247, 14111) },
+                    { CDF3(29711, 32655, 32735) },
+                    { CDF3(21169, 31394, 32417) },
+                    { CDF3(13487, 27198, 30957) },
+                    { CDF3( 8828, 21683, 27614) },
+                    { CDF3( 4270, 11451, 17038) },
+                    { CDF3(28708, 32578, 32731) },
+                    { CDF3(20120, 31241, 32482) },
+                    { CDF3(13692, 27550, 31321) },
+                    { CDF3( 9418, 22514, 28439) },
+                    { CDF3( 4999, 13283, 19462) },
+                }, {
+                    { CDF3( 5673, 14302, 19711) },
+                    { CDF3(26251, 30701, 31834) },
+                    { CDF3(12782, 23783, 27803) },
+                    { CDF3( 9127, 20657, 25808) },
+                    { CDF3( 6368, 16208, 21462) },
+                    { CDF3( 2465,  7177, 10822) },
+                    { CDF3(29961, 32563, 32719) },
+                    { CDF3(18318, 29891, 31949) },
+                    { CDF3(11361, 24514, 29357) },
+                    { CDF3( 7900, 19603, 25607) },
+                    { CDF3( 4002, 10590, 15546) },
+                    { CDF3(29637, 32310, 32595) },
+                    { CDF3(18296, 29913, 31809) },
+                    { CDF3(10144, 21515, 26871) },
+                    { CDF3( 5358, 14322, 20394) },
+                    { CDF3( 3067,  8362, 13346) },
+                    { CDF3(28652, 32470, 32676) },
+                    { CDF3(17538, 30771, 32209) },
+                    { CDF3(13924, 26882, 30494) },
+                    { CDF3(10496, 22837, 27869) },
+                    { CDF3( 7236, 16396, 21621) },
+                    { CDF3(30743, 32687, 32746) },
+                    { CDF3(23006, 31676, 32489) },
+                    { CDF3(14494, 27828, 31120) },
+                    { CDF3(10174, 22801, 28352) },
+                    { CDF3( 6242, 15281, 21043) },
+                    { CDF3(25817, 32243, 32720) },
+                    { CDF3(18618, 31367, 32325) },
+                    { CDF3(13997, 28318, 31878) },
+                    { CDF3(12255, 26534, 31383) },
+                    { CDF3( 9561, 21588, 28450) },
+                    { CDF3(28188, 32635, 32724) },
+                    { CDF3(22060, 32365, 32728) },
+                    { CDF3(18102, 30690, 32528) },
+                    { CDF3(14196, 28864, 31999) },
+                    { CDF3(12262, 25792, 30865) },
+                    { CDF3(24176, 32109, 32628) },
+                    { CDF3(18280, 29681, 31963) },
+                    { CDF3(10205, 23703, 29664) },
+                    { CDF3( 7889, 20025, 27676) },
+                    { CDF3( 6060, 16743, 23970) },
+                },
+            }, {
+                {
+                    { CDF3( 5141,  7096,  8260) },
+                    { CDF3(27186, 29022, 29789) },
+                    { CDF3( 6668, 12568, 15682) },
+                    { CDF3( 2172,  6181,  8638) },
+                    { CDF3( 1126,  3379,  4531) },
+                    { CDF3(  443,  1361,  2254) },
+                    { CDF3(26083, 31153, 32436) },
+                    { CDF3(13486, 24603, 28483) },
+                    { CDF3( 6508, 14840, 19910) },
+                    { CDF3( 3386,  8800, 13286) },
+                    { CDF3( 1530,  4322,  7054) },
+                    { CDF3(29639, 32080, 32548) },
+                    { CDF3(15897, 27552, 30290) },
+                    { CDF3( 8588, 20047, 25383) },
+                    { CDF3( 4889, 13339, 19269) },
+                    { CDF3( 2240,  6871, 10498) },
+                    { CDF3(28165, 32197, 32517) },
+                    { CDF3(20735, 30427, 31568) },
+                    { CDF3(14325, 24671, 27692) },
+                    { CDF3( 5119, 12554, 17805) },
+                    { CDF3( 1810,  5441,  8261) },
+                    { CDF3(31212, 32724, 32748) },
+                    { CDF3(23352, 31766, 32545) },
+                    { CDF3(14669, 27570, 31059) },
+                    { CDF3( 8492, 20894, 27272) },
+                    { CDF3( 3644, 10194, 15204) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 2461,  7013,  9371) },
+                    { CDF3(24749, 29600, 30986) },
+                    { CDF3( 9466, 19037, 22417) },
+                    { CDF3( 3584,  9280, 14400) },
+                    { CDF3( 1505,  3929,  5433) },
+                    { CDF3(  677,  1500,  2736) },
+                    { CDF3(23987, 30702, 32117) },
+                    { CDF3(13554, 24571, 29263) },
+                    { CDF3( 6211, 14556, 21155) },
+                    { CDF3( 3135, 10972, 15625) },
+                    { CDF3( 2435,  7127, 11427) },
+                    { CDF3(31300, 32532, 32550) },
+                    { CDF3(14757, 30365, 31954) },
+                    { CDF3( 4405, 11612, 18553) },
+                    { CDF3(  580,  4132,  7322) },
+                    { CDF3( 1695, 10169, 14124) },
+                    { CDF3(30008, 32282, 32591) },
+                    { CDF3(19244, 30108, 31748) },
+                    { CDF3(11180, 24158, 29555) },
+                    { CDF3( 5650, 14972, 19209) },
+                    { CDF3( 2114,  5109,  8456) },
+                    { CDF3(31856, 32716, 32748) },
+                    { CDF3(23012, 31664, 32572) },
+                    { CDF3(13694, 26656, 30636) },
+                    { CDF3( 8142, 19508, 26093) },
+                    { CDF3( 4253, 10955, 16724) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            }, {
+                {
+                    { CDF3(  601,   983,  1311) },
+                    { CDF3(18725, 23406, 28087) },
+                    { CDF3( 5461,  8192, 10923) },
+                    { CDF3( 3781, 15124, 21425) },
+                    { CDF3( 2587,  7761, 12072) },
+                    { CDF3(  106,   458,   810) },
+                    { CDF3(22282, 29710, 31894) },
+                    { CDF3( 8508, 20926, 25984) },
+                    { CDF3( 3726, 12713, 18083) },
+                    { CDF3( 1620,  7112, 10893) },
+                    { CDF3(  729,  2236,  3495) },
+                    { CDF3(30163, 32474, 32684) },
+                    { CDF3(18304, 30464, 32000) },
+                    { CDF3(11443, 26526, 29647) },
+                    { CDF3( 6007, 15292, 21299) },
+                    { CDF3( 2234,  6703,  8937) },
+                    { CDF3(30954, 32177, 32571) },
+                    { CDF3(17363, 29562, 31076) },
+                    { CDF3( 9686, 22464, 27410) },
+                    { CDF3( 8192, 16384, 21390) },
+                    { CDF3( 1755,  8046, 11264) },
+                    { CDF3(31168, 32734, 32748) },
+                    { CDF3(22486, 31441, 32471) },
+                    { CDF3(12833, 25627, 29738) },
+                    { CDF3( 6980, 17379, 23122) },
+                    { CDF3( 3111,  8887, 13479) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            },
+        }, .dc_sign = {
+            { { CDF1(16000) }, { CDF1(13056) }, { CDF1(18816) } },
+            { { CDF1(15232) }, { CDF1(12928) }, { CDF1(17280) } },
+        }, .br_tok = {
+            {
+                {
+                    { CDF3(14298, 20718, 24174) },
+                    { CDF3(12536, 19601, 23789) },
+                    { CDF3( 8712, 15051, 19503) },
+                    { CDF3( 6170, 11327, 15434) },
+                    { CDF3( 4742,  8926, 12538) },
+                    { CDF3( 3803,  7317, 10546) },
+                    { CDF3( 1696,  3317,  4871) },
+                    { CDF3(14392, 19951, 22756) },
+                    { CDF3(15978, 23218, 26818) },
+                    { CDF3(12187, 19474, 23889) },
+                    { CDF3( 9176, 15640, 20259) },
+                    { CDF3( 7068, 12655, 17028) },
+                    { CDF3( 5656, 10442, 14472) },
+                    { CDF3( 2580,  4992,  7244) },
+                    { CDF3(12136, 18049, 21426) },
+                    { CDF3(13784, 20721, 24481) },
+                    { CDF3(10836, 17621, 21900) },
+                    { CDF3( 8372, 14444, 18847) },
+                    { CDF3( 6523, 11779, 16000) },
+                    { CDF3( 5337,  9898, 13760) },
+                    { CDF3( 3034,  5860,  8462) },
+                }, {
+                    { CDF3(15967, 22905, 26286) },
+                    { CDF3(13534, 20654, 24579) },
+                    { CDF3( 9504, 16092, 20535) },
+                    { CDF3( 6975, 12568, 16903) },
+                    { CDF3( 5364, 10091, 14020) },
+                    { CDF3( 4357,  8370, 11857) },
+                    { CDF3( 2506,  4934,  7218) },
+                    { CDF3(23032, 28815, 30936) },
+                    { CDF3(19540, 26704, 29719) },
+                    { CDF3(15158, 22969, 27097) },
+                    { CDF3(11408, 18865, 23650) },
+                    { CDF3( 8885, 15448, 20250) },
+                    { CDF3( 7108, 12853, 17416) },
+                    { CDF3( 4231,  8041, 11480) },
+                    { CDF3(19823, 26490, 29156) },
+                    { CDF3(18890, 25929, 28932) },
+                    { CDF3(15660, 23491, 27433) },
+                    { CDF3(12147, 19776, 24488) },
+                    { CDF3( 9728, 16774, 21649) },
+                    { CDF3( 7919, 14277, 19066) },
+                    { CDF3( 5440, 10170, 14185) },
+                },
+            }, {
+                {
+                    { CDF3(14406, 20862, 24414) },
+                    { CDF3(11824, 18907, 23109) },
+                    { CDF3( 8257, 14393, 18803) },
+                    { CDF3( 5860, 10747, 14778) },
+                    { CDF3( 4475,  8486, 11984) },
+                    { CDF3( 3606,  6954, 10043) },
+                    { CDF3( 1736,  3410,  5048) },
+                    { CDF3(14430, 20046, 22882) },
+                    { CDF3(15593, 22899, 26709) },
+                    { CDF3(12102, 19368, 23811) },
+                    { CDF3( 9059, 15584, 20262) },
+                    { CDF3( 6999, 12603, 17048) },
+                    { CDF3( 5684, 10497, 14553) },
+                    { CDF3( 2822,  5438,  7862) },
+                    { CDF3(15785, 21585, 24359) },
+                    { CDF3(18347, 25229, 28266) },
+                    { CDF3(14974, 22487, 26389) },
+                    { CDF3(11423, 18681, 23271) },
+                    { CDF3( 8863, 15350, 20008) },
+                    { CDF3( 7153, 12852, 17278) },
+                    { CDF3( 3707,  7036,  9982) },
+                }, {
+                    { CDF3(15460, 21696, 25469) },
+                    { CDF3(12170, 19249, 23191) },
+                    { CDF3( 8723, 15027, 19332) },
+                    { CDF3( 6428, 11704, 15874) },
+                    { CDF3( 4922,  9292, 13052) },
+                    { CDF3( 4139,  7695, 11010) },
+                    { CDF3( 2291,  4508,  6598) },
+                    { CDF3(19856, 26920, 29828) },
+                    { CDF3(17923, 25289, 28792) },
+                    { CDF3(14278, 21968, 26297) },
+                    { CDF3(10910, 18136, 22950) },
+                    { CDF3( 8423, 14815, 19627) },
+                    { CDF3( 6771, 12283, 16774) },
+                    { CDF3( 4074,  7750, 11081) },
+                    { CDF3(19852, 26074, 28672) },
+                    { CDF3(19371, 26110, 28989) },
+                    { CDF3(16265, 23873, 27663) },
+                    { CDF3(12758, 20378, 24952) },
+                    { CDF3(10095, 17098, 21961) },
+                    { CDF3( 8250, 14628, 19451) },
+                    { CDF3( 5205,  9745, 13622) },
+                },
+            }, {
+                {
+                    { CDF3(10563, 16233, 19763) },
+                    { CDF3( 9794, 16022, 19804) },
+                    { CDF3( 6750, 11945, 15759) },
+                    { CDF3( 4963,  9186, 12752) },
+                    { CDF3( 3845,  7435, 10627) },
+                    { CDF3( 3051,  6085,  8834) },
+                    { CDF3( 1311,  2596,  3830) },
+                    { CDF3(11246, 16404, 19689) },
+                    { CDF3(12315, 18911, 22731) },
+                    { CDF3(10557, 17095, 21289) },
+                    { CDF3( 8136, 14006, 18249) },
+                    { CDF3( 6348, 11474, 15565) },
+                    { CDF3( 5196,  9655, 13400) },
+                    { CDF3( 2349,  4526,  6587) },
+                    { CDF3(13337, 18730, 21569) },
+                    { CDF3(19306, 26071, 28882) },
+                    { CDF3(15952, 23540, 27254) },
+                    { CDF3(12409, 19934, 24430) },
+                    { CDF3( 9760, 16706, 21389) },
+                    { CDF3( 8004, 14220, 18818) },
+                    { CDF3( 4138,  7794, 10961) },
+                }, {
+                    { CDF3(10870, 16684, 20949) },
+                    { CDF3( 9664, 15230, 18680) },
+                    { CDF3( 6886, 12109, 15408) },
+                    { CDF3( 4825,  8900, 12305) },
+                    { CDF3( 3630,  7162, 10314) },
+                    { CDF3( 3036,  6429,  9387) },
+                    { CDF3( 1671,  3296,  4940) },
+                    { CDF3(13819, 19159, 23026) },
+                    { CDF3(11984, 19108, 23120) },
+                    { CDF3(10690, 17210, 21663) },
+                    { CDF3( 7984, 14154, 18333) },
+                    { CDF3( 6868, 12294, 16124) },
+                    { CDF3( 5274,  8994, 12868) },
+                    { CDF3( 2988,  5771,  8424) },
+                    { CDF3(19736, 26647, 29141) },
+                    { CDF3(18933, 26070, 28984) },
+                    { CDF3(15779, 23048, 27200) },
+                    { CDF3(12638, 20061, 24532) },
+                    { CDF3(10692, 17545, 22220) },
+                    { CDF3( 9217, 15251, 20054) },
+                    { CDF3( 5078,  9284, 12594) },
+                },
+            }, {
+                {
+                    { CDF3( 2331,  3662,  5244) },
+                    { CDF3( 2891,  4771,  6145) },
+                    { CDF3( 4598,  7623,  9729) },
+                    { CDF3( 3520,  6845,  9199) },
+                    { CDF3( 3417,  6119,  9324) },
+                    { CDF3( 2601,  5412,  7385) },
+                    { CDF3(  600,  1173,  1744) },
+                    { CDF3( 7672, 13286, 17469) },
+                    { CDF3( 4232,  7792, 10793) },
+                    { CDF3( 2915,  5317,  7397) },
+                    { CDF3( 2318,  4356,  6152) },
+                    { CDF3( 2127,  4000,  5554) },
+                    { CDF3( 1850,  3478,  5275) },
+                    { CDF3(  977,  1933,  2843) },
+                    { CDF3(18280, 24387, 27989) },
+                    { CDF3(15852, 22671, 26185) },
+                    { CDF3(13845, 20951, 24789) },
+                    { CDF3(11055, 17966, 22129) },
+                    { CDF3( 9138, 15422, 19801) },
+                    { CDF3( 7454, 13145, 17456) },
+                    { CDF3( 3370,  6393,  9013) },
+                }, {
+                    { CDF3( 5842,  9229, 10838) },
+                    { CDF3( 2313,  3491,  4276) },
+                    { CDF3( 2998,  6104,  7496) },
+                    { CDF3( 2420,  7447,  9868) },
+                    { CDF3( 3034,  8495, 10923) },
+                    { CDF3( 4076,  8937, 10975) },
+                    { CDF3( 1086,  2370,  3299) },
+                    { CDF3( 9714, 17254, 20444) },
+                    { CDF3( 8543, 13698, 17123) },
+                    { CDF3( 4918,  9007, 11910) },
+                    { CDF3( 4129,  7532, 10553) },
+                    { CDF3( 2364,  5533,  8058) },
+                    { CDF3( 1834,  3546,  5563) },
+                    { CDF3( 1473,  2908,  4133) },
+                    { CDF3(15405, 21193, 25619) },
+                    { CDF3(15691, 21952, 26561) },
+                    { CDF3(12962, 19194, 24165) },
+                    { CDF3(10272, 17855, 22129) },
+                    { CDF3( 8588, 15270, 20718) },
+                    { CDF3( 8682, 14669, 19500) },
+                    { CDF3( 4870,  9636, 13205) },
+                },
+            },
+        },
+    }, [1] = {
+        .skip = {
+            {
+                { CDF1(30371) }, { CDF1( 7570) }, { CDF1(13155) },
+                { CDF1(20751) }, { CDF1(20969) }, { CDF1(27067) },
+                { CDF1(32013) }, { CDF1( 5495) }, { CDF1(17942) },
+                { CDF1(28280) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(31782) }, { CDF1( 1836) }, { CDF1(10689) },
+                { CDF1(17604) }, { CDF1(21622) }, { CDF1(27518) },
+                { CDF1(32399) }, { CDF1( 4419) }, { CDF1(16294) },
+                { CDF1(28345) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(31901) }, { CDF1(10311) }, { CDF1(18047) },
+                { CDF1(24806) }, { CDF1(23288) }, { CDF1(27914) },
+                { CDF1(32296) }, { CDF1( 4215) }, { CDF1(15756) },
+                { CDF1(28341) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(26726) }, { CDF1( 1045) }, { CDF1(11703) },
+                { CDF1(20590) }, { CDF1(18554) }, { CDF1(25970) },
+                { CDF1(31938) }, { CDF1( 5583) }, { CDF1(21313) },
+                { CDF1(29390) }, { CDF1(  641) }, { CDF1(22265) },
+                { CDF1(31452) },
+            }, {
+                { CDF1(26584) }, { CDF1(  188) }, { CDF1( 8847) },
+                { CDF1(24519) }, { CDF1(22938) }, { CDF1(30583) },
+                { CDF1(32608) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            },
+        }, .eob_bin_16 = {
+            {
+                { CDF4( 2125,  2551,  5165,  8946) },
+                { CDF4(  513,   765,  1859,  6339) },
+            }, {
+                { CDF4( 7637,  9498, 14259, 19108) },
+                { CDF4( 2497,  4096,  8866, 16993) },
+            },
+        }, .eob_bin_32 = {
+            {
+                { CDF5(  989,  1249,  2019,  4151, 10785) },
+                { CDF5(  313,   441,  1099,  2917,  8562) },
+            }, {
+                { CDF5( 8394, 10352, 13932, 18855, 26014) },
+                { CDF5( 2578,  4124,  8181, 13670, 24234) },
+            },
+        }, .eob_bin_64 = {
+            {
+                { CDF6( 1260,  1446,  2253,  3712,  6652, 13369) },
+                { CDF6(  401,   605,  1029,  2563,  5845, 12626) },
+            }, {
+                { CDF6( 8609, 10612, 14624, 18714, 22614, 29024) },
+                { CDF6( 1923,  3127,  5867,  9703, 14277, 27100) },
+            },
+        }, .eob_bin_128 = {
+            {
+                { CDF7(  685,   933,  1488,  2714,  4766,  8562, 19254) },
+                { CDF7(  217,   352,   618,  2303,  5261,  9969, 17472) },
+            }, {
+                { CDF7( 8045, 11200, 15497, 19595, 23948, 27408, 30938) },
+                { CDF7( 2310,  4160,  7471, 14997, 17931, 20768, 30240) },
+            },
+        }, .eob_bin_256 = {
+            {
+                { CDF8( 1448,  2109,  4151,  6263,
+                        9329, 13260, 17944, 23300) },
+                { CDF8(  399,  1019,  1749,  3038,
+                       10444, 15546, 22739, 27294) },
+            }, {
+                { CDF8( 6402,  8148, 12623, 15072,
+                       18728, 22847, 26447, 29377) },
+                { CDF8( 1674,  3252,  5734, 10159,
+                       22397, 23802, 24821, 30940) },
+            },
+        }, .eob_bin_512 = {
+            { CDF9( 1230,  2278,  5035,  7776, 11871,
+                   15346, 19590, 24584, 28749) },
+            { CDF9( 7265,  9979, 15819, 19250, 21780,
+                   23846, 26478, 28396, 31811) },
+        }, .eob_bin_1024 = {
+            { CDF10(  696,   948,  3145,  5702,  9706,
+                    13217, 17851, 21856, 25692, 28034) },
+            { CDF10( 2672,  3591,  9330, 17084, 22725,
+                    24284, 26527, 28027, 28377, 30876) },
+        }, .eob_hi_bit = {
+            {
+                {
+                    { CDF1(17471) }, { CDF1(20223) }, { CDF1(11357) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(20335) }, { CDF1(21667) }, { CDF1(14818) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(20430) }, { CDF1(20662) }, { CDF1(15367) },
+                    { CDF1(16970) }, { CDF1(14657) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(22117) }, { CDF1(22028) }, { CDF1(18650) },
+                    { CDF1(16042) }, { CDF1(15885) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(22409) }, { CDF1(21012) }, { CDF1(15650) },
+                    { CDF1(17395) }, { CDF1(15469) }, { CDF1(20205) },
+                    { CDF1(19511) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(24220) }, { CDF1(22480) }, { CDF1(17737) },
+                    { CDF1(18916) }, { CDF1(19268) }, { CDF1(18412) },
+                    { CDF1(18844) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(25991) }, { CDF1(20314) }, { CDF1(17731) },
+                    { CDF1(19678) }, { CDF1(18649) }, { CDF1(17307) },
+                    { CDF1(21798) }, { CDF1(17549) }, { CDF1(15630) },
+                }, {
+                    { CDF1(26585) }, { CDF1(21469) }, { CDF1(20432) },
+                    { CDF1(17735) }, { CDF1(19280) }, { CDF1(15235) },
+                    { CDF1(20297) }, { CDF1(22471) }, { CDF1(28997) },
+                },
+            }, {
+                {
+                    { CDF1(26605) }, { CDF1(11304) }, { CDF1(16726) },
+                    { CDF1(16560) }, { CDF1(20866) }, { CDF1(23524) },
+                    { CDF1(19878) }, { CDF1(13469) }, { CDF1(23084) },
+                }, {
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            },
+        }, .eob_base_tok = {
+            {
+                {
+                    { CDF2(17560, 29888) }, { CDF2(29671, 31549) },
+                    { CDF2(31007, 32056) }, { CDF2(27286, 30006) },
+                }, {
+                    { CDF2(26594, 31212) }, { CDF2(31208, 32582) },
+                    { CDF2(31835, 32637) }, { CDF2(30595, 32206) },
+                },
+            }, {
+                {
+                    { CDF2(15239, 29932) }, { CDF2(31315, 32095) },
+                    { CDF2(32130, 32434) }, { CDF2(30864, 31996) },
+                }, {
+                    { CDF2(26279, 30968) }, { CDF2(31142, 32495) },
+                    { CDF2(31713, 32540) }, { CDF2(31929, 32594) },
+                },
+            }, {
+                {
+                    { CDF2( 2644, 25198) }, { CDF2(32038, 32451) },
+                    { CDF2(32639, 32695) }, { CDF2(32166, 32518) },
+                }, {
+                    { CDF2(17187, 27668) }, { CDF2(31714, 32550) },
+                    { CDF2(32283, 32678) }, { CDF2(31930, 32563) },
+                },
+            }, {
+                {
+                    { CDF2( 1044,  2257) }, { CDF2(30755, 31923) },
+                    { CDF2(32208, 32693) }, { CDF2(32244, 32615) },
+                }, {
+                    { CDF2(21317, 26207) }, { CDF2(29133, 30868) },
+                    { CDF2(29311, 31231) }, { CDF2(29657, 31087) },
+                },
+            }, {
+                {
+                    { CDF2(  478,  1834) }, { CDF2(31005, 31987) },
+                    { CDF2(32317, 32724) }, { CDF2(30865, 32648) },
+                }, {
+                    { CDF2(10923, 21845) }, { CDF2(10923, 21845) },
+                    { CDF2(10923, 21845) }, { CDF2(10923, 21845) },
+                },
+            },
+        }, .base_tok = {
+            {
+                {
+                    { CDF3( 6041, 11854, 15927) },
+                    { CDF3(20326, 30905, 32251) },
+                    { CDF3(14164, 26831, 30725) },
+                    { CDF3( 9760, 20647, 26585) },
+                    { CDF3( 6416, 14953, 21219) },
+                    { CDF3( 2966,  7151, 10891) },
+                    { CDF3(23567, 31374, 32254) },
+                    { CDF3(14978, 27416, 30946) },
+                    { CDF3( 9434, 20225, 26254) },
+                    { CDF3( 6658, 14558, 20535) },
+                    { CDF3( 3916,  8677, 12989) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3(18088, 29545, 31587) },
+                    { CDF3(13062, 25843, 30073) },
+                    { CDF3( 8940, 16827, 22251) },
+                    { CDF3( 7654, 13220, 17973) },
+                    { CDF3( 5733, 10316, 14456) },
+                    { CDF3(22879, 31388, 32114) },
+                    { CDF3(15215, 27993, 30955) },
+                    { CDF3( 9397, 19445, 24978) },
+                    { CDF3( 3442,  9813, 15344) },
+                    { CDF3( 1368,  3936,  6532) },
+                    { CDF3(25494, 32033, 32406) },
+                    { CDF3(16772, 27963, 30718) },
+                    { CDF3( 9419, 18165, 23260) },
+                    { CDF3( 2677,  7501, 11797) },
+                    { CDF3( 1516,  4344,  7170) },
+                    { CDF3(26556, 31454, 32101) },
+                    { CDF3(17128, 27035, 30108) },
+                    { CDF3( 8324, 15344, 20249) },
+                    { CDF3( 1903,  5696,  9469) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 8455, 19003, 24368) },
+                    { CDF3(23563, 32021, 32604) },
+                    { CDF3(16237, 29446, 31935) },
+                    { CDF3(10724, 23999, 29358) },
+                    { CDF3( 6725, 17528, 24416) },
+                    { CDF3( 3927, 10927, 16825) },
+                    { CDF3(26313, 32288, 32634) },
+                    { CDF3(17430, 30095, 32095) },
+                    { CDF3(11116, 24606, 29679) },
+                    { CDF3( 7195, 18384, 25269) },
+                    { CDF3( 4726, 12852, 19315) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3(22822, 31648, 32483) },
+                    { CDF3(16724, 29633, 31929) },
+                    { CDF3(10261, 23033, 28725) },
+                    { CDF3( 7029, 17840, 24528) },
+                    { CDF3( 4867, 13886, 21502) },
+                    { CDF3(25298, 31892, 32491) },
+                    { CDF3(17809, 29330, 31512) },
+                    { CDF3( 9668, 21329, 26579) },
+                    { CDF3( 4774, 12956, 18976) },
+                    { CDF3( 2322,  7030, 11540) },
+                    { CDF3(25472, 31920, 32543) },
+                    { CDF3(17957, 29387, 31632) },
+                    { CDF3( 9196, 20593, 26400) },
+                    { CDF3( 4680, 12705, 19202) },
+                    { CDF3( 2917,  8456, 13436) },
+                    { CDF3(26471, 32059, 32574) },
+                    { CDF3(18458, 29783, 31909) },
+                    { CDF3( 8400, 19464, 25956) },
+                    { CDF3( 3812, 10973, 17206) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            }, {
+                {
+                    { CDF3( 6779, 13743, 17678) },
+                    { CDF3(24806, 31797, 32457) },
+                    { CDF3(17616, 29047, 31372) },
+                    { CDF3(11063, 23175, 28003) },
+                    { CDF3( 6521, 16110, 22324) },
+                    { CDF3( 2764,  7504, 11654) },
+                    { CDF3(25266, 32367, 32637) },
+                    { CDF3(19054, 30553, 32175) },
+                    { CDF3(12139, 25212, 29807) },
+                    { CDF3( 7311, 18162, 24704) },
+                    { CDF3( 3397,  9164, 14074) },
+                    { CDF3(25988, 32208, 32522) },
+                    { CDF3(16253, 28912, 31526) },
+                    { CDF3( 9151, 21387, 27372) },
+                    { CDF3( 5688, 14915, 21496) },
+                    { CDF3( 2717,  7627, 12004) },
+                    { CDF3(23144, 31855, 32443) },
+                    { CDF3(16070, 28491, 31325) },
+                    { CDF3( 8702, 20467, 26517) },
+                    { CDF3( 5243, 13956, 20367) },
+                    { CDF3( 2621,  7335, 11567) },
+                    { CDF3(26636, 32340, 32630) },
+                    { CDF3(19990, 31050, 32341) },
+                    { CDF3(13243, 26105, 30315) },
+                    { CDF3( 8588, 19521, 25918) },
+                    { CDF3( 4717, 11585, 17304) },
+                    { CDF3(25844, 32292, 32582) },
+                    { CDF3(19090, 30635, 32097) },
+                    { CDF3(11963, 24546, 28939) },
+                    { CDF3( 6218, 16087, 22354) },
+                    { CDF3( 2340,  6608, 10426) },
+                    { CDF3(28046, 32576, 32694) },
+                    { CDF3(21178, 31313, 32296) },
+                    { CDF3(13486, 26184, 29870) },
+                    { CDF3( 7149, 17871, 23723) },
+                    { CDF3( 2833,  7958, 12259) },
+                    { CDF3(27710, 32528, 32686) },
+                    { CDF3(20674, 31076, 32268) },
+                    { CDF3(12413, 24955, 29243) },
+                    { CDF3( 6676, 16927, 23097) },
+                    { CDF3( 2966,  8333, 12919) },
+                }, {
+                    { CDF3( 8639, 19339, 24429) },
+                    { CDF3(24404, 31837, 32525) },
+                    { CDF3(16997, 29425, 31784) },
+                    { CDF3(11253, 24234, 29149) },
+                    { CDF3( 6751, 17394, 24028) },
+                    { CDF3( 3490,  9830, 15191) },
+                    { CDF3(26283, 32471, 32714) },
+                    { CDF3(19599, 31168, 32442) },
+                    { CDF3(13146, 26954, 30893) },
+                    { CDF3( 8214, 20588, 26890) },
+                    { CDF3( 4699, 13081, 19300) },
+                    { CDF3(28212, 32458, 32669) },
+                    { CDF3(18594, 30316, 32100) },
+                    { CDF3(11219, 24408, 29234) },
+                    { CDF3( 6865, 17656, 24149) },
+                    { CDF3( 3678, 10362, 16006) },
+                    { CDF3(25825, 32136, 32616) },
+                    { CDF3(17313, 29853, 32021) },
+                    { CDF3(11197, 24471, 29472) },
+                    { CDF3( 6947, 17781, 24405) },
+                    { CDF3( 3768, 10660, 16261) },
+                    { CDF3(27352, 32500, 32706) },
+                    { CDF3(20850, 31468, 32469) },
+                    { CDF3(14021, 27707, 31133) },
+                    { CDF3( 8964, 21748, 27838) },
+                    { CDF3( 5437, 14665, 21187) },
+                    { CDF3(26304, 32492, 32698) },
+                    { CDF3(20409, 31380, 32385) },
+                    { CDF3(13682, 27222, 30632) },
+                    { CDF3( 8974, 21236, 26685) },
+                    { CDF3( 4234, 11665, 16934) },
+                    { CDF3(26273, 32357, 32711) },
+                    { CDF3(20672, 31242, 32441) },
+                    { CDF3(14172, 27254, 30902) },
+                    { CDF3( 9870, 21898, 27275) },
+                    { CDF3( 5164, 13506, 19270) },
+                    { CDF3(26725, 32459, 32728) },
+                    { CDF3(20991, 31442, 32527) },
+                    { CDF3(13071, 26434, 30811) },
+                    { CDF3( 8184, 20090, 26742) },
+                    { CDF3( 4803, 13255, 19895) },
+                },
+            }, {
+                {
+                    { CDF3( 7555, 14942, 18501) },
+                    { CDF3(24410, 31178, 32287) },
+                    { CDF3(14394, 26738, 30253) },
+                    { CDF3( 8413, 19554, 25195) },
+                    { CDF3( 4766, 12924, 18785) },
+                    { CDF3( 2029,  5806,  9207) },
+                    { CDF3(26776, 32364, 32663) },
+                    { CDF3(18732, 29967, 31931) },
+                    { CDF3(11005, 23786, 28852) },
+                    { CDF3( 6466, 16909, 23510) },
+                    { CDF3( 3044,  8638, 13419) },
+                    { CDF3(29208, 32582, 32704) },
+                    { CDF3(20068, 30857, 32208) },
+                    { CDF3(12003, 25085, 29595) },
+                    { CDF3( 6947, 17750, 24189) },
+                    { CDF3( 3245,  9103, 14007) },
+                    { CDF3(27359, 32465, 32669) },
+                    { CDF3(19421, 30614, 32174) },
+                    { CDF3(11915, 25010, 29579) },
+                    { CDF3( 6950, 17676, 24074) },
+                    { CDF3( 3007,  8473, 13096) },
+                    { CDF3(29002, 32676, 32735) },
+                    { CDF3(22102, 31849, 32576) },
+                    { CDF3(14408, 28009, 31405) },
+                    { CDF3( 9027, 21679, 27931) },
+                    { CDF3( 4694, 12678, 18748) },
+                    { CDF3(28216, 32528, 32682) },
+                    { CDF3(20849, 31264, 32318) },
+                    { CDF3(12756, 25815, 29751) },
+                    { CDF3( 7565, 18801, 24923) },
+                    { CDF3( 3509,  9533, 14477) },
+                    { CDF3(30133, 32687, 32739) },
+                    { CDF3(23063, 31910, 32515) },
+                    { CDF3(14588, 28051, 31132) },
+                    { CDF3( 9085, 21649, 27457) },
+                    { CDF3( 4261, 11654, 17264) },
+                    { CDF3(29518, 32691, 32748) },
+                    { CDF3(22451, 31959, 32613) },
+                    { CDF3(14864, 28722, 31700) },
+                    { CDF3( 9695, 22964, 28716) },
+                    { CDF3( 4932, 13358, 19502) },
+                }, {
+                    { CDF3( 6465, 16958, 21688) },
+                    { CDF3(25199, 31514, 32360) },
+                    { CDF3(14774, 27149, 30607) },
+                    { CDF3( 9257, 21438, 26972) },
+                    { CDF3( 5723, 15183, 21882) },
+                    { CDF3( 3150,  8879, 13731) },
+                    { CDF3(26989, 32262, 32682) },
+                    { CDF3(17396, 29937, 32085) },
+                    { CDF3(11387, 24901, 29784) },
+                    { CDF3( 7289, 18821, 25548) },
+                    { CDF3( 3734, 10577, 16086) },
+                    { CDF3(29728, 32501, 32695) },
+                    { CDF3(17431, 29701, 31903) },
+                    { CDF3( 9921, 22826, 28300) },
+                    { CDF3( 5896, 15434, 22068) },
+                    { CDF3( 3430,  9646, 14757) },
+                    { CDF3(28614, 32511, 32705) },
+                    { CDF3(19364, 30638, 32263) },
+                    { CDF3(13129, 26254, 30402) },
+                    { CDF3( 8754, 20484, 26440) },
+                    { CDF3( 4378, 11607, 17110) },
+                    { CDF3(30292, 32671, 32744) },
+                    { CDF3(21780, 31603, 32501) },
+                    { CDF3(14314, 27829, 31291) },
+                    { CDF3( 9611, 22327, 28263) },
+                    { CDF3( 4890, 13087, 19065) },
+                    { CDF3(25862, 32567, 32733) },
+                    { CDF3(20794, 32050, 32567) },
+                    { CDF3(17243, 30625, 32254) },
+                    { CDF3(13283, 27628, 31474) },
+                    { CDF3( 9669, 22532, 28918) },
+                    { CDF3(27435, 32697, 32748) },
+                    { CDF3(24922, 32390, 32714) },
+                    { CDF3(21449, 31504, 32536) },
+                    { CDF3(16392, 29729, 31832) },
+                    { CDF3(11692, 24884, 29076) },
+                    { CDF3(24193, 32290, 32735) },
+                    { CDF3(18909, 31104, 32563) },
+                    { CDF3(12236, 26841, 31403) },
+                    { CDF3( 8171, 21840, 29082) },
+                    { CDF3( 7224, 17280, 25275) },
+                },
+            }, {
+                {
+                    { CDF3( 3078,  6839,  9890) },
+                    { CDF3(13837, 20450, 24479) },
+                    { CDF3( 5914, 14222, 19328) },
+                    { CDF3( 3866, 10267, 14762) },
+                    { CDF3( 2612,  7208, 11042) },
+                    { CDF3( 1067,  2991,  4776) },
+                    { CDF3(25817, 31646, 32529) },
+                    { CDF3(13708, 26338, 30385) },
+                    { CDF3( 7328, 18585, 24870) },
+                    { CDF3( 4691, 13080, 19276) },
+                    { CDF3( 1825,  5253,  8352) },
+                    { CDF3(29386, 32315, 32624) },
+                    { CDF3(17160, 29001, 31360) },
+                    { CDF3( 9602, 21862, 27396) },
+                    { CDF3( 5915, 15772, 22148) },
+                    { CDF3( 2786,  7779, 12047) },
+                    { CDF3(29246, 32450, 32663) },
+                    { CDF3(18696, 29929, 31818) },
+                    { CDF3(10510, 23369, 28560) },
+                    { CDF3( 6229, 16499, 23125) },
+                    { CDF3( 2608,  7448, 11705) },
+                    { CDF3(30753, 32710, 32748) },
+                    { CDF3(21638, 31487, 32503) },
+                    { CDF3(12937, 26854, 30870) },
+                    { CDF3( 8182, 20596, 26970) },
+                    { CDF3( 3637, 10269, 15497) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 5244, 12150, 16906) },
+                    { CDF3(20486, 26858, 29701) },
+                    { CDF3( 7756, 18317, 23735) },
+                    { CDF3( 3452,  9256, 13146) },
+                    { CDF3( 2020,  5206,  8229) },
+                    { CDF3( 1801,  4993,  7903) },
+                    { CDF3(27051, 31858, 32531) },
+                    { CDF3(15988, 27531, 30619) },
+                    { CDF3( 9188, 21484, 26719) },
+                    { CDF3( 6273, 17186, 23800) },
+                    { CDF3( 3108,  9355, 14764) },
+                    { CDF3(31076, 32520, 32680) },
+                    { CDF3(18119, 30037, 31850) },
+                    { CDF3(10244, 22969, 27472) },
+                    { CDF3( 4692, 14077, 19273) },
+                    { CDF3( 3694, 11677, 17556) },
+                    { CDF3(30060, 32581, 32720) },
+                    { CDF3(21011, 30775, 32120) },
+                    { CDF3(11931, 24820, 29289) },
+                    { CDF3( 7119, 17662, 24356) },
+                    { CDF3( 3833, 10706, 16304) },
+                    { CDF3(31954, 32731, 32748) },
+                    { CDF3(23913, 31724, 32489) },
+                    { CDF3(15520, 28060, 31286) },
+                    { CDF3(11517, 23008, 28571) },
+                    { CDF3( 6193, 14508, 20629) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            }, {
+                {
+                    { CDF3( 1035,  2807,  4156) },
+                    { CDF3(13162, 18138, 20939) },
+                    { CDF3( 2696,  6633,  8755) },
+                    { CDF3( 1373,  4161,  6853) },
+                    { CDF3( 1099,  2746,  4716) },
+                    { CDF3(  340,  1021,  1599) },
+                    { CDF3(22826, 30419, 32135) },
+                    { CDF3(10395, 21762, 26942) },
+                    { CDF3( 4726, 12407, 17361) },
+                    { CDF3( 2447,  7080, 10593) },
+                    { CDF3( 1227,  3717,  6011) },
+                    { CDF3(28156, 31424, 31934) },
+                    { CDF3(16915, 27754, 30373) },
+                    { CDF3( 9148, 20990, 26431) },
+                    { CDF3( 5950, 15515, 21148) },
+                    { CDF3( 2492,  7327, 11526) },
+                    { CDF3(30602, 32477, 32670) },
+                    { CDF3(20026, 29955, 31568) },
+                    { CDF3(11220, 23628, 28105) },
+                    { CDF3( 6652, 17019, 22973) },
+                    { CDF3( 3064,  8536, 13043) },
+                    { CDF3(31769, 32724, 32748) },
+                    { CDF3(22230, 30887, 32373) },
+                    { CDF3(12234, 25079, 29731) },
+                    { CDF3( 7326, 18816, 25353) },
+                    { CDF3( 3933, 10907, 16616) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            },
+        }, .dc_sign = {
+            { { CDF1(16000) }, { CDF1(13056) }, { CDF1(18816) } },
+            { { CDF1(15232) }, { CDF1(12928) }, { CDF1(17280) } },
+        }, .br_tok = {
+            {
+                {
+                    { CDF3(14995, 21341, 24749) },
+                    { CDF3(13158, 20289, 24601) },
+                    { CDF3( 8941, 15326, 19876) },
+                    { CDF3( 6297, 11541, 15807) },
+                    { CDF3( 4817,  9029, 12776) },
+                    { CDF3( 3731,  7273, 10627) },
+                    { CDF3( 1847,  3617,  5354) },
+                    { CDF3(14472, 19659, 22343) },
+                    { CDF3(16806, 24162, 27533) },
+                    { CDF3(12900, 20404, 24713) },
+                    { CDF3( 9411, 16112, 20797) },
+                    { CDF3( 7056, 12697, 17148) },
+                    { CDF3( 5544, 10339, 14460) },
+                    { CDF3( 2954,  5704,  8319) },
+                    { CDF3(12464, 18071, 21354) },
+                    { CDF3(15482, 22528, 26034) },
+                    { CDF3(12070, 19269, 23624) },
+                    { CDF3( 8953, 15406, 20106) },
+                    { CDF3( 7027, 12730, 17220) },
+                    { CDF3( 5887, 10913, 15140) },
+                    { CDF3( 3793,  7278, 10447) },
+                }, {
+                    { CDF3(15571, 22232, 25749) },
+                    { CDF3(14506, 21575, 25374) },
+                    { CDF3(10189, 17089, 21569) },
+                    { CDF3( 7316, 13301, 17915) },
+                    { CDF3( 5783, 10912, 15190) },
+                    { CDF3( 4760,  9155, 13088) },
+                    { CDF3( 2993,  5966,  8774) },
+                    { CDF3(23424, 28903, 30778) },
+                    { CDF3(20775, 27666, 30290) },
+                    { CDF3(16474, 24410, 28299) },
+                    { CDF3(12471, 20180, 24987) },
+                    { CDF3( 9410, 16487, 21439) },
+                    { CDF3( 7536, 13614, 18529) },
+                    { CDF3( 5048,  9586, 13549) },
+                    { CDF3(21090, 27290, 29756) },
+                    { CDF3(20796, 27402, 30026) },
+                    { CDF3(17819, 25485, 28969) },
+                    { CDF3(13860, 21909, 26462) },
+                    { CDF3(11002, 18494, 23529) },
+                    { CDF3( 8953, 15929, 20897) },
+                    { CDF3( 6448, 11918, 16454) },
+                },
+            }, {
+                {
+                    { CDF3(15999, 22208, 25449) },
+                    { CDF3(13050, 19988, 24122) },
+                    { CDF3( 8594, 14864, 19378) },
+                    { CDF3( 6033, 11079, 15238) },
+                    { CDF3( 4554,  8683, 12347) },
+                    { CDF3( 3672,  7139, 10337) },
+                    { CDF3( 1900,  3771,  5576) },
+                    { CDF3(15788, 21340, 23949) },
+                    { CDF3(16825, 24235, 27758) },
+                    { CDF3(12873, 20402, 24810) },
+                    { CDF3( 9590, 16363, 21094) },
+                    { CDF3( 7352, 13209, 17733) },
+                    { CDF3( 5960, 10989, 15184) },
+                    { CDF3( 3232,  6234,  9007) },
+                    { CDF3(15761, 20716, 23224) },
+                    { CDF3(19318, 25989, 28759) },
+                    { CDF3(15529, 23094, 26929) },
+                    { CDF3(11662, 18989, 23641) },
+                    { CDF3( 8955, 15568, 20366) },
+                    { CDF3( 7281, 13106, 17708) },
+                    { CDF3( 4248,  8059, 11440) },
+                }, {
+                    { CDF3(14899, 21217, 24503) },
+                    { CDF3(13519, 20283, 24047) },
+                    { CDF3( 9429, 15966, 20365) },
+                    { CDF3( 6700, 12355, 16652) },
+                    { CDF3( 5088,  9704, 13716) },
+                    { CDF3( 4243,  8154, 11731) },
+                    { CDF3( 2702,  5364,  7861) },
+                    { CDF3(22745, 28388, 30454) },
+                    { CDF3(20235, 27146, 29922) },
+                    { CDF3(15896, 23715, 27637) },
+                    { CDF3(11840, 19350, 24131) },
+                    { CDF3( 9122, 15932, 20880) },
+                    { CDF3( 7488, 13581, 18362) },
+                    { CDF3( 5114,  9568, 13370) },
+                    { CDF3(20845, 26553, 28932) },
+                    { CDF3(20981, 27372, 29884) },
+                    { CDF3(17781, 25335, 28785) },
+                    { CDF3(13760, 21708, 26297) },
+                    { CDF3(10975, 18415, 23365) },
+                    { CDF3( 9045, 15789, 20686) },
+                    { CDF3( 6130, 11199, 15423) },
+                },
+            }, {
+                {
+                    { CDF3(13549, 19724, 23158) },
+                    { CDF3(11844, 18382, 22246) },
+                    { CDF3( 7919, 13619, 17773) },
+                    { CDF3( 5486, 10143, 13946) },
+                    { CDF3( 4166,  7983, 11324) },
+                    { CDF3( 3364,  6506,  9427) },
+                    { CDF3( 1598,  3160,  4674) },
+                    { CDF3(15281, 20979, 23781) },
+                    { CDF3(14939, 22119, 25952) },
+                    { CDF3(11363, 18407, 22812) },
+                    { CDF3( 8609, 14857, 19370) },
+                    { CDF3( 6737, 12184, 16480) },
+                    { CDF3( 5506, 10263, 14262) },
+                    { CDF3( 2990,  5786,  8380) },
+                    { CDF3(20249, 25253, 27417) },
+                    { CDF3(21070, 27518, 30001) },
+                    { CDF3(16854, 24469, 28074) },
+                    { CDF3(12864, 20486, 25000) },
+                    { CDF3( 9962, 16978, 21778) },
+                    { CDF3( 8074, 14338, 19048) },
+                    { CDF3( 4494,  8479, 11906) },
+                }, {
+                    { CDF3(13960, 19617, 22829) },
+                    { CDF3(11150, 17341, 21228) },
+                    { CDF3( 7150, 12964, 17190) },
+                    { CDF3( 5331, 10002, 13867) },
+                    { CDF3( 4167,  7744, 11057) },
+                    { CDF3( 3480,  6629,  9646) },
+                    { CDF3( 1883,  3784,  5686) },
+                    { CDF3(18752, 25660, 28912) },
+                    { CDF3(16968, 24586, 28030) },
+                    { CDF3(13520, 21055, 25313) },
+                    { CDF3(10453, 17626, 22280) },
+                    { CDF3( 8386, 14505, 19116) },
+                    { CDF3( 6742, 12595, 17008) },
+                    { CDF3( 4273,  8140, 11499) },
+                    { CDF3(22120, 27827, 30233) },
+                    { CDF3(20563, 27358, 29895) },
+                    { CDF3(17076, 24644, 28153) },
+                    { CDF3(13362, 20942, 25309) },
+                    { CDF3(10794, 17965, 22695) },
+                    { CDF3( 9014, 15652, 20319) },
+                    { CDF3( 5708, 10512, 14497) },
+                },
+            }, {
+                {
+                    { CDF3( 5705, 10930, 15725) },
+                    { CDF3( 7946, 12765, 16115) },
+                    { CDF3( 6801, 12123, 16226) },
+                    { CDF3( 5462, 10135, 14200) },
+                    { CDF3( 4189,  8011, 11507) },
+                    { CDF3( 3191,  6229,  9408) },
+                    { CDF3( 1057,  2137,  3212) },
+                    { CDF3(10018, 17067, 21491) },
+                    { CDF3( 7380, 12582, 16453) },
+                    { CDF3( 6068, 10845, 14339) },
+                    { CDF3( 5098,  9198, 12555) },
+                    { CDF3( 4312,  8010, 11119) },
+                    { CDF3( 3700,  6966,  9781) },
+                    { CDF3( 1693,  3326,  4887) },
+                    { CDF3(18757, 24930, 27774) },
+                    { CDF3(17648, 24596, 27817) },
+                    { CDF3(14707, 22052, 26026) },
+                    { CDF3(11720, 18852, 23292) },
+                    { CDF3( 9357, 15952, 20525) },
+                    { CDF3( 7810, 13753, 18210) },
+                    { CDF3( 3879,  7333, 10328) },
+                }, {
+                    { CDF3( 8278, 13242, 15922) },
+                    { CDF3(10547, 15867, 18919) },
+                    { CDF3( 9106, 15842, 20609) },
+                    { CDF3( 6833, 13007, 17218) },
+                    { CDF3( 4811,  9712, 13923) },
+                    { CDF3( 3985,  7352, 11128) },
+                    { CDF3( 1688,  3458,  5262) },
+                    { CDF3(12951, 21861, 26510) },
+                    { CDF3( 9788, 16044, 20276) },
+                    { CDF3( 6309, 11244, 14870) },
+                    { CDF3( 5183,  9349, 12566) },
+                    { CDF3( 4389,  8229, 11492) },
+                    { CDF3( 3633,  6945, 10620) },
+                    { CDF3( 3600,  6847,  9907) },
+                    { CDF3(21748, 28137, 30255) },
+                    { CDF3(19436, 26581, 29560) },
+                    { CDF3(16359, 24201, 27953) },
+                    { CDF3(13961, 21693, 25871) },
+                    { CDF3(11544, 18686, 23322) },
+                    { CDF3( 9372, 16462, 20952) },
+                    { CDF3( 6138, 11210, 15390) },
+                },
+            },
+        },
+    }, [2] = {
+        .skip = {
+            {
+                { CDF1(29614) }, { CDF1( 9068) }, { CDF1(12924) },
+                { CDF1(19538) }, { CDF1(17737) }, { CDF1(24619) },
+                { CDF1(30642) }, { CDF1( 4119) }, { CDF1(16026) },
+                { CDF1(25657) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(31957) }, { CDF1( 3230) }, { CDF1(11153) },
+                { CDF1(18123) }, { CDF1(20143) }, { CDF1(26536) },
+                { CDF1(31986) }, { CDF1( 3050) }, { CDF1(14603) },
+                { CDF1(25155) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(32363) }, { CDF1(10692) }, { CDF1(19090) },
+                { CDF1(24357) }, { CDF1(24442) }, { CDF1(28312) },
+                { CDF1(32169) }, { CDF1( 3648) }, { CDF1(15690) },
+                { CDF1(26815) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(30669) }, { CDF1( 3832) }, { CDF1(11663) },
+                { CDF1(18889) }, { CDF1(19782) }, { CDF1(23313) },
+                { CDF1(31330) }, { CDF1( 5124) }, { CDF1(18719) },
+                { CDF1(28468) }, { CDF1( 3082) }, { CDF1(20982) },
+                { CDF1(29443) },
+            }, {
+                { CDF1(28573) }, { CDF1( 3183) }, { CDF1(17802) },
+                { CDF1(25977) }, { CDF1(26677) }, { CDF1(27832) },
+                { CDF1(32387) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            },
+        }, .eob_bin_16 = {
+            {
+                { CDF4( 4016,  4897,  8881, 14968) },
+                { CDF4(  716,  1105,  2646, 10056) },
+            }, {
+                { CDF4(11139, 13270, 18241, 23566) },
+                { CDF4( 3192,  5032, 10297, 19755) },
+            },
+        }, .eob_bin_32 = {
+            {
+                { CDF5( 2515,  3003,  4452,  8162, 16041) },
+                { CDF5(  574,   821,  1836,  5089, 13128) },
+            }, {
+                { CDF5(13468, 16303, 20361, 25105, 29281) },
+                { CDF5( 3542,  5502, 10415, 16760, 25644) },
+            },
+        }, .eob_bin_64 = {
+            {
+                { CDF6( 2374,  2772,  4583,  7276, 12288, 19706) },
+                { CDF6(  497,   810,  1315,  3000,  7004, 15641) },
+            }, {
+                { CDF6(15050, 17126, 21410, 24886, 28156, 30726) },
+                { CDF6( 4034,  6290, 10235, 14982, 21214, 28491) },
+            },
+        }, .eob_bin_128 = {
+            {
+                { CDF7( 1366,  1738,  2527,  5016,  9355, 15797, 24643) },
+                { CDF7(  354,   558,   944,  2760,  7287, 14037, 21779) },
+            }, {
+                { CDF7(13627, 16246, 20173, 24429, 27948, 30415, 31863) },
+                { CDF7( 6275,  9889, 14769, 23164, 27988, 30493, 32272) },
+            },
+        }, .eob_bin_256 = {
+            {
+                { CDF8( 3089,  3920,  6038,  9460,
+                       14266, 19881, 25766, 29176) },
+                { CDF8( 1084,  2358,  3488,  5122,
+                       11483, 18103, 26023, 29799) },
+            }, {
+                { CDF8(11514, 13794, 17480, 20754,
+                       24361, 27378, 29492, 31277) },
+                { CDF8( 6571,  9610, 15516, 21826,
+                       29092, 30829, 31842, 32708) },
+            },
+        }, .eob_bin_512 = {
+            { CDF9( 2624,  3936,  6480,  9686, 13979,
+                   17726, 23267, 28410, 31078) },
+            { CDF9(12015, 14769, 19588, 22052, 24222,
+                   25812, 27300, 29219, 32114) },
+        }, .eob_bin_1024 = {
+            { CDF10( 2784,  3831,  7041, 10521, 14847,
+                    18844, 23155, 26682, 29229, 31045) },
+            { CDF10( 9577, 12466, 17739, 20750, 22061,
+                    23215, 24601, 25483, 25843, 32056) },
+        }, .eob_hi_bit = {
+            {
+                {
+                    { CDF1(18983) }, { CDF1(20512) }, { CDF1(14885) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(20090) }, { CDF1(19444) }, { CDF1(17286) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(19139) }, { CDF1(21487) }, { CDF1(18959) },
+                    { CDF1(20910) }, { CDF1(19089) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(20536) }, { CDF1(20664) }, { CDF1(20625) },
+                    { CDF1(19123) }, { CDF1(14862) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(19833) }, { CDF1(21502) }, { CDF1(17485) },
+                    { CDF1(20267) }, { CDF1(18353) }, { CDF1(23329) },
+                    { CDF1(21478) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(22041) }, { CDF1(23434) }, { CDF1(20001) },
+                    { CDF1(20554) }, { CDF1(20951) }, { CDF1(20145) },
+                    { CDF1(15562) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(23312) }, { CDF1(21607) }, { CDF1(16526) },
+                    { CDF1(18957) }, { CDF1(18034) }, { CDF1(18934) },
+                    { CDF1(24247) }, { CDF1(16921) }, { CDF1(17080) },
+                }, {
+                    { CDF1(26579) }, { CDF1(24910) }, { CDF1(18637) },
+                    { CDF1(19800) }, { CDF1(20388) }, { CDF1( 9887) },
+                    { CDF1(15642) }, { CDF1(30198) }, { CDF1(24721) },
+                },
+            }, {
+                {
+                    { CDF1(26998) }, { CDF1(16737) }, { CDF1(17838) },
+                    { CDF1(18922) }, { CDF1(19515) }, { CDF1(18636) },
+                    { CDF1(17333) }, { CDF1(15776) }, { CDF1(22658) },
+                }, {
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            },
+        }, .eob_base_tok = {
+            {
+                {
+                    { CDF2(20092, 30774) }, { CDF2(30695, 32020) },
+                    { CDF2(31131, 32103) }, { CDF2(28666, 30870) },
+                }, {
+                    { CDF2(27258, 31095) }, { CDF2(31804, 32623) },
+                    { CDF2(31763, 32528) }, { CDF2(31438, 32506) },
+                },
+            }, {
+                {
+                    { CDF2(18049, 30489) }, { CDF2(31706, 32286) },
+                    { CDF2(32163, 32473) }, { CDF2(31550, 32184) },
+                }, {
+                    { CDF2(27116, 30842) }, { CDF2(31971, 32598) },
+                    { CDF2(32088, 32576) }, { CDF2(32067, 32664) },
+                },
+            }, {
+                {
+                    { CDF2(12854, 29093) }, { CDF2(32272, 32558) },
+                    { CDF2(32667, 32729) }, { CDF2(32306, 32585) },
+                }, {
+                    { CDF2(25476, 30366) }, { CDF2(32169, 32687) },
+                    { CDF2(32479, 32689) }, { CDF2(31673, 32634) },
+                },
+            }, {
+                {
+                    { CDF2( 2809, 19301) }, { CDF2(32205, 32622) },
+                    { CDF2(32338, 32730) }, { CDF2(31786, 32616) },
+                }, {
+                    { CDF2(22737, 29105) }, { CDF2(30810, 32362) },
+                    { CDF2(30014, 32627) }, { CDF2(30528, 32574) },
+                },
+            }, {
+                {
+                    { CDF2(  935,  3382) }, { CDF2(30789, 31909) },
+                    { CDF2(32466, 32756) }, { CDF2(30860, 32513) },
+                }, {
+                    { CDF2(10923, 21845) }, { CDF2(10923, 21845) },
+                    { CDF2(10923, 21845) }, { CDF2(10923, 21845) },
+                },
+            },
+        }, .base_tok = {
+            {
+                {
+                    { CDF3( 8896, 16227, 20630) },
+                    { CDF3(23629, 31782, 32527) },
+                    { CDF3(15173, 27755, 31321) },
+                    { CDF3(10158, 21233, 27382) },
+                    { CDF3( 6420, 14857, 21558) },
+                    { CDF3( 3269,  8155, 12646) },
+                    { CDF3(24835, 32009, 32496) },
+                    { CDF3(16509, 28421, 31579) },
+                    { CDF3(10957, 21514, 27418) },
+                    { CDF3( 7881, 15930, 22096) },
+                    { CDF3( 5388, 10960, 15918) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3(20745, 30773, 32093) },
+                    { CDF3(15200, 27221, 30861) },
+                    { CDF3(13032, 20873, 25667) },
+                    { CDF3(12285, 18663, 23494) },
+                    { CDF3(11563, 17481, 21489) },
+                    { CDF3(26260, 31982, 32320) },
+                    { CDF3(15397, 28083, 31100) },
+                    { CDF3( 9742, 19217, 24824) },
+                    { CDF3( 3261,  9629, 15362) },
+                    { CDF3( 1480,  4322,  7499) },
+                    { CDF3(27599, 32256, 32460) },
+                    { CDF3(16857, 27659, 30774) },
+                    { CDF3( 9551, 18290, 23748) },
+                    { CDF3( 3052,  8933, 14103) },
+                    { CDF3( 2021,  5910,  9787) },
+                    { CDF3(29005, 32015, 32392) },
+                    { CDF3(17677, 27694, 30863) },
+                    { CDF3( 9204, 17356, 23219) },
+                    { CDF3( 2403,  7516, 12814) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3(10808, 22056, 26896) },
+                    { CDF3(25739, 32313, 32676) },
+                    { CDF3(17288, 30203, 32221) },
+                    { CDF3(11359, 24878, 29896) },
+                    { CDF3( 6949, 17767, 24893) },
+                    { CDF3( 4287, 11796, 18071) },
+                    { CDF3(27880, 32521, 32705) },
+                    { CDF3(19038, 31004, 32414) },
+                    { CDF3(12564, 26345, 30768) },
+                    { CDF3( 8269, 19947, 26779) },
+                    { CDF3( 5674, 14657, 21674) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3(25742, 32319, 32671) },
+                    { CDF3(19557, 31164, 32454) },
+                    { CDF3(13381, 26381, 30755) },
+                    { CDF3(10101, 21466, 26722) },
+                    { CDF3( 9209, 19650, 26825) },
+                    { CDF3(27107, 31917, 32432) },
+                    { CDF3(18056, 28893, 31203) },
+                    { CDF3(10200, 21434, 26764) },
+                    { CDF3( 4660, 12913, 19502) },
+                    { CDF3( 2368,  6930, 12504) },
+                    { CDF3(26960, 32158, 32613) },
+                    { CDF3(18628, 30005, 32031) },
+                    { CDF3(10233, 22442, 28232) },
+                    { CDF3( 5471, 14630, 21516) },
+                    { CDF3( 3235, 10767, 17109) },
+                    { CDF3(27696, 32440, 32692) },
+                    { CDF3(20032, 31167, 32438) },
+                    { CDF3( 8700, 21341, 28442) },
+                    { CDF3( 5662, 14831, 21795) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            }, {
+                {
+                    { CDF3( 9704, 17294, 21132) },
+                    { CDF3(26762, 32278, 32633) },
+                    { CDF3(18382, 29620, 31819) },
+                    { CDF3(10891, 23475, 28723) },
+                    { CDF3( 6358, 16583, 23309) },
+                    { CDF3( 3248,  9118, 14141) },
+                    { CDF3(27204, 32573, 32699) },
+                    { CDF3(19818, 30824, 32329) },
+                    { CDF3(11772, 25120, 30041) },
+                    { CDF3( 6995, 18033, 25039) },
+                    { CDF3( 3752, 10442, 16098) },
+                    { CDF3(27222, 32256, 32559) },
+                    { CDF3(15356, 28399, 31475) },
+                    { CDF3( 8821, 20635, 27057) },
+                    { CDF3( 5511, 14404, 21239) },
+                    { CDF3( 2935,  8222, 13051) },
+                    { CDF3(24875, 32120, 32529) },
+                    { CDF3(15233, 28265, 31445) },
+                    { CDF3( 8605, 20570, 26932) },
+                    { CDF3( 5431, 14413, 21196) },
+                    { CDF3( 2994,  8341, 13223) },
+                    { CDF3(28201, 32604, 32700) },
+                    { CDF3(21041, 31446, 32456) },
+                    { CDF3(13221, 26213, 30475) },
+                    { CDF3( 8255, 19385, 26037) },
+                    { CDF3( 4930, 12585, 18830) },
+                    { CDF3(28768, 32448, 32627) },
+                    { CDF3(19705, 30561, 32021) },
+                    { CDF3(11572, 23589, 28220) },
+                    { CDF3( 5532, 15034, 21446) },
+                    { CDF3( 2460,  7150, 11456) },
+                    { CDF3(29874, 32619, 32699) },
+                    { CDF3(21621, 31071, 32201) },
+                    { CDF3(12511, 24747, 28992) },
+                    { CDF3( 6281, 16395, 22748) },
+                    { CDF3( 3246,  9278, 14497) },
+                    { CDF3(29715, 32625, 32712) },
+                    { CDF3(20958, 31011, 32283) },
+                    { CDF3(11233, 23671, 28806) },
+                    { CDF3( 6012, 16128, 22868) },
+                    { CDF3( 3427,  9851, 15414) },
+                }, {
+                    { CDF3(11016, 22111, 26794) },
+                    { CDF3(25946, 32357, 32677) },
+                    { CDF3(17890, 30452, 32252) },
+                    { CDF3(11678, 25142, 29816) },
+                    { CDF3( 6720, 17534, 24584) },
+                    { CDF3( 4230, 11665, 17820) },
+                    { CDF3(28400, 32623, 32747) },
+                    { CDF3(21164, 31668, 32575) },
+                    { CDF3(13572, 27388, 31182) },
+                    { CDF3( 8234, 20750, 27358) },
+                    { CDF3( 5065, 14055, 20897) },
+                    { CDF3(28981, 32547, 32705) },
+                    { CDF3(18681, 30543, 32239) },
+                    { CDF3(10919, 24075, 29286) },
+                    { CDF3( 6431, 17199, 24077) },
+                    { CDF3( 3819, 10464, 16618) },
+                    { CDF3(26870, 32467, 32693) },
+                    { CDF3(19041, 30831, 32347) },
+                    { CDF3(11794, 25211, 30016) },
+                    { CDF3( 6888, 18019, 24970) },
+                    { CDF3( 4370, 12363, 18992) },
+                    { CDF3(29578, 32670, 32744) },
+                    { CDF3(23159, 32007, 32613) },
+                    { CDF3(15315, 28669, 31676) },
+                    { CDF3( 9298, 22607, 28782) },
+                    { CDF3( 6144, 15913, 22968) },
+                    { CDF3(28110, 32499, 32669) },
+                    { CDF3(21574, 30937, 32015) },
+                    { CDF3(12759, 24818, 28727) },
+                    { CDF3( 6545, 16761, 23042) },
+                    { CDF3( 3649, 10597, 16833) },
+                    { CDF3(28163, 32552, 32728) },
+                    { CDF3(22101, 31469, 32464) },
+                    { CDF3(13160, 25472, 30143) },
+                    { CDF3( 7303, 18684, 25468) },
+                    { CDF3( 5241, 13975, 20955) },
+                    { CDF3(28400, 32631, 32744) },
+                    { CDF3(22104, 31793, 32603) },
+                    { CDF3(13557, 26571, 30846) },
+                    { CDF3( 7749, 19861, 26675) },
+                    { CDF3( 4873, 14030, 21234) },
+                },
+            }, {
+                {
+                    { CDF3( 9800, 17635, 21073) },
+                    { CDF3(26153, 31885, 32527) },
+                    { CDF3(15038, 27852, 31006) },
+                    { CDF3( 8718, 20564, 26486) },
+                    { CDF3( 5128, 14076, 20514) },
+                    { CDF3( 2636,  7566, 11925) },
+                    { CDF3(27551, 32504, 32701) },
+                    { CDF3(18310, 30054, 32100) },
+                    { CDF3(10211, 23420, 29082) },
+                    { CDF3( 6222, 16876, 23916) },
+                    { CDF3( 3462,  9954, 15498) },
+                    { CDF3(29991, 32633, 32721) },
+                    { CDF3(19883, 30751, 32201) },
+                    { CDF3(11141, 24184, 29285) },
+                    { CDF3( 6420, 16940, 23774) },
+                    { CDF3( 3392,  9753, 15118) },
+                    { CDF3(28465, 32616, 32712) },
+                    { CDF3(19850, 30702, 32244) },
+                    { CDF3(10983, 24024, 29223) },
+                    { CDF3( 6294, 16770, 23582) },
+                    { CDF3( 3244,  9283, 14509) },
+                    { CDF3(30023, 32717, 32748) },
+                    { CDF3(22940, 32032, 32626) },
+                    { CDF3(14282, 27928, 31473) },
+                    { CDF3( 8562, 21327, 27914) },
+                    { CDF3( 4846, 13393, 19919) },
+                    { CDF3(29981, 32590, 32695) },
+                    { CDF3(20465, 30963, 32166) },
+                    { CDF3(11479, 23579, 28195) },
+                    { CDF3( 5916, 15648, 22073) },
+                    { CDF3( 3031,  8605, 13398) },
+                    { CDF3(31146, 32691, 32739) },
+                    { CDF3(23106, 31724, 32444) },
+                    { CDF3(13783, 26738, 30439) },
+                    { CDF3( 7852, 19468, 25807) },
+                    { CDF3( 3860, 11124, 16853) },
+                    { CDF3(31014, 32724, 32748) },
+                    { CDF3(23629, 32109, 32628) },
+                    { CDF3(14747, 28115, 31403) },
+                    { CDF3( 8545, 21242, 27478) },
+                    { CDF3( 4574, 12781, 19067) },
+                }, {
+                    { CDF3( 9185, 19694, 24688) },
+                    { CDF3(26081, 31985, 32621) },
+                    { CDF3(16015, 29000, 31787) },
+                    { CDF3(10542, 23690, 29206) },
+                    { CDF3( 6732, 17945, 24677) },
+                    { CDF3( 3916, 11039, 16722) },
+                    { CDF3(28224, 32566, 32744) },
+                    { CDF3(19100, 31138, 32485) },
+                    { CDF3(12528, 26620, 30879) },
+                    { CDF3( 7741, 20277, 26885) },
+                    { CDF3( 4566, 12845, 18990) },
+                    { CDF3(29933, 32593, 32718) },
+                    { CDF3(17670, 30333, 32155) },
+                    { CDF3(10385, 23600, 28909) },
+                    { CDF3( 6243, 16236, 22407) },
+                    { CDF3( 3976, 10389, 16017) },
+                    { CDF3(28377, 32561, 32738) },
+                    { CDF3(19366, 31175, 32482) },
+                    { CDF3(13327, 27175, 31094) },
+                    { CDF3( 8258, 20769, 27143) },
+                    { CDF3( 4703, 13198, 19527) },
+                    { CDF3(31086, 32706, 32748) },
+                    { CDF3(22853, 31902, 32583) },
+                    { CDF3(14759, 28186, 31419) },
+                    { CDF3( 9284, 22382, 28348) },
+                    { CDF3( 5585, 15192, 21868) },
+                    { CDF3(28291, 32652, 32746) },
+                    { CDF3(19849, 32107, 32571) },
+                    { CDF3(14834, 26818, 29214) },
+                    { CDF3(10306, 22594, 28672) },
+                    { CDF3( 6615, 17384, 23384) },
+                    { CDF3(28947, 32604, 32745) },
+                    { CDF3(25625, 32289, 32646) },
+                    { CDF3(18758, 28672, 31403) },
+                    { CDF3(10017, 23430, 28523) },
+                    { CDF3( 6862, 15269, 22131) },
+                    { CDF3(23933, 32509, 32739) },
+                    { CDF3(19927, 31495, 32631) },
+                    { CDF3(11903, 26023, 30621) },
+                    { CDF3( 7026, 20094, 27252) },
+                    { CDF3( 5998, 18106, 24437) },
+                },
+            }, {
+                {
+                    { CDF3( 4456, 11274, 15533) },
+                    { CDF3(21219, 29079, 31616) },
+                    { CDF3(11173, 23774, 28567) },
+                    { CDF3( 7282, 18293, 24263) },
+                    { CDF3( 4890, 13286, 19115) },
+                    { CDF3( 1890,  5508,  8659) },
+                    { CDF3(26651, 32136, 32647) },
+                    { CDF3(14630, 28254, 31455) },
+                    { CDF3( 8716, 21287, 27395) },
+                    { CDF3( 5615, 15331, 22008) },
+                    { CDF3( 2675,  7700, 12150) },
+                    { CDF3(29954, 32526, 32690) },
+                    { CDF3(16126, 28982, 31633) },
+                    { CDF3( 9030, 21361, 27352) },
+                    { CDF3( 5411, 14793, 21271) },
+                    { CDF3( 2943,  8422, 13163) },
+                    { CDF3(29539, 32601, 32730) },
+                    { CDF3(18125, 30385, 32201) },
+                    { CDF3(10422, 24090, 29468) },
+                    { CDF3( 6468, 17487, 24438) },
+                    { CDF3( 2970,  8653, 13531) },
+                    { CDF3(30912, 32715, 32748) },
+                    { CDF3(20666, 31373, 32497) },
+                    { CDF3(12509, 26640, 30917) },
+                    { CDF3( 8058, 20629, 27290) },
+                    { CDF3( 4231, 12006, 18052) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3(10202, 20633, 25484) },
+                    { CDF3(27336, 31445, 32352) },
+                    { CDF3(12420, 24384, 28552) },
+                    { CDF3( 7648, 18115, 23856) },
+                    { CDF3( 5662, 14341, 19902) },
+                    { CDF3( 3611, 10328, 15390) },
+                    { CDF3(30945, 32616, 32736) },
+                    { CDF3(18682, 30505, 32253) },
+                    { CDF3(11513, 25336, 30203) },
+                    { CDF3( 7449, 19452, 26148) },
+                    { CDF3( 4482, 13051, 18886) },
+                    { CDF3(32022, 32690, 32747) },
+                    { CDF3(18578, 30501, 32146) },
+                    { CDF3(11249, 23368, 28631) },
+                    { CDF3( 5645, 16958, 22158) },
+                    { CDF3( 5009, 11444, 16637) },
+                    { CDF3(31357, 32710, 32748) },
+                    { CDF3(21552, 31494, 32504) },
+                    { CDF3(13891, 27677, 31340) },
+                    { CDF3( 9051, 22098, 28172) },
+                    { CDF3( 5190, 13377, 19486) },
+                    { CDF3(32364, 32740, 32748) },
+                    { CDF3(24839, 31907, 32551) },
+                    { CDF3(17160, 28779, 31696) },
+                    { CDF3(12452, 24137, 29602) },
+                    { CDF3( 6165, 15389, 22477) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            }, {
+                {
+                    { CDF3( 2575,  7281, 11077) },
+                    { CDF3(14002, 20866, 25402) },
+                    { CDF3( 6343, 15056, 19658) },
+                    { CDF3( 4474, 11858, 17041) },
+                    { CDF3( 2865,  8299, 12534) },
+                    { CDF3( 1344,  3949,  6391) },
+                    { CDF3(24720, 31239, 32459) },
+                    { CDF3(12585, 25356, 29968) },
+                    { CDF3( 7181, 18246, 24444) },
+                    { CDF3( 5025, 13667, 19885) },
+                    { CDF3( 2521,  7304, 11605) },
+                    { CDF3(29908, 32252, 32584) },
+                    { CDF3(17421, 29156, 31575) },
+                    { CDF3( 9889, 22188, 27782) },
+                    { CDF3( 5878, 15647, 22123) },
+                    { CDF3( 2814,  8665, 13323) },
+                    { CDF3(30183, 32568, 32713) },
+                    { CDF3(18528, 30195, 32049) },
+                    { CDF3(10982, 24606, 29657) },
+                    { CDF3( 6957, 18165, 25231) },
+                    { CDF3( 3508, 10118, 15468) },
+                    { CDF3(31761, 32736, 32748) },
+                    { CDF3(21041, 31328, 32546) },
+                    { CDF3(12568, 26732, 31166) },
+                    { CDF3( 8052, 20720, 27733) },
+                    { CDF3( 4336, 12192, 18396) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            },
+        }, .dc_sign = {
+            { { CDF1(16000) }, { CDF1(13056) }, { CDF1(18816) } },
+            { { CDF1(15232) }, { CDF1(12928) }, { CDF1(17280) } },
+        }, .br_tok = {
+            {
+                {
+                    { CDF3(16138, 22223, 25509) },
+                    { CDF3(15347, 22430, 26332) },
+                    { CDF3( 9614, 16736, 21332) },
+                    { CDF3( 6600, 12275, 16907) },
+                    { CDF3( 4811,  9424, 13547) },
+                    { CDF3( 3748,  7809, 11420) },
+                    { CDF3( 2254,  4587,  6890) },
+                    { CDF3(15196, 20284, 23177) },
+                    { CDF3(18317, 25469, 28451) },
+                    { CDF3(13918, 21651, 25842) },
+                    { CDF3(10052, 17150, 21995) },
+                    { CDF3( 7499, 13630, 18587) },
+                    { CDF3( 6158, 11417, 16003) },
+                    { CDF3( 4014,  7785, 11252) },
+                    { CDF3(15048, 21067, 24384) },
+                    { CDF3(18202, 25346, 28553) },
+                    { CDF3(14302, 22019, 26356) },
+                    { CDF3(10839, 18139, 23166) },
+                    { CDF3( 8715, 15744, 20806) },
+                    { CDF3( 7536, 13576, 18544) },
+                    { CDF3( 5413, 10335, 14498) },
+                }, {
+                    { CDF3(17394, 24501, 27895) },
+                    { CDF3(15889, 23420, 27185) },
+                    { CDF3(11561, 19133, 23870) },
+                    { CDF3( 8285, 14812, 19844) },
+                    { CDF3( 6496, 12043, 16550) },
+                    { CDF3( 4771,  9574, 13677) },
+                    { CDF3( 3603,  6830, 10144) },
+                    { CDF3(21656, 27704, 30200) },
+                    { CDF3(21324, 27915, 30511) },
+                    { CDF3(17327, 25336, 28997) },
+                    { CDF3(13417, 21381, 26033) },
+                    { CDF3(10132, 17425, 22338) },
+                    { CDF3( 8580, 15016, 19633) },
+                    { CDF3( 5694, 11477, 16411) },
+                    { CDF3(24116, 29780, 31450) },
+                    { CDF3(23853, 29695, 31591) },
+                    { CDF3(20085, 27614, 30428) },
+                    { CDF3(15326, 24335, 28575) },
+                    { CDF3(11814, 19472, 24810) },
+                    { CDF3(10221, 18611, 24767) },
+                    { CDF3( 7689, 14558, 20321) },
+                },
+            }, {
+                {
+                    { CDF3(16214, 22380, 25770) },
+                    { CDF3(14213, 21304, 25295) },
+                    { CDF3( 9213, 15823, 20455) },
+                    { CDF3( 6395, 11758, 16139) },
+                    { CDF3( 4779,  9187, 13066) },
+                    { CDF3( 3821,  7501, 10953) },
+                    { CDF3( 2293,  4567,  6795) },
+                    { CDF3(15859, 21283, 23820) },
+                    { CDF3(18404, 25602, 28726) },
+                    { CDF3(14325, 21980, 26206) },
+                    { CDF3(10669, 17937, 22720) },
+                    { CDF3( 8297, 14642, 19447) },
+                    { CDF3( 6746, 12389, 16893) },
+                    { CDF3( 4324,  8251, 11770) },
+                    { CDF3(16532, 21631, 24475) },
+                    { CDF3(20667, 27150, 29668) },
+                    { CDF3(16728, 24510, 28175) },
+                    { CDF3(12861, 20645, 25332) },
+                    { CDF3(10076, 17361, 22417) },
+                    { CDF3( 8395, 14940, 19963) },
+                    { CDF3( 5731, 10683, 14912) },
+                }, {
+                    { CDF3(14433, 21155, 24938) },
+                    { CDF3(14658, 21716, 25545) },
+                    { CDF3( 9923, 16824, 21557) },
+                    { CDF3( 6982, 13052, 17721) },
+                    { CDF3( 5419, 10503, 15050) },
+                    { CDF3( 4852,  9162, 13014) },
+                    { CDF3( 3271,  6395,  9630) },
+                    { CDF3(22210, 27833, 30109) },
+                    { CDF3(20750, 27368, 29821) },
+                    { CDF3(16894, 24828, 28573) },
+                    { CDF3(13247, 21276, 25757) },
+                    { CDF3(10038, 17265, 22563) },
+                    { CDF3( 8587, 14947, 20327) },
+                    { CDF3( 5645, 11371, 15252) },
+                    { CDF3(22027, 27526, 29714) },
+                    { CDF3(23098, 29146, 31221) },
+                    { CDF3(19886, 27341, 30272) },
+                    { CDF3(15609, 23747, 28046) },
+                    { CDF3(11993, 20065, 24939) },
+                    { CDF3( 9637, 18267, 23671) },
+                    { CDF3( 7625, 13801, 19144) },
+                },
+            }, {
+                {
+                    { CDF3(14438, 20798, 24089) },
+                    { CDF3(12621, 19203, 23097) },
+                    { CDF3( 8177, 14125, 18402) },
+                    { CDF3( 5674, 10501, 14456) },
+                    { CDF3( 4236,  8239, 11733) },
+                    { CDF3( 3447,  6750,  9806) },
+                    { CDF3( 1986,  3950,  5864) },
+                    { CDF3(16208, 22099, 24930) },
+                    { CDF3(16537, 24025, 27585) },
+                    { CDF3(12780, 20381, 24867) },
+                    { CDF3( 9767, 16612, 21416) },
+                    { CDF3( 7686, 13738, 18398) },
+                    { CDF3( 6333, 11614, 15964) },
+                    { CDF3( 3941,  7571, 10836) },
+                    { CDF3(22819, 27422, 29202) },
+                    { CDF3(22224, 28514, 30721) },
+                    { CDF3(17660, 25433, 28913) },
+                    { CDF3(13574, 21482, 26002) },
+                    { CDF3(10629, 17977, 22938) },
+                    { CDF3( 8612, 15298, 20265) },
+                    { CDF3( 5607, 10491, 14596) },
+                }, {
+                    { CDF3(13569, 19800, 23206) },
+                    { CDF3(13128, 19924, 23869) },
+                    { CDF3( 8329, 14841, 19403) },
+                    { CDF3( 6130, 10976, 15057) },
+                    { CDF3( 4682,  8839, 12518) },
+                    { CDF3( 3656,  7409, 10588) },
+                    { CDF3( 2577,  5099,  7412) },
+                    { CDF3(22427, 28684, 30585) },
+                    { CDF3(20913, 27750, 30139) },
+                    { CDF3(15840, 24109, 27834) },
+                    { CDF3(12308, 20029, 24569) },
+                    { CDF3(10216, 16785, 21458) },
+                    { CDF3( 8309, 14203, 19113) },
+                    { CDF3( 6043, 11168, 15307) },
+                    { CDF3(23166, 28901, 30998) },
+                    { CDF3(21899, 28405, 30751) },
+                    { CDF3(18413, 26091, 29443) },
+                    { CDF3(15233, 23114, 27352) },
+                    { CDF3(12683, 20472, 25288) },
+                    { CDF3(10702, 18259, 23409) },
+                    { CDF3( 8125, 14464, 19226) },
+                },
+            }, {
+                {
+                    { CDF3( 9040, 14786, 18360) },
+                    { CDF3( 9979, 15718, 19415) },
+                    { CDF3( 7913, 13918, 18311) },
+                    { CDF3( 5859, 10889, 15184) },
+                    { CDF3( 4593,  8677, 12510) },
+                    { CDF3( 3820,  7396, 10791) },
+                    { CDF3( 1730,  3471,  5192) },
+                    { CDF3(11803, 18365, 22709) },
+                    { CDF3(11419, 18058, 22225) },
+                    { CDF3( 9418, 15774, 20243) },
+                    { CDF3( 7539, 13325, 17657) },
+                    { CDF3( 6233, 11317, 15384) },
+                    { CDF3( 5137,  9656, 13545) },
+                    { CDF3( 2977,  5774,  8349) },
+                    { CDF3(21207, 27246, 29640) },
+                    { CDF3(19547, 26578, 29497) },
+                    { CDF3(16169, 23871, 27690) },
+                    { CDF3(12820, 20458, 25018) },
+                    { CDF3(10224, 17332, 22214) },
+                    { CDF3( 8526, 15048, 19884) },
+                    { CDF3( 5037,  9410, 13118) },
+                }, {
+                    { CDF3(12339, 17329, 20140) },
+                    { CDF3(13505, 19895, 23225) },
+                    { CDF3( 9847, 16944, 21564) },
+                    { CDF3( 7280, 13256, 18348) },
+                    { CDF3( 4712, 10009, 14454) },
+                    { CDF3( 4361,  7914, 12477) },
+                    { CDF3( 2870,  5628,  7995) },
+                    { CDF3(20061, 25504, 28526) },
+                    { CDF3(15235, 22878, 26145) },
+                    { CDF3(12985, 19958, 24155) },
+                    { CDF3( 9782, 16641, 21403) },
+                    { CDF3( 9456, 16360, 20760) },
+                    { CDF3( 6855, 12940, 18557) },
+                    { CDF3( 5661, 10564, 15002) },
+                    { CDF3(25656, 30602, 31894) },
+                    { CDF3(22570, 29107, 31092) },
+                    { CDF3(18917, 26423, 29541) },
+                    { CDF3(15940, 23649, 27754) },
+                    { CDF3(12803, 20581, 25219) },
+                    { CDF3(11082, 18695, 23376) },
+                    { CDF3( 7939, 14373, 19005) },
+                },
+            },
+        },
+    }, [3] = {
+        .skip = {
+            {
+                { CDF1(26887) }, { CDF1( 6729) }, { CDF1(10361) },
+                { CDF1(17442) }, { CDF1(15045) }, { CDF1(22478) },
+                { CDF1(29072) }, { CDF1( 2713) }, { CDF1(11861) },
+                { CDF1(20773) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(31903) }, { CDF1( 2044) }, { CDF1( 7528) },
+                { CDF1(14618) }, { CDF1(16182) }, { CDF1(24168) },
+                { CDF1(31037) }, { CDF1( 2786) }, { CDF1(11194) },
+                { CDF1(20155) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(32510) }, { CDF1( 8430) }, { CDF1(17318) },
+                { CDF1(24154) }, { CDF1(23674) }, { CDF1(28789) },
+                { CDF1(32139) }, { CDF1( 3440) }, { CDF1(13117) },
+                { CDF1(22702) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            }, {
+                { CDF1(31671) }, { CDF1( 2056) }, { CDF1(11746) },
+                { CDF1(16852) }, { CDF1(18635) }, { CDF1(24715) },
+                { CDF1(31484) }, { CDF1( 4656) }, { CDF1(16074) },
+                { CDF1(24704) }, { CDF1( 1806) }, { CDF1(14645) },
+                { CDF1(25336) },
+            }, {
+                { CDF1(31539) }, { CDF1( 8433) }, { CDF1(20576) },
+                { CDF1(27904) }, { CDF1(27852) }, { CDF1(30026) },
+                { CDF1(32441) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                { CDF1(16384) },
+            },
+        }, .eob_bin_16 = {
+            {
+                { CDF4( 6708,  8958, 14746, 22133) },
+                { CDF4( 1222,  2074,  4783, 15410) },
+            }, {
+                { CDF4(19575, 21766, 26044, 29709) },
+                { CDF4( 7297, 10767, 19273, 28194) },
+            },
+        }, .eob_bin_32 = {
+            {
+                { CDF5( 4617,  5709,  8446, 13584, 23135) },
+                { CDF5( 1156,  1702,  3675,  9274, 20539) },
+            }, {
+                { CDF5(22086, 24282, 27010, 29770, 31743) },
+                { CDF5( 7699, 10897, 20891, 26926, 31628) },
+            },
+        }, .eob_bin_64 = {
+            {
+                { CDF6( 6307,  7541, 12060, 16358, 22553, 27865) },
+                { CDF6( 1289,  2320,  3971,  7926, 14153, 24291) },
+            }, {
+                { CDF6(24212, 25708, 28268, 30035, 31307, 32049) },
+                { CDF6( 8726, 12378, 19409, 26450, 30038, 32462) },
+            },
+        }, .eob_bin_128 = {
+            {
+                { CDF7( 3472,  4885,  7489, 12481, 18517, 24536, 29635) },
+                { CDF7(  886,  1731,  3271,  8469, 15569, 22126, 28383) },
+            }, {
+                { CDF7(24313, 26062, 28385, 30107, 31217, 31898, 32345) },
+                { CDF7( 9165, 13282, 21150, 30286, 31894, 32571, 32712) },
+            },
+        }, .eob_bin_256 = {
+            {
+                { CDF8( 5348,  7113, 11820, 15924,
+                       22106, 26777, 30334, 31757) },
+                { CDF8( 2453,  4474,  6307,  8777,
+                       16474, 22975, 29000, 31547) },
+            }, {
+                { CDF8(23110, 24597, 27140, 28894,
+                       30167, 30927, 31392, 32094) },
+                { CDF8( 9998, 17661, 25178, 28097,
+                       31308, 32038, 32403, 32695) },
+            },
+        }, .eob_bin_512 = {
+            { CDF9( 5927,  7809, 10923, 14597, 19439,
+                   24135, 28456, 31142, 32060) },
+            { CDF9(21093, 23043, 25742, 27658, 29097,
+                   29716, 30073, 30820, 31956) },
+        }, .eob_bin_1024 = {
+            { CDF10( 6698,  8334, 11961, 15762, 20186,
+                    23862, 27434, 29326, 31082, 32050) },
+            { CDF10(20569, 22426, 25569, 26859, 28053,
+                    28913, 29486, 29724, 29807, 32570) },
+        }, .eob_hi_bit = {
+            {
+                {
+                    { CDF1(20177) }, { CDF1(20789) }, { CDF1(20262) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(21416) }, { CDF1(20855) }, { CDF1(23410) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(20238) }, { CDF1(21057) }, { CDF1(19159) },
+                    { CDF1(22337) }, { CDF1(20159) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(20125) }, { CDF1(20559) }, { CDF1(21707) },
+                    { CDF1(22296) }, { CDF1(17333) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(19941) }, { CDF1(20527) }, { CDF1(21470) },
+                    { CDF1(22487) }, { CDF1(19558) }, { CDF1(22354) },
+                    { CDF1(20331) }, { CDF1(16384) }, { CDF1(16384) },
+                }, {
+                    { CDF1(22752) }, { CDF1(25006) }, { CDF1(22075) },
+                    { CDF1(21576) }, { CDF1(17740) }, { CDF1(21690) },
+                    { CDF1(19211) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            }, {
+                {
+                    { CDF1(21442) }, { CDF1(22358) }, { CDF1(18503) },
+                    { CDF1(20291) }, { CDF1(19945) }, { CDF1(21294) },
+                    { CDF1(21178) }, { CDF1(19400) }, { CDF1(10556) },
+                }, {
+                    { CDF1(24648) }, { CDF1(24949) }, { CDF1(20708) },
+                    { CDF1(23905) }, { CDF1(20501) }, { CDF1( 9558) },
+                    { CDF1( 9423) }, { CDF1(30365) }, { CDF1(19253) },
+                },
+            }, {
+                {
+                    { CDF1(26064) }, { CDF1(22098) }, { CDF1(19613) },
+                    { CDF1(20525) }, { CDF1(17595) }, { CDF1(16618) },
+                    { CDF1(20497) }, { CDF1(18989) }, { CDF1(15513) },
+                }, {
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                    { CDF1(16384) }, { CDF1(16384) }, { CDF1(16384) },
+                },
+            },
+        }, .eob_base_tok = {
+            {
+                {
+                    { CDF2(22497, 31198) }, { CDF2(31715, 32495) },
+                    { CDF2(31606, 32337) }, { CDF2(30388, 31990) },
+                }, {
+                    { CDF2(27877, 31584) }, { CDF2(32170, 32728) },
+                    { CDF2(32155, 32688) }, { CDF2(32219, 32702) },
+                },
+            }, {
+                {
+                    { CDF2(21457, 31043) }, { CDF2(31951, 32483) },
+                    { CDF2(32153, 32562) }, { CDF2(31473, 32215) },
+                }, {
+                    { CDF2(27558, 31151) }, { CDF2(32020, 32640) },
+                    { CDF2(32097, 32575) }, { CDF2(32242, 32719) },
+                },
+            }, {
+                {
+                    { CDF2(19980, 30591) }, { CDF2(32219, 32597) },
+                    { CDF2(32581, 32706) }, { CDF2(31803, 32287) },
+                }, {
+                    { CDF2(26473, 30507) }, { CDF2(32431, 32723) },
+                    { CDF2(32196, 32611) }, { CDF2(31588, 32528) },
+                },
+            }, {
+                {
+                    { CDF2(24647, 30463) }, { CDF2(32412, 32695) },
+                    { CDF2(32468, 32720) }, { CDF2(31269, 32523) },
+                }, {
+                    { CDF2(28482, 31505) }, { CDF2(32152, 32701) },
+                    { CDF2(31732, 32598) }, { CDF2(31767, 32712) },
+                },
+            }, {
+                {
+                    { CDF2(12358, 24977) }, { CDF2(31331, 32385) },
+                    { CDF2(32634, 32756) }, { CDF2(30411, 32548) },
+                }, {
+                    { CDF2(10923, 21845) }, { CDF2(10923, 21845) },
+                    { CDF2(10923, 21845) }, { CDF2(10923, 21845) },
+                },
+            },
+        }, .base_tok = {
+            {
+                {
+                    { CDF3( 7062, 16472, 22319) },
+                    { CDF3(24538, 32261, 32674) },
+                    { CDF3(13675, 28041, 31779) },
+                    { CDF3( 8590, 20674, 27631) },
+                    { CDF3( 5685, 14675, 22013) },
+                    { CDF3( 3655,  9898, 15731) },
+                    { CDF3(26493, 32418, 32658) },
+                    { CDF3(16376, 29342, 32090) },
+                    { CDF3(10594, 22649, 28970) },
+                    { CDF3( 8176, 17170, 24303) },
+                    { CDF3( 5605, 12694, 19139) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3(23888, 31902, 32542) },
+                    { CDF3(18612, 29687, 31987) },
+                    { CDF3(16245, 24852, 29249) },
+                    { CDF3(15765, 22608, 27559) },
+                    { CDF3(19895, 24699, 27510) },
+                    { CDF3(28401, 32212, 32457) },
+                    { CDF3(15274, 27825, 30980) },
+                    { CDF3( 9364, 18128, 24332) },
+                    { CDF3( 2283,  8193, 15082) },
+                    { CDF3( 1228,  3972,  7881) },
+                    { CDF3(29455, 32469, 32620) },
+                    { CDF3(17981, 28245, 31388) },
+                    { CDF3(10921, 20098, 26240) },
+                    { CDF3( 3743, 11829, 18657) },
+                    { CDF3( 2374,  9593, 15715) },
+                    { CDF3(31068, 32466, 32635) },
+                    { CDF3(20321, 29572, 31971) },
+                    { CDF3(10771, 20255, 27119) },
+                    { CDF3( 2795, 10410, 17361) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 9320, 22102, 27840) },
+                    { CDF3(27057, 32464, 32724) },
+                    { CDF3(16331, 30268, 32309) },
+                    { CDF3(10319, 23935, 29720) },
+                    { CDF3( 6189, 16448, 24106) },
+                    { CDF3( 3589, 10884, 18808) },
+                    { CDF3(29026, 32624, 32748) },
+                    { CDF3(19226, 31507, 32587) },
+                    { CDF3(12692, 26921, 31203) },
+                    { CDF3( 7049, 19532, 27635) },
+                    { CDF3( 7727, 15669, 23252) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3(28056, 32625, 32748) },
+                    { CDF3(22383, 32075, 32669) },
+                    { CDF3(15417, 27098, 31749) },
+                    { CDF3(18127, 26493, 27190) },
+                    { CDF3( 5461, 16384, 21845) },
+                    { CDF3(27982, 32091, 32584) },
+                    { CDF3(19045, 29868, 31972) },
+                    { CDF3(10397, 22266, 27932) },
+                    { CDF3( 5990, 13697, 21500) },
+                    { CDF3( 1792,  6912, 15104) },
+                    { CDF3(28198, 32501, 32718) },
+                    { CDF3(21534, 31521, 32569) },
+                    { CDF3(11109, 25217, 30017) },
+                    { CDF3( 5671, 15124, 26151) },
+                    { CDF3( 4681, 14043, 18725) },
+                    { CDF3(28688, 32580, 32741) },
+                    { CDF3(22576, 32079, 32661) },
+                    { CDF3(10627, 22141, 28340) },
+                    { CDF3( 9362, 14043, 28087) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            }, {
+                {
+                    { CDF3( 7754, 16948, 22142) },
+                    { CDF3(25670, 32330, 32691) },
+                    { CDF3(15663, 29225, 31994) },
+                    { CDF3( 9878, 23288, 29158) },
+                    { CDF3( 6419, 17088, 24336) },
+                    { CDF3( 3859, 11003, 17039) },
+                    { CDF3(27562, 32595, 32725) },
+                    { CDF3(17575, 30588, 32399) },
+                    { CDF3(10819, 24838, 30309) },
+                    { CDF3( 7124, 18686, 25916) },
+                    { CDF3( 4479, 12688, 19340) },
+                    { CDF3(28385, 32476, 32673) },
+                    { CDF3(15306, 29005, 31938) },
+                    { CDF3( 8937, 21615, 28322) },
+                    { CDF3( 5982, 15603, 22786) },
+                    { CDF3( 3620, 10267, 16136) },
+                    { CDF3(27280, 32464, 32667) },
+                    { CDF3(15607, 29160, 32004) },
+                    { CDF3( 9091, 22135, 28740) },
+                    { CDF3( 6232, 16632, 24020) },
+                    { CDF3( 4047, 11377, 17672) },
+                    { CDF3(29220, 32630, 32718) },
+                    { CDF3(19650, 31220, 32462) },
+                    { CDF3(13050, 26312, 30827) },
+                    { CDF3( 9228, 20870, 27468) },
+                    { CDF3( 6146, 15149, 21971) },
+                    { CDF3(30169, 32481, 32623) },
+                    { CDF3(17212, 29311, 31554) },
+                    { CDF3( 9911, 21311, 26882) },
+                    { CDF3( 4487, 13314, 20372) },
+                    { CDF3( 2570,  7772, 12889) },
+                    { CDF3(30924, 32613, 32708) },
+                    { CDF3(19490, 30206, 32107) },
+                    { CDF3(11232, 23998, 29276) },
+                    { CDF3( 6769, 17955, 25035) },
+                    { CDF3( 4398, 12623, 19214) },
+                    { CDF3(30609, 32627, 32722) },
+                    { CDF3(19370, 30582, 32287) },
+                    { CDF3(10457, 23619, 29409) },
+                    { CDF3( 6443, 17637, 24834) },
+                    { CDF3( 4645, 13236, 20106) },
+                }, {
+                    { CDF3( 8626, 20271, 26216) },
+                    { CDF3(26707, 32406, 32711) },
+                    { CDF3(16999, 30329, 32286) },
+                    { CDF3(11445, 25123, 30286) },
+                    { CDF3( 6411, 18828, 25601) },
+                    { CDF3( 6801, 12458, 20248) },
+                    { CDF3(29918, 32682, 32748) },
+                    { CDF3(20649, 31739, 32618) },
+                    { CDF3(12879, 27773, 31581) },
+                    { CDF3( 7896, 21751, 28244) },
+                    { CDF3( 5260, 14870, 23698) },
+                    { CDF3(29252, 32593, 32731) },
+                    { CDF3(17072, 30460, 32294) },
+                    { CDF3(10653, 24143, 29365) },
+                    { CDF3( 6536, 17490, 23983) },
+                    { CDF3( 4929, 13170, 20085) },
+                    { CDF3(28137, 32518, 32715) },
+                    { CDF3(18171, 30784, 32407) },
+                    { CDF3(11437, 25436, 30459) },
+                    { CDF3( 7252, 18534, 26176) },
+                    { CDF3( 4126, 13353, 20978) },
+                    { CDF3(31162, 32726, 32748) },
+                    { CDF3(23017, 32222, 32701) },
+                    { CDF3(15629, 29233, 32046) },
+                    { CDF3( 9387, 22621, 29480) },
+                    { CDF3( 6922, 17616, 25010) },
+                    { CDF3(28838, 32265, 32614) },
+                    { CDF3(19701, 30206, 31920) },
+                    { CDF3(11214, 22410, 27933) },
+                    { CDF3( 5320, 14177, 23034) },
+                    { CDF3( 5049, 12881, 17827) },
+                    { CDF3(27484, 32471, 32734) },
+                    { CDF3(21076, 31526, 32561) },
+                    { CDF3(12707, 26303, 31211) },
+                    { CDF3( 8169, 21722, 28219) },
+                    { CDF3( 6045, 19406, 27042) },
+                    { CDF3(27753, 32572, 32745) },
+                    { CDF3(20832, 31878, 32653) },
+                    { CDF3(13250, 27356, 31674) },
+                    { CDF3( 7718, 21508, 29858) },
+                    { CDF3( 7209, 18350, 25559) },
+                },
+            }, {
+                {
+                    { CDF3( 7876, 16901, 21741) },
+                    { CDF3(24001, 31898, 32625) },
+                    { CDF3(14529, 27959, 31451) },
+                    { CDF3( 8273, 20818, 27258) },
+                    { CDF3( 5278, 14673, 21510) },
+                    { CDF3( 2983,  8843, 14039) },
+                    { CDF3(28016, 32574, 32732) },
+                    { CDF3(17471, 30306, 32301) },
+                    { CDF3(10224, 24063, 29728) },
+                    { CDF3( 6602, 17954, 25052) },
+                    { CDF3( 4002, 11585, 17759) },
+                    { CDF3(30190, 32634, 32739) },
+                    { CDF3(17497, 30282, 32270) },
+                    { CDF3(10229, 23729, 29538) },
+                    { CDF3( 6344, 17211, 24440) },
+                    { CDF3( 3849, 11189, 17108) },
+                    { CDF3(28570, 32583, 32726) },
+                    { CDF3(17521, 30161, 32238) },
+                    { CDF3(10153, 23565, 29378) },
+                    { CDF3( 6455, 17341, 24443) },
+                    { CDF3( 3907, 11042, 17024) },
+                    { CDF3(30689, 32715, 32748) },
+                    { CDF3(21546, 31840, 32610) },
+                    { CDF3(13547, 27581, 31459) },
+                    { CDF3( 8912, 21757, 28309) },
+                    { CDF3( 5548, 15080, 22046) },
+                    { CDF3(30783, 32540, 32685) },
+                    { CDF3(17540, 29528, 31668) },
+                    { CDF3(10160, 21468, 26783) },
+                    { CDF3( 4724, 13393, 20054) },
+                    { CDF3( 2702,  8174, 13102) },
+                    { CDF3(31648, 32686, 32742) },
+                    { CDF3(20954, 31094, 32337) },
+                    { CDF3(12420, 25698, 30179) },
+                    { CDF3( 7304, 19320, 26248) },
+                    { CDF3( 4366, 12261, 18864) },
+                    { CDF3(31581, 32723, 32748) },
+                    { CDF3(21373, 31586, 32525) },
+                    { CDF3(12744, 26625, 30885) },
+                    { CDF3( 7431, 20322, 26950) },
+                    { CDF3( 4692, 13323, 20111) },
+                }, {
+                    { CDF3( 7833, 18369, 24095) },
+                    { CDF3(26650, 32273, 32702) },
+                    { CDF3(16371, 29961, 32191) },
+                    { CDF3(11055, 24082, 29629) },
+                    { CDF3( 6892, 18644, 25400) },
+                    { CDF3( 5006, 13057, 19240) },
+                    { CDF3(29834, 32666, 32748) },
+                    { CDF3(19577, 31335, 32570) },
+                    { CDF3(12253, 26509, 31122) },
+                    { CDF3( 7991, 20772, 27711) },
+                    { CDF3( 5677, 15910, 23059) },
+                    { CDF3(30109, 32532, 32720) },
+                    { CDF3(16747, 30166, 32252) },
+                    { CDF3(10134, 23542, 29184) },
+                    { CDF3( 5791, 16176, 23556) },
+                    { CDF3( 4362, 10414, 17284) },
+                    { CDF3(29492, 32626, 32748) },
+                    { CDF3(19894, 31402, 32525) },
+                    { CDF3(12942, 27071, 30869) },
+                    { CDF3( 8346, 21216, 27405) },
+                    { CDF3( 6572, 17087, 23859) },
+                    { CDF3(32035, 32735, 32748) },
+                    { CDF3(22957, 31838, 32618) },
+                    { CDF3(14724, 28572, 31772) },
+                    { CDF3(10364, 23999, 29553) },
+                    { CDF3( 7004, 18433, 25655) },
+                    { CDF3(27528, 32277, 32681) },
+                    { CDF3(16959, 31171, 32096) },
+                    { CDF3(10486, 23593, 27962) },
+                    { CDF3( 8192, 16384, 23211) },
+                    { CDF3( 8937, 17873, 20852) },
+                    { CDF3(27715, 32002, 32615) },
+                    { CDF3(15073, 29491, 31676) },
+                    { CDF3(11264, 24576, 28672) },
+                    { CDF3( 2341, 18725, 23406) },
+                    { CDF3( 7282, 18204, 25486) },
+                    { CDF3(28547, 32213, 32657) },
+                    { CDF3(20788, 29773, 32239) },
+                    { CDF3( 6780, 21469, 30508) },
+                    { CDF3( 5958, 14895, 23831) },
+                    { CDF3(16384, 21845, 27307) },
+                },
+            }, {
+                {
+                    { CDF3( 5992, 14304, 19765) },
+                    { CDF3(22612, 31238, 32456) },
+                    { CDF3(13456, 27162, 31087) },
+                    { CDF3( 8001, 20062, 26504) },
+                    { CDF3( 5168, 14105, 20764) },
+                    { CDF3( 2632,  7771, 12385) },
+                    { CDF3(27034, 32344, 32709) },
+                    { CDF3(15850, 29415, 31997) },
+                    { CDF3( 9494, 22776, 28841) },
+                    { CDF3( 6151, 16830, 23969) },
+                    { CDF3( 3461, 10039, 15722) },
+                    { CDF3(30134, 32569, 32731) },
+                    { CDF3(15638, 29422, 31945) },
+                    { CDF3( 9150, 21865, 28218) },
+                    { CDF3( 5647, 15719, 22676) },
+                    { CDF3( 3402,  9772, 15477) },
+                    { CDF3(28530, 32586, 32735) },
+                    { CDF3(17139, 30298, 32292) },
+                    { CDF3(10200, 24039, 29685) },
+                    { CDF3( 6419, 17674, 24786) },
+                    { CDF3( 3544, 10225, 15824) },
+                    { CDF3(31333, 32726, 32748) },
+                    { CDF3(20618, 31487, 32544) },
+                    { CDF3(12901, 27217, 31232) },
+                    { CDF3( 8624, 21734, 28171) },
+                    { CDF3( 5104, 14191, 20748) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3(11206, 21090, 26561) },
+                    { CDF3(28759, 32279, 32671) },
+                    { CDF3(14171, 27952, 31569) },
+                    { CDF3( 9743, 22907, 29141) },
+                    { CDF3( 6871, 17886, 24868) },
+                    { CDF3( 4960, 13152, 19315) },
+                    { CDF3(31077, 32661, 32748) },
+                    { CDF3(19400, 31195, 32515) },
+                    { CDF3(12752, 26858, 31040) },
+                    { CDF3( 8370, 22098, 28591) },
+                    { CDF3( 5457, 15373, 22298) },
+                    { CDF3(31697, 32706, 32748) },
+                    { CDF3(17860, 30657, 32333) },
+                    { CDF3(12510, 24812, 29261) },
+                    { CDF3( 6180, 19124, 24722) },
+                    { CDF3( 5041, 13548, 17959) },
+                    { CDF3(31552, 32716, 32748) },
+                    { CDF3(21908, 31769, 32623) },
+                    { CDF3(14470, 28201, 31565) },
+                    { CDF3( 9493, 22982, 28608) },
+                    { CDF3( 6858, 17240, 24137) },
+                    { CDF3(32543, 32752, 32756) },
+                    { CDF3(24286, 32097, 32666) },
+                    { CDF3(15958, 29217, 32024) },
+                    { CDF3(10207, 24234, 29958) },
+                    { CDF3( 6929, 18305, 25652) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            }, {
+                {
+                    { CDF3( 4137, 10847, 15682) },
+                    { CDF3(17824, 27001, 30058) },
+                    { CDF3(10204, 22796, 28291) },
+                    { CDF3( 6076, 15935, 22125) },
+                    { CDF3( 3852, 10937, 16816) },
+                    { CDF3( 2252,  6324, 10131) },
+                    { CDF3(25840, 32016, 32662) },
+                    { CDF3(15109, 28268, 31531) },
+                    { CDF3( 9385, 22231, 28340) },
+                    { CDF3( 6082, 16672, 23479) },
+                    { CDF3( 3318,  9427, 14681) },
+                    { CDF3(30594, 32574, 32718) },
+                    { CDF3(16836, 29552, 31859) },
+                    { CDF3( 9556, 22542, 28356) },
+                    { CDF3( 6305, 16725, 23540) },
+                    { CDF3( 3376,  9895, 15184) },
+                    { CDF3(29383, 32617, 32745) },
+                    { CDF3(18891, 30809, 32401) },
+                    { CDF3(11688, 25942, 30687) },
+                    { CDF3( 7468, 19469, 26651) },
+                    { CDF3( 3909, 11358, 17012) },
+                    { CDF3(31564, 32736, 32748) },
+                    { CDF3(20906, 31611, 32600) },
+                    { CDF3(13191, 27621, 31537) },
+                    { CDF3( 8768, 22029, 28676) },
+                    { CDF3( 5079, 14109, 20906) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                }, {
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                    { CDF3( 8192, 16384, 24576) },
+                },
+            },
+        }, .dc_sign = {
+            { { CDF1(16000) }, { CDF1(13056) }, { CDF1(18816) } },
+            { { CDF1(15232) }, { CDF1(12928) }, { CDF1(17280) } },
+        }, .br_tok = {
+            {
+                {
+                    { CDF3(18315, 24289, 27551) },
+                    { CDF3(16854, 24068, 27835) },
+                    { CDF3(10140, 17927, 23173) },
+                    { CDF3( 6722, 12982, 18267) },
+                    { CDF3( 4661,  9826, 14706) },
+                    { CDF3( 3832,  8165, 12294) },
+                    { CDF3( 2795,  6098,  9245) },
+                    { CDF3(17145, 23326, 26672) },
+                    { CDF3(20733, 27680, 30308) },
+                    { CDF3(16032, 24461, 28546) },
+                    { CDF3(11653, 20093, 25081) },
+                    { CDF3( 9290, 16429, 22086) },
+                    { CDF3( 7796, 14598, 19982) },
+                    { CDF3( 6502, 12378, 17441) },
+                    { CDF3(21681, 27732, 30320) },
+                    { CDF3(22389, 29044, 31261) },
+                    { CDF3(19027, 26731, 30087) },
+                    { CDF3(14739, 23755, 28624) },
+                    { CDF3(11358, 20778, 25511) },
+                    { CDF3(10995, 18073, 24190) },
+                    { CDF3( 9162, 14990, 20617) },
+                }, {
+                    { CDF3(21425, 27952, 30388) },
+                    { CDF3(18062, 25838, 29034) },
+                    { CDF3(11956, 19881, 24808) },
+                    { CDF3( 7718, 15000, 20980) },
+                    { CDF3( 5702, 11254, 16143) },
+                    { CDF3( 4898,  9088, 16864) },
+                    { CDF3( 3679,  6776, 11907) },
+                    { CDF3(23294, 30160, 31663) },
+                    { CDF3(24397, 29896, 31836) },
+                    { CDF3(19245, 27128, 30593) },
+                    { CDF3(13202, 19825, 26404) },
+                    { CDF3(11578, 19297, 23957) },
+                    { CDF3( 8073, 13297, 21370) },
+                    { CDF3( 5461, 10923, 19745) },
+                    { CDF3(27367, 30521, 31934) },
+                    { CDF3(24904, 30671, 31940) },
+                    { CDF3(23075, 28460, 31299) },
+                    { CDF3(14400, 23658, 30417) },
+                    { CDF3(13885, 23882, 28325) },
+                    { CDF3(14746, 22938, 27853) },
+                    { CDF3( 5461, 16384, 27307) },
+                },
+            }, {
+                {
+                    { CDF3(18274, 24813, 27890) },
+                    { CDF3(15537, 23149, 27003) },
+                    { CDF3( 9449, 16740, 21827) },
+                    { CDF3( 6700, 12498, 17261) },
+                    { CDF3( 4988,  9866, 14198) },
+                    { CDF3( 4236,  8147, 11902) },
+                    { CDF3( 2867,  5860,  8654) },
+                    { CDF3(17124, 23171, 26101) },
+                    { CDF3(20396, 27477, 30148) },
+                    { CDF3(16573, 24629, 28492) },
+                    { CDF3(12749, 20846, 25674) },
+                    { CDF3(10233, 17878, 22818) },
+                    { CDF3( 8525, 15332, 20363) },
+                    { CDF3( 6283, 11632, 16255) },
+                    { CDF3(20466, 26511, 29286) },
+                    { CDF3(23059, 29174, 31191) },
+                    { CDF3(19481, 27263, 30241) },
+                    { CDF3(15458, 23631, 28137) },
+                    { CDF3(12416, 20608, 25693) },
+                    { CDF3(10261, 18011, 23261) },
+                    { CDF3( 8016, 14655, 19666) },
+                }, {
+                    { CDF3(17616, 24586, 28112) },
+                    { CDF3(15809, 23299, 27155) },
+                    { CDF3(10767, 18890, 23793) },
+                    { CDF3( 7727, 14255, 18865) },
+                    { CDF3( 6129, 11926, 16882) },
+                    { CDF3( 4482,  9704, 14861) },
+                    { CDF3( 3277,  7452, 11522) },
+                    { CDF3(22956, 28551, 30730) },
+                    { CDF3(22724, 28937, 30961) },
+                    { CDF3(18467, 26324, 29580) },
+                    { CDF3(13234, 20713, 25649) },
+                    { CDF3(11181, 17592, 22481) },
+                    { CDF3( 8291, 18358, 24576) },
+                    { CDF3( 7568, 11881, 14984) },
+                    { CDF3(24948, 29001, 31147) },
+                    { CDF3(25674, 30619, 32151) },
+                    { CDF3(20841, 26793, 29603) },
+                    { CDF3(14669, 24356, 28666) },
+                    { CDF3(11334, 23593, 28219) },
+                    { CDF3( 8922, 14762, 22873) },
+                    { CDF3( 8301, 13544, 20535) },
+                },
+            }, {
+                {
+                    { CDF3(17113, 23733, 27081) },
+                    { CDF3(14139, 21406, 25452) },
+                    { CDF3( 8552, 15002, 19776) },
+                    { CDF3( 5871, 11120, 15378) },
+                    { CDF3( 4455,  8616, 12253) },
+                    { CDF3( 3469,  6910, 10386) },
+                    { CDF3( 2255,  4553,  6782) },
+                    { CDF3(18224, 24376, 27053) },
+                    { CDF3(19290, 26710, 29614) },
+                    { CDF3(14936, 22991, 27184) },
+                    { CDF3(11238, 18951, 23762) },
+                    { CDF3( 8786, 15617, 20588) },
+                    { CDF3( 7317, 13228, 18003) },
+                    { CDF3( 5101,  9512, 13493) },
+                    { CDF3(22639, 28222, 30210) },
+                    { CDF3(23216, 29331, 31307) },
+                    { CDF3(19075, 26762, 29895) },
+                    { CDF3(15014, 23113, 27457) },
+                    { CDF3(11938, 19857, 24752) },
+                    { CDF3( 9942, 17280, 22282) },
+                    { CDF3( 7167, 13144, 17752) },
+                }, {
+                    { CDF3(15820, 22738, 26488) },
+                    { CDF3(13530, 20885, 25216) },
+                    { CDF3( 8395, 15530, 20452) },
+                    { CDF3( 6574, 12321, 16380) },
+                    { CDF3( 5353, 10419, 14568) },
+                    { CDF3( 4613,  8446, 12381) },
+                    { CDF3( 3440,  7158,  9903) },
+                    { CDF3(24247, 29051, 31224) },
+                    { CDF3(22118, 28058, 30369) },
+                    { CDF3(16498, 24768, 28389) },
+                    { CDF3(12920, 21175, 26137) },
+                    { CDF3(10730, 18619, 25352) },
+                    { CDF3(10187, 16279, 22791) },
+                    { CDF3( 9310, 14631, 22127) },
+                    { CDF3(24970, 30558, 32057) },
+                    { CDF3(24801, 29942, 31698) },
+                    { CDF3(22432, 28453, 30855) },
+                    { CDF3(19054, 25680, 29580) },
+                    { CDF3(14392, 23036, 28109) },
+                    { CDF3(12495, 20947, 26650) },
+                    { CDF3(12442, 20326, 26214) },
+                },
+            }, {
+                {
+                    { CDF3(12162, 18785, 22648) },
+                    { CDF3(12749, 19697, 23806) },
+                    { CDF3( 8580, 15297, 20346) },
+                    { CDF3( 6169, 11749, 16543) },
+                    { CDF3( 4836,  9391, 13448) },
+                    { CDF3( 3821,  7711, 11613) },
+                    { CDF3( 2228,  4601,  7070) },
+                    { CDF3(16319, 24725, 28280) },
+                    { CDF3(15698, 23277, 27168) },
+                    { CDF3(12726, 20368, 25047) },
+                    { CDF3( 9912, 17015, 21976) },
+                    { CDF3( 7888, 14220, 19179) },
+                    { CDF3( 6777, 12284, 17018) },
+                    { CDF3( 4492,  8590, 12252) },
+                    { CDF3(23249, 28904, 30947) },
+                    { CDF3(21050, 27908, 30512) },
+                    { CDF3(17440, 25340, 28949) },
+                    { CDF3(14059, 22018, 26541) },
+                    { CDF3(11288, 18903, 23898) },
+                    { CDF3( 9411, 16342, 21428) },
+                    { CDF3( 6278, 11588, 15944) },
+                }, {
+                    { CDF3(13981, 20067, 23226) },
+                    { CDF3(16922, 23580, 26783) },
+                    { CDF3(11005, 19039, 24487) },
+                    { CDF3( 7389, 14218, 19798) },
+                    { CDF3( 5598, 11505, 17206) },
+                    { CDF3( 6090, 11213, 15659) },
+                    { CDF3( 3820,  7371, 10119) },
+                    { CDF3(21082, 26925, 29675) },
+                    { CDF3(21262, 28627, 31128) },
+                    { CDF3(18392, 26454, 30437) },
+                    { CDF3(14870, 22910, 27096) },
+                    { CDF3(12620, 19484, 24908) },
+                    { CDF3( 9290, 16553, 22802) },
+                    { CDF3( 6668, 14288, 20004) },
+                    { CDF3(27704, 31055, 31949) },
+                    { CDF3(24709, 29978, 31788) },
+                    { CDF3(21668, 29264, 31657) },
+                    { CDF3(18295, 26968, 30074) },
+                    { CDF3(16399, 24422, 29313) },
+                    { CDF3(14347, 23026, 28104) },
+                    { CDF3(12370, 19806, 24477) },
+                },
+            },
+        },
+    }
+};
+
+void dav1d_cdf_thread_update(const Dav1dFrameHeader *const hdr,
+                             CdfContext *const dst,
+                             const CdfContext *const src)
+{
+#define update_cdf_1d(n1d, name) \
+    do { \
+        dst->name[n1d] = 0; \
+    } while (0)
+#define update_cdf_2d(n1d, n2d, name) \
+    for (int j = 0; j < (n1d); j++) update_cdf_1d(n2d, name[j])
+#define update_cdf_3d(n1d, n2d, n3d, name) \
+    for (int k = 0; k < (n1d); k++) update_cdf_2d(n2d, n3d, name[k])
+#define update_cdf_4d(n1d, n2d, n3d, n4d, name) \
+    for (int l = 0; l < (n1d); l++) update_cdf_3d(n2d, n3d, n4d, name[l])
+
+    memcpy(dst, src, offsetof(CdfContext, m.intrabc));
+
+    update_cdf_3d(2, 2, 4, coef.eob_bin_16);
+    update_cdf_3d(2, 2, 5, coef.eob_bin_32);
+    update_cdf_3d(2, 2, 6, coef.eob_bin_64);
+    update_cdf_3d(2, 2, 7, coef.eob_bin_128);
+    update_cdf_3d(2, 2, 8, coef.eob_bin_256);
+    update_cdf_2d(2, 9, coef.eob_bin_512);
+    update_cdf_2d(2, 10, coef.eob_bin_1024);
+    update_cdf_4d(N_TX_SIZES, 2, 4, 2, coef.eob_base_tok);
+    update_cdf_4d(N_TX_SIZES, 2, 41 /*42*/, 3, coef.base_tok);
+    update_cdf_4d(4, 2, 21, 3, coef.br_tok);
+    update_cdf_4d(N_TX_SIZES, 2, 9, 1, coef.eob_hi_bit);
+    update_cdf_3d(N_TX_SIZES, 13, 1, coef.skip);
+    update_cdf_3d(2, 3, 1, coef.dc_sign);
+
+    update_cdf_3d(2, N_INTRA_PRED_MODES, N_UV_INTRA_PRED_MODES - 1 - !k, m.uv_mode);
+    update_cdf_2d(4, N_PARTITIONS - 3, m.partition[BL_128X128]);
+    for (int k = BL_64X64; k < BL_8X8; k++)
+        update_cdf_2d(4, N_PARTITIONS - 1, m.partition[k]);
+    update_cdf_2d(4, N_SUB8X8_PARTITIONS - 1, m.partition[BL_8X8]);
+    update_cdf_2d(6, 15, m.cfl_alpha);
+    update_cdf_2d(2, 15, m.txtp_inter1);
+    update_cdf_1d(11, m.txtp_inter2);
+    update_cdf_3d(2, N_INTRA_PRED_MODES, 6, m.txtp_intra1);
+    update_cdf_3d(3, N_INTRA_PRED_MODES, 4, m.txtp_intra2);
+    update_cdf_1d(7, m.cfl_sign);
+    update_cdf_2d(8, 6, m.angle_delta);
+    update_cdf_1d(4, m.filter_intra);
+    update_cdf_2d(3, DAV1D_MAX_SEGMENTS - 1, m.seg_id);
+    update_cdf_3d(2, 7, 6, m.pal_sz);
+    update_cdf_4d(2, 7, 5, k + 1, m.color_map);
+    update_cdf_3d(N_TX_SIZES - 1, 3, imin(k + 1, 2), m.txsz);
+    update_cdf_1d(3, m.delta_q);
+    update_cdf_2d(5, 3, m.delta_lf);
+    update_cdf_1d(2, m.restore_switchable);
+    update_cdf_1d(1, m.restore_wiener);
+    update_cdf_1d(1, m.restore_sgrproj);
+    update_cdf_2d(4, 1, m.txtp_inter3);
+    update_cdf_2d(N_BS_SIZES, 1, m.use_filter_intra);
+    update_cdf_3d(7, 3, 1, m.txpart);
+    update_cdf_2d(3, 1, m.skip);
+    update_cdf_3d(7, 3, 1, m.pal_y);
+    update_cdf_2d(2, 1, m.pal_uv);
+
+    if (IS_KEY_OR_INTRA(hdr))
+        return;
+
+    memcpy(dst->m.y_mode, src->m.y_mode,
+           offsetof(CdfContext, kfym) - offsetof(CdfContext, m.y_mode));
+
+    update_cdf_2d(4, N_INTRA_PRED_MODES - 1, m.y_mode);
+    update_cdf_2d(9, 15, m.wedge_idx);
+    update_cdf_2d(8, N_COMP_INTER_PRED_MODES - 1, m.comp_inter_mode);
+    update_cdf_3d(2, 8, DAV1D_N_SWITCHABLE_FILTERS - 1, m.filter);
+    update_cdf_2d(4, 3, m.interintra_mode);
+    update_cdf_2d(N_BS_SIZES, 2, m.motion_mode);
+    update_cdf_2d(3, 1, m.skip_mode);
+    update_cdf_2d(6, 1, m.newmv_mode);
+    update_cdf_2d(2, 1, m.globalmv_mode);
+    update_cdf_2d(6, 1, m.refmv_mode);
+    update_cdf_2d(3, 1, m.drl_bit);
+    update_cdf_2d(4, 1, m.intra);
+    update_cdf_2d(5, 1, m.comp);
+    update_cdf_2d(5, 1, m.comp_dir);
+    update_cdf_2d(6, 1, m.jnt_comp);
+    update_cdf_2d(6, 1, m.mask_comp);
+    update_cdf_2d(9, 1, m.wedge_comp);
+    update_cdf_3d(6, 3, 1, m.ref);
+    update_cdf_3d(3, 3, 1, m.comp_fwd_ref);
+    update_cdf_3d(2, 3, 1, m.comp_bwd_ref);
+    update_cdf_3d(3, 3, 1, m.comp_uni_ref);
+    update_cdf_2d(3, 1, m.seg_pred);
+    update_cdf_2d(4, 1, m.interintra);
+    update_cdf_2d(7, 1, m.interintra_wedge);
+    update_cdf_2d(N_BS_SIZES, 1, m.obmc);
+
+    for (int k = 0; k < 2; k++) {
+        update_cdf_1d(10, mv.comp[k].classes);
+        update_cdf_1d(1, mv.comp[k].sign);
+        update_cdf_1d(1, mv.comp[k].class0);
+        update_cdf_2d(2, 3, mv.comp[k].class0_fp);
+        update_cdf_1d(1, mv.comp[k].class0_hp);
+        update_cdf_2d(10, 1, mv.comp[k].classN);
+        update_cdf_1d(3, mv.comp[k].classN_fp);
+        update_cdf_1d(1, mv.comp[k].classN_hp);
+    }
+    update_cdf_1d(N_MV_JOINTS - 1, mv.joint);
+}
+
+/*
+ * CDF threading wrappers.
+ */
+void dav1d_cdf_thread_init_static(CdfThreadContext *const cdf, const unsigned qidx) {
+    cdf->ref = NULL;
+    cdf->data.qcat = (qidx > 20) + (qidx > 60) + (qidx > 120);
+}
+
+void dav1d_cdf_thread_copy(CdfContext *const dst, const CdfThreadContext *const src) {
+    if (src->ref) {
+        memcpy(dst, src->data.cdf, sizeof(*dst));
+    } else {
+        dst->coef = default_coef_cdf[src->data.qcat];
+        memcpy(&dst->m, &default_cdf.m,
+               offsetof(CdfDefaultContext, mv.joint));
+        memcpy(&dst->mv.comp[1], &default_cdf.mv.comp,
+               sizeof(default_cdf) - offsetof(CdfDefaultContext, mv.comp));
+    }
+}
+
+int dav1d_cdf_thread_alloc(Dav1dContext *const c, CdfThreadContext *const cdf,
+                           const int have_frame_mt)
+{
+    cdf->ref = dav1d_ref_create_using_pool(c->cdf_pool,
+                                           sizeof(CdfContext) + sizeof(atomic_uint));
+    if (!cdf->ref) return DAV1D_ERR(ENOMEM);
+    cdf->data.cdf = cdf->ref->data;
+    if (have_frame_mt) {
+        cdf->progress = (atomic_uint *) &cdf->data.cdf[1];
+        atomic_init(cdf->progress, 0);
+    }
+    return 0;
+}
+
+void dav1d_cdf_thread_ref(CdfThreadContext *const dst,
+                          CdfThreadContext *const src)
+{
+    *dst = *src;
+    if (src->ref)
+        dav1d_ref_inc(src->ref);
+}
+
+void dav1d_cdf_thread_unref(CdfThreadContext *const cdf) {
+    memset(&cdf->data, 0, sizeof(*cdf) - offsetof(CdfThreadContext, data));
+    dav1d_ref_dec(&cdf->ref);
+}
diff --git a/media/libdav1d/src/src/cdf.h b/media/libdav1d/src/src/cdf.h
new file mode 100644
index 0000000000..db837102b5
--- /dev/null
+++ b/media/libdav1d/src/src/cdf.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_CDF_H
+#define DAV1D_SRC_CDF_H
+
+#include 
+
+#include "src/levels.h"
+#include "src/ref.h"
+#include "src/thread_data.h"
+
+/* Buffers padded to [4]/[8]/[16] for SIMD where needed. */
+
+typedef struct CdfModeContext {
+    ALIGN(uint16_t uv_mode[2][N_INTRA_PRED_MODES][N_UV_INTRA_PRED_MODES + 2], 32);
+    ALIGN(uint16_t partition[N_BL_LEVELS][4][N_PARTITIONS + 6], 32);
+    ALIGN(uint16_t cfl_alpha[6][16], 32);
+    ALIGN(uint16_t txtp_inter1[2][16], 32);
+    ALIGN(uint16_t txtp_inter2[12 + 4], 32);
+    ALIGN(uint16_t txtp_intra1[2][N_INTRA_PRED_MODES][7 + 1], 16);
+    ALIGN(uint16_t txtp_intra2[3][N_INTRA_PRED_MODES][5 + 3], 16);
+    ALIGN(uint16_t cfl_sign[8], 16);
+    ALIGN(uint16_t angle_delta[8][8], 16);
+    ALIGN(uint16_t filter_intra[5 + 3], 16);
+    ALIGN(uint16_t seg_id[3][DAV1D_MAX_SEGMENTS], 16);
+    ALIGN(uint16_t pal_sz[2][7][7 + 1], 16);
+    ALIGN(uint16_t color_map[2][7][5][8], 16);
+    ALIGN(uint16_t txsz[N_TX_SIZES - 1][3][4], 8);
+    ALIGN(uint16_t delta_q[4], 8);
+    ALIGN(uint16_t delta_lf[5][4], 8);
+    ALIGN(uint16_t restore_switchable[3 + 1], 8);
+    ALIGN(uint16_t restore_wiener[2], 4);
+    ALIGN(uint16_t restore_sgrproj[2], 4);
+    ALIGN(uint16_t txtp_inter3[4][2], 4);
+    ALIGN(uint16_t use_filter_intra[N_BS_SIZES][2], 4);
+    ALIGN(uint16_t txpart[7][3][2], 4);
+    ALIGN(uint16_t skip[3][2], 4);
+    ALIGN(uint16_t pal_y[7][3][2], 4);
+    ALIGN(uint16_t pal_uv[2][2], 4);
+
+    /* key/intra */
+    ALIGN(uint16_t intrabc[2], 4);
+
+    /* inter/switch */
+    ALIGN(uint16_t y_mode[4][N_INTRA_PRED_MODES + 3], 32);
+    ALIGN(uint16_t wedge_idx[9][16], 32);
+    ALIGN(uint16_t comp_inter_mode[8][N_COMP_INTER_PRED_MODES], 16);
+    ALIGN(uint16_t filter[2][8][DAV1D_N_SWITCHABLE_FILTERS + 1], 8);
+    ALIGN(uint16_t interintra_mode[4][4], 8);
+    ALIGN(uint16_t motion_mode[N_BS_SIZES][3 + 1], 8);
+    ALIGN(uint16_t skip_mode[3][2], 4);
+    ALIGN(uint16_t newmv_mode[6][2], 4);
+    ALIGN(uint16_t globalmv_mode[2][2], 4);
+    ALIGN(uint16_t refmv_mode[6][2], 4);
+    ALIGN(uint16_t drl_bit[3][2], 4);
+    ALIGN(uint16_t intra[4][2], 4);
+    ALIGN(uint16_t comp[5][2], 4);
+    ALIGN(uint16_t comp_dir[5][2], 4);
+    ALIGN(uint16_t jnt_comp[6][2], 4);
+    ALIGN(uint16_t mask_comp[6][2], 4);
+    ALIGN(uint16_t wedge_comp[9][2], 4);
+    ALIGN(uint16_t ref[6][3][2], 4);
+    ALIGN(uint16_t comp_fwd_ref[3][3][2], 4);
+    ALIGN(uint16_t comp_bwd_ref[2][3][2], 4);
+    ALIGN(uint16_t comp_uni_ref[3][3][2], 4);
+    ALIGN(uint16_t seg_pred[3][2], 4);
+    ALIGN(uint16_t interintra[7][2], 4);
+    ALIGN(uint16_t interintra_wedge[7][2], 4);
+    ALIGN(uint16_t obmc[N_BS_SIZES][2], 4);
+} CdfModeContext;
+
+typedef struct CdfCoefContext {
+    ALIGN(uint16_t eob_bin_16[2][2][5 + 3], 16);
+    ALIGN(uint16_t eob_bin_32[2][2][6 + 2], 16);
+    ALIGN(uint16_t eob_bin_64[2][2][7 + 1], 16);
+    ALIGN(uint16_t eob_bin_128[2][2][8 + 0], 16);
+    ALIGN(uint16_t eob_bin_256[2][2][9 + 7], 32);
+    ALIGN(uint16_t eob_bin_512[2][10 + 6], 32);
+    ALIGN(uint16_t eob_bin_1024[2][11 + 5], 32);
+    ALIGN(uint16_t eob_base_tok[N_TX_SIZES][2][4][4], 8);
+    ALIGN(uint16_t base_tok[N_TX_SIZES][2][41][4], 8);
+    ALIGN(uint16_t br_tok[4 /*5*/][2][21][4], 8);
+    ALIGN(uint16_t eob_hi_bit[N_TX_SIZES][2][9][2], 4);
+    ALIGN(uint16_t skip[N_TX_SIZES][13][2], 4);
+    ALIGN(uint16_t dc_sign[2][3][2], 4);
+} CdfCoefContext;
+
+typedef struct CdfMvComponent {
+    ALIGN(uint16_t classes[11 + 5], 32);
+    ALIGN(uint16_t sign[2], 4);
+    ALIGN(uint16_t class0[2], 4);
+    ALIGN(uint16_t class0_fp[2][4], 8);
+    ALIGN(uint16_t class0_hp[2], 4);
+    ALIGN(uint16_t classN[10][2], 4);
+    ALIGN(uint16_t classN_fp[4], 8);
+    ALIGN(uint16_t classN_hp[2], 4);
+} CdfMvComponent;
+
+typedef struct CdfMvContext {
+    CdfMvComponent comp[2];
+    ALIGN(uint16_t joint[N_MV_JOINTS], 8);
+} CdfMvContext;
+
+typedef struct CdfContext {
+    CdfCoefContext coef;
+    CdfModeContext m;
+    CdfMvContext mv;
+    ALIGN(uint16_t kfym[5][5][N_INTRA_PRED_MODES + 3], 32);
+} CdfContext;
+
+typedef struct CdfThreadContext {
+    Dav1dRef *ref; ///< allocation origin
+    union {
+        CdfContext *cdf; // if ref != NULL
+        unsigned qcat; // if ref == NULL, from static CDF tables
+    } data;
+    atomic_uint *progress;
+} CdfThreadContext;
+
+void dav1d_cdf_thread_init_static(CdfThreadContext *cdf, unsigned qidx);
+int dav1d_cdf_thread_alloc(Dav1dContext *c, CdfThreadContext *cdf,
+                           const int have_frame_mt);
+void dav1d_cdf_thread_copy(CdfContext *dst, const CdfThreadContext *src);
+void dav1d_cdf_thread_ref(CdfThreadContext *dst, CdfThreadContext *src);
+void dav1d_cdf_thread_unref(CdfThreadContext *cdf);
+void dav1d_cdf_thread_update(const Dav1dFrameHeader *hdr, CdfContext *dst,
+                             const CdfContext *src);
+
+#endif /* DAV1D_SRC_CDF_H */
diff --git a/media/libdav1d/src/src/cpu.c b/media/libdav1d/src/src/cpu.c
new file mode 100644
index 0000000000..6b57fe4a97
--- /dev/null
+++ b/media/libdav1d/src/src/cpu.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+
+#include 
+#include 
+
+#include "src/cpu.h"
+#include "src/log.h"
+
+#ifdef _WIN32
+#include 
+#endif
+#ifdef __APPLE__
+#include 
+#include 
+#endif
+#if HAVE_UNISTD_H
+#include 
+#endif
+
+#if HAVE_PTHREAD_GETAFFINITY_NP
+#include 
+#if HAVE_PTHREAD_NP_H
+#include 
+#endif
+#if defined(__FreeBSD__)
+#define cpu_set_t cpuset_t
+#endif
+#endif
+
+#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO
+#include 
+#endif
+
+unsigned dav1d_cpu_flags = 0U;
+unsigned dav1d_cpu_flags_mask = ~0U;
+
+COLD void dav1d_init_cpu(void) {
+#if HAVE_ASM && !__has_feature(memory_sanitizer)
+// memory sanitizer is inherently incompatible with asm
+#if ARCH_AARCH64 || ARCH_ARM
+    dav1d_cpu_flags = dav1d_get_cpu_flags_arm();
+#elif ARCH_LOONGARCH
+    dav1d_cpu_flags = dav1d_get_cpu_flags_loongarch();
+#elif ARCH_PPC64LE
+    dav1d_cpu_flags = dav1d_get_cpu_flags_ppc();
+#elif ARCH_RISCV
+    dav1d_cpu_flags = dav1d_get_cpu_flags_riscv();
+#elif ARCH_X86
+    dav1d_cpu_flags = dav1d_get_cpu_flags_x86();
+#endif
+#endif
+}
+
+COLD void dav1d_set_cpu_flags_mask(const unsigned mask) {
+    dav1d_cpu_flags_mask = mask;
+}
+
+COLD int dav1d_num_logical_processors(Dav1dContext *const c) {
+#ifdef _WIN32
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+    GROUP_AFFINITY affinity;
+    if (GetThreadGroupAffinity(GetCurrentThread(), &affinity)) {
+        int num_processors = 1;
+        while (affinity.Mask &= affinity.Mask - 1)
+            num_processors++;
+        return num_processors;
+    }
+#else
+    SYSTEM_INFO system_info;
+    GetNativeSystemInfo(&system_info);
+    return system_info.dwNumberOfProcessors;
+#endif
+#elif HAVE_PTHREAD_GETAFFINITY_NP && defined(CPU_COUNT)
+    cpu_set_t affinity;
+    if (!pthread_getaffinity_np(pthread_self(), sizeof(affinity), &affinity))
+        return CPU_COUNT(&affinity);
+#elif defined(__APPLE__)
+    int num_processors;
+    size_t length = sizeof(num_processors);
+    if (!sysctlbyname("hw.logicalcpu", &num_processors, &length, NULL, 0))
+        return num_processors;
+#elif defined(_SC_NPROCESSORS_ONLN)
+    return (int)sysconf(_SC_NPROCESSORS_ONLN);
+#endif
+    if (c)
+        dav1d_log(c, "Unable to detect thread count, defaulting to single-threaded mode\n");
+    return 1;
+}
+
+COLD unsigned long dav1d_getauxval(unsigned long type) {
+#if HAVE_GETAUXVAL
+    return getauxval(type);
+#elif HAVE_ELF_AUX_INFO
+    unsigned long aux = 0;
+    int ret = elf_aux_info(type, &aux, sizeof(aux));
+    if (ret != 0)
+        errno = ret;
+    return aux;
+#else
+    errno = ENOSYS;
+    return 0;
+#endif
+}
diff --git a/media/libdav1d/src/src/cpu.h b/media/libdav1d/src/src/cpu.h
new file mode 100644
index 0000000000..5d712bbbef
--- /dev/null
+++ b/media/libdav1d/src/src/cpu.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright © 2018-2022, VideoLAN and dav1d authors
+ * Copyright © 2018-2022, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_CPU_H
+#define DAV1D_SRC_CPU_H
+
+#include "config.h"
+
+#include "common/attributes.h"
+
+#include "dav1d/common.h"
+#include "dav1d/dav1d.h"
+
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/cpu.h"
+#elif ARCH_LOONGARCH
+#include "src/loongarch/cpu.h"
+#elif ARCH_PPC64LE
+#include "src/ppc/cpu.h"
+#elif ARCH_RISCV
+#include "src/riscv/cpu.h"
+#elif ARCH_X86
+#include "src/x86/cpu.h"
+#endif
+
+EXTERN unsigned dav1d_cpu_flags;
+EXTERN unsigned dav1d_cpu_flags_mask;
+
+void dav1d_init_cpu(void);
+DAV1D_API void dav1d_set_cpu_flags_mask(unsigned mask);
+int dav1d_num_logical_processors(Dav1dContext *c);
+unsigned long dav1d_getauxval(unsigned long);
+
+static ALWAYS_INLINE unsigned dav1d_get_default_cpu_flags(void) {
+    unsigned flags = 0;
+
+#if ARCH_AARCH64 || ARCH_ARM
+#if defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32) || ARCH_AARCH64
+    flags |= DAV1D_ARM_CPU_FLAG_NEON;
+#endif
+#ifdef __ARM_FEATURE_DOTPROD
+    flags |= DAV1D_ARM_CPU_FLAG_DOTPROD;
+#endif
+#ifdef __ARM_FEATURE_MATMUL_INT8
+    flags |= DAV1D_ARM_CPU_FLAG_I8MM;
+#endif
+#if ARCH_AARCH64
+#ifdef __ARM_FEATURE_SVE
+    flags |= DAV1D_ARM_CPU_FLAG_SVE;
+#endif
+#ifdef __ARM_FEATURE_SVE2
+    flags |= DAV1D_ARM_CPU_FLAG_SVE2;
+#endif
+#endif /* ARCH_AARCH64 */
+#elif ARCH_PPC64LE
+#if defined(__VSX__)
+    flags |= DAV1D_PPC_CPU_FLAG_VSX;
+#endif
+#if defined(__POWER9_VECTOR__)
+    flags |= DAV1D_PPC_CPU_FLAG_PWR9;
+#endif
+#elif ARCH_RISCV
+#if defined(__riscv_v)
+    flags |= DAV1D_RISCV_CPU_FLAG_V;
+#endif
+#elif ARCH_X86
+#if defined(__AVX512F__) && defined(__AVX512CD__) && \
+    defined(__AVX512BW__) && defined(__AVX512DQ__) && \
+    defined(__AVX512VL__) && defined(__AVX512VNNI__) && \
+    defined(__AVX512IFMA__) && defined(__AVX512VBMI__) && \
+    defined(__AVX512VBMI2__) && defined(__AVX512VPOPCNTDQ__) && \
+    defined(__AVX512BITALG__) && defined(__GFNI__) && \
+    defined(__VAES__) && defined(__VPCLMULQDQ__)
+    flags |= DAV1D_X86_CPU_FLAG_AVX512ICL |
+             DAV1D_X86_CPU_FLAG_AVX2 |
+             DAV1D_X86_CPU_FLAG_SSE41 |
+             DAV1D_X86_CPU_FLAG_SSSE3 |
+             DAV1D_X86_CPU_FLAG_SSE2;
+#elif defined(__AVX2__)
+    flags |= DAV1D_X86_CPU_FLAG_AVX2 |
+             DAV1D_X86_CPU_FLAG_SSE41 |
+             DAV1D_X86_CPU_FLAG_SSSE3 |
+             DAV1D_X86_CPU_FLAG_SSE2;
+#elif defined(__SSE4_1__) || defined(__AVX__)
+    flags |= DAV1D_X86_CPU_FLAG_SSE41 |
+             DAV1D_X86_CPU_FLAG_SSSE3 |
+             DAV1D_X86_CPU_FLAG_SSE2;
+#elif defined(__SSSE3__)
+    flags |= DAV1D_X86_CPU_FLAG_SSSE3 |
+             DAV1D_X86_CPU_FLAG_SSE2;
+#elif ARCH_X86_64 || defined(__SSE2__) || \
+      (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+    flags |= DAV1D_X86_CPU_FLAG_SSE2;
+#endif
+#endif
+
+    return flags;
+}
+
+static ALWAYS_INLINE unsigned dav1d_get_cpu_flags(void) {
+    unsigned flags = dav1d_cpu_flags & dav1d_cpu_flags_mask;
+
+#if TRIM_DSP_FUNCTIONS
+/* Since this function is inlined, unconditionally setting a flag here will
+ * enable dead code elimination in the calling function. */
+    flags |= dav1d_get_default_cpu_flags();
+#endif
+
+    return flags;
+}
+
+#endif /* DAV1D_SRC_CPU_H */
diff --git a/media/libdav1d/src/src/ctx.c b/media/libdav1d/src/src/ctx.c
new file mode 100644
index 0000000000..0a0fe54c7c
--- /dev/null
+++ b/media/libdav1d/src/src/ctx.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "ctx.h"
+
+static void memset_w1(void *const ptr, const int value) {
+    set_ctx1((uint8_t *) ptr, 0, value);
+}
+
+static void memset_w2(void *const ptr, const int value) {
+    set_ctx2((uint8_t *) ptr, 0, value);
+}
+
+static void memset_w4(void *const ptr, const int value) {
+    set_ctx4((uint8_t *) ptr, 0, value);
+}
+
+static void memset_w8(void *const ptr, const int value) {
+    set_ctx8((uint8_t *) ptr, 0, value);
+}
+
+static void memset_w16(void *const ptr, const int value) {
+    set_ctx16((uint8_t *) ptr, 0, value);
+}
+
+static void memset_w32(void *const ptr, const int value) {
+    set_ctx32((uint8_t *) ptr, 0, value);
+}
+
+const dav1d_memset_pow2_fn dav1d_memset_pow2[6] = {
+    memset_w1,
+    memset_w2,
+    memset_w4,
+    memset_w8,
+    memset_w16,
+    memset_w32
+};
diff --git a/media/libdav1d/src/src/ctx.h b/media/libdav1d/src/src/ctx.h
new file mode 100644
index 0000000000..7dea8b6894
--- /dev/null
+++ b/media/libdav1d/src/src/ctx.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_CTX_H
+#define DAV1D_SRC_CTX_H
+
+#include 
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+union alias64 { uint64_t u64; uint8_t u8[8]; } ATTR_ALIAS;
+union alias32 { uint32_t u32; uint8_t u8[4]; } ATTR_ALIAS;
+union alias16 { uint16_t u16; uint8_t u8[2]; } ATTR_ALIAS;
+union alias8 { uint8_t u8; } ATTR_ALIAS;
+
+typedef void (*dav1d_memset_pow2_fn)(void *ptr, int value);
+EXTERN const dav1d_memset_pow2_fn dav1d_memset_pow2[6];
+
+static inline void dav1d_memset_likely_pow2(void *const ptr, const int value, const int n) {
+    assert(n >= 1 && n <= 32);
+    if ((n&(n-1)) == 0) {
+        dav1d_memset_pow2[ulog2(n)](ptr, value);
+    } else {
+        memset(ptr, value, n);
+    }
+}
+
+// For smaller sizes use multiplication to broadcast bytes. memset misbehaves on the smaller sizes.
+// For the larger sizes, we want to use memset to get access to vector operations.
+#define set_ctx1(var, off, val) \
+    ((union alias8 *) &(var)[off])->u8 = (val) * 0x01
+#define set_ctx2(var, off, val) \
+    ((union alias16 *) &(var)[off])->u16 = (val) * 0x0101
+#define set_ctx4(var, off, val) \
+    ((union alias32 *) &(var)[off])->u32 = (val) * 0x01010101U
+#define set_ctx8(var, off, val) \
+    ((union alias64 *) &(var)[off])->u64 = (val) * 0x0101010101010101ULL
+#define set_ctx16(var, off, val) do { \
+        memset(&(var)[off], val, 16); \
+    } while (0)
+#define set_ctx32(var, off, val) do { \
+        memset(&(var)[off], val, 32); \
+    } while (0)
+#define case_set(var) \
+    switch (var) { \
+    case 0: set_ctx(set_ctx1); break; \
+    case 1: set_ctx(set_ctx2); break; \
+    case 2: set_ctx(set_ctx4); break; \
+    case 3: set_ctx(set_ctx8); break; \
+    case 4: set_ctx(set_ctx16); break; \
+    case 5: set_ctx(set_ctx32); break; \
+    default: assert(0); \
+    }
+#define case_set_upto16(var) \
+    switch (var) { \
+    case 0: set_ctx(set_ctx1); break; \
+    case 1: set_ctx(set_ctx2); break; \
+    case 2: set_ctx(set_ctx4); break; \
+    case 3: set_ctx(set_ctx8); break; \
+    case 4: set_ctx(set_ctx16); break; \
+    default: assert(0); \
+    }
+
+#endif /* DAV1D_SRC_CTX_H */
diff --git a/media/libdav1d/src/src/data.c b/media/libdav1d/src/src/data.c
new file mode 100644
index 0000000000..bbbe02e8d1
--- /dev/null
+++ b/media/libdav1d/src/src/data.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "dav1d/data.h"
+
+#include "common/attributes.h"
+#include "common/validate.h"
+
+#include "src/data.h"
+#include "src/ref.h"
+
+uint8_t *dav1d_data_create_internal(Dav1dData *const buf, const size_t sz) {
+    validate_input_or_ret(buf != NULL, NULL);
+
+    if (sz > SIZE_MAX / 2) return NULL;
+    buf->ref = dav1d_ref_create(ALLOC_DAV1DDATA, sz);
+    if (!buf->ref) return NULL;
+    buf->data = buf->ref->const_data;
+    buf->sz = sz;
+    dav1d_data_props_set_defaults(&buf->m);
+    buf->m.size = sz;
+
+    return buf->ref->data;
+}
+
+int dav1d_data_wrap_internal(Dav1dData *const buf, const uint8_t *const ptr,
+                             const size_t sz,
+                             void (*const free_callback)(const uint8_t *data,
+                                                         void *cookie),
+                             void *const cookie)
+{
+    validate_input_or_ret(buf != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(ptr != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(free_callback != NULL, DAV1D_ERR(EINVAL));
+
+    if (sz > SIZE_MAX / 2) return DAV1D_ERR(EINVAL);
+    Dav1dRef *const ref = dav1d_malloc(ALLOC_DAV1DDATA, sizeof(Dav1dRef));
+    if (!ref) return DAV1D_ERR(ENOMEM);
+
+    buf->ref = dav1d_ref_init(ref, ptr, free_callback, cookie, 1);
+    buf->data = ptr;
+    buf->sz = sz;
+    dav1d_data_props_set_defaults(&buf->m);
+    buf->m.size = sz;
+
+    return 0;
+}
+
+int dav1d_data_wrap_user_data_internal(Dav1dData *const buf,
+                                       const uint8_t *const user_data,
+                                       void (*const free_callback)(const uint8_t *user_data,
+                                                                   void *cookie),
+                                       void *const cookie)
+{
+    validate_input_or_ret(buf != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(free_callback != NULL, DAV1D_ERR(EINVAL));
+
+    Dav1dRef *const ref = dav1d_malloc(ALLOC_DAV1DDATA, sizeof(Dav1dRef));
+    if (!ref) return DAV1D_ERR(ENOMEM);
+
+    buf->m.user_data.ref = dav1d_ref_init(ref, user_data, free_callback, cookie, 1);
+    buf->m.user_data.data = user_data;
+
+    return 0;
+}
+
+void dav1d_data_ref(Dav1dData *const dst, const Dav1dData *const src) {
+    assert(dst != NULL);
+    assert(dst->data == NULL);
+    assert(src != NULL);
+
+    if (src->ref) {
+        assert(src->data != NULL);
+        dav1d_ref_inc(src->ref);
+    }
+    if (src->m.user_data.ref) dav1d_ref_inc(src->m.user_data.ref);
+    *dst = *src;
+}
+
+void dav1d_data_props_copy(Dav1dDataProps *const dst,
+                           const Dav1dDataProps *const src)
+{
+    assert(dst != NULL);
+    assert(src != NULL);
+
+    dav1d_ref_dec(&dst->user_data.ref);
+    *dst = *src;
+    if (dst->user_data.ref) dav1d_ref_inc(dst->user_data.ref);
+}
+
+void dav1d_data_props_set_defaults(Dav1dDataProps *const props) {
+    assert(props != NULL);
+
+    memset(props, 0, sizeof(*props));
+    props->timestamp = INT64_MIN;
+    props->offset = -1;
+}
+
+void dav1d_data_props_unref_internal(Dav1dDataProps *const props) {
+    validate_input(props != NULL);
+
+    struct Dav1dRef *user_data_ref = props->user_data.ref;
+    dav1d_data_props_set_defaults(props);
+    dav1d_ref_dec(&user_data_ref);
+}
+
+void dav1d_data_unref_internal(Dav1dData *const buf) {
+    validate_input(buf != NULL);
+
+    struct Dav1dRef *user_data_ref = buf->m.user_data.ref;
+    if (buf->ref) {
+        validate_input(buf->data != NULL);
+        dav1d_ref_dec(&buf->ref);
+    }
+    memset(buf, 0, sizeof(*buf));
+    dav1d_data_props_set_defaults(&buf->m);
+    dav1d_ref_dec(&user_data_ref);
+}
diff --git a/media/libdav1d/src/src/data.h b/media/libdav1d/src/src/data.h
new file mode 100644
index 0000000000..b34c1db702
--- /dev/null
+++ b/media/libdav1d/src/src/data.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_DATA_H
+#define DAV1D_SRC_DATA_H
+
+#include "dav1d/data.h"
+
+void dav1d_data_ref(Dav1dData *dst, const Dav1dData *src);
+
+/**
+ * Copy the source properties to the destination and increase the
+ * user_data's reference count (if it's not NULL).
+ */
+void dav1d_data_props_copy(Dav1dDataProps *dst, const Dav1dDataProps *src);
+
+void dav1d_data_props_set_defaults(Dav1dDataProps *props);
+
+uint8_t *dav1d_data_create_internal(Dav1dData *buf, size_t sz);
+int dav1d_data_wrap_internal(Dav1dData *buf, const uint8_t *ptr, size_t sz,
+                             void (*free_callback)(const uint8_t *data,
+                                                   void *user_data),
+                             void *user_data);
+int dav1d_data_wrap_user_data_internal(Dav1dData *buf,
+                                       const uint8_t *user_data,
+                                       void (*free_callback)(const uint8_t *user_data,
+                                                             void *cookie),
+                                       void *cookie);
+void dav1d_data_unref_internal(Dav1dData *buf);
+void dav1d_data_props_unref_internal(Dav1dDataProps *props);
+
+#endif /* DAV1D_SRC_DATA_H */
diff --git a/media/libdav1d/src/src/dav1d.rc.in b/media/libdav1d/src/src/dav1d.rc.in
new file mode 100644
index 0000000000..ce5a33ad4d
--- /dev/null
+++ b/media/libdav1d/src/src/dav1d.rc.in
@@ -0,0 +1,32 @@
+#define API_VERSION_NUMBER @API_VERSION_MAJOR@,@API_VERSION_MINOR@,@API_VERSION_REVISION@,0
+#define API_VERSION_NUMBER_STR "@API_VERSION_MAJOR@.@API_VERSION_MINOR@.@API_VERSION_REVISION@"
+#define PROJECT_VERSION_NUMBER @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_REVISION@,0
+#define PROJECT_VERSION_NUMBER_STR "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_REVISION@"
+
+#include 
+
+1 VERSIONINFO
+FILETYPE VFT_DLL
+FILEOS VOS_NT_WINDOWS32
+PRODUCTVERSION PROJECT_VERSION_NUMBER
+FILEVERSION API_VERSION_NUMBER
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904E4"
+    BEGIN
+      VALUE "CompanyName", "VideoLAN"
+      VALUE "ProductName", "dav1d"
+      VALUE "ProductVersion", PROJECT_VERSION_NUMBER_STR
+      VALUE "FileVersion", API_VERSION_NUMBER_STR
+      VALUE "FileDescription", "dav1d " PROJECT_VERSION_NUMBER_STR " - AV1 decoder"
+      VALUE "InternalName", "dav1d"
+      VALUE "OriginalFilename", "libdav1d.dll"
+      VALUE "LegalCopyright", L"Copyright \251 @COPYRIGHT_YEARS@ VideoLAN and dav1d Authors"
+    END
+  END
+  BLOCK "VarFileInfo"
+  BEGIN
+    VALUE "Translation", 0x409, 1252
+  END
+END
diff --git a/media/libdav1d/src/src/decode.c b/media/libdav1d/src/src/decode.c
new file mode 100644
index 0000000000..fb5d23cda8
--- /dev/null
+++ b/media/libdav1d/src/src/decode.c
@@ -0,0 +1,3746 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "dav1d/data.h"
+
+#include "common/frame.h"
+#include "common/intops.h"
+
+#include "src/ctx.h"
+#include "src/decode.h"
+#include "src/dequant_tables.h"
+#include "src/env.h"
+#include "src/filmgrain.h"
+#include "src/log.h"
+#include "src/qm.h"
+#include "src/recon.h"
+#include "src/ref.h"
+#include "src/tables.h"
+#include "src/thread_task.h"
+#include "src/warpmv.h"
+
+static void init_quant_tables(const Dav1dSequenceHeader *const seq_hdr,
+                              const Dav1dFrameHeader *const frame_hdr,
+                              const int qidx, uint16_t (*dq)[3][2])
+{
+    for (int i = 0; i < (frame_hdr->segmentation.enabled ? 8 : 1); i++) {
+        const int yac = frame_hdr->segmentation.enabled ?
+            iclip_u8(qidx + frame_hdr->segmentation.seg_data.d[i].delta_q) : qidx;
+        const int ydc = iclip_u8(yac + frame_hdr->quant.ydc_delta);
+        const int uac = iclip_u8(yac + frame_hdr->quant.uac_delta);
+        const int udc = iclip_u8(yac + frame_hdr->quant.udc_delta);
+        const int vac = iclip_u8(yac + frame_hdr->quant.vac_delta);
+        const int vdc = iclip_u8(yac + frame_hdr->quant.vdc_delta);
+
+        dq[i][0][0] = dav1d_dq_tbl[seq_hdr->hbd][ydc][0];
+        dq[i][0][1] = dav1d_dq_tbl[seq_hdr->hbd][yac][1];
+        dq[i][1][0] = dav1d_dq_tbl[seq_hdr->hbd][udc][0];
+        dq[i][1][1] = dav1d_dq_tbl[seq_hdr->hbd][uac][1];
+        dq[i][2][0] = dav1d_dq_tbl[seq_hdr->hbd][vdc][0];
+        dq[i][2][1] = dav1d_dq_tbl[seq_hdr->hbd][vac][1];
+    }
+}
+
+static int read_mv_component_diff(MsacContext *const msac,
+                                  CdfMvComponent *const mv_comp,
+                                  const int mv_prec)
+{
+    const int sign = dav1d_msac_decode_bool_adapt(msac, mv_comp->sign);
+    const int cl = dav1d_msac_decode_symbol_adapt16(msac, mv_comp->classes, 10);
+    int up, fp = 3, hp = 1;
+
+    if (!cl) {
+        up = dav1d_msac_decode_bool_adapt(msac, mv_comp->class0);
+        if (mv_prec >= 0) {  // !force_integer_mv
+            fp = dav1d_msac_decode_symbol_adapt4(msac, mv_comp->class0_fp[up], 3);
+            if (mv_prec > 0) // allow_high_precision_mv
+                hp = dav1d_msac_decode_bool_adapt(msac, mv_comp->class0_hp);
+        }
+    } else {
+        up = 1 << cl;
+        for (int n = 0; n < cl; n++)
+            up |= dav1d_msac_decode_bool_adapt(msac, mv_comp->classN[n]) << n;
+        if (mv_prec >= 0) {  // !force_integer_mv
+            fp = dav1d_msac_decode_symbol_adapt4(msac, mv_comp->classN_fp, 3);
+            if (mv_prec > 0) // allow_high_precision_mv
+                hp = dav1d_msac_decode_bool_adapt(msac, mv_comp->classN_hp);
+        }
+    }
+
+    const int diff = ((up << 3) | (fp << 1) | hp) + 1;
+
+    return sign ? -diff : diff;
+}
+
+static void read_mv_residual(Dav1dTileState *const ts, mv *const ref_mv,
+                             const int mv_prec)
+{
+    MsacContext *const msac = &ts->msac;
+    const enum MVJoint mv_joint =
+        dav1d_msac_decode_symbol_adapt4(msac, ts->cdf.mv.joint, N_MV_JOINTS - 1);
+    if (mv_joint & MV_JOINT_V)
+        ref_mv->y += read_mv_component_diff(msac, &ts->cdf.mv.comp[0], mv_prec);
+    if (mv_joint & MV_JOINT_H)
+        ref_mv->x += read_mv_component_diff(msac, &ts->cdf.mv.comp[1], mv_prec);
+}
+
+static void read_tx_tree(Dav1dTaskContext *const t,
+                         const enum RectTxfmSize from,
+                         const int depth, uint16_t *const masks,
+                         const int x_off, const int y_off)
+{
+    const Dav1dFrameContext *const f = t->f;
+    const int bx4 = t->bx & 31, by4 = t->by & 31;
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[from];
+    const int txw = t_dim->lw, txh = t_dim->lh;
+    int is_split;
+
+    if (depth < 2 && from > (int) TX_4X4) {
+        const int cat = 2 * (TX_64X64 - t_dim->max) - depth;
+        const int a = t->a->tx[bx4] < txw;
+        const int l = t->l.tx[by4] < txh;
+
+        is_split = dav1d_msac_decode_bool_adapt(&t->ts->msac,
+                       t->ts->cdf.m.txpart[cat][a + l]);
+        if (is_split)
+            masks[depth] |= 1 << (y_off * 4 + x_off);
+    } else {
+        is_split = 0;
+    }
+
+    if (is_split && t_dim->max > TX_8X8) {
+        const enum RectTxfmSize sub = t_dim->sub;
+        const TxfmInfo *const sub_t_dim = &dav1d_txfm_dimensions[sub];
+        const int txsw = sub_t_dim->w, txsh = sub_t_dim->h;
+
+        read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 0, y_off * 2 + 0);
+        t->bx += txsw;
+        if (txw >= txh && t->bx < f->bw)
+            read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 1, y_off * 2 + 0);
+        t->bx -= txsw;
+        t->by += txsh;
+        if (txh >= txw && t->by < f->bh) {
+            read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 0, y_off * 2 + 1);
+            t->bx += txsw;
+            if (txw >= txh && t->bx < f->bw)
+                read_tx_tree(t, sub, depth + 1, masks,
+                             x_off * 2 + 1, y_off * 2 + 1);
+            t->bx -= txsw;
+        }
+        t->by -= txsh;
+    } else {
+        dav1d_memset_pow2[t_dim->lw](&t->a->tx[bx4], is_split ? TX_4X4 : txw);
+        dav1d_memset_pow2[t_dim->lh](&t->l.tx[by4], is_split ? TX_4X4 : txh);
+    }
+}
+
+static int neg_deinterleave(int diff, int ref, int max) {
+    if (!ref) return diff;
+    if (ref >= (max - 1)) return max - diff - 1;
+    if (2 * ref < max) {
+        if (diff <= 2 * ref) {
+            if (diff & 1)
+                return ref + ((diff + 1) >> 1);
+            else
+                return ref - (diff >> 1);
+        }
+        return diff;
+    } else {
+        if (diff <= 2 * (max - ref - 1)) {
+            if (diff & 1)
+                return ref + ((diff + 1) >> 1);
+            else
+                return ref - (diff >> 1);
+        }
+        return max - (diff + 1);
+    }
+}
+
+static void find_matching_ref(const Dav1dTaskContext *const t,
+                              const enum EdgeFlags intra_edge_flags,
+                              const int bw4, const int bh4,
+                              const int w4, const int h4,
+                              const int have_left, const int have_top,
+                              const int ref, uint64_t masks[2])
+{
+    /*const*/ refmvs_block *const *r = &t->rt.r[(t->by & 31) + 5];
+    int count = 0;
+    int have_topleft = have_top && have_left;
+    int have_topright = imax(bw4, bh4) < 32 &&
+                        have_top && t->bx + bw4 < t->ts->tiling.col_end &&
+                        (intra_edge_flags & EDGE_I444_TOP_HAS_RIGHT);
+
+#define bs(rp) dav1d_block_dimensions[(rp)->bs]
+#define matches(rp) ((rp)->ref.ref[0] == ref + 1 && (rp)->ref.ref[1] == -1)
+
+    if (have_top) {
+        const refmvs_block *r2 = &r[-1][t->bx];
+        if (matches(r2)) {
+            masks[0] |= 1;
+            count = 1;
+        }
+        int aw4 = bs(r2)[0];
+        if (aw4 >= bw4) {
+            const int off = t->bx & (aw4 - 1);
+            if (off) have_topleft = 0;
+            if (aw4 - off > bw4) have_topright = 0;
+        } else {
+            unsigned mask = 1 << aw4;
+            for (int x = aw4; x < w4; x += aw4) {
+                r2 += aw4;
+                if (matches(r2)) {
+                    masks[0] |= mask;
+                    if (++count >= 8) return;
+                }
+                aw4 = bs(r2)[0];
+                mask <<= aw4;
+            }
+        }
+    }
+    if (have_left) {
+        /*const*/ refmvs_block *const *r2 = r;
+        if (matches(&r2[0][t->bx - 1])) {
+            masks[1] |= 1;
+            if (++count >= 8) return;
+        }
+        int lh4 = bs(&r2[0][t->bx - 1])[1];
+        if (lh4 >= bh4) {
+            if (t->by & (lh4 - 1)) have_topleft = 0;
+        } else {
+            unsigned mask = 1 << lh4;
+            for (int y = lh4; y < h4; y += lh4) {
+                r2 += lh4;
+                if (matches(&r2[0][t->bx - 1])) {
+                    masks[1] |= mask;
+                    if (++count >= 8) return;
+                }
+                lh4 = bs(&r2[0][t->bx - 1])[1];
+                mask <<= lh4;
+            }
+        }
+    }
+    if (have_topleft && matches(&r[-1][t->bx - 1])) {
+        masks[1] |= 1ULL << 32;
+        if (++count >= 8) return;
+    }
+    if (have_topright && matches(&r[-1][t->bx + bw4])) {
+        masks[0] |= 1ULL << 32;
+    }
+#undef matches
+}
+
+static void derive_warpmv(const Dav1dTaskContext *const t,
+                          const int bw4, const int bh4,
+                          const uint64_t masks[2], const union mv mv,
+                          Dav1dWarpedMotionParams *const wmp)
+{
+    int pts[8][2 /* in, out */][2 /* x, y */], np = 0;
+    /*const*/ refmvs_block *const *r = &t->rt.r[(t->by & 31) + 5];
+
+#define add_sample(dx, dy, sx, sy, rp) do { \
+    pts[np][0][0] = 16 * (2 * dx + sx * bs(rp)[0]) - 8; \
+    pts[np][0][1] = 16 * (2 * dy + sy * bs(rp)[1]) - 8; \
+    pts[np][1][0] = pts[np][0][0] + (rp)->mv.mv[0].x; \
+    pts[np][1][1] = pts[np][0][1] + (rp)->mv.mv[0].y; \
+    np++; \
+} while (0)
+
+    // use masks[] to find the projectable motion vectors in the edges
+    if ((unsigned) masks[0] == 1 && !(masks[1] >> 32)) {
+        const int off = t->bx & (bs(&r[-1][t->bx])[0] - 1);
+        add_sample(-off, 0, 1, -1, &r[-1][t->bx]);
+    } else for (unsigned off = 0, xmask = (uint32_t) masks[0]; np < 8 && xmask;) { // top
+        const int tz = ctz(xmask);
+        off += tz;
+        xmask >>= tz;
+        add_sample(off, 0, 1, -1, &r[-1][t->bx + off]);
+        xmask &= ~1;
+    }
+    if (np < 8 && masks[1] == 1) {
+        const int off = t->by & (bs(&r[0][t->bx - 1])[1] - 1);
+        add_sample(0, -off, -1, 1, &r[-off][t->bx - 1]);
+    } else for (unsigned off = 0, ymask = (uint32_t) masks[1]; np < 8 && ymask;) { // left
+        const int tz = ctz(ymask);
+        off += tz;
+        ymask >>= tz;
+        add_sample(0, off, -1, 1, &r[off][t->bx - 1]);
+        ymask &= ~1;
+    }
+    if (np < 8 && masks[1] >> 32) // top/left
+        add_sample(0, 0, -1, -1, &r[-1][t->bx - 1]);
+    if (np < 8 && masks[0] >> 32) // top/right
+        add_sample(bw4, 0, 1, -1, &r[-1][t->bx + bw4]);
+    assert(np > 0 && np <= 8);
+#undef bs
+
+    // select according to motion vector difference against a threshold
+    int mvd[8], ret = 0;
+    const int thresh = 4 * iclip(imax(bw4, bh4), 4, 28);
+    for (int i = 0; i < np; i++) {
+        mvd[i] = abs(pts[i][1][0] - pts[i][0][0] - mv.x) +
+                 abs(pts[i][1][1] - pts[i][0][1] - mv.y);
+        if (mvd[i] > thresh)
+            mvd[i] = -1;
+        else
+            ret++;
+    }
+    if (!ret) {
+        ret = 1;
+    } else for (int i = 0, j = np - 1, k = 0; k < np - ret; k++, i++, j--) {
+        while (mvd[i] != -1) i++;
+        while (mvd[j] == -1) j--;
+        assert(i != j);
+        if (i > j) break;
+        // replace the discarded samples;
+        mvd[i] = mvd[j];
+        memcpy(pts[i], pts[j], sizeof(*pts));
+    }
+
+    if (!dav1d_find_affine_int(pts, ret, bw4, bh4, mv, wmp, t->bx, t->by) &&
+        !dav1d_get_shear_params(wmp))
+    {
+        wmp->type = DAV1D_WM_TYPE_AFFINE;
+    } else
+        wmp->type = DAV1D_WM_TYPE_IDENTITY;
+}
+
+static inline int findoddzero(const uint8_t *buf, int len) {
+    for (int n = 0; n < len; n++)
+        if (!buf[n * 2]) return 1;
+    return 0;
+}
+
+// meant to be SIMD'able, so that theoretical complexity of this function
+// times block size goes from w4*h4 to w4+h4-1
+// a and b are previous two lines containing (a) top/left entries or (b)
+// top/left entries, with a[0] being either the first top or first left entry,
+// depending on top_offset being 1 or 0, and b being the first top/left entry
+// for whichever has one. left_offset indicates whether the (len-1)th entry
+// has a left neighbour.
+// output is order[] and ctx for each member of this diagonal.
+static void order_palette(const uint8_t *pal_idx, const ptrdiff_t stride,
+                          const int i, const int first, const int last,
+                          uint8_t (*const order)[8], uint8_t *const ctx)
+{
+    int have_top = i > first;
+
+    assert(pal_idx);
+    pal_idx += first + (i - first) * stride;
+    for (int j = first, n = 0; j >= last; have_top = 1, j--, n++, pal_idx += stride - 1) {
+        const int have_left = j > 0;
+
+        assert(have_left || have_top);
+
+#define add(v_in) do { \
+        const int v = v_in; \
+        assert((unsigned)v < 8U); \
+        order[n][o_idx++] = v; \
+        mask |= 1 << v; \
+    } while (0)
+
+        unsigned mask = 0;
+        int o_idx = 0;
+        if (!have_left) {
+            ctx[n] = 0;
+            add(pal_idx[-stride]);
+        } else if (!have_top) {
+            ctx[n] = 0;
+            add(pal_idx[-1]);
+        } else {
+            const int l = pal_idx[-1], t = pal_idx[-stride], tl = pal_idx[-(stride + 1)];
+            const int same_t_l = t == l;
+            const int same_t_tl = t == tl;
+            const int same_l_tl = l == tl;
+            const int same_all = same_t_l & same_t_tl & same_l_tl;
+
+            if (same_all) {
+                ctx[n] = 4;
+                add(t);
+            } else if (same_t_l) {
+                ctx[n] = 3;
+                add(t);
+                add(tl);
+            } else if (same_t_tl | same_l_tl) {
+                ctx[n] = 2;
+                add(tl);
+                add(same_t_tl ? l : t);
+            } else {
+                ctx[n] = 1;
+                add(imin(t, l));
+                add(imax(t, l));
+                add(tl);
+            }
+        }
+        for (unsigned m = 1, bit = 0; m < 0x100; m <<= 1, bit++)
+            if (!(mask & m))
+                order[n][o_idx++] = bit;
+        assert(o_idx == 8);
+#undef add
+    }
+}
+
+static void read_pal_indices(Dav1dTaskContext *const t,
+                             uint8_t *const pal_idx,
+                             const int pal_sz, const int pl,
+                             const int w4, const int h4,
+                             const int bw4, const int bh4)
+{
+    Dav1dTileState *const ts = t->ts;
+    const ptrdiff_t stride = bw4 * 4;
+    assert(pal_idx);
+    uint8_t *const pal_tmp = t->scratch.pal_idx_uv;
+    pal_tmp[0] = dav1d_msac_decode_uniform(&ts->msac, pal_sz);
+    uint16_t (*const color_map_cdf)[8] =
+        ts->cdf.m.color_map[pl][pal_sz - 2];
+    uint8_t (*const order)[8] = t->scratch.pal_order;
+    uint8_t *const ctx = t->scratch.pal_ctx;
+    for (int i = 1; i < 4 * (w4 + h4) - 1; i++) {
+        // top/left-to-bottom/right diagonals ("wave-front")
+        const int first = imin(i, w4 * 4 - 1);
+        const int last = imax(0, i - h4 * 4 + 1);
+        order_palette(pal_tmp, stride, i, first, last, order, ctx);
+        for (int j = first, m = 0; j >= last; j--, m++) {
+            const int color_idx = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                                      color_map_cdf[ctx[m]], pal_sz - 1);
+            pal_tmp[(i - j) * stride + j] = order[m][color_idx];
+        }
+    }
+
+    t->c->pal_dsp.pal_idx_finish(pal_idx, pal_tmp, bw4 * 4, bh4 * 4,
+                                 w4 * 4, h4 * 4);
+}
+
+static void read_vartx_tree(Dav1dTaskContext *const t,
+                            Av1Block *const b, const enum BlockSize bs,
+                            const int bx4, const int by4)
+{
+    const Dav1dFrameContext *const f = t->f;
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+    const int bw4 = b_dim[0], bh4 = b_dim[1];
+
+    // var-tx tree coding
+    uint16_t tx_split[2] = { 0 };
+    b->max_ytx = dav1d_max_txfm_size_for_bs[bs][0];
+    if (!b->skip && (f->frame_hdr->segmentation.lossless[b->seg_id] ||
+                     b->max_ytx == TX_4X4))
+    {
+        b->max_ytx = b->uvtx = TX_4X4;
+        if (f->frame_hdr->txfm_mode == DAV1D_TX_SWITCHABLE) {
+            dav1d_memset_pow2[b_dim[2]](&t->a->tx[bx4], TX_4X4);
+            dav1d_memset_pow2[b_dim[3]](&t->l.tx[by4], TX_4X4);
+        }
+    } else if (f->frame_hdr->txfm_mode != DAV1D_TX_SWITCHABLE || b->skip) {
+        if (f->frame_hdr->txfm_mode == DAV1D_TX_SWITCHABLE) {
+            dav1d_memset_pow2[b_dim[2]](&t->a->tx[bx4], b_dim[2 + 0]);
+            dav1d_memset_pow2[b_dim[3]](&t->l.tx[by4], b_dim[2 + 1]);
+        }
+        b->uvtx = dav1d_max_txfm_size_for_bs[bs][f->cur.p.layout];
+    } else {
+        assert(bw4 <= 16 || bh4 <= 16 || b->max_ytx == TX_64X64);
+        int y, x, y_off, x_off;
+        const TxfmInfo *const ytx = &dav1d_txfm_dimensions[b->max_ytx];
+        for (y = 0, y_off = 0; y < bh4; y += ytx->h, y_off++) {
+            for (x = 0, x_off = 0; x < bw4; x += ytx->w, x_off++) {
+                read_tx_tree(t, b->max_ytx, 0, tx_split, x_off, y_off);
+                // contexts are updated inside read_tx_tree()
+                t->bx += ytx->w;
+            }
+            t->bx -= x;
+            t->by += ytx->h;
+        }
+        t->by -= y;
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-vartxtree[%x/%x]: r=%d\n",
+                   tx_split[0], tx_split[1], t->ts->msac.rng);
+        b->uvtx = dav1d_max_txfm_size_for_bs[bs][f->cur.p.layout];
+    }
+    assert(!(tx_split[0] & ~0x33));
+    b->tx_split0 = (uint8_t)tx_split[0];
+    b->tx_split1 = tx_split[1];
+}
+
+static inline unsigned get_prev_frame_segid(const Dav1dFrameContext *const f,
+                                            const int by, const int bx,
+                                            const int w4, int h4,
+                                            const uint8_t *ref_seg_map,
+                                            const ptrdiff_t stride)
+{
+    assert(f->frame_hdr->primary_ref_frame != DAV1D_PRIMARY_REF_NONE);
+
+    unsigned seg_id = 8;
+    ref_seg_map += by * stride + bx;
+    do {
+        for (int x = 0; x < w4; x++)
+            seg_id = imin(seg_id, ref_seg_map[x]);
+        ref_seg_map += stride;
+    } while (--h4 > 0 && seg_id);
+    assert(seg_id < 8);
+
+    return seg_id;
+}
+
+static inline void splat_oneref_mv(const Dav1dContext *const c,
+                                   Dav1dTaskContext *const t,
+                                   const enum BlockSize bs,
+                                   const Av1Block *const b,
+                                   const int bw4, const int bh4)
+{
+    const enum InterPredMode mode = b->inter_mode;
+    const refmvs_block ALIGN(tmpl, 16) = (refmvs_block) {
+        .ref.ref = { b->ref[0] + 1, b->interintra_type ? 0 : -1 },
+        .mv.mv[0] = b->mv[0],
+        .bs = bs,
+        .mf = (mode == GLOBALMV && imin(bw4, bh4) >= 2) | ((mode == NEWMV) * 2),
+    };
+    c->refmvs_dsp.splat_mv(&t->rt.r[(t->by & 31) + 5], &tmpl, t->bx, bw4, bh4);
+}
+
+static inline void splat_intrabc_mv(const Dav1dContext *const c,
+                                    Dav1dTaskContext *const t,
+                                    const enum BlockSize bs,
+                                    const Av1Block *const b,
+                                    const int bw4, const int bh4)
+{
+    const refmvs_block ALIGN(tmpl, 16) = (refmvs_block) {
+        .ref.ref = { 0, -1 },
+        .mv.mv[0] = b->mv[0],
+        .bs = bs,
+        .mf = 0,
+    };
+    c->refmvs_dsp.splat_mv(&t->rt.r[(t->by & 31) + 5], &tmpl, t->bx, bw4, bh4);
+}
+
+static inline void splat_tworef_mv(const Dav1dContext *const c,
+                                   Dav1dTaskContext *const t,
+                                   const enum BlockSize bs,
+                                   const Av1Block *const b,
+                                   const int bw4, const int bh4)
+{
+    assert(bw4 >= 2 && bh4 >= 2);
+    const enum CompInterPredMode mode = b->inter_mode;
+    const refmvs_block ALIGN(tmpl, 16) = (refmvs_block) {
+        .ref.ref = { b->ref[0] + 1, b->ref[1] + 1 },
+        .mv.mv = { b->mv[0], b->mv[1] },
+        .bs = bs,
+        .mf = (mode == GLOBALMV_GLOBALMV) | !!((1 << mode) & (0xbc)) * 2,
+    };
+    c->refmvs_dsp.splat_mv(&t->rt.r[(t->by & 31) + 5], &tmpl, t->bx, bw4, bh4);
+}
+
+static inline void splat_intraref(const Dav1dContext *const c,
+                                  Dav1dTaskContext *const t,
+                                  const enum BlockSize bs,
+                                  const int bw4, const int bh4)
+{
+    const refmvs_block ALIGN(tmpl, 16) = (refmvs_block) {
+        .ref.ref = { 0, -1 },
+        .mv.mv[0].n = INVALID_MV,
+        .bs = bs,
+        .mf = 0,
+    };
+    c->refmvs_dsp.splat_mv(&t->rt.r[(t->by & 31) + 5], &tmpl, t->bx, bw4, bh4);
+}
+
+static void mc_lowest_px(int *const dst, const int by4, const int bh4,
+                         const int mvy, const int ss_ver,
+                         const struct ScalableMotionParams *const smp)
+{
+    const int v_mul = 4 >> ss_ver;
+    if (!smp->scale) {
+        const int my = mvy >> (3 + ss_ver), dy = mvy & (15 >> !ss_ver);
+        *dst = imax(*dst, (by4 + bh4) * v_mul + my + 4 * !!dy);
+    } else {
+        int y = (by4 * v_mul << 4) + mvy * (1 << !ss_ver);
+        const int64_t tmp = (int64_t)(y) * smp->scale + (smp->scale - 0x4000) * 8;
+        y = apply_sign64((int)((llabs(tmp) + 128) >> 8), tmp) + 32;
+        const int bottom = ((y + (bh4 * v_mul - 1) * smp->step) >> 10) + 1 + 4;
+        *dst = imax(*dst, bottom);
+    }
+}
+
+static ALWAYS_INLINE void affine_lowest_px(Dav1dTaskContext *const t, int *const dst,
+                                           const uint8_t *const b_dim,
+                                           const Dav1dWarpedMotionParams *const wmp,
+                                           const int ss_ver, const int ss_hor)
+{
+    const int h_mul = 4 >> ss_hor, v_mul = 4 >> ss_ver;
+    assert(!((b_dim[0] * h_mul) & 7) && !((b_dim[1] * v_mul) & 7));
+    const int32_t *const mat = wmp->matrix;
+    const int y = b_dim[1] * v_mul - 8; // lowest y
+
+    const int src_y = t->by * 4 + ((y + 4) << ss_ver);
+    const int64_t mat5_y = (int64_t) mat[5] * src_y + mat[1];
+    // check left- and right-most blocks
+    for (int x = 0; x < b_dim[0] * h_mul; x += imax(8, b_dim[0] * h_mul - 8)) {
+        // calculate transformation relative to center of 8x8 block in
+        // luma pixel units
+        const int src_x = t->bx * 4 + ((x + 4) << ss_hor);
+        const int64_t mvy = ((int64_t) mat[4] * src_x + mat5_y) >> ss_ver;
+        const int dy = (int) (mvy >> 16) - 4;
+        *dst = imax(*dst, dy + 4 + 8);
+    }
+}
+
+static NOINLINE void affine_lowest_px_luma(Dav1dTaskContext *const t, int *const dst,
+                                           const uint8_t *const b_dim,
+                                           const Dav1dWarpedMotionParams *const wmp)
+{
+    affine_lowest_px(t, dst, b_dim, wmp, 0, 0);
+}
+
+static NOINLINE void affine_lowest_px_chroma(Dav1dTaskContext *const t, int *const dst,
+                                             const uint8_t *const b_dim,
+                                             const Dav1dWarpedMotionParams *const wmp)
+{
+    const Dav1dFrameContext *const f = t->f;
+    assert(f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400);
+    if (f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I444)
+        affine_lowest_px_luma(t, dst, b_dim, wmp);
+    else
+        affine_lowest_px(t, dst, b_dim, wmp, f->cur.p.layout & DAV1D_PIXEL_LAYOUT_I420, 1);
+}
+
+static void obmc_lowest_px(Dav1dTaskContext *const t,
+                           int (*const dst)[2], const int is_chroma,
+                           const uint8_t *const b_dim,
+                           const int bx4, const int by4, const int w4, const int h4)
+{
+    assert(!(t->bx & 1) && !(t->by & 1));
+    const Dav1dFrameContext *const f = t->f;
+    /*const*/ refmvs_block **r = &t->rt.r[(t->by & 31) + 5];
+    const int ss_ver = is_chroma && f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = is_chroma && f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int h_mul = 4 >> ss_hor, v_mul = 4 >> ss_ver;
+
+    if (t->by > t->ts->tiling.row_start &&
+        (!is_chroma || b_dim[0] * h_mul + b_dim[1] * v_mul >= 16))
+    {
+        for (int i = 0, x = 0; x < w4 && i < imin(b_dim[2], 4); ) {
+            // only odd blocks are considered for overlap handling, hence +1
+            const refmvs_block *const a_r = &r[-1][t->bx + x + 1];
+            const uint8_t *const a_b_dim = dav1d_block_dimensions[a_r->bs];
+
+            if (a_r->ref.ref[0] > 0) {
+                const int oh4 = imin(b_dim[1], 16) >> 1;
+                mc_lowest_px(&dst[a_r->ref.ref[0] - 1][is_chroma], t->by,
+                             (oh4 * 3 + 3) >> 2, a_r->mv.mv[0].y, ss_ver,
+                             &f->svc[a_r->ref.ref[0] - 1][1]);
+                i++;
+            }
+            x += imax(a_b_dim[0], 2);
+        }
+    }
+
+    if (t->bx > t->ts->tiling.col_start)
+        for (int i = 0, y = 0; y < h4 && i < imin(b_dim[3], 4); ) {
+            // only odd blocks are considered for overlap handling, hence +1
+            const refmvs_block *const l_r = &r[y + 1][t->bx - 1];
+            const uint8_t *const l_b_dim = dav1d_block_dimensions[l_r->bs];
+
+            if (l_r->ref.ref[0] > 0) {
+                const int oh4 = iclip(l_b_dim[1], 2, b_dim[1]);
+                mc_lowest_px(&dst[l_r->ref.ref[0] - 1][is_chroma],
+                             t->by + y, oh4, l_r->mv.mv[0].y, ss_ver,
+                             &f->svc[l_r->ref.ref[0] - 1][1]);
+                i++;
+            }
+            y += imax(l_b_dim[1], 2);
+        }
+}
+
+static int decode_b(Dav1dTaskContext *const t,
+                    const enum BlockLevel bl,
+                    const enum BlockSize bs,
+                    const enum BlockPartition bp,
+                    const enum EdgeFlags intra_edge_flags) {
+    Dav1dTileState *const ts = t->ts;
+    const Dav1dFrameContext *const f = t->f;
+    Av1Block b_mem, *const b = t->frame_thread.pass ?
+        &f->frame_thread.b[t->by * f->b4_stride + t->bx] : &b_mem;
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+    const int bx4 = t->bx & 31, by4 = t->by & 31;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int cbx4 = bx4 >> ss_hor, cby4 = by4 >> ss_ver;
+    const int bw4 = b_dim[0], bh4 = b_dim[1];
+    const int w4 = imin(bw4, f->bw - t->bx), h4 = imin(bh4, f->bh - t->by);
+    const int cbw4 = (bw4 + ss_hor) >> ss_hor, cbh4 = (bh4 + ss_ver) >> ss_ver;
+    const int have_left = t->bx > ts->tiling.col_start;
+    const int have_top = t->by > ts->tiling.row_start;
+    const int has_chroma = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400 &&
+                           (bw4 > ss_hor || t->bx & 1) &&
+                           (bh4 > ss_ver || t->by & 1);
+
+    if (t->frame_thread.pass == 2) {
+        if (b->intra) {
+            f->bd_fn.recon_b_intra(t, bs, intra_edge_flags, b);
+
+            const enum IntraPredMode y_mode_nofilt =
+                b->y_mode == FILTER_PRED ? DC_PRED : b->y_mode;
+#define set_ctx(rep_macro) \
+            rep_macro(edge->mode, off, y_mode_nofilt); \
+            rep_macro(edge->intra, off, 1)
+            BlockContext *edge = t->a;
+            for (int i = 0, off = bx4; i < 2; i++, off = by4, edge = &t->l) {
+                case_set(b_dim[2 + i]);
+            }
+#undef set_ctx
+            if (IS_INTER_OR_SWITCH(f->frame_hdr)) {
+                refmvs_block *const r = &t->rt.r[(t->by & 31) + 5 + bh4 - 1][t->bx];
+                for (int x = 0; x < bw4; x++) {
+                    r[x].ref.ref[0] = 0;
+                    r[x].bs = bs;
+                }
+                refmvs_block *const *rr = &t->rt.r[(t->by & 31) + 5];
+                for (int y = 0; y < bh4 - 1; y++) {
+                    rr[y][t->bx + bw4 - 1].ref.ref[0] = 0;
+                    rr[y][t->bx + bw4 - 1].bs = bs;
+                }
+            }
+
+            if (has_chroma) {
+                uint8_t uv_mode = b->uv_mode;
+                dav1d_memset_pow2[ulog2(cbw4)](&t->a->uvmode[cbx4], uv_mode);
+                dav1d_memset_pow2[ulog2(cbh4)](&t->l.uvmode[cby4], uv_mode);
+            }
+        } else {
+            if (IS_INTER_OR_SWITCH(f->frame_hdr) /* not intrabc */ &&
+                b->comp_type == COMP_INTER_NONE && b->motion_mode == MM_WARP)
+            {
+                if (b->matrix[0] == INT16_MIN) {
+                    t->warpmv.type = DAV1D_WM_TYPE_IDENTITY;
+                } else {
+                    t->warpmv.type = DAV1D_WM_TYPE_AFFINE;
+                    t->warpmv.matrix[2] = b->matrix[0] + 0x10000;
+                    t->warpmv.matrix[3] = b->matrix[1];
+                    t->warpmv.matrix[4] = b->matrix[2];
+                    t->warpmv.matrix[5] = b->matrix[3] + 0x10000;
+                    dav1d_set_affine_mv2d(bw4, bh4, b->mv2d, &t->warpmv,
+                                          t->bx, t->by);
+                    dav1d_get_shear_params(&t->warpmv);
+#define signabs(v) v < 0 ? '-' : ' ', abs(v)
+                    if (DEBUG_BLOCK_INFO)
+                        printf("[ %c%x %c%x %c%x\n  %c%x %c%x %c%x ]\n"
+                               "alpha=%c%x, beta=%c%x, gamma=%c%x, delta=%c%x, mv=y:%d,x:%d\n",
+                               signabs(t->warpmv.matrix[0]),
+                               signabs(t->warpmv.matrix[1]),
+                               signabs(t->warpmv.matrix[2]),
+                               signabs(t->warpmv.matrix[3]),
+                               signabs(t->warpmv.matrix[4]),
+                               signabs(t->warpmv.matrix[5]),
+                               signabs(t->warpmv.u.p.alpha),
+                               signabs(t->warpmv.u.p.beta),
+                               signabs(t->warpmv.u.p.gamma),
+                               signabs(t->warpmv.u.p.delta),
+                               b->mv2d.y, b->mv2d.x);
+#undef signabs
+                }
+            }
+            if (f->bd_fn.recon_b_inter(t, bs, b)) return -1;
+
+            const uint8_t *const filter = dav1d_filter_dir[b->filter2d];
+            BlockContext *edge = t->a;
+            for (int i = 0, off = bx4; i < 2; i++, off = by4, edge = &t->l) {
+#define set_ctx(rep_macro) \
+                rep_macro(edge->filter[0], off, filter[0]); \
+                rep_macro(edge->filter[1], off, filter[1]); \
+                rep_macro(edge->intra, off, 0)
+                case_set(b_dim[2 + i]);
+#undef set_ctx
+            }
+
+            if (IS_INTER_OR_SWITCH(f->frame_hdr)) {
+                refmvs_block *const r = &t->rt.r[(t->by & 31) + 5 + bh4 - 1][t->bx];
+                for (int x = 0; x < bw4; x++) {
+                    r[x].ref.ref[0] = b->ref[0] + 1;
+                    r[x].mv.mv[0] = b->mv[0];
+                    r[x].bs = bs;
+                }
+                refmvs_block *const *rr = &t->rt.r[(t->by & 31) + 5];
+                for (int y = 0; y < bh4 - 1; y++) {
+                    rr[y][t->bx + bw4 - 1].ref.ref[0] = b->ref[0] + 1;
+                    rr[y][t->bx + bw4 - 1].mv.mv[0] = b->mv[0];
+                    rr[y][t->bx + bw4 - 1].bs = bs;
+                }
+            }
+
+            if (has_chroma) {
+                dav1d_memset_pow2[ulog2(cbw4)](&t->a->uvmode[cbx4], DC_PRED);
+                dav1d_memset_pow2[ulog2(cbh4)](&t->l.uvmode[cby4], DC_PRED);
+            }
+        }
+        return 0;
+    }
+
+    const int cw4 = (w4 + ss_hor) >> ss_hor, ch4 = (h4 + ss_ver) >> ss_ver;
+
+    b->bl = bl;
+    b->bp = bp;
+    b->bs = bs;
+
+    const Dav1dSegmentationData *seg = NULL;
+
+    // segment_id (if seg_feature for skip/ref/gmv is enabled)
+    int seg_pred = 0;
+    if (f->frame_hdr->segmentation.enabled) {
+        if (!f->frame_hdr->segmentation.update_map) {
+            if (f->prev_segmap) {
+                unsigned seg_id = get_prev_frame_segid(f, t->by, t->bx, w4, h4,
+                                                       f->prev_segmap,
+                                                       f->b4_stride);
+                if (seg_id >= 8) return -1;
+                b->seg_id = seg_id;
+            } else {
+                b->seg_id = 0;
+            }
+            seg = &f->frame_hdr->segmentation.seg_data.d[b->seg_id];
+        } else if (f->frame_hdr->segmentation.seg_data.preskip) {
+            if (f->frame_hdr->segmentation.temporal &&
+                (seg_pred = dav1d_msac_decode_bool_adapt(&ts->msac,
+                                ts->cdf.m.seg_pred[t->a->seg_pred[bx4] +
+                                t->l.seg_pred[by4]])))
+            {
+                // temporal predicted seg_id
+                if (f->prev_segmap) {
+                    unsigned seg_id = get_prev_frame_segid(f, t->by, t->bx,
+                                                           w4, h4,
+                                                           f->prev_segmap,
+                                                           f->b4_stride);
+                    if (seg_id >= 8) return -1;
+                    b->seg_id = seg_id;
+                } else {
+                    b->seg_id = 0;
+                }
+            } else {
+                int seg_ctx;
+                const unsigned pred_seg_id =
+                    get_cur_frame_segid(t->by, t->bx, have_top, have_left,
+                                        &seg_ctx, f->cur_segmap, f->b4_stride);
+                const unsigned diff = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                                          ts->cdf.m.seg_id[seg_ctx],
+                                          DAV1D_MAX_SEGMENTS - 1);
+                const unsigned last_active_seg_id =
+                    f->frame_hdr->segmentation.seg_data.last_active_segid;
+                b->seg_id = neg_deinterleave(diff, pred_seg_id,
+                                             last_active_seg_id + 1);
+                if (b->seg_id > last_active_seg_id) b->seg_id = 0; // error?
+                if (b->seg_id >= DAV1D_MAX_SEGMENTS) b->seg_id = 0; // error?
+            }
+
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-segid[preskip;%d]: r=%d\n",
+                       b->seg_id, ts->msac.rng);
+
+            seg = &f->frame_hdr->segmentation.seg_data.d[b->seg_id];
+        }
+    } else {
+        b->seg_id = 0;
+    }
+
+    // skip_mode
+    if ((!seg || (!seg->globalmv && seg->ref == -1 && !seg->skip)) &&
+        f->frame_hdr->skip_mode_enabled && imin(bw4, bh4) > 1)
+    {
+        const int smctx = t->a->skip_mode[bx4] + t->l.skip_mode[by4];
+        b->skip_mode = dav1d_msac_decode_bool_adapt(&ts->msac,
+                           ts->cdf.m.skip_mode[smctx]);
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-skipmode[%d]: r=%d\n", b->skip_mode, ts->msac.rng);
+    } else {
+        b->skip_mode = 0;
+    }
+
+    // skip
+    if (b->skip_mode || (seg && seg->skip)) {
+        b->skip = 1;
+    } else {
+        const int sctx = t->a->skip[bx4] + t->l.skip[by4];
+        b->skip = dav1d_msac_decode_bool_adapt(&ts->msac, ts->cdf.m.skip[sctx]);
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-skip[%d]: r=%d\n", b->skip, ts->msac.rng);
+    }
+
+    // segment_id
+    if (f->frame_hdr->segmentation.enabled &&
+        f->frame_hdr->segmentation.update_map &&
+        !f->frame_hdr->segmentation.seg_data.preskip)
+    {
+        if (!b->skip && f->frame_hdr->segmentation.temporal &&
+            (seg_pred = dav1d_msac_decode_bool_adapt(&ts->msac,
+                            ts->cdf.m.seg_pred[t->a->seg_pred[bx4] +
+                            t->l.seg_pred[by4]])))
+        {
+            // temporal predicted seg_id
+            if (f->prev_segmap) {
+                unsigned seg_id = get_prev_frame_segid(f, t->by, t->bx, w4, h4,
+                                                       f->prev_segmap,
+                                                       f->b4_stride);
+                if (seg_id >= 8) return -1;
+                b->seg_id = seg_id;
+            } else {
+                b->seg_id = 0;
+            }
+        } else {
+            int seg_ctx;
+            const unsigned pred_seg_id =
+                get_cur_frame_segid(t->by, t->bx, have_top, have_left,
+                                    &seg_ctx, f->cur_segmap, f->b4_stride);
+            if (b->skip) {
+                b->seg_id = pred_seg_id;
+            } else {
+                const unsigned diff = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                                          ts->cdf.m.seg_id[seg_ctx],
+                                          DAV1D_MAX_SEGMENTS - 1);
+                const unsigned last_active_seg_id =
+                    f->frame_hdr->segmentation.seg_data.last_active_segid;
+                b->seg_id = neg_deinterleave(diff, pred_seg_id,
+                                             last_active_seg_id + 1);
+                if (b->seg_id > last_active_seg_id) b->seg_id = 0; // error?
+            }
+            if (b->seg_id >= DAV1D_MAX_SEGMENTS) b->seg_id = 0; // error?
+        }
+
+        seg = &f->frame_hdr->segmentation.seg_data.d[b->seg_id];
+
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-segid[postskip;%d]: r=%d\n",
+                   b->seg_id, ts->msac.rng);
+    }
+
+    // cdef index
+    if (!b->skip) {
+        const int idx = f->seq_hdr->sb128 ? ((t->bx & 16) >> 4) +
+                                           ((t->by & 16) >> 3) : 0;
+        if (t->cur_sb_cdef_idx_ptr[idx] == -1) {
+            const int v = dav1d_msac_decode_bools(&ts->msac,
+                              f->frame_hdr->cdef.n_bits);
+            t->cur_sb_cdef_idx_ptr[idx] = v;
+            if (bw4 > 16) t->cur_sb_cdef_idx_ptr[idx + 1] = v;
+            if (bh4 > 16) t->cur_sb_cdef_idx_ptr[idx + 2] = v;
+            if (bw4 == 32 && bh4 == 32) t->cur_sb_cdef_idx_ptr[idx + 3] = v;
+
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-cdef_idx[%d]: r=%d\n",
+                        *t->cur_sb_cdef_idx_ptr, ts->msac.rng);
+        }
+    }
+
+    // delta-q/lf
+    if (!((t->bx | t->by) & (31 >> !f->seq_hdr->sb128))) {
+        const int prev_qidx = ts->last_qidx;
+        const int have_delta_q = f->frame_hdr->delta.q.present &&
+            (bs != (f->seq_hdr->sb128 ? BS_128x128 : BS_64x64) || !b->skip);
+
+        uint32_t prev_delta_lf = ts->last_delta_lf.u32;
+
+        if (have_delta_q) {
+            int delta_q = dav1d_msac_decode_symbol_adapt4(&ts->msac,
+                                                          ts->cdf.m.delta_q, 3);
+            if (delta_q == 3) {
+                const int n_bits = 1 + dav1d_msac_decode_bools(&ts->msac, 3);
+                delta_q = dav1d_msac_decode_bools(&ts->msac, n_bits) +
+                          1 + (1 << n_bits);
+            }
+            if (delta_q) {
+                if (dav1d_msac_decode_bool_equi(&ts->msac)) delta_q = -delta_q;
+                delta_q *= 1 << f->frame_hdr->delta.q.res_log2;
+            }
+            ts->last_qidx = iclip(ts->last_qidx + delta_q, 1, 255);
+            if (have_delta_q && DEBUG_BLOCK_INFO)
+                printf("Post-delta_q[%d->%d]: r=%d\n",
+                       delta_q, ts->last_qidx, ts->msac.rng);
+
+            if (f->frame_hdr->delta.lf.present) {
+                const int n_lfs = f->frame_hdr->delta.lf.multi ?
+                    f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400 ? 4 : 2 : 1;
+
+                for (int i = 0; i < n_lfs; i++) {
+                    int delta_lf = dav1d_msac_decode_symbol_adapt4(&ts->msac,
+                        ts->cdf.m.delta_lf[i + f->frame_hdr->delta.lf.multi], 3);
+                    if (delta_lf == 3) {
+                        const int n_bits = 1 + dav1d_msac_decode_bools(&ts->msac, 3);
+                        delta_lf = dav1d_msac_decode_bools(&ts->msac, n_bits) +
+                                   1 + (1 << n_bits);
+                    }
+                    if (delta_lf) {
+                        if (dav1d_msac_decode_bool_equi(&ts->msac))
+                            delta_lf = -delta_lf;
+                        delta_lf *= 1 << f->frame_hdr->delta.lf.res_log2;
+                    }
+                    ts->last_delta_lf.i8[i] =
+                        iclip(ts->last_delta_lf.i8[i] + delta_lf, -63, 63);
+                    if (have_delta_q && DEBUG_BLOCK_INFO)
+                        printf("Post-delta_lf[%d:%d]: r=%d\n", i, delta_lf,
+                               ts->msac.rng);
+                }
+            }
+        }
+        if (ts->last_qidx == f->frame_hdr->quant.yac) {
+            // assign frame-wide q values to this sb
+            ts->dq = f->dq;
+        } else if (ts->last_qidx != prev_qidx) {
+            // find sb-specific quant parameters
+            init_quant_tables(f->seq_hdr, f->frame_hdr, ts->last_qidx, ts->dqmem);
+            ts->dq = ts->dqmem;
+        }
+        if (!ts->last_delta_lf.u32) {
+            // assign frame-wide lf values to this sb
+            ts->lflvl = f->lf.lvl;
+        } else if (ts->last_delta_lf.u32 != prev_delta_lf) {
+            // find sb-specific lf lvl parameters
+            ts->lflvl = ts->lflvlmem;
+            dav1d_calc_lf_values(ts->lflvlmem, f->frame_hdr, ts->last_delta_lf.i8);
+        }
+    }
+
+    if (b->skip_mode) {
+        b->intra = 0;
+    } else if (IS_INTER_OR_SWITCH(f->frame_hdr)) {
+        if (seg && (seg->ref >= 0 || seg->globalmv)) {
+            b->intra = !seg->ref;
+        } else {
+            const int ictx = get_intra_ctx(t->a, &t->l, by4, bx4,
+                                           have_top, have_left);
+            b->intra = !dav1d_msac_decode_bool_adapt(&ts->msac,
+                            ts->cdf.m.intra[ictx]);
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-intra[%d]: r=%d\n", b->intra, ts->msac.rng);
+        }
+    } else if (f->frame_hdr->allow_intrabc) {
+        b->intra = !dav1d_msac_decode_bool_adapt(&ts->msac, ts->cdf.m.intrabc);
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-intrabcflag[%d]: r=%d\n", b->intra, ts->msac.rng);
+    } else {
+        b->intra = 1;
+    }
+
+    // intra/inter-specific stuff
+    if (b->intra) {
+        uint16_t *const ymode_cdf = IS_INTER_OR_SWITCH(f->frame_hdr) ?
+            ts->cdf.m.y_mode[dav1d_ymode_size_context[bs]] :
+            ts->cdf.kfym[dav1d_intra_mode_context[t->a->mode[bx4]]]
+                        [dav1d_intra_mode_context[t->l.mode[by4]]];
+        b->y_mode = dav1d_msac_decode_symbol_adapt16(&ts->msac, ymode_cdf,
+                                                     N_INTRA_PRED_MODES - 1);
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-ymode[%d]: r=%d\n", b->y_mode, ts->msac.rng);
+
+        // angle delta
+        if (b_dim[2] + b_dim[3] >= 2 && b->y_mode >= VERT_PRED &&
+            b->y_mode <= VERT_LEFT_PRED)
+        {
+            uint16_t *const acdf = ts->cdf.m.angle_delta[b->y_mode - VERT_PRED];
+            const int angle = dav1d_msac_decode_symbol_adapt8(&ts->msac, acdf, 6);
+            b->y_angle = angle - 3;
+        } else {
+            b->y_angle = 0;
+        }
+
+        if (has_chroma) {
+            const int cfl_allowed = f->frame_hdr->segmentation.lossless[b->seg_id] ?
+                cbw4 == 1 && cbh4 == 1 : !!(cfl_allowed_mask & (1 << bs));
+            uint16_t *const uvmode_cdf = ts->cdf.m.uv_mode[cfl_allowed][b->y_mode];
+            b->uv_mode = dav1d_msac_decode_symbol_adapt16(&ts->msac, uvmode_cdf,
+                             N_UV_INTRA_PRED_MODES - 1 - !cfl_allowed);
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-uvmode[%d]: r=%d\n", b->uv_mode, ts->msac.rng);
+
+            b->uv_angle = 0;
+            if (b->uv_mode == CFL_PRED) {
+#define SIGN(a) (!!(a) + ((a) > 0))
+                const int sign = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                                     ts->cdf.m.cfl_sign, 7) + 1;
+                const int sign_u = sign * 0x56 >> 8, sign_v = sign - sign_u * 3;
+                assert(sign_u == sign / 3);
+                if (sign_u) {
+                    const int ctx = (sign_u == 2) * 3 + sign_v;
+                    b->cfl_alpha[0] = dav1d_msac_decode_symbol_adapt16(&ts->msac,
+                                          ts->cdf.m.cfl_alpha[ctx], 15) + 1;
+                    if (sign_u == 1) b->cfl_alpha[0] = -b->cfl_alpha[0];
+                } else {
+                    b->cfl_alpha[0] = 0;
+                }
+                if (sign_v) {
+                    const int ctx = (sign_v == 2) * 3 + sign_u;
+                    b->cfl_alpha[1] = dav1d_msac_decode_symbol_adapt16(&ts->msac,
+                                          ts->cdf.m.cfl_alpha[ctx], 15) + 1;
+                    if (sign_v == 1) b->cfl_alpha[1] = -b->cfl_alpha[1];
+                } else {
+                    b->cfl_alpha[1] = 0;
+                }
+#undef SIGN
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-uvalphas[%d/%d]: r=%d\n",
+                           b->cfl_alpha[0], b->cfl_alpha[1], ts->msac.rng);
+            } else if (b_dim[2] + b_dim[3] >= 2 && b->uv_mode >= VERT_PRED &&
+                       b->uv_mode <= VERT_LEFT_PRED)
+            {
+                uint16_t *const acdf = ts->cdf.m.angle_delta[b->uv_mode - VERT_PRED];
+                const int angle = dav1d_msac_decode_symbol_adapt8(&ts->msac, acdf, 6);
+                b->uv_angle = angle - 3;
+            }
+        }
+
+        b->pal_sz[0] = b->pal_sz[1] = 0;
+        if (f->frame_hdr->allow_screen_content_tools &&
+            imax(bw4, bh4) <= 16 && bw4 + bh4 >= 4)
+        {
+            const int sz_ctx = b_dim[2] + b_dim[3] - 2;
+            if (b->y_mode == DC_PRED) {
+                const int pal_ctx = (t->a->pal_sz[bx4] > 0) + (t->l.pal_sz[by4] > 0);
+                const int use_y_pal = dav1d_msac_decode_bool_adapt(&ts->msac,
+                                          ts->cdf.m.pal_y[sz_ctx][pal_ctx]);
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-y_pal[%d]: r=%d\n", use_y_pal, ts->msac.rng);
+                if (use_y_pal)
+                    f->bd_fn.read_pal_plane(t, b, 0, sz_ctx, bx4, by4);
+            }
+
+            if (has_chroma && b->uv_mode == DC_PRED) {
+                const int pal_ctx = b->pal_sz[0] > 0;
+                const int use_uv_pal = dav1d_msac_decode_bool_adapt(&ts->msac,
+                                           ts->cdf.m.pal_uv[pal_ctx]);
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-uv_pal[%d]: r=%d\n", use_uv_pal, ts->msac.rng);
+                if (use_uv_pal) // see aomedia bug 2183 for why we use luma coordinates
+                    f->bd_fn.read_pal_uv(t, b, sz_ctx, bx4, by4);
+            }
+        }
+
+        if (b->y_mode == DC_PRED && !b->pal_sz[0] &&
+            imax(b_dim[2], b_dim[3]) <= 3 && f->seq_hdr->filter_intra)
+        {
+            const int is_filter = dav1d_msac_decode_bool_adapt(&ts->msac,
+                                      ts->cdf.m.use_filter_intra[bs]);
+            if (is_filter) {
+                b->y_mode = FILTER_PRED;
+                b->y_angle = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                                 ts->cdf.m.filter_intra, 4);
+            }
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-filterintramode[%d/%d]: r=%d\n",
+                       b->y_mode, b->y_angle, ts->msac.rng);
+        }
+
+        if (b->pal_sz[0]) {
+            uint8_t *pal_idx;
+            if (t->frame_thread.pass) {
+                const int p = t->frame_thread.pass & 1;
+                assert(ts->frame_thread[p].pal_idx);
+                pal_idx = ts->frame_thread[p].pal_idx;
+                ts->frame_thread[p].pal_idx += bw4 * bh4 * 8;
+            } else
+                pal_idx = t->scratch.pal_idx_y;
+            read_pal_indices(t, pal_idx, b->pal_sz[0], 0, w4, h4, bw4, bh4);
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-y-pal-indices: r=%d\n", ts->msac.rng);
+        }
+
+        if (has_chroma && b->pal_sz[1]) {
+            uint8_t *pal_idx;
+            if (t->frame_thread.pass) {
+                const int p = t->frame_thread.pass & 1;
+                assert(ts->frame_thread[p].pal_idx);
+                pal_idx = ts->frame_thread[p].pal_idx;
+                ts->frame_thread[p].pal_idx += cbw4 * cbh4 * 8;
+            } else
+                pal_idx = t->scratch.pal_idx_uv;
+            read_pal_indices(t, pal_idx, b->pal_sz[1], 1, cw4, ch4, cbw4, cbh4);
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-uv-pal-indices: r=%d\n", ts->msac.rng);
+        }
+
+        const TxfmInfo *t_dim;
+        if (f->frame_hdr->segmentation.lossless[b->seg_id]) {
+            b->tx = b->uvtx = (int) TX_4X4;
+            t_dim = &dav1d_txfm_dimensions[TX_4X4];
+        } else {
+            b->tx = dav1d_max_txfm_size_for_bs[bs][0];
+            b->uvtx = dav1d_max_txfm_size_for_bs[bs][f->cur.p.layout];
+            t_dim = &dav1d_txfm_dimensions[b->tx];
+            if (f->frame_hdr->txfm_mode == DAV1D_TX_SWITCHABLE && t_dim->max > TX_4X4) {
+                const int tctx = get_tx_ctx(t->a, &t->l, t_dim, by4, bx4);
+                uint16_t *const tx_cdf = ts->cdf.m.txsz[t_dim->max - 1][tctx];
+                int depth = dav1d_msac_decode_symbol_adapt4(&ts->msac, tx_cdf,
+                                imin(t_dim->max, 2));
+
+                while (depth--) {
+                    b->tx = t_dim->sub;
+                    t_dim = &dav1d_txfm_dimensions[b->tx];
+                }
+            }
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-tx[%d]: r=%d\n", b->tx, ts->msac.rng);
+        }
+
+        // reconstruction
+        if (t->frame_thread.pass == 1) {
+            f->bd_fn.read_coef_blocks(t, bs, b);
+        } else {
+            f->bd_fn.recon_b_intra(t, bs, intra_edge_flags, b);
+        }
+
+        if (f->frame_hdr->loopfilter.level_y[0] ||
+            f->frame_hdr->loopfilter.level_y[1])
+        {
+            dav1d_create_lf_mask_intra(t->lf_mask, f->lf.level, f->b4_stride,
+                                       (const uint8_t (*)[8][2])
+                                       &ts->lflvl[b->seg_id][0][0][0],
+                                       t->bx, t->by, f->w4, f->h4, bs,
+                                       b->tx, b->uvtx, f->cur.p.layout,
+                                       &t->a->tx_lpf_y[bx4], &t->l.tx_lpf_y[by4],
+                                       has_chroma ? &t->a->tx_lpf_uv[cbx4] : NULL,
+                                       has_chroma ? &t->l.tx_lpf_uv[cby4] : NULL);
+        }
+        // update contexts
+        const enum IntraPredMode y_mode_nofilt =
+            b->y_mode == FILTER_PRED ? DC_PRED : b->y_mode;
+        BlockContext *edge = t->a;
+        for (int i = 0, off = bx4; i < 2; i++, off = by4, edge = &t->l) {
+            int t_lsz = ((uint8_t *) &t_dim->lw)[i]; // lw then lh
+#define set_ctx(rep_macro) \
+            rep_macro(edge->tx_intra, off, t_lsz); \
+            rep_macro(edge->tx, off, t_lsz); \
+            rep_macro(edge->mode, off, y_mode_nofilt); \
+            rep_macro(edge->pal_sz, off, b->pal_sz[0]); \
+            rep_macro(edge->seg_pred, off, seg_pred); \
+            rep_macro(edge->skip_mode, off, 0); \
+            rep_macro(edge->intra, off, 1); \
+            rep_macro(edge->skip, off, b->skip); \
+            /* see aomedia bug 2183 for why we use luma coordinates here */ \
+            rep_macro(t->pal_sz_uv[i], off, (has_chroma ? b->pal_sz[1] : 0)); \
+            if (IS_INTER_OR_SWITCH(f->frame_hdr)) { \
+                rep_macro(edge->comp_type, off, COMP_INTER_NONE); \
+                rep_macro(edge->ref[0], off, ((uint8_t) -1)); \
+                rep_macro(edge->ref[1], off, ((uint8_t) -1)); \
+                rep_macro(edge->filter[0], off, DAV1D_N_SWITCHABLE_FILTERS); \
+                rep_macro(edge->filter[1], off, DAV1D_N_SWITCHABLE_FILTERS); \
+            }
+            case_set(b_dim[2 + i]);
+#undef set_ctx
+        }
+        if (b->pal_sz[0])
+            f->bd_fn.copy_pal_block_y(t, bx4, by4, bw4, bh4);
+        if (has_chroma) {
+            uint8_t uv_mode = b->uv_mode;
+            dav1d_memset_pow2[ulog2(cbw4)](&t->a->uvmode[cbx4], uv_mode);
+            dav1d_memset_pow2[ulog2(cbh4)](&t->l.uvmode[cby4], uv_mode);
+            if (b->pal_sz[1])
+                f->bd_fn.copy_pal_block_uv(t, bx4, by4, bw4, bh4);
+        }
+        if (IS_INTER_OR_SWITCH(f->frame_hdr) || f->frame_hdr->allow_intrabc)
+            splat_intraref(f->c, t, bs, bw4, bh4);
+    } else if (IS_KEY_OR_INTRA(f->frame_hdr)) {
+        // intra block copy
+        refmvs_candidate mvstack[8];
+        int n_mvs, ctx;
+        dav1d_refmvs_find(&t->rt, mvstack, &n_mvs, &ctx,
+                          (union refmvs_refpair) { .ref = { 0, -1 }},
+                          bs, intra_edge_flags, t->by, t->bx);
+
+        if (mvstack[0].mv.mv[0].n)
+            b->mv[0] = mvstack[0].mv.mv[0];
+        else if (mvstack[1].mv.mv[0].n)
+            b->mv[0] = mvstack[1].mv.mv[0];
+        else {
+            if (t->by - (16 << f->seq_hdr->sb128) < ts->tiling.row_start) {
+                b->mv[0].y = 0;
+                b->mv[0].x = -(512 << f->seq_hdr->sb128) - 2048;
+            } else {
+                b->mv[0].y = -(512 << f->seq_hdr->sb128);
+                b->mv[0].x = 0;
+            }
+        }
+
+        const union mv ref = b->mv[0];
+        read_mv_residual(ts, &b->mv[0], -1);
+
+        // clip intrabc motion vector to decoded parts of current tile
+        int border_left = ts->tiling.col_start * 4;
+        int border_top  = ts->tiling.row_start * 4;
+        if (has_chroma) {
+            if (bw4 < 2 &&  ss_hor)
+                border_left += 4;
+            if (bh4 < 2 &&  ss_ver)
+                border_top  += 4;
+        }
+        int src_left   = t->bx * 4 + (b->mv[0].x >> 3);
+        int src_top    = t->by * 4 + (b->mv[0].y >> 3);
+        int src_right  = src_left + bw4 * 4;
+        int src_bottom = src_top  + bh4 * 4;
+        const int border_right = ((ts->tiling.col_end + (bw4 - 1)) & ~(bw4 - 1)) * 4;
+
+        // check against left or right tile boundary and adjust if necessary
+        if (src_left < border_left) {
+            src_right += border_left - src_left;
+            src_left  += border_left - src_left;
+        } else if (src_right > border_right) {
+            src_left  -= src_right - border_right;
+            src_right -= src_right - border_right;
+        }
+        // check against top tile boundary and adjust if necessary
+        if (src_top < border_top) {
+            src_bottom += border_top - src_top;
+            src_top    += border_top - src_top;
+        }
+
+        const int sbx = (t->bx >> (4 + f->seq_hdr->sb128)) << (6 + f->seq_hdr->sb128);
+        const int sby = (t->by >> (4 + f->seq_hdr->sb128)) << (6 + f->seq_hdr->sb128);
+        const int sb_size = 1 << (6 + f->seq_hdr->sb128);
+        // check for overlap with current superblock
+        if (src_bottom > sby && src_right > sbx) {
+            if (src_top - border_top >= src_bottom - sby) {
+                // if possible move src up into the previous suberblock row
+                src_top    -= src_bottom - sby;
+                src_bottom -= src_bottom - sby;
+            } else if (src_left - border_left >= src_right - sbx) {
+                // if possible move src left into the previous suberblock
+                src_left  -= src_right - sbx;
+                src_right -= src_right - sbx;
+            }
+        }
+        // move src up if it is below current superblock row
+        if (src_bottom > sby + sb_size) {
+            src_top    -= src_bottom - (sby + sb_size);
+            src_bottom -= src_bottom - (sby + sb_size);
+        }
+        // error out if mv still overlaps with the current superblock
+        if (src_bottom > sby && src_right > sbx)
+            return -1;
+
+        b->mv[0].x = (src_left - t->bx * 4) * 8;
+        b->mv[0].y = (src_top  - t->by * 4) * 8;
+
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-dmv[%d/%d,ref=%d/%d|%d/%d]: r=%d\n",
+                   b->mv[0].y, b->mv[0].x, ref.y, ref.x,
+                   mvstack[0].mv.mv[0].y, mvstack[0].mv.mv[0].x, ts->msac.rng);
+        read_vartx_tree(t, b, bs, bx4, by4);
+
+        // reconstruction
+        if (t->frame_thread.pass == 1) {
+            f->bd_fn.read_coef_blocks(t, bs, b);
+            b->filter2d = FILTER_2D_BILINEAR;
+        } else {
+            if (f->bd_fn.recon_b_inter(t, bs, b)) return -1;
+        }
+
+        splat_intrabc_mv(f->c, t, bs, b, bw4, bh4);
+        BlockContext *edge = t->a;
+        for (int i = 0, off = bx4; i < 2; i++, off = by4, edge = &t->l) {
+#define set_ctx(rep_macro) \
+            rep_macro(edge->tx_intra, off, b_dim[2 + i]); \
+            rep_macro(edge->mode, off, DC_PRED); \
+            rep_macro(edge->pal_sz, off, 0); \
+            /* see aomedia bug 2183 for why this is outside if (has_chroma) */ \
+            rep_macro(t->pal_sz_uv[i], off, 0); \
+            rep_macro(edge->seg_pred, off, seg_pred); \
+            rep_macro(edge->skip_mode, off, 0); \
+            rep_macro(edge->intra, off, 0); \
+            rep_macro(edge->skip, off, b->skip)
+            case_set(b_dim[2 + i]);
+#undef set_ctx
+        }
+        if (has_chroma) {
+            dav1d_memset_pow2[ulog2(cbw4)](&t->a->uvmode[cbx4], DC_PRED);
+            dav1d_memset_pow2[ulog2(cbh4)](&t->l.uvmode[cby4], DC_PRED);
+        }
+    } else {
+        // inter-specific mode/mv coding
+        int is_comp, has_subpel_filter;
+
+        if (b->skip_mode) {
+            is_comp = 1;
+        } else if ((!seg || (seg->ref == -1 && !seg->globalmv && !seg->skip)) &&
+                   f->frame_hdr->switchable_comp_refs && imin(bw4, bh4) > 1)
+        {
+            const int ctx = get_comp_ctx(t->a, &t->l, by4, bx4,
+                                         have_top, have_left);
+            is_comp = dav1d_msac_decode_bool_adapt(&ts->msac,
+                          ts->cdf.m.comp[ctx]);
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-compflag[%d]: r=%d\n", is_comp, ts->msac.rng);
+        } else {
+            is_comp = 0;
+        }
+
+        if (b->skip_mode) {
+            b->ref[0] = f->frame_hdr->skip_mode_refs[0];
+            b->ref[1] = f->frame_hdr->skip_mode_refs[1];
+            b->comp_type = COMP_INTER_AVG;
+            b->inter_mode = NEARESTMV_NEARESTMV;
+            b->drl_idx = NEAREST_DRL;
+            has_subpel_filter = 0;
+
+            refmvs_candidate mvstack[8];
+            int n_mvs, ctx;
+            dav1d_refmvs_find(&t->rt, mvstack, &n_mvs, &ctx,
+                              (union refmvs_refpair) { .ref = {
+                                    b->ref[0] + 1, b->ref[1] + 1 }},
+                              bs, intra_edge_flags, t->by, t->bx);
+
+            b->mv[0] = mvstack[0].mv.mv[0];
+            b->mv[1] = mvstack[0].mv.mv[1];
+            fix_mv_precision(f->frame_hdr, &b->mv[0]);
+            fix_mv_precision(f->frame_hdr, &b->mv[1]);
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-skipmodeblock[mv=1:y=%d,x=%d,2:y=%d,x=%d,refs=%d+%d\n",
+                       b->mv[0].y, b->mv[0].x, b->mv[1].y, b->mv[1].x,
+                       b->ref[0], b->ref[1]);
+        } else if (is_comp) {
+            const int dir_ctx = get_comp_dir_ctx(t->a, &t->l, by4, bx4,
+                                                 have_top, have_left);
+            if (dav1d_msac_decode_bool_adapt(&ts->msac,
+                    ts->cdf.m.comp_dir[dir_ctx]))
+            {
+                // bidir - first reference (fw)
+                const int ctx1 = av1_get_fwd_ref_ctx(t->a, &t->l, by4, bx4,
+                                                     have_top, have_left);
+                if (dav1d_msac_decode_bool_adapt(&ts->msac,
+                        ts->cdf.m.comp_fwd_ref[0][ctx1]))
+                {
+                    const int ctx2 = av1_get_fwd_ref_2_ctx(t->a, &t->l, by4, bx4,
+                                                           have_top, have_left);
+                    b->ref[0] = 2 + dav1d_msac_decode_bool_adapt(&ts->msac,
+                                        ts->cdf.m.comp_fwd_ref[2][ctx2]);
+                } else {
+                    const int ctx2 = av1_get_fwd_ref_1_ctx(t->a, &t->l, by4, bx4,
+                                                           have_top, have_left);
+                    b->ref[0] = dav1d_msac_decode_bool_adapt(&ts->msac,
+                                    ts->cdf.m.comp_fwd_ref[1][ctx2]);
+                }
+
+                // second reference (bw)
+                const int ctx3 = av1_get_bwd_ref_ctx(t->a, &t->l, by4, bx4,
+                                                     have_top, have_left);
+                if (dav1d_msac_decode_bool_adapt(&ts->msac,
+                        ts->cdf.m.comp_bwd_ref[0][ctx3]))
+                {
+                    b->ref[1] = 6;
+                } else {
+                    const int ctx4 = av1_get_bwd_ref_1_ctx(t->a, &t->l, by4, bx4,
+                                                           have_top, have_left);
+                    b->ref[1] = 4 + dav1d_msac_decode_bool_adapt(&ts->msac,
+                                        ts->cdf.m.comp_bwd_ref[1][ctx4]);
+                }
+            } else {
+                // unidir
+                const int uctx_p = av1_get_uni_p_ctx(t->a, &t->l, by4, bx4,
+                                                     have_top, have_left);
+                if (dav1d_msac_decode_bool_adapt(&ts->msac,
+                        ts->cdf.m.comp_uni_ref[0][uctx_p]))
+                {
+                    b->ref[0] = 4;
+                    b->ref[1] = 6;
+                } else {
+                    const int uctx_p1 = av1_get_uni_p1_ctx(t->a, &t->l, by4, bx4,
+                                                           have_top, have_left);
+                    b->ref[0] = 0;
+                    b->ref[1] = 1 + dav1d_msac_decode_bool_adapt(&ts->msac,
+                                        ts->cdf.m.comp_uni_ref[1][uctx_p1]);
+                    if (b->ref[1] == 2) {
+                        const int uctx_p2 = av1_get_uni_p2_ctx(t->a, &t->l, by4, bx4,
+                                                               have_top, have_left);
+                        b->ref[1] += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                         ts->cdf.m.comp_uni_ref[2][uctx_p2]);
+                    }
+                }
+            }
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-refs[%d/%d]: r=%d\n",
+                       b->ref[0], b->ref[1], ts->msac.rng);
+
+            refmvs_candidate mvstack[8];
+            int n_mvs, ctx;
+            dav1d_refmvs_find(&t->rt, mvstack, &n_mvs, &ctx,
+                              (union refmvs_refpair) { .ref = {
+                                    b->ref[0] + 1, b->ref[1] + 1 }},
+                              bs, intra_edge_flags, t->by, t->bx);
+
+            b->inter_mode = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                                ts->cdf.m.comp_inter_mode[ctx],
+                                N_COMP_INTER_PRED_MODES - 1);
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-compintermode[%d,ctx=%d,n_mvs=%d]: r=%d\n",
+                       b->inter_mode, ctx, n_mvs, ts->msac.rng);
+
+            const uint8_t *const im = dav1d_comp_inter_pred_modes[b->inter_mode];
+            b->drl_idx = NEAREST_DRL;
+            if (b->inter_mode == NEWMV_NEWMV) {
+                if (n_mvs > 1) { // NEARER, NEAR or NEARISH
+                    const int drl_ctx_v1 = get_drl_context(mvstack, 0);
+                    b->drl_idx += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                      ts->cdf.m.drl_bit[drl_ctx_v1]);
+                    if (b->drl_idx == NEARER_DRL && n_mvs > 2) {
+                        const int drl_ctx_v2 = get_drl_context(mvstack, 1);
+                        b->drl_idx += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                          ts->cdf.m.drl_bit[drl_ctx_v2]);
+                    }
+                    if (DEBUG_BLOCK_INFO)
+                        printf("Post-drlidx[%d,n_mvs=%d]: r=%d\n",
+                               b->drl_idx, n_mvs, ts->msac.rng);
+                }
+            } else if (im[0] == NEARMV || im[1] == NEARMV) {
+                b->drl_idx = NEARER_DRL;
+                if (n_mvs > 2) { // NEAR or NEARISH
+                    const int drl_ctx_v2 = get_drl_context(mvstack, 1);
+                    b->drl_idx += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                      ts->cdf.m.drl_bit[drl_ctx_v2]);
+                    if (b->drl_idx == NEAR_DRL && n_mvs > 3) {
+                        const int drl_ctx_v3 = get_drl_context(mvstack, 2);
+                        b->drl_idx += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                          ts->cdf.m.drl_bit[drl_ctx_v3]);
+                    }
+                    if (DEBUG_BLOCK_INFO)
+                        printf("Post-drlidx[%d,n_mvs=%d]: r=%d\n",
+                               b->drl_idx, n_mvs, ts->msac.rng);
+                }
+            }
+            assert(b->drl_idx >= NEAREST_DRL && b->drl_idx <= NEARISH_DRL);
+
+#define assign_comp_mv(idx) \
+            switch (im[idx]) { \
+            case NEARMV: \
+            case NEARESTMV: \
+                b->mv[idx] = mvstack[b->drl_idx].mv.mv[idx]; \
+                fix_mv_precision(f->frame_hdr, &b->mv[idx]); \
+                break; \
+            case GLOBALMV: \
+                has_subpel_filter |= \
+                    f->frame_hdr->gmv[b->ref[idx]].type == DAV1D_WM_TYPE_TRANSLATION; \
+                b->mv[idx] = get_gmv_2d(&f->frame_hdr->gmv[b->ref[idx]], \
+                                        t->bx, t->by, bw4, bh4, f->frame_hdr); \
+                break; \
+            case NEWMV: \
+                b->mv[idx] = mvstack[b->drl_idx].mv.mv[idx]; \
+                const int mv_prec = f->frame_hdr->hp - f->frame_hdr->force_integer_mv; \
+                read_mv_residual(ts, &b->mv[idx], mv_prec); \
+                break; \
+            }
+            has_subpel_filter = imin(bw4, bh4) == 1 ||
+                                b->inter_mode != GLOBALMV_GLOBALMV;
+            assign_comp_mv(0);
+            assign_comp_mv(1);
+#undef assign_comp_mv
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-residual_mv[1:y=%d,x=%d,2:y=%d,x=%d]: r=%d\n",
+                       b->mv[0].y, b->mv[0].x, b->mv[1].y, b->mv[1].x,
+                       ts->msac.rng);
+
+            // jnt_comp vs. seg vs. wedge
+            int is_segwedge = 0;
+            if (f->seq_hdr->masked_compound) {
+                const int mask_ctx = get_mask_comp_ctx(t->a, &t->l, by4, bx4);
+
+                is_segwedge = dav1d_msac_decode_bool_adapt(&ts->msac,
+                                  ts->cdf.m.mask_comp[mask_ctx]);
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-segwedge_vs_jntavg[%d,ctx=%d]: r=%d\n",
+                           is_segwedge, mask_ctx, ts->msac.rng);
+            }
+
+            if (!is_segwedge) {
+                if (f->seq_hdr->jnt_comp) {
+                    const int jnt_ctx =
+                        get_jnt_comp_ctx(f->seq_hdr->order_hint_n_bits,
+                                         f->cur.frame_hdr->frame_offset,
+                                         f->refp[b->ref[0]].p.frame_hdr->frame_offset,
+                                         f->refp[b->ref[1]].p.frame_hdr->frame_offset,
+                                         t->a, &t->l, by4, bx4);
+                    b->comp_type = COMP_INTER_WEIGHTED_AVG +
+                                   dav1d_msac_decode_bool_adapt(&ts->msac,
+                                       ts->cdf.m.jnt_comp[jnt_ctx]);
+                    if (DEBUG_BLOCK_INFO)
+                        printf("Post-jnt_comp[%d,ctx=%d[ac:%d,ar:%d,lc:%d,lr:%d]]: r=%d\n",
+                               b->comp_type == COMP_INTER_AVG,
+                               jnt_ctx, t->a->comp_type[bx4], t->a->ref[0][bx4],
+                               t->l.comp_type[by4], t->l.ref[0][by4],
+                               ts->msac.rng);
+                } else {
+                    b->comp_type = COMP_INTER_AVG;
+                }
+            } else {
+                if (wedge_allowed_mask & (1 << bs)) {
+                    const int ctx = dav1d_wedge_ctx_lut[bs];
+                    b->comp_type = COMP_INTER_WEDGE -
+                                   dav1d_msac_decode_bool_adapt(&ts->msac,
+                                       ts->cdf.m.wedge_comp[ctx]);
+                    if (b->comp_type == COMP_INTER_WEDGE)
+                        b->wedge_idx = dav1d_msac_decode_symbol_adapt16(&ts->msac,
+                                           ts->cdf.m.wedge_idx[ctx], 15);
+                } else {
+                    b->comp_type = COMP_INTER_SEG;
+                }
+                b->mask_sign = dav1d_msac_decode_bool_equi(&ts->msac);
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-seg/wedge[%d,wedge_idx=%d,sign=%d]: r=%d\n",
+                           b->comp_type == COMP_INTER_WEDGE,
+                           b->wedge_idx, b->mask_sign, ts->msac.rng);
+            }
+        } else {
+            b->comp_type = COMP_INTER_NONE;
+
+            // ref
+            if (seg && seg->ref > 0) {
+                b->ref[0] = seg->ref - 1;
+            } else if (seg && (seg->globalmv || seg->skip)) {
+                b->ref[0] = 0;
+            } else {
+                const int ctx1 = av1_get_ref_ctx(t->a, &t->l, by4, bx4,
+                                                 have_top, have_left);
+                if (dav1d_msac_decode_bool_adapt(&ts->msac,
+                                                 ts->cdf.m.ref[0][ctx1]))
+                {
+                    const int ctx2 = av1_get_ref_2_ctx(t->a, &t->l, by4, bx4,
+                                                       have_top, have_left);
+                    if (dav1d_msac_decode_bool_adapt(&ts->msac,
+                                                     ts->cdf.m.ref[1][ctx2]))
+                    {
+                        b->ref[0] = 6;
+                    } else {
+                        const int ctx3 = av1_get_ref_6_ctx(t->a, &t->l, by4, bx4,
+                                                           have_top, have_left);
+                        b->ref[0] = 4 + dav1d_msac_decode_bool_adapt(&ts->msac,
+                                            ts->cdf.m.ref[5][ctx3]);
+                    }
+                } else {
+                    const int ctx2 = av1_get_ref_3_ctx(t->a, &t->l, by4, bx4,
+                                                       have_top, have_left);
+                    if (dav1d_msac_decode_bool_adapt(&ts->msac,
+                                                     ts->cdf.m.ref[2][ctx2]))
+                    {
+                        const int ctx3 = av1_get_ref_5_ctx(t->a, &t->l, by4, bx4,
+                                                           have_top, have_left);
+                        b->ref[0] = 2 + dav1d_msac_decode_bool_adapt(&ts->msac,
+                                            ts->cdf.m.ref[4][ctx3]);
+                    } else {
+                        const int ctx3 = av1_get_ref_4_ctx(t->a, &t->l, by4, bx4,
+                                                           have_top, have_left);
+                        b->ref[0] = dav1d_msac_decode_bool_adapt(&ts->msac,
+                                        ts->cdf.m.ref[3][ctx3]);
+                    }
+                }
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-ref[%d]: r=%d\n", b->ref[0], ts->msac.rng);
+            }
+            b->ref[1] = -1;
+
+            refmvs_candidate mvstack[8];
+            int n_mvs, ctx;
+            dav1d_refmvs_find(&t->rt, mvstack, &n_mvs, &ctx,
+                              (union refmvs_refpair) { .ref = { b->ref[0] + 1, -1 }},
+                              bs, intra_edge_flags, t->by, t->bx);
+
+            // mode parsing and mv derivation from ref_mvs
+            if ((seg && (seg->skip || seg->globalmv)) ||
+                dav1d_msac_decode_bool_adapt(&ts->msac,
+                                             ts->cdf.m.newmv_mode[ctx & 7]))
+            {
+                if ((seg && (seg->skip || seg->globalmv)) ||
+                    !dav1d_msac_decode_bool_adapt(&ts->msac,
+                         ts->cdf.m.globalmv_mode[(ctx >> 3) & 1]))
+                {
+                    b->inter_mode = GLOBALMV;
+                    b->mv[0] = get_gmv_2d(&f->frame_hdr->gmv[b->ref[0]],
+                                          t->bx, t->by, bw4, bh4, f->frame_hdr);
+                    has_subpel_filter = imin(bw4, bh4) == 1 ||
+                        f->frame_hdr->gmv[b->ref[0]].type == DAV1D_WM_TYPE_TRANSLATION;
+                } else {
+                    has_subpel_filter = 1;
+                    if (dav1d_msac_decode_bool_adapt(&ts->msac,
+                            ts->cdf.m.refmv_mode[(ctx >> 4) & 15]))
+                    { // NEAREST, NEARER, NEAR or NEARISH
+                        b->inter_mode = NEARMV;
+                        b->drl_idx = NEARER_DRL;
+                        if (n_mvs > 2) { // NEARER, NEAR or NEARISH
+                            const int drl_ctx_v2 = get_drl_context(mvstack, 1);
+                            b->drl_idx += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                              ts->cdf.m.drl_bit[drl_ctx_v2]);
+                            if (b->drl_idx == NEAR_DRL && n_mvs > 3) { // NEAR or NEARISH
+                                const int drl_ctx_v3 =
+                                    get_drl_context(mvstack, 2);
+                                b->drl_idx += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                                  ts->cdf.m.drl_bit[drl_ctx_v3]);
+                            }
+                        }
+                    } else {
+                        b->inter_mode = NEARESTMV;
+                        b->drl_idx = NEAREST_DRL;
+                    }
+                    assert(b->drl_idx >= NEAREST_DRL && b->drl_idx <= NEARISH_DRL);
+                    b->mv[0] = mvstack[b->drl_idx].mv.mv[0];
+                    if (b->drl_idx < NEAR_DRL)
+                        fix_mv_precision(f->frame_hdr, &b->mv[0]);
+                }
+
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-intermode[%d,drl=%d,mv=y:%d,x:%d,n_mvs=%d]: r=%d\n",
+                           b->inter_mode, b->drl_idx, b->mv[0].y, b->mv[0].x, n_mvs,
+                           ts->msac.rng);
+            } else {
+                has_subpel_filter = 1;
+                b->inter_mode = NEWMV;
+                b->drl_idx = NEAREST_DRL;
+                if (n_mvs > 1) { // NEARER, NEAR or NEARISH
+                    const int drl_ctx_v1 = get_drl_context(mvstack, 0);
+                    b->drl_idx += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                      ts->cdf.m.drl_bit[drl_ctx_v1]);
+                    if (b->drl_idx == NEARER_DRL && n_mvs > 2) { // NEAR or NEARISH
+                        const int drl_ctx_v2 = get_drl_context(mvstack, 1);
+                        b->drl_idx += dav1d_msac_decode_bool_adapt(&ts->msac,
+                                          ts->cdf.m.drl_bit[drl_ctx_v2]);
+                    }
+                }
+                assert(b->drl_idx >= NEAREST_DRL && b->drl_idx <= NEARISH_DRL);
+                if (n_mvs > 1) {
+                    b->mv[0] = mvstack[b->drl_idx].mv.mv[0];
+                } else {
+                    assert(!b->drl_idx);
+                    b->mv[0] = mvstack[0].mv.mv[0];
+                    fix_mv_precision(f->frame_hdr, &b->mv[0]);
+                }
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-intermode[%d,drl=%d]: r=%d\n",
+                           b->inter_mode, b->drl_idx, ts->msac.rng);
+                const int mv_prec = f->frame_hdr->hp - f->frame_hdr->force_integer_mv;
+                read_mv_residual(ts, &b->mv[0], mv_prec);
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-residualmv[mv=y:%d,x:%d]: r=%d\n",
+                           b->mv[0].y, b->mv[0].x, ts->msac.rng);
+            }
+
+            // interintra flags
+            const int ii_sz_grp = dav1d_ymode_size_context[bs];
+            if (f->seq_hdr->inter_intra &&
+                interintra_allowed_mask & (1 << bs) &&
+                dav1d_msac_decode_bool_adapt(&ts->msac,
+                                             ts->cdf.m.interintra[ii_sz_grp]))
+            {
+                b->interintra_mode = dav1d_msac_decode_symbol_adapt4(&ts->msac,
+                                         ts->cdf.m.interintra_mode[ii_sz_grp],
+                                         N_INTER_INTRA_PRED_MODES - 1);
+                const int wedge_ctx = dav1d_wedge_ctx_lut[bs];
+                b->interintra_type = INTER_INTRA_BLEND +
+                                     dav1d_msac_decode_bool_adapt(&ts->msac,
+                                         ts->cdf.m.interintra_wedge[wedge_ctx]);
+                if (b->interintra_type == INTER_INTRA_WEDGE)
+                    b->wedge_idx = dav1d_msac_decode_symbol_adapt16(&ts->msac,
+                                       ts->cdf.m.wedge_idx[wedge_ctx], 15);
+            } else {
+                b->interintra_type = INTER_INTRA_NONE;
+            }
+            if (DEBUG_BLOCK_INFO && f->seq_hdr->inter_intra &&
+                interintra_allowed_mask & (1 << bs))
+            {
+                printf("Post-interintra[t=%d,m=%d,w=%d]: r=%d\n",
+                       b->interintra_type, b->interintra_mode,
+                       b->wedge_idx, ts->msac.rng);
+            }
+
+            // motion variation
+            if (f->frame_hdr->switchable_motion_mode &&
+                b->interintra_type == INTER_INTRA_NONE && imin(bw4, bh4) >= 2 &&
+                // is not warped global motion
+                !(!f->frame_hdr->force_integer_mv && b->inter_mode == GLOBALMV &&
+                  f->frame_hdr->gmv[b->ref[0]].type > DAV1D_WM_TYPE_TRANSLATION) &&
+                // has overlappable neighbours
+                ((have_left && findoddzero(&t->l.intra[by4 + 1], h4 >> 1)) ||
+                 (have_top && findoddzero(&t->a->intra[bx4 + 1], w4 >> 1))))
+            {
+                // reaching here means the block allows obmc - check warp by
+                // finding matching-ref blocks in top/left edges
+                uint64_t mask[2] = { 0, 0 };
+                find_matching_ref(t, intra_edge_flags, bw4, bh4, w4, h4,
+                                  have_left, have_top, b->ref[0], mask);
+                const int allow_warp = !f->svc[b->ref[0]][0].scale &&
+                    !f->frame_hdr->force_integer_mv &&
+                    f->frame_hdr->warp_motion && (mask[0] | mask[1]);
+
+                b->motion_mode = allow_warp ?
+                    dav1d_msac_decode_symbol_adapt4(&ts->msac,
+                        ts->cdf.m.motion_mode[bs], 2) :
+                    dav1d_msac_decode_bool_adapt(&ts->msac, ts->cdf.m.obmc[bs]);
+                if (b->motion_mode == MM_WARP) {
+                    has_subpel_filter = 0;
+                    derive_warpmv(t, bw4, bh4, mask, b->mv[0], &t->warpmv);
+#define signabs(v) v < 0 ? '-' : ' ', abs(v)
+                    if (DEBUG_BLOCK_INFO)
+                        printf("[ %c%x %c%x %c%x\n  %c%x %c%x %c%x ]\n"
+                               "alpha=%c%x, beta=%c%x, gamma=%c%x, delta=%c%x, "
+                               "mv=y:%d,x:%d\n",
+                               signabs(t->warpmv.matrix[0]),
+                               signabs(t->warpmv.matrix[1]),
+                               signabs(t->warpmv.matrix[2]),
+                               signabs(t->warpmv.matrix[3]),
+                               signabs(t->warpmv.matrix[4]),
+                               signabs(t->warpmv.matrix[5]),
+                               signabs(t->warpmv.u.p.alpha),
+                               signabs(t->warpmv.u.p.beta),
+                               signabs(t->warpmv.u.p.gamma),
+                               signabs(t->warpmv.u.p.delta),
+                               b->mv[0].y, b->mv[0].x);
+#undef signabs
+                    if (t->frame_thread.pass) {
+                        if (t->warpmv.type == DAV1D_WM_TYPE_AFFINE) {
+                            b->matrix[0] = t->warpmv.matrix[2] - 0x10000;
+                            b->matrix[1] = t->warpmv.matrix[3];
+                            b->matrix[2] = t->warpmv.matrix[4];
+                            b->matrix[3] = t->warpmv.matrix[5] - 0x10000;
+                        } else {
+                            b->matrix[0] = INT16_MIN;
+                        }
+                    }
+                }
+
+                if (DEBUG_BLOCK_INFO)
+                    printf("Post-motionmode[%d]: r=%d [mask: 0x%" PRIx64 "/0x%"
+                           PRIx64 "]\n", b->motion_mode, ts->msac.rng, mask[0],
+                            mask[1]);
+            } else {
+                b->motion_mode = MM_TRANSLATION;
+            }
+        }
+
+        // subpel filter
+        enum Dav1dFilterMode filter[2];
+        if (f->frame_hdr->subpel_filter_mode == DAV1D_FILTER_SWITCHABLE) {
+            if (has_subpel_filter) {
+                const int comp = b->comp_type != COMP_INTER_NONE;
+                const int ctx1 = get_filter_ctx(t->a, &t->l, comp, 0, b->ref[0],
+                                                by4, bx4);
+                filter[0] = dav1d_msac_decode_symbol_adapt4(&ts->msac,
+                               ts->cdf.m.filter[0][ctx1],
+                               DAV1D_N_SWITCHABLE_FILTERS - 1);
+                if (f->seq_hdr->dual_filter) {
+                    const int ctx2 = get_filter_ctx(t->a, &t->l, comp, 1,
+                                                    b->ref[0], by4, bx4);
+                    if (DEBUG_BLOCK_INFO)
+                        printf("Post-subpel_filter1[%d,ctx=%d]: r=%d\n",
+                               filter[0], ctx1, ts->msac.rng);
+                    filter[1] = dav1d_msac_decode_symbol_adapt4(&ts->msac,
+                                    ts->cdf.m.filter[1][ctx2],
+                                    DAV1D_N_SWITCHABLE_FILTERS - 1);
+                    if (DEBUG_BLOCK_INFO)
+                        printf("Post-subpel_filter2[%d,ctx=%d]: r=%d\n",
+                               filter[1], ctx2, ts->msac.rng);
+                } else {
+                    filter[1] = filter[0];
+                    if (DEBUG_BLOCK_INFO)
+                        printf("Post-subpel_filter[%d,ctx=%d]: r=%d\n",
+                               filter[0], ctx1, ts->msac.rng);
+                }
+            } else {
+                filter[0] = filter[1] = DAV1D_FILTER_8TAP_REGULAR;
+            }
+        } else {
+            filter[0] = filter[1] = f->frame_hdr->subpel_filter_mode;
+        }
+        b->filter2d = dav1d_filter_2d[filter[1]][filter[0]];
+
+        read_vartx_tree(t, b, bs, bx4, by4);
+
+        // reconstruction
+        if (t->frame_thread.pass == 1) {
+            f->bd_fn.read_coef_blocks(t, bs, b);
+        } else {
+            if (f->bd_fn.recon_b_inter(t, bs, b)) return -1;
+        }
+
+        if (f->frame_hdr->loopfilter.level_y[0] ||
+            f->frame_hdr->loopfilter.level_y[1])
+        {
+            const int is_globalmv =
+                b->inter_mode == (is_comp ? GLOBALMV_GLOBALMV : GLOBALMV);
+            const uint8_t (*const lf_lvls)[8][2] = (const uint8_t (*)[8][2])
+                &ts->lflvl[b->seg_id][0][b->ref[0] + 1][!is_globalmv];
+            const uint16_t tx_split[2] = { b->tx_split0, b->tx_split1 };
+            enum RectTxfmSize ytx = b->max_ytx, uvtx = b->uvtx;
+            if (f->frame_hdr->segmentation.lossless[b->seg_id]) {
+                ytx  = (enum RectTxfmSize) TX_4X4;
+                uvtx = (enum RectTxfmSize) TX_4X4;
+            }
+            dav1d_create_lf_mask_inter(t->lf_mask, f->lf.level, f->b4_stride, lf_lvls,
+                                       t->bx, t->by, f->w4, f->h4, b->skip, bs,
+                                       ytx, tx_split, uvtx, f->cur.p.layout,
+                                       &t->a->tx_lpf_y[bx4], &t->l.tx_lpf_y[by4],
+                                       has_chroma ? &t->a->tx_lpf_uv[cbx4] : NULL,
+                                       has_chroma ? &t->l.tx_lpf_uv[cby4] : NULL);
+        }
+
+        // context updates
+        if (is_comp)
+            splat_tworef_mv(f->c, t, bs, b, bw4, bh4);
+        else
+            splat_oneref_mv(f->c, t, bs, b, bw4, bh4);
+        BlockContext *edge = t->a;
+        for (int i = 0, off = bx4; i < 2; i++, off = by4, edge = &t->l) {
+#define set_ctx(rep_macro) \
+            rep_macro(edge->seg_pred, off, seg_pred); \
+            rep_macro(edge->skip_mode, off, b->skip_mode); \
+            rep_macro(edge->intra, off, 0); \
+            rep_macro(edge->skip, off, b->skip); \
+            rep_macro(edge->pal_sz, off, 0); \
+            /* see aomedia bug 2183 for why this is outside if (has_chroma) */ \
+            rep_macro(t->pal_sz_uv[i], off, 0); \
+            rep_macro(edge->tx_intra, off, b_dim[2 + i]); \
+            rep_macro(edge->comp_type, off, b->comp_type); \
+            rep_macro(edge->filter[0], off, filter[0]); \
+            rep_macro(edge->filter[1], off, filter[1]); \
+            rep_macro(edge->mode, off, b->inter_mode); \
+            rep_macro(edge->ref[0], off, b->ref[0]); \
+            rep_macro(edge->ref[1], off, ((uint8_t) b->ref[1]))
+            case_set(b_dim[2 + i]);
+#undef set_ctx
+        }
+        if (has_chroma) {
+            dav1d_memset_pow2[ulog2(cbw4)](&t->a->uvmode[cbx4], DC_PRED);
+            dav1d_memset_pow2[ulog2(cbh4)](&t->l.uvmode[cby4], DC_PRED);
+        }
+    }
+
+    // update contexts
+    if (f->frame_hdr->segmentation.enabled &&
+        f->frame_hdr->segmentation.update_map)
+    {
+        uint8_t *seg_ptr = &f->cur_segmap[t->by * f->b4_stride + t->bx];
+#define set_ctx(rep_macro) \
+        for (int y = 0; y < bh4; y++) { \
+            rep_macro(seg_ptr, 0, b->seg_id); \
+            seg_ptr += f->b4_stride; \
+        }
+        case_set(b_dim[2]);
+#undef set_ctx
+    }
+    if (!b->skip) {
+        uint16_t (*noskip_mask)[2] = &t->lf_mask->noskip_mask[by4 >> 1];
+        const unsigned mask = (~0U >> (32 - bw4)) << (bx4 & 15);
+        const int bx_idx = (bx4 & 16) >> 4;
+        for (int y = 0; y < bh4; y += 2, noskip_mask++) {
+            (*noskip_mask)[bx_idx] |= mask;
+            if (bw4 == 32) // this should be mask >> 16, but it's 0xffffffff anyway
+                (*noskip_mask)[1] |= mask;
+        }
+    }
+
+    if (t->frame_thread.pass == 1 && !b->intra && IS_INTER_OR_SWITCH(f->frame_hdr)) {
+        const int sby = (t->by - ts->tiling.row_start) >> f->sb_shift;
+        int (*const lowest_px)[2] = ts->lowest_pixel[sby];
+
+        // keep track of motion vectors for each reference
+        if (b->comp_type == COMP_INTER_NONE) {
+            // y
+            if (imin(bw4, bh4) > 1 &&
+                ((b->inter_mode == GLOBALMV && f->gmv_warp_allowed[b->ref[0]]) ||
+                 (b->motion_mode == MM_WARP && t->warpmv.type > DAV1D_WM_TYPE_TRANSLATION)))
+            {
+                affine_lowest_px_luma(t, &lowest_px[b->ref[0]][0], b_dim,
+                                      b->motion_mode == MM_WARP ? &t->warpmv :
+                                      &f->frame_hdr->gmv[b->ref[0]]);
+            } else {
+                mc_lowest_px(&lowest_px[b->ref[0]][0], t->by, bh4, b->mv[0].y,
+                             0, &f->svc[b->ref[0]][1]);
+                if (b->motion_mode == MM_OBMC) {
+                    obmc_lowest_px(t, lowest_px, 0, b_dim, bx4, by4, w4, h4);
+                }
+            }
+
+            // uv
+            if (has_chroma) {
+                // sub8x8 derivation
+                int is_sub8x8 = bw4 == ss_hor || bh4 == ss_ver;
+                refmvs_block *const *r;
+                if (is_sub8x8) {
+                    assert(ss_hor == 1);
+                    r = &t->rt.r[(t->by & 31) + 5];
+                    if (bw4 == 1) is_sub8x8 &= r[0][t->bx - 1].ref.ref[0] > 0;
+                    if (bh4 == ss_ver) is_sub8x8 &= r[-1][t->bx].ref.ref[0] > 0;
+                    if (bw4 == 1 && bh4 == ss_ver)
+                        is_sub8x8 &= r[-1][t->bx - 1].ref.ref[0] > 0;
+                }
+
+                // chroma prediction
+                if (is_sub8x8) {
+                    assert(ss_hor == 1);
+                    if (bw4 == 1 && bh4 == ss_ver) {
+                        const refmvs_block *const rr = &r[-1][t->bx - 1];
+                        mc_lowest_px(&lowest_px[rr->ref.ref[0] - 1][1],
+                                     t->by - 1, bh4, rr->mv.mv[0].y, ss_ver,
+                                     &f->svc[rr->ref.ref[0] - 1][1]);
+                    }
+                    if (bw4 == 1) {
+                        const refmvs_block *const rr = &r[0][t->bx - 1];
+                        mc_lowest_px(&lowest_px[rr->ref.ref[0] - 1][1],
+                                     t->by, bh4, rr->mv.mv[0].y, ss_ver,
+                                     &f->svc[rr->ref.ref[0] - 1][1]);
+                    }
+                    if (bh4 == ss_ver) {
+                        const refmvs_block *const rr = &r[-1][t->bx];
+                        mc_lowest_px(&lowest_px[rr->ref.ref[0] - 1][1],
+                                     t->by - 1, bh4, rr->mv.mv[0].y, ss_ver,
+                                     &f->svc[rr->ref.ref[0] - 1][1]);
+                    }
+                    mc_lowest_px(&lowest_px[b->ref[0]][1], t->by, bh4,
+                                 b->mv[0].y, ss_ver, &f->svc[b->ref[0]][1]);
+                } else {
+                    if (imin(cbw4, cbh4) > 1 &&
+                        ((b->inter_mode == GLOBALMV && f->gmv_warp_allowed[b->ref[0]]) ||
+                         (b->motion_mode == MM_WARP && t->warpmv.type > DAV1D_WM_TYPE_TRANSLATION)))
+                    {
+                        affine_lowest_px_chroma(t, &lowest_px[b->ref[0]][1], b_dim,
+                                                b->motion_mode == MM_WARP ? &t->warpmv :
+                                                &f->frame_hdr->gmv[b->ref[0]]);
+                    } else {
+                        mc_lowest_px(&lowest_px[b->ref[0]][1],
+                                     t->by & ~ss_ver, bh4 << (bh4 == ss_ver),
+                                     b->mv[0].y, ss_ver, &f->svc[b->ref[0]][1]);
+                        if (b->motion_mode == MM_OBMC) {
+                            obmc_lowest_px(t, lowest_px, 1, b_dim, bx4, by4, w4, h4);
+                        }
+                    }
+                }
+            }
+        } else {
+            // y
+            for (int i = 0; i < 2; i++) {
+                if (b->inter_mode == GLOBALMV_GLOBALMV && f->gmv_warp_allowed[b->ref[i]]) {
+                    affine_lowest_px_luma(t, &lowest_px[b->ref[i]][0], b_dim,
+                                          &f->frame_hdr->gmv[b->ref[i]]);
+                } else {
+                    mc_lowest_px(&lowest_px[b->ref[i]][0], t->by, bh4,
+                                 b->mv[i].y, 0, &f->svc[b->ref[i]][1]);
+                }
+            }
+
+            // uv
+            if (has_chroma) for (int i = 0; i < 2; i++) {
+                if (b->inter_mode == GLOBALMV_GLOBALMV &&
+                    imin(cbw4, cbh4) > 1 && f->gmv_warp_allowed[b->ref[i]])
+                {
+                    affine_lowest_px_chroma(t, &lowest_px[b->ref[i]][1], b_dim,
+                                            &f->frame_hdr->gmv[b->ref[i]]);
+                } else {
+                    mc_lowest_px(&lowest_px[b->ref[i]][1], t->by, bh4,
+                                 b->mv[i].y, ss_ver, &f->svc[b->ref[i]][1]);
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+#if __has_feature(memory_sanitizer)
+
+#include 
+
+static int checked_decode_b(Dav1dTaskContext *const t,
+                            const enum BlockLevel bl,
+                            const enum BlockSize bs,
+                            const enum BlockPartition bp,
+                            const enum EdgeFlags intra_edge_flags)
+{
+    const Dav1dFrameContext *const f = t->f;
+    const int err = decode_b(t, bl, bs, bp, intra_edge_flags);
+
+    if (err == 0 && !(t->frame_thread.pass & 1)) {
+        const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+        const int bw4 = b_dim[0], bh4 = b_dim[1];
+        const int w4 = imin(bw4, f->bw - t->bx), h4 = imin(bh4, f->bh - t->by);
+        const int has_chroma = f->seq_hdr->layout != DAV1D_PIXEL_LAYOUT_I400 &&
+                               (bw4 > ss_hor || t->bx & 1) &&
+                               (bh4 > ss_ver || t->by & 1);
+
+        for (int p = 0; p < 1 + 2 * has_chroma; p++) {
+            const int ss_ver = p && f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+            const int ss_hor = p && f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+            const ptrdiff_t stride = f->cur.stride[!!p];
+            const int bx = t->bx & ~ss_hor;
+            const int by = t->by & ~ss_ver;
+            const int width  = w4 << (2 - ss_hor + (bw4 == ss_hor));
+            const int height = h4 << (2 - ss_ver + (bh4 == ss_ver));
+
+            const uint8_t *data = f->cur.data[p] + (by << (2 - ss_ver)) * stride +
+                                  (bx << (2 - ss_hor + !!f->seq_hdr->hbd));
+
+            for (int y = 0; y < height; data += stride, y++) {
+                const size_t line_sz = width << !!f->seq_hdr->hbd;
+                if (__msan_test_shadow(data, line_sz) != -1) {
+                    fprintf(stderr, "B[%d](%d, %d) w4:%d, h4:%d, row:%d\n",
+                            p, bx, by, w4, h4, y);
+                    __msan_check_mem_is_initialized(data, line_sz);
+                }
+            }
+        }
+    }
+
+    return err;
+}
+
+#define decode_b checked_decode_b
+
+#endif /* defined(__has_feature) */
+
+static int decode_sb(Dav1dTaskContext *const t, const enum BlockLevel bl,
+                     const EdgeNode *const node)
+{
+    const Dav1dFrameContext *const f = t->f;
+    Dav1dTileState *const ts = t->ts;
+    const int hsz = 16 >> bl;
+    const int have_h_split = f->bw > t->bx + hsz;
+    const int have_v_split = f->bh > t->by + hsz;
+
+    if (!have_h_split && !have_v_split) {
+        assert(bl < BL_8X8);
+        return decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 0));
+    }
+
+    uint16_t *pc;
+    enum BlockPartition bp;
+    int ctx, bx8, by8;
+    if (t->frame_thread.pass != 2) {
+        if (0 && bl == BL_64X64)
+            printf("poc=%d,y=%d,x=%d,bl=%d,r=%d\n",
+                   f->frame_hdr->frame_offset, t->by, t->bx, bl, ts->msac.rng);
+        bx8 = (t->bx & 31) >> 1;
+        by8 = (t->by & 31) >> 1;
+        ctx = get_partition_ctx(t->a, &t->l, bl, by8, bx8);
+        pc = ts->cdf.m.partition[bl][ctx];
+    }
+
+    if (have_h_split && have_v_split) {
+        if (t->frame_thread.pass == 2) {
+            const Av1Block *const b = &f->frame_thread.b[t->by * f->b4_stride + t->bx];
+            bp = b->bl == bl ? b->bp : PARTITION_SPLIT;
+        } else {
+            bp = dav1d_msac_decode_symbol_adapt16(&ts->msac, pc,
+                                                  dav1d_partition_type_count[bl]);
+            if (f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I422 &&
+                (bp == PARTITION_V || bp == PARTITION_V4 ||
+                 bp == PARTITION_T_LEFT_SPLIT || bp == PARTITION_T_RIGHT_SPLIT))
+            {
+                return 1;
+            }
+            if (DEBUG_BLOCK_INFO)
+                printf("poc=%d,y=%d,x=%d,bl=%d,ctx=%d,bp=%d: r=%d\n",
+                       f->frame_hdr->frame_offset, t->by, t->bx, bl, ctx, bp,
+                       ts->msac.rng);
+        }
+        const uint8_t *const b = dav1d_block_sizes[bl][bp];
+
+        switch (bp) {
+        case PARTITION_NONE:
+            if (decode_b(t, bl, b[0], PARTITION_NONE, node->o))
+                return -1;
+            break;
+        case PARTITION_H:
+            if (decode_b(t, bl, b[0], PARTITION_H, node->h[0]))
+                return -1;
+            t->by += hsz;
+            if (decode_b(t, bl, b[0], PARTITION_H, node->h[1]))
+                return -1;
+            t->by -= hsz;
+            break;
+        case PARTITION_V:
+            if (decode_b(t, bl, b[0], PARTITION_V, node->v[0]))
+                return -1;
+            t->bx += hsz;
+            if (decode_b(t, bl, b[0], PARTITION_V, node->v[1]))
+                return -1;
+            t->bx -= hsz;
+            break;
+        case PARTITION_SPLIT:
+            if (bl == BL_8X8) {
+                const EdgeTip *const tip = (const EdgeTip *) node;
+                assert(hsz == 1);
+                if (decode_b(t, bl, BS_4x4, PARTITION_SPLIT, EDGE_ALL_TR_AND_BL))
+                    return -1;
+                const enum Filter2d tl_filter = t->tl_4x4_filter;
+                t->bx++;
+                if (decode_b(t, bl, BS_4x4, PARTITION_SPLIT, tip->split[0]))
+                    return -1;
+                t->bx--;
+                t->by++;
+                if (decode_b(t, bl, BS_4x4, PARTITION_SPLIT, tip->split[1]))
+                    return -1;
+                t->bx++;
+                t->tl_4x4_filter = tl_filter;
+                if (decode_b(t, bl, BS_4x4, PARTITION_SPLIT, tip->split[2]))
+                    return -1;
+                t->bx--;
+                t->by--;
+#if ARCH_X86_64
+                if (t->frame_thread.pass) {
+                    /* In 8-bit mode with 2-pass decoding the coefficient buffer
+                     * can end up misaligned due to skips here. Work around
+                     * the issue by explicitly realigning the buffer. */
+                    const int p = t->frame_thread.pass & 1;
+                    ts->frame_thread[p].cf =
+                        (void*)(((uintptr_t)ts->frame_thread[p].cf + 63) & ~63);
+                }
+#endif
+            } else {
+                if (decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 0)))
+                    return 1;
+                t->bx += hsz;
+                if (decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 1)))
+                    return 1;
+                t->bx -= hsz;
+                t->by += hsz;
+                if (decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 2)))
+                    return 1;
+                t->bx += hsz;
+                if (decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 3)))
+                    return 1;
+                t->bx -= hsz;
+                t->by -= hsz;
+            }
+            break;
+        case PARTITION_T_TOP_SPLIT: {
+            if (decode_b(t, bl, b[0], PARTITION_T_TOP_SPLIT, EDGE_ALL_TR_AND_BL))
+                return -1;
+            t->bx += hsz;
+            if (decode_b(t, bl, b[0], PARTITION_T_TOP_SPLIT, node->v[1]))
+                return -1;
+            t->bx -= hsz;
+            t->by += hsz;
+            if (decode_b(t, bl, b[1], PARTITION_T_TOP_SPLIT, node->h[1]))
+                return -1;
+            t->by -= hsz;
+            break;
+        }
+        case PARTITION_T_BOTTOM_SPLIT: {
+            if (decode_b(t, bl, b[0], PARTITION_T_BOTTOM_SPLIT, node->h[0]))
+                return -1;
+            t->by += hsz;
+            if (decode_b(t, bl, b[1], PARTITION_T_BOTTOM_SPLIT, node->v[0]))
+                return -1;
+            t->bx += hsz;
+            if (decode_b(t, bl, b[1], PARTITION_T_BOTTOM_SPLIT, 0))
+                return -1;
+            t->bx -= hsz;
+            t->by -= hsz;
+            break;
+        }
+        case PARTITION_T_LEFT_SPLIT: {
+            if (decode_b(t, bl, b[0], PARTITION_T_LEFT_SPLIT, EDGE_ALL_TR_AND_BL))
+                return -1;
+            t->by += hsz;
+            if (decode_b(t, bl, b[0], PARTITION_T_LEFT_SPLIT, node->h[1]))
+                return -1;
+            t->by -= hsz;
+            t->bx += hsz;
+            if (decode_b(t, bl, b[1], PARTITION_T_LEFT_SPLIT, node->v[1]))
+                return -1;
+            t->bx -= hsz;
+            break;
+        }
+        case PARTITION_T_RIGHT_SPLIT: {
+            if (decode_b(t, bl, b[0], PARTITION_T_RIGHT_SPLIT, node->v[0]))
+                return -1;
+            t->bx += hsz;
+            if (decode_b(t, bl, b[1], PARTITION_T_RIGHT_SPLIT, node->h[0]))
+                return -1;
+            t->by += hsz;
+            if (decode_b(t, bl, b[1], PARTITION_T_RIGHT_SPLIT, 0))
+                return -1;
+            t->by -= hsz;
+            t->bx -= hsz;
+            break;
+        }
+        case PARTITION_H4: {
+            const EdgeBranch *const branch = (const EdgeBranch *) node;
+            if (decode_b(t, bl, b[0], PARTITION_H4, node->h[0]))
+                return -1;
+            t->by += hsz >> 1;
+            if (decode_b(t, bl, b[0], PARTITION_H4, branch->h4))
+                return -1;
+            t->by += hsz >> 1;
+            if (decode_b(t, bl, b[0], PARTITION_H4, EDGE_ALL_LEFT_HAS_BOTTOM))
+                return -1;
+            t->by += hsz >> 1;
+            if (t->by < f->bh)
+                if (decode_b(t, bl, b[0], PARTITION_H4, node->h[1]))
+                    return -1;
+            t->by -= hsz * 3 >> 1;
+            break;
+        }
+        case PARTITION_V4: {
+            const EdgeBranch *const branch = (const EdgeBranch *) node;
+            if (decode_b(t, bl, b[0], PARTITION_V4, node->v[0]))
+                return -1;
+            t->bx += hsz >> 1;
+            if (decode_b(t, bl, b[0], PARTITION_V4, branch->v4))
+                return -1;
+            t->bx += hsz >> 1;
+            if (decode_b(t, bl, b[0], PARTITION_V4, EDGE_ALL_TOP_HAS_RIGHT))
+                return -1;
+            t->bx += hsz >> 1;
+            if (t->bx < f->bw)
+                if (decode_b(t, bl, b[0], PARTITION_V4, node->v[1]))
+                    return -1;
+            t->bx -= hsz * 3 >> 1;
+            break;
+        }
+        default: assert(0);
+        }
+    } else if (have_h_split) {
+        unsigned is_split;
+        if (t->frame_thread.pass == 2) {
+            const Av1Block *const b = &f->frame_thread.b[t->by * f->b4_stride + t->bx];
+            is_split = b->bl != bl;
+        } else {
+            is_split = dav1d_msac_decode_bool(&ts->msac,
+                           gather_top_partition_prob(pc, bl));
+            if (DEBUG_BLOCK_INFO)
+                printf("poc=%d,y=%d,x=%d,bl=%d,ctx=%d,bp=%d: r=%d\n",
+                       f->frame_hdr->frame_offset, t->by, t->bx, bl, ctx,
+                       is_split ? PARTITION_SPLIT : PARTITION_H, ts->msac.rng);
+        }
+
+        assert(bl < BL_8X8);
+        if (is_split) {
+            bp = PARTITION_SPLIT;
+            if (decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 0))) return 1;
+            t->bx += hsz;
+            if (decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 1))) return 1;
+            t->bx -= hsz;
+        } else {
+            bp = PARTITION_H;
+            if (decode_b(t, bl, dav1d_block_sizes[bl][PARTITION_H][0],
+                         PARTITION_H, node->h[0]))
+                return -1;
+        }
+    } else {
+        assert(have_v_split);
+        unsigned is_split;
+        if (t->frame_thread.pass == 2) {
+            const Av1Block *const b = &f->frame_thread.b[t->by * f->b4_stride + t->bx];
+            is_split = b->bl != bl;
+        } else {
+            is_split = dav1d_msac_decode_bool(&ts->msac,
+                           gather_left_partition_prob(pc, bl));
+            if (f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I422 && !is_split)
+                return 1;
+            if (DEBUG_BLOCK_INFO)
+                printf("poc=%d,y=%d,x=%d,bl=%d,ctx=%d,bp=%d: r=%d\n",
+                       f->frame_hdr->frame_offset, t->by, t->bx, bl, ctx,
+                       is_split ? PARTITION_SPLIT : PARTITION_V, ts->msac.rng);
+        }
+
+        assert(bl < BL_8X8);
+        if (is_split) {
+            bp = PARTITION_SPLIT;
+            if (decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 0))) return 1;
+            t->by += hsz;
+            if (decode_sb(t, bl + 1, INTRA_EDGE_SPLIT(node, 2))) return 1;
+            t->by -= hsz;
+        } else {
+            bp = PARTITION_V;
+            if (decode_b(t, bl, dav1d_block_sizes[bl][PARTITION_V][0],
+                         PARTITION_V, node->v[0]))
+                return -1;
+        }
+    }
+
+    if (t->frame_thread.pass != 2 && (bp != PARTITION_SPLIT || bl == BL_8X8)) {
+#define set_ctx(rep_macro) \
+        rep_macro(t->a->partition, bx8, dav1d_al_part_ctx[0][bl][bp]); \
+        rep_macro(t->l.partition, by8, dav1d_al_part_ctx[1][bl][bp])
+        case_set_upto16(ulog2(hsz));
+#undef set_ctx
+    }
+
+    return 0;
+}
+
+static void reset_context(BlockContext *const ctx, const int keyframe, const int pass) {
+    memset(ctx->intra, keyframe, sizeof(ctx->intra));
+    memset(ctx->uvmode, DC_PRED, sizeof(ctx->uvmode));
+    if (keyframe)
+        memset(ctx->mode, DC_PRED, sizeof(ctx->mode));
+
+    if (pass == 2) return;
+
+    memset(ctx->partition, 0, sizeof(ctx->partition));
+    memset(ctx->skip, 0, sizeof(ctx->skip));
+    memset(ctx->skip_mode, 0, sizeof(ctx->skip_mode));
+    memset(ctx->tx_lpf_y, 2, sizeof(ctx->tx_lpf_y));
+    memset(ctx->tx_lpf_uv, 1, sizeof(ctx->tx_lpf_uv));
+    memset(ctx->tx_intra, -1, sizeof(ctx->tx_intra));
+    memset(ctx->tx, TX_64X64, sizeof(ctx->tx));
+    if (!keyframe) {
+        memset(ctx->ref, -1, sizeof(ctx->ref));
+        memset(ctx->comp_type, 0, sizeof(ctx->comp_type));
+        memset(ctx->mode, NEARESTMV, sizeof(ctx->mode));
+    }
+    memset(ctx->lcoef, 0x40, sizeof(ctx->lcoef));
+    memset(ctx->ccoef, 0x40, sizeof(ctx->ccoef));
+    memset(ctx->filter, DAV1D_N_SWITCHABLE_FILTERS, sizeof(ctx->filter));
+    memset(ctx->seg_pred, 0, sizeof(ctx->seg_pred));
+    memset(ctx->pal_sz, 0, sizeof(ctx->pal_sz));
+}
+
+// { Y+U+V, Y+U } * 4
+static const uint8_t ss_size_mul[4][2] = {
+    [DAV1D_PIXEL_LAYOUT_I400] = {  4, 4 },
+    [DAV1D_PIXEL_LAYOUT_I420] = {  6, 5 },
+    [DAV1D_PIXEL_LAYOUT_I422] = {  8, 6 },
+    [DAV1D_PIXEL_LAYOUT_I444] = { 12, 8 },
+};
+
+static void setup_tile(Dav1dTileState *const ts,
+                       const Dav1dFrameContext *const f,
+                       const uint8_t *const data, const size_t sz,
+                       const int tile_row, const int tile_col,
+                       const unsigned tile_start_off)
+{
+    const int col_sb_start = f->frame_hdr->tiling.col_start_sb[tile_col];
+    const int col_sb128_start = col_sb_start >> !f->seq_hdr->sb128;
+    const int col_sb_end = f->frame_hdr->tiling.col_start_sb[tile_col + 1];
+    const int row_sb_start = f->frame_hdr->tiling.row_start_sb[tile_row];
+    const int row_sb_end = f->frame_hdr->tiling.row_start_sb[tile_row + 1];
+    const int sb_shift = f->sb_shift;
+
+    const uint8_t *const size_mul = ss_size_mul[f->cur.p.layout];
+    for (int p = 0; p < 2; p++) {
+        ts->frame_thread[p].pal_idx = f->frame_thread.pal_idx ?
+            &f->frame_thread.pal_idx[(size_t)tile_start_off * size_mul[1] / 8] :
+            NULL;
+        ts->frame_thread[p].cbi = f->frame_thread.cbi ?
+            &f->frame_thread.cbi[(size_t)tile_start_off * size_mul[0] / 64] :
+            NULL;
+        ts->frame_thread[p].cf = f->frame_thread.cf ?
+            (uint8_t*)f->frame_thread.cf +
+                (((size_t)tile_start_off * size_mul[0]) >> !f->seq_hdr->hbd) :
+            NULL;
+    }
+
+    dav1d_cdf_thread_copy(&ts->cdf, &f->in_cdf);
+    ts->last_qidx = f->frame_hdr->quant.yac;
+    ts->last_delta_lf.u32 = 0;
+
+    dav1d_msac_init(&ts->msac, data, sz, f->frame_hdr->disable_cdf_update);
+
+    ts->tiling.row = tile_row;
+    ts->tiling.col = tile_col;
+    ts->tiling.col_start = col_sb_start << sb_shift;
+    ts->tiling.col_end = imin(col_sb_end << sb_shift, f->bw);
+    ts->tiling.row_start = row_sb_start << sb_shift;
+    ts->tiling.row_end = imin(row_sb_end << sb_shift, f->bh);
+
+    // Reference Restoration Unit (used for exp coding)
+    int sb_idx, unit_idx;
+    if (f->frame_hdr->width[0] != f->frame_hdr->width[1]) {
+        // vertical components only
+        sb_idx = (ts->tiling.row_start >> 5) * f->sr_sb128w;
+        unit_idx = (ts->tiling.row_start & 16) >> 3;
+    } else {
+        sb_idx = (ts->tiling.row_start >> 5) * f->sb128w + col_sb128_start;
+        unit_idx = ((ts->tiling.row_start & 16) >> 3) +
+                   ((ts->tiling.col_start & 16) >> 4);
+    }
+    for (int p = 0; p < 3; p++) {
+        if (!((f->lf.restore_planes >> p) & 1U))
+            continue;
+
+        if (f->frame_hdr->width[0] != f->frame_hdr->width[1]) {
+            const int ss_hor = p && f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+            const int d = f->frame_hdr->super_res.width_scale_denominator;
+            const int unit_size_log2 = f->frame_hdr->restoration.unit_size[!!p];
+            const int rnd = (8 << unit_size_log2) - 1, shift = unit_size_log2 + 3;
+            const int x = ((4 * ts->tiling.col_start * d >> ss_hor) + rnd) >> shift;
+            const int px_x = x << (unit_size_log2 + ss_hor);
+            const int u_idx = unit_idx + ((px_x & 64) >> 6);
+            const int sb128x = px_x >> 7;
+            if (sb128x >= f->sr_sb128w) continue;
+            ts->lr_ref[p] = &f->lf.lr_mask[sb_idx + sb128x].lr[p][u_idx];
+        } else {
+            ts->lr_ref[p] = &f->lf.lr_mask[sb_idx].lr[p][unit_idx];
+        }
+
+        ts->lr_ref[p]->filter_v[0] = 3;
+        ts->lr_ref[p]->filter_v[1] = -7;
+        ts->lr_ref[p]->filter_v[2] = 15;
+        ts->lr_ref[p]->filter_h[0] = 3;
+        ts->lr_ref[p]->filter_h[1] = -7;
+        ts->lr_ref[p]->filter_h[2] = 15;
+        ts->lr_ref[p]->sgr_weights[0] = -32;
+        ts->lr_ref[p]->sgr_weights[1] = 31;
+    }
+
+    if (f->c->n_tc > 1) {
+        for (int p = 0; p < 2; p++)
+            atomic_init(&ts->progress[p], row_sb_start);
+    }
+}
+
+static void read_restoration_info(Dav1dTaskContext *const t,
+                                  Av1RestorationUnit *const lr, const int p,
+                                  const enum Dav1dRestorationType frame_type)
+{
+    const Dav1dFrameContext *const f = t->f;
+    Dav1dTileState *const ts = t->ts;
+
+    if (frame_type == DAV1D_RESTORATION_SWITCHABLE) {
+        const int filter = dav1d_msac_decode_symbol_adapt4(&ts->msac,
+                               ts->cdf.m.restore_switchable, 2);
+        lr->type = filter + !!filter; /* NONE/WIENER/SGRPROJ */
+    } else {
+        const unsigned type =
+            dav1d_msac_decode_bool_adapt(&ts->msac,
+                frame_type == DAV1D_RESTORATION_WIENER ?
+                ts->cdf.m.restore_wiener : ts->cdf.m.restore_sgrproj);
+        lr->type = type ? frame_type : DAV1D_RESTORATION_NONE;
+    }
+
+    if (lr->type == DAV1D_RESTORATION_WIENER) {
+        lr->filter_v[0] = p ? 0 :
+            dav1d_msac_decode_subexp(&ts->msac,
+                ts->lr_ref[p]->filter_v[0] + 5, 16, 1) - 5;
+        lr->filter_v[1] =
+            dav1d_msac_decode_subexp(&ts->msac,
+                ts->lr_ref[p]->filter_v[1] + 23, 32, 2) - 23;
+        lr->filter_v[2] =
+            dav1d_msac_decode_subexp(&ts->msac,
+                ts->lr_ref[p]->filter_v[2] + 17, 64, 3) - 17;
+
+        lr->filter_h[0] = p ? 0 :
+            dav1d_msac_decode_subexp(&ts->msac,
+                ts->lr_ref[p]->filter_h[0] + 5, 16, 1) - 5;
+        lr->filter_h[1] =
+            dav1d_msac_decode_subexp(&ts->msac,
+                ts->lr_ref[p]->filter_h[1] + 23, 32, 2) - 23;
+        lr->filter_h[2] =
+            dav1d_msac_decode_subexp(&ts->msac,
+                ts->lr_ref[p]->filter_h[2] + 17, 64, 3) - 17;
+        memcpy(lr->sgr_weights, ts->lr_ref[p]->sgr_weights, sizeof(lr->sgr_weights));
+        ts->lr_ref[p] = lr;
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-lr_wiener[pl=%d,v[%d,%d,%d],h[%d,%d,%d]]: r=%d\n",
+                   p, lr->filter_v[0], lr->filter_v[1],
+                   lr->filter_v[2], lr->filter_h[0],
+                   lr->filter_h[1], lr->filter_h[2], ts->msac.rng);
+    } else if (lr->type == DAV1D_RESTORATION_SGRPROJ) {
+        const unsigned idx = dav1d_msac_decode_bools(&ts->msac, 4);
+        const uint16_t *const sgr_params = dav1d_sgr_params[idx];
+        lr->type += idx;
+        lr->sgr_weights[0] = sgr_params[0] ? dav1d_msac_decode_subexp(&ts->msac,
+            ts->lr_ref[p]->sgr_weights[0] + 96, 128, 4) - 96 : 0;
+        lr->sgr_weights[1] = sgr_params[1] ? dav1d_msac_decode_subexp(&ts->msac,
+            ts->lr_ref[p]->sgr_weights[1] + 32, 128, 4) - 32 : 95;
+        memcpy(lr->filter_v, ts->lr_ref[p]->filter_v, sizeof(lr->filter_v));
+        memcpy(lr->filter_h, ts->lr_ref[p]->filter_h, sizeof(lr->filter_h));
+        ts->lr_ref[p] = lr;
+        if (DEBUG_BLOCK_INFO)
+            printf("Post-lr_sgrproj[pl=%d,idx=%d,w[%d,%d]]: r=%d\n",
+                   p, idx, lr->sgr_weights[0],
+                   lr->sgr_weights[1], ts->msac.rng);
+    }
+}
+
+// modeled after the equivalent function in aomdec:decodeframe.c
+static int check_trailing_bits_after_symbol_coder(const MsacContext *const msac) {
+    // check marker bit (single 1), followed by zeroes
+    const int n_bits = -(msac->cnt + 14);
+    assert(n_bits <= 0); // this assumes we errored out when cnt <= -15 in caller
+    const int n_bytes = (n_bits + 7) >> 3;
+    const uint8_t *p = &msac->buf_pos[n_bytes];
+    const int pattern = 128 >> ((n_bits - 1) & 7);
+    if ((p[-1] & (2 * pattern - 1)) != pattern)
+        return 1;
+
+    // check remainder zero bytes
+    for (; p < msac->buf_end; p++)
+        if (*p)
+            return 1;
+
+    return 0;
+}
+
+int dav1d_decode_tile_sbrow(Dav1dTaskContext *const t) {
+    const Dav1dFrameContext *const f = t->f;
+    const enum BlockLevel root_bl = f->seq_hdr->sb128 ? BL_128X128 : BL_64X64;
+    Dav1dTileState *const ts = t->ts;
+    const Dav1dContext *const c = f->c;
+    const int sb_step = f->sb_step;
+    const int tile_row = ts->tiling.row, tile_col = ts->tiling.col;
+    const int col_sb_start = f->frame_hdr->tiling.col_start_sb[tile_col];
+    const int col_sb128_start = col_sb_start >> !f->seq_hdr->sb128;
+
+    if (IS_INTER_OR_SWITCH(f->frame_hdr) || f->frame_hdr->allow_intrabc) {
+        dav1d_refmvs_tile_sbrow_init(&t->rt, &f->rf, ts->tiling.col_start,
+                                     ts->tiling.col_end, ts->tiling.row_start,
+                                     ts->tiling.row_end, t->by >> f->sb_shift,
+                                     ts->tiling.row, t->frame_thread.pass);
+    }
+
+    if (IS_INTER_OR_SWITCH(f->frame_hdr) && c->n_fc > 1) {
+        const int sby = (t->by - ts->tiling.row_start) >> f->sb_shift;
+        int (*const lowest_px)[2] = ts->lowest_pixel[sby];
+        for (int n = 0; n < 7; n++)
+            for (int m = 0; m < 2; m++)
+                lowest_px[n][m] = INT_MIN;
+    }
+
+    reset_context(&t->l, IS_KEY_OR_INTRA(f->frame_hdr), t->frame_thread.pass);
+    if (t->frame_thread.pass == 2) {
+        const int off_2pass = c->n_tc > 1 ? f->sb128w * f->frame_hdr->tiling.rows : 0;
+        for (t->bx = ts->tiling.col_start,
+             t->a = f->a + off_2pass + col_sb128_start + tile_row * f->sb128w;
+             t->bx < ts->tiling.col_end; t->bx += sb_step)
+        {
+            if (atomic_load_explicit(c->flush, memory_order_acquire))
+                return 1;
+            if (decode_sb(t, root_bl, dav1d_intra_edge_tree[root_bl]))
+                return 1;
+            if (t->bx & 16 || f->seq_hdr->sb128)
+                t->a++;
+        }
+        f->bd_fn.backup_ipred_edge(t);
+        return 0;
+    }
+
+    if (f->c->n_tc > 1 && f->frame_hdr->use_ref_frame_mvs) {
+        f->c->refmvs_dsp.load_tmvs(&f->rf, ts->tiling.row,
+                                   ts->tiling.col_start >> 1, ts->tiling.col_end >> 1,
+                                   t->by >> 1, (t->by + sb_step) >> 1);
+    }
+    memset(t->pal_sz_uv[1], 0, sizeof(*t->pal_sz_uv));
+    const int sb128y = t->by >> 5;
+    for (t->bx = ts->tiling.col_start, t->a = f->a + col_sb128_start + tile_row * f->sb128w,
+         t->lf_mask = f->lf.mask + sb128y * f->sb128w + col_sb128_start;
+         t->bx < ts->tiling.col_end; t->bx += sb_step)
+    {
+        if (atomic_load_explicit(c->flush, memory_order_acquire))
+            return 1;
+        if (root_bl == BL_128X128) {
+            t->cur_sb_cdef_idx_ptr = t->lf_mask->cdef_idx;
+            t->cur_sb_cdef_idx_ptr[0] = -1;
+            t->cur_sb_cdef_idx_ptr[1] = -1;
+            t->cur_sb_cdef_idx_ptr[2] = -1;
+            t->cur_sb_cdef_idx_ptr[3] = -1;
+        } else {
+            t->cur_sb_cdef_idx_ptr =
+                &t->lf_mask->cdef_idx[((t->bx & 16) >> 4) +
+                                      ((t->by & 16) >> 3)];
+            t->cur_sb_cdef_idx_ptr[0] = -1;
+        }
+        // Restoration filter
+        for (int p = 0; p < 3; p++) {
+            if (!((f->lf.restore_planes >> p) & 1U))
+                continue;
+
+            const int ss_ver = p && f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+            const int ss_hor = p && f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+            const int unit_size_log2 = f->frame_hdr->restoration.unit_size[!!p];
+            const int y = t->by * 4 >> ss_ver;
+            const int h = (f->cur.p.h + ss_ver) >> ss_ver;
+
+            const int unit_size = 1 << unit_size_log2;
+            const unsigned mask = unit_size - 1;
+            if (y & mask) continue;
+            const int half_unit = unit_size >> 1;
+            // Round half up at frame boundaries, if there's more than one
+            // restoration unit
+            if (y && y + half_unit > h) continue;
+
+            const enum Dav1dRestorationType frame_type = f->frame_hdr->restoration.type[p];
+
+            if (f->frame_hdr->width[0] != f->frame_hdr->width[1]) {
+                const int w = (f->sr_cur.p.p.w + ss_hor) >> ss_hor;
+                const int n_units = imax(1, (w + half_unit) >> unit_size_log2);
+
+                const int d = f->frame_hdr->super_res.width_scale_denominator;
+                const int rnd = unit_size * 8 - 1, shift = unit_size_log2 + 3;
+                const int x0 = ((4 *  t->bx            * d >> ss_hor) + rnd) >> shift;
+                const int x1 = ((4 * (t->bx + sb_step) * d >> ss_hor) + rnd) >> shift;
+
+                for (int x = x0; x < imin(x1, n_units); x++) {
+                    const int px_x = x << (unit_size_log2 + ss_hor);
+                    const int sb_idx = (t->by >> 5) * f->sr_sb128w + (px_x >> 7);
+                    const int unit_idx = ((t->by & 16) >> 3) + ((px_x & 64) >> 6);
+                    Av1RestorationUnit *const lr = &f->lf.lr_mask[sb_idx].lr[p][unit_idx];
+
+                    read_restoration_info(t, lr, p, frame_type);
+                }
+            } else {
+                const int x = 4 * t->bx >> ss_hor;
+                if (x & mask) continue;
+                const int w = (f->cur.p.w + ss_hor) >> ss_hor;
+                // Round half up at frame boundaries, if there's more than one
+                // restoration unit
+                if (x && x + half_unit > w) continue;
+                const int sb_idx = (t->by >> 5) * f->sr_sb128w + (t->bx >> 5);
+                const int unit_idx = ((t->by & 16) >> 3) + ((t->bx & 16) >> 4);
+                Av1RestorationUnit *const lr = &f->lf.lr_mask[sb_idx].lr[p][unit_idx];
+
+                read_restoration_info(t, lr, p, frame_type);
+            }
+        }
+        if (decode_sb(t, root_bl, dav1d_intra_edge_tree[root_bl]))
+            return 1;
+        if (t->bx & 16 || f->seq_hdr->sb128) {
+            t->a++;
+            t->lf_mask++;
+        }
+    }
+
+    if (f->seq_hdr->ref_frame_mvs && f->c->n_tc > 1 && IS_INTER_OR_SWITCH(f->frame_hdr)) {
+        dav1d_refmvs_save_tmvs(&f->c->refmvs_dsp, &t->rt,
+                               ts->tiling.col_start >> 1, ts->tiling.col_end >> 1,
+                               t->by >> 1, (t->by + sb_step) >> 1);
+    }
+
+    // backup pre-loopfilter pixels for intra prediction of the next sbrow
+    if (t->frame_thread.pass != 1)
+        f->bd_fn.backup_ipred_edge(t);
+
+    // backup t->a/l.tx_lpf_y/uv at tile boundaries to use them to "fix"
+    // up the initial value in neighbour tiles when running the loopfilter
+    int align_h = (f->bh + 31) & ~31;
+    memcpy(&f->lf.tx_lpf_right_edge[0][align_h * tile_col + t->by],
+           &t->l.tx_lpf_y[t->by & 16], sb_step);
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    align_h >>= ss_ver;
+    memcpy(&f->lf.tx_lpf_right_edge[1][align_h * tile_col + (t->by >> ss_ver)],
+           &t->l.tx_lpf_uv[(t->by & 16) >> ss_ver], sb_step >> ss_ver);
+
+    // error out on symbol decoder overread
+    if (ts->msac.cnt <= -15) return 1;
+
+    return c->strict_std_compliance &&
+           (t->by >> f->sb_shift) + 1 >= f->frame_hdr->tiling.row_start_sb[tile_row + 1] &&
+           check_trailing_bits_after_symbol_coder(&ts->msac);
+}
+
+int dav1d_decode_frame_init(Dav1dFrameContext *const f) {
+    const Dav1dContext *const c = f->c;
+    int retval = DAV1D_ERR(ENOMEM);
+
+    if (f->sbh > f->lf.start_of_tile_row_sz) {
+        dav1d_free(f->lf.start_of_tile_row);
+        f->lf.start_of_tile_row = dav1d_malloc(ALLOC_TILE, f->sbh * sizeof(uint8_t));
+        if (!f->lf.start_of_tile_row) {
+            f->lf.start_of_tile_row_sz = 0;
+            goto error;
+        }
+        f->lf.start_of_tile_row_sz = f->sbh;
+    }
+    int sby = 0;
+    for (int tile_row = 0; tile_row < f->frame_hdr->tiling.rows; tile_row++) {
+        f->lf.start_of_tile_row[sby++] = tile_row;
+        while (sby < f->frame_hdr->tiling.row_start_sb[tile_row + 1])
+            f->lf.start_of_tile_row[sby++] = 0;
+    }
+
+    const int n_ts = f->frame_hdr->tiling.cols * f->frame_hdr->tiling.rows;
+    if (n_ts != f->n_ts) {
+        if (c->n_fc > 1) {
+            dav1d_free(f->frame_thread.tile_start_off);
+            f->frame_thread.tile_start_off =
+                dav1d_malloc(ALLOC_TILE, sizeof(*f->frame_thread.tile_start_off) * n_ts);
+            if (!f->frame_thread.tile_start_off) {
+                f->n_ts = 0;
+                goto error;
+            }
+        }
+        dav1d_free_aligned(f->ts);
+        f->ts = dav1d_alloc_aligned(ALLOC_TILE, sizeof(*f->ts) * n_ts, 32);
+        if (!f->ts) goto error;
+        f->n_ts = n_ts;
+    }
+
+    const int a_sz = f->sb128w * f->frame_hdr->tiling.rows * (1 + (c->n_fc > 1 && c->n_tc > 1));
+    if (a_sz != f->a_sz) {
+        dav1d_free(f->a);
+        f->a = dav1d_malloc(ALLOC_TILE, sizeof(*f->a) * a_sz);
+        if (!f->a) {
+            f->a_sz = 0;
+            goto error;
+        }
+        f->a_sz = a_sz;
+    }
+
+    const int num_sb128 = f->sb128w * f->sb128h;
+    const uint8_t *const size_mul = ss_size_mul[f->cur.p.layout];
+    const int hbd = !!f->seq_hdr->hbd;
+    if (c->n_fc > 1) {
+        const unsigned sb_step4 = f->sb_step * 4;
+        int tile_idx = 0;
+        for (int tile_row = 0; tile_row < f->frame_hdr->tiling.rows; tile_row++) {
+            const unsigned row_off = f->frame_hdr->tiling.row_start_sb[tile_row] *
+                                     sb_step4 * f->sb128w * 128;
+            const unsigned b_diff = (f->frame_hdr->tiling.row_start_sb[tile_row + 1] -
+                                     f->frame_hdr->tiling.row_start_sb[tile_row]) * sb_step4;
+            for (int tile_col = 0; tile_col < f->frame_hdr->tiling.cols; tile_col++) {
+                f->frame_thread.tile_start_off[tile_idx++] = row_off + b_diff *
+                    f->frame_hdr->tiling.col_start_sb[tile_col] * sb_step4;
+            }
+        }
+
+        const int lowest_pixel_mem_sz = f->frame_hdr->tiling.cols * f->sbh;
+        if (lowest_pixel_mem_sz != f->tile_thread.lowest_pixel_mem_sz) {
+            dav1d_free(f->tile_thread.lowest_pixel_mem);
+            f->tile_thread.lowest_pixel_mem =
+                dav1d_malloc(ALLOC_TILE, lowest_pixel_mem_sz *
+                             sizeof(*f->tile_thread.lowest_pixel_mem));
+            if (!f->tile_thread.lowest_pixel_mem) {
+                f->tile_thread.lowest_pixel_mem_sz = 0;
+                goto error;
+            }
+            f->tile_thread.lowest_pixel_mem_sz = lowest_pixel_mem_sz;
+        }
+        int (*lowest_pixel_ptr)[7][2] = f->tile_thread.lowest_pixel_mem;
+        for (int tile_row = 0, tile_row_base = 0; tile_row < f->frame_hdr->tiling.rows;
+             tile_row++, tile_row_base += f->frame_hdr->tiling.cols)
+        {
+            const int tile_row_sb_h = f->frame_hdr->tiling.row_start_sb[tile_row + 1] -
+                                      f->frame_hdr->tiling.row_start_sb[tile_row];
+            for (int tile_col = 0; tile_col < f->frame_hdr->tiling.cols; tile_col++) {
+                f->ts[tile_row_base + tile_col].lowest_pixel = lowest_pixel_ptr;
+                lowest_pixel_ptr += tile_row_sb_h;
+            }
+        }
+
+        const int cbi_sz = num_sb128 * size_mul[0];
+        if (cbi_sz != f->frame_thread.cbi_sz) {
+            dav1d_free_aligned(f->frame_thread.cbi);
+            f->frame_thread.cbi =
+                dav1d_alloc_aligned(ALLOC_BLOCK, sizeof(*f->frame_thread.cbi) *
+                                    cbi_sz * 32 * 32 / 4, 64);
+            if (!f->frame_thread.cbi) {
+                f->frame_thread.cbi_sz = 0;
+                goto error;
+            }
+            f->frame_thread.cbi_sz = cbi_sz;
+        }
+
+        const int cf_sz = (num_sb128 * size_mul[0]) << hbd;
+        if (cf_sz != f->frame_thread.cf_sz) {
+            dav1d_free_aligned(f->frame_thread.cf);
+            f->frame_thread.cf =
+                dav1d_alloc_aligned(ALLOC_COEF, (size_t)cf_sz * 128 * 128 / 2, 64);
+            if (!f->frame_thread.cf) {
+                f->frame_thread.cf_sz = 0;
+                goto error;
+            }
+            memset(f->frame_thread.cf, 0, (size_t)cf_sz * 128 * 128 / 2);
+            f->frame_thread.cf_sz = cf_sz;
+        }
+
+        if (f->frame_hdr->allow_screen_content_tools) {
+            const int pal_sz = num_sb128 << hbd;
+            if (pal_sz != f->frame_thread.pal_sz) {
+                dav1d_free_aligned(f->frame_thread.pal);
+                f->frame_thread.pal =
+                    dav1d_alloc_aligned(ALLOC_PAL, sizeof(*f->frame_thread.pal) *
+                                        pal_sz * 16 * 16, 64);
+                if (!f->frame_thread.pal) {
+                    f->frame_thread.pal_sz = 0;
+                    goto error;
+                }
+                f->frame_thread.pal_sz = pal_sz;
+            }
+
+            const int pal_idx_sz = num_sb128 * size_mul[1];
+            if (pal_idx_sz != f->frame_thread.pal_idx_sz) {
+                dav1d_free_aligned(f->frame_thread.pal_idx);
+                f->frame_thread.pal_idx =
+                    dav1d_alloc_aligned(ALLOC_PAL, sizeof(*f->frame_thread.pal_idx) *
+                                        pal_idx_sz * 128 * 128 / 8, 64);
+                if (!f->frame_thread.pal_idx) {
+                    f->frame_thread.pal_idx_sz = 0;
+                    goto error;
+                }
+                f->frame_thread.pal_idx_sz = pal_idx_sz;
+            }
+        } else if (f->frame_thread.pal) {
+            dav1d_freep_aligned(&f->frame_thread.pal);
+            dav1d_freep_aligned(&f->frame_thread.pal_idx);
+            f->frame_thread.pal_sz = f->frame_thread.pal_idx_sz = 0;
+        }
+    }
+
+    // update allocation of block contexts for above
+    ptrdiff_t y_stride = f->cur.stride[0], uv_stride = f->cur.stride[1];
+    const int has_resize = f->frame_hdr->width[0] != f->frame_hdr->width[1];
+    const int need_cdef_lpf_copy = c->n_tc > 1 && has_resize;
+    if (y_stride * f->sbh * 4 != f->lf.cdef_buf_plane_sz[0] ||
+        uv_stride * f->sbh * 8 != f->lf.cdef_buf_plane_sz[1] ||
+        need_cdef_lpf_copy != f->lf.need_cdef_lpf_copy ||
+        f->sbh != f->lf.cdef_buf_sbh)
+    {
+        dav1d_free_aligned(f->lf.cdef_line_buf);
+        size_t alloc_sz = 64;
+        alloc_sz += (size_t)llabs(y_stride) * 4 * f->sbh << need_cdef_lpf_copy;
+        alloc_sz += (size_t)llabs(uv_stride) * 8 * f->sbh << need_cdef_lpf_copy;
+        uint8_t *ptr = f->lf.cdef_line_buf = dav1d_alloc_aligned(ALLOC_CDEF, alloc_sz, 32);
+        if (!ptr) {
+            f->lf.cdef_buf_plane_sz[0] = f->lf.cdef_buf_plane_sz[1] = 0;
+            goto error;
+        }
+
+        ptr += 32;
+        if (y_stride < 0) {
+            f->lf.cdef_line[0][0] = ptr - y_stride * (f->sbh * 4 - 1);
+            f->lf.cdef_line[1][0] = ptr - y_stride * (f->sbh * 4 - 3);
+        } else {
+            f->lf.cdef_line[0][0] = ptr + y_stride * 0;
+            f->lf.cdef_line[1][0] = ptr + y_stride * 2;
+        }
+        ptr += llabs(y_stride) * f->sbh * 4;
+        if (uv_stride < 0) {
+            f->lf.cdef_line[0][1] = ptr - uv_stride * (f->sbh * 8 - 1);
+            f->lf.cdef_line[0][2] = ptr - uv_stride * (f->sbh * 8 - 3);
+            f->lf.cdef_line[1][1] = ptr - uv_stride * (f->sbh * 8 - 5);
+            f->lf.cdef_line[1][2] = ptr - uv_stride * (f->sbh * 8 - 7);
+        } else {
+            f->lf.cdef_line[0][1] = ptr + uv_stride * 0;
+            f->lf.cdef_line[0][2] = ptr + uv_stride * 2;
+            f->lf.cdef_line[1][1] = ptr + uv_stride * 4;
+            f->lf.cdef_line[1][2] = ptr + uv_stride * 6;
+        }
+
+        if (need_cdef_lpf_copy) {
+            ptr += llabs(uv_stride) * f->sbh * 8;
+            if (y_stride < 0)
+                f->lf.cdef_lpf_line[0] = ptr - y_stride * (f->sbh * 4 - 1);
+            else
+                f->lf.cdef_lpf_line[0] = ptr;
+            ptr += llabs(y_stride) * f->sbh * 4;
+            if (uv_stride < 0) {
+                f->lf.cdef_lpf_line[1] = ptr - uv_stride * (f->sbh * 4 - 1);
+                f->lf.cdef_lpf_line[2] = ptr - uv_stride * (f->sbh * 8 - 1);
+            } else {
+                f->lf.cdef_lpf_line[1] = ptr;
+                f->lf.cdef_lpf_line[2] = ptr + uv_stride * f->sbh * 4;
+            }
+        }
+
+        f->lf.cdef_buf_plane_sz[0] = (int) y_stride * f->sbh * 4;
+        f->lf.cdef_buf_plane_sz[1] = (int) uv_stride * f->sbh * 8;
+        f->lf.need_cdef_lpf_copy = need_cdef_lpf_copy;
+        f->lf.cdef_buf_sbh = f->sbh;
+    }
+
+    const int sb128 = f->seq_hdr->sb128;
+    const int num_lines = c->n_tc > 1 ? f->sbh * 4 << sb128 : 12;
+    y_stride = f->sr_cur.p.stride[0], uv_stride = f->sr_cur.p.stride[1];
+    if (y_stride * num_lines != f->lf.lr_buf_plane_sz[0] ||
+        uv_stride * num_lines * 2 != f->lf.lr_buf_plane_sz[1])
+    {
+        dav1d_free_aligned(f->lf.lr_line_buf);
+        // lr simd may overread the input, so slightly over-allocate the lpf buffer
+        size_t alloc_sz = 128;
+        alloc_sz += (size_t)llabs(y_stride) * num_lines;
+        alloc_sz += (size_t)llabs(uv_stride) * num_lines * 2;
+        uint8_t *ptr = f->lf.lr_line_buf = dav1d_alloc_aligned(ALLOC_LR, alloc_sz, 64);
+        if (!ptr) {
+            f->lf.lr_buf_plane_sz[0] = f->lf.lr_buf_plane_sz[1] = 0;
+            goto error;
+        }
+
+        ptr += 64;
+        if (y_stride < 0)
+            f->lf.lr_lpf_line[0] = ptr - y_stride * (num_lines - 1);
+        else
+            f->lf.lr_lpf_line[0] = ptr;
+        ptr += llabs(y_stride) * num_lines;
+        if (uv_stride < 0) {
+            f->lf.lr_lpf_line[1] = ptr - uv_stride * (num_lines * 1 - 1);
+            f->lf.lr_lpf_line[2] = ptr - uv_stride * (num_lines * 2 - 1);
+        } else {
+            f->lf.lr_lpf_line[1] = ptr;
+            f->lf.lr_lpf_line[2] = ptr + uv_stride * num_lines;
+        }
+
+        f->lf.lr_buf_plane_sz[0] = (int) y_stride * num_lines;
+        f->lf.lr_buf_plane_sz[1] = (int) uv_stride * num_lines * 2;
+    }
+
+    // update allocation for loopfilter masks
+    if (num_sb128 != f->lf.mask_sz) {
+        dav1d_free(f->lf.mask);
+        dav1d_free(f->lf.level);
+        f->lf.mask = dav1d_malloc(ALLOC_LF, sizeof(*f->lf.mask) * num_sb128);
+        // over-allocate by 3 bytes since some of the SIMD implementations
+        // index this from the level type and can thus over-read by up to 3
+        f->lf.level = dav1d_malloc(ALLOC_LF, sizeof(*f->lf.level) * num_sb128 * 32 * 32 + 3);
+        if (!f->lf.mask || !f->lf.level) {
+            f->lf.mask_sz = 0;
+            goto error;
+        }
+        if (c->n_fc > 1) {
+            dav1d_free(f->frame_thread.b);
+            f->frame_thread.b = dav1d_malloc(ALLOC_BLOCK, sizeof(*f->frame_thread.b) *
+                                             num_sb128 * 32 * 32);
+            if (!f->frame_thread.b) {
+                f->lf.mask_sz = 0;
+                goto error;
+            }
+        }
+        f->lf.mask_sz = num_sb128;
+    }
+
+    f->sr_sb128w = (f->sr_cur.p.p.w + 127) >> 7;
+    const int lr_mask_sz = f->sr_sb128w * f->sb128h;
+    if (lr_mask_sz != f->lf.lr_mask_sz) {
+        dav1d_free(f->lf.lr_mask);
+        f->lf.lr_mask = dav1d_malloc(ALLOC_LR, sizeof(*f->lf.lr_mask) * lr_mask_sz);
+        if (!f->lf.lr_mask) {
+            f->lf.lr_mask_sz = 0;
+            goto error;
+        }
+        f->lf.lr_mask_sz = lr_mask_sz;
+    }
+    f->lf.restore_planes =
+        ((f->frame_hdr->restoration.type[0] != DAV1D_RESTORATION_NONE) << 0) +
+        ((f->frame_hdr->restoration.type[1] != DAV1D_RESTORATION_NONE) << 1) +
+        ((f->frame_hdr->restoration.type[2] != DAV1D_RESTORATION_NONE) << 2);
+    if (f->frame_hdr->loopfilter.sharpness != f->lf.last_sharpness) {
+        dav1d_calc_eih(&f->lf.lim_lut, f->frame_hdr->loopfilter.sharpness);
+        f->lf.last_sharpness = f->frame_hdr->loopfilter.sharpness;
+    }
+    dav1d_calc_lf_values(f->lf.lvl, f->frame_hdr, (int8_t[4]) { 0, 0, 0, 0 });
+    memset(f->lf.mask, 0, sizeof(*f->lf.mask) * num_sb128);
+
+    const int ipred_edge_sz = f->sbh * f->sb128w << hbd;
+    if (ipred_edge_sz != f->ipred_edge_sz) {
+        dav1d_free_aligned(f->ipred_edge[0]);
+        uint8_t *ptr = f->ipred_edge[0] =
+            dav1d_alloc_aligned(ALLOC_IPRED, ipred_edge_sz * 128 * 3, 64);
+        if (!ptr) {
+            f->ipred_edge_sz = 0;
+            goto error;
+        }
+        f->ipred_edge[1] = ptr + ipred_edge_sz * 128 * 1;
+        f->ipred_edge[2] = ptr + ipred_edge_sz * 128 * 2;
+        f->ipred_edge_sz = ipred_edge_sz;
+    }
+
+    const int re_sz = f->sb128h * f->frame_hdr->tiling.cols;
+    if (re_sz != f->lf.re_sz) {
+        dav1d_free(f->lf.tx_lpf_right_edge[0]);
+        f->lf.tx_lpf_right_edge[0] = dav1d_malloc(ALLOC_LF, re_sz * 32 * 2);
+        if (!f->lf.tx_lpf_right_edge[0]) {
+            f->lf.re_sz = 0;
+            goto error;
+        }
+        f->lf.tx_lpf_right_edge[1] = f->lf.tx_lpf_right_edge[0] + re_sz * 32;
+        f->lf.re_sz = re_sz;
+    }
+
+    // init ref mvs
+    if (IS_INTER_OR_SWITCH(f->frame_hdr) || f->frame_hdr->allow_intrabc) {
+        const int ret =
+            dav1d_refmvs_init_frame(&f->rf, f->seq_hdr, f->frame_hdr,
+                                    f->refpoc, f->mvs, f->refrefpoc, f->ref_mvs,
+                                    f->c->n_tc, f->c->n_fc);
+        if (ret < 0) goto error;
+    }
+
+    // setup dequant tables
+    init_quant_tables(f->seq_hdr, f->frame_hdr, f->frame_hdr->quant.yac, f->dq);
+    if (f->frame_hdr->quant.qm)
+        for (int i = 0; i < N_RECT_TX_SIZES; i++) {
+            f->qm[i][0] = dav1d_qm_tbl[f->frame_hdr->quant.qm_y][0][i];
+            f->qm[i][1] = dav1d_qm_tbl[f->frame_hdr->quant.qm_u][1][i];
+            f->qm[i][2] = dav1d_qm_tbl[f->frame_hdr->quant.qm_v][1][i];
+        }
+    else
+        memset(f->qm, 0, sizeof(f->qm));
+
+    // setup jnt_comp weights
+    if (f->frame_hdr->switchable_comp_refs) {
+        for (int i = 0; i < 7; i++) {
+            const unsigned ref0poc = f->refp[i].p.frame_hdr->frame_offset;
+
+            for (int j = i + 1; j < 7; j++) {
+                const unsigned ref1poc = f->refp[j].p.frame_hdr->frame_offset;
+
+                const unsigned d1 =
+                    imin(abs(get_poc_diff(f->seq_hdr->order_hint_n_bits, ref0poc,
+                                          f->cur.frame_hdr->frame_offset)), 31);
+                const unsigned d0 =
+                    imin(abs(get_poc_diff(f->seq_hdr->order_hint_n_bits, ref1poc,
+                                          f->cur.frame_hdr->frame_offset)), 31);
+                const int order = d0 <= d1;
+
+                static const uint8_t quant_dist_weight[3][2] = {
+                    { 2, 3 }, { 2, 5 }, { 2, 7 }
+                };
+                static const uint8_t quant_dist_lookup_table[4][2] = {
+                    { 9, 7 }, { 11, 5 }, { 12, 4 }, { 13, 3 }
+                };
+
+                int k;
+                for (k = 0; k < 3; k++) {
+                    const int c0 = quant_dist_weight[k][order];
+                    const int c1 = quant_dist_weight[k][!order];
+                    const int d0_c0 = d0 * c0;
+                    const int d1_c1 = d1 * c1;
+                    if ((d0 > d1 && d0_c0 < d1_c1) || (d0 <= d1 && d0_c0 > d1_c1)) break;
+                }
+
+                f->jnt_weights[i][j] = quant_dist_lookup_table[k][order];
+            }
+        }
+    }
+
+    /* Init loopfilter pointers. Increasing NULL pointers is technically UB,
+     * so just point the chroma pointers in 4:0:0 to the luma plane here to
+     * avoid having additional in-loop branches in various places. We never
+     * dereference those pointers so it doesn't really matter what they
+     * point at, as long as the pointers are valid. */
+    const int has_chroma = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400;
+    f->lf.p[0] = f->cur.data[0];
+    f->lf.p[1] = f->cur.data[has_chroma ? 1 : 0];
+    f->lf.p[2] = f->cur.data[has_chroma ? 2 : 0];
+    f->lf.sr_p[0] = f->sr_cur.p.data[0];
+    f->lf.sr_p[1] = f->sr_cur.p.data[has_chroma ? 1 : 0];
+    f->lf.sr_p[2] = f->sr_cur.p.data[has_chroma ? 2 : 0];
+
+    retval = 0;
+error:
+    return retval;
+}
+
+int dav1d_decode_frame_init_cdf(Dav1dFrameContext *const f) {
+    const Dav1dContext *const c = f->c;
+    int retval = DAV1D_ERR(EINVAL);
+
+    if (f->frame_hdr->refresh_context)
+        dav1d_cdf_thread_copy(f->out_cdf.data.cdf, &f->in_cdf);
+
+    // parse individual tiles per tile group
+    int tile_row = 0, tile_col = 0;
+    f->task_thread.update_set = 0;
+    for (int i = 0; i < f->n_tile_data; i++) {
+        const uint8_t *data = f->tile[i].data.data;
+        size_t size = f->tile[i].data.sz;
+
+        for (int j = f->tile[i].start; j <= f->tile[i].end; j++) {
+            size_t tile_sz;
+            if (j == f->tile[i].end) {
+                tile_sz = size;
+            } else {
+                if (f->frame_hdr->tiling.n_bytes > size) goto error;
+                tile_sz = 0;
+                for (unsigned k = 0; k < f->frame_hdr->tiling.n_bytes; k++)
+                    tile_sz |= (unsigned)*data++ << (k * 8);
+                tile_sz++;
+                size -= f->frame_hdr->tiling.n_bytes;
+                if (tile_sz > size) goto error;
+            }
+
+            setup_tile(&f->ts[j], f, data, tile_sz, tile_row, tile_col++,
+                       c->n_fc > 1 ? f->frame_thread.tile_start_off[j] : 0);
+
+            if (tile_col == f->frame_hdr->tiling.cols) {
+                tile_col = 0;
+                tile_row++;
+            }
+            if (j == f->frame_hdr->tiling.update && f->frame_hdr->refresh_context)
+                f->task_thread.update_set = 1;
+            data += tile_sz;
+            size -= tile_sz;
+        }
+    }
+
+    if (c->n_tc > 1) {
+        const int uses_2pass = c->n_fc > 1;
+        for (int n = 0; n < f->sb128w * f->frame_hdr->tiling.rows * (1 + uses_2pass); n++)
+            reset_context(&f->a[n], IS_KEY_OR_INTRA(f->frame_hdr),
+                          uses_2pass ? 1 + (n >= f->sb128w * f->frame_hdr->tiling.rows) : 0);
+    }
+
+    retval = 0;
+error:
+    return retval;
+}
+
+int dav1d_decode_frame_main(Dav1dFrameContext *const f) {
+    const Dav1dContext *const c = f->c;
+    int retval = DAV1D_ERR(EINVAL);
+
+    assert(f->c->n_tc == 1);
+
+    Dav1dTaskContext *const t = &c->tc[f - c->fc];
+    t->f = f;
+    t->frame_thread.pass = 0;
+
+    for (int n = 0; n < f->sb128w * f->frame_hdr->tiling.rows; n++)
+        reset_context(&f->a[n], IS_KEY_OR_INTRA(f->frame_hdr), 0);
+
+    // no threading - we explicitly interleave tile/sbrow decoding
+    // and post-filtering, so that the full process runs in-line
+    for (int tile_row = 0; tile_row < f->frame_hdr->tiling.rows; tile_row++) {
+        const int sbh_end =
+            imin(f->frame_hdr->tiling.row_start_sb[tile_row + 1], f->sbh);
+        for (int sby = f->frame_hdr->tiling.row_start_sb[tile_row];
+             sby < sbh_end; sby++)
+        {
+            t->by = sby << (4 + f->seq_hdr->sb128);
+            const int by_end = (t->by + f->sb_step) >> 1;
+            if (f->frame_hdr->use_ref_frame_mvs) {
+                f->c->refmvs_dsp.load_tmvs(&f->rf, tile_row,
+                                           0, f->bw >> 1, t->by >> 1, by_end);
+            }
+            for (int tile_col = 0; tile_col < f->frame_hdr->tiling.cols; tile_col++) {
+                t->ts = &f->ts[tile_row * f->frame_hdr->tiling.cols + tile_col];
+                if (dav1d_decode_tile_sbrow(t)) goto error;
+            }
+            if (IS_INTER_OR_SWITCH(f->frame_hdr)) {
+                dav1d_refmvs_save_tmvs(&f->c->refmvs_dsp, &t->rt,
+                                       0, f->bw >> 1, t->by >> 1, by_end);
+            }
+
+            // loopfilter + cdef + restoration
+            f->bd_fn.filter_sbrow(f, sby);
+        }
+    }
+
+    retval = 0;
+error:
+    return retval;
+}
+
+void dav1d_decode_frame_exit(Dav1dFrameContext *const f, int retval) {
+    const Dav1dContext *const c = f->c;
+
+    if (f->sr_cur.p.data[0])
+        atomic_init(&f->task_thread.error, 0);
+
+    if (c->n_fc > 1 && retval && f->frame_thread.cf) {
+        memset(f->frame_thread.cf, 0,
+               (size_t)f->frame_thread.cf_sz * 128 * 128 / 2);
+    }
+    for (int i = 0; i < 7; i++) {
+        if (f->refp[i].p.frame_hdr) {
+            if (!retval && c->n_fc > 1 && c->strict_std_compliance &&
+                atomic_load(&f->refp[i].progress[1]) == FRAME_ERROR)
+            {
+                retval = DAV1D_ERR(EINVAL);
+                atomic_store(&f->task_thread.error, 1);
+                atomic_store(&f->sr_cur.progress[1], FRAME_ERROR);
+            }
+            dav1d_thread_picture_unref(&f->refp[i]);
+        }
+        dav1d_ref_dec(&f->ref_mvs_ref[i]);
+    }
+
+    dav1d_picture_unref_internal(&f->cur);
+    dav1d_thread_picture_unref(&f->sr_cur);
+    dav1d_cdf_thread_unref(&f->in_cdf);
+    if (f->frame_hdr && f->frame_hdr->refresh_context) {
+        if (f->out_cdf.progress)
+            atomic_store(f->out_cdf.progress, retval == 0 ? 1 : TILE_ERROR);
+        dav1d_cdf_thread_unref(&f->out_cdf);
+    }
+    dav1d_ref_dec(&f->cur_segmap_ref);
+    dav1d_ref_dec(&f->prev_segmap_ref);
+    dav1d_ref_dec(&f->mvs_ref);
+    dav1d_ref_dec(&f->seq_hdr_ref);
+    dav1d_ref_dec(&f->frame_hdr_ref);
+
+    for (int i = 0; i < f->n_tile_data; i++)
+        dav1d_data_unref_internal(&f->tile[i].data);
+    f->task_thread.retval = retval;
+}
+
+int dav1d_decode_frame(Dav1dFrameContext *const f) {
+    assert(f->c->n_fc == 1);
+    // if n_tc > 1 (but n_fc == 1), we could run init/exit in the task
+    // threads also. Not sure it makes a measurable difference.
+    int res = dav1d_decode_frame_init(f);
+    if (!res) res = dav1d_decode_frame_init_cdf(f);
+    // wait until all threads have completed
+    if (!res) {
+        if (f->c->n_tc > 1) {
+            res = dav1d_task_create_tile_sbrow(f, 0, 1);
+            pthread_mutex_lock(&f->task_thread.ttd->lock);
+            pthread_cond_signal(&f->task_thread.ttd->cond);
+            if (!res) {
+                while (!f->task_thread.done[0] ||
+                       atomic_load(&f->task_thread.task_counter) > 0)
+                {
+                    pthread_cond_wait(&f->task_thread.cond,
+                                      &f->task_thread.ttd->lock);
+                }
+            }
+            pthread_mutex_unlock(&f->task_thread.ttd->lock);
+            res = f->task_thread.retval;
+        } else {
+            res = dav1d_decode_frame_main(f);
+            if (!res && f->frame_hdr->refresh_context && f->task_thread.update_set) {
+                dav1d_cdf_thread_update(f->frame_hdr, f->out_cdf.data.cdf,
+                                        &f->ts[f->frame_hdr->tiling.update].cdf);
+            }
+        }
+    }
+    dav1d_decode_frame_exit(f, res);
+    res = f->task_thread.retval;
+    f->n_tile_data = 0;
+    return res;
+}
+
+static int get_upscale_x0(const int in_w, const int out_w, const int step) {
+    const int err = out_w * step - (in_w << 14);
+    const int x0 = (-((out_w - in_w) << 13) + (out_w >> 1)) / out_w + 128 - (err / 2);
+    return x0 & 0x3fff;
+}
+
+int dav1d_submit_frame(Dav1dContext *const c) {
+    Dav1dFrameContext *f;
+    int res = -1;
+
+    // wait for c->out_delayed[next] and move into c->out if visible
+    Dav1dThreadPicture *out_delayed;
+    if (c->n_fc > 1) {
+        pthread_mutex_lock(&c->task_thread.lock);
+        const unsigned next = c->frame_thread.next++;
+        if (c->frame_thread.next == c->n_fc)
+            c->frame_thread.next = 0;
+
+        f = &c->fc[next];
+        while (f->n_tile_data > 0)
+            pthread_cond_wait(&f->task_thread.cond,
+                              &c->task_thread.lock);
+        out_delayed = &c->frame_thread.out_delayed[next];
+        if (out_delayed->p.data[0] || atomic_load(&f->task_thread.error)) {
+            unsigned first = atomic_load(&c->task_thread.first);
+            if (first + 1U < c->n_fc)
+                atomic_fetch_add(&c->task_thread.first, 1U);
+            else
+                atomic_store(&c->task_thread.first, 0);
+            atomic_compare_exchange_strong(&c->task_thread.reset_task_cur,
+                                           &first, UINT_MAX);
+            if (c->task_thread.cur && c->task_thread.cur < c->n_fc)
+                c->task_thread.cur--;
+        }
+        const int error = f->task_thread.retval;
+        if (error) {
+            f->task_thread.retval = 0;
+            c->cached_error = error;
+            dav1d_data_props_copy(&c->cached_error_props, &out_delayed->p.m);
+            dav1d_thread_picture_unref(out_delayed);
+        } else if (out_delayed->p.data[0]) {
+            const unsigned progress = atomic_load_explicit(&out_delayed->progress[1],
+                                                           memory_order_relaxed);
+            if ((out_delayed->visible || c->output_invisible_frames) &&
+                progress != FRAME_ERROR)
+            {
+                dav1d_thread_picture_ref(&c->out, out_delayed);
+                c->event_flags |= dav1d_picture_get_event_flags(out_delayed);
+            }
+            dav1d_thread_picture_unref(out_delayed);
+        }
+    } else {
+        f = c->fc;
+    }
+
+    f->seq_hdr = c->seq_hdr;
+    f->seq_hdr_ref = c->seq_hdr_ref;
+    dav1d_ref_inc(f->seq_hdr_ref);
+    f->frame_hdr = c->frame_hdr;
+    f->frame_hdr_ref = c->frame_hdr_ref;
+    c->frame_hdr = NULL;
+    c->frame_hdr_ref = NULL;
+    f->dsp = &c->dsp[f->seq_hdr->hbd];
+
+    const int bpc = 8 + 2 * f->seq_hdr->hbd;
+
+    if (!f->dsp->ipred.intra_pred[DC_PRED]) {
+        Dav1dDSPContext *const dsp = &c->dsp[f->seq_hdr->hbd];
+
+        switch (bpc) {
+#define assign_bitdepth_case(bd) \
+            dav1d_cdef_dsp_init_##bd##bpc(&dsp->cdef); \
+            dav1d_intra_pred_dsp_init_##bd##bpc(&dsp->ipred); \
+            dav1d_itx_dsp_init_##bd##bpc(&dsp->itx, bpc); \
+            dav1d_loop_filter_dsp_init_##bd##bpc(&dsp->lf); \
+            dav1d_loop_restoration_dsp_init_##bd##bpc(&dsp->lr, bpc); \
+            dav1d_mc_dsp_init_##bd##bpc(&dsp->mc); \
+            dav1d_film_grain_dsp_init_##bd##bpc(&dsp->fg); \
+            break
+#if CONFIG_8BPC
+        case 8:
+            assign_bitdepth_case(8);
+#endif
+#if CONFIG_16BPC
+        case 10:
+        case 12:
+            assign_bitdepth_case(16);
+#endif
+#undef assign_bitdepth_case
+        default:
+            dav1d_log(c, "Compiled without support for %d-bit decoding\n",
+                    8 + 2 * f->seq_hdr->hbd);
+            res = DAV1D_ERR(ENOPROTOOPT);
+            goto error;
+        }
+    }
+
+#define assign_bitdepth_case(bd) \
+        f->bd_fn.recon_b_inter = dav1d_recon_b_inter_##bd##bpc; \
+        f->bd_fn.recon_b_intra = dav1d_recon_b_intra_##bd##bpc; \
+        f->bd_fn.filter_sbrow = dav1d_filter_sbrow_##bd##bpc; \
+        f->bd_fn.filter_sbrow_deblock_cols = dav1d_filter_sbrow_deblock_cols_##bd##bpc; \
+        f->bd_fn.filter_sbrow_deblock_rows = dav1d_filter_sbrow_deblock_rows_##bd##bpc; \
+        f->bd_fn.filter_sbrow_cdef = dav1d_filter_sbrow_cdef_##bd##bpc; \
+        f->bd_fn.filter_sbrow_resize = dav1d_filter_sbrow_resize_##bd##bpc; \
+        f->bd_fn.filter_sbrow_lr = dav1d_filter_sbrow_lr_##bd##bpc; \
+        f->bd_fn.backup_ipred_edge = dav1d_backup_ipred_edge_##bd##bpc; \
+        f->bd_fn.read_coef_blocks = dav1d_read_coef_blocks_##bd##bpc; \
+        f->bd_fn.copy_pal_block_y = dav1d_copy_pal_block_y_##bd##bpc; \
+        f->bd_fn.copy_pal_block_uv = dav1d_copy_pal_block_uv_##bd##bpc; \
+        f->bd_fn.read_pal_plane = dav1d_read_pal_plane_##bd##bpc; \
+        f->bd_fn.read_pal_uv = dav1d_read_pal_uv_##bd##bpc
+    if (!f->seq_hdr->hbd) {
+#if CONFIG_8BPC
+        assign_bitdepth_case(8);
+#endif
+    } else {
+#if CONFIG_16BPC
+        assign_bitdepth_case(16);
+#endif
+    }
+#undef assign_bitdepth_case
+
+    int ref_coded_width[7];
+    if (IS_INTER_OR_SWITCH(f->frame_hdr)) {
+        if (f->frame_hdr->primary_ref_frame != DAV1D_PRIMARY_REF_NONE) {
+            const int pri_ref = f->frame_hdr->refidx[f->frame_hdr->primary_ref_frame];
+            if (!c->refs[pri_ref].p.p.data[0]) {
+                res = DAV1D_ERR(EINVAL);
+                goto error;
+            }
+        }
+        for (int i = 0; i < 7; i++) {
+            const int refidx = f->frame_hdr->refidx[i];
+            if (!c->refs[refidx].p.p.data[0] ||
+                f->frame_hdr->width[0] * 2 < c->refs[refidx].p.p.p.w ||
+                f->frame_hdr->height * 2 < c->refs[refidx].p.p.p.h ||
+                f->frame_hdr->width[0] > c->refs[refidx].p.p.p.w * 16 ||
+                f->frame_hdr->height > c->refs[refidx].p.p.p.h * 16 ||
+                f->seq_hdr->layout != c->refs[refidx].p.p.p.layout ||
+                bpc != c->refs[refidx].p.p.p.bpc)
+            {
+                for (int j = 0; j < i; j++)
+                    dav1d_thread_picture_unref(&f->refp[j]);
+                res = DAV1D_ERR(EINVAL);
+                goto error;
+            }
+            dav1d_thread_picture_ref(&f->refp[i], &c->refs[refidx].p);
+            ref_coded_width[i] = c->refs[refidx].p.p.frame_hdr->width[0];
+            if (f->frame_hdr->width[0] != c->refs[refidx].p.p.p.w ||
+                f->frame_hdr->height != c->refs[refidx].p.p.p.h)
+            {
+#define scale_fac(ref_sz, this_sz) \
+    ((((ref_sz) << 14) + ((this_sz) >> 1)) / (this_sz))
+                f->svc[i][0].scale = scale_fac(c->refs[refidx].p.p.p.w,
+                                               f->frame_hdr->width[0]);
+                f->svc[i][1].scale = scale_fac(c->refs[refidx].p.p.p.h,
+                                               f->frame_hdr->height);
+                f->svc[i][0].step = (f->svc[i][0].scale + 8) >> 4;
+                f->svc[i][1].step = (f->svc[i][1].scale + 8) >> 4;
+            } else {
+                f->svc[i][0].scale = f->svc[i][1].scale = 0;
+            }
+            f->gmv_warp_allowed[i] = f->frame_hdr->gmv[i].type > DAV1D_WM_TYPE_TRANSLATION &&
+                                     !f->frame_hdr->force_integer_mv &&
+                                     !dav1d_get_shear_params(&f->frame_hdr->gmv[i]) &&
+                                     !f->svc[i][0].scale;
+        }
+    }
+
+    // setup entropy
+    if (f->frame_hdr->primary_ref_frame == DAV1D_PRIMARY_REF_NONE) {
+        dav1d_cdf_thread_init_static(&f->in_cdf, f->frame_hdr->quant.yac);
+    } else {
+        const int pri_ref = f->frame_hdr->refidx[f->frame_hdr->primary_ref_frame];
+        dav1d_cdf_thread_ref(&f->in_cdf, &c->cdf[pri_ref]);
+    }
+    if (f->frame_hdr->refresh_context) {
+        res = dav1d_cdf_thread_alloc(c, &f->out_cdf, c->n_fc > 1);
+        if (res < 0) goto error;
+    }
+
+    // FIXME qsort so tiles are in order (for frame threading)
+    if (f->n_tile_data_alloc < c->n_tile_data) {
+        dav1d_free(f->tile);
+        assert(c->n_tile_data < INT_MAX / (int)sizeof(*f->tile));
+        f->tile = dav1d_malloc(ALLOC_TILE, c->n_tile_data * sizeof(*f->tile));
+        if (!f->tile) {
+            f->n_tile_data_alloc = f->n_tile_data = 0;
+            res = DAV1D_ERR(ENOMEM);
+            goto error;
+        }
+        f->n_tile_data_alloc = c->n_tile_data;
+    }
+    memcpy(f->tile, c->tile, c->n_tile_data * sizeof(*f->tile));
+    memset(c->tile, 0, c->n_tile_data * sizeof(*c->tile));
+    f->n_tile_data = c->n_tile_data;
+    c->n_tile_data = 0;
+
+    // allocate frame
+    res = dav1d_thread_picture_alloc(c, f, bpc);
+    if (res < 0) goto error;
+
+    if (f->frame_hdr->width[0] != f->frame_hdr->width[1]) {
+        res = dav1d_picture_alloc_copy(c, &f->cur, f->frame_hdr->width[0], &f->sr_cur.p);
+        if (res < 0) goto error;
+    } else {
+        dav1d_picture_ref(&f->cur, &f->sr_cur.p);
+    }
+
+    if (f->frame_hdr->width[0] != f->frame_hdr->width[1]) {
+        f->resize_step[0] = scale_fac(f->cur.p.w, f->sr_cur.p.p.w);
+        const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int in_cw = (f->cur.p.w + ss_hor) >> ss_hor;
+        const int out_cw = (f->sr_cur.p.p.w + ss_hor) >> ss_hor;
+        f->resize_step[1] = scale_fac(in_cw, out_cw);
+#undef scale_fac
+        f->resize_start[0] = get_upscale_x0(f->cur.p.w, f->sr_cur.p.p.w, f->resize_step[0]);
+        f->resize_start[1] = get_upscale_x0(in_cw, out_cw, f->resize_step[1]);
+    }
+
+    // move f->cur into output queue
+    if (c->n_fc == 1) {
+        if (f->frame_hdr->show_frame || c->output_invisible_frames) {
+            dav1d_thread_picture_ref(&c->out, &f->sr_cur);
+            c->event_flags |= dav1d_picture_get_event_flags(&f->sr_cur);
+        }
+    } else {
+        dav1d_thread_picture_ref(out_delayed, &f->sr_cur);
+    }
+
+    f->w4 = (f->frame_hdr->width[0] + 3) >> 2;
+    f->h4 = (f->frame_hdr->height + 3) >> 2;
+    f->bw = ((f->frame_hdr->width[0] + 7) >> 3) << 1;
+    f->bh = ((f->frame_hdr->height + 7) >> 3) << 1;
+    f->sb128w = (f->bw + 31) >> 5;
+    f->sb128h = (f->bh + 31) >> 5;
+    f->sb_shift = 4 + f->seq_hdr->sb128;
+    f->sb_step = 16 << f->seq_hdr->sb128;
+    f->sbh = (f->bh + f->sb_step - 1) >> f->sb_shift;
+    f->b4_stride = (f->bw + 31) & ~31;
+    f->bitdepth_max = (1 << f->cur.p.bpc) - 1;
+    atomic_init(&f->task_thread.error, 0);
+    const int uses_2pass = c->n_fc > 1;
+    const int cols = f->frame_hdr->tiling.cols;
+    const int rows = f->frame_hdr->tiling.rows;
+    atomic_store(&f->task_thread.task_counter,
+                 (cols * rows + f->sbh) << uses_2pass);
+
+    // ref_mvs
+    if (IS_INTER_OR_SWITCH(f->frame_hdr) || f->frame_hdr->allow_intrabc) {
+        f->mvs_ref = dav1d_ref_create_using_pool(c->refmvs_pool,
+            sizeof(*f->mvs) * f->sb128h * 16 * (f->b4_stride >> 1));
+        if (!f->mvs_ref) {
+            res = DAV1D_ERR(ENOMEM);
+            goto error;
+        }
+        f->mvs = f->mvs_ref->data;
+        if (!f->frame_hdr->allow_intrabc) {
+            for (int i = 0; i < 7; i++)
+                f->refpoc[i] = f->refp[i].p.frame_hdr->frame_offset;
+        } else {
+            memset(f->refpoc, 0, sizeof(f->refpoc));
+        }
+        if (f->frame_hdr->use_ref_frame_mvs) {
+            for (int i = 0; i < 7; i++) {
+                const int refidx = f->frame_hdr->refidx[i];
+                const int ref_w = ((ref_coded_width[i] + 7) >> 3) << 1;
+                const int ref_h = ((f->refp[i].p.p.h + 7) >> 3) << 1;
+                if (c->refs[refidx].refmvs != NULL &&
+                    ref_w == f->bw && ref_h == f->bh)
+                {
+                    f->ref_mvs_ref[i] = c->refs[refidx].refmvs;
+                    dav1d_ref_inc(f->ref_mvs_ref[i]);
+                    f->ref_mvs[i] = c->refs[refidx].refmvs->data;
+                } else {
+                    f->ref_mvs[i] = NULL;
+                    f->ref_mvs_ref[i] = NULL;
+                }
+                memcpy(f->refrefpoc[i], c->refs[refidx].refpoc,
+                       sizeof(*f->refrefpoc));
+            }
+        } else {
+            memset(f->ref_mvs_ref, 0, sizeof(f->ref_mvs_ref));
+        }
+    } else {
+        f->mvs_ref = NULL;
+        memset(f->ref_mvs_ref, 0, sizeof(f->ref_mvs_ref));
+    }
+
+    // segmap
+    if (f->frame_hdr->segmentation.enabled) {
+        // By default, the previous segmentation map is not initialised.
+        f->prev_segmap_ref = NULL;
+        f->prev_segmap = NULL;
+
+        // We might need a previous frame's segmentation map. This
+        // happens if there is either no update or a temporal update.
+        if (f->frame_hdr->segmentation.temporal || !f->frame_hdr->segmentation.update_map) {
+            const int pri_ref = f->frame_hdr->primary_ref_frame;
+            assert(pri_ref != DAV1D_PRIMARY_REF_NONE);
+            const int ref_w = ((ref_coded_width[pri_ref] + 7) >> 3) << 1;
+            const int ref_h = ((f->refp[pri_ref].p.p.h + 7) >> 3) << 1;
+            if (ref_w == f->bw && ref_h == f->bh) {
+                f->prev_segmap_ref = c->refs[f->frame_hdr->refidx[pri_ref]].segmap;
+                if (f->prev_segmap_ref) {
+                    dav1d_ref_inc(f->prev_segmap_ref);
+                    f->prev_segmap = f->prev_segmap_ref->data;
+                }
+            }
+        }
+
+        if (f->frame_hdr->segmentation.update_map) {
+            // We're updating an existing map, but need somewhere to
+            // put the new values. Allocate them here (the data
+            // actually gets set elsewhere)
+            f->cur_segmap_ref = dav1d_ref_create_using_pool(c->segmap_pool,
+                sizeof(*f->cur_segmap) * f->b4_stride * 32 * f->sb128h);
+            if (!f->cur_segmap_ref) {
+                dav1d_ref_dec(&f->prev_segmap_ref);
+                res = DAV1D_ERR(ENOMEM);
+                goto error;
+            }
+            f->cur_segmap = f->cur_segmap_ref->data;
+        } else if (f->prev_segmap_ref) {
+            // We're not updating an existing map, and we have a valid
+            // reference. Use that.
+            f->cur_segmap_ref = f->prev_segmap_ref;
+            dav1d_ref_inc(f->cur_segmap_ref);
+            f->cur_segmap = f->prev_segmap_ref->data;
+        } else {
+            // We need to make a new map. Allocate one here and zero it out.
+            const size_t segmap_size = sizeof(*f->cur_segmap) * f->b4_stride * 32 * f->sb128h;
+            f->cur_segmap_ref = dav1d_ref_create_using_pool(c->segmap_pool, segmap_size);
+            if (!f->cur_segmap_ref) {
+                res = DAV1D_ERR(ENOMEM);
+                goto error;
+            }
+            f->cur_segmap = f->cur_segmap_ref->data;
+            memset(f->cur_segmap, 0, segmap_size);
+        }
+    } else {
+        f->cur_segmap = NULL;
+        f->cur_segmap_ref = NULL;
+        f->prev_segmap_ref = NULL;
+    }
+
+    // update references etc.
+    const unsigned refresh_frame_flags = f->frame_hdr->refresh_frame_flags;
+    for (int i = 0; i < 8; i++) {
+        if (refresh_frame_flags & (1 << i)) {
+            if (c->refs[i].p.p.frame_hdr)
+                dav1d_thread_picture_unref(&c->refs[i].p);
+            dav1d_thread_picture_ref(&c->refs[i].p, &f->sr_cur);
+
+            dav1d_cdf_thread_unref(&c->cdf[i]);
+            if (f->frame_hdr->refresh_context) {
+                dav1d_cdf_thread_ref(&c->cdf[i], &f->out_cdf);
+            } else {
+                dav1d_cdf_thread_ref(&c->cdf[i], &f->in_cdf);
+            }
+
+            dav1d_ref_dec(&c->refs[i].segmap);
+            c->refs[i].segmap = f->cur_segmap_ref;
+            if (f->cur_segmap_ref)
+                dav1d_ref_inc(f->cur_segmap_ref);
+            dav1d_ref_dec(&c->refs[i].refmvs);
+            if (!f->frame_hdr->allow_intrabc) {
+                c->refs[i].refmvs = f->mvs_ref;
+                if (f->mvs_ref)
+                    dav1d_ref_inc(f->mvs_ref);
+            }
+            memcpy(c->refs[i].refpoc, f->refpoc, sizeof(f->refpoc));
+        }
+    }
+
+    if (c->n_fc == 1) {
+        if ((res = dav1d_decode_frame(f)) < 0) {
+            dav1d_thread_picture_unref(&c->out);
+            for (int i = 0; i < 8; i++) {
+                if (refresh_frame_flags & (1 << i)) {
+                    if (c->refs[i].p.p.frame_hdr)
+                        dav1d_thread_picture_unref(&c->refs[i].p);
+                    dav1d_cdf_thread_unref(&c->cdf[i]);
+                    dav1d_ref_dec(&c->refs[i].segmap);
+                    dav1d_ref_dec(&c->refs[i].refmvs);
+                }
+            }
+            goto error;
+        }
+    } else {
+        dav1d_task_frame_init(f);
+        pthread_mutex_unlock(&c->task_thread.lock);
+    }
+
+    return 0;
+error:
+    atomic_init(&f->task_thread.error, 1);
+    dav1d_cdf_thread_unref(&f->in_cdf);
+    if (f->frame_hdr->refresh_context)
+        dav1d_cdf_thread_unref(&f->out_cdf);
+    for (int i = 0; i < 7; i++) {
+        if (f->refp[i].p.frame_hdr)
+            dav1d_thread_picture_unref(&f->refp[i]);
+        dav1d_ref_dec(&f->ref_mvs_ref[i]);
+    }
+    if (c->n_fc == 1)
+        dav1d_thread_picture_unref(&c->out);
+    else
+        dav1d_thread_picture_unref(out_delayed);
+    dav1d_picture_unref_internal(&f->cur);
+    dav1d_thread_picture_unref(&f->sr_cur);
+    dav1d_ref_dec(&f->mvs_ref);
+    dav1d_ref_dec(&f->seq_hdr_ref);
+    dav1d_ref_dec(&f->frame_hdr_ref);
+    dav1d_data_props_copy(&c->cached_error_props, &c->in.m);
+
+    for (int i = 0; i < f->n_tile_data; i++)
+        dav1d_data_unref_internal(&f->tile[i].data);
+    f->n_tile_data = 0;
+
+    if (c->n_fc > 1)
+        pthread_mutex_unlock(&c->task_thread.lock);
+
+    return res;
+}
diff --git a/media/libdav1d/src/src/decode.h b/media/libdav1d/src/src/decode.h
new file mode 100644
index 0000000000..1eae5850a5
--- /dev/null
+++ b/media/libdav1d/src/src/decode.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_DECODE_H
+#define DAV1D_SRC_DECODE_H
+
+#include "src/internal.h"
+
+int dav1d_submit_frame(Dav1dContext *c);
+
+#endif /* DAV1D_SRC_DECODE_H */
diff --git a/media/libdav1d/src/src/dequant_tables.c b/media/libdav1d/src/src/dequant_tables.c
new file mode 100644
index 0000000000..520d727b03
--- /dev/null
+++ b/media/libdav1d/src/src/dequant_tables.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "src/dequant_tables.h"
+
+const uint16_t dav1d_dq_tbl[3][QINDEX_RANGE][2] = {
+    {
+        {    4,    4, }, {    8,    8, }, {    8,    9, }, {    9,   10, },
+        {   10,   11, }, {   11,   12, }, {   12,   13, }, {   12,   14, },
+        {   13,   15, }, {   14,   16, }, {   15,   17, }, {   16,   18, },
+        {   17,   19, }, {   18,   20, }, {   19,   21, }, {   19,   22, },
+        {   20,   23, }, {   21,   24, }, {   22,   25, }, {   23,   26, },
+        {   24,   27, }, {   25,   28, }, {   26,   29, }, {   26,   30, },
+        {   27,   31, }, {   28,   32, }, {   29,   33, }, {   30,   34, },
+        {   31,   35, }, {   32,   36, }, {   32,   37, }, {   33,   38, },
+        {   34,   39, }, {   35,   40, }, {   36,   41, }, {   37,   42, },
+        {   38,   43, }, {   38,   44, }, {   39,   45, }, {   40,   46, },
+        {   41,   47, }, {   42,   48, }, {   43,   49, }, {   43,   50, },
+        {   44,   51, }, {   45,   52, }, {   46,   53, }, {   47,   54, },
+        {   48,   55, }, {   48,   56, }, {   49,   57, }, {   50,   58, },
+        {   51,   59, }, {   52,   60, }, {   53,   61, }, {   53,   62, },
+        {   54,   63, }, {   55,   64, }, {   56,   65, }, {   57,   66, },
+        {   57,   67, }, {   58,   68, }, {   59,   69, }, {   60,   70, },
+        {   61,   71, }, {   62,   72, }, {   62,   73, }, {   63,   74, },
+        {   64,   75, }, {   65,   76, }, {   66,   77, }, {   66,   78, },
+        {   67,   79, }, {   68,   80, }, {   69,   81, }, {   70,   82, },
+        {   70,   83, }, {   71,   84, }, {   72,   85, }, {   73,   86, },
+        {   74,   87, }, {   74,   88, }, {   75,   89, }, {   76,   90, },
+        {   77,   91, }, {   78,   92, }, {   78,   93, }, {   79,   94, },
+        {   80,   95, }, {   81,   96, }, {   81,   97, }, {   82,   98, },
+        {   83,   99, }, {   84,  100, }, {   85,  101, }, {   85,  102, },
+        {   87,  104, }, {   88,  106, }, {   90,  108, }, {   92,  110, },
+        {   93,  112, }, {   95,  114, }, {   96,  116, }, {   98,  118, },
+        {   99,  120, }, {  101,  122, }, {  102,  124, }, {  104,  126, },
+        {  105,  128, }, {  107,  130, }, {  108,  132, }, {  110,  134, },
+        {  111,  136, }, {  113,  138, }, {  114,  140, }, {  116,  142, },
+        {  117,  144, }, {  118,  146, }, {  120,  148, }, {  121,  150, },
+        {  123,  152, }, {  125,  155, }, {  127,  158, }, {  129,  161, },
+        {  131,  164, }, {  134,  167, }, {  136,  170, }, {  138,  173, },
+        {  140,  176, }, {  142,  179, }, {  144,  182, }, {  146,  185, },
+        {  148,  188, }, {  150,  191, }, {  152,  194, }, {  154,  197, },
+        {  156,  200, }, {  158,  203, }, {  161,  207, }, {  164,  211, },
+        {  166,  215, }, {  169,  219, }, {  172,  223, }, {  174,  227, },
+        {  177,  231, }, {  180,  235, }, {  182,  239, }, {  185,  243, },
+        {  187,  247, }, {  190,  251, }, {  192,  255, }, {  195,  260, },
+        {  199,  265, }, {  202,  270, }, {  205,  275, }, {  208,  280, },
+        {  211,  285, }, {  214,  290, }, {  217,  295, }, {  220,  300, },
+        {  223,  305, }, {  226,  311, }, {  230,  317, }, {  233,  323, },
+        {  237,  329, }, {  240,  335, }, {  243,  341, }, {  247,  347, },
+        {  250,  353, }, {  253,  359, }, {  257,  366, }, {  261,  373, },
+        {  265,  380, }, {  269,  387, }, {  272,  394, }, {  276,  401, },
+        {  280,  408, }, {  284,  416, }, {  288,  424, }, {  292,  432, },
+        {  296,  440, }, {  300,  448, }, {  304,  456, }, {  309,  465, },
+        {  313,  474, }, {  317,  483, }, {  322,  492, }, {  326,  501, },
+        {  330,  510, }, {  335,  520, }, {  340,  530, }, {  344,  540, },
+        {  349,  550, }, {  354,  560, }, {  359,  571, }, {  364,  582, },
+        {  369,  593, }, {  374,  604, }, {  379,  615, }, {  384,  627, },
+        {  389,  639, }, {  395,  651, }, {  400,  663, }, {  406,  676, },
+        {  411,  689, }, {  417,  702, }, {  423,  715, }, {  429,  729, },
+        {  435,  743, }, {  441,  757, }, {  447,  771, }, {  454,  786, },
+        {  461,  801, }, {  467,  816, }, {  475,  832, }, {  482,  848, },
+        {  489,  864, }, {  497,  881, }, {  505,  898, }, {  513,  915, },
+        {  522,  933, }, {  530,  951, }, {  539,  969, }, {  549,  988, },
+        {  559, 1007, }, {  569, 1026, }, {  579, 1046, }, {  590, 1066, },
+        {  602, 1087, }, {  614, 1108, }, {  626, 1129, }, {  640, 1151, },
+        {  654, 1173, }, {  668, 1196, }, {  684, 1219, }, {  700, 1243, },
+        {  717, 1267, }, {  736, 1292, }, {  755, 1317, }, {  775, 1343, },
+        {  796, 1369, }, {  819, 1396, }, {  843, 1423, }, {  869, 1451, },
+        {  896, 1479, }, {  925, 1508, }, {  955, 1537, }, {  988, 1567, },
+        { 1022, 1597, }, { 1058, 1628, }, { 1098, 1660, }, { 1139, 1692, },
+        { 1184, 1725, }, { 1232, 1759, }, { 1282, 1793, }, { 1336, 1828, },
+    }, {
+        {    4,    4, }, {    9,    9, }, {   10,   11, }, {   13,   13, },
+        {   15,   16, }, {   17,   18, }, {   20,   21, }, {   22,   24, },
+        {   25,   27, }, {   28,   30, }, {   31,   33, }, {   34,   37, },
+        {   37,   40, }, {   40,   44, }, {   43,   48, }, {   47,   51, },
+        {   50,   55, }, {   53,   59, }, {   57,   63, }, {   60,   67, },
+        {   64,   71, }, {   68,   75, }, {   71,   79, }, {   75,   83, },
+        {   78,   88, }, {   82,   92, }, {   86,   96, }, {   90,  100, },
+        {   93,  105, }, {   97,  109, }, {  101,  114, }, {  105,  118, },
+        {  109,  122, }, {  113,  127, }, {  116,  131, }, {  120,  136, },
+        {  124,  140, }, {  128,  145, }, {  132,  149, }, {  136,  154, },
+        {  140,  158, }, {  143,  163, }, {  147,  168, }, {  151,  172, },
+        {  155,  177, }, {  159,  181, }, {  163,  186, }, {  166,  190, },
+        {  170,  195, }, {  174,  199, }, {  178,  204, }, {  182,  208, },
+        {  185,  213, }, {  189,  217, }, {  193,  222, }, {  197,  226, },
+        {  200,  231, }, {  204,  235, }, {  208,  240, }, {  212,  244, },
+        {  215,  249, }, {  219,  253, }, {  223,  258, }, {  226,  262, },
+        {  230,  267, }, {  233,  271, }, {  237,  275, }, {  241,  280, },
+        {  244,  284, }, {  248,  289, }, {  251,  293, }, {  255,  297, },
+        {  259,  302, }, {  262,  306, }, {  266,  311, }, {  269,  315, },
+        {  273,  319, }, {  276,  324, }, {  280,  328, }, {  283,  332, },
+        {  287,  337, }, {  290,  341, }, {  293,  345, }, {  297,  349, },
+        {  300,  354, }, {  304,  358, }, {  307,  362, }, {  310,  367, },
+        {  314,  371, }, {  317,  375, }, {  321,  379, }, {  324,  384, },
+        {  327,  388, }, {  331,  392, }, {  334,  396, }, {  337,  401, },
+        {  343,  409, }, {  350,  417, }, {  356,  425, }, {  362,  433, },
+        {  369,  441, }, {  375,  449, }, {  381,  458, }, {  387,  466, },
+        {  394,  474, }, {  400,  482, }, {  406,  490, }, {  412,  498, },
+        {  418,  506, }, {  424,  514, }, {  430,  523, }, {  436,  531, },
+        {  442,  539, }, {  448,  547, }, {  454,  555, }, {  460,  563, },
+        {  466,  571, }, {  472,  579, }, {  478,  588, }, {  484,  596, },
+        {  490,  604, }, {  499,  616, }, {  507,  628, }, {  516,  640, },
+        {  525,  652, }, {  533,  664, }, {  542,  676, }, {  550,  688, },
+        {  559,  700, }, {  567,  713, }, {  576,  725, }, {  584,  737, },
+        {  592,  749, }, {  601,  761, }, {  609,  773, }, {  617,  785, },
+        {  625,  797, }, {  634,  809, }, {  644,  825, }, {  655,  841, },
+        {  666,  857, }, {  676,  873, }, {  687,  889, }, {  698,  905, },
+        {  708,  922, }, {  718,  938, }, {  729,  954, }, {  739,  970, },
+        {  749,  986, }, {  759, 1002, }, {  770, 1018, }, {  782, 1038, },
+        {  795, 1058, }, {  807, 1078, }, {  819, 1098, }, {  831, 1118, },
+        {  844, 1138, }, {  856, 1158, }, {  868, 1178, }, {  880, 1198, },
+        {  891, 1218, }, {  906, 1242, }, {  920, 1266, }, {  933, 1290, },
+        {  947, 1314, }, {  961, 1338, }, {  975, 1362, }, {  988, 1386, },
+        { 1001, 1411, }, { 1015, 1435, }, { 1030, 1463, }, { 1045, 1491, },
+        { 1061, 1519, }, { 1076, 1547, }, { 1090, 1575, }, { 1105, 1603, },
+        { 1120, 1631, }, { 1137, 1663, }, { 1153, 1695, }, { 1170, 1727, },
+        { 1186, 1759, }, { 1202, 1791, }, { 1218, 1823, }, { 1236, 1859, },
+        { 1253, 1895, }, { 1271, 1931, }, { 1288, 1967, }, { 1306, 2003, },
+        { 1323, 2039, }, { 1342, 2079, }, { 1361, 2119, }, { 1379, 2159, },
+        { 1398, 2199, }, { 1416, 2239, }, { 1436, 2283, }, { 1456, 2327, },
+        { 1476, 2371, }, { 1496, 2415, }, { 1516, 2459, }, { 1537, 2507, },
+        { 1559, 2555, }, { 1580, 2603, }, { 1601, 2651, }, { 1624, 2703, },
+        { 1647, 2755, }, { 1670, 2807, }, { 1692, 2859, }, { 1717, 2915, },
+        { 1741, 2971, }, { 1766, 3027, }, { 1791, 3083, }, { 1817, 3143, },
+        { 1844, 3203, }, { 1871, 3263, }, { 1900, 3327, }, { 1929, 3391, },
+        { 1958, 3455, }, { 1990, 3523, }, { 2021, 3591, }, { 2054, 3659, },
+        { 2088, 3731, }, { 2123, 3803, }, { 2159, 3876, }, { 2197, 3952, },
+        { 2236, 4028, }, { 2276, 4104, }, { 2319, 4184, }, { 2363, 4264, },
+        { 2410, 4348, }, { 2458, 4432, }, { 2508, 4516, }, { 2561, 4604, },
+        { 2616, 4692, }, { 2675, 4784, }, { 2737, 4876, }, { 2802, 4972, },
+        { 2871, 5068, }, { 2944, 5168, }, { 3020, 5268, }, { 3102, 5372, },
+        { 3188, 5476, }, { 3280, 5584, }, { 3375, 5692, }, { 3478, 5804, },
+        { 3586, 5916, }, { 3702, 6032, }, { 3823, 6148, }, { 3953, 6268, },
+        { 4089, 6388, }, { 4236, 6512, }, { 4394, 6640, }, { 4559, 6768, },
+        { 4737, 6900, }, { 4929, 7036, }, { 5130, 7172, }, { 5347, 7312, },
+    }, {
+        {     4,     4 }, {    12,    13 }, {    18,    19 }, {    25,    27 },
+        {    33,    35 }, {    41,    44 }, {    50,    54 }, {    60,    64 },
+        {    70,    75 }, {    80,    87 }, {    91,    99 }, {   103,   112 },
+        {   115,   126 }, {   127,   139 }, {   140,   154 }, {   153,   168 },
+        {   166,   183 }, {   180,   199 }, {   194,   214 }, {   208,   230 },
+        {   222,   247 }, {   237,   263 }, {   251,   280 }, {   266,   297 },
+        {   281,   314 }, {   296,   331 }, {   312,   349 }, {   327,   366 },
+        {   343,   384 }, {   358,   402 }, {   374,   420 }, {   390,   438 },
+        {   405,   456 }, {   421,   475 }, {   437,   493 }, {   453,   511 },
+        {   469,   530 }, {   484,   548 }, {   500,   567 }, {   516,   586 },
+        {   532,   604 }, {   548,   623 }, {   564,   642 }, {   580,   660 },
+        {   596,   679 }, {   611,   698 }, {   627,   716 }, {   643,   735 },
+        {   659,   753 }, {   674,   772 }, {   690,   791 }, {   706,   809 },
+        {   721,   828 }, {   737,   846 }, {   752,   865 }, {   768,   884 },
+        {   783,   902 }, {   798,   920 }, {   814,   939 }, {   829,   957 },
+        {   844,   976 }, {   859,   994 }, {   874,  1012 }, {   889,  1030 },
+        {   904,  1049 }, {   919,  1067 }, {   934,  1085 }, {   949,  1103 },
+        {   964,  1121 }, {   978,  1139 }, {   993,  1157 }, {  1008,  1175 },
+        {  1022,  1193 }, {  1037,  1211 }, {  1051,  1229 }, {  1065,  1246 },
+        {  1080,  1264 }, {  1094,  1282 }, {  1108,  1299 }, {  1122,  1317 },
+        {  1136,  1335 }, {  1151,  1352 }, {  1165,  1370 }, {  1179,  1387 },
+        {  1192,  1405 }, {  1206,  1422 }, {  1220,  1440 }, {  1234,  1457 },
+        {  1248,  1474 }, {  1261,  1491 }, {  1275,  1509 }, {  1288,  1526 },
+        {  1302,  1543 }, {  1315,  1560 }, {  1329,  1577 }, {  1342,  1595 },
+        {  1368,  1627 }, {  1393,  1660 }, {  1419,  1693 }, {  1444,  1725 },
+        {  1469,  1758 }, {  1494,  1791 }, {  1519,  1824 }, {  1544,  1856 },
+        {  1569,  1889 }, {  1594,  1922 }, {  1618,  1954 }, {  1643,  1987 },
+        {  1668,  2020 }, {  1692,  2052 }, {  1717,  2085 }, {  1741,  2118 },
+        {  1765,  2150 }, {  1789,  2183 }, {  1814,  2216 }, {  1838,  2248 },
+        {  1862,  2281 }, {  1885,  2313 }, {  1909,  2346 }, {  1933,  2378 },
+        {  1957,  2411 }, {  1992,  2459 }, {  2027,  2508 }, {  2061,  2556 },
+        {  2096,  2605 }, {  2130,  2653 }, {  2165,  2701 }, {  2199,  2750 },
+        {  2233,  2798 }, {  2267,  2847 }, {  2300,  2895 }, {  2334,  2943 },
+        {  2367,  2992 }, {  2400,  3040 }, {  2434,  3088 }, {  2467,  3137 },
+        {  2499,  3185 }, {  2532,  3234 }, {  2575,  3298 }, {  2618,  3362 },
+        {  2661,  3426 }, {  2704,  3491 }, {  2746,  3555 }, {  2788,  3619 },
+        {  2830,  3684 }, {  2872,  3748 }, {  2913,  3812 }, {  2954,  3876 },
+        {  2995,  3941 }, {  3036,  4005 }, {  3076,  4069 }, {  3127,  4149 },
+        {  3177,  4230 }, {  3226,  4310 }, {  3275,  4390 }, {  3324,  4470 },
+        {  3373,  4550 }, {  3421,  4631 }, {  3469,  4711 }, {  3517,  4791 },
+        {  3565,  4871 }, {  3621,  4967 }, {  3677,  5064 }, {  3733,  5160 },
+        {  3788,  5256 }, {  3843,  5352 }, {  3897,  5448 }, {  3951,  5544 },
+        {  4005,  5641 }, {  4058,  5737 }, {  4119,  5849 }, {  4181,  5961 },
+        {  4241,  6073 }, {  4301,  6185 }, {  4361,  6297 }, {  4420,  6410 },
+        {  4479,  6522 }, {  4546,  6650 }, {  4612,  6778 }, {  4677,  6906 },
+        {  4742,  7034 }, {  4807,  7162 }, {  4871,  7290 }, {  4942,  7435 },
+        {  5013,  7579 }, {  5083,  7723 }, {  5153,  7867 }, {  5222,  8011 },
+        {  5291,  8155 }, {  5367,  8315 }, {  5442,  8475 }, {  5517,  8635 },
+        {  5591,  8795 }, {  5665,  8956 }, {  5745,  9132 }, {  5825,  9308 },
+        {  5905,  9484 }, {  5984,  9660 }, {  6063,  9836 }, {  6149, 10028 },
+        {  6234, 10220 }, {  6319, 10412 }, {  6404, 10604 }, {  6495, 10812 },
+        {  6587, 11020 }, {  6678, 11228 }, {  6769, 11437 }, {  6867, 11661 },
+        {  6966, 11885 }, {  7064, 12109 }, {  7163, 12333 }, {  7269, 12573 },
+        {  7376, 12813 }, {  7483, 13053 }, {  7599, 13309 }, {  7715, 13565 },
+        {  7832, 13821 }, {  7958, 14093 }, {  8085, 14365 }, {  8214, 14637 },
+        {  8352, 14925 }, {  8492, 15213 }, {  8635, 15502 }, {  8788, 15806 },
+        {  8945, 16110 }, {  9104, 16414 }, {  9275, 16734 }, {  9450, 17054 },
+        {  9639, 17390 }, {  9832, 17726 }, { 10031, 18062 }, { 10245, 18414 },
+        { 10465, 18766 }, { 10702, 19134 }, { 10946, 19502 }, { 11210, 19886 },
+        { 11482, 20270 }, { 11776, 20670 }, { 12081, 21070 }, { 12409, 21486 },
+        { 12750, 21902 }, { 13118, 22334 }, { 13501, 22766 }, { 13913, 23214 },
+        { 14343, 23662 }, { 14807, 24126 }, { 15290, 24590 }, { 15812, 25070 },
+        { 16356, 25551 }, { 16943, 26047 }, { 17575, 26559 }, { 18237, 27071 },
+        { 18949, 27599 }, { 19718, 28143 }, { 20521, 28687 }, { 21387, 29247 },
+    }
+};
diff --git a/media/libdav1d/src/src/dequant_tables.h b/media/libdav1d/src/src/dequant_tables.h
new file mode 100644
index 0000000000..17763377bc
--- /dev/null
+++ b/media/libdav1d/src/src/dequant_tables.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_DEQUANT_TABLES_H
+#define DAV1D_SRC_DEQUANT_TABLES_H
+
+#include 
+
+#include "src/levels.h"
+
+EXTERN const uint16_t dav1d_dq_tbl[3][QINDEX_RANGE][2];
+
+#endif /* DAV1D_SRC_DEQUANT_TABLES_H */
diff --git a/media/libdav1d/src/src/env.h b/media/libdav1d/src/src/env.h
new file mode 100644
index 0000000000..7c22f8240d
--- /dev/null
+++ b/media/libdav1d/src/src/env.h
@@ -0,0 +1,520 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_ENV_H
+#define DAV1D_SRC_ENV_H
+
+#include 
+#include 
+#include 
+
+#include "src/levels.h"
+#include "src/refmvs.h"
+#include "src/tables.h"
+
+typedef struct BlockContext {
+    uint8_t ALIGN(mode[32], 8);
+    uint8_t ALIGN(lcoef[32], 8);
+    uint8_t ALIGN(ccoef[2][32], 8);
+    uint8_t ALIGN(seg_pred[32], 8);
+    uint8_t ALIGN(skip[32], 8);
+    uint8_t ALIGN(skip_mode[32], 8);
+    uint8_t ALIGN(intra[32], 8);
+    uint8_t ALIGN(comp_type[32], 8);
+    int8_t ALIGN(ref[2][32], 8); // -1 means intra
+    uint8_t ALIGN(filter[2][32], 8); // 3 means unset
+    int8_t ALIGN(tx_intra[32], 8);
+    int8_t ALIGN(tx[32], 8);
+    uint8_t ALIGN(tx_lpf_y[32], 8);
+    uint8_t ALIGN(tx_lpf_uv[32], 8);
+    uint8_t ALIGN(partition[16], 8);
+    uint8_t ALIGN(uvmode[32], 8);
+    uint8_t ALIGN(pal_sz[32], 8);
+} BlockContext;
+
+static inline int get_intra_ctx(const BlockContext *const a,
+                                const BlockContext *const l,
+                                const int yb4, const int xb4,
+                                const int have_top, const int have_left)
+{
+    if (have_left) {
+        if (have_top) {
+            const int ctx = l->intra[yb4] + a->intra[xb4];
+            return ctx + (ctx == 2);
+        } else
+            return l->intra[yb4] * 2;
+    } else {
+        return have_top ? a->intra[xb4] * 2 : 0;
+    }
+}
+
+static inline int get_tx_ctx(const BlockContext *const a,
+                             const BlockContext *const l,
+                             const TxfmInfo *const max_tx,
+                             const int yb4, const int xb4)
+{
+    return (l->tx_intra[yb4] >= max_tx->lh) + (a->tx_intra[xb4] >= max_tx->lw);
+}
+
+static inline int get_partition_ctx(const BlockContext *const a,
+                                    const BlockContext *const l,
+                                    const enum BlockLevel bl,
+                                    const int yb8, const int xb8)
+{
+    return ((a->partition[xb8] >> (4 - bl)) & 1) +
+          (((l->partition[yb8] >> (4 - bl)) & 1) << 1);
+}
+
+static inline unsigned gather_left_partition_prob(const uint16_t *const in,
+                                                  const enum BlockLevel bl)
+{
+    unsigned out = in[PARTITION_H - 1] - in[PARTITION_H];
+    // Exploit the fact that cdfs for PARTITION_SPLIT, PARTITION_T_TOP_SPLIT,
+    // PARTITION_T_BOTTOM_SPLIT and PARTITION_T_LEFT_SPLIT are neighbors.
+    out += in[PARTITION_SPLIT - 1] - in[PARTITION_T_LEFT_SPLIT];
+    if (bl != BL_128X128)
+        out += in[PARTITION_H4 - 1] - in[PARTITION_H4];
+    return out;
+}
+
+static inline unsigned gather_top_partition_prob(const uint16_t *const in,
+                                                 const enum BlockLevel bl)
+{
+    // Exploit the fact that cdfs for PARTITION_V, PARTITION_SPLIT and
+    // PARTITION_T_TOP_SPLIT are neighbors.
+    unsigned out = in[PARTITION_V - 1] - in[PARTITION_T_TOP_SPLIT];
+    // Exploit the facts that cdfs for PARTITION_T_LEFT_SPLIT and
+    // PARTITION_T_RIGHT_SPLIT are neighbors, the probability for
+    // PARTITION_V4 is always zero, and the probability for
+    // PARTITION_T_RIGHT_SPLIT is zero in 128x128 blocks.
+    out += in[PARTITION_T_LEFT_SPLIT - 1];
+    if (bl != BL_128X128)
+        out += in[PARTITION_V4 - 1] - in[PARTITION_T_RIGHT_SPLIT];
+    return out;
+}
+
+static inline enum TxfmType get_uv_inter_txtp(const TxfmInfo *const uvt_dim,
+                                              const enum TxfmType ytxtp)
+{
+    if (uvt_dim->max == TX_32X32)
+        return ytxtp == IDTX ? IDTX : DCT_DCT;
+    if (uvt_dim->min == TX_16X16 &&
+        ((1 << ytxtp) & ((1 << H_FLIPADST) | (1 << V_FLIPADST) |
+                         (1 << H_ADST) | (1 << V_ADST))))
+    {
+        return DCT_DCT;
+    }
+
+    return ytxtp;
+}
+
+static inline int get_filter_ctx(const BlockContext *const a,
+                                 const BlockContext *const l,
+                                 const int comp, const int dir, const int ref,
+                                 const int yb4, const int xb4)
+{
+    const int a_filter = (a->ref[0][xb4] == ref || a->ref[1][xb4] == ref) ?
+                         a->filter[dir][xb4] : DAV1D_N_SWITCHABLE_FILTERS;
+    const int l_filter = (l->ref[0][yb4] == ref || l->ref[1][yb4] == ref) ?
+                         l->filter[dir][yb4] : DAV1D_N_SWITCHABLE_FILTERS;
+
+    if (a_filter == l_filter) {
+        return comp * 4 + a_filter;
+    } else if (a_filter == DAV1D_N_SWITCHABLE_FILTERS) {
+        return comp * 4 + l_filter;
+    } else if (l_filter == DAV1D_N_SWITCHABLE_FILTERS) {
+        return comp * 4 + a_filter;
+    } else {
+        return comp * 4 + DAV1D_N_SWITCHABLE_FILTERS;
+    }
+}
+
+static inline int get_comp_ctx(const BlockContext *const a,
+                               const BlockContext *const l,
+                               const int yb4, const int xb4,
+                               const int have_top, const int have_left)
+{
+    if (have_top) {
+        if (have_left) {
+            if (a->comp_type[xb4]) {
+                if (l->comp_type[yb4]) {
+                    return 4;
+                } else {
+                    // 4U means intra (-1) or bwd (>= 4)
+                    return 2 + ((unsigned)l->ref[0][yb4] >= 4U);
+                }
+            } else if (l->comp_type[yb4]) {
+                // 4U means intra (-1) or bwd (>= 4)
+                return 2 + ((unsigned)a->ref[0][xb4] >= 4U);
+            } else {
+                return (l->ref[0][yb4] >= 4) ^ (a->ref[0][xb4] >= 4);
+            }
+        } else {
+            return a->comp_type[xb4] ? 3 : a->ref[0][xb4] >= 4;
+        }
+    } else if (have_left) {
+        return l->comp_type[yb4] ? 3 : l->ref[0][yb4] >= 4;
+    } else {
+        return 1;
+    }
+}
+
+static inline int get_comp_dir_ctx(const BlockContext *const a,
+                                   const BlockContext *const l,
+                                   const int yb4, const int xb4,
+                                   const int have_top, const int have_left)
+{
+#define has_uni_comp(edge, off) \
+    ((edge->ref[0][off] < 4) == (edge->ref[1][off] < 4))
+
+    if (have_top && have_left) {
+        const int a_intra = a->intra[xb4], l_intra = l->intra[yb4];
+
+        if (a_intra && l_intra) return 2;
+        if (a_intra || l_intra) {
+            const BlockContext *const edge = a_intra ? l : a;
+            const int off = a_intra ? yb4 : xb4;
+
+            if (edge->comp_type[off] == COMP_INTER_NONE) return 2;
+            return 1 + 2 * has_uni_comp(edge, off);
+        }
+
+        const int a_comp = a->comp_type[xb4] != COMP_INTER_NONE;
+        const int l_comp = l->comp_type[yb4] != COMP_INTER_NONE;
+        const int a_ref0 = a->ref[0][xb4], l_ref0 = l->ref[0][yb4];
+
+        if (!a_comp && !l_comp) {
+            return 1 + 2 * ((a_ref0 >= 4) == (l_ref0 >= 4));
+        } else if (!a_comp || !l_comp) {
+            const BlockContext *const edge = a_comp ? a : l;
+            const int off = a_comp ? xb4 : yb4;
+
+            if (!has_uni_comp(edge, off)) return 1;
+            return 3 + ((a_ref0 >= 4) == (l_ref0 >= 4));
+        } else {
+            const int a_uni = has_uni_comp(a, xb4), l_uni = has_uni_comp(l, yb4);
+
+            if (!a_uni && !l_uni) return 0;
+            if (!a_uni || !l_uni) return 2;
+            return 3 + ((a_ref0 == 4) == (l_ref0 == 4));
+        }
+    } else if (have_top || have_left) {
+        const BlockContext *const edge = have_left ? l : a;
+        const int off = have_left ? yb4 : xb4;
+
+        if (edge->intra[off]) return 2;
+        if (edge->comp_type[off] == COMP_INTER_NONE) return 2;
+        return 4 * has_uni_comp(edge, off);
+    } else {
+        return 2;
+    }
+}
+
+static inline int get_poc_diff(const int order_hint_n_bits,
+                               const int poc0, const int poc1)
+{
+    if (!order_hint_n_bits) return 0;
+    const int mask = 1 << (order_hint_n_bits - 1);
+    const int diff = poc0 - poc1;
+    return (diff & (mask - 1)) - (diff & mask);
+}
+
+static inline int get_jnt_comp_ctx(const int order_hint_n_bits, const int poc,
+                                   const int ref0poc, const int ref1poc,
+                                   const BlockContext *const a,
+                                   const BlockContext *const l,
+                                   const int yb4, const int xb4)
+{
+    const int d0 = abs(get_poc_diff(order_hint_n_bits, ref0poc, poc));
+    const int d1 = abs(get_poc_diff(order_hint_n_bits, poc, ref1poc));
+    const int offset = d0 == d1;
+    const int a_ctx = a->comp_type[xb4] >= COMP_INTER_AVG ||
+                      a->ref[0][xb4] == 6;
+    const int l_ctx = l->comp_type[yb4] >= COMP_INTER_AVG ||
+                      l->ref[0][yb4] == 6;
+
+    return 3 * offset + a_ctx + l_ctx;
+}
+
+static inline int get_mask_comp_ctx(const BlockContext *const a,
+                                    const BlockContext *const l,
+                                    const int yb4, const int xb4)
+{
+    const int a_ctx = a->comp_type[xb4] >= COMP_INTER_SEG ? 1 :
+                      a->ref[0][xb4] == 6 ? 3 : 0;
+    const int l_ctx = l->comp_type[yb4] >= COMP_INTER_SEG ? 1 :
+                      l->ref[0][yb4] == 6 ? 3 : 0;
+
+    return imin(a_ctx + l_ctx, 5);
+}
+
+#define av1_get_ref_2_ctx av1_get_bwd_ref_ctx
+#define av1_get_ref_3_ctx av1_get_fwd_ref_ctx
+#define av1_get_ref_4_ctx av1_get_fwd_ref_1_ctx
+#define av1_get_ref_5_ctx av1_get_fwd_ref_2_ctx
+#define av1_get_ref_6_ctx av1_get_bwd_ref_1_ctx
+#define av1_get_uni_p_ctx av1_get_ref_ctx
+#define av1_get_uni_p2_ctx av1_get_fwd_ref_2_ctx
+
+static inline int av1_get_ref_ctx(const BlockContext *const a,
+                                  const BlockContext *const l,
+                                  const int yb4, const int xb4,
+                                  int have_top, int have_left)
+{
+    int cnt[2] = { 0 };
+
+    if (have_top && !a->intra[xb4]) {
+        cnt[a->ref[0][xb4] >= 4]++;
+        if (a->comp_type[xb4]) cnt[a->ref[1][xb4] >= 4]++;
+    }
+
+    if (have_left && !l->intra[yb4]) {
+        cnt[l->ref[0][yb4] >= 4]++;
+        if (l->comp_type[yb4]) cnt[l->ref[1][yb4] >= 4]++;
+    }
+
+    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
+}
+
+static inline int av1_get_fwd_ref_ctx(const BlockContext *const a,
+                                      const BlockContext *const l,
+                                      const int yb4, const int xb4,
+                                      const int have_top, const int have_left)
+{
+    int cnt[4] = { 0 };
+
+    if (have_top && !a->intra[xb4]) {
+        if (a->ref[0][xb4] < 4) cnt[a->ref[0][xb4]]++;
+        if (a->comp_type[xb4] && a->ref[1][xb4] < 4) cnt[a->ref[1][xb4]]++;
+    }
+
+    if (have_left && !l->intra[yb4]) {
+        if (l->ref[0][yb4] < 4) cnt[l->ref[0][yb4]]++;
+        if (l->comp_type[yb4] && l->ref[1][yb4] < 4) cnt[l->ref[1][yb4]]++;
+    }
+
+    cnt[0] += cnt[1];
+    cnt[2] += cnt[3];
+
+    return cnt[0] == cnt[2] ? 1 : cnt[0] < cnt[2] ? 0 : 2;
+}
+
+static inline int av1_get_fwd_ref_1_ctx(const BlockContext *const a,
+                                        const BlockContext *const l,
+                                        const int yb4, const int xb4,
+                                        const int have_top, const int have_left)
+{
+    int cnt[2] = { 0 };
+
+    if (have_top && !a->intra[xb4]) {
+        if (a->ref[0][xb4] < 2) cnt[a->ref[0][xb4]]++;
+        if (a->comp_type[xb4] && a->ref[1][xb4] < 2) cnt[a->ref[1][xb4]]++;
+    }
+
+    if (have_left && !l->intra[yb4]) {
+        if (l->ref[0][yb4] < 2) cnt[l->ref[0][yb4]]++;
+        if (l->comp_type[yb4] && l->ref[1][yb4] < 2) cnt[l->ref[1][yb4]]++;
+    }
+
+    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
+}
+
+static inline int av1_get_fwd_ref_2_ctx(const BlockContext *const a,
+                                        const BlockContext *const l,
+                                        const int yb4, const int xb4,
+                                        const int have_top, const int have_left)
+{
+    int cnt[2] = { 0 };
+
+    if (have_top && !a->intra[xb4]) {
+        if ((a->ref[0][xb4] ^ 2U) < 2) cnt[a->ref[0][xb4] - 2]++;
+        if (a->comp_type[xb4] && (a->ref[1][xb4] ^ 2U) < 2) cnt[a->ref[1][xb4] - 2]++;
+    }
+
+    if (have_left && !l->intra[yb4]) {
+        if ((l->ref[0][yb4] ^ 2U) < 2) cnt[l->ref[0][yb4] - 2]++;
+        if (l->comp_type[yb4] && (l->ref[1][yb4] ^ 2U) < 2) cnt[l->ref[1][yb4] - 2]++;
+    }
+
+    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
+}
+
+static inline int av1_get_bwd_ref_ctx(const BlockContext *const a,
+                                      const BlockContext *const l,
+                                      const int yb4, const int xb4,
+                                      const int have_top, const int have_left)
+{
+    int cnt[3] = { 0 };
+
+    if (have_top && !a->intra[xb4]) {
+        if (a->ref[0][xb4] >= 4) cnt[a->ref[0][xb4] - 4]++;
+        if (a->comp_type[xb4] && a->ref[1][xb4] >= 4) cnt[a->ref[1][xb4] - 4]++;
+    }
+
+    if (have_left && !l->intra[yb4]) {
+        if (l->ref[0][yb4] >= 4) cnt[l->ref[0][yb4] - 4]++;
+        if (l->comp_type[yb4] && l->ref[1][yb4] >= 4) cnt[l->ref[1][yb4] - 4]++;
+    }
+
+    cnt[1] += cnt[0];
+
+    return cnt[2] == cnt[1] ? 1 : cnt[1] < cnt[2] ? 0 : 2;
+}
+
+static inline int av1_get_bwd_ref_1_ctx(const BlockContext *const a,
+                                        const BlockContext *const l,
+                                        const int yb4, const int xb4,
+                                        const int have_top, const int have_left)
+{
+    int cnt[3] = { 0 };
+
+    if (have_top && !a->intra[xb4]) {
+        if (a->ref[0][xb4] >= 4) cnt[a->ref[0][xb4] - 4]++;
+        if (a->comp_type[xb4] && a->ref[1][xb4] >= 4) cnt[a->ref[1][xb4] - 4]++;
+    }
+
+    if (have_left && !l->intra[yb4]) {
+        if (l->ref[0][yb4] >= 4) cnt[l->ref[0][yb4] - 4]++;
+        if (l->comp_type[yb4] && l->ref[1][yb4] >= 4) cnt[l->ref[1][yb4] - 4]++;
+    }
+
+    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
+}
+
+static inline int av1_get_uni_p1_ctx(const BlockContext *const a,
+                                     const BlockContext *const l,
+                                     const int yb4, const int xb4,
+                                     const int have_top, const int have_left)
+{
+    int cnt[3] = { 0 };
+
+    if (have_top && !a->intra[xb4]) {
+        if (a->ref[0][xb4] - 1U < 3) cnt[a->ref[0][xb4] - 1]++;
+        if (a->comp_type[xb4] && a->ref[1][xb4] - 1U < 3) cnt[a->ref[1][xb4] - 1]++;
+    }
+
+    if (have_left && !l->intra[yb4]) {
+        if (l->ref[0][yb4] - 1U < 3) cnt[l->ref[0][yb4] - 1]++;
+        if (l->comp_type[yb4] && l->ref[1][yb4] - 1U < 3) cnt[l->ref[1][yb4] - 1]++;
+    }
+
+    cnt[1] += cnt[2];
+
+    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
+}
+
+static inline int get_drl_context(const refmvs_candidate *const ref_mv_stack,
+                                  const int ref_idx)
+{
+    if (ref_mv_stack[ref_idx].weight >= 640)
+        return ref_mv_stack[ref_idx + 1].weight < 640;
+
+    return ref_mv_stack[ref_idx + 1].weight < 640 ? 2 : 0;
+}
+
+static inline unsigned get_cur_frame_segid(const int by, const int bx,
+                                           const int have_top,
+                                           const int have_left,
+                                           int *const seg_ctx,
+                                           const uint8_t *cur_seg_map,
+                                           const ptrdiff_t stride)
+{
+    cur_seg_map += bx + by * stride;
+    if (have_left && have_top) {
+        const int l = cur_seg_map[-1];
+        const int a = cur_seg_map[-stride];
+        const int al = cur_seg_map[-(stride + 1)];
+
+        if (l == a && al == l) *seg_ctx = 2;
+        else if (l == a || al == l || a == al) *seg_ctx = 1;
+        else *seg_ctx = 0;
+        return a == al ? a : l;
+    } else {
+        *seg_ctx = 0;
+        return have_left ? cur_seg_map[-1] : have_top ? cur_seg_map[-stride] : 0;
+    }
+}
+
+static inline void fix_int_mv_precision(mv *const mv) {
+    mv->x = (mv->x - (mv->x >> 15) + 3) & ~7U;
+    mv->y = (mv->y - (mv->y >> 15) + 3) & ~7U;
+}
+
+static inline void fix_mv_precision(const Dav1dFrameHeader *const hdr,
+                                    mv *const mv)
+{
+    if (hdr->force_integer_mv) {
+        fix_int_mv_precision(mv);
+    } else if (!hdr->hp) {
+        mv->x = (mv->x - (mv->x >> 15)) & ~1U;
+        mv->y = (mv->y - (mv->y >> 15)) & ~1U;
+    }
+}
+
+static inline mv get_gmv_2d(const Dav1dWarpedMotionParams *const gmv,
+                            const int bx4, const int by4,
+                            const int bw4, const int bh4,
+                            const Dav1dFrameHeader *const hdr)
+{
+    switch (gmv->type) {
+    case DAV1D_WM_TYPE_ROT_ZOOM:
+        assert(gmv->matrix[5] ==  gmv->matrix[2]);
+        assert(gmv->matrix[4] == -gmv->matrix[3]);
+        // fall-through
+    default:
+    case DAV1D_WM_TYPE_AFFINE: {
+        const int x = bx4 * 4 + bw4 * 2 - 1;
+        const int y = by4 * 4 + bh4 * 2 - 1;
+        const int xc = (gmv->matrix[2] - (1 << 16)) * x +
+                       gmv->matrix[3] * y + gmv->matrix[0];
+        const int yc = (gmv->matrix[5] - (1 << 16)) * y +
+                       gmv->matrix[4] * x + gmv->matrix[1];
+        const int shift = 16 - (3 - !hdr->hp);
+        const int round = (1 << shift) >> 1;
+        mv res = (mv) {
+            .y = apply_sign(((abs(yc) + round) >> shift) << !hdr->hp, yc),
+            .x = apply_sign(((abs(xc) + round) >> shift) << !hdr->hp, xc),
+        };
+        if (hdr->force_integer_mv)
+            fix_int_mv_precision(&res);
+        return res;
+    }
+    case DAV1D_WM_TYPE_TRANSLATION: {
+        mv res = (mv) {
+            .y = gmv->matrix[0] >> 13,
+            .x = gmv->matrix[1] >> 13,
+        };
+        if (hdr->force_integer_mv)
+            fix_int_mv_precision(&res);
+        return res;
+    }
+    case DAV1D_WM_TYPE_IDENTITY:
+        return (mv) { .x = 0, .y = 0 };
+    }
+}
+
+#endif /* DAV1D_SRC_ENV_H */
diff --git a/media/libdav1d/src/src/ext/x86/x86inc.asm b/media/libdav1d/src/src/ext/x86/x86inc.asm
new file mode 100644
index 0000000000..a7ad39e9df
--- /dev/null
+++ b/media/libdav1d/src/src/ext/x86/x86inc.asm
@@ -0,0 +1,1996 @@
+;*****************************************************************************
+;* x86inc.asm: x86 abstraction layer
+;*****************************************************************************
+;* Copyright (C) 2005-2024 x264 project
+;*
+;* Authors: Loren Merritt 
+;*          Henrik Gramner 
+;*          Anton Mitrofanov 
+;*          Fiona Glaser 
+;*
+;* Permission to use, copy, modify, and/or distribute this software for any
+;* purpose with or without fee is hereby granted, provided that the above
+;* copyright notice and this permission notice appear in all copies.
+;*
+;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+;*****************************************************************************
+
+; This is a header file for the x86inc.asm assembly language, which uses
+; NASM/YASM syntax combined with a large number of macros to provide easy
+; abstraction between different calling conventions (x86_32, win64, linux64).
+; It also has various other useful features to simplify writing the kind of
+; DSP functions that are most often used.
+
+%ifndef private_prefix
+    %error private_prefix not defined
+%endif
+
+%ifndef public_prefix
+    %define public_prefix private_prefix
+%endif
+
+%ifndef STACK_ALIGNMENT
+    %if ARCH_X86_64
+        %define STACK_ALIGNMENT 16
+    %else
+        %define STACK_ALIGNMENT 4
+    %endif
+%endif
+
+%define WIN32  0
+%define WIN64  0
+%define UNIX64 0
+%if ARCH_X86_64
+    %ifidn __OUTPUT_FORMAT__,win32
+        %define WIN32  1
+        %define WIN64  1
+    %elifidn __OUTPUT_FORMAT__,win64
+        %define WIN32  1
+        %define WIN64  1
+    %elifidn __OUTPUT_FORMAT__,x64
+        %define WIN32  1
+        %define WIN64  1
+    %else
+        %define UNIX64 1
+    %endif
+%else
+    %ifidn __OUTPUT_FORMAT__,win32
+        %define WIN32  1
+    %endif
+%endif
+
+%define FORMAT_ELF 0
+%define FORMAT_MACHO 0
+%ifidn __OUTPUT_FORMAT__,elf
+    %define FORMAT_ELF 1
+%elifidn __OUTPUT_FORMAT__,elf32
+    %define FORMAT_ELF 1
+%elifidn __OUTPUT_FORMAT__,elf64
+    %define FORMAT_ELF 1
+%elifidn __OUTPUT_FORMAT__,macho
+    %define FORMAT_MACHO 1
+%elifidn __OUTPUT_FORMAT__,macho32
+    %define FORMAT_MACHO 1
+%elifidn __OUTPUT_FORMAT__,macho64
+    %define FORMAT_MACHO 1
+%endif
+
+%ifdef PREFIX
+    %define mangle(x) _ %+ x
+%else
+    %define mangle(x) x
+%endif
+
+; Use VEX-encoding even in non-AVX functions
+%ifndef FORCE_VEX_ENCODING
+    %define FORCE_VEX_ENCODING 0
+%endif
+
+%macro SECTION_RODATA 0-1 16
+    %ifidn __OUTPUT_FORMAT__,win32
+        SECTION .rdata align=%1
+    %elif WIN64
+        SECTION .rdata align=%1
+    %else
+        SECTION .rodata align=%1
+    %endif
+%endmacro
+
+%if ARCH_X86_64
+    %define PIC 1 ; always use PIC on x86-64
+    default rel
+%elifidn __OUTPUT_FORMAT__,win32
+    %define PIC 0 ; PIC isn't used on 32-bit Windows
+%elifndef PIC
+    %define PIC 0
+%endif
+
+%define HAVE_PRIVATE_EXTERN 1
+%ifdef __NASM_VERSION_ID__
+    %use smartalign
+    %if __NASM_VERSION_ID__ < 0x020e0000 ; 2.14
+        %define HAVE_PRIVATE_EXTERN 0
+    %endif
+%endif
+
+; Macros to eliminate most code duplication between x86_32 and x86_64:
+; Currently this works only for leaf functions which load all their arguments
+; into registers at the start, and make no other use of the stack. Luckily that
+; covers most use cases.
+
+; PROLOGUE:
+; %1 = number of arguments. loads them from stack if needed.
+; %2 = number of registers used. pushes callee-saved regs if needed.
+; %3 = number of xmm registers used. pushes callee-saved xmm regs if needed.
+; %4 = (optional) stack size to be allocated. The stack will be aligned before
+;      allocating the specified stack size. If the required stack alignment is
+;      larger than the known stack alignment the stack will be manually aligned
+;      and an extra register will be allocated to hold the original stack
+;      pointer (to not invalidate r0m etc.). To prevent the use of an extra
+;      register as stack pointer, request a negative stack size.
+; %4+/%5+ = list of names to define to registers
+; PROLOGUE can also be invoked by adding the same options to cglobal
+
+; e.g.
+; cglobal foo, 2,3,7,0x40, dst, src, tmp
+; declares a function (foo) that automatically loads two arguments (dst and
+; src) into registers, uses one additional register (tmp) plus 7 vector
+; registers (m0-m6) and allocates 0x40 bytes of stack space.
+
+; TODO Some functions can use some args directly from the stack. If they're the
+; last args then you can just not declare them, but if they're in the middle
+; we need more flexible macro.
+
+; RET:
+; Pops anything that was pushed by PROLOGUE, and returns.
+
+; REP_RET:
+; Use this instead of RET if it's a branch target.
+
+; registers:
+; rN and rNq are the native-size register holding function argument N
+; rNd, rNw, rNb are dword, word, and byte size
+; rNh is the high 8 bits of the word size
+; rNm is the original location of arg N (a register or on the stack), dword
+; rNmp is native size
+
+%macro DECLARE_REG 2-3
+    %define r%1q %2
+    %define r%1d %2d
+    %define r%1w %2w
+    %define r%1b %2b
+    %define r%1h %2h
+    %define %2q %2
+    %if %0 == 2
+        %define r%1m  %2d
+        %define r%1mp %2
+    %elif ARCH_X86_64 ; memory
+        %define r%1m [rstk + stack_offset + %3]
+        %define r%1mp qword r %+ %1 %+ m
+    %else
+        %define r%1m [rstk + stack_offset + %3]
+        %define r%1mp dword r %+ %1 %+ m
+    %endif
+    %define r%1  %2
+%endmacro
+
+%macro DECLARE_REG_SIZE 3
+    %define r%1q r%1
+    %define e%1q r%1
+    %define r%1d e%1
+    %define e%1d e%1
+    %define r%1w %1
+    %define e%1w %1
+    %define r%1h %3
+    %define e%1h %3
+    %define r%1b %2
+    %define e%1b %2
+    %if ARCH_X86_64 == 0
+        %define r%1 e%1
+    %endif
+%endmacro
+
+DECLARE_REG_SIZE ax, al, ah
+DECLARE_REG_SIZE bx, bl, bh
+DECLARE_REG_SIZE cx, cl, ch
+DECLARE_REG_SIZE dx, dl, dh
+DECLARE_REG_SIZE si, sil, null
+DECLARE_REG_SIZE di, dil, null
+DECLARE_REG_SIZE bp, bpl, null
+
+; t# defines for when per-arch register allocation is more complex than just function arguments
+
+%macro DECLARE_REG_TMP 1-*
+    %assign %%i 0
+    %rep %0
+        CAT_XDEFINE t, %%i, r%1
+        %assign %%i %%i+1
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro DECLARE_REG_TMP_SIZE 0-*
+    %rep %0
+        %define t%1q t%1 %+ q
+        %define t%1d t%1 %+ d
+        %define t%1w t%1 %+ w
+        %define t%1h t%1 %+ h
+        %define t%1b t%1 %+ b
+        %rotate 1
+    %endrep
+%endmacro
+
+DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14
+
+%if ARCH_X86_64
+    %define gprsize 8
+%else
+    %define gprsize 4
+%endif
+
+%macro LEA 2
+%if ARCH_X86_64
+    lea %1, [%2]
+%elif PIC
+    call $+5 ; special-cased to not affect the RSB on most CPU:s
+    pop %1
+    add %1, -$+1+%2
+%else
+    mov %1, %2
+%endif
+%endmacro
+
+; Repeats an instruction/operation for multiple arguments.
+; Example usage: "REPX {psrlw x, 8}, m0, m1, m2, m3"
+%macro REPX 2-* ; operation, args
+    %xdefine %%f(x) %1
+    %rep %0 - 1
+        %rotate 1
+        %%f(%1)
+    %endrep
+%endmacro
+
+%macro PUSH 1
+    push %1
+    %ifidn rstk, rsp
+        %assign stack_offset stack_offset+gprsize
+    %endif
+%endmacro
+
+%macro POP 1
+    pop %1
+    %ifidn rstk, rsp
+        %assign stack_offset stack_offset-gprsize
+    %endif
+%endmacro
+
+%macro PUSH_IF_USED 1-*
+    %rep %0
+        %if %1 < regs_used
+            PUSH r%1
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro POP_IF_USED 1-*
+    %rep %0
+        %if %1 < regs_used
+            pop r%1
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro LOAD_IF_USED 1-*
+    %rep %0
+        %if %1 < num_args
+            mov r%1, r %+ %1 %+ mp
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro SUB 2
+    sub %1, %2
+    %ifidn %1, rstk
+        %assign stack_offset stack_offset+(%2)
+    %endif
+%endmacro
+
+%macro ADD 2
+    add %1, %2
+    %ifidn %1, rstk
+        %assign stack_offset stack_offset-(%2)
+    %endif
+%endmacro
+
+%macro movifnidn 2
+    %ifnidn %1, %2
+        mov %1, %2
+    %endif
+%endmacro
+
+%if ARCH_X86_64 == 0
+    %define movsxd movifnidn
+%endif
+
+%macro movsxdifnidn 2
+    %ifnidn %1, %2
+        movsxd %1, %2
+    %endif
+%endmacro
+
+%macro ASSERT 1
+    %if (%1) == 0
+        %error assertion ``%1'' failed
+    %endif
+%endmacro
+
+%macro DEFINE_ARGS 0-*
+    %ifdef n_arg_names
+        %assign %%i 0
+        %rep n_arg_names
+            CAT_UNDEF arg_name %+ %%i, q
+            CAT_UNDEF arg_name %+ %%i, d
+            CAT_UNDEF arg_name %+ %%i, w
+            CAT_UNDEF arg_name %+ %%i, h
+            CAT_UNDEF arg_name %+ %%i, b
+            CAT_UNDEF arg_name %+ %%i, m
+            CAT_UNDEF arg_name %+ %%i, mp
+            CAT_UNDEF arg_name, %%i
+            %assign %%i %%i+1
+        %endrep
+    %endif
+
+    %xdefine %%stack_offset stack_offset
+    %undef stack_offset ; so that the current value of stack_offset doesn't get baked in by xdefine
+    %assign %%i 0
+    %rep %0
+        %xdefine %1q r %+ %%i %+ q
+        %xdefine %1d r %+ %%i %+ d
+        %xdefine %1w r %+ %%i %+ w
+        %xdefine %1h r %+ %%i %+ h
+        %xdefine %1b r %+ %%i %+ b
+        %xdefine %1m r %+ %%i %+ m
+        %xdefine %1mp r %+ %%i %+ mp
+        CAT_XDEFINE arg_name, %%i, %1
+        %assign %%i %%i+1
+        %rotate 1
+    %endrep
+    %xdefine stack_offset %%stack_offset
+    %assign n_arg_names %0
+%endmacro
+
+%define required_stack_alignment ((mmsize + 15) & ~15)
+%define vzeroupper_required (mmsize > 16 && (ARCH_X86_64 == 0 || xmm_regs_used > 16 || notcpuflag(avx512)))
+%define high_mm_regs (16*cpuflag(avx512))
+
+; Large stack allocations on Windows need to use stack probing in order
+; to guarantee that all stack memory is committed before accessing it.
+; This is done by ensuring that the guard page(s) at the end of the
+; currently committed pages are touched prior to any pages beyond that.
+%if WIN64
+    %assign STACK_PROBE_SIZE 8192
+%elifidn __OUTPUT_FORMAT__, win32
+    %assign STACK_PROBE_SIZE 4096
+%else
+    %assign STACK_PROBE_SIZE 0
+%endif
+
+%macro PROBE_STACK 1 ; stack_size
+    %if STACK_PROBE_SIZE
+        %assign %%i STACK_PROBE_SIZE
+        %rep %1 / STACK_PROBE_SIZE
+            mov eax, [rsp-%%i]
+            %assign %%i %%i+STACK_PROBE_SIZE
+        %endrep
+    %endif
+%endmacro
+
+%macro RESET_STACK_STATE 0
+    %ifidn rstk, rsp
+        %assign stack_offset stack_offset - stack_size_padded
+    %else
+        %xdefine rstk rsp
+    %endif
+    %assign stack_size 0
+    %assign stack_size_padded 0
+    %assign xmm_regs_used 0
+%endmacro
+
+%macro ALLOC_STACK 0-2 0, 0 ; stack_size, n_xmm_regs
+    RESET_STACK_STATE
+    %ifnum %2
+        %if mmsize != 8
+            %assign xmm_regs_used %2
+        %endif
+    %endif
+    %ifnum %1
+        %if %1 != 0
+            %assign %%pad 0
+            %assign stack_size %1
+            %if stack_size < 0
+                %assign stack_size -stack_size
+            %endif
+            %if WIN64
+                %assign %%pad %%pad + 32 ; shadow space
+                %if xmm_regs_used > 8
+                    %assign %%pad %%pad + (xmm_regs_used-8)*16 ; callee-saved xmm registers
+                %endif
+            %endif
+            %if required_stack_alignment <= STACK_ALIGNMENT
+                ; maintain the current stack alignment
+                %assign stack_size_padded stack_size + %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1))
+                PROBE_STACK stack_size_padded
+                SUB rsp, stack_size_padded
+            %else
+                %assign %%reg_num (regs_used - 1)
+                %xdefine rstk r %+ %%reg_num
+                ; align stack, and save original stack location directly above
+                ; it, i.e. in [rsp+stack_size_padded], so we can restore the
+                ; stack in a single instruction (i.e. mov rsp, rstk or mov
+                ; rsp, [rsp+stack_size_padded])
+                %if %1 < 0 ; need to store rsp on stack
+                    %xdefine rstkm [rsp + stack_size + %%pad]
+                    %assign %%pad %%pad + gprsize
+                %else ; can keep rsp in rstk during whole function
+                    %xdefine rstkm rstk
+                %endif
+                %assign stack_size_padded stack_size + ((%%pad + required_stack_alignment-1) & ~(required_stack_alignment-1))
+                PROBE_STACK stack_size_padded
+                mov rstk, rsp
+                and rsp, ~(required_stack_alignment-1)
+                sub rsp, stack_size_padded
+                movifnidn rstkm, rstk
+            %endif
+            WIN64_PUSH_XMM
+        %endif
+    %endif
+%endmacro
+
+%macro SETUP_STACK_POINTER 0-1 0
+    %ifnum %1
+        %if %1 != 0 && required_stack_alignment > STACK_ALIGNMENT
+            %if %1 > 0
+                ; Reserve an additional register for storing the original stack pointer, but avoid using
+                ; eax/rax for this purpose since it can potentially get overwritten as a return value.
+                %assign regs_used (regs_used + 1)
+                %if ARCH_X86_64 && regs_used == 7
+                    %assign regs_used 8
+                %elif ARCH_X86_64 == 0 && regs_used == 1
+                    %assign regs_used 2
+                %endif
+            %endif
+            %if ARCH_X86_64 && regs_used < 5 + UNIX64 * 3
+                ; Ensure that we don't clobber any registers containing arguments. For UNIX64 we also preserve r6 (rax)
+                ; since it's used as a hidden argument in vararg functions to specify the number of vector registers used.
+                %assign regs_used 5 + UNIX64 * 3
+            %endif
+        %endif
+    %endif
+%endmacro
+
+%if WIN64 ; Windows x64 ;=================================================
+
+DECLARE_REG 0,  rcx
+DECLARE_REG 1,  rdx
+DECLARE_REG 2,  R8
+DECLARE_REG 3,  R9
+DECLARE_REG 4,  R10, 40
+DECLARE_REG 5,  R11, 48
+DECLARE_REG 6,  rax, 56
+DECLARE_REG 7,  rdi, 64
+DECLARE_REG 8,  rsi, 72
+DECLARE_REG 9,  rbx, 80
+DECLARE_REG 10, rbp, 88
+DECLARE_REG 11, R14, 96
+DECLARE_REG 12, R15, 104
+DECLARE_REG 13, R12, 112
+DECLARE_REG 14, R13, 120
+
+%macro PROLOGUE 2-5+ 0, 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names...
+    %assign num_args %1
+    %assign regs_used %2
+    ASSERT regs_used >= num_args
+    SETUP_STACK_POINTER %4
+    ASSERT regs_used <= 15
+    PUSH_IF_USED 7, 8, 9, 10, 11, 12, 13, 14
+    ALLOC_STACK %4, %3
+    %if mmsize != 8 && stack_size == 0
+        WIN64_SPILL_XMM %3
+    %endif
+    LOAD_IF_USED 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+    %if %0 > 4
+        %ifnum %4
+            DEFINE_ARGS %5
+        %else
+            DEFINE_ARGS %4, %5
+        %endif
+    %elifnnum %4
+        DEFINE_ARGS %4
+    %endif
+%endmacro
+
+; Push XMM registers to the stack. If no argument is specified all used register
+; will be pushed, otherwise only push previously unpushed registers.
+%macro WIN64_PUSH_XMM 0-2 ; new_xmm_regs_used, xmm_regs_pushed
+    %if mmsize != 8
+        %if %0 == 2
+            %assign %%pushed %2
+            %assign xmm_regs_used %1
+        %elif %0 == 1
+            %assign %%pushed xmm_regs_used
+            %assign xmm_regs_used %1
+        %else
+            %assign %%pushed 0
+        %endif
+        ; Use the shadow space to store XMM6 and XMM7, the rest needs stack space allocated.
+        %if %%pushed <= 6 + high_mm_regs && xmm_regs_used > 6 + high_mm_regs
+            movaps [rstk + stack_offset +  8], xmm6
+        %endif
+        %if %%pushed <= 7 + high_mm_regs && xmm_regs_used > 7 + high_mm_regs
+            movaps [rstk + stack_offset + 24], xmm7
+        %endif
+        %assign %%pushed %%pushed - high_mm_regs - 8
+        %if %%pushed < 0
+            %assign %%pushed 0
+        %endif
+        %assign %%regs_to_push xmm_regs_used - %%pushed - high_mm_regs - 8
+        %if %%regs_to_push > 0
+            ASSERT (%%regs_to_push + %%pushed) * 16 <= stack_size_padded - stack_size - 32
+            %assign %%i %%pushed + 8
+            %rep %%regs_to_push
+                movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i
+                %assign %%i %%i+1
+            %endrep
+        %endif
+    %endif
+%endmacro
+
+; Allocated stack space for XMM registers and push all, or a subset, of those
+%macro WIN64_SPILL_XMM 1-2 ; xmm_regs_used, xmm_regs_reserved
+    RESET_STACK_STATE
+    %if mmsize != 8
+        %assign xmm_regs_used %1
+        ASSERT xmm_regs_used <= 16 + high_mm_regs
+        %if %0 == 2
+            ASSERT %2 >= %1
+            %assign %%xmm_regs_on_stack %2 - high_mm_regs - 8
+        %else
+            %assign %%xmm_regs_on_stack %1 - high_mm_regs - 8
+        %endif
+        %if %%xmm_regs_on_stack > 0
+            ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack.
+            %assign %%pad %%xmm_regs_on_stack*16 + 32
+            %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1))
+            SUB rsp, stack_size_padded
+        %endif
+        WIN64_PUSH_XMM
+    %endif
+%endmacro
+
+%macro WIN64_RESTORE_XMM_INTERNAL 0
+    %assign %%pad_size 0
+    %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8
+    %if %%xmm_regs_on_stack > 0
+        %assign %%i xmm_regs_used - high_mm_regs
+        %rep %%xmm_regs_on_stack
+            %assign %%i %%i-1
+            movaps xmm %+ %%i, [rsp + (%%i-8)*16 + stack_size + 32]
+        %endrep
+    %endif
+    %if stack_size_padded > 0
+        %if stack_size > 0 && required_stack_alignment > STACK_ALIGNMENT
+            mov rsp, rstkm
+        %else
+            add rsp, stack_size_padded
+            %assign %%pad_size stack_size_padded
+        %endif
+    %endif
+    %if xmm_regs_used > 7 + high_mm_regs
+        movaps xmm7, [rsp + stack_offset - %%pad_size + 24]
+    %endif
+    %if xmm_regs_used > 6 + high_mm_regs
+        movaps xmm6, [rsp + stack_offset - %%pad_size +  8]
+    %endif
+%endmacro
+
+%macro WIN64_RESTORE_XMM 0
+    WIN64_RESTORE_XMM_INTERNAL
+    RESET_STACK_STATE
+%endmacro
+
+%define has_epilogue regs_used > 7 || stack_size > 0 || vzeroupper_required || xmm_regs_used > 6+high_mm_regs
+
+%macro RET 0
+    WIN64_RESTORE_XMM_INTERNAL
+    POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7
+    %if vzeroupper_required
+        vzeroupper
+    %endif
+    AUTO_REP_RET
+%endmacro
+
+%elif ARCH_X86_64 ; *nix x64 ;=============================================
+
+DECLARE_REG 0,  rdi
+DECLARE_REG 1,  rsi
+DECLARE_REG 2,  rdx
+DECLARE_REG 3,  rcx
+DECLARE_REG 4,  R8
+DECLARE_REG 5,  R9
+DECLARE_REG 6,  rax, 8
+DECLARE_REG 7,  R10, 16
+DECLARE_REG 8,  R11, 24
+DECLARE_REG 9,  rbx, 32
+DECLARE_REG 10, rbp, 40
+DECLARE_REG 11, R14, 48
+DECLARE_REG 12, R15, 56
+DECLARE_REG 13, R12, 64
+DECLARE_REG 14, R13, 72
+
+%macro PROLOGUE 2-5+ 0, 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names...
+    %assign num_args %1
+    %assign regs_used %2
+    ASSERT regs_used >= num_args
+    SETUP_STACK_POINTER %4
+    ASSERT regs_used <= 15
+    PUSH_IF_USED 9, 10, 11, 12, 13, 14
+    ALLOC_STACK %4, %3
+    LOAD_IF_USED 6, 7, 8, 9, 10, 11, 12, 13, 14
+    %if %0 > 4
+        %ifnum %4
+            DEFINE_ARGS %5
+        %else
+            DEFINE_ARGS %4, %5
+        %endif
+    %elifnnum %4
+        DEFINE_ARGS %4
+    %endif
+%endmacro
+
+%define has_epilogue regs_used > 9 || stack_size > 0 || vzeroupper_required
+
+%macro RET 0
+    %if stack_size_padded > 0
+        %if required_stack_alignment > STACK_ALIGNMENT
+            mov rsp, rstkm
+        %else
+            add rsp, stack_size_padded
+        %endif
+    %endif
+    POP_IF_USED 14, 13, 12, 11, 10, 9
+    %if vzeroupper_required
+        vzeroupper
+    %endif
+    AUTO_REP_RET
+%endmacro
+
+%else ; X86_32 ;==============================================================
+
+DECLARE_REG 0, eax, 4
+DECLARE_REG 1, ecx, 8
+DECLARE_REG 2, edx, 12
+DECLARE_REG 3, ebx, 16
+DECLARE_REG 4, esi, 20
+DECLARE_REG 5, edi, 24
+DECLARE_REG 6, ebp, 28
+%define rsp esp
+
+%macro DECLARE_ARG 1-*
+    %rep %0
+        %define r%1m [rstk + stack_offset + 4*%1 + 4]
+        %define r%1mp dword r%1m
+        %rotate 1
+    %endrep
+%endmacro
+
+DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14
+
+%macro PROLOGUE 2-5+ 0, 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names...
+    %assign num_args %1
+    %assign regs_used %2
+    ASSERT regs_used >= num_args
+    %if num_args > 7
+        %assign num_args 7
+    %endif
+    %if regs_used > 7
+        %assign regs_used 7
+    %endif
+    SETUP_STACK_POINTER %4
+    ASSERT regs_used <= 7
+    PUSH_IF_USED 3, 4, 5, 6
+    ALLOC_STACK %4, %3
+    LOAD_IF_USED 0, 1, 2, 3, 4, 5, 6
+    %if %0 > 4
+        %ifnum %4
+            DEFINE_ARGS %5
+        %else
+            DEFINE_ARGS %4, %5
+        %endif
+    %elifnnum %4
+        DEFINE_ARGS %4
+    %endif
+%endmacro
+
+%define has_epilogue regs_used > 3 || stack_size > 0 || vzeroupper_required
+
+%macro RET 0
+    %if stack_size_padded > 0
+        %if required_stack_alignment > STACK_ALIGNMENT
+            mov rsp, rstkm
+        %else
+            add rsp, stack_size_padded
+        %endif
+    %endif
+    POP_IF_USED 6, 5, 4, 3
+    %if vzeroupper_required
+        vzeroupper
+    %endif
+    AUTO_REP_RET
+%endmacro
+
+%endif ;======================================================================
+
+%if WIN64 == 0
+    %macro WIN64_SPILL_XMM 1-2
+        RESET_STACK_STATE
+        %if mmsize != 8
+            %assign xmm_regs_used %1
+        %endif
+    %endmacro
+    %macro WIN64_RESTORE_XMM 0
+        RESET_STACK_STATE
+    %endmacro
+    %macro WIN64_PUSH_XMM 0-2
+        %if mmsize != 8 && %0 >= 1
+            %assign xmm_regs_used %1
+        %endif
+    %endmacro
+%endif
+
+; On AMD cpus <=K10, an ordinary ret is slow if it immediately follows either
+; a branch or a branch target. So switch to a 2-byte form of ret in that case.
+; We can automatically detect "follows a branch", but not a branch target.
+; (SSSE3 is a sufficient condition to know that your cpu doesn't have this problem.)
+%macro REP_RET 0
+    %if has_epilogue || cpuflag(ssse3)
+        RET
+    %else
+        rep ret
+    %endif
+    annotate_function_size
+%endmacro
+
+%define last_branch_adr $$
+%macro AUTO_REP_RET 0
+    %if notcpuflag(ssse3)
+        times ((last_branch_adr-$)>>31)+1 rep ; times 1 iff $ == last_branch_adr.
+    %endif
+    ret
+    annotate_function_size
+%endmacro
+
+%macro BRANCH_INSTR 0-*
+    %rep %0
+        %macro %1 1-2 %1
+            %2 %1
+            %if notcpuflag(ssse3)
+                %%branch_instr equ $
+                %xdefine last_branch_adr %%branch_instr
+            %endif
+        %endmacro
+        %rotate 1
+    %endrep
+%endmacro
+
+BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, jna, jnae, jb, jbe, jnb, jnbe, jc, jnc, js, jns, jo, jno, jp, jnp
+
+%macro TAIL_CALL 1-2 1 ; callee, is_nonadjacent
+    %if has_epilogue
+        call %1
+        RET
+    %elif %2
+        jmp %1
+    %endif
+    annotate_function_size
+%endmacro
+
+;=============================================================================
+; arch-independent part
+;=============================================================================
+
+%assign function_align 16
+
+; Begin a function.
+; Applies any symbol mangling needed for C linkage, and sets up a define such that
+; subsequent uses of the function name automatically refer to the mangled version.
+; Appends cpuflags to the function name if cpuflags has been specified.
+; The "" empty default parameter is a workaround for nasm, which fails if SUFFIX
+; is empty and we call cglobal_internal with just %1 %+ SUFFIX (without %2).
+%macro cglobal 1-2+ "" ; name, [PROLOGUE args]
+    cglobal_internal 1, %1 %+ SUFFIX, %2
+%endmacro
+%macro cvisible 1-2+ "" ; name, [PROLOGUE args]
+    cglobal_internal 0, %1 %+ SUFFIX, %2
+%endmacro
+%macro cglobal_internal 2-3+
+    annotate_function_size
+    %ifndef cglobaled_%2
+        %if %1
+            %xdefine %2 mangle(private_prefix %+ _ %+ %2)
+        %else
+            %xdefine %2 mangle(public_prefix %+ _ %+ %2)
+        %endif
+        %xdefine %2.skip_prologue %2 %+ .skip_prologue
+        CAT_XDEFINE cglobaled_, %2, 1
+    %endif
+    %xdefine current_function %2
+    %xdefine current_function_section __SECT__
+    %if FORMAT_ELF
+        %if %1
+            global %2:function hidden
+        %else
+            global %2:function
+        %endif
+    %elif FORMAT_MACHO && HAVE_PRIVATE_EXTERN && %1
+        global %2:private_extern
+    %else
+        global %2
+    %endif
+    %if WIN32 && !%1
+        %ifdef BUILDING_DLL
+            export %2
+        %endif
+    %endif
+    align function_align
+    %2:
+    RESET_MM_PERMUTATION        ; needed for x86-64, also makes disassembly somewhat nicer
+    %xdefine rstk rsp           ; copy of the original stack pointer, used when greater alignment than the known stack alignment is required
+    %assign stack_offset 0      ; stack pointer offset relative to the return address
+    %assign stack_size 0        ; amount of stack space that can be freely used inside a function
+    %assign stack_size_padded 0 ; total amount of allocated stack space, including space for callee-saved xmm registers on WIN64 and alignment padding
+    %assign xmm_regs_used 0     ; number of XMM registers requested, used for dealing with callee-saved registers on WIN64 and vzeroupper
+    %ifnidn %3, ""
+        PROLOGUE %3
+    %endif
+%endmacro
+
+; Create a global symbol from a local label with the correct name mangling and type
+%macro cglobal_label 1
+    %if FORMAT_ELF
+        global current_function %+ %1:function hidden
+    %elif FORMAT_MACHO && HAVE_PRIVATE_EXTERN
+        global current_function %+ %1:private_extern
+    %else
+        global current_function %+ %1
+    %endif
+    %1:
+%endmacro
+
+%macro cextern 1
+    %xdefine %1 mangle(private_prefix %+ _ %+ %1)
+    CAT_XDEFINE cglobaled_, %1, 2
+    extern %1
+%endmacro
+
+; Like cextern, but without the prefix. This should be used for symbols from external libraries.
+%macro cextern_naked 1
+    %ifdef PREFIX
+        %xdefine %1 mangle(%1)
+    %endif
+    CAT_XDEFINE cglobaled_, %1, 3
+    extern %1
+%endmacro
+
+%macro const 1-2+
+    %xdefine %1 mangle(private_prefix %+ _ %+ %1)
+    %if FORMAT_ELF
+        global %1:data hidden
+    %elif FORMAT_MACHO && HAVE_PRIVATE_EXTERN
+        global %1:private_extern
+    %else
+        global %1
+    %endif
+    %1: %2
+%endmacro
+
+%if FORMAT_ELF
+    ; The GNU linker assumes the stack is executable by default.
+    [SECTION .note.GNU-stack noalloc noexec nowrite progbits]
+
+    %ifdef __NASM_VERSION_ID__
+        %if __NASM_VERSION_ID__ >= 0x020e0300 ; 2.14.03
+            %if ARCH_X86_64
+                ; Control-flow Enforcement Technology (CET) properties.
+                [SECTION .note.gnu.property alloc noexec nowrite note align=gprsize]
+                dd 0x00000004  ; n_namesz
+                dd gprsize + 8 ; n_descsz
+                dd 0x00000005  ; n_type = NT_GNU_PROPERTY_TYPE_0
+                db "GNU",0     ; n_name
+                dd 0xc0000002  ; pr_type = GNU_PROPERTY_X86_FEATURE_1_AND
+                dd 0x00000004  ; pr_datasz
+                dd 0x00000002  ; pr_data = GNU_PROPERTY_X86_FEATURE_1_SHSTK
+                dd 0x00000000  ; pr_padding
+            %endif
+        %endif
+    %endif
+%endif
+
+; Tell debuggers how large the function was.
+; This may be invoked multiple times per function; we rely on later instances overriding earlier ones.
+; This is invoked by RET and similar macros, and also cglobal does it for the previous function,
+; but if the last function in a source file doesn't use any of the standard macros for its epilogue,
+; then its size might be unspecified.
+%macro annotate_function_size 0
+    %ifdef __YASM_VER__
+        %ifdef current_function
+            %if FORMAT_ELF
+                current_function_section
+                %%ecf equ $
+                size current_function %%ecf - current_function
+                __SECT__
+            %endif
+        %endif
+    %endif
+%endmacro
+
+; cpuflags
+
+%assign cpuflags_mmx       (1<<0)
+%assign cpuflags_mmx2      (1<<1)  | cpuflags_mmx
+%assign cpuflags_3dnow     (1<<2)  | cpuflags_mmx
+%assign cpuflags_3dnowext  (1<<3)  | cpuflags_3dnow
+%assign cpuflags_sse       (1<<4)  | cpuflags_mmx2
+%assign cpuflags_sse2      (1<<5)  | cpuflags_sse
+%assign cpuflags_sse2slow  (1<<6)  | cpuflags_sse2
+%assign cpuflags_lzcnt     (1<<7)  | cpuflags_sse2
+%assign cpuflags_sse3      (1<<8)  | cpuflags_sse2
+%assign cpuflags_ssse3     (1<<9)  | cpuflags_sse3
+%assign cpuflags_sse4      (1<<10) | cpuflags_ssse3
+%assign cpuflags_sse42     (1<<11) | cpuflags_sse4
+%assign cpuflags_aesni     (1<<12) | cpuflags_sse42
+%assign cpuflags_clmul     (1<<13) | cpuflags_sse42
+%assign cpuflags_gfni      (1<<14) | cpuflags_aesni|cpuflags_clmul
+%assign cpuflags_avx       (1<<15) | cpuflags_sse42
+%assign cpuflags_xop       (1<<16) | cpuflags_avx
+%assign cpuflags_fma4      (1<<17) | cpuflags_avx
+%assign cpuflags_fma3      (1<<18) | cpuflags_avx
+%assign cpuflags_bmi1      (1<<19) | cpuflags_avx|cpuflags_lzcnt
+%assign cpuflags_bmi2      (1<<20) | cpuflags_bmi1
+%assign cpuflags_avx2      (1<<21) | cpuflags_fma3|cpuflags_bmi2
+%assign cpuflags_avx512    (1<<22) | cpuflags_avx2 ; F, CD, BW, DQ, VL
+%assign cpuflags_avx512icl (1<<23) | cpuflags_avx512|cpuflags_gfni ; VNNI, IFMA, VBMI, VBMI2, VPOPCNTDQ, BITALG, VAES, VPCLMULQDQ
+
+%assign cpuflags_cache32   (1<<24)
+%assign cpuflags_cache64   (1<<25)
+%assign cpuflags_aligned   (1<<26) ; not a cpu feature, but a function variant
+%assign cpuflags_atom      (1<<27)
+
+; Returns a boolean value expressing whether or not the specified cpuflag is enabled.
+%define    cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1)
+%define notcpuflag(x) (cpuflag(x) ^ 1)
+
+; Takes an arbitrary number of cpuflags from the above list.
+; All subsequent functions (up to the next INIT_CPUFLAGS) is built for the specified cpu.
+; You shouldn't need to invoke this macro directly, it's a subroutine for INIT_MMX &co.
+%macro INIT_CPUFLAGS 0-*
+    %xdefine SUFFIX
+    %undef cpuname
+    %assign cpuflags 0
+
+    %if %0 >= 1
+        %rep %0
+            %ifdef cpuname
+                %xdefine cpuname cpuname %+ _%1
+            %else
+                %xdefine cpuname %1
+            %endif
+            %assign cpuflags cpuflags | cpuflags_%1
+            %rotate 1
+        %endrep
+        %xdefine SUFFIX _ %+ cpuname
+
+        %if cpuflag(avx)
+            %assign avx_enabled 1
+        %endif
+        %if (mmsize == 16 && notcpuflag(sse2)) || (mmsize == 32 && notcpuflag(avx2))
+            %define mova movaps
+            %define movu movups
+            %define movnta movntps
+        %endif
+        %if cpuflag(aligned)
+            %define movu mova
+        %elif cpuflag(sse3) && notcpuflag(ssse3)
+            %define movu lddqu
+        %endif
+    %endif
+
+    %if ARCH_X86_64 || cpuflag(sse2)
+        %ifdef __NASM_VERSION_ID__
+            ALIGNMODE p6
+        %else
+            CPU amdnop
+        %endif
+    %else
+        %ifdef __NASM_VERSION_ID__
+            ALIGNMODE nop
+        %else
+            CPU basicnop
+        %endif
+    %endif
+%endmacro
+
+; Merge mmx, sse*, and avx*
+; m# is a simd register of the currently selected size
+; xm# is the corresponding xmm register if mmsize >= 16, otherwise the same as m#
+; ym# is the corresponding ymm register if mmsize >= 32, otherwise the same as m#
+; zm# is the corresponding zmm register if mmsize >= 64, otherwise the same as m#
+; (All 4 remain in sync through SWAP.)
+
+%macro CAT_XDEFINE 3
+    %xdefine %1%2 %3
+%endmacro
+
+%macro CAT_UNDEF 2
+    %undef %1%2
+%endmacro
+
+%macro DEFINE_MMREGS 1 ; mmtype
+    %assign %%prev_mmregs 0
+    %ifdef num_mmregs
+        %assign %%prev_mmregs num_mmregs
+    %endif
+
+    %assign num_mmregs 8
+    %if ARCH_X86_64 && mmsize >= 16
+        %assign num_mmregs 16
+        %if cpuflag(avx512) || mmsize == 64
+            %assign num_mmregs 32
+        %endif
+    %endif
+
+    %assign %%i 0
+    %rep num_mmregs
+        CAT_XDEFINE m, %%i, %1 %+ %%i
+        CAT_XDEFINE nn%1, %%i, %%i
+        %assign %%i %%i+1
+    %endrep
+    %if %%prev_mmregs > num_mmregs
+        %rep %%prev_mmregs - num_mmregs
+            CAT_UNDEF m, %%i
+            CAT_UNDEF nn %+ mmtype, %%i
+            %assign %%i %%i+1
+        %endrep
+    %endif
+    %xdefine mmtype %1
+%endmacro
+
+; Prefer registers 16-31 over 0-15 to avoid having to use vzeroupper
+%macro AVX512_MM_PERMUTATION 0-1 0 ; start_reg
+    %if ARCH_X86_64 && cpuflag(avx512)
+        %assign %%i %1
+        %rep 16-%1
+            %assign %%i_high %%i+16
+            SWAP %%i, %%i_high
+            %assign %%i %%i+1
+        %endrep
+    %endif
+%endmacro
+
+%macro INIT_MMX 0-1+
+    %assign avx_enabled 0
+    %define RESET_MM_PERMUTATION INIT_MMX %1
+    %define mmsize 8
+    %define mova movq
+    %define movu movq
+    %define movh movd
+    %define movnta movntq
+    INIT_CPUFLAGS %1
+    DEFINE_MMREGS mm
+%endmacro
+
+%macro INIT_XMM 0-1+
+    %assign avx_enabled FORCE_VEX_ENCODING
+    %define RESET_MM_PERMUTATION INIT_XMM %1
+    %define mmsize 16
+    %define mova movdqa
+    %define movu movdqu
+    %define movh movq
+    %define movnta movntdq
+    INIT_CPUFLAGS %1
+    DEFINE_MMREGS xmm
+    %if WIN64
+        AVX512_MM_PERMUTATION 6 ; Swap callee-saved registers with volatile registers
+    %endif
+    %xdefine bcstw 1to8
+    %xdefine bcstd 1to4
+    %xdefine bcstq 1to2
+%endmacro
+
+%macro INIT_YMM 0-1+
+    %assign avx_enabled 1
+    %define RESET_MM_PERMUTATION INIT_YMM %1
+    %define mmsize 32
+    %define mova movdqa
+    %define movu movdqu
+    %undef movh
+    %define movnta movntdq
+    INIT_CPUFLAGS %1
+    DEFINE_MMREGS ymm
+    AVX512_MM_PERMUTATION
+    %xdefine bcstw 1to16
+    %xdefine bcstd 1to8
+    %xdefine bcstq 1to4
+%endmacro
+
+%macro INIT_ZMM 0-1+
+    %assign avx_enabled 1
+    %define RESET_MM_PERMUTATION INIT_ZMM %1
+    %define mmsize 64
+    %define mova movdqa
+    %define movu movdqu
+    %undef movh
+    %define movnta movntdq
+    INIT_CPUFLAGS %1
+    DEFINE_MMREGS zmm
+    AVX512_MM_PERMUTATION
+    %xdefine bcstw 1to32
+    %xdefine bcstd 1to16
+    %xdefine bcstq 1to8
+%endmacro
+
+INIT_XMM
+
+%macro DECLARE_MMCAST 1
+    %define  mmmm%1   mm%1
+    %define  mmxmm%1  mm%1
+    %define  mmymm%1  mm%1
+    %define  mmzmm%1  mm%1
+    %define xmmmm%1   mm%1
+    %define xmmxmm%1 xmm%1
+    %define xmmymm%1 xmm%1
+    %define xmmzmm%1 xmm%1
+    %define ymmmm%1   mm%1
+    %define ymmxmm%1 xmm%1
+    %define ymmymm%1 ymm%1
+    %define ymmzmm%1 ymm%1
+    %define zmmmm%1   mm%1
+    %define zmmxmm%1 xmm%1
+    %define zmmymm%1 ymm%1
+    %define zmmzmm%1 zmm%1
+    %define xm%1 xmm %+ m%1
+    %define ym%1 ymm %+ m%1
+    %define zm%1 zmm %+ m%1
+%endmacro
+
+%assign i 0
+%rep 32
+    DECLARE_MMCAST i
+    %assign i i+1
+%endrep
+
+; I often want to use macros that permute their arguments. e.g. there's no
+; efficient way to implement butterfly or transpose or dct without swapping some
+; arguments.
+;
+; I would like to not have to manually keep track of the permutations:
+; If I insert a permutation in the middle of a function, it should automatically
+; change everything that follows. For more complex macros I may also have multiple
+; implementations, e.g. the SSE2 and SSSE3 versions may have different permutations.
+;
+; Hence these macros. Insert a PERMUTE or some SWAPs at the end of a macro that
+; permutes its arguments. It's equivalent to exchanging the contents of the
+; registers, except that this way you exchange the register names instead, so it
+; doesn't cost any cycles.
+
+%macro PERMUTE 2-* ; takes a list of pairs to swap
+    %rep %0/2
+        %xdefine %%tmp%2 m%2
+        %rotate 2
+    %endrep
+    %rep %0/2
+        %xdefine m%1 %%tmp%2
+        CAT_XDEFINE nn, m%1, %1
+        %rotate 2
+    %endrep
+%endmacro
+
+%macro SWAP 2+ ; swaps a single chain (sometimes more concise than pairs)
+    %ifnum %1 ; SWAP 0, 1, ...
+        SWAP_INTERNAL_NUM %1, %2
+    %else ; SWAP m0, m1, ...
+        SWAP_INTERNAL_NAME %1, %2
+    %endif
+%endmacro
+
+%macro SWAP_INTERNAL_NUM 2-*
+    %rep %0-1
+        %xdefine %%tmp m%1
+        %xdefine m%1 m%2
+        %xdefine m%2 %%tmp
+        CAT_XDEFINE nn, m%1, %1
+        CAT_XDEFINE nn, m%2, %2
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro SWAP_INTERNAL_NAME 2-*
+    %xdefine %%args nn %+ %1
+    %rep %0-1
+        %xdefine %%args %%args, nn %+ %2
+        %rotate 1
+    %endrep
+    SWAP_INTERNAL_NUM %%args
+%endmacro
+
+; If SAVE_MM_PERMUTATION is placed at the end of a function, then any later
+; calls to that function will automatically load the permutation, so values can
+; be returned in mmregs.
+%macro SAVE_MM_PERMUTATION 0-1
+    %if %0
+        %xdefine %%f %1_m
+    %else
+        %xdefine %%f current_function %+ _m
+    %endif
+    %assign %%i 0
+    %rep num_mmregs
+        %xdefine %%tmp m %+ %%i
+        CAT_XDEFINE %%f, %%i, regnumof %+ %%tmp
+        %assign %%i %%i+1
+    %endrep
+%endmacro
+
+%macro LOAD_MM_PERMUTATION 0-1 ; name to load from
+    %if %0
+        %xdefine %%f %1_m
+    %else
+        %xdefine %%f current_function %+ _m
+    %endif
+    %xdefine %%tmp %%f %+ 0
+    %ifnum %%tmp
+        DEFINE_MMREGS mmtype
+        %assign %%i 0
+        %rep num_mmregs
+            %xdefine %%tmp %%f %+ %%i
+            CAT_XDEFINE %%m, %%i, m %+ %%tmp
+            %assign %%i %%i+1
+        %endrep
+        %rep num_mmregs
+            %assign %%i %%i-1
+            CAT_XDEFINE m, %%i, %%m %+ %%i
+            CAT_XDEFINE nn, m %+ %%i, %%i
+        %endrep
+    %endif
+%endmacro
+
+; Append cpuflags to the callee's name iff the appended name is known and the plain name isn't
+%macro call 1
+    %ifid %1
+        call_internal %1 %+ SUFFIX, %1
+    %else
+        call %1
+    %endif
+%endmacro
+%macro call_internal 2
+    %xdefine %%i %2
+    %define %%j %%i
+    %ifndef cglobaled_%2
+        %ifdef cglobaled_%1
+            %xdefine %%i %1
+        %endif
+    %elif FORMAT_ELF
+        %if ARCH_X86_64
+            %if cglobaled_%2 >= 2
+                ; Always emit PLT relocations when calling external functions,
+                ; the linker will eliminate unnecessary PLT indirections anyway.
+                %define %%j %%i wrt ..plt
+            %endif
+        %elif PIC && cglobaled_%2 == 3
+            ; Go through the GOT for functions declared using cextern_naked with
+            ; PIC, as such functions presumably exists in external libraries.
+            extern _GLOBAL_OFFSET_TABLE_
+            LEA eax, $$+_GLOBAL_OFFSET_TABLE_ wrt ..gotpc
+            %define %%j [eax+%%i wrt ..got]
+        %endif
+    %endif
+    call %%j
+    LOAD_MM_PERMUTATION %%i
+%endmacro
+
+; Substitutions that reduce instruction size but are functionally equivalent
+%macro add 2
+    %ifnum %2
+        %if %2==128
+            sub %1, -128
+        %else
+            add %1, %2
+        %endif
+    %else
+        add %1, %2
+    %endif
+%endmacro
+
+%macro sub 2
+    %ifnum %2
+        %if %2==128
+            add %1, -128
+        %else
+            sub %1, %2
+        %endif
+    %else
+        sub %1, %2
+    %endif
+%endmacro
+
+;=============================================================================
+; AVX abstraction layer
+;=============================================================================
+
+%assign i 0
+%rep 32
+    %if i < 8
+        CAT_XDEFINE sizeofmm, i, 8
+        CAT_XDEFINE regnumofmm, i, i
+    %endif
+    CAT_XDEFINE sizeofxmm, i, 16
+    CAT_XDEFINE sizeofymm, i, 32
+    CAT_XDEFINE sizeofzmm, i, 64
+    CAT_XDEFINE regnumofxmm, i, i
+    CAT_XDEFINE regnumofymm, i, i
+    CAT_XDEFINE regnumofzmm, i, i
+    %assign i i+1
+%endrep
+%undef i
+
+%macro CHECK_AVX_INSTR_EMU 3-*
+    %xdefine %%opcode %1
+    %xdefine %%dst %2
+    %rep %0-2
+        %ifidn %%dst, %3
+            %error non-avx emulation of ``%%opcode'' is not supported
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+;%1 == instruction
+;%2 == minimal instruction set
+;%3 == 1 if float, 0 if int
+;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation)
+;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not
+;%6+: operands
+%macro RUN_AVX_INSTR 6-9+
+    %ifnum sizeof%7
+        %assign __sizeofreg sizeof%7
+    %elifnum sizeof%6
+        %assign __sizeofreg sizeof%6
+    %else
+        %assign __sizeofreg mmsize
+    %endif
+    %assign __emulate_avx 0
+    %if avx_enabled && __sizeofreg >= 16
+        %xdefine __instr v%1
+    %else
+        %xdefine __instr %1
+        %if %0 >= 8+%4
+            %assign __emulate_avx 1
+        %endif
+    %endif
+    %ifnidn %2, fnord
+        %ifdef cpuname
+            %if notcpuflag(%2)
+                %error use of ``%1'' %2 instruction in cpuname function: current_function
+            %elif %3 == 0 && __sizeofreg == 16 && notcpuflag(sse2)
+                %error use of ``%1'' sse2 instruction in cpuname function: current_function
+            %elif %3 == 0 && __sizeofreg == 32 && notcpuflag(avx2)
+                %error use of ``%1'' avx2 instruction in cpuname function: current_function
+            %elif __sizeofreg == 16 && notcpuflag(sse)
+                %error use of ``%1'' sse instruction in cpuname function: current_function
+            %elif __sizeofreg == 32 && notcpuflag(avx)
+                %error use of ``%1'' avx instruction in cpuname function: current_function
+            %elif __sizeofreg == 64 && notcpuflag(avx512)
+                %error use of ``%1'' avx512 instruction in cpuname function: current_function
+            %elifidn %1, pextrw ; special case because the base instruction is mmx2,
+                %ifnid %6       ; but sse4 is required for memory operands
+                    %if notcpuflag(sse4)
+                        %error use of ``%1'' sse4 instruction in cpuname function: current_function
+                    %endif
+                %endif
+            %endif
+        %endif
+    %endif
+
+    %if __emulate_avx
+        %xdefine __src1 %7
+        %xdefine __src2 %8
+        %if %5 && %4 == 0
+            %ifnidn %6, %7
+                %ifidn %6, %8
+                    %xdefine __src1 %8
+                    %xdefine __src2 %7
+                %elifnnum sizeof%8
+                    ; 3-operand AVX instructions with a memory arg can only have it in src2,
+                    ; whereas SSE emulation prefers to have it in src1 (i.e. the mov).
+                    ; So, if the instruction is commutative with a memory arg, swap them.
+                    %xdefine __src1 %8
+                    %xdefine __src2 %7
+                %endif
+            %endif
+        %endif
+        %ifnidn %6, __src1
+            %if %0 >= 9
+                CHECK_AVX_INSTR_EMU {%1 %6, %7, %8, %9}, %6, __src2, %9
+            %else
+                CHECK_AVX_INSTR_EMU {%1 %6, %7, %8}, %6, __src2
+            %endif
+            %if __sizeofreg == 8
+                MOVQ %6, __src1
+            %elif %3
+                MOVAPS %6, __src1
+            %else
+                MOVDQA %6, __src1
+            %endif
+        %endif
+        %if %0 >= 9
+            %1 %6, __src2, %9
+        %else
+            %1 %6, __src2
+        %endif
+    %elif %0 >= 9
+        %if avx_enabled && __sizeofreg >= 16 && %4 == 1
+            %ifnnum regnumof%7
+                %if %3
+                    vmovaps %6, %7
+                %else
+                    vmovdqa %6, %7
+                %endif
+                __instr %6, %6, %8, %9
+            %else
+                __instr %6, %7, %8, %9
+            %endif
+        %else
+            __instr %6, %7, %8, %9
+        %endif
+    %elif %0 == 8
+        %if avx_enabled && __sizeofreg >= 16 && %4 == 0
+            %xdefine __src1 %7
+            %xdefine __src2 %8
+            %if %5
+                %ifnum regnumof%7
+                    %ifnum regnumof%8
+                        %if regnumof%7 < 8 && regnumof%8 >= 8 && regnumof%8 < 16 && sizeof%8 <= 32
+                            ; Most VEX-encoded instructions require an additional byte to encode when
+                            ; src2 is a high register (e.g. m8..15). If the instruction is commutative
+                            ; we can swap src1 and src2 when doing so reduces the instruction length.
+                            %xdefine __src1 %8
+                            %xdefine __src2 %7
+                        %endif
+                    %endif
+                %elifnum regnumof%8 ; put memory operands in src2 when possible
+                    %xdefine __src1 %8
+                    %xdefine __src2 %7
+                %else
+                    %assign __emulate_avx 1
+                %endif
+            %elifnnum regnumof%7
+                ; EVEX allows imm8 shift instructions to be used with memory operands,
+                ; but VEX does not. This handles those special cases.
+                %ifnnum %8
+                    %assign __emulate_avx 1
+                %elif notcpuflag(avx512)
+                    %assign __emulate_avx 1
+                %endif
+            %endif
+            %if __emulate_avx ; a separate load is required
+                %if %3
+                    vmovaps %6, %7
+                %else
+                    vmovdqa %6, %7
+                %endif
+                __instr %6, %6, %8
+            %else
+                __instr %6, __src1, __src2
+            %endif
+        %else
+            __instr %6, %7, %8
+        %endif
+    %elif %0 == 7
+        %if avx_enabled && __sizeofreg >= 16 && %5
+            %xdefine __src1 %6
+            %xdefine __src2 %7
+            %ifnum regnumof%6
+                %ifnum regnumof%7
+                    %if regnumof%6 < 8 && regnumof%7 >= 8 && regnumof%7 < 16 && sizeof%7 <= 32
+                        %xdefine __src1 %7
+                        %xdefine __src2 %6
+                    %endif
+                %endif
+            %endif
+            __instr %6, __src1, __src2
+        %else
+            __instr %6, %7
+        %endif
+    %else
+        __instr %6
+    %endif
+%endmacro
+
+;%1 == instruction
+;%2 == minimal instruction set
+;%3 == 1 if float, 0 if int
+;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation)
+;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not
+%macro AVX_INSTR 1-5 fnord, 0, 255, 0
+    %macro %1 1-10 fnord, fnord, fnord, fnord, %1, %2, %3, %4, %5
+        %ifidn %2, fnord
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1
+        %elifidn %3, fnord
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2
+        %elifidn %4, fnord
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3
+        %elifidn %5, fnord
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4
+        %else
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4, %5
+        %endif
+    %endmacro
+%endmacro
+
+; Instructions with both VEX/EVEX and legacy encodings
+; Non-destructive instructions are written without parameters
+AVX_INSTR addpd, sse2, 1, 0, 1
+AVX_INSTR addps, sse, 1, 0, 1
+AVX_INSTR addsd, sse2, 1, 0, 0
+AVX_INSTR addss, sse, 1, 0, 0
+AVX_INSTR addsubpd, sse3, 1, 0, 0
+AVX_INSTR addsubps, sse3, 1, 0, 0
+AVX_INSTR aesdec, aesni, 0, 0, 0
+AVX_INSTR aesdeclast, aesni, 0, 0, 0
+AVX_INSTR aesenc, aesni, 0, 0, 0
+AVX_INSTR aesenclast, aesni, 0, 0, 0
+AVX_INSTR aesimc, aesni
+AVX_INSTR aeskeygenassist, aesni
+AVX_INSTR andnpd, sse2, 1, 0, 0
+AVX_INSTR andnps, sse, 1, 0, 0
+AVX_INSTR andpd, sse2, 1, 0, 1
+AVX_INSTR andps, sse, 1, 0, 1
+AVX_INSTR blendpd, sse4, 1, 1, 0
+AVX_INSTR blendps, sse4, 1, 1, 0
+AVX_INSTR blendvpd, sse4, 1, 1, 0 ; last operand must be xmm0 with legacy encoding
+AVX_INSTR blendvps, sse4, 1, 1, 0 ; last operand must be xmm0 with legacy encoding
+AVX_INSTR cmpeqpd, sse2, 1, 0, 1
+AVX_INSTR cmpeqps, sse, 1, 0, 1
+AVX_INSTR cmpeqsd, sse2, 1, 0, 0
+AVX_INSTR cmpeqss, sse, 1, 0, 0
+AVX_INSTR cmplepd, sse2, 1, 0, 0
+AVX_INSTR cmpleps, sse, 1, 0, 0
+AVX_INSTR cmplesd, sse2, 1, 0, 0
+AVX_INSTR cmpless, sse, 1, 0, 0
+AVX_INSTR cmpltpd, sse2, 1, 0, 0
+AVX_INSTR cmpltps, sse, 1, 0, 0
+AVX_INSTR cmpltsd, sse2, 1, 0, 0
+AVX_INSTR cmpltss, sse, 1, 0, 0
+AVX_INSTR cmpneqpd, sse2, 1, 0, 1
+AVX_INSTR cmpneqps, sse, 1, 0, 1
+AVX_INSTR cmpneqsd, sse2, 1, 0, 0
+AVX_INSTR cmpneqss, sse, 1, 0, 0
+AVX_INSTR cmpnlepd, sse2, 1, 0, 0
+AVX_INSTR cmpnleps, sse, 1, 0, 0
+AVX_INSTR cmpnlesd, sse2, 1, 0, 0
+AVX_INSTR cmpnless, sse, 1, 0, 0
+AVX_INSTR cmpnltpd, sse2, 1, 0, 0
+AVX_INSTR cmpnltps, sse, 1, 0, 0
+AVX_INSTR cmpnltsd, sse2, 1, 0, 0
+AVX_INSTR cmpnltss, sse, 1, 0, 0
+AVX_INSTR cmpordpd, sse2 1, 0, 1
+AVX_INSTR cmpordps, sse 1, 0, 1
+AVX_INSTR cmpordsd, sse2 1, 0, 0
+AVX_INSTR cmpordss, sse 1, 0, 0
+AVX_INSTR cmppd, sse2, 1, 1, 0
+AVX_INSTR cmpps, sse, 1, 1, 0
+AVX_INSTR cmpsd, sse2, 1, 1, 0
+AVX_INSTR cmpss, sse, 1, 1, 0
+AVX_INSTR cmpunordpd, sse2, 1, 0, 1
+AVX_INSTR cmpunordps, sse, 1, 0, 1
+AVX_INSTR cmpunordsd, sse2, 1, 0, 0
+AVX_INSTR cmpunordss, sse, 1, 0, 0
+AVX_INSTR comisd, sse2, 1
+AVX_INSTR comiss, sse, 1
+AVX_INSTR cvtdq2pd, sse2, 1
+AVX_INSTR cvtdq2ps, sse2, 1
+AVX_INSTR cvtpd2dq, sse2, 1
+AVX_INSTR cvtpd2ps, sse2, 1
+AVX_INSTR cvtps2dq, sse2, 1
+AVX_INSTR cvtps2pd, sse2, 1
+AVX_INSTR cvtsd2si, sse2, 1
+AVX_INSTR cvtsd2ss, sse2, 1, 0, 0
+AVX_INSTR cvtsi2sd, sse2, 1, 0, 0
+AVX_INSTR cvtsi2ss, sse, 1, 0, 0
+AVX_INSTR cvtss2sd, sse2, 1, 0, 0
+AVX_INSTR cvtss2si, sse, 1
+AVX_INSTR cvttpd2dq, sse2, 1
+AVX_INSTR cvttps2dq, sse2, 1
+AVX_INSTR cvttsd2si, sse2, 1
+AVX_INSTR cvttss2si, sse, 1
+AVX_INSTR divpd, sse2, 1, 0, 0
+AVX_INSTR divps, sse, 1, 0, 0
+AVX_INSTR divsd, sse2, 1, 0, 0
+AVX_INSTR divss, sse, 1, 0, 0
+AVX_INSTR dppd, sse4, 1, 1, 0
+AVX_INSTR dpps, sse4, 1, 1, 0
+AVX_INSTR extractps, sse4, 1
+AVX_INSTR gf2p8affineinvqb, gfni, 0, 1, 0
+AVX_INSTR gf2p8affineqb, gfni, 0, 1, 0
+AVX_INSTR gf2p8mulb, gfni, 0, 0, 0
+AVX_INSTR haddpd, sse3, 1, 0, 0
+AVX_INSTR haddps, sse3, 1, 0, 0
+AVX_INSTR hsubpd, sse3, 1, 0, 0
+AVX_INSTR hsubps, sse3, 1, 0, 0
+AVX_INSTR insertps, sse4, 1, 1, 0
+AVX_INSTR lddqu, sse3
+AVX_INSTR ldmxcsr, sse, 1
+AVX_INSTR maskmovdqu, sse2
+AVX_INSTR maxpd, sse2, 1, 0, 1
+AVX_INSTR maxps, sse, 1, 0, 1
+AVX_INSTR maxsd, sse2, 1, 0, 0
+AVX_INSTR maxss, sse, 1, 0, 0
+AVX_INSTR minpd, sse2, 1, 0, 1
+AVX_INSTR minps, sse, 1, 0, 1
+AVX_INSTR minsd, sse2, 1, 0, 0
+AVX_INSTR minss, sse, 1, 0, 0
+AVX_INSTR movapd, sse2, 1
+AVX_INSTR movaps, sse, 1
+AVX_INSTR movd, mmx
+AVX_INSTR movddup, sse3, 1
+AVX_INSTR movdqa, sse2
+AVX_INSTR movdqu, sse2
+AVX_INSTR movhlps, sse, 1, 0, 0
+AVX_INSTR movhpd, sse2, 1, 0, 0
+AVX_INSTR movhps, sse, 1, 0, 0
+AVX_INSTR movlhps, sse, 1, 0, 0
+AVX_INSTR movlpd, sse2, 1, 0, 0
+AVX_INSTR movlps, sse, 1, 0, 0
+AVX_INSTR movmskpd, sse2, 1
+AVX_INSTR movmskps, sse, 1
+AVX_INSTR movntdq, sse2
+AVX_INSTR movntdqa, sse4
+AVX_INSTR movntpd, sse2, 1
+AVX_INSTR movntps, sse, 1
+AVX_INSTR movq, mmx
+AVX_INSTR movsd, sse2, 1, 0, 0
+AVX_INSTR movshdup, sse3, 1
+AVX_INSTR movsldup, sse3, 1
+AVX_INSTR movss, sse, 1, 0, 0
+AVX_INSTR movupd, sse2, 1
+AVX_INSTR movups, sse, 1
+AVX_INSTR mpsadbw, sse4, 0, 1, 0
+AVX_INSTR mulpd, sse2, 1, 0, 1
+AVX_INSTR mulps, sse, 1, 0, 1
+AVX_INSTR mulsd, sse2, 1, 0, 0
+AVX_INSTR mulss, sse, 1, 0, 0
+AVX_INSTR orpd, sse2, 1, 0, 1
+AVX_INSTR orps, sse, 1, 0, 1
+AVX_INSTR pabsb, ssse3
+AVX_INSTR pabsd, ssse3
+AVX_INSTR pabsw, ssse3
+AVX_INSTR packssdw, mmx, 0, 0, 0
+AVX_INSTR packsswb, mmx, 0, 0, 0
+AVX_INSTR packusdw, sse4, 0, 0, 0
+AVX_INSTR packuswb, mmx, 0, 0, 0
+AVX_INSTR paddb, mmx, 0, 0, 1
+AVX_INSTR paddd, mmx, 0, 0, 1
+AVX_INSTR paddq, sse2, 0, 0, 1
+AVX_INSTR paddsb, mmx, 0, 0, 1
+AVX_INSTR paddsw, mmx, 0, 0, 1
+AVX_INSTR paddusb, mmx, 0, 0, 1
+AVX_INSTR paddusw, mmx, 0, 0, 1
+AVX_INSTR paddw, mmx, 0, 0, 1
+AVX_INSTR palignr, ssse3, 0, 1, 0
+AVX_INSTR pand, mmx, 0, 0, 1
+AVX_INSTR pandn, mmx, 0, 0, 0
+AVX_INSTR pavgb, mmx2, 0, 0, 1
+AVX_INSTR pavgw, mmx2, 0, 0, 1
+AVX_INSTR pblendvb, sse4, 0, 1, 0 ; last operand must be xmm0 with legacy encoding
+AVX_INSTR pblendw, sse4, 0, 1, 0
+AVX_INSTR pclmulhqhqdq, clmul, 0, 0, 0
+AVX_INSTR pclmulhqlqdq, clmul, 0, 0, 0
+AVX_INSTR pclmullqhqdq, clmul, 0, 0, 0
+AVX_INSTR pclmullqlqdq, clmul, 0, 0, 0
+AVX_INSTR pclmulqdq, clmul, 0, 1, 0
+AVX_INSTR pcmpeqb, mmx, 0, 0, 1
+AVX_INSTR pcmpeqd, mmx, 0, 0, 1
+AVX_INSTR pcmpeqq, sse4, 0, 0, 1
+AVX_INSTR pcmpeqw, mmx, 0, 0, 1
+AVX_INSTR pcmpestri, sse42
+AVX_INSTR pcmpestrm, sse42
+AVX_INSTR pcmpgtb, mmx, 0, 0, 0
+AVX_INSTR pcmpgtd, mmx, 0, 0, 0
+AVX_INSTR pcmpgtq, sse42, 0, 0, 0
+AVX_INSTR pcmpgtw, mmx, 0, 0, 0
+AVX_INSTR pcmpistri, sse42
+AVX_INSTR pcmpistrm, sse42
+AVX_INSTR pextrb, sse4
+AVX_INSTR pextrd, sse4
+AVX_INSTR pextrq, sse4
+AVX_INSTR pextrw, mmx2
+AVX_INSTR phaddd, ssse3, 0, 0, 0
+AVX_INSTR phaddsw, ssse3, 0, 0, 0
+AVX_INSTR phaddw, ssse3, 0, 0, 0
+AVX_INSTR phminposuw, sse4
+AVX_INSTR phsubd, ssse3, 0, 0, 0
+AVX_INSTR phsubsw, ssse3, 0, 0, 0
+AVX_INSTR phsubw, ssse3, 0, 0, 0
+AVX_INSTR pinsrb, sse4, 0, 1, 0
+AVX_INSTR pinsrd, sse4, 0, 1, 0
+AVX_INSTR pinsrq, sse4, 0, 1, 0
+AVX_INSTR pinsrw, mmx2, 0, 1, 0
+AVX_INSTR pmaddubsw, ssse3, 0, 0, 0
+AVX_INSTR pmaddwd, mmx, 0, 0, 1
+AVX_INSTR pmaxsb, sse4, 0, 0, 1
+AVX_INSTR pmaxsd, sse4, 0, 0, 1
+AVX_INSTR pmaxsw, mmx2, 0, 0, 1
+AVX_INSTR pmaxub, mmx2, 0, 0, 1
+AVX_INSTR pmaxud, sse4, 0, 0, 1
+AVX_INSTR pmaxuw, sse4, 0, 0, 1
+AVX_INSTR pminsb, sse4, 0, 0, 1
+AVX_INSTR pminsd, sse4, 0, 0, 1
+AVX_INSTR pminsw, mmx2, 0, 0, 1
+AVX_INSTR pminub, mmx2, 0, 0, 1
+AVX_INSTR pminud, sse4, 0, 0, 1
+AVX_INSTR pminuw, sse4, 0, 0, 1
+AVX_INSTR pmovmskb, mmx2
+AVX_INSTR pmovsxbd, sse4
+AVX_INSTR pmovsxbq, sse4
+AVX_INSTR pmovsxbw, sse4
+AVX_INSTR pmovsxdq, sse4
+AVX_INSTR pmovsxwd, sse4
+AVX_INSTR pmovsxwq, sse4
+AVX_INSTR pmovzxbd, sse4
+AVX_INSTR pmovzxbq, sse4
+AVX_INSTR pmovzxbw, sse4
+AVX_INSTR pmovzxdq, sse4
+AVX_INSTR pmovzxwd, sse4
+AVX_INSTR pmovzxwq, sse4
+AVX_INSTR pmuldq, sse4, 0, 0, 1
+AVX_INSTR pmulhrsw, ssse3, 0, 0, 1
+AVX_INSTR pmulhuw, mmx2, 0, 0, 1
+AVX_INSTR pmulhw, mmx, 0, 0, 1
+AVX_INSTR pmulld, sse4, 0, 0, 1
+AVX_INSTR pmullw, mmx, 0, 0, 1
+AVX_INSTR pmuludq, sse2, 0, 0, 1
+AVX_INSTR por, mmx, 0, 0, 1
+AVX_INSTR psadbw, mmx2, 0, 0, 1
+AVX_INSTR pshufb, ssse3, 0, 0, 0
+AVX_INSTR pshufd, sse2
+AVX_INSTR pshufhw, sse2
+AVX_INSTR pshuflw, sse2
+AVX_INSTR psignb, ssse3, 0, 0, 0
+AVX_INSTR psignd, ssse3, 0, 0, 0
+AVX_INSTR psignw, ssse3, 0, 0, 0
+AVX_INSTR pslld, mmx, 0, 0, 0
+AVX_INSTR pslldq, sse2, 0, 0, 0
+AVX_INSTR psllq, mmx, 0, 0, 0
+AVX_INSTR psllw, mmx, 0, 0, 0
+AVX_INSTR psrad, mmx, 0, 0, 0
+AVX_INSTR psraw, mmx, 0, 0, 0
+AVX_INSTR psrld, mmx, 0, 0, 0
+AVX_INSTR psrldq, sse2, 0, 0, 0
+AVX_INSTR psrlq, mmx, 0, 0, 0
+AVX_INSTR psrlw, mmx, 0, 0, 0
+AVX_INSTR psubb, mmx, 0, 0, 0
+AVX_INSTR psubd, mmx, 0, 0, 0
+AVX_INSTR psubq, sse2, 0, 0, 0
+AVX_INSTR psubsb, mmx, 0, 0, 0
+AVX_INSTR psubsw, mmx, 0, 0, 0
+AVX_INSTR psubusb, mmx, 0, 0, 0
+AVX_INSTR psubusw, mmx, 0, 0, 0
+AVX_INSTR psubw, mmx, 0, 0, 0
+AVX_INSTR ptest, sse4
+AVX_INSTR punpckhbw, mmx, 0, 0, 0
+AVX_INSTR punpckhdq, mmx, 0, 0, 0
+AVX_INSTR punpckhqdq, sse2, 0, 0, 0
+AVX_INSTR punpckhwd, mmx, 0, 0, 0
+AVX_INSTR punpcklbw, mmx, 0, 0, 0
+AVX_INSTR punpckldq, mmx, 0, 0, 0
+AVX_INSTR punpcklqdq, sse2, 0, 0, 0
+AVX_INSTR punpcklwd, mmx, 0, 0, 0
+AVX_INSTR pxor, mmx, 0, 0, 1
+AVX_INSTR rcpps, sse, 1
+AVX_INSTR rcpss, sse, 1, 0, 0
+AVX_INSTR roundpd, sse4, 1
+AVX_INSTR roundps, sse4, 1
+AVX_INSTR roundsd, sse4, 1, 1, 0
+AVX_INSTR roundss, sse4, 1, 1, 0
+AVX_INSTR rsqrtps, sse, 1
+AVX_INSTR rsqrtss, sse, 1, 0, 0
+AVX_INSTR shufpd, sse2, 1, 1, 0
+AVX_INSTR shufps, sse, 1, 1, 0
+AVX_INSTR sqrtpd, sse2, 1
+AVX_INSTR sqrtps, sse, 1
+AVX_INSTR sqrtsd, sse2, 1, 0, 0
+AVX_INSTR sqrtss, sse, 1, 0, 0
+AVX_INSTR stmxcsr, sse, 1
+AVX_INSTR subpd, sse2, 1, 0, 0
+AVX_INSTR subps, sse, 1, 0, 0
+AVX_INSTR subsd, sse2, 1, 0, 0
+AVX_INSTR subss, sse, 1, 0, 0
+AVX_INSTR ucomisd, sse2, 1
+AVX_INSTR ucomiss, sse, 1
+AVX_INSTR unpckhpd, sse2, 1, 0, 0
+AVX_INSTR unpckhps, sse, 1, 0, 0
+AVX_INSTR unpcklpd, sse2, 1, 0, 0
+AVX_INSTR unpcklps, sse, 1, 0, 0
+AVX_INSTR xorpd, sse2, 1, 0, 1
+AVX_INSTR xorps, sse, 1, 0, 1
+
+; 3DNow instructions, for sharing code between AVX, SSE and 3DN
+AVX_INSTR pfadd, 3dnow, 1, 0, 1
+AVX_INSTR pfmul, 3dnow, 1, 0, 1
+AVX_INSTR pfsub, 3dnow, 1, 0, 0
+
+;%1 == instruction
+;%2 == minimal instruction set
+%macro GPR_INSTR 2
+    %macro %1 2-5 fnord, %1, %2
+        %ifdef cpuname
+            %if notcpuflag(%5)
+                %error use of ``%4'' %5 instruction in cpuname function: current_function
+            %endif
+        %endif
+        %ifidn %3, fnord
+            %4 %1, %2
+        %else
+            %4 %1, %2, %3
+        %endif
+    %endmacro
+%endmacro
+
+GPR_INSTR andn, bmi1
+GPR_INSTR bextr, bmi1
+GPR_INSTR blsi, bmi1
+GPR_INSTR blsmsk, bmi1
+GPR_INSTR blsr, bmi1
+GPR_INSTR bzhi, bmi2
+GPR_INSTR crc32, sse42
+GPR_INSTR mulx, bmi2
+GPR_INSTR pdep, bmi2
+GPR_INSTR pext, bmi2
+GPR_INSTR popcnt, sse42
+GPR_INSTR rorx, bmi2
+GPR_INSTR sarx, bmi2
+GPR_INSTR shlx, bmi2
+GPR_INSTR shrx, bmi2
+
+; base-4 constants for shuffles
+%assign i 0
+%rep 256
+    %assign j ((i>>6)&3)*1000 + ((i>>4)&3)*100 + ((i>>2)&3)*10 + (i&3)
+    %if j < 10
+        CAT_XDEFINE q000, j, i
+    %elif j < 100
+        CAT_XDEFINE q00, j, i
+    %elif j < 1000
+        CAT_XDEFINE q0, j, i
+    %else
+        CAT_XDEFINE q, j, i
+    %endif
+    %assign i i+1
+%endrep
+%undef i
+%undef j
+
+%macro FMA_INSTR 3
+    %macro %1 4-7 %1, %2, %3
+        %if cpuflag(xop)
+            v%5 %1, %2, %3, %4
+        %elifnidn %1, %4
+            %6 %1, %2, %3
+            %7 %1, %4
+        %else
+            %error non-xop emulation of ``%5 %1, %2, %3, %4'' is not supported
+        %endif
+    %endmacro
+%endmacro
+
+FMA_INSTR pmacsdd,  pmulld,  paddd ; sse4 emulation
+FMA_INSTR pmacsdql, pmuldq,  paddq ; sse4 emulation
+FMA_INSTR pmacsww,  pmullw,  paddw
+FMA_INSTR pmadcswd, pmaddwd, paddd
+
+; Macros for consolidating FMA3 and FMA4 using 4-operand (dst, src1, src2, src3) syntax.
+; FMA3 is only possible if dst is the same as one of the src registers.
+; Either src2 or src3 can be a memory operand.
+%macro FMA4_INSTR 2-*
+    %push fma4_instr
+    %xdefine %$prefix %1
+    %rep %0 - 1
+        %macro %$prefix%2 4-6 %$prefix, %2
+            %if notcpuflag(fma3) && notcpuflag(fma4)
+                %error use of ``%5%6'' fma instruction in cpuname function: current_function
+            %elif cpuflag(fma4)
+                v%5%6 %1, %2, %3, %4
+            %elifidn %1, %2
+                ; If %3 or %4 is a memory operand it needs to be encoded as the last operand.
+                %ifnum sizeof%3
+                    v%{5}213%6 %2, %3, %4
+                %else
+                    v%{5}132%6 %2, %4, %3
+                %endif
+            %elifidn %1, %3
+                v%{5}213%6 %3, %2, %4
+            %elifidn %1, %4
+                v%{5}231%6 %4, %2, %3
+            %else
+                %error fma3 emulation of ``%5%6 %1, %2, %3, %4'' is not supported
+            %endif
+        %endmacro
+        %rotate 1
+    %endrep
+    %pop
+%endmacro
+
+FMA4_INSTR fmadd,    pd, ps, sd, ss
+FMA4_INSTR fmaddsub, pd, ps
+FMA4_INSTR fmsub,    pd, ps, sd, ss
+FMA4_INSTR fmsubadd, pd, ps
+FMA4_INSTR fnmadd,   pd, ps, sd, ss
+FMA4_INSTR fnmsub,   pd, ps, sd, ss
+
+; Macros for converting VEX instructions to equivalent EVEX ones.
+%macro EVEX_INSTR 2-3 0 ; vex, evex, prefer_evex
+    %macro %1 2-7 fnord, fnord, %1, %2, %3
+        %ifidn %3, fnord
+            %define %%args %1, %2
+        %elifidn %4, fnord
+            %define %%args %1, %2, %3
+        %else
+            %define %%args %1, %2, %3, %4
+        %endif
+        %assign %%evex_required cpuflag(avx512) & %7
+        %ifnum regnumof%1
+            %if regnumof%1 >= 16 || sizeof%1 > 32
+                %assign %%evex_required 1
+            %endif
+        %endif
+        %ifnum regnumof%2
+            %if regnumof%2 >= 16 || sizeof%2 > 32
+                %assign %%evex_required 1
+            %endif
+        %endif
+        %ifnum regnumof%3
+            %if regnumof%3 >= 16 || sizeof%3 > 32
+                %assign %%evex_required 1
+            %endif
+        %endif
+        %if %%evex_required
+            %6 %%args
+        %else
+            %5 %%args ; Prefer VEX over EVEX due to shorter instruction length
+        %endif
+    %endmacro
+%endmacro
+
+EVEX_INSTR vbroadcastf128, vbroadcastf32x4
+EVEX_INSTR vbroadcasti128, vbroadcasti32x4
+EVEX_INSTR vextractf128,   vextractf32x4
+EVEX_INSTR vextracti128,   vextracti32x4
+EVEX_INSTR vinsertf128,    vinsertf32x4
+EVEX_INSTR vinserti128,    vinserti32x4
+EVEX_INSTR vmovdqa,        vmovdqa32
+EVEX_INSTR vmovdqu,        vmovdqu32
+EVEX_INSTR vpand,          vpandd
+EVEX_INSTR vpandn,         vpandnd
+EVEX_INSTR vpor,           vpord
+EVEX_INSTR vpxor,          vpxord
+EVEX_INSTR vrcpps,         vrcp14ps,   1 ; EVEX versions have higher precision
+EVEX_INSTR vrcpss,         vrcp14ss,   1
+EVEX_INSTR vrsqrtps,       vrsqrt14ps, 1
+EVEX_INSTR vrsqrtss,       vrsqrt14ss, 1
diff --git a/media/libdav1d/src/src/fg_apply.h b/media/libdav1d/src/src/fg_apply.h
new file mode 100644
index 0000000000..be6685d801
--- /dev/null
+++ b/media/libdav1d/src/src/fg_apply.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_FG_APPLY_H
+#define DAV1D_SRC_FG_APPLY_H
+
+#include "dav1d/picture.h"
+
+#include "common/bitdepth.h"
+
+#include "src/filmgrain.h"
+
+#ifdef BITDEPTH
+# define array_decl(type, name, sz) type name sz
+#else
+# define array_decl(type, name, sz) void *name
+#endif
+
+bitfn_decls(void dav1d_apply_grain,
+            const Dav1dFilmGrainDSPContext *const dsp,
+            Dav1dPicture *const out, const Dav1dPicture *const in);
+bitfn_decls(void dav1d_prep_grain,
+            const Dav1dFilmGrainDSPContext *const dsp,
+            Dav1dPicture *const out, const Dav1dPicture *const in,
+            array_decl(uint8_t, scaling, [3][SCALING_SIZE]),
+            array_decl(entry, grain_lut, [3][GRAIN_HEIGHT+1][GRAIN_WIDTH]));
+bitfn_decls(void dav1d_apply_grain_row,
+            const Dav1dFilmGrainDSPContext *const dsp,
+            Dav1dPicture *const out, const Dav1dPicture *const in,
+            array_decl(const uint8_t, scaling, [3][SCALING_SIZE]),
+            array_decl(const entry, grain_lut, [3][GRAIN_HEIGHT+1][GRAIN_WIDTH]),
+            const int row);
+
+#endif /* DAV1D_SRC_FG_APPLY_H */
diff --git a/media/libdav1d/src/src/fg_apply_tmpl.c b/media/libdav1d/src/src/fg_apply_tmpl.c
new file mode 100644
index 0000000000..044e257de9
--- /dev/null
+++ b/media/libdav1d/src/src/fg_apply_tmpl.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright © 2018, Niklas Haas
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "dav1d/common.h"
+#include "dav1d/picture.h"
+
+#include "common/intops.h"
+#include "common/bitdepth.h"
+
+#include "src/fg_apply.h"
+
+static void generate_scaling(const int bitdepth,
+                             const uint8_t points[][2], const int num,
+                             uint8_t scaling[SCALING_SIZE])
+{
+#if BITDEPTH == 8
+    const int shift_x = 0;
+    const int scaling_size = SCALING_SIZE;
+#else
+    assert(bitdepth > 8);
+    const int shift_x = bitdepth - 8;
+    const int scaling_size = 1 << bitdepth;
+#endif
+
+    if (num == 0) {
+        memset(scaling, 0, scaling_size);
+        return;
+    }
+
+    // Fill up the preceding entries with the initial value
+    memset(scaling, points[0][1], points[0][0] << shift_x);
+
+    // Linearly interpolate the values in the middle
+    for (int i = 0; i < num - 1; i++) {
+        const int bx = points[i][0];
+        const int by = points[i][1];
+        const int ex = points[i+1][0];
+        const int ey = points[i+1][1];
+        const int dx = ex - bx;
+        const int dy = ey - by;
+        assert(dx > 0);
+        const int delta = dy * ((0x10000 + (dx >> 1)) / dx);
+        for (int x = 0, d = 0x8000; x < dx; x++) {
+            scaling[(bx + x) << shift_x] = by + (d >> 16);
+            d += delta;
+        }
+    }
+
+    // Fill up the remaining entries with the final value
+    const int n = points[num - 1][0] << shift_x;
+    memset(&scaling[n], points[num - 1][1], scaling_size - n);
+
+#if BITDEPTH != 8
+    const int pad = 1 << shift_x, rnd = pad >> 1;
+    for (int i = 0; i < num - 1; i++) {
+        const int bx = points[i][0] << shift_x;
+        const int ex = points[i+1][0] << shift_x;
+        const int dx = ex - bx;
+        for (int x = 0; x < dx; x += pad) {
+            const int range = scaling[bx + x + pad] - scaling[bx + x];
+            for (int n = 1, r = rnd; n < pad; n++) {
+                r += range;
+                scaling[bx + x + n] = scaling[bx + x] + (r >> shift_x);
+            }
+        }
+    }
+#endif
+}
+
+#ifndef UNIT_TEST
+void bitfn(dav1d_prep_grain)(const Dav1dFilmGrainDSPContext *const dsp,
+                             Dav1dPicture *const out,
+                             const Dav1dPicture *const in,
+                             uint8_t scaling[3][SCALING_SIZE],
+                             entry grain_lut[3][GRAIN_HEIGHT+1][GRAIN_WIDTH])
+{
+    const Dav1dFilmGrainData *const data = &out->frame_hdr->film_grain.data;
+#if BITDEPTH != 8
+    const int bitdepth_max = (1 << out->p.bpc) - 1;
+#endif
+
+    // Generate grain LUTs as needed
+    dsp->generate_grain_y(grain_lut[0], data HIGHBD_TAIL_SUFFIX); // always needed
+    if (data->num_uv_points[0] || data->chroma_scaling_from_luma)
+        dsp->generate_grain_uv[in->p.layout - 1](grain_lut[1], grain_lut[0],
+                                                 data, 0 HIGHBD_TAIL_SUFFIX);
+    if (data->num_uv_points[1] || data->chroma_scaling_from_luma)
+        dsp->generate_grain_uv[in->p.layout - 1](grain_lut[2], grain_lut[0],
+                                                 data, 1 HIGHBD_TAIL_SUFFIX);
+
+    // Generate scaling LUTs as needed
+    if (data->num_y_points || data->chroma_scaling_from_luma)
+        generate_scaling(in->p.bpc, data->y_points, data->num_y_points, scaling[0]);
+    if (data->num_uv_points[0])
+        generate_scaling(in->p.bpc, data->uv_points[0], data->num_uv_points[0], scaling[1]);
+    if (data->num_uv_points[1])
+        generate_scaling(in->p.bpc, data->uv_points[1], data->num_uv_points[1], scaling[2]);
+
+    // Copy over the non-modified planes
+    assert(out->stride[0] == in->stride[0]);
+    if (!data->num_y_points) {
+        const ptrdiff_t stride = out->stride[0];
+        const ptrdiff_t sz = out->p.h * stride;
+        if (sz < 0)
+            memcpy((uint8_t*) out->data[0] + sz - stride,
+                   (uint8_t*) in->data[0] + sz - stride, -sz);
+        else
+            memcpy(out->data[0], in->data[0], sz);
+    }
+
+    if (in->p.layout != DAV1D_PIXEL_LAYOUT_I400 && !data->chroma_scaling_from_luma) {
+        assert(out->stride[1] == in->stride[1]);
+        const int ss_ver = in->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const ptrdiff_t stride = out->stride[1];
+        const ptrdiff_t sz = ((out->p.h + ss_ver) >> ss_ver) * stride;
+        if (sz < 0) {
+            if (!data->num_uv_points[0])
+                memcpy((uint8_t*) out->data[1] + sz - stride,
+                       (uint8_t*) in->data[1] + sz - stride, -sz);
+            if (!data->num_uv_points[1])
+                memcpy((uint8_t*) out->data[2] + sz - stride,
+                       (uint8_t*) in->data[2] + sz - stride, -sz);
+        } else {
+            if (!data->num_uv_points[0])
+                memcpy(out->data[1], in->data[1], sz);
+            if (!data->num_uv_points[1])
+                memcpy(out->data[2], in->data[2], sz);
+        }
+    }
+}
+
+void bitfn(dav1d_apply_grain_row)(const Dav1dFilmGrainDSPContext *const dsp,
+                                  Dav1dPicture *const out,
+                                  const Dav1dPicture *const in,
+                                  const uint8_t scaling[3][SCALING_SIZE],
+                                  const entry grain_lut[3][GRAIN_HEIGHT+1][GRAIN_WIDTH],
+                                  const int row)
+{
+    // Synthesize grain for the affected planes
+    const Dav1dFilmGrainData *const data = &out->frame_hdr->film_grain.data;
+    const int ss_y = in->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_x = in->p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int cpw = (out->p.w + ss_x) >> ss_x;
+    const int is_id = out->seq_hdr->mtrx == DAV1D_MC_IDENTITY;
+    pixel *const luma_src =
+        ((pixel *) in->data[0]) + row * FG_BLOCK_SIZE * PXSTRIDE(in->stride[0]);
+#if BITDEPTH != 8
+    const int bitdepth_max = (1 << out->p.bpc) - 1;
+#endif
+
+    if (data->num_y_points) {
+        const int bh = imin(out->p.h - row * FG_BLOCK_SIZE, FG_BLOCK_SIZE);
+        dsp->fgy_32x32xn(((pixel *) out->data[0]) + row * FG_BLOCK_SIZE * PXSTRIDE(out->stride[0]),
+                         luma_src, out->stride[0], data,
+                         out->p.w, scaling[0], grain_lut[0], bh, row HIGHBD_TAIL_SUFFIX);
+    }
+
+    if (!data->num_uv_points[0] && !data->num_uv_points[1] &&
+        !data->chroma_scaling_from_luma)
+    {
+        return;
+    }
+
+    const int bh = (imin(out->p.h - row * FG_BLOCK_SIZE, FG_BLOCK_SIZE) + ss_y) >> ss_y;
+
+    // extend padding pixels
+    if (out->p.w & ss_x) {
+        pixel *ptr = luma_src;
+        for (int y = 0; y < bh; y++) {
+            ptr[out->p.w] = ptr[out->p.w - 1];
+            ptr += PXSTRIDE(in->stride[0]) << ss_y;
+        }
+    }
+
+    const ptrdiff_t uv_off = row * FG_BLOCK_SIZE * PXSTRIDE(out->stride[1]) >> ss_y;
+    if (data->chroma_scaling_from_luma) {
+        for (int pl = 0; pl < 2; pl++)
+            dsp->fguv_32x32xn[in->p.layout - 1](((pixel *) out->data[1 + pl]) + uv_off,
+                                                ((const pixel *) in->data[1 + pl]) + uv_off,
+                                                in->stride[1], data, cpw,
+                                                scaling[0], grain_lut[1 + pl],
+                                                bh, row, luma_src, in->stride[0],
+                                                pl, is_id HIGHBD_TAIL_SUFFIX);
+    } else {
+        for (int pl = 0; pl < 2; pl++)
+            if (data->num_uv_points[pl])
+                dsp->fguv_32x32xn[in->p.layout - 1](((pixel *) out->data[1 + pl]) + uv_off,
+                                                    ((const pixel *) in->data[1 + pl]) + uv_off,
+                                                    in->stride[1], data, cpw,
+                                                    scaling[1 + pl], grain_lut[1 + pl],
+                                                    bh, row, luma_src, in->stride[0],
+                                                    pl, is_id HIGHBD_TAIL_SUFFIX);
+    }
+}
+
+void bitfn(dav1d_apply_grain)(const Dav1dFilmGrainDSPContext *const dsp,
+                              Dav1dPicture *const out,
+                              const Dav1dPicture *const in)
+{
+    ALIGN_STK_16(entry, grain_lut, 3,[GRAIN_HEIGHT + 1][GRAIN_WIDTH]);
+#if ARCH_X86_64 && BITDEPTH == 8
+    ALIGN_STK_64(uint8_t, scaling, 3,[SCALING_SIZE]);
+#else
+    uint8_t scaling[3][SCALING_SIZE];
+#endif
+    const int rows = (out->p.h + FG_BLOCK_SIZE - 1) / FG_BLOCK_SIZE;
+
+    bitfn(dav1d_prep_grain)(dsp, out, in, scaling, grain_lut);
+    for (int row = 0; row < rows; row++)
+        bitfn(dav1d_apply_grain_row)(dsp, out, in, scaling, grain_lut, row);
+}
+#endif
diff --git a/media/libdav1d/src/src/filmgrain.h b/media/libdav1d/src/src/filmgrain.h
new file mode 100644
index 0000000000..1509bb67e1
--- /dev/null
+++ b/media/libdav1d/src/src/filmgrain.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_FILM_GRAIN_H
+#define DAV1D_SRC_FILM_GRAIN_H
+
+#include "common/bitdepth.h"
+
+#include "src/levels.h"
+
+#define GRAIN_WIDTH 82
+#define GRAIN_HEIGHT 73
+#define FG_BLOCK_SIZE 32
+#if !defined(BITDEPTH) || BITDEPTH == 8
+#define SCALING_SIZE 256
+typedef int8_t entry;
+#else
+#define SCALING_SIZE 4096
+typedef int16_t entry;
+#endif
+
+#define decl_generate_grain_y_fn(name) \
+void (name)(entry buf[][GRAIN_WIDTH], \
+            const Dav1dFilmGrainData *const data HIGHBD_DECL_SUFFIX)
+typedef decl_generate_grain_y_fn(*generate_grain_y_fn);
+
+#define decl_generate_grain_uv_fn(name) \
+void (name)(entry buf[][GRAIN_WIDTH], \
+            const entry buf_y[][GRAIN_WIDTH], \
+            const Dav1dFilmGrainData *const data, const intptr_t uv HIGHBD_DECL_SUFFIX)
+typedef decl_generate_grain_uv_fn(*generate_grain_uv_fn);
+
+#define decl_fgy_32x32xn_fn(name) \
+void (name)(pixel *dst_row, const pixel *src_row, ptrdiff_t stride, \
+            const Dav1dFilmGrainData *data, \
+            size_t pw, const uint8_t scaling[SCALING_SIZE], \
+            const entry grain_lut[][GRAIN_WIDTH], \
+            int bh, int row_num HIGHBD_DECL_SUFFIX)
+typedef decl_fgy_32x32xn_fn(*fgy_32x32xn_fn);
+
+#define decl_fguv_32x32xn_fn(name) \
+void (name)(pixel *dst_row, const pixel *src_row, ptrdiff_t stride, \
+            const Dav1dFilmGrainData *data, size_t pw, \
+            const uint8_t scaling[SCALING_SIZE], \
+            const entry grain_lut[][GRAIN_WIDTH], int bh, int row_num, \
+            const pixel *luma_row, ptrdiff_t luma_stride, \
+            int uv_pl, int is_id HIGHBD_DECL_SUFFIX)
+typedef decl_fguv_32x32xn_fn(*fguv_32x32xn_fn);
+
+typedef struct Dav1dFilmGrainDSPContext {
+    generate_grain_y_fn generate_grain_y;
+    generate_grain_uv_fn generate_grain_uv[3];
+
+    fgy_32x32xn_fn fgy_32x32xn;
+    fguv_32x32xn_fn fguv_32x32xn[3];
+} Dav1dFilmGrainDSPContext;
+
+bitfn_decls(void dav1d_film_grain_dsp_init, Dav1dFilmGrainDSPContext *c);
+
+#endif /* DAV1D_SRC_FILM_GRAIN_H */
diff --git a/media/libdav1d/src/src/filmgrain_tmpl.c b/media/libdav1d/src/src/filmgrain_tmpl.c
new file mode 100644
index 0000000000..12e91dd661
--- /dev/null
+++ b/media/libdav1d/src/src/filmgrain_tmpl.c
@@ -0,0 +1,441 @@
+/*
+ * Copyright © 2018, Niklas Haas
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "src/filmgrain.h"
+#include "src/tables.h"
+
+#define SUB_GRAIN_WIDTH 44
+#define SUB_GRAIN_HEIGHT 38
+
+static inline int get_random_number(const int bits, unsigned *const state) {
+    const int r = *state;
+    unsigned bit = ((r >> 0) ^ (r >> 1) ^ (r >> 3) ^ (r >> 12)) & 1;
+    *state = (r >> 1) | (bit << 15);
+
+    return (*state >> (16 - bits)) & ((1 << bits) - 1);
+}
+
+static inline int round2(const int x, const uint64_t shift) {
+    return (x + ((1 << shift) >> 1)) >> shift;
+}
+
+static void generate_grain_y_c(entry buf[][GRAIN_WIDTH],
+                               const Dav1dFilmGrainData *const data
+                               HIGHBD_DECL_SUFFIX)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    unsigned seed = data->seed;
+    const int shift = 4 - bitdepth_min_8 + data->grain_scale_shift;
+    const int grain_ctr = 128 << bitdepth_min_8;
+    const int grain_min = -grain_ctr, grain_max = grain_ctr - 1;
+
+    for (int y = 0; y < GRAIN_HEIGHT; y++) {
+        for (int x = 0; x < GRAIN_WIDTH; x++) {
+            const int value = get_random_number(11, &seed);
+            buf[y][x] = round2(dav1d_gaussian_sequence[ value ], shift);
+        }
+    }
+
+    const int ar_pad = 3;
+    const int ar_lag = data->ar_coeff_lag;
+
+    for (int y = ar_pad; y < GRAIN_HEIGHT; y++) {
+        for (int x = ar_pad; x < GRAIN_WIDTH - ar_pad; x++) {
+            const int8_t *coeff = data->ar_coeffs_y;
+            int sum = 0;
+            for (int dy = -ar_lag; dy <= 0; dy++) {
+                for (int dx = -ar_lag; dx <= ar_lag; dx++) {
+                    if (!dx && !dy)
+                        break;
+                    sum += *(coeff++) * buf[y + dy][x + dx];
+                }
+            }
+
+            const int grain = buf[y][x] + round2(sum, data->ar_coeff_shift);
+            buf[y][x] = iclip(grain, grain_min, grain_max);
+        }
+    }
+}
+
+static NOINLINE void
+generate_grain_uv_c(entry buf[][GRAIN_WIDTH],
+                    const entry buf_y[][GRAIN_WIDTH],
+                    const Dav1dFilmGrainData *const data, const intptr_t uv,
+                    const int subx, const int suby HIGHBD_DECL_SUFFIX)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    unsigned seed = data->seed ^ (uv ? 0x49d8 : 0xb524);
+    const int shift = 4 - bitdepth_min_8 + data->grain_scale_shift;
+    const int grain_ctr = 128 << bitdepth_min_8;
+    const int grain_min = -grain_ctr, grain_max = grain_ctr - 1;
+
+    const int chromaW = subx ? SUB_GRAIN_WIDTH  : GRAIN_WIDTH;
+    const int chromaH = suby ? SUB_GRAIN_HEIGHT : GRAIN_HEIGHT;
+
+    for (int y = 0; y < chromaH; y++) {
+        for (int x = 0; x < chromaW; x++) {
+            const int value = get_random_number(11, &seed);
+            buf[y][x] = round2(dav1d_gaussian_sequence[ value ], shift);
+        }
+    }
+
+    const int ar_pad = 3;
+    const int ar_lag = data->ar_coeff_lag;
+
+    for (int y = ar_pad; y < chromaH; y++) {
+        for (int x = ar_pad; x < chromaW - ar_pad; x++) {
+            const int8_t *coeff = data->ar_coeffs_uv[uv];
+            int sum = 0;
+            for (int dy = -ar_lag; dy <= 0; dy++) {
+                for (int dx = -ar_lag; dx <= ar_lag; dx++) {
+                    // For the final (current) pixel, we need to add in the
+                    // contribution from the luma grain texture
+                    if (!dx && !dy) {
+                        if (!data->num_y_points)
+                            break;
+                        int luma = 0;
+                        const int lumaX = ((x - ar_pad) << subx) + ar_pad;
+                        const int lumaY = ((y - ar_pad) << suby) + ar_pad;
+                        for (int i = 0; i <= suby; i++) {
+                            for (int j = 0; j <= subx; j++) {
+                                luma += buf_y[lumaY + i][lumaX + j];
+                            }
+                        }
+                        luma = round2(luma, subx + suby);
+                        sum += luma * (*coeff);
+                        break;
+                    }
+
+                    sum += *(coeff++) * buf[y + dy][x + dx];
+                }
+            }
+
+            const int grain = buf[y][x] + round2(sum, data->ar_coeff_shift);
+            buf[y][x] = iclip(grain, grain_min, grain_max);
+        }
+    }
+}
+
+#define gnuv_ss_fn(nm, ss_x, ss_y) \
+static decl_generate_grain_uv_fn(generate_grain_uv_##nm##_c) { \
+    generate_grain_uv_c(buf, buf_y, data, uv, ss_x, ss_y HIGHBD_TAIL_SUFFIX); \
+}
+
+gnuv_ss_fn(420, 1, 1);
+gnuv_ss_fn(422, 1, 0);
+gnuv_ss_fn(444, 0, 0);
+
+// samples from the correct block of a grain LUT, while taking into account the
+// offsets provided by the offsets cache
+static inline entry sample_lut(const entry grain_lut[][GRAIN_WIDTH],
+                               const int offsets[2][2], const int subx, const int suby,
+                               const int bx, const int by, const int x, const int y)
+{
+    const int randval = offsets[bx][by];
+    const int offx = 3 + (2 >> subx) * (3 + (randval >> 4));
+    const int offy = 3 + (2 >> suby) * (3 + (randval & 0xF));
+    return grain_lut[offy + y + (FG_BLOCK_SIZE >> suby) * by]
+                    [offx + x + (FG_BLOCK_SIZE >> subx) * bx];
+}
+
+static void fgy_32x32xn_c(pixel *const dst_row, const pixel *const src_row,
+                          const ptrdiff_t stride,
+                          const Dav1dFilmGrainData *const data, const size_t pw,
+                          const uint8_t scaling[SCALING_SIZE],
+                          const entry grain_lut[][GRAIN_WIDTH],
+                          const int bh, const int row_num HIGHBD_DECL_SUFFIX)
+{
+    const int rows = 1 + (data->overlap_flag && row_num > 0);
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    const int grain_ctr = 128 << bitdepth_min_8;
+    const int grain_min = -grain_ctr, grain_max = grain_ctr - 1;
+
+    int min_value, max_value;
+    if (data->clip_to_restricted_range) {
+        min_value = 16 << bitdepth_min_8;
+        max_value = 235 << bitdepth_min_8;
+    } else {
+        min_value = 0;
+        max_value = BITDEPTH_MAX;
+    }
+
+    // seed[0] contains the current row, seed[1] contains the previous
+    unsigned seed[2];
+    for (int i = 0; i < rows; i++) {
+        seed[i] = data->seed;
+        seed[i] ^= (((row_num - i) * 37  + 178) & 0xFF) << 8;
+        seed[i] ^= (((row_num - i) * 173 + 105) & 0xFF);
+    }
+
+    assert(stride % (FG_BLOCK_SIZE * sizeof(pixel)) == 0);
+
+    int offsets[2 /* col offset */][2 /* row offset */];
+
+    // process this row in FG_BLOCK_SIZE^2 blocks
+    for (unsigned bx = 0; bx < pw; bx += FG_BLOCK_SIZE) {
+        const int bw = imin(FG_BLOCK_SIZE, (int) pw - bx);
+
+        if (data->overlap_flag && bx) {
+            // shift previous offsets left
+            for (int i = 0; i < rows; i++)
+                offsets[1][i] = offsets[0][i];
+        }
+
+        // update current offsets
+        for (int i = 0; i < rows; i++)
+            offsets[0][i] = get_random_number(8, &seed[i]);
+
+        // x/y block offsets to compensate for overlapped regions
+        const int ystart = data->overlap_flag && row_num ? imin(2, bh) : 0;
+        const int xstart = data->overlap_flag && bx      ? imin(2, bw) : 0;
+
+        static const int w[2][2] = { { 27, 17 }, { 17, 27 } };
+
+#define add_noise_y(x, y, grain)                                                  \
+        const pixel *const src = src_row + (y) * PXSTRIDE(stride) + (x) + bx;     \
+        pixel *const dst = dst_row + (y) * PXSTRIDE(stride) + (x) + bx;           \
+        const int noise = round2(scaling[ *src ] * (grain), data->scaling_shift); \
+        *dst = iclip(*src + noise, min_value, max_value);
+
+        for (int y = ystart; y < bh; y++) {
+            // Non-overlapped image region (straightforward)
+            for (int x = xstart; x < bw; x++) {
+                int grain = sample_lut(grain_lut, offsets, 0, 0, 0, 0, x, y);
+                add_noise_y(x, y, grain);
+            }
+
+            // Special case for overlapped column
+            for (int x = 0; x < xstart; x++) {
+                int grain = sample_lut(grain_lut, offsets, 0, 0, 0, 0, x, y);
+                int old   = sample_lut(grain_lut, offsets, 0, 0, 1, 0, x, y);
+                grain = round2(old * w[x][0] + grain * w[x][1], 5);
+                grain = iclip(grain, grain_min, grain_max);
+                add_noise_y(x, y, grain);
+            }
+        }
+
+        for (int y = 0; y < ystart; y++) {
+            // Special case for overlapped row (sans corner)
+            for (int x = xstart; x < bw; x++) {
+                int grain = sample_lut(grain_lut, offsets, 0, 0, 0, 0, x, y);
+                int old   = sample_lut(grain_lut, offsets, 0, 0, 0, 1, x, y);
+                grain = round2(old * w[y][0] + grain * w[y][1], 5);
+                grain = iclip(grain, grain_min, grain_max);
+                add_noise_y(x, y, grain);
+            }
+
+            // Special case for doubly-overlapped corner
+            for (int x = 0; x < xstart; x++) {
+                // Blend the top pixel with the top left block
+                int top = sample_lut(grain_lut, offsets, 0, 0, 0, 1, x, y);
+                int old = sample_lut(grain_lut, offsets, 0, 0, 1, 1, x, y);
+                top = round2(old * w[x][0] + top * w[x][1], 5);
+                top = iclip(top, grain_min, grain_max);
+
+                // Blend the current pixel with the left block
+                int grain = sample_lut(grain_lut, offsets, 0, 0, 0, 0, x, y);
+                old = sample_lut(grain_lut, offsets, 0, 0, 1, 0, x, y);
+                grain = round2(old * w[x][0] + grain * w[x][1], 5);
+                grain = iclip(grain, grain_min, grain_max);
+
+                // Mix the row rows together and apply grain
+                grain = round2(top * w[y][0] + grain * w[y][1], 5);
+                grain = iclip(grain, grain_min, grain_max);
+                add_noise_y(x, y, grain);
+            }
+        }
+    }
+}
+
+static NOINLINE void
+fguv_32x32xn_c(pixel *const dst_row, const pixel *const src_row,
+               const ptrdiff_t stride, const Dav1dFilmGrainData *const data,
+               const size_t pw, const uint8_t scaling[SCALING_SIZE],
+               const entry grain_lut[][GRAIN_WIDTH], const int bh,
+               const int row_num, const pixel *const luma_row,
+               const ptrdiff_t luma_stride, const int uv, const int is_id,
+               const int sx, const int sy HIGHBD_DECL_SUFFIX)
+{
+    const int rows = 1 + (data->overlap_flag && row_num > 0);
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    const int grain_ctr = 128 << bitdepth_min_8;
+    const int grain_min = -grain_ctr, grain_max = grain_ctr - 1;
+
+    int min_value, max_value;
+    if (data->clip_to_restricted_range) {
+        min_value = 16 << bitdepth_min_8;
+        max_value = (is_id ? 235 : 240) << bitdepth_min_8;
+    } else {
+        min_value = 0;
+        max_value = BITDEPTH_MAX;
+    }
+
+    // seed[0] contains the current row, seed[1] contains the previous
+    unsigned seed[2];
+    for (int i = 0; i < rows; i++) {
+        seed[i] = data->seed;
+        seed[i] ^= (((row_num - i) * 37  + 178) & 0xFF) << 8;
+        seed[i] ^= (((row_num - i) * 173 + 105) & 0xFF);
+    }
+
+    assert(stride % (FG_BLOCK_SIZE * sizeof(pixel)) == 0);
+
+    int offsets[2 /* col offset */][2 /* row offset */];
+
+    // process this row in FG_BLOCK_SIZE^2 blocks (subsampled)
+    for (unsigned bx = 0; bx < pw; bx += FG_BLOCK_SIZE >> sx) {
+        const int bw = imin(FG_BLOCK_SIZE >> sx, (int)(pw - bx));
+        if (data->overlap_flag && bx) {
+            // shift previous offsets left
+            for (int i = 0; i < rows; i++)
+                offsets[1][i] = offsets[0][i];
+        }
+
+        // update current offsets
+        for (int i = 0; i < rows; i++)
+            offsets[0][i] = get_random_number(8, &seed[i]);
+
+        // x/y block offsets to compensate for overlapped regions
+        const int ystart = data->overlap_flag && row_num ? imin(2 >> sy, bh) : 0;
+        const int xstart = data->overlap_flag && bx      ? imin(2 >> sx, bw) : 0;
+
+        static const int w[2 /* sub */][2 /* off */][2] = {
+            { { 27, 17 }, { 17, 27 } },
+            { { 23, 22 } },
+        };
+
+#define add_noise_uv(x, y, grain)                                                    \
+            const int lx = (bx + x) << sx;                                           \
+            const int ly = y << sy;                                                  \
+            const pixel *const luma = luma_row + ly * PXSTRIDE(luma_stride) + lx;    \
+            pixel avg = luma[0];                                                     \
+            if (sx)                                                                  \
+                avg = (avg + luma[1] + 1) >> 1;                                      \
+            const pixel *const src = src_row + (y) * PXSTRIDE(stride) + (bx + (x));  \
+            pixel *const dst = dst_row + (y) * PXSTRIDE(stride) + (bx + (x));        \
+            int val = avg;                                                           \
+            if (!data->chroma_scaling_from_luma) {                                   \
+                const int combined = avg * data->uv_luma_mult[uv] +                  \
+                               *src * data->uv_mult[uv];                             \
+                val = iclip_pixel( (combined >> 6) +                                 \
+                                   (data->uv_offset[uv] * (1 << bitdepth_min_8)) );  \
+            }                                                                        \
+            const int noise = round2(scaling[ val ] * (grain), data->scaling_shift); \
+            *dst = iclip(*src + noise, min_value, max_value);
+
+        for (int y = ystart; y < bh; y++) {
+            // Non-overlapped image region (straightforward)
+            for (int x = xstart; x < bw; x++) {
+                int grain = sample_lut(grain_lut, offsets, sx, sy, 0, 0, x, y);
+                add_noise_uv(x, y, grain);
+            }
+
+            // Special case for overlapped column
+            for (int x = 0; x < xstart; x++) {
+                int grain = sample_lut(grain_lut, offsets, sx, sy, 0, 0, x, y);
+                int old   = sample_lut(grain_lut, offsets, sx, sy, 1, 0, x, y);
+                grain = round2(old * w[sx][x][0] + grain * w[sx][x][1], 5);
+                grain = iclip(grain, grain_min, grain_max);
+                add_noise_uv(x, y, grain);
+            }
+        }
+
+        for (int y = 0; y < ystart; y++) {
+            // Special case for overlapped row (sans corner)
+            for (int x = xstart; x < bw; x++) {
+                int grain = sample_lut(grain_lut, offsets, sx, sy, 0, 0, x, y);
+                int old   = sample_lut(grain_lut, offsets, sx, sy, 0, 1, x, y);
+                grain = round2(old * w[sy][y][0] + grain * w[sy][y][1], 5);
+                grain = iclip(grain, grain_min, grain_max);
+                add_noise_uv(x, y, grain);
+            }
+
+            // Special case for doubly-overlapped corner
+            for (int x = 0; x < xstart; x++) {
+                // Blend the top pixel with the top left block
+                int top = sample_lut(grain_lut, offsets, sx, sy, 0, 1, x, y);
+                int old = sample_lut(grain_lut, offsets, sx, sy, 1, 1, x, y);
+                top = round2(old * w[sx][x][0] + top * w[sx][x][1], 5);
+                top = iclip(top, grain_min, grain_max);
+
+                // Blend the current pixel with the left block
+                int grain = sample_lut(grain_lut, offsets, sx, sy, 0, 0, x, y);
+                old = sample_lut(grain_lut, offsets, sx, sy, 1, 0, x, y);
+                grain = round2(old * w[sx][x][0] + grain * w[sx][x][1], 5);
+                grain = iclip(grain, grain_min, grain_max);
+
+                // Mix the row rows together and apply to image
+                grain = round2(top * w[sy][y][0] + grain * w[sy][y][1], 5);
+                grain = iclip(grain, grain_min, grain_max);
+                add_noise_uv(x, y, grain);
+            }
+        }
+    }
+}
+
+#define fguv_ss_fn(nm, ss_x, ss_y) \
+static decl_fguv_32x32xn_fn(fguv_32x32xn_##nm##_c) { \
+    fguv_32x32xn_c(dst_row, src_row, stride, data, pw, scaling, grain_lut, bh, \
+                   row_num, luma_row, luma_stride, uv_pl, is_id, ss_x, ss_y \
+                   HIGHBD_TAIL_SUFFIX); \
+}
+
+fguv_ss_fn(420, 1, 1);
+fguv_ss_fn(422, 1, 0);
+fguv_ss_fn(444, 0, 0);
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/filmgrain.h"
+#elif ARCH_X86
+#include "src/x86/filmgrain.h"
+#endif
+#endif
+
+COLD void bitfn(dav1d_film_grain_dsp_init)(Dav1dFilmGrainDSPContext *const c) {
+    c->generate_grain_y = generate_grain_y_c;
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I420 - 1] = generate_grain_uv_420_c;
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I422 - 1] = generate_grain_uv_422_c;
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I444 - 1] = generate_grain_uv_444_c;
+
+    c->fgy_32x32xn = fgy_32x32xn_c;
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I420 - 1] = fguv_32x32xn_420_c;
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I422 - 1] = fguv_32x32xn_422_c;
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I444 - 1] = fguv_32x32xn_444_c;
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+    film_grain_dsp_init_arm(c);
+#elif ARCH_X86
+    film_grain_dsp_init_x86(c);
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/getbits.c b/media/libdav1d/src/src/getbits.c
new file mode 100644
index 0000000000..13e7783fa3
--- /dev/null
+++ b/media/libdav1d/src/src/getbits.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/getbits.h"
+
+void dav1d_init_get_bits(GetBits *const c, const uint8_t *const data,
+                         const size_t sz)
+{
+    assert(sz);
+    c->ptr = c->ptr_start = data;
+    c->ptr_end = &c->ptr_start[sz];
+    c->state = 0;
+    c->bits_left = 0;
+    c->error = 0;
+}
+
+unsigned dav1d_get_bit(GetBits *const c) {
+    if (!c->bits_left) {
+        if (c->ptr >= c->ptr_end) {
+            c->error = 1;
+        } else {
+            const unsigned state = *c->ptr++;
+            c->bits_left = 7;
+            c->state = (uint64_t) state << 57;
+            return state >> 7;
+        }
+    }
+
+    const uint64_t state = c->state;
+    c->bits_left--;
+    c->state = state << 1;
+    return (unsigned) (state >> 63);
+}
+
+static inline void refill(GetBits *const c, const int n) {
+    assert(c->bits_left >= 0 && c->bits_left < 32);
+    unsigned state = 0;
+    do {
+        if (c->ptr >= c->ptr_end) {
+            c->error = 1;
+            if (state) break;
+            return;
+        }
+        state = (state << 8) | *c->ptr++;
+        c->bits_left += 8;
+    } while (n > c->bits_left);
+    c->state |= (uint64_t) state << (64 - c->bits_left);
+}
+
+#define GET_BITS(name, type, type64)            \
+type name(GetBits *const c, const int n) {      \
+    assert(n > 0 && n <= 32);                   \
+    /* Unsigned cast avoids refill after eob */ \
+    if ((unsigned) n > (unsigned) c->bits_left) \
+        refill(c, n);                           \
+    const uint64_t state = c->state;            \
+    c->bits_left -= n;                          \
+    c->state = state << n;                      \
+    return (type) ((type64) state >> (64 - n)); \
+}
+
+GET_BITS(dav1d_get_bits,  unsigned, uint64_t)
+GET_BITS(dav1d_get_sbits, int,      int64_t)
+
+unsigned dav1d_get_uleb128(GetBits *const c) {
+    uint64_t val = 0;
+    unsigned i = 0, more;
+
+    do {
+        const int v = dav1d_get_bits(c, 8);
+        more = v & 0x80;
+        val |= ((uint64_t) (v & 0x7F)) << i;
+        i += 7;
+    } while (more && i < 56);
+
+    if (val > UINT32_MAX || more) {
+        c->error = 1;
+        return 0;
+    }
+
+    return (unsigned) val;
+}
+
+unsigned dav1d_get_uniform(GetBits *const c, const unsigned max) {
+    // Output in range [0..max-1]
+    // max must be > 1, or else nothing is read from the bitstream
+    assert(max > 1);
+    const int l = ulog2(max) + 1;
+    assert(l > 1);
+    const unsigned m = (1U << l) - max;
+    const unsigned v = dav1d_get_bits(c, l - 1);
+    return v < m ? v : (v << 1) - m + dav1d_get_bit(c);
+}
+
+unsigned dav1d_get_vlc(GetBits *const c) {
+    if (dav1d_get_bit(c))
+        return 0;
+
+    int n_bits = 0;
+    do {
+        if (++n_bits == 32)
+            return UINT32_MAX;
+    } while (!dav1d_get_bit(c));
+
+    return ((1U << n_bits) - 1) + dav1d_get_bits(c, n_bits);
+}
+
+static unsigned get_bits_subexp_u(GetBits *const c, const unsigned ref,
+                                  const unsigned n)
+{
+    unsigned v = 0;
+
+    for (int i = 0;; i++) {
+        const int b = i ? 3 + i - 1 : 3;
+
+        if (n < v + 3 * (1 << b)) {
+            v += dav1d_get_uniform(c, n - v + 1);
+            break;
+        }
+
+        if (!dav1d_get_bit(c)) {
+            v += dav1d_get_bits(c, b);
+            break;
+        }
+
+        v += 1 << b;
+    }
+
+    return ref * 2 <= n ? inv_recenter(ref, v) : n - inv_recenter(n - ref, v);
+}
+
+int dav1d_get_bits_subexp(GetBits *const c, const int ref, const unsigned n) {
+    return (int) get_bits_subexp_u(c, ref + (1 << n), 2 << n) - (1 << n);
+}
diff --git a/media/libdav1d/src/src/getbits.h b/media/libdav1d/src/src/getbits.h
new file mode 100644
index 0000000000..67925943cd
--- /dev/null
+++ b/media/libdav1d/src/src/getbits.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_GETBITS_H
+#define DAV1D_SRC_GETBITS_H
+
+#include 
+#include 
+
+typedef struct GetBits {
+    uint64_t state;
+    int bits_left, error;
+    const uint8_t *ptr, *ptr_start, *ptr_end;
+} GetBits;
+
+void dav1d_init_get_bits(GetBits *c, const uint8_t *data, size_t sz);
+unsigned dav1d_get_bit(GetBits *c);
+unsigned dav1d_get_bits(GetBits *c, int n);
+int dav1d_get_sbits(GetBits *c, int n);
+unsigned dav1d_get_uleb128(GetBits *c);
+
+// Output in range 0..max-1
+unsigned dav1d_get_uniform(GetBits *c, unsigned max);
+unsigned dav1d_get_vlc(GetBits *c);
+int dav1d_get_bits_subexp(GetBits *c, int ref, unsigned n);
+
+// Discard bits from the buffer until we're next byte-aligned.
+static inline void dav1d_bytealign_get_bits(GetBits *c) {
+    // bits_left is never more than 7, because it is only incremented
+    // by refill(), called by dav1d_get_bits and that never reads more
+    // than 7 bits more than it needs.
+    //
+    // If this wasn't true, we would need to work out how many bits to
+    // discard (bits_left % 8), subtract that from bits_left and then
+    // shift state right by that amount.
+    assert(c->bits_left <= 7);
+
+    c->bits_left = 0;
+    c->state = 0;
+}
+
+// Return the current bit position relative to the start of the buffer.
+static inline unsigned dav1d_get_bits_pos(const GetBits *c) {
+    return (unsigned) (c->ptr - c->ptr_start) * 8 - c->bits_left;
+}
+
+#endif /* DAV1D_SRC_GETBITS_H */
diff --git a/media/libdav1d/src/src/internal.h b/media/libdav1d/src/src/internal.h
new file mode 100644
index 0000000000..b1770edb66
--- /dev/null
+++ b/media/libdav1d/src/src/internal.h
@@ -0,0 +1,471 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_INTERNAL_H
+#define DAV1D_SRC_INTERNAL_H
+
+#include 
+
+#include "dav1d/data.h"
+
+typedef struct Dav1dFrameContext Dav1dFrameContext;
+typedef struct Dav1dTileState Dav1dTileState;
+typedef struct Dav1dTaskContext Dav1dTaskContext;
+typedef struct Dav1dTask Dav1dTask;
+
+#include "common/attributes.h"
+
+#include "src/cdef.h"
+#include "src/cdf.h"
+#include "src/data.h"
+#include "src/env.h"
+#include "src/filmgrain.h"
+#include "src/intra_edge.h"
+#include "src/ipred.h"
+#include "src/itx.h"
+#include "src/levels.h"
+#include "src/lf_mask.h"
+#include "src/loopfilter.h"
+#include "src/looprestoration.h"
+#include "src/mc.h"
+#include "src/msac.h"
+#include "src/pal.h"
+#include "src/picture.h"
+#include "src/recon.h"
+#include "src/refmvs.h"
+#include "src/thread.h"
+
+typedef struct Dav1dDSPContext {
+    Dav1dFilmGrainDSPContext fg;
+    Dav1dIntraPredDSPContext ipred;
+    Dav1dMCDSPContext mc;
+    Dav1dInvTxfmDSPContext itx;
+    Dav1dLoopFilterDSPContext lf;
+    Dav1dCdefDSPContext cdef;
+    Dav1dLoopRestorationDSPContext lr;
+} Dav1dDSPContext;
+
+struct Dav1dTileGroup {
+    Dav1dData data;
+    int start, end;
+};
+
+enum TaskType {
+    DAV1D_TASK_TYPE_INIT,
+    DAV1D_TASK_TYPE_INIT_CDF,
+    DAV1D_TASK_TYPE_TILE_ENTROPY,
+    DAV1D_TASK_TYPE_ENTROPY_PROGRESS,
+    DAV1D_TASK_TYPE_TILE_RECONSTRUCTION,
+    DAV1D_TASK_TYPE_DEBLOCK_COLS,
+    DAV1D_TASK_TYPE_DEBLOCK_ROWS,
+    DAV1D_TASK_TYPE_CDEF,
+    DAV1D_TASK_TYPE_SUPER_RESOLUTION,
+    DAV1D_TASK_TYPE_LOOP_RESTORATION,
+    DAV1D_TASK_TYPE_RECONSTRUCTION_PROGRESS,
+    DAV1D_TASK_TYPE_FG_PREP,
+    DAV1D_TASK_TYPE_FG_APPLY,
+};
+
+struct Dav1dContext {
+    Dav1dFrameContext *fc;
+    unsigned n_fc;
+
+    Dav1dTaskContext *tc;
+    unsigned n_tc;
+
+    // cache of OBUs that make up a single frame before we submit them
+    // to a frame worker to be decoded
+    struct Dav1dTileGroup *tile;
+    int n_tile_data_alloc;
+    int n_tile_data;
+    int n_tiles;
+    Dav1dMemPool *seq_hdr_pool;
+    Dav1dRef *seq_hdr_ref;
+    Dav1dSequenceHeader *seq_hdr;
+    Dav1dMemPool *frame_hdr_pool;
+    Dav1dRef *frame_hdr_ref;
+    Dav1dFrameHeader *frame_hdr;
+
+    Dav1dRef *content_light_ref;
+    Dav1dContentLightLevel *content_light;
+    Dav1dRef *mastering_display_ref;
+    Dav1dMasteringDisplay *mastering_display;
+    Dav1dRef *itut_t35_ref;
+    Dav1dITUTT35 *itut_t35;
+    int n_itut_t35;
+
+    // decoded output picture queue
+    Dav1dData in;
+    Dav1dThreadPicture out, cache;
+    // dummy is a pointer to prevent compiler errors about atomic_load()
+    // not taking const arguments
+    atomic_int flush_mem, *flush;
+    struct {
+        Dav1dThreadPicture *out_delayed;
+        unsigned next;
+    } frame_thread;
+
+    // task threading (refer to tc[] for per_thread thingies)
+    struct TaskThreadData {
+        pthread_mutex_t lock;
+        pthread_cond_t cond;
+        atomic_uint first;
+        unsigned cur;
+        // This is used for delayed reset of the task cur pointer when
+        // such operation is needed but the thread doesn't enter a critical
+        // section (typically when executing the next sbrow task locklessly).
+        // See src/thread_task.c:reset_task_cur().
+        atomic_uint reset_task_cur;
+        atomic_int cond_signaled;
+        struct {
+            int exec, finished;
+            pthread_cond_t cond;
+            const Dav1dPicture *in;
+            Dav1dPicture *out;
+            enum TaskType type;
+            atomic_int progress[2]; /* [0]=started, [1]=completed */
+            union {
+                struct {
+                    ALIGN(int8_t grain_lut_8bpc[3][GRAIN_HEIGHT + 1][GRAIN_WIDTH], 16);
+                    ALIGN(uint8_t scaling_8bpc[3][256], 64);
+                };
+                struct {
+                    ALIGN(int16_t grain_lut_16bpc[3][GRAIN_HEIGHT + 1][GRAIN_WIDTH], 16);
+                    ALIGN(uint8_t scaling_16bpc[3][4096], 64);
+                };
+            };
+        } delayed_fg;
+        int inited;
+    } task_thread;
+
+    // reference/entropy state
+    Dav1dMemPool *segmap_pool;
+    Dav1dMemPool *refmvs_pool;
+    struct {
+        Dav1dThreadPicture p;
+        Dav1dRef *segmap;
+        Dav1dRef *refmvs;
+        uint8_t refpoc[7];
+    } refs[8];
+    Dav1dMemPool *cdf_pool;
+    CdfThreadContext cdf[8];
+
+    Dav1dDSPContext dsp[3 /* 8, 10, 12 bits/component */];
+    Dav1dPalDSPContext pal_dsp;
+    Dav1dRefmvsDSPContext refmvs_dsp;
+
+    Dav1dPicAllocator allocator;
+    int apply_grain;
+    int operating_point;
+    unsigned operating_point_idc;
+    int all_layers;
+    int max_spatial_id;
+    unsigned frame_size_limit;
+    int strict_std_compliance;
+    int output_invisible_frames;
+    enum Dav1dInloopFilterType inloop_filters;
+    enum Dav1dDecodeFrameType decode_frame_type;
+    int drain;
+    enum PictureFlags frame_flags;
+    enum Dav1dEventFlags event_flags;
+    Dav1dDataProps cached_error_props;
+    int cached_error;
+
+    Dav1dLogger logger;
+
+    Dav1dMemPool *picture_pool;
+    Dav1dMemPool *pic_ctx_pool;
+};
+
+struct Dav1dTask {
+    unsigned frame_idx;         // frame thread id
+    enum TaskType type;         // task work
+    int sby;                    // sbrow
+
+    // task dependencies
+    int recon_progress, deblock_progress;
+    int deps_skip;
+    struct Dav1dTask *next; // only used in task queue
+};
+
+struct Dav1dFrameContext {
+    Dav1dRef *seq_hdr_ref;
+    Dav1dSequenceHeader *seq_hdr;
+    Dav1dRef *frame_hdr_ref;
+    Dav1dFrameHeader *frame_hdr;
+    Dav1dThreadPicture refp[7];
+    Dav1dPicture cur; // during block coding / reconstruction
+    Dav1dThreadPicture sr_cur; // after super-resolution upscaling
+    Dav1dRef *mvs_ref;
+    refmvs_temporal_block *mvs, *ref_mvs[7];
+    Dav1dRef *ref_mvs_ref[7];
+    Dav1dRef *cur_segmap_ref, *prev_segmap_ref;
+    uint8_t *cur_segmap;
+    const uint8_t *prev_segmap;
+    uint8_t refpoc[7], refrefpoc[7][7];
+    uint8_t gmv_warp_allowed[7];
+    CdfThreadContext in_cdf, out_cdf;
+    struct Dav1dTileGroup *tile;
+    int n_tile_data_alloc;
+    int n_tile_data;
+
+    // for scalable references
+    struct ScalableMotionParams {
+        int scale; // if no scaling, this is 0
+        int step;
+    } svc[7][2 /* x, y */];
+    int resize_step[2 /* y, uv */], resize_start[2 /* y, uv */];
+
+    const Dav1dContext *c;
+    Dav1dTileState *ts;
+    int n_ts;
+    const Dav1dDSPContext *dsp;
+    struct {
+        recon_b_intra_fn recon_b_intra;
+        recon_b_inter_fn recon_b_inter;
+        filter_sbrow_fn filter_sbrow;
+        filter_sbrow_fn filter_sbrow_deblock_cols;
+        filter_sbrow_fn filter_sbrow_deblock_rows;
+        void (*filter_sbrow_cdef)(Dav1dTaskContext *tc, int sby);
+        filter_sbrow_fn filter_sbrow_resize;
+        filter_sbrow_fn filter_sbrow_lr;
+        backup_ipred_edge_fn backup_ipred_edge;
+        read_coef_blocks_fn read_coef_blocks;
+        copy_pal_block_fn copy_pal_block_y;
+        copy_pal_block_fn copy_pal_block_uv;
+        read_pal_plane_fn read_pal_plane;
+        read_pal_uv_fn read_pal_uv;
+    } bd_fn;
+
+    int ipred_edge_sz;
+    pixel *ipred_edge[3];
+    ptrdiff_t b4_stride;
+    int w4, h4, bw, bh, sb128w, sb128h, sbh, sb_shift, sb_step, sr_sb128w;
+    uint16_t dq[DAV1D_MAX_SEGMENTS][3 /* plane */][2 /* dc/ac */];
+    const uint8_t *qm[N_RECT_TX_SIZES][3 /* plane */];
+    BlockContext *a;
+    int a_sz /* w*tile_rows */;
+    refmvs_frame rf;
+    uint8_t jnt_weights[7][7];
+    int bitdepth_max;
+
+    struct {
+        int next_tile_row[2 /* 0: reconstruction, 1: entropy */];
+        atomic_int entropy_progress;
+        atomic_int deblock_progress; // in sby units
+        atomic_uint *frame_progress, *copy_lpf_progress;
+        // indexed using t->by * f->b4_stride + t->bx
+        Av1Block *b;
+        int16_t *cbi; /* bits 0-4: txtp, bits 5-15: eob */
+        // indexed using (t->by >> 1) * (f->b4_stride >> 1) + (t->bx >> 1)
+        pixel (*pal)[3 /* plane */][8 /* idx */];
+        // iterated over inside tile state
+        uint8_t *pal_idx;
+        coef *cf;
+        int prog_sz;
+        int cbi_sz, pal_sz, pal_idx_sz, cf_sz;
+        // start offsets per tile
+        unsigned *tile_start_off;
+    } frame_thread;
+
+    // loopfilter
+    struct {
+        uint8_t (*level)[4];
+        Av1Filter *mask;
+        Av1Restoration *lr_mask;
+        int mask_sz /* w*h */, lr_mask_sz;
+        int cdef_buf_plane_sz[2]; /* stride*sbh*4 */
+        int cdef_buf_sbh;
+        int lr_buf_plane_sz[2]; /* (stride*sbh*4) << sb128 if n_tc > 1, else stride*4 */
+        int re_sz /* h */;
+        Av1FilterLUT lim_lut;
+        ALIGN(uint8_t lvl[8 /* seg_id */][4 /* dir */][8 /* ref */][2 /* is_gmv */], 16);
+        int last_sharpness;
+        uint8_t *tx_lpf_right_edge[2];
+        uint8_t *cdef_line_buf, *lr_line_buf;
+        pixel *cdef_line[2 /* pre, post */][3 /* plane */];
+        pixel *cdef_lpf_line[3 /* plane */];
+        pixel *lr_lpf_line[3 /* plane */];
+
+        // in-loop filter per-frame state keeping
+        uint8_t *start_of_tile_row;
+        int start_of_tile_row_sz;
+        int need_cdef_lpf_copy;
+        pixel *p[3], *sr_p[3];
+        int restore_planes; // enum LrRestorePlanes
+    } lf;
+
+    struct {
+        pthread_mutex_t lock;
+        pthread_cond_t cond;
+        struct TaskThreadData *ttd;
+        struct Dav1dTask *tasks, *tile_tasks[2], init_task;
+        int num_tasks, num_tile_tasks;
+        atomic_int init_done;
+        atomic_int done[2];
+        int retval;
+        int update_set; // whether we need to update CDF reference
+        atomic_int error;
+        atomic_int task_counter;
+        struct Dav1dTask *task_head, *task_tail;
+        // Points to the task directly before the cur pointer in the queue.
+        // This cur pointer is theoretical here, we actually keep track of the
+        // "prev_t" variable. This is needed to not loose the tasks in
+        // [head;cur-1] when picking one for execution.
+        struct Dav1dTask *task_cur_prev;
+        struct { // async task insertion
+            atomic_int merge;
+            pthread_mutex_t lock;
+            Dav1dTask *head, *tail;
+        } pending_tasks;
+    } task_thread;
+
+    // threading (refer to tc[] for per-thread things)
+    struct FrameTileThreadData {
+        int (*lowest_pixel_mem)[7][2];
+        int lowest_pixel_mem_sz;
+    } tile_thread;
+};
+
+struct Dav1dTileState {
+    CdfContext cdf;
+    MsacContext msac;
+
+    struct {
+        int col_start, col_end, row_start, row_end; // in 4px units
+        int col, row; // in tile units
+    } tiling;
+
+    // in sby units, TILE_ERROR after a decoding error
+    atomic_int progress[2 /* 0: reconstruction, 1: entropy */];
+    struct {
+        uint8_t *pal_idx;
+        int16_t *cbi;
+        coef *cf;
+    } frame_thread[2 /* 0: reconstruction, 1: entropy */];
+
+    // in fullpel units, [0] = Y, [1] = UV, used for progress requirements
+    // each entry is one tile-sbrow; middle index is refidx
+    int (*lowest_pixel)[7][2];
+
+    uint16_t dqmem[DAV1D_MAX_SEGMENTS][3 /* plane */][2 /* dc/ac */];
+    const uint16_t (*dq)[3][2];
+    int last_qidx;
+
+    union {
+        int8_t i8[4];
+        uint32_t u32;
+    } last_delta_lf;
+    ALIGN(uint8_t lflvlmem[8 /* seg_id */][4 /* dir */][8 /* ref */][2 /* is_gmv */], 16);
+    const uint8_t (*lflvl)[4][8][2];
+
+    Av1RestorationUnit *lr_ref[3];
+};
+
+struct Dav1dTaskContext {
+    const Dav1dContext *c;
+    const Dav1dFrameContext *f;
+    Dav1dTileState *ts;
+    int bx, by;
+    BlockContext l, *a;
+    refmvs_tile rt;
+    ALIGN(union, 64) {
+        int16_t cf_8bpc [32 * 32];
+        int32_t cf_16bpc[32 * 32];
+    };
+    union {
+        uint8_t  al_pal_8bpc [2 /* a/l */][32 /* bx/y4 */][3 /* plane */][8 /* palette_idx */];
+        uint16_t al_pal_16bpc[2 /* a/l */][32 /* bx/y4 */][3 /* plane */][8 /* palette_idx */];
+    };
+    uint8_t pal_sz_uv[2 /* a/l */][32 /* bx4/by4 */];
+    ALIGN(union, 64) {
+        struct {
+            union {
+                uint8_t  lap_8bpc [128 * 32];
+                uint16_t lap_16bpc[128 * 32];
+                struct {
+                    int16_t compinter[2][128 * 128];
+                    uint8_t seg_mask[128 * 128];
+                };
+            };
+            union {
+                // stride=192 for non-SVC, or 320 for SVC
+                uint8_t  emu_edge_8bpc [320 * (256 + 7)];
+                uint16_t emu_edge_16bpc[320 * (256 + 7)];
+            };
+        };
+        struct {
+            union {
+                uint8_t levels[32 * 34];
+                struct {
+                    uint8_t pal_order[64][8];
+                    uint8_t pal_ctx[64];
+                };
+            };
+            union {
+                int16_t ac[32 * 32]; // intra-only
+                uint8_t txtp_map[32 * 32]; // inter-only
+            };
+            uint8_t pal_idx_y[32 * 64];
+            uint8_t pal_idx_uv[64 * 64]; /* also used as pre-pack scratch buffer */
+            union {
+                struct {
+                    uint8_t interintra_8bpc[64 * 64];
+                    uint8_t edge_8bpc[257];
+                    ALIGN(uint8_t pal_8bpc[3 /* plane */][8 /* palette_idx */], 8);
+                };
+                struct {
+                    uint16_t interintra_16bpc[64 * 64];
+                    uint16_t edge_16bpc[257];
+                    ALIGN(uint16_t pal_16bpc[3 /* plane */][8 /* palette_idx */], 16);
+                };
+            };
+        };
+    } scratch;
+
+    Dav1dWarpedMotionParams warpmv;
+    Av1Filter *lf_mask;
+    int top_pre_cdef_toggle;
+    int8_t *cur_sb_cdef_idx_ptr;
+    // for chroma sub8x8, we need to know the filter for all 4 subblocks in
+    // a 4x4 area, but the top/left one can go out of cache already, so this
+    // keeps it accessible
+    enum Filter2d tl_4x4_filter;
+
+    struct {
+        int pass;
+    } frame_thread;
+    struct {
+        struct thread_data td;
+        struct TaskThreadData *ttd;
+        struct FrameTileThreadData *fttd;
+        int flushed;
+        int die;
+    } task_thread;
+};
+
+#endif /* DAV1D_SRC_INTERNAL_H */
diff --git a/media/libdav1d/src/src/intra_edge.c b/media/libdav1d/src/src/intra_edge.c
new file mode 100644
index 0000000000..e9261e6cb8
--- /dev/null
+++ b/media/libdav1d/src/src/intra_edge.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2018-2023, VideoLAN and dav1d authors
+ * Copyright © 2018-2023, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/attributes.h"
+
+#include "src/intra_edge.h"
+#include "src/levels.h"
+
+struct ModeSelMem {
+    EdgeBranch *nwc[3 /* 64x64, 32x32, 16x16 */];
+    EdgeTip *nt;
+};
+
+/* Because we're using 16-bit offsets to refer to other nodes those arrays
+ * are placed in a struct to ensure they're consecutive in memory. */
+static struct {
+    EdgeBranch branch_sb128[1 + 4 + 16 + 64];
+    EdgeTip tip_sb128[256];
+    EdgeBranch branch_sb64[1 + 4 + 16];
+    EdgeTip tip_sb64[64];
+} ALIGN(nodes, 16);
+
+const EdgeNode *dav1d_intra_edge_tree[2] = {
+    (EdgeNode*)nodes.branch_sb128, (EdgeNode*)nodes.branch_sb64
+};
+
+static COLD void init_edges(EdgeNode *const node,
+                            const enum BlockLevel bl,
+                            const enum EdgeFlags edge_flags)
+{
+    node->o = edge_flags;
+    node->h[0] = edge_flags | EDGE_ALL_LEFT_HAS_BOTTOM;
+    node->v[0] = edge_flags | EDGE_ALL_TOP_HAS_RIGHT;
+
+    if (bl == BL_8X8) {
+        EdgeTip *const nt = (EdgeTip *) node;
+
+        node->h[1] = edge_flags & (EDGE_ALL_LEFT_HAS_BOTTOM |
+                                   EDGE_I420_TOP_HAS_RIGHT);
+        node->v[1] = edge_flags & (EDGE_ALL_TOP_HAS_RIGHT |
+                                   EDGE_I420_LEFT_HAS_BOTTOM |
+                                   EDGE_I422_LEFT_HAS_BOTTOM);
+
+        nt->split[0] = (edge_flags & EDGE_ALL_TOP_HAS_RIGHT) |
+                       EDGE_I422_LEFT_HAS_BOTTOM;
+        nt->split[1] = edge_flags | EDGE_I444_TOP_HAS_RIGHT;
+        nt->split[2] = edge_flags & (EDGE_I420_TOP_HAS_RIGHT |
+                                     EDGE_I420_LEFT_HAS_BOTTOM |
+                                     EDGE_I422_LEFT_HAS_BOTTOM);
+    } else {
+        EdgeBranch *const nwc = (EdgeBranch *) node;
+
+        node->h[1] = edge_flags & EDGE_ALL_LEFT_HAS_BOTTOM;
+        node->v[1] = edge_flags & EDGE_ALL_TOP_HAS_RIGHT;
+
+        nwc->h4 = EDGE_ALL_LEFT_HAS_BOTTOM;
+        nwc->v4 = EDGE_ALL_TOP_HAS_RIGHT;
+        if (bl == BL_16X16) {
+            nwc->h4 |= edge_flags & EDGE_I420_TOP_HAS_RIGHT;
+            nwc->v4 |= edge_flags & (EDGE_I420_LEFT_HAS_BOTTOM |
+                                     EDGE_I422_LEFT_HAS_BOTTOM);
+        }
+    }
+}
+
+#define PTR_OFFSET(a, b) ((uint16_t)((uintptr_t)(b) - (uintptr_t)(a)))
+
+static COLD void init_mode_node(EdgeBranch *const nwc,
+                               const enum BlockLevel bl,
+                               struct ModeSelMem *const mem,
+                               const int top_has_right,
+                               const int left_has_bottom)
+{
+    init_edges(&nwc->node, bl,
+               (top_has_right ? EDGE_ALL_TOP_HAS_RIGHT : 0) |
+               (left_has_bottom ? EDGE_ALL_LEFT_HAS_BOTTOM : 0));
+    if (bl == BL_16X16) {
+        for (int n = 0; n < 4; n++) {
+            EdgeTip *const nt = mem->nt++;
+            nwc->split_offset[n] = PTR_OFFSET(nwc, nt);
+            init_edges(&nt->node, bl + 1,
+                       ((n == 3 || (n == 1 && !top_has_right)) ? 0 :
+                        EDGE_ALL_TOP_HAS_RIGHT) |
+                       (!(n == 0 || (n == 2 && left_has_bottom)) ? 0 :
+                        EDGE_ALL_LEFT_HAS_BOTTOM));
+        }
+    } else {
+        for (int n = 0; n < 4; n++) {
+            EdgeBranch *const nwc_child = mem->nwc[bl]++;
+            nwc->split_offset[n] = PTR_OFFSET(nwc, nwc_child);
+            init_mode_node(nwc_child, bl + 1, mem,
+                           !(n == 3 || (n == 1 && !top_has_right)),
+                           n == 0 || (n == 2 && left_has_bottom));
+        }
+    }
+}
+
+COLD void dav1d_init_intra_edge_tree(void) {
+    // This function is guaranteed to be called only once
+    struct ModeSelMem mem;
+
+    mem.nwc[BL_128X128] = &nodes.branch_sb128[1];
+    mem.nwc[BL_64X64] = &nodes.branch_sb128[1 + 4];
+    mem.nwc[BL_32X32] = &nodes.branch_sb128[1 + 4 + 16];
+    mem.nt = nodes.tip_sb128;
+    init_mode_node(nodes.branch_sb128, BL_128X128, &mem, 1, 0);
+    assert(mem.nwc[BL_128X128] == &nodes.branch_sb128[1 + 4]);
+    assert(mem.nwc[BL_64X64] == &nodes.branch_sb128[1 + 4 + 16]);
+    assert(mem.nwc[BL_32X32] == &nodes.branch_sb128[1 + 4 + 16 + 64]);
+    assert(mem.nt == &nodes.tip_sb128[256]);
+
+    mem.nwc[BL_128X128] = NULL;
+    mem.nwc[BL_64X64] = &nodes.branch_sb64[1];
+    mem.nwc[BL_32X32] = &nodes.branch_sb64[1 + 4];
+    mem.nt = nodes.tip_sb64;
+    init_mode_node(nodes.branch_sb64, BL_64X64, &mem, 1, 0);
+    assert(mem.nwc[BL_64X64] == &nodes.branch_sb64[1 + 4]);
+    assert(mem.nwc[BL_32X32] == &nodes.branch_sb64[1 + 4 + 16]);
+    assert(mem.nt == &nodes.tip_sb64[64]);
+}
diff --git a/media/libdav1d/src/src/intra_edge.h b/media/libdav1d/src/src/intra_edge.h
new file mode 100644
index 0000000000..ecfb3de564
--- /dev/null
+++ b/media/libdav1d/src/src/intra_edge.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2018-2023, VideoLAN and dav1d authors
+ * Copyright © 2018-2023, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_INTRA_EDGE_H
+#define DAV1D_SRC_INTRA_EDGE_H
+
+#include 
+
+enum EdgeFlags {
+    EDGE_I444_TOP_HAS_RIGHT   = 1 << 0,
+    EDGE_I422_TOP_HAS_RIGHT   = 1 << 1,
+    EDGE_I420_TOP_HAS_RIGHT   = 1 << 2,
+    EDGE_I444_LEFT_HAS_BOTTOM = 1 << 3,
+    EDGE_I422_LEFT_HAS_BOTTOM = 1 << 4,
+    EDGE_I420_LEFT_HAS_BOTTOM = 1 << 5,
+    EDGE_ALL_TOP_HAS_RIGHT    = EDGE_I444_TOP_HAS_RIGHT |
+                                EDGE_I422_TOP_HAS_RIGHT |
+                                EDGE_I420_TOP_HAS_RIGHT,
+    EDGE_ALL_LEFT_HAS_BOTTOM  = EDGE_I444_LEFT_HAS_BOTTOM |
+                                EDGE_I422_LEFT_HAS_BOTTOM |
+                                EDGE_I420_LEFT_HAS_BOTTOM,
+    EDGE_ALL_TR_AND_BL        = EDGE_ALL_TOP_HAS_RIGHT |
+                                EDGE_ALL_LEFT_HAS_BOTTOM,
+};
+
+#define INTRA_EDGE_SPLIT(n, i) \
+    ((const EdgeNode*)((uintptr_t)(n) + ((const EdgeBranch*)(n))->split_offset[i]))
+
+typedef struct EdgeNode {
+    uint8_t /* enum EdgeFlags */ o, h[2], v[2];
+} EdgeNode;
+
+typedef struct EdgeTip {
+    EdgeNode node;
+    uint8_t /* enum EdgeFlags */ split[3];
+} EdgeTip;
+
+typedef struct EdgeBranch {
+    EdgeNode node;
+    uint8_t /* enum EdgeFlags */ h4, v4;
+    uint16_t split_offset[4]; /* relative to the address of this node */
+} EdgeBranch;
+
+/* Tree to keep track of which edges are available. */
+EXTERN const EdgeNode *dav1d_intra_edge_tree[2 /* BL_128X128, BL_64X64 */];
+
+void dav1d_init_intra_edge_tree(void);
+
+#endif /* DAV1D_SRC_INTRA_EDGE_H */
diff --git a/media/libdav1d/src/src/ipred.h b/media/libdav1d/src/src/ipred.h
new file mode 100644
index 0000000000..35adb02edf
--- /dev/null
+++ b/media/libdav1d/src/src/ipred.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_IPRED_H
+#define DAV1D_SRC_IPRED_H
+
+#include 
+
+#include "common/bitdepth.h"
+
+#include "src/levels.h"
+
+/*
+ * Intra prediction.
+ * - a is the angle (in degrees) for directional intra predictors. For other
+ *   modes, it is ignored;
+ * - topleft is the same as the argument given to dav1d_prepare_intra_edges(),
+ *   see ipred_prepare.h for more detailed documentation.
+ */
+#define decl_angular_ipred_fn(name) \
+void (name)(pixel *dst, ptrdiff_t stride, const pixel *topleft, \
+            int width, int height, int angle, int max_width, int max_height \
+            HIGHBD_DECL_SUFFIX)
+typedef decl_angular_ipred_fn(*angular_ipred_fn);
+
+/*
+ * Create a subsampled Y plane with the DC subtracted.
+ * - w/h_pad is the edge of the width/height that extends outside the visible
+ *   portion of the frame in 4px units;
+ * - ac has a stride of 16.
+ */
+#define decl_cfl_ac_fn(name) \
+void (name)(int16_t *ac, const pixel *y, ptrdiff_t stride, \
+            int w_pad, int h_pad, int cw, int ch)
+typedef decl_cfl_ac_fn(*cfl_ac_fn);
+
+/*
+ * dst[x,y] += alpha * ac[x,y]
+ * - alpha contains a q3 scalar in [-16,16] range;
+ */
+#define decl_cfl_pred_fn(name) \
+void (name)(pixel *dst, ptrdiff_t stride, const pixel *topleft, \
+            int width, int height, const int16_t *ac, int alpha \
+            HIGHBD_DECL_SUFFIX)
+typedef decl_cfl_pred_fn(*cfl_pred_fn);
+
+/*
+ * dst[x,y] = pal[idx[x,y]]
+ * - palette indices are [0-7]
+ * - only 16-byte alignment is guaranteed for idx.
+ */
+#define decl_pal_pred_fn(name) \
+void (name)(pixel *dst, ptrdiff_t stride, const pixel *pal, \
+            const uint8_t *idx, int w, int h)
+typedef decl_pal_pred_fn(*pal_pred_fn);
+
+typedef struct Dav1dIntraPredDSPContext {
+    angular_ipred_fn intra_pred[N_IMPL_INTRA_PRED_MODES];
+
+    // chroma-from-luma
+    cfl_ac_fn cfl_ac[3 /* 420, 422, 444 */];
+    cfl_pred_fn cfl_pred[DC_128_PRED + 1];
+
+    // palette
+    pal_pred_fn pal_pred;
+} Dav1dIntraPredDSPContext;
+
+bitfn_decls(void dav1d_intra_pred_dsp_init, Dav1dIntraPredDSPContext *c);
+
+#endif /* DAV1D_SRC_IPRED_H */
diff --git a/media/libdav1d/src/src/ipred_prepare.h b/media/libdav1d/src/src/ipred_prepare.h
new file mode 100644
index 0000000000..6a7efeb3d7
--- /dev/null
+++ b/media/libdav1d/src/src/ipred_prepare.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_IPRED_PREPARE_H
+#define DAV1D_SRC_IPRED_PREPARE_H
+
+#include 
+#include 
+
+#include "common/bitdepth.h"
+
+#include "src/env.h"
+#include "src/intra_edge.h"
+#include "src/levels.h"
+
+/*
+ * Luma intra edge preparation.
+ *
+ * x/y/start/w/h are in luma block (4px) units:
+ * - x and y are the absolute block positions in the image;
+ * - start/w/h are the *dependent tile* boundary positions. In practice, start
+ *   is the horizontal tile start, w is the horizontal tile end, the vertical
+ *   tile start is assumed to be 0 and h is the vertical image end.
+ *
+ * edge_flags signals which edges are available for this transform-block inside
+ * the given partition, as well as for the partition inside the superblock
+ * structure.
+ *
+ * dst and stride are pointers to the top/left position of the current block,
+ * and can be used to locate the top, left, top/left, top/right and bottom/left
+ * edge pointers also.
+ *
+ * angle is the angle_delta [-3..3] on input, and the absolute angle on output.
+ *
+ * mode is the intra prediction mode as coded in the bitstream. The return value
+ * is this same mode, converted to an index in the DSP functions.
+ *
+ * tw/th are the size of the transform block in block (4px) units.
+ *
+ * topleft_out is a pointer to scratch memory that will be filled with the edge
+ * pixels. The memory array should have space to be indexed in the [-2*w,2*w]
+ * range, in the following order:
+ * - [0] will be the top/left edge pixel;
+ * - [1..w] will be the top edge pixels (1 being left-most, w being right-most);
+ * - [w+1..2*w] will be the top/right edge pixels;
+ * - [-1..-w] will be the left edge pixels (-1 being top-most, -w being bottom-
+ *   most);
+ * - [-w-1..-2*w] will be the bottom/left edge pixels.
+ * Each edge may remain uninitialized if it is not used by the returned mode
+ * index. If edges are not available (because the edge position is outside the
+ * tile dimensions or because edge_flags indicates lack of edge availability),
+ * they will be extended from nearby edges as defined by the av1 spec.
+ */
+enum IntraPredMode
+    bytefn(dav1d_prepare_intra_edges)(int x, int have_left, int y, int have_top,
+                                      int w, int h, enum EdgeFlags edge_flags,
+                                      const pixel *dst, ptrdiff_t stride,
+                                      const pixel *prefilter_toplevel_sb_edge,
+                                      enum IntraPredMode mode, int *angle,
+                                      int tw, int th, int filter_edge,
+                                      pixel *topleft_out HIGHBD_DECL_SUFFIX);
+
+// These flags are OR'd with the angle argument into intra predictors.
+// ANGLE_USE_EDGE_FILTER_FLAG signals that edges should be convolved
+// with a filter before using them to predict values in a block.
+// ANGLE_SMOOTH_EDGE_FLAG means that edges are smooth and should use
+// reduced filter strength.
+#define ANGLE_USE_EDGE_FILTER_FLAG 1024
+#define ANGLE_SMOOTH_EDGE_FLAG      512
+
+static inline int sm_flag(const BlockContext *const b, const int idx) {
+    if (!b->intra[idx]) return 0;
+    const enum IntraPredMode m = b->mode[idx];
+    return (m == SMOOTH_PRED || m == SMOOTH_H_PRED ||
+            m == SMOOTH_V_PRED) ? ANGLE_SMOOTH_EDGE_FLAG : 0;
+}
+
+static inline int sm_uv_flag(const BlockContext *const b, const int idx) {
+    const enum IntraPredMode m = b->uvmode[idx];
+    return (m == SMOOTH_PRED || m == SMOOTH_H_PRED ||
+            m == SMOOTH_V_PRED) ? ANGLE_SMOOTH_EDGE_FLAG : 0;
+}
+
+#endif /* DAV1D_SRC_IPRED_PREPARE_H */
diff --git a/media/libdav1d/src/src/ipred_prepare_tmpl.c b/media/libdav1d/src/src/ipred_prepare_tmpl.c
new file mode 100644
index 0000000000..0bf9de9418
--- /dev/null
+++ b/media/libdav1d/src/src/ipred_prepare_tmpl.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "common/intops.h"
+
+#include "src/ipred_prepare.h"
+
+static const uint8_t av1_mode_conv[N_INTRA_PRED_MODES]
+                                  [2 /* have_left */][2 /* have_top */] =
+{
+    [DC_PRED]    = { { DC_128_PRED,  TOP_DC_PRED },
+                     { LEFT_DC_PRED, DC_PRED     } },
+    [PAETH_PRED] = { { DC_128_PRED,  VERT_PRED   },
+                     { HOR_PRED,     PAETH_PRED  } },
+};
+
+static const uint8_t av1_mode_to_angle_map[8] = {
+    90, 180, 45, 135, 113, 157, 203, 67
+};
+
+static const struct {
+    uint8_t needs_left:1;
+    uint8_t needs_top:1;
+    uint8_t needs_topleft:1;
+    uint8_t needs_topright:1;
+    uint8_t needs_bottomleft:1;
+} av1_intra_prediction_edges[N_IMPL_INTRA_PRED_MODES] = {
+    [DC_PRED]       = { .needs_top  = 1, .needs_left = 1 },
+    [VERT_PRED]     = { .needs_top  = 1 },
+    [HOR_PRED]      = { .needs_left = 1 },
+    [LEFT_DC_PRED]  = { .needs_left = 1 },
+    [TOP_DC_PRED]   = { .needs_top  = 1 },
+    [DC_128_PRED]   = { 0 },
+    [Z1_PRED]       = { .needs_top = 1, .needs_topright = 1,
+                        .needs_topleft = 1 },
+    [Z2_PRED]       = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
+    [Z3_PRED]       = { .needs_left = 1, .needs_bottomleft = 1,
+                        .needs_topleft = 1 },
+    [SMOOTH_PRED]   = { .needs_left = 1, .needs_top = 1 },
+    [SMOOTH_V_PRED] = { .needs_left = 1, .needs_top = 1 },
+    [SMOOTH_H_PRED] = { .needs_left = 1, .needs_top = 1 },
+    [PAETH_PRED]    = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
+    [FILTER_PRED]   = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
+};
+
+enum IntraPredMode
+bytefn(dav1d_prepare_intra_edges)(const int x, const int have_left,
+                                  const int y, const int have_top,
+                                  const int w, const int h,
+                                  const enum EdgeFlags edge_flags,
+                                  const pixel *const dst,
+                                  const ptrdiff_t stride,
+                                  const pixel *prefilter_toplevel_sb_edge,
+                                  enum IntraPredMode mode, int *const angle,
+                                  const int tw, const int th, const int filter_edge,
+                                  pixel *const topleft_out HIGHBD_DECL_SUFFIX)
+{
+    const int bitdepth = bitdepth_from_max(bitdepth_max);
+    assert(y < h && x < w);
+
+    switch (mode) {
+    case VERT_PRED:
+    case HOR_PRED:
+    case DIAG_DOWN_LEFT_PRED:
+    case DIAG_DOWN_RIGHT_PRED:
+    case VERT_RIGHT_PRED:
+    case HOR_DOWN_PRED:
+    case HOR_UP_PRED:
+    case VERT_LEFT_PRED: {
+        *angle = av1_mode_to_angle_map[mode - VERT_PRED] + 3 * *angle;
+
+        if (*angle <= 90)
+            mode = *angle < 90 && have_top ? Z1_PRED : VERT_PRED;
+        else if (*angle < 180)
+            mode = Z2_PRED;
+        else
+            mode = *angle > 180 && have_left ? Z3_PRED : HOR_PRED;
+        break;
+    }
+    case DC_PRED:
+    case PAETH_PRED:
+        mode = av1_mode_conv[mode][have_left][have_top];
+        break;
+    default:
+        break;
+    }
+
+    const pixel *dst_top;
+    if (have_top &&
+        (av1_intra_prediction_edges[mode].needs_top ||
+         av1_intra_prediction_edges[mode].needs_topleft ||
+         (av1_intra_prediction_edges[mode].needs_left && !have_left)))
+    {
+        if (prefilter_toplevel_sb_edge) {
+            dst_top = &prefilter_toplevel_sb_edge[x * 4];
+        } else {
+            dst_top = &dst[-PXSTRIDE(stride)];
+        }
+    }
+
+    if (av1_intra_prediction_edges[mode].needs_left) {
+        const int sz = th << 2;
+        pixel *const left = &topleft_out[-sz];
+
+        if (have_left) {
+            const int px_have = imin(sz, (h - y) << 2);
+
+            for (int i = 0; i < px_have; i++)
+                left[sz - 1 - i] = dst[PXSTRIDE(stride) * i - 1];
+            if (px_have < sz)
+                pixel_set(left, left[sz - px_have], sz - px_have);
+        } else {
+            pixel_set(left, have_top ? *dst_top : ((1 << bitdepth) >> 1) + 1, sz);
+        }
+
+        if (av1_intra_prediction_edges[mode].needs_bottomleft) {
+            const int have_bottomleft = (!have_left || y + th >= h) ? 0 :
+                                        (edge_flags & EDGE_I444_LEFT_HAS_BOTTOM);
+
+            if (have_bottomleft) {
+                const int px_have = imin(sz, (h - y - th) << 2);
+
+                for (int i = 0; i < px_have; i++)
+                    left[-(i + 1)] = dst[(sz + i) * PXSTRIDE(stride) - 1];
+                if (px_have < sz)
+                    pixel_set(left - sz, left[-px_have], sz - px_have);
+            } else {
+                pixel_set(left - sz, left[0], sz);
+            }
+        }
+    }
+
+    if (av1_intra_prediction_edges[mode].needs_top) {
+        const int sz = tw << 2;
+        pixel *const top = &topleft_out[1];
+
+        if (have_top) {
+            const int px_have = imin(sz, (w - x) << 2);
+            pixel_copy(top, dst_top, px_have);
+            if (px_have < sz)
+                pixel_set(top + px_have, top[px_have - 1], sz - px_have);
+        } else {
+            pixel_set(top, have_left ? dst[-1] : ((1 << bitdepth) >> 1) - 1, sz);
+        }
+
+        if (av1_intra_prediction_edges[mode].needs_topright) {
+            const int have_topright = (!have_top || x + tw >= w) ? 0 :
+                                      (edge_flags & EDGE_I444_TOP_HAS_RIGHT);
+
+            if (have_topright) {
+                const int px_have = imin(sz, (w - x - tw) << 2);
+
+                pixel_copy(top + sz, &dst_top[sz], px_have);
+                if (px_have < sz)
+                    pixel_set(top + sz + px_have, top[sz + px_have - 1],
+                              sz - px_have);
+            } else {
+                pixel_set(top + sz, top[sz - 1], sz);
+            }
+        }
+    }
+
+    if (av1_intra_prediction_edges[mode].needs_topleft) {
+        if (have_left)
+            *topleft_out = have_top ? dst_top[-1] : dst[-1];
+        else
+            *topleft_out = have_top ? *dst_top : (1 << bitdepth) >> 1;
+
+        if (mode == Z2_PRED && tw + th >= 6 && filter_edge)
+            *topleft_out = ((topleft_out[-1] + topleft_out[1]) * 5 +
+                            topleft_out[0] * 6 + 8) >> 4;
+    }
+
+    return mode;
+}
diff --git a/media/libdav1d/src/src/ipred_tmpl.c b/media/libdav1d/src/src/ipred_tmpl.c
new file mode 100644
index 0000000000..9cad40e5db
--- /dev/null
+++ b/media/libdav1d/src/src/ipred_tmpl.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "src/ipred.h"
+#include "src/tables.h"
+
+static NOINLINE void
+splat_dc(pixel *dst, const ptrdiff_t stride,
+         const int width, const int height, const int dc HIGHBD_DECL_SUFFIX)
+{
+#if BITDEPTH == 8
+    assert(dc <= 0xff);
+    if (width > 4) {
+        const uint64_t dcN = dc * 0x0101010101010101ULL;
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x += sizeof(dcN))
+                *((uint64_t *) &dst[x]) = dcN;
+            dst += PXSTRIDE(stride);
+        }
+    } else {
+        const unsigned dcN = dc * 0x01010101U;
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x += sizeof(dcN))
+                *((unsigned *) &dst[x]) = dcN;
+            dst += PXSTRIDE(stride);
+        }
+    }
+#else
+    assert(dc <= bitdepth_max);
+    const uint64_t dcN = dc * 0x0001000100010001ULL;
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x += sizeof(dcN) >> 1)
+            *((uint64_t *) &dst[x]) = dcN;
+        dst += PXSTRIDE(stride);
+    }
+#endif
+}
+
+static NOINLINE void
+cfl_pred(pixel *dst, const ptrdiff_t stride,
+         const int width, const int height, const int dc,
+         const int16_t *ac, const int alpha HIGHBD_DECL_SUFFIX)
+{
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x++) {
+            const int diff = alpha * ac[x];
+            dst[x] = iclip_pixel(dc + apply_sign((abs(diff) + 32) >> 6, diff));
+        }
+        ac += width;
+        dst += PXSTRIDE(stride);
+    }
+}
+
+static unsigned dc_gen_top(const pixel *const topleft, const int width) {
+    unsigned dc = width >> 1;
+    for (int i = 0; i < width; i++)
+       dc += topleft[1 + i];
+    return dc >> ctz(width);
+}
+
+static void ipred_dc_top_c(pixel *dst, const ptrdiff_t stride,
+                           const pixel *const topleft,
+                           const int width, const int height, const int a,
+                           const int max_width, const int max_height
+                           HIGHBD_DECL_SUFFIX)
+{
+    splat_dc(dst, stride, width, height, dc_gen_top(topleft, width)
+             HIGHBD_TAIL_SUFFIX);
+}
+
+static void ipred_cfl_top_c(pixel *dst, const ptrdiff_t stride,
+                            const pixel *const topleft,
+                            const int width, const int height,
+                            const int16_t *ac, const int alpha
+                            HIGHBD_DECL_SUFFIX)
+{
+    cfl_pred(dst, stride, width, height, dc_gen_top(topleft, width), ac, alpha
+             HIGHBD_TAIL_SUFFIX);
+}
+
+static unsigned dc_gen_left(const pixel *const topleft, const int height) {
+    unsigned dc = height >> 1;
+    for (int i = 0; i < height; i++)
+       dc += topleft[-(1 + i)];
+    return dc >> ctz(height);
+}
+
+static void ipred_dc_left_c(pixel *dst, const ptrdiff_t stride,
+                            const pixel *const topleft,
+                            const int width, const int height, const int a,
+                            const int max_width, const int max_height
+                            HIGHBD_DECL_SUFFIX)
+{
+    splat_dc(dst, stride, width, height, dc_gen_left(topleft, height)
+             HIGHBD_TAIL_SUFFIX);
+}
+
+static void ipred_cfl_left_c(pixel *dst, const ptrdiff_t stride,
+                             const pixel *const topleft,
+                             const int width, const int height,
+                             const int16_t *ac, const int alpha
+                             HIGHBD_DECL_SUFFIX)
+{
+    const unsigned dc = dc_gen_left(topleft, height);
+    cfl_pred(dst, stride, width, height, dc, ac, alpha HIGHBD_TAIL_SUFFIX);
+}
+
+#if BITDEPTH == 8
+#define MULTIPLIER_1x2 0x5556
+#define MULTIPLIER_1x4 0x3334
+#define BASE_SHIFT 16
+#else
+#define MULTIPLIER_1x2 0xAAAB
+#define MULTIPLIER_1x4 0x6667
+#define BASE_SHIFT 17
+#endif
+
+static unsigned dc_gen(const pixel *const topleft,
+                       const int width, const int height)
+{
+    unsigned dc = (width + height) >> 1;
+    for (int i = 0; i < width; i++)
+       dc += topleft[i + 1];
+    for (int i = 0; i < height; i++)
+       dc += topleft[-(i + 1)];
+    dc >>= ctz(width + height);
+
+    if (width != height) {
+        dc *= (width > height * 2 || height > width * 2) ? MULTIPLIER_1x4 :
+                                                           MULTIPLIER_1x2;
+        dc >>= BASE_SHIFT;
+    }
+    return dc;
+}
+
+static void ipred_dc_c(pixel *dst, const ptrdiff_t stride,
+                       const pixel *const topleft,
+                       const int width, const int height, const int a,
+                       const int max_width, const int max_height
+                       HIGHBD_DECL_SUFFIX)
+{
+    splat_dc(dst, stride, width, height, dc_gen(topleft, width, height)
+             HIGHBD_TAIL_SUFFIX);
+}
+
+static void ipred_cfl_c(pixel *dst, const ptrdiff_t stride,
+                        const pixel *const topleft,
+                        const int width, const int height,
+                        const int16_t *ac, const int alpha
+                        HIGHBD_DECL_SUFFIX)
+{
+    unsigned dc = dc_gen(topleft, width, height);
+    cfl_pred(dst, stride, width, height, dc, ac, alpha HIGHBD_TAIL_SUFFIX);
+}
+
+#undef MULTIPLIER_1x2
+#undef MULTIPLIER_1x4
+#undef BASE_SHIFT
+
+static void ipred_dc_128_c(pixel *dst, const ptrdiff_t stride,
+                           const pixel *const topleft,
+                           const int width, const int height, const int a,
+                           const int max_width, const int max_height
+                           HIGHBD_DECL_SUFFIX)
+{
+#if BITDEPTH == 16
+    const int dc = (bitdepth_max + 1) >> 1;
+#else
+    const int dc = 128;
+#endif
+    splat_dc(dst, stride, width, height, dc HIGHBD_TAIL_SUFFIX);
+}
+
+static void ipred_cfl_128_c(pixel *dst, const ptrdiff_t stride,
+                            const pixel *const topleft,
+                            const int width, const int height,
+                            const int16_t *ac, const int alpha
+                            HIGHBD_DECL_SUFFIX)
+{
+#if BITDEPTH == 16
+    const int dc = (bitdepth_max + 1) >> 1;
+#else
+    const int dc = 128;
+#endif
+    cfl_pred(dst, stride, width, height, dc, ac, alpha HIGHBD_TAIL_SUFFIX);
+}
+
+static void ipred_v_c(pixel *dst, const ptrdiff_t stride,
+                      const pixel *const topleft,
+                      const int width, const int height, const int a,
+                      const int max_width, const int max_height
+                      HIGHBD_DECL_SUFFIX)
+{
+    for (int y = 0; y < height; y++) {
+        pixel_copy(dst, topleft + 1, width);
+        dst += PXSTRIDE(stride);
+    }
+}
+
+static void ipred_h_c(pixel *dst, const ptrdiff_t stride,
+                      const pixel *const topleft,
+                      const int width, const int height, const int a,
+                      const int max_width, const int max_height
+                      HIGHBD_DECL_SUFFIX)
+{
+    for (int y = 0; y < height; y++) {
+        pixel_set(dst, topleft[-(1 + y)], width);
+        dst += PXSTRIDE(stride);
+    }
+}
+
+static void ipred_paeth_c(pixel *dst, const ptrdiff_t stride,
+                          const pixel *const tl_ptr,
+                          const int width, const int height, const int a,
+                          const int max_width, const int max_height
+                          HIGHBD_DECL_SUFFIX)
+{
+    const int topleft = tl_ptr[0];
+    for (int y = 0; y < height; y++) {
+        const int left = tl_ptr[-(y + 1)];
+        for (int x = 0; x < width; x++) {
+            const int top = tl_ptr[1 + x];
+            const int base = left + top - topleft;
+            const int ldiff = abs(left - base);
+            const int tdiff = abs(top - base);
+            const int tldiff = abs(topleft - base);
+
+            dst[x] = ldiff <= tdiff && ldiff <= tldiff ? left :
+                     tdiff <= tldiff ? top : topleft;
+        }
+        dst += PXSTRIDE(stride);
+    }
+}
+
+static void ipred_smooth_c(pixel *dst, const ptrdiff_t stride,
+                           const pixel *const topleft,
+                           const int width, const int height, const int a,
+                           const int max_width, const int max_height
+                           HIGHBD_DECL_SUFFIX)
+{
+    const uint8_t *const weights_hor = &dav1d_sm_weights[width];
+    const uint8_t *const weights_ver = &dav1d_sm_weights[height];
+    const int right = topleft[width], bottom = topleft[-height];
+
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x++) {
+            const int pred = weights_ver[y]  * topleft[1 + x] +
+                      (256 - weights_ver[y]) * bottom +
+                             weights_hor[x]  * topleft[-(1 + y)] +
+                      (256 - weights_hor[x]) * right;
+            dst[x] = (pred + 256) >> 9;
+        }
+        dst += PXSTRIDE(stride);
+    }
+}
+
+static void ipred_smooth_v_c(pixel *dst, const ptrdiff_t stride,
+                             const pixel *const topleft,
+                             const int width, const int height, const int a,
+                             const int max_width, const int max_height
+                             HIGHBD_DECL_SUFFIX)
+{
+    const uint8_t *const weights_ver = &dav1d_sm_weights[height];
+    const int bottom = topleft[-height];
+
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x++) {
+            const int pred = weights_ver[y]  * topleft[1 + x] +
+                      (256 - weights_ver[y]) * bottom;
+            dst[x] = (pred + 128) >> 8;
+        }
+        dst += PXSTRIDE(stride);
+    }
+}
+
+static void ipred_smooth_h_c(pixel *dst, const ptrdiff_t stride,
+                             const pixel *const topleft,
+                             const int width, const int height, const int a,
+                             const int max_width, const int max_height
+                             HIGHBD_DECL_SUFFIX)
+{
+    const uint8_t *const weights_hor = &dav1d_sm_weights[width];
+    const int right = topleft[width];
+
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x++) {
+            const int pred = weights_hor[x]  * topleft[-(y + 1)] +
+                      (256 - weights_hor[x]) * right;
+            dst[x] = (pred + 128) >> 8;
+        }
+        dst += PXSTRIDE(stride);
+    }
+}
+
+static NOINLINE int get_filter_strength(const int wh, const int angle,
+                                        const int is_sm)
+{
+    if (is_sm) {
+        if (wh <= 8) {
+            if (angle >= 64) return 2;
+            if (angle >= 40) return 1;
+        } else if (wh <= 16) {
+            if (angle >= 48) return 2;
+            if (angle >= 20) return 1;
+        } else if (wh <= 24) {
+            if (angle >=  4) return 3;
+        } else {
+            return 3;
+        }
+    } else {
+        if (wh <= 8) {
+            if (angle >= 56) return 1;
+        } else if (wh <= 16) {
+            if (angle >= 40) return 1;
+        } else if (wh <= 24) {
+            if (angle >= 32) return 3;
+            if (angle >= 16) return 2;
+            if (angle >=  8) return 1;
+        } else if (wh <= 32) {
+            if (angle >= 32) return 3;
+            if (angle >=  4) return 2;
+            return 1;
+        } else {
+            return 3;
+        }
+    }
+    return 0;
+}
+
+static NOINLINE void filter_edge(pixel *const out, const int sz,
+                                 const int lim_from, const int lim_to,
+                                 const pixel *const in, const int from,
+                                 const int to, const int strength)
+{
+    static const uint8_t kernel[3][5] = {
+        { 0, 4, 8, 4, 0 },
+        { 0, 5, 6, 5, 0 },
+        { 2, 4, 4, 4, 2 }
+    };
+
+    assert(strength > 0);
+    int i = 0;
+    for (; i < imin(sz, lim_from); i++)
+        out[i] = in[iclip(i, from, to - 1)];
+    for (; i < imin(lim_to, sz); i++) {
+        int s = 0;
+        for (int j = 0; j < 5; j++)
+            s += in[iclip(i - 2 + j, from, to - 1)] * kernel[strength - 1][j];
+        out[i] = (s + 8) >> 4;
+    }
+    for (; i < sz; i++)
+        out[i] = in[iclip(i, from, to - 1)];
+}
+
+static inline int get_upsample(const int wh, const int angle, const int is_sm) {
+    return angle < 40 && wh <= 16 >> is_sm;
+}
+
+static NOINLINE void upsample_edge(pixel *const out, const int hsz,
+                                   const pixel *const in, const int from,
+                                   const int to HIGHBD_DECL_SUFFIX)
+{
+    static const int8_t kernel[4] = { -1, 9, 9, -1 };
+    int i;
+    for (i = 0; i < hsz - 1; i++) {
+        out[i * 2] = in[iclip(i, from, to - 1)];
+
+        int s = 0;
+        for (int j = 0; j < 4; j++)
+            s += in[iclip(i + j - 1, from, to - 1)] * kernel[j];
+        out[i * 2 + 1] = iclip_pixel((s + 8) >> 4);
+    }
+    out[i * 2] = in[iclip(i, from, to - 1)];
+}
+
+static void ipred_z1_c(pixel *dst, const ptrdiff_t stride,
+                       const pixel *const topleft_in,
+                       const int width, const int height, int angle,
+                       const int max_width, const int max_height
+                       HIGHBD_DECL_SUFFIX)
+{
+    const int is_sm = (angle >> 9) & 0x1;
+    const int enable_intra_edge_filter = angle >> 10;
+    angle &= 511;
+    assert(angle < 90);
+    int dx = dav1d_dr_intra_derivative[angle >> 1];
+    pixel top_out[64 + 64];
+    const pixel *top;
+    int max_base_x;
+    const int upsample_above = enable_intra_edge_filter ?
+        get_upsample(width + height, 90 - angle, is_sm) : 0;
+    if (upsample_above) {
+        upsample_edge(top_out, width + height, &topleft_in[1], -1,
+                      width + imin(width, height) HIGHBD_TAIL_SUFFIX);
+        top = top_out;
+        max_base_x = 2 * (width + height) - 2;
+        dx <<= 1;
+    } else {
+        const int filter_strength = enable_intra_edge_filter ?
+            get_filter_strength(width + height, 90 - angle, is_sm) : 0;
+        if (filter_strength) {
+            filter_edge(top_out, width + height, 0, width + height,
+                        &topleft_in[1], -1, width + imin(width, height),
+                        filter_strength);
+            top = top_out;
+            max_base_x = width + height - 1;
+        } else {
+            top = &topleft_in[1];
+            max_base_x = width + imin(width, height) - 1;
+        }
+    }
+    const int base_inc = 1 + upsample_above;
+    for (int y = 0, xpos = dx; y < height;
+         y++, dst += PXSTRIDE(stride), xpos += dx)
+    {
+        const int frac = xpos & 0x3E;
+
+        for (int x = 0, base = xpos >> 6; x < width; x++, base += base_inc) {
+            if (base < max_base_x) {
+                const int v = top[base] * (64 - frac) + top[base + 1] * frac;
+                dst[x] = (v + 32) >> 6;
+            } else {
+                pixel_set(&dst[x], top[max_base_x], width - x);
+                break;
+            }
+        }
+    }
+}
+
+static void ipred_z2_c(pixel *dst, const ptrdiff_t stride,
+                       const pixel *const topleft_in,
+                       const int width, const int height, int angle,
+                       const int max_width, const int max_height
+                       HIGHBD_DECL_SUFFIX)
+{
+    const int is_sm = (angle >> 9) & 0x1;
+    const int enable_intra_edge_filter = angle >> 10;
+    angle &= 511;
+    assert(angle > 90 && angle < 180);
+    int dy = dav1d_dr_intra_derivative[(angle - 90) >> 1];
+    int dx = dav1d_dr_intra_derivative[(180 - angle) >> 1];
+    const int upsample_left = enable_intra_edge_filter ?
+        get_upsample(width + height, 180 - angle, is_sm) : 0;
+    const int upsample_above = enable_intra_edge_filter ?
+        get_upsample(width + height, angle - 90, is_sm) : 0;
+    pixel edge[64 + 64 + 1];
+    pixel *const topleft = &edge[64];
+
+    if (upsample_above) {
+        upsample_edge(topleft, width + 1, topleft_in, 0, width + 1
+                      HIGHBD_TAIL_SUFFIX);
+        dx <<= 1;
+    } else {
+        const int filter_strength = enable_intra_edge_filter ?
+            get_filter_strength(width + height, angle - 90, is_sm) : 0;
+
+        if (filter_strength) {
+            filter_edge(&topleft[1], width, 0, max_width,
+                        &topleft_in[1], -1, width,
+                        filter_strength);
+        } else {
+            pixel_copy(&topleft[1], &topleft_in[1], width);
+        }
+    }
+    if (upsample_left) {
+        upsample_edge(&topleft[-height * 2], height + 1, &topleft_in[-height],
+                      0, height + 1 HIGHBD_TAIL_SUFFIX);
+        dy <<= 1;
+    } else {
+        const int filter_strength = enable_intra_edge_filter ?
+            get_filter_strength(width + height, 180 - angle, is_sm) : 0;
+
+        if (filter_strength) {
+            filter_edge(&topleft[-height], height, height - max_height, height,
+                        &topleft_in[-height],
+                        0, height + 1, filter_strength);
+        } else {
+            pixel_copy(&topleft[-height], &topleft_in[-height], height);
+        }
+    }
+    *topleft = *topleft_in;
+
+    const int base_inc_x = 1 + upsample_above;
+    const pixel *const left = &topleft[-(1 + upsample_left)];
+    for (int y = 0, xpos = ((1 + upsample_above) << 6) - dx; y < height;
+         y++, xpos -= dx, dst += PXSTRIDE(stride))
+    {
+        int base_x = xpos >> 6;
+        const int frac_x = xpos & 0x3E;
+
+        for (int x = 0, ypos = (y << (6 + upsample_left)) - dy; x < width;
+             x++, base_x += base_inc_x, ypos -= dy)
+        {
+            int v;
+            if (base_x >= 0) {
+                v = topleft[base_x] * (64 - frac_x) +
+                    topleft[base_x + 1] * frac_x;
+            } else {
+                const int base_y = ypos >> 6;
+                assert(base_y >= -(1 + upsample_left));
+                const int frac_y = ypos & 0x3E;
+                v = left[-base_y] * (64 - frac_y) +
+                    left[-(base_y + 1)] * frac_y;
+            }
+            dst[x] = (v + 32) >> 6;
+        }
+    }
+}
+
+static void ipred_z3_c(pixel *dst, const ptrdiff_t stride,
+                       const pixel *const topleft_in,
+                       const int width, const int height, int angle,
+                       const int max_width, const int max_height
+                       HIGHBD_DECL_SUFFIX)
+{
+    const int is_sm = (angle >> 9) & 0x1;
+    const int enable_intra_edge_filter = angle >> 10;
+    angle &= 511;
+    assert(angle > 180);
+    int dy = dav1d_dr_intra_derivative[(270 - angle) >> 1];
+    pixel left_out[64 + 64];
+    const pixel *left;
+    int max_base_y;
+    const int upsample_left = enable_intra_edge_filter ?
+        get_upsample(width + height, angle - 180, is_sm) : 0;
+    if (upsample_left) {
+        upsample_edge(left_out, width + height,
+                      &topleft_in[-(width + height)],
+                      imax(width - height, 0), width + height + 1
+                      HIGHBD_TAIL_SUFFIX);
+        left = &left_out[2 * (width + height) - 2];
+        max_base_y = 2 * (width + height) - 2;
+        dy <<= 1;
+    } else {
+        const int filter_strength = enable_intra_edge_filter ?
+            get_filter_strength(width + height, angle - 180, is_sm) : 0;
+
+        if (filter_strength) {
+            filter_edge(left_out, width + height, 0, width + height,
+                        &topleft_in[-(width + height)],
+                        imax(width - height, 0), width + height + 1,
+                        filter_strength);
+            left = &left_out[width + height - 1];
+            max_base_y = width + height - 1;
+        } else {
+            left = &topleft_in[-1];
+            max_base_y = height + imin(width, height) - 1;
+        }
+    }
+    const int base_inc = 1 + upsample_left;
+    for (int x = 0, ypos = dy; x < width; x++, ypos += dy) {
+        const int frac = ypos & 0x3E;
+
+        for (int y = 0, base = ypos >> 6; y < height; y++, base += base_inc) {
+            if (base < max_base_y) {
+                const int v = left[-base] * (64 - frac) +
+                              left[-(base + 1)] * frac;
+                dst[y * PXSTRIDE(stride) + x] = (v + 32) >> 6;
+            } else {
+                do {
+                    dst[y * PXSTRIDE(stride) + x] = left[-max_base_y];
+                } while (++y < height);
+                break;
+            }
+        }
+    }
+}
+
+#if ARCH_X86
+#define FILTER(flt_ptr, p0, p1, p2, p3, p4, p5, p6) \
+    flt_ptr[ 0] * p0 + flt_ptr[ 1] * p1 +           \
+    flt_ptr[16] * p2 + flt_ptr[17] * p3 +           \
+    flt_ptr[32] * p4 + flt_ptr[33] * p5 +           \
+    flt_ptr[48] * p6
+#define FLT_INCR 2
+#else
+#define FILTER(flt_ptr, p0, p1, p2, p3, p4, p5, p6) \
+    flt_ptr[ 0] * p0 + flt_ptr[ 8] * p1 +           \
+    flt_ptr[16] * p2 + flt_ptr[24] * p3 +           \
+    flt_ptr[32] * p4 + flt_ptr[40] * p5 +           \
+    flt_ptr[48] * p6
+#define FLT_INCR 1
+#endif
+
+/* Up to 32x32 only */
+static void ipred_filter_c(pixel *dst, const ptrdiff_t stride,
+                           const pixel *const topleft_in,
+                           const int width, const int height, int filt_idx,
+                           const int max_width, const int max_height
+                           HIGHBD_DECL_SUFFIX)
+{
+    filt_idx &= 511;
+    assert(filt_idx < 5);
+
+    const int8_t *const filter = dav1d_filter_intra_taps[filt_idx];
+    const pixel *top = &topleft_in[1];
+    for (int y = 0; y < height; y += 2) {
+        const pixel *topleft = &topleft_in[-y];
+        const pixel *left = &topleft[-1];
+        ptrdiff_t left_stride = -1;
+        for (int x = 0; x < width; x += 4) {
+            const int p0 = *topleft;
+            const int p1 = top[0], p2 = top[1], p3 = top[2], p4 = top[3];
+            const int p5 = left[0 * left_stride], p6 = left[1 * left_stride];
+            pixel *ptr = &dst[x];
+            const int8_t *flt_ptr = filter;
+
+            for (int yy = 0; yy < 2; yy++) {
+                for (int xx = 0; xx < 4; xx++, flt_ptr += FLT_INCR) {
+                    const int acc = FILTER(flt_ptr, p0, p1, p2, p3, p4, p5, p6);
+                    ptr[xx] = iclip_pixel((acc + 8) >> 4);
+                }
+                ptr += PXSTRIDE(stride);
+            }
+            left = &dst[x + 4 - 1];
+            left_stride = PXSTRIDE(stride);
+            top += 4;
+            topleft = &top[-1];
+        }
+        top = &dst[PXSTRIDE(stride)];
+        dst = &dst[PXSTRIDE(stride) * 2];
+    }
+}
+
+static NOINLINE void
+cfl_ac_c(int16_t *ac, const pixel *ypx, const ptrdiff_t stride,
+         const int w_pad, const int h_pad, const int width, const int height,
+         const int ss_hor, const int ss_ver)
+{
+    int y, x;
+    int16_t *const ac_orig = ac;
+
+    assert(w_pad >= 0 && w_pad * 4 < width);
+    assert(h_pad >= 0 && h_pad * 4 < height);
+
+    for (y = 0; y < height - 4 * h_pad; y++) {
+        for (x = 0; x < width - 4 * w_pad; x++) {
+            int ac_sum = ypx[x << ss_hor];
+            if (ss_hor) ac_sum += ypx[x * 2 + 1];
+            if (ss_ver) {
+                ac_sum += ypx[(x << ss_hor) + PXSTRIDE(stride)];
+                if (ss_hor) ac_sum += ypx[x * 2 + 1 + PXSTRIDE(stride)];
+            }
+            ac[x] = ac_sum << (1 + !ss_ver + !ss_hor);
+        }
+        for (; x < width; x++)
+            ac[x] = ac[x - 1];
+        ac += width;
+        ypx += PXSTRIDE(stride) << ss_ver;
+    }
+    for (; y < height; y++) {
+        memcpy(ac, &ac[-width], width * sizeof(*ac));
+        ac += width;
+    }
+
+    const int log2sz = ctz(width) + ctz(height);
+    int sum = (1 << log2sz) >> 1;
+    for (ac = ac_orig, y = 0; y < height; y++) {
+        for (x = 0; x < width; x++)
+            sum += ac[x];
+        ac += width;
+    }
+    sum >>= log2sz;
+
+    // subtract DC
+    for (ac = ac_orig, y = 0; y < height; y++) {
+        for (x = 0; x < width; x++)
+            ac[x] -= sum;
+        ac += width;
+    }
+}
+
+#define cfl_ac_fn(fmt, ss_hor, ss_ver) \
+static void cfl_ac_##fmt##_c(int16_t *const ac, const pixel *const ypx, \
+                             const ptrdiff_t stride, const int w_pad, \
+                             const int h_pad, const int cw, const int ch) \
+{ \
+    cfl_ac_c(ac, ypx, stride, w_pad, h_pad, cw, ch, ss_hor, ss_ver); \
+}
+
+cfl_ac_fn(420, 1, 1)
+cfl_ac_fn(422, 1, 0)
+cfl_ac_fn(444, 0, 0)
+
+static void pal_pred_c(pixel *dst, const ptrdiff_t stride,
+                       const pixel *const pal, const uint8_t *idx,
+                       const int w, const int h)
+{
+    for (int y = 0; y < h; y++) {
+        for (int x = 0; x < w; x += 2) {
+            const int i = *idx++;
+            assert(!(i & 0x88));
+            dst[x + 0] = pal[i & 7];
+            dst[x + 1] = pal[i >> 4];
+        }
+        dst += PXSTRIDE(stride);
+    }
+}
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/ipred.h"
+#elif ARCH_RISCV
+#include "src/riscv/ipred.h"
+#elif ARCH_X86
+#include "src/x86/ipred.h"
+#elif ARCH_LOONGARCH64
+#include "src/loongarch/ipred.h"
+#endif
+#endif
+
+COLD void bitfn(dav1d_intra_pred_dsp_init)(Dav1dIntraPredDSPContext *const c) {
+    c->intra_pred[DC_PRED      ] = ipred_dc_c;
+    c->intra_pred[DC_128_PRED  ] = ipred_dc_128_c;
+    c->intra_pred[TOP_DC_PRED  ] = ipred_dc_top_c;
+    c->intra_pred[LEFT_DC_PRED ] = ipred_dc_left_c;
+    c->intra_pred[HOR_PRED     ] = ipred_h_c;
+    c->intra_pred[VERT_PRED    ] = ipred_v_c;
+    c->intra_pred[PAETH_PRED   ] = ipred_paeth_c;
+    c->intra_pred[SMOOTH_PRED  ] = ipred_smooth_c;
+    c->intra_pred[SMOOTH_V_PRED] = ipred_smooth_v_c;
+    c->intra_pred[SMOOTH_H_PRED] = ipred_smooth_h_c;
+    c->intra_pred[Z1_PRED      ] = ipred_z1_c;
+    c->intra_pred[Z2_PRED      ] = ipred_z2_c;
+    c->intra_pred[Z3_PRED      ] = ipred_z3_c;
+    c->intra_pred[FILTER_PRED  ] = ipred_filter_c;
+
+    c->cfl_ac[DAV1D_PIXEL_LAYOUT_I420 - 1] = cfl_ac_420_c;
+    c->cfl_ac[DAV1D_PIXEL_LAYOUT_I422 - 1] = cfl_ac_422_c;
+    c->cfl_ac[DAV1D_PIXEL_LAYOUT_I444 - 1] = cfl_ac_444_c;
+
+    c->cfl_pred[DC_PRED     ] = ipred_cfl_c;
+    c->cfl_pred[DC_128_PRED ] = ipred_cfl_128_c;
+    c->cfl_pred[TOP_DC_PRED ] = ipred_cfl_top_c;
+    c->cfl_pred[LEFT_DC_PRED] = ipred_cfl_left_c;
+
+    c->pal_pred = pal_pred_c;
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+    intra_pred_dsp_init_arm(c);
+#elif ARCH_RISCV
+    intra_pred_dsp_init_riscv(c);
+#elif ARCH_X86
+    intra_pred_dsp_init_x86(c);
+#elif ARCH_LOONGARCH64
+    intra_pred_dsp_init_loongarch(c);
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/itx.h b/media/libdav1d/src/src/itx.h
new file mode 100644
index 0000000000..8ef4f4df48
--- /dev/null
+++ b/media/libdav1d/src/src/itx.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_ITX_H
+#define DAV1D_SRC_ITX_H
+
+#include 
+
+#include "common/bitdepth.h"
+
+#include "src/levels.h"
+
+#define decl_itx_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, coef *coeff, int eob \
+            HIGHBD_DECL_SUFFIX)
+typedef decl_itx_fn(*itxfm_fn);
+
+#define decl_itx2_fns(w, h, opt) \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_identity_identity_##w##x##h, opt))
+
+#define decl_itx12_fns(w, h, opt) \
+decl_itx2_fns(w, h, opt); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_adst_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_flipadst_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_identity_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_dct_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_adst_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_flipadst_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_flipadst_dct_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_flipadst_adst_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_flipadst_flipadst_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_identity_dct_##w##x##h, opt))
+
+#define decl_itx16_fns(w, h, opt) \
+decl_itx12_fns(w, h, opt); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_identity_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_flipadst_identity_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_identity_adst_##w##x##h, opt)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_identity_flipadst_##w##x##h, opt))
+
+#define decl_itx17_fns(w, h, opt) \
+decl_itx16_fns(w, h, opt); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_wht_wht_##w##x##h, opt))
+
+typedef struct Dav1dInvTxfmDSPContext {
+    itxfm_fn itxfm_add[N_RECT_TX_SIZES][N_TX_TYPES_PLUS_LL];
+} Dav1dInvTxfmDSPContext;
+
+bitfn_decls(void dav1d_itx_dsp_init, Dav1dInvTxfmDSPContext *c, int bpc);
+
+#define assign_itx_fn(pfx, w, h, type, type_enum, ext) \
+    c->itxfm_add[pfx##TX_##w##X##h][type_enum] = \
+        BF(dav1d_inv_txfm_add_##type##_##w##x##h, ext)
+
+#define assign_itx1_fn(pfx, w, h, ext) \
+    assign_itx_fn(pfx, w, h, dct_dct,           DCT_DCT,           ext)
+
+#define assign_itx2_fn(pfx, w, h, ext) \
+    assign_itx1_fn(pfx, w, h, ext); \
+    assign_itx_fn(pfx, w, h, identity_identity, IDTX,              ext)
+
+#define assign_itx12_fn(pfx, w, h, ext) \
+    assign_itx2_fn(pfx, w, h, ext); \
+    assign_itx_fn(pfx, w, h, dct_adst,          ADST_DCT,          ext); \
+    assign_itx_fn(pfx, w, h, dct_flipadst,      FLIPADST_DCT,      ext); \
+    assign_itx_fn(pfx, w, h, dct_identity,      H_DCT,             ext); \
+    assign_itx_fn(pfx, w, h, adst_dct,          DCT_ADST,          ext); \
+    assign_itx_fn(pfx, w, h, adst_adst,         ADST_ADST,         ext); \
+    assign_itx_fn(pfx, w, h, adst_flipadst,     FLIPADST_ADST,     ext); \
+    assign_itx_fn(pfx, w, h, flipadst_dct,      DCT_FLIPADST,      ext); \
+    assign_itx_fn(pfx, w, h, flipadst_adst,     ADST_FLIPADST,     ext); \
+    assign_itx_fn(pfx, w, h, flipadst_flipadst, FLIPADST_FLIPADST, ext); \
+    assign_itx_fn(pfx, w, h, identity_dct,      V_DCT,             ext)
+
+#define assign_itx16_fn(pfx, w, h, ext) \
+    assign_itx12_fn(pfx, w, h, ext); \
+    assign_itx_fn(pfx, w, h, adst_identity,     H_ADST,            ext); \
+    assign_itx_fn(pfx, w, h, flipadst_identity, H_FLIPADST,        ext); \
+    assign_itx_fn(pfx, w, h, identity_adst,     V_ADST,            ext); \
+    assign_itx_fn(pfx, w, h, identity_flipadst, V_FLIPADST,        ext)
+
+#define assign_itx17_fn(pfx, w, h, ext) \
+    assign_itx16_fn(pfx, w, h, ext); \
+    assign_itx_fn(pfx, w, h, wht_wht,           WHT_WHT,           ext)
+
+#endif /* DAV1D_SRC_ITX_H */
diff --git a/media/libdav1d/src/src/itx_1d.c b/media/libdav1d/src/src/itx_1d.c
new file mode 100644
index 0000000000..14e89ca0c8
--- /dev/null
+++ b/media/libdav1d/src/src/itx_1d.c
@@ -0,0 +1,1082 @@
+/*
+ * Copyright © 2018-2019, VideoLAN and dav1d authors
+ * Copyright © 2018-2019, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "common/intops.h"
+
+#include "src/itx_1d.h"
+
+#define CLIP(a) iclip(a, min, max)
+
+/*
+ * In some places, we use the pattern like this:
+ * t2 = ((in1 *  1567         - in3 * (3784 - 4096) + 2048) >> 12) - in3;
+ * even though the reference code might use something like:
+ * t2 =  (in1 *  1567         - in3 *  3784         + 2048) >> 12;
+ *
+ * The reason for this is that for 12 bits/component bitstreams (corrupt/
+ * invalid ones, but they are codable nonetheless), each coefficient or
+ * input can be 19(+sign) bits, and therefore if the combination of the
+ * two multipliers (each 12 bits) is >= 4096, the result of the add/sub
+ * after the pair of multiplies will exceed the 31+sign bit range. Signed
+ * integer overflows are UB in C, and we'd like to prevent that.
+ *
+ * To workaround this, we invert one of the two coefficients (or, if both are
+ * multiples of 2, we reduce their magnitude by one bit). It should be noted
+ * that SIMD implementations do not have to follow this exact behaviour. The
+ * AV1 spec clearly states that the result of the multiply/add pairs should
+ * fit in 31+sign bit intermediates, and that streams violating this convention
+ * are not AV1-compliant. So, as long as we don't trigger UB (which some people
+ * would consider a security vulnerability), we're fine. So, SIMD can simply
+ * use the faster implementation, even if that might in some cases result in
+ * integer overflows, since these are not considered valid AV1 anyway, and in
+ * e.g. x86 assembly, integer overflows are not considered UB, but they merely
+ * wrap around.
+ */
+
+static NOINLINE void
+inv_dct4_1d_internal_c(int32_t *const c, const ptrdiff_t stride,
+                       const int min, const int max, const int tx64)
+{
+    assert(stride > 0);
+    const int in0 = c[0 * stride], in1 = c[1 * stride];
+
+    int t0, t1, t2, t3;
+    if (tx64) {
+        t0 = t1 = (in0 * 181 + 128) >> 8;
+        t2 = (in1 * 1567 + 2048) >> 12;
+        t3 = (in1 * 3784 + 2048) >> 12;
+    } else {
+        const int in2 = c[2 * stride], in3 = c[3 * stride];
+
+        t0 = ((in0 + in2) * 181 + 128) >> 8;
+        t1 = ((in0 - in2) * 181 + 128) >> 8;
+        t2 = ((in1 *  1567         - in3 * (3784 - 4096) + 2048) >> 12) - in3;
+        t3 = ((in1 * (3784 - 4096) + in3 *  1567         + 2048) >> 12) + in1;
+    }
+
+    c[0 * stride] = CLIP(t0 + t3);
+    c[1 * stride] = CLIP(t1 + t2);
+    c[2 * stride] = CLIP(t1 - t2);
+    c[3 * stride] = CLIP(t0 - t3);
+}
+
+static void inv_dct4_1d_c(int32_t *const c, const ptrdiff_t stride,
+                          const int min, const int max)
+{
+    inv_dct4_1d_internal_c(c, stride, min, max, 0);
+}
+
+static NOINLINE void
+inv_dct8_1d_internal_c(int32_t *const c, const ptrdiff_t stride,
+                       const int min, const int max, const int tx64)
+{
+    assert(stride > 0);
+    inv_dct4_1d_internal_c(c, stride << 1, min, max, tx64);
+
+    const int in1 = c[1 * stride], in3 = c[3 * stride];
+
+    int t4a, t5a, t6a, t7a;
+    if (tx64) {
+        t4a = (in1 *   799 + 2048) >> 12;
+        t5a = (in3 * -2276 + 2048) >> 12;
+        t6a = (in3 *  3406 + 2048) >> 12;
+        t7a = (in1 *  4017 + 2048) >> 12;
+    } else {
+        const int in5 = c[5 * stride], in7 = c[7 * stride];
+
+        t4a = ((in1 *   799         - in7 * (4017 - 4096) + 2048) >> 12) - in7;
+        t5a =  (in5 *  1703         - in3 *  1138         + 1024) >> 11;
+        t6a =  (in5 *  1138         + in3 *  1703         + 1024) >> 11;
+        t7a = ((in1 * (4017 - 4096) + in7 *  799          + 2048) >> 12) + in1;
+    }
+
+    const int t4  = CLIP(t4a + t5a);
+              t5a = CLIP(t4a - t5a);
+    const int t7  = CLIP(t7a + t6a);
+              t6a = CLIP(t7a - t6a);
+
+    const int t5  = ((t6a - t5a) * 181 + 128) >> 8;
+    const int t6  = ((t6a + t5a) * 181 + 128) >> 8;
+
+    const int t0 = c[0 * stride];
+    const int t1 = c[2 * stride];
+    const int t2 = c[4 * stride];
+    const int t3 = c[6 * stride];
+
+    c[0 * stride] = CLIP(t0 + t7);
+    c[1 * stride] = CLIP(t1 + t6);
+    c[2 * stride] = CLIP(t2 + t5);
+    c[3 * stride] = CLIP(t3 + t4);
+    c[4 * stride] = CLIP(t3 - t4);
+    c[5 * stride] = CLIP(t2 - t5);
+    c[6 * stride] = CLIP(t1 - t6);
+    c[7 * stride] = CLIP(t0 - t7);
+}
+
+static void inv_dct8_1d_c(int32_t *const c, const ptrdiff_t stride,
+                          const int min, const int max)
+{
+    inv_dct8_1d_internal_c(c, stride, min, max, 0);
+}
+
+static NOINLINE void
+inv_dct16_1d_internal_c(int32_t *const c, const ptrdiff_t stride,
+                        const int min, const int max, int tx64)
+{
+    assert(stride > 0);
+    inv_dct8_1d_internal_c(c, stride << 1, min, max, tx64);
+
+    const int in1 = c[1 * stride], in3 = c[3 * stride];
+    const int in5 = c[5 * stride], in7 = c[7 * stride];
+
+    int t8a, t9a, t10a, t11a, t12a, t13a, t14a, t15a;
+    if (tx64) {
+        t8a  = (in1 *   401 + 2048) >> 12;
+        t9a  = (in7 * -2598 + 2048) >> 12;
+        t10a = (in5 *  1931 + 2048) >> 12;
+        t11a = (in3 * -1189 + 2048) >> 12;
+        t12a = (in3 *  3920 + 2048) >> 12;
+        t13a = (in5 *  3612 + 2048) >> 12;
+        t14a = (in7 *  3166 + 2048) >> 12;
+        t15a = (in1 *  4076 + 2048) >> 12;
+    } else {
+        const int in9  = c[ 9 * stride], in11 = c[11 * stride];
+        const int in13 = c[13 * stride], in15 = c[15 * stride];
+
+        t8a  = ((in1  *   401         - in15 * (4076 - 4096) + 2048) >> 12) - in15;
+        t9a  =  (in9  *  1583         - in7  *  1299         + 1024) >> 11;
+        t10a = ((in5  *  1931         - in11 * (3612 - 4096) + 2048) >> 12) - in11;
+        t11a = ((in13 * (3920 - 4096) - in3  *  1189         + 2048) >> 12) + in13;
+        t12a = ((in13 *  1189         + in3  * (3920 - 4096) + 2048) >> 12) + in3;
+        t13a = ((in5  * (3612 - 4096) + in11 *  1931         + 2048) >> 12) + in5;
+        t14a =  (in9  *  1299         + in7  *  1583         + 1024) >> 11;
+        t15a = ((in1  * (4076 - 4096) + in15 *   401         + 2048) >> 12) + in1;
+    }
+
+    int t8  = CLIP(t8a  + t9a);
+    int t9  = CLIP(t8a  - t9a);
+    int t10 = CLIP(t11a - t10a);
+    int t11 = CLIP(t11a + t10a);
+    int t12 = CLIP(t12a + t13a);
+    int t13 = CLIP(t12a - t13a);
+    int t14 = CLIP(t15a - t14a);
+    int t15 = CLIP(t15a + t14a);
+
+    t9a  = ((  t14 *  1567         - t9  * (3784 - 4096)  + 2048) >> 12) - t9;
+    t14a = ((  t14 * (3784 - 4096) + t9  *  1567          + 2048) >> 12) + t14;
+    t10a = ((-(t13 * (3784 - 4096) + t10 *  1567)         + 2048) >> 12) - t13;
+    t13a = ((  t13 *  1567         - t10 * (3784 - 4096)  + 2048) >> 12) - t10;
+
+    t8a  = CLIP(t8   + t11);
+    t9   = CLIP(t9a  + t10a);
+    t10  = CLIP(t9a  - t10a);
+    t11a = CLIP(t8   - t11);
+    t12a = CLIP(t15  - t12);
+    t13  = CLIP(t14a - t13a);
+    t14  = CLIP(t14a + t13a);
+    t15a = CLIP(t15  + t12);
+
+    t10a = ((t13  - t10)  * 181 + 128) >> 8;
+    t13a = ((t13  + t10)  * 181 + 128) >> 8;
+    t11  = ((t12a - t11a) * 181 + 128) >> 8;
+    t12  = ((t12a + t11a) * 181 + 128) >> 8;
+
+    const int t0 = c[ 0 * stride];
+    const int t1 = c[ 2 * stride];
+    const int t2 = c[ 4 * stride];
+    const int t3 = c[ 6 * stride];
+    const int t4 = c[ 8 * stride];
+    const int t5 = c[10 * stride];
+    const int t6 = c[12 * stride];
+    const int t7 = c[14 * stride];
+
+    c[ 0 * stride] = CLIP(t0 + t15a);
+    c[ 1 * stride] = CLIP(t1 + t14);
+    c[ 2 * stride] = CLIP(t2 + t13a);
+    c[ 3 * stride] = CLIP(t3 + t12);
+    c[ 4 * stride] = CLIP(t4 + t11);
+    c[ 5 * stride] = CLIP(t5 + t10a);
+    c[ 6 * stride] = CLIP(t6 + t9);
+    c[ 7 * stride] = CLIP(t7 + t8a);
+    c[ 8 * stride] = CLIP(t7 - t8a);
+    c[ 9 * stride] = CLIP(t6 - t9);
+    c[10 * stride] = CLIP(t5 - t10a);
+    c[11 * stride] = CLIP(t4 - t11);
+    c[12 * stride] = CLIP(t3 - t12);
+    c[13 * stride] = CLIP(t2 - t13a);
+    c[14 * stride] = CLIP(t1 - t14);
+    c[15 * stride] = CLIP(t0 - t15a);
+}
+
+static void inv_dct16_1d_c(int32_t *const c, const ptrdiff_t stride,
+                           const int min, const int max)
+{
+    inv_dct16_1d_internal_c(c, stride, min, max, 0);
+}
+
+static NOINLINE void
+inv_dct32_1d_internal_c(int32_t *const c, const ptrdiff_t stride,
+                        const int min, const int max, const int tx64)
+{
+    assert(stride > 0);
+    inv_dct16_1d_internal_c(c, stride << 1, min, max, tx64);
+
+    const int in1  = c[ 1 * stride], in3  = c[ 3 * stride];
+    const int in5  = c[ 5 * stride], in7  = c[ 7 * stride];
+    const int in9  = c[ 9 * stride], in11 = c[11 * stride];
+    const int in13 = c[13 * stride], in15 = c[15 * stride];
+
+    int t16a, t17a, t18a, t19a, t20a, t21a, t22a, t23a;
+    int t24a, t25a, t26a, t27a, t28a, t29a, t30a, t31a;
+    if (tx64) {
+        t16a = (in1  *   201 + 2048) >> 12;
+        t17a = (in15 * -2751 + 2048) >> 12;
+        t18a = (in9  *  1751 + 2048) >> 12;
+        t19a = (in7  * -1380 + 2048) >> 12;
+        t20a = (in5  *   995 + 2048) >> 12;
+        t21a = (in11 * -2106 + 2048) >> 12;
+        t22a = (in13 *  2440 + 2048) >> 12;
+        t23a = (in3  *  -601 + 2048) >> 12;
+        t24a = (in3  *  4052 + 2048) >> 12;
+        t25a = (in13 *  3290 + 2048) >> 12;
+        t26a = (in11 *  3513 + 2048) >> 12;
+        t27a = (in5  *  3973 + 2048) >> 12;
+        t28a = (in7  *  3857 + 2048) >> 12;
+        t29a = (in9  *  3703 + 2048) >> 12;
+        t30a = (in15 *  3035 + 2048) >> 12;
+        t31a = (in1  *  4091 + 2048) >> 12;
+    } else {
+        const int in17 = c[17 * stride], in19 = c[19 * stride];
+        const int in21 = c[21 * stride], in23 = c[23 * stride];
+        const int in25 = c[25 * stride], in27 = c[27 * stride];
+        const int in29 = c[29 * stride], in31 = c[31 * stride];
+
+        t16a = ((in1  *   201         - in31 * (4091 - 4096) + 2048) >> 12) - in31;
+        t17a = ((in17 * (3035 - 4096) - in15 *  2751         + 2048) >> 12) + in17;
+        t18a = ((in9  *  1751         - in23 * (3703 - 4096) + 2048) >> 12) - in23;
+        t19a = ((in25 * (3857 - 4096) - in7  *  1380         + 2048) >> 12) + in25;
+        t20a = ((in5  *   995         - in27 * (3973 - 4096) + 2048) >> 12) - in27;
+        t21a = ((in21 * (3513 - 4096) - in11 *  2106         + 2048) >> 12) + in21;
+        t22a =  (in13 *  1220         - in19 *  1645         + 1024) >> 11;
+        t23a = ((in29 * (4052 - 4096) - in3  *   601         + 2048) >> 12) + in29;
+        t24a = ((in29 *   601         + in3  * (4052 - 4096) + 2048) >> 12) + in3;
+        t25a =  (in13 *  1645         + in19 *  1220         + 1024) >> 11;
+        t26a = ((in21 *  2106         + in11 * (3513 - 4096) + 2048) >> 12) + in11;
+        t27a = ((in5  * (3973 - 4096) + in27 *   995         + 2048) >> 12) + in5;
+        t28a = ((in25 *  1380         + in7  * (3857 - 4096) + 2048) >> 12) + in7;
+        t29a = ((in9  * (3703 - 4096) + in23 *  1751         + 2048) >> 12) + in9;
+        t30a = ((in17 *  2751         + in15 * (3035 - 4096) + 2048) >> 12) + in15;
+        t31a = ((in1  * (4091 - 4096) + in31 *   201         + 2048) >> 12) + in1;
+    }
+
+    int t16 = CLIP(t16a + t17a);
+    int t17 = CLIP(t16a - t17a);
+    int t18 = CLIP(t19a - t18a);
+    int t19 = CLIP(t19a + t18a);
+    int t20 = CLIP(t20a + t21a);
+    int t21 = CLIP(t20a - t21a);
+    int t22 = CLIP(t23a - t22a);
+    int t23 = CLIP(t23a + t22a);
+    int t24 = CLIP(t24a + t25a);
+    int t25 = CLIP(t24a - t25a);
+    int t26 = CLIP(t27a - t26a);
+    int t27 = CLIP(t27a + t26a);
+    int t28 = CLIP(t28a + t29a);
+    int t29 = CLIP(t28a - t29a);
+    int t30 = CLIP(t31a - t30a);
+    int t31 = CLIP(t31a + t30a);
+
+    t17a = ((  t30 *   799         - t17 * (4017 - 4096)  + 2048) >> 12) - t17;
+    t30a = ((  t30 * (4017 - 4096) + t17 *   799          + 2048) >> 12) + t30;
+    t18a = ((-(t29 * (4017 - 4096) + t18 *   799)         + 2048) >> 12) - t29;
+    t29a = ((  t29 *   799         - t18 * (4017 - 4096)  + 2048) >> 12) - t18;
+    t21a =  (  t26 *  1703         - t21 *  1138          + 1024) >> 11;
+    t26a =  (  t26 *  1138         + t21 *  1703          + 1024) >> 11;
+    t22a =  (-(t25 *  1138         + t22 *  1703        ) + 1024) >> 11;
+    t25a =  (  t25 *  1703         - t22 *  1138          + 1024) >> 11;
+
+    t16a = CLIP(t16  + t19);
+    t17  = CLIP(t17a + t18a);
+    t18  = CLIP(t17a - t18a);
+    t19a = CLIP(t16  - t19);
+    t20a = CLIP(t23  - t20);
+    t21  = CLIP(t22a - t21a);
+    t22  = CLIP(t22a + t21a);
+    t23a = CLIP(t23  + t20);
+    t24a = CLIP(t24  + t27);
+    t25  = CLIP(t25a + t26a);
+    t26  = CLIP(t25a - t26a);
+    t27a = CLIP(t24  - t27);
+    t28a = CLIP(t31  - t28);
+    t29  = CLIP(t30a - t29a);
+    t30  = CLIP(t30a + t29a);
+    t31a = CLIP(t31  + t28);
+
+    t18a = ((  t29  *  1567         - t18  * (3784 - 4096)  + 2048) >> 12) - t18;
+    t29a = ((  t29  * (3784 - 4096) + t18  *  1567          + 2048) >> 12) + t29;
+    t19  = ((  t28a *  1567         - t19a * (3784 - 4096)  + 2048) >> 12) - t19a;
+    t28  = ((  t28a * (3784 - 4096) + t19a *  1567          + 2048) >> 12) + t28a;
+    t20  = ((-(t27a * (3784 - 4096) + t20a *  1567)         + 2048) >> 12) - t27a;
+    t27  = ((  t27a *  1567         - t20a * (3784 - 4096)  + 2048) >> 12) - t20a;
+    t21a = ((-(t26  * (3784 - 4096) + t21  *  1567)         + 2048) >> 12) - t26;
+    t26a = ((  t26  *  1567         - t21  * (3784 - 4096)  + 2048) >> 12) - t21;
+
+    t16  = CLIP(t16a + t23a);
+    t17a = CLIP(t17  + t22);
+    t18  = CLIP(t18a + t21a);
+    t19a = CLIP(t19  + t20);
+    t20a = CLIP(t19  - t20);
+    t21  = CLIP(t18a - t21a);
+    t22a = CLIP(t17  - t22);
+    t23  = CLIP(t16a - t23a);
+    t24  = CLIP(t31a - t24a);
+    t25a = CLIP(t30  - t25);
+    t26  = CLIP(t29a - t26a);
+    t27a = CLIP(t28  - t27);
+    t28a = CLIP(t28  + t27);
+    t29  = CLIP(t29a + t26a);
+    t30a = CLIP(t30  + t25);
+    t31  = CLIP(t31a + t24a);
+
+    t20  = ((t27a - t20a) * 181 + 128) >> 8;
+    t27  = ((t27a + t20a) * 181 + 128) >> 8;
+    t21a = ((t26  - t21 ) * 181 + 128) >> 8;
+    t26a = ((t26  + t21 ) * 181 + 128) >> 8;
+    t22  = ((t25a - t22a) * 181 + 128) >> 8;
+    t25  = ((t25a + t22a) * 181 + 128) >> 8;
+    t23a = ((t24  - t23 ) * 181 + 128) >> 8;
+    t24a = ((t24  + t23 ) * 181 + 128) >> 8;
+
+    const int t0  = c[ 0 * stride];
+    const int t1  = c[ 2 * stride];
+    const int t2  = c[ 4 * stride];
+    const int t3  = c[ 6 * stride];
+    const int t4  = c[ 8 * stride];
+    const int t5  = c[10 * stride];
+    const int t6  = c[12 * stride];
+    const int t7  = c[14 * stride];
+    const int t8  = c[16 * stride];
+    const int t9  = c[18 * stride];
+    const int t10 = c[20 * stride];
+    const int t11 = c[22 * stride];
+    const int t12 = c[24 * stride];
+    const int t13 = c[26 * stride];
+    const int t14 = c[28 * stride];
+    const int t15 = c[30 * stride];
+
+    c[ 0 * stride] = CLIP(t0  + t31);
+    c[ 1 * stride] = CLIP(t1  + t30a);
+    c[ 2 * stride] = CLIP(t2  + t29);
+    c[ 3 * stride] = CLIP(t3  + t28a);
+    c[ 4 * stride] = CLIP(t4  + t27);
+    c[ 5 * stride] = CLIP(t5  + t26a);
+    c[ 6 * stride] = CLIP(t6  + t25);
+    c[ 7 * stride] = CLIP(t7  + t24a);
+    c[ 8 * stride] = CLIP(t8  + t23a);
+    c[ 9 * stride] = CLIP(t9  + t22);
+    c[10 * stride] = CLIP(t10 + t21a);
+    c[11 * stride] = CLIP(t11 + t20);
+    c[12 * stride] = CLIP(t12 + t19a);
+    c[13 * stride] = CLIP(t13 + t18);
+    c[14 * stride] = CLIP(t14 + t17a);
+    c[15 * stride] = CLIP(t15 + t16);
+    c[16 * stride] = CLIP(t15 - t16);
+    c[17 * stride] = CLIP(t14 - t17a);
+    c[18 * stride] = CLIP(t13 - t18);
+    c[19 * stride] = CLIP(t12 - t19a);
+    c[20 * stride] = CLIP(t11 - t20);
+    c[21 * stride] = CLIP(t10 - t21a);
+    c[22 * stride] = CLIP(t9  - t22);
+    c[23 * stride] = CLIP(t8  - t23a);
+    c[24 * stride] = CLIP(t7  - t24a);
+    c[25 * stride] = CLIP(t6  - t25);
+    c[26 * stride] = CLIP(t5  - t26a);
+    c[27 * stride] = CLIP(t4  - t27);
+    c[28 * stride] = CLIP(t3  - t28a);
+    c[29 * stride] = CLIP(t2  - t29);
+    c[30 * stride] = CLIP(t1  - t30a);
+    c[31 * stride] = CLIP(t0  - t31);
+}
+
+static void inv_dct32_1d_c(int32_t *const c, const ptrdiff_t stride,
+                           const int min, const int max)
+{
+    inv_dct32_1d_internal_c(c, stride, min, max, 0);
+}
+
+static void inv_dct64_1d_c(int32_t *const c, const ptrdiff_t stride,
+                           const int min, const int max)
+{
+    assert(stride > 0);
+    inv_dct32_1d_internal_c(c, stride << 1, min, max, 1);
+
+    const int in1  = c[ 1 * stride], in3  = c[ 3 * stride];
+    const int in5  = c[ 5 * stride], in7  = c[ 7 * stride];
+    const int in9  = c[ 9 * stride], in11 = c[11 * stride];
+    const int in13 = c[13 * stride], in15 = c[15 * stride];
+    const int in17 = c[17 * stride], in19 = c[19 * stride];
+    const int in21 = c[21 * stride], in23 = c[23 * stride];
+    const int in25 = c[25 * stride], in27 = c[27 * stride];
+    const int in29 = c[29 * stride], in31 = c[31 * stride];
+
+    int t32a = (in1  *   101 + 2048) >> 12;
+    int t33a = (in31 * -2824 + 2048) >> 12;
+    int t34a = (in17 *  1660 + 2048) >> 12;
+    int t35a = (in15 * -1474 + 2048) >> 12;
+    int t36a = (in9  *   897 + 2048) >> 12;
+    int t37a = (in23 * -2191 + 2048) >> 12;
+    int t38a = (in25 *  2359 + 2048) >> 12;
+    int t39a = (in7  *  -700 + 2048) >> 12;
+    int t40a = (in5  *   501 + 2048) >> 12;
+    int t41a = (in27 * -2520 + 2048) >> 12;
+    int t42a = (in21 *  2019 + 2048) >> 12;
+    int t43a = (in11 * -1092 + 2048) >> 12;
+    int t44a = (in13 *  1285 + 2048) >> 12;
+    int t45a = (in19 * -1842 + 2048) >> 12;
+    int t46a = (in29 *  2675 + 2048) >> 12;
+    int t47a = (in3  *  -301 + 2048) >> 12;
+    int t48a = (in3  *  4085 + 2048) >> 12;
+    int t49a = (in29 *  3102 + 2048) >> 12;
+    int t50a = (in19 *  3659 + 2048) >> 12;
+    int t51a = (in13 *  3889 + 2048) >> 12;
+    int t52a = (in11 *  3948 + 2048) >> 12;
+    int t53a = (in21 *  3564 + 2048) >> 12;
+    int t54a = (in27 *  3229 + 2048) >> 12;
+    int t55a = (in5  *  4065 + 2048) >> 12;
+    int t56a = (in7  *  4036 + 2048) >> 12;
+    int t57a = (in25 *  3349 + 2048) >> 12;
+    int t58a = (in23 *  3461 + 2048) >> 12;
+    int t59a = (in9  *  3996 + 2048) >> 12;
+    int t60a = (in15 *  3822 + 2048) >> 12;
+    int t61a = (in17 *  3745 + 2048) >> 12;
+    int t62a = (in31 *  2967 + 2048) >> 12;
+    int t63a = (in1  *  4095 + 2048) >> 12;
+
+    int t32 = CLIP(t32a + t33a);
+    int t33 = CLIP(t32a - t33a);
+    int t34 = CLIP(t35a - t34a);
+    int t35 = CLIP(t35a + t34a);
+    int t36 = CLIP(t36a + t37a);
+    int t37 = CLIP(t36a - t37a);
+    int t38 = CLIP(t39a - t38a);
+    int t39 = CLIP(t39a + t38a);
+    int t40 = CLIP(t40a + t41a);
+    int t41 = CLIP(t40a - t41a);
+    int t42 = CLIP(t43a - t42a);
+    int t43 = CLIP(t43a + t42a);
+    int t44 = CLIP(t44a + t45a);
+    int t45 = CLIP(t44a - t45a);
+    int t46 = CLIP(t47a - t46a);
+    int t47 = CLIP(t47a + t46a);
+    int t48 = CLIP(t48a + t49a);
+    int t49 = CLIP(t48a - t49a);
+    int t50 = CLIP(t51a - t50a);
+    int t51 = CLIP(t51a + t50a);
+    int t52 = CLIP(t52a + t53a);
+    int t53 = CLIP(t52a - t53a);
+    int t54 = CLIP(t55a - t54a);
+    int t55 = CLIP(t55a + t54a);
+    int t56 = CLIP(t56a + t57a);
+    int t57 = CLIP(t56a - t57a);
+    int t58 = CLIP(t59a - t58a);
+    int t59 = CLIP(t59a + t58a);
+    int t60 = CLIP(t60a + t61a);
+    int t61 = CLIP(t60a - t61a);
+    int t62 = CLIP(t63a - t62a);
+    int t63 = CLIP(t63a + t62a);
+
+    t33a = ((t33 * (4096 - 4076) + t62 *   401         + 2048) >> 12) - t33;
+    t34a = ((t34 *  -401         + t61 * (4096 - 4076) + 2048) >> 12) - t61;
+    t37a =  (t37 * -1299         + t58 *  1583         + 1024) >> 11;
+    t38a =  (t38 * -1583         + t57 * -1299         + 1024) >> 11;
+    t41a = ((t41 * (4096 - 3612) + t54 *  1931         + 2048) >> 12) - t41;
+    t42a = ((t42 * -1931         + t53 * (4096 - 3612) + 2048) >> 12) - t53;
+    t45a = ((t45 * -1189         + t50 * (3920 - 4096) + 2048) >> 12) + t50;
+    t46a = ((t46 * (4096 - 3920) + t49 * -1189         + 2048) >> 12) - t46;
+    t49a = ((t46 * -1189         + t49 * (3920 - 4096) + 2048) >> 12) + t49;
+    t50a = ((t45 * (3920 - 4096) + t50 *  1189         + 2048) >> 12) + t45;
+    t53a = ((t42 * (4096 - 3612) + t53 *  1931         + 2048) >> 12) - t42;
+    t54a = ((t41 *  1931         + t54 * (3612 - 4096) + 2048) >> 12) + t54;
+    t57a =  (t38 * -1299         + t57 *  1583         + 1024) >> 11;
+    t58a =  (t37 *  1583         + t58 *  1299         + 1024) >> 11;
+    t61a = ((t34 * (4096 - 4076) + t61 *   401         + 2048) >> 12) - t34;
+    t62a = ((t33 *   401         + t62 * (4076 - 4096) + 2048) >> 12) + t62;
+
+    t32a = CLIP(t32  + t35);
+    t33  = CLIP(t33a + t34a);
+    t34  = CLIP(t33a - t34a);
+    t35a = CLIP(t32  - t35);
+    t36a = CLIP(t39  - t36);
+    t37  = CLIP(t38a - t37a);
+    t38  = CLIP(t38a + t37a);
+    t39a = CLIP(t39  + t36);
+    t40a = CLIP(t40  + t43);
+    t41  = CLIP(t41a + t42a);
+    t42  = CLIP(t41a - t42a);
+    t43a = CLIP(t40  - t43);
+    t44a = CLIP(t47  - t44);
+    t45  = CLIP(t46a - t45a);
+    t46  = CLIP(t46a + t45a);
+    t47a = CLIP(t47  + t44);
+    t48a = CLIP(t48  + t51);
+    t49  = CLIP(t49a + t50a);
+    t50  = CLIP(t49a - t50a);
+    t51a = CLIP(t48  - t51);
+    t52a = CLIP(t55  - t52);
+    t53  = CLIP(t54a - t53a);
+    t54  = CLIP(t54a + t53a);
+    t55a = CLIP(t55  + t52);
+    t56a = CLIP(t56  + t59);
+    t57  = CLIP(t57a + t58a);
+    t58  = CLIP(t57a - t58a);
+    t59a = CLIP(t56  - t59);
+    t60a = CLIP(t63  - t60);
+    t61  = CLIP(t62a - t61a);
+    t62  = CLIP(t62a + t61a);
+    t63a = CLIP(t63  + t60);
+
+    t34a = ((t34  * (4096 - 4017) + t61  *   799         + 2048) >> 12) - t34;
+    t35  = ((t35a * (4096 - 4017) + t60a *   799         + 2048) >> 12) - t35a;
+    t36  = ((t36a *  -799         + t59a * (4096 - 4017) + 2048) >> 12) - t59a;
+    t37a = ((t37  *  -799         + t58  * (4096 - 4017) + 2048) >> 12) - t58;
+    t42a =  (t42  * -1138         + t53  *  1703         + 1024) >> 11;
+    t43  =  (t43a * -1138         + t52a *  1703         + 1024) >> 11;
+    t44  =  (t44a * -1703         + t51a * -1138         + 1024) >> 11;
+    t45a =  (t45  * -1703         + t50  * -1138         + 1024) >> 11;
+    t50a =  (t45  * -1138         + t50  *  1703         + 1024) >> 11;
+    t51  =  (t44a * -1138         + t51a *  1703         + 1024) >> 11;
+    t52  =  (t43a *  1703         + t52a *  1138         + 1024) >> 11;
+    t53a =  (t42  *  1703         + t53  *  1138         + 1024) >> 11;
+    t58a = ((t37  * (4096 - 4017) + t58  *   799         + 2048) >> 12) - t37;
+    t59  = ((t36a * (4096 - 4017) + t59a *   799         + 2048) >> 12) - t36a;
+    t60  = ((t35a *   799         + t60a * (4017 - 4096) + 2048) >> 12) + t60a;
+    t61a = ((t34  *   799         + t61  * (4017 - 4096) + 2048) >> 12) + t61;
+
+    t32  = CLIP(t32a + t39a);
+    t33a = CLIP(t33  + t38);
+    t34  = CLIP(t34a + t37a);
+    t35a = CLIP(t35  + t36);
+    t36a = CLIP(t35  - t36);
+    t37  = CLIP(t34a - t37a);
+    t38a = CLIP(t33  - t38);
+    t39  = CLIP(t32a - t39a);
+    t40  = CLIP(t47a - t40a);
+    t41a = CLIP(t46  - t41);
+    t42  = CLIP(t45a - t42a);
+    t43a = CLIP(t44  - t43);
+    t44a = CLIP(t44  + t43);
+    t45  = CLIP(t45a + t42a);
+    t46a = CLIP(t46  + t41);
+    t47  = CLIP(t47a + t40a);
+    t48  = CLIP(t48a + t55a);
+    t49a = CLIP(t49  + t54);
+    t50  = CLIP(t50a + t53a);
+    t51a = CLIP(t51  + t52);
+    t52a = CLIP(t51  - t52);
+    t53  = CLIP(t50a - t53a);
+    t54a = CLIP(t49  - t54);
+    t55  = CLIP(t48a - t55a);
+    t56  = CLIP(t63a - t56a);
+    t57a = CLIP(t62  - t57);
+    t58  = CLIP(t61a - t58a);
+    t59a = CLIP(t60  - t59);
+    t60a = CLIP(t60  + t59);
+    t61  = CLIP(t61a + t58a);
+    t62a = CLIP(t62  + t57);
+    t63  = CLIP(t63a + t56a);
+
+    t36  = ((t36a * (4096 - 3784) + t59a *  1567         + 2048) >> 12) - t36a;
+    t37a = ((t37  * (4096 - 3784) + t58  *  1567         + 2048) >> 12) - t37;
+    t38  = ((t38a * (4096 - 3784) + t57a *  1567         + 2048) >> 12) - t38a;
+    t39a = ((t39  * (4096 - 3784) + t56  *  1567         + 2048) >> 12) - t39;
+    t40a = ((t40  * -1567         + t55  * (4096 - 3784) + 2048) >> 12) - t55;
+    t41  = ((t41a * -1567         + t54a * (4096 - 3784) + 2048) >> 12) - t54a;
+    t42a = ((t42  * -1567         + t53  * (4096 - 3784) + 2048) >> 12) - t53;
+    t43  = ((t43a * -1567         + t52a * (4096 - 3784) + 2048) >> 12) - t52a;
+    t52  = ((t43a * (4096 - 3784) + t52a *  1567         + 2048) >> 12) - t43a;
+    t53a = ((t42  * (4096 - 3784) + t53  *  1567         + 2048) >> 12) - t42;
+    t54  = ((t41a * (4096 - 3784) + t54a *  1567         + 2048) >> 12) - t41a;
+    t55a = ((t40  * (4096 - 3784) + t55  *  1567         + 2048) >> 12) - t40;
+    t56a = ((t39  *  1567         + t56  * (3784 - 4096) + 2048) >> 12) + t56;
+    t57  = ((t38a *  1567         + t57a * (3784 - 4096) + 2048) >> 12) + t57a;
+    t58a = ((t37  *  1567         + t58  * (3784 - 4096) + 2048) >> 12) + t58;
+    t59  = ((t36a *  1567         + t59a * (3784 - 4096) + 2048) >> 12) + t59a;
+
+    t32a = CLIP(t32  + t47);
+    t33  = CLIP(t33a + t46a);
+    t34a = CLIP(t34  + t45);
+    t35  = CLIP(t35a + t44a);
+    t36a = CLIP(t36  + t43);
+    t37  = CLIP(t37a + t42a);
+    t38a = CLIP(t38  + t41);
+    t39  = CLIP(t39a + t40a);
+    t40  = CLIP(t39a - t40a);
+    t41a = CLIP(t38  - t41);
+    t42  = CLIP(t37a - t42a);
+    t43a = CLIP(t36  - t43);
+    t44  = CLIP(t35a - t44a);
+    t45a = CLIP(t34  - t45);
+    t46  = CLIP(t33a - t46a);
+    t47a = CLIP(t32  - t47);
+    t48a = CLIP(t63  - t48);
+    t49  = CLIP(t62a - t49a);
+    t50a = CLIP(t61  - t50);
+    t51  = CLIP(t60a - t51a);
+    t52a = CLIP(t59  - t52);
+    t53  = CLIP(t58a - t53a);
+    t54a = CLIP(t57  - t54);
+    t55  = CLIP(t56a - t55a);
+    t56  = CLIP(t56a + t55a);
+    t57a = CLIP(t57  + t54);
+    t58  = CLIP(t58a + t53a);
+    t59a = CLIP(t59  + t52);
+    t60  = CLIP(t60a + t51a);
+    t61a = CLIP(t61  + t50);
+    t62  = CLIP(t62a + t49a);
+    t63a = CLIP(t63  + t48);
+
+    t40a = ((t55  - t40 ) * 181 + 128) >> 8;
+    t41  = ((t54a - t41a) * 181 + 128) >> 8;
+    t42a = ((t53  - t42 ) * 181 + 128) >> 8;
+    t43  = ((t52a - t43a) * 181 + 128) >> 8;
+    t44a = ((t51  - t44 ) * 181 + 128) >> 8;
+    t45  = ((t50a - t45a) * 181 + 128) >> 8;
+    t46a = ((t49  - t46 ) * 181 + 128) >> 8;
+    t47  = ((t48a - t47a) * 181 + 128) >> 8;
+    t48  = ((t47a + t48a) * 181 + 128) >> 8;
+    t49a = ((t46  + t49 ) * 181 + 128) >> 8;
+    t50  = ((t45a + t50a) * 181 + 128) >> 8;
+    t51a = ((t44  + t51 ) * 181 + 128) >> 8;
+    t52  = ((t43a + t52a) * 181 + 128) >> 8;
+    t53a = ((t42  + t53 ) * 181 + 128) >> 8;
+    t54  = ((t41a + t54a) * 181 + 128) >> 8;
+    t55a = ((t40  + t55 ) * 181 + 128) >> 8;
+
+    const int t0  = c[ 0 * stride];
+    const int t1  = c[ 2 * stride];
+    const int t2  = c[ 4 * stride];
+    const int t3  = c[ 6 * stride];
+    const int t4  = c[ 8 * stride];
+    const int t5  = c[10 * stride];
+    const int t6  = c[12 * stride];
+    const int t7  = c[14 * stride];
+    const int t8  = c[16 * stride];
+    const int t9  = c[18 * stride];
+    const int t10 = c[20 * stride];
+    const int t11 = c[22 * stride];
+    const int t12 = c[24 * stride];
+    const int t13 = c[26 * stride];
+    const int t14 = c[28 * stride];
+    const int t15 = c[30 * stride];
+    const int t16 = c[32 * stride];
+    const int t17 = c[34 * stride];
+    const int t18 = c[36 * stride];
+    const int t19 = c[38 * stride];
+    const int t20 = c[40 * stride];
+    const int t21 = c[42 * stride];
+    const int t22 = c[44 * stride];
+    const int t23 = c[46 * stride];
+    const int t24 = c[48 * stride];
+    const int t25 = c[50 * stride];
+    const int t26 = c[52 * stride];
+    const int t27 = c[54 * stride];
+    const int t28 = c[56 * stride];
+    const int t29 = c[58 * stride];
+    const int t30 = c[60 * stride];
+    const int t31 = c[62 * stride];
+
+    c[ 0 * stride] = CLIP(t0  + t63a);
+    c[ 1 * stride] = CLIP(t1  + t62);
+    c[ 2 * stride] = CLIP(t2  + t61a);
+    c[ 3 * stride] = CLIP(t3  + t60);
+    c[ 4 * stride] = CLIP(t4  + t59a);
+    c[ 5 * stride] = CLIP(t5  + t58);
+    c[ 6 * stride] = CLIP(t6  + t57a);
+    c[ 7 * stride] = CLIP(t7  + t56);
+    c[ 8 * stride] = CLIP(t8  + t55a);
+    c[ 9 * stride] = CLIP(t9  + t54);
+    c[10 * stride] = CLIP(t10 + t53a);
+    c[11 * stride] = CLIP(t11 + t52);
+    c[12 * stride] = CLIP(t12 + t51a);
+    c[13 * stride] = CLIP(t13 + t50);
+    c[14 * stride] = CLIP(t14 + t49a);
+    c[15 * stride] = CLIP(t15 + t48);
+    c[16 * stride] = CLIP(t16 + t47);
+    c[17 * stride] = CLIP(t17 + t46a);
+    c[18 * stride] = CLIP(t18 + t45);
+    c[19 * stride] = CLIP(t19 + t44a);
+    c[20 * stride] = CLIP(t20 + t43);
+    c[21 * stride] = CLIP(t21 + t42a);
+    c[22 * stride] = CLIP(t22 + t41);
+    c[23 * stride] = CLIP(t23 + t40a);
+    c[24 * stride] = CLIP(t24 + t39);
+    c[25 * stride] = CLIP(t25 + t38a);
+    c[26 * stride] = CLIP(t26 + t37);
+    c[27 * stride] = CLIP(t27 + t36a);
+    c[28 * stride] = CLIP(t28 + t35);
+    c[29 * stride] = CLIP(t29 + t34a);
+    c[30 * stride] = CLIP(t30 + t33);
+    c[31 * stride] = CLIP(t31 + t32a);
+    c[32 * stride] = CLIP(t31 - t32a);
+    c[33 * stride] = CLIP(t30 - t33);
+    c[34 * stride] = CLIP(t29 - t34a);
+    c[35 * stride] = CLIP(t28 - t35);
+    c[36 * stride] = CLIP(t27 - t36a);
+    c[37 * stride] = CLIP(t26 - t37);
+    c[38 * stride] = CLIP(t25 - t38a);
+    c[39 * stride] = CLIP(t24 - t39);
+    c[40 * stride] = CLIP(t23 - t40a);
+    c[41 * stride] = CLIP(t22 - t41);
+    c[42 * stride] = CLIP(t21 - t42a);
+    c[43 * stride] = CLIP(t20 - t43);
+    c[44 * stride] = CLIP(t19 - t44a);
+    c[45 * stride] = CLIP(t18 - t45);
+    c[46 * stride] = CLIP(t17 - t46a);
+    c[47 * stride] = CLIP(t16 - t47);
+    c[48 * stride] = CLIP(t15 - t48);
+    c[49 * stride] = CLIP(t14 - t49a);
+    c[50 * stride] = CLIP(t13 - t50);
+    c[51 * stride] = CLIP(t12 - t51a);
+    c[52 * stride] = CLIP(t11 - t52);
+    c[53 * stride] = CLIP(t10 - t53a);
+    c[54 * stride] = CLIP(t9  - t54);
+    c[55 * stride] = CLIP(t8  - t55a);
+    c[56 * stride] = CLIP(t7  - t56);
+    c[57 * stride] = CLIP(t6  - t57a);
+    c[58 * stride] = CLIP(t5  - t58);
+    c[59 * stride] = CLIP(t4  - t59a);
+    c[60 * stride] = CLIP(t3  - t60);
+    c[61 * stride] = CLIP(t2  - t61a);
+    c[62 * stride] = CLIP(t1  - t62);
+    c[63 * stride] = CLIP(t0  - t63a);
+}
+
+static NOINLINE void
+inv_adst4_1d_internal_c(const int32_t *const in, const ptrdiff_t in_s,
+                        const int min, const int max,
+                        int32_t *const out, const ptrdiff_t out_s)
+{
+    assert(in_s > 0 && out_s != 0);
+    const int in0 = in[0 * in_s], in1 = in[1 * in_s];
+    const int in2 = in[2 * in_s], in3 = in[3 * in_s];
+
+    out[0 * out_s] = (( 1321         * in0 + (3803 - 4096) * in2 +
+                       (2482 - 4096) * in3 + (3344 - 4096) * in1 + 2048) >> 12) +
+                     in2 + in3 + in1;
+    out[1 * out_s] = (((2482 - 4096) * in0 -  1321         * in2 -
+                       (3803 - 4096) * in3 + (3344 - 4096) * in1 + 2048) >> 12) +
+                     in0 - in3 + in1;
+    out[2 * out_s] = (209 * (in0 - in2 + in3) + 128) >> 8;
+    out[3 * out_s] = (((3803 - 4096) * in0 + (2482 - 4096) * in2 -
+                        1321         * in3 - (3344 - 4096) * in1 + 2048) >> 12) +
+                     in0 + in2 - in1;
+}
+
+static NOINLINE void
+inv_adst8_1d_internal_c(const int32_t *const in, const ptrdiff_t in_s,
+                        const int min, const int max,
+                        int32_t *const out, const ptrdiff_t out_s)
+{
+    assert(in_s > 0 && out_s != 0);
+    const int in0 = in[0 * in_s], in1 = in[1 * in_s];
+    const int in2 = in[2 * in_s], in3 = in[3 * in_s];
+    const int in4 = in[4 * in_s], in5 = in[5 * in_s];
+    const int in6 = in[6 * in_s], in7 = in[7 * in_s];
+
+    const int t0a = (((4076 - 4096) * in7 +   401         * in0 + 2048) >> 12) + in7;
+    const int t1a = ((  401         * in7 - (4076 - 4096) * in0 + 2048) >> 12) - in0;
+    const int t2a = (((3612 - 4096) * in5 +  1931         * in2 + 2048) >> 12) + in5;
+    const int t3a = (( 1931         * in5 - (3612 - 4096) * in2 + 2048) >> 12) - in2;
+          int t4a =  ( 1299         * in3 +  1583         * in4 + 1024) >> 11;
+          int t5a =  ( 1583         * in3 -  1299         * in4 + 1024) >> 11;
+          int t6a = (( 1189         * in1 + (3920 - 4096) * in6 + 2048) >> 12) + in6;
+          int t7a = (((3920 - 4096) * in1 -  1189         * in6 + 2048) >> 12) + in1;
+
+    const int t0 = CLIP(t0a + t4a);
+    const int t1 = CLIP(t1a + t5a);
+          int t2 = CLIP(t2a + t6a);
+          int t3 = CLIP(t3a + t7a);
+    const int t4 = CLIP(t0a - t4a);
+    const int t5 = CLIP(t1a - t5a);
+          int t6 = CLIP(t2a - t6a);
+          int t7 = CLIP(t3a - t7a);
+
+    t4a = (((3784 - 4096) * t4 +  1567         * t5 + 2048) >> 12) + t4;
+    t5a = (( 1567         * t4 - (3784 - 4096) * t5 + 2048) >> 12) - t5;
+    t6a = (((3784 - 4096) * t7 -  1567         * t6 + 2048) >> 12) + t7;
+    t7a = (( 1567         * t7 + (3784 - 4096) * t6 + 2048) >> 12) + t6;
+
+    out[0 * out_s] =  CLIP(t0  + t2 );
+    out[7 * out_s] = -CLIP(t1  + t3 );
+    t2             =  CLIP(t0  - t2 );
+    t3             =  CLIP(t1  - t3 );
+    out[1 * out_s] = -CLIP(t4a + t6a);
+    out[6 * out_s] =  CLIP(t5a + t7a);
+    t6             =  CLIP(t4a - t6a);
+    t7             =  CLIP(t5a - t7a);
+
+    out[3 * out_s] = -(((t2 + t3) * 181 + 128) >> 8);
+    out[4 * out_s] =   ((t2 - t3) * 181 + 128) >> 8;
+    out[2 * out_s] =   ((t6 + t7) * 181 + 128) >> 8;
+    out[5 * out_s] = -(((t6 - t7) * 181 + 128) >> 8);
+}
+
+static NOINLINE void
+inv_adst16_1d_internal_c(const int32_t *const in, const ptrdiff_t in_s,
+                         const int min, const int max,
+                         int32_t *const out, const ptrdiff_t out_s)
+{
+    assert(in_s > 0 && out_s != 0);
+    const int in0  = in[ 0 * in_s], in1  = in[ 1 * in_s];
+    const int in2  = in[ 2 * in_s], in3  = in[ 3 * in_s];
+    const int in4  = in[ 4 * in_s], in5  = in[ 5 * in_s];
+    const int in6  = in[ 6 * in_s], in7  = in[ 7 * in_s];
+    const int in8  = in[ 8 * in_s], in9  = in[ 9 * in_s];
+    const int in10 = in[10 * in_s], in11 = in[11 * in_s];
+    const int in12 = in[12 * in_s], in13 = in[13 * in_s];
+    const int in14 = in[14 * in_s], in15 = in[15 * in_s];
+
+    int t0  = ((in15 * (4091 - 4096) + in0  *   201         + 2048) >> 12) + in15;
+    int t1  = ((in15 *   201         - in0  * (4091 - 4096) + 2048) >> 12) - in0;
+    int t2  = ((in13 * (3973 - 4096) + in2  *   995         + 2048) >> 12) + in13;
+    int t3  = ((in13 *   995         - in2  * (3973 - 4096) + 2048) >> 12) - in2;
+    int t4  = ((in11 * (3703 - 4096) + in4  *  1751         + 2048) >> 12) + in11;
+    int t5  = ((in11 *  1751         - in4  * (3703 - 4096) + 2048) >> 12) - in4;
+    int t6  =  (in9  *  1645         + in6  *  1220         + 1024) >> 11;
+    int t7  =  (in9  *  1220         - in6  *  1645         + 1024) >> 11;
+    int t8  = ((in7  *  2751         + in8  * (3035 - 4096) + 2048) >> 12) + in8;
+    int t9  = ((in7  * (3035 - 4096) - in8  *  2751         + 2048) >> 12) + in7;
+    int t10 = ((in5  *  2106         + in10 * (3513 - 4096) + 2048) >> 12) + in10;
+    int t11 = ((in5  * (3513 - 4096) - in10 *  2106         + 2048) >> 12) + in5;
+    int t12 = ((in3  *  1380         + in12 * (3857 - 4096) + 2048) >> 12) + in12;
+    int t13 = ((in3  * (3857 - 4096) - in12 *  1380         + 2048) >> 12) + in3;
+    int t14 = ((in1  *   601         + in14 * (4052 - 4096) + 2048) >> 12) + in14;
+    int t15 = ((in1  * (4052 - 4096) - in14 *   601         + 2048) >> 12) + in1;
+
+    int t0a  = CLIP(t0 + t8 );
+    int t1a  = CLIP(t1 + t9 );
+    int t2a  = CLIP(t2 + t10);
+    int t3a  = CLIP(t3 + t11);
+    int t4a  = CLIP(t4 + t12);
+    int t5a  = CLIP(t5 + t13);
+    int t6a  = CLIP(t6 + t14);
+    int t7a  = CLIP(t7 + t15);
+    int t8a  = CLIP(t0 - t8 );
+    int t9a  = CLIP(t1 - t9 );
+    int t10a = CLIP(t2 - t10);
+    int t11a = CLIP(t3 - t11);
+    int t12a = CLIP(t4 - t12);
+    int t13a = CLIP(t5 - t13);
+    int t14a = CLIP(t6 - t14);
+    int t15a = CLIP(t7 - t15);
+
+    t8   = ((t8a  * (4017 - 4096) + t9a  *   799         + 2048) >> 12) + t8a;
+    t9   = ((t8a  *   799         - t9a  * (4017 - 4096) + 2048) >> 12) - t9a;
+    t10  = ((t10a *  2276         + t11a * (3406 - 4096) + 2048) >> 12) + t11a;
+    t11  = ((t10a * (3406 - 4096) - t11a *  2276         + 2048) >> 12) + t10a;
+    t12  = ((t13a * (4017 - 4096) - t12a *   799         + 2048) >> 12) + t13a;
+    t13  = ((t13a *   799         + t12a * (4017 - 4096) + 2048) >> 12) + t12a;
+    t14  = ((t15a *  2276         - t14a * (3406 - 4096) + 2048) >> 12) - t14a;
+    t15  = ((t15a * (3406 - 4096) + t14a *  2276         + 2048) >> 12) + t15a;
+
+    t0   = CLIP(t0a + t4a);
+    t1   = CLIP(t1a + t5a);
+    t2   = CLIP(t2a + t6a);
+    t3   = CLIP(t3a + t7a);
+    t4   = CLIP(t0a - t4a);
+    t5   = CLIP(t1a - t5a);
+    t6   = CLIP(t2a - t6a);
+    t7   = CLIP(t3a - t7a);
+    t8a  = CLIP(t8  + t12);
+    t9a  = CLIP(t9  + t13);
+    t10a = CLIP(t10 + t14);
+    t11a = CLIP(t11 + t15);
+    t12a = CLIP(t8  - t12);
+    t13a = CLIP(t9  - t13);
+    t14a = CLIP(t10 - t14);
+    t15a = CLIP(t11 - t15);
+
+    t4a  = ((t4   * (3784 - 4096) + t5   *  1567         + 2048) >> 12) + t4;
+    t5a  = ((t4   *  1567         - t5   * (3784 - 4096) + 2048) >> 12) - t5;
+    t6a  = ((t7   * (3784 - 4096) - t6   *  1567         + 2048) >> 12) + t7;
+    t7a  = ((t7   *  1567         + t6   * (3784 - 4096) + 2048) >> 12) + t6;
+    t12  = ((t12a * (3784 - 4096) + t13a *  1567         + 2048) >> 12) + t12a;
+    t13  = ((t12a *  1567         - t13a * (3784 - 4096) + 2048) >> 12) - t13a;
+    t14  = ((t15a * (3784 - 4096) - t14a *  1567         + 2048) >> 12) + t15a;
+    t15  = ((t15a *  1567         + t14a * (3784 - 4096) + 2048) >> 12) + t14a;
+
+    out[ 0 * out_s] =  CLIP(t0  + t2  );
+    out[15 * out_s] = -CLIP(t1  + t3  );
+    t2a             =  CLIP(t0  - t2  );
+    t3a             =  CLIP(t1  - t3  );
+    out[ 3 * out_s] = -CLIP(t4a + t6a );
+    out[12 * out_s] =  CLIP(t5a + t7a );
+    t6              =  CLIP(t4a - t6a );
+    t7              =  CLIP(t5a - t7a );
+    out[ 1 * out_s] = -CLIP(t8a + t10a);
+    out[14 * out_s] =  CLIP(t9a + t11a);
+    t10             =  CLIP(t8a - t10a);
+    t11             =  CLIP(t9a - t11a);
+    out[ 2 * out_s] =  CLIP(t12 + t14 );
+    out[13 * out_s] = -CLIP(t13 + t15 );
+    t14a            =  CLIP(t12 - t14 );
+    t15a            =  CLIP(t13 - t15 );
+
+    out[ 7 * out_s] = -(((t2a  + t3a)  * 181 + 128) >> 8);
+    out[ 8 * out_s] =   ((t2a  - t3a)  * 181 + 128) >> 8;
+    out[ 4 * out_s] =   ((t6   + t7)   * 181 + 128) >> 8;
+    out[11 * out_s] = -(((t6   - t7)   * 181 + 128) >> 8);
+    out[ 6 * out_s] =   ((t10  + t11)  * 181 + 128) >> 8;
+    out[ 9 * out_s] = -(((t10  - t11)  * 181 + 128) >> 8);
+    out[ 5 * out_s] = -(((t14a + t15a) * 181 + 128) >> 8);
+    out[10 * out_s] =   ((t14a - t15a) * 181 + 128) >> 8;
+}
+
+#define inv_adst_1d(sz) \
+static void inv_adst##sz##_1d_c(int32_t *const c, const ptrdiff_t stride, \
+                                const int min, const int max) \
+{ \
+    inv_adst##sz##_1d_internal_c(c, stride, min, max, c, stride); \
+} \
+static void inv_flipadst##sz##_1d_c(int32_t *const c, const ptrdiff_t stride, \
+                                          const int min, const int max) \
+{ \
+    inv_adst##sz##_1d_internal_c(c, stride, min, max, \
+                                 &c[(sz - 1) * stride], -stride); \
+}
+
+inv_adst_1d( 4)
+inv_adst_1d( 8)
+inv_adst_1d(16)
+
+#undef inv_adst_1d
+
+static void inv_identity4_1d_c(int32_t *const c, const ptrdiff_t stride,
+                               const int min, const int max)
+{
+    assert(stride > 0);
+    for (int i = 0; i < 4; i++) {
+        const int in = c[stride * i];
+        c[stride * i] = in + ((in * 1697 + 2048) >> 12);
+    }
+}
+
+static void inv_identity8_1d_c(int32_t *const c, const ptrdiff_t stride,
+                               const int min, const int max)
+{
+    assert(stride > 0);
+    for (int i = 0; i < 8; i++)
+        c[stride * i] *= 2;
+}
+
+static void inv_identity16_1d_c(int32_t *const c, const ptrdiff_t stride,
+                                const int min, const int max)
+{
+    assert(stride > 0);
+    for (int i = 0; i < 16; i++) {
+        const int in = c[stride * i];
+        c[stride * i] = 2 * in + ((in * 1697 + 1024) >> 11);
+    }
+}
+
+static void inv_identity32_1d_c(int32_t *const c, const ptrdiff_t stride,
+                                const int min, const int max)
+{
+    assert(stride > 0);
+    for (int i = 0; i < 32; i++)
+        c[stride * i] *= 4;
+}
+
+const itx_1d_fn dav1d_tx1d_fns[N_TX_SIZES][N_TX_1D_TYPES] = {
+    [TX_4X4] = {
+        [DCT] = inv_dct4_1d_c,
+        [ADST] = inv_adst4_1d_c,
+        [FLIPADST] = inv_flipadst4_1d_c,
+        [IDENTITY] = inv_identity4_1d_c,
+    }, [TX_8X8] = {
+        [DCT] = inv_dct8_1d_c,
+        [ADST] = inv_adst8_1d_c,
+        [FLIPADST] = inv_flipadst8_1d_c,
+        [IDENTITY] = inv_identity8_1d_c,
+    }, [TX_16X16] = {
+        [DCT] = inv_dct16_1d_c,
+        [ADST] = inv_adst16_1d_c,
+        [FLIPADST] = inv_flipadst16_1d_c,
+        [IDENTITY] = inv_identity16_1d_c,
+    }, [TX_32X32] = {
+        [DCT] = inv_dct32_1d_c,
+        [IDENTITY] = inv_identity32_1d_c,
+    }, [TX_64X64] = {
+        [DCT] = inv_dct64_1d_c,
+    },
+};
+
+const uint8_t /* enum Tx1dType */ dav1d_tx1d_types[N_TX_TYPES][2] = {
+    [DCT_DCT]           = { DCT, DCT },
+    [ADST_DCT]          = { ADST, DCT },
+    [DCT_ADST]          = { DCT, ADST },
+    [ADST_ADST]         = { ADST, ADST },
+    [FLIPADST_DCT]      = { FLIPADST, DCT },
+    [DCT_FLIPADST]      = { DCT, FLIPADST },
+    [FLIPADST_FLIPADST] = { FLIPADST, FLIPADST },
+    [ADST_FLIPADST]     = { ADST, FLIPADST },
+    [FLIPADST_ADST]     = { FLIPADST, ADST },
+    [IDTX]              = { IDENTITY, IDENTITY },
+    [V_DCT]             = { DCT, IDENTITY },
+    [H_DCT]             = { IDENTITY, DCT },
+    [V_ADST]            = { ADST, IDENTITY },
+    [H_ADST]            = { IDENTITY, ADST },
+    [V_FLIPADST]        = { FLIPADST, IDENTITY },
+    [H_FLIPADST]        = { IDENTITY, FLIPADST },
+};
+
+#if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \
+  ARCH_AARCH64 || \
+  (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \
+))
+void dav1d_inv_wht4_1d_c(int32_t *const c, const ptrdiff_t stride) {
+    assert(stride > 0);
+    const int in0 = c[0 * stride], in1 = c[1 * stride];
+    const int in2 = c[2 * stride], in3 = c[3 * stride];
+
+    const int t0 = in0 + in1;
+    const int t2 = in2 - in3;
+    const int t4 = (t0 - t2) >> 1;
+    const int t3 = t4 - in3;
+    const int t1 = t4 - in1;
+
+    c[0 * stride] = t0 - t3;
+    c[1 * stride] = t3;
+    c[2 * stride] = t1;
+    c[3 * stride] = t2 + t1;
+}
+#endif
diff --git a/media/libdav1d/src/src/itx_1d.h b/media/libdav1d/src/src/itx_1d.h
new file mode 100644
index 0000000000..880ac99a35
--- /dev/null
+++ b/media/libdav1d/src/src/itx_1d.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2018-2019, VideoLAN and dav1d authors
+ * Copyright © 2018-2019, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include 
+#include 
+
+#include "src/levels.h"
+
+#ifndef DAV1D_SRC_ITX_1D_H
+#define DAV1D_SRC_ITX_1D_H
+
+enum Tx1dType {
+    DCT,
+    ADST,
+    IDENTITY,
+    FLIPADST,
+    N_TX_1D_TYPES,
+};
+
+#define decl_itx_1d_fn(name) \
+void (name)(int32_t *c, ptrdiff_t stride, int min, int max)
+typedef decl_itx_1d_fn(*itx_1d_fn);
+
+EXTERN const itx_1d_fn dav1d_tx1d_fns[N_TX_SIZES][N_TX_1D_TYPES];
+EXTERN const uint8_t /* enum Tx1dType */ dav1d_tx1d_types[N_TX_TYPES][2];
+
+void dav1d_inv_wht4_1d_c(int32_t *c, ptrdiff_t stride);
+
+#endif /* DAV1D_SRC_ITX_1D_H */
diff --git a/media/libdav1d/src/src/itx_tmpl.c b/media/libdav1d/src/src/itx_tmpl.c
new file mode 100644
index 0000000000..bafe0a86a6
--- /dev/null
+++ b/media/libdav1d/src/src/itx_tmpl.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright © 2018-2019, VideoLAN and dav1d authors
+ * Copyright © 2018-2019, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "src/itx.h"
+#include "src/itx_1d.h"
+#include "src/scan.h"
+#include "src/tables.h"
+
+static NOINLINE void
+inv_txfm_add_c(pixel *dst, const ptrdiff_t stride, coef *const coeff,
+               const int eob, const /*enum RectTxfmSize*/ int tx, const int shift,
+               const enum TxfmType txtp HIGHBD_DECL_SUFFIX)
+{
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx];
+    const int w = 4 * t_dim->w, h = 4 * t_dim->h;
+    const int has_dconly = txtp == DCT_DCT;
+    assert(w >= 4 && w <= 64);
+    assert(h >= 4 && h <= 64);
+    assert(eob >= 0);
+
+    const int is_rect2 = w * 2 == h || h * 2 == w;
+    const int rnd = (1 << shift) >> 1;
+
+    if (eob < has_dconly) {
+        int dc = coeff[0];
+        coeff[0] = 0;
+        if (is_rect2)
+            dc = (dc * 181 + 128) >> 8;
+        dc = (dc * 181 + 128) >> 8;
+        dc = (dc + rnd) >> shift;
+        dc = (dc * 181 + 128 + 2048) >> 12;
+        for (int y = 0; y < h; y++, dst += PXSTRIDE(stride))
+            for (int x = 0; x < w; x++)
+                dst[x] = iclip_pixel(dst[x] + dc);
+        return;
+    }
+
+    const uint8_t *const txtps = dav1d_tx1d_types[txtp];
+    const itx_1d_fn first_1d_fn = dav1d_tx1d_fns[t_dim->lw][txtps[0]];
+    const itx_1d_fn second_1d_fn = dav1d_tx1d_fns[t_dim->lh][txtps[1]];
+    const int sh = imin(h, 32), sw = imin(w, 32);
+#if BITDEPTH == 8
+    const int row_clip_min = INT16_MIN;
+    const int col_clip_min = INT16_MIN;
+#else
+    const int row_clip_min = (int) ((unsigned) ~bitdepth_max << 7);
+    const int col_clip_min = (int) ((unsigned) ~bitdepth_max << 5);
+#endif
+    const int row_clip_max = ~row_clip_min;
+    const int col_clip_max = ~col_clip_min;
+
+    int32_t tmp[64 * 64], *c = tmp;
+    int last_nonzero_col; // in first 1d itx
+    if (txtps[1] == IDENTITY && txtps[0] != IDENTITY) {
+        last_nonzero_col = imin(sh - 1, eob);
+    } else if (txtps[0] == IDENTITY && txtps[1] != IDENTITY) {
+        last_nonzero_col = eob >> (t_dim->lw + 2);
+    } else {
+        last_nonzero_col = dav1d_last_nonzero_col_from_eob[tx][eob];
+    }
+    assert(last_nonzero_col < sh);
+    for (int y = 0; y <= last_nonzero_col; y++, c += w) {
+        if (is_rect2)
+            for (int x = 0; x < sw; x++)
+                c[x] = (coeff[y + x * sh] * 181 + 128) >> 8;
+        else
+            for (int x = 0; x < sw; x++)
+                c[x] = coeff[y + x * sh];
+        first_1d_fn(c, 1, row_clip_min, row_clip_max);
+    }
+    if (last_nonzero_col + 1 < sh)
+        memset(c, 0, sizeof(*c) * (sh - last_nonzero_col - 1) * w);
+
+    memset(coeff, 0, sizeof(*coeff) * sw * sh);
+    for (int i = 0; i < w * sh; i++)
+        tmp[i] = iclip((tmp[i] + rnd) >> shift, col_clip_min, col_clip_max);
+
+    for (int x = 0; x < w; x++)
+        second_1d_fn(&tmp[x], w, col_clip_min, col_clip_max);
+
+    c = tmp;
+    for (int y = 0; y < h; y++, dst += PXSTRIDE(stride))
+        for (int x = 0; x < w; x++)
+            dst[x] = iclip_pixel(dst[x] + ((*c++ + 8) >> 4));
+}
+
+#define inv_txfm_fn(type1, type2, type, pfx, w, h, shift) \
+static void \
+inv_txfm_add_##type1##_##type2##_##w##x##h##_c(pixel *dst, \
+                                               const ptrdiff_t stride, \
+                                               coef *const coeff, \
+                                               const int eob \
+                                               HIGHBD_DECL_SUFFIX) \
+{ \
+    inv_txfm_add_c(dst, stride, coeff, eob, pfx##TX_##w##X##h, shift, type \
+                   HIGHBD_TAIL_SUFFIX); \
+}
+
+#define inv_txfm_fn64(pfx, w, h, shift) \
+inv_txfm_fn(dct, dct, DCT_DCT, pfx, w, h, shift)
+
+#define inv_txfm_fn32(pfx, w, h, shift) \
+inv_txfm_fn64(pfx, w, h, shift) \
+inv_txfm_fn(identity, identity, IDTX, pfx, w, h, shift)
+
+#define inv_txfm_fn16(pfx, w, h, shift) \
+inv_txfm_fn32(pfx, w, h, shift) \
+inv_txfm_fn(adst,     dct,      ADST_DCT,          pfx,  w, h, shift) \
+inv_txfm_fn(dct,      adst,     DCT_ADST,          pfx, w, h, shift) \
+inv_txfm_fn(adst,     adst,     ADST_ADST,         pfx, w, h, shift) \
+inv_txfm_fn(dct,      flipadst, DCT_FLIPADST,      pfx, w, h, shift) \
+inv_txfm_fn(flipadst, dct,      FLIPADST_DCT,      pfx, w, h, shift) \
+inv_txfm_fn(adst,     flipadst, ADST_FLIPADST,     pfx, w, h, shift) \
+inv_txfm_fn(flipadst, adst,     FLIPADST_ADST,     pfx, w, h, shift) \
+inv_txfm_fn(flipadst, flipadst, FLIPADST_FLIPADST, pfx, w, h, shift) \
+inv_txfm_fn(identity, dct,      H_DCT,             pfx, w, h, shift) \
+inv_txfm_fn(dct,      identity, V_DCT,             pfx, w, h, shift) \
+
+#define inv_txfm_fn84(pfx, w, h, shift) \
+inv_txfm_fn16(pfx, w, h, shift) \
+inv_txfm_fn(identity, flipadst, H_FLIPADST, pfx, w, h, shift) \
+inv_txfm_fn(flipadst, identity, V_FLIPADST, pfx, w, h, shift) \
+inv_txfm_fn(identity, adst,     H_ADST,     pfx, w, h, shift) \
+inv_txfm_fn(adst,     identity, V_ADST,     pfx, w, h, shift) \
+
+inv_txfm_fn84( ,  4,  4, 0)
+inv_txfm_fn84(R,  4,  8, 0)
+inv_txfm_fn84(R,  4, 16, 1)
+inv_txfm_fn84(R,  8,  4, 0)
+inv_txfm_fn84( ,  8,  8, 1)
+inv_txfm_fn84(R,  8, 16, 1)
+inv_txfm_fn32(R,  8, 32, 2)
+inv_txfm_fn84(R, 16,  4, 1)
+inv_txfm_fn84(R, 16,  8, 1)
+inv_txfm_fn16( , 16, 16, 2)
+inv_txfm_fn32(R, 16, 32, 1)
+inv_txfm_fn64(R, 16, 64, 2)
+inv_txfm_fn32(R, 32,  8, 2)
+inv_txfm_fn32(R, 32, 16, 1)
+inv_txfm_fn32( , 32, 32, 2)
+inv_txfm_fn64(R, 32, 64, 1)
+inv_txfm_fn64(R, 64, 16, 2)
+inv_txfm_fn64(R, 64, 32, 1)
+inv_txfm_fn64( , 64, 64, 2)
+
+#if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \
+  ARCH_AARCH64 || \
+  (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \
+))
+static void inv_txfm_add_wht_wht_4x4_c(pixel *dst, const ptrdiff_t stride,
+                                       coef *const coeff, const int eob
+                                       HIGHBD_DECL_SUFFIX)
+{
+    int32_t tmp[4 * 4], *c = tmp;
+    for (int y = 0; y < 4; y++, c += 4) {
+        for (int x = 0; x < 4; x++)
+            c[x] = coeff[y + x * 4] >> 2;
+        dav1d_inv_wht4_1d_c(c, 1);
+    }
+    memset(coeff, 0, sizeof(*coeff) * 4 * 4);
+
+    for (int x = 0; x < 4; x++)
+        dav1d_inv_wht4_1d_c(&tmp[x], 4);
+
+    c = tmp;
+    for (int y = 0; y < 4; y++, dst += PXSTRIDE(stride))
+        for (int x = 0; x < 4; x++)
+            dst[x] = iclip_pixel(dst[x] + *c++);
+}
+#endif
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/itx.h"
+#elif ARCH_LOONGARCH64
+#include "src/loongarch/itx.h"
+#elif ARCH_PPC64LE
+#include "src/ppc/itx.h"
+#elif ARCH_RISCV
+#include "src/riscv/itx.h"
+#elif ARCH_X86
+#include "src/x86/itx.h"
+#endif
+#endif
+
+COLD void bitfn(dav1d_itx_dsp_init)(Dav1dInvTxfmDSPContext *const c, int bpc) {
+#define assign_itx_all_fn64(w, h, pfx) \
+    c->itxfm_add[pfx##TX_##w##X##h][DCT_DCT  ] = \
+        inv_txfm_add_dct_dct_##w##x##h##_c
+
+#define assign_itx_all_fn32(w, h, pfx) \
+    assign_itx_all_fn64(w, h, pfx); \
+    c->itxfm_add[pfx##TX_##w##X##h][IDTX] = \
+        inv_txfm_add_identity_identity_##w##x##h##_c
+
+#define assign_itx_all_fn16(w, h, pfx) \
+    assign_itx_all_fn32(w, h, pfx); \
+    c->itxfm_add[pfx##TX_##w##X##h][DCT_ADST ] = \
+        inv_txfm_add_adst_dct_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][ADST_DCT ] = \
+        inv_txfm_add_dct_adst_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][ADST_ADST] = \
+        inv_txfm_add_adst_adst_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][ADST_FLIPADST] = \
+        inv_txfm_add_flipadst_adst_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][FLIPADST_ADST] = \
+        inv_txfm_add_adst_flipadst_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][DCT_FLIPADST] = \
+        inv_txfm_add_flipadst_dct_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][FLIPADST_DCT] = \
+        inv_txfm_add_dct_flipadst_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][FLIPADST_FLIPADST] = \
+        inv_txfm_add_flipadst_flipadst_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][H_DCT] = \
+        inv_txfm_add_dct_identity_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][V_DCT] = \
+        inv_txfm_add_identity_dct_##w##x##h##_c
+
+#define assign_itx_all_fn84(w, h, pfx) \
+    assign_itx_all_fn16(w, h, pfx); \
+    c->itxfm_add[pfx##TX_##w##X##h][H_FLIPADST] = \
+        inv_txfm_add_flipadst_identity_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][V_FLIPADST] = \
+        inv_txfm_add_identity_flipadst_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][H_ADST] = \
+        inv_txfm_add_adst_identity_##w##x##h##_c; \
+    c->itxfm_add[pfx##TX_##w##X##h][V_ADST] = \
+        inv_txfm_add_identity_adst_##w##x##h##_c; \
+
+#if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \
+  ARCH_AARCH64 || \
+  (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \
+))
+    c->itxfm_add[TX_4X4][WHT_WHT] = inv_txfm_add_wht_wht_4x4_c;
+#endif
+    assign_itx_all_fn84( 4,  4, );
+    assign_itx_all_fn84( 4,  8, R);
+    assign_itx_all_fn84( 4, 16, R);
+    assign_itx_all_fn84( 8,  4, R);
+    assign_itx_all_fn84( 8,  8, );
+    assign_itx_all_fn84( 8, 16, R);
+    assign_itx_all_fn32( 8, 32, R);
+    assign_itx_all_fn84(16,  4, R);
+    assign_itx_all_fn84(16,  8, R);
+    assign_itx_all_fn16(16, 16, );
+    assign_itx_all_fn32(16, 32, R);
+    assign_itx_all_fn64(16, 64, R);
+    assign_itx_all_fn32(32,  8, R);
+    assign_itx_all_fn32(32, 16, R);
+    assign_itx_all_fn32(32, 32, );
+    assign_itx_all_fn64(32, 64, R);
+    assign_itx_all_fn64(64, 16, R);
+    assign_itx_all_fn64(64, 32, R);
+    assign_itx_all_fn64(64, 64, );
+
+    int all_simd = 0;
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+    itx_dsp_init_arm(c, bpc, &all_simd);
+#endif
+#if ARCH_LOONGARCH64
+    itx_dsp_init_loongarch(c, bpc);
+#endif
+#if ARCH_PPC64LE
+    itx_dsp_init_ppc(c, bpc);
+#endif
+#if ARCH_RISCV
+    itx_dsp_init_riscv(c, bpc);
+#endif
+#if ARCH_X86
+    itx_dsp_init_x86(c, bpc, &all_simd);
+#endif
+#endif
+
+    if (!all_simd)
+        dav1d_init_last_nonzero_col_from_eob_tables();
+}
diff --git a/media/libdav1d/src/src/levels.h b/media/libdav1d/src/src/levels.h
new file mode 100644
index 0000000000..0f510e9f30
--- /dev/null
+++ b/media/libdav1d/src/src/levels.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LEVELS_H
+#define DAV1D_SRC_LEVELS_H
+
+#include 
+
+#include "dav1d/headers.h"
+#include "common/attributes.h"
+
+enum ObuMetaType {
+    OBU_META_HDR_CLL     = 1,
+    OBU_META_HDR_MDCV    = 2,
+    OBU_META_SCALABILITY = 3,
+    OBU_META_ITUT_T35    = 4,
+    OBU_META_TIMECODE    = 5,
+};
+
+enum TxfmSize {
+    TX_4X4,
+    TX_8X8,
+    TX_16X16,
+    TX_32X32,
+    TX_64X64,
+    N_TX_SIZES,
+};
+
+enum BlockLevel {
+    BL_128X128,
+    BL_64X64,
+    BL_32X32,
+    BL_16X16,
+    BL_8X8,
+    N_BL_LEVELS,
+};
+
+enum RectTxfmSize {
+    RTX_4X8 = N_TX_SIZES,
+    RTX_8X4,
+    RTX_8X16,
+    RTX_16X8,
+    RTX_16X32,
+    RTX_32X16,
+    RTX_32X64,
+    RTX_64X32,
+    RTX_4X16,
+    RTX_16X4,
+    RTX_8X32,
+    RTX_32X8,
+    RTX_16X64,
+    RTX_64X16,
+    N_RECT_TX_SIZES
+};
+
+enum TxfmType {
+    DCT_DCT,    // DCT  in both horizontal and vertical
+    ADST_DCT,   // ADST in vertical, DCT in horizontal
+    DCT_ADST,   // DCT  in vertical, ADST in horizontal
+    ADST_ADST,  // ADST in both directions
+    FLIPADST_DCT,
+    DCT_FLIPADST,
+    FLIPADST_FLIPADST,
+    ADST_FLIPADST,
+    FLIPADST_ADST,
+    IDTX,
+    V_DCT,
+    H_DCT,
+    V_ADST,
+    H_ADST,
+    V_FLIPADST,
+    H_FLIPADST,
+    N_TX_TYPES,
+    WHT_WHT = N_TX_TYPES,
+    N_TX_TYPES_PLUS_LL,
+};
+
+enum TxClass {
+    TX_CLASS_2D,
+    TX_CLASS_H,
+    TX_CLASS_V,
+};
+
+enum IntraPredMode {
+    DC_PRED,
+    VERT_PRED,
+    HOR_PRED,
+    DIAG_DOWN_LEFT_PRED,
+    DIAG_DOWN_RIGHT_PRED,
+    VERT_RIGHT_PRED,
+    HOR_DOWN_PRED,
+    HOR_UP_PRED,
+    VERT_LEFT_PRED,
+    SMOOTH_PRED,
+    SMOOTH_V_PRED,
+    SMOOTH_H_PRED,
+    PAETH_PRED,
+    N_INTRA_PRED_MODES,
+    CFL_PRED = N_INTRA_PRED_MODES,
+    N_UV_INTRA_PRED_MODES,
+    N_IMPL_INTRA_PRED_MODES = N_UV_INTRA_PRED_MODES,
+    LEFT_DC_PRED = DIAG_DOWN_LEFT_PRED,
+    TOP_DC_PRED,
+    DC_128_PRED,
+    Z1_PRED,
+    Z2_PRED,
+    Z3_PRED,
+    FILTER_PRED = N_INTRA_PRED_MODES,
+};
+
+enum InterIntraPredMode {
+    II_DC_PRED,
+    II_VERT_PRED,
+    II_HOR_PRED,
+    II_SMOOTH_PRED,
+    N_INTER_INTRA_PRED_MODES,
+};
+
+enum BlockPartition {
+    PARTITION_NONE,     // [ ] <-.
+    PARTITION_H,        // [-]   |
+    PARTITION_V,        // [|]   |
+    PARTITION_SPLIT,    // [+] --'
+    PARTITION_T_TOP_SPLIT,    // [⊥] i.e. split top, H bottom
+    PARTITION_T_BOTTOM_SPLIT, // [т] i.e. H top, split bottom
+    PARTITION_T_LEFT_SPLIT,   // [-|] i.e. split left, V right
+    PARTITION_T_RIGHT_SPLIT,  // [|-] i.e. V left, split right
+    PARTITION_H4,       // [Ⲷ]
+    PARTITION_V4,       // [Ⲽ]
+    N_PARTITIONS,
+    N_SUB8X8_PARTITIONS = PARTITION_T_TOP_SPLIT,
+};
+
+enum BlockSize {
+    BS_128x128,
+    BS_128x64,
+    BS_64x128,
+    BS_64x64,
+    BS_64x32,
+    BS_64x16,
+    BS_32x64,
+    BS_32x32,
+    BS_32x16,
+    BS_32x8,
+    BS_16x64,
+    BS_16x32,
+    BS_16x16,
+    BS_16x8,
+    BS_16x4,
+    BS_8x32,
+    BS_8x16,
+    BS_8x8,
+    BS_8x4,
+    BS_4x16,
+    BS_4x8,
+    BS_4x4,
+    N_BS_SIZES,
+};
+
+enum Filter2d { // order is horizontal, vertical
+    FILTER_2D_8TAP_REGULAR,
+    FILTER_2D_8TAP_REGULAR_SMOOTH,
+    FILTER_2D_8TAP_REGULAR_SHARP,
+    FILTER_2D_8TAP_SHARP_REGULAR,
+    FILTER_2D_8TAP_SHARP_SMOOTH,
+    FILTER_2D_8TAP_SHARP,
+    FILTER_2D_8TAP_SMOOTH_REGULAR,
+    FILTER_2D_8TAP_SMOOTH,
+    FILTER_2D_8TAP_SMOOTH_SHARP,
+    FILTER_2D_BILINEAR,
+    N_2D_FILTERS,
+};
+
+enum MVJoint {
+    MV_JOINT_ZERO,
+    MV_JOINT_H,
+    MV_JOINT_V,
+    MV_JOINT_HV,
+    N_MV_JOINTS,
+};
+
+enum InterPredMode {
+    NEARESTMV,
+    NEARMV,
+    GLOBALMV,
+    NEWMV,
+    N_INTER_PRED_MODES,
+};
+
+enum DRL_PROXIMITY {
+    NEAREST_DRL,
+    NEARER_DRL,
+    NEAR_DRL,
+    NEARISH_DRL
+};
+
+enum CompInterPredMode {
+    NEARESTMV_NEARESTMV,
+    NEARMV_NEARMV,
+    NEARESTMV_NEWMV,
+    NEWMV_NEARESTMV,
+    NEARMV_NEWMV,
+    NEWMV_NEARMV,
+    GLOBALMV_GLOBALMV,
+    NEWMV_NEWMV,
+    N_COMP_INTER_PRED_MODES,
+};
+
+enum CompInterType {
+    COMP_INTER_NONE,
+    COMP_INTER_WEIGHTED_AVG,
+    COMP_INTER_AVG,
+    COMP_INTER_SEG,
+    COMP_INTER_WEDGE,
+};
+
+enum InterIntraType {
+    INTER_INTRA_NONE,
+    INTER_INTRA_BLEND,
+    INTER_INTRA_WEDGE,
+};
+
+typedef union mv {
+    struct {
+        int16_t y, x;
+    };
+    uint32_t n;
+} mv;
+
+enum MotionMode {
+    MM_TRANSLATION,
+    MM_OBMC,
+    MM_WARP,
+};
+
+#define QINDEX_RANGE 256
+
+typedef struct Av1Block {
+    uint8_t bl, bs, bp;
+    uint8_t intra, seg_id, skip_mode, skip, uvtx;
+    union {
+        struct {
+            uint8_t y_mode, uv_mode, tx, pal_sz[2];
+            int8_t y_angle, uv_angle, cfl_alpha[2];
+        }; // intra
+        struct {
+            union {
+                struct {
+                    union mv mv[2];
+                    uint8_t wedge_idx, mask_sign, interintra_mode;
+                };
+                struct {
+                    union mv mv2d;
+                    int16_t matrix[4];
+                };
+            };
+            uint8_t comp_type, inter_mode, motion_mode, drl_idx;
+            int8_t ref[2];
+            uint8_t max_ytx, filter2d, interintra_type, tx_split0;
+            uint16_t tx_split1;
+        }; // inter
+    };
+} Av1Block;
+
+#endif /* DAV1D_SRC_LEVELS_H */
diff --git a/media/libdav1d/src/src/lf_apply.h b/media/libdav1d/src/src/lf_apply.h
new file mode 100644
index 0000000000..cf4c898550
--- /dev/null
+++ b/media/libdav1d/src/src/lf_apply.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LF_APPLY_H
+#define DAV1D_SRC_LF_APPLY_H
+
+#include 
+
+#include "common/bitdepth.h"
+
+#include "src/internal.h"
+#include "src/levels.h"
+
+void bytefn(dav1d_loopfilter_sbrow_cols)(const Dav1dFrameContext *f,
+                                         pixel *const p[3], Av1Filter *lflvl,
+                                         int sby, int start_of_tile_row);
+void bytefn(dav1d_loopfilter_sbrow_rows)(const Dav1dFrameContext *f,
+                                         pixel *const p[3], Av1Filter *lflvl,
+                                         int sby);
+
+void bytefn(dav1d_copy_lpf)(Dav1dFrameContext *const f,
+                            /*const*/ pixel *const src[3], int sby);
+
+#endif /* DAV1D_SRC_LF_APPLY_H */
diff --git a/media/libdav1d/src/src/lf_apply_tmpl.c b/media/libdav1d/src/src/lf_apply_tmpl.c
new file mode 100644
index 0000000000..4ef3becd82
--- /dev/null
+++ b/media/libdav1d/src/src/lf_apply_tmpl.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/lf_apply.h"
+#include "src/lr_apply.h"
+
+// The loop filter buffer stores 12 rows of pixels. A superblock block will
+// contain at most 2 stripes. Each stripe requires 4 rows pixels (2 above
+// and 2 below) the final 4 rows are used to swap the bottom of the last
+// stripe with the top of the next super block row.
+static void backup_lpf(const Dav1dFrameContext *const f,
+                       pixel *dst, const ptrdiff_t dst_stride,
+                       const pixel *src, const ptrdiff_t src_stride,
+                       const int ss_ver, const int sb128,
+                       int row, const int row_h, const int src_w,
+                       const int h, const int ss_hor, const int lr_backup)
+{
+    const int cdef_backup = !lr_backup;
+    const int dst_w = f->frame_hdr->super_res.enabled ?
+                      (f->frame_hdr->width[1] + ss_hor) >> ss_hor : src_w;
+
+    // The first stripe of the frame is shorter by 8 luma pixel rows.
+    int stripe_h = ((64 << (cdef_backup & sb128)) - 8 * !row) >> ss_ver;
+    src += (stripe_h - 2) * PXSTRIDE(src_stride);
+
+    if (f->c->n_tc == 1) {
+        if (row) {
+            const int top = 4 << sb128;
+            // Copy the top part of the stored loop filtered pixels from the
+            // previous sb row needed above the first stripe of this sb row.
+            pixel_copy(&dst[PXSTRIDE(dst_stride) *  0],
+                       &dst[PXSTRIDE(dst_stride) *  top],      dst_w);
+            pixel_copy(&dst[PXSTRIDE(dst_stride) *  1],
+                       &dst[PXSTRIDE(dst_stride) * (top + 1)], dst_w);
+            pixel_copy(&dst[PXSTRIDE(dst_stride) *  2],
+                       &dst[PXSTRIDE(dst_stride) * (top + 2)], dst_w);
+            pixel_copy(&dst[PXSTRIDE(dst_stride) *  3],
+                       &dst[PXSTRIDE(dst_stride) * (top + 3)], dst_w);
+        }
+        dst += 4 * PXSTRIDE(dst_stride);
+    }
+
+    if (lr_backup && (f->frame_hdr->width[0] != f->frame_hdr->width[1])) {
+        while (row + stripe_h <= row_h) {
+            const int n_lines = 4 - (row + stripe_h + 1 == h);
+            f->dsp->mc.resize(dst, dst_stride, src, src_stride,
+                              dst_w, n_lines, src_w, f->resize_step[ss_hor],
+                              f->resize_start[ss_hor] HIGHBD_CALL_SUFFIX);
+            row += stripe_h; // unmodified stripe_h for the 1st stripe
+            stripe_h = 64 >> ss_ver;
+            src += stripe_h * PXSTRIDE(src_stride);
+            dst += n_lines * PXSTRIDE(dst_stride);
+            if (n_lines == 3) {
+                pixel_copy(dst, &dst[-PXSTRIDE(dst_stride)], dst_w);
+                dst += PXSTRIDE(dst_stride);
+            }
+        }
+    } else {
+        while (row + stripe_h <= row_h) {
+            const int n_lines = 4 - (row + stripe_h + 1 == h);
+            for (int i = 0; i < 4; i++) {
+                pixel_copy(dst, i == n_lines ? &dst[-PXSTRIDE(dst_stride)] :
+                                               src, src_w);
+                dst += PXSTRIDE(dst_stride);
+                src += PXSTRIDE(src_stride);
+            }
+            row += stripe_h; // unmodified stripe_h for the 1st stripe
+            stripe_h = 64 >> ss_ver;
+            src += (stripe_h - 4) * PXSTRIDE(src_stride);
+        }
+    }
+}
+
+void bytefn(dav1d_copy_lpf)(Dav1dFrameContext *const f,
+                            /*const*/ pixel *const src[3], const int sby)
+{
+    const int have_tt = f->c->n_tc > 1;
+    const int resize = f->frame_hdr->width[0] != f->frame_hdr->width[1];
+    const int offset = 8 * !!sby;
+    const ptrdiff_t *const src_stride = f->cur.stride;
+    const ptrdiff_t *const lr_stride = f->sr_cur.p.stride;
+    const int tt_off = have_tt * sby * (4 << f->seq_hdr->sb128);
+    pixel *const dst[3] = {
+        f->lf.lr_lpf_line[0] + tt_off * PXSTRIDE(lr_stride[0]),
+        f->lf.lr_lpf_line[1] + tt_off * PXSTRIDE(lr_stride[1]),
+        f->lf.lr_lpf_line[2] + tt_off * PXSTRIDE(lr_stride[1])
+    };
+
+    // TODO Also check block level restore type to reduce copying.
+    const int restore_planes = f->lf.restore_planes;
+
+    if (f->seq_hdr->cdef || restore_planes & LR_RESTORE_Y) {
+        const int h = f->cur.p.h;
+        const int w = f->bw << 2;
+        const int row_h = imin((sby + 1) << (6 + f->seq_hdr->sb128), h - 1);
+        const int y_stripe = (sby << (6 + f->seq_hdr->sb128)) - offset;
+        if (restore_planes & LR_RESTORE_Y || !resize)
+            backup_lpf(f, dst[0], lr_stride[0],
+                       src[0] - offset * PXSTRIDE(src_stride[0]), src_stride[0],
+                       0, f->seq_hdr->sb128, y_stripe, row_h, w, h, 0, 1);
+        if (have_tt && resize) {
+            const ptrdiff_t cdef_off_y = sby * 4 * PXSTRIDE(src_stride[0]);
+            backup_lpf(f, f->lf.cdef_lpf_line[0] + cdef_off_y, src_stride[0],
+                       src[0] - offset * PXSTRIDE(src_stride[0]), src_stride[0],
+                       0, f->seq_hdr->sb128, y_stripe, row_h, w, h, 0, 0);
+        }
+    }
+    if ((f->seq_hdr->cdef || restore_planes & (LR_RESTORE_U | LR_RESTORE_V)) &&
+        f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400)
+    {
+        const int ss_ver = f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = f->sr_cur.p.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int h = (f->cur.p.h + ss_ver) >> ss_ver;
+        const int w = f->bw << (2 - ss_hor);
+        const int row_h = imin((sby + 1) << ((6 - ss_ver) + f->seq_hdr->sb128), h - 1);
+        const int offset_uv = offset >> ss_ver;
+        const int y_stripe = (sby << ((6 - ss_ver) + f->seq_hdr->sb128)) - offset_uv;
+        const ptrdiff_t cdef_off_uv = sby * 4 * PXSTRIDE(src_stride[1]);
+        if (f->seq_hdr->cdef || restore_planes & LR_RESTORE_U) {
+            if (restore_planes & LR_RESTORE_U || !resize)
+                backup_lpf(f, dst[1], lr_stride[1],
+                           src[1] - offset_uv * PXSTRIDE(src_stride[1]),
+                           src_stride[1], ss_ver, f->seq_hdr->sb128, y_stripe,
+                           row_h, w, h, ss_hor, 1);
+            if (have_tt && resize)
+                backup_lpf(f, f->lf.cdef_lpf_line[1] + cdef_off_uv, src_stride[1],
+                           src[1] - offset_uv * PXSTRIDE(src_stride[1]),
+                           src_stride[1], ss_ver, f->seq_hdr->sb128, y_stripe,
+                           row_h, w, h, ss_hor, 0);
+        }
+        if (f->seq_hdr->cdef || restore_planes & LR_RESTORE_V) {
+            if (restore_planes & LR_RESTORE_V || !resize)
+                backup_lpf(f, dst[2], lr_stride[1],
+                           src[2] - offset_uv * PXSTRIDE(src_stride[1]),
+                           src_stride[1], ss_ver, f->seq_hdr->sb128, y_stripe,
+                           row_h, w, h, ss_hor, 1);
+            if (have_tt && resize)
+                backup_lpf(f, f->lf.cdef_lpf_line[2] + cdef_off_uv, src_stride[1],
+                           src[2] - offset_uv * PXSTRIDE(src_stride[1]),
+                           src_stride[1], ss_ver, f->seq_hdr->sb128, y_stripe,
+                           row_h, w, h, ss_hor, 0);
+        }
+    }
+}
+
+static inline void filter_plane_cols_y(const Dav1dFrameContext *const f,
+                                       const int have_left,
+                                       const uint8_t (*lvl)[4],
+                                       const ptrdiff_t b4_stride,
+                                       const uint16_t (*const mask)[3][2],
+                                       pixel *dst, const ptrdiff_t ls,
+                                       const int w,
+                                       const int starty4, const int endy4)
+{
+    const Dav1dDSPContext *const dsp = f->dsp;
+
+    // filter edges between columns (e.g. block1 | block2)
+    for (int x = 0; x < w; x++) {
+        if (!have_left && !x) continue;
+        uint32_t hmask[4];
+        if (!starty4) {
+            hmask[0] = mask[x][0][0];
+            hmask[1] = mask[x][1][0];
+            hmask[2] = mask[x][2][0];
+            if (endy4 > 16) {
+                hmask[0] |= (unsigned) mask[x][0][1] << 16;
+                hmask[1] |= (unsigned) mask[x][1][1] << 16;
+                hmask[2] |= (unsigned) mask[x][2][1] << 16;
+            }
+        } else {
+            hmask[0] = mask[x][0][1];
+            hmask[1] = mask[x][1][1];
+            hmask[2] = mask[x][2][1];
+        }
+        hmask[3] = 0;
+        dsp->lf.loop_filter_sb[0][0](&dst[x * 4], ls, hmask,
+                                     (const uint8_t(*)[4]) &lvl[x][0], b4_stride,
+                                     &f->lf.lim_lut, endy4 - starty4 HIGHBD_CALL_SUFFIX);
+    }
+}
+
+static inline void filter_plane_rows_y(const Dav1dFrameContext *const f,
+                                       const int have_top,
+                                       const uint8_t (*lvl)[4],
+                                       const ptrdiff_t b4_stride,
+                                       const uint16_t (*const mask)[3][2],
+                                       pixel *dst, const ptrdiff_t ls,
+                                       const int w,
+                                       const int starty4, const int endy4)
+{
+    const Dav1dDSPContext *const dsp = f->dsp;
+
+    //                                 block1
+    // filter edges between rows (e.g. ------)
+    //                                 block2
+    for (int y = starty4; y < endy4;
+         y++, dst += 4 * PXSTRIDE(ls), lvl += b4_stride)
+    {
+        if (!have_top && !y) continue;
+        const uint32_t vmask[4] = {
+            mask[y][0][0] | ((unsigned) mask[y][0][1] << 16),
+            mask[y][1][0] | ((unsigned) mask[y][1][1] << 16),
+            mask[y][2][0] | ((unsigned) mask[y][2][1] << 16),
+            0,
+        };
+        dsp->lf.loop_filter_sb[0][1](dst, ls, vmask,
+                                     (const uint8_t(*)[4]) &lvl[0][1], b4_stride,
+                                     &f->lf.lim_lut, w HIGHBD_CALL_SUFFIX);
+    }
+}
+
+static inline void filter_plane_cols_uv(const Dav1dFrameContext *const f,
+                                        const int have_left,
+                                        const uint8_t (*lvl)[4],
+                                        const ptrdiff_t b4_stride,
+                                        const uint16_t (*const mask)[2][2],
+                                        pixel *const u, pixel *const v,
+                                        const ptrdiff_t ls, const int w,
+                                        const int starty4, const int endy4,
+                                        const int ss_ver)
+{
+    const Dav1dDSPContext *const dsp = f->dsp;
+
+    // filter edges between columns (e.g. block1 | block2)
+    for (int x = 0; x < w; x++) {
+        if (!have_left && !x) continue;
+        uint32_t hmask[3];
+        if (!starty4) {
+            hmask[0] = mask[x][0][0];
+            hmask[1] = mask[x][1][0];
+            if (endy4 > (16 >> ss_ver)) {
+                hmask[0] |= (unsigned) mask[x][0][1] << (16 >> ss_ver);
+                hmask[1] |= (unsigned) mask[x][1][1] << (16 >> ss_ver);
+            }
+        } else {
+            hmask[0] = mask[x][0][1];
+            hmask[1] = mask[x][1][1];
+        }
+        hmask[2] = 0;
+        dsp->lf.loop_filter_sb[1][0](&u[x * 4], ls, hmask,
+                                     (const uint8_t(*)[4]) &lvl[x][2], b4_stride,
+                                     &f->lf.lim_lut, endy4 - starty4 HIGHBD_CALL_SUFFIX);
+        dsp->lf.loop_filter_sb[1][0](&v[x * 4], ls, hmask,
+                                     (const uint8_t(*)[4]) &lvl[x][3], b4_stride,
+                                     &f->lf.lim_lut, endy4 - starty4 HIGHBD_CALL_SUFFIX);
+    }
+}
+
+static inline void filter_plane_rows_uv(const Dav1dFrameContext *const f,
+                                        const int have_top,
+                                        const uint8_t (*lvl)[4],
+                                        const ptrdiff_t b4_stride,
+                                        const uint16_t (*const mask)[2][2],
+                                        pixel *const u, pixel *const v,
+                                        const ptrdiff_t ls, const int w,
+                                        const int starty4, const int endy4,
+                                        const int ss_hor)
+{
+    const Dav1dDSPContext *const dsp = f->dsp;
+    ptrdiff_t off_l = 0;
+
+    //                                 block1
+    // filter edges between rows (e.g. ------)
+    //                                 block2
+    for (int y = starty4; y < endy4;
+         y++, off_l += 4 * PXSTRIDE(ls), lvl += b4_stride)
+    {
+        if (!have_top && !y) continue;
+        const uint32_t vmask[3] = {
+            mask[y][0][0] | ((unsigned) mask[y][0][1] << (16 >> ss_hor)),
+            mask[y][1][0] | ((unsigned) mask[y][1][1] << (16 >> ss_hor)),
+            0,
+        };
+        dsp->lf.loop_filter_sb[1][1](&u[off_l], ls, vmask,
+                                     (const uint8_t(*)[4]) &lvl[0][2], b4_stride,
+                                     &f->lf.lim_lut, w HIGHBD_CALL_SUFFIX);
+        dsp->lf.loop_filter_sb[1][1](&v[off_l], ls, vmask,
+                                     (const uint8_t(*)[4]) &lvl[0][3], b4_stride,
+                                     &f->lf.lim_lut, w HIGHBD_CALL_SUFFIX);
+    }
+}
+
+void bytefn(dav1d_loopfilter_sbrow_cols)(const Dav1dFrameContext *const f,
+                                         pixel *const p[3], Av1Filter *const lflvl,
+                                         int sby, const int start_of_tile_row)
+{
+    int x, have_left;
+    // Don't filter outside the frame
+    const int is_sb64 = !f->seq_hdr->sb128;
+    const int starty4 = (sby & is_sb64) << 4;
+    const int sbsz = 32 >> is_sb64;
+    const int sbl2 = 5 - is_sb64;
+    const int halign = (f->bh + 31) & ~31;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int vmask = 16 >> ss_ver, hmask = 16 >> ss_hor;
+    const unsigned vmax = 1U << vmask, hmax = 1U << hmask;
+    const unsigned endy4 = starty4 + imin(f->h4 - sby * sbsz, sbsz);
+    const unsigned uv_endy4 = (endy4 + ss_ver) >> ss_ver;
+
+    // fix lpf strength at tile col boundaries
+    const uint8_t *lpf_y = &f->lf.tx_lpf_right_edge[0][sby << sbl2];
+    const uint8_t *lpf_uv = &f->lf.tx_lpf_right_edge[1][sby << (sbl2 - ss_ver)];
+    for (int tile_col = 1;; tile_col++) {
+        x = f->frame_hdr->tiling.col_start_sb[tile_col];
+        if ((x << sbl2) >= f->bw) break;
+        const int bx4 = x & is_sb64 ? 16 : 0, cbx4 = bx4 >> ss_hor;
+        x >>= is_sb64;
+
+        uint16_t (*const y_hmask)[2] = lflvl[x].filter_y[0][bx4];
+        for (unsigned y = starty4, mask = 1 << y; y < endy4; y++, mask <<= 1) {
+            const int sidx = mask >= 0x10000U;
+            const unsigned smask = mask >> (sidx << 4);
+            const int idx = 2 * !!(y_hmask[2][sidx] & smask) +
+                                !!(y_hmask[1][sidx] & smask);
+            y_hmask[2][sidx] &= ~smask;
+            y_hmask[1][sidx] &= ~smask;
+            y_hmask[0][sidx] &= ~smask;
+            y_hmask[imin(idx, lpf_y[y - starty4])][sidx] |= smask;
+        }
+
+        if (f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400) {
+            uint16_t (*const uv_hmask)[2] = lflvl[x].filter_uv[0][cbx4];
+            for (unsigned y = starty4 >> ss_ver, uv_mask = 1 << y; y < uv_endy4;
+                 y++, uv_mask <<= 1)
+            {
+                const int sidx = uv_mask >= vmax;
+                const unsigned smask = uv_mask >> (sidx << (4 - ss_ver));
+                const int idx = !!(uv_hmask[1][sidx] & smask);
+                uv_hmask[1][sidx] &= ~smask;
+                uv_hmask[0][sidx] &= ~smask;
+                uv_hmask[imin(idx, lpf_uv[y - (starty4 >> ss_ver)])][sidx] |= smask;
+            }
+        }
+        lpf_y  += halign;
+        lpf_uv += halign >> ss_ver;
+    }
+
+    // fix lpf strength at tile row boundaries
+    if (start_of_tile_row) {
+        const BlockContext *a;
+        for (x = 0, a = &f->a[f->sb128w * (start_of_tile_row - 1)];
+             x < f->sb128w; x++, a++)
+        {
+            uint16_t (*const y_vmask)[2] = lflvl[x].filter_y[1][starty4];
+            const unsigned w = imin(32, f->w4 - (x << 5));
+            for (unsigned mask = 1, i = 0; i < w; mask <<= 1, i++) {
+                const int sidx = mask >= 0x10000U;
+                const unsigned smask = mask >> (sidx << 4);
+                const int idx = 2 * !!(y_vmask[2][sidx] & smask) +
+                                    !!(y_vmask[1][sidx] & smask);
+                y_vmask[2][sidx] &= ~smask;
+                y_vmask[1][sidx] &= ~smask;
+                y_vmask[0][sidx] &= ~smask;
+                y_vmask[imin(idx, a->tx_lpf_y[i])][sidx] |= smask;
+            }
+
+            if (f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400) {
+                const unsigned cw = (w + ss_hor) >> ss_hor;
+                uint16_t (*const uv_vmask)[2] = lflvl[x].filter_uv[1][starty4 >> ss_ver];
+                for (unsigned uv_mask = 1, i = 0; i < cw; uv_mask <<= 1, i++) {
+                    const int sidx = uv_mask >= hmax;
+                    const unsigned smask = uv_mask >> (sidx << (4 - ss_hor));
+                    const int idx = !!(uv_vmask[1][sidx] & smask);
+                    uv_vmask[1][sidx] &= ~smask;
+                    uv_vmask[0][sidx] &= ~smask;
+                    uv_vmask[imin(idx, a->tx_lpf_uv[i])][sidx] |= smask;
+                }
+            }
+        }
+    }
+
+    pixel *ptr;
+    uint8_t (*level_ptr)[4] = f->lf.level + f->b4_stride * sby * sbsz;
+    for (ptr = p[0], have_left = 0, x = 0; x < f->sb128w;
+         x++, have_left = 1, ptr += 128, level_ptr += 32)
+    {
+        filter_plane_cols_y(f, have_left, level_ptr, f->b4_stride,
+                            lflvl[x].filter_y[0], ptr, f->cur.stride[0],
+                            imin(32, f->w4 - x * 32), starty4, endy4);
+    }
+
+    if (!f->frame_hdr->loopfilter.level_u && !f->frame_hdr->loopfilter.level_v)
+        return;
+
+    ptrdiff_t uv_off;
+    level_ptr = f->lf.level + f->b4_stride * (sby * sbsz >> ss_ver);
+    for (uv_off = 0, have_left = 0, x = 0; x < f->sb128w;
+         x++, have_left = 1, uv_off += 128 >> ss_hor, level_ptr += 32 >> ss_hor)
+    {
+        filter_plane_cols_uv(f, have_left, level_ptr, f->b4_stride,
+                             lflvl[x].filter_uv[0],
+                             &p[1][uv_off], &p[2][uv_off], f->cur.stride[1],
+                             (imin(32, f->w4 - x * 32) + ss_hor) >> ss_hor,
+                             starty4 >> ss_ver, uv_endy4, ss_ver);
+    }
+}
+
+void bytefn(dav1d_loopfilter_sbrow_rows)(const Dav1dFrameContext *const f,
+                                         pixel *const p[3], Av1Filter *const lflvl,
+                                         int sby)
+{
+    int x;
+    // Don't filter outside the frame
+    const int have_top = sby > 0;
+    const int is_sb64 = !f->seq_hdr->sb128;
+    const int starty4 = (sby & is_sb64) << 4;
+    const int sbsz = 32 >> is_sb64;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const unsigned endy4 = starty4 + imin(f->h4 - sby * sbsz, sbsz);
+    const unsigned uv_endy4 = (endy4 + ss_ver) >> ss_ver;
+
+    pixel *ptr;
+    uint8_t (*level_ptr)[4] = f->lf.level + f->b4_stride * sby * sbsz;
+    for (ptr = p[0], x = 0; x < f->sb128w; x++, ptr += 128, level_ptr += 32) {
+        filter_plane_rows_y(f, have_top, level_ptr, f->b4_stride,
+                            lflvl[x].filter_y[1], ptr, f->cur.stride[0],
+                            imin(32, f->w4 - x * 32), starty4, endy4);
+    }
+
+    if (!f->frame_hdr->loopfilter.level_u && !f->frame_hdr->loopfilter.level_v)
+        return;
+
+    ptrdiff_t uv_off;
+    level_ptr = f->lf.level + f->b4_stride * (sby * sbsz >> ss_ver);
+    for (uv_off = 0, x = 0; x < f->sb128w;
+         x++, uv_off += 128 >> ss_hor, level_ptr += 32 >> ss_hor)
+    {
+        filter_plane_rows_uv(f, have_top, level_ptr, f->b4_stride,
+                             lflvl[x].filter_uv[1],
+                             &p[1][uv_off], &p[2][uv_off], f->cur.stride[1],
+                             (imin(32, f->w4 - x * 32) + ss_hor) >> ss_hor,
+                             starty4 >> ss_ver, uv_endy4, ss_hor);
+    }
+}
diff --git a/media/libdav1d/src/src/lf_mask.c b/media/libdav1d/src/src/lf_mask.c
new file mode 100644
index 0000000000..c81bd9b5f9
--- /dev/null
+++ b/media/libdav1d/src/src/lf_mask.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/ctx.h"
+#include "src/levels.h"
+#include "src/lf_mask.h"
+#include "src/tables.h"
+
+static void decomp_tx(uint8_t (*const txa)[2 /* txsz, step */][32 /* y */][32 /* x */],
+                      const enum RectTxfmSize from,
+                      const int depth,
+                      const int y_off, const int x_off,
+                      const uint16_t *const tx_masks)
+{
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[from];
+    const int is_split = (from == (int) TX_4X4 || depth > 1) ? 0 :
+        (tx_masks[depth] >> (y_off * 4 + x_off)) & 1;
+
+    if (is_split) {
+        const enum RectTxfmSize sub = t_dim->sub;
+        const int htw4 = t_dim->w >> 1, hth4 = t_dim->h >> 1;
+
+        decomp_tx(txa, sub, depth + 1, y_off * 2 + 0, x_off * 2 + 0, tx_masks);
+        if (t_dim->w >= t_dim->h)
+            decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][0][htw4],
+                      sub, depth + 1, y_off * 2 + 0, x_off * 2 + 1, tx_masks);
+        if (t_dim->h >= t_dim->w) {
+            decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][0],
+                      sub, depth + 1, y_off * 2 + 1, x_off * 2 + 0, tx_masks);
+            if (t_dim->w >= t_dim->h)
+                decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][htw4],
+                          sub, depth + 1, y_off * 2 + 1, x_off * 2 + 1, tx_masks);
+        }
+    } else {
+        const int lw = imin(2, t_dim->lw), lh = imin(2, t_dim->lh);
+
+#define set_ctx(rep_macro) \
+        for (int y = 0; y < t_dim->h; y++) { \
+            rep_macro(txa[0][0][y], 0, lw); \
+            rep_macro(txa[1][0][y], 0, lh); \
+            txa[0][1][y][0] = t_dim->w; \
+        }
+        case_set_upto16(t_dim->lw);
+#undef set_ctx
+        dav1d_memset_pow2[t_dim->lw](txa[1][1][0], t_dim->h);
+    }
+}
+
+static inline void mask_edges_inter(uint16_t (*const masks)[32][3][2],
+                                    const int by4, const int bx4,
+                                    const int w4, const int h4, const int skip,
+                                    const enum RectTxfmSize max_tx,
+                                    const uint16_t *const tx_masks,
+                                    uint8_t *const a, uint8_t *const l)
+{
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[max_tx];
+    int y, x;
+
+    ALIGN_STK_16(uint8_t, txa, 2 /* edge */, [2 /* txsz, step */][32 /* y */][32 /* x */]);
+    for (int y_off = 0, y = 0; y < h4; y += t_dim->h, y_off++)
+        for (int x_off = 0, x = 0; x < w4; x += t_dim->w, x_off++)
+            decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][y][x],
+                      max_tx, 0, y_off, x_off, tx_masks);
+
+    // left block edge
+    unsigned mask = 1U << by4;
+    for (y = 0; y < h4; y++, mask <<= 1) {
+        const int sidx = mask >= 0x10000;
+        const unsigned smask = mask >> (sidx << 4);
+        masks[0][bx4][imin(txa[0][0][y][0], l[y])][sidx] |= smask;
+    }
+
+    // top block edge
+    for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) {
+        const int sidx = mask >= 0x10000;
+        const unsigned smask = mask >> (sidx << 4);
+        masks[1][by4][imin(txa[1][0][0][x], a[x])][sidx] |= smask;
+    }
+
+    if (!skip) {
+        // inner (tx) left|right edges
+        for (y = 0, mask = 1U << by4; y < h4; y++, mask <<= 1) {
+            const int sidx = mask >= 0x10000U;
+            const unsigned smask = mask >> (sidx << 4);
+            int ltx = txa[0][0][y][0];
+            int step = txa[0][1][y][0];
+            for (x = step; x < w4; x += step) {
+                const int rtx = txa[0][0][y][x];
+                masks[0][bx4 + x][imin(rtx, ltx)][sidx] |= smask;
+                ltx = rtx;
+                step = txa[0][1][y][x];
+            }
+        }
+
+        //            top
+        // inner (tx) --- edges
+        //           bottom
+        for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) {
+            const int sidx = mask >= 0x10000U;
+            const unsigned smask = mask >> (sidx << 4);
+            int ttx = txa[1][0][0][x];
+            int step = txa[1][1][0][x];
+            for (y = step; y < h4; y += step) {
+                const int btx = txa[1][0][y][x];
+                masks[1][by4 + y][imin(ttx, btx)][sidx] |= smask;
+                ttx = btx;
+                step = txa[1][1][y][x];
+            }
+        }
+    }
+
+    for (y = 0; y < h4; y++)
+        l[y] = txa[0][0][y][w4 - 1];
+    memcpy(a, txa[1][0][h4 - 1], w4);
+}
+
+static inline void mask_edges_intra(uint16_t (*const masks)[32][3][2],
+                                    const int by4, const int bx4,
+                                    const int w4, const int h4,
+                                    const enum RectTxfmSize tx,
+                                    uint8_t *const a, uint8_t *const l)
+{
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx];
+    const int twl4 = t_dim->lw, thl4 = t_dim->lh;
+    const int twl4c = imin(2, twl4), thl4c = imin(2, thl4);
+    int y, x;
+
+    // left block edge
+    unsigned mask = 1U << by4;
+    for (y = 0; y < h4; y++, mask <<= 1) {
+        const int sidx = mask >= 0x10000;
+        const unsigned smask = mask >> (sidx << 4);
+        masks[0][bx4][imin(twl4c, l[y])][sidx] |= smask;
+    }
+
+    // top block edge
+    for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) {
+        const int sidx = mask >= 0x10000;
+        const unsigned smask = mask >> (sidx << 4);
+        masks[1][by4][imin(thl4c, a[x])][sidx] |= smask;
+    }
+
+    // inner (tx) left|right edges
+    const int hstep = t_dim->w;
+    unsigned t = 1U << by4;
+    unsigned inner = (unsigned) ((((uint64_t) t) << h4) - t);
+    unsigned inner1 = inner & 0xffff, inner2 = inner >> 16;
+    for (x = hstep; x < w4; x += hstep) {
+        if (inner1) masks[0][bx4 + x][twl4c][0] |= inner1;
+        if (inner2) masks[0][bx4 + x][twl4c][1] |= inner2;
+    }
+
+    //            top
+    // inner (tx) --- edges
+    //           bottom
+    const int vstep = t_dim->h;
+    t = 1U << bx4;
+    inner = (unsigned) ((((uint64_t) t) << w4) - t);
+    inner1 = inner & 0xffff;
+    inner2 = inner >> 16;
+    for (y = vstep; y < h4; y += vstep) {
+        if (inner1) masks[1][by4 + y][thl4c][0] |= inner1;
+        if (inner2) masks[1][by4 + y][thl4c][1] |= inner2;
+    }
+
+    dav1d_memset_likely_pow2(a, thl4c, w4);
+    dav1d_memset_likely_pow2(l, twl4c, h4);
+}
+
+static void mask_edges_chroma(uint16_t (*const masks)[32][2][2],
+                              const int cby4, const int cbx4,
+                              const int cw4, const int ch4,
+                              const int skip_inter,
+                              const enum RectTxfmSize tx,
+                              uint8_t *const a, uint8_t *const l,
+                              const int ss_hor, const int ss_ver)
+{
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx];
+    const int twl4 = t_dim->lw, thl4 = t_dim->lh;
+    const int twl4c = !!twl4, thl4c = !!thl4;
+    int y, x;
+    const int vbits = 4 - ss_ver, hbits = 4 - ss_hor;
+    const int vmask = 16 >> ss_ver, hmask = 16 >> ss_hor;
+    const unsigned vmax = 1 << vmask, hmax = 1 << hmask;
+
+    // left block edge
+    unsigned mask = 1U << cby4;
+    for (y = 0; y < ch4; y++, mask <<= 1) {
+        const int sidx = mask >= vmax;
+        const unsigned smask = mask >> (sidx << vbits);
+        masks[0][cbx4][imin(twl4c, l[y])][sidx] |= smask;
+    }
+
+    // top block edge
+    for (x = 0, mask = 1U << cbx4; x < cw4; x++, mask <<= 1) {
+        const int sidx = mask >= hmax;
+        const unsigned smask = mask >> (sidx << hbits);
+        masks[1][cby4][imin(thl4c, a[x])][sidx] |= smask;
+    }
+
+    if (!skip_inter) {
+        // inner (tx) left|right edges
+        const int hstep = t_dim->w;
+        unsigned t = 1U << cby4;
+        unsigned inner = (unsigned) ((((uint64_t) t) << ch4) - t);
+        unsigned inner1 = inner & ((1 << vmask) - 1), inner2 = inner >> vmask;
+        for (x = hstep; x < cw4; x += hstep) {
+            if (inner1) masks[0][cbx4 + x][twl4c][0] |= inner1;
+            if (inner2) masks[0][cbx4 + x][twl4c][1] |= inner2;
+        }
+
+        //            top
+        // inner (tx) --- edges
+        //           bottom
+        const int vstep = t_dim->h;
+        t = 1U << cbx4;
+        inner = (unsigned) ((((uint64_t) t) << cw4) - t);
+        inner1 = inner & ((1 << hmask) - 1), inner2 = inner >> hmask;
+        for (y = vstep; y < ch4; y += vstep) {
+            if (inner1) masks[1][cby4 + y][thl4c][0] |= inner1;
+            if (inner2) masks[1][cby4 + y][thl4c][1] |= inner2;
+        }
+    }
+
+    dav1d_memset_likely_pow2(a, thl4c, cw4);
+    dav1d_memset_likely_pow2(l, twl4c, ch4);
+}
+
+void dav1d_create_lf_mask_intra(Av1Filter *const lflvl,
+                                uint8_t (*const level_cache)[4],
+                                const ptrdiff_t b4_stride,
+                                const uint8_t (*filter_level)[8][2],
+                                const int bx, const int by,
+                                const int iw, const int ih,
+                                const enum BlockSize bs,
+                                const enum RectTxfmSize ytx,
+                                const enum RectTxfmSize uvtx,
+                                const enum Dav1dPixelLayout layout,
+                                uint8_t *const ay, uint8_t *const ly,
+                                uint8_t *const auv, uint8_t *const luv)
+{
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+    const int bw4 = imin(iw - bx, b_dim[0]);
+    const int bh4 = imin(ih - by, b_dim[1]);
+    const int bx4 = bx & 31;
+    const int by4 = by & 31;
+    assert(bw4 >= 0 && bh4 >= 0);
+
+    if (bw4 && bh4) {
+        uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx;
+        for (int y = 0; y < bh4; y++) {
+            for (int x = 0; x < bw4; x++) {
+                level_cache_ptr[x][0] = filter_level[0][0][0];
+                level_cache_ptr[x][1] = filter_level[1][0][0];
+            }
+            level_cache_ptr += b4_stride;
+        }
+
+        mask_edges_intra(lflvl->filter_y, by4, bx4, bw4, bh4, ytx, ay, ly);
+    }
+
+    if (!auv) return;
+
+    const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor),
+                          (b_dim[0] + ss_hor) >> ss_hor);
+    const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver),
+                          (b_dim[1] + ss_ver) >> ss_ver);
+    assert(cbw4 >= 0 && cbh4 >= 0);
+
+    if (!cbw4 || !cbh4) return;
+
+    const int cbx4 = bx4 >> ss_hor;
+    const int cby4 = by4 >> ss_ver;
+
+    uint8_t (*level_cache_ptr)[4] =
+        level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor);
+    for (int y = 0; y < cbh4; y++) {
+        for (int x = 0; x < cbw4; x++) {
+            level_cache_ptr[x][2] = filter_level[2][0][0];
+            level_cache_ptr[x][3] = filter_level[3][0][0];
+        }
+        level_cache_ptr += b4_stride;
+    }
+
+    mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, 0, uvtx,
+                      auv, luv, ss_hor, ss_ver);
+}
+
+void dav1d_create_lf_mask_inter(Av1Filter *const lflvl,
+                                uint8_t (*const level_cache)[4],
+                                const ptrdiff_t b4_stride,
+                                const uint8_t (*filter_level)[8][2],
+                                const int bx, const int by,
+                                const int iw, const int ih,
+                                const int skip, const enum BlockSize bs,
+                                const enum RectTxfmSize max_ytx,
+                                const uint16_t *const tx_masks,
+                                const enum RectTxfmSize uvtx,
+                                const enum Dav1dPixelLayout layout,
+                                uint8_t *const ay, uint8_t *const ly,
+                                uint8_t *const auv, uint8_t *const luv)
+{
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+    const int bw4 = imin(iw - bx, b_dim[0]);
+    const int bh4 = imin(ih - by, b_dim[1]);
+    const int bx4 = bx & 31;
+    const int by4 = by & 31;
+    assert(bw4 >= 0 && bh4 >= 0);
+
+    if (bw4 && bh4) {
+        uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx;
+        for (int y = 0; y < bh4; y++) {
+            for (int x = 0; x < bw4; x++) {
+                level_cache_ptr[x][0] = filter_level[0][0][0];
+                level_cache_ptr[x][1] = filter_level[1][0][0];
+            }
+            level_cache_ptr += b4_stride;
+        }
+
+        mask_edges_inter(lflvl->filter_y, by4, bx4, bw4, bh4, skip,
+                         max_ytx, tx_masks, ay, ly);
+    }
+
+    if (!auv) return;
+
+    const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor),
+                          (b_dim[0] + ss_hor) >> ss_hor);
+    const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver),
+                          (b_dim[1] + ss_ver) >> ss_ver);
+    assert(cbw4 >= 0 && cbh4 >= 0);
+
+    if (!cbw4 || !cbh4) return;
+
+    const int cbx4 = bx4 >> ss_hor;
+    const int cby4 = by4 >> ss_ver;
+
+    uint8_t (*level_cache_ptr)[4] =
+        level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor);
+    for (int y = 0; y < cbh4; y++) {
+        for (int x = 0; x < cbw4; x++) {
+            level_cache_ptr[x][2] = filter_level[2][0][0];
+            level_cache_ptr[x][3] = filter_level[3][0][0];
+        }
+        level_cache_ptr += b4_stride;
+    }
+
+    mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, skip, uvtx,
+                      auv, luv, ss_hor, ss_ver);
+}
+
+void dav1d_calc_eih(Av1FilterLUT *const lim_lut, const int filter_sharpness) {
+    // set E/I/H values from loopfilter level
+    const int sharp = filter_sharpness;
+    for (int level = 0; level < 64; level++) {
+        int limit = level;
+
+        if (sharp > 0) {
+            limit >>= (sharp + 3) >> 2;
+            limit = imin(limit, 9 - sharp);
+        }
+        limit = imax(limit, 1);
+
+        lim_lut->i[level] = limit;
+        lim_lut->e[level] = 2 * (level + 2) + limit;
+    }
+    lim_lut->sharp[0] = (sharp + 3) >> 2;
+    lim_lut->sharp[1] = sharp ? 9 - sharp : 0xff;
+}
+
+static void calc_lf_value(uint8_t (*const lflvl_values)[2],
+                          const int base_lvl, const int lf_delta,
+                          const int seg_delta,
+                          const Dav1dLoopfilterModeRefDeltas *const mr_delta)
+{
+    const int base = iclip(iclip(base_lvl + lf_delta, 0, 63) + seg_delta, 0, 63);
+
+    if (!mr_delta) {
+        memset(lflvl_values, base, sizeof(*lflvl_values) * 8);
+    } else {
+        const int sh = base >= 32;
+        lflvl_values[0][0] = lflvl_values[0][1] =
+            iclip(base + (mr_delta->ref_delta[0] * (1 << sh)), 0, 63);
+        for (int r = 1; r < 8; r++) {
+            for (int m = 0; m < 2; m++) {
+                const int delta =
+                    mr_delta->mode_delta[m] + mr_delta->ref_delta[r];
+                lflvl_values[r][m] = iclip(base + (delta * (1 << sh)), 0, 63);
+            }
+        }
+    }
+}
+
+static inline void calc_lf_value_chroma(uint8_t (*const lflvl_values)[2],
+                                        const int base_lvl, const int lf_delta,
+                                        const int seg_delta,
+                                        const Dav1dLoopfilterModeRefDeltas *const mr_delta)
+{
+    if (!base_lvl)
+        memset(lflvl_values, 0, sizeof(*lflvl_values) * 8);
+    else
+        calc_lf_value(lflvl_values, base_lvl, lf_delta, seg_delta, mr_delta);
+}
+
+void dav1d_calc_lf_values(uint8_t (*const lflvl_values)[4][8][2],
+                          const Dav1dFrameHeader *const hdr,
+                          const int8_t lf_delta[4])
+{
+    const int n_seg = hdr->segmentation.enabled ? 8 : 1;
+
+    if (!hdr->loopfilter.level_y[0] && !hdr->loopfilter.level_y[1]) {
+        memset(lflvl_values, 0, sizeof(*lflvl_values) * n_seg);
+        return;
+    }
+
+    const Dav1dLoopfilterModeRefDeltas *const mr_deltas =
+        hdr->loopfilter.mode_ref_delta_enabled ?
+        &hdr->loopfilter.mode_ref_deltas : NULL;
+    for (int s = 0; s < n_seg; s++) {
+        const Dav1dSegmentationData *const segd =
+            hdr->segmentation.enabled ? &hdr->segmentation.seg_data.d[s] : NULL;
+
+        calc_lf_value(lflvl_values[s][0], hdr->loopfilter.level_y[0],
+                      lf_delta[0], segd ? segd->delta_lf_y_v : 0, mr_deltas);
+        calc_lf_value(lflvl_values[s][1], hdr->loopfilter.level_y[1],
+                      lf_delta[hdr->delta.lf.multi ? 1 : 0],
+                      segd ? segd->delta_lf_y_h : 0, mr_deltas);
+        calc_lf_value_chroma(lflvl_values[s][2], hdr->loopfilter.level_u,
+                             lf_delta[hdr->delta.lf.multi ? 2 : 0],
+                             segd ? segd->delta_lf_u : 0, mr_deltas);
+        calc_lf_value_chroma(lflvl_values[s][3], hdr->loopfilter.level_v,
+                             lf_delta[hdr->delta.lf.multi ? 3 : 0],
+                             segd ? segd->delta_lf_v : 0, mr_deltas);
+    }
+}
diff --git a/media/libdav1d/src/src/lf_mask.h b/media/libdav1d/src/src/lf_mask.h
new file mode 100644
index 0000000000..01ab2cfded
--- /dev/null
+++ b/media/libdav1d/src/src/lf_mask.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LF_MASK_H
+#define DAV1D_SRC_LF_MASK_H
+
+#include 
+#include 
+
+#include "src/levels.h"
+
+typedef struct Av1FilterLUT {
+    ALIGN(uint8_t e[64], 16);
+    ALIGN(uint8_t i[64], 16);
+    ALIGN(uint64_t sharp[2], 16);
+} Av1FilterLUT;
+
+typedef struct Av1RestorationUnit {
+    /* SGR: type = DAV1D_RESTORATION_SGRPROJ + sgr_idx */
+    uint8_t /* enum Dav1dRestorationType */ type;
+    int8_t filter_h[3];
+    int8_t filter_v[3];
+    int8_t sgr_weights[2];
+} Av1RestorationUnit;
+
+// each struct describes one 128x128 area (1 or 4 SBs), pre-superres-scaling
+typedef struct Av1Filter {
+    // each bit is 1 col
+    uint16_t filter_y[2 /* 0=col, 1=row */][32][3][2];
+    uint16_t filter_uv[2 /* 0=col, 1=row */][32][2][2];
+    int8_t cdef_idx[4]; // -1 means "unset"
+    uint16_t noskip_mask[16][2]; // for 8x8 blocks, but stored on a 4x8 basis
+} Av1Filter;
+
+// each struct describes one 128x128 area (1 or 4 SBs), post-superres-scaling
+typedef struct Av1Restoration {
+    Av1RestorationUnit lr[3][4];
+} Av1Restoration;
+
+void dav1d_create_lf_mask_intra(Av1Filter *lflvl, uint8_t (*level_cache)[4],
+                                const ptrdiff_t b4_stride,
+                                const uint8_t (*level)[8][2], int bx, int by,
+                                int iw, int ih, enum BlockSize bs,
+                                enum RectTxfmSize ytx, enum RectTxfmSize uvtx,
+                                enum Dav1dPixelLayout layout, uint8_t *ay,
+                                uint8_t *ly, uint8_t *auv, uint8_t *luv);
+void dav1d_create_lf_mask_inter(Av1Filter *lflvl, uint8_t (*level_cache)[4],
+                                const ptrdiff_t b4_stride,
+                                const uint8_t (*level)[8][2], int bx, int by,
+                                int iw, int ih, int skip_inter,
+                                enum BlockSize bs, enum RectTxfmSize max_ytx,
+                                const uint16_t *tx_mask, enum RectTxfmSize uvtx,
+                                enum Dav1dPixelLayout layout, uint8_t *ay,
+                                uint8_t *ly, uint8_t *auv, uint8_t *luv);
+void dav1d_calc_eih(Av1FilterLUT *lim_lut, int filter_sharpness);
+void dav1d_calc_lf_values(uint8_t (*values)[4][8][2], const Dav1dFrameHeader *hdr,
+                          const int8_t lf_delta[4]);
+
+#endif /* DAV1D_SRC_LF_MASK_H */
diff --git a/media/libdav1d/src/src/lib.c b/media/libdav1d/src/src/lib.c
new file mode 100644
index 0000000000..8ced79616d
--- /dev/null
+++ b/media/libdav1d/src/src/lib.c
@@ -0,0 +1,760 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "vcs_version.h"
+
+#include 
+#include 
+
+#if defined(__linux__) && HAVE_DLSYM
+#include 
+#endif
+
+#include "dav1d/dav1d.h"
+#include "dav1d/data.h"
+
+#include "common/validate.h"
+
+#include "src/cpu.h"
+#include "src/fg_apply.h"
+#include "src/internal.h"
+#include "src/log.h"
+#include "src/obu.h"
+#include "src/qm.h"
+#include "src/ref.h"
+#include "src/thread_task.h"
+#include "src/wedge.h"
+
+static COLD void init_internal(void) {
+    dav1d_init_cpu();
+    dav1d_init_ii_wedge_masks();
+    dav1d_init_intra_edge_tree();
+    dav1d_init_qm_tables();
+    dav1d_init_thread();
+}
+
+COLD const char *dav1d_version(void) {
+    return DAV1D_VERSION;
+}
+
+COLD unsigned dav1d_version_api(void) {
+    return (DAV1D_API_VERSION_MAJOR << 16) |
+           (DAV1D_API_VERSION_MINOR <<  8) |
+           (DAV1D_API_VERSION_PATCH <<  0);
+}
+
+COLD void dav1d_default_settings(Dav1dSettings *const s) {
+    s->n_threads = 0;
+    s->max_frame_delay = 0;
+    s->apply_grain = 1;
+    s->allocator.cookie = NULL;
+    s->allocator.alloc_picture_callback = dav1d_default_picture_alloc;
+    s->allocator.release_picture_callback = dav1d_default_picture_release;
+    s->logger.cookie = NULL;
+    s->logger.callback = dav1d_log_default_callback;
+    s->operating_point = 0;
+    s->all_layers = 1; // just until the tests are adjusted
+    s->frame_size_limit = 0;
+    s->strict_std_compliance = 0;
+    s->output_invisible_frames = 0;
+    s->inloop_filters = DAV1D_INLOOPFILTER_ALL;
+    s->decode_frame_type = DAV1D_DECODEFRAMETYPE_ALL;
+}
+
+static void close_internal(Dav1dContext **const c_out, int flush);
+
+NO_SANITIZE("cfi-icall") // CFI is broken with dlsym()
+static COLD size_t get_stack_size_internal(const pthread_attr_t *const thread_attr) {
+#if defined(__linux__) && HAVE_DLSYM && defined(__GLIBC__)
+    /* glibc has an issue where the size of the TLS is subtracted from the stack
+     * size instead of allocated separately. As a result the specified stack
+     * size may be insufficient when used in an application with large amounts
+     * of TLS data. The following is a workaround to compensate for that.
+     * See https://sourceware.org/bugzilla/show_bug.cgi?id=11787 */
+    size_t (*const get_minstack)(const pthread_attr_t*) =
+        dlsym(RTLD_DEFAULT, "__pthread_get_minstack");
+    if (get_minstack)
+        return get_minstack(thread_attr) - PTHREAD_STACK_MIN;
+#endif
+    return 0;
+}
+
+static COLD void get_num_threads(Dav1dContext *const c, const Dav1dSettings *const s,
+                                 unsigned *n_tc, unsigned *n_fc)
+{
+    /* ceil(sqrt(n)) */
+    static const uint8_t fc_lut[49] = {
+        1,                                     /*     1 */
+        2, 2, 2,                               /*  2- 4 */
+        3, 3, 3, 3, 3,                         /*  5- 9 */
+        4, 4, 4, 4, 4, 4, 4,                   /* 10-16 */
+        5, 5, 5, 5, 5, 5, 5, 5, 5,             /* 17-25 */
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,       /* 26-36 */
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 37-49 */
+    };
+    *n_tc = s->n_threads ? s->n_threads :
+        iclip(dav1d_num_logical_processors(c), 1, DAV1D_MAX_THREADS);
+    *n_fc = s->max_frame_delay ? umin(s->max_frame_delay, *n_tc) :
+            *n_tc < 50 ? fc_lut[*n_tc - 1] : 8; // min(8, ceil(sqrt(n)))
+}
+
+COLD int dav1d_get_frame_delay(const Dav1dSettings *const s) {
+    unsigned n_tc, n_fc;
+    validate_input_or_ret(s != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s->n_threads >= 0 &&
+                          s->n_threads <= DAV1D_MAX_THREADS, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s->max_frame_delay >= 0 &&
+                          s->max_frame_delay <= DAV1D_MAX_FRAME_DELAY, DAV1D_ERR(EINVAL));
+
+    get_num_threads(NULL, s, &n_tc, &n_fc);
+    return n_fc;
+}
+
+COLD int dav1d_open(Dav1dContext **const c_out, const Dav1dSettings *const s) {
+    static pthread_once_t initted = PTHREAD_ONCE_INIT;
+    pthread_once(&initted, init_internal);
+
+    validate_input_or_ret(c_out != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s->n_threads >= 0 &&
+                          s->n_threads <= DAV1D_MAX_THREADS, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s->max_frame_delay >= 0 &&
+                          s->max_frame_delay <= DAV1D_MAX_FRAME_DELAY, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s->allocator.alloc_picture_callback != NULL,
+                          DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s->allocator.release_picture_callback != NULL,
+                          DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s->operating_point >= 0 &&
+                          s->operating_point <= 31, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(s->decode_frame_type >= DAV1D_DECODEFRAMETYPE_ALL &&
+                          s->decode_frame_type <= DAV1D_DECODEFRAMETYPE_KEY, DAV1D_ERR(EINVAL));
+
+    pthread_attr_t thread_attr;
+    if (pthread_attr_init(&thread_attr)) return DAV1D_ERR(ENOMEM);
+    size_t stack_size = 1024 * 1024 + get_stack_size_internal(&thread_attr);
+
+    pthread_attr_setstacksize(&thread_attr, stack_size);
+
+    Dav1dContext *const c = *c_out = dav1d_alloc_aligned(ALLOC_COMMON_CTX, sizeof(*c), 64);
+    if (!c) goto error;
+    memset(c, 0, sizeof(*c));
+
+    c->allocator = s->allocator;
+    c->logger = s->logger;
+    c->apply_grain = s->apply_grain;
+    c->operating_point = s->operating_point;
+    c->all_layers = s->all_layers;
+    c->frame_size_limit = s->frame_size_limit;
+    c->strict_std_compliance = s->strict_std_compliance;
+    c->output_invisible_frames = s->output_invisible_frames;
+    c->inloop_filters = s->inloop_filters;
+    c->decode_frame_type = s->decode_frame_type;
+
+    dav1d_data_props_set_defaults(&c->cached_error_props);
+
+    if (dav1d_mem_pool_init(ALLOC_OBU_HDR, &c->seq_hdr_pool) ||
+        dav1d_mem_pool_init(ALLOC_OBU_HDR, &c->frame_hdr_pool) ||
+        dav1d_mem_pool_init(ALLOC_SEGMAP, &c->segmap_pool) ||
+        dav1d_mem_pool_init(ALLOC_REFMVS, &c->refmvs_pool) ||
+        dav1d_mem_pool_init(ALLOC_PIC_CTX, &c->pic_ctx_pool) ||
+        dav1d_mem_pool_init(ALLOC_CDF, &c->cdf_pool))
+    {
+        goto error;
+    }
+
+    if (c->allocator.alloc_picture_callback   == dav1d_default_picture_alloc &&
+        c->allocator.release_picture_callback == dav1d_default_picture_release)
+    {
+        if (c->allocator.cookie) goto error;
+        if (dav1d_mem_pool_init(ALLOC_PIC, &c->picture_pool)) goto error;
+        c->allocator.cookie = c->picture_pool;
+    } else if (c->allocator.alloc_picture_callback   == dav1d_default_picture_alloc ||
+               c->allocator.release_picture_callback == dav1d_default_picture_release)
+    {
+        goto error;
+    }
+
+    /* On 32-bit systems extremely large frame sizes can cause overflows in
+     * dav1d_decode_frame() malloc size calculations. Prevent that from occuring
+     * by enforcing a maximum frame size limit, chosen to roughly correspond to
+     * the largest size possible to decode without exhausting virtual memory. */
+    if (sizeof(size_t) < 8 && s->frame_size_limit - 1 >= 8192 * 8192) {
+        c->frame_size_limit = 8192 * 8192;
+        if (s->frame_size_limit)
+            dav1d_log(c, "Frame size limit reduced from %u to %u.\n",
+                      s->frame_size_limit, c->frame_size_limit);
+    }
+
+    c->flush = &c->flush_mem;
+    atomic_init(c->flush, 0);
+
+    get_num_threads(c, s, &c->n_tc, &c->n_fc);
+
+    c->fc = dav1d_alloc_aligned(ALLOC_THREAD_CTX, sizeof(*c->fc) * c->n_fc, 32);
+    if (!c->fc) goto error;
+    memset(c->fc, 0, sizeof(*c->fc) * c->n_fc);
+
+    c->tc = dav1d_alloc_aligned(ALLOC_THREAD_CTX, sizeof(*c->tc) * c->n_tc, 64);
+    if (!c->tc) goto error;
+    memset(c->tc, 0, sizeof(*c->tc) * c->n_tc);
+    if (c->n_tc > 1) {
+        if (pthread_mutex_init(&c->task_thread.lock, NULL)) goto error;
+        if (pthread_cond_init(&c->task_thread.cond, NULL)) {
+            pthread_mutex_destroy(&c->task_thread.lock);
+            goto error;
+        }
+        if (pthread_cond_init(&c->task_thread.delayed_fg.cond, NULL)) {
+            pthread_cond_destroy(&c->task_thread.cond);
+            pthread_mutex_destroy(&c->task_thread.lock);
+            goto error;
+        }
+        c->task_thread.cur = c->n_fc;
+        atomic_init(&c->task_thread.reset_task_cur, UINT_MAX);
+        atomic_init(&c->task_thread.cond_signaled, 0);
+        c->task_thread.inited = 1;
+    }
+
+    if (c->n_fc > 1) {
+        const size_t out_delayed_sz = sizeof(*c->frame_thread.out_delayed) * c->n_fc;
+        c->frame_thread.out_delayed =
+            dav1d_malloc(ALLOC_THREAD_CTX, out_delayed_sz);
+        if (!c->frame_thread.out_delayed) goto error;
+        memset(c->frame_thread.out_delayed, 0, out_delayed_sz);
+    }
+    for (unsigned n = 0; n < c->n_fc; n++) {
+        Dav1dFrameContext *const f = &c->fc[n];
+        if (c->n_tc > 1) {
+            if (pthread_mutex_init(&f->task_thread.lock, NULL)) goto error;
+            if (pthread_cond_init(&f->task_thread.cond, NULL)) {
+                pthread_mutex_destroy(&f->task_thread.lock);
+                goto error;
+            }
+            if (pthread_mutex_init(&f->task_thread.pending_tasks.lock, NULL)) {
+                pthread_cond_destroy(&f->task_thread.cond);
+                pthread_mutex_destroy(&f->task_thread.lock);
+                goto error;
+            }
+        }
+        f->c = c;
+        f->task_thread.ttd = &c->task_thread;
+        f->lf.last_sharpness = -1;
+    }
+
+    for (unsigned m = 0; m < c->n_tc; m++) {
+        Dav1dTaskContext *const t = &c->tc[m];
+        t->f = &c->fc[0];
+        t->task_thread.ttd = &c->task_thread;
+        t->c = c;
+        memset(t->cf_16bpc, 0, sizeof(t->cf_16bpc));
+        if (c->n_tc > 1) {
+            if (pthread_mutex_init(&t->task_thread.td.lock, NULL)) goto error;
+            if (pthread_cond_init(&t->task_thread.td.cond, NULL)) {
+                pthread_mutex_destroy(&t->task_thread.td.lock);
+                goto error;
+            }
+            if (pthread_create(&t->task_thread.td.thread, &thread_attr, dav1d_worker_task, t)) {
+                pthread_cond_destroy(&t->task_thread.td.cond);
+                pthread_mutex_destroy(&t->task_thread.td.lock);
+                goto error;
+            }
+            t->task_thread.td.inited = 1;
+        }
+    }
+    dav1d_pal_dsp_init(&c->pal_dsp);
+    dav1d_refmvs_dsp_init(&c->refmvs_dsp);
+
+    pthread_attr_destroy(&thread_attr);
+
+    return 0;
+
+error:
+    if (c) close_internal(c_out, 0);
+    pthread_attr_destroy(&thread_attr);
+    return DAV1D_ERR(ENOMEM);
+}
+
+static int has_grain(const Dav1dPicture *const pic)
+{
+    const Dav1dFilmGrainData *fgdata = &pic->frame_hdr->film_grain.data;
+    return fgdata->num_y_points || fgdata->num_uv_points[0] ||
+           fgdata->num_uv_points[1] || (fgdata->clip_to_restricted_range &&
+                                        fgdata->chroma_scaling_from_luma);
+}
+
+static int output_image(Dav1dContext *const c, Dav1dPicture *const out)
+{
+    int res = 0;
+
+    Dav1dThreadPicture *const in = (c->all_layers || !c->max_spatial_id)
+                                   ? &c->out : &c->cache;
+    if (!c->apply_grain || !has_grain(&in->p)) {
+        dav1d_picture_move_ref(out, &in->p);
+        dav1d_thread_picture_unref(in);
+        goto end;
+    }
+
+    res = dav1d_apply_grain(c, out, &in->p);
+    dav1d_thread_picture_unref(in);
+end:
+    if (!c->all_layers && c->max_spatial_id && c->out.p.data[0]) {
+        dav1d_thread_picture_move_ref(in, &c->out);
+    }
+    return res;
+}
+
+static int output_picture_ready(Dav1dContext *const c, const int drain) {
+    if (c->cached_error) return 1;
+    if (!c->all_layers && c->max_spatial_id) {
+        if (c->out.p.data[0] && c->cache.p.data[0]) {
+            if (c->max_spatial_id == c->cache.p.frame_hdr->spatial_id ||
+                c->out.flags & PICTURE_FLAG_NEW_TEMPORAL_UNIT)
+                return 1;
+            dav1d_thread_picture_unref(&c->cache);
+            dav1d_thread_picture_move_ref(&c->cache, &c->out);
+            return 0;
+        } else if (c->cache.p.data[0] && drain) {
+            return 1;
+        } else if (c->out.p.data[0]) {
+            dav1d_thread_picture_move_ref(&c->cache, &c->out);
+            return 0;
+        }
+    }
+
+    return !!c->out.p.data[0];
+}
+
+static int drain_picture(Dav1dContext *const c, Dav1dPicture *const out) {
+    unsigned drain_count = 0;
+    int drained = 0;
+    do {
+        const unsigned next = c->frame_thread.next;
+        Dav1dFrameContext *const f = &c->fc[next];
+        pthread_mutex_lock(&c->task_thread.lock);
+        while (f->n_tile_data > 0)
+            pthread_cond_wait(&f->task_thread.cond,
+                              &f->task_thread.ttd->lock);
+        Dav1dThreadPicture *const out_delayed =
+            &c->frame_thread.out_delayed[next];
+        if (out_delayed->p.data[0] || atomic_load(&f->task_thread.error)) {
+            unsigned first = atomic_load(&c->task_thread.first);
+            if (first + 1U < c->n_fc)
+                atomic_fetch_add(&c->task_thread.first, 1U);
+            else
+                atomic_store(&c->task_thread.first, 0);
+            atomic_compare_exchange_strong(&c->task_thread.reset_task_cur,
+                                           &first, UINT_MAX);
+            if (c->task_thread.cur && c->task_thread.cur < c->n_fc)
+                c->task_thread.cur--;
+            drained = 1;
+        } else if (drained) {
+            pthread_mutex_unlock(&c->task_thread.lock);
+            break;
+        }
+        if (++c->frame_thread.next == c->n_fc)
+            c->frame_thread.next = 0;
+        pthread_mutex_unlock(&c->task_thread.lock);
+        const int error = f->task_thread.retval;
+        if (error) {
+            f->task_thread.retval = 0;
+            dav1d_data_props_copy(&c->cached_error_props, &out_delayed->p.m);
+            dav1d_thread_picture_unref(out_delayed);
+            return error;
+        }
+        if (out_delayed->p.data[0]) {
+            const unsigned progress =
+                atomic_load_explicit(&out_delayed->progress[1],
+                                     memory_order_relaxed);
+            if ((out_delayed->visible || c->output_invisible_frames) &&
+                progress != FRAME_ERROR)
+            {
+                dav1d_thread_picture_ref(&c->out, out_delayed);
+                c->event_flags |= dav1d_picture_get_event_flags(out_delayed);
+            }
+            dav1d_thread_picture_unref(out_delayed);
+            if (output_picture_ready(c, 0))
+                return output_image(c, out);
+        }
+    } while (++drain_count < c->n_fc);
+
+    if (output_picture_ready(c, 1))
+        return output_image(c, out);
+
+    return DAV1D_ERR(EAGAIN);
+}
+
+static int gen_picture(Dav1dContext *const c)
+{
+    Dav1dData *const in = &c->in;
+
+    if (output_picture_ready(c, 0))
+        return 0;
+
+    while (in->sz > 0) {
+        const ptrdiff_t res = dav1d_parse_obus(c, in);
+        if (res < 0) {
+            dav1d_data_unref_internal(in);
+        } else {
+            assert((size_t)res <= in->sz);
+            in->sz -= res;
+            in->data += res;
+            if (!in->sz) dav1d_data_unref_internal(in);
+        }
+        if (output_picture_ready(c, 0))
+            break;
+        if (res < 0)
+            return (int)res;
+    }
+
+    return 0;
+}
+
+int dav1d_send_data(Dav1dContext *const c, Dav1dData *const in)
+{
+    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(in != NULL, DAV1D_ERR(EINVAL));
+
+    if (in->data) {
+        validate_input_or_ret(in->sz > 0 && in->sz <= SIZE_MAX / 2, DAV1D_ERR(EINVAL));
+        c->drain = 0;
+    }
+    if (c->in.data)
+        return DAV1D_ERR(EAGAIN);
+    dav1d_data_ref(&c->in, in);
+
+    int res = gen_picture(c);
+    if (!res)
+        dav1d_data_unref_internal(in);
+
+    return res;
+}
+
+int dav1d_get_picture(Dav1dContext *const c, Dav1dPicture *const out)
+{
+    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
+
+    const int drain = c->drain;
+    c->drain = 1;
+
+    int res = gen_picture(c);
+    if (res < 0)
+        return res;
+
+    if (c->cached_error) {
+        const int res = c->cached_error;
+        c->cached_error = 0;
+        return res;
+    }
+
+    if (output_picture_ready(c, c->n_fc == 1))
+        return output_image(c, out);
+
+    if (c->n_fc > 1 && drain)
+        return drain_picture(c, out);
+
+    return DAV1D_ERR(EAGAIN);
+}
+
+int dav1d_apply_grain(Dav1dContext *const c, Dav1dPicture *const out,
+                      const Dav1dPicture *const in)
+{
+    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(in != NULL, DAV1D_ERR(EINVAL));
+
+    if (!has_grain(in)) {
+        dav1d_picture_ref(out, in);
+        return 0;
+    }
+
+    int res = dav1d_picture_alloc_copy(c, out, in->p.w, in);
+    if (res < 0) goto error;
+
+    if (c->n_tc > 1) {
+        dav1d_task_delayed_fg(c, out, in);
+    } else {
+        switch (out->p.bpc) {
+#if CONFIG_8BPC
+        case 8:
+            dav1d_apply_grain_8bpc(&c->dsp[0].fg, out, in);
+            break;
+#endif
+#if CONFIG_16BPC
+        case 10:
+        case 12:
+            dav1d_apply_grain_16bpc(&c->dsp[(out->p.bpc >> 1) - 4].fg, out, in);
+            break;
+#endif
+        default: abort();
+        }
+    }
+
+    return 0;
+
+error:
+    dav1d_picture_unref_internal(out);
+    return res;
+}
+
+void dav1d_flush(Dav1dContext *const c) {
+    dav1d_data_unref_internal(&c->in);
+    if (c->out.p.frame_hdr)
+        dav1d_thread_picture_unref(&c->out);
+    if (c->cache.p.frame_hdr)
+        dav1d_thread_picture_unref(&c->cache);
+
+    c->drain = 0;
+    c->cached_error = 0;
+
+    for (int i = 0; i < 8; i++) {
+        if (c->refs[i].p.p.frame_hdr)
+            dav1d_thread_picture_unref(&c->refs[i].p);
+        dav1d_ref_dec(&c->refs[i].segmap);
+        dav1d_ref_dec(&c->refs[i].refmvs);
+        dav1d_cdf_thread_unref(&c->cdf[i]);
+    }
+    c->frame_hdr = NULL;
+    c->seq_hdr = NULL;
+    dav1d_ref_dec(&c->seq_hdr_ref);
+
+    c->mastering_display = NULL;
+    c->content_light = NULL;
+    c->itut_t35 = NULL;
+    c->n_itut_t35 = 0;
+    dav1d_ref_dec(&c->mastering_display_ref);
+    dav1d_ref_dec(&c->content_light_ref);
+    dav1d_ref_dec(&c->itut_t35_ref);
+
+    dav1d_data_props_unref_internal(&c->cached_error_props);
+
+    if (c->n_fc == 1 && c->n_tc == 1) return;
+    atomic_store(c->flush, 1);
+
+    if (c->n_tc > 1) {
+        pthread_mutex_lock(&c->task_thread.lock);
+        // stop running tasks in worker threads
+        for (unsigned i = 0; i < c->n_tc; i++) {
+            Dav1dTaskContext *const tc = &c->tc[i];
+            while (!tc->task_thread.flushed) {
+                pthread_cond_wait(&tc->task_thread.td.cond, &c->task_thread.lock);
+            }
+        }
+        for (unsigned i = 0; i < c->n_fc; i++) {
+            c->fc[i].task_thread.task_head = NULL;
+            c->fc[i].task_thread.task_tail = NULL;
+            c->fc[i].task_thread.task_cur_prev = NULL;
+            c->fc[i].task_thread.pending_tasks.head = NULL;
+            c->fc[i].task_thread.pending_tasks.tail = NULL;
+            atomic_init(&c->fc[i].task_thread.pending_tasks.merge, 0);
+        }
+        atomic_init(&c->task_thread.first, 0);
+        c->task_thread.cur = c->n_fc;
+        atomic_store(&c->task_thread.reset_task_cur, UINT_MAX);
+        atomic_store(&c->task_thread.cond_signaled, 0);
+        pthread_mutex_unlock(&c->task_thread.lock);
+    }
+
+    if (c->n_fc > 1) {
+        for (unsigned n = 0, next = c->frame_thread.next; n < c->n_fc; n++, next++) {
+            if (next == c->n_fc) next = 0;
+            Dav1dFrameContext *const f = &c->fc[next];
+            dav1d_decode_frame_exit(f, -1);
+            f->n_tile_data = 0;
+            f->task_thread.retval = 0;
+            f->task_thread.error = 0;
+            Dav1dThreadPicture *out_delayed = &c->frame_thread.out_delayed[next];
+            if (out_delayed->p.frame_hdr) {
+                dav1d_thread_picture_unref(out_delayed);
+            }
+        }
+        c->frame_thread.next = 0;
+    }
+    atomic_store(c->flush, 0);
+}
+
+COLD void dav1d_close(Dav1dContext **const c_out) {
+    validate_input(c_out != NULL);
+#if TRACK_HEAP_ALLOCATIONS
+    dav1d_log_alloc_stats(*c_out);
+#endif
+    close_internal(c_out, 1);
+}
+
+static COLD void close_internal(Dav1dContext **const c_out, int flush) {
+    Dav1dContext *const c = *c_out;
+    if (!c) return;
+
+    if (flush) dav1d_flush(c);
+
+    if (c->tc) {
+        struct TaskThreadData *ttd = &c->task_thread;
+        if (ttd->inited) {
+            pthread_mutex_lock(&ttd->lock);
+            for (unsigned n = 0; n < c->n_tc && c->tc[n].task_thread.td.inited; n++)
+                c->tc[n].task_thread.die = 1;
+            pthread_cond_broadcast(&ttd->cond);
+            pthread_mutex_unlock(&ttd->lock);
+            for (unsigned n = 0; n < c->n_tc; n++) {
+                Dav1dTaskContext *const pf = &c->tc[n];
+                if (!pf->task_thread.td.inited) break;
+                pthread_join(pf->task_thread.td.thread, NULL);
+                pthread_cond_destroy(&pf->task_thread.td.cond);
+                pthread_mutex_destroy(&pf->task_thread.td.lock);
+            }
+            pthread_cond_destroy(&ttd->delayed_fg.cond);
+            pthread_cond_destroy(&ttd->cond);
+            pthread_mutex_destroy(&ttd->lock);
+        }
+        dav1d_free_aligned(c->tc);
+    }
+
+    for (unsigned n = 0; c->fc && n < c->n_fc; n++) {
+        Dav1dFrameContext *const f = &c->fc[n];
+
+        // clean-up threading stuff
+        if (c->n_fc > 1) {
+            dav1d_free(f->tile_thread.lowest_pixel_mem);
+            dav1d_free(f->frame_thread.b);
+            dav1d_free_aligned(f->frame_thread.cbi);
+            dav1d_free_aligned(f->frame_thread.pal_idx);
+            dav1d_free_aligned(f->frame_thread.cf);
+            dav1d_free(f->frame_thread.tile_start_off);
+            dav1d_free_aligned(f->frame_thread.pal);
+        }
+        if (c->n_tc > 1) {
+            pthread_mutex_destroy(&f->task_thread.pending_tasks.lock);
+            pthread_cond_destroy(&f->task_thread.cond);
+            pthread_mutex_destroy(&f->task_thread.lock);
+        }
+        dav1d_free(f->frame_thread.frame_progress);
+        dav1d_free(f->task_thread.tasks);
+        dav1d_free(f->task_thread.tile_tasks[0]);
+        dav1d_free_aligned(f->ts);
+        dav1d_free_aligned(f->ipred_edge[0]);
+        dav1d_free(f->a);
+        dav1d_free(f->tile);
+        dav1d_free(f->lf.mask);
+        dav1d_free(f->lf.level);
+        dav1d_free(f->lf.lr_mask);
+        dav1d_free(f->lf.tx_lpf_right_edge[0]);
+        dav1d_free(f->lf.start_of_tile_row);
+        dav1d_free_aligned(f->rf.r);
+        dav1d_free_aligned(f->lf.cdef_line_buf);
+        dav1d_free_aligned(f->lf.lr_line_buf);
+    }
+    dav1d_free_aligned(c->fc);
+    if (c->n_fc > 1 && c->frame_thread.out_delayed) {
+        for (unsigned n = 0; n < c->n_fc; n++)
+            if (c->frame_thread.out_delayed[n].p.frame_hdr)
+                dav1d_thread_picture_unref(&c->frame_thread.out_delayed[n]);
+        dav1d_free(c->frame_thread.out_delayed);
+    }
+    for (int n = 0; n < c->n_tile_data; n++)
+        dav1d_data_unref_internal(&c->tile[n].data);
+    dav1d_free(c->tile);
+    for (int n = 0; n < 8; n++) {
+        dav1d_cdf_thread_unref(&c->cdf[n]);
+        if (c->refs[n].p.p.frame_hdr)
+            dav1d_thread_picture_unref(&c->refs[n].p);
+        dav1d_ref_dec(&c->refs[n].refmvs);
+        dav1d_ref_dec(&c->refs[n].segmap);
+    }
+    dav1d_ref_dec(&c->seq_hdr_ref);
+    dav1d_ref_dec(&c->frame_hdr_ref);
+
+    dav1d_ref_dec(&c->mastering_display_ref);
+    dav1d_ref_dec(&c->content_light_ref);
+    dav1d_ref_dec(&c->itut_t35_ref);
+
+    dav1d_mem_pool_end(c->seq_hdr_pool);
+    dav1d_mem_pool_end(c->frame_hdr_pool);
+    dav1d_mem_pool_end(c->segmap_pool);
+    dav1d_mem_pool_end(c->refmvs_pool);
+    dav1d_mem_pool_end(c->cdf_pool);
+    dav1d_mem_pool_end(c->picture_pool);
+    dav1d_mem_pool_end(c->pic_ctx_pool);
+
+    dav1d_freep_aligned(c_out);
+}
+
+int dav1d_get_event_flags(Dav1dContext *const c, enum Dav1dEventFlags *const flags) {
+    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(flags != NULL, DAV1D_ERR(EINVAL));
+
+    *flags = c->event_flags;
+    c->event_flags = 0;
+    return 0;
+}
+
+int dav1d_get_decode_error_data_props(Dav1dContext *const c, Dav1dDataProps *const out) {
+    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
+
+    dav1d_data_props_unref_internal(out);
+    *out = c->cached_error_props;
+    dav1d_data_props_set_defaults(&c->cached_error_props);
+
+    return 0;
+}
+
+void dav1d_picture_unref(Dav1dPicture *const p) {
+    dav1d_picture_unref_internal(p);
+}
+
+uint8_t *dav1d_data_create(Dav1dData *const buf, const size_t sz) {
+    return dav1d_data_create_internal(buf, sz);
+}
+
+int dav1d_data_wrap(Dav1dData *const buf, const uint8_t *const ptr,
+                    const size_t sz,
+                    void (*const free_callback)(const uint8_t *data,
+                                                void *user_data),
+                    void *const user_data)
+{
+    return dav1d_data_wrap_internal(buf, ptr, sz, free_callback, user_data);
+}
+
+int dav1d_data_wrap_user_data(Dav1dData *const buf,
+                              const uint8_t *const user_data,
+                              void (*const free_callback)(const uint8_t *user_data,
+                                                          void *cookie),
+                              void *const cookie)
+{
+    return dav1d_data_wrap_user_data_internal(buf,
+                                              user_data,
+                                              free_callback,
+                                              cookie);
+}
+
+void dav1d_data_unref(Dav1dData *const buf) {
+    dav1d_data_unref_internal(buf);
+}
+
+void dav1d_data_props_unref(Dav1dDataProps *const props) {
+    dav1d_data_props_unref_internal(props);
+}
diff --git a/media/libdav1d/src/src/log.c b/media/libdav1d/src/src/log.c
new file mode 100644
index 0000000000..a08f6eb68d
--- /dev/null
+++ b/media/libdav1d/src/src/log.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "dav1d/dav1d.h"
+
+#include "common/validate.h"
+
+#include "src/internal.h"
+#include "src/log.h"
+
+#if CONFIG_LOG
+COLD void dav1d_log_default_callback(void *const cookie,
+                                     const char *const format, va_list ap)
+{
+    vfprintf(stderr, format, ap);
+}
+
+COLD void dav1d_log(Dav1dContext *const c, const char *const format, ...) {
+    assert(c != NULL);
+
+    if (!c->logger.callback)
+        return;
+
+    va_list ap;
+    va_start(ap, format);
+    c->logger.callback(c->logger.cookie, format, ap);
+    va_end(ap);
+}
+#endif
diff --git a/media/libdav1d/src/src/log.h b/media/libdav1d/src/src/log.h
new file mode 100644
index 0000000000..df32de7f25
--- /dev/null
+++ b/media/libdav1d/src/src/log.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOG_H
+#define DAV1D_SRC_LOG_H
+
+#include "config.h"
+
+#include 
+
+#include "dav1d/dav1d.h"
+
+#include "common/attributes.h"
+
+#if CONFIG_LOG
+#define dav1d_log dav1d_log
+void dav1d_log_default_callback(void *cookie, const char *format, va_list ap);
+void dav1d_log(Dav1dContext *c, const char *format, ...) ATTR_FORMAT_PRINTF(2, 3);
+#else
+#define dav1d_log_default_callback NULL
+#define dav1d_log(...) do { } while(0)
+#endif
+
+#endif /* DAV1D_SRC_LOG_H */
diff --git a/media/libdav1d/src/src/loongarch/cdef.S b/media/libdav1d/src/src/loongarch/cdef.S
new file mode 100644
index 0000000000..d069f66ae1
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/cdef.S
@@ -0,0 +1,2249 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/loongarch/loongson_asm.S"
+
+// static int cdef_find_dir_lsx(const pixel *img, const ptrdiff_t stride,
+//                            unsigned *const var HIGHBD_DECL_SUFFIX)
+// param: img: a0, stride: a1, var: a2
+function cdef_find_dir_8bpc_lsx
+    addi.d         sp,    sp,    -64
+    fst.d          f24,   sp,    0
+    fst.d          f25,   sp,    8
+    fst.d          f26,   sp,    16
+    fst.d          f27,   sp,    24
+    fst.d          f28,   sp,    32
+    fst.d          f29,   sp,    40
+    fst.d          f30,   sp,    48
+    fst.d          f31,   sp,    56
+
+    li.d           a3,    128
+    vreplgr2vr.w   vr31,  a3
+
+    // hv: vr0-vr3  diag: vr4-vr11  alt: vr12-vr23
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, vr8, vr9, vr10, \
+        vr11, vr12, vr13, vr14, vr15, vr16, vr17, vr18, vr19, \
+        vr20, vr21, vr22, vr23
+    vxor.v      \i,       \i,       \i
+.endr
+
+.CFDL01:  // 8
+    // 0
+    fld.d          f24,   a0,    0  //img
+    vpermi.w       vr25,  vr24,  0x01
+
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+
+    vsub.w         vr24,  vr24,  vr31  //px
+    vsub.w         vr25,  vr25,  vr31
+
+    vadd.w         vr4,   vr4,   vr24  //diag[0][y+x]
+    vadd.w         vr5,   vr5,   vr25
+
+    vpackev.w      vr26,  vr25,  vr24
+    vpackod.w      vr27,  vr25,  vr24
+    vpermi.w       vr26,  vr26,  0xd8 //px0246
+    vpermi.w       vr27,  vr27,  0xd8 //px1357
+    vadd.w         vr12,  vr12,  vr26
+    vadd.w         vr12,  vr12,  vr27  //alt[0][y+(x>>1)]
+
+    vhaddw.d.w     vr28,  vr24,  vr24
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr25,  vr25
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr0,   a3,    0    //hv[0][y]
+
+    vadd.w         vr15,  vr15,  vr26
+    vadd.w         vr15,  vr15,  vr27  //alt[1][3+y-(x>>1)]
+    vpermi.w       vr15,  vr15,  0x1b
+
+    vadd.w         vr9,   vr9,   vr24
+    vadd.w         vr8,   vr8,   vr25
+    vpermi.w       vr8,   vr8,   0x1b
+    vpermi.w       vr9,   vr9,   0x1b  //diag[1][7+y-x]
+
+    vxor.v         vr28,  vr28,  vr28
+    vxor.v         vr29,  vr29,  vr29
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.w     vr18,  vr28,  0x30
+    vshuf4i.w      vr19,  vr28,  0x39
+    vextrins.w     vr19,  vr29,  0x30
+    vshuf4i.w      vr20,  vr29,  0x39  //alt[2][3-(y>>1)+7]
+    vinsgr2vr.w    vr20,  zero,  3
+
+    vadd.w         vr2,   vr2,   vr24
+    vadd.w         vr3,   vr3,   vr25  //hv[1][x]
+
+    vadd.w         vr21,  vr21,  vr24
+    vadd.w         vr22,  vr22,  vr25  //alt[3][(y>>1)+x]
+
+    add.d          a0,    a0,    a1
+
+    // 1
+    fld.d          f24,   a0,    0  //img
+    vpermi.w       vr25,  vr24,  0x01
+
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+
+    vsub.w         vr24,  vr24,  vr31  //px
+    vsub.w         vr25,  vr25,  vr31
+
+    vbsrl.v        vr28,  vr4,   4  //1-4
+    vbsrl.v        vr29,  vr5,   4  //5-8
+    vextrins.w     vr28,  vr5,   0x30
+    vadd.w         vr28,  vr28,  vr24  //diag[0][y+x]
+    vadd.w         vr29,  vr29,  vr25
+    vbsll.v        vr5,   vr29,  4
+    vextrins.w     vr5,   vr28,  0x03
+    vextrins.w     vr6,   vr29,  0x03
+    vextrins.w     vr28,  vr4,   0x30
+    vshuf4i.w      vr4,   vr28,  0x93
+
+    vbsrl.v        vr28,  vr12,  4
+    vextrins.w     vr28,  vr13,  0x30
+    vpackev.w      vr26,  vr25,  vr24
+    vpackod.w      vr27,  vr25,  vr24
+    vpermi.w       vr26,  vr26,  0xd8 //px0246
+    vpermi.w       vr27,  vr27,  0xd8 //px1357
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[0][y+(x>>1)]
+    vextrins.w     vr13,  vr28,  0x03
+    vextrins.w     vr28,  vr12,  0x30
+    vshuf4i.w      vr12,  vr28,  0x93
+
+    vhaddw.d.w     vr28,  vr24,  vr24
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr25,  vr25
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr0,   a3,    1    //hv[0][y]
+
+    vbsrl.v        vr28,  vr15,  4
+    vextrins.w     vr28,  vr16,  0x30
+    vpermi.w       vr28,  vr28,  0x1b
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[1][3+y-(x>>1)]
+    vextrins.w     vr16,  vr28,  0x00
+    vextrins.w     vr28,  vr15,  0x00
+    vshuf4i.w      vr15,  vr28,  0x6c
+
+    vbsrl.v        vr28,  vr8,   4     //4321
+    vbsrl.v        vr29,  vr9,   4     //8765
+    vextrins.w     vr28,  vr9,   0x30
+    vpermi.w       vr28,  vr28,  0x1b
+    vpermi.w       vr29,  vr29,  0x1b
+    vadd.w         vr29,  vr29,  vr24
+    vadd.w         vr28,  vr28,  vr25  //diag[1][7+y-x]
+    vextrins.w     vr10,  vr29,  0x00
+    vextrins.w     vr29,  vr28,  0x00
+    vshuf4i.w      vr9,   vr29,  0x6c
+    vextrins.w     vr28,  vr8,   0x00
+    vshuf4i.w      vr8,   vr28,  0x6c
+
+    vbsll.v        vr28,  vr19,  4
+    vextrins.w     vr28,  vr18,  0x03
+    vbsll.v        vr29,  vr20,  4
+    vextrins.w     vr29,  vr19,  0x03
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25  //alt[2][3-(y>>1)+7]
+    vextrins.w     vr18,  vr28,  0x30
+    vextrins.w     vr28,  vr29,  0x00
+    vshuf4i.w      vr19,  vr28,  0x39
+    vbsrl.v        vr20,  vr29,  4
+
+    vadd.w         vr2,   vr2,   vr24
+    vadd.w         vr3,   vr3,   vr25  //hv[1][x]
+
+    vadd.w         vr21,  vr21,  vr24
+    vadd.w         vr22,  vr22,  vr25  //alt[3][(y>>1)+x]
+
+    add.d          a0,    a0,    a1
+
+    // 2
+    fld.d          f24,   a0,    0  //img
+    vpermi.w       vr25,  vr24,  0x01
+
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+
+    vsub.w         vr24,  vr24,  vr31  //px
+    vsub.w         vr25,  vr25,  vr31
+
+    vbsrl.v        vr28,  vr4,   8
+    vbsrl.v        vr29,  vr5,   8
+    vextrins.d     vr28,  vr5,   0x10  //2-5
+    vextrins.d     vr29,  vr6,   0x10  //6-9
+    vadd.w         vr28,  vr28,  vr24  //diag[0][y+x]
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.d     vr4,   vr28,  0x10
+    vextrins.d     vr5,   vr28,  0x01
+    vextrins.d     vr5,   vr29,  0x10
+    vextrins.d     vr6,   vr29,  0x01
+
+    vbsrl.v        vr28,  vr12,  8
+    vextrins.d     vr28,  vr13,  0x10
+    vpackev.w      vr26,  vr25,  vr24
+    vpackod.w      vr27,  vr25,  vr24
+    vpermi.w       vr26,  vr26,  0xd8 //px0246
+    vpermi.w       vr27,  vr27,  0xd8 //px1357
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[0][y+(x>>1)]
+    vextrins.d     vr12,  vr28,  0x10
+    vextrins.d     vr13,  vr28,  0x01
+
+    vhaddw.d.w     vr28,  vr24,  vr24
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr25,  vr25
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr0,   a3,    2    //hv[0][y]
+
+    vbsrl.v        vr28,  vr15,  8
+    vextrins.d     vr28,  vr16,  0x10
+    vpermi.w       vr28,  vr28,  0x1b
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[1][3+y-(x>>1)]
+    vpermi.w       vr28,  vr28,  0x1b
+    vextrins.d     vr15,  vr28,  0x10
+    vextrins.d     vr16,  vr28,  0x01
+
+    vbsrl.v        vr28,  vr8,   8
+    vextrins.d     vr28,  vr9,   0x10
+    vbsrl.v        vr29,  vr9,   8
+    vextrins.d     vr29,  vr10,  0x10
+    vpermi.w       vr28,  vr28,  0x1b  //5432
+    vpermi.w       vr29,  vr29,  0x1b  //9876
+    vadd.w         vr29,  vr29,  vr24
+    vadd.w         vr28,  vr28,  vr25
+    vpermi.w       vr28,  vr28,  0x1b
+    vpermi.w       vr29,  vr29,  0x1b
+    vextrins.d     vr8,   vr28,  0x10
+    vextrins.d     vr9,   vr28,  0x01
+    vextrins.d     vr9,   vr29,  0x10
+    vextrins.d     vr10,  vr29,  0x01  //diag[1][7+y-x]
+
+    vbsrl.v        vr28,  vr18,  8
+    vextrins.d     vr28,  vr19,  0x10 //2345
+    vbsrl.v        vr29,  vr19,  8
+    vextrins.d     vr29,  vr20,  0x10 //6789
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.d     vr18,  vr28,  0x10
+    vextrins.d     vr19,  vr28,  0x01
+    vextrins.d     vr19,  vr29,  0x10
+    vextrins.d     vr20,  vr29,  0x01   //alt[2][3-(y>>1)+7]
+
+    vadd.w         vr2,   vr2,   vr24
+    vadd.w         vr3,   vr3,   vr25  //hv[1][x]
+
+    vbsrl.v        vr28,  vr21,  4
+    vextrins.w     vr28,  vr22,  0x30  //1234
+    vbsrl.v        vr29,  vr22,  4     //5678
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25  //alt[3][(y>>1)+x]
+    vextrins.w     vr23,  vr29,  0x03
+    vextrins.w     vr29,  vr28,  0x33
+    vshuf4i.w      vr22,  vr29,  0x93
+    vextrins.w     vr28,  vr21,  0x30
+    vshuf4i.w      vr21,  vr28,  0x93
+
+    add.d          a0,    a0,    a1
+
+    // 3
+    fld.d          f24,   a0,    0  //img
+    vpermi.w       vr25,  vr24,  0x01
+
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+
+    vsub.w         vr24,  vr24,  vr31  //px
+    vsub.w         vr25,  vr25,  vr31
+
+    vbsll.v        vr28,  vr5,   4
+    vextrins.w     vr28,  vr4,   0x03 //3456
+    vbsll.v        vr29,  vr6,   4
+    vextrins.w     vr29,  vr5,   0x03 //78910
+    vadd.w         vr28,  vr28,  vr24  //diag[0][y+x]
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.w     vr4,   vr28,  0x30
+    vextrins.w     vr28,  vr29,  0x00
+    vshuf4i.w      vr5,   vr28,  0x39
+    vbsrl.v        vr6,   vr29,  4
+
+    vbsll.v        vr28,  vr13,  4
+    vextrins.w     vr28,  vr12,  0x03
+    vpackev.w      vr26,  vr25,  vr24
+    vpackod.w      vr27,  vr25,  vr24
+    vpermi.w       vr26,  vr26,  0xd8 //px0246
+    vpermi.w       vr27,  vr27,  0xd8 //px1357
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[0][y+(x>>1)]
+    vextrins.w     vr12,  vr28,  0x30
+    vbsrl.v        vr13,  vr28,  4
+
+    vhaddw.d.w     vr28,  vr24,  vr24
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr25,  vr25
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr0,   a3,    3    //hv[0][y]
+
+    vbsll.v        vr28,  vr16,  4
+    vextrins.w     vr28,  vr15,  0x03
+    vpermi.w       vr28,  vr28,  0x1b  //6543
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[1][3+y-(x>>1)]
+    vextrins.w     vr15,  vr28,  0x33
+    vshuf4i.w      vr16,  vr28,  0xc6
+    vinsgr2vr.w    vr16,  zero,  3
+
+    vbsll.v        vr28,  vr9,   4
+    vextrins.w     vr28,  vr8,   0x03  //3456
+    vbsll.v        vr29,  vr10,  4
+    vextrins.w     vr29,  vr9,   0x03  //78910
+    vpermi.w       vr28,  vr28,  0x1b  //6543
+    vpermi.w       vr29,  vr29,  0x1b  //10987
+    vadd.w         vr29,  vr29,  vr24
+    vadd.w         vr28,  vr28,  vr25  //diag[1][7+y-x]
+    vextrins.w     vr8,   vr28,  0x33
+    vextrins.w     vr28,  vr29,  0x33
+    vshuf4i.w      vr9,   vr28,  0xc6
+    vshuf4i.w      vr10,  vr29,  0xc6
+    vinsgr2vr.w    vr10,  zero,  3
+
+    vbsrl.v        vr28,  vr18,  8
+    vextrins.d     vr28,  vr19,  0x10 //2345
+    vbsrl.v        vr29,  vr19,  8
+    vextrins.d     vr29,  vr20,  0x10 //6789
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.d     vr18,  vr28,  0x10
+    vextrins.d     vr19,  vr28,  0x01
+    vextrins.d     vr19,  vr29,  0x10
+    vextrins.d     vr20,  vr29,  0x01   //alt[2][3-(y>>1)+7]
+
+    vadd.w         vr2,   vr2,   vr24
+    vadd.w         vr3,   vr3,   vr25  //hv[1][x]
+
+    vbsrl.v        vr28,  vr21,  4
+    vextrins.w     vr28,  vr22,  0x30  //1234
+    vbsrl.v        vr29,  vr22,  4     //5678
+    vextrins.w     vr29,  vr23,  0x30
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25  //alt[3][(y>>1)+x]
+    vextrins.w     vr23,  vr29,  0x03
+    vextrins.w     vr29,  vr28,  0x33
+    vshuf4i.w      vr22,  vr29,  0x93
+    vextrins.w     vr28,  vr21,  0x30
+    vshuf4i.w      vr21,  vr28,  0x93
+
+    add.d          a0,    a0,    a1
+
+    // 4
+    fld.d          f24,   a0,    0  //img
+    vpermi.w       vr25,  vr24,  0x01
+
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+
+    vsub.w         vr24,  vr24,  vr31  //px
+    vsub.w         vr25,  vr25,  vr31
+
+    vadd.w         vr5,   vr5,   vr24  //diag[0][y+x]
+    vadd.w         vr6,   vr6,   vr25
+
+    vpackev.w      vr26,  vr25,  vr24
+    vpackod.w      vr27,  vr25,  vr24
+    vpermi.w       vr26,  vr26,  0xd8 //px0246
+    vpermi.w       vr27,  vr27,  0xd8 //px1357
+    vadd.w         vr13,  vr13,  vr26
+    vadd.w         vr13,  vr13,  vr27  //alt[0][y+(x>>1)]
+
+    vhaddw.d.w     vr28,  vr24,  vr24
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr25,  vr25
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr1,   a3,    0    //hv[0][y]
+
+    vpermi.w       vr16,  vr16,  0x1b
+    vadd.w         vr16,  vr16,  vr26
+    vadd.w         vr16,  vr16,  vr27  //alt[1][3+y-(x>>1)]
+    vpermi.w       vr16,  vr16,  0x1b
+
+    vpermi.w       vr9,   vr9,   0x1b
+    vpermi.w       vr10,  vr10,  0x1b
+    vadd.w         vr10,  vr10,  vr24
+    vadd.w         vr9,   vr9,   vr25
+    vpermi.w       vr9,   vr9,   0x1b
+    vpermi.w       vr10,  vr10,  0x1b  //diag[1][7+y-x]
+
+    vbsrl.v        vr28,  vr18,  4
+    vextrins.w     vr28,  vr19,  0x30  //1234
+    vbsrl.v        vr29,  vr19,  4
+    vextrins.w     vr29,  vr20,  0x30  //5678
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25  //alt[2][3-(y>>1)+7]
+    vextrins.w     vr20,  vr29,  0x03
+    vextrins.w     vr29,  vr28,  0x33
+    vshuf4i.w      vr19,  vr29,  0x93
+    vbsll.v        vr18,  vr28,  4
+
+    vadd.w         vr2,   vr2,   vr24
+    vadd.w         vr3,   vr3,   vr25  //hv[1][x]
+
+    vbsrl.v        vr28,  vr21,  8
+    vextrins.d     vr28,  vr22,  0x10
+    vbsrl.v        vr29,  vr22,  8
+    vextrins.d     vr29,  vr23,  0x10
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.d     vr21,  vr28,  0x10
+    vextrins.d     vr22,  vr28,  0x01
+    vextrins.d     vr22,  vr29,  0x10
+    vextrins.d     vr23,  vr29,  0x01  //alt[3][(y>>1)+x]
+
+    add.d          a0,    a0,    a1
+
+    // 5
+    fld.d          f24,   a0,    0  //img
+    vpermi.w       vr25,  vr24,  0x01
+
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+
+    vsub.w         vr24,  vr24,  vr31  //px
+    vsub.w         vr25,  vr25,  vr31
+
+    vbsrl.v        vr28,  vr5,   4  //5-8
+    vbsrl.v        vr29,  vr6,   4  //9-12
+    vextrins.w     vr28,  vr6,   0x30
+    vadd.w         vr28,  vr28,  vr24  //diag[0][y+x]
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.w     vr7,   vr29,  0x03
+    vextrins.w     vr29,  vr28,  0x33
+    vshuf4i.w      vr6,   vr29,  0x93
+    vextrins.w     vr28,  vr5,   0x30
+    vshuf4i.w      vr5,   vr28,  0x93
+
+    vbsrl.v        vr28,  vr13,  4
+    vextrins.w     vr28,  vr14,  0x30
+    vpackev.w      vr26,  vr25,  vr24
+    vpackod.w      vr27,  vr25,  vr24
+    vpermi.w       vr26,  vr26,  0xd8 //px0246
+    vpermi.w       vr27,  vr27,  0xd8 //px1357
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[0][y+(x>>1)]
+    vextrins.w     vr14,  vr28,  0x03
+    vextrins.w     vr28,  vr13,  0x30
+    vshuf4i.w      vr13,  vr28,  0x93
+
+    vhaddw.d.w     vr28,  vr24,  vr24
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr25,  vr25
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr1,   a3,    1    //hv[0][y]
+
+    vbsrl.v        vr28,  vr16,  4
+    vextrins.w     vr28,  vr17,  0x30
+    vpermi.w       vr28,  vr28,  0x1b
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[1][3+y-(x>>1)]
+    vextrins.w     vr17,  vr28,  0x00
+    vextrins.w     vr28,  vr16,  0x00
+    vshuf4i.w      vr16,  vr28,  0x6c
+
+    vbsrl.v        vr28,  vr9,   4
+    vbsrl.v        vr29,  vr10,  4
+    vextrins.w     vr28,  vr10,  0x30
+    vpermi.w       vr28,  vr28,  0x1b  //8-5
+    vpermi.w       vr29,  vr29,  0x1b  //12-9
+    vadd.w         vr29,  vr29,  vr24
+    vadd.w         vr28,  vr28,  vr25  //diag[1][7+y-x]
+    vextrins.w     vr11,  vr29,  0x00
+    vextrins.w     vr29,  vr28,  0x00
+    vshuf4i.w      vr10,  vr29,  0x6c
+    vextrins.w     vr28,  vr9,   0x00
+    vshuf4i.w      vr9,   vr28,  0x6c
+
+    vbsrl.v        vr28,  vr18,  4
+    vextrins.w     vr28,  vr19,  0x30  //1234
+    vbsrl.v        vr29,  vr19,  4
+    vextrins.w     vr29,  vr20,  0x30  //5678
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25  //alt[2][3-(y>>1)+7]
+    vextrins.w     vr20,  vr29,  0x03
+    vextrins.w     vr29,  vr28,  0x33
+    vshuf4i.w      vr19,  vr29,  0x93
+    vbsll.v        vr18,  vr28,  4
+
+    vadd.w         vr2,   vr2,   vr24
+    vadd.w         vr3,   vr3,   vr25  //hv[1][x]
+
+    vbsrl.v        vr28,  vr21,  8
+    vextrins.d     vr28,  vr22,  0x10
+    vbsrl.v        vr29,  vr22,  8
+    vextrins.d     vr29,  vr23,  0x10
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.d     vr21,  vr28,  0x10
+    vextrins.d     vr22,  vr28,  0x01
+    vextrins.d     vr22,  vr29,  0x10
+    vextrins.d     vr23,  vr29,  0x01  //alt[3][(y>>1)+x]
+
+    add.d          a0,    a0,    a1
+
+    // 6
+    fld.d          f24,   a0,    0  //img
+    vpermi.w       vr25,  vr24,  0x01
+
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+
+    vsub.w         vr24,  vr24,  vr31  //px
+    vsub.w         vr25,  vr25,  vr31
+
+    vbsrl.v        vr28,  vr5,   8
+    vbsrl.v        vr29,  vr6,   8
+    vextrins.d     vr28,  vr6,   0x10  //6-9
+    vextrins.d     vr29,  vr7,   0x10  //10-13
+    vadd.w         vr28,  vr28,  vr24  //diag[0][y+x]
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.d     vr5,   vr28,  0x10
+    vextrins.d     vr6,   vr28,  0x01
+    vextrins.d     vr6,   vr29,  0x10
+    vextrins.d     vr7,   vr29,  0x01
+
+    vbsrl.v        vr28,  vr13,  8
+    vextrins.d     vr28,  vr14,  0x10
+    vpackev.w      vr26,  vr25,  vr24
+    vpackod.w      vr27,  vr25,  vr24
+    vpermi.w       vr26,  vr26,  0xd8 //px0246
+    vpermi.w       vr27,  vr27,  0xd8 //px1357
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[0][y+(x>>1)]
+    vextrins.d     vr13,  vr28,  0x10
+    vextrins.d     vr14,  vr28,  0x01
+
+    vhaddw.d.w     vr28,  vr24,  vr24
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr25,  vr25
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr1,   a3,    2    //hv[0][y]
+
+    vbsrl.v        vr28,  vr16,  8
+    vextrins.d     vr28,  vr17,  0x10
+    vpermi.w       vr28,  vr28,  0x1b
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[1][3+y-(x>>1)]
+    vpermi.w       vr28,  vr28,  0x1b
+    vextrins.d     vr16,  vr28,  0x10
+    vextrins.d     vr17,  vr28,  0x01
+
+    vbsrl.v        vr28,  vr9,   8
+    vextrins.d     vr28,  vr10,  0x10
+    vbsrl.v        vr29,  vr10,  8
+    vextrins.d     vr29,  vr11,  0x10
+    vpermi.w       vr28,  vr28,  0x1b  //9876
+    vpermi.w       vr29,  vr29,  0x1b  //13-10
+    vadd.w         vr29,  vr29,  vr24
+    vadd.w         vr28,  vr28,  vr25
+    vpermi.w       vr28,  vr28,  0x1b
+    vpermi.w       vr29,  vr29,  0x1b
+    vextrins.d     vr9,   vr28,  0x10
+    vextrins.d     vr10,  vr28,  0x01
+    vextrins.d     vr10,  vr29,  0x10
+    vextrins.d     vr11,  vr29,  0x01  //diag[1][7+y-x]
+
+    vadd.w         vr18,  vr18,  vr24 //0123
+    vadd.w         vr19,  vr19,  vr25 //4567 alt[2][3-(y>>1)+7]
+
+    vadd.w         vr2,   vr2,   vr24
+    vadd.w         vr3,   vr3,   vr25  //hv[1][x]
+
+    vbsll.v        vr28,  vr22,  4
+    vextrins.w     vr28,  vr21,  0x03  //3456
+    vbsll.v        vr29,  vr23,  4
+    vextrins.w     vr29,  vr22,  0x03  //78910
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25  //alt[3][(y>>1)+x]
+    vextrins.w     vr21,  vr28,  0x30
+    vextrins.w     vr28,  vr29,  0x00
+    vshuf4i.w      vr22,  vr28,  0x39
+    vbsrl.v        vr23,  vr29,  4
+
+    add.d          a0,    a0,    a1
+
+    // 7
+    fld.d          f24,   a0,    0  //img
+    vpermi.w       vr25,  vr24,  0x01
+
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr24,  vr24,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+    vsllwil.hu.bu  vr25,  vr25,  0
+
+    vsub.w         vr24,  vr24,  vr31  //px
+    vsub.w         vr25,  vr25,  vr31
+
+    vbsll.v        vr28,  vr6,   4
+    vextrins.w     vr28,  vr5,   0x03 //78910
+    vbsll.v        vr29,  vr7,   4
+    vextrins.w     vr29,  vr6,   0x03 //11-14
+    vadd.w         vr28,  vr28,  vr24  //diag[0][y+x]
+    vadd.w         vr29,  vr29,  vr25
+    vextrins.w     vr5,   vr28,  0x30
+    vextrins.w     vr28,  vr29,  0x00
+    vshuf4i.w      vr6,   vr28,  0x39
+    vbsrl.v        vr7,   vr29,  4
+
+    vbsll.v        vr28,  vr14,  4
+    vextrins.w     vr28,  vr13,  0x03
+    vpackev.w      vr26,  vr25,  vr24
+    vpackod.w      vr27,  vr25,  vr24
+    vpermi.w       vr26,  vr26,  0xd8 //px0246
+    vpermi.w       vr27,  vr27,  0xd8 //px1357
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[0][y+(x>>1)]
+    vextrins.w     vr13,  vr28,  0x30
+    vbsrl.v        vr14,  vr28,  4
+
+    vhaddw.d.w     vr28,  vr24,  vr24
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr25,  vr25
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr1,   a3,    3    //hv[0][y]
+
+    vbsll.v        vr28,  vr17,  4
+    vextrins.w     vr28,  vr16,  0x03
+    vpermi.w       vr28,  vr28,  0x1b  //10987
+    vadd.w         vr28,  vr28,  vr26
+    vadd.w         vr28,  vr28,  vr27  //alt[1][3+y-(x>>1)]
+    vextrins.w     vr16,  vr28,  0x33
+    vshuf4i.w      vr17,  vr28,  0xc6
+    vinsgr2vr.w    vr17,  zero,  3
+
+    vbsll.v        vr28,  vr10,  4
+    vextrins.w     vr28,  vr9,   0x03  //7-10
+    vbsll.v        vr29,  vr11,  4
+    vextrins.w     vr29,  vr10,  0x03  //11-14
+    vpermi.w       vr28,  vr28,  0x1b  //10-7
+    vpermi.w       vr29,  vr29,  0x1b  //14-11
+    vadd.w         vr29,  vr29,  vr24
+    vadd.w         vr28,  vr28,  vr25  //diag[1][7+y-x]
+    vextrins.w     vr9,   vr28,  0x33
+    vextrins.w     vr28,  vr29,  0x33
+    vshuf4i.w      vr10,  vr28,  0xc6
+    vshuf4i.w      vr11,  vr29,  0xc6
+    vinsgr2vr.w    vr11,  zero,  3
+
+    vadd.w         vr18,  vr18,  vr24 //0123
+    vadd.w         vr19,  vr19,  vr25 //4567 alt[2][3-(y>>1)+7]
+
+    vadd.w         vr2,   vr2,   vr24
+    vadd.w         vr3,   vr3,   vr25  //hv[1][x]
+
+    vbsll.v        vr28,  vr22,  4
+    vextrins.w     vr28,  vr21,  0x03  //3456
+    vbsll.v        vr29,  vr23,  4
+    vextrins.w     vr29,  vr22,  0x03  //78910
+    vadd.w         vr28,  vr28,  vr24
+    vadd.w         vr29,  vr29,  vr25  //alt[3][(y>>1)+x]
+    vextrins.w     vr21,  vr28,  0x30
+    vextrins.w     vr28,  vr29,  0x00
+    vshuf4i.w      vr22,  vr28,  0x39
+    vbsrl.v        vr23,  vr29,  4
+
+    add.d          a0,    a0,    a1
+
+    vxor.v         vr24,  vr24,  vr24  //unsigned cost[8]
+    vxor.v         vr25,  vr25,  vr25
+
+    vmul.w         vr26,  vr0,   vr0
+    vmul.w         vr27,  vr1,   vr1
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vhaddw.d.w     vr28,  vr27,  vr27
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+
+    vmul.w         vr26,  vr2,   vr2
+    vmul.w         vr27,  vr3,   vr3
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    vhaddw.d.w     vr28,  vr27,  vr27
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a5,    vr28,  0
+    add.d          a4,    a4,    a5
+
+    li.d           a6,    105
+    mul.w          a3,    a3,    a6
+    mul.w          a4,    a4,    a6
+    vinsgr2vr.w    vr24,  a3,    2
+    vinsgr2vr.w    vr25,  a4,    2
+
+    vxor.v         vr30,  vr30,  vr30  //div_table
+    vxor.v         vr31,  vr31,  vr31
+    li.d           t0,    840
+    vinsgr2vr.w    vr30,  t0,    0
+    li.d           t0,    420
+    vinsgr2vr.w    vr30,  t0,    1
+    li.d           t0,    280
+    vinsgr2vr.w    vr30,  t0,    2
+    li.d           t0,    210
+    vinsgr2vr.w    vr30,  t0,    3
+    li.d           t0,    168
+    vinsgr2vr.w    vr31,  t0,    0
+    li.d           t0,    140
+    vinsgr2vr.w    vr31,  t0,    1
+    li.d           t0,    120
+    vinsgr2vr.w    vr31,  t0,    2
+
+    vbsll.v        vr27,  vr7,   4
+    vextrins.w     vr27,  vr6,   0x03
+    vpermi.w       vr27,  vr27,  0x1b
+    vmul.w         vr26,  vr4,   vr4
+    vmadd.w        vr26,  vr27,  vr27
+    vmul.w         vr26,  vr26,  vr30
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a3,    vr28,  0
+    vbsll.v        vr27,  vr6,   4
+    vpermi.w       vr27,  vr27,  0x1b
+    vmul.w         vr26,  vr5,   vr5
+    vmadd.w        vr26,  vr27,  vr27
+    vmul.w         vr26,  vr26,  vr31
+    vextrins.w     vr26,  vr31,  0x33
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4   //cost[0]
+
+    vbsll.v        vr27,  vr11,  4
+    vextrins.w     vr27,  vr10,  0x03
+    vpermi.w       vr27,  vr27,  0x1b
+    vmul.w         vr26,  vr8,   vr8
+    vmadd.w        vr26,  vr27,  vr27
+    vmul.w         vr26,  vr26,  vr30
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    vbsll.v        vr27,  vr10,  4
+    vpermi.w       vr27,  vr27,  0x1b
+    vmul.w         vr26,  vr9,   vr9
+    vmadd.w        vr26,  vr27,  vr27
+    vmul.w         vr26,  vr26,  vr31
+    vextrins.w     vr26,  vr31,  0x33
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a5,    vr28,  0
+    add.d          a4,    a4,    a5   //cost[4]
+
+    vpickve2gr.w   a5,    vr5,   3
+    mul.w          a5,    a5,    a5
+    mul.w          a5,    a5,    a6
+    add.w          a3,    a3,    a5
+    vinsgr2vr.w    vr24,  a3,    0
+    vpickve2gr.w   a5,    vr9,   3
+    mul.w          a5,    a5,    a5
+    mul.w          a5,    a5,    a6
+    add.w          a4,    a4,    a5
+    vinsgr2vr.w    vr25,  a4,    0
+
+    //n=0
+    vpickve2gr.w   a3,    vr24,  1
+    vmul.w         vr26,  vr13,  vr13
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    vpickve2gr.w   a5,    vr12,  3
+    mul.w          a5,    a5,    a5
+    add.d          a3,    a3,    a4
+    add.d          a3,    a3,    a5
+    mul.w          a3,    a3,    a6  //*cost_ptr
+
+    vextrins.w     vr29,  vr30,  0x01
+    vextrins.w     vr29,  vr30,  0x13
+    vextrins.w     vr29,  vr31,  0x21
+    vextrins.w     vr29,  vr31,  0x33
+    vbsll.v        vr27,  vr14,  4
+    vpermi.w       vr27,  vr27,  0x1b
+    vmul.w         vr28,  vr12,  vr12
+    vextrins.w     vr28,  vr31,  0x33
+    vmadd.w        vr28,  vr27,  vr27
+    vmul.w         vr26,  vr28,  vr29
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr24,  a3,    1
+
+    //n=1
+    vpickve2gr.w   a3,    vr24,  3
+    vmul.w         vr26,  vr16,  vr16
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    vpickve2gr.w   a5,    vr15,  3
+    mul.w          a5,    a5,    a5
+    add.d          a3,    a3,    a4
+    add.d          a3,    a3,    a5
+    mul.w          a3,    a3,    a6  //*cost_ptr
+
+    vbsll.v        vr27,  vr17,  4
+    vpermi.w       vr27,  vr27,  0x1b
+    vmul.w         vr28,  vr15,  vr15
+    vextrins.w     vr28,  vr31,  0x33
+    vmadd.w        vr28,  vr27,  vr27
+    vmul.w         vr26,  vr28,  vr29
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr24,  a3,    3
+
+    //n=2
+    vpickve2gr.w   a3,    vr25,  1
+    vmul.w         vr26,  vr19,  vr19
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    vpickve2gr.w   a5,    vr18,  3
+    mul.w          a5,    a5,    a5
+    add.d          a3,    a3,    a4
+    add.d          a3,    a3,    a5
+    mul.w          a3,    a3,    a6  //*cost_ptr
+
+    vbsll.v        vr27,  vr20,  4
+    vpermi.w       vr27,  vr27,  0x1b
+    vmul.w         vr28,  vr18,  vr18
+    vextrins.w     vr28,  vr31,  0x33
+    vmadd.w        vr28,  vr27,  vr27
+    vmul.w         vr26,  vr28,  vr29
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr25,  a3,    1
+
+    //n=3
+    vpickve2gr.w   a3,    vr25,  3
+    vmul.w         vr26,  vr22,  vr22
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    vpickve2gr.w   a5,    vr21,  3
+    mul.w          a5,    a5,    a5
+    add.d          a3,    a3,    a4
+    add.d          a3,    a3,    a5
+    mul.w          a3,    a3,    a6  //*cost_ptr
+
+    vbsll.v        vr27,  vr23,  4
+    vpermi.w       vr27,  vr27,  0x1b
+    vmul.w         vr28,  vr21,  vr21
+    vextrins.w     vr28,  vr31,  0x33
+    vmadd.w        vr28,  vr27,  vr27
+    vmul.w         vr26,  vr28,  vr29
+    vhaddw.d.w     vr28,  vr26,  vr26
+    vhaddw.q.d     vr28,  vr28,  vr28
+    vpickve2gr.d   a4,    vr28,  0
+    add.d          a3,    a3,    a4
+    vinsgr2vr.w    vr25,  a3,    3
+
+    xor            a3,    a3,    a3  //best_dir
+    vpickve2gr.w   a4,    vr24,  0   //best_cost
+.BSETDIR01:
+    vpickve2gr.w   a5,    vr24,  1
+    bge            a4,    a5,    .BSETDIR02
+    or             a4,    a5,    a5
+    ori            a3,    zero,  1
+.BSETDIR02:
+    vpickve2gr.w   a5,    vr24,  2
+    bge            a4,    a5,    .BSETDIR03
+    or             a4,    a5,    a5
+    ori            a3,    zero,  2
+.BSETDIR03:
+    vpickve2gr.w   a5,    vr24,  3
+    bge            a4,    a5,    .BSETDIR04
+    or             a4,    a5,    a5
+    ori            a3,    zero,  3
+.BSETDIR04:
+    vpickve2gr.w   a5,    vr25,  0
+    bge            a4,    a5,    .BSETDIR05
+    or             a4,    a5,    a5
+    ori            a3,    zero,  4
+.BSETDIR05:
+    vpickve2gr.w   a5,    vr25,  1
+    bge            a4,    a5,    .BSETDIR06
+    or             a4,    a5,    a5
+    ori            a3,    zero,  5
+.BSETDIR06:
+    vpickve2gr.w   a5,    vr25,  2
+    bge            a4,    a5,    .BSETDIR07
+    or             a4,    a5,    a5
+    ori            a3,    zero,  6
+.BSETDIR07:
+    vpickve2gr.w   a5,    vr25,  3
+    bge            a4,    a5,    .BSETDIREND
+    or             a4,    a5,    a5
+    ori            a3,    zero,  7
+.BSETDIREND:
+    xori           a5,    a3,    4
+    li.d           a1,    4
+    bge            a5,    a1,    .GETCOST01
+    vreplve.w      vr26,  vr24,  a5
+    b              .GETCOST02
+.GETCOST01:
+    vreplve.w      vr26,  vr25,  a5
+.GETCOST02:
+    vpickve2gr.w   a5,    vr26,  0
+    sub.w          a5,    a4,    a5
+    srai.d         a5,    a5,    10
+    st.w           a5,    a2,    0
+    or             a0,    a3,    a3
+
+    fld.d          f24,   sp,    0
+    fld.d          f25,   sp,    8
+    fld.d          f26,   sp,    16
+    fld.d          f27,   sp,    24
+    fld.d          f28,   sp,    32
+    fld.d          f29,   sp,    40
+    fld.d          f30,   sp,    48
+    fld.d          f31,   sp,    56
+    addi.d         sp,    sp,    64
+
+endfunc
+
+.macro cdef_fill tmp, stride, w, h
+    beqz          \h,     700f         //h
+    or            t0,     zero,  zero  //y
+100:
+    or            t1,     zero,  zero  //xx
+    srai.d        s6,     \w,    3     //x
+    beqz          s6,     300f
+200:
+    vstx          vr18,   \tmp,    t1
+    addi.d        t1,     t1,    16
+    addi.d        s6,     s6,    -1
+    bnez          s6,     200b
+300:
+    andi          s6,     \w,    4
+    beqz          s6,     400f
+    fstx.d        f18,    \tmp,    t1
+    addi.d        t1,     t1,    8
+400:
+    andi          s6,     \w,    2
+    beqz          s6,     500f
+    fstx.s        f18,    \tmp,    t1
+    addi.d        t1,     t1,    4
+500:
+    andi          s6,     \w,    1
+    beqz          s6,     600f
+    li.w          s6,     -16384
+    stx.h         s6,     \tmp,    t1
+    addi.d        t1,     t1,    2
+600:
+    add.d         \tmp,     \tmp,    \stride
+    add.d         \tmp,     \tmp,    \stride
+    addi.d        t0,     t0,    1
+    blt           t0,     \h,    100b
+700:
+.endm
+
+const dav1d_cdef_directions
+.byte   1 * 12 + 0,  2 * 12 + 0
+.byte   1 * 12 + 0,  2 * 12 - 1
+.byte   -1 * 12 + 1, -2 * 12 + 2
+.byte   0 * 12 + 1, -1 * 12 + 2
+.byte   0 * 12 + 1,  0 * 12 + 2
+.byte   0 * 12 + 1,  1 * 12 + 2
+.byte   1 * 12 + 1,  2 * 12 + 2
+.byte   1 * 12 + 0,  2 * 12 + 1
+.byte   1 * 12 + 0,  2 * 12 + 0
+.byte   1 * 12 + 0,  2 * 12 - 1
+.byte   -1 * 12 + 1, -2 * 12 + 2
+.byte   0 * 12 + 1, -1 * 12 + 2
+endconst
+
+.macro constrain_vrh in0, in1, in2, tmp0, tmp1, out
+    vabsd.h        \tmp0, \in0,  vr23   //adiff
+    vsra.h         \tmp1, \tmp0, \in2
+    vsub.h         \tmp1, \in1,  \tmp1
+    vmax.h         \tmp1, vr23,  \tmp1  //imax
+    vmin.h         \tmp0, \tmp0, \tmp1  //imin
+
+    //apply_sign
+    vslt.h         \tmp1, \in0,  vr23
+    vandn.v        \in0,  \tmp1, \tmp0
+    vsigncov.h     \tmp0, \tmp1, \tmp0
+    vor.v          \out,  \in0,  \tmp0
+.endm
+
+.macro iclip_vrh in0, in1, in2, tmp0, tmp1, out
+    vmin.h         \tmp0, \in2,  \in0
+    vslt.h         \in0,  \in0,  \in1
+    vand.v         \tmp1, \in0,  \in1
+    vandn.v        \tmp0, \in0,  \tmp0
+    vor.v          \out,  \tmp1, \tmp0
+.endm
+
+.macro cdef_padding_data
+    //y < 0
+    beqz          t7,     90f
+4:
+    or            t4,     t5,    t5  //data index xx
+    slli.d        t0,     t4,    1
+    mul.w         t2,     t7,    s5
+    slli.d        t2,     t2,    1
+    add.d         t2,     s4,    t2
+
+    sub.d         t3,     t6,    t5  //loop param x
+    srai.d        t3,     t3,    3
+    add.d         t3,     t3,    t5
+    beq           t5,     t3,    6f
+5:  // /8
+    fldx.d        f18,    a3,    t4
+    vsllwil.hu.bu vr18,   vr18,  0
+    vstx          vr18,   t2,    t0
+    addi.d        t0,     t0,    16
+    addi.d        t4,     t4,    8
+
+    addi.d        t3,     t3,    -1
+    bne           t5,     t3,    5b
+6:  // &4
+    sub.d         t1,     t6,    t5
+    andi          t1,     t1,    4
+    beqz          t1,     7f
+
+    fldx.s        f18,    a3,    t4
+    vsllwil.hu.bu vr18,   vr18,  0
+    fstx.d        f18,    t2,    t0
+    addi.d        t0,     t0,    8
+    addi.d        t4,     t4,    4
+7:  // &2
+    sub.d         t1,     t6,    t5
+    andi          t1,     t1,    2
+    beqz          t1,     9f
+
+    ldx.bu        t1,     a3,    t4
+    stx.h         t1,     t2,    t0
+    addi.d        t0,     t0,    2
+    addi.d        t4,     t4,    1
+    ldx.bu        t1,     a3,    t4
+    stx.h         t1,     t2,    t0
+    addi.d        t0,     t0,    2
+    addi.d        t4,     t4,    1
+9:
+    add.d         a3,     a3,    a1
+    addi.d        t7,     t7,    1
+    bnez          t7,     4b
+
+90:
+    // y < h
+    beqz          s1,     12f
+    beqz          t5,     12f
+    or            t7,     zero,  zero  //y
+10:
+    or            t4,     t5,    t5  //data index x
+11:
+    slli.d        t3,     t7,    1
+    addi.d        t3,     t3,    2
+    add.d         t3,     t3,    t4
+    ldx.bu        t1,     a2,    t3
+
+    mul.w         t3,     t7,    s5
+    add.d         t3,     t3,    t4
+    slli.d        t3,     t3,    1
+    stx.h         t1,     s4,    t3
+
+    addi.d        t4,     t4,    1
+    bnez          t4,     11b
+
+    addi.d        t7,     t7,    1
+    bne           t7,     s1,    10b
+
+12:
+    // y = 0 ; y < h
+    or            s0,     s4,    s4
+    beqz          s1,     20f
+    or            s6,     a0,    a0
+    or            t7,     zero,  zero  //y
+    srai.d        t4,     t6,    3    //loop max
+13:
+    or            t0,     zero,  zero //loop param
+    or            t3,     t0,    t0   //data index src
+    or            t1,     t0,    t0   //data index tmp
+    beqz          t4,     16f
+15:  // /8
+    fldx.d        f18,    s6,    t3
+    vsllwil.hu.bu vr18,   vr18,  0
+    vstx          vr18,   s0,    t1
+    addi.d        t3,     t3,    8
+    addi.d        t1,     t1,    16
+
+    addi.d        t0,     t0,    1
+    blt           t0,     t4,    15b
+16:  // &4
+    andi          t0,     t6,    4
+    beqz          t0,     17f
+
+    fldx.s        f18,    s6,    t3
+    vsllwil.hu.bu vr18,   vr18,  0
+    fstx.d        f18,    s0,    t1
+    addi.d        t3,     t3,    4
+    addi.d        t1,     t1,    8
+17:  // &2
+    andi          t0,     t6,    2
+    beqz          t0,     19f
+
+    ldx.bu        t2,     s6,    t3
+    stx.h         t2,     s0,    t1
+    addi.d        t3,     t3,    1
+    addi.d        t1,     t1,    2
+    ldx.bu        t2,     s6,    t3
+    stx.h         t2,     s0,    t1
+    addi.d        t3,     t3,    1
+    addi.d        t1,     t1,    2
+19: // src+ tmp+
+    add.d         s6,     s6,    a1
+    add.d         s0,     s0,    s5
+    add.d         s0,     s0,    s5
+
+    addi.d        t7,     t7,    1
+    blt           t7,     s1,    13b
+
+    // y = h ; y < y_end
+20:
+    beq           s1,     t8,    27f
+    or            t7,     s1,    s1  //y
+    sub.d         t4,     t6,    t5
+    srai.d        t4,     t4,    3
+    add.d         t4,     t4,    t5   //8 loop max
+21:
+    or            t0,     t5,    t5   //xx
+    or            t3,     t0,    t0   //data index bottom
+    slli.d        t1,     t0,    1    //data index tmp
+    beq           t5,     t4,    23f
+22:  // /8
+    fldx.d        f18,    a4,    t3
+    vsllwil.hu.bu vr18,   vr18,  0
+    vstx          vr18,   s0,    t1
+    addi.d        t3,     t3,    8
+    addi.d        t1,     t1,    16
+
+    addi.d        t0,     t0,    1
+    blt           t0,     t4,    22b
+23:  // &4
+    sub.d         t0,     t6,    t5
+    andi          t0,     t0,    4
+    beqz          t0,     24f
+
+    fldx.s        f18,    a4,    t3
+    vsllwil.hu.bu vr18,   vr18,  0
+    fstx.d        f18,    s0,    t1
+    addi.d        t3,     t3,    4
+    addi.d        t1,     t1,    8
+24:  // &2
+    sub.d         t0,     t6,    t5
+    andi          t0,     t0,    2
+    beqz          t0,     26f
+
+    ldx.bu        t2,     a4,    t3
+    stx.h         t2,     s0,    t1
+    addi.d        t3,     t3,    1
+    addi.d        t1,     t1,    2
+    ldx.bu        t2,     a4,    t3
+    stx.h         t2,     s0,    t1
+    addi.d        t3,     t3,    1
+    addi.d        t1,     t1,    2
+26: // bottom+ tmp+
+    add.d         a4,     a4,    a1
+    add.d         s0,     s0,    s5
+    add.d         s0,     s0,    s5
+
+    addi.d        t7,     t7,    1
+    blt           t7,     t8,    21b
+27:
+    // padding end
+.endm
+
+.macro cdef_pri_sec_init
+    clz.w          t3,    a6
+    sub.w          t3,    t2,    t3
+    sub.w          t3,    s7,    t3  //sec_shift
+
+    vreplgr2vr.h   vr4,   t0         //pri_tap_k
+    vreplgr2vr.h   vr9,   a5         //pri_strength
+    vreplgr2vr.h   vr10,  t1         //pri_shift
+    vreplgr2vr.h   vr18,  a6         //sec_strength
+    vreplgr2vr.h   vr19,  t3         //sec_shift
+
+    or             t2,    s1,    s1  //dowhile loop param
+    addi.d         s1,    a7,    2
+    slli.d         s1,    s1,    1   //directions dir+2
+    addi.d         s2,    a7,    4
+    slli.d         s2,    s2,    1   //directions dir+4
+    slli.d         s3,    a7,    1   //directions dir+0
+
+    la.local       t0,    dav1d_cdef_directions
+    add.d          s1,    t0,    s1
+    ld.b           a2,    s1,    0  //off01
+    ld.b           a3,    s1,    1  //off11
+    add.d          s2,    t0,    s2
+    ld.b           s1,    s2,    0  //off02
+    ld.b           s2,    s2,    1  //off12
+    add.d          s3,    t0,    s3
+    ld.b           t0,    s3,    0  //off03
+    ld.b           s3,    s3,    1  //off13
+
+    slli.d         a2,    a2,    1
+    slli.d         a3,    a3,    1
+    slli.d         s1,    s1,    1
+    slli.d         s2,    s2,    1
+    slli.d         t0,    t0,    1
+    slli.d         s3,    s3,    1
+.endm
+
+.macro cdef_pri_init
+    vreplgr2vr.h   vr4,   t0         //pri_tap_k
+    vreplgr2vr.h   vr9,   a5         //pri_strength
+    vreplgr2vr.h   vr10,  t1         //pri_shift
+
+    or             t2,    s1,    s1  //dowhile loop param
+    addi.d         s1,    a7,    2
+    slli.d         s1,    s1,    1   //directions dir+2
+
+    la.local       t0,    dav1d_cdef_directions
+    add.d          s1,    t0,    s1
+    ld.b           a2,    s1,    0  //off01
+    ld.b           a3,    s1,    1  //off11
+
+    slli.d         a2,    a2,    1
+    slli.d         a3,    a3,    1
+.endm
+
+.macro cdef_sec_init
+    clz.w          t3,    a6
+    li.w           t2,    31
+    sub.w          t3,    t2,    t3
+    sub.w          t3,    s7,    t3  //sec_shift
+
+    vreplgr2vr.h   vr18,  a6         //sec_strength
+    vreplgr2vr.h   vr19,  t3         //sec_shift
+
+    or             t2,    s1,    s1  //dowhile loop param
+    addi.d         s2,    a7,    4
+    slli.d         s2,    s2,    1   //directions dir+4
+    slli.d         s3,    a7,    1   //directions dir+0
+
+    la.local       t0,    dav1d_cdef_directions
+    add.d          s1,    t0,    s1
+    add.d          s2,    t0,    s2
+    ld.b           s1,    s2,    0  //off02
+    ld.b           s2,    s2,    1  //off12
+    add.d          s3,    t0,    s3
+    ld.b           t0,    s3,    0  //off03
+    ld.b           s3,    s3,    1  //off13
+
+    slli.d         s1,    s1,    1
+    slli.d         s2,    s2,    1
+    slli.d         t0,    t0,    1
+    slli.d         s3,    s3,    1
+.endm
+
+.macro cdef_process_data_w8 in0, in1
+    vsub.h       vr11,   vr5,   vr0
+    vsub.h       vr12,   vr6,   vr0
+    vsub.h       vr13,   vr7,   vr0
+    vsub.h       vr14,   vr8,   vr0
+
+    constrain_vrh   vr11,  \in0,   \in1,  vr16,  vr17,  vr11
+    constrain_vrh   vr12,  \in0,   \in1,  vr16,  vr17,  vr12
+    constrain_vrh   vr13,  \in0,   \in1,  vr16,  vr17,  vr13
+    constrain_vrh   vr14,  \in0,   \in1,  vr16,  vr17,  vr14
+.endm
+
+.macro cdef_process_data_w4 in0, in1
+    vpermi.w       vr6,  vr5,  0x44
+    vpermi.w       vr8,  vr7,  0x44
+
+    vsub.h         vr12,  vr6,   vr0
+    vsub.h         vr14,  vr8,   vr0
+
+    constrain_vrh   vr12,  \in0,   \in1,  vr16,  vr17,  vr12
+    constrain_vrh   vr14,  \in0,   \in1,  vr16,  vr17,  vr14
+.endm
+
+.macro cdef_calc_sum_tapchange_w8
+    vmul.h         vr1,   vr15,  vr11  //sum
+    vmadd.h        vr1,   vr15,  vr12  //sum
+    vand.v         vr15,  vr15,  vr21
+    vor.v          vr15,  vr15,  vr22
+    vmadd.h        vr1,   vr15,  vr13  //sum
+    vmadd.h        vr1,   vr15,  vr14  //sum
+.endm
+
+.macro cdef_calc_sum_tapchange_w4
+    vmul.h         vr1,   vr15,  vr12  //sum
+    vand.v         vr15,  vr15,  vr21
+    vor.v          vr15,  vr15,  vr22
+    vmadd.h        vr1,   vr15,  vr14  //sum
+.endm
+
+.macro cdef_calc_sum_no_tapchange_w4 in0
+    vmadd.h        vr1,   \in0,  vr12
+    vmadd.h        vr1,   \in0,  vr14
+.endm
+
+.macro cdef_calc_sum_no_tapchange_w8 in0
+    vmadd.h        vr1,   \in0,  vr11  //sum
+    vmadd.h        vr1,   \in0,  vr12
+    vmadd.h        vr1,   \in0,  vr13
+    vmadd.h        vr1,   \in0,  vr14
+.endm
+
+.macro cdef_calc_maxmin_w4
+    vmin.hu        vr3,   vr6,   vr3
+    vmax.h         vr2,   vr6,   vr2
+    vmin.hu        vr3,   vr8,   vr3  //min
+    vmax.h         vr2,   vr8,   vr2  //max
+.endm
+
+.macro cdef_calc_maxmin_w8
+    vmin.hu        vr3,   vr5,   vr3
+    vmax.h         vr2,   vr5,   vr2
+    vmin.hu        vr3,   vr6,   vr3
+    vmax.h         vr2,   vr6,   vr2
+    vmin.hu        vr3,   vr7,   vr3
+    vmax.h         vr2,   vr7,   vr2
+    vmin.hu        vr3,   vr8,   vr3  //min
+    vmax.h         vr2,   vr8,   vr2  //max
+.endm
+
+.macro cdef_calc_dst
+    vslti.h        vr5,   vr1,   0
+    vand.v         vr5,   vr5,   vr20
+    vsub.h         vr5,   vr1,   vr5
+    vaddi.hu       vr5,   vr5,   8
+    vsrai.h        vr5,   vr5,   4
+    vadd.h         vr5,   vr0,   vr5
+.endm
+
+//static NOINLINE void cdef_filter_block_lsx
+//                    (pixel *dst, const ptrdiff_t dst_stride,
+//                     const pixel (*left)[2], const pixel *const top,
+//                     const int pri_strength, const int sec_strength,
+//                     const int dir, const int damping, const int w, int h,
+//                     const enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX)
+// w=4 h=4
+//param: dst:a0, dst_stride:a1, left:a2, top:a3, bottom:a4, pri_strength:a5
+//sec_strength:a6, dir:a7, damping:s7, w:s0, h:s1, edges:s2
+function cdef_filter_block_4x4_8bpc_lsx
+    ld.w           t0,    sp,    0
+    ld.w           t1,    sp,    8
+    addi.d         sp,    sp,    -(64+288)
+    st.d           s0,    sp,    0
+    st.d           s1,    sp,    8
+    st.d           s2,    sp,    16
+    st.d           s3,    sp,    24
+    st.d           s4,    sp,    32
+    st.d           s5,    sp,    40
+    st.d           s6,    sp,    48
+    st.d           s7,    sp,    56
+
+    li.w           s0,    4         //w
+    li.w           s1,    4         //h
+    or             s2,    t1,    t1 //edges
+    or             s7,    t0,    t0 //damping
+
+    li.d           s5,    12         //tmp_stride
+    addi.d         s4,    sp,    64
+    slli.d         t0,    s5,    1
+    addi.d         t0,    t0,    2
+    slli.d         t0,    t0,    1
+    add.d          s4,    s4,    t0  //ptr tmp
+    vxor.v         vr23,  vr23,  vr23
+    li.w           t2,    1
+    vreplgr2vr.h   vr20,  t2
+    vaddi.hu       vr21,  vr20,  2
+    vaddi.hu       vr22,  vr20,  1
+
+    li.w          t0,     -16384
+    vreplgr2vr.h  vr18,   t0
+
+    //padding
+    li.w          t5,     -2        //x_start
+    addi.d        t6,     s0,    2  //x_end
+    li.w          t7,     -2        //y_start
+    addi.d        t8,     s1,    2  //y_end
+    li.w          t2,     2
+
+    andi          t4,     s2,    4
+    bnez          t4,     1f
+
+    //CDEF_HAVE_TOP
+    slli.d        t3,     s5,    2
+    addi.d        t4,     s4,    -4
+    sub.d         t4,     t4,    t3
+    addi.d        t3,     s0,    4
+
+    cdef_fill     t4,     s5,    t3,     t2
+
+    or            t7,     zero,  zero
+
+1:  //CDEF_HAVE_BOTTOM
+    andi          t4,     s2,8
+    bnez          t4,     2f
+
+    mul.w         t3,     s1,    s5
+    slli.d        t3,     t3,  1
+    add.d         t4,     s4,  t3
+    addi.d        t4,     t4,    -4
+    li.d          t3,     8
+
+    cdef_fill     t4,     s5,    t3,     t2
+
+    addi.d        t8,     t8,    -2
+
+2:  //CDEF_HAVE_LEFT
+    andi          t4,     s2,1
+    bnez          t4,     3f
+
+    mul.w         t3,     t7,    s5
+    slli.d        t3,     t3,    1
+    add.d         t4,     s4,    t3
+    addi.d        t4,     t4,    -4
+    sub.d         t3,     t8,    t7
+
+    cdef_fill     t4,     s5,    t2,     t3
+
+    or            t5,     zero,  zero
+
+3:  //CDEF_HAVE_RIGHT
+    andi          t4,     s2,2
+    bnez          t4,     40f
+
+    mul.w         t3,     t7,    s5
+    slli.d        t3,     t3,    1
+    add.d         t4,     s4,    t3
+    addi.d        t4,     t4,    8
+    sub.d         t3,     t8,    t7
+
+    cdef_fill     t4,     s5,    t2,     t3
+
+    addi.d        t6,     t6,    -2
+
+40:
+    cdef_padding_data
+
+    beqz           a5,    33f
+
+28:  //if (pri_strength)
+    li.w           t0,    4
+    andi           t1,    a5,    1
+    sub.d          t0,    t0,    t1  //pri_tap
+
+    clz.w          t1,    a5
+    li.d           t2,    31
+    sub.w          t1,    t2,    t1
+    sub.w          t1,    s7,    t1
+
+    blt            t1,    zero,  281f
+    or             t1,    t1,    t1
+    b              282f
+281:
+    or             t1,    zero,  zero   //t1: pri_shift
+282:
+
+    beqz           a6,    31f
+
+29:  //if (sec_strength)
+    cdef_pri_sec_init
+
+30:
+    fld.s          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+    vpermi.w       vr0,   vr0,   0x44
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+    vor.v          vr2,   vr0,   vr0   //max
+    vor.v          vr3,   vr0,   vr0   //min
+    vor.v          vr15,  vr4,   vr4   //pri_tap_k
+
+    sub.d          t4,    s4,    a2
+    sub.d          t5,    s4,    a3
+
+    fldx.d         f5,    s4,    a2   //p0_00
+    fld.d          f6,    t4,    0    //p0_01
+    fldx.d         f7,    s4,    a3   //p0_10
+    fld.d          f8,    t5,    0    //p0_11
+
+    cdef_process_data_w4 vr9,   vr10
+    cdef_calc_sum_tapchange_w4
+    cdef_calc_maxmin_w4
+
+    sub.d          t4,    s4,    s1  //tmp[-off02]
+    sub.d          t5,    s4,    t0  //tmp[-off03]
+
+    fldx.d         f5,    s4,    s1   //s0_00
+    fld.d          f6,    t4,    0    //s0_01
+    fldx.d         f7,    s4,    t0   //s0_02
+    fld.d          f8,    t5,    0    //s0_03
+
+    cdef_process_data_w4 vr18, vr19
+    cdef_calc_sum_no_tapchange_w4 vr22
+    cdef_calc_maxmin_w4
+
+    sub.d          t4,    s4,    s2  //tmp[-off12]
+    sub.d          t5,    s4,    s3  //tmp[-off13]
+
+    fldx.d         f5,    s4,    s2   //s0_10
+    fld.d          f6,    t4,    0    //s0_11
+    fldx.d         f7,    s4,    s3   //s0_12
+    fld.d          f8,    t5,    0    //s0_13
+
+    cdef_process_data_w4 vr18, vr19
+    cdef_calc_sum_no_tapchange_w4 vr20
+    cdef_calc_maxmin_w4
+
+    vshuf4i.w      vr5,   vr1,   0x0e
+    vshuf4i.w      vr6,   vr3,   0x0e
+    vshuf4i.w      vr7,   vr2,   0x0e
+    vadd.h         vr1,   vr1,   vr5
+    vmin.hu        vr3,   vr6,   vr3
+    vmax.h         vr2,   vr7,   vr2
+
+    cdef_calc_dst
+    iclip_vrh       vr5,   vr3,   vr2,  vr16,  vr17,  vr5
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.s          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    30b
+    b              35f
+
+31:  // pri_strength only
+    cdef_pri_init
+
+32:
+    fld.s          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+    vpermi.w       vr0,   vr0,   0x44
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+    vor.v          vr15,  vr4,   vr4   //pri_tap_k
+
+    sub.d          t4,    s4,    a2
+    sub.d          t5,    s4,    a3
+
+    fldx.d         f5,    s4,    a2   //p0_00
+    fld.d          f6,    t4,    0    //p0_01
+    fldx.d         f7,    s4,    a3   //p0_10
+    fld.d          f8,    t5,    0    //p0_11
+
+    cdef_process_data_w4 vr9,   vr10
+    cdef_calc_sum_tapchange_w4
+
+    vshuf4i.w      vr5,   vr1,   0x0e
+    vadd.h         vr1,   vr1,   vr5
+
+    cdef_calc_dst
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.s          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    32b
+    b              35f
+
+33:   // sec_strength only
+    cdef_sec_init
+
+34:
+    fld.s          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+    vpermi.w       vr0,   vr0,   0x44
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+
+    sub.d          t4,    s4,    s1  //tmp[-off02]
+    sub.d          t5,    s4,    t0  //tmp[-off03]
+
+    fldx.d         f5,    s4,    s1   //s0_00
+    fld.d          f6,    t4,    0    //s0_01
+    fldx.d         f7,    s4,    t0   //s0_02
+    fld.d          f8,    t5,    0    //s0_03
+
+    cdef_process_data_w4 vr18, vr19
+    cdef_calc_sum_no_tapchange_w4 vr22
+
+    sub.d          t4,    s4,    s2  //tmp[-off12]
+    sub.d          t5,    s4,    s3  //tmp[-off13]
+
+    fldx.d         f5,    s4,    s2   //s0_10
+    fld.d          f6,    t4,    0    //s0_11
+    fldx.d         f7,    s4,    s3   //s0_12
+    fld.d          f8,    t5,    0    //s0_13
+
+    cdef_process_data_w4 vr18, vr19
+    cdef_calc_sum_no_tapchange_w4 vr20
+
+    vshuf4i.w      vr5,   vr1,   0x0e
+    vadd.h         vr1,   vr1,   vr5
+
+    cdef_calc_dst
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.s          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    34b
+
+35:
+    ld.d           s0,    sp,    0
+    ld.d           s1,    sp,    8
+    ld.d           s2,    sp,    16
+    ld.d           s3,    sp,    24
+    ld.d           s4,    sp,    32
+    ld.d           s5,    sp,    40
+    ld.d           s6,    sp,    48
+    ld.d           s7,    sp,    56
+    addi.d         sp,    sp,    (64+288)
+endfunc
+
+function cdef_filter_block_4x8_8bpc_lsx
+    ld.w           t0,    sp,    0
+    ld.w           t1,    sp,    8
+    addi.d         sp,    sp,    -(64+288)
+    st.d           s0,    sp,    0
+    st.d           s1,    sp,    8
+    st.d           s2,    sp,    16
+    st.d           s3,    sp,    24
+    st.d           s4,    sp,    32
+    st.d           s5,    sp,    40
+    st.d           s6,    sp,    48
+    st.d           s7,    sp,    56
+
+    li.w           s0,    4         //w
+    li.w           s1,    8         //h
+    or             s2,    t1,    t1 //edges
+    or             s7,    t0,    t0 //damping
+
+    li.d           s5,    12         //tmp_stride
+    addi.d         s4,    sp,    64
+    slli.d         t0,    s5,    1
+    addi.d         t0,    t0,    2
+    slli.d         t0,    t0,    1
+    add.d          s4,    s4,    t0  //ptr tmp
+    vxor.v         vr23,  vr23,  vr23
+    li.w           t2,    1
+    vreplgr2vr.h   vr20,  t2
+    vaddi.hu       vr21,  vr20,  2
+    vaddi.hu       vr22,  vr20,  1
+
+    li.w          t0,     -16384
+    vreplgr2vr.h  vr18,   t0
+
+    //padding
+    li.w          t5,     -2        //x_start
+    addi.d        t6,     s0,    2  //x_end
+    li.w          t7,     -2        //y_start
+    addi.d        t8,     s1,    2  //y_end
+    li.w          t2,     2
+
+    andi          t4,     s2,    4
+    bnez          t4,     1f
+
+    //CDEF_HAVE_TOP
+    slli.d        t3,     s5,    2
+    addi.d        t4,     s4,    -4
+    sub.d         t4,     t4,    t3
+    addi.d        t3,     s0,    4
+
+    cdef_fill     t4,     s5,    t3,     t2
+
+    or            t7,     zero,  zero
+
+1:  //CDEF_HAVE_BOTTOM
+    andi          t4,     s2,8
+    bnez          t4,     2f
+
+    mul.w         t3,     s1,    s5
+    slli.d        t3,     t3,  1
+    add.d         t4,     s4,  t3
+    addi.d        t4,     t4,    -4
+    li.d          t3,     8
+
+    cdef_fill     t4,     s5,    t3,     t2
+
+    addi.d        t8,     t8,    -2
+
+2:  //CDEF_HAVE_LEFT
+    andi          t4,     s2,1
+    bnez          t4,     3f
+
+    mul.w         t3,     t7,    s5
+    slli.d        t3,     t3,    1
+    add.d         t4,     s4,    t3
+    addi.d        t4,     t4,    -4
+    sub.d         t3,     t8,    t7
+
+    cdef_fill     t4,     s5,    t2,     t3
+
+    or            t5,     zero,  zero
+
+3:  //CDEF_HAVE_RIGHT
+    andi          t4,     s2,2
+    bnez          t4,     40f
+
+    mul.w         t3,     t7,    s5
+    slli.d        t3,     t3,    1
+    add.d         t4,     s4,    t3
+    addi.d        t4,     t4,    8
+    sub.d         t3,     t8,    t7
+
+    cdef_fill     t4,     s5,    t2,     t3
+
+    addi.d        t6,     t6,    -2
+
+40:
+    cdef_padding_data
+
+    beqz           a5,    33f
+
+28:  //if (pri_strength)
+    li.w           t0,    4
+    andi           t1,    a5,    1
+    sub.d          t0,    t0,    t1  //pri_tap
+
+    clz.w          t1,    a5
+    li.d           t2,    31
+    sub.w          t1,    t2,    t1
+    sub.w          t1,    s7,    t1
+
+    blt            t1,    zero,  281f
+    or             t1,    t1,    t1
+    b              282f
+281:
+    or             t1,    zero,  zero   //t1: pri_shift
+282:
+
+    beqz           a6,    31f
+
+29:  //if (sec_strength)
+    cdef_pri_sec_init
+
+30:
+    fld.s          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+    vpermi.w       vr0,   vr0,   0x44
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+    vor.v          vr2,   vr0,   vr0   //max
+    vor.v          vr3,   vr0,   vr0   //min
+    vor.v          vr15,  vr4,   vr4   //pri_tap_k
+
+    sub.d          t4,    s4,    a2
+    sub.d          t5,    s4,    a3
+
+    fldx.d         f5,    s4,    a2   //p0_00
+    fld.d          f6,    t4,    0    //p0_01
+    fldx.d         f7,    s4,    a3   //p0_10
+    fld.d          f8,    t5,    0    //p0_11
+
+    cdef_process_data_w4 vr9,   vr10
+    cdef_calc_sum_tapchange_w4
+    cdef_calc_maxmin_w4
+
+    sub.d          t4,    s4,    s1  //tmp[-off02]
+    sub.d          t5,    s4,    t0  //tmp[-off03]
+
+    fldx.d         f5,    s4,    s1   //s0_00
+    fld.d          f6,    t4,    0    //s0_01
+    fldx.d         f7,    s4,    t0   //s0_02
+    fld.d          f8,    t5,    0    //s0_03
+
+    cdef_process_data_w4 vr18, vr19
+    cdef_calc_sum_no_tapchange_w4 vr22
+    cdef_calc_maxmin_w4
+
+    sub.d          t4,    s4,    s2  //tmp[-off12]
+    sub.d          t5,    s4,    s3  //tmp[-off13]
+
+    fldx.d         f5,    s4,    s2   //s0_10
+    fld.d          f6,    t4,    0    //s0_11
+    fldx.d         f7,    s4,    s3   //s0_12
+    fld.d          f8,    t5,    0    //s0_13
+
+    cdef_process_data_w4 vr18, vr19
+    cdef_calc_sum_no_tapchange_w4 vr20
+    cdef_calc_maxmin_w4
+
+    vshuf4i.w      vr5,   vr1,   0x0e
+    vshuf4i.w      vr6,   vr3,   0x0e
+    vshuf4i.w      vr7,   vr2,   0x0e
+    vadd.h         vr1,   vr1,   vr5
+    vmin.hu        vr3,   vr6,   vr3
+    vmax.h         vr2,   vr7,   vr2
+
+    cdef_calc_dst
+    iclip_vrh       vr5,   vr3,   vr2,  vr16,  vr17,  vr5
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.s          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    30b
+    b              35f
+
+31:  // pri_strength only
+    cdef_pri_init
+
+32:
+    fld.s          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+    vpermi.w       vr0,   vr0,   0x44
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+    vor.v          vr15,  vr4,   vr4   //pri_tap_k
+
+    sub.d          t4,    s4,    a2
+    sub.d          t5,    s4,    a3
+
+    fldx.d         f5,    s4,    a2   //p0_00
+    fld.d          f6,    t4,    0    //p0_01
+    fldx.d         f7,    s4,    a3   //p0_10
+    fld.d          f8,    t5,    0    //p0_11
+
+    cdef_process_data_w4 vr9,   vr10
+    cdef_calc_sum_tapchange_w4
+
+    vshuf4i.w      vr5,   vr1,   0x0e
+    vadd.h         vr1,   vr1,   vr5
+
+    cdef_calc_dst
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.s          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    32b
+    b              35f
+
+33:   // sec_strength only
+    cdef_sec_init
+
+34:
+    fld.s          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+    vpermi.w       vr0,   vr0,   0x44
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+
+    sub.d          t4,    s4,    s1  //tmp[-off02]
+    sub.d          t5,    s4,    t0  //tmp[-off03]
+
+    fldx.d         f5,    s4,    s1   //s0_00
+    fld.d          f6,    t4,    0    //s0_01
+    fldx.d         f7,    s4,    t0   //s0_02
+    fld.d          f8,    t5,    0    //s0_03
+
+    cdef_process_data_w4 vr18, vr19
+    cdef_calc_sum_no_tapchange_w4 vr22
+
+    sub.d          t4,    s4,    s2  //tmp[-off12]
+    sub.d          t5,    s4,    s3  //tmp[-off13]
+
+    fldx.d         f5,    s4,    s2   //s0_10
+    fld.d          f6,    t4,    0    //s0_11
+    fldx.d         f7,    s4,    s3   //s0_12
+    fld.d          f8,    t5,    0    //s0_13
+
+    cdef_process_data_w4 vr18, vr19
+    cdef_calc_sum_no_tapchange_w4 vr20
+
+    vshuf4i.w      vr5,   vr1,   0x0e
+    vadd.h         vr1,   vr1,   vr5
+
+    cdef_calc_dst
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.s          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    34b
+
+35:
+    ld.d           s0,    sp,    0
+    ld.d           s1,    sp,    8
+    ld.d           s2,    sp,    16
+    ld.d           s3,    sp,    24
+    ld.d           s4,    sp,    32
+    ld.d           s5,    sp,    40
+    ld.d           s6,    sp,    48
+    ld.d           s7,    sp,    56
+    addi.d         sp,    sp,    (64+288)
+endfunc
+
+function cdef_filter_block_8x8_8bpc_lsx
+    ld.w           t0,    sp,    0
+    ld.w           t1,    sp,    8
+    addi.d         sp,    sp,    -(64+288)
+    st.d           s0,    sp,    0
+    st.d           s1,    sp,    8
+    st.d           s2,    sp,    16
+    st.d           s3,    sp,    24
+    st.d           s4,    sp,    32
+    st.d           s5,    sp,    40
+    st.d           s6,    sp,    48
+    st.d           s7,    sp,    56
+
+    li.w           s0,    8         //w
+    li.w           s1,    8         //h
+    or             s2,    t1,    t1 //edges
+    or             s7,    t0,    t0 //damping
+
+    // cdef_filter_block_kernel
+    li.d           s5,    12         //tmp_stride
+    addi.d         s4,    sp,    64
+    slli.d         t0,    s5,    1
+    addi.d         t0,    t0,    2
+    slli.d         t0,    t0,    1
+    add.d          s4,    s4,    t0  //ptr tmp
+    vxor.v         vr23,  vr23,  vr23
+    li.w           t2,    1
+    vreplgr2vr.h   vr20,  t2
+    vaddi.hu       vr21,  vr20,  2
+    vaddi.hu       vr22,  vr20,  1
+
+    li.w          t0,     -16384
+    vreplgr2vr.h  vr18,   t0
+
+    //padding
+    li.w          t5,     -2        //x_start
+    addi.d        t6,     s0,    2  //x_end
+    li.w          t7,     -2        //y_start
+    addi.d        t8,     s1,    2  //y_end
+    li.w          t2,     2
+
+    andi          t4,     s2,    4
+    bnez          t4,     1f
+
+    //CDEF_HAVE_TOP
+    slli.d        t3,     s5,    2
+    addi.d        t4,     s4,    -4
+    sub.d         t4,     t4,    t3
+    addi.d        t3,     s0,    4
+
+    cdef_fill     t4,     s5,    t3,     t2
+
+    or            t7,     zero,  zero
+
+1:  //CDEF_HAVE_BOTTOM
+    andi          t4,     s2,8
+    bnez          t4,     2f
+
+    mul.w         t3,     s1,    s5
+    slli.d        t3,     t3,  1
+    add.d         t4,     s4,  t3
+    addi.d        t4,     t4,    -4
+    li.d          t3,     12
+
+    cdef_fill     t4,     s5,    t3,    t2
+
+    addi.d        t8,     t8,    -2
+
+2:  //CDEF_HAVE_LEFT
+    andi          t4,     s2,1
+    bnez          t4,     3f
+
+    mul.w         t3,     t7,    s5
+    slli.d        t3,     t3,    1
+    add.d         t4,     s4,    t3
+    addi.d        t4,     t4,    -4
+    sub.d         t3,     t8,    t7
+    li.d          t2,     2
+
+    cdef_fill     t4,     s5,    t2,    t3
+
+    or            t5,     zero,  zero
+
+3:  //CDEF_HAVE_RIGHT
+    andi          t4,     s2,2
+    bnez          t4,     40f
+
+    mul.w         t3,     t7,    s5
+    slli.d        t3,     t3,    1
+    add.d         t4,     s4,    t3
+    addi.d        t4,     t4,    16
+    sub.d         t3,     t8,    t7
+    li.d          t2,     2
+
+    cdef_fill     t4,     s5,    t2,    t3
+
+    addi.d        t6,     t6,    -2
+
+40:
+    cdef_padding_data
+
+    beqz           a5,    33f
+
+28:  //if (pri_strength)
+    li.w           t0,    4
+    andi           t1,    a5,    1
+    sub.d          t0,    t0,    t1  //pri_tap
+
+    //edit
+    clz.w          t1,    a5
+    li.d           t2,    31
+    sub.w          t3,    t2,    t1
+    sub.w          t3,    s7,    t3
+
+    or             t1,    zero,  zero   //t1: pri_shift
+    blt            t3,    zero,  281f
+    or             t1,    t3,    t3
+281:
+
+    beqz           a6,    31f
+
+29:  //if (sec_strength)
+    cdef_pri_sec_init
+
+301:
+    fld.d          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+    vor.v          vr2,   vr0,   vr0   //max
+    vor.v          vr3,   vr0,   vr0   //min
+    vor.v          vr15,  vr4,   vr4   //pri_tap_k
+
+    sub.d          t4,    s4,    a2
+    sub.d          t5,    s4,    a3
+
+    vldx           vr5,  s4,    a2
+    vld            vr6,  t4,    0
+    vldx           vr7,  s4,    a3
+    vld            vr8,  t5,    0
+
+    cdef_process_data_w8 vr9, vr10
+    cdef_calc_sum_tapchange_w8
+    cdef_calc_maxmin_w8
+
+    //s 00-03
+    sub.d          t4,    s4,    s1  //tmp[-off02]
+    sub.d          t5,    s4,    t0  //tmp[-off03]
+
+    vldx           vr5,  s4,    s1
+    vld            vr6,  t4,    0
+    vldx           vr7,  s4,    t0
+    vld            vr8,  t5,    0
+
+    cdef_process_data_w8 vr18, vr19
+    cdef_calc_sum_no_tapchange_w8 vr22
+    cdef_calc_maxmin_w8
+
+    //s 10-13
+    sub.d          t4,    s4,    s2  //tmp[-off12]
+    sub.d          t5,    s4,    s3  //tmp[-off13]
+
+    vldx           vr5,  s4,    s2
+    vld            vr6,  t4,    0
+    vldx           vr7,  s4,    s3
+    vld            vr8,  t5,    0
+
+    cdef_process_data_w8 vr18, vr19
+    cdef_calc_sum_no_tapchange_w8 vr20
+
+    cdef_calc_maxmin_w8
+    cdef_calc_dst
+
+    iclip_vrh       vr5,   vr3,   vr2,  vr16,  vr17,  vr5
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.d          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    301b
+    b              35f
+
+31:  // pri_strength only
+    cdef_pri_init
+
+32:
+    fld.d          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+    vor.v          vr15,  vr4,   vr4   //pri_tap_k
+
+    sub.d          t4,    s4,    a2
+    sub.d          t5,    s4,    a3
+
+    vldx           vr5,  s4,    a2
+    vld            vr6,  t4,    0
+    vldx           vr7,  s4,    a3
+    vld            vr8,  t5,    0
+
+    cdef_process_data_w8 vr9, vr10
+    cdef_calc_sum_tapchange_w8
+    cdef_calc_dst
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.d          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    32b
+    b              35f
+
+33:   // sec_strength only
+    cdef_sec_init
+
+34:
+    fld.d          f0,    a0,    0     //px
+    vsllwil.hu.bu  vr0,   vr0,   0
+
+    vxor.v         vr1,   vr1,   vr1   //sum
+
+    sub.d          t4,    s4,    s1  //tmp[-off02]
+    sub.d          t5,    s4,    t0  //tmp[-off03]
+
+    vldx           vr5,  s4,    s1
+    vld            vr6,  t4,    0
+    vldx           vr7,  s4,    t0
+    vld            vr8,  t5,    0
+
+    cdef_process_data_w8 vr18,  vr19
+    cdef_calc_sum_no_tapchange_w8 vr22
+
+    sub.d          t4,    s4,    s2  //tmp[-off12]
+    sub.d          t5,    s4,    s3  //tmp[-off13]
+
+    vldx           vr5,  s4,    s2
+    vld            vr6,  t4,    0
+    vldx           vr7,  s4,    s3
+    vld            vr8,  t5,    0
+
+    cdef_process_data_w8 vr18,  vr19
+    cdef_calc_sum_no_tapchange_w8 vr20
+    cdef_calc_dst
+
+    vsrlni.b.h     vr5,   vr5,   0
+    fst.d          f5,    a0,    0
+
+    add.d          a0,    a0,    a1
+    add.d          s4,    s4,    s5
+    add.d          s4,    s4,    s5
+
+    addi.d         t2,    t2,    -1
+    blt            zero,  t2,    34b
+
+35:
+    ld.d           s0,    sp,    0
+    ld.d           s1,    sp,    8
+    ld.d           s2,    sp,    16
+    ld.d           s3,    sp,    24
+    ld.d           s4,    sp,    32
+    ld.d           s5,    sp,    40
+    ld.d           s6,    sp,    48
+    ld.d           s7,    sp,    56
+    addi.d         sp,    sp,    (64+288)
+endfunc
+
diff --git a/media/libdav1d/src/src/loongarch/cdef.h b/media/libdav1d/src/src/loongarch/cdef.h
new file mode 100644
index 0000000000..f9e39742cf
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/cdef.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_CDEF_H
+#define DAV1D_SRC_LOONGARCH_CDEF_H
+
+#include "config.h"
+#include "src/cdef.h"
+#include "src/cpu.h"
+
+decl_cdef_dir_fn(BF(dav1d_cdef_find_dir, lsx));
+decl_cdef_fn(BF(dav1d_cdef_filter_block_4x4, lsx));
+decl_cdef_fn(BF(dav1d_cdef_filter_block_4x8, lsx));
+decl_cdef_fn(BF(dav1d_cdef_filter_block_8x8, lsx));
+
+static ALWAYS_INLINE void cdef_dsp_init_loongarch(Dav1dCdefDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LSX)) return;
+
+#if BITDEPTH == 8
+    c->dir = BF(dav1d_cdef_find_dir, lsx);
+    c->fb[0] = BF(dav1d_cdef_filter_block_8x8, lsx);
+    c->fb[1] = BF(dav1d_cdef_filter_block_4x8, lsx);
+    c->fb[2] = BF(dav1d_cdef_filter_block_4x4, lsx);
+#endif
+}
+
+#endif /* DAV1D_SRC_LOONGARCH_CDEF_H */
diff --git a/media/libdav1d/src/src/loongarch/cpu.c b/media/libdav1d/src/src/loongarch/cpu.c
new file mode 100644
index 0000000000..8e6b562018
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/cpu.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "common/attributes.h"
+
+#include "src/cpu.h"
+#include "src/loongarch/cpu.h"
+
+#if HAVE_GETAUXVAL
+#include 
+
+#define LA_HWCAP_LSX    ( 1 << 4 )
+#define LA_HWCAP_LASX   ( 1 << 5 )
+#endif
+
+COLD unsigned dav1d_get_cpu_flags_loongarch(void) {
+    unsigned flags = dav1d_get_default_cpu_flags();
+#if HAVE_GETAUXVAL
+    unsigned long hw_cap = dav1d_getauxval(AT_HWCAP);
+    flags |= (hw_cap & LA_HWCAP_LSX) ? DAV1D_LOONGARCH_CPU_FLAG_LSX : 0;
+    flags |= (hw_cap & LA_HWCAP_LASX) ? DAV1D_LOONGARCH_CPU_FLAG_LASX : 0;
+#endif
+
+    return flags;
+}
diff --git a/media/libdav1d/src/src/loongarch/cpu.h b/media/libdav1d/src/src/loongarch/cpu.h
new file mode 100644
index 0000000000..d00ff67dac
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/cpu.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_CPU_H
+#define DAV1D_SRC_LOONGARCH_CPU_H
+
+enum CpuFlags {
+    DAV1D_LOONGARCH_CPU_FLAG_LSX  = 1 << 0,
+    DAV1D_LOONGARCH_CPU_FLAG_LASX = 1 << 1,
+};
+
+unsigned dav1d_get_cpu_flags_loongarch(void);
+
+#endif /* DAV1D_SRC_LOONGARCH_CPU_H */
diff --git a/media/libdav1d/src/src/loongarch/ipred.S b/media/libdav1d/src/src/loongarch/ipred.S
new file mode 100644
index 0000000000..ddc77380f9
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/ipred.S
@@ -0,0 +1,4260 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/loongarch/loongson_asm.S"
+
+.macro ipred_dc_gen topleft, width, height
+    add.d          t0,      \width,  \height //dc
+    srai.d         t0,      t0,      1
+    addi.d         t3,      \topleft,1
+
+    or             t1,      zero,    zero  //data index
+    srai.d         t2,      \width,  4     //loop param
+    beqz           t2,      2f
+
+1:  // width/16
+    vldx           vr0,     t3,      t1
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+    vhaddw.du.wu   vr0,     vr0,     vr0
+    vhaddw.qu.du   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+
+    addi.d         t1,      t1,      16
+    addi.d         t2,      t2,      -1
+    bnez           t2,      1b
+    b              4f
+
+2:  // &8
+    andi           t2,      \width,  8
+    beqz           t2,      3f
+
+    vxor.v         vr0,     vr0,     vr0
+    fldx.d         f0,      t3,      t1
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+    vhaddw.du.wu   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+    addi.d         t1,      t1,      8
+    b              4f
+
+3:  // &4
+    andi           t2,      \width,  4
+    beqz           t2,      4f
+
+    vxor.v         vr0,     vr0,     vr0
+    fldx.s         f0,      t3,      t1
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+
+    vpickve2gr.wu  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+    addi.d         t1,      t1,      4
+
+4:
+    addi.d         t3,      \topleft,0
+    srai.d         t2,      \height, 4     //loop param
+    beqz           t2,      8f
+
+7:  // height/16
+    addi.d         t3,      t3,      -16
+    vld            vr0,     t3,      0
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+    vhaddw.du.wu   vr0,     vr0,     vr0
+    vhaddw.qu.du   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+
+    addi.d         t2,      t2,      -1
+    bnez           t2,      7b
+    b              10f
+
+8:  // &8
+    andi           t2,      \height, 8
+    beqz           t2,      9f
+
+    addi.d         t3,      t3,      -8
+    vxor.v         vr0,     vr0,     vr0
+    fld.d          f0,      t3,      0
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+    vhaddw.du.wu   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+    b              10f
+
+9:  // &4
+    andi           t2,      \height, 4
+    beqz           t2,      10f
+
+    addi.d         t3,      t3,      -4
+    vxor.v         vr0,     vr0,     vr0
+    fld.s          f0,      t3,      0
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+
+    vpickve2gr.wu  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+
+10:
+    add.d          t1,      \width,  \height
+    ctz.w          t1,      t1
+    sra.w          t0,      t0,      t1
+
+    // w != h
+    beq            \width,  \height, 16f
+    add.d          t2,      \height, \height
+    add.d          t3,      \width,  \width
+    slt            t2,      t2,      \width
+    slt            t3,      t3,      \height
+    or             t2,      t2,      t3
+    li.w           t3,      0x3334
+    maskeqz        t1,      t3,      t2
+    li.w           t3,      0x5556
+    masknez        t2,      t3,      t2
+    or             t1,      t1,      t2
+    mul.w          t0,      t0,      t1
+    srai.w         t0,      t0,      16
+
+16:
+.endm
+
+.macro ipred_splat_dc dst, stride, width, height, dc
+    li.w           t1,      4
+    blt            t1,      \width,  2f
+
+    li.w           t1,      0x01010101
+    mulw.d.wu      t1,      \dc,     t1
+    beqz           \height, 7f
+    or             t2,      \dst,    \dst
+1:  // width <= 4
+    st.w           t1,      t2,      0
+    add.d          t2,      t2,      \stride
+    addi.d         \height, \height, -1
+    bnez           \height, 1b
+    b              7f
+
+2:  //width > 4
+    li.d           t1,      0x0101010101010101
+    mul.d          t1,      \dc,     t1
+    vreplgr2vr.d   vr0,     t1
+    or             t4,      \dst,    \dst
+    beqz           \height, 7f
+
+3:
+    andi           t5,      \width,  64
+    beqz           t5,      4f
+    vst            vr0,     t4,      0
+    vst            vr0,     t4,      16
+    vst            vr0,     t4,      32
+    vst            vr0,     t4,      48
+    b              6f
+
+4:
+    andi           t5,      \width,  32
+    beqz           t5,      41f
+    vst            vr0,     t4,      0
+    vst            vr0,     t4,      16
+    b              6f
+
+41:
+    andi           t5,      \width,  16
+    beqz           t5,      5f
+    vst            vr0,     t4,      0
+    b              6f
+
+5:
+    fst.d          f0,      t4,      0
+
+6:
+    add.d          t4,      t4,      \stride
+    addi.d         \height, \height, -1
+    bnez           \height, 3b
+
+7:
+.endm
+
+.macro ipred_dc_gen_top topleft, width
+    srai.d         t0,      \width,  1
+    addi.d         t1,      \topleft,1
+
+    srai.d         t2,      \width,  4
+    beqz           t2,      2f
+1:
+    vld            vr0,     t1,      0
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+    vhaddw.du.wu   vr0,     vr0,     vr0
+    vhaddw.qu.du   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t3,      vr0,     0
+    add.d          t0,      t0,      t3
+
+    addi.d         t1,      t1,      16
+    addi.d         t2,      t2,      -1
+    bnez           t2,      1b
+    b              4f
+
+2:  // &8
+    andi           t2,      \width,  8
+    beqz           t2,      3f
+
+    vxor.v         vr0,     vr0,     vr0
+    fld.d          f0,      t1,      0
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+    vhaddw.du.wu   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t2,      vr0,     0
+    add.d          t0,      t0,      t2
+
+    addi.d         t1,      t1,      8
+    b              4f
+
+3:  // &4
+    andi           t2,      \width,  4
+    beqz           t2,      4f
+
+    vxor.v         vr0,     vr0,     vr0
+    fld.s          f0,      t1,      0
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t2,      vr0,     0
+    add.d          t0,      t0,      t2
+    addi.d         t1,      t1,      4
+
+4:
+    ctz.w          t1,      \width
+    sra.w          t0,      t0,      t1
+.endm
+
+.macro ipred_dc_gen_left topleft, height
+    srai.d         t0,      \height, 1
+    srai.d         t2,      \height, 4     //loop param
+    beqz           t2,      8f
+
+7:  // height/16
+    addi.d         \topleft,\topleft,-16
+    vld            vr0,     \topleft,0
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+    vhaddw.du.wu   vr0,     vr0,     vr0
+    vhaddw.qu.du   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+
+    addi.d         t2,      t2,      -1
+    bnez           t2,      7b
+    b              10f
+
+8:  // &8
+    andi           t2,      \height, 8
+    beqz           t2,      9f
+
+    addi.d         \topleft,\topleft,-8
+    vxor.v         vr0,     vr0,     vr0
+    fld.d          f0,      \topleft,0
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+    vhaddw.du.wu   vr0,     vr0,     vr0
+
+    vpickve2gr.du  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+    b              10f
+
+9:  // &4
+    andi           t2,      \height, 4
+    beqz           t2,      10f
+
+    addi.d         \topleft,\topleft,-4
+    vxor.v         vr0,     vr0,     vr0
+    fld.s          f0,      \topleft,0
+
+    vhaddw.hu.bu   vr0,     vr0,     vr0
+    vhaddw.wu.hu   vr0,     vr0,     vr0
+
+    vpickve2gr.wu  t4,      vr0,     0
+    add.d          t0,      t0,      t4
+
+10:
+    ctz.w          t1,      \height
+    sra.w          t0,      t0,      t1
+
+.endm
+
+// void ipred_dc_lsx(pixel *dst, const ptrdiff_t stride,
+//                   const pixel *const topleft,
+//                   const int width, const int height, const int a,
+//                   const int max_width, const int max_height
+//                   HIGHBD_DECL_SUFFIX)
+function ipred_dc_8bpc_lsx
+    ipred_dc_gen   a2, a3, a4
+    ipred_splat_dc a0, a1, a3, a4, t0
+
+endfunc
+
+// void ipred_dc_128_lsx(pixel *dst, const ptrdiff_t stride,
+//                       const pixel *const topleft,
+//                       const int width, const int height, const int a,
+//                       const int max_width, const int max_height
+//                       HIGHBD_DECL_SUFFIX)
+function ipred_dc_128_8bpc_lsx
+    li.w           t0,      128
+    ipred_splat_dc a0, a1, a3, a4, t0
+
+endfunc
+
+// void ipred_dc_top_c(pixel *dst, const ptrdiff_t stride,
+//                     const pixel *const topleft,
+//                     const int width, const int height, const int a,
+//                     const int max_width, const int max_height
+//                     HIGHBD_DECL_SUFFIX)
+function ipred_dc_top_8bpc_lsx
+    ipred_dc_gen_top a2, a3
+    ipred_splat_dc   a0, a1, a3, a4, t0
+
+endfunc
+
+// void ipred_dc_left_c(pixel *dst, const ptrdiff_t stride,
+//                      const pixel *const topleft,
+//                      const int width, const int height, const int a,
+//                      const int max_width, const int max_height
+//                      HIGHBD_DECL_SUFFIX)
+function ipred_dc_left_8bpc_lsx
+    ipred_dc_gen_left a2, a4
+    ipred_splat_dc    a0, a1, a3, a4, t0
+
+endfunc
+
+.macro pixel_set_8bpc dst_ptr, src_ptr, width
+    vldrepl.b      vr0,     \src_ptr, 0
+1:
+    andi           a5,      \width,   64
+    beqz           a5,      2f
+
+    vst            vr0,     \dst_ptr, 0
+    vst            vr0,     \dst_ptr, 16
+    vst            vr0,     \dst_ptr, 32
+    vst            vr0,     \dst_ptr, 48
+    b              6f
+2:
+    andi           a5,      \width,   32
+    beqz           a5,      3f
+
+    vst            vr0,     \dst_ptr, 0
+    vst            vr0,     \dst_ptr, 16
+    b              6f
+3:
+    andi           a5,      \width,   16
+    beqz           a5,      4f
+
+    vst            vr0,     \dst_ptr, 0
+    b              6f
+4:
+    andi           a5,      \width,   8
+    beqz           a5,      5f
+
+    fst.d          f0,      \dst_ptr, 0
+    b              6f
+5:
+    andi           a5,      \width,   4
+    beqz           a5,      6f
+
+    fst.s          f0,      \dst_ptr, 0
+6:
+.endm
+
+// void ipred_h_c(pixel *dst, const ptrdiff_t stride,
+//                const pixel *const topleft,
+//                const int width, const int height, const int a,
+//                const int max_width, const int max_height
+//                HIGHBD_DECL_SUFFIX)
+function ipred_h_8bpc_lsx
+    beqz           a4,      .IPRED_H_END
+.IPRED_H_LOOP:
+    addi.d         a2,      a2,      -1
+
+    pixel_set_8bpc a0, a2, a3
+
+    add.d          a0,      a0,      a1
+    addi.d         a4,      a4,      -1
+    bnez           a4,      .IPRED_H_LOOP
+
+.IPRED_H_END:
+endfunc
+
+.macro pixel_copy_8bpc dst_ptr, src_ptr, width
+1:
+    andi           a5,      \width,   64
+    beqz           a5,      2f
+
+    vld            vr0,     \src_ptr, 0
+    vld            vr1,     \src_ptr, 16
+    vld            vr2,     \src_ptr, 32
+    vld            vr3,     \src_ptr, 48
+
+    vst            vr0,     \dst_ptr, 0
+    vst            vr1,     \dst_ptr, 16
+    vst            vr2,     \dst_ptr, 32
+    vst            vr3,     \dst_ptr, 48
+
+    b              6f
+2:
+    andi           a5,      \width,   32
+    beqz           a5,      3f
+
+    vld            vr0,     \src_ptr, 0
+    vld            vr1,     \src_ptr, 16
+
+    vst            vr0,     \dst_ptr, 0
+    vst            vr1,     \dst_ptr, 16
+
+    b              6f
+3:
+    andi           a5,      \width,   16
+    beqz           a5,      4f
+
+    vld            vr0,     \src_ptr, 0
+    vst            vr0,     \dst_ptr, 0
+
+    b              6f
+4:
+    andi           a5,      \width,   8
+    beqz           a5,      5f
+
+    fld.d          f0,      \src_ptr, 0
+    fst.d          f0,      \dst_ptr, 0
+
+    b              6f
+5:
+    andi           a5,      \width,   4
+    beqz           a5,      6f
+
+    fld.s          f0,      \src_ptr, 0
+    fst.s          f0,      \dst_ptr, 0
+6:
+.endm
+
+// void ipred_v_lsx(pixel *dst, const ptrdiff_t stride,
+//                  const pixel *const topleft,
+//                  const int width, const int height, const int a,
+//                  const int max_width, const int max_height
+//                  HIGHBD_DECL_SUFFIX)
+function ipred_v_8bpc_lsx
+    beqz           a4,      .IPRED_V_END
+    addi.d         a2,      a2,      1
+.IPRED_V_LOOP:
+    pixel_copy_8bpc  a0, a2, a3
+
+    add.d          a0,      a0,      a1
+    addi.d         a4,      a4,      -1
+    bnez           a4,      .IPRED_V_LOOP
+
+.IPRED_V_END:
+endfunc
+
+// void ipred_paeth_lsx(pixel *dst, const ptrdiff_t stride,
+//                      const pixel *const tl_ptr,
+//                      const int width, const int height, const int a,
+//                      const int max_width, const int max_height
+//                      HIGHBD_DECL_SUFFIX)
+function ipred_paeth_8bpc_lsx
+    vldrepl.b      vr0,     a2,      0    //topleft
+    vsllwil.hu.bu  vr0,     vr0,     0
+    or             a6,      a2,      a2
+    addi.d         a7,      a2,      1
+
+.IPRED_PAETH_H_LOOP:
+    addi.d         a6,      a6,      -1
+    vldrepl.b      vr1,     a6,      0   //left
+    vsllwil.hu.bu  vr1,     vr1,     0
+
+.IPRED_PAETH_W_LOOP64:
+    andi           a5,      a3,      64
+    beqz           a5,      .IPRED_PAETH_W_LOOP32
+
+    vld            vr2,     a7,      0   //top
+    vpermi.w       vr9,     vr2,     0x0e
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr9,     vr9,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+    vabsd.hu       vr10,    vr0,     vr9
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vadd.h         vr11,    vr1,     vr9
+    vabsd.hu       vr6,     vr3,     vr6  //tldiff
+    vabsd.hu       vr11,    vr3,     vr11 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+
+    vsle.hu        vr12,    vr5,     vr11
+    vbitsel.v      vr7,     vr0,     vr9,    vr12
+    vsle.hu        vr12,    vr10,    vr5
+    vsle.hu        vr8,     vr10,    vr11
+    vand.v         vr12,    vr12,    vr8
+    vbitsel.v      vr12,    vr7,     vr1,    vr12
+    vsrlni.b.h     vr12,    vr12,    0
+
+    vpermi.w       vr12,    vr3,     0x44
+
+    vst            vr12,    a0,      0
+
+    vld            vr2,     a7,      16   //top
+    vpermi.w       vr9,     vr2,     0x0e
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr9,     vr9,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+    vabsd.hu       vr10,    vr0,     vr9
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vadd.h         vr11,    vr1,     vr9
+    vabsd.hu       vr6,     vr3,     vr6  //tldiff
+    vabsd.hu       vr11,    vr3,     vr11 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+
+    vsle.hu        vr12,    vr5,     vr11
+    vbitsel.v      vr7,     vr0,     vr9,    vr12
+    vsle.hu        vr12,    vr10,    vr5
+    vsle.hu        vr8,     vr10,    vr11
+    vand.v         vr12,    vr12,    vr8
+    vbitsel.v      vr12,    vr7,     vr1,    vr12
+    vsrlni.b.h     vr12,    vr12,    0
+
+    vpermi.w       vr12,    vr3,     0x44
+
+    vst            vr12,    a0,      16
+
+    vld            vr2,     a7,      32   //top
+    vpermi.w       vr9,     vr2,     0x0e
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr9,     vr9,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+    vabsd.hu       vr10,    vr0,     vr9
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vadd.h         vr11,    vr1,     vr9
+    vabsd.hu       vr6,     vr3,     vr6  //tldiff
+    vabsd.hu       vr11,    vr3,     vr11 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+
+    vsle.hu        vr12,    vr5,     vr11
+    vbitsel.v      vr7,     vr0,     vr9,    vr12
+    vsle.hu        vr12,    vr10,    vr5
+    vsle.hu        vr8,     vr10,    vr11
+    vand.v         vr12,    vr12,    vr8
+    vbitsel.v      vr12,    vr7,     vr1,    vr12
+    vsrlni.b.h     vr12,    vr12,    0
+
+    vpermi.w       vr12,    vr3,     0x44
+
+    vst            vr12,    a0,      32
+
+    vld            vr2,     a7,      48   //top
+    vpermi.w       vr9,     vr2,     0x0e
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr9,     vr9,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+    vabsd.hu       vr10,    vr0,     vr9
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vadd.h         vr11,    vr1,     vr9
+    vabsd.hu       vr6,     vr3,     vr6  //tldiff
+    vabsd.hu       vr11,    vr3,     vr11 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+
+    vsle.hu        vr12,    vr5,     vr11
+    vbitsel.v      vr7,     vr0,     vr9,    vr12
+    vsle.hu        vr12,    vr10,    vr5
+    vsle.hu        vr8,     vr10,    vr11
+    vand.v         vr12,    vr12,    vr8
+    vbitsel.v      vr12,    vr7,     vr1,    vr12
+    vsrlni.b.h     vr12,    vr12,    0
+
+    vpermi.w       vr12,    vr3,     0x44
+
+    vst            vr12,    a0,      48
+
+    b              .IPRED_PAETH_W_LOOPEND
+
+.IPRED_PAETH_W_LOOP32:
+    andi           a5,      a3,      32
+    beqz           a5,      .IPRED_PAETH_W_LOOP16
+
+    vld            vr2,     a7,      0   //top
+    vpermi.w       vr9,     vr2,     0x0e
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr9,     vr9,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+    vabsd.hu       vr10,    vr0,     vr9
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vadd.h         vr11,    vr1,     vr9
+    vabsd.hu       vr6,     vr3,     vr6  //tldiff
+    vabsd.hu       vr11,    vr3,     vr11 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+
+    vsle.hu        vr12,    vr5,     vr11
+    vbitsel.v      vr7,     vr0,     vr9,    vr12
+    vsle.hu        vr12,    vr10,    vr5
+    vsle.hu        vr8,     vr10,    vr11
+    vand.v         vr12,    vr12,    vr8
+    vbitsel.v      vr12,    vr7,     vr1,    vr12
+    vsrlni.b.h     vr12,    vr12,    0
+
+    vpermi.w       vr12,    vr3,     0x44
+
+    vst            vr12,    a0,      0
+
+    vld            vr2,     a7,      16   //top
+    vpermi.w       vr9,     vr2,     0x0e
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr9,     vr9,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+    vabsd.hu       vr10,    vr0,     vr9
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vadd.h         vr11,    vr1,     vr9
+    vabsd.hu       vr6,     vr3,     vr6  //tldiff
+    vabsd.hu       vr11,    vr3,     vr11 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+
+    vsle.hu        vr12,    vr5,     vr11
+    vbitsel.v      vr7,     vr0,     vr9,    vr12
+    vsle.hu        vr12,    vr10,    vr5
+    vsle.hu        vr8,     vr10,    vr11
+    vand.v         vr12,    vr12,    vr8
+    vbitsel.v      vr12,    vr7,     vr1,    vr12
+    vsrlni.b.h     vr12,    vr12,    0
+
+    vpermi.w       vr12,    vr3,     0x44
+
+    vst            vr12,    a0,      16
+
+    b              .IPRED_PAETH_W_LOOPEND
+
+.IPRED_PAETH_W_LOOP16:
+    andi           a5,      a3,      16
+    beqz           a5,      .IPRED_PAETH_W_LOOP8
+
+    vld            vr2,     a7,      0   //top
+    vpermi.w       vr9,     vr2,     0x0e
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr9,     vr9,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+    vabsd.hu       vr10,    vr0,     vr9
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vadd.h         vr11,    vr1,     vr9
+    vabsd.hu       vr6,     vr3,     vr6  //tldiff
+    vabsd.hu       vr11,    vr3,     vr11 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+
+    vsle.hu        vr12,    vr5,     vr11
+    vbitsel.v      vr7,     vr0,     vr9,    vr12
+    vsle.hu        vr12,    vr10,    vr5
+    vsle.hu        vr8,     vr10,    vr11
+    vand.v         vr12,    vr12,    vr8
+    vbitsel.v      vr12,    vr7,     vr1,    vr12
+    vsrlni.b.h     vr12,    vr12,    0
+
+    vpermi.w       vr12,    vr3,     0x44
+
+    vst            vr12,    a0,      0
+
+    b              .IPRED_PAETH_W_LOOPEND
+
+.IPRED_PAETH_W_LOOP8:
+    andi           a5,      a3,      8
+    beqz           a5,      .IPRED_PAETH_W_LOOP4
+
+    fld.d          f2,      a7,      0   //top
+    vsllwil.hu.bu  vr2,     vr2,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vabsd.hu       vr6,     vr3,     vr6 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+    fst.d          f3,      a0,      0
+
+    b              .IPRED_PAETH_W_LOOPEND
+
+.IPRED_PAETH_W_LOOP4:
+    andi           a5,      a3,      4
+    beqz           a5,      .IPRED_PAETH_W_LOOPEND
+
+    fld.s          f2,      a7,      0   //top
+    vsllwil.hu.bu  vr2,     vr2,     0
+
+    vabsd.hu       vr5,     vr0,     vr1  //tdiff
+    vabsd.hu       vr4,     vr0,     vr2  //ldiff
+
+    vadd.h         vr3,     vr0,     vr0
+    vadd.h         vr6,     vr1,     vr2
+    vabsd.hu       vr6,     vr3,     vr6 //tldiff
+
+    vsle.hu        vr3,     vr5,     vr6
+    vbitsel.v      vr7,     vr0,     vr2,    vr3
+    vsle.hu        vr3,     vr4,     vr5
+    vsle.hu        vr8,     vr4,     vr6
+    vand.v         vr3,     vr3,     vr8
+    vbitsel.v      vr3,     vr7,     vr1,    vr3
+    vsrlni.b.h     vr3,     vr3,     0
+    fst.s          f3,      a0,      0
+
+    b              .IPRED_PAETH_W_LOOPEND
+
+.IPRED_PAETH_W_LOOPEND:
+    add.d         a0,       a0,      a1
+    addi.d        a4,       a4,      -1
+    bnez          a4,       .IPRED_PAETH_H_LOOP
+endfunc
+
+const dav1d_sm_weights
+    .byte  0,   0
+    // bs = 2
+    .byte  255, 128
+    // bs = 4
+    .byte  255, 149,  85,  64
+    // bs = 8
+    .byte  255, 197, 146, 105,  73,  50,  37,  32
+    // bs = 16
+    .byte  255, 225, 196, 170, 145, 123, 102,  84
+    .byte  68,  54,  43,  33,  26,  20,  17,  16
+    // bs = 32
+    .byte  255, 240, 225, 210, 196, 182, 169, 157
+    .byte  145, 133, 122, 111, 101,  92,  83,  74
+    .byte  66,  59,  52,  45,  39,  34,  29,  25
+    .byte  21,  17,  14,  12,  10,   9,   8,   8
+    // bs = 64
+    .byte  255, 248, 240, 233, 225, 218, 210, 203
+    .byte  196, 189, 182, 176, 169, 163, 156, 150
+    .byte  144, 138, 133, 127, 121, 116, 111, 106
+    .byte  101,  96,  91,  86,  82,  77,  73,  69
+    .byte  65,  61,  57,  54,  50,  47,  44,  41
+    .byte  38,  35,  32,  29,  27,  25,  22,  20
+    .byte  18,  16,  15,  13,  12,  10,   9,   8
+    .byte  7,   6,   6,   5,   5,   4,   4,   4
+endconst
+
+// void ipred_smooth_lsx(pixel *dst, const ptrdiff_t stride,
+//                       const pixel *const topleft,
+//                       const int width, const int height, const int a,
+//                       const int max_width, const int max_height
+//                       HIGHBD_DECL_SUFFIX)
+function ipred_smooth_8bpc_lsx
+    la.local       a5,      dav1d_sm_weights
+    add.d          a6,      a5,      a3  //hor
+    add.d          a5,      a5,      a4  //ver
+
+    add.d          a7,      a2,      a3
+    sub.d          t0,      a2,      a4
+
+    vldrepl.b      vr0,     a7,      0  //right
+    vldrepl.b      vr1,     t0,      0  //bottom
+
+    vsllwil.hu.bu  vr0,     vr0,     0
+    vsllwil.wu.hu  vr0,     vr0,     0
+    vsllwil.hu.bu  vr1,     vr1,     0
+    vsllwil.wu.hu  vr1,     vr1,     0
+
+    li.w           t0,      256
+    vreplgr2vr.w   vr6,     t0
+
+    addi.d         t0,      a2,      1   //ptr topleft[x]
+    addi.d         t3,      a2,      -1  //ptr topleft[y]
+
+.IPRED_SMOOTH_H_LOOP:
+    vldrepl.b      vr2,     a5,      0  //ver[y]
+    vldrepl.b      vr3,     t3,      0  //topleft[y]
+
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.wu.hu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr3,     vr3,     0
+    vsllwil.wu.hu  vr3,     vr3,     0
+
+    vsub.w         vr7,     vr6,     vr2  //256-ver[y]
+
+    or             t1,      zero,    zero  //xx
+    srai.d         t2,      a3,      2     //loop max
+
+.IPRED_SMOOTH_W_LOOP:
+    fldx.s         f4,      t0,      t1   //topleft[x]
+    fldx.s         f5,      a6,      t1   //hor[x]
+
+    vsllwil.hu.bu  vr4,     vr4,     0
+    vsllwil.wu.hu  vr4,     vr4,     0
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsllwil.wu.hu  vr5,     vr5,     0
+
+    vsub.w         vr8,     vr6,     vr5  //256-hor[x]
+
+    vmul.w         vr9,     vr8,     vr0
+    vmadd.w        vr9,     vr5,     vr3
+    vmadd.w        vr9,     vr7,     vr1
+    vmadd.w        vr9,     vr2,     vr4  //pred
+
+    vadd.w         vr9,     vr9,     vr6
+    vsrlni.h.w     vr9,     vr9,     9
+    vsrlni.b.h     vr9,     vr9,     0
+
+    fstx.s         f9,      a0,      t1
+
+    addi.d         t1,      t1,      4
+    addi.d         t2,      t2,      -1
+    bnez           t2,      .IPRED_SMOOTH_W_LOOP
+
+.IPRED_SMOOTH_W_LOOP_END:
+    addi.d         t3,      t3,      -1
+    addi.d         a5,      a5,      1
+    add.d          a0,      a0,      a1
+    addi.d         a4,      a4,      -1
+    bnez           a4,      .IPRED_SMOOTH_H_LOOP
+
+endfunc
+
+// void ipred_smooth_v_lsx(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const topleft,
+//                         const int width, const int height, const int a,
+//                         const int max_width, const int max_height
+//                         HIGHBD_DECL_SUFFIX)
+function ipred_smooth_v_8bpc_lsx
+    la.local       a5,      dav1d_sm_weights
+    add.d          a5,      a5,      a4  //ver
+
+    sub.d          t0,      a2,      a4
+    vldrepl.b      vr0,     t0,      0  //bottom
+    vsllwil.hu.bu  vr0,     vr0,     0
+
+    li.w           t0,      256
+    vreplgr2vr.h   vr2,     t0
+    li.w           t0,      128
+    vreplgr2vr.h   vr3,     t0
+
+    addi.d         t0,      a2,      1   //ptr topleft[x]
+
+.IPRED_SMOOTH_V_H_LOOP:
+    vldrepl.b      vr1,     a5,      0  //ver[y]
+    vsllwil.hu.bu  vr1,     vr1,     0
+    vsub.h         vr5,     vr2,     vr1  //256-ver[y]
+
+    or             t1,      zero,    zero  //xx
+    srai.d         t2,      a3,      3     //loop max
+    beqz           t2,      .IPRED_SMOOTH_V_W_LOOP4
+
+.IPRED_SMOOTH_V_W_LOOP8:
+    fldx.d         f4,      t0,      t1   //topleft[x]
+    vsllwil.hu.bu  vr4,     vr4,     0
+
+    vmul.h         vr6,     vr5,     vr0
+    vmadd.h        vr6,     vr1,     vr4  //pred
+    vadd.h         vr6,     vr6,     vr3
+    vsrlni.b.h     vr6,     vr6,     8
+
+    fstx.d         f6,      a0,      t1
+
+    addi.d         t1,      t1,      8
+    addi.d         t2,      t2,      -1
+    bnez           t2,      .IPRED_SMOOTH_V_W_LOOP8
+    b              .IPRED_SMOOTH_V_W_LOOP_END
+
+.IPRED_SMOOTH_V_W_LOOP4:
+    fldx.s         f4,      t0,      t1   //topleft[x]
+    vsllwil.hu.bu  vr4,     vr4,     0
+
+    vmul.h         vr6,     vr5,     vr0
+    vmadd.h        vr6,     vr1,     vr4  //pred
+    vadd.h         vr6,     vr6,     vr3
+    vsrai.h        vr6,     vr6,     8
+    vsrlni.b.h     vr6,     vr6,     0
+
+    fstx.s         f6,      a0,      t1
+
+    addi.d         t1,      t1,      4
+
+.IPRED_SMOOTH_V_W_LOOP_END:
+    addi.d         a5,      a5,      1
+    add.d          a0,      a0,      a1
+    addi.d         a4,      a4,      -1
+    bnez           a4,      .IPRED_SMOOTH_V_H_LOOP
+
+endfunc
+
+// void ipred_smooth_h_lsx(pixel *dst, const ptrdiff_t stride,
+//                         const pixel *const topleft,
+//                         const int width, const int height, const int a,
+//                         const int max_width, const int max_height
+//                         HIGHBD_DECL_SUFFIX)
+function ipred_smooth_h_8bpc_lsx
+    la.local       a5,      dav1d_sm_weights
+    add.d          a6,      a5,      a3  //hor
+
+    add.d          a7,      a2,      a3
+    vldrepl.b      vr0,     a7,      0  //right
+    vsllwil.hu.bu  vr0,     vr0,     0
+
+    li.w           t0,      256
+    vreplgr2vr.h   vr1,     t0
+    li.w           t0,      128
+    vreplgr2vr.h   vr2,     t0
+
+    addi.d         t3,      a2,      -1  //ptr topleft[y]
+
+.IPRED_SMOOTH_H_H_LOOP:
+    vldrepl.b      vr3,     t3,      0  //topleft[y]
+    vsllwil.hu.bu  vr3,     vr3,     0
+
+    or             t1,      zero,    zero  //xx
+    srai.d         t2,      a3,      3     //loop max
+    beqz           t2,      .IPRED_SMOOTH_H_W_LOOP4
+
+.IPRED_SMOOTH_H_W_LOOP8:
+    fldx.d         f5,      a6,      t1   //hor[x]
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsub.h         vr4,     vr1,     vr5  //256-hor[x]
+
+    vmul.h         vr6,     vr4,     vr0
+    vmadd.h        vr6,     vr5,     vr3  //pred
+    vadd.h         vr6,     vr6,     vr2
+    vsrlni.b.h     vr6,     vr6,     8
+
+    fstx.d         f6,      a0,      t1
+
+    addi.d         t1,      t1,      8
+    addi.d         t2,      t2,      -1
+    bnez           t2,      .IPRED_SMOOTH_H_W_LOOP8
+    b              .IPRED_SMOOTH_W_H_LOOP_END
+
+.IPRED_SMOOTH_H_W_LOOP4:
+    fldx.s         f5,      a6,      t1   //hor[x]
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsub.h         vr4,     vr1,     vr5  //256-hor[x]
+
+    vmul.h         vr6,     vr4,     vr0
+    vmadd.h        vr6,     vr5,     vr3  //pred
+    vadd.h         vr6,     vr6,     vr2
+    vsrai.h        vr6,     vr6,     8
+    vsrlni.b.h     vr6,     vr6,     0
+
+    fstx.s         f6,      a0,      t1
+
+    addi.d         t1,      t1,      4
+
+.IPRED_SMOOTH_W_H_LOOP_END:
+    addi.d         t3,      t3,      -1
+    add.d          a0,      a0,      a1
+    addi.d         a4,      a4,      -1
+    bnez           a4,      .IPRED_SMOOTH_H_H_LOOP
+
+endfunc
+
+// void pal_pred_lsx(pixel *dst, const ptrdiff_t stride,
+//                   const pixel *const pal, const uint8_t *idx,
+//                   const int w, const int h)
+function pal_pred_8bpc_lsx
+    srai.d         a7,      a5,      2
+
+.PAL_PRED_WLOOP4:
+    andi           a6,      a4,      4
+    beqz           a6,      .PAL_PRED_WLOOP8
+    fld.d          f0,      a3,      0
+    vsrli.b        vr1,     vr0,     4
+    vandi.b        vr2,     vr0,     7
+    vilvl.b        vr0,     vr1,     vr2
+    fld.d          f1,      a2,      0
+    vshuf.b        vr2,     vr1,     vr1,    vr0
+
+    vstelm.w       vr2,     a0,      0,      0
+    add.d          a0,      a0,      a1
+    vstelm.w       vr2,     a0,      0,      1
+    add.d          a0,      a0,      a1
+    vstelm.w       vr2,     a0,      0,      2
+    add.d          a0,      a0,      a1
+    vstelm.w       vr2,     a0,      0,      3
+    add.d          a0,      a0,      a1
+
+    addi.d         a3,      a3,      8
+    addi.d         a7,      a7,      -1
+    bnez           a7,      .PAL_PRED_WLOOP4
+    b              .PAL_PRED_END
+
+.PAL_PRED_WLOOP8:
+    andi           a6,      a4,      8
+    beqz           a6,      .PAL_PRED_WLOOP16
+
+    vld            vr0,     a3,      0
+    vsrli.b        vr1,     vr0,     4
+    vandi.b        vr2,     vr0,     7
+    vilvl.b        vr0,     vr1,     vr2
+    vilvh.b        vr3,     vr1,     vr2
+    fld.d          f1,      a2,      0
+    vshuf.b        vr0,     vr1,     vr1,    vr0
+    vshuf.b        vr3,     vr1,     vr1,    vr3
+
+    vstelm.d       vr0,     a0,      0,      0
+    add.d          a0,      a0,      a1
+    vstelm.d       vr0,     a0,      0,      1
+    add.d          a0,      a0,      a1
+
+    vstelm.d       vr3,     a0,      0,      0
+    add.d          a0,      a0,      a1
+    vstelm.d       vr3,     a0,      0,      1
+    add.d          a0,      a0,      a1
+
+    addi.d         a3,      a3,      16
+    addi.d         a7,      a7,      -1
+    bnez           a7,      .PAL_PRED_WLOOP8
+    b              .PAL_PRED_END
+
+.PAL_PRED_WLOOP16:
+    andi           a6,      a4,      16
+    beqz           a6,      .PAL_PRED_WLOOP32
+
+    vld            vr0,     a3,      0
+    vld            vr1,     a3,      16
+    fld.d          f6,      a2,      0
+    vsrli.b        vr2,     vr0,     4
+    vandi.b        vr3,     vr0,     7
+    vsrli.b        vr4,     vr1,     4
+    vandi.b        vr5,     vr1,     7
+    vilvl.b        vr0,     vr2,     vr3
+    vilvh.b        vr1,     vr2,     vr3
+    vilvl.b        vr2,     vr4,     vr5
+    vilvh.b        vr3,     vr4,     vr5
+    vshuf.b        vr0,     vr6,     vr6,    vr0
+    vshuf.b        vr1,     vr6,     vr6,    vr1
+    vshuf.b        vr2,     vr6,     vr6,    vr2
+    vshuf.b        vr3,     vr6,     vr6,    vr3
+
+    vst            vr0,     a0,      0
+    add.d          a0,      a0,      a1
+    vst            vr1,     a0,      0
+    add.d          a0,      a0,      a1
+    vst            vr2,     a0,      0
+    add.d          a0,      a0,      a1
+    vst            vr3,     a0,      0
+    add.d          a0,      a0,      a1
+
+    addi.d         a3,      a3,      32
+    addi.d         a7,      a7,      -1
+    bnez           a7,      .PAL_PRED_WLOOP16
+    b              .PAL_PRED_END
+
+.PAL_PRED_WLOOP32:
+    andi           a6,      a4,      32
+    beqz           a6,      .PAL_PRED_WLOOP64
+
+    vld            vr0,     a3,      0
+    vld            vr1,     a3,      16
+    vld            vr2,     a3,      32
+    vld            vr3,     a3,      48
+    fld.d          f4,      a2,      0
+    vsrli.b        vr5,     vr0,     4
+    vandi.b        vr6,     vr0,     7
+    vsrli.b        vr7,     vr1,     4
+    vandi.b        vr8,     vr1,     7
+    vsrli.b        vr9,     vr2,     4
+    vandi.b        vr10,    vr2,     7
+    vsrli.b        vr11,    vr3,     4
+    vandi.b        vr12,    vr3,     7
+    vilvl.b        vr0,     vr5,     vr6
+    vilvh.b        vr1,     vr5,     vr6
+    vilvl.b        vr2,     vr7,     vr8
+    vilvh.b        vr3,     vr7,     vr8
+    vilvl.b        vr5,     vr9,     vr10
+    vilvh.b        vr6,     vr9,     vr10
+    vilvl.b        vr7,     vr11,    vr12
+    vilvh.b        vr8,     vr11,    vr12
+    vshuf.b        vr0,     vr4,     vr4,    vr0
+    vshuf.b        vr1,     vr4,     vr4,    vr1
+    vshuf.b        vr2,     vr4,     vr4,    vr2
+    vshuf.b        vr3,     vr4,     vr4,    vr3
+    vshuf.b        vr5,     vr4,     vr4,    vr5
+    vshuf.b        vr6,     vr4,     vr4,    vr6
+    vshuf.b        vr7,     vr4,     vr4,    vr7
+    vshuf.b        vr8,     vr4,     vr4,    vr8
+
+    vst            vr0,     a0,      0
+    vst            vr1,     a0,      16
+    add.d          a0,      a0,      a1
+    vst            vr2,     a0,      0
+    vst            vr3,     a0,      16
+    add.d          a0,      a0,      a1
+    vst            vr5,     a0,      0
+    vst            vr6,     a0,      16
+    add.d          a0,      a0,      a1
+    vst            vr7,     a0,      0
+    vst            vr8,     a0,      16
+    add.d          a0,      a0,      a1
+
+    addi.d         a3,      a3,      64
+    addi.d         a7,      a7,      -1
+    bnez           a7,      .PAL_PRED_WLOOP32
+    b              .PAL_PRED_END
+
+.PAL_PRED_WLOOP64:
+    vld            vr0,     a3,      0
+    vld            vr1,     a3,      16
+    fld.d          f2,      a2,      0
+    vsrli.b        vr3,     vr0,     4
+    vandi.b        vr4,     vr0,     7
+    vsrli.b        vr5,     vr1,     4
+    vandi.b        vr6,     vr1,     7
+    vilvl.b        vr0,     vr3,     vr4
+    vilvh.b        vr1,     vr3,     vr4
+    vilvl.b        vr3,     vr5,     vr6
+    vilvh.b        vr4,     vr5,     vr6
+    vshuf.b        vr0,     vr2,     vr2,    vr0
+    vshuf.b        vr1,     vr2,     vr2,    vr1
+    vshuf.b        vr3,     vr2,     vr2,    vr3
+    vshuf.b        vr4,     vr2,     vr2,    vr4
+
+    vst            vr0,     a0,      0
+    vst            vr1,     a0,      16
+    vst            vr3,     a0,      32
+    vst            vr4,     a0,      48
+
+    add.d          a0,      a0,      a1
+    addi.d         a3,      a3,      32
+    addi.d         a5,      a5,      -1
+    bnez           a5,      .PAL_PRED_WLOOP64
+
+.PAL_PRED_END:
+endfunc
+
+.macro apply_sign_vrh v, s, vrzero, vrt0 ,out
+    vslt.h         \vrt0,   \s,      \vrzero
+    vandn.v        \s,      \vrt0,   \v
+    vsigncov.h     \v,      \vrt0,   \v
+    vor.v          \out,    \s,      \v
+.endm
+
+.macro iclip_pixel_vrh in0, in1, in2, tmp0, tmp1, out
+    vmin.h         \tmp0,   \in2,    \in0
+    vslt.h         \in0,    \in0,    \in1
+    vand.v         \tmp1,   \in0,    \in1
+    vandn.v        \tmp0,   \in0,    \tmp0
+    vor.v          \out,    \tmp1,   \tmp0
+.endm
+
+.macro ipred_cfl_pred dst, stride, w, h, dc, ac, alpha
+    vreplgr2vr.h   vr2,     \alpha
+    vreplgr2vr.h   vr7,     \dc
+    li.w           t1,      32
+    vreplgr2vr.h   vr3,     t1
+    vxor.v         vr4,     vr4,     vr4
+    li.w           t1,      255
+    vreplgr2vr.h   vr6,     t1
+    add.d          t4,      \w,      \w
+
+1:
+    or             t1,      zero,    zero
+    or             t2,      zero,    zero
+    srai.d         t3,      \w,      3
+    beqz           t3,      3f
+
+2:
+    vldx           vr0,     \ac,     t1
+    vmul.h         vr1,     vr2,     vr0
+    vadda.h        vr0,     vr1,     vr3
+    vsrai.h        vr0,     vr0,     6
+    apply_sign_vrh vr0, vr1, vr4, vr5, vr0
+    vadd.h         vr1,     vr0,     vr7
+    iclip_pixel_vrh vr1, vr4, vr6, vr5, vr8, vr0
+    vsrlni.b.h     vr0,     vr0,     0
+    fstx.d         f0,      \dst,    t2
+
+    addi.d         t1,      t1,      16
+    addi.d         t2,      t2,      8
+    addi.d         t3,      t3,      -1
+    bnez           t3,      2b
+    b              4f
+
+3:
+    fld.d          f0,      \ac,     0
+    vmul.h         vr1,     vr2,     vr0
+    vadda.h        vr0,     vr1,     vr3
+    vsrai.h        vr0,     vr0,     6
+    apply_sign_vrh vr0, vr1, vr4, vr5, vr0
+    vadd.h         vr1,     vr0,     vr7
+    iclip_pixel_vrh vr1, vr4, vr6, vr5, vr8, vr0
+    vsrlni.b.h     vr0,     vr0,     0
+    fst.s          f0,      \dst,    0
+
+4:
+    add.d          \ac,     \ac,     t4
+    add.d          \dst,    \dst,    \stride
+    addi.d         \h,      \h,      -1
+    bnez           \h,      1b
+.endm
+
+function ipred_cfl_8bpc_lsx
+    ipred_dc_gen   a2, a3, a4
+    ipred_cfl_pred a0, a1, a3, a4, t0, a5, a6
+endfunc
+
+function ipred_cfl_top_8bpc_lsx
+    ipred_dc_gen_top   a2, a3
+    ipred_cfl_pred a0, a1, a3, a4, t0, a5, a6
+endfunc
+
+function ipred_cfl_left_8bpc_lsx
+    ipred_dc_gen_left   a2, a4
+    ipred_cfl_pred a0, a1, a3, a4, t0, a5, a6
+endfunc
+
+function ipred_cfl_128_8bpc_lsx
+    li.w           t0,      128
+    ipred_cfl_pred a0, a1, a3, a4, t0, a5, a6
+endfunc
+
+const dav1d_filter_intra_taps_lsx
+    //arr0  8*7
+.byte    -6, -5, -3, -3, -4, -3, -3, -3
+.byte    10,  2,  1,  1,  6,  2,  2,  1
+.byte    0, 10,  1,  1,  0,  6,  2,  2
+.byte    0,  0, 10,  2,  0,  0,  6,  2
+.byte    0,  0,  0, 10,  0,  0,  0,  6
+.byte    12,  9,  7,  5,  2,  2,  2,  3
+.byte    0,  0,  0,  0, 12,  9,  7,  5
+    //arr1
+.byte    -10,  -6,  -4,  -2, -10,  -6,  -4,  -2
+.byte    16,   0,   0,   0,  16,   0,   0,   0
+.byte    0,  16,   0,   0,   0,  16,   0,   0
+.byte    0,   0,  16,   0,   0,   0,  16,   0
+.byte    0,   0,   0,  16,   0,   0,   0,  16
+.byte    10,   6,   4,   2,   0,   0,   0,   0
+.byte    0,   0,   0,   0,  10,   6,   4,   2
+    //arr2
+.byte    -8,  -8,  -8,  -8,  -4,  -4,  -4,  -4
+.byte    8,   0,   0,   0,   4,   0,   0,   0
+.byte    0,   8,   0,   0,   0,   4,   0,   0
+.byte    0,   0,   8,   0,   0,   0,   4,   0
+.byte    0,   0,   0,   8,   0,   0,   0,   4
+.byte    16,  16,  16,  16,   0,   0,   0,   0
+.byte    0,   0,   0,   0,  16,  16,  16,  16
+    //arr3
+.byte    -2,  -1,  -1,   0,  -1,  -1,  -1,  -1
+.byte    8,   3,   2,   1,   4,   3,   2,   2
+.byte    0,   8,   3,   2,   0,   4,   3,   2
+.byte    0,   0,   8,   3,   0,   0,   4,   3
+.byte    0,   0,   0,   8,   0,   0,   0,   4
+.byte    10,   6,   4,   2,   3,   4,   4,   3
+.byte    0,   0,   0,   0,  10,   6,   4,   3
+    //arr4
+.byte    -12, -10,  -9,  -8, -10,  -9,  -8,  -7
+.byte    14,   0,   0,   0,  12,   1,   0,   0
+.byte    0,  14,   0,   0,   0,  12,   0,   0
+.byte    0,   0,  14,   0,   0,   0,  12,   1
+.byte    0,   0,   0,  14,   0,   0,   0,  12
+.byte    14,  12,  11,  10,   0,   0,   1,   1
+.byte    0,   0,   0,   0,  14,  12,  11,   9
+endconst
+
+.macro ipred_filter_load_p
+    vldrepl.b      vr0,     t0,      0
+    vldrepl.b      vr1,     a7,      0
+    vldrepl.b      vr2,     a7,      1
+    vldrepl.b      vr3,     a7,      2
+    vldrepl.b      vr4,     a7,      3
+    vldrepl.b      vr5,     t1,      0
+    vldrepl.b      vr6,     t1,      -1
+
+    vsllwil.hu.bu  vr0,     vr0,     0
+    vsllwil.hu.bu  vr1,     vr1,     0
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr3,     vr3,     0
+    vsllwil.hu.bu  vr4,     vr4,     0
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsllwil.hu.bu  vr6,     vr6,     0
+.endm
+
+.macro ipred_filter_loadx_p
+    vldrepl.b      vr0,     t0,      0
+    vldrepl.b      vr1,     a7,      0
+    vldrepl.b      vr2,     a7,      1
+    vldrepl.b      vr3,     a7,      2
+    vldrepl.b      vr4,     a7,      3
+    vldrepl.b      vr5,     t1,      0
+    ldx.bu         t3,      t1,      a1
+    vreplgr2vr.b   vr6,     t3
+
+    vsllwil.hu.bu  vr0,     vr0,     0
+    vsllwil.hu.bu  vr1,     vr1,     0
+    vsllwil.hu.bu  vr2,     vr2,     0
+    vsllwil.hu.bu  vr3,     vr3,     0
+    vsllwil.hu.bu  vr4,     vr4,     0
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsllwil.hu.bu  vr6,     vr6,     0
+.endm
+
+.macro ipred_filter_load_fltptr
+    fld.d          f7,      a6,      0
+    fld.d          f8,      a6,      8
+    fld.d          f9,      a6,      16
+    fld.d          f10,     a6,      24
+    fld.d          f11,     a6,      32
+    fld.d          f12,     a6,      40
+    fld.d          f13,     a6,      48
+
+    vsllwil.h.b    vr7,     vr7,     0
+    vsllwil.h.b    vr8,     vr8,     0
+    vsllwil.h.b    vr9,     vr9,     0
+    vsllwil.h.b    vr10,    vr10,    0
+    vsllwil.h.b    vr11,    vr11,    0
+    vsllwil.h.b    vr12,    vr12,    0
+    vsllwil.h.b    vr13,    vr13,    0
+.endm
+
+.macro ipred_filter_calc_acc
+    vmul.h         vr7,     vr7,     vr0
+    vmadd.h        vr7,     vr8,     vr1
+    vmadd.h        vr7,     vr9,     vr2
+    vmadd.h        vr7,     vr10,    vr3
+    vmadd.h        vr7,     vr11,    vr4
+    vmadd.h        vr7,     vr12,    vr5
+    vmadd.h        vr7,     vr13,    vr6
+    vaddi.hu       vr7,     vr7,     8
+    vsrai.h        vr7,     vr7,     4
+    iclip_pixel_vrh vr7, vr14, vr15, vr9, vr10, vr8
+    vsrlni.b.h     vr8,     vr8,     0
+.endm
+
+// void ipred_filter_lsx(pixel *dst, const ptrdiff_t stride,
+//                       const pixel *const topleft_in,
+//                       const int width, const int height, int filt_idx,
+//                       const int max_width, const int max_height
+//                       HIGHBD_DECL_SUFFIX)
+function ipred_filter_8bpc_lsx
+    andi           a5,      a5,      511
+    la.local       a6,      dav1d_filter_intra_taps_lsx
+    li.w           a7,      56
+    mul.w          a7,      a7,      a5
+    add.d          a6,      a6,      a7   //*filter
+    addi.d         a7,      a2,      1    //*top
+    or             a5,      zero,    zero //y
+    vxor.v         vr14,    vr14,    vr14
+    li.w           t0,      255
+    vreplgr2vr.h   vr15,    t0
+
+.FILTER_LOOP_H:
+    sub.d          t0,      a2,      a5   //*topleft
+    addi.d         t1,      t0,      -1   //left
+
+    ctz.w          t2,      a3
+    addi.d         t3,      t2,      -2
+    beqz           t3,      .FILTER_LOOP_W4
+    addi.d         t3,      t2,      -3
+    beqz           t3,      .FILTER_LOOP_W8
+    addi.d         t3,      t2,      -4
+    beqz           t3,      .FILTER_LOOP_W16
+    addi.d         t3,      t2,      -5
+    beqz           t3,      .FILTER_LOOP_W32
+
+.FILTER_LOOP_W4:
+    ipred_filter_load_p
+
+    or             t3,      a0,      a0  //*ptr
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    b              .FILTER_LOOP_W_END
+
+.FILTER_LOOP_W8:
+    ipred_filter_load_p
+
+    or             t3,      a0,      a0
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      3
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      4
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    b              .FILTER_LOOP_W_END
+
+.FILTER_LOOP_W16:
+    ipred_filter_load_p
+
+    or             t3,      a0,      a0
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      3
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      4
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      7
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      8
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      11
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      12
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    b              .FILTER_LOOP_W_END
+
+.FILTER_LOOP_W32:
+    ipred_filter_load_p
+
+    or             t3,      a0,      a0
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      3
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      4
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      7
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      8
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      11
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      12
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      15
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      16
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      19
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      20
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      23
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      24
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+    addi.d         t1,      a0,      27
+    addi.d         a7,      a7,      4
+    addi.d         t0,      a7,      -1
+
+    ipred_filter_loadx_p
+
+    addi.d         t3,      a0,      28
+
+    ipred_filter_load_fltptr
+    ipred_filter_calc_acc
+
+    fst.s          f8,      t3,      0
+    add.d          t3,      t3,      a1
+    vstelm.w       vr8,     t3,      0,      1
+    add.d          t3,      t3,      a1
+
+.FILTER_LOOP_W_END:
+    add.d          a7,      a0,      a1
+    add.d          t2,      a1,      a1
+    add.d          a0,      a0,      t2
+    addi.d         a5,      a5,      2
+    blt            a5,      a4,      .FILTER_LOOP_H
+endfunc
+
+const dav1d_dr_intra_derivative
+    // Values that are 0 will never be used
+    .short  0         // Angles:
+    .short  1023, 0   //  3,  93, 183
+    .short  547       //  6,  96, 186
+    .short  372, 0, 0 //  9,  99, 189
+    .short  273       // 14, 104, 194
+    .short  215, 0    // 17, 107, 197
+    .short  178       // 20, 110, 200
+    .short  151, 0    // 23, 113, 203 (113 & 203 are base angles)
+    .short  132       // 26, 116, 206
+    .short  116, 0    // 29, 119, 209
+    .short  102, 0    // 32, 122, 212
+    .short  90        // 36, 126, 216
+    .short  80, 0     // 39, 129, 219
+    .short  71        // 42, 132, 222
+    .short  64, 0     // 45, 135, 225 (45 & 135 are base angles)
+    .short  57        // 48, 138, 228
+    .short  51, 0     // 51, 141, 231
+    .short  45, 0     // 54, 144, 234
+    .short  40        // 58, 148, 238
+    .short  35, 0     // 61, 151, 241
+    .short  31        // 64, 154, 244
+    .short  27, 0     // 67, 157, 247 (67 & 157 are base angles)
+    .short  23        // 70, 160, 250
+    .short  19, 0     // 73, 163, 253
+    .short  15, 0     // 76, 166, 256
+    .short  11, 0     // 81, 171, 261
+    .short  7         // 84, 174, 264
+    .short  3         // 87, 177, 267
+endconst
+
+const z1_upsample_edge_kernel
+    .short  -1, 9, 9, -1, -1, 9, 9, -1
+endconst
+
+const ipred_filter_edge_kernel1
+    .short  0, 4, 8, 4, 0, 4, 8, 4
+    .short  0, 5, 6, 5, 0, 5, 6, 5
+    .short  2, 4, 4, 4, 2, 4, 4, 4
+endconst
+
+const ipred_filter_edge_kernel2
+    .short  0, 0, 0, 0, 0, 0, 0, 0
+    .short  0, 0, 0, 0, 0, 0, 0, 0
+    .short  2, 2, 2, 2, 2, 2, 2, 2
+endconst
+
+.macro z1_upsample_edge_calc_loop
+    vsllwil.hu.bu  vr10,    vr7,     0
+    vsllwil.hu.bu  vr11,    vr11,    0
+    vsllwil.hu.bu  vr12,    vr12,    0
+    vsllwil.hu.bu  vr13,    vr13,    0
+
+    vmul.h         vr10,    vr10,    vr0
+    vmul.h         vr11,    vr11,    vr0
+    vmul.h         vr12,    vr12,    vr0
+    vmul.h         vr13,    vr13,    vr0
+
+    vhaddw.w.h     vr10,    vr10,    vr10
+    vhaddw.w.h     vr11,    vr11,    vr11
+    vhaddw.w.h     vr12,    vr12,    vr12
+    vhaddw.w.h     vr13,    vr13,    vr13
+    vhaddw.d.w     vr10,    vr10,    vr10
+    vhaddw.d.w     vr11,    vr11,    vr11
+    vhaddw.d.w     vr12,    vr12,    vr12
+    vhaddw.d.w     vr13,    vr13,    vr13
+
+    vpackev.h      vr10,    vr11,    vr10
+    vpackev.h      vr11,    vr13,    vr12
+    vpackev.w      vr12,    vr11,    vr10  //s:01234567
+    vsrari.h       vr12,    vr12,    4
+    iclip_pixel_vrh vr12, vr15, vr16, vr10, vr11, vr12
+    vsrlni.b.h     vr12,    vr12,    0  //out: 13579...
+    vbsrl.v        vr11,    vr7,     1  //out:02468...
+    vilvl.b        vr13,    vr12,    vr11
+.endm
+
+.macro z1_upsample_edge_data_init1
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vbsrl.v        vr13,    vr7,     3
+    z1_upsample_edge_calc_loop
+.endm
+
+.macro z1_upsample_edge_data_init2
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x76
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_upsample_edge_calc_loop
+.endm
+
+.macro z1_upsample_edge_calc_other
+    vsllwil.hu.bu  vr10,    vr7,     0
+    vmul.h         vr10,    vr10,    vr0
+    vhaddw.w.h     vr10,    vr10,    vr10
+    vhaddw.d.w     vr10,    vr10,    vr10
+    vreplvei.h     vr12,    vr10,    0   //s0-s7
+    vsrari.h       vr12,    vr12,    4
+
+    iclip_pixel_vrh vr12, vr15, vr16, vr10, vr11, vr12
+    vsrlni.b.h     vr12,    vr12,    0
+    vilvl.b        vr13,    vr12,    vr7
+.endm
+
+.macro z1_filter_edge_calc_loop1
+    vmul.h         vr10,    vr10,    vr1
+    vmul.h         vr11,    vr11,    vr1
+    vmul.h         vr12,    vr12,    vr1
+    vmul.h         vr13,    vr13,    vr1
+
+    vhaddw.w.h     vr10,    vr10,    vr10
+    vhaddw.w.h     vr11,    vr11,    vr11
+    vhaddw.w.h     vr12,    vr12,    vr12
+    vhaddw.w.h     vr13,    vr13,    vr13
+    vhaddw.d.w     vr10,    vr10,    vr10
+    vhaddw.d.w     vr11,    vr11,    vr11
+    vhaddw.d.w     vr12,    vr12,    vr12
+    vhaddw.d.w     vr13,    vr13,    vr13
+
+    vpackev.h      vr10,    vr11,    vr10
+    vpackev.h      vr11,    vr13,    vr12
+    vpackev.w      vr10,    vr11,    vr10  //s:01234567
+.endm
+
+.macro z1_filter_edge_calc_loop2
+    vsllwil.hu.bu  vr13,    vr13,    0
+    vmadd.h        vr10,    vr13,    vr6
+    vsrari.h       vr12,    vr10,    4
+    vsrlni.b.h     vr12,    vr12,    0  //out: 0-7
+.endm
+
+.macro z1_filter_edge_calc_other
+    vsllwil.hu.bu  vr10,    vr10,    0
+    vmul.h         vr11,    vr10,    vr1
+    vhaddw.w.h     vr11,    vr11,    vr11
+    vhaddw.d.w     vr11,    vr11,    vr11
+    vreplvei.h     vr12,    vr11,    4
+    vextrins.h     vr12,    vr11,    0x00
+
+    vreplvei.h     vr13,    vr10,    1
+    vmadd.h        vr12,    vr13,    vr6
+    vsrari.h       vr12,    vr12,    4
+    vsrlni.b.h     vr12,    vr12,    0  //out: 0-7
+.endm
+
+.macro z1_filter_edge_data_init1
+    vbsll.v        vr10,    vr7,     1
+    vextrins.b     vr10,    vr10,    0x01
+    vbsrl.v        vr12,    vr7,     1
+    vbsrl.v        vr13,    vr7,     2
+    vsllwil.hu.bu  vr10,    vr10,    0
+    vsllwil.hu.bu  vr11,    vr7,     0
+    vsllwil.hu.bu  vr12,    vr12,    0
+    vsllwil.hu.bu  vr13,    vr13,    0
+    z1_filter_edge_calc_loop1
+.endm
+
+.macro z1_filter_edge_data_init2
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vbsrl.v        vr13,    vr7,     3
+    vsllwil.hu.bu  vr10,    vr7,     0
+    vsllwil.hu.bu  vr11,    vr11,    0
+    vsllwil.hu.bu  vr12,    vr12,    0
+    vsllwil.hu.bu  vr13,    vr13,    0
+    z1_filter_edge_calc_loop1
+.endm
+
+.macro z1_filter_edge_data_init3
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x76
+    vsllwil.hu.bu  vr10,    vr7,     0
+    vsllwil.hu.bu  vr11,    vr11,    0
+    vsllwil.hu.bu  vr12,    vr12,    0
+    vsllwil.hu.bu  vr13,    vr13,    0
+    z1_filter_edge_calc_loop1
+.endm
+
+.macro z1_filter_edge_data_init4
+    vbsll.v        vr10,    vr7,     1
+    vextrins.b     vr10,    vr10,    0x01
+    vbsrl.v        vr12,    vr7,     1
+    vbsrl.v        vr13,    vr7,     2
+    vextrins.b     vr13,    vr13,    0x76
+    vsllwil.hu.bu  vr10,    vr10,    0
+    vsllwil.hu.bu  vr11,    vr7,     0
+    vsllwil.hu.bu  vr12,    vr12,    0
+    vsllwil.hu.bu  vr13,    vr13,    0
+    z1_filter_edge_calc_loop1
+.endm
+
+.macro pixel_set_8bpc_allw dst_ptr, src_ptr, width, tmp0, tmp1
+    vldrepl.b      vr10,    \src_ptr, 0
+    or             \tmp1,   zero,     zero
+    srai.d         \tmp0,   \width,   4
+    beqz           \tmp0,   2f
+1:
+    vstx           vr10,    \dst_ptr, \tmp1
+    addi.d         \tmp1,   \tmp1,    16
+    addi.d         \tmp0,   \tmp0,    -1
+    bnez           \tmp0,   1b
+2:
+    andi           \tmp0,   \width,   8
+    beqz           \tmp0,   3f
+    fstx.d         f10,     \dst_ptr, \tmp1
+    addi.d         \tmp1,   \tmp1,    8
+3:
+    andi           \tmp0,   \width,   4
+    beqz           \tmp0,   4f
+    fstx.s         f10,     \dst_ptr, \tmp1
+    addi.d         \tmp1,   \tmp1,    4
+4:
+    andi           \tmp0,   \width,   2
+    beqz           \tmp0,   5f
+    ldx.bu         \tmp0,   \src_ptr, zero
+    stx.b          \tmp0,   \dst_ptr, \tmp1
+    addi.d         \tmp1,   \tmp1,    1
+    stx.b          \tmp0,   \dst_ptr, \tmp1
+    addi.d         \tmp1,   \tmp1,    1
+5:
+    andi           \tmp0,   \width,   1
+    beqz           \tmp0,   6f
+    ldx.bu         \tmp0,   \src_ptr, zero
+    stx.b          \tmp0,   \dst_ptr, \tmp1
+6:
+.endm
+
+// void ipred_z1_lsx(pixel *dst, const ptrdiff_t stride,
+//                   const pixel *const topleft_in,
+//                   const int width, const int height, int angle,
+//                   const int max_width, const int max_height
+//                   HIGHBD_DECL_SUFFIX)
+function ipred_z1_8bpc_lsx
+    addi.d         a2,      a2,      1   //&topleft_in[1]
+    addi.d         sp,      sp,      -128
+    or             t2,      sp,      sp  //top_out
+    srai.d         a6,      a5,      9
+    andi           a6,      a6,      1   //is_sum
+    srai.d         a7,      a5,      10  //enable_intra_edge_filter
+    andi           a5,      a5,      511
+
+    la.local       t0,      dav1d_dr_intra_derivative
+    andi           t1,      a5,      0xFFE
+    ldx.hu         t1,      t0,      t1  //dx
+
+    beqz           a7,      .IPRED_Z1_NOTUA
+    add.d          t3,      a3,      a4
+    li.w           t4,      90
+    sub.w          t4,      t4,      a5
+    // ipred_get_upsample t5:upsample_above
+    li.w           t6,      16
+    sra.d          t6,      t6,      a6
+    bge            t6,      t3,      .Z1_GETUS1
+    addi.d         t5,      zero,    0
+    b              .Z1_GETUS2
+.Z1_GETUS1:
+    addi.d         t5,      zero,    1
+.Z1_GETUS2:
+    li.w           t6,      40
+    blt            t4,      t6,      .Z1_GETUS3
+    addi.d         t6,      zero,    0
+    b              .Z1_GETUS4
+.Z1_GETUS3:
+    addi.d         t6,      zero,    1
+.Z1_GETUS4:
+    and            t5,      t5,      t6
+
+    beqz           t5,      .IPRED_Z1_NOTUA
+
+    la.local       t0,      z1_upsample_edge_kernel
+    vld            vr0,     t0,      0   //kernel
+    vxor.v         vr15,    vr15,    vr15
+    li.w           t0,      255
+    vreplgr2vr.h   vr16,    t0
+
+.Z1_UEDGE_W4:
+    andi           t6,      a3,     4
+    beqz           t6,      .Z1_UEDGE_W8
+.Z1_UEDGE_W4_H4:
+    andi           t6,      a4,     4
+    beqz           t6,      .Z1_UEDGE_W4_H8
+
+    //0-6
+    vld            vr7,     a2,      -1
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x76
+    vbsrl.v        vr13,    vr7,     3
+    z1_upsample_edge_calc_loop
+
+    fst.d          f13,     t2,     0
+    vstelm.w       vr13,    t2,     8,    2
+    vstelm.h       vr13,    t2,     12,   6
+
+    ld.bu          t7,      a2,     7
+    st.b           t7,      t2,     14
+
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W4_H8:
+    andi           t6,      a4,     8
+    beqz           t6,      .Z1_UEDGE_W4_H16
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,     0
+
+    //8-10
+    vldrepl.b      vr7,     a2,     7
+    z1_upsample_edge_calc_other
+
+    vstelm.w       vr13,    t2,     16,   0
+    vstelm.h       vr13,    t2,     20,   2
+
+    ld.bu          t7,      a2,     7
+    st.b           t7,      t2,     22
+
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W4_H16:
+    andi           t6,      a4,     16
+    beqz           t6,      .Z1_UEDGE_W4_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,     0
+
+    //8-15
+    vldrepl.b      vr7,     a2,     7
+    z1_upsample_edge_calc_other
+    vst            vr13,    t2,     16
+
+    //16-18
+    vstelm.w       vr13,    t2,     32,   0
+    vstelm.h       vr13,    t2,     36,   2
+
+    ld.bu          t7,      a2,     7
+    st.b           t7,      t2,     38
+
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W4_H32:
+    andi           t6,      a4,     32
+    beqz           t6,      .Z1_UEDGE_W4_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,     0
+
+    //8-15
+    vldrepl.b      vr7,     a2,     7
+    z1_upsample_edge_calc_other
+    vst            vr13,    t2,     16
+
+    vst            vr13,    t2,     32 //16-23
+    vst            vr13,    t2,     48 //24-31
+
+    //32-34
+    vstelm.w       vr13,    t2,     64,   0
+    vstelm.h       vr13,    t2,     68,   2
+
+    ld.bu          t7,      a2,     7
+    st.b           t7,      t2,     70
+
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W4_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,     0
+
+    //8-15
+    vldrepl.b      vr7,     a2,     7
+    z1_upsample_edge_calc_other
+    vst            vr13,    t2,     16
+
+    vst            vr13,    t2,     32 //16-23
+    vst            vr13,    t2,     48 //24-31
+    vst            vr13,    t2,     64 //32-39
+    vst            vr13,    t2,     80 //40-47
+    vst            vr13,    t2,     96 //48-55
+    vst            vr13,    t2,     112 //56-63
+
+    //64-66
+    vstelm.w       vr13,    t2,     128,   0
+    vstelm.h       vr13,    t2,     132,   2
+
+    ld.bu          t7,      a2,     7
+    st.b           t7,      t2,     134
+
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W8:
+    andi           t6,      a3,     8
+    beqz           t6,      .Z1_UEDGE_W16
+.Z1_UEDGE_W8_H4:
+    andi           t6,      a4,     4
+    beqz           t6,      .Z1_UEDGE_W8_H8
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x32
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x21
+    vextrins.b     vr13,    vr13,    0x31
+    z1_upsample_edge_calc_loop
+    vstelm.w       vr13,    t2,     16,    0
+    vstelm.h       vr13,    t2,     20,    2
+
+    ld.bu          t7,      a2,     11
+    st.b           t7,      t2,     22
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W8_H8:
+    andi           t6,      a4,     8
+    beqz           t6,      .Z1_UEDGE_W8_H16
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-14
+    vld            vr7,     a2,      7
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x76
+    vbsrl.v        vr13,    vr7,     3
+    z1_upsample_edge_calc_loop
+    fst.d          f13,     t2,     16
+    vstelm.w       vr13,    t2,     24,    2
+    vstelm.h       vr13,    t2,     28,    6
+
+    ld.bu          t7,      a2,     15
+    st.b           t7,      t2,     30
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W8_H16:
+    andi           t6,      a4,     16
+    beqz           t6,      .Z1_UEDGE_W8_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,     16
+
+    //16-22
+    vldrepl.b      vr7,     a2,     15
+    z1_upsample_edge_calc_other
+    fst.d          f13,     t2,     32
+    vstelm.w       vr13,    t2,     40,   2
+    vstelm.h       vr13,    t2,     44,   6
+
+    ld.bu          t7,      a2,     15
+    st.b           t7,      t2,     46
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W8_H32:
+    andi           t6,      a4,     32
+    beqz           t6,      .Z1_UEDGE_W8_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,     16
+
+    //16-23
+    vldrepl.b      vr7,     a2,     15
+    z1_upsample_edge_calc_other
+    vst            vr13,    t2,     32
+
+    vst            vr13,    t2,     48 //24-31
+
+    //32-38
+    fst.d          f13,     t2,     64
+    vstelm.w       vr13,    t2,     72,   2
+    vstelm.h       vr13,    t2,     76,   6
+
+    ld.bu          t7,      a2,     15
+    st.b           t7,      t2,     78
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W8_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,     16
+
+    //16-23
+    vldrepl.b      vr7,     a2,     15
+    z1_upsample_edge_calc_other
+    vst            vr13,    t2,     32
+
+    vst            vr13,    t2,     48 //24-31
+    vst            vr13,    t2,     64 //32-39
+    vst            vr13,    t2,     80 //40-47
+    vst            vr13,    t2,     96 //48-55
+    vst            vr13,    t2,     112 //56-63
+
+    //64-70
+    fst.d          f13,     t2,     128
+    vstelm.w       vr13,    t2,     136,   2
+    vstelm.h       vr13,    t2,     140,   6
+
+    ld.bu          t7,      a2,     15
+    st.b           t7,      t2,     142
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W16:
+    andi           t6,      a3,     16
+    beqz           t6,      .Z1_UEDGE_W32
+.Z1_UEDGE_W16_H4:
+    andi           t6,      a4,     4
+    beqz           t6,      .Z1_UEDGE_W16_H8
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     16
+
+    //16-18
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vstelm.w       vr13,    t2,     32,    0
+    vstelm.h       vr13,    t2,     36,    2
+
+    ld.bu          t7,      a2,     19
+    st.b           t7,      t2,     38
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W16_H8:
+    andi           t6,      a4,     8
+    beqz           t6,      .Z1_UEDGE_W16_H16
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      16
+
+    //16-22
+    vld            vr7,     a2,      15
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x76
+    vbsrl.v        vr13,    vr7,     3
+    z1_upsample_edge_calc_loop
+    fst.d          f13,     t2,     32
+    vstelm.w       vr13,    t2,     40,    2
+    vstelm.h       vr13,    t2,     44,    6
+
+    ld.bu          t7,      a2,     23
+    st.b           t7,      t2,     46
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W16_H16:
+    andi           t6,      a4,     16
+    beqz           t6,      .Z1_UEDGE_W16_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-30
+    vld            vr7,     a2,      23
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x76
+    vbsrl.v        vr13,    vr7,     3
+    z1_upsample_edge_calc_loop
+    fst.d          f13,     t2,     48
+    vstelm.w       vr13,    t2,     56,    2
+    vstelm.h       vr13,    t2,     60,    6
+
+    ld.bu          t7,      a2,     31
+    st.b           t7,      t2,     62
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W16_H32:
+    andi           t6,      a4,     32
+    beqz           t6,      .Z1_UEDGE_W16_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,      48
+
+    //32-39
+    vldrepl.b      vr7,     a2,      31
+    z1_upsample_edge_calc_other
+    vst            vr13,    t2,      64
+
+    //40-46
+    fst.d          f13,     t2,     80
+    vstelm.w       vr13,    t2,     88,    2
+    vstelm.h       vr13,    t2,     92,    6
+
+    ld.bu          t7,      a2,     31
+    st.b           t7,      t2,     94
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W16_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,      48
+
+    //32-39
+    vldrepl.b      vr7,     a2,      31
+    z1_upsample_edge_calc_other
+    vst            vr13,    t2,      64
+
+    vst            vr13,    t2,      80  //40-47
+    vst            vr13,    t2,      96  //48-55
+    vst            vr13,    t2,      112 //56-63
+    vst            vr13,    t2,      128 //64-71
+
+    //72-78
+    fst.d          f13,     t2,     144
+    vstelm.w       vr13,    t2,     152,    2
+    vstelm.h       vr13,    t2,     156,    6
+
+    ld.bu          t7,      a2,     31
+    st.b           t7,      t2,     158
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W32:
+    andi           t6,      a3,     32
+    beqz           t6,      .Z1_UEDGE_W64
+.Z1_UEDGE_W32_H8:
+    andi           t6,      a4,     8
+    beqz           t6,      .Z1_UEDGE_W32_H16
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      48
+
+    //32-38
+    vld            vr7,     a2,      31
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x76
+    vbsrl.v        vr13,    vr7,     3
+    z1_upsample_edge_calc_loop
+    fst.d          f13,     t2,      64
+    vstelm.w       vr13,    t2,      72,    2
+    vstelm.h       vr13,    t2,      76,    6
+
+    ld.bu          t7,      a2,     39
+    st.b           t7,      t2,     78
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W32_H16:
+    andi           t6,      a4,     16
+    beqz           t6,      .Z1_UEDGE_W32_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      48
+
+    //32-39
+    vld            vr7,     a2,      31
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      64
+
+    //40-46
+    vld            vr7,     a2,      39
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x76
+    vbsrl.v        vr13,    vr7,     3
+    z1_upsample_edge_calc_loop
+    fst.d          f13,     t2,      80
+    vstelm.w       vr13,    t2,      88,    2
+    vstelm.h       vr13,    t2,      92,    6
+
+    ld.bu          t7,      a2,     47
+    st.b           t7,      t2,     94
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W32_H32:
+    andi           t6,      a4,     32
+    beqz           t6,      .Z1_UEDGE_W32_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      48
+
+    //32-39
+    vld            vr7,     a2,      31
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      64
+
+    //40-47
+    vld            vr7,     a2,      39
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      80
+
+    //48-55
+    vld            vr7,     a2,      47
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      96
+
+    //56-62
+    vld            vr7,     a2,      55
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vextrins.b     vr12,    vr12,    0x76
+    vbsrl.v        vr13,    vr7,     3
+    z1_upsample_edge_calc_loop
+    fst.d          f13,     t2,      112
+    vstelm.w       vr13,    t2,      120,   2
+    vstelm.h       vr13,    t2,      124,   6
+
+    ld.bu          t7,      a2,     63
+    st.b           t7,      t2,     126
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W32_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      48
+
+    //32-39
+    vld            vr7,     a2,      31
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      64
+
+    //40-47
+    vld            vr7,     a2,      39
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      80
+
+    //48-55
+    vld            vr7,     a2,      47
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      96
+
+    //56-63
+    vld            vr7,     a2,      55
+    z1_upsample_edge_data_init2
+    vst            vr13,    t2,      112
+
+    //64-71
+    vldrepl.b      vr7,     a2,      63
+    z1_upsample_edge_calc_other
+    vst            vr13,    t2,      128
+
+    vst            vr13,    t2,      144 //72-79
+    vst            vr13,    t2,      160 //80-87
+
+    //88-94
+    fst.d          f13,     t2,     176
+    vstelm.w       vr13,    t2,     184,    2
+    vstelm.h       vr13,    t2,     188,    6
+
+    ld.bu          t7,      a2,     63
+    st.b           t7,      t2,     190
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W64:
+.Z1_UEDGE_W64_H16:
+    andi           t6,      a4,     16
+    beqz           t6,      .Z1_UEDGE_W64_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      48
+
+    //32-39
+    vld            vr7,     a2,      31
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      64
+
+    //40-47
+    vld            vr7,     a2,      39
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      80
+
+    //48-55
+    vld            vr7,     a2,      47
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      96
+
+    //56-63
+    vld            vr7,     a2,      55
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      112
+
+    //64-71
+    vld            vr7,     a2,      63
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      128
+
+    //72-78
+    vld            vr7,     a2,      71
+    z1_upsample_edge_data_init2
+    fst.d          f13,     t2,     144
+    vstelm.w       vr13,    t2,     152,    2
+    vstelm.h       vr13,    t2,     156,    6
+
+    ld.bu          t7,      a2,     79
+    st.b           t7,      t2,     158
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W64_H32:
+    andi           t6,      a4,     32
+    beqz           t6,      .Z1_UEDGE_W64_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      48
+
+    //32-39
+    vld            vr7,     a2,      31
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      64
+
+    //40-47
+    vld            vr7,     a2,      39
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      80
+
+    //48-55
+    vld            vr7,     a2,      47
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      96
+
+    //56-63
+    vld            vr7,     a2,      55
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      112
+
+    //64-71
+    vld            vr7,     a2,      63
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      128
+
+    //72-79
+    vld            vr7,     a2,      71
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      144
+
+    //80-87
+    vld            vr7,     a2,      79
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      160
+
+    //88-94
+    vld            vr7,     a2,      87
+    z1_upsample_edge_data_init2
+    fst.d          f13,     t2,     176
+    vstelm.w       vr13,    t2,     184,    2
+    vstelm.h       vr13,    t2,     188,    6
+
+    ld.bu          t7,      a2,     95
+    st.b           t7,      t2,     190
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_W64_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,     0
+
+    //8-15
+    vld            vr7,     a2,      7
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      16
+
+    //16-23
+    vld            vr7,     a2,      15
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      32
+
+    //24-31
+    vld            vr7,     a2,      23
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      48
+
+    //32-39
+    vld            vr7,     a2,      31
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      64
+
+    //40-47
+    vld            vr7,     a2,      39
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      80
+
+    //48-55
+    vld            vr7,     a2,      47
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      96
+
+    //56-63
+    vld            vr7,     a2,      55
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      112
+
+    //64-71
+    vld            vr7,     a2,      63
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      128
+
+    //72-79
+    vld            vr7,     a2,      71
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      144
+
+    //80-87
+    vld            vr7,     a2,      79
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      160
+
+    //88-95
+    vld            vr7,     a2,      87
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      176
+
+    //96-103
+    vld            vr7,     a2,      95
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      192
+
+    //104-111
+    vld            vr7,     a2,      103
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      208
+
+    //112-119
+    vld            vr7,     a2,      111
+    z1_upsample_edge_data_init1
+    vst            vr13,    t2,      224
+
+    //120-126
+    vld            vr7,     a2,      119
+    z1_upsample_edge_data_init2
+    fst.d          f13,     t2,      240
+    vstelm.w       vr13,    t2,      248,    2
+    vstelm.h       vr13,    t2,      252,    6
+
+    ld.bu          t7,      a2,      127
+    st.b           t7,      t2,      254
+    b              .Z1_UEDGE_END
+
+.Z1_UEDGE_END:
+    //upsample_edge end
+
+    or             a7,      t2,      t2   //top
+    add.d          t0,      a3,      a4
+    slli.d         t0,      t0,      1
+    addi.d         t0,      t0,      -2   //max_base_x
+    slli.d         t1,      t1,      1
+    b              .IPRED_Z1_UA_END
+
+.IPRED_Z1_NOTUA:
+    or             t5,      zero,    zero  //upsample_above=0
+    beqz           a7,      .IPRED_Z1_NOTFS
+    add.d          a7,      a3,      a4  //w+h
+    li.w           t4,      90
+    sub.d          t4,      t4,      a5
+    // ipred_get_filter_strength a6:filter_strength
+    beqz           a6,      .Z1_GETFS20
+.Z1_GETFS10:  //wh<=8
+    addi.d         t6,      a7,      -8
+    blt            zero,    t6,      .Z1_GETFS11
+    addi.d         t6,      t4,      -64
+    blt            t6,      zero,    .Z1_GETFS101
+    ori            a6,      zero,    2
+    b              .Z1_GETFS40
+.Z1_GETFS101:
+    addi.d         t6,      t4,      -40
+    blt            t6,      zero,    .Z1_GETFS30
+    ori            a6,      zero,    1
+    b              .Z1_GETFS40
+.Z1_GETFS11:  //wh<=16
+    addi.d         t6,      a7,      -16
+    blt            zero,    t6,      .Z1_GETFS12
+    addi.d         t6,      t4,      -48
+    blt            t6,      zero,    .Z1_GETFS111
+    ori            a6,      zero,    2
+    b              .Z1_GETFS40
+.Z1_GETFS111:
+    addi.d         t6,      t4,      -20
+    blt            t6,      zero,    .Z1_GETFS30
+    ori            a6,      zero,    1
+    b              .Z1_GETFS40
+.Z1_GETFS12:  //wh<=24
+    addi.d         t6,      a7,      -24
+    blt            zero,    t6,      .Z1_GETFS13
+    addi.d         t6,      t4,      -4
+    blt            t6,      zero,    .Z1_GETFS30
+    ori            a6,      zero,    3
+    b              .Z1_GETFS40
+.Z1_GETFS13:
+    ori            a6,      zero,    3
+    b              .Z1_GETFS40
+
+.Z1_GETFS20:  //wh<=8
+    addi.d         t6,      a7,      -8
+    blt            zero,    t6,      .Z1_GETFS21
+    addi.d         t6,      t4,      -56
+    blt            t6,      zero,    .Z1_GETFS30
+    ori            a6,      zero,    1
+    b              .Z1_GETFS40
+.Z1_GETFS21:  //wh<=16
+    addi.d         t6,      a7,      -16
+    blt            zero,    t6,      .Z1_GETFS22
+    addi.d         t6,      t4,      -40
+    blt            t6,      zero,    .Z1_GETFS30
+    ori            a6,      zero,    1
+    b              .Z1_GETFS40
+.Z1_GETFS22:  //wh<=24
+    addi.d         t6,      a7,      -24
+    blt            zero,    t6,      .Z1_GETFS23
+    addi.d         t6,      t4,      -32
+    blt            t6,      zero,    .Z1_GETFS221
+    ori            a6,      zero,    3
+    b              .Z1_GETFS40
+.Z1_GETFS221:
+    addi.d         t6,      t4,      -16
+    blt            t6,      zero,    .Z1_GETFS222
+    ori            a6,      zero,    2
+    b              .Z1_GETFS40
+.Z1_GETFS222:
+    addi.d         t6,      t4,      -8
+    blt            t6,      zero,    .Z1_GETFS30
+    ori            a6,      zero,    1
+    b              .Z1_GETFS40
+.Z1_GETFS23:  //wh<=32
+    addi.d         t6,      a7,      -32
+    blt            zero,    t6,      .Z1_GETFS24
+    addi.d         t6,      t4,      -32
+    blt            t6,      zero,    .Z1_GETFS231
+    ori            a6,      zero,    3
+    b              .Z1_GETFS40
+.Z1_GETFS231:
+    addi.d         t6,      t4,      -4
+    blt            t6,      zero,    .Z1_GETFS232
+    ori            a6,      zero,    2
+    b              .Z1_GETFS40
+.Z1_GETFS232:
+    ori            a6,      zero,    1
+    b              .Z1_GETFS40
+.Z1_GETFS24:
+    ori            a6,      zero,    3
+    b              .Z1_GETFS40
+.Z1_GETFS30:
+   or              a6,      zero,    zero
+.Z1_GETFS40:
+
+    beqz           a6,      .IPRED_Z1_NOTFS
+
+.IPRED_Z1_IFFS:
+    // filter_edge
+    addi.d         a6,      a6,      -1
+    slli.d         a6,      a6,      4
+    la.local       t0,      ipred_filter_edge_kernel1
+    vldx           vr1,     t0,      a6    //kernel[0-3]
+
+    la.local       t0,      ipred_filter_edge_kernel2
+    vldx           vr6,     t0,      a6    //kernel[4]
+
+.IPRED_Z1_FS_W4:
+    andi           t0,      a3,      4
+    beqz           t0,      .IPRED_Z1_FS_W8
+.IPRED_Z1_FS_W4_H4:
+    andi           t0,      a4,      4
+    beqz           t0,      .IPRED_Z1_FS_W4_H8
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init4
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W4_H8:
+    andi           t0,      a4,      8
+    beqz           t0,      .IPRED_Z1_FS_W4_H16
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init4
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-11
+    vreplvei.b     vr10,    vr7,     8
+    vextrins.b     vr10,    vr7,     0x07
+    z1_filter_edge_calc_other
+    fst.s          f12,     t2,      8
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W4_H16:
+    andi           t0,      a4,      16
+    beqz           t0,      .IPRED_Z1_FS_W4_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init4
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vreplvei.b     vr10,    vr7,     8
+    vextrins.b     vr10,    vr7,     0x07
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      8
+
+    //16-19
+    vreplvei.b     vr12,    vr12,    1
+    fst.s          f12,     t2,      16
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W4_H32:
+    andi           t0,      a4,      32
+    beqz           t0,      .IPRED_Z1_FS_W4_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init4
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vreplvei.b     vr10,    vr7,     8
+    vextrins.b     vr10,    vr7,     0x07
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vreplvei.b     vr12,    vr12,    1
+    fst.d          f12,     t2,      16
+
+    fst.d          f12,     t2,      24 //24-31
+    fst.s          f12,     t2,      32 //32-35
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W4_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init4
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vreplvei.b     vr10,    vr7,     8
+    vextrins.b     vr10,    vr7,     0x07
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vreplvei.b     vr12,    vr12,    1
+    fst.d          f12,     t2,      16
+
+    fst.d          f12,     t2,      24 //24-31
+    fst.d          f12,     t2,      32 //32-39
+    fst.d          f12,     t2,      40 //40-47
+    fst.d          f12,     t2,      48 //48-55
+    fst.d          f12,     t2,      56 //56-63
+    fst.s          f12,     t2,      64 //64-67
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W8:
+    andi           t0,      a3,      8
+    beqz           t0,      .IPRED_Z1_FS_W16
+.IPRED_Z1_FS_W8_H4:
+    andi           t0,      a4,      4
+    beqz           t0,      .IPRED_Z1_FS_W8_H8
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-11
+    vld            vr7,     a2,      6
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x32
+    vsllwil.hu.bu  vr10,    vr7,     0
+    vsllwil.hu.bu  vr11,    vr11,    0
+    vsllwil.hu.bu  vr12,    vr12,    0
+    vsllwil.hu.bu  vr13,    vr13,    0
+    z1_filter_edge_calc_loop1
+
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x21
+    vextrins.b     vr13,    vr13,    0x31
+    z1_filter_edge_calc_loop2
+    fst.s          f12,     t2,      8
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W8_H8:
+    andi           t0,      a4,      8
+    beqz           t0,      .IPRED_Z1_FS_W8_H16
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W8_H16:
+    andi           t0,      a4,      16
+    beqz           t0,      .IPRED_Z1_FS_W8_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vreplvei.b     vr10,    vr7,     9
+    vextrins.b     vr10,    vr7,     0x08
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      16
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W8_H32:
+    andi           t0,      a4,      32
+    beqz           t0,      .IPRED_Z1_FS_W8_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vreplvei.b     vr10,    vr7,     9
+    vextrins.b     vr10,    vr7,     0x08
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vreplvei.b     vr12,    vr12,    1
+    fst.d          f12,     t2,      24
+
+    //32-39
+    fst.d          f12,     t2,      32
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W8_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vreplvei.b     vr10,    vr7,     9
+    vextrins.b     vr10,    vr7,     0x08
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vreplvei.b     vr12,    vr12,    1
+    fst.d          f12,     t2,      24
+
+    fst.d          f12,     t2,      32  //32-39
+    fst.d          f12,     t2,      40  //40-47
+    fst.d          f12,     t2,      48  //48-55
+    fst.d          f12,     t2,      56  //56-63
+    fst.d          f12,     t2,      64  //64-71
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W16:
+    andi           t0,      a3,      16
+    beqz           t0,      .IPRED_Z1_FS_W32
+.IPRED_Z1_FS_W16_H4:
+    andi           t0,      a4,      4
+    beqz           t0,      .IPRED_Z1_FS_W16_H8
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-19
+    vld            vr7,     a2,      14
+    vbsrl.v        vr11,    vr7,     1
+    vbsrl.v        vr12,    vr7,     2
+    vbsrl.v        vr13,    vr7,     3
+    vextrins.b     vr13,    vr13,    0x32
+    vsllwil.hu.bu  vr10,    vr7,     0
+    vsllwil.hu.bu  vr11,    vr11,    0
+    vsllwil.hu.bu  vr12,    vr12,    0
+    vsllwil.hu.bu  vr13,    vr13,    0
+    z1_filter_edge_calc_loop1
+
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x21
+    vextrins.b     vr13,    vr13,    0x31
+    z1_filter_edge_calc_loop2
+    fst.s          f12,     t2,      16
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W16_H8:
+    andi           t0,      a4,      8
+    beqz           t0,      .IPRED_Z1_FS_W16_H16
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W16_H16:
+    andi           t0,      a4,      16
+    beqz           t0,      .IPRED_Z1_FS_W16_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W16_H32:
+    andi           t0,      a4,      32
+    beqz           t0,      .IPRED_Z1_FS_W16_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vreplvei.b     vr10,    vr7,     9
+    vextrins.b     vr10,    vr7,     0x08
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      32
+
+    //40-47
+    vreplvei.b     vr12,    vr12,    1
+    fst.d          f12,     t2,      40
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W16_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vreplvei.b     vr10,    vr7,     9
+    vextrins.b     vr10,    vr7,     0x08
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      32
+
+    //40-47
+    vreplvei.b     vr12,    vr12,    1
+    fst.d          f12,     t2,      40
+
+    fst.d          f12,     t2,      48 //48-55
+    fst.d          f12,     t2,      56 //56-63
+    fst.d          f12,     t2,      64 //64-71
+    fst.d          f12,     t2,      72 //72-81
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W32:
+    andi           t0,      a3,      32
+    beqz           t0,      .IPRED_Z1_FS_W64
+.IPRED_Z1_FS_W32_H8:
+    andi           t0,      a4,      8
+    beqz           t0,      .IPRED_Z1_FS_W32_H16
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vld            vr7,     a2,      30
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      32
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W32_H16:
+    andi           t0,      a4,      16
+    beqz           t0,      .IPRED_Z1_FS_W32_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vld            vr7,     a2,      30
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      32
+
+    //40-47
+    vld            vr7,     a2,      38
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      40
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W32_H32:
+    andi           t0,      a4,      32
+    beqz           t0,      .IPRED_Z1_FS_W32_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vld            vr7,     a2,      30
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      32
+
+    //40-47
+    vld            vr7,     a2,      38
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      40
+
+    //48-55
+    vld            vr7,     a2,      46
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      48
+
+    //56-63
+    vld            vr7,     a2,      54
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      56
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W32_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vld            vr7,     a2,      30
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      32
+
+    //40-47
+    vld            vr7,     a2,      38
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      40
+
+    //48-55
+    vld            vr7,     a2,      46
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      48
+
+    //56-63
+    vld            vr7,     a2,      54
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      56
+
+    //64-71
+    vreplvei.b     vr10,    vr7,     9
+    vextrins.b     vr10,    vr7,     0x08
+    z1_filter_edge_calc_other
+    fst.d          f12,     t2,      64
+
+    //72-89
+    vreplvei.b     vr12,    vr12,    1
+    fst.d          f12,     t2,      72
+
+    fst.d          f12,     t2,      80 //80-87
+    fst.d          f12,     t2,      88 //88-95
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W64:
+.IPRED_Z1_FS_W64_H16:
+    andi           t0,      a4,      16
+    beqz           t0,      .IPRED_Z1_FS_W64_H32
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vld            vr7,     a2,      30
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      32
+
+    //40-47
+    vld            vr7,     a2,      38
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      40
+
+    //48-55
+    vld            vr7,     a2,      46
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      48
+
+    //56-63
+    vld            vr7,     a2,      54
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      56
+
+    //64-71
+    vld            vr7,     a2,      62
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      64
+
+    //72-79
+    vld            vr7,     a2,      70
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      72
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W64_H32:
+    andi           t0,      a4,      32
+    beqz           t0,      .IPRED_Z1_FS_W64_H64
+
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vld            vr7,     a2,      30
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      32
+
+    //40-47
+    vld            vr7,     a2,      38
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      40
+
+    //48-55
+    vld            vr7,     a2,      46
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      48
+
+    //56-63
+    vld            vr7,     a2,      54
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      56
+
+    //64-71
+    vld            vr7,     a2,      62
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      64
+
+    //72-79
+    vld            vr7,     a2,      70
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      72
+
+    //80-87
+    vld            vr7,     a2,      78
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      80
+
+    //88-95
+    vld            vr7,     a2,      86
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      88
+
+    b              .IPRED_Z1_FS_END
+
+.IPRED_Z1_FS_W64_H64:
+    //0-7
+    vld            vr7,     a2,      -1
+    z1_filter_edge_data_init1
+    vbsrl.v        vr13,    vr7,     3
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      0
+
+    //8-15
+    vld            vr7,     a2,      6
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      8
+
+    //16-23
+    vld            vr7,     a2,      14
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      16
+
+    //24-31
+    vld            vr7,     a2,      22
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      24
+
+    //32-39
+    vld            vr7,     a2,      30
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      32
+
+    //40-47
+    vld            vr7,     a2,      38
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      40
+
+    //48-55
+    vld            vr7,     a2,      46
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      48
+
+    //56-63
+    vld            vr7,     a2,      54
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      56
+
+    //64-71
+    vld            vr7,     a2,      62
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      64
+
+    //72-79
+    vld            vr7,     a2,      70
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      72
+
+    //80-87
+    vld            vr7,     a2,      78
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      80
+
+    //88-95
+    vld            vr7,     a2,      86
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      88
+
+    //96-103
+    vld            vr7,     a2,      94
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      96
+
+    //104-111
+    vld            vr7,     a2,      102
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      104
+
+    //112-119
+    vld            vr7,     a2,      110
+    z1_filter_edge_data_init2
+    vbsrl.v        vr13,    vr7,     4
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      112
+
+    //120-127
+    vld            vr7,     a2,      118
+    z1_filter_edge_data_init3
+    vbsrl.v        vr13,    vr7,     4
+    vextrins.b     vr13,    vr13,    0x65
+    vextrins.b     vr13,    vr13,    0x75
+    z1_filter_edge_calc_loop2
+    fst.d          f12,     t2,      120
+
+.IPRED_Z1_FS_END:
+    addi.d         t0,      a7,      -1   //max_base_x
+    or             a7,      t2,      t2   //top
+    b              .IPRED_Z1_UA_END
+
+.IPRED_Z1_NOTFS:
+    or             a7,      a2,      a2   //top
+    // imin_gr
+    blt            a3,      a4,      .Z1_IMIN1
+    or             t0,      a4,      a4
+    b              .Z1_IMIN2
+.Z1_IMIN1:
+    or             t0,      a3,      a3
+.Z1_IMIN2:
+
+    add.d          t0,      a3,      t0
+    addi.d         t0,      t0,      -1   //max_base_x
+
+.IPRED_Z1_UA_END:
+    //st dst, t1:dx  a2 a6 t6 t7
+    beqz           t5,      .Z1_UA0
+
+    li.w           a5,      64
+    vreplgr2vr.h   vr0,     a5
+    vsrai.h        vr7,     vr0,     1
+    or             t2,      zero,    zero  //y
+    or             t3,      t1,      t1    //xpos
+.Z1_LOOPY:
+    andi           t4,      t3,      0x3e  //frac
+    vreplgr2vr.h   vr1,     t4
+    vsub.h         vr2,     vr0,     vr1
+    or             a6,      zero,    zero  //x
+    or             a2,      zero,    zero  //base_num
+    srai.d         t6,      t3,      6     //base
+
+    or             t7,      t6,      t6
+    bge            t7,      t0,      .Z1_LOOPX
+.Z1_BASENUM:
+    addi.d         a2,      a2,      1
+    addi.d         t7,      t7,      2
+    blt            t7,      t0,      .Z1_BASENUM
+
+.Z1_LOOPX:
+    blt            a2,      a3,      .Z1_LOOPX_BASEMAX
+
+    srai.d         t8,      a3,      3  //loop param
+    beqz           t8,      .Z1_LOOPX_W4
+.Z1_LOOPX_W8:
+    add.d          t5,      a7,      t6
+    vld            vr3,     t5,      0
+    vpickev.b      vr5,     vr3,     vr3  //0 2 4 6...
+    vpickod.b      vr6,     vr3,     vr3  //1 3 5 7...
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsllwil.hu.bu  vr6,     vr6,     0
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    fstx.d         f3,      a0,      a6
+
+    addi.d         a6,      a6,      8
+    addi.d         t6,      t6,      16
+    addi.d         t8,      t8,      -1
+    bnez           t8,      .Z1_LOOPX_W8
+    b              .Z1_LOOPY_END
+.Z1_LOOPX_W4:
+    vldx           vr3,     a7,      t6
+    vsllwil.hu.bu  vr3,     vr3,     0
+    vpickev.h      vr5,     vr3,     vr3  //0 2 4 6...
+    vpickod.h      vr6,     vr3,     vr3  //1 3 5 7...
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    fstx.s         f3,      a0,      a6
+    b              .Z1_LOOPY_END
+.Z1_LOOPX_BASEMAX:
+    srai.d         t8,      a2,      3  //loop param
+    beqz           t8,      .Z1_LOOPX_BASEMAX4
+.Z1_LOOPX_BASEMAX8:
+    add.d          t5,      a7,      t6
+    vld            vr3,     t5,      0
+    vpickev.b      vr5,     vr3,     vr3  //0 2 4 6...
+    vpickod.b      vr6,     vr3,     vr3  //1 3 5 7...
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsllwil.hu.bu  vr6,     vr6,     0
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    fstx.d         f3,      a0,      a6
+
+    addi.d         a6,      a6,      8
+    addi.d         t6,      t6,      16
+    addi.d         t8,      t8,      -1
+    bnez           t8,      .Z1_LOOPX_BASEMAX8
+.Z1_LOOPX_BASEMAX4:
+    andi           t8,      a2,      4
+    beqz           t8,      .Z1_LOOPX_BASEMAX2
+
+    vldx           vr3,     a7,      t6
+    vsllwil.hu.bu  vr3,     vr3,     0
+    vpickev.h      vr5,     vr3,     vr3  //0 2 4 6...
+    vpickod.h      vr6,     vr3,     vr3  //1 3 5 7...
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    fstx.s         f3,      a0,      a6
+
+    addi.d         a6,      a6,      4
+    addi.d         t6,      t6,      8
+.Z1_LOOPX_BASEMAX2:
+    andi           t8,      a2,     2
+    beqz           t8,      .Z1_LOOPX_BASEMAX1
+
+    vldx           vr3,     a7,      t6
+    vsllwil.hu.bu  vr3,     vr3,     0
+    vpickev.h      vr5,     vr3,     vr3  //0 2 4 6...
+    vpickod.h      vr6,     vr3,     vr3  //1 3 5 7...
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    vpickve2gr.bu  t7,      vr3,     0
+    vpickve2gr.bu  t8,      vr3,     1
+    stx.b          t7,      a0,      a6
+    addi.d         a6,      a6,      1
+    stx.b          t8,      a0,      a6
+    addi.d         a6,      a6,      1
+    addi.d         t6,      t6,      4
+.Z1_LOOPX_BASEMAX1:
+    andi           t8,      a2,     1
+    beqz           t8,      .Z1_LOOPX_BASEMAX_MSET
+
+    add.d          a2,      a7,      t6
+    sub.d          t7,      a5,      t4
+    ld.bu          t8,      a2,      0
+    mul.w          t7,      t7,      t8
+    ld.bu          t8,      a2,      1
+    mul.w          t8,      t8,      t4
+    add.d          t7,      t7,      t8
+    addi.d         t7,      t7,      32
+    srai.d         t7,      t7,      6
+    stx.b          t7,      a0,      a6
+
+    addi.d         a6,      a6,      1
+.Z1_LOOPX_BASEMAX_MSET:  //memset
+    add.d          t6,      a0,      a6  //dst
+    add.d          t7,      a7,      t0  //src
+    sub.d          a2,      a3,      a6  //size
+    pixel_set_8bpc_allw t6, t7, a2, t8, t4
+.Z1_LOOPY_END:
+    addi.d         t2,      t2,      1
+    add.d          a0,      a0,      a1
+    add.d          t3,      t3,      t1
+    blt            t2,      a4,      .Z1_LOOPY
+    b              .Z1_END
+
+.Z1_UA0:
+    li.w           a5,      64
+    vreplgr2vr.h   vr0,     a5
+    vsrai.h        vr7,     vr0,     1
+    or             t2,      zero,    zero  //y
+    or             t3,      t1,      t1    //xpos
+.Z1_UA0_LOOPY:
+    andi           t4,      t3,      0x3e  //frac
+    vreplgr2vr.h   vr1,     t4
+    vsub.h         vr2,     vr0,     vr1
+    or             a6,      zero,    zero  //x
+    srai.d         t6,      t3,      6     //base
+
+    sub.d          a2,      t0,      t6     //a2:base_num
+    blt            a2,      zero,    .Z1_UA0_BASENUM
+    b              .Z1_UA0_LOOPX
+.Z1_UA0_BASENUM:
+    or             a2,      zero,    zero
+
+.Z1_UA0_LOOPX:
+    blt            a2,      a3,      .Z1_UA0_LOOPX_BASEMAX
+
+    srai.d         t8,      a3,      3  //loop param
+    beqz           t8,      .Z1_UA0_LOOPX_W4
+.Z1_UA0_LOOPX_W8:
+    add.d          t5,      a7,      t6
+    vld            vr5,     t5,      0
+    vld            vr6,     t5,      1
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsllwil.hu.bu  vr6,     vr6,     0
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    fstx.d         f3,      a0,      a6
+
+    addi.d         a6,      a6,      8
+    addi.d         t6,      t6,      8
+    addi.d         t8,      t8,      -1
+    bnez           t8,      .Z1_UA0_LOOPX_W8
+    b              .Z1_UA0_LOOPY_END
+.Z1_UA0_LOOPX_W4:
+    vldx           vr5,     a7,      t6
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vbsrl.v        vr6,     vr5,     2
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    fstx.s         f3,      a0,      a6
+    b              .Z1_UA0_LOOPY_END
+.Z1_UA0_LOOPX_BASEMAX:
+    srai.d         t8,      a2,      3  //loop param
+    beqz           t8,      .Z1_UA0_LOOPX_BASEMAX4
+.Z1_UA0_LOOPX_BASEMAX8:
+    add.d          t5,      a7,      t6
+    vld            vr5,     t5,      0
+    vld            vr6,     t5,      1
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vsllwil.hu.bu  vr6,     vr6,     0
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    fstx.d         f3,      a0,      a6
+
+    addi.d         a6,      a6,      8
+    addi.d         t6,      t6,      8
+    addi.d         t8,      t8,      -1
+    bnez           t8,      .Z1_UA0_LOOPX_BASEMAX8
+.Z1_UA0_LOOPX_BASEMAX4:
+    andi           t8,      a2,      4
+    beqz           t8,      .Z1_UA0_LOOPX_BASEMAX2
+
+    vldx           vr5,     a7,      t6
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vbsrl.v        vr6,     vr5,     2
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    fstx.s         f3,      a0,      a6
+
+    addi.d         a6,      a6,      4
+    addi.d         t6,      t6,      4
+.Z1_UA0_LOOPX_BASEMAX2:
+    andi           t8,      a2,     2
+    beqz           t8,      .Z1_UA0_LOOPX_BASEMAX1
+
+    vldx           vr5,     a7,      t6
+    vsllwil.hu.bu  vr5,     vr5,     0
+    vbsrl.v        vr6,     vr5,     2
+
+    vmul.h         vr3,     vr5,     vr2
+    vmadd.h        vr3,     vr6,     vr1
+    vadd.h         vr3,     vr3,     vr7
+    vsrai.h        vr3,     vr3,     6
+    vsrlni.b.h     vr3,     vr3,     0
+    vpickve2gr.bu  t7,      vr3,     0
+    vpickve2gr.bu  t8,      vr3,     1
+    stx.b          t7,      a0,      a6
+    addi.d         a6,      a6,      1
+    stx.b          t8,      a0,      a6
+    addi.d         a6,      a6,      1
+    addi.d         t6,      t6,      2
+.Z1_UA0_LOOPX_BASEMAX1:
+    andi           t8,      a2,     1
+    beqz           t8,      .Z1_UA0_LOOPX_BASEMAX_MSET
+
+    add.d          a2,      a7,      t6
+    sub.d          t7,      a5,      t4
+    ld.bu          t8,      a2,      0
+    mul.w          t7,      t7,      t8
+    ld.bu          t8,      a2,      1
+    mul.w          t8,      t8,      t4
+    add.d          t7,      t7,      t8
+    addi.d         t7,      t7,      32
+    srai.d         t7,      t7,      6
+    stx.b          t7,      a0,      a6
+
+    addi.d         a6,      a6,      1
+.Z1_UA0_LOOPX_BASEMAX_MSET:  //memset
+    add.d          t6,      a0,      a6  //dst
+    add.d          t7,      a7,      t0  //src
+    sub.d          a2,      a3,      a6  //size
+    pixel_set_8bpc_allw t6, t7, a2, t8, t4
+.Z1_UA0_LOOPY_END:
+    addi.d         t2,      t2,      1
+    add.d          a0,      a0,      a1
+    add.d          t3,      t3,      t1
+    blt            t2,      a4,      .Z1_UA0_LOOPY
+
+.Z1_END:
+    addi.d         sp,      sp,      128
+endfunc
+
diff --git a/media/libdav1d/src/src/loongarch/ipred.h b/media/libdav1d/src/src/loongarch/ipred.h
new file mode 100644
index 0000000000..c9f4bc1bfd
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/ipred.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_IPRED_H
+#define DAV1D_SRC_LOONGARCH_IPRED_H
+
+#include "config.h"
+#include "src/ipred.h"
+#include "src/cpu.h"
+#include "src/tables.h"
+
+#define MULTIPLIER_1x2 0x5556
+#define MULTIPLIER_1x4 0x3334
+#define BASE_SHIFT 16
+
+#define init_fn(type0, type1, name, suffix) \
+    c->type0[type1] = BF(dav1d_##name, suffix)
+
+#define init_angular_ipred_fn(type, name, suffix) \
+    init_fn(intra_pred, type, name, suffix)
+#define init_cfl_pred_fn(type, name, suffix) \
+    init_fn(cfl_pred, type, name, suffix)
+
+decl_angular_ipred_fn(BF(dav1d_ipred_dc, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_dc_128, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_dc_top, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_dc_left, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_h, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_v, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_paeth, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth_v, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth_h, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_filter, lsx));
+decl_angular_ipred_fn(BF(dav1d_ipred_z1, lsx));
+
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl, lsx));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_128, lsx));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_top, lsx));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_left, lsx));
+
+decl_pal_pred_fn(BF(dav1d_pal_pred, lsx));
+
+static ALWAYS_INLINE void intra_pred_dsp_init_loongarch(Dav1dIntraPredDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LSX)) return;
+
+#if BITDEPTH == 8
+    init_angular_ipred_fn(DC_PRED,       ipred_dc,       lsx);
+    init_angular_ipred_fn(DC_128_PRED,   ipred_dc_128,   lsx);
+    init_angular_ipred_fn(TOP_DC_PRED,   ipred_dc_top,   lsx);
+    init_angular_ipred_fn(LEFT_DC_PRED,  ipred_dc_left,  lsx);
+    init_angular_ipred_fn(HOR_PRED,      ipred_h,        lsx);
+    init_angular_ipred_fn(VERT_PRED,     ipred_v,        lsx);
+    init_angular_ipred_fn(PAETH_PRED,    ipred_paeth,    lsx);
+    init_angular_ipred_fn(SMOOTH_PRED,   ipred_smooth,   lsx);
+    init_angular_ipred_fn(SMOOTH_V_PRED, ipred_smooth_v, lsx);
+    init_angular_ipred_fn(SMOOTH_H_PRED, ipred_smooth_h, lsx);
+    init_angular_ipred_fn(FILTER_PRED,   ipred_filter,   lsx);
+    init_angular_ipred_fn(Z1_PRED,       ipred_z1,       lsx);
+
+    init_cfl_pred_fn(DC_PRED,      ipred_cfl,      lsx);
+    init_cfl_pred_fn(DC_128_PRED,  ipred_cfl_128,  lsx);
+    init_cfl_pred_fn(TOP_DC_PRED,  ipred_cfl_top,  lsx);
+    init_cfl_pred_fn(LEFT_DC_PRED, ipred_cfl_left, lsx);
+
+    c->pal_pred = BF(dav1d_pal_pred, lsx);
+#endif
+}
+
+#endif /* DAV1D_SRC_LOONGARCH_IPRED_H */
diff --git a/media/libdav1d/src/src/loongarch/itx.S b/media/libdav1d/src/src/loongarch/itx.S
new file mode 100644
index 0000000000..8440baac97
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/itx.S
@@ -0,0 +1,4781 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/loongarch/loongson_asm.S"
+#include "src/loongarch/loongson_util.S"
+
+.macro PUSH_REG
+    addi.d           sp,     sp,    -64
+    fst.d            f24,    sp,     0
+    fst.d            f25,    sp,     8
+    fst.d            f26,    sp,     16
+    fst.d            f27,    sp,     24
+    fst.d            f28,    sp,     32
+    fst.d            f29,    sp,     40
+    fst.d            f30,    sp,     48
+    fst.d            f31,    sp,     56
+.endm
+
+.macro POP_REG
+    fld.d            f24,    sp,     0
+    fld.d            f25,    sp,     8
+    fld.d            f26,    sp,     16
+    fld.d            f27,    sp,     24
+    fld.d            f28,    sp,     32
+    fld.d            f29,    sp,     40
+    fld.d            f30,    sp,     48
+    fld.d            f31,    sp,     56
+    addi.d           sp,     sp,     64
+.endm
+
+.macro malloc_space number
+    li.w          t0,       \number
+    sub.d         sp,       sp,       t0
+    addi.d        sp,       sp,       -64
+    PUSH_REG
+.endm
+
+.macro free_space number
+    POP_REG
+    li.w          t0,       \number
+    add.d         sp,       sp,       t0
+    addi.d        sp,       sp,       64
+.endm
+
+.macro iwht4
+    vadd.h        vr0,       vr0,     vr1
+    vsub.h        vr4,       vr2,     vr3
+    vsub.h        vr5,       vr0,     vr4
+    vsrai.h       vr5,       vr5,     1
+    vsub.h        vr2,       vr5,     vr1
+    vsub.h        vr1,       vr5,     vr3
+    vadd.h        vr3,       vr4,     vr2
+    vsub.h        vr0,       vr0,     vr1
+.endm
+
+.macro DST_ADD_W4 in0, in1, in2, in3, in4, in5
+    vilvl.w       \in0,     \in1,     \in0  // 0 1  2  3  4  5  6  7 x ...
+    vilvl.w       \in2,     \in3,     \in2  // 8 9 10 11 12 13 14 15 x ...
+    vsllwil.hu.bu \in0,     \in0,     0
+    vsllwil.hu.bu \in2,     \in2,     0
+    vadd.h        \in0,     \in4,     \in0
+    vadd.h        \in2,     \in5,     \in2
+    vssrani.bu.h  \in2,     \in0,     0
+    vstelm.w      \in2,     a0,       0,    0
+    vstelmx.w     \in2,     a0,       a1,   1
+    vstelmx.w     \in2,     a0,       a1,   2
+    vstelmx.w     \in2,     a0,       a1,   3
+.endm
+
+.macro VLD_DST_ADD_W4 in0, in1
+    vld           vr0,      a0,       0
+    vldx          vr1,      a0,       a1
+    vld           vr2,      t2,       0
+    vldx          vr3,      t2,       a1
+
+    DST_ADD_W4    vr0, vr1, vr2, vr3, \in0, \in1
+.endm
+
+function inv_txfm_add_wht_wht_4x4_8bpc_lsx
+    vld           vr0,       a2,      0
+    vld           vr2,       a2,      16
+
+    vxor.v        vr20,      vr20,    vr20
+    vsrai.h       vr0,       vr0,     2
+    vsrai.h       vr2,       vr2,     2
+    vst           vr20,      a2,      0
+    vpickod.d     vr1,       vr0,     vr0
+    vpickod.d     vr3,       vr2,     vr2
+    vst           vr20,      a2,      16
+
+    iwht4
+
+    LSX_TRANSPOSE4x4_H vr0, vr1, vr2, vr3, vr0, vr1, vr2, vr3, vr4, vr5
+
+    iwht4
+
+    vilvl.d       vr4,       vr1,     vr0
+    vilvl.d       vr5,       vr3,     vr2
+    alsl.d        t2,        a1,      a0,    1
+    VLD_DST_ADD_W4 vr4, vr5
+endfunc
+
+const idct_coeffs, align=4
+    .word          2896, 2896*8, 1567, 3784
+    .word          799, 4017, 3406, 2276
+    .word          401, 4076, 3166, 2598
+    .word          1931, 3612, 3920, 1189
+    .word          201, 4091, 3035, 2751
+    .word          1751, 3703, 3857, 1380
+    .word          995, 3973, 3513, 2106
+    .word          2440, 3290, 4052, 601
+endconst
+
+.macro vsrari_h_x4 in0, in1, in2, in3, out0, out1, out2, out3, shift
+    vsrari.h      \out0,    \in0,     \shift
+    vsrari.h      \out1,    \in1,     \shift
+    vsrari.h      \out2,    \in2,     \shift
+    vsrari.h      \out3,    \in3,     \shift
+.endm
+
+.macro vsrari_h_x8 in0, in1, in2, in3, in4, in5, in6, in7, out0, \
+                   out1, out2, out3, out4, out5, out6, out7, shift
+    vsrari.h      \out0,    \in0,     \shift
+    vsrari.h      \out1,    \in1,     \shift
+    vsrari.h      \out2,    \in2,     \shift
+    vsrari.h      \out3,    \in3,     \shift
+    vsrari.h      \out4,    \in4,     \shift
+    vsrari.h      \out5,    \in5,     \shift
+    vsrari.h      \out6,    \in6,     \shift
+    vsrari.h      \out7,    \in7,     \shift
+.endm
+
+.macro vmulev_vmaddod_lsx in0, in1, in2, in3, out0, out1, sz
+    vmulwev.w.h   \out0,    \in0,     \in2
+    vmulwod.w.h   \out1,    \in0,     \in2
+    vmaddwev.w.h  \out0,    \in1,     \in3
+    vmaddwod.w.h  \out1,    \in1,     \in3
+.ifc \sz, .4h
+    vilvl.w       \out0,    \out1,    \out0
+.else
+    vilvl.w       vr22,     \out1,    \out0
+    vilvh.w       \out1,    \out1,    \out0
+    vor.v         \out0,    vr22,     vr22
+.endif
+.endm
+
+const idct_coeffs_h, align=4
+    .short          2896, 2896*8, 1567, 3784
+    .short          799, 4017, 3406, 2276
+    .short          401, 4076, 3166, 2598
+    .short          1931, 3612, 3920, 1189
+    .short          201, 4091, 3035, 2751
+    .short          1751, 3703, 3857, 1380
+    .short          995, 3973, 3513, 2106
+    .short          2440, 3290, 4052, 601
+endconst
+
+const iadst4_coeffs, align=4
+    .word          1321, 3803, 2482, 3344
+endconst
+
+.macro inv_dct4_lsx in0, in1, in2, in3, out0, out1, out2, out3, sz
+    la.local      t0,       idct_coeffs_h
+
+    vldrepl.h     vr20,     t0,       0    // 2896
+    vmulev_vmaddod_lsx \in0, \in2, vr20, vr20, vr16, vr18, \sz
+    vneg.h        vr21,     vr20
+    vmulev_vmaddod_lsx \in0, \in2, vr20, vr21, vr17, vr19, \sz
+    vssrarni.h.w  vr18,     vr16,     12   // t0
+    vssrarni.h.w  vr19,     vr17,     12   // t1
+
+    vldrepl.h     vr20,     t0,       4    // 1567
+    vldrepl.h     vr21,     t0,       6    // 3784
+    vmulev_vmaddod_lsx \in1, \in3, vr21, vr20, \in0, vr16, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx \in1, \in3, vr20, vr21, \in2, vr17, \sz
+    vssrarni.h.w  vr16,     \in0,     12   // t3
+    vssrarni.h.w  vr17,     \in2,     12   // t2
+
+    vsadd.h       \out0,    vr18,     vr16
+    vsadd.h       \out1,    vr19,     vr17
+    vssub.h       \out2,    vr19,     vr17
+    vssub.h       \out3,    vr18,     vr16
+.endm
+
+functionl inv_dct_4h_x4_lsx
+    inv_dct4_lsx vr0, vr1, vr2, vr3, vr0, vr1, vr2, vr3, .4h
+endfuncl
+
+functionl inv_dct_8h_x4_lsx
+    inv_dct4_lsx vr0, vr1, vr2, vr3, vr0, vr1, vr2, vr3, .8h
+endfuncl
+
+.macro inv_adst4_core_lsx in0, in1, in2, in3, out0, out1, out2, out3
+    vsub.w        vr16,     \in0,    \in2  // in0-in2
+    vmul.w        vr17,     \in0,    vr20  // in0*1321
+    vmul.w        vr19,     \in0,    vr22  // in0*2482
+    vmul.w        vr18,     \in1,    vr23  // in1*3344
+    vmadd.w       vr17,     \in2,    vr21  // in0*1321+in2*3803
+    vmsub.w       vr19,     \in2,    vr20  // in2*1321
+    vadd.w        vr16,     vr16,    \in3  // in0-in2+in3
+    vmadd.w       vr17,     \in3,    vr22  // in0*1321+in2*3803+in3*2482
+    vmsub.w       vr19,     \in3,    vr21  // in0*2482-in2*1321-in3*3803
+    vadd.w        vr15,     vr17,    vr19
+    vmul.w        \out2,    vr16,    vr23  // out[2] 8  9  10 11
+    vadd.w        \out0,    vr17,    vr18  // out[0] 0  1  2  3
+    vadd.w        \out1,    vr19,    vr18  // out[1] 4  5  6  7
+    vsub.w        \out3,    vr15,    vr18  // out[3] 12 13 14 15
+.endm
+
+.macro inv_adst4_lsx in0, in1, in2, in3, out0, out1, out2, out3
+    la.local      t0,       iadst4_coeffs
+
+    vldrepl.w     vr20,     t0,      0     // 1321
+    vldrepl.w     vr21,     t0,      4     // 3803
+    vldrepl.w     vr22,     t0,      8     // 2482
+    vldrepl.w     vr23,     t0,      12    // 3344
+
+    vsllwil.w.h   vr0,      \in0,    0
+    vsllwil.w.h   vr1,      \in1,    0
+    vsllwil.w.h   vr2,      \in2,    0
+    vsllwil.w.h   vr3,      \in3,    0
+    inv_adst4_core_lsx vr0, vr1, vr2, vr3, \out0, \out1, \out2, \out3
+    vssrarni.h.w  \out0,    \out0,   12
+    vssrarni.h.w  \out1,    \out1,   12
+    vssrarni.h.w  \out2,    \out2,   12
+    vssrarni.h.w  \out3,    \out3,   12
+.endm
+
+functionl inv_adst_4h_x4_lsx
+    inv_adst4_lsx vr0, vr1, vr2, vr3, vr0, vr1, vr2, vr3
+endfuncl
+
+functionl inv_flipadst_4h_x4_lsx
+    inv_adst4_lsx vr0, vr1, vr2, vr3, vr3, vr2, vr1, vr0
+endfuncl
+
+.macro inv_adst_8x4_lsx in0, in1, in2, in3, out0, out1, out2, out3
+    la.local      t0,       iadst4_coeffs
+    vldrepl.w     vr20,     t0,      0     // 1321
+    vldrepl.w     vr21,     t0,      4     // 3803
+    vldrepl.w     vr22,     t0,      8     // 2482
+    vldrepl.w     vr23,     t0,      12    // 3344
+
+    vsllwil.w.h   vr10,     \in0,     0     // in0
+    vsllwil.w.h   vr11,     \in1,     0     // in1
+    vsllwil.w.h   vr12,     \in2,     0     // in2
+    vsllwil.w.h   vr13,     \in3,     0     // in3
+    inv_adst4_core_lsx vr10, vr11, vr12, vr13, vr10, vr11, vr12, vr13
+
+    vexth.w.h     \in0,      \in0           // in0
+    vexth.w.h     \in1,      \in1           // in1
+    vexth.w.h     \in2,      \in2           // in2
+    vexth.w.h     \in3,      \in3           // in3
+    inv_adst4_core_lsx \in0, \in1, \in2, \in3, \out0, \out1, \out2, \out3
+
+    vssrarni.h.w  \out0,     vr10,    12
+    vssrarni.h.w  \out1,     vr11,    12
+    vssrarni.h.w  \out2,     vr12,    12
+    vssrarni.h.w  \out3,     vr13,    12
+.endm
+
+functionl inv_adst_8h_x4_lsx
+    inv_adst_8x4_lsx vr0, vr1, vr2, vr3, vr0, vr1, vr2, vr3
+endfuncl
+
+functionl inv_flipadst_8h_x4_lsx
+    inv_adst_8x4_lsx vr0, vr1, vr2, vr3, vr3, vr2, vr1, vr0
+endfuncl
+
+functionl inv_identity_4h_x4_lsx
+    li.w          t0,       1697
+    vreplgr2vr.h  vr20,     t0
+
+    vilvl.d       vr0,      vr1,      vr0
+    vilvl.d       vr2,      vr3,      vr2
+    vmulwev.w.h   vr16,     vr0,      vr20
+    vmulwod.w.h   vr17,     vr0,      vr20
+    vmulwev.w.h   vr18,     vr2,      vr20
+    vmulwod.w.h   vr19,     vr2,      vr20
+    vilvl.w       vr1,      vr17,     vr16
+    vilvh.w       vr3,      vr17,     vr16
+    vilvl.w       vr22,     vr19,     vr18
+    vilvh.w       vr23,     vr19,     vr18
+    vssrarni.h.w  vr3,      vr1,      12
+    vssrarni.h.w  vr23,     vr22,     12
+    vsadd.h       vr0,      vr3,      vr0  // t0
+    vsadd.h       vr2,      vr23,     vr2  // t2
+    vilvh.d       vr1,      vr0,      vr0  // t1
+    vilvh.d       vr3,      vr2,      vr2  // t3
+endfuncl
+
+.macro inv_identity4_lsx1 in0, in1, in2, out0, out1
+    vsllwil.w.h   vr16,     \in0,     0
+    vexth.w.h     vr17,     \in1
+    vmul.w        vr18,     vr16,     \in2
+    vmul.w        vr19,     vr17,     \in2
+    vsrari.w      vr18,     vr18,     12
+    vsrari.w      vr19,     vr19,     12
+    vadd.w        \out0,    vr18,     vr16
+    vadd.w        \out1,    vr19,     vr17
+    vssrarni.h.w  \out1,    \out0,    1
+.endm
+
+functionl inv_identity_8h_x4_lsx
+    li.w          t0,        1697
+    vreplgr2vr.h  vr20,      t0
+    vmulwev.w.h   vr16,      vr0,     vr20
+    vmulwod.w.h   vr17,      vr0,     vr20
+    vmulwev.w.h   vr18,      vr1,     vr20
+    vmulwod.w.h   vr19,      vr1,     vr20
+    vilvl.w       vr21,      vr17,    vr16
+    vilvh.w       vr22,      vr17,    vr16
+    vilvl.w       vr23,      vr19,    vr18
+    vilvh.w       vr16,      vr19,    vr18
+    vssrarni.h.w  vr22,      vr21,    12
+    vssrarni.h.w  vr16,      vr23,    12
+    vsadd.h       vr0,       vr22,    vr0  // t0
+    vsadd.h       vr1,       vr16,    vr1  // t1
+    vmulwev.w.h   vr16,      vr2,     vr20
+    vmulwod.w.h   vr17,      vr2,     vr20
+    vmulwev.w.h   vr18,      vr3,     vr20
+    vmulwod.w.h   vr19,      vr3,     vr20
+    vilvl.w       vr21,      vr17,    vr16
+    vilvh.w       vr22,      vr17,    vr16
+    vilvl.w       vr23,      vr19,    vr18
+    vilvh.w       vr16,      vr19,    vr18
+    vssrarni.h.w  vr22,      vr21,    12
+    vssrarni.h.w  vr16,      vr23,    12
+    vsadd.h       vr2,       vr22,    vr2  // t2
+    vsadd.h       vr3,       vr16,    vr3  // t3
+endfuncl
+
+functionl inv_identity_8h_x4_lsx1
+    li.w          t0,        1697
+    vreplgr2vr.w  vr20,      t0
+.irp i, vr0, vr1, vr2, vr3
+    inv_identity4_lsx1 \i, \i vr20, vr21, \i
+.endr
+endfuncl
+
+functionl inv_txfm_add_4x4_lsx
+    vxor.v        vr23,     vr23,     vr23
+    vld           vr0,      a2,       0
+    vld           vr2,      a2,       16
+    vilvh.d       vr1,      vr0,      vr0
+    vilvh.d       vr3,      vr2,      vr2
+    vst           vr23,     a2,       0
+    vst           vr23,     a2,       16
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+    LSX_TRANSPOSE4x4_H vr0, vr1, vr2, vr3, vr0, vr1, vr2, vr3, vr4, vr5
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vilvl.d       vr4,      vr1,      vr0
+    vilvl.d       vr5,      vr3,      vr2
+    vsrari.h      vr4,      vr4,      4
+    vsrari.h      vr5,      vr5,      4
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W4 vr4, vr5
+endfuncl
+
+.macro idct_dc w, h, shift
+    ld.h          t2,       a2,       0      // dc
+    vldi          vr0,      0x8b5            // 181
+    vreplgr2vr.w  vr1,      t2
+    vldi          vr20,     0x880            // 128
+    vmul.w        vr2,      vr0,      vr1    // dc * 181
+    st.h          zero,     a2,       0
+    vsrari.w      vr2,      vr2,      8      // (dc * 181 + 128) >> 8
+    vld           vr10,     a0,       0      // 0 1 2 3 4 5 6 7
+
+.if (2*\w == \h) || (2*\h == \w)
+    vmul.w        vr2,      vr0,      vr2
+    vsrari.w      vr2,      vr2,      8      // (dc * 181 + 128) >> 8
+.endif
+.if \shift>0
+    vsrari.w      vr2,      vr2,      \shift      // (dc + rnd) >> shift
+.endif
+    vldx          vr11,     a0,       a1     // 8 9 10 11 12 13 14 15
+    alsl.d        t2,       a1,       a0,    1
+    vmadd.w       vr20,     vr2,      vr0
+    vld           vr12,     t2,       0      // 16 17 18 19 20 21 22 23
+    vssrarni.h.w  vr20,     vr20,     12
+    vldx          vr13,     t2,       a1     // 24 25 26 27 28 29 30 31
+.endm
+
+.macro fun4x4 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_4x4_8bpc_lsx
+.ifc \txfm1\()_\txfm2, dct_dct
+    bnez          a3,       1f
+
+    idct_dc 4, 4, 0
+
+    DST_ADD_W4    vr10, vr11, vr12, vr13, vr20, vr20
+    b             .\txfm1\()_\txfm2\()_4X4_END
+1:
+.endif
+
+    la.local     t7,    inv_\txfm1\()_4h_x4_lsx
+    la.local     t8,    inv_\txfm2\()_4h_x4_lsx
+
+    b            inv_txfm_add_4x4_lsx
+.\txfm1\()_\txfm2\()_4X4_END:
+endfunc
+.endm
+
+fun4x4 dct, dct
+fun4x4 identity, identity
+fun4x4 adst, dct
+fun4x4 dct, adst
+fun4x4 adst, adst
+fun4x4 dct, flipadst
+fun4x4 flipadst, adst
+fun4x4 adst, flipadst
+fun4x4 flipadst, dct
+fun4x4 flipadst, flipadst
+fun4x4 dct, identity
+fun4x4 identity, dct
+fun4x4 flipadst, identity
+fun4x4 identity, flipadst
+fun4x4 identity, adst
+fun4x4 adst, identity
+
+const iadst8_coeffs_h, align=4
+    .short          4076, 401, 3612, 1931
+    .short          2598, 3166, 1189, 3920
+    .short          2896, 0, 1567, 3784, 0, 0, 0, 0
+endconst
+
+.macro inv_adst8_lsx out0, out1, out2, out3, out4, out5, out6, out7, sz
+    la.local      t0,       iadst8_coeffs_h
+
+    vldrepl.h     vr20,     t0,       0     // 4076
+    vldrepl.h     vr21,     t0,       2     // 401
+    vmulev_vmaddod_lsx vr7, vr0, vr20, vr21, vr16, vr17, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr7, vr0, vr21, vr20, vr18, vr19, \sz
+    vssrarni.h.w  vr17,     vr16,     12    // t0a
+    vssrarni.h.w  vr19,     vr18,     12    // t1a
+
+    vldrepl.h     vr20,     t0,       4     // 3612
+    vldrepl.h     vr21,     t0,       6     // 1931
+    vmulev_vmaddod_lsx vr5, vr2, vr20, vr21, vr0, vr16, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr5, vr2, vr21, vr20, vr7, vr18, \sz
+    vssrarni.h.w  vr16,     vr0,      12    // t2a
+    vssrarni.h.w  vr18,     vr7,      12    // t3a
+
+    vldrepl.h     vr20,     t0,       8     // 2598
+    vldrepl.h     vr21,     t0,       10    // 3166
+    vmulev_vmaddod_lsx vr3, vr4, vr20, vr21, vr2, vr0, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr3, vr4, vr21, vr20, vr5, vr7, \sz
+    vssrarni.h.w  vr0,      vr2,      12    // t4a
+    vssrarni.h.w  vr7,      vr5,      12    // t5a
+
+    vldrepl.h     vr20,     t0,       12    // 1189
+    vldrepl.h     vr21,     t0,       14    // 3920
+    vmulev_vmaddod_lsx vr1, vr6, vr20, vr21, vr3, vr2, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr1, vr6, vr21, vr20, vr4, vr5, \sz
+    vssrarni.h.w  vr2,      vr3,      12    // t6a
+    vssrarni.h.w  vr5,      vr4,      12    // t7a
+
+    vsadd.h       vr3,      vr17,     vr0   // t0
+    vssub.h       vr4,      vr17,     vr0   // t4
+    vsadd.h       vr1,      vr19,     vr7   // t1
+    vssub.h       vr6,      vr19,     vr7   // t5
+    vsadd.h       vr17,     vr16,     vr2   // t2
+    vssub.h       vr19,     vr16,     vr2   // t6
+    vsadd.h       vr0,      vr18,     vr5   // t3
+    vssub.h       vr7,      vr18,     vr5   // t7
+
+    la.local      t0,       idct_coeffs_h
+
+    vldrepl.h     vr20,     t0,       4     // 1567
+    vldrepl.h     vr21,     t0,       6     // 3784
+    vmulev_vmaddod_lsx vr4, vr6, vr21, vr20, vr16, vr5, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr4, vr6, vr20, vr21, vr18, vr2, \sz
+    vssrarni.h.w  vr5,      vr16,     12    // t4a
+    vssrarni.h.w  vr2,      vr18,     12    // t5a
+
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr7, vr19, vr20, vr21, vr4, vr16, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr7, vr19, vr21, vr20, vr6, vr18, \sz
+    vssrarni.h.w  vr16,     vr4,      12    // t7a
+    vssrarni.h.w  vr18,     vr6,      12    // t6a
+
+    vsadd.h       vr4,      vr5,      vr18  // out1
+    vssub.h       vr19,     vr5,      vr18  // t6
+    vsadd.h       vr20,     vr1,      vr0   // out7
+    vssub.h       vr18,     vr1,      vr0   // t3
+    vsadd.h       \out0,    vr3,      vr17  // out0
+    vssub.h       vr5,      vr3,      vr17  // t2
+    vsadd.h       \out6,    vr2,      vr16  // out6
+    vssub.h       vr23,     vr2,      vr16  // t7
+
+    vsllwil.w.h   vr3,      vr20,     0     // out7
+    vexth.w.h     \out7,    vr20            // out7
+    vsllwil.w.h   vr21,     vr4,      0     // out1
+    vexth.w.h     \out1,    vr4             // out1
+    vneg.w        vr3,      vr3
+    vneg.w        \out7,    \out7
+    vneg.w        vr21,     vr21
+    vneg.w        \out1,    \out1
+    vssrarni.h.w  \out7,    vr3,      0
+    vssrarni.h.w  \out1,    vr21,     0
+
+    la.local      t0,       idct_coeffs_h
+
+    vldrepl.h     vr20,     t0,       0     // 2896
+    vmulev_vmaddod_lsx vr5, vr18, vr20, vr20, vr16, \out3, \sz
+    vneg.h        vr21,     vr20
+    vmulev_vmaddod_lsx vr5, vr18, vr20, vr21, vr17, \out4, \sz
+    vsrari.w      vr16,     vr16,     12
+    vsrari.w      \out3,    \out3,    12
+    vneg.w        vr16,     vr16
+    vneg.w        \out3,    \out3
+    vssrarni.h.w  \out3,    vr16,     0     // out3
+    vssrarni.h.w  \out4,    vr17,     12    // out4
+
+    vmulev_vmaddod_lsx vr19, vr23, vr20, vr20, vr16, \out2, \sz
+    vmulev_vmaddod_lsx vr19, vr23, vr20, vr21, vr17, \out5, \sz
+    vssrarni.h.w  \out2,    vr16,     12    // out2
+    vsrari.w      vr17,     vr17,     12
+    vsrari.w      \out5,    \out5,    12
+    vneg.w        vr17,     vr17
+    vneg.w        \out5,    \out5
+    vssrarni.h.w  \out5,    vr17,     0     // out5
+.endm
+
+functionl inv_adst_8h_x8_lsx
+    inv_adst8_lsx vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, .8h
+endfuncl
+
+functionl inv_flipadst_8h_x8_lsx
+    inv_adst8_lsx vr7, vr6, vr5, vr4, vr3, vr2, vr1, vr0, .8h
+endfuncl
+
+functionl inv_adst_4h_x8_lsx
+    inv_adst8_lsx vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, .8h
+endfuncl
+
+functionl inv_flipadst_4h_x8_lsx
+    inv_adst8_lsx vr7, vr6, vr5, vr4, vr3, vr2, vr1, vr0, .8h
+endfuncl
+
+.macro inv_dct8_lsx in0, in1, in2, in3, in4, in5, in6, in7, sz
+    inv_dct4_lsx \in0, \in2, \in4, \in6, \in0, \in2, \in4, \in6, \sz
+
+    la.local      t0,       idct_coeffs_h
+
+    vldrepl.h     vr20,     t0,       8        // 799
+    vldrepl.h     vr21,     t0,       10       // 4017
+    vmulev_vmaddod_lsx  \in1, \in7, vr21, vr20, vr16, vr17, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx  \in1, \in7, vr20, vr21, vr18, vr19, \sz
+    vssrarni.h.w  vr17,     vr16,     12       // t7a
+    vssrarni.h.w  vr19,     vr18,     12       // t4a
+
+    vldrepl.h     vr20,     t0,       12       // 3406
+    vldrepl.h     vr21,     t0,       14       // 2276
+    vmulev_vmaddod_lsx  \in5, \in3, vr21, vr20, \in1, vr16, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx  \in5, \in3, vr20, vr21, \in7, vr18, \sz
+    vssrarni.h.w  vr16,     \in1,       12      // t6a
+    vssrarni.h.w  vr18,     \in7,       12      // t5a
+
+    vssub.h       \in7,     vr19,      vr18     // t5a
+    vsadd.h       vr18,     vr19,      vr18     // t4
+    vssub.h       \in5,     vr17,      vr16     // t6a
+    vsadd.h       vr16,     vr17,      vr16     // t7
+
+    vldrepl.h     vr20,     t0,        0        // 2896
+    vmulev_vmaddod_lsx  \in5, \in7, vr20, vr20, \in1, vr17, \sz
+    vneg.h        vr21,     vr20
+    vmulev_vmaddod_lsx  \in5, \in7, vr20, vr21, vr23, vr19, \sz
+    vssrarni.h.w  vr17,     \in1,      12       // t6
+    vssrarni.h.w  vr19,     vr23,      12       // t5
+
+    vssub.h       \in7,      \in0,     vr16     //c[7]
+    vsadd.h       \in0,      \in0,     vr16     //c[0]
+    vssub.h       \in5,      \in4,     vr19     //c[5]
+    vsadd.h       vr23,      \in4,     vr19     //c[2]
+    vssub.h       \in4,      \in6,     vr18     //c[4]
+    vsadd.h       \in3,      \in6,     vr18     //c[3]
+    vssub.h       \in6,      \in2,     vr17     //c[6]
+    vsadd.h       \in1,      \in2,     vr17     //c[1]
+    vor.v         \in2,      vr23,     vr23
+.endm
+
+functionl inv_dct_8h_x8_lsx
+    inv_dct8_lsx vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, .8h
+endfuncl
+
+functionl inv_dct_4h_x8_lsx
+    inv_dct8_lsx vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, .4h
+endfuncl
+
+.macro DST_ADD_W8 in0, in1, in2, in3, in4, in5, in6, in7
+    vsllwil.hu.bu vr0,      \in0,     0
+    vsllwil.hu.bu vr1,      \in1,     0
+    vsllwil.hu.bu vr2,      \in2,     0
+    vsllwil.hu.bu vr3,      \in3,     0
+    vadd.h        vr0,      \in4,     vr0
+    vadd.h        vr1,      \in5,     vr1
+    vadd.h        vr2,      \in6,     vr2
+    vadd.h        vr3,      \in7,     vr3
+    vssrani.bu.h  vr1,      vr0,      0
+    vssrani.bu.h  vr3,      vr2,      0
+    vstelm.d      vr1,      a0,       0,    0
+    vstelmx.d     vr1,      a0,       a1,   1
+    vstelmx.d     vr3,      a0,       a1,   0
+    vstelmx.d     vr3,      a0,       a1,   1
+.endm
+
+.macro VLD_DST_ADD_W8 in0, in1, in2, in3
+    vld           vr0,      a0,       0
+    vldx          vr1,      a0,       a1
+    vld           vr2,      t2,       0
+    vldx          vr3,      t2,       a1
+
+    DST_ADD_W8 vr0, vr1, vr2, vr3, \in0, \in1, \in2, \in3
+.endm
+
+functionl inv_identity_8h_x8_lsx
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vsadd.h       \i,       \i,       \i
+.endr
+endfuncl
+
+functionl inv_identity_4h_x8_lsx
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vsadd.h       \i,       \i,       \i
+.endr
+endfuncl
+
+.macro def_fn_8x8_base variant
+functionl inv_txfm_\variant\()add_8x8_lsx
+    vxor.v  vr23, vr23, vr23
+    vld_x8 a2, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+.irp i, 0, 16, 32, 48, 64, 80, 96, 112
+    vst           vr23,     a2,       \i
+.endr
+
+.ifc \variant, identity_
+    // The identity shl #1 and downshift srshr #1 cancel out
+    b             .itx_8x8_epilog
+.else
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vsrari.h      \i,       \i,       1
+.endr
+
+.itx_8x8_epilog:
+    LSX_TRANSPOSE8x8_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vsrari_h_x8 vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23, 4
+
+    alsl.d        t2,       a1,       a0,     1
+    VLD_DST_ADD_W8 vr16, vr17, vr18, vr19
+    add.d         a0,       a0,       a1
+    alsl.d        t2,       a1,       a0,     1
+    VLD_DST_ADD_W8 vr20, vr21, vr22, vr23
+.endif
+endfuncl
+.endm
+
+def_fn_8x8_base identity_
+def_fn_8x8_base
+
+.macro fn8x8 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_8x8_8bpc_lsx
+.ifc \txfm1\()_\txfm2, dct_dct
+    bnez          a3,       .NO_HAS_DCONLY_8x8
+
+    idct_dc 8, 8, 1
+
+    DST_ADD_W8 vr10, vr11, vr12, vr13, vr20, vr20, vr20, vr20
+
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,     1
+    VLD_DST_ADD_W8 vr20, vr20, vr20, vr20
+
+    b             .\txfm1\()_\txfm2\()_8X8_END
+.NO_HAS_DCONLY_8x8:
+.endif
+    la.local      t8,       inv_\txfm2\()_8h_x8_lsx
+.ifc \txfm1, identity
+    b             inv_txfm_identity_add_8x8_lsx
+.else
+    la.local      t7,       inv_\txfm1\()_8h_x8_lsx
+    b             inv_txfm_add_8x8_lsx
+.endif
+.\txfm1\()_\txfm2\()_8X8_END:
+endfunc
+.endm
+
+fn8x8 dct, dct
+fn8x8 identity, identity
+fn8x8 dct, adst
+fn8x8 dct, flipadst
+fn8x8 dct, identity
+fn8x8 adst, dct
+fn8x8 adst, adst
+fn8x8 adst, flipadst
+fn8x8 flipadst, dct
+fn8x8 flipadst, adst
+fn8x8 flipadst, flipadst
+fn8x8 identity, dct
+fn8x8 adst, identity
+fn8x8 flipadst, identity
+fn8x8 identity, adst
+fn8x8 identity, flipadst
+
+.macro rect2_lsx in0, in1, out0
+    vsllwil.w.h   vr22,     \in0,     0     // in1
+    vexth.w.h     \in0,     \in0            // in1
+    vmul.w        vr22,     vr22,     \in1
+    vmul.w        \out0,    \in0,     \in1
+    vssrarni.h.w  \out0,    vr22,     12
+.endm
+
+.macro LSX_TRANSPOSE8x4_H in0, in1, in2, in3, in4, in5, in6, in7, out0, out1, \
+                          out2, out3, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5
+    vilvl.h       \tmp0,    \in1,     \in0
+    vilvl.h       \tmp1,    \in3,     \in2
+    vilvl.w       \tmp2,    \tmp1,    \tmp0
+    vilvh.w       \tmp3,    \tmp1,    \tmp0
+    vilvl.h       \tmp0,    \in5,     \in4
+    vilvl.h       \tmp1,    \in7,     \in6
+    vilvl.w       \tmp4,    \tmp1,    \tmp0
+    vilvh.w       \tmp5,    \tmp1,    \tmp0
+    vilvl.d       \out0,    \tmp4,    \tmp2
+    vilvh.d       \out1,    \tmp4,    \tmp2
+    vilvl.d       \out2,    \tmp5,    \tmp3
+    vilvh.d       \out3,    \tmp5,    \tmp3
+.endm
+
+functionl inv_txfm_add_8x4_lsx
+    vxor.v        vr23,     vr23,     vr23
+    vld           vr0,      a2,       0
+    vld           vr2,      a2,       16
+    vld           vr4,      a2,       32
+    vld           vr6,      a2,       48
+.irp i, 0, 16, 32, 48
+    vst           vr23,     a2,       \i
+.endr
+
+    li.w          t0,       2896
+    vreplgr2vr.w  vr23,     t0
+    rect2_lsx     vr0,      vr23,     vr0
+    rect2_lsx     vr2,      vr23,     vr2
+    rect2_lsx     vr4,      vr23,     vr4
+    rect2_lsx     vr6,      vr23,     vr6
+
+    vilvh.d       vr1,      vr0,      vr0
+    vilvh.d       vr3,      vr2,      vr2
+    vilvh.d       vr5,      vr4,      vr4
+    vilvh.d       vr7,      vr6,      vr6
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+    LSX_TRANSPOSE8x4_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, vr0, vr1, \
+                       vr2, vr3, vr16, vr17, vr18, vr19, vr20, vr21
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vsrari_h_x4 vr0, vr1, vr2, vr3, vr16, vr17, vr18, vr19, 4
+
+    alsl.d        t2,       a1,       a0,     1
+    VLD_DST_ADD_W8 vr16, vr17, vr18, vr19
+endfuncl
+
+.macro LSX_TRANSPOSE4x8_H in0, in1, in2, in3, out0, out1, out2, out3, out4, \
+                          out5, out6, out7, tmp0, tmp1, tmp2, tmp3
+    vilvl.h       \tmp0,    \in1,     \in0
+    vilvl.h       \tmp1,    \in3,     \in2
+    vilvh.h       \tmp2,    \in1,     \in0
+    vilvh.h       \tmp3,    \in3,     \in2
+    vilvl.w       \out0,    \tmp1,    \tmp0
+    vilvh.w       \out2,    \tmp1,    \tmp0
+    vilvl.w       \out4,    \tmp3,    \tmp2
+    vilvh.w       \out6,    \tmp3,    \tmp2
+
+    vbsrl.v       \out1,    \out0,    8
+    vbsrl.v       \out3,    \out2,    8
+    vbsrl.v       \out5,    \out4,    8
+    vbsrl.v       \out7,    \out6,    8
+    vinsgr2vr.d   \out0,    zero,     1
+    vinsgr2vr.d   \out2,    zero,     1
+    vinsgr2vr.d   \out4,    zero,     1
+    vinsgr2vr.d   \out6,    zero,     1
+.endm
+
+functionl inv_txfm_add_4x8_lsx
+    vxor.v        vr23,     vr23,     vr23
+    vld           vr0,      a2,       0
+    vld           vr1,      a2,       16
+    vld           vr2,      a2,       32
+    vld           vr3,      a2,       48
+.irp i, 0, 16, 32, 48
+    vst           vr23,     a2,       \i
+.endr
+
+    li.w          t0,       2896
+    vreplgr2vr.w  vr23,     t0
+    rect2_lsx     vr0,      vr23,     vr0
+    rect2_lsx     vr1,      vr23,     vr1
+    rect2_lsx     vr2,      vr23,     vr2
+    rect2_lsx     vr3,      vr23,     vr3
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+    LSX_TRANSPOSE4x8_H vr0, vr1, vr2, vr3, vr0, vr1, vr2, vr3, vr4, vr5, \
+                       vr6, vr7, vr16, vr17, vr18, vr19
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vilvl.d       vr0,      vr1,      vr0
+    vilvl.d       vr1,      vr3,      vr2
+    vilvl.d       vr2,      vr5,      vr4
+    vilvl.d       vr3,      vr7,      vr6
+
+    vsrari_h_x4 vr0, vr1, vr2, vr3, vr16, vr17, vr18, vr19, 4
+
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W4 vr16, vr17
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W4 vr18, vr19
+endfuncl
+
+.macro fn8x4 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_8x4_8bpc_lsx
+.ifc \txfm1()_\txfm2, dct_dct
+    bnez          a3,       .NO_HAS_DCONLY_8x4
+
+    idct_dc 8, 4, 0
+
+    DST_ADD_W8 vr10, vr11, vr12, vr13, vr5, vr5, vr5, vr5
+
+    b             .\txfm1\()_\txfm2\()_8X4_END
+.NO_HAS_DCONLY_8x4:
+.endif
+    la.local      t7,       inv_\txfm1\()_4h_x8_lsx
+    la.local      t8,       inv_\txfm2\()_8h_x4_lsx
+    b             inv_txfm_add_8x4_lsx
+.\txfm1\()_\txfm2\()_8X4_END:
+endfunc
+.endm
+
+fn8x4 dct, dct
+fn8x4 identity, identity
+fn8x4 dct, adst
+fn8x4 dct, flipadst
+fn8x4 dct, identity
+fn8x4 adst, dct
+fn8x4 adst, adst
+fn8x4 adst, flipadst
+fn8x4 flipadst, dct
+fn8x4 flipadst, adst
+fn8x4 flipadst, flipadst
+fn8x4 identity, dct
+fn8x4 adst, identity
+fn8x4 flipadst, identity
+fn8x4 identity, adst
+fn8x4 identity, flipadst
+
+.macro fn4x8 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_4x8_8bpc_lsx
+.ifc \txfm1()_\txfm2, dct_dct
+    bnez          a3,       .NO_HAS_DCONLY_4x8
+
+    idct_dc 4, 8, 0
+
+    DST_ADD_W4 vr10, vr11, vr12, vr13, vr20, vr20
+
+    add.d         a0,       a0,       a1
+    alsl.d        t2,       a1,       a0,   1
+    VLD_DST_ADD_W4 vr5, vr5
+    b             .\txfm1\()_\txfm2\()_4X8_END
+.NO_HAS_DCONLY_4x8:
+.endif
+    la.local      t7,       inv_\txfm1\()_8h_x4_lsx
+    la.local      t8,       inv_\txfm2\()_4h_x8_lsx
+    b             inv_txfm_add_4x8_lsx
+.\txfm1\()_\txfm2\()_4X8_END:
+endfunc
+.endm
+
+fn4x8 dct, dct
+fn4x8 identity, identity
+fn4x8 dct, adst
+fn4x8 dct, flipadst
+fn4x8 dct, identity
+fn4x8 adst, dct
+fn4x8 adst, adst
+fn4x8 adst, flipadst
+fn4x8 flipadst, dct
+fn4x8 flipadst, adst
+fn4x8 flipadst, flipadst
+fn4x8 identity, dct
+fn4x8 adst, identity
+fn4x8 flipadst, identity
+fn4x8 identity, adst
+fn4x8 identity, flipadst
+
+.macro inv_identity4_lsx_x2 in0, in1, in2, in3, in4, out0, out1
+    vsllwil.w.h   vr4,      \in0,    0
+    vexth.w.h     vr5,      \in0
+    vsllwil.w.h   vr6,      \in1,    0
+    vexth.w.h     vr7,      \in1
+    vmul.w        vr4,      vr4,     \in2
+    vmul.w        vr5,      vr5,     \in2
+    vmul.w        vr6,      vr6,     \in2
+    vmul.w        vr7,      vr7,     \in2
+    vssrarni.h.w  vr5,      vr4,     12
+    vssrarni.h.w  vr7,      vr6,     12
+    vsadd.h       \out0,    vr5,     \in3
+    vsadd.h       \out1,    vr7,     \in4
+.endm
+
+.macro vmul_vmadd_w in0, in1, in2, in3, out0, out1
+    vsllwil.w.h   vr22,     \in0,     0
+    vexth.w.h     vr23,     \in0
+    vmul.w        \out0,    vr22,     \in2
+    vmul.w        \out1,    vr23,     \in2
+    vsllwil.w.h   vr22,     \in1,     0
+    vexth.w.h     vr23,     \in1
+    vmadd.w       \out0,    vr22,     \in3
+    vmadd.w       \out1,    vr23,     \in3
+.endm
+
+.macro vmul_vmsub_w in0, in1, in2, in3, out0, out1
+    vsllwil.w.h   vr22,     \in0,     0
+    vexth.w.h     vr23,     \in0
+    vmul.w        \out0,    vr22,     \in2
+    vmul.w        \out1,    vr23,     \in2
+    vsllwil.w.h   vr22,     \in1,     0
+    vexth.w.h     vr23,     \in1
+    vmsub.w       \out0,    vr22,     \in3
+    vmsub.w       \out1,    vr23,     \in3
+.endm
+
+.macro inv_dct16_lsx sz
+    inv_dct8_lsx vr0, vr2, vr4, vr6, vr8, vr10, vr12, vr14, \sz
+
+    la.local      t0,       idct_coeffs_h
+    vldrepl.h     vr20,     t0,       16        // 401
+    vldrepl.h     vr21,     t0,       18        // 4076
+    vmulev_vmaddod_lsx vr1, vr15, vr21, vr20, vr16, vr17, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr1, vr15, vr20, vr21, vr18, vr19, \sz
+    vssrarni.h.w  vr17,     vr16,     12        // t15a
+    vssrarni.h.w  vr19,     vr18,     12        // t8a
+    vldrepl.h     vr20,     t0,       20        // 3166 -> 1583
+    vldrepl.h     vr21,     t0,       22        // 2598 -> 1299
+    vmulev_vmaddod_lsx vr9, vr7, vr21, vr20, vr1, vr16, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr9, vr7, vr20, vr21, vr15, vr18, \sz
+    vssrarni.h.w  vr16,     vr1,      12        // t14a
+    vssrarni.h.w  vr18,     vr15,     12        // t9a
+    vldrepl.h     vr20,     t0,       24        // 1931
+    vldrepl.h     vr21,     t0,       26        // 3612
+    vmulev_vmaddod_lsx vr5, vr11, vr21, vr20, vr7, vr1, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr5, vr11, vr20, vr21, vr9, vr15, \sz
+    vssrarni.h.w  vr1,      vr7,      12        // t13a
+    vssrarni.h.w  vr15,     vr9,      12        // t10a
+    vldrepl.h     vr20,     t0,       28        // 3920
+    vldrepl.h     vr21,     t0,       30        // 1189
+    vmulev_vmaddod_lsx vr13, vr3, vr21, vr20, vr5, vr7, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr13, vr3, vr20, vr21, vr11, vr9, \sz
+    vssrarni.h.w  vr7,      vr5,      12        // t12a
+    vssrarni.h.w  vr9,      vr11,     12        // t11a
+
+    vsadd.h       vr5,      vr19,     vr18     // t8
+    vssub.h       vr11,     vr19,     vr18     // t9
+    vssub.h       vr3,      vr9,      vr15     // t10
+    vsadd.h       vr13,     vr9,      vr15     // t11
+    vsadd.h       vr18,     vr7,      vr1      // t12
+    vssub.h       vr19,     vr7,      vr1      // t13
+    vssub.h       vr9,      vr17,     vr16     // t14
+    vsadd.h       vr15,     vr17,     vr16     // t15
+
+    vldrepl.h     vr20,     t0,       4        // 1567
+    vldrepl.h     vr21,     t0,       6        // 3784
+    vmulev_vmaddod_lsx vr9, vr11, vr21, vr20, vr1, vr16, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr9, vr11, vr20, vr21, vr7, vr17, \sz
+    vssrarni.h.w  vr16,     vr1,      12       // t14a
+    vssrarni.h.w  vr17,     vr7,      12       // t9a
+
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr19, vr3, vr21, vr20, vr9, vr1, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr19, vr3, vr20, vr21, vr11, vr7, \sz
+    vneg.w        vr1,      vr1
+    vneg.w        vr9,      vr9
+    vssrarni.h.w  vr7,      vr11,     12       // t13a
+    vssrarni.h.w  vr1,      vr9,      12       // t10a
+    vsadd.h       vr9,      vr5,      vr13     // t8a
+    vssub.h       vr11,     vr5,      vr13     // t11a
+    vssub.h       vr3,      vr15,     vr18     // t12a
+    vsadd.h       vr19,     vr15,     vr18     // t15a
+    vsadd.h       vr5,      vr17,     vr1      // t9
+    vssub.h       vr13,     vr17,     vr1      // t10
+    vssub.h       vr15,     vr16,     vr7      // t13
+    vsadd.h       vr18,     vr16,     vr7      // t14
+
+    vldrepl.h     vr20,     t0,       0        // 2896
+    vmulev_vmaddod_lsx vr15, vr13, vr20, vr20, vr1, vr7, \sz
+    vneg.h        vr21,     vr20
+    vmulev_vmaddod_lsx vr15, vr13, vr20, vr21, vr17, vr16, \sz
+    vssrarni.h.w  vr7,      vr1,      12       // t13a
+    vssrarni.h.w  vr16,     vr17,     12       // t10a
+
+    vmulev_vmaddod_lsx vr3, vr11, vr20, vr20, vr13, vr23, \sz
+    vmulev_vmaddod_lsx vr3, vr11, vr20, vr21, vr15, vr17, \sz
+    vssrarni.h.w  vr23,     vr13,     12       // t12
+    vssrarni.h.w  vr17,     vr15,     12       // t11
+
+    vssub.h       vr15,     vr0,     vr19      // c[15]
+    vsadd.h       vr0,      vr0,     vr19      // c[0]
+    vsadd.h       vr1,      vr2,     vr18      // c[1]
+    vssub.h       vr20,     vr2,     vr18      // c[14]
+    vsadd.h       vr2,      vr4,     vr7       // c[2]
+    vssub.h       vr13,     vr4,     vr7       // c[13]
+    vsadd.h       vr3,      vr6,     vr23      // c[3]
+    vssub.h       vr21,     vr6,     vr23      // c[12]
+    vsadd.h       vr4,      vr8,     vr17      // c[4]
+    vssub.h       vr11,     vr8,     vr17      // c[11]
+    vsadd.h       vr7,      vr14,    vr9       // c[7]
+    vssub.h       vr8,      vr14,    vr9       // c[8]
+    vsadd.h       vr6,      vr12,    vr5       // c[6]
+    vssub.h       vr9,      vr12,    vr5       // c[9]
+    vsadd.h       vr5,      vr10,    vr16      // c[5]
+    vssub.h       vr10,     vr10,    vr16      // c[10]
+    vor.v         vr14,     vr20,    vr20
+    vor.v         vr12,     vr21,    vr21
+.endm
+
+functionl inv_dct_8h_x16_lsx
+    inv_dct16_lsx .8h
+endfuncl
+
+functionl inv_dct_4h_x16_lsx
+    inv_dct16_lsx .4h
+endfuncl
+
+.macro VLD_DST_ADD_W4_x4 in0, in1, in2, in3, in4, in5, in6 ,in7
+    alsl.d        t2,       a1,       a0,    1
+
+    VLD_DST_ADD_W4 \in0, \in1
+
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W4 \in2, \in3
+
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W4 \in4, \in5
+
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W4 \in6, \in7
+.endm
+
+.macro def_fn_4x16_base txfm
+functionl inv_txfm_\txfm\()add_4x16_lsx
+    PUSH_REG
+    blt           a3,       t5,       416f
+    vld           vr0,      a2,       16
+    vld           vr1,      a2,       48
+    vld           vr2,      a2,       80
+    vld           vr3,      a2,       112
+    vxor.v        vr23,     vr23,     vr23
+.irp i, 16, 48, 80, 112
+    vst           vr23,     a2,       \i
+.endr
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+.ifnc \txfm, identity_
+    vsrari.h      vr0,      vr0,      1
+    vsrari.h      vr1,      vr1,      1
+    vsrari.h      vr2,      vr2,      1
+    vsrari.h      vr3,      vr3,      1
+.endif
+
+    LSX_TRANSPOSE4x8_H vr0, vr1, vr2, vr3, vr8, vr9, vr24, vr25, vr26, \
+                       vr27, vr14, vr28, vr10, vr11, vr12, vr13
+
+416:
+    bge           a3,       t5,       416416f
+.irp i, vr8, vr9, vr24, vr25, vr26, vr27, vr14, vr28
+    vxor.v        \i,       \i,       \i
+.endr
+
+416416:
+    vld           vr0,      a2,       0
+    vld           vr1,      a2,       32
+    vld           vr2,      a2,       64
+    vld           vr3,      a2,       96
+    vxor.v        vr23,     vr23,     vr23
+.irp i, 0, 32, 64, 96
+    vst           vr23,     a2,       \i
+.endr
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+.ifnc \txfm, identity_
+    vsrari.h      vr0,      vr0,      1
+    vsrari.h      vr1,      vr1,      1
+    vsrari.h      vr2,      vr2,      1
+    vsrari.h      vr3,      vr3,      1
+.endif
+
+    LSX_TRANSPOSE4x8_H vr0, vr1, vr2, vr3, vr0, vr1, vr2, vr3, vr4, vr5, \
+                       vr6, vr7, vr16, vr17, vr18, vr19
+
+    vor.v         vr10,     vr24,     vr24
+    vor.v         vr11,     vr25,     vr25
+    vor.v         vr12,     vr26,     vr26
+    vor.v         vr13,     vr27,     vr27
+    vor.v         vr15,     vr28,     vr28
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vilvl.d       vr16,     vr1,      vr0
+    vilvl.d       vr17,     vr3,      vr2
+    vilvl.d       vr18,     vr5,      vr4
+    vilvl.d       vr19,     vr7,      vr6
+    vilvl.d       vr20,     vr9,      vr8
+    vilvl.d       vr21,     vr11,     vr10
+    vilvl.d       vr22,     vr13,     vr12
+    vilvl.d       vr23,     vr15,     vr14
+
+.irp i, vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    vsrari.h     \i,       \i,       4
+.endr
+
+    VLD_DST_ADD_W4_x4 vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    POP_REG
+endfuncl
+.endm
+
+def_fn_4x16_base identity_
+def_fn_4x16_base
+
+.macro fn4x16 txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_4x16_8bpc_lsx
+.ifc \txfm1()_\txfm2, dct_dct
+    bnez          a3,       .NO_HAS_DCONLY_4x16
+
+    idct_dc 4, 16, 1
+
+    DST_ADD_W4 vr10, vr11, vr12, vr13, vr5, vr5
+
+.rept 3
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,   1
+
+    VLD_DST_ADD_W4 vr5, vr5
+.endr
+    b             .\txfm1\()_\txfm2\()_4X16_END
+
+.NO_HAS_DCONLY_4x16:
+.endif
+    li.w          t5,       \eob_half
+    la.local      t7,       inv_\txfm1\()_8h_x4_lsx
+.ifc \txfm1, identity
+    la.local      t7,       inv_\txfm1\()_8h_x4_lsx1
+.endif
+    la.local      t8,       inv_\txfm2\()_4h_x16_lsx
+
+.ifc \txfm1, identity
+    b             inv_txfm_identity_add_4x16_lsx
+.else
+    b             inv_txfm_add_4x16_lsx
+.endif
+.\txfm1\()_\txfm2\()_4X16_END:
+endfunc
+.endm
+
+fn4x16 dct, dct, 29
+fn4x16 identity, identity, 29
+fn4x16 dct, adst, 29
+fn4x16 dct, flipadst, 29
+fn4x16 dct, identity, 8
+fn4x16 adst, dct, 29
+fn4x16 adst, adst, 29
+fn4x16 adst, flipadst, 29
+fn4x16 flipadst, dct, 29
+fn4x16 flipadst, adst, 29
+fn4x16 flipadst, flipadst, 29
+fn4x16 identity, dct, 32
+fn4x16 adst, identity, 8
+fn4x16 flipadst, identity, 8
+fn4x16 identity, adst, 32
+fn4x16 identity, flipadst, 32
+
+.macro inv_identity16_lsx in0, in1, in2, out0, sz
+.ifc \sz, .8h
+    vsllwil.w.h   vr16,     \in0,     0
+    vexth.w.h     vr17,     \in0
+    vmul.w        vr16,     vr16,     \in1
+    vmul.w        vr17,     vr17,     \in1
+    vsadd.h       \in2,     \in2,     \in2
+    vssrarni.h.w  vr17,     vr16,     11
+    vsadd.h       \out0,    vr17,     \in2
+.else
+    vsllwil.w.h   vr16,     \in0,     0
+    vmul.w        vr16,     vr16,     \in1
+    vsadd.h       \in2,     \in2,     \in2
+    vssrarni.h.w  vr16,     vr16,     11
+    vsadd.h       \out0,    vr16,     \in2
+.endif
+.endm
+
+.macro inv_identity16_lsx1 in0, in1, in2, out0
+    vsllwil.w.h   vr16,     \in0,     0
+    vexth.w.h     vr17,     \in1
+    vmul.w        vr18,     vr16,     \in2
+    vmul.w        vr19,     vr17,     \in2
+    vsrari.w      vr18,     vr18,     11
+    vsrari.w      vr19,     vr19,     11
+    vslli.w       vr16,     vr16,     1
+    vslli.w       vr17,     vr17,     1
+    vadd.w        vr16,     vr18,     vr16
+    vadd.w        \out0,    vr19,     vr17
+    vssrarni.h.w  \out0,    vr16,     1
+.endm
+
+functionl inv_identity_8h_x16_lsx
+    li.w          t0,       1697
+    vreplgr2vr.w  vr20,     t0
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, vr8, \
+    vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    inv_identity16_lsx \i, vr20, \i, \i, .8h
+.endr
+endfuncl
+
+functionl inv_identity_4h_x16_lsx
+    li.w          t0,       1697
+    vreplgr2vr.w  vr20,     t0
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, vr8, \
+    vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    inv_identity16_lsx \i, vr20, \i, \i, .4h
+.endr
+endfuncl
+
+functionl inv_identity_8h_x16_lsx1
+    li.w          t0,       1697
+    vreplgr2vr.w  vr20,     t0
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, vr8, \
+    vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    inv_identity16_lsx1 \i, \i, vr20, \i
+.endr
+endfuncl
+
+const iadst16_coeffs_h, align=4
+    .short         4091, 201, 3973, 995
+    .short         3703, 1751, 3290, 2440
+    .short         2751, 3035, 2106, 3513
+    .short         1380, 3857, 601, 4052
+endconst
+
+.macro inv_adst16_lsx txfm, sz
+    la.local      t0,       iadst16_coeffs_h
+    vldrepl.h     vr20,     t0,        0        // 4091
+    vldrepl.h     vr21,     t0,        2        // 201
+    vmulev_vmaddod_lsx vr15, vr0, vr20, vr21, vr16, vr18, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr15, vr0, vr21, vr20, vr17, vr19, \sz
+    vssrarni.h.w  vr18,     vr16,      12       // t0
+    vssrarni.h.w  vr19,     vr17,      12       // t1
+    vldrepl.h     vr20,     t0,        4        // 3973
+    vldrepl.h     vr21,     t0,        6        // 995
+    vmulev_vmaddod_lsx vr13, vr2, vr20, vr21, vr16, vr0, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr13, vr2, vr21, vr20, vr17, vr15, \sz
+    vssrarni.h.w  vr0,      vr16,      12       // t2
+    vssrarni.h.w  vr15,     vr17,      12       // t3
+    vldrepl.h     vr20,     t0,        8       // 3703
+    vldrepl.h     vr21,     t0,        10       // 1751
+    vmulev_vmaddod_lsx vr11, vr4, vr20, vr21, vr16, vr2, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr11, vr4, vr21, vr20, vr17, vr13, \sz
+    vssrarni.h.w  vr2,      vr16,      12       // t4
+    vssrarni.h.w  vr13,     vr17,      12       // t5
+    vldrepl.h     vr20,     t0,        12       // 3290 -> 1645
+    vldrepl.h     vr21,     t0,        14       // 2440 -> 1220
+    vmulev_vmaddod_lsx vr9, vr6, vr20, vr21, vr16, vr4, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr9, vr6, vr21, vr20, vr17, vr11, \sz
+    vssrarni.h.w  vr4,      vr16,      12       // t6
+    vssrarni.h.w  vr11,     vr17,      12       // t7
+    vldrepl.h     vr20,     t0,        16       // 2751
+    vldrepl.h     vr21,     t0,        18       // 3035
+    vmulev_vmaddod_lsx vr7, vr8, vr20, vr21, vr16, vr6, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr7, vr8, vr21, vr20, vr17, vr9, \sz
+    vssrarni.h.w  vr6,      vr16,      12       // t8
+    vssrarni.h.w  vr9,      vr17,      12       // t9
+    vldrepl.h     vr20,     t0,        20       // 2106
+    vldrepl.h     vr21,     t0,        22       // 3513
+    vmulev_vmaddod_lsx vr5, vr10, vr20, vr21, vr16, vr7, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr5, vr10, vr21, vr20, vr17, vr8, \sz
+    vssrarni.h.w  vr7,      vr16,      12       // t10
+    vssrarni.h.w  vr8,      vr17,      12       // t11
+    vldrepl.h     vr20,     t0,        24       // 1380
+    vldrepl.h     vr21,     t0,        26       // 3857
+    vmulev_vmaddod_lsx vr3, vr12, vr20, vr21, vr16, vr5, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr3, vr12, vr21, vr20, vr17, vr10, \sz
+    vssrarni.h.w  vr5,      vr16,      12       // t12
+    vssrarni.h.w  vr10,     vr17,      12       // t13
+    vldrepl.h     vr20,     t0,        28       // 601
+    vldrepl.h     vr21,     t0,        30       // 4052
+    vmulev_vmaddod_lsx vr1, vr14, vr20, vr21, vr16, vr3, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr1, vr14, vr21, vr20, vr17, vr12, \sz
+    vssrarni.h.w  vr3,      vr16,      12       // t14
+    vssrarni.h.w  vr12,     vr17,      12       // t15
+
+    vsadd.h       vr1,      vr18,      vr6      // t0a
+    vssub.h       vr14,     vr18,      vr6      // t8a
+    vsadd.h       vr16,     vr19,      vr9      // t1a
+    vssub.h       vr17,     vr19,      vr9      // t9a
+    vsadd.h       vr6,      vr0,       vr7      // t2a
+    vssub.h       vr18,     vr0,       vr7      // t10a
+    vsadd.h       vr9,      vr15,      vr8      // t3a
+    vssub.h       vr19,     vr15,      vr8      // t11a
+    vsadd.h       vr0,      vr2,       vr5      // t4a
+    vssub.h       vr7,      vr2,       vr5      // t12a
+    vsadd.h       vr8,      vr13,      vr10     // t5a
+    vssub.h       vr15,     vr13,      vr10     // t13a
+    vsadd.h       vr2,      vr4,       vr3      // t6a
+    vssub.h       vr5,      vr4,       vr3      // t14a
+    vsadd.h       vr10,     vr11,      vr12     // t7a
+    vssub.h       vr13,     vr11,      vr12     // t15a
+
+    la.local      t0,       idct_coeffs_h
+
+    vldrepl.h     vr20,     t0,        8        // 799
+    vldrepl.h     vr21,     t0,        10       // 4017
+    vmulev_vmaddod_lsx vr14, vr17, vr21, vr20, vr3, vr11, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr14, vr17, vr20, vr21, vr4, vr12, \sz
+    vssrarni.h.w  vr11,     vr3,       12       // t8
+    vssrarni.h.w  vr12,     vr4,       12       // t9
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr15, vr7, vr20, vr21, vr3, vr14, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr15, vr7, vr21, vr20, vr4, vr17, \sz
+    vssrarni.h.w  vr14,     vr3,       12       // t13
+    vssrarni.h.w  vr17,     vr4,       12       // t12
+    vldrepl.h     vr20,     t0,        12       // 3406
+    vldrepl.h     vr21,     t0,        14       // 2276
+    vmulev_vmaddod_lsx vr18, vr19, vr21, vr20, vr3, vr7, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr18, vr19, vr20, vr21, vr4, vr15, \sz
+    vssrarni.h.w  vr7,      vr3,       12       // t10
+    vssrarni.h.w  vr15,     vr4,       12       // t11
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr13, vr5, vr20, vr21, vr3, vr18, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr13, vr5, vr21, vr20, vr4, vr19, \sz
+    vssrarni.h.w  vr18,     vr3,       12       // t15
+    vssrarni.h.w  vr19,     vr4,       12       // t14
+
+    vsadd.h       vr5,      vr1,       vr0      // t0
+    vssub.h       vr13,     vr1,       vr0      // t4
+    vsadd.h       vr3,      vr16,      vr8      // t1
+    vssub.h       vr4,      vr16,      vr8      // t5
+    vsadd.h       vr0,      vr6,       vr2      // t2
+    vssub.h       vr1,      vr6,       vr2      // t6
+    vsadd.h       vr8,      vr9,       vr10     // t3
+    vssub.h       vr16,     vr9,       vr10     // t7
+    vsadd.h       vr2,      vr11,      vr17     // t8a
+    vssub.h       vr6,      vr11,      vr17     // t12a
+    vsadd.h       vr9,      vr12,      vr14     // t9a
+    vssub.h       vr10,     vr12,      vr14     // t13a
+    vsadd.h       vr11,     vr7,       vr19     // t10a
+    vssub.h       vr17,     vr7,       vr19     // t14a
+    vsadd.h       vr12,     vr15,      vr18     // t11a
+    vssub.h       vr14,     vr15,      vr18     // t15a
+
+    vldrepl.h     vr20,     t0,        4        // 1567
+    vldrepl.h     vr21,     t0,        6       // 3784
+    vmulev_vmaddod_lsx vr13, vr4, vr21, vr20, vr7, vr18, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr13, vr4, vr20, vr21, vr15, vr19, \sz
+    vssrarni.h.w  vr18,     vr7,       12       // t4a
+    vssrarni.h.w  vr19,     vr15,      12       // t5a
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr16, vr1, vr20, vr21, vr7, vr4, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr16, vr1, vr21, vr20, vr15, vr13, \sz
+    vssrarni.h.w  vr4,      vr7,       12       // t7a
+    vssrarni.h.w  vr13,     vr15,      12       // t6a
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr6, vr10, vr21, vr20, vr7, vr1, \sz
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr6, vr10, vr20, vr21, vr15, vr16, \sz
+    vssrarni.h.w  vr1,      vr7,       12       // t12
+    vssrarni.h.w  vr16,     vr15,      12       // t13
+    vneg.h        vr21,     vr21
+    vmulev_vmaddod_lsx vr14, vr17, vr20, vr21, vr7, vr6, \sz
+    vneg.h        vr20,     vr20
+    vmulev_vmaddod_lsx vr14, vr17, vr21, vr20, vr15, vr10, \sz
+    vssrarni.h.w  vr6,      vr7,       12       // t15
+    vssrarni.h.w  vr10,     vr15,      12       // t14
+
+    vssub.h       vr17,     vr5,       vr0      // t2a
+    vsadd.h       vr14,     vr5,       vr0      // out[0]
+    vssub.h       vr7,      vr3,       vr8      // t3a
+    vsadd.h       vr15,     vr3,       vr8      // out[15]
+    vsllwil.w.h   vr22,     vr15,      0
+    vexth.w.h     vr15,     vr15
+    vneg.w        vr22,     vr22
+    vneg.w        vr15,     vr15
+    vssrarni.h.w  vr15,     vr22,      0        // out[15]
+
+    vsadd.h       vr3,      vr19,      vr4      // out[12]
+    vssub.h       vr8,      vr19,      vr4      // t7
+    vssub.h       vr0,      vr18,      vr13     // t6
+    vsadd.h       vr5,      vr18,      vr13     // out[3]
+    vsllwil.w.h   vr22,     vr5,       0
+    vexth.w.h     vr5,      vr5
+    vneg.w        vr22,     vr22
+    vneg.w        vr5,      vr5
+    vssrarni.h.w  vr5,      vr22,      0        // out[3]
+
+    vsadd.h       vr13,     vr9,       vr12     // out[14]
+    vssub.h       vr19,     vr9,       vr12     // t11
+    vssub.h       vr4,      vr2,       vr11     // t10
+    vsadd.h       vr18,     vr2,       vr11     // out[1]
+    vsllwil.w.h   vr22,     vr18,      0
+    vexth.w.h     vr18,     vr18
+    vneg.w        vr22,     vr22
+    vneg.w        vr18,     vr18
+    vssrarni.h.w  vr18,     vr22,      0        // out[1]
+
+    vsadd.h       vr2,      vr1,       vr10     // out[2]
+    vssub.h       vr11,     vr1,       vr10     // t14a
+    vssub.h       vr12,     vr16,      vr6      // t15a
+    vsadd.h       vr9,      vr16,      vr6      // out[13]
+    vsllwil.w.h   vr22,     vr9,       0
+    vexth.w.h     vr9,      vr9
+    vneg.w        vr22,     vr22
+    vneg.w        vr9,      vr9
+    vssrarni.h.w  vr9,      vr22,      0        // out[13]
+
+    vldrepl.h     vr20,     t0,        0        // 2896
+    vmulev_vmaddod_lsx vr17, vr7, vr20, vr20, vr6, vr10, \sz
+    vneg.h        vr21,     vr20
+    vmulev_vmaddod_lsx vr17, vr7, vr20, vr21, vr16, vr1, \sz
+    vssrarni.h.w  vr1,      vr16,      12       // out[8]
+    vsrari.w      vr6,      vr6,       12
+    vsrari.w      vr10,     vr10,      12
+    vneg.w        vr6,      vr6
+    vneg.w        vr10,     vr10
+    vssrarni.h.w  vr10,     vr6,       0        // out[7]
+    vmulev_vmaddod_lsx vr0, vr8, vr20, vr21, vr16, vr17, \sz
+    vmulev_vmaddod_lsx vr0, vr8, vr20, vr20, vr6, vr7, \sz
+    vssrarni.h.w  vr7,      vr6,       12       // out[4]
+    vsrari.w      vr16,     vr16,      12
+    vsrari.w      vr17,     vr17,      12
+    vneg.w        vr16,     vr16
+    vneg.w        vr17,     vr17
+    vssrarni.h.w  vr17,     vr16,       0        // out[11]
+
+    vmulev_vmaddod_lsx vr4, vr19, vr20, vr21, vr16, vr0, \sz
+    vmulev_vmaddod_lsx vr4, vr19, vr20, vr20, vr6, vr8, \sz
+    vssrarni.h.w  vr8,      vr6,       12       // out[6]
+    vsrari.w      vr16,     vr16,      12
+    vsrari.w      vr0,      vr0,       12
+    vneg.w        vr16,     vr16
+    vneg.w        vr0,      vr0
+    vssrarni.h.w  vr0,      vr16,      0    // out[9]
+
+    vmulev_vmaddod_lsx vr11, vr12, vr20, vr20, vr6, vr4, \sz
+    vmulev_vmaddod_lsx vr11, vr12, vr20, vr21, vr16, vr19, \sz
+    vssrarni.h.w  vr19,     vr16,      12       // out[10]
+    vsrari.w      vr6,      vr6,       12
+    vsrari.w      vr4,      vr4,       12
+    vneg.w        vr6,      vr6
+    vneg.w        vr4,      vr4
+    vssrarni.h.w  vr4,      vr6,       0        // out[5]
+
+.ifc \txfm, adst
+    vor.v         vr12,     vr3,       vr3
+    vor.v         vr3,      vr5,       vr5
+    vor.v         vr5,      vr4,       vr4
+    vor.v         vr4,      vr7,       vr7
+    vor.v         vr7,      vr10,      vr10
+    vor.v         vr10,     vr19,      vr19
+    vor.v         vr6,      vr8,       vr8
+    vor.v         vr8,      vr1,       vr1
+    vor.v         vr11,     vr17,      vr17
+    vor.v         vr20,     vr13,      vr13
+    vor.v         vr13,     vr9,       vr9
+    vor.v         vr9,      vr0,       vr0
+    vor.v         vr0,      vr14,      vr14
+    vor.v         vr14,     vr20,      vr20
+    vor.v         vr1,      vr18,      vr18
+.else
+    vor.v         vr6,      vr0,       vr0
+    vor.v         vr0,      vr15,      vr15
+    vor.v         vr15,     vr14,      vr14
+    vor.v         vr14,     vr18,      vr18
+    vor.v         vr11,     vr7,       vr7
+    vor.v         vr7,      vr1,       vr1
+    vor.v         vr1,      vr13,      vr13
+    vor.v         vr13,     vr2,       vr2
+    vor.v         vr2,      vr9,       vr9
+    vor.v         vr9,      vr8,       vr8
+    vor.v         vr8,      vr10,      vr10
+    vor.v         vr10,     vr4,       vr4
+    vor.v         vr4,      vr17,      vr17
+    vor.v         vr12,     vr5,       vr5
+    vor.v         vr5,      vr19,      vr19
+.endif
+.endm // inv_adst16_lsx
+
+functionl inv_adst_8h_x16_lsx
+    inv_adst16_lsx adst, 8h
+endfuncl
+
+functionl inv_flipadst_8h_x16_lsx
+    inv_adst16_lsx flipadst, 8h
+endfuncl
+
+functionl inv_adst_4h_x16_lsx
+    inv_adst16_lsx adst, 4h
+endfuncl
+
+functionl inv_flipadst_4h_x16_lsx
+    inv_adst16_lsx flipadst, 4h
+endfuncl
+
+.macro VLD_DST_ADD_W8_x4 in0, in1, in2, in3, in4, in5, in6, in7, in8, \
+                         in9, in10, in11, in12, in13, in14, in15
+
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W8 \in0, \in1, \in2, \in3
+
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W8 \in4, \in5, \in6, \in7
+
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W8 \in8, \in9, \in10, \in11
+
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W8 \in12, \in13, \in14, \in15
+.endm
+
+.macro def_base_8x16 txfm1
+functionl inv_txfm_\txfm1\()add_8x16_lsx
+    blt     a3,    t5,   816f
+    vld_x8 a2, 16, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vxor.v        vr23,     vr23,     vr23
+.irp i, 16, 48, 80, 112, 144, 176, 208, 240
+    vst           vr23,     a2,       \i
+.endr
+
+    li.w          t0,       2896
+    vreplgr2vr.w  vr23,     t0
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    rect2_lsx     \i,       vr23,     \i
+.endr
+
+.ifc \txfm1, identity_
+    LSX_TRANSPOSE8x8_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+.else
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+    vsrari_h_x8 vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, 1
+
+    LSX_TRANSPOSE8x8_H vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                       vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                       vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+.endif
+
+816:
+    bge           a3,       t5,       816816f
+.irp i, vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    vxor.v        \i,       \i,       \i
+.endr
+
+816816:
+    vld_x8 a2, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vxor.v        vr23,     vr23,     vr23
+.irp i, 0, 32, 64, 96, 128, 160, 192, 224
+    vst           vr23,     a2,       \i
+.endr
+
+    li.w          t0,       2896
+    vreplgr2vr.w  vr23,     t0
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    rect2_lsx     \i,       vr23,     \i
+.endr
+
+.ifc \txfm1, identity_
+
+.else
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vsrari.h      \i,       \i,       1
+.endr
+.endif
+
+    LSX_TRANSPOSE8x8_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vor.v   vr0, vr0, vr0
+    vsrari_h_x8 vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23, 4
+    vsrari_h_x8 vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, 4
+
+    VLD_DST_ADD_W8_x4 vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                      vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+endfuncl
+.endm
+
+def_base_8x16 identity_
+def_base_8x16
+
+.macro DST_ADD_W16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11
+    vsllwil.hu.bu vr4,      \in0,     0
+    vexth.hu.bu   vr0,      \in0
+    vsllwil.hu.bu vr5,      \in1,     0
+    vexth.hu.bu   vr1,      \in1
+    vsllwil.hu.bu vr6,      \in2,     0
+    vexth.hu.bu   vr2,      \in2
+    vsllwil.hu.bu vr7,      \in3,     0
+    vexth.hu.bu   vr3,      \in3
+    vadd.h        vr4,      vr4,      \in4
+    vadd.h        vr0,      vr0,      \in5
+    vadd.h        vr5,      vr5,      \in6
+    vadd.h        vr1,      vr1,      \in7
+    vadd.h        vr6,      vr6,      \in8
+    vadd.h        vr2,      vr2,      \in9
+    vadd.h        vr7,      vr7,      \in10
+    vadd.h        vr3,      vr3,      \in11
+    vssrani.bu.h  vr0,      vr4,      0
+    vssrani.bu.h  vr1,      vr5,      0
+    vssrani.bu.h  vr2,      vr6,      0
+    vssrani.bu.h  vr3,      vr7,      0
+    vst           vr0,      a0,       0
+    vstx          vr1,      a0,       a1
+    vst           vr2,      t2,       0
+    vstx          vr3,      t2,       a1
+.endm
+
+.macro VLD_DST_ADD_W16 in0, in1, in2, in3, in4, in5, in6, in7
+    vld           vr0,      a0,       0
+    vldx          vr1,      a0,       a1
+    vld           vr2,      t2,       0
+    vldx          vr3,      t2,       a1
+    DST_ADD_W16 vr0, vr1, vr2, vr3, \in0, \in1, \in2, \in3, \
+                \in4, \in5, \in6, \in7
+.endm
+
+.macro def_fn_16x8 txfm1
+functionl inv_txfm_\txfm1\()add_16x8_lsx
+    PUSH_REG
+
+    vld_x16 a2, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    vxor.v        vr23,     vr23,     vr23
+.irp i, 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, \
+    176, 192, 208, 224, 240
+    vst           vr23,     a2,       \i
+.endr
+
+    li.w          t0,       2896
+    vreplgr2vr.w  vr23,     t0
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+    vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    rect2_lsx     \i,       vr23,     \i
+.endr
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+.ifnc \txfm1, identity_
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+    vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    vsrari.h       \i,       \i,       1
+.endr
+.endif
+
+    LSX_TRANSPOSE8x8_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vsrari_h_x8 vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                vr24, vr25, vr26, vr27, vr28, vr29, vr30, vr31, 4
+
+    LSX_TRANSPOSE8x8_H vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                       vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vsrari_h_x8 vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, 4
+
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W16 vr24, vr8, vr25, vr9, vr26, vr10, vr27, vr11
+
+    alsl.d        a0,       a1,       a0,    2
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W16 vr28, vr12, vr29, vr13, vr30, vr14, vr31, vr15
+
+    POP_REG
+endfuncl
+.endm
+
+def_fn_16x8 identity_
+def_fn_16x8
+
+.macro fun16x8 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_16x8_8bpc_lsx
+.ifc \txfm1\()_\txfm2, dct_dct
+    bnez          a3,       .NO_HAS_DCONLY_16x8
+
+    idct_dc 16, 8, 1
+
+    DST_ADD_W16 vr10, vr11, vr12, vr13, vr20, vr20, vr20, \
+                vr20, vr20, vr20, vr20, vr20
+
+    alsl.d        a0,       a1,       a0,     2
+    alsl.d        t2,       a1,       a0,     1
+    VLD_DST_ADD_W16 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+    b             .\txfm1\()_\txfm2\()_16x8_END
+.NO_HAS_DCONLY_16x8:
+.endif
+
+    la.local     t7,    inv_\txfm1\()_8h_x16_lsx
+.ifc \txfm1, identity
+    la.local     t7,    inv_identity_8h_x16_lsx1
+.endif
+
+    la.local     t8,    inv_\txfm2\()_8h_x8_lsx
+
+.ifc \txfm1, identity
+    b            inv_txfm_identity_add_16x8_lsx
+.else
+    b            inv_txfm_add_16x8_lsx
+.endif
+
+.\txfm1\()_\txfm2\()_16x8_END:
+endfunc
+.endm
+
+fun16x8 dct, dct
+fun16x8 identity, identity
+fun16x8 dct, adst
+fun16x8 dct, flipadst
+fun16x8 dct, identity
+fun16x8 adst, dct
+fun16x8 adst, adst
+fun16x8 adst, flipadst
+fun16x8 flipadst, dct
+fun16x8 flipadst, adst
+fun16x8 flipadst, flipadst
+fun16x8 identity, dct
+fun16x8 adst, identity
+fun16x8 flipadst, identity
+fun16x8 identity, adst
+fun16x8 identity, flipadst
+
+.macro fun8x16 txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_8x16_8bpc_lsx
+.ifc \txfm1\()_\txfm2, dct_dct
+    bnez          a3,       .NO_HAS_DCONLY_8x16
+
+    idct_dc 8, 16, 1
+
+    DST_ADD_W8 vr10, vr11, vr12, vr13, vr20, vr20, vr20, vr20
+.rept 3
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,     1
+    VLD_DST_ADD_W8 vr20, vr20, vr20, vr20
+.endr
+
+    b             .\txfm1\()_\txfm2\()_8x16_END
+.NO_HAS_DCONLY_8x16:
+.endif
+    li.w         t5,    \eob_half
+.ifnc \txfm1, identity
+    la.local     t7,    inv_\txfm1\()_8h_x8_lsx
+.endif
+
+    la.local     t8,    inv_\txfm2\()_8h_x16_lsx
+.ifc \txfm1, identity
+    b            inv_txfm_identity_add_8x16_lsx
+.else
+    b            inv_txfm_add_8x16_lsx
+.endif
+.\txfm1\()_\txfm2\()_8x16_END:
+endfunc
+.endm
+
+fun8x16 dct, dct, 43
+fun8x16 identity, identity, 43
+fun8x16 dct, adst, 43
+fun8x16 dct, flipadst, 43
+fun8x16 dct, identity, 8
+fun8x16 adst, dct, 43
+fun8x16 adst, adst, 43
+fun8x16 adst, flipadst, 43
+fun8x16 flipadst, dct, 43
+fun8x16 flipadst, adst, 43
+fun8x16 flipadst, flipadst, 43
+fun8x16 identity, dct, 64
+fun8x16 adst, identity, 8
+fun8x16 flipadst, identity, 8
+fun8x16 identity, adst, 64
+fun8x16 identity, flipadst, 64
+
+functionl inv_txfm_add_16x16_lsx
+    malloc_space 512
+
+    addi.d        t1,       sp,       64
+    addi.d        t2,       a2,       0
+.rept 2
+    vld_x16 a2, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vxor.v        vr23,     vr23,     vr23
+.irp i, 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, \
+    384, 416, 448, 480
+    vst           vr23,     a2,       \i
+.endr
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+
+    LSX_TRANSPOSE8x8_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+    LSX_TRANSPOSE8x8_H vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                       vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+    vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    vsrari.h       \i,       \i,       2
+.endr
+    vst_x8 t1, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vst_x8 t1, 16, 32, vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    addi.d         t1,       t1,       256
+    addi.d         a2,       a2,       16
+    blt            a3,       t5,       1616f
+.endr
+
+1616:
+    bge           a3,       t5,       16161616f
+    addi.d        t1,       sp,       320
+    vxor.v        vr23,     vr23,     vr23
+.irp i, 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, \
+    240
+    vst           vr23,     t1,       \i
+.endr
+
+16161616:
+    addi.d        t1,       sp,       64
+.rept 2
+    vld_x16 t1, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vst_x16 t1, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    addi.d        t1,       t1,       16
+.endr
+    alsl.d        t2,       a1,       a0,    1
+    addi.d        t1,       sp,       64
+.rept 4
+    vld_x8 t1, 0, 16, vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    vsrari_h_x8 vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23, \
+                vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23 4
+    VLD_DST_ADD_W16 vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    alsl.d        a0,       a1,       a0,    2
+    alsl.d        t2,       a1,       a0,    1
+    addi.d        t1,       t1,       128
+.endr
+    free_space 512
+endfuncl
+
+.macro fun16x16 txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_16x16_8bpc_lsx
+.ifc \txfm1\()_\txfm2, dct_dct
+    bnez          a3,       .NO_HAS_DCONLY_16x16
+
+    idct_dc 16, 16, 2
+
+    DST_ADD_W16 vr10, vr11, vr12, vr13, vr20, vr20, vr20, \
+                    vr20, vr20, vr20, vr20, vr20
+.rept 3
+    alsl.d        a0,       a1,       a0,     2
+    alsl.d        t2,       a1,       a0,     1
+
+    VLD_DST_ADD_W16 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+.endr
+    b             .\txfm1\()_\txfm2\()_16x16_END
+.NO_HAS_DCONLY_16x16:
+.endif
+    li.w         t5,    \eob_half
+    la.local     t7,    inv_\txfm1\()_8h_x16_lsx
+    la.local     t8,    inv_\txfm2\()_8h_x16_lsx
+
+    b            inv_txfm_add_16x16_lsx
+.\txfm1\()_\txfm2\()_16x16_END:
+endfunc
+.endm
+
+fun16x16 dct, dct, 36
+fun16x16 adst, adst, 36
+fun16x16 adst, dct, 36
+fun16x16 dct, adst, 36
+fun16x16 flipadst, dct, 36
+fun16x16 dct, flipadst, 36
+fun16x16 adst, flipadst, 36
+fun16x16 flipadst, adst, 36
+
+.macro dct_8x32_core_lsx in1, in2, vld_st0, vld_st1, vld_stride, \
+                         vst_st0, vst_st1, vst_st2, vst_st3, vst_stride, \
+                         transpose8x8, shift
+    la.local      t0,       idct_coeffs
+    vldrepl.w     vr20,     t0,       64           // 201
+    vldrepl.w     vr21,     t0,       68           // 4091
+    vmul_vmadd_w vr0, vr30, vr21, vr20, vr8, vr9
+    vmul_vmsub_w vr0, vr30, vr20, vr21, vr11, vr10
+    vssrarni.h.w  vr9,      vr8,      12           // t31a
+    vssrarni.h.w  vr10,     vr11,     12           // t16a
+    vldrepl.w     vr20,     t0,       72           // 3035
+    vldrepl.w     vr21,     t0,       76           // 2751
+    vmul_vmadd_w vr19, vr7, vr21, vr20, vr8, vr0
+    vmul_vmsub_w vr19, vr7, vr20, vr21, vr11, vr30
+    vssrarni.h.w  vr0,      vr8,      12           // t30a
+    vssrarni.h.w  vr30,     vr11,     12           // t17a
+    vldrepl.w     vr20,     t0,       80           // 1751
+    vldrepl.w     vr21,     t0,       84           // 3703
+    vmul_vmadd_w vr4, vr26, vr21, vr20, vr8, vr7
+    vmul_vmsub_w vr4, vr26, vr20, vr21, vr11, vr19
+    vssrarni.h.w  vr7,      vr8,      12           // t29a
+    vssrarni.h.w  vr19,     vr11,     12           // t18a
+    vldrepl.w     vr20,     t0,       88           // 3857
+    vldrepl.w     vr21,     t0,       92           // 1380
+    vmul_vmadd_w vr27, vr3, vr21, vr20, vr8, vr4
+    vmul_vmsub_w vr27, vr3, vr20, vr21, vr11, vr26
+    vssrarni.h.w  vr4,      vr8,      12           // t28a
+    vssrarni.h.w  vr26,     vr11,     12           // t19a
+    vldrepl.w     vr20,     t0,       96           // 995
+    vldrepl.w     vr21,     t0,       100          // 3973
+    vmul_vmadd_w vr2, vr28, vr21, vr20, vr8, vr3
+    vmul_vmsub_w vr2, vr28, vr20, vr21, vr11, vr27
+    vssrarni.h.w  vr3,      vr8,      12           // t27a
+    vssrarni.h.w  vr27,     vr11,     12           // t20a
+    vldrepl.w     vr20,     t0,       104          // 3513
+    vldrepl.w     vr21,     t0,       108          // 2106
+    vmul_vmadd_w vr25, vr5, vr21, vr20, vr8, vr2
+    vmul_vmsub_w vr25, vr5, vr20, vr21, vr11, vr28
+    vssrarni.h.w  vr2,      vr8,      12           // t26a
+    vssrarni.h.w  vr28,     vr11,     12           // t21a
+    vldrepl.w     vr20,     t0,       112          // 2440 -> 1220
+    vldrepl.w     vr21,     t0,       116          // 3290 -> 1645
+    vmul_vmadd_w vr6, vr24, vr21, vr20, vr8, vr5
+    vmul_vmsub_w vr6, vr24, vr20, vr21, vr11, vr25
+    vssrarni.h.w  vr5,      vr8,      12           // t25a
+    vssrarni.h.w  vr25,     vr11,     12           // t22a
+    vldrepl.w     vr20,     t0,       120          // 4052
+    vldrepl.w     vr21,     t0,       124          // 601
+    vmul_vmadd_w vr29, vr1, vr21, vr20, vr8, vr6
+    vmul_vmsub_w vr29, vr1, vr20, vr21, vr11, vr24
+    vssrarni.h.w  vr6,      vr8,      12           // t24a
+    vssrarni.h.w  vr24,     vr11,     12           // t23a
+
+    vsadd.h       vr1,      vr10,     vr30         // t16
+    vssub.h       vr29,     vr10,     vr30         // t17
+    vssub.h       vr8,      vr26,     vr19         // t18
+    vsadd.h       vr31,     vr26,     vr19         // t19
+    vsadd.h       vr10,     vr27,     vr28         // t20
+    vssub.h       vr30,     vr27,     vr28         // t21
+    vssub.h       vr19,     vr24,     vr25         // t22
+    vsadd.h       vr26,     vr24,     vr25         // t23
+    vsadd.h       vr27,     vr6,      vr5          // t24
+    vssub.h       vr28,     vr6,      vr5          // t25
+    vssub.h       vr24,     vr3,      vr2          // t26
+    vsadd.h       vr25,     vr3,      vr2          // t27
+    vsadd.h       vr5,      vr4,      vr7          // t28
+    vssub.h       vr6,      vr4,      vr7          // t29
+    vssub.h       vr2,      vr9,      vr0          // t30
+    vsadd.h       vr3,      vr9,      vr0          // t31
+
+    vldrepl.w     vr20,     t0,       16           // 799
+    vldrepl.w     vr21,     t0,       20           // 4017
+    vmul_vmadd_w vr2, vr29, vr21, vr20, vr4, vr7
+    vmul_vmsub_w vr2, vr29, vr20, vr21, vr11, vr0
+    vssrarni.h.w  vr7,      vr4,      12           // t30a
+    vssrarni.h.w  vr0,      vr11,     12           // t17a
+    vmul_vmadd_w vr6, vr8, vr21, vr20, vr4, vr9
+    vneg.w        vr4,      vr4
+    vneg.w        vr9,      vr9
+    vmul_vmsub_w vr6, vr8, vr20, vr21, vr11, vr2
+    vssrarni.h.w  vr9,      vr4,      12           // t18a
+    vssrarni.h.w  vr2,      vr11,     12           // t29a
+    vldrepl.w     vr20,     t0,       24           // 3406 -> 1703
+    vldrepl.w     vr21,     t0,       28           // 2276 -> 1138
+    vmul_vmadd_w vr24, vr30, vr21, vr20, vr4, vr29
+    vmul_vmsub_w vr24, vr30, vr20, vr21, vr11, vr6
+    vssrarni.h.w  vr29,     vr4,      12           // t26a
+    vssrarni.h.w  vr6,      vr11,     12           // t21a
+    vmul_vmadd_w vr28, vr19, vr21, vr20, vr4, vr8
+    vneg.w        vr4,      vr4
+    vneg.w        vr8,      vr8
+    vmul_vmsub_w vr28, vr19, vr20, vr21, vr11, vr24
+    vssrarni.h.w  vr8,      vr4,      12           // t22a
+    vssrarni.h.w  vr24,     vr11,     12           // t25a
+
+    vsadd.h       vr4,      vr1,      vr31         // t16a
+    vssub.h       vr30,     vr1,      vr31         // t19a
+    vsadd.h       vr19,     vr0,      vr9          // t17
+    vssub.h       vr28,     vr0,      vr9          // t18
+    vssub.h       vr1,      vr26,     vr10         // t20a
+    vsadd.h       vr31,     vr26,     vr10         // t23a
+    vssub.h       vr0,      vr8,      vr6          // t21
+    vsadd.h       vr9,      vr8,      vr6          // t22
+    vsadd.h       vr10,     vr27,     vr25         // t24a
+    vssub.h       vr26,     vr27,     vr25         // t27a
+    vsadd.h       vr6,      vr24,     vr29         // t25
+    vssub.h       vr8,      vr24,     vr29         // t26
+    vssub.h       vr25,     vr3,      vr5          // t28a
+    vsadd.h       vr27,     vr3,      vr5          // t31a
+    vssub.h       vr24,     vr7,      vr2          // t29
+    vsadd.h       vr29,     vr7,      vr2          // t30
+
+    vldrepl.w     vr20,     t0,       8            // 1567
+    vldrepl.w     vr21,     t0,       12           // 3784
+    vmul_vmadd_w vr24, vr28, vr21, vr20, vr3, vr5
+    vmul_vmsub_w vr24, vr28, vr20, vr21, vr11, vr2
+    vssrarni.h.w  vr5,      vr3,      12           // t29a
+    vssrarni.h.w  vr2,      vr11,     12           // 18a
+    vmul_vmadd_w vr25, vr30, vr21, vr20, vr3, vr7
+    vmul_vmsub_w vr25, vr30, vr20, vr21, vr11, vr24
+    vssrarni.h.w  vr7,      vr3,      12           // t28
+    vssrarni.h.w  vr24,     vr11,     12           // t19
+    vmul_vmadd_w vr26, vr1, vr21, vr20, vr3, vr28
+    vneg.w        vr3,      vr3
+    vneg.w        vr28,     vr28
+    vmul_vmsub_w vr26, vr1, vr20, vr21, vr11, vr25
+    vssrarni.h.w  vr28,     vr3,      12           // t20
+    vssrarni.h.w  vr25,     vr11,     12           // t27
+    vmul_vmadd_w vr8, vr0, vr21, vr20, vr3, vr30
+    vneg.w        vr3,      vr3
+    vneg.w        vr30,     vr30
+    vmul_vmsub_w vr8, vr0, vr20, vr21, vr11, vr1
+    vssrarni.h.w  vr30,     vr3,      12           // t21a
+    vssrarni.h.w  vr1,      vr11,     12           // t26a
+
+    vsadd.h       vr3,      vr4,      vr31         // t16
+    vssub.h       vr26,     vr4,      vr31         // t23
+    vsadd.h       vr0,      vr19,     vr9          // t17a
+    vssub.h       vr8,      vr19,     vr9          // t22a
+    vsadd.h       vr4,      vr2,      vr30         // t18
+    vssub.h       vr31,     vr2,      vr30         // t21
+    vsadd.h       vr9,      vr24,     vr28         // t19a
+    vssub.h       vr19,     vr24,     vr28         // t20a
+    vssub.h       vr2,      vr27,     vr10         // t24
+    vsadd.h       vr30,     vr27,     vr10         // t31
+    vssub.h       vr24,     vr29,     vr6          // t25a
+    vsadd.h       vr28,     vr29,     vr6          // t30a
+    vssub.h       vr10,     vr5,      vr1          // t26
+    vsadd.h       vr27,     vr5,      vr1          // t29
+    vssub.h       vr6,      vr7,      vr25         // t27a
+    vsadd.h       vr29,     vr7,      vr25         // t28a
+
+    vldrepl.w     vr20,     t0,       0            // 2896
+    vmul_vmsub_w vr6, vr19, vr20, vr20, vr1, vr5
+    vmul_vmadd_w vr6, vr19, vr20, vr20, vr11, vr7
+    vssrarni.h.w  vr5,      vr1,      12           // t20
+    vssrarni.h.w  vr7,      vr11,     12           // t27
+    vmul_vmsub_w vr10, vr31, vr20, vr20, vr1, vr25
+    vmul_vmadd_w vr10, vr31, vr20, vr20, vr11, vr6
+    vssrarni.h.w  vr25,     vr1,      12           // t21a
+    vssrarni.h.w  vr6,      vr11,     12           // t26a
+    vmul_vmsub_w vr24, vr8, vr20, vr20, vr1, vr19
+    vmul_vmadd_w vr24, vr8, vr20, vr20, vr11, vr10
+    vssrarni.h.w  vr19,     vr1,      12           // t22
+    vssrarni.h.w  vr10,     vr11,     12           // t25
+    vmul_vmsub_w vr2, vr26, vr20, vr20, vr1, vr31
+    vmul_vmadd_w vr2, vr26, vr20, vr20, vr11, vr8
+    vssrarni.h.w  vr31,     vr1,      12           // t23a
+    vssrarni.h.w  vr8,      vr11,     12           // t24a
+
+    // t31 t30a t29 t28a t27 t26a t25 t24a t23a t22 t21a t20 t19a t18 t17a t16
+    // vr30 vr28 vr27 vr29 vr7 vr6 vr10 vr8 vr31 vr19 vr25 vr5 vr9 vr4 vr0 vr3
+    vld_x8 \in2, \vld_st0, \vld_stride, vr11, vr12, vr13, vr14, vr15, vr16, vr17, vr18
+
+    vsadd.h       vr1,      vr11,     vr30         // c[0]
+    vssub.h       vr2,      vr11,     vr30         // c[31]
+    vsadd.h       vr24,     vr12,     vr28         // c[1]
+    vssub.h       vr26,     vr12,     vr28         // c[30]
+    vsadd.h       vr11,     vr13,     vr27         // c[2]
+    vssub.h       vr30,     vr13,     vr27         // c[29]
+    vsadd.h       vr12,     vr14,     vr29         // c[3]
+    vssub.h       vr28,     vr14,     vr29         // c[28]
+    vsadd.h       vr13,     vr15,     vr7          // c[4]
+    vssub.h       vr27,     vr15,     vr7          // c[27]
+    vsadd.h       vr14,     vr16,     vr6          // c[5]
+    vssub.h       vr29,     vr16,     vr6          // c[26]
+    vsadd.h       vr7,      vr17,     vr10         // c[6]
+    vssub.h       vr15,     vr17,     vr10         // c[25]
+    vsadd.h       vr6,      vr18,     vr8          // c[7]
+    vssub.h       vr16,     vr18,     vr8          // c[24]
+
+.ifnb \transpose8x8
+    LSX_TRANSPOSE8x8_H vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6, \
+                       vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6, \
+                       vr8, vr10, vr17, vr18, vr20, vr21, vr22, vr23
+.endif
+
+.ifnb \shift
+.irp i, vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6
+    vsrari.h      \i,       \i,       \shift
+.endr
+.endif
+
+    vst_x8 \in1, \vst_st0, \vst_stride, vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6
+
+.ifnb \transpose8x8
+    LSX_TRANSPOSE8x8_H vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2, \
+                       vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2, \
+                       vr8, vr10, vr17, vr18, vr20, vr21, vr22, vr23
+.endif
+
+.ifnb \shift
+.irp i, vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2
+    vsrari.h      \i,       \i,       \shift
+.endr
+.endif
+
+    vst_x8 \in1, \vst_st1, \vst_stride, vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2
+
+    vld_x8 \in2, \vld_st1, \vld_stride, vr11, vr12, vr13, vr14, vr15, vr16, vr17, vr18
+
+    vsadd.h       vr1,      vr11,     vr31         // c[8]
+    vssub.h       vr2,      vr11,     vr31         // c[23]
+    vsadd.h       vr24,     vr12,     vr19         // c[9]
+    vssub.h       vr26,     vr12,     vr19         // c[22]
+    vsadd.h       vr11,     vr13,     vr25         // c[10]
+    vssub.h       vr30,     vr13,     vr25         // c[21]
+    vsadd.h       vr12,     vr14,     vr5          // c[11]
+    vssub.h       vr28,     vr14,     vr5          // c[20]
+    vsadd.h       vr13,     vr15,     vr9          // c[12]
+    vssub.h       vr27,     vr15,     vr9          // c[19]
+    vsadd.h       vr14,     vr16,     vr4          // c[13]
+    vssub.h       vr29,     vr16,     vr4          // c[18]
+    vsadd.h       vr7,      vr17,     vr0          // c[14]
+    vssub.h       vr15,     vr17,     vr0          // c[17]
+    vsadd.h       vr6,      vr18,     vr3          // c[15]
+    vssub.h       vr16,     vr18,     vr3          // c[16]
+
+.ifnb \transpose8x8
+    LSX_TRANSPOSE8x8_H vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6, \
+                       vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6, \
+                       vr8, vr10, vr17, vr18, vr20, vr21, vr22, vr23
+.endif
+
+.ifnb \shift
+.irp i, vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6
+    vsrari.h      \i,       \i,       \shift
+.endr
+.endif
+
+    vst_x8 \in1, \vst_st2, \vst_stride, vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6
+
+.ifnb \transpose8x8
+    LSX_TRANSPOSE8x8_H vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2, \
+                       vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2, \
+                       vr8, vr10, vr17, vr18, vr20, vr21, vr22, vr23
+.endif
+
+.ifnb \shift
+.irp i, vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2
+    vsrari.h      \i,       \i,       \shift
+.endr
+.endif
+
+    vst_x8 \in1, \vst_st3, \vst_stride, vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2
+.endm
+
+const eob_32x32
+        .short 36, 136, 300, 1024
+endconst
+
+const eob_8x32
+        .short 43, 107, 171, 256
+endconst
+
+const eob_16x32
+        .short 36, 151, 279, 512
+endconst
+
+.macro DST_ADD_W32 in0, in1, in2, in3, in4, in5, in6, in7
+    vsllwil.hu.bu vr4,      vr10,     0
+    vsllwil.hu.bu vr5,      vr11,     0
+    vsllwil.hu.bu vr6,      vr12,     0
+    vsllwil.hu.bu vr7,      vr13,     0
+    vexth.hu.bu   vr10,     vr10
+    vexth.hu.bu   vr11,     vr11
+    vexth.hu.bu   vr12,     vr12
+    vexth.hu.bu   vr13,     vr13
+    vadd.h        vr4,      vr4,      \in0
+    vadd.h        vr10,     vr10,     \in1
+    vadd.h        vr5,      vr5,      \in2
+    vadd.h        vr11,     vr11,     \in3
+    vadd.h        vr6,      vr6,      \in4
+    vadd.h        vr12,     vr12,     \in5
+    vadd.h        vr7,      vr7,      \in6
+    vadd.h        vr13,     vr13,     \in7
+    vssrani.bu.h  vr10,     vr4,      0
+    vssrani.bu.h  vr11,     vr5,      0
+    vssrani.bu.h  vr12,     vr6,      0
+    vssrani.bu.h  vr13,     vr7,      0
+    vst           vr10,     a0,       0
+    vst           vr11,     a0,       16
+    vst           vr12,     t2,       0
+    vst           vr13,     t2,       16
+.endm
+
+.macro idct_dc_w32 w, h, shift
+    ld.h          t2,       a2,       0      // dc
+    vldi          vr0,      0x8b5            // 181
+    vreplgr2vr.w  vr1,      t2
+    vldi          vr20,     0x880            // 128
+    vmul.w        vr2,      vr0,      vr1    // dc * 181
+    st.h          zero,     a2,       0
+    add.d         t2,       a0,       a1
+    vsrari.w      vr2,      vr2,      8      // (dc * 181 + 128) >> 8
+    vld           vr13,     t2,       16
+
+.if (2*\w == \h) || (2*\h == \w)
+    vmul.w        vr2,      vr2,      vr0
+    vsrari.w      vr2,      vr2,      8
+.endif
+
+.if \shift>0
+    vsrari.w      vr2,      vr2,      \shift      // (dc + rnd) >> shift
+.endif
+    vld           vr11,     a0,       16
+    vmadd.w       vr20,     vr2,      vr0
+    vld           vr12,     t2,       0
+    vssrarni.h.w  vr20,     vr20,     12
+    vld           vr10,     a0,       0
+.endm
+
+function inv_txfm_add_dct_dct_32x8_8bpc_lsx
+    bnez          a3,       .NO_HAS_DCONLY_32x8
+
+    idct_dc_w32 32, 8, 2
+
+    DST_ADD_W32 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+
+.rept 3
+    alsl.d        a0,       a1,       a0,     1
+    add.d         t2,       a0,       a1
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     t2,       0
+    vld           vr13,     t2,       16
+    DST_ADD_W32 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+.endr
+    b             .DCT_DCT_32X8_END
+.NO_HAS_DCONLY_32x8:
+    malloc_space 512+256
+
+    addi.d        t1,       sp,       64
+    addi.d        t2,       a2,       0
+    addi.d        t3,       sp,       64
+    addi.d        t3,       t3,       512
+
+    vld_x16 t2, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vxor.v        vr31,     vr31,     vr31
+    vst_x16 t2, 0, 32, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    inv_dct16_lsx .8h
+
+    vst_x16 t3, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vld_x16 t2, 16, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+
+    vxor.v        vr31,     vr31,     vr31
+
+    vst_x16 t2, 16, 32, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    dct_8x32_core_lsx t1, t3, 0, 128, 16, 0, 48, 16, 32, 64, transpose8x8, 2
+
+    addi.d        t2,       sp,       64
+.rept 4
+    vld_x8 t2, 0, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    inv_dct8_lsx vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, .8h
+
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vsrari.h      \i,       \i,       4
+.endr
+
+    vst_x8 t2, 0, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    addi.d        t2,       t2,       16
+.endr
+
+    addi.d        t0,       sp,       64
+.rept 4
+    add.d         t2,       a0,       a1
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     t2,       0
+    vld           vr13,     t2,       16
+    vld_x8 t0, 0, 16, vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    DST_ADD_W32 vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    alsl.d        a0,       a1,       a0,     1
+    addi.d        t0,       t0,       128
+.endr
+    free_space 512+256
+.DCT_DCT_32X8_END:
+endfunc
+
+function inv_txfm_add_dct_dct_32x16_8bpc_lsx
+    bnez          a3,       .NO_HAS_DCONLY_32x16
+
+    idct_dc_w32 32, 16, 1
+
+    DST_ADD_W32 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+
+.rept 7
+    alsl.d        a0,       a1,       a0,     1
+    add.d         t2,       a0,       a1
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     t2,       0
+    vld           vr13,     t2,       16
+    DST_ADD_W32 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+.endr
+    b             .DCT_DCT_32X16_END
+.NO_HAS_DCONLY_32x16:
+    malloc_space 1024+256                            // 32*32*2+512
+    addi.d        t1,       sp,       64
+    addi.d        t2,       a2,       0
+    addi.d        t3,       sp,       64
+    addi.d        t3,       t3,       1024
+.rept 2
+    vld_x16 t2, 0, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vxor.v        vr31,     vr31,     vr31
+    vst_x16 t2, 0, 64, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    li.w          t0,       2896
+    vreplgr2vr.w  vr23,     t0
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+     vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    rect2_lsx   \i, vr23, \i
+.endr
+
+    inv_dct16_lsx .8h
+
+    vst_x16 t3, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vld_x16 t2, 32, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+
+    la.local      t0,       idct_coeffs
+    vldrepl.w     vr23,     t0,       0        // 2896
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+    vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+    rect2_lsx \i, vr23, \i
+.endr
+    vxor.v        vr31,     vr31,     vr31
+    vst_x16 t2, 32, 64, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    dct_8x32_core_lsx t1, t3, 0, 128, 16, 0, 48, 16, 32, 64, transpose8x8, 1
+
+    addi.d        t2,       t2,       16
+    addi.d        t1,       t1,       512
+.endr
+
+    addi.d        t2,       sp,       64
+.rept 4
+    vld_x16 t2, 0, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    inv_dct16_lsx .8h
+
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+    vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    vsrari.h      \i,       \i,       4
+.endr
+
+    vst_x16 t2, 0, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    addi.d        t2,       t2,       16
+.endr
+
+    addi.d        t0,       sp,       64
+.rept 8
+    add.d         t2,       a0,       a1
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     t2,       0
+    vld           vr13,     t2,       16
+    vld_x8 t0, 0, 16, vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    DST_ADD_W32 vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+    alsl.d        a0,       a1,       a0,     1
+    addi.d        t0,       t0,       128
+.endr
+    free_space 1024+256
+.DCT_DCT_32X16_END:
+endfunc
+
+function inv_txfm_add_dct_dct_32x32_8bpc_lsx
+    bnez          a3,       .NO_HAS_DCONLY_32x32
+
+    idct_dc_w32 32, 32, 2
+
+    DST_ADD_W32 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+.rept 15
+    alsl.d        a0,       a1,       a0,     1
+    add.d         t2,       a0,       a1
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     t2,       0
+    vld           vr13,     t2,       16
+    DST_ADD_W32 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+.endr
+    b             .DCT_DCT_32X32_END
+.NO_HAS_DCONLY_32x32:
+    malloc_space 2560                              // 32*32*2+512
+
+    addi.d        t1,       sp,       64
+    addi.d        t2,       a2,       0
+    addi.d        t3,       sp,       1024
+    addi.d        t3,       t3,       1024
+    addi.d        t3,       t3,       64
+
+    la.local      t8,       eob_32x32
+.DCT_DCT_EOB_32x32:
+    ld.h          t7,       t8,       0
+    addi.d        t8,       t8,       2
+
+    vld_x16 t2, 0, 128, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vxor.v        vr31,     vr31,     vr31
+    vst_x16 t2, 0, 128, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    inv_dct16_lsx .8h
+
+    vst_x16 t3, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vld_x16 t2, 64, 128, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+
+    vxor.v        vr31,     vr31,     vr31
+
+    vst_x16 t2, 64, 128, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    dct_8x32_core_lsx t1, t3, 0, 128, 16, 0, 48, 16, 32, 64, transpose8x8, 2
+
+    addi.d        t2,       t2,       16
+    addi.d        t1,       t1,       512
+    bge           a3,       t7,       .DCT_DCT_EOB_32x32
+
+    la.local      t8,       eob_32x32
+    vxor.v        vr31,     vr31,     vr31
+    ld.h          t7,       t8,       4
+    bge           a3,       t7,       .DCT_DCT_EOB_32x32_END   // a3>=t7
+    vst_x16 sp, 64+1536, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+        vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    addi.d        t1,       sp,       256+64
+    vst_x16 t1, 1536, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+        vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    ld.h          t7,       t8,       2
+    bge           a3,       t7,       .DCT_DCT_EOB_32x32_END
+    vst_x16 sp, 64+1024, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+        vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    vst_x16 t1, 1024, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+        vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    ld.h          t7,       t8,       0
+    bge           a3,       t7,       .DCT_DCT_EOB_32x32_END
+    vst_x16 sp, 64+512, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+        vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    vst_x16 t1, 512, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+        vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+.DCT_DCT_EOB_32x32_END:
+    addi.d        t2,       sp,       64
+    addi.d        t1,       sp,       64
+.rept 4
+    vld_x16 t2, 0, 128, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    inv_dct16_lsx .8h
+
+    vst_x16 t3, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vld_x16 t2, 64, 128, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+
+    dct_8x32_core_lsx t1, t3, 0, 128, 16, 0, 1536, 512, 1024, 64, , 4
+
+    addi.d        t2,       t2,       16
+    addi.d        t1,       t1,       16
+.endr
+
+    addi.d        t0,       sp,       64
+.rept 16
+    add.d         t2,       a0,       a1
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     t2,       0
+    vld           vr13,     t2,       16
+    vld_x8 t0, 0, 16, vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    DST_ADD_W32 vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    alsl.d        a0,       a1,       a0,     1
+    addi.d        t0,       t0,       128
+.endr
+
+    free_space 2560                                // 32*32*2+512
+.DCT_DCT_32X32_END:
+endfunc
+
+/*
+ * temp: vr8, vr9, vr10, vr12, vr20, vr21, vr22, vr23
+ */
+.macro dct_8x8_tx64_core_lsx in0, in1, in2, in3, in4, in5, in6, in7, out0, \
+                             out1, out2, out3, out4, out5, out6, out7, rect2
+
+    la.local      t0,       idct_coeffs
+
+.ifc \rect2, rect2_lsx
+    vldrepl.w     vr23,      t0,       0        // 2896
+.irp i, \in0, \in1, \in2, \in3, \in4, \in5, \in6, \in7
+    rect2_lsx \i, vr23, \i
+.endr
+.endif
+
+    la.local      t0,       idct_coeffs
+
+    vldrepl.w     vr20,     t0,       8            // 1567
+    vldrepl.w     vr21,     t0,       12           // 3784
+    vsllwil.w.h   vr22,     \in2,     0
+    vexth.w.h     vr23,     \in2
+    vmul.w        vr8,      vr22,     vr20
+    vmul.w        vr10,     vr23,     vr20
+    vmul.w        \in2,     vr22,     vr21
+    vmul.w        vr9,      vr23,     vr21
+    vssrarni.h.w  vr10,     vr8,      12           // t2
+    vssrarni.h.w  vr9,      \in2,     12           // t3
+
+    vldrepl.w     vr20,     t0,       0            // 2896
+    vsllwil.w.h   vr22,     \in0,     0
+    vexth.w.h     vr23,     \in0
+    vmul.w        vr8,      vr22,     vr20
+    vmul.w        \in2,     vr23,     vr20
+    vssrarni.h.w  \in2,     vr8,      12
+
+    vsadd.h       vr8,      \in2,     vr9          // c[0]
+    vssub.h       vr9,      \in2,     vr9          // c[3]
+    vsadd.h       \in0,     \in2,     vr10         // c[1]
+    vssub.h       vr10,     \in2,     vr10         // c[2]
+
+    // inv_dct8_1d_internal_c tx64
+    // in1 in3
+    vldrepl.w     vr20,     t0,       16           // 799
+    vldrepl.w     vr21,     t0,       20           // 4017
+
+    vsllwil.w.h   vr22,     \in1,     0
+    vexth.w.h     vr23,     \in1
+    vmul.w        \in2,     vr22,     vr21
+    vmul.w        \in4,     vr23,     vr21
+    vmul.w        \in1,     vr22,     vr20
+    vmul.w        \in6,     vr23,     vr20
+    vssrarni.h.w  \in4,     \in2,     12           // t7a
+    vssrarni.h.w  \in6,     \in1,     12           // t4a
+
+    vldrepl.w     vr20,     t0,       24           // 3406
+    vldrepl.w     vr21,     t0,       28           // 2276
+
+    vsllwil.w.h   vr22,     \in3,     0
+    vexth.w.h     vr23,     \in3
+    vneg.w        vr21,     vr21
+    vmul.w        \in2,     vr22,     vr20
+    vmul.w        \in1,     vr23,     vr20
+    vmul.w        \in3,     vr22,     vr21
+    vmul.w        \in7,     vr23,     vr21
+    vssrarni.h.w  \in1,     \in2,     12           // t6a
+    vssrarni.h.w  \in7,     \in3,     12           // t5a
+
+    vsadd.h       \in3,     \in6,     \in7         // t4
+    vssub.h       \in6,     \in6,     \in7         // t5a
+    vsadd.h       \in5,     \in4,     \in1         // t7
+    vssub.h       \in4,     \in4,     \in1         // t6a
+
+    vldrepl.w     vr20,     t0,       0            // 2896
+    vmul_vmadd_w  \in4, \in6, vr20, vr20, vr21, \in1
+    vmul_vmsub_w  \in4, \in6, vr20, vr20, \in2, \in7
+    vssrarni.h.w  \in1,     vr21,     12           // t6
+    vssrarni.h.w  \in7,     \in2,     12           // t5
+
+    vsadd.h       \out0,    vr8,      \in5         // c[0]
+    vssub.h       \out7,    vr8,      \in5         // c[7]
+    vsadd.h       \out1,    \in0,     \in1         // c[1]
+    vssub.h       \out6,    \in0,     \in1         // c[6]
+    vsadd.h       \out2,    vr10,     \in7         // c[2]
+    vssub.h       \out5,    vr10,     \in7         // c[5]
+    vsadd.h       \out3,    vr9,      \in3         // c[3]
+    vssub.h       \out4,    vr9,      \in3         // c[4]
+.endm
+
+/*
+ * input:  in0,  in1,  in2,  in3,  in4,  in5,  in6,  in7       (fixed)
+ *         vr0,  vr1,  vr2,  vr3,  vr4,  vr5,  vr6,  vr7
+ *         in8,  in9,  in10, in11, in12, in13, in14, in15
+ *         vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+ * output: out0, out1, out2, out3, out4, out5, out6, out7      (fixed)
+ *         vr22, vr18, vr17, vr28, vr20, vr14, vr15, vr16
+ *         out8, out9, out10, out11, out12, out13, out14, out15
+ *         vr27, vr30, vr23,  vr21,  vr29,  vr26,  vr25,  vr24
+ */
+.macro dct_8x16_tx64_core_lsx rect2
+    dct_8x8_tx64_core_lsx vr0, vr2, vr4, vr6, vr19, vr25, vr27, vr29, vr11, \
+                          vr12, vr13, vr14, vr15, vr16, vr17, vr18, \rect2
+
+    // in1 in3 in5 in7 in9  in11 in13 in15
+    // vr1 vr3 vr5 vr7 vr24 vr26 vr28 vr30
+    la.local      t0,       idct_coeffs
+
+.ifc \rect2, rect2_lsx
+    vldrepl.w     vr23,      t0,       0        // 2896
+.irp i, vr1, vr3, vr5, vr7, vr24, vr26, vr28, vr30
+    rect2_lsx \i, vr23, \i
+.endr
+.endif
+
+    vldrepl.w     vr20,     t0,       32           // 401
+    vldrepl.w     vr21,     t0,       36           // 4076
+    vsllwil.w.h   vr22,     vr1,      0
+    vexth.w.h     vr23,     vr1
+    vmul.w        vr0,      vr22,     vr21
+    vmul.w        vr10,     vr23,     vr21
+    vmul.w        vr1,      vr22,     vr20
+    vmul.w        vr29,     vr23,     vr20
+    vssrarni.h.w  vr10,     vr0,      12           // t15a
+    vssrarni.h.w  vr29,     vr1,      12           // t8a
+
+    vldrepl.w     vr20,     t0,       40           // 3166 -> 1583
+    vldrepl.w     vr21,     t0,       44           // 2598 -> 1299
+    vsllwil.w.h   vr22,     vr7,      0
+    vexth.w.h     vr23,     vr7
+    vneg.w        vr21,     vr21
+    vmul.w        vr0,      vr22,     vr20
+    vmul.w        vr30,     vr23,     vr20
+    vmul.w        vr7,      vr22,     vr21
+    vmul.w        vr31,     vr23,     vr21
+    vssrarni.h.w  vr30,     vr0,      12           // t14a
+    vssrarni.h.w  vr31,     vr7,      12           // t9a
+
+    vldrepl.w     vr20,     t0,       48           // 1931
+    vldrepl.w     vr21,     t0,       52           // 3612
+    vsllwil.w.h   vr22,     vr5,      0
+    vexth.w.h     vr23,     vr5
+    vmul.w        vr0,      vr22,     vr21
+    vmul.w        vr24,     vr23,     vr21
+    vmul.w        vr5,      vr22,     vr20
+    vmul.w        vr25,     vr23,     vr20
+    vssrarni.h.w  vr24,     vr0,      12           // t13a
+    vssrarni.h.w  vr25,     vr5,      12           // t10a
+
+    vldrepl.w     vr20,     t0,       56           // 3920
+    vldrepl.w     vr21,     t0,       60           // 1189
+    vsllwil.w.h   vr22,     vr3,      0
+    vexth.w.h     vr23,     vr3
+    vneg.w        vr21,     vr21
+    vmul.w        vr0,      vr22,     vr20
+    vmul.w        vr26,     vr23,     vr20
+    vmul.w        vr3,      vr22,     vr21
+    vmul.w        vr27,     vr23,     vr21
+    vssrarni.h.w  vr26,     vr0,      12           // t12a
+    vssrarni.h.w  vr27,     vr3,      12           // t11a
+
+    // vr22 vr23 vr30 vr31 vr24 vr25 vr26 vr27
+    vsadd.h       vr28,     vr29,      vr31        // t8
+    vssub.h       vr19,     vr29,      vr31        // t9
+    vssub.h       vr29,     vr27,      vr25        // t10
+    vsadd.h       vr9,      vr27,      vr25        // t11
+    vsadd.h       vr31,     vr26,      vr24        // t12
+    vssub.h       vr25,     vr26,      vr24        // t13
+    vssub.h       vr27,     vr10,      vr30        // t14
+    vsadd.h       vr24,     vr10,      vr30        // t15
+
+    vldrepl.w     vr20,     t0,       8            // 1567
+    vldrepl.w     vr21,     t0,       12           // 3784
+    vmul_vmadd_w vr27, vr19, vr21, vr20, vr0, vr26
+    vmul_vmsub_w vr27, vr19, vr20, vr21, vr1, vr30
+    vssrarni.h.w  vr26,     vr0,       12          // t14a
+    vssrarni.h.w  vr30,     vr1,       12          // t9a
+
+    vmul_vmadd_w vr25, vr29, vr21, vr20, vr0, vr19
+    vneg.w        vr0,      vr0
+    vneg.w        vr19,     vr19
+    vmul_vmsub_w vr25, vr29, vr20, vr21, vr1, vr27
+    vssrarni.h.w  vr19,     vr0,       12          // t10a
+    vssrarni.h.w  vr27,     vr1,       12          // t13a
+
+    vsadd.h       vr25,     vr28,     vr9          // t8a
+    vssub.h       vr29,     vr28,     vr9          // t11a
+    vssub.h       vr28,     vr24,     vr31         // t12a
+    vsadd.h       vr10,     vr24,     vr31         // t15a
+    vsadd.h       vr9,      vr30,     vr19         // t9
+    vssub.h       vr31,     vr30,     vr19         // t10
+    vssub.h       vr30,     vr26,     vr27         // t13
+    vsadd.h       vr24,     vr26,     vr27         // t14
+
+    vldrepl.w     vr20,     t0,       0            // 2896
+    vmul_vmadd_w vr30, vr31, vr20, vr20, vr0, vr26
+    vmul_vmsub_w vr30, vr31, vr20, vr20, vr1, vr27
+    vssrarni.h.w  vr26,     vr0,      12           // t13a
+    vssrarni.h.w  vr27,     vr1,      12           // t10a
+
+    vmul_vmadd_w vr28, vr29, vr20, vr20, vr0, vr31
+    vmul_vmsub_w vr28, vr29, vr20, vr20, vr1, vr30
+    vssrarni.h.w  vr31,     vr0,      12           // t12
+    vssrarni.h.w  vr30,     vr1,      12           // t11
+
+    // vr11 vr12 ... vr18
+    vsadd.h       vr28,     vr14,     vr31         // c[3]
+    vssub.h       vr29,     vr14,     vr31         // c[12]
+    vsadd.h       vr20,     vr15,     vr30         // c[4]
+    vssub.h       vr21,     vr15,     vr30         // c[11]
+    vsadd.h       vr14,     vr16,     vr27         // c[5]
+    vssub.h       vr23,     vr16,     vr27         // c[10]
+    vsadd.h       vr15,     vr17,     vr9          // c[6]
+    vssub.h       vr30,     vr17,     vr9          // c[9]
+    vsadd.h       vr16,     vr18,     vr25         // c[7]
+    vssub.h       vr27,     vr18,     vr25         // c[8]
+    vsadd.h       vr17,     vr13,     vr26         // c[2]
+    vssub.h       vr26,     vr13,     vr26         // c[13]
+    vsadd.h       vr18,     vr12,     vr24         // c[1]
+    vssub.h       vr25,     vr12,     vr24         // c[14]
+    vsadd.h       vr22,     vr11,     vr10         // c[0]
+    vssub.h       vr24,     vr11,     vr10         // c[15]
+.endm // dct_8x16_tx64_core_lsx
+
+.macro vmul_vssrarni_hw in0, in1, in2, tmp0, tmp1, out0, out1
+    vsllwil.w.h   vr22,      \in0,     0
+    vexth.w.h     vr23,      \in0
+    vmul.w        \tmp0,     vr22,     \in1
+    vmul.w        \out0,     vr23,     \in1
+    vmul.w        \tmp1,     vr22,     \in2
+    vmul.w        \out1,     vr23,     \in2
+    vssrarni.h.w  \out0,     \tmp0,    12
+    vssrarni.h.w  \out1,     \tmp1,    12
+.endm
+
+const idct64_coeffs, align=4
+    .word         101, 4095, 2967, -2824
+    .word         1660, 3745, 3822, -1474
+    .word         4076, 401, 4017, 799
+    .word         4036, -700, 2359, 3349
+    .word         3461, -2191, 897, 3996
+    .word         -3166, -2598, -799, -4017
+    .word         501, 4065, 3229, -2520
+    .word         2019, 3564, 3948, -1092
+    .word         3612, 1931, 2276, 3406
+    .word         4085, -301, 2675, 3102
+    .word         3659, -1842, 1285, 3889
+    .word         -3920, -1189, -3406, -2276
+endconst
+
+.macro dct64_step1_lsx
+    vldrepl.w     vr20,     t0,       0            // 101
+    vldrepl.w     vr21,     t0,       4            // 4095
+    vmul_vssrarni_hw vr0, vr20, vr21, vr16, vr0, vr8, vr9    // vr8 t32a vr9 t63a
+    vldrepl.w     vr20,     t0,       8            // 2967
+    vldrepl.w     vr21,     t0,       12           // -2824
+    vmul_vssrarni_hw vr1, vr20, vr21, vr16, vr1, vr10, vr11  // vr10 t62a vr11 t33a
+    vldrepl.w     vr20,     t0,       16           // 1660
+    vldrepl.w     vr21,     t0,       20           // 3745
+    vmul_vssrarni_hw vr2, vr20, vr21, vr16, vr2, vr12, vr13  // vr12 t34a vr13 t61a
+    vldrepl.w     vr20,     t0,       24           // 3822
+    vldrepl.w     vr21,     t0,       28           // -1474
+    vmul_vssrarni_hw vr3, vr20, vr21, vr16, vr3, vr14, vr15  // vr14 t60a vr15 t35a
+
+    vsadd.h       vr0,      vr8,      vr11         // t32
+    vssub.h       vr1,      vr8,      vr11         // t33
+    vssub.h       vr2,      vr15,     vr12         // t34
+    vsadd.h       vr3,      vr15,     vr12         // t35
+    vsadd.h       vr4,      vr14,     vr13         // t60
+    vssub.h       vr5,      vr14,     vr13         // t61
+    vssub.h       vr6,      vr9,      vr10         // t62
+    vsadd.h       vr7,      vr9,      vr10         // t63
+
+    vldrepl.w     vr20,     t0,       32           // 4076
+    vldrepl.w     vr21,     t0,       36           // 401
+    vmul_vmadd_w vr6, vr1, vr20, vr21, vr9, vr10
+    vmul_vmsub_w vr6, vr1, vr21, vr20, vr13, vr11
+    vssrarni.h.w  vr10,     vr9,      12           // t62a
+    vssrarni.h.w  vr11,     vr13,     12           // t33a
+
+    vmul_vmadd_w vr5, vr2, vr20, vr21, vr9, vr1
+    vmul_vmsub_w vr5, vr2, vr21, vr20, vr13, vr6
+    vneg.w        vr9,      vr9
+    vneg.w        vr1,      vr1
+    vssrarni.h.w  vr6,      vr13,     12           // t61a
+    vssrarni.h.w  vr1,      vr9,      12           // t34a
+
+    vsadd.h       vr2,      vr0,      vr3          // t32a
+    vssub.h       vr5,      vr0,      vr3          // t35a
+    vsadd.h       vr9,      vr11,     vr1          // t33
+    vssub.h       vr13,     vr11,     vr1          // t34
+    vssub.h       vr0,      vr7,      vr4          // t60a
+    vsadd.h       vr3,      vr7,      vr4          // t63a
+    vssub.h       vr1,      vr10,     vr6          // t61
+    vsadd.h       vr11,     vr10,     vr6          // t62
+
+    vldrepl.w     vr20,     t0,       40           // 4017
+    vldrepl.w     vr21,     t0,       44           // 799
+    vmul_vmadd_w vr1, vr13, vr20, vr21, vr8, vr4
+    vmul_vmsub_w vr1, vr13, vr21, vr20, vr12, vr7
+    vssrarni.h.w  vr4,      vr8,      12           // t61a
+    vssrarni.h.w  vr7,      vr12,     12           // t34a
+
+    vmul_vmadd_w vr0, vr5, vr20, vr21, vr8, vr6
+    vmul_vmsub_w vr0, vr5, vr21, vr20, vr12, vr10
+    vssrarni.h.w  vr6,      vr8,      12           // t60
+    vssrarni.h.w  vr10,     vr12,     12           // t35
+
+    vst_x8 t6, 0, 16, vr2, vr9, vr7, vr10, vr6, vr4, vr11, vr3
+.endm // dct64_step1
+
+    // in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+    // in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+    // in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+    // in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+.macro dct64_step2_lsx
+    vld           vr0,      t5,       0            // t32a
+    vld           vr2,      t4,       0            // t63a
+    vld           vr3,      t5,       16*8         // t56a
+    vld           vr1,      t4,       16*8         // t39a
+    vld           vr4,      t5,       16*16        // t40a
+    vld           vr6,      t4,       16*16        // t55a
+    vld           vr7,      t5,       16*24        // t48a
+    vld           vr5,      t4,       16*24        // t47a
+
+    vsadd.h       vr8,      vr0,      vr1          // t32
+    vssub.h       vr9,      vr0,      vr1          // t39
+    vsadd.h       vr10,     vr2,      vr3          // t63
+    vssub.h       vr11,     vr2,      vr3          // t56
+    vssub.h       vr12,     vr5,      vr4          // t40
+    vsadd.h       vr13,     vr5,      vr4          // t47
+    vsadd.h       vr14,     vr7,      vr6          // t48
+    vssub.h       vr15,     vr7,      vr6          // t55
+    vldrepl.w     vr20,     t0,       8            // 1567
+    vldrepl.w     vr21,     t0,       12           // 3784
+    vmul_vmadd_w  vr11, vr9, vr21, vr20, vr0, vr2
+    vmul_vmsub_w  vr11, vr9, vr20, vr21, vr1, vr3
+    vssrarni.h.w  vr2,      vr0,      12           // t56a
+    vssrarni.h.w  vr3,      vr1,      12           // t39a
+    vmul_vmadd_w  vr15, vr12, vr21, vr20, vr0, vr4
+    vmul_vmsub_w  vr15, vr12, vr20, vr21, vr1, vr5
+    vneg.w        vr0,      vr0
+    vneg.w        vr4,      vr4
+    vssrarni.h.w  vr5,      vr1,      12           // t55a
+    vssrarni.h.w  vr4,      vr0,      12           // t40a
+    vsadd.h       vr9,      vr8,      vr13         // t32a
+    vssub.h       vr11,     vr8,      vr13         // t47a
+    vsadd.h       vr6,      vr3,      vr4          // t39
+    vssub.h       vr7,      vr3,      vr4          // t40
+    vssub.h       vr12,     vr10,     vr14         // t48a
+    vsadd.h       vr15,     vr10,     vr14         // t63a
+    vssub.h       vr0,      vr2,      vr5          // t55
+    vsadd.h       vr1,      vr2,      vr5          // t56
+
+    vldrepl.w     vr20,     t0,       0            // 2896
+    vmul_vmsub_w vr0, vr7, vr20, vr20, vr8, vr13
+    vmul_vmadd_w vr0, vr7, vr20, vr20, vr3, vr4
+    vssrarni.h.w  vr13,     vr8,      12           // t40a
+    vssrarni.h.w  vr4,      vr3,      12           // t55a
+    vmul_vmsub_w vr12, vr11, vr20, vr20, vr8, vr10
+    vmul_vmadd_w vr12, vr11, vr20, vr20, vr3, vr14
+    vssrarni.h.w  vr10,     vr8,      12           // t47
+    vssrarni.h.w  vr14,     vr3,      12           // t48
+
+    // t32a t39 t40a t47  t48  t55a t56 t63a
+    // vr9  vr6 vr13 vr10 vr14 vr4  vr1 vr15
+    vst           vr9,      t5,       0            // t32a
+    vst           vr6,      t4,       0            // t39
+    vst           vr13,     t5,       16*8         // t40a
+    vst           vr10,     t4,       16*8         // t47
+    vst           vr14,     t5,       16*16        // t48
+    vst           vr4,      t4,       16*16        // t55a
+    vst           vr1,      t5,       16*24        // t56
+    vst           vr15,     t4,       16*24        // t63a
+.endm // dct64_step2_lsx
+
+.macro dct64_step3_lsx
+    //                t0   t1   t2   t3   t4    t5    t6    t7
+    vld_x8 t3, 0, 16, vr2, vr3, vr7, vr8, vr11, vr12, vr16, vr17
+    vld           vr9,      t5,       16*24    // t56
+    vld           vr6,      t5,       16*24+16 // t57a
+    vld           vr13,     t5,       16*24+32 // t58
+    vld           vr10,     t5,       16*24+48 // t59a
+    vld           vr14,     t4,       16*24-48 // t60
+    vld           vr4,      t4,       16*24-32 // t61a
+    vld           vr1,      t4,       16*24-16 // t62
+    vld           vr15,     t4,       16*24    // t63a
+    vsadd.h       vr20,     vr2,      vr15     // c[0]
+    vssub.h       vr21,     vr2,      vr15     // c[63]
+    vsadd.h       vr22,     vr3,      vr1      // c[1]
+    vssub.h       vr23,     vr3,      vr1      // c[62]
+    vsadd.h       vr24,     vr7,      vr4      // c[2]
+    vssub.h       vr25,     vr7,      vr4      // c[61]
+    vsadd.h       vr26,     vr8,      vr14     // c[3]
+    vssub.h       vr27,     vr8,      vr14     // c[60]
+    vsadd.h       vr28,     vr11,     vr10     // c[4]
+    vssub.h       vr29,     vr11,     vr10     // c[59]
+    vsadd.h       vr30,     vr12,     vr13     // c[5]
+    vssub.h       vr31,     vr12,     vr13     // c[58]
+    vsadd.h       vr2,      vr16,     vr6      // c[6]
+    vssub.h       vr15,     vr16,     vr6      // c[57]
+    vsadd.h       vr1,      vr17,     vr9      // c[7]
+    vssub.h       vr3,      vr17,     vr9      // c[56]
+.endm // dct64_step3_lsx
+
+.macro dct64_step4_lsx transpose8x8, shift, start0, stride0, start1, stride1
+    dct64_step3_lsx
+
+.ifnb \transpose8x8
+    LSX_TRANSPOSE8x8_H vr20, vr22, vr24, vr26, vr28, vr30, vr2, vr1, \
+                       vr20, vr22, vr24, vr26, vr28, vr30, vr2, vr1, \
+                       vr4, vr7, vr8, vr14, vr10, vr11, vr12, vr13
+
+    LSX_TRANSPOSE8x8_H vr3, vr15, vr31, vr29, vr27, vr25, vr23, vr21, \
+                       vr3, vr15, vr31, vr29, vr27, vr25, vr23, vr21, \
+                       vr4, vr7, vr8, vr14, vr10, vr11, vr12, vr13
+.endif
+
+.ifnb \shift
+.irp i, vr20, vr22, vr24, vr26, vr28, vr30, vr2, vr1, \
+     vr3, vr15, vr31, vr29, vr27, vr25, vr23, vr21
+     vsrari.h     \i,       \i,       \shift
+.endr
+.endif
+
+    vst_x8 t7, \start0, \stride0, vr20, vr22, vr24, vr26, vr28, vr30, vr2, vr1
+
+    vst_x8 t7, \start1, \stride1, vr3, vr15, vr31, vr29, vr27, vr25, vr23, vr21
+.endm // dct64_step4_lsx
+
+.macro dct64_step5_lsx in0, in1, in2, in3, in4, in5, in6, in7
+    fld.d         f4,       t0,       0
+    fldx.d        f5,       t0,       a1
+    fld.d         f6,       t6,       0
+    fldx.d        f7,       t6,       a1
+    alsl.d        t0,       a1,       t0,    2
+    alsl.d        t6,       a1,       t6,    2
+    fld.d         f8,       t0,       0
+    fldx.d        f9,       t0,       a1
+    fld.d         f10,      t6,       0
+    fldx.d        f11,      t6,       a1
+.irp i, vr4, vr5, vr6, vr7, vr8, vr9, vr10, vr11
+    vsllwil.hu.bu   \i,      \i,       0
+.endr
+    vsrari.h      vr20,     \in0,     4
+    vsrari.h      vr22,     \in1,     4
+    vsrari.h      vr24,     \in2,     4
+    vsrari.h      vr26,     \in3,     4
+    vsrari.h      vr28,     \in4,     4
+    vsrari.h      vr30,     \in5,     4
+    vsrari.h      vr2,      \in6,     4
+    vsrari.h      vr1,      \in7,     4
+    vadd.h        vr4,      vr4,      vr20
+    vadd.h        vr5,      vr5,      vr22
+    vadd.h        vr6,      vr6,      vr24
+    vadd.h        vr7,      vr7,      vr26
+    vadd.h        vr8,      vr8,      vr28
+    vadd.h        vr9,      vr9,      vr30
+    vadd.h        vr10,     vr10,     vr2
+    vadd.h        vr11,     vr11,     vr1
+    vssrani.bu.h  vr5,      vr4,      0
+    vssrani.bu.h  vr7,      vr6,      0
+    vssrani.bu.h  vr9,      vr8,      0
+    vssrani.bu.h  vr11,     vr10,     0
+
+    vstelm.d      vr5,      t1,       0,     0
+    vstelm.d      vr5,      t2,       0,     1
+    alsl.d        t1,       a1,       t1,    1
+    alsl.d        t2,       a1,       t2,    1
+    vstelm.d      vr7,      t1,       0,     0
+    vstelm.d      vr7,      t2,       0,     1
+    alsl.d        t1,       a1,       t1,    1
+    alsl.d        t2,       a1,       t2,    1
+    vstelm.d      vr9,      t1,       0,     0
+    vstelm.d      vr9,      t2,       0,     1
+    alsl.d        t1,       a1,       t1,    1
+    alsl.d        t2,       a1,       t2,    1
+    vstelm.d      vr11,     t1,       0,     0
+    vstelm.d      vr11,     t2,       0,     1
+.endm // dct64_step5_lsx
+
+.macro dct_8x32_tx64_new_lsx vld_loc0, stride0, vld_loc1, stride1, rect2
+    vld_x8 t2, \vld_loc0, \stride0, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    dct_8x16_tx64_core_lsx \rect2
+
+    vst_x16 t3, 0, 16, vr22, vr18, vr17, vr28, vr20, vr14, vr15, vr16, \
+            vr27, vr30, vr23, vr21, vr29, vr26, vr25, vr24
+
+    vxor.v        vr31,     vr31,     vr31
+    vst_x8 t2, \vld_loc0, \stride0, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    vld_x8 t2, \vld_loc1, \stride1, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    vst_x8 t2, \vld_loc1, \stride1, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    la.local      t0,       idct_coeffs
+
+.ifc \rect2, rect2_lsx
+    vldrepl.w     vr23,      t0,       0        // 2896
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    rect2_lsx \i, vr23, \i
+.endr
+.endif
+
+    vldrepl.w     vr20,     t0,       64           // 201
+    vldrepl.w     vr21,     t0,       68           // 4091
+    vsllwil.w.h   vr22,     vr0,      0
+    vexth.w.h     vr23,     vr0
+    vmul.w        vr8,      vr22,     vr21
+    vmul.w        vr9,      vr23,     vr21
+    vmul.w        vr0,      vr22,     vr20
+    vmul.w        vr10,     vr23,     vr20
+    vssrarni.h.w  vr9,      vr8,      12           // t31a
+    vssrarni.h.w  vr10,     vr0,      12           // t16a
+
+    vldrepl.w     vr20,     t0,       72           // 3035
+    vldrepl.w     vr21,     t0,       76           // 2751
+    vsllwil.w.h   vr22,     vr7,      0
+    vexth.w.h     vr23,     vr7
+    vneg.w        vr21,     vr21
+    vmul.w        vr8,      vr22,     vr20
+    vmul.w        vr0,      vr23,     vr20
+    vmul.w        vr7,      vr22,     vr21
+    vmul.w        vr30,     vr23,     vr21
+    vssrarni.h.w  vr0,      vr8,      12           // t30a
+    vssrarni.h.w  vr30,     vr7,      12           // t17a
+
+    vldrepl.w     vr20,     t0,       80           // 1751
+    vldrepl.w     vr21,     t0,       84           // 3703
+    vsllwil.w.h   vr22,     vr4,      0
+    vexth.w.h     vr23,     vr4
+    vmul.w        vr8,      vr22,     vr21
+    vmul.w        vr7,      vr23,     vr21
+    vmul.w        vr4,      vr22,     vr20
+    vmul.w        vr19,     vr23,     vr20
+    vssrarni.h.w  vr7,      vr8,      12           // t29a
+    vssrarni.h.w  vr19,     vr4,      12           // t18a
+
+    vldrepl.w     vr20,     t0,       88           // 3857
+    vldrepl.w     vr21,     t0,       92           // 1380
+    vsllwil.w.h   vr22,     vr3,      0
+    vexth.w.h     vr23,     vr3
+    vneg.w        vr21,     vr21
+    vmul.w        vr8,      vr22,     vr20
+    vmul.w        vr4,      vr23,     vr20
+    vmul.w        vr3,      vr22,     vr21
+    vmul.w        vr26,     vr23,     vr21
+    vssrarni.h.w  vr4,      vr8,      12           // t28a
+    vssrarni.h.w  vr26,     vr3,      12           // t19a
+
+    vldrepl.w     vr20,     t0,       96           // 995
+    vldrepl.w     vr21,     t0,       100          // 3973
+    vsllwil.w.h   vr22,     vr2,      0
+    vexth.w.h     vr23,     vr2
+    vmul.w        vr8,      vr22,     vr21
+    vmul.w        vr3,      vr23,     vr21
+    vmul.w        vr2,      vr22,     vr20
+    vmul.w        vr27,     vr23,     vr20
+    vssrarni.h.w  vr3,      vr8,      12           // t27a
+    vssrarni.h.w  vr27,     vr2,      12           // t20a
+
+    vldrepl.w     vr20,     t0,       104          // 3513
+    vldrepl.w     vr21,     t0,       108          // 2106
+    vsllwil.w.h   vr22,     vr5,      0
+    vexth.w.h     vr23,     vr5
+    vneg.w        vr21,     vr21
+    vmul.w        vr8,      vr22,     vr20
+    vmul.w        vr2,      vr23,     vr20
+    vmul.w        vr5,      vr22,     vr21
+    vmul.w        vr28,     vr23,     vr21
+    vssrarni.h.w  vr2,      vr8,      12           // t26a
+    vssrarni.h.w  vr28,     vr5,      12           // t21a
+
+    vldrepl.w     vr20,     t0,       112          // 2440 -> 1220
+    vldrepl.w     vr21,     t0,       116          // 3290 -> 1645
+    vsllwil.w.h   vr22,     vr6,      0
+    vexth.w.h     vr23,     vr6
+    vmul.w        vr8,      vr22,     vr21
+    vmul.w        vr5,      vr23,     vr21
+    vmul.w        vr6,      vr22,     vr20
+    vmul.w        vr25,     vr23,     vr20
+    vssrarni.h.w  vr5,      vr8,      12           // t25a
+    vssrarni.h.w  vr25,     vr6,      12           // t22a
+
+    vldrepl.w     vr20,     t0,       120          // 4052
+    vldrepl.w     vr21,     t0,       124          // 601
+    vsllwil.w.h   vr22,     vr1,      0
+    vexth.w.h     vr23,     vr1
+    vneg.w        vr21,     vr21
+    vmul.w        vr8,      vr22,     vr20
+    vmul.w        vr6,      vr23,     vr20
+    vmul.w        vr1,      vr22,     vr21
+    vmul.w        vr24,     vr23,     vr21
+    vssrarni.h.w  vr6,      vr8,      12           // t24a
+    vssrarni.h.w  vr24,     vr1,      12           // t23a
+
+    vsadd.h       vr1,      vr10,     vr30         // t16
+    vssub.h       vr29,     vr10,     vr30         // t17
+    vssub.h       vr8,      vr26,     vr19         // t18
+    vsadd.h       vr31,     vr26,     vr19         // t19
+    vsadd.h       vr10,     vr27,     vr28         // t20
+    vssub.h       vr30,     vr27,     vr28         // t21
+    vssub.h       vr19,     vr24,     vr25         // t22
+    vsadd.h       vr26,     vr24,     vr25         // t23
+    vsadd.h       vr27,     vr6,      vr5          // t24
+    vssub.h       vr28,     vr6,      vr5          // t25
+    vssub.h       vr24,     vr3,      vr2          // t26
+    vsadd.h       vr25,     vr3,      vr2          // t27
+    vsadd.h       vr5,      vr4,      vr7          // t28
+    vssub.h       vr6,      vr4,      vr7          // t29
+    vssub.h       vr2,      vr9,      vr0          // t30
+    vsadd.h       vr3,      vr9,      vr0          // t31
+
+    vldrepl.w     vr20,     t0,       16           // 799
+    vldrepl.w     vr21,     t0,       20           // 4017
+    vmul_vmadd_w vr2, vr29, vr21, vr20, vr4, vr7
+    vmul_vmsub_w vr2, vr29, vr20, vr21, vr11, vr0
+    vssrarni.h.w  vr7,      vr4,      12           // t30a
+    vssrarni.h.w  vr0,      vr11,     12           // t17a
+    vmul_vmadd_w vr6, vr8, vr21, vr20, vr4, vr9
+    vneg.w        vr4,      vr4
+    vneg.w        vr9,      vr9
+    vmul_vmsub_w vr6, vr8, vr20, vr21, vr11, vr2
+    vssrarni.h.w  vr9,      vr4,      12           // t18a
+    vssrarni.h.w  vr2,      vr11,     12           // t29a
+
+    vldrepl.w     vr20,     t0,       24           // 3406 -> 1703
+    vldrepl.w     vr21,     t0,       28           // 2276 -> 1138
+    vmul_vmadd_w vr24, vr30, vr21, vr20, vr4, vr29
+    vmul_vmsub_w vr24, vr30, vr20, vr21, vr11, vr6
+    vssrarni.h.w  vr29,     vr4,      12           // t26a
+    vssrarni.h.w  vr6,      vr11,     12           // t21a
+
+    vmul_vmadd_w vr28, vr19, vr21, vr20, vr4, vr8
+    vneg.w        vr4,      vr4
+    vneg.w        vr8,      vr8
+    vmul_vmsub_w vr28, vr19, vr20, vr21, vr11, vr24
+    vssrarni.h.w  vr8,      vr4,      12           // t22a
+    vssrarni.h.w  vr24,     vr11,     12           // t25a
+
+    vsadd.h       vr4,      vr1,      vr31         // t16a
+    vssub.h       vr30,     vr1,      vr31         // t19a
+    vsadd.h       vr19,     vr0,      vr9          // t17
+    vssub.h       vr28,     vr0,      vr9          // t18
+    vssub.h       vr1,      vr26,     vr10         // t20a
+    vsadd.h       vr31,     vr26,     vr10         // t23a
+    vssub.h       vr0,      vr8,      vr6          // t21
+    vsadd.h       vr9,      vr8,      vr6          // t22
+    vsadd.h       vr10,     vr27,     vr25         // t24a
+    vssub.h       vr26,     vr27,     vr25         // t27a
+    vsadd.h       vr6,      vr24,     vr29         // t25
+    vssub.h       vr8,      vr24,     vr29         // t26
+    vssub.h       vr25,     vr3,      vr5          // t28a
+    vsadd.h       vr27,     vr3,      vr5          // t31a
+    vssub.h       vr24,     vr7,      vr2          // t29
+    vsadd.h       vr29,     vr7,      vr2          // t30
+
+    vldrepl.w     vr20,     t0,       8            // 1567
+    vldrepl.w     vr21,     t0,       12           // 3784
+    vmul_vmadd_w vr24, vr28, vr21, vr20, vr3, vr5
+    vmul_vmsub_w vr24, vr28, vr20, vr21, vr11, vr2
+    vssrarni.h.w  vr5,      vr3,      12           // t29a
+    vssrarni.h.w  vr2,      vr11,     12           // 18a
+
+    vmul_vmadd_w vr25, vr30, vr21, vr20, vr3, vr7
+    vmul_vmsub_w vr25, vr30, vr20, vr21, vr11, vr24
+    vssrarni.h.w  vr7,      vr3,      12           // t28
+    vssrarni.h.w  vr24,     vr11,     12           // t19
+
+    vmul_vmadd_w vr26, vr1, vr21, vr20, vr3, vr28
+    vneg.w        vr3,      vr3
+    vneg.w        vr28,     vr28
+    vmul_vmsub_w vr26, vr1, vr20, vr21, vr11, vr25
+    vssrarni.h.w  vr28,     vr3,      12           // t20
+    vssrarni.h.w  vr25,     vr11,     12           // t27
+
+    vmul_vmadd_w vr8, vr0, vr21, vr20, vr3, vr30
+    vneg.w        vr3,      vr3
+    vneg.w        vr30,     vr30
+    vmul_vmsub_w vr8, vr0, vr20, vr21, vr11, vr1
+    vssrarni.h.w  vr30,     vr3,      12           // t21a
+    vssrarni.h.w  vr1,      vr11,     12           // t26a
+
+    vsadd.h       vr3,      vr4,      vr31         // t16
+    vssub.h       vr26,     vr4,      vr31         // t23
+    vsadd.h       vr0,      vr19,     vr9          // t17a
+    vssub.h       vr8,      vr19,     vr9          // t22a
+    vsadd.h       vr4,      vr2,      vr30         // t18
+    vssub.h       vr31,     vr2,      vr30         // t21
+    vsadd.h       vr9,      vr24,     vr28         // t19a
+    vssub.h       vr19,     vr24,     vr28         // t20a
+    vssub.h       vr2,      vr27,     vr10         // t24
+    vsadd.h       vr30,     vr27,     vr10         // t31
+    vssub.h       vr24,     vr29,     vr6          // t25a
+    vsadd.h       vr28,     vr29,     vr6          // t30a
+    vssub.h       vr10,     vr5,      vr1          // t26
+    vsadd.h       vr27,     vr5,      vr1          // t29
+    vssub.h       vr6,      vr7,      vr25         // t27a
+    vsadd.h       vr29,     vr7,      vr25         // t28a
+
+    vldrepl.w     vr20,     t0,       0            // 2896
+    vmul_vmsub_w vr6, vr19, vr20, vr20, vr1, vr5
+    vmul_vmadd_w vr6, vr19, vr20, vr20, vr11, vr7
+    vssrarni.h.w  vr5,      vr1,      12           // t20
+    vssrarni.h.w  vr7,      vr11,     12           // t27
+
+    vmul_vmsub_w vr10, vr31, vr20, vr20, vr1, vr25
+    vmul_vmadd_w vr10, vr31, vr20, vr20, vr11, vr6
+    vssrarni.h.w  vr25,     vr1,      12           // t21a
+    vssrarni.h.w  vr6,      vr11,     12           // t26a
+
+    vmul_vmsub_w vr24, vr8, vr20, vr20, vr1, vr19
+    vmul_vmadd_w vr24, vr8, vr20, vr20, vr11, vr10
+    vssrarni.h.w  vr19,     vr1,      12           // t22
+    vssrarni.h.w  vr10,     vr11,     12           // t25
+
+    vmul_vmsub_w vr2, vr26, vr20, vr20, vr1, vr31
+    vmul_vmadd_w vr2, vr26, vr20, vr20, vr11, vr8
+    vssrarni.h.w  vr31,     vr1,      12           // t23a
+    vssrarni.h.w  vr8,      vr11,     12           // t24a
+
+    // t31 t30a t29 t28a t27 t26a t25 t24a t23a t22 t21a t20 t19a t18 t17a t16
+    // vr30 vr28 vr27 vr29 vr7 vr6 vr10 vr8 vr31 vr19 vr25 vr5 vr9 vr4 vr0 vr3
+    vld_x8 t3, 0, 16, vr11, vr12, vr13, vr14, vr15, vr16, vr17, vr18
+
+    vsadd.h       vr1,      vr11,     vr30         // c[0]
+    vssub.h       vr2,      vr11,     vr30         // c[31]
+    vsadd.h       vr24,     vr12,     vr28         // c[1]
+    vssub.h       vr26,     vr12,     vr28         // c[30]
+    vsadd.h       vr11,     vr13,     vr27         // c[2]
+    vssub.h       vr30,     vr13,     vr27         // c[29]
+    vsadd.h       vr12,     vr14,     vr29         // c[3]
+    vssub.h       vr28,     vr14,     vr29         // c[28]
+    vsadd.h       vr13,     vr15,     vr7          // c[4]
+    vssub.h       vr27,     vr15,     vr7          // c[27]
+    vsadd.h       vr14,     vr16,     vr6          // c[5]
+    vssub.h       vr29,     vr16,     vr6          // c[26]
+    vsadd.h       vr7,      vr17,     vr10         // c[6]
+    vssub.h       vr15,     vr17,     vr10         // c[25]
+    vsadd.h       vr6,      vr18,     vr8          // c[7]
+    vssub.h       vr16,     vr18,     vr8          // c[24]
+
+    vst_x8 t3, 0, 16, vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6
+
+    vst_x8 t3, 384, 16, vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2
+
+    vld_x8 t3, 128, 16, vr11, vr12, vr13, vr14, vr15, vr16, vr17, vr18
+
+    vsadd.h       vr1,      vr11,     vr31         // c[8]
+    vssub.h       vr2,      vr11,     vr31         // c[23]
+    vsadd.h       vr24,     vr12,     vr19         // c[9]
+    vssub.h       vr26,     vr12,     vr19         // c[22]
+    vsadd.h       vr11,     vr13,     vr25         // c[10]
+    vssub.h       vr30,     vr13,     vr25         // c[21]
+    vsadd.h       vr12,     vr14,     vr5          // c[11]
+    vssub.h       vr28,     vr14,     vr5          // c[20]
+    vsadd.h       vr13,     vr15,     vr9          // c[12]
+    vssub.h       vr27,     vr15,     vr9          // c[19]
+    vsadd.h       vr14,     vr16,     vr4          // c[13]
+    vssub.h       vr29,     vr16,     vr4          // c[18]
+    vsadd.h       vr7,      vr17,     vr0          // c[14]
+    vssub.h       vr15,     vr17,     vr0          // c[17]
+    vsadd.h       vr6,      vr18,     vr3          // c[15]
+    vssub.h       vr16,     vr18,     vr3          // c[16]
+
+    vst_x8 t3, 128, 16, vr1, vr24, vr11, vr12, vr13, vr14, vr7, vr6
+
+    vst_x8 t3, 256, 16, vr16, vr15, vr29, vr27, vr28, vr30, vr26, vr2
+.endm // dct_8x32_tx64_new_lsx
+
+.macro DST_ADD_W64 in0, in1, in2, in3, in4, in5, in6, in7
+    vsllwil.hu.bu vr4,      vr10,     0
+    vsllwil.hu.bu vr5,      vr11,     0
+    vsllwil.hu.bu vr6,      vr12,     0
+    vsllwil.hu.bu vr7,      vr13,     0
+    vexth.hu.bu   vr10,     vr10
+    vexth.hu.bu   vr11,     vr11
+    vexth.hu.bu   vr12,     vr12
+    vexth.hu.bu   vr13,     vr13
+    vadd.h        vr4,      vr4,      \in0
+    vadd.h        vr10,     vr10,     \in1
+    vadd.h        vr5,      vr5,      \in2
+    vadd.h        vr11,     vr11,     \in3
+    vadd.h        vr6,      vr6,      \in4
+    vadd.h        vr12,     vr12,     \in5
+    vadd.h        vr7,      vr7,      \in6
+    vadd.h        vr13,     vr13,     \in7
+    vssrani.bu.h  vr10,     vr4,      0
+    vssrani.bu.h  vr11,     vr5,      0
+    vssrani.bu.h  vr12,     vr6,      0
+    vssrani.bu.h  vr13,     vr7,      0
+    vst           vr10,     a0,       0
+    vst           vr11,     a0,       16
+    vst           vr12,     a0,       32
+    vst           vr13,     a0,       48
+.endm
+
+.macro idct_dc_w64 w, h, shift
+    ld.h          t2,       a2,       0
+    vldi          vr0,      0x8b5
+    vreplgr2vr.w  vr1,      t2
+    vldi          vr20,     0x880
+    vmul.w        vr2,      vr0,      vr1
+    st.h          zero,     a2,       0
+    vsrari.w      vr2,      vr2,      8
+    vld           vr13,     a0,       48
+
+.if (2*\w == \h) || (2*\h == \w)
+    vmul.w        vr2,      vr2,      vr0
+    vsrari.w      vr2,      vr2,      8
+.endif
+
+.if \shift>0
+    vsrari.w      vr2,      vr2,      \shift
+.endif
+    vld           vr11,     a0,       16
+    vmadd.w       vr20,     vr2,      vr0
+    vld           vr12,     a0,       32
+    vssrarni.h.w  vr20,     vr20,     12
+    vld           vr10,     a0,       0
+.endm
+
+function inv_txfm_add_dct_dct_64x64_8bpc_lsx
+    bnez          a3,       .NO_HAS_DCONLY_64x64
+
+    idct_dc_w64 64, 64, 2
+
+    DST_ADD_W64 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+
+    li.w          t3,       63
+.loop63:
+    add.d         a0,       a0,       a1
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     a0,       32
+    vld           vr13,     a0,       48
+    DST_ADD_W64 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+    addi.d        t3,       t3,       -1
+    blt           zero,     t3,       .loop63
+    b             .DCT_DCT_64X64_END
+.NO_HAS_DCONLY_64x64:
+
+    malloc_space  64*32*2+512+512
+
+.macro dct64x64_core1_lsx shift, rect2
+    //addi.d        t2,       a2,       \in0
+    //addi.d        t7,       t7,       \in1
+    li.w          t4,       64*32*2+64
+    add.d         t3,       sp,       t4
+    addi.d        t6,       t3,       512
+    add.d         t5,       t6,       zero
+
+    dct_8x32_tx64_new_lsx 0, 256, 128, 256, \rect2
+
+    la.local      t0,       idct64_coeffs
+    vxor.v        vr31,     vr31,     vr31
+
+    //addi.d        a4,       a2,       \in2         // 32 ...
+    // in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+    vld           vr0,      a4,       128*0        // in1
+    vld           vr1,      a4,       128*15       // in31
+    vld           vr2,      a4,       128*8        // in17
+    vld           vr3,      a4,       128*7        // in15
+    la.local      a6,       idct_coeffs
+.ifc \rect2, rect2_lsx
+    vldrepl.w     vr23,      a6,       0        // 2896
+.irp i, vr0, vr1, vr2, vr3
+    rect2_lsx \i, vr23, \i
+.endr
+.endif
+    vst           vr31,     a4,       128*0
+    vst           vr31,     a4,       128*15
+    vst           vr31,     a4,       128*8
+    vst           vr31,     a4,       128*7
+    dct64_step1_lsx
+
+    addi.d        t0,       t0,       48
+    addi.d        t6,       t6,       128
+    // in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+    vld           vr0,      a4,       128*3        // in7
+    vld           vr1,      a4,       128*12       // in25
+    vld           vr2,      a4,       128*11       // in23
+    vld           vr3,      a4,       128*4        // in9
+    la.local      a6,       idct_coeffs
+.ifc \rect2, rect2_lsx
+    vldrepl.w     vr23,      a6,       0        // 2896
+.irp i, vr0, vr1, vr2, vr3
+    rect2_lsx \i, vr23, \i
+.endr
+.endif
+    vst           vr31,     a4,       128*3
+    vst           vr31,     a4,       128*12
+    vst           vr31,     a4,       128*11
+    vst           vr31,     a4,       128*4
+    dct64_step1_lsx
+
+    addi.d        t0,       t0,       48
+    addi.d        t6,       t6,       128
+    // in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+    vld           vr0,      a4,       128*2        // in5
+    vld           vr1,      a4,       128*13       // in27
+    vld           vr2,      a4,       128*10       // in21
+    vld           vr3,      a4,       128*5        // in11
+    la.local      a6,       idct_coeffs
+.ifc \rect2, rect2_lsx
+    vldrepl.w     vr23,      a6,      0        // 2896
+.irp i, vr0, vr1, vr2, vr3
+    rect2_lsx \i, vr23, \i
+.endr
+.endif
+    vst           vr31,     a4,       128*2
+    vst           vr31,     a4,       128*13
+    vst           vr31,     a4,       128*10
+    vst           vr31,     a4,       128*5
+    dct64_step1_lsx
+
+    addi.d        t0,       t0,       48
+    addi.d        t6,       t6,       128
+    // in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+    vld           vr0,      a4,       128*1        // in3
+    vld           vr1,      a4,       128*14       // in29
+    vld           vr2,      a4,       128*9        // in19
+    vld           vr3,      a4,       128*6        // in13
+    la.local      a6,       idct_coeffs
+.ifc \rect2, rect2_lsx
+    vldrepl.w     vr23,      a6,       0        // 2896
+.irp i, vr0, vr1, vr2, vr3
+    rect2_lsx \i, vr23, \i
+.endr
+.endif
+    vst           vr31,     a4,       128*1
+    vst           vr31,     a4,       128*14
+    vst           vr31,     a4,       128*9
+    vst           vr31,     a4,       128*6
+    dct64_step1_lsx
+
+    la.local      t0,       idct_coeffs
+    addi.d        t4,       t5,       16*7
+    // t32a/t39/t40a/t47/t48/t55a/t56/t63a
+    dct64_step2_lsx
+
+    addi.d        t5,       t5,       16
+    addi.d        t4,       t4,       -16
+    // t33/t38a/t41/t46a/t49a/t54/t57a/t62
+    dct64_step2_lsx
+
+    addi.d        t5,       t5,       16
+    addi.d        t4,       t4,       -16
+    // t34a/t37/t42a/t45/t50/t53a/t58/t61a
+    dct64_step2_lsx
+
+    addi.d        t5,       t5,       16
+    addi.d        t4,       t4,       -16
+    // t35/t36a/t43/t44a/t51a/t52/t59a/t60
+    dct64_step2_lsx
+
+    li.w          t4,       64*32*2+64+512
+    add.d         t5,       t4,       sp
+    addi.d        t4,       t5,       16*7
+    dct64_step4_lsx transpose8x8, \shift, 0, 128, 112, 128
+
+    addi.d        t3,       t3,       128
+    addi.d        t4,       t4,       -16*8
+    addi.d        t5,       t5,       -16*8
+    dct64_step4_lsx transpose8x8, \shift, 16, 128, 96, 128
+
+    addi.d        t5,       t5,       -16*8
+    addi.d        t4,       t4,       -16*8
+    addi.d        t3,       t3,       128
+    dct64_step4_lsx transpose8x8, \shift, 32, 128, 80, 128
+
+    addi.d        t5,       t5,       -16*8
+    addi.d        t4,       t4,       -16*8
+    addi.d        t3,       t3,       128
+    dct64_step4_lsx transpose8x8, \shift, 48, 128, 64, 128
+.endm
+    la.local      t8,       eob_32x32
+    addi.d        t2,       a2,       0
+    addi.d        t7,       sp,       64
+    addi.d        t7,       t7,       0
+    addi.d        a4,       a2,       64
+.DCT_DCT_EOB_64x64:
+    ld.h          a5,       t8,       0
+    addi.d        t8,       t8,       2
+    dct64x64_core1_lsx 2, no_rect2
+    addi.d        t2,       t2,       16
+    addi.d        t7,       t7,       128*8
+    addi.d        a4,       a4,       16
+    bge           a3,       a5,       .DCT_DCT_EOB_64x64
+
+    la.local      t8,       eob_32x32
+    vxor.v        vr31,     vr31,     vr31
+
+    ld.h          t7,       t8,       4
+    bge           a3,       t7,       .DCT_DCT_EOB_64x64_END
+    li.d          t1,       1024*3+64
+    add.d         t0,       sp,       t1
+.rept 4
+    vst_x16 t0, 0, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    addi.d t0, t0, 256
+.endr
+
+    ld.h          t7,       t8,       2
+    bge           a3,       t7,       .DCT_DCT_EOB_64x64_END
+    li.d          t1,       1024*2+64
+    add.d         t0,       sp,       t1
+.rept 4
+    vst_x16 t0, 0, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    addi.d        t0,       t0,       256
+.endr
+    ld.h          t7,       t8,       0
+    bge           a3,       t7,       .DCT_DCT_EOB_64x64_END
+
+    li.d          t1,       1024*1+64
+    add.d         t0,       sp,       t1
+.rept 4
+    vst_x16 t0, 0, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    addi.d        t0,       t0,       256
+.endr
+
+.DCT_DCT_EOB_64x64_END:
+
+.macro dct64x64_core2_lsx in0, in1, rect2
+    addi.d        t2,       sp,       64+\in0
+    addi.d        t7,       sp,       64+\in0
+    li.w          t4,       64*32*2+64
+    add.d         t3,       sp,       t4
+    addi.d        t6,       t3,       512
+    add.d         t5,       t6,       zero
+
+    addi.d        t2,       t2,       1024
+    addi.d        t2,       t2,       1024
+    dct_8x32_tx64_new_lsx -2048, 512, 256-2048, 512, \rect2
+
+    la.local      t0,       idct64_coeffs
+    addi.d        t2,       sp,       64+64*2+\in0
+    addi.d        t4,       t2,       256*7
+    addi.d        t4,       t4,       256
+
+    vld           vr0,      t2,       256*0        // in1
+    vld           vr1,      t4,       256*7        // in31
+    vld           vr2,      t4,       256*0        // in17
+    vld           vr3,      t2,       256*7        // in15
+    dct64_step1_lsx
+
+    addi.d        t0,       t0,       48
+    addi.d        t6,       t6,       128
+    vld           vr0,      t2,       256*3        // in7
+    vld           vr1,      t4,       256*4        // in25
+    vld           vr2,      t4,       256*3        // in23
+    vld           vr3,      t2,       256*4        // in9
+    dct64_step1_lsx
+
+    addi.d        t0,        t0,       48
+    addi.d        t6,        t6,       128
+    vld           vr0,       t2,       256*2       // in5
+    vld           vr1,       t4,       256*5       // in27
+    vld           vr2,       t4,       256*2       // in21
+    vld           vr3,       t2,       256*5       // in11
+    dct64_step1_lsx
+
+    addi.d        t0,        t0,       48
+    addi.d        t6,        t6,       128
+    vld           vr0,       t2,       256*1       // in3
+    vld           vr1,       t4,       256*6       // in29
+    vld           vr2,       t4,       256*1       // in19
+    vld           vr3,       t2,       256*6       // in13
+    dct64_step1_lsx
+
+    la.local      t0,       idct_coeffs
+    addi.d        t4,       t5,       16*7
+    // t32a/t39/t40a/t47/t48/t55a/t56/t63a
+    dct64_step2_lsx
+
+    addi.d        t5,       t5,       16
+    addi.d        t4,       t4,       -16
+    // t33/t38a/t41/t46a/t49a/t54/t57a/t62
+    dct64_step2_lsx
+
+    addi.d        t5,       t5,       16
+    addi.d        t4,       t4,       -16
+    // t34a/t37/t42a/t45/t50/t53a/t58/t61a
+    dct64_step2_lsx
+
+    addi.d        t5,       t5,       16
+    addi.d        t4,       t4,       -16
+    // t35/t36a/t43/t44a/t51a/t52/t59a/t60
+    dct64_step2_lsx
+
+    li.w          t4,       64*32*2+64+512
+    add.d         t5,       t4,       sp
+    addi.d        t4,       t5,       16*7
+    addi.d        a0,       a0,       \in1
+    // 0 - 7, 56 -63
+    dct64_step3_lsx
+    li.w          t8,       0
+    mul.w         t0,       t8,       a1
+    add.d         t0,       a0,       t0
+    alsl.d        t6,       a1,       t0,      1
+    addi.d        t1,       t0,       0
+    add.d         t2,       t0,       a1
+    dct64_step5_lsx vr20, vr22, vr24, vr26, vr28, vr30, vr2, vr1
+    li.w          t8,       56
+    mul.w         t0,       t8,       a1
+    add.d         t0,       a0,       t0
+    alsl.d        t6,       a1,       t0,      1
+    addi.d        t1,       t0,       0
+    add.d         t2,       t0,       a1
+    dct64_step5_lsx vr3, vr15, vr31, vr29, vr27, vr25, vr23, vr21
+
+    // 8 - 15, 48 - 55
+    addi.d        t3,       t3,       128
+    addi.d        t4,       t4,       -16*8
+    addi.d        t5,       t5,       -16*8
+    dct64_step3_lsx
+    li.w          t8,       8
+    mul.w         t0,       t8,       a1
+    add.d         t0,       t0,       a0
+    alsl.d        t6,       a1,       t0,     1
+    addi.d        t1,       t0,       0
+    add.d         t2,       t0,       a1
+    dct64_step5_lsx vr20, vr22, vr24, vr26, vr28, vr30, vr2, vr1
+    li.w          t8,       48
+    mul.w         t0,       t8,       a1
+    add.d         t0,       t0,       a0
+    alsl.d        t6,       a1,       t0,     1
+    addi.d        t1,       t0,       0
+    add.d         t2,       t0,       a1
+    dct64_step5_lsx vr3, vr15, vr31, vr29, vr27, vr25, vr23, vr21
+
+    // 16 - 23, 40 - 47
+    addi.d        t3,       t3,       128
+    addi.d        t4,       t4,       -16*8
+    addi.d        t5,       t5,       -16*8
+    dct64_step3_lsx
+    li.w          t8,       16
+    mul.w         t0,       t8,       a1
+    add.d         t0,       t0,       a0
+    alsl.d        t6,       a1,       t0,     1
+    addi.d        t1,       t0,       0
+    add.d         t2,       t0,       a1
+    dct64_step5_lsx vr20, vr22, vr24, vr26, vr28, vr30, vr2, vr1
+    li.w          t8,       40
+    mul.w         t0,       t8,       a1
+    add.d         t0,       t0,       a0
+    alsl.d        t6,       a1,       t0,     1
+    addi.d        t1,       t0,       0
+    add.d         t2,       t0,       a1
+    dct64_step5_lsx vr3, vr15, vr31, vr29, vr27, vr25, vr23, vr21
+
+    // 24 - 31, 32 - 39
+    addi.d        t3,       t3,       128
+    addi.d        t4,       t4,       -16*8
+    addi.d        t5,       t5,       -16*8
+    dct64_step3_lsx
+    li.w          t8,       24
+    mul.w         t0,       t8,       a1
+    add.d         t0,       t0,       a0
+    alsl.d        t6,       a1,       t0,     1
+    addi.d        t1,       t0,       0
+    add.d         t2,       t0,       a1
+    dct64_step5_lsx vr20, vr22, vr24, vr26, vr28, vr30, vr2, vr1
+    li.w          t8,       32
+    mul.w         t0,       t8,       a1
+    add.d         t0,       t0,       a0
+    alsl.d        t6,       a1,       t0,     1
+    addi.d        t1,       t0,       0
+    add.d         t2,       t0,       a1
+    dct64_step5_lsx vr3, vr15, vr31, vr29, vr27, vr25, vr23, vr21
+.endm
+    dct64x64_core2_lsx 16*0, 0, no_rect2
+    dct64x64_core2_lsx 16*1, 8, no_rect2
+    dct64x64_core2_lsx 16*2, 8, no_rect2
+    dct64x64_core2_lsx 16*3, 8, no_rect2
+    dct64x64_core2_lsx 16*4, 8, no_rect2
+    dct64x64_core2_lsx 16*5, 8, no_rect2
+    dct64x64_core2_lsx 16*6, 8, no_rect2
+    dct64x64_core2_lsx 16*7, 8, no_rect2
+
+    free_space 64*32*2+512+512
+.DCT_DCT_64X64_END:
+endfunc
+
+function inv_txfm_add_dct_dct_64x32_8bpc_lsx
+    bnez          a3,       .NO_HAS_DCONLY_64x32
+
+    idct_dc_w64 64, 32, 1
+
+    DST_ADD_W64 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+
+    li.w          t3,       31
+.loop31:
+    add.d         a0,       a0,       a1
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     a0,       32
+    vld           vr13,     a0,       48
+    DST_ADD_W64 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+    addi.d        t3,       t3,       -1
+    blt           zero,     t3,       .loop31
+    b             .DCT_DCT_64X32_END
+.NO_HAS_DCONLY_64x32:
+    malloc_space  64*32*2+512+512
+
+    la.local      t8,       eob_32x32
+    addi.d        t2,       a2,       0
+    addi.d        t7,       sp,       64
+    addi.d        t7,       t7,       0
+    addi.d        a4,       a2,       64
+.DCT_DCT_EOB_64x32:
+    ld.h          a5,       t8,       0
+    addi.d        t8,       t8,       2
+    dct64x64_core1_lsx 1, rect2_lsx
+    addi.d        t2,       t2,       16
+    addi.d        t7,       t7,       128*8
+    addi.d        a4,       a4,       16
+    bge           a3,       a5,       .DCT_DCT_EOB_64x32
+
+    la.local      t8,       eob_32x32
+    vxor.v        vr31,     vr31,     vr31
+
+    ld.h          t7,       t8,       4
+    bge           a3,       t7,       .DCT_DCT_EOB_64x32_END
+    li.d          t1,       1024*3+64
+    add.d         t0,       sp,       t1
+.rept 4
+    vst_x16 t0, 0, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    addi.d t0, t0, 256
+.endr
+
+    ld.h          t7,       t8,       2
+    bge           a3,       t7,       .DCT_DCT_EOB_64x32_END
+    li.d          t1,       1024*2+64
+    add.d         t0,       sp,       t1
+.rept 4
+    vst_x16 t0, 0, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    addi.d        t0,       t0,       256
+.endr
+
+    ld.h          t7,       t8,       0
+    bge           a3,       t7,       .DCT_DCT_EOB_64x32_END
+    li.d          t1,       1024*1+64
+    add.d         t0,       sp,       t1
+.rept 4
+    vst_x16 t0, 0, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31, \
+            vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    addi.d        t0,       t0,       256
+.endr
+
+.DCT_DCT_EOB_64x32_END:
+    addi.d        t2,       sp,       64
+    li.w          t4,       64*32*2+64
+    add.d         t3,       sp,       t4
+    addi.d        t5,       sp,       64
+    addi.d        t5,       t5,       1024
+    addi.d        t5,       t5,       1024
+.rept 8
+    vld_x8 t2, 0, 256, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    addi.d        t4,       t2,       1024
+    addi.d        t4,       t4,       1024
+
+    vld_x8 t4, 0, 256, vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    inv_dct16_lsx no_rect2
+
+    vst_x16 t3, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    addi.d        t4,       t2,       128
+    vld_x8 t4, 0, 256, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    addi.d        t4,       t4,       1024
+    addi.d        t4,       t4,       1024
+
+    vld_x8 t4, 0, 256, vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+
+    dct_8x32_core_lsx t5, t3, 0, 128, 16, -2048, 1024, -1024, 0, 128, , 4
+
+    addi.d        t2,       t2,       16
+    addi.d        t5,       t5,       16
+    addi.d        t1,       t1,       16
+.endr
+    addi.d        t2,       sp,       64
+    li.w          t3,       32
+.loop32:
+    vld           vr10,     a0,       0
+    vld           vr11,     a0,       16
+    vld           vr12,     a0,       32
+    vld           vr13,     a0,       48
+    vld_x8 t2, 0, 16, vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    DST_ADD_W64 vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    add.d         a0,       a0,       a1
+    addi.d        t2,       t2,       128
+    addi.d        t3,       t3,       -1
+    blt           zero,     t3,       .loop32
+
+    free_space  64*32*2+512+512
+.DCT_DCT_64X32_END:
+endfunc
+
+.macro VLD_DST_ADD_W8_H32 in0
+    vld           vr4,      t3,       0
+    vld           vr5,      t3,       16
+    vld           vr6,      t3,       32
+    vld           vr7,      t3,       48
+    VLD_DST_ADD_W8 vr4, vr5, vr6, vr7
+    addi.d        t3,       t3,       64
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       t2,     2
+    vld           vr4,      t3,       0
+    vld           vr5,      t3,       16
+    vld           vr6,      t3,       32
+    vld           vr7,      t3,       48
+    VLD_DST_ADD_W8 vr4, vr5, vr6, vr7
+    addi.d        t3,       sp,       \in0
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       t2,     2
+.endm
+
+function inv_txfm_add_dct_dct_8x32_8bpc_lsx
+    bnez          a3,       .NO_HAS_DCONLY_8x32
+
+    idct_dc 8, 32, 2
+
+    DST_ADD_W8 vr10, vr11, vr12, vr13, vr20, vr20, vr20, vr20
+.rept 7
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,     1
+
+    VLD_DST_ADD_W8 vr20, vr20, vr20, vr20
+.endr
+    b             .DCT_DCT_8X32_END
+.NO_HAS_DCONLY_8x32:
+    malloc_space 512
+
+    la.local      t8,       eob_8x32
+    addi.d        t3,       sp,       64
+    addi.d        t2,       a2,       0
+.DCT_DCT_EOB_8x32:
+    ld.h          t7,       t8,       0
+    addi.d        t8,       t8,       2
+
+    vld_x8 a2, 0, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    inv_dct8_lsx vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, .8h
+
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vsrari.h      \i,       \i,       2
+.endr
+
+    vxor.v        vr31,     vr31,     vr31
+    vst_x8 a2, 0, 64, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    LSX_TRANSPOSE8x8_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+    vst_x8 t3, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    addi.d        a2,       a2,       16
+    addi.d        t3,       t3,       128
+    bge           a3,       t7,       .DCT_DCT_EOB_8x32
+
+    la.local      t8,       eob_8x32
+    vxor.v        vr31,     vr31,     vr31
+    ld.h          t7,       t8,       4
+    bge           a3,       t7,       .DCT_DCT_EOB_8x32_END
+    vst_x8 sp, 64+384, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    ld.h          t7,       t8,       2
+    bge           a3,       t7,       .DCT_DCT_EOB_8x32_END
+    vst_x8 sp, 64+256, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    ld.h          t7,       t8,       0
+    bge           a3,       t7,       .DCT_DCT_EOB_8x32_END
+    vst_x8 sp, 64+128, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+.DCT_DCT_EOB_8x32_END:
+    addi.d        t2,       sp,       64
+    addi.d        t3,       sp,       64
+
+    vld_x16 t2, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    inv_dct16_lsx .8h
+
+    vst_x16 t3, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vld_x16 t2, 16, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+
+    dct_8x32_core_lsx t2, t3, 0, 256, 32, 0, 128, 256, 384, 16, , 4
+
+    alsl.d        t2,       a1,       a0,     1
+    addi.d        t3,       sp,       64
+
+    VLD_DST_ADD_W8_H32 320
+    VLD_DST_ADD_W8_H32 448
+    VLD_DST_ADD_W8_H32 192
+    VLD_DST_ADD_W8_H32 0
+
+    free_space 512
+.DCT_DCT_8X32_END:
+endfunc
+
+function inv_txfm_add_identity_identity_8x32_8bpc_lsx
+    la.local      t7,       eob_8x32
+    alsl.d        t2,       a1,       a0,     1
+
+.IDENTITY_IDENTITY_EOB_8x32:
+    ld.h          t6,       t7,       0
+    addi.d        t7,       t7,       2
+    vld_x8 a2, 0, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    vxor.v        vr23,     vr23,     vr23
+    vst_x8 a2, 0, 64, vr23, vr23, vr23, vr23, vr23, vr23, vr23, vr23
+
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vsrari.h       \i,       \i,       1
+.endr
+
+    LSX_TRANSPOSE8x8_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                   vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23, \
+                   vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+.irp i, vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+    vsrari.h       \i,       \i,       2
+.endr
+    VLD_DST_ADD_W8 vr16, vr17, vr18, vr19
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,     1
+
+    VLD_DST_ADD_W8 vr20, vr21, vr22, vr23
+    add.d         a0,       a1,       a0
+    alsl.d        t2,       a1,       a0,     1
+
+    addi.d        a2,       a2,       16
+    bge           a3,       t6,       .IDENTITY_IDENTITY_EOB_8x32
+endfunc
+
+.macro def_fn_16x4_base txfm
+functionl inv_txfm_\txfm\()add_16x4_lsx
+    vld_x8 a2, 0, 16, vr0, vr2, vr4, vr6, vr8, vr10, vr12, vr14
+
+.ifc \txfm, identity_
+    li.w          t0,       1697
+    vreplgr2vr.w  vr20,     t0
+.irp i, vr0, vr2, vr4, vr6, vr8, vr10, vr12, vr14
+    inv_identity16_lsx \i, vr20, \i, \i, .8h
+.endr
+
+    vilvh.d       vr1,      vr0,      vr0
+    vilvh.d       vr3,      vr2,      vr2
+    vilvh.d       vr5,      vr4,      vr4
+    vilvh.d       vr7,      vr6,      vr6
+    vilvh.d       vr9,      vr8,      vr8
+    vilvh.d       vr11,     vr10,     vr10
+    vilvh.d       vr13,     vr12,     vr12
+    vilvh.d       vr15,     vr14,     vr14
+.else
+    vilvh.d       vr1,      vr0,      vr0
+    vilvh.d       vr3,      vr2,      vr2
+    vilvh.d       vr5,      vr4,      vr4
+    vilvh.d       vr7,      vr6,      vr6
+    vilvh.d       vr9,      vr8,      vr8
+    vilvh.d       vr11,     vr10,     vr10
+    vilvh.d       vr13,     vr12,     vr12
+    vilvh.d       vr15,     vr14,     vr14
+
+    move          t6,       ra
+    jirl          ra,       t7,       0
+    move          ra,       t6
+.endif
+
+    vxor.v        vr23,     vr23,     vr23
+    vst_x8 a2, 0, 16, vr23, vr23, vr23, vr23, vr23, vr23, vr23, vr23
+
+    LSX_TRANSPOSE8x4_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, vr0, vr1, \
+                       vr2, vr3, vr16, vr17, vr18, vr19, vr20, vr21
+
+    LSX_TRANSPOSE8x4_H vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, vr4, \
+                       vr5, vr6, vr7, vr16, vr17, vr18, vr19, vr20, vr21
+
+    vsrari.h      vr0,      vr0,      1
+    vsrari.h      vr1,      vr1,      1
+    vsrari.h      vr2,      vr2,      1
+    vsrari.h      vr3,      vr3,      1
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vsrari.h      vr8,      vr0,      4
+    vsrari.h      vr9,      vr1,      4
+    vsrari.h      vr10,     vr2,      4
+    vsrari.h      vr11,     vr3,      4
+    vsrari.h      vr0,      vr4,      1
+    vsrari.h      vr1,      vr5,      1
+    vsrari.h      vr2,      vr6,      1
+    vsrari.h      vr3,      vr7,      1
+
+    move          t6,       ra
+    jirl          ra,       t8,       0
+    move          ra,       t6
+
+    vsrari.h      vr16,     vr0,      4
+    vsrari.h      vr17,     vr1,      4
+    vsrari.h      vr18,     vr2,      4
+    vsrari.h      vr19,     vr3,      4
+
+    alsl.d        t2,       a1,       a0,    1
+    VLD_DST_ADD_W16 vr8, vr16, vr9, vr17, vr10, vr18, vr11, vr19
+endfuncl
+.endm
+
+def_fn_16x4_base identity_
+def_fn_16x4_base
+
+.macro fn_16x4 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_16x4_8bpc_lsx
+.ifc \txfm1\()_\txfm2, dct_dct
+    bnez          a3,       .NO_HAS_DCONLY_16x4
+
+    idct_dc 16, 4, 1
+
+    DST_ADD_W16 vr10, vr11, vr12, vr13, vr20, vr20, vr20, \
+                vr20, vr20, vr20, vr20, vr20
+    b             .\txfm1\()_\txfm2\()_16x4_END
+.NO_HAS_DCONLY_16x4:
+.endif
+
+.ifnc \txfm1, identity
+    la.local     t7,    inv_\txfm1\()_4h_x16_lsx
+.endif
+    la.local     t8,    inv_\txfm2\()_8h_x4_lsx
+
+.ifc \txfm1, identity
+    b            inv_txfm_identity_add_16x4_lsx
+.else
+    b            inv_txfm_add_16x4_lsx
+.endif
+.\txfm1\()_\txfm2\()_16x4_END:
+endfunc
+.endm
+
+fn_16x4 dct, dct
+fn_16x4 identity, identity
+fn_16x4 adst, dct
+
+.macro VLD_DST_ADD_W16_H32 in0
+    vld           vr14,     t3,       0
+    vld           vr15,     t3,       16
+    vld           vr16,     t3,       32
+    vld           vr17,     t3,       48
+    vld           vr18,     t5,       0
+    vld           vr19,     t5,       16
+    vld           vr20,     t5,       32
+    vld           vr21,     t5,       48
+    vsrari_h_x8 vr14, vr18, vr15, vr19, vr16, vr20, vr17, vr21, \
+                vr14, vr18, vr15, vr19, vr16, vr20, vr17, vr21, 4
+    VLD_DST_ADD_W16 vr14, vr18, vr15, vr19, vr16, vr20, vr17, vr21
+    alsl.d        a0,       a1,       a0,    2
+    alsl.d        t2,       a1,       t2,    2
+    addi.d        t3,       t3,       64
+    addi.d        t5,       t5,       64
+    vld           vr14,     t3,       0
+    vld           vr15,     t3,       16
+    vld           vr16,     t3,       32
+    vld           vr17,     t3,       48
+    vld           vr18,     t5,       0
+    vld           vr19,     t5,       16
+    vld           vr20,     t5,       32
+    vld           vr21,     t5,       48
+    vsrari_h_x8 vr14, vr18, vr15, vr19, vr16, vr20, vr17, vr21, \
+                vr14, vr18, vr15, vr19, vr16, vr20, vr17, vr21, 4
+    VLD_DST_ADD_W16 vr14, vr18, vr15, vr19, vr16, vr20, vr17, vr21
+    alsl.d        a0,       a1,       a0,    2
+    alsl.d        t2,       a1,       t2,    2
+    addi.d        t3,       sp,       \in0
+    addi.d        t5,       sp,       \in0+512
+.endm
+
+function inv_txfm_add_dct_dct_16x32_8bpc_lsx
+    bnez          a3,       .NO_HAS_DCONLY_16x32
+
+    idct_dc 16, 32, 1
+
+    DST_ADD_W16 vr10, vr11, vr12, vr13, vr20, vr20, vr20, \
+                    vr20, vr20, vr20, vr20, vr20
+.rept 7
+    alsl.d        a0,       a1,       a0,     2
+    alsl.d        t2,       a1,       a0,     1
+
+    VLD_DST_ADD_W16 vr20, vr20, vr20, vr20, vr20, vr20, vr20, vr20
+.endr
+    b             .DCT_DCT_16x32_END
+.NO_HAS_DCONLY_16x32:
+    malloc_space 512+512
+
+    addi.d        t3,       sp,       64
+    la.local      t8,       eob_16x32
+
+.DCT_DCT_EOB_16x32:
+    ld.h          t7,       t8,       0
+    addi.d        t8,       t8,       2
+    vld_x16 a2, 0, 64, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vxor.v        vr31,     vr31,     vr31
+.irp i, 0, 64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960
+    vst           vr31,     a2,       \i
+.endr
+
+    li.w          t0,       2896
+    vreplgr2vr.w  vr23,     t0
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+     vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    rect2_lsx   \i, vr23, \i
+.endr
+
+    inv_dct16_lsx .8h
+
+    LSX_TRANSPOSE8x8_H vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+    LSX_TRANSPOSE8x8_H vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                       vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15, \
+                       vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23
+
+.irp i, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+    vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+    vsrari.h       \i,       \i,       1
+.endr
+
+    vst_x8 t3, 0, 16, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+    vst_x8 t3, 512, 16, vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    addi.d        a2,       a2,       16
+    addi.d        t3,       t3,       128
+    bge           a3,       t7,       .DCT_DCT_EOB_16x32
+
+    la.local      t8,       eob_16x32
+    vxor.v        vr31,     vr31,     vr31
+
+    ld.h          t7,       t8,       4
+    bge           a3,       t7,       .DCT_DCT_EOB_16x32_END
+    vst_x8 sp, 64+384, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    vst_x8 sp, 64+896, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    ld.h          t7,       t8,       2
+    bge           a3,       t7,       .DCT_DCT_EOB_16x32_END
+    vst_x8 sp, 64+256, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    vst_x8 sp, 64+768, 16,  vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+    ld.h          t7,       t8,       0
+    bge           a3,       t7,       .DCT_DCT_EOB_16x32_END
+    vst_x8 sp, 64+128, 16, vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+    vst_x8 sp, 64+512+128, 16  vr31, vr31, vr31, vr31, vr31, vr31, vr31, vr31
+
+.DCT_DCT_EOB_16x32_END:
+    addi.d      t7,   sp,    64
+.rept 2
+    vld_x16 t7, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    inv_dct16_lsx .8h
+
+    vst_x16 t7, 0, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr8, vr9, vr10, vr11, vr12, vr13, vr14, vr15
+
+    vld_x16 t7, 16, 32, vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7, \
+            vr19, vr24, vr25, vr26, vr27, vr28, vr29, vr30
+
+    dct_8x32_core_lsx t7, t7, 0, 256, 32, 0, 128, 256, 384, 16, ,
+
+    addi.d        t7,       t7,       512
+.endr
+    alsl.d        t2,       a1,       a0,    1
+    addi.d        t3,       sp,       64
+    addi.d        t5,       sp,       512+64
+
+    VLD_DST_ADD_W16_H32 320
+    VLD_DST_ADD_W16_H32 448
+    VLD_DST_ADD_W16_H32 192
+    VLD_DST_ADD_W16_H32 0
+
+    free_space 512+512
+.DCT_DCT_16x32_END:
+endfunc
+
+.macro xvmulev_xvmaddod_lasx in0, in1, in2, in3, out0, out1
+    xvmulwev.w.h   \out0,    \in0,     \in2
+    xvmulwod.w.h   \out1,    \in0,     \in2
+    xvmaddwev.w.h  \out0,    \in1,     \in3
+    xvmaddwod.w.h  \out1,    \in1,     \in3
+.endm
+
+.macro xvsrari_h_x16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, \
+                     in11, in12, in13, in14, in15, out0, out1, out2, out3, \
+                     out4, out5, out6, out7, out8, out9, out10, out11, out12, \
+                     out13, out14, out15, shift
+    xvsrari.h  \out0,       \in0,     \shift
+    xvsrari.h  \out1,       \in1,     \shift
+    xvsrari.h  \out2,       \in2,     \shift
+    xvsrari.h  \out3,       \in3,     \shift
+    xvsrari.h  \out4,       \in4,     \shift
+    xvsrari.h  \out5,       \in5,     \shift
+    xvsrari.h  \out6,       \in6,     \shift
+    xvsrari.h  \out7,       \in7,     \shift
+    xvsrari.h  \out8,       \in8,     \shift
+    xvsrari.h  \out9,       \in9,     \shift
+    xvsrari.h  \out10,      \in10,    \shift
+    xvsrari.h  \out11,      \in11,    \shift
+    xvsrari.h  \out12,      \in12,    \shift
+    xvsrari.h  \out13,      \in13,    \shift
+    xvsrari.h  \out14,      \in14,    \shift
+    xvsrari.h  \out15,      \in15,    \shift
+.endm
+
+.macro xvpermi_q_x2 in0, in1, in2, in3, out0, out1, out2, out3, tmp0, tmp1
+    xvor.v      \tmp0,      \in0,     \in0
+    xvor.v      \tmp1,      \in1,     \in1
+    xvpermi.q   \out0,      \in2,     0x02
+    xvpermi.q   \out1,      \in3,     0x02
+    xvpermi.q   \out2,      \tmp0,    0x31
+    xvpermi.q   \out3,      \tmp1,    0x31
+.endm
+
+.macro DST_ADD_W16_LASX in0, in1, in2, in3, in4, in5, in6, in7
+    vext2xv.hu.bu xr0,      \in0
+    vext2xv.hu.bu xr1,      \in1
+    vext2xv.hu.bu xr2,      \in2
+    vext2xv.hu.bu xr3,      \in3
+    xvadd.h       xr0,      xr0,      \in4
+    xvadd.h       xr1,      xr1,      \in5
+    xvadd.h       xr2,      xr2,      \in6
+    xvadd.h       xr3,      xr3,      \in7
+    xvssrani.bu.h xr1,      xr0,      0
+    xvssrani.bu.h xr3,      xr2,      0
+    xvpermi.d     xr0,      xr1,      0b11011000
+    xvpermi.d     xr2,      xr3,      0b11011000
+    xvpermi.d     xr1,      xr0,      0b00001110
+    xvpermi.d     xr3,      xr2,      0b00001110
+    vst           vr0,      a0,       0
+    vstx          vr1,      a0,       a1
+    vst           vr2,      t2,       0
+    vstx          vr3,      t2,       a1
+.endm
+
+.macro XVLD_DST_ADD_W16 in0, in1, in2, in3
+    vld           vr0,      a0,       0
+    vldx          vr1,      a0,       a1
+    vld           vr2,      t2,       0
+    vldx          vr3,      t2,       a1
+    DST_ADD_W16_LASX xr0, xr1, xr2, xr3, \in0, \in1, \in2, \in3
+.endm
+
+.macro inv_adst16_lasx
+    la.local      t0,       iadst16_coeffs_h
+
+    xvldrepl.h    xr20,     t0,       0        // 4091
+    xvldrepl.h    xr21,     t0,       2        // 201
+    xvmulev_xvmaddod_lasx xr15, xr0, xr20, xr21, xr16, xr18
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr15, xr0, xr21, xr20, xr17, xr19
+    xvilvl.w      xr15,     xr18,     xr16
+    xvilvl.w      xr0,      xr19,     xr17
+    xvilvh.w      xr18,     xr18,     xr16
+    xvilvh.w      xr19,     xr19,     xr17
+    xvssrarni.h.w xr18,     xr15,     12       // t0
+    xvssrarni.h.w xr19,     xr0,      12       // t1
+
+    xvldrepl.h    xr20,     t0,       4        // 3973
+    xvldrepl.h    xr21,     t0,       6        // 995
+    xvmulev_xvmaddod_lasx xr13, xr2, xr20, xr21, xr16, xr0
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr13, xr2, xr21, xr20, xr17, xr15
+    xvilvl.w      xr13,     xr0,      xr16
+    xvilvl.w      xr2,      xr15,     xr17
+    xvilvh.w      xr0,      xr0,      xr16
+    xvilvh.w      xr15,     xr15,     xr17
+    xvssrarni.h.w xr0,      xr13,     12       // t2
+    xvssrarni.h.w xr15,     xr2,      12       // t3
+
+    xvldrepl.h    xr20,     t0,        8       // 3703
+    xvldrepl.h    xr21,     t0,        10      // 1751
+    xvmulev_xvmaddod_lasx xr11, xr4, xr20, xr21, xr16, xr2
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr11, xr4, xr21, xr20, xr17, xr13
+    xvilvl.w      xr11,     xr2,       xr16
+    xvilvl.w      xr4,      xr13,      xr17
+    xvilvh.w      xr2,      xr2,       xr16
+    xvilvh.w      xr13,     xr13,      xr17
+    xvssrarni.h.w xr2,      xr11,      12       // t4
+    xvssrarni.h.w xr13,     xr4,       12       // t5
+
+    xvldrepl.h    xr20,     t0,        12       // 3290 -> 1645
+    xvldrepl.h    xr21,     t0,        14       // 2440 -> 1220
+    xvmulev_xvmaddod_lasx xr9, xr6, xr20, xr21, xr16, xr4
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr9, xr6, xr21, xr20, xr17, xr11
+    xvilvl.w      xr9,      xr4,       xr16
+    xvilvl.w      xr6,      xr11,      xr17
+    xvilvh.w      xr4,      xr4,       xr16
+    xvilvh.w      xr11,     xr11,      xr17
+    xvssrarni.h.w xr4,      xr9,       12       // t6
+    xvssrarni.h.w xr11,     xr6,       12       // t7
+
+    xvldrepl.h    xr20,     t0,        16       // 2751
+    xvldrepl.h    xr21,     t0,        18       // 3035
+    xvmulev_xvmaddod_lasx xr7, xr8, xr20, xr21, xr16, xr6
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr7, xr8, xr21, xr20, xr17, xr9
+    xvilvl.w      xr7,      xr6,       xr16
+    xvilvl.w      xr8,      xr9,       xr17
+    xvilvh.w      xr6,      xr6,       xr16
+    xvilvh.w      xr9,      xr9,       xr17
+    xvssrarni.h.w xr6,      xr7,       12       // t8
+    xvssrarni.h.w xr9,      xr8,       12       // t9
+
+    xvldrepl.h    xr20,     t0,        20       // 2106
+    xvldrepl.h    xr21,     t0,        22       // 3513
+    xvmulev_xvmaddod_lasx xr5, xr10, xr20, xr21, xr16, xr7
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr5, xr10, xr21, xr20, xr17, xr8
+    xvilvl.w      xr5,      xr7,       xr16
+    xvilvl.w      xr10,     xr8,       xr17
+    xvilvh.w      xr7,      xr7,       xr16
+    xvilvh.w      xr8,      xr8,       xr17
+    xvssrarni.h.w xr7,      xr5,       12       // t10
+    xvssrarni.h.w xr8,      xr10,      12       // t11
+
+    xvldrepl.h    xr20,     t0,        24       // 1380
+    xvldrepl.h    xr21,     t0,        26       // 3857
+    xvmulev_xvmaddod_lasx xr3, xr12, xr20, xr21, xr16, xr5
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr3, xr12, xr21, xr20, xr17, xr10
+    xvilvl.w      xr3,      xr5,       xr16
+    xvilvl.w      xr12,     xr10,      xr17
+    xvilvh.w      xr5,      xr5,       xr16
+    xvilvh.w      xr10,     xr10,      xr17
+    xvssrarni.h.w xr5,      xr3,       12       // t12
+    xvssrarni.h.w xr10,     xr12,      12       // t13
+
+    xvldrepl.h    xr20,     t0,        28       // 601
+    xvldrepl.h    xr21,     t0,        30       // 4052
+    xvmulev_xvmaddod_lasx xr1, xr14, xr20, xr21, xr16, xr3
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr1, xr14, xr21, xr20, xr17, xr12
+    xvilvl.w      xr1,      xr3,       xr16
+    xvilvl.w      xr14,     xr12,      xr17
+    xvilvh.w      xr3,      xr3,       xr16
+    xvilvh.w      xr12,     xr12,      xr17
+    xvssrarni.h.w xr3,      xr1,       12       // t14
+    xvssrarni.h.w xr12,     xr14,      12       // t15
+
+    xvsadd.h      xr1,      xr18,      xr6      // t0a
+    xvssub.h      xr14,     xr18,      xr6      // t8a
+    xvsadd.h      xr16,     xr19,      xr9      // t1a
+    xvssub.h      xr17,     xr19,      xr9      // t9a
+    xvsadd.h      xr6,      xr0,       xr7      // t2a
+    xvssub.h      xr18,     xr0,       xr7      // t10a
+    xvsadd.h      xr9,      xr15,      xr8      // t3a
+    xvssub.h      xr19,     xr15,      xr8      // t11a
+    xvsadd.h      xr0,      xr2,       xr5      // t4a
+    xvssub.h      xr7,      xr2,       xr5      // t12a
+    xvsadd.h      xr8,      xr13,      xr10     // t5a
+    xvssub.h      xr15,     xr13,      xr10     // t13a
+    xvsadd.h      xr2,      xr4,       xr3      // t6a
+    xvssub.h      xr5,      xr4,       xr3      // t14a
+    xvsadd.h      xr10,     xr11,      xr12     // t7a
+    xvssub.h      xr13,     xr11,      xr12     // t15a
+
+    la.local      t0,       idct_coeffs_h
+
+    xvldrepl.h    xr20,     t0,        8        // 799
+    xvldrepl.h    xr21,     t0,        10       // 4017
+    xvmulev_xvmaddod_lasx xr14, xr17, xr21, xr20, xr3, xr11
+    xvneg.h       xr21,     xr21
+    xvmulev_xvmaddod_lasx xr14, xr17, xr20, xr21, xr4, xr12
+    xvilvl.w      xr14,     xr11,      xr3
+    xvilvl.w      xr17,     xr12,      xr4
+    xvilvh.w      xr11,     xr11,      xr3
+    xvilvh.w      xr12,     xr12,      xr4
+    xvssrarni.h.w xr11,     xr14,      12       // t8
+    xvssrarni.h.w xr12,     xr17,      12       // t9
+
+    xvneg.h       xr21,     xr21
+    xvmulev_xvmaddod_lasx xr15, xr7, xr20, xr21, xr3, xr14
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr15, xr7, xr21, xr20, xr4, xr17
+    xvilvl.w      xr15,     xr14,      xr3
+    xvilvl.w      xr7,      xr17,      xr4
+    xvilvh.w      xr14,     xr14,      xr3
+    xvilvh.w      xr17,     xr17,      xr4
+    xvssrarni.h.w xr14,     xr15,      12       // t13
+    xvssrarni.h.w xr17,     xr7,       12       // t12
+
+    xvldrepl.h    xr20,     t0,        12       // 3406
+    xvldrepl.h    xr21,     t0,        14       // 2276
+    xvmulev_xvmaddod_lasx xr18, xr19, xr21, xr20, xr3, xr7
+    xvneg.h       xr21,     xr21
+    xvmulev_xvmaddod_lasx xr18, xr19, xr20, xr21, xr4, xr15
+    xvilvl.w      xr18,     xr7,       xr3
+    xvilvl.w      xr19,     xr15,      xr4
+    xvilvh.w      xr7,      xr7,       xr3
+    xvilvh.w      xr15,     xr15,      xr4
+    xvssrarni.h.w xr7,      xr18,      12       // t10
+    xvssrarni.h.w xr15,     xr19,      12       // t11
+
+    xvneg.h       xr21,     xr21
+    xvmulev_xvmaddod_lasx xr13, xr5, xr20, xr21, xr3, xr18
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr13, xr5, xr21, xr20, xr4, xr19
+    xvilvl.w      xr13,     xr18,      xr3
+    xvilvl.w      xr5,      xr19,      xr4
+    xvilvh.w      xr18,     xr18,      xr3
+    xvilvh.w      xr19,     xr19,      xr4
+    xvssrarni.h.w xr18,     xr13,      12       // t15
+    xvssrarni.h.w xr19,     xr5,       12       // t14
+
+    xvsadd.h      xr5,      xr1,       xr0      // t0
+    xvssub.h      xr13,     xr1,       xr0      // t4
+    xvsadd.h      xr3,      xr16,      xr8      // t1
+    xvssub.h      xr4,      xr16,      xr8      // t5
+    xvsadd.h      xr0,      xr6,       xr2      // t2
+    xvssub.h      xr1,      xr6,       xr2      // t6
+    xvsadd.h      xr8,      xr9,       xr10     // t3
+    xvssub.h      xr16,     xr9,       xr10     // t7
+    xvsadd.h      xr2,      xr11,      xr17     // t8a
+    xvssub.h      xr6,      xr11,      xr17     // t12a
+    xvsadd.h      xr9,      xr12,      xr14     // t9a
+    xvssub.h      xr10,     xr12,      xr14     // t13a
+    xvsadd.h      xr11,     xr7,       xr19     // t10a
+    xvssub.h      xr17,     xr7,       xr19     // t14a
+    xvsadd.h      xr12,     xr15,      xr18     // t11a
+    xvssub.h      xr14,     xr15,      xr18     // t15a
+
+    la.local      t0,       idct_coeffs_h
+
+    xvldrepl.h    xr20,     t0,        4        // 1567
+    xvldrepl.h    xr21,     t0,        6        // 3784
+    xvmulev_xvmaddod_lasx xr13, xr4, xr21, xr20, xr7, xr18
+    xvneg.h       xr21,     xr21
+    xvmulev_xvmaddod_lasx xr13, xr4, xr20, xr21, xr15, xr19
+    xvilvl.w      xr13,     xr18,      xr7
+    xvilvl.w      xr4,      xr19,      xr15
+    xvilvh.w      xr18,     xr18,      xr7
+    xvilvh.w      xr19,     xr19,      xr15
+    xvssrarni.h.w xr18,     xr13,      12       // t4a
+    xvssrarni.h.w xr19,     xr4,       12       // t5a
+
+    xvneg.h       xr21,     xr21
+    xvmulev_xvmaddod_lasx xr16, xr1, xr20, xr21, xr7, xr4
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr16, xr1, xr21, xr20, xr15, xr13
+    xvilvl.w      xr16,     xr4,       xr7
+    xvilvl.w      xr1,      xr13,      xr15
+    xvilvh.w      xr4,      xr4,       xr7
+    xvilvh.w      xr13,     xr13,      xr15
+    xvssrarni.h.w xr4,      xr16,      12       // t7a
+    xvssrarni.h.w xr13,     xr1,       12       // t6a
+
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr6, xr10, xr21, xr20, xr7, xr1
+    xvneg.h       xr21,     xr21
+    xvmulev_xvmaddod_lasx xr6, xr10, xr20, xr21, xr15, xr16
+    xvilvl.w      xr6,      xr1,       xr7
+    xvilvl.w      xr10,     xr16,      xr15
+    xvilvh.w      xr1,      xr1,       xr7
+    xvilvh.w      xr16,     xr16,      xr15
+    xvssrarni.h.w xr1,      xr6,       12       // t12
+    xvssrarni.h.w xr16,     xr10,      12       // t13
+
+    xvneg.h       xr21,     xr21
+    xvmulev_xvmaddod_lasx xr14, xr17, xr20, xr21, xr7, xr6
+    xvneg.h       xr20,     xr20
+    xvmulev_xvmaddod_lasx xr14, xr17, xr21, xr20, xr15, xr10
+    xvilvl.w      xr14,     xr6,       xr7
+    xvilvl.w      xr17,     xr10,      xr15
+    xvilvh.w      xr6,      xr6,       xr7
+    xvilvh.w      xr10,     xr10,      xr15
+    xvssrarni.h.w xr6,      xr14,      12       // t15
+    xvssrarni.h.w xr10,     xr17,      12       // t14
+
+    xvsadd.h       xr14,     xr5,       xr0      // out[0]
+    xvssub.h       xr17,     xr5,       xr0      // t2a
+    xvssub.h       xr7,      xr3,       xr8      // t3a
+    xvsadd.h       xr15,     xr3,       xr8      // out[15]
+    xvsllwil.w.h   xr22,     xr15,      0
+    xvexth.w.h     xr15,     xr15
+    xvneg.w        xr22,     xr22
+    xvneg.w        xr15,     xr15
+    xvssrarni.h.w  xr15,     xr22,      0        // out[15]
+    xvssub.h       xr7,      xr3,       xr8      // t3a
+
+    xvsadd.h       xr3,      xr19,      xr4      // out[12]
+    xvssub.h       xr8,      xr19,      xr4      // t7
+    xvssub.h       xr0,      xr18,      xr13     // t6
+    xvsadd.h       xr5,      xr18,      xr13     // out[3]
+    xvsllwil.w.h   xr22,     xr5,       0
+    xvexth.w.h     xr5,      xr5
+    xvneg.w        xr22,     xr22
+    xvneg.w        xr5,      xr5
+    xvssrarni.h.w  xr5,      xr22,      0        // out[3]
+
+    xvsadd.h       xr13,     xr9,       xr12     // out[14]
+    xvssub.h       xr19,     xr9,       xr12     // t11
+    xvssub.h       xr4,      xr2,       xr11     // t10
+    xvsadd.h       xr18,     xr2,       xr11     // out[1]
+    xvsllwil.w.h   xr22,     xr18,      0
+    xvexth.w.h     xr18,     xr18
+    xvneg.w        xr22,     xr22
+    xvneg.w        xr18,     xr18
+    xvssrarni.h.w  xr18,     xr22,      0        // out[1]
+
+    xvsadd.h       xr2,      xr1,       xr10     // out[2]
+    xvssub.h       xr11,     xr1,       xr10     // t14a
+    xvssub.h       xr12,     xr16,      xr6      // t15a
+    xvsadd.h       xr9,      xr16,      xr6      // out[13]
+    xvsllwil.w.h   xr22,     xr9,       0
+    xvexth.w.h     xr9,      xr9
+    xvneg.w        xr22,     xr22
+    xvneg.w        xr9,      xr9
+    xvssrarni.h.w  xr9,      xr22,      0        // out[13]
+
+    xvldrepl.h     xr20,     t0,        0        // 2896
+    xvmulev_xvmaddod_lasx xr17, xr7, xr20, xr20, xr6, xr10
+    xvneg.h        xr21,     xr20
+    xvmulev_xvmaddod_lasx xr17, xr7, xr20, xr21, xr16, xr1
+    xvilvl.w       xr17,     xr10,      xr6
+    xvilvl.w       xr7,      xr1,       xr16
+    xvilvh.w       xr10,     xr10,      xr6
+    xvilvh.w       xr1,      xr1,       xr16
+    xvssrarni.h.w  xr1,      xr7,       12       // out[8]
+    xvsrari.w      xr17,     xr17,      12
+    xvsrari.w      xr10,     xr10,      12
+    xvneg.w        xr17,     xr17
+    xvneg.w        xr10,     xr10
+    xvssrarni.h.w  xr10,     xr17,      0        // out[7]
+
+    xvmulev_xvmaddod_lasx xr0, xr8, xr20, xr21, xr16, xr17
+    xvmulev_xvmaddod_lasx xr0, xr8, xr20, xr20, xr6, xr7
+    xvilvl.w       xr0,      xr17,      xr16
+    xvilvl.w       xr8,      xr7,       xr6
+    xvilvh.w       xr17,     xr17,      xr16
+    xvilvh.w       xr7,      xr7,       xr6
+    xvssrarni.h.w  xr7,      xr8,       12       // out[4]
+    xvsrari.w      xr0,      xr0,       12
+    xvsrari.w      xr17,     xr17,      12
+    xvneg.w        xr0,      xr0
+    xvneg.w        xr17,     xr17
+    xvssrarni.h.w xr17,      xr0,       0        // out[11]
+
+    xvmulev_xvmaddod_lasx xr4, xr19, xr20, xr21, xr16, xr0
+    xvmulev_xvmaddod_lasx xr4, xr19, xr20, xr20, xr6, xr8
+    xvilvl.w       xr4,      xr0,       xr16
+    xvilvl.w       xr19,     xr8,       xr6
+    xvilvh.w       xr0,      xr0,       xr16
+    xvilvh.w       xr8,      xr8,       xr6
+    xvssrarni.h.w  xr8,      xr19,      12       // out[6]
+    xvsrari.w      xr4,      xr4,       12
+    xvsrari.w      xr0,      xr0,       12
+    xvneg.w        xr4,      xr4
+    xvneg.w        xr0,      xr0
+    xvssrarni.h.w  xr0,      xr4,       0        // out[9]
+    xvmulev_xvmaddod_lasx xr11, xr12, xr20, xr20, xr6, xr4
+    xvmulev_xvmaddod_lasx xr11, xr12, xr20, xr21, xr16, xr19
+    xvilvl.w       xr11,     xr4,       xr6
+    xvilvl.w       xr12,     xr19,      xr16
+    xvilvh.w       xr4,      xr4,       xr6
+    xvilvh.w       xr19,     xr19,      xr16
+    xvssrarni.h.w  xr19,     xr12,      12       // out[10]
+    xvsrari.w      xr11,     xr11,      12
+    xvsrari.w      xr4,      xr4,       12
+    xvneg.w        xr11,     xr11
+    xvneg.w        xr4,      xr4
+    xvssrarni.h.w  xr4,      xr11,      0        // out[5]
+.endm
+
+function inv_txfm_add_adst_adst_16x16_8bpc_lasx
+    PUSH_REG
+    xvld_x16 a2, 0, 32, xr0, xr1, xr2, xr3, xr4, xr5, xr6, xr7, \
+             xr8, xr9, xr10, xr11, xr12, xr13, xr14, xr15
+
+    inv_adst16_lasx
+
+    LASX_TRANSPOSE8x8_H xr14, xr18, xr2, xr5, xr7, xr4, xr8, xr10, \
+                        xr14, xr18, xr2, xr5, xr7, xr28, xr6, xr10, \
+                        xr20, xr21, xr22, xr23, xr24, xr25, xr26, xr27
+
+    LASX_TRANSPOSE8x8_H xr1,  xr0,  xr19, xr17, xr3, xr9, xr13, xr15, \
+                        xr29, xr30, xr11, xr17, xr31, xr19, xr16, xr15, \
+                        xr20, xr21, xr22, xr23, xr24, xr25, xr26, xr27
+
+    xvsrari_h_x16 xr14, xr18, xr2, xr5, xr7, xr28, xr6, xr10, \
+                  xr29, xr30, xr11, xr17, xr31, xr19, xr16, xr15, \
+                  xr0, xr1, xr2, xr3, xr4, xr5, xr6, xr7, \
+                  xr8, xr9, xr10, xr11, xr12, xr13, xr14, xr15, 2
+
+    xvpermi_q_x2 xr0, xr1, xr8, xr9, xr0, xr1, xr8, xr9, xr20, xr21
+    xvpermi_q_x2 xr2, xr3, xr10, xr11, xr2, xr3, xr10, xr11, xr20, xr21
+    xvpermi_q_x2 xr4, xr5, xr12, xr13, xr4, xr5, xr12, xr13, xr20, xr21
+    xvpermi_q_x2 xr6, xr7, xr14, xr15, xr6, xr7, xr14, xr15, xr20, xr21
+
+    inv_adst16_lasx
+
+    xvsrari_h_x16 xr14, xr18, xr2,  xr5,  xr7,  xr4, xr8,  xr10, \
+                  xr1,  xr0,  xr19, xr17, xr3,  xr9, xr13, xr15, \
+                  xr14, xr18, xr11, xr5,  xr7,  xr4, xr8,  xr10, \
+                  xr12, xr16, xr19, xr17, xr20, xr9, xr13, xr15, 4
+
+    xvxor.v       xr23,     xr23,     xr23
+.irp i, 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480
+    xvst          xr23,     a2,       \i
+.endr
+    alsl.d        t2,       a1,       a0,    1
+    XVLD_DST_ADD_W16 xr14, xr18, xr11, xr5
+    alsl.d        a0,       a1,       a0,    2
+    alsl.d        t2,       a1,       a0,    1
+    XVLD_DST_ADD_W16 xr7, xr4, xr8, xr10
+    alsl.d        a0,       a1,       a0,    2
+    alsl.d        t2,       a1,       a0,    1
+    XVLD_DST_ADD_W16 xr12, xr16, xr19, xr17
+    alsl.d        a0,       a1,       a0,    2
+    alsl.d        t2,       a1,       a0,    1
+    XVLD_DST_ADD_W16 xr20, xr9, xr13, xr15
+    POP_REG
+endfunc
diff --git a/media/libdav1d/src/src/loongarch/itx.h b/media/libdav1d/src/src/loongarch/itx.h
new file mode 100644
index 0000000000..e0b81f38a6
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/itx.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_ITX_H
+#define DAV1D_SRC_LOONGARCH_ITX_H
+
+#include "src/cpu.h"
+#include "src/itx.h"
+
+decl_itx17_fns( 4,  4, lsx);
+decl_itx16_fns( 4,  8, lsx);
+decl_itx16_fns( 4, 16, lsx);
+decl_itx16_fns( 8,  4, lsx);
+decl_itx16_fns( 8,  8, lsx);
+decl_itx16_fns( 8, 16, lsx);
+decl_itx2_fns ( 8, 32, lsx);
+decl_itx16_fns(16,  8, lsx);
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_16x4, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_identity_identity_16x4, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_dct_16x4, lsx));
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_16x16, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_adst_16x16, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_dct_16x16, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_adst_16x16, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_flipadst_dct_16x16, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_flipadst_16x16, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_flipadst_16x16, lsx));
+decl_itx_fn(BF(dav1d_inv_txfm_add_flipadst_adst_16x16, lsx));
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_16x32, lsx));
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_32x8, lsx));
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_32x16, lsx));
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_32x32, lsx));
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x32, lsx));
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x64, lsx));
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_adst_adst_16x16, lasx));
+
+static ALWAYS_INLINE void itx_dsp_init_loongarch(Dav1dInvTxfmDSPContext *const c, int bpc) {
+#if BITDEPTH == 8
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LSX)) return;
+
+    if (BITDEPTH != 8 ) return;
+
+    assign_itx17_fn( ,  4,  4, lsx);
+    assign_itx16_fn(R,  4,  8, lsx);
+    assign_itx16_fn(R,  4, 16, lsx);
+    assign_itx16_fn(R,  8,  4, lsx);
+    assign_itx16_fn( ,  8,  8, lsx);
+    assign_itx16_fn(R,  8, 16, lsx);
+    assign_itx2_fn (R,  8, 32, lsx);
+    assign_itx16_fn(R, 16,  8, lsx);
+    assign_itx1_fn (R, 64, 32, lsx);
+    assign_itx1_fn ( , 64, 64, lsx);
+
+    c->itxfm_add[RTX_16X4][DCT_DCT] = dav1d_inv_txfm_add_dct_dct_16x4_8bpc_lsx;
+    c->itxfm_add[RTX_16X4][IDTX] = dav1d_inv_txfm_add_identity_identity_16x4_8bpc_lsx;
+    c->itxfm_add[RTX_16X4][DCT_ADST] = dav1d_inv_txfm_add_adst_dct_16x4_8bpc_lsx;
+
+    c->itxfm_add[TX_16X16][DCT_DCT] = dav1d_inv_txfm_add_dct_dct_16x16_8bpc_lsx;
+    c->itxfm_add[TX_16X16][ADST_ADST] = dav1d_inv_txfm_add_adst_adst_16x16_8bpc_lsx;
+    c->itxfm_add[TX_16X16][DCT_ADST] = dav1d_inv_txfm_add_adst_dct_16x16_8bpc_lsx;
+    c->itxfm_add[TX_16X16][ADST_DCT] = dav1d_inv_txfm_add_dct_adst_16x16_8bpc_lsx;
+    c->itxfm_add[TX_16X16][DCT_FLIPADST] = dav1d_inv_txfm_add_flipadst_dct_16x16_8bpc_lsx;
+    c->itxfm_add[TX_16X16][FLIPADST_DCT] = dav1d_inv_txfm_add_dct_flipadst_16x16_8bpc_lsx;
+    c->itxfm_add[TX_16X16][FLIPADST_ADST] = dav1d_inv_txfm_add_adst_flipadst_16x16_8bpc_lsx;
+    c->itxfm_add[TX_16X16][ADST_FLIPADST] = dav1d_inv_txfm_add_flipadst_adst_16x16_8bpc_lsx;
+
+    c->itxfm_add[RTX_16X32][DCT_DCT] = dav1d_inv_txfm_add_dct_dct_16x32_8bpc_lsx;
+
+    c->itxfm_add[RTX_32X8][DCT_DCT] = dav1d_inv_txfm_add_dct_dct_32x8_8bpc_lsx;
+
+    c->itxfm_add[RTX_32X16][DCT_DCT] = dav1d_inv_txfm_add_dct_dct_32x16_8bpc_lsx;
+
+    c->itxfm_add[TX_32X32][DCT_DCT] = dav1d_inv_txfm_add_dct_dct_32x32_8bpc_lsx;
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LASX)) return;
+
+    if (BITDEPTH != 8 ) return;
+
+    c->itxfm_add[TX_16X16][ADST_ADST] = dav1d_inv_txfm_add_adst_adst_16x16_8bpc_lasx;
+
+#endif
+}
+
+#endif /* DAV1D_SRC_LOONGARCH_ITX_H */
diff --git a/media/libdav1d/src/src/loongarch/loongson_asm.S b/media/libdav1d/src/src/loongarch/loongson_asm.S
new file mode 100644
index 0000000000..fe91888a6c
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/loongson_asm.S
@@ -0,0 +1,777 @@
+/*********************************************************************
+ * Copyright (c) 2022 Loongson Technology Corporation Limited
+ * Contributed by Gu Xiwei(guxiwei-hf@loongson.cn)
+ *                Shiyou Yin(yinshiyou-hf@loongson.cn)
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *********************************************************************/
+
+/*
+ * This file is a LoongArch assembly helper file and available under ISC
+ * license. It provides a large number of macros and alias to simplify
+ * writing assembly code, especially for LSX and LASX optimizations.
+ *
+ * Any one can modify it or add new features for his/her own purposes.
+ * Contributing a patch will be appreciated as it might be useful for
+ * others as well. Send patches to loongson contributor mentioned above.
+ *
+ * MAJOR version: Usage changes, incompatible with previous version.
+ * MINOR version: Add new macros/functions, or bug fixes.
+ * MICRO version: Comment changes or implementation changes.
+ */
+
+#define LML_VERSION_MAJOR 0
+#define LML_VERSION_MINOR 4
+#define LML_VERSION_MICRO 0
+
+#define DEFAULT_ALIGN    5
+
+/* Set prefix as needed. */
+#ifndef PRIVATE_PREFIX
+#define PRIVATE_PREFIX dav1d_
+#endif
+
+#define PASTE(a,b) a ## b
+#define CONCAT(a,b) PASTE(a,b)
+
+#ifdef PREFIX
+#define ASM_PREF CONCAT(_,PRIVATE_PREFIX)
+#else
+#define ASM_PREF PRIVATE_PREFIX
+#endif
+
+.macro function name, align=DEFAULT_ALIGN
+.macro endfunc
+    jirl    $r0, $r1, 0x0
+    .size ASM_PREF\name, . - ASM_PREF\name
+    .purgem endfunc
+.endm
+.text ;
+.align \align ;
+.globl ASM_PREF\name ;
+.hidden ASM_PREF\name ;
+.type  ASM_PREF\name, @function ;
+ASM_PREF\name: ;
+.endm
+
+.macro  const name, align=DEFAULT_ALIGN
+    .macro endconst
+    .size  \name, . - \name
+    .purgem endconst
+    .endm
+.section .rodata
+.align   \align
+\name:
+.endm
+
+/*
+ *============================================================================
+ * LoongArch register alias
+ *============================================================================
+ */
+
+#define a0 $a0
+#define a1 $a1
+#define a2 $a2
+#define a3 $a3
+#define a4 $a4
+#define a5 $a5
+#define a6 $a6
+#define a7 $a7
+
+#define t0 $t0
+#define t1 $t1
+#define t2 $t2
+#define t3 $t3
+#define t4 $t4
+#define t5 $t5
+#define t6 $t6
+#define t7 $t7
+#define t8 $t8
+
+#define s0 $s0
+#define s1 $s1
+#define s2 $s2
+#define s3 $s3
+#define s4 $s4
+#define s5 $s5
+#define s6 $s6
+#define s7 $s7
+#define s8 $s8
+
+#define zero $zero
+#define sp   $sp
+#define ra   $ra
+
+#define fa0  $fa0
+#define fa1  $fa1
+#define fa2  $fa2
+#define fa3  $fa3
+#define fa4  $fa4
+#define fa5  $fa5
+#define fa6  $fa6
+#define fa7  $fa7
+#define ft0  $ft0
+#define ft1  $ft1
+#define ft2  $ft2
+#define ft3  $ft3
+#define ft4  $ft4
+#define ft5  $ft5
+#define ft6  $ft6
+#define ft7  $ft7
+#define ft8  $ft8
+#define ft9  $ft9
+#define ft10 $ft10
+#define ft11 $ft11
+#define ft12 $ft12
+#define ft13 $ft13
+#define ft14 $ft14
+#define ft15 $ft15
+#define fs0  $fs0
+#define fs1  $fs1
+#define fs2  $fs2
+#define fs3  $fs3
+#define fs4  $fs4
+#define fs5  $fs5
+#define fs6  $fs6
+#define fs7  $fs7
+
+#define f0  $f0
+#define f1  $f1
+#define f2  $f2
+#define f3  $f3
+#define f4  $f4
+#define f5  $f5
+#define f6  $f6
+#define f7  $f7
+#define f8  $f8
+#define f9  $f9
+#define f10 $f10
+#define f11 $f11
+#define f12 $f12
+#define f13 $f13
+#define f14 $f14
+#define f15 $f15
+#define f16 $f16
+#define f17 $f17
+#define f18 $f18
+#define f19 $f19
+#define f20 $f20
+#define f21 $f21
+#define f22 $f22
+#define f23 $f23
+#define f24 $f24
+#define f25 $f25
+#define f26 $f26
+#define f27 $f27
+#define f28 $f28
+#define f29 $f29
+#define f30 $f30
+#define f31 $f31
+
+#define vr0 $vr0
+#define vr1 $vr1
+#define vr2 $vr2
+#define vr3 $vr3
+#define vr4 $vr4
+#define vr5 $vr5
+#define vr6 $vr6
+#define vr7 $vr7
+#define vr8 $vr8
+#define vr9 $vr9
+#define vr10 $vr10
+#define vr11 $vr11
+#define vr12 $vr12
+#define vr13 $vr13
+#define vr14 $vr14
+#define vr15 $vr15
+#define vr16 $vr16
+#define vr17 $vr17
+#define vr18 $vr18
+#define vr19 $vr19
+#define vr20 $vr20
+#define vr21 $vr21
+#define vr22 $vr22
+#define vr23 $vr23
+#define vr24 $vr24
+#define vr25 $vr25
+#define vr26 $vr26
+#define vr27 $vr27
+#define vr28 $vr28
+#define vr29 $vr29
+#define vr30 $vr30
+#define vr31 $vr31
+
+#define xr0 $xr0
+#define xr1 $xr1
+#define xr2 $xr2
+#define xr3 $xr3
+#define xr4 $xr4
+#define xr5 $xr5
+#define xr6 $xr6
+#define xr7 $xr7
+#define xr8 $xr8
+#define xr9 $xr9
+#define xr10 $xr10
+#define xr11 $xr11
+#define xr12 $xr12
+#define xr13 $xr13
+#define xr14 $xr14
+#define xr15 $xr15
+#define xr16 $xr16
+#define xr17 $xr17
+#define xr18 $xr18
+#define xr19 $xr19
+#define xr20 $xr20
+#define xr21 $xr21
+#define xr22 $xr22
+#define xr23 $xr23
+#define xr24 $xr24
+#define xr25 $xr25
+#define xr26 $xr26
+#define xr27 $xr27
+#define xr28 $xr28
+#define xr29 $xr29
+#define xr30 $xr30
+#define xr31 $xr31
+
+/*
+ *============================================================================
+ * LSX/LASX synthesize instructions
+ *============================================================================
+ */
+
+/*
+ * Description : Dot product of byte vector elements
+ * Arguments   : Inputs  - vj, vk
+ *               Outputs - vd
+ *               Return Type - halfword
+ */
+.macro vdp2.h.bu vd, vj, vk
+    vmulwev.h.bu      \vd,    \vj,    \vk
+    vmaddwod.h.bu     \vd,    \vj,    \vk
+.endm
+
+.macro vdp2.h.bu.b vd, vj, vk
+    vmulwev.h.bu.b    \vd,    \vj,    \vk
+    vmaddwod.h.bu.b   \vd,    \vj,    \vk
+.endm
+
+.macro vdp2.w.h vd, vj, vk
+    vmulwev.w.h       \vd,    \vj,    \vk
+    vmaddwod.w.h      \vd,    \vj,    \vk
+.endm
+
+.macro xvdp2.h.bu xd, xj, xk
+    xvmulwev.h.bu    \xd,    \xj,    \xk
+    xvmaddwod.h.bu   \xd,    \xj,    \xk
+.endm
+
+.macro xvdp2.h.bu.b xd, xj, xk
+    xvmulwev.h.bu.b    \xd,  \xj,    \xk
+    xvmaddwod.h.bu.b   \xd,  \xj,    \xk
+.endm
+
+.macro xvdp2.w.h xd, xj, xk
+    xvmulwev.w.h       \xd,  \xj,    \xk
+    xvmaddwod.w.h      \xd,  \xj,    \xk
+.endm
+
+/*
+ * Description : Dot product & addition of halfword vector elements
+ * Arguments   : Inputs  - vj, vk
+ *               Outputs - vd
+ *               Return Type - twice size of input
+ */
+.macro vdp2add.h.bu vd, vj, vk
+    vmaddwev.h.bu     \vd,    \vj,    \vk
+    vmaddwod.h.bu     \vd,    \vj,    \vk
+.endm
+
+.macro vdp2add.h.bu.b vd, vj, vk
+    vmaddwev.h.bu.b   \vd,    \vj,    \vk
+    vmaddwod.h.bu.b   \vd,    \vj,    \vk
+.endm
+
+.macro vdp2add.w.h vd, vj, vk
+    vmaddwev.w.h      \vd,    \vj,    \vk
+    vmaddwod.w.h      \vd,    \vj,    \vk
+.endm
+
+.macro xvdp2add.h.bu.b xd, xj, xk
+    xvmaddwev.h.bu.b   \xd,  \xj,    \xk
+    xvmaddwod.h.bu.b   \xd,  \xj,    \xk
+.endm
+
+.macro xvdp2add.w.h xd, xj, xk
+    xvmaddwev.w.h      \xd,  \xj,    \xk
+    xvmaddwod.w.h      \xd,  \xj,    \xk
+.endm
+
+/*
+ * Description : Range element vj[i] to vk[i] ~ vj[i]
+ * clip: vj > vk ? vj : vk && vj < va ? vj : va
+ */
+.macro vclip.h  vd,  vj, vk, va
+    vmax.h    \vd,  \vj,   \vk
+    vmin.h    \vd,  \vd,   \va
+.endm
+
+.macro vclip.w  vd,  vj, vk, va
+    vmax.w    \vd,  \vj,   \vk
+    vmin.w    \vd,  \vd,   \va
+.endm
+
+.macro xvclip.h  xd,  xj, xk, xa
+    xvmax.h    \xd,  \xj,   \xk
+    xvmin.h    \xd,  \xd,   \xa
+.endm
+
+.macro xvclip.w  xd,  xj, xk, xa
+    xvmax.w    \xd,  \xj,   \xk
+    xvmin.w    \xd,  \xd,   \xa
+.endm
+
+/*
+ * Description : Range element vj[i] to 0 ~ 255
+ * clip255: vj < 255 ? vj : 255 && vj > 0 ? vj : 0
+ */
+.macro vclip255.h  vd, vj
+    vmaxi.h   \vd,   \vj,  0
+    vsat.hu   \vd,   \vd,  7
+.endm
+
+.macro vclip255.w  vd, vj
+    vmaxi.w   \vd,   \vj,  0
+    vsat.wu   \vd,   \vd,  7
+.endm
+
+.macro xvclip255.h  xd, xj
+    xvmaxi.h   \xd,   \xj,  0
+    xvsat.hu   \xd,   \xd,  7
+.endm
+
+.macro xvclip255.w  xd, xj
+    xvmaxi.w   \xd,   \xj,  0
+    xvsat.wu   \xd,   \xd,  7
+.endm
+
+/*
+ * Description : Store elements of vector
+ * vd : Data vector to be stroed
+ * rk : Address of data storage
+ * ra : Offset of address
+ * si : Index of data in vd
+ */
+.macro vstelmx.b vd, rk, ra, si
+    add.d      \rk,  \rk,  \ra
+    vstelm.b   \vd,  \rk,  0, \si
+.endm
+
+.macro vstelmx.h vd, rk, ra, si
+    add.d      \rk,  \rk,  \ra
+    vstelm.h   \vd,  \rk,  0, \si
+.endm
+
+.macro vstelmx.w vd, rk, ra, si
+    add.d      \rk,  \rk,  \ra
+    vstelm.w   \vd,  \rk,  0, \si
+.endm
+
+.macro vstelmx.d  vd, rk, ra, si
+    add.d      \rk,  \rk,  \ra
+    vstelm.d   \vd,  \rk,  0, \si
+.endm
+
+.macro vmov xd, xj
+    vor.v  \xd,  \xj,  \xj
+.endm
+
+.macro xmov xd, xj
+    xvor.v  \xd,  \xj,  \xj
+.endm
+
+.macro xvstelmx.d  xd, rk, ra, si
+    add.d      \rk, \rk,  \ra
+    xvstelm.d  \xd, \rk,  0, \si
+.endm
+
+/*
+ *============================================================================
+ * LSX/LASX custom macros
+ *============================================================================
+ */
+
+/*
+ * Load 4 float, double, V128, v256 elements with stride.
+ */
+.macro FLDS_LOADX_4 src, stride, stride2, stride3, out0, out1, out2, out3
+    fld.s     \out0,    \src,    0
+    fldx.s    \out1,    \src,    \stride
+    fldx.s    \out2,    \src,    \stride2
+    fldx.s    \out3,    \src,    \stride3
+.endm
+
+.macro FLDD_LOADX_4 src, stride, stride2, stride3, out0, out1, out2, out3
+    fld.d     \out0,    \src,    0
+    fldx.d    \out1,    \src,    \stride
+    fldx.d    \out2,    \src,    \stride2
+    fldx.d    \out3,    \src,    \stride3
+.endm
+
+.macro LSX_LOADX_4 src, stride, stride2, stride3, out0, out1, out2, out3
+    vld     \out0,    \src,    0
+    vldx    \out1,    \src,    \stride
+    vldx    \out2,    \src,    \stride2
+    vldx    \out3,    \src,    \stride3
+.endm
+
+.macro LASX_LOADX_4 src, stride, stride2, stride3, out0, out1, out2, out3
+    xvld    \out0,    \src,    0
+    xvldx   \out1,    \src,    \stride
+    xvldx   \out2,    \src,    \stride2
+    xvldx   \out3,    \src,    \stride3
+.endm
+
+/*
+ * Description : Transpose 4x4 block with half-word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3
+ *               Outputs - out0, out1, out2, out3
+ */
+.macro LSX_TRANSPOSE4x4_H in0, in1, in2, in3, out0, out1, out2, out3, \
+                          tmp0, tmp1
+    vilvl.h   \tmp0,  \in1,   \in0
+    vilvl.h   \tmp1,  \in3,   \in2
+    vilvl.w   \out0,  \tmp1,  \tmp0
+    vilvh.w   \out2,  \tmp1,  \tmp0
+    vilvh.d   \out1,  \out0,  \out0
+    vilvh.d   \out3,  \out0,  \out2
+.endm
+
+/*
+ * Description : Transpose 4x4 block with word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3
+ *               Outputs - out0, out1, out2, out3
+ * Details     :
+ * Example     :
+ *               1, 2, 3, 4            1, 5, 9,13
+ *               5, 6, 7, 8    to      2, 6,10,14
+ *               9,10,11,12  =====>    3, 7,11,15
+ *              13,14,15,16            4, 8,12,16
+ */
+.macro LSX_TRANSPOSE4x4_W in0, in1, in2, in3, out0, out1, out2, out3, \
+                          tmp0, tmp1
+
+    vilvl.w    \tmp0,   \in1,    \in0
+    vilvh.w    \out1,   \in1,    \in0
+    vilvl.w    \tmp1,   \in3,    \in2
+    vilvh.w    \out3,   \in3,    \in2
+
+    vilvl.d    \out0,   \tmp1,   \tmp0
+    vilvl.d    \out2,   \out3,   \out1
+    vilvh.d    \out3,   \out3,   \out1
+    vilvh.d    \out1,   \tmp1,   \tmp0
+.endm
+
+/*
+ * Description : Transpose 8x8 block with half-word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3, in4, in5, in6, in7
+ *               Outputs - out0, out1, out2, out3, out4, out5, out6, out7
+ */
+.macro LSX_TRANSPOSE8x8_H in0, in1, in2, in3, in4, in5, in6, in7, out0, out1,   \
+                          out2, out3, out4, out5, out6, out7, tmp0, tmp1, tmp2, \
+                          tmp3, tmp4, tmp5, tmp6, tmp7
+    vilvl.h      \tmp0,    \in6,   \in4
+    vilvl.h      \tmp1,    \in7,   \in5
+    vilvl.h      \tmp2,    \in2,   \in0
+    vilvl.h      \tmp3,    \in3,   \in1
+
+    vilvl.h      \tmp4,    \tmp1,  \tmp0
+    vilvh.h      \tmp5,    \tmp1,  \tmp0
+    vilvl.h      \tmp6,    \tmp3,  \tmp2
+    vilvh.h      \tmp7,    \tmp3,  \tmp2
+
+    vilvh.h      \tmp0,    \in6,   \in4
+    vilvh.h      \tmp1,    \in7,   \in5
+    vilvh.h      \tmp2,    \in2,   \in0
+    vilvh.h      \tmp3,    \in3,   \in1
+
+    vpickev.d    \out0,    \tmp4,  \tmp6
+    vpickod.d    \out1,    \tmp4,  \tmp6
+    vpickev.d    \out2,    \tmp5,  \tmp7
+    vpickod.d    \out3,    \tmp5,  \tmp7
+
+    vilvl.h      \tmp4,    \tmp1,  \tmp0
+    vilvh.h      \tmp5,    \tmp1,  \tmp0
+    vilvl.h      \tmp6,    \tmp3,  \tmp2
+    vilvh.h      \tmp7,    \tmp3,  \tmp2
+
+    vpickev.d    \out4,    \tmp4,  \tmp6
+    vpickod.d    \out5,    \tmp4,  \tmp6
+    vpickev.d    \out6,    \tmp5,  \tmp7
+    vpickod.d    \out7,    \tmp5,  \tmp7
+.endm
+
+/*
+ * Description : Transpose 16x8 block with byte elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3, in4, in5, in6, in7
+ *               Outputs - out0, out1, out2, out3, out4, out5, out6, out7
+ */
+.macro LASX_TRANSPOSE16X8_B in0, in1, in2, in3, in4, in5, in6, in7,        \
+                            in8, in9, in10, in11, in12, in13, in14, in15,  \
+                            out0, out1, out2, out3, out4, out5, out6, out7,\
+                            tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7
+    xvilvl.b   \tmp0,    \in2,     \in0
+    xvilvl.b   \tmp1,    \in3,     \in1
+    xvilvl.b   \tmp2,    \in6,     \in4
+    xvilvl.b   \tmp3,    \in7,     \in5
+    xvilvl.b   \tmp4,    \in10,    \in8
+    xvilvl.b   \tmp5,    \in11,    \in9
+    xvilvl.b   \tmp6,    \in14,    \in12
+    xvilvl.b   \tmp7,    \in15,    \in13
+    xvilvl.b   \out0,    \tmp1,    \tmp0
+    xvilvh.b   \out1,    \tmp1,    \tmp0
+    xvilvl.b   \out2,    \tmp3,    \tmp2
+    xvilvh.b   \out3,    \tmp3,    \tmp2
+    xvilvl.b   \out4,    \tmp5,    \tmp4
+    xvilvh.b   \out5,    \tmp5,    \tmp4
+    xvilvl.b   \out6,    \tmp7,    \tmp6
+    xvilvh.b   \out7,    \tmp7,    \tmp6
+    xvilvl.w   \tmp0,    \out2,    \out0
+    xvilvh.w   \tmp2,    \out2,    \out0
+    xvilvl.w   \tmp4,    \out3,    \out1
+    xvilvh.w   \tmp6,    \out3,    \out1
+    xvilvl.w   \tmp1,    \out6,    \out4
+    xvilvh.w   \tmp3,    \out6,    \out4
+    xvilvl.w   \tmp5,    \out7,    \out5
+    xvilvh.w   \tmp7,    \out7,    \out5
+    xvilvl.d   \out0,    \tmp1,    \tmp0
+    xvilvh.d   \out1,    \tmp1,    \tmp0
+    xvilvl.d   \out2,    \tmp3,    \tmp2
+    xvilvh.d   \out3,    \tmp3,    \tmp2
+    xvilvl.d   \out4,    \tmp5,    \tmp4
+    xvilvh.d   \out5,    \tmp5,    \tmp4
+    xvilvl.d   \out6,    \tmp7,    \tmp6
+    xvilvh.d   \out7,    \tmp7,    \tmp6
+.endm
+
+/*
+ * Description : Transpose 4x4 block with half-word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3
+ *               Outputs - out0, out1, out2, out3
+ */
+.macro LASX_TRANSPOSE4x4_H in0, in1, in2, in3, out0, out1, out2, out3, \
+                           tmp0, tmp1
+    xvilvl.h   \tmp0,  \in1,   \in0
+    xvilvl.h   \tmp1,  \in3,   \in2
+    xvilvl.w   \out0,  \tmp1,  \tmp0
+    xvilvh.w   \out2,  \tmp1,  \tmp0
+    xvilvh.d   \out1,  \out0,  \out0
+    xvilvh.d   \out3,  \out0,  \out2
+.endm
+
+/*
+ * Description : Transpose 4x8 block with half-word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3
+ *               Outputs - out0, out1, out2, out3
+ */
+.macro LASX_TRANSPOSE4x8_H in0, in1, in2, in3, out0, out1, out2, out3, \
+                           tmp0, tmp1
+    xvilvl.h      \tmp0,    \in2,   \in0
+    xvilvl.h      \tmp1,    \in3,   \in1
+    xvilvl.h      \out2,    \tmp1,  \tmp0
+    xvilvh.h      \out3,    \tmp1,  \tmp0
+
+    xvilvl.d      \out0,    \out2,  \out2
+    xvilvh.d      \out1,    \out2,  \out2
+    xvilvl.d      \out2,    \out3,  \out3
+    xvilvh.d      \out3,    \out3,  \out3
+.endm
+
+/*
+ * Description : Transpose 8x8 block with half-word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3, in4, in5, in6, in7
+ *               Outputs - out0, out1, out2, out3, out4, out5, out6, out7
+ */
+.macro LASX_TRANSPOSE8x8_H in0, in1, in2, in3, in4, in5, in6, in7,         \
+                           out0, out1, out2, out3, out4, out5, out6, out7, \
+                           tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7
+    xvilvl.h     \tmp0,   \in6,     \in4
+    xvilvl.h     \tmp1,   \in7,     \in5
+    xvilvl.h     \tmp2,   \in2,     \in0
+    xvilvl.h     \tmp3,   \in3,     \in1
+
+    xvilvl.h     \tmp4,   \tmp1,    \tmp0
+    xvilvh.h     \tmp5,   \tmp1,    \tmp0
+    xvilvl.h     \tmp6,   \tmp3,    \tmp2
+    xvilvh.h     \tmp7,   \tmp3,    \tmp2
+
+    xvilvh.h     \tmp0,   \in6,     \in4
+    xvilvh.h     \tmp1,   \in7,     \in5
+    xvilvh.h     \tmp2,   \in2,     \in0
+    xvilvh.h     \tmp3,   \in3,     \in1
+
+    xvpickev.d   \out0,   \tmp4,    \tmp6
+    xvpickod.d   \out1,   \tmp4,    \tmp6
+    xvpickev.d   \out2,   \tmp5,    \tmp7
+    xvpickod.d   \out3,   \tmp5,    \tmp7
+
+    xvilvl.h     \tmp4,   \tmp1,    \tmp0
+    xvilvh.h     \tmp5,   \tmp1,    \tmp0
+    xvilvl.h     \tmp6,   \tmp3,    \tmp2
+    xvilvh.h     \tmp7,   \tmp3,    \tmp2
+
+    xvpickev.d   \out4,   \tmp4,    \tmp6
+    xvpickod.d   \out5,   \tmp4,    \tmp6
+    xvpickev.d   \out6,   \tmp5,    \tmp7
+    xvpickod.d   \out7,   \tmp5,    \tmp7
+.endm
+
+/*
+ * Description : Transpose 2x4x4 block with half-word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3
+ *               Outputs - out0, out1, out2, out3
+ */
+.macro LASX_TRANSPOSE2x4x4_H in0, in1, in2, in3, out0, out1, out2, out3, \
+                             tmp0, tmp1, tmp2
+    xvilvh.h   \tmp1,    \in0,     \in1
+    xvilvl.h   \out1,    \in0,     \in1
+    xvilvh.h   \tmp0,    \in2,     \in3
+    xvilvl.h   \out3,    \in2,     \in3
+
+    xvilvh.w   \tmp2,    \out3,    \out1
+    xvilvl.w   \out3,    \out3,    \out1
+
+    xvilvl.w   \out2,    \tmp0,    \tmp1
+    xvilvh.w   \tmp1,    \tmp0,    \tmp1
+
+    xvilvh.d   \out0,    \out2,    \out3
+    xvilvl.d   \out2,    \out2,    \out3
+    xvilvh.d   \out1,    \tmp1,    \tmp2
+    xvilvl.d   \out3,    \tmp1,    \tmp2
+.endm
+
+/*
+ * Description : Transpose 4x4 block with word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3
+ *               Outputs - out0, out1, out2, out3
+ * Details     :
+ * Example     :
+ *               1, 2, 3, 4,  1, 2, 3, 4        1,5, 9,13, 1,5, 9,13
+ *               5, 6, 7, 8,  5, 6, 7, 8   to   2,6,10,14, 2,6,10,14
+ *               9,10,11,12,  9,10,11,12 =====> 3,7,11,15, 3,7,11,15
+ *              13,14,15,16, 13,14,15,16        4,8,12,16, 4,8,12,16
+ */
+.macro LASX_TRANSPOSE4x4_W in0, in1, in2, in3, out0, out1, out2, out3, \
+                           tmp0, tmp1
+
+    xvilvl.w    \tmp0,   \in1,    \in0
+    xvilvh.w    \out1,   \in1,    \in0
+    xvilvl.w    \tmp1,   \in3,    \in2
+    xvilvh.w    \out3,   \in3,    \in2
+
+    xvilvl.d    \out0,   \tmp1,   \tmp0
+    xvilvl.d    \out2,   \out3,   \out1
+    xvilvh.d    \out3,   \out3,   \out1
+    xvilvh.d    \out1,   \tmp1,   \tmp0
+.endm
+
+/*
+ * Description : Transpose 8x8 block with word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3, in4, in5, in6, in7
+ *               Outputs - out0, out1, out2, out3, out4, out5, out6,
+ *               _out7
+ * Example     : LASX_TRANSPOSE8x8_W
+ *         in0 : 1,2,3,4,5,6,7,8
+ *         in1 : 2,2,3,4,5,6,7,8
+ *         in2 : 3,2,3,4,5,6,7,8
+ *         in3 : 4,2,3,4,5,6,7,8
+ *         in4 : 5,2,3,4,5,6,7,8
+ *         in5 : 6,2,3,4,5,6,7,8
+ *         in6 : 7,2,3,4,5,6,7,8
+ *         in7 : 8,2,3,4,5,6,7,8
+ *
+ *        out0 : 1,2,3,4,5,6,7,8
+ *        out1 : 2,2,2,2,2,2,2,2
+ *        out2 : 3,3,3,3,3,3,3,3
+ *        out3 : 4,4,4,4,4,4,4,4
+ *        out4 : 5,5,5,5,5,5,5,5
+ *        out5 : 6,6,6,6,6,6,6,6
+ *        out6 : 7,7,7,7,7,7,7,7
+ *        out7 : 8,8,8,8,8,8,8,8
+ */
+.macro LASX_TRANSPOSE8x8_W in0, in1, in2, in3, in4, in5, in6, in7,\
+                           out0, out1, out2, out3, out4, out5, out6, out7,\
+                           tmp0, tmp1, tmp2, tmp3
+    xvilvl.w    \tmp0,   \in2,    \in0
+    xvilvl.w    \tmp1,   \in3,    \in1
+    xvilvh.w    \tmp2,   \in2,    \in0
+    xvilvh.w    \tmp3,   \in3,    \in1
+    xvilvl.w    \out0,   \tmp1,   \tmp0
+    xvilvh.w    \out1,   \tmp1,   \tmp0
+    xvilvl.w    \out2,   \tmp3,   \tmp2
+    xvilvh.w    \out3,   \tmp3,   \tmp2
+
+    xvilvl.w    \tmp0,   \in6,    \in4
+    xvilvl.w    \tmp1,   \in7,    \in5
+    xvilvh.w    \tmp2,   \in6,    \in4
+    xvilvh.w    \tmp3,   \in7,    \in5
+    xvilvl.w    \out4,   \tmp1,   \tmp0
+    xvilvh.w    \out5,   \tmp1,   \tmp0
+    xvilvl.w    \out6,   \tmp3,   \tmp2
+    xvilvh.w    \out7,   \tmp3,   \tmp2
+
+    xmov        \tmp0,   \out0
+    xmov        \tmp1,   \out1
+    xmov        \tmp2,   \out2
+    xmov        \tmp3,   \out3
+    xvpermi.q   \out0,   \out4,   0x02
+    xvpermi.q   \out1,   \out5,   0x02
+    xvpermi.q   \out2,   \out6,   0x02
+    xvpermi.q   \out3,   \out7,   0x02
+    xvpermi.q   \out4,   \tmp0,   0x31
+    xvpermi.q   \out5,   \tmp1,   0x31
+    xvpermi.q   \out6,   \tmp2,   0x31
+    xvpermi.q   \out7,   \tmp3,   0x31
+.endm
+
+/*
+ * Description : Transpose 4x4 block with double-word elements in vectors
+ * Arguments   : Inputs  - in0, in1, in2, in3
+ *               Outputs - out0, out1, out2, out3
+ * Example     : LASX_TRANSPOSE4x4_D
+ *         in0 : 1,2,3,4
+ *         in1 : 1,2,3,4
+ *         in2 : 1,2,3,4
+ *         in3 : 1,2,3,4
+ *
+ *        out0 : 1,1,1,1
+ *        out1 : 2,2,2,2
+ *        out2 : 3,3,3,3
+ *        out3 : 4,4,4,4
+ */
+.macro LASX_TRANSPOSE4x4_D in0, in1, in2, in3, out0, out1, out2, out3, \
+                           tmp0, tmp1
+    xvilvl.d    \tmp0,   \in1,    \in0
+    xvilvh.d    \out1,   \in1,    \in0
+    xvilvh.d    \tmp1,   \in3,    \in2
+    xvilvl.d    \out2,   \in3,    \in2
+
+    xvor.v      \out0,   \tmp0,   \tmp0
+    xvor.v      \out3,   \tmp1,   \tmp1
+
+    xvpermi.q   \out0,   \out2,   0x02
+    xvpermi.q   \out2,   \tmp0,   0x31
+    xvpermi.q   \out3,   \out1,   0x31
+    xvpermi.q   \out1,   \tmp1,   0x02
+.endm
diff --git a/media/libdav1d/src/src/loongarch/loongson_util.S b/media/libdav1d/src/src/loongarch/loongson_util.S
new file mode 100644
index 0000000000..0941cb7703
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/loongson_util.S
@@ -0,0 +1,192 @@
+/******************************************************************************
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef DAV1D_SRC_LOONGSON_UTIL_S
+#define DAV1D_SRC_LOONGSON_UTIL_S
+
+#ifndef DEFAULT_ALIGN
+#define DEFAULT_ALIGN 5
+#endif
+
+//That l means local defines local functions
+.macro functionl name, align=DEFAULT_ALIGN
+.macro endfuncl
+    jirl    $r0, $r1, 0x0
+    .size \name, . - \name
+    .purgem endfuncl
+.endm
+.text ;
+.align \align ;
+.hidden \name ;
+.type \name, @function ;
+\name: ;
+.endm
+
+.macro TRANSPOSE_4x16B in0, in1 ,in2, in3, in4, in5, in6, in7
+    vpackev.b        \in4,  \in1,  \in0
+    vpackod.b        \in5,  \in1,  \in0
+    vpackev.b        \in6,  \in3,  \in2
+    vpackod.b        \in7,  \in3,  \in2
+
+    vpackev.h        \in0,  \in6,  \in4
+    vpackod.h        \in2,  \in6,  \in4
+    vpackev.h        \in1,  \in7,  \in5
+    vpackod.h        \in3,  \in7,  \in5
+.endm
+
+.macro TRANSPOSE_8x16B in0, in1, in2, in3, in4, in5, in6, in7, in8, in9
+    vpackev.b        \in8,  \in1,  \in0
+    vpackod.b        \in9,  \in1,  \in0
+    vpackev.b        \in1,  \in3,  \in2
+    vpackod.b        \in3,  \in3,  \in2
+    vpackev.b        \in0,  \in5,  \in4
+    vpackod.b        \in5,  \in5,  \in4
+    vpackev.b        \in2,  \in7,  \in6
+    vpackod.b        \in7,  \in7,  \in6
+
+    vpackev.h        \in4,  \in2,  \in0
+    vpackod.h        \in2,  \in2,  \in0
+    vpackev.h        \in6,  \in7,  \in5
+    vpackod.h        \in7,  \in7,  \in5
+    vpackev.h        \in5,  \in3,  \in9
+    vpackod.h        \in9,  \in3,  \in9
+    vpackev.h        \in3,  \in1,  \in8
+    vpackod.h        \in8,  \in1,  \in8
+
+    vpackev.w        \in0,  \in4,  \in3
+    vpackod.w        \in4,  \in4,  \in3
+    vpackev.w        \in1,  \in6,  \in5
+    vpackod.w        \in5,  \in6,  \in5
+    vpackod.w        \in6,  \in2,  \in8
+    vpackev.w        \in2,  \in2,  \in8
+    vpackev.w        \in3,  \in7,  \in9
+    vpackod.w        \in7,  \in7,  \in9
+.endm
+
+.macro vld_x8 src, start, stride, in0, in1, in2, in3, in4, in5, in6, in7
+    vld           \in0,     \src,     \start
+    vld           \in1,     \src,     \start+(\stride*1)
+    vld           \in2,     \src,     \start+(\stride*2)
+    vld           \in3,     \src,     \start+(\stride*3)
+    vld           \in4,     \src,     \start+(\stride*4)
+    vld           \in5,     \src,     \start+(\stride*5)
+    vld           \in6,     \src,     \start+(\stride*6)
+    vld           \in7,     \src,     \start+(\stride*7)
+.endm
+
+.macro vst_x8 src, start, stride, in0, in1, in2, in3, in4, in5, in6, in7
+    vst           \in0,     \src,     \start
+    vst           \in1,     \src,     \start+(\stride*1)
+    vst           \in2,     \src,     \start+(\stride*2)
+    vst           \in3,     \src,     \start+(\stride*3)
+    vst           \in4,     \src,     \start+(\stride*4)
+    vst           \in5,     \src,     \start+(\stride*5)
+    vst           \in6,     \src,     \start+(\stride*6)
+    vst           \in7,     \src,     \start+(\stride*7)
+.endm
+
+.macro vld_x16 src, start, stride, in0, in1, in2, in3, in4, in5, in6, in7, \
+               in8, in9, in10, in11, in12, in13, in14, in15
+
+    vld_x8 \src, \start, \stride, \in0, \in1, \in2, \in3, \in4, \in5, \in6, \in7
+
+    vld           \in8,     \src,     \start+(\stride*8)
+    vld           \in9,     \src,     \start+(\stride*9)
+    vld           \in10,    \src,     \start+(\stride*10)
+    vld           \in11,    \src,     \start+(\stride*11)
+    vld           \in12,    \src,     \start+(\stride*12)
+    vld           \in13,    \src,     \start+(\stride*13)
+    vld           \in14,    \src,     \start+(\stride*14)
+    vld           \in15,    \src,     \start+(\stride*15)
+.endm
+
+.macro vst_x16 src, start, stride, in0, in1, in2, in3, in4, in5, in6, in7, \
+               in8, in9, in10, in11, in12, in13, in14, in15
+
+    vst_x8 \src, \start, \stride, \in0, \in1, \in2, \in3, \in4, \in5, \in6, \in7
+
+    vst           \in8,     \src,     \start+(\stride*8)
+    vst           \in9,     \src,     \start+(\stride*9)
+    vst           \in10,    \src,     \start+(\stride*10)
+    vst           \in11,    \src,     \start+(\stride*11)
+    vst           \in12,    \src,     \start+(\stride*12)
+    vst           \in13,    \src,     \start+(\stride*13)
+    vst           \in14,    \src,     \start+(\stride*14)
+    vst           \in15,    \src,     \start+(\stride*15)
+.endm
+
+.macro xvld_x8 src, start, stride, in0, in1, in2, in3, in4, in5, in6, in7
+    xvld           \in0,     \src,     \start
+    xvld           \in1,     \src,     \start+(\stride)
+    xvld           \in2,     \src,     \start+(\stride<<1)
+    xvld           \in3,     \src,     \start+(\stride<<1)+(\stride)
+    xvld           \in4,     \src,     \start+(\stride<<2)
+    xvld           \in5,     \src,     \start+(\stride<<2)+(\stride)
+    xvld           \in6,     \src,     \start+(\stride*6)
+    xvld           \in7,     \src,     \start+(\stride<<3)-(\stride)
+.endm
+
+.macro xvst_x8 src, start, stride, in0, in1, in2, in3, in4, in5, in6, in7
+    xvst           \in0,     \src,     \start
+    xvst           \in1,     \src,     \start+(\stride)
+    xvst           \in2,     \src,     \start+(\stride<<1)
+    xvst           \in3,     \src,     \start+(\stride<<1)+(\stride)
+    xvst           \in4,     \src,     \start+(\stride<<2)
+    xvst           \in5,     \src,     \start+(\stride<<2)+(\stride)
+    xvst           \in6,     \src,     \start+(\stride*6)
+    xvst           \in7,     \src,     \start+(\stride<<3)-(\stride)
+.endm
+
+.macro xvld_x16 src, start, stride, in0, in1, in2, in3, in4, in5, in6, in7, \
+                in8, in9, in10, in11, in12, in13, in14, in15
+    xvld_x8 \src, \start, \stride, \in0, \in1, \in2, \in3, \in4, \in5, \in6, \in7
+
+    xvld           \in8,     \src,     \start+(\stride<<3)
+    xvld           \in9,     \src,     \start+(\stride<<3)+(\stride)
+    xvld           \in10,    \src,     \start+(\stride*10)
+    xvld           \in11,    \src,     \start+(\stride*11)
+    xvld           \in12,    \src,     \start+(\stride*12)
+    xvld           \in13,    \src,     \start+(\stride*13)
+    xvld           \in14,    \src,     \start+(\stride*14)
+    xvld           \in15,    \src,     \start+(\stride<<4)-(\stride)
+.endm
+
+.macro xvst_x16 src, start, stride, in0, in1, in2, in3, in4, in5, in6, in7, \
+               in8, in9, in10, in11, in12, in13, in14, in15
+    xvst_x8 \src, \start, \stride, \in0, \in1, \in2, \in3, \in4, \in5, \in6, \in7
+
+    xvst           \in8,     \src,     \start+(\stride<<3)
+    xvst           \in9,     \src,     \start+(\stride<<3)+(\stride)
+    xvst           \in10,    \src,     \start+(\stride*10)
+    xvst           \in11,    \src,     \start+(\stride*11)
+    xvst           \in12,    \src,     \start+(\stride*12)
+    xvst           \in13,    \src,     \start+(\stride*13)
+    xvst           \in14,    \src,     \start+(\stride*14)
+    xvst           \in15,    \src,     \start+(\stride<<4)-(\stride)
+.endm
+
+#endif /* DAV1D_SRC_LOONGSON_UTIL_S */
diff --git a/media/libdav1d/src/src/loongarch/loopfilter.S b/media/libdav1d/src/src/loongarch/loopfilter.S
new file mode 100644
index 0000000000..3c11d6657c
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/loopfilter.S
@@ -0,0 +1,1215 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/loongarch/loongson_asm.S"
+#include "src/loongarch/loongson_util.S"
+
+// depending on how many pixels need to be stored, returns:
+// t4 = (1 << 0) : 0 pixels
+// t4 = (1 << 4) : inner 4 pixels
+// t4 = (1 << 6) : inner 6 pixels
+// t4 = 0 : all pixels
+.macro FILTER wd
+functionl lpf_16_wd\wd\()_lsx
+    vabsd.bu         vr0,   vr22,  vr23 // abs(p1 - p0)
+    vabsd.bu         vr1,   vr25,  vr24 // abs(q1 - q0)
+    vabsd.bu         vr2,   vr23,  vr24 // abs(p0 - q0)
+    vabsd.bu         vr3,   vr22,  vr25 // abs(p1 - q1)
+.if \wd >= 6
+    vabsd.bu         vr4,   vr21,  vr22 // abs(p2 - p1)
+    vabsd.bu         vr5,   vr26,  vr25 // abs(q2 - q1)
+.endif
+.if \wd >= 8
+    vabsd.bu         vr6,   vr20,  vr21 // abs(p3 - p2)
+    vabsd.bu         vr7,   vr27,  vr26 // abs(q3 - q3)
+.endif
+.if \wd >= 6
+    vmax.bu          vr4,   vr4,   vr5
+.endif
+    vsadd.bu         vr2,   vr2,   vr2  // abs(p0 - q0) * 2
+.if \wd >= 8
+    vmax.bu          vr6,   vr6,   vr7
+.endif
+    vsrli.b          vr3,   vr3,   1    // abs(p1 - q1) >> 1
+.if \wd >= 8
+    vmax.bu          vr4,   vr4,   vr6
+.endif
+.if \wd >= 6
+    vand.v           vr4,   vr4,   vr14
+.endif
+    vmax.bu          vr0,   vr0,   vr1  // max(abs(p1 - p0), abs(q1 - q0))
+    vsadd.bu         vr2,   vr2,   vr3  // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
+.if \wd >= 6
+    vmax.bu          vr4,   vr0,   vr4
+    vsle.bu          vr1,   vr4,   vr11 // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
+.else
+    vsle.bu          vr1,   vr0,   vr11 // max(abs(p1 - p0), abs(q1 - q0)) <= I
+.endif
+    vsle.bu          vr2,   vr2,   vr10 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
+    vand.v           vr1,   vr1,   vr2  // fm
+    vand.v           vr1,   vr1,   vr13 // fm && wd >= 4
+.if \wd >= 6
+    vand.v           vr14,  vr14,  vr1  // fm && wd > 4
+.endif
+.if \wd >= 16
+    vand.v           vr15,  vr15,  vr1  // fm && wd == 16
+.endif
+    vhaddw.qu.du     vr8,   vr1,   vr1
+    vpickve2gr.du    t6,    vr8,   0
+    bnez             t6,    9f          // if (!fm || wd < 4) return;
+    li.w             t4,    1 << 0
+    jirl             zero,  ra,    0x00
+
+9:
+.if \wd >= 6
+    vabsd.bu         vr2,   vr21,  vr23 // abs(p2 - p0)
+    vabsd.bu         vr3,   vr22,  vr23 // abs(p1 - p0)
+    vabsd.bu         vr4,   vr25,  vr24 // abs(q1 - q0)
+    vabsd.bu         vr5,   vr26,  vr24 // abs(q2 - q0)
+.if \wd >= 8
+    vabsd.bu         vr6,   vr20,  vr23 // abs(p3 - p0)
+    vabsd.bu         vr7,   vr27,  vr24 // abs(q3 - q0)
+.endif
+    vmax.bu          vr2,   vr2,   vr3
+    vmax.bu          vr4,   vr4,   vr5
+.if \wd >= 8
+    vmax.bu          vr6,   vr6,   vr7
+.endif
+    vmax.bu          vr2,   vr2,   vr4
+.if \wd >= 8
+    vmax.bu          vr2,   vr2,   vr6
+.endif
+
+.if \wd == 16
+    vabsd.bu         vr3,   vr17,  vr23 // abs(p6 - p0)
+    vabsd.bu         vr4,   vr18,  vr23 // abs(p5 - p0)
+    vabsd.bu         vr5,   vr19,  vr23 // abs(p4 - p0)
+.endif
+    vslei.bu         vr2,   vr2,   1    // flat8in
+.if \wd == 16
+    vabsd.bu         vr6,   vr28,  vr24 // abs(q4 - q0)
+    vabsd.bu         vr7,   vr29,  vr24 // abs(q5 - q0)
+    vabsd.bu         vr8,   vr30,  vr24 // abs(q6 - q0)
+.endif
+    vand.v           vr14,  vr2,   vr14 // flat8in && fm && wd > 4
+    vandn.v          vr1,   vr14,  vr1  // fm && wd >= 4 && !flat8in
+.if \wd == 16
+    vmax.bu          vr3,   vr3,   vr4
+    vmax.bu          vr5,   vr5,   vr6
+.endif
+    vhaddw.qu.du     vr9,   vr1,   vr1
+.if \wd == 16
+    vmax.bu          vr7,   vr7,   vr8
+    vmax.bu          vr3,   vr3,   vr5
+    vmax.bu          vr3,   vr3,   vr7
+    vslei.bu         vr3,   vr3,   1    // flat8out
+.endif
+    vpickve2gr.du    t6,    vr9,   0
+.if \wd == 16
+    vand.v           vr15,  vr15,  vr3  // flat8out && fm && wd == 16
+    vand.v           vr15,  vr15,  vr14 // flat8out && flat8in && fm && wd == 16
+    vandn.v          vr14,  vr15,  vr14 // flat8in && fm && wd >= 4 && !flat8out
+.endif
+    beqz             t6,    1f          // skip wd == 4 case
+.endif
+    vxori.b          vr2,   vr22,  128  // p1 - 128
+    vxori.b          vr3,   vr25,  128  // q1 - 128
+    vslt.bu          vr0,   vr12,  vr0  // hev
+    vssub.b          vr2,   vr2,   vr3  // iclip_diff(p1 - q1)
+    vand.v           vr4,   vr2,   vr0  // if (hev) iclip_diff(p1 - q1)
+    vandn.v          vr0,   vr0,   vr1  // (fm && wd >= 4 && !hev)
+    vxor.v           vr5,   vr5,   vr5
+    vaddi.hu         vr5,   vr5,   3
+    vsubwev.h.bu     vr2,   vr24,  vr23
+    vsubwod.h.bu     vr3,   vr24,  vr23
+    vmul.h           vr2,   vr2,   vr5
+    vmul.h           vr3,   vr3,   vr5
+    vxor.v           vr6,   vr6,   vr6
+    vaddwev.h.b      vr7,   vr4,   vr6
+    vaddwod.h.b      vr6,   vr4,   vr6
+    vadd.h           vr2,   vr2,   vr7
+    vadd.h           vr3,   vr3,   vr6
+    vssrani.b.h      vr2,   vr2,   0
+    vssrani.b.h      vr3,   vr3,   0
+    vilvl.b          vr2,   vr3,   vr2 // f
+    vxor.v           vr6,   vr6,   vr6
+    vaddi.bu         vr5,   vr6,   3
+    vaddi.bu         vr6,   vr6,   4   // 4
+    vsadd.b          vr4,   vr6,   vr2 // imin(f + 4, 127)
+    vsadd.b          vr5,   vr5,   vr2 // imin(f + 3, 127)
+    vsrai.b          vr4,   vr4,   3   // f1
+    vsrai.b          vr5,   vr5,   3   // f2
+    vaddi.bu         vr2,   vr23,  0   // p0
+    vaddi.bu         vr3,   vr24,  0   // q0
+    vxori.b          vr2,   vr2,   128
+    vxori.b          vr3,   vr3,   128
+    vsadd.b          vr2,   vr2,   vr5 // p0 + f2 out p0
+    vssub.b          vr3,   vr3,   vr4 // q0 - f1 out q0
+    vxori.b          vr2,   vr2,   128
+    vxori.b          vr3,   vr3,   128
+    vsrari.b         vr4,   vr4,   1   // (f1 + 1) >> 1
+    vbitsel.v        vr23,  vr23,  vr2,   vr1 // if (fm && wd >= 4)
+    vbitsel.v        vr24,  vr24,  vr3,   vr1 // if (fm && wd >= 4)
+    vaddi.bu         vr2,   vr22,  0   // p1
+    vaddi.bu         vr3,   vr25,  0   // q1
+    vxori.b          vr2,   vr2,   128
+    vxori.b          vr3,   vr3,   128
+    vsadd.b          vr2,   vr2,   vr4 // out p1
+    vssub.b          vr3,   vr3,   vr4 // out q1
+    vxori.b          vr2,   vr2,   128
+    vxori.b          vr3,   vr3,   128
+    vbitsel.v        vr22,  vr22,  vr2,   vr0 // if (fm && wd >= 4 && !hev)
+    vbitsel.v        vr25,  vr25,  vr3,   vr0 // if (fm && wd >= 4 && !hev)
+1:
+
+.if \wd == 6
+    vhaddw.qu.du     vr0,   vr14,  vr14
+    vpickve2gr.du    t6,    vr0,   0
+    beqz             t6,    2f        // skip if there's no flat8in
+
+    vaddwev.h.bu     vr0,   vr21,  vr21
+    vaddwod.h.bu     vr1,   vr21,  vr21 // p2 * 2
+    vaddwev.h.bu     vr2,   vr21,  vr22
+    vaddwod.h.bu     vr3,   vr21,  vr22 // p2 + p1
+    vaddwev.h.bu     vr4,   vr22,  vr23
+    vaddwod.h.bu     vr5,   vr22,  vr23 // p1 + p0
+    vaddwev.h.bu     vr6,   vr23,  vr24
+    vaddwod.h.bu     vr7,   vr23,  vr24 // p0 + q0
+    vadd.h           vr8,   vr0,   vr2
+    vadd.h           vr9,   vr1,   vr3
+    vadd.h           vr10,  vr4,   vr6
+    vadd.h           vr11,  vr5,   vr7
+    vaddwev.h.bu     vr12,  vr24,  vr25
+    vaddwod.h.bu     vr13,  vr24,  vr25 // q0 + q1
+    vadd.h           vr8,   vr8,   vr10
+    vadd.h           vr9,   vr9,   vr11
+    vsub.h           vr12,  vr12,  vr0
+    vsub.h           vr13,  vr13,  vr1
+    vaddwev.h.bu     vr10,  vr25,  vr26
+    vaddwod.h.bu     vr11,  vr25,  vr26 // q1 + q2
+    vssrlrni.bu.h    vr0,   vr8,   3
+    vssrlrni.bu.h    vr1,   vr9,   3
+    vilvl.b          vr0,   vr1,   vr0  // out p1
+
+    vadd.h           vr8,   vr8,   vr12
+    vadd.h           vr9,   vr9,   vr13
+    vsub.h           vr10,  vr10,  vr2
+    vsub.h           vr11,  vr11,  vr3
+    vaddwev.h.bu     vr12,  vr26,  vr26 // q2 + q2
+    vaddwod.h.bu     vr13,  vr26,  vr26
+    vssrlrni.bu.h    vr1,   vr8,   3
+    vssrlrni.bu.h    vr2,   vr9,   3
+    vilvl.b          vr1,   vr2,   vr1  // out p0
+
+    vadd.h           vr8,   vr8,   vr10
+    vadd.h           vr9,   vr9,   vr11
+    vsub.h           vr12,  vr12,  vr4
+    vsub.h           vr13,  vr13,  vr5
+    vssrlrni.bu.h    vr2,   vr8,   3
+    vssrlrni.bu.h    vr3,   vr9,   3
+    vilvl.b          vr2,   vr3,   vr2  // out q0
+
+    vbitsel.v        vr22,  vr22,  vr0,  vr14
+    vadd.h           vr8,   vr8,   vr12
+    vadd.h           vr9,   vr9,   vr13
+    vbitsel.v        vr23,  vr23,  vr1,  vr14
+    vssrlrni.bu.h    vr3,   vr8,   3
+    vssrlrni.bu.h    vr4,   vr9,   3
+    vilvl.b          vr3,   vr4,   vr3
+    vbitsel.v        vr24,  vr24,  vr2,  vr14
+    vbitsel.v        vr25,  vr25,  vr3,  vr14
+.elseif \wd >= 8
+    vhaddw.qu.du     vr0,   vr14,  vr14
+    vpickve2gr.du    t6,    vr0,   0
+.if \wd == 8
+    beqz             t6,    8f  // skip if there's no flat8in
+.else
+    beqz             t6,    2f  // skip if there's no flat8in
+.endif
+
+    vaddwev.h.bu     vr0,   vr20,  vr21
+    vaddwod.h.bu     vr1,   vr20,  vr21 // p3 + p2
+    vaddwev.h.bu     vr2,   vr22,  vr25
+    vaddwod.h.bu     vr3,   vr22,  vr25 // p1 + q1
+    vaddwev.h.bu     vr4,   vr20,  vr22
+    vaddwod.h.bu     vr5,   vr20,  vr22 // p3 + p1
+    vaddwev.h.bu     vr6,   vr23,  vr26
+    vaddwod.h.bu     vr7,   vr23,  vr26 // p0 + q2
+    vadd.h           vr8,   vr0,   vr0
+    vadd.h           vr9,   vr1,   vr1  // 2 * (p3 + p2)
+    vxor.v           vr10,  vr10,  vr10
+    vaddwev.h.bu     vr11,  vr23,  vr10
+    vaddwod.h.bu     vr12,  vr23,  vr10
+    vaddwev.h.bu     vr13,  vr24,  vr10
+    vaddwod.h.bu     vr10,  vr24,  vr10
+    vadd.h           vr8,   vr8,   vr11 // + p0
+    vadd.h           vr9,   vr9,   vr12
+    vadd.h           vr8,   vr8,   vr13 // + q0
+    vadd.h           vr9,   vr9,   vr10
+    vadd.h           vr8,   vr8,   vr4
+    vadd.h           vr9,   vr9,   vr5  // + p3 + p1
+    vsub.h           vr2,   vr2,   vr0
+    vsub.h           vr3,   vr3,   vr1  // p1 + q1 - p3 - p2
+    vsub.h           vr6,   vr6,   vr4
+    vsub.h           vr7,   vr7,   vr5  // p0 + q2 - p3 - p1
+    vssrlrni.bu.h    vr10,  vr8,   3
+    vssrlrni.bu.h    vr11,  vr9,   3
+    vilvl.b          vr10,  vr11,  vr10 // out p2
+
+    vadd.h           vr8,   vr8,   vr2
+    vadd.h           vr9,   vr9,   vr3
+    vaddwev.h.bu     vr0,   vr20,  vr23
+    vaddwod.h.bu     vr1,   vr20,  vr23 // p3 + p0
+    vaddwev.h.bu     vr2,   vr24,  vr27
+    vaddwod.h.bu     vr3,   vr24,  vr27 // q0 + q3
+    vssrlrni.bu.h    vr11,  vr8,   3
+    vssrlrni.bu.h    vr12,  vr9,   3
+    vilvl.b          vr11,  vr12,  vr11 // out p1
+
+    vadd.h           vr8,   vr8,   vr6
+    vadd.h           vr9,   vr9,   vr7
+    vsub.h           vr2,   vr2,   vr0 // q0 + q3 - p3 - p0
+    vsub.h           vr3,   vr3,   vr1
+    vaddwev.h.bu     vr4,   vr21,  vr24 // p2 + q0
+    vaddwod.h.bu     vr5,   vr21,  vr24
+    vaddwev.h.bu     vr6,   vr25,  vr27 // q1 + q3
+    vaddwod.h.bu     vr7,   vr25,  vr27
+    vssrlrni.bu.h    vr12,  vr8,   3
+    vssrlrni.bu.h    vr13,  vr9,   3
+    vilvl.b          vr12,  vr13,  vr12 // out p0
+
+    vadd.h           vr8,   vr8,   vr2
+    vadd.h           vr9,   vr9,   vr3
+    vsub.h           vr6,   vr6,   vr4 // q1 + q3 - p2 - q0
+    vsub.h           vr7,   vr7,   vr5
+    vaddwev.h.bu     vr0,   vr22,  vr25 // p1 + q1
+    vaddwod.h.bu     vr1,   vr22,  vr25
+    vaddwev.h.bu     vr2,   vr26,  vr27
+    vaddwod.h.bu     vr3,   vr26,  vr27 // q2 + q3
+    vssrlrni.bu.h    vr13,  vr8,   3
+    vssrlrni.bu.h    vr4,   vr9,   3
+    vilvl.b          vr13,  vr4,   vr13 // out q0
+
+    vadd.h           vr8,   vr8,   vr6
+    vadd.h           vr9,   vr9,   vr7
+    vsub.h           vr2,   vr2,   vr0  // q2 + q3 - p1 - q1
+    vsub.h           vr3,   vr3,   vr1
+    vssrlrni.bu.h    vr0,   vr8,   3
+    vssrlrni.bu.h    vr1,   vr9,   3
+    vilvl.b          vr0,   vr1,   vr0 // out q1
+
+    vadd.h           vr8,   vr8,   vr2
+    vadd.h           vr9,   vr9,   vr3
+
+    vbitsel.v        vr21,  vr21,  vr10,  vr14
+    vbitsel.v        vr22,  vr22,  vr11,  vr14
+    vbitsel.v        vr23,  vr23,  vr12,  vr14
+    vbitsel.v        vr24,  vr24,  vr13,  vr14
+    vssrlrni.bu.h    vr1,   vr8,   3
+    vssrlrni.bu.h    vr2,   vr9,   3
+    vilvl.b          vr1,   vr2,  vr1 // out q2
+    vbitsel.v        vr25,  vr25,  vr0,   vr14
+    vbitsel.v        vr26,  vr26,  vr1,   vr14
+.endif
+2:
+.if \wd == 16
+    vhaddw.qu.du     vr2,   vr15,  vr15
+    vpickve2gr.du    t6,    vr2,   0
+    bnez             t6,    1f                 // check if flat8out is needed
+    vhaddw.qu.du     vr2,   vr14,  vr14
+    vpickve2gr.du    t6,    vr2,   0
+    beqz             t6,    8f                 // if there was no flat8in, just write the inner 4 pixels
+    b                7f                        // if flat8in was used, write the inner 6 pixels
+1:
+
+    vaddwev.h.bu     vr2,   vr17,  vr17  // p6 + p6
+    vaddwod.h.bu     vr3,   vr17,  vr17
+    vaddwev.h.bu     vr4,   vr17,  vr18
+    vaddwod.h.bu     vr5,   vr17,  vr18  // p6 + p5
+    vaddwev.h.bu     vr6,   vr17,  vr19
+    vaddwod.h.bu     vr7,   vr17,  vr19  // p6 + p4
+    vaddwev.h.bu     vr8,   vr17,  vr20
+    vaddwod.h.bu     vr9,   vr17,  vr20  // p6 + p3
+    vadd.h           vr12,  vr2,   vr4
+    vadd.h           vr13,  vr3,   vr5
+    vadd.h           vr10,  vr6,   vr8
+    vadd.h           vr11,  vr7,   vr9
+    vaddwev.h.bu     vr6,   vr17,  vr21
+    vaddwod.h.bu     vr7,   vr17,  vr21  // p6 + p2
+    vadd.h           vr12,  vr12,  vr10
+    vadd.h           vr13,  vr13,  vr11
+    vaddwev.h.bu     vr8,   vr17,  vr22
+    vaddwod.h.bu     vr9,   vr17,  vr22  // p6 + p1
+    vaddwev.h.bu     vr10,  vr18,  vr23
+    vaddwod.h.bu     vr11,  vr18,  vr23  // p5 + p0
+    vadd.h           vr6,   vr6,   vr8
+    vadd.h           vr7,   vr7,   vr9
+    vaddwev.h.bu     vr8,   vr19,  vr24
+    vaddwod.h.bu     vr9,   vr19,  vr24  // p4 + q0
+    vadd.h           vr12,  vr12,  vr6
+    vadd.h           vr13,  vr13,  vr7
+    vadd.h           vr10,  vr10,  vr8
+    vadd.h           vr11,  vr11,  vr9
+    vaddwev.h.bu     vr6,   vr20,  vr25
+    vaddwod.h.bu     vr7,   vr20,  vr25  // p3 + q1
+    vadd.h           vr12,  vr12,  vr10
+    vadd.h           vr13,  vr13,  vr11
+    vsub.h           vr6,   vr6,   vr2
+    vsub.h           vr7,   vr7,   vr3
+    vaddwev.h.bu     vr2,   vr21,  vr26
+    vaddwod.h.bu     vr3,   vr21,  vr26  // p2 + q2
+    vssrlrni.bu.h    vr0,   vr12,  4
+    vssrlrni.bu.h    vr1,   vr13,  4
+    vilvl.b          vr0,   vr1,   vr0   // out p5
+    vadd.h           vr12,  vr12,  vr6
+    vadd.h           vr13,  vr13,  vr7   // - (p6 + p6) + (p3 + q1)
+    vsub.h           vr2,   vr2,   vr4
+    vsub.h           vr3,   vr3,   vr5
+    vaddwev.h.bu     vr4,   vr22,  vr27
+    vaddwod.h.bu     vr5,   vr22,  vr27  // p1 + q3
+    vaddwev.h.bu     vr6,   vr17,  vr19
+    vaddwod.h.bu     vr7,   vr17,  vr19  // p6 + p4
+    vssrlrni.bu.h    vr1,   vr12,  4
+    vssrlrni.bu.h    vr8,   vr13,  4
+    vilvl.b          vr1,   vr8,   vr1   // out p4
+    vadd.h           vr12,  vr12,  vr2
+    vadd.h           vr13,  vr13,  vr3   // - (p6 + p5) + (p2 + q2)
+    vsub.h           vr4,   vr4,   vr6
+    vsub.h           vr5,   vr5,   vr7
+    vaddwev.h.bu     vr6,   vr23,  vr28
+    vaddwod.h.bu     vr7,   vr23,  vr28  // p0 + q4
+    vaddwev.h.bu     vr8,   vr17,  vr20
+    vaddwod.h.bu     vr9,   vr17,  vr20  // p6 + p3
+    vssrlrni.bu.h    vr2,   vr12,  4
+    vssrlrni.bu.h    vr10,  vr13,  4
+    vilvl.b          vr2,   vr10,  vr2   // out p3
+    vadd.h           vr12,  vr12,  vr4
+    vadd.h           vr13,  vr13,  vr5   // - (p6 + p4) + (p1 + q3)
+    vsub.h           vr6,   vr6,   vr8
+    vsub.h           vr7,   vr7,   vr9
+    vaddwev.h.bu     vr8,   vr24,  vr29
+    vaddwod.h.bu     vr9,   vr24,  vr29  // q0 + q5
+    vaddwev.h.bu     vr4,   vr17,  vr21
+    vaddwod.h.bu     vr5,   vr17,  vr21  // p6 + p2
+    vssrlrni.bu.h    vr3,   vr12,  4
+    vssrlrni.bu.h    vr11,  vr13,  4
+    vilvl.b          vr3,   vr11,  vr3   // out p2
+    vadd.h           vr12,  vr12,  vr6
+    vadd.h           vr13,  vr13,  vr7   // - (p6 + p3) + (p0 + q4)
+    vsub.h           vr8,   vr8,   vr4
+    vsub.h           vr9,   vr9,   vr5
+    vaddwev.h.bu     vr6,   vr25,  vr30
+    vaddwod.h.bu     vr7,   vr25,  vr30  // q1 + q6
+    vaddwev.h.bu     vr10,  vr17,  vr22
+    vaddwod.h.bu     vr11,  vr17,  vr22  // p6 + p1
+    vssrlrni.bu.h    vr4,   vr12,  4
+    vssrlrni.bu.h    vr5,   vr13,  4
+    vilvl.b          vr4,   vr5,   vr4   // out p1
+
+    vadd.h           vr12,  vr12,  vr8
+    vadd.h           vr13,  vr13,  vr9   // - (p6 + p2) + (q0 + q5)
+    vsub.h           vr6,   vr6,   vr10
+    vsub.h           vr7,   vr7,   vr11
+    vaddwev.h.bu     vr8,   vr26,  vr30
+    vaddwod.h.bu     vr9,   vr26,  vr30  // q2 + q6
+    vbitsel.v        vr0,   vr18,  vr0,  vr15  // out p5
+    vaddwev.h.bu     vr10,  vr18,  vr23
+    vaddwod.h.bu     vr11,  vr18,  vr23  // p5 + p0
+    vssrlrni.bu.h    vr5,   vr12,  4
+    vssrlrni.bu.h    vr18,  vr13,  4
+    vilvl.b          vr5,   vr18,  vr5   // out p0
+
+    vadd.h           vr12,  vr12,  vr6
+    vadd.h           vr13,  vr13,  vr7   // - (p6 + p1) + (q1 + q6)
+    vsub.h           vr8,   vr8,   vr10
+    vsub.h           vr9,   vr9,   vr11
+    vaddwev.h.bu     vr10,  vr27,  vr30
+    vaddwod.h.bu     vr11,  vr27,  vr30  // q3 + q6
+    vbitsel.v        vr1,   vr19,  vr1,  vr15  // out p4
+
+    vaddwev.h.bu     vr18,  vr19,  vr24
+    vaddwod.h.bu     vr19,  vr19,  vr24  // p4 + q0
+    vssrlrni.bu.h    vr6,   vr12,  4
+    vssrlrni.bu.h    vr7,   vr13,  4
+    vilvl.b          vr6,   vr7,   vr6   // out q0
+
+    vadd.h           vr12,  vr12,  vr8
+    vadd.h           vr13,  vr13,  vr9   // - (p5 + p0) + (q2 + q6)
+    vsub.h           vr10,  vr10,  vr18
+    vsub.h           vr11,  vr11,  vr19
+    vaddwev.h.bu     vr8,   vr28,  vr30
+    vaddwod.h.bu     vr9,   vr28,  vr30  // q4 + q6
+    vbitsel.v        vr2,   vr20,  vr2,  vr15  // out p3
+    vaddwev.h.bu     vr18,  vr20,  vr25
+    vaddwod.h.bu     vr19,  vr20,  vr25  // p3 + q1
+    vssrlrni.bu.h    vr7,   vr12,  4
+    vssrlrni.bu.h    vr20,  vr13,  4
+    vilvl.b          vr7,   vr20,  vr7   // out q1
+
+    vadd.h           vr12,  vr12,  vr10
+    vadd.h           vr13,  vr13,  vr11  // - (p4 + q0) + (q3 + q6)
+    vsub.h           vr18,  vr8,   vr18
+    vsub.h           vr19,  vr9,   vr19
+    vaddwev.h.bu     vr10,  vr29,  vr30
+    vaddwod.h.bu     vr11,  vr29,  vr30  // q5 + q6
+    vbitsel.v        vr3,   vr21,  vr3,  vr15  // out p2
+    vaddwev.h.bu     vr20,  vr21,  vr26
+    vaddwod.h.bu     vr21,  vr21,  vr26  // p2 + q2
+    vssrlrni.bu.h    vr8,   vr12,  4
+    vssrlrni.bu.h    vr9,   vr13,  4
+    vilvl.b          vr8,   vr9,   vr8   // out q2
+
+    vadd.h           vr12,  vr12,  vr18
+    vadd.h           vr13,  vr13,  vr19  // - (p3 + q1) + (q4 + q6)
+    vsub.h           vr10,  vr10,  vr20
+    vsub.h           vr11,  vr11,  vr21
+    vaddwev.h.bu     vr18,  vr30,  vr30
+    vaddwod.h.bu     vr19,  vr30,  vr30  // q6 + q6
+    vbitsel.v        vr4,   vr22,  vr4,  vr15  // out p1
+    vaddwev.h.bu     vr20,  vr22,  vr27
+    vaddwod.h.bu     vr21,  vr22,  vr27  // p1 + q3
+    vssrlrni.bu.h    vr9,   vr12,  4
+    vssrlrni.bu.h    vr22,  vr13,  4
+    vilvl.b          vr9,   vr22,  vr9   // out q3
+    vadd.h           vr12,  vr12,  vr10
+    vadd.h           vr13,  vr13,  vr11  // - (p2 + q2) + (q5 + q6)
+    vsub.h           vr18,  vr18,  vr20
+    vsub.h           vr19,  vr19,  vr21
+    vbitsel.v        vr5,   vr23,  vr5,  vr15  // out p0
+    vssrlrni.bu.h    vr10,  vr12,  4
+    vssrlrni.bu.h    vr23,  vr13,  4
+    vilvl.b          vr10,  vr23,  vr10  // out q4
+    vadd.h           vr12,  vr12,  vr18
+    vadd.h           vr13,  vr13,  vr19  // - (p1 + q3) + (q6 + q6)
+    vssrlrni.bu.h    vr11,  vr12,  4
+    vssrlrni.bu.h    vr12,  vr13,  4
+    vilvl.b          vr11,  vr12,  vr11  // out q5
+    vbitsel.v        vr6,   vr24,  vr6,  vr15
+    vbitsel.v        vr7,   vr25,  vr7,  vr15
+    vbitsel.v        vr8,   vr26,  vr8,  vr15
+    vbitsel.v        vr9,   vr27,  vr9,  vr15
+    vbitsel.v        vr10,  vr28,  vr10, vr15
+    vbitsel.v        vr11,  vr29,  vr11, vr15
+.endif
+    li.w             t4,    0
+    jirl             zero,  ra,    0x00
+.if \wd == 16
+7:
+    // Return to a shorter epilogue, writing only the inner 6 pixels
+    li.w             t4,    1 << 6
+    jirl             zero,  ra,    0x00
+.endif
+.if \wd >= 8
+8:
+    // Return to a shorter epilogue, writing only the inner 4 pixels
+    li.w             t4,    1 << 4
+    jirl             zero,  ra,    0x00
+.endif
+endfuncl
+.endm
+
+FILTER 16
+FILTER 8
+FILTER 6
+FILTER 4
+
+.macro LPF_16_WD16
+    move             t7,    ra
+    bl               lpf_16_wd16_lsx
+    move             ra,    t7
+    beqz             t4,    1f
+    andi             t5,    t4,    1 << 6
+    bnez             t5,    7f
+    andi             t5,    t4,    1 << 4
+    bnez             t5,    8f
+    jirl             zero,  ra,    0x00
+1:
+.endm
+
+.macro LPF_16_WD8
+    move             t7,    ra
+    bl               lpf_16_wd8_lsx
+    move             ra,    t7
+    beqz             t4,    1f
+    andi             t5,    t4,    1 << 4
+    bnez             t5,    8f
+    jirl             zero,  ra,    0x00
+1:
+.endm
+
+.macro LPF_16_WD6
+    move             t7,    ra
+    bl               lpf_16_wd6_lsx
+    move             ra,    t7
+    beqz             t4,    1f
+    jirl             zero,  ra,    0x00
+1:
+.endm
+
+.macro LPF_16_WD4
+    move             t7,    ra
+    bl               lpf_16_wd4_lsx
+    move             ra,    t7
+    beqz             t4,    1f
+    jirl             zero,  ra,    0x00
+1:
+.endm
+
+functionl lpf_v_4_16_lsx
+    slli.d           t3,    a1,    1
+    sub.d            t3,    a0,    t3
+    vld              vr22,  t3,    0   // p1
+    vldx             vr23,  t3,    a1  // p0
+    vld              vr24,  a0,    0   // q0
+    vldx             vr25,  a0,    a1  // q1
+
+    LPF_16_WD4
+
+    vst              vr22,  t3,    0   // p1
+    vstx             vr23,  t3,    a1  // p0
+    vst              vr24,  a0,    0   // q0
+    vstx             vr25,  a0,    a1  // q1
+endfuncl
+
+functionl lpf_h_4_16_lsx
+    addi.d           t3,    a0,   -2
+    fld.s            f22,   t3,    0
+    fldx.s           f23,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.s            f24,   t3,    0
+    fldx.s           f25,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.s            f17,   t3,    0
+    fldx.s           f18,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.s            f19,   t3,    0
+    fldx.s           f20,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vilvl.w          vr22,  vr17,  vr22
+    vilvl.w          vr23,  vr18,  vr23
+    vilvl.w          vr24,  vr19,  vr24
+    vilvl.w          vr25,  vr20,  vr25
+    fld.s            f17,   t3,    0
+    fldx.s           f18,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.s            f19,   t3,    0
+    fldx.s           f20,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.s            f26,   t3,    0
+    fldx.s           f27,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.s            f28,   t3,    0
+    fldx.s           f29,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vilvl.w          vr17,  vr26,  vr17
+    vilvl.w          vr18,  vr27,  vr18
+    vilvl.w          vr19,  vr28,  vr19
+    vilvl.w          vr20,  vr29,  vr20
+    vilvl.d          vr22,  vr17,  vr22
+    vilvl.d          vr23,  vr18,  vr23
+    vilvl.d          vr24,  vr19,  vr24
+    vilvl.d          vr25,  vr20,  vr25
+    addi.d           a0,    t3,    2
+
+    TRANSPOSE_4x16B  vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    LPF_16_WD4
+
+    slli.d           t3,    a1,    4
+    sub.d            a0,    a0,    t3
+
+    TRANSPOSE_4x16B  vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    addi.d           a0,    a0,   -2
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    0
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    1
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    2
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    3
+    add.d            a0,    a0,    a1
+.endr
+    addi.d           a0,    a0,    2
+endfuncl
+
+functionl lpf_v_6_16_lsx
+    slli.d           t3,    a1,    1
+    sub.d            t3,    a0,    t3
+    sub.d            s0,    t3,    a1
+    vld              vr21,  s0,    0   // p2
+    vldx             vr22,  s0,    a1  // p1
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr23,  s0,    0   // p0
+    vldx             vr24,  s0,    a1  // q0
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr25,  s0,    0   // q1
+    vldx             vr26,  s0,    a1  // q2
+
+    LPF_16_WD6
+
+    vst              vr22,  t3,    0   // p1
+    vstx             vr23,  t3,    a1  // p0
+    vst              vr24,  a0,    0   // q0
+    vstx             vr25,  a0,    a1  // q1
+endfuncl
+
+functionl lpf_h_6_16_lsx
+    addi.d           t3,    a0,   -4
+    fld.d            f20,   t3,    0
+    fldx.d           f21,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f22,   t3,    0
+    fldx.d           f23,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f24,   t3,    0
+    fldx.d           f25,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f26,   t3,    0
+    fldx.d           f27,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f16,   t3,    0
+    fldx.d           f17,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f18,   t3,    0
+    fldx.d           f19,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f28,   t3,    0
+    fldx.d           f29,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f30,   t3,    0
+    fldx.d           f31,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+
+    vilvl.d          vr20,  vr16,  vr20
+    vilvl.d          vr21,  vr17,  vr21
+    vilvl.d          vr22,  vr18,  vr22
+    vilvl.d          vr23,  vr19,  vr23
+    vilvl.d          vr24,  vr28,  vr24
+    vilvl.d          vr25,  vr29,  vr25
+    vilvl.d          vr26,  vr30,  vr26
+    vilvl.d          vr27,  vr31,  vr27
+    addi.d           a0,    t3,    4
+
+    TRANSPOSE_8x16B vr20, vr21, vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    LPF_16_WD6
+
+    slli.d           t3,    a1,    4
+    sub.d            a0,    a0,    t3
+
+    TRANSPOSE_4x16B vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    addi.d           a0,    a0,   -2
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    0
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    1
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    2
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    3
+    add.d            a0,    a0,    a1
+.endr
+    addi.d           a0,    a0,    2
+endfuncl
+
+functionl lpf_v_8_16_lsx
+    slli.d           t3,    a1,    2
+    sub.d            s0,    a0,    t3
+    vld              vr20,  s0,    0   // p3
+    vldx             vr21,  s0,    a1  // p2
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr22,  s0,    0   // p1
+    vldx             vr23,  s0,    a1  // p0
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr24,  s0,    0   // q0
+    vldx             vr25,  s0,    a1  // q1
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr26,  s0,    0   // q2
+    vldx             vr27,  s0,    a1  // q3
+
+    LPF_16_WD8
+
+    sub.d            t3,    a0,    t3
+    add.d            t3,    t3,    a1  // -3
+    vst              vr21,  t3,    0   // p2
+    vstx             vr22,  t3,    a1  // p1
+    alsl.d           t3,    a1,    t3,   1
+    vst              vr23,  t3,    0   // p0
+    vstx             vr24,  t3,    a1  // q0
+    alsl.d           t3,    a1,    t3,   1
+    vst              vr25,  t3,    0   // q1
+    vstx             vr26,  t3,    a1  // q2
+    jirl             zero,  ra,    0x00
+8:
+    slli.d           t3,    a1,    1
+    sub.d            t3,    a0,    t3
+    vst              vr22,  t3,    0   // p1
+    vstx             vr23,  t3,    a1  // p0
+    alsl.d           t3,    a1,    t3,   1
+    vst              vr24,  t3,    0   // q0
+    vstx             vr25,  t3,    a1  // q1
+endfuncl
+
+functionl lpf_h_8_16_lsx
+    addi.d           t3,    a0,   -4
+    fld.d            f20,   t3,    0
+    fldx.d           f21,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f22,   t3,    0
+    fldx.d           f23,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f24,   t3,    0
+    fldx.d           f25,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f26,   t3,    0
+    fldx.d           f27,   t3,    a1
+
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f16,   t3,    0
+    fldx.d           f17,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f18,   t3,    0
+    fldx.d           f19,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f28,   t3,    0
+    fldx.d           f29,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    fld.d            f30,   t3,    0
+    fldx.d           f31,   t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+
+    vilvl.d          vr20,  vr16,  vr20
+    vilvl.d          vr21,  vr17,  vr21
+    vilvl.d          vr22,  vr18,  vr22
+    vilvl.d          vr23,  vr19,  vr23
+    vilvl.d          vr24,  vr28,  vr24
+    vilvl.d          vr25,  vr29,  vr25
+    vilvl.d          vr26,  vr30,  vr26
+    vilvl.d          vr27,  vr31,  vr27
+    addi.d           a0,    t3,    4
+
+    TRANSPOSE_8x16B vr20, vr21, vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    LPF_16_WD8
+
+    slli.d           t3,    a1,    4
+    sub.d            a0,    a0,    t3
+
+    TRANSPOSE_8x16B vr20, vr21, vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    addi.d           a0,    a0,   -4
+.irp i, vr20, vr21, vr22, vr23, vr24, vr25, vr26, vr27
+    vstelm.d         \i,    a0,    0,    0
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr20, vr21, vr22, vr23, vr24, vr25, vr26, vr27
+    vstelm.d         \i,    a0,    0,    1
+    add.d            a0,    a0,    a1
+.endr
+    addi.d           a0,    a0,    4
+    jirl             zero,  ra,    0x00
+
+8:
+    slli.d           t3,    a1,    4
+    sub.d            a0,    a0,    t3
+
+    TRANSPOSE_4x16B vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    addi.d           a0,    a0,   -2
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    0
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    1
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    2
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr22, vr23, vr24, vr25
+    vstelm.w         \i,    a0,    0,    3
+    add.d            a0,    a0,    a1
+.endr
+    addi.d           a0,    a0,    2
+endfuncl
+
+functionl lpf_v_16_16_lsx
+    slli.d           t3,    a1,    3
+    sub.d            s0,    a0,    t3
+    add.d            s0,    s0,    a1
+    vld              vr17,  s0,    0        // p6
+    vldx             vr18,  s0,    a1       // p5
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr19,  s0,    0        // p4
+    vldx             vr20,  s0,    a1       // p3
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr21,  s0,    0        // p2
+    vldx             vr22,  s0,    a1       // p1
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr23,  s0,    0        // p0
+    vldx             vr24,  s0,    a1       // q0
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr25,  s0,    0        // q1
+    vldx             vr26,  s0,    a1       // q2
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr27,  s0,    0        // q3
+    vldx             vr28,  s0,    a1       // q4
+    alsl.d           s0,    a1,    s0,   1
+    vld              vr29,  s0,    0        // q5
+    vldx             vr30,  s0,    a1       // q6
+
+    LPF_16_WD16
+
+    sub.d            s0,    a0,    t3
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr0,   s0,    0        // p5
+    vstx             vr1,   s0,    a1       // p4
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr2,   s0,    0        // p3
+    vstx             vr3,   s0,    a1       // p2
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr4,   s0,    0        // p1
+    vstx             vr5,   s0,    a1       // p0
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr6,   s0,    0        // q0
+    vstx             vr7,   s0,    a1       // q1
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr8,   s0,    0        // q2
+    vstx             vr9,   s0,    a1       // q3
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr10,  s0,    0        // q4
+    vstx             vr11,  s0,    a1       // q5
+    jirl             zero,  ra,    0x00
+7:
+    slli.d           t3,    a1,    1
+    add.d            t3,    t3,    a1
+    sub.d            s0,    a0,    t3
+    vst              vr21,  s0,    0        // p2
+    vstx             vr22,  s0,    a1       // p1
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr23,  s0,    0        // p0
+    vstx             vr24,  s0,    a1       // q0
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr25,  s0,    0        // q1
+    vstx             vr26,  s0,    a1       // q2
+    jirl             zero,  ra,    0x00
+8:
+    slli.d           t3,    a1,    1
+    sub.d            s0,    a0,    t3
+    vst              vr22,  s0,    0        // p1
+    vstx             vr23,  s0,    a1       // p0
+    alsl.d           s0,    a1,    s0,   1
+    vst              vr24,  s0,    0        // q0
+    vstx             vr25,  s0,    a1       // q1
+endfuncl
+
+functionl lpf_h_16_16_lsx
+    addi.d           t3,    a0,   -8
+    vld              vr16,  t3,    0
+    vldx             vr17,  t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vld              vr18,  t3,    0
+    vldx             vr19,  t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vld              vr20,  t3,    0
+    vldx             vr21,  t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vld              vr22,  t3,    0
+    vldx             vr23,  t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vld              vr24,  t3,    0
+    vldx             vr25,  t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vld              vr26,  t3,    0
+    vldx             vr27,  t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vld              vr28,  t3,    0
+    vldx             vr29,  t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+    vld              vr30,  t3,    0
+    vldx             vr31,  t3,    a1
+    alsl.d           t3,    a1,    t3,   1
+.macro SWAPD in0, in1
+    vaddi.bu         vr0,   \in0,  0
+    vilvl.d          \in0,  \in1,  \in0
+    vilvh.d          \in1,  \in1,  vr0
+.endm
+    SWAPD            vr16,  vr24
+    SWAPD            vr17,  vr25
+    SWAPD            vr18,  vr26
+    SWAPD            vr19,  vr27
+    SWAPD            vr20,  vr28
+    SWAPD            vr21,  vr29
+    SWAPD            vr22,  vr30
+    SWAPD            vr23,  vr31
+    addi.d           a0,    t3,    8
+
+    TRANSPOSE_8x16B vr16, vr17, vr18, vr19, vr20, vr21, vr22, vr23, vr0, vr1
+    TRANSPOSE_8x16B vr24, vr25, vr26, vr27, vr28, vr29, vr30, vr31, vr0, vr1
+
+    LPF_16_WD16
+
+    slli.d           t3,    a1,    4
+    sub.d            a0,    a0,    t3
+
+    TRANSPOSE_8x16B vr16, vr17, vr0,  vr1,  vr2,  vr3,  vr4,  vr5,  vr18, vr19
+    TRANSPOSE_8x16B vr6,  vr7,  vr8,  vr9,  vr10, vr11, vr30, vr31, vr18, vr19
+
+    addi.d           t3,    a0,   -8
+.irp i, vr16, vr17, vr0, vr1, vr2, vr3, vr4, vr5
+    vstelm.d         \i,    t3,    0,    0
+    add.d            t3,    t3,    a1
+.endr
+.irp i, vr16, vr17, vr0, vr1, vr2, vr3, vr4, vr5
+    vstelm.d         \i,    t3,    0,    1
+    add.d            t3,    t3,    a1
+.endr
+.irp i, vr6, vr7, vr8, vr9, vr10, vr11, vr30, vr31
+    vstelm.d         \i,    a0,    0,    0
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr6, vr7, vr8, vr9, vr10, vr11, vr30, vr31
+    vstelm.d         \i,    a0,    0,    1
+    add.d            a0,    a0,    a1
+.endr
+    jirl             zero,  ra,    0x00
+
+7:
+    slli.d           t3,    a1,    4
+    sub.d            a0,    a0,    t3
+
+    TRANSPOSE_8x16B vr20, vr21, vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    addi.d           a0,    a0,   -4
+.irp i, vr20, vr21, vr22, vr23, vr24, vr25, vr26, vr27
+    vstelm.d         \i,    a0,    0,    0
+    add.d            a0,    a0,    a1
+.endr
+.irp i, vr20, vr21, vr22, vr23, vr24, vr25, vr26, vr27
+    vstelm.d         \i,    a0,    0,    1
+    add.d            a0,    a0,    a1
+.endr
+    addi.d           a0,    a0,    4
+    jirl             zero,  ra,    0x00
+8:
+
+    slli.d           t3,    a1,    4
+    sub.d            a0,    a0,    t3
+
+    TRANSPOSE_4x16B vr22, vr23, vr24, vr25, vr26, vr27, vr28, vr29
+
+    addi.d           a0,    a0,   -2
+.irp i, 0, 1, 2, 3
+    vstelm.w         vr22,  a0,    0,    \i
+    add.d            a0,    a0,    a1
+    vstelm.w         vr23,  a0,    0,    \i
+    add.d            a0,    a0,    a1
+    vstelm.w         vr24,  a0,    0,    \i
+    add.d            a0,    a0,    a1
+    vstelm.w         vr25,  a0,    0,    \i
+    add.d            a0,    a0,    a1
+.endr
+    addi.d           a0,    a0,    2
+endfuncl
+
+.macro PUSH_REG
+    addi.d           sp,    sp,   -64-8
+    fst.d            f24,   sp,    0
+    fst.d            f25,   sp,    8
+    fst.d            f26,   sp,    16
+    fst.d            f27,   sp,    24
+    fst.d            f28,   sp,    32
+    fst.d            f29,   sp,    40
+    fst.d            f30,   sp,    48
+    fst.d            f31,   sp,    56
+    st.d             s0,    sp,    64
+.endm
+.macro POP_REG
+    fld.d            f24,   sp,    0
+    fld.d            f25,   sp,    8
+    fld.d            f26,   sp,    16
+    fld.d            f27,   sp,    24
+    fld.d            f28,   sp,    32
+    fld.d            f29,   sp,    40
+    fld.d            f30,   sp,    48
+    fld.d            f31,   sp,    56
+    ld.d             s0,    sp,    64
+    addi.d           sp,    sp,    64+8
+.endm
+
+const mask_1248
+.word 1, 2, 4, 8
+endconst
+
+.macro LPF_FUNC DIR, TYPE
+function lpf_\DIR\()_sb_\TYPE\()_8bpc_lsx
+    PUSH_REG
+    move             t8,    ra
+    vld              vr0,   a2,    0 //vmask
+    vpickve2gr.wu    t0,    vr0,   0
+    vpickve2gr.wu    t1,    vr0,   1
+.ifc \TYPE, y
+    vpickve2gr.wu    t2,    vr0,   2
+.endif
+    addi.d           a5,    a5,    128 // Move to sharp part of lut
+.ifc \TYPE, y
+    or               t1,    t1,    t2 // vmask[1] |= vmaks[2]
+.endif
+    slli.d           a4,    a4,    2
+.ifc \DIR, v
+    sub.d            a4,    a3,    a4
+.else
+    addi.d           a3,    a3,   -4
+.endif
+    or               t0,    t0,    t1 // vmaks[0] |= vmask[1]
+1:
+    andi             t3,    t0,    0x0f
+.ifc \DIR, v
+    vld              vr0,   a4,    0 // l[-b4_stride][]
+    addi.d           a4,    a4,    16
+    vld              vr1,   a3,    0 // l[0][]
+    addi.d           a3,    a3,    16
+.else
+    fld.d            f0,    a3,    0
+    fldx.d           f1,    a3,    a4
+    alsl.d           a3,    a4,    a3,   1
+    fld.d            f2,    a3,    0
+    fldx.d           f3,    a3,    a4
+    alsl.d           a3,    a4,    a3,   1
+    vilvl.w          vr1,   vr1,   vr0
+    vilvl.w          vr2,   vr3,   vr2
+    vilvl.d          vr0,   vr2,   vr1
+    vilvh.d          vr1,   vr2,   vr1
+.endif
+    beqz             t3,    7f
+    //l[0][] ? l[0][] : l[-b4_stride][]
+    vseqi.b          vr2,   vr1,    0
+    vbitsel.v        vr1,   vr1,   vr0,   vr2
+    li.w             t3,    0xff
+    vreplgr2vr.w     vr3,   t3
+    vand.v           vr1,   vr1,   vr3
+    vshuf4i.b        vr1,   vr1,   0x00 // L --       1  0  2   0
+    vseqi.w          vr2,   vr1,   0    //            0 -1  0  -1
+    vseqi.w          vr2,   vr2,   0    // L != 0 -- -1  0 -1   0
+    vhaddw.qu.du     vr3,   vr2,   vr2
+    vpickve2gr.du    t4,    vr3,   0
+    beqz             t4,    7f          // if (!L) continue
+    la.local         t3,    mask_1248   // bits x
+    vld              vr16,  t3,    0
+    vreplgr2vr.w     vr13,  t0          // vmask[0]
+    vreplgr2vr.w     vr14,  t1          // vmaks[1]
+    vand.v           vr13,  vr13,  vr16
+    vseqi.w          vr13,  vr13,  0
+    vseqi.w          vr13,  vr13,  0    // if (vmask[0] & x)
+    vand.v           vr13,  vr13,  vr2  // vmask[0] &= L != 0
+    vand.v           vr14,  vr14,  vr16
+    vseqi.w          vr14,  vr14,  0
+    vseqi.w          vr14,  vr14,  0    // if (vmask[1] & x)
+.ifc \TYPE, y
+    vreplgr2vr.w     vr15,  t2          // vmask[2]
+    vand.v           vr15,  vr15,  vr16
+    vseqi.w          vr15,  vr15,  0
+    vseqi.w          vr15,  vr15,  0    // if (vmask[2] & x)
+.endif
+    vldrepl.b        vr5,   a5,    0    // sharp[0]
+    addi.d           t5,    a5,    8
+    vldrepl.b        vr6,   t5,    0    // sharp[1]
+    vsrl.b           vr3,   vr1,   vr5  // L >> sharp[0]
+    vsrli.b          vr12,  vr1,   4    // H
+    vmin.bu          vr3,   vr3,   vr6  // imin(L >> sharp[0], sharp[1])
+    vaddi.bu         vr0,   vr1,   2    // L + 2
+    vmaxi.bu         vr11,  vr3,   1    // imax(imin(), 1) = limit = I
+    vslli.b          vr0,   vr0,   1    // 2*(L + 2)
+    vadd.b           vr10,  vr0,   vr11 // 2*(L + 2) + limit = E
+.ifc \TYPE, y
+    andi             t3,    t2,    0x0f
+    beqz             t3,    2f
+    //wd16
+    bl               lpf_\DIR\()_16_16_lsx
+    b                8f
+2:
+.endif
+    andi             t3,    t1,    0x0f
+    beqz             t3,    3f
+.ifc \TYPE, y
+    // wd8
+    bl               lpf_\DIR\()_8_16_lsx
+.else
+    // wd6
+    bl               lpf_\DIR\()_6_16_lsx
+.endif
+    b                8f
+3:
+    // wd4
+    bl               lpf_\DIR\()_4_16_lsx
+.ifc \DIR, h
+    b                8f
+7:
+    // For dir h, the functions above increment a0.
+    // If the whole function is skipped, increment it here instead.
+    alsl.d           a0,    a1,    a0,    4
+.else
+7:
+.endif
+8:
+    srli.d           t0,    t0,    4
+    srli.d           t1,    t1,    4
+.ifc \TYPE, y
+    srli.d           t2,    t2,    4
+.endif
+.ifc \DIR, v
+    addi.d           a0,    a0,    16
+.else
+    // For dir h, a0 is returned incremented
+.endif
+    bnez             t0,    1b
+    move             ra,    t8
+    POP_REG
+endfunc
+.endm
+
+LPF_FUNC h, y
+LPF_FUNC v, y
+LPF_FUNC h, uv
+LPF_FUNC v, uv
diff --git a/media/libdav1d/src/src/loongarch/loopfilter.h b/media/libdav1d/src/src/loongarch/loopfilter.h
new file mode 100644
index 0000000000..844faf0c30
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/loopfilter.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_LOOPFILTER_H
+#define DAV1D_SRC_LOONGARCH_LOOPFILTER_H
+
+#include "src/cpu.h"
+#include "src/loopfilter.h"
+
+decl_loopfilter_sb_fn(BF(dav1d_lpf_h_sb_y, lsx));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_v_sb_y, lsx));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_h_sb_uv, lsx));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_v_sb_uv, lsx));
+
+static ALWAYS_INLINE void loop_filter_dsp_init_loongarch(Dav1dLoopFilterDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LSX)) return;
+
+#if BITDEPTH == 8
+    c->loop_filter_sb[0][0] = BF(dav1d_lpf_h_sb_y, lsx);
+    c->loop_filter_sb[0][1] = BF(dav1d_lpf_v_sb_y, lsx);
+    c->loop_filter_sb[1][0] = BF(dav1d_lpf_h_sb_uv, lsx);
+    c->loop_filter_sb[1][1] = BF(dav1d_lpf_v_sb_uv, lsx);
+#endif
+}
+
+#endif /* DAV1D_SRC_LOONGARCH_LOOPFILTER_H */
diff --git a/media/libdav1d/src/src/loongarch/looprestoration.S b/media/libdav1d/src/src/loongarch/looprestoration.S
new file mode 100644
index 0000000000..d75f5422cc
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/looprestoration.S
@@ -0,0 +1,1956 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/loongarch/loongson_asm.S"
+
+#define REST_UNIT_STRIDE (400)
+
+.macro MADD_HU_BU in0, in1, out0, out1
+    vsllwil.hu.bu vr12,     \in0,     0
+    vexth.hu.bu   vr13,     \in0
+    vmadd.h       \out0,    vr12,     \in1
+    vmadd.h       \out1,    vr13,     \in1
+.endm
+
+const wiener_shuf
+.byte 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
+endconst
+
+/*
+void wiener_filter_h_lsx(int32_t *hor_ptr,
+                         uint8_t *tmp_ptr,
+                         const int16_t filterh[8],
+                         const int w, const int h)
+*/
+function wiener_filter_h_8bpc_lsx
+    addi.d        sp,       sp,       -40
+    fst.d         f24,      sp,       0
+    fst.d         f25,      sp,       8
+    fst.d         f26,      sp,       16
+    fst.d         f27,      sp,       24
+    fst.d         f28,      sp,       32
+    li.w          t7,       1<<14          // clip_limit
+
+    la.local      t1,       wiener_shuf
+    vld           vr4,      t1,       0
+    vld           vr14,     a2,       0    // filter[0][k]
+    vreplvei.h    vr21,     vr14,     0
+    vreplvei.h    vr22,     vr14,     1
+    vreplvei.h    vr23,     vr14,     2
+    vreplvei.h    vr24,     vr14,     3
+    vreplvei.h    vr25,     vr14,     4
+    vreplvei.h    vr26,     vr14,     5
+    vreplvei.h    vr27,     vr14,     6
+    vreplgr2vr.w  vr0,      t7
+
+.WIENER_FILTER_H_H:
+    addi.w        a4,       a4,       -1    // h
+    addi.w        t0,       a3,       0     // w
+    addi.d        t1,       a1,       0     // tmp_ptr
+    addi.d        t2,       a0,       0     // hor_ptr
+
+.WIENER_FILTER_H_W:
+    addi.w        t0,       t0,       -16
+    vld           vr5,      t1,       0
+    vld           vr13,     t1,       16
+
+    vsubi.bu      vr14,     vr4,      2
+    vsubi.bu      vr15,     vr4,      1
+    vshuf.b       vr6,      vr13,     vr5,     vr14  // 1 ... 8, 9 ... 16
+    vshuf.b       vr7,      vr13,     vr5,     vr15  // 2 ... 9, 10 ... 17
+    vshuf.b       vr8,      vr13,     vr5,     vr4   // 3 ... 10, 11 ... 18
+    vaddi.bu      vr14,     vr4,      1
+    vaddi.bu      vr15,     vr4,      2
+    vshuf.b       vr9,      vr13,     vr5,     vr14  // 4 ... 11, 12 ... 19
+    vshuf.b       vr10,     vr13,     vr5,     vr15  // 5 ... 12, 13 ... 20
+    vaddi.bu      vr14,     vr4,      3
+    vshuf.b       vr11,     vr13,     vr5,     vr14  // 6 ... 13, 14 ... 21
+
+    vsllwil.hu.bu vr15,     vr8,      0    //  3  4  5  6  7  8  9 10
+    vexth.hu.bu   vr16,     vr8            // 11 12 13 14 15 16 17 18
+    vsllwil.wu.hu vr17,     vr15,     7    //  3  4  5  6
+    vexth.wu.hu   vr18,     vr15           //  7  8  9 10
+    vsllwil.wu.hu vr19,     vr16,     7    // 11 12 13 14
+    vexth.wu.hu   vr20,     vr16           // 15 16 17 18
+    vslli.w       vr18,     vr18,     7
+    vslli.w       vr20,     vr20,     7
+    vxor.v        vr15,     vr15,     vr15
+    vxor.v        vr14,     vr14,     vr14
+
+    MADD_HU_BU    vr5,   vr21,  vr14,  vr15
+    MADD_HU_BU    vr6,   vr22,  vr14,  vr15
+    MADD_HU_BU    vr7,   vr23,  vr14,  vr15
+    MADD_HU_BU    vr8,   vr24,  vr14,  vr15
+    MADD_HU_BU    vr9,   vr25,  vr14,  vr15
+    MADD_HU_BU    vr10,  vr26,  vr14,  vr15
+    MADD_HU_BU    vr11,  vr27,  vr14,  vr15
+
+    vsllwil.w.h   vr5,      vr14,     0   //  0  1  2  3
+    vexth.w.h     vr6,      vr14          //  4  5  6  7
+    vsllwil.w.h   vr7,      vr15,     0   //  8  9 10 11
+    vexth.w.h     vr8,      vr15          // 12 13 14 15
+    vadd.w        vr17,     vr17,     vr5
+    vadd.w        vr18,     vr18,     vr6
+    vadd.w        vr19,     vr19,     vr7
+    vadd.w        vr20,     vr20,     vr8
+    vadd.w        vr17,     vr17,     vr0
+    vadd.w        vr18,     vr18,     vr0
+    vadd.w        vr19,     vr19,     vr0
+    vadd.w        vr20,     vr20,     vr0
+
+    vsrli.w       vr1,      vr0,      1
+    vsubi.wu      vr1,      vr1,      1
+    vxor.v        vr3,      vr3,      vr3
+    vsrari.w      vr17,     vr17,     3
+    vsrari.w      vr18,     vr18,     3
+    vsrari.w      vr19,     vr19,     3
+    vsrari.w      vr20,     vr20,     3
+    vclip.w       vr17,     vr17,     vr3,     vr1
+    vclip.w       vr18,     vr18,     vr3,     vr1
+    vclip.w       vr19,     vr19,     vr3,     vr1
+    vclip.w       vr20,     vr20,     vr3,     vr1
+
+    vst           vr17,     t2,       0
+    vst           vr18,     t2,       16
+    vst           vr19,     t2,       32
+    vst           vr20,     t2,       48
+    addi.d        t1,       t1,       16
+    addi.d        t2,       t2,       64
+    blt           zero,     t0,       .WIENER_FILTER_H_W
+
+    addi.d        a1,       a1,       REST_UNIT_STRIDE
+    addi.d        a0,       a0,       (REST_UNIT_STRIDE << 2)
+    bnez          a4,       .WIENER_FILTER_H_H
+
+    fld.d         f24,      sp,       0
+    fld.d         f25,      sp,       8
+    fld.d         f26,      sp,       16
+    fld.d         f27,      sp,       24
+    fld.d         f28,      sp,       32
+    addi.d        sp,       sp,       40
+endfunc
+
+.macro APPLY_FILTER in0, in1, in2
+    alsl.d         t7,      \in0,     \in1,    2
+    vld            vr10,    t7,       0
+    vld            vr11,    t7,       16
+    vld            vr12,    t7,       32
+    vld            vr13,    t7,       48
+    vmadd.w        vr14,    vr10,     \in2
+    vmadd.w        vr15,    vr11,     \in2
+    vmadd.w        vr16,    vr12,     \in2
+    vmadd.w        vr17,    vr13,     \in2
+.endm
+
+.macro wiener_filter_v_8bpc_core_lsx
+    vreplgr2vr.w  vr14,     t6
+    vreplgr2vr.w  vr15,     t6
+    vreplgr2vr.w  vr16,     t6
+    vreplgr2vr.w  vr17,     t6
+
+    addi.w        t7,       t2,       0      // j + index k
+    mul.w         t7,       t7,       t8     // (j + index) * REST_UNIT_STRIDE
+    add.w         t7,       t7,       t4     // (j + index) * REST_UNIT_STRIDE + i
+
+    APPLY_FILTER  t7, a2, vr2
+    APPLY_FILTER  t8, t7, vr3
+    APPLY_FILTER  t8, t7, vr4
+    APPLY_FILTER  t8, t7, vr5
+    APPLY_FILTER  t8, t7, vr6
+    APPLY_FILTER  t8, t7, vr7
+    APPLY_FILTER  t8, t7, vr8
+    vssrarni.hu.w vr15,     vr14,     11
+    vssrarni.hu.w vr17,     vr16,     11
+    vssrlni.bu.h  vr17,     vr15,     0
+.endm
+
+/*
+void wiener_filter_v_lsx(uint8_t *p,
+                         const ptrdiff_t p_stride,
+                         const int32_t *hor,
+                         const int16_t filterv[8],
+                         const int w, const int h)
+*/
+function wiener_filter_v_8bpc_lsx
+    li.w          t6,       -(1 << 18)
+
+    li.w          t8,       REST_UNIT_STRIDE
+    ld.h          t0,       a3,       0
+    ld.h          t1,       a3,       2
+    vreplgr2vr.w  vr2,      t0
+    vreplgr2vr.w  vr3,      t1
+    ld.h          t0,       a3,       4
+    ld.h          t1,       a3,       6
+    vreplgr2vr.w  vr4,      t0
+    vreplgr2vr.w  vr5,      t1
+    ld.h          t0,       a3,       8
+    ld.h          t1,       a3,       10
+    vreplgr2vr.w  vr6,      t0
+    vreplgr2vr.w  vr7,      t1
+    ld.h          t0,       a3,       12
+    vreplgr2vr.w  vr8,      t0
+
+    andi          t1,       a4,       0xf
+    sub.w         t0,       a4,       t1    // w-w%16
+    or            t2,       zero,     zero  // j
+    or            t4,       zero,     zero
+    beqz          t0,       .WIENER_FILTER_V_W_LT16
+
+.WIENER_FILTER_V_H:
+    andi          t1,       a4,       0xf
+    add.d         t3,       zero,     a0     // p
+    or            t4,       zero,     zero   // i
+
+.WIENER_FILTER_V_W:
+
+    wiener_filter_v_8bpc_core_lsx
+
+    mul.w         t5,       t2,       a1   // j * stride
+    add.w         t5,       t5,       t4   // j * stride + i
+    add.d         t3,       a0,       t5
+    addi.w        t4,       t4,       16
+    vst           vr17,     t3,       0
+    bne           t0,       t4,       .WIENER_FILTER_V_W
+
+    beqz          t1,       .WIENER_FILTER_V_W_EQ16
+
+    wiener_filter_v_8bpc_core_lsx
+
+    addi.d        t3,       t3,       16
+    andi          t1,       a4,       0xf
+
+.WIENER_FILTER_V_ST_REM:
+    vstelm.b      vr17,     t3,       0,    0
+    vbsrl.v       vr17,     vr17,     1
+    addi.d        t3,       t3,       1
+    addi.w        t1,       t1,       -1
+    bnez          t1,       .WIENER_FILTER_V_ST_REM
+.WIENER_FILTER_V_W_EQ16:
+    addi.w        t2,       t2,       1
+    blt           t2,       a5,       .WIENER_FILTER_V_H
+    b              .WIENER_FILTER_V_END
+
+.WIENER_FILTER_V_W_LT16:
+    andi          t1,       a4,       0xf
+    add.d         t3,       zero,     a0
+
+    wiener_filter_v_8bpc_core_lsx
+
+    mul.w         t5,       t2,       a1   // j * stride
+    add.d         t3,       a0,       t5
+
+.WIENER_FILTER_V_ST_REM_1:
+    vstelm.b      vr17,     t3,       0,    0
+    vbsrl.v       vr17,     vr17,     1
+    addi.d        t3,       t3,       1
+    addi.w        t1,       t1,       -1
+    bnez          t1,       .WIENER_FILTER_V_ST_REM_1
+
+    addi.w        t2,       t2,       1
+    blt           t2,       a5,       .WIENER_FILTER_V_W_LT16
+
+.WIENER_FILTER_V_END:
+endfunc
+
+/*
+void boxsum3_h(int32_t *sumsq, coef *sum, const pixel *src,
+               const int w, const int h)
+*/
+function boxsum3_h_8bpc_lsx
+    addi.d         a2,      a2,      REST_UNIT_STRIDE
+    li.w           t0,      1
+    addi.w         a3,      a3,      -2
+    addi.w         a4,      a4,      -4
+
+.LBS3_H_H:
+    alsl.d         t1,      t0,      a1,    1     // sum_v    *sum_v = sum + x
+    alsl.d         t2,      t0,      a0,    2     // sumsq_v  *sumsq_v = sumsq + x
+    add.d          t3,      t0,      a2           // s
+    addi.w         t5,      a3,      0
+.LBS3_H_W:
+    vld            vr0,     t3,      0
+    vld            vr1,     t3,      REST_UNIT_STRIDE
+    vld            vr2,     t3,      (REST_UNIT_STRIDE<<1)
+
+    vilvl.b        vr3,     vr1,     vr0
+    vhaddw.hu.bu   vr4,     vr3,     vr3
+    vilvh.b        vr5,     vr1,     vr0
+    vhaddw.hu.bu   vr6,     vr5,     vr5
+    vsllwil.hu.bu  vr7,     vr2,     0
+    vexth.hu.bu    vr8,     vr2
+    // sum_v
+    vadd.h         vr4,     vr4,     vr7
+    vadd.h         vr6,     vr6,     vr8
+    vst            vr4,     t1,      REST_UNIT_STRIDE<<1
+    vst            vr6,     t1,      (REST_UNIT_STRIDE<<1)+16
+    addi.d         t1,      t1,      32
+    // sumsq
+    vmulwev.h.bu   vr9,     vr3,     vr3
+    vmulwod.h.bu   vr10,    vr3,     vr3
+    vmulwev.h.bu   vr11,    vr5,     vr5
+    vmulwod.h.bu   vr12,    vr5,     vr5
+    vaddwev.w.hu   vr13,    vr10,    vr9
+    vaddwod.w.hu   vr14,    vr10,    vr9
+    vaddwev.w.hu   vr15,    vr12,    vr11
+    vaddwod.w.hu   vr16,    vr12,    vr11
+    vmaddwev.w.hu  vr13,    vr7,     vr7
+    vmaddwod.w.hu  vr14,    vr7,     vr7
+    vmaddwev.w.hu  vr15,    vr8,     vr8
+    vmaddwod.w.hu  vr16,    vr8,     vr8
+    vilvl.w        vr9,     vr14,    vr13
+    vilvh.w        vr10,    vr14,    vr13
+    vilvl.w        vr11,    vr16,    vr15
+    vilvh.w        vr12,    vr16,    vr15
+    vst            vr9,     t2,      REST_UNIT_STRIDE<<2
+    vst            vr10,    t2,      (REST_UNIT_STRIDE<<2)+16
+    vst            vr11,    t2,      (REST_UNIT_STRIDE<<2)+32
+    vst            vr12,    t2,      (REST_UNIT_STRIDE<<2)+48
+
+    addi.d         t2,      t2,      64
+    addi.w         t5,      t5,      -16
+    addi.d         t3,      t3,      16
+    blt            zero,    t5,      .LBS3_H_W
+
+    addi.d         a0,      a0,      REST_UNIT_STRIDE<<2
+    addi.d         a1,      a1,      REST_UNIT_STRIDE<<1
+    addi.d         a2,      a2,      REST_UNIT_STRIDE
+    addi.d         a4,      a4,      -1
+    blt            zero,    a4,      .LBS3_H_H
+endfunc
+
+/*
+void boxsum3_v(int32_t *sumsq, coef *sum,
+               const int w, const int h)
+*/
+function boxsum3_v_8bpc_lsx
+    addi.d         a0,      a0,      (REST_UNIT_STRIDE<<2)
+    addi.d         a1,      a1,      (REST_UNIT_STRIDE<<1)
+    addi.w         a3,      a3,      -4
+    addi.w         a2,      a2,      -4
+
+.LBS3_V_H:
+    sub.w          t3,      a2,      zero
+    addi.d         t0,      a0,      4
+    addi.d         t1,      a1,      2
+    addi.d         t5,      a0,      8
+    addi.d         t6,      a1,      4
+
+    vld            vr0,      t1,      0   // a 0 1 2 3 4 5 6 7
+    vld            vr1,      t1,      2   // b 1 2 3 4 5 6 7 8
+    vld            vr2,      t1,      4   // c 2 3 4 5 6 7 8 9
+    vld            vr3,      t0,      0   // a2 0 1 2 3
+    vld            vr4,      t0,      4   // b2 1 2 3 4
+    vld            vr5,      t0,      8   // c2 2 3 4 5
+    vld            vr6,      t0,      16  //    3 4 5 6
+    vld            vr7,      t0,      20  //    4 5 6 7
+    vld            vr8,      t0,      24  //    5 6 7 8
+    vadd.h         vr9,      vr0,     vr1
+    vadd.w         vr10,     vr3,     vr4
+    vadd.w         vr11,     vr6,     vr7
+    vadd.h         vr9,      vr9,     vr2
+    vadd.w         vr10,     vr10,    vr5
+    vadd.w         vr11,     vr11,    vr8
+    vpickve2gr.h   t7,       vr2,     6
+    vpickve2gr.w   t8,       vr8,     2
+    vst            vr9,      t6,      0
+    vst            vr10,     t5,      0
+    vst            vr11,     t5,      16
+
+    addi.d         t1,       t1,      16
+    addi.d         t0,       t0,      32
+    addi.d         t5,       t5,      32
+    addi.d         t6,       t6,      16
+    addi.d         t3,       t3,      -8
+    bge            zero,     t3,      .LBS3_V_H0
+
+.LBS3_V_W8:
+    vld            vr0,      t1,      0   // a 0 1 2 3 4 5 6 7
+    vld            vr1,      t1,      2   // b 1 2 3 4 5 6 7 8
+    vld            vr2,      t1,      4   // c 2 3 4 5 6 7 8 9
+    vld            vr3,      t0,      0   // a2 0 1 2 3
+    vld            vr4,      t0,      4   // b2 1 2 3 4
+    vld            vr5,      t0,      8   // c2 2 3 4 5
+    vld            vr6,      t0,      16  //    3 4 5 6
+    vld            vr7,      t0,      20  //    4 5 6 7
+    vld            vr8,      t0,      24  //    5 6 7 8
+    vinsgr2vr.h    vr0,      t7,      0
+    vinsgr2vr.w    vr3,      t8,      0
+    vpickve2gr.h   t7,       vr2,     6
+    vpickve2gr.w   t8,       vr8,     2
+    vadd.h         vr9,      vr0,     vr1
+    vadd.w         vr10,     vr3,     vr4
+    vadd.w         vr11,     vr6,     vr7
+    vadd.h         vr9,      vr9,     vr2
+    vadd.w         vr10,     vr10,    vr5
+    vadd.w         vr11,     vr11,    vr8
+    vst            vr9,      t6,      0
+    vst            vr10,     t5,      0
+    vst            vr11,     t5,      16
+    addi.d         t3,       t3,      -8
+    addi.d         t1,       t1,      16
+    addi.d         t0,       t0,      32
+    addi.d         t5,       t5,      32
+    addi.d         t6,       t6,      16
+    blt            zero,     t3,      .LBS3_V_W8
+
+.LBS3_V_H0:
+    addi.d         a1,       a1,      REST_UNIT_STRIDE<<1
+    addi.d         a0,       a0,      REST_UNIT_STRIDE<<2
+    addi.w         a3,       a3,      -1
+    bnez           a3,       .LBS3_V_H
+endfunc
+
+/*
+boxsum3_selfguided_filter(int32_t *sumsq, coef *sum,
+                          const int w, const int h,
+                          const unsigned s)
+*/
+function boxsum3_sgf_h_8bpc_lsx
+    addi.d        a0,       a0,        REST_UNIT_STRIDE<<2
+    addi.d        a0,       a0,        12   // AA
+    addi.d        a1,       a1,        REST_UNIT_STRIDE<<1
+    addi.d        a1,       a1,        6    // BB
+    la.local      t8,       dav1d_sgr_x_by_x
+    li.w          t6,       455
+    vreplgr2vr.w  vr20,     t6
+    li.w          t6,       255
+    vreplgr2vr.w  vr22,     t6
+    vaddi.wu      vr21,     vr22,      1  // 256
+    vreplgr2vr.w  vr6,      a4
+    vldi          vr19,     0x809
+    addi.w        a2,       a2,        2  // w + 2
+    addi.w        a3,       a3,        2  // h + 2
+
+.LBS3SGF_H_H:
+    addi.w        t2,       a2,        0
+    addi.d        t0,       a0,        -4
+    addi.d        t1,       a1,        -2
+
+.LBS3SGF_H_W:
+    addi.w        t2,       t2,        -8
+    vld           vr0,      t0,        0   // AA[i]
+    vld           vr1,      t0,        16
+    vld           vr2,      t1,        0   // BB[i]
+
+    vmul.w        vr4,      vr0,       vr19 // a * n
+    vmul.w        vr5,      vr1,       vr19 // a * n
+    vsllwil.w.h   vr9,      vr2,       0
+    vexth.w.h     vr10,     vr2
+    vmsub.w       vr4,      vr9,       vr9   // p
+    vmsub.w       vr5,      vr10,      vr10   // p
+    vmaxi.w       vr4,      vr4,       0
+    vmaxi.w       vr5,      vr5,       0    // p
+    vmul.w        vr4,      vr4,       vr6  // p * s
+    vmul.w        vr5,      vr5,       vr6  // p * s
+    vsrlri.w      vr4,      vr4,       20
+    vsrlri.w      vr5,      vr5,       20   // z
+    vmin.w        vr4,      vr4,       vr22
+    vmin.w        vr5,      vr5,       vr22
+
+    vpickve2gr.w  t6,       vr4,       0
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr7,      t7,        0
+    vpickve2gr.w  t6,       vr4,       1
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr7,      t7,        1
+    vpickve2gr.w  t6,       vr4,       2
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr7,      t7,        2
+    vpickve2gr.w  t6,       vr4,       3
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr7,      t7,        3
+
+    vpickve2gr.w  t6,       vr5,       0
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr8,      t7,        0
+    vpickve2gr.w  t6,       vr5,       1
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr8,      t7,        1
+    vpickve2gr.w  t6,       vr5,       2
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr8,      t7,        2
+    vpickve2gr.w  t6,       vr5,       3
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr8,      t7,        3     // x
+
+    vmul.w        vr9,      vr7,       vr9   // x * BB[i]
+    vmul.w        vr10,     vr8,       vr10
+    vmul.w        vr9,      vr9,       vr20  // x * BB[i] * sgr_one_by_x
+    vmul.w        vr10,     vr10,      vr20
+    vsrlri.w      vr9,      vr9,       12
+    vsrlri.w      vr10,     vr10,      12
+    vsub.w        vr7,      vr21,      vr7
+    vsub.w        vr8,      vr21,      vr8
+    vpickev.h     vr8,      vr8,       vr7
+
+    vst           vr9,      t0,        0
+    vst           vr10,     t0,        16
+    vst           vr8,      t1,        0
+    addi.d        t0,       t0,        32
+    addi.d        t1,       t1,        16
+    blt           zero,     t2,        .LBS3SGF_H_W
+
+    addi.d        a0,       a0,        REST_UNIT_STRIDE<<2
+    addi.d        a1,       a1,        REST_UNIT_STRIDE<<1
+    addi.w        a3,       a3,        -1
+    bnez          a3,       .LBS3SGF_H_H
+endfunc
+
+/*
+boxsum3_selfguided_filter(coef *dst, pixel *src,
+                  int32_t *sumsq, coef *sum,
+                  const int w, const int h)
+*/
+function boxsum3_sgf_v_8bpc_lsx
+    addi.d        a1,        a1,      (3*REST_UNIT_STRIDE+3)   // src
+    addi.d        a2,        a2,      REST_UNIT_STRIDE<<2
+    addi.d        a2,        a2,      (REST_UNIT_STRIDE<<2)+12
+    addi.d        a3,        a3,      REST_UNIT_STRIDE<<2
+    addi.d        a3,        a3,      6
+.LBS3SGF_V_H:
+    // A int32_t *sumsq
+    addi.d        t0,        a2,      -(REST_UNIT_STRIDE<<2)   // -stride
+    addi.d        t1,        a2,      0    // sumsq
+    addi.d        t2,        a2,      REST_UNIT_STRIDE<<2      // +stride
+    addi.d        t6,        a1,      0
+    addi.w        t7,        a4,      0
+    addi.d        t8,        a0,      0
+    // B coef *sum
+    addi.d        t3,        a3,      -(REST_UNIT_STRIDE<<1)   // -stride
+    addi.d        t4,        a3,      0
+    addi.d        t5,        a3,      REST_UNIT_STRIDE<<1
+
+.LBS3SGF_V_W:
+    vld           vr0,       t0,      0   // P[i - REST_UNIT_STRIDE]
+    vld           vr1,       t0,      16
+    vld           vr2,       t1,      -4  // P[i-1]  -1 0 1 2
+    vld           vr3,       t1,      12           // 3 4 5 6
+    vld           vr4,       t2,      0   // P[i + REST_UNIT_STRIDE]
+    vld           vr5,       t2,      16
+    vld           vr6,       t1,      0   // p[i]     0 1 2 3
+    vld           vr7,       t1,      16           // 4 5 6 7
+    vld           vr8,       t1,      4   // p[i+1]   1 2 3 4
+    vld           vr9,       t1,      20           // 5 6 7 8
+
+    vld           vr10,      t0,      -4  // P[i - 1 - REST_UNIT_STRIDE]
+    vld           vr11,      t0,      12
+    vld           vr12,      t2,      -4  // P[i - 1 + REST_UNIT_STRIDE]
+    vld           vr13,      t2,      12
+    vld           vr14,      t0,      4   // P[i + 1 - REST_UNIT_STRIDE]
+    vld           vr15,      t0,      20
+    vld           vr16,      t2,      4   // P[i + 1 + REST_UNIT_STRIDE]
+    vld           vr17,      t2,      20
+
+    vadd.w        vr0,       vr2,     vr0
+    vadd.w        vr4,       vr6,     vr4
+    vadd.w        vr0,       vr0,     vr8
+    vadd.w        vr20,      vr0,     vr4
+    vslli.w       vr20,      vr20,    2      // 0 1 2 3
+    vadd.w        vr0,       vr1,     vr3
+    vadd.w        vr4,       vr5,     vr7
+    vadd.w        vr0,       vr0,     vr9
+    vadd.w        vr21,      vr0,     vr4
+    vslli.w       vr21,      vr21,    2      // 4 5 6 7
+    vadd.w        vr12,      vr10,    vr12
+    vadd.w        vr16,      vr14,    vr16
+    vadd.w        vr22,      vr12,    vr16
+    vslli.w       vr23,      vr22,    1
+    vadd.w        vr22,      vr23,    vr22
+    vadd.w        vr11,      vr11,    vr13
+    vadd.w        vr15,      vr15,    vr17
+    vadd.w        vr0,       vr11,    vr15
+    vslli.w       vr23,      vr0,     1
+    vadd.w        vr23,      vr23,    vr0
+    vadd.w        vr20,      vr20,    vr22   // b
+    vadd.w        vr21,      vr21,    vr23
+
+    // B coef *sum
+    vld           vr0,       t3,      0   // P[i - REST_UNIT_STRIDE]
+    vld           vr1,       t4,      -2  // p[i - 1]
+    vld           vr2,       t4,      0   // p[i]
+    vld           vr3,       t4,      2   // p[i + 1]
+    vld           vr4,       t5,      0   // P[i + REST_UNIT_STRIDE]
+    vld           vr5,       t3,      -2  // P[i - 1 - REST_UNIT_STRIDE]
+    vld           vr6,       t5,      -2  // P[i - 1 + REST_UNIT_STRIDE]
+    vld           vr7,       t3,      2   // P[i + 1 - REST_UNIT_STRIDE]
+    vld           vr8,       t5,      2   // P[i + 1 + REST_UNIT_STRIDE]
+    vaddwev.w.h   vr9,       vr0,     vr1
+    vaddwod.w.h   vr10,      vr0,     vr1
+    vaddwev.w.h   vr11,      vr2,     vr3
+    vaddwod.w.h   vr12,      vr2,     vr3
+    vadd.w        vr9,       vr11,    vr9
+    vadd.w        vr10,      vr12,    vr10
+    vilvl.w       vr11,      vr10,    vr9    // 0 1 2 3
+    vilvh.w       vr12,      vr10,    vr9    // 4 5 6 7
+    vsllwil.w.h   vr0,       vr4,     0
+    vexth.w.h     vr1,       vr4
+    vadd.w        vr0,       vr11,    vr0
+    vadd.w        vr1,       vr12,    vr1
+    vslli.w       vr0,       vr0,     2
+    vslli.w       vr1,       vr1,     2
+    vaddwev.w.h   vr9,       vr5,     vr6
+    vaddwod.w.h   vr10,      vr5,     vr6
+    vaddwev.w.h   vr11,      vr7,     vr8
+    vaddwod.w.h   vr12,      vr7,     vr8
+    vadd.w        vr9,       vr11,    vr9
+    vadd.w        vr10,      vr12,    vr10
+    vilvl.w       vr13,      vr10,    vr9
+    vilvh.w       vr14,      vr10,    vr9
+    vslli.w       vr15,      vr13,    1
+    vslli.w       vr16,      vr14,    1
+    vadd.w        vr15,      vr13,    vr15   // a
+    vadd.w        vr16,      vr14,    vr16
+    vadd.w        vr22,      vr0,     vr15
+    vadd.w        vr23,      vr1,     vr16
+    vld           vr0,       t6,      0      // src
+    vsllwil.hu.bu vr0,       vr0,     0
+    vsllwil.wu.hu vr1,       vr0,     0
+    vexth.wu.hu   vr2,       vr0
+    vmadd.w       vr20,      vr22,    vr1
+    vmadd.w       vr21,      vr23,    vr2
+    vssrlrni.h.w  vr21,      vr20,    9
+    vst           vr21,      t8,      0
+    addi.d        t8,        t8,      16
+
+    addi.d        t0,        t0,      32
+    addi.d        t1,        t1,      32
+    addi.d        t2,        t2,      32
+    addi.d        t3,        t3,      16
+    addi.d        t4,        t4,      16
+    addi.d        t5,        t5,      16
+    addi.d        t6,        t6,      8
+    addi.w        t7,        t7,      -8
+    blt           zero,      t7,      .LBS3SGF_V_W
+
+    addi.w        a5,        a5,      -1
+    addi.d        a0,        a0,      384*2
+    addi.d        a1,        a1,      REST_UNIT_STRIDE
+    addi.d        a3,        a3,      REST_UNIT_STRIDE<<1
+    addi.d        a2,        a2,      REST_UNIT_STRIDE<<2
+    bnez          a5,        .LBS3SGF_V_H
+endfunc
+
+function boxsum3_sgf_v_8bpc_lasx
+    addi.d        a1,        a1,      (3*REST_UNIT_STRIDE+3)   // src
+    addi.d        a2,        a2,      REST_UNIT_STRIDE<<2
+    addi.d        a2,        a2,      (REST_UNIT_STRIDE<<2)+12
+    addi.d        a3,        a3,      REST_UNIT_STRIDE<<2
+    addi.d        a3,        a3,      6
+.LBS3SGF_V_H_LASX:
+    // A int32_t *sumsq
+    addi.d        t0,        a2,      -(REST_UNIT_STRIDE<<2)   // -stride
+    addi.d        t1,        a2,      0    // sumsq
+    addi.d        t2,        a2,      REST_UNIT_STRIDE<<2      // +stride
+    addi.d        t6,        a1,      0
+    addi.w        t7,        a4,      0
+    addi.d        t8,        a0,      0
+    // B coef *sum
+    addi.d        t3,        a3,      -(REST_UNIT_STRIDE<<1)   // -stride
+    addi.d        t4,        a3,      0
+    addi.d        t5,        a3,      REST_UNIT_STRIDE<<1
+
+.LBS3SGF_V_W_LASX:
+    xvld           xr0,       t0,      0   // P[i - REST_UNIT_STRIDE]
+    xvld           xr1,       t0,      32
+    xvld           xr2,       t1,      -4  // P[i-1]  -1 0 1 2
+    xvld           xr3,       t1,      28           // 3 4 5 6
+    xvld           xr4,       t2,      0   // P[i + REST_UNIT_STRIDE]
+    xvld           xr5,       t2,      32
+    xvld           xr6,       t1,      0   // p[i]     0 1 2 3
+    xvld           xr7,       t1,      32           // 4 5 6 7
+    xvld           xr8,       t1,      4   // p[i+1]   1 2 3 4
+    xvld           xr9,       t1,      36           // 5 6 7 8
+
+    xvld           xr10,      t0,      -4  // P[i - 1 - REST_UNIT_STRIDE]
+    xvld           xr11,      t0,      28
+    xvld           xr12,      t2,      -4  // P[i - 1 + REST_UNIT_STRIDE]
+    xvld           xr13,      t2,      28
+    xvld           xr14,      t0,      4   // P[i + 1 - REST_UNIT_STRIDE]
+    xvld           xr15,      t0,      36
+    xvld           xr16,      t2,      4   // P[i + 1 + REST_UNIT_STRIDE]
+    xvld           xr17,      t2,      36
+
+    xvadd.w        xr0,       xr2,     xr0
+    xvadd.w        xr4,       xr6,     xr4
+    xvadd.w        xr0,       xr0,     xr8
+    xvadd.w        xr20,      xr0,     xr4
+    xvslli.w       xr20,      xr20,    2      // 0 1 2 3
+    xvadd.w        xr0,       xr1,     xr3
+    xvadd.w        xr4,       xr5,     xr7
+    xvadd.w        xr0,       xr0,     xr9
+    xvadd.w        xr21,      xr0,     xr4
+    xvslli.w       xr21,      xr21,    2      // 4 5 6 7
+    xvadd.w        xr12,      xr10,    xr12
+    xvadd.w        xr16,      xr14,    xr16
+    xvadd.w        xr22,      xr12,    xr16
+    xvslli.w       xr23,      xr22,    1
+    xvadd.w        xr22,      xr23,    xr22
+    xvadd.w        xr11,      xr11,    xr13
+    xvadd.w        xr15,      xr15,    xr17
+    xvadd.w        xr0,       xr11,    xr15
+    xvslli.w       xr23,      xr0,     1
+    xvadd.w        xr23,      xr23,    xr0
+    xvadd.w        xr20,      xr20,    xr22   // b
+    xvadd.w        xr21,      xr21,    xr23
+
+    // B coef *sum
+    xvld           xr0,       t3,      0   // P[i - REST_UNIT_STRIDE]
+    xvld           xr1,       t4,      -2  // p[i - 1]
+    xvld           xr2,       t4,      0   // p[i]
+    xvld           xr3,       t4,      2   // p[i + 1]
+    xvld           xr4,       t5,      0   // P[i + REST_UNIT_STRIDE]
+    xvld           xr5,       t3,      -2  // P[i - 1 - REST_UNIT_STRIDE]
+    xvld           xr6,       t5,      -2  // P[i - 1 + REST_UNIT_STRIDE]
+    xvld           xr7,       t3,      2   // P[i + 1 - REST_UNIT_STRIDE]
+    xvld           xr8,       t5,      2   // P[i + 1 + REST_UNIT_STRIDE]
+
+    xvaddwev.w.h   xr9,       xr0,     xr1
+    xvaddwod.w.h   xr10,      xr0,     xr1
+    xvaddwev.w.h   xr11,      xr2,     xr3
+    xvaddwod.w.h   xr12,      xr2,     xr3
+    xvadd.w        xr9,       xr11,    xr9   // 0 2 4 6 8 10 12 14
+    xvadd.w        xr10,      xr12,    xr10  // 1 3 5 7 9 11 13 15
+    xvilvl.w       xr11,      xr10,    xr9   // 0 1 2 3 8 9 10 11
+    xvilvh.w       xr12,      xr10,    xr9   // 4 5 6 7 12 13 14 15
+    xvsllwil.w.h   xr0,       xr4,     0     // 0 1 2 3 8 9 10 11
+    xvexth.w.h     xr1,       xr4            // 4 5 6 7 12 13 14 15
+
+    xvadd.w        xr0,       xr11,    xr0
+    xvadd.w        xr1,       xr12,    xr1
+    xvslli.w       xr0,       xr0,     2
+    xvslli.w       xr1,       xr1,     2
+
+    xvaddwev.w.h   xr9,       xr5,     xr6
+    xvaddwod.w.h   xr10,      xr5,     xr6
+    xvaddwev.w.h   xr11,      xr7,     xr8
+    xvaddwod.w.h   xr12,      xr7,     xr8
+    xvadd.w        xr9,       xr11,    xr9
+    xvadd.w        xr10,      xr12,    xr10
+    xvilvl.w       xr13,      xr10,    xr9   // 0 1 2 3 8 9 10 11
+    xvilvh.w       xr14,      xr10,    xr9   // 4 5 6 7 12 13 14 15
+
+    xvslli.w       xr15,      xr13,    1
+    xvslli.w       xr16,      xr14,    1
+    xvadd.w        xr15,      xr13,    xr15   // a
+    xvadd.w        xr16,      xr14,    xr16
+    xvadd.w        xr22,      xr0,     xr15   // A B
+    xvadd.w        xr23,      xr1,     xr16   // C D
+
+    vld            vr0,       t6,      0      // src
+    vilvh.d        vr2,       vr0,     vr0
+    vext2xv.wu.bu  xr1,       xr0
+    vext2xv.wu.bu  xr2,       xr2
+    xvor.v         xr15,      xr22,    xr22   // A B
+    xvpermi.q      xr22,      xr23,    0b00000010  // A C
+    xvpermi.q      xr23,      xr15,    0b00110001
+    xvmadd.w       xr20,      xr22,    xr1
+    xvmadd.w       xr21,      xr23,    xr2
+    xvssrlrni.h.w  xr21,      xr20,    9
+    xvpermi.d      xr22,      xr21,    0b11011000
+    xvst           xr22,      t8,      0
+    addi.d         t8,        t8,      32
+
+    addi.d        t0,        t0,      64
+    addi.d        t1,        t1,      64
+    addi.d        t2,        t2,      64
+    addi.d        t3,        t3,      32
+    addi.d        t4,        t4,      32
+    addi.d        t5,        t5,      32
+    addi.d        t6,        t6,      16
+    addi.w        t7,        t7,      -16
+    blt           zero,      t7,      .LBS3SGF_V_W_LASX
+
+    addi.w        a5,        a5,      -1
+    addi.d        a0,        a0,      384*2
+    addi.d        a1,        a1,      REST_UNIT_STRIDE
+    addi.d        a3,        a3,      REST_UNIT_STRIDE<<1
+    addi.d        a2,        a2,      REST_UNIT_STRIDE<<2
+    bnez          a5,        .LBS3SGF_V_H_LASX
+endfunc
+
+#define FILTER_OUT_STRIDE (384)
+
+/*
+sgr_3x3_finish_c(const pixel *p, const ptrdiff_t stride,
+                   const int16_t *dst, const int w1;
+                   const int w, const int h);
+*/
+function sgr_3x3_finish_8bpc_lsx
+    vreplgr2vr.w  vr3,     a3            // w1
+    andi          t4,      a4,       0x7
+    sub.w         t5,      a4,       t4
+
+    beq           zero,    t5,       .LSGR3X3_REM
+
+.LSGR3X3_H:
+    addi.d        t0,      a0,       0
+    addi.d        t1,      a2,       0
+    addi.w        t2,      t5,       0
+    andi          t4,      a4,       0x7
+.LSGR3X3_W:
+    vld           vr0,     t0,       0
+    vld           vr1,     t1,       0
+    vsllwil.hu.bu vr2,     vr0,      4   // u 8 h
+    vsllwil.wu.hu vr4,     vr2,      0   // p
+    vexth.wu.hu   vr5,     vr2           // p
+    vslli.w       vr6,     vr4,      7
+    vslli.w       vr7,     vr5,      7
+    vsllwil.w.h   vr8,     vr1,      0   // dst
+    vexth.w.h     vr9,     vr1           // dst
+    vsub.w        vr8,     vr8,      vr4
+    vsub.w        vr9,     vr9,      vr5
+    vmadd.w       vr6,     vr8,      vr3  // v 0 - 3
+    vmadd.w       vr7,     vr9,      vr3  // v 4 - 7
+    vssrarni.hu.w vr7,     vr6,      11
+    vssrlni.bu.h  vr7,     vr7,      0
+    vstelm.d      vr7,     t0,       0,    0
+    addi.d        t0,      t0,       8
+    addi.d        t1,      t1,       16
+    addi.d        t2,      t2,       -8
+    bne           zero,    t2,       .LSGR3X3_W
+
+    beq           t4,      zero,     .LSGR3X3_NOREM
+
+    vld           vr0,     t0,       0
+    vld           vr1,     t1,       0
+    vsllwil.hu.bu vr2,     vr0,      4   // u 8 h
+    vsllwil.wu.hu vr4,     vr2,      0   // p
+    vexth.wu.hu   vr5,     vr2           // p
+    vslli.w       vr6,     vr4,      7
+    vslli.w       vr7,     vr5,      7
+    vsllwil.w.h   vr8,     vr1,      0   // dst
+    vexth.w.h     vr9,     vr1           // dst
+    vsub.w        vr8,     vr8,      vr4
+    vsub.w        vr9,     vr9,      vr5
+    vmadd.w       vr6,     vr8,      vr3  // v 0 - 3
+    vmadd.w       vr7,     vr9,      vr3  // v 4 - 7
+    vssrarni.hu.w vr7,     vr6,      11
+    vssrlni.bu.h  vr7,     vr7,      0
+
+.LSGR3X3_ST:
+    vstelm.b      vr7,     t0,       0,    0
+    addi.d        t0,      t0,       1
+    vbsrl.v       vr7,     vr7,      1
+    addi.w        t4,      t4,       -1
+    bnez          t4,      .LSGR3X3_ST
+
+.LSGR3X3_NOREM:
+    addi.w        a5,      a5,       -1
+    add.d         a0,      a0,       a1
+    addi.d        a2,      a2,       (FILTER_OUT_STRIDE<<1)
+    bnez          a5,      .LSGR3X3_H
+    b             .LSGR3X3_END
+
+.LSGR3X3_REM:
+    andi          t4,      a4,       0x7
+    addi.d        t0,      a0,       0
+    vld           vr0,     t0,       0
+    vld           vr1,     a2,       0
+    vsllwil.hu.bu vr2,     vr0,      4   // u 8 h
+    vsllwil.wu.hu vr4,     vr2,      0   // p
+    vexth.wu.hu   vr5,     vr2           // p
+    vslli.w       vr6,     vr4,      7
+    vslli.w       vr7,     vr5,      7
+    vsllwil.w.h   vr8,     vr1,      0   // dst
+    vexth.w.h     vr9,     vr1           // dst
+    vsub.w        vr8,     vr8,      vr4
+    vsub.w        vr9,     vr9,      vr5
+    vmadd.w       vr6,     vr8,      vr3  // v 0 - 3
+    vmadd.w       vr7,     vr9,      vr3  // v 4 - 7
+    vssrarni.hu.w vr7,     vr6,      11
+    vssrlni.bu.h  vr7,     vr7,      0
+
+.LSGR3X3_REM_ST:
+    vstelm.b      vr7,     t0,       0,    0
+    addi.d        t0,      t0,       1
+    vbsrl.v       vr7,     vr7,      1
+    addi.w        t4,      t4,       -1
+    bnez          t4,      .LSGR3X3_REM_ST
+    addi.w        a5,      a5,       -1
+    add.d         a0,      a0,       a1
+    addi.d        a2,      a2,       (FILTER_OUT_STRIDE<<1)
+    bnez          a5,      .LSGR3X3_REM
+
+.LSGR3X3_END:
+endfunc
+
+/*
+void boxsum5(int32_t *sumsq, coef *sum,
+             const pixel *const src,
+             const int w, const int h)
+*/
+function boxsum5_h_8bpc_lsx
+    addi.w        a4,      a4,        -4
+    addi.d        a0,      a0,        REST_UNIT_STRIDE<<2
+    addi.d        a1,      a1,        REST_UNIT_STRIDE<<1
+    li.w          t6,      1
+.LBOXSUM5_H_H:
+    addi.w        t3,      a3,        0
+    addi.d        t2,      a2,        0
+    addi.d        t0,      a0,        0
+    addi.d        t1,      a1,        0
+
+.LBOXSUM5_H_W:
+    vld           vr0,     t2,        0                   // a
+    vld           vr1,     t2,        REST_UNIT_STRIDE    // b
+    vld           vr2,     t2,        REST_UNIT_STRIDE<<1 // c
+    vld           vr3,     t2,        REST_UNIT_STRIDE*3  // d
+    vld           vr4,     t2,        REST_UNIT_STRIDE<<2 // e
+
+    vilvl.b       vr5,     vr1,       vr0
+    vilvh.b       vr6,     vr1,       vr0
+    vilvl.b       vr7,     vr3,       vr2
+    vilvh.b       vr8,     vr3,       vr2
+    //sum_v
+    vhaddw.hu.bu  vr9,     vr5,       vr5  // 0 1  2  3  4  5  6  7
+    vhaddw.hu.bu  vr10,    vr6,       vr6  // 8 9 10 11 12 13 14 15  a+b
+    vhaddw.hu.bu  vr11,    vr7,       vr7
+    vhaddw.hu.bu  vr12,    vr8,       vr8
+    vadd.h        vr9,     vr9,       vr11
+    vadd.h        vr10,    vr10,      vr12  // a + b + c + d
+    vsllwil.hu.bu vr11,    vr4,       0
+    vexth.hu.bu   vr12,    vr4
+    vadd.h        vr9,     vr9,       vr11
+    vadd.h        vr10,    vr10,      vr12
+    vst           vr9,     t1,        0
+    vst           vr10,    t1,        16
+    addi.d        t1,      t1,        32
+
+    // sumsq
+    vmulwev.h.bu  vr9,     vr5,       vr5  // a*a 0 1  2  3  4  5  6  7
+    vmulwev.h.bu  vr10,    vr6,       vr6  // a*a 8 9 10 11 12 13 14 15
+    vmulwod.h.bu  vr13,    vr5,       vr5  // b*b 0 1  2  3  4  5  6  7
+    vmulwod.h.bu  vr14,    vr6,       vr6  // b*b 8 9 10 11 12 13 14 15
+    vmulwev.h.bu  vr15,    vr7,       vr7  // c*c 0 1  2  3  4  5  6  7
+    vmulwev.h.bu  vr16,    vr8,       vr8  // c*c 8 9 10 11 12 13 14 15
+    vmulwod.h.bu  vr17,    vr7,       vr7  // d*d 0 1  2  3  4  5  6  7
+    vmulwod.h.bu  vr18,    vr8,       vr8  // d*d 8 9 10 11 12 13 14 15
+    vaddwev.w.hu  vr5,     vr9,       vr13  // 0 2 4 6
+    vaddwod.w.hu  vr6,     vr9,       vr13  // 1 3 5 7
+    vaddwev.w.hu  vr7,     vr10,      vr14  // 8 10 12 14
+    vaddwod.w.hu  vr8,     vr10,      vr14  // 9 11 13 15   a + b
+    vaddwev.w.hu  vr19,    vr15,      vr17  // 0 2 4 6
+    vaddwod.w.hu  vr20,    vr15,      vr17  // 1 3 5 7
+    vaddwev.w.hu  vr21,    vr16,      vr18  // 8 10 12 14
+    vaddwod.w.hu  vr22,    vr16,      vr18  // 9 11 13 15   c + d
+    vadd.w        vr5,     vr5,       vr19
+    vadd.w        vr6,     vr6,       vr20
+    vadd.w        vr7,     vr7,       vr21
+    vadd.w        vr8,     vr8,       vr22
+    vmaddwev.w.hu vr5,     vr11,      vr11
+    vmaddwod.w.hu vr6,     vr11,      vr11
+    vmaddwev.w.hu vr7,     vr12,      vr12
+    vmaddwod.w.hu vr8,     vr12,      vr12
+    vilvl.w       vr19,    vr6,       vr5
+    vilvh.w       vr20,    vr6,       vr5
+    vilvl.w       vr21,    vr8,       vr7
+    vilvh.w       vr22,    vr8,       vr7
+
+    vst           vr19,    t0,        0
+    vst           vr20,    t0,        16
+    vst           vr21,    t0,        32
+    vst           vr22,    t0,        48
+    addi.d        t0,      t0,        64
+    addi.d        t2,      t2,        16
+    addi.w        t3,      t3,        -16
+    blt           zero,    t3,        .LBOXSUM5_H_W
+
+    addi.d        a0,      a0,        REST_UNIT_STRIDE<<2
+    addi.d        a1,      a1,        REST_UNIT_STRIDE<<1
+    addi.d        a2,      a2,        REST_UNIT_STRIDE
+    addi.d        a4,      a4,        -1
+    bnez          a4,      .LBOXSUM5_H_H
+endfunc
+
+/*
+void boxsum5_h(int32_t *sumsq, coef *sum,
+               const int w, const int h)
+*/
+function boxsum5_v_8bpc_lsx
+    addi.d         a0,      a0,      (REST_UNIT_STRIDE<<2)
+    addi.d         a1,      a1,      (REST_UNIT_STRIDE<<1)
+    addi.w         a3,      a3,      -4
+    addi.w         a2,      a2,      -4
+
+.LBOXSUM5_V_H:
+    addi.w         t3,      a2,      0
+    addi.d         t0,      a0,      0
+    addi.d         t1,      a1,      0
+    addi.d         t2,      a0,      8
+    addi.d         t3,      a1,      4
+    addi.d         t4,      a2,      0
+
+    vld            vr0,     t1,      0   // a 0 1 2 3 4 5 6 7
+    vld            vr1,     t1,      2   // b 1 2 3 4 5 6 7 8
+    vld            vr2,     t1,      4   // c 2
+    vld            vr3,     t1,      6   // d 3
+    vld            vr4,     t1,      8   // e 4 5 6 7 8 9 10 11
+    vadd.h         vr5,     vr0,     vr1
+    vadd.h         vr6,     vr2,     vr3
+    vpickve2gr.w   t5,      vr4,     2
+    vadd.h         vr5,     vr5,     vr6
+    vadd.h         vr5,     vr5,     vr4
+    vst            vr5,     t3,      0
+
+    vld            vr0,     t0,      0  // 0 1 2 3   a
+    vld            vr1,     t0,      4  // 1 2 3 4   b
+    vld            vr2,     t0,      8  // 2 3 4 5   c
+    vld            vr3,     t0,      12 // 3 4 5 6   d
+    vld            vr4,     t0,      16 // 4 5 6 7   e  a
+    vld            vr5,     t0,      20 // 5 6 7 8      b
+    vld            vr6,     t0,      24 // 6 7 8 9      c
+    vld            vr7,     t0,      28 // 7 8 9 10     d
+    vld            vr8,     t0,      32 // 8 9 10 11    e
+
+    vadd.w         vr9,     vr0,     vr1
+    vadd.w         vr10,    vr2,     vr3
+    vadd.w         vr9,     vr9,     vr10
+    vadd.w         vr9,     vr9,     vr4
+    vadd.w         vr10,    vr4,     vr5
+    vadd.w         vr11,    vr6,     vr7
+    vadd.w         vr10,    vr10,    vr8
+    vadd.w         vr10,    vr10,    vr11
+    vst            vr9,     t2,      0
+    vst            vr10,    t2,      16
+
+    addi.d         t3,      t3,      16
+    addi.d         t1,      t1,      16
+    addi.d         t0,      t0,      32
+    addi.d         t2,      t2,      32
+    addi.w         t4,      t4,      -8
+    bge            zero,    t4,      .LBOXSUM5_V_H1
+
+.LBOXSUM5_V_W:
+    vld            vr0,     t1,      0   // a 0 1 2 3 4 5 6 7
+    vld            vr1,     t1,      2   // b 1 2 3 4 5 6 7 8
+    vld            vr2,     t1,      4   // c 2
+    vld            vr3,     t1,      6   // d 3
+    vld            vr4,     t1,      8   // e 4 5 6 7 8 9 10 11
+    vinsgr2vr.w    vr0,     t5,      0
+    vpickve2gr.w   t5,      vr4,     2
+    vextrins.h     vr1,     vr0,     0x01
+    vadd.h         vr5,     vr0,     vr1
+    vadd.h         vr6,     vr2,     vr3
+    vadd.h         vr5,     vr5,     vr6
+    vadd.h         vr5,     vr5,     vr4
+    vst            vr5,     t3,      0
+
+    vaddi.hu       vr0,     vr8,     0  // 8  9 10 11  a
+    vld            vr1,     t0,      4  // 9 10 11 12  b
+    vld            vr2,     t0,      8  // 10 11 12 13 c
+    vld            vr3,     t0,      12 // 14 15 16 17 d
+    vld            vr4,     t0,      16 // 15 16 17 18 e  a
+    vld            vr5,     t0,      20 // 16 17 18 19    b
+    vld            vr6,     t0,      24 // 17 18 19 20    c
+    vld            vr7,     t0,      28 // 18 19 20 21    d
+    vld            vr8,     t0,      32 // 19 20 21 22    e
+    vextrins.w     vr1,     vr0,     0x01
+    vadd.w         vr9,     vr0,     vr1
+    vadd.w         vr10,    vr2,     vr3
+    vadd.w         vr9,     vr9,     vr10
+    vadd.w         vr9,     vr9,     vr4
+    vadd.w         vr10,    vr4,     vr5
+    vadd.w         vr11,    vr6,     vr7
+    vadd.w         vr10,    vr10,    vr8
+    vadd.w         vr10,    vr10,    vr11
+    vst            vr9,     t2,      0
+    vst            vr10,    t2,      16
+
+    addi.d         t3,      t3,      16
+    addi.d         t1,      t1,      16
+    addi.d         t0,      t0,      32
+    addi.d         t2,      t2,      32
+    addi.w         t4,      t4,      -8
+    blt            zero,    t4,      .LBOXSUM5_V_W
+
+.LBOXSUM5_V_H1:
+    addi.d         a1,       a1,      REST_UNIT_STRIDE<<1
+    addi.d         a0,       a0,      REST_UNIT_STRIDE<<2
+    addi.w         a3,       a3,      -1
+    bnez           a3,       .LBOXSUM5_V_H
+endfunc
+
+/*
+selfguided_filter(int32_t *sumsq, coef *sum,
+                  const int w, const int h,
+                  const unsigned s)
+*/
+function boxsum5_sgf_h_8bpc_lsx
+    addi.d        a0,       a0,        REST_UNIT_STRIDE<<2
+    addi.d        a0,       a0,        12   // AA
+    addi.d        a1,       a1,        REST_UNIT_STRIDE<<1
+    addi.d        a1,       a1,        6    // BB
+    la.local      t8,       dav1d_sgr_x_by_x
+    li.w          t6,       164
+    vreplgr2vr.w  vr20,     t6
+    li.w          t6,       255
+    vreplgr2vr.w  vr22,     t6
+    vaddi.wu      vr21,     vr22,      1  // 256
+    vreplgr2vr.w  vr6,      a4
+    vldi          vr19,     0x819
+    addi.w        a2,       a2,        2  // w + 2
+    addi.w        a3,       a3,        2  // h + 2
+
+.LBS5SGF_H_H:
+    addi.w        t2,       a2,        0
+    addi.d        t0,       a0,        -4
+    addi.d        t1,       a1,        -2
+
+.LBS5SGF_H_W:
+    vld           vr0,      t0,        0   // AA[i]
+    vld           vr1,      t0,        16
+    vld           vr2,      t1,        0   // BB[i]
+
+    vmul.w        vr4,      vr0,       vr19 // a * n
+    vmul.w        vr5,      vr1,       vr19 // a * n
+    vsllwil.w.h   vr9,      vr2,       0
+    vexth.w.h     vr10,     vr2
+    vmsub.w       vr4,      vr9,       vr9   // p
+    vmsub.w       vr5,      vr10,      vr10   // p
+    vmaxi.w       vr4,      vr4,       0
+    vmaxi.w       vr5,      vr5,       0    // p
+    vmul.w        vr4,      vr4,       vr6  // p * s
+    vmul.w        vr5,      vr5,       vr6  // p * s
+    vsrlri.w      vr4,      vr4,       20
+    vsrlri.w      vr5,      vr5,       20   // z
+    vmin.w        vr4,      vr4,       vr22
+    vmin.w        vr5,      vr5,       vr22
+
+    // load table data
+    vpickve2gr.w  t6,       vr4,       0
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr7,      t7,        0
+    vpickve2gr.w  t6,       vr4,       1
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr7,      t7,        1
+    vpickve2gr.w  t6,       vr4,       2
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr7,      t7,        2
+    vpickve2gr.w  t6,       vr4,       3
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr7,      t7,        3
+
+    vpickve2gr.w  t6,       vr5,       0
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr8,      t7,        0
+    vpickve2gr.w  t6,       vr5,       1
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr8,      t7,        1
+    vpickve2gr.w  t6,       vr5,       2
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr8,      t7,        2
+    vpickve2gr.w  t6,       vr5,       3
+    ldx.bu        t7,       t8,        t6
+    vinsgr2vr.w   vr8,      t7,        3     // x
+
+    vmul.w        vr9,      vr7,       vr9   // x * BB[i]
+    vmul.w        vr10,     vr8,       vr10
+    vmul.w        vr9,      vr9,       vr20  // x * BB[i] * sgr_one_by_x
+    vmul.w        vr10,     vr10,      vr20
+    vsrlri.w      vr9,      vr9,       12
+    vsrlri.w      vr10,     vr10,      12
+    vsub.w        vr7,      vr21,      vr7
+    vsub.w        vr8,      vr21,      vr8
+    vpickev.h     vr8,      vr8,       vr7
+    vst           vr9,      t0,        0
+    vst           vr10,     t0,        16
+    vst           vr8,      t1,        0
+    addi.d        t0,       t0,        32
+    addi.d        t1,       t1,        16
+    addi.w        t2,       t2,        -8
+    blt           zero,     t2,        .LBS5SGF_H_W
+
+    addi.d        a0,       a0,        REST_UNIT_STRIDE<<2
+    addi.d        a0,       a0,        REST_UNIT_STRIDE<<2
+    addi.d        a1,       a1,        REST_UNIT_STRIDE<<2
+    addi.w        a3,       a3,        -2
+    blt           zero,     a3,        .LBS5SGF_H_H
+endfunc
+
+/*
+selfguided_filter(coef *dst, pixel *src,
+                  int32_t *sumsq, coef *sum,
+                  const int w, const int h)
+*/
+function boxsum5_sgf_v_8bpc_lsx
+    addi.d        a1,        a1,       3*REST_UNIT_STRIDE+3       // src
+    addi.d        a2,        a2,       (2*REST_UNIT_STRIDE+3)<<1  // A
+    addi.d        a2,        a2,       (2*REST_UNIT_STRIDE+3)<<1
+    addi.d        a3,        a3,       (2*REST_UNIT_STRIDE+3)<<1  // B
+    addi.w        a5,        a5,       -1
+    vldi          vr10,      0x806
+    vldi          vr11,      0x805
+    vldi          vr22,      0x406
+
+.LBS5SGF_V_H:
+    addi.d        t0,        a0,       0
+    addi.d        t1,        a1,       0
+    addi.d        t2,        a2,       0
+    addi.d        t3,        a3,       0
+    addi.w        t4,        a4,       0
+
+    addi.d        t5,        a0,       384*2
+    addi.d        t6,        a1,       REST_UNIT_STRIDE
+    addi.d        t7,        a2,       REST_UNIT_STRIDE<<2
+    addi.d        t8,        a3,       REST_UNIT_STRIDE<<1   // B
+.LBS5SGF_V_W:
+    // a
+    vld           vr0,       t3,       -REST_UNIT_STRIDE*2
+    vld           vr1,       t3,       REST_UNIT_STRIDE*2
+    vld           vr2,       t3,       (-REST_UNIT_STRIDE-1)*2
+    vld           vr3,       t3,       (REST_UNIT_STRIDE-1)*2
+    vld           vr4,       t3,       (1-REST_UNIT_STRIDE)*2
+    vld           vr5,       t3,       (1+REST_UNIT_STRIDE)*2
+    vaddwev.w.h   vr6,       vr0,      vr1
+    vaddwod.w.h   vr7,       vr0,      vr1
+    vmul.w        vr6,       vr6,      vr10
+    vmul.w        vr7,       vr7,      vr10
+    vaddwev.w.h   vr8,       vr2,      vr3
+    vaddwod.w.h   vr9,       vr2,      vr3
+    vaddwev.w.h   vr12,      vr4,      vr5
+    vaddwod.w.h   vr13,      vr4,      vr5
+    vadd.w        vr8,       vr8,      vr12
+    vadd.w        vr9,       vr9,      vr13
+    vmadd.w       vr6,       vr8,      vr11
+    vmadd.w       vr7,       vr9,      vr11
+    vilvl.w       vr18,      vr7,      vr6
+    vilvh.w       vr19,      vr7,      vr6
+    // b
+    vld           vr0,       t2,       -REST_UNIT_STRIDE*4
+    vld           vr1,       t2,       -REST_UNIT_STRIDE*4+16
+    vld           vr2,       t2,       REST_UNIT_STRIDE*4
+    vld           vr3,       t2,       REST_UNIT_STRIDE*4+16
+    vld           vr4,       t2,       (-REST_UNIT_STRIDE-1)*4
+    vld           vr5,       t2,       (-REST_UNIT_STRIDE-1)*4+16
+    vld           vr8,       t2,       (REST_UNIT_STRIDE-1)*4
+    vld           vr9,       t2,       (REST_UNIT_STRIDE-1)*4+16
+    vld           vr12,      t2,       (1-REST_UNIT_STRIDE)*4
+    vld           vr13,      t2,       (1-REST_UNIT_STRIDE)*4+16
+    vld           vr14,      t2,       (1+REST_UNIT_STRIDE)*4
+    vld           vr15,      t2,       (1+REST_UNIT_STRIDE)*4+16
+    vadd.w        vr0,       vr0,      vr2  // 0 1 2 3
+    vadd.w        vr1,       vr1,      vr3  // 4 5 6 7
+    vmul.w        vr20,      vr0,      vr10
+    vmul.w        vr21,      vr1,      vr10
+    vadd.w        vr4,       vr4,      vr8  // 0 1 2 3
+    vadd.w        vr5,       vr5,      vr9  // 4 5 6 7
+    vadd.w        vr12,      vr12,     vr14
+    vadd.w        vr13,      vr13,     vr15
+    vadd.w        vr12,      vr12,     vr4
+    vadd.w        vr13,      vr13,     vr5
+    vmadd.w       vr20,      vr12,     vr11
+    vmadd.w       vr21,      vr13,     vr11
+    vld           vr2,       t1,       0
+    vsllwil.hu.bu vr2,       vr2,      0
+    vsllwil.wu.hu vr3,       vr2,      0
+    vexth.wu.hu   vr4,       vr2
+    vmadd.w       vr20,      vr18,     vr3
+    vmadd.w       vr21,      vr19,     vr4
+    vssrlrni.h.w  vr21,      vr20,     9
+    vst           vr21,      t0,       0
+
+    addi.d        t1,        t1,       8
+    addi.d        t2,        t2,       32
+    addi.d        t3,        t3,       16
+
+    // a
+    vld           vr0,       t8,       0
+    vld           vr1,       t8,       -2
+    vld           vr2,       t8,       2
+    vmulwev.w.h   vr3,       vr0,      vr22
+    vmulwod.w.h   vr4,       vr0,      vr22
+    vaddwev.w.h   vr5,       vr1,      vr2
+    vaddwod.w.h   vr6,       vr1,      vr2
+    vmadd.w       vr3,       vr5,      vr11
+    vmadd.w       vr4,       vr6,      vr11
+    vilvl.w       vr19,      vr4,      vr3
+    vilvh.w       vr20,      vr4,      vr3
+    // b
+    vld           vr0,       t7,       0
+    vld           vr1,       t7,       -4
+    vld           vr2,       t7,       4
+    vld           vr5,       t7,       16
+    vld           vr6,       t7,       12
+    vld           vr7,       t7,       20
+    vmul.w        vr8,       vr0,      vr10
+    vmul.w        vr9,       vr5,      vr10
+    vadd.w        vr12,      vr1,      vr2
+    vadd.w        vr13,      vr6,      vr7
+    vmadd.w       vr8,       vr12,     vr11
+    vmadd.w       vr9,       vr13,     vr11
+    vld           vr2,       t6,       0
+    vsllwil.hu.bu vr2,       vr2,      0
+    vsllwil.wu.hu vr3,       vr2,      0
+    vexth.wu.hu   vr4,       vr2
+    vmadd.w       vr8,       vr19,     vr3
+    vmadd.w       vr9,       vr20,     vr4
+    vssrlrni.h.w  vr9,       vr8,      8
+    vst           vr9,       t0,       384*2
+
+    addi.d        t0,        t0,       16
+    addi.d        t8,        t8,       16
+    addi.d        t7,        t7,       32
+    addi.d        t6,        t6,       8
+    addi.w        t4,        t4,       -8
+    blt           zero,      t4,       .LBS5SGF_V_W
+
+    addi.w        a5,        a5,       -2
+    addi.d        a0,        a0,       384*4                // dst
+    addi.d        a1,        a1,       REST_UNIT_STRIDE<<1  // src
+    addi.d        a2,        a2,       REST_UNIT_STRIDE<<2  //
+    addi.d        a2,        a2,       REST_UNIT_STRIDE<<2
+    addi.d        a3,        a3,       REST_UNIT_STRIDE<<2  //
+    blt           zero,      a5,       .LBS5SGF_V_H
+    bnez          a5,        .LBS5SGF_END
+.LBS5SGF_V_W1:
+    // a
+    vld           vr0,       a3,       -REST_UNIT_STRIDE*2
+    vld           vr1,       a3,       REST_UNIT_STRIDE*2
+    vld           vr2,       a3,       (-REST_UNIT_STRIDE-1)*2
+    vld           vr3,       a3,       (REST_UNIT_STRIDE-1)*2
+    vld           vr4,       a3,       (1-REST_UNIT_STRIDE)*2
+    vld           vr5,       a3,       (1+REST_UNIT_STRIDE)*2
+    vaddwev.w.h   vr6,       vr0,      vr1
+    vaddwod.w.h   vr7,       vr0,      vr1
+    vmul.w        vr6,       vr6,      vr10
+    vmul.w        vr7,       vr7,      vr10
+    vaddwev.w.h   vr8,       vr2,      vr3
+    vaddwod.w.h   vr9,       vr2,      vr3
+    vaddwev.w.h   vr12,      vr4,      vr5
+    vaddwod.w.h   vr13,      vr4,      vr5
+    vadd.w        vr8,       vr8,      vr12
+    vadd.w        vr9,       vr9,      vr13
+    vmadd.w       vr6,       vr8,      vr11
+    vmadd.w       vr7,       vr9,      vr11
+    vilvl.w       vr18,      vr7,      vr6
+    vilvh.w       vr19,      vr7,      vr6
+    // b
+    vld           vr0,       a2,       -REST_UNIT_STRIDE*4
+    vld           vr1,       a2,       -REST_UNIT_STRIDE*4+16
+    vld           vr2,       a2,       REST_UNIT_STRIDE*4
+    vld           vr3,       a2,       REST_UNIT_STRIDE*4+16
+    vld           vr4,       a2,       (-REST_UNIT_STRIDE-1)*4
+    vld           vr5,       a2,       (-REST_UNIT_STRIDE-1)*4+16
+    vld           vr8,       a2,       (REST_UNIT_STRIDE-1)*4
+    vld           vr9,       a2,       (REST_UNIT_STRIDE-1)*4+16
+    vld           vr12,      a2,       (1-REST_UNIT_STRIDE)*4
+    vld           vr13,      a2,       (1-REST_UNIT_STRIDE)*4+16
+    vld           vr14,      a2,       (1+REST_UNIT_STRIDE)*4
+    vld           vr15,      a2,       (1+REST_UNIT_STRIDE)*4+16
+    vadd.w        vr0,       vr0,      vr2  // 0 1 2 3
+    vadd.w        vr1,       vr1,      vr3  // 4 5 6 7
+    vmul.w        vr20,      vr0,      vr10
+    vmul.w        vr21,      vr1,      vr10
+    vadd.w        vr4,       vr4,      vr8  // 0 1 2 3
+    vadd.w        vr5,       vr5,      vr9  // 4 5 6 7
+    vadd.w        vr12,      vr12,     vr14
+    vadd.w        vr13,      vr13,     vr15
+    vadd.w        vr12,      vr12,     vr4
+    vadd.w        vr13,      vr13,     vr5
+    vmadd.w       vr20,      vr12,     vr11
+    vmadd.w       vr21,      vr13,     vr11
+    vld           vr2,       a1,       0
+    vsllwil.hu.bu vr2,       vr2,      0
+    vsllwil.wu.hu vr3,       vr2,      0
+    vexth.wu.hu   vr4,       vr2
+    vmadd.w       vr20,      vr18,     vr3
+    vmadd.w       vr21,      vr19,     vr4
+    vssrlrni.h.w  vr21,      vr20,     9
+    vst           vr21,      a0,       0
+    addi.d        a3,        a3,       16
+    addi.d        a2,        a2,       32
+    addi.d        a1,        a1,       8
+    addi.d        a0,        a0,       16
+    addi.w        a4,        a4,       -8
+    blt           zero,      a4,       .LBS5SGF_V_W1
+.LBS5SGF_END:
+endfunc
+
+/*
+void dav1d_sgr_mix_finish_lsx(uint8_t *p, const ptrdiff_t stride,
+                              const int16_t *dst0, const int16_t *dst1,
+                              const int w0, const int w1,
+                              const int w, const int h);
+*/
+function sgr_mix_finish_8bpc_lsx
+    vreplgr2vr.w  vr3,     a4            // w0
+    vreplgr2vr.w  vr13,    a5            // w1
+    andi          t4,      a6,       0x7
+    sub.w         t5,      a6,       t4
+
+    beq           zero,    t5,      .LSGRMIX_REM
+
+.LSGRMIX_H:
+    addi.d        t0,      a0,       0
+    addi.d        t1,      a2,       0   // dst0
+    addi.d        t3,      a3,       0   // dst1
+    addi.w        t2,      t5,       0
+    andi          t4,      a6,       0x7
+.LSGRMIX_W:
+    vld           vr0,     t0,       0
+    vld           vr1,     t1,       0
+    vld           vr10,    t3,       0
+    vsllwil.hu.bu vr2,     vr0,      4   // u 8 h
+    vsllwil.wu.hu vr4,     vr2,      0   // u 0 1 2 3
+    vexth.wu.hu   vr5,     vr2           // u 4 5 6 7
+    vslli.w       vr6,     vr4,      7
+    vslli.w       vr7,     vr5,      7
+    vsllwil.w.h   vr8,     vr1,      0   // dst0
+    vexth.w.h     vr9,     vr1           // dst0
+    vsub.w        vr8,     vr8,      vr4
+    vsub.w        vr9,     vr9,      vr5
+    vmadd.w       vr6,     vr8,      vr3  // v 0 - 3
+    vmadd.w       vr7,     vr9,      vr3  // v 4 - 7
+
+    vsllwil.w.h   vr11,    vr10,     0    // dst1
+    vexth.w.h     vr12,    vr10           // dst1
+    vsub.w        vr11,    vr11,     vr4
+    vsub.w        vr12,    vr12,     vr5
+    vmadd.w       vr6,     vr11,     vr13
+    vmadd.w       vr7,     vr12,     vr13
+
+    vssrarni.hu.w vr7,     vr6,      11
+    vssrlni.bu.h  vr7,     vr7,      0
+    vstelm.d      vr7,     t0,       0,    0
+    addi.d        t0,      t0,       8
+    addi.d        t1,      t1,       16
+    addi.d        t3,      t3,       16
+    addi.d        t2,      t2,       -8
+    bne           zero,    t2,       .LSGRMIX_W
+
+    beq           t4,      zero,     .LSGRMIX_W8
+
+    vld           vr0,     t0,       0
+    vld           vr1,     t1,       0
+    vld           vr10,    t3,       0
+    vsllwil.hu.bu vr2,     vr0,      4   // u 8 h
+    vsllwil.wu.hu vr4,     vr2,      0   // p
+    vexth.wu.hu   vr5,     vr2           // p
+    vslli.w       vr6,     vr4,      7
+    vslli.w       vr7,     vr5,      7
+    vsllwil.w.h   vr8,     vr1,      0   // dst
+    vexth.w.h     vr9,     vr1           // dst
+    vsub.w        vr8,     vr8,      vr4
+    vsub.w        vr9,     vr9,      vr5
+    vmadd.w       vr6,     vr8,      vr3  // v 0 - 3
+    vmadd.w       vr7,     vr9,      vr3  // v 4 - 7
+
+    vsllwil.w.h   vr11,    vr10,     0    // dst1
+    vexth.w.h     vr12,    vr10           // dst1
+    vsub.w        vr11,    vr11,     vr4
+    vsub.w        vr12,    vr12,     vr5
+    vmadd.w       vr6,     vr11,     vr13
+    vmadd.w       vr7,     vr12,     vr13
+
+    vssrarni.hu.w vr7,     vr6,      11
+    vssrlni.bu.h  vr7,     vr7,      0
+
+.LSGRMIX_ST:
+    vstelm.b      vr7,     t0,       0,    0
+    addi.d        t0,      t0,       1
+    vbsrl.v       vr7,     vr7,      1
+    addi.w        t4,      t4,       -1
+    bnez          t4,      .LSGRMIX_ST
+
+.LSGRMIX_W8:
+    addi.w        a7,      a7,       -1
+    add.d         a0,      a0,       a1
+    addi.d        a2,      a2,       (FILTER_OUT_STRIDE<<1)
+    addi.d        a3,      a3,       (FILTER_OUT_STRIDE<<1)
+    bnez          a7,      .LSGRMIX_H
+    b             .LSGR_MIX_END
+
+.LSGRMIX_REM:
+    andi          t4,      a6,       0x7
+    vld           vr0,     a0,       0
+    vld           vr1,     a2,       0
+    vld           vr10,    a3,       0
+    vsllwil.hu.bu vr2,     vr0,      4   // u 8 h
+    vsllwil.wu.hu vr4,     vr2,      0   // p
+    vexth.wu.hu   vr5,     vr2           // p
+    vslli.w       vr6,     vr4,      7
+    vslli.w       vr7,     vr5,      7
+    vsllwil.w.h   vr8,     vr1,      0   // dst
+    vexth.w.h     vr9,     vr1           // dst
+    vsub.w        vr8,     vr8,      vr4
+    vsub.w        vr9,     vr9,      vr5
+    vmadd.w       vr6,     vr8,      vr3  // v 0 - 3
+    vmadd.w       vr7,     vr9,      vr3  // v 4 - 7
+
+    vsllwil.w.h   vr11,    vr10,     0    // dst1
+    vexth.w.h     vr12,    vr10           // dst1
+    vsub.w        vr11,    vr11,     vr4
+    vsub.w        vr12,    vr12,     vr5
+    vmadd.w       vr6,     vr11,     vr13
+    vmadd.w       vr7,     vr12,     vr13
+
+    vssrarni.hu.w vr7,     vr6,      11
+    vssrlni.bu.h  vr7,     vr7,      0
+    addi.d        t0,      a0,       0
+.LSGRMIX_REM_ST:
+    vstelm.b      vr7,     t0,       0,    0
+    addi.d        t0,      t0,       1
+    vbsrl.v       vr7,     vr7,      1
+    addi.w        t4,      t4,       -1
+    bnez          t4,      .LSGRMIX_REM_ST
+
+    addi.w        a7,      a7,       -1
+    add.d         a0,      a0,       a1
+    addi.d        a2,      a2,       (FILTER_OUT_STRIDE<<1)
+    addi.d        a3,      a3,       (FILTER_OUT_STRIDE<<1)
+    bnez          a7,      .LSGRMIX_REM
+
+.LSGR_MIX_END:
+endfunc
+
+.macro MADD_HU_BU_LASX in0, in1, out0, out1
+    xvsllwil.hu.bu xr12,     \in0,     0
+    xvexth.hu.bu   xr13,     \in0
+    xvmadd.h       \out0,    xr12,     \in1
+    xvmadd.h       \out1,    xr13,     \in1
+.endm
+
+const wiener_shuf_lasx
+.byte 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
+.byte 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
+endconst
+
+function wiener_filter_h_8bpc_lasx
+    addi.d         sp,       sp,       -40
+    fst.d          f24,      sp,       0
+    fst.d          f25,      sp,       8
+    fst.d          f26,      sp,       16
+    fst.d          f27,      sp,       24
+    fst.d          f28,      sp,       32
+    li.w           t7,       1<<14          // clip_limit
+
+    la.local       t1,       wiener_shuf_lasx
+    xvld           xr4,      t1,       0
+    vld            vr27,     a2,       0    // filter[0][k]
+    xvpermi.q      xr14,     xr27,     0b00000000
+    xvrepl128vei.h xr21,     xr14,     0
+    xvrepl128vei.h xr22,     xr14,     1
+    xvrepl128vei.h xr23,     xr14,     2
+    xvrepl128vei.h xr24,     xr14,     3
+    xvrepl128vei.h xr25,     xr14,     4
+    xvrepl128vei.h xr26,     xr14,     5
+    xvrepl128vei.h xr27,     xr14,     6
+    xvreplgr2vr.w  xr0,      t7
+
+.WIENER_FILTER_H_H_LASX:
+    addi.w         a4,       a4,       -1    // h
+    addi.w         t0,       a3,       0     // w
+    addi.d         t1,       a1,       0     // tmp_ptr
+    addi.d         t2,       a0,       0     // hor_ptr
+
+.WIENER_FILTER_H_W_LASX:
+    addi.w         t0,       t0,       -32
+    xvld           xr5,      t1,       0
+    xvld           xr13,     t1,       16
+
+    xvsubi.bu      xr14,     xr4,      2
+    xvsubi.bu      xr15,     xr4,      1
+    xvshuf.b       xr6,      xr13,     xr5,     xr14  // 1 ... 8, 9 ... 16
+    xvshuf.b       xr7,      xr13,     xr5,     xr15  // 2 ... 9, 10 ... 17
+    xvshuf.b       xr8,      xr13,     xr5,     xr4   // 3 ... 10, 11 ... 18
+    xvaddi.bu      xr14,     xr4,      1
+    xvaddi.bu      xr15,     xr4,      2
+    xvshuf.b       xr9,      xr13,     xr5,     xr14  // 4 ... 11, 12 ... 19
+    xvshuf.b       xr10,     xr13,     xr5,     xr15  // 5 ... 12, 13 ... 20
+    xvaddi.bu      xr14,     xr4,      3
+    xvshuf.b       xr11,     xr13,     xr5,     xr14  // 6 ... 13, 14 ... 21
+
+    xvsllwil.hu.bu xr15,     xr8,      0    //  3  4  5  6  7  8  9 10
+    xvexth.hu.bu   xr16,     xr8            // 11 12 13 14 15 16 17 18
+    xvsllwil.wu.hu xr17,     xr15,     7    //  3  4  5  6
+    xvexth.wu.hu   xr18,     xr15           //  7  8  9 10
+    xvsllwil.wu.hu xr19,     xr16,     7    // 11 12 13 14
+    xvexth.wu.hu   xr20,     xr16           // 15 16 17 18
+    xvslli.w       xr18,     xr18,     7
+    xvslli.w       xr20,     xr20,     7
+    xvxor.v        xr15,     xr15,     xr15
+    xvxor.v        xr14,     xr14,     xr14
+
+    MADD_HU_BU_LASX xr5,  xr21, xr14, xr15
+    MADD_HU_BU_LASX xr6,  xr22, xr14, xr15
+    MADD_HU_BU_LASX xr7,  xr23, xr14, xr15
+    MADD_HU_BU_LASX xr8,  xr24, xr14, xr15
+    MADD_HU_BU_LASX xr9,  xr25, xr14, xr15
+    MADD_HU_BU_LASX xr10, xr26, xr14, xr15
+    MADD_HU_BU_LASX xr11, xr27, xr14, xr15
+
+    xvsllwil.w.h   xr5,      xr14,     0   //  0  1  2  3
+    xvexth.w.h     xr6,      xr14          //  4  5  6  7
+    xvsllwil.w.h   xr7,      xr15,     0   //  8  9 10 11
+    xvexth.w.h     xr8,      xr15          // 12 13 14 15
+    xvadd.w        xr17,     xr17,     xr5
+    xvadd.w        xr18,     xr18,     xr6
+    xvadd.w        xr19,     xr19,     xr7
+    xvadd.w        xr20,     xr20,     xr8
+    xvadd.w        xr17,     xr17,     xr0
+    xvadd.w        xr18,     xr18,     xr0
+    xvadd.w        xr19,     xr19,     xr0
+    xvadd.w        xr20,     xr20,     xr0
+
+    xvsrli.w       xr1,      xr0,      1
+    xvsubi.wu      xr1,      xr1,      1
+    xvxor.v        xr3,      xr3,      xr3
+    xvsrari.w      xr17,     xr17,     3
+    xvsrari.w      xr18,     xr18,     3
+    xvsrari.w      xr19,     xr19,     3
+    xvsrari.w      xr20,     xr20,     3
+    xvclip.w       xr17,     xr17,     xr3,     xr1
+    xvclip.w       xr18,     xr18,     xr3,     xr1
+    xvclip.w       xr19,     xr19,     xr3,     xr1
+    xvclip.w       xr20,     xr20,     xr3,     xr1
+
+    xvor.v         xr5,      xr17,     xr17
+    xvor.v         xr6,      xr19,     xr19
+    xvpermi.q      xr17,     xr18,     0b00000010
+    xvpermi.q      xr19,     xr20,     0b00000010
+
+    xvst           xr17,     t2,       0
+    xvst           xr19,     t2,       32
+    xvpermi.q      xr18,     xr5,      0b00110001
+    xvpermi.q      xr20,     xr6,      0b00110001
+    xvst           xr18,     t2,       64
+    xvst           xr20,     t2,       96
+    addi.d         t1,       t1,       32
+    addi.d         t2,       t2,       128
+    blt            zero,     t0,       .WIENER_FILTER_H_W_LASX
+
+    addi.d         a1,       a1,       REST_UNIT_STRIDE
+    addi.d         a0,       a0,       (REST_UNIT_STRIDE << 2)
+    bnez           a4,       .WIENER_FILTER_H_H_LASX
+
+    fld.d          f24,      sp,       0
+    fld.d          f25,      sp,       8
+    fld.d          f26,      sp,       16
+    fld.d          f27,      sp,       24
+    fld.d          f28,      sp,       32
+    addi.d         sp,       sp,       40
+endfunc
+
+.macro APPLY_FILTER_LASX in0, in1, in2
+    alsl.d         t7,       \in0,     \in1,    2
+    xvld           xr10,     t7,       0
+    xvld           xr12,     t7,       32
+    xvmadd.w       xr14,     xr10,     \in2
+    xvmadd.w       xr16,     xr12,     \in2
+.endm
+
+.macro wiener_filter_v_8bpc_core_lasx
+    xvreplgr2vr.w  xr14,     t6
+    xvreplgr2vr.w  xr16,     t6
+
+    addi.w         t7,       t2,       0      // j + index k
+    mul.w          t7,       t7,       t8     // (j + index) * REST_UNIT_STRIDE
+    add.w          t7,       t7,       t4     // (j + index) * REST_UNIT_STRIDE + i
+
+    APPLY_FILTER_LASX  t7, a2, xr2
+    APPLY_FILTER_LASX  t8, t7, xr3
+    APPLY_FILTER_LASX  t8, t7, xr4
+    APPLY_FILTER_LASX  t8, t7, xr5
+    APPLY_FILTER_LASX  t8, t7, xr6
+    APPLY_FILTER_LASX  t8, t7, xr7
+    APPLY_FILTER_LASX  t8, t7, xr8
+    xvssrarni.hu.w xr16,     xr14,      11
+    xvpermi.d      xr17,     xr16,      0b11011000
+    xvssrlni.bu.h  xr17,     xr17,      0
+    xvpermi.d      xr17,     xr17,      0b00001000
+.endm
+
+function wiener_filter_v_8bpc_lasx
+    li.w          t6,       -(1 << 18)
+
+    li.w          t8,       REST_UNIT_STRIDE
+    ld.h          t0,       a3,       0
+    ld.h          t1,       a3,       2
+    xvreplgr2vr.w xr2,      t0
+    xvreplgr2vr.w xr3,      t1
+    ld.h          t0,       a3,       4
+    ld.h          t1,       a3,       6
+    xvreplgr2vr.w xr4,      t0
+    xvreplgr2vr.w xr5,      t1
+    ld.h          t0,       a3,       8
+    ld.h          t1,       a3,       10
+    xvreplgr2vr.w xr6,      t0
+    xvreplgr2vr.w xr7,      t1
+    ld.h          t0,       a3,       12
+    xvreplgr2vr.w xr8,      t0
+
+    andi          t1,       a4,       0xf
+    sub.w         t0,       a4,       t1    // w-w%16
+    or            t2,       zero,     zero  // j
+    or            t4,       zero,     zero
+    beqz          t0,       .WIENER_FILTER_V_W_LT16_LASX
+
+.WIENER_FILTER_V_H_LASX:
+    andi          t1,       a4,       0xf
+    add.d         t3,       zero,     a0     // p
+    or            t4,       zero,     zero   // i
+
+.WIENER_FILTER_V_W_LASX:
+
+    wiener_filter_v_8bpc_core_lasx
+
+    mul.w         t5,       t2,       a1   // j * stride
+    add.w         t5,       t5,       t4   // j * stride + i
+    add.d         t3,       a0,       t5
+    addi.w        t4,       t4,       16
+    vst           vr17,     t3,       0
+    bne           t0,       t4,       .WIENER_FILTER_V_W_LASX
+
+    beqz          t1,       .WIENER_FILTER_V_W_EQ16_LASX
+
+    wiener_filter_v_8bpc_core_lsx
+
+    addi.d        t3,       t3,       16
+    andi          t1,       a4,       0xf
+
+.WIENER_FILTER_V_ST_REM_LASX:
+    vstelm.b      vr17,     t3,       0,    0
+    vbsrl.v       vr17,     vr17,     1
+    addi.d        t3,       t3,       1
+    addi.w        t1,       t1,       -1
+    bnez          t1,       .WIENER_FILTER_V_ST_REM_LASX
+.WIENER_FILTER_V_W_EQ16_LASX:
+    addi.w        t2,       t2,       1
+    blt           t2,       a5,       .WIENER_FILTER_V_H_LASX
+    b              .WIENER_FILTER_V_LASX_END
+
+.WIENER_FILTER_V_W_LT16_LASX:
+    andi          t1,       a4,       0xf
+    add.d         t3,       zero,     a0
+
+    wiener_filter_v_8bpc_core_lsx
+
+    mul.w         t5,       t2,       a1   // j * stride
+    add.d         t3,       a0,       t5
+
+.WIENER_FILTER_V_ST_REM_1_LASX:
+    vstelm.b      vr17,     t3,       0,    0
+    vbsrl.v       vr17,     vr17,     1
+    addi.d        t3,       t3,       1
+    addi.w        t1,       t1,       -1
+    bnez          t1,       .WIENER_FILTER_V_ST_REM_1_LASX
+
+    addi.w        t2,       t2,       1
+    blt           t2,       a5,       .WIENER_FILTER_V_W_LT16_LASX
+
+.WIENER_FILTER_V_LASX_END:
+endfunc
+
+function boxsum3_sgf_h_8bpc_lasx
+    addi.d         a0,       a0,        (REST_UNIT_STRIDE<<2)+12  // AA
+    //addi.d        a0,       a0,        12   // AA
+    addi.d         a1,       a1,        (REST_UNIT_STRIDE<<1)+6   // BB
+    //addi.d        a1,       a1,        6    // BB
+    la.local       t8,       dav1d_sgr_x_by_x
+    li.w           t6,       455
+    xvreplgr2vr.w  xr20,     t6
+    li.w           t6,       255
+    xvreplgr2vr.w  xr22,     t6
+    xvaddi.wu      xr21,     xr22,      1  // 256
+    xvreplgr2vr.w  xr6,      a4
+    xvldi          xr19,     0x809
+    addi.w         a2,       a2,        2  // w + 2
+    addi.w         a3,       a3,        2  // h + 2
+
+.LBS3SGF_H_H_LASX:
+    addi.w         t2,       a2,        0
+    addi.d         t0,       a0,        -4
+    addi.d         t1,       a1,        -2
+
+.LBS3SGF_H_W_LASX:
+    addi.w         t2,       t2,        -16
+    xvld           xr0,      t0,        0   // AA[i]
+    xvld           xr1,      t0,        32
+    xvld           xr2,      t1,        0   // BB[i]
+
+    xvmul.w        xr4,      xr0,       xr19 // a * n
+    xvmul.w        xr5,      xr1,       xr19
+    vext2xv.w.h    xr9,      xr2
+    xvpermi.q      xr10,     xr2,       0b00000001
+    vext2xv.w.h    xr10,     xr10
+    xvmsub.w       xr4,      xr9,       xr9  // p
+    xvmsub.w       xr5,      xr10,      xr10
+    xvmaxi.w       xr4,      xr4,       0
+    xvmaxi.w       xr5,      xr5,       0
+    xvmul.w        xr4,      xr4,       xr6  // p * s
+    xvmul.w        xr5,      xr5,       xr6
+    xvsrlri.w      xr4,      xr4,       20
+    xvsrlri.w      xr5,      xr5,       20
+    xvmin.w        xr4,      xr4,       xr22
+    xvmin.w        xr5,      xr5,       xr22
+
+    vpickve2gr.w   t6,       vr4,       0
+    ldx.bu         t7,       t8,        t6
+    vinsgr2vr.w    vr7,      t7,        0
+    vpickve2gr.w   t6,       vr4,       1
+    ldx.bu         t7,       t8,        t6
+    vinsgr2vr.w    vr7,      t7,        1
+    vpickve2gr.w   t6,       vr4,       2
+    ldx.bu         t7,       t8,        t6
+    vinsgr2vr.w    vr7,      t7,        2
+    vpickve2gr.w   t6,       vr4,       3
+    ldx.bu         t7,       t8,        t6
+    vinsgr2vr.w    vr7,      t7,        3
+
+    xvpickve2gr.w  t6,       xr4,       4
+    ldx.bu         t7,       t8,        t6
+    xvinsgr2vr.w   xr7,      t7,        4
+    xvpickve2gr.w  t6,       xr4,       5
+    ldx.bu         t7,       t8,        t6
+    xvinsgr2vr.w   xr7,      t7,        5
+    xvpickve2gr.w  t6,       xr4,       6
+    ldx.bu         t7,       t8,        t6
+    xvinsgr2vr.w   xr7,      t7,        6
+    xvpickve2gr.w  t6,       xr4,       7
+    ldx.bu         t7,       t8,        t6
+    xvinsgr2vr.w   xr7,      t7,        7     // x
+
+    vpickve2gr.w   t6,       vr5,       0
+    ldx.bu         t7,       t8,        t6
+    vinsgr2vr.w    vr8,      t7,        0
+    vpickve2gr.w   t6,       vr5,       1
+    ldx.bu         t7,       t8,        t6
+    vinsgr2vr.w    vr8,      t7,        1
+    vpickve2gr.w   t6,       vr5,       2
+    ldx.bu         t7,       t8,        t6
+    vinsgr2vr.w    vr8,      t7,        2
+    vpickve2gr.w   t6,       vr5,       3
+    ldx.bu         t7,       t8,        t6
+    vinsgr2vr.w    vr8,      t7,        3
+
+    xvpickve2gr.w  t6,       xr5,       4
+    ldx.bu         t7,       t8,        t6
+    xvinsgr2vr.w   xr8,      t7,        4
+    xvpickve2gr.w  t6,       xr5,       5
+    ldx.bu         t7,       t8,        t6
+    xvinsgr2vr.w   xr8,      t7,        5
+    xvpickve2gr.w  t6,       xr5,       6
+    ldx.bu         t7,       t8,        t6
+    xvinsgr2vr.w   xr8,      t7,        6
+    xvpickve2gr.w  t6,       xr5,       7
+    ldx.bu         t7,       t8,        t6
+    xvinsgr2vr.w   xr8,      t7,        7     // x
+
+    xvmul.w        xr9,      xr7,       xr9   // x * BB[i]
+    xvmul.w        xr10,     xr8,       xr10
+    xvmul.w        xr9,      xr9,       xr20  // x * BB[i] * sgr_one_by_x
+    xvmul.w        xr10,     xr10,      xr20
+    xvsrlri.w      xr9,      xr9,       12
+    xvsrlri.w      xr10,     xr10,      12
+    xvsub.w        xr7,      xr21,      xr7
+    xvsub.w        xr8,      xr21,      xr8
+    xvpickev.h     xr12,     xr8,       xr7
+    xvpermi.d      xr11,     xr12,      0b11011000
+
+    xvst           xr9,      t0,        0
+    xvst           xr10,     t0,        32
+    xvst           xr11,     t1,        0
+    addi.d         t0,       t0,        64
+    addi.d         t1,       t1,        32
+    blt            zero,     t2,        .LBS3SGF_H_W_LASX
+
+    addi.d         a0,       a0,        REST_UNIT_STRIDE<<2
+    addi.d         a1,       a1,        REST_UNIT_STRIDE<<1
+    addi.w         a3,       a3,        -1
+    bnez           a3,       .LBS3SGF_H_H_LASX
+endfunc
+
+function boxsum3_h_8bpc_lasx
+    addi.d         a2,      a2,      REST_UNIT_STRIDE
+    li.w           t0,      1
+    addi.w         a3,      a3,      -2
+    addi.w         a4,      a4,      -4
+.LBS3_H_H_LASX:
+    alsl.d         t1,      t0,      a1,    1     // sum_v    *sum_v = sum + x
+    alsl.d         t2,      t0,      a0,    2     // sumsq_v  *sumsq_v = sumsq + x
+    add.d          t3,      t0,      a2           // s
+    addi.w         t5,      a3,      0
+
+.LBS3_H_W_LASX:
+    xvld           xr0,     t3,      0
+    xvld           xr1,     t3,      REST_UNIT_STRIDE
+    xvld           xr2,     t3,      (REST_UNIT_STRIDE<<1)
+
+    xvilvl.b       xr3,     xr1,     xr0
+    xvhaddw.hu.bu  xr4,     xr3,     xr3
+    xvilvh.b       xr5,     xr1,     xr0
+    xvhaddw.hu.bu  xr6,     xr5,     xr5
+    xvsllwil.hu.bu xr7,     xr2,     0
+    xvexth.hu.bu   xr8,     xr2
+    // sum_v
+    xvadd.h        xr4,     xr4,     xr7  // 0 2
+    xvadd.h        xr6,     xr6,     xr8  // 1 3
+    xvor.v         xr9,     xr4,     xr4
+    xvpermi.q      xr4,     xr6,     0b00000010
+    xvpermi.q      xr6,     xr9,     0b00110001
+    xvst           xr4,     t1,      REST_UNIT_STRIDE<<1
+    xvst           xr6,     t1,      (REST_UNIT_STRIDE<<1)+32
+    addi.d         t1,      t1,      64
+    // sumsq
+    xvmulwev.h.bu  xr9,     xr3,     xr3
+    xvmulwod.h.bu  xr10,    xr3,     xr3
+    xvmulwev.h.bu  xr11,    xr5,     xr5
+    xvmulwod.h.bu  xr12,    xr5,     xr5
+    xvaddwev.w.hu  xr13,    xr10,    xr9
+    xvaddwod.w.hu  xr14,    xr10,    xr9
+    xvaddwev.w.hu  xr15,    xr12,    xr11
+    xvaddwod.w.hu  xr16,    xr12,    xr11
+    xvmaddwev.w.hu xr13,    xr7,     xr7
+    xvmaddwod.w.hu xr14,    xr7,     xr7
+    xvmaddwev.w.hu xr15,    xr8,     xr8
+    xvmaddwod.w.hu xr16,    xr8,     xr8
+    xvilvl.w       xr9,     xr14,    xr13
+    xvilvh.w       xr10,    xr14,    xr13
+    xvilvl.w       xr11,    xr16,    xr15
+    xvilvh.w       xr12,    xr16,    xr15
+    xvor.v         xr7,     xr9,     xr9
+    xvor.v         xr8,     xr11,    xr11
+    xvpermi.q      xr9,     xr10,    0b00000010
+    xvpermi.q      xr10,    xr7,     0b00110001
+    xvpermi.q      xr11,    xr12,    0b00000010
+    xvpermi.q      xr12,    xr8,     0b00110001
+    xvst           xr9,     t2,      REST_UNIT_STRIDE<<2
+    xvst           xr11,    t2,      (REST_UNIT_STRIDE<<2)+32
+    xvst           xr10,    t2,      (REST_UNIT_STRIDE<<2)+64
+    xvst           xr12,    t2,      (REST_UNIT_STRIDE<<2)+96
+
+    addi.d         t2,      t2,      128
+    addi.w         t5,      t5,      -32
+    addi.d         t3,      t3,      32
+    blt            zero,    t5,      .LBS3_H_W_LASX
+
+    addi.d         a0,      a0,      REST_UNIT_STRIDE<<2
+    addi.d         a1,      a1,      REST_UNIT_STRIDE<<1
+    addi.d         a2,      a2,      REST_UNIT_STRIDE
+    addi.d         a4,      a4,      -1
+    blt            zero,    a4,      .LBS3_H_H_LASX
+endfunc
diff --git a/media/libdav1d/src/src/loongarch/looprestoration.h b/media/libdav1d/src/src/loongarch/looprestoration.h
new file mode 100644
index 0000000000..2e05f8634c
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/looprestoration.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_LOOPRESTORATION_H
+#define DAV1D_SRC_LOONGARCH_LOOPRESTORATION_H
+
+#include "common/intops.h"
+#include "src/cpu.h"
+#include "src/looprestoration.h"
+
+void dav1d_wiener_filter_lsx(uint8_t *p, const ptrdiff_t stride,
+                             const uint8_t (*const left)[4],
+                             const uint8_t *lpf,
+                             const int w, const int h,
+                             const LooprestorationParams *const params,
+                             const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+void dav1d_wiener_filter_lasx(uint8_t *p, const ptrdiff_t stride,
+                             const uint8_t (*const left)[4],
+                             const uint8_t *lpf,
+                             const int w, const int h,
+                             const LooprestorationParams *const params,
+                             const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+void dav1d_sgr_filter_3x3_lsx(pixel *p, const ptrdiff_t p_stride,
+                              const pixel (*const left)[4],
+                              const pixel *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+void dav1d_sgr_filter_3x3_lasx(pixel *p, const ptrdiff_t p_stride,
+                              const pixel (*const left)[4],
+                              const pixel *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+void dav1d_sgr_filter_5x5_lsx(pixel *p, const ptrdiff_t p_stride,
+                              const pixel (*const left)[4],
+                              const pixel *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+void dav1d_sgr_filter_mix_lsx(pixel *p, const ptrdiff_t p_stride,
+                              const pixel (*const left)[4],
+                              const pixel *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+void dav1d_sgr_filter_mix_lasx(pixel *p, const ptrdiff_t p_stride,
+                               const pixel (*const left)[4],
+                               const pixel *lpf,
+                               const int w, const int h,
+                               const LooprestorationParams *const params,
+                               const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+static ALWAYS_INLINE void loop_restoration_dsp_init_loongarch(Dav1dLoopRestorationDSPContext *const c, int bpc)
+{
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LSX)) return;
+
+#if BITDEPTH == 8
+    c->wiener[0] = c->wiener[1] = dav1d_wiener_filter_lsx;
+
+    c->sgr[0] = dav1d_sgr_filter_5x5_lsx;
+    c->sgr[1] = dav1d_sgr_filter_3x3_lsx;
+    c->sgr[2] = dav1d_sgr_filter_mix_lsx;
+#endif
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LASX)) return;
+
+#if BITDEPTH == 8
+    c->wiener[0] = c->wiener[1] = dav1d_wiener_filter_lasx;
+
+    c->sgr[1] = dav1d_sgr_filter_3x3_lasx;
+#endif
+}
+
+#endif /* DAV1D_SRC_LOONGARCH_LOOPRESTORATION_H */
diff --git a/media/libdav1d/src/src/loongarch/looprestoration_inner.c b/media/libdav1d/src/src/loongarch/looprestoration_inner.c
new file mode 100644
index 0000000000..926c20474a
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/looprestoration_inner.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/loongarch/looprestoration.h"
+
+#if BITDEPTH == 8
+
+#define REST_UNIT_STRIDE (400)
+
+void BF(dav1d_wiener_filter_h, lsx)(int32_t *hor_ptr,
+                                    uint8_t *tmp_ptr,
+                                    const int16_t filterh[8],
+                                    const int w, const int h);
+
+void BF(dav1d_wiener_filter_h, lasx)(int32_t *hor_ptr,
+                                     uint8_t *tmp_ptr,
+                                     const int16_t filterh[8],
+                                     const int w, const int h);
+
+void BF(dav1d_wiener_filter_v, lsx)(uint8_t *p,
+                                    const ptrdiff_t p_stride,
+                                    const int32_t *hor,
+                                    const int16_t filterv[8],
+                                    const int w, const int h);
+
+void BF(dav1d_wiener_filter_v, lasx)(uint8_t *p,
+                                     const ptrdiff_t p_stride,
+                                     const int32_t *hor,
+                                     const int16_t filterv[8],
+                                     const int w, const int h);
+
+// This function refers to the function in the ppc/looprestoration_init_tmpl.c.
+static inline void padding(uint8_t *dst, const uint8_t *p,
+                           const ptrdiff_t stride, const uint8_t (*left)[4],
+                           const uint8_t *lpf, int unit_w, const int stripe_h,
+                           const enum LrEdgeFlags edges)
+{
+    const int have_left = !!(edges & LR_HAVE_LEFT);
+    const int have_right = !!(edges & LR_HAVE_RIGHT);
+
+    // Copy more pixels if we don't have to pad them
+    unit_w += 3 * have_left + 3 * have_right;
+    uint8_t *dst_l = dst + 3 * !have_left;
+    p -= 3 * have_left;
+    lpf -= 3 * have_left;
+
+    if (edges & LR_HAVE_TOP) {
+        // Copy previous loop filtered rows
+        const uint8_t *const above_1 = lpf;
+        const uint8_t *const above_2 = above_1 + PXSTRIDE(stride);
+        pixel_copy(dst_l, above_1, unit_w);
+        pixel_copy(dst_l + REST_UNIT_STRIDE, above_1, unit_w);
+        pixel_copy(dst_l + 2 * REST_UNIT_STRIDE, above_2, unit_w);
+    } else {
+        // Pad with first row
+        pixel_copy(dst_l, p, unit_w);
+        pixel_copy(dst_l + REST_UNIT_STRIDE, p, unit_w);
+        pixel_copy(dst_l + 2 * REST_UNIT_STRIDE, p, unit_w);
+        if (have_left) {
+            pixel_copy(dst_l, &left[0][1], 3);
+            pixel_copy(dst_l + REST_UNIT_STRIDE, &left[0][1], 3);
+            pixel_copy(dst_l + 2 * REST_UNIT_STRIDE, &left[0][1], 3);
+        }
+    }
+
+    uint8_t *dst_tl = dst_l + 3 * REST_UNIT_STRIDE;
+    if (edges & LR_HAVE_BOTTOM) {
+        // Copy next loop filtered rows
+        const uint8_t *const below_1 = lpf + 6 * PXSTRIDE(stride);
+        const uint8_t *const below_2 = below_1 + PXSTRIDE(stride);
+        pixel_copy(dst_tl + stripe_h * REST_UNIT_STRIDE, below_1, unit_w);
+        pixel_copy(dst_tl + (stripe_h + 1) * REST_UNIT_STRIDE, below_2, unit_w);
+        pixel_copy(dst_tl + (stripe_h + 2) * REST_UNIT_STRIDE, below_2, unit_w);
+    } else {
+        // Pad with last row
+        const uint8_t *const src = p + (stripe_h - 1) * PXSTRIDE(stride);
+        pixel_copy(dst_tl + stripe_h * REST_UNIT_STRIDE, src, unit_w);
+        pixel_copy(dst_tl + (stripe_h + 1) * REST_UNIT_STRIDE, src, unit_w);
+        pixel_copy(dst_tl + (stripe_h + 2) * REST_UNIT_STRIDE, src, unit_w);
+        if (have_left) {
+            pixel_copy(dst_tl + stripe_h * REST_UNIT_STRIDE, &left[stripe_h - 1][1], 3);
+            pixel_copy(dst_tl + (stripe_h + 1) * REST_UNIT_STRIDE, &left[stripe_h - 1][1], 3);
+            pixel_copy(dst_tl + (stripe_h + 2) * REST_UNIT_STRIDE, &left[stripe_h - 1][1], 3);
+        }
+    }
+
+    // Inner UNIT_WxSTRIPE_H
+    for (int j = 0; j < stripe_h; j++) {
+        pixel_copy(dst_tl + 3 * have_left, p + 3 * have_left, unit_w - 3 * have_left);
+        dst_tl += REST_UNIT_STRIDE;
+        p += PXSTRIDE(stride);
+    }
+
+    if (!have_right) {
+        uint8_t *pad = dst_l + unit_w;
+        uint8_t *row_last = &dst_l[unit_w - 1];
+        // Pad 3x(STRIPE_H+6) with last column
+        for (int j = 0; j < stripe_h + 6; j++) {
+            pixel_set(pad, *row_last, 3);
+            pad += REST_UNIT_STRIDE;
+            row_last += REST_UNIT_STRIDE;
+        }
+    }
+
+    if (!have_left) {
+        // Pad 3x(STRIPE_H+6) with first column
+        for (int j = 0; j < stripe_h + 6; j++) {
+            pixel_set(dst, *dst_l, 3);
+            dst += REST_UNIT_STRIDE;
+            dst_l += REST_UNIT_STRIDE;
+        }
+    } else {
+        dst += 3 * REST_UNIT_STRIDE;
+        for (int j = 0; j < stripe_h; j++) {
+            pixel_copy(dst, &left[j][1], 3);
+            dst += REST_UNIT_STRIDE;
+        }
+    }
+}
+
+// This function refers to the function in the ppc/looprestoration_init_tmpl.c.
+
+// FIXME Could split into luma and chroma specific functions,
+// (since first and last tops are always 0 for chroma)
+// FIXME Could implement a version that requires less temporary memory
+// (should be possible to implement with only 6 rows of temp storage)
+void dav1d_wiener_filter_lsx(uint8_t *p, const ptrdiff_t p_stride,
+                              const uint8_t (*const left)[4],
+                              const uint8_t *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    const int16_t (*const filter)[8] = params->filter;
+
+    // Wiener filtering is applied to a maximum stripe height of 64 + 3 pixels
+    // of padding above and below
+    ALIGN_STK_16(uint8_t, tmp, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE,);
+    padding(tmp, p, p_stride, left, lpf, w, h, edges);
+    ALIGN_STK_16(int32_t, hor, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE + 64,);
+
+    BF(dav1d_wiener_filter_h, lsx)(hor, tmp, filter[0], w, h + 6);
+    BF(dav1d_wiener_filter_v, lsx)(p, p_stride, hor, filter[1], w, h);
+}
+
+void dav1d_wiener_filter_lasx(uint8_t *p, const ptrdiff_t p_stride,
+                              const uint8_t (*const left)[4],
+                              const uint8_t *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    const int16_t (*const filter)[8] = params->filter;
+
+    // Wiener filtering is applied to a maximum stripe height of 64 + 3 pixels
+    // of padding above and below
+    ALIGN_STK_16(uint8_t, tmp, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE,);
+    padding(tmp, p, p_stride, left, lpf, w, h, edges);
+    ALIGN_STK_16(int32_t, hor, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE + 64,);
+
+    BF(dav1d_wiener_filter_h, lasx)(hor, tmp, filter[0], w, h + 6);
+    BF(dav1d_wiener_filter_v, lasx)(p, p_stride, hor, filter[1], w, h);
+}
+
+void BF(dav1d_boxsum3_h, lsx)(int32_t *sumsq, int16_t *sum, pixel *src,
+                              const int w, const int h);
+void BF(dav1d_boxsum3_v, lsx)(int32_t *sumsq, int16_t *sum,
+                              const int w, const int h);
+
+void BF(dav1d_boxsum3_sgf_h, lsx)(int32_t *sumsq, int16_t *sum,
+                                  const int w, const int h, const int w1);
+void BF(dav1d_boxsum3_sgf_v, lsx)(int16_t *dst, uint8_t *tmp,
+                                  int32_t *sumsq, int16_t *sum,
+                                  const int w, const int h);
+void BF(dav1d_sgr_3x3_finish, lsx)(pixel *p, const ptrdiff_t p_stride,
+                                   int16_t *dst, int w1,
+                                   const int w, const int h);
+
+void BF(dav1d_boxsum3_h, lasx)(int32_t *sumsq, int16_t *sum, pixel *src,
+                               const int w, const int h);
+void BF(dav1d_boxsum3_sgf_h, lasx)(int32_t *sumsq, int16_t *sum,
+                                   const int w, const int h, const int w1);
+void BF(dav1d_boxsum3_sgf_v, lasx)(int16_t *dst, uint8_t *tmp,
+                                   int32_t *sumsq, int16_t *sum,
+                                   const int w, const int h);
+
+static inline void boxsum3_lsx(int32_t *sumsq, coef *sum, pixel *src,
+                               const int w, const int h)
+{
+    BF(dav1d_boxsum3_h, lsx)(sumsq, sum, src, w + 6, h + 6);
+    BF(dav1d_boxsum3_v, lsx)(sumsq, sum, w + 6, h + 6);
+}
+
+static inline void boxsum3_lasx(int32_t *sumsq, coef *sum, pixel *src,
+                               const int w, const int h)
+{
+    BF(dav1d_boxsum3_h, lasx)(sumsq, sum, src, w + 6, h + 6);
+    BF(dav1d_boxsum3_v, lsx)(sumsq, sum, w + 6, h + 6);
+}
+
+void dav1d_sgr_filter_3x3_lsx(pixel *p, const ptrdiff_t p_stride,
+                              const pixel (*const left)[4],
+                              const pixel *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(uint8_t, tmp, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE,);
+    padding(tmp, p, p_stride, left, lpf, w, h, edges);
+    coef dst[64 * 384];
+
+    ALIGN_STK_16(int32_t, sumsq, 68 * REST_UNIT_STRIDE + 8, );
+    ALIGN_STK_16(int16_t, sum, 68 * REST_UNIT_STRIDE + 16, );
+
+    boxsum3_lsx(sumsq, sum, tmp, w, h);
+    BF(dav1d_boxsum3_sgf_h, lsx)(sumsq, sum, w, h, params->sgr.s1);
+    BF(dav1d_boxsum3_sgf_v, lsx)(dst, tmp, sumsq, sum, w, h);
+    BF(dav1d_sgr_3x3_finish, lsx)(p, p_stride, dst, params->sgr.w1, w, h);
+}
+
+void dav1d_sgr_filter_3x3_lasx(pixel *p, const ptrdiff_t p_stride,
+                              const pixel (*const left)[4],
+                              const pixel *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(uint8_t, tmp, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE,);
+    padding(tmp, p, p_stride, left, lpf, w, h, edges);
+    coef dst[64 * 384];
+
+    ALIGN_STK_16(int32_t, sumsq, 68 * REST_UNIT_STRIDE + 8, );
+    ALIGN_STK_16(int16_t, sum, 68 * REST_UNIT_STRIDE + 16, );
+
+    boxsum3_lasx(sumsq, sum, tmp, w, h);
+    BF(dav1d_boxsum3_sgf_h, lasx)(sumsq, sum, w, h, params->sgr.s1);
+    BF(dav1d_boxsum3_sgf_v, lasx)(dst, tmp, sumsq, sum, w, h);
+    BF(dav1d_sgr_3x3_finish, lsx)(p, p_stride, dst, params->sgr.w1, w, h);
+}
+
+void BF(dav1d_boxsum5_h, lsx)(int32_t *sumsq, int16_t *sum,
+                              const uint8_t *const src,
+                              const int w, const int h);
+
+void BF(dav1d_boxsum5_v, lsx)(int32_t *sumsq, int16_t *sum,
+                              const int w, const int h);
+
+void BF(dav1d_boxsum5_sgf_h, lsx)(int32_t *sumsq, int16_t *sum,
+                                  const int w, const int h,
+                                  const unsigned s);
+
+void BF(dav1d_boxsum5_sgf_v, lsx)(int16_t *dst, uint8_t *src,
+                                  int32_t *sumsq, int16_t *sum,
+                                  const int w, const int h);
+
+void BF(dav1d_sgr_mix_finish, lsx)(uint8_t *p, const ptrdiff_t stride,
+                                   const int16_t *dst0, const int16_t *dst1,
+                                   const int w0, const int w1,
+                                   const int w, const int h);
+
+static inline void boxsum5_lsx(int32_t *sumsq, coef *sum, pixel *src,
+                               const int w, const int h)
+{
+    BF(dav1d_boxsum5_h, lsx)(sumsq, sum, src, w + 6, h + 6);
+    BF(dav1d_boxsum5_v, lsx)(sumsq, sum, w + 6, h + 6);
+}
+
+void dav1d_sgr_filter_5x5_lsx(pixel *p, const ptrdiff_t p_stride,
+                              const pixel (*const left)[4],
+                              const pixel *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(uint8_t, tmp, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE,);
+    padding(tmp, p, p_stride, left, lpf, w, h, edges);
+    coef dst[64 * 384];
+
+    ALIGN_STK_16(int32_t, sumsq, 68 * REST_UNIT_STRIDE + 8, );
+    ALIGN_STK_16(int16_t, sum, 68 * REST_UNIT_STRIDE + 16, );
+
+    boxsum5_lsx(sumsq, sum, tmp, w, h);
+    BF(dav1d_boxsum5_sgf_h, lsx)(sumsq, sum, w, h, params->sgr.s0);
+    BF(dav1d_boxsum5_sgf_v, lsx)(dst, tmp, sumsq, sum, w, h);
+    BF(dav1d_sgr_3x3_finish, lsx)(p, p_stride, dst, params->sgr.w0, w, h);
+}
+
+void dav1d_sgr_filter_mix_lsx(pixel *p, const ptrdiff_t p_stride,
+                              const pixel (*const left)[4],
+                              const pixel *lpf,
+                              const int w, const int h,
+                              const LooprestorationParams *const params,
+                              const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(uint8_t, tmp, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE,);
+    padding(tmp, p, p_stride, left, lpf, w, h, edges);
+    coef dst0[64 * 384];
+    coef dst1[64 * 384];
+
+    ALIGN_STK_16(int32_t, sumsq0, 68 * REST_UNIT_STRIDE + 8, );
+    ALIGN_STK_16(int16_t, sum0, 68 * REST_UNIT_STRIDE + 16, );
+
+    boxsum5_lsx(sumsq0, sum0, tmp, w, h);
+    BF(dav1d_boxsum5_sgf_h, lsx)(sumsq0, sum0, w, h, params->sgr.s0);
+    BF(dav1d_boxsum5_sgf_v, lsx)(dst0, tmp, sumsq0, sum0, w, h);
+
+    boxsum3_lsx(sumsq0, sum0, tmp, w, h);
+    BF(dav1d_boxsum3_sgf_h, lsx)(sumsq0, sum0, w, h, params->sgr.s1);
+    BF(dav1d_boxsum3_sgf_v, lsx)(dst1, tmp, sumsq0, sum0, w, h);
+
+    BF(dav1d_sgr_mix_finish, lsx)(p, p_stride, dst0, dst1, params->sgr.w0,
+                                   params->sgr.w1, w, h);
+}
+#endif
diff --git a/media/libdav1d/src/src/loongarch/mc.S b/media/libdav1d/src/src/loongarch/mc.S
new file mode 100644
index 0000000000..42c595d8b6
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/mc.S
@@ -0,0 +1,6145 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/loongarch/loongson_asm.S"
+
+/*
+static void warp_affine_8x8_c(pixel *dst, const ptrdiff_t dst_stride,
+                              const pixel *src, const ptrdiff_t src_stride,
+                              const int16_t *const abcd, int mx, int my
+                              HIGHBD_DECL_SUFFIX)
+*/
+.macro vld_filter_row dst, src, inc
+    addi.w          t3,       \src,     512
+    srai.w          t3,       t3,       10
+    add.w           \src,     \src,     \inc
+    addi.w          t3,       t3,       64
+    slli.w          t3,       t3,       3
+    fldx.d          \dst,     t4,       t3
+.endm
+
+.macro warp_filter_horz_lsx
+    addi.w          t5,       a5,       0
+    vld             vr10,     a2,       0
+    add.d           a2,       a2,       a3
+
+    vld_filter_row f0, t5, t0
+    vld_filter_row f1, t5, t0
+    vld_filter_row f2, t5, t0
+    vld_filter_row f3, t5, t0
+    vld_filter_row f4, t5, t0
+    vld_filter_row f5, t5, t0
+    vld_filter_row f6, t5, t0
+    vld_filter_row f7, t5, t0
+
+    vxor.v          vr10,     vr10,     vr20
+
+    vbsrl.v         vr8,      vr10,     1
+    vbsrl.v         vr9,      vr10,     2
+    vilvl.d         vr8,      vr8,      vr10
+    vilvl.d         vr0,      vr1,      vr0
+    vmulwev.h.b     vr11,     vr8,      vr0
+    vmulwod.h.b     vr12,     vr8,      vr0
+    vbsrl.v         vr8,      vr10,     3
+    vbsrl.v         vr19,     vr10,     4
+    vilvl.d         vr8,      vr8,      vr9
+    vilvl.d         vr2,      vr3,      vr2
+    vmulwev.h.b     vr13,     vr8,      vr2
+    vmulwod.h.b     vr14,     vr8,      vr2
+    vbsrl.v         vr8,      vr10,     5
+    vbsrl.v         vr9,      vr10,     6
+    vilvl.d         vr8,      vr8,      vr19
+    vilvl.d         vr4,      vr5,      vr4
+    vmulwev.h.b     vr15,     vr8,      vr4
+    vmulwod.h.b     vr16,     vr8,      vr4
+    vbsrl.v         vr8,      vr10,     7
+    vilvl.d         vr8,      vr8,      vr9
+    vilvl.d         vr6,      vr7,      vr6
+    vmulwev.h.b     vr17,     vr8,      vr6
+    vmulwod.h.b     vr18,     vr8,      vr6
+
+    vadd.h          vr11,     vr11,     vr12
+    vadd.h          vr13,     vr13,     vr14
+    vadd.h          vr15,     vr15,     vr16
+    vadd.h          vr17,     vr17,     vr18
+    vpickev.h       vr12,     vr13,     vr11
+    vpickod.h       vr14,     vr13,     vr11
+    vpickev.h       vr16,     vr17,     vr15
+    vpickod.h       vr18,     vr17,     vr15
+    vadd.h          vr11,     vr12,     vr14
+    vadd.h          vr15,     vr16,     vr18
+    vpickev.h       vr12,     vr15,     vr11
+    vpickod.h       vr14,     vr15,     vr11
+    vadd.h          vr11,     vr12,     vr14
+
+    add.d           a5,       a5,       t1
+.endm
+
+.macro transpose_8x8b_extend_lsx in0, in1, in2, in3, in4, in5, in6, in7
+    vilvl.b         \in0,     \in1,     \in0
+    vilvl.b         \in2,     \in3,     \in2
+    vilvl.b         \in4,     \in5,     \in4
+    vilvl.b         \in6,     \in7,     \in6
+
+    vpackev.h       \in1,     \in2,     \in0
+    vpackod.h       \in3,     \in2,     \in0
+    vpackev.h       \in5,     \in6,     \in4
+    vpackod.h       \in7,     \in6,     \in4
+
+    vpackev.w       \in0,     \in5,     \in1
+    vpackod.w       \in2,     \in5,     \in1
+    vpackev.w       \in1,     \in7,     \in3
+    vpackod.w       \in3,     \in7,     \in3
+
+    vexth.h.b       \in4,     \in0
+    vsllwil.h.b     \in0,     \in0,     0
+    vexth.h.b       \in5,     \in1
+    vsllwil.h.b     \in1,     \in1,     0
+    vexth.h.b       \in6,     \in2
+    vsllwil.h.b     \in2,     \in2,     0
+    vexth.h.b       \in7,     \in3
+    vsllwil.h.b     \in3,     \in3,     0
+.endm
+
+.macro warp t, shift
+function warp_affine_8x8\t\()_8bpc_lsx
+    addi.d          sp,       sp,      -64
+    fst.d           f24,      sp,      0
+    fst.d           f25,      sp,      8
+    fst.d           f26,      sp,      16
+    fst.d           f27,      sp,      24
+    fst.d           f28,      sp,      32
+    fst.d           f29,      sp,      40
+    fst.d           f30,      sp,      48
+    fst.d           f31,      sp,      56
+
+    ld.h            t0,       a4,      0
+    ld.h            t1,       a4,      2
+    ld.h            t2,       a4,      4
+    ld.h            a4,       a4,      6
+
+    li.d            t7,       8
+    alsl.w          t3,       a3,      a3,     1
+    sub.d           a2,       a2,      t3
+    addi.d          a2,       a2,      -3
+    la.local        t4,       dav1d_mc_warp_filter
+
+.ifnb \t
+    slli.d          a1,       a1,      1
+.endif
+
+    li.w            t3,       128
+    vreplgr2vr.b    vr20,     t3
+.ifb \t
+    vreplgr2vr.h    vr21,     t3
+.else
+    li.w            t3,       2048
+    vreplgr2vr.h    vr21,     t3
+.endif
+    warp_filter_horz_lsx
+    vsrari.h        vr24,     vr11,    3
+    warp_filter_horz_lsx
+    vsrari.h        vr25,     vr11,    3
+    warp_filter_horz_lsx
+    vsrari.h        vr26,     vr11,    3
+    warp_filter_horz_lsx
+    vsrari.h        vr27,     vr11,    3
+    warp_filter_horz_lsx
+    vsrari.h        vr28,     vr11,    3
+    warp_filter_horz_lsx
+    vsrari.h        vr29,     vr11,    3
+    warp_filter_horz_lsx
+    vsrari.h        vr30,     vr11,    3
+
+1:
+    addi.d          t6,       a6,      0
+    warp_filter_horz_lsx
+    vsrari.h        vr31,     vr11,    3
+
+    vld_filter_row f0, t6, t2
+    vld_filter_row f1, t6, t2
+    vld_filter_row f2, t6, t2
+    vld_filter_row f3, t6, t2
+    vld_filter_row f4, t6, t2
+    vld_filter_row f5, t6, t2
+    vld_filter_row f6, t6, t2
+    vld_filter_row f7, t6, t2
+
+    transpose_8x8b_extend_lsx vr0, vr1, vr2, vr3, vr4, vr5, vr6, vr7
+
+    vmulwev.w.h     vr16,     vr24,    vr0
+    vmulwod.w.h     vr17,     vr24,    vr0
+    vmaddwev.w.h    vr16,     vr25,    vr1
+    vmaddwod.w.h    vr17,     vr25,    vr1
+    vmaddwev.w.h    vr16,     vr26,    vr2
+    vmaddwod.w.h    vr17,     vr26,    vr2
+    vmaddwev.w.h    vr16,     vr27,    vr3
+    vmaddwod.w.h    vr17,     vr27,    vr3
+    vmaddwev.w.h    vr16,     vr28,    vr4
+    vmaddwod.w.h    vr17,     vr28,    vr4
+    vmaddwev.w.h    vr16,     vr29,    vr5
+    vmaddwod.w.h    vr17,     vr29,    vr5
+    vmaddwev.w.h    vr16,     vr30,    vr6
+    vmaddwod.w.h    vr17,     vr30,    vr6
+    vmaddwev.w.h    vr16,     vr31,    vr7
+    vmaddwod.w.h    vr17,     vr31,    vr7
+
+    vssrarni.h.w    vr16,     vr16,    \shift
+    vssrarni.h.w    vr17,     vr17,    \shift
+    vilvl.h         vr16,     vr17,    vr16
+    vadd.h          vr16,     vr16,    vr21
+
+    vor.v           vr24,     vr25,    vr25
+    vor.v           vr25,     vr26,    vr26
+    vor.v           vr26,     vr27,    vr27
+    vor.v           vr27,     vr28,    vr28
+    vor.v           vr28,     vr29,    vr29
+    vor.v           vr29,     vr30,    vr30
+    vor.v           vr30,     vr31,    vr31
+
+.ifb \t
+    vssrarni.bu.h   vr16,     vr16,    0
+.endif
+
+    addi.d          t7,       t7,      -1
+.ifnb \t
+    vst             vr16,     a0,      0
+.else
+    vstelm.d        vr16,     a0,      0,   0
+.endif
+    add.d           a0,       a1,      a0
+
+    add.d           a6,       a6,      a4
+    blt             zero,     t7,      1b
+
+    fld.d           f24,      sp,      0
+    fld.d           f25,      sp,      8
+    fld.d           f26,      sp,      16
+    fld.d           f27,      sp,      24
+    fld.d           f28,      sp,      32
+    fld.d           f29,      sp,      40
+    fld.d           f30,      sp,      48
+    fld.d           f31,      sp,      56
+    addi.d          sp,       sp,      64
+endfunc
+.endm
+
+warp  , 11
+warp t, 7
+
+.macro FILTER_WARP_RND_P_LASX in0, in1, in2, out0, out1, out2, out3
+    xvshuf.b        xr2,    \in0,     \in0,     \in2
+
+    addi.w          t4,     \in1,     512
+    srai.w          t4,     t4,       10
+    addi.w          t4,     t4,       64
+    slli.w          t4,     t4,       3
+    vldx            vr3,    t5,       t4
+    add.w           t3,     t3,       t0   // tmx += abcd[0]
+
+    addi.w          t4,     t3,       512
+    srai.w          t4,     t4,       10
+    addi.w          t4,     t4,       64
+    slli.w          t4,     t4,       3
+    vldx            vr4,    t5,       t4
+    add.w           t3,     t3,       t0   // tmx += abcd[0]
+
+    addi.w          t4,     t3,       512
+    srai.w          t4,     t4,       10
+    addi.w          t4,     t4,       64
+    slli.w          t4,     t4,       3
+    vldx            vr5,    t5,       t4
+    add.w           t3,     t3,       t0   // tmx += abcd[0]
+
+    addi.w          t4,     t3,       512
+    srai.w          t4,     t4,       10
+    addi.w          t4,     t4,       64
+    slli.w          t4,     t4,       3
+    vldx            vr6,    t5,       t4
+    add.w           t3,     t3,       t0   // tmx += abcd[0]
+
+    xvinsve0.d      xr3,    xr5,      1
+    xvinsve0.d      xr3,    xr4,      2
+    xvinsve0.d      xr3,    xr6,      3
+
+    xvmulwev.h.bu.b xr4,    xr2,      xr3
+    xvmulwod.h.bu.b xr5,    xr2,      xr3
+    xvilvl.d        xr2,    xr5,      xr4
+    xvilvh.d        xr3,    xr5,      xr4
+    xvhaddw.w.h     xr2,    xr2,      xr2
+    xvhaddw.w.h     xr3,    xr3,      xr3
+    xvhaddw.d.w     xr2,    xr2,      xr2
+    xvhaddw.d.w     xr3,    xr3,      xr3
+    xvhaddw.q.d     xr2,    xr2,      xr2
+    xvhaddw.q.d     xr3,    xr3,      xr3
+
+    xvextrins.w     \out0,  xr2,      \out1
+    xvextrins.w     \out2,  xr3,      \out3
+.endm
+
+.macro FILTER_WARP_CLIP_LASX in0, in1, in2, out0, out1
+    add.w           \in0,     \in0,    \in1
+    addi.w          t6,       \in0,    512
+    srai.w          t6,       t6,      10
+    addi.w          t6,       t6,      64
+    slli.w          t6,       t6,      3
+    fldx.d          f1,       t5,      t6
+
+    add.w           t2,       t2,      t7
+    addi.w          t6,       t2,      512
+    srai.w          t6,       t6,      10
+    addi.w          t6,       t6,      64
+    slli.w          t6,       t6,      3
+    fldx.d          f2,       t5,      t6
+
+    vilvl.d         vr0,      vr2,     vr1
+    vext2xv.h.b     xr0,      xr0
+    xvmulwev.w.h    xr3,      \in2,    xr0
+    xvmaddwod.w.h   xr3,      \in2,    xr0
+    xvhaddw.d.w     xr3,      xr3,     xr3
+    xvhaddw.q.d     xr3,      xr3,     xr3
+    xvextrins.w     \out0,    xr3,     \out1
+.endm
+
+const shuf0
+.byte  0, 1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 9
+.byte  1, 2, 3, 4, 5, 6, 7, 8, 3, 4, 5, 6, 7, 8, 9, 10
+endconst
+
+const warp_sh
+.rept 2
+.byte 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+.endr
+.rept 2
+.byte 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+.endr
+endconst
+
+.macro warp_lasx t, shift
+function warp_affine_8x8\t\()_8bpc_lasx
+    addi.d          sp,       sp,      -16
+    ld.h            t0,       a4,      0   // abcd[0]
+    ld.h            t1,       a4,      2   // abcd[1]
+    fst.d           f24,      sp,      0
+    fst.d           f25,      sp,      8
+
+    alsl.w          t2,       a3,      a3,     1
+    addi.w          t3,       a5,      0
+    la.local        t4,       warp_sh
+    la.local        t5,       dav1d_mc_warp_filter
+    sub.d           a2,       a2,      t2
+    addi.d          a2,       a2,      -3
+    vld             vr0,      a2,      0
+    xvld            xr24,     t4,      0
+    xvld            xr25,     t4,      32
+    la.local        t2,       shuf0
+    xvld            xr1,      t2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    xvaddi.bu        xr9,    xr1,      4
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr7, 0x00, xr8, 0x00
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr10, 0x00, xr11, 0x00
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr7, 0x10, xr8, 0x10
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr10, 0x10, xr11, 0x10
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr7, 0x20, xr8, 0x20
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr10, 0x20, xr11, 0x20
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr7, 0x30, xr8, 0x30
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr10, 0x30, xr11, 0x30
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr12, 0x00, xr13, 0x00
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr14, 0x00, xr15, 0x00
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr12, 0x10, xr13, 0x10
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr14, 0x10, xr15, 0x10
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr12, 0x20, xr13, 0x20
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr14, 0x20, xr15, 0x20
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr12, 0x30, xr13, 0x30
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr14, 0x30, xr15, 0x30
+
+    xvsrarni.h.w    xr12,     xr7,     3
+    xvsrarni.h.w    xr13,     xr8,     3
+    xvsrarni.h.w    xr14,     xr10,    3
+    xvsrarni.h.w    xr15,     xr11,    3
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr7, 0x00, xr8, 0x00
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr10, 0x00, xr11, 0x00
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr7, 0x10, xr8, 0x10
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr10, 0x10, xr11, 0x10
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr7, 0x20, xr8, 0x20
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr10, 0x20, xr11, 0x20
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr7, 0x30, xr8, 0x30
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr10, 0x30, xr11, 0x30
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr16, 0x00, xr17, 0x00
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr18, 0x00, xr19, 0x00
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr16, 0x10, xr17, 0x10
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr18, 0x10, xr19, 0x10
+
+    add.w           a5,       a5,      t1
+    or              t3,       a5,      a5
+    add.d           a2,       a2,      a3
+    vld             vr0,      a2,      0
+    xvpermi.q       xr0,      xr0,     0x00
+    FILTER_WARP_RND_P_LASX xr0, a5, xr1, xr16, 0x20, xr17, 0x20
+    FILTER_WARP_RND_P_LASX xr0, t3, xr9, xr18, 0x20, xr19, 0x20
+
+    xvsrarni.h.w    xr16,     xr7,     3
+    xvsrarni.h.w    xr17,     xr8,     3
+    xvsrarni.h.w    xr18,     xr10,    3
+    xvsrarni.h.w    xr19,     xr11,    3
+
+    addi.w          t2,       a6,      0   // my
+    ld.h            t7,       a4,      4   // abcd[2]
+    ld.h            t8,       a4,      6   // abcd[3]
+
+.ifnb \t
+    slli.d          a1,       a1,      1
+.endif
+
+    // y = 0
+    FILTER_WARP_CLIP_LASX  t2, zero, xr12,  xr20, 0x00
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr13,  xr20, 0x10
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr14,  xr20, 0x20
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr15,  xr20, 0x30
+
+    xvshuf.b         xr12,     xr16,    xr12,   xr24
+    xvshuf.b         xr13,     xr17,    xr13,   xr24
+    xvshuf.b         xr14,     xr18,    xr14,   xr24
+    xvshuf.b         xr15,     xr19,    xr15,   xr24
+    xvextrins.h      xr24,     xr25,    0x70
+
+    add.w           a6,       a6,      t8
+    addi.w          t2,       a6,      0
+    FILTER_WARP_CLIP_LASX  t2, zero, xr12,  xr21, 0x00
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr13,  xr21, 0x10
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr14,  xr21, 0x20
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr15,  xr21, 0x30
+
+.ifnb \t
+    xvssrarni.h.w   xr21,     xr20,     \shift
+    xvpermi.q       xr22,     xr21,     0x01
+    vilvl.h         vr23,     vr22,     vr21
+    vilvh.h         vr21,     vr22,     vr21
+    vst             vr23,     a0,       0
+    vstx            vr21,     a0,       a1
+.else
+    xvssrarni.hu.w   xr21,    xr20,     \shift
+    xvssrlni.bu.h    xr22,    xr21,     0
+    xvpermi.q        xr23,    xr22,     0x01
+    vilvl.b          vr21,    vr23,     vr22
+    fst.d            f21,     a0,       0
+    add.d            a0,      a0,       a1
+    vstelm.d         vr21,    a0,       0,     1
+.endif
+
+    xvaddi.bu        xr25,     xr25,    2
+    xvshuf.b         xr12,     xr16,    xr12,   xr24
+    xvshuf.b         xr13,     xr17,    xr13,   xr24
+    xvshuf.b         xr14,     xr18,    xr14,   xr24
+    xvshuf.b         xr15,     xr19,    xr15,   xr24
+    xvextrins.h      xr24,     xr25,    0x70
+
+    add.w           a6,       a6,      t8
+    addi.w          t2,       a6,      0
+    FILTER_WARP_CLIP_LASX  t2, zero, xr12,  xr20, 0x00
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr13,  xr20, 0x10
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr14,  xr20, 0x20
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr15,  xr20, 0x30
+
+    xvaddi.bu        xr25,     xr25,    2
+    xvshuf.b         xr12,     xr16,    xr12,   xr24
+    xvshuf.b         xr13,     xr17,    xr13,   xr24
+    xvshuf.b         xr14,     xr18,    xr14,   xr24
+    xvshuf.b         xr15,     xr19,    xr15,   xr24
+    xvextrins.h      xr24,     xr25,    0x70
+
+    add.w           a6,       a6,      t8
+    addi.w          t2,       a6,      0
+    FILTER_WARP_CLIP_LASX  t2, zero, xr12,  xr21, 0x00
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr13,  xr21, 0x10
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr14,  xr21, 0x20
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr15,  xr21, 0x30
+
+.ifnb \t
+    xvssrarni.h.w   xr21,     xr20,     \shift
+    alsl.d          a0,       a1,       a0,     1
+    xvpermi.q       xr22,     xr21,     0x01
+    vilvl.h         vr23,     vr22,     vr21
+    vilvh.h         vr21,     vr22,     vr21
+    vst             vr23,     a0,       0
+    vstx            vr21,     a0,       a1
+.else
+    xvssrarni.hu.w   xr21,    xr20,     11
+    xvssrlni.bu.h    xr22,    xr21,     0
+    xvpermi.q        xr23,    xr22,     0x01
+    vilvl.b          vr21,    vr23,     vr22
+    add.d            a0,      a0,       a1
+    fst.d            f21,     a0,       0
+    add.d            a0,      a0,       a1
+    vstelm.d         vr21,    a0,       0,     1
+.endif
+
+    xvaddi.bu        xr25,     xr25,    2
+    xvshuf.b         xr12,     xr16,    xr12,   xr24
+    xvshuf.b         xr13,     xr17,    xr13,   xr24
+    xvshuf.b         xr14,     xr18,    xr14,   xr24
+    xvshuf.b         xr15,     xr19,    xr15,   xr24
+    xvextrins.h      xr24,     xr25,    0x70
+
+    add.w           a6,       a6,      t8
+    addi.w          t2,       a6,      0
+    FILTER_WARP_CLIP_LASX  t2, zero, xr12,  xr20, 0x00
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr13,  xr20, 0x10
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr14,  xr20, 0x20
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr15,  xr20, 0x30
+
+    xvaddi.bu        xr25,     xr25,    2
+    xvshuf.b         xr12,     xr16,    xr12,   xr24
+    xvshuf.b         xr13,     xr17,    xr13,   xr24
+    xvshuf.b         xr14,     xr18,    xr14,   xr24
+    xvshuf.b         xr15,     xr19,    xr15,   xr24
+    xvextrins.h      xr24,     xr25,    0x70
+
+    add.w           a6,       a6,      t8
+    addi.w          t2,       a6,      0
+    FILTER_WARP_CLIP_LASX  t2, zero, xr12,  xr21, 0x00
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr13,  xr21, 0x10
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr14,  xr21, 0x20
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr15,  xr21, 0x30
+
+.ifnb \t
+    xvssrarni.h.w   xr21,     xr20,     \shift
+    alsl.d          a0,       a1,       a0,     1
+    xvpermi.q       xr22,     xr21,     0x01
+    vilvl.h         vr23,     vr22,     vr21
+    vilvh.h         vr21,     vr22,     vr21
+    vst             vr23,     a0,       0
+    vstx            vr21,     a0,       a1
+.else
+    xvssrarni.hu.w   xr21,    xr20,     11
+    xvssrlni.bu.h    xr22,    xr21,     0
+    xvpermi.q        xr23,    xr22,     0x01
+    vilvl.b          vr21,    vr23,     vr22
+    add.d            a0,      a0,       a1
+    fst.d            f21,     a0,       0
+    add.d            a0,      a0,       a1
+    vstelm.d         vr21,    a0,       0,     1
+.endif
+
+    xvaddi.bu        xr25,     xr25,    2
+    xvshuf.b         xr12,     xr16,    xr12,   xr24
+    xvshuf.b         xr13,     xr17,    xr13,   xr24
+    xvshuf.b         xr14,     xr18,    xr14,   xr24
+    xvshuf.b         xr15,     xr19,    xr15,   xr24
+    xvextrins.h      xr24,     xr25,    0x70
+
+    add.w           a6,       a6,      t8
+    addi.w          t2,       a6,      0
+    FILTER_WARP_CLIP_LASX  t2, zero, xr12,  xr20, 0x00
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr13,  xr20, 0x10
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr14,  xr20, 0x20
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr15,  xr20, 0x30
+
+    xvshuf.b         xr12,     xr16,    xr12,   xr24
+    xvshuf.b         xr13,     xr17,    xr13,   xr24
+    xvshuf.b         xr14,     xr18,    xr14,   xr24
+    xvshuf.b         xr15,     xr19,    xr15,   xr24
+
+    add.w           a6,       a6,      t8
+    addi.w          t2,       a6,      0
+    FILTER_WARP_CLIP_LASX  t2, zero, xr12,  xr21, 0x00
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr13,  xr21, 0x10
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr14,  xr21, 0x20
+    FILTER_WARP_CLIP_LASX  t2, t7,   xr15,  xr21, 0x30
+
+.ifnb \t
+    xvssrarni.h.w   xr21,     xr20,     \shift
+    alsl.d          a0,       a1,       a0,     1
+    xvpermi.q       xr22,     xr21,     0x01
+    vilvl.h         vr23,     vr22,     vr21
+    vilvh.h         vr21,     vr22,     vr21
+    vst             vr23,     a0,       0
+    vstx            vr21,     a0,       a1
+.else
+    xvssrarni.hu.w   xr21,    xr20,     11
+    xvssrlni.bu.h    xr22,    xr21,     0
+    xvpermi.q        xr23,    xr22,     0x01
+    vilvl.b          vr21,    vr23,     vr22
+    add.d            a0,      a0,       a1
+    fst.d            f21,     a0,       0
+    add.d            a0,      a0,       a1
+    vstelm.d         vr21,    a0,       0,     1
+.endif
+    fld.d            f24,     sp,       0
+    fld.d            f25,     sp,       8
+    addi.d           sp,      sp,       16
+endfunc
+.endm
+
+warp_lasx , 11
+warp_lasx t, 7
+
+/*
+static void w_avg_c(pixel *dst, const ptrdiff_t dst_stride,
+                    const int16_t *tmp1, const int16_t *tmp2,
+                    const int w, int h,
+                    const int weight HIGHBD_DECL_SUFFIX)
+*/
+
+#define bpc8_sh     5     // sh = intermediate_bits + 1
+#define bpcw8_sh    8     // sh = intermediate_bits + 4
+
+#define bpc_sh   bpc8_sh
+#define bpcw_sh  bpcw8_sh
+
+function avg_8bpc_lsx
+    addi.d        t8,     a0,     0
+
+    clz.w         t0,     a4
+    li.w          t1,     24
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .AVG_LSX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0  // The jump addresses are relative to AVG_LSX_JRTABLE
+    add.d         t1,     t1,      t2 // Get absolute address
+    jirl          $r0,    t1,      0
+
+    .align   3
+.AVG_LSX_JRTABLE:
+    .hword .AVG_W128_LSX - .AVG_LSX_JRTABLE
+    .hword .AVG_W64_LSX  - .AVG_LSX_JRTABLE
+    .hword .AVG_W32_LSX  - .AVG_LSX_JRTABLE
+    .hword .AVG_W16_LSX  - .AVG_LSX_JRTABLE
+    .hword .AVG_W8_LSX   - .AVG_LSX_JRTABLE
+    .hword .AVG_W4_LSX   - .AVG_LSX_JRTABLE
+
+.AVG_W4_LSX:
+    vld           vr0,    a2,     0
+    vld           vr1,    a3,     0
+    vadd.h        vr2,    vr0,    vr1
+    vssrarni.bu.h vr3,    vr2,    bpc_sh
+    vstelm.w      vr3,    a0,     0,    0
+    add.d         a0,     a0,     a1
+    vstelm.w      vr3,    a0,     0,    1
+    addi.w        a5,     a5,     -2
+    addi.d        a2,     a2,     16
+    addi.d        a3,     a3,     16
+    add.d         a0,     a0,     a1
+    blt           zero,   a5,     .AVG_W4_LSX
+    b             .AVG_END_LSX
+
+.AVG_W8_LSX:
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vadd.h        vr4,    vr0,    vr1
+    vadd.h        vr5,    vr2,    vr3
+    vssrarni.bu.h vr5,    vr4,    bpc_sh
+    addi.w        a5,     a5,     -2
+    addi.d        a2,     a2,     32
+    vstelm.d      vr5,    a0,     0,    0
+    add.d         a0,     a0,     a1
+    vstelm.d      vr5,    a0,     0,    1
+    addi.d        a3,     a3,     32
+    add.d         a0,     a0,     a1
+    blt           zero,   a5,     .AVG_W8_LSX
+    b             .AVG_END_LSX
+
+.AVG_W16_LSX:
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vadd.h        vr4,    vr0,    vr1
+    vadd.h        vr5,    vr2,    vr3
+    vssrarni.bu.h vr5,    vr4,    bpc_sh
+    addi.w        a5,     a5,     -1
+    addi.d        a2,     a2,     32
+    vst           vr5,    a0,     0
+    addi.d        a3,     a3,     32
+    add.d         a0,     a0,     a1
+    blt           zero,   a5,     .AVG_W16_LSX
+    b             .AVG_END_LSX
+
+.AVG_W32_LSX:
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr4,    a2,     32
+    vld           vr6,    a2,     48
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vld           vr5,    a3,     32
+    vld           vr7,    a3,     48
+    vadd.h        vr0,    vr0,    vr1
+    vadd.h        vr2,    vr2,    vr3
+    vadd.h        vr4,    vr4,    vr5
+    vadd.h        vr6,    vr6,    vr7
+    vssrarni.bu.h vr2,    vr0,    bpc_sh
+    vssrarni.bu.h vr6,    vr4,    bpc_sh
+    addi.w        a5,     a5,     -1
+    addi.d        a2,     a2,     64
+    vst           vr2,    a0,     0
+    vst           vr6,    a0,     16
+    addi.d        a3,     a3,     64
+    add.d         a0,     a0,     a1
+    blt           zero,   a5,     .AVG_W32_LSX
+    b             .AVG_END_LSX
+
+.AVG_W64_LSX:
+.rept 4
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vadd.h        vr0,    vr0,    vr1
+    vadd.h        vr2,    vr2,    vr3
+    vssrarni.bu.h vr2,    vr0,    bpc_sh
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    vst           vr2,    a0,     0
+    addi.d        a0,     a0,     16
+.endr
+    addi.w        a5,     a5,     -1
+    add.d         t8,     t8,     a1
+    add.d         a0,     t8,     zero
+    blt           zero,   a5,     .AVG_W64_LSX
+    b             .AVG_END_LSX
+
+.AVG_W128_LSX:
+.rept 8
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vadd.h        vr0,    vr0,    vr1
+    vadd.h        vr2,    vr2,    vr3
+    vssrarni.bu.h vr2,    vr0,    bpc_sh
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    vst           vr2,    a0,     0
+    addi.d        a0,     a0,     16
+.endr
+    addi.w        a5,     a5,     -1
+    add.d         t8,     t8,     a1
+    add.d         a0,     t8,     zero
+    blt           zero,   a5,     .AVG_W128_LSX
+.AVG_END_LSX:
+endfunc
+
+function avg_8bpc_lasx
+    clz.w         t0,     a4
+    li.w          t1,     24
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .AVG_LASX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0
+    add.d         t1,     t1,      t2
+    jirl          $r0,    t1,      0
+
+    .align   3
+.AVG_LASX_JRTABLE:
+    .hword .AVG_W128_LASX - .AVG_LASX_JRTABLE
+    .hword .AVG_W64_LASX  - .AVG_LASX_JRTABLE
+    .hword .AVG_W32_LASX  - .AVG_LASX_JRTABLE
+    .hword .AVG_W16_LASX  - .AVG_LASX_JRTABLE
+    .hword .AVG_W8_LASX   - .AVG_LASX_JRTABLE
+    .hword .AVG_W4_LASX   - .AVG_LASX_JRTABLE
+
+.AVG_W4_LASX:
+    vld            vr0,    a2,     0
+    vld            vr1,    a3,     0
+    vadd.h         vr0,    vr0,    vr1
+    vssrarni.bu.h  vr1,    vr0,    bpc_sh
+    vstelm.w       vr1,    a0,     0,    0
+    add.d          a0,     a0,     a1
+    vstelm.w       vr1,    a0,     0,    1
+    addi.w         a5,     a5,     -2
+    addi.d         a2,     a2,     16
+    addi.d         a3,     a3,     16
+    add.d          a0,     a0,     a1
+    blt            zero,   a5,     .AVG_W4_LASX
+    b              .AVG_END_LASX
+.AVG_W8_LASX:
+    xvld           xr0,    a2,     0
+    xvld           xr1,    a3,     0
+    xvadd.h        xr2,    xr0,    xr1
+    xvssrarni.bu.h xr1,    xr2,    bpc_sh
+    xvstelm.d      xr1,    a0,     0,    0
+    add.d          a0,     a0,     a1
+    xvstelm.d      xr1,    a0,     0,    2
+    addi.w         a5,     a5,     -2
+    addi.d         a2,     a2,     32
+    addi.d         a3,     a3,     32
+    add.d          a0,     a1,     a0
+    blt            zero,   a5,     .AVG_W8_LASX
+    b              .AVG_END_LASX
+.AVG_W16_LASX:
+    xvld           xr0,    a2,     0
+    xvld           xr2,    a2,     32
+    xvld           xr1,    a3,     0
+    xvld           xr3,    a3,     32
+    xvadd.h        xr4,    xr0,    xr1
+    xvadd.h        xr5,    xr2,    xr3
+    xvssrarni.bu.h xr5,    xr4,    bpc_sh
+    xvpermi.d      xr2,    xr5,    0xd8
+    xvpermi.d      xr3,    xr5,    0x8d
+    vst            vr2,    a0,     0
+    vstx           vr3,    a0,     a1
+    addi.w         a5,     a5,     -2
+    addi.d         a2,     a2,     64
+    addi.d         a3,     a3,     64
+    alsl.d         a0,     a1,     a0,   1
+    blt            zero,   a5,     .AVG_W16_LASX
+    b              .AVG_END_LASX
+.AVG_W32_LASX:
+    xvld           xr0,    a2,     0
+    xvld           xr2,    a2,     32
+    xvld           xr1,    a3,     0
+    xvld           xr3,    a3,     32
+    xvadd.h        xr4,    xr0,    xr1
+    xvadd.h        xr5,    xr2,    xr3
+    xvssrarni.bu.h xr5,    xr4,    bpc_sh
+    xvpermi.d      xr6,    xr5,    0xd8
+    xvst           xr6,    a0,     0
+    addi.w         a5,     a5,     -1
+    addi.d         a2,     a2,     64
+    addi.d         a3,     a3,     64
+    add.d          a0,     a0,     a1
+    blt            zero,   a5,     .AVG_W32_LASX
+    b              .AVG_END_LASX
+.AVG_W64_LASX:
+    xvld           xr0,    a2,     0
+    xvld           xr2,    a2,     32
+    xvld           xr4,    a2,     64
+    xvld           xr6,    a2,     96
+    xvld           xr1,    a3,     0
+    xvld           xr3,    a3,     32
+    xvld           xr5,    a3,     64
+    xvld           xr7,    a3,     96
+    xvadd.h        xr0,    xr0,    xr1
+    xvadd.h        xr2,    xr2,    xr3
+    xvadd.h        xr4,    xr4,    xr5
+    xvadd.h        xr6,    xr6,    xr7
+    xvssrarni.bu.h xr2,    xr0,    bpc_sh
+    xvssrarni.bu.h xr6,    xr4,    bpc_sh
+    xvpermi.d      xr1,    xr2,    0xd8
+    xvpermi.d      xr3,    xr6,    0xd8
+    xvst           xr1,    a0,     0
+    xvst           xr3,    a0,     32
+    addi.w         a5,     a5,     -1
+    addi.d         a2,     a2,     128
+    addi.d         a3,     a3,     128
+    add.d          a0,     a0,     a1
+    blt            zero,   a5,     .AVG_W64_LASX
+    b              .AVG_END_LASX
+.AVG_W128_LASX:
+    xvld           xr0,    a2,     0
+    xvld           xr2,    a2,     32
+    xvld           xr4,    a2,     64
+    xvld           xr6,    a2,     96
+    xvld           xr8,    a2,     128
+    xvld           xr10,   a2,     160
+    xvld           xr12,   a2,     192
+    xvld           xr14,   a2,     224
+    xvld           xr1,    a3,     0
+    xvld           xr3,    a3,     32
+    xvld           xr5,    a3,     64
+    xvld           xr7,    a3,     96
+    xvld           xr9,    a3,     128
+    xvld           xr11,   a3,     160
+    xvld           xr13,   a3,     192
+    xvld           xr15,   a3,     224
+    xvadd.h        xr0,    xr0,    xr1
+    xvadd.h        xr2,    xr2,    xr3
+    xvadd.h        xr4,    xr4,    xr5
+    xvadd.h        xr6,    xr6,    xr7
+    xvadd.h        xr8,    xr8,    xr9
+    xvadd.h        xr10,   xr10,   xr11
+    xvadd.h        xr12,   xr12,   xr13
+    xvadd.h        xr14,   xr14,   xr15
+    xvssrarni.bu.h xr2,    xr0,    bpc_sh
+    xvssrarni.bu.h xr6,    xr4,    bpc_sh
+    xvssrarni.bu.h xr10,   xr8,    bpc_sh
+    xvssrarni.bu.h xr14,   xr12,   bpc_sh
+    xvpermi.d      xr1,    xr2,    0xd8
+    xvpermi.d      xr3,    xr6,    0xd8
+    xvpermi.d      xr5,    xr10,   0xd8
+    xvpermi.d      xr7,    xr14,   0xd8
+    xvst           xr1,    a0,     0
+    xvst           xr3,    a0,     32
+    xvst           xr5,    a0,     64
+    xvst           xr7,    a0,     96
+    addi.w         a5,     a5,     -1
+    addi.d         a2,     a2,     256
+    addi.d         a3,     a3,     256
+    add.d          a0,     a0,     a1
+    blt            zero,   a5,     .AVG_W128_LASX
+.AVG_END_LASX:
+endfunc
+
+function w_avg_8bpc_lsx
+    addi.d        t8,     a0,     0
+    li.w          t2,     16
+    sub.w         t2,     t2,     a6  // 16 - weight
+    vreplgr2vr.h  vr21,   a6
+    vreplgr2vr.h  vr22,   t2
+
+    clz.w         t0,     a4
+    li.w          t1,     24
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .W_AVG_LSX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0
+    add.d         t1,     t1,      t2
+    jirl          $r0,    t1,      0
+
+    .align   3
+.W_AVG_LSX_JRTABLE:
+    .hword .W_AVG_W128_LSX - .W_AVG_LSX_JRTABLE
+    .hword .W_AVG_W64_LSX  - .W_AVG_LSX_JRTABLE
+    .hword .W_AVG_W32_LSX  - .W_AVG_LSX_JRTABLE
+    .hword .W_AVG_W16_LSX  - .W_AVG_LSX_JRTABLE
+    .hword .W_AVG_W8_LSX   - .W_AVG_LSX_JRTABLE
+    .hword .W_AVG_W4_LSX   - .W_AVG_LSX_JRTABLE
+
+.W_AVG_W4_LSX:
+    vld           vr0,    a2,     0
+    vld           vr1,    a3,     0
+    vmulwev.w.h   vr2,    vr0,    vr21
+    vmulwod.w.h   vr3,    vr0,    vr21
+    vmaddwev.w.h  vr2,    vr1,    vr22
+    vmaddwod.w.h  vr3,    vr1,    vr22
+    vssrarni.hu.w vr3,    vr2,    bpcw_sh
+    vssrlni.bu.h  vr1,    vr3,    0
+    vpickod.w     vr4,    vr2,    vr1
+    vilvl.b       vr0,    vr4,    vr1
+    fst.s         f0,     a0,     0
+    add.d         a0,     a0,     a1
+    vstelm.w      vr0,    a0,     0,   1
+    addi.w        a5,     a5,     -2
+    addi.d        a2,     a2,     16
+    addi.d        a3,     a3,     16
+    add.d         a0,     a1,     a0
+    blt           zero,   a5,     .W_AVG_W4_LSX
+    b             .W_AVG_END_LSX
+.W_AVG_W8_LSX:
+    vld           vr0,    a2,     0
+    vld           vr1,    a3,     0
+    vmulwev.w.h   vr2,    vr0,    vr21
+    vmulwod.w.h   vr3,    vr0,    vr21
+    vmaddwev.w.h  vr2,    vr1,    vr22
+    vmaddwod.w.h  vr3,    vr1,    vr22
+    vssrarni.hu.w vr3,    vr2,    bpcw_sh
+    vssrlni.bu.h  vr1,    vr3,    0
+    vpickod.w     vr4,    vr2,    vr1
+    vilvl.b       vr0,    vr4,    vr1
+    fst.d         f0,     a0,     0
+    addi.w        a5,     a5,     -1
+    addi.d        a2,     a2,     16
+    addi.d        a3,     a3,     16
+    add.d         a0,     a0,     a1
+    blt           zero,   a5,     .W_AVG_W8_LSX
+    b             .W_AVG_END_LSX
+.W_AVG_W16_LSX:
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vmulwev.w.h   vr4,    vr0,    vr21
+    vmulwod.w.h   vr5,    vr0,    vr21
+    vmulwev.w.h   vr6,    vr2,    vr21
+    vmulwod.w.h   vr7,    vr2,    vr21
+    vmaddwev.w.h  vr4,    vr1,    vr22
+    vmaddwod.w.h  vr5,    vr1,    vr22
+    vmaddwev.w.h  vr6,    vr3,    vr22
+    vmaddwod.w.h  vr7,    vr3,    vr22
+    vssrarni.hu.w vr6,    vr4,    bpcw_sh
+    vssrarni.hu.w vr7,    vr5,    bpcw_sh
+    vssrlrni.bu.h vr7,    vr6,    0
+    vshuf4i.w     vr8,    vr7,    0x4E
+    vilvl.b       vr0,    vr8,    vr7
+    vst           vr0,    a0,     0
+    addi.w        a5,     a5,     -1
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    add.d         a0,     a0,     a1
+    blt           zero,   a5,     .W_AVG_W16_LSX
+    b             .W_AVG_END_LSX
+.W_AVG_W32_LSX:
+.rept 2
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vmulwev.w.h   vr4,    vr0,    vr21
+    vmulwod.w.h   vr5,    vr0,    vr21
+    vmulwev.w.h   vr6,    vr2,    vr21
+    vmulwod.w.h   vr7,    vr2,    vr21
+    vmaddwev.w.h  vr4,    vr1,    vr22
+    vmaddwod.w.h  vr5,    vr1,    vr22
+    vmaddwev.w.h  vr6,    vr3,    vr22
+    vmaddwod.w.h  vr7,    vr3,    vr22
+    vssrarni.hu.w vr6,    vr4,    bpcw_sh
+    vssrarni.hu.w vr7,    vr5,    bpcw_sh
+    vssrlrni.bu.h vr7,    vr6,    0
+    vshuf4i.w     vr8,    vr7,    0x4E
+    vilvl.b       vr0,    vr8,    vr7
+    vst           vr0,    a0,     0
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    addi.d        a0,     a0,     16
+.endr
+    addi.w        a5,     a5,     -1
+    add.d         t8,     t8,     a1
+    add.d         a0,     t8,     zero
+    blt           zero,   a5,     .W_AVG_W32_LSX
+    b             .W_AVG_END_LSX
+
+.W_AVG_W64_LSX:
+.rept 4
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vmulwev.w.h   vr4,    vr0,    vr21
+    vmulwod.w.h   vr5,    vr0,    vr21
+    vmulwev.w.h   vr6,    vr2,    vr21
+    vmulwod.w.h   vr7,    vr2,    vr21
+    vmaddwev.w.h  vr4,    vr1,    vr22
+    vmaddwod.w.h  vr5,    vr1,    vr22
+    vmaddwev.w.h  vr6,    vr3,    vr22
+    vmaddwod.w.h  vr7,    vr3,    vr22
+    vssrarni.hu.w vr6,    vr4,    bpcw_sh
+    vssrarni.hu.w vr7,    vr5,    bpcw_sh
+    vssrlrni.bu.h vr7,    vr6,    0
+    vshuf4i.w     vr8,    vr7,    0x4E
+    vilvl.b       vr0,    vr8,    vr7
+    vst           vr0,    a0,     0
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    addi.d        a0,     a0,     16
+.endr
+    addi.w        a5,     a5,     -1
+    add.d         t8,     t8,     a1
+    add.d         a0,     t8,     zero
+    blt           zero,   a5,     .W_AVG_W64_LSX
+    b             .W_AVG_END_LSX
+
+.W_AVG_W128_LSX:
+.rept 8
+    vld           vr0,    a2,     0
+    vld           vr2,    a2,     16
+    vld           vr1,    a3,     0
+    vld           vr3,    a3,     16
+    vmulwev.w.h   vr4,    vr0,    vr21
+    vmulwod.w.h   vr5,    vr0,    vr21
+    vmulwev.w.h   vr6,    vr2,    vr21
+    vmulwod.w.h   vr7,    vr2,    vr21
+    vmaddwev.w.h  vr4,    vr1,    vr22
+    vmaddwod.w.h  vr5,    vr1,    vr22
+    vmaddwev.w.h  vr6,    vr3,    vr22
+    vmaddwod.w.h  vr7,    vr3,    vr22
+    vssrarni.hu.w vr6,    vr4,    bpcw_sh
+    vssrarni.hu.w vr7,    vr5,    bpcw_sh
+    vssrlrni.bu.h vr7,    vr6,    0
+    vshuf4i.w     vr8,    vr7,    0x4E
+    vilvl.b       vr0,    vr8,    vr7
+    vst           vr0,    a0,     0
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    addi.d        a0,     a0,     16
+.endr
+    addi.w        a5,     a5,     -1
+    add.d         t8,     t8,     a1
+    add.d         a0,     t8,     zero
+    blt           zero,   a5,     .W_AVG_W128_LSX
+.W_AVG_END_LSX:
+endfunc
+
+function w_avg_8bpc_lasx
+    addi.d        t8,     a0,     0
+    li.w          t2,     16
+    sub.w         t2,     t2,     a6  // 16 - weight
+    xvreplgr2vr.h xr21,   a6
+    xvreplgr2vr.h xr22,   t2
+
+    clz.w         t0,     a4
+    li.w          t1,     24
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .W_AVG_LASX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0
+    add.d         t1,     t1,      t2
+    jirl          $r0,    t1,      0
+
+    .align   3
+.W_AVG_LASX_JRTABLE:
+    .hword .W_AVG_W128_LASX - .W_AVG_LASX_JRTABLE
+    .hword .W_AVG_W64_LASX  - .W_AVG_LASX_JRTABLE
+    .hword .W_AVG_W32_LASX  - .W_AVG_LASX_JRTABLE
+    .hword .W_AVG_W16_LASX  - .W_AVG_LASX_JRTABLE
+    .hword .W_AVG_W8_LASX   - .W_AVG_LASX_JRTABLE
+    .hword .W_AVG_W4_LASX   - .W_AVG_LASX_JRTABLE
+
+.W_AVG_W4_LASX:
+    vld            vr0,    a2,     0
+    vld            vr1,    a3,     0
+    xvpermi.d      xr2,    xr0,    0xD8
+    xvpermi.d      xr3,    xr1,    0xD8
+    xvilvl.h       xr4,    xr3,    xr2
+    xvmulwev.w.h   xr0,    xr4,    xr21
+    xvmaddwod.w.h  xr0,    xr4,    xr22
+    xvssrarni.hu.w xr1,    xr0,    bpcw_sh
+    xvssrlni.bu.h  xr0,    xr1,    0
+    fst.s          f0,     a0,     0
+    add.d          a0,     a0,     a1
+    xvstelm.w      xr0,    a0,     0,     4
+    addi.w         a5,     a5,     -2
+    addi.d         a2,     a2,     16
+    addi.d         a3,     a3,     16
+    add.d          a0,     a1,     a0
+    blt            zero,   a5,     .W_AVG_W4_LASX
+    b              .W_AVG_END_LASX
+
+.W_AVG_W8_LASX:
+    xvld           xr0,    a2,     0
+    xvld           xr1,    a3,     0
+    xvmulwev.w.h   xr2,    xr0,    xr21
+    xvmulwod.w.h   xr3,    xr0,    xr21
+    xvmaddwev.w.h  xr2,    xr1,    xr22
+    xvmaddwod.w.h  xr3,    xr1,    xr22
+    xvssrarni.hu.w xr3,    xr2,    bpcw_sh
+    xvssrlni.bu.h  xr1,    xr3,    0
+    xvpickod.w     xr4,    xr2,    xr1
+    xvilvl.b       xr0,    xr4,    xr1
+    xvstelm.d      xr0,    a0,     0,     0
+    add.d          a0,     a0,     a1
+    xvstelm.d      xr0,    a0,     0,     2
+    addi.w         a5,     a5,     -2
+    addi.d         a2,     a2,     32
+    addi.d         a3,     a3,     32
+    add.d          a0,     a0,     a1
+    blt            zero,   a5,     .W_AVG_W8_LASX
+    b              .W_AVG_END_LASX
+
+.W_AVG_W16_LASX:
+    xvld           xr0,    a2,     0
+    xvld           xr1,    a3,     0
+    xvmulwev.w.h   xr2,    xr0,    xr21
+    xvmulwod.w.h   xr3,    xr0,    xr21
+    xvmaddwev.w.h  xr2,    xr1,    xr22
+    xvmaddwod.w.h  xr3,    xr1,    xr22
+    xvssrarni.hu.w xr3,    xr2,    bpcw_sh
+    xvssrlni.bu.h  xr1,    xr3,    0
+    xvpickod.w     xr4,    xr2,    xr1
+    xvilvl.b       xr0,    xr4,    xr1
+    xvpermi.d      xr1,    xr0,    0xD8
+    vst            vr1,    a0,     0
+    addi.w         a5,     a5,     -1
+    addi.d         a2,     a2,     32
+    addi.d         a3,     a3,     32
+    add.d          a0,     a0,     a1
+    blt            zero,   a5,     .W_AVG_W16_LASX
+    b              .W_AVG_END_LSX
+
+.W_AVG_W32_LASX:
+    xvld           xr0,    a2,     0
+    xvld           xr2,    a2,     32
+    xvld           xr1,    a3,     0
+    xvld           xr3,    a3,     32
+    xvmulwev.w.h   xr4,    xr0,    xr21
+    xvmulwod.w.h   xr5,    xr0,    xr21
+    xvmulwev.w.h   xr6,    xr2,    xr21
+    xvmulwod.w.h   xr7,    xr2,    xr21
+    xvmaddwev.w.h  xr4,    xr1,    xr22
+    xvmaddwod.w.h  xr5,    xr1,    xr22
+    xvmaddwev.w.h  xr6,    xr3,    xr22
+    xvmaddwod.w.h  xr7,    xr3,    xr22
+    xvssrarni.hu.w xr6,    xr4,    bpcw_sh
+    xvssrarni.hu.w xr7,    xr5,    bpcw_sh
+    xvssrlni.bu.h  xr7,    xr6,    0
+    xvshuf4i.w     xr8,    xr7,    0x4E
+    xvilvl.b       xr9,    xr8,    xr7
+    xvpermi.d      xr0,    xr9,    0xD8
+    xvst           xr0,    a0,     0
+    addi.w         a5,     a5,     -1
+    addi.d         a2,     a2,     64
+    addi.d         a3,     a3,     64
+    add.d          a0,     a0,     a1
+    blt            zero,   a5,     .W_AVG_W32_LASX
+    b              .W_AVG_END_LASX
+
+.W_AVG_W64_LASX:
+.rept 2
+    xvld           xr0,    a2,     0
+    xvld           xr2,    a2,     32
+    xvld           xr1,    a3,     0
+    xvld           xr3,    a3,     32
+    xvmulwev.w.h   xr4,    xr0,    xr21
+    xvmulwod.w.h   xr5,    xr0,    xr21
+    xvmulwev.w.h   xr6,    xr2,    xr21
+    xvmulwod.w.h   xr7,    xr2,    xr21
+    xvmaddwev.w.h  xr4,    xr1,    xr22
+    xvmaddwod.w.h  xr5,    xr1,    xr22
+    xvmaddwev.w.h  xr6,    xr3,    xr22
+    xvmaddwod.w.h  xr7,    xr3,    xr22
+    xvssrarni.hu.w xr6,    xr4,    bpcw_sh
+    xvssrarni.hu.w xr7,    xr5,    bpcw_sh
+    xvssrlni.bu.h  xr7,    xr6,    0
+    xvshuf4i.w     xr8,    xr7,    0x4E
+    xvilvl.b       xr9,    xr8,    xr7
+    xvpermi.d      xr0,    xr9,    0xD8
+    xvst           xr0,    a0,     0
+    addi.d         a2,     a2,     64
+    addi.d         a3,     a3,     64
+    addi.d         a0,     a0,     32
+.endr
+    addi.w         a5,     a5,     -1
+    add.d          t8,     t8,     a1
+    add.d          a0,     t8,     zero
+    blt            zero,   a5,     .W_AVG_W64_LASX
+    b              .W_AVG_END_LASX
+
+.W_AVG_W128_LASX:
+.rept 4
+    xvld           xr0,    a2,     0
+    xvld           xr2,    a2,     32
+    xvld           xr1,    a3,     0
+    xvld           xr3,    a3,     32
+    xvmulwev.w.h   xr4,    xr0,    xr21
+    xvmulwod.w.h   xr5,    xr0,    xr21
+    xvmulwev.w.h   xr6,    xr2,    xr21
+    xvmulwod.w.h   xr7,    xr2,    xr21
+    xvmaddwev.w.h  xr4,    xr1,    xr22
+    xvmaddwod.w.h  xr5,    xr1,    xr22
+    xvmaddwev.w.h  xr6,    xr3,    xr22
+    xvmaddwod.w.h  xr7,    xr3,    xr22
+    xvssrarni.hu.w xr6,    xr4,    bpcw_sh
+    xvssrarni.hu.w xr7,    xr5,    bpcw_sh
+    xvssrlni.bu.h  xr7,    xr6,    0
+    xvshuf4i.w     xr8,    xr7,    0x4E
+    xvilvl.b       xr9,    xr8,    xr7
+    xvpermi.d      xr0,    xr9,    0xD8
+    xvst           xr0,    a0,     0
+    addi.d         a2,     a2,     64
+    addi.d         a3,     a3,     64
+    addi.d         a0,     a0,     32
+.endr
+
+    addi.w         a5,     a5,     -1
+    add.d          t8,     t8,     a1
+    add.d          a0,     t8,     zero
+    blt            zero,   a5,     .W_AVG_W128_LASX
+.W_AVG_END_LASX:
+endfunc
+
+#undef bpc_sh
+#undef bpcw_sh
+
+#define mask_sh         10
+/*
+static void mask_c(pixel *dst, const ptrdiff_t dst_stride,
+                   const int16_t *tmp1, const int16_t *tmp2, const int w, int h,
+                   const uint8_t *mask HIGHBD_DECL_SUFFIX)
+*/
+function mask_8bpc_lsx
+    vldi          vr21,   0x440   // 64
+    vxor.v        vr19,   vr19,   vr19
+    addi.d        t8,     a0,     0
+    clz.w         t0,     a4
+    li.w          t1,     24
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .MASK_LSX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0
+    add.d         t1,     t1,      t2
+    jirl          $r0,    t1,      0
+
+    .align   3
+.MASK_LSX_JRTABLE:
+    .hword .MASK_W128_LSX - .MASK_LSX_JRTABLE
+    .hword .MASK_W64_LSX  - .MASK_LSX_JRTABLE
+    .hword .MASK_W32_LSX  - .MASK_LSX_JRTABLE
+    .hword .MASK_W16_LSX  - .MASK_LSX_JRTABLE
+    .hword .MASK_W8_LSX   - .MASK_LSX_JRTABLE
+    .hword .MASK_W4_LSX   - .MASK_LSX_JRTABLE
+
+.MASK_W4_LSX:
+    vld           vr0,     a2,     0
+    vld           vr1,     a3,     0
+    fld.d         f22,     a6,     0
+
+    vilvl.b       vr2,    vr19,   vr22
+    vsub.h        vr3,    vr21,   vr2
+
+    vmulwev.w.h   vr4,    vr0,    vr2
+    vmulwod.w.h   vr5,    vr0,    vr2
+    vmaddwev.w.h  vr4,    vr1,    vr3
+    vmaddwod.w.h  vr5,    vr1,    vr3
+    vssrarni.hu.w vr5,    vr4,    mask_sh
+    vssrlrni.bu.h vr1,    vr5,    0
+    vpickod.w     vr4,    vr2,    vr1
+    vilvl.b       vr0,    vr4,    vr1
+    fst.s         f0,     a0,     0
+    add.d         a0,     a0,     a1
+    vstelm.w      vr0,    a0,     0,    1
+    addi.d        a2,     a2,     16
+    addi.d        a3,     a3,     16
+    addi.d        a6,     a6,     8
+    add.d         a0,     a0,     a1
+    addi.w        a5,     a5,     -2
+    blt           zero,   a5,     .MASK_W4_LSX
+    b             .MASK_END_LSX
+.MASK_W8_LSX:
+    vld           vr0,    a2,     0
+    vld           vr10,   a2,     16
+    vld           vr1,    a3,     0
+    vld           vr11,   a3,     16
+    vld           vr22,   a6,     0
+
+    vilvl.b       vr2,    vr19,   vr22
+    vilvh.b       vr12,   vr19,   vr22
+    vsub.h        vr3,    vr21,   vr2
+    vsub.h        vr13,   vr21,   vr12
+
+    vmulwev.w.h   vr4,    vr0,    vr2
+    vmulwod.w.h   vr5,    vr0,    vr2
+    vmulwev.w.h   vr14,   vr10,   vr12
+    vmulwod.w.h   vr15,   vr10,   vr12
+    vmaddwev.w.h  vr4,    vr1,    vr3
+    vmaddwod.w.h  vr5,    vr1,    vr3
+    vmaddwev.w.h  vr14,   vr11,   vr13
+    vmaddwod.w.h  vr15,   vr11,   vr13
+    vssrarni.hu.w vr14,   vr4,    mask_sh
+    vssrarni.hu.w vr15,   vr5,    mask_sh
+    vssrlrni.bu.h vr15,   vr14,   0
+    vshuf4i.w     vr6,    vr15,   0x4E
+    vilvl.b       vr0,    vr6,    vr15
+    fst.d         f0,     a0,     0
+    add.d         a0,     a0,     a1
+    vstelm.d      vr0,    a0,     0,   1
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    addi.d        a6,     a6,     16
+    add.d         a0,     a0,     a1
+    addi.w        a5,     a5,     -2
+    blt           zero,   a5,     .MASK_W8_LSX
+    b             .MASK_END_LSX
+
+.MASK_W16_LSX:
+    vld           vr0,    a2,     0
+    vld           vr10,   a2,     16
+    vld           vr1,    a3,     0
+    vld           vr11,   a3,     16
+    vld           vr22,   a6,     0
+
+    vilvl.b       vr2,    vr19,   vr22
+    vilvh.b       vr12,   vr19,   vr22
+    vsub.h        vr3,    vr21,   vr2
+    vsub.h        vr13,   vr21,   vr12
+
+    vmulwev.w.h   vr4,    vr0,    vr2
+    vmulwod.w.h   vr5,    vr0,    vr2
+    vmulwev.w.h   vr14,   vr10,   vr12
+    vmulwod.w.h   vr15,   vr10,   vr12
+    vmaddwev.w.h  vr4,    vr1,    vr3
+    vmaddwod.w.h  vr5,    vr1,    vr3
+    vmaddwev.w.h  vr14,   vr11,   vr13
+    vmaddwod.w.h  vr15,   vr11,   vr13
+    vssrarni.hu.w vr14,   vr4,    mask_sh
+    vssrarni.hu.w vr15,   vr5,    mask_sh
+    vssrlrni.bu.h vr15,   vr14,   0
+    vshuf4i.w     vr6,    vr15,   0x4E
+    vilvl.b       vr0,    vr6,    vr15
+    vst           vr0,    a0,     0
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    addi.d        a6,     a6,     16
+    add.d         a0,     a0,     a1
+    addi.w        a5,     a5,     -1
+    blt           zero,   a5,     .MASK_W16_LSX
+    b             .MASK_END_LSX
+.MASK_W32_LSX:
+.rept 2
+    vld           vr0,    a2,     0
+    vld           vr10,   a2,     16
+    vld           vr1,    a3,     0
+    vld           vr11,   a3,     16
+    vld           vr22,   a6,     0
+    vilvl.b       vr2,    vr19,   vr22
+    vilvh.b       vr12,   vr19,   vr22
+    vsub.h        vr3,    vr21,   vr2
+    vsub.h        vr13,   vr21,   vr12
+    vmulwev.w.h   vr4,    vr0,    vr2
+    vmulwod.w.h   vr5,    vr0,    vr2
+    vmulwev.w.h   vr14,   vr10,   vr12
+    vmulwod.w.h   vr15,   vr10,   vr12
+    vmaddwev.w.h  vr4,    vr1,    vr3
+    vmaddwod.w.h  vr5,    vr1,    vr3
+    vmaddwev.w.h  vr14,   vr11,   vr13
+    vmaddwod.w.h  vr15,   vr11,   vr13
+    vssrarni.hu.w vr14,   vr4,    mask_sh
+    vssrarni.hu.w vr15,   vr5,    mask_sh
+    vssrlrni.bu.h vr15,   vr14,   0
+    vshuf4i.w     vr6,    vr15,   0x4E
+    vilvl.b       vr0,    vr6,    vr15
+    vst           vr0,    a0,     0
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    addi.d        a6,     a6,     16
+    addi.d        a0,     a0,     16
+.endr
+    add.d         t8,     t8,     a1
+    add.d         a0,     t8,     zero
+    addi.w        a5,     a5,     -1
+    blt           zero,   a5,     .MASK_W32_LSX
+    b             .MASK_END_LSX
+.MASK_W64_LSX:
+.rept 4
+    vld           vr0,    a2,     0
+    vld           vr10,   a2,     16
+    vld           vr1,    a3,     0
+    vld           vr11,   a3,     16
+    vld           vr22,   a6,     0
+    vilvl.b       vr2,    vr19,   vr22
+    vilvh.b       vr12,   vr19,   vr22
+    vsub.h        vr3,    vr21,   vr2
+    vsub.h        vr13,   vr21,   vr12
+    vmulwev.w.h   vr4,    vr0,    vr2
+    vmulwod.w.h   vr5,    vr0,    vr2
+    vmulwev.w.h   vr14,   vr10,   vr12
+    vmulwod.w.h   vr15,   vr10,   vr12
+    vmaddwev.w.h  vr4,    vr1,    vr3
+    vmaddwod.w.h  vr5,    vr1,    vr3
+    vmaddwev.w.h  vr14,   vr11,   vr13
+    vmaddwod.w.h  vr15,   vr11,   vr13
+    vssrarni.hu.w vr14,   vr4,    mask_sh
+    vssrarni.hu.w vr15,   vr5,    mask_sh
+    vssrlrni.bu.h vr15,   vr14,   0
+    vshuf4i.w     vr6,    vr15,   0x4E
+    vilvl.b       vr0,    vr6,    vr15
+    vst           vr0,    a0,     0
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    addi.d        a6,     a6,     16
+    addi.d        a0,     a0,     16
+.endr
+    add.d         t8,     t8,     a1
+    add.d         a0,     t8,     zero
+    addi.w        a5,     a5,     -1
+    blt           zero,   a5,     .MASK_W64_LSX
+    b             .MASK_END_LSX
+.MASK_W128_LSX:
+.rept 8
+    vld           vr0,    a2,     0
+    vld           vr10,   a2,     16
+    vld           vr1,    a3,     0
+    vld           vr11,   a3,     16
+    vld           vr22,   a6,     0
+    vilvl.b       vr2,    vr19,   vr22
+    vilvh.b       vr12,   vr19,   vr22
+    vsub.h        vr3,    vr21,   vr2
+    vsub.h        vr13,   vr21,   vr12
+    vmulwev.w.h   vr4,    vr0,    vr2
+    vmulwod.w.h   vr5,    vr0,    vr2
+    vmulwev.w.h   vr14,   vr10,   vr12
+    vmulwod.w.h   vr15,   vr10,   vr12
+    vmaddwev.w.h  vr4,    vr1,    vr3
+    vmaddwod.w.h  vr5,    vr1,    vr3
+    vmaddwev.w.h  vr14,   vr11,   vr13
+    vmaddwod.w.h  vr15,   vr11,   vr13
+    vssrarni.hu.w vr14,   vr4,    mask_sh
+    vssrarni.hu.w vr15,   vr5,    mask_sh
+    vssrlrni.bu.h vr15,   vr14,   0
+    vshuf4i.w     vr6,    vr15,   0x4E
+    vilvl.b       vr0,    vr6,    vr15
+    vst           vr0,    a0,     0
+    addi.d        a2,     a2,     32
+    addi.d        a3,     a3,     32
+    addi.d        a6,     a6,     16
+    addi.d        a0,     a0,     16
+.endr
+    add.d         t8,     t8,     a1
+    add.d         a0,     t8,     zero
+    addi.w        a5,     a5,     -1
+    blt           zero,   a5,     .MASK_W128_LSX
+.MASK_END_LSX:
+endfunc
+
+function mask_8bpc_lasx
+    xvldi         xr21,   0x440   // 64
+    xvxor.v       xr19,   xr19,   xr19
+    addi.d        t8,     a0,     0
+    clz.w         t0,     a4
+    li.w          t1,     24
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .MASK_LASX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0
+    add.d         t1,     t1,      t2
+    jirl          $r0,    t1,      0
+
+    .align   3
+.MASK_LASX_JRTABLE:
+    .hword .MASK_W128_LASX - .MASK_LASX_JRTABLE
+    .hword .MASK_W64_LASX  - .MASK_LASX_JRTABLE
+    .hword .MASK_W32_LASX  - .MASK_LASX_JRTABLE
+    .hword .MASK_W16_LASX  - .MASK_LASX_JRTABLE
+    .hword .MASK_W8_LASX   - .MASK_LASX_JRTABLE
+    .hword .MASK_W4_LASX   - .MASK_LASX_JRTABLE
+
+.MASK_W4_LASX:
+    vld            vr0,    a2,     0
+    vld            vr1,    a3,     0
+    fld.d          f22,    a6,     0
+
+    vilvl.h        vr4,    vr1,    vr0
+    vilvh.h        vr14,   vr1,    vr0
+    vilvl.b        vr2,    vr19,   vr22
+    vsub.h         vr3,    vr21,   vr2
+    xvpermi.q      xr14,   xr4,    0x20
+    vilvl.h        vr5,    vr3,    vr2
+    vilvh.h        vr15,   vr3,    vr2
+    xvpermi.q      xr15,   xr5,    0x20
+    xvmulwev.w.h   xr0,    xr14,   xr15
+    xvmaddwod.w.h  xr0,    xr14,   xr15
+    xvssrarni.hu.w xr1,    xr0,    mask_sh
+    xvssrlni.bu.h  xr2,    xr1,    0
+    fst.s          f2,     a0,     0
+    add.d          a0,     a0,     a1
+    xvstelm.w      xr2,    a0,     0,    4
+
+    addi.d         a2,     a2,     16
+    addi.d         a3,     a3,     16
+    addi.d         a6,     a6,     8
+    add.d          a0,     a0,     a1
+    addi.w         a5,     a5,     -2
+    blt            zero,   a5,     .MASK_W4_LASX
+    b              .MASK_END_LASX
+
+.MASK_W8_LASX:
+    xvld           xr0,    a2,      0
+    xvld           xr1,    a3,      0
+    vld            vr22,   a6,      0
+
+    vext2xv.hu.bu  xr2,    xr22
+    xvsub.h        xr3,    xr21,    xr2
+    xvmulwev.w.h   xr4,    xr0,     xr2
+    xvmulwod.w.h   xr5,    xr0,     xr2
+    xvmaddwev.w.h  xr4,    xr1,     xr3
+    xvmaddwod.w.h  xr5,    xr1,     xr3
+    xvssrarni.hu.w xr5,    xr4,     mask_sh
+    xvssrlni.bu.h  xr1,    xr5,     0
+    xvpickod.w     xr4,    xr2,     xr1
+    xvilvl.b       xr0,    xr4,     xr1
+    fst.d          f0,     a0,      0
+    add.d          a0,     a0,      a1
+    xvstelm.d      xr0,    a0,      0,    2
+
+    addi.d         a2,     a2,      32
+    addi.d         a3,     a3,      32
+    addi.d         a6,     a6,      16
+    add.d          a0,     a0,      a1
+    addi.w         a5,     a5,      -2
+    blt            zero,   a5,      .MASK_W8_LASX
+    b              .MASK_END_LASX
+
+.MASK_W16_LASX:
+    xvld           xr0,    a2,      0
+    xvld           xr1,    a3,      0
+    vld            vr22,   a6,      0
+
+    vext2xv.hu.bu  xr2,    xr22
+    xvsub.h        xr3,    xr21,    xr2
+    xvmulwev.w.h   xr4,    xr0,     xr2
+    xvmulwod.w.h   xr5,    xr0,     xr2
+    xvmaddwev.w.h  xr4,    xr1,     xr3
+    xvmaddwod.w.h  xr5,    xr1,     xr3
+    xvssrarni.hu.w xr5,    xr4,     mask_sh
+    xvssrlni.bu.h  xr1,    xr5,     0
+    xvpickod.w     xr4,    xr2,    xr1
+    xvilvl.b       xr0,    xr4,    xr1
+    xvpermi.d      xr1,    xr0,     0xD8
+    vst            vr1,    a0,      0
+
+    addi.d         a2,     a2,      32
+    addi.d         a3,     a3,      32
+    addi.d         a6,     a6,      16
+    add.d          a0,     a0,      a1
+    addi.w         a5,     a5,      -1
+    blt            zero,   a5,      .MASK_W16_LASX
+    b              .MASK_END_LASX
+.MASK_W32_LASX:
+    xvld           xr0,    a2,      0
+    xvld           xr10,   a2,      32
+    xvld           xr1,    a3,      0
+    xvld           xr11,   a3,      32
+    xvld           xr22,   a6,      0
+    vext2xv.hu.bu  xr2,    xr22
+    xvpermi.q      xr4,    xr22,    0x01
+    vext2xv.hu.bu  xr12,   xr4
+    xvsub.h        xr3,    xr21,    xr2
+    xvsub.h        xr13,   xr21,    xr12
+
+    xvmulwev.w.h   xr4,    xr0,     xr2
+    xvmulwod.w.h   xr5,    xr0,     xr2
+    xvmulwev.w.h   xr14,   xr10,    xr12
+    xvmulwod.w.h   xr15,   xr10,    xr12
+    xvmaddwev.w.h  xr4,    xr1,     xr3
+    xvmaddwod.w.h  xr5,    xr1,     xr3
+    xvmaddwev.w.h  xr14,   xr11,    xr13
+    xvmaddwod.w.h  xr15,   xr11,    xr13
+    xvssrarni.hu.w xr14,   xr4,     mask_sh
+    xvssrarni.hu.w xr15,   xr5,     mask_sh
+    xvssrlni.bu.h  xr15,   xr14,    0
+    xvshuf4i.w     xr6,    xr15,    0x4E
+    xvilvl.b       xr1,    xr6,     xr15
+    xvpermi.d      xr0,    xr1,     0xD8
+    xvst           xr0,    a0,      0
+
+    addi.d         a2,     a2,      64
+    addi.d         a3,     a3,      64
+    addi.d         a6,     a6,      32
+    add.d          a0,     a0,      a1
+    addi.w         a5,     a5,      -1
+    blt            zero,   a5,      .MASK_W32_LASX
+    b              .MASK_END_LASX
+
+.MASK_W64_LASX:
+.rept 2
+    xvld           xr0,    a2,      0
+    xvld           xr10,   a2,      32
+    xvld           xr1,    a3,      0
+    xvld           xr11,   a3,      32
+    xvld           xr22,   a6,      0
+    vext2xv.hu.bu  xr2,    xr22
+    xvpermi.q      xr4,    xr22,    0x01
+    vext2xv.hu.bu  xr12,   xr4
+    xvsub.h        xr3,    xr21,    xr2
+    xvsub.h        xr13,   xr21,    xr12
+
+    xvmulwev.w.h   xr4,    xr0,     xr2
+    xvmulwod.w.h   xr5,    xr0,     xr2
+    xvmulwev.w.h   xr14,   xr10,    xr12
+    xvmulwod.w.h   xr15,   xr10,    xr12
+    xvmaddwev.w.h  xr4,    xr1,     xr3
+    xvmaddwod.w.h  xr5,    xr1,     xr3
+    xvmaddwev.w.h  xr14,   xr11,    xr13
+    xvmaddwod.w.h  xr15,   xr11,    xr13
+    xvssrarni.hu.w xr14,   xr4,     mask_sh
+    xvssrarni.hu.w xr15,   xr5,     mask_sh
+    xvssrlni.bu.h  xr15,   xr14,    0
+    xvshuf4i.w     xr6,    xr15,    0x4E
+    xvilvl.b       xr1,    xr6,     xr15
+    xvpermi.d      xr0,    xr1,     0xD8
+    xvst           xr0,    a0,      0
+    addi.d         a2,     a2,      64
+    addi.d         a3,     a3,      64
+    addi.d         a6,     a6,      32
+    addi.d         a0,     a0,      32
+.endr
+    add.d          t8,     t8,     a1
+    add.d          a0,     t8,     zero
+    addi.w         a5,     a5,      -1
+    blt            zero,   a5,      .MASK_W64_LASX
+    b              .MASK_END_LASX
+
+.MASK_W128_LASX:
+.rept 4
+    xvld           xr0,    a2,      0
+    xvld           xr10,   a2,      32
+    xvld           xr1,    a3,      0
+    xvld           xr11,   a3,      32
+    xvld           xr22,   a6,      0
+    vext2xv.hu.bu  xr2,    xr22
+    xvpermi.q      xr4,    xr22,    0x01
+    vext2xv.hu.bu  xr12,   xr4
+    xvsub.h        xr3,    xr21,    xr2
+    xvsub.h        xr13,   xr21,    xr12
+
+    xvmulwev.w.h   xr4,    xr0,     xr2
+    xvmulwod.w.h   xr5,    xr0,     xr2
+    xvmulwev.w.h   xr14,   xr10,    xr12
+    xvmulwod.w.h   xr15,   xr10,    xr12
+    xvmaddwev.w.h  xr4,    xr1,     xr3
+    xvmaddwod.w.h  xr5,    xr1,     xr3
+    xvmaddwev.w.h  xr14,   xr11,    xr13
+    xvmaddwod.w.h  xr15,   xr11,    xr13
+    xvssrarni.hu.w xr14,   xr4,     mask_sh
+    xvssrarni.hu.w xr15,   xr5,     mask_sh
+    xvssrlni.bu.h  xr15,   xr14,    0
+    xvshuf4i.w     xr6,    xr15,    0x4E
+    xvilvl.b       xr1,    xr6,     xr15
+    xvpermi.d      xr0,    xr1,     0xD8
+    xvst           xr0,    a0,      0
+
+    addi.d         a2,     a2,      64
+    addi.d         a3,     a3,      64
+    addi.d         a6,     a6,      32
+    addi.d         a0,     a0,      32
+.endr
+    add.d          t8,     t8,     a1
+    add.d          a0,     t8,     zero
+    addi.w         a5,     a5,      -1
+    blt            zero,   a5,      .MASK_W128_LASX
+.MASK_END_LASX:
+endfunc
+
+/*
+static void w_mask_c(pixel *dst, const ptrdiff_t dst_stride,
+                     const int16_t *tmp1, const int16_t *tmp2, const int w, int h,
+                     uint8_t *mask, const int sign,
+                     const int ss_hor, const int ss_ver HIGHBD_DECL_SUFFIX)
+*/
+function w_mask_420_8bpc_lsx
+    addi.d        sp,      sp,    -24
+    fst.d         f24,     sp,    0
+    fst.d         f25,     sp,    8
+    fst.d         f26,     sp,    16
+    vldi          vr20,    0x440
+    vreplgr2vr.h  vr21,    a7
+    vldi          vr22,    0x426
+
+    clz.w         t0,      a4
+    li.w          t1,      24
+    sub.w         t0,      t0,      t1
+    la.local      t1,      .WMASK420_LSX_JRTABLE
+    alsl.d        t0,      t0,      t1,    1
+    ld.h          t8,      t0,      0
+    add.d         t1,      t1,      t8
+    jirl          $r0,     t1,      0
+
+    .align   3
+.WMASK420_LSX_JRTABLE:
+    .hword .WMASK420_W128_LSX - .WMASK420_LSX_JRTABLE
+    .hword .WMASK420_W64_LSX  - .WMASK420_LSX_JRTABLE
+    .hword .WMASK420_W32_LSX  - .WMASK420_LSX_JRTABLE
+    .hword .WMASK420_W16_LSX  - .WMASK420_LSX_JRTABLE
+    .hword .WMASK420_W8_LSX   - .WMASK420_LSX_JRTABLE
+    .hword .WMASK420_W4_LSX   - .WMASK420_LSX_JRTABLE
+
+.WMASK420_W4_LSX:
+    vld           vr0,     a2,       0
+    vld           vr1,     a2,       16
+    vld           vr2,     a3,       0
+    vld           vr3,     a3,       16
+    addi.w        a5,      a5,       -4
+
+    vabsd.h       vr4,     vr0,      vr2
+    vabsd.h       vr5,     vr1,      vr3
+    vaddi.hu      vr4,     vr4,      8
+    vaddi.hu      vr5,     vr5,      8
+    vsrli.h       vr4,     vr4,      8
+    vsrli.h       vr5,     vr5,      8
+    vadd.h        vr4,     vr4,      vr22
+    vadd.h        vr5,     vr5,      vr22
+    vmin.hu       vr6,     vr4,      vr20
+    vmin.hu       vr7,     vr5,      vr20
+    vsub.h        vr8,     vr20,     vr6
+    vsub.h        vr9,     vr20,     vr7
+    vmulwev.w.h   vr4,     vr6,      vr0
+    vmulwod.w.h   vr5,     vr6,      vr0
+    vmulwev.w.h   vr10,    vr7,      vr1
+    vmulwod.w.h   vr11,    vr7,      vr1
+    vmaddwev.w.h  vr4,     vr8,      vr2
+    vmaddwod.w.h  vr5,     vr8,      vr2
+    vmaddwev.w.h  vr10,    vr9,      vr3
+    vmaddwod.w.h  vr11,    vr9,      vr3
+    vilvl.w       vr0,     vr5,      vr4
+    vilvh.w       vr1,     vr5,      vr4
+    vilvl.w       vr2,     vr11,     vr10
+    vilvh.w       vr3,     vr11,     vr10
+    vssrarni.hu.w vr1,     vr0,      10
+    vssrarni.hu.w vr3,     vr2,      10
+    vssrlni.bu.h  vr3,     vr1,      0
+    vstelm.w      vr3,     a0,       0,    0
+    add.d         a0,      a0,       a1
+    vstelm.w      vr3,     a0,       0,    1
+    add.d         a0,      a0,       a1
+    vstelm.w      vr3,     a0,       0,    2
+    add.d         a0,      a0,       a1
+    vstelm.w      vr3,     a0,       0,    3
+    add.d         a0,      a0,       a1
+    vpickev.h     vr0,     vr7,      vr6
+    vpickod.h     vr1,     vr7,      vr6
+    vadd.h        vr0,     vr0,      vr1
+    vshuf4i.h     vr0,     vr0,      0xd8
+    vhaddw.w.h    vr2,     vr0,      vr0
+    vpickev.h     vr2,     vr2,      vr2
+    vsub.h        vr2,     vr2,      vr21
+    vaddi.hu      vr2,     vr2,      2
+    vssrani.bu.h  vr2,     vr2,      2
+    vstelm.w      vr2,     a6,       0,    0
+
+    addi.d        a2,      a2,       32
+    addi.d        a3,      a3,       32
+    addi.d        a6,      a6,       4
+    blt           zero,    a5,       .WMASK420_W4_LSX
+    b             .END_W420
+
+.WMASK420_W8_LSX:
+    vld           vr0,     a2,       0
+    vld           vr1,     a2,       16
+    vld           vr2,     a3,       0
+    vld           vr3,     a3,       16
+    addi.w        a5,      a5,       -2
+
+    vabsd.h       vr4,     vr0,      vr2
+    vabsd.h       vr5,     vr1,      vr3
+    vaddi.hu      vr4,     vr4,      8
+    vaddi.hu      vr5,     vr5,      8
+    vsrli.h       vr4,     vr4,      8
+    vsrli.h       vr5,     vr5,      8
+    vadd.h        vr4,     vr4,      vr22
+    vadd.h        vr5,     vr5,      vr22
+    vmin.hu       vr6,     vr4,      vr20
+    vmin.hu       vr7,     vr5,      vr20
+    vsub.h        vr8,     vr20,     vr6
+    vsub.h        vr9,     vr20,     vr7
+    vmulwev.w.h   vr4,     vr6,      vr0
+    vmulwod.w.h   vr5,     vr6,      vr0
+    vmulwev.w.h   vr10,    vr7,      vr1
+    vmulwod.w.h   vr11,    vr7,      vr1
+    vmaddwev.w.h  vr4,     vr8,      vr2
+    vmaddwod.w.h  vr5,     vr8,      vr2
+    vmaddwev.w.h  vr10,    vr9,      vr3
+    vmaddwod.w.h  vr11,    vr9,      vr3
+    vssrarni.hu.w vr10,    vr4,      10
+    vssrarni.hu.w vr11,    vr5,      10
+    vssrlni.bu.h  vr11,    vr10,     0
+    vshuf4i.w     vr0,     vr11,     0x4E
+    vilvl.b       vr3,     vr0,      vr11
+    vstelm.d      vr3,     a0,       0,     0
+    add.d         a0,      a0,       a1
+    vstelm.d      vr3,     a0,       0,     1
+    add.d         a0,      a0,       a1
+    vpickev.h     vr0,     vr7,      vr6
+    vpickod.h     vr1,     vr7,      vr6
+    vadd.h        vr0,     vr0,      vr1
+    vilvh.d       vr2,     vr0,      vr0
+    vadd.h        vr2,     vr2,      vr0
+    vsub.h        vr2,     vr2,      vr21
+    vaddi.hu      vr2,     vr2,      2
+    vssrani.bu.h  vr2,     vr2,      2
+    vstelm.w      vr2,     a6,       0,     0
+
+    addi.d        a2,      a2,       32
+    addi.d        a3,      a3,       32
+    addi.d        a6,      a6,       4
+    blt           zero,    a5,       .WMASK420_W8_LSX
+    b             .END_W420
+
+.WMASK420_W16_LSX:
+    vld           vr0,     a2,       0
+    vld           vr1,     a2,       16
+    alsl.d        a2,      a4,       a2,    1
+    vld           vr2,     a2,       0
+    vld           vr3,     a2,       16
+    vld           vr4,     a3,       0
+    vld           vr5,     a3,       16
+    alsl.d        a3,      a4,       a3,    1
+    vld           vr6,     a3,       0
+    vld           vr7,     a3,       16
+
+    vabsd.h       vr8,     vr0,      vr4
+    vabsd.h       vr9,     vr1,      vr5
+    vabsd.h       vr10,    vr2,      vr6
+    vabsd.h       vr11,    vr3,      vr7
+    vaddi.hu      vr8,     vr8,      8
+    vaddi.hu      vr9,     vr9,      8
+    vaddi.hu      vr10,    vr10,     8
+    vaddi.hu      vr11,    vr11,     8
+    vsrli.h       vr8,     vr8,      8
+    vsrli.h       vr9,     vr9,      8
+    vsrli.h       vr10,    vr10,     8
+    vsrli.h       vr11,    vr11,     8
+    vadd.h        vr8,     vr8,      vr22
+    vadd.h        vr9,     vr9,      vr22
+    vadd.h        vr10,    vr10,     vr22
+    vadd.h        vr11,    vr11,     vr22
+    vmin.hu       vr12,    vr8,      vr20
+    vmin.hu       vr13,    vr9,      vr20
+    vmin.hu       vr14,    vr10,     vr20
+    vmin.hu       vr15,    vr11,     vr20
+    vsub.h        vr16,    vr20,     vr12
+    vsub.h        vr17,    vr20,     vr13
+    vsub.h        vr18,    vr20,     vr14
+    vsub.h        vr19,    vr20,     vr15
+    vmulwev.w.h   vr8,     vr12,     vr0
+    vmulwod.w.h   vr9,     vr12,     vr0
+    vmulwev.w.h   vr10,    vr13,     vr1
+    vmulwod.w.h   vr11,    vr13,     vr1
+    vmulwev.w.h   vr23,    vr14,     vr2
+    vmulwod.w.h   vr24,    vr14,     vr2
+    vmulwev.w.h   vr25,    vr15,     vr3
+    vmulwod.w.h   vr26,    vr15,     vr3
+    vmaddwev.w.h  vr8,     vr16,     vr4
+    vmaddwod.w.h  vr9,     vr16,     vr4
+    vmaddwev.w.h  vr10,    vr17,     vr5
+    vmaddwod.w.h  vr11,    vr17,     vr5
+    vmaddwev.w.h  vr23,    vr18,     vr6
+    vmaddwod.w.h  vr24,    vr18,     vr6
+    vmaddwev.w.h  vr25,    vr19,     vr7
+    vmaddwod.w.h  vr26,    vr19,     vr7
+    vssrarni.hu.w vr10,    vr8,      10
+    vssrarni.hu.w vr11,    vr9,      10
+    vssrarni.hu.w vr25,    vr23,     10
+    vssrarni.hu.w vr26,    vr24,     10
+    vssrlni.bu.h  vr11,    vr10,     0
+    vssrlni.bu.h  vr26,    vr25,     0
+    vshuf4i.w     vr0,     vr11,     0x4E
+    vshuf4i.w     vr1,     vr26,     0x4E
+    vilvl.b       vr3,     vr0,      vr11
+    vilvl.b       vr7,     vr1,      vr26
+    vst           vr3,     a0,       0
+    vstx          vr7,     a0,       a1
+    vpickev.h     vr0,     vr13,     vr12
+    vpickod.h     vr1,     vr13,     vr12
+    vpickev.h     vr2,     vr15,     vr14
+    vpickod.h     vr3,     vr15,     vr14
+    vadd.h        vr4,     vr0,      vr1
+    vadd.h        vr5,     vr2,      vr3
+    vadd.h        vr4,     vr4,      vr5
+    vsub.h        vr4,     vr4,      vr21
+    vssrarni.bu.h vr4,     vr4,      2
+    vstelm.d      vr4,     a6,       0,    0
+
+    alsl.d        a2,      a4,       a2,   1
+    alsl.d        a3,      a4,       a3,   1
+    alsl.d        a0,      a1,       a0,   1
+    addi.d        a6,      a6,       8
+    addi.w        a5,      a5,       -2
+    blt           zero,    a5,       .WMASK420_W16_LSX
+    b    .END_W420
+
+.WMASK420_W32_LSX:
+.WMASK420_W64_LSX:
+.WMASK420_W128_LSX:
+
+.LOOP_W32_420_LSX:
+    add.d         t1,       a2,       zero
+    add.d         t2,       a3,       zero
+    add.d         t3,       a0,       zero
+    add.d         t4,       a6,       zero
+    alsl.d        t5,       a4,       t1,     1
+    alsl.d        t6,       a4,       t2,     1
+    or            t7,       a4,       a4
+
+.W32_420_LSX:
+    vld           vr0,      t1,       0
+    vld           vr1,      t1,       16
+    vld           vr2,      t2,       0
+    vld           vr3,      t2,       16
+    vld           vr4,      t5,       0
+    vld           vr5,      t5,       16
+    vld           vr6,      t6,       0
+    vld           vr7,      t6,       16
+    addi.d        t1,       t1,       32
+    addi.d        t2,       t2,       32
+    addi.d        t5,       t5,       32
+    addi.d        t6,       t6,       32
+    addi.w        t7,       t7,       -16
+    vabsd.h       vr8,      vr0,      vr2
+    vabsd.h       vr9,      vr1,      vr3
+    vabsd.h       vr10,     vr4,      vr6
+    vabsd.h       vr11,     vr5,      vr7
+    vaddi.hu      vr8,      vr8,      8
+    vaddi.hu      vr9,      vr9,      8
+    vaddi.hu      vr10,     vr10,     8
+    vaddi.hu      vr11,     vr11,     8
+    vsrli.h       vr8,      vr8,      8
+    vsrli.h       vr9,      vr9,      8
+    vsrli.h       vr10,     vr10,     8
+    vsrli.h       vr11,     vr11,     8
+    vadd.h        vr8,      vr8,      vr22
+    vadd.h        vr9,      vr9,      vr22
+    vadd.h        vr10,     vr10,     vr22
+    vadd.h        vr11,     vr11,     vr22
+    vmin.hu       vr12,     vr8,      vr20
+    vmin.hu       vr13,     vr9,      vr20
+    vmin.hu       vr14,     vr10,     vr20
+    vmin.hu       vr15,     vr11,     vr20
+    vsub.h        vr16,     vr20,     vr12
+    vsub.h        vr17,     vr20,     vr13
+    vsub.h        vr18,     vr20,     vr14
+    vsub.h        vr19,     vr20,     vr15
+    vmulwev.w.h   vr8,      vr12,     vr0
+    vmulwod.w.h   vr9,      vr12,     vr0
+    vmulwev.w.h   vr10,     vr13,     vr1
+    vmulwod.w.h   vr11,     vr13,     vr1
+    vmulwev.w.h   vr23,     vr14,     vr4
+    vmulwod.w.h   vr24,     vr14,     vr4
+    vmulwev.w.h   vr25,     vr15,     vr5
+    vmulwod.w.h   vr26,     vr15,     vr5
+    vmaddwev.w.h  vr8,      vr16,     vr2
+    vmaddwod.w.h  vr9,      vr16,     vr2
+    vmaddwev.w.h  vr10,     vr17,     vr3
+    vmaddwod.w.h  vr11,     vr17,     vr3
+    vmaddwev.w.h  vr23,     vr18,     vr6
+    vmaddwod.w.h  vr24,     vr18,     vr6
+    vmaddwev.w.h  vr25,     vr19,     vr7
+    vmaddwod.w.h  vr26,     vr19,     vr7
+    vssrarni.hu.w vr10,     vr8,      10
+    vssrarni.hu.w vr11,     vr9,      10
+    vssrarni.hu.w vr25,     vr23,     10
+    vssrarni.hu.w vr26,     vr24,     10
+    vssrlni.bu.h  vr11,     vr10,     0
+    vssrlni.bu.h  vr26,     vr25,     0
+    vshuf4i.w     vr8,      vr11,     0x4E
+    vshuf4i.w     vr9,      vr26,     0x4E
+    vilvl.b       vr3,      vr8,      vr11
+    vilvl.b       vr7,      vr9,      vr26
+    vst           vr3,      t3,       0
+    vstx          vr7,      a1,       t3
+    addi.d        t3,       t3,       16
+    vpickev.h     vr8,      vr13,     vr12
+    vpickod.h     vr9,      vr13,     vr12
+    vpickev.h     vr10,     vr15,     vr14
+    vpickod.h     vr11,     vr15,     vr14
+    vadd.h        vr8,      vr8,      vr9
+    vadd.h        vr10,     vr10,     vr11
+    vadd.h        vr12,     vr8,      vr10
+    vsub.h        vr12,     vr12,     vr21
+    vssrarni.bu.h vr12,     vr12,     2
+    vstelm.d      vr12,     t4,       0,     0
+    addi.d        t4,       t4,       8
+    bne           t7,       zero,     .W32_420_LSX
+
+    alsl.d        a2,       a4,       a2,     2
+    alsl.d        a3,       a4,       a3,     2
+    alsl.d        a0,       a1,       a0,     1
+    srai.w        t8,       a4,       1
+    add.d         a6,       a6,       t8
+    addi.w        a5,       a5,       -2
+    blt           zero,     a5,       .LOOP_W32_420_LSX
+
+.END_W420:
+    fld.d            f24,     sp,    0
+    fld.d            f25,     sp,    8
+    fld.d            f26,     sp,    16
+    addi.d           sp,      sp,    24
+endfunc
+
+function w_mask_420_8bpc_lasx
+    xvldi          xr20,    0x440
+    xvreplgr2vr.h  xr21,    a7
+    xvldi          xr22,    0x426
+
+    clz.w          t0,      a4
+    li.w           t1,      24
+    sub.w          t0,      t0,      t1
+    la.local       t1,      .WMASK420_LASX_JRTABLE
+    alsl.d         t0,      t0,      t1,    1
+    ld.h           t8,      t0,      0
+    add.d          t1,      t1,      t8
+    jirl           $r0,     t1,      0
+
+    .align   3
+.WMASK420_LASX_JRTABLE:
+    .hword .WMASK420_W128_LASX - .WMASK420_LASX_JRTABLE
+    .hword .WMASK420_W64_LASX  - .WMASK420_LASX_JRTABLE
+    .hword .WMASK420_W32_LASX  - .WMASK420_LASX_JRTABLE
+    .hword .WMASK420_W16_LASX  - .WMASK420_LASX_JRTABLE
+    .hword .WMASK420_W8_LASX   - .WMASK420_LASX_JRTABLE
+    .hword .WMASK420_W4_LASX   - .WMASK420_LASX_JRTABLE
+
+.WMASK420_W4_LASX:
+    xvld           xr0,     a2,     0
+    xvld           xr1,     a3,     0
+    addi.w         a5,      a5,     -4
+
+    xvabsd.h       xr2,     xr0,    xr1
+    xvaddi.hu      xr2,     xr2,    8
+    xvsrli.h       xr2,     xr2,    8
+    xvadd.h        xr2,     xr2,    xr22
+    xvmin.hu       xr3,     xr2,    xr20
+    xvsub.h        xr4,     xr20,   xr3
+    xvmulwev.w.h   xr5,     xr3,    xr0
+    xvmulwod.w.h   xr6,     xr3,    xr0
+    xvmaddwev.w.h  xr5,     xr4,    xr1
+    xvmaddwod.w.h  xr6,     xr4,    xr1
+    xvilvl.w       xr7,     xr6,    xr5
+    xvilvh.w       xr8,     xr6,    xr5
+    xvssrarni.hu.w xr8,     xr7,    10
+    xvssrlni.bu.h  xr9,     xr8,    0
+    vstelm.w       vr9,     a0,     0,     0
+    add.d          a0,      a0,     a1
+    vstelm.w       vr9,     a0,     0,     1
+    add.d          a0,      a0,     a1
+    xvstelm.w      xr9,     a0,     0,     4
+    add.d          a0,      a0,     a1
+    xvstelm.w      xr9,     a0,     0,     5
+    add.d          a0,      a0,     a1
+
+    xvhaddw.w.h    xr3,     xr3,    xr3
+    xvpermi.d      xr4,     xr3,    0xb1
+    xvadd.h        xr3,     xr3,    xr4
+    xvpickev.h     xr3,     xr3,    xr3
+    xvsub.h        xr3,     xr3,    xr21
+    xvssrarni.bu.h xr3,     xr3,    2
+    vstelm.h       vr3,     a6,     0,     0
+    xvstelm.h      xr3,     a6,     2,     8
+
+    addi.d         a2,     a2,      32
+    addi.d         a3,     a3,      32
+    addi.d         a6,     a6,      4
+    blt            zero,   a5,      .WMASK420_W4_LASX
+    b              .END_W420_LASX
+
+.WMASK420_W8_LASX:
+    xvld           xr0,      a2,     0
+    xvld           xr1,      a2,     32
+    xvld           xr2,      a3,     0
+    xvld           xr3,      a3,     32
+    addi.w         a5,       a5,     -4
+
+    xvabsd.h       xr4,      xr0,    xr2
+    xvabsd.h       xr5,      xr1,    xr3
+    xvaddi.hu      xr4,      xr4,    8
+    xvaddi.hu      xr5,      xr5,    8
+    xvsrli.h       xr4,      xr4,    8
+    xvsrli.h       xr5,      xr5,    8
+    xvadd.h        xr4,      xr4,    xr22
+    xvadd.h        xr5,      xr5,    xr22
+    xvmin.hu       xr6,      xr4,    xr20
+    xvmin.hu       xr7,      xr5,    xr20
+    xvsub.h        xr8,      xr20,   xr6
+    xvsub.h        xr9,      xr20,   xr7
+    xvmulwev.w.h   xr10,     xr6,    xr0
+    xvmulwod.w.h   xr11,     xr6,    xr0
+    xvmulwev.w.h   xr12,     xr7,    xr1
+    xvmulwod.w.h   xr13,     xr7,    xr1
+    xvmaddwev.w.h  xr10,     xr8,    xr2
+    xvmaddwod.w.h  xr11,     xr8,    xr2
+    xvmaddwev.w.h  xr12,     xr9,    xr3
+    xvmaddwod.w.h  xr13,     xr9,    xr3
+    xvssrarni.hu.w xr12,     xr10,   10
+    xvssrarni.hu.w xr13,     xr11,   10
+    xvssrlni.bu.h  xr13,     xr12,   0
+    xvshuf4i.w     xr1,      xr13,   0x4E
+    xvilvl.b       xr17,     xr1,    xr13
+    vstelm.d       vr17,     a0,     0,     0
+    add.d          a0,       a0,     a1
+    xvstelm.d      xr17,     a0,     0,     2
+    add.d          a0,       a0,     a1
+    xvstelm.d      xr17,     a0,     0,     1
+    add.d          a0,       a0,     a1
+    xvstelm.d      xr17,     a0,     0,     3
+    add.d          a0,       a0,     a1
+
+    xvhaddw.w.h    xr6,      xr6,    xr6
+    xvhaddw.w.h    xr7,      xr7,    xr7
+    xvpickev.h     xr8,      xr7,    xr6
+    xvpermi.q      xr9,      xr8,    0x01
+    vadd.h         vr8,      vr8,    vr9
+    vsub.h         vr8,      vr8,    vr21
+    vssrarni.bu.h  vr8,      vr8,    2
+    vstelm.d       vr8,      a6,     0,    0
+    addi.d         a2,       a2,     64
+    addi.d         a3,       a3,     64
+    addi.d         a6,       a6,     8
+    blt            zero,     a5,     .WMASK420_W8_LASX
+    b              .END_W420_LASX
+
+.WMASK420_W16_LASX:
+    xvld           xr0,      a2,     0
+    xvld           xr1,      a2,     32
+    xvld           xr2,      a3,     0
+    xvld           xr3,      a3,     32
+    addi.w         a5,       a5,     -2
+
+    xvabsd.h       xr4,      xr0,    xr2
+    xvabsd.h       xr5,      xr1,    xr3
+    xvaddi.hu      xr4,      xr4,    8
+    xvaddi.hu      xr5,      xr5,    8
+    xvsrli.h       xr4,      xr4,    8
+    xvsrli.h       xr5,      xr5,    8
+    xvadd.h        xr4,      xr4,    xr22
+    xvadd.h        xr5,      xr5,    xr22
+    xvmin.hu       xr4,      xr4,    xr20
+    xvmin.hu       xr5,      xr5,    xr20
+    xvsub.h        xr6,      xr20,   xr4
+    xvsub.h        xr7,      xr20,   xr5
+    xvmulwev.w.h   xr8,      xr4,    xr0
+    xvmulwod.w.h   xr9,      xr4,    xr0
+    xvmulwev.w.h   xr10,     xr5,    xr1
+    xvmulwod.w.h   xr11,     xr5,    xr1
+    xvmaddwev.w.h  xr8,      xr6,    xr2
+    xvmaddwod.w.h  xr9,      xr6,    xr2
+    xvmaddwev.w.h  xr10,     xr7,    xr3
+    xvmaddwod.w.h  xr11,     xr7,    xr3
+    xvssrarni.hu.w xr10,     xr8,    10
+    xvssrarni.hu.w xr11,     xr9,    10
+    xvssrlni.bu.h  xr11,     xr10,   0
+    xvshuf4i.w     xr8,      xr11,   0x4E
+    xvilvl.b       xr15,     xr8,    xr11
+    xvpermi.d      xr16,     xr15,   0xd8
+    vst            vr16,     a0,     0
+    add.d          a0,       a0,     a1
+    xvpermi.q      xr16,     xr16,   0x01
+    vst            vr16,     a0,     0
+    add.d          a0,       a0,     a1
+
+    xvhaddw.w.h    xr4,      xr4,    xr4
+    xvhaddw.w.h    xr5,      xr5,    xr5
+    xvadd.h        xr4,      xr5,    xr4
+    xvpickev.h     xr6,      xr4,    xr4
+    xvpermi.d      xr7,      xr6,    0x08
+    vsub.h         vr7,      vr7,    vr21
+    vssrarni.bu.h  vr7,      vr7,    2
+    vstelm.d       vr7,      a6,     0,    0
+
+    addi.d         a2,       a2,     64
+    addi.d         a3,       a3,     64
+    addi.d         a6,       a6,     8
+    blt            zero,     a5,     .WMASK420_W16_LASX
+    b              .END_W420_LASX
+
+.WMASK420_W32_LASX:
+.WMASK420_W64_LASX:
+.WMASK420_W128_LASX:
+
+.LOOP_W32_420_LASX:
+    add.d          t1,       a2,       zero
+    add.d          t2,       a3,       zero
+    add.d          t3,       a0,       zero
+    add.d          t4,       a6,       zero
+    alsl.d         t5,       a4,       t1,     1
+    alsl.d         t6,       a4,       t2,     1
+    or             t7,       a4,       a4
+.W32_420_LASX:
+    xvld           xr0,      t1,       0
+    xvld           xr1,      t2,       0
+    xvld           xr2,      t5,       0
+    xvld           xr3,      t6,       0
+    addi.d         t1,       t1,       32
+    addi.d         t2,       t2,       32
+    addi.d         t5,       t5,       32
+    addi.d         t6,       t6,       32
+    addi.w         t7,       t7,       -16
+    xvabsd.h       xr4,      xr0,      xr1
+    xvabsd.h       xr5,      xr2,      xr3
+    xvaddi.hu      xr4,      xr4,      8
+    xvaddi.hu      xr5,      xr5,      8
+    xvsrli.h       xr4,      xr4,      8
+    xvsrli.h       xr5,      xr5,      8
+    xvadd.h        xr4,      xr4,      xr22
+    xvadd.h        xr5,      xr5,      xr22
+    xvmin.hu       xr6,      xr4,      xr20
+    xvmin.hu       xr7,      xr5,      xr20
+    xvsub.h        xr8,      xr20,     xr6
+    xvsub.h        xr9,      xr20,     xr7
+    xvmulwev.w.h   xr10,     xr6,      xr0
+    xvmulwod.w.h   xr11,     xr6,      xr0
+    xvmulwev.w.h   xr12,     xr7,      xr2
+    xvmulwod.w.h   xr13,     xr7,      xr2
+    xvmaddwev.w.h  xr10,     xr8,      xr1
+    xvmaddwod.w.h  xr11,     xr8,      xr1
+    xvmaddwev.w.h  xr12,     xr9,      xr3
+    xvmaddwod.w.h  xr13,     xr9,      xr3
+    xvssrarni.hu.w xr12,     xr10,     10
+    xvssrarni.hu.w xr13,     xr11,     10
+    xvssrlni.bu.h  xr13,     xr12,     0
+    xvshuf4i.w     xr10,     xr13,     0x4E
+    xvilvl.b       xr17,     xr10,     xr13
+    xvpermi.d      xr18,     xr17,     0x08
+    xvpermi.d      xr19,     xr17,     0x0d
+    vst            vr18,     t3,       0
+    vstx           vr19,     t3,       a1
+    addi.d         t3,       t3,       16
+
+    xvhaddw.w.h    xr6,      xr6,      xr6
+    xvhaddw.w.h    xr7,      xr7,      xr7
+    xvadd.h        xr6,      xr7,      xr6
+    xvpickev.h     xr7,      xr6,      xr6
+    xvpermi.d      xr8,      xr7,      0x08
+    vsub.h         vr9,      vr8,      vr21
+    vssrarni.bu.h  vr9,      vr9,      2
+    vstelm.d       vr9,      t4,       0,      0
+    addi.d         t4,       t4,       8
+    bne            t7,       zero,     .W32_420_LASX
+
+    alsl.d         a2,       a4,       a2,     2
+    alsl.d         a3,       a4,       a3,     2
+    alsl.d         a0,       a1,       a0,     1
+    srai.w         t8,       a4,       1
+    add.d          a6,       a6,       t8
+    addi.w         a5,       a5,       -2
+    blt            zero,     a5,       .LOOP_W32_420_LASX
+
+.END_W420_LASX:
+endfunc
+
+#undef bpc_sh
+#undef bpcw_sh
+
+.macro  vhaddw.d.h  in0
+    vhaddw.w.h  \in0,  \in0,  \in0
+    vhaddw.d.w  \in0,  \in0,  \in0
+.endm
+.macro  vhaddw.q.w  in0
+    vhaddw.d.w  \in0,  \in0,  \in0
+    vhaddw.q.d  \in0,  \in0,  \in0
+.endm
+.macro PUT_H_8W in0
+    vshuf.b          vr2,    \in0,  \in0,   vr6
+    vshuf.b          vr3,    \in0,  \in0,   vr7
+    vshuf.b          vr4,    \in0,  \in0,   vr8
+    vmulwev.h.bu.b   vr12,   vr2,   vr10
+    vmulwev.h.bu.b   vr13,   vr3,   vr11
+    vmulwev.h.bu.b   vr14,   vr3,   vr10
+    vmulwev.h.bu.b   vr15,   vr4,   vr11
+    vmaddwod.h.bu.b  vr12,   vr2,   vr10
+    vmaddwod.h.bu.b  vr13,   vr3,   vr11
+    vmaddwod.h.bu.b  vr14,   vr3,   vr10
+    vmaddwod.h.bu.b  vr15,   vr4,   vr11
+    vadd.h           vr12,   vr12,  vr13
+    vadd.h           vr14,   vr14,  vr15
+    vhaddw.w.h       vr12,   vr12,  vr12
+    vhaddw.w.h       vr14,   vr14,  vr14
+    vpickev.h        \in0,   vr14,  vr12
+    vadd.h           \in0,   \in0,  vr9
+.endm
+
+const subpel_h_shuf0
+.byte 0, 1, 2, 3, 1, 2, 3, 4, 16, 17, 18, 19, 17, 18, 19, 20
+endconst
+const subpel_h_shuf1
+.byte 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6
+endconst
+const subpel_h_shuf2
+.byte 0, 1, 2, 3, 1, 2, 3, 4,  8,  9, 10, 11,  9, 10, 11, 12
+.byte 2, 3, 4, 5, 3, 4, 5, 6, 10, 11, 12, 13, 11, 12, 13, 14
+endconst
+const subpel_h_shuf3
+.byte 0, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11
+.byte 0, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11
+endconst
+
+.macro FILTER_8TAP_8W in0
+    vshuf.b         vr13,    \in0,  \in0,  vr7
+    vshuf.b         vr14,    \in0,  \in0,  vr11
+    vshuf.b         vr15,    \in0,  \in0,  vr12
+    vmulwev.h.bu.b  vr16,    vr13,  vr8
+    vmulwev.h.bu.b  vr17,    vr14,  vr10
+    vmulwev.h.bu.b  vr18,    vr14,  vr8
+    vmulwev.h.bu.b  vr19,    vr15,  vr10
+    vmaddwod.h.bu.b vr16,    vr13,  vr8
+    vmaddwod.h.bu.b vr17,    vr14,  vr10
+    vmaddwod.h.bu.b vr18,    vr14,  vr8
+    vmaddwod.h.bu.b vr19,    vr15,  vr10
+    vadd.h          vr16,    vr16,  vr17
+    vadd.h          vr18,    vr18,  vr19
+    vhaddw.w.h      vr16,    vr16,  vr16
+    vhaddw.w.h      \in0,    vr18,  vr18
+    vssrarni.h.w    \in0,    vr16,  2
+.endm
+
+.macro PUT_8TAP_8BPC_LSX lable
+    li.w             t0,     4
+    la.local         t6,     dav1d_mc_subpel_filters
+    slli.d           t2,     a3,    1  //src_stride*2
+    add.d            t3,     t2,    a3 //src_stride*3
+    slli.d           t4,     t2,    1  //src_stride*4
+
+    bnez             a6,     .l_\lable\()put_h //mx
+    bnez             a7,     .l_\lable\()put_v //my
+
+    clz.w            t1,     a4
+    li.w             t5,     24
+    sub.w            t1,     t1,    t5
+    la.local         t5,     .l_\lable\()put_hv0_jtable
+    alsl.d           t1,     t1,    t5,   3
+    ld.d             t6,     t1,    0
+    add.d            t5,     t5,    t6
+    jirl             $r0,    t5,    0
+
+    .align   3
+.l_\lable\()put_hv0_jtable:
+    .dword .l_\lable\()put_hv0_128w - .l_\lable\()put_hv0_jtable
+    .dword .l_\lable\()put_hv0_64w  - .l_\lable\()put_hv0_jtable
+    .dword .l_\lable\()put_hv0_32w  - .l_\lable\()put_hv0_jtable
+    .dword .l_\lable\()put_hv0_16w  - .l_\lable\()put_hv0_jtable
+    .dword .l_\lable\()put_hv0_8w   - .l_\lable\()put_hv0_jtable
+    .dword .l_\lable\()put_hv0_4w   - .l_\lable\()put_hv0_jtable
+    .dword .l_\lable\()put_hv0_2w   - .l_\lable\()put_hv0_jtable
+
+.l_\lable\()put_hv0_2w:
+    vldrepl.h        vr0,    a2,    0
+    add.d            a2,     a2,    a3
+    vldrepl.h        vr1,    a2,    0
+    vstelm.h         vr0,    a0,    0,     0
+    add.d            a0,     a0,    a1
+    vstelm.h         vr1,    a0,    0,     0
+    add.d            a2,     a2,    a3
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv0_2w
+    b                .l_\lable\()end_put_8tap
+.l_\lable\()put_hv0_4w:
+    fld.s            f0,     a2,    0
+    fldx.s           f1,     a2,    a3
+    fst.s            f0,     a0,    0
+    fstx.s           f1,     a0,    a1
+    alsl.d           a2,     a3,    a2,    1
+    alsl.d           a0,     a1,    a0,    1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv0_4w
+    b                .l_\lable\()end_put_8tap
+.l_\lable\()put_hv0_8w:
+    fld.d            f0,     a2,    0
+    fldx.d           f1,     a2,    a3
+    fst.d            f0,     a0,    0
+    fstx.d           f1,     a0,    a1
+    alsl.d           a2,     a3,    a2,    1
+    alsl.d           a0,     a1,    a0,    1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv0_8w
+    b                .l_\lable\()end_put_8tap
+.l_\lable\()put_hv0_16w:
+    vld              vr0,    a2,    0
+    vldx             vr1,    a2,    a3
+    vst              vr0,    a0,    0
+    vstx             vr1,    a0,    a1
+    alsl.d           a2,     a3,    a2,    1
+    alsl.d           a0,     a1,    a0,    1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv0_16w
+    b                .l_\lable\()end_put_8tap
+.l_\lable\()put_hv0_32w:
+    vld              vr0,    a2,    0
+    vld              vr1,    a2,    16
+    add.d            a2,     a2,    a3
+    vld              vr2,    a2,    0
+    vld              vr3,    a2,    16
+    vst              vr0,    a0,    0
+    vst              vr1,    a0,    16
+    add.d            a0,     a0,    a1
+    vst              vr2,    a0,    0
+    vst              vr3,    a0,    16
+    add.d            a2,     a2,    a3
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv0_32w
+    b                .l_\lable\()end_put_8tap
+.l_\lable\()put_hv0_64w:
+    vld              vr0,    a2,    0
+    vld              vr1,    a2,    16
+    vld              vr2,    a2,    32
+    vld              vr3,    a2,    48
+    add.d            a2,     a2,    a3
+    vld              vr4,    a2,    0
+    vld              vr5,    a2,    16
+    vld              vr6,    a2,    32
+    vld              vr7,    a2,    48
+    add.d            a2,     a2,    a3
+    vst              vr0,    a0,    0
+    vst              vr1,    a0,    16
+    vst              vr2,    a0,    32
+    vst              vr3,    a0,    48
+    add.d            a0,     a0,    a1
+    vst              vr4,    a0,    0
+    vst              vr5,    a0,    16
+    vst              vr6,    a0,    32
+    vst              vr7,    a0,    48
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv0_64w
+    b                .l_\lable\()end_put_8tap
+.l_\lable\()put_hv0_128w:
+    vld              vr0,    a2,    0
+    vld              vr1,    a2,    16
+    vld              vr2,    a2,    32
+    vld              vr3,    a2,    48
+    vld              vr4,    a2,    64
+    vld              vr5,    a2,    80
+    vld              vr6,    a2,    96
+    vld              vr7,    a2,    112
+    add.d            a2,     a2,    a3
+    vld              vr8,    a2,    0
+    vld              vr9,    a2,    16
+    vld              vr10,   a2,    32
+    vld              vr11,   a2,    48
+    vld              vr12,   a2,    64
+    vld              vr13,   a2,    80
+    vld              vr14,   a2,    96
+    vld              vr15,   a2,    112
+    add.d            a2,     a2,    a3
+    vst              vr0,    a0,    0
+    vst              vr1,    a0,    16
+    vst              vr2,    a0,    32
+    vst              vr3,    a0,    48
+    vst              vr4,    a0,    64
+    vst              vr5,    a0,    80
+    vst              vr6,    a0,    96
+    vst              vr7,    a0,    112
+    add.d            a0,     a0,    a1
+    vst              vr8,    a0,    0
+    vst              vr9,    a0,    16
+    vst              vr10,   a0,    32
+    vst              vr11,   a0,    48
+    vst              vr12,   a0,    64
+    vst              vr13,   a0,    80
+    vst              vr14,   a0,    96
+    vst              vr15,   a0,    112
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv0_128w
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_h:
+    bnez             a7,     .l_\lable\()put_hv //if(fh) && if (fv)
+    ld.d             t5,     sp,    0  //filter_type
+    andi             t1,     t5,    3
+    blt              t0,     a4,    .l_\lable\()put_h_idx_fh
+    andi             t1,     t5,    1
+    addi.w           t1,     t1,    3
+
+.l_\lable\()put_h_idx_fh:
+    addi.w           t5,     zero,  120
+    mul.w            t1,     t1,    t5
+    addi.w           t5,     a6,    -1
+    slli.w           t5,     t5,    3
+    add.w            t1,     t1,    t5
+    add.d            t7,     t6,    t1 //fh's offset
+    li.w             t1,     34
+    vreplgr2vr.h     vr9,    t1
+
+    clz.w            t1,     a4
+    li.w             t5,     24
+    sub.w            t1,     t1,    t5
+    la.local         t5,     .l_\lable\()put_h_jtable
+    alsl.d           t1,     t1,    t5,   3
+    ld.d             t6,     t1,    0
+    add.d            t5,     t5,    t6
+    jirl             $r0,    t5,    0
+
+    .align   3
+.l_\lable\()put_h_jtable:
+    .dword .l_\lable\()put_h_128w - .l_\lable\()put_h_jtable
+    .dword .l_\lable\()put_h_64w  - .l_\lable\()put_h_jtable
+    .dword .l_\lable\()put_h_32w  - .l_\lable\()put_h_jtable
+    .dword .l_\lable\()put_h_16w  - .l_\lable\()put_h_jtable
+    .dword .l_\lable\()put_h_8w   - .l_\lable\()put_h_jtable
+    .dword .l_\lable\()put_h_4w   - .l_\lable\()put_h_jtable
+    .dword .l_\lable\()put_h_2w   - .l_\lable\()put_h_jtable
+
+.l_\lable\()put_h_2w:
+    addi.d           t7,     t7,    2
+    addi.d           a2,     a2,    -1
+    vldrepl.w        vr8,    t7,    0
+    la.local         t7,     subpel_h_shuf0
+    vld              vr7,    t7,    0
+.l_\lable\()put_h_2w_loop:
+    vld              vr0,    a2,    0
+    vldx             vr1,    a2,    a3
+    add.d            a2,     a2,    t2
+
+    vshuf.b          vr0,    vr1,   vr0,   vr7
+    vdp2.h.bu.b      vr1,    vr0,   vr8
+    vhaddw.w.h       vr0,    vr1,   vr1
+    vpickev.h        vr0,    vr0,   vr0
+    vadd.h           vr0,    vr0,   vr9
+    vssrani.bu.h     vr0,    vr0,   6
+
+    vstelm.h         vr0,    a0,    0,     0
+    add.d            a0,     a0,    a1
+    vstelm.h         vr0,    a0,    0,     1
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_h_2w_loop
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_h_4w:
+    addi.d           t7,     t7,    2
+    addi.d           a2,     a2,    -1
+    vldrepl.w        vr8,    t7,    0
+    la.local         t7,     subpel_h_shuf1
+    vld              vr7,    t7,    0
+.l_\lable\()put_h_4w_loop:
+    vld              vr0,    a2,    0
+    vldx             vr1,    a2,    a3
+    add.d            a2,     a2,    t2
+
+    vshuf.b          vr0,    vr0,   vr0,   vr7
+    vshuf.b          vr1,    vr1,   vr1,   vr7
+    vmulwev.h.bu.b   vr2,    vr0,   vr8
+    vmulwev.h.bu.b   vr3,    vr1,   vr8
+    vmaddwod.h.bu.b  vr2,    vr0,   vr8
+    vmaddwod.h.bu.b  vr3,    vr1,   vr8
+    vhaddw.w.h       vr0,    vr2,   vr2
+    vhaddw.w.h       vr1,    vr3,   vr3
+    vpickev.h        vr0,    vr1,   vr0
+    vadd.h           vr0,    vr0,   vr9
+    vssrani.bu.h     vr0,    vr0,   6
+
+    vstelm.w         vr0,    a0,    0,     0
+    add.d            a0,     a0,    a1
+    vstelm.w         vr0,    a0,    0,     1
+    add.d            a0,     a0,    a1
+    addi.d           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_h_4w_loop
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_h_8w:
+    fld.d            f10,    t7,    0
+    vreplvei.w       vr11,   vr10,  1
+    vreplvei.w       vr10,   vr10,  0
+    la.local         t7,     subpel_h_shuf1
+    vld              vr6,    t7,    0
+    vaddi.bu         vr7,    vr6,   4
+    vaddi.bu         vr8,    vr6,   8
+    addi.d           a2,     a2,    -3
+.l_\lable\()put_h_8w_loop:
+    vld              vr0,    a2,    0
+    vldx             vr1,    a2,    a3
+    add.d            a2,     a2,    t2
+    PUT_H_8W         vr0
+    PUT_H_8W         vr1
+    vssrani.bu.h     vr1,    vr0,   6
+    vstelm.d         vr1,    a0,    0,    0
+    add.d            a0,     a0,    a1
+    vstelm.d         vr1,    a0,    0,    1
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_h_8w_loop
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_h_16w:
+.l_\lable\()put_h_32w:
+.l_\lable\()put_h_64w:
+.l_\lable\()put_h_128w:
+    fld.d            f10,    t7,    0
+    vreplvei.w       vr11,   vr10,  1
+    vreplvei.w       vr10,   vr10,  0
+    la.local         t7,     subpel_h_shuf1
+    vld              vr6,    t7,    0
+    vaddi.bu         vr7,    vr6,   4
+    vaddi.bu         vr8,    vr6,   8
+    addi.d           a2,     a2,    -3
+    addi.d           t0,     a2,    0 //src
+    addi.w           t5,     a5,    0 //h
+    addi.d           t8,     a0,    0 //dst
+.l_\lable\()put_h_16w_loop:
+    vld              vr0,    a2,    0
+    vld              vr1,    a2,    8
+    add.d            a2,     a2,    a3
+    PUT_H_8W         vr0
+    PUT_H_8W         vr1
+    vssrani.bu.h     vr1,    vr0,   6
+    vst              vr1,    a0,    0
+    add.d            a0,     a0,    a1
+    addi.d           a5,     a5,    -1
+    bnez             a5,     .l_\lable\()put_h_16w_loop
+    addi.d           a2,     t0,    16
+    addi.d           t0,     t0,    16
+    addi.d           a0,     t8,    16
+    addi.d           t8,     t8,    16
+    addi.w           a5,     t5,    0
+    addi.w           a4,     a4,    -16
+    bnez             a4,     .l_\lable\()put_h_16w_loop
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_v:
+    ld.d             t1,     sp,    0  //filter_type
+    srli.w           t1,     t1,    2
+    blt              t0,     a5,    .l_\lable\()put_v_idx_fv
+    andi             t1,     t1,    1
+    addi.w           t1,     t1,    3
+
+.l_\lable\()put_v_idx_fv:
+    addi.w           t5,     zero,  120
+    mul.w            t1,     t1,    t5
+    addi.w           t5,     a7,    -1
+    slli.w           t5,     t5,    3
+    add.w            t1,     t1,    t5
+    add.d            t1,     t6,    t1 //fv's offset
+    vldrepl.d        vr8,    t1,    0
+    sub.d            a2,     a2,    t3
+
+    vilvl.h          vr8,    vr8,   vr8
+    vreplvei.w       vr9,    vr8,   1
+    vreplvei.w       vr10,   vr8,   2
+    vreplvei.w       vr11,   vr8,   3
+    vreplvei.w       vr8,    vr8,   0
+
+    clz.w            t1,     a4
+    li.w             t5,     24
+    sub.w            t1,     t1,    t5
+    la.local         t5,     .l_\lable\()put_v_jtable
+    alsl.d           t1,     t1,    t5,   3
+    ld.d             t6,     t1,    0
+    add.d            t5,     t5,    t6
+    jirl             $r0,    t5,    0
+
+    .align   3
+.l_\lable\()put_v_jtable:
+    .dword .l_\lable\()put_v_128w - .l_\lable\()put_v_jtable
+    .dword .l_\lable\()put_v_64w  - .l_\lable\()put_v_jtable
+    .dword .l_\lable\()put_v_32w  - .l_\lable\()put_v_jtable
+    .dword .l_\lable\()put_v_16w  - .l_\lable\()put_v_jtable
+    .dword .l_\lable\()put_v_8w   - .l_\lable\()put_v_jtable
+    .dword .l_\lable\()put_v_4w   - .l_\lable\()put_v_jtable
+    .dword .l_\lable\()put_v_2w   - .l_\lable\()put_v_jtable
+
+.l_\lable\()put_v_2w:
+    fld.s            f0,     a2,    0
+    fldx.s           f1,     a2,    a3
+    fldx.s           f2,     a2,    t2
+    add.d            a2,     a2,    t3
+    fld.s            f3,     a2,    0
+    fldx.s           f4,     a2,    a3
+    fldx.s           f5,     a2,    t2
+    fldx.s           f6,     a2,    t3
+    add.d            a2,     a2,    t4
+
+    vilvl.h          vr0,    vr1,   vr0 //0 1
+    vilvl.h          vr1,    vr2,   vr1 //1 2
+    vilvl.b          vr0,    vr1,   vr0 //01 12
+    vilvl.h          vr2,    vr3,   vr2 //2 3
+    vilvl.h          vr3,    vr4,   vr3 //3 4
+    vilvl.b          vr1,    vr3,   vr2 //23 34
+    vilvl.h          vr2,    vr5,   vr4 //4 5
+    vilvl.h          vr3,    vr6,   vr5 //5 6
+    vilvl.b          vr2,    vr3,   vr2 //45 56
+.l_\lable\()put_v_2w_loop:
+    fld.s            f7,     a2,    0
+    vilvl.h          vr3,    vr7,   vr6 //6 7
+    fldx.s           f6,     a2,    a3
+    add.d            a2,     a2,    t2
+    vilvl.h          vr4,    vr6,   vr7 //7 8
+    vilvl.b          vr3,    vr4,   vr3 //67 78
+
+    vmulwev.h.bu.b   vr12,   vr0,   vr8
+    vmulwev.h.bu.b   vr13,   vr1,   vr9
+    vmulwev.h.bu.b   vr14,   vr2,   vr10
+    vmulwev.h.bu.b   vr15,   vr3,   vr11
+    vmaddwod.h.bu.b  vr12,   vr0,   vr8
+    vmaddwod.h.bu.b  vr13,   vr1,   vr9
+    vmaddwod.h.bu.b  vr14,   vr2,   vr10
+    vmaddwod.h.bu.b  vr15,   vr3,   vr11
+    vaddi.hu         vr0,    vr1,   0
+    vaddi.hu         vr1,    vr2,   0
+    vaddi.hu         vr2,    vr3,   0
+    vadd.h           vr12,   vr12,  vr13
+    vadd.h           vr12,   vr12,  vr14
+    vadd.h           vr12,   vr12,  vr15
+
+    vssrarni.bu.h    vr12,   vr12,  6
+    vstelm.h         vr12,   a0,    0,   0
+    add.d            a0,     a0,    a1
+    vstelm.h         vr12,   a0,    0,   1
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_v_2w_loop
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_v_4w:
+    fld.s            f0,     a2,    0
+    fldx.s           f1,     a2,    a3
+    fldx.s           f2,     a2,    t2
+    add.d            a2,     a2,    t3
+    fld.s            f3,     a2,    0
+    fldx.s           f4,     a2,    a3
+    fldx.s           f5,     a2,    t2
+    fldx.s           f6,     a2,    t3
+    add.d            a2,     a2,    t4
+
+    vilvl.w          vr0,    vr1,   vr0
+    vilvl.w          vr1,    vr2,   vr1
+    vilvl.b          vr0,    vr1,   vr0
+    vilvl.w          vr1,    vr3,   vr2
+    vilvl.w          vr2,    vr4,   vr3
+    vilvl.b          vr1,    vr2,   vr1
+    vilvl.w          vr2,    vr5,   vr4
+    vilvl.w          vr3,    vr6,   vr5
+    vilvl.b          vr2,    vr3,   vr2
+.l_\lable\()put_v_4w_loop:
+    fld.s            f7,     a2,    0
+
+    vilvl.w          vr3,    vr7,   vr6
+    fldx.s           f6,     a2,    a3
+    add.d            a2,     a2,    t2
+    vilvl.w          vr4,    vr6,   vr7
+    vilvl.b          vr3,    vr4,   vr3
+
+    vmulwev.h.bu.b   vr12,   vr0,   vr8
+    vmulwev.h.bu.b   vr13,   vr1,   vr9
+    vmulwev.h.bu.b   vr14,   vr2,   vr10
+    vmulwev.h.bu.b   vr15,   vr3,   vr11
+    vmaddwod.h.bu.b  vr12,   vr0,   vr8
+    vmaddwod.h.bu.b  vr13,   vr1,   vr9
+    vmaddwod.h.bu.b  vr14,   vr2,   vr10
+    vmaddwod.h.bu.b  vr15,   vr3,   vr11
+    vaddi.hu         vr0,    vr1,   0
+    vaddi.hu         vr1,    vr2,   0
+    vaddi.hu         vr2,    vr3,   0
+    vadd.h           vr12,   vr12,  vr13
+    vadd.h           vr12,   vr12,  vr14
+    vadd.h           vr12,   vr12,  vr15
+
+    vssrarni.bu.h    vr12,   vr12,  6
+    vstelm.w         vr12,   a0,    0,   0
+    add.d            a0,     a0,    a1
+    vstelm.w         vr12,   a0,    0,   1
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_v_4w_loop
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_v_8w:
+.l_\lable\()put_v_16w:
+.l_\lable\()put_v_32w:
+.l_\lable\()put_v_64w:
+.l_\lable\()put_v_128w:
+    addi.d           t0,     a2,    0 //src
+    addi.d           t5,     a5,    0 //h
+    addi.d           t8,     a0,    0 //dst
+.l_\lable\()put_v_8w_loop0:
+    fld.d            f0,     a2,    0
+    fldx.d           f1,     a2,    a3
+    fldx.d           f2,     a2,    t2
+    add.d            a2,     a2,    t3
+    fld.d            f3,     a2,    0
+    fldx.d           f4,     a2,    a3
+    fldx.d           f5,     a2,    t2
+    fldx.d           f6,     a2,    t3
+    add.d            a2,     a2,    t4
+
+    vilvl.b          vr0,    vr1,   vr0 //0 1
+    vilvl.b          vr1,    vr2,   vr1 //1 2
+    vilvl.b          vr2,    vr3,   vr2 //2 3
+    vilvl.b          vr3,    vr4,   vr3 //3 4
+    vilvl.b          vr4,    vr5,   vr4 //4 5
+    vilvl.b          vr5,    vr6,   vr5 //5 6
+.l_\lable\()put_v_8w_loop:
+    fld.d            f7,     a2,    0
+    vilvl.b          vr12,   vr7,   vr6 //6 7
+    fldx.d           f6,     a2,    a3
+    add.d            a2,     a2,    t2
+    vilvl.b          vr13,   vr6,   vr7 //7 8
+
+    vmulwev.h.bu.b   vr14,   vr0,   vr8
+    vmulwev.h.bu.b   vr15,   vr1,   vr8
+    vmulwev.h.bu.b   vr16,   vr2,   vr9
+    vmulwev.h.bu.b   vr17,   vr3,   vr9
+    vmulwev.h.bu.b   vr18,   vr4,   vr10
+    vmulwev.h.bu.b   vr19,   vr5,   vr10
+    vmulwev.h.bu.b   vr20,   vr12,  vr11
+    vmulwev.h.bu.b   vr21,   vr13,  vr11
+    vmaddwod.h.bu.b  vr14,   vr0,   vr8
+    vmaddwod.h.bu.b  vr15,   vr1,   vr8
+    vmaddwod.h.bu.b  vr16,   vr2,   vr9
+    vmaddwod.h.bu.b  vr17,   vr3,   vr9
+    vmaddwod.h.bu.b  vr18,   vr4,   vr10
+    vmaddwod.h.bu.b  vr19,   vr5,   vr10
+    vmaddwod.h.bu.b  vr20,   vr12,  vr11
+    vmaddwod.h.bu.b  vr21,   vr13,  vr11
+
+    vaddi.hu         vr0,    vr2,   0
+    vaddi.hu         vr1,    vr3,   0
+    vaddi.hu         vr2,    vr4,   0
+    vaddi.hu         vr3,    vr5,   0
+    vaddi.hu         vr4,    vr12,  0
+    vaddi.hu         vr5,    vr13,  0
+    vadd.h           vr14,   vr14,  vr16
+    vadd.h           vr14,   vr14,  vr18
+    vadd.h           vr14,   vr14,  vr20
+    vadd.h           vr15,   vr15,  vr17
+    vadd.h           vr15,   vr15,  vr19
+    vadd.h           vr15,   vr15,  vr21
+
+    vssrarni.bu.h    vr15,   vr14,  6
+    vstelm.d         vr15,   a0,    0,   0
+    add.d            a0,     a0,    a1
+    vstelm.d         vr15,   a0,    0,   1
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_v_8w_loop
+    addi.d           a2,     t0,    8
+    addi.d           t0,     t0,    8
+    addi.d           a0,     t8,    8
+    addi.d           t8,     t8,    8
+    addi.d           a5,     t5,    0
+    addi.w           a4,     a4,    -8
+    bnez             a4,     .l_\lable\()put_v_8w_loop0
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_hv:
+    ld.d             t5,     sp,    0  //filter_type
+    andi             t1,     t5,    3
+    blt              t0,     a4,    .l_\lable\()put_hv_idx_fh
+    andi             t1,     t5,    1
+    addi.w           t1,     t1,    3
+.l_\lable\()put_hv_idx_fh:
+    addi.w           t5,     zero,  120
+    mul.w            t1,     t1,    t5
+    addi.w           t5,     a6,    -1
+    slli.w           t5,     t5,    3
+    add.w            t1,     t1,    t5
+    add.d            t1,     t6,    t1 //fh's offset
+    vldrepl.d        vr8,    t1,    0
+    ld.d             t1,     sp,    0  //filter_type
+    srli.w           t1,     t1,    2
+    blt              t0,     a5,    .l_\lable\()put_hv_idx_fv
+    andi             t1,     t1,    1
+    addi.w           t1,     t1,    3
+.l_\lable\()put_hv_idx_fv:
+    addi.w           t5,     zero,  120
+    mul.w            t1,     t1,    t5
+    addi.w           t5,     a7,    -1
+    slli.w           t5,     t5,    3
+    add.w            t1,     t1,    t5
+    add.d            t1,     t6,    t1 //fv's offset
+    vldrepl.d        vr9,    t1,    0
+    vexth.h.b        vr9,    vr9
+
+    sub.d            a2,     a2,    t3
+    addi.d           a2,     a2,    -3
+
+    clz.w            t1,     a4
+    li.w             t5,     24
+    sub.w            t1,     t1,    t5
+    la.local         t5,     .l_\lable\()put_hv_jtable
+    alsl.d           t1,     t1,    t5,   3
+    ld.d             t6,     t1,    0
+    add.d            t5,     t5,    t6
+    jirl             $r0,    t5,    0
+
+    .align   3
+.l_\lable\()put_hv_jtable:
+    .dword .l_\lable\()put_hv_128w - .l_\lable\()put_hv_jtable
+    .dword .l_\lable\()put_hv_64w  - .l_\lable\()put_hv_jtable
+    .dword .l_\lable\()put_hv_32w  - .l_\lable\()put_hv_jtable
+    .dword .l_\lable\()put_hv_16w  - .l_\lable\()put_hv_jtable
+    .dword .l_\lable\()put_hv_8w   - .l_\lable\()put_hv_jtable
+    .dword .l_\lable\()put_hv_4w   - .l_\lable\()put_hv_jtable
+    .dword .l_\lable\()put_hv_2w   - .l_\lable\()put_hv_jtable
+
+.l_\lable\()put_hv_2w:
+    addi.d           a2,     a2,    2
+    vld              vr0,    a2,    0
+    vldx             vr1,    a2,    a3
+    vldx             vr2,    a2,    t2
+    add.d            a2,     a2,    t3
+    vld              vr3,    a2,    0
+    vldx             vr4,    a2,    a3
+    vldx             vr5,    a2,    t2
+    vldx             vr6,    a2,    t3
+    add.d            a2,     a2,    t4
+
+    la.local         t1,     subpel_h_shuf0
+    vld              vr7,    t1,    0
+    vbsrl.v          vr8,    vr8,   2
+    vreplvei.w       vr8,    vr8,   0
+
+    //fv
+    vreplvei.w       vr14,   vr9,   1
+    vreplvei.w       vr15,   vr9,   2
+    vreplvei.w       vr16,   vr9,   3
+    vreplvei.w       vr9,    vr9,   0
+
+    vshuf.b          vr0,    vr1,   vr0,  vr7
+    vshuf.b          vr1,    vr3,   vr2,  vr7
+    vshuf.b          vr2,    vr5,   vr4,  vr7
+    vshuf.b          vr3,    vr6,   vr6,  vr7
+    vmulwev.h.bu.b   vr10,   vr0,   vr8
+    vmulwev.h.bu.b   vr11,   vr1,   vr8
+    vmulwev.h.bu.b   vr12,   vr2,   vr8
+    vmulwev.h.bu.b   vr13,   vr3,   vr8
+    vmaddwod.h.bu.b  vr10,   vr0,   vr8
+    vmaddwod.h.bu.b  vr11,   vr1,   vr8
+    vmaddwod.h.bu.b  vr12,   vr2,   vr8
+    vmaddwod.h.bu.b  vr13,   vr3,   vr8
+    vhaddw.w.h       vr0,    vr10,  vr10
+    vhaddw.w.h       vr1,    vr11,  vr11
+    vssrarni.h.w     vr1,    vr0,   2 //h0 h1 h2 h3
+    vhaddw.w.h       vr2,    vr12,  vr12
+    vhaddw.w.h       vr3,    vr13,  vr13
+    vssrarni.h.w     vr3,    vr2,   2 //h4 h5 h6 ~
+    vbsrl.v          vr2,    vr1,   4
+    vextrins.w       vr2,    vr3,   0x30 //h1 h2 h3 h4
+    vilvl.h          vr4,    vr2,   vr1 //h0 h1 h1 h2 --
+    vilvh.h          vr5,    vr2,   vr1 //h2 h3 h3 h4 --
+    vbsrl.v          vr6,    vr3,   4
+    vilvl.h          vr6,    vr6,   vr3 //h4 h5 h5 h6 --
+    vbsrl.v          vr3,    vr3,   8  //h6 ~
+.l_\lable\()put_hv_2w_loop:
+    vld              vr0,    a2,    0
+    vldx             vr2,    a2,    a3
+    add.d            a2,     a2,    t2
+    vshuf.b          vr0,    vr2,   vr0,  vr7
+    vdp2.h.bu.b      vr17,   vr0,   vr8
+    vhaddw.w.h       vr17,   vr17,  vr17
+    vssrarni.h.w     vr17,   vr17,  2 //h7 h8
+    vextrins.w       vr3,    vr17,  0x10 //h6 h7
+    vilvl.h          vr3,    vr17,  vr3  //h6 h7 h7 h8 --
+
+    vmulwev.w.h      vr18,   vr4,   vr9
+    vmulwev.w.h      vr19,   vr5,   vr14
+    vmulwev.w.h      vr20,   vr6,   vr15
+    vmulwev.w.h      vr21,   vr3,   vr16
+    vmaddwod.w.h     vr18,   vr4,   vr9
+    vmaddwod.w.h     vr19,   vr5,   vr14
+    vmaddwod.w.h     vr20,   vr6,   vr15
+    vmaddwod.w.h     vr21,   vr3,   vr16
+    vaddi.hu         vr4,    vr5,   0
+    vaddi.hu         vr5,    vr6,   0
+    vaddi.hu         vr6,    vr3,   0
+    vbsrl.v          vr3,    vr17,  4 //h8 ~
+    vadd.w           vr18,   vr18,  vr19
+    vadd.w           vr18,   vr18,  vr20
+    vadd.w           vr18,   vr18,  vr21
+
+    vssrarni.hu.w    vr0,    vr18,  10
+    vssrani.bu.h     vr0,    vr0,   0
+    vstelm.h         vr0,    a0,    0,   0
+    add.d            a0,     a0,    a1
+    vstelm.h         vr0,    a0,    0,   1
+    add.d            a0,     a0,    a1
+    addi.d           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv_2w_loop
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_hv_4w:
+    addi.d           a2,     a2,    2 //ignore leading 0
+    vld              vr0,    a2,    0
+    vldx             vr1,    a2,    a3
+    vldx             vr2,    a2,    t2
+    add.d            a2,     a2,    t3
+    vld              vr3,    a2,    0
+    vldx             vr4,    a2,    a3
+    vldx             vr5,    a2,    t2
+    vldx             vr6,    a2,    t3
+    add.d            a2,     a2,    t4
+
+    la.local         t1,     subpel_h_shuf1
+    vld              vr7,    t1,    0
+    vbsrl.v          vr8,    vr8,   2
+    vreplvei.w       vr8,    vr8,   0
+
+    //fv
+    vreplvei.w       vr17,   vr9,   0
+    vreplvei.w       vr18,   vr9,   1
+    vreplvei.w       vr19,   vr9,   2
+    vreplvei.w       vr20,   vr9,   3
+
+    //DAV1D_FILTER_8TAP_RND
+    vshuf.b          vr0,    vr0,   vr0,  vr7
+    vshuf.b          vr1,    vr1,   vr1,  vr7
+    vshuf.b          vr2,    vr2,   vr2,  vr7
+    vshuf.b          vr3,    vr3,   vr3,  vr7
+    vshuf.b          vr4,    vr4,   vr4,  vr7
+    vshuf.b          vr5,    vr5,   vr5,  vr7
+    vshuf.b          vr6,    vr6,   vr6,  vr7
+
+    vmulwev.h.bu.b   vr10,   vr0,   vr8
+    vmulwev.h.bu.b   vr11,   vr1,   vr8
+    vmulwev.h.bu.b   vr12,   vr2,   vr8
+    vmulwev.h.bu.b   vr13,   vr3,   vr8
+    vmulwev.h.bu.b   vr14,   vr4,   vr8
+    vmulwev.h.bu.b   vr15,   vr5,   vr8
+    vmulwev.h.bu.b   vr16,   vr6,   vr8
+    vmaddwod.h.bu.b  vr10,   vr0,   vr8
+    vmaddwod.h.bu.b  vr11,   vr1,   vr8
+    vmaddwod.h.bu.b  vr12,   vr2,   vr8
+    vmaddwod.h.bu.b  vr13,   vr3,   vr8
+    vmaddwod.h.bu.b  vr14,   vr4,   vr8
+    vmaddwod.h.bu.b  vr15,   vr5,   vr8
+    vmaddwod.h.bu.b  vr16,   vr6,   vr8
+
+    vhaddw.w.h       vr10,   vr10,  vr10
+    vhaddw.w.h       vr11,   vr11,  vr11
+    vhaddw.w.h       vr12,   vr12,  vr12
+    vhaddw.w.h       vr13,   vr13,  vr13
+    vhaddw.w.h       vr14,   vr14,  vr14
+    vhaddw.w.h       vr15,   vr15,  vr15
+    vhaddw.w.h       vr16,   vr16,  vr16
+
+    vssrarni.h.w     vr10,   vr10,  2 //h0
+    vssrarni.h.w     vr11,   vr11,  2 //h1
+    vssrarni.h.w     vr12,   vr12,  2 //h2
+    vssrarni.h.w     vr13,   vr13,  2 //h3
+    vssrarni.h.w     vr14,   vr14,  2 //h4
+    vssrarni.h.w     vr15,   vr15,  2 //h5
+    vssrarni.h.w     vr16,   vr16,  2 //h6
+
+    //h0
+    vilvl.h          vr0,    vr11,  vr10 //01
+    vilvl.h          vr1,    vr13,  vr12 //23
+    vilvl.h          vr2,    vr15,  vr14 //45
+    //h1
+    vilvl.h          vr4,    vr12,  vr11 //12
+    vilvl.h          vr5,    vr14,  vr13 //34
+    vilvl.h          vr6,    vr16,  vr15 //56
+
+.l_\lable\()put_hv_4w_loop:
+    vld              vr9,    a2,    0
+    vldx             vr10,   a2,    a3
+    add.d            a2,     a2,    t2
+
+    //DAV1D_FILTER_8TAP_CLIP
+    vshuf.b          vr9,    vr9,   vr9,  vr7
+    vshuf.b          vr10,   vr10,  vr10, vr7
+    vmulwev.h.bu.b   vr11,   vr9,   vr8
+    vmulwev.h.bu.b   vr12,   vr10,  vr8
+    vmaddwod.h.bu.b  vr11,   vr9,   vr8
+    vmaddwod.h.bu.b  vr12,   vr10,  vr8
+    vhaddw.w.h       vr11,   vr11,  vr11
+    vhaddw.w.h       vr12,   vr12,  vr12
+    vssrarni.h.w     vr11,   vr11,  2 //h7
+    vssrarni.h.w     vr12,   vr12,  2 //h8
+    vilvl.h          vr3,    vr11,  vr16 //67
+    vilvl.h          vr13,   vr12,  vr11 //78
+
+    vmulwev.w.h      vr9,    vr0,   vr17
+    vmulwev.w.h      vr10,   vr1,   vr18
+    vmulwev.w.h      vr14,   vr2,   vr19
+    vmulwev.w.h      vr15,   vr3,   vr20
+    vmaddwod.w.h     vr9,    vr0,   vr17
+    vmaddwod.w.h     vr10,   vr1,   vr18
+    vmaddwod.w.h     vr14,   vr2,   vr19
+    vmaddwod.w.h     vr15,   vr3,   vr20
+    vadd.w           vr16,   vr9,   vr10
+    vadd.w           vr16,   vr16,  vr14
+    vadd.w           vr16,   vr16,  vr15
+
+    vmulwev.w.h      vr9,    vr4,   vr17
+    vmulwev.w.h      vr10,   vr5,   vr18
+    vmulwev.w.h      vr14,   vr6,   vr19
+    vmulwev.w.h      vr15,   vr13,  vr20
+    vmaddwod.w.h     vr9,    vr4,   vr17
+    vmaddwod.w.h     vr10,   vr5,   vr18
+    vmaddwod.w.h     vr14,   vr6,   vr19
+    vmaddwod.w.h     vr15,   vr13,  vr20
+    vadd.w           vr21,   vr9,   vr10
+    vadd.w           vr21,   vr21,  vr14
+    vadd.w           vr21,   vr21,  vr15
+
+    vssrarni.hu.w    vr21,   vr16,  10
+    vssrani.bu.h     vr21,   vr21,  0
+    //cache
+    vaddi.hu         vr0,    vr1,   0
+    vaddi.hu         vr1,    vr2,   0
+    vaddi.hu         vr2,    vr3,   0
+    vaddi.hu         vr4,    vr5,   0
+    vaddi.hu         vr5,    vr6,   0
+    vaddi.hu         vr6,    vr13,  0
+    vaddi.hu         vr16,   vr12,  0
+
+    vstelm.w         vr21,   a0,    0,    0
+    add.d            a0,     a0,    a1
+    vstelm.w         vr21,   a0,    0,    1
+    add.d            a0,     a0,    a1
+    addi.w           a5,     a5,    -2
+    bnez             a5,     .l_\lable\()put_hv_4w_loop
+    b                .l_\lable\()end_put_8tap
+
+.l_\lable\()put_hv_8w:
+.l_\lable\()put_hv_16w:
+.l_\lable\()put_hv_32w:
+.l_\lable\()put_hv_64w:
+.l_\lable\()put_hv_128w:
+    addi.d          sp,      sp,    -8*8
+    fst.d           f24,     sp,    0
+    fst.d           f25,     sp,    8
+    fst.d           f26,     sp,    16
+    fst.d           f27,     sp,    24
+    fst.d           f28,     sp,    32
+    fst.d           f29,     sp,    40
+    fst.d           f30,     sp,    48
+    fst.d           f31,     sp,    56
+    addi.d          t0,      a2,    0 //src
+    addi.d          t5,      a5,    0 //h
+    addi.d          t8,      a0,    0 //dst
+    la.local        t1,      subpel_h_shuf1
+    vld             vr7,     t1,    0
+    vaddi.bu        vr11,    vr7,   4
+    vaddi.bu        vr12,    vr7,   8
+    vreplvei.w      vr10,    vr8,   1
+    vreplvei.w      vr8,     vr8,   0
+    vreplvei.w      vr20,    vr9,   1
+    vreplvei.w      vr21,    vr9,   2
+    vreplvei.w      vr22,    vr9,   3
+    vreplvei.w      vr9,     vr9,   0
+.l_\lable\()put_hv_8w_loop0:
+    vld             vr0,     a2,    0
+    vldx            vr1,     a2,    a3
+    vldx            vr2,     a2,    t2
+    add.d           a2,      a2,    t3
+    vld             vr3,     a2,    0
+    vldx            vr4,     a2,    a3
+    vldx            vr5,     a2,    t2
+    vldx            vr6,     a2,    t3
+    add.d           a2,      a2,    t4
+
+    FILTER_8TAP_8W  vr0 //h0
+    FILTER_8TAP_8W  vr1 //h1
+    FILTER_8TAP_8W  vr2 //h2
+    FILTER_8TAP_8W  vr3 //h3
+    FILTER_8TAP_8W  vr4 //h4
+    FILTER_8TAP_8W  vr5 //h5
+    FILTER_8TAP_8W  vr6 //h6
+
+    //h0' low part
+    vilvl.h         vr23,    vr1,   vr0 //01
+    vilvl.h         vr24,    vr3,   vr2 //23
+    vilvl.h         vr25,    vr5,   vr4 //45
+    //h0' high part
+    vilvh.h         vr26,    vr1,   vr0 //01
+    vilvh.h         vr27,    vr3,   vr2 //23
+    vilvh.h         vr28,    vr5,   vr4 //45
+
+    //h1' low part
+    vilvl.h         vr29,    vr2,   vr1 //12
+    vilvl.h         vr30,    vr4,   vr3 //34
+    vilvl.h         vr31,    vr6,   vr5 //56
+    //h1' high part
+    vilvh.h         vr0,     vr2,   vr1 //12
+    vilvh.h         vr1,     vr4,   vr3 //34
+    vilvh.h         vr2,     vr6,   vr5 //56
+
+.l_\lable\()put_hv_8w_loop:
+    vld             vr3,     a2,    0
+    vldx            vr4,     a2,    a3
+    add.d           a2,      a2,    t2
+
+    FILTER_8TAP_8W  vr3 //h7
+    FILTER_8TAP_8W  vr4 //h8
+
+    //h0' low part
+    vilvl.h         vr16,    vr3,   vr6 //67 ~low
+    vmulwev.w.h     vr13,    vr23,  vr9
+    vmulwev.w.h     vr14,    vr24,  vr20
+    vmulwev.w.h     vr15,    vr25,  vr21
+    vmulwev.w.h     vr17,    vr16,  vr22
+    vmaddwod.w.h    vr13,    vr23,  vr9
+    vmaddwod.w.h    vr14,    vr24,  vr20
+    vmaddwod.w.h    vr15,    vr25,  vr21
+    vmaddwod.w.h    vr17,    vr16,  vr22
+    vadd.w          vr13,    vr13,  vr14
+    vadd.w          vr13,    vr13,  vr15
+    vadd.w          vr13,    vr13,  vr17
+    //cache
+    vaddi.hu        vr23,    vr24,  0
+    vaddi.hu        vr24,    vr25,  0
+    vaddi.hu        vr25,    vr16,  0
+
+    //h0' high part
+    vilvh.h         vr17,    vr3,   vr6 //67 ~high
+    vmulwev.w.h     vr14,    vr26,  vr9
+    vmulwev.w.h     vr15,    vr27,  vr20
+    vmulwev.w.h     vr16,    vr28,  vr21
+    vmulwev.w.h     vr18,    vr17,  vr22
+    vmaddwod.w.h    vr14,    vr26,  vr9
+    vmaddwod.w.h    vr15,    vr27,  vr20
+    vmaddwod.w.h    vr16,    vr28,  vr21
+    vmaddwod.w.h    vr18,    vr17,  vr22
+    vadd.w          vr14,    vr14,  vr15
+    vadd.w          vr14,    vr14,  vr16
+    vadd.w          vr14,    vr14,  vr18
+    vssrarni.hu.w   vr14,    vr13,  10
+    vssrarni.bu.h   vr5,     vr14,  0
+    vstelm.d        vr5,     a0,    0,   0
+    add.d           a0,      a0,    a1
+    //cache
+    vaddi.hu        vr26,    vr27,  0
+    vaddi.hu        vr27,    vr28,  0
+    vaddi.hu        vr28,    vr17,  0
+    vaddi.hu        vr6,     vr4,   0
+
+    vilvl.h         vr5,     vr4,   vr3 //78 ~low
+    vilvh.h         vr4,     vr4,   vr3 //78 ~high
+
+    //h1' low part
+    vmulwev.w.h     vr13,    vr29,  vr9
+    vmulwev.w.h     vr14,    vr30,  vr20
+    vmulwev.w.h     vr15,    vr31,  vr21
+    vmulwev.w.h     vr16,    vr5,   vr22
+    vmaddwod.w.h    vr13,    vr29,  vr9
+    vmaddwod.w.h    vr14,    vr30,  vr20
+    vmaddwod.w.h    vr15,    vr31,  vr21
+    vmaddwod.w.h    vr16,    vr5,   vr22
+    vadd.w          vr13,    vr13,  vr14
+    vadd.w          vr13,    vr13,  vr15
+    vadd.w          vr13,    vr13,  vr16
+    //cache
+    vaddi.hu        vr29,    vr30,  0
+    vaddi.hu        vr30,    vr31,  0
+    vaddi.hu        vr31,    vr5,   0
+
+    //h1' high part
+    vmulwev.w.h     vr14,    vr0,   vr9
+    vmulwev.w.h     vr15,    vr1,   vr20
+    vmulwev.w.h     vr16,    vr2,   vr21
+    vmulwev.w.h     vr17,    vr4,   vr22
+    vmaddwod.w.h    vr14,    vr0,   vr9
+    vmaddwod.w.h    vr15,    vr1,   vr20
+    vmaddwod.w.h    vr16,    vr2,   vr21
+    vmaddwod.w.h    vr17,    vr4,   vr22
+    vadd.w          vr14,    vr14,  vr15
+    vadd.w          vr14,    vr14,  vr16
+    vadd.w          vr14,    vr14,  vr17
+    vssrarni.hu.w   vr14,    vr13,  10
+    vssrarni.bu.h   vr5,     vr14,  0
+    vstelm.d        vr5,     a0,    0,   0
+    add.d           a0,      a0,    a1
+    //cache
+    vaddi.hu        vr0,     vr1,   0
+    vaddi.hu        vr1,     vr2,   0
+    vaddi.hu        vr2,     vr4,   0
+
+    addi.w          a5,      a5,    -2
+    bnez            a5,      .l_\lable\()put_hv_8w_loop
+    addi.d          a2,      t0,    8
+    addi.d          t0,      t0,    8
+    addi.d          a0,      t8,    8
+    addi.d          t8,      t8,    8
+    addi.d          a5,      t5,    0
+    addi.w          a4,      a4,    -8
+    bnez            a4,      .l_\lable\()put_hv_8w_loop0
+    fld.d           f24,     sp,    0
+    fld.d           f25,     sp,    8
+    fld.d           f26,     sp,    16
+    fld.d           f27,     sp,    24
+    fld.d           f28,     sp,    32
+    fld.d           f29,     sp,    40
+    fld.d           f30,     sp,    48
+    fld.d           f31,     sp,    56
+    addi.d          sp,      sp,    8*8
+.l_\lable\()end_put_8tap:
+.endm
+
+function put_8tap_regular_8bpc_lsx
+    addi.d   sp, sp,  -16
+    st.d   zero, sp,  0
+    PUT_8TAP_8BPC_LSX 0
+    addi.d   sp, sp,  16
+endfunc
+
+function put_8tap_smooth_regular_8bpc_lsx
+    addi.d   sp, sp,  -16
+    li.w     t0, 1
+    st.d     t0, sp,  0
+    PUT_8TAP_8BPC_LSX 1
+    addi.d   sp, sp,  16
+endfunc
+
+function put_8tap_sharp_regular_8bpc_lsx
+    addi.d   sp, sp,  -16
+    li.w     t0, 2
+    st.d     t0, sp,  0
+    PUT_8TAP_8BPC_LSX 2
+    addi.d   sp, sp,  16
+endfunc
+
+function put_8tap_regular_smooth_8bpc_lsx
+    addi.d   sp, sp,  -16
+    li.w     t0, 4
+    st.d     t0, sp,  0
+    PUT_8TAP_8BPC_LSX 4
+    addi.d   sp, sp,  16
+endfunc
+
+function put_8tap_smooth_8bpc_lsx
+    addi.d   sp, sp,  -16
+    li.w     t0, 5
+    st.d     t0, sp,  0
+    PUT_8TAP_8BPC_LSX 5
+    addi.d   sp, sp,  16
+endfunc
+
+function put_8tap_sharp_smooth_8bpc_lsx
+    addi.d   sp, sp,  -16
+    li.w     t0, 6
+    st.d     t0, sp,  0
+    PUT_8TAP_8BPC_LSX 6
+    addi.d   sp, sp,  16
+endfunc
+
+function put_8tap_regular_sharp_8bpc_lsx
+    addi.d   sp, sp,  -16
+    li.w     t0, 8
+    st.d     t0, sp,  0
+    PUT_8TAP_8BPC_LSX 8
+    addi.d   sp, sp,  16
+endfunc
+
+function put_8tap_smooth_sharp_8bpc_lsx
+    addi.d   sp, sp,  -16
+    li.w     t0, 9
+    st.d     t0, sp,  0
+    PUT_8TAP_8BPC_LSX 9
+    addi.d   sp, sp,  16
+endfunc
+
+function put_8tap_sharp_8bpc_lsx
+    addi.d   sp, sp,  -16
+    li.w     t0, 10
+    st.d     t0, sp,  0
+    PUT_8TAP_8BPC_LSX 10
+    addi.d   sp, sp,  16
+endfunc
+
+const shufb1
+.byte 0,1,2,3,4,5,6,7,1,2,3,4,5,6,7,8
+endconst
+
+.macro PREP_H_8W in0
+    vshuf.b          vr2,    \in0,  \in0,   vr6
+    vshuf.b          vr3,    \in0,  \in0,   vr7
+    vshuf.b          vr4,    \in0,  \in0,   vr8
+    vmulwev.h.bu.b   vr12,   vr2,   vr22
+    vmulwev.h.bu.b   vr13,   vr3,   vr23
+    vmulwev.h.bu.b   vr14,   vr3,   vr22
+    vmulwev.h.bu.b   vr15,   vr4,   vr23
+    vmaddwod.h.bu.b  vr12,   vr2,   vr22
+    vmaddwod.h.bu.b  vr13,   vr3,   vr23
+    vmaddwod.h.bu.b  vr14,   vr3,   vr22
+    vmaddwod.h.bu.b  vr15,   vr4,   vr23
+    vadd.h           vr12,   vr12,  vr13
+    vadd.h           vr14,   vr14,  vr15
+    vhaddw.w.h       vr12,   vr12,  vr12
+    vhaddw.w.h       \in0,   vr14,  vr14
+    vssrarni.h.w     \in0,   vr12,  2
+.endm
+
+.macro PREP_HV_8W_LASX in0
+    xvshuf.b         xr4,   \in0,  \in0,   xr19
+    xvshuf.b         xr5,   \in0,  \in0,   xr20
+    xvshuf.b         xr6,   \in0,  \in0,   xr21
+    xvmulwev.h.bu.b  xr7,   xr4,   xr22
+    xvmulwev.h.bu.b  xr9,   xr5,   xr23
+    xvmulwev.h.bu.b  xr10,  xr5,   xr22
+    xvmulwev.h.bu.b  xr11,  xr6,   xr23
+    xvmaddwod.h.bu.b xr7,   xr4,   xr22
+    xvmaddwod.h.bu.b xr9,   xr5,   xr23
+    xvmaddwod.h.bu.b xr10,  xr5,   xr22
+    xvmaddwod.h.bu.b xr11,  xr6,   xr23
+    xvadd.h          xr7,   xr7,   xr9
+    xvadd.h          xr9,   xr10,  xr11
+    xvhaddw.w.h      xr7,   xr7,   xr7
+    xvhaddw.w.h      \in0,  xr9,   xr9
+    xvssrarni.h.w    \in0,  xr7,   2
+.endm
+
+.macro PREP_8TAP_8BPC_LASX lable
+    li.w             t0,     4
+    la.local         t6,     dav1d_mc_subpel_filters
+    slli.d           t2,     a2,    1  //src_stride*2
+    add.d            t3,     t2,    a2 //src_stride*3
+    slli.d           t4,     t2,    1
+
+    bnez             a5,     .l_\lable\()h_lasx //mx
+    bnez             a6,     .l_\lable\()v_lasx
+
+    clz.w            t1,     a3
+    li.w             t5,     24
+    sub.w            t1,     t1,    t5
+    la.local         t5,     .l_\lable\()prep_hv0_jtable_lasx
+    alsl.d           t1,     t1,    t5,   1
+    ld.h             t8,     t1,    0
+    add.d            t5,     t5,    t8
+    jirl             $r0,    t5,    0
+
+    .align   3
+.l_\lable\()prep_hv0_jtable_lasx:
+    .hword .l_\lable\()hv0_128w_lasx - .l_\lable\()prep_hv0_jtable_lasx
+    .hword .l_\lable\()hv0_64w_lasx  - .l_\lable\()prep_hv0_jtable_lasx
+    .hword .l_\lable\()hv0_32w_lasx  - .l_\lable\()prep_hv0_jtable_lasx
+    .hword .l_\lable\()hv0_16w_lasx  - .l_\lable\()prep_hv0_jtable_lasx
+    .hword .l_\lable\()hv0_8w_lasx   - .l_\lable\()prep_hv0_jtable_lasx
+    .hword .l_\lable\()hv0_4w_lasx   - .l_\lable\()prep_hv0_jtable_lasx
+
+.l_\lable\()hv0_4w_lasx:
+    fld.s            f0,     a1,    0
+    fldx.s           f1,     a1,    a2
+    fldx.s           f2,     a1,    t2
+    fldx.s           f3,     a1,    t3
+    add.d            a1,     a1,    t4
+    xvpackev.w       xr0,    xr1,   xr0
+    xvpackev.w       xr1,    xr3,   xr2
+    xvpermi.q        xr0,    xr1,   0x02
+    xvsllwil.hu.bu   xr0,    xr0,   4
+    xvst             xr0,    a0,    0
+    addi.d           a0,     a0,    32
+    addi.d           a4,     a4,    -4
+    bnez             a4,     .l_\lable\()hv0_4w_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+.l_\lable\()hv0_8w_lasx:
+    fld.d            f0,     a1,    0
+    fldx.d           f1,     a1,    a2
+    fldx.d           f2,     a1,    t2
+    fldx.d           f3,     a1,    t3
+    add.d            a1,     a1,    t4
+    xvpermi.q        xr0,    xr1,   0x02
+    xvpermi.q        xr2,    xr3,   0x02
+    xvsllwil.hu.bu   xr0,    xr0,   4
+    xvsllwil.hu.bu   xr2,    xr2,   4
+    xvst             xr0,    a0,    0
+    xvst             xr2,    a0,    32
+    addi.d           a0,     a0,    64
+    addi.d           a4,     a4,    -4
+    bnez             a4,     .l_\lable\()hv0_8w_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+.l_\lable\()hv0_16w_lasx:
+    vld              vr0,    a1,    0
+    vldx             vr1,    a1,    a2
+    vldx             vr2,    a1,    t2
+    vldx             vr3,    a1,    t3
+    add.d            a1,     a1,    t4
+    vext2xv.hu.bu    xr0,    xr0
+    vext2xv.hu.bu    xr1,    xr1
+    vext2xv.hu.bu    xr2,    xr2
+    vext2xv.hu.bu    xr3,    xr3
+    xvslli.h         xr0,    xr0,   4
+    xvslli.h         xr1,    xr1,   4
+    xvslli.h         xr2,    xr2,   4
+    xvslli.h         xr3,    xr3,   4
+    xvst             xr0,    a0,    0
+    xvst             xr1,    a0,    32
+    xvst             xr2,    a0,    64
+    xvst             xr3,    a0,    96
+    addi.d           a0,     a0,    128
+    addi.d           a4,     a4,    -4
+    bnez             a4,     .l_\lable\()hv0_16w_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+.l_\lable\()hv0_32w_lasx:
+    xvld             xr0,    a1,    0
+    xvldx            xr1,    a1,    a2
+    xvldx            xr2,    a1,    t2
+    xvldx            xr3,    a1,    t3
+    add.d            a1,     a1,    t4
+    xvpermi.d        xr4,    xr0,   0xD8
+    xvpermi.d        xr5,    xr1,   0xD8
+    xvpermi.d        xr6,    xr2,   0xD8
+    xvpermi.d        xr7,    xr3,   0xD8
+    xvpermi.d        xr10,   xr0,   0x32
+    xvpermi.d        xr11,   xr1,   0x32
+    xvpermi.d        xr12,   xr2,   0x32
+    xvpermi.d        xr13,   xr3,   0x32
+    xvsllwil.hu.bu   xr0,    xr4,   4
+    xvsllwil.hu.bu   xr1,    xr5,   4
+    xvsllwil.hu.bu   xr2,    xr6,   4
+    xvsllwil.hu.bu   xr3,    xr7,   4
+    xvsllwil.hu.bu   xr4,    xr10,  4
+    xvsllwil.hu.bu   xr5,    xr11,  4
+    xvsllwil.hu.bu   xr6,    xr12,  4
+    xvsllwil.hu.bu   xr7,    xr13,  4
+    xvst             xr0,    a0,    0
+    xvst             xr4,    a0,    32
+    xvst             xr1,    a0,    64
+    xvst             xr5,    a0,    96
+    xvst             xr2,    a0,    128
+    xvst             xr6,    a0,    160
+    xvst             xr3,    a0,    192
+    xvst             xr7,    a0,    224
+    addi.d           a0,     a0,    256
+    addi.d           a4,     a4,    -4
+    bnez             a4,     .l_\lable\()hv0_32w_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+.l_\lable\()hv0_64w_lasx:
+.l_\lable\()hv0_128w_lasx:
+    addi.d           t0,     a1,    0
+    addi.d           t5,     a4,    0
+    srli.w           t7,     a3,    5
+    slli.w           t7,     t7,    6
+    addi.d           t8,     a0,    0
+.l_\lable\()hv0_32_loop_lasx:
+    xvld             xr0,    a1,    0
+    xvldx            xr1,    a1,    a2
+    xvldx            xr2,    a1,    t2
+    xvldx            xr3,    a1,    t3
+    add.d            a1,     a1,    t4
+    xvpermi.d        xr4,    xr0,   0xD8
+    xvpermi.d        xr5,    xr1,   0xD8
+    xvpermi.d        xr6,    xr2,   0xD8
+    xvpermi.d        xr7,    xr3,   0xD8
+    xvpermi.d        xr10,   xr0,   0x32
+    xvpermi.d        xr11,   xr1,   0x32
+    xvpermi.d        xr12,   xr2,   0x32
+    xvpermi.d        xr13,   xr3,   0x32
+    xvsllwil.hu.bu   xr0,    xr4,   4
+    xvsllwil.hu.bu   xr1,    xr5,   4
+    xvsllwil.hu.bu   xr2,    xr6,   4
+    xvsllwil.hu.bu   xr3,    xr7,   4
+    xvsllwil.hu.bu   xr4,    xr10,  4
+    xvsllwil.hu.bu   xr5,    xr11,  4
+    xvsllwil.hu.bu   xr6,    xr12,  4
+    xvsllwil.hu.bu   xr7,    xr13,  4
+    xvst             xr0,    a0,    0
+    xvst             xr4,    a0,    32
+    add.d            t1,     a0,    t7
+    xvst             xr1,    t1,    0
+    xvst             xr5,    t1,    32
+    add.d            t1,     t1,    t7
+    xvst             xr2,    t1,    0
+    xvst             xr6,    t1,    32
+    add.d            t1,     t1,    t7
+    xvst             xr3,    t1,    0
+    xvst             xr7,    t1,    32
+    add.d            a0,     t1,    t7
+    addi.d           a4,     a4,   -4
+    bnez             a4,     .l_\lable\()hv0_32_loop_lasx
+    addi.d           a1,     t0,    32
+    addi.d           t0,     t0,    32
+    addi.d           a0,     t8,    64
+    addi.d           t8,     t8,    64
+    addi.d           a4,     t5,    0
+    addi.d           a3,     a3,   -32
+    bnez             a3,     .l_\lable\()hv0_32_loop_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()h_lasx:
+    bnez             a6,     .l_\lable\()hv_lasx //if(fh) && if (fv)
+
+    andi             t1,    a7,    3
+    blt              t0,    a3,    .l_\lable\()h_idx_fh_lasx
+    andi             t1,    a7,    1
+    addi.w           t1,    t1,    3
+.l_\lable\()h_idx_fh_lasx:
+    addi.w           t5,    zero,  120
+    mul.w            t1,    t1,    t5
+    addi.w           t5,    a5,    -1
+    slli.w           t5,    t5,    3
+    add.w            t1,    t1,    t5
+    add.d            t1,    t6,    t1 //fh's offset
+    xvldrepl.d       xr22,  t1,    0
+
+    addi.d           a1,    a1,    -3
+    clz.w            t1,    a3
+    li.w             t5,    24
+    sub.w            t1,    t1,    t5
+    la.local         t5,    .l_\lable\()prep_h_jtable_lasx
+    alsl.d           t1,    t1,    t5,   1
+    ld.h             t8,    t1,    0
+    add.d            t5,    t5,    t8
+    jirl             $r0,   t5,    0
+
+    .align   3
+.l_\lable\()prep_h_jtable_lasx:
+    .hword .l_\lable\()h_128w_lasx - .l_\lable\()prep_h_jtable_lasx
+    .hword .l_\lable\()h_64w_lasx  - .l_\lable\()prep_h_jtable_lasx
+    .hword .l_\lable\()h_32w_lasx  - .l_\lable\()prep_h_jtable_lasx
+    .hword .l_\lable\()h_16w_lasx  - .l_\lable\()prep_h_jtable_lasx
+    .hword .l_\lable\()h_8w_lasx   - .l_\lable\()prep_h_jtable_lasx
+    .hword .l_\lable\()h_4w_lasx   - .l_\lable\()prep_h_jtable_lasx
+
+.l_\lable\()h_4w_lasx:
+    addi.d           a1,    a1,    2
+    la.local         t7,    subpel_h_shuf1
+    vld              vr7,   t7,    0
+    xvreplve0.q      xr7,   xr7
+    xvbsrl.v         xr22,  xr22,  2
+    xvreplve0.w      xr22,  xr22
+.l_\lable\()h_4w_loop_lasx:
+    vld              vr0,   a1,    0
+    vldx             vr1,   a1,    a2
+    vldx             vr2,   a1,    t2
+    vldx             vr3,   a1,    t3
+    add.d            a1,    a1,    t4
+    xvpermi.q        xr1,   xr0,   0x20
+    xvpermi.q        xr3,   xr2,   0x20
+    xvshuf.b         xr1,   xr1,   xr1,   xr7
+    xvshuf.b         xr3,   xr3,   xr3,   xr7
+    xvmulwev.h.bu.b  xr0,   xr1,   xr22
+    xvmulwev.h.bu.b  xr2,   xr3,   xr22
+    xvmaddwod.h.bu.b xr0,   xr1,   xr22
+    xvmaddwod.h.bu.b xr2,   xr3,   xr22
+    xvhaddw.w.h      xr0,   xr0,   xr0
+    xvhaddw.w.h      xr2,   xr2,   xr2
+    xvssrarni.h.w    xr2,   xr0,   2
+    xvpermi.d        xr2,   xr2,   0xd8
+    xvst             xr2,   a0,    0
+    addi.d           a0,    a0,    32
+    addi.w           a4,    a4,    -4
+    bnez             a4,    .l_\lable\()h_4w_loop_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()h_8w_lasx:
+    la.local         t7,    subpel_h_shuf1
+    vld              vr6,   t7,    0
+    vbsrl.v          vr23,  vr22,  4 //fh
+    xvreplve0.w      xr23,  xr23
+    xvreplve0.w      xr22,  xr22
+    xvreplve0.q      xr19,  xr6
+    xvaddi.bu        xr20,  xr19,  4
+    xvaddi.bu        xr21,  xr19,  8
+.l_\lable\()h_8w_loop_lasx:
+    xvld             xr0,   a1,    0
+    xvldx            xr1,   a1,    a2
+    add.d            a1,    a1,    t2
+    xvpermi.q        xr0,   xr1,   0x02
+    PREP_HV_8W_LASX  xr0
+    xvst             xr0,   a0,    0
+    addi.d           a0,    a0,    32
+    addi.d           a4,    a4,   -2
+    bnez             a4,    .l_\lable\()h_8w_loop_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()h_16w_lasx:
+    la.local         t7,    subpel_h_shuf1
+    vld              vr6,   t7,    0
+    vbsrl.v          vr23,  vr22,  4 //fh
+    xvreplve0.w      xr23,  xr23
+    xvreplve0.w      xr22,  xr22
+    xvreplve0.q      xr19,  xr6
+    xvaddi.bu        xr20,  xr19,  4
+    xvaddi.bu        xr21,  xr19,  8
+.l_\lable\()h_16w_loop_lasx:
+    xvld             xr0,   a1,    0
+    xvld             xr1,   a1,    8
+    add.d            a1,    a1,    a2
+    xvpermi.q        xr0,   xr1,   0x02
+    PREP_HV_8W_LASX  xr0
+    xvst             xr0,   a0,    0
+    xvld             xr0,   a1,    0
+    xvld             xr1,   a1,    8
+    add.d            a1,    a1,    a2
+    xvpermi.q        xr0,   xr1,   0x02
+    PREP_HV_8W_LASX  xr0
+    xvst             xr0,   a0,    32
+    addi.d           a0,    a0,    64
+    addi.w           a4,    a4,    -2
+    bnez             a4,     .l_\lable\()h_16w_loop_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()h_32w_lasx:
+.l_\lable\()h_64w_lasx:
+.l_\lable\()h_128w_lasx:
+    la.local         t7,    subpel_h_shuf1
+    vld              vr6,   t7,    0
+    vbsrl.v          vr23,  vr22,  4 //fh
+    xvreplve0.w      xr23,  xr23
+    xvreplve0.w      xr22,  xr22
+    xvreplve0.q      xr19,  xr6
+    xvaddi.bu        xr20,  xr19,  4
+    xvaddi.bu        xr21,  xr19,  8
+    addi.d           t5,    a1,    0 //src
+    addi.d           t6,    a3,    0 //w
+    slli.w           t7,    a3,    1 //store offset
+    addi.d           t8,    a0,    0 //dst
+.l_\lable\()h_16_loop_lasx:
+    xvld             xr0,   a1,    0
+    xvld             xr1,   a1,    8
+    xvpermi.q        xr0,   xr1,   0x02
+    PREP_HV_8W_LASX  xr0
+    xvst             xr0,   a0,    0
+    xvld             xr0,   a1,    16
+    xvld             xr1,   a1,    24
+    xvpermi.q        xr0,   xr1,   0x02
+    PREP_HV_8W_LASX  xr0
+    xvst             xr0,   a0,    32
+    addi.d           a0,    a0,    64
+    addi.d           a1,    a1,    32
+    addi.d           a3,    a3,   -32
+    bnez             a3,    .l_\lable\()h_16_loop_lasx
+    add.d            a1,    t5,    a2
+    add.d            t5,    t5,    a2
+    add.d            a0,    t8,    t7
+    add.d            t8,    t8,    t7
+    addi.d           a3,    t6,    0
+    addi.d           a4,    a4,    -1
+    bnez             a4,    .l_\lable\()h_16_loop_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()hv_lasx:
+    andi             t1,    a7,    3
+    blt              t0,    a3,    .l_\lable\()hv_idx_fh_lasx
+    andi             t1,    a7,    1
+    addi.w           t1,    t1,    3
+.l_\lable\()hv_idx_fh_lasx:
+    addi.w           t5,    zero,  120
+    mul.w            t1,    t1,    t5
+    addi.w           t5,    a5,    -1
+    slli.w           t5,    t5,    3
+    add.w            t1,    t1,    t5
+    add.d            t1,    t6,    t1 //fh's offset
+    xvldrepl.d       xr22,  t1,    0
+    srli.w           a7,    a7,    2
+    blt              t0,    a4,    .l_\lable\()hv_idx_fv_lasx
+    andi             a7,    a7,    1
+    addi.w           a7,    a7,    3
+.l_\lable\()hv_idx_fv_lasx:
+    addi.w           t5,    zero,  120
+    mul.w            a7,    a7,    t5
+    addi.w           t5,    a6,    -1
+    slli.w           t5,    t5,    3
+    add.w            a7,    a7,    t5
+    add.d            a7,    t6,    a7 //fv's offset
+    xvldrepl.d       xr8,   a7,    0
+    xvsllwil.h.b     xr8,   xr8,   0
+    sub.d            a1,    a1,    t3
+    addi.d           a1,    a1,    -1 //ignore leading 0s
+    beq              a3,    t0,    .l_\lable\()hv_4w_lasx
+    addi.d           a1,    a1,    -2
+    b                .l_\lable\()hv_8w_lasx
+.l_\lable\()hv_4w_lasx:
+    xvld             xr0,   a1,    0
+    xvldx            xr1,   a1,    a2
+    xvldx            xr2,   a1,    t2
+    xvldx            xr3,   a1,    t3
+    add.d            a1,    a1,    t4
+    xvld             xr4,   a1,    0
+    xvldx            xr5,   a1,    a2
+    xvldx            xr6,   a1,    t2
+    la.local         t1,    subpel_h_shuf2
+    xvld             xr7,   t1,    0
+    vbsrl.v          vr22,  vr22,  2
+    xvreplve0.w      xr22,  xr22
+    xvreplve0.q      xr8,   xr8
+    xvrepl128vei.w   xr12,  xr8,   0
+    xvrepl128vei.w   xr13,  xr8,   1
+    xvrepl128vei.w   xr14,  xr8,   2
+    xvrepl128vei.w   xr15,  xr8,   3
+    xvilvl.d         xr0,   xr1,   xr0
+    xvilvl.d         xr2,   xr3,   xr2
+    xvilvl.d         xr4,   xr5,   xr4
+    xvreplve0.q      xr0,   xr0
+    xvreplve0.q      xr2,   xr2
+    xvreplve0.q      xr4,   xr4
+    xvreplve0.q      xr6,   xr6
+    xvshuf.b         xr0,   xr0,   xr0,   xr7
+    xvshuf.b         xr2,   xr2,   xr2,   xr7
+    xvshuf.b         xr4,   xr4,   xr4,   xr7
+    xvshuf.b         xr6,   xr6,   xr6,   xr7
+    xvmulwev.h.bu.b  xr1,   xr0,   xr22
+    xvmulwev.h.bu.b  xr3,   xr2,   xr22
+    xvmulwev.h.bu.b  xr5,   xr4,   xr22
+    xvmulwev.h.bu.b  xr9,   xr6,   xr22
+    xvmaddwod.h.bu.b xr1,   xr0,   xr22
+    xvmaddwod.h.bu.b xr3,   xr2,   xr22
+    xvmaddwod.h.bu.b xr5,   xr4,   xr22
+    xvmaddwod.h.bu.b xr9,   xr6,   xr22
+    xvhaddw.w.h      xr1,   xr1,   xr1  // a0 b0 a1 b1  c0 d0 c1 d1
+    xvhaddw.w.h      xr3,   xr3,   xr3  // a2 b2 a3 b3  c2 d2 c3 d3
+    xvhaddw.w.h      xr5,   xr5,   xr5  // a4 b4 a5 b5  c4 d4 c5 d5
+    xvhaddw.w.h      xr9,   xr9,   xr9  // a6 b6 -  -   c6 d6 -  -
+    xvssrarni.h.w    xr3,   xr1,   2    // a0 b0 a1 b1  a2 b2 a3 b3  c0 d0 c1 d1  c2 d2 c3 d3
+    xvssrarni.h.w    xr9,   xr5,   2    // a4 b4 a5 b5  a6 b6 -  -   c4 d4 c5 d5  c6 d6 -  -
+    xvbsrl.v         xr4,   xr3,   4
+    xvextrins.w      xr4,   xr9,   0x30 // a1 b1 a2 b2  a3 b3 a4 b4  c1 d1 c2 d2  c3 d3 c4 d4
+    xvilvl.h         xr5,   xr4,   xr3  // a0 a1 b0 b1  a1 a2 b1 b2  c0 c1 d0 d1  c1 c2 d1 d2
+    xvilvh.h         xr6,   xr4,   xr3  // a2 a3 b2 b3  a3 a4 b3 b4  c2 c3 d2 d3  c3 c4 d3 d4
+    xvbsrl.v         xr10,  xr9,   4    // a5 b5 a6 b6  -  -  -  -   c5 d5 c6 d6  -  -  -  -
+    xvilvl.h         xr11,  xr10,  xr9  // a4 a5 b4 b5  a5 a6 b5 b6  c4 c5 d4 d5  c5 c6 d5 d6
+.l_\lable\()hv_w4_loop_lasx:
+    xvmulwev.w.h     xr16,  xr5,   xr12 //a0 a1 (h0)
+    xvmulwev.w.h     xr17,  xr6,   xr12 //a2 a3 (h1)
+    xvmulwev.w.h     xr18,  xr6,   xr13 //a2 a3 (h0)
+    xvmulwev.w.h     xr19,  xr11,  xr13 //a4 a5 (h1)
+    xvmulwev.w.h     xr20,  xr11,  xr14 //a4 a5 (h0)
+    xvmaddwod.w.h    xr16,  xr5,   xr12 //
+    xvmaddwod.w.h    xr17,  xr6,   xr12 //
+    xvmaddwod.w.h    xr18,  xr6,   xr13 //
+    xvmaddwod.w.h    xr19,  xr11,  xr13 //
+    xvmaddwod.w.h    xr20,  xr11,  xr14 //
+    xvaddi.wu        xr5,   xr11,   0
+    xvadd.w          xr16,  xr16,  xr18 //a0 a1 + a2 a3
+    xvldx            xr18,  a1,    t3   //a7 b7 c7 d7
+    add.d            a1,    a1,    t4
+    xvadd.w          xr17,  xr17,  xr19 //a2 a3 + a4 a5
+    xvld             xr19,  a1,    0    //a8 b8 c8 d8
+    xvadd.w          xr16,  xr16,  xr20 //a0 a1 + a2 a3 + a4 a5
+    xvldx            xr20,  a1,    a2   //a9 b9 c9 d9
+    xvilvl.d         xr18,  xr19,  xr18
+    xvreplve0.q      xr18,  xr18
+    xvldx            xr19,  a1,    t2   //aa ba ca da
+    xvilvl.d         xr20,  xr19,  xr20
+    xvreplve0.q      xr20,  xr20
+    xvshuf.b         xr18,  xr18,  xr18,  xr7
+    xvshuf.b         xr20,  xr20,  xr20,  xr7
+    xvmulwev.h.bu.b  xr21,  xr18,  xr22
+    xvmulwev.h.bu.b  xr23,  xr20,  xr22
+    xvmaddwod.h.bu.b xr21,  xr18,  xr22
+    xvmaddwod.h.bu.b xr23,  xr20,  xr22
+    xvhaddw.w.h      xr21,  xr21,  xr21 //a7 b7 a8 b8 c7 d7 c8 d8
+    xvhaddw.w.h      xr23,  xr23,  xr23 //a9 b9 aa ba c9 d9 ca da
+    xvssrarni.h.w    xr23,  xr21,  2    //a7 b7 a8 b8  a9 b9 aa ba  c7 d7 c8 d8  c9 d9 ca da
+    xvbsll.v         xr0,   xr23,  4
+    xvextrins.w      xr0,   xr9,   0x02 //a6 b6 a7 b7  a8 b8 a9 b9  c6 d6 c7 d7  c8 d8 c9 d9
+    xvilvl.h         xr6,   xr23,  xr0  //a6 a7 b6 b7  a7 a8 b7 b8  c6 c7 d6 d7  c7 c8 d7 d8
+    xvilvh.h         xr11,  xr23,  xr0  //a8 a9 b8 b9  a9 aa b9 ba  c8 c9 d8 d9  c9 ca d9 da
+    xvbsrl.v         xr9,   xr23,  4
+    xvmulwev.w.h     xr1 ,  xr6,   xr14 //a6 a7 (h0)
+    xvmulwev.w.h     xr2 ,  xr6,   xr15 //a6 a7 (h1)
+    xvmulwev.w.h     xr3 ,  xr11,  xr15 //a8 a9 (h1)
+    xvmaddwod.w.h    xr1 ,  xr6,   xr14
+    xvmaddwod.w.h    xr2 ,  xr6,   xr15
+    xvmaddwod.w.h    xr3 ,  xr11,  xr15
+    xvadd.w          xr17,  xr17,  xr1  //a2 a3 + a4 a5 + a6 a7
+    xvadd.w          xr16,  xr16,  xr2  //a0 a1 + a2 a3 + a4 a5 + a6 a7
+    xvadd.w          xr17,  xr17,  xr3  //a2 a3 + a4 a5 + a6 a7 + a8 a9
+    xvssrarni.h.w    xr17,  xr16,  6    //a01 b01 a12 b12  a23 b23 a34 b34  c01 d01 c12 d12  c23 d23 c34 d34
+    xvpermi.d        xr17,  xr17,  0xd8 //a01 b01 a12 b12  c01 d01 c12 d12  a23 b23 a34 b34  c23 d23 c34 d34
+    xvshuf4i.w       xr17,  xr17,  0xd8
+    xvst             xr17,  a0,    0
+    addi.d           a0,    a0,    32
+    addi.d           a4,    a4,    -4
+    bnez             a4,    .l_\lable\()hv_w4_loop_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()hv_8w_lasx:
+    addi.d           sp,    sp,   -4*8
+    fst.d            f24,   sp,    0
+    fst.d            f25,   sp,    8
+    fst.d            f26,   sp,    16
+    fst.d            f27,   sp,    24
+    la.local         t1,    subpel_h_shuf1
+    vld              vr19,  t1,    0
+    addi.d           t0,    a1,    0
+    addi.d           t5,    a4,    0
+    slli.w           t7,    a3,    1 // store offset
+    addi.d           t8,    a0,    0
+    xvreplve0.q      xr19,  xr19
+    xvaddi.bu        xr20,  xr19,  4
+    xvaddi.bu        xr21,  xr19,  8
+    vbsrl.v          vr23,  vr22,  4
+    xvreplve0.w      xr22,  xr22 //f0f1f2f3
+    xvreplve0.w      xr23,  xr23 //f4f5f6f7
+    xvreplve0.q      xr8,   xr8
+    xvrepl128vei.w   xr24,  xr8,   0
+    xvrepl128vei.w   xr25,  xr8,   1
+    xvrepl128vei.w   xr26,  xr8,   2
+    xvrepl128vei.w   xr27,  xr8,   3
+.l_\lable\()hv_8w_loop0_lasx:
+    xvld             xr0,   a1,    0
+    xvldx            xr1,   a1,    a2
+    xvldx            xr2,   a1,    t2
+    add.d            a1,    a1,    t3
+    xvld             xr3,   a1,    0
+    xvldx            xr4,   a1,    a2
+    xvldx            xr5,   a1,    t2
+    xvldx            xr6,   a1,    t3
+    add.d            a1,    a1,    t4
+    xvpermi.q        xr0,   xr3,   0x02 //0 3
+    xvpermi.q        xr1,   xr4,   0x02 //1 4
+    xvpermi.q        xr2,   xr5,   0x02 //2 5
+    xvpermi.q        xr3,   xr6,   0x02 //3 6
+    PREP_HV_8W_LASX  xr0 //a0b0c0d0 e0f0g0h0 a3b3c3d3 e3f3g3h3
+    PREP_HV_8W_LASX  xr1 //a1b1c1d1 e1f1g1h1 a4b4c4d4 e4f4g4h4
+    PREP_HV_8W_LASX  xr2 //a2b2c2d2 e2f2g2h2 a5b5c5d5 e5f5g5h5
+    PREP_HV_8W_LASX  xr3 //a3b3c3d3 e3f3g3h3 a6b6c6d6 e6f6g6h6
+    xvpermi.d        xr0,   xr0,   0xd8
+    xvpermi.d        xr1,   xr1,   0xd8
+    xvpermi.d        xr2,   xr2,   0xd8
+    xvpermi.d        xr18,  xr3,   0xd8
+    xvilvl.h         xr12,  xr1,   xr0 //a0a1b0b1c0c1d0d1 e0e1f0f1g0g1h0h1
+    xvilvh.h         xr13,  xr1,   xr0 //a3a4b3b4c3c4d3d4 e3e4f3f4g3g4h3h4
+    xvilvl.h         xr14,  xr2,   xr1 //a1a2b1b2c1c2d1d2 e1e2f1f2g1g2h1h2
+    xvilvh.h         xr15,  xr2,   xr1 //a4a5b4b5c4c5d4d5 e4e5f4f5g4g5h4h5
+    xvilvl.h         xr16,  xr18,  xr2 //a2a3b2b3c2c3d2d3 e2e3f2f3g2g3h2h3
+    xvilvh.h         xr17,  xr18,  xr2 //a5a6b5b6c5c6d5d6 e5e6f5f6g5g6h5h6
+.l_\lable\()hv_8w_loop_lasx:
+    xvld             xr0,   a1,    0
+    xvldx            xr1,   a1,    a2
+    add.d            a1,    a1,    t2
+    xvpermi.q        xr0,   xr1,   0x02 //7 8
+    PREP_HV_8W_LASX  xr0                //a7b7c7d7e7f7g7h7 a8b8c8d8e8f8g8h8
+    xvpermi.q        xr3,   xr0,   0x03 //a6b6c6d6e6f6g6h6 a7b7c7d7e7f7g7h7
+    xvpermi.d        xr3,   xr3,   0xd8 //a6b6c6d6a7b7c7d7 e6f6g6h6e7f7g7h7
+    xvpermi.d        xr1,   xr0,   0xd8 //a7b7c7d7a8b8c8d8 e7f7g7h7e8f8g8h8
+    xvilvl.h         xr18,  xr1,   xr3  //a6a7b6b7c6c7d6d7 e6e7f6f7g6g7h6h7
+    xvilvh.h         xr2,   xr1,   xr3  //a7a8b7b8c7c8d7d8 e7e8f7f8g7g8h7h8
+    xvaddi.hu        xr3,   xr0,   0
+    xvmulwev.w.h     xr4,   xr12,  xr24 //01
+    xvmulwev.w.h     xr5,   xr14,  xr24 //12
+    xvmulwev.w.h     xr6,   xr16,  xr25 //23
+    xvmulwev.w.h     xr7,   xr13,  xr25 //34
+    xvmulwev.w.h     xr8,   xr15,  xr26 //45
+    xvmulwev.w.h     xr9,   xr17,  xr26 //56
+    xvmulwev.w.h     xr10,  xr18,  xr27 //67
+    xvmulwev.w.h     xr11,  xr2,   xr27 //78
+    xvmaddwod.w.h    xr4,   xr12,  xr24 //01
+    xvmaddwod.w.h    xr5,   xr14,  xr24 //12
+    xvmaddwod.w.h    xr6,   xr16,  xr25 //23
+    xvmaddwod.w.h    xr7,   xr13,  xr25 //34
+    xvmaddwod.w.h    xr8,   xr15,  xr26 //45
+    xvmaddwod.w.h    xr9,   xr17,  xr26 //56
+    xvmaddwod.w.h    xr10,  xr18,  xr27 //67
+    xvmaddwod.w.h    xr11,  xr2,   xr27 //78
+    xvadd.w          xr4,   xr4,   xr6
+    xvadd.w          xr5,   xr5,   xr7
+    xvadd.w          xr4,   xr4,   xr8
+    xvadd.w          xr5,   xr5,   xr9
+    xvadd.w          xr4,   xr4,   xr10
+    xvadd.w          xr5,   xr5,   xr11
+    xvaddi.hu        xr12,  xr16,  0 //01 <-- 23
+    xvaddi.hu        xr14,  xr13,  0 //12 <-- 34
+    xvaddi.hu        xr16,  xr15,  0 //23 <-- 45
+    xvaddi.hu        xr13,  xr17,  0 //34 <-- 56
+    xvaddi.hu        xr15,  xr18,  0 //45 <-- 67
+    xvaddi.hu        xr17,  xr2,   0 //56 <-- 78
+    xvssrarni.h.w    xr5,   xr4,   6
+    xvpermi.d        xr5,   xr5,   0xd8
+    vst              vr5,   a0,    0
+    xvpermi.q        xr5,   xr5,   0x11
+    vstx             vr5,   a0,    t7
+    alsl.d           a0,    t7,    a0,  1
+    addi.d           a4,    a4,   -2
+    bnez             a4,    .l_\lable\()hv_8w_loop_lasx
+    addi.d           a1,    t0,    8
+    addi.d           t0,    t0,    8
+    addi.d           a0,    t8,    16
+    addi.d           t8,    t8,    16
+    addi.d           a4,    t5,    0
+    addi.d           a3,    a3,   -8
+    bnez             a3,    .l_\lable\()hv_8w_loop0_lasx
+    fld.d            f24,   sp,    0
+    fld.d            f25,   sp,    8
+    fld.d            f26,   sp,    16
+    fld.d            f27,   sp,    24
+    addi.d           sp,    sp,    4*8
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()v_lasx:
+    srli.w           a7,    a7,    2
+    blt              t0,    a4,    .l_\lable\()v_idx_fv_lasx
+    andi             a7,    a7,    1
+    addi.w           a7,    a7,    3
+.l_\lable\()v_idx_fv_lasx:
+    addi.w           t5,    zero,  120
+    mul.w            a7,    a7,    t5
+    addi.w           t5,    a6,    -1
+    slli.w           t5,    t5,    3
+    add.w            a7,    a7,    t5
+    add.d            a7,    t6,    a7 //fv's offset
+    xvldrepl.d       xr8,   a7,    0
+    xvrepl128vei.h   xr12,  xr8,   0
+    xvrepl128vei.h   xr13,  xr8,   1
+    xvrepl128vei.h   xr14,  xr8,   2
+    xvrepl128vei.h   xr15,  xr8,   3
+    sub.d            a1,    a1,    t3
+    beq              a3,    t0,    .l_\lable\()v_4w_lasx
+    addi.w           t0,    t0,    4
+    beq              a3,    t0,    .l_\lable\()v_8w_lasx
+    blt              t0,    a3,    .l_\lable\()v_16w_lasx
+.l_\lable\()v_4w_lasx:
+    la.local         t6,    subpel_h_shuf3
+    xvld             xr11,  t6,    0
+    fld.s            f0,    a1,    0   //a0b0c0d0
+    fldx.s           f1,    a1,    a2  //a1b1c1d1
+    fldx.s           f2,    a1,    t2  //a2b2c2d2
+    add.d            a1,    a1,    t3
+    fld.s            f3,    a1,    0   //a3b3c3d3
+    fldx.s           f4,    a1,    a2  //a4b4c4d4
+    fldx.s           f5,    a1,    t2  //a5b5c5d5
+    fldx.s           f6,    a1,    t3  //a6b6c6d6
+    vilvl.w          vr0,   vr1,   vr0 //01
+    vilvl.w          vr1,   vr3,   vr2 //23
+    vilvl.d          vr0,   vr1,   vr0 //0123
+    vilvl.w          vr2,   vr5,   vr4 //45
+    vilvl.d          vr1,   vr2,   vr1 //2345
+    xvpermi.q        xr0,   xr1,   0x02 //0123 2345
+    xvbsrl.v         xr1,   xr0,   4    //123- 345-
+    xvpermi.q        xr4,   xr6,   0x02
+    xvextrins.w      xr1,   xr4,   0x30 //1234 3456
+    xvilvl.b         xr2,   xr1,   xr0  //0112 2334         //a0a1b0b1c0c1d0d1 a1a2b1b2c1c2d1d2 a2a3b2b3c2c3d2d3 a3a4b3b4c3c4d3d4
+    xvilvh.b         xr3,   xr1,   xr0  //2334 4556         //a2a3b2b3c2c3d2d3 a3a4b3b4c3c4d3d4 a4a5b4b5c4c5d4d5 a5a6b5b6c5c6d5d6
+.l_\lable\()v_4w_loop_lasx:
+    add.d            a1,    a1,    t4
+    fld.s            f0,    a1,    0  //a7b7c7d7
+    fldx.s           f1,    a1,    a2 //a8b8c8d8
+    fldx.s           f4,    a1,    t2 //a9b9c9d9
+    fldx.s           f5,    a1,    t3 //aabacada
+    vilvl.w          vr7,   vr0,   vr6 //67
+    vilvl.w          vr10,  vr4,   vr1 //89
+    vextrins.w       vr7,   vr1,   0x20//678-
+    vextrins.w       vr10,  vr5,   0x20//89a-
+    xvpermi.q        xr7,   xr10,  0x02//678- 89a-
+    xvshuf.b         xr4,   xr7,   xr7,  xr11 //67 78 89 9a //a6a7b6b7c6c7d6d7 a7a8b7b8c7c8d7d8 a8a9b8b9c8c9d8d9 a9aab9bac9cad9da
+    xvpermi.q        xr7,   xr3,   0x11 //4556
+    xvpermi.q        xr7,   xr4,   0x02 //45 56 67 78       //a4a5b4b5c4c5d4d5 a5a6b5b6c5c6d5d6 a6a7b6b7c6c7d6d7 a7a8b7b8c7c8d7d8
+    xvmulwev.h.bu.b  xr16,  xr2,   xr12
+    xvmulwev.h.bu.b  xr17,  xr3,   xr13
+    xvmulwev.h.bu.b  xr18,  xr7,   xr14
+    xvmulwev.h.bu.b  xr19,  xr4,   xr15
+    xvmaddwod.h.bu.b xr16,  xr2,   xr12
+    xvmaddwod.h.bu.b xr17,  xr3,   xr13
+    xvmaddwod.h.bu.b xr18,  xr7,   xr14
+    xvmaddwod.h.bu.b xr19,  xr4,   xr15
+    xvadd.h          xr16,  xr16,  xr17
+    xvadd.h          xr16,  xr16,  xr18
+    xvadd.h          xr16,  xr16,  xr19
+    xvsrari.h        xr16,  xr16,  2
+    xvaddi.bu        xr2,   xr7,   0
+    xvaddi.bu        xr3,   xr4,   0
+    xvaddi.bu        xr6,   xr5,   0
+    xvst             xr16,  a0,    0
+    addi.d           a0,    a0,    32
+    addi.w           a4,    a4,   -4
+    bnez             a4,    .l_\lable\()v_4w_loop_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()v_8w_lasx:
+    fld.d            f0,    a1,    0
+    fldx.d           f1,    a1,    a2
+    fldx.d           f2,    a1,    t2
+    add.d            a1,    a1,    t3
+    fld.d            f3,    a1,    0
+    fldx.d           f4,    a1,    a2
+    fldx.d           f5,    a1,    t2
+    fldx.d           f6,    a1,    t3
+    xvpermi.q        xr0,   xr1,   0x02
+    xvpermi.q        xr1,   xr2,   0x02
+    xvilvl.b         xr0,   xr1,   xr0 //01 12
+    xvpermi.q        xr2,   xr3,   0x02
+    xvpermi.q        xr3,   xr4,   0x02
+    xvilvl.b         xr2,   xr3,   xr2 //23 34
+    xvpermi.q        xr4,   xr5,   0x02
+    xvpermi.q        xr5,   xr6,   0x02
+    xvilvl.b         xr4,   xr5,   xr4 //45 56
+.l_\lable\()v_8w_loop_lasx:
+    add.d            a1,    a1,    t4
+    fld.d            f7,    a1,    0   //7
+    fldx.d           f10,   a1,    a2  //8
+    fldx.d           f11,   a1,    t2  //9
+    fldx.d           f18,   a1,    t3  //a
+    xvpermi.q        xr6,   xr7,   0x02
+    xvpermi.q        xr7,   xr10,  0x02
+    xvilvl.b         xr6,   xr7,   xr6  //67 78
+    xvpermi.q        xr10,  xr11,  0x02
+    xvpermi.q        xr11,  xr18,  0x02
+    xvilvl.b         xr10,  xr11,  xr10 //89 9a
+    xvmulwev.h.bu.b  xr1,   xr0,   xr12
+    xvmulwev.h.bu.b  xr3,   xr2,   xr13
+    xvmulwev.h.bu.b  xr5,   xr4,   xr14
+    xvmulwev.h.bu.b  xr7,   xr6,   xr15
+    xvmulwev.h.bu.b  xr9,   xr2,   xr12
+    xvmulwev.h.bu.b  xr11,  xr4,   xr13
+    xvmulwev.h.bu.b  xr16,  xr6,   xr14
+    xvmulwev.h.bu.b  xr17,  xr10,  xr15
+    xvmaddwod.h.bu.b xr1,   xr0,   xr12
+    xvmaddwod.h.bu.b xr3,   xr2,   xr13
+    xvmaddwod.h.bu.b xr5,   xr4,   xr14
+    xvmaddwod.h.bu.b xr7,   xr6,   xr15
+    xvmaddwod.h.bu.b xr9,   xr2,   xr12
+    xvmaddwod.h.bu.b xr11,  xr4,   xr13
+    xvmaddwod.h.bu.b xr16,  xr6,   xr14
+    xvmaddwod.h.bu.b xr17,  xr10,  xr15
+    xvadd.h          xr1,   xr1,   xr3
+    xvadd.h          xr1,   xr1,   xr5
+    xvadd.h          xr1,   xr1,   xr7
+    xvadd.h          xr9,   xr9,   xr11
+    xvadd.h          xr9,   xr9,   xr16
+    xvadd.h          xr9,   xr9,   xr17
+    xvaddi.bu        xr0,   xr4,   0
+    xvaddi.bu        xr2,   xr6,   0
+    xvaddi.bu        xr4,   xr10,  0
+    xvaddi.bu        xr6,   xr18,  0
+    xvsrari.h        xr1,   xr1,   2
+    xvsrari.h        xr9,   xr9,   2
+    xvst             xr1,   a0,    0
+    xvst             xr9,   a0,    32
+    addi.d           a0,    a0,    64
+    addi.w           a4,    a4,   -4
+    bnez             a4,    .l_\lable\()v_8w_loop_lasx
+    b                .l_\lable\()end_pre_8tap_lasx
+
+.l_\lable\()v_16w_lasx:
+    addi.d           t0,    a0,    0 //dst
+    addi.d           t5,    a1,    0 //src
+    slli.w           t7,    a3,    1 //w
+    addi.d           t8,    a4,    0 //h
+.l_\lable\()v_16w_loop0_lasx:
+    vld              vr0,   a1,    0
+    vldx             vr1,   a1,    a2
+    vldx             vr2,   a1,    t2
+    add.d            a1,    a1,    t3
+    vld              vr3,   a1,    0
+    vldx             vr4,   a1,    a2
+    vldx             vr5,   a1,    t2
+    vldx             vr6,   a1,    t3
+    add.d            a1,    a1,    t4
+    xvpermi.d        xr0,   xr0,   0xd8
+    xvpermi.d        xr1,   xr1,   0xd8
+    xvpermi.d        xr2,   xr2,   0xd8
+    xvpermi.d        xr3,   xr3,   0xd8
+    xvpermi.d        xr4,   xr4,   0xd8
+    xvpermi.d        xr5,   xr5,   0xd8
+    xvpermi.d        xr6,   xr6,   0xd8
+    xvilvl.b         xr0,   xr1,   xr0 //01
+    xvilvl.b         xr1,   xr2,   xr1 //12
+    xvilvl.b         xr2,   xr3,   xr2 //23
+    xvilvl.b         xr3,   xr4,   xr3 //34
+    xvilvl.b         xr4,   xr5,   xr4 //45
+    xvilvl.b         xr5,   xr6,   xr5 //56
+.l_\lable\()v_16w_loop_lasx:
+    vld              vr7,   a1,    0   //7
+    vldx             vr10,  a1,    a2  //8
+    add.d            a1,    a1,    t2
+    xvpermi.d        xr7,   xr7,   0xd8
+    xvpermi.d        xr10,  xr10,  0xd8
+    xvilvl.b         xr6,   xr7,   xr6 //67
+    xvilvl.b         xr7,   xr10,  xr7 //78
+    xvmulwev.h.bu.b  xr9,   xr0,   xr12
+    xvmulwev.h.bu.b  xr11,  xr2,   xr13
+    xvmulwev.h.bu.b  xr16,  xr4,   xr14
+    xvmulwev.h.bu.b  xr17,  xr6,   xr15
+    xvmulwev.h.bu.b  xr18,  xr1,   xr12
+    xvmulwev.h.bu.b  xr19,  xr3,   xr13
+    xvmulwev.h.bu.b  xr20,  xr5,   xr14
+    xvmulwev.h.bu.b  xr21,  xr7,   xr15
+    xvmaddwod.h.bu.b xr9,   xr0,   xr12
+    xvmaddwod.h.bu.b xr11,  xr2,   xr13
+    xvmaddwod.h.bu.b xr16,  xr4,   xr14
+    xvmaddwod.h.bu.b xr17,  xr6,   xr15
+    xvmaddwod.h.bu.b xr18,  xr1,   xr12
+    xvmaddwod.h.bu.b xr19,  xr3,   xr13
+    xvmaddwod.h.bu.b xr20,  xr5,   xr14
+    xvmaddwod.h.bu.b xr21,  xr7,   xr15
+    xvadd.h          xr9,   xr9,   xr11
+    xvadd.h          xr9,   xr9,   xr16
+    xvadd.h          xr9,   xr9,   xr17
+    xvadd.h          xr11,  xr18,  xr19
+    xvadd.h          xr11,  xr11,  xr20
+    xvadd.h          xr11,  xr11,  xr21
+    xvsrari.h        xr9,   xr9,   2
+    xvsrari.h        xr11,  xr11,  2
+    xvaddi.bu        xr0,   xr2,   0
+    xvaddi.bu        xr1,   xr3,   0
+    xvaddi.bu        xr2,   xr4,   0
+    xvaddi.bu        xr3,   xr5,   0
+    xvaddi.bu        xr4,   xr6,   0
+    xvaddi.bu        xr5,   xr7,   0
+    xvaddi.bu        xr6,   xr10,  0
+    xvst             xr9,   a0,    0
+    xvstx            xr11,  a0,    t7
+    alsl.d           a0,    t7,    a0,  1
+    addi.d           a4,    a4,   -2
+    bnez             a4,    .l_\lable\()v_16w_loop_lasx
+    addi.d           a3,    a3,   -16
+    addi.d           a0,    t0,    32
+    addi.d           t0,    t0,    32
+    addi.d           a1,    t5,    16
+    addi.d           t5,    t5,    16
+    addi.d           a4,    t8,    0
+    bnez             a3,    .l_\lable\()v_16w_loop0_lasx
+.l_\lable\()end_pre_8tap_lasx:
+.endm
+
+function prep_8tap_regular_8bpc_lasx
+    addi.w a7, zero, 0
+    PREP_8TAP_8BPC_LASX 0
+endfunc
+
+function prep_8tap_smooth_regular_8bpc_lasx
+    addi.w a7, zero, 1
+    PREP_8TAP_8BPC_LASX 1
+endfunc
+
+function prep_8tap_sharp_regular_8bpc_lasx
+    addi.w a7, zero, 2
+    PREP_8TAP_8BPC_LASX 2
+endfunc
+
+function prep_8tap_regular_smooth_8bpc_lasx
+    addi.w a7, zero, 4
+    PREP_8TAP_8BPC_LASX 4
+endfunc
+
+function prep_8tap_smooth_8bpc_lasx
+    addi.w a7, zero, 5
+    PREP_8TAP_8BPC_LASX 5
+endfunc
+
+function prep_8tap_sharp_smooth_8bpc_lasx
+    addi.w a7, zero, 6
+    PREP_8TAP_8BPC_LASX 6
+endfunc
+
+function prep_8tap_regular_sharp_8bpc_lasx
+    addi.w a7, zero, 8
+    PREP_8TAP_8BPC_LASX 8
+endfunc
+
+function prep_8tap_smooth_sharp_8bpc_lasx
+    addi.w a7, zero, 9
+    PREP_8TAP_8BPC_LASX 9
+endfunc
+
+function prep_8tap_sharp_8bpc_lasx
+    addi.w a7, zero, 10
+    PREP_8TAP_8BPC_LASX 10
+endfunc
+
+.macro PREP_8TAP_8BPC_LSX lable
+    li.w             t0,     4
+    la.local         t6,     dav1d_mc_subpel_filters
+    la.local         t7,     shufb1
+    vld              vr23,   t7,    0
+    slli.d           t2,     a2,    1  //src_stride*2
+    add.d            t3,     t2,    a2 //src_stride*3
+    slli.d           t4,     t2,    1
+
+    bnez             a5,     .l_\lable\()h_lsx //mx
+    bnez             a6,     .l_\lable\()v_lsx
+
+    clz.w            t1,     a3
+    li.w             t5,     24
+    sub.w            t1,     t1,    t5
+    la.local         t5,     .l_\lable\()prep_hv0_jtable_lsx
+    alsl.d           t1,     t1,    t5,   1
+    ld.h             t8,     t1,    0
+    add.d            t5,     t5,    t8
+    jirl             $r0,    t5,    0
+    .align   3
+.l_\lable\()prep_hv0_jtable_lsx:
+    .hword .l_\lable\()hv0_128w_lsx - .l_\lable\()prep_hv0_jtable_lsx
+    .hword .l_\lable\()hv0_64w_lsx  - .l_\lable\()prep_hv0_jtable_lsx
+    .hword .l_\lable\()hv0_32w_lsx  - .l_\lable\()prep_hv0_jtable_lsx
+    .hword .l_\lable\()hv0_16w_lsx  - .l_\lable\()prep_hv0_jtable_lsx
+    .hword .l_\lable\()hv0_8w_lsx   - .l_\lable\()prep_hv0_jtable_lsx
+    .hword .l_\lable\()hv0_4w_lsx   - .l_\lable\()prep_hv0_jtable_lsx
+
+.l_\lable\()hv0_4w_lsx:
+    fld.s            f0,     a1,    0
+    fldx.s           f1,     a1,    a2
+    add.d            a1,     a1,    t2
+    vilvl.w          vr0,    vr1,   vr0
+    vsllwil.hu.bu    vr0,    vr0,   4
+    vst              vr0,    a0,    0
+    addi.d           a0,     a0,    16
+    addi.d           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()hv0_4w_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+.l_\lable\()hv0_8w_lsx:
+    fld.d            f0,     a1,    0
+    fldx.d           f1,     a1,    a2
+    add.d            a1,     a1,    t2
+    vsllwil.hu.bu    vr0,    vr0,   4
+    vsllwil.hu.bu    vr1,    vr1,   4
+    vst              vr0,    a0,    0
+    vst              vr1,    a0,    16
+    addi.d           a0,     a0,    32
+    addi.d           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()hv0_8w_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+.l_\lable\()hv0_16w_lsx:
+    vld              vr0,    a1,    0
+    vldx             vr1,    a1,    a2
+    add.d            a1,     a1,    t2
+    vsllwil.hu.bu    vr2,    vr0,   4
+    vsllwil.hu.bu    vr4,    vr1,   4
+    vexth.hu.bu      vr3,    vr0
+    vexth.hu.bu      vr5,    vr1
+    vslli.h          vr3,    vr3,   4
+    vslli.h          vr5,    vr5,   4
+    vst              vr2,    a0,    0
+    vst              vr3,    a0,    16
+    vst              vr4,    a0,    32
+    vst              vr5,    a0,    48
+    addi.d           a0,     a0,    64
+    addi.d           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()hv0_16w_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+.l_\lable\()hv0_32w_lsx:
+.l_\lable\()hv0_64w_lsx:
+.l_\lable\()hv0_128w_lsx:
+    addi.d           t0,     a1,    0
+    addi.d           t5,     a4,    0
+    srli.w           t7,     a3,    4
+    slli.w           t7,     t7,    5
+    addi.d           t8,     a0,    0
+.l_\lable\()hv0_16_loop_lsx:
+    vld              vr0,    a1,    0
+    vldx             vr1,    a1,    a2
+    add.d            a1,     a1,    t2
+    vsllwil.hu.bu    vr2,    vr0,   4
+    vsllwil.hu.bu    vr3,    vr1,   4
+    vexth.hu.bu      vr0,    vr0
+    vexth.hu.bu      vr1,    vr1
+    vslli.h          vr0,    vr0,   4
+    vslli.h          vr1,    vr1,   4
+    vst              vr2,    a0,    0
+    vst              vr0,    a0,    16
+    add.d            a0,     a0,    t7
+    vst              vr3,    a0,    0
+    vst              vr1,    a0,    16
+    add.d            a0,     a0,    t7
+    addi.d           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()hv0_16_loop_lsx
+    addi.d           a1,     t0,    16
+    addi.d           t0,     t0,    16
+    addi.d           a0,     t8,    32
+    addi.d           t8,     t8,    32
+    addi.d           a4,     t5,    0
+    addi.d           a3,     a3,    -16
+    bnez             a3,     .l_\lable\()hv0_16_loop_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+.l_\lable\()h_lsx:
+    bnez             a6,     .l_\lable\()hv_lsx //if(fh) && if (fv)
+
+    andi             t1,     a7,    3
+    blt              t0,     a3,    .l_\lable\()h_idx_fh_lsx
+    andi             t1,     a7,    1
+    addi.w           t1,     t1,    3
+.l_\lable\()h_idx_fh_lsx:
+    addi.w           t5,     zero,  120
+    mul.w            t1,     t1,    t5
+    addi.w           t5,     a5,    -1
+    slli.w           t5,     t5,    3
+    add.w            t1,     t1,    t5
+    add.d            t1,     t6,    t1 //fh's offset
+    vldrepl.d        vr23,   t1,    0
+
+    addi.d           a1,     a1,    -3
+    clz.w            t1,     a3
+    li.w             t5,     24
+    sub.w            t1,     t1,    t5
+    la.local         t5,     .l_\lable\()prep_h_jtable_lsx
+    alsl.d           t1,     t1,    t5,   1
+    ld.h             t8,     t1,    0
+    add.d            t5,     t5,    t8
+    jirl             $r0,    t5,    0
+
+    .align   3
+.l_\lable\()prep_h_jtable_lsx:
+    .hword .l_\lable\()h_128w_lsx - .l_\lable\()prep_h_jtable_lsx
+    .hword .l_\lable\()h_64w_lsx  - .l_\lable\()prep_h_jtable_lsx
+    .hword .l_\lable\()h_32w_lsx  - .l_\lable\()prep_h_jtable_lsx
+    .hword .l_\lable\()h_16w_lsx  - .l_\lable\()prep_h_jtable_lsx
+    .hword .l_\lable\()h_8w_lsx   - .l_\lable\()prep_h_jtable_lsx
+    .hword .l_\lable\()h_4w_lsx   - .l_\lable\()prep_h_jtable_lsx
+
+.l_\lable\()h_4w_lsx:
+    addi.d           a1,     a1,    2
+    la.local         t7,     subpel_h_shuf1
+    vld              vr7,    t7,    0
+    vbsrl.v          vr23,   vr23,  2
+    vreplvei.w       vr23,   vr23,  0
+.l_\lable\()h_4w_loop_lsx:
+    vld              vr0,    a1,    0
+    vldx             vr1,    a1,    a2
+    add.d            a1,     a1,    t2
+    vshuf.b          vr0,    vr0,   vr0,   vr7
+    vshuf.b          vr1,    vr1,   vr1,   vr7
+    vmulwev.h.bu.b   vr2,    vr0,   vr23
+    vmulwev.h.bu.b   vr3,    vr1,   vr23
+    vmaddwod.h.bu.b  vr2,    vr0,   vr23
+    vmaddwod.h.bu.b  vr3,    vr1,   vr23
+    vhaddw.w.h       vr0,    vr2,   vr2
+    vhaddw.w.h       vr1,    vr3,   vr3
+    vssrarni.h.w     vr1,    vr0,   2
+    vst              vr1,    a0,    0
+    addi.d           a0,     a0,    16
+    addi.w           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()h_4w_loop_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+
+.l_\lable\()h_8w_lsx:
+    vreplvei.w       vr22,   vr23,  0 //fh
+    vreplvei.w       vr23,   vr23,  1
+    la.local         t7,     subpel_h_shuf1
+    vld              vr6,    t7,    0
+    vaddi.bu         vr7,    vr6,   4
+    vaddi.bu         vr8,    vr6,   8
+.l_\lable\()h_8w_loop_lsx:
+    vld              vr0,    a1,    0
+    vldx             vr1,    a1,    a2
+    add.d            a1,     a1,    t2
+    PREP_H_8W        vr0
+    PREP_H_8W        vr1
+    vst              vr0,    a0,    0
+    vst              vr1,    a0,    16
+    addi.d           a0,     a0,    32
+    addi.d           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()h_8w_loop_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+
+.l_\lable\()h_16w_lsx:
+.l_\lable\()h_32w_lsx:
+.l_\lable\()h_64w_lsx:
+.l_\lable\()h_128w_lsx:
+    vreplvei.w       vr22,   vr23,  0 //fh
+    vreplvei.w       vr23,   vr23,  1
+    la.local         t7,     subpel_h_shuf1
+    vld              vr6,    t7,    0
+    vaddi.bu         vr7,    vr6,   4
+    vaddi.bu         vr8,    vr6,   8
+    srli.w           t7,     a3,    4
+    slli.w           t6,     t7,    5
+.l_\lable\()h_16w_loop0_lsx:
+    addi.d           t0,     a1,    0 //src
+    addi.d           t5,     a4,    0 //h
+    addi.d           t8,     a0,    0 //dst
+.l_\lable\()h_16w_loop_lsx:
+    vld              vr0,    a1,    0
+    vld              vr1,    a1,    8
+    add.d            a1,     a1,    a2
+    PREP_H_8W        vr0
+    PREP_H_8W        vr1
+    vst              vr0,    a0,    0
+    vst              vr1,    a0,    16
+    add.d            a0,     a0,    t6
+    addi.d           t5,     t5,    -1
+    bnez             t5,     .l_\lable\()h_16w_loop_lsx
+    addi.d           a1,     t0,    16
+    addi.d           a0,     t8,    32
+    addi.w           t7,     t7,    -1
+    bnez             t7,     .l_\lable\()h_16w_loop0_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+
+.l_\lable\()hv_lsx:
+    andi             t1,     a7,    3
+    blt              t0,     a3,    .l_\lable\()hv_idx_fh_lsx
+    andi             t1,     a7,    1
+    addi.w           t1,     t1,    3
+.l_\lable\()hv_idx_fh_lsx:
+    addi.w           t5,     zero,  120
+    mul.w            t1,     t1,    t5
+    addi.w           t5,     a5,    -1
+    slli.w           t5,     t5,    3
+    add.w            t1,     t1,    t5
+    add.d            t1,     t6,    t1 //fh's offset
+    vldrepl.d        vr8,    t1,    0
+    srli.w           a7,     a7,    2
+    blt              t0,     a4,    .l_\lable\()hv_idx_fv_lsx
+    andi             a7,     a7,    1
+    addi.w           a7,     a7,    3
+.l_\lable\()hv_idx_fv_lsx:
+    addi.w           t5,     zero,  120
+    mul.w            a7,     a7,    t5
+    addi.w           t5,     a6,    -1
+    slli.w           t5,     t5,    3
+    add.w            a7,     a7,    t5
+    add.d            a7,     t6,    a7 //fv's offset
+    vldrepl.d        vr9,    a7,    0
+    vsllwil.h.b      vr9,    vr9,   0
+
+    sub.d            a1,     a1,    t3
+    addi.d           a1,     a1,    -3
+    beq              a3,     t0,    .l_\lable\()hv_4w_lsx
+    b                .l_\lable\()hv_8w_lsx
+.l_\lable\()hv_4w_lsx:
+    addi.d           a1,     a1,    2 //ignore leading 0s
+    vld              vr0,    a1,    0
+    vldx             vr1,    a1,    a2
+    vldx             vr2,    a1,    t2
+    add.d            a1,     a1,    t3
+    vld              vr3,    a1,    0
+    vldx             vr4,    a1,    a2
+    vldx             vr5,    a1,    t2
+    vldx             vr6,    a1,    t3
+    add.d            a1,     a1,    t4
+
+    la.local         t1,     subpel_h_shuf1
+    vld              vr7,    t1,    0
+    vbsrl.v          vr8,    vr8,   2
+    vreplvei.w       vr8,    vr8,   0
+
+    //fv
+    vreplvei.w       vr17,   vr9,   0
+    vreplvei.w       vr18,   vr9,   1
+    vreplvei.w       vr19,   vr9,   2
+    vreplvei.w       vr20,   vr9,   3
+
+    //DAV1D_FILTER_8TAP_RND
+    vshuf.b          vr0,    vr0,   vr0,  vr7
+    vshuf.b          vr1,    vr1,   vr1,  vr7
+    vshuf.b          vr2,    vr2,   vr2,  vr7
+    vshuf.b          vr3,    vr3,   vr3,  vr7
+    vshuf.b          vr4,    vr4,   vr4,  vr7
+    vshuf.b          vr5,    vr5,   vr5,  vr7
+    vshuf.b          vr6,    vr6,   vr6,  vr7
+
+    vmulwev.h.bu.b   vr10,   vr0,   vr8
+    vmulwev.h.bu.b   vr11,   vr1,   vr8
+    vmulwev.h.bu.b   vr12,   vr2,   vr8
+    vmulwev.h.bu.b   vr13,   vr3,   vr8
+    vmulwev.h.bu.b   vr14,   vr4,   vr8
+    vmulwev.h.bu.b   vr15,   vr5,   vr8
+    vmulwev.h.bu.b   vr16,   vr6,   vr8
+    vmaddwod.h.bu.b  vr10,   vr0,   vr8
+    vmaddwod.h.bu.b  vr11,   vr1,   vr8
+    vmaddwod.h.bu.b  vr12,   vr2,   vr8
+    vmaddwod.h.bu.b  vr13,   vr3,   vr8
+    vmaddwod.h.bu.b  vr14,   vr4,   vr8
+    vmaddwod.h.bu.b  vr15,   vr5,   vr8
+    vmaddwod.h.bu.b  vr16,   vr6,   vr8
+
+    vhaddw.w.h       vr10,   vr10,  vr10
+    vhaddw.w.h       vr11,   vr11,  vr11
+    vhaddw.w.h       vr12,   vr12,  vr12
+    vhaddw.w.h       vr13,   vr13,  vr13
+    vhaddw.w.h       vr14,   vr14,  vr14
+    vhaddw.w.h       vr15,   vr15,  vr15
+    vhaddw.w.h       vr16,   vr16,  vr16
+
+    vssrarni.h.w     vr10,   vr10,  2 //h0
+    vssrarni.h.w     vr11,   vr11,  2 //h1
+    vssrarni.h.w     vr12,   vr12,  2 //h2
+    vssrarni.h.w     vr13,   vr13,  2 //h3
+    vssrarni.h.w     vr14,   vr14,  2 //h4
+    vssrarni.h.w     vr15,   vr15,  2 //h5
+    vssrarni.h.w     vr16,   vr16,  2 //h6
+
+    //h0
+    vilvl.h          vr0,    vr11,  vr10 //01
+    vilvl.h          vr1,    vr13,  vr12 //23
+    vilvl.h          vr2,    vr15,  vr14 //45
+    //h1
+    vilvl.h          vr4,    vr12,  vr11 //12
+    vilvl.h          vr5,    vr14,  vr13 //34
+    vilvl.h          vr6,    vr16,  vr15 //56
+
+.l_\lable\()hv_w4_loop_lsx:
+    vld              vr9,    a1,    0
+    vldx             vr10,   a1,    a2
+    add.d            a1,     a1,    t2
+
+    //DAV1D_FILTER_8TAP_CLIP
+    vshuf.b          vr9,    vr9,   vr9,  vr7
+    vshuf.b          vr10,   vr10,  vr10, vr7
+    vmulwev.h.bu.b   vr11,   vr9,   vr8
+    vmulwev.h.bu.b   vr12,   vr10,  vr8
+    vmaddwod.h.bu.b  vr11,   vr9,   vr8
+    vmaddwod.h.bu.b  vr12,   vr10,  vr8
+    vhaddw.w.h       vr11,   vr11,  vr11
+    vhaddw.w.h       vr12,   vr12,  vr12
+    vssrarni.h.w     vr11,   vr11,  2 //7h
+    vssrarni.h.w     vr12,   vr12,  2 //h8
+    vilvl.h          vr3,    vr11,  vr16 //67
+    vilvl.h          vr13,   vr12,  vr11 //78
+
+    vmulwev.w.h      vr9,    vr0,   vr17
+    vmulwev.w.h      vr10,   vr1,   vr18
+    vmulwev.w.h      vr14,   vr2,   vr19
+    vmulwev.w.h      vr15,   vr3,   vr20
+    vmaddwod.w.h     vr9,    vr0,   vr17
+    vmaddwod.w.h     vr10,   vr1,   vr18
+    vmaddwod.w.h     vr14,   vr2,   vr19
+    vmaddwod.w.h     vr15,   vr3,   vr20
+    vadd.w           vr16,   vr9,   vr10
+    vadd.w           vr16,   vr16,  vr14
+    vadd.w           vr16,   vr16,  vr15
+
+    vmulwev.w.h      vr9,    vr4,   vr17
+    vmulwev.w.h      vr10,   vr5,   vr18
+    vmulwev.w.h      vr14,   vr6,   vr19
+    vmulwev.w.h      vr15,   vr13,  vr20
+    vmaddwod.w.h     vr9,    vr4,   vr17
+    vmaddwod.w.h     vr10,   vr5,   vr18
+    vmaddwod.w.h     vr14,   vr6,   vr19
+    vmaddwod.w.h     vr15,   vr13,  vr20
+    vadd.w           vr21,   vr9,   vr10
+    vadd.w           vr21,   vr21,  vr14
+    vadd.w           vr21,   vr21,  vr15
+
+    vssrarni.h.w     vr21,   vr16,  6
+    //cache
+    vaddi.hu         vr0,    vr1,   0
+    vaddi.hu         vr1,    vr2,   0
+    vaddi.hu         vr2,    vr3,   0
+    vaddi.hu         vr4,    vr5,   0
+    vaddi.hu         vr5,    vr6,   0
+    vaddi.hu         vr6,    vr13,  0
+    vaddi.hu         vr16,   vr12,  0
+
+    vst              vr21,   a0,    0
+    addi.d           a0,     a0,    16
+    addi.d           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()hv_w4_loop_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+
+.l_\lable\()hv_8w_lsx:
+.l_\lable\()hv_16w_lsx:
+.l_\lable\()hv_32w_lsx:
+.l_\lable\()hv_64w_lsx:
+.l_\lable\()hv_128w_lsx:
+    addi.d          sp,      sp,    -8*8
+    fst.d           f24,     sp,    0
+    fst.d           f25,     sp,    8
+    fst.d           f26,     sp,    16
+    fst.d           f27,     sp,    24
+    fst.d           f28,     sp,    32
+    fst.d           f29,     sp,    40
+    fst.d           f30,     sp,    48
+    fst.d           f31,     sp,    56
+    addi.d          t0,      a1,    0 //src
+    addi.d          t5,      a4,    0 //h
+    addi.d          t8,      a0,    0 //dst
+    slli.w          t6,      a3,    1
+    la.local        t1,      subpel_h_shuf1
+    vld             vr7,     t1,    0
+    vaddi.bu        vr11,    vr7,   4
+    vaddi.bu        vr12,    vr7,   8
+    vreplvei.w      vr10,    vr8,   1
+    vreplvei.w      vr8,     vr8,   0
+    vreplvei.w      vr20,    vr9,   1
+    vreplvei.w      vr21,    vr9,   2
+    vreplvei.w      vr22,    vr9,   3
+    vreplvei.w      vr9,     vr9,   0
+.l_\lable\()prep_hv_8w_loop0_lsx:
+    vld             vr0,     a1,    0
+    vldx            vr1,     a1,    a2
+    vldx            vr2,     a1,    t2
+    add.d           a1,      a1,    t3
+    vld             vr3,     a1,    0
+    vldx            vr4,     a1,    a2
+    vldx            vr5,     a1,    t2
+    vldx            vr6,     a1,    t3
+    add.d           a1,      a1,    t4
+
+    FILTER_8TAP_8W  vr0 //h0
+    FILTER_8TAP_8W  vr1 //h1
+    FILTER_8TAP_8W  vr2 //h2
+    FILTER_8TAP_8W  vr3 //h3
+    FILTER_8TAP_8W  vr4 //h4
+    FILTER_8TAP_8W  vr5 //h5
+    FILTER_8TAP_8W  vr6 //h6
+
+    //h0' low part
+    vilvl.h         vr23,    vr1,   vr0 //01
+    vilvl.h         vr24,    vr3,   vr2 //23
+    vilvl.h         vr25,    vr5,   vr4 //45
+    //h0' high part
+    vilvh.h         vr26,    vr1,   vr0 //01
+    vilvh.h         vr27,    vr3,   vr2 //23
+    vilvh.h         vr28,    vr5,   vr4 //45
+
+    //h1' low part
+    vilvl.h         vr29,    vr2,   vr1 //12
+    vilvl.h         vr30,    vr4,   vr3 //34
+    vilvl.h         vr31,    vr6,   vr5 //56
+    //h1' high part
+    vilvh.h         vr0,     vr2,   vr1 //12
+    vilvh.h         vr1,     vr4,   vr3 //34
+    vilvh.h         vr2,     vr6,   vr5 //56
+
+.l_\lable\()prep_hv_8w_loop_lsx:
+    vld             vr3,     a1,    0
+    vldx            vr4,     a1,    a2
+    add.d           a1,      a1,    t2
+
+    FILTER_8TAP_8W  vr3 //h7
+    FILTER_8TAP_8W  vr4 //h8
+
+    //h0' low part
+    vilvl.h         vr16,    vr3,   vr6 //67 ~low
+    vmulwev.w.h     vr13,    vr23,  vr9
+    vmulwev.w.h     vr14,    vr24,  vr20
+    vmulwev.w.h     vr15,    vr25,  vr21
+    vmulwev.w.h     vr17,    vr16,  vr22
+    vmaddwod.w.h    vr13,    vr23,  vr9
+    vmaddwod.w.h    vr14,    vr24,  vr20
+    vmaddwod.w.h    vr15,    vr25,  vr21
+    vmaddwod.w.h    vr17,    vr16,  vr22
+    vadd.w          vr13,    vr13,  vr14
+    vadd.w          vr13,    vr13,  vr15
+    vadd.w          vr13,    vr13,  vr17
+    //cache
+    vaddi.hu        vr23,    vr24,  0
+    vaddi.hu        vr24,    vr25,  0
+    vaddi.hu        vr25,    vr16,  0
+
+    //h0' high part
+    vilvh.h         vr17,    vr3,   vr6 //67 ~high
+    vmulwev.w.h     vr14,    vr26,  vr9
+    vmulwev.w.h     vr15,    vr27,  vr20
+    vmulwev.w.h     vr16,    vr28,  vr21
+    vmulwev.w.h     vr18,    vr17,  vr22
+    vmaddwod.w.h    vr14,    vr26,  vr9
+    vmaddwod.w.h    vr15,    vr27,  vr20
+    vmaddwod.w.h    vr16,    vr28,  vr21
+    vmaddwod.w.h    vr18,    vr17,  vr22
+    vadd.w          vr14,    vr14,  vr15
+    vadd.w          vr14,    vr14,  vr16
+    vadd.w          vr14,    vr14,  vr18
+    vssrarni.h.w    vr14,    vr13,  6
+    vst             vr14,    a0,    0
+    add.d           a0,      a0,    t6
+    //cache
+    vaddi.hu        vr26,    vr27,  0
+    vaddi.hu        vr27,    vr28,  0
+    vaddi.hu        vr28,    vr17,  0
+    vaddi.hu        vr6,     vr4,   0
+
+    vilvl.h         vr5,     vr4,   vr3 //78 ~low
+    vilvh.h         vr4,     vr4,   vr3 //78 ~high
+
+    //h1' low part
+    vmulwev.w.h     vr13,    vr29,  vr9
+    vmulwev.w.h     vr14,    vr30,  vr20
+    vmulwev.w.h     vr15,    vr31,  vr21
+    vmulwev.w.h     vr16,    vr5,   vr22
+    vmaddwod.w.h    vr13,    vr29,  vr9
+    vmaddwod.w.h    vr14,    vr30,  vr20
+    vmaddwod.w.h    vr15,    vr31,  vr21
+    vmaddwod.w.h    vr16,    vr5,   vr22
+    vadd.w          vr13,    vr13,  vr14
+    vadd.w          vr13,    vr13,  vr15
+    vadd.w          vr13,    vr13,  vr16
+    //cache
+    vaddi.hu        vr29,    vr30,  0
+    vaddi.hu        vr30,    vr31,  0
+    vaddi.hu        vr31,    vr5,   0
+
+    //h1' high part
+    vmulwev.w.h     vr14,    vr0,   vr9
+    vmulwev.w.h     vr15,    vr1,   vr20
+    vmulwev.w.h     vr16,    vr2,   vr21
+    vmulwev.w.h     vr17,    vr4,   vr22
+    vmaddwod.w.h    vr14,    vr0,   vr9
+    vmaddwod.w.h    vr15,    vr1,   vr20
+    vmaddwod.w.h    vr16,    vr2,   vr21
+    vmaddwod.w.h    vr17,    vr4,   vr22
+    vadd.w          vr14,    vr14,  vr15
+    vadd.w          vr14,    vr14,  vr16
+    vadd.w          vr14,    vr14,  vr17
+    vssrarni.h.w    vr14,    vr13,  6
+    vst             vr14,    a0,    0
+    add.d           a0,      a0,    t6
+    //cache
+    vaddi.hu        vr0,     vr1,   0
+    vaddi.hu        vr1,     vr2,   0
+    vaddi.hu        vr2,     vr4,   0
+    addi.w          a4,      a4,    -2
+    bnez            a4,      .l_\lable\()prep_hv_8w_loop_lsx
+    addi.d          a1,      t0,    8
+    addi.d          t0,      t0,    8
+    addi.d          a0,      t8,    16
+    addi.d          t8,      t8,    16
+    addi.d          a4,      t5,    0
+    addi.w          a3,      a3,    -8
+    bnez            a3,      .l_\lable\()prep_hv_8w_loop0_lsx
+    fld.d           f24,     sp,    0
+    fld.d           f25,     sp,    8
+    fld.d           f26,     sp,    16
+    fld.d           f27,     sp,    24
+    fld.d           f28,     sp,    32
+    fld.d           f29,     sp,    40
+    fld.d           f30,     sp,    48
+    fld.d           f31,     sp,    56
+    addi.d          sp,      sp,    8*8
+    b                .l_\lable\()end_pre_8tap_lsx
+
+.l_\lable\()v_lsx:
+    srli.w           a7,    a7,     2
+    blt              t0,    a4,     .l_\lable\()v_idx_fv_lsx
+    andi             a7,    a7,     1
+    addi.w           a7,    a7,     3
+.l_\lable\()v_idx_fv_lsx:
+    addi.w           t5,     zero,  120
+    mul.w            a7,     a7,    t5
+    addi.w           t5,     a6,    -1
+    slli.w           t5,     t5,    3
+    add.w            a7,     a7,    t5
+    add.d            a7,     t6,    a7 //fv's offset
+    vldrepl.d        vr8,    a7,    0
+
+    vilvl.h          vr8,    vr8,   vr8
+    vreplvei.w       vr9,    vr8,   1
+    vreplvei.w       vr10,   vr8,   2
+    vreplvei.w       vr11,   vr8,   3
+    vreplvei.w       vr8,    vr8,   0
+
+    sub.d            a1,     a1,    t3
+    beq              a3,     t0,    .l_\lable\()v_4w_lsx
+    blt              t0,     a3,    .l_\lable\()v_8w_lsx
+.l_\lable\()v_4w_lsx:
+    fld.s            f0,     a1,    0
+    fldx.s           f1,     a1,    a2
+    fldx.s           f2,     a1,    t2
+    add.d            a1,     a1,    t3
+    fld.s            f3,     a1,    0
+    fldx.s           f4,     a1,    a2
+    fldx.s           f5,     a1,    t2
+    fldx.s           f6,     a1,    t3
+    add.d            a1,     a1,    t4
+
+    vilvl.w          vr0,    vr1,   vr0
+    vilvl.w          vr1,    vr2,   vr1
+    vilvl.b          vr0,    vr1,   vr0 //0 1 1 2
+    vilvl.w          vr1,    vr3,   vr2
+    vilvl.w          vr2,    vr4,   vr3
+    vilvl.b          vr1,    vr2,   vr1 //2 3 3 4
+    vilvl.w          vr2,    vr5,   vr4
+    vilvl.w          vr3,    vr6,   vr5
+    vilvl.b          vr2,    vr3,   vr2 //4 5 5 6
+.l_\lable\()v_4w_loop_lsx:
+    fld.s            f7,     a1,     0
+
+    vilvl.w          vr3,    vr7,   vr6
+    fldx.s           f6,     a1,    a2
+    add.d            a1,     a1,    t2
+    vilvl.w          vr4,    vr6,   vr7
+    vilvl.b          vr3,    vr4,   vr3 //6 7 7 8
+
+    vmulwev.h.bu.b   vr12,   vr0,   vr8
+    vmulwev.h.bu.b   vr13,   vr1,   vr9
+    vmulwev.h.bu.b   vr14,   vr2,   vr10
+    vmulwev.h.bu.b   vr15,   vr3,   vr11
+    vmaddwod.h.bu.b  vr12,   vr0,   vr8
+    vmaddwod.h.bu.b  vr13,   vr1,   vr9
+    vmaddwod.h.bu.b  vr14,   vr2,   vr10
+    vmaddwod.h.bu.b  vr15,   vr3,   vr11
+    vaddi.hu         vr0,    vr1,   0
+    vaddi.hu         vr1,    vr2,   0
+    vaddi.hu         vr2,    vr3,   0
+    vadd.h           vr12,   vr12,  vr13
+    vadd.h           vr12,   vr12,  vr14
+    vadd.h           vr12,   vr12,  vr15
+
+    vsrari.h         vr12,   vr12,  2
+    vst              vr12,   a0,    0
+    addi.d           a0,     a0,    16
+    addi.w           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()v_4w_loop_lsx
+    b                .l_\lable\()end_pre_8tap_lsx
+
+.l_\lable\()v_8w_lsx:
+    addi.d           t0,     a1,    0
+    addi.d           t5,     a4,    0
+    addi.d           t8,     a0,    0
+    slli.w           t6,     a3,    1
+.l_\lable\()v_8w_loop0_lsx:
+    fld.d            f0,     a1,    0
+    fldx.d           f1,     a1,    a2
+    fldx.d           f2,     a1,    t2
+    add.d            a1,     a1,    t3
+    fld.d            f3,     a1,    0
+    fldx.d           f4,     a1,    a2
+    fldx.d           f5,     a1,    t2
+    fldx.d           f6,     a1,    t3
+    add.d            a1,     a1,    t4
+
+    vilvl.b          vr0,    vr1,   vr0 //0 1
+    vilvl.b          vr1,    vr2,   vr1 //1 2
+    vilvl.b          vr2,    vr3,   vr2 //2 3
+    vilvl.b          vr3,    vr4,   vr3 //3 4
+    vilvl.b          vr4,    vr5,   vr4 //4 5
+    vilvl.b          vr5,    vr6,   vr5 //5 6
+.l_\lable\()v_8w_loop_lsx:
+    fld.d            f7,     a1,    0
+    vilvl.b          vr12,   vr7,   vr6 //6 7
+    fldx.d           f6,     a1,    a2
+    add.d            a1,     a1,    t2
+    vilvl.b          vr13,   vr6,   vr7 //7 8
+
+    vmulwev.h.bu.b   vr14,   vr0,   vr8
+    vmulwev.h.bu.b   vr15,   vr1,   vr8
+    vmulwev.h.bu.b   vr16,   vr2,   vr9
+    vmulwev.h.bu.b   vr17,   vr3,   vr9
+    vmulwev.h.bu.b   vr18,   vr4,   vr10
+    vmulwev.h.bu.b   vr19,   vr5,   vr10
+    vmulwev.h.bu.b   vr20,   vr12,  vr11
+    vmulwev.h.bu.b   vr21,   vr13,  vr11
+    vmaddwod.h.bu.b  vr14,   vr0,   vr8
+    vmaddwod.h.bu.b  vr15,   vr1,   vr8
+    vmaddwod.h.bu.b  vr16,   vr2,   vr9
+    vmaddwod.h.bu.b  vr17,   vr3,   vr9
+    vmaddwod.h.bu.b  vr18,   vr4,   vr10
+    vmaddwod.h.bu.b  vr19,   vr5,   vr10
+    vmaddwod.h.bu.b  vr20,   vr12,  vr11
+    vmaddwod.h.bu.b  vr21,   vr13,  vr11
+
+    vaddi.hu         vr0,    vr2,   0
+    vaddi.hu         vr1,    vr3,   0
+    vaddi.hu         vr2,    vr4,   0
+    vaddi.hu         vr3,    vr5,   0
+    vaddi.hu         vr4,    vr12,  0
+    vaddi.hu         vr5,    vr13,  0
+    vadd.h           vr14,   vr14,  vr16
+    vadd.h           vr14,   vr14,  vr18
+    vadd.h           vr14,   vr14,  vr20
+    vadd.h           vr15,   vr15,  vr17
+    vadd.h           vr15,   vr15,  vr19
+    vadd.h           vr15,   vr15,  vr21
+
+    vsrari.h         vr14,   vr14,  2
+    vsrari.h         vr15,   vr15,  2
+    vst              vr14,   a0,    0
+    add.d            a0,     a0,    t6
+    vst              vr15,   a0,    0
+    add.d            a0,     a0,    t6
+    addi.w           a4,     a4,    -2
+    bnez             a4,     .l_\lable\()v_8w_loop_lsx
+    addi.d           a1,     t0,    8
+    addi.d           t0,     t0,    8
+    addi.d           a0,     t8,    16
+    addi.d           t8,     t8,    16
+    addi.d           a4,     t5,    0
+    addi.d           a3,     a3,    -8
+    bnez             a3,     .l_\lable\()v_8w_loop0_lsx
+.l_\lable\()end_pre_8tap_lsx:
+.endm
+
+function prep_8tap_regular_8bpc_lsx
+    addi.w a7, zero, 0
+    PREP_8TAP_8BPC_LSX 0
+endfunc
+
+function prep_8tap_smooth_regular_8bpc_lsx
+    addi.w a7, zero, 1
+    PREP_8TAP_8BPC_LSX 1
+endfunc
+
+function prep_8tap_sharp_regular_8bpc_lsx
+    addi.w a7, zero, 2
+    PREP_8TAP_8BPC_LSX 2
+endfunc
+
+function prep_8tap_regular_smooth_8bpc_lsx
+    addi.w a7, zero, 4
+    PREP_8TAP_8BPC_LSX 4
+endfunc
+
+function prep_8tap_smooth_8bpc_lsx
+    addi.w a7, zero, 5
+    PREP_8TAP_8BPC_LSX 5
+endfunc
+
+function prep_8tap_sharp_smooth_8bpc_lsx
+    addi.w a7, zero, 6
+    PREP_8TAP_8BPC_LSX 6
+endfunc
+
+function prep_8tap_regular_sharp_8bpc_lsx
+    addi.w a7, zero, 8
+    PREP_8TAP_8BPC_LSX 8
+endfunc
+
+function prep_8tap_smooth_sharp_8bpc_lsx
+    addi.w a7, zero, 9
+    PREP_8TAP_8BPC_LSX 9
+endfunc
+
+function prep_8tap_sharp_8bpc_lsx
+    addi.w a7, zero, 10
+    PREP_8TAP_8BPC_LSX 10
+endfunc
+
+/*
+ * static void blend_lsx(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                         const int w, int h, const uint8_t *mask)
+ */
+function blend_8bpc_lsx
+    addi.d        t8,     zero,    64
+    vreplgr2vr.b  vr23,   t8
+
+    clz.w         t0,     a3
+    li.w          t1,     26
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .BLEND_LSX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0  // The jump addresses are relative to JRTABLE
+    add.d         t1,     t1,      t2 // Get absolute address
+    jirl          $r0,    t1,      0
+
+    .align   3
+.BLEND_LSX_JRTABLE:
+    .hword .BLEND_W32_LSX  - .BLEND_LSX_JRTABLE
+    .hword .BLEND_W16_LSX  - .BLEND_LSX_JRTABLE
+    .hword .BLEND_W8_LSX   - .BLEND_LSX_JRTABLE
+    .hword .BLEND_W4_LSX   - .BLEND_LSX_JRTABLE
+
+.BLEND_W4_LSX:
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+    vld             vr2,    a5,      0
+
+    vsllwil.hu.bu   vr1,    vr1,     0
+    vsllwil.hu.bu   vr4,    vr2,     0
+    vmul.h          vr1,    vr1,     vr4  //b*m
+    vsub.b          vr3,    vr23,    vr2
+    vsllwil.hu.bu   vr0,    vr0,     0
+    vsllwil.hu.bu   vr3,    vr3,     0
+    vmadd.h         vr1,    vr0,     vr3
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.w        vr1,    a0,      0,   0
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      4
+    addi.d          a5,     a5,      4
+
+    blt             zero,   a4,     .BLEND_W4_LSX
+    b              .BLEND_END_LSX
+.BLEND_W8_LSX:
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+    vld             vr2,    a5,      0
+
+    vsllwil.hu.bu   vr1,    vr1,     0
+    vsllwil.hu.bu   vr4,    vr2,     0
+    vmul.h          vr1,    vr1,     vr4  //b*m
+    vsub.b          vr3,    vr23,    vr2
+    vsllwil.hu.bu   vr0,    vr0,     0
+    vsllwil.hu.bu   vr3,    vr3,     0
+    vmadd.h         vr1,    vr0,     vr3
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.d        vr1,    a0,      0,   0
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      8
+    addi.d          a5,     a5,      8
+
+    blt             zero,   a4,     .BLEND_W8_LSX
+    b               .BLEND_END_LSX
+.BLEND_W16_LSX:
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+    vld             vr2,    a5,      0
+
+    vexth.hu.bu     vr5,    vr1
+    vsllwil.hu.bu   vr1,    vr1,     0
+    vexth.hu.bu     vr6,    vr2
+    vsllwil.hu.bu   vr4,    vr2,     0
+    vmul.h          vr1,    vr1,     vr4  //b*m
+    vmul.h          vr5,    vr5,     vr6  //b*m
+    vsub.b          vr3,    vr23,    vr2
+    vexth.hu.bu     vr7,    vr0
+    vexth.hu.bu     vr8,    vr3
+    vmadd.h         vr5,    vr7,     vr8
+    vsllwil.hu.bu   vr0,    vr0,     0
+    vsllwil.hu.bu   vr3,    vr3,     0
+    vmadd.h         vr1,    vr0,     vr3
+    vssrarni.bu.h   vr5,    vr1,     6
+
+    vst             vr5,    a0,      0
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      16
+    addi.d          a5,     a5,      16
+
+    blt             zero,   a4,     .BLEND_W16_LSX
+    b               .BLEND_END_LSX
+.BLEND_W32_LSX:
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+    vld             vr2,    a5,      0
+
+    vexth.hu.bu     vr5,    vr1
+    vsllwil.hu.bu   vr1,    vr1,     0
+    vexth.hu.bu     vr6,    vr2
+    vsllwil.hu.bu   vr4,    vr2,     0
+    vmul.h          vr1,    vr1,     vr4  //b*m
+    vmul.h          vr5,    vr5,     vr6  //b*m
+    vsub.b          vr3,    vr23,    vr2
+    vexth.hu.bu     vr7,    vr0
+    vexth.hu.bu     vr8,    vr3
+    vmadd.h         vr5,    vr7,     vr8
+    vsllwil.hu.bu   vr0,    vr0,     0
+    vsllwil.hu.bu   vr3,    vr3,     0
+    vmadd.h         vr1,    vr0,     vr3
+    vssrarni.bu.h   vr5,    vr1,     6
+
+    vst             vr5,    a0,      0
+
+    /* sencond */
+    vld             vr0,    a0,      16
+    vld             vr1,    a2,      16
+    vld             vr2,    a5,      16
+
+    vexth.hu.bu     vr5,    vr1
+    vsllwil.hu.bu   vr1,    vr1,     0
+    vexth.hu.bu     vr6,    vr2
+    vsllwil.hu.bu   vr4,    vr2,     0
+    vmul.h          vr1,    vr1,     vr4  //b*m
+    vmul.h          vr5,    vr5,     vr6  //b*m
+    vsub.b          vr3,    vr23,    vr2
+    vexth.hu.bu     vr7,    vr0
+    vexth.hu.bu     vr8,    vr3
+    vmadd.h         vr5,    vr7,     vr8
+    vsllwil.hu.bu   vr0,    vr0,     0
+    vsllwil.hu.bu   vr3,    vr3,     0
+    vmadd.h         vr1,    vr0,     vr3
+    vssrarni.bu.h   vr5,    vr1,     6
+
+    vst             vr5,    a0,      16
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      32
+    addi.d          a5,     a5,      32
+
+    blt             zero,   a4,     .BLEND_W32_LSX
+.BLEND_END_LSX:
+
+endfunc
+
+const obmc_masks_la
+/* Unused */
+.byte 0,  0,  0,  0
+/* 2 */
+.byte 45, 19, 64, 0
+/* 4 */
+.byte 39, 25, 50, 14, 59,  5, 64,  0
+/* 8 */
+.byte 36, 28, 42, 22, 48, 16, 53, 11, 57,  7, 61,  3, 64,  0, 64,  0
+/* 16 */
+.byte 34, 30, 37, 27, 40, 24, 43, 21, 46, 18, 49, 15, 52, 12, 54, 10
+.byte 56,  8, 58,  6, 60,  4, 61,  3, 64,  0, 64,  0, 64,  0, 64,  0
+/* 32 */
+.byte 33, 31, 35, 29, 36, 28, 38, 26, 40, 24, 41, 23, 43, 21, 44, 20
+.byte 45, 19, 47, 17, 48, 16, 50, 14, 51, 13, 52, 12, 53, 11, 55,  9
+.byte 56,  8, 57,  7, 58,  6, 59,  5, 60,  4, 60,  4, 61,  3, 62,  2
+endconst
+
+/*
+ * static void blend_v_lsx(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                           const int w, int h)
+ */
+function blend_v_8bpc_lsx
+    la.local      t8,     obmc_masks_la
+
+    clz.w         t0,     a3
+    li.w          t1,     26
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .BLEND_V_LSX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0  // The jump addresses are relative to JRTABLE
+    add.d         t1,     t1,      t2 // Get absolute address
+    jirl          $r0,    t1,      0
+
+    .align   3
+.BLEND_V_LSX_JRTABLE:
+    .hword .BLEND_V_W32_LSX  - .BLEND_V_LSX_JRTABLE
+    .hword .BLEND_V_W16_LSX  - .BLEND_V_LSX_JRTABLE
+    .hword .BLEND_V_W8_LSX   - .BLEND_V_LSX_JRTABLE
+    .hword .BLEND_V_W4_LSX   - .BLEND_V_LSX_JRTABLE
+    .hword .BLEND_V_W2_LSX   - .BLEND_V_LSX_JRTABLE
+    .hword .BLEND_V_W2_LSX_1 - .BLEND_V_LSX_JRTABLE  //Instructions must be 4-byte aligned
+
+.BLEND_V_W2_LSX:
+    ld.bu           t6,     t8,      4
+    ld.bu           t7,     t8,      5
+
+.BLEND_V_W2_LSX_1:
+    ld.bu           t0,     a0,      0
+    ld.bu           t1,     a2,      0
+    mul.d           t0,     t0,      t6
+    mul.d           t1,     t1,      t7
+    addi.d          t0,     t0,      32
+    add.d           t0,     t0,      t1
+    srli.d          t0,     t0,      6
+    st.b            t0,     a0,      0
+
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      2
+    addi.d          a5,     a5,      2
+
+    blt             zero,   a4,     .BLEND_V_W2_LSX_1
+    b               .BLEND_V_END_LSX
+
+.BLEND_V_W4_LSX:
+    vld             vr20,   t8,      8
+
+.BLEND_V_W4_LSX_1:
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr0,    vr1,     vr0
+    vdp2.h.bu       vr1,    vr0,     vr20
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.h        vr1,    a0,      0,   0
+    vstelm.b        vr1,    a0,      2,   2
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      4
+
+    blt             zero,   a4,     .BLEND_V_W4_LSX_1
+    b              .BLEND_V_END_LSX
+
+.BLEND_V_W8_LSX:
+    vld             vr20,   t8,      16
+
+.BLEND_V_W8_LSX_1:
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr0,    vr1,     vr0
+    vdp2.h.bu       vr1,    vr0,     vr20
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.w        vr1,    a0,      0,   0
+    vstelm.h        vr1,    a0,      4,   2
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      8
+
+    blt             zero,   a4,     .BLEND_V_W8_LSX_1
+    b              .BLEND_V_END_LSX
+
+.BLEND_V_W16_LSX:
+    vld             vr20,   t8,      32
+    vld             vr21,   t8,      48
+
+.BLEND_V_W16_LSX_1:
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr2,    vr1,     vr0
+    vilvh.b         vr3,    vr1,     vr0
+    vmulwev.h.bu    vr4,    vr2,     vr20
+    vmulwev.h.bu    vr5,    vr3,     vr21
+    vmaddwod.h.bu   vr4,    vr2,     vr20
+    vmaddwod.h.bu   vr5,    vr3,     vr21
+    vssrarni.bu.h   vr5,    vr4,     6
+
+    vstelm.d        vr5,    a0,      0,   0
+    vstelm.w        vr5,    a0,      8,   2
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      16
+
+    blt             zero,   a4,     .BLEND_V_W16_LSX_1
+    b              .BLEND_V_END_LSX
+
+.BLEND_V_W32_LSX:
+    vld             vr20,   t8,      64
+    vld             vr21,   t8,      80
+    vld             vr22,   t8,      96
+
+.BLEND_V_W32_LSX_1:
+    vld             vr0,    a0,      0
+    vld             vr1,    a0,      16
+    vld             vr2,    a2,      0
+    vld             vr3,    a2,      16
+
+    vilvl.b         vr4,    vr2,     vr0
+    vmulwev.h.bu    vr7,    vr4,     vr20
+    vilvh.b         vr5,    vr2,     vr0
+    vmulwev.h.bu    vr8,    vr5,     vr21
+    vilvl.b         vr6,    vr3,     vr1
+    vmulwev.h.bu    vr9,    vr6,     vr22
+    vmaddwod.h.bu   vr7,    vr4,     vr20
+    vmaddwod.h.bu   vr8,    vr5,     vr21
+    vmaddwod.h.bu   vr9,    vr6,     vr22
+    vssrarni.bu.h   vr8,    vr7,     6
+    vssrarni.bu.h   vr9,    vr9,     6
+
+    vst             vr8,    a0,      0
+    vstelm.d        vr9,    a0,      16,   0
+    addi.w          a4,     a4,      -1
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      32
+
+    blt             zero,   a4,     .BLEND_V_W32_LSX_1
+
+.BLEND_V_END_LSX:
+
+endfunc
+
+/*
+ * static void blend_h_lsx(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                           const int w, int h)
+ */
+function blend_h_8bpc_lsx
+    la.local      t8,     obmc_masks_la
+    alsl.d        t8,     a4,      t8,    1
+    srli.d        t0,     a4,      1
+    srli.d        t1,     a4,      2
+    add.d         a4,     t0,      t1  // h = (h * 3) >> 2;
+    slli.d        a4,     a4,      1
+    add.d         a4,     a4,      t8
+
+    clz.w         t0,     a3
+    li.w          t1,     24
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .BLEND_H_LSX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0  // The jump addresses are relative to JRTABLE
+    add.d         t1,     t1,      t2 // Get absolute address
+    jirl          $r0,    t1,      0
+
+    .align   3
+.BLEND_H_LSX_JRTABLE:
+    .hword .BLEND_H_W128_LSX - .BLEND_H_LSX_JRTABLE
+    .hword .BLEND_H_W64_LSX  - .BLEND_H_LSX_JRTABLE
+    .hword .BLEND_H_W32_LSX  - .BLEND_H_LSX_JRTABLE
+    .hword .BLEND_H_W16_LSX  - .BLEND_H_LSX_JRTABLE
+    .hword .BLEND_H_W8_LSX   - .BLEND_H_LSX_JRTABLE
+    .hword .BLEND_H_W4_LSX   - .BLEND_H_LSX_JRTABLE
+    .hword .BLEND_H_W2_LSX   - .BLEND_H_LSX_JRTABLE
+    .hword .BLEND_H_END_LSX  - .BLEND_H_LSX_JRTABLE  //Instructions must be 4-byte aligned
+
+.BLEND_H_W2_LSX:
+    vldrepl.h       vr20,   t8,      0
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr0,    vr1,     vr0
+    vdp2.h.bu       vr1,    vr0,     vr20
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.h        vr1,    a0,      0,   0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      2
+
+    blt             t8,     a4,     .BLEND_H_W2_LSX
+    b               .BLEND_H_END_LSX
+
+.BLEND_H_W4_LSX:
+    vldrepl.h       vr20,   t8,      0
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr0,    vr1,     vr0
+    vdp2.h.bu       vr1,    vr0,     vr20
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.w        vr1,    a0,      0,   0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      4
+
+    blt             t8,     a4,     .BLEND_H_W4_LSX
+    b               .BLEND_H_END_LSX
+
+.BLEND_H_W8_LSX:
+    vldrepl.h       vr20,   t8,      0
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr0,    vr1,     vr0
+    vdp2.h.bu       vr1,    vr0,     vr20
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.d        vr1,    a0,      0,   0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      8
+
+    blt             t8,     a4,     .BLEND_H_W8_LSX
+    b               .BLEND_H_END_LSX
+
+.BLEND_H_W16_LSX:
+    vldrepl.h       vr20,   t8,      0
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr2,    vr1,     vr0
+    vilvh.b         vr3,    vr1,     vr0
+    vmulwev.h.bu    vr4,    vr2,     vr20
+    vmulwev.h.bu    vr5,    vr3,     vr20
+    vmaddwod.h.bu   vr4,    vr2,     vr20
+    vmaddwod.h.bu   vr5,    vr3,     vr20
+    vssrarni.bu.h   vr5,    vr4,     6
+
+    vst             vr5,    a0,      0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      16
+
+    blt             t8,     a4,     .BLEND_H_W16_LSX
+    b               .BLEND_H_END_LSX
+
+.BLEND_H_W32_LSX:
+    vldrepl.h       vr20,   t8,      0
+
+    vld             vr0,    a0,      0
+    vld             vr1,    a0,      16
+    vld             vr2,    a2,      0
+    vld             vr3,    a2,      16
+
+    vilvl.b         vr4,    vr2,     vr0
+    vilvh.b         vr5,    vr2,     vr0
+    vilvl.b         vr6,    vr3,     vr1
+    vilvh.b         vr3,    vr3,     vr1
+    vmulwev.h.bu    vr7,    vr4,     vr20
+    vmulwev.h.bu    vr8,    vr5,     vr20
+    vmulwev.h.bu    vr9,    vr6,     vr20
+    vmulwev.h.bu    vr0,    vr3,     vr20
+    vmaddwod.h.bu   vr7,    vr4,     vr20
+    vmaddwod.h.bu   vr8,    vr5,     vr20
+    vmaddwod.h.bu   vr9,    vr6,     vr20
+    vmaddwod.h.bu   vr0,    vr3,     vr20
+    vssrarni.bu.h   vr8,    vr7,     6
+    vssrarni.bu.h   vr0,    vr9,     6
+
+    vst             vr8,    a0,      0
+    vst             vr0,    a0,      16
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      32
+
+    blt             t8,     a4,     .BLEND_H_W32_LSX
+    b               .BLEND_H_END_LSX
+
+.BLEND_H_W64_LSX:
+    vldrepl.h       vr20,   t8,      0
+
+    vld             vr0,    a0,      0
+    vld             vr1,    a0,      16
+    vld             vr2,    a0,      32
+    vld             vr3,    a0,      48
+    vld             vr4,    a2,      0
+    vld             vr5,    a2,      16
+    vld             vr6,    a2,      32
+    vld             vr7,    a2,      48
+
+    vilvl.b         vr8,    vr4,     vr0
+    vilvh.b         vr9,    vr4,     vr0
+    vilvl.b         vr10,   vr5,     vr1
+    vilvh.b         vr11,   vr5,     vr1
+    vilvl.b         vr12,   vr6,     vr2
+    vilvh.b         vr13,   vr6,     vr2
+    vilvl.b         vr14,   vr7,     vr3
+    vilvh.b         vr15,   vr7,     vr3
+    vmulwev.h.bu    vr0,    vr8,     vr20
+    vmulwev.h.bu    vr1,    vr9,     vr20
+    vmulwev.h.bu    vr2,    vr10,    vr20
+    vmulwev.h.bu    vr3,    vr11,    vr20
+    vmulwev.h.bu    vr4,    vr12,    vr20
+    vmulwev.h.bu    vr5,    vr13,    vr20
+    vmulwev.h.bu    vr6,    vr14,    vr20
+    vmulwev.h.bu    vr7,    vr15,    vr20
+
+    vmaddwod.h.bu   vr0,    vr8,     vr20
+    vmaddwod.h.bu   vr1,    vr9,     vr20
+    vmaddwod.h.bu   vr2,    vr10,    vr20
+    vmaddwod.h.bu   vr3,    vr11,    vr20
+    vmaddwod.h.bu   vr4,    vr12,    vr20
+    vmaddwod.h.bu   vr5,    vr13,    vr20
+    vmaddwod.h.bu   vr6,    vr14,    vr20
+    vmaddwod.h.bu   vr7,    vr15,    vr20
+
+    vssrarni.bu.h   vr1,    vr0,     6
+    vssrarni.bu.h   vr3,    vr2,     6
+    vssrarni.bu.h   vr5,    vr4,     6
+    vssrarni.bu.h   vr7,    vr6,     6
+
+    vst             vr1,    a0,      0
+    vst             vr3,    a0,      16
+    vst             vr5,    a0,      32
+    vst             vr7,    a0,      48
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      64
+
+    blt             t8,     a4,     .BLEND_H_W64_LSX
+    b               .BLEND_H_END_LSX
+
+.BLEND_H_W128_LSX:
+    vldrepl.h       vr20,   t8,      0
+
+    vld             vr0,    a0,      0
+    vld             vr1,    a0,      16
+    vld             vr2,    a0,      32
+    vld             vr3,    a0,      48
+    vld             vr4,    a2,      0
+    vld             vr5,    a2,      16
+    vld             vr6,    a2,      32
+    vld             vr7,    a2,      48
+
+    vilvl.b         vr8,    vr4,     vr0
+    vilvh.b         vr9,    vr4,     vr0
+    vilvl.b         vr10,   vr5,     vr1
+    vilvh.b         vr11,   vr5,     vr1
+    vilvl.b         vr12,   vr6,     vr2
+    vilvh.b         vr13,   vr6,     vr2
+    vilvl.b         vr14,   vr7,     vr3
+    vilvh.b         vr15,   vr7,     vr3
+    vmulwev.h.bu    vr0,    vr8,     vr20
+    vmulwev.h.bu    vr1,    vr9,     vr20
+    vmulwev.h.bu    vr2,    vr10,    vr20
+    vmulwev.h.bu    vr3,    vr11,    vr20
+    vmulwev.h.bu    vr4,    vr12,    vr20
+    vmulwev.h.bu    vr5,    vr13,    vr20
+    vmulwev.h.bu    vr6,    vr14,    vr20
+    vmulwev.h.bu    vr7,    vr15,    vr20
+
+    vmaddwod.h.bu   vr0,    vr8,     vr20
+    vmaddwod.h.bu   vr1,    vr9,     vr20
+    vmaddwod.h.bu   vr2,    vr10,    vr20
+    vmaddwod.h.bu   vr3,    vr11,    vr20
+    vmaddwod.h.bu   vr4,    vr12,    vr20
+    vmaddwod.h.bu   vr5,    vr13,    vr20
+    vmaddwod.h.bu   vr6,    vr14,    vr20
+    vmaddwod.h.bu   vr7,    vr15,    vr20
+
+    vssrarni.bu.h   vr1,    vr0,     6
+    vssrarni.bu.h   vr3,    vr2,     6
+    vssrarni.bu.h   vr5,    vr4,     6
+    vssrarni.bu.h   vr7,    vr6,     6
+
+    vst             vr1,    a0,      0
+    vst             vr3,    a0,      16
+    vst             vr5,    a0,      32
+    vst             vr7,    a0,      48
+
+    /* second */
+    vld             vr0,    a0,      64
+    vld             vr1,    a0,      80
+    vld             vr2,    a0,      96
+    vld             vr3,    a0,      112
+    vld             vr4,    a2,      64
+    vld             vr5,    a2,      80
+    vld             vr6,    a2,      96
+    vld             vr7,    a2,      112
+
+    vilvl.b         vr8,    vr4,     vr0
+    vilvh.b         vr9,    vr4,     vr0
+    vilvl.b         vr10,   vr5,     vr1
+    vilvh.b         vr11,   vr5,     vr1
+    vilvl.b         vr12,   vr6,     vr2
+    vilvh.b         vr13,   vr6,     vr2
+    vilvl.b         vr14,   vr7,     vr3
+    vilvh.b         vr15,   vr7,     vr3
+    vmulwev.h.bu    vr0,    vr8,     vr20
+    vmulwev.h.bu    vr1,    vr9,     vr20
+    vmulwev.h.bu    vr2,    vr10,    vr20
+    vmulwev.h.bu    vr3,    vr11,    vr20
+    vmulwev.h.bu    vr4,    vr12,    vr20
+    vmulwev.h.bu    vr5,    vr13,    vr20
+    vmulwev.h.bu    vr6,    vr14,    vr20
+    vmulwev.h.bu    vr7,    vr15,    vr20
+
+    vmaddwod.h.bu   vr0,    vr8,     vr20
+    vmaddwod.h.bu   vr1,    vr9,     vr20
+    vmaddwod.h.bu   vr2,    vr10,    vr20
+    vmaddwod.h.bu   vr3,    vr11,    vr20
+    vmaddwod.h.bu   vr4,    vr12,    vr20
+    vmaddwod.h.bu   vr5,    vr13,    vr20
+    vmaddwod.h.bu   vr6,    vr14,    vr20
+    vmaddwod.h.bu   vr7,    vr15,    vr20
+
+    vssrarni.bu.h   vr1,    vr0,     6
+    vssrarni.bu.h   vr3,    vr2,     6
+    vssrarni.bu.h   vr5,    vr4,     6
+    vssrarni.bu.h   vr7,    vr6,     6
+
+    vst             vr1,    a0,      64
+    vst             vr3,    a0,      80
+    vst             vr5,    a0,      96
+    vst             vr7,    a0,      112
+
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      128
+
+    blt             t8,     a4,     .BLEND_H_W128_LSX
+    b               .BLEND_H_END_LSX
+
+.BLEND_H_END_LSX:
+
+endfunc
+
+/*
+ * static void blend_h_lsx(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                           const int w, int h)
+ */
+function blend_h_8bpc_lasx
+    la.local      t8,     obmc_masks_la
+    alsl.d        t8,     a4,      t8,    1
+    srli.d        t0,     a4,      1
+    srli.d        t1,     a4,      2
+    add.d         a4,     t0,      t1  // h = (h * 3) >> 2;
+    slli.d        a4,     a4,      1
+    add.d         a4,     a4,      t8
+
+    clz.w         t0,     a3
+    li.w          t1,     24
+    sub.w         t0,     t0,      t1
+    la.local      t1,     .BLEND_H_LASX_JRTABLE
+    alsl.d        t0,     t0,      t1,    1
+    ld.h          t2,     t0,      0  // The jump addresses are relative to JRTABLE
+    add.d         t1,     t1,      t2 // Get absolute address
+    jirl          $r0,    t1,      0
+
+    .align   3
+.BLEND_H_LASX_JRTABLE:
+    .hword .BLEND_H_W128_LASX - .BLEND_H_LASX_JRTABLE
+    .hword .BLEND_H_W64_LASX  - .BLEND_H_LASX_JRTABLE
+    .hword .BLEND_H_W32_LASX  - .BLEND_H_LASX_JRTABLE
+    .hword .BLEND_H_W16_LASX  - .BLEND_H_LASX_JRTABLE
+    .hword .BLEND_H_W8_LASX   - .BLEND_H_LASX_JRTABLE
+    .hword .BLEND_H_W4_LASX   - .BLEND_H_LASX_JRTABLE
+    .hword .BLEND_H_W2_LASX   - .BLEND_H_LASX_JRTABLE
+    .hword .BLEND_H_END_LASX  - .BLEND_H_LASX_JRTABLE  //Instructions must be 4-byte aligned
+
+.BLEND_H_W2_LASX:
+    vldrepl.h       vr20,   t8,      0
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr0,    vr1,     vr0
+    vdp2.h.bu       vr1,    vr0,     vr20
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.h        vr1,    a0,      0,   0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      2
+
+    blt             t8,     a4,     .BLEND_H_W2_LASX
+    b               .BLEND_H_END_LASX
+
+.BLEND_H_W4_LASX:
+    vldrepl.h       vr20,   t8,      0
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr0,    vr1,     vr0
+    vdp2.h.bu       vr1,    vr0,     vr20
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.w        vr1,    a0,      0,   0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      4
+
+    blt             t8,     a4,     .BLEND_H_W4_LASX
+    b               .BLEND_H_END_LASX
+
+.BLEND_H_W8_LASX:
+    vldrepl.h       vr20,   t8,      0
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr0,    vr1,     vr0
+    vdp2.h.bu       vr1,    vr0,     vr20
+    vssrarni.bu.h   vr1,    vr1,     6
+
+    vstelm.d        vr1,    a0,      0,   0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      8
+
+    blt             t8,     a4,     .BLEND_H_W8_LASX
+    b               .BLEND_H_END_LASX
+
+.BLEND_H_W16_LASX:
+    vldrepl.h       vr20,   t8,      0
+    vld             vr0,    a0,      0
+    vld             vr1,    a2,      0
+
+    vilvl.b         vr2,    vr1,     vr0
+    vilvh.b         vr3,    vr1,     vr0
+    vmulwev.h.bu    vr4,    vr2,     vr20
+    vmulwev.h.bu    vr5,    vr3,     vr20
+    vmaddwod.h.bu   vr4,    vr2,     vr20
+    vmaddwod.h.bu   vr5,    vr3,     vr20
+    vssrarni.bu.h   vr5,    vr4,     6
+
+    vst             vr5,    a0,      0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      16
+
+    blt             t8,     a4,     .BLEND_H_W16_LSX
+    b               .BLEND_H_END_LSX
+
+.BLEND_H_W32_LASX:
+    xvldrepl.h      xr20,   t8,      0
+
+    xvld            xr0,    a0,      0
+    xvld            xr1,    a2,      0
+
+    xvilvl.b        xr2,    xr1,     xr0
+    xvilvh.b        xr3,    xr1,     xr0
+
+    xvmulwev.h.bu   xr4,    xr2,     xr20
+    xvmulwev.h.bu   xr5,    xr3,     xr20
+    xvmaddwod.h.bu  xr4,    xr2,     xr20
+    xvmaddwod.h.bu  xr5,    xr3,     xr20
+    xvssrarni.bu.h  xr5,    xr4,     6
+
+    xvst            xr5,    a0,      0
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      32
+
+    blt             t8,     a4,     .BLEND_H_W32_LASX
+    b               .BLEND_H_END_LASX
+
+.BLEND_H_W64_LASX:
+    xvldrepl.h      xr20,   t8,      0
+
+    xvld            xr0,    a0,      0
+    xvld            xr1,    a0,      32
+    xvld            xr2,    a2,      0
+    xvld            xr3,    a2,      32
+
+    xvilvl.b        xr4,    xr2,     xr0
+    xvilvh.b        xr5,    xr2,     xr0
+    xvilvl.b        xr6,    xr3,     xr1
+    xvilvh.b        xr7,    xr3,     xr1
+
+    xvmulwev.h.bu   xr0,    xr4,     xr20
+    xvmulwev.h.bu   xr1,    xr5,     xr20
+    xvmulwev.h.bu   xr2,    xr6,     xr20
+    xvmulwev.h.bu   xr3,    xr7,     xr20
+    xvmaddwod.h.bu  xr0,    xr4,     xr20
+    xvmaddwod.h.bu  xr1,    xr5,     xr20
+    xvmaddwod.h.bu  xr2,    xr6,     xr20
+    xvmaddwod.h.bu  xr3,    xr7,     xr20
+    xvssrarni.bu.h  xr1,    xr0,     6
+    xvssrarni.bu.h  xr3,    xr2,     6
+
+    xvst            xr1,    a0,      0
+    xvst            xr3,    a0,      32
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      64
+
+    blt             t8,     a4,     .BLEND_H_W64_LASX
+    b               .BLEND_H_END_LASX
+
+.BLEND_H_W128_LASX:
+    xvldrepl.h      xr20,   t8,      0
+
+    xvld            xr0,    a0,      0
+    xvld            xr1,    a0,      32
+    xvld            xr2,    a0,      64
+    xvld            xr3,    a0,      96
+    xvld            xr4,    a2,      0
+    xvld            xr5,    a2,      32
+    xvld            xr6,    a2,      64
+    xvld            xr7,    a2,      96
+
+    xvilvl.b        xr8,    xr4,     xr0
+    xvilvh.b        xr9,    xr4,     xr0
+    xvilvl.b        xr10,   xr5,     xr1
+    xvilvh.b        xr11,   xr5,     xr1
+    xvilvl.b        xr12,   xr6,     xr2
+    xvilvh.b        xr13,   xr6,     xr2
+    xvilvl.b        xr14,   xr7,     xr3
+    xvilvh.b        xr15,   xr7,     xr3
+
+    xvmulwev.h.bu   xr0,    xr8,     xr20
+    xvmulwev.h.bu   xr1,    xr9,     xr20
+    xvmulwev.h.bu   xr2,    xr10,    xr20
+    xvmulwev.h.bu   xr3,    xr11,    xr20
+    xvmulwev.h.bu   xr4,    xr12,    xr20
+    xvmulwev.h.bu   xr5,    xr13,    xr20
+    xvmulwev.h.bu   xr6,    xr14,    xr20
+    xvmulwev.h.bu   xr7,    xr15,    xr20
+    xvmaddwod.h.bu  xr0,    xr8,     xr20
+    xvmaddwod.h.bu  xr1,    xr9,     xr20
+    xvmaddwod.h.bu  xr2,    xr10,    xr20
+    xvmaddwod.h.bu  xr3,    xr11,    xr20
+    xvmaddwod.h.bu  xr4,    xr12,    xr20
+    xvmaddwod.h.bu  xr5,    xr13,    xr20
+    xvmaddwod.h.bu  xr6,    xr14,    xr20
+    xvmaddwod.h.bu  xr7,    xr15,    xr20
+    xvssrarni.bu.h  xr1,    xr0,     6
+    xvssrarni.bu.h  xr3,    xr2,     6
+    xvssrarni.bu.h  xr5,    xr4,     6
+    xvssrarni.bu.h  xr7,    xr6,     6
+
+    xvst            xr1,    a0,      0
+    xvst            xr3,    a0,      32
+    xvst            xr5,    a0,      64
+    xvst            xr7,    a0,      96
+    addi.d          t8,     t8,      2
+    add.d           a0,     a0,      a1
+    addi.d          a2,     a2,      128
+
+    blt             t8,     a4,     .BLEND_H_W128_LASX
+    b               .BLEND_H_END_LASX
+
+.BLEND_H_END_LASX:
+
+endfunc
+
+/*
+ *  a1=16 | a2=8 | a3=4
+ *  temp reg: a4
+ */
+.macro PIXEL_COPY_LSX _dst, _src, _size
+    blt             \_size,  a1,     8f
+16:
+    vld             vr0,     \_src,  0
+    vst             vr0,     \_dst,  0
+    addi.d          \_size,  \_size, -16
+    addi.d          \_dst,   \_dst,  16
+    addi.d          \_src,   \_src,  16
+    blt             a1,      \_size, 16b
+8:
+    blt             \_size,  a2,     14f
+    ld.d            a4,      \_src,  0
+    st.d            a4,      \_dst,  0
+    addi.d          \_size,  \_size, -8
+    addi.d          \_dst,   \_dst,  8
+    addi.d          \_src,   \_src,  8
+14:
+    blt             \_size,  a3,     11f
+    ld.w            a4,      \_src,  0
+    st.w            a4,      \_dst,  0
+    addi.d          \_size,  \_size, -4
+    addi.d          \_dst,   \_dst,  4
+    addi.d          \_src,   \_src,  4
+11:
+    beqz            \_size,  110f
+111:
+    ld.b            a4,      \_src,  0
+    st.b            a4,      \_dst,  0
+    addi.d          \_size,  \_size, -1
+    addi.d          \_dst,   \_dst,  1
+    addi.d          \_src,   \_src,  1
+    bnez            \_size,  111b
+110:
+.endm
+
+/*
+ *  a1=16 | a2=8 | a3=4
+ */
+.macro PIXEL_SET_LSX _dst, _vsrc, _size
+    blt             \_size,  a1,     8f
+16:
+    vst             \_vsrc,  \_dst,  0
+    addi.d          \_size,  \_size, -16
+    addi.d          \_dst,   \_dst,  16
+    blt             a1,      \_size, 16b
+8:
+    blt             \_size,  a2,     14f
+    vstelm.d        \_vsrc,  \_dst,  0,   0
+    addi.d          \_size,  \_size, -8
+    addi.d          \_dst,   \_dst,  8
+14:
+    blt             \_size,  a3,     11f
+    vstelm.w        \_vsrc,  \_dst,  0,   0
+    addi.d          \_size,  \_size, -4
+    addi.d          \_dst,   \_dst,  4
+11:
+    beqz            \_size,  110f
+111:
+    vstelm.b        \_vsrc,  \_dst,  0,   0
+    addi.d          \_size,  \_size, -1
+    addi.d          \_dst,   \_dst,  1
+    bnez            \_size,  111b
+110:
+.endm
+
+/*
+ *  temp reg: a4 a5 t2 t3 vr0
+ */
+.macro DEGE_LOOP need_left, need_right
+0:
+    addi.d          t2,      t6,     0   // dst
+    addi.d          t3,      t7,     0   // src
+.if \need_left
+    vldrepl.b       vr0,     t3,     0
+    addi.d          a5,      t0,     0
+    PIXEL_SET_LSX t2, vr0, a5
+.endif
+
+    addi.d          a5,      t4,     0
+    PIXEL_COPY_LSX t2, t3, a5
+
+.if \need_right
+    vldrepl.b       vr0,     t3,     -1
+    addi.d          a5,      t1,     0
+    PIXEL_SET_LSX t2, vr0, a5
+.endif
+
+    addi.d          t5,      t5,     -1
+    add.d           t7,      t7,     t8
+    add.d           t6,      t6,     a7
+    bnez            t5,      0b
+.endm
+
+/*
+ * static void emu_edge_c(const intptr_t bw, const intptr_t bh,
+ *                        const intptr_t iw, const intptr_t ih,
+ *                        const intptr_t x, const intptr_t y,
+ *                        pixel *dst, const ptrdiff_t dst_stride,
+ *                        const pixel *ref, const ptrdiff_t ref_stride)
+ */
+function emu_edge_8bpc_lsx
+    vxor.v          vr23,   vr23,    vr23   // zero
+    addi.d          t0,     a3,      -1     // ih - 1
+    addi.d          t1,     a2,      -1     // iw - 1
+    vreplgr2vr.w    vr22,   t0
+    vinsgr2vr.w     vr22,   t1,        1
+    vreplgr2vr.w    vr0,    a5
+    vinsgr2vr.w     vr0,    a4,        1     // [0] - h | [1] - w
+
+    vclip.w         vr2,    vr0,      vr23,    vr22
+    vpickve2gr.w    t0,     vr2,      0
+    ld.d            t2,     sp,       0
+    ld.d            t8,     sp,       8     // ref_stride
+    mul.w           t0,     t0,       t8
+    vpickve2gr.w    t1,     vr2,      1
+    add.d           t2,     t2,       t1
+    add.d           t7,     t0,       t2    // ref
+
+    addi.d          t0,     a0,       -1     // bw - 1
+    addi.d          t1,     a1,       -1     // bh - 1
+    vreplgr2vr.w    vr21,   t0
+    vreplgr2vr.w    vr22,   t1
+    vilvl.d         vr21,   vr22,      vr21
+    sub.d           t2,     zero,      a4    // -x
+    add.d           t3,     a0,        a4
+    sub.d           t3,     t3,        a2    // x + bw - iw
+    sub.d           t4,     zero,      a5    // -y
+    add.d           t5,     a1,        a5
+    sub.d           t5,     t5,        a3    // y + bh - ih
+    vreplgr2vr.w    vr0,    t2
+    vinsgr2vr.w     vr0,    t3,        1
+    vinsgr2vr.w     vr0,    t4,        2
+    vinsgr2vr.w     vr0,    t5,        3
+    vclip.w         vr2,    vr0,       vr23,    vr21
+    vpickve2gr.w    t0,     vr2,       0     // left_ext
+    vpickve2gr.w    t1,     vr2,       1     // right_ext
+    vpickve2gr.w    t2,     vr2,       2     // top_ext
+    vpickve2gr.w    t3,     vr2,       3     // bottom_ext
+
+    mul.w           t6,     t2,        a7
+    add.d           t4,     t0,        t1
+    add.d           t5,     t2,        t3
+    sub.d           t4,     a0,        t4    // center_w
+    sub.d           t5,     a1,        t5    // center_h
+
+    addi.d          a1,     zero,      16
+    addi.d          a2,     zero,      8
+    addi.d          a3,     zero,      4
+    add.d           t6,     t6,        a6    // blk
+
+    beqz            t0,     2f
+    // need_left
+    beqz            t1,     3f
+    // need_left + need_right
+    DEGE_LOOP       1,   1
+    b               5f
+
+2:
+    // !need_left
+    beqz            t1,     4f
+    // !need_left + need_right
+    DEGE_LOOP       0,   1
+    b               5f
+
+3:
+    // need_left + !need_right
+    DEGE_LOOP       1,   0
+    b               5f
+
+4:
+    // !need_left + !need_right
+    DEGE_LOOP       0,   0
+
+5:
+    vpickve2gr.w    t2,     vr2,       2     // top_ext
+    vpickve2gr.w    t3,     vr2,       3     // bottom_ext
+    sub.d           t7,     a7,        a0    // dst_stride - bw
+    mul.w           t8,     t2,        a7
+
+    beqz            t3,     2f
+    // need_bottom
+    sub.d           t0,     t6,        a7    //  &dst[-PXSTRIDE(dst_stride)]
+1:
+    addi.d          t1,     t0,        0
+    addi.d          a5,     a0,        0
+    PIXEL_COPY_LSX t6, t1, a5
+    add.d           t6,     t6,        t7
+    addi.d          t3,     t3,   -1
+    bnez            t3,     1b
+2:
+    beqz            t2,     3f
+    // need_top
+    add.d           t8,     t8,        a6    // blk
+1:
+    addi.d          t1,     t8,        0
+    addi.d          a5,     a0,        0
+    PIXEL_COPY_LSX a6, t1, a5
+    add.d           a6,     a6,        t7
+    addi.d          t2,     t2,   -1
+    bnez            t2,     1b
+3:
+
+endfunc
diff --git a/media/libdav1d/src/src/loongarch/mc.h b/media/libdav1d/src/src/loongarch/mc.h
new file mode 100644
index 0000000000..092b4d19b7
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/mc.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_MC_H
+#define DAV1D_SRC_LOONGARCH_MC_H
+
+#include "config.h"
+#include "src/mc.h"
+#include "src/cpu.h"
+
+#define init_mc_fn(type, name, suffix) \
+    c->mc[type] = BF(dav1d_put_##name, suffix)
+#define init_mct_fn(type, name, suffix) \
+    c->mct[type] = BF(dav1d_prep_##name, suffix)
+
+decl_avg_fn(BF(dav1d_avg, lsx));
+decl_w_avg_fn(BF(dav1d_w_avg, lsx));
+decl_mask_fn(BF(dav1d_mask, lsx));
+decl_warp8x8_fn(BF(dav1d_warp_affine_8x8, lsx));
+decl_warp8x8t_fn(BF(dav1d_warp_affine_8x8t, lsx));
+decl_w_mask_fn(BF(dav1d_w_mask_420, lsx));
+decl_blend_fn(BF(dav1d_blend, lsx));
+decl_blend_dir_fn(BF(dav1d_blend_v, lsx));
+decl_blend_dir_fn(BF(dav1d_blend_h, lsx));
+decl_emu_edge_fn(BF(dav1d_emu_edge, lsx));
+
+decl_8tap_fns(lsx);
+
+decl_avg_fn(BF(dav1d_avg, lasx));
+decl_w_avg_fn(BF(dav1d_w_avg, lasx));
+decl_mask_fn(BF(dav1d_mask, lasx));
+decl_warp8x8_fn(BF(dav1d_warp_affine_8x8, lasx));
+decl_warp8x8t_fn(BF(dav1d_warp_affine_8x8t, lasx));
+decl_w_mask_fn(BF(dav1d_w_mask_420, lasx));
+decl_blend_dir_fn(BF(dav1d_blend_h, lasx));
+
+decl_8tap_gen(mct, prep, lasx);
+
+static ALWAYS_INLINE void mc_dsp_init_loongarch(Dav1dMCDSPContext *const c) {
+#if BITDEPTH == 8
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LSX)) return;
+
+    c->avg = BF(dav1d_avg, lsx);
+    c->w_avg = BF(dav1d_w_avg, lsx);
+    c->mask = BF(dav1d_mask, lsx);
+    c->warp8x8 = BF(dav1d_warp_affine_8x8, lsx);
+    c->warp8x8t = BF(dav1d_warp_affine_8x8t, lsx);
+    c->w_mask[2] = BF(dav1d_w_mask_420, lsx);
+    c->blend = BF(dav1d_blend, lsx);
+    c->blend_v = BF(dav1d_blend_v, lsx);
+    c->blend_h = BF(dav1d_blend_h, lsx);
+    c->emu_edge = BF(dav1d_emu_edge, lsx);
+
+    init_8tap_fns(lsx);
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LASX)) return;
+
+    c->avg = BF(dav1d_avg, lasx);
+    c->w_avg = BF(dav1d_w_avg, lasx);
+    c->mask = BF(dav1d_mask, lasx);
+    c->warp8x8 = BF(dav1d_warp_affine_8x8, lasx);
+    c->warp8x8t = BF(dav1d_warp_affine_8x8t, lasx);
+    c->w_mask[2] = BF(dav1d_w_mask_420, lasx);
+    c->blend_h = BF(dav1d_blend_h, lasx);
+
+    init_8tap_gen(mct, lasx);
+#endif
+}
+
+#endif /* DAV1D_SRC_LOONGARCH_MC_H */
diff --git a/media/libdav1d/src/src/loongarch/msac.S b/media/libdav1d/src/src/loongarch/msac.S
new file mode 100644
index 0000000000..f36c4e072c
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/msac.S
@@ -0,0 +1,612 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "loongson_asm.S"
+
+const min_prob
+  .short 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0
+endconst
+
+const ph_0xff00
+.rept 8
+  .short 0xff00
+.endr
+endconst
+
+.macro decode_symbol_adapt w
+    addi.d          sp,      sp,     -48
+    vldrepl.h       vr0,     a0,      24   //rng
+    fst.s           f0,      sp,      0    //val==0
+    vld             vr1,     a1,      0    //cdf
+.if \w == 16
+    vld             vr11,    a1,      16
+.endif
+    vldrepl.d       vr2,     a0,      16   //dif
+    ld.w            t1,      a0,      32   //allow_update_cdf
+    la.local        t2,      min_prob
+    addi.d          t2,      t2,      30
+    slli.w          t3,      a2,      1
+    sub.d           t2,      t2,      t3
+    vld             vr3,     t2,      0    //min_prob
+.if \w == 16
+    vld             vr13,    t2,      16
+.endif
+    vsrli.h         vr4,     vr0,     8    //r = s->rng >> 8
+    vslli.h         vr4,     vr4,     8    //r << 8
+    vsrli.h         vr5,     vr1,     6
+    vslli.h         vr5,     vr5,     7
+.if \w == 16
+    vsrli.h         vr15,    vr11,    6
+    vslli.h         vr15,    vr15,    7
+.endif
+    vmuh.hu         vr5,     vr4,     vr5
+    vadd.h          vr5,     vr5,     vr3  //v
+.if \w == 16
+    vmuh.hu         vr15,    vr4,     vr15
+    vadd.h          vr15,    vr15,    vr13
+.endif
+    addi.d          t8,      sp,      2
+    vst             vr5,     t8,      0    //store v
+.if \w == 16
+    vst             vr15,    t8,      16
+.endif
+    vreplvei.h      vr20,    vr2,     3    //c
+    vsle.hu         vr6,     vr5,     vr20
+.if \w == 16
+    vsle.hu         vr16,    vr15,    vr20
+    vpickev.b       vr21,    vr16,    vr6
+.endif
+.if \w <= 8
+    vmskltz.h       vr10,    vr6
+.else
+    vmskltz.b       vr10,    vr21
+.endif
+    beqz            t1,      .renorm\()\w
+
+    // update_cdf
+    alsl.d          t1,      a2,      a1,   1
+    ld.h            t2,      t1,      0    //count
+    srli.w          t3,      t2,      4    //count >> 4
+.if \w == 16
+    addi.w          t3,      t3,      5    //rate
+.else
+    addi.w          t3,      t3,      4
+    li.w            t5,      2
+    sltu            t5,      t5,      a2
+    add.w           t3,      t3,      t5   //rate
+.endif
+    sltui           t5,      t2,      32
+    add.w           t2,      t2,      t5   //count + (count < 32)
+    vreplgr2vr.h    vr9,     t3
+    vseq.h          vr7,     vr7,     vr7
+    vavgr.hu        vr5,     vr6,     vr7  //i >= val ? -1 : 32768
+    vsub.h          vr5,     vr5,     vr1
+    vsub.h          vr8,     vr1,     vr6
+.if \w == 16
+    vavgr.hu        vr15,    vr16,    vr7
+    vsub.h          vr15,    vr15,    vr11
+    vsub.h          vr18,    vr11,    vr16
+.endif
+    vsra.h          vr5,     vr5,     vr9
+    vadd.h          vr8,     vr8,     vr5
+.if \w == 4
+    fst.d           f8,      a1,      0
+.else
+    vst             vr8,     a1,      0
+.endif
+.if \w == 16
+    vsra.h          vr15,    vr15,    vr9
+    vadd.h          vr18,    vr18,    vr15
+    vst             vr18,    a1,      16
+.endif
+    st.h            t2,      t1,      0
+
+.renorm\()\w:
+    vpickve2gr.h    t3,      vr10,    0
+    ctz.w           a7,      t3            // ret
+    alsl.d          t3,      a7,      t8,      1
+    ld.hu           t4,      t3,      0    // v
+    ld.hu           t5,      t3,      -2   // u
+    sub.w           t5,      t5,      t4   // rng
+    slli.d          t4,      t4,      48
+    vpickve2gr.d    t6,      vr2,     0
+    sub.d           t6,      t6,      t4   // dif
+    clz.w           t4,      t5            // d
+    xori            t4,      t4,      16   // d
+    sll.d           t6,      t6,      t4
+    ld.w            t0,      a0,      28   //cnt
+    sll.w           t5,      t5,      t4
+    sub.w           t7,      t0,      t4   // cnt-d
+    st.w            t5,      a0,      24   // store rng
+    bgeu            t0,      t4,      9f
+
+    // refill
+    ld.d            t0,      a0,      0    // buf_pos
+    ld.d            t1,      a0,      8    // buf_end
+    addi.d          t2,      t0,      8
+    bltu            t1,      t2,      2f
+
+    ld.d            t3,      t0,      0    // next_bits
+    addi.w          t1,      t7,      -48  // shift_bits = cnt + 16 (- 64)
+    nor             t3,      t3,      t3
+    sub.w           t2,      zero,    t1
+    revb.d          t3,      t3            // next_bits = bswap(next_bits)
+    srli.w          t2,      t2,      3    // num_bytes_read
+    srl.d           t3,      t3,      t1   // next_bits >>= (shift_bits & 63)
+    b               3f
+1:
+    addi.w          t3,      t7,      -48
+    srl.d           t3,      t3,      t3   // pad with ones
+    b               4f
+2:
+    bgeu            t0,      t1,      1b
+    ld.d            t3,      t1,      -8   // next_bits
+    sub.w           t2,      t2,      t1
+    sub.w           t1,      t1,      t0   // num_bytes_left
+    slli.w          t2,      t2,      3
+    srl.d           t3,      t3,      t2
+    addi.w          t2,      t7,      -48
+    nor             t3,      t3,      t3
+    sub.w           t4,      zero,    t2
+    revb.d          t3,      t3
+    srli.w          t4,      t4,      3
+    srl.d           t3,      t3,      t2
+    sltu            t2,      t1,      t4
+    maskeqz         t1,      t1,      t2
+    masknez         t2,      t4,      t2
+    or              t2,      t2,      t1   // num_bytes_read
+3:
+    slli.w          t1,      t2,      3
+    add.d           t0,      t0,      t2
+    add.w           t7,      t7,      t1   // cnt += num_bits_read
+    st.d            t0,      a0,      0
+4:
+    or              t6,      t6,      t3   // dif |= next_bits
+9:
+    st.w            t7,      a0,      28   // store cnt
+    st.d            t6,      a0,      16   // store dif
+    move            a0,      a7
+    addi.d          sp,      sp,      48
+.endm
+
+function msac_decode_symbol_adapt4_lsx
+    decode_symbol_adapt 4
+endfunc
+
+function msac_decode_symbol_adapt8_lsx
+    decode_symbol_adapt 8
+endfunc
+
+function msac_decode_symbol_adapt16_lsx
+    decode_symbol_adapt 16
+endfunc
+
+function msac_decode_bool_lsx
+    ld.w            t0,      a0,      24   // rng
+    srli.w          a1,      a1,      6
+    ld.d            t1,      a0,      16   // dif
+    srli.w          t2,      t0,      8    // r >> 8
+    mul.w           t2,      t2,      a1
+    ld.w            a5,      a0,      28   // cnt
+    srli.w          t2,      t2,      1
+    addi.w          t2,      t2,      4    // v
+    slli.d          t3,      t2,      48   // vw
+    sltu            t4,      t1,      t3
+    move            t8,      t4            // ret
+    xori            t4,      t4,      1
+    maskeqz         t6,      t3,      t4   // if (ret) vw
+    sub.d           t6,      t1,      t6   // dif
+    slli.w          t5,      t2,      1
+    sub.w           t5,      t0,      t5   // r - 2v
+    maskeqz         t7,      t5,      t4   // if (ret) r - 2v
+    add.w           t5,      t2,      t7   // v(rng)
+
+    // renorm
+    clz.w           t4,      t5            // d
+    xori            t4,      t4,      16   // d
+    sll.d           t6,      t6,      t4
+    sll.w           t5,      t5,      t4
+    sub.w           t7,      a5,      t4   // cnt-d
+    st.w            t5,      a0,      24   // store rng
+    bgeu            a5,      t4,      9f
+
+    // refill
+    ld.d            t0,      a0,      0    // buf_pos
+    ld.d            t1,      a0,      8    // buf_end
+    addi.d          t2,      t0,      8
+    bltu            t1,      t2,      2f
+
+    ld.d            t3,      t0,      0    // next_bits
+    addi.w          t1,      t7,      -48  // shift_bits = cnt + 16 (- 64)
+    nor             t3,      t3,      t3
+    sub.w           t2,      zero,    t1
+    revb.d          t3,      t3            // next_bits = bswap(next_bits)
+    srli.w          t2,      t2,      3    // num_bytes_read
+    srl.d           t3,      t3,      t1   // next_bits >>= (shift_bits & 63)
+    b               3f
+1:
+    addi.w          t3,      t7,      -48
+    srl.d           t3,      t3,      t3   // pad with ones
+    b               4f
+2:
+    bgeu            t0,      t1,      1b
+    ld.d            t3,      t1,      -8   // next_bits
+    sub.w           t2,      t2,      t1
+    sub.w           t1,      t1,      t0   // num_bytes_left
+    slli.w          t2,      t2,      3
+    srl.d           t3,      t3,      t2
+    addi.w          t2,      t7,      -48
+    nor             t3,      t3,      t3
+    sub.w           t4,      zero,    t2
+    revb.d          t3,      t3
+    srli.w          t4,      t4,      3
+    srl.d           t3,      t3,      t2
+    sltu            t2,      t1,      t4
+    maskeqz         t1,      t1,      t2
+    masknez         t2,      t4,      t2
+    or              t2,      t2,      t1   // num_bytes_read
+3:
+    slli.w          t1,      t2,      3
+    add.d           t0,      t0,      t2
+    add.w           t7,      t7,      t1   // cnt += num_bits_read
+    st.d            t0,      a0,      0
+4:
+    or              t6,      t6,      t3   // dif |= next_bits
+9:
+    st.w            t7,      a0,      28   // store cnt
+    st.d            t6,      a0,      16   // store dif
+    move            a0,      t8
+endfunc
+
+function msac_decode_bool_equi_lsx
+    ld.w            t0,      a0,      24   // rng
+    ld.d            t1,      a0,      16   // dif
+    ld.w            a5,      a0,      28   // cnt
+    srli.w          t2,      t0,      8    // r >> 8
+    slli.w          t2,      t2,      7
+    addi.w          t2,      t2,      4    // v
+
+    slli.d          t3,      t2,      48   // vw
+    sltu            t4,      t1,      t3
+    move            t8,      t4            // ret
+    xori            t4,      t4,      1
+    maskeqz         t6,      t3,      t4   // if (ret) vw
+    sub.d           t6,      t1,      t6   // dif
+    slli.w          t5,      t2,      1
+    sub.w           t5,      t0,      t5   // r - 2v
+    maskeqz         t7,      t5,      t4   // if (ret) r - 2v
+    add.w           t5,      t2,      t7   // v(rng)
+
+    // renorm
+    clz.w           t4,      t5            // d
+    xori            t4,      t4,      16   // d
+    sll.d           t6,      t6,      t4
+    sll.w           t5,      t5,      t4
+    sub.w           t7,      a5,      t4   // cnt-d
+    st.w            t5,      a0,      24   // store rng
+    bgeu            a5,      t4,      9f
+
+    // refill
+    ld.d            t0,      a0,      0    // buf_pos
+    ld.d            t1,      a0,      8    // buf_end
+    addi.d          t2,      t0,      8
+    bltu            t1,      t2,      2f
+
+    ld.d            t3,      t0,      0    // next_bits
+    addi.w          t1,      t7,      -48  // shift_bits = cnt + 16 (- 64)
+    nor             t3,      t3,      t3
+    sub.w           t2,      zero,    t1
+    revb.d          t3,      t3            // next_bits = bswap(next_bits)
+    srli.w          t2,      t2,      3    // num_bytes_read
+    srl.d           t3,      t3,      t1   // next_bits >>= (shift_bits & 63)
+    b               3f
+1:
+    addi.w          t3,      t7,      -48
+    srl.d           t3,      t3,      t3   // pad with ones
+    b               4f
+2:
+    bgeu            t0,      t1,      1b
+    ld.d            t3,      t1,      -8   // next_bits
+    sub.w           t2,      t2,      t1
+    sub.w           t1,      t1,      t0   // num_bytes_left
+    slli.w          t2,      t2,      3
+    srl.d           t3,      t3,      t2
+    addi.w          t2,      t7,      -48
+    nor             t3,      t3,      t3
+    sub.w           t4,      zero,    t2
+    revb.d          t3,      t3
+    srli.w          t4,      t4,      3
+    srl.d           t3,      t3,      t2
+    sltu            t2,      t1,      t4
+    maskeqz         t1,      t1,      t2
+    masknez         t2,      t4,      t2
+    or              t2,      t2,      t1   // num_bytes_read
+3:
+    slli.w          t1,      t2,      3
+    add.d           t0,      t0,      t2
+    add.w           t7,      t7,      t1   // cnt += num_bits_read
+    st.d            t0,      a0,      0
+4:
+    or              t6,      t6,      t3   // dif |= next_bits
+9:
+    st.w            t7,      a0,      28   // store cnt
+    st.d            t6,      a0,      16   // store dif
+    move            a0,      t8
+endfunc
+
+function msac_decode_bool_adapt_lsx
+    ld.hu           a3,      a1,      0    // cdf[0] /f
+    ld.w            t0,      a0,      24   // rng
+    ld.d            t1,      a0,      16   // dif
+    srli.w          t2,      t0,      8    // r >> 8
+    srli.w          a7,      a3,      6
+    mul.w           t2,      t2,      a7
+    ld.w            a4,      a0,      32   // allow_update_cdf
+    ld.w            a5,      a0,      28   // cnt
+    srli.w          t2,      t2,      1
+    addi.w          t2,      t2,      4    // v
+    slli.d          t3,      t2,      48   // vw
+    sltu            t4,      t1,      t3
+    move            t8,      t4            // bit
+    xori            t4,      t4,      1
+    maskeqz         t6,      t3,      t4   // if (ret) vw
+    sub.d           t6,      t1,      t6   // dif
+    slli.w          t5,      t2,      1
+    sub.w           t5,      t0,      t5   // r - 2v
+    maskeqz         t7,      t5,      t4   // if (ret) r - 2v
+    add.w           t5,      t2,      t7   // v(rng)
+    beqz            a4,      .renorm
+
+    // update_cdf
+    ld.hu           t0,      a1,      2    // cdf[1]
+    srli.w          t1,      t0,      4
+    addi.w          t1,      t1,      4    // rate
+    sltui           t2,      t0,      32   // count < 32
+    add.w           t0,      t0,      t2   // count + (count < 32)
+    sub.w           a3,      a3,      t8   // cdf[0] -= bit
+    slli.w          t4,      t8,      15
+    sub.w           t7,      a3,      t4   // cdf[0] - bit - 32768
+    sra.w           t7,      t7,      t1   // (cdf[0] - bit - 32768) >> rate
+    sub.w           t7,      a3,      t7   // cdf[0]
+    st.h            t7,      a1,      0
+    st.h            t0,      a1,      2
+
+.renorm:
+    clz.w           t4,      t5            // d
+    xori            t4,      t4,      16   // d
+    sll.d           t6,      t6,      t4
+    sll.w           t5,      t5,      t4
+    sub.w           t7,      a5,      t4   // cnt-d
+    st.w            t5,      a0,      24   // store rng
+    bgeu            a5,      t4,      9f
+
+    // refill
+    ld.d            t0,      a0,      0    // buf_pos
+    ld.d            t1,      a0,      8    // buf_end
+    addi.d          t2,      t0,      8
+    bltu            t1,      t2,      2f
+
+    ld.d            t3,      t0,      0    // next_bits
+    addi.w          t1,      t7,      -48  // shift_bits = cnt + 16 (- 64)
+    nor             t3,      t3,      t3
+    sub.w           t2,      zero,    t1
+    revb.d          t3,      t3            // next_bits = bswap(next_bits)
+    srli.w          t2,      t2,      3    // num_bytes_read
+    srl.d           t3,      t3,      t1   // next_bits >>= (shift_bits & 63)
+    b               3f
+1:
+    addi.w          t3,      t7,      -48
+    srl.d           t3,      t3,      t3   // pad with ones
+    b               4f
+2:
+    bgeu            t0,      t1,      1b
+    ld.d            t3,      t1,      -8   // next_bits
+    sub.w           t2,      t2,      t1
+    sub.w           t1,      t1,      t0   // num_bytes_left
+    slli.w          t2,      t2,      3
+    srl.d           t3,      t3,      t2
+    addi.w          t2,      t7,      -48
+    nor             t3,      t3,      t3
+    sub.w           t4,      zero,    t2
+    revb.d          t3,      t3
+    srli.w          t4,      t4,      3
+    srl.d           t3,      t3,      t2
+    sltu            t2,      t1,      t4
+    maskeqz         t1,      t1,      t2
+    masknez         t2,      t4,      t2
+    or              t2,      t2,      t1   // num_bytes_read
+3:
+    slli.w          t1,      t2,      3
+    add.d           t0,      t0,      t2
+    add.w           t7,      t7,      t1   // cnt += num_bits_read
+    st.d            t0,      a0,      0
+4:
+    or              t6,      t6,      t3   // dif |= next_bits
+9:
+    st.w            t7,      a0,      28   // store cnt
+    st.d            t6,      a0,      16   // store dif
+    move            a0,      t8
+endfunc
+
+.macro HI_TOK allow_update_cdf
+.\allow_update_cdf\()_hi_tok_lsx_start:
+.if \allow_update_cdf == 1
+    ld.hu        a4,    a1,    0x06 // cdf[3]
+.endif
+    vor.v        vr1,   vr0,   vr0
+    vsrli.h      vr1,   vr1,   0x06 // cdf[val] >> EC_PROB_SHIFT
+    vstelm.h     vr2,   sp,    0, 0 // -0x1a
+    vand.v       vr2,   vr2,   vr4  // (8 x rng) & 0xff00
+    vslli.h      vr1,   vr1,   0x07
+    vmuh.hu      vr1,   vr1,   vr2
+    vadd.h       vr1,   vr1,   vr5 // v += EC_MIN_PROB/* 4 */ * ((unsigned)n_symbols/* 3 */ - val);
+    vst          vr1,   sp,    0x02 // -0x18
+    vssub.hu     vr1,   vr1,   vr3 // v - c
+    vseqi.h      vr1,   vr1,   0
+.if \allow_update_cdf == 1
+    addi.d       t4,    a4,    0x50
+    srli.d       t4,    t4,    0x04
+    sltui        t7,    a4,    32
+    add.w        a4,    a4,    t7
+
+    vreplgr2vr.h vr7,   t4
+    vavgr.hu     vr9,   vr8,   vr1
+    vsub.h       vr9,   vr9,   vr0
+    vsub.h       vr0,   vr0,   vr1
+    vsra.h       vr9,   vr9,   vr7
+    vadd.h       vr0,   vr0,   vr9
+    vstelm.d     vr0,   a1,    0,  0
+    st.h         a4,    a1,    0x06
+.endif
+    vmsknz.b     vr7,   vr1
+    movfr2gr.s   t4,    f7
+    ctz.w        t4,    t4 // loop_times * 2
+    addi.d       t7,    t4,    2
+    ldx.hu       t6,    sp,    t4  // u
+    ldx.hu       t5,    sp,    t7  // v
+    addi.w       t3,    t3,    0x05
+    addi.w       t4,    t4,   -0x05 // if t4 == 3, continue
+    sub.w        t6,    t6,    t5   // u - v , rng for ctx_norm
+    slli.d       t5,    t5,    0x30 //  (ec_win)v << (EC_WIN_SIZE - 16)
+    sub.d        t1,    t1,    t5   //  s->dif - ((ec_win)v << (EC_WIN_SIZE - 16))
+    // Init ctx_norm  param
+    clz.w        t7,    t6
+    xori         t7,    t7,    0x1f
+    xori         t7,    t7,    0x0f //  d = 15 ^ (31 ^ clz(rng));
+    sll.d        t1,    t1,    t7   //  dif << d
+    sll.d        t6,    t6,    t7   //  rng << d
+    // update vr2 8 x rng
+    vreplgr2vr.h vr2,   t6
+    vreplvei.h   vr2,   vr2,   0
+    st.w         t6,    a0,    0x18 // store rng
+    move         t0,    t2
+    sub.w        t2,    t2,    t7   // cnt - d
+    bgeu         t0,    t7,    .\allow_update_cdf\()_hi_tok_lsx_ctx_norm_end     // if ((unsigned)cnt < (unsigned)d)  goto ctx_norm_end
+    // Step into ctx_fill
+    ld.d         t5,    a0,    0x00 // buf_pos
+    ld.d         t6,    a0,    0x08 // end_pos
+    addi.d       t7,    t5,    0x08 // buf_pos + 8
+    sub.d        t7,    t7,    t6   // (buf_pos + 8) - end_pos
+    blt          zero,  t7,    .\allow_update_cdf\()_hi_tok_lsx_ctx_refill_eob
+    // (end_pos - buf_pos) >= 8
+    ld.d         t6,    t5,    0x00 // load buf_pos[0]~buf_pos[7]
+    addi.w       t7,    t2,   -0x30 // cnt - 0x30
+    nor          t6,    t6,    t6   // not buf data
+    revb.d       t6,    t6          // Byte reversal
+    srl.d        t6,    t6,    t7   // Replace left shift with right shift
+    sub.w        t7,    zero,  t7   // neg
+    srli.w       t7,    t7,    0x03 // Loop times
+    or           t1,    t1,    t6   // dif |= (ec_win)(*buf_pos++ ^ 0xff) << c
+    b            .\allow_update_cdf\()_hi_tok_lsx_ctx_refill_end
+.\allow_update_cdf\()_hi_tok_lsx_ctx_refill_eob:
+    bge          t5,    t6,    .\allow_update_cdf\()_hi_tok_lsx_ctx_refill_one
+    // end_pos - buf_pos < 8 && buf_pos < end_pos
+    ld.d         t0,    t6,   -0x08
+    slli.d       t7,    t7,    0x03
+    srl.d        t6,    t0,    t7   // Retrieve the buf data and remove the excess data
+    addi.w       t7,    t2,   -0x30 // cnt - 0x30
+    nor          t6,    t6,    t6   // not
+    revb.d       t6,    t6          // Byte reversal
+    srl.d        t6,    t6,    t7   // Replace left shift with right shift
+    sub.w        t7,    zero,  t7   // neg
+    or           t1,    t1,    t6   // dif |= (ec_win)(*buf_pos++ ^ 0xff) << c
+    ld.d         t6,    a0,    0x08 // end_pos
+    srli.w       t7,    t7,    0x03 // Loop times
+    sub.d        t6,    t6,    t5   // end_pos - buf_pos
+    slt          t0,    t6,    t7
+    maskeqz      a3,    t6,    t0   // min(loop_times, end_pos - buf_pos)
+    masknez      t0,    t7,    t0
+    or           t7,    a3,    t0
+    b            .\allow_update_cdf\()_hi_tok_lsx_ctx_refill_end
+.\allow_update_cdf\()_hi_tok_lsx_ctx_refill_one:
+    // buf_pos >= end_pos
+    addi.w       t7,    t2,   -0x10
+    andi         t7,    t7,    0xf
+    nor          t0,    zero,  zero
+    srl.d        t0,    t0,    t7
+    or           t1,    t1,    t0 // dif |= ~(~(ec_win)0xff << c);
+    b            .\allow_update_cdf\()_hi_tok_lsx_ctx_norm_end
+.\allow_update_cdf\()_hi_tok_lsx_ctx_refill_end:
+    add.d        t5,    t5,    t7        // buf_pos + Loop_times
+    st.d         t5,    a0,    0x00      // Store buf_pos
+    alsl.w       t2,    t7,    t2,  0x03 // update cnt
+.\allow_update_cdf\()_hi_tok_lsx_ctx_norm_end:
+    srli.d       t7,    t1,    0x30
+    vreplgr2vr.h vr3,   t7        // broadcast the high 16 bits of dif
+    add.w        t3,    t4,    t3 // update control parameter
+    beqz         t3,    .\allow_update_cdf\()_hi_tok_lsx_end // control loop for at most 4 times.
+    blt          zero,  t4,    .\allow_update_cdf\()_hi_tok_lsx_start // tok_br == 3
+.\allow_update_cdf\()_hi_tok_lsx_end:
+    addi.d       t3,    t3,    0x1e
+    st.d         t1,    a0,    0x10 // store dif
+    st.w         t2,    a0,    0x1c // store cnt
+    srli.w       a0,    t3,    0x01 // tok
+    addi.d       sp,    sp,    0x1a
+.endm
+
+/**
+ * @param unsigned dav1d_msac_decode_hi_tok_c(MsacContext *const s, uint16_t *const cdf)
+ * * Reg Alloction
+ * * vr0: cdf;
+ * * vr1: temp;
+ * * vr2: rng;
+ * * vr3: dif;
+ * * vr4: const 0xff00ff00...ff00ff00;
+ * * vr5: const 0x0004080c;
+ * * vr6: const 0;
+ * * t0: allow_update_cdf, tmp;
+ * * t1: dif;
+ * * t2: cnt;
+ * * t3: 0xffffffe8, outermost control parameter;
+ * * t4: loop time
+ * * t5: v, buf_pos, temp;
+ * * t6: u, rng, end_pos, buf, temp;
+ * * t7: temp;
+ */
+function msac_decode_hi_tok_lsx
+    fld.d     f0,    a1,   0    // Load cdf[0]~cdf[3]
+    vldrepl.h vr2,   a0,   0x18 //  8 x rng, assert(rng <= 65535U), only the lower 16 bits are valid
+    vldrepl.h vr3,   a0,   0x16 // broadcast the high 16 bits of dif, c = s->dif >> (EC_WIN_SIZE - 16)
+    ld.w      t0,    a0,   0x20 // allow_update_cdf
+    la.local  t7,    ph_0xff00
+    vld       vr4,   t7,   0x00 // 0xff00ff00...ff00ff00
+    la.local  t7,    min_prob
+    vld       vr5,   t7,   12 * 2 // 0x0004080c
+    vxor.v    vr6,   vr6,  vr6    // const 0
+    ld.d      t1,    a0,   0x10   // dif
+    ld.w      t2,    a0,   0x1c   // cnt
+    orn       t3,    t3,   t3
+    srli.d    t3,    t3,   32
+    addi.d    t3,    t3,  -0x17 // 0xffffffe8
+    vseq.h    vr8,   vr8,  vr8
+    addi.d    sp,    sp,  -0x1a // alloc stack
+    beqz      t0,    .hi_tok_lsx_no_update_cdf
+    HI_TOK 1
+    jirl      zero,  ra,   0x0
+.hi_tok_lsx_no_update_cdf:
+    HI_TOK 0
+endfunc
diff --git a/media/libdav1d/src/src/loongarch/msac.h b/media/libdav1d/src/src/loongarch/msac.h
new file mode 100644
index 0000000000..146557c116
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/msac.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_MSAC_H
+#define DAV1D_SRC_LOONGARCH_MSAC_H
+
+unsigned dav1d_msac_decode_symbol_adapt4_lsx(MsacContext *s, uint16_t *cdf,
+                                              size_t n_symbols);
+unsigned dav1d_msac_decode_symbol_adapt8_lsx(MsacContext *s, uint16_t *cdf,
+                                              size_t n_symbols);
+unsigned dav1d_msac_decode_symbol_adapt16_lsx(MsacContext *s, uint16_t *cdf,
+                                               size_t n_symbols);
+unsigned dav1d_msac_decode_bool_adapt_lsx(MsacContext *s, uint16_t *cdf);
+unsigned dav1d_msac_decode_bool_lsx(MsacContext *s, unsigned f);
+unsigned dav1d_msac_decode_bool_equi_lsx(MsacContext *s);
+unsigned dav1d_msac_decode_hi_tok_lsx(MsacContext *s, uint16_t *cdf);
+
+#define dav1d_msac_decode_symbol_adapt4  dav1d_msac_decode_symbol_adapt4_lsx
+#define dav1d_msac_decode_symbol_adapt8  dav1d_msac_decode_symbol_adapt8_lsx
+#define dav1d_msac_decode_symbol_adapt16 dav1d_msac_decode_symbol_adapt16_lsx
+#define dav1d_msac_decode_bool_adapt     dav1d_msac_decode_bool_adapt_lsx
+#define dav1d_msac_decode_bool           dav1d_msac_decode_bool_lsx
+#define dav1d_msac_decode_bool_equi      dav1d_msac_decode_bool_equi_lsx
+#define dav1d_msac_decode_hi_tok         dav1d_msac_decode_hi_tok_lsx
+
+#endif /* DAV1D_SRC_LOONGARCH_MSAC_H */
diff --git a/media/libdav1d/src/src/loongarch/refmvs.S b/media/libdav1d/src/src/loongarch/refmvs.S
new file mode 100644
index 0000000000..c1463fd560
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/refmvs.S
@@ -0,0 +1,701 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/loongarch/loongson_asm.S"
+
+/*
+static void splat_mv_c(refmvs_block **rr, const refmvs_block *const rmv,
+                       const int bx4, const int bw4, int bh4)
+*/
+
+function splat_mv_lsx
+    vld           vr0,      a1,       0          // 0 1 ... 11 ...
+    clz.w         t4,       a3
+    vaddi.bu      vr1,      vr0,      0
+    addi.w        t4,       t4,       -26
+    vextrins.w    vr1,      vr0,      0x30       // 0 1 2 ... 11 0 1 2 3
+    la.local      t5,       .SPLAT_LSX_JRTABLE
+    vbsrl.v       vr2,      vr1,      4          // 4 5 6 7...11 0 1 2 3 0 0 0 0
+    alsl.d        t6,       t4,       t5,     1
+    vextrins.w    vr2,      vr0,      0x31       // 4 5 6 7...11 0 1 2 3 4 5 6 7
+    ld.h          t7,       t6,       0
+    vbsrl.v       vr3,      vr2,      4          // 8 9 10 11 0 1 2 3 4 5 6 7 0 0 0 0
+    add.d         t8,       t5,       t7
+    alsl.d        a2,       a2,       a2,     1
+    vextrins.w    vr3,      vr0,      0x32       // 8 9 10 11 0 1 2 3 4 5 6 7 8 9 10 11
+    slli.w        a2,       a2,       2
+    jirl          $r0,      t8,       0
+
+.SPLAT_LSX_JRTABLE:
+    .hword .SPLAT_W32_LSX - .SPLAT_LSX_JRTABLE
+    .hword .SPLAT_W16_LSX - .SPLAT_LSX_JRTABLE
+    .hword .SPLAT_W8_LSX  - .SPLAT_LSX_JRTABLE
+    .hword .SPLAT_W4_LSX  - .SPLAT_LSX_JRTABLE
+    .hword .SPLAT_W2_LSX  - .SPLAT_LSX_JRTABLE
+    .hword .SPLAT_W1_LSX  - .SPLAT_LSX_JRTABLE
+
+.SPLAT_W1_LSX:
+    ld.d          t3,       a0,       0
+    addi.d        a0,       a0,       8
+    addi.d        a4,       a4,       -1
+    add.d         t3,       t3,       a2
+
+    fst.d         f1,       t3,       0
+    fst.s         f3,       t3,       8
+    blt           zero,     a4,       .SPLAT_W1_LSX
+    b             .splat_end
+.SPLAT_W2_LSX:
+    ld.d          t3,       a0,       0
+    addi.d        a0,       a0,       8
+    addi.d        a4,       a4,       -1
+    add.d         t3,       t3,       a2
+
+    vst           vr1,      t3,       0
+    fst.d         f2,       t3,       16
+    blt           zero,     a4,       .SPLAT_W2_LSX
+    b             .splat_end
+
+.SPLAT_W4_LSX:
+    ld.d          t3,       a0,       0
+    addi.d        a0,       a0,       8
+    addi.d        a4,       a4,       -1
+    add.d         t3,       t3,       a2
+
+    vst           vr1,      t3,       0
+    vst           vr2,      t3,       16
+    vst           vr3,      t3,       32
+    blt           zero,     a4,       .SPLAT_W4_LSX
+    b             .splat_end
+
+.SPLAT_W8_LSX:
+    ld.d          t3,       a0,       0
+    addi.d        a0,       a0,       8
+    addi.d        a4,       a4,       -1
+    add.d         t3,       t3,       a2
+
+    vst           vr1,      t3,       0
+    vst           vr2,      t3,       16
+    vst           vr3,      t3,       32
+
+    vst           vr1,      t3,       48
+    vst           vr2,      t3,       64
+    vst           vr3,      t3,       80
+    blt           zero,     a4,       .SPLAT_W8_LSX
+    b             .splat_end
+
+.SPLAT_W16_LSX:
+    ld.d          t3,       a0,       0
+    addi.d        a0,       a0,       8
+    addi.d        a4,       a4,       -1
+    add.d         t3,       t3,       a2
+
+.rept 2
+    vst           vr1,      t3,       0
+    vst           vr2,      t3,       16
+    vst           vr3,      t3,       32
+
+    vst           vr1,      t3,       48
+    vst           vr2,      t3,       64
+    vst           vr3,      t3,       80
+
+    addi.d        t3,       t3,       96
+.endr
+
+    blt           zero,     a4,       .SPLAT_W16_LSX
+    b             .splat_end
+
+.SPLAT_W32_LSX:
+    ld.d          t3,       a0,       0
+    addi.d        a0,       a0,       8
+    addi.d        a4,       a4,       -1
+    add.d         t3,       t3,       a2
+
+.rept 4
+    vst           vr1,      t3,       0
+    vst           vr2,      t3,       16
+    vst           vr3,      t3,       32
+
+    vst           vr1,      t3,       48
+    vst           vr2,      t3,       64
+    vst           vr3,      t3,       80
+
+    addi.d        t3,       t3,       96
+.endr
+
+    blt           zero,     a4,       .SPLAT_W32_LSX
+
+.splat_end:
+endfunc
+
+const la_div_mult
+.short    0, 16384, 8192, 5461, 4096, 3276, 2730, 2340
+.short 2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092
+.short 1024,   963,  910,  862,  819,  780,  744,  712
+.short  682,   655,  630,  606,  585,  564,  546,  528
+endconst
+
+/*
+ *  temp reg: a6 a7
+ */
+.macro LOAD_SET_LOOP is_odd
+    slli.d          a6,      t6,     2
+    add.d           a6,      a6,     t6  // col_w * 5
+0:
+    addi.d          a7,      zero,   0   // x
+.if \is_odd
+    stx.w           t7,      t3,     a7
+    addi.d          a7,      a7,     5
+    bge             a7,      a6,     2f
+.endif
+
+1:
+    stx.w           t7,      t3,     a7
+    addi.d          a7,      a7,     5
+    stx.w           t7,      t3,     a7
+    addi.d          a7,      a7,     5
+    blt             a7,      a6,     1b
+2:
+    add.d           t3,      t3,     t2
+    addi.d          t5,      t5,     1
+    blt             t5,      a5,     0b
+.endm
+
+/*
+ * static void load_tmvs_c(const refmvs_frame *const rf, int tile_row_idx,
+ *                         const int col_start8, const int col_end8,
+ *                         const int row_start8, int row_end8)
+ */
+function load_tmvs_lsx
+    addi.d         sp,      sp,       -80
+    st.d           s0,      sp,       0
+    st.d           s1,      sp,       8
+    st.d           s2,      sp,       16
+    st.d           s3,      sp,       24
+    st.d           s4,      sp,       32
+    st.d           s5,      sp,       40
+    st.d           s6,      sp,       48
+    st.d           s7,      sp,       56
+    st.d           s8,      sp,       64
+
+    vld           vr16,     a0,       16
+    vld           vr0,      a0,       48    // rf->mfmv_ref, rf->mfmv_ref2cur
+    ld.w          s8,       a0,       80    // [0] - rf->n_mfmvs
+    vld           vr17,     a0,       96    // [0] - rp_ref| [1]- rp_proj
+    ld.d          t1,       a0,       112   // stride
+    ld.w          t0,       a0,       128
+    addi.w        t0,       t0,       -1
+    bnez          t0,       1f
+    addi.w        a1,       zero,     0
+1:
+    addi.d        t0,       a3,       8
+    vinsgr2vr.w   vr1,      t0,       0
+    vinsgr2vr.w   vr1,      a5,       1
+    vmin.w        vr1,      vr1,      vr16  // [0] col_end8i [1] row_end8
+    addi.d        t0,       a2,       -8
+    bge           t0,       zero,     2f
+    addi.w        t0,       zero,     0     // t0 col_start8i
+2:
+    vpickve2gr.d  t4,       vr17,     1     // rf->rp_proj
+    slli.d        t2,       t1,       2
+    add.d         t2,       t2,       t1    // stride * 5
+    slli.d        a1,       a1,       4     // tile_row_idx * 16
+    andi          t3,       a4,       0xf
+    add.d         t3,       t3,       a1    // tile_row_idx * 16 + row_start8 & 15
+    mul.w         t3,       t3,       t2
+    mul.w         t8,       a1,       t2
+    vpickve2gr.w  a5,       vr1,      1
+    addi.d        t5,       a4,       0
+    sub.d         t6,       a3,       a2     // col_end8 - col_start8
+    li.w          t7,       0x80008000
+    slli.d        a7,       a2,       2
+    add.d         t3,       t3,       a2
+    add.d         t3,       t3,       a7
+    add.d         t3,       t3,       t4     // rp_proj
+    andi          a6,       t6,       1
+    bnez          a6,       3f
+    LOAD_SET_LOOP 0
+    b             4f
+3:
+    LOAD_SET_LOOP 1
+4:
+    addi.d        a6,       zero,     0      // n
+    bge           a6,       s8,       .end_load
+    add.d         t3,       t8,       t4     // rp_proj
+    mul.w         t6,       a4,       t2
+    addi.d        s7,       zero,     40
+    vpickve2gr.w  t1,       vr1,      0      // col_end8i
+    addi.d        t5,       a0,       58     // rf->mfmv_ref2ref - 1
+    la.local      t8,       la_div_mult
+    vld           vr6,      t8,       0
+    vld           vr7,      t8,       16
+    vld           vr8,      t8,       32
+    vld           vr9,      t8,       48
+    li.w          t8,       0x3fff
+    vreplgr2vr.h  vr21,     t8
+    vxor.v        vr18,     vr18,     vr18   // zero
+    vsub.h        vr20,     vr18,     vr21
+    vpickev.b     vr12,     vr7,      vr6
+    vpickod.b     vr13,     vr7,      vr6
+    vpickev.b     vr14,     vr9,      vr8
+    vpickod.b     vr15,     vr9,      vr8
+    vpickve2gr.d  s6,       vr17,     0       // rf->rp_ref
+5:
+    vld           vr10,     t5,       0       // ref2ref [1...7]
+    vpickve2gr.b  t8,       vr0,      8       // ref2cur
+    vbsrl.v       vr0,      vr0,      1
+    addi.w        t4,       t8,       32
+    beqz          t4,       8f                // INVALID_REF2CUR
+
+    vreplgr2vr.h  vr23,     t8
+    vshuf.b       vr6,      vr14,     vr12,    vr10
+    vshuf.b       vr7,      vr15,     vr13,    vr10
+    vilvl.b       vr8,      vr7,      vr6
+    vmulwev.w.h   vr6,      vr8,      vr23
+    vmulwod.w.h   vr7,      vr8,      vr23
+
+    vpickve2gr.b  s0,       vr0,      4       // ref
+    slli.d        t8,       s0,       3
+    ldx.d         s1,       s6,       t8      // rf->rp_ref[ref]
+    addi.d        s0,       s0,       -4      // ref_sign
+    vreplgr2vr.h  vr19,     s0
+    add.d         s1,       s1,       t6      // &rf->rp_ref[ref][row_start8 * stride]
+    addi.d        s2,       a4,       0       // y
+    vilvl.w       vr8,      vr7,      vr6
+    vilvh.w       vr9,      vr7,      vr6
+6:                                            // for (int y = row_start8;
+    andi          s3,       s2,       0xff8
+
+    addi.d        s4,       s3,       8
+    blt           a4,       s3,       0f
+    addi.d        s3,       a4,       0        // y_proj_start
+0:
+    blt           s4,       a5,       0f
+    addi.d        s4,       a5,       0        // y_proj_end
+0:
+    addi.d        s5,       t0,       0        // x
+7:                                             // for (int x = col_start8i;
+    slli.d        a7,       s5,       2
+    add.d         a7,       a7,       s5
+    add.d         a7,       s1,       a7      // rb
+    vld           vr3,      a7,       0       // [rb]
+    vpickve2gr.b  t4,       vr3,      4       // b_ref
+    beqz          t4,       .end_x
+    vreplve.b     vr11,     vr10,     t4
+    vpickve2gr.b  t7,       vr11,     4       // ref2ref
+    beqz          t7,       .end_x
+    vsllwil.w.h   vr4,      vr3,      0
+    vreplgr2vr.w  vr6,      t4
+    vshuf.w       vr6,      vr9,      vr8      // frac
+    vmul.w        vr5,      vr6,      vr4
+    vsrai.w       vr4,      vr5,      31
+    vadd.w        vr4,      vr4,      vr5
+    vssrarni.h.w  vr4,      vr4,      14
+    vclip.h       vr4,      vr4,      vr20,    vr21  // offset
+    vxor.v        vr5,      vr4,      vr19    // offset.x ^ ref_sign
+    vori.b        vr5,      vr5,      0x1     // offset.x ^ ref_sign
+    vabsd.h       vr4,      vr4,      vr18
+    vsrli.h       vr4,      vr4,      6       // abs(offset.x) >> 6
+    vsigncov.h    vr4,      vr5,      vr4     // apply_sign
+    vpickve2gr.h  s0,       vr4,      0
+    add.d         s0,       s2,       s0      // pos_y
+    blt           s0,       s3,       .n_posy
+    bge           s0,       s4,       .n_posy
+    andi          s0,       s0,       0xf
+    mul.w         s0,       s0,       t2      // pos
+    vpickve2gr.h  t7,       vr4,      1
+    add.d         t7,       t7,       s5      // pos_x
+    add.d         s0,       t3,       s0      // rp_proj + pos
+
+.loop_posx:
+    andi          t4,       s5,       0xff8 // x_sb_align
+
+    blt           t7,       a2,       .n_posx
+    addi.d        t8,       t4,       -8
+    blt           t7,       t8,       .n_posx
+
+    bge           t7,       a3,       .n_posx
+    addi.d        t4,       t4,       16
+    bge           t7,       t4,       .n_posx
+
+    slli.d        t4,       t7,       2
+    add.d         t4,       t4,       t7      // pos_x * 5
+    add.d         t4,       s0,       t4      // rp_proj[pos + pos_x]
+    vstelm.w      vr3,      t4,       0,   0
+    vstelm.b      vr11,     t4,       4,   4
+
+.n_posx:
+    addi.d        s5,       s5,       1       // x + 1
+    bge           s5,       t1,       .ret_posx
+    addi.d        a7,       a7,       5       // rb + 1
+    vld           vr4,      a7,       0       // [rb]
+    vseq.b        vr5,      vr4,      vr3
+
+    vpickve2gr.d  t8,       vr5,      0
+    cto.d         t8,       t8
+    blt           t8,       s7,       7b
+
+    addi.d        t7,       t7,       1       // pos_x + 1
+
+    /*  Core computing loop expansion(sencond)  */
+    andi          t4,       s5,       0xff8 // x_sb_align
+
+    blt           t7,       a2,       .n_posx
+    addi.d        t8,       t4,       -8
+    blt           t7,       t8,       .n_posx
+
+    bge           t7,       a3,       .n_posx
+    addi.d        t4,       t4,       16
+    bge           t7,       t4,       .n_posx
+
+    slli.d        t4,       t7,       2
+    add.d         t4,       t4,       t7      // pos_x * 5
+    add.d         t4,       s0,       t4      // rp_proj[pos + pos_x]
+    vstelm.w      vr3,      t4,       0,   0
+    vstelm.b      vr11,     t4,       4,   4
+
+    addi.d        s5,       s5,       1       // x + 1
+    bge           s5,       t1,       .ret_posx
+    addi.d        a7,       a7,       5       // rb + 1
+    vld           vr4,      a7,       0       // [rb]
+    vseq.b        vr5,      vr4,      vr3
+
+    vpickve2gr.d  t8,       vr5,      0
+    cto.d         t8,       t8
+    blt           t8,       s7,       7b
+
+    addi.d        t7,       t7,       1       // pos_x + 1
+
+    /*  Core computing loop expansion(third)  */
+    andi          t4,       s5,       0xff8 // x_sb_align
+
+    blt           t7,       a2,       .n_posx
+    addi.d        t8,       t4,       -8
+    blt           t7,       t8,       .n_posx
+
+    bge           t7,       a3,       .n_posx
+    addi.d        t4,       t4,       16
+    bge           t7,       t4,       .n_posx
+
+    slli.d        t4,       t7,       2
+    add.d         t4,       t4,       t7      // pos_x * 5
+    add.d         t4,       s0,       t4      // rp_proj[pos + pos_x]
+    vstelm.w      vr3,      t4,       0,   0
+    vstelm.b      vr11,     t4,       4,   4
+
+    addi.d        s5,       s5,       1       // x + 1
+    bge           s5,       t1,       .ret_posx
+    addi.d        a7,       a7,       5       // rb + 1
+    vld           vr4,      a7,       0       // [rb]
+    vseq.b        vr5,      vr4,      vr3
+
+    vpickve2gr.d  t8,       vr5,      0
+    cto.d         t8,       t8
+    blt           t8,       s7,       7b
+
+    addi.d        t7,       t7,       1       // pos_x + 1
+
+    b             .loop_posx
+
+.n_posy:
+    addi.d        s5,       s5,       1       // x + 1
+    bge           s5,       t1,       .ret_posx
+    addi.d        a7,       a7,       5       // rb + 1
+    vld           vr4,      a7,       0       // [rb]
+    vseq.b        vr5,      vr4,      vr3
+
+    vpickve2gr.d  t8,       vr5,      0
+    cto.d         t8,       t8
+    blt           t8,       s7,       7b
+
+    addi.d        s5,       s5,       1       // x + 1
+    bge           s5,       t1,       .ret_posx
+    addi.d        a7,       a7,       5       // rb + 1
+    vld           vr4,      a7,       0       // [rb]
+    vseq.b        vr5,      vr4,      vr3
+
+    vpickve2gr.d  t8,       vr5,      0
+    cto.d         t8,       t8
+    blt           t8,       s7,       7b
+
+    b             .n_posy
+
+.end_x:
+    addi.d        s5,       s5,       1       // x + 1
+    blt           s5,       t1,       7b
+
+.ret_posx:
+    add.d         s1,       s1,       t2      // r + stride
+    addi.d        s2,       s2,       1       // y + 1
+    blt           s2,       a5,       6b
+8:
+    addi.d        a6,       a6,       1       // n + 1
+    addi.d        t5,       t5,       7       // mfmv_ref2ref(offset) + 7
+    blt           a6,       s8,       5b
+
+.end_load:
+    ld.d           s0,      sp,       0
+    ld.d           s1,      sp,       8
+    ld.d           s2,      sp,       16
+    ld.d           s3,      sp,       24
+    ld.d           s4,      sp,       32
+    ld.d           s5,      sp,       40
+    ld.d           s6,      sp,       48
+    ld.d           s7,      sp,       56
+    ld.d           s8,      sp,       64
+    addi.d         sp,      sp,       80
+endfunc
+
+const mv_tbls
+    .byte           255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+    .byte           0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0
+    .byte           4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
+    .byte           4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
+endconst
+
+const mask_mult
+    .byte           1, 0, 2, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0
+endconst
+
+const mask_mv0
+    .byte           1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
+endconst
+
+const mask_mv1
+    .byte           4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
+endconst
+
+// void dav1d_save_tmvs_lsx(refmvs_temporal_block *rp, ptrdiff_t stride,
+//                          refmvs_block **rr, const uint8_t *ref_sign,
+//                          int col_end8, int row_end8,
+//                          int col_start8, int row_start8)
+function save_tmvs_lsx
+    addi.d      sp,         sp,        -0x28
+    st.d        s0,         sp,         0x00
+    st.d        s1,         sp,         0x08
+    st.d        s2,         sp,         0x10
+    st.d        s3,         sp,         0x18
+    st.d        s4,         sp,         0x20
+    move        t0,         ra
+
+    vxor.v      vr10,       vr10,       vr10
+    vld         vr11,       a3,         0       // Load ref_sign[0] ~ Load ref_sign[7]
+    la.local    t2,         .save_tevs_tbl
+    la.local    s1,         mask_mult
+    la.local    t7,         mv_tbls
+    vld         vr9,        s1,         0       // Load mask_mult
+    vslli.d     vr11,       vr11,       8       // 0, ref_sign[0], ... ,ref_sign[6]
+    la.local    s3,         mask_mv0
+    vld         vr8,        s3,         0       // Load mask_mv0
+    la.local    s4,         mask_mv1
+    vld         vr7,        s4,         0       // Load mask_mv1
+    li.d        s0,         5
+    li.d        t8,         12 * 2
+    mul.d       a1,         a1,         s0     // stride *= 5
+    sub.d       a5,         a5,         a7      // h = row_end8 - row_start8
+    slli.d      a7,         a7,         1       // row_start8 <<= 1
+1:
+    li.d        s0,         5
+    andi        t3,         a7,         30      // (y & 15) * 2
+    slli.d      s4,         t3,         3
+    ldx.d       t3,         a2,         s4      // b = rr[(y & 15) * 2]
+    addi.d      t3,         t3,         12      // &b[... + 1]
+    mul.d       s4,         a4,         t8
+    add.d       t4,         s4,         t3      // end_cand_b = &b[col_end8*2 + 1]
+    mul.d       s3,         a6,         t8
+    add.d       t3,         s3,         t3      // cand_b = &b[x*2 + 1]
+    mul.d       s4,         a6,         s0
+    add.d       a3,         s4,         a0      // &rp[x]
+2:
+    /* First cand_b */
+    ld.b        t5,         t3,         10      // cand_b->bs
+    vld         vr0,        t3,         0       // cand_b->mv and ref
+    alsl.d      t5,         t5,         t2,     2  // bt2 index
+    ld.h        s3,         t3,         8       // cand_b->ref
+    ld.h        t6,         t5,         0       // bt2
+    move        s0,         t2
+    alsl.d      t3,         t6,         t3,     1   // Next cand_b += bt2 * 2
+    vor.v       vr2,        vr0,        vr0
+    vinsgr2vr.h vr1,        s3,         0
+    move        t1 ,        t3
+    bge         t3,         t4,        3f
+
+    /* Next cand_b */
+    ld.b        s0,         t3,         10      // cand_b->bs
+    vld         vr4,        t3,         0       // cand_b->mv and ref
+    alsl.d      s0,         s0,         t2,     2 // bt2 index
+    ld.h        s4,         t3,         8       // cand_b->ref
+    ld.h        t6,         s0,         0       // bt2
+    alsl.d      t3,         t6,         t3,     1   // Next cand_b += bt2*2
+    vpackev.d   vr2,        vr4,        vr0     // a0.mv[0] a0.mv[1] a1.mv[0], a1.mv[1]
+    vinsgr2vr.h vr1,        s4,         1   // a0.ref[0] a0.ref[1], a1.ref[0], a1.ref[1]
+3:
+    vabsd.h     vr2,        vr2,        vr10    // abs(mv[].xy)
+    vsle.b      vr16,       vr10,       vr1
+    vand.v      vr1,        vr16,       vr1
+    vshuf.b     vr1,        vr11,       vr11,   vr1     // ref_sign[ref]
+    vsrli.h     vr2,        vr2,        12      // abs(mv[].xy) >> 12
+    vilvl.b     vr1,        vr1,        vr1
+    vmulwev.h.bu    vr1,    vr1,        vr9    // ef_sign[ref] * {1, 2}
+
+    vseqi.w     vr2,        vr2,        0       // abs(mv[].xy) <= 4096
+    vpickev.h   vr2,        vr2,        vr2     // abs() condition to 16 bit
+
+    vand.v      vr1,        vr2,        vr1     // h[0-3] contains conditions for mv[0-1]
+    vhaddw.wu.hu    vr1,    vr1,        vr1     // Combine condition for [1] and [0]
+    vpickve2gr.wu   s1,     vr1,        0       // Extract case for first block
+    vpickve2gr.wu   s2,     vr1,        1
+
+    ld.hu           t5,     t5,         2       // Fetch jump table entry
+    ld.hu           s0,     s0,         2
+    alsl.d          s3,     s1,         t7,    4   // Load permutation table base on case
+    vld             vr1,    s3,         0
+    alsl.d          s4,     s2,         t7,    4
+    vld             vr5,    s4,         0
+    sub.d           t5,     t2,         t5     // Find jump table target
+    sub.d           s0,     t2,         s0
+
+    vshuf.b         vr0,    vr0,        vr0,    vr1 // Permute cand_b to output refmvs_temporal_block
+    vshuf.b         vr4,    vr4,        vr4,    vr5
+    vsle.b          vr16,   vr10,       vr1
+    vand.v          vr0,    vr16,       vr0
+
+    vsle.b          vr17,   vr10,       vr5
+    vand.v          vr4,    vr17,       vr4
+    // v1 follows on v0, with another 3 full repetitions of the pattern.
+    vshuf.b         vr1,    vr0,        vr0,    vr8 // 1, 2, 3, ... , 15, 16
+    vshuf.b         vr5,    vr4,        vr4,    vr8 // 1, 2, 3, ... , 15, 16
+    // v2 ends with 3 complete repetitions of the pattern.
+    vshuf.b         vr2,    vr1,        vr0,    vr7
+    vshuf.b         vr6,    vr5,        vr4,    vr7    // 4, 5, 6, 7, ... , 12, 13, 14, 15, 16, 17, 18, 19
+
+    jirl            ra,     t5,         0
+    bge             t1 ,    t4,         4f      // if (cand_b >= end)
+    vor.v           vr0,    vr4,        vr4
+    vor.v           vr1,    vr5,        vr5
+    vor.v           vr2,    vr6,        vr6
+    jirl            ra,     s0,         0
+    blt             t3,     t4,         2b      // if (cand_b < end)
+
+4:
+    addi.d          a5,     a5,         -1      // h--
+    addi.d          a7,     a7,         2       // y += 2
+    add.d           a0,     a0,         a1      // rp += stride
+    blt             zero,   a5,         1b
+
+    ld.d        s0,         sp,         0x00
+    ld.d        s1,         sp,         0x08
+    ld.d        s2,         sp,         0x10
+    ld.d        s3,         sp,         0x18
+    ld.d        s4,         sp,         0x20
+    addi.d      sp,         sp,         0x28
+
+    move            ra,     t0
+    jirl            zero,   ra,         0x00
+
+10:
+    addi.d          s1,     a3,         4
+    vstelm.w        vr0,    a3,         0,      0   // .mv
+    vstelm.b        vr0,    s1,         0,      4   // .ref
+    addi.d          a3,     a3,         5
+    jirl            zero,   ra,         0x00
+20:
+    addi.d          s1,     a3,         8
+    vstelm.d        vr0,    a3,         0,      0   // .mv
+    vstelm.h        vr0,    s1,         0,      4   // .ref
+    addi.d          a3,     a3,         2 * 5
+    jirl            zero,   ra,         0x00
+40:
+    vst             vr0,    a3,         0
+    vstelm.w        vr1,    a3,         0x10,   0
+    addi.d          a3,     a3,         4 * 5
+    jirl            zero,   ra,         0x00
+
+80:
+    vst             vr0,    a3,         0
+    vst             vr1,    a3,         0x10           // This writes 6 full entries plus 2 extra bytes
+    vst             vr2,    a3,         5 * 8 - 16     // Write the last few, overlapping with the first write.
+    addi.d          a3,     a3,         8 * 5
+    jirl            zero,   ra,         0x00
+160:
+    addi.d          s1,     a3,         6 * 5
+    addi.d          s2,     a3,         12 * 5
+    vst             vr0,    a3,         0
+    vst             vr1,    a3,         0x10          // This writes 6 full entries plus 2 extra bytes
+    vst             vr0,    a3,         6 * 5
+    vst             vr1,    a3,         6 * 5 + 16    // Write another 6 full entries, slightly overlapping with the first set
+    vstelm.d        vr0,    s2,         0,      0     // Write 8 bytes (one full entry) after the first 12
+    vst             vr2,    a3,         5 * 16 - 16   // Write the last 3 entries
+    addi.d          a3,     a3,         16 * 5
+    jirl            zero,   ra,         0x00
+
+.save_tevs_tbl:
+        .hword 16 * 12   // bt2 * 12, 12 is sizeof(refmvs_block)
+        .hword .save_tevs_tbl - 160b
+        .hword 16 * 12
+        .hword .save_tevs_tbl - 160b
+        .hword 8 * 12
+        .hword .save_tevs_tbl -  80b
+        .hword 8 * 12
+        .hword .save_tevs_tbl -  80b
+        .hword 8 * 12
+        .hword .save_tevs_tbl -  80b
+        .hword 8 * 12
+        .hword .save_tevs_tbl -  80b
+        .hword 4 * 12
+        .hword .save_tevs_tbl -  40b
+        .hword 4 * 12
+        .hword .save_tevs_tbl -  40b
+        .hword 4 * 12
+        .hword .save_tevs_tbl -  40b
+        .hword 4 * 12
+        .hword .save_tevs_tbl -  40b
+        .hword 2 * 12
+        .hword .save_tevs_tbl -  20b
+        .hword 2 * 12
+        .hword .save_tevs_tbl -  20b
+        .hword 2 * 12
+        .hword .save_tevs_tbl -  20b
+        .hword 2 * 12
+        .hword .save_tevs_tbl -  20b
+        .hword 2 * 12
+        .hword .save_tevs_tbl -  20b
+        .hword 1 * 12
+        .hword .save_tevs_tbl -  10b
+        .hword 1 * 12
+        .hword .save_tevs_tbl -  10b
+        .hword 1 * 12
+        .hword .save_tevs_tbl -  10b
+        .hword 1 * 12
+        .hword .save_tevs_tbl -  10b
+        .hword 1 * 12
+        .hword .save_tevs_tbl -  10b
+        .hword 1 * 12
+        .hword .save_tevs_tbl -  10b
+        .hword 1 * 12
+        .hword .save_tevs_tbl -  10b
+endfunc
+
diff --git a/media/libdav1d/src/src/loongarch/refmvs.h b/media/libdav1d/src/src/loongarch/refmvs.h
new file mode 100644
index 0000000000..f944f30501
--- /dev/null
+++ b/media/libdav1d/src/src/loongarch/refmvs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOONGARCH_REFMVS_H
+#define DAV1D_SRC_LOONGARCH_REFMVS_H
+
+#include "src/cpu.h"
+#include "src/refmvs.h"
+
+decl_splat_mv_fn(dav1d_splat_mv_lsx);
+decl_load_tmvs_fn(dav1d_load_tmvs_lsx);
+decl_save_tmvs_fn(dav1d_save_tmvs_lsx);
+
+static ALWAYS_INLINE void refmvs_dsp_init_loongarch(Dav1dRefmvsDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_LOONGARCH_CPU_FLAG_LSX)) return;
+
+    c->splat_mv = dav1d_splat_mv_lsx;
+    c->load_tmvs = dav1d_load_tmvs_lsx;
+    c->save_tmvs = dav1d_save_tmvs_lsx;
+}
+
+#endif /* DAV1D_SRC_LOONGARCH_REFMVS_H */
diff --git a/media/libdav1d/src/src/loopfilter.h b/media/libdav1d/src/src/loopfilter.h
new file mode 100644
index 0000000000..a0f78c9657
--- /dev/null
+++ b/media/libdav1d/src/src/loopfilter.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOOPFILTER_H
+#define DAV1D_SRC_LOOPFILTER_H
+
+#include 
+#include 
+
+#include "common/bitdepth.h"
+
+#include "src/levels.h"
+#include "src/lf_mask.h"
+
+#define decl_loopfilter_sb_fn(name) \
+void (name)(pixel *dst, ptrdiff_t stride, const uint32_t *mask, \
+            const uint8_t (*lvl)[4], ptrdiff_t lvl_stride, \
+            const Av1FilterLUT *lut, int w HIGHBD_DECL_SUFFIX)
+typedef decl_loopfilter_sb_fn(*loopfilter_sb_fn);
+
+typedef struct Dav1dLoopFilterDSPContext {
+    /*
+     * dimension 1: plane (0=luma, 1=chroma)
+     * dimension 2: 0=col-edge filter (h), 1=row-edge filter (v)
+     *
+     * dst/stride are aligned by 32
+     */
+    loopfilter_sb_fn loop_filter_sb[2][2];
+} Dav1dLoopFilterDSPContext;
+
+bitfn_decls(void dav1d_loop_filter_dsp_init, Dav1dLoopFilterDSPContext *c);
+
+#endif /* DAV1D_SRC_LOOPFILTER_H */
diff --git a/media/libdav1d/src/src/loopfilter_tmpl.c b/media/libdav1d/src/src/loopfilter_tmpl.c
new file mode 100644
index 0000000000..0a2baf1e86
--- /dev/null
+++ b/media/libdav1d/src/src/loopfilter_tmpl.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "src/loopfilter.h"
+
+static NOINLINE void
+loop_filter(pixel *dst, int E, int I, int H,
+            const ptrdiff_t stridea, const ptrdiff_t strideb, const int wd
+            HIGHBD_DECL_SUFFIX)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    const int F = 1 << bitdepth_min_8;
+    E <<= bitdepth_min_8;
+    I <<= bitdepth_min_8;
+    H <<= bitdepth_min_8;
+
+    for (int i = 0; i < 4; i++, dst += stridea) {
+        int p6, p5, p4, p3, p2;
+        int p1 = dst[strideb * -2], p0 = dst[strideb * -1];
+        int q0 = dst[strideb * +0], q1 = dst[strideb * +1];
+        int q2, q3, q4, q5, q6;
+        int fm, flat8out, flat8in;
+
+        fm = abs(p1 - p0) <= I && abs(q1 - q0) <= I &&
+             abs(p0 - q0) * 2 + (abs(p1 - q1) >> 1) <= E;
+
+        if (wd > 4) {
+            p2 = dst[strideb * -3];
+            q2 = dst[strideb * +2];
+
+            fm &= abs(p2 - p1) <= I && abs(q2 - q1) <= I;
+
+            if (wd > 6) {
+                p3 = dst[strideb * -4];
+                q3 = dst[strideb * +3];
+
+                fm &= abs(p3 - p2) <= I && abs(q3 - q2) <= I;
+            }
+        }
+        if (!fm) continue;
+
+        if (wd >= 16) {
+            p6 = dst[strideb * -7];
+            p5 = dst[strideb * -6];
+            p4 = dst[strideb * -5];
+            q4 = dst[strideb * +4];
+            q5 = dst[strideb * +5];
+            q6 = dst[strideb * +6];
+
+            flat8out = abs(p6 - p0) <= F && abs(p5 - p0) <= F &&
+                       abs(p4 - p0) <= F && abs(q4 - q0) <= F &&
+                       abs(q5 - q0) <= F && abs(q6 - q0) <= F;
+        }
+
+        if (wd >= 6)
+            flat8in = abs(p2 - p0) <= F && abs(p1 - p0) <= F &&
+                      abs(q1 - q0) <= F && abs(q2 - q0) <= F;
+
+        if (wd >= 8)
+            flat8in &= abs(p3 - p0) <= F && abs(q3 - q0) <= F;
+
+        if (wd >= 16 && (flat8out & flat8in)) {
+            dst[strideb * -6] = (p6 + p6 + p6 + p6 + p6 + p6 * 2 + p5 * 2 +
+                                 p4 * 2 + p3 + p2 + p1 + p0 + q0 + 8) >> 4;
+            dst[strideb * -5] = (p6 + p6 + p6 + p6 + p6 + p5 * 2 + p4 * 2 +
+                                 p3 * 2 + p2 + p1 + p0 + q0 + q1 + 8) >> 4;
+            dst[strideb * -4] = (p6 + p6 + p6 + p6 + p5 + p4 * 2 + p3 * 2 +
+                                 p2 * 2 + p1 + p0 + q0 + q1 + q2 + 8) >> 4;
+            dst[strideb * -3] = (p6 + p6 + p6 + p5 + p4 + p3 * 2 + p2 * 2 +
+                                 p1 * 2 + p0 + q0 + q1 + q2 + q3 + 8) >> 4;
+            dst[strideb * -2] = (p6 + p6 + p5 + p4 + p3 + p2 * 2 + p1 * 2 +
+                                 p0 * 2 + q0 + q1 + q2 + q3 + q4 + 8) >> 4;
+            dst[strideb * -1] = (p6 + p5 + p4 + p3 + p2 + p1 * 2 + p0 * 2 +
+                                 q0 * 2 + q1 + q2 + q3 + q4 + q5 + 8) >> 4;
+            dst[strideb * +0] = (p5 + p4 + p3 + p2 + p1 + p0 * 2 + q0 * 2 +
+                                 q1 * 2 + q2 + q3 + q4 + q5 + q6 + 8) >> 4;
+            dst[strideb * +1] = (p4 + p3 + p2 + p1 + p0 + q0 * 2 + q1 * 2 +
+                                 q2 * 2 + q3 + q4 + q5 + q6 + q6 + 8) >> 4;
+            dst[strideb * +2] = (p3 + p2 + p1 + p0 + q0 + q1 * 2 + q2 * 2 +
+                                 q3 * 2 + q4 + q5 + q6 + q6 + q6 + 8) >> 4;
+            dst[strideb * +3] = (p2 + p1 + p0 + q0 + q1 + q2 * 2 + q3 * 2 +
+                                 q4 * 2 + q5 + q6 + q6 + q6 + q6 + 8) >> 4;
+            dst[strideb * +4] = (p1 + p0 + q0 + q1 + q2 + q3 * 2 + q4 * 2 +
+                                 q5 * 2 + q6 + q6 + q6 + q6 + q6 + 8) >> 4;
+            dst[strideb * +5] = (p0 + q0 + q1 + q2 + q3 + q4 * 2 + q5 * 2 +
+                                 q6 * 2 + q6 + q6 + q6 + q6 + q6 + 8) >> 4;
+        } else if (wd >= 8 && flat8in) {
+            dst[strideb * -3] = (p3 + p3 + p3 + 2 * p2 + p1 + p0 + q0 + 4) >> 3;
+            dst[strideb * -2] = (p3 + p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4) >> 3;
+            dst[strideb * -1] = (p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4) >> 3;
+            dst[strideb * +0] = (p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4) >> 3;
+            dst[strideb * +1] = (p1 + p0 + q0 + 2 * q1 + q2 + q3 + q3 + 4) >> 3;
+            dst[strideb * +2] = (p0 + q0 + q1 + 2 * q2 + q3 + q3 + q3 + 4) >> 3;
+        } else if (wd == 6 && flat8in) {
+            dst[strideb * -2] = (p2 + 2 * p2 + 2 * p1 + 2 * p0 + q0 + 4) >> 3;
+            dst[strideb * -1] = (p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3;
+            dst[strideb * +0] = (p1 + 2 * p0 + 2 * q0 + 2 * q1 + q2 + 4) >> 3;
+            dst[strideb * +1] = (p0 + 2 * q0 + 2 * q1 + 2 * q2 + q2 + 4) >> 3;
+        } else {
+            const int hev = abs(p1 - p0) > H || abs(q1 - q0) > H;
+
+#define iclip_diff(v) iclip(v, -128 * (1 << bitdepth_min_8), \
+                                128 * (1 << bitdepth_min_8) - 1)
+
+            if (hev) {
+                int f = iclip_diff(p1 - q1), f1, f2;
+                f = iclip_diff(3 * (q0 - p0) + f);
+
+                f1 = imin(f + 4, (128 << bitdepth_min_8) - 1) >> 3;
+                f2 = imin(f + 3, (128 << bitdepth_min_8) - 1) >> 3;
+
+                dst[strideb * -1] = iclip_pixel(p0 + f2);
+                dst[strideb * +0] = iclip_pixel(q0 - f1);
+            } else {
+                int f = iclip_diff(3 * (q0 - p0)), f1, f2;
+
+                f1 = imin(f + 4, (128 << bitdepth_min_8) - 1) >> 3;
+                f2 = imin(f + 3, (128 << bitdepth_min_8) - 1) >> 3;
+
+                dst[strideb * -1] = iclip_pixel(p0 + f2);
+                dst[strideb * +0] = iclip_pixel(q0 - f1);
+
+                f = (f1 + 1) >> 1;
+                dst[strideb * -2] = iclip_pixel(p1 + f);
+                dst[strideb * +1] = iclip_pixel(q1 - f);
+            }
+#undef iclip_diff
+        }
+    }
+}
+
+static void loop_filter_h_sb128y_c(pixel *dst, const ptrdiff_t stride,
+                                   const uint32_t *const vmask,
+                                   const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                                   const Av1FilterLUT *lut, const int h
+                                   HIGHBD_DECL_SUFFIX)
+{
+    const unsigned vm = vmask[0] | vmask[1] | vmask[2];
+    for (unsigned y = 1; vm & ~(y - 1);
+         y <<= 1, dst += 4 * PXSTRIDE(stride), l += b4_stride)
+    {
+        if (vm & y) {
+            const int L = l[0][0] ? l[0][0] : l[-1][0];
+            if (!L) continue;
+            const int H = L >> 4;
+            const int E = lut->e[L], I = lut->i[L];
+            const int idx = (vmask[2] & y) ? 2 : !!(vmask[1] & y);
+            loop_filter(dst, E, I, H, PXSTRIDE(stride), 1, 4 << idx
+                        HIGHBD_TAIL_SUFFIX);
+        }
+    }
+}
+
+static void loop_filter_v_sb128y_c(pixel *dst, const ptrdiff_t stride,
+                                   const uint32_t *const vmask,
+                                   const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                                   const Av1FilterLUT *lut, const int w
+                                   HIGHBD_DECL_SUFFIX)
+{
+    const unsigned vm = vmask[0] | vmask[1] | vmask[2];
+    for (unsigned x = 1; vm & ~(x - 1); x <<= 1, dst += 4, l++) {
+        if (vm & x) {
+            const int L = l[0][0] ? l[0][0] : l[-b4_stride][0];
+            if (!L) continue;
+            const int H = L >> 4;
+            const int E = lut->e[L], I = lut->i[L];
+            const int idx = (vmask[2] & x) ? 2 : !!(vmask[1] & x);
+            loop_filter(dst, E, I, H, 1, PXSTRIDE(stride), 4 << idx
+                        HIGHBD_TAIL_SUFFIX);
+        }
+    }
+}
+
+static void loop_filter_h_sb128uv_c(pixel *dst, const ptrdiff_t stride,
+                                    const uint32_t *const vmask,
+                                    const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                                    const Av1FilterLUT *lut, const int h
+                                    HIGHBD_DECL_SUFFIX)
+{
+    const unsigned vm = vmask[0] | vmask[1];
+    for (unsigned y = 1; vm & ~(y - 1);
+         y <<= 1, dst += 4 * PXSTRIDE(stride), l += b4_stride)
+    {
+        if (vm & y) {
+            const int L = l[0][0] ? l[0][0] : l[-1][0];
+            if (!L) continue;
+            const int H = L >> 4;
+            const int E = lut->e[L], I = lut->i[L];
+            const int idx = !!(vmask[1] & y);
+            loop_filter(dst, E, I, H, PXSTRIDE(stride), 1, 4 + 2 * idx
+                        HIGHBD_TAIL_SUFFIX);
+        }
+    }
+}
+
+static void loop_filter_v_sb128uv_c(pixel *dst, const ptrdiff_t stride,
+                                    const uint32_t *const vmask,
+                                    const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                                    const Av1FilterLUT *lut, const int w
+                                    HIGHBD_DECL_SUFFIX)
+{
+    const unsigned vm = vmask[0] | vmask[1];
+    for (unsigned x = 1; vm & ~(x - 1); x <<= 1, dst += 4, l++) {
+        if (vm & x) {
+            const int L = l[0][0] ? l[0][0] : l[-b4_stride][0];
+            if (!L) continue;
+            const int H = L >> 4;
+            const int E = lut->e[L], I = lut->i[L];
+            const int idx = !!(vmask[1] & x);
+            loop_filter(dst, E, I, H, 1, PXSTRIDE(stride), 4 + 2 * idx
+                        HIGHBD_TAIL_SUFFIX);
+        }
+    }
+}
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/loopfilter.h"
+#elif ARCH_LOONGARCH64
+#include "src/loongarch/loopfilter.h"
+#elif ARCH_PPC64LE
+#include "src/ppc/loopfilter.h"
+#elif ARCH_X86
+#include "src/x86/loopfilter.h"
+#endif
+#endif
+
+COLD void bitfn(dav1d_loop_filter_dsp_init)(Dav1dLoopFilterDSPContext *const c) {
+    c->loop_filter_sb[0][0] = loop_filter_h_sb128y_c;
+    c->loop_filter_sb[0][1] = loop_filter_v_sb128y_c;
+    c->loop_filter_sb[1][0] = loop_filter_h_sb128uv_c;
+    c->loop_filter_sb[1][1] = loop_filter_v_sb128uv_c;
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+    loop_filter_dsp_init_arm(c);
+#elif ARCH_LOONGARCH64
+    loop_filter_dsp_init_loongarch(c);
+#elif ARCH_PPC64LE
+    loop_filter_dsp_init_ppc(c);
+#elif ARCH_X86
+    loop_filter_dsp_init_x86(c);
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/looprestoration.h b/media/libdav1d/src/src/looprestoration.h
new file mode 100644
index 0000000000..f55dd31947
--- /dev/null
+++ b/media/libdav1d/src/src/looprestoration.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LOOPRESTORATION_H
+#define DAV1D_SRC_LOOPRESTORATION_H
+
+#include 
+#include 
+
+#include "common/bitdepth.h"
+
+enum LrEdgeFlags {
+    LR_HAVE_LEFT = 1 << 0,
+    LR_HAVE_RIGHT = 1 << 1,
+    LR_HAVE_TOP = 1 << 2,
+    LR_HAVE_BOTTOM = 1 << 3,
+};
+
+#ifdef BITDEPTH
+typedef const pixel (*const_left_pixel_row)[4];
+#else
+typedef const void *const_left_pixel_row;
+#endif
+
+typedef union LooprestorationParams {
+    ALIGN(int16_t filter[2][8], 16);
+    struct {
+        uint32_t s0, s1;
+        int16_t w0, w1;
+    } sgr;
+} LooprestorationParams;
+
+// Although the spec applies restoration filters over 4x4 blocks,
+// they can be applied to a bigger surface.
+//    * w is constrained by the restoration unit size (w <= 256)
+//    * h is constrained by the stripe height (h <= 64)
+// The filter functions are allowed to do aligned writes past the right
+// edge of the buffer, aligned up to the minimum loop restoration unit size
+// (which is 32 pixels for subsampled chroma and 64 pixels for luma).
+#define decl_lr_filter_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const_left_pixel_row left, \
+            const pixel *lpf, int w, int h, \
+            const LooprestorationParams *params, \
+            enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+typedef decl_lr_filter_fn(*looprestorationfilter_fn);
+
+typedef struct Dav1dLoopRestorationDSPContext {
+    looprestorationfilter_fn wiener[2]; /* 7-tap, 5-tap */
+    looprestorationfilter_fn sgr[3]; /* 5x5, 3x3, mix */
+} Dav1dLoopRestorationDSPContext;
+
+bitfn_decls(void dav1d_loop_restoration_dsp_init, Dav1dLoopRestorationDSPContext *c, int bpc);
+
+#endif /* DAV1D_SRC_LOOPRESTORATION_H */
diff --git a/media/libdav1d/src/src/looprestoration_tmpl.c b/media/libdav1d/src/src/looprestoration_tmpl.c
new file mode 100644
index 0000000000..c172462b97
--- /dev/null
+++ b/media/libdav1d/src/src/looprestoration_tmpl.c
@@ -0,0 +1,1384 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+
+#include "common/attributes.h"
+#include "common/bitdepth.h"
+#include "common/intops.h"
+
+#include "src/looprestoration.h"
+#include "src/tables.h"
+
+// 256 * 1.5 + 3 + 3 = 390
+#define REST_UNIT_STRIDE (390)
+
+static void wiener_filter_h(uint16_t *dst, const pixel (*left)[4],
+                            const pixel *src, const int16_t fh[8],
+                            const int w, const enum LrEdgeFlags edges
+                            HIGHBD_DECL_SUFFIX)
+{
+    const int bitdepth = bitdepth_from_max(bitdepth_max);
+    const int round_bits_h = 3 + (bitdepth == 12) * 2;
+    const int rounding_off_h = 1 << (round_bits_h - 1);
+    const int clip_limit = 1 << (bitdepth + 1 + 7 - round_bits_h);
+
+    if (w < 6) {
+        // For small widths, do the fully conditional loop with
+        // conditions on each access.
+        for (int x = 0; x < w; x++) {
+            int sum = (1 << (bitdepth + 6));
+#if BITDEPTH == 8
+            sum += src[x] * 128;
+#endif
+            for (int i = 0; i < 7; i++) {
+                int idx = x + i - 3;
+                if (idx < 0) {
+                    if (!(edges & LR_HAVE_LEFT))
+                        sum += src[0] * fh[i];
+                    else if (left)
+                        sum += left[0][4 + idx] * fh[i];
+                    else
+                        sum += src[idx] * fh[i];
+                } else if (idx >= w && !(edges & LR_HAVE_RIGHT)) {
+                    sum += src[w - 1] * fh[i];
+                } else
+                    sum += src[idx] * fh[i];
+            }
+            sum = iclip((sum + rounding_off_h) >> round_bits_h, 0, clip_limit - 1);
+            dst[x] = sum;
+        }
+
+        return;
+    }
+
+    // For larger widths, do separate loops with less conditions; first
+    // handle the start of the row.
+    int start = 3;
+    if (!(edges & LR_HAVE_LEFT)) {
+        // If there's no left edge, pad using the leftmost pixel.
+        for (int x = 0; x < 3; x++) {
+            int sum = (1 << (bitdepth + 6));
+#if BITDEPTH == 8
+            sum += src[x] * 128;
+#endif
+            for (int i = 0; i < 7; i++) {
+                int idx = x + i - 3;
+                if (idx < 0)
+                    sum += src[0] * fh[i];
+                else
+                    sum += src[idx] * fh[i];
+            }
+            sum = iclip((sum + rounding_off_h) >> round_bits_h, 0, clip_limit - 1);
+            dst[x] = sum;
+        }
+    } else if (left) {
+        // If we have the left edge and a separate left buffer, pad using that.
+        for (int x = 0; x < 3; x++) {
+            int sum = (1 << (bitdepth + 6));
+#if BITDEPTH == 8
+            sum += src[x] * 128;
+#endif
+            for (int i = 0; i < 7; i++) {
+                int idx = x + i - 3;
+                if (idx < 0)
+                    sum += left[0][4 + idx] * fh[i];
+                else
+                    sum += src[idx] * fh[i];
+            }
+            sum = iclip((sum + rounding_off_h) >> round_bits_h, 0, clip_limit - 1);
+            dst[x] = sum;
+        }
+    } else {
+        // If we have the left edge, but no separate left buffer, we're in the
+        // top/bottom area (lpf) with the left edge existing in the same
+        // buffer; just do the regular loop from the start.
+        start = 0;
+    }
+    int end = w - 3;
+    if (edges & LR_HAVE_RIGHT)
+        end = w;
+
+    // Do a condititon free loop for the bulk of the row.
+    for (int x = start; x < end; x++) {
+        int sum = (1 << (bitdepth + 6));
+#if BITDEPTH == 8
+        sum += src[x] * 128;
+#endif
+        for (int i = 0; i < 7; i++) {
+            int idx = x + i - 3;
+            sum += src[idx] * fh[i];
+        }
+        sum = iclip((sum + rounding_off_h) >> round_bits_h, 0, clip_limit - 1);
+        dst[x] = sum;
+    }
+
+    // If we need to, calculate the end of the row with a condition for
+    // right edge padding.
+    for (int x = end; x < w; x++) {
+        int sum = (1 << (bitdepth + 6));
+#if BITDEPTH == 8
+        sum += src[x] * 128;
+#endif
+        for (int i = 0; i < 7; i++) {
+            int idx = x + i - 3;
+            if (idx >= w)
+                sum += src[w - 1] * fh[i];
+            else
+                sum += src[idx] * fh[i];
+        }
+        sum = iclip((sum + rounding_off_h) >> round_bits_h, 0, clip_limit - 1);
+        dst[x] = sum;
+    }
+}
+
+static void wiener_filter_v(pixel *p, uint16_t **ptrs, const int16_t fv[8],
+                            const int w HIGHBD_DECL_SUFFIX)
+{
+    const int bitdepth = bitdepth_from_max(bitdepth_max);
+
+    const int round_bits_v = 11 - (bitdepth == 12) * 2;
+    const int rounding_off_v = 1 << (round_bits_v - 1);
+    const int round_offset = 1 << (bitdepth + (round_bits_v - 1));
+
+    for (int i = 0; i < w; i++) {
+        int sum = -round_offset;
+
+        // Only filter using 6 input rows. The 7th row is assumed to be
+        // identical to the last one.
+        //
+        // This function is assumed to only be called at the end, when doing
+        // padding at the bottom.
+        for (int k = 0; k < 6; k++)
+            sum += ptrs[k][i] * fv[k];
+        sum += ptrs[5][i] * fv[6];
+
+        p[i] = iclip_pixel((sum + rounding_off_v) >> round_bits_v);
+    }
+
+    // Shift the pointers, but only update the first 5; the 6th pointer is kept
+    // as it was before (and the 7th is implicitly identical to the 6th).
+    for (int i = 0; i < 5; i++)
+        ptrs[i] = ptrs[i + 1];
+}
+
+static void wiener_filter_hv(pixel *p, uint16_t **ptrs, const pixel (*left)[4],
+                             const pixel *src, const int16_t filter[2][8],
+                             const int w, const enum LrEdgeFlags edges
+                             HIGHBD_DECL_SUFFIX)
+{
+    const int bitdepth = bitdepth_from_max(bitdepth_max);
+
+    const int round_bits_v = 11 - (bitdepth == 12) * 2;
+    const int rounding_off_v = 1 << (round_bits_v - 1);
+    const int round_offset = 1 << (bitdepth + (round_bits_v - 1));
+
+    const int16_t *fh = filter[0];
+    const int16_t *fv = filter[1];
+
+    // Do combined horziontal and vertical filtering; doing horizontal
+    // filtering of one row, combined with vertical filtering of 6
+    // preexisting rows and the newly filtered row.
+
+    // For simplicity in the C implementation, just do a separate call
+    // of the horizontal filter, into a temporary buffer.
+    uint16_t tmp[REST_UNIT_STRIDE];
+    wiener_filter_h(tmp, left, src, fh, w, edges HIGHBD_TAIL_SUFFIX);
+
+    for (int i = 0; i < w; i++) {
+        int sum = -round_offset;
+
+        // Filter using the 6 stored preexisting rows, and the newly
+        // filtered one in tmp[].
+        for (int k = 0; k < 6; k++)
+            sum += ptrs[k][i] * fv[k];
+        sum += tmp[i] * fv[6];
+        // At this point, after having read all inputs at point [i], we
+        // could overwrite [i] with the newly filtered data.
+
+        p[i] = iclip_pixel((sum + rounding_off_v) >> round_bits_v);
+    }
+
+    // For simplicity in the C implementation, just memcpy the newly
+    // filtered row into ptrs[6]. Normally, in steady state filtering,
+    // this output row, ptrs[6], is equal to ptrs[0]. However at startup,
+    // at the top of the filtered area, we may have ptrs[0] equal to ptrs[1],
+    // so we can't assume we can write into ptrs[0] but we need to keep
+    // a separate pointer for the next row to write into.
+    memcpy(ptrs[6], tmp, sizeof(uint16_t) * REST_UNIT_STRIDE);
+
+    // Rotate the window of pointers. Shift the 6 pointers downwards one step.
+    for (int i = 0; i < 6; i++)
+        ptrs[i] = ptrs[i + 1];
+    // The topmost pointer, ptrs[6], which isn't used as input, is set to
+    // ptrs[0], which will be used as output for the next _hv call.
+    // At the start of the filtering, the caller may set ptrs[6] to the
+    // right next buffer to fill in, instead.
+    ptrs[6] = ptrs[0];
+}
+
+// FIXME Could split into luma and chroma specific functions,
+// (since first and last tops are always 0 for chroma)
+static void wiener_c(pixel *p, const ptrdiff_t stride,
+                     const pixel (*left)[4],
+                     const pixel *lpf, const int w, int h,
+                     const LooprestorationParams *const params,
+                     const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    // Values stored between horizontal and vertical filtering don't
+    // fit in a uint8_t.
+    uint16_t hor[6 * REST_UNIT_STRIDE];
+    uint16_t *ptrs[7], *rows[6];
+    for (int i = 0; i < 6; i++)
+        rows[i] = &hor[i * REST_UNIT_STRIDE];
+    const int16_t (*const filter)[8] = params->filter;
+    const int16_t *fh = params->filter[0];
+    const int16_t *fv = params->filter[1];
+    const pixel *lpf_bottom = lpf + 6*PXSTRIDE(stride);
+
+    const pixel *src = p;
+    if (edges & LR_HAVE_TOP) {
+        ptrs[0] = rows[0];
+        ptrs[1] = rows[0];
+        ptrs[2] = rows[1];
+        ptrs[3] = rows[2];
+        ptrs[4] = rows[2];
+        ptrs[5] = rows[2];
+
+        wiener_filter_h(rows[0], NULL, lpf, fh, w, edges HIGHBD_TAIL_SUFFIX);
+        lpf += PXSTRIDE(stride);
+        wiener_filter_h(rows[1], NULL, lpf, fh, w, edges HIGHBD_TAIL_SUFFIX);
+
+        wiener_filter_h(rows[2], left, src, fh, w, edges HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v1;
+
+        ptrs[4] = ptrs[5] = rows[3];
+        wiener_filter_h(rows[3], left, src, fh, w, edges HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v2;
+
+        ptrs[5] = rows[4];
+        wiener_filter_h(rows[4], left, src, fh, w, edges HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v3;
+    } else {
+        ptrs[0] = rows[0];
+        ptrs[1] = rows[0];
+        ptrs[2] = rows[0];
+        ptrs[3] = rows[0];
+        ptrs[4] = rows[0];
+        ptrs[5] = rows[0];
+
+        wiener_filter_h(rows[0], left, src, fh, w, edges HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v1;
+
+        ptrs[4] = ptrs[5] = rows[1];
+        wiener_filter_h(rows[1], left, src, fh, w, edges HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v2;
+
+        ptrs[5] = rows[2];
+        wiener_filter_h(rows[2], left, src, fh, w, edges HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v3;
+
+        ptrs[6] = rows[3];
+        wiener_filter_hv(p, ptrs, left, src, filter, w, edges
+                         HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+        p += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v3;
+
+        ptrs[6] = rows[4];
+        wiener_filter_hv(p, ptrs, left, src, filter, w, edges
+                         HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+        p += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto v3;
+    }
+
+    ptrs[6] = ptrs[5] + REST_UNIT_STRIDE;
+    do {
+        wiener_filter_hv(p, ptrs, left, src, filter, w, edges
+                         HIGHBD_TAIL_SUFFIX);
+        left++;
+        src += PXSTRIDE(stride);
+        p += PXSTRIDE(stride);
+    } while (--h > 0);
+
+    if (!(edges & LR_HAVE_BOTTOM))
+        goto v3;
+
+    wiener_filter_hv(p, ptrs, NULL, lpf_bottom, filter, w, edges
+                     HIGHBD_TAIL_SUFFIX);
+    lpf_bottom += PXSTRIDE(stride);
+    p += PXSTRIDE(stride);
+
+    wiener_filter_hv(p, ptrs, NULL, lpf_bottom, filter, w, edges
+                     HIGHBD_TAIL_SUFFIX);
+    p += PXSTRIDE(stride);
+v1:
+    wiener_filter_v(p, ptrs, fv, w HIGHBD_TAIL_SUFFIX);
+
+    return;
+
+v3:
+    wiener_filter_v(p, ptrs, fv, w HIGHBD_TAIL_SUFFIX);
+    p += PXSTRIDE(stride);
+v2:
+    wiener_filter_v(p, ptrs, fv, w HIGHBD_TAIL_SUFFIX);
+    p += PXSTRIDE(stride);
+    goto v1;
+}
+
+// SGR
+static NOINLINE void rotate(int32_t **sumsq_ptrs, coef **sum_ptrs, int n)
+{
+    int32_t *tmp32 = sumsq_ptrs[0];
+    coef *tmpc = sum_ptrs[0];
+    for (int i = 0; i < n - 1; i++) {
+        sumsq_ptrs[i] = sumsq_ptrs[i + 1];
+        sum_ptrs[i] = sum_ptrs[i + 1];
+    }
+    sumsq_ptrs[n - 1] = tmp32;
+    sum_ptrs[n - 1] = tmpc;
+}
+
+static NOINLINE void rotate5_x2(int32_t **sumsq_ptrs, coef **sum_ptrs)
+{
+    int32_t *tmp32[2];
+    coef *tmpc[2];
+    for (int i = 0; i < 2; i++) {
+        tmp32[i] = sumsq_ptrs[i];
+        tmpc[i] = sum_ptrs[i];
+    }
+    for (int i = 0; i < 3; i++) {
+        sumsq_ptrs[i] = sumsq_ptrs[i + 2];
+        sum_ptrs[i] = sum_ptrs[i + 2];
+    }
+    for (int i = 0; i < 2; i++) {
+        sumsq_ptrs[3 + i] = tmp32[i];
+        sum_ptrs[3 + i] = tmpc[i];
+    }
+}
+
+static NOINLINE void sgr_box3_row_h(int32_t *sumsq, coef *sum,
+                                    const pixel (*left)[4],
+                                    const pixel *src, const int w,
+                                    const enum LrEdgeFlags edges)
+{
+    sumsq++;
+    sum++;
+    int a = edges & LR_HAVE_LEFT ? (left ? left[0][2] : src[-2]) : src[0];
+    int b = edges & LR_HAVE_LEFT ? (left ? left[0][3] : src[-1]) : src[0];
+    for (int x = -1; x < w + 1; x++) {
+        int c = (x + 1 < w || (edges & LR_HAVE_RIGHT)) ? src[x + 1] : src[w - 1];
+        sum[x] = a + b + c;
+        sumsq[x] = a * a + b * b + c * c;
+        a = b;
+        b = c;
+    }
+}
+
+static NOINLINE void sgr_box5_row_h(int32_t *sumsq, coef *sum,
+                                    const pixel (*left)[4],
+                                    const pixel *src, const int w,
+                                    const enum LrEdgeFlags edges)
+{
+    sumsq++;
+    sum++;
+    int a = edges & LR_HAVE_LEFT ? (left ? left[0][1] : src[-3]) : src[0];
+    int b = edges & LR_HAVE_LEFT ? (left ? left[0][2] : src[-2]) : src[0];
+    int c = edges & LR_HAVE_LEFT ? (left ? left[0][3] : src[-1]) : src[0];
+    int d = src[0];
+    for (int x = -1; x < w + 1; x++) {
+        int e = (x + 2 < w || (edges & LR_HAVE_RIGHT)) ? src[x + 2] : src[w - 1];
+        sum[x] = a + b + c + d + e;
+        sumsq[x] = a * a + b * b + c * c + d * d + e * e;
+        a = b;
+        b = c;
+        c = d;
+        d = e;
+    }
+}
+
+static void sgr_box35_row_h(int32_t *sumsq3, coef *sum3,
+                            int32_t *sumsq5, coef *sum5,
+                            const pixel (*left)[4],
+                            const pixel *src, const int w,
+                            const enum LrEdgeFlags edges)
+{
+    sgr_box3_row_h(sumsq3, sum3, left, src, w, edges);
+    sgr_box5_row_h(sumsq5, sum5, left, src, w, edges);
+}
+
+static NOINLINE void sgr_box3_row_v(int32_t **sumsq, coef **sum,
+                                    int32_t *sumsq_out, coef *sum_out,
+                                    const int w)
+{
+    for (int x = 0; x < w + 2; x++) {
+        int sq_a = sumsq[0][x];
+        int sq_b = sumsq[1][x];
+        int sq_c = sumsq[2][x];
+        int s_a = sum[0][x];
+        int s_b = sum[1][x];
+        int s_c = sum[2][x];
+        sumsq_out[x] = sq_a + sq_b + sq_c;
+        sum_out[x] = s_a + s_b + s_c;
+    }
+}
+
+static NOINLINE void sgr_box5_row_v(int32_t **sumsq, coef **sum,
+                                    int32_t *sumsq_out, coef *sum_out,
+                                    const int w)
+{
+    for (int x = 0; x < w + 2; x++) {
+        int sq_a = sumsq[0][x];
+        int sq_b = sumsq[1][x];
+        int sq_c = sumsq[2][x];
+        int sq_d = sumsq[3][x];
+        int sq_e = sumsq[4][x];
+        int s_a = sum[0][x];
+        int s_b = sum[1][x];
+        int s_c = sum[2][x];
+        int s_d = sum[3][x];
+        int s_e = sum[4][x];
+        sumsq_out[x] = sq_a + sq_b + sq_c + sq_d + sq_e;
+        sum_out[x] = s_a + s_b + s_c + s_d + s_e;
+    }
+}
+
+static NOINLINE void sgr_calc_row_ab(int32_t *AA, coef *BB, int w, int s,
+                                     int bitdepth_max, int n, int sgr_one_by_x)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    for (int i = 0; i < w + 2; i++) {
+        const int a =
+            (AA[i] + ((1 << (2 * bitdepth_min_8)) >> 1)) >> (2 * bitdepth_min_8);
+        const int b =
+            (BB[i] + ((1 << bitdepth_min_8) >> 1)) >> bitdepth_min_8;
+
+        const unsigned p = imax(a * n - b * b, 0);
+        const unsigned z = (p * s + (1 << 19)) >> 20;
+        const unsigned x = dav1d_sgr_x_by_x[umin(z, 255)];
+
+        // This is where we invert A and B, so that B is of size coef.
+        AA[i] = (x * BB[i] * sgr_one_by_x + (1 << 11)) >> 12;
+        BB[i] = x;
+    }
+}
+
+static void sgr_box3_vert(int32_t **sumsq, coef **sum,
+                          int32_t *sumsq_out, coef *sum_out,
+                          const int w, const int s, const int bitdepth_max)
+{
+    sgr_box3_row_v(sumsq, sum, sumsq_out, sum_out, w);
+    sgr_calc_row_ab(sumsq_out, sum_out, w, s, bitdepth_max, 9, 455);
+    rotate(sumsq, sum, 3);
+}
+
+static void sgr_box5_vert(int32_t **sumsq, coef **sum,
+                          int32_t *sumsq_out, coef *sum_out,
+                          const int w, const int s, const int bitdepth_max)
+{
+    sgr_box5_row_v(sumsq, sum, sumsq_out, sum_out, w);
+    sgr_calc_row_ab(sumsq_out, sum_out, w, s, bitdepth_max, 25, 164);
+    rotate5_x2(sumsq, sum);
+}
+
+static void sgr_box3_hv(int32_t **sumsq, coef **sum,
+                        int32_t *AA, coef *BB,
+                        const pixel (*left)[4],
+                        const pixel *src, const int w,
+                        const int s,
+                        const enum LrEdgeFlags edges,
+                        const int bitdepth_max)
+{
+    sgr_box3_row_h(sumsq[2], sum[2], left, src, w, edges);
+    sgr_box3_vert(sumsq, sum, AA, BB, w, s, bitdepth_max);
+}
+
+static NOINLINE void sgr_finish_filter_row1(coef *tmp,
+                                            const pixel *src,
+                                            int32_t **A_ptrs, coef **B_ptrs,
+                                            const int w)
+{
+#define EIGHT_NEIGHBORS(P, i)\
+    ((P[1][i] + P[1][i - 1] + P[1][i + 1] + P[0][i] + P[2][i]) * 4 + \
+     (P[0][i - 1] + P[2][i - 1] +                           \
+      P[0][i + 1] + P[2][i + 1]) * 3)
+    for (int i = 0; i < w; i++) {
+        const int a = EIGHT_NEIGHBORS(B_ptrs, i + 1);
+        const int b = EIGHT_NEIGHBORS(A_ptrs, i + 1);
+        tmp[i] = (b - a * src[i] + (1 << 8)) >> 9;
+    }
+#undef EIGHT_NEIGHBORS
+}
+
+#define FILTER_OUT_STRIDE (384)
+
+static NOINLINE void sgr_finish_filter2(coef *tmp,
+                                        const pixel *src,
+                                        const ptrdiff_t src_stride,
+                                        int32_t **A_ptrs, coef **B_ptrs,
+                                        const int w, const int h)
+{
+#define SIX_NEIGHBORS(P, i)\
+    ((P[0][i]     + P[1][i]) * 6 +   \
+     (P[0][i - 1] + P[1][i - 1] +    \
+      P[0][i + 1] + P[1][i + 1]) * 5)
+    for (int i = 0; i < w; i++) {
+        const int a = SIX_NEIGHBORS(B_ptrs, i + 1);
+        const int b = SIX_NEIGHBORS(A_ptrs, i + 1);
+        tmp[i] = (b - a * src[i] + (1 << 8)) >> 9;
+    }
+    if (h <= 1)
+        return;
+    tmp += FILTER_OUT_STRIDE;
+    src += PXSTRIDE(src_stride);
+    const int32_t *A = &A_ptrs[1][1];
+    const coef *B = &B_ptrs[1][1];
+    for (int i = 0; i < w; i++) {
+        const int a = B[i] * 6 + (B[i - 1] + B[i + 1]) * 5;
+        const int b = A[i] * 6 + (A[i - 1] + A[i + 1]) * 5;
+        tmp[i] = (b - a * src[i] + (1 << 7)) >> 8;
+    }
+#undef SIX_NEIGHBORS
+}
+
+static NOINLINE void sgr_weighted_row1(pixel *dst, const coef *t1,
+                                       const int w, const int w1 HIGHBD_DECL_SUFFIX)
+{
+    for (int i = 0; i < w; i++) {
+        const int v = w1 * t1[i];
+        dst[i] = iclip_pixel(dst[i] + ((v + (1 << 10)) >> 11));
+    }
+}
+
+static NOINLINE void sgr_weighted2(pixel *dst, const ptrdiff_t dst_stride,
+                                   const coef *t1, const coef *t2,
+                                   const int w, const int h,
+                                   const int w0, const int w1 HIGHBD_DECL_SUFFIX)
+{
+    for (int j = 0; j < h; j++) {
+        for (int i = 0; i < w; i++) {
+            const int v = w0 * t1[i] + w1 * t2[i];
+            dst[i] = iclip_pixel(dst[i] + ((v + (1 << 10)) >> 11));
+        }
+        dst += PXSTRIDE(dst_stride);
+        t1 += FILTER_OUT_STRIDE;
+        t2 += FILTER_OUT_STRIDE;
+    }
+}
+
+static NOINLINE void sgr_finish1(pixel **dst, const ptrdiff_t stride,
+                                 int32_t **A_ptrs, coef **B_ptrs, const int w,
+                                 const int w1 HIGHBD_DECL_SUFFIX)
+{
+    // Only one single row, no stride needed
+    ALIGN_STK_16(coef, tmp, 384,);
+
+    sgr_finish_filter_row1(tmp, *dst, A_ptrs, B_ptrs, w);
+    sgr_weighted_row1(*dst, tmp, w, w1 HIGHBD_TAIL_SUFFIX);
+    *dst += PXSTRIDE(stride);
+    rotate(A_ptrs, B_ptrs, 3);
+}
+
+static NOINLINE void sgr_finish2(pixel **dst, const ptrdiff_t stride,
+                                 int32_t **A_ptrs, coef **B_ptrs,
+                                 const int w, const int h, const int w1
+                                 HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(coef, tmp, 2*FILTER_OUT_STRIDE,);
+
+    sgr_finish_filter2(tmp, *dst, stride, A_ptrs, B_ptrs, w, h);
+    sgr_weighted_row1(*dst, tmp, w, w1 HIGHBD_TAIL_SUFFIX);
+    *dst += PXSTRIDE(stride);
+    if (h > 1) {
+        sgr_weighted_row1(*dst, tmp + FILTER_OUT_STRIDE, w, w1 HIGHBD_TAIL_SUFFIX);
+        *dst += PXSTRIDE(stride);
+    }
+    rotate(A_ptrs, B_ptrs, 2);
+}
+
+static NOINLINE void sgr_finish_mix(pixel **dst, const ptrdiff_t stride,
+                                    int32_t **A5_ptrs, coef **B5_ptrs,
+                                    int32_t **A3_ptrs, coef **B3_ptrs,
+                                    const int w, const int h,
+                                    const int w0, const int w1 HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(coef, tmp5, 2*FILTER_OUT_STRIDE,);
+    ALIGN_STK_16(coef, tmp3, 2*FILTER_OUT_STRIDE,);
+
+    sgr_finish_filter2(tmp5, *dst, stride, A5_ptrs, B5_ptrs, w, h);
+    sgr_finish_filter_row1(tmp3, *dst, A3_ptrs, B3_ptrs, w);
+    if (h > 1)
+        sgr_finish_filter_row1(tmp3 + FILTER_OUT_STRIDE, *dst + PXSTRIDE(stride),
+                               &A3_ptrs[1], &B3_ptrs[1], w);
+    sgr_weighted2(*dst, stride, tmp5, tmp3, w, h, w0, w1 HIGHBD_TAIL_SUFFIX);
+    *dst += h*PXSTRIDE(stride);
+    rotate(A5_ptrs, B5_ptrs, 2);
+    rotate(A3_ptrs, B3_ptrs, 4);
+}
+
+
+static void sgr_3x3_c(pixel *dst, const ptrdiff_t stride,
+                      const pixel (*left)[4], const pixel *lpf,
+                      const int w, int h,
+                      const LooprestorationParams *const params,
+                      const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+#define BUF_STRIDE (384 + 16)
+    ALIGN_STK_16(int32_t, sumsq_buf, BUF_STRIDE * 3 + 16,);
+    ALIGN_STK_16(coef, sum_buf, BUF_STRIDE * 3 + 16,);
+    int32_t *sumsq_ptrs[3], *sumsq_rows[3];
+    coef *sum_ptrs[3], *sum_rows[3];
+    for (int i = 0; i < 3; i++) {
+        sumsq_rows[i] = &sumsq_buf[i * BUF_STRIDE];
+        sum_rows[i] = &sum_buf[i * BUF_STRIDE];
+    }
+
+    ALIGN_STK_16(int32_t, A_buf, BUF_STRIDE * 3 + 16,);
+    ALIGN_STK_16(coef, B_buf, BUF_STRIDE * 3 + 16,);
+    int32_t *A_ptrs[3];
+    coef *B_ptrs[3];
+    for (int i = 0; i < 3; i++) {
+        A_ptrs[i] = &A_buf[i * BUF_STRIDE];
+        B_ptrs[i] = &B_buf[i * BUF_STRIDE];
+    }
+    const pixel *src = dst;
+    const pixel *lpf_bottom = lpf + 6*PXSTRIDE(stride);
+
+    if (edges & LR_HAVE_TOP) {
+        sumsq_ptrs[0] = sumsq_rows[0];
+        sumsq_ptrs[1] = sumsq_rows[1];
+        sumsq_ptrs[2] = sumsq_rows[2];
+        sum_ptrs[0] = sum_rows[0];
+        sum_ptrs[1] = sum_rows[1];
+        sum_ptrs[2] = sum_rows[2];
+
+        sgr_box3_row_h(sumsq_rows[0], sum_rows[0], NULL, lpf, w, edges);
+        lpf += PXSTRIDE(stride);
+        sgr_box3_row_h(sumsq_rows[1], sum_rows[1], NULL, lpf, w, edges);
+
+        sgr_box3_hv(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                    left, src, w, params->sgr.s1, edges, BITDEPTH_MAX);
+        left++;
+        src += PXSTRIDE(stride);
+        rotate(A_ptrs, B_ptrs, 3);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sgr_box3_hv(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                    left, src, w, params->sgr.s1, edges, BITDEPTH_MAX);
+        left++;
+        src += PXSTRIDE(stride);
+        rotate(A_ptrs, B_ptrs, 3);
+
+        if (--h <= 0)
+            goto vert_2;
+    } else {
+        sumsq_ptrs[0] = sumsq_rows[0];
+        sumsq_ptrs[1] = sumsq_rows[0];
+        sumsq_ptrs[2] = sumsq_rows[0];
+        sum_ptrs[0] = sum_rows[0];
+        sum_ptrs[1] = sum_rows[0];
+        sum_ptrs[2] = sum_rows[0];
+
+        sgr_box3_row_h(sumsq_rows[0], sum_rows[0], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        rotate(A_ptrs, B_ptrs, 3);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sumsq_ptrs[2] = sumsq_rows[1];
+        sum_ptrs[2] = sum_rows[1];
+
+        sgr_box3_hv(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                    left, src, w, params->sgr.s1, edges, BITDEPTH_MAX);
+        left++;
+        src += PXSTRIDE(stride);
+        rotate(A_ptrs, B_ptrs, 3);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        sumsq_ptrs[2] = sumsq_rows[2];
+        sum_ptrs[2] = sum_rows[2];
+    }
+
+    do {
+        sgr_box3_hv(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                    left, src, w, params->sgr.s1, edges, BITDEPTH_MAX);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_finish1(&dst, stride, A_ptrs, B_ptrs,
+                    w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+    } while (--h > 0);
+
+    if (!(edges & LR_HAVE_BOTTOM))
+        goto vert_2;
+
+    sgr_box3_hv(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                NULL, lpf_bottom, w, params->sgr.s1, edges, BITDEPTH_MAX);
+    lpf_bottom += PXSTRIDE(stride);
+
+    sgr_finish1(&dst, stride, A_ptrs, B_ptrs,
+                w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+
+    sgr_box3_hv(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                NULL, lpf_bottom, w, params->sgr.s1, edges, BITDEPTH_MAX);
+
+    sgr_finish1(&dst, stride, A_ptrs, B_ptrs,
+                w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_2:
+    sumsq_ptrs[2] = sumsq_ptrs[1];
+    sum_ptrs[2] = sum_ptrs[1];
+    sgr_box3_vert(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+
+    sgr_finish1(&dst, stride, A_ptrs, B_ptrs,
+                w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+
+output_1:
+    sumsq_ptrs[2] = sumsq_ptrs[1];
+    sum_ptrs[2] = sum_ptrs[1];
+    sgr_box3_vert(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+
+    sgr_finish1(&dst, stride, A_ptrs, B_ptrs,
+                w, params->sgr.w1 HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_1:
+    sumsq_ptrs[2] = sumsq_ptrs[1];
+    sum_ptrs[2] = sum_ptrs[1];
+    sgr_box3_vert(sumsq_ptrs, sum_ptrs, A_ptrs[2], B_ptrs[2],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+    rotate(A_ptrs, B_ptrs, 3);
+    goto output_1;
+}
+
+static void sgr_5x5_c(pixel *dst, const ptrdiff_t stride,
+                      const pixel (*left)[4], const pixel *lpf,
+                      const int w, int h,
+                      const LooprestorationParams *const params,
+                      const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(int32_t, sumsq_buf, BUF_STRIDE * 5 + 16,);
+    ALIGN_STK_16(coef, sum_buf, BUF_STRIDE * 5 + 16,);
+    int32_t *sumsq_ptrs[5], *sumsq_rows[5];
+    coef *sum_ptrs[5], *sum_rows[5];
+    for (int i = 0; i < 5; i++) {
+        sumsq_rows[i] = &sumsq_buf[i * BUF_STRIDE];
+        sum_rows[i] = &sum_buf[i * BUF_STRIDE];
+    }
+
+    ALIGN_STK_16(int32_t, A_buf, BUF_STRIDE * 2 + 16,);
+    ALIGN_STK_16(coef, B_buf, BUF_STRIDE * 2 + 16,);
+    int32_t *A_ptrs[2];
+    coef *B_ptrs[2];
+    for (int i = 0; i < 2; i++) {
+        A_ptrs[i] = &A_buf[i * BUF_STRIDE];
+        B_ptrs[i] = &B_buf[i * BUF_STRIDE];
+    }
+    const pixel *src = dst;
+    const pixel *lpf_bottom = lpf + 6*PXSTRIDE(stride);
+
+    if (edges & LR_HAVE_TOP) {
+        sumsq_ptrs[0] = sumsq_rows[0];
+        sumsq_ptrs[1] = sumsq_rows[0];
+        sumsq_ptrs[2] = sumsq_rows[1];
+        sumsq_ptrs[3] = sumsq_rows[2];
+        sumsq_ptrs[4] = sumsq_rows[3];
+        sum_ptrs[0] = sum_rows[0];
+        sum_ptrs[1] = sum_rows[0];
+        sum_ptrs[2] = sum_rows[1];
+        sum_ptrs[3] = sum_rows[2];
+        sum_ptrs[4] = sum_rows[3];
+
+        sgr_box5_row_h(sumsq_rows[0], sum_rows[0], NULL, lpf, w, edges);
+        lpf += PXSTRIDE(stride);
+        sgr_box5_row_h(sumsq_rows[1], sum_rows[1], NULL, lpf, w, edges);
+
+        sgr_box5_row_h(sumsq_rows[2], sum_rows[2], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sgr_box5_row_h(sumsq_rows[3], sum_rows[3], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+        sgr_box5_vert(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                      w, params->sgr.s0, BITDEPTH_MAX);
+        rotate(A_ptrs, B_ptrs, 2);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        // ptrs are rotated by 2; both [3] and [4] now point at rows[0]; set
+        // one of them to point at the previously unused rows[4].
+        sumsq_ptrs[3] = sumsq_rows[4];
+        sum_ptrs[3] = sum_rows[4];
+    } else {
+        sumsq_ptrs[0] = sumsq_rows[0];
+        sumsq_ptrs[1] = sumsq_rows[0];
+        sumsq_ptrs[2] = sumsq_rows[0];
+        sumsq_ptrs[3] = sumsq_rows[0];
+        sumsq_ptrs[4] = sumsq_rows[0];
+        sum_ptrs[0] = sum_rows[0];
+        sum_ptrs[1] = sum_rows[0];
+        sum_ptrs[2] = sum_rows[0];
+        sum_ptrs[3] = sum_rows[0];
+        sum_ptrs[4] = sum_rows[0];
+
+        sgr_box5_row_h(sumsq_rows[0], sum_rows[0], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sumsq_ptrs[4] = sumsq_rows[1];
+        sum_ptrs[4] = sum_rows[1];
+
+        sgr_box5_row_h(sumsq_rows[1], sum_rows[1], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                      w, params->sgr.s0, BITDEPTH_MAX);
+        rotate(A_ptrs, B_ptrs, 2);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        sumsq_ptrs[3] = sumsq_rows[2];
+        sumsq_ptrs[4] = sumsq_rows[3];
+        sum_ptrs[3] = sum_rows[2];
+        sum_ptrs[4] = sum_rows[3];
+
+        sgr_box5_row_h(sumsq_rows[2], sum_rows[2], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto odd;
+
+        sgr_box5_row_h(sumsq_rows[3], sum_rows[3], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                      w, params->sgr.s0, BITDEPTH_MAX);
+        sgr_finish2(&dst, stride, A_ptrs, B_ptrs,
+                    w, 2, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        // ptrs are rotated by 2; both [3] and [4] now point at rows[0]; set
+        // one of them to point at the previously unused rows[4].
+        sumsq_ptrs[3] = sumsq_rows[4];
+        sum_ptrs[3] = sum_rows[4];
+    }
+
+    do {
+        sgr_box5_row_h(sumsq_ptrs[3], sum_ptrs[3], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        if (--h <= 0)
+            goto odd;
+
+        sgr_box5_row_h(sumsq_ptrs[4], sum_ptrs[4], left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                      w, params->sgr.s0, BITDEPTH_MAX);
+        sgr_finish2(&dst, stride, A_ptrs, B_ptrs,
+                    w, 2, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+    } while (--h > 0);
+
+    if (!(edges & LR_HAVE_BOTTOM))
+        goto vert_2;
+
+    sgr_box5_row_h(sumsq_ptrs[3], sum_ptrs[3], NULL, lpf_bottom, w, edges);
+    lpf_bottom += PXSTRIDE(stride);
+    sgr_box5_row_h(sumsq_ptrs[4], sum_ptrs[4], NULL, lpf_bottom, w, edges);
+
+output_2:
+    sgr_box5_vert(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                  w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_finish2(&dst, stride, A_ptrs, B_ptrs,
+                w, 2, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_2:
+    // Duplicate the last row twice more
+    sumsq_ptrs[3] = sumsq_ptrs[2];
+    sumsq_ptrs[4] = sumsq_ptrs[2];
+    sum_ptrs[3] = sum_ptrs[2];
+    sum_ptrs[4] = sum_ptrs[2];
+    goto output_2;
+
+odd:
+    // Copy the last row as padding once
+    sumsq_ptrs[4] = sumsq_ptrs[3];
+    sum_ptrs[4] = sum_ptrs[3];
+
+    sgr_box5_vert(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                  w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_finish2(&dst, stride, A_ptrs, B_ptrs,
+                w, 2, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+
+output_1:
+    // Duplicate the last row twice more
+    sumsq_ptrs[3] = sumsq_ptrs[2];
+    sumsq_ptrs[4] = sumsq_ptrs[2];
+    sum_ptrs[3] = sum_ptrs[2];
+    sum_ptrs[4] = sum_ptrs[2];
+
+    sgr_box5_vert(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                  w, params->sgr.s0, BITDEPTH_MAX);
+    // Output only one row
+    sgr_finish2(&dst, stride, A_ptrs, B_ptrs,
+                w, 1, params->sgr.w0 HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_1:
+    // Copy the last row as padding once
+    sumsq_ptrs[4] = sumsq_ptrs[3];
+    sum_ptrs[4] = sum_ptrs[3];
+
+    sgr_box5_vert(sumsq_ptrs, sum_ptrs, A_ptrs[1], B_ptrs[1],
+                  w, params->sgr.s0, BITDEPTH_MAX);
+    rotate(A_ptrs, B_ptrs, 2);
+
+    goto output_1;
+}
+
+static void sgr_mix_c(pixel *dst, const ptrdiff_t stride,
+                      const pixel (*left)[4], const pixel *lpf,
+                      const int w, int h,
+                      const LooprestorationParams *const params,
+                      const enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX)
+{
+    ALIGN_STK_16(int32_t, sumsq5_buf, BUF_STRIDE * 5 + 16,);
+    ALIGN_STK_16(coef, sum5_buf, BUF_STRIDE * 5 + 16,);
+    int32_t *sumsq5_ptrs[5], *sumsq5_rows[5];
+    coef *sum5_ptrs[5], *sum5_rows[5];
+    for (int i = 0; i < 5; i++) {
+        sumsq5_rows[i] = &sumsq5_buf[i * BUF_STRIDE];
+        sum5_rows[i] = &sum5_buf[i * BUF_STRIDE];
+    }
+    ALIGN_STK_16(int32_t, sumsq3_buf, BUF_STRIDE * 3 + 16,);
+    ALIGN_STK_16(coef, sum3_buf, BUF_STRIDE * 3 + 16,);
+    int32_t *sumsq3_ptrs[3], *sumsq3_rows[3];
+    coef *sum3_ptrs[3], *sum3_rows[3];
+    for (int i = 0; i < 3; i++) {
+        sumsq3_rows[i] = &sumsq3_buf[i * BUF_STRIDE];
+        sum3_rows[i] = &sum3_buf[i * BUF_STRIDE];
+    }
+
+    ALIGN_STK_16(int32_t, A5_buf, BUF_STRIDE * 2 + 16,);
+    ALIGN_STK_16(coef, B5_buf, BUF_STRIDE * 2 + 16,);
+    int32_t *A5_ptrs[2];
+    coef *B5_ptrs[2];
+    for (int i = 0; i < 2; i++) {
+        A5_ptrs[i] = &A5_buf[i * BUF_STRIDE];
+        B5_ptrs[i] = &B5_buf[i * BUF_STRIDE];
+    }
+    ALIGN_STK_16(int32_t, A3_buf, BUF_STRIDE * 4 + 16,);
+    ALIGN_STK_16(coef, B3_buf, BUF_STRIDE * 4 + 16,);
+    int32_t *A3_ptrs[4];
+    coef *B3_ptrs[4];
+    for (int i = 0; i < 4; i++) {
+        A3_ptrs[i] = &A3_buf[i * BUF_STRIDE];
+        B3_ptrs[i] = &B3_buf[i * BUF_STRIDE];
+    }
+    const pixel *src = dst;
+    const pixel *lpf_bottom = lpf + 6*PXSTRIDE(stride);
+
+    if (edges & LR_HAVE_TOP) {
+        sumsq5_ptrs[0] = sumsq5_rows[0];
+        sumsq5_ptrs[1] = sumsq5_rows[0];
+        sumsq5_ptrs[2] = sumsq5_rows[1];
+        sumsq5_ptrs[3] = sumsq5_rows[2];
+        sumsq5_ptrs[4] = sumsq5_rows[3];
+        sum5_ptrs[0] = sum5_rows[0];
+        sum5_ptrs[1] = sum5_rows[0];
+        sum5_ptrs[2] = sum5_rows[1];
+        sum5_ptrs[3] = sum5_rows[2];
+        sum5_ptrs[4] = sum5_rows[3];
+
+        sumsq3_ptrs[0] = sumsq3_rows[0];
+        sumsq3_ptrs[1] = sumsq3_rows[1];
+        sumsq3_ptrs[2] = sumsq3_rows[2];
+        sum3_ptrs[0] = sum3_rows[0];
+        sum3_ptrs[1] = sum3_rows[1];
+        sum3_ptrs[2] = sum3_rows[2];
+
+        sgr_box35_row_h(sumsq3_rows[0], sum3_rows[0],
+                        sumsq5_rows[0], sum5_rows[0],
+                        NULL, lpf, w, edges);
+        lpf += PXSTRIDE(stride);
+        sgr_box35_row_h(sumsq3_rows[1], sum3_rows[1],
+                        sumsq5_rows[1], sum5_rows[1],
+                        NULL, lpf, w, edges);
+
+        sgr_box35_row_h(sumsq3_rows[2], sum3_rows[2],
+                        sumsq5_rows[2], sum5_rows[2],
+                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        rotate(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sgr_box35_row_h(sumsq3_ptrs[2], sum3_ptrs[2],
+                        sumsq5_rows[3], sum5_rows[3],
+                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+        sgr_box5_vert(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                      w, params->sgr.s0, BITDEPTH_MAX);
+        rotate(A5_ptrs, B5_ptrs, 2);
+        sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        rotate(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        // ptrs are rotated by 2; both [3] and [4] now point at rows[0]; set
+        // one of them to point at the previously unused rows[4].
+        sumsq5_ptrs[3] = sumsq5_rows[4];
+        sum5_ptrs[3] = sum5_rows[4];
+    } else {
+        sumsq5_ptrs[0] = sumsq5_rows[0];
+        sumsq5_ptrs[1] = sumsq5_rows[0];
+        sumsq5_ptrs[2] = sumsq5_rows[0];
+        sumsq5_ptrs[3] = sumsq5_rows[0];
+        sumsq5_ptrs[4] = sumsq5_rows[0];
+        sum5_ptrs[0] = sum5_rows[0];
+        sum5_ptrs[1] = sum5_rows[0];
+        sum5_ptrs[2] = sum5_rows[0];
+        sum5_ptrs[3] = sum5_rows[0];
+        sum5_ptrs[4] = sum5_rows[0];
+
+        sumsq3_ptrs[0] = sumsq3_rows[0];
+        sumsq3_ptrs[1] = sumsq3_rows[0];
+        sumsq3_ptrs[2] = sumsq3_rows[0];
+        sum3_ptrs[0] = sum3_rows[0];
+        sum3_ptrs[1] = sum3_rows[0];
+        sum3_ptrs[2] = sum3_rows[0];
+
+        sgr_box35_row_h(sumsq3_rows[0], sum3_rows[0],
+                        sumsq5_rows[0], sum5_rows[0],
+                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        rotate(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto vert_1;
+
+        sumsq5_ptrs[4] = sumsq5_rows[1];
+        sum5_ptrs[4] = sum5_rows[1];
+
+        sumsq3_ptrs[2] = sumsq3_rows[1];
+        sum3_ptrs[2] = sum3_rows[1];
+
+        sgr_box35_row_h(sumsq3_rows[1], sum3_rows[1],
+                        sumsq5_rows[1], sum5_rows[1],
+                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                      w, params->sgr.s0, BITDEPTH_MAX);
+        rotate(A5_ptrs, B5_ptrs, 2);
+        sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        rotate(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        sumsq5_ptrs[3] = sumsq5_rows[2];
+        sumsq5_ptrs[4] = sumsq5_rows[3];
+        sum5_ptrs[3] = sum5_rows[2];
+        sum5_ptrs[4] = sum5_rows[3];
+
+        sumsq3_ptrs[2] = sumsq3_rows[2];
+        sum3_ptrs[2] = sum3_rows[2];
+
+        sgr_box35_row_h(sumsq3_rows[2], sum3_rows[2],
+                        sumsq5_rows[2], sum5_rows[2],
+                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        rotate(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto odd;
+
+        sgr_box35_row_h(sumsq3_ptrs[2], sum3_ptrs[2],
+                        sumsq5_rows[3], sum5_rows[3],
+                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                      w, params->sgr.s0, BITDEPTH_MAX);
+        sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        sgr_finish_mix(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                       w, 2, params->sgr.w0, params->sgr.w1
+                       HIGHBD_TAIL_SUFFIX);
+
+        if (--h <= 0)
+            goto vert_2;
+
+        // ptrs are rotated by 2; both [3] and [4] now point at rows[0]; set
+        // one of them to point at the previously unused rows[4].
+        sumsq5_ptrs[3] = sumsq5_rows[4];
+        sum5_ptrs[3] = sum5_rows[4];
+    }
+
+    do {
+        sgr_box35_row_h(sumsq3_ptrs[2], sum3_ptrs[2],
+                        sumsq5_ptrs[3], sum5_ptrs[3],
+                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        rotate(A3_ptrs, B3_ptrs, 4);
+
+        if (--h <= 0)
+            goto odd;
+
+        sgr_box35_row_h(sumsq3_ptrs[2], sum3_ptrs[2],
+                        sumsq5_ptrs[4], sum5_ptrs[4],
+                        left, src, w, edges);
+        left++;
+        src += PXSTRIDE(stride);
+
+        sgr_box5_vert(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                      w, params->sgr.s0, BITDEPTH_MAX);
+        sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                      w, params->sgr.s1, BITDEPTH_MAX);
+        sgr_finish_mix(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                       w, 2, params->sgr.w0, params->sgr.w1
+                       HIGHBD_TAIL_SUFFIX);
+    } while (--h > 0);
+
+    if (!(edges & LR_HAVE_BOTTOM))
+        goto vert_2;
+
+    sgr_box35_row_h(sumsq3_ptrs[2], sum3_ptrs[2],
+                    sumsq5_ptrs[3], sum5_ptrs[3],
+                    NULL, lpf_bottom, w, edges);
+    lpf_bottom += PXSTRIDE(stride);
+    sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+    rotate(A3_ptrs, B3_ptrs, 4);
+
+    sgr_box35_row_h(sumsq3_ptrs[2], sum3_ptrs[2],
+                    sumsq5_ptrs[4], sum5_ptrs[4],
+                    NULL, lpf_bottom, w, edges);
+
+output_2:
+    sgr_box5_vert(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                  w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+    sgr_finish_mix(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                   w, 2, params->sgr.w0, params->sgr.w1
+                   HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_2:
+    // Duplicate the last row twice more
+    sumsq5_ptrs[3] = sumsq5_ptrs[2];
+    sumsq5_ptrs[4] = sumsq5_ptrs[2];
+    sum5_ptrs[3] = sum5_ptrs[2];
+    sum5_ptrs[4] = sum5_ptrs[2];
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+    sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+    rotate(A3_ptrs, B3_ptrs, 4);
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+
+    goto output_2;
+
+odd:
+    // Copy the last row as padding once
+    sumsq5_ptrs[4] = sumsq5_ptrs[3];
+    sum5_ptrs[4] = sum5_ptrs[3];
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+
+    sgr_box5_vert(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                  w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+    sgr_finish_mix(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                   w, 2, params->sgr.w0, params->sgr.w1
+                   HIGHBD_TAIL_SUFFIX);
+
+output_1:
+    // Duplicate the last row twice more
+    sumsq5_ptrs[3] = sumsq5_ptrs[2];
+    sumsq5_ptrs[4] = sumsq5_ptrs[2];
+    sum5_ptrs[3] = sum5_ptrs[2];
+    sum5_ptrs[4] = sum5_ptrs[2];
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+
+    sgr_box5_vert(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                  w, params->sgr.s0, BITDEPTH_MAX);
+    sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+    rotate(A3_ptrs, B3_ptrs, 4);
+    // Output only one row
+    sgr_finish_mix(&dst, stride, A5_ptrs, B5_ptrs, A3_ptrs, B3_ptrs,
+                   w, 1, params->sgr.w0, params->sgr.w1
+                   HIGHBD_TAIL_SUFFIX);
+    return;
+
+vert_1:
+    // Copy the last row as padding once
+    sumsq5_ptrs[4] = sumsq5_ptrs[3];
+    sum5_ptrs[4] = sum5_ptrs[3];
+
+    sumsq3_ptrs[2] = sumsq3_ptrs[1];
+    sum3_ptrs[2] = sum3_ptrs[1];
+
+    sgr_box5_vert(sumsq5_ptrs, sum5_ptrs, A5_ptrs[1], B5_ptrs[1],
+                  w, params->sgr.s0, BITDEPTH_MAX);
+    rotate(A5_ptrs, B5_ptrs, 2);
+    sgr_box3_vert(sumsq3_ptrs, sum3_ptrs, A3_ptrs[3], B3_ptrs[3],
+                  w, params->sgr.s1, BITDEPTH_MAX);
+    rotate(A3_ptrs, B3_ptrs, 4);
+
+    goto output_1;
+}
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/looprestoration.h"
+#elif ARCH_LOONGARCH64
+#include "src/loongarch/looprestoration.h"
+#elif ARCH_PPC64LE
+#include "src/ppc/looprestoration.h"
+#elif ARCH_X86
+#include "src/x86/looprestoration.h"
+#endif
+#endif
+
+COLD void bitfn(dav1d_loop_restoration_dsp_init)(Dav1dLoopRestorationDSPContext *const c,
+                                                 const int bpc)
+{
+    c->wiener[0] = c->wiener[1] = wiener_c;
+    c->sgr[0] = sgr_5x5_c;
+    c->sgr[1] = sgr_3x3_c;
+    c->sgr[2] = sgr_mix_c;
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+    loop_restoration_dsp_init_arm(c, bpc);
+#elif ARCH_LOONGARCH64
+    loop_restoration_dsp_init_loongarch(c, bpc);
+#elif ARCH_PPC64LE
+    loop_restoration_dsp_init_ppc(c, bpc);
+#elif ARCH_X86
+    loop_restoration_dsp_init_x86(c, bpc);
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/lr_apply.h b/media/libdav1d/src/src/lr_apply.h
new file mode 100644
index 0000000000..2815367534
--- /dev/null
+++ b/media/libdav1d/src/src/lr_apply.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_LR_APPLY_H
+#define DAV1D_SRC_LR_APPLY_H
+
+#include 
+#include 
+
+#include "common/bitdepth.h"
+
+#include "src/internal.h"
+
+enum LrRestorePlanes {
+    LR_RESTORE_Y = 1 << 0,
+    LR_RESTORE_U = 1 << 1,
+    LR_RESTORE_V = 1 << 2,
+};
+
+void bytefn(dav1d_lr_sbrow)(Dav1dFrameContext *const f, pixel *const dst[3],
+                            int sby);
+
+#endif /* DAV1D_SRC_LR_APPLY_H */
diff --git a/media/libdav1d/src/src/lr_apply_tmpl.c b/media/libdav1d/src/src/lr_apply_tmpl.c
new file mode 100644
index 0000000000..ec0acdf605
--- /dev/null
+++ b/media/libdav1d/src/src/lr_apply_tmpl.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/lr_apply.h"
+
+static void lr_stripe(const Dav1dFrameContext *const f, pixel *p,
+                      const pixel (*left)[4], int x, int y,
+                      const int plane, const int unit_w, const int row_h,
+                      const Av1RestorationUnit *const lr, enum LrEdgeFlags edges)
+{
+    const Dav1dDSPContext *const dsp = f->dsp;
+    const int chroma = !!plane;
+    const int ss_ver = chroma & (f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420);
+    const ptrdiff_t stride = f->sr_cur.p.stride[chroma];
+    const int sby = (y + (y ? 8 << ss_ver : 0)) >> (6 - ss_ver + f->seq_hdr->sb128);
+    const int have_tt = f->c->n_tc > 1;
+    const pixel *lpf = f->lf.lr_lpf_line[plane] +
+        have_tt * (sby * (4 << f->seq_hdr->sb128) - 4) * PXSTRIDE(stride) + x;
+
+    // The first stripe of the frame is shorter by 8 luma pixel rows.
+    int stripe_h = imin((64 - 8 * !y) >> ss_ver, row_h - y);
+
+    looprestorationfilter_fn lr_fn;
+    LooprestorationParams params;
+    if (lr->type == DAV1D_RESTORATION_WIENER) {
+        int16_t (*const filter)[8] = params.filter;
+        filter[0][0] = filter[0][6] = lr->filter_h[0];
+        filter[0][1] = filter[0][5] = lr->filter_h[1];
+        filter[0][2] = filter[0][4] = lr->filter_h[2];
+        filter[0][3] = -(filter[0][0] + filter[0][1] + filter[0][2]) * 2;
+#if BITDEPTH != 8
+        /* For 8-bit SIMD it's beneficial to handle the +128 separately
+         * in order to avoid overflows. */
+        filter[0][3] += 128;
+#endif
+
+        filter[1][0] = filter[1][6] = lr->filter_v[0];
+        filter[1][1] = filter[1][5] = lr->filter_v[1];
+        filter[1][2] = filter[1][4] = lr->filter_v[2];
+        filter[1][3] = 128 - (filter[1][0] + filter[1][1] + filter[1][2]) * 2;
+
+        lr_fn = dsp->lr.wiener[!(filter[0][0] | filter[1][0])];
+    } else {
+        assert(lr->type >= DAV1D_RESTORATION_SGRPROJ);
+        const int sgr_idx = lr->type - DAV1D_RESTORATION_SGRPROJ;
+        const uint16_t *const sgr_params = dav1d_sgr_params[sgr_idx];
+        params.sgr.s0 = sgr_params[0];
+        params.sgr.s1 = sgr_params[1];
+        params.sgr.w0 = lr->sgr_weights[0];
+        params.sgr.w1 = 128 - (lr->sgr_weights[0] + lr->sgr_weights[1]);
+
+        lr_fn = dsp->lr.sgr[!!sgr_params[0] + !!sgr_params[1] * 2 - 1];
+    }
+
+    while (y + stripe_h <= row_h) {
+        // Change the HAVE_BOTTOM bit in edges to (sby + 1 != f->sbh || y + stripe_h != row_h)
+        edges ^= (-(sby + 1 != f->sbh || y + stripe_h != row_h) ^ edges) & LR_HAVE_BOTTOM;
+        lr_fn(p, stride, left, lpf, unit_w, stripe_h, ¶ms, edges HIGHBD_CALL_SUFFIX);
+
+        left += stripe_h;
+        y += stripe_h;
+        p += stripe_h * PXSTRIDE(stride);
+        edges |= LR_HAVE_TOP;
+        stripe_h = imin(64 >> ss_ver, row_h - y);
+        if (stripe_h == 0) break;
+        lpf += 4 * PXSTRIDE(stride);
+    }
+}
+
+static void backup4xU(pixel (*dst)[4], const pixel *src, const ptrdiff_t src_stride,
+                      int u)
+{
+    for (; u > 0; u--, dst++, src += PXSTRIDE(src_stride))
+        pixel_copy(dst, src, 4);
+}
+
+static void lr_sbrow(const Dav1dFrameContext *const f, pixel *p, const int y,
+                     const int w, const int h, const int row_h, const int plane)
+{
+    const int chroma = !!plane;
+    const int ss_ver = chroma & (f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420);
+    const int ss_hor = chroma & (f->sr_cur.p.p.layout != DAV1D_PIXEL_LAYOUT_I444);
+    const ptrdiff_t p_stride = f->sr_cur.p.stride[chroma];
+
+    const int unit_size_log2 = f->frame_hdr->restoration.unit_size[!!plane];
+    const int unit_size = 1 << unit_size_log2;
+    const int half_unit_size = unit_size >> 1;
+    const int max_unit_size = unit_size + half_unit_size;
+
+    // Y coordinate of the sbrow (y is 8 luma pixel rows above row_y)
+    const int row_y = y + ((8 >> ss_ver) * !!y);
+
+    // FIXME This is an ugly hack to lookup the proper AV1Filter unit for
+    // chroma planes. Question: For Multithreaded decoding, is it better
+    // to store the chroma LR information with collocated Luma information?
+    // In other words. For a chroma restoration unit locate at 128,128 and
+    // with a 4:2:0 chroma subsampling, do we store the filter information at
+    // the AV1Filter unit located at (128,128) or (256,256)
+    // TODO Support chroma subsampling.
+    const int shift_hor = 7 - ss_hor;
+
+    /* maximum sbrow height is 128 + 8 rows offset */
+    ALIGN_STK_16(pixel, pre_lr_border, 2, [128 + 8][4]);
+    const Av1RestorationUnit *lr[2];
+
+    enum LrEdgeFlags edges = (y > 0 ? LR_HAVE_TOP : 0) | LR_HAVE_RIGHT;
+
+    int aligned_unit_pos = row_y & ~(unit_size - 1);
+    if (aligned_unit_pos && aligned_unit_pos + half_unit_size > h)
+        aligned_unit_pos -= unit_size;
+    aligned_unit_pos <<= ss_ver;
+    const int sb_idx = (aligned_unit_pos >> 7) * f->sr_sb128w;
+    const int unit_idx = ((aligned_unit_pos >> 6) & 1) << 1;
+    lr[0] = &f->lf.lr_mask[sb_idx].lr[plane][unit_idx];
+    int restore = lr[0]->type != DAV1D_RESTORATION_NONE;
+    int x = 0, bit = 0;
+    for (; x + max_unit_size <= w; p += unit_size, edges |= LR_HAVE_LEFT, bit ^= 1) {
+        const int next_x = x + unit_size;
+        const int next_u_idx = unit_idx + ((next_x >> (shift_hor - 1)) & 1);
+        lr[!bit] =
+            &f->lf.lr_mask[sb_idx + (next_x >> shift_hor)].lr[plane][next_u_idx];
+        const int restore_next = lr[!bit]->type != DAV1D_RESTORATION_NONE;
+        if (restore_next)
+            backup4xU(pre_lr_border[bit], p + unit_size - 4, p_stride, row_h - y);
+        if (restore)
+            lr_stripe(f, p, pre_lr_border[!bit], x, y, plane, unit_size, row_h,
+                      lr[bit], edges);
+        x = next_x;
+        restore = restore_next;
+    }
+    if (restore) {
+        edges &= ~LR_HAVE_RIGHT;
+        const int unit_w = w - x;
+        lr_stripe(f, p, pre_lr_border[!bit], x, y, plane, unit_w, row_h, lr[bit], edges);
+    }
+}
+
+void bytefn(dav1d_lr_sbrow)(Dav1dFrameContext *const f, pixel *const dst[3],
+                            const int sby)
+{
+    const int offset_y = 8 * !!sby;
+    const ptrdiff_t *const dst_stride = f->sr_cur.p.stride;
+    const int restore_planes = f->lf.restore_planes;
+    const int not_last = sby + 1 < f->sbh;
+
+    if (restore_planes & LR_RESTORE_Y) {
+        const int h = f->sr_cur.p.p.h;
+        const int w = f->sr_cur.p.p.w;
+        const int next_row_y = (sby + 1) << (6 + f->seq_hdr->sb128);
+        const int row_h = imin(next_row_y - 8 * not_last, h);
+        const int y_stripe = (sby << (6 + f->seq_hdr->sb128)) - offset_y;
+        lr_sbrow(f, dst[0] - offset_y * PXSTRIDE(dst_stride[0]), y_stripe, w,
+                 h, row_h, 0);
+    }
+    if (restore_planes & (LR_RESTORE_U | LR_RESTORE_V)) {
+        const int ss_ver = f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = f->sr_cur.p.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int h = (f->sr_cur.p.p.h + ss_ver) >> ss_ver;
+        const int w = (f->sr_cur.p.p.w + ss_hor) >> ss_hor;
+        const int next_row_y = (sby + 1) << ((6 - ss_ver) + f->seq_hdr->sb128);
+        const int row_h = imin(next_row_y - (8 >> ss_ver) * not_last, h);
+        const int offset_uv = offset_y >> ss_ver;
+        const int y_stripe = (sby << ((6 - ss_ver) + f->seq_hdr->sb128)) - offset_uv;
+        if (restore_planes & LR_RESTORE_U)
+            lr_sbrow(f, dst[1] - offset_uv * PXSTRIDE(dst_stride[1]), y_stripe,
+                     w, h, row_h, 1);
+
+        if (restore_planes & LR_RESTORE_V)
+            lr_sbrow(f, dst[2] - offset_uv * PXSTRIDE(dst_stride[1]), y_stripe,
+                     w, h, row_h, 2);
+    }
+}
diff --git a/media/libdav1d/src/src/mc.h b/media/libdav1d/src/src/mc.h
new file mode 100644
index 0000000000..587b9080c6
--- /dev/null
+++ b/media/libdav1d/src/src/mc.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_MC_H
+#define DAV1D_SRC_MC_H
+
+#include 
+#include 
+
+#include "common/bitdepth.h"
+
+#include "src/levels.h"
+
+#define decl_mc_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const pixel *src, ptrdiff_t src_stride, \
+            int w, int h, int mx, int my HIGHBD_DECL_SUFFIX)
+typedef decl_mc_fn(*mc_fn);
+
+#define decl_mc_scaled_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const pixel *src, ptrdiff_t src_stride, \
+            int w, int h, int mx, int my, int dx, int dy HIGHBD_DECL_SUFFIX)
+typedef decl_mc_scaled_fn(*mc_scaled_fn);
+
+#define decl_warp8x8_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const pixel *src, ptrdiff_t src_stride, \
+            const int16_t *abcd, int mx, int my HIGHBD_DECL_SUFFIX)
+typedef decl_warp8x8_fn(*warp8x8_fn);
+
+#define decl_mct_fn(name) \
+void (name)(int16_t *tmp, const pixel *src, ptrdiff_t src_stride, \
+            int w, int h, int mx, int my HIGHBD_DECL_SUFFIX)
+typedef decl_mct_fn(*mct_fn);
+
+#define decl_mct_scaled_fn(name) \
+void (name)(int16_t *tmp, const pixel *src, ptrdiff_t src_stride, \
+            int w, int h, int mx, int my, int dx, int dy HIGHBD_DECL_SUFFIX)
+typedef decl_mct_scaled_fn(*mct_scaled_fn);
+
+#define decl_warp8x8t_fn(name) \
+void (name)(int16_t *tmp, const ptrdiff_t tmp_stride, \
+            const pixel *src, ptrdiff_t src_stride, \
+            const int16_t *abcd, int mx, int my HIGHBD_DECL_SUFFIX)
+typedef decl_warp8x8t_fn(*warp8x8t_fn);
+
+#define decl_avg_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const int16_t *tmp1, const int16_t *tmp2, int w, int h \
+            HIGHBD_DECL_SUFFIX)
+typedef decl_avg_fn(*avg_fn);
+
+#define decl_w_avg_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const int16_t *tmp1, const int16_t *tmp2, int w, int h, int weight \
+            HIGHBD_DECL_SUFFIX)
+typedef decl_w_avg_fn(*w_avg_fn);
+
+#define decl_mask_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const int16_t *tmp1, const int16_t *tmp2, int w, int h, \
+            const uint8_t *mask HIGHBD_DECL_SUFFIX)
+typedef decl_mask_fn(*mask_fn);
+
+#define decl_w_mask_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const int16_t *tmp1, const int16_t *tmp2, int w, int h, \
+            uint8_t *mask, int sign HIGHBD_DECL_SUFFIX)
+typedef decl_w_mask_fn(*w_mask_fn);
+
+#define decl_blend_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, const pixel *tmp, \
+            int w, int h, const uint8_t *mask)
+typedef decl_blend_fn(*blend_fn);
+
+#define decl_blend_dir_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, const pixel *tmp, int w, int h)
+typedef decl_blend_dir_fn(*blend_dir_fn);
+
+#define decl_emu_edge_fn(name) \
+void (name)(intptr_t bw, intptr_t bh, intptr_t iw, intptr_t ih, intptr_t x, intptr_t y, \
+            pixel *dst, ptrdiff_t dst_stride, const pixel *src, ptrdiff_t src_stride)
+typedef decl_emu_edge_fn(*emu_edge_fn);
+
+#define decl_resize_fn(name) \
+void (name)(pixel *dst, ptrdiff_t dst_stride, \
+            const pixel *src, ptrdiff_t src_stride, \
+            int dst_w, int h, int src_w, int dx, int mx HIGHBD_DECL_SUFFIX)
+typedef decl_resize_fn(*resize_fn);
+
+#define decl_8tap_gen(decl_name, fn_name, opt) \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_regular,        opt)); \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_regular_smooth, opt)); \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_regular_sharp,  opt)); \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_smooth_regular, opt)); \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_smooth,         opt)); \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_smooth_sharp,   opt)); \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_sharp_regular,  opt)); \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_sharp_smooth,   opt)); \
+    decl_##decl_name##_fn(BF(dav1d_##fn_name##_8tap_sharp,          opt))
+
+#define decl_8tap_fns(opt) \
+    decl_8tap_gen(mc,  put,  opt); \
+    decl_8tap_gen(mct, prep, opt)
+
+#define init_8tap_gen(name, opt) \
+    init_##name##_fn(FILTER_2D_8TAP_REGULAR,        8tap_regular,        opt); \
+    init_##name##_fn(FILTER_2D_8TAP_REGULAR_SMOOTH, 8tap_regular_smooth, opt); \
+    init_##name##_fn(FILTER_2D_8TAP_REGULAR_SHARP,  8tap_regular_sharp,  opt); \
+    init_##name##_fn(FILTER_2D_8TAP_SMOOTH_REGULAR, 8tap_smooth_regular, opt); \
+    init_##name##_fn(FILTER_2D_8TAP_SMOOTH,         8tap_smooth,         opt); \
+    init_##name##_fn(FILTER_2D_8TAP_SMOOTH_SHARP,   8tap_smooth_sharp,   opt); \
+    init_##name##_fn(FILTER_2D_8TAP_SHARP_REGULAR,  8tap_sharp_regular,  opt); \
+    init_##name##_fn(FILTER_2D_8TAP_SHARP_SMOOTH,   8tap_sharp_smooth,   opt); \
+    init_##name##_fn(FILTER_2D_8TAP_SHARP,          8tap_sharp,          opt)
+
+#define init_8tap_fns(opt) \
+    init_8tap_gen(mc,  opt); \
+    init_8tap_gen(mct, opt)
+
+typedef struct Dav1dMCDSPContext {
+    mc_fn mc[N_2D_FILTERS];
+    mc_scaled_fn mc_scaled[N_2D_FILTERS];
+    mct_fn mct[N_2D_FILTERS];
+    mct_scaled_fn mct_scaled[N_2D_FILTERS];
+    avg_fn avg;
+    w_avg_fn w_avg;
+    mask_fn mask;
+    w_mask_fn w_mask[3 /* 444, 422, 420 */];
+    blend_fn blend;
+    blend_dir_fn blend_v;
+    blend_dir_fn blend_h;
+    warp8x8_fn warp8x8;
+    warp8x8t_fn warp8x8t;
+    emu_edge_fn emu_edge;
+    resize_fn resize;
+} Dav1dMCDSPContext;
+
+bitfn_decls(void dav1d_mc_dsp_init, Dav1dMCDSPContext *c);
+
+#endif /* DAV1D_SRC_MC_H */
diff --git a/media/libdav1d/src/src/mc_tmpl.c b/media/libdav1d/src/src/mc_tmpl.c
new file mode 100644
index 0000000000..b936d94ccd
--- /dev/null
+++ b/media/libdav1d/src/src/mc_tmpl.c
@@ -0,0 +1,1006 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "src/mc.h"
+#include "src/tables.h"
+
+#if BITDEPTH == 8
+#define get_intermediate_bits(bitdepth_max) 4
+// Output in interval [-5132, 9212], fits in int16_t as is
+#define PREP_BIAS 0
+#else
+// 4 for 10 bits/component, 2 for 12 bits/component
+#define get_intermediate_bits(bitdepth_max) (14 - bitdepth_from_max(bitdepth_max))
+// Output in interval [-20588, 36956] (10-bit), [-20602, 36983] (12-bit)
+// Subtract a bias to ensure the output fits in int16_t
+#define PREP_BIAS 8192
+#endif
+
+static NOINLINE void
+put_c(pixel *dst, const ptrdiff_t dst_stride,
+      const pixel *src, const ptrdiff_t src_stride, const int w, int h)
+{
+    do {
+        pixel_copy(dst, src, w);
+
+        dst += dst_stride;
+        src += src_stride;
+    } while (--h);
+}
+
+static NOINLINE void
+prep_c(int16_t *tmp, const pixel *src, const ptrdiff_t src_stride,
+       const int w, int h HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    do {
+        for (int x = 0; x < w; x++)
+            tmp[x] = (src[x] << intermediate_bits) - PREP_BIAS;
+
+        tmp += w;
+        src += src_stride;
+    } while (--h);
+}
+
+#define FILTER_8TAP(src, x, F, stride) \
+    (F[0] * src[x + -3 * stride] + \
+     F[1] * src[x + -2 * stride] + \
+     F[2] * src[x + -1 * stride] + \
+     F[3] * src[x + +0 * stride] + \
+     F[4] * src[x + +1 * stride] + \
+     F[5] * src[x + +2 * stride] + \
+     F[6] * src[x + +3 * stride] + \
+     F[7] * src[x + +4 * stride])
+
+#define FILTER_8TAP2(src, x, F) \
+    (F[0] * src[0][x] + \
+     F[1] * src[1][x] + \
+     F[2] * src[2][x] + \
+     F[3] * src[3][x] + \
+     F[4] * src[4][x] + \
+     F[5] * src[5][x] + \
+     F[6] * src[6][x] + \
+     F[7] * src[7][x])
+
+#define DAV1D_FILTER_8TAP_RND(src, x, F, stride, sh) \
+    ((FILTER_8TAP(src, x, F, stride) + ((1 << (sh)) >> 1)) >> (sh))
+
+#define DAV1D_FILTER_8TAP_RND2(src, x, F, stride, rnd, sh) \
+    ((FILTER_8TAP(src, x, F, stride) + (rnd)) >> (sh))
+
+#define DAV1D_FILTER_8TAP_RND3(src, x, F, sh) \
+    ((FILTER_8TAP2(src, x, F) + ((1 << (sh)) >> 1)) >> (sh))
+
+#define DAV1D_FILTER_8TAP_CLIP(src, x, F, stride, sh) \
+    iclip_pixel(DAV1D_FILTER_8TAP_RND(src, x, F, stride, sh))
+
+#define DAV1D_FILTER_8TAP_CLIP2(src, x, F, stride, rnd, sh) \
+    iclip_pixel(DAV1D_FILTER_8TAP_RND2(src, x, F, stride, rnd, sh))
+
+#define DAV1D_FILTER_8TAP_CLIP3(src, x, F, sh) \
+    iclip_pixel(DAV1D_FILTER_8TAP_RND3(src, x, F, sh))
+
+#define GET_H_FILTER(mx) \
+    const int8_t *const fh = !(mx) ? NULL : w > 4 ? \
+        dav1d_mc_subpel_filters[filter_type & 3][(mx) - 1] : \
+        dav1d_mc_subpel_filters[3 + (filter_type & 1)][(mx) - 1]
+
+#define GET_V_FILTER(my) \
+    const int8_t *const fv = !(my) ? NULL : h > 4 ? \
+        dav1d_mc_subpel_filters[filter_type >> 2][(my) - 1] : \
+        dav1d_mc_subpel_filters[3 + ((filter_type >> 2) & 1)][(my) - 1]
+
+#define GET_FILTERS() \
+    GET_H_FILTER(mx); \
+    GET_V_FILTER(my)
+
+static NOINLINE void
+put_8tap_c(pixel *dst, ptrdiff_t dst_stride,
+           const pixel *src, ptrdiff_t src_stride,
+           const int w, int h, const int mx, const int my,
+           const int filter_type HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    const int intermediate_rnd = 32 + ((1 << (6 - intermediate_bits)) >> 1);
+
+    GET_FILTERS();
+    dst_stride = PXSTRIDE(dst_stride);
+    src_stride = PXSTRIDE(src_stride);
+
+    if (fh) {
+        if (fv) {
+            int tmp_h = h + 7;
+            int16_t mid[128 * 135], *mid_ptr = mid;
+
+            src -= src_stride * 3;
+            do {
+                for (int x = 0; x < w; x++)
+                    mid_ptr[x] = DAV1D_FILTER_8TAP_RND(src, x, fh, 1,
+                                                       6 - intermediate_bits);
+
+                mid_ptr += 128;
+                src += src_stride;
+            } while (--tmp_h);
+
+            mid_ptr = mid + 128 * 3;
+            do {
+                for (int x = 0; x < w; x++)
+                    dst[x] = DAV1D_FILTER_8TAP_CLIP(mid_ptr, x, fv, 128,
+                                                    6 + intermediate_bits);
+
+                mid_ptr += 128;
+                dst += dst_stride;
+            } while (--h);
+        } else {
+            do {
+                for (int x = 0; x < w; x++) {
+                    dst[x] = DAV1D_FILTER_8TAP_CLIP2(src, x, fh, 1,
+                                                     intermediate_rnd, 6);
+                }
+
+                dst += dst_stride;
+                src += src_stride;
+            } while (--h);
+        }
+    } else if (fv) {
+        do {
+            for (int x = 0; x < w; x++)
+                dst[x] = DAV1D_FILTER_8TAP_CLIP(src, x, fv, src_stride, 6);
+
+            dst += dst_stride;
+            src += src_stride;
+        } while (--h);
+    } else
+        put_c(dst, dst_stride, src, src_stride, w, h);
+}
+
+static NOINLINE void
+put_8tap_scaled_c(pixel *dst, const ptrdiff_t dst_stride,
+                  const pixel *src, ptrdiff_t src_stride,
+                  const int w, int h, const int mx, int my,
+                  const int dx, const int dy, const int filter_type
+                  HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    const int intermediate_rnd = (1 << intermediate_bits) >> 1;
+    int16_t mid[128 * 8];
+    int16_t *mid_ptrs[8];
+    int in_y = -8;
+    src_stride = PXSTRIDE(src_stride);
+
+    for (int i = 0; i < 8; i++)
+        mid_ptrs[i] = &mid[128 * i];
+
+    src -= src_stride * 3;
+
+    for (int y = 0; y < h; y++) {
+        int x;
+        int src_y = my >> 10;
+        GET_V_FILTER((my & 0x3ff) >> 6);
+
+        while (in_y < src_y) {
+            int imx = mx, ioff = 0;
+            int16_t *mid_ptr = mid_ptrs[0];
+
+            for (int i = 0; i < 7; i++)
+                mid_ptrs[i] = mid_ptrs[i + 1];
+            mid_ptrs[7] = mid_ptr;
+
+            for (x = 0; x < w; x++) {
+                GET_H_FILTER(imx >> 6);
+                mid_ptr[x] = fh ? DAV1D_FILTER_8TAP_RND(src, ioff, fh, 1,
+                                                        6 - intermediate_bits) :
+                                  src[ioff] << intermediate_bits;
+                imx += dx;
+                ioff += imx >> 10;
+                imx &= 0x3ff;
+            }
+
+            src += src_stride;
+            in_y++;
+        }
+
+        for (x = 0; x < w; x++)
+            dst[x] = fv ? DAV1D_FILTER_8TAP_CLIP3(mid_ptrs, x, fv,
+                                                  6 + intermediate_bits) :
+                          iclip_pixel((mid_ptrs[3][x] + intermediate_rnd) >>
+                                              intermediate_bits);
+
+        my += dy;
+        dst += PXSTRIDE(dst_stride);
+    }
+}
+
+static NOINLINE void
+prep_8tap_c(int16_t *tmp, const pixel *src, ptrdiff_t src_stride,
+            const int w, int h, const int mx, const int my,
+            const int filter_type HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    GET_FILTERS();
+    src_stride = PXSTRIDE(src_stride);
+
+    if (fh) {
+        if (fv) {
+            int tmp_h = h + 7;
+            int16_t mid[128 * 135], *mid_ptr = mid;
+
+            src -= src_stride * 3;
+            do {
+                for (int x = 0; x < w; x++)
+                    mid_ptr[x] = DAV1D_FILTER_8TAP_RND(src, x, fh, 1,
+                                                       6 - intermediate_bits);
+
+                mid_ptr += 128;
+                src += src_stride;
+            } while (--tmp_h);
+
+            mid_ptr = mid + 128 * 3;
+            do {
+                for (int x = 0; x < w; x++) {
+                    int t = DAV1D_FILTER_8TAP_RND(mid_ptr, x, fv, 128, 6) -
+                                  PREP_BIAS;
+                    assert(t >= INT16_MIN && t <= INT16_MAX);
+                    tmp[x] = t;
+                }
+
+                mid_ptr += 128;
+                tmp += w;
+            } while (--h);
+        } else {
+            do {
+                for (int x = 0; x < w; x++)
+                    tmp[x] = DAV1D_FILTER_8TAP_RND(src, x, fh, 1,
+                                                   6 - intermediate_bits) -
+                             PREP_BIAS;
+
+                tmp += w;
+                src += src_stride;
+            } while (--h);
+        }
+    } else if (fv) {
+        do {
+            for (int x = 0; x < w; x++)
+                tmp[x] = DAV1D_FILTER_8TAP_RND(src, x, fv, src_stride,
+                                               6 - intermediate_bits) -
+                         PREP_BIAS;
+
+            tmp += w;
+            src += src_stride;
+        } while (--h);
+    } else
+        prep_c(tmp, src, src_stride, w, h HIGHBD_TAIL_SUFFIX);
+}
+
+static NOINLINE void
+prep_8tap_scaled_c(int16_t *tmp, const pixel *src, ptrdiff_t src_stride,
+                   const int w, int h, const int mx, int my,
+                   const int dx, const int dy, const int filter_type
+                   HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    int16_t mid[128 * 8];
+    int16_t *mid_ptrs[8];
+    int in_y = -8;
+    src_stride = PXSTRIDE(src_stride);
+
+    for (int i = 0; i < 8; i++)
+        mid_ptrs[i] = &mid[128 * i];
+
+    src -= src_stride * 3;
+
+    for (int y = 0; y < h; y++) {
+        int x;
+        int src_y = my >> 10;
+        GET_V_FILTER((my & 0x3ff) >> 6);
+
+        while (in_y < src_y) {
+            int imx = mx, ioff = 0;
+            int16_t *mid_ptr = mid_ptrs[0];
+
+            for (int i = 0; i < 7; i++)
+                mid_ptrs[i] = mid_ptrs[i + 1];
+            mid_ptrs[7] = mid_ptr;
+
+            for (x = 0; x < w; x++) {
+                GET_H_FILTER(imx >> 6);
+                mid_ptr[x] = fh ? DAV1D_FILTER_8TAP_RND(src, ioff, fh, 1,
+                                                        6 - intermediate_bits) :
+                                  src[ioff] << intermediate_bits;
+                imx += dx;
+                ioff += imx >> 10;
+                imx &= 0x3ff;
+            }
+
+            src += src_stride;
+            in_y++;
+        }
+
+        for (x = 0; x < w; x++)
+            tmp[x] = (fv ? DAV1D_FILTER_8TAP_RND3(mid_ptrs, x, fv, 6)
+                         : mid_ptrs[3][x]) - PREP_BIAS;
+
+        my += dy;
+        tmp += w;
+    }
+}
+
+#define filter_fns(type, type_h, type_v) \
+static void put_8tap_##type##_c(pixel *const dst, \
+                                const ptrdiff_t dst_stride, \
+                                const pixel *const src, \
+                                const ptrdiff_t src_stride, \
+                                const int w, const int h, \
+                                const int mx, const int my \
+                                HIGHBD_DECL_SUFFIX) \
+{ \
+    put_8tap_c(dst, dst_stride, src, src_stride, w, h, mx, my, \
+               type_h | (type_v << 2) HIGHBD_TAIL_SUFFIX); \
+} \
+static void put_8tap_##type##_scaled_c(pixel *const dst, \
+                                       const ptrdiff_t dst_stride, \
+                                       const pixel *const src, \
+                                       const ptrdiff_t src_stride, \
+                                       const int w, const int h, \
+                                       const int mx, const int my, \
+                                       const int dx, const int dy \
+                                       HIGHBD_DECL_SUFFIX) \
+{ \
+    put_8tap_scaled_c(dst, dst_stride, src, src_stride, w, h, mx, my, dx, dy, \
+                      type_h | (type_v << 2) HIGHBD_TAIL_SUFFIX); \
+} \
+static void prep_8tap_##type##_c(int16_t *const tmp, \
+                                 const pixel *const src, \
+                                 const ptrdiff_t src_stride, \
+                                 const int w, const int h, \
+                                 const int mx, const int my \
+                                 HIGHBD_DECL_SUFFIX) \
+{ \
+    prep_8tap_c(tmp, src, src_stride, w, h, mx, my, \
+                type_h | (type_v << 2) HIGHBD_TAIL_SUFFIX); \
+} \
+static void prep_8tap_##type##_scaled_c(int16_t *const tmp, \
+                                        const pixel *const src, \
+                                        const ptrdiff_t src_stride, \
+                                        const int w, const int h, \
+                                        const int mx, const int my, \
+                                        const int dx, const int dy \
+                                        HIGHBD_DECL_SUFFIX) \
+{ \
+    prep_8tap_scaled_c(tmp, src, src_stride, w, h, mx, my, dx, dy, \
+                       type_h | (type_v << 2) HIGHBD_TAIL_SUFFIX); \
+}
+
+filter_fns(regular,        DAV1D_FILTER_8TAP_REGULAR, DAV1D_FILTER_8TAP_REGULAR)
+filter_fns(regular_sharp,  DAV1D_FILTER_8TAP_REGULAR, DAV1D_FILTER_8TAP_SHARP)
+filter_fns(regular_smooth, DAV1D_FILTER_8TAP_REGULAR, DAV1D_FILTER_8TAP_SMOOTH)
+filter_fns(smooth,         DAV1D_FILTER_8TAP_SMOOTH,  DAV1D_FILTER_8TAP_SMOOTH)
+filter_fns(smooth_regular, DAV1D_FILTER_8TAP_SMOOTH,  DAV1D_FILTER_8TAP_REGULAR)
+filter_fns(smooth_sharp,   DAV1D_FILTER_8TAP_SMOOTH,  DAV1D_FILTER_8TAP_SHARP)
+filter_fns(sharp,          DAV1D_FILTER_8TAP_SHARP,   DAV1D_FILTER_8TAP_SHARP)
+filter_fns(sharp_regular,  DAV1D_FILTER_8TAP_SHARP,   DAV1D_FILTER_8TAP_REGULAR)
+filter_fns(sharp_smooth,   DAV1D_FILTER_8TAP_SHARP,   DAV1D_FILTER_8TAP_SMOOTH)
+
+#define FILTER_BILIN(src, x, mxy, stride) \
+    (16 * src[x] + ((mxy) * (src[x + stride] - src[x])))
+
+#define FILTER_BILIN_RND(src, x, mxy, stride, sh) \
+    ((FILTER_BILIN(src, x, mxy, stride) + ((1 << (sh)) >> 1)) >> (sh))
+
+#define FILTER_BILIN_CLIP(src, x, mxy, stride, sh) \
+    iclip_pixel(FILTER_BILIN_RND(src, x, mxy, stride, sh))
+
+#define FILTER_BILIN2(src1, src2, x, mxy) \
+    (16 * src1[x] + ((mxy) * (src2[x] - src1[x])))
+
+#define FILTER_BILIN_RND2(src1, src2, x, mxy, sh) \
+    ((FILTER_BILIN2(src1, src2, x, mxy) + ((1 << (sh)) >> 1)) >> (sh))
+
+#define FILTER_BILIN_CLIP2(src1, src2, x, mxy, sh) \
+    iclip_pixel(FILTER_BILIN_RND2(src1, src2, x, mxy, sh))
+
+static void put_bilin_c(pixel *dst, ptrdiff_t dst_stride,
+                        const pixel *src, ptrdiff_t src_stride,
+                        const int w, int h, const int mx, const int my
+                        HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    const int intermediate_rnd = (1 << intermediate_bits) >> 1;
+    dst_stride = PXSTRIDE(dst_stride);
+    src_stride = PXSTRIDE(src_stride);
+
+    if (mx) {
+        if (my) {
+            int16_t mid[128 * 129], *mid_ptr = mid;
+            int tmp_h = h + 1;
+
+            do {
+                for (int x = 0; x < w; x++)
+                    mid_ptr[x] = FILTER_BILIN_RND(src, x, mx, 1,
+                                                  4 - intermediate_bits);
+
+                mid_ptr += 128;
+                src += src_stride;
+            } while (--tmp_h);
+
+            mid_ptr = mid;
+            do {
+                for (int x = 0; x < w; x++)
+                    dst[x] = FILTER_BILIN_CLIP(mid_ptr, x, my, 128,
+                                               4 + intermediate_bits);
+
+                mid_ptr += 128;
+                dst += dst_stride;
+            } while (--h);
+        } else {
+            do {
+                for (int x = 0; x < w; x++) {
+                    const int px = FILTER_BILIN_RND(src, x, mx, 1,
+                                                    4 - intermediate_bits);
+                    dst[x] = iclip_pixel((px + intermediate_rnd) >> intermediate_bits);
+                }
+
+                dst += dst_stride;
+                src += src_stride;
+            } while (--h);
+        }
+    } else if (my) {
+        do {
+            for (int x = 0; x < w; x++)
+                dst[x] = FILTER_BILIN_CLIP(src, x, my, src_stride, 4);
+
+            dst += dst_stride;
+            src += src_stride;
+        } while (--h);
+    } else
+        put_c(dst, dst_stride, src, src_stride, w, h);
+}
+
+static void put_bilin_scaled_c(pixel *dst, ptrdiff_t dst_stride,
+                               const pixel *src, ptrdiff_t src_stride,
+                               const int w, int h, const int mx, int my,
+                               const int dx, const int dy
+                               HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    int16_t mid[128 * 2];
+    int in_y = -2;
+
+    do {
+        int x;
+        int y = my >> 10;
+        int16_t *mid1 = &mid[(y & 1) * 128];
+        int16_t *mid2 = &mid[((y + 1) & 1) * 128];
+        int dmy = my & 0x3ff;
+
+        while (in_y < y) {
+            int imx = mx, ioff = 0;
+            int16_t *mid_ptr = &mid[(in_y & 1) * 128];
+
+            for (x = 0; x < w; x++) {
+                mid_ptr[x] = FILTER_BILIN_RND(src, ioff, imx >> 6, 1,
+                                              4 - intermediate_bits);
+                imx += dx;
+                ioff += imx >> 10;
+                imx &= 0x3ff;
+            }
+
+            src += PXSTRIDE(src_stride);
+            in_y++;
+        }
+
+        for (x = 0; x < w; x++)
+            dst[x] = FILTER_BILIN_CLIP2(mid1, mid2, x, dmy >> 6,
+                                       4 + intermediate_bits);
+
+        my += dy;
+        dst += PXSTRIDE(dst_stride);
+    } while (--h);
+}
+
+static void prep_bilin_c(int16_t *tmp,
+                         const pixel *src, ptrdiff_t src_stride,
+                         const int w, int h, const int mx, const int my
+                         HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    src_stride = PXSTRIDE(src_stride);
+
+    if (mx) {
+        if (my) {
+            int16_t mid[128 * 129], *mid_ptr = mid;
+            int tmp_h = h + 1;
+
+            do {
+                for (int x = 0; x < w; x++)
+                    mid_ptr[x] = FILTER_BILIN_RND(src, x, mx, 1,
+                                                  4 - intermediate_bits);
+
+                mid_ptr += 128;
+                src += src_stride;
+            } while (--tmp_h);
+
+            mid_ptr = mid;
+            do {
+                for (int x = 0; x < w; x++)
+                    tmp[x] = FILTER_BILIN_RND(mid_ptr, x, my, 128, 4) -
+                             PREP_BIAS;
+
+                mid_ptr += 128;
+                tmp += w;
+            } while (--h);
+        } else {
+            do {
+                for (int x = 0; x < w; x++)
+                    tmp[x] = FILTER_BILIN_RND(src, x, mx, 1,
+                                              4 - intermediate_bits) -
+                             PREP_BIAS;
+
+                tmp += w;
+                src += src_stride;
+            } while (--h);
+        }
+    } else if (my) {
+        do {
+            for (int x = 0; x < w; x++)
+                tmp[x] = FILTER_BILIN_RND(src, x, my, src_stride,
+                                          4 - intermediate_bits) - PREP_BIAS;
+
+            tmp += w;
+            src += src_stride;
+        } while (--h);
+    } else
+        prep_c(tmp, src, src_stride, w, h HIGHBD_TAIL_SUFFIX);
+}
+
+static void prep_bilin_scaled_c(int16_t *tmp,
+                                const pixel *src, ptrdiff_t src_stride,
+                                const int w, int h, const int mx, int my,
+                                const int dx, const int dy HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    int16_t mid[128 * 2];
+    int in_y = -2;
+
+    do {
+        int x;
+        int y = my >> 10;
+        int16_t *mid1 = &mid[(y & 1) * 128];
+        int16_t *mid2 = &mid[((y + 1) & 1) * 128];
+        int dmy = my & 0x3ff;
+
+        while (in_y < y) {
+            int imx = mx, ioff = 0;
+            int16_t *mid_ptr = &mid[(in_y & 1) * 128];
+
+            for (x = 0; x < w; x++) {
+                mid_ptr[x] = FILTER_BILIN_RND(src, ioff, imx >> 6, 1,
+                                              4 - intermediate_bits);
+                imx += dx;
+                ioff += imx >> 10;
+                imx &= 0x3ff;
+            }
+
+            src += PXSTRIDE(src_stride);
+            in_y++;
+        }
+
+        for (x = 0; x < w; x++)
+            tmp[x] = FILTER_BILIN_RND2(mid1, mid2, x, dmy >> 6, 4) - PREP_BIAS;
+
+        my += dy;
+        tmp += w;
+    } while (--h);
+}
+
+static void avg_c(pixel *dst, const ptrdiff_t dst_stride,
+                  const int16_t *tmp1, const int16_t *tmp2, const int w, int h
+                  HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    const int sh = intermediate_bits + 1;
+    const int rnd = (1 << intermediate_bits) + PREP_BIAS * 2;
+    do {
+        for (int x = 0; x < w; x++)
+            dst[x] = iclip_pixel((tmp1[x] + tmp2[x] + rnd) >> sh);
+
+        tmp1 += w;
+        tmp2 += w;
+        dst += PXSTRIDE(dst_stride);
+    } while (--h);
+}
+
+static void w_avg_c(pixel *dst, const ptrdiff_t dst_stride,
+                    const int16_t *tmp1, const int16_t *tmp2, const int w, int h,
+                    const int weight HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    const int sh = intermediate_bits + 4;
+    const int rnd = (8 << intermediate_bits) + PREP_BIAS * 16;
+    do {
+        for (int x = 0; x < w; x++)
+            dst[x] = iclip_pixel((tmp1[x] * weight +
+                                  tmp2[x] * (16 - weight) + rnd) >> sh);
+
+        tmp1 += w;
+        tmp2 += w;
+        dst += PXSTRIDE(dst_stride);
+    } while (--h);
+}
+
+static void mask_c(pixel *dst, const ptrdiff_t dst_stride,
+                   const int16_t *tmp1, const int16_t *tmp2, const int w, int h,
+                   const uint8_t *mask HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    const int sh = intermediate_bits + 6;
+    const int rnd = (32 << intermediate_bits) + PREP_BIAS * 64;
+    do {
+        for (int x = 0; x < w; x++)
+            dst[x] = iclip_pixel((tmp1[x] * mask[x] +
+                                  tmp2[x] * (64 - mask[x]) + rnd) >> sh);
+
+        tmp1 += w;
+        tmp2 += w;
+        mask += w;
+        dst += PXSTRIDE(dst_stride);
+    } while (--h);
+}
+
+#define blend_px(a, b, m) (((a * (64 - m) + b * m) + 32) >> 6)
+static void blend_c(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                    const int w, int h, const uint8_t *mask)
+{
+    do {
+        for (int x = 0; x < w; x++) {
+            dst[x] = blend_px(dst[x], tmp[x], mask[x]);
+        }
+        dst += PXSTRIDE(dst_stride);
+        tmp += w;
+        mask += w;
+    } while (--h);
+}
+
+static void blend_v_c(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                      const int w, int h)
+{
+    const uint8_t *const mask = &dav1d_obmc_masks[w];
+    do {
+        for (int x = 0; x < (w * 3) >> 2; x++) {
+            dst[x] = blend_px(dst[x], tmp[x], mask[x]);
+        }
+        dst += PXSTRIDE(dst_stride);
+        tmp += w;
+    } while (--h);
+}
+
+static void blend_h_c(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                      const int w, int h)
+{
+    const uint8_t *mask = &dav1d_obmc_masks[h];
+    h = (h * 3) >> 2;
+    do {
+        const int m = *mask++;
+        for (int x = 0; x < w; x++) {
+            dst[x] = blend_px(dst[x], tmp[x], m);
+        }
+        dst += PXSTRIDE(dst_stride);
+        tmp += w;
+    } while (--h);
+}
+
+static void w_mask_c(pixel *dst, const ptrdiff_t dst_stride,
+                     const int16_t *tmp1, const int16_t *tmp2, const int w, int h,
+                     uint8_t *mask, const int sign,
+                     const int ss_hor, const int ss_ver HIGHBD_DECL_SUFFIX)
+{
+    // store mask at 2x2 resolution, i.e. store 2x1 sum for even rows,
+    // and then load this intermediate to calculate final value for odd rows
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    const int bitdepth = bitdepth_from_max(bitdepth_max);
+    const int sh = intermediate_bits + 6;
+    const int rnd = (32 << intermediate_bits) + PREP_BIAS * 64;
+    const int mask_sh = bitdepth + intermediate_bits - 4;
+    const int mask_rnd = 1 << (mask_sh - 5);
+    do {
+        for (int x = 0; x < w; x++) {
+            const int tmpdiff = tmp1[x] - tmp2[x];
+            const int m = imin(38 + ((abs(tmpdiff) + mask_rnd) >> mask_sh), 64);
+            dst[x] = iclip_pixel((tmpdiff * m + tmp2[x] * 64 + rnd) >> sh);
+
+            if (ss_hor) {
+                x++;
+
+                const int tmpdiff = tmp1[x] - tmp2[x];
+                const int n = imin(38 + ((abs(tmpdiff) + mask_rnd) >> mask_sh), 64);
+                dst[x] = iclip_pixel((tmpdiff * n + tmp2[x] * 64 + rnd) >> sh);
+
+                if (h & ss_ver) {
+                    mask[x >> 1] = (m + n + mask[x >> 1] + 2 - sign) >> 2;
+                } else if (ss_ver) {
+                    mask[x >> 1] = m + n;
+                } else {
+                    mask[x >> 1] = (m + n + 1 - sign) >> 1;
+                }
+            } else {
+                mask[x] = m;
+            }
+        }
+
+        tmp1 += w;
+        tmp2 += w;
+        dst += PXSTRIDE(dst_stride);
+        if (!ss_ver || (h & 1)) mask += w >> ss_hor;
+    } while (--h);
+}
+
+#define w_mask_fns(ssn, ss_hor, ss_ver) \
+static void w_mask_##ssn##_c(pixel *const dst, const ptrdiff_t dst_stride, \
+                             const int16_t *const tmp1, const int16_t *const tmp2, \
+                             const int w, const int h, uint8_t *mask, \
+                             const int sign HIGHBD_DECL_SUFFIX) \
+{ \
+    w_mask_c(dst, dst_stride, tmp1, tmp2, w, h, mask, sign, ss_hor, ss_ver \
+             HIGHBD_TAIL_SUFFIX); \
+}
+
+w_mask_fns(444, 0, 0);
+w_mask_fns(422, 1, 0);
+w_mask_fns(420, 1, 1);
+
+#undef w_mask_fns
+
+#define FILTER_WARP_RND(src, x, F, stride, sh) \
+    ((F[0] * src[x - 3 * stride] + \
+      F[1] * src[x - 2 * stride] + \
+      F[2] * src[x - 1 * stride] + \
+      F[3] * src[x + 0 * stride] + \
+      F[4] * src[x + 1 * stride] + \
+      F[5] * src[x + 2 * stride] + \
+      F[6] * src[x + 3 * stride] + \
+      F[7] * src[x + 4 * stride] + \
+      ((1 << (sh)) >> 1)) >> (sh))
+
+#define FILTER_WARP_CLIP(src, x, F, stride, sh) \
+    iclip_pixel(FILTER_WARP_RND(src, x, F, stride, sh))
+
+static void warp_affine_8x8_c(pixel *dst, const ptrdiff_t dst_stride,
+                              const pixel *src, const ptrdiff_t src_stride,
+                              const int16_t *const abcd, int mx, int my
+                              HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    int16_t mid[15 * 8], *mid_ptr = mid;
+
+    src -= 3 * PXSTRIDE(src_stride);
+    for (int y = 0; y < 15; y++, mx += abcd[1]) {
+        for (int x = 0, tmx = mx; x < 8; x++, tmx += abcd[0]) {
+            const int8_t *const filter =
+                dav1d_mc_warp_filter[64 + ((tmx + 512) >> 10)];
+
+            mid_ptr[x] = FILTER_WARP_RND(src, x, filter, 1,
+                                         7 - intermediate_bits);
+        }
+        src += PXSTRIDE(src_stride);
+        mid_ptr += 8;
+    }
+
+    mid_ptr = &mid[3 * 8];
+    for (int y = 0; y < 8; y++, my += abcd[3]) {
+        for (int x = 0, tmy = my; x < 8; x++, tmy += abcd[2]) {
+            const int8_t *const filter =
+                dav1d_mc_warp_filter[64 + ((tmy + 512) >> 10)];
+
+            dst[x] = FILTER_WARP_CLIP(mid_ptr, x, filter, 8,
+                                      7 + intermediate_bits);
+        }
+        mid_ptr += 8;
+        dst += PXSTRIDE(dst_stride);
+    }
+}
+
+static void warp_affine_8x8t_c(int16_t *tmp, const ptrdiff_t tmp_stride,
+                               const pixel *src, const ptrdiff_t src_stride,
+                               const int16_t *const abcd, int mx, int my
+                               HIGHBD_DECL_SUFFIX)
+{
+    const int intermediate_bits = get_intermediate_bits(bitdepth_max);
+    int16_t mid[15 * 8], *mid_ptr = mid;
+
+    src -= 3 * PXSTRIDE(src_stride);
+    for (int y = 0; y < 15; y++, mx += abcd[1]) {
+        for (int x = 0, tmx = mx; x < 8; x++, tmx += abcd[0]) {
+            const int8_t *const filter =
+                dav1d_mc_warp_filter[64 + ((tmx + 512) >> 10)];
+
+            mid_ptr[x] = FILTER_WARP_RND(src, x, filter, 1,
+                                         7 - intermediate_bits);
+        }
+        src += PXSTRIDE(src_stride);
+        mid_ptr += 8;
+    }
+
+    mid_ptr = &mid[3 * 8];
+    for (int y = 0; y < 8; y++, my += abcd[3]) {
+        for (int x = 0, tmy = my; x < 8; x++, tmy += abcd[2]) {
+            const int8_t *const filter =
+                dav1d_mc_warp_filter[64 + ((tmy + 512) >> 10)];
+
+            tmp[x] = FILTER_WARP_RND(mid_ptr, x, filter, 8, 7) - PREP_BIAS;
+        }
+        mid_ptr += 8;
+        tmp += tmp_stride;
+    }
+}
+
+static void emu_edge_c(const intptr_t bw, const intptr_t bh,
+                       const intptr_t iw, const intptr_t ih,
+                       const intptr_t x, const intptr_t y,
+                       pixel *dst, const ptrdiff_t dst_stride,
+                       const pixel *ref, const ptrdiff_t ref_stride)
+{
+    // find offset in reference of visible block to copy
+    ref += iclip((int) y, 0, (int) ih - 1) * PXSTRIDE(ref_stride) +
+           iclip((int) x, 0, (int) iw - 1);
+
+    // number of pixels to extend (left, right, top, bottom)
+    const int left_ext = iclip((int) -x, 0, (int) bw - 1);
+    const int right_ext = iclip((int) (x + bw - iw), 0, (int) bw - 1);
+    assert(left_ext + right_ext < bw);
+    const int top_ext = iclip((int) -y, 0, (int) bh - 1);
+    const int bottom_ext = iclip((int) (y + bh - ih), 0, (int) bh - 1);
+    assert(top_ext + bottom_ext < bh);
+
+    // copy visible portion first
+    pixel *blk = dst + top_ext * PXSTRIDE(dst_stride);
+    const int center_w = (int) (bw - left_ext - right_ext);
+    const int center_h = (int) (bh - top_ext - bottom_ext);
+    for (int y = 0; y < center_h; y++) {
+        pixel_copy(blk + left_ext, ref, center_w);
+        // extend left edge for this line
+        if (left_ext)
+            pixel_set(blk, blk[left_ext], left_ext);
+        // extend right edge for this line
+        if (right_ext)
+            pixel_set(blk + left_ext + center_w, blk[left_ext + center_w - 1],
+                      right_ext);
+        ref += PXSTRIDE(ref_stride);
+        blk += PXSTRIDE(dst_stride);
+    }
+
+    // copy top
+    blk = dst + top_ext * PXSTRIDE(dst_stride);
+    for (int y = 0; y < top_ext; y++) {
+        pixel_copy(dst, blk, bw);
+        dst += PXSTRIDE(dst_stride);
+    }
+
+    // copy bottom
+    dst += center_h * PXSTRIDE(dst_stride);
+    for (int y = 0; y < bottom_ext; y++) {
+        pixel_copy(dst, &dst[-PXSTRIDE(dst_stride)], bw);
+        dst += PXSTRIDE(dst_stride);
+    }
+}
+
+static void resize_c(pixel *dst, const ptrdiff_t dst_stride,
+                     const pixel *src, const ptrdiff_t src_stride,
+                     const int dst_w, int h, const int src_w,
+                     const int dx, const int mx0 HIGHBD_DECL_SUFFIX)
+{
+    do {
+        int mx = mx0, src_x = -1;
+        for (int x = 0; x < dst_w; x++) {
+            const int8_t *const F = dav1d_resize_filter[mx >> 8];
+            dst[x] = iclip_pixel((-(F[0] * src[iclip(src_x - 3, 0, src_w - 1)] +
+                                    F[1] * src[iclip(src_x - 2, 0, src_w - 1)] +
+                                    F[2] * src[iclip(src_x - 1, 0, src_w - 1)] +
+                                    F[3] * src[iclip(src_x + 0, 0, src_w - 1)] +
+                                    F[4] * src[iclip(src_x + 1, 0, src_w - 1)] +
+                                    F[5] * src[iclip(src_x + 2, 0, src_w - 1)] +
+                                    F[6] * src[iclip(src_x + 3, 0, src_w - 1)] +
+                                    F[7] * src[iclip(src_x + 4, 0, src_w - 1)]) +
+                                  64) >> 7);
+            mx += dx;
+            src_x += mx >> 14;
+            mx &= 0x3fff;
+        }
+
+        dst += PXSTRIDE(dst_stride);
+        src += PXSTRIDE(src_stride);
+    } while (--h);
+}
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/mc.h"
+#elif ARCH_LOONGARCH64
+#include "src/loongarch/mc.h"
+#elif ARCH_PPC64LE
+#include "src/ppc/mc.h"
+#elif ARCH_RISCV
+#include "src/riscv/mc.h"
+#elif ARCH_X86
+#include "src/x86/mc.h"
+#endif
+#endif
+
+COLD void bitfn(dav1d_mc_dsp_init)(Dav1dMCDSPContext *const c) {
+#define init_mc_fns(type, name) do { \
+    c->mc        [type] = put_##name##_c; \
+    c->mc_scaled [type] = put_##name##_scaled_c; \
+    c->mct       [type] = prep_##name##_c; \
+    c->mct_scaled[type] = prep_##name##_scaled_c; \
+} while (0)
+
+    init_mc_fns(FILTER_2D_8TAP_REGULAR,        8tap_regular);
+    init_mc_fns(FILTER_2D_8TAP_REGULAR_SMOOTH, 8tap_regular_smooth);
+    init_mc_fns(FILTER_2D_8TAP_REGULAR_SHARP,  8tap_regular_sharp);
+    init_mc_fns(FILTER_2D_8TAP_SHARP_REGULAR,  8tap_sharp_regular);
+    init_mc_fns(FILTER_2D_8TAP_SHARP_SMOOTH,   8tap_sharp_smooth);
+    init_mc_fns(FILTER_2D_8TAP_SHARP,          8tap_sharp);
+    init_mc_fns(FILTER_2D_8TAP_SMOOTH_REGULAR, 8tap_smooth_regular);
+    init_mc_fns(FILTER_2D_8TAP_SMOOTH,         8tap_smooth);
+    init_mc_fns(FILTER_2D_8TAP_SMOOTH_SHARP,   8tap_smooth_sharp);
+    init_mc_fns(FILTER_2D_BILINEAR,            bilin);
+
+    c->avg      = avg_c;
+    c->w_avg    = w_avg_c;
+    c->mask     = mask_c;
+    c->blend    = blend_c;
+    c->blend_v  = blend_v_c;
+    c->blend_h  = blend_h_c;
+    c->w_mask[0] = w_mask_444_c;
+    c->w_mask[1] = w_mask_422_c;
+    c->w_mask[2] = w_mask_420_c;
+    c->warp8x8  = warp_affine_8x8_c;
+    c->warp8x8t = warp_affine_8x8t_c;
+    c->emu_edge = emu_edge_c;
+    c->resize   = resize_c;
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+    mc_dsp_init_arm(c);
+#elif ARCH_LOONGARCH64
+    mc_dsp_init_loongarch(c);
+#elif ARCH_PPC64LE
+    mc_dsp_init_ppc(c);
+#elif ARCH_RISCV
+    mc_dsp_init_riscv(c);
+#elif ARCH_X86
+    mc_dsp_init_x86(c);
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/mem.c b/media/libdav1d/src/src/mem.c
new file mode 100644
index 0000000000..9f0e394472
--- /dev/null
+++ b/media/libdav1d/src/src/mem.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright © 2020, VideoLAN and dav1d authors
+ * Copyright © 2020, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "src/internal.h"
+
+#if TRACK_HEAP_ALLOCATIONS
+#include 
+
+#include "src/log.h"
+
+#define DEFAULT_ALIGN 16
+
+typedef struct {
+    size_t sz;
+    unsigned align;
+    enum AllocationType type;
+} Dav1dAllocationData;
+
+typedef struct {
+    size_t curr_sz;
+    size_t peak_sz;
+    unsigned num_allocs;
+    unsigned num_reuses;
+} AllocStats;
+
+static AllocStats tracked_allocs[N_ALLOC_TYPES];
+static size_t curr_total_sz;
+static size_t peak_total_sz;
+static pthread_mutex_t track_alloc_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void *track_alloc(const enum AllocationType type, char *ptr,
+                         const size_t sz, const size_t align)
+{
+    assert(align >= sizeof(Dav1dAllocationData));
+    if (ptr) {
+        ptr += align;
+        Dav1dAllocationData *const d = &((Dav1dAllocationData*)ptr)[-1];
+        AllocStats *const s = &tracked_allocs[type];
+
+        d->sz = sz;
+        d->align = (unsigned)align;
+        d->type = type;
+
+        pthread_mutex_lock(&track_alloc_mutex);
+        s->num_allocs++;
+        s->curr_sz += sz;
+        if (s->curr_sz > s->peak_sz)
+            s->peak_sz = s->curr_sz;
+
+        curr_total_sz += sz;
+        if (curr_total_sz > peak_total_sz)
+            peak_total_sz = curr_total_sz;
+        pthread_mutex_unlock(&track_alloc_mutex);
+    }
+    return ptr;
+}
+
+static void *track_free(char *const ptr) {
+    const Dav1dAllocationData *const d = &((Dav1dAllocationData*)ptr)[-1];
+    const size_t sz = d->sz;
+
+    pthread_mutex_lock(&track_alloc_mutex);
+    tracked_allocs[d->type].curr_sz -= sz;
+    curr_total_sz -= sz;
+    pthread_mutex_unlock(&track_alloc_mutex);
+
+    return ptr - d->align;
+}
+
+static void dav1d_track_reuse(const enum AllocationType type) {
+    pthread_mutex_lock(&track_alloc_mutex);
+    tracked_allocs[type].num_reuses++;
+    pthread_mutex_unlock(&track_alloc_mutex);
+}
+
+void *dav1d_malloc(const enum AllocationType type, const size_t sz) {
+    void *const ptr = malloc(sz + DEFAULT_ALIGN);
+    return track_alloc(type, ptr, sz, DEFAULT_ALIGN);
+}
+
+void *dav1d_alloc_aligned(const enum AllocationType type,
+                          const size_t sz, const size_t align)
+{
+    void *const ptr = dav1d_alloc_aligned_internal(align, sz + align);
+    return track_alloc(type, ptr, sz, align);
+}
+
+void *dav1d_realloc(const enum AllocationType type,
+                    void *ptr, const size_t sz)
+{
+    if (!ptr)
+        return dav1d_malloc(type, sz);
+    ptr = realloc((char*)ptr - DEFAULT_ALIGN, sz + DEFAULT_ALIGN);
+    if (ptr)
+        ptr = track_free((char*)ptr + DEFAULT_ALIGN);
+    return track_alloc(type, ptr, sz, DEFAULT_ALIGN);
+}
+
+void dav1d_free(void *ptr) {
+    if (ptr)
+        free(track_free(ptr));
+}
+
+void dav1d_free_aligned(void *ptr) {
+    if (ptr) {
+        dav1d_free_aligned_internal(track_free(ptr));
+    }
+}
+
+static COLD int cmp_stats(const void *const a, const void *const b) {
+    const size_t a_sz = ((const AllocStats*)a)->peak_sz;
+    const size_t b_sz = ((const AllocStats*)b)->peak_sz;
+    return a_sz < b_sz ? -1 : a_sz > b_sz;
+}
+
+/* Insert spaces as thousands separators for better readability */
+static COLD int format_tsep(char *const s, const size_t n, const size_t value) {
+    if (value < 1000)
+        return snprintf(s, n, "%u", (unsigned)value);
+
+    const int len = format_tsep(s, n, value / 1000);
+    assert((size_t)len < n);
+    return len + snprintf(s + len, n - len, " %03u", (unsigned)(value % 1000));
+}
+
+COLD void dav1d_log_alloc_stats(Dav1dContext *const c) {
+    static const char *const type_names[N_ALLOC_TYPES] = {
+        [ALLOC_BLOCK     ] = "Block data",
+        [ALLOC_CDEF      ] = "CDEF line buffers",
+        [ALLOC_CDF       ] = "CDF contexts",
+        [ALLOC_COEF      ] = "Coefficient data",
+        [ALLOC_COMMON_CTX] = "Common context data",
+        [ALLOC_DAV1DDATA ] = "Dav1dData",
+        [ALLOC_IPRED     ] = "Intra pred edges",
+        [ALLOC_LF        ] = "Loopfilter data",
+        [ALLOC_LR        ] = "Looprestoration data",
+        [ALLOC_OBU_HDR   ] = "OBU headers",
+        [ALLOC_OBU_META  ] = "OBU metadata",
+        [ALLOC_PAL       ] = "Palette data",
+        [ALLOC_PIC       ] = "Picture buffers",
+        [ALLOC_PIC_CTX   ] = "Picture context data",
+        [ALLOC_REFMVS    ] = "Reference mv data",
+        [ALLOC_SEGMAP    ] = "Segmentation maps",
+        [ALLOC_THREAD_CTX] = "Thread context data",
+        [ALLOC_TILE      ] = "Tile data",
+    };
+
+    struct {
+        AllocStats stats;
+        enum AllocationType type;
+    } data[N_ALLOC_TYPES];
+    unsigned total_allocs = 0;
+    unsigned total_reuses = 0;
+
+    pthread_mutex_lock(&track_alloc_mutex);
+    for (int i = 0; i < N_ALLOC_TYPES; i++) {
+        AllocStats *const s = &data[i].stats;
+        *s = tracked_allocs[i];
+        data[i].type = i;
+        total_allocs += s->num_allocs;
+        total_reuses += s->num_reuses;
+    }
+    size_t total_sz = peak_total_sz;
+    pthread_mutex_unlock(&track_alloc_mutex);
+
+    /* Sort types by memory usage */
+    qsort(&data, N_ALLOC_TYPES, sizeof(*data), cmp_stats);
+
+    const double inv_total_share = 100.0 / total_sz;
+    char total_sz_buf[32];
+    const int sz_len = 4 + format_tsep(total_sz_buf, sizeof(total_sz_buf), total_sz);
+
+    dav1d_log(c, "\n Type                    Allocs    Reuses    Share    Peak size\n"
+                 "---------------------------------------------------------------------\n");
+    for (int i = N_ALLOC_TYPES - 1; i >= 0; i--) {
+        const AllocStats *const s = &data[i].stats;
+        if (s->num_allocs) {
+            const double share = s->peak_sz * inv_total_share;
+            char sz_buf[32];
+            format_tsep(sz_buf, sizeof(sz_buf), s->peak_sz);
+            dav1d_log(c, " %-20s%10u%10u%8.1f%%%*s\n", type_names[data[i].type],
+                      s->num_allocs, s->num_reuses, share, sz_len, sz_buf);
+        }
+    }
+    dav1d_log(c, "---------------------------------------------------------------------\n"
+                 "%31u%10u             %s\n",
+                 total_allocs, total_reuses, total_sz_buf);
+}
+#endif /* TRACK_HEAP_ALLOCATIONS */
+
+static COLD void mem_pool_destroy(Dav1dMemPool *const pool) {
+    pthread_mutex_destroy(&pool->lock);
+    dav1d_free(pool);
+}
+
+void dav1d_mem_pool_push(Dav1dMemPool *const pool, Dav1dMemPoolBuffer *const buf) {
+    pthread_mutex_lock(&pool->lock);
+    const int ref_cnt = --pool->ref_cnt;
+    if (!pool->end) {
+        buf->next = pool->buf;
+        pool->buf = buf;
+        pthread_mutex_unlock(&pool->lock);
+        assert(ref_cnt > 0);
+    } else {
+        pthread_mutex_unlock(&pool->lock);
+        dav1d_free_aligned(buf->data);
+        if (!ref_cnt) mem_pool_destroy(pool);
+    }
+}
+
+Dav1dMemPoolBuffer *dav1d_mem_pool_pop(Dav1dMemPool *const pool, const size_t size) {
+    assert(!(size & (sizeof(void*) - 1)));
+    pthread_mutex_lock(&pool->lock);
+    Dav1dMemPoolBuffer *buf = pool->buf;
+    pool->ref_cnt++;
+    uint8_t *data;
+    if (buf) {
+        pool->buf = buf->next;
+        pthread_mutex_unlock(&pool->lock);
+        data = buf->data;
+        if ((uintptr_t)buf - (uintptr_t)data != size) {
+            /* Reallocate if the size has changed */
+            dav1d_free_aligned(data);
+            goto alloc;
+        }
+#if TRACK_HEAP_ALLOCATIONS
+        dav1d_track_reuse(pool->type);
+#endif
+    } else {
+        pthread_mutex_unlock(&pool->lock);
+alloc:
+        data = dav1d_alloc_aligned(pool->type,
+                                   size + sizeof(Dav1dMemPoolBuffer), 64);
+        if (!data) {
+            pthread_mutex_lock(&pool->lock);
+            const int ref_cnt = --pool->ref_cnt;
+            pthread_mutex_unlock(&pool->lock);
+            if (!ref_cnt) mem_pool_destroy(pool);
+            return NULL;
+        }
+        buf = (Dav1dMemPoolBuffer*)(data + size);
+        buf->data = data;
+    }
+
+    return buf;
+}
+
+COLD int dav1d_mem_pool_init(const enum AllocationType type,
+                             Dav1dMemPool **const ppool)
+{
+    Dav1dMemPool *const pool = dav1d_malloc(ALLOC_COMMON_CTX,
+                                            sizeof(Dav1dMemPool));
+    if (pool) {
+        if (!pthread_mutex_init(&pool->lock, NULL)) {
+            pool->buf = NULL;
+            pool->ref_cnt = 1;
+            pool->end = 0;
+#if TRACK_HEAP_ALLOCATIONS
+            pool->type = type;
+#endif
+            *ppool = pool;
+            return 0;
+        }
+        dav1d_free(pool);
+    }
+    *ppool = NULL;
+    return DAV1D_ERR(ENOMEM);
+}
+
+COLD void dav1d_mem_pool_end(Dav1dMemPool *const pool) {
+    if (pool) {
+        pthread_mutex_lock(&pool->lock);
+        Dav1dMemPoolBuffer *buf = pool->buf;
+        const int ref_cnt = --pool->ref_cnt;
+        pool->buf = NULL;
+        pool->end = 1;
+        pthread_mutex_unlock(&pool->lock);
+
+        while (buf) {
+            void *const data = buf->data;
+            buf = buf->next;
+            dav1d_free_aligned(data);
+        }
+        if (!ref_cnt) mem_pool_destroy(pool);
+    }
+}
diff --git a/media/libdav1d/src/src/mem.h b/media/libdav1d/src/src/mem.h
new file mode 100644
index 0000000000..0ff7deb7dc
--- /dev/null
+++ b/media/libdav1d/src/src/mem.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_MEM_H
+#define DAV1D_SRC_MEM_H
+
+#define TRACK_HEAP_ALLOCATIONS 0
+
+#include 
+
+#if defined(_WIN32) || HAVE_MEMALIGN
+#include 
+#endif
+
+#include "dav1d/dav1d.h"
+
+#include "common/attributes.h"
+
+#include "src/thread.h"
+
+enum AllocationType {
+    ALLOC_BLOCK,
+    ALLOC_CDEF,
+    ALLOC_CDF,
+    ALLOC_COEF,
+    ALLOC_COMMON_CTX,
+    ALLOC_DAV1DDATA,
+    ALLOC_IPRED,
+    ALLOC_LF,
+    ALLOC_LR,
+    ALLOC_OBU_HDR,
+    ALLOC_OBU_META,
+    ALLOC_PAL,
+    ALLOC_PIC,
+    ALLOC_PIC_CTX,
+    ALLOC_REFMVS,
+    ALLOC_SEGMAP,
+    ALLOC_THREAD_CTX,
+    ALLOC_TILE,
+    N_ALLOC_TYPES,
+};
+
+typedef struct Dav1dMemPoolBuffer {
+    void *data;
+    struct Dav1dMemPoolBuffer *next;
+} Dav1dMemPoolBuffer;
+
+typedef struct Dav1dMemPool {
+    pthread_mutex_t lock;
+    Dav1dMemPoolBuffer *buf;
+    int ref_cnt;
+    int end;
+#if TRACK_HEAP_ALLOCATIONS
+    enum AllocationType type;
+#endif
+} Dav1dMemPool;
+
+// TODO: Move this to a common location?
+#define ROUND_UP(x,a) (((x)+((a)-1)) & ~((a)-1))
+
+/*
+ * Allocate align-byte aligned memory. The return value can be released
+ * by calling the dav1d_free_aligned() function.
+ */
+static inline void *dav1d_alloc_aligned_internal(const size_t sz, const size_t align) {
+    assert(!(align & (align - 1)));
+#ifdef _WIN32
+    return _aligned_malloc(sz, align);
+#elif HAVE_POSIX_MEMALIGN
+    void *ptr;
+    if (posix_memalign(&ptr, align, sz)) return NULL;
+    return ptr;
+#elif HAVE_MEMALIGN
+    return memalign(align, sz);
+#elif HAVE_ALIGNED_ALLOC
+    // The C11 standard specifies that the size parameter
+    // must be an integral multiple of alignment.
+    return aligned_alloc(align, ROUND_UP(sz, align));
+#else
+    void *const buf = malloc(sz + align + sizeof(void *));
+    if (!buf) return NULL;
+
+    void *const ptr = (void *)(((uintptr_t)buf + sizeof(void *) + align - 1) & ~(align - 1));
+    ((void **)ptr)[-1] = buf;
+    return ptr;
+#endif
+}
+
+static inline void dav1d_free_aligned_internal(void *ptr) {
+#ifdef _WIN32
+    _aligned_free(ptr);
+#elif HAVE_POSIX_MEMALIGN || HAVE_MEMALIGN || HAVE_ALIGNED_ALLOC
+    free(ptr);
+#else
+    if (ptr) free(((void **)ptr)[-1]);
+#endif
+}
+
+#if TRACK_HEAP_ALLOCATIONS
+void *dav1d_malloc(enum AllocationType type, size_t sz);
+void *dav1d_realloc(enum AllocationType type, void *ptr, size_t sz);
+void *dav1d_alloc_aligned(enum AllocationType type, size_t sz, size_t align);
+void dav1d_free(void *ptr);
+void dav1d_free_aligned(void *ptr);
+void dav1d_log_alloc_stats(Dav1dContext *c);
+#else
+#define dav1d_mem_pool_init(type, pool) dav1d_mem_pool_init(pool)
+#define dav1d_malloc(type, sz) malloc(sz)
+#define dav1d_realloc(type, ptr, sz) realloc(ptr, sz)
+#define dav1d_alloc_aligned(type, sz, align) dav1d_alloc_aligned_internal(sz, align)
+#define dav1d_free(ptr) free(ptr)
+#define dav1d_free_aligned(ptr) dav1d_free_aligned_internal(ptr)
+#endif /* TRACK_HEAP_ALLOCATIONS */
+
+void dav1d_mem_pool_push(Dav1dMemPool *pool, Dav1dMemPoolBuffer *buf);
+Dav1dMemPoolBuffer *dav1d_mem_pool_pop(Dav1dMemPool *pool, size_t size);
+int dav1d_mem_pool_init(enum AllocationType type, Dav1dMemPool **pool);
+void dav1d_mem_pool_end(Dav1dMemPool *pool);
+
+static inline void dav1d_freep_aligned(void *ptr) {
+    void **mem = (void **) ptr;
+    if (*mem) {
+        dav1d_free_aligned(*mem);
+        *mem = NULL;
+    }
+}
+
+#endif /* DAV1D_SRC_MEM_H */
diff --git a/media/libdav1d/src/src/meson.build b/media/libdav1d/src/src/meson.build
new file mode 100644
index 0000000000..108b7623ab
--- /dev/null
+++ b/media/libdav1d/src/src/meson.build
@@ -0,0 +1,408 @@
+# Copyright © 2018-2019, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Build definition for the dav1d library
+#
+
+# libdav1d source files
+libdav1d_sources = files(
+    'cdf.c',
+    'cpu.c',
+    'ctx.c',
+    'data.c',
+    'decode.c',
+    'dequant_tables.c',
+    'getbits.c',
+    'intra_edge.c',
+    'itx_1d.c',
+    'lf_mask.c',
+    'lib.c',
+    'log.c',
+    'mem.c',
+    'msac.c',
+    'obu.c',
+    'pal.c',
+    'picture.c',
+    'qm.c',
+    'ref.c',
+    'refmvs.c',
+    'scan.c',
+    'tables.c',
+    'thread_task.c',
+    'warpmv.c',
+    'wedge.c',
+)
+
+# libdav1d bitdepth source files
+# These files are compiled for each bitdepth with
+# `BITDEPTH` defined to the currently built bitdepth.
+libdav1d_tmpl_sources = files(
+    'cdef_apply_tmpl.c',
+    'cdef_tmpl.c',
+    'fg_apply_tmpl.c',
+    'filmgrain_tmpl.c',
+    'ipred_prepare_tmpl.c',
+    'ipred_tmpl.c',
+    'itx_tmpl.c',
+    'lf_apply_tmpl.c',
+    'loopfilter_tmpl.c',
+    'looprestoration_tmpl.c',
+    'lr_apply_tmpl.c',
+    'mc_tmpl.c',
+    'recon_tmpl.c',
+)
+
+libdav1d_arch_tmpl_sources = {}
+
+libdav1d_bitdepth_objs = []
+
+# ASM specific sources
+libdav1d_asm_objs = []
+# Arch-specific flags
+arch_flags = {}
+if is_asm_enabled
+    if (host_machine.cpu_family() == 'aarch64' or
+        host_machine.cpu_family().startswith('arm'))
+
+        libdav1d_sources += files(
+            'arm/cpu.c',
+        )
+        if (host_machine.cpu_family() == 'aarch64' or
+            host_machine.cpu() == 'arm64')
+            libdav1d_sources_asm = files(
+                # itx.S is used for both 8 and 16 bpc.
+                'arm/64/itx.S',
+                'arm/64/looprestoration_common.S',
+                'arm/64/msac.S',
+                'arm/64/refmvs.S',
+            )
+
+            if dav1d_bitdepths.contains('8')
+                libdav1d_sources_asm += files(
+                    'arm/64/cdef.S',
+                    'arm/64/filmgrain.S',
+                    'arm/64/ipred.S',
+                    'arm/64/loopfilter.S',
+                    'arm/64/looprestoration.S',
+                    'arm/64/mc.S',
+                    'arm/64/mc_dotprod.S',
+                )
+            endif
+
+            if dav1d_bitdepths.contains('16')
+                libdav1d_sources_asm += files(
+                    'arm/64/cdef16.S',
+                    'arm/64/filmgrain16.S',
+                    'arm/64/ipred16.S',
+                    'arm/64/itx16.S',
+                    'arm/64/loopfilter16.S',
+                    'arm/64/looprestoration16.S',
+                    'arm/64/mc16.S',
+                    'arm/64/mc16_sve.S',
+                )
+            endif
+        elif host_machine.cpu_family().startswith('arm')
+            libdav1d_sources_asm = files(
+                # itx.S is used for both 8 and 16 bpc.
+                'arm/32/itx.S',
+                'arm/32/looprestoration_common.S',
+                'arm/32/msac.S',
+                'arm/32/refmvs.S',
+            )
+
+            if dav1d_bitdepths.contains('8')
+                libdav1d_sources_asm += files(
+                    'arm/32/cdef.S',
+                    'arm/32/filmgrain.S',
+                    'arm/32/ipred.S',
+                    'arm/32/loopfilter.S',
+                    'arm/32/looprestoration.S',
+                    'arm/32/mc.S',
+                )
+            endif
+
+            if dav1d_bitdepths.contains('16')
+                libdav1d_sources_asm += files(
+                    'arm/32/cdef16.S',
+                    'arm/32/filmgrain16.S',
+                    'arm/32/ipred16.S',
+                    'arm/32/itx16.S',
+                    'arm/32/loopfilter16.S',
+                    'arm/32/looprestoration16.S',
+                    'arm/32/mc16.S',
+                )
+            endif
+        endif
+
+        if use_gaspp
+            libdav1d_asm_objs = gaspp_gen.process(libdav1d_sources_asm)
+        else
+            libdav1d_sources += libdav1d_sources_asm
+        endif
+    elif host_machine.cpu_family().startswith('x86')
+
+        libdav1d_sources += files(
+            'x86/cpu.c',
+        )
+
+        # NASM source files
+        libdav1d_sources_asm = files(
+            'x86/cpuid.asm',
+            'x86/msac.asm',
+            'x86/pal.asm',
+            'x86/refmvs.asm',
+            'x86/itx_avx512.asm',
+            'x86/cdef_avx2.asm',
+            'x86/itx_avx2.asm',
+            'x86/cdef_sse.asm',
+            'x86/itx_sse.asm',
+        )
+
+        if dav1d_bitdepths.contains('8')
+            libdav1d_sources_asm += files(
+                'x86/cdef_avx512.asm',
+                'x86/filmgrain_avx512.asm',
+                'x86/ipred_avx512.asm',
+                'x86/loopfilter_avx512.asm',
+                'x86/looprestoration_avx512.asm',
+                'x86/mc_avx512.asm',
+                'x86/filmgrain_avx2.asm',
+                'x86/ipred_avx2.asm',
+                'x86/loopfilter_avx2.asm',
+                'x86/looprestoration_avx2.asm',
+                'x86/mc_avx2.asm',
+                'x86/filmgrain_sse.asm',
+                'x86/ipred_sse.asm',
+                'x86/loopfilter_sse.asm',
+                'x86/looprestoration_sse.asm',
+                'x86/mc_sse.asm',
+            )
+        endif
+
+        if dav1d_bitdepths.contains('16')
+            libdav1d_sources_asm += files(
+                'x86/cdef16_avx512.asm',
+                'x86/filmgrain16_avx512.asm',
+                'x86/ipred16_avx512.asm',
+                'x86/itx16_avx512.asm',
+                'x86/loopfilter16_avx512.asm',
+                'x86/looprestoration16_avx512.asm',
+                'x86/mc16_avx512.asm',
+                'x86/cdef16_avx2.asm',
+                'x86/filmgrain16_avx2.asm',
+                'x86/ipred16_avx2.asm',
+                'x86/itx16_avx2.asm',
+                'x86/loopfilter16_avx2.asm',
+                'x86/looprestoration16_avx2.asm',
+                'x86/mc16_avx2.asm',
+                'x86/cdef16_sse.asm',
+                'x86/filmgrain16_sse.asm',
+                'x86/ipred16_sse.asm',
+                'x86/itx16_sse.asm',
+                'x86/loopfilter16_sse.asm',
+                'x86/looprestoration16_sse.asm',
+                'x86/mc16_sse.asm',
+            )
+        endif
+
+        # Compile the ASM sources with NASM
+        libdav1d_asm_objs = nasm_gen.process(libdav1d_sources_asm)
+    elif host_machine.cpu_family().startswith('loongarch')
+        libdav1d_sources += files(
+            'loongarch/cpu.c',
+        )
+
+        libdav1d_arch_tmpl_sources += {'default': files(
+            'loongarch/looprestoration_inner.c',
+        )}
+
+        libdav1d_sources_asm = files(
+            'loongarch/cdef.S',
+            'loongarch/ipred.S',
+            'loongarch/mc.S',
+            'loongarch/loopfilter.S',
+            'loongarch/looprestoration.S',
+            'loongarch/msac.S',
+            'loongarch/refmvs.S',
+            'loongarch/itx.S',
+        )
+        libdav1d_asm_objs += libdav1d_sources_asm
+    elif host_machine.cpu() == 'ppc64le'
+        arch_flags += {'vsx': ['-maltivec', '-mvsx', '-DDAV1D_VSX']}
+        libdav1d_sources += files(
+            'ppc/cpu.c',
+        )
+        libdav1d_arch_tmpl_sources += {'vsx': files(
+            'ppc/cdef_tmpl.c',
+            'ppc/looprestoration_tmpl.c',
+        )}
+        arch_flags += {'pwr9': ['-mcpu=power9', '-DDAV1D_PWR9']}
+        libdav1d_arch_tmpl_sources += {'pwr9': files(
+            'ppc/itx_tmpl.c',
+            'ppc/loopfilter_tmpl.c',
+            'ppc/mc_tmpl.c',
+        )}
+    elif host_machine.cpu_family().startswith('riscv')
+        libdav1d_sources += files(
+            'riscv/cpu.c',
+        )
+        if host_machine.cpu_family() == 'riscv64'
+            libdav1d_sources += files(
+                'riscv/64/cpu.S',
+                'riscv/64/pal.S',
+            )
+
+            if dav1d_bitdepths.contains('8')
+                libdav1d_sources += files(
+                    'riscv/64/cdef.S',
+                    'riscv/64/ipred.S',
+                    'riscv/64/itx.S',
+                    'riscv/64/mc.S',
+                )
+            endif
+
+            if dav1d_bitdepths.contains('16')
+                libdav1d_sources += files(
+                    'riscv/64/cdef16.S',
+                    'riscv/64/ipred16.S',
+                    'riscv/64/mc16.S',
+                )
+            endif
+        endif
+    endif
+endif
+
+
+
+libdav1d_rc_obj = []
+libdav1d_flags = []
+api_export_flags = []
+
+#
+# Windows .rc file and API export flags
+#
+
+if host_machine.system() == 'windows'
+    if get_option('default_library') != 'static'
+        rc_file = configure_file(
+            input : 'dav1d.rc.in',
+            output : 'dav1d.rc',
+            configuration : rc_data
+        )
+
+        libdav1d_rc_obj = winmod.compile_resources(rc_file)
+
+        api_export_flags = ['-DDAV1D_BUILDING_DLL']
+    endif
+
+    if (host_machine.cpu_family() == 'x86_64' and cc.get_id() == 'gcc')
+        # We don't expect to reference data members from other DLLs without
+        # dllimport attributes. Set the -mcmodel=small flag, which avoids
+        # generating indirection via .refptr. for all potentially
+        # dllimported variable references.
+        libdav1d_flags += '-mcmodel=small'
+    endif
+endif
+
+
+
+#
+# Library definitions
+#
+
+# Helper library for each bitdepth
+libdav1d_bitdepth_objs = []
+foreach bitdepth : dav1d_bitdepths
+    libdav1d_bitdepth_objs += static_library(
+        'dav1d_bitdepth_@0@'.format(bitdepth),
+        libdav1d_tmpl_sources, config_h_target,
+        include_directories: dav1d_inc_dirs,
+        dependencies : [stdatomic_dependencies],
+        c_args : ['-DBITDEPTH=@0@'.format(bitdepth)] + libdav1d_flags,
+        install : false,
+        build_by_default : false,
+    ).extract_all_objects(recursive: true)
+endforeach
+
+# Helper library for each bitdepth and architecture-specific flags
+foreach bitdepth : dav1d_bitdepths
+    foreach subarch : libdav1d_arch_tmpl_sources.keys()
+        libdav1d_bitdepth_objs += static_library(
+            'dav1d_arch_bitdepth_@0@_@1@'.format(bitdepth,subarch),
+            libdav1d_arch_tmpl_sources[subarch], config_h_target,
+            include_directories: dav1d_inc_dirs,
+            dependencies : [stdatomic_dependencies],
+            c_args : ['-DBITDEPTH=@0@'.format(bitdepth)] + libdav1d_flags + arch_flags.get(subarch, []),
+            install : false,
+            build_by_default : false,
+        ).extract_all_objects(recursive: true)
+    endforeach
+endforeach
+
+# The final dav1d library
+if host_machine.system() == 'windows'
+    dav1d_soversion = ''
+else
+    dav1d_soversion = dav1d_api_version_major
+endif
+
+libdav1d = library('dav1d',
+    libdav1d_sources,
+    libdav1d_asm_objs,
+    libdav1d_rc_obj,
+    rev_target,
+    config_h_target,
+
+    objects : [
+        libdav1d_bitdepth_objs,
+        ],
+
+    include_directories : dav1d_inc_dirs,
+    dependencies : [
+        stdatomic_dependencies,
+        thread_dependency,
+        thread_compat_dep,
+        libdl_dependency,
+        ],
+    c_args : [libdav1d_flags, api_export_flags],
+    version : dav1d_soname_version,
+    soversion : dav1d_soversion,
+    install : true,
+)
+
+dav1d_dep = declare_dependency(link_with: libdav1d,
+    include_directories : include_directories('../include')
+)
+
+#
+# Generate pkg-config .pc file
+#
+pkg_mod = import('pkgconfig')
+pkg_mod.generate(libraries: libdav1d,
+    version: meson.project_version(),
+    name: 'libdav1d',
+    filebase: 'dav1d',
+    description: 'AV1 decoding library'
+)
diff --git a/media/libdav1d/src/src/msac.c b/media/libdav1d/src/src/msac.c
new file mode 100644
index 0000000000..971ba85e29
--- /dev/null
+++ b/media/libdav1d/src/src/msac.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/msac.h"
+
+#define EC_PROB_SHIFT 6
+#define EC_MIN_PROB 4  // must be <= (1<buf_pos;
+    const uint8_t *buf_end = s->buf_end;
+    int c = EC_WIN_SIZE - s->cnt - 24;
+    ec_win dif = s->dif;
+    do {
+        if (buf_pos >= buf_end) {
+            // set remaining bits to 1;
+            dif |= ~(~(ec_win)0xff << c);
+            break;
+        }
+        dif |= (ec_win)(*buf_pos++ ^ 0xff) << c;
+        c -= 8;
+    } while (c >= 0);
+    s->dif = dif;
+    s->cnt = EC_WIN_SIZE - c - 24;
+    s->buf_pos = buf_pos;
+}
+
+int dav1d_msac_decode_subexp(MsacContext *const s, const int ref,
+                             const int n, unsigned k)
+{
+    assert(n >> k == 8);
+
+    unsigned a = 0;
+    if (dav1d_msac_decode_bool_equi(s)) {
+        if (dav1d_msac_decode_bool_equi(s))
+            k += dav1d_msac_decode_bool_equi(s) + 1;
+        a = 1 << k;
+    }
+    const unsigned v = dav1d_msac_decode_bools(s, k) + a;
+    return ref * 2 <= n ? inv_recenter(ref, v) :
+                          n - 1 - inv_recenter(n - 1 - ref, v);
+}
+
+#if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \
+  ARCH_AARCH64 || \
+  (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \
+))
+/* Takes updated dif and range values, renormalizes them so that
+ * 32768 <= rng < 65536 (reading more bytes from the stream into dif if
+ * necessary), and stores them back in the decoder context.
+ * dif: The new value of dif.
+ * rng: The new value of the range. */
+static inline void ctx_norm(MsacContext *const s, const ec_win dif,
+                            const unsigned rng)
+{
+    const int d = 15 ^ (31 ^ clz(rng));
+    const int cnt = s->cnt;
+    assert(rng <= 65535U);
+    s->dif = dif << d;
+    s->rng = rng << d;
+    s->cnt = cnt - d;
+    // unsigned compare avoids redundant refills at eob
+    if ((unsigned)cnt < (unsigned)d)
+        ctx_refill(s);
+}
+
+unsigned dav1d_msac_decode_bool_equi_c(MsacContext *const s) {
+    const unsigned r = s->rng;
+    ec_win dif = s->dif;
+    assert((dif >> (EC_WIN_SIZE - 16)) < r);
+    // When the probability is 1/2, f = 16384 >> EC_PROB_SHIFT = 256 and we can
+    // replace the multiply with a simple shift.
+    unsigned v = ((r >> 8) << 7) + EC_MIN_PROB;
+    const ec_win vw = (ec_win)v << (EC_WIN_SIZE - 16);
+    const unsigned ret = dif >= vw;
+    dif -= ret * vw;
+    v += ret * (r - 2 * v);
+    ctx_norm(s, dif, v);
+    return !ret;
+}
+
+/* Decode a single binary value.
+ * f: The probability that the bit is one
+ * Return: The value decoded (0 or 1). */
+unsigned dav1d_msac_decode_bool_c(MsacContext *const s, const unsigned f) {
+    const unsigned r = s->rng;
+    ec_win dif = s->dif;
+    assert((dif >> (EC_WIN_SIZE - 16)) < r);
+    unsigned v = ((r >> 8) * (f >> EC_PROB_SHIFT) >> (7 - EC_PROB_SHIFT)) + EC_MIN_PROB;
+    const ec_win vw = (ec_win)v << (EC_WIN_SIZE - 16);
+    const unsigned ret = dif >= vw;
+    dif -= ret * vw;
+    v += ret * (r - 2 * v);
+    ctx_norm(s, dif, v);
+    return !ret;
+}
+
+/* Decodes a symbol given an inverse cumulative distribution function (CDF)
+ * table in Q15. */
+unsigned dav1d_msac_decode_symbol_adapt_c(MsacContext *const s,
+                                          uint16_t *const cdf,
+                                          const size_t n_symbols)
+{
+    const unsigned c = s->dif >> (EC_WIN_SIZE - 16), r = s->rng >> 8;
+    unsigned u, v = s->rng, val = -1;
+
+    assert(n_symbols <= 15);
+    assert(cdf[n_symbols] <= 32);
+
+    do {
+        val++;
+        u = v;
+        v = r * (cdf[val] >> EC_PROB_SHIFT);
+        v >>= 7 - EC_PROB_SHIFT;
+        v += EC_MIN_PROB * ((unsigned)n_symbols - val);
+    } while (c < v);
+
+    assert(u <= s->rng);
+
+    ctx_norm(s, s->dif - ((ec_win)v << (EC_WIN_SIZE - 16)), u - v);
+
+    if (s->allow_update_cdf) {
+        const unsigned count = cdf[n_symbols];
+        const unsigned rate = 4 + (count >> 4) + (n_symbols > 2);
+        unsigned i;
+        for (i = 0; i < val; i++)
+            cdf[i] += (32768 - cdf[i]) >> rate;
+        for (; i < n_symbols; i++)
+            cdf[i] -= cdf[i] >> rate;
+        cdf[n_symbols] = count + (count < 32);
+    }
+
+    return val;
+}
+
+unsigned dav1d_msac_decode_bool_adapt_c(MsacContext *const s,
+                                        uint16_t *const cdf)
+{
+    const unsigned bit = dav1d_msac_decode_bool(s, *cdf);
+
+    if (s->allow_update_cdf) {
+        // update_cdf() specialized for boolean CDFs
+        const unsigned count = cdf[1];
+        const int rate = 4 + (count >> 4);
+        if (bit)
+            cdf[0] += (32768 - cdf[0]) >> rate;
+        else
+            cdf[0] -= cdf[0] >> rate;
+        cdf[1] = count + (count < 32);
+    }
+
+    return bit;
+}
+
+unsigned dav1d_msac_decode_hi_tok_c(MsacContext *const s, uint16_t *const cdf) {
+    unsigned tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3);
+    unsigned tok = 3 + tok_br;
+    if (tok_br == 3) {
+        tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3);
+        tok = 6 + tok_br;
+        if (tok_br == 3) {
+            tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3);
+            tok = 9 + tok_br;
+            if (tok_br == 3)
+                tok = 12 + dav1d_msac_decode_symbol_adapt4(s, cdf, 3);
+        }
+    }
+    return tok;
+}
+#endif
+
+void dav1d_msac_init(MsacContext *const s, const uint8_t *const data,
+                     const size_t sz, const int disable_cdf_update_flag)
+{
+    s->buf_pos = data;
+    s->buf_end = data + sz;
+    s->dif = 0;
+    s->rng = 0x8000;
+    s->cnt = -15;
+    s->allow_update_cdf = !disable_cdf_update_flag;
+    ctx_refill(s);
+
+#if ARCH_X86_64 && HAVE_ASM
+    s->symbol_adapt16 = dav1d_msac_decode_symbol_adapt_c;
+
+    msac_init_x86(s);
+#endif
+}
diff --git a/media/libdav1d/src/src/msac.h b/media/libdav1d/src/src/msac.h
new file mode 100644
index 0000000000..eb97650fce
--- /dev/null
+++ b/media/libdav1d/src/src/msac.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_MSAC_H
+#define DAV1D_SRC_MSAC_H
+
+#include 
+#include 
+
+#include "common/intops.h"
+
+typedef size_t ec_win;
+
+typedef struct MsacContext {
+    const uint8_t *buf_pos;
+    const uint8_t *buf_end;
+    ec_win dif;
+    unsigned rng;
+    int cnt;
+    int allow_update_cdf;
+
+#if ARCH_X86_64 && HAVE_ASM
+    unsigned (*symbol_adapt16)(struct MsacContext *s, uint16_t *cdf, size_t n_symbols);
+#endif
+} MsacContext;
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/msac.h"
+#elif ARCH_LOONGARCH64
+#include "src/loongarch/msac.h"
+#elif ARCH_X86
+#include "src/x86/msac.h"
+#endif
+#endif
+
+void dav1d_msac_init(MsacContext *s, const uint8_t *data, size_t sz,
+                     int disable_cdf_update_flag);
+unsigned dav1d_msac_decode_symbol_adapt_c(MsacContext *s, uint16_t *cdf,
+                                          size_t n_symbols);
+unsigned dav1d_msac_decode_bool_adapt_c(MsacContext *s, uint16_t *cdf);
+unsigned dav1d_msac_decode_bool_equi_c(MsacContext *s);
+unsigned dav1d_msac_decode_bool_c(MsacContext *s, unsigned f);
+unsigned dav1d_msac_decode_hi_tok_c(MsacContext *s, uint16_t *cdf);
+int dav1d_msac_decode_subexp(MsacContext *s, int ref, int n, unsigned k);
+
+/* Supported n_symbols ranges: adapt4: 1-3, adapt8: 1-7, adapt16: 3-15 */
+#ifndef dav1d_msac_decode_symbol_adapt4
+#define dav1d_msac_decode_symbol_adapt4  dav1d_msac_decode_symbol_adapt_c
+#endif
+#ifndef dav1d_msac_decode_symbol_adapt8
+#define dav1d_msac_decode_symbol_adapt8  dav1d_msac_decode_symbol_adapt_c
+#endif
+#ifndef dav1d_msac_decode_symbol_adapt16
+#define dav1d_msac_decode_symbol_adapt16 dav1d_msac_decode_symbol_adapt_c
+#endif
+#ifndef dav1d_msac_decode_bool_adapt
+#define dav1d_msac_decode_bool_adapt     dav1d_msac_decode_bool_adapt_c
+#endif
+#ifndef dav1d_msac_decode_bool_equi
+#define dav1d_msac_decode_bool_equi      dav1d_msac_decode_bool_equi_c
+#endif
+#ifndef dav1d_msac_decode_bool
+#define dav1d_msac_decode_bool           dav1d_msac_decode_bool_c
+#endif
+#ifndef dav1d_msac_decode_hi_tok
+#define dav1d_msac_decode_hi_tok         dav1d_msac_decode_hi_tok_c
+#endif
+
+static inline unsigned dav1d_msac_decode_bools(MsacContext *const s, unsigned n) {
+    unsigned v = 0;
+    while (n--)
+        v = (v << 1) | dav1d_msac_decode_bool_equi(s);
+    return v;
+}
+
+static inline int dav1d_msac_decode_uniform(MsacContext *const s, const unsigned n) {
+    assert(n > 0);
+    const int l = ulog2(n) + 1;
+    assert(l > 1);
+    const unsigned m = (1 << l) - n;
+    const unsigned v = dav1d_msac_decode_bools(s, l - 1);
+    return v < m ? v : (v << 1) - m + dav1d_msac_decode_bool_equi(s);
+}
+
+#endif /* DAV1D_SRC_MSAC_H */
diff --git a/media/libdav1d/src/src/obu.c b/media/libdav1d/src/src/obu.c
new file mode 100644
index 0000000000..da5002aec7
--- /dev/null
+++ b/media/libdav1d/src/src/obu.c
@@ -0,0 +1,1695 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+
+#include "dav1d/data.h"
+
+#include "common/frame.h"
+#include "common/intops.h"
+#include "common/validate.h"
+
+#include "src/decode.h"
+#include "src/getbits.h"
+#include "src/levels.h"
+#include "src/log.h"
+#include "src/obu.h"
+#include "src/ref.h"
+#include "src/thread_task.h"
+
+static int check_trailing_bits(GetBits *const gb,
+                               const int strict_std_compliance)
+{
+    const int trailing_one_bit = dav1d_get_bit(gb);
+
+    if (gb->error)
+        return DAV1D_ERR(EINVAL);
+
+    if (!strict_std_compliance)
+        return 0;
+
+    if (!trailing_one_bit || gb->state)
+        return DAV1D_ERR(EINVAL);
+
+    ptrdiff_t size = gb->ptr_end - gb->ptr;
+    while (size > 0 && gb->ptr[size - 1] == 0)
+        size--;
+
+    if (size)
+        return DAV1D_ERR(EINVAL);
+
+    return 0;
+}
+
+static NOINLINE int parse_seq_hdr(Dav1dSequenceHeader *const hdr,
+                                  GetBits *const gb,
+                                  const int strict_std_compliance)
+{
+#define DEBUG_SEQ_HDR 0
+
+#if DEBUG_SEQ_HDR
+    const unsigned init_bit_pos = dav1d_get_bits_pos(gb);
+#endif
+
+    memset(hdr, 0, sizeof(*hdr));
+    hdr->profile = dav1d_get_bits(gb, 3);
+    if (hdr->profile > 2) goto error;
+#if DEBUG_SEQ_HDR
+    printf("SEQHDR: post-profile: off=%u\n",
+           dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+
+    hdr->still_picture = dav1d_get_bit(gb);
+    hdr->reduced_still_picture_header = dav1d_get_bit(gb);
+    if (hdr->reduced_still_picture_header && !hdr->still_picture) goto error;
+#if DEBUG_SEQ_HDR
+    printf("SEQHDR: post-stillpicture_flags: off=%u\n",
+           dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+
+    if (hdr->reduced_still_picture_header) {
+        hdr->num_operating_points = 1;
+        hdr->operating_points[0].major_level = dav1d_get_bits(gb, 3);
+        hdr->operating_points[0].minor_level = dav1d_get_bits(gb, 2);
+        hdr->operating_points[0].initial_display_delay = 10;
+    } else {
+        hdr->timing_info_present = dav1d_get_bit(gb);
+        if (hdr->timing_info_present) {
+            hdr->num_units_in_tick = dav1d_get_bits(gb, 32);
+            hdr->time_scale = dav1d_get_bits(gb, 32);
+            if (strict_std_compliance && (!hdr->num_units_in_tick || !hdr->time_scale))
+                goto error;
+            hdr->equal_picture_interval = dav1d_get_bit(gb);
+            if (hdr->equal_picture_interval) {
+                const unsigned num_ticks_per_picture = dav1d_get_vlc(gb);
+                if (num_ticks_per_picture == UINT32_MAX)
+                    goto error;
+                hdr->num_ticks_per_picture = num_ticks_per_picture + 1;
+            }
+
+            hdr->decoder_model_info_present = dav1d_get_bit(gb);
+            if (hdr->decoder_model_info_present) {
+                hdr->encoder_decoder_buffer_delay_length = dav1d_get_bits(gb, 5) + 1;
+                hdr->num_units_in_decoding_tick = dav1d_get_bits(gb, 32);
+                if (strict_std_compliance && !hdr->num_units_in_decoding_tick)
+                    goto error;
+                hdr->buffer_removal_delay_length = dav1d_get_bits(gb, 5) + 1;
+                hdr->frame_presentation_delay_length = dav1d_get_bits(gb, 5) + 1;
+            }
+        }
+#if DEBUG_SEQ_HDR
+        printf("SEQHDR: post-timinginfo: off=%u\n",
+               dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+
+        hdr->display_model_info_present = dav1d_get_bit(gb);
+        hdr->num_operating_points = dav1d_get_bits(gb, 5) + 1;
+        for (int i = 0; i < hdr->num_operating_points; i++) {
+            struct Dav1dSequenceHeaderOperatingPoint *const op =
+                &hdr->operating_points[i];
+            op->idc = dav1d_get_bits(gb, 12);
+            if (op->idc && (!(op->idc & 0xff) || !(op->idc & 0xf00)))
+                goto error;
+            op->major_level = 2 + dav1d_get_bits(gb, 3);
+            op->minor_level = dav1d_get_bits(gb, 2);
+            if (op->major_level > 3)
+                op->tier = dav1d_get_bit(gb);
+            if (hdr->decoder_model_info_present) {
+                op->decoder_model_param_present = dav1d_get_bit(gb);
+                if (op->decoder_model_param_present) {
+                    struct Dav1dSequenceHeaderOperatingParameterInfo *const opi =
+                        &hdr->operating_parameter_info[i];
+                    opi->decoder_buffer_delay =
+                        dav1d_get_bits(gb, hdr->encoder_decoder_buffer_delay_length);
+                    opi->encoder_buffer_delay =
+                        dav1d_get_bits(gb, hdr->encoder_decoder_buffer_delay_length);
+                    opi->low_delay_mode = dav1d_get_bit(gb);
+                }
+            }
+            if (hdr->display_model_info_present)
+                op->display_model_param_present = dav1d_get_bit(gb);
+            op->initial_display_delay =
+                op->display_model_param_present ? dav1d_get_bits(gb, 4) + 1 : 10;
+        }
+#if DEBUG_SEQ_HDR
+        printf("SEQHDR: post-operating-points: off=%u\n",
+               dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+    }
+
+    hdr->width_n_bits = dav1d_get_bits(gb, 4) + 1;
+    hdr->height_n_bits = dav1d_get_bits(gb, 4) + 1;
+    hdr->max_width = dav1d_get_bits(gb, hdr->width_n_bits) + 1;
+    hdr->max_height = dav1d_get_bits(gb, hdr->height_n_bits) + 1;
+#if DEBUG_SEQ_HDR
+    printf("SEQHDR: post-size: off=%u\n",
+           dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+    if (!hdr->reduced_still_picture_header) {
+        hdr->frame_id_numbers_present = dav1d_get_bit(gb);
+        if (hdr->frame_id_numbers_present) {
+            hdr->delta_frame_id_n_bits = dav1d_get_bits(gb, 4) + 2;
+            hdr->frame_id_n_bits = dav1d_get_bits(gb, 3) + hdr->delta_frame_id_n_bits + 1;
+        }
+    }
+#if DEBUG_SEQ_HDR
+    printf("SEQHDR: post-frame-id-numbers-present: off=%u\n",
+           dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+
+    hdr->sb128 = dav1d_get_bit(gb);
+    hdr->filter_intra = dav1d_get_bit(gb);
+    hdr->intra_edge_filter = dav1d_get_bit(gb);
+    if (hdr->reduced_still_picture_header) {
+        hdr->screen_content_tools = DAV1D_ADAPTIVE;
+        hdr->force_integer_mv = DAV1D_ADAPTIVE;
+    } else {
+        hdr->inter_intra = dav1d_get_bit(gb);
+        hdr->masked_compound = dav1d_get_bit(gb);
+        hdr->warped_motion = dav1d_get_bit(gb);
+        hdr->dual_filter = dav1d_get_bit(gb);
+        hdr->order_hint = dav1d_get_bit(gb);
+        if (hdr->order_hint) {
+            hdr->jnt_comp = dav1d_get_bit(gb);
+            hdr->ref_frame_mvs = dav1d_get_bit(gb);
+        }
+        hdr->screen_content_tools = dav1d_get_bit(gb) ? DAV1D_ADAPTIVE : dav1d_get_bit(gb);
+    #if DEBUG_SEQ_HDR
+        printf("SEQHDR: post-screentools: off=%u\n",
+               dav1d_get_bits_pos(gb) - init_bit_pos);
+    #endif
+        hdr->force_integer_mv = hdr->screen_content_tools ?
+                                dav1d_get_bit(gb) ? DAV1D_ADAPTIVE : dav1d_get_bit(gb) : 2;
+        if (hdr->order_hint)
+            hdr->order_hint_n_bits = dav1d_get_bits(gb, 3) + 1;
+    }
+    hdr->super_res = dav1d_get_bit(gb);
+    hdr->cdef = dav1d_get_bit(gb);
+    hdr->restoration = dav1d_get_bit(gb);
+#if DEBUG_SEQ_HDR
+    printf("SEQHDR: post-featurebits: off=%u\n",
+           dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+
+    hdr->hbd = dav1d_get_bit(gb);
+    if (hdr->profile == 2 && hdr->hbd)
+        hdr->hbd += dav1d_get_bit(gb);
+    if (hdr->profile != 1)
+        hdr->monochrome = dav1d_get_bit(gb);
+    hdr->color_description_present = dav1d_get_bit(gb);
+    if (hdr->color_description_present) {
+        hdr->pri = dav1d_get_bits(gb, 8);
+        hdr->trc = dav1d_get_bits(gb, 8);
+        hdr->mtrx = dav1d_get_bits(gb, 8);
+    } else {
+        hdr->pri = DAV1D_COLOR_PRI_UNKNOWN;
+        hdr->trc = DAV1D_TRC_UNKNOWN;
+        hdr->mtrx = DAV1D_MC_UNKNOWN;
+    }
+    if (hdr->monochrome) {
+        hdr->color_range = dav1d_get_bit(gb);
+        hdr->layout = DAV1D_PIXEL_LAYOUT_I400;
+        hdr->ss_hor = hdr->ss_ver = 1;
+        hdr->chr = DAV1D_CHR_UNKNOWN;
+    } else if (hdr->pri == DAV1D_COLOR_PRI_BT709 &&
+               hdr->trc == DAV1D_TRC_SRGB &&
+               hdr->mtrx == DAV1D_MC_IDENTITY)
+    {
+        hdr->layout = DAV1D_PIXEL_LAYOUT_I444;
+        hdr->color_range = 1;
+        if (hdr->profile != 1 && !(hdr->profile == 2 && hdr->hbd == 2))
+            goto error;
+    } else {
+        hdr->color_range = dav1d_get_bit(gb);
+        switch (hdr->profile) {
+        case 0: hdr->layout = DAV1D_PIXEL_LAYOUT_I420;
+                hdr->ss_hor = hdr->ss_ver = 1;
+                break;
+        case 1: hdr->layout = DAV1D_PIXEL_LAYOUT_I444;
+                break;
+        case 2:
+            if (hdr->hbd == 2) {
+                hdr->ss_hor = dav1d_get_bit(gb);
+                if (hdr->ss_hor)
+                    hdr->ss_ver = dav1d_get_bit(gb);
+            } else
+                hdr->ss_hor = 1;
+            hdr->layout = hdr->ss_hor ?
+                          hdr->ss_ver ? DAV1D_PIXEL_LAYOUT_I420 :
+                                        DAV1D_PIXEL_LAYOUT_I422 :
+                                        DAV1D_PIXEL_LAYOUT_I444;
+            break;
+        }
+        hdr->chr = (hdr->ss_hor & hdr->ss_ver) ?
+                   dav1d_get_bits(gb, 2) : DAV1D_CHR_UNKNOWN;
+    }
+    if (strict_std_compliance &&
+        hdr->mtrx == DAV1D_MC_IDENTITY && hdr->layout != DAV1D_PIXEL_LAYOUT_I444)
+    {
+        goto error;
+    }
+    if (!hdr->monochrome)
+        hdr->separate_uv_delta_q = dav1d_get_bit(gb);
+#if DEBUG_SEQ_HDR
+    printf("SEQHDR: post-colorinfo: off=%u\n",
+           dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+
+    hdr->film_grain_present = dav1d_get_bit(gb);
+#if DEBUG_SEQ_HDR
+    printf("SEQHDR: post-filmgrain: off=%u\n",
+           dav1d_get_bits_pos(gb) - init_bit_pos);
+#endif
+
+    // We needn't bother flushing the OBU here: we'll check we didn't
+    // overrun in the caller and will then discard gb, so there's no
+    // point in setting its position properly.
+
+    return check_trailing_bits(gb, strict_std_compliance);
+
+error:
+    return DAV1D_ERR(EINVAL);
+}
+
+int dav1d_parse_sequence_header(Dav1dSequenceHeader *const out,
+                                const uint8_t *const ptr, const size_t sz)
+{
+    validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(ptr != NULL, DAV1D_ERR(EINVAL));
+    validate_input_or_ret(sz > 0 && sz <= SIZE_MAX / 2, DAV1D_ERR(EINVAL));
+
+    GetBits gb;
+    dav1d_init_get_bits(&gb, ptr, sz);
+    int res = DAV1D_ERR(ENOENT);
+
+    do {
+        dav1d_get_bit(&gb); // obu_forbidden_bit
+        const enum Dav1dObuType type = dav1d_get_bits(&gb, 4);
+        const int has_extension = dav1d_get_bit(&gb);
+        const int has_length_field = dav1d_get_bit(&gb);
+        dav1d_get_bits(&gb, 1 + 8 * has_extension); // ignore
+
+        const uint8_t *obu_end = gb.ptr_end;
+        if (has_length_field) {
+            const size_t len = dav1d_get_uleb128(&gb);
+            if (len > (size_t)(obu_end - gb.ptr)) return DAV1D_ERR(EINVAL);
+            obu_end = gb.ptr + len;
+        }
+
+        if (type == DAV1D_OBU_SEQ_HDR) {
+            if ((res = parse_seq_hdr(out, &gb, 0)) < 0) return res;
+            if (gb.ptr > obu_end) return DAV1D_ERR(EINVAL);
+            dav1d_bytealign_get_bits(&gb);
+        }
+
+        if (gb.error) return DAV1D_ERR(EINVAL);
+        assert(gb.state == 0 && gb.bits_left == 0);
+        gb.ptr = obu_end;
+    } while (gb.ptr < gb.ptr_end);
+
+    return res;
+}
+
+static int read_frame_size(Dav1dContext *const c, GetBits *const gb,
+                           const int use_ref)
+{
+    const Dav1dSequenceHeader *const seqhdr = c->seq_hdr;
+    Dav1dFrameHeader *const hdr = c->frame_hdr;
+
+    if (use_ref) {
+        for (int i = 0; i < 7; i++) {
+            if (dav1d_get_bit(gb)) {
+                const Dav1dThreadPicture *const ref =
+                    &c->refs[c->frame_hdr->refidx[i]].p;
+                if (!ref->p.frame_hdr) return -1;
+                hdr->width[1] = ref->p.frame_hdr->width[1];
+                hdr->height = ref->p.frame_hdr->height;
+                hdr->render_width = ref->p.frame_hdr->render_width;
+                hdr->render_height = ref->p.frame_hdr->render_height;
+                hdr->super_res.enabled = seqhdr->super_res && dav1d_get_bit(gb);
+                if (hdr->super_res.enabled) {
+                    const int d = hdr->super_res.width_scale_denominator =
+                        9 + dav1d_get_bits(gb, 3);
+                    hdr->width[0] = imax((hdr->width[1] * 8 + (d >> 1)) / d,
+                                         imin(16, hdr->width[1]));
+                } else {
+                    hdr->super_res.width_scale_denominator = 8;
+                    hdr->width[0] = hdr->width[1];
+                }
+                return 0;
+            }
+        }
+    }
+
+    if (hdr->frame_size_override) {
+        hdr->width[1] = dav1d_get_bits(gb, seqhdr->width_n_bits) + 1;
+        hdr->height = dav1d_get_bits(gb, seqhdr->height_n_bits) + 1;
+    } else {
+        hdr->width[1] = seqhdr->max_width;
+        hdr->height = seqhdr->max_height;
+    }
+    hdr->super_res.enabled = seqhdr->super_res && dav1d_get_bit(gb);
+    if (hdr->super_res.enabled) {
+        const int d = hdr->super_res.width_scale_denominator = 9 + dav1d_get_bits(gb, 3);
+        hdr->width[0] = imax((hdr->width[1] * 8 + (d >> 1)) / d, imin(16, hdr->width[1]));
+    } else {
+        hdr->super_res.width_scale_denominator = 8;
+        hdr->width[0] = hdr->width[1];
+    }
+    hdr->have_render_size = dav1d_get_bit(gb);
+    if (hdr->have_render_size) {
+        hdr->render_width = dav1d_get_bits(gb, 16) + 1;
+        hdr->render_height = dav1d_get_bits(gb, 16) + 1;
+    } else {
+        hdr->render_width = hdr->width[1];
+        hdr->render_height = hdr->height;
+    }
+    return 0;
+}
+
+static inline int tile_log2(const int sz, const int tgt) {
+    int k;
+    for (k = 0; (sz << k) < tgt; k++) ;
+    return k;
+}
+
+static const Dav1dLoopfilterModeRefDeltas default_mode_ref_deltas = {
+    .mode_delta = { 0, 0 },
+    .ref_delta = { 1, 0, 0, 0, -1, 0, -1, -1 },
+};
+
+static int parse_frame_hdr(Dav1dContext *const c, GetBits *const gb) {
+#define DEBUG_FRAME_HDR 0
+
+#if DEBUG_FRAME_HDR
+    const uint8_t *const init_ptr = gb->ptr;
+#endif
+    const Dav1dSequenceHeader *const seqhdr = c->seq_hdr;
+    Dav1dFrameHeader *const hdr = c->frame_hdr;
+
+    if (!seqhdr->reduced_still_picture_header)
+        hdr->show_existing_frame = dav1d_get_bit(gb);
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-show_existing_frame: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+    if (hdr->show_existing_frame) {
+        hdr->existing_frame_idx = dav1d_get_bits(gb, 3);
+        if (seqhdr->decoder_model_info_present && !seqhdr->equal_picture_interval)
+            hdr->frame_presentation_delay = dav1d_get_bits(gb, seqhdr->frame_presentation_delay_length);
+        if (seqhdr->frame_id_numbers_present) {
+            hdr->frame_id = dav1d_get_bits(gb, seqhdr->frame_id_n_bits);
+            Dav1dFrameHeader *const ref_frame_hdr = c->refs[hdr->existing_frame_idx].p.p.frame_hdr;
+            if (!ref_frame_hdr || ref_frame_hdr->frame_id != hdr->frame_id) goto error;
+        }
+        return 0;
+    }
+
+    if (seqhdr->reduced_still_picture_header) {
+        hdr->frame_type = DAV1D_FRAME_TYPE_KEY;
+        hdr->show_frame = 1;
+    } else {
+        hdr->frame_type = dav1d_get_bits(gb, 2);
+        hdr->show_frame = dav1d_get_bit(gb);
+    }
+    if (hdr->show_frame) {
+        if (seqhdr->decoder_model_info_present && !seqhdr->equal_picture_interval)
+            hdr->frame_presentation_delay = dav1d_get_bits(gb, seqhdr->frame_presentation_delay_length);
+        hdr->showable_frame = hdr->frame_type != DAV1D_FRAME_TYPE_KEY;
+    } else
+        hdr->showable_frame = dav1d_get_bit(gb);
+    hdr->error_resilient_mode =
+        (hdr->frame_type == DAV1D_FRAME_TYPE_KEY && hdr->show_frame) ||
+        hdr->frame_type == DAV1D_FRAME_TYPE_SWITCH ||
+        seqhdr->reduced_still_picture_header || dav1d_get_bit(gb);
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-frametype_bits: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+    hdr->disable_cdf_update = dav1d_get_bit(gb);
+    hdr->allow_screen_content_tools = seqhdr->screen_content_tools == DAV1D_ADAPTIVE ?
+                                      dav1d_get_bit(gb) : seqhdr->screen_content_tools;
+    if (hdr->allow_screen_content_tools)
+        hdr->force_integer_mv = seqhdr->force_integer_mv == DAV1D_ADAPTIVE ?
+                                dav1d_get_bit(gb) : seqhdr->force_integer_mv;
+
+    if (IS_KEY_OR_INTRA(hdr))
+        hdr->force_integer_mv = 1;
+
+    if (seqhdr->frame_id_numbers_present)
+        hdr->frame_id = dav1d_get_bits(gb, seqhdr->frame_id_n_bits);
+
+    if (!seqhdr->reduced_still_picture_header)
+        hdr->frame_size_override = hdr->frame_type == DAV1D_FRAME_TYPE_SWITCH ? 1 : dav1d_get_bit(gb);
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-frame_size_override_flag: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+    if (seqhdr->order_hint)
+        hdr->frame_offset = dav1d_get_bits(gb, seqhdr->order_hint_n_bits);
+    hdr->primary_ref_frame = !hdr->error_resilient_mode && IS_INTER_OR_SWITCH(hdr) ?
+                             dav1d_get_bits(gb, 3) : DAV1D_PRIMARY_REF_NONE;
+
+    if (seqhdr->decoder_model_info_present) {
+        hdr->buffer_removal_time_present = dav1d_get_bit(gb);
+        if (hdr->buffer_removal_time_present) {
+            for (int i = 0; i < c->seq_hdr->num_operating_points; i++) {
+                const struct Dav1dSequenceHeaderOperatingPoint *const seqop = &seqhdr->operating_points[i];
+                struct Dav1dFrameHeaderOperatingPoint *const op = &hdr->operating_points[i];
+                if (seqop->decoder_model_param_present) {
+                    int in_temporal_layer = (seqop->idc >> hdr->temporal_id) & 1;
+                    int in_spatial_layer  = (seqop->idc >> (hdr->spatial_id + 8)) & 1;
+                    if (!seqop->idc || (in_temporal_layer && in_spatial_layer))
+                        op->buffer_removal_time = dav1d_get_bits(gb, seqhdr->buffer_removal_delay_length);
+                }
+            }
+        }
+    }
+
+    if (IS_KEY_OR_INTRA(hdr)) {
+        hdr->refresh_frame_flags = (hdr->frame_type == DAV1D_FRAME_TYPE_KEY &&
+                                    hdr->show_frame) ? 0xff : dav1d_get_bits(gb, 8);
+        if (hdr->refresh_frame_flags != 0xff && hdr->error_resilient_mode && seqhdr->order_hint)
+            for (int i = 0; i < 8; i++)
+                dav1d_get_bits(gb, seqhdr->order_hint_n_bits);
+        if (c->strict_std_compliance &&
+            hdr->frame_type == DAV1D_FRAME_TYPE_INTRA && hdr->refresh_frame_flags == 0xff)
+        {
+            goto error;
+        }
+        if (read_frame_size(c, gb, 0) < 0) goto error;
+        if (hdr->allow_screen_content_tools && !hdr->super_res.enabled)
+            hdr->allow_intrabc = dav1d_get_bit(gb);
+    } else {
+        hdr->refresh_frame_flags = hdr->frame_type == DAV1D_FRAME_TYPE_SWITCH ? 0xff :
+                                   dav1d_get_bits(gb, 8);
+        if (hdr->error_resilient_mode && seqhdr->order_hint)
+            for (int i = 0; i < 8; i++)
+                dav1d_get_bits(gb, seqhdr->order_hint_n_bits);
+        if (seqhdr->order_hint) {
+            hdr->frame_ref_short_signaling = dav1d_get_bit(gb);
+            if (hdr->frame_ref_short_signaling) {
+                hdr->refidx[0] = dav1d_get_bits(gb, 3);
+                hdr->refidx[1] = hdr->refidx[2] = -1;
+                hdr->refidx[3] = dav1d_get_bits(gb, 3);
+
+                /* +1 allows for unconditional stores, as unused
+                 * values can be dumped into frame_offset[-1]. */
+                int frame_offset_mem[8+1];
+                int *const frame_offset = &frame_offset_mem[1];
+                int earliest_ref = -1;
+                for (int i = 0, earliest_offset = INT_MAX; i < 8; i++) {
+                    const Dav1dFrameHeader *const refhdr = c->refs[i].p.p.frame_hdr;
+                    if (!refhdr) goto error;
+                    const int diff = get_poc_diff(seqhdr->order_hint_n_bits,
+                                                  refhdr->frame_offset,
+                                                  hdr->frame_offset);
+                    frame_offset[i] = diff;
+                    if (diff < earliest_offset) {
+                        earliest_offset = diff;
+                        earliest_ref = i;
+                    }
+                }
+                frame_offset[hdr->refidx[0]] = INT_MIN; // = reference frame is used
+                frame_offset[hdr->refidx[3]] = INT_MIN;
+                assert(earliest_ref >= 0);
+
+                int refidx = -1;
+                for (int i = 0, latest_offset = 0; i < 8; i++) {
+                    const int hint = frame_offset[i];
+                    if (hint >= latest_offset) {
+                        latest_offset = hint;
+                        refidx = i;
+                    }
+                }
+                frame_offset[refidx] = INT_MIN;
+                hdr->refidx[6] = refidx;
+
+                for (int i = 4; i < 6; i++) {
+                    /* Unsigned compares to handle negative values. */
+                    unsigned earliest_offset = UINT8_MAX;
+                    refidx = -1;
+                    for (int j = 0; j < 8; j++) {
+                        const unsigned hint = frame_offset[j];
+                        if (hint < earliest_offset) {
+                            earliest_offset = hint;
+                            refidx = j;
+                        }
+                    }
+                    frame_offset[refidx] = INT_MIN;
+                    hdr->refidx[i] = refidx;
+                }
+
+                for (int i = 1; i < 7; i++) {
+                    refidx = hdr->refidx[i];
+                    if (refidx < 0) {
+                        unsigned latest_offset = ~UINT8_MAX;
+                        for (int j = 0; j < 8; j++) {
+                            const unsigned hint = frame_offset[j];
+                            if (hint >= latest_offset) {
+                                latest_offset = hint;
+                                refidx = j;
+                            }
+                        }
+                        frame_offset[refidx] = INT_MIN;
+                        hdr->refidx[i] = refidx >= 0 ? refidx : earliest_ref;
+                    }
+                }
+            }
+        }
+        for (int i = 0; i < 7; i++) {
+            if (!hdr->frame_ref_short_signaling)
+                hdr->refidx[i] = dav1d_get_bits(gb, 3);
+            if (seqhdr->frame_id_numbers_present) {
+                const unsigned delta_ref_frame_id = dav1d_get_bits(gb, seqhdr->delta_frame_id_n_bits) + 1;
+                const unsigned ref_frame_id = (hdr->frame_id + (1 << seqhdr->frame_id_n_bits) - delta_ref_frame_id) & ((1 << seqhdr->frame_id_n_bits) - 1);
+                Dav1dFrameHeader *const ref_frame_hdr = c->refs[hdr->refidx[i]].p.p.frame_hdr;
+                if (!ref_frame_hdr || ref_frame_hdr->frame_id != ref_frame_id) goto error;
+            }
+        }
+        const int use_ref = !hdr->error_resilient_mode &&
+                            hdr->frame_size_override;
+        if (read_frame_size(c, gb, use_ref) < 0) goto error;
+        if (!hdr->force_integer_mv)
+            hdr->hp = dav1d_get_bit(gb);
+        hdr->subpel_filter_mode = dav1d_get_bit(gb) ? DAV1D_FILTER_SWITCHABLE :
+                                                      dav1d_get_bits(gb, 2);
+        hdr->switchable_motion_mode = dav1d_get_bit(gb);
+        if (!hdr->error_resilient_mode && seqhdr->ref_frame_mvs &&
+            seqhdr->order_hint && IS_INTER_OR_SWITCH(hdr))
+        {
+            hdr->use_ref_frame_mvs = dav1d_get_bit(gb);
+        }
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-frametype-specific-bits: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    if (!seqhdr->reduced_still_picture_header && !hdr->disable_cdf_update)
+        hdr->refresh_context = !dav1d_get_bit(gb);
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-refresh_context: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    // tile data
+    hdr->tiling.uniform = dav1d_get_bit(gb);
+    const int sbsz_min1 = (64 << seqhdr->sb128) - 1;
+    const int sbsz_log2 = 6 + seqhdr->sb128;
+    const int sbw = (hdr->width[0] + sbsz_min1) >> sbsz_log2;
+    const int sbh = (hdr->height + sbsz_min1) >> sbsz_log2;
+    const int max_tile_width_sb = 4096 >> sbsz_log2;
+    const int max_tile_area_sb = 4096 * 2304 >> (2 * sbsz_log2);
+    hdr->tiling.min_log2_cols = tile_log2(max_tile_width_sb, sbw);
+    hdr->tiling.max_log2_cols = tile_log2(1, imin(sbw, DAV1D_MAX_TILE_COLS));
+    hdr->tiling.max_log2_rows = tile_log2(1, imin(sbh, DAV1D_MAX_TILE_ROWS));
+    const int min_log2_tiles = imax(tile_log2(max_tile_area_sb, sbw * sbh),
+                              hdr->tiling.min_log2_cols);
+    if (hdr->tiling.uniform) {
+        for (hdr->tiling.log2_cols = hdr->tiling.min_log2_cols;
+             hdr->tiling.log2_cols < hdr->tiling.max_log2_cols && dav1d_get_bit(gb);
+             hdr->tiling.log2_cols++) ;
+        const int tile_w = 1 + ((sbw - 1) >> hdr->tiling.log2_cols);
+        hdr->tiling.cols = 0;
+        for (int sbx = 0; sbx < sbw; sbx += tile_w, hdr->tiling.cols++)
+            hdr->tiling.col_start_sb[hdr->tiling.cols] = sbx;
+        hdr->tiling.min_log2_rows =
+            imax(min_log2_tiles - hdr->tiling.log2_cols, 0);
+
+        for (hdr->tiling.log2_rows = hdr->tiling.min_log2_rows;
+             hdr->tiling.log2_rows < hdr->tiling.max_log2_rows && dav1d_get_bit(gb);
+             hdr->tiling.log2_rows++) ;
+        const int tile_h = 1 + ((sbh - 1) >> hdr->tiling.log2_rows);
+        hdr->tiling.rows = 0;
+        for (int sby = 0; sby < sbh; sby += tile_h, hdr->tiling.rows++)
+            hdr->tiling.row_start_sb[hdr->tiling.rows] = sby;
+    } else {
+        hdr->tiling.cols = 0;
+        int widest_tile = 0, max_tile_area_sb = sbw * sbh;
+        for (int sbx = 0; sbx < sbw && hdr->tiling.cols < DAV1D_MAX_TILE_COLS; hdr->tiling.cols++) {
+            const int tile_width_sb = imin(sbw - sbx, max_tile_width_sb);
+            const int tile_w = (tile_width_sb > 1) ? 1 + dav1d_get_uniform(gb, tile_width_sb) : 1;
+            hdr->tiling.col_start_sb[hdr->tiling.cols] = sbx;
+            sbx += tile_w;
+            widest_tile = imax(widest_tile, tile_w);
+        }
+        hdr->tiling.log2_cols = tile_log2(1, hdr->tiling.cols);
+        if (min_log2_tiles) max_tile_area_sb >>= min_log2_tiles + 1;
+        const int max_tile_height_sb = imax(max_tile_area_sb / widest_tile, 1);
+
+        hdr->tiling.rows = 0;
+        for (int sby = 0; sby < sbh && hdr->tiling.rows < DAV1D_MAX_TILE_ROWS; hdr->tiling.rows++) {
+            const int tile_height_sb = imin(sbh - sby, max_tile_height_sb);
+            const int tile_h = (tile_height_sb > 1) ? 1 + dav1d_get_uniform(gb, tile_height_sb) : 1;
+            hdr->tiling.row_start_sb[hdr->tiling.rows] = sby;
+            sby += tile_h;
+        }
+        hdr->tiling.log2_rows = tile_log2(1, hdr->tiling.rows);
+    }
+    hdr->tiling.col_start_sb[hdr->tiling.cols] = sbw;
+    hdr->tiling.row_start_sb[hdr->tiling.rows] = sbh;
+    if (hdr->tiling.log2_cols || hdr->tiling.log2_rows) {
+        hdr->tiling.update = dav1d_get_bits(gb, hdr->tiling.log2_cols + hdr->tiling.log2_rows);
+        if (hdr->tiling.update >= hdr->tiling.cols * hdr->tiling.rows)
+            goto error;
+        hdr->tiling.n_bytes = dav1d_get_bits(gb, 2) + 1;
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-tiling: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    // quant data
+    hdr->quant.yac = dav1d_get_bits(gb, 8);
+    if (dav1d_get_bit(gb))
+        hdr->quant.ydc_delta = dav1d_get_sbits(gb, 7);
+    if (!seqhdr->monochrome) {
+        // If the sequence header says that delta_q might be different
+        // for U, V, we must check whether it actually is for this
+        // frame.
+        const int diff_uv_delta = seqhdr->separate_uv_delta_q ? dav1d_get_bit(gb) : 0;
+        if (dav1d_get_bit(gb))
+            hdr->quant.udc_delta = dav1d_get_sbits(gb, 7);
+        if (dav1d_get_bit(gb))
+            hdr->quant.uac_delta = dav1d_get_sbits(gb, 7);
+        if (diff_uv_delta) {
+            if (dav1d_get_bit(gb))
+                hdr->quant.vdc_delta = dav1d_get_sbits(gb, 7);
+            if (dav1d_get_bit(gb))
+                hdr->quant.vac_delta = dav1d_get_sbits(gb, 7);
+        } else {
+            hdr->quant.vdc_delta = hdr->quant.udc_delta;
+            hdr->quant.vac_delta = hdr->quant.uac_delta;
+        }
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-quant: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+    hdr->quant.qm = dav1d_get_bit(gb);
+    if (hdr->quant.qm) {
+        hdr->quant.qm_y = dav1d_get_bits(gb, 4);
+        hdr->quant.qm_u = dav1d_get_bits(gb, 4);
+        hdr->quant.qm_v = seqhdr->separate_uv_delta_q ? dav1d_get_bits(gb, 4) :
+                                                        hdr->quant.qm_u;
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-qm: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    // segmentation data
+    hdr->segmentation.enabled = dav1d_get_bit(gb);
+    if (hdr->segmentation.enabled) {
+        if (hdr->primary_ref_frame == DAV1D_PRIMARY_REF_NONE) {
+            hdr->segmentation.update_map = 1;
+            hdr->segmentation.update_data = 1;
+        } else {
+            hdr->segmentation.update_map = dav1d_get_bit(gb);
+            if (hdr->segmentation.update_map)
+                hdr->segmentation.temporal = dav1d_get_bit(gb);
+            hdr->segmentation.update_data = dav1d_get_bit(gb);
+        }
+
+        if (hdr->segmentation.update_data) {
+            hdr->segmentation.seg_data.last_active_segid = -1;
+            for (int i = 0; i < DAV1D_MAX_SEGMENTS; i++) {
+                Dav1dSegmentationData *const seg =
+                    &hdr->segmentation.seg_data.d[i];
+                if (dav1d_get_bit(gb)) {
+                    seg->delta_q = dav1d_get_sbits(gb, 9);
+                    hdr->segmentation.seg_data.last_active_segid = i;
+                }
+                if (dav1d_get_bit(gb)) {
+                    seg->delta_lf_y_v = dav1d_get_sbits(gb, 7);
+                    hdr->segmentation.seg_data.last_active_segid = i;
+                }
+                if (dav1d_get_bit(gb)) {
+                    seg->delta_lf_y_h = dav1d_get_sbits(gb, 7);
+                    hdr->segmentation.seg_data.last_active_segid = i;
+                }
+                if (dav1d_get_bit(gb)) {
+                    seg->delta_lf_u = dav1d_get_sbits(gb, 7);
+                    hdr->segmentation.seg_data.last_active_segid = i;
+                }
+                if (dav1d_get_bit(gb)) {
+                    seg->delta_lf_v = dav1d_get_sbits(gb, 7);
+                    hdr->segmentation.seg_data.last_active_segid = i;
+                }
+                if (dav1d_get_bit(gb)) {
+                    seg->ref = dav1d_get_bits(gb, 3);
+                    hdr->segmentation.seg_data.last_active_segid = i;
+                    hdr->segmentation.seg_data.preskip = 1;
+                } else {
+                    seg->ref = -1;
+                }
+                if ((seg->skip = dav1d_get_bit(gb))) {
+                    hdr->segmentation.seg_data.last_active_segid = i;
+                    hdr->segmentation.seg_data.preskip = 1;
+                }
+                if ((seg->globalmv = dav1d_get_bit(gb))) {
+                    hdr->segmentation.seg_data.last_active_segid = i;
+                    hdr->segmentation.seg_data.preskip = 1;
+                }
+            }
+        } else {
+            // segmentation.update_data was false so we should copy
+            // segmentation data from the reference frame.
+            assert(hdr->primary_ref_frame != DAV1D_PRIMARY_REF_NONE);
+            const int pri_ref = hdr->refidx[hdr->primary_ref_frame];
+            if (!c->refs[pri_ref].p.p.frame_hdr) goto error;
+            hdr->segmentation.seg_data =
+                c->refs[pri_ref].p.p.frame_hdr->segmentation.seg_data;
+        }
+    } else {
+        for (int i = 0; i < DAV1D_MAX_SEGMENTS; i++)
+            hdr->segmentation.seg_data.d[i].ref = -1;
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-segmentation: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    // delta q
+    if (hdr->quant.yac) {
+        hdr->delta.q.present = dav1d_get_bit(gb);
+        if (hdr->delta.q.present) {
+            hdr->delta.q.res_log2 = dav1d_get_bits(gb, 2);
+            if (!hdr->allow_intrabc) {
+                hdr->delta.lf.present = dav1d_get_bit(gb);
+                if (hdr->delta.lf.present) {
+                    hdr->delta.lf.res_log2 = dav1d_get_bits(gb, 2);
+                    hdr->delta.lf.multi = dav1d_get_bit(gb);
+                }
+            }
+        }
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-delta_q_lf_flags: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    // derive lossless flags
+    const int delta_lossless = !hdr->quant.ydc_delta && !hdr->quant.udc_delta &&
+        !hdr->quant.uac_delta && !hdr->quant.vdc_delta && !hdr->quant.vac_delta;
+    hdr->all_lossless = 1;
+    for (int i = 0; i < DAV1D_MAX_SEGMENTS; i++) {
+        hdr->segmentation.qidx[i] = hdr->segmentation.enabled ?
+            iclip_u8(hdr->quant.yac + hdr->segmentation.seg_data.d[i].delta_q) :
+            hdr->quant.yac;
+        hdr->segmentation.lossless[i] =
+            !hdr->segmentation.qidx[i] && delta_lossless;
+        hdr->all_lossless &= hdr->segmentation.lossless[i];
+    }
+
+    // loopfilter
+    if (hdr->all_lossless || hdr->allow_intrabc) {
+        hdr->loopfilter.mode_ref_delta_enabled = 1;
+        hdr->loopfilter.mode_ref_delta_update = 1;
+        hdr->loopfilter.mode_ref_deltas = default_mode_ref_deltas;
+    } else {
+        hdr->loopfilter.level_y[0] = dav1d_get_bits(gb, 6);
+        hdr->loopfilter.level_y[1] = dav1d_get_bits(gb, 6);
+        if (!seqhdr->monochrome &&
+            (hdr->loopfilter.level_y[0] || hdr->loopfilter.level_y[1]))
+        {
+            hdr->loopfilter.level_u = dav1d_get_bits(gb, 6);
+            hdr->loopfilter.level_v = dav1d_get_bits(gb, 6);
+        }
+        hdr->loopfilter.sharpness = dav1d_get_bits(gb, 3);
+
+        if (hdr->primary_ref_frame == DAV1D_PRIMARY_REF_NONE) {
+            hdr->loopfilter.mode_ref_deltas = default_mode_ref_deltas;
+        } else {
+            const int ref = hdr->refidx[hdr->primary_ref_frame];
+            if (!c->refs[ref].p.p.frame_hdr) goto error;
+            hdr->loopfilter.mode_ref_deltas =
+                c->refs[ref].p.p.frame_hdr->loopfilter.mode_ref_deltas;
+        }
+        hdr->loopfilter.mode_ref_delta_enabled = dav1d_get_bit(gb);
+        if (hdr->loopfilter.mode_ref_delta_enabled) {
+            hdr->loopfilter.mode_ref_delta_update = dav1d_get_bit(gb);
+            if (hdr->loopfilter.mode_ref_delta_update) {
+                for (int i = 0; i < 8; i++)
+                    if (dav1d_get_bit(gb))
+                        hdr->loopfilter.mode_ref_deltas.ref_delta[i] =
+                            dav1d_get_sbits(gb, 7);
+                for (int i = 0; i < 2; i++)
+                    if (dav1d_get_bit(gb))
+                        hdr->loopfilter.mode_ref_deltas.mode_delta[i] =
+                            dav1d_get_sbits(gb, 7);
+            }
+        }
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-lpf: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    // cdef
+    if (!hdr->all_lossless && seqhdr->cdef && !hdr->allow_intrabc) {
+        hdr->cdef.damping = dav1d_get_bits(gb, 2) + 3;
+        hdr->cdef.n_bits = dav1d_get_bits(gb, 2);
+        for (int i = 0; i < (1 << hdr->cdef.n_bits); i++) {
+            hdr->cdef.y_strength[i] = dav1d_get_bits(gb, 6);
+            if (!seqhdr->monochrome)
+                hdr->cdef.uv_strength[i] = dav1d_get_bits(gb, 6);
+        }
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-cdef: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    // restoration
+    if ((!hdr->all_lossless || hdr->super_res.enabled) &&
+        seqhdr->restoration && !hdr->allow_intrabc)
+    {
+        hdr->restoration.type[0] = dav1d_get_bits(gb, 2);
+        if (!seqhdr->monochrome) {
+            hdr->restoration.type[1] = dav1d_get_bits(gb, 2);
+            hdr->restoration.type[2] = dav1d_get_bits(gb, 2);
+        }
+
+        if (hdr->restoration.type[0] || hdr->restoration.type[1] ||
+            hdr->restoration.type[2])
+        {
+            // Log2 of the restoration unit size.
+            hdr->restoration.unit_size[0] = 6 + seqhdr->sb128;
+            if (dav1d_get_bit(gb)) {
+                hdr->restoration.unit_size[0]++;
+                if (!seqhdr->sb128)
+                    hdr->restoration.unit_size[0] += dav1d_get_bit(gb);
+            }
+            hdr->restoration.unit_size[1] = hdr->restoration.unit_size[0];
+            if ((hdr->restoration.type[1] || hdr->restoration.type[2]) &&
+                seqhdr->ss_hor == 1 && seqhdr->ss_ver == 1)
+            {
+                hdr->restoration.unit_size[1] -= dav1d_get_bit(gb);
+            }
+        } else {
+            hdr->restoration.unit_size[0] = 8;
+        }
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-restoration: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    if (!hdr->all_lossless)
+        hdr->txfm_mode = dav1d_get_bit(gb) ? DAV1D_TX_SWITCHABLE : DAV1D_TX_LARGEST;
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-txfmmode: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+    if (IS_INTER_OR_SWITCH(hdr))
+        hdr->switchable_comp_refs = dav1d_get_bit(gb);
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-refmode: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+    if (hdr->switchable_comp_refs && IS_INTER_OR_SWITCH(hdr) && seqhdr->order_hint) {
+        const int poc = hdr->frame_offset;
+        int off_before = -1, off_after = -1;
+        int off_before_idx, off_after_idx;
+        for (int i = 0; i < 7; i++) {
+            if (!c->refs[hdr->refidx[i]].p.p.frame_hdr) goto error;
+            const int refpoc = c->refs[hdr->refidx[i]].p.p.frame_hdr->frame_offset;
+
+            const int diff = get_poc_diff(seqhdr->order_hint_n_bits, refpoc, poc);
+            if (diff > 0) {
+                if (off_after < 0 || get_poc_diff(seqhdr->order_hint_n_bits,
+                                                  off_after, refpoc) > 0)
+                {
+                    off_after = refpoc;
+                    off_after_idx = i;
+                }
+            } else if (diff < 0 && (off_before < 0 ||
+                                    get_poc_diff(seqhdr->order_hint_n_bits,
+                                                 refpoc, off_before) > 0))
+            {
+                off_before = refpoc;
+                off_before_idx = i;
+            }
+        }
+
+        if ((off_before | off_after) >= 0) {
+            hdr->skip_mode_refs[0] = imin(off_before_idx, off_after_idx);
+            hdr->skip_mode_refs[1] = imax(off_before_idx, off_after_idx);
+            hdr->skip_mode_allowed = 1;
+        } else if (off_before >= 0) {
+            int off_before2 = -1;
+            int off_before2_idx;
+            for (int i = 0; i < 7; i++) {
+                if (!c->refs[hdr->refidx[i]].p.p.frame_hdr) goto error;
+                const int refpoc = c->refs[hdr->refidx[i]].p.p.frame_hdr->frame_offset;
+                if (get_poc_diff(seqhdr->order_hint_n_bits,
+                                 refpoc, off_before) < 0) {
+                    if (off_before2 < 0 || get_poc_diff(seqhdr->order_hint_n_bits,
+                                                        refpoc, off_before2) > 0)
+                    {
+                        off_before2 = refpoc;
+                        off_before2_idx = i;
+                    }
+                }
+            }
+
+            if (off_before2 >= 0) {
+                hdr->skip_mode_refs[0] = imin(off_before_idx, off_before2_idx);
+                hdr->skip_mode_refs[1] = imax(off_before_idx, off_before2_idx);
+                hdr->skip_mode_allowed = 1;
+            }
+        }
+    }
+    if (hdr->skip_mode_allowed)
+        hdr->skip_mode_enabled = dav1d_get_bit(gb);
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-extskip: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+    if (!hdr->error_resilient_mode && IS_INTER_OR_SWITCH(hdr) && seqhdr->warped_motion)
+        hdr->warp_motion = dav1d_get_bit(gb);
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-warpmotionbit: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+    hdr->reduced_txtp_set = dav1d_get_bit(gb);
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-reducedtxtpset: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    for (int i = 0; i < 7; i++)
+        hdr->gmv[i] = dav1d_default_wm_params;
+
+    if (IS_INTER_OR_SWITCH(hdr)) {
+        for (int i = 0; i < 7; i++) {
+            hdr->gmv[i].type = !dav1d_get_bit(gb) ? DAV1D_WM_TYPE_IDENTITY :
+                                dav1d_get_bit(gb) ? DAV1D_WM_TYPE_ROT_ZOOM :
+                                dav1d_get_bit(gb) ? DAV1D_WM_TYPE_TRANSLATION :
+                                                    DAV1D_WM_TYPE_AFFINE;
+
+            if (hdr->gmv[i].type == DAV1D_WM_TYPE_IDENTITY) continue;
+
+            const Dav1dWarpedMotionParams *ref_gmv;
+            if (hdr->primary_ref_frame == DAV1D_PRIMARY_REF_NONE) {
+                ref_gmv = &dav1d_default_wm_params;
+            } else {
+                const int pri_ref = hdr->refidx[hdr->primary_ref_frame];
+                if (!c->refs[pri_ref].p.p.frame_hdr) goto error;
+                ref_gmv = &c->refs[pri_ref].p.p.frame_hdr->gmv[i];
+            }
+            int32_t *const mat = hdr->gmv[i].matrix;
+            const int32_t *const ref_mat = ref_gmv->matrix;
+            int bits, shift;
+
+            if (hdr->gmv[i].type >= DAV1D_WM_TYPE_ROT_ZOOM) {
+                mat[2] = (1 << 16) + 2 *
+                    dav1d_get_bits_subexp(gb, (ref_mat[2] - (1 << 16)) >> 1, 12);
+                mat[3] = 2 * dav1d_get_bits_subexp(gb, ref_mat[3] >> 1, 12);
+
+                bits = 12;
+                shift = 10;
+            } else {
+                bits = 9 - !hdr->hp;
+                shift = 13 + !hdr->hp;
+            }
+
+            if (hdr->gmv[i].type == DAV1D_WM_TYPE_AFFINE) {
+                mat[4] = 2 * dav1d_get_bits_subexp(gb, ref_mat[4] >> 1, 12);
+                mat[5] = (1 << 16) + 2 *
+                    dav1d_get_bits_subexp(gb, (ref_mat[5] - (1 << 16)) >> 1, 12);
+            } else {
+                mat[4] = -mat[3];
+                mat[5] = mat[2];
+            }
+
+            mat[0] = dav1d_get_bits_subexp(gb, ref_mat[0] >> shift, bits) * (1 << shift);
+            mat[1] = dav1d_get_bits_subexp(gb, ref_mat[1] >> shift, bits) * (1 << shift);
+        }
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-gmv: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    if (seqhdr->film_grain_present && (hdr->show_frame || hdr->showable_frame)) {
+        hdr->film_grain.present = dav1d_get_bit(gb);
+        if (hdr->film_grain.present) {
+            const unsigned seed = dav1d_get_bits(gb, 16);
+            hdr->film_grain.update = hdr->frame_type != DAV1D_FRAME_TYPE_INTER || dav1d_get_bit(gb);
+            if (!hdr->film_grain.update) {
+                const int refidx = dav1d_get_bits(gb, 3);
+                int i;
+                for (i = 0; i < 7; i++)
+                    if (hdr->refidx[i] == refidx)
+                        break;
+                if (i == 7 || !c->refs[refidx].p.p.frame_hdr) goto error;
+                hdr->film_grain.data = c->refs[refidx].p.p.frame_hdr->film_grain.data;
+                hdr->film_grain.data.seed = seed;
+            } else {
+                Dav1dFilmGrainData *const fgd = &hdr->film_grain.data;
+                fgd->seed = seed;
+
+                fgd->num_y_points = dav1d_get_bits(gb, 4);
+                if (fgd->num_y_points > 14) goto error;
+                for (int i = 0; i < fgd->num_y_points; i++) {
+                    fgd->y_points[i][0] = dav1d_get_bits(gb, 8);
+                    if (i && fgd->y_points[i - 1][0] >= fgd->y_points[i][0])
+                        goto error;
+                    fgd->y_points[i][1] = dav1d_get_bits(gb, 8);
+                }
+
+                if (!seqhdr->monochrome)
+                    fgd->chroma_scaling_from_luma = dav1d_get_bit(gb);
+                if (seqhdr->monochrome || fgd->chroma_scaling_from_luma ||
+                    (seqhdr->ss_ver == 1 && seqhdr->ss_hor == 1 && !fgd->num_y_points))
+                {
+                    fgd->num_uv_points[0] = fgd->num_uv_points[1] = 0;
+                } else for (int pl = 0; pl < 2; pl++) {
+                    fgd->num_uv_points[pl] = dav1d_get_bits(gb, 4);
+                    if (fgd->num_uv_points[pl] > 10) goto error;
+                    for (int i = 0; i < fgd->num_uv_points[pl]; i++) {
+                        fgd->uv_points[pl][i][0] = dav1d_get_bits(gb, 8);
+                        if (i && fgd->uv_points[pl][i - 1][0] >= fgd->uv_points[pl][i][0])
+                            goto error;
+                        fgd->uv_points[pl][i][1] = dav1d_get_bits(gb, 8);
+                    }
+                }
+
+                if (seqhdr->ss_hor == 1 && seqhdr->ss_ver == 1 &&
+                    !!fgd->num_uv_points[0] != !!fgd->num_uv_points[1])
+                {
+                    goto error;
+                }
+
+                fgd->scaling_shift = dav1d_get_bits(gb, 2) + 8;
+                fgd->ar_coeff_lag = dav1d_get_bits(gb, 2);
+                const int num_y_pos = 2 * fgd->ar_coeff_lag * (fgd->ar_coeff_lag + 1);
+                if (fgd->num_y_points)
+                    for (int i = 0; i < num_y_pos; i++)
+                        fgd->ar_coeffs_y[i] = dav1d_get_bits(gb, 8) - 128;
+                for (int pl = 0; pl < 2; pl++)
+                    if (fgd->num_uv_points[pl] || fgd->chroma_scaling_from_luma) {
+                        const int num_uv_pos = num_y_pos + !!fgd->num_y_points;
+                        for (int i = 0; i < num_uv_pos; i++)
+                            fgd->ar_coeffs_uv[pl][i] = dav1d_get_bits(gb, 8) - 128;
+                        if (!fgd->num_y_points)
+                            fgd->ar_coeffs_uv[pl][num_uv_pos] = 0;
+                    }
+                fgd->ar_coeff_shift = dav1d_get_bits(gb, 2) + 6;
+                fgd->grain_scale_shift = dav1d_get_bits(gb, 2);
+                for (int pl = 0; pl < 2; pl++)
+                    if (fgd->num_uv_points[pl]) {
+                        fgd->uv_mult[pl] = dav1d_get_bits(gb, 8) - 128;
+                        fgd->uv_luma_mult[pl] = dav1d_get_bits(gb, 8) - 128;
+                        fgd->uv_offset[pl] = dav1d_get_bits(gb, 9) - 256;
+                    }
+                fgd->overlap_flag = dav1d_get_bit(gb);
+                fgd->clip_to_restricted_range = dav1d_get_bit(gb);
+            }
+        }
+    }
+#if DEBUG_FRAME_HDR
+    printf("HDR: post-filmgrain: off=%td\n",
+           (gb->ptr - init_ptr) * 8 - gb->bits_left);
+#endif
+
+    return 0;
+
+error:
+    dav1d_log(c, "Error parsing frame header\n");
+    return DAV1D_ERR(EINVAL);
+}
+
+static void parse_tile_hdr(Dav1dContext *const c, GetBits *const gb) {
+    const int n_tiles = c->frame_hdr->tiling.cols * c->frame_hdr->tiling.rows;
+    const int have_tile_pos = n_tiles > 1 ? dav1d_get_bit(gb) : 0;
+
+    if (have_tile_pos) {
+        const int n_bits = c->frame_hdr->tiling.log2_cols +
+                           c->frame_hdr->tiling.log2_rows;
+        c->tile[c->n_tile_data].start = dav1d_get_bits(gb, n_bits);
+        c->tile[c->n_tile_data].end = dav1d_get_bits(gb, n_bits);
+    } else {
+        c->tile[c->n_tile_data].start = 0;
+        c->tile[c->n_tile_data].end = n_tiles - 1;
+    }
+}
+
+ptrdiff_t dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in) {
+    GetBits gb;
+    int res;
+
+    dav1d_init_get_bits(&gb, in->data, in->sz);
+
+    // obu header
+    const int obu_forbidden_bit = dav1d_get_bit(&gb);
+    if (c->strict_std_compliance && obu_forbidden_bit) goto error;
+    const enum Dav1dObuType type = dav1d_get_bits(&gb, 4);
+    const int has_extension = dav1d_get_bit(&gb);
+    const int has_length_field = dav1d_get_bit(&gb);
+    dav1d_get_bit(&gb); // reserved
+
+    int temporal_id = 0, spatial_id = 0;
+    if (has_extension) {
+        temporal_id = dav1d_get_bits(&gb, 3);
+        spatial_id = dav1d_get_bits(&gb, 2);
+        dav1d_get_bits(&gb, 3); // reserved
+    }
+
+    if (has_length_field) {
+        const size_t len = dav1d_get_uleb128(&gb);
+        if (len > (size_t)(gb.ptr_end - gb.ptr)) goto error;
+        gb.ptr_end = gb.ptr + len;
+    }
+    if (gb.error) goto error;
+
+    // We must have read a whole number of bytes at this point (1 byte
+    // for the header and whole bytes at a time when reading the
+    // leb128 length field).
+    assert(gb.bits_left == 0);
+
+    // skip obu not belonging to the selected temporal/spatial layer
+    if (type != DAV1D_OBU_SEQ_HDR && type != DAV1D_OBU_TD &&
+        has_extension && c->operating_point_idc != 0)
+    {
+        const int in_temporal_layer = (c->operating_point_idc >> temporal_id) & 1;
+        const int in_spatial_layer = (c->operating_point_idc >> (spatial_id + 8)) & 1;
+        if (!in_temporal_layer || !in_spatial_layer)
+            return gb.ptr_end - gb.ptr_start;
+    }
+
+    switch (type) {
+    case DAV1D_OBU_SEQ_HDR: {
+        Dav1dRef *ref = dav1d_ref_create_using_pool(c->seq_hdr_pool,
+                                                    sizeof(Dav1dSequenceHeader));
+        if (!ref) return DAV1D_ERR(ENOMEM);
+        Dav1dSequenceHeader *seq_hdr = ref->data;
+        if ((res = parse_seq_hdr(seq_hdr, &gb, c->strict_std_compliance)) < 0) {
+            dav1d_log(c, "Error parsing sequence header\n");
+            dav1d_ref_dec(&ref);
+            goto error;
+        }
+
+        const int op_idx =
+            c->operating_point < seq_hdr->num_operating_points ? c->operating_point : 0;
+        c->operating_point_idc = seq_hdr->operating_points[op_idx].idc;
+        const unsigned spatial_mask = c->operating_point_idc >> 8;
+        c->max_spatial_id = spatial_mask ? ulog2(spatial_mask) : 0;
+
+        // If we have read a sequence header which is different from
+        // the old one, this is a new video sequence and can't use any
+        // previous state. Free that state.
+
+        if (!c->seq_hdr) {
+            c->frame_hdr = NULL;
+            c->frame_flags |= PICTURE_FLAG_NEW_SEQUENCE;
+        // see 7.5, operating_parameter_info is allowed to change in
+        // sequence headers of a single sequence
+        } else if (memcmp(seq_hdr, c->seq_hdr, offsetof(Dav1dSequenceHeader, operating_parameter_info))) {
+            c->frame_hdr = NULL;
+            c->mastering_display = NULL;
+            c->content_light = NULL;
+            dav1d_ref_dec(&c->mastering_display_ref);
+            dav1d_ref_dec(&c->content_light_ref);
+            for (int i = 0; i < 8; i++) {
+                if (c->refs[i].p.p.frame_hdr)
+                    dav1d_thread_picture_unref(&c->refs[i].p);
+                dav1d_ref_dec(&c->refs[i].segmap);
+                dav1d_ref_dec(&c->refs[i].refmvs);
+                dav1d_cdf_thread_unref(&c->cdf[i]);
+            }
+            c->frame_flags |= PICTURE_FLAG_NEW_SEQUENCE;
+        // If operating_parameter_info changed, signal it
+        } else if (memcmp(seq_hdr->operating_parameter_info, c->seq_hdr->operating_parameter_info,
+                          sizeof(seq_hdr->operating_parameter_info)))
+        {
+            c->frame_flags |= PICTURE_FLAG_NEW_OP_PARAMS_INFO;
+        }
+        dav1d_ref_dec(&c->seq_hdr_ref);
+        c->seq_hdr_ref = ref;
+        c->seq_hdr = seq_hdr;
+        break;
+    }
+    case DAV1D_OBU_REDUNDANT_FRAME_HDR:
+        if (c->frame_hdr) break;
+        // fall-through
+    case DAV1D_OBU_FRAME:
+    case DAV1D_OBU_FRAME_HDR:
+        if (!c->seq_hdr) goto error;
+        if (!c->frame_hdr_ref) {
+            c->frame_hdr_ref = dav1d_ref_create_using_pool(c->frame_hdr_pool,
+                                                           sizeof(Dav1dFrameHeader));
+            if (!c->frame_hdr_ref) return DAV1D_ERR(ENOMEM);
+        }
+#ifndef NDEBUG
+        // ensure that the reference is writable
+        assert(dav1d_ref_is_writable(c->frame_hdr_ref));
+#endif
+        c->frame_hdr = c->frame_hdr_ref->data;
+        memset(c->frame_hdr, 0, sizeof(*c->frame_hdr));
+        c->frame_hdr->temporal_id = temporal_id;
+        c->frame_hdr->spatial_id = spatial_id;
+        if ((res = parse_frame_hdr(c, &gb)) < 0) {
+            c->frame_hdr = NULL;
+            goto error;
+        }
+        for (int n = 0; n < c->n_tile_data; n++)
+            dav1d_data_unref_internal(&c->tile[n].data);
+        c->n_tile_data = 0;
+        c->n_tiles = 0;
+        if (type != DAV1D_OBU_FRAME) {
+            // This is actually a frame header OBU so read the
+            // trailing bit and check for overrun.
+            if (check_trailing_bits(&gb, c->strict_std_compliance) < 0) {
+                c->frame_hdr = NULL;
+                goto error;
+            }
+        }
+
+        if (c->frame_size_limit && (int64_t)c->frame_hdr->width[1] *
+            c->frame_hdr->height > c->frame_size_limit)
+        {
+            dav1d_log(c, "Frame size %dx%d exceeds limit %u\n", c->frame_hdr->width[1],
+                      c->frame_hdr->height, c->frame_size_limit);
+            c->frame_hdr = NULL;
+            return DAV1D_ERR(ERANGE);
+        }
+
+        if (type != DAV1D_OBU_FRAME)
+            break;
+        // OBU_FRAMEs shouldn't be signaled with show_existing_frame
+        if (c->frame_hdr->show_existing_frame) {
+            c->frame_hdr = NULL;
+            goto error;
+        }
+
+        // This is the frame header at the start of a frame OBU.
+        // There's no trailing bit at the end to skip, but we do need
+        // to align to the next byte.
+        dav1d_bytealign_get_bits(&gb);
+        // fall-through
+    case DAV1D_OBU_TILE_GRP: {
+        if (!c->frame_hdr) goto error;
+        if (c->n_tile_data_alloc < c->n_tile_data + 1) {
+            if ((c->n_tile_data + 1) > INT_MAX / (int)sizeof(*c->tile)) goto error;
+            struct Dav1dTileGroup *tile = dav1d_realloc(ALLOC_TILE, c->tile,
+                                                        (c->n_tile_data + 1) * sizeof(*c->tile));
+            if (!tile) goto error;
+            c->tile = tile;
+            memset(c->tile + c->n_tile_data, 0, sizeof(*c->tile));
+            c->n_tile_data_alloc = c->n_tile_data + 1;
+        }
+        parse_tile_hdr(c, &gb);
+        // Align to the next byte boundary and check for overrun.
+        dav1d_bytealign_get_bits(&gb);
+        if (gb.error) goto error;
+
+        dav1d_data_ref(&c->tile[c->n_tile_data].data, in);
+        c->tile[c->n_tile_data].data.data = gb.ptr;
+        c->tile[c->n_tile_data].data.sz = (size_t)(gb.ptr_end - gb.ptr);
+        // ensure tile groups are in order and sane, see 6.10.1
+        if (c->tile[c->n_tile_data].start > c->tile[c->n_tile_data].end ||
+            c->tile[c->n_tile_data].start != c->n_tiles)
+        {
+            for (int i = 0; i <= c->n_tile_data; i++)
+                dav1d_data_unref_internal(&c->tile[i].data);
+            c->n_tile_data = 0;
+            c->n_tiles = 0;
+            goto error;
+        }
+        c->n_tiles += 1 + c->tile[c->n_tile_data].end -
+                          c->tile[c->n_tile_data].start;
+        c->n_tile_data++;
+        break;
+    }
+    case DAV1D_OBU_METADATA: {
+#define DEBUG_OBU_METADATA 0
+#if DEBUG_OBU_METADATA
+        const uint8_t *const init_ptr = gb.ptr;
+#endif
+        // obu metadta type field
+        const enum ObuMetaType meta_type = dav1d_get_uleb128(&gb);
+        if (gb.error) goto error;
+
+        switch (meta_type) {
+        case OBU_META_HDR_CLL: {
+            Dav1dRef *ref = dav1d_ref_create(ALLOC_OBU_META,
+                                             sizeof(Dav1dContentLightLevel));
+            if (!ref) return DAV1D_ERR(ENOMEM);
+            Dav1dContentLightLevel *const content_light = ref->data;
+
+            content_light->max_content_light_level = dav1d_get_bits(&gb, 16);
+#if DEBUG_OBU_METADATA
+            printf("CLLOBU: max-content-light-level: %d [off=%td]\n",
+                   content_light->max_content_light_level,
+                   (gb.ptr - init_ptr) * 8 - gb.bits_left);
+#endif
+            content_light->max_frame_average_light_level = dav1d_get_bits(&gb, 16);
+#if DEBUG_OBU_METADATA
+            printf("CLLOBU: max-frame-average-light-level: %d [off=%td]\n",
+                   content_light->max_frame_average_light_level,
+                   (gb.ptr - init_ptr) * 8 - gb.bits_left);
+#endif
+
+            if (check_trailing_bits(&gb, c->strict_std_compliance) < 0) {
+                dav1d_ref_dec(&ref);
+                goto error;
+            }
+
+            dav1d_ref_dec(&c->content_light_ref);
+            c->content_light = content_light;
+            c->content_light_ref = ref;
+            break;
+        }
+        case OBU_META_HDR_MDCV: {
+            Dav1dRef *ref = dav1d_ref_create(ALLOC_OBU_META,
+                                             sizeof(Dav1dMasteringDisplay));
+            if (!ref) return DAV1D_ERR(ENOMEM);
+            Dav1dMasteringDisplay *const mastering_display = ref->data;
+
+            for (int i = 0; i < 3; i++) {
+                mastering_display->primaries[i][0] = dav1d_get_bits(&gb, 16);
+                mastering_display->primaries[i][1] = dav1d_get_bits(&gb, 16);
+#if DEBUG_OBU_METADATA
+                printf("MDCVOBU: primaries[%d]: (%d, %d) [off=%td]\n", i,
+                       mastering_display->primaries[i][0],
+                       mastering_display->primaries[i][1],
+                       (gb.ptr - init_ptr) * 8 - gb.bits_left);
+#endif
+            }
+            mastering_display->white_point[0] = dav1d_get_bits(&gb, 16);
+#if DEBUG_OBU_METADATA
+            printf("MDCVOBU: white-point-x: %d [off=%td]\n",
+                   mastering_display->white_point[0],
+                   (gb.ptr - init_ptr) * 8 - gb.bits_left);
+#endif
+            mastering_display->white_point[1] = dav1d_get_bits(&gb, 16);
+#if DEBUG_OBU_METADATA
+            printf("MDCVOBU: white-point-y: %d [off=%td]\n",
+                   mastering_display->white_point[1],
+                   (gb.ptr - init_ptr) * 8 - gb.bits_left);
+#endif
+            mastering_display->max_luminance = dav1d_get_bits(&gb, 32);
+#if DEBUG_OBU_METADATA
+            printf("MDCVOBU: max-luminance: %d [off=%td]\n",
+                   mastering_display->max_luminance,
+                   (gb.ptr - init_ptr) * 8 - gb.bits_left);
+#endif
+            mastering_display->min_luminance = dav1d_get_bits(&gb, 32);
+#if DEBUG_OBU_METADATA
+            printf("MDCVOBU: min-luminance: %d [off=%td]\n",
+                   mastering_display->min_luminance,
+                   (gb.ptr - init_ptr) * 8 - gb.bits_left);
+#endif
+            if (check_trailing_bits(&gb, c->strict_std_compliance) < 0) {
+                dav1d_ref_dec(&ref);
+                goto error;
+            }
+
+            dav1d_ref_dec(&c->mastering_display_ref);
+            c->mastering_display = mastering_display;
+            c->mastering_display_ref = ref;
+            break;
+        }
+        case OBU_META_ITUT_T35: {
+            ptrdiff_t payload_size = gb.ptr_end - gb.ptr;
+            // Don't take into account all the trailing bits for payload_size
+            while (payload_size > 0 && !gb.ptr[payload_size - 1])
+                payload_size--; // trailing_zero_bit x 8
+            payload_size--; // trailing_one_bit + trailing_zero_bit x 7
+
+            int country_code_extension_byte = 0;
+            const int country_code = dav1d_get_bits(&gb, 8);
+            payload_size--;
+            if (country_code == 0xFF) {
+                country_code_extension_byte = dav1d_get_bits(&gb, 8);
+                payload_size--;
+            }
+
+            if (payload_size <= 0 || gb.ptr[payload_size] != 0x80) {
+                dav1d_log(c, "Malformed ITU-T T.35 metadata message format\n");
+                break;
+            }
+
+            if ((c->n_itut_t35 + 1) > INT_MAX / (int)sizeof(*c->itut_t35)) goto error;
+            struct Dav1dITUTT35 *itut_t35 = dav1d_realloc(ALLOC_OBU_META, c->itut_t35,
+                                                          (c->n_itut_t35 + 1) * sizeof(*c->itut_t35));
+            if (!itut_t35) goto error;
+            c->itut_t35 = itut_t35;
+            memset(c->itut_t35 + c->n_itut_t35, 0, sizeof(*c->itut_t35));
+
+            struct itut_t35_ctx_context *itut_t35_ctx;
+            if (!c->n_itut_t35) {
+                assert(!c->itut_t35_ref);
+                itut_t35_ctx = dav1d_malloc(ALLOC_OBU_META, sizeof(struct itut_t35_ctx_context));
+                if (!itut_t35_ctx) goto error;
+                c->itut_t35_ref = dav1d_ref_init(&itut_t35_ctx->ref, c->itut_t35,
+                                                 dav1d_picture_free_itut_t35, itut_t35_ctx, 0);
+            } else {
+                assert(c->itut_t35_ref && atomic_load(&c->itut_t35_ref->ref_cnt) == 1);
+                itut_t35_ctx = c->itut_t35_ref->user_data;
+                c->itut_t35_ref->const_data = (uint8_t *)c->itut_t35;
+            }
+            itut_t35_ctx->itut_t35 = c->itut_t35;
+            itut_t35_ctx->n_itut_t35 = c->n_itut_t35 + 1;
+
+            Dav1dITUTT35 *const itut_t35_metadata = &c->itut_t35[c->n_itut_t35];
+            itut_t35_metadata->payload = dav1d_malloc(ALLOC_OBU_META, payload_size);
+            if (!itut_t35_metadata->payload) goto error;
+
+            itut_t35_metadata->country_code = country_code;
+            itut_t35_metadata->country_code_extension_byte = country_code_extension_byte;
+            itut_t35_metadata->payload_size = payload_size;
+
+            // We know that we've read a whole number of bytes and that the
+            // payload is within the OBU boundaries, so just use memcpy()
+            assert(gb.bits_left == 0);
+            memcpy(itut_t35_metadata->payload, gb.ptr, payload_size);
+
+            c->n_itut_t35++;
+            break;
+        }
+        case OBU_META_SCALABILITY:
+        case OBU_META_TIMECODE:
+            // ignore metadata OBUs we don't care about
+            break;
+        default:
+            // print a warning but don't fail for unknown types
+            if (meta_type > 31) // Types 6 to 31 are "Unregistered user private", so ignore them.
+                dav1d_log(c, "Unknown Metadata OBU type %d\n", meta_type);
+            break;
+        }
+
+        break;
+    }
+    case DAV1D_OBU_TD:
+        c->frame_flags |= PICTURE_FLAG_NEW_TEMPORAL_UNIT;
+        break;
+    case DAV1D_OBU_PADDING:
+        // ignore OBUs we don't care about
+        break;
+    default:
+        // print a warning but don't fail for unknown types
+        dav1d_log(c, "Unknown OBU type %d of size %td\n", type, gb.ptr_end - gb.ptr);
+        break;
+    }
+
+    if (c->seq_hdr && c->frame_hdr) {
+        if (c->frame_hdr->show_existing_frame) {
+            if (!c->refs[c->frame_hdr->existing_frame_idx].p.p.frame_hdr) goto error;
+            switch (c->refs[c->frame_hdr->existing_frame_idx].p.p.frame_hdr->frame_type) {
+            case DAV1D_FRAME_TYPE_INTER:
+            case DAV1D_FRAME_TYPE_SWITCH:
+                if (c->decode_frame_type > DAV1D_DECODEFRAMETYPE_REFERENCE)
+                    goto skip;
+                break;
+            case DAV1D_FRAME_TYPE_INTRA:
+                if (c->decode_frame_type > DAV1D_DECODEFRAMETYPE_INTRA)
+                    goto skip;
+                // fall-through
+            default:
+                break;
+            }
+            if (!c->refs[c->frame_hdr->existing_frame_idx].p.p.data[0]) goto error;
+            if (c->strict_std_compliance &&
+                !c->refs[c->frame_hdr->existing_frame_idx].p.showable)
+            {
+                goto error;
+            }
+            if (c->n_fc == 1) {
+                dav1d_thread_picture_ref(&c->out,
+                                         &c->refs[c->frame_hdr->existing_frame_idx].p);
+                dav1d_picture_copy_props(&c->out.p,
+                                         c->content_light, c->content_light_ref,
+                                         c->mastering_display, c->mastering_display_ref,
+                                         c->itut_t35, c->itut_t35_ref, c->n_itut_t35,
+                                         &in->m);
+                // Must be removed from the context after being attached to the frame
+                dav1d_ref_dec(&c->itut_t35_ref);
+                c->itut_t35 = NULL;
+                c->n_itut_t35 = 0;
+                c->event_flags |= dav1d_picture_get_event_flags(&c->refs[c->frame_hdr->existing_frame_idx].p);
+            } else {
+                pthread_mutex_lock(&c->task_thread.lock);
+                // need to append this to the frame output queue
+                const unsigned next = c->frame_thread.next++;
+                if (c->frame_thread.next == c->n_fc)
+                    c->frame_thread.next = 0;
+
+                Dav1dFrameContext *const f = &c->fc[next];
+                while (f->n_tile_data > 0)
+                    pthread_cond_wait(&f->task_thread.cond,
+                                      &f->task_thread.ttd->lock);
+                Dav1dThreadPicture *const out_delayed =
+                    &c->frame_thread.out_delayed[next];
+                if (out_delayed->p.data[0] || atomic_load(&f->task_thread.error)) {
+                    unsigned first = atomic_load(&c->task_thread.first);
+                    if (first + 1U < c->n_fc)
+                        atomic_fetch_add(&c->task_thread.first, 1U);
+                    else
+                        atomic_store(&c->task_thread.first, 0);
+                    atomic_compare_exchange_strong(&c->task_thread.reset_task_cur,
+                                                   &first, UINT_MAX);
+                    if (c->task_thread.cur && c->task_thread.cur < c->n_fc)
+                        c->task_thread.cur--;
+                }
+                const int error = f->task_thread.retval;
+                if (error) {
+                    c->cached_error = error;
+                    f->task_thread.retval = 0;
+                    dav1d_data_props_copy(&c->cached_error_props, &out_delayed->p.m);
+                    dav1d_thread_picture_unref(out_delayed);
+                } else if (out_delayed->p.data[0]) {
+                    const unsigned progress = atomic_load_explicit(&out_delayed->progress[1],
+                                                                   memory_order_relaxed);
+                    if ((out_delayed->visible || c->output_invisible_frames) &&
+                        progress != FRAME_ERROR)
+                    {
+                        dav1d_thread_picture_ref(&c->out, out_delayed);
+                        c->event_flags |= dav1d_picture_get_event_flags(out_delayed);
+                    }
+                    dav1d_thread_picture_unref(out_delayed);
+                }
+                dav1d_thread_picture_ref(out_delayed,
+                                         &c->refs[c->frame_hdr->existing_frame_idx].p);
+                out_delayed->visible = 1;
+                dav1d_picture_copy_props(&out_delayed->p,
+                                         c->content_light, c->content_light_ref,
+                                         c->mastering_display, c->mastering_display_ref,
+                                         c->itut_t35, c->itut_t35_ref, c->n_itut_t35,
+                                         &in->m);
+                // Must be removed from the context after being attached to the frame
+                dav1d_ref_dec(&c->itut_t35_ref);
+                c->itut_t35 = NULL;
+                c->n_itut_t35 = 0;
+
+                pthread_mutex_unlock(&c->task_thread.lock);
+            }
+            if (c->refs[c->frame_hdr->existing_frame_idx].p.p.frame_hdr->frame_type == DAV1D_FRAME_TYPE_KEY) {
+                const int r = c->frame_hdr->existing_frame_idx;
+                c->refs[r].p.showable = 0;
+                for (int i = 0; i < 8; i++) {
+                    if (i == r) continue;
+
+                    if (c->refs[i].p.p.frame_hdr)
+                        dav1d_thread_picture_unref(&c->refs[i].p);
+                    dav1d_thread_picture_ref(&c->refs[i].p, &c->refs[r].p);
+
+                    dav1d_cdf_thread_unref(&c->cdf[i]);
+                    dav1d_cdf_thread_ref(&c->cdf[i], &c->cdf[r]);
+
+                    dav1d_ref_dec(&c->refs[i].segmap);
+                    c->refs[i].segmap = c->refs[r].segmap;
+                    if (c->refs[r].segmap)
+                        dav1d_ref_inc(c->refs[r].segmap);
+                    dav1d_ref_dec(&c->refs[i].refmvs);
+                }
+            }
+            c->frame_hdr = NULL;
+        } else if (c->n_tiles == c->frame_hdr->tiling.cols * c->frame_hdr->tiling.rows) {
+            switch (c->frame_hdr->frame_type) {
+            case DAV1D_FRAME_TYPE_INTER:
+            case DAV1D_FRAME_TYPE_SWITCH:
+                if (c->decode_frame_type > DAV1D_DECODEFRAMETYPE_REFERENCE ||
+                    (c->decode_frame_type == DAV1D_DECODEFRAMETYPE_REFERENCE &&
+                     !c->frame_hdr->refresh_frame_flags))
+                    goto skip;
+                break;
+            case DAV1D_FRAME_TYPE_INTRA:
+                if (c->decode_frame_type > DAV1D_DECODEFRAMETYPE_INTRA ||
+                    (c->decode_frame_type == DAV1D_DECODEFRAMETYPE_REFERENCE &&
+                     !c->frame_hdr->refresh_frame_flags))
+                    goto skip;
+                // fall-through
+            default:
+                break;
+            }
+            if (!c->n_tile_data)
+                goto error;
+            if ((res = dav1d_submit_frame(c)) < 0)
+                return res;
+            assert(!c->n_tile_data);
+            c->frame_hdr = NULL;
+            c->n_tiles = 0;
+        }
+    }
+
+    return gb.ptr_end - gb.ptr_start;
+
+skip:
+    // update refs with only the headers in case we skip the frame
+    for (int i = 0; i < 8; i++) {
+        if (c->frame_hdr->refresh_frame_flags & (1 << i)) {
+            dav1d_thread_picture_unref(&c->refs[i].p);
+            c->refs[i].p.p.frame_hdr = c->frame_hdr;
+            c->refs[i].p.p.seq_hdr = c->seq_hdr;
+            c->refs[i].p.p.frame_hdr_ref = c->frame_hdr_ref;
+            c->refs[i].p.p.seq_hdr_ref = c->seq_hdr_ref;
+            dav1d_ref_inc(c->frame_hdr_ref);
+            dav1d_ref_inc(c->seq_hdr_ref);
+        }
+    }
+
+    dav1d_ref_dec(&c->frame_hdr_ref);
+    c->frame_hdr = NULL;
+    c->n_tiles = 0;
+
+    return gb.ptr_end - gb.ptr_start;
+
+error:
+    dav1d_data_props_copy(&c->cached_error_props, &in->m);
+    dav1d_log(c, gb.error ? "Overrun in OBU bit buffer\n" :
+                            "Error parsing OBU data\n");
+    return DAV1D_ERR(EINVAL);
+}
diff --git a/media/libdav1d/src/src/obu.h b/media/libdav1d/src/src/obu.h
new file mode 100644
index 0000000000..22901f020b
--- /dev/null
+++ b/media/libdav1d/src/src/obu.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_OBU_H
+#define DAV1D_SRC_OBU_H
+
+#include "dav1d/data.h"
+#include "src/internal.h"
+
+ptrdiff_t dav1d_parse_obus(Dav1dContext *c, Dav1dData *in);
+
+#endif /* DAV1D_SRC_OBU_H */
diff --git a/media/libdav1d/src/src/pal.c b/media/libdav1d/src/src/pal.c
new file mode 100644
index 0000000000..8e2cdecde1
--- /dev/null
+++ b/media/libdav1d/src/src/pal.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/attributes.h"
+
+#include "src/pal.h"
+
+// fill invisible edges and pack to 4-bit (2 pixels per byte)
+static void pal_idx_finish_c(uint8_t *dst, const uint8_t *src,
+                             const int bw, const int bh,
+                             const int w, const int h)
+{
+    assert(bw >= 4 && bw <= 64 && !(bw & (bw - 1)));
+    assert(bh >= 4 && bh <= 64 && !(bh & (bh - 1)));
+    assert(w  >= 4 && w <= bw && !(w & 3));
+    assert(h  >= 4 && h <= bh && !(h & 3));
+
+    const int dst_w = w / 2;
+    const int dst_bw = bw / 2;
+
+    for (int y = 0; y < h; y++, src += bw, dst += dst_bw) {
+        for (int x = 0; x < dst_w; x++)
+            dst[x] = src[x * 2 + 0] | (src[x * 2 + 1] << 4);
+        if (dst_w < dst_bw)
+            memset(dst + dst_w, src[w - 1] * 0x11, dst_bw - dst_w);
+    }
+
+    if (h < bh) {
+        const uint8_t *const last_row = &dst[-dst_bw];
+        for (int y = h; y < bh; y++, dst += dst_bw)
+            memcpy(dst, last_row, dst_bw);
+    }
+}
+
+#if HAVE_ASM
+#if ARCH_RISCV
+#include "riscv/pal.h"
+#elif ARCH_X86
+#include "x86/pal.h"
+#endif
+#endif
+
+COLD void dav1d_pal_dsp_init(Dav1dPalDSPContext *const c) {
+    c->pal_idx_finish = pal_idx_finish_c;
+
+#if HAVE_ASM
+#if ARCH_RISCV
+    pal_dsp_init_riscv(c);
+#elif ARCH_X86
+    pal_dsp_init_x86(c);
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/pal.h b/media/libdav1d/src/src/pal.h
new file mode 100644
index 0000000000..6a6d729bef
--- /dev/null
+++ b/media/libdav1d/src/src/pal.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_PAL_H
+#define DAV1D_SRC_PAL_H
+
+#include 
+
+#define decl_pal_idx_finish_fn(name) \
+void (name)(uint8_t *dst, const uint8_t *src, int bw, int bh, int w, int h)
+typedef decl_pal_idx_finish_fn(*pal_idx_finish_fn);
+
+typedef struct Dav1dPalDSPContext {
+    pal_idx_finish_fn pal_idx_finish;
+} Dav1dPalDSPContext;
+
+void dav1d_pal_dsp_init(Dav1dPalDSPContext *dsp);
+
+#endif /* DAV1D_SRC_PAL_H */
diff --git a/media/libdav1d/src/src/picture.c b/media/libdav1d/src/src/picture.c
new file mode 100644
index 0000000000..290bd095ea
--- /dev/null
+++ b/media/libdav1d/src/src/picture.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "common/intops.h"
+#include "common/validate.h"
+
+#include "src/internal.h"
+#include "src/log.h"
+#include "src/picture.h"
+#include "src/ref.h"
+#include "src/thread.h"
+#include "src/thread_task.h"
+
+int dav1d_default_picture_alloc(Dav1dPicture *const p, void *const cookie) {
+    assert(sizeof(Dav1dMemPoolBuffer) <= DAV1D_PICTURE_ALIGNMENT);
+    const int hbd = p->p.bpc > 8;
+    const int aligned_w = (p->p.w + 127) & ~127;
+    const int aligned_h = (p->p.h + 127) & ~127;
+    const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400;
+    const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    ptrdiff_t y_stride = aligned_w << hbd;
+    ptrdiff_t uv_stride = has_chroma ? y_stride >> ss_hor : 0;
+    /* Due to how mapping of addresses to sets works in most L1 and L2 cache
+     * implementations, strides of multiples of certain power-of-two numbers
+     * may cause multiple rows of the same superblock to map to the same set,
+     * causing evictions of previous rows resulting in a reduction in cache
+     * hit rate. Avoid that by slightly padding the stride when necessary. */
+    if (!(y_stride & 1023))
+        y_stride += DAV1D_PICTURE_ALIGNMENT;
+    if (!(uv_stride & 1023) && has_chroma)
+        uv_stride += DAV1D_PICTURE_ALIGNMENT;
+    p->stride[0] = y_stride;
+    p->stride[1] = uv_stride;
+    const size_t y_sz = y_stride * aligned_h;
+    const size_t uv_sz = uv_stride * (aligned_h >> ss_ver);
+    const size_t pic_size = y_sz + 2 * uv_sz;
+
+    Dav1dMemPoolBuffer *const buf = dav1d_mem_pool_pop(cookie, pic_size +
+                                                       DAV1D_PICTURE_ALIGNMENT -
+                                                       sizeof(Dav1dMemPoolBuffer));
+    if (!buf) return DAV1D_ERR(ENOMEM);
+    p->allocator_data = buf;
+
+    uint8_t *const data = buf->data;
+    p->data[0] = data;
+    p->data[1] = has_chroma ? data + y_sz : NULL;
+    p->data[2] = has_chroma ? data + y_sz + uv_sz : NULL;
+
+    return 0;
+}
+
+void dav1d_default_picture_release(Dav1dPicture *const p, void *const cookie) {
+    dav1d_mem_pool_push(cookie, p->allocator_data);
+}
+
+struct pic_ctx_context {
+    Dav1dPicAllocator allocator;
+    Dav1dPicture pic;
+    Dav1dRef ref;
+    void *extra_data[];
+};
+
+static void free_buffer(const uint8_t *const data, void *const user_data) {
+    Dav1dMemPoolBuffer *buf = (Dav1dMemPoolBuffer *)data;
+    struct pic_ctx_context *pic_ctx = buf->data;
+
+    pic_ctx->allocator.release_picture_callback(&pic_ctx->pic,
+                                                pic_ctx->allocator.cookie);
+    dav1d_mem_pool_push(user_data, buf);
+}
+
+void dav1d_picture_free_itut_t35(const uint8_t *const data, void *const user_data) {
+    struct itut_t35_ctx_context *itut_t35_ctx = user_data;
+
+    for (size_t i = 0; i < itut_t35_ctx->n_itut_t35; i++)
+        dav1d_free(itut_t35_ctx->itut_t35[i].payload);
+    dav1d_free(itut_t35_ctx->itut_t35);
+    dav1d_free(itut_t35_ctx);
+}
+
+static int picture_alloc(Dav1dContext *const c,
+                         Dav1dPicture *const p,
+                         const int w, const int h,
+                         Dav1dSequenceHeader *const seq_hdr, Dav1dRef *const seq_hdr_ref,
+                         Dav1dFrameHeader *const frame_hdr, Dav1dRef *const frame_hdr_ref,
+                         const int bpc,
+                         const Dav1dDataProps *const props,
+                         Dav1dPicAllocator *const p_allocator,
+                         void **const extra_ptr)
+{
+    if (p->data[0]) {
+        dav1d_log(c, "Picture already allocated!\n");
+        return -1;
+    }
+    assert(bpc > 0 && bpc <= 16);
+
+    size_t extra = c->n_fc > 1 ? sizeof(atomic_int) * 2 : 0;
+    Dav1dMemPoolBuffer *buf = dav1d_mem_pool_pop(c->pic_ctx_pool,
+                                                 extra + sizeof(struct pic_ctx_context));
+    if (buf == NULL)
+        return DAV1D_ERR(ENOMEM);
+
+    struct pic_ctx_context *pic_ctx = buf->data;
+
+    p->p.w = w;
+    p->p.h = h;
+    p->seq_hdr = seq_hdr;
+    p->frame_hdr = frame_hdr;
+    p->p.layout = seq_hdr->layout;
+    p->p.bpc = bpc;
+    dav1d_data_props_set_defaults(&p->m);
+    const int res = p_allocator->alloc_picture_callback(p, p_allocator->cookie);
+    if (res < 0) {
+        dav1d_mem_pool_push(c->pic_ctx_pool, buf);
+        return res;
+    }
+
+    pic_ctx->allocator = *p_allocator;
+    pic_ctx->pic = *p;
+    p->ref = dav1d_ref_init(&pic_ctx->ref, buf, free_buffer, c->pic_ctx_pool, 0);
+
+    p->seq_hdr_ref = seq_hdr_ref;
+    if (seq_hdr_ref) dav1d_ref_inc(seq_hdr_ref);
+
+    p->frame_hdr_ref = frame_hdr_ref;
+    if (frame_hdr_ref) dav1d_ref_inc(frame_hdr_ref);
+
+    if (extra && extra_ptr)
+        *extra_ptr = &pic_ctx->extra_data;
+
+    return 0;
+}
+
+void dav1d_picture_copy_props(Dav1dPicture *const p,
+                              Dav1dContentLightLevel *const content_light, Dav1dRef *const content_light_ref,
+                              Dav1dMasteringDisplay *const mastering_display, Dav1dRef *const mastering_display_ref,
+                              Dav1dITUTT35 *const itut_t35, Dav1dRef *itut_t35_ref, size_t n_itut_t35,
+                              const Dav1dDataProps *const props)
+{
+    dav1d_data_props_copy(&p->m, props);
+
+    dav1d_ref_dec(&p->content_light_ref);
+    p->content_light_ref = content_light_ref;
+    p->content_light = content_light;
+    if (content_light_ref) dav1d_ref_inc(content_light_ref);
+
+    dav1d_ref_dec(&p->mastering_display_ref);
+    p->mastering_display_ref = mastering_display_ref;
+    p->mastering_display = mastering_display;
+    if (mastering_display_ref) dav1d_ref_inc(mastering_display_ref);
+
+    dav1d_ref_dec(&p->itut_t35_ref);
+    p->itut_t35_ref = itut_t35_ref;
+    p->itut_t35 = itut_t35;
+    p->n_itut_t35 = n_itut_t35;
+    if (itut_t35_ref) dav1d_ref_inc(itut_t35_ref);
+}
+
+int dav1d_thread_picture_alloc(Dav1dContext *const c, Dav1dFrameContext *const f,
+                               const int bpc)
+{
+    Dav1dThreadPicture *const p = &f->sr_cur;
+
+    const int res = picture_alloc(c, &p->p, f->frame_hdr->width[1], f->frame_hdr->height,
+                                  f->seq_hdr, f->seq_hdr_ref,
+                                  f->frame_hdr, f->frame_hdr_ref,
+                                  bpc, &f->tile[0].data.m, &c->allocator,
+                                  (void **) &p->progress);
+    if (res) return res;
+
+    // Don't clear these flags from c->frame_flags if the frame is not going to be output.
+    // This way they will be added to the next visible frame too.
+    const int flags_mask = ((f->frame_hdr->show_frame || c->output_invisible_frames) &&
+                            c->max_spatial_id == f->frame_hdr->spatial_id)
+                           ? 0 : (PICTURE_FLAG_NEW_SEQUENCE | PICTURE_FLAG_NEW_OP_PARAMS_INFO);
+    p->flags = c->frame_flags;
+    c->frame_flags &= flags_mask;
+
+    p->visible = f->frame_hdr->show_frame;
+    p->showable = f->frame_hdr->showable_frame;
+
+    if (p->visible) {
+        // Only add HDR10+ and T35 metadata when show frame flag is enabled
+        dav1d_picture_copy_props(&p->p, c->content_light, c->content_light_ref,
+                                 c->mastering_display, c->mastering_display_ref,
+                                 c->itut_t35, c->itut_t35_ref, c->n_itut_t35,
+                                 &f->tile[0].data.m);
+
+        // Must be removed from the context after being attached to the frame
+        dav1d_ref_dec(&c->itut_t35_ref);
+        c->itut_t35 = NULL;
+        c->n_itut_t35 = 0;
+    } else {
+        dav1d_data_props_copy(&p->p.m, &f->tile[0].data.m);
+    }
+
+    if (c->n_fc > 1) {
+        atomic_init(&p->progress[0], 0);
+        atomic_init(&p->progress[1], 0);
+    }
+    return res;
+}
+
+int dav1d_picture_alloc_copy(Dav1dContext *const c, Dav1dPicture *const dst, const int w,
+                             const Dav1dPicture *const src)
+{
+    Dav1dMemPoolBuffer *const buf = (Dav1dMemPoolBuffer *)src->ref->const_data;
+    struct pic_ctx_context *const pic_ctx = buf->data;
+    const int res = picture_alloc(c, dst, w, src->p.h,
+                                  src->seq_hdr, src->seq_hdr_ref,
+                                  src->frame_hdr, src->frame_hdr_ref,
+                                  src->p.bpc, &src->m, &pic_ctx->allocator,
+                                  NULL);
+    if (res) return res;
+
+    dav1d_picture_copy_props(dst, src->content_light, src->content_light_ref,
+                             src->mastering_display, src->mastering_display_ref,
+                             src->itut_t35, src->itut_t35_ref, src->n_itut_t35,
+                             &src->m);
+
+    return 0;
+}
+
+void dav1d_picture_ref(Dav1dPicture *const dst, const Dav1dPicture *const src) {
+    assert(dst != NULL);
+    assert(dst->data[0] == NULL);
+    assert(src != NULL);
+
+    if (src->ref) {
+        assert(src->data[0] != NULL);
+        dav1d_ref_inc(src->ref);
+    }
+    if (src->frame_hdr_ref) dav1d_ref_inc(src->frame_hdr_ref);
+    if (src->seq_hdr_ref) dav1d_ref_inc(src->seq_hdr_ref);
+    if (src->m.user_data.ref) dav1d_ref_inc(src->m.user_data.ref);
+    if (src->content_light_ref) dav1d_ref_inc(src->content_light_ref);
+    if (src->mastering_display_ref) dav1d_ref_inc(src->mastering_display_ref);
+    if (src->itut_t35_ref) dav1d_ref_inc(src->itut_t35_ref);
+    *dst = *src;
+}
+
+void dav1d_picture_move_ref(Dav1dPicture *const dst, Dav1dPicture *const src) {
+    assert(dst != NULL);
+    assert(dst->data[0] == NULL);
+    assert(src != NULL);
+
+    if (src->ref)
+        assert(src->data[0] != NULL);
+
+    *dst = *src;
+    memset(src, 0, sizeof(*src));
+}
+
+void dav1d_thread_picture_ref(Dav1dThreadPicture *const dst,
+                              const Dav1dThreadPicture *const src)
+{
+    dav1d_picture_ref(&dst->p, &src->p);
+    dst->visible = src->visible;
+    dst->showable = src->showable;
+    dst->progress = src->progress;
+    dst->flags = src->flags;
+}
+
+void dav1d_thread_picture_move_ref(Dav1dThreadPicture *const dst,
+                                   Dav1dThreadPicture *const src)
+{
+    dav1d_picture_move_ref(&dst->p, &src->p);
+    dst->visible = src->visible;
+    dst->showable = src->showable;
+    dst->progress = src->progress;
+    dst->flags = src->flags;
+    memset(src, 0, sizeof(*src));
+}
+
+void dav1d_picture_unref_internal(Dav1dPicture *const p) {
+    validate_input(p != NULL);
+
+    if (p->ref) {
+        validate_input(p->data[0] != NULL);
+        dav1d_ref_dec(&p->ref);
+    }
+    dav1d_ref_dec(&p->seq_hdr_ref);
+    dav1d_ref_dec(&p->frame_hdr_ref);
+    dav1d_ref_dec(&p->m.user_data.ref);
+    dav1d_ref_dec(&p->content_light_ref);
+    dav1d_ref_dec(&p->mastering_display_ref);
+    dav1d_ref_dec(&p->itut_t35_ref);
+    memset(p, 0, sizeof(*p));
+    dav1d_data_props_set_defaults(&p->m);
+}
+
+void dav1d_thread_picture_unref(Dav1dThreadPicture *const p) {
+    dav1d_picture_unref_internal(&p->p);
+
+    p->progress = NULL;
+}
+
+enum Dav1dEventFlags dav1d_picture_get_event_flags(const Dav1dThreadPicture *const p) {
+    if (!p->flags)
+        return 0;
+
+    enum Dav1dEventFlags flags = 0;
+    if (p->flags & PICTURE_FLAG_NEW_SEQUENCE)
+       flags |= DAV1D_EVENT_FLAG_NEW_SEQUENCE;
+    if (p->flags & PICTURE_FLAG_NEW_OP_PARAMS_INFO)
+       flags |= DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO;
+
+    return flags;
+}
diff --git a/media/libdav1d/src/src/picture.h b/media/libdav1d/src/src/picture.h
new file mode 100644
index 0000000000..88aee08f4a
--- /dev/null
+++ b/media/libdav1d/src/src/picture.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_PICTURE_H
+#define DAV1D_SRC_PICTURE_H
+
+#include 
+
+#include "src/thread.h"
+#include "dav1d/picture.h"
+
+#include "src/thread_data.h"
+#include "src/ref.h"
+
+enum PlaneType {
+    PLANE_TYPE_Y,
+    PLANE_TYPE_UV,
+    PLANE_TYPE_BLOCK,
+    PLANE_TYPE_ALL,
+};
+
+enum PictureFlags {
+    PICTURE_FLAG_NEW_SEQUENCE =       1 << 0,
+    PICTURE_FLAG_NEW_OP_PARAMS_INFO = 1 << 1,
+    PICTURE_FLAG_NEW_TEMPORAL_UNIT  = 1 << 2,
+};
+
+typedef struct Dav1dThreadPicture {
+    Dav1dPicture p;
+    int visible;
+    // This can be set for inter frames, non-key intra frames, or for invisible
+    // keyframes that have not yet been made visible using the show-existing-frame
+    // mechanism.
+    int showable;
+    enum PictureFlags flags;
+    // [0] block data (including segmentation map and motion vectors)
+    // [1] pixel data
+    atomic_uint *progress;
+} Dav1dThreadPicture;
+
+typedef struct Dav1dPictureBuffer {
+    void *data;
+    struct Dav1dPictureBuffer *next;
+} Dav1dPictureBuffer;
+
+/*
+ * Allocate a picture with custom border size.
+ */
+int dav1d_thread_picture_alloc(Dav1dContext *c, Dav1dFrameContext *f, const int bpc);
+
+/**
+ * Allocate a picture with identical metadata to an existing picture.
+ * The width is a separate argument so this function can be used for
+ * super-res, where the width changes, but everything else is the same.
+ * For the more typical use case of allocating a new image of the same
+ * dimensions, use src->p.w as width.
+ */
+int dav1d_picture_alloc_copy(Dav1dContext *c, Dav1dPicture *dst, const int w,
+                             const Dav1dPicture *src);
+
+/**
+ * Create a copy of a picture.
+ */
+void dav1d_picture_ref(Dav1dPicture *dst, const Dav1dPicture *src);
+void dav1d_thread_picture_ref(Dav1dThreadPicture *dst,
+                              const Dav1dThreadPicture *src);
+void dav1d_thread_picture_move_ref(Dav1dThreadPicture *dst,
+                                   Dav1dThreadPicture *src);
+void dav1d_thread_picture_unref(Dav1dThreadPicture *p);
+
+/**
+ * Move a picture reference.
+ */
+void dav1d_picture_move_ref(Dav1dPicture *dst, Dav1dPicture *src);
+
+int dav1d_default_picture_alloc(Dav1dPicture *p, void *cookie);
+void dav1d_default_picture_release(Dav1dPicture *p, void *cookie);
+void dav1d_picture_unref_internal(Dav1dPicture *p);
+
+struct itut_t35_ctx_context {
+    Dav1dITUTT35 *itut_t35;
+    size_t n_itut_t35;
+    Dav1dRef ref;
+};
+
+void dav1d_picture_free_itut_t35(const uint8_t *data, void *user_data);
+void dav1d_picture_copy_props(Dav1dPicture *p,
+                              Dav1dContentLightLevel *content_light, Dav1dRef *content_light_ref,
+                              Dav1dMasteringDisplay *mastering_display, Dav1dRef *mastering_display_ref,
+                              Dav1dITUTT35 *itut_t35, Dav1dRef *itut_t35_ref, size_t n_itut_t35,
+                              const Dav1dDataProps *props);
+
+/**
+ * Get event flags from picture flags.
+ */
+enum Dav1dEventFlags dav1d_picture_get_event_flags(const Dav1dThreadPicture *p);
+
+#endif /* DAV1D_SRC_PICTURE_H */
diff --git a/media/libdav1d/src/src/ppc/cdef.h b/media/libdav1d/src/src/ppc/cdef.h
new file mode 100644
index 0000000000..b794ba53be
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/cdef.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2019, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include 
+
+#include "common/bitdepth.h"
+#include "common/intops.h"
+
+#include "src/cdef.h"
+#include "src/cpu.h"
+
+#define cdef_vsx_fn(w, h) \
+void dav1d_cdef_filter_##w##x##h##_vsx(pixel *const dst, \
+                                       const ptrdiff_t dst_stride, \
+                                       const pixel (*left)[2], \
+                                       const pixel *const top, \
+                                       const pixel *const bottom, \
+                                       const int pri_strength, \
+                                       const int sec_strength, \
+                                       const int dir, \
+                                       const int damping, \
+                                       const enum CdefEdgeFlags edges)
+
+cdef_vsx_fn(4, 4);
+cdef_vsx_fn(4, 8);
+cdef_vsx_fn(8, 8);
+
+static ALWAYS_INLINE void cdef_dsp_init_ppc(Dav1dCdefDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_PPC_CPU_FLAG_VSX)) return;
+
+#if BITDEPTH == 8
+    c->fb[0] = dav1d_cdef_filter_8x8_vsx;
+    c->fb[1] = dav1d_cdef_filter_4x8_vsx;
+    c->fb[2] = dav1d_cdef_filter_4x4_vsx;
+#endif
+}
diff --git a/media/libdav1d/src/src/ppc/cdef_tmpl.c b/media/libdav1d/src/src/ppc/cdef_tmpl.c
new file mode 100644
index 0000000000..6ef87ad448
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/cdef_tmpl.c
@@ -0,0 +1,636 @@
+/*
+ * Copyright © 2019, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/ppc/dav1d_types.h"
+#include "src/ppc/cdef.h"
+
+#if BITDEPTH == 8
+static inline i16x8 vconstrain(const i16x8 diff, const int16_t threshold,
+                               const uint16_t shift)
+{
+    const i16x8 zero = vec_splat_s16(0);
+    if (!threshold) return zero;
+    const i16x8 abs_diff = vec_abs(diff);
+    const b16x8 mask = vec_cmplt(diff, zero);
+    const i16x8 thr = vec_splats(threshold);
+    const i16x8 sub = vec_sub(thr, vec_sra(abs_diff, vec_splats(shift)));
+    const i16x8 max = vec_max(zero, sub);
+    const i16x8 min = vec_min(abs_diff, max);
+    const i16x8 neg = vec_sub(zero, min);
+    return vec_sel(min, neg, mask);
+}
+
+static inline void copy4xN(uint16_t *tmp,
+                           const uint8_t *src, const ptrdiff_t src_stride,
+                           const uint8_t (*left)[2], const uint8_t *const top,
+                           const uint8_t *const bottom, const int w, const int h,
+                           const enum CdefEdgeFlags edges)
+{
+    const u16x8 fill = vec_splats((uint16_t)INT16_MAX);
+
+    u16x8 l0;
+    u16x8 l1;
+
+    int y_start = -2, y_end = h + 2;
+
+    // Copy top and bottom first
+    if (!(edges & CDEF_HAVE_TOP)) {
+        l0 = fill;
+        l1 = fill;
+        y_start = 0;
+    } else {
+        l0 = u8h_to_u16(vec_vsx_ld(0, top + 0 * src_stride - 2));
+        l1 = u8h_to_u16(vec_vsx_ld(0, top + 1 * src_stride - 2));
+    }
+
+    vec_st(l0, 0, tmp - 2 * 8);
+    vec_st(l1, 0, tmp - 1 * 8);
+
+    if (!(edges & CDEF_HAVE_BOTTOM)) {
+        l0 = fill;
+        l1 = fill;
+        y_end -= 2;
+    } else {
+        l0 = u8h_to_u16(vec_vsx_ld(0, bottom + 0 * src_stride - 2));
+        l1 = u8h_to_u16(vec_vsx_ld(0, bottom + 1 * src_stride - 2));
+    }
+
+    vec_st(l0, 0, tmp + (h + 0) * 8);
+    vec_st(l1, 0, tmp + (h + 1) * 8);
+
+    int y_with_left_edge = 0;
+    if (!(edges & CDEF_HAVE_LEFT)) {
+        u16x8 l = u8h_to_u16(vec_vsx_ld(0, src));
+        vec_vsx_st(l, 0, tmp + 2);
+
+        y_with_left_edge = 1;
+    }
+
+    for (int y = y_with_left_edge; y < h; y++) {
+        u16x8 l = u8h_to_u16(vec_vsx_ld(0, src - 2 + y * src_stride));
+        vec_st(l, 0, tmp + y * 8);
+    }
+
+    if (!(edges & CDEF_HAVE_LEFT)) {
+        for (int y = y_start; y < y_end; y++) {
+            tmp[y * 8] = INT16_MAX;
+            tmp[1 + y * 8] = INT16_MAX;
+        }
+    } else {
+        for (int y = 0; y < h; y++) {
+            tmp[y * 8] = left[y][0];
+            tmp[1 + y * 8] = left[y][1];
+        }
+    }
+    if (!(edges & CDEF_HAVE_RIGHT)) {
+        for (int y = y_start; y < y_end; y++) {
+            tmp[- 2 + (y + 1) * 8] = INT16_MAX;
+            tmp[- 1 + (y + 1) * 8] = INT16_MAX;
+        }
+    }
+}
+
+static inline void copy8xN(uint16_t *tmp,
+                           const uint8_t *src, const ptrdiff_t src_stride,
+                           const uint8_t (*left)[2], const uint8_t *const top,
+                           const uint8_t *const bottom, const int w, const int h,
+                           const enum CdefEdgeFlags edges)
+{
+    const u16x8 fill = vec_splats((uint16_t)INT16_MAX);
+
+    u16x8 l0h, l0l;
+    u16x8 l1h, l1l;
+
+    int y_start = -2, y_end = h + 2;
+
+    // Copy top and bottom first
+    if (!(edges & CDEF_HAVE_TOP)) {
+        l0h = fill;
+        l0l = fill;
+        l1h = fill;
+        l1l = fill;
+        y_start = 0;
+    } else {
+        u8x16 l0 = vec_vsx_ld(0, top + 0 * src_stride - 2);
+        u8x16 l1 = vec_vsx_ld(0, top + 1 * src_stride - 2);
+        l0h = u8h_to_u16(l0);
+        l0l = u8l_to_u16(l0);
+        l1h = u8h_to_u16(l1);
+        l1l = u8l_to_u16(l1);
+    }
+
+    vec_st(l0h, 0, tmp - 4 * 8);
+    vec_st(l0l, 0, tmp - 3 * 8);
+    vec_st(l1h, 0, tmp - 2 * 8);
+    vec_st(l1l, 0, tmp - 1 * 8);
+
+    if (!(edges & CDEF_HAVE_BOTTOM)) {
+        l0h = fill;
+        l0l = fill;
+        l1h = fill;
+        l1l = fill;
+        y_end -= 2;
+    } else {
+        u8x16 l0 = vec_vsx_ld(0, bottom + 0 * src_stride - 2);
+        u8x16 l1 = vec_vsx_ld(0, bottom + 1 * src_stride - 2);
+        l0h = u8h_to_u16(l0);
+        l0l = u8l_to_u16(l0);
+        l1h = u8h_to_u16(l1);
+        l1l = u8l_to_u16(l1);
+    }
+
+    vec_st(l0h, 0, tmp + (h + 0) * 16);
+    vec_st(l0l, 0, tmp + (h + 0) * 16 + 8);
+    vec_st(l1h, 0, tmp + (h + 1) * 16);
+    vec_st(l1l, 0, tmp + (h + 1) * 16 + 8);
+
+    int y_with_left_edge = 0;
+    if (!(edges & CDEF_HAVE_LEFT)) {
+        u8x16 l = vec_vsx_ld(0, src);
+        u16x8 lh = u8h_to_u16(l);
+        u16x8 ll = u8l_to_u16(l);
+        vec_vsx_st(lh, 0, tmp + 2);
+        vec_vsx_st(ll, 0, tmp + 8 + 2);
+
+        y_with_left_edge = 1;
+    }
+
+    for (int y = y_with_left_edge; y < h; y++) {
+        u8x16 l = vec_vsx_ld(0, src - 2 + y * src_stride);
+        u16x8 lh = u8h_to_u16(l);
+        u16x8 ll = u8l_to_u16(l);
+        vec_st(lh, 0, tmp + y * 16);
+        vec_st(ll, 0, tmp + 8 + y * 16);
+    }
+
+    if (!(edges & CDEF_HAVE_LEFT)) {
+        for (int y = y_start; y < y_end; y++) {
+            tmp[y * 16] = INT16_MAX;
+            tmp[1 + y * 16] = INT16_MAX;
+        }
+    } else {
+        for (int y = 0; y < h; y++) {
+            tmp[y * 16] = left[y][0];
+            tmp[1 + y * 16] = left[y][1];
+        }
+    }
+    if (!(edges & CDEF_HAVE_RIGHT)) {
+        for (int y = y_start; y < y_end; y++) {
+            tmp[- 6 + (y + 1) * 16] = INT16_MAX;
+            tmp[- 5 + (y + 1) * 16] = INT16_MAX;
+        }
+    }
+}
+
+static inline i16x8 max_mask(i16x8 a, i16x8 b) {
+    const i16x8 I16X8_INT16_MAX = vec_splats((int16_t)INT16_MAX);
+
+    const b16x8 mask = vec_cmpeq(a, I16X8_INT16_MAX);
+
+    const i16x8 val = vec_sel(a, b, mask);
+
+    return vec_max(val, b);
+}
+
+#define LOAD_PIX(addr) \
+    const i16x8 px = (i16x8)vec_vsx_ld(0, addr); \
+    i16x8 sum = vec_splat_s16(0);
+
+#define LOAD_PIX4(addr) \
+    const i16x8 a = (i16x8)vec_vsx_ld(0, addr); \
+    const i16x8 b = (i16x8)vec_vsx_ld(0, addr + 8); \
+    const i16x8 px = vec_xxpermdi(a, b, 0); \
+    i16x8 sum = vec_splat_s16(0);
+
+#define LOAD_DIR(p, addr, o0, o1) \
+    const i16x8 p ## 0 = (i16x8)vec_vsx_ld(0, addr + o0); \
+    const i16x8 p ## 1 = (i16x8)vec_vsx_ld(0, addr - o0); \
+    const i16x8 p ## 2 = (i16x8)vec_vsx_ld(0, addr + o1); \
+    const i16x8 p ## 3 = (i16x8)vec_vsx_ld(0, addr - o1);
+
+#define LOAD_DIR4(p, addr, o0, o1) \
+    LOAD_DIR(p ## a, addr, o0, o1) \
+    LOAD_DIR(p ## b, addr + 8, o0, o1) \
+    const i16x8 p ## 0 = vec_xxpermdi(p ## a ## 0, p ## b ## 0, 0); \
+    const i16x8 p ## 1 = vec_xxpermdi(p ## a ## 1, p ## b ## 1, 0); \
+    const i16x8 p ## 2 = vec_xxpermdi(p ## a ## 2, p ## b ## 2, 0); \
+    const i16x8 p ## 3 = vec_xxpermdi(p ## a ## 3, p ## b ## 3, 0);
+
+#define CONSTRAIN(p, strength, shift) \
+    const i16x8 p ## _d0 = vec_sub(p ## 0, px); \
+    const i16x8 p ## _d1 = vec_sub(p ## 1, px); \
+    const i16x8 p ## _d2 = vec_sub(p ## 2, px); \
+    const i16x8 p ## _d3 = vec_sub(p ## 3, px); \
+\
+    i16x8 p ## _c0 = vconstrain(p ## _d0, strength, shift); \
+    i16x8 p ## _c1 = vconstrain(p ## _d1, strength, shift); \
+    i16x8 p ## _c2 = vconstrain(p ## _d2, strength, shift); \
+    i16x8 p ## _c3 = vconstrain(p ## _d3, strength, shift);
+
+#define SETUP_MINMAX \
+    i16x8 max = px; \
+    i16x8 min = px; \
+
+#define MIN_MAX(p) \
+    max = max_mask(p ## 0, max); \
+    min = vec_min(p ## 0, min); \
+    max = max_mask(p ## 1, max); \
+    min = vec_min(p ## 1, min); \
+    max = max_mask(p ## 2, max); \
+    min = vec_min(p ## 2, min); \
+    max = max_mask(p ## 3, max); \
+    min = vec_min(p ## 3, min);
+
+#define MAKE_TAPS \
+    const int16_t tap_odd = (pri_strength >> bitdepth_min_8) & 1; \
+    const i16x8 tap0 = vec_splats((int16_t)(4 - tap_odd)); \
+    const i16x8 tap1 = vec_splats((int16_t)(2 + tap_odd));
+
+#define PRI_0_UPDATE_SUM(p) \
+    sum = vec_madd(tap0, p ## _c0, sum); \
+    sum = vec_madd(tap0, p ## _c1, sum); \
+    sum = vec_madd(tap1, p ## _c2, sum); \
+    sum = vec_madd(tap1, p ## _c3, sum);
+
+#define UPDATE_SUM(p) \
+    const i16x8 p ## sum0 = vec_add(p ## _c0, p ## _c1); \
+    const i16x8 p ## sum1 = vec_add(p ## _c2, p ## _c3); \
+    sum = vec_add(sum, p ## sum0); \
+    sum = vec_add(sum, p ## sum1);
+
+#define SEC_0_UPDATE_SUM(p) \
+    sum = vec_madd(vec_splat_s16(2), p ## _c0, sum); \
+    sum = vec_madd(vec_splat_s16(2), p ## _c1, sum); \
+    sum = vec_madd(vec_splat_s16(2), p ## _c2, sum); \
+    sum = vec_madd(vec_splat_s16(2), p ## _c3, sum);
+
+#define BIAS \
+    i16x8 bias = vec_and((i16x8)vec_cmplt(sum, vec_splat_s16(0)), vec_splat_s16(1)); \
+    bias = vec_sub(vec_splat_s16(8), bias); \
+
+#define STORE4 \
+    dst[0] = vdst[0]; \
+    dst[1] = vdst[1]; \
+    dst[2] = vdst[2]; \
+    dst[3] = vdst[3]; \
+\
+    tmp += 8; \
+    dst += PXSTRIDE(dst_stride); \
+    dst[0] = vdst[4]; \
+    dst[1] = vdst[5]; \
+    dst[2] = vdst[6]; \
+    dst[3] = vdst[7]; \
+\
+    tmp += 8; \
+    dst += PXSTRIDE(dst_stride);
+
+#define STORE4_CLAMPED \
+    BIAS \
+    i16x8 unclamped = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); \
+    i16x8 vdst = vec_max(vec_min(unclamped, max), min); \
+    STORE4
+
+#define STORE4_UNCLAMPED \
+    BIAS \
+    i16x8 vdst = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); \
+    STORE4
+
+#define STORE8 \
+    dst[0] = vdst[0]; \
+    dst[1] = vdst[1]; \
+    dst[2] = vdst[2]; \
+    dst[3] = vdst[3]; \
+    dst[4] = vdst[4]; \
+    dst[5] = vdst[5]; \
+    dst[6] = vdst[6]; \
+    dst[7] = vdst[7]; \
+\
+    tmp += 16; \
+    dst += PXSTRIDE(dst_stride);
+
+#define STORE8_CLAMPED \
+    BIAS \
+    i16x8 unclamped = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); \
+    i16x8 vdst = vec_max(vec_min(unclamped, max), min); \
+    STORE8
+
+#define STORE8_UNCLAMPED \
+    BIAS \
+    i16x8 vdst = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); \
+    STORE8
+
+#define DIRECTIONS(w, tmp_stride) \
+    static const int8_t cdef_directions##w[8 /* dir */][2 /* pass */] = { \
+        { -1 * tmp_stride + 1, -2 * tmp_stride + 2 }, \
+        {  0 * tmp_stride + 1, -1 * tmp_stride + 2 }, \
+        {  0 * tmp_stride + 1,  0 * tmp_stride + 2 }, \
+        {  0 * tmp_stride + 1,  1 * tmp_stride + 2 }, \
+        {  1 * tmp_stride + 1,  2 * tmp_stride + 2 }, \
+        {  1 * tmp_stride + 0,  2 * tmp_stride + 1 }, \
+        {  1 * tmp_stride + 0,  2 * tmp_stride + 0 }, \
+        {  1 * tmp_stride + 0,  2 * tmp_stride - 1 } \
+    };
+
+DIRECTIONS(4, 8)
+DIRECTIONS(8, 16)
+
+static inline void
+filter_4xN(pixel *dst, const ptrdiff_t dst_stride,
+           const pixel (*left)[2], const pixel *const top,
+           const pixel *const bottom, const int w, const int h,
+           const int pri_strength, const int sec_strength, const int dir,
+           const int pri_shift, const int sec_shift,
+           const enum CdefEdgeFlags edges, uint16_t *tmp)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    const int off1 = cdef_directions4[dir][0];
+    const int off1_1 = cdef_directions4[dir][1];
+
+    const int off2 = cdef_directions4[(dir + 2) & 7][0];
+    const int off3 = cdef_directions4[(dir + 6) & 7][0];
+
+    const int off2_1 = cdef_directions4[(dir + 2) & 7][1];
+    const int off3_1 = cdef_directions4[(dir + 6) & 7][1];
+
+    MAKE_TAPS
+
+    for (int y = 0; y < h / 2; y++) {
+        LOAD_PIX4(tmp)
+
+        SETUP_MINMAX
+
+        // Primary pass
+        LOAD_DIR4(p, tmp, off1, off1_1)
+
+        CONSTRAIN(p, pri_strength, pri_shift)
+
+        MIN_MAX(p)
+
+        PRI_0_UPDATE_SUM(p)
+
+        // Secondary pass 1
+        LOAD_DIR4(s, tmp, off2, off3)
+
+        CONSTRAIN(s, sec_strength, sec_shift)
+
+        MIN_MAX(s)
+
+        SEC_0_UPDATE_SUM(s)
+
+        // Secondary pass 2
+        LOAD_DIR4(s2, tmp, off2_1, off3_1)
+
+        CONSTRAIN(s2, sec_strength, sec_shift)
+
+        MIN_MAX(s2)
+
+        UPDATE_SUM(s2)
+
+        // Store
+        STORE4_CLAMPED
+    }
+}
+
+static inline void
+filter_4xN_pri(pixel *dst, const ptrdiff_t dst_stride,
+           const pixel (*left)[2], const pixel *const top,
+           const pixel *const bottom, const int w, const int h,
+           const int pri_strength, const int dir,
+           const int pri_shift, const enum CdefEdgeFlags edges,
+           uint16_t *tmp)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    const int off1 = cdef_directions4[dir][0];
+    const int off1_1 = cdef_directions4[dir][1];
+
+    MAKE_TAPS
+
+    for (int y = 0; y < h / 2; y++) {
+        LOAD_PIX4(tmp)
+
+        // Primary pass
+        LOAD_DIR4(p, tmp, off1, off1_1)
+
+        CONSTRAIN(p, pri_strength, pri_shift)
+
+        PRI_0_UPDATE_SUM(p)
+
+        STORE4_UNCLAMPED
+    }
+}
+
+static inline void
+filter_4xN_sec(pixel *dst, const ptrdiff_t dst_stride,
+           const pixel (*left)[2], const pixel *const top,
+           const pixel *const bottom, const int w, const int h,
+           const int sec_strength, const int dir,
+           const int sec_shift, const enum CdefEdgeFlags edges,
+           uint16_t *tmp)
+{
+    const int off2 = cdef_directions4[(dir + 2) & 7][0];
+    const int off3 = cdef_directions4[(dir + 6) & 7][0];
+
+    const int off2_1 = cdef_directions4[(dir + 2) & 7][1];
+    const int off3_1 = cdef_directions4[(dir + 6) & 7][1];
+
+    for (int y = 0; y < h / 2; y++) {
+        LOAD_PIX4(tmp)
+        // Secondary pass 1
+        LOAD_DIR4(s, tmp, off2, off3)
+
+        CONSTRAIN(s, sec_strength, sec_shift)
+
+        SEC_0_UPDATE_SUM(s)
+
+        // Secondary pass 2
+        LOAD_DIR4(s2, tmp, off2_1, off3_1)
+
+        CONSTRAIN(s2, sec_strength, sec_shift)
+
+        UPDATE_SUM(s2)
+
+        STORE4_UNCLAMPED
+    }
+}
+
+static inline void
+filter_8xN(pixel *dst, const ptrdiff_t dst_stride,
+           const pixel (*left)[2], const pixel *const top,
+           const pixel *const bottom, const int w, const int h,
+           const int pri_strength, const int sec_strength, const int dir,
+           const int pri_shift, const int sec_shift, const enum CdefEdgeFlags edges,
+           uint16_t *tmp)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+
+    const int off1 = cdef_directions8[dir][0];
+    const int off1_1 = cdef_directions8[dir][1];
+
+    const int off2 = cdef_directions8[(dir + 2) & 7][0];
+    const int off3 = cdef_directions8[(dir + 6) & 7][0];
+
+    const int off2_1 = cdef_directions8[(dir + 2) & 7][1];
+    const int off3_1 = cdef_directions8[(dir + 6) & 7][1];
+
+    MAKE_TAPS
+
+    for (int y = 0; y < h; y++) {
+        LOAD_PIX(tmp)
+
+        SETUP_MINMAX
+
+        // Primary pass
+        LOAD_DIR(p, tmp, off1, off1_1)
+
+        CONSTRAIN(p, pri_strength, pri_shift)
+
+        MIN_MAX(p)
+
+        PRI_0_UPDATE_SUM(p)
+
+        // Secondary pass 1
+        LOAD_DIR(s, tmp, off2, off3)
+
+        CONSTRAIN(s, sec_strength, sec_shift)
+
+        MIN_MAX(s)
+
+        SEC_0_UPDATE_SUM(s)
+
+        // Secondary pass 2
+        LOAD_DIR(s2, tmp, off2_1, off3_1)
+
+        CONSTRAIN(s2, sec_strength, sec_shift)
+
+        MIN_MAX(s2)
+
+        UPDATE_SUM(s2)
+
+        // Store
+        STORE8_CLAMPED
+    }
+
+}
+
+static inline void
+filter_8xN_pri(pixel *dst, const ptrdiff_t dst_stride,
+           const pixel (*left)[2], const pixel *const top,
+           const pixel *const bottom, const int w, const int h,
+           const int pri_strength, const int dir,
+           const int pri_shift, const enum CdefEdgeFlags edges,
+           uint16_t *tmp)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    const int off1 = cdef_directions8[dir][0];
+    const int off1_1 = cdef_directions8[dir][1];
+
+    MAKE_TAPS
+
+    for (int y = 0; y < h; y++) {
+        LOAD_PIX(tmp)
+
+        // Primary pass
+        LOAD_DIR(p, tmp, off1, off1_1)
+
+        CONSTRAIN(p, pri_strength, pri_shift)
+
+        PRI_0_UPDATE_SUM(p)
+
+        STORE8_UNCLAMPED
+    }
+}
+
+static inline void
+filter_8xN_sec(pixel *dst, const ptrdiff_t dst_stride,
+           const pixel (*left)[2], const pixel *const top,
+           const pixel *const bottom, const int w, const int h,
+           const int sec_strength, const int dir,
+           const int sec_shift, const enum CdefEdgeFlags edges,
+           uint16_t *tmp)
+{
+    const int off2 = cdef_directions8[(dir + 2) & 7][0];
+    const int off3 = cdef_directions8[(dir + 6) & 7][0];
+
+    const int off2_1 = cdef_directions8[(dir + 2) & 7][1];
+    const int off3_1 = cdef_directions8[(dir + 6) & 7][1];
+
+    for (int y = 0; y < h; y++) {
+        LOAD_PIX(tmp)
+
+        // Secondary pass 1
+        LOAD_DIR(s, tmp, off2, off3)
+
+        CONSTRAIN(s, sec_strength, sec_shift)
+
+        SEC_0_UPDATE_SUM(s)
+
+        // Secondary pass 2
+        LOAD_DIR(s2, tmp, off2_1, off3_1)
+
+        CONSTRAIN(s2, sec_strength, sec_shift)
+
+        UPDATE_SUM(s2)
+
+        STORE8_UNCLAMPED
+    }
+}
+
+#define cdef_fn(w, h, tmp_stride) \
+void dav1d_cdef_filter_##w##x##h##_vsx(pixel *const dst, \
+                                       const ptrdiff_t dst_stride, \
+                                       const pixel (*left)[2], \
+                                       const pixel *const top, \
+                                       const pixel *const bottom, \
+                                       const int pri_strength, \
+                                       const int sec_strength, \
+                                       const int dir, \
+                                       const int damping, \
+                                       const enum CdefEdgeFlags edges) \
+{ \
+    ALIGN_STK_16(uint16_t, tmp_buf, 12 * tmp_stride + 8,); \
+    uint16_t *tmp = tmp_buf + 2 * tmp_stride + 2; \
+    copy##w##xN(tmp - 2, dst, dst_stride, left, top, bottom, w, h, edges); \
+    if (pri_strength) { \
+        const int pri_shift = imax(0, damping - ulog2(pri_strength)); \
+        if (sec_strength) { \
+            const int sec_shift = damping - ulog2(sec_strength); \
+            filter_##w##xN(dst, dst_stride, left, top, bottom, w, h, pri_strength, \
+                           sec_strength, dir, pri_shift, sec_shift, edges, tmp); \
+        } else { \
+            filter_##w##xN_pri(dst, dst_stride, left, top, bottom, w, h, pri_strength, \
+                               dir, pri_shift, edges, tmp); \
+        } \
+    } else { \
+        const int sec_shift = damping - ulog2(sec_strength); \
+        filter_##w##xN_sec(dst, dst_stride, left, top, bottom, w, h, sec_strength, \
+                           dir, sec_shift, edges, tmp); \
+    } \
+}
+
+cdef_fn(4, 4, 8);
+cdef_fn(4, 8, 8);
+cdef_fn(8, 8, 16);
+#endif
diff --git a/media/libdav1d/src/src/ppc/cpu.c b/media/libdav1d/src/src/ppc/cpu.c
new file mode 100644
index 0000000000..f6d9ac6269
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/cpu.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "common/attributes.h"
+
+#include "src/cpu.h"
+#include "src/ppc/cpu.h"
+
+#define HAVE_AUX ((HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO) && ARCH_PPC64LE)
+#if HAVE_AUX
+#include 
+#endif
+
+COLD unsigned dav1d_get_cpu_flags_ppc(void) {
+    unsigned flags = dav1d_get_default_cpu_flags();
+#if HAVE_AUX
+    unsigned long hw_cap = dav1d_getauxval(AT_HWCAP);
+    unsigned long hw_cap2 = dav1d_getauxval(AT_HWCAP2);
+    flags |= (hw_cap & PPC_FEATURE_HAS_VSX) ? DAV1D_PPC_CPU_FLAG_VSX : 0;
+    flags |= (hw_cap2 & PPC_FEATURE2_ARCH_3_00) ? DAV1D_PPC_CPU_FLAG_PWR9 : 0;
+#endif
+    return flags;
+}
diff --git a/media/libdav1d/src/src/ppc/cpu.h b/media/libdav1d/src/src/ppc/cpu.h
new file mode 100644
index 0000000000..02db7a60ac
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/cpu.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_PPC_CPU_H
+#define DAV1D_SRC_PPC_CPU_H
+
+enum CpuFlags {
+    DAV1D_PPC_CPU_FLAG_VSX = 1 << 0,
+    DAV1D_PPC_CPU_FLAG_PWR9 = 1 << 1,
+};
+
+unsigned dav1d_get_cpu_flags_ppc(void);
+
+#endif /* DAV1D_SRC_PPC_CPU_H */
diff --git a/media/libdav1d/src/src/ppc/dav1d_types.h b/media/libdav1d/src/src/ppc/dav1d_types.h
new file mode 100644
index 0000000000..9a8bc7a732
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/dav1d_types.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_PPC_TYPES_H
+#define DAV1D_SRC_PPC_TYPES_H
+
+#include 
+#undef pixel
+
+#define u8x16 vector unsigned char
+#define i8x16 vector signed char
+#define b8x16 vector bool char
+#define u16x8 vector unsigned short
+#define i16x8 vector signed short
+#define b16x8 vector bool short
+#define u32x4 vector unsigned int
+#define i32x4 vector signed int
+#define b32x4 vector bool int
+#define u64x2 vector unsigned long long
+#define i64x2 vector signed long long
+#define b64x2 vector bool long long
+
+#define i8h_to_i16(v) ((i16x8) vec_unpackh((i8x16)v))
+#define i8l_to_i16(v) ((i16x8) vec_unpackl((i8x16)v))
+#define u8h_to_i16(v) ((i16x8) vec_mergeh((u8x16) v, vec_splat_u8(0)))
+#define u8l_to_i16(v) ((i16x8) vec_mergel((u8x16) v, vec_splat_u8(0)))
+#define u8h_to_u16(v) ((u16x8) vec_mergeh((u8x16) v, vec_splat_u8(0)))
+#define u8l_to_u16(v) ((u16x8) vec_mergel((u8x16) v, vec_splat_u8(0)))
+#define u16h_to_i32(v) ((i32x4) vec_mergeh((u16x8) v, vec_splat_u16(0)))
+#define i16h_to_i32(v) ((i32x4) vec_unpackh((i16x8)v))
+#define u16l_to_i32(v) ((i32x4) vec_mergel((u16x8) v, vec_splat_u16(0)))
+#define i16l_to_i32(v) ((i32x4) vec_unpackl((i16x8)v))
+
+#endif /* DAV1D_SRC_PPC_TYPES_H */
diff --git a/media/libdav1d/src/src/ppc/itx.h b/media/libdav1d/src/src/ppc/itx.h
new file mode 100644
index 0000000000..6bddf7a38f
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/itx.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2023, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/itx.h"
+
+decl_itx17_fns( 4,  4, pwr9);
+decl_itx16_fns( 4,  8, pwr9);
+decl_itx16_fns( 4, 16, pwr9);
+decl_itx16_fns( 8,  4, pwr9);
+decl_itx16_fns( 8,  8, pwr9);
+decl_itx16_fns( 8, 16, pwr9);
+decl_itx2_fns ( 8, 32, pwr9);
+decl_itx16_fns(16,  4, pwr9);
+decl_itx16_fns(16,  8, pwr9);
+decl_itx12_fns(16, 16, pwr9);
+decl_itx2_fns (16, 32, pwr9);
+decl_itx2_fns (32,  8, pwr9);
+decl_itx2_fns (32, 16, pwr9);
+decl_itx2_fns (32, 32, pwr9);
+
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_16x64, pwr9));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_32x64, pwr9));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x16, pwr9));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x32, pwr9));
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x64, pwr9));
+
+static ALWAYS_INLINE void itx_dsp_init_ppc(Dav1dInvTxfmDSPContext *const c, const int bpc) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_PPC_CPU_FLAG_PWR9)) return;
+
+#if BITDEPTH == 8
+    assign_itx17_fn( ,  4,  4, pwr9);
+    assign_itx16_fn(R,  4,  8, pwr9);
+    assign_itx16_fn(R,  8,  4, pwr9);
+    assign_itx16_fn(,   8,  8, pwr9);
+    assign_itx16_fn(R,  4, 16, pwr9);
+    assign_itx16_fn(R,  16, 4, pwr9);
+#endif
+}
diff --git a/media/libdav1d/src/src/ppc/itx_tmpl.c b/media/libdav1d/src/src/ppc/itx_tmpl.c
new file mode 100644
index 0000000000..818065522e
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/itx_tmpl.c
@@ -0,0 +1,2006 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/ppc/dav1d_types.h"
+#include "src/ppc/itx.h"
+#include "src/ppc/utils.h"
+
+#if BITDEPTH == 8
+
+#define LOAD_4(src, stride, a, b, c, d) \
+{  \
+    uint8_t *s = src; \
+    a = vec_xl(0, s); \
+    s += stride; \
+    b = vec_xl(0, s); \
+    s += stride; \
+    c = vec_xl(0, s); \
+    s += stride; \
+    d = vec_xl(0, s); \
+}
+
+#define LOAD_DECLARE_2_I16(src, a, b) \
+    i16x8 a = vec_xl(0, src); \
+    i16x8 b = vec_xl(0, src + 8);
+
+#define UNPACK_DECLARE_4_I16_I32(sa, sb, a, b, c, d) \
+    i32x4 a = i16h_to_i32(sa); \
+    i32x4 b = i16l_to_i32(sa); \
+    i32x4 c = i16h_to_i32(sb); \
+    i32x4 d = i16l_to_i32(sb);
+
+#define LOAD_COEFF_4(coeff) \
+    LOAD_DECLARE_2_I16(coeff, c01, c23) \
+    UNPACK_DECLARE_4_I16_I32(c01, c23, c0, c1, c2, c3)
+
+#define LOAD_SCALE_COEFF_4x8(coeff, scale) \
+    LOAD_DECLARE_2_I16(coeff, c04, c15) \
+    LOAD_DECLARE_2_I16(coeff+16, c26, c37) \
+    i16x8 c01 = (i16x8)vec_mergeh((i64x2)c04, (i64x2)c15); \
+    i16x8 c23 = (i16x8)vec_mergeh((i64x2)c26, (i64x2)c37); \
+    i16x8 c45 = (i16x8)vec_mergel((i64x2)c04, (i64x2)c15); \
+    i16x8 c67 = (i16x8)vec_mergel((i64x2)c26, (i64x2)c37); \
+    c01 = vec_mradds(c01, scale, vec_splat_s16(0)); \
+    c23 = vec_mradds(c23, scale, vec_splat_s16(0)); \
+    UNPACK_DECLARE_4_I16_I32(c01, c23, c0, c1, c2, c3) \
+    c45 = vec_mradds(c45, scale, vec_splat_s16(0)); \
+    c67 = vec_mradds(c67, scale, vec_splat_s16(0)); \
+    UNPACK_DECLARE_4_I16_I32(c45, c67, c4, c5, c6, c7)
+
+#define LOAD_SCALE_COEFF_8x4(coeff, scale) \
+    LOAD_DECLARE_2_I16(coeff, c01, c23) \
+    LOAD_DECLARE_2_I16(coeff+16, c45, c67) \
+    c01 = vec_mradds(c01, scale, vec_splat_s16(0)); \
+    c23 = vec_mradds(c23, scale, vec_splat_s16(0)); \
+    UNPACK_DECLARE_4_I16_I32(c01, c23, c0, c1, c2, c3) \
+    c45 = vec_mradds(c45, scale, vec_splat_s16(0)); \
+    c67 = vec_mradds(c67, scale, vec_splat_s16(0)); \
+    UNPACK_DECLARE_4_I16_I32(c45, c67, c4, c5, c6, c7)
+
+#define LOAD_COEFF_8x8(coeff) \
+    LOAD_DECLARE_2_I16(coeff, c0, c1) \
+    LOAD_DECLARE_2_I16(coeff+16, c2, c3) \
+    LOAD_DECLARE_2_I16(coeff+32, c4, c5) \
+    LOAD_DECLARE_2_I16(coeff+48, c6, c7) \
+    UNPACK_DECLARE_4_I16_I32(c0, c1, c0h, c0l, c1h, c1l) \
+    UNPACK_DECLARE_4_I16_I32(c2, c3, c2h, c2l, c3h, c3l) \
+    UNPACK_DECLARE_4_I16_I32(c4, c5, c4h, c4l, c5h, c5l) \
+    UNPACK_DECLARE_4_I16_I32(c6, c7, c6h, c6l, c7h, c7l) \
+
+#define LOAD_COEFF_4x16(coeff) \
+    LOAD_DECLARE_2_I16(coeff,    a0b0, c0d0) \
+    LOAD_DECLARE_2_I16(coeff+16, a1b1, c1d1) \
+    LOAD_DECLARE_2_I16(coeff+32, a2b2, c2d2) \
+    LOAD_DECLARE_2_I16(coeff+48, a3b3, c3d3) \
+    UNPACK_DECLARE_4_I16_I32(a0b0, c0d0, cA0, cB0, cC0, cD0) \
+    UNPACK_DECLARE_4_I16_I32(a1b1, c1d1, cA1, cB1, cC1, cD1) \
+    UNPACK_DECLARE_4_I16_I32(a2b2, c2d2, cA2, cB2, cC2, cD2) \
+    UNPACK_DECLARE_4_I16_I32(a3b3, c3d3, cA3, cB3, cC3, cD3)
+
+#define LOAD_DECLARE_4(src, stride, a, b, c, d) \
+    u8x16 a, b, c, d; \
+    LOAD_4(src, stride, a, b, c, d)
+
+#define STORE_LEN(l, dst, stride, a, b, c, d) \
+{ \
+    uint8_t *dst2 = dst; \
+    vec_xst_len(a, dst2, l); \
+    dst2 += stride; \
+    vec_xst_len(b, dst2, l); \
+    dst2 += stride; \
+    vec_xst_len(c, dst2, l); \
+    dst2 += stride; \
+    vec_xst_len(d, dst2, l); \
+}
+
+#define STORE_4(dst, stride, a, b, c, d) \
+    STORE_LEN(4, dst, stride, a, b, c, d)
+
+#define STORE_8(dst, stride, ab, cd, ef, gh) \
+    STORE_LEN(8, dst, stride, ab, cd, ef, gh)
+
+#define STORE_16(dst, stride, l0, l1, l2, l3) \
+{ \
+    uint8_t *dst##2 = dst; \
+    vec_xst(l0, 0, dst##2); \
+    dst##2 += stride; \
+    vec_xst(l1, 0, dst##2); \
+    dst##2 += stride; \
+    vec_xst(l2, 0, dst##2); \
+    dst##2 += stride; \
+    vec_xst(l3, 0, dst##2); \
+}
+
+#define APPLY_COEFF_4(a, b, c, d, c01, c23) \
+{ \
+    u8x16 ab = (u8x16)vec_mergeh((u32x4)a, (u32x4)b); \
+    u8x16 cd = (u8x16)vec_mergeh((u32x4)c, (u32x4)d); \
+ \
+    c01 = vec_adds(c01, vec_splat_s16(8)); \
+    c23 = vec_adds(c23, vec_splat_s16(8)); \
+    c01 = vec_sra(c01, vec_splat_u16(4)); \
+    c23 = vec_sra(c23, vec_splat_u16(4)); \
+ \
+    i16x8 abs = u8h_to_i16(ab); \
+    i16x8 cds = u8h_to_i16(cd); \
+ \
+    abs = vec_adds(abs, c01); \
+    cds = vec_adds(cds, c23); \
+ \
+    a = vec_packsu(abs, abs); \
+    c = vec_packsu(cds, cds); \
+ \
+    b = (u8x16)vec_mergeo((u32x4)a, (u32x4)a); \
+    d = (u8x16)vec_mergeo((u32x4)c, (u32x4)c); \
+}
+
+#define APPLY_COEFF_8x4(ab, cd, c01, c23) \
+{ \
+    i16x8 abs = u8h_to_i16(ab); \
+    i16x8 cds = u8h_to_i16(cd); \
+    c01 = vec_adds(c01, vec_splat_s16(8)); \
+    c23 = vec_adds(c23, vec_splat_s16(8)); \
+    c01 = vec_sra(c01, vec_splat_u16(4)); \
+    c23 = vec_sra(c23, vec_splat_u16(4)); \
+ \
+    abs = vec_adds(abs, c01); \
+    cds = vec_adds(cds, c23); \
+ \
+    ab = vec_packsu(abs, abs); \
+    cd = vec_packsu(cds, cds); \
+}
+
+#define APPLY_COEFF_16x4(a, b, c, d, \
+                         c00c01, c02c03, c04c05, c06c07, \
+                         c08c09, c10c11, c12c13, c14c15) \
+{ \
+    i16x8 ah = u8h_to_i16(a); \
+    i16x8 al = u8l_to_i16(a); \
+    i16x8 bh = u8h_to_i16(b); \
+    i16x8 bl = u8l_to_i16(b); \
+    i16x8 ch = u8h_to_i16(c); \
+    i16x8 cl = u8l_to_i16(c); \
+    i16x8 dh = u8h_to_i16(d); \
+    i16x8 dl = u8l_to_i16(d); \
+    SCALE_ROUND_4(c00c01, c02c03, c04c05, c06c07, vec_splat_s16(8), vec_splat_u16(4)) \
+    SCALE_ROUND_4(c08c09, c10c11, c12c13, c14c15, vec_splat_s16(8), vec_splat_u16(4)) \
+ \
+    ah = vec_adds(ah, c00c01); \
+    al = vec_adds(al, c02c03); \
+    bh = vec_adds(bh, c04c05); \
+    bl = vec_adds(bl, c06c07); \
+    ch = vec_adds(ch, c08c09); \
+    cl = vec_adds(cl, c10c11); \
+    dh = vec_adds(dh, c12c13); \
+    dl = vec_adds(dl, c14c15); \
+ \
+    a = vec_packsu(ah, al); \
+    b = vec_packsu(bh, bl); \
+    c = vec_packsu(ch, cl); \
+    d = vec_packsu(dh, dl); \
+}
+
+#define IDCT_4_INNER(c0, c1, c2, c3) \
+{ \
+    i32x4 o0 = vec_add(c0, c2); \
+    i32x4 o1 = vec_sub(c0, c2); \
+ \
+    i32x4 v2896 = vec_splats(2896); \
+    i32x4 v1567 = vec_splats(1567); \
+    i32x4 v3784 = vec_splats(3784); \
+    i32x4 v2048 = vec_splats(2048); \
+ \
+    o0 = vec_mul(o0, v2896); \
+    o1 = vec_mul(o1, v2896); \
+ \
+    i32x4 o2a = vec_mul(c1, v1567); \
+    i32x4 o2b = vec_mul(c3, v3784); \
+    i32x4 o3a = vec_mul(c1, v3784); \
+    i32x4 o3b = vec_mul(c3, v1567); \
+ \
+    i32x4 o2 = vec_sub(o2a, o2b); \
+    i32x4 o3 = vec_add(o3a, o3b); \
+ \
+    u32x4 v12 = vec_splat_u32(12); \
+ \
+    o0 = vec_add(o0, v2048); \
+    o1 = vec_add(o1, v2048); \
+    o2 = vec_add(o2, v2048); \
+    o3 = vec_add(o3, v2048); \
+ \
+    o0 = vec_sra(o0, v12); \
+    o1 = vec_sra(o1, v12); \
+    o2 = vec_sra(o2, v12); \
+    o3 = vec_sra(o3, v12); \
+ \
+    c0 = vec_add(o0, o3); \
+    c1 = vec_add(o1, o2); \
+    c2 = vec_sub(o1, o2); \
+    c3 = vec_sub(o0, o3); \
+ \
+}
+
+#define dct4_for_dct8(c0, c1, c2, c3, c03, c12) \
+    IDCT_4_INNER(c0, c1, c2, c3) \
+    c03 = vec_packs(c0, c3); \
+    c12 = vec_packs(c1, c2); \
+
+#define dct_4_in(c0, c1, c2, c3, c01, c23) \
+{ \
+    IDCT_4_INNER(c0, c1, c2, c3) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+    c0 = i16h_to_i32(c01); \
+    c1 = i16l_to_i32(c01); \
+    c2 = i16h_to_i32(c23); \
+    c3 = i16l_to_i32(c23); \
+}
+
+#define dct_4_out(c0, c1, c2, c3, c01, c23) \
+    IDCT_4_INNER(c0, c1, c2, c3) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+
+
+#define IDENTITY_4(c01, c23) \
+{ \
+    i16x8 v1697 = vec_splats((int16_t)(1697*8)); \
+    i16x8 o01 = vec_mradds(c01, v1697, vec_splat_s16(0)); \
+    i16x8 o23 = vec_mradds(c23, v1697, vec_splat_s16(0)); \
+    c01 = vec_adds(c01, o01); \
+    c23 = vec_adds(c23, o23); \
+}
+
+#define identity_4_in(c0, c1, c2, c3, c01, c23) \
+{ \
+    IDENTITY_4(c01, c23) \
+    c0 = i16h_to_i32(c01); \
+    c1 = i16l_to_i32(c01); \
+    c2 = i16h_to_i32(c23); \
+    c3 = i16l_to_i32(c23); \
+}
+
+#define identity_4_out(c0, c1, c2, c3, c01, c23) \
+{ \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+    IDENTITY_4(c01, c23) \
+}
+
+#define ADST_INNER_4(c0, c1, c2, c3, oc0, oc1, oc2, oc3) \
+{ \
+    i32x4 v1321 = vec_splats(1321); \
+    i32x4 v3803 = vec_splats(3803); \
+    i32x4 v2482 = vec_splats(2482); \
+    i32x4 v3344 = vec_splats(3344); \
+    i32x4 v2048 = vec_splats(2048); \
+    i32x4 i0_v1321 = vec_mul(c0, v1321); \
+    i32x4 i0_v2482 = vec_mul(c0, v2482); \
+    i32x4 i0_v3803 = vec_mul(c0, v3803); \
+    i32x4 i1 = vec_mul(c1, v3344); \
+    i32x4 i2_v1321 = vec_mul(c2, v1321); \
+    i32x4 i2_v2482 = vec_mul(c2, v2482); \
+    i32x4 i2_v3803 = vec_mul(c2, v3803); \
+    i32x4 i3_v1321 = vec_mul(c3, v1321); \
+    i32x4 i3_v2482 = vec_mul(c3, v2482); \
+    i32x4 i3_v3803 = vec_mul(c3, v3803); \
+ \
+    i32x4 n1 = vec_sub(i1, v2048); \
+    i1 = vec_add(i1, v2048); \
+ \
+ \
+    i32x4 o0 = vec_add(i0_v1321, i2_v3803); \
+    i32x4 o1 = vec_sub(i0_v2482, i2_v1321); \
+    i32x4 o2 = vec_sub(c0, c2); \
+    i32x4 o3 = vec_add(i0_v3803, i2_v2482); \
+ \
+    o0 = vec_add(o0, i3_v2482); \
+    o1 = vec_sub(o1, i3_v3803); \
+    o2 = vec_add(o2, c3); \
+    o3 = vec_sub(o3, i3_v1321); \
+ \
+    o0 = vec_add(o0, i1); \
+    o1 = vec_add(o1, i1); \
+    o2 = vec_mul(o2, v3344); \
+    o3 = vec_sub(o3, n1); \
+ \
+    o2 = vec_add(o2, v2048); \
+ \
+    oc0 = vec_sra(o0, vec_splat_u32(12)); \
+    oc1 = vec_sra(o1, vec_splat_u32(12)); \
+    oc2 = vec_sra(o2, vec_splat_u32(12)); \
+    oc3 = vec_sra(o3, vec_splat_u32(12)); \
+}
+
+#define adst_4_in(c0, c1, c2, c3, c01, c23) \
+{ \
+    ADST_INNER_4(c0, c1, c2, c3, c0, c1, c2, c3) \
+}
+
+#define flipadst_4_in(c0, c1, c2, c3, c01, c23) \
+{ \
+    ADST_INNER_4(c0, c1, c2, c3, c3, c2, c1, c0) \
+}
+
+#define adst_4_out(c0, c1, c2, c3, c01, c23) \
+{ \
+    ADST_INNER_4(c0, c1, c2, c3, c0, c1, c2, c3) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+}
+
+#define flipadst_4_out(c0, c1, c2, c3, c01, c23) \
+{ \
+    ADST_INNER_4(c0, c1, c2, c3, c3, c2, c1, c0) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+}
+
+static void dc_only_4xN(uint8_t *dst, const ptrdiff_t stride, int16_t *const coeff, int n, int is_rect2, int shift)
+{
+    int dc = coeff[0];
+    const int rnd = (1 << shift) >> 1;
+    if (is_rect2)
+        dc = (dc * 181 + 128) >> 8;
+    dc = (dc * 181 + 128) >> 8;
+    dc = (dc + rnd) >> shift;
+    dc = (dc * 181 + 128 + 2048) >> 12;
+
+    i16x8 vdc = vec_splats((int16_t)dc);
+    coeff[0] = 0;
+    for (int i = 0; i < n; i++, dst += 4 * stride) {
+        LOAD_DECLARE_4(dst, stride, a, b, c, d)
+
+        i16x8 as = u8h_to_i16(a);
+        i16x8 bs = u8h_to_i16(b);
+        i16x8 cs = u8h_to_i16(c);
+        i16x8 ds = u8h_to_i16(d);
+
+        as = vec_adds(as, vdc);
+        bs = vec_adds(bs, vdc);
+        cs = vec_adds(cs, vdc);
+        ds = vec_adds(ds, vdc);
+
+        a = vec_packsu(as, as);
+        b = vec_packsu(bs, bs);
+        c = vec_packsu(cs, cs);
+        d = vec_packsu(ds, ds);
+
+        STORE_4(dst, stride, a, b, c, d)
+    }
+}
+
+static void dc_only_8xN(uint8_t *dst, const ptrdiff_t stride, int16_t *const coeff, int n, int is_rect2, int shift)
+{
+    int dc = coeff[0];
+    const int rnd = (1 << shift) >> 1;
+    if (is_rect2)
+        dc = (dc * 181 + 128) >> 8;
+    dc = (dc * 181 + 128) >> 8;
+    dc = (dc + rnd) >> shift;
+    dc = (dc * 181 + 128 + 2048) >> 12;
+
+    i16x8 vdc = vec_splats((int16_t)dc);
+    coeff[0] = 0;
+
+    for (int i = 0; i < n; i++, dst += 4 * stride) {
+        LOAD_DECLARE_4(dst, stride, a, b, c, d)
+
+        i16x8 as = u8h_to_i16(a);
+        i16x8 bs = u8h_to_i16(b);
+        i16x8 cs = u8h_to_i16(c);
+        i16x8 ds = u8h_to_i16(d);
+
+        as = vec_adds(as, vdc);
+        bs = vec_adds(bs, vdc);
+        cs = vec_adds(cs, vdc);
+        ds = vec_adds(ds, vdc);
+
+        a = vec_packsu(as, as);
+        b = vec_packsu(bs, bs);
+        c = vec_packsu(cs, cs);
+        d = vec_packsu(ds, ds);
+
+        STORE_8(dst, stride, a, b, c, d)
+    }
+}
+
+static void dc_only_16xN(uint8_t *dst, const ptrdiff_t stride, int16_t *const coeff, int n, int is_rect2, int shift)
+{
+    int dc = coeff[0];
+    const int rnd = (1 << shift) >> 1;
+    if (is_rect2)
+        dc = (dc * 181 + 128) >> 8;
+    dc = (dc * 181 + 128) >> 8;
+    dc = (dc + rnd) >> shift;
+    dc = (dc * 181 + 128 + 2048) >> 12;
+
+    i16x8 vdc = vec_splats((int16_t)dc);
+    coeff[0] = 0;
+
+    for (int i = 0; i < n; i++, dst += 4 * stride) {
+        LOAD_DECLARE_4(dst, stride, a, b, c, d)
+
+        i16x8 ah = u8h_to_i16(a);
+        i16x8 bh = u8h_to_i16(b);
+        i16x8 ch = u8h_to_i16(c);
+        i16x8 dh = u8h_to_i16(d);
+        i16x8 al = u8l_to_i16(a);
+        i16x8 bl = u8l_to_i16(b);
+        i16x8 cl = u8l_to_i16(c);
+        i16x8 dl = u8l_to_i16(d);
+
+        ah = vec_adds(ah, vdc);
+        bh = vec_adds(bh, vdc);
+        ch = vec_adds(ch, vdc);
+        dh = vec_adds(dh, vdc);
+        al = vec_adds(al, vdc);
+        bl = vec_adds(bl, vdc);
+        cl = vec_adds(cl, vdc);
+        dl = vec_adds(dl, vdc);
+
+        a = vec_packsu(ah, al);
+        b = vec_packsu(bh, bl);
+        c = vec_packsu(ch, cl);
+        d = vec_packsu(dh, dl);
+
+        STORE_16(dst, stride, a, b, c, d)
+    }
+}
+
+void dav1d_inv_txfm_add_dct_dct_4x4_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride,
+                                              int16_t *const coeff, const int eob)
+{
+    assert(eob >= 0);
+
+    if (eob < 1) {
+        return dc_only_4xN(dst, stride, coeff, 1, 0, 0);
+    }
+
+    LOAD_COEFF_4(coeff)
+
+    dct_4_in(c0, c1, c2, c3, c01, c23)
+
+    TRANSPOSE4_I32(c0, c1, c2, c3)
+
+    memset(coeff, 0, sizeof(*coeff) * 4 * 4);
+
+    dct_4_out(c0, c1, c2, c3, c01, c23)
+
+    LOAD_DECLARE_4(dst, stride, a, b, c, d)
+
+    APPLY_COEFF_4(a, b, c, d, c01, c23)
+
+    STORE_4(dst, stride, a, b, c, d)
+}
+
+void dav1d_inv_txfm_add_wht_wht_4x4_8bpc_pwr9(pixel *dst, const ptrdiff_t stride,
+                                              coef *const coeff, const int eob)
+{
+    LOAD_COEFF_4(coeff)
+
+    u32x4 v2 = vec_splat_u32(2);
+
+    c0 = vec_sra(c0, v2);
+    c1 = vec_sra(c1, v2);
+    c2 = vec_sra(c2, v2);
+    c3 = vec_sra(c3, v2);
+
+    i32x4 t0 = vec_add(c0, c1);
+    i32x4 t2 = vec_sub(c2, c3);
+    i32x4 t4 = vec_sra(vec_sub(t0, t2), vec_splat_u32(1));
+    i32x4 t3 = vec_sub(t4, c3);
+    i32x4 t1 = vec_sub(t4, c1);
+    c0 = vec_sub(t0, t3);
+    c1 = t3;
+    c2 = t1;
+    c3 = vec_add(t2, t1);
+
+    memset(coeff, 0, sizeof(*coeff) * 4 * 4);
+
+    TRANSPOSE4_I32(c0, c1, c2, c3)
+
+    t0 = vec_add(c0, c1);
+    t2 = vec_sub(c2, c3);
+    t4 = vec_sra(vec_sub(t0, t2), vec_splat_u32(1));
+    t3 = vec_sub(t4, c3);
+    t1 = vec_sub(t4, c1);
+    c0 = vec_sub(t0, t3);
+    c1 = t3;
+    c2 = t1;
+    c3 = vec_add(t2, t1);
+
+    c01 = vec_packs(c0, c1);
+    c23 = vec_packs(c2, c3);
+
+    LOAD_DECLARE_4(dst, stride, a, b, c, d)
+
+    u8x16 ab = (u8x16)vec_mergeh((u32x4)a, (u32x4)b);
+    u8x16 cd = (u8x16)vec_mergeh((u32x4)c, (u32x4)d);
+
+    i16x8 abs = u8h_to_i16(ab);
+    i16x8 cds = u8h_to_i16(cd);
+
+    abs = vec_adds(abs, c01);
+    cds = vec_adds(cds, c23);
+
+    a = vec_packsu(abs, abs);
+    c = vec_packsu(cds, cds);
+
+    b = (u8x16)vec_mergeo((u32x4)a, (u32x4)a);
+    d = (u8x16)vec_mergeo((u32x4)c, (u32x4)c);
+
+    STORE_4(dst, stride, a, b, c, d)
+}
+
+#define inv_txfm_fn4x4(type1, type2) \
+void dav1d_inv_txfm_add_##type1##_##type2##_4x4_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride, \
+                                                          int16_t *const coeff, const int eob) \
+{ \
+    LOAD_COEFF_4(coeff) \
+    type1##_4_in(c0, c1, c2, c3, c01, c23) \
+    memset(coeff, 0, sizeof(*coeff) * 4 * 4); \
+    TRANSPOSE4_I32(c0, c1, c2, c3) \
+    type2##_4_out(c0, c1, c2, c3, c01, c23) \
+    LOAD_DECLARE_4(dst, stride, a, b, c, d) \
+    APPLY_COEFF_4(a, b, c, d, c01, c23) \
+    STORE_4(dst, stride, a, b, c, d) \
+}
+
+inv_txfm_fn4x4(adst,     dct     )
+inv_txfm_fn4x4(dct,      adst    )
+inv_txfm_fn4x4(dct,      flipadst)
+inv_txfm_fn4x4(flipadst, dct     )
+inv_txfm_fn4x4(adst,     flipadst)
+inv_txfm_fn4x4(flipadst, adst    )
+inv_txfm_fn4x4(identity, dct     )
+inv_txfm_fn4x4(dct,      identity)
+inv_txfm_fn4x4(identity, flipadst)
+inv_txfm_fn4x4(flipadst, identity)
+inv_txfm_fn4x4(identity, adst   )
+inv_txfm_fn4x4(adst,     identity)
+inv_txfm_fn4x4(identity, identity)
+inv_txfm_fn4x4(adst,     adst    )
+inv_txfm_fn4x4(flipadst, flipadst)
+
+
+#define IDCT_8_INNER(c0, c1, c2, c3, c4, c5, c6, c7, c03, c12, c74, c65) \
+    dct4_for_dct8(c0, c2, c4, c6, c03, c12) \
+ \
+    i32x4 v799 = vec_splats(799); \
+    i32x4 v4017 = vec_splats(4017); \
+    i32x4 v3406 = vec_splats(3406); \
+    i32x4 v2276 = vec_splats(2276); \
+    i32x4 v2048 = vec_splats(2048); \
+    u32x4 v12 = vec_splat_u32(12); \
+ \
+    i32x4 c1v799 = vec_mul(c1, v799); \
+    i32x4 c7v4017 = vec_mul(c7, v4017); \
+    i32x4 c5v3406 = vec_mul(c5, v3406); \
+    i32x4 c3v2276 = vec_mul(c3, v2276); \
+    i32x4 c5v2276 = vec_mul(c5, v2276); \
+    i32x4 c3v3406 = vec_mul(c3, v3406); \
+    i32x4 c1v4017 = vec_mul(c1, v4017); \
+    i32x4 c7v799 = vec_mul(c7, v799); \
+ \
+    i32x4 t4a = vec_subs(c1v799, c7v4017); \
+    i32x4 t5a = vec_subs(c5v3406, c3v2276); \
+    i32x4 t6a = vec_adds(c5v2276, c3v3406); \
+    i32x4 t7a = vec_adds(c1v4017, c7v799); \
+ \
+    t4a = vec_adds(t4a, v2048); \
+    t5a = vec_adds(t5a, v2048); \
+    t6a = vec_adds(t6a, v2048); \
+    t7a = vec_adds(t7a, v2048); \
+ \
+    t4a = vec_sra(t4a, v12); \
+    t7a = vec_sra(t7a, v12); \
+    t5a = vec_sra(t5a, v12); \
+    t6a = vec_sra(t6a, v12); \
+ \
+    i16x8 t7at4a = vec_packs(t7a, t4a); \
+    i16x8 t6at5a = vec_packs(t6a, t5a); \
+ \
+    i16x8 t7t4 = vec_adds(t7at4a, t6at5a); \
+    t6at5a = vec_subs(t7at4a, t6at5a); \
+ \
+    t6a = i16h_to_i32(t6at5a); \
+    t5a = i16l_to_i32(t6at5a); \
+ \
+    i32x4 t6 = vec_add(t6a, t5a); \
+    i32x4 t5 = vec_sub(t6a, t5a); \
+ \
+    t6 = vec_mul(t6, vec_splats(181)); \
+    t5 = vec_mul(t5, vec_splats(181)); \
+    t6 = vec_add(t6, vec_splats(128)); \
+    t5 = vec_add(t5, vec_splats(128)); \
+ \
+    t6 = vec_sra(t6, vec_splat_u32(8)); \
+    t5 = vec_sra(t5, vec_splat_u32(8)); \
+ \
+    i16x8 t6t5 = vec_packs(t6, t5); \
+ \
+    c74 = vec_subs(c03, t7t4); \
+    c65 = vec_subs(c12, t6t5); \
+    c03 = vec_adds(c03, t7t4); \
+    c12 = vec_adds(c12, t6t5); \
+
+#define UNPACK_4_I16_I32(t0, t1, t2, t3) \
+    t0 = i16h_to_i32(t0##t1); \
+    t1 = i16l_to_i32(t0##t1); \
+    t2 = i16h_to_i32(t2##t3); \
+    t3 = i16l_to_i32(t2##t3);
+
+#define UNPACK_PAIR_I16_I32(hi, lo, v) \
+    hi = i16h_to_i32(v); \
+    lo = i16l_to_i32(v); \
+
+
+#define dct_8_in(c0, c1, c2, c3, c4, c5, c6, c7, ...) \
+{ \
+    i16x8 c0##c3, c1##c2, c7##c4, c6##c5; \
+    IDCT_8_INNER(c0, c1, c2, c3, c4, c5, c6, c7, c0##c3, c1##c2, c7##c4, c6##c5) \
+    UNPACK_4_I16_I32(c0, c3, c1, c2) \
+    UNPACK_4_I16_I32(c7, c4, c6, c5) \
+}
+
+#define dct_8_out(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+{ \
+    i16x8 c03, c12, c74, c65; \
+    IDCT_8_INNER(c0, c1, c2, c3, c4, c5, c6, c7, c03, c12, c74, c65) \
+    c01 = (i16x8)vec_mergeh((u64x2)c03, (u64x2)c12); \
+    c23 = (i16x8)vec_mergel((u64x2)c12, (u64x2)c03); \
+    c45 = (i16x8)vec_mergel((u64x2)c74, (u64x2)c65); \
+    c67 = (i16x8)vec_mergeh((u64x2)c65, (u64x2)c74); \
+}
+
+#define dct_8x2_in(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                   c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                   c0, c1, c2, c3, c4, c5, c6, c7) \
+{ \
+    dct_8_in(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h,) \
+    dct_8_in(c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l,) \
+}
+
+#define dct_8x2_out(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                    c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                    c0, c1, c2, c3, c4, c5, c6, c7) \
+{ \
+    i16x8 c03h, c12h, c74h, c65h; \
+    i16x8 c03l, c12l, c74l, c65l; \
+    { \
+        IDCT_8_INNER(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, c03h, c12h, c74h, c65h) \
+    } \
+    { \
+        IDCT_8_INNER(c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, c03l, c12l, c74l, c65l) \
+    } \
+    c0 = (i16x8)vec_mergeh((u64x2)c03h, (u64x2)c03l); \
+    c3 = (i16x8)vec_mergel((u64x2)c03h, (u64x2)c03l); \
+    c1 = (i16x8)vec_mergeh((u64x2)c12h, (u64x2)c12l); \
+    c2 = (i16x8)vec_mergel((u64x2)c12h, (u64x2)c12l); \
+    c7 = (i16x8)vec_mergeh((u64x2)c74h, (u64x2)c74l); \
+    c4 = (i16x8)vec_mergel((u64x2)c74h, (u64x2)c74l); \
+    c6 = (i16x8)vec_mergeh((u64x2)c65h, (u64x2)c65l); \
+    c5 = (i16x8)vec_mergel((u64x2)c65h, (u64x2)c65l); \
+}
+
+#define IDENTITY_8(c01, c23, c45, c67) \
+{ \
+    c01 = vec_adds(c01, c01); \
+    c23 = vec_adds(c23, c23); \
+    c45 = vec_adds(c45, c45); \
+    c67 = vec_adds(c67, c67); \
+}
+
+#define identity_8_in(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+{ \
+    IDENTITY_8(c01, c23, c45, c67) \
+    UNPACK_PAIR_I16_I32(c0, c1, c01) \
+    UNPACK_PAIR_I16_I32(c2, c3, c23) \
+    UNPACK_PAIR_I16_I32(c4, c5, c45) \
+    UNPACK_PAIR_I16_I32(c6, c7, c67) \
+}
+
+#define identity_8_out(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+    c45 = vec_packs(c4, c5); \
+    c67 = vec_packs(c6, c7); \
+    IDENTITY_8(c01, c23, c45, c67)
+
+#define identity_8x2_in(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                        c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                        c0, c1, c2, c3, c4, c5, c6, c7) \
+{ \
+    IDENTITY_8(c0, c1, c2, c3) \
+    IDENTITY_8(c4, c5, c6, c7) \
+    UNPACK_PAIR_I16_I32(c0h, c0l, c0) \
+    UNPACK_PAIR_I16_I32(c1h, c1l, c1) \
+    UNPACK_PAIR_I16_I32(c2h, c2l, c2) \
+    UNPACK_PAIR_I16_I32(c3h, c3l, c3) \
+    UNPACK_PAIR_I16_I32(c4h, c4l, c4) \
+    UNPACK_PAIR_I16_I32(c5h, c5l, c5) \
+    UNPACK_PAIR_I16_I32(c6h, c6l, c6) \
+    UNPACK_PAIR_I16_I32(c7h, c7l, c7) \
+}
+
+#define PACK_4(c0, c1, c2, c3, \
+               c0h, c1h, c2h, c3h, \
+               c0l, c1l, c2l, c3l) \
+{ \
+    c0 = vec_packs(c0h, c0l); \
+    c1 = vec_packs(c1h, c1l); \
+    c2 = vec_packs(c2h, c2l); \
+    c3 = vec_packs(c3h, c3l); \
+}
+
+#define DECLARE_PACK_4(c0, c1, c2, c3, \
+                       c0h, c1h, c2h, c3h, \
+                       c0l, c1l, c2l, c3l) \
+    i16x8 c0, c1, c2, c3; \
+    PACK_4(c0, c1, c2, c3, c0h, c1h, c2h, c3h, c0l, c1l, c2l, c3l);
+
+#define PACK_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+               c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+               c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l) \
+{ \
+    c0 = vec_packs(c0h, c0l); \
+    c1 = vec_packs(c1h, c1l); \
+    c2 = vec_packs(c2h, c2l); \
+    c3 = vec_packs(c3h, c3l); \
+    c4 = vec_packs(c4h, c4l); \
+    c5 = vec_packs(c5h, c5l); \
+    c6 = vec_packs(c6h, c6l); \
+    c7 = vec_packs(c7h, c7l); \
+}
+
+#define identity_8x2_out(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                         c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                         c0, c1, c2, c3, c4, c5, c6, c7) \
+{ \
+    PACK_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+           c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+           c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l) \
+    IDENTITY_8(c0, c1, c2, c3) \
+    IDENTITY_8(c4, c5, c6, c7) \
+}
+
+#define DECLARE_SPLAT_I32(val) \
+    i32x4 v##val = vec_splats(val);
+
+#define DECLARE_MUL_PAIR_I32(ca, cb, va, vb) \
+    i32x4 ca##va = vec_mul(ca, va); \
+    i32x4 cb##vb = vec_mul(cb, vb); \
+    i32x4 ca##vb = vec_mul(ca, vb); \
+    i32x4 cb##va = vec_mul(cb, va);
+
+#define ADD_SUB_PAIR(r0, r1, ca, cb, va, vb) \
+    r0 = vec_adds(ca##va, cb##vb); \
+    r1 = vec_subs(ca##vb, cb##va);
+
+#define DECLARE_ADD_SUB_PAIR(r0, r1, ca, cb, va, vb) \
+    i32x4 r0, r1; \
+    ADD_SUB_PAIR(r0, r1, ca, cb, va, vb)
+
+#define SCALE_ROUND_4(a, b, c, d, rnd, shift) \
+    a = vec_adds(a, rnd); \
+    b = vec_adds(b, rnd); \
+    c = vec_adds(c, rnd); \
+    d = vec_adds(d, rnd); \
+    a = vec_sra(a, shift); \
+    b = vec_sra(b, shift); \
+    c = vec_sra(c, shift); \
+    d = vec_sra(d, shift);
+
+#define ADST_INNER_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+                     o0, o1, o2, o3, o4, o5, o6, o7) \
+{ \
+    DECLARE_SPLAT_I32(4076) \
+    DECLARE_SPLAT_I32(401) \
+ \
+    DECLARE_SPLAT_I32(3612) \
+    DECLARE_SPLAT_I32(1931) \
+ \
+    DECLARE_SPLAT_I32(2598) \
+    DECLARE_SPLAT_I32(3166) \
+ \
+    DECLARE_SPLAT_I32(1189) \
+    DECLARE_SPLAT_I32(3920) \
+ \
+    DECLARE_SPLAT_I32(3784) \
+    DECLARE_SPLAT_I32(1567) \
+ \
+    DECLARE_SPLAT_I32(2048) \
+    u32x4 v12 = vec_splat_u32(12); \
+ \
+    DECLARE_MUL_PAIR_I32(c7, c0, v4076, v401) \
+    DECLARE_MUL_PAIR_I32(c5, c2, v3612, v1931) \
+    DECLARE_MUL_PAIR_I32(c3, c4, v2598, v3166) \
+    DECLARE_MUL_PAIR_I32(c1, c6, v1189, v3920) \
+ \
+    DECLARE_ADD_SUB_PAIR(t0a, t1a, c7, c0, v4076, v401) \
+    DECLARE_ADD_SUB_PAIR(t2a, t3a, c5, c2, v3612, v1931) \
+    DECLARE_ADD_SUB_PAIR(t4a, t5a, c3, c4, v2598, v3166) \
+    DECLARE_ADD_SUB_PAIR(t6a, t7a, c1, c6, v1189, v3920) \
+ \
+    SCALE_ROUND_4(t0a, t1a, t2a, t3a, v2048, v12) \
+    SCALE_ROUND_4(t4a, t5a, t6a, t7a, v2048, v12) \
+ \
+    i32x4 t0 = vec_add(t0a, t4a); \
+    i32x4 t1 = vec_add(t1a, t5a); \
+    i32x4 t2 = vec_add(t2a, t6a); \
+    i32x4 t3 = vec_add(t3a, t7a); \
+    i32x4 t4 = vec_sub(t0a, t4a); \
+    i32x4 t5 = vec_sub(t1a, t5a); \
+    i32x4 t6 = vec_sub(t2a, t6a); \
+    i32x4 t7 = vec_sub(t3a, t7a); \
+ \
+    i16x8 t0t1 = vec_packs(t0, t1); \
+    i16x8 t2t3 = vec_packs(t2, t3); \
+    i16x8 t4t5 = vec_packs(t4, t5); \
+    i16x8 t6t7 = vec_packs(t6, t7); \
+ \
+    UNPACK_4_I16_I32(t4, t5, t6, t7) \
+    UNPACK_4_I16_I32(t0, t1, t2, t3) \
+ \
+    DECLARE_MUL_PAIR_I32(t4, t5, v3784, v1567) \
+    DECLARE_MUL_PAIR_I32(t7, t6, v3784, v1567) \
+ \
+    ADD_SUB_PAIR(t4a, t5a, t4, t5, v3784, v1567) \
+    ADD_SUB_PAIR(t7a, t6a, t7, t6, v1567, v3784) \
+ \
+    SCALE_ROUND_4(t4a, t5a, t6a, t7a, v2048, v12) \
+  \
+    o0 = vec_add(t0, t2); \
+    o1 = vec_add(t4a, t6a); \
+    o7 = vec_add(t1, t3); \
+    o6 = vec_add(t5a, t7a); \
+    t2 = vec_sub(t0, t2); \
+    t3 = vec_sub(t1, t3); \
+    t6 = vec_sub(t4a, t6a); \
+    t7 = vec_sub(t5a, t7a); \
+ \
+    i16x8 o7##o1 = vec_packs(o7, o1); \
+    i16x8 o0##o6 = vec_packs(o0, o6); \
+    t2t3 = vec_packs(t2, t3); \
+    t6t7 = vec_packs(t6, t7); \
+ \
+    UNPACK_4_I16_I32(t2, t3, t6, t7) \
+    UNPACK_4_I16_I32(o7, o1, o0, o6) \
+ \
+    o7 = -o7; \
+    o1 = -o1; \
+ \
+    o3 = vec_add(t2, t3); \
+    o4 = vec_sub(t2, t3); \
+    o5 = vec_sub(t6, t7); \
+    o2 = vec_add(t6, t7); \
+ \
+    i32x4 v181 = vec_splats(181); \
+    i32x4 v128 = vec_splats(128); \
+    u32x4 v8 = vec_splat_u32(8); \
+ \
+    o2 = vec_mul(o2, v181); \
+    o3 = vec_mul(o3, v181); \
+    o4 = vec_mul(o4, v181); \
+    o5 = vec_mul(o5, v181); \
+ \
+    SCALE_ROUND_4(o2, o3, o4, o5, v128, v8) \
+ \
+    o3 = -o3; \
+    o5 = -o5; \
+}
+
+#define adst_8_in(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+{\
+    ADST_INNER_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+                 c0, c1, c2, c3, c4, c5, c6, c7) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+    c45 = vec_packs(c4, c5); \
+    c67 = vec_packs(c6, c7); \
+    UNPACK_PAIR_I16_I32(c0, c1, c01) \
+    UNPACK_PAIR_I16_I32(c2, c3, c23) \
+    UNPACK_PAIR_I16_I32(c4, c5, c45) \
+    UNPACK_PAIR_I16_I32(c6, c7, c67) \
+}
+
+#define adst_8_out(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+{\
+    ADST_INNER_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+                 c0, c1, c2, c3, c4, c5, c6, c7) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+    c45 = vec_packs(c4, c5); \
+    c67 = vec_packs(c6, c7); \
+}
+
+#define adst_8x2_in(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                    c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                    c0, c1, c2, c3, c4, c5, c6, c7) \
+{ \
+    ADST_INNER_8(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                 c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h) \
+    ADST_INNER_8(c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                 c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l) \
+}
+
+#define adst_8x2_out(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                    c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                    c0, c1, c2, c3, c4, c5, c6, c7) \
+{ \
+    ADST_INNER_8(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                 c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h) \
+    ADST_INNER_8(c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                 c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l) \
+    PACK_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+           c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+           c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l) \
+}
+
+#define flipadst_8_in(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+{\
+    ADST_INNER_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+                 c7, c6, c5, c4, c3, c2, c1, c0) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+    c45 = vec_packs(c4, c5); \
+    c67 = vec_packs(c6, c7); \
+    UNPACK_PAIR_I16_I32(c0, c1, c01) \
+    UNPACK_PAIR_I16_I32(c2, c3, c23) \
+    UNPACK_PAIR_I16_I32(c4, c5, c45) \
+    UNPACK_PAIR_I16_I32(c6, c7, c67) \
+}
+
+#define flipadst_8_out(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+{\
+    ADST_INNER_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+                 c7, c6, c5, c4, c3, c2, c1, c0) \
+    c01 = vec_packs(c0, c1); \
+    c23 = vec_packs(c2, c3); \
+    c45 = vec_packs(c4, c5); \
+    c67 = vec_packs(c6, c7); \
+}
+
+#define flipadst_8x2_in(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                        c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                        c0, c1, c2, c3, c4, c5, c6, c7) \
+{ \
+    ADST_INNER_8(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                 c7h, c6h, c5h, c4h, c3h, c2h, c1h, c0h) \
+    ADST_INNER_8(c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                 c7l, c6l, c5l, c4l, c3l, c2l, c1l, c0l) \
+}
+
+#define flipadst_8x2_out(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                         c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                         c0, c1, c2, c3, c4, c5, c6, c7) \
+{ \
+    ADST_INNER_8(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                 c7h, c6h, c5h, c4h, c3h, c2h, c1h, c0h) \
+    ADST_INNER_8(c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                 c7l, c6l, c5l, c4l, c3l, c2l, c1l, c0l) \
+    PACK_8(c0, c1, c2, c3, c4, c5, c6, c7, \
+           c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+           c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l) \
+}
+
+void dav1d_inv_txfm_add_dct_dct_4x8_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride,
+                                              int16_t *const coeff, const int eob)
+{
+    i16x8 v = vec_splats((int16_t)(2896*8));
+
+    if (eob < 1) {
+        return dc_only_4xN(dst, stride, coeff, 2, 1, 0);
+    }
+
+    LOAD_SCALE_COEFF_4x8(coeff, v)
+
+    dct_4_in(c0, c1, c2, c3, c01, c23)
+    dct_4_in(c4, c5, c6, c7, c45, c67)
+
+
+    memset(coeff, 0, sizeof(*coeff) * 4 * 8);
+
+    TRANSPOSE4_I32(c0, c1, c2, c3);
+    TRANSPOSE4_I32(c4, c5, c6, c7);
+
+    dct_8_out(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67)
+
+    LOAD_DECLARE_4(dst, stride, a, b, cc, d)
+    LOAD_DECLARE_4(dst + 4 * stride, stride, e, f, g, hh)
+
+    APPLY_COEFF_4(a, b, cc, d, c01, c23)
+    APPLY_COEFF_4(e, f, g, hh, c45, c67)
+
+    STORE_4(dst, stride, a, b, cc, d)
+    STORE_4(dst + 4 * stride, stride, e, f, g, hh)
+}
+
+
+#define inv_txfm_fn4x8(type1, type2) \
+void dav1d_inv_txfm_add_##type1##_##type2##_4x8_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride, \
+                                                          int16_t *const coeff, const int eob) \
+{ \
+    i16x8 v = vec_splats((int16_t)(2896*8)); \
+    LOAD_SCALE_COEFF_4x8(coeff, v) \
+    type1##_4_in(c0, c1, c2, c3, c01, c23) \
+    type1##_4_in(c4, c5, c6, c7, c45, c67) \
+    memset(coeff, 0, sizeof(*coeff) * 4 * 8); \
+    TRANSPOSE4_I32(c0, c1, c2, c3); \
+    TRANSPOSE4_I32(c4, c5, c6, c7); \
+    type2##_8_out(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+    LOAD_DECLARE_4(dst, stride, a, b, c, d) \
+    LOAD_DECLARE_4(dst + 4 * stride, stride, e, f, g, h) \
+    APPLY_COEFF_4(a, b, c, d, c01, c23) \
+    APPLY_COEFF_4(e, f, g, h, c45, c67) \
+    STORE_4(dst, stride, a, b, c, d) \
+    STORE_4(dst + 4 * stride, stride, e, f, g, h) \
+}
+
+inv_txfm_fn4x8(adst,     dct     )
+inv_txfm_fn4x8(dct,      adst    )
+inv_txfm_fn4x8(dct,      flipadst)
+inv_txfm_fn4x8(flipadst, dct     )
+inv_txfm_fn4x8(adst,     flipadst)
+inv_txfm_fn4x8(flipadst, adst    )
+inv_txfm_fn4x8(identity, dct     )
+inv_txfm_fn4x8(dct,      identity)
+inv_txfm_fn4x8(identity, flipadst)
+inv_txfm_fn4x8(flipadst, identity)
+inv_txfm_fn4x8(identity, adst   )
+inv_txfm_fn4x8(adst,     identity)
+inv_txfm_fn4x8(identity, identity)
+inv_txfm_fn4x8(adst,     adst    )
+inv_txfm_fn4x8(flipadst, flipadst)
+
+
+void dav1d_inv_txfm_add_dct_dct_8x4_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride,
+                                              int16_t *const coeff, const int eob)
+{
+    i16x8 v = vec_splats((int16_t)(2896*8));
+
+    if (eob < 1) {
+        return dc_only_8xN(dst, stride, coeff, 1, 1, 0);
+    }
+
+    LOAD_SCALE_COEFF_8x4(coeff, v)
+
+    dct_8_in(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67)
+
+    memset(coeff, 0, sizeof(*coeff) * 8 * 4);
+
+    TRANSPOSE4_I32(c0, c1, c2, c3)
+    TRANSPOSE4_I32(c4, c5, c6, c7)
+
+    dct_4_out(c0, c1, c2, c3, c01, c23)
+    dct_4_out(c4, c5, c6, c7, c45, c67)
+
+    LOAD_DECLARE_4(dst, stride, ae, bf, cg, dh)
+
+    i16x8 c04 = (i16x8)vec_mergeh((u64x2)c01, (u64x2)c45);
+    i16x8 c15 = (i16x8)vec_mergel((u64x2)c01, (u64x2)c45);
+    i16x8 c26 = (i16x8)vec_mergeh((u64x2)c23, (u64x2)c67);
+    i16x8 c37 = (i16x8)vec_mergel((u64x2)c23, (u64x2)c67);
+
+    APPLY_COEFF_8x4(ae, bf, c04, c15)
+    APPLY_COEFF_8x4(cg, dh, c26, c37)
+
+    STORE_8(dst, stride, ae, bf, cg, dh)
+}
+
+
+#define inv_txfm_fn8x4(type1, type2) \
+void dav1d_inv_txfm_add_##type1##_##type2##_8x4_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride, \
+                                                          int16_t *const coeff, const int eob) \
+{ \
+    i16x8 v = vec_splats((int16_t)(2896*8)); \
+    LOAD_SCALE_COEFF_8x4(coeff, v) \
+    type1##_8_in(c0, c1, c2, c3, c4, c5, c6, c7, c01, c23, c45, c67) \
+    memset(coeff, 0, sizeof(*coeff) * 8 * 4); \
+    TRANSPOSE4_I32(c0, c1, c2, c3) \
+    TRANSPOSE4_I32(c4, c5, c6, c7) \
+    type2##_4_out(c0, c1, c2, c3, c01, c23) \
+    type2##_4_out(c4, c5, c6, c7, c45, c67) \
+    LOAD_DECLARE_4(dst, stride, ae, bf, cg, dh) \
+    i16x8 c04 = (i16x8)vec_mergeh((u64x2)c01, (u64x2)c45); \
+    i16x8 c15 = (i16x8)vec_mergel((u64x2)c01, (u64x2)c45); \
+    i16x8 c26 = (i16x8)vec_mergeh((u64x2)c23, (u64x2)c67); \
+    i16x8 c37 = (i16x8)vec_mergel((u64x2)c23, (u64x2)c67); \
+    APPLY_COEFF_8x4(ae, bf, c04, c15) \
+    APPLY_COEFF_8x4(cg, dh, c26, c37) \
+    STORE_8(dst, stride, ae, bf, cg, dh) \
+}
+inv_txfm_fn8x4(adst,     dct     )
+inv_txfm_fn8x4(dct,      adst    )
+inv_txfm_fn8x4(dct,      flipadst)
+inv_txfm_fn8x4(flipadst, dct     )
+inv_txfm_fn8x4(adst,     flipadst)
+inv_txfm_fn8x4(flipadst, adst    )
+inv_txfm_fn8x4(identity, dct     )
+inv_txfm_fn8x4(dct,      identity)
+inv_txfm_fn8x4(identity, flipadst)
+inv_txfm_fn8x4(flipadst, identity)
+inv_txfm_fn8x4(identity, adst   )
+inv_txfm_fn8x4(adst,     identity)
+inv_txfm_fn8x4(identity, identity)
+inv_txfm_fn8x4(adst,     adst    )
+inv_txfm_fn8x4(flipadst, flipadst)
+
+void dav1d_inv_txfm_add_dct_dct_8x8_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride,
+                                              int16_t *const coeff, const int eob)
+{
+    if (eob < 1) {
+        return dc_only_8xN(dst, stride, coeff, 2, 0, 1);
+    }
+
+    LOAD_COEFF_8x8(coeff)
+
+    dct_8x2_in(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h,
+               c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l,
+               c0, c1, c2, c3, c4, c5, c6, c7)
+
+    memset(coeff, 0, sizeof(*coeff) * 8 * 8);
+
+    SCALE_ROUND_4(c0h, c1h, c2h, c3h, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(c4h, c5h, c6h, c7h, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(c0l, c1l, c2l, c3l, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(c4l, c5l, c6l, c7l, vec_splat_s32(1), vec_splat_u32(1))
+
+    TRANSPOSE8_I32(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h,
+                   c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l)
+
+    dct_8x2_out(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h,
+                c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l,
+                c0, c1, c2, c3, c4, c5, c6, c7)
+
+    LOAD_DECLARE_4(dst, stride, a, b, cc, d)
+    LOAD_DECLARE_4(dst + 4 * stride, stride, e, f, g, hh)
+
+    APPLY_COEFF_8x4(a, b, c0, c1)
+    APPLY_COEFF_8x4(cc, d, c2, c3)
+    APPLY_COEFF_8x4(e, f, c4, c5)
+    APPLY_COEFF_8x4(g, hh, c6, c7)
+
+    STORE_8(dst, stride, a, b, cc, d)
+    STORE_8(dst + 4 * stride, stride, e, f, g, hh)
+}
+
+#define inv_txfm_fn8x8(type1, type2) \
+void dav1d_inv_txfm_add_##type1##_##type2##_8x8_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride, \
+                                                          int16_t *const coeff, const int eob) \
+{ \
+    LOAD_COEFF_8x8(coeff) \
+    type1##_8x2_in(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                   c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                   c0, c1, c2, c3, c4, c5, c6, c7) \
+    SCALE_ROUND_4(c0h, c1h, c2h, c3h, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c4h, c5h, c6h, c7h, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c0l, c1l, c2l, c3l, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c4l, c5l, c6l, c7l, vec_splat_s32(1), vec_splat_u32(1)) \
+    memset(coeff, 0, sizeof(*coeff) * 8 * 8); \
+    TRANSPOSE8_I32(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                   c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l) \
+    type2##_8x2_out(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                    c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                    c0, c1, c2, c3, c4, c5, c6, c7) \
+    LOAD_DECLARE_4(dst, stride, a, b, c, d) \
+    LOAD_DECLARE_4(dst + 4 * stride, stride, e, f, g, h) \
+    APPLY_COEFF_8x4(a, b, c0, c1) \
+    APPLY_COEFF_8x4(c, d, c2, c3) \
+    APPLY_COEFF_8x4(e, f, c4, c5) \
+    APPLY_COEFF_8x4(g, h, c6, c7) \
+    STORE_8(dst, stride, a, b, c, d) \
+    STORE_8(dst + 4 * stride, stride, e, f, g, h) \
+}
+inv_txfm_fn8x8(adst,     dct     )
+inv_txfm_fn8x8(dct,      adst    )
+inv_txfm_fn8x8(dct,      flipadst)
+inv_txfm_fn8x8(flipadst, dct     )
+inv_txfm_fn8x8(adst,     flipadst)
+inv_txfm_fn8x8(flipadst, adst    )
+inv_txfm_fn8x8(dct,      identity)
+inv_txfm_fn8x8(flipadst, identity)
+inv_txfm_fn8x8(adst,     identity)
+inv_txfm_fn8x8(adst,     adst    )
+inv_txfm_fn8x8(flipadst, flipadst)
+
+// identity + scale is a no op
+#define inv_txfm_fn8x8_identity(type2) \
+void dav1d_inv_txfm_add_identity_##type2##_8x8_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride, \
+                                                         int16_t *const coeff, const int eob) \
+{ \
+    LOAD_COEFF_8x8(coeff) \
+    memset(coeff, 0, sizeof(*coeff) * 8 * 8); \
+    TRANSPOSE8_I32(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                   c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l) \
+    type2##_8x2_out(c0h, c1h, c2h, c3h, c4h, c5h, c6h, c7h, \
+                    c0l, c1l, c2l, c3l, c4l, c5l, c6l, c7l, \
+                    c0, c1, c2, c3, c4, c5, c6, c7) \
+    LOAD_DECLARE_4(dst, stride, a, b, c, d) \
+    LOAD_DECLARE_4(dst + 4 * stride, stride, e, f, g, h) \
+    APPLY_COEFF_8x4(a, b, c0, c1) \
+    APPLY_COEFF_8x4(c, d, c2, c3) \
+    APPLY_COEFF_8x4(e, f, c4, c5) \
+    APPLY_COEFF_8x4(g, h, c6, c7) \
+    STORE_8(dst, stride, a, b, c, d) \
+    STORE_8(dst + 4 * stride, stride, e, f, g, h) \
+}
+inv_txfm_fn8x8_identity(dct     )
+inv_txfm_fn8x8_identity(flipadst)
+inv_txfm_fn8x8_identity(adst    )
+inv_txfm_fn8x8_identity(identity)
+
+#define CLIP16_I32_8(a, b, c, d, e, f, g, h, \
+                     ab, cd, ef, gh) \
+{ \
+    ab = vec_packs(a, b); \
+    cd = vec_packs(c, d); \
+    ef = vec_packs(e, f); \
+    gh = vec_packs(g, h); \
+    UNPACK_PAIR_I16_I32(a, b, ab) \
+    UNPACK_PAIR_I16_I32(c, d, cd) \
+    UNPACK_PAIR_I16_I32(e, f, ef) \
+    UNPACK_PAIR_I16_I32(g, h, gh) \
+}
+
+#define MUL_4_INPLACE(a, b, c, d, v) \
+    a = vec_mul(a, v); \
+    b = vec_mul(b, v); \
+    c = vec_mul(c, v); \
+    d = vec_mul(d, v); \
+
+#define IDENTITY_16_V(v) \
+{ \
+    i16x8 v_ = vec_adds(v, v); \
+    v = vec_mradds(v, v1697_16, v_); \
+}
+
+#define IDENTITY_16_INNER(c00c01, c02c03, c04c05, c06c07, \
+                          c08c09, c10c11, c12c13, c14c15) \
+{ \
+    i16x8 v1697_16 = vec_splats((int16_t)(1697*16)); \
+    IDENTITY_16_V(c00c01) \
+    IDENTITY_16_V(c02c03) \
+    IDENTITY_16_V(c04c05) \
+    IDENTITY_16_V(c06c07) \
+    IDENTITY_16_V(c08c09) \
+    IDENTITY_16_V(c10c11) \
+    IDENTITY_16_V(c12c13) \
+    IDENTITY_16_V(c14c15) \
+}
+
+#define IDENTITY_16_4_I32(a, b, c, d) \
+{ \
+    i32x4 a2 = vec_add(a, a); \
+    i32x4 b2 = vec_add(b, b); \
+    i32x4 c2 = vec_add(c, c); \
+    i32x4 d2 = vec_add(d, d); \
+    MUL_4_INPLACE(a, b, c, d, v1697) \
+    SCALE_ROUND_4(a, b, c, d, v1024, vec_splat_u32(11)); \
+    a = vec_add(a2, a); \
+    b = vec_add(b2, b); \
+    c = vec_add(c2, c); \
+    d = vec_add(d2, d); \
+}
+
+
+#define identity_16_in(c00, c01, c02, c03, c04, c05, c06, c07, \
+                       c08, c09, c10, c11, c12, c13, c14, c15, \
+                       c00c01, c02c03, c04c05, c06c07, \
+                       c08c09, c10c11, c12c13, c14c15) \
+{ \
+    DECLARE_SPLAT_I32(1697) \
+    DECLARE_SPLAT_I32(1024) \
+    IDENTITY_16_4_I32(c00, c01, c02, c03) \
+    IDENTITY_16_4_I32(c04, c05, c06, c07) \
+    IDENTITY_16_4_I32(c08, c09, c10, c11) \
+    IDENTITY_16_4_I32(c12, c13, c14, c15) \
+}
+
+#define identity_16_out(c00, c01, c02, c03, c04, c05, c06, c07, \
+                        c08, c09, c10, c11, c12, c13, c14, c15, \
+                        c00c01, c02c03, c04c05, c06c07, \
+                        c08c09, c10c11, c12c13, c14c15) \
+{ \
+    PACK_8(c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15, \
+           c00, c02, c04, c06, c08, c10, c12, c14, \
+           c01, c03, c05, c07, c09, c11, c13, c15)  \
+    IDENTITY_16_INNER(c00c01, c02c03, c04c05, c06c07, \
+                      c08c09, c10c11, c12c13, c14c15) \
+}
+
+#define IDCT_16_INNER(c00, c01, c02, c03, c04, c05, c06, c07, \
+                      c08, c09, c10, c11, c12, c13, c14, c15, \
+                      c00c03, c01c02, c07c04, c06c05, \
+                      c08c11, c09c10, c14c13, c15c12) \
+    IDCT_8_INNER(c00, c02, c04, c06, c08, c10, c12, c14, \
+                 c00c03, c01c02, c07c04, c06c05) \
+    DECLARE_SPLAT_I32(128) \
+    DECLARE_SPLAT_I32(181) \
+    DECLARE_SPLAT_I32(401) \
+    DECLARE_SPLAT_I32(4076) \
+    DECLARE_SPLAT_I32(3166) \
+    DECLARE_SPLAT_I32(2598) \
+    DECLARE_SPLAT_I32(1931) \
+    DECLARE_SPLAT_I32(3612) \
+    DECLARE_SPLAT_I32(3920) \
+    DECLARE_SPLAT_I32(1189) \
+    DECLARE_SPLAT_I32(1567) \
+    DECLARE_SPLAT_I32(3784) \
+\
+    DECLARE_MUL_PAIR_I32(c01, c15,  v401, v4076) \
+    DECLARE_MUL_PAIR_I32(c09, c07, v3166, v2598) \
+    DECLARE_MUL_PAIR_I32(c05, c11, v1931, v3612) \
+    DECLARE_MUL_PAIR_I32(c13, c03, v3920, v1189) \
+\
+    DECLARE_ADD_SUB_PAIR(t15a, t08a, c01, c15, v4076,  v401) \
+    DECLARE_ADD_SUB_PAIR(t14a, t09a, c09, c07, v2598, v3166) \
+    DECLARE_ADD_SUB_PAIR(t13a, t10a, c05, c11, v3612, v1931) \
+    DECLARE_ADD_SUB_PAIR(t12a, t11a, c13, c03, v1189, v3920) \
+\
+    SCALE_ROUND_4(t15a, t08a, t14a, t09a, v2048, v12) \
+    SCALE_ROUND_4(t13a, t10a, t12a, t11a, v2048, v12) \
+\
+    CLIP16_I32_8(t15a, t08a, t14a, t09a, \
+                 t13a, t10a, t12a, t11a, \
+                 c08c11, c09c10, c14c13, c15c12) \
+    DECLARE_ADD_SUB_PAIR(t08, t09, t08a, t09a,,) \
+    DECLARE_ADD_SUB_PAIR(t11, t10, t11a, t10a,,) \
+    DECLARE_ADD_SUB_PAIR(t12, t13, t12a, t13a,,) \
+    DECLARE_ADD_SUB_PAIR(t15, t14, t15a, t14a,,) \
+\
+    CLIP16_I32_8(t08, t09, t11, t10, \
+                 t12, t13, t15, t14, \
+                 c08c11, c09c10, c14c13, c15c12) \
+\
+    DECLARE_MUL_PAIR_I32(t14, t09, v1567, v3784) \
+    DECLARE_MUL_PAIR_I32(t13, t10, v1567, v3784) \
+    \
+    ADD_SUB_PAIR(t14a, t09a, t14, t09, v3784, v1567) \
+    ADD_SUB_PAIR(t10a, t13a, t13, t10, v3784, v1567) \
+    t10a = -t10a; \
+\
+    SCALE_ROUND_4(t14a, t09a, t13a, t10a, v2048, v12) \
+\
+    ADD_SUB_PAIR(t08a, t11a, t08, t11,,) \
+    ADD_SUB_PAIR(t09, t10, t09a, t10a,,) \
+    ADD_SUB_PAIR(t15a, t12a, t15, t12,,) \
+    ADD_SUB_PAIR(t14, t13, t14a, t13a,,) \
+\
+    CLIP16_I32_8(t08a, t11a, t09, t10, \
+                 t15a, t12a, t14, t13, \
+                 c08c11, c09c10, c14c13, c15c12) \
+    ADD_SUB_PAIR(t13a, t10a, t13, t10,,); \
+    ADD_SUB_PAIR(t12, t11, t12a, t11a,,); \
+\
+    MUL_4_INPLACE(t13a, t10a, t12, t11, v181); \
+    SCALE_ROUND_4(t13a, t10a, t12, t11, v128, vec_splat_u32(8)) \
+\
+    DECLARE_PACK_4(t15at12, t14t13a, t08at11, t09t10a, \
+                   t15a, t14, t08a, t09, \
+                   t12, t13a, t11,  t10a) \
+\
+    c15c12 = vec_subs(c00c03, t15at12); \
+    c14c13 = vec_subs(c01c02, t14t13a); \
+    c08c11 = vec_subs(c07c04, t08at11); \
+    c09c10 = vec_subs(c06c05, t09t10a); \
+    c00c03 = vec_adds(c00c03, t15at12); \
+    c01c02 = vec_adds(c01c02, t14t13a); \
+    c07c04 = vec_adds(c07c04, t08at11); \
+    c06c05 = vec_adds(c06c05, t09t10a); \
+
+#define dct_16_out(c00, c01, c02, c03, c04, c05, c06, c07, \
+                   c08, c09, c10, c11, c12, c13, c14, c15, \
+                   c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15) \
+\
+    i16x8 c00c03, c01c02, c07c04, c06c05, c08c11, c09c10, c14c13, c15c12; \
+    IDCT_16_INNER(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00c03, c01c02, c07c04, c06c05, c08c11, c09c10, c14c13, c15c12) \
+    c00c01 = (i16x8)vec_mergeh((u64x2)c00c03, (u64x2)c01c02); \
+    c02c03 = (i16x8)vec_mergel((u64x2)c01c02, (u64x2)c00c03); \
+    c04c05 = (i16x8)vec_mergel((u64x2)c07c04, (u64x2)c06c05); \
+    c06c07 = (i16x8)vec_mergeh((u64x2)c06c05, (u64x2)c07c04); \
+    c08c09 = (i16x8)vec_mergeh((u64x2)c08c11, (u64x2)c09c10); \
+    c10c11 = (i16x8)vec_mergel((u64x2)c09c10, (u64x2)c08c11); \
+    c12c13 = (i16x8)vec_mergel((u64x2)c15c12, (u64x2)c14c13); \
+    c14c15 = (i16x8)vec_mergeh((u64x2)c14c13, (u64x2)c15c12); \
+
+#define dct_16_in(c00, c01, c02, c03, c04, c05, c06, c07, \
+                  c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00c03, c01c02, c07c04, c06c05, c08c11, c09c10, c14c13, c15c12) \
+\
+    IDCT_16_INNER(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00c03, c01c02, c07c04, c06c05, c08c11, c09c10, c14c13, c15c12) \
+    UNPACK_PAIR_I16_I32(c00, c03, c00c03) \
+    UNPACK_PAIR_I16_I32(c01, c02, c01c02) \
+    UNPACK_PAIR_I16_I32(c07, c04, c07c04) \
+    UNPACK_PAIR_I16_I32(c06, c05, c06c05) \
+    UNPACK_PAIR_I16_I32(c08, c11, c08c11) \
+    UNPACK_PAIR_I16_I32(c09, c10, c09c10) \
+    UNPACK_PAIR_I16_I32(c14, c13, c14c13) \
+    UNPACK_PAIR_I16_I32(c15, c12, c15c12) \
+
+
+#define dct_4x4_in(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3, \
+                   cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3, \
+                   a0b0, c0d0, a1b1, c1d1, a2b2, c2d2, a3b3, c3d3) \
+    dct_4_in(cA0, cA1, cA2, cA3, a0b0, c0d0) \
+    dct_4_in(cB0, cB1, cB2, cB3, a1b1, c1d1) \
+    dct_4_in(cC0, cC1, cC2, cC3, a2b2, c2d2) \
+    dct_4_in(cD0, cD1, cD2, cD3, a3b3, c3d3)
+
+
+#define PACK_4x4(c00, c01, c02, c03, \
+                 c04, c05, c06, c07, \
+                 c08, c09, c10, c11, \
+                 c12, c13, c14, c15, \
+                 c00c01, c02c03, c04c05, c06c07, \
+                 c08c09, c10c11, c12c13, c14c15) \
+{ \
+    c00c01 = vec_packs(c00, c04); c02c03 = vec_packs(c08, c12); \
+    c04c05 = vec_packs(c01, c05); c06c07 = vec_packs(c09, c13); \
+    c08c09 = vec_packs(c02, c06); c10c11 = vec_packs(c10, c14); \
+    c12c13 = vec_packs(c03, c07); c14c15 = vec_packs(c11, c15); \
+}
+
+
+
+#define dct_4x4_out(c00, c01, c02, c03, \
+                    c04, c05, c06, c07, \
+                    c08, c09, c10, c11, \
+                    c12, c13, c14, c15, \
+                    c00c01, c02c03, c04c05, c06c07, \
+                    c08c09, c10c11, c12c13, c14c15) \
+{ \
+    IDCT_4_INNER(c00, c01, c02, c03) \
+    IDCT_4_INNER(c04, c05, c06, c07) \
+    IDCT_4_INNER(c08, c09, c10, c11) \
+    IDCT_4_INNER(c12, c13, c14, c15) \
+\
+    PACK_4x4(c00, c01, c02, c03, \
+             c04, c05, c06, c07, \
+             c08, c09, c10, c11, \
+             c12, c13, c14, c15, \
+             c00c01, c02c03, c04c05, c06c07, \
+             c08c09, c10c11, c12c13, c14c15) \
+}
+
+#define IDENTITY_4_I32(a, b, c, d) \
+{ \
+    DECLARE_SPLAT_I32(5793) \
+    DECLARE_SPLAT_I32(2048) \
+    MUL_4_INPLACE(a, b, c, d, v5793) \
+    SCALE_ROUND_4(a, b, c, d, v2048, vec_splat_u32(12)) \
+}
+
+#define identity_4x4_in(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3, \
+                       cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3, \
+                       a0b0, c0d0, a1b1, c1d1, a2b2, c2d2, a3b3, c3d3) \
+{ \
+    IDENTITY_4_I32(cA0, cA1, cA2, cA3) \
+    IDENTITY_4_I32(cB0, cB1, cB2, cB3) \
+    IDENTITY_4_I32(cC0, cC1, cC2, cC3) \
+    IDENTITY_4_I32(cD0, cD1, cD2, cD3) \
+}
+
+#define identity_4x4_out(c00, c01, c02, c03, \
+                         c04, c05, c06, c07, \
+                         c08, c09, c10, c11, \
+                         c12, c13, c14, c15, \
+                         c00c01, c02c03, c04c05, c06c07, \
+                         c08c09, c10c11, c12c13, c14c15) \
+{ \
+    PACK_4x4(c00, c01, c02, c03, \
+             c04, c05, c06, c07, \
+             c08, c09, c10, c11, \
+             c12, c13, c14, c15, \
+             c00c01, c02c03, c04c05, c06c07, \
+             c08c09, c10c11, c12c13, c14c15) \
+    IDENTITY_4(c00c01, c02c03) \
+    IDENTITY_4(c04c05, c06c07) \
+    IDENTITY_4(c08c09, c10c11) \
+    IDENTITY_4(c12c13, c14c15) \
+}
+
+#define adst_4x4_in(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3, \
+                    cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3, \
+                    a0b0, c0d0, a1b1, c1d1, a2b2, c2d2, a3b3, c3d3) \
+    adst_4_in(cA0, cA1, cA2, cA3, a0b0, c0d0) \
+    adst_4_in(cB0, cB1, cB2, cB3, a1b1, c1d1) \
+    adst_4_in(cC0, cC1, cC2, cC3, a2b2, c2d2) \
+    adst_4_in(cD0, cD1, cD2, cD3, a3b3, c3d3)
+
+#define adst_4x4_out(c00, c01, c02, c03, \
+                     c04, c05, c06, c07, \
+                     c08, c09, c10, c11, \
+                     c12, c13, c14, c15, \
+                     c00c01, c02c03, c04c05, c06c07, \
+                     c08c09, c10c11, c12c13, c14c15) \
+{ \
+    ADST_INNER_4(c00, c01, c02, c03, c00, c01, c02, c03) \
+    ADST_INNER_4(c04, c05, c06, c07, c04, c05, c06, c07) \
+    ADST_INNER_4(c08, c09, c10, c11, c08, c09, c10, c11) \
+    ADST_INNER_4(c12, c13, c14, c15, c12, c13, c14, c15) \
+\
+    PACK_4x4(c00, c01, c02, c03, \
+             c04, c05, c06, c07, \
+             c08, c09, c10, c11, \
+             c12, c13, c14, c15, \
+             c00c01, c02c03, c04c05, c06c07, \
+             c08c09, c10c11, c12c13, c14c15) \
+}
+
+#define flipadst_4x4_in(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3, \
+                        cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3, \
+                        a0b0, c0d0, a1b1, c1d1, a2b2, c2d2, a3b3, c3d3) \
+    flipadst_4_in(cA0, cA1, cA2, cA3, a0b0, c0d0) \
+    flipadst_4_in(cB0, cB1, cB2, cB3, a1b1, c1d1) \
+    flipadst_4_in(cC0, cC1, cC2, cC3, a2b2, c2d2) \
+    flipadst_4_in(cD0, cD1, cD2, cD3, a3b3, c3d3)
+
+#define flipadst_4x4_out(c00, c01, c02, c03, \
+                         c04, c05, c06, c07, \
+                         c08, c09, c10, c11, \
+                         c12, c13, c14, c15, \
+                         c00c01, c02c03, c04c05, c06c07, \
+                         c08c09, c10c11, c12c13, c14c15) \
+{ \
+    ADST_INNER_4(c00, c01, c02, c03, c03, c02, c01, c00) \
+    ADST_INNER_4(c04, c05, c06, c07, c07, c06, c05, c04) \
+    ADST_INNER_4(c08, c09, c10, c11, c11, c10, c09, c08) \
+    ADST_INNER_4(c12, c13, c14, c15, c15, c14, c13, c12) \
+\
+    PACK_4x4(c00, c01, c02, c03, \
+             c04, c05, c06, c07, \
+             c08, c09, c10, c11, \
+             c12, c13, c14, c15, \
+             c00c01, c02c03, c04c05, c06c07, \
+             c08c09, c10c11, c12c13, c14c15) \
+}
+
+#define ADST_INNER_16(c00, c01, c02, c03, c04, c05, c06, c07, \
+                      c08, c09, c10, c11, c12, c13, c14, c15, \
+                      o00, o01, o02, o03, o04, o05, o06, o07, \
+                      o08, o09, o10, o11, o12, o13, o14, o15, \
+                      c00c01, c02c03, c04c05, c06c07) \
+    DECLARE_SPLAT_I32(2048); \
+    u32x4 v12 = vec_splat_u32(12); \
+    DECLARE_SPLAT_I32(4091) \
+    DECLARE_SPLAT_I32(201) \
+    DECLARE_SPLAT_I32(3973) \
+    DECLARE_SPLAT_I32(995) \
+    DECLARE_SPLAT_I32(3703) \
+    DECLARE_SPLAT_I32(1751) \
+    DECLARE_SPLAT_I32(3290) \
+    DECLARE_SPLAT_I32(2440) \
+    DECLARE_SPLAT_I32(2751) \
+    DECLARE_SPLAT_I32(3035) \
+    DECLARE_SPLAT_I32(2106) \
+    DECLARE_SPLAT_I32(3513) \
+    DECLARE_SPLAT_I32(1380) \
+    DECLARE_SPLAT_I32(3857) \
+    DECLARE_SPLAT_I32(601) \
+    DECLARE_SPLAT_I32(4052) \
+\
+    DECLARE_MUL_PAIR_I32(c15, c00, v4091, v201) \
+    DECLARE_MUL_PAIR_I32(c13, c02, v3973, v995) \
+    DECLARE_MUL_PAIR_I32(c11, c04, v3703, v1751) \
+    DECLARE_MUL_PAIR_I32(c09, c06, v3290, v2440) \
+    DECLARE_MUL_PAIR_I32(c07, c08, v2751, v3035) \
+    DECLARE_MUL_PAIR_I32(c05, c10, v2106, v3513) \
+    DECLARE_MUL_PAIR_I32(c03, c12, v1380, v3857) \
+    DECLARE_MUL_PAIR_I32(c01, c14,  v601, v4052) \
+\
+    DECLARE_ADD_SUB_PAIR(t00, t01, c15, c00, v4091, v201);\
+    DECLARE_ADD_SUB_PAIR(t02, t03, c13, c02, v3973, v995) \
+    DECLARE_ADD_SUB_PAIR(t04, t05, c11, c04, v3703, v1751) \
+    DECLARE_ADD_SUB_PAIR(t06, t07, c09, c06, v3290, v2440) \
+    DECLARE_ADD_SUB_PAIR(t08, t09, c07, c08, v2751, v3035) \
+    DECLARE_ADD_SUB_PAIR(t10, t11, c05, c10, v2106, v3513) \
+    DECLARE_ADD_SUB_PAIR(t12, t13, c03, c12, v1380, v3857) \
+    DECLARE_ADD_SUB_PAIR(t14, t15, c01, c14,  v601, v4052) \
+\
+    SCALE_ROUND_4(t00, t01, t02, t03, v2048, v12) \
+    SCALE_ROUND_4(t04, t05, t06, t07, v2048, v12) \
+    SCALE_ROUND_4(t08, t09, t10, t11, v2048, v12) \
+    SCALE_ROUND_4(t12, t13, t14, t15, v2048, v12) \
+\
+    DECLARE_ADD_SUB_PAIR(t00a, t08a, t00, t08,,) \
+    DECLARE_ADD_SUB_PAIR(t01a, t09a, t01, t09,,) \
+    DECLARE_ADD_SUB_PAIR(t02a, t10a, t02, t10,,) \
+    DECLARE_ADD_SUB_PAIR(t03a, t11a, t03, t11,,) \
+    DECLARE_ADD_SUB_PAIR(t04a, t12a, t04, t12,,) \
+    DECLARE_ADD_SUB_PAIR(t05a, t13a, t05, t13,,) \
+    DECLARE_ADD_SUB_PAIR(t06a, t14a, t06, t14,,) \
+    DECLARE_ADD_SUB_PAIR(t07a, t15a, t07, t15,,) \
+\
+    CLIP16_I32_8(t00a, t08a, t01a, t09a, t02a, t10a, t03a, t11a, \
+                 c00c01, c02c03, c04c05, c06c07); \
+    CLIP16_I32_8(t04a, t12a, t05a, t13a, t06a, t14a, t07a, t15a, \
+                 c00c01, c02c03, c04c05, c06c07); \
+\
+    DECLARE_SPLAT_I32(4017) \
+    DECLARE_SPLAT_I32(799) \
+    DECLARE_SPLAT_I32(2276) \
+    DECLARE_SPLAT_I32(3406) \
+\
+    DECLARE_MUL_PAIR_I32(t08a, t09a, v4017,  v799); \
+    DECLARE_MUL_PAIR_I32(t10a, t11a, v2276, v3406); \
+    DECLARE_MUL_PAIR_I32(t13a, t12a,  v799, v4017); \
+    DECLARE_MUL_PAIR_I32(t15a, t14a, v3406, v2276); \
+\
+    ADD_SUB_PAIR(t08, t09, t08a, t09a, v4017,  v799); \
+    ADD_SUB_PAIR(t10, t11, t10a, t11a, v2276, v3406); \
+    ADD_SUB_PAIR(t13, t12, t13a, t12a,  v799, v4017); \
+    ADD_SUB_PAIR(t15, t14, t15a, t14a, v3406, v2276); \
+\
+    SCALE_ROUND_4(t08, t09, t10, t11, v2048, v12) \
+    SCALE_ROUND_4(t13, t12, t15, t14, v2048, v12) \
+\
+    ADD_SUB_PAIR(t00, t04, t00a, t04a,,); \
+    ADD_SUB_PAIR(t01, t05, t01a, t05a,,); \
+    ADD_SUB_PAIR(t02, t06, t02a, t06a,,); \
+    ADD_SUB_PAIR(t03, t07, t03a, t07a,,); \
+    ADD_SUB_PAIR(t08a, t12a, t08, t12,,); \
+    ADD_SUB_PAIR(t09a, t13a, t09, t13,,); \
+    ADD_SUB_PAIR(t10a, t14a, t10, t14,,); \
+    ADD_SUB_PAIR(t11a, t15a, t11, t15,,); \
+\
+    CLIP16_I32_8(t00, t04, t01, t05, t02, t06, t03, t07, \
+                 c00c01, c02c03, c04c05, c06c07) \
+    CLIP16_I32_8(t08a, t12a, t09a, t13a, t10a, t14a, t11a, t15a, \
+                 c00c01, c02c03, c04c05, c06c07) \
+\
+    DECLARE_SPLAT_I32(3784) \
+    DECLARE_SPLAT_I32(1567) \
+\
+    DECLARE_MUL_PAIR_I32(t04, t05, v3784, v1567) \
+    DECLARE_MUL_PAIR_I32(t07, t06, v1567, v3784) \
+    DECLARE_MUL_PAIR_I32(t12a, t13a, v3784, v1567) \
+    DECLARE_MUL_PAIR_I32(t15a, t14a, v1567, v3784) \
+\
+    ADD_SUB_PAIR(t04a, t05a, t04, t05, v3784, v1567) \
+    ADD_SUB_PAIR(t07a, t06a, t07, t06, v1567, v3784) \
+    ADD_SUB_PAIR(t12, t13, t12a, t13a, v3784, v1567) \
+    ADD_SUB_PAIR(t15, t14, t15a, t14a, v1567, v3784) \
+\
+    SCALE_ROUND_4(t04a, t05a, t07a, t06a, v2048, v12) \
+    SCALE_ROUND_4(t12, t13, t15, t14, v2048, v12) \
+\
+    ADD_SUB_PAIR(o00, t02a, t00,  t02,,) \
+    ADD_SUB_PAIR(o15, t03a, t01,  t03,,) \
+    ADD_SUB_PAIR(o03, t06,  t04a, t06a,,) \
+    ADD_SUB_PAIR(o12, t07,  t05a, t07a,,) \
+    ADD_SUB_PAIR(o01, t10,  t08a, t10a,,) \
+    ADD_SUB_PAIR(o14, t11,  t09a, t11a,,) \
+    ADD_SUB_PAIR(o02, t14a, t12,  t14,,) \
+    ADD_SUB_PAIR(o13, t15a, t13,  t15,,) \
+\
+    CLIP16_I32_8(o00, t02a, o15, t03a, o03, t06, o12, t07, \
+                 c00c01, c02c03, c04c05, c06c07) \
+    CLIP16_I32_8(o01, t10, o14, t11, o02, t14a, o13, t15a, \
+                 c00c01, c02c03, c04c05, c06c07) \
+\
+    DECLARE_SPLAT_I32(181) \
+    DECLARE_SPLAT_I32(128) \
+    u32x4 v8 = vec_splat_u32(8); \
+\
+    ADD_SUB_PAIR(o07, o08, t02a, t03a,,) \
+    ADD_SUB_PAIR(o04, o11, t06,  t07,,) \
+    ADD_SUB_PAIR(o06, o09, t10,  t11,,) \
+    ADD_SUB_PAIR(o05, o10, t14a, t15a,,) \
+\
+    MUL_4_INPLACE(o07, o08, o04, o11, v181) \
+    MUL_4_INPLACE(o06, o09, o05, o10, v181) \
+\
+    SCALE_ROUND_4(o07, o08, o04, o11, v128, v8) \
+    SCALE_ROUND_4(o06, o09, o05, o10, v128, v8) \
+\
+    o01 = -o01; \
+    o03 = -o03; \
+    o05 = -o05; \
+    o07 = -o07; \
+    o09 = -o09; \
+    o11 = -o11; \
+    o13 = -o13; \
+    o15 = -o15; \
+
+#define adst_16_in(c00, c01, c02, c03, c04, c05, c06, c07, \
+                   c08, c09, c10, c11, c12, c13, c14, c15, \
+                   c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15) \
+{ \
+    ADST_INNER_16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00c01, c02c03, c04c05, c06c07) \
+}
+
+#define adst_16_out(c00, c01, c02, c03, c04, c05, c06, c07, \
+                    c08, c09, c10, c11, c12, c13, c14, c15, \
+                    c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15) \
+{ \
+    ADST_INNER_16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00c01, c02c03, c04c05, c06c07) \
+    PACK_8(c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15, \
+           c00, c02, c04, c06, c08, c10, c12, c14, \
+           c01, c03, c05, c07, c09, c11, c13, c15) \
+}
+
+#define flipadst_16_in(c00, c01, c02, c03, c04, c05, c06, c07, \
+                       c08, c09, c10, c11, c12, c13, c14, c15, \
+                       c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15) \
+{ \
+    ADST_INNER_16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c15, c14, c13, c12, c11, c10, c09, c08, c07, c06, c05, c04, c03, c02, c01, c00, \
+                  c00c01, c02c03, c04c05, c06c07) \
+}
+
+#define flipadst_16_out(c00, c01, c02, c03, c04, c05, c06, c07, \
+                        c08, c09, c10, c11, c12, c13, c14, c15, \
+                        c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15) \
+{ \
+    ADST_INNER_16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c15, c14, c13, c12, c11, c10, c09, c08, c07, c06, c05, c04, c03, c02, c01, c00, \
+                  c00c01, c02c03, c04c05, c06c07) \
+    PACK_8(c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15, \
+           c00, c02, c04, c06, c08, c10, c12, c14, \
+           c01, c03, c05, c07, c09, c11, c13, c15) \
+}
+
+
+void dav1d_inv_txfm_add_dct_dct_4x16_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride,
+                                               int16_t *const coeff, const int eob
+                                               HIGHBD_DECL_SUFFIX)
+{
+    if (eob < 1) {
+        return dc_only_4xN(dst, stride, coeff, 4, 0, 1);
+    }
+
+    LOAD_COEFF_4x16(coeff)
+
+    dct_4x4_in(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3,
+               cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3,
+               a0b0, c0d0, a1b1, c1d1, a2b2, c2d2, a3b3, c3d3)
+
+    memset(coeff, 0, sizeof(*coeff) * 4 * 16);
+
+    SCALE_ROUND_4(cA0, cB0, cC0, cD0, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(cA1, cB1, cC1, cD1, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(cA2, cB2, cC2, cD2, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(cA3, cB3, cC3, cD3, vec_splat_s32(1), vec_splat_u32(1))
+    TRANSPOSE4x16_I32(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3,
+                      cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3)
+
+    dct_16_out(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3,
+               cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3,
+               a0b0, c0d0, a1b1, c1d1, a2b2, c2d2, a3b3, c3d3)
+
+    LOAD_DECLARE_4(dst, stride, l00, l01, l02, l03)
+    LOAD_DECLARE_4(dst + 4 * stride, stride, l04, l05, l06, l07)
+    LOAD_DECLARE_4(dst + 8 * stride, stride, l08, l09, l10, l11)
+    LOAD_DECLARE_4(dst + 12 * stride, stride, l12, l13, l14, l15)
+
+    APPLY_COEFF_4(l00, l01, l02, l03, a0b0, c0d0);
+    APPLY_COEFF_4(l04, l05, l06, l07, a1b1, c1d1);
+    APPLY_COEFF_4(l08, l09, l10, l11, a2b2, c2d2);
+    APPLY_COEFF_4(l12, l13, l14, l15, a3b3, c3d3);
+
+    STORE_4(dst, stride,               l00, l01, l02, l03);
+    STORE_4(dst + 4 * stride, stride,  l04, l05, l06, l07);
+    STORE_4(dst + 8 * stride, stride,  l08, l09, l10, l11);
+    STORE_4(dst + 12 * stride, stride, l12, l13, l14, l15);
+}
+
+#define inv_txfm_fn4x16(type1, type2) \
+void dav1d_inv_txfm_add_##type1##_##type2##_4x16_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride, \
+                                                          int16_t *const coeff, const int eob) \
+{ \
+    LOAD_COEFF_4x16(coeff) \
+    type1##_4x4_in(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3, \
+                   cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3, \
+                   a0b0, c0d0, a1b1, c1d1, a2b2, c2d2, a3b3, c3d3) \
+    memset(coeff, 0, sizeof(*coeff) * 4 * 16); \
+    SCALE_ROUND_4(cA0, cB0, cC0, cD0, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(cA1, cB1, cC1, cD1, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(cA2, cB2, cC2, cD2, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(cA3, cB3, cC3, cD3, vec_splat_s32(1), vec_splat_u32(1)) \
+    TRANSPOSE4x16_I32(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3, \
+                      cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3) \
+    type2##_16_out(cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3, \
+                   cC0, cC1, cC2, cC3, cD0, cD1, cD2, cD3, \
+                   a0b0, c0d0, a1b1, c1d1, a2b2, c2d2, a3b3, c3d3) \
+    LOAD_DECLARE_4(dst, stride, l00, l01, l02, l03) \
+    LOAD_DECLARE_4(dst + 4 * stride, stride, l04, l05, l06, l07) \
+    LOAD_DECLARE_4(dst + 8 * stride, stride, l08, l09, l10, l11) \
+    LOAD_DECLARE_4(dst + 12 * stride, stride, l12, l13, l14, l15) \
+    APPLY_COEFF_4(l00, l01, l02, l03, a0b0, c0d0); \
+    APPLY_COEFF_4(l04, l05, l06, l07, a1b1, c1d1); \
+    APPLY_COEFF_4(l08, l09, l10, l11, a2b2, c2d2); \
+    APPLY_COEFF_4(l12, l13, l14, l15, a3b3, c3d3); \
+    STORE_4(dst, stride,               l00, l01, l02, l03); \
+    STORE_4(dst + 4 * stride, stride,  l04, l05, l06, l07); \
+    STORE_4(dst + 8 * stride, stride,  l08, l09, l10, l11); \
+    STORE_4(dst + 12 * stride, stride, l12, l13, l14, l15); \
+}
+inv_txfm_fn4x16(adst,     dct     )
+inv_txfm_fn4x16(dct,      adst    )
+inv_txfm_fn4x16(dct,      flipadst)
+inv_txfm_fn4x16(flipadst, dct     )
+inv_txfm_fn4x16(adst,     flipadst)
+inv_txfm_fn4x16(flipadst, adst    )
+inv_txfm_fn4x16(identity, dct     )
+inv_txfm_fn4x16(dct,      identity)
+inv_txfm_fn4x16(identity, flipadst)
+inv_txfm_fn4x16(flipadst, identity)
+inv_txfm_fn4x16(identity, adst   )
+inv_txfm_fn4x16(adst,     identity)
+inv_txfm_fn4x16(identity, identity)
+inv_txfm_fn4x16(adst,     adst    )
+inv_txfm_fn4x16(flipadst, flipadst)
+
+void dav1d_inv_txfm_add_dct_dct_16x4_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride,
+                                               int16_t *const coeff, const int eob)
+{
+
+    if (eob < 1) {
+        return dc_only_16xN(dst, stride, coeff, 1, 0, 1);
+    }
+
+    LOAD_DECLARE_2_I16(coeff, c00c01, c02c03) \
+    LOAD_DECLARE_2_I16(coeff+16, c04c05, c06c07) \
+    LOAD_DECLARE_2_I16(coeff+32, c08c09, c10c11) \
+    LOAD_DECLARE_2_I16(coeff+48, c12c13, c14c15) \
+    UNPACK_DECLARE_4_I16_I32(c00c01, c02c03, c00, c01, c02, c03)
+    UNPACK_DECLARE_4_I16_I32(c04c05, c06c07, c04, c05, c06, c07)
+    UNPACK_DECLARE_4_I16_I32(c08c09, c10c11, c08, c09, c10, c11)
+    UNPACK_DECLARE_4_I16_I32(c12c13, c14c15, c12, c13, c14, c15)
+
+    dct_16_in(c00, c01, c02, c03, c04, c05, c06, c07,
+              c08, c09, c10, c11, c12, c13, c14, c15,
+              c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15)
+    memset(coeff, 0, sizeof(*coeff) * 16 * 4);
+    SCALE_ROUND_4(c00, c01, c02, c03, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(c04, c05, c06, c07, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(c08, c09, c10, c11, vec_splat_s32(1), vec_splat_u32(1))
+    SCALE_ROUND_4(c12, c13, c14, c15, vec_splat_s32(1), vec_splat_u32(1))
+
+    TRANSPOSE4_I32(c00, c01, c02, c03);
+    TRANSPOSE4_I32(c04, c05, c06, c07);
+    TRANSPOSE4_I32(c08, c09, c10, c11);
+    TRANSPOSE4_I32(c12, c13, c14, c15);
+
+    dct_4x4_out(c00, c01, c02, c03,
+                c04, c05, c06, c07,
+                c08, c09, c10, c11,
+                c12, c13, c14, c15,
+                c00c01, c02c03, c04c05, c06c07,
+                c08c09, c10c11, c12c13, c14c15)
+
+    LOAD_DECLARE_4(dst, stride, l0, l1, l2, l3)
+
+    APPLY_COEFF_16x4(l0, l1, l2, l3,
+                     c00c01, c02c03, c04c05, c06c07,
+                     c08c09, c10c11, c12c13, c14c15)
+
+    STORE_16(dst, stride, l0, l1, l2, l3)
+}
+
+#define inv_txfm_fn16x4(type1, type2) \
+void dav1d_inv_txfm_add_##type1##_##type2##_16x4_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride, \
+                                                          int16_t *const coeff, const int eob) \
+{ \
+    LOAD_DECLARE_2_I16(coeff, c00c01, c02c03) \
+    LOAD_DECLARE_2_I16(coeff+16, c04c05, c06c07) \
+    LOAD_DECLARE_2_I16(coeff+32, c08c09, c10c11) \
+    LOAD_DECLARE_2_I16(coeff+48, c12c13, c14c15) \
+    UNPACK_DECLARE_4_I16_I32(c00c01, c02c03, c00, c01, c02, c03) \
+    UNPACK_DECLARE_4_I16_I32(c04c05, c06c07, c04, c05, c06, c07) \
+    UNPACK_DECLARE_4_I16_I32(c08c09, c10c11, c08, c09, c10, c11) \
+    UNPACK_DECLARE_4_I16_I32(c12c13, c14c15, c12, c13, c14, c15) \
+    type1##_16_in(c00, c01, c02, c03, c04, c05, c06, c07, \
+                  c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15) \
+    memset(coeff, 0, sizeof(*coeff) * 16 * 4); \
+    SCALE_ROUND_4(c00, c01, c02, c03, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c04, c05, c06, c07, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c08, c09, c10, c11, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c12, c13, c14, c15, vec_splat_s32(1), vec_splat_u32(1)) \
+    TRANSPOSE4_I32(c00, c01, c02, c03); \
+    TRANSPOSE4_I32(c04, c05, c06, c07); \
+    TRANSPOSE4_I32(c08, c09, c10, c11); \
+    TRANSPOSE4_I32(c12, c13, c14, c15); \
+    type2##_4x4_out(c00, c01, c02, c03, \
+                    c04, c05, c06, c07, \
+                    c08, c09, c10, c11, \
+                    c12, c13, c14, c15, \
+                    c00c01, c02c03, c04c05, c06c07, \
+                    c08c09, c10c11, c12c13, c14c15); \
+    LOAD_DECLARE_4(dst, stride, l0, l1, l2, l3) \
+    APPLY_COEFF_16x4(l0, l1, l2, l3, \
+                     c00c01, c02c03, c04c05, c06c07, \
+                     c08c09, c10c11, c12c13, c14c15) \
+    STORE_16(dst, stride, l0, l1, l2, l3) \
+}
+
+inv_txfm_fn16x4(adst,     dct     )
+inv_txfm_fn16x4(dct,      adst    )
+inv_txfm_fn16x4(dct,      flipadst)
+inv_txfm_fn16x4(flipadst, dct     )
+inv_txfm_fn16x4(adst,     flipadst)
+inv_txfm_fn16x4(flipadst, adst    )
+inv_txfm_fn16x4(dct,      identity)
+inv_txfm_fn16x4(flipadst, identity)
+inv_txfm_fn16x4(adst,     identity)
+inv_txfm_fn16x4(identity, identity)
+inv_txfm_fn16x4(adst,     adst    )
+inv_txfm_fn16x4(flipadst, flipadst)
+
+#define inv_txfm_fn16x4_identity(type2) \
+void dav1d_inv_txfm_add_identity_##type2##_16x4_8bpc_pwr9(uint8_t *dst, const ptrdiff_t stride, \
+                                                          int16_t *const coeff, const int eob) \
+{ \
+    LOAD_DECLARE_2_I16(coeff, c00c01, c02c03) \
+    LOAD_DECLARE_2_I16(coeff+16, c04c05, c06c07) \
+    LOAD_DECLARE_2_I16(coeff+32, c08c09, c10c11) \
+    LOAD_DECLARE_2_I16(coeff+48, c12c13, c14c15) \
+    UNPACK_DECLARE_4_I16_I32(c00c01, c02c03, c00, c01, c02, c03) \
+    UNPACK_DECLARE_4_I16_I32(c04c05, c06c07, c04, c05, c06, c07) \
+    UNPACK_DECLARE_4_I16_I32(c08c09, c10c11, c08, c09, c10, c11) \
+    UNPACK_DECLARE_4_I16_I32(c12c13, c14c15, c12, c13, c14, c15) \
+    identity_16_in(c00, c01, c02, c03, c04, c05, c06, c07, \
+                  c08, c09, c10, c11, c12, c13, c14, c15, \
+                  c00c01, c02c03, c04c05, c06c07, c08c09, c10c11, c12c13, c14c15) \
+    memset(coeff, 0, sizeof(*coeff) * 16 * 4); \
+    SCALE_ROUND_4(c00, c01, c02, c03, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c04, c05, c06, c07, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c08, c09, c10, c11, vec_splat_s32(1), vec_splat_u32(1)) \
+    SCALE_ROUND_4(c12, c13, c14, c15, vec_splat_s32(1), vec_splat_u32(1)) \
+    CLIP16_I32_8(c00, c01, c02, c03, c04, c05, c06, c07, c00c01, c02c03, c04c05, c06c07) \
+    CLIP16_I32_8(c08, c09, c10, c11, c12, c13, c14, c15, c08c09, c10c11, c12c13, c14c15) \
+    TRANSPOSE4_I32(c00, c01, c02, c03); \
+    TRANSPOSE4_I32(c04, c05, c06, c07); \
+    TRANSPOSE4_I32(c08, c09, c10, c11); \
+    TRANSPOSE4_I32(c12, c13, c14, c15); \
+    type2##_4x4_out(c00, c01, c02, c03, \
+                    c04, c05, c06, c07, \
+                    c08, c09, c10, c11, \
+                    c12, c13, c14, c15, \
+                    c00c01, c02c03, c04c05, c06c07, \
+                    c08c09, c10c11, c12c13, c14c15); \
+    LOAD_DECLARE_4(dst, stride, l0, l1, l2, l3) \
+    APPLY_COEFF_16x4(l0, l1, l2, l3, \
+                     c00c01, c02c03, c04c05, c06c07, \
+                     c08c09, c10c11, c12c13, c14c15) \
+    STORE_16(dst, stride, l0, l1, l2, l3) \
+}
+
+inv_txfm_fn16x4_identity(dct)
+inv_txfm_fn16x4_identity(adst)
+inv_txfm_fn16x4_identity(flipadst)
+
+#endif // BITDEPTH
diff --git a/media/libdav1d/src/src/ppc/loopfilter.h b/media/libdav1d/src/src/ppc/loopfilter.h
new file mode 100644
index 0000000000..fc97b375bb
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/loopfilter.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/loopfilter.h"
+
+decl_loopfilter_sb_fn(BF(dav1d_lpf_h_sb_y, pwr9));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_v_sb_y, pwr9));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_h_sb_uv, pwr9));
+decl_loopfilter_sb_fn(BF(dav1d_lpf_v_sb_uv, pwr9));
+
+static ALWAYS_INLINE void loop_filter_dsp_init_ppc(Dav1dLoopFilterDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_PPC_CPU_FLAG_PWR9)) return;
+
+#if BITDEPTH == 8
+    c->loop_filter_sb[0][0] = BF(dav1d_lpf_h_sb_y, pwr9);
+    c->loop_filter_sb[0][1] = BF(dav1d_lpf_v_sb_y, pwr9);
+    c->loop_filter_sb[1][0] = BF(dav1d_lpf_h_sb_uv, pwr9);
+    c->loop_filter_sb[1][1] = BF(dav1d_lpf_v_sb_uv, pwr9);
+#endif
+}
diff --git a/media/libdav1d/src/src/ppc/loopfilter_tmpl.c b/media/libdav1d/src/src/ppc/loopfilter_tmpl.c
new file mode 100644
index 0000000000..107192f836
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/loopfilter_tmpl.c
@@ -0,0 +1,1690 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * Copyright © 2024, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#undef NDEBUG
+#include 
+
+#include 
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "src/ppc/dav1d_types.h"
+#include "src/ppc/loopfilter.h"
+
+#if BITDEPTH == 8
+
+#define LOAD4_H(idx) \
+    u8x16 idx##0 = vec_xl(0, dst); /* p1_0 p0_0 q0_0 q1_0 */ \
+    dst += stridea; \
+    u8x16 idx##1 = vec_xl(0, dst); /* p1_1 p0_1 q0_1 q1_1 */ \
+    dst += stridea; \
+    u8x16 idx##2 = vec_xl(0, dst); /* p1_2 p0_2 q0_2 q1_2 */ \
+    dst += stridea; \
+    u8x16 idx##3 = vec_xl(0, dst); /* p1_3 p0_3 q0_3 q1_3 */ \
+
+// return idx##_01 and idx##_23
+#define LOAD4_H_SINGLE(idx) \
+    LOAD4_H(idx) \
+    \
+    u8x16 idx##_01 = vec_mergeh(idx##0, idx##1); /* p1_0 p1_1 p0_0 p0_1 q0_0 q0_1 q1_0 q1_1 */ \
+    u8x16 idx##_23 = vec_mergeh(idx##2, idx##3); /* p1_2 p1_3 p0_2 p0_3 q0_2 q0_3 q1_2 q1_3 */
+
+
+#define DECLARE_ADD_16HL(r, a, b) \
+    u16x8 r##h = vec_add(a##h, b##h); \
+    u16x8 r##l = vec_add(a##l, b##l);
+
+#define ADD_16HL(r, a, b) \
+    r##h = vec_add(a##h, b##h); \
+    r##l = vec_add(a##l, b##l);
+
+#define ADD_AND_SHIFT4(v) \
+    v##h = vec_sr(vec_add(v##h, v4u16), v3u16); \
+    v##l = vec_sr(vec_add(v##l, v4u16), v3u16);
+#define ADD_AND_SHIFT8(v) \
+    v##h = vec_sr(vec_add(v##h, v8u16), v4u16); \
+    v##l = vec_sr(vec_add(v##l, v8u16), v4u16);
+
+#define PACK_AND_SEL(v, m) \
+    vec_sel(v, vec_pack(o##v##h, o##v##l), m)
+
+#define UNPACK_16(v) \
+    u16x8 v##h = u8h_to_u16(v); \
+    u16x8 v##l = u8l_to_u16(v);
+
+
+#define APPLY_4 \
+    b8x16 hev = vec_cmpgt(max_a_p1p0_q1q0, H); \
+ \
+    i8x16 ps1 = (i8x16)vec_xor(p1, s); \
+    i8x16 ps0 = (i8x16)vec_xor(p0, s); \
+    i8x16 qs0 = (i8x16)vec_xor(q0, s); \
+    i8x16 qs1 = (i8x16)vec_xor(q1, s); \
+    i8x16 f0 = vec_and(vec_subs(ps1, qs1), hev); \
+    i16x8 q0sh = (i16x8)q0h; \
+    i16x8 q0sl = (i16x8)q0l; \
+    i16x8 p0sh = (i16x8)p0h; \
+    i16x8 p0sl = (i16x8)p0l; \
+    i16x8 f0h = i8h_to_i16(f0); \
+    i16x8 f0l = i8l_to_i16(f0); \
+    i16x8 d0h = vec_sub(q0sh, p0sh); \
+    i16x8 d0l = vec_sub(q0sl, p0sl); \
+    u8x16 v3u8 = vec_splat_u8(3); \
+    i16x8 d0h_2 = vec_add(d0h, d0h); \
+    i16x8 d0l_2 = vec_add(d0l, d0l); \
+    u8x16 v4u8 = vec_splat_u8(4); \
+    i16x8 f0_d0h = vec_add(d0h, f0h); \
+    i16x8 f0_d0l = vec_add(d0l, f0l); \
+    i16x8 fh = vec_add(d0h_2, f0_d0h); \
+    i16x8 fl = vec_add(d0l_2, f0_d0l); \
+    i8x16 f = vec_packs(fh, fl); \
+    i8x16 f1 = vec_adds(f, (i8x16)v4u8); \
+    i8x16 f2 = vec_adds(f, (i8x16)v3u8); \
+    f1 = vec_sra(f1, v3u8); \
+    f2 = vec_sra(f2, v3u8); \
+    f1 = vec_and(f1, fm); \
+    f2 = vec_and(f2, fm); \
+    i8x16 f3 = vec_adds(f1, (i8x16)v1u8); \
+    b8x16 m3 = vec_and(~hev, (b8x16)fm); \
+    f3 = vec_sra(f3, v1u8); \
+    f3 = vec_and(f3, m3); \
+    i8x16 op0s = vec_adds(ps0, f2); \
+    i8x16 oq0s = vec_subs(qs0, f1); \
+    i8x16 oq1s = vec_subs(qs1, f3); \
+    i8x16 op1s = vec_adds(ps1, f3); \
+    p0 = (u8x16)vec_xor(op0s, s); \
+    q0 = (u8x16)vec_xor(oq0s, s); \
+    q1 = (u8x16)vec_xor(oq1s, s); \
+    p1 = (u8x16)vec_xor(op1s, s);
+
+#define APPLY_8 \
+    DECLARE_ADD_16HL(p1p0, p1, p0) \
+    DECLARE_ADD_16HL(p2q0, p2, q0) \
+    DECLARE_ADD_16HL(q1q2, q1, q2) \
+    DECLARE_ADD_16HL(p3p3, p3, p3) \
+    DECLARE_ADD_16HL(q0q3, q0, q3) \
+    DECLARE_ADD_16HL(p3p2, p3, p2) \
+    DECLARE_ADD_16HL(p1q1, p1, q1) \
+    DECLARE_ADD_16HL(p3p0, p3, p0) \
+    DECLARE_ADD_16HL(p0q2, p0, q2) \
+    DECLARE_ADD_16HL(q1q3, q1, q3) \
+    DECLARE_ADD_16HL(q3q3, q3, q3) \
+    DECLARE_ADD_16HL(q0q1q2q3, q0q3, q1q2) \
+    DECLARE_ADD_16HL(p2p1p0q0, p1p0, p2q0) \
+    DECLARE_ADD_16HL(p3p3p3p2, p3p3, p3p2) \
+    DECLARE_ADD_16HL(p3p3p1q1, p3p3, p1q1) \
+    DECLARE_ADD_16HL(p3p0q1q2, p3p0, q1q2) \
+    DECLARE_ADD_16HL(p1p0q1q3, p1p0, q1q3) \
+    DECLARE_ADD_16HL(p0q2q3q3, p0q2, q3q3) \
+ \
+    DECLARE_ADD_16HL(op2, p3p3p3p2, p2p1p0q0) \
+    DECLARE_ADD_16HL(op1, p3p3p1q1, p2p1p0q0) \
+    DECLARE_ADD_16HL(op0, p3p0q1q2, p2p1p0q0) \
+    DECLARE_ADD_16HL(oq0, p2p1p0q0, q0q1q2q3) \
+    DECLARE_ADD_16HL(oq1, p1p0q1q3, q0q1q2q3) \
+    DECLARE_ADD_16HL(oq2, p0q2q3q3, q0q1q2q3) \
+ \
+    ADD_AND_SHIFT4(op2) \
+    ADD_AND_SHIFT4(op1) \
+    ADD_AND_SHIFT4(op0) \
+    ADD_AND_SHIFT4(oq0) \
+    ADD_AND_SHIFT4(oq1) \
+    ADD_AND_SHIFT4(oq2) \
+ \
+    p2 = PACK_AND_SEL(p2, apply_8); \
+    p1 = PACK_AND_SEL(p1, apply_8); \
+    p0 = PACK_AND_SEL(p0, apply_8); \
+    q0 = PACK_AND_SEL(q0, apply_8); \
+    q1 = PACK_AND_SEL(q1, apply_8); \
+    q2 = PACK_AND_SEL(q2, apply_8);
+
+#define APPLY_16 \
+    DECLARE_ADD_16HL(p6p6, p6, p6) \
+    DECLARE_ADD_16HL(p6p5, p6, p5) \
+    DECLARE_ADD_16HL(p6p4, p6, p4) \
+    DECLARE_ADD_16HL(p4p3, p4, p3) \
+    DECLARE_ADD_16HL(p2p1, p2, p1) \
+    DECLARE_ADD_16HL(p2q2, p2, q2) \
+    DECLARE_ADD_16HL(p3q1, p3, q1) \
+    DECLARE_ADD_16HL(p0q0, p0, q0) \
+    DECLARE_ADD_16HL(p0q1, p0, q1) \
+    DECLARE_ADD_16HL(p1q3, p1, q3) \
+    DECLARE_ADD_16HL(p1q0, p1, q0) \
+    DECLARE_ADD_16HL(p1q5, p1, q5) \
+    DECLARE_ADD_16HL(q3q4, q3, q4) \
+    DECLARE_ADD_16HL(q2q5, q2, q5) \
+    DECLARE_ADD_16HL(q1q6, q1, q6) \
+    DECLARE_ADD_16HL(q0q1, q0, q1) \
+    DECLARE_ADD_16HL(q6q6, q6, q6) \
+    DECLARE_ADD_16HL(q2q6, q2, q6) \
+    DECLARE_ADD_16HL(q3q6, q3, q6) \
+    DECLARE_ADD_16HL(q4q6, q4, q6) \
+    DECLARE_ADD_16HL(p5q0, p5, q0) \
+ \
+    DECLARE_ADD_16HL(p6q2, p6, q2) \
+    DECLARE_ADD_16HL(p6p6p6p4, p6p6, p6p4) \
+    DECLARE_ADD_16HL(p6p5p2p1, p6p5, p2p1) \
+    DECLARE_ADD_16HL(p4p3p0q0, p4p3, p0q0) \
+    DECLARE_ADD_16HL(p2q2p3q1, p2q2, p3q1) \
+    DECLARE_ADD_16HL(p6p5p6p6, p6p5, p6p6) \
+    DECLARE_ADD_16HL(p6p5p3q1, p6p5, p3q1) \
+    DECLARE_ADD_16HL(p6p6p1q3, p6p6, p1q3) \
+    DECLARE_ADD_16HL(q2q5q3q4, q2q5, q3q4) \
+    DECLARE_ADD_16HL(p2p1q1q6, p2p1, q1q6) \
+    DECLARE_ADD_16HL(p0q0q3q6, p0q0, q3q6) \
+    DECLARE_ADD_16HL(q4q6q6q6, q4q6, q6q6) \
+    u16x8 q5q6q6q6h = vec_madd(v3u16, q6h, q5h); \
+    u16x8 q5q6q6q6l = vec_madd(v3u16, q6l, q5l); \
+    DECLARE_ADD_16HL(p0q0q1q6, p0q0, q1q6) \
+    DECLARE_ADD_16HL(p0q1q3q4, p0q1, q3q4) \
+ \
+    DECLARE_ADD_16HL(p6q2p2p1, p6q2, p2p1) \
+    DECLARE_ADD_16HL(p1q0q2q5, p1q0, q2q5) \
+    DECLARE_ADD_16HL(p0q1p5q0, p0q1, p5q0) \
+    DECLARE_ADD_16HL(q0q1q2q6, q0q1, q2q6) \
+    DECLARE_ADD_16HL(p3q1q2q6, p3q1, q2q6) \
+    DECLARE_ADD_16HL(q2q6q4q6, q2q6, q4q6) \
+    DECLARE_ADD_16HL(q3q6p1q5, q3q6, p1q5) \
+ \
+    DECLARE_ADD_16HL(p4p3p0q0p2p1q1q6, p4p3p0q0, p2p1q1q6) \
+    DECLARE_ADD_16HL(p6p5p2p1p4p3p0q0, p6p5p2p1, p4p3p0q0) \
+    DECLARE_ADD_16HL(p2p1q1q6q2q5q3q4, p2p1q1q6, q2q5q3q4) \
+    DECLARE_ADD_16HL(q2q5q3q4q4q6q6q6, q2q5q3q4, q4q6q6q6) \
+    DECLARE_ADD_16HL(p6p5p2p1p4p3p0q0p2q2p3q1, p6p5p2p1p4p3p0q0, p2q2p3q1) \
+    DECLARE_ADD_16HL(p6p6p6p4p6p5p2p1p4p3p0q0, p6p6p6p4, p6p5p2p1p4p3p0q0) \
+    DECLARE_ADD_16HL(p4p3p0q0p2p1q1q6q2q5q3q4, p4p3p0q0p2p1q1q6, q2q5q3q4) \
+    DECLARE_ADD_16HL(p2p1q1q6q2q5q3q4p0q0q3q6, p2p1q1q6q2q5q3q4, p0q0q3q6) \
+    DECLARE_ADD_16HL(p0q0q1q6q2q5q3q4q4q6q6q6, p0q0q1q6, q2q5q3q4q4q6q6q6) \
+    DECLARE_ADD_16HL(p6p5p2p1p4p3p0q0p0q1q3q4, p6p5p2p1p4p3p0q0, p0q1q3q4) \
+ \
+    DECLARE_ADD_16HL(op5, p6p6p6p4p6p5p2p1p4p3p0q0, p6p5p6p6) \
+    DECLARE_ADD_16HL(op4, p6p6p6p4p6p5p2p1p4p3p0q0, p6p5p3q1) \
+    DECLARE_ADD_16HL(op3, p6p6p6p4, p6p5p2p1p4p3p0q0p2q2p3q1) \
+    DECLARE_ADD_16HL(op2, p6p6p1q3, p6p5p2p1p4p3p0q0p2q2p3q1) \
+    DECLARE_ADD_16HL(op1, p6p5p2p1p4p3p0q0p0q1q3q4, p6q2p2p1) \
+    DECLARE_ADD_16HL(op0, p6p5p2p1p4p3p0q0p0q1q3q4, p1q0q2q5) \
+    DECLARE_ADD_16HL(oq0, p4p3p0q0p2p1q1q6q2q5q3q4, p0q1p5q0) \
+    DECLARE_ADD_16HL(oq1, p4p3p0q0p2p1q1q6q2q5q3q4, q0q1q2q6) \
+    DECLARE_ADD_16HL(oq2, p2p1q1q6q2q5q3q4p0q0q3q6, p3q1q2q6) \
+    DECLARE_ADD_16HL(oq3, p2p1q1q6q2q5q3q4p0q0q3q6, q2q6q4q6) \
+    DECLARE_ADD_16HL(oq4, p0q0q1q6q2q5q3q4q4q6q6q6, q3q6p1q5) \
+    DECLARE_ADD_16HL(oq5, p0q0q1q6q2q5q3q4q4q6q6q6, q5q6q6q6) \
+ \
+    ADD_AND_SHIFT8(op5) \
+    ADD_AND_SHIFT8(op4) \
+    ADD_AND_SHIFT8(op3) \
+    ADD_AND_SHIFT8(op2) \
+    ADD_AND_SHIFT8(op1) \
+    ADD_AND_SHIFT8(op0) \
+    ADD_AND_SHIFT8(oq0) \
+    ADD_AND_SHIFT8(oq1) \
+    ADD_AND_SHIFT8(oq2) \
+    ADD_AND_SHIFT8(oq3) \
+    ADD_AND_SHIFT8(oq4) \
+    ADD_AND_SHIFT8(oq5) \
+ \
+    p5 = PACK_AND_SEL(p5, apply_16); \
+    p4 = PACK_AND_SEL(p4, apply_16); \
+    p3 = PACK_AND_SEL(p3, apply_16); \
+    p2 = PACK_AND_SEL(p2, apply_16); \
+    p1 = PACK_AND_SEL(p1, apply_16); \
+    p0 = PACK_AND_SEL(p0, apply_16); \
+    q0 = PACK_AND_SEL(q0, apply_16); \
+    q1 = PACK_AND_SEL(q1, apply_16); \
+    q2 = PACK_AND_SEL(q2, apply_16); \
+    q3 = PACK_AND_SEL(q3, apply_16); \
+    q4 = PACK_AND_SEL(q4, apply_16); \
+    q5 = PACK_AND_SEL(q5, apply_16); \
+
+
+
+static inline void store_h_4(u8x16 out, uint8_t *dst, int stridea)
+{
+    u8x16 out1 = (u8x16)vec_splat((u32x4)out, 1);
+    u8x16 out2 = (u8x16)vec_splat((u32x4)out, 2);
+    u8x16 out3 = (u8x16)vec_splat((u32x4)out, 3);
+    vec_xst_len(out, dst, 4);
+    dst += stridea;
+    vec_xst_len(out1, dst, 4);
+    dst += stridea;
+    vec_xst_len(out2, dst, 4);
+    dst += stridea;
+    vec_xst_len(out3, dst, 4);
+}
+
+static inline void store_h_8(u8x16 outa, u8x16 outb, uint8_t *dst, int stridea)
+{
+    u8x16 out1 = (u8x16)vec_mergel((u64x2)outa, (u64x2)outa);
+    u8x16 out3 = (u8x16)vec_mergel((u64x2)outb, (u64x2)outb);
+    vec_xst_len(outa, dst, 6);
+    dst += stridea;
+    vec_xst_len(out1, dst, 6);
+    dst += stridea;
+    vec_xst_len(outb, dst, 6);
+    dst += stridea;
+    vec_xst_len(out3, dst, 6);
+}
+
+// Assume a layout  {v}0 {v}1 {v}2 {v}3, produces {v}01 {v}23
+#define MERGEH_4(v) \
+    u8x16 v##01 = vec_mergeh(v##0, v##1); \
+    u8x16 v##23 = vec_mergeh(v##2, v##3);
+
+#define MERGEL_4(v) \
+    u8x16 v##01 = vec_mergel(v##0, v##1); \
+    u8x16 v##23 = vec_mergel(v##2, v##3);
+
+// produce {v}0123h
+#define MERGEH_U16_0123(v) \
+    u16x8 v##0123h = vec_mergeh((u16x8)v##01, (u16x8)v##23);
+
+#define MERGEHL_U16_0123(v) \
+    u16x8 v##0123l = vec_mergel((u16x8)v##01, (u16x8)v##23);
+
+#define MERGE_U16_0123(v) \
+    u16x8 v##0123h = vec_mergeh((u16x8)v##01, (u16x8)v##23); \
+    u16x8 v##0123l = vec_mergel((u16x8)v##01, (u16x8)v##23);
+
+// produce {ac,bd}0123h{dir}
+#define MERGEH_U32_LINE(dir) \
+    u32x4 ac0123h##dir = vec_mergeh((u32x4)a0123##dir, (u32x4)c0123##dir); \
+    u32x4 bd0123h##dir = vec_mergeh((u32x4)b0123##dir, (u32x4)d0123##dir);
+
+#define MERGEL_U32_LINE(dir) \
+    u32x4 ac0123l##dir = vec_mergel((u32x4)a0123##dir, (u32x4)c0123##dir); \
+    u32x4 bd0123l##dir = vec_mergel((u32x4)b0123##dir, (u32x4)d0123##dir);
+
+
+// produce the pair of mergeh/mergel of {ac,bd}01234{dira}{dirb}
+#define MERGE_U32(oh, ol, dira, dirb) \
+    oh = (u8x16)vec_mergeh(ac0123##dira##dirb, bd0123##dira##dirb); \
+    ol = (u8x16)vec_mergel(ac0123##dira##dirb, bd0123##dira##dirb);
+
+#define MERGEHL_U8(a, b) \
+    u8x16 a##b##h = vec_mergeh(a, b); \
+    u8x16 a##b##l = vec_mergel(a, b);
+
+#define MERGEHL_U16(out, a, b) \
+    u8x16 out##h = (u8x16)vec_mergeh((u16x8)a, (u16x8)b); \
+    u8x16 out##l = (u8x16)vec_mergel((u16x8)a, (u16x8)b);
+
+#define MERGEHL_U32(out, a, b) \
+    u8x16 out##h = (u8x16)vec_mergeh((u32x4)a, (u32x4)b); \
+    u8x16 out##l = (u8x16)vec_mergel((u32x4)a, (u32x4)b);
+
+static inline void
+loop_filter_h_4_all(uint8_t *dst, u8x16 E, u8x16 I, u8x16 H,
+                const ptrdiff_t stridea, b32x4 apply)
+{
+    dst -= 2;
+    uint8_t *dst2 = dst;
+    u8x16 p1, p0, q0, q1;
+
+    LOAD4_H(a)
+    dst += stridea;
+    LOAD4_H(b)
+    dst += stridea;
+    LOAD4_H(c)
+    dst += stridea;
+    LOAD4_H(d)
+
+    MERGEH_4(a)
+    MERGEH_4(b)
+    MERGEH_4(c)
+    MERGEH_4(d)
+
+    MERGEH_U16_0123(a)
+    MERGEH_U16_0123(b)
+    MERGEH_U16_0123(c)
+    MERGEH_U16_0123(d)
+
+    MERGEH_U32_LINE(h)
+    MERGEL_U32_LINE(h)
+
+    MERGE_U32(p1, p0, h, h)
+    MERGE_U32(q0, q1, l, h)
+
+    const u8x16 zero = vec_splat_u8(0);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const b8x16 s = (b8x16)vec_splats((uint8_t)128);
+
+    const u8x16 a_p1_p0 = vec_absd(p1, p0);
+    const u8x16 a_q1_q0 = vec_absd(q1, q0);
+    const u8x16 a_p0_q0 = vec_absd(p0, q0);
+    const u8x16 a_p1_q1 = vec_absd(p1, q1);
+
+    u8x16 cmp_E = vec_adds(a_p0_q0, a_p0_q0);
+    const u8x16 max_a_p1p0_q1q0 = vec_max(a_p1_p0, a_q1_q0);
+    const u8x16 cmp_I = max_a_p1p0_q1q0;
+    cmp_E = vec_adds(vec_sr(a_p1_q1, v1u8), cmp_E);
+    const b8x16 ltI = vec_cmple(cmp_I, I);
+    const b8x16 ltE = vec_cmple(cmp_E, E);
+    b8x16 fm = vec_and(ltI, ltE);
+
+    fm = vec_and(fm, (b8x16)apply);
+    if (vec_all_eq(fm, zero))
+        return;
+
+    UNPACK_16(p0)
+    UNPACK_16(q0)
+
+    APPLY_4
+
+    u8x16 p1p0ab = (u8x16)vec_mergeh(p1, p0); // p1 p0 ...
+    u8x16 q0q1ab = (u8x16)vec_mergeh(q0, q1); // q0 q1 ...
+    u8x16 p1p0cd = (u8x16)vec_mergel(p1, p0); // p1 p0 ...
+    u8x16 q0q1cd = (u8x16)vec_mergel(q0, q1); // q0 q1 ...
+
+    u8x16 outa = (u8x16)vec_mergeh((u16x8)p1p0ab, (u16x8)q0q1ab); // op1 op0 oq0 oq1 ...
+    u8x16 outb = (u8x16)vec_mergel((u16x8)p1p0ab, (u16x8)q0q1ab);
+    u8x16 outc = (u8x16)vec_mergeh((u16x8)p1p0cd, (u16x8)q0q1cd);
+    u8x16 outd = (u8x16)vec_mergel((u16x8)p1p0cd, (u16x8)q0q1cd);
+
+    if (apply[0]) {
+        store_h_4(outa, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+    if (apply[1]) {
+        store_h_4(outb, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+    if (apply[2]) {
+        store_h_4(outc, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+    if (apply[3]) {
+        store_h_4(outd, dst2, stridea);
+    }
+}
+
+static inline void
+loop_filter_h_6_all(uint8_t *dst, u8x16 E, u8x16 I, u8x16 H,
+                    const ptrdiff_t stridea, b32x4 apply, b32x4 m6)
+{
+    uint8_t *dst2 = dst - 2;
+    dst -= 3;
+    u8x16 p2, p1, p0, q0, q1, q2;
+
+    LOAD4_H(a)
+    dst += stridea;
+    LOAD4_H(b)
+    dst += stridea;
+    LOAD4_H(c)
+    dst += stridea;
+    LOAD4_H(d)
+
+    MERGEH_4(a)
+    MERGEH_4(b)
+    MERGEH_4(c)
+    MERGEH_4(d)
+
+    MERGE_U16_0123(a)
+    MERGE_U16_0123(b)
+    MERGE_U16_0123(c)
+    MERGE_U16_0123(d)
+
+    MERGEH_U32_LINE(h)
+    MERGEL_U32_LINE(h)
+    MERGEH_U32_LINE(l)
+
+    MERGE_U32(p2, p1, h, h)
+    MERGE_U32(p0, q0, l, h)
+    MERGE_U32(q1, q2, h, l)
+
+    const u8x16 F = vec_splat_u8(1);
+
+    const u8x16 zero = vec_splat_u8(0);
+    const u16x8 v3u16 = vec_splat_u16(3);
+    const u16x8 v4u16 = vec_splat_u16(4);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const b8x16 s = (b8x16)vec_splats((uint8_t)128);
+
+    const u8x16 a_p1_p0 = vec_absd(p1, p0);
+    const u8x16 a_q1_q0 = vec_absd(q1, q0);
+    const u8x16 a_p0_q0 = vec_absd(p0, q0);
+    const u8x16 a_p1_q1 = vec_absd(p1, q1);
+    const u8x16 a_p2_p1 = vec_absd(p2, p1);
+    const u8x16 a_q2_q1 = vec_absd(q2, q1);
+    const u8x16 a_p2_p0 = vec_absd(p2, p0);
+    const u8x16 a_q2_q0 = vec_absd(q2, q0);
+
+    u8x16 max_a_p2p1_q2q1 = vec_max(a_p2_p1, a_q2_q1);
+    u8x16 cmp_E = vec_adds(a_p0_q0, a_p0_q0);
+    const u8x16 max_a_p1p0_q1q0 = vec_max(a_p1_p0, a_q1_q0);
+    u8x16 max_a_p2p0_q2q0 = vec_max(a_p2_p0, a_q2_q0);
+    u8x16 cmp_I_m6 = max_a_p2p1_q2q1;
+    u8x16 cmp_I_m4 = max_a_p1p0_q1q0;
+    cmp_E = vec_adds(vec_sr(a_p1_q1, v1u8), cmp_E);
+    cmp_I_m6 = vec_and(cmp_I_m6, (u8x16)m6);
+    u8x16 cmp_I = vec_max(cmp_I_m4, cmp_I_m6);
+    const b8x16 ltE = vec_cmple(cmp_E, E);
+    const b8x16 ltI = vec_cmple(cmp_I, I);
+    b8x16 fm = vec_and(ltI, ltE);
+
+    fm = vec_and(fm, (b8x16)apply);
+    if (vec_all_eq(fm, zero))
+        return;
+
+    UNPACK_16(p2)
+    UNPACK_16(p1)
+    UNPACK_16(p0)
+    UNPACK_16(q0)
+    UNPACK_16(q1)
+    UNPACK_16(q2)
+
+    m6 = vec_and(m6, (b32x4)fm);
+
+    u8x16 cmp_flat8in = vec_max(max_a_p2p0_q2q0, max_a_p1p0_q1q0);
+    b8x16 apply_6 = vec_and(vec_cmple(cmp_flat8in, F), (b8x16)m6);
+
+    b8x16 apply_4 = vec_andc(fm, apply_6);
+
+    if (vec_any_ne(apply_4, zero)) {
+        APPLY_4
+    }
+
+    if (vec_any_ne(apply_6, zero)) {
+        DECLARE_ADD_16HL(p2p2, p2, p2)
+        DECLARE_ADD_16HL(p2p1, p2, p1)
+        DECLARE_ADD_16HL(p1p0, p1, p0)
+        DECLARE_ADD_16HL(p0q0, p0, q0)
+        DECLARE_ADD_16HL(q0q1, q0, q1)
+        DECLARE_ADD_16HL(q1q2, q1, q2)
+        DECLARE_ADD_16HL(p2p2p0q0, p2p2, p0q0)
+        DECLARE_ADD_16HL(p2p1p1p0, p2p1, p1p0)
+        DECLARE_ADD_16HL(p1p0q1q2, p1p0, q1q2)
+        DECLARE_ADD_16HL(p0q0q0q1, p0q0, q0q1)
+        u16x8 q1q2q2q2h = q2h * 3 + q1h;
+        u16x8 q1q2q2q2l = q2l * 3 + q1l;
+
+        DECLARE_ADD_16HL(op1, p2p2p0q0, p2p1p1p0)
+        DECLARE_ADD_16HL(op0, p2p1p1p0, p0q0q0q1)
+        DECLARE_ADD_16HL(oq0, p1p0q1q2, p0q0q0q1)
+        DECLARE_ADD_16HL(oq1, p0q0q0q1, q1q2q2q2)
+
+        ADD_AND_SHIFT4(op1)
+        ADD_AND_SHIFT4(op0)
+        ADD_AND_SHIFT4(oq0)
+        ADD_AND_SHIFT4(oq1)
+
+        p1 = PACK_AND_SEL(p1, apply_6);
+        p0 = PACK_AND_SEL(p0, apply_6);
+        q0 = PACK_AND_SEL(q0, apply_6);
+        q1 = PACK_AND_SEL(q1, apply_6);
+    }
+
+    u8x16 p1p0ab = (u8x16)vec_mergeh(p1, p0); // p1 p0 ...
+    u8x16 q0q1ab = (u8x16)vec_mergeh(q0, q1); // q0 q1 ...
+    u8x16 p1p0cd = (u8x16)vec_mergel(p1, p0); // p1 p0 ...
+    u8x16 q0q1cd = (u8x16)vec_mergel(q0, q1); // q0 q1 ...
+
+    u8x16 outa = (u8x16)vec_mergeh((u16x8)p1p0ab, (u16x8)q0q1ab); // op1 op0 oq0 oq1 ...
+    u8x16 outb = (u8x16)vec_mergel((u16x8)p1p0ab, (u16x8)q0q1ab);
+    u8x16 outc = (u8x16)vec_mergeh((u16x8)p1p0cd, (u16x8)q0q1cd);
+    u8x16 outd = (u8x16)vec_mergel((u16x8)p1p0cd, (u16x8)q0q1cd);
+
+    if (apply[0]) {
+        store_h_4(outa, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+    if (apply[1]) {
+        store_h_4(outb, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+    if (apply[2]) {
+        store_h_4(outc, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+    if (apply[3]) {
+        store_h_4(outd, dst2, stridea);
+    }
+}
+
+static inline void
+loop_filter_h_8_all(uint8_t *dst, u8x16 E, u8x16 I, u8x16 H,
+                    const ptrdiff_t stridea, b32x4 apply, b32x4 m8)
+{
+    uint8_t *dst2 = dst - 3;
+    dst -= 4;
+    u8x16 p3, p2, p1, p0, q0, q1, q2, q3;
+
+    LOAD4_H(a)
+    dst += stridea;
+    LOAD4_H(b)
+    dst += stridea;
+    LOAD4_H(c)
+    dst += stridea;
+    LOAD4_H(d)
+
+    MERGEH_4(a)
+    MERGEH_4(b)
+    MERGEH_4(c)
+    MERGEH_4(d)
+
+    MERGE_U16_0123(a)
+    MERGE_U16_0123(b)
+    MERGE_U16_0123(c)
+    MERGE_U16_0123(d)
+
+    MERGEH_U32_LINE(h)
+    MERGEL_U32_LINE(h)
+    MERGEH_U32_LINE(l)
+    MERGEL_U32_LINE(l)
+
+    MERGE_U32(p3, p2, h, h)
+    MERGE_U32(p1, p0, l, h)
+    MERGE_U32(q0, q1, h, l)
+    MERGE_U32(q2, q3, l, l)
+
+    const u8x16 F = vec_splat_u8(1);
+
+    const u8x16 zero = vec_splat_u8(0);
+    const u16x8 v3u16 = vec_splat_u16(3);
+    const u16x8 v4u16 = vec_splat_u16(4);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const b8x16 s = (b8x16)vec_splats((uint8_t)128);
+
+    const u8x16 a_p1_p0 = vec_absd(p1, p0);
+    const u8x16 a_q1_q0 = vec_absd(q1, q0);
+    const u8x16 a_p0_q0 = vec_absd(p0, q0);
+    const u8x16 a_p1_q1 = vec_absd(p1, q1);
+    const u8x16 a_p2_p1 = vec_absd(p2, p1);
+    const u8x16 a_q2_q1 = vec_absd(q2, q1);
+    const u8x16 a_p2_p0 = vec_absd(p2, p0);
+    const u8x16 a_q2_q0 = vec_absd(q2, q0);
+    const u8x16 a_p3_p0 = vec_absd(p3, p0);
+    const u8x16 a_q3_q0 = vec_absd(q3, q0);
+    const u8x16 a_p3_p2 = vec_absd(p3, p2);
+    const u8x16 a_q3_q2 = vec_absd(q3, q2);
+
+    u8x16 max_a_p2p1_q2q1 = vec_max(a_p2_p1, a_q2_q1);
+    u8x16 max_a_p3p2_q3q2 = vec_max(a_p3_p2, a_q3_q2);
+    u8x16 cmp_E = vec_adds(a_p0_q0, a_p0_q0);
+    const u8x16 max_a_p1p0_q1q0 = vec_max(a_p1_p0, a_q1_q0);
+    const u8x16 max_a_p2p0_q2q0 = vec_max(a_p2_p0, a_q2_q0);
+    u8x16 max_a_p3p0_q3q0 = vec_max(a_p3_p0, a_q3_q0);
+    u8x16 cmp_I_m8 = vec_max(max_a_p2p1_q2q1, max_a_p3p2_q3q2);
+    u8x16 cmp_I_m4 = max_a_p1p0_q1q0;
+    cmp_E = vec_adds(vec_sr(a_p1_q1, v1u8), cmp_E);
+    cmp_I_m8 = vec_and(cmp_I_m8, (u8x16)m8);
+    u8x16 cmp_I = vec_max(cmp_I_m4, cmp_I_m8);
+    const b8x16 ltE = vec_cmple(cmp_E, E);
+    const b8x16 ltI = vec_cmple(cmp_I, I);
+    b8x16 fm = vec_and(ltI, ltE);
+
+    fm = vec_and(fm, (b8x16)apply);
+    if (vec_all_eq(fm, zero))
+        return;
+
+    #define UNPACK_16(v) \
+        u16x8 v##h = u8h_to_u16(v); \
+        u16x8 v##l = u8l_to_u16(v);
+
+    UNPACK_16(p3)
+    UNPACK_16(p2)
+    UNPACK_16(p1)
+    UNPACK_16(p0)
+    UNPACK_16(q0)
+    UNPACK_16(q1)
+    UNPACK_16(q2)
+    UNPACK_16(q3)
+
+    m8 = vec_and(m8, (b32x4)fm);
+
+    u8x16 cmp_flat8in = vec_max(max_a_p2p0_q2q0, max_a_p1p0_q1q0);
+    cmp_flat8in = vec_max(max_a_p3p0_q3q0, cmp_flat8in);
+    b8x16 apply_8 = vec_and(vec_cmple(cmp_flat8in, F), (b8x16)m8);
+
+    b8x16 apply_4 = vec_andc(fm, apply_8);
+
+    if (vec_any_ne(apply_4, zero)) {
+        APPLY_4
+    }
+
+    if (vec_any_ne(apply_8, zero)) {
+        APPLY_8
+    }
+
+    MERGEHL_U8(p2, p1) // A0 A1 A2 A3 B0 B1 B2 B3
+    MERGEHL_U8(p0, q0)
+    MERGEHL_U8(q1, q2)
+
+    MERGEHL_U16(ab_p2p1p0q0, p2p1h, p0q0h)       // A0 p2 p1 p0 q0 | A1 p2 p1 p0 q0 | A2 ...
+                                                 // B0 ...
+    MERGEHL_U16(cd_p2p1p0q0, p2p1l, p0q0l)       // C0 ...
+                                                 // D0 ...
+    MERGEHL_U16(ab_q1q2, q1q2h, q1q2h)           // A0 q1 q2 q1 q2 | A1 q1 q2 ...
+                                                 // B0 ...
+    MERGEHL_U16(cd_q1q2, q1q2l, q1q2l)           // C0 ...
+                                                 // D0 ...
+
+    MERGEHL_U32(a, ab_p2p1p0q0h, ab_q1q2h) // A0 p2 p1 p0 q0 q1 q2 q1 q2 | A1 ..
+                                           // A2 ... | A3 ...
+    MERGEHL_U32(b, ab_p2p1p0q0l, ab_q1q2l) // B0 ...
+                                           // C2 ...
+    MERGEHL_U32(c, cd_p2p1p0q0h, cd_q1q2h) // C0 ...
+                                           // C2
+    MERGEHL_U32(d, cd_p2p1p0q0l, cd_q1q2l) // D0 ..
+                                           // D2 ..
+    if (apply[0]) {
+        store_h_8(ah, al, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+    if (apply[1]) {
+        store_h_8(bh, bl, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+
+    if (apply[2]) {
+        store_h_8(ch, cl, dst2, stridea);
+    }
+    dst2 += 4 * stridea;
+    if (apply[3]) {
+        store_h_8(dh, dl, dst2, stridea);
+    }
+
+}
+
+static inline void
+loop_filter_h_16_all(uint8_t *dst, u8x16 E, u8x16 I, u8x16 H,
+                    const ptrdiff_t stridea, b32x4 apply, b32x4 m8, b32x4 m16)
+{
+    uint8_t *dst2 = dst -6 ;
+    dst -= 7;
+    u8x16 p3, p2, p1, p0, q0, q1, q2, q3;
+    u8x16 p6, p5, p4, q4, q5, q6;
+
+    LOAD4_H(a)
+    dst += stridea;
+    LOAD4_H(b)
+    dst += stridea;
+    LOAD4_H(c)
+    dst += stridea;
+    LOAD4_H(d)
+
+    {
+        MERGEH_4(a)
+        MERGEH_4(b)
+        MERGEH_4(c)
+        MERGEH_4(d)
+
+        MERGE_U16_0123(a)
+        MERGE_U16_0123(b)
+        MERGE_U16_0123(c)
+        MERGE_U16_0123(d)
+
+        MERGEH_U32_LINE(h)
+        MERGEL_U32_LINE(h)
+        MERGEH_U32_LINE(l)
+        MERGEL_U32_LINE(l)
+
+        MERGE_U32(p6, p5, h, h)
+        MERGE_U32(p4, p3, l, h)
+        MERGE_U32(p2, p1, h, l)
+        MERGE_U32(p0, q0, l, l)
+    }
+    {
+        MERGEL_4(a)
+        MERGEL_4(b)
+        MERGEL_4(c)
+        MERGEL_4(d)
+
+        MERGE_U16_0123(a)
+        MERGE_U16_0123(b)
+        MERGE_U16_0123(c)
+        MERGE_U16_0123(d)
+
+        MERGEH_U32_LINE(h)
+        MERGEL_U32_LINE(h)
+        MERGEH_U32_LINE(l)
+
+        MERGE_U32(q1, q2, h, h)
+        MERGE_U32(q3, q4, l, h)
+        MERGE_U32(q5, q6, h, l)
+    }
+
+    const u8x16 F = vec_splat_u8(1);
+
+    const u8x16 zero = vec_splat_u8(0);
+    const u16x8 v3u16 = vec_splat_u16(3);
+    const u16x8 v4u16 = vec_splat_u16(4);
+    const u16x8 v8u16 = vec_splat_u16(8);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const b8x16 s = (b8x16)vec_splats((uint8_t)128);
+
+    const u8x16 a_p6_p0 = vec_absd(p6, p0);
+    const u8x16 a_p5_p0 = vec_absd(p5, p0);
+    const u8x16 a_p4_p0 = vec_absd(p4, p0);
+    const u8x16 a_q4_q0 = vec_absd(q4, q0);
+    const u8x16 a_q5_q0 = vec_absd(q5, q0);
+    const u8x16 a_q6_q0 = vec_absd(q6, q0);
+
+    const u8x16 a_p1_p0 = vec_absd(p1, p0);
+    const u8x16 a_q1_q0 = vec_absd(q1, q0);
+    const u8x16 a_p0_q0 = vec_absd(p0, q0);
+    const u8x16 a_p1_q1 = vec_absd(p1, q1);
+    const u8x16 a_p2_p1 = vec_absd(p2, p1);
+    const u8x16 a_q2_q1 = vec_absd(q2, q1);
+    const u8x16 a_p2_p0 = vec_absd(p2, p0);
+    const u8x16 a_q2_q0 = vec_absd(q2, q0);
+    const u8x16 a_p3_p0 = vec_absd(p3, p0);
+    const u8x16 a_q3_q0 = vec_absd(q3, q0);
+    const u8x16 a_p3_p2 = vec_absd(p3, p2);
+    const u8x16 a_q3_q2 = vec_absd(q3, q2);
+
+    u8x16 max_a_p2p1_q2q1 = vec_max(a_p2_p1, a_q2_q1);
+    u8x16 max_a_p3p2_q3q2 = vec_max(a_p3_p2, a_q3_q2);
+    u8x16 cmp_E = vec_adds(a_p0_q0, a_p0_q0);
+    const u8x16 max_a_p1p0_q1q0 = vec_max(a_p1_p0, a_q1_q0);
+    const u8x16 max_a_p2p0_q2q0 = vec_max(a_p2_p0, a_q2_q0);
+
+    const u8x16 max_a_p4p0_q4q0 = vec_max(a_p4_p0, a_q4_q0);
+    const u8x16 max_a_p5p0_q5q0 = vec_max(a_p5_p0, a_q5_q0);
+    const u8x16 max_a_p6p0_q6q0 = vec_max(a_p6_p0, a_q6_q0);
+
+    b32x4 m8_16 = vec_or(m8, m16);
+
+    u8x16 max_a_p3p0_q3q0 = vec_max(a_p3_p0, a_q3_q0);
+    u8x16 cmp_I_m8 = vec_max(max_a_p2p1_q2q1, max_a_p3p2_q3q2);
+    u8x16 cmp_I_m4 = max_a_p1p0_q1q0;
+    cmp_E = vec_adds(vec_sr(a_p1_q1, v1u8), cmp_E);
+    cmp_I_m8 = vec_and(cmp_I_m8, (b8x16)m8_16);
+    u8x16 cmp_I = vec_max(cmp_I_m4, cmp_I_m8);
+    const b8x16 ltE = vec_cmple(cmp_E, E);
+    const b8x16 ltI = vec_cmple(cmp_I, I);
+    b8x16 fm = vec_and(ltI, ltE);
+
+    fm = vec_and(fm, (b8x16)apply);
+    if (vec_all_eq(fm, zero))
+        return;
+
+    u8x16 cmp_flat8in = vec_max(max_a_p2p0_q2q0, max_a_p1p0_q1q0);
+    u8x16 cmp_flat8out = vec_max(max_a_p6p0_q6q0, max_a_p5p0_q5q0);
+
+    m8_16 = vec_and(m8_16, (b32x4)fm);
+    m16 = vec_and(m16, (b32x4)fm);
+
+    cmp_flat8in = vec_max(max_a_p3p0_q3q0, cmp_flat8in);
+    cmp_flat8out = vec_max(max_a_p4p0_q4q0, cmp_flat8out);
+    b8x16 flat8in = vec_cmple(cmp_flat8in, F);
+    b8x16 flat8out = vec_cmple(cmp_flat8out, F);
+    flat8in = vec_and(flat8in, (b8x16)m8_16);
+    flat8out = vec_and(flat8out, (b8x16)m16);
+
+    b8x16 apply_16 = vec_and(flat8out, flat8in);
+    b8x16 apply_8 = vec_andc(flat8in, flat8out);
+
+    UNPACK_16(p6)
+    UNPACK_16(p5)
+    UNPACK_16(p4)
+    UNPACK_16(p3)
+    UNPACK_16(p2)
+    UNPACK_16(p1)
+    UNPACK_16(p0)
+
+    b8x16 apply_4 = vec_and(fm, vec_nor(apply_16, apply_8));
+
+    UNPACK_16(q0)
+    UNPACK_16(q1)
+    UNPACK_16(q2)
+    UNPACK_16(q3)
+    UNPACK_16(q4)
+    UNPACK_16(q5)
+    UNPACK_16(q6)
+
+    if (vec_any_ne(apply_4, zero)) {
+        APPLY_4
+    }
+
+    if (vec_any_ne(apply_16, zero)) {
+        APPLY_16
+    }
+
+    if (vec_any_ne(apply_8, zero)) {
+        APPLY_8
+    }
+
+    MERGEHL_U8(p5, p4)
+    MERGEHL_U8(p3, p2)
+    MERGEHL_U8(p1, p0)
+    MERGEHL_U8(q0, q1)
+    MERGEHL_U8(q2, q3)
+    MERGEHL_U8(q4, q5)
+
+    MERGEHL_U16(ab_p5p4p3p2, p5p4h, p3p2h)
+    MERGEHL_U16(cd_p5p4p3p2, p5p4l, p3p2l)
+    MERGEHL_U16(ab_p1p0q0q1, p1p0h, q0q1h)
+    MERGEHL_U16(cd_p1p0q0q1, p1p0l, q0q1l)
+    MERGEHL_U16(ab_q2q3q4q5, q2q3h, q4q5h)
+    MERGEHL_U16(cd_q2q3q4q5, q2q3l, q4q5l)
+
+
+    MERGEHL_U32(a_p5p4p3p2q2q3q4q5, ab_p5p4p3p2h, ab_q2q3q4q5h) // A0 p5p4p3p2 q2q3q4q5 A1
+                                                                // A2                   A3
+    MERGEHL_U32(a_p1p0q0q1q2q3q4q5, ab_p1p0q0q1h, ab_q2q3q4q5h) // A0 p1p0q0q1 q2q3q4q5 A1
+                                                                // A2                   A3
+    MERGEHL_U32(b_p5p4p3p2q2q3q4q5, ab_p5p4p3p2l, ab_q2q3q4q5l) // B0 p5p4p3p2 q2q3q4q5 B1
+                                                                // A2                   A3
+    MERGEHL_U32(b_p1p0q0q1q2q3q4q5, ab_p1p0q0q1l, ab_q2q3q4q5l) // B0 p1p0q0q1 q2q3q4q5 B1
+                                                                // B2                   B3
+    MERGEHL_U32(c_p5p4p3p2q2q3q4q5, cd_p5p4p3p2h, cd_q2q3q4q5h) // C0 p5p4p3p2 q2q3q4q5 C1
+                                                                // C2                   C3
+    MERGEHL_U32(c_p1p0q0q1q2q3q4q5, cd_p1p0q0q1h, cd_q2q3q4q5h) // C0 p1p0q0q1 q2q3q4q5 C1
+                                                                // C2                   C3
+    MERGEHL_U32(d_p5p4p3p2q2q3q4q5, cd_p5p4p3p2l, cd_q2q3q4q5l) // D0 p5p4p3p2 q2q3q4q5 D1
+                                                                // D2                   D3
+    MERGEHL_U32(d_p1p0q0q1q2q3q4q5, cd_p1p0q0q1l, cd_q2q3q4q5l) // D0 p1p0q0q1 q2q3q4q5 D1
+                                                                // D2                   D3
+
+    MERGEHL_U32(a01, a_p5p4p3p2q2q3q4q5h, a_p1p0q0q1q2q3q4q5h) // A0 p5p4p3p2 p1p0q0q1 q2q3q4q5 q2q3q4q5
+                                                               // A1
+    vec_xst_len(a01h, dst2, 12);
+    dst2 += stridea;
+    vec_xst_len(a01l, dst2, 12);
+    dst2 += stridea;
+    MERGEHL_U32(a23, a_p5p4p3p2q2q3q4q5l, a_p1p0q0q1q2q3q4q5l) // A2
+                                                               // A3
+    vec_xst_len(a23h, dst2, 12);
+    dst2 += stridea;
+    vec_xst_len(a23l, dst2, 12);
+    dst2 += stridea;
+    MERGEHL_U32(b01, b_p5p4p3p2q2q3q4q5h, b_p1p0q0q1q2q3q4q5h) // B0 p5p4p3p2 p1p0q0q1 q2q3q4q5 q2q3q4q5
+                                                               // B1
+    vec_xst_len(b01h, dst2, 12);
+    dst2 += stridea;
+    vec_xst_len(b01l, dst2, 12);
+    dst2 += stridea;
+    MERGEHL_U32(b23, b_p5p4p3p2q2q3q4q5l, b_p1p0q0q1q2q3q4q5l) // B2
+                                                               // B3
+    vec_xst_len(b23h, dst2, 12);
+    dst2 += stridea;
+    vec_xst_len(b23l, dst2, 12);
+    dst2 += stridea;
+    MERGEHL_U32(c01, c_p5p4p3p2q2q3q4q5h, c_p1p0q0q1q2q3q4q5h) // C0 p5p4p3p2 p1p0q0q1 q2q3q4q5 q2q3q4q5
+                                                               // C1
+    vec_xst_len(c01h, dst2, 12);
+    dst2 += stridea;
+    vec_xst_len(c01l, dst2, 12);
+    dst2 += stridea;
+    MERGEHL_U32(c23, c_p5p4p3p2q2q3q4q5l, c_p1p0q0q1q2q3q4q5l) // C2
+                                                               // C3
+    vec_xst_len(c23h, dst2, 12);
+    dst2 += stridea;
+    vec_xst_len(c23l, dst2, 12);
+    dst2 += stridea;
+    MERGEHL_U32(d01, d_p5p4p3p2q2q3q4q5h, d_p1p0q0q1q2q3q4q5h) // D0 p5p4p3p2 p1p0q0q1 q2q3q4q5 q2q3q4q5
+                                                               // D1
+    vec_xst_len(d01h, dst2, 12);
+    dst2 += stridea;
+    vec_xst_len(d01l, dst2, 12);
+    dst2 += stridea;
+    MERGEHL_U32(d23, d_p5p4p3p2q2q3q4q5l, d_p1p0q0q1q2q3q4q5l) // D2
+                                                               // D3
+    vec_xst_len(d23h, dst2, 12);
+    dst2 += stridea;
+    vec_xst_len(d23l, dst2, 12);
+    dst2 += stridea;
+}
+
+static inline void
+loop_filter_v_4_all(uint8_t *dst, u8x16 E, u8x16 I, u8x16 H,
+                    const ptrdiff_t strideb, b32x4 apply)
+{
+    uint8_t *p1d = dst + strideb * -2;
+    uint8_t *p0d = dst + strideb * -1;
+    uint8_t *q0d = dst + strideb * +0;
+    uint8_t *q1d = dst + strideb * +1;
+
+    u8x16 p1 = vec_xl(0, p1d);
+    u8x16 p0 = vec_xl(0, p0d);
+    u8x16 q0 = vec_xl(0, q0d);
+    u8x16 q1 = vec_xl(0, q1d);
+
+    const u8x16 zero = vec_splat_u8(0);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const b8x16 s = (b8x16)vec_splats((uint8_t)128);
+
+    const u8x16 a_p1_p0 = vec_absd(p1, p0);
+    const u8x16 a_q1_q0 = vec_absd(q1, q0);
+    const u8x16 a_p0_q0 = vec_absd(p0, q0);
+    const u8x16 a_p1_q1 = vec_absd(p1, q1);
+
+    u8x16 cmp_E = vec_adds(a_p0_q0, a_p0_q0);
+    const u8x16 max_a_p1p0_q1q0 = vec_max(a_p1_p0, a_q1_q0);
+    const u8x16 cmp_I = max_a_p1p0_q1q0;
+    cmp_E = vec_adds(vec_sr(a_p1_q1, v1u8), cmp_E);
+    const b8x16 ltI = vec_cmple(cmp_I, I);
+    const b8x16 ltE = vec_cmple(cmp_E, E);
+    b8x16 fm = vec_and(ltI, ltE);
+
+    fm = vec_and(fm, (b8x16)apply);
+    if (vec_all_eq(fm, zero))
+        return;
+
+    UNPACK_16(p0)
+    UNPACK_16(q0)
+
+    APPLY_4
+
+    vec_xst(p0, 0, p0d);
+    vec_xst(q0, 0, q0d);
+    vec_xst(q1, 0, q1d);
+    vec_xst(p1, 0, p1d);
+}
+
+static inline void
+loop_filter_v_6_all(uint8_t *dst, u8x16 E, u8x16 I, u8x16 H,
+                    const ptrdiff_t strideb, b32x4 apply, b32x4 m6)
+{
+    uint8_t *p2d = dst + strideb * -3;
+    uint8_t *p1d = dst + strideb * -2;
+    uint8_t *p0d = dst + strideb * -1;
+    uint8_t *q0d = dst + strideb * +0;
+    uint8_t *q1d = dst + strideb * +1;
+    uint8_t *q2d = dst + strideb * +2;
+
+    u8x16 p2 = vec_xl(0, p2d);
+    u8x16 p1 = vec_xl(0, p1d);
+    u8x16 p0 = vec_xl(0, p0d);
+    u8x16 q0 = vec_xl(0, q0d);
+    u8x16 q1 = vec_xl(0, q1d);
+    u8x16 q2 = vec_xl(0, q2d);
+
+    const u8x16 F = vec_splat_u8(1);
+
+    const u8x16 zero = vec_splat_u8(0);
+    const u16x8 v3u16 = vec_splat_u16(3);
+    const u16x8 v4u16 = vec_splat_u16(4);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const b8x16 s = (b8x16)vec_splats((uint8_t)128);
+
+    const u8x16 a_p1_p0 = vec_absd(p1, p0);
+    const u8x16 a_q1_q0 = vec_absd(q1, q0);
+    const u8x16 a_p0_q0 = vec_absd(p0, q0);
+    const u8x16 a_p1_q1 = vec_absd(p1, q1);
+    const u8x16 a_p2_p1 = vec_absd(p2, p1);
+    const u8x16 a_q2_q1 = vec_absd(q2, q1);
+    const u8x16 a_p2_p0 = vec_absd(p2, p0);
+    const u8x16 a_q2_q0 = vec_absd(q2, q0);
+
+    u8x16 max_a_p2p1_q2q1 = vec_max(a_p2_p1, a_q2_q1);
+    u8x16 cmp_E = vec_adds(a_p0_q0, a_p0_q0);
+    const u8x16 max_a_p1p0_q1q0 = vec_max(a_p1_p0, a_q1_q0);
+    u8x16 max_a_p2p0_q2q0 = vec_max(a_p2_p0, a_q2_q0);
+    u8x16 cmp_I_m6 = max_a_p2p1_q2q1;
+    u8x16 cmp_I_m4 = max_a_p1p0_q1q0;
+    cmp_E = vec_adds(vec_sr(a_p1_q1, v1u8), cmp_E);
+    cmp_I_m6 = vec_and(cmp_I_m6, (u8x16)m6);
+    u8x16 cmp_I = vec_max(cmp_I_m4, cmp_I_m6);
+    const b8x16 ltE = vec_cmple(cmp_E, E);
+    const b8x16 ltI = vec_cmple(cmp_I, I);
+    b8x16 fm = vec_and(ltI, ltE);
+
+    fm = vec_and(fm, (b8x16)apply);
+    if (vec_all_eq(fm, zero))
+        return;
+
+    UNPACK_16(p2)
+    UNPACK_16(p1)
+    UNPACK_16(p0)
+    UNPACK_16(q0)
+    UNPACK_16(q1)
+    UNPACK_16(q2)
+
+    m6 = vec_and(m6, (b32x4)fm);
+
+    u8x16 cmp_flat8in = vec_max(max_a_p2p0_q2q0, max_a_p1p0_q1q0);
+    b8x16 apply_6 = vec_and(vec_cmple(cmp_flat8in, F), (b8x16)m6);
+
+    b8x16 apply_4 = vec_andc(fm, apply_6);
+
+    if (vec_any_ne(apply_4, zero)) {
+        APPLY_4
+    }
+
+    if (vec_any_ne(apply_6, zero)) {
+        DECLARE_ADD_16HL(p2p2, p2, p2)
+        DECLARE_ADD_16HL(p2p1, p2, p1)
+        DECLARE_ADD_16HL(p1p0, p1, p0)
+        DECLARE_ADD_16HL(p0q0, p0, q0)
+        DECLARE_ADD_16HL(q0q1, q0, q1)
+        DECLARE_ADD_16HL(q1q2, q1, q2)
+        DECLARE_ADD_16HL(p2p2p0q0, p2p2, p0q0)
+        DECLARE_ADD_16HL(p2p1p1p0, p2p1, p1p0)
+        DECLARE_ADD_16HL(p1p0q1q2, p1p0, q1q2)
+        DECLARE_ADD_16HL(p0q0q0q1, p0q0, q0q1)
+        u16x8 q1q2q2q2h = q2h * 3 + q1h;
+        u16x8 q1q2q2q2l = q2l * 3 + q1l;
+
+        DECLARE_ADD_16HL(op1, p2p2p0q0, p2p1p1p0)
+        DECLARE_ADD_16HL(op0, p2p1p1p0, p0q0q0q1)
+        DECLARE_ADD_16HL(oq0, p1p0q1q2, p0q0q0q1)
+        DECLARE_ADD_16HL(oq1, p0q0q0q1, q1q2q2q2)
+
+        ADD_AND_SHIFT4(op1)
+        ADD_AND_SHIFT4(op0)
+        ADD_AND_SHIFT4(oq0)
+        ADD_AND_SHIFT4(oq1)
+
+        p1 = PACK_AND_SEL(p1, apply_6);
+        p0 = PACK_AND_SEL(p0, apply_6);
+        q0 = PACK_AND_SEL(q0, apply_6);
+        q1 = PACK_AND_SEL(q1, apply_6);
+    }
+
+    vec_xst(p0, 0, p0d);
+    vec_xst(q0, 0, q0d);
+    vec_xst(q1, 0, q1d);
+    vec_xst(p1, 0, p1d);
+}
+
+static inline void
+loop_filter_v_8_all(uint8_t *dst, u8x16 E, u8x16 I, u8x16 H,
+                    const ptrdiff_t strideb, b32x4 apply, b32x4 m8)
+{
+
+    uint8_t *p3d = dst + strideb * -4;
+    uint8_t *p2d = dst + strideb * -3;
+    uint8_t *p1d = dst + strideb * -2;
+    uint8_t *p0d = dst + strideb * -1;
+    uint8_t *q0d = dst + strideb * +0;
+    uint8_t *q1d = dst + strideb * +1;
+    uint8_t *q2d = dst + strideb * +2;
+    uint8_t *q3d = dst + strideb * +3;
+
+    u8x16 p3 = vec_xl(0, p3d);
+    u8x16 p2 = vec_xl(0, p2d);
+    u8x16 p1 = vec_xl(0, p1d);
+    u8x16 p0 = vec_xl(0, p0d);
+    u8x16 q0 = vec_xl(0, q0d);
+    u8x16 q1 = vec_xl(0, q1d);
+    u8x16 q2 = vec_xl(0, q2d);
+    u8x16 q3 = vec_xl(0, q3d);
+
+    const u8x16 F = vec_splat_u8(1);
+
+    const u8x16 zero = vec_splat_u8(0);
+    const u16x8 v3u16 = vec_splat_u16(3);
+    const u16x8 v4u16 = vec_splat_u16(4);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const b8x16 s = (b8x16)vec_splats((uint8_t)128);
+
+    const u8x16 a_p1_p0 = vec_absd(p1, p0);
+    const u8x16 a_q1_q0 = vec_absd(q1, q0);
+    const u8x16 a_p0_q0 = vec_absd(p0, q0);
+    const u8x16 a_p1_q1 = vec_absd(p1, q1);
+    const u8x16 a_p2_p1 = vec_absd(p2, p1);
+    const u8x16 a_q2_q1 = vec_absd(q2, q1);
+    const u8x16 a_p2_p0 = vec_absd(p2, p0);
+    const u8x16 a_q2_q0 = vec_absd(q2, q0);
+    const u8x16 a_p3_p0 = vec_absd(p3, p0);
+    const u8x16 a_q3_q0 = vec_absd(q3, q0);
+    const u8x16 a_p3_p2 = vec_absd(p3, p2);
+    const u8x16 a_q3_q2 = vec_absd(q3, q2);
+
+    u8x16 max_a_p2p1_q2q1 = vec_max(a_p2_p1, a_q2_q1);
+    u8x16 max_a_p3p2_q3q2 = vec_max(a_p3_p2, a_q3_q2);
+    u8x16 cmp_E = vec_adds(a_p0_q0, a_p0_q0);
+    const u8x16 max_a_p1p0_q1q0 = vec_max(a_p1_p0, a_q1_q0);
+    const u8x16 max_a_p2p0_q2q0 = vec_max(a_p2_p0, a_q2_q0);
+    u8x16 max_a_p3p0_q3q0 = vec_max(a_p3_p0, a_q3_q0);
+    u8x16 cmp_I_m8 = vec_max(max_a_p2p1_q2q1, max_a_p3p2_q3q2);
+    u8x16 cmp_I_m4 = max_a_p1p0_q1q0;
+    cmp_E = vec_adds(vec_sr(a_p1_q1, v1u8), cmp_E);
+    cmp_I_m8 = vec_and(cmp_I_m8, (u8x16)m8);
+    u8x16 cmp_I = vec_max(cmp_I_m4, cmp_I_m8);
+    const b8x16 ltE = vec_cmple(cmp_E, E);
+    const b8x16 ltI = vec_cmple(cmp_I, I);
+    b8x16 fm = vec_and(ltI, ltE);
+
+    fm = vec_and(fm, (b8x16)apply);
+    if (vec_all_eq(fm, zero))
+        return;
+
+    #define UNPACK_16(v) \
+        u16x8 v##h = u8h_to_u16(v); \
+        u16x8 v##l = u8l_to_u16(v);
+
+    UNPACK_16(p3)
+    UNPACK_16(p2)
+    UNPACK_16(p1)
+    UNPACK_16(p0)
+    UNPACK_16(q0)
+    UNPACK_16(q1)
+    UNPACK_16(q2)
+    UNPACK_16(q3)
+
+    m8 = vec_and(m8, (b32x4)fm);
+
+    u8x16 cmp_flat8in = vec_max(max_a_p2p0_q2q0, max_a_p1p0_q1q0);
+    cmp_flat8in = vec_max(max_a_p3p0_q3q0, cmp_flat8in);
+    b8x16 apply_8 = vec_and(vec_cmple(cmp_flat8in, F), (b8x16)m8);
+
+    b8x16 apply_4 = vec_andc(fm, apply_8);
+
+    if (vec_any_ne(apply_4, zero)) {
+        APPLY_4
+    }
+
+    if (vec_any_ne(apply_8, zero)) {
+        APPLY_8
+    }
+
+    vec_xst(p0, 0, p0d);
+    vec_xst(q0, 0, q0d);
+    vec_xst(q1, 0, q1d);
+    vec_xst(p1, 0, p1d);
+    vec_xst(q2, 0, q2d);
+    vec_xst(p2, 0, p2d);
+}
+
+static inline void
+loop_filter_v_16_all(uint8_t *dst, u8x16 E, u8x16 I, u8x16 H,
+                    const ptrdiff_t strideb, b32x4 apply, b32x4 m8, b32x4 m16)
+{
+
+    uint8_t *p6d = dst + strideb * -7;
+    uint8_t *p5d = dst + strideb * -6;
+    uint8_t *p4d = dst + strideb * -5;
+    uint8_t *p3d = dst + strideb * -4;
+    uint8_t *p2d = dst + strideb * -3;
+    uint8_t *p1d = dst + strideb * -2;
+    uint8_t *p0d = dst + strideb * -1;
+    uint8_t *q0d = dst + strideb * +0;
+    uint8_t *q1d = dst + strideb * +1;
+    uint8_t *q2d = dst + strideb * +2;
+    uint8_t *q3d = dst + strideb * +3;
+    uint8_t *q4d = dst + strideb * +4;
+    uint8_t *q5d = dst + strideb * +5;
+    uint8_t *q6d = dst + strideb * +6;
+
+    u8x16 p6 = vec_xl(0, p6d);
+    u8x16 p5 = vec_xl(0, p5d);
+    u8x16 p4 = vec_xl(0, p4d);
+    u8x16 p3 = vec_xl(0, p3d);
+    u8x16 p2 = vec_xl(0, p2d);
+    u8x16 p1 = vec_xl(0, p1d);
+    u8x16 p0 = vec_xl(0, p0d);
+    u8x16 q0 = vec_xl(0, q0d);
+    u8x16 q1 = vec_xl(0, q1d);
+    u8x16 q2 = vec_xl(0, q2d);
+    u8x16 q3 = vec_xl(0, q3d);
+    u8x16 q4 = vec_xl(0, q4d);
+    u8x16 q5 = vec_xl(0, q5d);
+    u8x16 q6 = vec_xl(0, q6d);
+
+    const u8x16 F = vec_splat_u8(1);
+
+    const u8x16 zero = vec_splat_u8(0);
+    const u16x8 v3u16 = vec_splat_u16(3);
+    const u16x8 v4u16 = vec_splat_u16(4);
+    const u16x8 v8u16 = vec_splat_u16(8);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const b8x16 s = (b8x16)vec_splats((uint8_t)128);
+
+    const u8x16 a_p6_p0 = vec_absd(p6, p0);
+    const u8x16 a_p5_p0 = vec_absd(p5, p0);
+    const u8x16 a_p4_p0 = vec_absd(p4, p0);
+    const u8x16 a_q4_q0 = vec_absd(q4, q0);
+    const u8x16 a_q5_q0 = vec_absd(q5, q0);
+    const u8x16 a_q6_q0 = vec_absd(q6, q0);
+
+    const u8x16 a_p1_p0 = vec_absd(p1, p0);
+    const u8x16 a_q1_q0 = vec_absd(q1, q0);
+    const u8x16 a_p0_q0 = vec_absd(p0, q0);
+    const u8x16 a_p1_q1 = vec_absd(p1, q1);
+    const u8x16 a_p2_p1 = vec_absd(p2, p1);
+    const u8x16 a_q2_q1 = vec_absd(q2, q1);
+    const u8x16 a_p2_p0 = vec_absd(p2, p0);
+    const u8x16 a_q2_q0 = vec_absd(q2, q0);
+    const u8x16 a_p3_p0 = vec_absd(p3, p0);
+    const u8x16 a_q3_q0 = vec_absd(q3, q0);
+    const u8x16 a_p3_p2 = vec_absd(p3, p2);
+    const u8x16 a_q3_q2 = vec_absd(q3, q2);
+
+    u8x16 max_a_p2p1_q2q1 = vec_max(a_p2_p1, a_q2_q1);
+    u8x16 max_a_p3p2_q3q2 = vec_max(a_p3_p2, a_q3_q2);
+    u8x16 cmp_E = vec_adds(a_p0_q0, a_p0_q0);
+    const u8x16 max_a_p1p0_q1q0 = vec_max(a_p1_p0, a_q1_q0);
+    const u8x16 max_a_p2p0_q2q0 = vec_max(a_p2_p0, a_q2_q0);
+
+    const u8x16 max_a_p4p0_q4q0 = vec_max(a_p4_p0, a_q4_q0);
+    const u8x16 max_a_p5p0_q5q0 = vec_max(a_p5_p0, a_q5_q0);
+    const u8x16 max_a_p6p0_q6q0 = vec_max(a_p6_p0, a_q6_q0);
+
+    b32x4 m8_16 = vec_or(m8, m16);
+
+    u8x16 max_a_p3p0_q3q0 = vec_max(a_p3_p0, a_q3_q0);
+    u8x16 cmp_I_m8 = vec_max(max_a_p2p1_q2q1, max_a_p3p2_q3q2);
+    u8x16 cmp_I_m4 = max_a_p1p0_q1q0;
+    cmp_E = vec_adds(vec_sr(a_p1_q1, v1u8), cmp_E);
+    cmp_I_m8 = vec_and(cmp_I_m8, (u8x16)m8_16);
+    u8x16 cmp_I = vec_max(cmp_I_m4, cmp_I_m8);
+    const b8x16 ltE = vec_cmple(cmp_E, E);
+    const b8x16 ltI = vec_cmple(cmp_I, I);
+    b8x16 fm = vec_and(ltI, ltE);
+
+    fm = vec_and(fm, (b8x16)apply);
+    if (vec_all_eq(fm, zero))
+        return;
+
+    u8x16 cmp_flat8in = vec_max(max_a_p2p0_q2q0, max_a_p1p0_q1q0);
+    u8x16 cmp_flat8out = vec_max(max_a_p6p0_q6q0, max_a_p5p0_q5q0);
+
+    m8_16 = vec_and(m8_16, (b32x4)fm);
+    m16 = vec_and(m16, (b32x4)fm);
+
+    cmp_flat8in = vec_max(max_a_p3p0_q3q0, cmp_flat8in);
+    cmp_flat8out = vec_max(max_a_p4p0_q4q0, cmp_flat8out);
+    b8x16 flat8in = vec_cmple(cmp_flat8in, F);
+    b8x16 flat8out = vec_cmple(cmp_flat8out, F);
+    flat8in = vec_and(flat8in, (b8x16)m8_16);
+    flat8out = vec_and(flat8out, (b8x16)m16);
+
+    b8x16 apply_16 = vec_and(flat8out, flat8in);
+    b8x16 apply_8 = vec_andc(flat8in, flat8out);
+
+    UNPACK_16(p6)
+    UNPACK_16(p5)
+    UNPACK_16(p4)
+    UNPACK_16(p3)
+    UNPACK_16(p2)
+    UNPACK_16(p1)
+    UNPACK_16(p0)
+
+    b8x16 apply_4 = vec_nor(apply_16, apply_8);
+
+    UNPACK_16(q0)
+    UNPACK_16(q1)
+    UNPACK_16(q2)
+    UNPACK_16(q3)
+    UNPACK_16(q4)
+    UNPACK_16(q5)
+    UNPACK_16(q6)
+
+    if (vec_any_ne(apply_4, zero)) {
+        APPLY_4
+    }
+    if (vec_any_ne(apply_16, zero)) {
+        APPLY_16
+    }
+    if (vec_any_ne(apply_8, zero)) {
+        APPLY_8
+    }
+
+    vec_xst(p5, 0, p5d);
+    vec_xst(p4, 0, p4d);
+    vec_xst(p3, 0, p3d);
+    vec_xst(p2, 0, p2d);
+    vec_xst(p1, 0, p1d);
+    vec_xst(p0, 0, p0d);
+    vec_xst(q0, 0, q0d);
+    vec_xst(q1, 0, q1d);
+    vec_xst(q2, 0, q2d);
+    vec_xst(q3, 0, q3d);
+    vec_xst(q4, 0, q4d);
+    vec_xst(q5, 0, q5d);
+}
+
+#if defined(DAV1D_VSX)
+#define LPF(fn) BF(dav1d_lpf_##fn, vsx)
+#elif defined(DAV1D_PWR9)
+#define LPF(fn) BF(dav1d_lpf_##fn, pwr9)
+#endif
+
+void LPF(h_sb_y)(pixel *dst, const ptrdiff_t stride,
+                 const uint32_t *const vmask,
+                 const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                 const Av1FilterLUT *lut, const int h)
+{
+    unsigned vm = vmask[0] | vmask[1] | vmask[2];
+
+    u32x4 vm0 = vec_splats(vmask[0] | vmask[1] | vmask[2]);
+    u32x4 vm1 = vec_splats(vmask[1]);
+    u32x4 vm2 = vec_splats(vmask[2]);
+    u32x4 mm = (u32x4){1, 2, 4, 8};
+
+    const u8x16 sharp = vec_xl(0, (uint8_t *)lut->sharp);
+    const u8x16 s0 = vec_splat(sharp, 0);
+    const u8x16 s1 = vec_splat(sharp, 8);
+    const u32x4 v4u32 = vec_splat_u32(4);
+    const u32x4 zero = vec_splat_u32(0);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const u8x16 v2u8 = vec_splat_u8(2);
+    const u8x16 v4u8 = vec_splat_u8(4);
+    const uint8_t (*pl)[4] = &l[-1];
+
+    const u8x16 spread = (u8x16){
+        0x00, 0x00, 0x00, 0x00,
+        0x04, 0x04, 0x04, 0x04,
+        0x08, 0x08, 0x08, 0x08,
+        0x0c, 0x0c, 0x0c, 0x0c,
+    };
+
+    for (;
+        vm;
+        vm >>= 4,
+        mm = vec_sl(mm, v4u32),
+        dst += 4 * 4 * PXSTRIDE(stride),
+        pl += 4 * b4_stride) {
+        if (!(vm & 0x0f))
+            continue;
+        u32x4 la = (u32x4)vec_xl(0, (uint8_t *)pl);  // l[-1] l[0] ...
+        u32x4 lb = (u32x4)vec_xl(1 * 4 * b4_stride, (uint8_t *)pl);
+        u32x4 lc = (u32x4)vec_xl(2 * 4 * b4_stride, (uint8_t *)pl);
+        u32x4 ld = (u32x4)vec_xl(3 * 4 * b4_stride, (uint8_t *)pl);
+
+        u32x4 Lac = vec_mergeh(la, lc); // la[-1] lb[-1] la[0] lb[0]
+        u32x4 Lbd = vec_mergeh(lb, ld); // lc[-1] ld[-1] lc[0] ld[0]
+
+        u32x4 wd16 = vec_and(vm2, mm); // vmask[2] & [1,2,4,8]
+        u32x4 wd8 = vec_and(vm1, mm); // vmask[1] & [1,2,4,8]
+        u32x4 wd4 = vec_and(vm0, mm); // vm & [1,2,4,8]
+
+        u32x4 L_1 = (u32x4)vec_mergeh(Lac, Lbd); // la[-1] lb[-1] lc[-1] ld[-1]
+        u32x4 L_0 = (u32x4)vec_mergel(Lac, Lbd); // la[ 0] lb[ 0] lc[ 0] ld[ 0]
+
+        b8x16 mask = vec_cmpeq((u8x16)L_0, (u8x16)zero);
+
+        u32x4 L4 = (u32x4)vec_sel((u8x16)L_0, (u8x16)L_1, mask); // if !l[0][0] { l[-1][0] }
+
+        u8x16 L = (u8x16)vec_perm((u8x16)L4, (u8x16)L4, spread); // La La La La Lb Lb Lb Lb ...
+
+        b32x4 m16 = vec_cmpeq(wd16, mm);
+        b32x4 m8 = vec_cmpeq(wd8, mm);
+        b32x4 m4 = vec_cmpeq(wd4, mm);
+
+        b32x4 apply = vec_cmpne((u32x4)L, zero);
+
+        if (vec_all_eq((u32x4)L, zero))
+            continue;
+
+        u8x16 I = vec_sr(L, s0); // L >> sharp[0]
+        u8x16 H = vec_sr(L, v4u8);
+        I = vec_min(I, s1); // min(L >> sharp[0], sharp[1])
+        u8x16 E = vec_add(L, v2u8); // L + 2
+        I = vec_max(I, v1u8); // max(min(L >> sharp[0], sharp[1]), 1)
+        E = vec_add(E, E); // 2 * (L + 2)
+        E = vec_add(E, I); // 2 * (L + 2) + limit
+
+        apply = vec_and(m4, apply);
+
+        if (vec_any_ne(wd16, zero)) {
+            loop_filter_h_16_all(dst, E, I, H, PXSTRIDE(stride), apply, m8, m16);
+        } else if (vec_any_ne(wd8, zero)) {
+            loop_filter_h_8_all(dst, E, I, H, PXSTRIDE(stride), apply, m8);
+        } else { // wd4 == 0 already tested
+            loop_filter_h_4_all(dst, E, I, H, PXSTRIDE(stride), apply);
+        }
+    }
+}
+
+void LPF(v_sb_y)(pixel *dst, const ptrdiff_t stride,
+                 const uint32_t *const vmask,
+                 const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                 const Av1FilterLUT *lut, const int w)
+{
+    unsigned vm = vmask[0] | vmask[1] | vmask[2];
+
+    u32x4 vm0 = vec_splats(vmask[0] | vmask[1] | vmask[2]);
+    u32x4 vm1 = vec_splats(vmask[1]);
+    u32x4 vm2 = vec_splats(vmask[2]);
+
+    u8x16 sharp = vec_xl(0, (uint8_t *)lut->sharp);
+    u8x16 s0 = vec_splat(sharp, 0);
+    u8x16 s1 = vec_splat(sharp, 8);
+    u32x4 mm = (u32x4){1, 2, 4, 8};
+    u32x4 v4u32 = vec_splat_u32(4);
+    u32x4 zero = vec_splat_u32(0);
+    u8x16 v1u8 = vec_splat_u8(1);
+    u8x16 v2u8 = vec_splat_u8(2);
+    u8x16 v4u8 = vec_splat_u8(4);
+    const uint8_t (*pl)[4] = l;
+    const uint8_t (*plb4)[4] = l - b4_stride;
+    const u8x16 spread = (u8x16){
+        0x00, 0x00, 0x00, 0x00,
+        0x04, 0x04, 0x04, 0x04,
+        0x08, 0x08, 0x08, 0x08,
+        0x0c, 0x0c, 0x0c, 0x0c,
+    };
+
+    for (;
+        vm;
+        vm >>= 4,
+        mm = vec_sl(mm, v4u32),
+        dst += 4 * 4,
+        pl += 4,
+        plb4 += 4) {
+        if (!(vm & 0x0f))
+            continue;
+        u32x4 L_0  = (u32x4)vec_xl(0, (uint8_t *)pl);
+        u32x4 L_b4 = (u32x4)vec_xl(0, (uint8_t *)plb4);
+
+        u32x4 wd16 = vec_and(vm2, mm); // vmask[2] & [1,2,4,8]
+        u32x4 wd8 = vec_and(vm1, mm); // vmask[1] & [1,2,4,8]
+        u32x4 wd4 = vec_and(vm0, mm); // vm & [1,2,4,8]
+
+        b8x16 mask = vec_cmpeq((u8x16)L_0, (u8x16)zero);
+
+        u32x4 L4 = (u32x4)vec_sel((u8x16)L_0, (u8x16)L_b4, mask); // if !l[0][0] { l[-b4_stride][0] }
+
+        u8x16 L = (u8x16)vec_perm((u8x16)L4, (u8x16)L4, spread); // La La La La Lb Lb Lb Lb ...
+
+        b32x4 m16 = vec_cmpeq(wd16, mm);
+        b32x4 m8 = vec_cmpeq(wd8, mm);
+        b32x4 m4 = vec_cmpeq(wd4, mm);
+
+        b32x4 apply = vec_cmpne((u32x4)L, zero);
+
+        if (vec_all_eq((u32x4)L, zero))
+            continue;
+
+        u8x16 I = vec_sr(L, s0); // L >> sharp[0]
+        u8x16 H = vec_sr(L, v4u8);
+        I = vec_min(I, s1); // min(L >> sharp[0], sharp[1])
+        u8x16 E = vec_add(L, v2u8); // L + 2
+        I = vec_max(I, v1u8); // max(min(L >> sharp[0], sharp[1]), 1)
+        E = vec_add(E, E); // 2 * (L + 2)
+        E = vec_add(E, I); // 2 * (L + 2) + limit
+
+        apply = vec_and(apply, m4);
+
+        if (vec_any_ne(wd16, zero)) {
+            loop_filter_v_16_all(dst, E, I, H, PXSTRIDE(stride), apply, m8, m16);
+        } else if (vec_any_ne(wd8, zero)) {
+            loop_filter_v_8_all(dst, E, I, H, PXSTRIDE(stride), apply, m8);
+        } else {
+            loop_filter_v_4_all(dst, E, I, H, PXSTRIDE(stride), apply);
+        }
+
+    }
+}
+
+void LPF(h_sb_uv)(pixel *dst, const ptrdiff_t stride,
+                  const uint32_t *const vmask,
+                  const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                  const Av1FilterLUT *lut, const int h)
+{
+    unsigned vm = vmask[0] | vmask[1];
+    u32x4 vm0 = vec_splats(vm);
+    u32x4 vm1 = vec_splats(vmask[1]);
+    u32x4 mm = (u32x4){1, 2, 4, 8};
+
+    const u8x16 sharp = vec_xl(0, (uint8_t *)lut->sharp);
+    const u8x16 s0 = vec_splat(sharp, 0);
+    const u8x16 s1 = vec_splat(sharp, 8);
+    const u32x4 v4u32 = vec_splat_u32(4);
+    const u32x4 zero = vec_splat_u32(0);
+    const u8x16 v1u8 = vec_splat_u8(1);
+    const u8x16 v2u8 = vec_splat_u8(2);
+    const u8x16 v4u8 = vec_splat_u8(4);
+    const uint8_t (*pl)[4] = &l[-1];
+    const u8x16 spread = (u8x16){
+        0x00, 0x00, 0x00, 0x00,
+        0x04, 0x04, 0x04, 0x04,
+        0x08, 0x08, 0x08, 0x08,
+        0x0c, 0x0c, 0x0c, 0x0c,
+    };
+
+    for (;
+        vm;
+        vm >>= 4,
+        mm = vec_sl(mm, v4u32),
+        dst += 4 * 4 * PXSTRIDE(stride),
+        pl += 4 * b4_stride) {
+        if (!(vm & 0x0f))
+            continue;
+        u32x4 la = (u32x4)vec_xl(0, (uint8_t *)pl);  // l[-1] l[0] ...
+        u32x4 lb = (u32x4)vec_xl(1 * 4 * b4_stride, (uint8_t *)pl);
+        u32x4 lc = (u32x4)vec_xl(2 * 4 * b4_stride, (uint8_t *)pl);
+        u32x4 ld = (u32x4)vec_xl(3 * 4 * b4_stride, (uint8_t *)pl);
+
+        u32x4 Lac = vec_mergeh(la, lc); // la[-1] lb[-1] la[0] lb[0]
+        u32x4 Lbd = vec_mergeh(lb, ld); // lc[-1] ld[-1] lc[0] ld[0]
+
+        u32x4 wd6 = vec_and(vm1, mm); // vmask[1] & [1,2,4,8]
+        u32x4 wd4 = vec_and(vm0, mm); // vm & [1,2,4,8]
+
+        u32x4 L_1 = (u32x4)vec_mergeh(Lac, Lbd); // la[-1] lb[-1] lc[-1] ld[-1]
+        u32x4 L_0 = (u32x4)vec_mergel(Lac, Lbd); // la[ 0] lb[ 0] lc[ 0] ld[ 0]
+
+        b8x16 mask = vec_cmpeq((u8x16)L_0, (u8x16)zero);
+
+        u32x4 L4 = (u32x4)vec_sel((u8x16)L_0, (u8x16)L_1, mask); // if !l[0][0] { l[-1][0] }
+
+        u8x16 L = (u8x16)vec_perm((u8x16)L4, (u8x16)L4, spread); // La La La La Lb Lb Lb Lb ...
+
+        b32x4 m6 = vec_cmpeq(wd6, mm);
+        b32x4 m4 = vec_cmpeq(wd4, mm);
+
+        b32x4 apply = vec_cmpne((u32x4)L, zero);
+
+        if (vec_all_eq((u32x4)L, zero))
+            continue;
+
+        u8x16 I = vec_sr(L, s0); // L >> sharp[0]
+        u8x16 H = vec_sr(L, v4u8);
+        I = vec_min(I, s1); // min(L >> sharp[0], sharp[1])
+        u8x16 E = vec_add(L, v2u8); // L + 2
+        I = vec_max(I, v1u8); // max(min(L >> sharp[0], sharp[1]), 1)
+        E = vec_add(E, E); // 2 * (L + 2)
+        E = vec_add(E, I); // 2 * (L + 2) + limit
+
+        apply = vec_and(m4, apply);
+
+        if (vec_any_ne(wd6, zero)) {
+            loop_filter_h_6_all(dst, E, I, H, PXSTRIDE(stride), apply, m6);
+            // loop_filter_h_8
+        } else { // wd4 == 0 already tested
+            loop_filter_h_4_all(dst, E, I, H, PXSTRIDE(stride), apply);
+
+            // loop_filter_h_4
+        }
+
+    }
+}
+
+void LPF(v_sb_uv)(pixel *dst, const ptrdiff_t stride,
+                  const uint32_t *const vmask,
+                  const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                  const Av1FilterLUT *lut, const int w)
+{
+    unsigned vm = vmask[0] | vmask[1];
+
+    u32x4 vm0 = vec_splats(vm);
+    u32x4 vm1 = vec_splats(vmask[1]);
+
+    u8x16 sharp = vec_xl(0, (uint8_t *)lut->sharp);
+    u8x16 s0 = vec_splat(sharp, 0);
+    u8x16 s1 = vec_splat(sharp, 8);
+    u32x4 mm = (u32x4){1, 2, 4, 8};
+    u32x4 v4u32 = vec_splat_u32(4);
+    u32x4 zero = vec_splat_u32(0);
+    u8x16 v1u8 = vec_splat_u8(1);
+    u8x16 v2u8 = vec_splat_u8(2);
+    u8x16 v4u8 = vec_splat_u8(4);
+    const uint8_t (*pl)[4] = l;
+    const uint8_t (*plb4)[4] = l - b4_stride;
+    const u8x16 spread = (u8x16){
+        0x00, 0x00, 0x00, 0x00,
+        0x04, 0x04, 0x04, 0x04,
+        0x08, 0x08, 0x08, 0x08,
+        0x0c, 0x0c, 0x0c, 0x0c,
+    };
+
+    for (;
+        vm;
+        vm >>= 4,
+        mm = vec_sl(mm, v4u32),
+        dst += 4 * 4,
+        pl += 4,
+        plb4 += 4) {
+        if (!(vm & 0x0f))
+            continue;
+        u32x4 L_0  = (u32x4)vec_xl(0, (uint8_t *)pl);
+        u32x4 L_b4 = (u32x4)vec_xl(0, (uint8_t *)plb4);
+
+        u32x4 wd6 = vec_and(vm1, mm); // vmask[1] & [1,2,4,8]
+        u32x4 wd4 = vec_and(vm0, mm); // vm & [1,2,4,8]
+
+        b8x16 mask = vec_cmpeq((u8x16)L_0, (u8x16)zero);
+
+        u32x4 L4 = (u32x4)vec_sel((u8x16)L_0, (u8x16)L_b4, mask); // if !l[0][0] { l[-b4_stride][0] }
+
+        u8x16 L = (u8x16)vec_perm((u8x16)L4, (u8x16)L4, spread); // La La La La Lb Lb Lb Lb ...
+
+        b32x4 m6 = vec_cmpeq(wd6, mm);
+        b32x4 m4 = vec_cmpeq(wd4, mm);
+
+        b32x4 apply = vec_cmpne((u32x4)L, zero);
+
+        if (vec_all_eq((u32x4)L, zero))
+            continue;
+
+        u8x16 I = vec_sr(L, s0); // L >> sharp[0]
+        u8x16 H = vec_sr(L, v4u8);
+        I = vec_min(I, s1); // min(L >> sharp[0], sharp[1])
+        u8x16 E = vec_add(L, v2u8); // L + 2
+        I = vec_max(I, v1u8); // max(min(L >> sharp[0], sharp[1]), 1)
+        E = vec_add(E, E); // 2 * (L + 2)
+        E = vec_add(E, I); // 2 * (L + 2) + limit
+
+        apply = vec_and(apply, m4);
+
+        if (vec_any_ne(wd6, zero)) {
+            loop_filter_v_6_all(dst, E, I, H, PXSTRIDE(stride), apply, m6);
+        } else {
+            loop_filter_v_4_all(dst, E, I, H, PXSTRIDE(stride), apply);
+        }
+    }
+}
+
+#endif // BITDEPTH
diff --git a/media/libdav1d/src/src/ppc/looprestoration.h b/media/libdav1d/src/src/ppc/looprestoration.h
new file mode 100644
index 0000000000..614234abfc
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/looprestoration.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Michail Alvanos
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/intops.h"
+
+#include "src/cpu.h"
+#include "src/looprestoration.h"
+
+void dav1d_wiener_filter_vsx(uint8_t *p, const ptrdiff_t stride,
+                             const uint8_t (*const left)[4],
+                             const uint8_t *lpf,
+                             const int w, const int h,
+                             const LooprestorationParams *const params,
+                             const enum LrEdgeFlags edges);
+
+static ALWAYS_INLINE void loop_restoration_dsp_init_ppc(Dav1dLoopRestorationDSPContext *const c, const int bpc) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_PPC_CPU_FLAG_VSX)) return;
+
+#if BITDEPTH == 8
+    c->wiener[0] = c->wiener[1] = dav1d_wiener_filter_vsx;
+#endif
+}
diff --git a/media/libdav1d/src/src/ppc/looprestoration_tmpl.c b/media/libdav1d/src/src/ppc/looprestoration_tmpl.c
new file mode 100644
index 0000000000..76c1d07f80
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/looprestoration_tmpl.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Michail Alvanos
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/ppc/dav1d_types.h"
+#include "src/ppc/looprestoration.h"
+
+#if BITDEPTH == 8
+
+#define REST_UNIT_STRIDE (400)
+
+static inline i32x4 iclip_vec(i32x4 v, const i32x4 minv, const i32x4 maxv) {
+    v = vec_max(minv, v);
+    v = vec_min(maxv, v);
+    return v;
+}
+
+#define APPLY_FILTER_H(v, f, ssum1, ssum2) do {  \
+    i16x8 ktmp_u16_high = (i16x8) u8h_to_u16(v); \
+    i16x8 ktmp_u16_low  = (i16x8) u8l_to_u16(v); \
+    ssum1 = vec_madd(ktmp_u16_high, f, ssum1);   \
+    ssum2 = vec_madd(ktmp_u16_low, f, ssum2);    \
+} while (0)
+
+static void wiener_filter_h_vsx(int32_t *hor_ptr,
+                                uint8_t *tmp_ptr,
+                                const int16_t filterh[8],
+                                const int w, const int h)
+{
+    const i32x4 zerov = vec_splats(0);
+    const i32x4 seven_vec = vec_splats(7);
+    const i32x4 bitdepth_added_vec = vec_splats(1 << 14);
+    const i32x4 round_bits_vec = vec_splats(3);
+    const i32x4 rounding_off_vec = vec_splats(1<<2);
+    const i32x4 clip_limit_v = vec_splats((1 << 13) - 1);
+
+    i16x8 filterhvall = vec_vsx_ld(0, filterh);
+    i16x8 filterhv0 =  vec_splat( filterhvall, 0);
+    i16x8 filterhv1 =  vec_splat( filterhvall, 1);
+    i16x8 filterhv2 =  vec_splat( filterhvall, 2);
+    i16x8 filterhv3 =  vec_splat( filterhvall, 3);
+    i16x8 filterhv4 =  vec_splat( filterhvall, 4);
+    i16x8 filterhv5 =  vec_splat( filterhvall, 5);
+    i16x8 filterhv6 =  vec_splat( filterhvall, 6);
+
+    for (int j = 0; j < h + 6; j++) {
+        for (int i = 0; i < w; i+=16) {
+            i32x4 sum1 = bitdepth_added_vec;
+            i32x4 sum2 = bitdepth_added_vec;
+            i32x4 sum3 = bitdepth_added_vec;
+            i32x4 sum4 = bitdepth_added_vec;
+
+            u8x16 tmp_v0 = vec_ld(0, &tmp_ptr[i]);
+            u8x16 tmp_v7 = vec_ld(0, &tmp_ptr[i+16]);
+
+            u8x16 tmp_v1 = vec_sld( tmp_v7, tmp_v0, 15);
+            u8x16 tmp_v2 = vec_sld( tmp_v7, tmp_v0, 14);
+            u8x16 tmp_v3 = vec_sld( tmp_v7, tmp_v0, 13);
+            u8x16 tmp_v4 = vec_sld( tmp_v7, tmp_v0, 12);
+            u8x16 tmp_v5 = vec_sld( tmp_v7, tmp_v0, 11);
+            u8x16 tmp_v6 = vec_sld( tmp_v7, tmp_v0, 10);
+
+            u16x8 tmp_u16_high = u8h_to_u16(tmp_v3);
+            u16x8 tmp_u16_low  = u8l_to_u16(tmp_v3);
+
+            i32x4 tmp_expanded1 = i16h_to_i32(tmp_u16_high);
+            i32x4 tmp_expanded2 = i16l_to_i32(tmp_u16_high);
+            i32x4 tmp_expanded3 = i16h_to_i32(tmp_u16_low);
+            i32x4 tmp_expanded4 = i16l_to_i32(tmp_u16_low);
+
+            i16x8 ssum1 = (i16x8) zerov;
+            i16x8 ssum2 = (i16x8) zerov;
+
+            APPLY_FILTER_H(tmp_v0, filterhv0, ssum1, ssum2);
+            APPLY_FILTER_H(tmp_v1, filterhv1, ssum1, ssum2);
+            APPLY_FILTER_H(tmp_v2, filterhv2, ssum1, ssum2);
+            APPLY_FILTER_H(tmp_v3, filterhv3, ssum1, ssum2);
+            APPLY_FILTER_H(tmp_v4, filterhv4, ssum1, ssum2);
+            APPLY_FILTER_H(tmp_v5, filterhv5, ssum1, ssum2);
+            APPLY_FILTER_H(tmp_v6, filterhv6, ssum1, ssum2);
+
+            sum1 += i16h_to_i32(ssum1) + (tmp_expanded1 << seven_vec);
+            sum2 += i16l_to_i32(ssum1) + (tmp_expanded2 << seven_vec);
+            sum3 += i16h_to_i32(ssum2) + (tmp_expanded3 << seven_vec);
+            sum4 += i16l_to_i32(ssum2) + (tmp_expanded4 << seven_vec);
+
+            sum1 = (sum1 + rounding_off_vec) >> round_bits_vec;
+            sum2 = (sum2 + rounding_off_vec) >> round_bits_vec;
+            sum3 = (sum3 + rounding_off_vec) >> round_bits_vec;
+            sum4 = (sum4 + rounding_off_vec) >> round_bits_vec;
+
+            sum1 = iclip_vec(sum1, zerov, clip_limit_v);
+            sum2 = iclip_vec(sum2, zerov, clip_limit_v);
+            sum3 = iclip_vec(sum3, zerov, clip_limit_v);
+            sum4 = iclip_vec(sum4, zerov, clip_limit_v);
+
+            vec_st(sum1,  0, &hor_ptr[i]);
+            vec_st(sum2, 16, &hor_ptr[i]);
+            vec_st(sum3, 32, &hor_ptr[i]);
+            vec_st(sum4, 48, &hor_ptr[i]);
+        }
+        tmp_ptr += REST_UNIT_STRIDE;
+        hor_ptr += REST_UNIT_STRIDE;
+    }
+}
+
+static inline i16x8 iclip_u8_vec(i16x8 v) {
+    const i16x8 zerov = vec_splats((int16_t)0);
+    const i16x8 maxv = vec_splats((int16_t)255);
+    v = vec_max(zerov, v);
+    v = vec_min(maxv, v);
+    return v;
+}
+
+#define APPLY_FILTER_V(index, f) do { \
+    i32x4 v1 = vec_ld( 0, &hor[(j + index) * REST_UNIT_STRIDE + i]); \
+    i32x4 v2 = vec_ld(16, &hor[(j + index) * REST_UNIT_STRIDE + i]); \
+    i32x4 v3 = vec_ld(32, &hor[(j + index) * REST_UNIT_STRIDE + i]); \
+    i32x4 v4 = vec_ld(48, &hor[(j + index) * REST_UNIT_STRIDE + i]); \
+    sum1 = sum1 + v1 * f; \
+    sum2 = sum2 + v2 * f; \
+    sum3 = sum3 + v3 * f; \
+    sum4 = sum4 + v4 * f; \
+} while (0)
+
+#define LOAD_AND_APPLY_FILTER_V(sumpixelv, hor) do { \
+    i32x4 sum1 = round_vec; \
+    i32x4 sum2 = round_vec; \
+    i32x4 sum3 = round_vec; \
+    i32x4 sum4 = round_vec; \
+    APPLY_FILTER_V(0, filterv0); \
+    APPLY_FILTER_V(1, filterv1); \
+    APPLY_FILTER_V(2, filterv2); \
+    APPLY_FILTER_V(3, filterv3); \
+    APPLY_FILTER_V(4, filterv4); \
+    APPLY_FILTER_V(5, filterv5); \
+    APPLY_FILTER_V(6, filterv6); \
+    sum1 = sum1 >> round_bits_vec; \
+    sum2 = sum2 >> round_bits_vec; \
+    sum3 = sum3 >> round_bits_vec; \
+    sum4 = sum4 >> round_bits_vec; \
+    i16x8 sum_short_packed_1 = (i16x8) vec_pack(sum1, sum2); \
+    i16x8 sum_short_packed_2 = (i16x8) vec_pack(sum3, sum4); \
+    sum_short_packed_1 = iclip_u8_vec(sum_short_packed_1); \
+    sum_short_packed_2 = iclip_u8_vec(sum_short_packed_2); \
+    sum_pixel = (u8x16) vec_pack(sum_short_packed_1, sum_short_packed_2); \
+} while (0)
+
+static inline void wiener_filter_v_vsx(uint8_t *p,
+                                       const ptrdiff_t stride,
+                                       const int32_t *hor,
+                                       const int16_t filterv[8],
+                                       const int w, const int h)
+{
+    const i32x4 round_bits_vec = vec_splats(11);
+    const i32x4 round_vec = vec_splats((1 << 10) - (1 << 18));
+
+    i32x4 filterv0 =  vec_splats((int32_t) filterv[0]);
+    i32x4 filterv1 =  vec_splats((int32_t) filterv[1]);
+    i32x4 filterv2 =  vec_splats((int32_t) filterv[2]);
+    i32x4 filterv3 =  vec_splats((int32_t) filterv[3]);
+    i32x4 filterv4 =  vec_splats((int32_t) filterv[4]);
+    i32x4 filterv5 =  vec_splats((int32_t) filterv[5]);
+    i32x4 filterv6 =  vec_splats((int32_t) filterv[6]);
+
+    for (int j = 0; j < h; j++) {
+        for (int i = 0; i <(w-w%16); i += 16) {
+            u8x16 sum_pixel;
+            LOAD_AND_APPLY_FILTER_V(sum_pixel, hor);
+            vec_vsx_st(sum_pixel, 0, &p[j * PXSTRIDE(stride) + i]);
+        }
+        // remaining loop
+        if (w & 0xf){
+            int i=w-w%16;
+            ALIGN_STK_16(uint8_t, tmp_out, 16,);
+            u8x16 sum_pixel;
+
+            LOAD_AND_APPLY_FILTER_V(sum_pixel, hor);
+            vec_vsx_st(sum_pixel, 0, tmp_out);
+
+            for (int k=0; ifilter;
+
+    // Wiener filtering is applied to a maximum stripe height of 64 + 3 pixels
+    // of padding above and below
+    ALIGN_STK_16(uint8_t, tmp, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE,);
+    padding(tmp, p, stride, left, lpf, w, h, edges);
+    ALIGN_STK_16(int32_t, hor, 70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE + 64,);
+
+    wiener_filter_h_vsx(hor, tmp, filter[0], w, h);
+    wiener_filter_v_vsx(p, stride, hor, filter[1], w, h);
+}
+#endif
diff --git a/media/libdav1d/src/src/ppc/mc.h b/media/libdav1d/src/src/ppc/mc.h
new file mode 100644
index 0000000000..44fa142ad4
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/mc.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/mc.h"
+
+decl_blend_fn(BF(dav1d_blend, pwr9));
+decl_blend_dir_fn(BF(dav1d_blend_h, pwr9));
+decl_blend_dir_fn(BF(dav1d_blend_v, pwr9));
+
+static ALWAYS_INLINE void mc_dsp_init_ppc(Dav1dMCDSPContext *const c) {
+  const unsigned flags = dav1d_get_cpu_flags();
+
+  if (!(flags & DAV1D_PPC_CPU_FLAG_PWR9)) return;
+
+#if BITDEPTH == 8
+  c->blend = BF(dav1d_blend, pwr9);
+  c->blend_h = BF(dav1d_blend_h, pwr9);
+  c->blend_v = BF(dav1d_blend_v, pwr9);
+#endif
+
+}
diff --git a/media/libdav1d/src/src/ppc/mc_tmpl.c b/media/libdav1d/src/src/ppc/mc_tmpl.c
new file mode 100644
index 0000000000..e00058e26c
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/mc_tmpl.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/attributes.h"
+#include "src/ppc/mc.h"
+#include "src/tables.h"
+#include "src/ppc/dav1d_types.h"
+
+#if BITDEPTH == 8
+
+#define blend_px(a, b, m) (((a * (64 - m) + b * m) + 32) >> 6)
+
+typedef void (*blend_line)(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride);
+
+#define BLEND_LINES4(d0_u16, d1_u16, d2_u16, d3_u16, ab0, ab1, ab2, ab3, nm_m0, nm_m1, nm_m2, nm_m3) \
+{ \
+    u16x8 anm0 = vec_mule(ab0, nm_m0); \
+    u16x8 anm1 = vec_mule(ab1, nm_m1); \
+    u16x8 anm2 = vec_mule(ab2, nm_m2); \
+    u16x8 anm3 = vec_mule(ab3, nm_m3); \
+\
+    u16x8 bm0 = vec_mulo(ab0, nm_m0); \
+    u16x8 bm1 = vec_mulo(ab1, nm_m1); \
+    u16x8 bm2 = vec_mulo(ab2, nm_m2); \
+    u16x8 bm3 = vec_mulo(ab3, nm_m3); \
+\
+    d0_u16 = vec_add(anm0, bm0); \
+    d1_u16 = vec_add(anm1, bm1); \
+    d2_u16 = vec_add(anm2, bm2); \
+    d3_u16 = vec_add(anm3, bm3); \
+\
+    d0_u16 = vec_add(d0_u16, vec_splats((uint16_t)32)); \
+    d1_u16 = vec_add(d1_u16, vec_splats((uint16_t)32)); \
+    d2_u16 = vec_add(d2_u16, vec_splats((uint16_t)32)); \
+    d3_u16 = vec_add(d3_u16, vec_splats((uint16_t)32)); \
+\
+    d0_u16 = vec_sr(d0_u16, vec_splat_u16(6)); \
+    d1_u16 = vec_sr(d1_u16, vec_splat_u16(6)); \
+    d2_u16 = vec_sr(d2_u16, vec_splat_u16(6)); \
+    d3_u16 = vec_sr(d3_u16, vec_splat_u16(6)); \
+}
+
+#define BLEND_LINES3(d0_u16, d1_u16, d2_u16, ab0, ab1, ab2, nm_m0, nm_m1, nm_2) \
+{ \
+    u16x8 anm0 = vec_mule(ab0, nm_m0); \
+    u16x8 anm1 = vec_mule(ab1, nm_m1); \
+    u16x8 anm2 = vec_mule(ab2, nm_m2); \
+\
+    u16x8 bm0 = vec_mulo(ab0, nm_m0); \
+    u16x8 bm1 = vec_mulo(ab1, nm_m1); \
+    u16x8 bm2 = vec_mulo(ab2, nm_m2); \
+\
+    d0_u16 = vec_add(anm0, bm0); \
+    d1_u16 = vec_add(anm1, bm1); \
+    d2_u16 = vec_add(anm2, bm2); \
+\
+    d0_u16 = vec_add(d0_u16, vec_splats((uint16_t)32)); \
+    d1_u16 = vec_add(d1_u16, vec_splats((uint16_t)32)); \
+    d2_u16 = vec_add(d2_u16, vec_splats((uint16_t)32)); \
+\
+    d0_u16 = vec_sr(d0_u16, vec_splat_u16(6)); \
+    d1_u16 = vec_sr(d1_u16, vec_splat_u16(6)); \
+    d2_u16 = vec_sr(d2_u16, vec_splat_u16(6)); \
+}
+
+#define BLEND_LINES2(d0_u16, d1_u16, ab0, ab1, nm_m0, nm_m1) \
+{ \
+    u16x8 anm0 = vec_mule(ab0, nm_m0); \
+    u16x8 anm1 = vec_mule(ab1, nm_m1); \
+\
+    u16x8 bm0 = vec_mulo(ab0, nm_m0); \
+    u16x8 bm1 = vec_mulo(ab1, nm_m1); \
+\
+    d0_u16 = vec_add(anm0, bm0); \
+    d1_u16 = vec_add(anm1, bm1); \
+\
+    d0_u16 = vec_add(d0_u16, vec_splats((uint16_t)32)); \
+    d1_u16 = vec_add(d1_u16, vec_splats((uint16_t)32)); \
+\
+    d0_u16 = vec_sr(d0_u16, vec_splat_u16(6)); \
+    d1_u16 = vec_sr(d1_u16, vec_splat_u16(6)); \
+}
+
+static void blend4(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    u8x16 v64u8 = vec_splats((uint8_t)64);
+    u8x16 a0 = vec_xl(0, dst);
+    u8x16 a1 = vec_xl(0, dst + stride);
+    u8x16 a2 = vec_xl(0, dst + 2 * stride);
+    u8x16 a3 = vec_xl(0, dst + 3 * stride);
+    u8x16 m0 = vec_xl(0, mask);
+    u8x16 m1 = vec_xl(0, mask + 4);
+    u8x16 m2 = vec_xl(0, mask + 2 * 4);
+    u8x16 m3 = vec_xl(0, mask + 3 * 4);
+    u8x16 b0 = vec_xl(0, tmp);
+    u8x16 b1 = vec_xl(0, tmp + 4);
+    u8x16 b2 = vec_xl(0, tmp + 2 * 4);
+    u8x16 b3 = vec_xl(0, tmp + 3 * 4);
+
+    u8x16 nm0 = vec_sub(v64u8, m0);
+    u8x16 nm1 = vec_sub(v64u8, m1);
+    u8x16 nm2 = vec_sub(v64u8, m2);
+    u8x16 nm3 = vec_sub(v64u8, m3);
+
+    u8x16 ab0 = vec_mergeh(a0, b0); // a even, b odd
+    u8x16 ab1 = vec_mergeh(a1, b1); // a even, b odd
+    u8x16 ab2 = vec_mergeh(a2, b2); // a even, b odd
+    u8x16 ab3 = vec_mergeh(a3, b3); // a even, b odd
+    u8x16 nm_m0 = vec_mergeh(nm0, m0);
+    u8x16 nm_m1 = vec_mergeh(nm1, m1);
+    u8x16 nm_m2 = vec_mergeh(nm2, m2);
+    u8x16 nm_m3 = vec_mergeh(nm3, m3);
+
+    u16x8 d0_u16, d1_u16, d2_u16, d3_u16;
+
+    BLEND_LINES4(d0_u16, d1_u16, d2_u16, d3_u16, ab0, ab1, ab2, ab3, nm_m0, nm_m1, nm_m2, nm_m3);
+
+    u8x16 d0 = (u8x16)vec_pack(d0_u16, d0_u16);
+    u8x16 d1 = (u8x16)vec_pack(d1_u16, d1_u16);
+    u8x16 d2 = (u8x16)vec_pack(d2_u16, d2_u16);
+    u8x16 d3 = (u8x16)vec_pack(d3_u16, d3_u16);
+
+    vec_xst_len(d0, dst, 4);
+    vec_xst_len(d1, dst + stride, 4);
+    vec_xst_len(d2, dst + 2 * stride, 4);
+    vec_xst_len(d3, dst + 3 * stride, 4);
+}
+
+static void blend8(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    u8x16 v64u8 = vec_splats((uint8_t)64);
+    u8x16 a0 = vec_xl(0, dst);
+    u8x16 a1 = vec_xl(0, dst + stride);
+    u8x16 a2 = vec_xl(0, dst + 2 * stride);
+    u8x16 a3 = vec_xl(0, dst + 3 * stride);
+    u8x16 m0 = vec_xl(0, mask);
+    u8x16 m1 = vec_xl(0, mask + 8);
+    u8x16 m2 = vec_xl(0, mask + 2 * 8);
+    u8x16 m3 = vec_xl(0, mask + 3 * 8);
+    u8x16 b0 = vec_xl(0, tmp);
+    u8x16 b1 = vec_xl(0, tmp + 8);
+    u8x16 b2 = vec_xl(0, tmp + 2 * 8);
+    u8x16 b3 = vec_xl(0, tmp + 3 * 8);
+
+    u8x16 nm0 = vec_sub(v64u8, m0);
+    u8x16 nm1 = vec_sub(v64u8, m1);
+    u8x16 nm2 = vec_sub(v64u8, m2);
+    u8x16 nm3 = vec_sub(v64u8, m3);
+
+    u8x16 ab0 = vec_mergeh(a0, b0); // a even, b odd
+    u8x16 ab1 = vec_mergeh(a1, b1); // a even, b odd
+    u8x16 ab2 = vec_mergeh(a2, b2); // a even, b odd
+    u8x16 ab3 = vec_mergeh(a3, b3); // a even, b odd
+    u8x16 nm_m0 = vec_mergeh(nm0, m0);
+    u8x16 nm_m1 = vec_mergeh(nm1, m1);
+    u8x16 nm_m2 = vec_mergeh(nm2, m2);
+    u8x16 nm_m3 = vec_mergeh(nm3, m3);
+
+    u16x8 d0_u16, d1_u16, d2_u16, d3_u16;
+
+    BLEND_LINES4(d0_u16, d1_u16, d2_u16, d3_u16, ab0, ab1, ab2, ab3, nm_m0, nm_m1, nm_m2, nm_m3);
+
+    u8x16 d0 = (u8x16)vec_pack(d0_u16, d0_u16);
+    u8x16 d1 = (u8x16)vec_pack(d1_u16, d1_u16);
+    u8x16 d2 = (u8x16)vec_pack(d2_u16, d2_u16);
+    u8x16 d3 = (u8x16)vec_pack(d3_u16, d3_u16);
+
+    vec_xst_len(d0, dst, 8);
+    vec_xst_len(d1, dst + stride, 8);
+    vec_xst_len(d2, dst + 2 * stride, 8);
+    vec_xst_len(d3, dst + 3 * stride, 8);
+}
+
+static inline void blend16_lines(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride, int mstride)
+{
+    u8x16 v64u8 = vec_splats((uint8_t)64);
+    u8x16 a0 = vec_xl(0, dst);
+    u8x16 a1 = vec_xl(0, dst + stride);
+    u8x16 a2 = vec_xl(0, dst + 2 * stride);
+    u8x16 a3 = vec_xl(0, dst + 3 * stride);
+    u8x16 m0 = vec_xl(0, mask);
+    u8x16 m1 = vec_xl(0, mask + mstride);
+    u8x16 m2 = vec_xl(0, mask + 2 * mstride);
+    u8x16 m3 = vec_xl(0, mask + 3 * mstride);
+    u8x16 b0 = vec_xl(0, tmp);
+    u8x16 b1 = vec_xl(0, tmp + mstride);
+    u8x16 b2 = vec_xl(0, tmp + 2 * mstride);
+    u8x16 b3 = vec_xl(0, tmp + 3 * mstride);
+
+    u8x16 nm0 = vec_sub(v64u8, m0);
+    u8x16 nm1 = vec_sub(v64u8, m1);
+    u8x16 nm2 = vec_sub(v64u8, m2);
+    u8x16 nm3 = vec_sub(v64u8, m3);
+
+    u8x16 ab0 = vec_mergeh(a0, b0);
+    u8x16 ab1 = vec_mergeh(a1, b1);
+    u8x16 ab2 = vec_mergeh(a2, b2);
+    u8x16 ab3 = vec_mergeh(a3, b3);
+
+    u8x16 nm_m0 = vec_mergeh(nm0, m0);
+    u8x16 nm_m1 = vec_mergeh(nm1, m1);
+    u8x16 nm_m2 = vec_mergeh(nm2, m2);
+    u8x16 nm_m3 = vec_mergeh(nm3, m3);
+
+    u16x8 d0h_u16, d1h_u16, d2h_u16, d3h_u16;
+    u16x8 d0l_u16, d1l_u16, d2l_u16, d3l_u16;
+
+    BLEND_LINES4(d0h_u16, d1h_u16, d2h_u16, d3h_u16, ab0, ab1, ab2, ab3, nm_m0, nm_m1, nm_m2, nm_m3)
+
+    ab0 = vec_mergel(a0, b0);
+    ab1 = vec_mergel(a1, b1);
+    ab2 = vec_mergel(a2, b2);
+    ab3 = vec_mergel(a3, b3);
+
+    nm_m0 = vec_mergel(nm0, m0);
+    nm_m1 = vec_mergel(nm1, m1);
+    nm_m2 = vec_mergel(nm2, m2);
+    nm_m3 = vec_mergel(nm3, m3);
+
+    BLEND_LINES4(d0l_u16, d1l_u16, d2l_u16, d3l_u16, ab0, ab1, ab2, ab3, nm_m0, nm_m1, nm_m2, nm_m3)
+
+    u8x16 d0 = (u8x16)vec_pack(d0h_u16, d0l_u16);
+    u8x16 d1 = (u8x16)vec_pack(d1h_u16, d1l_u16);
+    u8x16 d2 = (u8x16)vec_pack(d2h_u16, d2l_u16);
+    u8x16 d3 = (u8x16)vec_pack(d3h_u16, d3l_u16);
+
+    vec_xst(d0, 0,dst);
+    vec_xst(d1, 0,dst + stride);
+    vec_xst(d2, 0,dst + 2 * stride);
+    vec_xst(d3, 0,dst + 3 * stride);
+}
+
+static void blend16(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    blend16_lines(dst, tmp, mask, stride, 16);
+}
+
+static void blend32(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    for (int i = 0; i < 2; i++, dst += 16, tmp += 16, mask += 16) {
+        blend16_lines(dst, tmp, mask, stride, 32);
+    }
+}
+
+static blend_line blend_funcs[4] = {
+    blend4, blend8, blend16, blend32
+};
+
+void dav1d_blend_8bpc_pwr9(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                           const int w, int h, const uint8_t *mask)
+{
+    assert(w <= 32);
+    blend_line blend = blend_funcs[ctz(w) - 2];
+
+    for (int y = 0; y < h; y+=4) {
+        blend(dst, tmp, mask, PXSTRIDE(dst_stride));
+        dst += 4 * PXSTRIDE(dst_stride);
+        tmp += 4 * w;
+        mask += 4 * w;
+    }
+}
+
+static inline void blend_v_h(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride, int mstride, int l)
+{
+    u8x16 v64u8 = vec_splats((uint8_t)64);
+    u8x16 a0 = vec_xl(0, dst);
+    u8x16 a1 = vec_xl(0, dst + stride);
+    u8x16 m0 = vec_xl(0, mask);
+    u8x16 b0 = vec_xl(0, tmp);
+    u8x16 b1 = vec_xl(0, tmp + mstride);
+
+    u8x16 nm0 = vec_sub(v64u8, m0);
+
+    u8x16 ab0 = vec_mergeh(a0, b0); // a even, b odd
+    u8x16 ab1 = vec_mergeh(a1, b1); // a even, b odd
+    u8x16 nm_m0 = vec_mergeh(nm0, m0);
+
+    u16x8 d0_u16, d1_u16;
+
+    BLEND_LINES2(d0_u16, d1_u16, ab0, ab1, nm_m0, nm_m0);
+
+    u8x16 d0 = (u8x16)vec_pack(d0_u16, d0_u16);
+    u8x16 d1 = (u8x16)vec_pack(d1_u16, d1_u16);
+
+    vec_xst_len(d0, dst, l);
+    vec_xst_len(d1, dst + stride, l);
+}
+
+static inline void blend_v_hl(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride, int mstride, int l)
+{
+    u8x16 v64u8 = vec_splats((uint8_t)64);
+    u8x16 a0 = vec_xl(0, dst);
+    u8x16 a1 = vec_xl(0, dst + stride);
+    u8x16 m0 = vec_xl(0, mask);
+    u8x16 b0 = vec_xl(0, tmp);
+    u8x16 b1 = vec_xl(0, tmp + mstride);
+
+    u8x16 nm0 = vec_sub(v64u8, m0);
+
+    u8x16 ab0 = vec_mergeh(a0, b0);
+    u8x16 ab1 = vec_mergeh(a1, b1);
+
+    u8x16 nm_m0 = vec_mergeh(nm0, m0);
+
+    u16x8 d0h_u16, d1h_u16;
+    u16x8 d0l_u16, d1l_u16;
+
+    BLEND_LINES2(d0h_u16, d1h_u16, ab0, ab1, nm_m0, nm_m0)
+
+    ab0 = vec_mergel(a0, b0);
+    ab1 = vec_mergel(a1, b1);
+
+    nm_m0 = vec_mergel(nm0, m0);
+
+    BLEND_LINES2(d0l_u16, d1l_u16, ab0, ab1,nm_m0, nm_m0)
+
+    u8x16 d0 = (u8x16)vec_pack(d0h_u16, d0l_u16);
+    u8x16 d1 = (u8x16)vec_pack(d1h_u16, d1l_u16);
+
+    vec_xst_len(d0, dst, l);
+    vec_xst_len(d1, dst + stride, l);
+}
+
+static void blend_v3(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    blend_v_h(dst, tmp, mask, stride, 4, 3);
+}
+
+static void blend_v6(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    blend_v_h(dst, tmp, mask, stride, 8, 6);
+}
+
+static void blend_v12(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    blend_v_hl(dst, tmp, mask, stride, 16, 12);
+}
+
+static void blend_v24(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    blend_v_hl(dst, tmp, mask, stride, 32, 16);
+    blend_v_h(dst + 16, tmp + 16, mask + 16, stride, 32, 8);
+}
+
+static void blend_v1(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride)
+{
+    dst[0] = blend_px(dst[0], tmp[0], mask[0]);
+    dst[stride] = blend_px(dst[stride], tmp[2], mask[0]);
+}
+
+static blend_line blend_v_funcs[5] = {
+    blend_v1, blend_v3, blend_v6, blend_v12, blend_v24
+};
+
+void dav1d_blend_v_8bpc_pwr9(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                             const int w, int h)
+{
+    const uint8_t *const mask = &dav1d_obmc_masks[w];
+
+    assert(w <= 32);
+    blend_line blend = blend_v_funcs[ctz(w) - 1];
+
+    for (int y = 0; y < h; y+=2) {
+        blend(dst, tmp, mask, PXSTRIDE(dst_stride));
+
+        dst += 2 * PXSTRIDE(dst_stride);
+        tmp += 2 * w;
+    }
+}
+
+static inline void blend_h_h(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride, int mstride, int l)
+{
+    u8x16 v64u8 = vec_splats((uint8_t)64);
+    u8x16 a0 = vec_xl(0, dst);
+    u8x16 a1 = vec_xl(0, dst + stride);
+    u8x16 a2 = vec_xl(0, dst + 2 * stride);
+    u8x16 m = vec_xl(0, mask);
+    u8x16 b0 = vec_xl(0, tmp);
+    u8x16 b1 = vec_xl(0, tmp + mstride);
+    u8x16 b2 = vec_xl(0, tmp + 2 * mstride);
+    u8x16 m0 = vec_splat(m, 0);
+    u8x16 m1 = vec_splat(m, 1);
+    u8x16 m2 = vec_splat(m, 2);
+
+    u8x16 nm0 = vec_sub(v64u8, m0);
+    u8x16 nm1 = vec_sub(v64u8, m1);
+    u8x16 nm2 = vec_sub(v64u8, m2);
+
+    u8x16 ab0 = vec_mergeh(a0, b0); // a even, b odd
+    u8x16 ab1 = vec_mergeh(a1, b1); // a even, b odd
+    u8x16 ab2 = vec_mergeh(a2, b2); // a even, b odd
+    u8x16 nm_m0 = vec_mergeh(nm0, m0);
+    u8x16 nm_m1 = vec_mergeh(nm1, m1);
+    u8x16 nm_m2 = vec_mergeh(nm2, m2);
+
+    u16x8 d0_u16, d1_u16, d2_u16;
+
+    BLEND_LINES3(d0_u16, d1_u16, d2_u16, ab0, ab1, ab2, nm_m0, nm_m1, nm_m2);
+
+    u8x16 d0 = (u8x16)vec_pack(d0_u16, d0_u16);
+    u8x16 d1 = (u8x16)vec_pack(d1_u16, d1_u16);
+    u8x16 d2 = (u8x16)vec_pack(d2_u16, d2_u16);
+
+    vec_xst_len(d0, dst, l);
+    vec_xst_len(d1, dst + stride, l);
+    vec_xst_len(d2, dst + 2 * stride, l);
+}
+
+static inline void blend_h_hl(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride, int mstride)
+{
+    u8x16 v64u8 = vec_splats((uint8_t)64);
+    u8x16 a0 = vec_xl(0, dst);
+    u8x16 a1 = vec_xl(0, dst + stride);
+    u8x16 a2 = vec_xl(0, dst + 2 * stride);
+    u8x16 m = vec_xl(0, mask);
+    u8x16 b0 = vec_xl(0, tmp);
+    u8x16 b1 = vec_xl(0, tmp + mstride);
+    u8x16 b2 = vec_xl(0, tmp + 2 * mstride);
+    u8x16 m0 = vec_splat(m, 0);
+    u8x16 m1 = vec_splat(m, 1);
+    u8x16 m2 = vec_splat(m, 2);
+
+    u8x16 nm0 = vec_sub(v64u8, m0);
+    u8x16 nm1 = vec_sub(v64u8, m1);
+    u8x16 nm2 = vec_sub(v64u8, m2);
+
+    u8x16 ab0 = vec_mergeh(a0, b0);
+    u8x16 ab1 = vec_mergeh(a1, b1);
+    u8x16 ab2 = vec_mergeh(a2, b2);
+
+    u8x16 nm_m0 = vec_mergeh(nm0, m0);
+    u8x16 nm_m1 = vec_mergeh(nm1, m1);
+    u8x16 nm_m2 = vec_mergeh(nm2, m2);
+
+    u16x8 d0h_u16, d1h_u16, d2h_u16;
+    u16x8 d0l_u16, d1l_u16, d2l_u16;
+
+    BLEND_LINES3(d0h_u16, d1h_u16, d2h_u16,  ab0, ab1, ab2, nm_m0, nm_m1, nm_m2)
+
+    ab0 = vec_mergel(a0, b0);
+    ab1 = vec_mergel(a1, b1);
+    ab2 = vec_mergel(a2, b2);
+
+    nm_m0 = vec_mergel(nm0, m0);
+    nm_m1 = vec_mergel(nm1, m1);
+    nm_m2 = vec_mergel(nm2, m2);
+
+    BLEND_LINES3(d0l_u16, d1l_u16, d2l_u16, ab0, ab1, ab2, nm_m0, nm_m1, nm_m2)
+
+    u8x16 d0 = (u8x16)vec_pack(d0h_u16, d0l_u16);
+    u8x16 d1 = (u8x16)vec_pack(d1h_u16, d1l_u16);
+    u8x16 d2 = (u8x16)vec_pack(d2h_u16, d2l_u16);
+
+    vec_xst(d0, 0, dst);
+    vec_xst(d1, 0,dst + stride);
+    vec_xst(d2, 0,dst + 2 * stride);
+}
+
+static void blend_h2(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride) {
+    for (int y = 0; y < 3; y++) {
+        const int m = *mask++;
+        for (int x = 0; x < 2; x++) {
+            dst[x] = blend_px(dst[x], tmp[x], m);
+        }
+        dst += stride;
+        tmp += 2;
+    }
+}
+
+static void blend_h4(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride) {
+    blend_h_h(dst, tmp, mask, stride, 4, 4);
+}
+
+static void blend_h8(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride) {
+    blend_h_h(dst, tmp, mask, stride, 8, 8);
+}
+
+static void blend_h16(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride) {
+    blend_h_hl(dst, tmp, mask, stride, 16);
+}
+
+static void blend_h32(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride) {
+    blend_h_hl(dst, tmp, mask, stride, 32);
+    blend_h_hl(dst + 16, tmp + 16, mask, stride, 32);
+}
+
+static void blend_h64(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride) {
+    blend_h_hl(dst, tmp, mask, stride, 64);
+    blend_h_hl(dst + 16, tmp + 16, mask, stride, 64);
+    blend_h_hl(dst + 32, tmp + 32, mask, stride, 64);
+    blend_h_hl(dst + 48, tmp + 48, mask, stride, 64);
+}
+
+static void blend_h128(uint8_t *dst, const uint8_t *tmp, const uint8_t *mask, int stride) {
+    for (int i = 0; i < 2; i++, dst += 64, tmp += 64) {
+        blend_h_hl(dst, tmp, mask, stride, 128);
+        blend_h_hl(dst + 16, tmp + 16, mask, stride, 128);
+        blend_h_hl(dst + 32, tmp + 32, mask, stride, 128);
+        blend_h_hl(dst + 48, tmp + 48, mask, stride, 128);
+    }
+}
+
+static blend_line blend_h_funcs[7] = {
+    blend_h2, blend_h4, blend_h8, blend_h16, blend_h32, blend_h64, blend_h128
+};
+
+void dav1d_blend_h_8bpc_pwr9(pixel *dst, const ptrdiff_t dst_stride, const pixel *tmp,
+                             const int w, int h)
+{
+    const uint8_t *mask = &dav1d_obmc_masks[h];
+    h = (h * 3) >> 2;
+
+    assert(w <= 128);
+    blend_line blend = blend_h_funcs[ctz(w) - 1];
+
+    if (h == 1) {
+        const int m = *mask++;
+        for (int x = 0; x < w; x++) {
+            dst[x] = blend_px(dst[x], tmp[x], m);
+        }
+    } else
+    for (int y = 0; y < h; y+=3) {
+        blend(dst, tmp, mask, PXSTRIDE(dst_stride));
+        dst += 3 * PXSTRIDE(dst_stride);
+        tmp += 3 * w;
+        mask += 3;
+    }
+}
+
+#endif // BITDEPTH
diff --git a/media/libdav1d/src/src/ppc/utils.h b/media/libdav1d/src/src/ppc/utils.h
new file mode 100644
index 0000000000..3b0a5445bc
--- /dev/null
+++ b/media/libdav1d/src/src/ppc/utils.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Luca Barbato
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_PPC_UTILS_H
+#define DAV1D_SRC_PPC_UTILS_H
+
+#include "src/ppc/dav1d_types.h"
+
+#define assert_eq(a, b) \
+    if ((a) != (b)) \
+        printf("%d: %d vs %d\n", __LINE__, a, b); \
+    assert((a) == (b));
+
+#define MERGE_I32(a, b, h, l) \
+{ \
+    h = vec_mergeh(a, b); \
+    l = vec_mergel(a, b); \
+}
+
+#define DECLARE_MERGE_I32(a, b, h, l) \
+    i32x4 h, l; \
+    MERGE_I32(a, b, h, l)
+
+
+// Transpose a 4x4 matrix of i32x4 vectors
+#define TRANSPOSE4_I32(c0, c1, c2, c3) \
+{ \
+    DECLARE_MERGE_I32(c0, c2, m02h, m02l) \
+    DECLARE_MERGE_I32(c1, c3, m13h, m13l) \
+\
+    MERGE_I32(m02h, m13h, c0, c1) \
+    MERGE_I32(m02l, m13l, c2, c3) \
+}
+
+// Transpose a 8x8 matrix of i32x4 vectors
+#define TRANSPOSE8_I32(c0, c1, c2, c3, c4, c5, c6, c7, \
+                       c8, c9, cA, cB, cC, cD, cE, cF) \
+{ \
+    DECLARE_MERGE_I32(c0, c2, m02h, m02l) \
+    DECLARE_MERGE_I32(c1, c3, m13h, m13l) \
+    DECLARE_MERGE_I32(c4, c6, m46h, m46l) \
+    DECLARE_MERGE_I32(c5, c7, m57h, m57l) \
+    DECLARE_MERGE_I32(c8, cA, m8Ah, m8Al) \
+    DECLARE_MERGE_I32(c9, cB, m9Bh, m9Bl) \
+    DECLARE_MERGE_I32(cC, cE, mCEh, mCEl) \
+    DECLARE_MERGE_I32(cD, cF, mDFh, mDFl) \
+\
+    MERGE_I32(m02h, m13h, c0, c1) \
+    MERGE_I32(m02l, m13l, c2, c3) \
+    MERGE_I32(m46h, m57h, c8, c9) \
+    MERGE_I32(m46l, m57l, cA, cB) \
+    MERGE_I32(m8Ah, m9Bh, c4, c5) \
+    MERGE_I32(m8Al, m9Bl, c6, c7) \
+    MERGE_I32(mCEh, mDFh, cC, cD) \
+    MERGE_I32(mCEl, mDFl, cE, cF) \
+}
+
+// Transpose a 4x16 matrix of i32x4 vectors
+#define TRANSPOSE4x16_I32(c0, c1, c2, c3, c4, c5, c6, c7, \
+                          c8, c9, cA, cB, cC, cD, cE, cF) \
+{ \
+    DECLARE_MERGE_I32(c0, c2, m02h, m02l) \
+    DECLARE_MERGE_I32(c1, c3, m13h, m13l) \
+    DECLARE_MERGE_I32(c4, c6, m46h, m46l) \
+    DECLARE_MERGE_I32(c5, c7, m57h, m57l) \
+    DECLARE_MERGE_I32(c8, cA, m8Ah, m8Al) \
+    DECLARE_MERGE_I32(c9, cB, m9Bh, m9Bl) \
+    DECLARE_MERGE_I32(cC, cE, mCEh, mCEl) \
+    DECLARE_MERGE_I32(cD, cF, mDFh, mDFl) \
+\
+    MERGE_I32(m02h, m13h, c0, c1) \
+    MERGE_I32(m02l, m13l, c2, c3) \
+    MERGE_I32(m46h, m57h, c4, c5) \
+    MERGE_I32(m46l, m57l, c6, c7) \
+    MERGE_I32(m8Ah, m9Bh, c8, c9) \
+    MERGE_I32(m8Al, m9Bl, cA, cB) \
+    MERGE_I32(mCEh, mDFh, cC, cD) \
+    MERGE_I32(mCEl, mDFl, cE, cF) \
+}
+
+#endif // DAV1D_SRC_PPC_UTILS_H
diff --git a/media/libdav1d/src/src/qm.c b/media/libdav1d/src/src/qm.c
new file mode 100644
index 0000000000..a523da5e4d
--- /dev/null
+++ b/media/libdav1d/src/src/qm.c
@@ -0,0 +1,1693 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/attributes.h"
+
+#include "src/qm.h"
+
+static const uint8_t qm_tbl_32x16[][2][512] = {
+    {
+        {
+             32,  31,  31,  31,  32,  32,  34,  35,  36,  39,  44,  46,  48,  53,  58,  61,  65,  71,  79,  81,  82,  88,  91,  94,  97, 100, 103, 107, 110, 114, 118, 122,
+             31,  32,  32,  32,  32,  33,  34,  34,  34,  37,  41,  43,  45,  49,  54,  57,  60,  65,  72,  74,  75,  80,  83,  85,  88,  91,  94,  97, 101, 104, 108, 111,
+             32,  32,  33,  33,  34,  35,  37,  37,  38,  40,  43,  44,  46,  50,  54,  56,  58,  63,  70,  71,  72,  77,  80,  83,  86,  89,  93,  96, 100, 104, 107, 111,
+             34,  34,  33,  34,  35,  37,  39,  41,  43,  45,  48,  49,  51,  54,  58,  60,  63,  68,  74,  75,  76,  80,  81,  82,  85,  87,  90,  93,  97, 100, 103, 107,
+             36,  35,  34,  35,  36,  38,  42,  45,  48,  50,  53,  55,  56,  60,  63,  66,  68,  73,  79,  80,  81,  85,  88,  91,  94,  97,  98, 100, 101, 103, 105, 107,
+             44,  42,  41,  41,  42,  42,  48,  50,  54,  58,  63,  65,  67,  71,  75,  77,  79,  84,  90,  91,  92,  97, 100, 100, 100, 100, 101, 104, 108, 112, 115, 119,
+             53,  51,  49,  49,  50,  49,  54,  57,  60,  65,  71,  73,  76,  82,  87,  89,  92,  97, 104, 105, 106, 108, 106, 105, 107, 111, 114, 117, 117, 117, 118, 119,
+             59,  56,  54,  54,  54,  53,  58,  61,  64,  69,  75,  78,  80,  87,  92,  95,  98, 103, 110, 112, 113, 115, 114, 118, 123, 121, 120, 119, 123, 127, 131, 136,
+             65,  62,  59,  59,  59,  58,  63,  65,  68,  73,  79,  82,  85,  92,  98, 101, 105, 111, 118, 119, 121, 126, 130, 131, 128, 127, 131, 136, 138, 137, 136, 136,
+             79,  75,  72,  71,  71,  69,  73,  76,  78,  84,  90,  93,  96, 103, 110, 114, 118, 125, 133, 135, 136, 142, 142, 137, 140, 145, 144, 142, 141, 146, 151, 156,
+             87,  82,  78,  78,  77,  75,  79,  82,  84,  89,  95,  98, 102, 109, 116, 120, 124, 132, 141, 142, 144, 149, 148, 153, 157, 152, 150, 155, 161, 159, 157, 156,
+             90,  85,  82,  81,  80,  78,  78,  83,  87,  89,  93, 100, 102, 107, 115, 118, 123, 132, 136, 140, 151, 153, 155, 160, 161, 164, 170, 168, 165, 167, 172, 178,
+             93,  88,  86,  84,  82,  82,  80,  84,  86,  91,  94,  98, 105, 107, 112, 119, 122, 130, 135, 140, 149, 153, 162, 165, 167, 173, 174, 177, 183, 185, 182, 179,
+             96,  91,  90,  87,  86,  86,  83,  84,  89,  91,  95, 100, 102, 110, 111, 118, 123, 128, 135, 138, 149, 152, 160, 167, 173, 178, 180, 187, 188, 190, 197, 203,
+             99,  94,  93,  90,  89,  89,  88,  87,  90,  93,  97,  99, 105, 107, 115, 116, 124, 127, 135, 139, 146, 152, 159, 166, 171, 182, 186, 191, 193, 201, 203, 204,
+            102,  97,  97,  93,  93,  92,  92,  90,  90,  96,  97, 103, 104, 111, 112, 120, 121, 130, 131, 142, 143, 154, 155, 168, 169, 181, 183, 198, 200, 206, 208, 217,
+        }, {
+             32,  31,  30,  32,  33,  37,  42,  45,  49,  48,  49,  49,  50,  52,  54,  55,  57,  60,  63,  64,  64,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,
+             31,  31,  32,  34,  36,  40,  43,  44,  46,  46,  45,  46,  46,  48,  50,  51,  52,  54,  57,  58,  59,  61,  62,  62,  63,  64,  65,  66,  67,  68,  69,  70,
+             37,  38,  40,  41,  43,  47,  47,  47,  48,  47,  46,  46,  46,  47,  49,  49,  50,  52,  55,  55,  56,  58,  59,  60,  62,  63,  64,  65,  67,  68,  69,  70,
+             42,  42,  42,  44,  45,  47,  48,  49,  50,  50,  49,  49,  50,  50,  52,  52,  53,  55,  58,  58,  58,  60,  60,  60,  60,  61,  62,  63,  64,  65,  66,  67,
+             48,  47,  46,  46,  47,  47,  50,  51,  53,  53,  53,  53,  54,  54,  55,  56,  56,  58,  60,  61,  61,  63,  64,  65,  66,  67,  66,  66,  66,  66,  67,  67,
+             49,  47,  45,  45,  46,  45,  49,  51,  53,  56,  58,  59,  59,  61,  62,  63,  64,  65,  67,  68,  68,  69,  71,  70,  69,  68,  68,  69,  70,  71,  72,  73,
+             52,  50,  48,  48,  47,  47,  50,  52,  54,  57,  61,  62,  64,  66,  68,  69,  70,  72,  75,  75,  75,  76,  74,  72,  73,  74,  75,  75,  74,  74,  73,  73,
+             54,  52,  50,  49,  49,  48,  52,  54,  55,  59,  62,  64,  65,  68,  71,  72,  73,  75,  78,  78,  79,  79,  78,  79,  81,  79,  78,  76,  77,  78,  80,  81,
+             57,  54,  52,  51,  51,  50,  53,  55,  57,  60,  64,  65,  67,  71,  73,  75,  76,  79,  82,  82,  83,  85,  86,  85,  83,  82,  83,  84,  84,  83,  82,  81,
+             63,  60,  57,  57,  56,  54,  57,  59,  60,  64,  67,  69,  71,  75,  78,  80,  82,  85,  89,  89,  90,  92,  91,  88,  89,  90,  89,  87,  86,  87,  88,  90,
+             66,  63,  60,  59,  59,  57,  60,  61,  62,  66,  69,  71,  73,  77,  80,  82,  84,  88,  92,  92,  93,  95,  94,  95,  96,  93,  92,  93,  94,  93,  91,  90,
+             67,  64,  62,  61,  60,  58,  58,  61,  63,  65,  67,  70,  72,  74,  78,  80,  82,  86,  88,  90,  95,  96,  96,  98,  97,  98, 100,  98,  96,  96,  97,  99,
+             68,  65,  63,  62,  60,  60,  59,  61,  62,  65,  66,  68,  72,  73,  76,  79,  80,  84,  87,  89,  93,  94,  98,  99,  99, 102, 101, 102, 103, 103, 101,  99,
+             69,  66,  65,  63,  62,  61,  60,  60,  63,  64,  66,  68,  70,  73,  74,  78,  80,  82,  85,  87,  91,  92,  96,  98, 101, 102, 103, 105, 105, 105, 107, 108,
+             71,  67,  66,  64,  63,  62,  62,  61,  62,  64,  66,  67,  70,  71,  75,  76,  79,  81,  84,  86,  89,  91,  94,  97,  98, 102, 104, 106, 106, 109, 109, 108,
+             72,  68,  68,  65,  65,  63,  63,  61,  62,  65,  65,  68,  69,  72,  73,  77,  77,  81,  81,  86,  87,  91,  91,  96,  97, 101, 102, 107, 107, 109, 110, 113,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  32,  32,  32,  34,  36,  38,  39,  44,  47,  49,  53,  58,  61,  65,  71,  76,  79,  82,  86,  89,  92,  95,  98, 101, 104, 107, 110, 114,
+             31,  32,  32,  32,  32,  33,  33,  34,  34,  36,  37,  41,  44,  46,  49,  54,  56,  60,  65,  69,  72,  75,  78,  81,  84,  86,  89,  92,  95,  98, 101, 104,
+             32,  32,  32,  33,  34,  35,  35,  36,  37,  39,  40,  42,  45,  47,  50,  54,  56,  59,  64,  68,  70,  73,  76,  79,  82,  85,  88,  91,  94,  97, 100, 104,
+             32,  33,  33,  33,  34,  36,  36,  38,  40,  41,  42,  45,  47,  48,  51,  55,  57,  60,  65,  69,  71,  74,  77,  78,  80,  83,  85,  88,  91,  94,  97, 100,
+             36,  35,  35,  35,  36,  38,  40,  42,  48,  49,  50,  53,  56,  57,  60,  63,  65,  68,  73,  76,  79,  81,  84,  87,  89,  92,  93,  94,  95,  96,  98, 100,
+             44,  42,  41,  41,  42,  42,  44,  48,  54,  56,  58,  63,  66,  67,  71,  75,  77,  79,  84,  88,  90,  92,  95,  95,  95,  95,  95,  98, 101, 105, 108, 111,
+             47,  45,  44,  44,  45,  45,  47,  50,  56,  58,  60,  66,  69,  71,  75,  79,  81,  84,  89,  92,  95,  97, 100,  99, 101, 105, 108, 110, 110, 110, 111, 111,
+             53,  51,  49,  49,  50,  49,  51,  54,  60,  63,  65,  71,  75,  77,  82,  87,  89,  92,  97, 101, 104, 106, 109, 112, 116, 114, 113, 112, 115, 119, 123, 126,
+             65,  62,  60,  59,  59,  58,  60,  63,  68,  71,  73,  79,  84,  86,  92,  98, 100, 105, 111, 115, 118, 121, 124, 124, 121, 120, 124, 128, 129, 128, 127, 127,
+             73,  69,  67,  66,  65,  64,  66,  69,  74,  77,  79,  85,  90,  93,  99, 105, 107, 112, 119, 123, 127, 130, 133, 130, 132, 136, 136, 133, 132, 136, 141, 145,
+             79,  75,  72,  71,  71,  69,  71,  73,  78,  81,  84,  90,  95,  97, 103, 110, 113, 118, 125, 130, 133, 136, 140, 145, 148, 143, 141, 146, 151, 149, 147, 145,
+             87,  83,  80,  79,  78,  76,  76,  80,  84,  86,  90,  96,  99, 103, 111, 114, 118, 126, 130, 134, 143, 146, 147, 152, 151, 155, 160, 158, 154, 156, 161, 166,
+             90,  86,  84,  82,  80,  80,  78,  82,  83,  88,  91,  94, 101, 103, 108, 114, 116, 124, 129, 134, 142, 145, 153, 156, 157, 163, 163, 166, 171, 173, 169, 166,
+             93,  88,  87,  84,  83,  83,  81,  81,  86,  88,  92,  96,  98, 105, 107, 113, 117, 122, 129, 131, 141, 144, 151, 157, 163, 167, 169, 175, 175, 177, 183, 189,
+             96,  91,  90,  87,  87,  86,  85,  84,  87,  90,  94,  96, 101, 102, 110, 111, 118, 121, 129, 132, 138, 144, 150, 156, 161, 171, 174, 179, 181, 188, 188, 190,
+             99,  94,  94,  90,  90,  88,  89,  86,  87,  93,  93,  99,  99, 106, 107, 115, 116, 124, 125, 135, 136, 145, 146, 158, 159, 170, 171, 185, 186, 192, 193, 201,
+        }, {
+             32,  31,  30,  31,  33,  37,  39,  42,  49,  48,  48,  49,  50,  51,  52,  54,  55,  57,  60,  62,  63,  64,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
+             31,  31,  32,  33,  36,  40,  41,  43,  46,  46,  46,  45,  46,  47,  48,  50,  51,  52,  54,  56,  57,  59,  60,  61,  62,  63,  64,  65,  65,  66,  67,  68,
+             35,  37,  38,  38,  41,  45,  46,  46,  48,  47,  46,  45,  46,  47,  47,  49,  49,  50,  53,  54,  55,  56,  58,  59,  60,  61,  62,  64,  65,  66,  67,  68,
+             38,  40,  40,  41,  44,  47,  47,  48,  49,  48,  48,  47,  48,  48,  48,  50,  50,  51,  53,  55,  56,  57,  58,  58,  59,  60,  60,  61,  62,  63,  64,  65,
+             48,  47,  46,  46,  47,  47,  48,  50,  53,  53,  53,  53,  54,  54,  54,  55,  56,  56,  58,  60,  60,  61,  62,  63,  64,  65,  65,  65,  65,  65,  65,  65,
+             49,  47,  45,  45,  46,  45,  47,  49,  53,  55,  56,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  68,  67,  66,  66,  67,  68,  69,  70,  71,
+             50,  48,  46,  46,  46,  46,  47,  50,  54,  55,  56,  59,  61,  61,  63,  65,  65,  66,  68,  69,  70,  71,  72,  71,  71,  72,  73,  73,  72,  72,  71,  71,
+             52,  50,  48,  48,  47,  47,  48,  50,  54,  56,  57,  61,  63,  64,  66,  68,  69,  70,  72,  74,  75,  75,  76,  78,  79,  77,  76,  74,  75,  76,  77,  78,
+             57,  54,  52,  52,  51,  50,  51,  53,  57,  58,  60,  64,  66,  68,  71,  73,  74,  76,  79,  81,  82,  83,  84,  83,  81,  80,  81,  82,  82,  81,  79,  78,
+             61,  57,  55,  55,  54,  52,  54,  56,  59,  61,  62,  66,  68,  70,  73,  76,  77,  79,  82,  84,  86,  87,  88,  86,  86,  88,  87,  85,  83,  85,  86,  87,
+             63,  60,  58,  57,  56,  54,  55,  57,  60,  62,  64,  67,  70,  71,  75,  78,  79,  82,  85,  87,  89,  90,  91,  93,  94,  91,  89,  90,  92,  90,  89,  87,
+             67,  63,  61,  60,  59,  57,  57,  60,  63,  64,  66,  69,  71,  73,  77,  79,  81,  85,  87,  88,  92,  93,  94,  96,  95,  96,  97,  95,  93,  93,  94,  96,
+             68,  64,  63,  61,  60,  59,  58,  60,  61,  64,  65,  67,  71,  72,  75,  78,  79,  83,  85,  87,  91,  92,  95,  96,  97,  99,  98,  99, 100, 100,  98,  96,
+             69,  65,  64,  62,  61,  61,  59,  59,  62,  63,  65,  67,  68,  72,  73,  76,  78,  81,  84,  85,  89,  90,  93,  96,  98,  99, 100, 102, 102, 102, 103, 105,
+             70,  66,  65,  63,  63,  62,  61,  60,  61,  63,  65,  66,  69,  70,  74,  74,  78,  79,  82,  84,  87,  89,  91,  94,  96, 100, 101, 103, 103, 105, 105, 105,
+             71,  67,  67,  64,  64,  62,  62,  60,  61,  64,  64,  67,  67,  71,  71,  75,  75,  79,  80,  84,  84,  89,  89,  94,  94,  98,  99, 104, 104, 106, 106, 109,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  32,  32,  32,  34,  34,  36,  39,  40,  44,  47,  49,  53,  57,  59,  65,  69,  71,  79,  81,  82,  87,  90,  92,  95,  98, 100, 103, 106,
+             31,  32,  32,  32,  32,  32,  33,  34,  34,  34,  37,  38,  41,  44,  46,  49,  53,  54,  60,  63,  65,  72,  74,  75,  79,  82,  84,  87,  89,  92,  94,  97,
+             32,  32,  32,  32,  33,  34,  34,  35,  36,  37,  39,  40,  42,  45,  46,  50,  53,  54,  59,  62,  64,  71,  72,  73,  77,  80,  83,  85,  88,  91,  94,  97,
+             32,  32,  32,  33,  34,  34,  35,  37,  37,  38,  40,  41,  43,  46,  47,  50,  53,  54,  58,  62,  63,  70,  71,  72,  76,  78,  81,  83,  85,  88,  90,  93,
+             36,  35,  35,  34,  36,  37,  38,  42,  44,  48,  50,  51,  53,  56,  57,  60,  63,  64,  68,  71,  73,  79,  80,  81,  85,  87,  88,  88,  89,  90,  92,  93,
+             39,  38,  38,  37,  39,  40,  40,  45,  47,  51,  54,  55,  58,  61,  62,  65,  68,  69,  73,  76,  78,  84,  85,  86,  90,  89,  90,  92,  95,  98, 101, 104,
+             44,  42,  41,  41,  42,  42,  42,  48,  50,  54,  58,  59,  63,  66,  67,  71,  74,  75,  79,  83,  84,  90,  91,  92,  96,  99, 102, 103, 103, 103, 103, 104,
+             53,  51,  50,  49,  50,  49,  49,  54,  56,  60,  65,  67,  71,  75,  77,  82,  86,  87,  92,  96,  97, 104, 105, 106, 110, 108, 106, 105, 108, 111, 114, 118,
+             58,  55,  54,  53,  53,  53,  52,  57,  59,  63,  68,  70,  74,  79,  81,  86,  90,  91,  97, 100, 102, 109, 110, 111, 114, 113, 117, 120, 121, 120, 119, 118,
+             65,  62,  60,  59,  59,  58,  58,  63,  65,  68,  73,  75,  79,  85,  86,  92,  97,  98, 105, 109, 111, 118, 120, 121, 125, 129, 128, 125, 124, 127, 131, 135,
+             79,  75,  73,  72,  71,  70,  69,  73,  75,  78,  84,  85,  90,  95,  97, 103, 108, 111, 118, 122, 125, 133, 135, 136, 140, 135, 133, 137, 141, 139, 137, 135,
+             81,  77,  75,  74,  72,  71,  70,  75,  77,  80,  85,  87,  91,  97,  99, 105, 110, 112, 119, 124, 127, 135, 137, 139, 143, 146, 150, 148, 144, 146, 150, 154,
+             88,  83,  81,  79,  78,  77,  76,  79,  81,  85,  88,  91,  97,  99, 104, 109, 111, 119, 123, 127, 135, 137, 145, 147, 148, 153, 153, 155, 160, 161, 158, 155,
+             90,  86,  84,  82,  81,  80,  78,  79,  83,  85,  89,  92,  94, 101, 102, 108, 112, 117, 123, 125, 134, 136, 143, 148, 154, 157, 158, 164, 164, 165, 170, 175,
+             93,  88,  88,  84,  84,  83,  82,  81,  84,  86,  90,  92,  97,  98, 105, 106, 113, 115, 122, 125, 131, 136, 141, 147, 151, 160, 163, 168, 169, 175, 175, 176,
+             96,  91,  91,  87,  87,  85,  86,  83,  84,  89,  89,  95,  95, 102, 102, 110, 110, 118, 119, 128, 129, 137, 138, 149, 149, 159, 160, 173, 174, 179, 180, 187,
+        }, {
+             32,  31,  31,  30,  33,  35,  37,  42,  44,  49,  48,  48,  49,  50,  51,  52,  54,  54,  57,  59,  60,  63,  64,  64,  66,  67,  68,  69,  70,  71,  72,  73,
+             31,  31,  32,  32,  36,  38,  40,  43,  44,  46,  46,  45,  45,  46,  47,  48,  49,  50,  52,  54,  54,  57,  58,  59,  60,  61,  62,  63,  64,  65,  65,  66,
+             34,  35,  36,  36,  40,  42,  44,  45,  46,  47,  46,  46,  45,  46,  47,  47,  49,  49,  51,  52,  53,  56,  57,  57,  59,  60,  61,  62,  63,  64,  65,  66,
+             37,  38,  39,  40,  43,  45,  47,  47,  47,  48,  47,  46,  46,  46,  47,  47,  48,  49,  50,  52,  52,  55,  55,  56,  57,  58,  59,  60,  60,  61,  62,  63,
+             48,  47,  46,  46,  47,  47,  47,  50,  51,  53,  53,  53,  53,  54,  54,  54,  55,  55,  56,  58,  58,  60,  61,  61,  63,  63,  63,  63,  63,  63,  63,  63,
+             48,  47,  46,  45,  46,  46,  46,  50,  51,  53,  54,  55,  56,  56,  57,  57,  58,  59,  60,  61,  62,  64,  64,  65,  66,  65,  64,  65,  66,  67,  68,  69,
+             49,  47,  46,  45,  46,  45,  45,  49,  51,  53,  56,  56,  58,  59,  60,  61,  62,  62,  64,  65,  65,  67,  68,  68,  69,  70,  71,  71,  70,  70,  69,  69,
+             52,  50,  48,  48,  47,  47,  47,  50,  52,  54,  57,  58,  61,  63,  64,  66,  68,  68,  70,  72,  72,  75,  75,  75,  77,  75,  74,  72,  73,  74,  75,  76,
+             54,  51,  50,  49,  49,  48,  48,  51,  53,  55,  58,  59,  62,  65,  65,  68,  70,  70,  73,  74,  75,  77,  78,  78,  79,  78,  79,  80,  80,  78,  77,  76,
+             57,  54,  53,  52,  51,  50,  50,  53,  54,  57,  60,  61,  64,  66,  68,  71,  73,  74,  76,  78,  79,  82,  82,  83,  84,  85,  84,  82,  81,  82,  83,  84,
+             63,  60,  58,  57,  56,  55,  54,  57,  59,  60,  64,  65,  67,  70,  71,  75,  77,  78,  82,  84,  85,  89,  89,  90,  91,  88,  87,  88,  89,  88,  86,  84,
+             64,  61,  59,  58,  57,  56,  55,  58,  59,  61,  64,  65,  68,  71,  72,  75,  78,  79,  82,  85,  86,  90,  90,  91,  93,  93,  94,  93,  90,  90,  92,  93,
+             67,  63,  62,  60,  59,  58,  57,  59,  60,  63,  64,  66,  70,  70,  73,  76,  77,  81,  83,  85,  89,  90,  93,  94,  94,  96,  96,  96,  97,  97,  95,  93,
+             68,  64,  63,  61,  60,  60,  58,  58,  61,  62,  64,  66,  67,  71,  71,  75,  77,  79,  82,  83,  87,  88,  91,  93,  95,  97,  97,  99,  99,  99, 100, 101,
+             69,  65,  65,  62,  62,  61,  60,  59,  61,  62,  64,  65,  68,  68,  72,  73,  76,  77,  81,  82,  85,  87,  89,  92,  93,  97,  98, 100, 100, 102, 102, 101,
+             69,  66,  66,  63,  63,  61,  61,  59,  60,  63,  63,  66,  66,  70,  70,  73,  74,  78,  78,  82,  82,  86,  87,  91,  91,  95,  96, 101, 101, 103, 103, 105,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  32,  32,  32,  34,  35,  36,  39,  41,  44,  47,  48,  53,  55,  58,  63,  65,  71,  74,  79,  82,  82,  87,  89,  92,  94,  97,  99,
+             31,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  37,  39,  41,  44,  45,  49,  51,  54,  58,  60,  65,  68,  72,  75,  75,  79,  82,  84,  86,  88,  91,
+             31,  32,  32,  32,  33,  33,  34,  34,  35,  36,  36,  39,  40,  42,  44,  45,  50,  51,  54,  58,  59,  64,  67,  71,  73,  74,  78,  81,  83,  85,  88,  91,
+             32,  32,  32,  33,  34,  34,  35,  36,  37,  38,  38,  40,  41,  43,  45,  46,  50,  51,  54,  57,  58,  63,  66,  70,  72,  72,  76,  78,  80,  82,  85,  87,
+             35,  35,  34,  34,  35,  36,  37,  39,  41,  45,  46,  48,  49,  51,  53,  54,  57,  59,  61,  65,  66,  71,  73,  77,  79,  79,  83,  83,  84,  85,  86,  87,
+             36,  35,  35,  34,  36,  36,  38,  40,  42,  47,  48,  50,  51,  53,  56,  56,  60,  61,  63,  67,  68,  73,  75,  79,  81,  81,  85,  87,  89,  92,  94,  97,
+             44,  42,  41,  41,  42,  42,  42,  44,  48,  52,  54,  58,  60,  63,  66,  67,  71,  72,  75,  78,  79,  84,  86,  90,  92,  92,  96,  97,  97,  97,  97,  97,
+             47,  45,  45,  44,  44,  45,  45,  47,  50,  55,  56,  60,  62,  66,  69,  70,  75,  77,  79,  83,  84,  89,  91,  95,  97,  97, 100,  99, 101, 104, 107, 110,
+             53,  51,  50,  49,  49,  50,  49,  51,  54,  59,  60,  65,  67,  71,  75,  76,  82,  84,  87,  91,  92,  97, 100, 104, 105, 106, 110, 113, 114, 112, 111, 110,
+             62,  59,  58,  57,  57,  57,  56,  58,  61,  65,  66,  71,  74,  78,  82,  83,  90,  92,  95, 100, 102, 108, 110, 115, 117, 117, 120, 118, 116, 119, 123, 126,
+             65,  62,  61,  59,  59,  59,  58,  60,  63,  67,  68,  73,  76,  79,  84,  85,  92,  94,  98, 103, 105, 111, 113, 118, 120, 121, 125, 128, 132, 130, 128, 126,
+             79,  75,  74,  72,  71,  71,  69,  71,  73,  77,  78,  84,  86,  90,  95,  96, 103, 106, 110, 116, 118, 125, 128, 133, 136, 136, 141, 139, 135, 136, 140, 144,
+             82,  78,  76,  74,  73,  73,  71,  73,  76,  79,  80,  86,  88,  92,  97,  98, 106, 108, 112, 118, 120, 127, 131, 136, 139, 139, 144, 145, 150, 151, 147, 144,
+             88,  83,  82,  79,  79,  78,  76,  76,  81,  82,  85,  89,  91,  97,  98, 104, 107, 111, 117, 119, 127, 129, 135, 140, 145, 148, 148, 153, 153, 154, 159, 163,
+             90,  86,  85,  82,  81,  80,  79,  78,  81,  83,  87,  88,  93,  94, 101, 101, 108, 110, 116, 119, 124, 129, 134, 139, 142, 150, 153, 157, 157, 163, 163, 163,
+             93,  88,  88,  84,  84,  82,  83,  80,  80,  86,  86,  91,  91,  97,  98, 105, 105, 112, 113, 121, 122, 130, 130, 140, 140, 149, 150, 161, 162, 166, 167, 173,
+        }, {
+             32,  31,  31,  30,  33,  33,  37,  39,  42,  47,  49,  48,  48,  49,  50,  50,  52,  53,  54,  56,  57,  60,  61,  63,  64,  64,  66,  67,  68,  69,  70,  70,
+             31,  31,  32,  32,  35,  36,  40,  41,  43,  46,  46,  46,  45,  45,  46,  46,  48,  49,  50,  51,  52,  54,  56,  57,  58,  59,  60,  61,  62,  63,  63,  64,
+             33,  34,  34,  35,  37,  38,  43,  43,  44,  46,  47,  46,  46,  45,  46,  46,  47,  48,  49,  51,  51,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,
+             37,  38,  39,  40,  42,  43,  47,  47,  47,  48,  48,  47,  46,  46,  46,  46,  47,  48,  49,  50,  50,  52,  53,  55,  56,  56,  57,  58,  59,  59,  60,  61,
+             45,  45,  45,  44,  46,  46,  47,  48,  49,  51,  52,  51,  51,  51,  52,  52,  53,  53,  54,  55,  55,  57,  58,  59,  60,  60,  61,  61,  61,  61,  61,  61,
+             48,  47,  46,  46,  47,  47,  47,  48,  50,  52,  53,  53,  53,  53,  54,  54,  54,  55,  55,  56,  56,  58,  59,  60,  61,  61,  63,  63,  64,  65,  66,  67,
+             49,  47,  46,  45,  45,  46,  45,  47,  49,  53,  53,  56,  57,  58,  59,  59,  61,  61,  62,  63,  64,  65,  66,  67,  68,  68,  69,  69,  68,  68,  67,  67,
+             50,  48,  47,  46,  46,  46,  46,  47,  50,  53,  54,  56,  57,  59,  61,  61,  63,  64,  65,  66,  66,  68,  69,  70,  71,  71,  72,  70,  71,  72,  73,  74,
+             52,  50,  49,  48,  47,  47,  47,  48,  50,  53,  54,  57,  59,  61,  63,  64,  66,  67,  68,  70,  70,  72,  73,  75,  75,  75,  77,  78,  77,  76,  75,  74,
+             56,  53,  52,  51,  50,  50,  49,  50,  53,  55,  56,  59,  61,  63,  65,  66,  70,  71,  72,  74,  75,  77,  79,  80,  81,  81,  82,  80,  79,  80,  81,  82,
+             57,  54,  53,  52,  51,  51,  50,  51,  53,  56,  57,  60,  61,  64,  66,  67,  71,  72,  73,  76,  76,  79,  80,  82,  83,  83,  84,  85,  86,  85,  83,  82,
+             63,  60,  59,  57,  56,  56,  54,  55,  57,  60,  60,  64,  65,  67,  70,  71,  75,  76,  78,  81,  82,  85,  86,  89,  90,  90,  92,  90,  88,  88,  89,  90,
+             64,  61,  60,  58,  57,  57,  55,  56,  58,  61,  61,  64,  66,  68,  71,  71,  75,  77,  79,  82,  83,  86,  87,  90,  91,  91,  93,  93,  94,  94,  92,  90,
+             67,  63,  62,  60,  60,  59,  57,  57,  60,  61,  63,  65,  66,  70,  70,  73,  75,  77,  80,  81,  85,  86,  89,  91,  93,  94,  94,  96,  96,  95,  97,  98,
+             68,  64,  64,  61,  61,  60,  59,  58,  60,  61,  63,  64,  67,  67,  71,  71,  74,  75,  79,  80,  83,  85,  87,  89,  91,  94,  95,  97,  97,  99,  98,  98,
+             68,  65,  65,  62,  62,  60,  61,  59,  59,  62,  62,  65,  65,  68,  68,  72,  72,  76,  76,  80,  80,  84,  84,  89,  89,  93,  93,  97,  98,  99,  99, 102,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  32,  32,  32,  33,  34,  36,  36,  39,  40,  44,  46,  48,  52,  53,  58,  58,  65,  66,  71,  74,  79,  81,  82,  86,  88,  91,  93,
+             31,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  35,  37,  38,  41,  43,  45,  48,  49,  53,  54,  60,  61,  65,  68,  72,  74,  75,  78,  81,  83,  85,
+             31,  32,  32,  32,  32,  33,  33,  33,  34,  34,  35,  35,  38,  39,  41,  43,  45,  48,  49,  53,  54,  59,  60,  65,  67,  72,  73,  74,  78,  80,  82,  85,
+             32,  32,  32,  33,  33,  34,  35,  35,  36,  37,  38,  38,  40,  41,  43,  44,  46,  49,  50,  53,  54,  58,  59,  63,  66,  70,  71,  72,  75,  77,  79,  81,
+             33,  33,  33,  33,  34,  35,  36,  36,  38,  39,  42,  42,  44,  45,  46,  48,  50,  52,  53,  57,  57,  62,  63,  67,  69,  73,  75,  75,  78,  80,  80,  81,
+             36,  35,  35,  34,  35,  36,  37,  38,  41,  42,  48,  48,  50,  51,  53,  55,  56,  59,  60,  63,  63,  68,  69,  73,  75,  79,  80,  81,  84,  86,  88,  90,
+             40,  39,  39,  38,  38,  39,  40,  41,  44,  45,  51,  51,  54,  56,  59,  60,  62,  65,  66,  69,  70,  74,  75,  79,  81,  85,  86,  87,  90,  90,  90,  90,
+             44,  42,  42,  41,  41,  42,  42,  42,  46,  48,  54,  54,  58,  59,  63,  65,  67,  70,  71,  74,  75,  79,  80,  84,  86,  90,  91,  92,  95,  98, 100, 102,
+             51,  49,  49,  47,  47,  48,  48,  48,  52,  53,  58,  59,  63,  65,  69,  72,  74,  78,  79,  83,  84,  89,  90,  94,  97, 101, 102, 103, 106, 105, 103, 103,
+             53,  51,  51,  49,  49,  50,  49,  49,  53,  54,  60,  60,  65,  67,  71,  73,  76,  80,  82,  86,  87,  92,  93,  97, 100, 104, 105, 106, 109, 112, 114, 117,
+             65,  62,  61,  59,  59,  59,  58,  58,  62,  63,  68,  68,  73,  75,  79,  82,  85,  90,  92,  97,  98, 105, 106, 111, 113, 118, 120, 121, 124, 122, 119, 117,
+             66,  63,  62,  60,  60,  60,  59,  59,  63,  64,  69,  69,  74,  76,  80,  83,  86,  91,  93,  98,  99, 106, 107, 112, 115, 119, 121, 122, 125, 127, 130, 134,
+             79,  75,  74,  72,  71,  71,  69,  69,  72,  73,  78,  79,  84,  85,  90,  93,  96, 101, 103, 109, 110, 118, 119, 125, 128, 133, 135, 136, 140, 140, 137, 134,
+             81,  77,  76,  74,  73,  72,  71,  70,  74,  75,  80,  80,  85,  87,  91,  94,  98, 103, 105, 111, 112, 119, 121, 127, 130, 135, 137, 139, 142, 144, 148, 151,
+             87,  83,  82,  79,  79,  78,  77,  75,  78,  80,  84,  85,  89,  90,  96,  97, 103, 105, 111, 113, 118, 122, 126, 131, 134, 141, 143, 147, 147, 152, 151, 152,
+             90,  85,  85,  81,  81,  80,  80,  77,  78,  83,  83,  87,  88,  93,  93, 100, 100, 107, 107, 115, 115, 123, 123, 132, 132, 140, 140, 151, 151, 155, 155, 160,
+        }, {
+             32,  31,  31,  30,  31,  33,  35,  37,  41,  42,  49,  49,  48,  48,  49,  49,  50,  51,  52,  54,  54,  57,  57,  60,  61,  63,  64,  64,  66,  67,  68,  68,
+             31,  31,  31,  32,  33,  36,  38,  40,  42,  43,  46,  46,  46,  45,  45,  46,  46,  47,  48,  50,  50,  52,  52,  54,  56,  57,  58,  59,  60,  61,  62,  62,
+             32,  33,  33,  33,  35,  37,  39,  41,  43,  43,  47,  47,  46,  46,  45,  46,  46,  47,  48,  49,  50,  52,  52,  54,  55,  57,  58,  58,  59,  60,  61,  62,
+             37,  38,  38,  40,  41,  43,  45,  47,  47,  47,  48,  48,  47,  46,  46,  46,  46,  47,  47,  48,  49,  50,  51,  52,  53,  55,  55,  56,  57,  58,  58,  59,
+             40,  41,  41,  42,  43,  44,  46,  47,  48,  48,  50,  50,  49,  49,  48,  49,  49,  49,  50,  51,  51,  52,  53,  55,  56,  57,  58,  58,  59,  59,  59,  59,
+             48,  47,  47,  46,  46,  47,  47,  47,  49,  50,  53,  53,  53,  53,  53,  53,  54,  54,  54,  55,  55,  56,  57,  58,  59,  60,  61,  61,  62,  63,  64,  65,
+             49,  47,  47,  45,  46,  46,  46,  46,  49,  49,  53,  53,  54,  55,  56,  57,  57,  58,  58,  59,  59,  60,  61,  62,  63,  64,  65,  65,  66,  66,  65,  65,
+             49,  47,  47,  45,  45,  46,  45,  45,  48,  49,  53,  54,  56,  56,  58,  59,  59,  61,  61,  62,  62,  64,  64,  65,  66,  67,  68,  68,  69,  70,  71,  71,
+             51,  49,  49,  47,  47,  47,  47,  46,  49,  50,  54,  54,  57,  58,  61,  62,  63,  64,  65,  67,  67,  69,  69,  71,  72,  73,  73,  74,  75,  74,  72,  71,
+             52,  50,  49,  48,  48,  47,  47,  47,  50,  50,  54,  55,  57,  58,  61,  62,  64,  66,  66,  68,  68,  70,  71,  72,  73,  75,  75,  75,  76,  77,  78,  79,
+             57,  54,  54,  52,  51,  51,  50,  50,  52,  53,  57,  57,  60,  61,  64,  65,  67,  69,  71,  73,  73,  76,  77,  79,  80,  82,  82,  83,  84,  82,  81,  79,
+             58,  55,  54,  52,  52,  52,  51,  50,  53,  54,  57,  57,  60,  61,  64,  66,  67,  70,  71,  73,  74,  77,  77,  79,  81,  82,  83,  83,  85,  85,  86,  87,
+             63,  60,  59,  57,  57,  56,  55,  54,  57,  57,  60,  61,  64,  65,  67,  69,  71,  73,  75,  77,  78,  82,  82,  85,  86,  89,  89,  90,  91,  91,  89,  87,
+             64,  61,  60,  58,  57,  57,  56,  55,  57,  58,  61,  61,  64,  65,  68,  69,  71,  74,  75,  78,  78,  82,  83,  86,  87,  90,  90,  91,  92,  93,  94,  95,
+             67,  63,  63,  60,  60,  59,  58,  57,  59,  60,  62,  63,  65,  66,  69,  70,  73,  74,  77,  78,  81,  83,  85,  87,  88,  92,  92,  94,  94,  96,  95,  95,
+             67,  64,  64,  61,  61,  60,  60,  58,  58,  61,  61,  64,  64,  67,  67,  70,  71,  74,  74,  78,  78,  82,  82,  86,  86,  90,  90,  95,  95,  96,  96,  98,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  32,  32,  32,  32,  34,  34,  36,  36,  39,  39,  44,  44,  48,  48,  53,  53,  58,  58,  65,  65,  71,  71,  79,  79,  82,  82,  87,
+             31,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  37,  37,  41,  41,  45,  45,  49,  49,  54,  54,  60,  60,  65,  65,  72,  72,  75,  75,  79,
+             31,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  37,  37,  41,  41,  45,  45,  49,  49,  54,  54,  60,  60,  65,  65,  72,  72,  75,  75,  79,
+             32,  32,  32,  33,  33,  34,  34,  35,  35,  37,  37,  38,  38,  40,  40,  43,  43,  46,  46,  50,  50,  54,  54,  58,  58,  63,  63,  70,  70,  72,  72,  76,
+             32,  32,  32,  33,  33,  34,  34,  35,  35,  37,  37,  38,  38,  40,  40,  43,  43,  46,  46,  50,  50,  54,  54,  58,  58,  63,  63,  70,  70,  72,  72,  76,
+             36,  35,  35,  34,  34,  36,  36,  38,  38,  42,  42,  48,  48,  50,  50,  53,  53,  56,  56,  60,  60,  63,  63,  68,  68,  73,  73,  79,  79,  81,  81,  84,
+             36,  35,  35,  34,  34,  36,  36,  38,  38,  42,  42,  48,  48,  50,  50,  53,  53,  56,  56,  60,  60,  63,  63,  68,  68,  73,  73,  79,  79,  81,  81,  84,
+             44,  42,  42,  41,  41,  42,  42,  42,  42,  48,  48,  54,  54,  58,  58,  63,  63,  67,  67,  71,  71,  75,  75,  79,  79,  84,  84,  90,  90,  92,  92,  96,
+             44,  42,  42,  41,  41,  42,  42,  42,  42,  48,  48,  54,  54,  58,  58,  63,  63,  67,  67,  71,  71,  75,  75,  79,  79,  84,  84,  90,  90,  92,  92,  96,
+             53,  51,  51,  49,  49,  50,  50,  49,  49,  54,  54,  60,  60,  65,  65,  71,  71,  76,  76,  82,  82,  87,  87,  92,  92,  97,  97, 104, 104, 106, 106, 109,
+             53,  51,  51,  49,  49,  50,  50,  49,  49,  54,  54,  60,  60,  65,  65,  71,  71,  76,  76,  82,  82,  87,  87,  92,  92,  97,  97, 104, 104, 106, 106, 109,
+             65,  62,  62,  59,  59,  59,  59,  58,  58,  63,  63,  68,  68,  73,  73,  79,  79,  85,  85,  92,  92,  98,  98, 105, 105, 111, 111, 118, 118, 121, 121, 124,
+             65,  62,  62,  59,  59,  59,  59,  58,  58,  63,  63,  68,  68,  73,  73,  79,  79,  85,  85,  92,  92,  98,  98, 105, 105, 111, 111, 118, 118, 121, 121, 124,
+             79,  75,  75,  72,  72,  71,  71,  69,  69,  73,  73,  78,  78,  84,  84,  90,  90,  96,  96, 103, 103, 110, 110, 118, 118, 125, 125, 133, 133, 136, 136, 141,
+             79,  75,  75,  72,  72,  71,  71,  69,  69,  73,  73,  78,  78,  84,  84,  90,  90,  96,  96, 103, 103, 110, 110, 118, 118, 125, 125, 133, 133, 136, 136, 141,
+             87,  82,  82,  78,  78,  77,  77,  75,  75,  79,  79,  84,  84,  89,  89,  95,  95, 102, 102, 109, 109, 116, 116, 124, 124, 132, 132, 141, 141, 144, 144, 149,
+        }, {
+             32,  31,  31,  30,  30,  33,  33,  37,  37,  42,  42,  49,  49,  48,  48,  49,  49,  50,  50,  52,  52,  54,  54,  57,  57,  60,  60,  63,  63,  64,  64,  66,
+             31,  31,  31,  32,  32,  36,  36,  40,  40,  43,  43,  46,  46,  46,  46,  45,  45,  46,  46,  48,  48,  50,  50,  52,  52,  54,  54,  57,  57,  59,  59,  60,
+             31,  31,  31,  32,  32,  36,  36,  40,  40,  43,  43,  46,  46,  46,  46,  45,  45,  46,  46,  48,  48,  50,  50,  52,  52,  54,  54,  57,  57,  59,  59,  60,
+             37,  38,  38,  40,  40,  43,  43,  47,  47,  47,  47,  48,  48,  47,  47,  46,  46,  46,  46,  47,  47,  49,  49,  50,  50,  52,  52,  55,  55,  56,  56,  57,
+             37,  38,  38,  40,  40,  43,  43,  47,  47,  47,  47,  48,  48,  47,  47,  46,  46,  46,  46,  47,  47,  49,  49,  50,  50,  52,  52,  55,  55,  56,  56,  57,
+             48,  47,  47,  46,  46,  47,  47,  47,  47,  50,  50,  53,  53,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,  56,  56,  58,  58,  60,  60,  61,  61,  63,
+             48,  47,  47,  46,  46,  47,  47,  47,  47,  50,  50,  53,  53,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,  56,  56,  58,  58,  60,  60,  61,  61,  63,
+             49,  47,  47,  45,  45,  46,  46,  45,  45,  49,  49,  53,  53,  56,  56,  58,  58,  59,  59,  61,  61,  62,  62,  64,  64,  65,  65,  67,  67,  68,  68,  69,
+             49,  47,  47,  45,  45,  46,  46,  45,  45,  49,  49,  53,  53,  56,  56,  58,  58,  59,  59,  61,  61,  62,  62,  64,  64,  65,  65,  67,  67,  68,  68,  69,
+             52,  50,  50,  48,  48,  47,  47,  47,  47,  50,  50,  54,  54,  57,  57,  61,  61,  64,  64,  66,  66,  68,  68,  70,  70,  72,  72,  75,  75,  75,  75,  77,
+             52,  50,  50,  48,  48,  47,  47,  47,  47,  50,  50,  54,  54,  57,  57,  61,  61,  64,  64,  66,  66,  68,  68,  70,  70,  72,  72,  75,  75,  75,  75,  77,
+             57,  54,  54,  52,  52,  51,  51,  50,  50,  53,  53,  57,  57,  60,  60,  64,  64,  67,  67,  71,  71,  73,  73,  76,  76,  79,  79,  82,  82,  83,  83,  84,
+             57,  54,  54,  52,  52,  51,  51,  50,  50,  53,  53,  57,  57,  60,  60,  64,  64,  67,  67,  71,  71,  73,  73,  76,  76,  79,  79,  82,  82,  83,  83,  84,
+             63,  60,  60,  57,  57,  56,  56,  54,  54,  57,  57,  60,  60,  64,  64,  67,  67,  71,  71,  75,  75,  78,  78,  82,  82,  85,  85,  89,  89,  90,  90,  92,
+             63,  60,  60,  57,  57,  56,  56,  54,  54,  57,  57,  60,  60,  64,  64,  67,  67,  71,  71,  75,  75,  78,  78,  82,  82,  85,  85,  89,  89,  90,  90,  92,
+             66,  63,  63,  60,  60,  59,  59,  57,  57,  60,  60,  62,  62,  66,  66,  69,  69,  73,  73,  77,  77,  80,  80,  84,  84,  88,  88,  92,  92,  93,  93,  95,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  32,  32,  32,  32,  34,  34,  35,  36,  38,  39,  41,  44,  44,  48,  48,  53,  53,  57,  58,  61,  65,  67,  71,  72,  79,  79,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  35,  36,  38,  39,  41,  42,  45,  45,  49,  50,  53,  54,  57,  60,  62,  66,  66,  73,  73,
+             31,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  36,  37,  39,  41,  42,  45,  45,  49,  49,  52,  54,  57,  60,  61,  65,  66,  72,  72,
+             32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  36,  36,  37,  37,  38,  40,  41,  42,  43,  46,  46,  49,  50,  52,  54,  56,  59,  60,  64,  64,  71,  71,
+             32,  32,  32,  32,  33,  33,  34,  34,  35,  35,  37,  37,  38,  38,  40,  40,  41,  43,  43,  46,  46,  49,  50,  52,  54,  56,  58,  60,  63,  64,  70,  70,
+             34,  34,  34,  33,  33,  34,  35,  35,  37,  37,  39,  39,  42,  43,  44,  45,  46,  48,  48,  51,  51,  54,  54,  57,  58,  60,  63,  64,  68,  68,  74,  74,
+             36,  35,  35,  35,  34,  35,  36,  37,  38,  39,  42,  42,  47,  48,  49,  50,  51,  53,  54,  56,  56,  59,  60,  62,  63,  66,  68,  69,  73,  73,  79,  79,
+             38,  37,  37,  36,  36,  37,  38,  38,  39,  40,  44,  44,  48,  49,  51,  52,  54,  56,  56,  59,  59,  62,  63,  65,  67,  69,  71,  72,  76,  76,  82,  82,
+             44,  42,  42,  41,  41,  41,  42,  42,  42,  43,  48,  48,  52,  54,  56,  58,  60,  63,  64,  67,  67,  71,  71,  74,  75,  77,  79,  81,  84,  85,  90,  90,
+             44,  43,  43,  42,  41,  42,  43,  43,  43,  44,  48,  48,  53,  54,  57,  58,  60,  64,  64,  67,  67,  71,  72,  75,  76,  78,  80,  82,  85,  86,  91,  91,
+             53,  51,  51,  50,  49,  49,  50,  49,  49,  50,  54,  54,  59,  60,  63,  65,  67,  71,  72,  76,  76,  81,  82,  85,  87,  89,  92,  94,  97,  98, 104, 104,
+             53,  51,  51,  50,  49,  49,  50,  49,  49,  50,  54,  54,  59,  60,  63,  65,  67,  71,  72,  76,  76,  81,  82,  85,  87,  89,  92,  94,  97,  98, 104, 104,
+             62,  60,  59,  58,  57,  57,  57,  56,  56,  56,  61,  61,  65,  66,  69,  71,  74,  78,  79,  83,  83,  89,  90,  94,  95,  98, 102, 103, 108, 108, 115, 115,
+             65,  62,  62,  60,  59,  59,  59,  59,  58,  58,  63,  63,  67,  68,  71,  73,  76,  79,  81,  85,  85,  91,  92,  96,  98, 101, 105, 106, 111, 111, 118, 118,
+             73,  70,  69,  67,  66,  66,  65,  65,  64,  64,  69,  69,  73,  74,  77,  79,  81,  85,  86,  91,  91,  98,  99, 103, 105, 108, 112, 114, 119, 119, 127, 127,
+             79,  75,  75,  73,  72,  71,  71,  70,  69,  69,  73,  73,  77,  78,  81,  84,  86,  90,  91,  96,  96, 103, 103, 108, 110, 114, 118, 120, 125, 125, 133, 133,
+        }, {
+             32,  31,  31,  30,  30,  32,  33,  34,  37,  37,  42,  42,  47,  49,  48,  48,  48,  49,  49,  50,  50,  52,  52,  53,  54,  55,  57,  58,  60,  60,  63,  63,
+             31,  31,  31,  32,  32,  33,  35,  37,  40,  40,  43,  43,  46,  47,  46,  46,  46,  45,  46,  47,  47,  48,  48,  50,  50,  51,  52,  53,  55,  55,  58,  58,
+             31,  31,  31,  32,  32,  34,  36,  37,  40,  40,  43,  43,  46,  46,  46,  46,  45,  45,  45,  46,  46,  48,  48,  49,  50,  51,  52,  53,  54,  55,  57,  57,
+             35,  36,  36,  37,  37,  39,  40,  42,  45,  45,  46,  46,  47,  47,  47,  46,  46,  45,  46,  46,  46,  47,  47,  48,  49,  50,  51,  51,  53,  53,  56,  56,
+             37,  38,  38,  39,  40,  41,  43,  44,  47,  47,  47,  47,  48,  48,  47,  47,  46,  46,  46,  46,  46,  47,  47,  48,  49,  49,  50,  51,  52,  53,  55,  55,
+             42,  42,  42,  42,  42,  44,  45,  45,  47,  47,  48,  48,  50,  50,  50,  50,  49,  49,  49,  50,  50,  50,  50,  51,  52,  52,  53,  54,  55,  55,  58,  58,
+             48,  47,  47,  46,  46,  46,  47,  47,  47,  48,  50,  50,  52,  53,  53,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,  56,  56,  57,  58,  59,  60,  60,
+             48,  47,  47,  46,  46,  46,  46,  47,  47,  47,  50,  50,  52,  53,  53,  54,  54,  55,  55,  55,  55,  56,  56,  57,  57,  58,  58,  59,  60,  60,  62,  62,
+             49,  47,  47,  46,  45,  45,  46,  45,  45,  46,  49,  49,  53,  53,  55,  56,  57,  58,  58,  59,  59,  61,  61,  62,  62,  63,  64,  64,  65,  65,  67,  67,
+             49,  47,  47,  46,  45,  45,  46,  46,  46,  46,  49,  49,  53,  54,  55,  56,  57,  59,  59,  60,  60,  61,  61,  62,  63,  63,  64,  65,  66,  66,  68,  68,
+             52,  50,  50,  48,  48,  48,  47,  47,  47,  47,  50,  50,  53,  54,  56,  57,  59,  61,  62,  64,  64,  66,  66,  68,  68,  69,  70,  71,  72,  73,  75,  75,
+             52,  50,  50,  48,  48,  48,  47,  47,  47,  47,  50,  50,  53,  54,  56,  57,  59,  61,  62,  64,  64,  66,  66,  68,  68,  69,  70,  71,  72,  73,  75,  75,
+             56,  54,  53,  52,  51,  51,  50,  50,  49,  49,  53,  53,  55,  56,  58,  59,  61,  63,  64,  66,  66,  69,  70,  71,  72,  74,  75,  76,  77,  78,  80,  80,
+             57,  54,  54,  52,  52,  51,  51,  51,  50,  50,  53,  53,  56,  57,  58,  60,  61,  64,  64,  67,  67,  70,  71,  72,  73,  75,  76,  77,  79,  79,  82,  82,
+             61,  58,  57,  56,  55,  54,  54,  53,  52,  53,  56,  56,  58,  59,  61,  62,  63,  66,  66,  69,  69,  72,  73,  75,  76,  78,  79,  80,  82,  83,  86,  86,
+             63,  60,  60,  58,  57,  57,  56,  55,  54,  55,  57,  57,  60,  60,  62,  64,  65,  67,  68,  71,  71,  74,  75,  77,  78,  80,  82,  83,  85,  85,  89,  89,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  33,  34,  34,  36,  36,  38,  39,  41,  44,  44,  47,  48,  50,  53,  53,  57,  58,  61,  65,  65,  70,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  35,  35,  37,  38,  39,  41,  41,  44,  45,  47,  50,  50,  54,  55,  57,  61,  61,  65,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  34,  37,  37,  39,  41,  41,  44,  45,  46,  49,  49,  53,  54,  56,  60,  60,  64,
+             31,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  35,  35,  35,  36,  36,  38,  39,  40,  42,  42,  44,  45,  47,  50,  50,  53,  54,  56,  59,  59,  63,
+             32,  32,  32,  32,  33,  33,  34,  34,  34,  35,  35,  36,  37,  37,  38,  38,  40,  40,  41,  43,  43,  45,  46,  47,  50,  50,  53,  54,  56,  58,  58,  62,
+             32,  32,  32,  32,  33,  33,  34,  34,  34,  35,  35,  36,  37,  37,  38,  38,  40,  40,  41,  43,  43,  45,  46,  47,  50,  50,  53,  54,  56,  58,  58,  62,
+             35,  35,  35,  34,  34,  34,  35,  36,  36,  37,  37,  40,  41,  43,  46,  46,  47,  48,  49,  51,  51,  53,  54,  55,  57,  57,  60,  61,  63,  66,  66,  70,
+             36,  35,  35,  35,  34,  34,  36,  36,  37,  38,  38,  41,  42,  44,  48,  48,  50,  50,  51,  53,  53,  56,  56,  58,  60,  60,  63,  63,  65,  68,  68,  72,
+             39,  38,  38,  37,  37,  37,  38,  38,  39,  40,  40,  43,  44,  46,  50,  50,  52,  53,  54,  57,  57,  59,  60,  61,  64,  64,  67,  68,  69,  72,  72,  76,
+             44,  42,  42,  41,  41,  41,  42,  42,  42,  42,  42,  46,  48,  50,  54,  54,  57,  58,  60,  63,  63,  66,  67,  68,  71,  71,  74,  75,  77,  79,  79,  83,
+             44,  42,  42,  41,  41,  41,  42,  42,  42,  42,  42,  46,  48,  50,  54,  54,  57,  58,  60,  63,  63,  66,  67,  68,  71,  71,  74,  75,  77,  79,  79,  83,
+             51,  49,  49,  48,  47,  47,  48,  48,  48,  48,  48,  52,  53,  55,  58,  58,  62,  63,  66,  69,  69,  73,  74,  76,  79,  79,  83,  84,  86,  89,  89,  93,
+             53,  52,  51,  50,  49,  49,  49,  50,  49,  49,  49,  53,  54,  56,  60,  60,  64,  65,  67,  71,  71,  75,  76,  78,  82,  82,  86,  87,  89,  92,  92,  96,
+             58,  56,  55,  54,  53,  53,  53,  53,  53,  52,  52,  56,  57,  59,  63,  63,  67,  68,  70,  74,  74,  78,  79,  82,  86,  86,  90,  91,  93,  97,  97, 101,
+             65,  63,  62,  61,  59,  59,  59,  59,  58,  58,  58,  62,  63,  65,  68,  68,  72,  73,  76,  79,  79,  84,  85,  88,  92,  92,  97,  98, 100, 105, 105, 109,
+             65,  63,  62,  61,  59,  59,  59,  59,  58,  58,  58,  62,  63,  65,  68,  68,  72,  73,  76,  79,  79,  84,  85,  88,  92,  92,  97,  98, 100, 105, 105, 109,
+        }, {
+             32,  31,  31,  31,  30,  30,  33,  33,  35,  37,  37,  41,  42,  44,  49,  49,  48,  48,  48,  49,  49,  50,  50,  51,  52,  52,  54,  54,  55,  57,  57,  59,
+             31,  31,  31,  31,  32,  32,  34,  35,  37,  39,  39,  42,  42,  44,  47,  47,  46,  46,  46,  46,  46,  47,  47,  48,  48,  48,  50,  51,  51,  53,  53,  55,
+             31,  31,  31,  32,  32,  32,  35,  36,  37,  40,  40,  42,  43,  44,  46,  46,  46,  46,  45,  45,  45,  46,  46,  47,  48,  48,  49,  50,  51,  52,  52,  54,
+             33,  34,  34,  34,  35,  35,  37,  38,  40,  43,  43,  44,  44,  45,  47,  47,  46,  46,  46,  45,  45,  46,  46,  47,  47,  47,  49,  49,  50,  51,  51,  53,
+             37,  38,  38,  39,  40,  40,  42,  43,  44,  47,  47,  47,  47,  47,  48,  48,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  48,  49,  49,  50,  50,  52,
+             37,  38,  38,  39,  40,  40,  42,  43,  44,  47,  47,  47,  47,  47,  48,  48,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  48,  49,  49,  50,  50,  52,
+             45,  45,  45,  45,  44,  44,  46,  46,  46,  47,  47,  49,  49,  50,  52,  52,  51,  51,  51,  51,  51,  52,  52,  52,  53,  53,  54,  54,  54,  55,  55,  57,
+             48,  47,  47,  46,  46,  46,  47,  47,  47,  47,  47,  49,  50,  51,  53,  53,  53,  53,  53,  53,  53,  54,  54,  54,  54,  54,  55,  55,  56,  56,  56,  58,
+             48,  47,  47,  46,  45,  45,  46,  46,  46,  47,  47,  49,  50,  51,  53,  53,  54,  54,  54,  55,  55,  56,  56,  56,  57,  57,  58,  58,  58,  59,  59,  61,
+             49,  47,  47,  46,  45,  45,  45,  46,  45,  45,  45,  48,  49,  51,  53,  53,  55,  56,  57,  58,  58,  59,  59,  60,  61,  61,  62,  62,  63,  64,  64,  65,
+             49,  47,  47,  46,  45,  45,  45,  46,  45,  45,  45,  48,  49,  51,  53,  53,  55,  56,  57,  58,  58,  59,  59,  60,  61,  61,  62,  62,  63,  64,  64,  65,
+             51,  50,  49,  48,  47,  47,  47,  47,  47,  46,  46,  49,  50,  52,  54,  54,  56,  57,  58,  61,  61,  62,  63,  64,  65,  65,  67,  67,  68,  69,  69,  70,
+             52,  50,  50,  49,  48,  48,  47,  47,  47,  47,  47,  50,  50,  52,  54,  54,  57,  57,  59,  61,  61,  63,  64,  65,  66,  66,  68,  68,  69,  70,  70,  72,
+             54,  52,  51,  51,  49,  49,  49,  49,  48,  48,  48,  51,  51,  53,  55,  55,  58,  58,  60,  62,  62,  64,  65,  66,  68,  68,  70,  70,  71,  73,  73,  74,
+             57,  55,  54,  53,  52,  52,  51,  51,  51,  50,  50,  52,  53,  54,  57,  57,  59,  60,  61,  64,  64,  66,  67,  68,  71,  71,  73,  73,  74,  76,  76,  78,
+             57,  55,  54,  53,  52,  52,  51,  51,  51,  50,  50,  52,  53,  54,  57,  57,  59,  60,  61,  64,  64,  66,  67,  68,  71,  71,  73,  73,  74,  76,  76,  78,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  34,  34,  35,  36,  36,  38,  39,  39,  42,  44,  44,  47,  48,  49,  53,  53,  55,  58,  58,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  35,  35,  37,  38,  38,  40,  42,  42,  45,  46,  47,  50,  51,  52,  55,  55,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  34,  34,  36,  37,  37,  40,  41,  41,  44,  45,  46,  49,  49,  51,  54,  54,
+             31,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  34,  34,  34,  35,  35,  37,  38,  38,  40,  41,  41,  44,  45,  46,  49,  49,  51,  54,  54,
+             32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  35,  35,  35,  36,  36,  37,  37,  37,  39,  40,  40,  42,  42,  43,  45,  46,  47,  49,  50,  51,  54,  54,
+             32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  35,  35,  36,  37,  37,  37,  38,  38,  40,  40,  40,  42,  43,  43,  45,  46,  47,  49,  50,  51,  54,  54,
+             32,  33,  33,  33,  33,  33,  33,  34,  34,  35,  36,  36,  36,  38,  38,  39,  40,  40,  41,  42,  42,  44,  45,  45,  47,  48,  48,  51,  51,  53,  55,  55,
+             35,  35,  35,  35,  34,  34,  35,  36,  36,  37,  38,  38,  39,  42,  42,  44,  47,  47,  48,  49,  49,  51,  52,  52,  54,  55,  56,  58,  59,  60,  62,  62,
+             36,  35,  35,  35,  35,  34,  35,  36,  36,  37,  38,  38,  40,  42,  42,  45,  48,  48,  49,  50,  50,  52,  53,  54,  56,  56,  57,  59,  60,  61,  63,  63,
+             38,  37,  37,  37,  36,  36,  36,  38,  38,  38,  39,  39,  41,  44,  44,  46,  49,  49,  51,  52,  52,  55,  56,  56,  58,  59,  60,  62,  63,  64,  67,  67,
+             44,  43,  42,  42,  41,  41,  41,  42,  42,  42,  42,  42,  44,  48,  48,  50,  54,  54,  56,  58,  58,  61,  63,  63,  66,  67,  67,  71,  71,  72,  75,  75,
+             44,  43,  42,  42,  41,  41,  41,  42,  42,  42,  42,  42,  44,  48,  48,  50,  54,  54,  56,  58,  58,  61,  63,  63,  66,  67,  67,  71,  71,  72,  75,  75,
+             47,  46,  45,  45,  44,  44,  44,  45,  45,  45,  45,  45,  47,  50,  50,  53,  56,  56,  58,  60,  60,  64,  66,  66,  69,  70,  71,  74,  75,  76,  79,  79,
+             53,  52,  51,  51,  49,  49,  49,  49,  50,  49,  49,  49,  51,  54,  54,  57,  60,  60,  63,  65,  65,  69,  71,  72,  75,  76,  77,  81,  82,  83,  87,  87,
+             53,  52,  51,  51,  49,  49,  49,  49,  50,  49,  49,  49,  51,  54,  54,  57,  60,  60,  63,  65,  65,  69,  71,  72,  75,  76,  77,  81,  82,  83,  87,  87,
+             59,  57,  56,  56,  54,  54,  54,  54,  54,  54,  53,  53,  55,  58,  58,  61,  64,  64,  67,  69,  69,  73,  75,  76,  79,  80,  81,  86,  87,  88,  92,  92,
+        }, {
+             32,  31,  31,  31,  30,  30,  31,  33,  33,  34,  37,  37,  39,  42,  42,  45,  49,  49,  48,  48,  48,  49,  49,  49,  50,  50,  51,  52,  52,  53,  54,  54,
+             31,  31,  31,  31,  31,  31,  32,  35,  35,  36,  39,  39,  40,  42,  42,  45,  47,  47,  47,  46,  46,  46,  46,  46,  47,  48,  48,  49,  49,  50,  51,  51,
+             31,  31,  31,  31,  32,  32,  33,  35,  36,  37,  40,  40,  41,  43,  43,  44,  46,  46,  46,  46,  46,  45,  45,  45,  46,  46,  47,  48,  48,  48,  50,  50,
+             31,  32,  32,  32,  32,  33,  33,  36,  36,  37,  41,  41,  42,  43,  43,  45,  47,  47,  46,  46,  46,  45,  45,  45,  46,  46,  47,  48,  48,  48,  50,  50,
+             35,  36,  37,  37,  38,  38,  38,  41,  41,  42,  45,  45,  46,  46,  46,  47,  48,  48,  47,  46,  46,  46,  45,  46,  46,  46,  47,  47,  47,  48,  49,  49,
+             37,  38,  38,  38,  39,  40,  40,  43,  43,  44,  47,  47,  47,  47,  47,  47,  48,  48,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  48,  49,  49,
+             38,  39,  40,  40,  40,  41,  41,  43,  44,  45,  47,  47,  47,  48,  48,  48,  49,  49,  48,  48,  48,  47,  47,  47,  48,  48,  48,  48,  48,  49,  50,  50,
+             47,  46,  46,  46,  45,  45,  45,  46,  46,  47,  47,  47,  48,  50,  50,  51,  52,  52,  52,  52,  52,  52,  52,  52,  53,  53,  53,  53,  53,  54,  55,  55,
+             48,  47,  47,  47,  46,  46,  46,  47,  47,  47,  47,  47,  48,  50,  50,  51,  53,  53,  53,  53,  53,  53,  53,  53,  54,  54,  54,  54,  54,  54,  55,  55,
+             48,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  48,  50,  50,  51,  53,  53,  53,  54,  54,  54,  55,  55,  55,  55,  55,  56,  56,  56,  57,  57,
+             49,  48,  47,  47,  45,  45,  45,  45,  46,  45,  45,  45,  47,  49,  49,  51,  53,  53,  55,  56,  56,  57,  58,  58,  59,  59,  60,  61,  61,  61,  62,  62,
+             49,  48,  47,  47,  45,  45,  45,  45,  46,  45,  45,  45,  47,  49,  49,  51,  53,  53,  55,  56,  56,  57,  58,  58,  59,  59,  60,  61,  61,  61,  62,  62,
+             50,  49,  48,  48,  46,  46,  46,  46,  46,  46,  46,  46,  47,  50,  50,  52,  54,  54,  55,  56,  56,  58,  59,  60,  61,  61,  61,  63,  63,  63,  65,  65,
+             52,  50,  50,  50,  48,  48,  48,  47,  47,  47,  47,  47,  48,  50,  50,  52,  54,  54,  56,  57,  57,  60,  61,  61,  63,  64,  64,  66,  66,  67,  68,  68,
+             52,  50,  50,  50,  48,  48,  48,  47,  47,  47,  47,  47,  48,  50,  50,  52,  54,  54,  56,  57,  57,  60,  61,  61,  63,  64,  64,  66,  66,  67,  68,  68,
+             54,  53,  52,  52,  50,  50,  50,  49,  49,  49,  48,  48,  50,  52,  52,  54,  55,  55,  57,  59,  59,  61,  62,  63,  65,  65,  66,  68,  68,  69,  71,  71,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  34,  34,  34,  35,  36,  36,  38,  39,  39,  41,  44,  44,  44,  47,  48,  48,  51,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  35,  35,  35,  37,  38,  38,  40,  42,  42,  43,  45,  46,  46,  49,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  34,  34,  34,  36,  37,  37,  39,  41,  41,  42,  44,  45,  45,  47,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  34,  34,  34,  36,  37,  37,  39,  41,  41,  42,  44,  45,  45,  47,
+             31,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  35,  35,  35,  36,  36,  36,  37,  39,  39,  40,  42,  42,  42,  44,  45,  45,  48,
+             32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  35,  35,  35,  36,  37,  37,  37,  38,  38,  38,  40,  40,  40,  41,  43,  43,  43,  45,  46,  46,  48,
+             32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  35,  35,  35,  36,  37,  37,  37,  38,  38,  38,  40,  40,  40,  41,  43,  43,  43,  45,  46,  46,  48,
+             32,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  35,  36,  36,  36,  38,  38,  38,  39,  40,  40,  41,  42,  42,  43,  45,  45,  45,  47,  48,  48,  50,
+             35,  35,  35,  35,  34,  34,  34,  34,  35,  36,  36,  37,  37,  37,  39,  41,  41,  42,  45,  46,  46,  47,  48,  48,  49,  51,  51,  51,  53,  54,  54,  56,
+             36,  35,  35,  35,  35,  34,  34,  35,  36,  36,  36,  37,  38,  38,  40,  42,  42,  43,  47,  48,  48,  49,  50,  50,  51,  53,  53,  54,  56,  56,  56,  58,
+             36,  35,  35,  35,  35,  34,  34,  35,  36,  36,  36,  37,  38,  38,  40,  42,  42,  43,  47,  48,  48,  49,  50,  50,  51,  53,  53,  54,  56,  56,  56,  58,
+             40,  39,  39,  39,  39,  38,  38,  38,  39,  39,  39,  40,  41,  41,  42,  45,  45,  46,  50,  51,  51,  53,  54,  54,  56,  59,  59,  59,  61,  62,  62,  64,
+             44,  43,  42,  42,  41,  41,  41,  41,  42,  42,  42,  42,  42,  42,  44,  48,  48,  49,  52,  54,  54,  56,  58,  58,  60,  63,  63,  64,  66,  67,  67,  69,
+             44,  43,  42,  42,  41,  41,  41,  41,  42,  42,  42,  42,  42,  42,  44,  48,  48,  49,  52,  54,  54,  56,  58,  58,  60,  63,  63,  64,  66,  67,  67,  69,
+             47,  46,  45,  45,  45,  44,  44,  44,  44,  45,  45,  45,  45,  45,  47,  50,  50,  51,  55,  56,  56,  58,  60,  60,  62,  66,  66,  67,  69,  70,  70,  73,
+             53,  52,  51,  51,  50,  49,  49,  49,  49,  50,  50,  49,  49,  49,  51,  54,  54,  55,  59,  60,  60,  63,  65,  65,  67,  71,  71,  72,  75,  76,  76,  79,
+        }, {
+             32,  31,  31,  31,  31,  30,  30,  31,  33,  33,  33,  35,  37,  37,  39,  42,  42,  43,  47,  49,  49,  48,  48,  48,  48,  49,  49,  49,  50,  50,  50,  51,
+             31,  31,  31,  31,  31,  31,  31,  32,  34,  35,  35,  37,  39,  39,  40,  42,  42,  43,  46,  47,  47,  47,  47,  47,  47,  46,  46,  47,  48,  48,  48,  49,
+             31,  31,  31,  31,  32,  32,  32,  33,  35,  36,  36,  38,  40,  40,  41,  43,  43,  43,  46,  46,  46,  46,  46,  46,  45,  45,  45,  45,  46,  46,  46,  47,
+             31,  31,  31,  31,  32,  32,  32,  33,  35,  36,  36,  38,  40,  40,  41,  43,  43,  43,  46,  46,  46,  46,  46,  46,  45,  45,  45,  45,  46,  46,  46,  47,
+             33,  33,  34,  34,  34,  35,  35,  35,  37,  38,  38,  41,  43,  43,  43,  44,  44,  45,  46,  47,  47,  46,  46,  46,  46,  45,  45,  45,  46,  46,  46,  47,
+             37,  38,  38,  38,  39,  40,  40,  40,  42,  43,  43,  45,  47,  47,  47,  47,  47,  47,  48,  48,  48,  47,  47,  47,  46,  46,  46,  46,  46,  46,  46,  47,
+             37,  38,  38,  38,  39,  40,  40,  40,  42,  43,  43,  45,  47,  47,  47,  47,  47,  47,  48,  48,  48,  47,  47,  47,  46,  46,  46,  46,  46,  46,  46,  47,
+             38,  39,  40,  40,  40,  41,  41,  41,  43,  44,  44,  46,  47,  47,  47,  48,  48,  48,  48,  49,  49,  48,  48,  48,  47,  47,  47,  47,  48,  48,  48,  48,
+             45,  45,  45,  45,  45,  44,  44,  45,  46,  46,  46,  47,  47,  47,  48,  49,  49,  50,  51,  52,  52,  52,  51,  51,  51,  51,  51,  52,  52,  52,  52,  52,
+             48,  47,  47,  47,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  48,  50,  50,  50,  52,  53,  53,  53,  53,  53,  53,  53,  53,  53,  54,  54,  54,  54,
+             48,  47,  47,  47,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  48,  50,  50,  50,  52,  53,  53,  53,  53,  53,  53,  53,  53,  53,  54,  54,  54,  54,
+             49,  48,  47,  47,  46,  45,  45,  45,  46,  46,  46,  46,  46,  46,  47,  49,  49,  50,  52,  53,  53,  54,  54,  54,  55,  56,  56,  56,  57,  57,  57,  58,
+             49,  48,  47,  47,  46,  45,  45,  45,  45,  46,  46,  45,  45,  45,  47,  49,  49,  50,  53,  53,  53,  55,  56,  56,  57,  58,  58,  58,  59,  59,  59,  60,
+             49,  48,  47,  47,  46,  45,  45,  45,  45,  46,  46,  45,  45,  45,  47,  49,  49,  50,  53,  53,  53,  55,  56,  56,  57,  58,  58,  58,  59,  59,  59,  60,
+             50,  49,  48,  48,  47,  46,  46,  46,  46,  46,  46,  46,  46,  46,  47,  50,  50,  50,  53,  54,  54,  55,  56,  56,  57,  59,  59,  60,  61,  61,  61,  62,
+             52,  51,  50,  50,  49,  48,  48,  48,  47,  47,  47,  47,  47,  47,  48,  50,  50,  51,  53,  54,  54,  56,  57,  57,  59,  61,  61,  62,  63,  64,  64,  65,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  35,  36,  36,  36,  37,  39,  39,  39,  41,  44,  44,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  34,  35,  35,  35,  37,  38,  38,  38,  40,  42,  42,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  36,  37,  37,  37,  39,  41,  41,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  36,  37,  37,  37,  39,  41,  41,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  36,  37,  37,  37,  39,  41,  41,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  34,  34,  34,  34,  35,  35,  35,  36,  36,  36,  36,  38,  39,  39,  39,  40,  42,  42,
+             32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  35,  35,  35,  36,  37,  37,  37,  37,  38,  38,  38,  39,  40,  40,  40,  42,  43,  43,
+             32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  35,  35,  35,  36,  37,  37,  37,  37,  38,  38,  38,  39,  40,  40,  40,  42,  43,  43,
+             32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  35,  35,  35,  36,  37,  37,  37,  37,  38,  38,  38,  39,  40,  40,  40,  42,  43,  43,
+             34,  34,  34,  34,  34,  34,  33,  33,  33,  34,  35,  35,  35,  36,  37,  37,  37,  38,  39,  39,  39,  41,  43,  43,  43,  44,  45,  45,  45,  46,  48,  48,
+             36,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  37,  38,  38,  38,  40,  42,  42,  42,  45,  48,  48,  48,  49,  50,  50,  50,  52,  53,  53,
+             36,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  37,  38,  38,  38,  40,  42,  42,  42,  45,  48,  48,  48,  49,  50,  50,  50,  52,  53,  53,
+             36,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  37,  38,  38,  38,  40,  42,  42,  42,  45,  48,  48,  48,  49,  50,  50,  50,  52,  53,  53,
+             39,  39,  38,  38,  38,  38,  37,  37,  37,  38,  39,  39,  39,  40,  40,  40,  40,  42,  45,  45,  45,  47,  51,  51,  51,  52,  54,  54,  54,  56,  58,  58,
+             44,  43,  42,  42,  42,  41,  41,  41,  41,  41,  42,  42,  42,  42,  42,  42,  42,  45,  48,  48,  48,  50,  54,  54,  54,  56,  58,  58,  58,  60,  63,  63,
+             44,  43,  42,  42,  42,  41,  41,  41,  41,  41,  42,  42,  42,  42,  42,  42,  42,  45,  48,  48,  48,  50,  54,  54,  54,  56,  58,  58,  58,  60,  63,  63,
+        }, {
+             32,  31,  31,  31,  31,  31,  30,  30,  30,  32,  33,  33,  33,  35,  37,  37,  37,  39,  42,  42,  42,  45,  49,  49,  49,  48,  48,  48,  48,  48,  49,  49,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  33,  34,  34,  34,  36,  38,  38,  38,  40,  42,  42,  42,  45,  48,  48,  48,  47,  47,  47,  47,  47,  47,  47,
+             31,  31,  31,  31,  31,  32,  32,  32,  32,  34,  36,  36,  36,  38,  40,  40,  40,  41,  43,  43,  43,  44,  46,  46,  46,  46,  46,  46,  46,  45,  45,  45,
+             31,  31,  31,  31,  31,  32,  32,  32,  32,  34,  36,  36,  36,  38,  40,  40,  40,  41,  43,  43,  43,  44,  46,  46,  46,  46,  46,  46,  46,  45,  45,  45,
+             31,  31,  31,  31,  31,  32,  32,  32,  32,  34,  36,  36,  36,  38,  40,  40,  40,  41,  43,  43,  43,  44,  46,  46,  46,  46,  46,  46,  46,  45,  45,  45,
+             33,  34,  34,  34,  34,  35,  35,  35,  35,  37,  39,  39,  39,  41,  43,  43,  43,  44,  45,  45,  45,  46,  47,  47,  47,  47,  46,  46,  46,  46,  45,  45,
+             37,  37,  38,  38,  38,  39,  40,  40,  40,  41,  43,  43,  43,  45,  47,  47,  47,  47,  47,  47,  47,  47,  48,  48,  48,  47,  47,  47,  47,  46,  46,  46,
+             37,  37,  38,  38,  38,  39,  40,  40,  40,  41,  43,  43,  43,  45,  47,  47,  47,  47,  47,  47,  47,  47,  48,  48,  48,  47,  47,  47,  47,  46,  46,  46,
+             37,  37,  38,  38,  38,  39,  40,  40,  40,  41,  43,  43,  43,  45,  47,  47,  47,  47,  47,  47,  47,  47,  48,  48,  48,  47,  47,  47,  47,  46,  46,  46,
+             42,  42,  42,  42,  42,  42,  42,  42,  42,  44,  45,  45,  45,  46,  47,  47,  47,  48,  48,  48,  48,  49,  50,  50,  50,  50,  50,  50,  50,  49,  49,  49,
+             48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  47,  49,  50,  50,  50,  51,  53,  53,  53,  53,  53,  53,  53,  53,  53,  53,
+             48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  47,  49,  50,  50,  50,  51,  53,  53,  53,  53,  53,  53,  53,  53,  53,  53,
+             48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  47,  49,  50,  50,  50,  51,  53,  53,  53,  53,  53,  53,  53,  53,  53,  53,
+             48,  48,  47,  47,  47,  46,  45,  45,  45,  46,  46,  46,  46,  46,  46,  46,  46,  48,  50,  50,  50,  51,  53,  53,  53,  54,  54,  54,  54,  55,  56,  56,
+             49,  48,  47,  47,  47,  46,  45,  45,  45,  45,  46,  46,  46,  45,  45,  45,  45,  47,  49,  49,  49,  51,  53,  53,  53,  54,  56,  56,  56,  57,  58,  58,
+             49,  48,  47,  47,  47,  46,  45,  45,  45,  45,  46,  46,  46,  45,  45,  45,  45,  47,  49,  49,  49,  51,  53,  53,  53,  54,  56,  56,  56,  57,  58,  58,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  34,  35,  36,  36,  36,  37,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  35,  35,  35,  35,  36,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  34,  35,  35,  35,  36,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  36,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  36,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  36,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  35,  35,  35,  35,  35,  36,  36,  36,  36,  37,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  34,  35,  35,  35,  35,  36,  36,  36,  36,  37,  37,  37,  37,  37,  38,
+             32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  34,  35,  35,  35,  35,  36,  36,  37,  37,  37,  37,  38,  38,  38,  38,  39,
+             32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  34,  35,  35,  35,  35,  36,  36,  37,  37,  37,  37,  38,  38,  38,  38,  39,
+             32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  34,  35,  35,  35,  35,  36,  36,  37,  37,  37,  37,  38,  38,  38,  38,  39,
+             33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  35,  35,  35,  35,  36,  36,  36,  36,  37,  38,  39,  39,  39,  40,  41,  42,  42,  42,  42,
+             35,  35,  35,  35,  35,  35,  34,  34,  34,  34,  34,  35,  35,  36,  36,  36,  36,  37,  37,  37,  37,  39,  40,  41,  41,  41,  43,  45,  46,  46,  46,  46,
+             36,  35,  35,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  36,  37,  38,  38,  38,  38,  40,  41,  42,  42,  42,  44,  47,  48,  48,  48,  49,
+             36,  35,  35,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  36,  37,  38,  38,  38,  38,  40,  41,  42,  42,  42,  44,  47,  48,  48,  48,  49,
+             36,  35,  35,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  36,  37,  38,  38,  38,  38,  40,  41,  42,  42,  42,  44,  47,  48,  48,  48,  49,
+        }, {
+             32,  31,  31,  31,  31,  31,  31,  30,  30,  30,  30,  31,  33,  33,  33,  33,  35,  36,  37,  37,  37,  39,  41,  42,  42,  42,  44,  47,  49,  49,  49,  49,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  34,  34,  34,  34,  36,  37,  38,  38,  38,  39,  41,  42,  42,  42,  44,  46,  48,  48,  48,  48,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  33,  34,  35,  35,  35,  37,  38,  39,  39,  39,  40,  42,  42,  42,  42,  44,  46,  47,  47,  47,  47,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  33,  35,  36,  36,  36,  37,  39,  40,  40,  40,  41,  42,  43,  43,  43,  44,  46,  46,  46,  46,  46,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  33,  35,  36,  36,  36,  37,  39,  40,  40,  40,  41,  42,  43,  43,  43,  44,  46,  46,  46,  46,  46,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  33,  35,  36,  36,  36,  37,  39,  40,  40,  40,  41,  42,  43,  43,  43,  44,  46,  46,  46,  46,  46,
+             33,  33,  34,  34,  34,  34,  34,  34,  35,  35,  35,  36,  37,  38,  38,  38,  40,  42,  43,  43,  43,  43,  44,  44,  44,  44,  45,  46,  47,  47,  47,  47,
+             35,  36,  36,  37,  37,  37,  37,  38,  38,  38,  38,  39,  40,  41,  41,  41,  43,  44,  45,  45,  45,  46,  46,  46,  46,  46,  47,  47,  48,  48,  48,  47,
+             37,  37,  38,  38,  38,  38,  39,  39,  40,  40,  40,  41,  42,  43,  43,  43,  44,  46,  47,  47,  47,  47,  47,  47,  47,  47,  47,  48,  48,  48,  48,  47,
+             37,  37,  38,  38,  38,  38,  39,  39,  40,  40,  40,  41,  42,  43,  43,  43,  44,  46,  47,  47,  47,  47,  47,  47,  47,  47,  47,  48,  48,  48,  48,  47,
+             37,  37,  38,  38,  38,  38,  39,  39,  40,  40,  40,  41,  42,  43,  43,  43,  44,  46,  47,  47,  47,  47,  47,  47,  47,  47,  47,  48,  48,  48,  48,  47,
+             40,  41,  41,  41,  41,  41,  41,  42,  42,  42,  42,  43,  44,  44,  44,  44,  45,  47,  47,  47,  47,  48,  48,  48,  48,  48,  49,  49,  50,  50,  50,  49,
+             45,  45,  45,  45,  45,  45,  45,  44,  44,  44,  44,  45,  46,  46,  46,  46,  46,  47,  47,  47,  47,  48,  49,  49,  49,  49,  50,  51,  52,  52,  52,  52,
+             48,  48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  47,  47,  47,  48,  49,  50,  50,  50,  51,  52,  53,  53,  53,  53,
+             48,  48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  47,  47,  47,  48,  49,  50,  50,  50,  51,  52,  53,  53,  53,  53,
+             48,  48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  47,  47,  47,  48,  49,  50,  50,  50,  51,  52,  53,  53,  53,  53,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  34,  34,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  34,  34,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  34,  34,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  35,  35,  36,  36,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  37,  37,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  37,  37,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  37,  37,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  37,  37,
+             32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,  35,  36,  36,  36,  36,  36,  36,  37,  38,  38,
+             34,  34,  34,  34,  34,  34,  34,  34,  34,  33,  33,  33,  33,  33,  34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  37,  37,  37,  37,  38,  38,  39,  39,
+        }, {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  30,  30,  30,  30,  30,  31,  32,  33,  33,  33,  33,  33,  34,  35,  36,  37,  37,  37,  37,  39,  40,  42,  42,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  33,  34,  34,  34,  34,  35,  36,  37,  38,  38,  38,  38,  39,  41,  42,  42,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  33,  34,  35,  35,  35,  35,  36,  37,  38,  39,  39,  39,  39,  40,  41,  42,  42,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  33,  35,  35,  35,  35,  35,  37,  38,  39,  40,  40,  40,  40,  41,  42,  43,  43,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  36,  36,  36,  37,  38,  39,  40,  40,  40,  40,  41,  42,  43,  43,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  36,  36,  36,  37,  38,  39,  40,  40,  40,  40,  41,  42,  43,  43,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  36,  36,  36,  37,  38,  39,  40,  40,  40,  40,  41,  42,  43,  43,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  34,  35,  36,  36,  36,  36,  37,  39,  40,  41,  41,  41,  41,  42,  42,  43,  43,
+             33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  36,  37,  38,  38,  38,  38,  39,  41,  42,  43,  43,  43,  43,  43,  44,  44,  44,
+             35,  35,  35,  36,  36,  36,  36,  36,  36,  37,  37,  37,  37,  37,  38,  39,  40,  40,  40,  40,  40,  42,  43,  44,  45,  45,  45,  45,  45,  45,  46,  46,
+             37,  37,  38,  38,  38,  38,  38,  38,  39,  39,  40,  40,  40,  40,  40,  41,  42,  43,  43,  43,  43,  44,  45,  47,  47,  47,  47,  47,  47,  47,  47,  47,
+             37,  37,  38,  38,  38,  38,  38,  38,  39,  39,  40,  40,  40,  40,  40,  41,  42,  43,  43,  43,  43,  44,  45,  47,  47,  47,  47,  47,  47,  47,  47,  47,
+             37,  37,  38,  38,  38,  38,  38,  38,  39,  39,  40,  40,  40,  40,  40,  41,  42,  43,  43,  43,  43,  44,  45,  47,  47,  47,  47,  47,  47,  47,  47,  47,
+             37,  37,  38,  38,  38,  38,  38,  38,  39,  39,  40,  40,  40,  40,  40,  41,  42,  43,  43,  43,  43,  44,  45,  47,  47,  47,  47,  47,  47,  47,  47,  47,
+             38,  39,  39,  40,  40,  40,  40,  40,  40,  40,  41,  41,  41,  41,  41,  42,  43,  44,  44,  44,  44,  45,  46,  47,  47,  47,  47,  47,  47,  47,  48,  48,
+             42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  43,  44,  44,  45,  45,  45,  45,  45,  46,  47,  47,  47,  47,  47,  48,  48,  48,  48,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,
+        }, {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  30,  30,  30,  30,  30,  30,  30,  31,  31,  32,  33,  33,  33,  33,  33,  33,  33,  34,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  33,  34,  34,  34,  34,  34,  34,  34,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  33,  34,  34,  34,  34,  34,  34,  34,  35,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  33,  33,  34,  35,  35,  35,  35,  35,  35,  35,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  35,  35,  35,  35,  35,  35,  36,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  35,  36,  36,  36,  36,  36,  36,  36,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  35,  36,  36,  36,  36,  36,  36,  36,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  35,  36,  36,  36,  36,  36,  36,  36,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  35,  36,  36,  36,  36,  36,  36,  36,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  35,  36,  36,  36,  36,  36,  36,  36,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  35,  36,  36,  36,  36,  36,  36,  36,
+             32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  35,  35,  36,  37,  37,  37,  37,  37,  37,  38,
+             33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  36,  37,  37,  38,  38,  38,  38,  38,  38,  39,
+             34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  35,  35,  36,  36,  36,  36,  36,  36,  36,  36,  36,  37,  37,  38,  39,  40,  40,  40,  40,  40,  40,  40,
+             35,  35,  36,  36,  36,  37,  37,  37,  37,  37,  37,  37,  37,  37,  38,  38,  38,  38,  38,  38,  38,  38,  39,  40,  40,  41,  41,  41,  41,  41,  41,  42,
+             37,  37,  37,  38,  38,  38,  38,  38,  38,  38,  38,  38,  39,  39,  39,  40,  40,  40,  40,  40,  40,  40,  41,  41,  42,  43,  43,  43,  43,  43,  43,  44,
+        },
+    }, {
+        {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+        }, {
+             32,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  30,  30,  30,  30,  30,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  30,  30,  30,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+        },
+    },
+};
+
+static const uint8_t qm_tbl_32x32_t[][2][528] = {
+    {
+        {
+             32,
+             31,  32,
+             31,  32,  32,
+             31,  32,  32,  32,
+             31,  32,  32,  33,  33,
+             32,  32,  32,  33,  34,  35,
+             34,  34,  33,  34,  35,  37,  39,
+             35,  34,  34,  35,  36,  37,  41,  43,
+             36,  35,  34,  35,  36,  38,  42,  45,  48,
+             39,  38,  37,  38,  39,  40,  45,  47,  50,  54,
+             44,  42,  41,  41,  42,  42,  47,  50,  54,  58,  63,
+             46,  44,  42,  43,  44,  44,  49,  52,  55,  59,  65,  67,
+             48,  46,  44,  45,  45,  46,  51,  53,  57,  61,  67,  69,  71,
+             54,  51,  49,  49,  50,  49,  54,  57,  60,  65,  71,  74,  76,  82,
+             59,  56,  54,  54,  54,  53,  58,  61,  64,  69,  75,  78,  80,  87,  92,
+             62,  59,  56,  56,  56,  55,  60,  63,  66,  71,  77,  80,  83,  89,  95,  98,
+             65,  62,  59,  59,  59,  58,  63,  65,  68,  73,  79,  82,  85,  92,  98, 101, 105,
+             71,  68,  65,  64,  64,  63,  68,  70,  73,  78,  84,  87,  90,  97, 103, 107, 111, 117,
+             80,  76,  72,  72,  71,  69,  74,  76,  79,  84,  90,  93,  96, 104, 110, 114, 118, 125, 134,
+             81,  77,  73,  73,  72,  70,  75,  77,  80,  85,  91,  94,  97, 105, 111, 115, 119, 126, 135, 137,
+             83,  78,  75,  74,  74,  72,  76,  79,  81,  86,  92,  95,  99, 106, 113, 117, 121, 128, 137, 138, 140,
+             88,  84,  80,  79,  78,  76,  80,  82,  85,  91,  95,  98, 103, 111, 115, 119, 126, 134, 139, 144, 147, 152,
+             91,  86,  83,  82,  81,  79,  81,  84,  88,  92,  95, 100, 107, 110, 115, 123, 127, 132, 140, 147, 151, 154, 159,
+             94,  89,  86,  85,  84,  82,  82,  86,  90,  92,  97, 103, 105, 111, 119, 121, 128, 136, 139, 146, 156, 158, 161, 166,
+             97,  92,  90,  88,  86,  85,  84,  89,  91,  95, 100, 102, 108, 114, 116, 125, 130, 133, 143, 148, 152, 163, 166, 168, 174,
+            101,  95,  93,  91,  89,  89,  87,  91,  93,  98, 101, 105, 111, 113, 120, 126, 130, 138, 142, 149, 157, 159, 171, 174, 176, 183,
+            104,  99,  97,  94,  93,  93,  90,  92,  96, 100, 102, 108, 111, 116, 122, 125, 134, 137, 144, 151, 155, 165, 169, 179, 182, 184, 191,
+            107, 102, 101,  97,  96,  96,  93,  93,  99, 101, 105, 110, 113, 120, 122, 129, 133, 140, 146, 150, 161, 163, 173, 178, 187, 191, 193, 200,
+            111, 105, 104, 101, 100,  99,  97,  96, 102, 103, 109, 111, 117, 120, 125, 131, 135, 143, 146, 156, 158, 168, 173, 180, 189, 195, 200, 202, 210,
+            115, 109, 108, 104, 104, 102, 101, 100, 103, 106, 111, 113, 119, 121, 129, 131, 140, 142, 151, 155, 162, 168, 176, 183, 188, 199, 204, 210, 212, 220,
+            119, 113, 112, 107, 107, 106, 105, 103, 105, 110, 112, 117, 120, 125, 130, 135, 140, 145, 152, 157, 165, 169, 179, 183, 193, 197, 210, 214, 220, 222, 231,
+            123, 116, 116, 111, 111, 109, 110, 107, 107, 114, 114, 121, 122, 130, 130, 140, 140, 150, 151, 163, 164, 176, 177, 190, 191, 204, 206, 222, 224, 230, 232, 242,
+        }, {
+             32,
+             31,  31,
+             30,  31,  32,
+             32,  33,  33,  35,
+             33,  34,  35,  37,  39,
+             36,  38,  40,  41,  43,  47,
+             41,  42,  42,  43,  45,  47,  48,
+             45,  45,  44,  45,  46,  47,  49,  50,
+             49,  47,  46,  47,  47,  48,  50,  51,  53,
+             48,  47,  45,  46,  46,  46,  49,  51,  53,  54,
+             49,  47,  45,  45,  45,  45,  49,  51,  53,  55,  58,
+             50,  47,  45,  46,  46,  46,  49,  51,  54,  56,  59,  60,
+             50,  48,  46,  46,  46,  46,  50,  52,  54,  56,  60,  60,  61,
+             52,  50,  47,  47,  47,  47,  50,  52,  54,  57,  61,  62,  63,  66,
+             54,  52,  49,  49,  49,  48,  52,  53,  55,  58,  62,  64,  65,  68,  71,
+             56,  53,  51,  50,  50,  49,  52,  54,  56,  59,  63,  64,  66,  69,  72,  73,
+             57,  54,  52,  51,  51,  50,  53,  55,  56,  60,  63,  65,  67,  70,  73,  75,  76,
+             60,  57,  54,  54,  53,  52,  55,  57,  58,  61,  65,  67,  68,  72,  75,  77,  79,  82,
+             63,  60,  57,  57,  56,  54,  57,  59,  60,  63,  67,  69,  71,  75,  78,  80,  82,  85,  89,
+             64,  61,  58,  57,  57,  55,  58,  59,  61,  64,  67,  69,  71,  75,  78,  80,  82,  85,  89,  90,
+             65,  61,  58,  58,  57,  55,  58,  60,  61,  64,  68,  70,  71,  75,  79,  81,  83,  86,  90,  91,  91,
+             67,  63,  61,  60,  59,  57,  60,  61,  63,  66,  69,  70,  73,  77,  79,  81,  85,  88,  90,  92,  94,  96,
+             68,  64,  62,  61,  60,  58,  59,  61,  64,  66,  67,  71,  74,  75,  78,  82,  84,  86,  90,  93,  94,  96,  98,
+             69,  65,  63,  62,  61,  59,  59,  62,  64,  65,  68,  71,  72,  75,  79,  80,  83,  87,  89,  92,  96,  97,  98, 100,
+             70,  66,  64,  63,  62,  61,  60,  63,  64,  66,  69,  70,  73,  76,  77,  81,  84,  85,  89,  92,  93,  98,  99, 100, 102,
+             71,  67,  66,  64,  63,  62,  61,  63,  64,  67,  68,  70,  74,  75,  78,  81,  83,  86,  88,  91,  94,  95, 100, 101, 102, 104,
+             72,  68,  67,  65,  64,  64,  61,  63,  65,  67,  68,  71,  73,  75,  78,  79,  84,  85,  88,  91,  93,  97,  98, 102, 103, 104, 106,
+             73,  69,  68,  66,  65,  65,  63,  63,  66,  67,  69,  71,  73,  76,  77,  81,  82,  85,  88,  90,  94,  95,  99, 101, 104, 105, 106, 109,
+             74,  70,  70,  67,  66,  66,  64,  63,  66,  67,  70,  71,  74,  75,  78,  80,  82,  86,  87,  91,  92,  96,  98, 101, 104, 106, 108, 108, 111,
+             75,  71,  71,  68,  68,  67,  66,  64,  66,  68,  70,  71,  74,  75,  79,  79,  84,  84,  88,  90,  93,  95,  98, 101, 103, 107, 108, 110, 111, 113,
+             76,  72,  72,  69,  69,  68,  67,  65,  66,  69,  70,  72,  74,  76,  78,  81,  83,  85,  88,  90,  93,  95,  98, 100, 104, 105, 109, 111, 112, 113, 116,
+             78,  74,  74,  70,  70,  69,  69,  66,  66,  70,  70,  74,  74,  77,  78,  82,  82,  86,  87,  92,  92,  96,  97, 102, 102, 107, 107, 112, 113, 115, 115, 118,
+        },
+    }, {
+        {
+             32,
+             31,  32,
+             31,  32,  32,
+             31,  32,  32,  32,
+             31,  32,  32,  32,  33,
+             32,  32,  32,  33,  34,  35,
+             32,  33,  33,  33,  34,  36,  36,
+             34,  34,  33,  34,  35,  37,  38,  39,
+             36,  35,  34,  35,  36,  38,  40,  42,  48,
+             38,  37,  36,  36,  38,  39,  41,  44,  50,  51,
+             39,  38,  37,  38,  39,  40,  42,  45,  50,  52,  54,
+             44,  42,  41,  41,  42,  42,  44,  47,  54,  56,  58,  63,
+             47,  45,  44,  44,  45,  45,  47,  50,  56,  58,  60,  66,  69,
+             49,  47,  46,  45,  46,  46,  48,  51,  57,  60,  62,  68,  71,  73,
+             54,  51,  50,  49,  50,  49,  51,  54,  60,  63,  65,  71,  75,  77,  82,
+             59,  56,  54,  54,  54,  53,  55,  58,  64,  67,  69,  75,  79,  81,  87,  92,
+             61,  58,  56,  56,  56,  55,  57,  60,  65,  68,  70,  77,  81,  83,  89,  94,  97,
+             65,  62,  60,  59,  59,  58,  60,  63,  68,  71,  73,  79,  84,  87,  92,  98, 101, 105,
+             71,  68,  65,  65,  64,  63,  65,  68,  73,  76,  78,  84,  89,  92,  97, 103, 106, 111, 117,
+             76,  72,  70,  69,  68,  66,  68,  71,  76,  79,  81,  88,  92,  95, 101, 107, 110, 115, 122, 127,
+             80,  76,  73,  72,  71,  69,  71,  74,  79,  82,  84,  90,  95,  98, 104, 110, 113, 118, 125, 130, 134,
+             83,  78,  76,  75,  74,  72,  73,  76,  81,  84,  86,  92,  97, 100, 106, 113, 116, 121, 128, 133, 137, 140,
+             86,  82,  79,  78,  77,  74,  76,  79,  84,  87,  89,  95, 100, 103, 109, 116, 119, 124, 131, 136, 140, 144, 147,
+             89,  85,  82,  81,  79,  78,  78,  82,  86,  87,  92,  97, 100, 105, 112, 114, 120, 128, 131, 136, 146, 147, 150, 155,
+             92,  88,  85,  84,  82,  81,  80,  85,  86,  90,  95,  97, 102, 107, 110, 117, 122, 125, 134, 138, 142, 152, 154, 156, 162,
+             95,  90,  88,  86,  85,  84,  82,  86,  88,  93,  95,  99, 105, 106, 113, 118, 121, 129, 132, 139, 146, 148, 159, 161, 163, 169,
+             98,  93,  91,  89,  88,  87,  85,  87,  90,  94,  96, 102, 104, 109, 114, 117, 126, 128, 134, 141, 145, 154, 157, 166, 168, 170, 176,
+            101,  96,  95,  92,  91,  90,  88,  88,  93,  95,  99, 103, 106, 112, 114, 121, 124, 131, 136, 140, 149, 151, 160, 165, 173, 176, 178, 184,
+            104,  99,  98,  95,  94,  93,  91,  90,  95,  96, 102, 103, 109, 112, 117, 122, 125, 133, 136, 145, 146, 156, 160, 167, 174, 180, 184, 186, 193,
+            108, 102, 101,  98,  97,  96,  95,  93,  97, 100, 104, 106, 111, 113, 121, 122, 130, 132, 140, 143, 150, 155, 162, 169, 174, 183, 188, 192, 194, 201,
+            111, 105, 105, 101, 100,  99,  98,  96,  98, 103, 105, 109, 112, 117, 121, 125, 130, 135, 141, 146, 152, 156, 165, 169, 178, 181, 193, 196, 201, 202, 210,
+            114, 109, 109, 104, 104, 102, 102,  99, 100, 106, 106, 113, 113, 120, 121, 129, 130, 139, 140, 151, 151, 162, 162, 175, 176, 187, 188, 203, 204, 210, 211, 219,
+        }, {
+             32,
+             31,  31,
+             30,  31,  31,
+             31,  32,  32,  33,
+             33,  34,  35,  36,  39,
+             36,  38,  39,  40,  43,  47,
+             38,  40,  41,  41,  44,  47,  47,
+             41,  42,  42,  43,  45,  47,  48,  48,
+             49,  47,  46,  46,  47,  48,  49,  50,  53,
+             49,  47,  46,  46,  46,  47,  48,  50,  53,  53,
+             48,  47,  46,  45,  46,  46,  48,  49,  53,  54,  54,
+             49,  47,  45,  45,  45,  45,  47,  49,  53,  55,  55,  58,
+             50,  48,  46,  46,  46,  46,  47,  50,  54,  55,  56,  59,  61,
+             51,  48,  47,  46,  47,  46,  47,  50,  54,  55,  56,  60,  61,  62,
+             52,  50,  48,  47,  47,  47,  48,  50,  54,  56,  57,  61,  63,  64,  66,
+             54,  52,  50,  49,  49,  48,  49,  52,  55,  57,  58,  62,  64,  66,  68,  71,
+             55,  53,  51,  50,  50,  49,  50,  52,  56,  58,  59,  63,  65,  66,  69,  72,  73,
+             57,  54,  52,  51,  51,  50,  51,  53,  56,  58,  60,  63,  66,  67,  70,  73,  74,  76,
+             60,  57,  55,  54,  53,  52,  53,  55,  58,  60,  61,  65,  68,  69,  72,  75,  77,  79,  82,
+             62,  59,  57,  56,  55,  53,  54,  56,  59,  61,  63,  66,  69,  70,  74,  77,  78,  80,  84,  86,
+             63,  60,  58,  57,  56,  54,  55,  57,  60,  62,  63,  67,  70,  71,  75,  78,  79,  82,  85,  87,  89,
+             65,  61,  59,  58,  57,  55,  56,  58,  61,  63,  64,  68,  71,  72,  75,  79,  80,  83,  86,  88,  90,  91,
+             66,  63,  60,  59,  58,  56,  58,  59,  62,  64,  65,  69,  72,  73,  76,  80,  81,  84,  87,  90,  91,  93,  94,
+             67,  64,  62,  61,  59,  58,  58,  60,  63,  64,  66,  69,  71,  73,  77,  78,  81,  85,  86,  89,  93,  94,  95,  97,
+             68,  65,  63,  62,  60,  59,  58,  61,  62,  64,  67,  68,  71,  74,  75,  79,  81,  83,  87,  89,  91,  95,  96,  97,  99,
+             69,  66,  64,  63,  61,  61,  59,  61,  62,  65,  66,  68,  72,  73,  76,  78,  80,  84,  85,  88,  91,  92,  97,  98,  98, 101,
+             70,  67,  65,  63,  62,  62,  60,  61,  63,  65,  66,  69,  71,  73,  76,  77,  81,  83,  85,  88,  90,  94,  95,  99, 100, 100, 103,
+             71,  67,  67,  64,  63,  63,  61,  61,  64,  65,  67,  69,  71,  74,  75,  78,  80,  83,  85,  87,  91,  92,  95,  97, 100, 102, 102, 105,
+             72,  68,  68,  65,  65,  64,  62,  62,  64,  65,  68,  69,  72,  73,  76,  78,  80,  83,  84,  88,  89,  93,  95,  97, 100, 102, 104, 104, 107,
+             73,  69,  69,  66,  66,  65,  64,  63,  64,  66,  68,  69,  72,  73,  77,  77,  81,  82,  86,  87,  90,  92,  95,  97,  99, 103, 104, 106, 106, 109,
+             74,  70,  70,  67,  67,  66,  65,  63,  64,  67,  68,  70,  72,  74,  76,  78,  80,  82,  85,  87,  90,  91,  95,  96, 100, 101, 105, 106, 108, 108, 111,
+             75,  71,  71,  68,  68,  66,  66,  64,  64,  68,  68,  71,  71,  75,  75,  79,  79,  83,  84,  88,  89,  93,  93,  98,  98, 102, 103, 108, 108, 110, 110, 113,
+        },
+    }, {
+        {
+             32,
+             31,  32,
+             31,  32,  32,
+             31,  32,  32,  32,
+             31,  32,  32,  32,  33,
+             32,  32,  32,  32,  33,  34,
+             32,  32,  32,  32,  34,  34,  35,
+             34,  34,  33,  33,  35,  36,  37,  39,
+             34,  34,  34,  34,  36,  36,  37,  41,  42,
+             36,  35,  34,  34,  36,  37,  38,  42,  45,  48,
+             39,  38,  38,  37,  39,  40,  40,  45,  47,  50,  54,
+             41,  39,  39,  38,  40,  40,  41,  46,  48,  51,  55,  56,
+             44,  42,  41,  41,  42,  42,  42,  47,  50,  54,  58,  59,  63,
+             48,  46,  45,  44,  45,  45,  45,  50,  53,  56,  61,  62,  66,  70,
+             49,  47,  46,  45,  46,  46,  46,  51,  53,  57,  62,  63,  68,  71,  73,
+             54,  51,  50,  49,  50,  49,  49,  54,  56,  60,  65,  67,  71,  76,  77,  82,
+             58,  55,  54,  53,  53,  53,  52,  57,  59,  63,  68,  70,  74,  79,  81,  86,  90,
+             59,  57,  55,  54,  54,  54,  54,  59,  61,  64,  69,  71,  75,  80,  82,  87,  91,  93,
+             65,  62,  60,  59,  59,  58,  58,  63,  65,  68,  73,  75,  79,  85,  87,  92,  97,  99, 105,
+             69,  66,  64,  63,  63,  62,  61,  66,  68,  71,  76,  78,  83,  88,  90,  96, 100, 102, 109, 113,
+             71,  68,  66,  65,  64,  63,  63,  68,  70,  73,  78,  80,  84,  90,  92,  97, 102, 104, 111, 115, 117,
+             80,  76,  73,  72,  71,  70,  69,  74,  76,  79,  84,  86,  90,  96,  98, 104, 109, 111, 118, 123, 125, 134,
+             81,  77,  75,  74,  73,  72,  71,  75,  77,  80,  85,  87,  91,  97,  99, 105, 110, 112, 120, 125, 127, 136, 137,
+             83,  78,  76,  75,  74,  73,  72,  76,  78,  81,  86,  88,  92,  98, 100, 106, 111, 113, 121, 126, 128, 137, 139, 140,
+             87,  83,  81,  79,  78,  77,  75,  80,  82,  85,  90,  91,  96, 101, 103, 110, 114, 117, 125, 129, 133, 142, 143, 145, 150,
+             90,  85,  83,  81,  80,  79,  78,  81,  83,  87,  89,  93,  98, 100, 106, 110, 114, 121, 124, 130, 136, 138, 148, 149, 151, 156,
+             93,  88,  86,  84,  83,  82,  80,  82,  85,  89,  90,  96,  98, 102, 107, 109, 118, 120, 125, 131, 134, 143, 145, 153, 156, 157, 163,
+             95,  90,  89,  86,  85,  85,  83,  83,  88,  89,  93,  97,  99, 105, 106, 113, 116, 122, 127, 130, 139, 140, 148, 153, 159, 162, 164, 169,
+             98,  93,  92,  89,  88,  87,  86,  85,  89,  90,  96,  97, 102, 105, 109, 114, 117, 124, 126, 134, 136, 144, 148, 154, 160, 166, 169, 170, 176,
+            101,  96,  95,  91,  91,  90,  89,  87,  90,  93,  97,  99, 104, 105, 112, 113, 121, 122, 130, 133, 139, 144, 150, 155, 160, 168, 172, 176, 177, 184,
+            104,  99,  98,  94,  94,  92,  92,  90,  92,  96,  98, 102, 104, 109, 112, 116, 121, 125, 130, 135, 141, 144, 152, 155, 163, 166, 177, 179, 184, 185, 191,
+            107, 101, 101,  97,  97,  95,  95,  93,  93,  99,  99, 105, 105, 112, 112, 120, 120, 129, 129, 139, 140, 149, 149, 161, 161, 172, 172, 185, 186, 191, 192, 199,
+        }, {
+             32,
+             31,  31,
+             30,  31,  31,
+             30,  31,  31,  32,
+             33,  34,  35,  35,  39,
+             35,  36,  37,  37,  41,  43,
+             36,  38,  39,  40,  43,  45,  47,
+             41,  42,  42,  42,  45,  46,  47,  48,
+             44,  44,  44,  44,  46,  46,  47,  49,  50,
+             49,  47,  47,  46,  47,  47,  48,  50,  51,  53,
+             48,  47,  46,  45,  46,  46,  46,  49,  51,  53,  54,
+             48,  47,  46,  45,  46,  46,  46,  49,  51,  53,  54,  55,
+             49,  47,  46,  45,  45,  45,  45,  49,  51,  53,  55,  56,  58,
+             50,  48,  47,  46,  46,  46,  46,  50,  51,  54,  56,  57,  59,  61,
+             51,  48,  47,  46,  47,  46,  46,  50,  51,  54,  56,  57,  60,  62,  62,
+             52,  50,  48,  47,  47,  47,  47,  50,  52,  54,  57,  58,  61,  63,  64,  66,
+             54,  51,  50,  49,  49,  48,  48,  51,  53,  55,  58,  59,  62,  64,  65,  68,  70,
+             55,  52,  51,  50,  49,  49,  48,  52,  53,  55,  59,  60,  62,  65,  66,  68,  70,  71,
+             57,  54,  53,  52,  51,  50,  50,  53,  54,  56,  60,  61,  63,  66,  67,  70,  73,  73,  76,
+             59,  56,  54,  53,  53,  52,  51,  54,  56,  58,  61,  62,  65,  68,  69,  72,  74,  75,  78,  80,
+             60,  57,  55,  54,  53,  53,  52,  55,  56,  58,  61,  63,  65,  68,  69,  72,  75,  76,  79,  81,  82,
+             63,  60,  58,  57,  56,  55,  54,  57,  59,  60,  63,  65,  67,  70,  71,  75,  77,  78,  82,  84,  85,  89,
+             64,  61,  59,  58,  57,  56,  55,  58,  59,  61,  64,  65,  68,  71,  72,  75,  78,  79,  82,  85,  86,  89,  90,
+             65,  61,  60,  58,  57,  56,  55,  58,  59,  61,  64,  65,  68,  71,  72,  75,  78,  79,  83,  85,  86,  90,  91,  91,
+             67,  63,  61,  60,  59,  58,  57,  60,  61,  63,  65,  66,  69,  72,  73,  77,  79,  80,  84,  86,  88,  92,  93,  93,  95,
+             68,  64,  63,  61,  60,  59,  58,  60,  61,  63,  65,  67,  70,  71,  74,  76,  78,  81,  83,  86,  88,  89,  94,  94,  95,  97,
+             68,  65,  64,  62,  61,  60,  58,  59,  61,  64,  64,  68,  69,  71,  74,  75,  79,  80,  83,  86,  87,  91,  92,  95,  96,  97,  99,
+             69,  66,  65,  63,  62,  61,  59,  59,  62,  63,  65,  67,  69,  72,  72,  76,  78,  80,  83,  84,  88,  89,  92,  94,  97,  98,  99, 101,
+             70,  67,  66,  63,  63,  62,  61,  60,  63,  63,  66,  67,  69,  71,  73,  76,  77,  81,  82,  85,  86,  90,  91,  94,  96,  99, 100, 100, 103,
+             71,  67,  67,  64,  64,  63,  62,  61,  62,  64,  66,  67,  70,  71,  74,  74,  78,  79,  83,  84,  87,  89,  91,  94,  95,  99, 100, 102, 102, 104,
+             72,  68,  68,  65,  65,  64,  63,  61,  62,  65,  66,  68,  69,  71,  73,  75,  77,  79,  82,  84,  87,  88,  92,  93,  96,  97, 101, 102, 104, 104, 106,
+             73,  69,  69,  66,  66,  64,  64,  62,  62,  66,  66,  69,  69,  72,  73,  76,  77,  81,  81,  85,  85,  89,  90,  94,  94,  99,  99, 104, 104, 106, 106, 108,
+        },
+    }, {
+        {
+             32,
+             31,  32,
+             31,  32,  32,
+             31,  32,  32,  32,
+             31,  32,  32,  32,  33,
+             31,  32,  32,  32,  33,  33,
+             32,  32,  32,  32,  33,  34,  35,
+             32,  33,  33,  33,  34,  34,  36,  36,
+             34,  34,  34,  33,  35,  35,  37,  38,  39,
+             35,  35,  34,  34,  36,  36,  38,  39,  42,  46,
+             36,  35,  35,  34,  36,  36,  38,  40,  42,  47,  48,
+             39,  38,  38,  37,  39,  39,  40,  42,  45,  49,  50,  54,
+             41,  40,  39,  38,  40,  40,  41,  43,  46,  50,  52,  55,  57,
+             44,  42,  42,  41,  42,  42,  42,  44,  47,  52,  54,  58,  60,  63,
+             47,  45,  45,  44,  44,  45,  45,  47,  50,  55,  56,  60,  62,  66,  69,
+             48,  46,  45,  44,  45,  45,  46,  47,  51,  55,  57,  61,  63,  67,  70,  71,
+             54,  51,  50,  49,  49,  50,  49,  51,  54,  59,  60,  65,  67,  71,  75,  76,  82,
+             56,  53,  52,  51,  51,  51,  51,  53,  56,  60,  61,  66,  69,  73,  77,  78,  84,  86,
+             59,  56,  55,  54,  54,  54,  53,  55,  58,  62,  64,  69,  71,  75,  79,  80,  87,  89,  92,
+             64,  61,  60,  58,  58,  58,  57,  59,  62,  66,  67,  72,  75,  79,  83,  84,  91,  93,  97, 102,
+             65,  62,  61,  59,  59,  59,  58,  60,  63,  67,  68,  73,  75,  79,  84,  85,  92,  94,  98, 103, 105,
+             71,  68,  67,  65,  64,  64,  63,  65,  68,  72,  73,  78,  80,  84,  89,  90,  97, 100, 103, 109, 111, 117,
+             74,  71,  69,  68,  67,  67,  65,  67,  70,  74,  75,  80,  83,  86,  91,  93, 100, 102, 106, 112, 114, 120, 123,
+             80,  76,  74,  72,  71,  71,  69,  71,  74,  78,  79,  84,  86,  90,  95,  96, 104, 106, 110, 116, 118, 125, 128, 134,
+             82,  78,  76,  74,  73,  73,  71,  73,  76,  79,  80,  86,  88,  92,  97,  98, 106, 108, 112, 118, 120, 127, 131, 136, 139,
+             83,  78,  77,  75,  74,  74,  72,  73,  76,  80,  81,  86,  89,  92,  97,  99, 106, 109, 113, 119, 121, 128, 131, 137, 139, 140,
+             87,  83,  81,  79,  78,  78,  75,  77,  80,  83,  85,  90,  92,  96, 100, 102, 110, 112, 117, 122, 125, 133, 135, 142, 144, 145, 150,
+             90,  85,  84,  81,  80,  80,  78,  78,  82,  84,  87,  91,  93,  98,  99, 106, 108, 113, 118, 121, 129, 130, 137, 141, 147, 150, 151, 156,
+             92,  88,  87,  84,  83,  82,  80,  80,  84,  85,  90,  91,  95,  98, 102, 106, 109, 115, 117, 125, 126, 134, 137, 142, 148, 152, 155, 156, 162,
+             95,  90,  89,  86,  85,  84,  83,  82,  85,  87,  91,  92,  97,  98, 105, 105, 112, 114, 121, 123, 129, 133, 138, 143, 147, 155, 158, 161, 162, 168,
+             97,  92,  92,  88,  88,  86,  86,  84,  85,  90,  91,  95,  97, 101, 104, 108, 112, 116, 121, 125, 130, 133, 140, 143, 150, 152, 162, 164, 168, 168, 174,
+            100,  95,  95,  90,  90,  89,  89,  86,  86,  92,  92,  97,  98, 104, 104, 111, 111, 119, 119, 128, 129, 137, 137, 147, 148, 157, 158, 169, 170, 174, 175, 181,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             30,  31,  31,  32,
+             33,  34,  34,  34,  37,
+             33,  34,  35,  35,  38,  39,
+             36,  38,  39,  40,  42,  43,  47,
+             38,  40,  40,  41,  43,  44,  47,  47,
+             41,  42,  42,  42,  44,  45,  47,  48,  48,
+             47,  46,  46,  45,  46,  47,  47,  48,  50,  52,
+             49,  47,  47,  46,  47,  47,  48,  49,  50,  52,  53,
+             48,  47,  46,  45,  46,  46,  46,  48,  49,  52,  53,  54,
+             49,  47,  46,  45,  46,  46,  46,  47,  49,  52,  53,  55,  55,
+             49,  47,  46,  45,  45,  45,  45,  47,  49,  52,  53,  55,  57,  58,
+             50,  48,  47,  46,  46,  46,  46,  47,  50,  53,  54,  56,  57,  59,  61,
+             50,  48,  47,  46,  46,  46,  46,  47,  50,  53,  54,  56,  58,  60,  61,  61,
+             52,  50,  49,  47,  47,  47,  47,  48,  50,  53,  54,  57,  59,  61,  63,  63,  66,
+             53,  50,  50,  48,  48,  48,  47,  49,  51,  54,  55,  58,  59,  62,  64,  64,  67,  68,
+             54,  52,  51,  49,  49,  49,  48,  49,  52,  55,  55,  58,  60,  62,  64,  65,  68,  69,  71,
+             56,  54,  53,  51,  51,  51,  49,  51,  53,  55,  56,  59,  61,  63,  66,  66,  70,  71,  73,  75,
+             57,  54,  53,  52,  51,  51,  50,  51,  53,  56,  56,  60,  61,  63,  66,  67,  70,  71,  73,  76,  76,
+             60,  57,  56,  54,  53,  53,  52,  53,  55,  58,  58,  61,  63,  65,  68,  68,  72,  73,  75,  78,  79,  82,
+             61,  58,  57,  55,  55,  54,  53,  54,  56,  58,  59,  62,  64,  66,  69,  69,  73,  74,  76,  79,  80,  83,  84,
+             63,  60,  59,  57,  56,  56,  54,  55,  57,  60,  60,  63,  65,  67,  70,  71,  75,  76,  78,  81,  82,  85,  86,  89,
+             64,  61,  60,  58,  57,  57,  55,  56,  58,  60,  61,  64,  66,  68,  70,  71,  75,  77,  79,  82,  82,  86,  87,  90,  91,
+             65,  61,  60,  58,  57,  57,  55,  56,  58,  61,  61,  64,  66,  68,  71,  71,  75,  77,  79,  82,  83,  86,  88,  90,  91,  91,
+             67,  63,  62,  60,  59,  59,  57,  58,  60,  62,  63,  66,  67,  69,  72,  73,  77,  78,  80,  83,  84,  88,  89,  92,  93,  93,  95,
+             67,  64,  63,  61,  60,  60,  58,  58,  61,  61,  63,  65,  67,  70,  70,  74,  75,  78,  80,  81,  85,  86,  89,  91,  93,  94,  95,  97,
+             68,  65,  64,  62,  61,  60,  59,  58,  61,  61,  64,  65,  67,  69,  71,  73,  75,  78,  79,  83,  83,  87,  88,  91,  93,  95,  96,  97,  99,
+             69,  65,  65,  62,  62,  61,  60,  59,  61,  62,  64,  65,  68,  68,  72,  72,  76,  76,  80,  81,  84,  86,  88,  90,  92,  95,  96,  98,  98, 100,
+             70,  66,  66,  63,  63,  62,  61,  60,  60,  63,  64,  66,  67,  69,  71,  73,  75,  77,  79,  81,  84,  85,  88,  89,  93,  93,  97,  98, 100, 100, 102,
+             71,  67,  67,  64,  64,  62,  62,  60,  60,  64,  64,  67,  67,  70,  70,  74,  74,  78,  78,  82,  82,  86,  86,  91,  91,  95,  95, 100, 100, 101, 101, 104,
+        },
+    }, {
+        {
+             32,
+             31,  32,
+             31,  32,  32,
+             31,  32,  32,  32,
+             31,  32,  32,  32,  32,
+             31,  32,  32,  32,  33,  33,
+             32,  32,  32,  32,  33,  33,  34,
+             32,  32,  32,  32,  33,  34,  35,  35,
+             33,  33,  33,  33,  34,  35,  36,  36,  38,
+             34,  34,  34,  33,  34,  35,  36,  37,  39,  39,
+             36,  35,  35,  34,  35,  36,  37,  38,  42,  42,  48,
+             36,  35,  35,  34,  35,  36,  38,  38,  42,  43,  48,  49,
+             39,  38,  38,  37,  38,  39,  40,  40,  44,  45,  50,  51,  54,
+             41,  39,  39,  38,  39,  40,  40,  41,  45,  46,  51,  52,  55,  56,
+             44,  42,  42,  41,  41,  42,  42,  42,  46,  47,  54,  54,  58,  59,  63,
+             46,  44,  44,  42,  43,  44,  44,  44,  48,  49,  55,  55,  59,  61,  65,  67,
+             48,  46,  46,  44,  45,  45,  45,  46,  50,  51,  57,  57,  61,  63,  67,  69,  71,
+             52,  50,  49,  48,  48,  48,  48,  48,  52,  53,  59,  59,  64,  65,  70,  72,  74,  78,
+             54,  51,  51,  49,  49,  50,  49,  49,  53,  54,  60,  60,  65,  67,  71,  74,  76,  80,  82,
+             58,  56,  55,  53,  53,  53,  53,  53,  57,  58,  63,  64,  68,  70,  75,  77,  80,  84,  86,  91,
+             59,  56,  56,  54,  54,  54,  53,  53,  57,  58,  64,  64,  69,  70,  75,  78,  80,  85,  87,  91,  92,
+             65,  62,  61,  59,  59,  59,  58,  58,  62,  63,  68,  68,  73,  75,  79,  82,  85,  90,  92,  97,  98, 105,
+             66,  63,  63,  60,  60,  60,  59,  59,  63,  64,  69,  69,  74,  76,  80,  83,  86,  91,  93,  98,  99, 106, 107,
+             71,  68,  67,  65,  65,  64,  63,  63,  67,  68,  73,  73,  78,  80,  84,  87,  90,  95,  97, 103, 103, 111, 112, 117,
+             74,  71,  70,  68,  67,  67,  66,  65,  69,  70,  75,  75,  80,  82,  86,  89,  93,  97, 100, 105, 106, 114, 115, 120, 123,
+             80,  76,  75,  72,  72,  71,  70,  69,  73,  74,  79,  79,  84,  86,  90,  93,  96, 101, 104, 110, 110, 118, 119, 125, 128, 134,
+             81,  77,  77,  74,  73,  73,  71,  71,  74,  75,  80,  80,  85,  87,  91,  94,  98, 103, 105, 111, 112, 120, 121, 127, 130, 136, 137,
+             83,  78,  78,  75,  74,  74,  72,  72,  75,  76,  81,  81,  86,  88,  92,  95,  99, 104, 106, 112, 113, 121, 122, 128, 131, 137, 139, 140,
+             86,  82,  81,  78,  77,  77,  75,  74,  78,  79,  84,  84,  89,  91,  95,  98, 101, 106, 109, 115, 116, 124, 125, 131, 135, 140, 142, 144, 147,
+             89,  84,  84,  80,  80,  79,  78,  77,  79,  81,  85,  86,  91,  92,  97,  98, 104, 106, 112, 114, 119, 123, 128, 132, 135, 142, 145, 148, 149, 153,
+             91,  86,  86,  82,  82,  81,  80,  79,  80,  84,  85,  88,  91,  94,  97, 100, 104, 107, 112, 115, 120, 123, 129, 132, 138, 140, 148, 150, 153, 154, 159,
+             93,  88,  88,  84,  84,  83,  83,  80,  81,  86,  86,  91,  91,  96,  97, 103, 103, 110, 110, 118, 119, 126, 126, 135, 136, 144, 144, 155, 155, 159, 159, 164,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             30,  31,  31,  32,
+             31,  32,  32,  33,  34,
+             33,  34,  35,  35,  37,  39,
+             35,  37,  37,  38,  39,  41,  44,
+             36,  38,  39,  40,  41,  43,  46,  47,
+             40,  41,  41,  42,  43,  44,  46,  47,  48,
+             41,  42,  42,  42,  43,  45,  46,  47,  48,  48,
+             49,  47,  47,  46,  46,  47,  47,  48,  50,  50,  53,
+             49,  47,  47,  46,  46,  47,  47,  47,  49,  50,  53,  53,
+             48,  47,  47,  45,  46,  46,  46,  46,  49,  49,  53,  53,  54,
+             48,  47,  46,  45,  45,  46,  46,  46,  49,  49,  53,  53,  54,  55,
+             49,  47,  46,  45,  45,  45,  45,  45,  48,  49,  53,  54,  55,  56,  58,
+             50,  47,  47,  45,  46,  46,  46,  46,  49,  49,  54,  54,  56,  57,  59,  60,
+             50,  48,  48,  46,  46,  46,  46,  46,  49,  50,  54,  54,  56,  57,  60,  60,  61,
+             52,  49,  49,  47,  47,  47,  47,  46,  49,  50,  54,  54,  57,  58,  61,  62,  63,  65,
+             52,  50,  49,  47,  47,  47,  47,  47,  49,  50,  54,  54,  57,  58,  61,  62,  63,  65,  66,
+             54,  52,  51,  49,  49,  49,  48,  48,  51,  52,  55,  55,  58,  59,  62,  63,  65,  67,  68,  70,
+             54,  52,  51,  49,  49,  49,  48,  48,  51,  52,  55,  56,  58,  60,  62,  64,  65,  67,  68,  70,  71,
+             57,  54,  54,  52,  51,  51,  50,  50,  52,  53,  56,  57,  60,  61,  63,  65,  67,  69,  70,  73,  73,  76,
+             57,  55,  54,  52,  52,  51,  51,  50,  53,  53,  57,  57,  60,  61,  64,  65,  67,  70,  71,  73,  74,  77,  77,
+             60,  57,  56,  54,  54,  53,  52,  52,  54,  55,  58,  59,  61,  63,  65,  67,  68,  71,  72,  75,  75,  79,  79,  82,
+             61,  58,  57,  55,  55,  54,  53,  53,  55,  56,  59,  59,  62,  63,  66,  68,  69,  72,  73,  76,  76,  80,  80,  83,  84,
+             63,  60,  59,  57,  57,  56,  55,  54,  57,  57,  60,  61,  63,  65,  67,  69,  71,  73,  75,  78,  78,  82,  82,  85,  86,  89,
+             64,  61,  60,  58,  57,  57,  56,  55,  57,  58,  61,  61,  64,  65,  68,  69,  71,  74,  75,  78,  78,  82,  83,  86,  87,  89,  90,
+             65,  61,  61,  58,  58,  57,  56,  55,  58,  58,  61,  62,  64,  65,  68,  70,  71,  74,  75,  78,  79,  83,  83,  86,  88,  90,  91,  91,
+             66,  63,  62,  60,  59,  58,  57,  56,  59,  59,  62,  63,  65,  66,  69,  70,  72,  75,  76,  79,  80,  84,  84,  87,  89,  91,  92,  93,  94,
+             67,  64,  63,  61,  60,  59,  58,  57,  59,  60,  62,  63,  66,  66,  70,  70,  73,  74,  77,  78,  81,  83,  85,  87,  89,  92,  93,  94,  94,  96,
+             68,  64,  64,  61,  61,  60,  59,  58,  59,  61,  62,  64,  65,  67,  69,  71,  72,  74,  77,  78,  81,  82,  85,  86,  89,  90,  94,  94,  96,  96,  98,
+             69,  65,  65,  62,  62,  61,  61,  58,  59,  62,  62,  65,  65,  68,  68,  71,  71,  75,  75,  79,  79,  83,  83,  87,  87,  91,  91,  96,  96,  97,  97,  99,
+        },
+    }, {
+        {
+             32,
+             31,  32,
+             31,  32,  32,
+             31,  32,  32,  32,
+             31,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  33,
+             31,  32,  32,  32,  32,  33,  33,
+             32,  32,  32,  32,  32,  34,  34,  35,
+             32,  32,  32,  32,  32,  34,  34,  35,  35,
+             34,  34,  34,  33,  33,  35,  35,  37,  37,  39,
+             34,  34,  34,  33,  33,  35,  35,  37,  37,  39,  39,
+             36,  35,  35,  34,  34,  36,  36,  38,  38,  42,  42,  48,
+             36,  35,  35,  34,  34,  36,  36,  38,  38,  42,  42,  48,  48,
+             39,  38,  38,  37,  37,  39,  39,  40,  40,  45,  45,  50,  50,  54,
+             39,  38,  38,  37,  37,  39,  39,  40,  40,  45,  45,  50,  50,  54,  54,
+             44,  42,  42,  41,  41,  42,  42,  42,  42,  47,  47,  54,  54,  58,  58,  63,
+             44,  42,  42,  41,  41,  42,  42,  42,  42,  47,  47,  54,  54,  58,  58,  63,  63,
+             48,  46,  46,  44,  44,  45,  45,  46,  46,  51,  51,  57,  57,  61,  61,  67,  67,  71,
+             48,  46,  46,  44,  44,  45,  45,  46,  46,  51,  51,  57,  57,  61,  61,  67,  67,  71,  71,
+             54,  51,  51,  49,  49,  50,  50,  49,  49,  54,  54,  60,  60,  65,  65,  71,  71,  76,  76,  82,
+             54,  51,  51,  49,  49,  50,  50,  49,  49,  54,  54,  60,  60,  65,  65,  71,  71,  76,  76,  82,  82,
+             59,  56,  56,  54,  54,  54,  54,  53,  53,  58,  58,  64,  64,  69,  69,  75,  75,  80,  80,  87,  87,  92,
+             59,  56,  56,  54,  54,  54,  54,  53,  53,  58,  58,  64,  64,  69,  69,  75,  75,  80,  80,  87,  87,  92,  92,
+             65,  62,  62,  59,  59,  59,  59,  58,  58,  63,  63,  68,  68,  73,  73,  79,  79,  85,  85,  92,  92,  98,  98, 105,
+             65,  62,  62,  59,  59,  59,  59,  58,  58,  63,  63,  68,  68,  73,  73,  79,  79,  85,  85,  92,  92,  98,  98, 105, 105,
+             71,  68,  68,  65,  65,  64,  64,  63,  63,  68,  68,  73,  73,  78,  78,  84,  84,  90,  90,  97,  97, 103, 103, 111, 111, 117,
+             71,  68,  68,  65,  65,  64,  64,  63,  63,  68,  68,  73,  73,  78,  78,  84,  84,  90,  90,  97,  97, 103, 103, 111, 111, 117, 117,
+             80,  76,  76,  72,  72,  71,  71,  69,  69,  74,  74,  79,  79,  84,  84,  90,  90,  96,  96, 104, 104, 110, 110, 118, 118, 125, 125, 134,
+             80,  76,  76,  72,  72,  71,  71,  69,  69,  74,  74,  79,  79,  84,  84,  90,  90,  96,  96, 104, 104, 110, 110, 118, 118, 125, 125, 134, 134,
+             83,  78,  78,  75,  75,  74,  74,  72,  72,  76,  76,  81,  81,  86,  86,  92,  92,  99,  99, 106, 106, 113, 113, 121, 121, 128, 128, 137, 137, 140,
+             83,  78,  78,  75,  75,  74,  74,  72,  72,  76,  76,  81,  81,  86,  86,  92,  92,  99,  99, 106, 106, 113, 113, 121, 121, 128, 128, 137, 137, 140, 140,
+             87,  83,  83,  79,  79,  77,  77,  75,  75,  80,  80,  84,  84,  90,  90,  96,  96, 102, 102, 109, 109, 116, 116, 124, 124, 132, 132, 141, 141, 144, 144, 149,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             30,  31,  31,  32,
+             30,  31,  31,  32,  32,
+             33,  34,  34,  35,  35,  39,
+             33,  34,  34,  35,  35,  39,  39,
+             36,  38,  38,  40,  40,  43,  43,  47,
+             36,  38,  38,  40,  40,  43,  43,  47,  47,
+             41,  42,  42,  42,  42,  45,  45,  47,  47,  48,
+             41,  42,  42,  42,  42,  45,  45,  47,  47,  48,  48,
+             49,  47,  47,  46,  46,  47,  47,  48,  48,  50,  50,  53,
+             49,  47,  47,  46,  46,  47,  47,  48,  48,  50,  50,  53,  53,
+             48,  47,  47,  45,  45,  46,  46,  46,  46,  49,  49,  53,  53,  54,
+             48,  47,  47,  45,  45,  46,  46,  46,  46,  49,  49,  53,  53,  54,  54,
+             49,  47,  47,  45,  45,  45,  45,  45,  45,  49,  49,  53,  53,  55,  55,  58,
+             49,  47,  47,  45,  45,  45,  45,  45,  45,  49,  49,  53,  53,  55,  55,  58,  58,
+             50,  48,  48,  46,  46,  46,  46,  46,  46,  50,  50,  54,  54,  56,  56,  60,  60,  61,
+             50,  48,  48,  46,  46,  46,  46,  46,  46,  50,  50,  54,  54,  56,  56,  60,  60,  61,  61,
+             52,  50,  50,  47,  47,  47,  47,  47,  47,  50,  50,  54,  54,  57,  57,  61,  61,  63,  63,  66,
+             52,  50,  50,  47,  47,  47,  47,  47,  47,  50,  50,  54,  54,  57,  57,  61,  61,  63,  63,  66,  66,
+             54,  52,  52,  49,  49,  49,  49,  48,  48,  52,  52,  55,  55,  58,  58,  62,  62,  65,  65,  68,  68,  71,
+             54,  52,  52,  49,  49,  49,  49,  48,  48,  52,  52,  55,  55,  58,  58,  62,  62,  65,  65,  68,  68,  71,  71,
+             57,  54,  54,  52,  52,  51,  51,  50,  50,  53,  53,  56,  56,  60,  60,  63,  63,  67,  67,  70,  70,  73,  73,  76,
+             57,  54,  54,  52,  52,  51,  51,  50,  50,  53,  53,  56,  56,  60,  60,  63,  63,  67,  67,  70,  70,  73,  73,  76,  76,
+             60,  57,  57,  54,  54,  53,  53,  52,  52,  55,  55,  58,  58,  61,  61,  65,  65,  68,  68,  72,  72,  75,  75,  79,  79,  82,
+             60,  57,  57,  54,  54,  53,  53,  52,  52,  55,  55,  58,  58,  61,  61,  65,  65,  68,  68,  72,  72,  75,  75,  79,  79,  82,  82,
+             63,  60,  60,  57,  57,  56,  56,  54,  54,  57,  57,  60,  60,  63,  63,  67,  67,  71,  71,  75,  75,  78,  78,  82,  82,  85,  85,  89,
+             63,  60,  60,  57,  57,  56,  56,  54,  54,  57,  57,  60,  60,  63,  63,  67,  67,  71,  71,  75,  75,  78,  78,  82,  82,  85,  85,  89,  89,
+             65,  61,  61,  58,  58,  57,  57,  55,  55,  58,  58,  61,  61,  64,  64,  68,  68,  71,  71,  75,  75,  79,  79,  83,  83,  86,  86,  90,  90,  91,
+             65,  61,  61,  58,  58,  57,  57,  55,  55,  58,  58,  61,  61,  64,  64,  68,  68,  71,  71,  75,  75,  79,  79,  83,  83,  86,  86,  90,  90,  91,  91,
+             67,  63,  63,  60,  60,  59,  59,  57,  57,  60,  60,  62,  62,  66,  66,  69,  69,  72,  72,  76,  76,  80,  80,  84,  84,  88,  88,  92,  92,  93,  93,  95,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  32,  32,
+             31,  32,  32,  32,
+             31,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  33,  33,
+             32,  32,  32,  32,  32,  33,  33,  34,
+             32,  32,  32,  32,  32,  33,  34,  34,  35,
+             32,  32,  32,  32,  33,  33,  34,  34,  35,  35,
+             34,  34,  34,  33,  33,  34,  35,  35,  37,  37,  39,
+             34,  34,  34,  33,  33,  34,  35,  35,  37,  37,  39,  39,
+             35,  35,  35,  34,  34,  35,  36,  36,  38,  38,  42,  42,  46,
+             36,  35,  35,  34,  34,  35,  36,  37,  38,  38,  42,  42,  47,  48,
+             38,  37,  37,  36,  36,  37,  38,  38,  39,  40,  44,  44,  48,  50,  51,
+             39,  38,  38,  38,  37,  38,  39,  39,  40,  41,  45,  45,  49,  50,  52,  54,
+             41,  40,  40,  39,  38,  39,  40,  40,  41,  41,  46,  46,  50,  52,  54,  55,  57,
+             44,  42,  42,  41,  41,  41,  42,  42,  42,  43,  47,  47,  52,  54,  56,  58,  60,  63,
+             45,  43,  43,  42,  41,  42,  42,  43,  43,  43,  48,  48,  53,  54,  57,  58,  60,  64,  65,
+             48,  46,  46,  45,  44,  45,  45,  45,  46,  46,  51,  51,  55,  57,  59,  61,  63,  67,  68,  71,
+             48,  46,  46,  45,  44,  45,  45,  45,  46,  46,  51,  51,  55,  57,  59,  61,  63,  67,  68,  71,  71,
+             53,  51,  51,  49,  49,  49,  49,  49,  49,  49,  54,  54,  58,  59,  62,  64,  67,  71,  72,  75,  75,  81,
+             54,  52,  51,  50,  49,  49,  50,  49,  49,  50,  54,  54,  59,  60,  63,  65,  67,  71,  72,  76,  76,  81,  82,
+             57,  55,  55,  53,  52,  52,  52,  52,  52,  52,  57,  57,  61,  62,  65,  67,  70,  74,  75,  79,  79,  85,  85,  89,
+             59,  56,  56,  54,  54,  54,  54,  54,  53,  54,  58,  58,  62,  64,  67,  69,  71,  75,  76,  80,  80,  86,  87,  90,  92,
+             62,  59,  59,  57,  56,  56,  56,  56,  55,  56,  60,  60,  64,  66,  69,  71,  73,  77,  78,  83,  83,  89,  89,  93,  95,  98,
+             65,  62,  62,  60,  59,  59,  59,  59,  58,  58,  63,  63,  67,  68,  71,  73,  75,  79,  81,  85,  85,  91,  92,  96,  98, 101, 105,
+             67,  64,  64,  62,  61,  61,  60,  60,  59,  60,  64,  64,  68,  69,  72,  74,  77,  81,  82,  87,  87,  93,  94,  98,  99, 103, 106, 108,
+             71,  68,  68,  66,  65,  64,  64,  64,  63,  63,  68,  68,  72,  73,  76,  78,  80,  84,  85,  90,  90,  97,  97, 102, 103, 107, 111, 113, 117,
+             72,  69,  69,  66,  65,  65,  65,  64,  63,  64,  68,  68,  72,  73,  76,  78,  81,  85,  86,  91,  91,  97,  98, 102, 104, 108, 111, 113, 118, 119,
+             80,  76,  76,  73,  72,  72,  71,  70,  69,  70,  74,  74,  78,  79,  82,  84,  86,  90,  91,  96,  96, 103, 104, 108, 110, 114, 118, 120, 125, 126, 134,
+             80,  76,  76,  73,  72,  72,  71,  70,  69,  70,  74,  74,  78,  79,  82,  84,  86,  90,  91,  96,  96, 103, 104, 108, 110, 114, 118, 120, 125, 126, 134, 134,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             30,  31,  31,  31,
+             30,  31,  31,  31,  32,
+             32,  32,  33,  33,  33,  35,
+             33,  34,  34,  35,  35,  37,  39,
+             34,  35,  35,  36,  36,  38,  40,  41,
+             36,  38,  38,  39,  40,  41,  43,  44,  47,
+             37,  38,  39,  40,  40,  42,  43,  44,  47,  47,
+             41,  42,  42,  42,  42,  43,  45,  45,  47,  47,  48,
+             41,  42,  42,  42,  42,  43,  45,  45,  47,  47,  48,  48,
+             47,  46,  46,  46,  45,  46,  47,  47,  47,  48,  50,  50,  52,
+             49,  48,  47,  47,  46,  47,  47,  47,  48,  48,  50,  50,  52,  53,
+             49,  47,  47,  46,  46,  46,  46,  47,  47,  47,  50,  50,  52,  53,  53,
+             48,  47,  47,  46,  45,  46,  46,  46,  46,  47,  49,  49,  52,  53,  54,  54,
+             49,  47,  47,  46,  45,  45,  46,  46,  46,  46,  49,  49,  52,  53,  54,  55,  55,
+             49,  47,  47,  45,  45,  45,  45,  45,  45,  45,  49,  49,  52,  53,  55,  55,  57,  58,
+             49,  47,  47,  46,  45,  45,  45,  45,  45,  46,  49,  49,  52,  53,  55,  56,  57,  59,  59,
+             50,  48,  48,  47,  46,  46,  46,  46,  46,  46,  50,  50,  53,  54,  55,  56,  58,  60,  60,  61,
+             50,  48,  48,  47,  46,  46,  46,  46,  46,  46,  50,  50,  53,  54,  55,  56,  58,  60,  60,  61,  61,
+             52,  50,  49,  48,  47,  47,  47,  47,  46,  47,  50,  50,  53,  54,  56,  57,  59,  61,  61,  63,  63,  66,
+             52,  50,  50,  48,  47,  47,  47,  47,  47,  47,  50,  50,  53,  54,  56,  57,  59,  61,  61,  63,  63,  66,  66,
+             54,  51,  51,  50,  49,  49,  49,  48,  48,  48,  51,  51,  54,  55,  57,  58,  60,  62,  62,  65,  65,  67,  68,  69,
+             54,  52,  52,  50,  49,  49,  49,  49,  48,  48,  52,  52,  55,  55,  57,  58,  60,  62,  63,  65,  65,  68,  68,  70,  71,
+             56,  53,  53,  51,  51,  50,  50,  50,  49,  49,  52,  52,  55,  56,  58,  59,  61,  63,  63,  66,  66,  69,  69,  71,  72,  73,
+             57,  54,  54,  52,  52,  51,  51,  51,  50,  50,  53,  53,  56,  56,  58,  60,  61,  63,  64,  67,  67,  70,  70,  72,  73,  75,  76,
+             58,  55,  55,  53,  52,  52,  52,  51,  50,  51,  54,  54,  56,  57,  59,  60,  62,  64,  65,  67,  67,  71,  71,  73,  74,  75,  77,  78,
+             60,  57,  57,  55,  54,  54,  53,  53,  52,  52,  55,  55,  58,  58,  60,  61,  63,  65,  66,  68,  68,  72,  72,  74,  75,  77,  79,  80,  82,
+             60,  57,  57,  55,  54,  54,  54,  53,  52,  52,  55,  55,  58,  58,  60,  62,  63,  65,  66,  69,  69,  72,  73,  75,  76,  77,  79,  80,  82,  82,
+             63,  60,  60,  58,  57,  57,  56,  55,  54,  55,  57,  57,  60,  60,  62,  63,  65,  67,  68,  71,  71,  74,  75,  77,  78,  80,  82,  83,  85,  85,  89,
+             63,  60,  60,  58,  57,  57,  56,  55,  54,  55,  57,  57,  60,  60,  62,  63,  65,  67,  68,  71,  71,  74,  75,  77,  78,  80,  82,  83,  85,  85,  89,  89,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  31,  32,
+             31,  32,  32,  32,
+             31,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  33,
+             31,  32,  32,  32,  32,  32,  33,  33,
+             32,  32,  32,  32,  32,  32,  33,  33,  34,
+             32,  32,  32,  32,  32,  32,  33,  34,  34,  35,
+             32,  32,  32,  32,  32,  32,  33,  34,  34,  35,  35,
+             33,  33,  33,  33,  33,  33,  34,  35,  35,  36,  36,  38,
+             34,  34,  34,  34,  33,  33,  35,  35,  36,  37,  37,  39,  39,
+             34,  34,  34,  34,  34,  34,  35,  36,  36,  37,  37,  40,  41,  42,
+             36,  35,  35,  35,  34,  34,  36,  36,  37,  38,  38,  42,  42,  45,  48,
+             36,  35,  35,  35,  34,  34,  36,  36,  37,  38,  38,  42,  42,  45,  48,  48,
+             38,  38,  38,  37,  37,  37,  38,  38,  39,  40,  40,  43,  44,  46,  50,  50,  52,
+             39,  38,  38,  38,  37,  37,  39,  39,  39,  40,  40,  44,  45,  47,  50,  50,  53,  54,
+             41,  40,  40,  39,  38,  38,  40,  40,  40,  41,  41,  45,  46,  48,  52,  52,  54,  55,  57,
+             44,  42,  42,  42,  41,  41,  42,  42,  42,  42,  42,  46,  47,  50,  54,  54,  57,  58,  60,  63,
+             44,  42,  42,  42,  41,  41,  42,  42,  42,  42,  42,  46,  47,  50,  54,  54,  57,  58,  60,  63,  63,
+             47,  46,  45,  45,  44,  44,  44,  45,  45,  45,  45,  49,  50,  52,  56,  56,  59,  60,  62,  66,  66,  69,
+             48,  47,  46,  45,  44,  44,  45,  45,  45,  46,  46,  50,  51,  53,  57,  57,  60,  61,  63,  67,  67,  70,  71,
+             50,  49,  48,  47,  46,  46,  47,  47,  47,  47,  47,  51,  52,  54,  58,  58,  61,  62,  65,  68,  68,  72,  73,  75,
+             54,  52,  51,  50,  49,  49,  49,  50,  49,  49,  49,  53,  54,  56,  60,  60,  64,  65,  67,  71,  71,  75,  76,  78,  82,
+             54,  52,  51,  50,  49,  49,  49,  50,  49,  49,  49,  53,  54,  56,  60,  60,  64,  65,  67,  71,  71,  75,  76,  78,  82,  82,
+             58,  56,  55,  54,  53,  53,  53,  53,  53,  52,  52,  56,  57,  59,  63,  63,  67,  68,  70,  74,  74,  78,  79,  82,  86,  86,  90,
+             59,  57,  56,  55,  54,  54,  54,  54,  54,  53,  53,  57,  58,  60,  64,  64,  68,  69,  71,  75,  75,  79,  80,  83,  87,  87,  91,  92,
+             61,  59,  58,  57,  56,  56,  56,  56,  55,  55,  55,  59,  60,  62,  65,  65,  69,  70,  73,  77,  77,  81,  82,  85,  89,  89,  93,  94,  97,
+             65,  63,  62,  61,  59,  59,  59,  59,  59,  58,  58,  62,  63,  65,  68,  68,  72,  73,  75,  79,  79,  84,  85,  88,  92,  92,  97,  98, 101, 105,
+             65,  63,  62,  61,  59,  59,  59,  59,  59,  58,  58,  62,  63,  65,  68,  68,  72,  73,  75,  79,  79,  84,  85,  88,  92,  92,  97,  98, 101, 105, 105,
+             70,  67,  67,  65,  64,  64,  63,  63,  63,  62,  62,  66,  67,  69,  72,  72,  76,  77,  79,  83,  83,  88,  89,  92,  96,  96, 101, 102, 105, 109, 109, 114,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             30,  31,  31,  31,  32,
+             30,  31,  31,  31,  32,  32,
+             33,  33,  34,  34,  34,  34,  37,
+             33,  34,  34,  35,  35,  35,  38,  39,
+             34,  36,  36,  36,  37,  37,  40,  40,  42,
+             36,  38,  38,  39,  40,  40,  42,  43,  45,  47,
+             36,  38,  38,  39,  40,  40,  42,  43,  45,  47,  47,
+             40,  41,  41,  41,  42,  42,  44,  44,  45,  47,  47,  48,
+             41,  42,  42,  42,  42,  42,  44,  45,  46,  47,  47,  48,  48,
+             44,  44,  44,  44,  44,  44,  45,  46,  46,  47,  47,  49,  49,  50,
+             49,  48,  47,  47,  46,  46,  47,  47,  47,  48,  48,  50,  50,  51,  53,
+             49,  48,  47,  47,  46,  46,  47,  47,  47,  48,  48,  50,  50,  51,  53,  53,
+             48,  47,  47,  46,  45,  45,  46,  46,  46,  47,  47,  49,  50,  51,  53,  53,  54,
+             48,  47,  47,  46,  45,  45,  46,  46,  46,  46,  46,  49,  49,  51,  53,  53,  54,  54,
+             49,  47,  47,  46,  45,  45,  46,  46,  46,  46,  46,  49,  49,  51,  53,  53,  54,  55,  55,
+             49,  47,  47,  46,  45,  45,  45,  45,  45,  45,  45,  48,  49,  51,  53,  53,  55,  55,  57,  58,
+             49,  47,  47,  46,  45,  45,  45,  45,  45,  45,  45,  48,  49,  51,  53,  53,  55,  55,  57,  58,  58,
+             50,  48,  48,  47,  46,  46,  46,  46,  46,  46,  46,  49,  50,  51,  54,  54,  56,  56,  57,  59,  59,  61,
+             50,  49,  48,  47,  46,  46,  46,  46,  46,  46,  46,  49,  50,  51,  54,  54,  56,  56,  58,  60,  60,  61,  61,
+             51,  49,  49,  48,  47,  47,  47,  47,  47,  46,  46,  49,  50,  51,  54,  54,  56,  57,  58,  60,  60,  62,  62,  63,
+             52,  50,  50,  49,  47,  47,  47,  47,  47,  47,  47,  49,  50,  52,  54,  54,  57,  57,  59,  61,  61,  63,  63,  65,  66,
+             52,  50,  50,  49,  47,  47,  47,  47,  47,  47,  47,  49,  50,  52,  54,  54,  57,  57,  59,  61,  61,  63,  63,  65,  66,  66,
+             54,  52,  51,  50,  49,  49,  49,  49,  48,  48,  48,  51,  51,  53,  55,  55,  58,  58,  60,  62,  62,  64,  65,  66,  68,  68,  70,
+             54,  52,  52,  51,  49,  49,  49,  49,  49,  48,  48,  51,  52,  53,  55,  55,  58,  58,  60,  62,  62,  64,  65,  66,  68,  68,  70,  71,
+             55,  53,  53,  52,  50,  50,  50,  50,  49,  49,  49,  51,  52,  54,  56,  56,  58,  59,  60,  63,  63,  65,  66,  67,  69,  69,  71,  72,  73,
+             57,  55,  54,  53,  52,  52,  51,  51,  50,  50,  50,  52,  53,  54,  56,  56,  59,  60,  61,  63,  63,  66,  67,  68,  70,  70,  73,  73,  74,  76,
+             57,  55,  54,  53,  52,  52,  51,  51,  50,  50,  50,  52,  53,  54,  56,  56,  59,  60,  61,  63,  63,  66,  67,  68,  70,  70,  73,  73,  74,  76,  76,
+             59,  57,  56,  55,  54,  54,  53,  53,  52,  51,  51,  54,  55,  56,  58,  58,  60,  61,  63,  65,  65,  67,  68,  70,  72,  72,  74,  75,  76,  78,  78,  80,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  31,  32,
+             31,  31,  32,  32,
+             31,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  32,  33,
+             31,  32,  32,  32,  32,  32,  32,  33,  33,
+             32,  32,  32,  32,  32,  32,  33,  33,  33,  34,
+             32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  35,
+             32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  35,  35,
+             32,  33,  33,  33,  33,  33,  33,  34,  34,  35,  36,  36,  36,
+             34,  34,  34,  34,  33,  33,  34,  35,  35,  35,  37,  37,  38,  39,
+             34,  34,  34,  34,  33,  33,  34,  35,  35,  35,  37,  37,  38,  39,  39,
+             35,  34,  34,  34,  34,  34,  34,  35,  36,  36,  37,  37,  39,  41,  41,  43,
+             36,  35,  35,  35,  34,  34,  35,  36,  36,  37,  38,  38,  40,  42,  42,  45,  48,
+             36,  35,  35,  35,  34,  34,  35,  36,  36,  37,  38,  38,  40,  42,  42,  45,  48,  48,
+             38,  37,  37,  37,  36,  36,  36,  38,  38,  38,  39,  39,  41,  44,  44,  47,  50,  50,  51,
+             39,  39,  38,  38,  37,  37,  38,  39,  39,  39,  40,  40,  42,  45,  45,  47,  50,  50,  52,  54,
+             39,  39,  38,  38,  37,  37,  38,  39,  39,  39,  40,  40,  42,  45,  45,  47,  50,  50,  52,  54,  54,
+             42,  41,  41,  41,  40,  40,  40,  41,  41,  41,  42,  42,  44,  47,  47,  49,  53,  53,  55,  56,  56,  60,
+             44,  43,  42,  42,  41,  41,  41,  42,  42,  42,  42,  42,  44,  47,  47,  50,  54,  54,  56,  58,  58,  61,  63,
+             44,  43,  43,  42,  41,  41,  41,  42,  42,  42,  43,  43,  45,  48,  48,  51,  54,  54,  56,  58,  58,  62,  64,  64,
+             47,  46,  45,  45,  44,  44,  44,  44,  45,  45,  45,  45,  47,  50,  50,  53,  56,  56,  58,  60,  60,  64,  66,  66,  69,
+             48,  47,  46,  46,  45,  44,  45,  45,  45,  45,  46,  46,  47,  51,  51,  53,  57,  57,  59,  61,  61,  65,  67,  67,  70,  71,
+             49,  48,  47,  47,  46,  45,  45,  46,  46,  46,  46,  46,  48,  51,  51,  54,  57,  57,  60,  62,  62,  66,  68,  68,  71,  72,  73,
+             53,  51,  51,  51,  49,  49,  49,  49,  49,  49,  49,  49,  51,  54,  54,  57,  59,  59,  62,  64,  64,  69,  71,  71,  74,  75,  77,  81,
+             54,  52,  51,  51,  50,  49,  49,  50,  50,  49,  49,  49,  51,  54,  54,  57,  60,  60,  63,  65,  65,  69,  71,  72,  75,  76,  77,  81,  82,
+             55,  53,  53,  52,  51,  50,  50,  51,  51,  51,  50,  50,  52,  55,  55,  58,  61,  61,  64,  66,  66,  70,  72,  73,  76,  77,  78,  83,  83,  85,
+             59,  57,  56,  56,  54,  54,  54,  54,  54,  54,  53,  53,  55,  58,  58,  61,  64,  64,  67,  69,  69,  73,  75,  76,  79,  80,  81,  86,  87,  88,  92,
+             59,  57,  56,  56,  54,  54,  54,  54,  54,  54,  53,  53,  55,  58,  58,  61,  64,  64,  67,  69,  69,  73,  75,  76,  79,  80,  81,  86,  87,  88,  92,  92,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             30,  31,  31,  31,  31,
+             30,  31,  31,  31,  31,  32,
+             31,  31,  32,  32,  32,  32,  33,
+             33,  34,  34,  34,  35,  35,  35,  38,
+             33,  34,  34,  34,  35,  35,  36,  38,  39,
+             34,  35,  35,  36,  36,  36,  37,  40,  40,  41,
+             36,  38,  38,  38,  39,  40,  40,  43,  43,  44,  47,
+             36,  38,  38,  38,  39,  40,  40,  43,  43,  44,  47,  47,
+             38,  39,  40,  40,  41,  41,  41,  43,  44,  45,  47,  47,  47,
+             41,  42,  42,  42,  42,  42,  43,  44,  45,  45,  47,  47,  48,  48,
+             41,  42,  42,  42,  42,  42,  43,  44,  45,  45,  47,  47,  48,  48,  48,
+             45,  45,  45,  45,  44,  44,  44,  46,  46,  46,  47,  47,  48,  49,  49,  50,
+             49,  48,  47,  47,  46,  46,  46,  47,  47,  47,  48,  48,  49,  50,  50,  51,  53,
+             49,  48,  47,  47,  46,  46,  46,  47,  47,  47,  48,  48,  49,  50,  50,  51,  53,  53,
+             49,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  48,  50,  50,  51,  53,  53,  53,
+             48,  47,  47,  47,  46,  45,  45,  46,  46,  46,  46,  46,  48,  49,  49,  51,  53,  53,  54,  54,
+             48,  47,  47,  47,  46,  45,  45,  46,  46,  46,  46,  46,  48,  49,  49,  51,  53,  53,  54,  54,  54,
+             49,  47,  47,  47,  45,  45,  45,  45,  45,  45,  45,  45,  47,  49,  49,  51,  53,  53,  54,  55,  55,  57,
+             49,  47,  47,  46,  45,  45,  45,  45,  45,  45,  45,  45,  47,  49,  49,  51,  53,  53,  55,  55,  55,  57,  58,
+             49,  47,  47,  47,  45,  45,  45,  45,  45,  45,  45,  45,  47,  49,  49,  51,  53,  53,  55,  56,  56,  58,  58,  59,
+             50,  49,  48,  48,  46,  46,  46,  46,  46,  46,  46,  46,  47,  50,  50,  52,  54,  54,  55,  56,  56,  58,  59,  59,  61,
+             50,  49,  48,  48,  47,  46,  46,  46,  46,  46,  46,  46,  47,  50,  50,  52,  54,  54,  55,  56,  56,  59,  60,  60,  61,  61,
+             51,  49,  48,  48,  47,  46,  46,  47,  47,  46,  46,  46,  47,  50,  50,  52,  54,  54,  55,  56,  56,  59,  60,  60,  61,  62,  62,
+             52,  50,  49,  49,  48,  47,  47,  47,  47,  47,  46,  46,  48,  50,  50,  52,  54,  54,  56,  57,  57,  60,  61,  61,  63,  63,  64,  66,
+             52,  50,  50,  49,  48,  47,  47,  47,  47,  47,  47,  47,  48,  50,  50,  52,  54,  54,  56,  57,  57,  60,  61,  61,  63,  63,  64,  66,  66,
+             53,  51,  50,  50,  48,  48,  48,  48,  48,  48,  47,  47,  48,  51,  51,  52,  54,  54,  56,  58,  58,  60,  61,  62,  63,  64,  64,  67,  67,  68,
+             54,  53,  52,  52,  50,  49,  49,  49,  49,  49,  48,  48,  49,  52,  52,  53,  55,  55,  57,  58,  58,  61,  62,  63,  64,  65,  66,  68,  68,  69,  71,
+             54,  53,  52,  52,  50,  49,  49,  49,  49,  49,  48,  48,  49,  52,  52,  53,  55,  55,  57,  58,  58,  61,  62,  63,  64,  65,  66,  68,  68,  69,  71,  71,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  31,  32,
+             31,  31,  32,  32,
+             31,  31,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  32,  32,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,
+             32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,
+             32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  35,  35,
+             32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  35,  35,  35,
+             32,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  35,  36,  36,  36,
+             34,  34,  34,  34,  34,  33,  33,  34,  35,  35,  35,  36,  37,  37,  38,  39,
+             34,  34,  34,  34,  34,  33,  33,  34,  35,  35,  35,  36,  37,  37,  38,  39,  39,
+             34,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  36,  37,  37,  38,  40,  40,  41,
+             35,  35,  35,  35,  34,  34,  34,  34,  36,  36,  36,  37,  38,  38,  39,  42,  42,  43,  46,
+             36,  35,  35,  35,  35,  34,  34,  35,  36,  36,  36,  37,  38,  38,  40,  42,  42,  44,  47,  48,
+             36,  35,  35,  35,  35,  34,  34,  35,  36,  36,  36,  37,  38,  38,  40,  42,  42,  44,  47,  48,  48,
+             38,  37,  37,  37,  36,  36,  36,  36,  37,  38,  38,  39,  39,  39,  41,  44,  44,  45,  48,  50,  50,  51,
+             39,  39,  38,  38,  38,  37,  37,  38,  39,  39,  39,  40,  40,  40,  42,  45,  45,  46,  49,  50,  50,  52,  54,
+             39,  39,  38,  38,  38,  37,  37,  38,  39,  39,  39,  40,  40,  40,  42,  45,  45,  46,  49,  50,  50,  52,  54,  54,
+             41,  40,  40,  40,  39,  38,  38,  39,  40,  40,  40,  41,  41,  41,  43,  46,  46,  47,  50,  52,  52,  54,  55,  55,  57,
+             44,  43,  42,  42,  42,  41,  41,  41,  42,  42,  42,  42,  42,  42,  44,  47,  47,  49,  52,  54,  54,  56,  58,  58,  60,  63,
+             44,  43,  42,  42,  42,  41,  41,  41,  42,  42,  42,  42,  42,  42,  44,  47,  47,  49,  52,  54,  54,  56,  58,  58,  60,  63,  63,
+             45,  44,  43,  43,  42,  41,  41,  42,  42,  42,  42,  43,  43,  43,  45,  48,  48,  49,  53,  54,  54,  57,  58,  58,  60,  64,  64,  65,
+             47,  46,  45,  45,  45,  44,  44,  44,  44,  45,  45,  45,  45,  45,  47,  50,  50,  51,  55,  56,  56,  58,  60,  60,  62,  66,  66,  67,  69,
+             48,  47,  46,  46,  45,  44,  44,  45,  45,  45,  45,  45,  46,  46,  47,  51,  51,  52,  55,  57,  57,  59,  61,  61,  63,  67,  67,  68,  70,  71,
+             48,  47,  46,  46,  45,  44,  44,  45,  45,  45,  45,  45,  46,  46,  47,  51,  51,  52,  55,  57,  57,  59,  61,  61,  63,  67,  67,  68,  70,  71,  71,
+             51,  50,  49,  49,  48,  47,  47,  47,  48,  48,  48,  48,  48,  48,  50,  53,  53,  54,  57,  58,  58,  61,  63,  63,  66,  69,  69,  70,  73,  74,  74,  77,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  31,  31,
+             30,  31,  31,  31,  31,  32,
+             30,  31,  31,  31,  31,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  33,
+             33,  33,  34,  34,  34,  34,  34,  35,  37,
+             33,  34,  34,  34,  35,  35,  35,  36,  38,  39,
+             33,  34,  34,  34,  35,  35,  35,  36,  38,  39,  39,
+             35,  36,  37,  37,  37,  38,  38,  38,  41,  41,  41,  44,
+             36,  37,  38,  38,  39,  40,  40,  40,  42,  43,  43,  46,  47,
+             36,  37,  38,  38,  39,  40,  40,  40,  42,  43,  43,  46,  47,  47,
+             38,  39,  40,  40,  40,  41,  41,  41,  43,  44,  44,  46,  47,  47,  47,
+             41,  42,  42,  42,  42,  42,  42,  43,  44,  45,  45,  46,  47,  47,  48,  48,
+             41,  42,  42,  42,  42,  42,  42,  43,  44,  45,  45,  46,  47,  47,  48,  48,  48,
+             43,  43,  43,  43,  43,  43,  43,  43,  45,  45,  45,  46,  47,  47,  48,  49,  49,  49,
+             47,  47,  46,  46,  46,  45,  45,  46,  46,  47,  47,  47,  47,  47,  48,  50,  50,  50,  52,
+             49,  48,  47,  47,  47,  46,  46,  46,  47,  47,  47,  47,  48,  48,  49,  50,  50,  51,  52,  53,
+             49,  48,  47,  47,  47,  46,  46,  46,  47,  47,  47,  47,  48,  48,  49,  50,  50,  51,  52,  53,  53,
+             49,  48,  47,  47,  46,  46,  46,  46,  46,  46,  46,  47,  47,  47,  48,  50,  50,  50,  52,  53,  53,  53,
+             48,  47,  47,  47,  46,  45,  45,  45,  46,  46,  46,  46,  46,  46,  48,  49,  49,  50,  52,  53,  53,  54,  54,
+             48,  47,  47,  47,  46,  45,  45,  45,  46,  46,  46,  46,  46,  46,  48,  49,  49,  50,  52,  53,  53,  54,  54,  54,
+             49,  47,  47,  47,  46,  45,  45,  45,  46,  46,  46,  46,  46,  46,  47,  49,  49,  50,  52,  53,  53,  54,  55,  55,  55,
+             49,  47,  47,  47,  46,  45,  45,  45,  45,  45,  45,  45,  45,  45,  47,  49,  49,  50,  52,  53,  53,  55,  55,  55,  57,  58,
+             49,  47,  47,  47,  46,  45,  45,  45,  45,  45,  45,  45,  45,  45,  47,  49,  49,  50,  52,  53,  53,  55,  55,  55,  57,  58,  58,
+             49,  48,  47,  47,  46,  45,  45,  45,  45,  45,  45,  45,  45,  45,  47,  49,  49,  50,  52,  53,  53,  55,  56,  56,  57,  59,  59,  59,
+             50,  49,  48,  48,  47,  46,  46,  46,  46,  46,  46,  46,  46,  46,  47,  50,  50,  50,  53,  54,  54,  55,  56,  56,  57,  59,  59,  60,  61,
+             50,  49,  48,  48,  47,  46,  46,  46,  46,  46,  46,  46,  46,  46,  47,  50,  50,  50,  53,  54,  54,  55,  56,  56,  58,  60,  60,  60,  61,  61,
+             50,  49,  48,  48,  47,  46,  46,  46,  46,  46,  46,  46,  46,  46,  47,  50,  50,  50,  53,  54,  54,  55,  56,  56,  58,  60,  60,  60,  61,  61,  61,
+             51,  50,  49,  49,  48,  47,  47,  47,  47,  47,  47,  47,  46,  46,  48,  50,  50,  51,  53,  54,  54,  56,  57,  57,  58,  60,  60,  61,  62,  63,  63,  64,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  31,  32,
+             31,  31,  32,  32,
+             31,  31,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  34,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  34,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  34,  35,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  34,  34,  34,  34,  35,  35,  35,
+             33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  35,  36,  36,  36,  37,
+             34,  34,  34,  34,  34,  34,  33,  33,  33,  34,  35,  35,  35,  36,  37,  37,  37,  38,  39,
+             34,  34,  34,  34,  34,  34,  33,  33,  33,  34,  35,  35,  35,  36,  37,  37,  37,  38,  39,  39,
+             34,  34,  34,  34,  34,  34,  33,  33,  33,  34,  35,  35,  35,  36,  37,  37,  37,  38,  39,  39,  39,
+             35,  34,  34,  34,  34,  34,  34,  34,  34,  35,  36,  36,  36,  36,  37,  37,  37,  39,  41,  41,  41,  43,
+             36,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  37,  38,  38,  38,  40,  42,  42,  42,  45,  48,
+             36,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  37,  38,  38,  38,  40,  42,  42,  42,  45,  48,  48,
+             36,  35,  35,  35,  35,  35,  34,  34,  34,  35,  36,  36,  36,  37,  38,  38,  38,  40,  42,  42,  42,  45,  48,  48,  48,
+             37,  37,  37,  37,  37,  36,  36,  36,  36,  37,  38,  38,  38,  38,  39,  39,  39,  41,  44,  44,  44,  46,  49,  49,  49,  51,
+             39,  39,  38,  38,  38,  38,  37,  37,  37,  38,  39,  39,  39,  40,  40,  40,  40,  42,  45,  45,  45,  47,  50,  50,  50,  52,  54,
+             39,  39,  38,  38,  38,  38,  37,  37,  37,  38,  39,  39,  39,  40,  40,  40,  40,  42,  45,  45,  45,  47,  50,  50,  50,  52,  54,  54,
+             39,  39,  38,  38,  38,  38,  37,  37,  37,  38,  39,  39,  39,  40,  40,  40,  40,  42,  45,  45,  45,  47,  50,  50,  50,  52,  54,  54,  54,
+             41,  41,  40,  40,  40,  39,  39,  39,  39,  40,  40,  40,  40,  41,  41,  41,  41,  44,  46,  46,  46,  49,  52,  52,  52,  54,  56,  56,  56,  58,
+             44,  43,  42,  42,  42,  41,  41,  41,  41,  41,  42,  42,  42,  42,  42,  42,  42,  45,  47,  47,  47,  50,  54,  54,  54,  56,  58,  58,  58,  60,  63,
+             44,  43,  42,  42,  42,  41,  41,  41,  41,  41,  42,  42,  42,  42,  42,  42,  42,  45,  47,  47,  47,  50,  54,  54,  54,  56,  58,  58,  58,  60,  63,  63,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,
+             30,  31,  31,  31,  31,  31,  32,
+             30,  31,  31,  31,  31,  31,  32,  32,
+             30,  31,  31,  31,  31,  31,  32,  32,  32,
+             32,  32,  33,  33,  33,  33,  33,  33,  33,  35,
+             33,  34,  34,  34,  34,  35,  35,  35,  35,  37,  39,
+             33,  34,  34,  34,  34,  35,  35,  35,  35,  37,  39,  39,
+             33,  34,  34,  34,  34,  35,  35,  35,  35,  37,  39,  39,  39,
+             35,  35,  36,  36,  36,  37,  37,  37,  37,  39,  41,  41,  41,  43,
+             36,  37,  38,  38,  38,  39,  40,  40,  40,  41,  43,  43,  43,  45,  47,
+             36,  37,  38,  38,  38,  39,  40,  40,  40,  41,  43,  43,  43,  45,  47,  47,
+             36,  37,  38,  38,  38,  39,  40,  40,  40,  41,  43,  43,  43,  45,  47,  47,  47,
+             39,  39,  40,  40,  40,  41,  41,  41,  41,  42,  44,  44,  44,  45,  47,  47,  47,  47,
+             41,  42,  42,  42,  42,  42,  42,  42,  42,  43,  45,  45,  45,  46,  47,  47,  47,  48,  48,
+             41,  42,  42,  42,  42,  42,  42,  42,  42,  43,  45,  45,  45,  46,  47,  47,  47,  48,  48,  48,
+             41,  42,  42,  42,  42,  42,  42,  42,  42,  43,  45,  45,  45,  46,  47,  47,  47,  48,  48,  48,  48,
+             45,  45,  45,  45,  45,  44,  44,  44,  44,  45,  46,  46,  46,  47,  47,  47,  47,  48,  49,  49,  49,  50,
+             49,  48,  47,  47,  47,  47,  46,  46,  46,  47,  47,  47,  47,  47,  48,  48,  48,  49,  50,  50,  50,  51,  53,
+             49,  48,  47,  47,  47,  47,  46,  46,  46,  47,  47,  47,  47,  47,  48,  48,  48,  49,  50,  50,  50,  51,  53,  53,
+             49,  48,  47,  47,  47,  47,  46,  46,  46,  47,  47,  47,  47,  47,  48,  48,  48,  49,  50,  50,  50,  51,  53,  53,  53,
+             49,  48,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  47,  48,  50,  50,  50,  51,  53,  53,  53,  53,
+             48,  48,  47,  47,  47,  46,  45,  45,  45,  46,  46,  46,  46,  46,  46,  46,  46,  48,  49,  49,  49,  51,  53,  53,  53,  53,  54,
+             48,  48,  47,  47,  47,  46,  45,  45,  45,  46,  46,  46,  46,  46,  46,  46,  46,  48,  49,  49,  49,  51,  53,  53,  53,  53,  54,  54,
+             48,  48,  47,  47,  47,  46,  45,  45,  45,  46,  46,  46,  46,  46,  46,  46,  46,  48,  49,  49,  49,  51,  53,  53,  53,  53,  54,  54,  54,
+             49,  48,  47,  47,  47,  46,  45,  45,  45,  45,  46,  46,  46,  46,  46,  46,  46,  47,  49,  49,  49,  51,  53,  53,  53,  54,  55,  55,  55,  56,
+             49,  48,  47,  47,  47,  46,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  47,  49,  49,  49,  51,  53,  53,  53,  54,  55,  55,  55,  57,  58,
+             49,  48,  47,  47,  47,  46,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  47,  49,  49,  49,  51,  53,  53,  53,  54,  55,  55,  55,  57,  58,  58,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  32,
+             31,  31,  31,  32,  32,
+             31,  31,  31,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  34,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  35,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  35,  35,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  34,  34,  34,  34,  35,  35,  35,  35,
+             32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  35,  35,  36,  36,  36,  36,
+             33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  35,  35,  35,  35,  36,  36,  36,  36,  37,  38,
+             34,  34,  34,  34,  34,  34,  34,  33,  33,  33,  33,  34,  35,  35,  35,  35,  36,  36,  37,  37,  37,  38,  39,  39,
+             34,  34,  34,  34,  34,  34,  34,  33,  33,  33,  33,  34,  35,  35,  35,  35,  36,  36,  37,  37,  37,  38,  39,  39,  39,
+             34,  34,  34,  34,  34,  34,  34,  33,  33,  33,  33,  34,  35,  35,  35,  35,  36,  36,  37,  37,  37,  38,  39,  39,  39,  39,
+             34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  36,  36,  36,  36,  37,  37,  37,  37,  38,  40,  41,  41,  41,  42,
+             35,  35,  35,  35,  35,  35,  34,  34,  34,  34,  34,  35,  36,  36,  36,  36,  37,  37,  38,  38,  38,  39,  41,  42,  42,  42,  44,  46,
+             36,  35,  35,  35,  35,  35,  35,  34,  34,  34,  34,  35,  36,  36,  36,  36,  37,  38,  38,  38,  38,  40,  42,  42,  42,  42,  45,  47,  48,
+             36,  35,  35,  35,  35,  35,  35,  34,  34,  34,  34,  35,  36,  36,  36,  36,  37,  38,  38,  38,  38,  40,  42,  42,  42,  42,  45,  47,  48,  48,
+             36,  35,  35,  35,  35,  35,  35,  34,  34,  34,  34,  35,  36,  36,  36,  36,  37,  38,  38,  38,  38,  40,  42,  42,  42,  42,  45,  47,  48,  48,  48,
+             37,  37,  36,  36,  36,  36,  36,  35,  35,  35,  35,  36,  37,  37,  37,  37,  38,  39,  39,  39,  39,  41,  42,  43,  43,  43,  45,  48,  49,  49,  49,  50,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,
+             30,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  31,  31,  31,  31,  31,  31,  32,
+             30,  30,  31,  31,  31,  31,  31,  31,  32,  32,
+             30,  30,  31,  31,  31,  31,  31,  31,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  34,
+             33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  36,  37,
+             33,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  37,  38,  39,
+             33,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  37,  38,  39,  39,
+             33,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  37,  38,  39,  39,  39,
+             34,  35,  36,  36,  36,  36,  36,  37,  37,  37,  37,  38,  40,  40,  40,  40,  42,
+             36,  36,  37,  37,  37,  37,  38,  38,  39,  39,  39,  40,  41,  42,  42,  42,  44,  46,
+             36,  37,  38,  38,  38,  38,  39,  39,  40,  40,  40,  41,  42,  43,  43,  43,  45,  46,  47,
+             36,  37,  38,  38,  38,  38,  39,  39,  40,  40,  40,  41,  42,  43,  43,  43,  45,  46,  47,  47,
+             36,  37,  38,  38,  38,  38,  39,  39,  40,  40,  40,  41,  42,  43,  43,  43,  45,  46,  47,  47,  47,
+             38,  39,  39,  40,  40,  40,  40,  41,  41,  41,  41,  42,  43,  44,  44,  44,  45,  47,  47,  47,  47,  47,
+             40,  41,  41,  41,  41,  41,  41,  42,  42,  42,  42,  43,  44,  44,  44,  44,  45,  47,  47,  47,  47,  48,  48,
+             41,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  43,  44,  45,  45,  45,  46,  47,  47,  47,  47,  48,  48,  48,
+             41,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  43,  44,  45,  45,  45,  46,  47,  47,  47,  47,  48,  48,  48,  48,
+             41,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  43,  44,  45,  45,  45,  46,  47,  47,  47,  47,  48,  48,  48,  48,  48,
+             44,  44,  44,  44,  44,  44,  44,  44,  44,  44,  44,  44,  45,  46,  46,  46,  46,  47,  47,  47,  47,  48,  49,  49,  49,  49,  50,
+             47,  47,  46,  46,  46,  46,  46,  46,  45,  45,  45,  46,  46,  47,  47,  47,  47,  47,  47,  47,  47,  48,  49,  50,  50,  50,  51,  52,
+             49,  48,  48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  48,  48,  48,  49,  50,  50,  50,  50,  51,  52,  53,
+             49,  48,  48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  48,  48,  48,  49,  50,  50,  50,  50,  51,  52,  53,  53,
+             49,  48,  48,  47,  47,  47,  47,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  48,  48,  48,  49,  50,  50,  50,  50,  51,  52,  53,  53,  53,
+             49,  48,  47,  47,  47,  47,  47,  46,  46,  46,  46,  46,  46,  47,  47,  47,  47,  47,  47,  47,  47,  48,  49,  50,  50,  50,  51,  52,  53,  53,  53,  53,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  32,  32,
+             31,  31,  31,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  34,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  34,  34,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  34,  34,  35,  35,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  34,  34,  35,  35,  35,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,
+             32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  35,  35,  35,  36,  36,  36,  36,  36,
+             33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  36,  36,  36,  37,  38,
+             34,  34,  34,  34,  34,  34,  34,  34,  34,  33,  33,  33,  33,  33,  34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  37,  37,  37,  37,  38,  38,  39,
+             34,  34,  34,  34,  34,  34,  34,  34,  34,  33,  33,  33,  33,  33,  34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  37,  37,  37,  37,  38,  38,  39,  39,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  32,
+             30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,
+             30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,
+             30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,
+             32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  35,
+             33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  36,  37,
+             33,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  36,  37,  38,  39,
+             33,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  36,  37,  38,  39,  39,
+             33,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  36,  37,  38,  39,  39,  39,
+             33,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  36,  37,  38,  39,  39,  39,  39,
+             34,  35,  35,  35,  35,  35,  35,  36,  36,  36,  36,  36,  36,  36,  37,  38,  39,  40,  40,  40,  40,  41,
+             35,  36,  36,  36,  37,  37,  37,  37,  37,  37,  38,  38,  38,  38,  38,  39,  41,  41,  41,  41,  41,  42,  44,
+             36,  37,  37,  38,  38,  38,  38,  38,  38,  39,  39,  39,  39,  39,  40,  41,  42,  43,  43,  43,  43,  44,  45,  46,
+             36,  37,  37,  38,  38,  38,  38,  38,  39,  39,  40,  40,  40,  40,  40,  41,  42,  43,  43,  43,  43,  44,  46,  47,  47,
+             36,  37,  37,  38,  38,  38,  38,  38,  39,  39,  40,  40,  40,  40,  40,  41,  42,  43,  43,  43,  43,  44,  46,  47,  47,  47,
+             36,  37,  37,  38,  38,  38,  38,  38,  39,  39,  40,  40,  40,  40,  40,  41,  42,  43,  43,  43,  43,  44,  46,  47,  47,  47,  47,
+             37,  37,  38,  38,  39,  39,  39,  39,  39,  40,  40,  40,  40,  40,  41,  42,  43,  43,  43,  43,  43,  44,  46,  47,  47,  47,  47,  47,
+             38,  39,  39,  40,  40,  40,  40,  40,  40,  40,  41,  41,  41,  41,  41,  42,  43,  44,  44,  44,  44,  45,  46,  47,  47,  47,  47,  47,  47,
+             40,  40,  40,  41,  41,  41,  41,  41,  41,  41,  42,  42,  42,  42,  42,  43,  44,  44,  44,  44,  44,  45,  46,  47,  47,  47,  47,  47,  48,  48,
+             41,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  43,  43,  44,  45,  45,  45,  45,  45,  46,  47,  47,  47,  47,  47,  48,  48,  48,
+             41,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  42,  43,  43,  44,  45,  45,  45,  45,  45,  46,  47,  47,  47,  47,  47,  48,  48,  48,  48,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  32,
+             31,  31,  31,  31,  31,  32,  32,
+             31,  31,  31,  31,  31,  32,  32,  32,
+             31,  31,  31,  31,  31,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,
+             31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+             32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,
+             30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,
+             30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,
+             30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,
+             30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,
+             30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,
+             31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,
+             32,  32,  32,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  35,  36,
+             33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  36,  37,  37,
+             33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  36,  37,  37,  38,  39,
+             33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  36,  37,  37,  38,  39,  39,
+             33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  36,  37,  37,  38,  39,  39,  39,
+             33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  36,  37,  37,  38,  39,  39,  39,  39,
+             33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  36,  37,  37,  38,  39,  39,  39,  39,  39,
+             33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  36,  37,  37,  38,  39,  39,  39,  39,  39,  39,
+             34,  34,  34,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  36,  36,  36,  36,  36,  36,  36,  36,  37,  37,  38,  39,  40,  40,  40,  40,  40,  40,  40,
+        },
+    }, {
+        {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+             31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+        }, {
+             32,
+             31,  31,
+             31,  31,  31,
+             31,  31,  31,  31,
+             31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+             30,  30,  30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,
+             30,  30,  30,  30,  30,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  32,  32,
+        },
+    },
+};
+
+const uint8_t *dav1d_qm_tbl[16][2][N_RECT_TX_SIZES];
+static uint8_t qm_tbl_4x4[15][2][16];
+static uint8_t qm_tbl_4x8[15][2][32];
+static uint8_t qm_tbl_4x16[15][2][64];
+static uint8_t qm_tbl_8x4[15][2][32];
+static uint8_t qm_tbl_8x8[15][2][64];
+static uint8_t qm_tbl_8x16[15][2][128];
+static uint8_t qm_tbl_8x32[15][2][256];
+static uint8_t qm_tbl_16x4[15][2][64];
+static uint8_t qm_tbl_16x8[15][2][128];
+static uint8_t qm_tbl_16x16[15][2][256];
+static uint8_t qm_tbl_16x32[15][2][512];
+static uint8_t qm_tbl_32x8[15][2][256];
+static uint8_t qm_tbl_32x32[15][2][1024];
+
+static void subsample(uint8_t *dst, const uint8_t *const src,
+                      const int h, const int hstep, const int vstep)
+{
+    for (int y = 0; y < h; y += vstep)
+        for (int x = 0; x < 32; x += hstep)
+            *dst++ = src[y * 32 + x];
+}
+
+static void transpose(uint8_t *const dst, const uint8_t *const src,
+                      const int w, const int h)
+{
+    for (int y = 0, y_off = 0; y < h; y++, y_off += w)
+        for (int x = 0, x_off = 0; x < w; x++, x_off += h)
+            dst[x_off + y] = src[y_off + x];
+}
+
+static void untriangle(uint8_t *dst, const uint8_t *src, const int sz) {
+    for (int y = 0; y < sz; y++) {
+        memcpy(dst, src, y + 1);
+        const uint8_t *src_ptr = &src[y];
+        for (int x = y + 1; x < sz; x++) {
+            src_ptr += x;
+            dst[x] = *src_ptr;
+        }
+        dst += sz;
+        src += y + 1;
+    }
+}
+
+COLD void dav1d_init_qm_tables(void) {
+    // This function is guaranteed to be called only once
+
+    for (int i = 0; i < 15; i++)
+        for (int j = 0; j < 2; j++) {
+            // note that the w/h in the assignment is inverted, this is on purpose
+            // because we store coefficients transposed
+            dav1d_qm_tbl[i][j][RTX_4X8  ] = qm_tbl_8x4[i][j];
+            dav1d_qm_tbl[i][j][RTX_8X4  ] = qm_tbl_4x8[i][j];
+            dav1d_qm_tbl[i][j][RTX_4X16 ] = qm_tbl_16x4[i][j];
+            dav1d_qm_tbl[i][j][RTX_16X4 ] = qm_tbl_4x16[i][j];
+            dav1d_qm_tbl[i][j][RTX_8X16 ] = qm_tbl_16x8[i][j];
+            dav1d_qm_tbl[i][j][RTX_16X8 ] = qm_tbl_8x16[i][j];
+            dav1d_qm_tbl[i][j][RTX_8X32 ] = qm_tbl_32x8[i][j];
+            dav1d_qm_tbl[i][j][RTX_32X8 ] = qm_tbl_8x32[i][j];
+            dav1d_qm_tbl[i][j][RTX_16X32] = qm_tbl_32x16[i][j];
+            dav1d_qm_tbl[i][j][RTX_32X16] = qm_tbl_16x32[i][j];
+
+            dav1d_qm_tbl[i][j][ TX_4X4  ] = qm_tbl_4x4[i][j];
+            dav1d_qm_tbl[i][j][ TX_8X8  ] = qm_tbl_8x8[i][j];
+            dav1d_qm_tbl[i][j][ TX_16X16] = qm_tbl_16x16[i][j];
+            dav1d_qm_tbl[i][j][ TX_32X32] = qm_tbl_32x32[i][j];
+
+            untriangle(qm_tbl_32x32[i][j], qm_tbl_32x32_t[i][j], 32);
+            subsample(qm_tbl_4x4[i][j],   &qm_tbl_32x32[i][j][32*3+3], 32, 8, 8);
+            subsample(qm_tbl_8x4[i][j],   &qm_tbl_32x16[i][j][32*1+1], 16, 4, 4);
+            subsample(qm_tbl_8x8[i][j],   &qm_tbl_32x32[i][j][32*1+1], 32, 4, 4);
+            subsample(qm_tbl_16x4[i][j],  &qm_tbl_32x16[i][j][32*1+0], 16, 2, 4);
+            subsample(qm_tbl_16x8[i][j],  &qm_tbl_32x16[i][j][32*0+0], 16, 2, 2);
+            subsample(qm_tbl_16x16[i][j], &qm_tbl_32x32[i][j][32*0+0], 32, 2, 2);
+            subsample(qm_tbl_32x8[i][j],  &qm_tbl_32x16[i][j][32*0+0], 16, 1, 2);
+            transpose(qm_tbl_4x8[i][j], qm_tbl_8x4[i][j], 8, 4);
+            transpose(qm_tbl_4x16[i][j], qm_tbl_16x4[i][j], 16, 4);
+            transpose(qm_tbl_8x16[i][j], qm_tbl_16x8[i][j], 16, 8);
+            transpose(qm_tbl_8x32[i][j], qm_tbl_32x8[i][j], 32, 8);
+            transpose(qm_tbl_16x32[i][j], qm_tbl_32x16[i][j], 32, 16);
+
+            dav1d_qm_tbl[i][j][ TX_64X64] = dav1d_qm_tbl[i][j][ TX_32X32];
+            dav1d_qm_tbl[i][j][RTX_64X32] = dav1d_qm_tbl[i][j][ TX_32X32];
+            dav1d_qm_tbl[i][j][RTX_64X16] = dav1d_qm_tbl[i][j][RTX_32X16];
+            dav1d_qm_tbl[i][j][RTX_32X64] = dav1d_qm_tbl[i][j][ TX_32X32];
+            dav1d_qm_tbl[i][j][RTX_16X64] = dav1d_qm_tbl[i][j][RTX_16X32];
+        }
+
+    // dav1d_qm_tbl[15][*][*] == NULL
+}
diff --git a/media/libdav1d/src/src/qm.h b/media/libdav1d/src/src/qm.h
new file mode 100644
index 0000000000..8191c8afa7
--- /dev/null
+++ b/media/libdav1d/src/src/qm.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_QM_H
+#define DAV1D_SRC_QM_H
+
+#include "src/levels.h"
+
+EXTERN const uint8_t *dav1d_qm_tbl[16][2][N_RECT_TX_SIZES];
+
+void dav1d_init_qm_tables(void);
+
+#endif /* DAV1D_SRC_QM_H */
diff --git a/media/libdav1d/src/src/recon.h b/media/libdav1d/src/src/recon.h
new file mode 100644
index 0000000000..721924916f
--- /dev/null
+++ b/media/libdav1d/src/src/recon.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_RECON_H
+#define DAV1D_SRC_RECON_H
+
+#include "src/internal.h"
+#include "src/levels.h"
+
+#define DEBUG_BLOCK_INFO 0 && \
+        f->frame_hdr->frame_offset == 2 && t->by >= 0 && t->by < 4 && \
+        t->bx >= 8 && t->bx < 12
+#define DEBUG_B_PIXELS 0
+
+#define decl_recon_b_intra_fn(name) \
+void (name)(Dav1dTaskContext *t, enum BlockSize bs, \
+            enum EdgeFlags intra_edge_flags, const Av1Block *b)
+typedef decl_recon_b_intra_fn(*recon_b_intra_fn);
+
+#define decl_recon_b_inter_fn(name) \
+int (name)(Dav1dTaskContext *t, enum BlockSize bs, const Av1Block *b)
+typedef decl_recon_b_inter_fn(*recon_b_inter_fn);
+
+#define decl_filter_sbrow_fn(name) \
+void (name)(Dav1dFrameContext *f, int sby)
+typedef decl_filter_sbrow_fn(*filter_sbrow_fn);
+
+#define decl_backup_ipred_edge_fn(name) \
+void (name)(Dav1dTaskContext *t)
+typedef decl_backup_ipred_edge_fn(*backup_ipred_edge_fn);
+
+#define decl_read_coef_blocks_fn(name) \
+void (name)(Dav1dTaskContext *t, enum BlockSize bs, const Av1Block *b)
+typedef decl_read_coef_blocks_fn(*read_coef_blocks_fn);
+
+#define decl_copy_pal_block_fn(name) \
+void (name)(Dav1dTaskContext *t, int bx4, int by4, int bw4, int bh4)
+typedef decl_copy_pal_block_fn(*copy_pal_block_fn);
+
+#define decl_read_pal_plane_fn(name) \
+void (name)(Dav1dTaskContext *t, Av1Block *b, int pl, int sz_ctx, int bx4, int by4)
+typedef decl_read_pal_plane_fn(*read_pal_plane_fn);
+
+#define decl_read_pal_uv_fn(name) \
+void (name)(Dav1dTaskContext *t, Av1Block *b, int sz_ctx, int bx4, int by4)
+typedef decl_read_pal_uv_fn(*read_pal_uv_fn);
+
+decl_recon_b_intra_fn(dav1d_recon_b_intra_8bpc);
+decl_recon_b_intra_fn(dav1d_recon_b_intra_16bpc);
+
+decl_recon_b_inter_fn(dav1d_recon_b_inter_8bpc);
+decl_recon_b_inter_fn(dav1d_recon_b_inter_16bpc);
+
+decl_filter_sbrow_fn(dav1d_filter_sbrow_8bpc);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_16bpc);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_deblock_cols_8bpc);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_deblock_cols_16bpc);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_deblock_rows_8bpc);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_deblock_rows_16bpc);
+void dav1d_filter_sbrow_cdef_8bpc(Dav1dTaskContext *tc, int sby);
+void dav1d_filter_sbrow_cdef_16bpc(Dav1dTaskContext *tc, int sby);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_resize_8bpc);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_resize_16bpc);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_lr_8bpc);
+decl_filter_sbrow_fn(dav1d_filter_sbrow_lr_16bpc);
+
+decl_backup_ipred_edge_fn(dav1d_backup_ipred_edge_8bpc);
+decl_backup_ipred_edge_fn(dav1d_backup_ipred_edge_16bpc);
+
+decl_read_coef_blocks_fn(dav1d_read_coef_blocks_8bpc);
+decl_read_coef_blocks_fn(dav1d_read_coef_blocks_16bpc);
+
+decl_copy_pal_block_fn(dav1d_copy_pal_block_y_8bpc);
+decl_copy_pal_block_fn(dav1d_copy_pal_block_y_16bpc);
+decl_copy_pal_block_fn(dav1d_copy_pal_block_uv_8bpc);
+decl_copy_pal_block_fn(dav1d_copy_pal_block_uv_16bpc);
+decl_read_pal_plane_fn(dav1d_read_pal_plane_8bpc);
+decl_read_pal_plane_fn(dav1d_read_pal_plane_16bpc);
+decl_read_pal_uv_fn(dav1d_read_pal_uv_8bpc);
+decl_read_pal_uv_fn(dav1d_read_pal_uv_16bpc);
+
+#endif /* DAV1D_SRC_RECON_H */
diff --git a/media/libdav1d/src/src/recon_tmpl.c b/media/libdav1d/src/src/recon_tmpl.c
new file mode 100644
index 0000000000..dbe24359cf
--- /dev/null
+++ b/media/libdav1d/src/src/recon_tmpl.c
@@ -0,0 +1,2310 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "common/attributes.h"
+#include "common/bitdepth.h"
+#include "common/dump.h"
+#include "common/frame.h"
+#include "common/intops.h"
+
+#include "src/cdef_apply.h"
+#include "src/ctx.h"
+#include "src/ipred_prepare.h"
+#include "src/lf_apply.h"
+#include "src/lr_apply.h"
+#include "src/recon.h"
+#include "src/scan.h"
+#include "src/tables.h"
+#include "src/wedge.h"
+
+static inline unsigned read_golomb(MsacContext *const msac) {
+    int len = 0;
+    unsigned val = 1;
+
+    while (!dav1d_msac_decode_bool_equi(msac) && len < 32) len++;
+    while (len--) val = (val << 1) + dav1d_msac_decode_bool_equi(msac);
+
+    return val - 1;
+}
+
+static inline unsigned get_skip_ctx(const TxfmInfo *const t_dim,
+                                    const enum BlockSize bs,
+                                    const uint8_t *const a,
+                                    const uint8_t *const l,
+                                    const int chroma,
+                                    const enum Dav1dPixelLayout layout)
+{
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+
+    if (chroma) {
+        const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int not_one_blk = b_dim[2] - (!!b_dim[2] && ss_hor) > t_dim->lw ||
+                                b_dim[3] - (!!b_dim[3] && ss_ver) > t_dim->lh;
+        unsigned ca, cl;
+
+#define MERGE_CTX(dir, type, no_val) \
+        c##dir = *(const type *) dir != no_val; \
+        break
+
+        switch (t_dim->lw) {
+        /* For some reason the MSVC CRT _wassert() function is not flagged as
+         * __declspec(noreturn), so when using those headers the compiler will
+         * expect execution to continue after an assertion has been triggered
+         * and will therefore complain about the use of uninitialized variables
+         * when compiled in debug mode if we put the default case at the end. */
+        default: assert(0); /* fall-through */
+        case TX_4X4:   MERGE_CTX(a, uint8_t,  0x40);
+        case TX_8X8:   MERGE_CTX(a, uint16_t, 0x4040);
+        case TX_16X16: MERGE_CTX(a, uint32_t, 0x40404040U);
+        case TX_32X32: MERGE_CTX(a, uint64_t, 0x4040404040404040ULL);
+        }
+        switch (t_dim->lh) {
+        default: assert(0); /* fall-through */
+        case TX_4X4:   MERGE_CTX(l, uint8_t,  0x40);
+        case TX_8X8:   MERGE_CTX(l, uint16_t, 0x4040);
+        case TX_16X16: MERGE_CTX(l, uint32_t, 0x40404040U);
+        case TX_32X32: MERGE_CTX(l, uint64_t, 0x4040404040404040ULL);
+        }
+#undef MERGE_CTX
+
+        return 7 + not_one_blk * 3 + ca + cl;
+    } else if (b_dim[2] == t_dim->lw && b_dim[3] == t_dim->lh) {
+        return 0;
+    } else {
+        unsigned la, ll;
+
+#define MERGE_CTX(dir, type, tx) \
+        if (tx == TX_64X64) { \
+            uint64_t tmp = *(const uint64_t *) dir; \
+            tmp |= *(const uint64_t *) &dir[8]; \
+            l##dir = (unsigned) (tmp >> 32) | (unsigned) tmp; \
+        } else \
+            l##dir = *(const type *) dir; \
+        if (tx == TX_32X32) l##dir |= *(const type *) &dir[sizeof(type)]; \
+        if (tx >= TX_16X16) l##dir |= l##dir >> 16; \
+        if (tx >= TX_8X8)   l##dir |= l##dir >> 8; \
+        break
+
+        switch (t_dim->lw) {
+        default: assert(0); /* fall-through */
+        case TX_4X4:   MERGE_CTX(a, uint8_t,  TX_4X4);
+        case TX_8X8:   MERGE_CTX(a, uint16_t, TX_8X8);
+        case TX_16X16: MERGE_CTX(a, uint32_t, TX_16X16);
+        case TX_32X32: MERGE_CTX(a, uint32_t, TX_32X32);
+        case TX_64X64: MERGE_CTX(a, uint32_t, TX_64X64);
+        }
+        switch (t_dim->lh) {
+        default: assert(0); /* fall-through */
+        case TX_4X4:   MERGE_CTX(l, uint8_t,  TX_4X4);
+        case TX_8X8:   MERGE_CTX(l, uint16_t, TX_8X8);
+        case TX_16X16: MERGE_CTX(l, uint32_t, TX_16X16);
+        case TX_32X32: MERGE_CTX(l, uint32_t, TX_32X32);
+        case TX_64X64: MERGE_CTX(l, uint32_t, TX_64X64);
+        }
+#undef MERGE_CTX
+
+        return dav1d_skip_ctx[umin(la & 0x3F, 4)][umin(ll & 0x3F, 4)];
+    }
+}
+
+static inline unsigned get_dc_sign_ctx(const int /*enum RectTxfmSize*/ tx,
+                                       const uint8_t *const a,
+                                       const uint8_t *const l)
+{
+    uint64_t mask = 0xC0C0C0C0C0C0C0C0ULL, mul = 0x0101010101010101ULL;
+    int s;
+
+#if ARCH_X86_64 && defined(__GNUC__)
+    /* Coerce compilers into producing better code. For some reason
+     * every x86-64 compiler is awful at handling 64-bit constants. */
+    __asm__("" : "+r"(mask), "+r"(mul));
+#endif
+
+    switch(tx) {
+    default: assert(0); /* fall-through */
+    case TX_4X4: {
+        int t = *(const uint8_t *) a >> 6;
+        t    += *(const uint8_t *) l >> 6;
+        s = t - 1 - 1;
+        break;
+    }
+    case TX_8X8: {
+        uint32_t t = *(const uint16_t *) a & (uint32_t) mask;
+        t         += *(const uint16_t *) l & (uint32_t) mask;
+        t *= 0x04040404U;
+        s = (int) (t >> 24) - 2 - 2;
+        break;
+    }
+    case TX_16X16: {
+        uint32_t t = (*(const uint32_t *) a & (uint32_t) mask) >> 6;
+        t         += (*(const uint32_t *) l & (uint32_t) mask) >> 6;
+        t *= (uint32_t) mul;
+        s = (int) (t >> 24) - 4 - 4;
+        break;
+    }
+    case TX_32X32: {
+        uint64_t t = (*(const uint64_t *) a & mask) >> 6;
+        t         += (*(const uint64_t *) l & mask) >> 6;
+        t *= mul;
+        s = (int) (t >> 56) - 8 - 8;
+        break;
+    }
+    case TX_64X64: {
+        uint64_t t = (*(const uint64_t *) &a[0] & mask) >> 6;
+        t         += (*(const uint64_t *) &a[8] & mask) >> 6;
+        t         += (*(const uint64_t *) &l[0] & mask) >> 6;
+        t         += (*(const uint64_t *) &l[8] & mask) >> 6;
+        t *= mul;
+        s = (int) (t >> 56) - 16 - 16;
+        break;
+    }
+    case RTX_4X8: {
+        uint32_t t = *(const uint8_t  *) a & (uint32_t) mask;
+        t         += *(const uint16_t *) l & (uint32_t) mask;
+        t *= 0x04040404U;
+        s = (int) (t >> 24) - 1 - 2;
+        break;
+    }
+    case RTX_8X4: {
+        uint32_t t = *(const uint16_t *) a & (uint32_t) mask;
+        t         += *(const uint8_t  *) l & (uint32_t) mask;
+        t *= 0x04040404U;
+        s = (int) (t >> 24) - 2 - 1;
+        break;
+    }
+    case RTX_8X16: {
+        uint32_t t = *(const uint16_t *) a & (uint32_t) mask;
+        t         += *(const uint32_t *) l & (uint32_t) mask;
+        t = (t >> 6) * (uint32_t) mul;
+        s = (int) (t >> 24) - 2 - 4;
+        break;
+    }
+    case RTX_16X8: {
+        uint32_t t = *(const uint32_t *) a & (uint32_t) mask;
+        t         += *(const uint16_t *) l & (uint32_t) mask;
+        t = (t >> 6) * (uint32_t) mul;
+        s = (int) (t >> 24) - 4 - 2;
+        break;
+    }
+    case RTX_16X32: {
+        uint64_t t = *(const uint32_t *) a & (uint32_t) mask;
+        t         += *(const uint64_t *) l & mask;
+        t = (t >> 6) * mul;
+        s = (int) (t >> 56) - 4 - 8;
+        break;
+    }
+    case RTX_32X16: {
+        uint64_t t = *(const uint64_t *) a & mask;
+        t         += *(const uint32_t *) l & (uint32_t) mask;
+        t = (t >> 6) * mul;
+        s = (int) (t >> 56) - 8 - 4;
+        break;
+    }
+    case RTX_32X64: {
+        uint64_t t = (*(const uint64_t *) &a[0] & mask) >> 6;
+        t         += (*(const uint64_t *) &l[0] & mask) >> 6;
+        t         += (*(const uint64_t *) &l[8] & mask) >> 6;
+        t *= mul;
+        s = (int) (t >> 56) - 8 - 16;
+        break;
+    }
+    case RTX_64X32: {
+        uint64_t t = (*(const uint64_t *) &a[0] & mask) >> 6;
+        t         += (*(const uint64_t *) &a[8] & mask) >> 6;
+        t         += (*(const uint64_t *) &l[0] & mask) >> 6;
+        t *= mul;
+        s = (int) (t >> 56) - 16 - 8;
+        break;
+    }
+    case RTX_4X16: {
+        uint32_t t = *(const uint8_t  *) a & (uint32_t) mask;
+        t         += *(const uint32_t *) l & (uint32_t) mask;
+        t = (t >> 6) * (uint32_t) mul;
+        s = (int) (t >> 24) - 1 - 4;
+        break;
+    }
+    case RTX_16X4: {
+        uint32_t t = *(const uint32_t *) a & (uint32_t) mask;
+        t         += *(const uint8_t  *) l & (uint32_t) mask;
+        t = (t >> 6) * (uint32_t) mul;
+        s = (int) (t >> 24) - 4 - 1;
+        break;
+    }
+    case RTX_8X32: {
+        uint64_t t = *(const uint16_t *) a & (uint32_t) mask;
+        t         += *(const uint64_t *) l & mask;
+        t = (t >> 6) * mul;
+        s = (int) (t >> 56) - 2 - 8;
+        break;
+    }
+    case RTX_32X8: {
+        uint64_t t = *(const uint64_t *) a & mask;
+        t         += *(const uint16_t *) l & (uint32_t) mask;
+        t = (t >> 6) * mul;
+        s = (int) (t >> 56) - 8 - 2;
+        break;
+    }
+    case RTX_16X64: {
+        uint64_t t = *(const uint32_t *) a & (uint32_t) mask;
+        t         += *(const uint64_t *) &l[0] & mask;
+        t = (t >> 6) + ((*(const uint64_t *) &l[8] & mask) >> 6);
+        t *= mul;
+        s = (int) (t >> 56) - 4 - 16;
+        break;
+    }
+    case RTX_64X16: {
+        uint64_t t = *(const uint64_t *) &a[0] & mask;
+        t         += *(const uint32_t *) l & (uint32_t) mask;
+        t = (t >> 6) + ((*(const uint64_t *) &a[8] & mask) >> 6);
+        t *= mul;
+        s = (int) (t >> 56) - 16 - 4;
+        break;
+    }
+    }
+
+    return (s != 0) + (s > 0);
+}
+
+static inline unsigned get_lo_ctx(const uint8_t *const levels,
+                                  const enum TxClass tx_class,
+                                  unsigned *const hi_mag,
+                                  const uint8_t (*const ctx_offsets)[5],
+                                  const unsigned x, const unsigned y,
+                                  const ptrdiff_t stride)
+{
+    unsigned mag = levels[0 * stride + 1] + levels[1 * stride + 0];
+    unsigned offset;
+    if (tx_class == TX_CLASS_2D) {
+        mag += levels[1 * stride + 1];
+        *hi_mag = mag;
+        mag += levels[0 * stride + 2] + levels[2 * stride + 0];
+        offset = ctx_offsets[umin(y, 4)][umin(x, 4)];
+    } else {
+        mag += levels[0 * stride + 2];
+        *hi_mag = mag;
+        mag += levels[0 * stride + 3] + levels[0 * stride + 4];
+        offset = 26 + (y > 1 ? 10 : y * 5);
+    }
+    return offset + (mag > 512 ? 4 : (mag + 64) >> 7);
+}
+
+static int decode_coefs(Dav1dTaskContext *const t,
+                        uint8_t *const a, uint8_t *const l,
+                        const enum RectTxfmSize tx, const enum BlockSize bs,
+                        const Av1Block *const b, const int intra,
+                        const int plane, coef *cf,
+                        enum TxfmType *const txtp, uint8_t *res_ctx)
+{
+    Dav1dTileState *const ts = t->ts;
+    const int chroma = !!plane;
+    const Dav1dFrameContext *const f = t->f;
+    const int lossless = f->frame_hdr->segmentation.lossless[b->seg_id];
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx];
+    const int dbg = DEBUG_BLOCK_INFO && plane && 0;
+
+    if (dbg)
+        printf("Start: r=%d\n", ts->msac.rng);
+
+    // does this block have any non-zero coefficients
+    const int sctx = get_skip_ctx(t_dim, bs, a, l, chroma, f->cur.p.layout);
+    const int all_skip = dav1d_msac_decode_bool_adapt(&ts->msac,
+                             ts->cdf.coef.skip[t_dim->ctx][sctx]);
+    if (dbg)
+        printf("Post-non-zero[%d][%d][%d]: r=%d\n",
+               t_dim->ctx, sctx, all_skip, ts->msac.rng);
+    if (all_skip) {
+        *res_ctx = 0x40;
+        *txtp = lossless * WHT_WHT; /* lossless ? WHT_WHT : DCT_DCT */
+        return -1;
+    }
+
+    // transform type (chroma: derived, luma: explicitly coded)
+    if (lossless) {
+        assert(t_dim->max == TX_4X4);
+        *txtp = WHT_WHT;
+    } else if (t_dim->max + intra >= TX_64X64) {
+        *txtp = DCT_DCT;
+    } else if (chroma) {
+        // inferred from either the luma txtp (inter) or a LUT (intra)
+        *txtp = intra ? dav1d_txtp_from_uvmode[b->uv_mode] :
+                        get_uv_inter_txtp(t_dim, *txtp);
+    } else if (!f->frame_hdr->segmentation.qidx[b->seg_id]) {
+        // In libaom, lossless is checked by a literal qidx == 0, but not all
+        // such blocks are actually lossless. The remainder gets an implicit
+        // transform type (for luma)
+        *txtp = DCT_DCT;
+    } else {
+        unsigned idx;
+        if (intra) {
+            const enum IntraPredMode y_mode_nofilt = b->y_mode == FILTER_PRED ?
+                dav1d_filter_mode_to_y_mode[b->y_angle] : b->y_mode;
+            if (f->frame_hdr->reduced_txtp_set || t_dim->min == TX_16X16) {
+                idx = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                          ts->cdf.m.txtp_intra2[t_dim->min][y_mode_nofilt], 4);
+                *txtp = dav1d_tx_types_per_set[idx + 0];
+            } else {
+                idx = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                          ts->cdf.m.txtp_intra1[t_dim->min][y_mode_nofilt], 6);
+                *txtp = dav1d_tx_types_per_set[idx + 5];
+            }
+            if (dbg)
+                printf("Post-txtp-intra[%d->%d][%d][%d->%d]: r=%d\n",
+                       tx, t_dim->min, y_mode_nofilt, idx, *txtp, ts->msac.rng);
+        } else {
+            if (f->frame_hdr->reduced_txtp_set || t_dim->max == TX_32X32) {
+                idx = dav1d_msac_decode_bool_adapt(&ts->msac,
+                          ts->cdf.m.txtp_inter3[t_dim->min]);
+                *txtp = (idx - 1) & IDTX; /* idx ? DCT_DCT : IDTX */
+            } else if (t_dim->min == TX_16X16) {
+                idx = dav1d_msac_decode_symbol_adapt16(&ts->msac,
+                          ts->cdf.m.txtp_inter2, 11);
+                *txtp = dav1d_tx_types_per_set[idx + 12];
+            } else {
+                idx = dav1d_msac_decode_symbol_adapt16(&ts->msac,
+                          ts->cdf.m.txtp_inter1[t_dim->min], 15);
+                *txtp = dav1d_tx_types_per_set[idx + 24];
+            }
+            if (dbg)
+                printf("Post-txtp-inter[%d->%d][%d->%d]: r=%d\n",
+                       tx, t_dim->min, idx, *txtp, ts->msac.rng);
+        }
+    }
+
+    // find end-of-block (eob)
+    int eob;
+    const int slw = imin(t_dim->lw, TX_32X32), slh = imin(t_dim->lh, TX_32X32);
+    const int tx2dszctx = slw + slh;
+    const enum TxClass tx_class = dav1d_tx_type_class[*txtp];
+    const int is_1d = tx_class != TX_CLASS_2D;
+    switch (tx2dszctx) {
+#define case_sz(sz, bin, ns, is_1d) \
+    case sz: { \
+        uint16_t *const eob_bin_cdf = ts->cdf.coef.eob_bin_##bin[chroma]is_1d; \
+        eob = dav1d_msac_decode_symbol_adapt##ns(&ts->msac, eob_bin_cdf, 4 + sz); \
+        break; \
+    }
+    case_sz(0,   16,  8, [is_1d]);
+    case_sz(1,   32,  8, [is_1d]);
+    case_sz(2,   64,  8, [is_1d]);
+    case_sz(3,  128,  8, [is_1d]);
+    case_sz(4,  256, 16, [is_1d]);
+    case_sz(5,  512, 16,        );
+    case_sz(6, 1024, 16,        );
+#undef case_sz
+    }
+    if (dbg)
+        printf("Post-eob_bin_%d[%d][%d][%d]: r=%d\n",
+               16 << tx2dszctx, chroma, is_1d, eob, ts->msac.rng);
+    if (eob > 1) {
+        const int eob_bin = eob - 2;
+        uint16_t *const eob_hi_bit_cdf =
+            ts->cdf.coef.eob_hi_bit[t_dim->ctx][chroma][eob_bin];
+        const int eob_hi_bit = dav1d_msac_decode_bool_adapt(&ts->msac, eob_hi_bit_cdf);
+        if (dbg)
+            printf("Post-eob_hi_bit[%d][%d][%d][%d]: r=%d\n",
+                   t_dim->ctx, chroma, eob_bin, eob_hi_bit, ts->msac.rng);
+        eob = ((eob_hi_bit | 2) << eob_bin) | dav1d_msac_decode_bools(&ts->msac, eob_bin);
+        if (dbg)
+            printf("Post-eob[%d]: r=%d\n", eob, ts->msac.rng);
+    }
+    assert(eob >= 0);
+
+    // base tokens
+    uint16_t (*const eob_cdf)[4] = ts->cdf.coef.eob_base_tok[t_dim->ctx][chroma];
+    uint16_t (*const hi_cdf)[4] = ts->cdf.coef.br_tok[imin(t_dim->ctx, 3)][chroma];
+    unsigned rc, dc_tok;
+
+    if (eob) {
+        uint16_t (*const lo_cdf)[4] = ts->cdf.coef.base_tok[t_dim->ctx][chroma];
+        uint8_t *const levels = t->scratch.levels; // bits 0-5: tok, 6-7: lo_tok
+
+        /* eob */
+        unsigned ctx = 1 + (eob > 2 << tx2dszctx) + (eob > 4 << tx2dszctx);
+        int eob_tok = dav1d_msac_decode_symbol_adapt4(&ts->msac, eob_cdf[ctx], 2);
+        int tok = eob_tok + 1;
+        int level_tok = tok * 0x41;
+        unsigned mag;
+
+#define DECODE_COEFS_CLASS(tx_class) \
+        unsigned x, y; \
+        uint8_t *level; \
+        if (tx_class == TX_CLASS_2D) \
+            rc = scan[eob], x = rc >> shift, y = rc & mask; \
+        else if (tx_class == TX_CLASS_H) \
+            /* Transposing reduces the stride and padding requirements */ \
+            x = eob & mask, y = eob >> shift, rc = eob; \
+        else /* tx_class == TX_CLASS_V */ \
+            x = eob & mask, y = eob >> shift, rc = (x << shift2) | y; \
+        if (dbg) \
+            printf("Post-lo_tok[%d][%d][%d][%d=%d=%d]: r=%d\n", \
+                   t_dim->ctx, chroma, ctx, eob, rc, tok, ts->msac.rng); \
+        if (eob_tok == 2) { \
+            ctx = (tx_class == TX_CLASS_2D ? (x | y) > 1 : y != 0) ? 14 : 7; \
+            tok = dav1d_msac_decode_hi_tok(&ts->msac, hi_cdf[ctx]); \
+            level_tok = tok + (3 << 6); \
+            if (dbg) \
+                printf("Post-hi_tok[%d][%d][%d][%d=%d=%d]: r=%d\n", \
+                       imin(t_dim->ctx, 3), chroma, ctx, eob, rc, tok, \
+                       ts->msac.rng); \
+        } \
+        cf[rc] = tok << 11; \
+        if (tx_class == TX_CLASS_2D) \
+            level = levels + rc; \
+        else \
+            level = levels + x * stride + y; \
+        *level = (uint8_t) level_tok; \
+        for (int i = eob - 1; i > 0; i--) { /* ac */ \
+            unsigned rc_i; \
+            if (tx_class == TX_CLASS_2D) \
+                rc_i = scan[i], x = rc_i >> shift, y = rc_i & mask; \
+            else if (tx_class == TX_CLASS_H) \
+                x = i & mask, y = i >> shift, rc_i = i; \
+            else /* tx_class == TX_CLASS_V */ \
+                x = i & mask, y = i >> shift, rc_i = (x << shift2) | y; \
+            assert(x < 32 && y < 32); \
+            if (tx_class == TX_CLASS_2D) \
+                level = levels + rc_i; \
+            else \
+                level = levels + x * stride + y; \
+            ctx = get_lo_ctx(level, tx_class, &mag, lo_ctx_offsets, x, y, stride); \
+            if (tx_class == TX_CLASS_2D) \
+                y |= x; \
+            tok = dav1d_msac_decode_symbol_adapt4(&ts->msac, lo_cdf[ctx], 3); \
+            if (dbg) \
+                printf("Post-lo_tok[%d][%d][%d][%d=%d=%d]: r=%d\n", \
+                       t_dim->ctx, chroma, ctx, i, rc_i, tok, ts->msac.rng); \
+            if (tok == 3) { \
+                mag &= 63; \
+                ctx = (y > (tx_class == TX_CLASS_2D) ? 14 : 7) + \
+                      (mag > 12 ? 6 : (mag + 1) >> 1); \
+                tok = dav1d_msac_decode_hi_tok(&ts->msac, hi_cdf[ctx]); \
+                if (dbg) \
+                    printf("Post-hi_tok[%d][%d][%d][%d=%d=%d]: r=%d\n", \
+                           imin(t_dim->ctx, 3), chroma, ctx, i, rc_i, tok, \
+                           ts->msac.rng); \
+                *level = (uint8_t) (tok + (3 << 6)); \
+                cf[rc_i] = (tok << 11) | rc; \
+                rc = rc_i; \
+            } else { \
+                /* 0x1 for tok, 0x7ff as bitmask for rc, 0x41 for level_tok */ \
+                tok *= 0x17ff41; \
+                *level = (uint8_t) tok; \
+                /* tok ? (tok << 11) | rc : 0 */ \
+                tok = (tok >> 9) & (rc + ~0x7ffu); \
+                if (tok) rc = rc_i; \
+                cf[rc_i] = tok; \
+            } \
+        } \
+        /* dc */ \
+        ctx = (tx_class == TX_CLASS_2D) ? 0 : \
+            get_lo_ctx(levels, tx_class, &mag, lo_ctx_offsets, 0, 0, stride); \
+        dc_tok = dav1d_msac_decode_symbol_adapt4(&ts->msac, lo_cdf[ctx], 3); \
+        if (dbg) \
+            printf("Post-dc_lo_tok[%d][%d][%d][%d]: r=%d\n", \
+                   t_dim->ctx, chroma, ctx, dc_tok, ts->msac.rng); \
+        if (dc_tok == 3) { \
+            if (tx_class == TX_CLASS_2D) \
+                mag = levels[0 * stride + 1] + levels[1 * stride + 0] + \
+                      levels[1 * stride + 1]; \
+            mag &= 63; \
+            ctx = mag > 12 ? 6 : (mag + 1) >> 1; \
+            dc_tok = dav1d_msac_decode_hi_tok(&ts->msac, hi_cdf[ctx]); \
+            if (dbg) \
+                printf("Post-dc_hi_tok[%d][%d][0][%d]: r=%d\n", \
+                       imin(t_dim->ctx, 3), chroma, dc_tok, ts->msac.rng); \
+        } \
+        break
+
+        const uint16_t *scan;
+        switch (tx_class) {
+        case TX_CLASS_2D: {
+            const unsigned nonsquare_tx = tx >= RTX_4X8;
+            const uint8_t (*const lo_ctx_offsets)[5] =
+                dav1d_lo_ctx_offsets[nonsquare_tx + (tx & nonsquare_tx)];
+            scan = dav1d_scans[tx];
+            const ptrdiff_t stride = 4 << slh;
+            const unsigned shift = slh + 2, shift2 = 0;
+            const unsigned mask = (4 << slh) - 1;
+            memset(levels, 0, stride * ((4 << slw) + 2));
+            DECODE_COEFS_CLASS(TX_CLASS_2D);
+        }
+        case TX_CLASS_H: {
+            const uint8_t (*const lo_ctx_offsets)[5] = NULL;
+            const ptrdiff_t stride = 16;
+            const unsigned shift = slh + 2, shift2 = 0;
+            const unsigned mask = (4 << slh) - 1;
+            memset(levels, 0, stride * ((4 << slh) + 2));
+            DECODE_COEFS_CLASS(TX_CLASS_H);
+        }
+        case TX_CLASS_V: {
+            const uint8_t (*const lo_ctx_offsets)[5] = NULL;
+            const ptrdiff_t stride = 16;
+            const unsigned shift = slw + 2, shift2 = slh + 2;
+            const unsigned mask = (4 << slw) - 1;
+            memset(levels, 0, stride * ((4 << slw) + 2));
+            DECODE_COEFS_CLASS(TX_CLASS_V);
+        }
+#undef DECODE_COEFS_CLASS
+        default: assert(0);
+        }
+    } else { // dc-only
+        int tok_br = dav1d_msac_decode_symbol_adapt4(&ts->msac, eob_cdf[0], 2);
+        dc_tok = 1 + tok_br;
+        if (dbg)
+            printf("Post-dc_lo_tok[%d][%d][%d][%d]: r=%d\n",
+                   t_dim->ctx, chroma, 0, dc_tok, ts->msac.rng);
+        if (tok_br == 2) {
+            dc_tok = dav1d_msac_decode_hi_tok(&ts->msac, hi_cdf[0]);
+            if (dbg)
+                printf("Post-dc_hi_tok[%d][%d][0][%d]: r=%d\n",
+                       imin(t_dim->ctx, 3), chroma, dc_tok, ts->msac.rng);
+        }
+        rc = 0;
+    }
+
+    // residual and sign
+    const uint16_t *const dq_tbl = ts->dq[b->seg_id][plane];
+    const uint8_t *const qm_tbl = *txtp < IDTX ? f->qm[tx][plane] : NULL;
+    const int dq_shift = imax(0, t_dim->ctx - 2);
+    const int cf_max = ~(~127U << (BITDEPTH == 8 ? 8 : f->cur.p.bpc));
+    unsigned cul_level, dc_sign_level;
+
+    if (!dc_tok) {
+        cul_level = 0;
+        dc_sign_level = 1 << 6;
+        if (qm_tbl) goto ac_qm;
+        goto ac_noqm;
+    }
+
+    const int dc_sign_ctx = get_dc_sign_ctx(tx, a, l);
+    uint16_t *const dc_sign_cdf = ts->cdf.coef.dc_sign[chroma][dc_sign_ctx];
+    const int dc_sign = dav1d_msac_decode_bool_adapt(&ts->msac, dc_sign_cdf);
+    if (dbg)
+        printf("Post-dc_sign[%d][%d][%d]: r=%d\n",
+               chroma, dc_sign_ctx, dc_sign, ts->msac.rng);
+
+    int dc_dq = dq_tbl[0];
+    dc_sign_level = (dc_sign - 1) & (2 << 6);
+
+    if (qm_tbl) {
+        dc_dq = (dc_dq * qm_tbl[0] + 16) >> 5;
+
+        if (dc_tok == 15) {
+            dc_tok = read_golomb(&ts->msac) + 15;
+            if (dbg)
+                printf("Post-dc_residual[%d->%d]: r=%d\n",
+                       dc_tok - 15, dc_tok, ts->msac.rng);
+
+            dc_tok &= 0xfffff;
+            dc_dq = (dc_dq * dc_tok) & 0xffffff;
+        } else {
+            dc_dq *= dc_tok;
+            assert(dc_dq <= 0xffffff);
+        }
+        cul_level = dc_tok;
+        dc_dq >>= dq_shift;
+        dc_dq = umin(dc_dq, cf_max + dc_sign);
+        cf[0] = (coef) (dc_sign ? -dc_dq : dc_dq);
+
+        if (rc) ac_qm: {
+            const unsigned ac_dq = dq_tbl[1];
+            do {
+                const int sign = dav1d_msac_decode_bool_equi(&ts->msac);
+                if (dbg)
+                    printf("Post-sign[%d=%d]: r=%d\n", rc, sign, ts->msac.rng);
+                const unsigned rc_tok = cf[rc];
+                unsigned tok, dq = (ac_dq * qm_tbl[rc] + 16) >> 5;
+                int dq_sat;
+
+                if (rc_tok >= (15 << 11)) {
+                    tok = read_golomb(&ts->msac) + 15;
+                    if (dbg)
+                        printf("Post-residual[%d=%d->%d]: r=%d\n",
+                               rc, tok - 15, tok, ts->msac.rng);
+
+                    tok &= 0xfffff;
+                    dq = (dq * tok) & 0xffffff;
+                } else {
+                    tok = rc_tok >> 11;
+                    dq *= tok;
+                    assert(dq <= 0xffffff);
+                }
+                cul_level += tok;
+                dq >>= dq_shift;
+                dq_sat = umin(dq, cf_max + sign);
+                cf[rc] = (coef) (sign ? -dq_sat : dq_sat);
+
+                rc = rc_tok & 0x3ff;
+            } while (rc);
+        }
+    } else {
+        // non-qmatrix is the common case and allows for additional optimizations
+        if (dc_tok == 15) {
+            dc_tok = read_golomb(&ts->msac) + 15;
+            if (dbg)
+                printf("Post-dc_residual[%d->%d]: r=%d\n",
+                       dc_tok - 15, dc_tok, ts->msac.rng);
+
+            dc_tok &= 0xfffff;
+            dc_dq = ((dc_dq * dc_tok) & 0xffffff) >> dq_shift;
+            dc_dq = umin(dc_dq, cf_max + dc_sign);
+        } else {
+            dc_dq = ((dc_dq * dc_tok) >> dq_shift);
+            assert(dc_dq <= cf_max);
+        }
+        cul_level = dc_tok;
+        cf[0] = (coef) (dc_sign ? -dc_dq : dc_dq);
+
+        if (rc) ac_noqm: {
+            const unsigned ac_dq = dq_tbl[1];
+            do {
+                const int sign = dav1d_msac_decode_bool_equi(&ts->msac);
+                if (dbg)
+                    printf("Post-sign[%d=%d]: r=%d\n", rc, sign, ts->msac.rng);
+                const unsigned rc_tok = cf[rc];
+                unsigned tok;
+                int dq;
+
+                // residual
+                if (rc_tok >= (15 << 11)) {
+                    tok = read_golomb(&ts->msac) + 15;
+                    if (dbg)
+                        printf("Post-residual[%d=%d->%d]: r=%d\n",
+                               rc, tok - 15, tok, ts->msac.rng);
+
+                    // coefficient parsing, see 5.11.39
+                    tok &= 0xfffff;
+
+                    // dequant, see 7.12.3
+                    dq = ((ac_dq * tok) & 0xffffff) >> dq_shift;
+                    dq = umin(dq, cf_max + sign);
+                } else {
+                    // cannot exceed cf_max, so we can avoid the clipping
+                    tok = rc_tok >> 11;
+                    dq = ((ac_dq * tok) >> dq_shift);
+                    assert(dq <= cf_max);
+                }
+                cul_level += tok;
+                cf[rc] = (coef) (sign ? -dq : dq);
+
+                rc = rc_tok & 0x3ff; // next non-zero rc, zero if eob
+            } while (rc);
+        }
+    }
+
+    // context
+    *res_ctx = umin(cul_level, 63) | dc_sign_level;
+
+    return eob;
+}
+
+static void read_coef_tree(Dav1dTaskContext *const t,
+                           const enum BlockSize bs, const Av1Block *const b,
+                           const enum RectTxfmSize ytx, const int depth,
+                           const uint16_t *const tx_split,
+                           const int x_off, const int y_off, pixel *dst)
+{
+    const Dav1dFrameContext *const f = t->f;
+    Dav1dTileState *const ts = t->ts;
+    const Dav1dDSPContext *const dsp = f->dsp;
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[ytx];
+    const int txw = t_dim->w, txh = t_dim->h;
+
+    /* y_off can be larger than 3 since lossless blocks use TX_4X4 but can't
+     * be splitted. Aviods an undefined left shift. */
+    if (depth < 2 && tx_split[depth] &&
+        tx_split[depth] & (1 << (y_off * 4 + x_off)))
+    {
+        const enum RectTxfmSize sub = t_dim->sub;
+        const TxfmInfo *const sub_t_dim = &dav1d_txfm_dimensions[sub];
+        const int txsw = sub_t_dim->w, txsh = sub_t_dim->h;
+
+        read_coef_tree(t, bs, b, sub, depth + 1, tx_split,
+                       x_off * 2 + 0, y_off * 2 + 0, dst);
+        t->bx += txsw;
+        if (txw >= txh && t->bx < f->bw)
+            read_coef_tree(t, bs, b, sub, depth + 1, tx_split, x_off * 2 + 1,
+                           y_off * 2 + 0, dst ? &dst[4 * txsw] : NULL);
+        t->bx -= txsw;
+        t->by += txsh;
+        if (txh >= txw && t->by < f->bh) {
+            if (dst)
+                dst += 4 * txsh * PXSTRIDE(f->cur.stride[0]);
+            read_coef_tree(t, bs, b, sub, depth + 1, tx_split,
+                           x_off * 2 + 0, y_off * 2 + 1, dst);
+            t->bx += txsw;
+            if (txw >= txh && t->bx < f->bw)
+                read_coef_tree(t, bs, b, sub, depth + 1, tx_split, x_off * 2 + 1,
+                               y_off * 2 + 1, dst ? &dst[4 * txsw] : NULL);
+            t->bx -= txsw;
+        }
+        t->by -= txsh;
+    } else {
+        const int bx4 = t->bx & 31, by4 = t->by & 31;
+        enum TxfmType txtp;
+        uint8_t cf_ctx;
+        int eob;
+        coef *cf;
+
+        if (t->frame_thread.pass) {
+            const int p = t->frame_thread.pass & 1;
+            assert(ts->frame_thread[p].cf);
+            cf = ts->frame_thread[p].cf;
+            ts->frame_thread[p].cf += imin(t_dim->w, 8) * imin(t_dim->h, 8) * 16;
+        } else {
+            cf = bitfn(t->cf);
+        }
+        if (t->frame_thread.pass != 2) {
+            eob = decode_coefs(t, &t->a->lcoef[bx4], &t->l.lcoef[by4],
+                               ytx, bs, b, 0, 0, cf, &txtp, &cf_ctx);
+            if (DEBUG_BLOCK_INFO)
+                printf("Post-y-cf-blk[tx=%d,txtp=%d,eob=%d]: r=%d\n",
+                       ytx, txtp, eob, ts->msac.rng);
+            dav1d_memset_likely_pow2(&t->a->lcoef[bx4], cf_ctx, imin(txw, f->bw - t->bx));
+            dav1d_memset_likely_pow2(&t->l.lcoef[by4], cf_ctx, imin(txh, f->bh - t->by));
+#define set_ctx(rep_macro) \
+            for (int y = 0; y < txh; y++) { \
+                rep_macro(txtp_map, 0, txtp); \
+                txtp_map += 32; \
+            }
+            uint8_t *txtp_map = &t->scratch.txtp_map[by4 * 32 + bx4];
+            case_set_upto16(t_dim->lw);
+#undef set_ctx
+            if (t->frame_thread.pass == 1)
+                *ts->frame_thread[1].cbi++ = eob * (1 << 5) + txtp;
+        } else {
+            const int cbi = *ts->frame_thread[0].cbi++;
+            eob  = cbi >> 5;
+            txtp = cbi & 0x1f;
+        }
+        if (!(t->frame_thread.pass & 1)) {
+            assert(dst);
+            if (eob >= 0) {
+                if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                    coef_dump(cf, imin(t_dim->h, 8) * 4, imin(t_dim->w, 8) * 4, 3, "dq");
+                dsp->itx.itxfm_add[ytx][txtp](dst, f->cur.stride[0], cf, eob
+                                              HIGHBD_CALL_SUFFIX);
+                if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                    hex_dump(dst, f->cur.stride[0], t_dim->w * 4, t_dim->h * 4, "recon");
+            }
+        }
+    }
+}
+
+void bytefn(dav1d_read_coef_blocks)(Dav1dTaskContext *const t,
+                                    const enum BlockSize bs, const Av1Block *const b)
+{
+    const Dav1dFrameContext *const f = t->f;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int bx4 = t->bx & 31, by4 = t->by & 31;
+    const int cbx4 = bx4 >> ss_hor, cby4 = by4 >> ss_ver;
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+    const int bw4 = b_dim[0], bh4 = b_dim[1];
+    const int cbw4 = (bw4 + ss_hor) >> ss_hor, cbh4 = (bh4 + ss_ver) >> ss_ver;
+    const int has_chroma = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400 &&
+                           (bw4 > ss_hor || t->bx & 1) &&
+                           (bh4 > ss_ver || t->by & 1);
+
+    if (b->skip) {
+        BlockContext *const a = t->a;
+        dav1d_memset_pow2[b_dim[2]](&a->lcoef[bx4], 0x40);
+        dav1d_memset_pow2[b_dim[3]](&t->l.lcoef[by4], 0x40);
+        if (has_chroma) {
+            dav1d_memset_pow2_fn memset_cw = dav1d_memset_pow2[ulog2(cbw4)];
+            dav1d_memset_pow2_fn memset_ch = dav1d_memset_pow2[ulog2(cbh4)];
+            memset_cw(&a->ccoef[0][cbx4], 0x40);
+            memset_cw(&a->ccoef[1][cbx4], 0x40);
+            memset_ch(&t->l.ccoef[0][cby4], 0x40);
+            memset_ch(&t->l.ccoef[1][cby4], 0x40);
+        }
+        return;
+    }
+
+    Dav1dTileState *const ts = t->ts;
+    const int w4 = imin(bw4, f->bw - t->bx), h4 = imin(bh4, f->bh - t->by);
+    const int cw4 = (w4 + ss_hor) >> ss_hor, ch4 = (h4 + ss_ver) >> ss_ver;
+    assert(t->frame_thread.pass == 1);
+    assert(!b->skip);
+    const TxfmInfo *const uv_t_dim = &dav1d_txfm_dimensions[b->uvtx];
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[b->intra ? b->tx : b->max_ytx];
+    const uint16_t tx_split[2] = { b->tx_split0, b->tx_split1 };
+
+    for (int init_y = 0; init_y < h4; init_y += 16) {
+        const int sub_h4 = imin(h4, 16 + init_y);
+        for (int init_x = 0; init_x < w4; init_x += 16) {
+            const int sub_w4 = imin(w4, init_x + 16);
+            int y_off = !!init_y, y, x;
+            for (y = init_y, t->by += init_y; y < sub_h4;
+                 y += t_dim->h, t->by += t_dim->h, y_off++)
+            {
+                int x_off = !!init_x;
+                for (x = init_x, t->bx += init_x; x < sub_w4;
+                     x += t_dim->w, t->bx += t_dim->w, x_off++)
+                {
+                    if (!b->intra) {
+                        read_coef_tree(t, bs, b, b->max_ytx, 0, tx_split,
+                                       x_off, y_off, NULL);
+                    } else {
+                        uint8_t cf_ctx = 0x40;
+                        enum TxfmType txtp;
+                        const int eob =
+                            decode_coefs(t, &t->a->lcoef[bx4 + x],
+                                         &t->l.lcoef[by4 + y], b->tx, bs, b, 1,
+                                         0, ts->frame_thread[1].cf, &txtp, &cf_ctx);
+                        if (DEBUG_BLOCK_INFO)
+                            printf("Post-y-cf-blk[tx=%d,txtp=%d,eob=%d]: r=%d\n",
+                                   b->tx, txtp, eob, ts->msac.rng);
+                        *ts->frame_thread[1].cbi++ = eob * (1 << 5) + txtp;
+                        ts->frame_thread[1].cf += imin(t_dim->w, 8) * imin(t_dim->h, 8) * 16;
+                        dav1d_memset_likely_pow2(&t->a->lcoef[bx4 + x], cf_ctx, imin(t_dim->w, f->bw - t->bx));
+                        dav1d_memset_likely_pow2(&t->l.lcoef[by4 + y], cf_ctx, imin(t_dim->h, f->bh - t->by));
+                    }
+                }
+                t->bx -= x;
+            }
+            t->by -= y;
+
+            if (!has_chroma) continue;
+
+            const int sub_ch4 = imin(ch4, (init_y + 16) >> ss_ver);
+            const int sub_cw4 = imin(cw4, (init_x + 16) >> ss_hor);
+            for (int pl = 0; pl < 2; pl++) {
+                for (y = init_y >> ss_ver, t->by += init_y; y < sub_ch4;
+                     y += uv_t_dim->h, t->by += uv_t_dim->h << ss_ver)
+                {
+                    for (x = init_x >> ss_hor, t->bx += init_x; x < sub_cw4;
+                         x += uv_t_dim->w, t->bx += uv_t_dim->w << ss_hor)
+                    {
+                        uint8_t cf_ctx = 0x40;
+                        enum TxfmType txtp;
+                        if (!b->intra)
+                            txtp = t->scratch.txtp_map[(by4 + (y << ss_ver)) * 32 +
+                                                        bx4 + (x << ss_hor)];
+                        const int eob =
+                            decode_coefs(t, &t->a->ccoef[pl][cbx4 + x],
+                                         &t->l.ccoef[pl][cby4 + y], b->uvtx, bs,
+                                         b, b->intra, 1 + pl, ts->frame_thread[1].cf,
+                                         &txtp, &cf_ctx);
+                        if (DEBUG_BLOCK_INFO)
+                            printf("Post-uv-cf-blk[pl=%d,tx=%d,"
+                                   "txtp=%d,eob=%d]: r=%d\n",
+                                   pl, b->uvtx, txtp, eob, ts->msac.rng);
+                        *ts->frame_thread[1].cbi++ = eob * (1 << 5) + txtp;
+                        ts->frame_thread[1].cf += uv_t_dim->w * uv_t_dim->h * 16;
+                        int ctw = imin(uv_t_dim->w, (f->bw - t->bx + ss_hor) >> ss_hor);
+                        int cth = imin(uv_t_dim->h, (f->bh - t->by + ss_ver) >> ss_ver);
+                        dav1d_memset_likely_pow2(&t->a->ccoef[pl][cbx4 + x], cf_ctx, ctw);
+                        dav1d_memset_likely_pow2(&t->l.ccoef[pl][cby4 + y], cf_ctx, cth);
+                    }
+                    t->bx -= x << ss_hor;
+                }
+                t->by -= y << ss_ver;
+            }
+        }
+    }
+}
+
+static int mc(Dav1dTaskContext *const t,
+              pixel *const dst8, int16_t *const dst16, const ptrdiff_t dst_stride,
+              const int bw4, const int bh4,
+              const int bx, const int by, const int pl,
+              const mv mv, const Dav1dThreadPicture *const refp, const int refidx,
+              const enum Filter2d filter_2d)
+{
+    assert((dst8 != NULL) ^ (dst16 != NULL));
+    const Dav1dFrameContext *const f = t->f;
+    const int ss_ver = !!pl && f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = !!pl && f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int h_mul = 4 >> ss_hor, v_mul = 4 >> ss_ver;
+    const int mvx = mv.x, mvy = mv.y;
+    const int mx = mvx & (15 >> !ss_hor), my = mvy & (15 >> !ss_ver);
+    ptrdiff_t ref_stride = refp->p.stride[!!pl];
+    const pixel *ref;
+
+    if (refp->p.p.w == f->cur.p.w && refp->p.p.h == f->cur.p.h) {
+        const int dx = bx * h_mul + (mvx >> (3 + ss_hor));
+        const int dy = by * v_mul + (mvy >> (3 + ss_ver));
+        int w, h;
+
+        if (refp->p.data[0] != f->cur.data[0]) { // i.e. not for intrabc
+            w = (f->cur.p.w + ss_hor) >> ss_hor;
+            h = (f->cur.p.h + ss_ver) >> ss_ver;
+        } else {
+            w = f->bw * 4 >> ss_hor;
+            h = f->bh * 4 >> ss_ver;
+        }
+        if (dx < !!mx * 3 || dy < !!my * 3 ||
+            dx + bw4 * h_mul + !!mx * 4 > w ||
+            dy + bh4 * v_mul + !!my * 4 > h)
+        {
+            pixel *const emu_edge_buf = bitfn(t->scratch.emu_edge);
+            f->dsp->mc.emu_edge(bw4 * h_mul + !!mx * 7, bh4 * v_mul + !!my * 7,
+                                w, h, dx - !!mx * 3, dy - !!my * 3,
+                                emu_edge_buf, 192 * sizeof(pixel),
+                                refp->p.data[pl], ref_stride);
+            ref = &emu_edge_buf[192 * !!my * 3 + !!mx * 3];
+            ref_stride = 192 * sizeof(pixel);
+        } else {
+            ref = ((pixel *) refp->p.data[pl]) + PXSTRIDE(ref_stride) * dy + dx;
+        }
+
+        if (dst8 != NULL) {
+            f->dsp->mc.mc[filter_2d](dst8, dst_stride, ref, ref_stride, bw4 * h_mul,
+                                     bh4 * v_mul, mx << !ss_hor, my << !ss_ver
+                                     HIGHBD_CALL_SUFFIX);
+        } else {
+            f->dsp->mc.mct[filter_2d](dst16, ref, ref_stride, bw4 * h_mul,
+                                      bh4 * v_mul, mx << !ss_hor, my << !ss_ver
+                                      HIGHBD_CALL_SUFFIX);
+        }
+    } else {
+        assert(refp != &f->sr_cur);
+
+        const int orig_pos_y = (by * v_mul << 4) + mvy * (1 << !ss_ver);
+        const int orig_pos_x = (bx * h_mul << 4) + mvx * (1 << !ss_hor);
+#define scale_mv(res, val, scale) do { \
+            const int64_t tmp = (int64_t)(val) * scale + (scale - 0x4000) * 8; \
+            res = apply_sign64((int) ((llabs(tmp) + 128) >> 8), tmp) + 32;     \
+        } while (0)
+        int pos_y, pos_x;
+        scale_mv(pos_x, orig_pos_x, f->svc[refidx][0].scale);
+        scale_mv(pos_y, orig_pos_y, f->svc[refidx][1].scale);
+#undef scale_mv
+        const int left = pos_x >> 10;
+        const int top = pos_y >> 10;
+        const int right =
+            ((pos_x + (bw4 * h_mul - 1) * f->svc[refidx][0].step) >> 10) + 1;
+        const int bottom =
+            ((pos_y + (bh4 * v_mul - 1) * f->svc[refidx][1].step) >> 10) + 1;
+
+        if (DEBUG_BLOCK_INFO)
+            printf("Off %dx%d [%d,%d,%d], size %dx%d [%d,%d]\n",
+                   left, top, orig_pos_x, f->svc[refidx][0].scale, refidx,
+                   right-left, bottom-top,
+                   f->svc[refidx][0].step, f->svc[refidx][1].step);
+
+        const int w = (refp->p.p.w + ss_hor) >> ss_hor;
+        const int h = (refp->p.p.h + ss_ver) >> ss_ver;
+        if (left < 3 || top < 3 || right + 4 > w || bottom + 4 > h) {
+            pixel *const emu_edge_buf = bitfn(t->scratch.emu_edge);
+            f->dsp->mc.emu_edge(right - left + 7, bottom - top + 7,
+                                w, h, left - 3, top - 3,
+                                emu_edge_buf, 320 * sizeof(pixel),
+                                refp->p.data[pl], ref_stride);
+            ref = &emu_edge_buf[320 * 3 + 3];
+            ref_stride = 320 * sizeof(pixel);
+            if (DEBUG_BLOCK_INFO) printf("Emu\n");
+        } else {
+            ref = ((pixel *) refp->p.data[pl]) + PXSTRIDE(ref_stride) * top + left;
+        }
+
+        if (dst8 != NULL) {
+            f->dsp->mc.mc_scaled[filter_2d](dst8, dst_stride, ref, ref_stride,
+                                            bw4 * h_mul, bh4 * v_mul,
+                                            pos_x & 0x3ff, pos_y & 0x3ff,
+                                            f->svc[refidx][0].step,
+                                            f->svc[refidx][1].step
+                                            HIGHBD_CALL_SUFFIX);
+        } else {
+            f->dsp->mc.mct_scaled[filter_2d](dst16, ref, ref_stride,
+                                             bw4 * h_mul, bh4 * v_mul,
+                                             pos_x & 0x3ff, pos_y & 0x3ff,
+                                             f->svc[refidx][0].step,
+                                             f->svc[refidx][1].step
+                                             HIGHBD_CALL_SUFFIX);
+        }
+    }
+
+    return 0;
+}
+
+static int obmc(Dav1dTaskContext *const t,
+                pixel *const dst, const ptrdiff_t dst_stride,
+                const uint8_t *const b_dim, const int pl,
+                const int bx4, const int by4, const int w4, const int h4)
+{
+    assert(!(t->bx & 1) && !(t->by & 1));
+    const Dav1dFrameContext *const f = t->f;
+    /*const*/ refmvs_block **r = &t->rt.r[(t->by & 31) + 5];
+    pixel *const lap = bitfn(t->scratch.lap);
+    const int ss_ver = !!pl && f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = !!pl && f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int h_mul = 4 >> ss_hor, v_mul = 4 >> ss_ver;
+    int res;
+
+    if (t->by > t->ts->tiling.row_start &&
+        (!pl || b_dim[0] * h_mul + b_dim[1] * v_mul >= 16))
+    {
+        for (int i = 0, x = 0; x < w4 && i < imin(b_dim[2], 4); ) {
+            // only odd blocks are considered for overlap handling, hence +1
+            const refmvs_block *const a_r = &r[-1][t->bx + x + 1];
+            const uint8_t *const a_b_dim = dav1d_block_dimensions[a_r->bs];
+            const int step4 = iclip(a_b_dim[0], 2, 16);
+
+            if (a_r->ref.ref[0] > 0) {
+                const int ow4 = imin(step4, b_dim[0]);
+                const int oh4 = imin(b_dim[1], 16) >> 1;
+                res = mc(t, lap, NULL, ow4 * h_mul * sizeof(pixel), ow4, (oh4 * 3 + 3) >> 2,
+                         t->bx + x, t->by, pl, a_r->mv.mv[0],
+                         &f->refp[a_r->ref.ref[0] - 1], a_r->ref.ref[0] - 1,
+                         dav1d_filter_2d[t->a->filter[1][bx4 + x + 1]][t->a->filter[0][bx4 + x + 1]]);
+                if (res) return res;
+                f->dsp->mc.blend_h(&dst[x * h_mul], dst_stride, lap,
+                                   h_mul * ow4, v_mul * oh4);
+                i++;
+            }
+            x += step4;
+        }
+    }
+
+    if (t->bx > t->ts->tiling.col_start)
+        for (int i = 0, y = 0; y < h4 && i < imin(b_dim[3], 4); ) {
+            // only odd blocks are considered for overlap handling, hence +1
+            const refmvs_block *const l_r = &r[y + 1][t->bx - 1];
+            const uint8_t *const l_b_dim = dav1d_block_dimensions[l_r->bs];
+            const int step4 = iclip(l_b_dim[1], 2, 16);
+
+            if (l_r->ref.ref[0] > 0) {
+                const int ow4 = imin(b_dim[0], 16) >> 1;
+                const int oh4 = imin(step4, b_dim[1]);
+                res = mc(t, lap, NULL, h_mul * ow4 * sizeof(pixel), ow4, oh4,
+                         t->bx, t->by + y, pl, l_r->mv.mv[0],
+                         &f->refp[l_r->ref.ref[0] - 1], l_r->ref.ref[0] - 1,
+                         dav1d_filter_2d[t->l.filter[1][by4 + y + 1]][t->l.filter[0][by4 + y + 1]]);
+                if (res) return res;
+                f->dsp->mc.blend_v(&dst[y * v_mul * PXSTRIDE(dst_stride)],
+                                   dst_stride, lap, h_mul * ow4, v_mul * oh4);
+                i++;
+            }
+            y += step4;
+        }
+    return 0;
+}
+
+static int warp_affine(Dav1dTaskContext *const t,
+                       pixel *dst8, int16_t *dst16, const ptrdiff_t dstride,
+                       const uint8_t *const b_dim, const int pl,
+                       const Dav1dThreadPicture *const refp,
+                       const Dav1dWarpedMotionParams *const wmp)
+{
+    assert((dst8 != NULL) ^ (dst16 != NULL));
+    const Dav1dFrameContext *const f = t->f;
+    const Dav1dDSPContext *const dsp = f->dsp;
+    const int ss_ver = !!pl && f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = !!pl && f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int h_mul = 4 >> ss_hor, v_mul = 4 >> ss_ver;
+    assert(!((b_dim[0] * h_mul) & 7) && !((b_dim[1] * v_mul) & 7));
+    const int32_t *const mat = wmp->matrix;
+    const int width = (refp->p.p.w + ss_hor) >> ss_hor;
+    const int height = (refp->p.p.h + ss_ver) >> ss_ver;
+
+    for (int y = 0; y < b_dim[1] * v_mul; y += 8) {
+        const int src_y = t->by * 4 + ((y + 4) << ss_ver);
+        const int64_t mat3_y = (int64_t) mat[3] * src_y + mat[0];
+        const int64_t mat5_y = (int64_t) mat[5] * src_y + mat[1];
+        for (int x = 0; x < b_dim[0] * h_mul; x += 8) {
+            // calculate transformation relative to center of 8x8 block in
+            // luma pixel units
+            const int src_x = t->bx * 4 + ((x + 4) << ss_hor);
+            const int64_t mvx = ((int64_t) mat[2] * src_x + mat3_y) >> ss_hor;
+            const int64_t mvy = ((int64_t) mat[4] * src_x + mat5_y) >> ss_ver;
+
+            const int dx = (int) (mvx >> 16) - 4;
+            const int mx = (((int) mvx & 0xffff) - wmp->u.p.alpha * 4 -
+                                                   wmp->u.p.beta  * 7) & ~0x3f;
+            const int dy = (int) (mvy >> 16) - 4;
+            const int my = (((int) mvy & 0xffff) - wmp->u.p.gamma * 4 -
+                                                   wmp->u.p.delta * 4) & ~0x3f;
+
+            const pixel *ref_ptr;
+            ptrdiff_t ref_stride = refp->p.stride[!!pl];
+
+            if (dx < 3 || dx + 8 + 4 > width || dy < 3 || dy + 8 + 4 > height) {
+                pixel *const emu_edge_buf = bitfn(t->scratch.emu_edge);
+                f->dsp->mc.emu_edge(15, 15, width, height, dx - 3, dy - 3,
+                                    emu_edge_buf, 32 * sizeof(pixel),
+                                    refp->p.data[pl], ref_stride);
+                ref_ptr = &emu_edge_buf[32 * 3 + 3];
+                ref_stride = 32 * sizeof(pixel);
+            } else {
+                ref_ptr = ((pixel *) refp->p.data[pl]) + PXSTRIDE(ref_stride) * dy + dx;
+            }
+            if (dst16 != NULL)
+                dsp->mc.warp8x8t(&dst16[x], dstride, ref_ptr, ref_stride,
+                                 wmp->u.abcd, mx, my HIGHBD_CALL_SUFFIX);
+            else
+                dsp->mc.warp8x8(&dst8[x], dstride, ref_ptr, ref_stride,
+                                wmp->u.abcd, mx, my HIGHBD_CALL_SUFFIX);
+        }
+        if (dst8) dst8  += 8 * PXSTRIDE(dstride);
+        else      dst16 += 8 * dstride;
+    }
+    return 0;
+}
+
+void bytefn(dav1d_recon_b_intra)(Dav1dTaskContext *const t, const enum BlockSize bs,
+                                 const enum EdgeFlags intra_edge_flags,
+                                 const Av1Block *const b)
+{
+    Dav1dTileState *const ts = t->ts;
+    const Dav1dFrameContext *const f = t->f;
+    const Dav1dDSPContext *const dsp = f->dsp;
+    const int bx4 = t->bx & 31, by4 = t->by & 31;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int cbx4 = bx4 >> ss_hor, cby4 = by4 >> ss_ver;
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+    const int bw4 = b_dim[0], bh4 = b_dim[1];
+    const int w4 = imin(bw4, f->bw - t->bx), h4 = imin(bh4, f->bh - t->by);
+    const int cw4 = (w4 + ss_hor) >> ss_hor, ch4 = (h4 + ss_ver) >> ss_ver;
+    const int has_chroma = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400 &&
+                           (bw4 > ss_hor || t->bx & 1) &&
+                           (bh4 > ss_ver || t->by & 1);
+    const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[b->tx];
+    const TxfmInfo *const uv_t_dim = &dav1d_txfm_dimensions[b->uvtx];
+
+    // coefficient coding
+    pixel *const edge = bitfn(t->scratch.edge) + 128;
+    const int cbw4 = (bw4 + ss_hor) >> ss_hor, cbh4 = (bh4 + ss_ver) >> ss_ver;
+
+    const int intra_edge_filter_flag = f->seq_hdr->intra_edge_filter << 10;
+
+    for (int init_y = 0; init_y < h4; init_y += 16) {
+        const int sub_h4 = imin(h4, 16 + init_y);
+        const int sub_ch4 = imin(ch4, (init_y + 16) >> ss_ver);
+        for (int init_x = 0; init_x < w4; init_x += 16) {
+            if (b->pal_sz[0]) {
+                pixel *dst = ((pixel *) f->cur.data[0]) +
+                             4 * (t->by * PXSTRIDE(f->cur.stride[0]) + t->bx);
+                const uint8_t *pal_idx;
+                if (t->frame_thread.pass) {
+                    const int p = t->frame_thread.pass & 1;
+                    assert(ts->frame_thread[p].pal_idx);
+                    pal_idx = ts->frame_thread[p].pal_idx;
+                    ts->frame_thread[p].pal_idx += bw4 * bh4 * 8;
+                } else {
+                    pal_idx = t->scratch.pal_idx_y;
+                }
+                const pixel *const pal = t->frame_thread.pass ?
+                    f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) +
+                                        ((t->bx >> 1) + (t->by & 1))][0] :
+                    bytefn(t->scratch.pal)[0];
+                f->dsp->ipred.pal_pred(dst, f->cur.stride[0], pal,
+                                       pal_idx, bw4 * 4, bh4 * 4);
+                if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                    hex_dump(dst, PXSTRIDE(f->cur.stride[0]),
+                             bw4 * 4, bh4 * 4, "y-pal-pred");
+            }
+
+            const int intra_flags = (sm_flag(t->a, bx4) |
+                                     sm_flag(&t->l, by4) |
+                                     intra_edge_filter_flag);
+            const int sb_has_tr = init_x + 16 < w4 ? 1 : init_y ? 0 :
+                              intra_edge_flags & EDGE_I444_TOP_HAS_RIGHT;
+            const int sb_has_bl = init_x ? 0 : init_y + 16 < h4 ? 1 :
+                              intra_edge_flags & EDGE_I444_LEFT_HAS_BOTTOM;
+            int y, x;
+            const int sub_w4 = imin(w4, init_x + 16);
+            for (y = init_y, t->by += init_y; y < sub_h4;
+                 y += t_dim->h, t->by += t_dim->h)
+            {
+                pixel *dst = ((pixel *) f->cur.data[0]) +
+                               4 * (t->by * PXSTRIDE(f->cur.stride[0]) +
+                                    t->bx + init_x);
+                for (x = init_x, t->bx += init_x; x < sub_w4;
+                     x += t_dim->w, t->bx += t_dim->w)
+                {
+                    if (b->pal_sz[0]) goto skip_y_pred;
+
+                    int angle = b->y_angle;
+                    const enum EdgeFlags edge_flags =
+                        (((y > init_y || !sb_has_tr) && (x + t_dim->w >= sub_w4)) ?
+                             0 : EDGE_I444_TOP_HAS_RIGHT) |
+                        ((x > init_x || (!sb_has_bl && y + t_dim->h >= sub_h4)) ?
+                             0 : EDGE_I444_LEFT_HAS_BOTTOM);
+                    const pixel *top_sb_edge = NULL;
+                    if (!(t->by & (f->sb_step - 1))) {
+                        top_sb_edge = f->ipred_edge[0];
+                        const int sby = t->by >> f->sb_shift;
+                        top_sb_edge += f->sb128w * 128 * (sby - 1);
+                    }
+                    const enum IntraPredMode m =
+                        bytefn(dav1d_prepare_intra_edges)(t->bx,
+                                                          t->bx > ts->tiling.col_start,
+                                                          t->by,
+                                                          t->by > ts->tiling.row_start,
+                                                          ts->tiling.col_end,
+                                                          ts->tiling.row_end,
+                                                          edge_flags, dst,
+                                                          f->cur.stride[0], top_sb_edge,
+                                                          b->y_mode, &angle,
+                                                          t_dim->w, t_dim->h,
+                                                          f->seq_hdr->intra_edge_filter,
+                                                          edge HIGHBD_CALL_SUFFIX);
+                    dsp->ipred.intra_pred[m](dst, f->cur.stride[0], edge,
+                                             t_dim->w * 4, t_dim->h * 4,
+                                             angle | intra_flags,
+                                             4 * f->bw - 4 * t->bx,
+                                             4 * f->bh - 4 * t->by
+                                             HIGHBD_CALL_SUFFIX);
+
+                    if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS) {
+                        hex_dump(edge - t_dim->h * 4, t_dim->h * 4,
+                                 t_dim->h * 4, 2, "l");
+                        hex_dump(edge, 0, 1, 1, "tl");
+                        hex_dump(edge + 1, t_dim->w * 4,
+                                 t_dim->w * 4, 2, "t");
+                        hex_dump(dst, f->cur.stride[0],
+                                 t_dim->w * 4, t_dim->h * 4, "y-intra-pred");
+                    }
+
+                skip_y_pred: {}
+                    if (!b->skip) {
+                        coef *cf;
+                        int eob;
+                        enum TxfmType txtp;
+                        if (t->frame_thread.pass) {
+                            const int p = t->frame_thread.pass & 1;
+                            const int cbi = *ts->frame_thread[p].cbi++;
+                            cf = ts->frame_thread[p].cf;
+                            ts->frame_thread[p].cf += imin(t_dim->w, 8) * imin(t_dim->h, 8) * 16;
+                            eob  = cbi >> 5;
+                            txtp = cbi & 0x1f;
+                        } else {
+                            uint8_t cf_ctx;
+                            cf = bitfn(t->cf);
+                            eob = decode_coefs(t, &t->a->lcoef[bx4 + x],
+                                               &t->l.lcoef[by4 + y], b->tx, bs,
+                                               b, 1, 0, cf, &txtp, &cf_ctx);
+                            if (DEBUG_BLOCK_INFO)
+                                printf("Post-y-cf-blk[tx=%d,txtp=%d,eob=%d]: r=%d\n",
+                                       b->tx, txtp, eob, ts->msac.rng);
+                            dav1d_memset_likely_pow2(&t->a->lcoef[bx4 + x], cf_ctx, imin(t_dim->w, f->bw - t->bx));
+                            dav1d_memset_likely_pow2(&t->l.lcoef[by4 + y], cf_ctx, imin(t_dim->h, f->bh - t->by));
+                        }
+                        if (eob >= 0) {
+                            if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                                coef_dump(cf, imin(t_dim->h, 8) * 4,
+                                          imin(t_dim->w, 8) * 4, 3, "dq");
+                            dsp->itx.itxfm_add[b->tx]
+                                              [txtp](dst,
+                                                     f->cur.stride[0],
+                                                     cf, eob HIGHBD_CALL_SUFFIX);
+                            if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                                hex_dump(dst, f->cur.stride[0],
+                                         t_dim->w * 4, t_dim->h * 4, "recon");
+                        }
+                    } else if (!t->frame_thread.pass) {
+                        dav1d_memset_pow2[t_dim->lw](&t->a->lcoef[bx4 + x], 0x40);
+                        dav1d_memset_pow2[t_dim->lh](&t->l.lcoef[by4 + y], 0x40);
+                    }
+                    dst += 4 * t_dim->w;
+                }
+                t->bx -= x;
+            }
+            t->by -= y;
+
+            if (!has_chroma) continue;
+
+            const ptrdiff_t stride = f->cur.stride[1];
+
+            if (b->uv_mode == CFL_PRED) {
+                assert(!init_x && !init_y);
+
+                int16_t *const ac = t->scratch.ac;
+                pixel *y_src = ((pixel *) f->cur.data[0]) + 4 * (t->bx & ~ss_hor) +
+                                 4 * (t->by & ~ss_ver) * PXSTRIDE(f->cur.stride[0]);
+                const ptrdiff_t uv_off = 4 * ((t->bx >> ss_hor) +
+                                              (t->by >> ss_ver) * PXSTRIDE(stride));
+                pixel *const uv_dst[2] = { ((pixel *) f->cur.data[1]) + uv_off,
+                                           ((pixel *) f->cur.data[2]) + uv_off };
+
+                const int furthest_r =
+                    ((cw4 << ss_hor) + t_dim->w - 1) & ~(t_dim->w - 1);
+                const int furthest_b =
+                    ((ch4 << ss_ver) + t_dim->h - 1) & ~(t_dim->h - 1);
+                dsp->ipred.cfl_ac[f->cur.p.layout - 1](ac, y_src, f->cur.stride[0],
+                                                         cbw4 - (furthest_r >> ss_hor),
+                                                         cbh4 - (furthest_b >> ss_ver),
+                                                         cbw4 * 4, cbh4 * 4);
+                for (int pl = 0; pl < 2; pl++) {
+                    if (!b->cfl_alpha[pl]) continue;
+                    int angle = 0;
+                    const pixel *top_sb_edge = NULL;
+                    if (!((t->by & ~ss_ver) & (f->sb_step - 1))) {
+                        top_sb_edge = f->ipred_edge[pl + 1];
+                        const int sby = t->by >> f->sb_shift;
+                        top_sb_edge += f->sb128w * 128 * (sby - 1);
+                    }
+                    const int xpos = t->bx >> ss_hor, ypos = t->by >> ss_ver;
+                    const int xstart = ts->tiling.col_start >> ss_hor;
+                    const int ystart = ts->tiling.row_start >> ss_ver;
+                    const enum IntraPredMode m =
+                        bytefn(dav1d_prepare_intra_edges)(xpos, xpos > xstart,
+                                                          ypos, ypos > ystart,
+                                                          ts->tiling.col_end >> ss_hor,
+                                                          ts->tiling.row_end >> ss_ver,
+                                                          0, uv_dst[pl], stride,
+                                                          top_sb_edge, DC_PRED, &angle,
+                                                          uv_t_dim->w, uv_t_dim->h, 0,
+                                                          edge HIGHBD_CALL_SUFFIX);
+                    dsp->ipred.cfl_pred[m](uv_dst[pl], stride, edge,
+                                           uv_t_dim->w * 4,
+                                           uv_t_dim->h * 4,
+                                           ac, b->cfl_alpha[pl]
+                                           HIGHBD_CALL_SUFFIX);
+                }
+                if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS) {
+                    ac_dump(ac, 4*cbw4, 4*cbh4, "ac");
+                    hex_dump(uv_dst[0], stride, cbw4 * 4, cbh4 * 4, "u-cfl-pred");
+                    hex_dump(uv_dst[1], stride, cbw4 * 4, cbh4 * 4, "v-cfl-pred");
+                }
+            } else if (b->pal_sz[1]) {
+                const ptrdiff_t uv_dstoff = 4 * ((t->bx >> ss_hor) +
+                                              (t->by >> ss_ver) * PXSTRIDE(f->cur.stride[1]));
+                const pixel (*pal)[8];
+                const uint8_t *pal_idx;
+                if (t->frame_thread.pass) {
+                    const int p = t->frame_thread.pass & 1;
+                    assert(ts->frame_thread[p].pal_idx);
+                    pal = f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) +
+                                              ((t->bx >> 1) + (t->by & 1))];
+                    pal_idx = ts->frame_thread[p].pal_idx;
+                    ts->frame_thread[p].pal_idx += cbw4 * cbh4 * 8;
+                } else {
+                    pal = bytefn(t->scratch.pal);
+                    pal_idx = t->scratch.pal_idx_uv;
+                }
+
+                f->dsp->ipred.pal_pred(((pixel *) f->cur.data[1]) + uv_dstoff,
+                                       f->cur.stride[1], pal[1],
+                                       pal_idx, cbw4 * 4, cbh4 * 4);
+                f->dsp->ipred.pal_pred(((pixel *) f->cur.data[2]) + uv_dstoff,
+                                       f->cur.stride[1], pal[2],
+                                       pal_idx, cbw4 * 4, cbh4 * 4);
+                if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS) {
+                    hex_dump(((pixel *) f->cur.data[1]) + uv_dstoff,
+                             PXSTRIDE(f->cur.stride[1]),
+                             cbw4 * 4, cbh4 * 4, "u-pal-pred");
+                    hex_dump(((pixel *) f->cur.data[2]) + uv_dstoff,
+                             PXSTRIDE(f->cur.stride[1]),
+                             cbw4 * 4, cbh4 * 4, "v-pal-pred");
+                }
+            }
+
+            const int sm_uv_fl = sm_uv_flag(t->a, cbx4) |
+                                 sm_uv_flag(&t->l, cby4);
+            const int uv_sb_has_tr =
+                ((init_x + 16) >> ss_hor) < cw4 ? 1 : init_y ? 0 :
+                intra_edge_flags & (EDGE_I420_TOP_HAS_RIGHT >> (f->cur.p.layout - 1));
+            const int uv_sb_has_bl =
+                init_x ? 0 : ((init_y + 16) >> ss_ver) < ch4 ? 1 :
+                intra_edge_flags & (EDGE_I420_LEFT_HAS_BOTTOM >> (f->cur.p.layout - 1));
+            const int sub_cw4 = imin(cw4, (init_x + 16) >> ss_hor);
+            for (int pl = 0; pl < 2; pl++) {
+                for (y = init_y >> ss_ver, t->by += init_y; y < sub_ch4;
+                     y += uv_t_dim->h, t->by += uv_t_dim->h << ss_ver)
+                {
+                    pixel *dst = ((pixel *) f->cur.data[1 + pl]) +
+                                   4 * ((t->by >> ss_ver) * PXSTRIDE(stride) +
+                                        ((t->bx + init_x) >> ss_hor));
+                    for (x = init_x >> ss_hor, t->bx += init_x; x < sub_cw4;
+                         x += uv_t_dim->w, t->bx += uv_t_dim->w << ss_hor)
+                    {
+                        if ((b->uv_mode == CFL_PRED && b->cfl_alpha[pl]) ||
+                            b->pal_sz[1])
+                        {
+                            goto skip_uv_pred;
+                        }
+
+                        int angle = b->uv_angle;
+                        // this probably looks weird because we're using
+                        // luma flags in a chroma loop, but that's because
+                        // prepare_intra_edges() expects luma flags as input
+                        const enum EdgeFlags edge_flags =
+                            (((y > (init_y >> ss_ver) || !uv_sb_has_tr) &&
+                              (x + uv_t_dim->w >= sub_cw4)) ?
+                                 0 : EDGE_I444_TOP_HAS_RIGHT) |
+                            ((x > (init_x >> ss_hor) ||
+                              (!uv_sb_has_bl && y + uv_t_dim->h >= sub_ch4)) ?
+                                 0 : EDGE_I444_LEFT_HAS_BOTTOM);
+                        const pixel *top_sb_edge = NULL;
+                        if (!((t->by & ~ss_ver) & (f->sb_step - 1))) {
+                            top_sb_edge = f->ipred_edge[1 + pl];
+                            const int sby = t->by >> f->sb_shift;
+                            top_sb_edge += f->sb128w * 128 * (sby - 1);
+                        }
+                        const enum IntraPredMode uv_mode =
+                             b->uv_mode == CFL_PRED ? DC_PRED : b->uv_mode;
+                        const int xpos = t->bx >> ss_hor, ypos = t->by >> ss_ver;
+                        const int xstart = ts->tiling.col_start >> ss_hor;
+                        const int ystart = ts->tiling.row_start >> ss_ver;
+                        const enum IntraPredMode m =
+                            bytefn(dav1d_prepare_intra_edges)(xpos, xpos > xstart,
+                                                              ypos, ypos > ystart,
+                                                              ts->tiling.col_end >> ss_hor,
+                                                              ts->tiling.row_end >> ss_ver,
+                                                              edge_flags, dst, stride,
+                                                              top_sb_edge, uv_mode,
+                                                              &angle, uv_t_dim->w,
+                                                              uv_t_dim->h,
+                                                              f->seq_hdr->intra_edge_filter,
+                                                              edge HIGHBD_CALL_SUFFIX);
+                        angle |= intra_edge_filter_flag;
+                        dsp->ipred.intra_pred[m](dst, stride, edge,
+                                                 uv_t_dim->w * 4,
+                                                 uv_t_dim->h * 4,
+                                                 angle | sm_uv_fl,
+                                                 (4 * f->bw + ss_hor -
+                                                  4 * (t->bx & ~ss_hor)) >> ss_hor,
+                                                 (4 * f->bh + ss_ver -
+                                                  4 * (t->by & ~ss_ver)) >> ss_ver
+                                                 HIGHBD_CALL_SUFFIX);
+                        if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS) {
+                            hex_dump(edge - uv_t_dim->h * 4, uv_t_dim->h * 4,
+                                     uv_t_dim->h * 4, 2, "l");
+                            hex_dump(edge, 0, 1, 1, "tl");
+                            hex_dump(edge + 1, uv_t_dim->w * 4,
+                                     uv_t_dim->w * 4, 2, "t");
+                            hex_dump(dst, stride, uv_t_dim->w * 4,
+                                     uv_t_dim->h * 4, pl ? "v-intra-pred" : "u-intra-pred");
+                        }
+
+                    skip_uv_pred: {}
+                        if (!b->skip) {
+                            enum TxfmType txtp;
+                            int eob;
+                            coef *cf;
+                            if (t->frame_thread.pass) {
+                                const int p = t->frame_thread.pass & 1;
+                                const int cbi = *ts->frame_thread[p].cbi++;
+                                cf = ts->frame_thread[p].cf;
+                                ts->frame_thread[p].cf += uv_t_dim->w * uv_t_dim->h * 16;
+                                eob  = cbi >> 5;
+                                txtp = cbi & 0x1f;
+                            } else {
+                                uint8_t cf_ctx;
+                                cf = bitfn(t->cf);
+                                eob = decode_coefs(t, &t->a->ccoef[pl][cbx4 + x],
+                                                   &t->l.ccoef[pl][cby4 + y],
+                                                   b->uvtx, bs, b, 1, 1 + pl, cf,
+                                                   &txtp, &cf_ctx);
+                                if (DEBUG_BLOCK_INFO)
+                                    printf("Post-uv-cf-blk[pl=%d,tx=%d,"
+                                           "txtp=%d,eob=%d]: r=%d [x=%d,cbx4=%d]\n",
+                                           pl, b->uvtx, txtp, eob, ts->msac.rng, x, cbx4);
+                                int ctw = imin(uv_t_dim->w, (f->bw - t->bx + ss_hor) >> ss_hor);
+                                int cth = imin(uv_t_dim->h, (f->bh - t->by + ss_ver) >> ss_ver);
+                                dav1d_memset_likely_pow2(&t->a->ccoef[pl][cbx4 + x], cf_ctx, ctw);
+                                dav1d_memset_likely_pow2(&t->l.ccoef[pl][cby4 + y], cf_ctx, cth);
+                            }
+                            if (eob >= 0) {
+                                if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                                    coef_dump(cf, uv_t_dim->h * 4,
+                                              uv_t_dim->w * 4, 3, "dq");
+                                dsp->itx.itxfm_add[b->uvtx]
+                                                  [txtp](dst, stride,
+                                                         cf, eob HIGHBD_CALL_SUFFIX);
+                                if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                                    hex_dump(dst, stride, uv_t_dim->w * 4,
+                                             uv_t_dim->h * 4, "recon");
+                            }
+                        } else if (!t->frame_thread.pass) {
+                            dav1d_memset_pow2[uv_t_dim->lw](&t->a->ccoef[pl][cbx4 + x], 0x40);
+                            dav1d_memset_pow2[uv_t_dim->lh](&t->l.ccoef[pl][cby4 + y], 0x40);
+                        }
+                        dst += uv_t_dim->w * 4;
+                    }
+                    t->bx -= x << ss_hor;
+                }
+                t->by -= y << ss_ver;
+            }
+        }
+    }
+}
+
+int bytefn(dav1d_recon_b_inter)(Dav1dTaskContext *const t, const enum BlockSize bs,
+                                const Av1Block *const b)
+{
+    Dav1dTileState *const ts = t->ts;
+    const Dav1dFrameContext *const f = t->f;
+    const Dav1dDSPContext *const dsp = f->dsp;
+    const int bx4 = t->bx & 31, by4 = t->by & 31;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    const int cbx4 = bx4 >> ss_hor, cby4 = by4 >> ss_ver;
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+    const int bw4 = b_dim[0], bh4 = b_dim[1];
+    const int w4 = imin(bw4, f->bw - t->bx), h4 = imin(bh4, f->bh - t->by);
+    const int has_chroma = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400 &&
+                           (bw4 > ss_hor || t->bx & 1) &&
+                           (bh4 > ss_ver || t->by & 1);
+    const int chr_layout_idx = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I400 ? 0 :
+                               DAV1D_PIXEL_LAYOUT_I444 - f->cur.p.layout;
+    int res;
+
+    // prediction
+    const int cbh4 = (bh4 + ss_ver) >> ss_ver, cbw4 = (bw4 + ss_hor) >> ss_hor;
+    pixel *dst = ((pixel *) f->cur.data[0]) +
+        4 * (t->by * PXSTRIDE(f->cur.stride[0]) + t->bx);
+    const ptrdiff_t uvdstoff =
+        4 * ((t->bx >> ss_hor) + (t->by >> ss_ver) * PXSTRIDE(f->cur.stride[1]));
+    if (IS_KEY_OR_INTRA(f->frame_hdr)) {
+        // intrabc
+        assert(!f->frame_hdr->super_res.enabled);
+        res = mc(t, dst, NULL, f->cur.stride[0], bw4, bh4, t->bx, t->by, 0,
+                 b->mv[0], &f->sr_cur, 0 /* unused */, FILTER_2D_BILINEAR);
+        if (res) return res;
+        if (has_chroma) for (int pl = 1; pl < 3; pl++) {
+            res = mc(t, ((pixel *)f->cur.data[pl]) + uvdstoff, NULL, f->cur.stride[1],
+                     bw4 << (bw4 == ss_hor), bh4 << (bh4 == ss_ver),
+                     t->bx & ~ss_hor, t->by & ~ss_ver, pl, b->mv[0],
+                     &f->sr_cur, 0 /* unused */, FILTER_2D_BILINEAR);
+            if (res) return res;
+        }
+    } else if (b->comp_type == COMP_INTER_NONE) {
+        const Dav1dThreadPicture *const refp = &f->refp[b->ref[0]];
+        const enum Filter2d filter_2d = b->filter2d;
+
+        if (imin(bw4, bh4) > 1 &&
+            ((b->inter_mode == GLOBALMV && f->gmv_warp_allowed[b->ref[0]]) ||
+             (b->motion_mode == MM_WARP && t->warpmv.type > DAV1D_WM_TYPE_TRANSLATION)))
+        {
+            res = warp_affine(t, dst, NULL, f->cur.stride[0], b_dim, 0, refp,
+                              b->motion_mode == MM_WARP ? &t->warpmv :
+                                  &f->frame_hdr->gmv[b->ref[0]]);
+            if (res) return res;
+        } else {
+            res = mc(t, dst, NULL, f->cur.stride[0],
+                     bw4, bh4, t->bx, t->by, 0, b->mv[0], refp, b->ref[0], filter_2d);
+            if (res) return res;
+            if (b->motion_mode == MM_OBMC) {
+                res = obmc(t, dst, f->cur.stride[0], b_dim, 0, bx4, by4, w4, h4);
+                if (res) return res;
+            }
+        }
+        if (b->interintra_type) {
+            pixel *const tl_edge = bitfn(t->scratch.edge) + 32;
+            enum IntraPredMode m = b->interintra_mode == II_SMOOTH_PRED ?
+                                   SMOOTH_PRED : b->interintra_mode;
+            pixel *const tmp = bitfn(t->scratch.interintra);
+            int angle = 0;
+            const pixel *top_sb_edge = NULL;
+            if (!(t->by & (f->sb_step - 1))) {
+                top_sb_edge = f->ipred_edge[0];
+                const int sby = t->by >> f->sb_shift;
+                top_sb_edge += f->sb128w * 128 * (sby - 1);
+            }
+            m = bytefn(dav1d_prepare_intra_edges)(t->bx, t->bx > ts->tiling.col_start,
+                                                  t->by, t->by > ts->tiling.row_start,
+                                                  ts->tiling.col_end, ts->tiling.row_end,
+                                                  0, dst, f->cur.stride[0], top_sb_edge,
+                                                  m, &angle, bw4, bh4, 0, tl_edge
+                                                  HIGHBD_CALL_SUFFIX);
+            dsp->ipred.intra_pred[m](tmp, 4 * bw4 * sizeof(pixel),
+                                     tl_edge, bw4 * 4, bh4 * 4, 0, 0, 0
+                                     HIGHBD_CALL_SUFFIX);
+            dsp->mc.blend(dst, f->cur.stride[0], tmp,
+                          bw4 * 4, bh4 * 4, II_MASK(0, bs, b));
+        }
+
+        if (!has_chroma) goto skip_inter_chroma_pred;
+
+        // sub8x8 derivation
+        int is_sub8x8 = bw4 == ss_hor || bh4 == ss_ver;
+        refmvs_block *const *r;
+        if (is_sub8x8) {
+            assert(ss_hor == 1);
+            r = &t->rt.r[(t->by & 31) + 5];
+            if (bw4 == 1) is_sub8x8 &= r[0][t->bx - 1].ref.ref[0] > 0;
+            if (bh4 == ss_ver) is_sub8x8 &= r[-1][t->bx].ref.ref[0] > 0;
+            if (bw4 == 1 && bh4 == ss_ver)
+                is_sub8x8 &= r[-1][t->bx - 1].ref.ref[0] > 0;
+        }
+
+        // chroma prediction
+        if (is_sub8x8) {
+            assert(ss_hor == 1);
+            ptrdiff_t h_off = 0, v_off = 0;
+            if (bw4 == 1 && bh4 == ss_ver) {
+                for (int pl = 0; pl < 2; pl++) {
+                    res = mc(t, ((pixel *) f->cur.data[1 + pl]) + uvdstoff,
+                             NULL, f->cur.stride[1],
+                             bw4, bh4, t->bx - 1, t->by - 1, 1 + pl,
+                             r[-1][t->bx - 1].mv.mv[0],
+                             &f->refp[r[-1][t->bx - 1].ref.ref[0] - 1],
+                             r[-1][t->bx - 1].ref.ref[0] - 1,
+                             t->frame_thread.pass != 2 ? t->tl_4x4_filter :
+                                 f->frame_thread.b[((t->by - 1) * f->b4_stride) + t->bx - 1].filter2d);
+                    if (res) return res;
+                }
+                v_off = 2 * PXSTRIDE(f->cur.stride[1]);
+                h_off = 2;
+            }
+            if (bw4 == 1) {
+                const enum Filter2d left_filter_2d =
+                    dav1d_filter_2d[t->l.filter[1][by4]][t->l.filter[0][by4]];
+                for (int pl = 0; pl < 2; pl++) {
+                    res = mc(t, ((pixel *) f->cur.data[1 + pl]) + uvdstoff + v_off, NULL,
+                             f->cur.stride[1], bw4, bh4, t->bx - 1,
+                             t->by, 1 + pl, r[0][t->bx - 1].mv.mv[0],
+                             &f->refp[r[0][t->bx - 1].ref.ref[0] - 1],
+                             r[0][t->bx - 1].ref.ref[0] - 1,
+                             t->frame_thread.pass != 2 ? left_filter_2d :
+                                 f->frame_thread.b[(t->by * f->b4_stride) + t->bx - 1].filter2d);
+                    if (res) return res;
+                }
+                h_off = 2;
+            }
+            if (bh4 == ss_ver) {
+                const enum Filter2d top_filter_2d =
+                    dav1d_filter_2d[t->a->filter[1][bx4]][t->a->filter[0][bx4]];
+                for (int pl = 0; pl < 2; pl++) {
+                    res = mc(t, ((pixel *) f->cur.data[1 + pl]) + uvdstoff + h_off, NULL,
+                             f->cur.stride[1], bw4, bh4, t->bx, t->by - 1,
+                             1 + pl, r[-1][t->bx].mv.mv[0],
+                             &f->refp[r[-1][t->bx].ref.ref[0] - 1],
+                             r[-1][t->bx].ref.ref[0] - 1,
+                             t->frame_thread.pass != 2 ? top_filter_2d :
+                                 f->frame_thread.b[((t->by - 1) * f->b4_stride) + t->bx].filter2d);
+                    if (res) return res;
+                }
+                v_off = 2 * PXSTRIDE(f->cur.stride[1]);
+            }
+            for (int pl = 0; pl < 2; pl++) {
+                res = mc(t, ((pixel *) f->cur.data[1 + pl]) + uvdstoff + h_off + v_off, NULL, f->cur.stride[1],
+                         bw4, bh4, t->bx, t->by, 1 + pl, b->mv[0],
+                         refp, b->ref[0], filter_2d);
+                if (res) return res;
+            }
+        } else {
+            if (imin(cbw4, cbh4) > 1 &&
+                ((b->inter_mode == GLOBALMV && f->gmv_warp_allowed[b->ref[0]]) ||
+                 (b->motion_mode == MM_WARP && t->warpmv.type > DAV1D_WM_TYPE_TRANSLATION)))
+            {
+                for (int pl = 0; pl < 2; pl++) {
+                    res = warp_affine(t, ((pixel *) f->cur.data[1 + pl]) + uvdstoff, NULL,
+                                      f->cur.stride[1], b_dim, 1 + pl, refp,
+                                      b->motion_mode == MM_WARP ? &t->warpmv :
+                                          &f->frame_hdr->gmv[b->ref[0]]);
+                    if (res) return res;
+                }
+            } else {
+                for (int pl = 0; pl < 2; pl++) {
+                    res = mc(t, ((pixel *) f->cur.data[1 + pl]) + uvdstoff,
+                             NULL, f->cur.stride[1],
+                             bw4 << (bw4 == ss_hor), bh4 << (bh4 == ss_ver),
+                             t->bx & ~ss_hor, t->by & ~ss_ver,
+                             1 + pl, b->mv[0], refp, b->ref[0], filter_2d);
+                    if (res) return res;
+                    if (b->motion_mode == MM_OBMC) {
+                        res = obmc(t, ((pixel *) f->cur.data[1 + pl]) + uvdstoff,
+                                   f->cur.stride[1], b_dim, 1 + pl, bx4, by4, w4, h4);
+                        if (res) return res;
+                    }
+                }
+            }
+            if (b->interintra_type) {
+                // FIXME for 8x32 with 4:2:2 subsampling, this probably does
+                // the wrong thing since it will select 4x16, not 4x32, as a
+                // transform size...
+                const uint8_t *const ii_mask = II_MASK(chr_layout_idx, bs, b);
+
+                for (int pl = 0; pl < 2; pl++) {
+                    pixel *const tmp = bitfn(t->scratch.interintra);
+                    pixel *const tl_edge = bitfn(t->scratch.edge) + 32;
+                    enum IntraPredMode m =
+                        b->interintra_mode == II_SMOOTH_PRED ?
+                        SMOOTH_PRED : b->interintra_mode;
+                    int angle = 0;
+                    pixel *const uvdst = ((pixel *) f->cur.data[1 + pl]) + uvdstoff;
+                    const pixel *top_sb_edge = NULL;
+                    if (!(t->by & (f->sb_step - 1))) {
+                        top_sb_edge = f->ipred_edge[pl + 1];
+                        const int sby = t->by >> f->sb_shift;
+                        top_sb_edge += f->sb128w * 128 * (sby - 1);
+                    }
+                    m = bytefn(dav1d_prepare_intra_edges)(t->bx >> ss_hor,
+                                                          (t->bx >> ss_hor) >
+                                                              (ts->tiling.col_start >> ss_hor),
+                                                          t->by >> ss_ver,
+                                                          (t->by >> ss_ver) >
+                                                              (ts->tiling.row_start >> ss_ver),
+                                                          ts->tiling.col_end >> ss_hor,
+                                                          ts->tiling.row_end >> ss_ver,
+                                                          0, uvdst, f->cur.stride[1],
+                                                          top_sb_edge, m,
+                                                          &angle, cbw4, cbh4, 0, tl_edge
+                                                          HIGHBD_CALL_SUFFIX);
+                    dsp->ipred.intra_pred[m](tmp, cbw4 * 4 * sizeof(pixel),
+                                             tl_edge, cbw4 * 4, cbh4 * 4, 0, 0, 0
+                                             HIGHBD_CALL_SUFFIX);
+                    dsp->mc.blend(uvdst, f->cur.stride[1], tmp,
+                                  cbw4 * 4, cbh4 * 4, ii_mask);
+                }
+            }
+        }
+
+    skip_inter_chroma_pred: {}
+        t->tl_4x4_filter = filter_2d;
+    } else {
+        const enum Filter2d filter_2d = b->filter2d;
+        // Maximum super block size is 128x128
+        int16_t (*tmp)[128 * 128] = t->scratch.compinter;
+        int jnt_weight;
+        uint8_t *const seg_mask = t->scratch.seg_mask;
+        const uint8_t *mask;
+
+        for (int i = 0; i < 2; i++) {
+            const Dav1dThreadPicture *const refp = &f->refp[b->ref[i]];
+
+            if (b->inter_mode == GLOBALMV_GLOBALMV && f->gmv_warp_allowed[b->ref[i]]) {
+                res = warp_affine(t, NULL, tmp[i], bw4 * 4, b_dim, 0, refp,
+                                  &f->frame_hdr->gmv[b->ref[i]]);
+                if (res) return res;
+            } else {
+                res = mc(t, NULL, tmp[i], 0, bw4, bh4, t->bx, t->by, 0,
+                         b->mv[i], refp, b->ref[i], filter_2d);
+                if (res) return res;
+            }
+        }
+        switch (b->comp_type) {
+        case COMP_INTER_AVG:
+            dsp->mc.avg(dst, f->cur.stride[0], tmp[0], tmp[1],
+                        bw4 * 4, bh4 * 4 HIGHBD_CALL_SUFFIX);
+            break;
+        case COMP_INTER_WEIGHTED_AVG:
+            jnt_weight = f->jnt_weights[b->ref[0]][b->ref[1]];
+            dsp->mc.w_avg(dst, f->cur.stride[0], tmp[0], tmp[1],
+                          bw4 * 4, bh4 * 4, jnt_weight HIGHBD_CALL_SUFFIX);
+            break;
+        case COMP_INTER_SEG:
+            dsp->mc.w_mask[chr_layout_idx](dst, f->cur.stride[0],
+                                           tmp[b->mask_sign], tmp[!b->mask_sign],
+                                           bw4 * 4, bh4 * 4, seg_mask,
+                                           b->mask_sign HIGHBD_CALL_SUFFIX);
+            mask = seg_mask;
+            break;
+        case COMP_INTER_WEDGE:
+            mask = WEDGE_MASK(0, bs, 0, b->wedge_idx);
+            dsp->mc.mask(dst, f->cur.stride[0],
+                         tmp[b->mask_sign], tmp[!b->mask_sign],
+                         bw4 * 4, bh4 * 4, mask HIGHBD_CALL_SUFFIX);
+            if (has_chroma)
+                mask = WEDGE_MASK(chr_layout_idx, bs, b->mask_sign, b->wedge_idx);
+            break;
+        }
+
+        // chroma
+        if (has_chroma) for (int pl = 0; pl < 2; pl++) {
+            for (int i = 0; i < 2; i++) {
+                const Dav1dThreadPicture *const refp = &f->refp[b->ref[i]];
+                if (b->inter_mode == GLOBALMV_GLOBALMV &&
+                    imin(cbw4, cbh4) > 1 && f->gmv_warp_allowed[b->ref[i]])
+                {
+                    res = warp_affine(t, NULL, tmp[i], bw4 * 4 >> ss_hor,
+                                      b_dim, 1 + pl,
+                                      refp, &f->frame_hdr->gmv[b->ref[i]]);
+                    if (res) return res;
+                } else {
+                    res = mc(t, NULL, tmp[i], 0, bw4, bh4, t->bx, t->by,
+                             1 + pl, b->mv[i], refp, b->ref[i], filter_2d);
+                    if (res) return res;
+                }
+            }
+            pixel *const uvdst = ((pixel *) f->cur.data[1 + pl]) + uvdstoff;
+            switch (b->comp_type) {
+            case COMP_INTER_AVG:
+                dsp->mc.avg(uvdst, f->cur.stride[1], tmp[0], tmp[1],
+                            bw4 * 4 >> ss_hor, bh4 * 4 >> ss_ver
+                            HIGHBD_CALL_SUFFIX);
+                break;
+            case COMP_INTER_WEIGHTED_AVG:
+                dsp->mc.w_avg(uvdst, f->cur.stride[1], tmp[0], tmp[1],
+                              bw4 * 4 >> ss_hor, bh4 * 4 >> ss_ver, jnt_weight
+                              HIGHBD_CALL_SUFFIX);
+                break;
+            case COMP_INTER_WEDGE:
+            case COMP_INTER_SEG:
+                dsp->mc.mask(uvdst, f->cur.stride[1],
+                             tmp[b->mask_sign], tmp[!b->mask_sign],
+                             bw4 * 4 >> ss_hor, bh4 * 4 >> ss_ver, mask
+                             HIGHBD_CALL_SUFFIX);
+                break;
+            }
+        }
+    }
+
+    if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS) {
+        hex_dump(dst, f->cur.stride[0], b_dim[0] * 4, b_dim[1] * 4, "y-pred");
+        if (has_chroma) {
+            hex_dump(&((pixel *) f->cur.data[1])[uvdstoff], f->cur.stride[1],
+                     cbw4 * 4, cbh4 * 4, "u-pred");
+            hex_dump(&((pixel *) f->cur.data[2])[uvdstoff], f->cur.stride[1],
+                     cbw4 * 4, cbh4 * 4, "v-pred");
+        }
+    }
+
+    const int cw4 = (w4 + ss_hor) >> ss_hor, ch4 = (h4 + ss_ver) >> ss_ver;
+
+    if (b->skip) {
+        // reset coef contexts
+        BlockContext *const a = t->a;
+        dav1d_memset_pow2[b_dim[2]](&a->lcoef[bx4], 0x40);
+        dav1d_memset_pow2[b_dim[3]](&t->l.lcoef[by4], 0x40);
+        if (has_chroma) {
+            dav1d_memset_pow2_fn memset_cw = dav1d_memset_pow2[ulog2(cbw4)];
+            dav1d_memset_pow2_fn memset_ch = dav1d_memset_pow2[ulog2(cbh4)];
+            memset_cw(&a->ccoef[0][cbx4], 0x40);
+            memset_cw(&a->ccoef[1][cbx4], 0x40);
+            memset_ch(&t->l.ccoef[0][cby4], 0x40);
+            memset_ch(&t->l.ccoef[1][cby4], 0x40);
+        }
+        return 0;
+    }
+
+    const TxfmInfo *const uvtx = &dav1d_txfm_dimensions[b->uvtx];
+    const TxfmInfo *const ytx = &dav1d_txfm_dimensions[b->max_ytx];
+    const uint16_t tx_split[2] = { b->tx_split0, b->tx_split1 };
+
+    for (int init_y = 0; init_y < bh4; init_y += 16) {
+        for (int init_x = 0; init_x < bw4; init_x += 16) {
+            // coefficient coding & inverse transforms
+            int y_off = !!init_y, y;
+            dst += PXSTRIDE(f->cur.stride[0]) * 4 * init_y;
+            for (y = init_y, t->by += init_y; y < imin(h4, init_y + 16);
+                 y += ytx->h, y_off++)
+            {
+                int x, x_off = !!init_x;
+                for (x = init_x, t->bx += init_x; x < imin(w4, init_x + 16);
+                     x += ytx->w, x_off++)
+                {
+                    read_coef_tree(t, bs, b, b->max_ytx, 0, tx_split,
+                                   x_off, y_off, &dst[x * 4]);
+                    t->bx += ytx->w;
+                }
+                dst += PXSTRIDE(f->cur.stride[0]) * 4 * ytx->h;
+                t->bx -= x;
+                t->by += ytx->h;
+            }
+            dst -= PXSTRIDE(f->cur.stride[0]) * 4 * y;
+            t->by -= y;
+
+            // chroma coefs and inverse transform
+            if (has_chroma) for (int pl = 0; pl < 2; pl++) {
+                pixel *uvdst = ((pixel *) f->cur.data[1 + pl]) + uvdstoff +
+                    (PXSTRIDE(f->cur.stride[1]) * init_y * 4 >> ss_ver);
+                for (y = init_y >> ss_ver, t->by += init_y;
+                     y < imin(ch4, (init_y + 16) >> ss_ver); y += uvtx->h)
+                {
+                    int x;
+                    for (x = init_x >> ss_hor, t->bx += init_x;
+                         x < imin(cw4, (init_x + 16) >> ss_hor); x += uvtx->w)
+                    {
+                        coef *cf;
+                        int eob;
+                        enum TxfmType txtp;
+                        if (t->frame_thread.pass) {
+                            const int p = t->frame_thread.pass & 1;
+                            const int cbi = *ts->frame_thread[p].cbi++;
+                            cf = ts->frame_thread[p].cf;
+                            ts->frame_thread[p].cf += uvtx->w * uvtx->h * 16;
+                            eob  = cbi >> 5;
+                            txtp = cbi & 0x1f;
+                        } else {
+                            uint8_t cf_ctx;
+                            cf = bitfn(t->cf);
+                            txtp = t->scratch.txtp_map[(by4 + (y << ss_ver)) * 32 +
+                                                        bx4 + (x << ss_hor)];
+                            eob = decode_coefs(t, &t->a->ccoef[pl][cbx4 + x],
+                                               &t->l.ccoef[pl][cby4 + y],
+                                               b->uvtx, bs, b, 0, 1 + pl,
+                                               cf, &txtp, &cf_ctx);
+                            if (DEBUG_BLOCK_INFO)
+                                printf("Post-uv-cf-blk[pl=%d,tx=%d,"
+                                       "txtp=%d,eob=%d]: r=%d\n",
+                                       pl, b->uvtx, txtp, eob, ts->msac.rng);
+                            int ctw = imin(uvtx->w, (f->bw - t->bx + ss_hor) >> ss_hor);
+                            int cth = imin(uvtx->h, (f->bh - t->by + ss_ver) >> ss_ver);
+                            dav1d_memset_likely_pow2(&t->a->ccoef[pl][cbx4 + x], cf_ctx, ctw);
+                            dav1d_memset_likely_pow2(&t->l.ccoef[pl][cby4 + y], cf_ctx, cth);
+                        }
+                        if (eob >= 0) {
+                            if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                                coef_dump(cf, uvtx->h * 4, uvtx->w * 4, 3, "dq");
+                            dsp->itx.itxfm_add[b->uvtx]
+                                              [txtp](&uvdst[4 * x],
+                                                     f->cur.stride[1],
+                                                     cf, eob HIGHBD_CALL_SUFFIX);
+                            if (DEBUG_BLOCK_INFO && DEBUG_B_PIXELS)
+                                hex_dump(&uvdst[4 * x], f->cur.stride[1],
+                                         uvtx->w * 4, uvtx->h * 4, "recon");
+                        }
+                        t->bx += uvtx->w << ss_hor;
+                    }
+                    uvdst += PXSTRIDE(f->cur.stride[1]) * 4 * uvtx->h;
+                    t->bx -= x << ss_hor;
+                    t->by += uvtx->h << ss_ver;
+                }
+                t->by -= y << ss_ver;
+            }
+        }
+    }
+    return 0;
+}
+
+void bytefn(dav1d_filter_sbrow_deblock_cols)(Dav1dFrameContext *const f, const int sby) {
+    if (!(f->c->inloop_filters & DAV1D_INLOOPFILTER_DEBLOCK) ||
+        (!f->frame_hdr->loopfilter.level_y[0] && !f->frame_hdr->loopfilter.level_y[1]))
+    {
+        return;
+    }
+    const int y = sby * f->sb_step * 4;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    pixel *const p[3] = {
+        f->lf.p[0] + y * PXSTRIDE(f->cur.stride[0]),
+        f->lf.p[1] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver),
+        f->lf.p[2] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver)
+    };
+    Av1Filter *mask = f->lf.mask + (sby >> !f->seq_hdr->sb128) * f->sb128w;
+    bytefn(dav1d_loopfilter_sbrow_cols)(f, p, mask, sby,
+                                        f->lf.start_of_tile_row[sby]);
+}
+
+void bytefn(dav1d_filter_sbrow_deblock_rows)(Dav1dFrameContext *const f, const int sby) {
+    const int y = sby * f->sb_step * 4;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    pixel *const p[3] = {
+        f->lf.p[0] + y * PXSTRIDE(f->cur.stride[0]),
+        f->lf.p[1] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver),
+        f->lf.p[2] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver)
+    };
+    Av1Filter *mask = f->lf.mask + (sby >> !f->seq_hdr->sb128) * f->sb128w;
+    if (f->c->inloop_filters & DAV1D_INLOOPFILTER_DEBLOCK &&
+        (f->frame_hdr->loopfilter.level_y[0] || f->frame_hdr->loopfilter.level_y[1]))
+    {
+        bytefn(dav1d_loopfilter_sbrow_rows)(f, p, mask, sby);
+    }
+    if (f->seq_hdr->cdef || f->lf.restore_planes) {
+        // Store loop filtered pixels required by CDEF / LR
+        bytefn(dav1d_copy_lpf)(f, p, sby);
+    }
+}
+
+void bytefn(dav1d_filter_sbrow_cdef)(Dav1dTaskContext *const tc, const int sby) {
+    const Dav1dFrameContext *const f = tc->f;
+    if (!(f->c->inloop_filters & DAV1D_INLOOPFILTER_CDEF)) return;
+    const int sbsz = f->sb_step;
+    const int y = sby * sbsz * 4;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    pixel *const p[3] = {
+        f->lf.p[0] + y * PXSTRIDE(f->cur.stride[0]),
+        f->lf.p[1] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver),
+        f->lf.p[2] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver)
+    };
+    Av1Filter *prev_mask = f->lf.mask + ((sby - 1) >> !f->seq_hdr->sb128) * f->sb128w;
+    Av1Filter *mask = f->lf.mask + (sby >> !f->seq_hdr->sb128) * f->sb128w;
+    const int start = sby * sbsz;
+    if (sby) {
+        const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        pixel *p_up[3] = {
+            p[0] - 8 * PXSTRIDE(f->cur.stride[0]),
+            p[1] - (8 * PXSTRIDE(f->cur.stride[1]) >> ss_ver),
+            p[2] - (8 * PXSTRIDE(f->cur.stride[1]) >> ss_ver),
+        };
+        bytefn(dav1d_cdef_brow)(tc, p_up, prev_mask, start - 2, start, 1, sby);
+    }
+    const int n_blks = sbsz - 2 * (sby + 1 < f->sbh);
+    const int end = imin(start + n_blks, f->bh);
+    bytefn(dav1d_cdef_brow)(tc, p, mask, start, end, 0, sby);
+}
+
+void bytefn(dav1d_filter_sbrow_resize)(Dav1dFrameContext *const f, const int sby) {
+    const int sbsz = f->sb_step;
+    const int y = sby * sbsz * 4;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const pixel *const p[3] = {
+        f->lf.p[0] + y * PXSTRIDE(f->cur.stride[0]),
+        f->lf.p[1] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver),
+        f->lf.p[2] + (y * PXSTRIDE(f->cur.stride[1]) >> ss_ver)
+    };
+    pixel *const sr_p[3] = {
+        f->lf.sr_p[0] + y * PXSTRIDE(f->sr_cur.p.stride[0]),
+        f->lf.sr_p[1] + (y * PXSTRIDE(f->sr_cur.p.stride[1]) >> ss_ver),
+        f->lf.sr_p[2] + (y * PXSTRIDE(f->sr_cur.p.stride[1]) >> ss_ver)
+    };
+    const int has_chroma = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400;
+    for (int pl = 0; pl < 1 + 2 * has_chroma; pl++) {
+        const int ss_ver = pl && f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int h_start = 8 * !!sby >> ss_ver;
+        const ptrdiff_t dst_stride = f->sr_cur.p.stride[!!pl];
+        pixel *dst = sr_p[pl] - h_start * PXSTRIDE(dst_stride);
+        const ptrdiff_t src_stride = f->cur.stride[!!pl];
+        const pixel *src = p[pl] - h_start * PXSTRIDE(src_stride);
+        const int h_end = 4 * (sbsz - 2 * (sby + 1 < f->sbh)) >> ss_ver;
+        const int ss_hor = pl && f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int dst_w = (f->sr_cur.p.p.w + ss_hor) >> ss_hor;
+        const int src_w = (4 * f->bw + ss_hor) >> ss_hor;
+        const int img_h = (f->cur.p.h - sbsz * 4 * sby + ss_ver) >> ss_ver;
+
+        f->dsp->mc.resize(dst, dst_stride, src, src_stride, dst_w,
+                          imin(img_h, h_end) + h_start, src_w,
+                          f->resize_step[!!pl], f->resize_start[!!pl]
+                          HIGHBD_CALL_SUFFIX);
+    }
+}
+
+void bytefn(dav1d_filter_sbrow_lr)(Dav1dFrameContext *const f, const int sby) {
+    if (!(f->c->inloop_filters & DAV1D_INLOOPFILTER_RESTORATION)) return;
+    const int y = sby * f->sb_step * 4;
+    const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    pixel *const sr_p[3] = {
+        f->lf.sr_p[0] + y * PXSTRIDE(f->sr_cur.p.stride[0]),
+        f->lf.sr_p[1] + (y * PXSTRIDE(f->sr_cur.p.stride[1]) >> ss_ver),
+        f->lf.sr_p[2] + (y * PXSTRIDE(f->sr_cur.p.stride[1]) >> ss_ver)
+    };
+    bytefn(dav1d_lr_sbrow)(f, sr_p, sby);
+}
+
+void bytefn(dav1d_filter_sbrow)(Dav1dFrameContext *const f, const int sby) {
+    bytefn(dav1d_filter_sbrow_deblock_cols)(f, sby);
+    bytefn(dav1d_filter_sbrow_deblock_rows)(f, sby);
+    if (f->seq_hdr->cdef)
+        bytefn(dav1d_filter_sbrow_cdef)(f->c->tc, sby);
+    if (f->frame_hdr->width[0] != f->frame_hdr->width[1])
+        bytefn(dav1d_filter_sbrow_resize)(f, sby);
+    if (f->lf.restore_planes)
+        bytefn(dav1d_filter_sbrow_lr)(f, sby);
+}
+
+void bytefn(dav1d_backup_ipred_edge)(Dav1dTaskContext *const t) {
+    const Dav1dFrameContext *const f = t->f;
+    Dav1dTileState *const ts = t->ts;
+    const int sby = t->by >> f->sb_shift;
+    const int sby_off = f->sb128w * 128 * sby;
+    const int x_off = ts->tiling.col_start;
+
+    const pixel *const y =
+        ((const pixel *) f->cur.data[0]) + x_off * 4 +
+                    ((t->by + f->sb_step) * 4 - 1) * PXSTRIDE(f->cur.stride[0]);
+    pixel_copy(&f->ipred_edge[0][sby_off + x_off * 4], y,
+               4 * (ts->tiling.col_end - x_off));
+
+    if (f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I400) {
+        const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = f->cur.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+
+        const ptrdiff_t uv_off = (x_off * 4 >> ss_hor) +
+            (((t->by + f->sb_step) * 4 >> ss_ver) - 1) * PXSTRIDE(f->cur.stride[1]);
+        for (int pl = 1; pl <= 2; pl++)
+            pixel_copy(&f->ipred_edge[pl][sby_off + (x_off * 4 >> ss_hor)],
+                       &((const pixel *) f->cur.data[pl])[uv_off],
+                       4 * (ts->tiling.col_end - x_off) >> ss_hor);
+    }
+}
+
+void bytefn(dav1d_copy_pal_block_y)(Dav1dTaskContext *const t,
+                                    const int bx4, const int by4,
+                                    const int bw4, const int bh4)
+
+{
+    const Dav1dFrameContext *const f = t->f;
+    pixel *const pal = t->frame_thread.pass ?
+        f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) +
+                            ((t->bx >> 1) + (t->by & 1))][0] :
+        bytefn(t->scratch.pal)[0];
+    for (int x = 0; x < bw4; x++)
+        memcpy(bytefn(t->al_pal)[0][bx4 + x][0], pal, 8 * sizeof(pixel));
+    for (int y = 0; y < bh4; y++)
+        memcpy(bytefn(t->al_pal)[1][by4 + y][0], pal, 8 * sizeof(pixel));
+}
+
+void bytefn(dav1d_copy_pal_block_uv)(Dav1dTaskContext *const t,
+                                     const int bx4, const int by4,
+                                     const int bw4, const int bh4)
+
+{
+    const Dav1dFrameContext *const f = t->f;
+    const pixel (*const pal)[8] = t->frame_thread.pass ?
+        f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) +
+                            ((t->bx >> 1) + (t->by & 1))] :
+        bytefn(t->scratch.pal);
+    // see aomedia bug 2183 for why we use luma coordinates here
+    for (int pl = 1; pl <= 2; pl++) {
+        for (int x = 0; x < bw4; x++)
+            memcpy(bytefn(t->al_pal)[0][bx4 + x][pl], pal[pl], 8 * sizeof(pixel));
+        for (int y = 0; y < bh4; y++)
+            memcpy(bytefn(t->al_pal)[1][by4 + y][pl], pal[pl], 8 * sizeof(pixel));
+    }
+}
+
+void bytefn(dav1d_read_pal_plane)(Dav1dTaskContext *const t, Av1Block *const b,
+                                  const int pl, const int sz_ctx,
+                                  const int bx4, const int by4)
+{
+    Dav1dTileState *const ts = t->ts;
+    const Dav1dFrameContext *const f = t->f;
+    const int pal_sz = b->pal_sz[pl] = dav1d_msac_decode_symbol_adapt8(&ts->msac,
+                                           ts->cdf.m.pal_sz[pl][sz_ctx], 6) + 2;
+    pixel cache[16], used_cache[8];
+    int l_cache = pl ? t->pal_sz_uv[1][by4] : t->l.pal_sz[by4];
+    int n_cache = 0;
+    // don't reuse above palette outside SB64 boundaries
+    int a_cache = by4 & 15 ? pl ? t->pal_sz_uv[0][bx4] : t->a->pal_sz[bx4] : 0;
+    const pixel *l = bytefn(t->al_pal)[1][by4][pl];
+    const pixel *a = bytefn(t->al_pal)[0][bx4][pl];
+
+    // fill/sort cache
+    while (l_cache && a_cache) {
+        if (*l < *a) {
+            if (!n_cache || cache[n_cache - 1] != *l)
+                cache[n_cache++] = *l;
+            l++;
+            l_cache--;
+        } else {
+            if (*a == *l) {
+                l++;
+                l_cache--;
+            }
+            if (!n_cache || cache[n_cache - 1] != *a)
+                cache[n_cache++] = *a;
+            a++;
+            a_cache--;
+        }
+    }
+    if (l_cache) {
+        do {
+            if (!n_cache || cache[n_cache - 1] != *l)
+                cache[n_cache++] = *l;
+            l++;
+        } while (--l_cache > 0);
+    } else if (a_cache) {
+        do {
+            if (!n_cache || cache[n_cache - 1] != *a)
+                cache[n_cache++] = *a;
+            a++;
+        } while (--a_cache > 0);
+    }
+
+    // find reused cache entries
+    int i = 0;
+    for (int n = 0; n < n_cache && i < pal_sz; n++)
+        if (dav1d_msac_decode_bool_equi(&ts->msac))
+            used_cache[i++] = cache[n];
+    const int n_used_cache = i;
+
+    // parse new entries
+    pixel *const pal = t->frame_thread.pass ?
+        f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) +
+                            ((t->bx >> 1) + (t->by & 1))][pl] :
+        bytefn(t->scratch.pal)[pl];
+    if (i < pal_sz) {
+        const int bpc = BITDEPTH == 8 ? 8 : f->cur.p.bpc;
+        int prev = pal[i++] = dav1d_msac_decode_bools(&ts->msac, bpc);
+
+        if (i < pal_sz) {
+            int bits = bpc - 3 + dav1d_msac_decode_bools(&ts->msac, 2);
+            const int max = (1 << bpc) - 1;
+
+            do {
+                const int delta = dav1d_msac_decode_bools(&ts->msac, bits);
+                prev = pal[i++] = imin(prev + delta + !pl, max);
+                if (prev + !pl >= max) {
+                    for (; i < pal_sz; i++)
+                        pal[i] = max;
+                    break;
+                }
+                bits = imin(bits, 1 + ulog2(max - prev - !pl));
+            } while (i < pal_sz);
+        }
+
+        // merge cache+new entries
+        int n = 0, m = n_used_cache;
+        for (i = 0; i < pal_sz; i++) {
+            if (n < n_used_cache && (m >= pal_sz || used_cache[n] <= pal[m])) {
+                pal[i] = used_cache[n++];
+            } else {
+                assert(m < pal_sz);
+                pal[i] = pal[m++];
+            }
+        }
+    } else {
+        memcpy(pal, used_cache, n_used_cache * sizeof(*used_cache));
+    }
+
+    if (DEBUG_BLOCK_INFO) {
+        printf("Post-pal[pl=%d,sz=%d,cache_size=%d,used_cache=%d]: r=%d, cache=",
+               pl, pal_sz, n_cache, n_used_cache, ts->msac.rng);
+        for (int n = 0; n < n_cache; n++)
+            printf("%c%02x", n ? ' ' : '[', cache[n]);
+        printf("%s, pal=", n_cache ? "]" : "[]");
+        for (int n = 0; n < pal_sz; n++)
+            printf("%c%02x", n ? ' ' : '[', pal[n]);
+        printf("]\n");
+    }
+}
+
+void bytefn(dav1d_read_pal_uv)(Dav1dTaskContext *const t, Av1Block *const b,
+                               const int sz_ctx, const int bx4, const int by4)
+{
+    bytefn(dav1d_read_pal_plane)(t, b, 1, sz_ctx, bx4, by4);
+
+    // V pal coding
+    Dav1dTileState *const ts = t->ts;
+    const Dav1dFrameContext *const f = t->f;
+    pixel *const pal = t->frame_thread.pass ?
+        f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) +
+                            ((t->bx >> 1) + (t->by & 1))][2] :
+        bytefn(t->scratch.pal)[2];
+    const int bpc = BITDEPTH == 8 ? 8 : f->cur.p.bpc;
+    if (dav1d_msac_decode_bool_equi(&ts->msac)) {
+        const int bits = bpc - 4 + dav1d_msac_decode_bools(&ts->msac, 2);
+        int prev = pal[0] = dav1d_msac_decode_bools(&ts->msac, bpc);
+        const int max = (1 << bpc) - 1;
+        for (int i = 1; i < b->pal_sz[1]; i++) {
+            int delta = dav1d_msac_decode_bools(&ts->msac, bits);
+            if (delta && dav1d_msac_decode_bool_equi(&ts->msac)) delta = -delta;
+            prev = pal[i] = (prev + delta) & max;
+        }
+    } else {
+        for (int i = 0; i < b->pal_sz[1]; i++)
+            pal[i] = dav1d_msac_decode_bools(&ts->msac, bpc);
+    }
+    if (DEBUG_BLOCK_INFO) {
+        printf("Post-pal[pl=2]: r=%d ", ts->msac.rng);
+        for (int n = 0; n < b->pal_sz[1]; n++)
+            printf("%c%02x", n ? ' ' : '[', pal[n]);
+        printf("]\n");
+    }
+}
diff --git a/media/libdav1d/src/src/ref.c b/media/libdav1d/src/src/ref.c
new file mode 100644
index 0000000000..5a4d3a2457
--- /dev/null
+++ b/media/libdav1d/src/src/ref.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "src/ref.h"
+
+static void default_free_callback(const uint8_t *const data, void *const user_data) {
+    assert(data == user_data);
+    dav1d_free_aligned(user_data);
+}
+
+Dav1dRef *dav1d_ref_create(const enum AllocationType type, size_t size) {
+    size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+
+    uint8_t *const data = dav1d_alloc_aligned(type, size + sizeof(Dav1dRef), 64);
+    if (!data) return NULL;
+
+    Dav1dRef *const res = (Dav1dRef*)(data + size);
+    res->const_data = res->user_data = res->data = data;
+    atomic_init(&res->ref_cnt, 1);
+    res->free_ref = 0;
+    res->free_callback = default_free_callback;
+
+    return res;
+}
+
+static void pool_free_callback(const uint8_t *const data, void *const user_data) {
+    dav1d_mem_pool_push((Dav1dMemPool*)data, user_data);
+}
+
+Dav1dRef *dav1d_ref_create_using_pool(Dav1dMemPool *const pool, size_t size) {
+    size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+
+    Dav1dMemPoolBuffer *const buf =
+        dav1d_mem_pool_pop(pool, size + sizeof(Dav1dRef));
+    if (!buf) return NULL;
+
+    Dav1dRef *const res = &((Dav1dRef*)buf)[-1];
+    res->data = buf->data;
+    res->const_data = pool;
+    atomic_init(&res->ref_cnt, 1);
+    res->free_ref = 0;
+    res->free_callback = pool_free_callback;
+    res->user_data = buf;
+
+    return res;
+}
+
+void dav1d_ref_dec(Dav1dRef **const pref) {
+    assert(pref != NULL);
+
+    Dav1dRef *const ref = *pref;
+    if (!ref) return;
+
+    *pref = NULL;
+    if (atomic_fetch_sub(&ref->ref_cnt, 1) == 1) {
+        const int free_ref = ref->free_ref;
+        ref->free_callback(ref->const_data, ref->user_data);
+        if (free_ref) dav1d_free(ref);
+    }
+}
diff --git a/media/libdav1d/src/src/ref.h b/media/libdav1d/src/src/ref.h
new file mode 100644
index 0000000000..f1c96eb914
--- /dev/null
+++ b/media/libdav1d/src/src/ref.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_REF_H
+#define DAV1D_SRC_REF_H
+
+#include "dav1d/dav1d.h"
+
+#include "src/mem.h"
+#include "src/thread.h"
+
+#include 
+#include 
+
+struct Dav1dRef {
+    void *data;
+    const void *const_data;
+    atomic_int ref_cnt;
+    int free_ref;
+    void (*free_callback)(const uint8_t *data, void *user_data);
+    void *user_data;
+};
+
+#if !TRACK_HEAP_ALLOCATIONS
+#define dav1d_ref_create(type, size) dav1d_ref_create(size)
+#endif
+
+Dav1dRef *dav1d_ref_create(enum AllocationType type, size_t size);
+Dav1dRef *dav1d_ref_create_using_pool(Dav1dMemPool *pool, size_t size);
+void dav1d_ref_dec(Dav1dRef **ref);
+
+static inline Dav1dRef *dav1d_ref_init(Dav1dRef *const ref, const void *const ptr,
+                                       void (*const free_callback)(const uint8_t *data, void *user_data),
+                                       void *const user_data, const int free_ref)
+{
+    ref->data = NULL;
+    ref->const_data = ptr;
+    atomic_init(&ref->ref_cnt, 1);
+    ref->free_ref = free_ref;
+    ref->free_callback = free_callback;
+    ref->user_data = user_data;
+    return ref;
+}
+
+static inline void dav1d_ref_inc(Dav1dRef *const ref) {
+    atomic_fetch_add_explicit(&ref->ref_cnt, 1, memory_order_relaxed);
+}
+
+static inline int dav1d_ref_is_writable(Dav1dRef *const ref) {
+    return atomic_load(&ref->ref_cnt) == 1 && ref->data;
+}
+
+#endif /* DAV1D_SRC_REF_H */
diff --git a/media/libdav1d/src/src/refmvs.c b/media/libdav1d/src/src/refmvs.c
new file mode 100644
index 0000000000..ac86c92e08
--- /dev/null
+++ b/media/libdav1d/src/src/refmvs.c
@@ -0,0 +1,935 @@
+/*
+ * Copyright © 2020, VideoLAN and dav1d authors
+ * Copyright © 2020, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "dav1d/common.h"
+
+#include "common/intops.h"
+
+#include "src/env.h"
+#include "src/mem.h"
+#include "src/refmvs.h"
+
+static void add_spatial_candidate(refmvs_candidate *const mvstack, int *const cnt,
+                                  const int weight, const refmvs_block *const b,
+                                  const union refmvs_refpair ref, const mv gmv[2],
+                                  int *const have_newmv_match,
+                                  int *const have_refmv_match)
+{
+    if (b->mv.mv[0].n == INVALID_MV) return; // intra block, no intrabc
+
+    if (ref.ref[1] == -1) {
+        for (int n = 0; n < 2; n++) {
+            if (b->ref.ref[n] == ref.ref[0]) {
+                const mv cand_mv = ((b->mf & 1) && gmv[0].n != INVALID_MV) ?
+                                   gmv[0] : b->mv.mv[n];
+
+                *have_refmv_match = 1;
+                *have_newmv_match |= b->mf >> 1;
+
+                const int last = *cnt;
+                for (int m = 0; m < last; m++)
+                    if (mvstack[m].mv.mv[0].n == cand_mv.n) {
+                        mvstack[m].weight += weight;
+                        return;
+                    }
+
+                if (last < 8) {
+                    mvstack[last].mv.mv[0] = cand_mv;
+                    mvstack[last].weight = weight;
+                    *cnt = last + 1;
+                }
+                return;
+            }
+        }
+    } else if (b->ref.pair == ref.pair) {
+        const refmvs_mvpair cand_mv = { .mv = {
+            [0] = ((b->mf & 1) && gmv[0].n != INVALID_MV) ? gmv[0] : b->mv.mv[0],
+            [1] = ((b->mf & 1) && gmv[1].n != INVALID_MV) ? gmv[1] : b->mv.mv[1],
+        }};
+
+        *have_refmv_match = 1;
+        *have_newmv_match |= b->mf >> 1;
+
+        const int last = *cnt;
+        for (int n = 0; n < last; n++)
+            if (mvstack[n].mv.n == cand_mv.n) {
+                mvstack[n].weight += weight;
+                return;
+            }
+
+        if (last < 8) {
+            mvstack[last].mv = cand_mv;
+            mvstack[last].weight = weight;
+            *cnt = last + 1;
+        }
+    }
+}
+
+static int scan_row(refmvs_candidate *const mvstack, int *const cnt,
+                    const union refmvs_refpair ref, const mv gmv[2],
+                    const refmvs_block *b, const int bw4, const int w4,
+                    const int max_rows, const int step,
+                    int *const have_newmv_match, int *const have_refmv_match)
+{
+    const refmvs_block *cand_b = b;
+    const enum BlockSize first_cand_bs = cand_b->bs;
+    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
+    int cand_bw4 = first_cand_b_dim[0];
+    int len = imax(step, imin(bw4, cand_bw4));
+
+    if (bw4 <= cand_bw4) {
+        // FIXME weight can be higher for odd blocks (bx4 & 1), but then the
+        // position of the first block has to be odd already, i.e. not just
+        // for row_offset=-3/-5
+        // FIXME why can this not be cand_bw4?
+        const int weight = bw4 == 1 ? 2 :
+                           imax(2, imin(2 * max_rows, first_cand_b_dim[1]));
+        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
+                              have_newmv_match, have_refmv_match);
+        return weight >> 1;
+    }
+
+    for (int x = 0;;) {
+        // FIXME if we overhang above, we could fill a bitmask so we don't have
+        // to repeat the add_spatial_candidate() for the next row, but just increase
+        // the weight here
+        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
+                              have_newmv_match, have_refmv_match);
+        x += len;
+        if (x >= w4) return 1;
+        cand_b = &b[x];
+        cand_bw4 = dav1d_block_dimensions[cand_b->bs][0];
+        assert(cand_bw4 < bw4);
+        len = imax(step, cand_bw4);
+    }
+}
+
+static int scan_col(refmvs_candidate *const mvstack, int *const cnt,
+                    const union refmvs_refpair ref, const mv gmv[2],
+                    /*const*/ refmvs_block *const *b, const int bh4, const int h4,
+                    const int bx4, const int max_cols, const int step,
+                    int *const have_newmv_match, int *const have_refmv_match)
+{
+    const refmvs_block *cand_b = &b[0][bx4];
+    const enum BlockSize first_cand_bs = cand_b->bs;
+    const uint8_t *const first_cand_b_dim = dav1d_block_dimensions[first_cand_bs];
+    int cand_bh4 = first_cand_b_dim[1];
+    int len = imax(step, imin(bh4, cand_bh4));
+
+    if (bh4 <= cand_bh4) {
+        // FIXME weight can be higher for odd blocks (by4 & 1), but then the
+        // position of the first block has to be odd already, i.e. not just
+        // for col_offset=-3/-5
+        // FIXME why can this not be cand_bh4?
+        const int weight = bh4 == 1 ? 2 :
+                           imax(2, imin(2 * max_cols, first_cand_b_dim[0]));
+        add_spatial_candidate(mvstack, cnt, len * weight, cand_b, ref, gmv,
+                            have_newmv_match, have_refmv_match);
+        return weight >> 1;
+    }
+
+    for (int y = 0;;) {
+        // FIXME if we overhang above, we could fill a bitmask so we don't have
+        // to repeat the add_spatial_candidate() for the next row, but just increase
+        // the weight here
+        add_spatial_candidate(mvstack, cnt, len * 2, cand_b, ref, gmv,
+                              have_newmv_match, have_refmv_match);
+        y += len;
+        if (y >= h4) return 1;
+        cand_b = &b[y][bx4];
+        cand_bh4 = dav1d_block_dimensions[cand_b->bs][1];
+        assert(cand_bh4 < bh4);
+        len = imax(step, cand_bh4);
+    }
+}
+
+static inline union mv mv_projection(const union mv mv, const int num, const int den) {
+    static const uint16_t div_mult[32] = {
+           0, 16384, 8192, 5461, 4096, 3276, 2730, 2340,
+        2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092,
+        1024,   963,  910,  862,  819,  780,  744,  712,
+         682,   655,  630,  606,  585,  564,  546,  528
+    };
+    assert(den > 0 && den < 32);
+    assert(num > -32 && num < 32);
+    const int frac = num * div_mult[den];
+    const int y = mv.y * frac, x = mv.x * frac;
+    // Round and clip according to AV1 spec section 7.9.3
+    return (union mv) { // 0x3fff == (1 << 14) - 1
+        .y = iclip((y + 8192 + (y >> 31)) >> 14, -0x3fff, 0x3fff),
+        .x = iclip((x + 8192 + (x >> 31)) >> 14, -0x3fff, 0x3fff)
+    };
+}
+
+static void add_temporal_candidate(const refmvs_frame *const rf,
+                                   refmvs_candidate *const mvstack, int *const cnt,
+                                   const refmvs_temporal_block *const rb,
+                                   const union refmvs_refpair ref, int *const globalmv_ctx,
+                                   const union mv gmv[])
+{
+    if (rb->mv.n == INVALID_MV) return;
+
+    union mv mv = mv_projection(rb->mv, rf->pocdiff[ref.ref[0] - 1], rb->ref);
+    fix_mv_precision(rf->frm_hdr, &mv);
+
+    const int last = *cnt;
+    if (ref.ref[1] == -1) {
+        if (globalmv_ctx)
+            *globalmv_ctx = (abs(mv.x - gmv[0].x) | abs(mv.y - gmv[0].y)) >= 16;
+
+        for (int n = 0; n < last; n++)
+            if (mvstack[n].mv.mv[0].n == mv.n) {
+                mvstack[n].weight += 2;
+                return;
+            }
+        if (last < 8) {
+            mvstack[last].mv.mv[0] = mv;
+            mvstack[last].weight = 2;
+            *cnt = last + 1;
+        }
+    } else {
+        refmvs_mvpair mvp = { .mv = {
+            [0] = mv,
+            [1] = mv_projection(rb->mv, rf->pocdiff[ref.ref[1] - 1], rb->ref),
+        }};
+        fix_mv_precision(rf->frm_hdr, &mvp.mv[1]);
+
+        for (int n = 0; n < last; n++)
+            if (mvstack[n].mv.n == mvp.n) {
+                mvstack[n].weight += 2;
+                return;
+            }
+        if (last < 8) {
+            mvstack[last].mv = mvp;
+            mvstack[last].weight = 2;
+            *cnt = last + 1;
+        }
+    }
+}
+
+static void add_compound_extended_candidate(refmvs_candidate *const same,
+                                            int *const same_count,
+                                            const refmvs_block *const cand_b,
+                                            const int sign0, const int sign1,
+                                            const union refmvs_refpair ref,
+                                            const uint8_t *const sign_bias)
+{
+    refmvs_candidate *const diff = &same[2];
+    int *const diff_count = &same_count[2];
+
+    for (int n = 0; n < 2; n++) {
+        const int cand_ref = cand_b->ref.ref[n];
+
+        if (cand_ref <= 0) break;
+
+        mv cand_mv = cand_b->mv.mv[n];
+        if (cand_ref == ref.ref[0]) {
+            if (same_count[0] < 2)
+                same[same_count[0]++].mv.mv[0] = cand_mv;
+            if (diff_count[1] < 2) {
+                if (sign1 ^ sign_bias[cand_ref - 1]) {
+                    cand_mv.y = -cand_mv.y;
+                    cand_mv.x = -cand_mv.x;
+                }
+                diff[diff_count[1]++].mv.mv[1] = cand_mv;
+            }
+        } else if (cand_ref == ref.ref[1]) {
+            if (same_count[1] < 2)
+                same[same_count[1]++].mv.mv[1] = cand_mv;
+            if (diff_count[0] < 2) {
+                if (sign0 ^ sign_bias[cand_ref - 1]) {
+                    cand_mv.y = -cand_mv.y;
+                    cand_mv.x = -cand_mv.x;
+                }
+                diff[diff_count[0]++].mv.mv[0] = cand_mv;
+            }
+        } else {
+            mv i_cand_mv = (union mv) {
+                .x = -cand_mv.x,
+                .y = -cand_mv.y
+            };
+
+            if (diff_count[0] < 2) {
+                diff[diff_count[0]++].mv.mv[0] =
+                    sign0 ^ sign_bias[cand_ref - 1] ?
+                    i_cand_mv : cand_mv;
+            }
+
+            if (diff_count[1] < 2) {
+                diff[diff_count[1]++].mv.mv[1] =
+                    sign1 ^ sign_bias[cand_ref - 1] ?
+                    i_cand_mv : cand_mv;
+            }
+        }
+    }
+}
+
+static void add_single_extended_candidate(refmvs_candidate mvstack[8], int *const cnt,
+                                          const refmvs_block *const cand_b,
+                                          const int sign, const uint8_t *const sign_bias)
+{
+    for (int n = 0; n < 2; n++) {
+        const int cand_ref = cand_b->ref.ref[n];
+
+        if (cand_ref <= 0) break;
+        // we need to continue even if cand_ref == ref.ref[0], since
+        // the candidate could have been added as a globalmv variant,
+        // which changes the value
+        // FIXME if scan_{row,col}() returned a mask for the nearest
+        // edge, we could skip the appropriate ones here
+
+        mv cand_mv = cand_b->mv.mv[n];
+        if (sign ^ sign_bias[cand_ref - 1]) {
+            cand_mv.y = -cand_mv.y;
+            cand_mv.x = -cand_mv.x;
+        }
+
+        int m;
+        const int last = *cnt;
+        for (m = 0; m < last; m++)
+            if (cand_mv.n == mvstack[m].mv.mv[0].n)
+                break;
+        if (m == last) {
+            mvstack[m].mv.mv[0] = cand_mv;
+            mvstack[m].weight = 2; // "minimal"
+            *cnt = last + 1;
+        }
+    }
+}
+
+/*
+ * refmvs_frame allocates memory for one sbrow (32 blocks high, whole frame
+ * wide) of 4x4-resolution refmvs_block entries for spatial MV referencing.
+ * mvrefs_tile[] keeps a list of 35 (32 + 3 above) pointers into this memory,
+ * and each sbrow, the bottom entries (y=27/29/31) are exchanged with the top
+ * (-5/-3/-1) pointers by calling dav1d_refmvs_tile_sbrow_init() at the start
+ * of each tile/sbrow.
+ *
+ * For temporal MV referencing, we call dav1d_refmvs_save_tmvs() at the end of
+ * each tile/sbrow (when tile column threading is enabled), or at the start of
+ * each interleaved sbrow (i.e. once for all tile columns together, when tile
+ * column threading is disabled). This will copy the 4x4-resolution spatial MVs
+ * into 8x8-resolution refmvs_temporal_block structures. Then, for subsequent
+ * frames, at the start of each tile/sbrow (when tile column threading is
+ * enabled) or at the start of each interleaved sbrow (when tile column
+ * threading is disabled), we call load_tmvs(), which will project the MVs to
+ * their respective position in the current frame.
+ */
+
+void dav1d_refmvs_find(const refmvs_tile *const rt,
+                       refmvs_candidate mvstack[8], int *const cnt,
+                       int *const ctx,
+                       const union refmvs_refpair ref, const enum BlockSize bs,
+                       const enum EdgeFlags edge_flags,
+                       const int by4, const int bx4)
+{
+    const refmvs_frame *const rf = rt->rf;
+    const uint8_t *const b_dim = dav1d_block_dimensions[bs];
+    const int bw4 = b_dim[0], w4 = imin(imin(bw4, 16), rt->tile_col.end - bx4);
+    const int bh4 = b_dim[1], h4 = imin(imin(bh4, 16), rt->tile_row.end - by4);
+    mv gmv[2], tgmv[2];
+
+    *cnt = 0;
+    assert(ref.ref[0] >=  0 && ref.ref[0] <= 8 &&
+           ref.ref[1] >= -1 && ref.ref[1] <= 8);
+    if (ref.ref[0] > 0) {
+        tgmv[0] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[0] - 1],
+                             bx4, by4, bw4, bh4, rf->frm_hdr);
+        gmv[0] = rf->frm_hdr->gmv[ref.ref[0] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
+                 tgmv[0] : (mv) { .n = INVALID_MV };
+    } else {
+        tgmv[0] = (mv) { .n = 0 };
+        gmv[0] = (mv) { .n = INVALID_MV };
+    }
+    if (ref.ref[1] > 0) {
+        tgmv[1] = get_gmv_2d(&rf->frm_hdr->gmv[ref.ref[1] - 1],
+                             bx4, by4, bw4, bh4, rf->frm_hdr);
+        gmv[1] = rf->frm_hdr->gmv[ref.ref[1] - 1].type > DAV1D_WM_TYPE_TRANSLATION ?
+                 tgmv[1] : (mv) { .n = INVALID_MV };
+    }
+
+    // top
+    int have_newmv = 0, have_col_mvs = 0, have_row_mvs = 0;
+    unsigned max_rows = 0, n_rows = ~0;
+    const refmvs_block *b_top;
+    if (by4 > rt->tile_row.start) {
+        max_rows = imin((by4 - rt->tile_row.start + 1) >> 1, 2 + (bh4 > 1));
+        b_top = &rt->r[(by4 & 31) - 1 + 5][bx4];
+        n_rows = scan_row(mvstack, cnt, ref, gmv, b_top,
+                          bw4, w4, max_rows, bw4 >= 16 ? 4 : 1,
+                          &have_newmv, &have_row_mvs);
+    }
+
+    // left
+    unsigned max_cols = 0, n_cols = ~0U;
+    refmvs_block *const *b_left;
+    if (bx4 > rt->tile_col.start) {
+        max_cols = imin((bx4 - rt->tile_col.start + 1) >> 1, 2 + (bw4 > 1));
+        b_left = &rt->r[(by4 & 31) + 5];
+        n_cols = scan_col(mvstack, cnt, ref, gmv, b_left,
+                          bh4, h4, bx4 - 1, max_cols, bh4 >= 16 ? 4 : 1,
+                          &have_newmv, &have_col_mvs);
+    }
+
+    // top/right
+    if (n_rows != ~0U && edge_flags & EDGE_I444_TOP_HAS_RIGHT &&
+        imax(bw4, bh4) <= 16 && bw4 + bx4 < rt->tile_col.end)
+    {
+        add_spatial_candidate(mvstack, cnt, 4, &b_top[bw4], ref, gmv,
+                              &have_newmv, &have_row_mvs);
+    }
+
+    const int nearest_match = have_col_mvs + have_row_mvs;
+    const int nearest_cnt = *cnt;
+    for (int n = 0; n < nearest_cnt; n++)
+        mvstack[n].weight += 640;
+
+    // temporal
+    int globalmv_ctx = rf->frm_hdr->use_ref_frame_mvs;
+    if (rf->use_ref_frame_mvs) {
+        const ptrdiff_t stride = rf->rp_stride;
+        const int by8 = by4 >> 1, bx8 = bx4 >> 1;
+        const refmvs_temporal_block *const rbi = &rt->rp_proj[(by8 & 15) * stride + bx8];
+        const refmvs_temporal_block *rb = rbi;
+        const int step_h = bw4 >= 16 ? 2 : 1, step_v = bh4 >= 16 ? 2 : 1;
+        const int w8 = imin((w4 + 1) >> 1, 8), h8 = imin((h4 + 1) >> 1, 8);
+        for (int y = 0; y < h8; y += step_v) {
+            for (int x = 0; x < w8; x+= step_h) {
+                add_temporal_candidate(rf, mvstack, cnt, &rb[x], ref,
+                                       !(x | y) ? &globalmv_ctx : NULL, tgmv);
+            }
+            rb += stride * step_v;
+        }
+        if (imin(bw4, bh4) >= 2 && imax(bw4, bh4) < 16) {
+            const int bh8 = bh4 >> 1, bw8 = bw4 >> 1;
+            rb = &rbi[bh8 * stride];
+            const int has_bottom = by8 + bh8 < imin(rt->tile_row.end >> 1,
+                                                    (by8 & ~7) + 8);
+            if (has_bottom && bx8 - 1 >= imax(rt->tile_col.start >> 1, bx8 & ~7)) {
+                add_temporal_candidate(rf, mvstack, cnt, &rb[-1], ref,
+                                       NULL, NULL);
+            }
+            if (bx8 + bw8 < imin(rt->tile_col.end >> 1, (bx8 & ~7) + 8)) {
+                if (has_bottom) {
+                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8], ref,
+                                           NULL, NULL);
+                }
+                if (by8 + bh8 - 1 < imin(rt->tile_row.end >> 1, (by8 & ~7) + 8)) {
+                    add_temporal_candidate(rf, mvstack, cnt, &rb[bw8 - stride],
+                                           ref, NULL, NULL);
+                }
+            }
+        }
+    }
+    assert(*cnt <= 8);
+
+    // top/left (which, confusingly, is part of "secondary" references)
+    int have_dummy_newmv_match;
+    if ((n_rows | n_cols) != ~0U) {
+        add_spatial_candidate(mvstack, cnt, 4, &b_top[-1], ref, gmv,
+                              &have_dummy_newmv_match, &have_row_mvs);
+    }
+
+    // "secondary" (non-direct neighbour) top & left edges
+    // what is different about secondary is that everything is now in 8x8 resolution
+    for (int n = 2; n <= 3; n++) {
+        if ((unsigned) n > n_rows && (unsigned) n <= max_rows) {
+            n_rows += scan_row(mvstack, cnt, ref, gmv,
+                               &rt->r[(((by4 & 31) - 2 * n + 1) | 1) + 5][bx4 | 1],
+                               bw4, w4, 1 + max_rows - n, bw4 >= 16 ? 4 : 2,
+                               &have_dummy_newmv_match, &have_row_mvs);
+        }
+
+        if ((unsigned) n > n_cols && (unsigned) n <= max_cols) {
+            n_cols += scan_col(mvstack, cnt, ref, gmv, &rt->r[((by4 & 31) | 1) + 5],
+                               bh4, h4, (bx4 - n * 2 + 1) | 1,
+                               1 + max_cols - n, bh4 >= 16 ? 4 : 2,
+                               &have_dummy_newmv_match, &have_col_mvs);
+        }
+    }
+    assert(*cnt <= 8);
+
+    const int ref_match_count = have_col_mvs + have_row_mvs;
+
+    // context build-up
+    int refmv_ctx, newmv_ctx;
+    switch (nearest_match) {
+    case 0:
+        refmv_ctx = imin(2, ref_match_count);
+        newmv_ctx = ref_match_count > 0;
+        break;
+    case 1:
+        refmv_ctx = imin(ref_match_count * 3, 4);
+        newmv_ctx = 3 - have_newmv;
+        break;
+    case 2:
+        refmv_ctx = 5;
+        newmv_ctx = 5 - have_newmv;
+        break;
+    }
+
+    // sorting (nearest, then "secondary")
+    int len = nearest_cnt;
+    while (len) {
+        int last = 0;
+        for (int n = 1; n < len; n++) {
+            if (mvstack[n - 1].weight < mvstack[n].weight) {
+#define EXCHANGE(a, b) do { refmvs_candidate tmp = a; a = b; b = tmp; } while (0)
+                EXCHANGE(mvstack[n - 1], mvstack[n]);
+                last = n;
+            }
+        }
+        len = last;
+    }
+    len = *cnt;
+    while (len > nearest_cnt) {
+        int last = nearest_cnt;
+        for (int n = nearest_cnt + 1; n < len; n++) {
+            if (mvstack[n - 1].weight < mvstack[n].weight) {
+                EXCHANGE(mvstack[n - 1], mvstack[n]);
+#undef EXCHANGE
+                last = n;
+            }
+        }
+        len = last;
+    }
+
+    if (ref.ref[1] > 0) {
+        if (*cnt < 2) {
+            const int sign0 = rf->sign_bias[ref.ref[0] - 1];
+            const int sign1 = rf->sign_bias[ref.ref[1] - 1];
+            const int sz4 = imin(w4, h4);
+            refmvs_candidate *const same = &mvstack[*cnt];
+            int same_count[4] = { 0 };
+
+            // non-self references in top
+            if (n_rows != ~0U) for (int x = 0; x < sz4;) {
+                const refmvs_block *const cand_b = &b_top[x];
+                add_compound_extended_candidate(same, same_count, cand_b,
+                                                sign0, sign1, ref, rf->sign_bias);
+                x += dav1d_block_dimensions[cand_b->bs][0];
+            }
+
+            // non-self references in left
+            if (n_cols != ~0U) for (int y = 0; y < sz4;) {
+                const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
+                add_compound_extended_candidate(same, same_count, cand_b,
+                                                sign0, sign1, ref, rf->sign_bias);
+                y += dav1d_block_dimensions[cand_b->bs][1];
+            }
+
+            refmvs_candidate *const diff = &same[2];
+            const int *const diff_count = &same_count[2];
+
+            // merge together
+            for (int n = 0; n < 2; n++) {
+                int m = same_count[n];
+
+                if (m >= 2) continue;
+
+                const int l = diff_count[n];
+                if (l) {
+                    same[m].mv.mv[n] = diff[0].mv.mv[n];
+                    if (++m == 2) continue;
+                    if (l == 2) {
+                        same[1].mv.mv[n] = diff[1].mv.mv[n];
+                        continue;
+                    }
+                }
+                do {
+                    same[m].mv.mv[n] = tgmv[n];
+                } while (++m < 2);
+            }
+
+            // if the first extended was the same as the non-extended one,
+            // then replace it with the second extended one
+            int n = *cnt;
+            if (n == 1 && mvstack[0].mv.n == same[0].mv.n)
+                mvstack[1].mv = mvstack[2].mv;
+            do {
+                mvstack[n].weight = 2;
+            } while (++n < 2);
+            *cnt = 2;
+        }
+
+        // clamping
+        const int left = -(bx4 + bw4 + 4) * 4 * 8;
+        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
+        const int top = -(by4 + bh4 + 4) * 4 * 8;
+        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
+
+        const int n_refmvs = *cnt;
+        int n = 0;
+        do {
+            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
+            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
+            mvstack[n].mv.mv[1].x = iclip(mvstack[n].mv.mv[1].x, left, right);
+            mvstack[n].mv.mv[1].y = iclip(mvstack[n].mv.mv[1].y, top, bottom);
+        } while (++n < n_refmvs);
+
+        switch (refmv_ctx >> 1) {
+        case 0:
+            *ctx = imin(newmv_ctx, 1);
+            break;
+        case 1:
+            *ctx = 1 + imin(newmv_ctx, 3);
+            break;
+        case 2:
+            *ctx = iclip(3 + newmv_ctx, 4, 7);
+            break;
+        }
+
+        return;
+    } else if (*cnt < 2 && ref.ref[0] > 0) {
+        const int sign = rf->sign_bias[ref.ref[0] - 1];
+        const int sz4 = imin(w4, h4);
+
+        // non-self references in top
+        if (n_rows != ~0U) for (int x = 0; x < sz4 && *cnt < 2;) {
+            const refmvs_block *const cand_b = &b_top[x];
+            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
+            x += dav1d_block_dimensions[cand_b->bs][0];
+        }
+
+        // non-self references in left
+        if (n_cols != ~0U) for (int y = 0; y < sz4 && *cnt < 2;) {
+            const refmvs_block *const cand_b = &b_left[y][bx4 - 1];
+            add_single_extended_candidate(mvstack, cnt, cand_b, sign, rf->sign_bias);
+            y += dav1d_block_dimensions[cand_b->bs][1];
+        }
+    }
+    assert(*cnt <= 8);
+
+    // clamping
+    int n_refmvs = *cnt;
+    if (n_refmvs) {
+        const int left = -(bx4 + bw4 + 4) * 4 * 8;
+        const int right = (rf->iw4 - bx4 + 4) * 4 * 8;
+        const int top = -(by4 + bh4 + 4) * 4 * 8;
+        const int bottom = (rf->ih4 - by4 + 4) * 4 * 8;
+
+        int n = 0;
+        do {
+            mvstack[n].mv.mv[0].x = iclip(mvstack[n].mv.mv[0].x, left, right);
+            mvstack[n].mv.mv[0].y = iclip(mvstack[n].mv.mv[0].y, top, bottom);
+        } while (++n < n_refmvs);
+    }
+
+    for (int n = *cnt; n < 2; n++)
+        mvstack[n].mv.mv[0] = tgmv[0];
+
+    *ctx = (refmv_ctx << 4) | (globalmv_ctx << 3) | newmv_ctx;
+}
+
+void dav1d_refmvs_tile_sbrow_init(refmvs_tile *const rt, const refmvs_frame *const rf,
+                                  const int tile_col_start4, const int tile_col_end4,
+                                  const int tile_row_start4, const int tile_row_end4,
+                                  const int sby, int tile_row_idx, const int pass)
+{
+    if (rf->n_tile_threads == 1) tile_row_idx = 0;
+    rt->rp_proj = &rf->rp_proj[16 * rf->rp_stride * tile_row_idx];
+    const ptrdiff_t r_stride = rf->rp_stride * 2;
+    const ptrdiff_t pass_off = (rf->n_frame_threads > 1 && pass == 2) ?
+        35 * 2 * rf->n_blocks : 0;
+    refmvs_block *r = &rf->r[35 * r_stride * tile_row_idx + pass_off];
+    const int sbsz = rf->sbsz;
+    const int off = (sbsz * sby) & 16;
+    for (int i = 0; i < sbsz; i++, r += r_stride)
+        rt->r[off + 5 + i] = r;
+    rt->r[off + 0] = r;
+    r += r_stride;
+    rt->r[off + 1] = NULL;
+    rt->r[off + 2] = r;
+    r += r_stride;
+    rt->r[off + 3] = NULL;
+    rt->r[off + 4] = r;
+    if (sby & 1) {
+#define EXCHANGE(a, b) do { void *const tmp = a; a = b; b = tmp; } while (0)
+        EXCHANGE(rt->r[off + 0], rt->r[off + sbsz + 0]);
+        EXCHANGE(rt->r[off + 2], rt->r[off + sbsz + 2]);
+        EXCHANGE(rt->r[off + 4], rt->r[off + sbsz + 4]);
+#undef EXCHANGE
+    }
+
+    rt->rf = rf;
+    rt->tile_row.start = tile_row_start4;
+    rt->tile_row.end = imin(tile_row_end4, rf->ih4);
+    rt->tile_col.start = tile_col_start4;
+    rt->tile_col.end = imin(tile_col_end4, rf->iw4);
+}
+
+static void load_tmvs_c(const refmvs_frame *const rf, int tile_row_idx,
+                        const int col_start8, const int col_end8,
+                        const int row_start8, int row_end8)
+{
+    if (rf->n_tile_threads == 1) tile_row_idx = 0;
+    assert(row_start8 >= 0);
+    assert((unsigned) (row_end8 - row_start8) <= 16U);
+    row_end8 = imin(row_end8, rf->ih8);
+    const int col_start8i = imax(col_start8 - 8, 0);
+    const int col_end8i = imin(col_end8 + 8, rf->iw8);
+
+    const ptrdiff_t stride = rf->rp_stride;
+    refmvs_temporal_block *rp_proj =
+        &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride];
+    for (int y = row_start8; y < row_end8; y++) {
+        for (int x = col_start8; x < col_end8; x++)
+            rp_proj[x].mv.n = INVALID_MV;
+        rp_proj += stride;
+    }
+
+    rp_proj = &rf->rp_proj[16 * stride * tile_row_idx];
+    for (int n = 0; n < rf->n_mfmvs; n++) {
+        const int ref2cur = rf->mfmv_ref2cur[n];
+        if (ref2cur == INVALID_REF2CUR) continue;
+
+        const int ref = rf->mfmv_ref[n];
+        const int ref_sign = ref - 4;
+        const refmvs_temporal_block *r = &rf->rp_ref[ref][row_start8 * stride];
+        for (int y = row_start8; y < row_end8; y++) {
+            const int y_sb_align = y & ~7;
+            const int y_proj_start = imax(y_sb_align, row_start8);
+            const int y_proj_end = imin(y_sb_align + 8, row_end8);
+            for (int x = col_start8i; x < col_end8i; x++) {
+                const refmvs_temporal_block *rb = &r[x];
+                const int b_ref = rb->ref;
+                if (!b_ref) continue;
+                const int ref2ref = rf->mfmv_ref2ref[n][b_ref - 1];
+                if (!ref2ref) continue;
+                const mv b_mv = rb->mv;
+                const mv offset = mv_projection(b_mv, ref2cur, ref2ref);
+                int pos_x = x + apply_sign(abs(offset.x) >> 6,
+                                           offset.x ^ ref_sign);
+                const int pos_y = y + apply_sign(abs(offset.y) >> 6,
+                                                 offset.y ^ ref_sign);
+                if (pos_y >= y_proj_start && pos_y < y_proj_end) {
+                    const ptrdiff_t pos = (pos_y & 15) * stride;
+                    for (;;) {
+                        const int x_sb_align = x & ~7;
+                        if (pos_x >= imax(x_sb_align - 8, col_start8) &&
+                            pos_x < imin(x_sb_align + 16, col_end8))
+                        {
+                            rp_proj[pos + pos_x].mv = rb->mv;
+                            rp_proj[pos + pos_x].ref = ref2ref;
+                        }
+                        if (++x >= col_end8i) break;
+                        rb++;
+                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
+                        pos_x++;
+                    }
+                } else {
+                    for (;;) {
+                        if (++x >= col_end8i) break;
+                        rb++;
+                        if (rb->ref != b_ref || rb->mv.n != b_mv.n) break;
+                    }
+                }
+                x--;
+            }
+            r += stride;
+        }
+    }
+}
+
+static void save_tmvs_c(refmvs_temporal_block *rp, const ptrdiff_t stride,
+                        refmvs_block *const *const rr,
+                        const uint8_t *const ref_sign,
+                        const int col_end8, const int row_end8,
+                        const int col_start8, const int row_start8)
+{
+    for (int y = row_start8; y < row_end8; y++) {
+        const refmvs_block *const b = rr[(y & 15) * 2];
+
+        for (int x = col_start8; x < col_end8;) {
+            const refmvs_block *const cand_b = &b[x * 2 + 1];
+            const int bw8 = (dav1d_block_dimensions[cand_b->bs][0] + 1) >> 1;
+
+            if (cand_b->ref.ref[1] > 0 && ref_sign[cand_b->ref.ref[1] - 1] &&
+                (abs(cand_b->mv.mv[1].y) | abs(cand_b->mv.mv[1].x)) < 4096)
+            {
+                for (int n = 0; n < bw8; n++, x++)
+                    rp[x] = (refmvs_temporal_block) { .mv = cand_b->mv.mv[1],
+                                                      .ref = cand_b->ref.ref[1] };
+            } else if (cand_b->ref.ref[0] > 0 && ref_sign[cand_b->ref.ref[0] - 1] &&
+                       (abs(cand_b->mv.mv[0].y) | abs(cand_b->mv.mv[0].x)) < 4096)
+            {
+                for (int n = 0; n < bw8; n++, x++)
+                    rp[x] = (refmvs_temporal_block) { .mv = cand_b->mv.mv[0],
+                                                      .ref = cand_b->ref.ref[0] };
+            } else {
+                for (int n = 0; n < bw8; n++, x++) {
+                    rp[x].mv.n = 0;
+                    rp[x].ref = 0; // "invalid"
+                }
+            }
+        }
+        rp += stride;
+    }
+}
+
+int dav1d_refmvs_init_frame(refmvs_frame *const rf,
+                            const Dav1dSequenceHeader *const seq_hdr,
+                            const Dav1dFrameHeader *const frm_hdr,
+                            const uint8_t ref_poc[7],
+                            refmvs_temporal_block *const rp,
+                            const uint8_t ref_ref_poc[7][7],
+                            /*const*/ refmvs_temporal_block *const rp_ref[7],
+                            const int n_tile_threads, const int n_frame_threads)
+{
+    const int rp_stride = ((frm_hdr->width[0] + 127) & ~127) >> 3;
+    const int n_tile_rows = n_tile_threads > 1 ? frm_hdr->tiling.rows : 1;
+    const int n_blocks = rp_stride * n_tile_rows;
+
+    rf->sbsz = 16 << seq_hdr->sb128;
+    rf->frm_hdr = frm_hdr;
+    rf->iw8 = (frm_hdr->width[0] + 7) >> 3;
+    rf->ih8 = (frm_hdr->height + 7) >> 3;
+    rf->iw4 = rf->iw8 << 1;
+    rf->ih4 = rf->ih8 << 1;
+    rf->rp = rp;
+    rf->rp_stride = rp_stride;
+    rf->n_tile_threads = n_tile_threads;
+    rf->n_frame_threads = n_frame_threads;
+
+    if (n_blocks != rf->n_blocks) {
+        const size_t r_sz = sizeof(*rf->r) * 35 * 2 * n_blocks * (1 + (n_frame_threads > 1));
+        const size_t rp_proj_sz = sizeof(*rf->rp_proj) * 16 * n_blocks;
+        /* Note that sizeof(*rf->r) == 12, but it's accessed using 16-byte unaligned
+         * loads in save_tmvs() asm which can overread 4 bytes into rp_proj. */
+        dav1d_free_aligned(rf->r);
+        rf->r = dav1d_alloc_aligned(ALLOC_REFMVS, r_sz + rp_proj_sz, 64);
+        if (!rf->r) {
+            rf->n_blocks = 0;
+            return DAV1D_ERR(ENOMEM);
+        }
+
+        rf->rp_proj = (refmvs_temporal_block*)((uintptr_t)rf->r + r_sz);
+        rf->n_blocks = n_blocks;
+    }
+
+    const int poc = frm_hdr->frame_offset;
+    for (int i = 0; i < 7; i++) {
+        const int poc_diff = get_poc_diff(seq_hdr->order_hint_n_bits,
+                                          ref_poc[i], poc);
+        rf->sign_bias[i] = poc_diff > 0;
+        rf->mfmv_sign[i] = poc_diff < 0;
+        rf->pocdiff[i] = iclip(get_poc_diff(seq_hdr->order_hint_n_bits,
+                                            poc, ref_poc[i]), -31, 31);
+    }
+
+    // temporal MV setup
+    rf->n_mfmvs = 0;
+    rf->rp_ref = rp_ref;
+    if (frm_hdr->use_ref_frame_mvs && seq_hdr->order_hint_n_bits) {
+        int total = 2;
+        if (rp_ref[0] && ref_ref_poc[0][6] != ref_poc[3] /* alt-of-last != gold */) {
+            rf->mfmv_ref[rf->n_mfmvs++] = 0; // last
+            total = 3;
+        }
+        if (rp_ref[4] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[4],
+                                      frm_hdr->frame_offset) > 0)
+        {
+            rf->mfmv_ref[rf->n_mfmvs++] = 4; // bwd
+        }
+        if (rp_ref[5] && get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[5],
+                                      frm_hdr->frame_offset) > 0)
+        {
+            rf->mfmv_ref[rf->n_mfmvs++] = 5; // altref2
+        }
+        if (rf->n_mfmvs < total && rp_ref[6] &&
+            get_poc_diff(seq_hdr->order_hint_n_bits, ref_poc[6],
+                         frm_hdr->frame_offset) > 0)
+        {
+            rf->mfmv_ref[rf->n_mfmvs++] = 6; // altref
+        }
+        if (rf->n_mfmvs < total && rp_ref[1])
+            rf->mfmv_ref[rf->n_mfmvs++] = 1; // last2
+
+        for (int n = 0; n < rf->n_mfmvs; n++) {
+            const int rpoc = ref_poc[rf->mfmv_ref[n]];
+            const int diff1 = get_poc_diff(seq_hdr->order_hint_n_bits,
+                                           rpoc, frm_hdr->frame_offset);
+            if (abs(diff1) > 31) {
+                rf->mfmv_ref2cur[n] = INVALID_REF2CUR;
+            } else {
+                rf->mfmv_ref2cur[n] = rf->mfmv_ref[n] < 4 ? -diff1 : diff1;
+                for (int m = 0; m < 7; m++) {
+                    const int rrpoc = ref_ref_poc[rf->mfmv_ref[n]][m];
+                    const int diff2 = get_poc_diff(seq_hdr->order_hint_n_bits,
+                                                   rpoc, rrpoc);
+                    // unsigned comparison also catches the < 0 case
+                    rf->mfmv_ref2ref[n][m] = (unsigned) diff2 > 31U ? 0 : diff2;
+                }
+            }
+        }
+    }
+    rf->use_ref_frame_mvs = rf->n_mfmvs > 0;
+
+    return 0;
+}
+
+static void splat_mv_c(refmvs_block **rr, const refmvs_block *const rmv,
+                       const int bx4, const int bw4, int bh4)
+{
+    do {
+        refmvs_block *const r = *rr++ + bx4;
+        for (int x = 0; x < bw4; x++)
+            r[x] = *rmv;
+    } while (--bh4);
+}
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+#include "src/arm/refmvs.h"
+#elif ARCH_LOONGARCH64
+#include "src/loongarch/refmvs.h"
+#elif ARCH_X86
+#include "src/x86/refmvs.h"
+#endif
+#endif
+
+COLD void dav1d_refmvs_dsp_init(Dav1dRefmvsDSPContext *const c)
+{
+    c->load_tmvs = load_tmvs_c;
+    c->save_tmvs = save_tmvs_c;
+    c->splat_mv = splat_mv_c;
+
+#if HAVE_ASM
+#if ARCH_AARCH64 || ARCH_ARM
+    refmvs_dsp_init_arm(c);
+#elif ARCH_LOONGARCH64
+    refmvs_dsp_init_loongarch(c);
+#elif ARCH_X86
+    refmvs_dsp_init_x86(c);
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/refmvs.h b/media/libdav1d/src/src/refmvs.h
new file mode 100644
index 0000000000..9e0ed747bd
--- /dev/null
+++ b/media/libdav1d/src/src/refmvs.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright © 2020, VideoLAN and dav1d authors
+ * Copyright © 2020, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_REF_MVS_H
+#define DAV1D_SRC_REF_MVS_H
+
+#include 
+
+#include "dav1d/headers.h"
+
+#include "common/intops.h"
+
+#include "src/intra_edge.h"
+#include "src/tables.h"
+
+#define INVALID_MV 0x80008000
+#define INVALID_REF2CUR (-32)
+
+PACKED(typedef struct refmvs_temporal_block {
+    mv mv;
+    uint8_t ref;
+}) refmvs_temporal_block;
+CHECK_SIZE(refmvs_temporal_block, 5);
+
+PACKED(typedef union refmvs_refpair {
+    int8_t ref[2]; // [0] = 0: intra=1, [1] = -1: comp=0
+    uint16_t pair;
+}) ALIGN(refmvs_refpair, 2);
+CHECK_SIZE(refmvs_refpair, 2);
+
+typedef union refmvs_mvpair {
+    mv mv[2];
+    uint64_t n;
+} refmvs_mvpair;
+CHECK_SIZE(refmvs_mvpair, 8);
+
+PACKED(typedef struct refmvs_block {
+    refmvs_mvpair mv;
+    refmvs_refpair ref;
+    uint8_t bs, mf; // 1 = globalmv+affine, 2 = newmv
+}) ALIGN(refmvs_block, 4);
+CHECK_SIZE(refmvs_block, 12);
+
+typedef struct refmvs_frame {
+    const Dav1dFrameHeader *frm_hdr;
+    int iw4, ih4, iw8, ih8;
+    int sbsz;
+    int use_ref_frame_mvs;
+    uint8_t sign_bias[7], mfmv_sign[7];
+    int8_t pocdiff[7];
+    uint8_t mfmv_ref[3];
+    int8_t mfmv_ref2cur[3];
+    uint8_t mfmv_ref2ref[3][7];
+    int n_mfmvs;
+
+    int n_blocks;
+    refmvs_temporal_block *rp;
+    /*const*/ refmvs_temporal_block *const *rp_ref;
+    refmvs_temporal_block *rp_proj;
+    ptrdiff_t rp_stride;
+
+    refmvs_block *r; // 35 x r_stride memory
+    int n_tile_threads, n_frame_threads;
+} refmvs_frame;
+
+typedef struct refmvs_tile {
+    const refmvs_frame *rf;
+    refmvs_block *r[32 + 5];
+    refmvs_temporal_block *rp_proj;
+    struct {
+        int start, end;
+    } tile_col, tile_row;
+} refmvs_tile;
+
+typedef struct refmvs_candidate {
+    refmvs_mvpair mv;
+    int weight;
+} refmvs_candidate;
+
+// initialize temporal MVs; this can be done in any configuration, e.g. one
+// tile/sbrow at a time, where col_{start,end}8 are the tile boundaries; or
+// it can just be for the whole frame's sbrow, where col_{start,end}8 are the
+// frame boundaries. row_{start,end}8 are the superblock row boundaries.
+#define decl_load_tmvs_fn(name) \
+void (name)(const refmvs_frame *rf, int tile_row_idx, \
+            int col_start8, int col_end8, int row_start8, int row_end8)
+typedef decl_load_tmvs_fn(*load_tmvs_fn);
+
+#define decl_save_tmvs_fn(name) \
+void (name)(refmvs_temporal_block *rp, const ptrdiff_t stride, \
+            refmvs_block *const *const rr, const uint8_t *const ref_sign, \
+            int col_end8, int row_end8, int col_start8, int row_start8)
+typedef decl_save_tmvs_fn(*save_tmvs_fn);
+
+#define decl_splat_mv_fn(name) \
+void (name)(refmvs_block **rr, const refmvs_block *rmv, int bx4, int bw4, int bh4)
+typedef decl_splat_mv_fn(*splat_mv_fn);
+
+typedef struct Dav1dRefmvsDSPContext {
+    load_tmvs_fn load_tmvs;
+    save_tmvs_fn save_tmvs;
+    splat_mv_fn splat_mv;
+} Dav1dRefmvsDSPContext;
+
+// call once per frame
+int dav1d_refmvs_init_frame(refmvs_frame *rf,
+                            const Dav1dSequenceHeader *seq_hdr,
+                            const Dav1dFrameHeader *frm_hdr,
+                            const uint8_t ref_poc[7],
+                            refmvs_temporal_block *rp,
+                            const uint8_t ref_ref_poc[7][7],
+                            /*const*/ refmvs_temporal_block *const rp_ref[7],
+                            int n_tile_threads, int n_frame_threads);
+
+// cache the current tile/sbrow (or frame/sbrow)'s projectable motion vectors
+// into buffers for use in future frame's temporal MV prediction
+static inline void dav1d_refmvs_save_tmvs(const Dav1dRefmvsDSPContext *const dsp,
+                                          const refmvs_tile *const rt,
+                                          const int col_start8, int col_end8,
+                                          const int row_start8, int row_end8)
+{
+    const refmvs_frame *const rf = rt->rf;
+
+    assert(row_start8 >= 0);
+    assert((unsigned) (row_end8 - row_start8) <= 16U);
+    row_end8 = imin(row_end8, rf->ih8);
+    col_end8 = imin(col_end8, rf->iw8);
+
+    const ptrdiff_t stride = rf->rp_stride;
+    const uint8_t *const ref_sign = rf->mfmv_sign;
+    refmvs_temporal_block *rp = &rf->rp[row_start8 * stride];
+
+    dsp->save_tmvs(rp, stride, rt->r + 6, ref_sign,
+                   col_end8, row_end8, col_start8, row_start8);
+}
+
+// initialize tile boundaries and refmvs_block pointers for one tile/sbrow
+void dav1d_refmvs_tile_sbrow_init(refmvs_tile *rt, const refmvs_frame *rf,
+                                  int tile_col_start4, int tile_col_end4,
+                                  int tile_row_start4, int tile_row_end4,
+                                  int sby, int tile_row_idx, int pass);
+
+// call for each block
+void dav1d_refmvs_find(const refmvs_tile *rt,
+                       refmvs_candidate mvstack[8], int *cnt,
+                       int *ctx, const refmvs_refpair ref, enum BlockSize bs,
+                       enum EdgeFlags edge_flags, int by4, int bx4);
+
+void dav1d_refmvs_dsp_init(Dav1dRefmvsDSPContext *dsp);
+void dav1d_refmvs_dsp_init_arm(Dav1dRefmvsDSPContext *dsp);
+void dav1d_refmvs_dsp_init_loongarch(Dav1dRefmvsDSPContext *dsp);
+void dav1d_refmvs_dsp_init_x86(Dav1dRefmvsDSPContext *dsp);
+
+#endif /* DAV1D_SRC_REF_MVS_H */
diff --git a/media/libdav1d/src/src/riscv/64/cdef.S b/media/libdav1d/src/src/riscv/64/cdef.S
new file mode 100644
index 0000000000..cb550af79a
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/cdef.S
@@ -0,0 +1,703 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Bogdan Gligorijevic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+.macro constrain_vectors vec1, vec2, vec_sub, strength, shift, vec_tmp1, vec_tmp2
+    vmslt.vx v0, \vec_tmp1, zero
+    vneg.v \vec_tmp1, \vec_tmp1, v0.t
+    vmmv.m v1, v0
+
+    vmslt.vx v0, \vec_tmp2, zero
+    vneg.v \vec_tmp2, \vec_tmp2, v0.t
+
+    vsra.vx \vec1, \vec_tmp1, \shift
+    vsra.vx \vec2, \vec_tmp2, \shift
+
+    vrsub.vx \vec1, \vec1, \strength
+    vrsub.vx \vec2, \vec2, \strength
+
+    vmax.vx \vec1, \vec1, zero
+    vmax.vx \vec2, \vec2, zero
+
+    vmin.vv \vec_tmp1, \vec1, \vec_tmp1
+    vmin.vv \vec_tmp2, \vec2, \vec_tmp2
+
+    vneg.v \vec_tmp2, \vec_tmp2, v0.t
+
+    vmmv.m v0, v1
+    vneg.v \vec_tmp1, \vec_tmp1, v0.t
+.endm
+
+.macro padding_fn w, h
+    li t5, -32768 # INT16_MIN
+
+    andi t4, a7, 4
+    li t2, -2 # y_start
+
+.if \w == 4
+    vsetivli zero, \w + 4, e16, m1, ta, ma
+.else
+    vsetivli zero, \w + 4, e16, m2, ta, ma
+.endif
+    vmv.v.x v0, t5
+    bnez t4, L(top_done_\w\()x\h)
+
+    slli t5, a1, 1
+    addi t5, t5, 2
+    slli t5, t5, 1
+    sub t5, a0, t5
+
+    sh1add t4, a1, t5
+    vse16.v v0, (t5)
+    vse16.v v0, (t4)
+    li t2, 0
+
+L(top_done_\w\()x\h):
+    andi t4, a7, 8
+    li t3, 2 + \h # y_end
+    bnez t4, L(bottom_done_\w\()x\h)
+
+    li t5, \h
+    mul t5, a1, t5
+    addi t5, t5, -2
+    sh1add t5, t5, a0
+
+    sh1add t4, a1, t5
+    vse16.v v0, (t5)
+    vse16.v v0, (t4)
+    addi t3, t3, -2
+
+L(bottom_done_\w\()x\h):
+    andi t4, a7, 1
+    li t0, -2 # x_start
+
+.if \w == 4
+    vsetivli zero, 2, e16, m1, ta, ma
+.else
+    vsetivli zero, 2, e16, m2, ta, ma
+.endif
+
+    bnez t4, L(left_done_\w\()x\h)
+
+    mul t5, a1, t2
+    addi t5, t5, -2
+    sh1add t5, t5, a0
+
+    sub t0, t3, t2
+
+3:
+    vse16.v v0, (t5)
+    sh1add t5, a1, t5
+    addi t0, t0, -1
+    bnez t0, 3b
+
+L(left_done_\w\()x\h):
+
+    andi t4, a7, 2
+    li t1, 2 + \w # x_end
+    bnez t4, L(right_done_\w\()x\h)
+
+    mul t5, t2, a1
+    addi t5, t5, \w
+    sh1add t5, t5, a0
+
+    sub t1, t3, t2
+
+4:
+    vse16.v v0, (t5)
+    sh1add t5, a1, t5
+    addi t1, t1, -1
+    bnez t1, 4b
+
+    li t1, \w
+
+L(right_done_\w\()x\h):
+
+    beqz t2, L(top_skip_\w\()x\h)
+
+    mul t5, a1, t2
+    add t5, t0, t5
+    sh1add a0, t5, a0 # tmp += y_start * tmp_stride + x_start
+    add a5, a5, t0
+
+    sub t5, t1, t0 # x_end - x_start
+    slli t6, t0, 1
+.if \w == 4
+    vsetvli zero, t5, e16, m1, ta, ma
+.else
+    vsetvli zero, t5, e16, m2, ta, ma
+.endif
+
+5:
+    vle8.v v0, (a5)
+    addi t2, t2, 1
+    vzext.vf2 v2, v0
+    add a5, a3, a5
+    vse16.v v2, (a0)
+    sh1add a0, a1, a0
+    bnez t2, 5b
+
+    sub a0, a0, t6 # tmp -= x_start
+
+L(top_skip_\w\()x\h):
+
+    li a5, \h
+    beqz t0, L(left_skip_\w\()x\h)
+
+    sh1add a0, t0, a0 # tmp += x_start
+
+7:
+.if \w == 4
+    vsetivli zero, 2, e16, m1, ta, ma
+.else
+    vsetivli zero, 2, e16, m2, ta, ma
+.endif
+
+    vle8.v v0, (a4)
+    addi a5, a5, -1
+    vzext.vf2 v2, v0
+    addi a4, a4, 2
+    vse16.v v2, (a0)
+    sh1add a0, a1, a0
+    bnez a5, 7b
+
+    li a5, \h
+    mul t5, a1, a5
+    add t5, t5, t0
+    slli t5, t5, 1
+    sub a0, a0, t5 # tmp -= h * tmp_stride + x_start
+
+L(left_skip_\w\()x\h):
+
+8:
+.if \w == 4
+    vsetvli zero, t1, e16, m1, ta, ma
+.else
+    vsetvli zero, t1, e16, m2, ta, ma
+.endif
+
+    vle8.v v0, (a2)
+    vzext.vf2 v2, v0
+    vse16.v v2, (a0)
+    add a2, a3, a2
+    sh1add a0, a1, a0
+    addi a5, a5, -1
+    bnez a5, 8b
+
+
+    li a5, \h
+    sh1add a0, t0, a0 # tmp += x_start
+    add a6, a6, t0 # bottom += x_start
+    beq a5, t3, L(bottom_skip_\w\()x\h)
+
+    sub t5, t1, t0
+.if \w == 4
+    vsetvli zero, t5, e16, m1, ta, ma
+.else
+    vsetvli zero, t5, e16, m2, ta, ma
+.endif
+
+9:
+    vle8.v v0, (a6)
+    add a6, a3, a6
+    vzext.vf2 v2, v0
+    addi a5, a5, 1
+    vse16.v v2, (a0)
+    sh1add a0, a1, a0
+    bne a5, t3, 9b
+
+L(bottom_skip_\w\()x\h):
+    li t6, \h
+    mul t6, a3, t6
+    sub a2, a2, t6 # src -= h * src_stride
+    mul t5, a1, t3
+    add t5, t5, t0
+    slli t5, t5, 1
+    sub a0, a0, t5 # tmp -= y_end * tmp_stride + x_start
+.endm
+
+
+.macro cdef_fn w, h
+function cdef_filter_block_\w\()x\h\()_8bpc_rvv, export=1, ext="v,zba,zbb"
+    csrw vxrm, zero
+
+    addi sp, sp, -32 - 144*2
+    sd a5, 24(sp) # pri_strength
+    sd a6, 16(sp) # sec_strength
+    sd a7, 8(sp) # dir
+
+
+    ld a7, 8 + 32 + 144*2(sp) # edges
+    mv a6, a4 # bottom
+    mv a5, a3 # top
+    mv a4, a2 # left
+    mv a3, a1 # dst_stride
+    mv a2, a0 # dst
+    li a1, 12 # tmp_stride
+    addi a0, sp, 32 + 2*(2*12+2)
+    padding_fn \w, \h
+
+    ld a4, 32 + 2*144(sp) # damping
+    ld a5, 24(sp) # pri_strength
+    ld a6, 16(sp) # sec_strength
+    ld a7, 8(sp) # dir
+
+    beqz a5, cdef_filter_sec_only_\w\()x\h
+
+    bnez a6, cdef_filter_pri_sec_\w\()x\h
+
+    andi t0, a5, 1
+    li t1, 4
+    sub t4, t1, t0
+
+    li t1, 63
+    clz t2, a5
+    sub t1, t1, t2
+    sub t1, a4, t1
+
+    li t0, \h
+
+    la t2, dav1d_cdef_directions
+    addi t3, a7, 2
+    sh1add t2, t3, t2
+
+    blt zero, t1, 1f
+    mv t1, zero
+1:
+    vsetivli zero, \w, e16, m1, ta, mu
+
+    lb t3, 0(t2)
+
+    vle8.v v0, (a2)
+    vzext.vf2 v2, v0
+
+    sh1add t6, t3, a0
+    slli t3, t3, 1
+    sub t3, a0, t3
+
+    vle16.v v4, (t6)
+    vle16.v v6, (t3)
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v12, a5, t1, v8, v16
+
+    vmul.vx v28, v16, t4
+    vmacc.vx v28, t4, v8
+
+    lb t3, 1(t2)
+
+    andi t5, t4, 3
+    ori t5, t5, 2
+
+    sh1add t6, t3, a0
+    slli t3, t3, 1
+    sub t3, a0, t3
+
+    vsetvli zero, zero, e16, m1, ta, mu
+
+    vle16.v v4, (t6)
+    vle16.v v6, (t3)
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v12, a5, t1, v8, v16
+
+    vmacc.vx v28, t5, v16
+    vmacc.vx v28, t5, v8
+
+    vmslt.vx v0, v28, zero
+    vadd.vi v28, v28, -1, v0.t
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vnclip.wi v24, v28, 4
+
+    vadd.vv v28, v2, v24
+
+    vsetvli zero, zero, e8, mf2, ta, ma
+
+    vnclipu.wi v24, v28, 0
+
+    vse8.v v24, (a2)
+
+    addi t0, t0, -1
+    add a2, a2, a3
+    sh1add a0, a1, a0
+
+    bnez t0, 1b
+
+    addi sp, sp, 32 + 144*2
+    ret
+
+cdef_filter_sec_only_\w\()x\h:
+    li t1, 63
+    clz t2, a6
+    sub t1, t1, t2
+    sub t1, a4, t1
+
+    li t0, \h
+
+    la t2, dav1d_cdef_directions
+    addi t3, a7, 4
+    sh1add t3, t3, t2
+    sh1add t2, a7, t2
+
+2:
+    vsetivli zero, \w, e16, m1, ta, mu
+
+    lb t4, 0(t3)
+    lb t5, 0(t2)
+
+    vle8.v v0, (a2)
+    vzext.vf2 v2, v0
+
+    sh1add t6, t4, a0
+    slli t4, t4, 1
+    sub t4, a0, t4
+
+    vle16.v v4, (t6)
+    vle16.v v6, (t4)
+
+    sh1add t4, t5, a0
+    slli t5, t5, 1
+    sub t5, a0, t5
+
+    vle16.v v8, (t4)
+    vle16.v v10, (t5)
+
+    vwsub.vv v12, v4, v2
+    vwsub.vv v14, v6, v2
+    vwsub.vv v16, v8, v2
+    vwsub.vv v18, v10, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    li t4, 2
+    constrain_vectors v4, v6, v12, a6, t1, v12, v14
+    constrain_vectors v8, v10, v14, a6, t1, v16, v18
+
+    vmul.vx v28, v18, t4
+    vmacc.vx v28, t4, v16
+    vmacc.vx v28, t4, v14
+    vmacc.vx v28, t4, v12
+
+
+    lb t4, 1(t3)
+    lb t5, 1(t2)
+
+    sh1add t6, t4, a0
+    slli t4, t4, 1
+    sub t4, a0, t4
+
+    vsetvli zero, zero, e16, m1, ta, mu
+
+    vle16.v v4, (t6)
+    vle16.v v6, (t4)
+
+    sh1add t4, t5, a0
+    slli t5, t5, 1
+    sub t5, a0, t5
+
+    vle16.v v8, (t4)
+    vle16.v v10, (t5)
+
+    vwsub.vv v12, v4, v2
+    vwsub.vv v14, v6, v2
+    vwsub.vv v16, v8, v2
+    vwsub.vv v18, v10, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v12, a6, t1, v12, v14
+    constrain_vectors v8, v10, v14, a6, t1, v16, v18
+
+    vadd.vv v4, v28, v12
+    vadd.vv v28, v4, v14
+    vadd.vv v4, v28, v16
+    vadd.vv v28, v4, v18
+
+    vmslt.vx v0, v28, zero
+    vadd.vi v28, v28, -1, v0.t
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vnclip.wi v24, v28, 4
+
+    vadd.vv v28, v2, v24
+
+    vsetvli zero, zero, e8, mf2, ta, ma
+
+    vnclipu.wi v24, v28, 0
+
+    vse8.v v24, (a2)
+
+    addi t0, t0, -1
+    add a2, a2, a3
+    sh1add a0, a1, a0
+
+    bnez t0, 2b
+
+    addi sp, sp, 32 + 144*2
+    ret
+cdef_filter_pri_sec_\w\()x\h:
+
+    li t1, 63
+    clz t2, a5
+    clz t3, a6
+    sub t2, t1, t2
+    sub t3, t1, t3
+    sub t1, a4, t2
+    sub t2, a4, t3
+
+    li t0, \h
+
+    la t3, dav1d_cdef_directions
+
+    blt zero, t1, 3f
+    mv t1, zero
+3:
+    vsetivli zero, \w, e16, m1, ta, ma
+
+    li t4, 4
+    andi t6, a5, 1
+    addi t5, a7, 2
+    sub t4, t4, t6
+
+    sh1add t5, t5, t3
+
+    vle8.v v0, (a2)
+
+    lb t6, 0(t5)
+
+    vzext.vf2 v2, v0
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v2
+    vmax.vv v24, v4, v2
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v12, a5, t1, v8, v16
+
+    vmul.vx v28, v16, t4
+    vmacc.vx v28, t4, v8
+
+    lb t6, 1(t5)
+
+    andi t4, t4, 3
+    ori t4, t4, 2
+
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v12, a5, t1, v8, v16
+
+    addi t5, a7, 4
+    vmacc.vx v28, t4, v16
+    vmacc.vx v28, t4, v8
+
+    sh1add t5, t5, t3
+
+    lb t6, 0(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    li t6, 2
+    constrain_vectors v4, v6, v12, a6, t2, v8, v16
+
+    vmacc.vx v28, t6, v16
+    vmacc.vx v28, t6, v8
+
+    lb t6, 1(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v12, a6, t2, v8, v16
+
+    sh1add t5, a7, t3
+
+    vadd.vv v4, v28, v8
+    vadd.vv v28, v4, v16
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    lb t6, 0(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    li t6, 2
+    constrain_vectors v4, v6, v12, a6, t2, v8, v16
+
+    vmacc.vx v28, t6, v16
+    vmacc.vx v28, t6, v8
+
+    lb t6, 1(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v12, a6, t2, v8, v16
+
+    vadd.vv v4, v28, v8
+    vadd.vv v28, v4, v16
+
+    vmslt.vx v0, v28, zero
+    vadd.vi v28, v28, -1, v0.t
+
+    vsetvli zero, zero, e16, m1, ta, mu
+
+    vnclip.wi v16, v28, 4
+
+    vadd.vv v28, v2, v16
+
+    vmslt.vv v0, v20, v28
+    vmerge.vvm v4, v20, v28, v0
+
+    vmslt.vv v0, v4, v24
+    vmerge.vvm v28, v24, v4, v0
+
+    vsetvli zero, zero, e8, mf2, ta, ma
+
+    vnclipu.wi v24, v28, 0
+
+    vse8.v v24, (a2)
+
+    addi t0, t0, -1
+    add a2, a2, a3
+    sh1add a0, a1, a0
+
+    bnez t0, 3b
+
+    addi sp, sp, 32 + 144*2
+    ret
+endfunc
+.endm
+
+cdef_fn 4, 4
+cdef_fn 4, 8
+cdef_fn 8, 8
diff --git a/media/libdav1d/src/src/riscv/64/cdef16.S b/media/libdav1d/src/src/riscv/64/cdef16.S
new file mode 100644
index 0000000000..3ac770d238
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/cdef16.S
@@ -0,0 +1,689 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Bogdan Gligorijevic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+.macro constrain_vectors vec1, vec2, vec_sub, strength, shift, vec_tmp1, vec_tmp2
+    vmslt.vx v0, \vec_tmp1, zero
+    vneg.v \vec_tmp1, \vec_tmp1, v0.t
+    vmmv.m v1, v0
+
+    vmslt.vx v0, \vec_tmp2, zero
+    vneg.v \vec_tmp2, \vec_tmp2, v0.t
+
+    vsra.vx \vec1, \vec_tmp1, \shift
+    vsra.vx \vec2, \vec_tmp2, \shift
+
+    vrsub.vx \vec1, \vec1, \strength
+    vrsub.vx \vec2, \vec2, \strength
+
+    vmax.vx \vec1, \vec1, zero
+    vmax.vx \vec2, \vec2, zero
+
+    vmin.vv \vec_tmp1, \vec1, \vec_tmp1
+    vmin.vv \vec_tmp2, \vec2, \vec_tmp2
+
+    vneg.v \vec_tmp2, \vec_tmp2, v0.t
+
+    vmmv.m v0, v1
+    vneg.v \vec_tmp1, \vec_tmp1, v0.t
+.endm
+
+.macro padding_fn w, h
+    li t5, -32768 # INT16_MIN
+
+    andi t4, a7, 4
+    li t2, -2 # y_start
+
+.if \w == 4
+    vsetivli zero, \w + 4, e16, m1, ta, ma
+.else
+    vsetivli zero, \w + 4, e16, m2, ta, ma
+.endif
+    vmv.v.x v0, t5
+    bnez t4, L(top_done_\w\()x\h)
+
+    slli t5, a1, 1
+    addi t5, t5, 2
+    slli t5, t5, 1
+    sub t5, a0, t5
+
+    sh1add t4, a1, t5
+    vse16.v v0, (t5)
+    vse16.v v0, (t4)
+    li t2, 0
+
+L(top_done_\w\()x\h):
+    andi t4, a7, 8
+    li t3, 2 + \h # y_end
+    bnez t4, L(bottom_done_\w\()x\h)
+
+    li t5, \h
+    mul t5, a1, t5
+    addi t5, t5, -2
+    sh1add t5, t5, a0
+
+    sh1add t4, a1, t5
+    vse16.v v0, (t5)
+    vse16.v v0, (t4)
+    addi t3, t3, -2
+
+L(bottom_done_\w\()x\h):
+    andi t4, a7, 1
+    li t0, -2 # x_start
+
+.if \w == 4
+    vsetivli zero, 2, e16, m1, ta, ma
+.else
+    vsetivli zero, 2, e16, m2, ta, ma
+.endif
+
+    bnez t4, L(left_done_\w\()x\h)
+
+    mul t5, a1, t2
+    addi t5, t5, -2
+    sh1add t5, t5, a0
+
+    sub t0, t3, t2
+
+3:
+    vse16.v v0, (t5)
+    sh1add t5, a1, t5
+    addi t0, t0, -1
+    bnez t0, 3b
+
+L(left_done_\w\()x\h):
+
+    andi t4, a7, 2
+    li t1, 2 + \w # x_end
+    bnez t4, L(right_done_\w\()x\h)
+
+    mul t5, t2, a1
+    addi t5, t5, \w
+    sh1add t5, t5, a0
+
+    sub t1, t3, t2
+
+4:
+    vse16.v v0, (t5)
+    sh1add t5, a1, t5
+    addi t1, t1, -1
+    bnez t1, 4b
+
+    li t1, \w
+
+L(right_done_\w\()x\h):
+
+    beqz t2, L(top_skip_\w\()x\h)
+
+    mul t5, a1, t2
+    add t5, t0, t5
+    sh1add a0, t5, a0 # tmp += y_start * tmp_stride + x_start
+    sh1add a5, t0, a5 # top += x_start
+
+    sub t5, t1, t0
+    slli t6, t0, 1
+.if \w == 4
+    vsetvli zero, t5, e16, m1, ta, ma
+.else
+    vsetvli zero, t5, e16, m2, ta, ma
+.endif
+
+5:
+    vle16.v v2, (a5)
+    addi t2, t2, 1
+    add a5, a3, a5
+    vse16.v v2, (a0)
+    sh1add a0, a1, a0
+    bnez t2, 5b
+
+    sub a0, a0, t6 # tmp -= x_start
+
+L(top_skip_\w\()x\h):
+
+    li a5, \h
+    beqz t0, L(left_skip_\w\()x\h)
+
+    sh1add a0, t0, a0 # tmp += x_start
+
+7:
+.if \w == 4
+    vsetivli zero, 2, e16, m1, ta, ma
+.else
+    vsetivli zero, 2, e16, m2, ta, ma
+.endif
+
+    vle16.v v2, (a4)
+    addi a5, a5, -1
+    addi a4, a4, 4
+    vse16.v v2, (a0)
+    sh1add a0, a1, a0
+    bnez a5, 7b
+
+    li a5, \h
+    mul t5, a1, a5
+    add t5, t5, t0
+    slli t5, t5, 1
+    sub a0, a0, t5 # tmp -= h * tmp_stride + x_start
+
+L(left_skip_\w\()x\h):
+
+8:
+.if \w == 4
+    vsetvli zero, t1, e16, m1, ta, ma
+.else
+    vsetvli zero, t1, e16, m2, ta, ma
+.endif
+
+    vle16.v v2, (a2)
+    add a2, a3, a2
+    vse16.v v2, (a0)
+    sh1add a0, a1, a0
+    addi a5, a5, -1
+    bnez a5, 8b
+
+
+    li a5, \h
+    sh1add a0, t0, a0 # tmp += x_start
+    sh1add a6, t0, a6 # bottom += x_start
+    beq a5, t3, L(bottom_skip_\w\()x\h)
+
+    sub t5, t1, t0
+.if \w == 4
+    vsetvli zero, t5, e16, m1, ta, ma
+.else
+    vsetvli zero, t5, e16, m2, ta, ma
+.endif
+
+9:
+    vle16.v v2, (a6)
+    add a6, a3, a6
+    addi a5, a5, 1
+    vse16.v v2, (a0)
+    sh1add a0, a1, a0
+    bne a5, t3, 9b
+
+L(bottom_skip_\w\()x\h):
+    li t6, \h
+    mul t6, a3, t6
+    sub a2, a2, t6 # src -= h * PXSTRIDE(src_stride)
+    mul t5, a1, t3
+    add t5, t5, t0
+    slli t5, t5, 1
+    sub a0, a0, t5 # tmp -= y_end * tmp_stride + x_start
+.endm
+
+.macro cdef_fn w, h
+function cdef_filter_block_\w\()x\h\()_16bpc_rvv, export=1, ext="v,zba,zbb"
+    csrw vxrm, zero
+
+    addi sp, sp, -32 - 144*2
+    sd a5, 24(sp) # pri_strength
+    sd a6, 16(sp) # sec_strength
+    sd a7, 8(sp) # dir
+
+    ld a7, 8 + 32 + 144*2(sp) # edges
+    mv a6, a4 # bottom
+    mv a5, a3 # top
+    mv a4, a2 # left
+    mv a3, a1 # dst_stride
+    mv a2, a0 # dst
+    li a1, 12 # tmp_stride
+    addi a0, sp, 32 + 2*(2*12+2)
+
+    padding_fn \w, \h
+
+    ld a4, 32 + 2*144(sp) # damping
+    ld a5, 24(sp) # pri_strength
+    ld a6, 16(sp) # sec_strength
+    ld a7, 8(sp) # dir
+
+    beqz a5, cdef_filter_sec_only_\w\()x\h
+
+    bnez a6, cdef_filter_pri_sec_\w\()x\h
+
+    li t1, 64-8
+    ld t4, 32 + 2*144 + 16(sp) # bitdepth_max
+    clz t4, t4
+    sub t4, t1, t4
+    sra t4, a5, t4
+    andi t0, t4, 1
+    li t1, 4
+    sub t4, t1, t0
+
+    li t1, 63
+    clz t2, a5
+    sub t1, t1, t2
+    sub t1, a4, t1
+
+    li t0, \h
+
+    la t2, dav1d_cdef_directions
+    addi t3, a7, 2
+    sh1add t2, t3, t2
+
+    vsetivli zero, \w, e16, m1, ta, ma
+    blt zero, t1, 1f
+    mv t1, zero
+1:
+    lb t3, 0(t2)
+
+    vle16.v v2, (a2)
+
+    sh1add t6, t3, a0
+    slli t3, t3, 1
+    sub t3, a0, t3
+
+    vle16.v v4, (t6)
+    vle16.v v6, (t3)
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v2, a5, t1, v8, v16
+
+    vmul.vx v28, v16, t4
+    vmacc.vx v28, t4, v8
+
+    lb t3, 1(t2)
+
+    andi t5, t4, 3
+    ori t5, t5, 2
+
+    sh1add t6, t3, a0
+    slli t3, t3, 1
+    sub t3, a0, t3
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (t6)
+    vle16.v v6, (t3)
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v2, a5, t1, v8, v16
+
+    vmacc.vx v28, t5, v16
+    vmacc.vx v28, t5, v8
+
+    vmslt.vx v0, v28, zero
+    vadd.vi v28, v28, -1, v0.t
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vnclip.wi v24, v28, 4
+
+    vadd.vv v28, v2, v24
+
+    vse16.v v28, (a2)
+
+    add a2, a2, a3
+    sh1add a0, a1, a0
+
+    addi t0, t0, -1
+    bnez t0, 1b
+
+    addi sp, sp, 32 + 144*2
+    ret
+
+cdef_filter_sec_only_\w\()x\h:
+    li t1, 63
+    clz t2, a6
+    sub t1, t1, t2
+    sub t1, a4, t1
+
+    li t0, \h
+
+    la t2, dav1d_cdef_directions
+    addi t3, a7, 4
+    sh1add t3, t3, t2
+    sh1add t2, a7, t2
+
+    vsetivli zero, \w, e16, m1, ta, ma
+2:
+
+    lb t4, 0(t3)
+    lb t5, 0(t2)
+
+    vle16.v v2, (a2)
+
+    sh1add t6, t4, a0
+    slli t4, t4, 1
+    sub t4, a0, t4
+
+    vle16.v v4, (t6)
+    vle16.v v6, (t4)
+
+    sh1add t4, t5, a0
+    slli t5, t5, 1
+    sub t5, a0, t5
+
+    vle16.v v8, (t4)
+    vle16.v v10, (t5)
+
+    vwsub.vv v12, v4, v2
+    vwsub.vv v14, v6, v2
+    vwsub.vv v16, v8, v2
+    vwsub.vv v18, v10, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    li t4, 2
+    constrain_vectors v4, v6, v2, a6, t1, v12, v14
+    constrain_vectors v8, v10, v2, a6, t1, v16, v18
+
+    vmul.vx v28, v18, t4
+    vmacc.vx v28, t4, v16
+    vmacc.vx v28, t4, v14
+    vmacc.vx v28, t4, v12
+
+    lb t4, 1(t3)
+    lb t5, 1(t2)
+
+    sh1add t6, t4, a0
+    slli t4, t4, 1
+    sub t4, a0, t4
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (t6)
+    vle16.v v6, (t4)
+
+    sh1add t4, t5, a0
+    slli t5, t5, 1
+    sub t5, a0, t5
+
+    vle16.v v8, (t4)
+    vle16.v v10, (t5)
+
+    vwsub.vv v12, v4, v2
+    vwsub.vv v14, v6, v2
+    vwsub.vv v16, v8, v2
+    vwsub.vv v18, v10, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v2, a6, t1, v12, v14
+    constrain_vectors v8, v10, v2, a6, t1, v16, v18
+
+    vadd.vv v4, v28, v12
+    vadd.vv v28, v4, v14
+    vadd.vv v4, v28, v16
+    vadd.vv v28, v4, v18
+
+    vmslt.vx v0, v28, zero
+    vadd.vi v28, v28, -1, v0.t
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vnclip.wi v24, v28, 4
+
+    vadd.vv v28, v2, v24
+
+    vse16.v v28, (a2)
+
+    add a2, a2, a3
+    sh1add a0, a1, a0
+
+    addi t0, t0, -1
+    bnez t0, 2b
+
+    addi sp, sp, 32 + 144*2
+    ret
+cdef_filter_pri_sec_\w\()x\h:
+
+    li t1, 63
+    clz t2, a5
+    clz t3, a6
+    sub t2, t1, t2
+    sub t3, t1, t3
+    sub t1, a4, t2
+    sub t2, a4, t3
+
+    li t0, \h
+
+    la t3, dav1d_cdef_directions
+
+    vsetivli zero, \w, e16, m1, ta, ma
+    blt zero, t1, 3f
+    mv t1, zero
+3:
+    li t5, 64-8
+    ld t4, 32 + 2*144 + 16(sp) # bitdepth_max
+    clz t4, t4
+    sub t4, t5, t4
+    sra t4, a5, t4
+    li t6, 4
+    andi t5, t4, 1
+    sub t4, t6, t5
+
+    addi t5, a7, 2
+
+    sh1add t5, t5, t3
+
+    vle16.v v2, (a2)
+
+    lb t6, 0(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v2
+    vmax.vv v24, v4, v2
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v2, a5, t1, v8, v16
+
+    vmul.vx v28, v16, t4
+    vmacc.vx v28, t4, v8
+
+    andi t4, t4, 3
+    ori t4, t4, 2
+
+    lb t6, 1(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v2, a5, t1, v8, v16
+
+    addi t5, a7, 4
+    vmacc.vx v28, t4, v16
+    vmacc.vx v28, t4, v8
+
+    sh1add t5, t5, t3
+
+    lb t6, 0(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    li t6, 2
+    constrain_vectors v4, v6, v2, a6, t2, v8, v16
+
+    vmacc.vx v28, t6, v16
+    vmacc.vx v28, t6, v8
+
+    lb t6, 1(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v2, a6, t2, v8, v16
+
+    sh1add t5, a7, t3
+
+    vadd.vv v4, v28, v8
+    vadd.vv v28, v4, v16
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    lb t6, 0(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    li t6, 2
+    constrain_vectors v4, v6, v2, a6, t2, v8, v16
+
+    vmacc.vx v28, t6, v16
+    vmacc.vx v28, t6, v8
+
+    lb t6, 1(t5)
+
+    sh1add a4, t6, a0
+    slli t6, t6, 1
+    sub t6, a0, t6
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vle16.v v4, (a4)
+    vle16.v v6, (t6)
+
+    vminu.vv v20, v4, v20
+    vmax.vv v24, v4, v24
+    vminu.vv v20, v6, v20
+    vmax.vv v24, v6, v24
+
+    vwsub.vv v8, v4, v2
+    vwsub.vv v16, v6, v2
+
+    vsetvli zero, zero, e32, m2, ta, mu
+
+    constrain_vectors v4, v6, v2, a6, t2, v8, v16
+
+    vadd.vv v4, v28, v8
+    vadd.vv v28, v4, v16
+
+    vmslt.vx v0, v28, zero
+    vadd.vi v28, v28, -1, v0.t
+
+    vsetvli zero, zero, e16, m1, ta, ma
+
+    vnclip.wi v16, v28, 4
+
+    vadd.vv v28, v2, v16
+
+    vmslt.vv v0, v20, v28
+    vmerge.vvm v4, v20, v28, v0
+
+    vmslt.vv v0, v4, v24
+    vmerge.vvm v28, v24, v4, v0
+
+    vse16.v v28, (a2)
+
+    add a2, a2, a3
+    sh1add a0, a1, a0
+
+    addi t0, t0, -1
+    bnez t0, 3b
+
+    addi sp, sp, 32 + 144*2
+    ret
+endfunc
+.endm
+
+cdef_fn 4, 4
+cdef_fn 4, 8
+cdef_fn 8, 8
diff --git a/media/libdav1d/src/src/riscv/64/cpu.S b/media/libdav1d/src/src/riscv/64/cpu.S
new file mode 100644
index 0000000000..a81c6d8748
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/cpu.S
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+// This function detects non-compliant RVV 0.7.1 hardware which reports support
+//  for the V extension through HWCAP, by intentionally setting tail and mask
+//  agnostic vector configurations that were only introduced in RVV 0.9 spec.
+// Existing non-compliant (pre RVV 1.0) hardware will set the VILL bit in VTYPE
+//  (indicating an illegal vector configuration) which is stored in the XLEN-1
+//  bit position, thus a simple sign check is sufficient for detection.
+// This work around is inexpensive and harmless on compliant hardware, but we
+//  should still consider removing it once all non-compliant RVV 0.7.1 hardware
+//  is out of service.
+function has_compliant_rvv, export=1, ext=v
+  vsetvli t0, zero, e8, m1, ta, ma
+  csrr a0, vtype
+  sgtz a0, a0
+  ret
+endfunc
+
+function get_vlenb, export=1
+  csrr a0, vlenb
+  ret
+endfunc
diff --git a/media/libdav1d/src/src/riscv/64/ipred.S b/media/libdav1d/src/src/riscv/64/ipred.S
new file mode 100644
index 0000000000..c257350767
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/ipred.S
@@ -0,0 +1,508 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Bogdan Gligorijevic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+// void ipred_v_8bpc_rvv(pixel *dst, const ptrdiff_t stride,
+//                       const pixel *const topleft,
+//                       const int width, const int height, const int a,
+//                       const int max_width, const int max_height)
+function ipred_v_8bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    addi a2, a2, 1
+    vsetvli t0, a3, e8, m1, ta, ma
+    bne t0, a3, 3f  // Go to slow path - whole row doesn't fit in regsiter
+1:
+    // Fast path - row fits in register
+    add t1, a0, a1
+    vle8.v v4, (a2)
+2:
+    vse8.v v4, (a0)
+    sh1add a0, a1, a0
+    vse8.v v4, (t1)
+    sh1add t1, a1, t1
+    addi a4, a4, -2
+    bnez a4, 2b
+    ret
+
+    // Row doesn't fit in register.
+3:
+    vsetvli t0, a3, e8, m2, ta, ma  // Try using 2 registers at once (LMUL=2)
+    beq t0, a3, 1b  // Back to fast path - now it fits
+
+4:
+    // No need for more vsetli, since both width and VLEN are power of 2, so there is no tail.
+    vle8.v v4, (a2)
+    mv t2, a0
+    mv t1, a4
+5:
+    vse8.v v4, (t2)
+    add t2, t2, a1
+    addi t1, t1, -1
+    bnez t1, 5b  // Loop over rows.
+
+    sub a3, a3, t0
+    add a2, a2, t0
+    add a0, a0, t0
+    bnez a3, 4b  // Loop over columns
+
+    ret
+endfunc
+
+
+function dc_gen_8bpc_rvv, export=1, ext="v,zbb"
+    .variant_cc dav1d_dc_gen_8bpc_rvv
+    add t1, a1, a2
+    srli t5, t1, 1
+    mv t1, a1
+    addi t2, a0, 1
+    vsetvli zero, t1, e16, m4, ta, ma
+    vmv.v.x v0, zero
+1:
+    vsetvli t3, t1, e8, m2, tu, ma
+    vle8.v v4, (t2)
+    vwaddu.wv v0, v0, v4
+
+    sub t1, t1, t3
+    add t2, t2, t3
+    bnez t1, 1b
+
+    mv t1, a2
+    mv t2, a0
+    vsetvli zero, t1, e16, m4, ta, ma
+    vmv.v.x v8, zero
+2:
+    vsetvli t3, t1, e8, m2, tu, ma
+    sub t2, t2, t3
+    vle8.v v4, (t2)
+    vwaddu.wv v8, v8, v4
+    sub t1, t1, t3
+
+    bnez t1, 2b
+
+    vsetvli zero, zero, e32, m8, ta, ma
+    vmv.s.x v16, t5
+    vmv.s.x v12, zero
+    vsetvli zero, a1, e16, m4, ta, ma
+    vwredsum.vs v24, v0, v16
+    vsetvli zero, a2, e16, m4, ta, ma
+    vwredsum.vs v16, v8, v12
+    vsetvli zero, zero, e32, m8, ta, ma
+    vmv.x.s t5, v24
+    vmv.x.s t1, v16
+    add t5, t5, t1
+
+    add t1, a1, a2
+    ctz t1, t1
+
+    srl a0, t5, t1
+
+
+    beq a1, a2, 5f
+    slli t1, a1, 1
+    sltu t2, t1, a2
+    slli t3, a2, 1
+    sltu t1, t3, a1
+    or t1, t1, t2
+    bnez t1, 3f
+
+    li t1, 0x5556
+    j 4f
+3:
+    li t1, 0x3334
+4:
+    mul a0, a0, t1
+    srli a0, a0, 16
+5:
+    jr t0
+endfunc
+
+function dc_gen_top_8bpc_rvv, export=1, ext="v,zbb"
+    .variant_cc dav1d_dc_gen_top_8bpc_rvv
+    mv t1, a1
+    srli t5, a1, 1
+    addi a0, a0, 1
+    vsetvli zero, t1, e16, m4, ta, ma
+    vmv.v.x v0, zero
+1:
+    vsetvli t3, t1, e8, m2, tu, ma
+    vle8.v v4, (a0)
+    vwaddu.wv v0, v0, v4
+    sub t1, t1, t3
+
+    add a0, a0, t3
+    bnez t1, 1b
+    j dc_gen_sum_up_8bpc_rvv
+endfunc
+
+function dc_gen_left_8bpc_rvv, export=1, ext="v,zbb"
+    .variant_cc dav1d_dc_gen_left_8bpc_rvv
+    mv t1, a1
+    srli t5, a1, 1
+    vsetvli t2, t1, e16, m4, ta, ma
+    vmv.v.x v0, zero
+
+1:
+    vsetvli t3, t1, e8, m2, tu, ma
+    sub a0, a0, t3
+    vle8.v v4, (a0)
+    vwaddu.wv v0, v0, v4
+    sub t1, t1, t3
+    bnez t1, 1b
+
+    j dc_gen_sum_up_8bpc_rvv
+endfunc
+
+function dc_gen_sum_up_8bpc_rvv, export=1, ext="v,zbb"
+    .variant_cc dav1d_dc_gen_sum_up_8bpc_rvv
+    vsetvli zero, a1, e32, m8, ta, ma
+    vmv.s.x v4, t5
+    vsetvli zero, zero, e16, m4, ta, ma
+    vwredsum.vs v8, v0, v4
+    vsetvli zero, zero, e32, m8, ta, ma
+    vmv.x.s t5, v8
+
+    ctz t1, a1
+
+    srl a0, t5, t1
+    jr t0
+endfunc
+
+function cfl_pred_8bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+1:
+    li t2, 0
+    mv t3, a2
+2:
+    vsetvli t0, t3, e16, m2, ta, ma
+    add t4, a0, t2
+    vle16.v v0, (a5)
+    sh1add a5, t0, a5
+
+    vwmul.vx v4, v0, a6
+    vsetvli zero, zero, e32, m4, ta, mu
+    vneg.v v8, v4
+    vmslt.vx v0, v4, x0
+    vmax.vv v12, v8, v4
+    vssra.vi v16, v12, 6
+    vneg.v v16, v16, v0.t
+    vadd.vx v20, v16, a4
+    vmax.vx v0, v20, zero
+    vsetvli zero, zero, e16, m2, ta, ma
+    vnclipu.wi v4, v0, 0
+    vsetvli zero, zero, e8, m1, ta, ma
+    vnclipu.wi v0, v4, 0
+    vse8.v v0, (t4)
+    add t2, t0, t2
+    sub t3, t3, t0
+    bnez t3, 2b
+    addi a3, a3, -1
+    add a0, a0, a1
+
+    bnez a3, 1b
+    ret
+endfunc
+
+function ipred_cfl_8bpc_rvv, export=1, ext=v
+    mv t6, a0 # dst
+    mv a0, a2 # topleft
+    mv t4, a1 # stride
+    mv a1, a3 # width
+    mv a2, a4 # height
+    jal t0, dc_gen_8bpc_rvv
+    mv a2, a3 # width
+    mv a3, a4 # height
+    mv a4, a0 # dc_get_top
+    mv a0, t6 # dst
+    mv a1, t4 # stride
+    j cfl_pred_8bpc_rvv
+endfunc
+
+function ipred_cfl_128_8bpc_rvv, export=1, ext="v,zba"
+    # dc = 128, then just rearrange registers
+    mv a2, a3
+    mv a3, a4
+    li a4, 128
+
+    j cfl_pred_8bpc_rvv
+endfunc
+
+function ipred_cfl_top_8bpc_rvv, export=1, ext=v
+    mv t6, a0 # dst
+    mv a0, a2 # topleft
+    mv t4, a1 # stride
+    mv a1, a3 # width
+    jal t0, dc_gen_top_8bpc_rvv
+    mv a3, a4 # height
+    mv a4, a0 # dc_get_top
+    mv a0, t6 # dst
+    mv a2, a1 # width
+    mv a1, t4 # stride
+    j cfl_pred_8bpc_rvv
+endfunc
+
+function ipred_cfl_left_8bpc_rvv, export=1, ext="v,zba"
+    mv t6, a0 # dst
+    mv a0, a2 # topleft
+    mv t4, a1 # stride
+    mv a1, a4 # height
+    mv a2, a3 # width
+    jal t0, dc_gen_left_8bpc_rvv
+    mv a3, a4 # height
+    mv a4, a0 # dc_get_left
+    mv a1, t4 # stride
+    mv a0, t6 # dst
+    j cfl_pred_8bpc_rvv
+endfunc
+
+function ipred_paeth_8bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    li t0, 0
+    mv t3, a2
+    lbu t1, (a2)
+    addi a6, a2, -1
+    addi a2, a2, 1
+1:
+    lbu t2, (a6)
+    mv t3, a3
+2:
+    sub t5, a3, t3
+    add t5, a2, t5
+    vsetvli t6, t3, e8, m1, ta, ma
+    vle8.v v2, (t5)
+    vwaddu.vx v4, v2, t2
+    vsetvli zero, zero, e16, m2, ta, ma
+    vwsub.vx v8, v4, t1
+
+    vsetvli zero, zero, e32, m4, ta, mu
+    vzext.vf4 v24, v2
+    vsub.vx v12, v8, t1
+    vmslt.vx v0, v12, zero
+    vneg.v v12, v12, v0.t
+    vsub.vx v16, v8, t2
+    vmslt.vx v0, v16, zero
+    vneg.v v16, v16, v0.t
+    vsub.vv v20, v8, v24
+    vmslt.vx v0, v20, zero
+    vneg.v v20, v20, v0.t
+
+    sub t5, a3, t3
+    vmsleu.vv v4, v16, v20
+    vmsleu.vv v5, v16, v12
+    vmsgtu.vv v0, v20, v12
+    vmand.mm v6, v4, v5
+
+    vsetvli zero, zero, e8, m1, ta, ma
+    vmerge.vxm v8, v2, t1, v0
+    vmmv.m v0, v6
+    add t5, a0, t5
+    sub t3, t3, t6
+    vmerge.vxm v4, v8, t2, v0
+
+    vse8.v v4, (t5)
+
+    bnez t3, 2b
+
+    addi a4, a4, -1
+    addi a6, a6, -1
+    add a0, a0, a1
+    bnez a4, 1b
+    ret
+endfunc
+
+function ipred_smooth_8bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    la t0, dav1d_sm_weights
+    add t1, t0, a3
+    add t2, a2, a3
+    add t0, t0, a4
+    lbu t2, (t2)
+    sub t3, a2, a4
+    addi a6, a2, -1
+    addi a2, a2, 1
+    lbu t3, (t3)
+1:
+    mv t6, a3
+
+    lbu a7, (a6)
+    lbu t4, (t0)
+2:
+    li a5, 256
+    vsetvli t5, t6, e8, m1, ta, ma
+    vle8.v v2, (t1)
+    add t1, t1, t5
+    vle8.v v4, (a2)
+    add a2, a2, t5
+    sub a5, a5, t4
+
+    vwmulu.vx v8, v4, t4
+    vsetvli zero, zero, e16, m2, ta, ma
+    mul a5, a5, t3
+
+    vadd.vx v4, v8, a5
+    vsetvli zero, zero, e8, m1, ta, ma
+    vwmulu.vx v8, v2, a7
+
+    vneg.v v12, v2
+    vwmaccu.vx v8, t2, v12
+    vsetvli zero, zero, e16, m2, ta, ma
+    vwaddu.vv v12, v4, v8
+
+    sub a5, a3, t6
+    sub t6, t6, t5
+    add a5, a5, a0
+    vnclipu.wi v2, v12, 9
+    vsetvli zero, zero, e8, m1, ta, ma
+    vnclipu.wi v0, v2, 0
+    vse8.v v0, (a5)
+
+    bnez t6, 2b
+
+    sub t1, t1, a3
+    add a0, a0, a1
+    sub a2, a2, a3
+    addi a4, a4, -1
+    addi t0, t0, 1
+    addi a6, a6, -1
+    bnez a4, 1b
+
+    ret
+endfunc
+
+function ipred_smooth_v_8bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    la t0, dav1d_sm_weights
+    add t2, a2, a3
+    add t0, t0, a4
+    sub t3, a2, a4
+    addi a2, a2, 1
+    lbu t3, (t3)
+1:
+    mv t6, a3
+
+    lbu t4, (t0)
+2:
+    li a5, 256
+    vsetvli t5, t6, e8, m1, ta, ma
+    vle8.v v4, (a2)
+    add a2, a2, t5
+    sub a5, a5, t4
+
+    vwmulu.vx v8, v4, t4
+    vsetvli zero, zero, e16, m2, ta, ma
+    mul a5, a5, t3
+    vwaddu.vx v4, v8, a5
+
+    sub a5, a3, t6
+    sub t6, t6, t5
+    add a5, a5, a0
+    vsetvli zero, zero, e16, m2, ta, ma
+    vnclipu.wi v2, v4, 8
+    vsetvli zero, zero, e8, m1, ta, ma
+    vnclipu.wi v0, v2, 0
+    vse8.v v0, (a5)
+
+    bnez t6, 2b
+
+    add a0, a0, a1
+    sub a2, a2, a3
+    addi a4, a4, -1
+    addi t0, t0, 1
+    bnez a4, 1b
+
+    ret
+endfunc
+
+function ipred_smooth_h_8bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    la t0, dav1d_sm_weights
+    add t1, t0, a3
+    add t2, a2, a3
+    lbu t2, (t2)
+    addi a6, a2, -1
+1:
+    mv t6, a3
+
+    lbu a7, (a6)
+2:
+    vsetvli t5, t6, e8, m1, ta, ma
+    vle8.v v2, (t1)
+    add t1, t1, t5
+
+    vwmulu.vx v8, v2, a7
+
+    vneg.v v12, v2
+    vwmaccu.vx v8, t2, v12
+
+    sub a5, a3, t6
+    sub t6, t6, t5
+    add a5, a5, a0
+    vsetvli zero, zero, e8, m1, ta, ma
+    vnclipu.wi v0, v8, 8
+    vse8.v v0, (a5)
+
+    bnez t6, 2b
+
+    sub t1, t1, a3
+    add a0, a0, a1
+    addi a4, a4, -1
+    addi a6, a6, -1
+    bnez a4, 1b
+
+    ret
+endfunc
+
+function pal_pred_8bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    vsetivli t5, 8, e8, m1, ta, ma
+    vle8.v v30, (a2)
+    li t0, 2
+    srli t1, a4, 1
+1:
+    mv t4, a4
+2:
+    vsetvli t5, t1, e8, m1, ta, ma
+    vle8.v v0, (a3)
+    add a3, a3, t5
+    vsrl.vi v2, v0, 4
+    sub t6, a4, t4
+    vand.vi v1, v0, 7
+    add t6, a0, t6
+    vrgather.vv v3, v30, v1
+    addi t2, t6, 1
+    vrgather.vv v4, v30, v2
+    slli t5, t5, 1
+    vsse8.v v3, (t6), t0
+    sub t4, t4, t5
+    vsse8.v v4, (t2), t0
+
+    bnez t4, 2b
+    addi a5, a5, -1
+    add a0, a0, a1
+    bnez a5, 1b
+    ret
+endfunc
diff --git a/media/libdav1d/src/src/riscv/64/ipred16.S b/media/libdav1d/src/src/riscv/64/ipred16.S
new file mode 100644
index 0000000000..4ac6acf1cf
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/ipred16.S
@@ -0,0 +1,471 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Bogdan Gligorijevic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+function dc_gen_16bpc_rvv, export=1, ext="v,zba,zbb"
+    .variant_cc dav1d_dc_gen_16bpc_rvv
+    add t1, a1, a2
+    srli t5, t1, 1
+    mv t1, a1
+    addi t2, a0, 2
+    vsetvli zero, t1, e32, m8, ta, ma
+    vmv.v.x v0, zero
+1:
+    vsetvli t3, t1, e16, m4, tu, ma
+    vle16.v v8, (t2)
+    vwaddu.wv v0, v0, v8
+    sub t1, t1, t3
+
+    sh1add t2, t3, t2
+    bnez t1, 1b
+
+    mv t1, a2
+    mv t2, a0
+    vsetvli zero, t1, e32, m8, ta, ma
+    vmv.v.x v16, zero
+2:
+    vsetvli t3, t1, e16, m4, tu, ma
+    sub t1, t1, t3
+    sll t3, t3, 1
+    sub t2, t2, t3
+    vle16.v v8, (t2)
+    vwaddu.wv v16, v16, v8
+
+    bnez t1, 2b
+
+    vsetvli zero, a1, e32, m8, ta, ma
+    vmv.s.x v24, t5
+    vmv.s.x v25, zero
+    vredsum.vs v8, v0, v24
+    vsetvli zero, a2, e32, m8, ta, ma
+    vredsum.vs v0, v16, v25
+    vmv.x.s t5, v8
+    vmv.x.s t1, v0
+    add t5, t5, t1
+
+    add t1, a1, a2
+    ctz t1, t1
+
+    srl a0, t5, t1
+
+    beq a1, a2, 5f
+    slli t1, a1, 1
+    sltu t2, t1, a2
+    slli t3, a2, 1
+    sltu t1, t3, a1
+    or t1, t1, t2
+    bnez t1, 3f
+
+    li t1, 0xAAAB
+    j 4f
+3:
+    li t1, 0x6667
+4:
+    mul a0, a0, t1
+    li t1, 17
+    srl a0, a0, t1
+5:
+    jr t0
+endfunc
+
+function dc_gen_top_16bpc_rvv, export=1, ext="v,zba,zbb"
+    .variant_cc dav1d_dc_gen_top_16bpc_rvv
+    mv t1, a1
+    srli t5, a1, 1
+    addi a0, a0, 2
+    vsetvli zero, t1, e32, m2, ta, ma
+    vmv.v.x v0, zero
+1:
+    vsetvli t3, t1, e16, m1, tu, ma
+    vle16.v v4, (a0)
+    vwaddu.wv v0, v0, v4
+
+    sh1add a0, t3, a0
+    sub t1, t1, t3
+    bnez t1, 1b
+
+    j dc_gen_sum_up_16bpc_rvv
+endfunc
+
+function dc_gen_left_16bpc_rvv, export=1, ext="v,zba,zbb"
+    .variant_cc dav1d_dc_gen_left_16bpc_rvv
+    mv t1, a1
+    srli t5, a1, 1
+    vsetvli zero, t1, e32, m2, ta, ma
+    vmv.v.x v0, zero
+1:
+    vsetvli t3, t1, e16, m1, tu, ma
+    sub t1, t1, t3
+    slli t3, t3, 1
+    sub a0, a0, t3
+    vle16.v v4, (a0)
+    vwaddu.wv v0, v0, v4
+
+    bnez t1, 1b
+
+    j dc_gen_sum_up_16bpc_rvv
+endfunc
+
+function dc_gen_sum_up_16bpc_rvv, export=1, ext="v,zba,zbb"
+    .variant_cc dav1d_dc_gen_sum_up_16bpc_rvv
+
+    vsetvli zero, a1, e32, m2, ta, ma
+    vmv.s.x v4, t5
+    vredsum.vs v8, v0, v4
+    vmv.x.s t5, v8
+
+    ctz t1, a1
+
+    srl a0, t5, t1
+    jr t0
+endfunc
+
+function cfl_pred_16bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+1:
+    li t2, 0
+    mv t3, a2
+2:
+    vsetvli t0, t3, e16, m2, ta, ma
+    sh1add t4, t2, a0
+    vle16.v v0, (a5)
+    sh1add a5, t0, a5
+
+    vwmul.vx v4, v0, a6
+    vsetvli zero, zero, e32, m4, ta, mu
+    vneg.v v8, v4
+    vmslt.vx v0, v4, x0
+    vmax.vv v12, v8, v4
+    vssra.vi v16, v12, 6
+    vneg.v v16, v16, v0.t
+    vadd.vx v20, v16, a4
+    vmax.vx v0, v20, zero
+    vmin.vx v0, v0, a7
+    vsetvli zero, zero, e16, m2, ta, ma
+    vnclipu.wi v4, v0, 0
+    vse16.v v4, (t4)
+    add t2, t0, t2
+    sub t3, t3, t0
+    bnez t3, 2b
+    addi a3, a3, -1
+    add a0, a0, a1
+
+    bnez a3, 1b
+    ret
+endfunc
+
+function ipred_cfl_16bpc_rvv, export=1, ext=v
+    mv t6, a0 # dst
+    mv a0, a2 # topleft
+    mv t4, a1 # stride
+    mv a1, a3 # width
+    mv a2, a4 # height
+    jal t0, dc_gen_16bpc_rvv
+    mv a2, a3 # width
+    mv a3, a4 # height
+    mv a4, a0 # dc_get_top
+    mv a0, t6 # dst
+    mv a1, t4 # stride
+    j cfl_pred_16bpc_rvv
+endfunc
+
+function ipred_cfl_128_16bpc_rvv, export=1, ext="v,zba"
+    # dc = (bitdepth_max + 1) >> 1, then just rearrange registers
+    mv a2, a3
+    mv a3, a4
+    addi a4, a7, 1
+    srli a4, a4, 1
+
+    j cfl_pred_16bpc_rvv
+endfunc
+
+function ipred_cfl_top_16bpc_rvv, export=1, ext=v
+    mv t6, a0 # dst
+    mv a0, a2 # topleft
+    mv t4, a1 # stride
+    mv a1, a3 # width
+    jal t0, dc_gen_top_16bpc_rvv
+    mv a3, a4 # height
+    mv a4, a0 # dc_get_top
+    mv a0, t6 # dst
+    mv a2, a1 # width
+    mv a1, t4 # stride
+    j cfl_pred_16bpc_rvv
+endfunc
+
+function ipred_cfl_left_16bpc_rvv, export=1, ext=v
+    mv t6, a0 # dst
+    mv a0, a2 # topleft
+    mv t4, a1 # stride
+    mv a1, a4 # height
+    mv a2, a3 # width
+    jal t0, dc_gen_left_16bpc_rvv
+    mv a3, a4 # height
+    mv a4, a0 # dc_get_top
+    mv a1, t4 # stride
+    mv a0, t6 # dst
+    j cfl_pred_16bpc_rvv
+endfunc
+
+function ipred_paeth_16bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    li t0, 0
+    mv t3, a2
+    lhu t1, (a2)
+    addi a6, a2, -2
+    addi a2, a2, 2
+1:
+    lhu t2, (a6)
+    mv t3, a3
+2:
+    sub t5, a3, t3
+    sh1add t5, t5, a2
+    vsetvli t6, t3, e16, m2, ta, ma
+    vle16.v v2, (t5)
+    vwaddu.vx v4, v2, t2
+
+    vsetvli zero, zero, e32, m4, ta, mu
+    vsub.vx v8, v4, t1
+    vzext.vf2 v24, v2
+    vsub.vx v12, v8, t1
+    vmslt.vx v0, v12, zero
+    vneg.v v12, v12, v0.t
+    vsub.vx v16, v8, t2
+    vmslt.vx v0, v16, zero
+    vneg.v v16, v16, v0.t
+    vsub.vv v20, v8, v24
+    vmslt.vx v0, v20, zero
+    vneg.v v20, v20, v0.t
+
+    sub t5, a3, t3
+    vmsleu.vv v4, v16, v20
+    vmsleu.vv v5, v16, v12
+    vmsgtu.vv v0, v20, v12
+    vmand.mm v6, v4, v5
+
+    vsetvli zero, zero, e16, m2, ta, ma
+    vmerge.vxm v8, v2, t1, v0
+    vmmv.m v0, v6
+    sh1add t5, t5, a0
+    sub t3, t3, t6
+    vmerge.vxm v4, v8, t2, v0
+
+    vse16.v v4, (t5)
+
+    bnez t3, 2b
+
+    addi a4, a4, -1
+    addi a6, a6, -2
+    add a0, a0, a1
+    bnez a4, 1b
+    ret
+endfunc
+
+function ipred_smooth_16bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    la t0, dav1d_sm_weights
+    add t1, t0, a3
+    sh1add t2, a3, a2
+    slli t3, a4, 1
+    add t0, t0, a4
+    lhu t2, (t2)
+    sub t3, a2, t3
+    addi a6, a2, -2
+    addi a2, a2, 2
+    lhu t3, (t3)
+1:
+    mv t6, a3
+
+    lhu a7, (a6)
+    lbu t4, (t0)
+2:
+    li a5, 256
+    vsetvli t5, t6, e16, m2, ta, ma
+    vle8.v v2, (t1)
+    add t1, t1, t5
+    vle16.v v4, (a2)
+    sh1add a2, t5, a2
+    sub a5, a5, t4
+
+    vwmul.vx v8, v4, t4
+    mul a5, a5, t3
+
+    vsetvli zero, zero, e32, m4, ta, ma
+    vadd.vx v4, v8, a5
+
+    li a5, 256
+    vzext.vf4 v12, v2
+    vmul.vx v8, v12, a7
+
+    vrsub.vx v12, v12, a5
+    vmacc.vx v8, t2, v12
+    vadd.vv v12, v4, v8
+    vsetvli zero, zero, e32, m4, ta, ma
+
+    sub a5, a3, t6
+    sub t6, t6, t5
+    sh1add a5, a5, a0
+    vsetvli zero, zero, e16, m2, ta, ma
+    vnclipu.wi v2, v12, 9
+    vse16.v v2, (a5)
+
+    bnez t6, 2b
+
+    sub t1, t1, a3
+    slli t6, a3, 1
+    add a0, a0, a1
+    sub a2, a2, t6
+    addi a4, a4, -1
+    addi t0, t0, 1
+    addi a6, a6, -2
+    bnez a4, 1b
+
+    ret
+endfunc
+
+function ipred_smooth_v_16bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    la t0, dav1d_sm_weights
+    slli t3, a4, 1
+    add t0, t0, a4
+    sub t3, a2, t3
+    addi a2, a2, 2
+    lhu t3, (t3)
+1:
+    mv t6, a3
+
+    lbu t4, (t0)
+2:
+    li a5, 256
+    vsetvli t5, t6, e16, m2, ta, ma
+    vle16.v v4, (a2)
+    sh1add a2, t5, a2
+    sub a5, a5, t4
+
+    vwmul.vx v8, v4, t4
+    mul a5, a5, t3
+
+    vsetvli zero, zero, e32, m4, ta, ma
+    vadd.vx v4, v8, a5
+    vsetvli zero, zero, e32, m4, ta, ma
+
+    sub a5, a3, t6
+    sub t6, t6, t5
+    sh1add a5, a5, a0
+    vsetvli zero, zero, e16, m2, ta, ma
+    vnclipu.wi v2, v4, 8
+    vse16.v v2, (a5)
+
+    bnez t6, 2b
+
+    slli t6, a3, 1
+    add a0, a0, a1
+    sub a2, a2, t6
+    addi a4, a4, -1
+    addi t0, t0, 1
+    bnez a4, 1b
+
+    ret
+endfunc
+
+function ipred_smooth_h_16bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    la t0, dav1d_sm_weights
+    add t1, t0, a3
+    sh1add t2, a3, a2
+    lhu t2, (t2)
+    addi a6, a2, -2
+1:
+    mv t6, a3
+
+    lhu a7, (a6)
+2:
+    vsetvli t5, t6, e16, m2, ta, ma
+    vle8.v v2, (t1)
+    add t1, t1, t5
+
+    li a5, 256
+    vsetvli zero, zero, e32, m4, ta, ma
+    vzext.vf4 v12, v2
+    vmul.vx v8, v12, a7
+
+    vrsub.vx v12, v12, a5
+    vmacc.vx v8, t2, v12
+
+    sub a5, a3, t6
+    sub t6, t6, t5
+    sh1add a5, a5, a0
+    vsetvli zero, zero, e16, m2, ta, ma
+    vnclipu.wi v2, v8, 8
+    vse16.v v2, (a5)
+
+    bnez t6, 2b
+
+    sub t1, t1, a3
+    add a0, a0, a1
+    addi a4, a4, -1
+    addi a6, a6, -2
+    bnez a4, 1b
+
+    ret
+endfunc
+
+function pal_pred_16bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+    vsetivli t5, 8, e16, m1, ta, ma
+    vle16.v v30, (a2)
+    li t0, 4
+    srli t1, a4, 1
+    li t2, 1
+1:
+    mv t4, a4
+2:
+    vsetvli t5, t1, e8, mf2, ta, ma
+    vle8.v v0, (a3)
+    add a3, a3, t5
+    vand.vi v1, v0, 7
+    sub t6, a4, t4
+    vsrl.vi v2, v0, 4
+    vwmul.vx v4, v1, t2
+    vwmul.vx v6, v2, t2
+    vsetvli zero, zero, e16, m1, ta, ma
+    sh1add t6, t6, a0
+    vrgather.vv v8, v30, v4
+    addi t3, t6, 2
+    vrgather.vv v10, v30, v6
+    slli t5, t5, 1
+    vsse16.v v8, (t6), t0
+    vsse16.v v10, (t3), t0
+
+    sub t4, t4, t5
+    bnez t4, 2b
+    add a0, a0, a1
+    addi a5, a5, -1
+    bnez a5, 1b
+    ret
+endfunc
diff --git a/media/libdav1d/src/src/riscv/64/itx.S b/media/libdav1d/src/src/riscv/64/itx.S
new file mode 100644
index 0000000000..e7e99155e5
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/itx.S
@@ -0,0 +1,2071 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2023, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+function inv_txfm_add_4x4_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 4, e16, mf2, ta, ma
+  vle16.v v0, (a2)
+  addi t0, a2, 8
+  vle16.v v1, (t0)
+  addi t0, t0, 8
+  vle16.v v2, (t0)
+  addi t0, t0, 8
+  vle16.v v3, (t0)
+
+  jalr t0, a4
+
+  vmv.v.x v4, zero
+
+  vsseg4e16.v v0, (a2)
+  vle16.v v0, (a2)
+  vse16.v v4, (a2)
+  addi t0, a2, 8
+  vle16.v v1, (t0)
+  vse16.v v4, (t0)
+  addi t0, t0, 8
+  vle16.v v2, (t0)
+  vse16.v v4, (t0)
+  addi t0, t0, 8
+  vle16.v v3, (t0)
+  vse16.v v4, (t0)
+
+  jalr t0, a5
+
+  vssra.vi v0, v0, 4
+  vssra.vi v1, v1, 4
+  vssra.vi v2, v2, 4
+  vssra.vi v3, v3, 4
+
+itx_4x4_end:
+  vsetvli zero, zero, e8, mf4, ta, ma
+  vle8.v v4, (a0)
+  add t0, a0, a1
+  vle8.v v5, (t0)
+  add t0, t0, a1
+  vle8.v v6, (t0)
+  add t0, t0, a1
+  vle8.v v7, (t0)
+
+  vwaddu.wv v0, v0, v4
+  vwaddu.wv v1, v1, v5
+  vwaddu.wv v2, v2, v6
+  vwaddu.wv v3, v3, v7
+
+  vsetvli zero, zero, e16, mf2, ta, ma
+  vmax.vx v0, v0, zero
+  vmax.vx v1, v1, zero
+  vmax.vx v2, v2, zero
+  vmax.vx v3, v3, zero
+
+  vsetvli zero, zero, e8, mf4, ta, ma
+
+  vnclipu.wi v4, v0, 0
+  vnclipu.wi v5, v1, 0
+  vnclipu.wi v6, v2, 0
+  vnclipu.wi v7, v3, 0
+
+  vse8.v v4, (a0)
+  add a0, a0, a1
+  vse8.v v5, (a0)
+  add a0, a0, a1
+  vse8.v v6, (a0)
+  add a0, a0, a1
+  vse8.v v7, (a0)
+
+  ret
+endfunc
+
+function inv_identity_e16_x4_rvv, export=1, ext=v
+  li t1, (5793-4096)*8
+  vsmul.vx v4, v0, t1
+  vsmul.vx v5, v1, t1
+  vsmul.vx v6, v2, t1
+  vsmul.vx v7, v3, t1
+
+  vsadd.vv v0, v0, v4
+  vsadd.vv v1, v1, v5
+  vsadd.vv v2, v2, v6
+  vsadd.vv v3, v3, v7
+
+  jr t0
+endfunc
+
+.macro iwht_4
+  vadd.vv v0, v0, v1
+  vsub.vv v5, v2, v3
+  vsub.vv v4, v0, v5
+  vsra.vi v4, v4, 1
+  vsub.vv v2, v4, v1
+  vsub.vv v1, v4, v3
+  vadd.vv v3, v5, v2
+  vsub.vv v0, v0, v1
+.endm
+
+.macro idct_4 o0, o1, o2, o3
+  li t1, 2896
+  li t2, 1567
+  li t3, 3784
+
+  vwmul.vx v16, \o0, t1
+  vwmul.vx v18, \o0, t1
+  vwmacc.vx v16, t1, \o2
+  neg t1, t1
+  vwmacc.vx v18, t1, \o2
+
+  vwmul.vx v20, \o1, t3
+  neg t3, t3
+  vwmul.vx v22, \o1, t2
+  vwmacc.vx v20, t2, \o3
+  vwmacc.vx v22, t3, \o3
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+  vnclip.wi v22, v22, 12
+
+  vsadd.vv \o0, v16, v20
+  vsadd.vv \o1, v18, v22
+  vssub.vv \o2, v18, v22
+  vssub.vv \o3, v16, v20
+.endm
+
+.macro iadst_4 o0, o1, o2, o3, lm2, lm
+  li t1, 1321
+  li t2, 3803
+  li t3, 2482
+
+  vwmul.vx v16, v0, t1
+  vwmul.vx v18, v0, t3
+  neg t1, t1
+  vwmacc.vx v16, t2, v2
+  vwmacc.vx v18, t1, v2
+  neg t2, t2
+  vwmacc.vx v16, t3, v3
+  vwmacc.vx v18, t2, v3
+
+  vwsub.vv v20,  v0, v2
+  vwadd.wv v20, v20, v3
+
+  li t1, 3344
+  vwmul.vx v22, v1, t1
+
+  vsetvli zero, zero, e32, \lm2, ta, ma
+
+  vmul.vx v20, v20, t1
+
+  vadd.vv v24, v16, v18
+  vadd.vv v16, v16, v22
+  vadd.vv v18, v18, v22
+  vsub.vv v22, v24, v22
+
+  vsetvli zero, zero, e16, \lm, ta, ma
+
+  vnclip.wi \o0, v16, 12
+  vnclip.wi \o1, v18, 12
+  vnclip.wi \o2, v20, 12
+  vnclip.wi \o3, v22, 12
+.endm
+
+function inv_dct_e16_x4_rvv, export=1, ext=v
+  idct_4 v0, v1, v2, v3
+  jr t0
+endfunc
+
+function inv_adst_e16_x4_rvv, export=1, ext=v
+  iadst_4 v0, v1, v2, v3, m1, mf2
+  jr t0
+endfunc
+
+function inv_flipadst_e16_x4_rvv, export=1, ext=v
+  iadst_4 v3, v2, v1, v0, m1, mf2
+  jr t0
+endfunc
+
+function inv_adst_e16_x4w_rvv, export=1, ext=v
+  iadst_4 v0, v1, v2, v3, m2, m1
+  jr t0
+endfunc
+
+function inv_flipadst_e16_x4w_rvv, export=1, ext=v
+  iadst_4 v3, v2, v1, v0, m2, m1
+  jr t0
+endfunc
+
+function inv_txfm_add_wht_wht_4x4_8bpc_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 4, e16, mf2, ta, ma
+  vle16.v v0, (a2)
+  addi t0, a2, 8
+  vle16.v v1, (t0)
+  addi t0, t0, 8
+  vle16.v v2, (t0)
+  addi t0, t0, 8
+  vle16.v v3, (t0)
+
+  vsra.vi v0, v0, 2
+  vsra.vi v1, v1, 2
+  vsra.vi v2, v2, 2
+  vsra.vi v3, v3, 2
+
+  iwht_4
+
+  vmv.v.x v4, zero
+
+  vsseg4e16.v v0, (a2)
+  vle16.v v0, (a2)
+  vse16.v v4, (a2)
+  addi t0, a2, 8
+  vle16.v v1, (t0)
+  vse16.v v4, (t0)
+  addi t0, t0, 8
+  vle16.v v2, (t0)
+  vse16.v v4, (t0)
+  addi t0, t0, 8
+  vle16.v v3, (t0)
+  vse16.v v4, (t0)
+
+  iwht_4
+
+  j itx_4x4_end
+endfunc
+
+.macro def_fn_4x4 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_4x4_8bpc_rvv, export=1, ext=v
+.ifc \txfm1\()_\txfm2, dct_dct
+  beqz a3, 1f
+.endif
+  la a4, inv_\txfm1\()_e16_x4_rvv
+  la a5, inv_\txfm2\()_e16_x4_rvv
+  j inv_txfm_add_4x4_rvv
+.ifc \txfm1\()_\txfm2, dct_dct
+1:
+  csrw vxrm, zero
+  vsetivli zero, 4, e16, mf2, ta, ma
+  ld t2, (a2)
+  li t1, 2896*8
+  vmv.v.x v0, t2
+  vsmul.vx v0, v0, t1
+  sd x0, (a2)
+  vsmul.vx v0, v0, t1
+  vssra.vi v0, v0, 4
+  vmv.v.v v1, v0
+  vmv.v.v v2, v0
+  vmv.v.v v3, v0
+  j itx_4x4_end
+.endif
+endfunc
+.endm
+
+def_fn_4x4 dct, dct
+def_fn_4x4 identity, identity
+def_fn_4x4 dct, adst
+def_fn_4x4 dct, flipadst
+def_fn_4x4 dct, identity
+def_fn_4x4 adst, dct
+def_fn_4x4 adst, adst
+def_fn_4x4 adst, flipadst
+def_fn_4x4 flipadst, dct
+def_fn_4x4 flipadst, adst
+def_fn_4x4 flipadst, flipadst
+def_fn_4x4 identity, dct
+def_fn_4x4 adst, identity
+def_fn_4x4 flipadst, identity
+def_fn_4x4 identity, adst
+def_fn_4x4 identity, flipadst
+
+.macro def_fn_8x8_base variant
+function inv_txfm_\variant\()add_8x8_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 8, e16, m1, ta, ma
+  vle16.v v0, (a2)
+  addi t0, a2, 16
+  vle16.v v1, (t0)
+  addi t0, t0, 16
+  vle16.v v2, (t0)
+  addi t0, t0, 16
+  vle16.v v3, (t0)
+  addi t0, t0, 16
+  vle16.v v4, (t0)
+  addi t0, t0, 16
+  vle16.v v5, (t0)
+  addi t0, t0, 16
+  vle16.v v6, (t0)
+  addi t0, t0, 16
+  vle16.v v7, (t0)
+
+.ifc \variant, identity_
+  // The identity vsadd.vv and downshift vssra.vi 1 cancel out
+
+  j L(itx_8x8_epilog)
+.else
+  jalr t0, a4
+
+  vssra.vi v0, v0, 1
+  vssra.vi v1, v1, 1
+  vssra.vi v2, v2, 1
+  vssra.vi v3, v3, 1
+  vssra.vi v4, v4, 1
+  vssra.vi v5, v5, 1
+  vssra.vi v6, v6, 1
+  vssra.vi v7, v7, 1
+
+L(itx_8x8_epilog):
+  vsseg8e16.v v0, (a2)
+  vle16.v v0, (a2)
+  addi t0, a2, 16
+  vle16.v v1, (t0)
+  addi t0, t0, 16
+  vle16.v v2, (t0)
+  addi t0, t0, 16
+  vle16.v v3, (t0)
+  addi t0, t0, 16
+  vle16.v v4, (t0)
+  addi t0, t0, 16
+  vle16.v v5, (t0)
+  addi t0, t0, 16
+  vle16.v v6, (t0)
+  addi t0, t0, 16
+  vle16.v v7, (t0)
+
+  jalr t0, a5
+
+  vssra.vi v0, v0, 4
+  vssra.vi v1, v1, 4
+  vssra.vi v2, v2, 4
+  vssra.vi v3, v3, 4
+  vssra.vi v4, v4, 4
+  vssra.vi v5, v5, 4
+  vssra.vi v6, v6, 4
+  vssra.vi v7, v7, 4
+
+  li t1, 64
+  vsetvli zero, t1, e16, m8, ta, ma
+  vmv.v.x v8, zero
+  vse16.v v8, (a2)
+
+itx_8x8_end:
+  vsetivli zero, 8, e8, mf2, ta, ma
+  vle8.v v8, (a0)
+  add t0, a0, a1
+  vle8.v v9, (t0)
+  add t0, t0, a1
+  vle8.v v10, (t0)
+  add t0, t0, a1
+  vle8.v v11, (t0)
+  add t0, t0, a1
+  vle8.v v12, (t0)
+  add t0, t0, a1
+  vle8.v v13, (t0)
+  add t0, t0, a1
+  vle8.v v14, (t0)
+  add t0, t0, a1
+  vle8.v v15, (t0)
+
+  vwaddu.wv v0, v0, v8
+  vwaddu.wv v1, v1, v9
+  vwaddu.wv v2, v2, v10
+  vwaddu.wv v3, v3, v11
+  vwaddu.wv v4, v4, v12
+  vwaddu.wv v5, v5, v13
+  vwaddu.wv v6, v6, v14
+  vwaddu.wv v7, v7, v15
+
+  vsetvli zero, zero, e16, m1, ta, ma
+  vmax.vx v0, v0, zero
+  vmax.vx v1, v1, zero
+  vmax.vx v2, v2, zero
+  vmax.vx v3, v3, zero
+  vmax.vx v4, v4, zero
+  vmax.vx v5, v5, zero
+  vmax.vx v6, v6, zero
+  vmax.vx v7, v7, zero
+
+  vsetvli zero, zero, e8, mf2, ta, ma
+
+  vnclipu.wi v8, v0, 0
+  vnclipu.wi v9, v1, 0
+  vnclipu.wi v10, v2, 0
+  vnclipu.wi v11, v3, 0
+  vnclipu.wi v12, v4, 0
+  vnclipu.wi v13, v5, 0
+  vnclipu.wi v14, v6, 0
+  vnclipu.wi v15, v7, 0
+
+  vse8.v v8, (a0)
+  add a0, a0, a1
+  vse8.v v9, (a0)
+  add a0, a0, a1
+  vse8.v v10, (a0)
+  add a0, a0, a1
+  vse8.v v11, (a0)
+  add a0, a0, a1
+  vse8.v v12, (a0)
+  add a0, a0, a1
+  vse8.v v13, (a0)
+  add a0, a0, a1
+  vse8.v v14, (a0)
+  add a0, a0, a1
+  vse8.v v15, (a0)
+
+  ret
+.endif
+endfunc
+.endm
+
+def_fn_8x8_base identity_
+def_fn_8x8_base
+
+function inv_identity_e16_x8_rvv, export=1, ext=v
+  vsadd.vv v0, v0, v0
+  vsadd.vv v1, v1, v1
+  vsadd.vv v2, v2, v2
+  vsadd.vv v3, v3, v3
+  vsadd.vv v4, v4, v4
+  vsadd.vv v5, v5, v5
+  vsadd.vv v6, v6, v6
+  vsadd.vv v7, v7, v7
+
+  jr t0
+endfunc
+
+.macro idct_8 o0, o1, o2, o3, o4, o5, o6, o7
+  idct_4 \o0, \o2, \o4, \o6
+
+  li t1, 799
+  li t2, 4017
+  li t3, 3406
+  li t4, 2276
+
+  vwmul.vx v22, \o1, t2
+  neg t2, t2
+  vwmul.vx v16, \o1, t1
+  vwmacc.vx v22, t1, \o7
+  vwmacc.vx v16, t2, \o7
+
+  vwmul.vx v20, \o5, t4
+  neg t4, t4
+  vwmul.vx v18, \o5, t3
+  vwmacc.vx v20, t3, \o3
+  vwmacc.vx v18, t4, \o3
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+  vnclip.wi v22, v22, 12
+
+  vssub.vv \o7, v22, v20
+  vsadd.vv v22, v22, v20
+  vssub.vv \o1, v16, v18
+  vsadd.vv v16, v16, v18
+
+  li t2, 2896
+
+  vwmul.vx v18, \o7, t2
+  vwmul.vx v20, \o7, t2
+  vwmacc.vx v20, t2, \o1
+  neg t2, t2
+  vwmacc.vx v18, t2, \o1
+
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+
+  vssub.vv \o7, \o0, v22
+  vsadd.vv \o0, \o0, v22
+  vssub.vv v17, \o2, v20
+  vsadd.vv \o1, \o2, v20
+  vssub.vv \o5, \o4, v18
+  vsadd.vv \o2, \o4, v18
+  vssub.vv \o4, \o6, v16
+  vsadd.vv \o3, \o6, v16
+  vmv.v.v \o6, v17
+.endm
+
+.macro iadst_8 o0, o1, o2, o3, o4, o5, o6, o7
+  li t1, 4076
+  li t2, 401
+  li t3, 3612
+  li t4, 1931
+  li t5, 2598
+  li t6, 3166
+
+  vwmul.vx v16, v7, t1
+  neg t1, t1
+  vwmul.vx v18, v7, t2
+  vwmacc.vx v16, t2, v0
+  vwmacc.vx v18, t1, v0
+
+  vwmul.vx v20, v5, t3
+  neg t3, t3
+  vwmul.vx v22, v5, t4
+  vwmacc.vx v20, t4, v2
+  vwmacc.vx v22, t3, v2
+
+  vwmul.vx v24, v3, t5
+  neg t5, t5
+  vwmul.vx v26, v3, t6
+  vwmacc.vx v24, t6, v4
+  vwmacc.vx v26, t5, v4
+
+  li t2, 1189
+  li t3, 3920
+  li t4, 1567
+  li t5, 3784
+  li t6, 2896
+
+  vwmul.vx v28, v1, t2
+  neg t2, t2
+  vwmul.vx v30, v1, t3
+  vwmacc.vx v28, t3, v6
+  vwmacc.vx v30, t2, v6
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+  vnclip.wi v22, v22, 12
+  vnclip.wi v24, v24, 12
+  vnclip.wi v26, v26, 12
+  vnclip.wi v28, v28, 12
+  vnclip.wi v30, v30, 12
+
+  vssub.vv  v4, v16, v24
+  vsadd.vv v16, v16, v24
+  vsadd.vv  v1, v18, v26
+  vsadd.vv  v2, v20, v28
+  vsadd.vv  v3, v22, v30
+  vssub.vv  v5, v18, v26
+  vssub.vv  v6, v20, v28
+  vssub.vv v30, v22, v30
+
+  vsadd.vv \o0, v16, v2
+  vsadd.vv \o7,  v1, v3
+  vssub.vv  v2, v16, v2
+  vssub.vv  v3,  v1, v3
+
+  vwmul.vx v16,  v4, t5
+  vwmul.vx v18,  v4, t4
+  vwmul.vx v20, v30, t5
+  vwmul.vx v22, v30, t4
+  vwmacc.vx v16, t4, v5
+  neg t4, t4
+  vwmacc.vx v22, t5, v6
+  neg t5, t5
+  vwmacc.vx v20, t4, v6
+  vwmacc.vx v18, t5, v5
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+  vnclip.wi v22, v22, 12
+
+  vsadd.vv \o1, v16, v20
+  vsadd.vv \o6, v18, v22
+  vssub.vv v16, v16, v20
+  vssub.vv v17, v18, v22
+
+  vwmul.vx v18, v2, t6
+  vwmul.vx v20, v2, t6
+  vwmul.vx v22, v16, t6
+  vwmul.vx v24, v16, t6
+  vwmacc.vx v18, t6, v3
+  vwmacc.vx v22, t6, v17
+  neg t6, t6
+  vwmacc.vx v20, t6, v3
+  vwmacc.vx v24, t6, v17
+
+  vnclip.wi \o3, v18, 12
+  vnclip.wi \o4, v20, 12
+  vnclip.wi \o2, v22, 12
+  vnclip.wi \o5, v24, 12
+
+  vmv.v.x v16, zero
+  vssub.vv \o1, v16, \o1
+  vssub.vv \o3, v16, \o3
+  vssub.vv \o5, v16, \o5
+  vssub.vv \o7, v16, \o7
+.endm
+
+function inv_dct_e16_x8_rvv, export=1, ext=v
+  idct_8 v0, v1, v2, v3, v4, v5, v6, v7
+  jr t0
+endfunc
+
+function inv_adst_e16_x8_rvv, export=1, ext=v
+  iadst_8 v0, v1, v2, v3, v4, v5, v6, v7
+  jr t0
+endfunc
+
+function inv_flipadst_e16_x8_rvv, export=1, ext=v
+  iadst_8 v7, v6, v5, v4, v3, v2, v1, v0
+  jr t0
+endfunc
+
+.macro def_fn_8x8 txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_8x8_8bpc_rvv, export=1, ext=v
+.ifc \txfm1\()_\txfm2, dct_dct
+  beqz a3, 1f
+.endif
+  la a5, inv_\txfm2\()_e16_x8_rvv
+.ifc \txfm1, identity
+  j inv_txfm_identity_add_8x8_rvv
+.else
+  la a4, inv_\txfm1\()_e16_x8_rvv
+  j inv_txfm_add_8x8_rvv
+.endif
+.ifc \txfm1\()_\txfm2, dct_dct
+1:
+  csrw vxrm, zero
+  vsetivli zero, 8, e16, m1, ta, ma
+  ld t2, (a2)
+  li t1, 2896*8
+  vmv.v.x v0, t2
+  vsmul.vx v0, v0, t1
+  sd x0, (a2)
+  vssra.vi v0, v0, 1
+  vsmul.vx v0, v0, t1
+  vssra.vi v0, v0, 4
+  vmv.v.v v1, v0
+  vmv.v.v v2, v0
+  vmv.v.v v3, v0
+  vmv.v.v v4, v0
+  vmv.v.v v5, v0
+  vmv.v.v v6, v0
+  vmv.v.v v7, v0
+  j itx_8x8_end
+.endif
+endfunc
+.endm
+
+def_fn_8x8 dct, dct
+def_fn_8x8 identity, identity
+def_fn_8x8 dct, adst
+def_fn_8x8 dct, flipadst
+def_fn_8x8 dct, identity
+def_fn_8x8 adst, dct
+def_fn_8x8 adst, adst
+def_fn_8x8 adst, flipadst
+def_fn_8x8 flipadst, dct
+def_fn_8x8 flipadst, adst
+def_fn_8x8 flipadst, flipadst
+def_fn_8x8 identity, dct
+def_fn_8x8 adst, identity
+def_fn_8x8 flipadst, identity
+def_fn_8x8 identity, adst
+def_fn_8x8 identity, flipadst
+
+function inv_txfm_add_4x8_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 8, e16, m1, ta, ma
+  vle16.v v0, (a2)
+  addi t0, a2, 16
+  vle16.v v1, (t0)
+  addi t0, t0, 16
+  vle16.v v2, (t0)
+  addi t0, t0, 16
+  vle16.v v3, (t0)
+
+  li t1, 2896*8
+.irp i, 0, 1, 2, 3
+  vsmul.vx v\i, v\i, t1
+.endr
+
+  jalr t0, a4
+
+  vsseg4e16.v v0, (a2)
+
+  vsetivli zero, 4, e16, mf2, ta, ma
+  vmv.v.x v8, zero
+  vle16.v v0, (a2)
+  vse16.v v8, (a2)
+.irp i, 1, 2, 3, 4, 5, 6, 7
+  addi a2, a2, 8
+  vle16.v v\i, (a2)
+  vse16.v v8, (a2)
+.endr
+
+  jalr t0, a5
+
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7
+  vssra.vi v\i, v\i, 4
+.endr
+
+  vsetvli zero, zero, e8, mf4, ta, ma
+  vle8.v v8, (a0)
+  add t0, a0, a1
+  vle8.v v9, (t0)
+.irp i, 10, 11, 12, 13, 14, 15
+  add t0, t0, a1
+  vle8.v v\i, (t0)
+.endr
+
+  vwaddu.wv v0, v0,  v8
+  vwaddu.wv v1, v1,  v9
+  vwaddu.wv v2, v2, v10
+  vwaddu.wv v3, v3, v11
+  vwaddu.wv v4, v4, v12
+  vwaddu.wv v5, v5, v13
+  vwaddu.wv v6, v6, v14
+  vwaddu.wv v7, v7, v15
+
+  vsetvli zero, zero, e16, mf2, ta, ma
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7
+  vmax.vx v\i, v\i, zero
+.endr
+
+  vsetvli zero, zero, e8, mf4, ta, ma
+
+  vnclipu.wi  v8, v0, 0
+  vnclipu.wi  v9, v1, 0
+  vnclipu.wi v10, v2, 0
+  vnclipu.wi v11, v3, 0
+  vnclipu.wi v12, v4, 0
+  vnclipu.wi v13, v5, 0
+  vnclipu.wi v14, v6, 0
+  vnclipu.wi v15, v7, 0
+
+  vse8.v v8, (a0)
+.irp i, 9, 10, 11, 12, 13, 14, 15
+  add a0, a0, a1
+  vse8.v v\i, (a0)
+.endr
+
+  ret
+endfunc
+
+function inv_txfm_add_8x4_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 4, e16, mf2, ta, ma
+  vle16.v v0, (a2)
+  addi t0, a2, 8
+  vle16.v v1, (t0)
+.irp i, 2, 3, 4, 5, 6, 7
+  addi t0, t0, 8
+  vle16.v v\i, (t0)
+.endr
+
+  li t1, 2896*8
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7
+  vsmul.vx v\i, v\i, t1
+.endr
+
+  jalr t0, a4
+
+  vsseg8e16.v v0, (a2)
+
+  vsetivli zero, 8, e16, m1, ta, ma
+  vmv.v.x v4, zero
+  vle16.v v0, (a2)
+  vse16.v v4, (a2)
+.irp i, 1, 2, 3
+  addi a2, a2, 16
+  vle16.v v\i, (a2)
+  vse16.v v4, (a2)
+.endr
+
+  jalr t0, a5
+
+  vssra.vi v0, v0, 4
+  vssra.vi v1, v1, 4
+  vssra.vi v2, v2, 4
+  vssra.vi v3, v3, 4
+
+  vsetvli zero, zero, e8, mf2, ta, ma
+  vle8.v v4, (a0)
+  add t0, a0, a1
+  vle8.v v5, (t0)
+  add t0, t0, a1
+  vle8.v v6, (t0)
+  add t0, t0, a1
+  vle8.v v7, (t0)
+
+  vwaddu.wv v0, v0, v4
+  vwaddu.wv v1, v1, v5
+  vwaddu.wv v2, v2, v6
+  vwaddu.wv v3, v3, v7
+
+  vsetvli zero, zero, e16, m1, ta, ma
+  vmax.vx v0, v0, zero
+  vmax.vx v1, v1, zero
+  vmax.vx v2, v2, zero
+  vmax.vx v3, v3, zero
+
+  vsetvli zero, zero, e8, mf2, ta, ma
+
+  vnclipu.wi v4, v0, 0
+  vnclipu.wi v5, v1, 0
+  vnclipu.wi v6, v2, 0
+  vnclipu.wi v7, v3, 0
+
+  vse8.v v4, (a0)
+  add a0, a0, a1
+  vse8.v v5, (a0)
+  add a0, a0, a1
+  vse8.v v6, (a0)
+  add a0, a0, a1
+  vse8.v v7, (a0)
+
+  ret
+endfunc
+
+/* Define symbols added in .if statement */
+.equ dct, 1
+.equ identity, 2
+.equ adst, 3
+.equ flipadst, 4
+
+.macro def_fn_48 w, h, txfm1, txfm2
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_rvv, export=1
+.if \w == 4 && (\txfm1 == adst || \txfm1 == flipadst)
+  la a4, inv_\txfm1\()_e16_x\w\()w_rvv
+.else
+  la a4, inv_\txfm1\()_e16_x\w\()_rvv
+.endif
+.if \h == 4 && (\txfm2 == adst || \txfm2 == flipadst)
+  la a5, inv_\txfm2\()_e16_x\h\()w_rvv
+.else
+  la a5, inv_\txfm2\()_e16_x\h\()_rvv
+.endif
+  j inv_txfm_add_\w\()x\h\()_rvv
+endfunc
+.endm
+
+.macro def_fns_48 w, h
+def_fn_48 \w, \h, dct, dct
+def_fn_48 \w, \h, identity, identity
+def_fn_48 \w, \h, dct, adst
+def_fn_48 \w, \h, dct, flipadst
+def_fn_48 \w, \h, dct, identity
+def_fn_48 \w, \h, adst, dct
+def_fn_48 \w, \h, adst, adst
+def_fn_48 \w, \h, adst, flipadst
+def_fn_48 \w, \h, flipadst, dct
+def_fn_48 \w, \h, flipadst, adst
+def_fn_48 \w, \h, flipadst, flipadst
+def_fn_48 \w, \h, identity, dct
+def_fn_48 \w, \h, adst, identity
+def_fn_48 \w, \h, flipadst, identity
+def_fn_48 \w, \h, identity, adst
+def_fn_48 \w, \h, identity, flipadst
+.endm
+
+def_fns_48 4, 8
+def_fns_48 8, 4
+
+function inv_identity_e16_x16_rvv, export=1, ext=v
+  li t1, 2*(5793-4096)*8
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vsmul.vx v16, v\i, t1
+  vsadd.vv v\i, v\i, v\i
+  vsadd.vv v\i, v\i, v16
+.endr
+  jr t0
+endfunc
+
+function inv_dct_e16_x16_rvv, export=1, ext=v
+  idct_8 v0, v2, v4, v6, v8, v10, v12, v14
+
+  li t1, 401
+  li t2, 4076
+  li t3, 3166
+  li t4, 2598
+
+  vwmul.vx v30, v1, t2
+  neg t2, t2
+  vwmul.vx v16, v1, t1
+  vwmacc.vx v30, t1, v15
+  vwmacc.vx v16, t2, v15
+
+  vwmul.vx v28, v9, t4
+  neg t4, t4
+  vwmul.vx v18, v9, t3
+  vwmacc.vx v28, t3, v7
+  vwmacc.vx v18, t4, v7
+
+  li t1, 1931
+  li t2, 3612
+  li t3, 3920
+  li t4, 1189
+
+  vwmul.vx v26, v5, t2
+  neg t2, t2
+  vwmul.vx v20, v5, t1
+  vwmacc.vx v26, t1, v11
+  vwmacc.vx v20, t2, v11
+
+  vwmul.vx v24, v13, t4
+  neg t4, t4
+  vwmul.vx v22, v13, t3
+  vwmacc.vx v24, t3, v3
+  vwmacc.vx v22, t4, v3
+
+  li t2, 2896
+  li t3, 1567
+  li t4, 3784
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+  vnclip.wi v22, v22, 12
+  vnclip.wi v24, v24, 12
+  vnclip.wi v26, v26, 12
+  vnclip.wi v28, v28, 12
+  vnclip.wi v30, v30, 12
+
+  vssub.vv  v3, v16, v18
+  vsadd.vv v16, v16, v18
+  vssub.vv  v5, v22, v20
+  vsadd.vv v22, v22, v20
+  vssub.vv v11, v24, v26
+  vsadd.vv v24, v24, v26
+  vssub.vv v13, v30, v28
+  vsadd.vv v30, v30, v28
+
+  vwmul.vx v28, v13, t4
+  neg t4, t4
+  vwmul.vx v18, v13, t3
+  vwmul.vx v26, v11, t3
+  vwmacc.vx v28, t3, v3
+  neg t3, t3
+  vwmul.vx v20, v11, t4
+  vwmacc.vx v18, t4, v3
+  vwmacc.vx v20, t3, v5
+  vwmacc.vx v26, t4, v5
+
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+  vnclip.wi v26, v26, 12
+  vnclip.wi v28, v28, 12
+
+  vssub.vv  v5, v18, v20
+  vsadd.vv v18, v18, v20
+  vssub.vv v11, v28, v26
+  vsadd.vv v28, v28, v26
+
+  vssub.vv  v7, v16, v22
+  vsadd.vv v16, v16, v22
+  vssub.vv  v9, v30, v24
+  vsadd.vv v30, v30, v24
+
+  vwmul.vx v20, v11, t2
+  vwmul.vx v22,  v9, t2
+  vwmul.vx v24,  v9, t2
+  vwmul.vx v26, v11, t2
+  vwmacc.vx v24, t2, v7
+  vwmacc.vx v26, t2, v5
+  neg t2, t2
+  vwmacc.vx v20, t2, v5
+  vwmacc.vx v22, t2, v7
+
+  vnclip.wi v20, v20, 12
+  vnclip.wi v22, v22, 12
+  vnclip.wi v24, v24, 12
+  vnclip.wi v26, v26, 12
+
+  vssub.vv v15,  v0, v30
+  vsadd.vv  v0,  v0, v30
+  vssub.vv v17,  v2, v28
+  vsadd.vv  v1,  v2, v28
+  vssub.vv v13,  v4, v26
+  vsadd.vv  v2,  v4, v26
+  vssub.vv v19,  v6, v24
+  vsadd.vv  v3,  v6, v24
+  vssub.vv v11,  v8, v22
+  vsadd.vv  v4,  v8, v22
+  vsadd.vv  v5, v10, v20
+  vssub.vv v10, v10, v20
+  vssub.vv  v9, v12, v18
+  vsadd.vv  v6, v12, v18
+  vssub.vv  v8, v14, v16
+  vsadd.vv  v7, v14, v16
+  vmv.v.v v14, v17
+  vmv.v.v v12, v19
+
+  jr t0
+endfunc
+
+.macro iadst_16 o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15
+  li t1, 4091
+  li t2, 201
+  li t3, 3973
+  li t4, 995
+
+  vwmul.vx v16, v15, t1
+  neg t1, t1
+  vwmul.vx v18, v15, t2
+  vwmacc.vx v16, t2, v0
+  vwmacc.vx v18, t1, v0
+
+  vwmul.vx v20, v13, t3
+  neg t3, t3
+  vwmul.vx v22, v13, t4
+  vwmacc.vx v20, t4, v2
+  vwmacc.vx v22, t3, v2
+
+  li t1, 3703
+  li t2, 1751
+  li t3, 3290
+  li t4, 2440
+
+  vwmul.vx v24, v11, t1
+  neg t1, t1
+  vwmul.vx v26, v11, t2
+  vwmacc.vx v24, t2, v4
+  vwmacc.vx v26, t1, v4
+
+  vwmul.vx v28, v9, t3
+  neg t3, t3
+  vwmul.vx v30, v9, t4
+  vwmacc.vx v28, t4, v6
+  vwmacc.vx v30, t3, v6
+
+  vnclip.wi  v0, v16, 12
+  vnclip.wi v18, v18, 12
+  vnclip.wi  v2, v20, 12
+  vnclip.wi v22, v22, 12
+  vnclip.wi  v4, v24, 12
+  vnclip.wi v26, v26, 12
+  vnclip.wi  v6, v28, 12
+  vnclip.wi v30, v30, 12
+
+  li t1, 2751
+  li t2, 3035
+  li t3, 2106
+  li t4, 3513
+
+  vwmul.vx v16, v7, t1
+  neg t1, t1
+  vwmul.vx v20, v7, t2
+  vwmacc.vx v16, t2, v8
+  vwmacc.vx v20, t1, v8
+
+  vwmul.vx v24, v5, t3
+  neg t3, t3
+  vwmul.vx v28, v5, t4
+  vwmacc.vx v24, t4, v10
+  vwmacc.vx v28, t3, v10
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi  v9, v20, 12
+  vnclip.wi v24, v24, 12
+  vnclip.wi v11, v28, 12
+
+  vssub.vv  v8,  v0, v16
+  vsadd.vv  v0,  v0, v16
+  vssub.vv v10,  v2, v24
+  vsadd.vv  v2,  v2, v24
+
+  li t1, 1380
+  li t2, 3857
+  li t3, 601
+  li t4, 4052
+
+  vwmul.vx v16, v3, t1
+  neg t1, t1
+  vwmul.vx v20, v3, t2
+  vwmacc.vx v16, t2, v12
+  vwmacc.vx v20, t1, v12
+
+  vwmul.vx v24, v1, t3
+  neg t3, t3
+  vwmul.vx v28, v1, t4
+  vwmacc.vx v24, t4, v14
+  vwmacc.vx v28, t3, v14
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi v13, v20, 12
+  vnclip.wi v24, v24, 12
+  vnclip.wi v15, v28, 12
+
+  vssub.vv v12,  v4, v16
+  vsadd.vv v16,  v4, v16
+  vssub.vv v14,  v6, v24
+  vsadd.vv v20,  v6, v24
+
+  vsadd.vv  v1, v18,  v9
+  vssub.vv  v9, v18,  v9
+  vsadd.vv  v3, v22, v11
+  vssub.vv v11, v22, v11
+  vsadd.vv v18, v26, v13
+  vssub.vv v13, v26, v13
+  vsadd.vv v22, v30, v15
+  vssub.vv v15, v30, v15
+
+  vssub.vv v4, v0, v16
+  vsadd.vv v0, v0, v16
+  vssub.vv v5, v1, v18
+  vsadd.vv v1, v1, v18
+  vssub.vv v6, v2, v20
+  vsadd.vv v2, v2, v20
+  vssub.vv v7, v3, v22
+  vsadd.vv v3, v3, v22
+
+  li t1, 799
+  li t2, 4017
+  li t3, 3406
+  li t4, 2276
+
+  vwmul.vx v16,  v8, t2
+  vwmul.vx v18,  v8, t1
+  vwmul.vx v20, v10, t4
+  vwmul.vx v22, v10, t3
+  vwmul.vx v24, v13, t2
+  vwmul.vx v26, v13, t1
+  vwmul.vx v28, v15, t4
+  vwmul.vx v30, v15, t3
+  vwmacc.vx v16, t1,  v9
+  neg t1, t1
+  vwmacc.vx v20, t3, v11
+  neg t3, t3
+  vwmacc.vx v26, t2, v12
+  neg t2, t2
+  vwmacc.vx v30, t4, v14
+  neg t4, t4
+  vwmacc.vx v18, t2,  v9
+  vwmacc.vx v22, t4, v11
+  vwmacc.vx v24, t1, v12
+  vwmacc.vx v28, t3, v14
+
+  li t2, 2896
+  li t3, 1567
+  li t4, 3784
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+  vnclip.wi v22, v22, 12
+  vnclip.wi v24, v24, 12
+  vnclip.wi v26, v26, 12
+  vnclip.wi v28, v28, 12
+  vnclip.wi v30, v30, 12
+
+  vsadd.vv  v8, v16, v24
+  vsadd.vv  v9, v18, v26
+  vsadd.vv v10, v20, v28
+  vsadd.vv v11, v22, v30
+  vssub.vv v12, v16, v24
+  vssub.vv v13, v18, v26
+  vssub.vv v14, v20, v28
+  vssub.vv v15, v22, v30
+
+  vwmul.vx v16,  v4, t4
+  vwmul.vx v18,  v4, t3
+  vwmul.vx v20,  v7, t4
+  vwmul.vx v22,  v7, t3
+  vwmul.vx v24, v12, t4
+  vwmul.vx v26, v12, t3
+  vwmul.vx v28, v15, t4
+  vwmul.vx v30, v15, t3
+  vwmacc.vx v16, t3,  v5
+  vwmacc.vx v22, t4,  v6
+  vwmacc.vx v24, t3, v13
+  neg t3, t3
+  vwmacc.vx v30, t4, v14
+  neg t4, t4
+  vwmacc.vx v20, t3,  v6
+  vwmacc.vx v28, t3, v14
+  vwmacc.vx v18, t4,  v5
+  vwmacc.vx v26, t4, v13
+
+  vnclip.wi v16, v16, 12
+  vnclip.wi v18, v18, 12
+  vnclip.wi v20, v20, 12
+  vnclip.wi v22, v22, 12
+  vnclip.wi v24, v24, 12
+  vnclip.wi v26, v26, 12
+  vnclip.wi v28, v28, 12
+  vnclip.wi v30, v30, 12
+
+.ifc \o0, v0
+  vsadd.vv \o14, v9, v11
+  vssub.vv  v11, v9, v11
+  vssub.vv   v9, v1,  v3
+  vsadd.vv \o15, v1,  v3
+  vsadd.vv  \o1, v8, v10
+  vssub.vv  v10, v8, v10
+  vssub.vv   v8, v0,  v2
+  vsadd.vv  \o0, v0,  v2
+.else
+  vsadd.vv  \o1, v8, v10
+  vssub.vv  v10, v8, v10
+  vssub.vv   v8, v0,  v2
+  vsadd.vv  \o0, v0,  v2
+  vsadd.vv   v2, v9, v11
+  vssub.vv  v11, v9, v11
+  vssub.vv   v9, v1,  v3
+  vsadd.vv \o15, v1,  v3
+  vmv.v.v  \o14, v2
+.endif
+
+  vsadd.vv  \o3, v16, v20
+  vssub.vv   v6, v16, v20
+  vsadd.vv \o12, v18, v22
+  vssub.vv   v7, v18, v22
+  vsadd.vv  \o2, v24, v28
+  vssub.vv  v24, v24, v28
+  vsadd.vv \o13, v26, v30
+  vssub.vv  v26, v26, v30
+
+  neg t3, t2
+
+  vwmul.vx v28, v24, t2
+  vwmul.vx v30, v24, t2
+  vwmacc.vx v28, t2, v26
+  vwmacc.vx v30, t3, v26
+
+  vwmul.vx v24, v10, t2
+  vwmul.vx v26, v10, t2
+  vwmacc.vx v24, t2, v11
+  vwmacc.vx v26, t3, v11
+
+  vwmul.vx v20, v6, t2
+  vwmul.vx v22, v6, t2
+  vwmacc.vx v20, t2, v7
+  vwmacc.vx v22, t3, v7
+
+  vwmul.vx v16, v8, t2
+  vwmul.vx v18, v8, t2
+  vwmacc.vx v16, t2, v9
+  vwmacc.vx v18, t3, v9
+
+  vnclip.wi  \o7, v16, 12
+  vnclip.wi  \o8, v18, 12
+  vnclip.wi  \o4, v20, 12
+  vnclip.wi \o11, v22, 12
+  vnclip.wi  \o6, v24, 12
+  vnclip.wi  \o9, v26, 12
+  vnclip.wi  \o5, v28, 12
+  vnclip.wi \o10, v30, 12
+
+  vmv.v.x v16, zero
+  vssub.vv  \o1, v16,  \o1
+  vssub.vv  \o3, v16,  \o3
+  vssub.vv  \o5, v16,  \o5
+  vssub.vv  \o7, v16,  \o7
+  vssub.vv  \o9, v16,  \o9
+  vssub.vv \o11, v16, \o11
+  vssub.vv \o13, v16, \o13
+  vssub.vv \o15, v16, \o15
+.endm
+
+function inv_adst_e16_x16_rvv, export=1, ext=v
+  iadst_16 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
+  jr t0
+endfunc
+
+function inv_flipadst_e16_x16_rvv, export=1, ext=v
+  iadst_16 v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1, v0
+  jr t0
+endfunc
+
+.macro def_horz_16 variant
+function inv_txfm_horz\variant\()_16x8_rvv, export=1, ext=v
+  vmv.v.x v16, zero
+  vle16.v v0, (t4)
+  vse16.v v16, (t4)
+.irp i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  add t4, t4, t6
+  vle16.v v\i, (t4)
+  vse16.v v16, (t4)
+.endr
+.ifc \variant, _identity
+  li t1, 2*(5793-4096)*8
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vsmul.vx v16, v\i, t1
+  vsra.vi v16, v16, 1
+  vaadd.vv v\i, v\i, v16
+.endr
+  j L(horz_16x8_epilog)
+.else
+  jalr t0, a4
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vssra.vi v\i, v\i, 2
+.endr
+L(horz_16x8_epilog):
+  vsse16.v v0, (t5), t6
+.irp i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  addi t5, t5, 2
+  vsse16.v v\i, (t5), t6
+.endr
+  jr a7
+.endif
+endfunc
+.endm
+
+def_horz_16 _identity
+def_horz_16
+
+function inv_txfm_add_vert_8x16_rvv, export=1, ext=v
+  vsetivli zero, 8, e16, m1, ta, ma
+
+  vle16.v v0, (t4)
+.irp i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  add t4, t4, t6
+  vle16.v v\i, (t4)
+.endr
+
+  jalr t0, a5
+
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vssra.vi v\i, v\i, 4
+.endr
+
+  vsetivli zero, 8, e8, mf2, ta, ma
+
+  vle8.v v16, (t5)
+  add t0, t5, a1
+  vle8.v v17, (t0)
+.irp i, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+  add t0, t0, a1
+  vle8.v v\i, (t0)
+.endr
+
+  vwaddu.wv v0, v0, v16
+  vwaddu.wv v1, v1, v17
+  vwaddu.wv v2, v2, v18
+  vwaddu.wv v3, v3, v19
+  vwaddu.wv v4, v4, v20
+  vwaddu.wv v5, v5, v21
+  vwaddu.wv v6, v6, v22
+  vwaddu.wv v7, v7, v23
+  vwaddu.wv v8, v8, v24
+  vwaddu.wv v9, v9, v25
+  vwaddu.wv v10, v10, v26
+  vwaddu.wv v11, v11, v27
+  vwaddu.wv v12, v12, v28
+  vwaddu.wv v13, v13, v29
+  vwaddu.wv v14, v14, v30
+  vwaddu.wv v15, v15, v31
+
+  vsetvli zero, zero, e16, m1, ta, ma
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vmax.vx v\i, v\i, zero
+.endr
+
+  vsetvli zero, zero, e8, mf2, ta, ma
+  vnclipu.wi v16, v0, 0
+  vnclipu.wi v17, v1, 0
+  vnclipu.wi v18, v2, 0
+  vnclipu.wi v19, v3, 0
+  vnclipu.wi v20, v4, 0
+  vnclipu.wi v21, v5, 0
+  vnclipu.wi v22, v6, 0
+  vnclipu.wi v23, v7, 0
+  vnclipu.wi v24, v8, 0
+  vnclipu.wi v25, v9, 0
+  vnclipu.wi v26, v10, 0
+  vnclipu.wi v27, v11, 0
+  vnclipu.wi v28, v12, 0
+  vnclipu.wi v29, v13, 0
+  vnclipu.wi v30, v14, 0
+  vnclipu.wi v31, v15, 0
+
+  vse8.v v16, (t5)
+.irp i, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+  add t5, t5, a1
+  vse8.v v\i, (t5)
+.endr
+
+  jr a7
+endfunc
+
+function inv_txfm_add_16x16_rvv, export=1, ext=v
+  csrw vxrm, zero
+  vsetivli zero, 8, e16, m1, ta, ma
+  addi sp, sp, -16*32
+.irp i, 8, 0
+  addi t4, a2, \i*2
+  addi t5, sp, \i*16*2
+.if \i == 8
+  blt a3, a7, 1f
+.endif
+  li t6, 16*2
+  jalr a7, a6
+.if \i == 8
+  j 2f
+1:
+  li t1, 64
+  vsetvli zero, t1, e16, m8, ta, ma
+  vmv.v.x v0, zero
+  vse16.v v0, (t5)
+  addi t5, t5, 128
+  vse16.v v0, (t5)
+  vsetivli zero, 8, e16, m1, ta, ma
+2:
+.endif
+.endr
+.irp i, 0, 8
+  addi t4, sp, \i*2
+  addi t5, a0, \i
+  li t6, 16*2
+  jal a7, inv_txfm_add_vert_8x16_rvv
+.endr
+  addi sp, sp, 16*32
+  ret
+endfunc
+
+.macro def_fn_16x16 txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_16x16_8bpc_rvv, export=1, ext=v
+.ifc \txfm1\()_\txfm2, dct_dct
+ beqz a3, 1f
+.endif
+.ifc \txfm1, identity
+  la a6, inv_txfm_horz_identity_16x8_rvv
+.else
+  la a6, inv_txfm_horz_16x8_rvv
+  la a4, inv_\txfm1\()_e16_x16_rvv
+.endif
+  la a5, inv_\txfm2\()_e16_x16_rvv
+  li a7, \eob_half
+  j inv_txfm_add_16x16_rvv
+.ifc \txfm1\()_\txfm2, dct_dct
+1:
+  csrw vxrm, zero
+  vsetivli zero, 16, e16, m2, ta, ma
+  lh t2, (a2)
+  li t3, 2896*8
+  li t4, 1<<14
+  li t5, 0xFFFF
+  li t6, -0x10000
+
+  sh x0, (a2)
+
+  mul t2, t2, t3
+  add t2, t2, t4
+  srai t2, t2, 15
+  ble t2, t5, 3f
+  mv t2, t5
+3:
+  ble t6, t2, 4f
+  mv t2, t6
+4:
+  addi t2, t2, 2
+  srai t2, t2, 2
+  mul t2, t2, t3
+  add t2, t2, t4
+  srai t2, t2, 15
+  ble t2, t5, 5f
+  mv t2, t5
+5:
+  ble t6, t2, 6f
+  mv t2, t6
+6:
+  addi t2, t2, 8
+  srai t2, t2, 4
+  vmv.v.x v24, t2
+
+  vsetvli zero, zero, e8, m1, ta, ma
+  add t2, a1, a1
+  li t3, 16
+2:
+  add t0, a0, a1
+  vle8.v v16, (a0)
+  vle8.v v17, (t0)
+
+  vwaddu.wv v0, v24, v16
+  vwaddu.wv v2, v24, v17
+
+  addi t3, t3, -2 # loop counter
+
+
+  vsetvli zero, zero, e16, m2, ta, ma
+.irp i, 0, 2
+  vmax.vx v\i, v\i, zero
+.endr
+
+  vsetvli zero, zero, e8, m1, ta, ma
+
+  vnclipu.wi  v16, v0, 0
+  vnclipu.wi  v17, v2, 0
+
+  add t0, a0, a1
+  vse8.v v16, (a0)
+  add a0, a0, t2
+  vse8.v v17, (t0)
+
+  bnez t3, 2b
+
+  ret
+.endif
+endfunc
+.endm
+
+def_fn_16x16 dct, dct, 36
+def_fn_16x16 identity, identity, 36
+def_fn_16x16 dct, adst, 36
+def_fn_16x16 dct, flipadst, 36
+def_fn_16x16 dct, identity, 8
+def_fn_16x16 adst, dct, 36
+def_fn_16x16 adst, adst, 36
+def_fn_16x16 adst, flipadst, 36
+def_fn_16x16 flipadst, dct, 36
+def_fn_16x16 flipadst, adst, 36
+def_fn_16x16 flipadst, flipadst, 36
+def_fn_16x16 identity, dct, 8
+
+.macro def_fn_416_base variant
+function inv_txfm_\variant\()add_4x16_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 8, e16, m1, ta, ma
+
+  blt a3, a6, 1f
+
+  addi t0, a2, 16
+  vle16.v v0, (t0)
+  addi t0, t0, 32
+  vle16.v v1, (t0)
+  addi t0, t0, 32
+  vle16.v v2, (t0)
+  addi t0, t0, 32
+  vle16.v v3, (t0)
+
+.ifc \variant, identity_
+  li t1, (5793-4096)*8
+  vsmul.vx v8, v0, t1
+  vaadd.vv v4, v0, v8
+  vsmul.vx v8, v1, t1
+  vaadd.vv v5, v1, v8
+  vsmul.vx v8, v2, t1
+  vaadd.vv v6, v2, v8
+  vsmul.vx v8, v3, t1
+  vaadd.vv v7, v3, v8
+.else
+  jalr t0, a4
+
+  vssra.vi v4, v0, 1
+  vssra.vi v5, v1, 1
+  vssra.vi v6, v2, 1
+  vssra.vi v7, v3, 1
+.endif
+
+  j 2f
+
+1:
+.irp i, 4, 5, 6, 7
+  vmv.v.x v\i, zero
+.endr
+
+2:
+  vle16.v v0, (a2)
+  addi t0, a2, 32
+  vle16.v v1, (t0)
+  addi t0, t0, 32
+  vle16.v v2, (t0)
+  addi t0, t0, 32
+  vle16.v v3, (t0)
+
+.ifc \variant, identity_
+  li t1, (5793-4096)*8
+.irp i, 0, 1, 2, 3
+  vsmul.vx v8, v\i, t1
+  vaadd.vv v\i, v\i, v8
+.endr
+
+  j L(itx_4x16_epilog)
+.else
+  jalr t0, a4
+
+  vssra.vi v0, v0, 1
+  vssra.vi v1, v1, 1
+  vssra.vi v2, v2, 1
+  vssra.vi v3, v3, 1
+
+L(itx_4x16_epilog):
+  vsseg4e16.v v0, (a2)
+  addi t0, a2, 64
+  vsseg4e16.v v4, (t0)
+
+  vsetivli zero, 4, e16, mf2, ta, ma
+
+  vmv.v.x v16, zero
+  vle16.v v0, (a2)
+  vse16.v v16, (a2)
+  addi t0, a2, 8
+  vle16.v v1, (t0)
+  vse16.v v16, (t0)
+.irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  addi t0, t0, 8
+  vle16.v v\i, (t0)
+  vse16.v v16, (t0)
+.endr
+
+  jalr t0, a5
+
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vssra.vi v\i, v\i, 4
+.endr
+
+  vsetvli zero, zero, e8, mf4, ta, ma
+
+  vle8.v v16, (a0)
+  add t0, a0, a1
+  vle8.v v17, (t0)
+.irp i, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+  add t0, t0, a1
+  vle8.v v\i, (t0)
+.endr
+
+  vwaddu.wv  v0,  v0, v16
+  vwaddu.wv  v1,  v1, v17
+  vwaddu.wv  v2,  v2, v18
+  vwaddu.wv  v3,  v3, v19
+  vwaddu.wv  v4,  v4, v20
+  vwaddu.wv  v5,  v5, v21
+  vwaddu.wv  v6,  v6, v22
+  vwaddu.wv  v7,  v7, v23
+  vwaddu.wv  v8,  v8, v24
+  vwaddu.wv  v9,  v9, v25
+  vwaddu.wv v10, v10, v26
+  vwaddu.wv v11, v11, v27
+  vwaddu.wv v12, v12, v28
+  vwaddu.wv v13, v13, v29
+  vwaddu.wv v14, v14, v30
+  vwaddu.wv v15, v15, v31
+
+  vsetvli zero, zero, e16, mf2, ta, ma
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vmax.vx v\i, v\i, zero
+.endr
+
+  vsetvli zero, zero, e8, mf4, ta, ma
+
+  vnclipu.wi v16,  v0, 0
+  vnclipu.wi v17,  v1, 0
+  vnclipu.wi v18,  v2, 0
+  vnclipu.wi v19,  v3, 0
+  vnclipu.wi v20,  v4, 0
+  vnclipu.wi v21,  v5, 0
+  vnclipu.wi v22,  v6, 0
+  vnclipu.wi v23,  v7, 0
+  vnclipu.wi v24,  v8, 0
+  vnclipu.wi v25,  v9, 0
+  vnclipu.wi v26, v10, 0
+  vnclipu.wi v27, v11, 0
+  vnclipu.wi v28, v12, 0
+  vnclipu.wi v29, v13, 0
+  vnclipu.wi v30, v14, 0
+  vnclipu.wi v31, v15, 0
+
+  vse8.v v16, (a0)
+.irp i, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+  add a0, a0, a1
+  vse8.v v\i, (a0)
+.endr
+
+  ret
+.endif
+endfunc
+
+function inv_txfm_\variant\()add_16x4_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 4, e16, mf2, ta, ma
+  vle16.v v0, (a2)
+  addi t0, a2, 8
+  vle16.v v1, (t0)
+.irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  addi t0, t0, 8
+  vle16.v v\i, (t0)
+.endr
+
+.ifc \variant, identity_
+  li t1, 2*(5793-4096)*8
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vsmul.vx v16, v\i, t1
+  vssra.vi v16, v16, 1
+  vsadd.vv v\i, v\i, v16
+.endr
+
+  j L(itx_16x4_epilog)
+.else
+  jalr t0, a4
+
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vssra.vi v\i, v\i, 1
+.endr
+
+L(itx_16x4_epilog):
+  li t0, 32
+  vssseg8e16.v v0, (a2), t0
+  addi t1, a2, 16
+  vssseg8e16.v v8, (t1), t0
+
+.irp j, 0, 8
+  vsetivli zero, 8, e16, m1, ta, ma
+
+  vmv.v.x v4, zero
+  addi t0, a2, \j*2
+  vle16.v v0, (t0)
+  vse16.v v4, (t0)
+.irp i, 1, 2, 3
+  addi t0, t0, 32
+  vle16.v v\i, (t0)
+  vse16.v v4, (t0)
+.endr
+
+  jalr t0, a5
+
+  vssra.vi v0, v0, 4
+  vssra.vi v1, v1, 4
+  vssra.vi v2, v2, 4
+  vssra.vi v3, v3, 4
+
+  vsetvli zero, zero, e8, mf2, ta, ma
+  addi t0, a0, \j
+  vle8.v v4, (t0)
+  add t0, t0, a1
+  vle8.v v5, (t0)
+  add t0, t0, a1
+  vle8.v v6, (t0)
+  add t0, t0, a1
+  vle8.v v7, (t0)
+
+  vwaddu.wv v0, v0, v4
+  vwaddu.wv v1, v1, v5
+  vwaddu.wv v2, v2, v6
+  vwaddu.wv v3, v3, v7
+
+  vsetvli zero, zero, e16, m1, ta, ma
+  vmax.vx v0, v0, zero
+  vmax.vx v1, v1, zero
+  vmax.vx v2, v2, zero
+  vmax.vx v3, v3, zero
+
+  vsetvli zero, zero, e8, mf2, ta, ma
+
+  vnclipu.wi v4, v0, 0
+  vnclipu.wi v5, v1, 0
+  vnclipu.wi v6, v2, 0
+  vnclipu.wi v7, v3, 0
+
+  addi t0, a0, \j
+  vse8.v v4, (t0)
+  add t0, t0, a1
+  vse8.v v5, (t0)
+  add t0, t0, a1
+  vse8.v v6, (t0)
+  add t0, t0, a1
+  vse8.v v7, (t0)
+.endr
+
+  ret
+.endif
+endfunc
+.endm
+
+def_fn_416_base identity_
+def_fn_416_base
+
+.macro def_fn_416 w, h, txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_rvv, export=1
+.if \w == 4 && (\txfm1 == adst || \txfm1 == flipadst)
+  la a4, inv_\txfm1\()_e16_x\w\()w_rvv
+.elseif \txfm1 != identity
+  la a4, inv_\txfm1\()_e16_x\w\()_rvv
+.endif
+.if \h == 4 && (\txfm2 == adst || \txfm2 == flipadst)
+  la a5, inv_\txfm2\()_e16_x\h\()w_rvv
+.else
+  la a5, inv_\txfm2\()_e16_x\h\()_rvv
+.endif
+.if \w == 4
+  li a6, \eob_half
+.endif
+.ifc \txfm1, identity
+  j inv_txfm_identity_add_\w\()x\h\()_rvv
+.else
+  j inv_txfm_add_\w\()x\h\()_rvv
+.endif
+endfunc
+.endm
+
+.macro def_fns_416 w, h
+def_fn_416 \w, \h, dct, dct, 29
+def_fn_416 \w, \h, identity, identity, 29
+def_fn_416 \w, \h, dct, adst, 29
+def_fn_416 \w, \h, dct, flipadst, 29
+def_fn_416 \w, \h, dct, identity, 8
+def_fn_416 \w, \h, adst, dct, 29
+def_fn_416 \w, \h, adst, adst, 29
+def_fn_416 \w, \h, adst, flipadst, 29
+def_fn_416 \w, \h, flipadst, dct, 29
+def_fn_416 \w, \h, flipadst, adst, 29
+def_fn_416 \w, \h, flipadst, flipadst, 29
+def_fn_416 \w, \h, identity, dct, 32
+def_fn_416 \w, \h, adst, identity, 8
+def_fn_416 \w, \h, flipadst, identity, 8
+def_fn_416 \w, \h, identity, adst, 32
+def_fn_416 \w, \h, identity, flipadst, 32
+.endm
+
+def_fns_416 4, 16
+def_fns_416 16, 4
+
+.macro def_fn_816_base variant
+function inv_txfm_\variant\()add_8x16_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 8, e16, m1, ta, ma
+
+  blt a3, a6, 1f
+
+  vmv.v.x v16, zero
+  addi t0, a2, 16
+  vle16.v v0, (t0)
+  vse16.v v16, (t0)
+.irp i, 1, 2, 3, 4, 5, 6, 7
+  addi t0, t0, 32
+  vle16.v v\i, (t0)
+  vse16.v v16, (t0)
+.endr
+
+  li t1, 2896*8
+.ifc \variant, identity_
+  vsmul.vx  v8, v0, t1
+  vsmul.vx  v9, v1, t1
+  vsmul.vx v10, v2, t1
+  vsmul.vx v11, v3, t1
+  vsmul.vx v12, v4, t1
+  vsmul.vx v13, v5, t1
+  vsmul.vx v14, v6, t1
+  vsmul.vx v15, v7, t1
+.else
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7
+  vsmul.vx v\i, v\i, t1
+.endr
+
+  jalr t0, a4
+
+  vssra.vi  v8, v0, 1
+  vssra.vi  v9, v1, 1
+  vssra.vi v10, v2, 1
+  vssra.vi v11, v3, 1
+  vssra.vi v12, v4, 1
+  vssra.vi v13, v5, 1
+  vssra.vi v14, v6, 1
+  vssra.vi v15, v7, 1
+.endif
+
+  j 2f
+
+1:
+.irp i, 8, 9, 10, 11, 12, 13, 14, 15
+  vmv.v.x v\i, zero
+.endr
+
+2:
+  vmv.v.x v16, zero
+  vle16.v v0, (a2)
+  vse16.v v16, (a2)
+  addi t0, a2, 32
+  vle16.v v1, (t0)
+  vse16.v v16, (t0)
+.irp i, 2, 3, 4, 5, 6, 7
+  addi t0, t0, 32
+  vle16.v v\i, (t0)
+  vse16.v v16, (t0)
+.endr
+
+  li t1, 2896*8
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7
+  vsmul.vx v\i, v\i, t1
+.endr
+
+.ifc \variant, identity_
+  j L(itx_8x16_epilog)
+.else
+  jalr t0, a4
+
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7
+  vssra.vi v\i, v\i, 1
+.endr
+
+L(itx_8x16_epilog):
+  addi t4, sp, -8*32
+  vsseg8e16.v v0, (t4)
+  addi t0, t4, 8*16
+  vsseg8e16.v v8, (t0)
+
+  mv t5, a0
+  li t6, 16
+  jal a7, inv_txfm_add_vert_8x16_rvv
+
+  ret
+.endif
+endfunc
+
+function inv_txfm_\variant\()add_16x8_rvv, export=1, ext=v
+  csrw vxrm, zero
+
+  vsetivli zero, 8, e16, m1, ta, ma
+  vle16.v v0, (a2)
+  addi t0, a2, 16
+  vle16.v v1, (t0)
+.irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  addi t0, t0, 16
+  vle16.v v\i, (t0)
+.endr
+
+  li t1, 2896*8
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vsmul.vx v\i, v\i, t1
+.endr
+
+.ifc \variant, identity_
+  li t1, 2*(5793-4096)*8
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vsmul.vx v16, v\i, t1
+  vssra.vi v16, v16, 1
+  vsadd.vv v\i, v\i, v16
+.endr
+
+  j L(itx_16x8_epilog)
+.else
+  jalr t0, a4
+
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+  vssra.vi v\i, v\i, 1
+.endr
+
+L(itx_16x8_epilog):
+  li t0, 32
+  vssseg8e16.v v0, (a2), t0
+  addi t1, a2, 16
+  vssseg8e16.v v8, (t1), t0
+
+.irp j, 0, 8
+  vsetivli zero, 8, e16, m1, ta, ma
+
+  vmv.v.x v8, zero
+  addi t0, a2, \j*2
+  vle16.v v0, (t0)
+  vse16.v v8, (t0)
+.irp i, 1, 2, 3, 4, 5, 6, 7
+  addi t0, t0, 32
+  vle16.v v\i, (t0)
+  vse16.v v8, (t0)
+.endr
+
+  jalr t0, a5
+
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7
+  vssra.vi v\i, v\i, 4
+.endr
+
+  vsetvli zero, zero, e8, mf2, ta, ma
+  addi t0, a0, \j
+  vle8.v v8, (t0)
+.irp i, 9, 10, 11, 12, 13, 14, 15
+  add t0, t0, a1
+  vle8.v v\i, (t0)
+.endr
+
+  vwaddu.wv v0, v0, v8
+  vwaddu.wv v1, v1, v9
+  vwaddu.wv v2, v2, v10
+  vwaddu.wv v3, v3, v11
+  vwaddu.wv v4, v4, v12
+  vwaddu.wv v5, v5, v13
+  vwaddu.wv v6, v6, v14
+  vwaddu.wv v7, v7, v15
+
+  vsetvli zero, zero, e16, m1, ta, ma
+.irp i, 0, 1, 2, 3, 4, 5, 6, 7
+  vmax.vx v\i, v\i, zero
+.endr
+
+  vsetvli zero, zero, e8, mf2, ta, ma
+
+  vnclipu.wi  v8, v0, 0
+  vnclipu.wi  v9, v1, 0
+  vnclipu.wi v10, v2, 0
+  vnclipu.wi v11, v3, 0
+  vnclipu.wi v12, v4, 0
+  vnclipu.wi v13, v5, 0
+  vnclipu.wi v14, v6, 0
+  vnclipu.wi v15, v7, 0
+
+  addi t0, a0, \j
+  vse8.v v8, (t0)
+.irp i, 9, 10, 11, 12, 13, 14, 15
+  add t0, t0, a1
+  vse8.v v\i, (t0)
+.endr
+.endr
+
+  ret
+.endif
+endfunc
+.endm
+
+def_fn_816_base identity_
+def_fn_816_base
+
+.macro def_fn_816 w, h, txfm1, txfm2, eob_half
+function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_rvv, export=1
+.ifnc \txfm1, identity
+  la a4, inv_\txfm1\()_e16_x\w\()_rvv
+.endif
+  la a5, inv_\txfm2\()_e16_x\h\()_rvv
+.if \w == 8
+  li a6, \eob_half
+.endif
+.ifc \txfm1, identity
+  j inv_txfm_identity_add_\w\()x\h\()_rvv
+.else
+  j inv_txfm_add_\w\()x\h\()_rvv
+.endif
+endfunc
+.endm
+
+.macro def_fns_816 w, h
+def_fn_816 \w, \h, dct, dct, 43
+def_fn_816 \w, \h, identity, identity, 43
+def_fn_816 \w, \h, dct, adst, 43
+def_fn_816 \w, \h, dct, flipadst, 43
+def_fn_816 \w, \h, dct, identity, 8
+def_fn_816 \w, \h, adst, dct, 43
+def_fn_816 \w, \h, adst, adst, 43
+def_fn_816 \w, \h, adst, flipadst, 43
+def_fn_816 \w, \h, flipadst, dct, 43
+def_fn_816 \w, \h, flipadst, adst, 43
+def_fn_816 \w, \h, flipadst, flipadst, 43
+def_fn_816 \w, \h, identity, dct, 64
+def_fn_816 \w, \h, adst, identity, 8
+def_fn_816 \w, \h, flipadst, identity, 8
+def_fn_816 \w, \h, identity, adst, 64
+def_fn_816 \w, \h, identity, flipadst, 64
+.endm
+
+def_fns_816 8, 16
+def_fns_816 16, 8
diff --git a/media/libdav1d/src/src/riscv/64/mc.S b/media/libdav1d/src/src/riscv/64/mc.S
new file mode 100644
index 0000000000..afc83ce2c7
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/mc.S
@@ -0,0 +1,975 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Nathan Egge, Niklas Haas, Bogdan Gligorijevic
+ * Copyright © 2025, Sungjoon Moon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+function blend_vl512_8bpc_rvv, export=1, ext=zbb
+  srai t0, a3, 3
+  ctz t0, t0
+  addi t0, t0, 0xc5
+  j L(blend_epilog)
+endfunc
+
+function blend_vl256_8bpc_rvv, export=1, ext=zbb
+  ctz t0, a3
+  addi t0, t0, 0xc3
+  j L(blend_epilog)
+endfunc
+
+function blend_8bpc_rvv, export=1, ext="v,zbb"
+  ctz t0, a3
+  addi t0, t0, 0xc4
+L(blend_epilog):
+  csrw vxrm, zero
+  andi t0, t0, 0xc7
+  vsetvl zero, a3, t0
+  li t1, 64
+1:
+  addi a4, a4, -2
+  vle8.v v4, (a2)
+  add a2, a2, a3
+  vle8.v v6, (a2)
+  add a2, a2, a3
+  vle8.v v8, (a5)
+  add a5, a5, a3
+  vle8.v v10, (a5)
+  add a5, a5, a3
+  vle8.v v0, (a0)
+  add t0, a0, a1
+  vle8.v v2, (t0)
+  vwmulu.vv v16, v4, v8
+  vwmulu.vv v20, v6, v10
+  vrsub.vx v8, v8, t1
+  vrsub.vx v10, v10, t1
+  vwmaccu.vv v16, v0, v8
+  vwmaccu.vv v20, v2, v10
+  vnclipu.wi v0, v16, 6
+  vnclipu.wi v2, v20, 6
+  vse8.v v0, (a0)
+  vse8.v v2, (t0)
+  add a0, t0, a1
+  bnez a4, 1b
+  ret
+endfunc
+
+function blend_h_vl512_8bpc_rvv, export=1, ext=zbb
+  srai t0, a3, 3
+  li t2, 64
+  ctz t0, t0
+  addi t0, t0, 0xc5
+  j L(blend_h_epilog)
+endfunc
+
+function blend_h_vl256_8bpc_rvv, export=1, ext=zbb
+  srai t0, a3, 2
+  li t2, 64
+  ctz t0, t0
+  addi t0, t0, 0xc5
+  j L(blend_h_epilog)
+endfunc
+
+function blend_h_8bpc_rvv, export=1, ext="v,zbb"
+  li t2, 64
+  bgt a3, t2, 128f
+  ctz t0, a3
+  addi t0, t0, 0xc4
+L(blend_h_epilog):
+  csrw vxrm, zero
+  andi t0, t0, 0xc7
+  vsetvl zero, a3, t0
+  la t1, dav1d_obmc_masks
+  srai t0, a4, 2
+  add t1, t1, a4
+  sub a4, a4, t0
+0:
+  mv t5, ra
+1:
+  addi a4, a4, -2
+  lbu t3, (t1)
+  addi t1, t1, 1
+  lbu t4, (t1)
+  addi t1, t1, 1
+  vle8.v v8, (a2)
+  add a2, a2, a3
+  vle8.v v12, (a2)
+  add a2, a2, a3
+  vle8.v v0, (a0)
+  add t0, a0, a1
+  vle8.v v4, (t0)
+  vwmulu.vx v16, v8, t3
+  vwmulu.vx v24, v12, t4
+  sub t3, t2, t3
+  sub t4, t2, t4
+  vwmaccu.vx v16, t3, v0
+  vwmaccu.vx v24, t4, v4
+  vnclipu.wi v0, v16, 6
+  vnclipu.wi v4, v24, 6
+  vse8.v v0, (a0)
+  vse8.v v4, (t0)
+  add a0, t0, a1
+  bgtz a4, 1b
+  jr t5
+128:
+  csrw vxrm, zero
+  vsetvli zero, t2, e8, m4, ta, ma
+  la t1, dav1d_obmc_masks
+  srai t0, a4, 2
+  add t1, t1, a4
+  sub a4, a4, t0
+  mv a5, a0
+  mv a6, a2
+  mv a7, a4
+  jal t5, 1b
+  add t1, t1, a4
+  add a0, a5, t2
+  add a2, a6, t2
+  mv a4, a7
+  sub t1, t1, a4
+  j 0b
+endfunc
+
+function blend_v_vl512_8bpc_rvv, export=1, ext=zbb
+  srai t0, a3, 3
+  ctz t0, t0
+  addi t0, t0, 0xc5
+  j L(blend_v_epilog)
+endfunc
+
+function blend_v_vl256_8bpc_rvv, export=1, ext=zbb
+  srai t0, a3, 2
+  ctz t0, t0
+  addi t0, t0, 0xc5
+  j L(blend_v_epilog)
+endfunc
+
+function blend_v_8bpc_rvv, export=1, ext="v,zbb"
+  ctz t0, a3
+  addi t0, t0, 0xc4
+L(blend_v_epilog):
+  andi t0, t0, 0xc7
+  srai t1, a3, 2
+  sub t1, a3, t1
+  vsetvl zero, t1, t0
+  csrw vxrm, zero
+  la t1, dav1d_obmc_masks
+  add t1, t1, a3
+  vle8.v v8, (t1)
+  li t0, 64
+  vrsub.vx v10, v8, t0
+1:
+  addi a4, a4, -2
+  vle8.v v4, (a2)
+  add a2, a2, a3
+  vle8.v v6, (a2)
+  add a2, a2, a3
+  vle8.v v0, (a0)
+  add t0, a0, a1
+  vle8.v v2, (t0)
+  vwmulu.vv v12, v4, v8
+  vwmulu.vv v16, v6, v8
+  vwmaccu.vv v12, v0, v10
+  vwmaccu.vv v16, v2, v10
+  vnclipu.wi v0, v12, 6
+  vnclipu.wi v2, v16, 6
+  vse8.v v0, (a0)
+  vse8.v v2, (t0)
+  add a0, t0, a1
+  bnez a4, 1b
+  ret
+endfunc
+
+.macro avg va, vb, vm
+    vadd.vv \va, \va, \vb
+.endm
+
+.macro w_avg va, vb, vm
+    vwmul.vx v24, \va, a6
+    vwmacc.vx v24, a7, \vb
+    vnclip.wi \va, v24, 8
+.endm
+
+.macro mask va, vb, vm
+    vwmul.vv v24, \va, \vm
+    vrsub.vx \vm, \vm, a7
+    vwmacc.vv v24, \vb, \vm
+    vnclip.wi \va, v24, 10
+.endm
+
+.macro bidir_fn type, shift
+function \type\()_8bpc_rvv, export=1, ext="v,zba,zbb"
+.ifc \type, w_avg
+    li a7, 16
+    sub a7, a7, a6
+.endif
+.ifc \type, mask
+    li a7, 64
+.endif
+    li t0, 4
+    csrw vxrm, zero
+    beq t0, a4, 4f
+    csrr t0, vlenb
+    ctz t1, a4
+    ctz t0, t0
+    li t2, 1
+    sub t0, t1, t0
+    li t4, -3
+    bgt t0, t2, 2f
+    max t0, t0, t4
+    andi t1, t0, 0x7
+    addi t0, t1, 1 # may overflow into E16 bit
+    ori t0, t0, MA | TA | E16
+    ori t1, t1, MA | TA | E8
+1:
+    addi a5, a5, -4
+.rept 2
+    vsetvl zero, a4, t0
+    sh1add t3, a4, a2
+    vle16.v v0, (a2)
+    sh1add a2, a4, t3
+    vle16.v v4, (t3)
+    sh1add t3, a4, a3
+    vle16.v v8, (a3)
+    sh1add a3, a4, t3
+    vle16.v v12, (t3)
+.ifc \type, mask
+    add t3, a4, a6
+    vle8.v v24, (a6)
+    add a6, a4, t3
+    vle8.v v26, (t3)
+    vzext.vf2 v16, v24
+    vzext.vf2 v20, v26
+.endif
+    \type v0, v8, v16
+    \type v4, v12, v20
+    vmax.vx v8, v0, zero
+    vmax.vx v12, v4, zero
+    vsetvl zero, zero, t1
+    vnclipu.wi v0, v8,  \shift
+    vnclipu.wi v2, v12, \shift
+    add t3, a1, a0
+    vse8.v v0, (a0)
+    add a0, a1, t3
+    vse8.v v2, (t3)
+.endr
+    bnez a5, 1b
+    ret
+2:
+    mv t0, a0
+    neg t4, a4
+    add a0, a1, a0
+    addi a5, a5, -1
+20:
+    vsetvli t2, a4, e16, m4, ta, ma
+    sh1add t4, t2, t4
+    sh1add t3, t2, a2
+    vle16.v v0, (a2)
+    sh1add a2, t2, t3
+    vle16.v v4, (t3)
+    sh1add t3, t2, a3
+    vle16.v v8, (a3)
+    sh1add a3, t2, t3
+    vle16.v v12, (t3)
+.ifc \type, mask
+    add t3, t2, a6
+    vle8.v v24, (a6)
+    add a6, t2, t3
+    vle8.v v26, (t3)
+    vzext.vf2 v16, v24
+    vzext.vf2 v20, v26
+.endif
+    \type v0, v8, v16
+    \type v4, v12, v20
+    vmax.vx v8, v0, zero
+    vmax.vx v12, v4, zero
+    vsetvli zero, zero, e8, m2, ta, ma
+    vnclipu.wi v0, v8,  \shift
+    vnclipu.wi v2, v12, \shift
+    add t3, t2, t0
+    vse8.v v0, (t0)
+    add t0, t2, t3
+    vse8.v v2, (t3)
+    bnez t4, 20b
+    bnez a5, 2b
+    ret
+4:
+    slli t0, a5, 2
+    vsetvli t1, t0, e16, m4, ta, ma
+    vle16.v v0, (a2)
+    sh1add a2, t1, a2
+    vle16.v v4, (a3)
+    sh1add a3, t1, a3
+.ifc \type, mask
+    vle8.v v16, (a6)
+    add a6, t1, a6
+    vzext.vf2 v8, v16
+.endif
+    \type v0, v4, v8
+    vmax.vx v8, v0, zero
+    vsetvli zero, zero, e8, m2, ta, ma
+    vnclipu.wi v0, v8, \shift
+    vsetvli t1, a5, e32, m2, ta, ma
+    vsse32.v v0, (a0), a1
+    ctz t0, t1
+    sub a5, a5, t1
+    sll t0, a1, t0
+    add a0, t0, a0
+    bnez a5, 4b
+    ret
+endfunc
+.endm
+
+bidir_fn avg,   5
+bidir_fn w_avg, 0
+bidir_fn mask,  0
+
+function warp_8x8_8bpc_rvv, export=1, ext="v"
+    csrw vxrm, zero
+
+    vsetivli zero, 8, e16, m1, ta, ma
+    addi sp, sp, -2*15*8
+    mv t5, sp
+    li t0, 3
+    mul t0, a3, t0
+    sub a2, a2, t0
+    addi a2, a2, -3
+
+    li t0, 64
+    addi a3, a3, -8
+    li t1, 15
+    la t2, dav1d_mc_warp_filter
+
+    lh t6, (a4)
+    lh t4, 2(a4)
+    vid.v v30
+    vwmul.vx v28, v30, t6
+1:
+    addi t1, t1, -1
+
+
+    vsetvli zero, zero, e32, m2, ta, ma
+    vadd.vx v4, v28, a5
+    add a5, a5, t4
+    vssra.vi v2, v4, 10
+    vadd.vx v2, v2, t0
+    vsll.vi v24, v2, 3
+    vsetvli zero, zero, e8, mf2, ta, ma
+
+    vluxseg8ei32.v v2, (t2), v24
+
+    vsetvli zero, zero, e16, m1, ta, ma
+.irp i, 2, 3, 4, 5, 6, 7, 8, 9
+    vle8.v v10, (a2)
+    addi a2, a2, 1
+
+    vsext.vf2 v14, v\i
+    vzext.vf2 v16, v10
+
+.if \i == 2
+    vwmulsu.vv v12, v14, v16
+.else
+    vwmaccsu.vv v12, v14, v16
+.endif
+.endr
+    vnclip.wi v10, v12, 3
+
+    add a2, a2, a3
+    vse16.v v10, (t5)
+    addi t5, t5, 16
+
+    bnez t1, 1b
+
+    mv t5, sp
+    li t1, 8
+
+    lh t6, 4(a4)
+    lh t4, 6(a4)
+    vwmul.vx v28, v30, t6
+2:
+    addi t1, t1, -1
+
+    vsetvli zero, zero, e32, m2, ta, ma
+    vadd.vx v4, v28, a6
+
+    add a6, a6, t4
+    vssra.vi v2, v4, 10
+    vadd.vx v2, v2, t0
+    vsll.vi v24, v2, 3
+    vsetvli zero, zero, e8, mf2, ta, ma
+
+    vluxseg8ei32.v v2, (t2), v24
+    vsetvli zero, zero, e16, m1, ta, ma
+
+.irp i, 2, 3, 4, 5, 6, 7, 8, 9
+    vle16.v v10, (t5)
+    addi t5, t5, 16
+
+    vsext.vf2 v14, v\i
+
+.if \i == 2
+    vwmul.vv v12, v14, v10
+.else
+    vwmacc.vv v12, v14, v10
+.endif
+.endr
+    addi t5, t5, -16*7
+    vnclip.wi v10, v12, 11
+
+    vmax.vx v10, v10, zero
+    vsetvli zero, zero, e8, mf2, ta, ma
+
+    vnclipu.wi v12, v10, 0
+
+    vse8.v v12, (a0)
+    add a0, a0, a1
+
+    bnez t1, 2b
+
+    addi sp, sp, 2*15*8
+
+    ret
+endfunc
+
+function warp_8x8t_8bpc_rvv, export=1, ext="v,zba"
+    csrw vxrm, zero
+
+    vsetivli zero, 8, e16, m1, ta, ma
+    addi sp, sp, -2*15*8
+    mv t5, sp
+    li t0, 3
+    mul t0, a3, t0
+    sub a2, a2, t0
+    addi a2, a2, -3
+
+    li t0, 64
+    addi a3, a3, -8
+    li t1, 15
+    la t2, dav1d_mc_warp_filter
+
+    lh t6, (a4)
+    lh t4, 2(a4)
+    vid.v v30
+    vwmul.vx v28, v30, t6
+1:
+    addi t1, t1, -1
+
+
+    vsetvli zero, zero, e32, m2, ta, ma
+    vadd.vx v4, v28, a5
+    add a5, a5, t4
+    vssra.vi v2, v4, 10
+    vadd.vx v2, v2, t0
+    vsll.vi v24, v2, 3
+    vsetvli zero, zero, e8, mf2, ta, ma
+
+    vluxseg8ei32.v v2, (t2), v24
+
+    vsetvli zero, zero, e16, m1, ta, ma
+.irp i, 2, 3, 4, 5, 6, 7, 8, 9
+    vle8.v v10, (a2)
+    addi a2, a2, 1
+
+    vsext.vf2 v14, v\i
+    vzext.vf2 v16, v10
+
+.if \i == 2
+    vwmulsu.vv v12, v14, v16
+.else
+    vwmaccsu.vv v12, v14, v16
+.endif
+.endr
+    vnclip.wi v10, v12, 3
+
+    add a2, a2, a3
+    vse16.v v10, (t5)
+    addi t5, t5, 16
+
+    bnez t1, 1b
+
+    mv t5, sp
+    li t1, 8
+
+    lh t6, 4(a4)
+    lh t4, 6(a4)
+    vwmul.vx v28, v30, t6
+2:
+    addi t1, t1, -1
+
+    vsetvli zero, zero, e32, m2, ta, ma
+    vadd.vx v4, v28, a6
+    add a6, a6, t4
+    vssra.vi v2, v4, 10
+    vadd.vx v2, v2, t0
+    vsll.vi v24, v2, 3
+    vsetvli zero, zero, e8, mf2, ta, ma
+
+    vluxseg8ei32.v v2, (t2), v24
+    vsetvli zero, zero, e16, m1, ta, ma
+
+.irp i, 2, 3, 4, 5, 6, 7, 8, 9
+    vle16.v v10, (t5)
+    addi t5, t5, 16
+
+    vsext.vf2 v14, v\i
+
+.if \i == 2
+    vwmul.vv v12, v14, v10
+.else
+    vwmacc.vv v12, v14, v10
+.endif
+
+.endr
+    addi t5, t5, -16*7
+    vnclip.wi v10, v12, 7
+
+    vse16.v v10, (a0)
+    sh1add a0, a1, a0
+
+    bnez t1, 2b
+
+    addi sp, sp, 2*15*8
+
+    ret
+endfunc
+
+function emu_edge_8bpc_rvv, export=1, ext="v,zbb"
+  ld t0, 0(sp)
+  ld t1, 8(sp)
+
+  // int cx = iclip((int) x, 0, (int) iw - 1);
+  max t2, a4, zero
+  addi t4, a2, -1
+  min t2, t2, t4
+
+  // int cy = iclip((int) y, 0, (int) ih - 1);
+  max t3, a5, zero
+  addi t5, a3, -1
+  min t3, t3, t5
+
+  // ref += cy*PXSTRIDE(ref_stride) + cx
+  mul t3, t3, t1
+  add t3, t3, t2
+
+  add t0, t0, t3
+
+  addi t4, a0, -1
+
+  neg t2, a4
+  add t3, a4, a0
+  sub t3, t3, a2
+
+  // int left_ext = iclip((int) -x, 0, (int) bw - 1);
+  max t2, t2, zero
+  min a2, t2, t4 # a2 = left_ext
+
+  // int right_ext = iclip((int) (x + bw - iw), 0, (int) bw - 1);
+  max t3, t3, zero
+  min a4, t3, t4 # a4 = right_ext
+
+  addi t6, a1, -1
+
+  neg t4, a5
+  add t5, a5, a1
+  sub t5, t5, a3
+
+  // int top_ext = iclip((int) -y, 0, (int) bh - 1);
+  max t4, t4, zero
+  min a3, t4, t6 # a3 = top_ext
+
+  // int bottom_ext = iclip((int) (x + bh - ih), 0, (int) bh - 1);
+  max t5, t5, zero
+  min a5, t5, t6 # a5 = bottom_ext
+
+  sub t4, a1, a3
+  sub t4, t4, a5 # t4 = center_h
+
+  mul t5, a3, a7
+  add a1, a6, t5 # blk = dst + top_ext * dst_stride
+
+  sub t3, a0, a2
+  sub t3, t3, a4 # t3 = center_w = bw - left_ext - right_ext
+
+.macro v_loop need_left, need_right
+9:
+  # pixel_copy()
+  add t5, a1, a2 # t5 = blk + left_ext
+  mv t2, t0 # ref
+0:
+  vsetvli t6, t3, e8, m1, ta, ma
+  vle8.v v8, (t2)
+  add t2, t2, t6
+
+  vse8.v v8, (t5)
+  sub t3, t3, t6
+  add t5, t5, t6
+  bnez t3, 0b
+
+  sub t3, a0, a2
+  sub t3, t3, a4 # t3 = center_w = bw - left_ext - right_ext
+
+.if \need_left
+  lb t2, (t0) # ref[0]
+  # pixel_set()
+  vsetvli t6, a2, e8, m1, ta, ma
+  vmv.v.x v8, t2
+  mv t2, a2 # left_ext
+  mv t5, a1 # blk
+0:
+  vse8.v v8, (t5)
+  sub t2, t2, t6 # left_ext -= t6
+  add t5, t5, t6 # blk += t6
+  vsetvli t6, t2, e8, m1, ta, ma
+  bnez t2, 0b
+.endif
+
+.if \need_right
+  add t5, a1, a2 # t5 = blk + left_ext
+  add t5, t5, t3 # t5 = blk + left_ext + center_w
+  lb t2, -1(t5) # blk[left_ext + center_w - 1]
+  # pixel_set()
+  vsetvli t6, a4, e8, m1, ta, ma
+  vmv.v.x v8, t2
+  mv t2, a4 # right_ext
+0:
+  vse8.v v8, (t5)
+  sub t2, t2, t6
+  add t5, t5, t6
+  vsetvli t6, t2, e8, m1, ta, ma
+  bnez t2, 0b
+.endif
+
+  add t0, t0, t1 # ref += ref_stride
+  add a1, a1, a7 # blk += dst_stride
+  addi t4, t4, -1 # center_h--
+  bnez t4, 9b
+.endm
+
+L(emu_edge_center):
+  blez t4, L(emu_edge_bottom)
+
+  beqz a2, 1f # if (left_ext)
+  beqz a4, 2f # if (right_ext)
+  v_loop 1, 1
+  j L(emu_edge_bottom)
+
+1:
+  beqz a4, 3f
+  v_loop 0, 1
+  j L(emu_edge_bottom)
+
+2:
+  v_loop 1, 0
+  j L(emu_edge_bottom)
+
+3:
+  v_loop 0, 0
+
+L(emu_edge_bottom): # copy bottom
+  blez a5, L(emu_edge_top)
+  mv t2, a0 # bw
+2:
+  mv t5, a5 # bottom_ext
+  mv t1, a1 # dst
+
+  vsetvli t6, t2, e8, m1, ta, ma
+  sub t0, t1, a7 # dst - dst_stride
+  vle8.v v8, (t0)
+0:
+  vse8.v v8, (t1)
+  add t1, t1, a7
+  addi t5, t5, -1
+  bnez t5, 0b
+
+  sub t2, t2, t6
+  add a1, a1, t6
+  bnez t2, 2b
+
+L(emu_edge_top): # copy top
+  blez a3, L(emu_edge_end)
+  mul t5, a3, a7
+  add t1, a6, t5 # blk = dst + top_ext * PXSTRIDE(dst_stride)
+  # a6 = dst
+1:
+  mv t0, a3 # top_ext
+  mv t4, a6 # dst
+
+  vsetvli t6, a0, e8, m1, ta, ma
+  vle8.v v8, (t1)
+0:
+  vse8.v v8, (t4)
+  add t4, t4, a7
+  vse8.v v8, (t4)
+  add t4, t4, a7
+  addi t0, t0, -2
+  bgtz t0, 0b
+
+  sub a0, a0, t6
+  add t1, t1, t6
+  add a6, a6, t6
+
+  bnez a0, 1b
+
+L(emu_edge_end):
+  ret
+endfunc
+
+.macro w_mask_fn type vlen
+function w_mask_\type\()_\vlen\()8bpc_rvv, export=1, ext="v,zba,zbb"
+  csrw vxrm, zero
+  li t1, 38*256+8
+.ifc \vlen, vl256_
+  addi t0, zero, 64
+  bgt a4, t0, 2f
+  li t2, 0xCAC9C8CFCE0000
+  li t3, 0xC1C0C7C6C50000
+.else
+  addi t0, zero, 32
+  bgt a4, t0, 2f
+  li t2, 0xCAC9C8CF0000
+  li t3, 0xC1C0C7C60000
+.endif
+  ctz t4, a4
+  slli t4, t4, 3
+  srl t2, t2, t4
+  andi t2, t2, 0xFF
+  srl t3, t3, t4
+  andi t3, t3, 0xFF
+
+1:
+.if \type == 444
+w_mask_body 444 narrow
+
+  sh1add a0, a1, a0 # dst += dst_stride
+  add a6, a6, a4 # mask += w
+.elseif \type == 422
+w_mask_body 422 narrow
+
+  sh1add a0, a1, a0 # dst += dst_stride
+  srli t4, a4, 1
+  add a6, a6, t4 # mask += w >> 1
+.elseif \type == 420
+w_mask_body 420 narrow
+
+  sh1add a0, a1, a0 # dst += dst_stride
+.endif
+
+  sh1add a2, a4, a2
+  sh1add a3, a4, a3
+
+  addi a5, a5, -2
+  bnez a5, 1b
+
+  ret
+
+2:
+  li t2, 0xca
+  li t3, 0xc1
+
+3:
+  mv t5, zero
+
+.if \type == 444
+w_mask_body 444 wide # VLEN>=256
+.elseif \type == 422
+w_mask_body 422 wide # VLEN>=256
+.elseif \type == 420
+w_mask_body 420 wide # VLEN>=256
+.endif
+
+  add t5, t5, t6
+  bne t5, a4, 4b
+
+  sh1add a0, a1, a0 # dst += dst_stride
+.if \type == 444
+  add a6, a6, a4 # mask += w
+.elseif \type == 422
+  srli t4, a4, 1
+  add a6, a6, t4 # mask += w >> 1
+.elseif \type == 420
+.endif
+
+  sh1add a2, a4, a2
+  sh1add a3, a4, a3
+
+  addi a5, a5, -2
+  bnez a5, 3b
+
+  ret
+
+endfunc
+.endm
+
+.macro w_mask_body type size
+  mv t0, a0 # dst
+
+4:
+  vsetvl t6, a4, t2
+
+  # load tmp1 and tmp2
+  vle16.v v0, (a2) # tmp1[x]
+
+  sh1add t4, a4, a2 # tmp1
+  vle16.v v16, (t4) # tmp1[x]
+  sh1add a2, t6, a2 # tmp1 += w / k
+
+  vle16.v v4, (a3) # tmp2[x]
+
+  sh1add t4, a4, a3 # tmp2
+  vle16.v v20, (t4) # tmp2[x]
+  sh1add a3, t6, a3 # tmp2 += w / k
+
+  # v12 = abs(tmp1[x] - tmp2[x])
+  vsub.vv v12, v0, v4 # tmp1[x] - tmp2[x]
+  vsub.vv v8, v4, v0 # tmp2[x] - tmp1[x]
+  vmax.vv v8, v12, v8
+
+  vsub.vv v28, v16, v20 # tmp1[x] - tmp2[x]
+  vsub.vv v24, v20, v16 # tmp2[x] - tmp1[x]
+  vmax.vv v24, v28, v24
+
+  li t4, 64
+
+  # min(38 + (v12 + 8) >> 8, 64) -> min((v12 + 38*256 + 8) >> 8, 64)
+  vadd.vx v8, v8, t1
+  vsra.vi v8, v8, 8
+  vmin.vx v8, v8, t4
+
+  vadd.vx v24, v24, t1
+  vsra.vi v24, v24, 8
+  vmin.vx v24, v24, t4
+
+  # dst[x] = (tmp1[x] - tmp2[x]) * m + 64 * tmp2[x];
+  # v12, v28 = tmp1[x] - tmp2[x]
+  # v8, v24 = {m,n}
+  vwmul.vx v0, v4, t4
+  vwmacc.vv v0, v8, v12
+  vnclipu.wi v0, v0, 10
+  vmax.vx v0, v0, zero
+
+  vwmul.vx v16, v20, t4
+  vwmacc.vv v16, v24, v28
+  vnclipu.wi v16, v16, 10
+  vmax.vx v16, v16, zero
+
+.if \type == 444
+  vsetvl zero, zero, t3
+
+  vnclipu.wi v0, v0, 0
+  vnclipu.wi v16, v16, 0
+
+  vse8.v v0, (t0) # dst[x] =
+  add t4, t0, a1
+  vse8.v v16, (t4) # dst[x] =
+  add t0, t0, t6
+
+  vnsrl.wi v8, v8, 0
+  vnsrl.wi v24, v24, 0
+
+  vse8.v v8, (a6) # mask[x] = m
+  add t4, a6, a4
+  vse8.v v24, (t4) # mask[x] = m
+  add a6, a6, t6
+
+.elseif \type == 422
+  # v4, v20 = m
+  # v12, v28 = n
+  vnsrl.wi v4, v8, 0
+  vnsrl.wi v8, v8, 16
+
+  vnsrl.wi v20, v24, 0
+  vnsrl.wi v24, v24, 16
+
+  # v8, v24 = m + n - sign
+  vadd.vv v8, v4, v8
+  vsub.vx v8, v8, a7
+
+  vadd.vv v24, v20, v24
+  vsub.vx v24, v24, a7
+
+  vsetvl zero, zero, t3
+
+  vnclipu.wi v0, v0, 0
+  vnclipu.wi v16, v16, 0
+
+  vse8.v v0, (t0) # dst[x] =
+  add t4, t0, a1
+  vse8.v v16, (t4) # dst[x] =
+  add t0, t0, t6
+
+  vnclipu.wi v8, v8, 1
+  vnclipu.wi v24, v24, 1
+
+.ifc \size, wide
+  srli t4, t6, 1
+  vsetvl zero, t4, t3
+.endif
+
+  vse8.v v8, (a6) # mask[x] = m + n + 1 - sign
+  srli t4, a4, 1
+  add t4, a6, t4
+  vse8.v v24, (t4) # mask[x] = m + n + 1 - sign
+  srli t4, t6, 1
+  add a6, a6, t4
+.elseif \type == 420
+  # v4, v20 = m
+  # v12, v28 = n
+  vnsrl.wi v4, v8, 0
+  vnsrl.wi v8, v8, 16
+
+  vnsrl.wi v20, v24, 0
+  vnsrl.wi v24, v24, 16
+
+  # v8 = m + n + mask[x >> 1]
+  vadd.vv v8, v4, v8
+  vadd.vv v24, v20, v24
+  vadd.vv v8, v8, v24
+  vsub.vx v8, v8, a7
+
+  vsetvl zero, zero, t3
+
+  vnclipu.wi v0, v0, 0
+  vnclipu.wi v16, v16, 0
+
+  vse8.v v0, (t0) # dst[x] =
+  add t4, t0, a1
+  vse8.v v16, (t4) # dst[x] =
+  add t0, t0, t6
+
+  vnclipu.wi v8, v8, 2
+
+  vse8.v v8, (a6) # mask[x] = (m + n + mask[x >> 1] + 2 - sign) >> 2;
+  srli t4, t6, 1
+  add a6, a6, t4
+.endif
+.endm
+
+w_mask_fn 444
+w_mask_fn 444 vl256_
+w_mask_fn 422
+w_mask_fn 422 vl256_
+w_mask_fn 420
+w_mask_fn 420 vl256_
diff --git a/media/libdav1d/src/src/riscv/64/mc16.S b/media/libdav1d/src/src/riscv/64/mc16.S
new file mode 100644
index 0000000000..680c61821b
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/mc16.S
@@ -0,0 +1,135 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+function blend_vl512_16bpc_rvv, export=1, ext=zbb
+  srai t0, a3, 3
+  ctz t0, t0
+  addi t0, t0, 0xc6
+  j L(blend_epilog)
+endfunc
+
+function blend_vl256_16bpc_rvv, export=1, ext=zbb
+  ctz t0, a3
+  addi t0, t0, 0xc4
+  j L(blend_epilog)
+endfunc
+
+function blend_16bpc_rvv, export=1, ext="v,zbb"
+  ctz t0, a3
+  addi t0, t0, 0xc5
+L(blend_epilog):
+  csrw vxrm, zero
+  andi t0, t0, 0xc7
+  ori t0, t0, 8
+  add a6, a3, a3
+  vsetvl zero, a3, t0
+1:
+  addi a4, a4, -2
+  vle8.v v24, (a5)
+  add a5, a5, a3
+  vle8.v v28, (a5)
+  add a5, a5, a3
+  vle16.v v8, (a2)
+  add a2, a2, a6
+  vle16.v v12, (a2)
+  add a2, a2, a6
+  vzext.vf2 v16, v24
+  vzext.vf2 v20, v28
+  vle16.v v0, (a0)
+  add t0, a0, a1
+  vle16.v v4, (t0)
+  vrsub.vx v16, v16, x0
+  vrsub.vx v20, v20, x0
+  vsub.vv  v8, v0, v8
+  vsub.vv  v12, v4, v12
+  vsll.vi  v16, v16, 9
+  vsll.vi  v20, v20, 9
+  vsmul.vv v8, v8, v16
+  vsmul.vv v12, v12, v20
+  vadd.vv  v0, v0, v8
+  vadd.vv  v4, v4, v12
+  vse16.v v0, (a0)
+  vse16.v v4, (t0)
+  add a0, t0, a1
+  bnez a4, 1b
+  ret
+endfunc
+
+function blend_v_vl512_16bpc_rvv, export=1, ext=zbb
+  srai t0, a3, 3
+  ctz t0, t0
+  addi t0, t0, 0xc6
+  j L(blend_v_epilog)
+endfunc
+
+function blend_v_vl256_16bpc_rvv, export=1, ext=zbb
+  srai t0, a3, 2
+  ctz t0, t0
+  addi t0, t0, 0xc6
+  j L(blend_v_epilog)
+endfunc
+
+function blend_v_16bpc_rvv, export=1, ext="v,zbb"
+  ctz t0, a3
+  addi t0, t0, 0xc5
+L(blend_v_epilog):
+  andi t0, t0, 0xc7
+  ori t0, t0, 8
+  srai t1, a3, 2
+  sub t1, a3, t1
+  vsetvl zero, t1, t0
+  csrw vxrm, zero
+  la t1, dav1d_obmc_masks
+  add t1, t1, a3
+  vle8.v v20, (t1)
+  vzext.vf2 v16, v20
+  add a3, a3, a3
+  vrsub.vx v20, v16, x0
+  vsll.vi v20, v20, 9
+1:
+  addi a4, a4, -2
+  vle16.v v8, (a2)
+  add a2, a2, a3
+  vle16.v v12, (a2)
+  add a2, a2, a3
+  vle16.v v0, (a0)
+  add t0, a0, a1
+  vle16.v v4, (t0)
+  vsub.vv v8, v0, v8
+  vsub.vv v12, v4, v12
+  vsmul.vv v8, v8, v20
+  vsmul.vv v12, v12, v20
+  vadd.vv  v0, v0, v8
+  vadd.vv  v4, v4, v12
+  vse16.v v0, (a0)
+  vse16.v v4, (t0)
+  add a0, t0, a1
+  bnez a4, 1b
+  ret
+endfunc
diff --git a/media/libdav1d/src/src/riscv/64/pal.S b/media/libdav1d/src/src/riscv/64/pal.S
new file mode 100644
index 0000000000..b8fb6e3569
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/64/pal.S
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Bogdan Gligorijevic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "src/riscv/asm.S"
+
+function pal_idx_finish_rvv, export=1, ext="v,zba,zbb"
+    csrw vxrm, zero
+    srl t0, a2, 1
+    sub a2, a2, a4
+    srl t1, a4, 1
+    mv t2, a5
+
+    csrr t6, vlenb
+    li t4, -3
+    ctz a6, t0
+    ctz t6, t6
+    li a7, 16
+    sub a6, a6, t6
+    li t6, 1<<4+1
+
+    // a6 is never > 3 for VLEN >=128
+    // that would've required stripmining with a6 set to 3
+    max a6, a6, t4
+    li t5, 2
+    andi a6, a6, 7
+    addi t4, a1, 1
+    ori a6, a6, 0xc0
+
+1:
+    sub t3, t0, t1
+    vsetvl zero, t1, a6
+    vlse8.v v0, (a1), t5
+    sh1add a1, t1, a1
+    vlse8.v v8, (t4), t5
+    sh1add t4, t1, t4
+    vmacc.vx v0, a7, v8
+    vse8.v v0, (a0)
+    add a0, a0, t1
+    ble t3, zero, 4f
+
+    lbu a4, -1(a1)
+    mul a4, a4, t6
+    vsetvl zero, t3, a6
+    vmv.v.x v0, a4
+    vse8.v v0, (a0)
+    add a0, a0, t3
+4:
+    addi t2, t2, -1
+    add a1, a1, a2
+    add t4, t4, a2
+    bnez t2, 1b
+
+    sub t1, a3, a5
+
+    sub t2, a0, t0
+    ble t1, zero, 7f
+
+    vsetvl zero, t0, a6
+    vle8.v v0, (t2)
+    add t2, a0, t0
+5:
+    addi t1, t1, -2
+    vse8.v v0, (a0)
+    vse8.v v0, (t2)
+    sh1add a0, t0, a0
+    sh1add t2, t0, t2
+
+    bnez t1, 5b
+7:
+    ret
+endfunc
diff --git a/media/libdav1d/src/src/riscv/asm.S b/media/libdav1d/src/src/riscv/asm.S
new file mode 100644
index 0000000000..c2e5a2ff59
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/asm.S
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2023, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_RISCV_ASM_S
+#define DAV1D_SRC_RISCV_ASM_S
+
+#include "config.h"
+
+#if !defined(PIC)
+#if defined(__PIC__)
+#define PIC __PIC__
+#elif defined(__pic__)
+#define PIC __pic__
+#endif
+#endif
+
+#ifndef PRIVATE_PREFIX
+#define PRIVATE_PREFIX dav1d_
+#endif
+
+#define PASTE(a,b) a ## b
+#define CONCAT(a,b) PASTE(a,b)
+
+#ifdef PREFIX
+#define EXTERN CONCAT(_,PRIVATE_PREFIX)
+#else
+#define EXTERN PRIVATE_PREFIX
+#endif
+
+.macro arch ext:req, more:vararg
+    .option arch, +\ext
+    .ifnb \more
+        arch \more
+    .endif
+.endm
+
+.macro function name, export=0, ext=
+    .macro endfunc
+#ifdef __ELF__
+        .size   \name, . - \name
+#endif
+        .option pop
+        .purgem endfunc
+    .endm
+        .text
+        .option push
+    .ifnb \ext
+        arch \ext
+    .endif
+    .if \export
+        .global EXTERN\name
+#ifdef __ELF__
+        .type   EXTERN\name, %function
+        .hidden EXTERN\name
+#elif defined(__MACH__)
+        .private_extern EXTERN\name
+#endif
+EXTERN\name:
+    .else
+#ifdef __ELF__
+        .type \name, %function
+#endif
+    .endif
+\name:
+.endm
+
+.macro  const   name, export=0, align=2
+    .macro endconst
+#ifdef __ELF__
+        .size   \name, . - \name
+#endif
+        .purgem endconst
+    .endm
+#if defined(_WIN32)
+        .section        .rdata
+#elif !defined(__MACH__)
+        .section        .rodata
+#else
+        .const_data
+#endif
+        .align          \align
+    .if \export
+        .global EXTERN\name
+#ifdef __ELF__
+        .hidden EXTERN\name
+#elif defined(__MACH__)
+        .private_extern EXTERN\name
+#endif
+EXTERN\name:
+    .endif
+\name:
+.endm
+
+.macro thread_local name, align=3, quads=1
+    .macro end_thread_local
+        .size  \name, . - \name
+        .purgem end_thread_local
+    .endm
+        .section .tbss, "waT"
+        .align \align
+        .hidden \name
+\name:
+    .rept \quads
+        .quad 0
+    .endr
+        end_thread_local
+.endm
+
+#define L(x) .L ## x
+
+#define MA      (1 << 7)
+#define TA      (1 << 6)
+#define E8      (0 << 3)
+#define E16     (1 << 3)
+#define E32     (2 << 3)
+#define E64     (3 << 3)
+#define M1      0
+#define M2      1
+#define M4      2
+#define M8      3
+#define MF2     7
+#define MF4     6
+#define MF8     5
+
+#endif /* DAV1D_SRC_RISCV_ASM_S */
diff --git a/media/libdav1d/src/src/riscv/cdef.h b/media/libdav1d/src/src/riscv/cdef.h
new file mode 100644
index 0000000000..2cf467edc1
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/cdef.h
@@ -0,0 +1,31 @@
+#include "src/cpu.h"
+#include "src/cdef.h"
+
+extern void BF(dav1d_cdef_filter_block_4x4, rvv)(pixel *dst, const ptrdiff_t dst_stride,
+                                    const pixel (*left)[2],
+                                    const pixel *const top, const pixel *const bottom,
+                                    const int pri_strength, const int sec_strength, const int dir,
+                                    const int damping, const enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+extern void BF(dav1d_cdef_filter_block_4x8, rvv)(pixel *dst, const ptrdiff_t dst_stride,
+                                    const pixel (*left)[2],
+                                    const pixel *const top, const pixel *const bottom,
+                                    const int pri_strength, const int sec_strength, const int dir,
+                                    const int damping, const enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+extern void BF(dav1d_cdef_filter_block_8x8, rvv)(pixel *dst, const ptrdiff_t dst_stride,
+                                    const pixel (*left)[2],
+                                    const pixel *const top, const pixel *const bottom,
+                                    const int pri_strength, const int sec_strength, const int dir,
+                                    const int damping, const enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+
+static ALWAYS_INLINE void cdef_dsp_init_riscv(Dav1dCdefDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+    if (!(flags & DAV1D_RISCV_CPU_FLAG_V)) return;
+
+    // c->dir = BF(dav1d_cdef_dir, rvv);
+    c->fb[0] = BF(dav1d_cdef_filter_block_8x8, rvv);
+    c->fb[1] = BF(dav1d_cdef_filter_block_4x8, rvv);
+    c->fb[2] = BF(dav1d_cdef_filter_block_4x4, rvv);
+}
diff --git a/media/libdav1d/src/src/riscv/cpu.c b/media/libdav1d/src/src/riscv/cpu.c
new file mode 100644
index 0000000000..f0ccd4fa1d
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/cpu.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2022, VideoLAN and dav1d authors
+ * Copyright © 2022, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "common/attributes.h"
+
+#include "src/cpu.h"
+#include "src/riscv/cpu.h"
+
+#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO
+#include 
+#define HWCAP_RVV (1 << ('v' - 'a'))
+#endif
+
+int dav1d_has_compliant_rvv(void);
+
+COLD unsigned dav1d_get_cpu_flags_riscv(void) {
+    unsigned flags = dav1d_get_default_cpu_flags();
+#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO
+    unsigned long hw_cap = dav1d_getauxval(AT_HWCAP);
+    flags |= (hw_cap & HWCAP_RVV) && dav1d_has_compliant_rvv() ? DAV1D_RISCV_CPU_FLAG_V : 0;
+#endif
+
+    return flags;
+}
diff --git a/media/libdav1d/src/src/riscv/cpu.h b/media/libdav1d/src/src/riscv/cpu.h
new file mode 100644
index 0000000000..f020f6a670
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/cpu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2022, VideoLAN and dav1d authors
+ * Copyright © 2022, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_RISCV_CPU_H
+#define DAV1D_SRC_RISCV_CPU_H
+
+enum CpuFlags {
+    DAV1D_RISCV_CPU_FLAG_V = 1 << 0,
+};
+
+unsigned dav1d_get_cpu_flags_riscv(void);
+
+int dav1d_get_vlenb(void);
+
+#define dav1d_get_vlen() (dav1d_get_vlenb()*8)
+
+#endif /* DAV1D_SRC_RISCV_CPU_H */
diff --git a/media/libdav1d/src/src/riscv/ipred.h b/media/libdav1d/src/src/riscv/ipred.h
new file mode 100644
index 0000000000..14076e54de
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/ipred.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Bogdan Gligorijevic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/ipred.h"
+
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl, rvv));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_128, rvv));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_top, rvv));
+decl_cfl_pred_fn(BF(dav1d_ipred_cfl_left, rvv));
+
+decl_angular_ipred_fn(BF(dav1d_ipred_v, rvv));
+decl_angular_ipred_fn(BF(dav1d_ipred_paeth, rvv));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth, rvv));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth_v, rvv));
+decl_angular_ipred_fn(BF(dav1d_ipred_smooth_h, rvv));
+
+
+decl_pal_pred_fn(BF(dav1d_pal_pred, rvv));
+
+static ALWAYS_INLINE void intra_pred_dsp_init_riscv(Dav1dIntraPredDSPContext *const c) {
+  const unsigned flags = dav1d_get_cpu_flags();
+
+  if (!(flags & DAV1D_RISCV_CPU_FLAG_V)) return;
+
+#if BITDEPTH == 8
+    c->cfl_pred[DC_PRED     ] = dav1d_ipred_cfl_8bpc_rvv;
+    c->cfl_pred[DC_128_PRED ] = dav1d_ipred_cfl_128_8bpc_rvv;
+    c->cfl_pred[TOP_DC_PRED ] = dav1d_ipred_cfl_top_8bpc_rvv;
+    c->cfl_pred[LEFT_DC_PRED] = dav1d_ipred_cfl_left_8bpc_rvv;
+
+    c->intra_pred[VERT_PRED    ] = dav1d_ipred_v_8bpc_rvv;
+    c->intra_pred[PAETH_PRED   ] = dav1d_ipred_paeth_8bpc_rvv;
+    c->intra_pred[SMOOTH_PRED  ] = dav1d_ipred_smooth_8bpc_rvv;
+    c->intra_pred[SMOOTH_V_PRED] = dav1d_ipred_smooth_v_8bpc_rvv;
+    c->intra_pred[SMOOTH_H_PRED] = dav1d_ipred_smooth_h_8bpc_rvv;
+
+    c->pal_pred = dav1d_pal_pred_8bpc_rvv;
+#elif BITDEPTH == 16
+    c->cfl_pred[DC_PRED     ] = dav1d_ipred_cfl_16bpc_rvv;
+    c->cfl_pred[DC_128_PRED ] = dav1d_ipred_cfl_128_16bpc_rvv;
+    c->cfl_pred[TOP_DC_PRED ] = dav1d_ipred_cfl_top_16bpc_rvv;
+    c->cfl_pred[LEFT_DC_PRED] = dav1d_ipred_cfl_left_16bpc_rvv;
+
+    c->intra_pred[PAETH_PRED   ] = dav1d_ipred_paeth_16bpc_rvv;
+    c->intra_pred[SMOOTH_PRED  ] = dav1d_ipred_smooth_16bpc_rvv;
+    c->intra_pred[SMOOTH_V_PRED] = dav1d_ipred_smooth_v_16bpc_rvv;
+    c->intra_pred[SMOOTH_H_PRED] = dav1d_ipred_smooth_h_16bpc_rvv;
+
+    c->pal_pred = dav1d_pal_pred_16bpc_rvv;
+#endif
+}
diff --git a/media/libdav1d/src/src/riscv/itx.h b/media/libdav1d/src/src/riscv/itx.h
new file mode 100644
index 0000000000..e11b138348
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/itx.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2023, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/itx.h"
+
+#define decl_itx_fns(ext) \
+decl_itx17_fns( 4,  4, ext); \
+decl_itx16_fns( 4,  8, ext); \
+decl_itx16_fns( 4, 16, ext); \
+decl_itx16_fns( 8,  4, ext); \
+decl_itx16_fns( 8,  8, ext); \
+decl_itx16_fns( 8, 16, ext); \
+decl_itx16_fns(16,  4, ext); \
+decl_itx16_fns(16,  8, ext); \
+decl_itx16_fns(16, 16, ext)
+
+decl_itx_fns(rvv);
+
+static ALWAYS_INLINE void itx_dsp_init_riscv(Dav1dInvTxfmDSPContext *const c, int const bpc) {
+  const unsigned flags = dav1d_get_cpu_flags();
+
+  if (!(flags & DAV1D_RISCV_CPU_FLAG_V)) return;
+
+#if BITDEPTH == 8
+  assign_itx17_fn( ,  4,  4, rvv);
+  assign_itx16_fn(R,  4,  8, rvv);
+  assign_itx16_fn(R,  4, 16, rvv);
+  assign_itx16_fn(R,  8,  4, rvv);
+  assign_itx16_fn( ,  8,  8, rvv);
+  assign_itx16_fn(R,  8, 16, rvv);
+  assign_itx16_fn(R, 16,  4, rvv);
+  assign_itx16_fn(R, 16,  8, rvv);
+  assign_itx12_fn( , 16, 16, rvv);
+#endif
+}
diff --git a/media/libdav1d/src/src/riscv/mc.h b/media/libdav1d/src/src/riscv/mc.h
new file mode 100644
index 0000000000..b66524c3bd
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/mc.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright © 2024, VideoLAN and dav1d authors
+ * Copyright © 2024, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/mc.h"
+
+decl_blend_fn(BF(dav1d_blend, rvv));
+decl_blend_dir_fn(BF(dav1d_blend_h, rvv));
+decl_blend_dir_fn(BF(dav1d_blend_v, rvv));
+
+decl_blend_fn(BF(dav1d_blend_vl256, rvv));
+decl_blend_dir_fn(BF(dav1d_blend_h_vl256, rvv));
+decl_blend_dir_fn(BF(dav1d_blend_v_vl256, rvv));
+
+decl_blend_fn(BF(dav1d_blend_vl512, rvv));
+decl_blend_dir_fn(BF(dav1d_blend_h_vl512, rvv));
+decl_blend_dir_fn(BF(dav1d_blend_v_vl512, rvv));
+
+decl_avg_fn(BF(dav1d_avg, rvv));
+decl_w_avg_fn(BF(dav1d_w_avg, rvv));
+decl_mask_fn(BF(dav1d_mask, rvv));
+
+decl_w_mask_fn(BF(dav1d_w_mask_444, rvv));
+decl_w_mask_fn(BF(dav1d_w_mask_422, rvv));
+decl_w_mask_fn(BF(dav1d_w_mask_420, rvv));
+
+decl_w_mask_fn(BF(dav1d_w_mask_444_vl256, rvv));
+decl_w_mask_fn(BF(dav1d_w_mask_422_vl256, rvv));
+decl_w_mask_fn(BF(dav1d_w_mask_420_vl256, rvv));
+
+decl_warp8x8_fn(BF(dav1d_warp_8x8, rvv));
+decl_warp8x8t_fn(BF(dav1d_warp_8x8t, rvv));
+decl_emu_edge_fn(BF(dav1d_emu_edge, rvv));
+
+static ALWAYS_INLINE void mc_dsp_init_riscv(Dav1dMCDSPContext *const c) {
+  const unsigned flags = dav1d_get_cpu_flags();
+
+  if (!(flags & DAV1D_RISCV_CPU_FLAG_V)) return;
+
+  c->blend = BF(dav1d_blend, rvv);
+  c->blend_v = BF(dav1d_blend_v, rvv);
+
+  if (dav1d_get_vlen() >= 256) {
+    c->blend = BF(dav1d_blend_vl256, rvv);
+    c->blend_v = BF(dav1d_blend_v_vl256, rvv);
+  }
+
+  if (dav1d_get_vlen() >= 512) {
+    c->blend = BF(dav1d_blend_vl512, rvv);
+    c->blend_v = BF(dav1d_blend_v_vl512, rvv);
+  }
+
+#if BITDEPTH == 8
+  c->blend_h = BF(dav1d_blend_h, rvv);
+  c->emu_edge = BF(dav1d_emu_edge, rvv);
+
+  c->w_mask[0] = BF(dav1d_w_mask_444, rvv);
+  c->w_mask[1] = BF(dav1d_w_mask_422, rvv);
+  c->w_mask[2] = BF(dav1d_w_mask_420, rvv);
+
+  c->avg     = BF(dav1d_avg, rvv);
+  c->w_avg   = BF(dav1d_w_avg, rvv);
+  c->mask    = BF(dav1d_mask, rvv);
+
+  c->warp8x8 = BF(dav1d_warp_8x8, rvv);
+  c->warp8x8t = BF(dav1d_warp_8x8t, rvv);
+
+  if (dav1d_get_vlen() >= 256) {
+    c->blend_h = BF(dav1d_blend_h_vl256, rvv);
+
+    c->w_mask[0] = BF(dav1d_w_mask_444_vl256, rvv);
+    c->w_mask[1] = BF(dav1d_w_mask_422_vl256, rvv);
+    c->w_mask[2] = BF(dav1d_w_mask_420_vl256, rvv);
+  }
+  if (dav1d_get_vlen() >= 512) {
+    c->blend_h = BF(dav1d_blend_h_vl512, rvv);
+  }
+#endif
+}
diff --git a/media/libdav1d/src/src/riscv/pal.h b/media/libdav1d/src/src/riscv/pal.h
new file mode 100644
index 0000000000..f272d705da
--- /dev/null
+++ b/media/libdav1d/src/src/riscv/pal.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2024, Bogdan Gligorijevic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/pal.h"
+
+decl_pal_idx_finish_fn(dav1d_pal_idx_finish_rvv);
+
+static ALWAYS_INLINE void pal_dsp_init_riscv(Dav1dPalDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+  if (!(flags & DAV1D_RISCV_CPU_FLAG_V)) return;
+
+    c->pal_idx_finish = dav1d_pal_idx_finish_rvv;
+}
diff --git a/media/libdav1d/src/src/scan.c b/media/libdav1d/src/src/scan.c
new file mode 100644
index 0000000000..6f9dc03691
--- /dev/null
+++ b/media/libdav1d/src/src/scan.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "src/scan.h"
+#include "src/thread.h"
+
+static const uint16_t ALIGN(scan_4x4[], 32) = {
+     0,  4,  1,  2,
+     5,  8, 12,  9,
+     6,  3,  7, 10,
+    13, 14, 11, 15,
+};
+
+static const uint16_t ALIGN(scan_4x8[], 32) = {
+     0,  8,  1, 16,
+     9,  2, 24, 17,
+    10,  3, 25, 18,
+    11,  4, 26, 19,
+    12,  5, 27, 20,
+    13,  6, 28, 21,
+    14,  7, 29, 22,
+    15, 30, 23, 31,
+};
+
+static const uint16_t ALIGN(scan_4x16[], 32) = {
+     0, 16,  1, 32,
+    17,  2, 48, 33,
+    18,  3, 49, 34,
+    19,  4, 50, 35,
+    20,  5, 51, 36,
+    21,  6, 52, 37,
+    22,  7, 53, 38,
+    23,  8, 54, 39,
+    24,  9, 55, 40,
+    25, 10, 56, 41,
+    26, 11, 57, 42,
+    27, 12, 58, 43,
+    28, 13, 59, 44,
+    29, 14, 60, 45,
+    30, 15, 61, 46,
+    31, 62, 47, 63,
+};
+
+static const uint16_t ALIGN(scan_8x4[], 32) = {
+     0,  1,  4,  2,  5,  8,  3,  6,
+     9, 12,  7, 10, 13, 16, 11, 14,
+    17, 20, 15, 18, 21, 24, 19, 22,
+    25, 28, 23, 26, 29, 27, 30, 31,
+};
+
+static const uint16_t ALIGN(scan_8x8[], 32) = {
+     0,  8,  1,  2,  9, 16, 24, 17,
+    10,  3,  4, 11, 18, 25, 32, 40,
+    33, 26, 19, 12,  5,  6, 13, 20,
+    27, 34, 41, 48, 56, 49, 42, 35,
+    28, 21, 14,  7, 15, 22, 29, 36,
+    43, 50, 57, 58, 51, 44, 37, 30,
+    23, 31, 38, 45, 52, 59, 60, 53,
+    46, 39, 47, 54, 61, 62, 55, 63,
+};
+
+static const uint16_t ALIGN(scan_8x16[], 32) = {
+      0,  16,   1,  32,  17,   2,  48,  33,
+     18,   3,  64,  49,  34,  19,   4,  80,
+     65,  50,  35,  20,   5,  96,  81,  66,
+     51,  36,  21,   6, 112,  97,  82,  67,
+     52,  37,  22,   7, 113,  98,  83,  68,
+     53,  38,  23,   8, 114,  99,  84,  69,
+     54,  39,  24,   9, 115, 100,  85,  70,
+     55,  40,  25,  10, 116, 101,  86,  71,
+     56,  41,  26,  11, 117, 102,  87,  72,
+     57,  42,  27,  12, 118, 103,  88,  73,
+     58,  43,  28,  13, 119, 104,  89,  74,
+     59,  44,  29,  14, 120, 105,  90,  75,
+     60,  45,  30,  15, 121, 106,  91,  76,
+     61,  46,  31, 122, 107,  92,  77,  62,
+     47, 123, 108,  93,  78,  63, 124, 109,
+     94,  79, 125, 110,  95, 126, 111, 127,
+};
+
+static const uint16_t ALIGN(scan_8x32[], 32) = {
+      0,  32,   1,  64,  33,   2,  96,  65,
+     34,   3, 128,  97,  66,  35,   4, 160,
+    129,  98,  67,  36,   5, 192, 161, 130,
+     99,  68,  37,   6, 224, 193, 162, 131,
+    100,  69,  38,   7, 225, 194, 163, 132,
+    101,  70,  39,   8, 226, 195, 164, 133,
+    102,  71,  40,   9, 227, 196, 165, 134,
+    103,  72,  41,  10, 228, 197, 166, 135,
+    104,  73,  42,  11, 229, 198, 167, 136,
+    105,  74,  43,  12, 230, 199, 168, 137,
+    106,  75,  44,  13, 231, 200, 169, 138,
+    107,  76,  45,  14, 232, 201, 170, 139,
+    108,  77,  46,  15, 233, 202, 171, 140,
+    109,  78,  47,  16, 234, 203, 172, 141,
+    110,  79,  48,  17, 235, 204, 173, 142,
+    111,  80,  49,  18, 236, 205, 174, 143,
+    112,  81,  50,  19, 237, 206, 175, 144,
+    113,  82,  51,  20, 238, 207, 176, 145,
+    114,  83,  52,  21, 239, 208, 177, 146,
+    115,  84,  53,  22, 240, 209, 178, 147,
+    116,  85,  54,  23, 241, 210, 179, 148,
+    117,  86,  55,  24, 242, 211, 180, 149,
+    118,  87,  56,  25, 243, 212, 181, 150,
+    119,  88,  57,  26, 244, 213, 182, 151,
+    120,  89,  58,  27, 245, 214, 183, 152,
+    121,  90,  59,  28, 246, 215, 184, 153,
+    122,  91,  60,  29, 247, 216, 185, 154,
+    123,  92,  61,  30, 248, 217, 186, 155,
+    124,  93,  62,  31, 249, 218, 187, 156,
+    125,  94,  63, 250, 219, 188, 157, 126,
+     95, 251, 220, 189, 158, 127, 252, 221,
+    190, 159, 253, 222, 191, 254, 223, 255,
+};
+
+static const uint16_t ALIGN(scan_16x4[], 32) = {
+     0,  1,  4,  2,  5,  8,  3,  6,  9, 12,  7, 10, 13, 16, 11, 14,
+    17, 20, 15, 18, 21, 24, 19, 22, 25, 28, 23, 26, 29, 32, 27, 30,
+    33, 36, 31, 34, 37, 40, 35, 38, 41, 44, 39, 42, 45, 48, 43, 46,
+    49, 52, 47, 50, 53, 56, 51, 54, 57, 60, 55, 58, 61, 59, 62, 63,
+};
+
+static const uint16_t ALIGN(scan_16x8[], 32) = {
+      0,   1,   8,   2,   9,  16,   3,  10,  17,  24,   4,  11,  18,  25,  32,   5,
+     12,  19,  26,  33,  40,   6,  13,  20,  27,  34,  41,  48,   7,  14,  21,  28,
+     35,  42,  49,  56,  15,  22,  29,  36,  43,  50,  57,  64,  23,  30,  37,  44,
+     51,  58,  65,  72,  31,  38,  45,  52,  59,  66,  73,  80,  39,  46,  53,  60,
+     67,  74,  81,  88,  47,  54,  61,  68,  75,  82,  89,  96,  55,  62,  69,  76,
+     83,  90,  97, 104,  63,  70,  77,  84,  91,  98, 105, 112,  71,  78,  85,  92,
+     99, 106, 113, 120,  79,  86,  93, 100, 107, 114, 121,  87,  94, 101, 108, 115,
+    122,  95, 102, 109, 116, 123, 103, 110, 117, 124, 111, 118, 125, 119, 126, 127,
+};
+
+static const uint16_t ALIGN(scan_16x16[], 32) = {
+      0,  16,   1,   2,  17,  32,  48,  33,  18,   3,   4,  19,  34,  49,  64,  80,
+     65,  50,  35,  20,   5,   6,  21,  36,  51,  66,  81,  96, 112,  97,  82,  67,
+     52,  37,  22,   7,   8,  23,  38,  53,  68,  83,  98, 113, 128, 144, 129, 114,
+     99,  84,  69,  54,  39,  24,   9,  10,  25,  40,  55,  70,  85, 100, 115, 130,
+    145, 160, 176, 161, 146, 131, 116, 101,  86,  71,  56,  41,  26,  11,  12,  27,
+     42,  57,  72,  87, 102, 117, 132, 147, 162, 177, 192, 208, 193, 178, 163, 148,
+    133, 118, 103,  88,  73,  58,  43,  28,  13,  14,  29,  44,  59,  74,  89, 104,
+    119, 134, 149, 164, 179, 194, 209, 224, 240, 225, 210, 195, 180, 165, 150, 135,
+    120, 105,  90,  75,  60,  45,  30,  15,  31,  46,  61,  76,  91, 106, 121, 136,
+    151, 166, 181, 196, 211, 226, 241, 242, 227, 212, 197, 182, 167, 152, 137, 122,
+    107,  92,  77,  62,  47,  63,  78,  93, 108, 123, 138, 153, 168, 183, 198, 213,
+    228, 243, 244, 229, 214, 199, 184, 169, 154, 139, 124, 109,  94,  79,  95, 110,
+    125, 140, 155, 170, 185, 200, 215, 230, 245, 246, 231, 216, 201, 186, 171, 156,
+    141, 126, 111, 127, 142, 157, 172, 187, 202, 217, 232, 247, 248, 233, 218, 203,
+    188, 173, 158, 143, 159, 174, 189, 204, 219, 234, 249, 250, 235, 220, 205, 190,
+    175, 191, 206, 221, 236, 251, 252, 237, 222, 207, 223, 238, 253, 254, 239, 255,
+};
+
+static const uint16_t ALIGN(scan_16x32[], 32) = {
+      0,  32,   1,  64,  33,   2,  96,  65,  34,   3, 128,  97,  66,  35,   4, 160,
+    129,  98,  67,  36,   5, 192, 161, 130,  99,  68,  37,   6, 224, 193, 162, 131,
+    100,  69,  38,   7, 256, 225, 194, 163, 132, 101,  70,  39,   8, 288, 257, 226,
+    195, 164, 133, 102,  71,  40,   9, 320, 289, 258, 227, 196, 165, 134, 103,  72,
+     41,  10, 352, 321, 290, 259, 228, 197, 166, 135, 104,  73,  42,  11, 384, 353,
+    322, 291, 260, 229, 198, 167, 136, 105,  74,  43,  12, 416, 385, 354, 323, 292,
+    261, 230, 199, 168, 137, 106,  75,  44,  13, 448, 417, 386, 355, 324, 293, 262,
+    231, 200, 169, 138, 107,  76,  45,  14, 480, 449, 418, 387, 356, 325, 294, 263,
+    232, 201, 170, 139, 108,  77,  46,  15, 481, 450, 419, 388, 357, 326, 295, 264,
+    233, 202, 171, 140, 109,  78,  47,  16, 482, 451, 420, 389, 358, 327, 296, 265,
+    234, 203, 172, 141, 110,  79,  48,  17, 483, 452, 421, 390, 359, 328, 297, 266,
+    235, 204, 173, 142, 111,  80,  49,  18, 484, 453, 422, 391, 360, 329, 298, 267,
+    236, 205, 174, 143, 112,  81,  50,  19, 485, 454, 423, 392, 361, 330, 299, 268,
+    237, 206, 175, 144, 113,  82,  51,  20, 486, 455, 424, 393, 362, 331, 300, 269,
+    238, 207, 176, 145, 114,  83,  52,  21, 487, 456, 425, 394, 363, 332, 301, 270,
+    239, 208, 177, 146, 115,  84,  53,  22, 488, 457, 426, 395, 364, 333, 302, 271,
+    240, 209, 178, 147, 116,  85,  54,  23, 489, 458, 427, 396, 365, 334, 303, 272,
+    241, 210, 179, 148, 117,  86,  55,  24, 490, 459, 428, 397, 366, 335, 304, 273,
+    242, 211, 180, 149, 118,  87,  56,  25, 491, 460, 429, 398, 367, 336, 305, 274,
+    243, 212, 181, 150, 119,  88,  57,  26, 492, 461, 430, 399, 368, 337, 306, 275,
+    244, 213, 182, 151, 120,  89,  58,  27, 493, 462, 431, 400, 369, 338, 307, 276,
+    245, 214, 183, 152, 121,  90,  59,  28, 494, 463, 432, 401, 370, 339, 308, 277,
+    246, 215, 184, 153, 122,  91,  60,  29, 495, 464, 433, 402, 371, 340, 309, 278,
+    247, 216, 185, 154, 123,  92,  61,  30, 496, 465, 434, 403, 372, 341, 310, 279,
+    248, 217, 186, 155, 124,  93,  62,  31, 497, 466, 435, 404, 373, 342, 311, 280,
+    249, 218, 187, 156, 125,  94,  63, 498, 467, 436, 405, 374, 343, 312, 281, 250,
+    219, 188, 157, 126,  95, 499, 468, 437, 406, 375, 344, 313, 282, 251, 220, 189,
+    158, 127, 500, 469, 438, 407, 376, 345, 314, 283, 252, 221, 190, 159, 501, 470,
+    439, 408, 377, 346, 315, 284, 253, 222, 191, 502, 471, 440, 409, 378, 347, 316,
+    285, 254, 223, 503, 472, 441, 410, 379, 348, 317, 286, 255, 504, 473, 442, 411,
+    380, 349, 318, 287, 505, 474, 443, 412, 381, 350, 319, 506, 475, 444, 413, 382,
+    351, 507, 476, 445, 414, 383, 508, 477, 446, 415, 509, 478, 447, 510, 479, 511,
+};
+
+static const uint16_t ALIGN(scan_32x8[], 32) = {
+      0,   1,   8,   2,   9,  16,   3,  10,  17,  24,   4,  11,  18,  25,  32,   5,  12,  19,  26,  33,  40,   6,  13,  20,  27,  34,  41,  48,   7,  14,  21,  28,
+     35,  42,  49,  56,  15,  22,  29,  36,  43,  50,  57,  64,  23,  30,  37,  44,  51,  58,  65,  72,  31,  38,  45,  52,  59,  66,  73,  80,  39,  46,  53,  60,
+     67,  74,  81,  88,  47,  54,  61,  68,  75,  82,  89,  96,  55,  62,  69,  76,  83,  90,  97, 104,  63,  70,  77,  84,  91,  98, 105, 112,  71,  78,  85,  92,
+     99, 106, 113, 120,  79,  86,  93, 100, 107, 114, 121, 128,  87,  94, 101, 108, 115, 122, 129, 136,  95, 102, 109, 116, 123, 130, 137, 144, 103, 110, 117, 124,
+    131, 138, 145, 152, 111, 118, 125, 132, 139, 146, 153, 160, 119, 126, 133, 140, 147, 154, 161, 168, 127, 134, 141, 148, 155, 162, 169, 176, 135, 142, 149, 156,
+    163, 170, 177, 184, 143, 150, 157, 164, 171, 178, 185, 192, 151, 158, 165, 172, 179, 186, 193, 200, 159, 166, 173, 180, 187, 194, 201, 208, 167, 174, 181, 188,
+    195, 202, 209, 216, 175, 182, 189, 196, 203, 210, 217, 224, 183, 190, 197, 204, 211, 218, 225, 232, 191, 198, 205, 212, 219, 226, 233, 240, 199, 206, 213, 220,
+    227, 234, 241, 248, 207, 214, 221, 228, 235, 242, 249, 215, 222, 229, 236, 243, 250, 223, 230, 237, 244, 251, 231, 238, 245, 252, 239, 246, 253, 247, 254, 255,
+};
+
+static const uint16_t ALIGN(scan_32x16[], 32) = {
+      0,   1,  16,   2,  17,  32,   3,  18,  33,  48,   4,  19,  34,  49,  64,   5,  20,  35,  50,  65,  80,   6,  21,  36,  51,  66,  81,  96,   7,  22,  37,  52,
+     67,  82,  97, 112,   8,  23,  38,  53,  68,  83,  98, 113, 128,   9,  24,  39,  54,  69,  84,  99, 114, 129, 144,  10,  25,  40,  55,  70,  85, 100, 115, 130,
+    145, 160,  11,  26,  41,  56,  71,  86, 101, 116, 131, 146, 161, 176,  12,  27,  42,  57,  72,  87, 102, 117, 132, 147, 162, 177, 192,  13,  28,  43,  58,  73,
+     88, 103, 118, 133, 148, 163, 178, 193, 208,  14,  29,  44,  59,  74,  89, 104, 119, 134, 149, 164, 179, 194, 209, 224,  15,  30,  45,  60,  75,  90, 105, 120,
+    135, 150, 165, 180, 195, 210, 225, 240,  31,  46,  61,  76,  91, 106, 121, 136, 151, 166, 181, 196, 211, 226, 241, 256,  47,  62,  77,  92, 107, 122, 137, 152,
+    167, 182, 197, 212, 227, 242, 257, 272,  63,  78,  93, 108, 123, 138, 153, 168, 183, 198, 213, 228, 243, 258, 273, 288,  79,  94, 109, 124, 139, 154, 169, 184,
+    199, 214, 229, 244, 259, 274, 289, 304,  95, 110, 125, 140, 155, 170, 185, 200, 215, 230, 245, 260, 275, 290, 305, 320, 111, 126, 141, 156, 171, 186, 201, 216,
+    231, 246, 261, 276, 291, 306, 321, 336, 127, 142, 157, 172, 187, 202, 217, 232, 247, 262, 277, 292, 307, 322, 337, 352, 143, 158, 173, 188, 203, 218, 233, 248,
+    263, 278, 293, 308, 323, 338, 353, 368, 159, 174, 189, 204, 219, 234, 249, 264, 279, 294, 309, 324, 339, 354, 369, 384, 175, 190, 205, 220, 235, 250, 265, 280,
+    295, 310, 325, 340, 355, 370, 385, 400, 191, 206, 221, 236, 251, 266, 281, 296, 311, 326, 341, 356, 371, 386, 401, 416, 207, 222, 237, 252, 267, 282, 297, 312,
+    327, 342, 357, 372, 387, 402, 417, 432, 223, 238, 253, 268, 283, 298, 313, 328, 343, 358, 373, 388, 403, 418, 433, 448, 239, 254, 269, 284, 299, 314, 329, 344,
+    359, 374, 389, 404, 419, 434, 449, 464, 255, 270, 285, 300, 315, 330, 345, 360, 375, 390, 405, 420, 435, 450, 465, 480, 271, 286, 301, 316, 331, 346, 361, 376,
+    391, 406, 421, 436, 451, 466, 481, 496, 287, 302, 317, 332, 347, 362, 377, 392, 407, 422, 437, 452, 467, 482, 497, 303, 318, 333, 348, 363, 378, 393, 408, 423,
+    438, 453, 468, 483, 498, 319, 334, 349, 364, 379, 394, 409, 424, 439, 454, 469, 484, 499, 335, 350, 365, 380, 395, 410, 425, 440, 455, 470, 485, 500, 351, 366,
+    381, 396, 411, 426, 441, 456, 471, 486, 501, 367, 382, 397, 412, 427, 442, 457, 472, 487, 502, 383, 398, 413, 428, 443, 458, 473, 488, 503, 399, 414, 429, 444,
+    459, 474, 489, 504, 415, 430, 445, 460, 475, 490, 505, 431, 446, 461, 476, 491, 506, 447, 462, 477, 492, 507, 463, 478, 493, 508, 479, 494, 509, 495, 510, 511,
+};
+
+static const uint16_t ALIGN(scan_32x32[], 32) = {
+       0,   32,    1,    2,   33,   64,   96,   65,   34,    3,    4,   35,   66,   97,  128,  160,  129,   98,   67,   36,    5,    6,   37,   68,   99,  130,  161,  192,  224,  193,  162,  131,
+     100,   69,   38,    7,    8,   39,   70,  101,  132,  163,  194,  225,  256,  288,  257,  226,  195,  164,  133,  102,   71,   40,    9,   10,   41,   72,  103,  134,  165,  196,  227,  258,
+     289,  320,  352,  321,  290,  259,  228,  197,  166,  135,  104,   73,   42,   11,   12,   43,   74,  105,  136,  167,  198,  229,  260,  291,  322,  353,  384,  416,  385,  354,  323,  292,
+     261,  230,  199,  168,  137,  106,   75,   44,   13,   14,   45,   76,  107,  138,  169,  200,  231,  262,  293,  324,  355,  386,  417,  448,  480,  449,  418,  387,  356,  325,  294,  263,
+     232,  201,  170,  139,  108,   77,   46,   15,   16,   47,   78,  109,  140,  171,  202,  233,  264,  295,  326,  357,  388,  419,  450,  481,  512,  544,  513,  482,  451,  420,  389,  358,
+     327,  296,  265,  234,  203,  172,  141,  110,   79,   48,   17,   18,   49,   80,  111,  142,  173,  204,  235,  266,  297,  328,  359,  390,  421,  452,  483,  514,  545,  576,  608,  577,
+     546,  515,  484,  453,  422,  391,  360,  329,  298,  267,  236,  205,  174,  143,  112,   81,   50,   19,   20,   51,   82,  113,  144,  175,  206,  237,  268,  299,  330,  361,  392,  423,
+     454,  485,  516,  547,  578,  609,  640,  672,  641,  610,  579,  548,  517,  486,  455,  424,  393,  362,  331,  300,  269,  238,  207,  176,  145,  114,   83,   52,   21,   22,   53,   84,
+     115,  146,  177,  208,  239,  270,  301,  332,  363,  394,  425,  456,  487,  518,  549,  580,  611,  642,  673,  704,  736,  705,  674,  643,  612,  581,  550,  519,  488,  457,  426,  395,
+     364,  333,  302,  271,  240,  209,  178,  147,  116,   85,   54,   23,   24,   55,   86,  117,  148,  179,  210,  241,  272,  303,  334,  365,  396,  427,  458,  489,  520,  551,  582,  613,
+     644,  675,  706,  737,  768,  800,  769,  738,  707,  676,  645,  614,  583,  552,  521,  490,  459,  428,  397,  366,  335,  304,  273,  242,  211,  180,  149,  118,   87,   56,   25,   26,
+      57,   88,  119,  150,  181,  212,  243,  274,  305,  336,  367,  398,  429,  460,  491,  522,  553,  584,  615,  646,  677,  708,  739,  770,  801,  832,  864,  833,  802,  771,  740,  709,
+     678,  647,  616,  585,  554,  523,  492,  461,  430,  399,  368,  337,  306,  275,  244,  213,  182,  151,  120,   89,   58,   27,   28,   59,   90,  121,  152,  183,  214,  245,  276,  307,
+     338,  369,  400,  431,  462,  493,  524,  555,  586,  617,  648,  679,  710,  741,  772,  803,  834,  865,  896,  928,  897,  866,  835,  804,  773,  742,  711,  680,  649,  618,  587,  556,
+     525,  494,  463,  432,  401,  370,  339,  308,  277,  246,  215,  184,  153,  122,   91,   60,   29,   30,   61,   92,  123,  154,  185,  216,  247,  278,  309,  340,  371,  402,  433,  464,
+     495,  526,  557,  588,  619,  650,  681,  712,  743,  774,  805,  836,  867,  898,  929,  960,  992,  961,  930,  899,  868,  837,  806,  775,  744,  713,  682,  651,  620,  589,  558,  527,
+     496,  465,  434,  403,  372,  341,  310,  279,  248,  217,  186,  155,  124,   93,   62,   31,   63,   94,  125,  156,  187,  218,  249,  280,  311,  342,  373,  404,  435,  466,  497,  528,
+     559,  590,  621,  652,  683,  714,  745,  776,  807,  838,  869,  900,  931,  962,  993,  994,  963,  932,  901,  870,  839,  808,  777,  746,  715,  684,  653,  622,  591,  560,  529,  498,
+     467,  436,  405,  374,  343,  312,  281,  250,  219,  188,  157,  126,   95,  127,  158,  189,  220,  251,  282,  313,  344,  375,  406,  437,  468,  499,  530,  561,  592,  623,  654,  685,
+     716,  747,  778,  809,  840,  871,  902,  933,  964,  995,  996,  965,  934,  903,  872,  841,  810,  779,  748,  717,  686,  655,  624,  593,  562,  531,  500,  469,  438,  407,  376,  345,
+     314,  283,  252,  221,  190,  159,  191,  222,  253,  284,  315,  346,  377,  408,  439,  470,  501,  532,  563,  594,  625,  656,  687,  718,  749,  780,  811,  842,  873,  904,  935,  966,
+     997,  998,  967,  936,  905,  874,  843,  812,  781,  750,  719,  688,  657,  626,  595,  564,  533,  502,  471,  440,  409,  378,  347,  316,  285,  254,  223,  255,  286,  317,  348,  379,
+     410,  441,  472,  503,  534,  565,  596,  627,  658,  689,  720,  751,  782,  813,  844,  875,  906,  937,  968,  999, 1000,  969,  938,  907,  876,  845,  814,  783,  752,  721,  690,  659,
+     628,  597,  566,  535,  504,  473,  442,  411,  380,  349,  318,  287,  319,  350,  381,  412,  443,  474,  505,  536,  567,  598,  629,  660,  691,  722,  753,  784,  815,  846,  877,  908,
+     939,  970, 1001, 1002,  971,  940,  909,  878,  847,  816,  785,  754,  723,  692,  661,  630,  599,  568,  537,  506,  475,  444,  413,  382,  351,  383,  414,  445,  476,  507,  538,  569,
+     600,  631,  662,  693,  724,  755,  786,  817,  848,  879,  910,  941,  972, 1003, 1004,  973,  942,  911,  880,  849,  818,  787,  756,  725,  694,  663,  632,  601,  570,  539,  508,  477,
+     446,  415,  447,  478,  509,  540,  571,  602,  633,  664,  695,  726,  757,  788,  819,  850,  881,  912,  943,  974, 1005, 1006,  975,  944,  913,  882,  851,  820,  789,  758,  727,  696,
+     665,  634,  603,  572,  541,  510,  479,  511,  542,  573,  604,  635,  666,  697,  728,  759,  790,  821,  852,  883,  914,  945,  976, 1007, 1008,  977,  946,  915,  884,  853,  822,  791,
+     760,  729,  698,  667,  636,  605,  574,  543,  575,  606,  637,  668,  699,  730,  761,  792,  823,  854,  885,  916,  947,  978, 1009, 1010,  979,  948,  917,  886,  855,  824,  793,  762,
+     731,  700,  669,  638,  607,  639,  670,  701,  732,  763,  794,  825,  856,  887,  918,  949,  980, 1011, 1012,  981,  950,  919,  888,  857,  826,  795,  764,  733,  702,  671,  703,  734,
+     765,  796,  827,  858,  889,  920,  951,  982, 1013, 1014,  983,  952,  921,  890,  859,  828,  797,  766,  735,  767,  798,  829,  860,  891,  922,  953,  984, 1015, 1016,  985,  954,  923,
+     892,  861,  830,  799,  831,  862,  893,  924,  955,  986, 1017, 1018,  987,  956,  925,  894,  863,  895,  926,  957,  988, 1019, 1020,  989,  958,  927,  959,  990, 1021, 1022,  991, 1023,
+};
+
+const uint16_t *const dav1d_scans[N_RECT_TX_SIZES] = {
+    [ TX_4X4  ] = scan_4x4,
+    [ TX_8X8  ] = scan_8x8,
+    [ TX_16X16] = scan_16x16,
+    [ TX_32X32] = scan_32x32,
+    [ TX_64X64] = scan_32x32,
+    [RTX_4X8  ] = scan_4x8,
+    [RTX_8X4  ] = scan_8x4,
+    [RTX_8X16 ] = scan_8x16,
+    [RTX_16X8 ] = scan_16x8,
+    [RTX_16X32] = scan_16x32,
+    [RTX_32X16] = scan_32x16,
+    [RTX_32X64] = scan_32x32,
+    [RTX_64X32] = scan_32x32,
+    [RTX_4X16 ] = scan_4x16,
+    [RTX_16X4 ] = scan_16x4,
+    [RTX_8X32 ] = scan_8x32,
+    [RTX_32X8 ] = scan_32x8,
+    [RTX_16X64] = scan_16x32,
+    [RTX_64X16] = scan_32x16,
+};
+
+static uint8_t last_nonzero_col_from_eob_4x4[16];
+static uint8_t last_nonzero_col_from_eob_8x8[64];
+static uint8_t last_nonzero_col_from_eob_16x16[256];
+static uint8_t last_nonzero_col_from_eob_32x32[1024];
+static uint8_t last_nonzero_col_from_eob_4x8[32];
+static uint8_t last_nonzero_col_from_eob_8x4[32];
+static uint8_t last_nonzero_col_from_eob_8x16[128];
+static uint8_t last_nonzero_col_from_eob_16x8[128];
+static uint8_t last_nonzero_col_from_eob_16x32[512];
+static uint8_t last_nonzero_col_from_eob_32x16[512];
+static uint8_t last_nonzero_col_from_eob_4x16[64];
+static uint8_t last_nonzero_col_from_eob_16x4[64];
+static uint8_t last_nonzero_col_from_eob_8x32[256];
+static uint8_t last_nonzero_col_from_eob_32x8[256];
+
+static COLD void init_tbl(uint8_t *const last_nonzero_col_from_eob,
+                          const uint16_t *const scan, const int w, const int h)
+{
+    int max_col = 0;
+    for (int y = 0, n = 0; y < h; y++) {
+        for (int x = 0; x < w; x++, n++) {
+            const int rc = scan[n];
+            const int rcx = rc & (h - 1);
+            max_col = imax(max_col, rcx);
+            last_nonzero_col_from_eob[n] = max_col;
+        }
+    }
+}
+
+static COLD void init_internal(void) {
+    init_tbl(last_nonzero_col_from_eob_4x4,   scan_4x4,    4,  4);
+    init_tbl(last_nonzero_col_from_eob_8x8,   scan_8x8,    8,  8);
+    init_tbl(last_nonzero_col_from_eob_16x16, scan_16x16, 16, 16);
+    init_tbl(last_nonzero_col_from_eob_32x32, scan_32x32, 32, 32);
+    init_tbl(last_nonzero_col_from_eob_4x8,   scan_4x8,    4,  8);
+    init_tbl(last_nonzero_col_from_eob_8x4,   scan_8x4,    8,  4);
+    init_tbl(last_nonzero_col_from_eob_8x16,  scan_8x16,   8, 16);
+    init_tbl(last_nonzero_col_from_eob_16x8,  scan_16x8,  16,  8);
+    init_tbl(last_nonzero_col_from_eob_16x32, scan_16x32, 16, 32);
+    init_tbl(last_nonzero_col_from_eob_32x16, scan_32x16, 32, 16);
+    init_tbl(last_nonzero_col_from_eob_4x16,  scan_4x16,   4, 16);
+    init_tbl(last_nonzero_col_from_eob_16x4,  scan_16x4,  16,  4);
+    init_tbl(last_nonzero_col_from_eob_8x32,  scan_8x32,   8, 32);
+    init_tbl(last_nonzero_col_from_eob_32x8,  scan_32x8,  32,  8);
+}
+
+COLD void dav1d_init_last_nonzero_col_from_eob_tables(void) {
+    static pthread_once_t initted = PTHREAD_ONCE_INIT;
+    pthread_once(&initted, init_internal);
+}
+
+const uint8_t *const dav1d_last_nonzero_col_from_eob[N_RECT_TX_SIZES] = {
+    [ TX_4X4  ] = last_nonzero_col_from_eob_4x4,
+    [ TX_8X8  ] = last_nonzero_col_from_eob_8x8,
+    [ TX_16X16] = last_nonzero_col_from_eob_16x16,
+    [ TX_32X32] = last_nonzero_col_from_eob_32x32,
+    [ TX_64X64] = last_nonzero_col_from_eob_32x32,
+    [RTX_4X8  ] = last_nonzero_col_from_eob_4x8,
+    [RTX_8X4  ] = last_nonzero_col_from_eob_8x4,
+    [RTX_8X16 ] = last_nonzero_col_from_eob_8x16,
+    [RTX_16X8 ] = last_nonzero_col_from_eob_16x8,
+    [RTX_16X32] = last_nonzero_col_from_eob_16x32,
+    [RTX_32X16] = last_nonzero_col_from_eob_32x16,
+    [RTX_32X64] = last_nonzero_col_from_eob_32x32,
+    [RTX_64X32] = last_nonzero_col_from_eob_32x32,
+    [RTX_4X16 ] = last_nonzero_col_from_eob_4x16,
+    [RTX_16X4 ] = last_nonzero_col_from_eob_16x4,
+    [RTX_8X32 ] = last_nonzero_col_from_eob_8x32,
+    [RTX_32X8 ] = last_nonzero_col_from_eob_32x8,
+    [RTX_16X64] = last_nonzero_col_from_eob_16x32,
+    [RTX_64X16] = last_nonzero_col_from_eob_32x16,
+};
diff --git a/media/libdav1d/src/src/scan.h b/media/libdav1d/src/src/scan.h
new file mode 100644
index 0000000000..2bd0b5b84e
--- /dev/null
+++ b/media/libdav1d/src/src/scan.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_SCAN_H
+#define DAV1D_SRC_SCAN_H
+
+#include 
+
+#include "src/levels.h"
+
+EXTERN const uint16_t *const dav1d_scans[N_RECT_TX_SIZES];
+EXTERN const uint8_t *const dav1d_last_nonzero_col_from_eob[N_RECT_TX_SIZES];
+
+void dav1d_init_last_nonzero_col_from_eob_tables(void);
+
+#endif /* DAV1D_SRC_SCAN_H */
diff --git a/media/libdav1d/src/src/tables.c b/media/libdav1d/src/src/tables.c
new file mode 100644
index 0000000000..524864c4fa
--- /dev/null
+++ b/media/libdav1d/src/src/tables.c
@@ -0,0 +1,1020 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/attributes.h"
+
+#include "src/levels.h"
+#include "src/tables.h"
+
+const uint8_t dav1d_al_part_ctx[2][N_BL_LEVELS][N_PARTITIONS] = {
+    {
+        // partitions:
+        // none,  h,    v, split,  tts,  tbs,  tls,  trs,   h4,   v4
+        { 0x00, 0x00, 0x10,   -1, 0x00, 0x10, 0x10, 0x10,   -1,   -1 }, // bl128
+        { 0x10, 0x10, 0x18,   -1, 0x10, 0x18, 0x18, 0x18, 0x10, 0x1c }, // bl64
+        { 0x18, 0x18, 0x1c,   -1, 0x18, 0x1c, 0x1c, 0x1c, 0x18, 0x1e }, // bl32
+        { 0x1c, 0x1c, 0x1e,   -1, 0x1c, 0x1e, 0x1e, 0x1e, 0x1c, 0x1f }, // bl16
+        { 0x1e, 0x1e, 0x1f, 0x1f,   -1,   -1,   -1,   -1,   -1,   -1 }, // bl8
+    }, {
+        { 0x00, 0x10, 0x00,   -1, 0x10, 0x10, 0x00, 0x10,   -1,   -1 }, // bl128
+        { 0x10, 0x18, 0x10,   -1, 0x18, 0x18, 0x10, 0x18, 0x1c, 0x10 }, // bl64
+        { 0x18, 0x1c, 0x18,   -1, 0x1c, 0x1c, 0x18, 0x1c, 0x1e, 0x18 }, // bl32
+        { 0x1c, 0x1e, 0x1c,   -1, 0x1e, 0x1e, 0x1c, 0x1e, 0x1f, 0x1c }, // bl16
+        { 0x1e, 0x1f, 0x1e, 0x1f,   -1,   -1,   -1,   -1,   -1,   -1 }, // bl8
+    }
+};
+
+const uint8_t /* enum BlockSize */
+    dav1d_block_sizes[N_BL_LEVELS][N_PARTITIONS][2] =
+{
+    [BL_128X128] = {
+        [PARTITION_NONE]           = { BS_128x128 },
+        [PARTITION_H]              = { BS_128x64 },
+        [PARTITION_V]              = { BS_64x128 },
+        [PARTITION_T_TOP_SPLIT]    = { BS_64x64, BS_128x64 },
+        [PARTITION_T_BOTTOM_SPLIT] = { BS_128x64, BS_64x64 },
+        [PARTITION_T_LEFT_SPLIT]   = { BS_64x64, BS_64x128 },
+        [PARTITION_T_RIGHT_SPLIT]  = { BS_64x128, BS_64x64 },
+    }, [BL_64X64] = {
+        [PARTITION_NONE]           = { BS_64x64 },
+        [PARTITION_H]              = { BS_64x32 },
+        [PARTITION_V]              = { BS_32x64 },
+        [PARTITION_T_TOP_SPLIT]    = { BS_32x32, BS_64x32 },
+        [PARTITION_T_BOTTOM_SPLIT] = { BS_64x32, BS_32x32 },
+        [PARTITION_T_LEFT_SPLIT]   = { BS_32x32, BS_32x64 },
+        [PARTITION_T_RIGHT_SPLIT]  = { BS_32x64, BS_32x32 },
+        [PARTITION_H4]             = { BS_64x16 },
+        [PARTITION_V4]             = { BS_16x64 },
+    }, [BL_32X32] = {
+        [PARTITION_NONE]           = { BS_32x32 },
+        [PARTITION_H]              = { BS_32x16 },
+        [PARTITION_V]              = { BS_16x32 },
+        [PARTITION_T_TOP_SPLIT]    = { BS_16x16, BS_32x16 },
+        [PARTITION_T_BOTTOM_SPLIT] = { BS_32x16, BS_16x16 },
+        [PARTITION_T_LEFT_SPLIT]   = { BS_16x16, BS_16x32 },
+        [PARTITION_T_RIGHT_SPLIT]  = { BS_16x32, BS_16x16 },
+        [PARTITION_H4]             = { BS_32x8  },
+        [PARTITION_V4]             = { BS_8x32  },
+    }, [BL_16X16] = {
+        [PARTITION_NONE]           = { BS_16x16 },
+        [PARTITION_H]              = { BS_16x8  },
+        [PARTITION_V]              = { BS_8x16  },
+        [PARTITION_T_TOP_SPLIT]    = { BS_8x8,   BS_16x8  },
+        [PARTITION_T_BOTTOM_SPLIT] = { BS_16x8,  BS_8x8   },
+        [PARTITION_T_LEFT_SPLIT]   = { BS_8x8,   BS_8x16  },
+        [PARTITION_T_RIGHT_SPLIT]  = { BS_8x16,  BS_8x8   },
+        [PARTITION_H4]             = { BS_16x4  },
+        [PARTITION_V4]             = { BS_4x16  },
+    }, [BL_8X8] = {
+        [PARTITION_NONE]           = { BS_8x8   },
+        [PARTITION_H]              = { BS_8x4   },
+        [PARTITION_V]              = { BS_4x8   },
+        [PARTITION_SPLIT]          = { BS_4x4   },
+    }
+};
+
+const uint8_t dav1d_block_dimensions[N_BS_SIZES][4] = {
+    [BS_128x128] = { 32, 32, 5, 5 },
+    [BS_128x64]  = { 32, 16, 5, 4 },
+    [BS_64x128]  = { 16, 32, 4, 5 },
+    [BS_64x64]   = { 16, 16, 4, 4 },
+    [BS_64x32]   = { 16,  8, 4, 3 },
+    [BS_64x16]   = { 16,  4, 4, 2 },
+    [BS_32x64]   = {  8, 16, 3, 4 },
+    [BS_32x32]   = {  8,  8, 3, 3 },
+    [BS_32x16]   = {  8,  4, 3, 2 },
+    [BS_32x8]    = {  8,  2, 3, 1 },
+    [BS_16x64]   = {  4, 16, 2, 4 },
+    [BS_16x32]   = {  4,  8, 2, 3 },
+    [BS_16x16]   = {  4,  4, 2, 2 },
+    [BS_16x8]    = {  4,  2, 2, 1 },
+    [BS_16x4]    = {  4,  1, 2, 0 },
+    [BS_8x32]    = {  2,  8, 1, 3 },
+    [BS_8x16]    = {  2,  4, 1, 2 },
+    [BS_8x8]     = {  2,  2, 1, 1 },
+    [BS_8x4]     = {  2,  1, 1, 0 },
+    [BS_4x16]    = {  1,  4, 0, 2 },
+    [BS_4x8]     = {  1,  2, 0, 1 },
+    [BS_4x4]     = {  1,  1, 0, 0 },
+};
+
+const TxfmInfo dav1d_txfm_dimensions[N_RECT_TX_SIZES] = {
+    [ TX_4X4]   = { .w = 1, .h = 1, .lw = 0, .lh = 0,
+                    .min = 0, .max = 0, .ctx = 0 },
+    [ TX_8X8]   = { .w = 2, .h = 2, .lw = 1, .lh = 1,
+                    .min = 1, .max = 1, .sub = TX_4X4, .ctx = 1 },
+    [ TX_16X16] = { .w = 4, .h = 4, .lw = 2, .lh = 2,
+                    .min = 2, .max = 2, .sub = TX_8X8, .ctx = 2 },
+    [ TX_32X32] = { .w = 8, .h = 8, .lw = 3, .lh = 3,
+                    .min = 3, .max = 3, .sub = TX_16X16, .ctx = 3 },
+    [ TX_64X64] = { .w = 16, .h = 16, .lw = 4, .lh = 4,
+                    .min = 4, .max = 4, .sub = TX_32X32, .ctx = 4 },
+    [RTX_4X8]   = { .w = 1, .h = 2, .lw = 0, .lh = 1,
+                    .min = 0, .max = 1, .sub = TX_4X4, .ctx = 1 },
+    [RTX_8X4]   = { .w = 2, .h = 1, .lw = 1, .lh = 0,
+                    .min = 0, .max = 1, .sub = TX_4X4, .ctx = 1 },
+    [RTX_8X16]  = { .w = 2, .h = 4, .lw = 1, .lh = 2,
+                    .min = 1, .max = 2, .sub = TX_8X8, .ctx = 2 },
+    [RTX_16X8]  = { .w = 4, .h = 2, .lw = 2, .lh = 1,
+                    .min = 1, .max = 2, .sub = TX_8X8, .ctx = 2 },
+    [RTX_16X32] = { .w = 4, .h = 8, .lw = 2, .lh = 3,
+                    .min = 2, .max = 3, .sub = TX_16X16, .ctx = 3 },
+    [RTX_32X16] = { .w = 8, .h = 4, .lw = 3, .lh = 2,
+                    .min = 2, .max = 3, .sub = TX_16X16, .ctx = 3 },
+    [RTX_32X64] = { .w = 8, .h = 16, .lw = 3, .lh = 4,
+                    .min = 3, .max = 4, .sub = TX_32X32, .ctx = 4 },
+    [RTX_64X32] = { .w = 16, .h = 8, .lw = 4, .lh = 3,
+                    .min = 3, .max = 4, .sub = TX_32X32, .ctx = 4 },
+    [RTX_4X16]  = { .w = 1, .h = 4, .lw = 0, .lh = 2,
+                    .min = 0, .max = 2, .sub = RTX_4X8, .ctx = 1 },
+    [RTX_16X4]  = { .w = 4, .h = 1, .lw = 2, .lh = 0,
+                    .min = 0, .max = 2, .sub = RTX_8X4, .ctx = 1 },
+    [RTX_8X32]  = { .w = 2, .h = 8, .lw = 1, .lh = 3,
+                    .min = 1, .max = 3, .sub = RTX_8X16, .ctx = 2 },
+    [RTX_32X8]  = { .w = 8, .h = 2, .lw = 3, .lh = 1,
+                    .min = 1, .max = 3, .sub = RTX_16X8, .ctx = 2 },
+    [RTX_16X64] = { .w = 4, .h = 16, .lw = 2, .lh = 4,
+                    .min = 2, .max = 4, .sub = RTX_16X32, .ctx = 3 },
+    [RTX_64X16] = { .w = 16, .h = 4, .lw = 4, .lh = 2,
+                    .min = 2, .max = 4, .sub = RTX_32X16, .ctx = 3 },
+};
+
+const uint8_t /* enum (Rect)TxfmSize */
+    dav1d_max_txfm_size_for_bs[N_BS_SIZES][4 /* y, 420, 422, 444 */] =
+{
+    [BS_128x128] = {  TX_64X64,  TX_32X32,  TX_32X32,  TX_32X32 },
+    [BS_128x64]  = {  TX_64X64,  TX_32X32,  TX_32X32,  TX_32X32 },
+    [BS_64x128]  = {  TX_64X64,  TX_32X32,       0,    TX_32X32 },
+    [BS_64x64]   = {  TX_64X64,  TX_32X32,  TX_32X32,  TX_32X32 },
+    [BS_64x32]   = { RTX_64X32, RTX_32X16,  TX_32X32,  TX_32X32 },
+    [BS_64x16]   = { RTX_64X16, RTX_32X8,  RTX_32X16, RTX_32X16 },
+    [BS_32x64]   = { RTX_32X64, RTX_16X32,       0,    TX_32X32 },
+    [BS_32x32]   = {  TX_32X32,  TX_16X16, RTX_16X32,  TX_32X32 },
+    [BS_32x16]   = { RTX_32X16, RTX_16X8,   TX_16X16, RTX_32X16 },
+    [BS_32x8]    = { RTX_32X8,  RTX_16X4,  RTX_16X8,  RTX_32X8  },
+    [BS_16x64]   = { RTX_16X64, RTX_8X32,        0,   RTX_16X32 },
+    [BS_16x32]   = { RTX_16X32, RTX_8X16,        0,   RTX_16X32 },
+    [BS_16x16]   = {  TX_16X16,  TX_8X8,   RTX_8X16,   TX_16X16 },
+    [BS_16x8]    = { RTX_16X8,  RTX_8X4,    TX_8X8,   RTX_16X8  },
+    [BS_16x4]    = { RTX_16X4,  RTX_8X4,   RTX_8X4,   RTX_16X4  },
+    [BS_8x32]    = { RTX_8X32,  RTX_4X16,       0,    RTX_8X32  },
+    [BS_8x16]    = { RTX_8X16,  RTX_4X8,        0,    RTX_8X16  },
+    [BS_8x8]     = {  TX_8X8,    TX_4X4,   RTX_4X8,    TX_8X8   },
+    [BS_8x4]     = { RTX_8X4,    TX_4X4,    TX_4X4,   RTX_8X4   },
+    [BS_4x16]    = { RTX_4X16,  RTX_4X8,        0,    RTX_4X16  },
+    [BS_4x8]     = { RTX_4X8,    TX_4X4,        0,    RTX_4X8   },
+    [BS_4x4]     = {  TX_4X4,    TX_4X4,    TX_4X4,    TX_4X4   },
+};
+
+const uint8_t /* enum TxfmType */
+    dav1d_txtp_from_uvmode[N_UV_INTRA_PRED_MODES] =
+{
+    [DC_PRED]              = DCT_DCT,
+    [VERT_PRED]            = ADST_DCT,
+    [HOR_PRED]             = DCT_ADST,
+    [DIAG_DOWN_LEFT_PRED]  = DCT_DCT,
+    [DIAG_DOWN_RIGHT_PRED] = ADST_ADST,
+    [VERT_RIGHT_PRED]      = ADST_DCT,
+    [HOR_DOWN_PRED]        = DCT_ADST,
+    [HOR_UP_PRED]          = DCT_ADST,
+    [VERT_LEFT_PRED]       = ADST_DCT,
+    [SMOOTH_PRED]          = ADST_ADST,
+    [SMOOTH_V_PRED]        = ADST_DCT,
+    [SMOOTH_H_PRED]        = DCT_ADST,
+    [PAETH_PRED]           = ADST_ADST,
+};
+
+const uint8_t /* enum InterPredMode */
+    dav1d_comp_inter_pred_modes[N_COMP_INTER_PRED_MODES][2] =
+{
+    [NEARESTMV_NEARESTMV] = { NEARESTMV, NEARESTMV },
+    [NEARMV_NEARMV]       = { NEARMV,    NEARMV    },
+    [NEWMV_NEWMV]         = { NEWMV,     NEWMV     },
+    [GLOBALMV_GLOBALMV]   = { GLOBALMV,  GLOBALMV  },
+    [NEWMV_NEARESTMV]     = { NEWMV,     NEARESTMV },
+    [NEWMV_NEARMV]        = { NEWMV,     NEARMV    },
+    [NEARESTMV_NEWMV]     = { NEARESTMV, NEWMV     },
+    [NEARMV_NEWMV]        = { NEARMV,    NEWMV     },
+};
+
+const uint8_t dav1d_partition_type_count[N_BL_LEVELS] = {
+    [BL_128X128] = N_PARTITIONS - 3,
+    [BL_64X64]   = N_PARTITIONS - 1,
+    [BL_32X32]   = N_PARTITIONS - 1,
+    [BL_16X16]   = N_PARTITIONS - 1,
+    [BL_8X8]     = N_SUB8X8_PARTITIONS - 1,
+};
+
+const uint8_t /* enum TxfmType */ dav1d_tx_types_per_set[40] = {
+    /* Intra2 */
+    IDTX, DCT_DCT, ADST_ADST, ADST_DCT, DCT_ADST,
+    /* Intra1 */
+    IDTX, DCT_DCT, V_DCT, H_DCT, ADST_ADST, ADST_DCT, DCT_ADST,
+    /* Inter2 */
+    IDTX, V_DCT, H_DCT, DCT_DCT, ADST_DCT, DCT_ADST, FLIPADST_DCT,
+    DCT_FLIPADST, ADST_ADST, FLIPADST_FLIPADST, ADST_FLIPADST, FLIPADST_ADST,
+    /* Inter1 */
+    IDTX, V_DCT, H_DCT, V_ADST, H_ADST, V_FLIPADST, H_FLIPADST,
+    DCT_DCT, ADST_DCT, DCT_ADST, FLIPADST_DCT, DCT_FLIPADST,
+    ADST_ADST, FLIPADST_FLIPADST, ADST_FLIPADST, FLIPADST_ADST,
+};
+
+const uint8_t dav1d_ymode_size_context[N_BS_SIZES] = {
+    [BS_128x128] = 3,
+    [BS_128x64]  = 3,
+    [BS_64x128]  = 3,
+    [BS_64x64]   = 3,
+    [BS_64x32]   = 3,
+    [BS_64x16]   = 2,
+    [BS_32x64]   = 3,
+    [BS_32x32]   = 3,
+    [BS_32x16]   = 2,
+    [BS_32x8 ]   = 1,
+    [BS_16x64]   = 2,
+    [BS_16x32]   = 2,
+    [BS_16x16]   = 2,
+    [BS_16x8 ]   = 1,
+    [BS_16x4 ]   = 0,
+    [BS_8x32 ]   = 1,
+    [BS_8x16 ]   = 1,
+    [BS_8x8  ]   = 1,
+    [BS_8x4  ]   = 0,
+    [BS_4x16 ]   = 0,
+    [BS_4x8  ]   = 0,
+    [BS_4x4  ]   = 0,
+};
+
+const uint8_t dav1d_lo_ctx_offsets[3][5][5] = {
+    { /* w == h */
+        {  0,  1,  6,  6, 21 },
+        {  1,  6,  6, 21, 21 },
+        {  6,  6, 21, 21, 21 },
+        {  6, 21, 21, 21, 21 },
+        { 21, 21, 21, 21, 21 },
+    }, { /* w > h */
+        {  0, 16,  6,  6, 21 },
+        { 16, 16,  6, 21, 21 },
+        { 16, 16, 21, 21, 21 },
+        { 16, 16, 21, 21, 21 },
+        { 16, 16, 21, 21, 21 },
+    }, { /* w < h */
+        {  0, 11, 11, 11, 11 },
+        { 11, 11, 11, 11, 11 },
+        {  6,  6, 21, 21, 21 },
+        {  6, 21, 21, 21, 21 },
+        { 21, 21, 21, 21, 21 },
+    },
+};
+
+const uint8_t dav1d_skip_ctx[5][5] = {
+    { 1, 2, 2, 2, 3 },
+    { 2, 4, 4, 4, 5 },
+    { 2, 4, 4, 4, 5 },
+    { 2, 4, 4, 4, 5 },
+    { 3, 5, 5, 5, 6 },
+};
+
+const uint8_t /* enum TxClass */ dav1d_tx_type_class[N_TX_TYPES_PLUS_LL] = {
+    [DCT_DCT]           = TX_CLASS_2D,
+    [ADST_DCT]          = TX_CLASS_2D,
+    [DCT_ADST]          = TX_CLASS_2D,
+    [ADST_ADST]         = TX_CLASS_2D,
+    [FLIPADST_DCT]      = TX_CLASS_2D,
+    [DCT_FLIPADST]      = TX_CLASS_2D,
+    [FLIPADST_FLIPADST] = TX_CLASS_2D,
+    [ADST_FLIPADST]     = TX_CLASS_2D,
+    [FLIPADST_ADST]     = TX_CLASS_2D,
+    [IDTX]              = TX_CLASS_2D,
+    [V_DCT]             = TX_CLASS_V,
+    [H_DCT]             = TX_CLASS_H,
+    [V_ADST]            = TX_CLASS_V,
+    [H_ADST]            = TX_CLASS_H,
+    [V_FLIPADST]        = TX_CLASS_V,
+    [H_FLIPADST]        = TX_CLASS_H,
+    [WHT_WHT]           = TX_CLASS_2D,
+};
+
+const uint8_t /* enum Filter2d */ dav1d_filter_2d[DAV1D_N_FILTERS][DAV1D_N_FILTERS] = {
+    [DAV1D_FILTER_8TAP_REGULAR] = {
+        [DAV1D_FILTER_8TAP_REGULAR] = FILTER_2D_8TAP_REGULAR,
+        [DAV1D_FILTER_8TAP_SHARP]   = FILTER_2D_8TAP_REGULAR_SHARP,
+        [DAV1D_FILTER_8TAP_SMOOTH]  = FILTER_2D_8TAP_REGULAR_SMOOTH,
+    }, [DAV1D_FILTER_8TAP_SHARP] = {
+        [DAV1D_FILTER_8TAP_REGULAR] = FILTER_2D_8TAP_SHARP_REGULAR,
+        [DAV1D_FILTER_8TAP_SHARP]   = FILTER_2D_8TAP_SHARP,
+        [DAV1D_FILTER_8TAP_SMOOTH]  = FILTER_2D_8TAP_SHARP_SMOOTH,
+    }, [DAV1D_FILTER_8TAP_SMOOTH] = {
+        [DAV1D_FILTER_8TAP_REGULAR] = FILTER_2D_8TAP_SMOOTH_REGULAR,
+        [DAV1D_FILTER_8TAP_SHARP]   = FILTER_2D_8TAP_SMOOTH_SHARP,
+        [DAV1D_FILTER_8TAP_SMOOTH]  = FILTER_2D_8TAP_SMOOTH,
+    }, [DAV1D_FILTER_BILINEAR] = {
+        [DAV1D_FILTER_BILINEAR]     = FILTER_2D_BILINEAR,
+    }
+};
+
+const uint8_t /* enum Dav1dFilterMode */ dav1d_filter_dir[N_2D_FILTERS][2] = {
+    [FILTER_2D_8TAP_REGULAR]        = { DAV1D_FILTER_8TAP_REGULAR, DAV1D_FILTER_8TAP_REGULAR },
+    [FILTER_2D_8TAP_REGULAR_SMOOTH] = { DAV1D_FILTER_8TAP_SMOOTH,  DAV1D_FILTER_8TAP_REGULAR },
+    [FILTER_2D_8TAP_REGULAR_SHARP]  = { DAV1D_FILTER_8TAP_SHARP,   DAV1D_FILTER_8TAP_REGULAR },
+    [FILTER_2D_8TAP_SHARP_REGULAR]  = { DAV1D_FILTER_8TAP_REGULAR, DAV1D_FILTER_8TAP_SHARP   },
+    [FILTER_2D_8TAP_SHARP_SMOOTH]   = { DAV1D_FILTER_8TAP_SMOOTH,  DAV1D_FILTER_8TAP_SHARP   },
+    [FILTER_2D_8TAP_SHARP]          = { DAV1D_FILTER_8TAP_SHARP,   DAV1D_FILTER_8TAP_SHARP   },
+    [FILTER_2D_8TAP_SMOOTH_REGULAR] = { DAV1D_FILTER_8TAP_REGULAR, DAV1D_FILTER_8TAP_SMOOTH  },
+    [FILTER_2D_8TAP_SMOOTH]         = { DAV1D_FILTER_8TAP_SMOOTH,  DAV1D_FILTER_8TAP_SMOOTH  },
+    [FILTER_2D_8TAP_SMOOTH_SHARP]   = { DAV1D_FILTER_8TAP_SHARP,   DAV1D_FILTER_8TAP_SMOOTH  },
+    [FILTER_2D_BILINEAR]            = { DAV1D_FILTER_BILINEAR,     DAV1D_FILTER_BILINEAR     },
+};
+
+const uint8_t dav1d_filter_mode_to_y_mode[5] = {
+    DC_PRED, VERT_PRED, HOR_PRED, HOR_DOWN_PRED, DC_PRED
+};
+
+const uint8_t dav1d_intra_mode_context[N_INTRA_PRED_MODES] = {
+    [DC_PRED]              = 0,
+    [VERT_PRED]            = 1,
+    [HOR_PRED]             = 2,
+    [DIAG_DOWN_LEFT_PRED]  = 3,
+    [DIAG_DOWN_RIGHT_PRED] = 4,
+    [VERT_RIGHT_PRED]      = 4,
+    [HOR_DOWN_PRED]        = 4,
+    [HOR_UP_PRED]          = 4,
+    [VERT_LEFT_PRED]       = 3,
+    [SMOOTH_PRED]          = 0,
+    [SMOOTH_V_PRED]        = 1,
+    [SMOOTH_H_PRED]        = 2,
+    [PAETH_PRED]           = 0,
+};
+
+const uint8_t dav1d_wedge_ctx_lut[N_BS_SIZES] = {
+    [BS_32x32] = 6,
+    [BS_32x16] = 5,
+    [BS_32x8]  = 8,
+    [BS_16x32] = 4,
+    [BS_16x16] = 3,
+    [BS_16x8]  = 2,
+    [BS_8x32]  = 7,
+    [BS_8x16]  = 1,
+    [BS_8x8]   = 0,
+};
+
+const Dav1dWarpedMotionParams dav1d_default_wm_params = {
+    .type = DAV1D_WM_TYPE_IDENTITY,
+    .matrix = {
+        0, 0, 1 << 16,
+        0, 0, 1 << 16,
+    },
+    .u.p.alpha = 0,
+    .u.p.beta = 0,
+    .u.p.gamma = 0,
+    .u.p.delta = 0,
+};
+
+const int8_t dav1d_cdef_directions[2 + 8 + 2 /* dir */][2 /* pass */] = {
+    {  1 * 12 + 0,  2 * 12 + 0 }, // 6
+    {  1 * 12 + 0,  2 * 12 - 1 }, // 7
+    { -1 * 12 + 1, -2 * 12 + 2 }, // 0
+    {  0 * 12 + 1, -1 * 12 + 2 }, // 1
+    {  0 * 12 + 1,  0 * 12 + 2 }, // 2
+    {  0 * 12 + 1,  1 * 12 + 2 }, // 3
+    {  1 * 12 + 1,  2 * 12 + 2 }, // 4
+    {  1 * 12 + 0,  2 * 12 + 1 }, // 5
+    {  1 * 12 + 0,  2 * 12 + 0 }, // 6
+    {  1 * 12 + 0,  2 * 12 - 1 }, // 7
+    { -1 * 12 + 1, -2 * 12 + 2 }, // 0
+    {  0 * 12 + 1, -1 * 12 + 2 }, // 1
+};
+
+const uint16_t ALIGN(dav1d_sgr_params[16][2], 4) = {
+    { 140, 3236 }, { 112, 2158 }, {  93, 1618 }, {  80, 1438 },
+    {  70, 1295 }, {  58, 1177 }, {  47, 1079 }, {  37,  996 },
+    {  30,  925 }, {  25,  863 }, {   0, 2589 }, {   0, 1618 },
+    {   0, 1177 }, {   0,  925 }, {  56,    0 }, {  22,    0 },
+};
+
+ATTR_MCMODEL_SMALL
+const uint8_t ALIGN(dav1d_sgr_x_by_x[256], 64) = {
+    255, 128,  85,  64,  51,  43,  37,  32,  28,  26,  23,  21,  20,  18,  17,
+     16,  15,  14,  13,  13,  12,  12,  11,  11,  10,  10,   9,   9,   9,   9,
+      8,   8,   8,   8,   7,   7,   7,   7,   7,   6,   6,   6,   6,   6,   6,
+      6,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   3,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      0
+};
+
+ATTR_MCMODEL_SMALL
+const int8_t ALIGN(dav1d_mc_subpel_filters[6][15][8], 8) = {
+    [DAV1D_FILTER_8TAP_REGULAR] = {
+        {   0,   1,  -3,  63,   4,  -1,   0,   0 },
+        {   0,   1,  -5,  61,   9,  -2,   0,   0 },
+        {   0,   1,  -6,  58,  14,  -4,   1,   0 },
+        {   0,   1,  -7,  55,  19,  -5,   1,   0 },
+        {   0,   1,  -7,  51,  24,  -6,   1,   0 },
+        {   0,   1,  -8,  47,  29,  -6,   1,   0 },
+        {   0,   1,  -7,  42,  33,  -6,   1,   0 },
+        {   0,   1,  -7,  38,  38,  -7,   1,   0 },
+        {   0,   1,  -6,  33,  42,  -7,   1,   0 },
+        {   0,   1,  -6,  29,  47,  -8,   1,   0 },
+        {   0,   1,  -6,  24,  51,  -7,   1,   0 },
+        {   0,   1,  -5,  19,  55,  -7,   1,   0 },
+        {   0,   1,  -4,  14,  58,  -6,   1,   0 },
+        {   0,   0,  -2,   9,  61,  -5,   1,   0 },
+        {   0,   0,  -1,   4,  63,  -3,   1,   0 }
+    }, [DAV1D_FILTER_8TAP_SMOOTH] = {
+        {   0,   1,  14,  31,  17,   1,   0,   0 },
+        {   0,   0,  13,  31,  18,   2,   0,   0 },
+        {   0,   0,  11,  31,  20,   2,   0,   0 },
+        {   0,   0,  10,  30,  21,   3,   0,   0 },
+        {   0,   0,   9,  29,  22,   4,   0,   0 },
+        {   0,   0,   8,  28,  23,   5,   0,   0 },
+        {   0,  -1,   8,  27,  24,   6,   0,   0 },
+        {   0,  -1,   7,  26,  26,   7,  -1,   0 },
+        {   0,   0,   6,  24,  27,   8,  -1,   0 },
+        {   0,   0,   5,  23,  28,   8,   0,   0 },
+        {   0,   0,   4,  22,  29,   9,   0,   0 },
+        {   0,   0,   3,  21,  30,  10,   0,   0 },
+        {   0,   0,   2,  20,  31,  11,   0,   0 },
+        {   0,   0,   2,  18,  31,  13,   0,   0 },
+        {   0,   0,   1,  17,  31,  14,   1,   0 }
+    }, [DAV1D_FILTER_8TAP_SHARP] = {
+        {  -1,   1,  -3,  63,   4,  -1,   1,   0 },
+        {  -1,   3,  -6,  62,   8,  -3,   2,  -1 },
+        {  -1,   4,  -9,  60,  13,  -5,   3,  -1 },
+        {  -2,   5, -11,  58,  19,  -7,   3,  -1 },
+        {  -2,   5, -11,  54,  24,  -9,   4,  -1 },
+        {  -2,   5, -12,  50,  30, -10,   4,  -1 },
+        {  -2,   5, -12,  45,  35, -11,   5,  -1 },
+        {  -2,   6, -12,  40,  40, -12,   6,  -2 },
+        {  -1,   5, -11,  35,  45, -12,   5,  -2 },
+        {  -1,   4, -10,  30,  50, -12,   5,  -2 },
+        {  -1,   4,  -9,  24,  54, -11,   5,  -2 },
+        {  -1,   3,  -7,  19,  58, -11,   5,  -2 },
+        {  -1,   3,  -5,  13,  60,  -9,   4,  -1 },
+        {  -1,   2,  -3,   8,  62,  -6,   3,  -1 },
+        {   0,   1,  -1,   4,  63,  -3,   1,  -1 }
+    /* width <= 4 */
+    }, [3 + DAV1D_FILTER_8TAP_REGULAR] = {
+        {   0,   0,  -2,  63,   4,  -1,   0,   0 },
+        {   0,   0,  -4,  61,   9,  -2,   0,   0 },
+        {   0,   0,  -5,  58,  14,  -3,   0,   0 },
+        {   0,   0,  -6,  55,  19,  -4,   0,   0 },
+        {   0,   0,  -6,  51,  24,  -5,   0,   0 },
+        {   0,   0,  -7,  47,  29,  -5,   0,   0 },
+        {   0,   0,  -6,  42,  33,  -5,   0,   0 },
+        {   0,   0,  -6,  38,  38,  -6,   0,   0 },
+        {   0,   0,  -5,  33,  42,  -6,   0,   0 },
+        {   0,   0,  -5,  29,  47,  -7,   0,   0 },
+        {   0,   0,  -5,  24,  51,  -6,   0,   0 },
+        {   0,   0,  -4,  19,  55,  -6,   0,   0 },
+        {   0,   0,  -3,  14,  58,  -5,   0,   0 },
+        {   0,   0,  -2,   9,  61,  -4,   0,   0 },
+        {   0,   0,  -1,   4,  63,  -2,   0,   0 }
+    }, [3 + DAV1D_FILTER_8TAP_SMOOTH] = {
+        {   0,   0,  15,  31,  17,   1,   0,   0 },
+        {   0,   0,  13,  31,  18,   2,   0,   0 },
+        {   0,   0,  11,  31,  20,   2,   0,   0 },
+        {   0,   0,  10,  30,  21,   3,   0,   0 },
+        {   0,   0,   9,  29,  22,   4,   0,   0 },
+        {   0,   0,   8,  28,  23,   5,   0,   0 },
+        {   0,   0,   7,  27,  24,   6,   0,   0 },
+        {   0,   0,   6,  26,  26,   6,   0,   0 },
+        {   0,   0,   6,  24,  27,   7,   0,   0 },
+        {   0,   0,   5,  23,  28,   8,   0,   0 },
+        {   0,   0,   4,  22,  29,   9,   0,   0 },
+        {   0,   0,   3,  21,  30,  10,   0,   0 },
+        {   0,   0,   2,  20,  31,  11,   0,   0 },
+        {   0,   0,   2,  18,  31,  13,   0,   0 },
+        {   0,   0,   1,  17,  31,  15,   0,   0 }
+    /* Bilin scaled being very rarely used, add a new table entry
+     * and use the put/prep_8tap_scaled code, thus acting as a
+     * scaled bilinear filter. */
+    }, [5] = {
+        {   0,   0,   0, 60,   4,   0,   0,   0 },
+        {   0,   0,   0, 56,   8,   0,   0,   0 },
+        {   0,   0,   0, 52,  12,   0,   0,   0 },
+        {   0,   0,   0, 48,  16,   0,   0,   0 },
+        {   0,   0,   0, 44,  20,   0,   0,   0 },
+        {   0,   0,   0, 40,  24,   0,   0,   0 },
+        {   0,   0,   0, 36,  28,   0,   0,   0 },
+        {   0,   0,   0, 32,  32,   0,   0,   0 },
+        {   0,   0,   0, 28,  36,   0,   0,   0 },
+        {   0,   0,   0, 24,  40,   0,   0,   0 },
+        {   0,   0,   0, 20,  44,   0,   0,   0 },
+        {   0,   0,   0, 16,  48,   0,   0,   0 },
+        {   0,   0,   0, 12,  52,   0,   0,   0 },
+        {   0,   0,   0,  8,  56,   0,   0,   0 },
+        {   0,   0,   0,  4,  60,   0,   0,   0 }
+    }
+};
+
+ATTR_MCMODEL_SMALL
+const int8_t ALIGN(dav1d_mc_warp_filter[193][8], 8) = {
+    // [-1, 0)
+    { 0,   0, 127,   1,   0, 0, 0, 0 }, { 0,  -1, 127,   2,   0, 0, 0, 0 },
+    { 1,  -3, 127,   4, - 1, 0, 0, 0 }, { 1,  -4, 126,   6,  -2, 1, 0, 0 },
+    { 1,  -5, 126,   8, - 3, 1, 0, 0 }, { 1,  -6, 125,  11,  -4, 1, 0, 0 },
+    { 1,  -7, 124,  13, - 4, 1, 0, 0 }, { 2,  -8, 123,  15,  -5, 1, 0, 0 },
+    { 2,  -9, 122,  18, - 6, 1, 0, 0 }, { 2, -10, 121,  20,  -6, 1, 0, 0 },
+    { 2, -11, 120,  22, - 7, 2, 0, 0 }, { 2, -12, 119,  25,  -8, 2, 0, 0 },
+    { 3, -13, 117,  27, - 8, 2, 0, 0 }, { 3, -13, 116,  29,  -9, 2, 0, 0 },
+    { 3, -14, 114,  32, -10, 3, 0, 0 }, { 3, -15, 113,  35, -10, 2, 0, 0 },
+    { 3, -15, 111,  37, -11, 3, 0, 0 }, { 3, -16, 109,  40, -11, 3, 0, 0 },
+    { 3, -16, 108,  42, -12, 3, 0, 0 }, { 4, -17, 106,  45, -13, 3, 0, 0 },
+    { 4, -17, 104,  47, -13, 3, 0, 0 }, { 4, -17, 102,  50, -14, 3, 0, 0 },
+    { 4, -17, 100,  52, -14, 3, 0, 0 }, { 4, -18,  98,  55, -15, 4, 0, 0 },
+    { 4, -18,  96,  58, -15, 3, 0, 0 }, { 4, -18,  94,  60, -16, 4, 0, 0 },
+    { 4, -18,  91,  63, -16, 4, 0, 0 }, { 4, -18,  89,  65, -16, 4, 0, 0 },
+    { 4, -18,  87,  68, -17, 4, 0, 0 }, { 4, -18,  85,  70, -17, 4, 0, 0 },
+    { 4, -18,  82,  73, -17, 4, 0, 0 }, { 4, -18,  80,  75, -17, 4, 0, 0 },
+    { 4, -18,  78,  78, -18, 4, 0, 0 }, { 4, -17,  75,  80, -18, 4, 0, 0 },
+    { 4, -17,  73,  82, -18, 4, 0, 0 }, { 4, -17,  70,  85, -18, 4, 0, 0 },
+    { 4, -17,  68,  87, -18, 4, 0, 0 }, { 4, -16,  65,  89, -18, 4, 0, 0 },
+    { 4, -16,  63,  91, -18, 4, 0, 0 }, { 4, -16,  60,  94, -18, 4, 0, 0 },
+    { 3, -15,  58,  96, -18, 4, 0, 0 }, { 4, -15,  55,  98, -18, 4, 0, 0 },
+    { 3, -14,  52, 100, -17, 4, 0, 0 }, { 3, -14,  50, 102, -17, 4, 0, 0 },
+    { 3, -13,  47, 104, -17, 4, 0, 0 }, { 3, -13,  45, 106, -17, 4, 0, 0 },
+    { 3, -12,  42, 108, -16, 3, 0, 0 }, { 3, -11,  40, 109, -16, 3, 0, 0 },
+    { 3, -11,  37, 111, -15, 3, 0, 0 }, { 2, -10,  35, 113, -15, 3, 0, 0 },
+    { 3, -10,  32, 114, -14, 3, 0, 0 }, { 2, - 9,  29, 116, -13, 3, 0, 0 },
+    { 2,  -8,  27, 117, -13, 3, 0, 0 }, { 2, - 8,  25, 119, -12, 2, 0, 0 },
+    { 2,  -7,  22, 120, -11, 2, 0, 0 }, { 1, - 6,  20, 121, -10, 2, 0, 0 },
+    { 1,  -6,  18, 122, - 9, 2, 0, 0 }, { 1, - 5,  15, 123, - 8, 2, 0, 0 },
+    { 1,  -4,  13, 124, - 7, 1, 0, 0 }, { 1, - 4,  11, 125, - 6, 1, 0, 0 },
+    { 1,  -3,   8, 126, - 5, 1, 0, 0 }, { 1, - 2,   6, 126, - 4, 1, 0, 0 },
+    { 0,  -1,   4, 127, - 3, 1, 0, 0 }, { 0,   0,   2, 127, - 1, 0, 0, 0 },
+    // [0, 1)
+    {  0, 0,   0, 127,   1,   0, 0,  0 }, {  0, 0,  -1, 127,   2,   0, 0,  0 },
+    {  0, 1,  -3, 127,   4,  -2, 1,  0 }, {  0, 1,  -5, 127,   6,  -2, 1,  0 },
+    {  0, 2,  -6, 126,   8,  -3, 1,  0 }, { -1, 2,  -7, 126,  11,  -4, 2, -1 },
+    { -1, 3,  -8, 125,  13,  -5, 2, -1 }, { -1, 3, -10, 124,  16,  -6, 3, -1 },
+    { -1, 4, -11, 123,  18,  -7, 3, -1 }, { -1, 4, -12, 122,  20,  -7, 3, -1 },
+    { -1, 4, -13, 121,  23,  -8, 3, -1 }, { -2, 5, -14, 120,  25,  -9, 4, -1 },
+    { -1, 5, -15, 119,  27, -10, 4, -1 }, { -1, 5, -16, 118,  30, -11, 4, -1 },
+    { -2, 6, -17, 116,  33, -12, 5, -1 }, { -2, 6, -17, 114,  35, -12, 5, -1 },
+    { -2, 6, -18, 113,  38, -13, 5, -1 }, { -2, 7, -19, 111,  41, -14, 6, -2 },
+    { -2, 7, -19, 110,  43, -15, 6, -2 }, { -2, 7, -20, 108,  46, -15, 6, -2 },
+    { -2, 7, -20, 106,  49, -16, 6, -2 }, { -2, 7, -21, 104,  51, -16, 7, -2 },
+    { -2, 7, -21, 102,  54, -17, 7, -2 }, { -2, 8, -21, 100,  56, -18, 7, -2 },
+    { -2, 8, -22,  98,  59, -18, 7, -2 }, { -2, 8, -22,  96,  62, -19, 7, -2 },
+    { -2, 8, -22,  94,  64, -19, 7, -2 }, { -2, 8, -22,  91,  67, -20, 8, -2 },
+    { -2, 8, -22,  89,  69, -20, 8, -2 }, { -2, 8, -22,  87,  72, -21, 8, -2 },
+    { -2, 8, -21,  84,  74, -21, 8, -2 }, { -2, 8, -22,  82,  77, -21, 8, -2 },
+    { -2, 8, -21,  79,  79, -21, 8, -2 }, { -2, 8, -21,  77,  82, -22, 8, -2 },
+    { -2, 8, -21,  74,  84, -21, 8, -2 }, { -2, 8, -21,  72,  87, -22, 8, -2 },
+    { -2, 8, -20,  69,  89, -22, 8, -2 }, { -2, 8, -20,  67,  91, -22, 8, -2 },
+    { -2, 7, -19,  64,  94, -22, 8, -2 }, { -2, 7, -19,  62,  96, -22, 8, -2 },
+    { -2, 7, -18,  59,  98, -22, 8, -2 }, { -2, 7, -18,  56, 100, -21, 8, -2 },
+    { -2, 7, -17,  54, 102, -21, 7, -2 }, { -2, 7, -16,  51, 104, -21, 7, -2 },
+    { -2, 6, -16,  49, 106, -20, 7, -2 }, { -2, 6, -15,  46, 108, -20, 7, -2 },
+    { -2, 6, -15,  43, 110, -19, 7, -2 }, { -2, 6, -14,  41, 111, -19, 7, -2 },
+    { -1, 5, -13,  38, 113, -18, 6, -2 }, { -1, 5, -12,  35, 114, -17, 6, -2 },
+    { -1, 5, -12,  33, 116, -17, 6, -2 }, { -1, 4, -11,  30, 118, -16, 5, -1 },
+    { -1, 4, -10,  27, 119, -15, 5, -1 }, { -1, 4,  -9,  25, 120, -14, 5, -2 },
+    { -1, 3,  -8,  23, 121, -13, 4, -1 }, { -1, 3,  -7,  20, 122, -12, 4, -1 },
+    { -1, 3,  -7,  18, 123, -11, 4, -1 }, { -1, 3,  -6,  16, 124, -10, 3, -1 },
+    { -1, 2,  -5,  13, 125,  -8, 3, -1 }, { -1, 2,  -4,  11, 126,  -7, 2, -1 },
+    {  0, 1,  -3,   8, 126,  -6, 2,  0 }, {  0, 1,  -2,   6, 127,  -5, 1,  0 },
+    {  0, 1,  -2,   4, 127,  -3, 1,  0 }, {  0, 0,   0,   2, 127,  -1, 0,  0 },
+    // [1, 2)
+    { 0, 0, 0,   1, 127,   0,   0, 0 }, { 0, 0, 0,  -1, 127,   2,   0, 0 },
+    { 0, 0, 1,  -3, 127,   4,  -1, 0 }, { 0, 0, 1,  -4, 126,   6,  -2, 1 },
+    { 0, 0, 1,  -5, 126,   8,  -3, 1 }, { 0, 0, 1,  -6, 125,  11,  -4, 1 },
+    { 0, 0, 1,  -7, 124,  13,  -4, 1 }, { 0, 0, 2,  -8, 123,  15,  -5, 1 },
+    { 0, 0, 2,  -9, 122,  18,  -6, 1 }, { 0, 0, 2, -10, 121,  20,  -6, 1 },
+    { 0, 0, 2, -11, 120,  22,  -7, 2 }, { 0, 0, 2, -12, 119,  25,  -8, 2 },
+    { 0, 0, 3, -13, 117,  27,  -8, 2 }, { 0, 0, 3, -13, 116,  29,  -9, 2 },
+    { 0, 0, 3, -14, 114,  32, -10, 3 }, { 0, 0, 3, -15, 113,  35, -10, 2 },
+    { 0, 0, 3, -15, 111,  37, -11, 3 }, { 0, 0, 3, -16, 109,  40, -11, 3 },
+    { 0, 0, 3, -16, 108,  42, -12, 3 }, { 0, 0, 4, -17, 106,  45, -13, 3 },
+    { 0, 0, 4, -17, 104,  47, -13, 3 }, { 0, 0, 4, -17, 102,  50, -14, 3 },
+    { 0, 0, 4, -17, 100,  52, -14, 3 }, { 0, 0, 4, -18,  98,  55, -15, 4 },
+    { 0, 0, 4, -18,  96,  58, -15, 3 }, { 0, 0, 4, -18,  94,  60, -16, 4 },
+    { 0, 0, 4, -18,  91,  63, -16, 4 }, { 0, 0, 4, -18,  89,  65, -16, 4 },
+    { 0, 0, 4, -18,  87,  68, -17, 4 }, { 0, 0, 4, -18,  85,  70, -17, 4 },
+    { 0, 0, 4, -18,  82,  73, -17, 4 }, { 0, 0, 4, -18,  80,  75, -17, 4 },
+    { 0, 0, 4, -18,  78,  78, -18, 4 }, { 0, 0, 4, -17,  75,  80, -18, 4 },
+    { 0, 0, 4, -17,  73,  82, -18, 4 }, { 0, 0, 4, -17,  70,  85, -18, 4 },
+    { 0, 0, 4, -17,  68,  87, -18, 4 }, { 0, 0, 4, -16,  65,  89, -18, 4 },
+    { 0, 0, 4, -16,  63,  91, -18, 4 }, { 0, 0, 4, -16,  60,  94, -18, 4 },
+    { 0, 0, 3, -15,  58,  96, -18, 4 }, { 0, 0, 4, -15,  55,  98, -18, 4 },
+    { 0, 0, 3, -14,  52, 100, -17, 4 }, { 0, 0, 3, -14,  50, 102, -17, 4 },
+    { 0, 0, 3, -13,  47, 104, -17, 4 }, { 0, 0, 3, -13,  45, 106, -17, 4 },
+    { 0, 0, 3, -12,  42, 108, -16, 3 }, { 0, 0, 3, -11,  40, 109, -16, 3 },
+    { 0, 0, 3, -11,  37, 111, -15, 3 }, { 0, 0, 2, -10,  35, 113, -15, 3 },
+    { 0, 0, 3, -10,  32, 114, -14, 3 }, { 0, 0, 2,  -9,  29, 116, -13, 3 },
+    { 0, 0, 2,  -8,  27, 117, -13, 3 }, { 0, 0, 2,  -8,  25, 119, -12, 2 },
+    { 0, 0, 2,  -7,  22, 120, -11, 2 }, { 0, 0, 1,  -6,  20, 121, -10, 2 },
+    { 0, 0, 1,  -6,  18, 122,  -9, 2 }, { 0, 0, 1,  -5,  15, 123,  -8, 2 },
+    { 0, 0, 1,  -4,  13, 124,  -7, 1 }, { 0, 0, 1,  -4,  11, 125,  -6, 1 },
+    { 0, 0, 1,  -3,   8, 126,  -5, 1 }, { 0, 0, 1,  -2,   6, 126,  -4, 1 },
+    { 0, 0, 0,  -1,   4, 127,  -3, 1 }, { 0, 0, 0,   0,   2, 127,  -1, 0 },
+    // dummy (replicate row index 191)
+    { 0, 0, 0,   0,   2, 127,  -1, 0 },
+};
+
+ATTR_MCMODEL_SMALL
+const int8_t ALIGN(dav1d_resize_filter[64][8], 8) = {
+    { 0,  0,  0, -128,    0,  0,  0, 0 }, { 0,  0,  1, -128,   -2,  1,  0, 0 },
+    { 0, -1,  3, -127,   -4,  2, -1, 0 }, { 0, -1,  4, -127,   -6,  3, -1, 0 },
+    { 0, -2,  6, -126,   -8,  3, -1, 0 }, { 0, -2,  7, -125,  -11,  4, -1, 0 },
+    { 1, -2,  8, -125,  -13,  5, -2, 0 }, { 1, -3,  9, -124,  -15,  6, -2, 0 },
+    { 1, -3, 10, -123,  -18,  6, -2, 1 }, { 1, -3, 11, -122,  -20,  7, -3, 1 },
+    { 1, -4, 12, -121,  -22,  8, -3, 1 }, { 1, -4, 13, -120,  -25,  9, -3, 1 },
+    { 1, -4, 14, -118,  -28,  9, -3, 1 }, { 1, -4, 15, -117,  -30, 10, -4, 1 },
+    { 1, -5, 16, -116,  -32, 11, -4, 1 }, { 1, -5, 16, -114,  -35, 12, -4, 1 },
+    { 1, -5, 17, -112,  -38, 12, -4, 1 }, { 1, -5, 18, -111,  -40, 13, -5, 1 },
+    { 1, -5, 18, -109,  -43, 14, -5, 1 }, { 1, -6, 19, -107,  -45, 14, -5, 1 },
+    { 1, -6, 19, -105,  -48, 15, -5, 1 }, { 1, -6, 19, -103,  -51, 16, -5, 1 },
+    { 1, -6, 20, -101,  -53, 16, -6, 1 }, { 1, -6, 20,  -99,  -56, 17, -6, 1 },
+    { 1, -6, 20,  -97,  -58, 17, -6, 1 }, { 1, -6, 20,  -95,  -61, 18, -6, 1 },
+    { 2, -7, 20,  -93,  -64, 18, -6, 2 }, { 2, -7, 20,  -91,  -66, 19, -6, 1 },
+    { 2, -7, 20,  -88,  -69, 19, -6, 1 }, { 2, -7, 20,  -86,  -71, 19, -6, 1 },
+    { 2, -7, 20,  -84,  -74, 20, -7, 2 }, { 2, -7, 20,  -81,  -76, 20, -7, 1 },
+    { 2, -7, 20,  -79,  -79, 20, -7, 2 }, { 1, -7, 20,  -76,  -81, 20, -7, 2 },
+    { 2, -7, 20,  -74,  -84, 20, -7, 2 }, { 1, -6, 19,  -71,  -86, 20, -7, 2 },
+    { 1, -6, 19,  -69,  -88, 20, -7, 2 }, { 1, -6, 19,  -66,  -91, 20, -7, 2 },
+    { 2, -6, 18,  -64,  -93, 20, -7, 2 }, { 1, -6, 18,  -61,  -95, 20, -6, 1 },
+    { 1, -6, 17,  -58,  -97, 20, -6, 1 }, { 1, -6, 17,  -56,  -99, 20, -6, 1 },
+    { 1, -6, 16,  -53, -101, 20, -6, 1 }, { 1, -5, 16,  -51, -103, 19, -6, 1 },
+    { 1, -5, 15,  -48, -105, 19, -6, 1 }, { 1, -5, 14,  -45, -107, 19, -6, 1 },
+    { 1, -5, 14,  -43, -109, 18, -5, 1 }, { 1, -5, 13,  -40, -111, 18, -5, 1 },
+    { 1, -4, 12,  -38, -112, 17, -5, 1 }, { 1, -4, 12,  -35, -114, 16, -5, 1 },
+    { 1, -4, 11,  -32, -116, 16, -5, 1 }, { 1, -4, 10,  -30, -117, 15, -4, 1 },
+    { 1, -3,  9,  -28, -118, 14, -4, 1 }, { 1, -3,  9,  -25, -120, 13, -4, 1 },
+    { 1, -3,  8,  -22, -121, 12, -4, 1 }, { 1, -3,  7,  -20, -122, 11, -3, 1 },
+    { 1, -2,  6,  -18, -123, 10, -3, 1 }, { 0, -2,  6,  -15, -124,  9, -3, 1 },
+    { 0, -2,  5,  -13, -125,  8, -2, 1 }, { 0, -1,  4,  -11, -125,  7, -2, 0 },
+    { 0, -1,  3,   -8, -126,  6, -2, 0 }, { 0, -1,  3,   -6, -127,  4, -1, 0 },
+    { 0, -1,  2,   -4, -127,  3, -1, 0 }, { 0,  0,  1,   -2, -128,  1,  0, 0 },
+};
+
+const uint8_t ALIGN(dav1d_sm_weights[128], 16) = {
+    // Unused, because we always offset by bs, which is at least 2.
+      0,   0,
+    // bs = 2
+    255, 128,
+    // bs = 4
+    255, 149,  85,  64,
+    // bs = 8
+    255, 197, 146, 105,  73,  50,  37,  32,
+    // bs = 16
+    255, 225, 196, 170, 145, 123, 102,  84,
+     68,  54,  43,  33,  26,  20,  17,  16,
+    // bs = 32
+    255, 240, 225, 210, 196, 182, 169, 157,
+    145, 133, 122, 111, 101,  92,  83,  74,
+     66,  59,  52,  45,  39,  34,  29,  25,
+     21,  17,  14,  12,  10,   9,   8,   8,
+    // bs = 64
+    255, 248, 240, 233, 225, 218, 210, 203,
+    196, 189, 182, 176, 169, 163, 156, 150,
+    144, 138, 133, 127, 121, 116, 111, 106,
+    101,  96,  91,  86,  82,  77,  73,  69,
+     65,  61,  57,  54,  50,  47,  44,  41,
+     38,  35,  32,  29,  27,  25,  22,  20,
+     18,  16,  15,  13,  12,  10,   9,   8,
+      7,   6,   6,   5,   5,   4,   4,   4
+};
+
+ATTR_MCMODEL_SMALL
+const uint16_t dav1d_dr_intra_derivative[44] = {
+    // Values that are 0 will never be used
+          0,    // Angles:
+    1023, 0,    //  3,  93, 183
+     547,       //  6,  96, 186
+     372, 0, 0, //  9,  99, 189
+     273,       // 14, 104, 194
+     215, 0,    // 17, 107, 197
+     178,       // 20, 110, 200
+     151, 0,    // 23, 113, 203 (113 & 203 are base angles)
+     132,       // 26, 116, 206
+     116, 0,    // 29, 119, 209
+     102, 0,    // 32, 122, 212
+      90,       // 36, 126, 216
+      80, 0,    // 39, 129, 219
+      71,       // 42, 132, 222
+      64, 0,    // 45, 135, 225 (45 & 135 are base angles)
+      57,       // 48, 138, 228
+      51, 0,    // 51, 141, 231
+      45, 0,    // 54, 144, 234
+      40,       // 58, 148, 238
+      35, 0,    // 61, 151, 241
+      31,       // 64, 154, 244
+      27, 0,    // 67, 157, 247 (67 & 157 are base angles)
+      23,       // 70, 160, 250
+      19, 0,    // 73, 163, 253
+      15, 0,    // 76, 166, 256
+      11, 0,    // 81, 171, 261
+       7,       // 84, 174, 264
+       3        // 87, 177, 267
+};
+
+#if ARCH_X86
+#define F(idx, f0, f1, f2, f3, f4, f5, f6) \
+    [2*idx+0]  = f0, [2*idx+1]  = f1,      \
+    [2*idx+16] = f2, [2*idx+17] = f3,      \
+    [2*idx+32] = f4, [2*idx+33] = f5,      \
+    [2*idx+48] = f6
+#else
+#define F(idx, f0, f1, f2, f3, f4, f5, f6) \
+    [1*idx+0]  = f0, [1*idx+8]  = f1,      \
+    [1*idx+16] = f2, [1*idx+24] = f3,      \
+    [1*idx+32] = f4, [1*idx+40] = f5,      \
+    [1*idx+48] = f6
+#endif
+ATTR_MCMODEL_SMALL
+const int8_t ALIGN(dav1d_filter_intra_taps[5][64], 64) = {
+    {
+        F( 0,  -6, 10,  0,  0,  0, 12,  0 ),
+        F( 1,  -5,  2, 10,  0,  0,  9,  0 ),
+        F( 2,  -3,  1,  1, 10,  0,  7,  0 ),
+        F( 3,  -3,  1,  1,  2, 10,  5,  0 ),
+        F( 4,  -4,  6,  0,  0,  0,  2, 12 ),
+        F( 5,  -3,  2,  6,  0,  0,  2,  9 ),
+        F( 6,  -3,  2,  2,  6,  0,  2,  7 ),
+        F( 7,  -3,  1,  2,  2,  6,  3,  5 ),
+    }, {
+        F( 0, -10, 16,  0,  0,  0, 10,  0 ),
+        F( 1,  -6,  0, 16,  0,  0,  6,  0 ),
+        F( 2,  -4,  0,  0, 16,  0,  4,  0 ),
+        F( 3,  -2,  0,  0,  0, 16,  2,  0 ),
+        F( 4, -10, 16,  0,  0,  0,  0, 10 ),
+        F( 5,  -6,  0, 16,  0,  0,  0,  6 ),
+        F( 6,  -4,  0,  0, 16,  0,  0,  4 ),
+        F( 7,  -2,  0,  0,  0, 16,  0,  2 ),
+    }, {
+        F( 0,  -8,  8,  0,  0,  0, 16,  0 ),
+        F( 1,  -8,  0,  8,  0,  0, 16,  0 ),
+        F( 2,  -8,  0,  0,  8,  0, 16,  0 ),
+        F( 3,  -8,  0,  0,  0,  8, 16,  0 ),
+        F( 4,  -4,  4,  0,  0,  0,  0, 16 ),
+        F( 5,  -4,  0,  4,  0,  0,  0, 16 ),
+        F( 6,  -4,  0,  0,  4,  0,  0, 16 ),
+        F( 7,  -4,  0,  0,  0,  4,  0, 16 ),
+    }, {
+        F( 0,  -2,  8,  0,  0,  0, 10,  0 ),
+        F( 1,  -1,  3,  8,  0,  0,  6,  0 ),
+        F( 2,  -1,  2,  3,  8,  0,  4,  0 ),
+        F( 3,   0,  1,  2,  3,  8,  2,  0 ),
+        F( 4,  -1,  4,  0,  0,  0,  3, 10 ),
+        F( 5,  -1,  3,  4,  0,  0,  4,  6 ),
+        F( 6,  -1,  2,  3,  4,  0,  4,  4 ),
+        F( 7,  -1,  2,  2,  3,  4,  3,  3 ),
+    }, {
+        F( 0, -12, 14,  0,  0,  0, 14,  0 ),
+        F( 1, -10,  0, 14,  0,  0, 12,  0 ),
+        F( 2,  -9,  0,  0, 14,  0, 11,  0 ),
+        F( 3,  -8,  0,  0,  0, 14, 10,  0 ),
+        F( 4, -10, 12,  0,  0,  0,  0, 14 ),
+        F( 5,  -9,  1, 12,  0,  0,  0, 12 ),
+        F( 6,  -8,  0,  0, 12,  0,  1, 11 ),
+        F( 7,  -7,  0,  0,  1, 12,  1,  9 ),
+    }
+};
+
+const uint8_t ALIGN(dav1d_obmc_masks[64], 16) = {
+    /* Unused */
+     0,  0,
+    /* 2 */
+    19,  0,
+    /* 4 */
+    25, 14,  5,  0,
+    /* 8 */
+    28, 22, 16, 11,  7,  3,  0,  0,
+    /* 16 */
+    30, 27, 24, 21, 18, 15, 12, 10,  8,  6,  4,  3,  0,  0,  0,  0,
+    /* 32 */
+    31, 29, 28, 26, 24, 23, 21, 20, 19, 17, 16, 14, 13, 12, 11,  9,
+     8,  7,  6,  5,  4,  4,  3,  2,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+// Taken from the spec. Range is [-2048, 2047], mean is 0 and stddev is 512
+ATTR_MCMODEL_SMALL
+const int16_t dav1d_gaussian_sequence[2048] = {
+    56,    568,   -180,  172,   124,   -84,   172,   -64,   -900,  24,   820,
+    224,   1248,  996,   272,   -8,    -916,  -388,  -732,  -104,  -188, 800,
+    112,   -652,  -320,  -376,  140,   -252,  492,   -168,  44,    -788, 588,
+    -584,  500,   -228,  12,    680,   272,   -476,  972,   -100,  652,  368,
+    432,   -196,  -720,  -192,  1000,  -332,  652,   -136,  -552,  -604, -4,
+    192,   -220,  -136,  1000,  -52,   372,   -96,   -624,  124,   -24,  396,
+    540,   -12,   -104,  640,   464,   244,   -208,  -84,   368,   -528, -740,
+    248,   -968,  -848,  608,   376,   -60,   -292,  -40,   -156,  252,  -292,
+    248,   224,   -280,  400,   -244,  244,   -60,   76,    -80,   212,  532,
+    340,   128,   -36,   824,   -352,  -60,   -264,  -96,   -612,  416,  -704,
+    220,   -204,  640,   -160,  1220,  -408,  900,   336,   20,    -336, -96,
+    -792,  304,   48,    -28,   -1232, -1172, -448,  104,   -292,  -520, 244,
+    60,    -948,  0,     -708,  268,   108,   356,   -548,  488,   -344, -136,
+    488,   -196,  -224,  656,   -236,  -1128, 60,    4,     140,   276,  -676,
+    -376,  168,   -108,  464,   8,     564,   64,    240,   308,   -300, -400,
+    -456,  -136,  56,    120,   -408,  -116,  436,   504,   -232,  328,  844,
+    -164,  -84,   784,   -168,  232,   -224,  348,   -376,  128,   568,  96,
+    -1244, -288,  276,   848,   832,   -360,  656,   464,   -384,  -332, -356,
+    728,   -388,  160,   -192,  468,   296,   224,   140,   -776,  -100, 280,
+    4,     196,   44,    -36,   -648,  932,   16,    1428,  28,    528,  808,
+    772,   20,    268,   88,    -332,  -284,  124,   -384,  -448,  208,  -228,
+    -1044, -328,  660,   380,   -148,  -300,  588,   240,   540,   28,   136,
+    -88,   -436,  256,   296,   -1000, 1400,  0,     -48,   1056,  -136, 264,
+    -528,  -1108, 632,   -484,  -592,  -344,  796,   124,   -668,  -768, 388,
+    1296,  -232,  -188,  -200,  -288,  -4,    308,   100,   -168,  256,  -500,
+    204,   -508,  648,   -136,  372,   -272,  -120,  -1004, -552,  -548, -384,
+    548,   -296,  428,   -108,  -8,    -912,  -324,  -224,  -88,   -112, -220,
+    -100,  996,   -796,  548,   360,   -216,  180,   428,   -200,  -212, 148,
+    96,    148,   284,   216,   -412,  -320,  120,   -300,  -384,  -604, -572,
+    -332,  -8,    -180,  -176,  696,   116,   -88,   628,   76,    44,   -516,
+    240,   -208,  -40,   100,   -592,  344,   -308,  -452,  -228,  20,   916,
+    -1752, -136,  -340,  -804,  140,   40,    512,   340,   248,   184,  -492,
+    896,   -156,  932,   -628,  328,   -688,  -448,  -616,  -752,  -100, 560,
+    -1020, 180,   -800,  -64,   76,    576,   1068,  396,   660,   552,  -108,
+    -28,   320,   -628,  312,   -92,   -92,   -472,  268,   16,    560,  516,
+    -672,  -52,   492,   -100,  260,   384,   284,   292,   304,   -148, 88,
+    -152,  1012,  1064,  -228,  164,   -376,  -684,  592,   -392,  156,  196,
+    -524,  -64,   -884,  160,   -176,  636,   648,   404,   -396,  -436, 864,
+    424,   -728,  988,   -604,  904,   -592,  296,   -224,  536,   -176, -920,
+    436,   -48,   1176,  -884,  416,   -776,  -824,  -884,  524,   -548, -564,
+    -68,   -164,  -96,   692,   364,   -692,  -1012, -68,   260,   -480, 876,
+    -1116, 452,   -332,  -352,  892,   -1088, 1220,  -676,  12,    -292, 244,
+    496,   372,   -32,   280,   200,   112,   -440,  -96,   24,    -644, -184,
+    56,    -432,  224,   -980,  272,   -260,  144,   -436,  420,   356,  364,
+    -528,  76,    172,   -744,  -368,  404,   -752,  -416,  684,   -688, 72,
+    540,   416,   92,    444,   480,   -72,   -1416, 164,   -1172, -68,  24,
+    424,   264,   1040,  128,   -912,  -524,  -356,  64,    876,   -12,  4,
+    -88,   532,   272,   -524,  320,   276,   -508,  940,   24,    -400, -120,
+    756,   60,    236,   -412,  100,   376,   -484,  400,   -100,  -740, -108,
+    -260,  328,   -268,  224,   -200,  -416,  184,   -604,  -564,  -20,  296,
+    60,    892,   -888,  60,    164,   68,    -760,  216,   -296,  904,  -336,
+    -28,   404,   -356,  -568,  -208,  -1480, -512,  296,   328,   -360, -164,
+    -1560, -776,  1156,  -428,  164,   -504,  -112,  120,   -216,  -148, -264,
+    308,   32,    64,    -72,   72,    116,   176,   -64,   -272,  460,  -536,
+    -784,  -280,  348,   108,   -752,  -132,  524,   -540,  -776,  116,  -296,
+    -1196, -288,  -560,  1040,  -472,  116,   -848,  -1116, 116,   636,  696,
+    284,   -176,  1016,  204,   -864,  -648,  -248,  356,   972,   -584, -204,
+    264,   880,   528,   -24,   -184,  116,   448,   -144,  828,   524,  212,
+    -212,  52,    12,    200,   268,   -488,  -404,  -880,  824,   -672, -40,
+    908,   -248,  500,   716,   -576,  492,   -576,  16,    720,   -108, 384,
+    124,   344,   280,   576,   -500,  252,   104,   -308,  196,   -188, -8,
+    1268,  296,   1032,  -1196, 436,   316,   372,   -432,  -200,  -660, 704,
+    -224,  596,   -132,  268,   32,    -452,  884,   104,   -1008, 424,  -1348,
+    -280,  4,     -1168, 368,   476,   696,   300,   -8,    24,    180,  -592,
+    -196,  388,   304,   500,   724,   -160,  244,   -84,   272,   -256, -420,
+    320,   208,   -144,  -156,  156,   364,   452,   28,    540,   316,  220,
+    -644,  -248,  464,   72,    360,   32,    -388,  496,   -680,  -48,  208,
+    -116,  -408,  60,    -604,  -392,  548,   -840,  784,   -460,  656,  -544,
+    -388,  -264,  908,   -800,  -628,  -612,  -568,  572,   -220,  164,  288,
+    -16,   -308,  308,   -112,  -636,  -760,  280,   -668,  432,   364,  240,
+    -196,  604,   340,   384,   196,   592,   -44,   -500,  432,   -580, -132,
+    636,   -76,   392,   4,     -412,  540,   508,   328,   -356,  -36,  16,
+    -220,  -64,   -248,  -60,   24,    -192,  368,   1040,  92,    -24,  -1044,
+    -32,   40,    104,   148,   192,   -136,  -520,  56,    -816,  -224, 732,
+    392,   356,   212,   -80,   -424,  -1008, -324,  588,   -1496, 576,  460,
+    -816,  -848,  56,    -580,  -92,   -1372, -112,  -496,  200,   364,  52,
+    -140,  48,    -48,   -60,   84,    72,    40,    132,   -356,  -268, -104,
+    -284,  -404,  732,   -520,  164,   -304,  -540,  120,   328,   -76,  -460,
+    756,   388,   588,   236,   -436,  -72,   -176,  -404,  -316,  -148, 716,
+    -604,  404,   -72,   -88,   -888,  -68,   944,   88,    -220,  -344, 960,
+    472,   460,   -232,  704,   120,   832,   -228,  692,   -508,  132,  -476,
+    844,   -748,  -364,  -44,   1116,  -1104, -1056, 76,    428,   552,  -692,
+    60,    356,   96,    -384,  -188,  -612,  -576,  736,   508,   892,  352,
+    -1132, 504,   -24,   -352,  324,   332,   -600,  -312,  292,   508,  -144,
+    -8,    484,   48,    284,   -260,  -240,  256,   -100,  -292,  -204, -44,
+    472,   -204,  908,   -188,  -1000, -256,  92,    1164,  -392,  564,  356,
+    652,   -28,   -884,  256,   484,   -192,  760,   -176,  376,   -524, -452,
+    -436,  860,   -736,  212,   124,   504,   -476,  468,   76,    -472, 552,
+    -692,  -944,  -620,  740,   -240,  400,   132,   20,    192,   -196, 264,
+    -668,  -1012, -60,   296,   -316,  -828,  76,    -156,  284,   -768, -448,
+    -832,  148,   248,   652,   616,   1236,  288,   -328,  -400,  -124, 588,
+    220,   520,   -696,  1032,  768,   -740,  -92,   -272,  296,   448,  -464,
+    412,   -200,  392,   440,   -200,  264,   -152,  -260,  320,   1032, 216,
+    320,   -8,    -64,   156,   -1016, 1084,  1172,  536,   484,   -432, 132,
+    372,   -52,   -256,  84,    116,   -352,  48,    116,   304,   -384, 412,
+    924,   -300,  528,   628,   180,   648,   44,    -980,  -220,  1320, 48,
+    332,   748,   524,   -268,  -720,  540,   -276,  564,   -344,  -208, -196,
+    436,   896,   88,    -392,  132,   80,    -964,  -288,  568,   56,   -48,
+    -456,  888,   8,     552,   -156,  -292,  948,   288,   128,   -716, -292,
+    1192,  -152,  876,   352,   -600,  -260,  -812,  -468,  -28,   -120, -32,
+    -44,   1284,  496,   192,   464,   312,   -76,   -516,  -380,  -456, -1012,
+    -48,   308,   -156,  36,    492,   -156,  -808,  188,   1652,  68,   -120,
+    -116,  316,   160,   -140,  352,   808,   -416,  592,   316,   -480, 56,
+    528,   -204,  -568,  372,   -232,  752,   -344,  744,   -4,    324,  -416,
+    -600,  768,   268,   -248,  -88,   -132,  -420,  -432,  80,    -288, 404,
+    -316,  -1216, -588,  520,   -108,  92,    -320,  368,   -480,  -216, -92,
+    1688,  -300,  180,   1020,  -176,  820,   -68,   -228,  -260,  436,  -904,
+    20,    40,    -508,  440,   -736,  312,   332,   204,   760,   -372, 728,
+    96,    -20,   -632,  -520,  -560,  336,   1076,  -64,   -532,  776,  584,
+    192,   396,   -728,  -520,  276,   -188,  80,    -52,   -612,  -252, -48,
+    648,   212,   -688,  228,   -52,   -260,  428,   -412,  -272,  -404, 180,
+    816,   -796,  48,    152,   484,   -88,   -216,  988,   696,   188,  -528,
+    648,   -116,  -180,  316,   476,   12,    -564,  96,    476,   -252, -364,
+    -376,  -392,  556,   -256,  -576,  260,   -352,  120,   -16,   -136, -260,
+    -492,  72,    556,   660,   580,   616,   772,   436,   424,   -32,  -324,
+    -1268, 416,   -324,  -80,   920,   160,   228,   724,   32,    -516, 64,
+    384,   68,    -128,  136,   240,   248,   -204,  -68,   252,   -932, -120,
+    -480,  -628,  -84,   192,   852,   -404,  -288,  -132,  204,   100,  168,
+    -68,   -196,  -868,  460,   1080,  380,   -80,   244,   0,     484,  -888,
+    64,    184,   352,   600,   460,   164,   604,   -196,  320,   -64,  588,
+    -184,  228,   12,    372,   48,    -848,  -344,  224,   208,   -200, 484,
+    128,   -20,   272,   -468,  -840,  384,   256,   -720,  -520,  -464, -580,
+    112,   -120,  644,   -356,  -208,  -608,  -528,  704,   560,   -424, 392,
+    828,   40,    84,    200,   -152,  0,     -144,  584,   280,   -120, 80,
+    -556,  -972,  -196,  -472,  724,   80,    168,   -32,   88,    160,  -688,
+    0,     160,   356,   372,   -776,  740,   -128,  676,   -248,  -480, 4,
+    -364,  96,    544,   232,   -1032, 956,   236,   356,   20,    -40,  300,
+    24,    -676,  -596,  132,   1120,  -104,  532,   -1096, 568,   648,  444,
+    508,   380,   188,   -376,  -604,  1488,  424,   24,    756,   -220, -192,
+    716,   120,   920,   688,   168,   44,    -460,  568,   284,   1144, 1160,
+    600,   424,   888,   656,   -356,  -320,  220,   316,   -176,  -724, -188,
+    -816,  -628,  -348,  -228,  -380,  1012,  -452,  -660,  736,   928,  404,
+    -696,  -72,   -268,  -892,  128,   184,   -344,  -780,  360,   336,  400,
+    344,   428,   548,   -112,  136,   -228,  -216,  -820,  -516,  340,  92,
+    -136,  116,   -300,  376,   -244,  100,   -316,  -520,  -284,  -12,  824,
+    164,   -548,  -180,  -128,  116,   -924,  -828,  268,   -368,  -580, 620,
+    192,   160,   0,     -1676, 1068,  424,   -56,   -360,  468,   -156, 720,
+    288,   -528,  556,   -364,  548,   -148,  504,   316,   152,   -648, -620,
+    -684,  -24,   -376,  -384,  -108,  -920,  -1032, 768,   180,   -264, -508,
+    -1268, -260,  -60,   300,   -240,  988,   724,   -376,  -576,  -212, -736,
+    556,   192,   1092,  -620,  -880,  376,   -56,   -4,    -216,  -32,  836,
+    268,   396,   1332,  864,   -600,  100,   56,    -412,  -92,   356,  180,
+    884,   -468,  -436,  292,   -388,  -804,  -704,  -840,  368,   -348, 140,
+    -724,  1536,  940,   372,   112,   -372,  436,   -480,  1136,  296,  -32,
+    -228,  132,   -48,   -220,  868,   -1016, -60,   -1044, -464,  328,  916,
+    244,   12,    -736,  -296,  360,   468,   -376,  -108,  -92,   788,  368,
+    -56,   544,   400,   -672,  -420,  728,   16,    320,   44,    -284, -380,
+    -796,  488,   132,   204,   -596,  -372,  88,    -152,  -908,  -636, -572,
+    -624,  -116,  -692,  -200,  -56,   276,   -88,   484,   -324,  948,  864,
+    1000,  -456,  -184,  -276,  292,   -296,  156,   676,   320,   160,  908,
+    -84,   -1236, -288,  -116,  260,   -372,  -644,  732,   -756,  -96,  84,
+    344,   -520,  348,   -688,  240,   -84,   216,   -1044, -136,  -676, -396,
+    -1500, 960,   -40,   176,   168,   1516,  420,   -504,  -344,  -364, -360,
+    1216,  -940,  -380,  -212,  252,   -660,  -708,  484,   -444,  -152, 928,
+    -120,  1112,  476,   -260,  560,   -148,  -344,  108,   -196,  228,  -288,
+    504,   560,   -328,  -88,   288,   -1008, 460,   -228,  468,   -836, -196,
+    76,    388,   232,   412,   -1168, -716,  -644,  756,   -172,  -356, -504,
+    116,   432,   528,   48,    476,   -168,  -608,  448,   160,   -532, -272,
+    28,    -676,  -12,   828,   980,   456,   520,   104,   -104,  256,  -344,
+    -4,    -28,   -368,  -52,   -524,  -572,  -556,  -200,  768,   1124, -208,
+    -512,  176,   232,   248,   -148,  -888,  604,   -600,  -304,  804,  -156,
+    -212,  488,   -192,  -804,  -256,  368,   -360,  -916,  -328,  228,  -240,
+    -448,  -472,  856,   -556,  -364,  572,   -12,   -156,  -368,  -340, 432,
+    252,   -752,  -152,  288,   268,   -580,  -848,  -592,  108,   -76,  244,
+    312,   -716,  592,   -80,   436,   360,   4,     -248,  160,   516,  584,
+    732,   44,    -468,  -280,  -292,  -156,  -588,  28,    308,   912,  24,
+    124,   156,   180,   -252,  944,   -924,  -772,  -520,  -428,  -624, 300,
+    -212,  -1144, 32,    -724,  800,   -1128, -212,  -1288, -848,  180,  -416,
+    440,   192,   -576,  -792,  -76,   -1080, 80,    -532,  -352,  -132, 380,
+    -820,  148,   1112,  128,   164,   456,   700,   -924,  144,   -668, -384,
+    648,   -832,  508,   552,   -52,   -100,  -656,  208,   -568,  748,  -88,
+    680,   232,   300,   192,   -408,  -1012, -152,  -252,  -268,  272,  -876,
+    -664,  -648,  -332,  -136,  16,    12,    1152,  -28,   332,   -536, 320,
+    -672,  -460,  -316,  532,   -260,  228,   -40,   1052,  -816,  180,  88,
+    -496,  -556,  -672,  -368,  428,   92,    356,   404,   -408,  252,  196,
+    -176,  -556,  792,   268,   32,    372,   40,    96,    -332,  328,  120,
+    372,   -900,  -40,   472,   -264,  -592,  952,   128,   656,   112,  664,
+    -232,  420,   4,     -344,  -464,  556,   244,   -416,  -32,   252,  0,
+    -412,  188,   -696,  508,   -476,  324,   -1096, 656,   -312,  560,  264,
+    -136,  304,   160,   -64,   -580,  248,   336,   -720,  560,   -348, -288,
+    -276,  -196,  -500,  852,   -544,  -236,  -1128, -992,  -776,  116,  56,
+    52,    860,   884,   212,   -12,   168,   1020,  512,   -552,  924,  -148,
+    716,   188,   164,   -340,  -520,  -184,  880,   -152,  -680,  -208, -1156,
+    -300,  -528,  -472,  364,   100,   -744,  -1056, -32,   540,   280,  144,
+    -676,  -32,   -232,  -280,  -224,  96,    568,   -76,   172,   148,  148,
+    104,   32,    -296,  -32,   788,   -80,   32,    -16,   280,   288,  944,
+    428,   -484
+};
diff --git a/media/libdav1d/src/src/tables.h b/media/libdav1d/src/src/tables.h
new file mode 100644
index 0000000000..f3c00cfb00
--- /dev/null
+++ b/media/libdav1d/src/src/tables.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_TABLES_H
+#define DAV1D_SRC_TABLES_H
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/levels.h"
+
+EXTERN const uint8_t dav1d_al_part_ctx[2][N_BL_LEVELS][N_PARTITIONS];
+EXTERN const uint8_t /* enum BlockSize */
+                     dav1d_block_sizes[N_BL_LEVELS][N_PARTITIONS][2];
+// width, height (in 4px blocks), log2 versions of these two
+EXTERN const uint8_t dav1d_block_dimensions[N_BS_SIZES][4];
+typedef struct TxfmInfo {
+    // width, height (in 4px blocks), log2 of them, min/max of log2, sub, pad
+    uint8_t w, h, lw, lh, min, max, sub, ctx;
+} TxfmInfo;
+EXTERN const TxfmInfo dav1d_txfm_dimensions[N_RECT_TX_SIZES];
+EXTERN const uint8_t /* enum (Rect)TxfmSize */
+                     dav1d_max_txfm_size_for_bs[N_BS_SIZES][4 /* y, 420, 422, 444 */];
+EXTERN const uint8_t /* enum TxfmType */
+                     dav1d_txtp_from_uvmode[N_UV_INTRA_PRED_MODES];
+
+EXTERN const uint8_t /* enum InterPredMode */
+                     dav1d_comp_inter_pred_modes[N_COMP_INTER_PRED_MODES][2];
+
+EXTERN const uint8_t dav1d_partition_type_count[N_BL_LEVELS];
+EXTERN const uint8_t /* enum TxfmType */ dav1d_tx_types_per_set[40];
+
+EXTERN const uint8_t dav1d_filter_mode_to_y_mode[5];
+EXTERN const uint8_t dav1d_ymode_size_context[N_BS_SIZES];
+EXTERN const uint8_t dav1d_lo_ctx_offsets[3][5][5];
+EXTERN const uint8_t dav1d_skip_ctx[5][5];
+EXTERN const uint8_t /* enum TxClass */
+                     dav1d_tx_type_class[N_TX_TYPES_PLUS_LL];
+EXTERN const uint8_t /* enum Filter2d */
+                     dav1d_filter_2d[DAV1D_N_FILTERS /* h */][DAV1D_N_FILTERS /* v */];
+EXTERN const uint8_t /* enum Dav1dFilterMode */ dav1d_filter_dir[N_2D_FILTERS][2];
+EXTERN const uint8_t dav1d_intra_mode_context[N_INTRA_PRED_MODES];
+EXTERN const uint8_t dav1d_wedge_ctx_lut[N_BS_SIZES];
+
+static const unsigned cfl_allowed_mask =
+    (1 << BS_32x32) |
+    (1 << BS_32x16) |
+    (1 << BS_32x8) |
+    (1 << BS_16x32) |
+    (1 << BS_16x16) |
+    (1 << BS_16x8) |
+    (1 << BS_16x4) |
+    (1 << BS_8x32) |
+    (1 << BS_8x16) |
+    (1 << BS_8x8) |
+    (1 << BS_8x4) |
+    (1 << BS_4x16) |
+    (1 << BS_4x8) |
+    (1 << BS_4x4);
+
+static const unsigned wedge_allowed_mask =
+    (1 << BS_32x32) |
+    (1 << BS_32x16) |
+    (1 << BS_32x8) |
+    (1 << BS_16x32) |
+    (1 << BS_16x16) |
+    (1 << BS_16x8) |
+    (1 << BS_8x32) |
+    (1 << BS_8x16) |
+    (1 << BS_8x8);
+
+static const unsigned interintra_allowed_mask =
+    (1 << BS_32x32) |
+    (1 << BS_32x16) |
+    (1 << BS_16x32) |
+    (1 << BS_16x16) |
+    (1 << BS_16x8) |
+    (1 << BS_8x16) |
+    (1 << BS_8x8);
+
+EXTERN const Dav1dWarpedMotionParams dav1d_default_wm_params;
+
+EXTERN const int8_t dav1d_cdef_directions[12][2];
+
+EXTERN const uint16_t dav1d_sgr_params[16][2];
+EXTERN const uint8_t dav1d_sgr_x_by_x[256];
+
+EXTERN const int8_t dav1d_mc_subpel_filters[6][15][8];
+EXTERN const int8_t dav1d_mc_warp_filter[193][8];
+EXTERN const int8_t dav1d_resize_filter[64][8];
+
+EXTERN const uint8_t dav1d_sm_weights[128];
+EXTERN const uint16_t dav1d_dr_intra_derivative[44];
+EXTERN const int8_t dav1d_filter_intra_taps[5][64];
+
+EXTERN const uint8_t dav1d_obmc_masks[64];
+
+EXTERN const int16_t dav1d_gaussian_sequence[2048]; // for fgs
+
+#endif /* DAV1D_SRC_TABLES_H */
diff --git a/media/libdav1d/src/src/thread.h b/media/libdav1d/src/src/thread.h
new file mode 100644
index 0000000000..459aaced66
--- /dev/null
+++ b/media/libdav1d/src/src/thread.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_THREAD_H
+#define DAV1D_SRC_THREAD_H
+
+#if defined(_WIN32)
+
+#include 
+#include 
+
+#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT
+#define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT
+
+typedef struct {
+    HANDLE h;
+    void *(*func)(void*);
+    void *arg;
+} pthread_t;
+
+typedef struct {
+    unsigned stack_size;
+} pthread_attr_t;
+
+typedef SRWLOCK pthread_mutex_t;
+typedef CONDITION_VARIABLE pthread_cond_t;
+typedef INIT_ONCE pthread_once_t;
+
+void dav1d_init_thread(void);
+void dav1d_set_thread_name(const wchar_t *name);
+#define dav1d_set_thread_name(name) dav1d_set_thread_name(L##name)
+
+int dav1d_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+                         void *(*func)(void*), void *arg);
+int dav1d_pthread_join(pthread_t *thread, void **res);
+int dav1d_pthread_once(pthread_once_t *once_control,
+                       void (*init_routine)(void));
+
+#define pthread_create dav1d_pthread_create
+#define pthread_join(thread, res) dav1d_pthread_join(&(thread), res)
+#define pthread_once   dav1d_pthread_once
+
+static inline int pthread_attr_init(pthread_attr_t *const attr) {
+    attr->stack_size = 0;
+    return 0;
+}
+
+static inline int pthread_attr_destroy(pthread_attr_t *const attr) {
+    return 0;
+}
+
+static inline int pthread_attr_setstacksize(pthread_attr_t *const attr,
+                                            const size_t stack_size)
+{
+    if (stack_size > UINT_MAX) return 1;
+    attr->stack_size = (unsigned) stack_size;
+    return 0;
+}
+
+static inline int pthread_mutex_init(pthread_mutex_t *const mutex,
+                                     const void *const attr)
+{
+    InitializeSRWLock(mutex);
+    return 0;
+}
+
+static inline int pthread_mutex_destroy(pthread_mutex_t *const mutex) {
+    return 0;
+}
+
+static inline int pthread_mutex_lock(pthread_mutex_t *const mutex) {
+    AcquireSRWLockExclusive(mutex);
+    return 0;
+}
+
+static inline int pthread_mutex_unlock(pthread_mutex_t *const mutex) {
+    ReleaseSRWLockExclusive(mutex);
+    return 0;
+}
+
+static inline int pthread_cond_init(pthread_cond_t *const cond,
+                                    const void *const attr)
+{
+    InitializeConditionVariable(cond);
+    return 0;
+}
+
+static inline int pthread_cond_destroy(pthread_cond_t *const cond) {
+    return 0;
+}
+
+static inline int pthread_cond_wait(pthread_cond_t *const cond,
+                                    pthread_mutex_t *const mutex)
+{
+    return !SleepConditionVariableSRW(cond, mutex, INFINITE, 0);
+}
+
+static inline int pthread_cond_signal(pthread_cond_t *const cond) {
+    WakeConditionVariable(cond);
+    return 0;
+}
+
+static inline int pthread_cond_broadcast(pthread_cond_t *const cond) {
+    WakeAllConditionVariable(cond);
+    return 0;
+}
+
+#else
+
+#include 
+#if defined(__FreeBSD__)
+ /* ALIGN from  conflicts with ALIGN from "common/attributes.h" */
+#define _SYS_PARAM_H_
+#include 
+#endif
+#if HAVE_PTHREAD_NP_H
+#include 
+#endif
+
+#define dav1d_init_thread() do {} while (0)
+
+/* Thread naming support */
+
+#ifdef __linux__
+
+#include 
+
+static inline void dav1d_set_thread_name(const char *const name) {
+    prctl(PR_SET_NAME, name);
+}
+
+#elif HAVE_PTHREAD_SETNAME_NP && defined(__APPLE__)
+
+static inline void dav1d_set_thread_name(const char *const name) {
+    pthread_setname_np(name);
+}
+
+#elif HAVE_PTHREAD_SETNAME_NP && defined(__NetBSD__)
+
+static inline void dav1d_set_thread_name(const char *const name) {
+    pthread_setname_np(pthread_self(), "%s", (void*)name);
+}
+
+#elif HAVE_PTHREAD_SETNAME_NP
+
+static inline void dav1d_set_thread_name(const char *const name) {
+    pthread_setname_np(pthread_self(), name);
+}
+
+#elif HAVE_PTHREAD_SET_NAME_NP
+
+static inline void dav1d_set_thread_name(const char *const name) {
+    pthread_set_name_np(pthread_self(), name);
+}
+
+#elif defined(__HAIKU__)
+
+#include 
+
+static inline void dav1d_set_thread_name(const char *const name) {
+    rename_thread(find_thread(NULL), name);
+}
+
+#else
+
+#define dav1d_set_thread_name(name) do {} while (0)
+
+#endif
+
+#endif
+
+#endif /* DAV1D_SRC_THREAD_H */
diff --git a/media/libdav1d/src/src/thread_data.h b/media/libdav1d/src/src/thread_data.h
new file mode 100644
index 0000000000..62814e6348
--- /dev/null
+++ b/media/libdav1d/src/src/thread_data.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_THREAD_DATA_H
+#define DAV1D_SRC_THREAD_DATA_H
+
+#include "src/thread.h"
+
+struct thread_data {
+    pthread_t thread;
+    pthread_cond_t cond;
+    pthread_mutex_t lock;
+    int inited;
+};
+
+#endif /* DAV1D_SRC_THREAD_DATA_H */
diff --git a/media/libdav1d/src/src/thread_task.c b/media/libdav1d/src/src/thread_task.c
new file mode 100644
index 0000000000..1ededde43c
--- /dev/null
+++ b/media/libdav1d/src/src/thread_task.c
@@ -0,0 +1,936 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "common/frame.h"
+
+#include "src/thread_task.h"
+#include "src/fg_apply.h"
+
+// This function resets the cur pointer to the first frame theoretically
+// executable after a task completed (ie. each time we update some progress or
+// insert some tasks in the queue).
+// When frame_idx is set, it can be either from a completed task, or from tasks
+// inserted in the queue, in which case we have to make sure the cur pointer
+// isn't past this insert.
+// The special case where frame_idx is UINT_MAX is to handle the reset after
+// completing a task and locklessly signaling progress. In this case we don't
+// enter a critical section, which is needed for this function, so we set an
+// atomic for a delayed handling, happening here. Meaning we can call this
+// function without any actual update other than what's in the atomic, hence
+// this special case.
+static inline int reset_task_cur(const Dav1dContext *const c,
+                                 struct TaskThreadData *const ttd,
+                                 unsigned frame_idx)
+{
+    const unsigned first = atomic_load(&ttd->first);
+    unsigned reset_frame_idx = atomic_exchange(&ttd->reset_task_cur, UINT_MAX);
+    if (reset_frame_idx < first) {
+        if (frame_idx == UINT_MAX) return 0;
+        reset_frame_idx = UINT_MAX;
+    }
+    if (!ttd->cur && c->fc[first].task_thread.task_cur_prev == NULL)
+        return 0;
+    if (reset_frame_idx != UINT_MAX) {
+        if (frame_idx == UINT_MAX) {
+            if (reset_frame_idx > first + ttd->cur)
+                return 0;
+            ttd->cur = reset_frame_idx - first;
+            goto cur_found;
+        }
+    } else if (frame_idx == UINT_MAX)
+        return 0;
+    if (frame_idx < first) frame_idx += c->n_fc;
+    const unsigned min_frame_idx = umin(reset_frame_idx, frame_idx);
+    const unsigned cur_frame_idx = first + ttd->cur;
+    if (ttd->cur < c->n_fc && cur_frame_idx < min_frame_idx)
+        return 0;
+    for (ttd->cur = min_frame_idx - first; ttd->cur < c->n_fc; ttd->cur++)
+        if (c->fc[(first + ttd->cur) % c->n_fc].task_thread.task_head)
+            break;
+cur_found:
+    for (unsigned i = ttd->cur; i < c->n_fc; i++)
+        c->fc[(first + i) % c->n_fc].task_thread.task_cur_prev = NULL;
+    return 1;
+}
+
+static inline void reset_task_cur_async(struct TaskThreadData *const ttd,
+                                        unsigned frame_idx, unsigned n_frames)
+{
+    const unsigned first = atomic_load(&ttd->first);
+    if (frame_idx < first) frame_idx += n_frames;
+    unsigned last_idx = frame_idx;
+    do {
+        frame_idx = last_idx;
+        last_idx = atomic_exchange(&ttd->reset_task_cur, frame_idx);
+    } while (last_idx < frame_idx);
+    if (frame_idx == first && atomic_load(&ttd->first) != first) {
+        unsigned expected = frame_idx;
+        atomic_compare_exchange_strong(&ttd->reset_task_cur, &expected, UINT_MAX);
+    }
+}
+
+static void insert_tasks_between(Dav1dFrameContext *const f,
+                                 Dav1dTask *const first, Dav1dTask *const last,
+                                 Dav1dTask *const a, Dav1dTask *const b,
+                                 const int cond_signal)
+{
+    struct TaskThreadData *const ttd = f->task_thread.ttd;
+    if (atomic_load(f->c->flush)) return;
+    assert(!a || a->next == b);
+    if (!a) f->task_thread.task_head = first;
+    else a->next = first;
+    if (!b) f->task_thread.task_tail = last;
+    last->next = b;
+    reset_task_cur(f->c, ttd, first->frame_idx);
+    if (cond_signal && !atomic_fetch_or(&ttd->cond_signaled, 1))
+        pthread_cond_signal(&ttd->cond);
+}
+
+static void insert_tasks(Dav1dFrameContext *const f,
+                         Dav1dTask *const first, Dav1dTask *const last,
+                         const int cond_signal)
+{
+    // insert task back into task queue
+    Dav1dTask *t_ptr, *prev_t = NULL;
+    for (t_ptr = f->task_thread.task_head;
+         t_ptr; prev_t = t_ptr, t_ptr = t_ptr->next)
+    {
+        // entropy coding precedes other steps
+        if (t_ptr->type == DAV1D_TASK_TYPE_TILE_ENTROPY) {
+            if (first->type > DAV1D_TASK_TYPE_TILE_ENTROPY) continue;
+            // both are entropy
+            if (first->sby > t_ptr->sby) continue;
+            if (first->sby < t_ptr->sby) {
+                insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal);
+                return;
+            }
+            // same sby
+        } else {
+            if (first->type == DAV1D_TASK_TYPE_TILE_ENTROPY) {
+                insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal);
+                return;
+            }
+            if (first->sby > t_ptr->sby) continue;
+            if (first->sby < t_ptr->sby) {
+                insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal);
+                return;
+            }
+            // same sby
+            if (first->type > t_ptr->type) continue;
+            if (first->type < t_ptr->type) {
+                insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal);
+                return;
+            }
+            // same task type
+        }
+
+        // sort by tile-id
+        assert(first->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION ||
+               first->type == DAV1D_TASK_TYPE_TILE_ENTROPY);
+        assert(first->type == t_ptr->type);
+        assert(t_ptr->sby == first->sby);
+        const int p = first->type == DAV1D_TASK_TYPE_TILE_ENTROPY;
+        const int t_tile_idx = (int) (first - f->task_thread.tile_tasks[p]);
+        const int p_tile_idx = (int) (t_ptr - f->task_thread.tile_tasks[p]);
+        assert(t_tile_idx != p_tile_idx);
+        if (t_tile_idx > p_tile_idx) continue;
+        insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal);
+        return;
+    }
+    // append at the end
+    insert_tasks_between(f, first, last, prev_t, NULL, cond_signal);
+}
+
+static inline void insert_task(Dav1dFrameContext *const f,
+                               Dav1dTask *const t, const int cond_signal)
+{
+    insert_tasks(f, t, t, cond_signal);
+}
+
+static inline void add_pending(Dav1dFrameContext *const f, Dav1dTask *const t) {
+    pthread_mutex_lock(&f->task_thread.pending_tasks.lock);
+    t->next = NULL;
+    if (!f->task_thread.pending_tasks.head)
+        f->task_thread.pending_tasks.head = t;
+    else
+        f->task_thread.pending_tasks.tail->next = t;
+    f->task_thread.pending_tasks.tail = t;
+    atomic_store(&f->task_thread.pending_tasks.merge, 1);
+    pthread_mutex_unlock(&f->task_thread.pending_tasks.lock);
+}
+
+static inline int merge_pending_frame(Dav1dFrameContext *const f) {
+    int const merge = atomic_load(&f->task_thread.pending_tasks.merge);
+    if (merge) {
+        pthread_mutex_lock(&f->task_thread.pending_tasks.lock);
+        Dav1dTask *t = f->task_thread.pending_tasks.head;
+        f->task_thread.pending_tasks.head = NULL;
+        f->task_thread.pending_tasks.tail = NULL;
+        atomic_store(&f->task_thread.pending_tasks.merge, 0);
+        pthread_mutex_unlock(&f->task_thread.pending_tasks.lock);
+        while (t) {
+            Dav1dTask *const tmp = t->next;
+            insert_task(f, t, 0);
+            t = tmp;
+        }
+    }
+    return merge;
+}
+
+static inline int merge_pending(const Dav1dContext *const c) {
+    int res = 0;
+    for (unsigned i = 0; i < c->n_fc; i++)
+        res |= merge_pending_frame(&c->fc[i]);
+    return res;
+}
+
+static int create_filter_sbrow(Dav1dFrameContext *const f,
+                               const int pass, Dav1dTask **res_t)
+{
+    const int has_deblock = f->frame_hdr->loopfilter.level_y[0] ||
+                            f->frame_hdr->loopfilter.level_y[1];
+    const int has_cdef = f->seq_hdr->cdef;
+    const int has_resize = f->frame_hdr->width[0] != f->frame_hdr->width[1];
+    const int has_lr = f->lf.restore_planes;
+
+    Dav1dTask *tasks = f->task_thread.tasks;
+    const int uses_2pass = f->c->n_fc > 1;
+    int num_tasks = f->sbh * (1 + uses_2pass);
+    if (num_tasks > f->task_thread.num_tasks) {
+        const size_t size = sizeof(Dav1dTask) * num_tasks;
+        tasks = dav1d_realloc(ALLOC_COMMON_CTX, f->task_thread.tasks, size);
+        if (!tasks) return -1;
+        memset(tasks, 0, size);
+        f->task_thread.tasks = tasks;
+        f->task_thread.num_tasks = num_tasks;
+    }
+    tasks += f->sbh * (pass & 1);
+
+    if (pass & 1) {
+        f->frame_thread.entropy_progress = 0;
+    } else {
+        const int prog_sz = ((f->sbh + 31) & ~31) >> 5;
+        if (prog_sz > f->frame_thread.prog_sz) {
+            atomic_uint *const prog = dav1d_realloc(ALLOC_COMMON_CTX, f->frame_thread.frame_progress,
+                                                    2 * prog_sz * sizeof(*prog));
+            if (!prog) return -1;
+            f->frame_thread.frame_progress = prog;
+            f->frame_thread.copy_lpf_progress = prog + prog_sz;
+        }
+        f->frame_thread.prog_sz = prog_sz;
+        memset(f->frame_thread.frame_progress, 0, prog_sz * sizeof(atomic_uint));
+        memset(f->frame_thread.copy_lpf_progress, 0, prog_sz * sizeof(atomic_uint));
+        atomic_store(&f->frame_thread.deblock_progress, 0);
+    }
+    f->frame_thread.next_tile_row[pass & 1] = 0;
+
+    Dav1dTask *t = &tasks[0];
+    t->sby = 0;
+    t->recon_progress = 1;
+    t->deblock_progress = 0;
+    t->type = pass == 1 ? DAV1D_TASK_TYPE_ENTROPY_PROGRESS :
+              has_deblock ? DAV1D_TASK_TYPE_DEBLOCK_COLS :
+              has_cdef || has_lr /* i.e. LR backup */ ? DAV1D_TASK_TYPE_DEBLOCK_ROWS :
+              has_resize ? DAV1D_TASK_TYPE_SUPER_RESOLUTION :
+              DAV1D_TASK_TYPE_RECONSTRUCTION_PROGRESS;
+    t->frame_idx = (int)(f - f->c->fc);
+
+    *res_t = t;
+    return 0;
+}
+
+int dav1d_task_create_tile_sbrow(Dav1dFrameContext *const f, const int pass,
+                                 const int cond_signal)
+{
+    Dav1dTask *tasks = f->task_thread.tile_tasks[0];
+    const int uses_2pass = f->c->n_fc > 1;
+    const int num_tasks = f->frame_hdr->tiling.cols * f->frame_hdr->tiling.rows;
+    if (pass < 2) {
+        int alloc_num_tasks = num_tasks * (1 + uses_2pass);
+        if (alloc_num_tasks > f->task_thread.num_tile_tasks) {
+            const size_t size = sizeof(Dav1dTask) * alloc_num_tasks;
+            tasks = dav1d_realloc(ALLOC_COMMON_CTX, f->task_thread.tile_tasks[0], size);
+            if (!tasks) return -1;
+            memset(tasks, 0, size);
+            f->task_thread.tile_tasks[0] = tasks;
+            f->task_thread.num_tile_tasks = alloc_num_tasks;
+        }
+        f->task_thread.tile_tasks[1] = tasks + num_tasks;
+    }
+    tasks += num_tasks * (pass & 1);
+
+    Dav1dTask *pf_t;
+    if (create_filter_sbrow(f, pass, &pf_t))
+        return -1;
+
+    Dav1dTask *prev_t = NULL;
+    for (int tile_idx = 0; tile_idx < num_tasks; tile_idx++) {
+        Dav1dTileState *const ts = &f->ts[tile_idx];
+        Dav1dTask *t = &tasks[tile_idx];
+        t->sby = ts->tiling.row_start >> f->sb_shift;
+        if (pf_t && t->sby) {
+            prev_t->next = pf_t;
+            prev_t = pf_t;
+            pf_t = NULL;
+        }
+        t->recon_progress = 0;
+        t->deblock_progress = 0;
+        t->deps_skip = 0;
+        t->type = pass != 1 ? DAV1D_TASK_TYPE_TILE_RECONSTRUCTION :
+                              DAV1D_TASK_TYPE_TILE_ENTROPY;
+        t->frame_idx = (int)(f - f->c->fc);
+        if (prev_t) prev_t->next = t;
+        prev_t = t;
+    }
+    if (pf_t) {
+        prev_t->next = pf_t;
+        prev_t = pf_t;
+    }
+    prev_t->next = NULL;
+
+    atomic_store(&f->task_thread.done[pass & 1], 0);
+
+    // XXX in theory this could be done locklessly, at this point they are no
+    // tasks in the frameQ, so no other runner should be using this lock, but
+    // we must add both passes at once
+    pthread_mutex_lock(&f->task_thread.pending_tasks.lock);
+    assert(f->task_thread.pending_tasks.head == NULL || pass == 2);
+    if (!f->task_thread.pending_tasks.head)
+        f->task_thread.pending_tasks.head = &tasks[0];
+    else
+        f->task_thread.pending_tasks.tail->next = &tasks[0];
+    f->task_thread.pending_tasks.tail = prev_t;
+    atomic_store(&f->task_thread.pending_tasks.merge, 1);
+    atomic_store(&f->task_thread.init_done, 1);
+    pthread_mutex_unlock(&f->task_thread.pending_tasks.lock);
+
+    return 0;
+}
+
+void dav1d_task_frame_init(Dav1dFrameContext *const f) {
+    const Dav1dContext *const c = f->c;
+
+    atomic_store(&f->task_thread.init_done, 0);
+    // schedule init task, which will schedule the remaining tasks
+    Dav1dTask *const t = &f->task_thread.init_task;
+    t->type = DAV1D_TASK_TYPE_INIT;
+    t->frame_idx = (int)(f - c->fc);
+    t->sby = 0;
+    t->recon_progress = t->deblock_progress = 0;
+    insert_task(f, t, 1);
+}
+
+void dav1d_task_delayed_fg(Dav1dContext *const c, Dav1dPicture *const out,
+                           const Dav1dPicture *const in)
+{
+    struct TaskThreadData *const ttd = &c->task_thread;
+    ttd->delayed_fg.in = in;
+    ttd->delayed_fg.out = out;
+    ttd->delayed_fg.type = DAV1D_TASK_TYPE_FG_PREP;
+    atomic_init(&ttd->delayed_fg.progress[0], 0);
+    atomic_init(&ttd->delayed_fg.progress[1], 0);
+    pthread_mutex_lock(&ttd->lock);
+    ttd->delayed_fg.exec = 1;
+    ttd->delayed_fg.finished = 0;
+    pthread_cond_signal(&ttd->cond);
+    do {
+        pthread_cond_wait(&ttd->delayed_fg.cond, &ttd->lock);
+    } while (!ttd->delayed_fg.finished);
+    pthread_mutex_unlock(&ttd->lock);
+}
+
+static inline int ensure_progress(struct TaskThreadData *const ttd,
+                                  Dav1dFrameContext *const f,
+                                  Dav1dTask *const t, const enum TaskType type,
+                                  atomic_int *const state, int *const target)
+{
+    // deblock_rows (non-LR portion) depends on deblock of previous sbrow,
+    // so ensure that completed. if not, re-add to task-queue; else, fall-through
+    int p1 = atomic_load(state);
+    if (p1 < t->sby) {
+        t->type = type;
+        t->recon_progress = t->deblock_progress = 0;
+        *target = t->sby;
+        add_pending(f, t);
+        pthread_mutex_lock(&ttd->lock);
+        return 1;
+    }
+    return 0;
+}
+
+static inline int check_tile(Dav1dTask *const t, Dav1dFrameContext *const f,
+                             const int frame_mt)
+{
+    const int tp = t->type == DAV1D_TASK_TYPE_TILE_ENTROPY;
+    const int tile_idx = (int)(t - f->task_thread.tile_tasks[tp]);
+    Dav1dTileState *const ts = &f->ts[tile_idx];
+    const int p1 = atomic_load(&ts->progress[tp]);
+    if (p1 < t->sby) return 1;
+    int error = p1 == TILE_ERROR;
+    error |= atomic_fetch_or(&f->task_thread.error, error);
+    if (!error && frame_mt && !tp) {
+        const int p2 = atomic_load(&ts->progress[1]);
+        if (p2 <= t->sby) return 1;
+        error = p2 == TILE_ERROR;
+        error |= atomic_fetch_or(&f->task_thread.error, error);
+    }
+    if (!error && frame_mt && !IS_KEY_OR_INTRA(f->frame_hdr)) {
+        // check reference state
+        const Dav1dThreadPicture *p = &f->sr_cur;
+        const int ss_ver = p->p.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const unsigned p_b = (t->sby + 1) << (f->sb_shift + 2);
+        const int tile_sby = t->sby - (ts->tiling.row_start >> f->sb_shift);
+        const int (*const lowest_px)[2] = ts->lowest_pixel[tile_sby];
+        for (int n = t->deps_skip; n < 7; n++, t->deps_skip++) {
+            unsigned lowest;
+            if (tp) {
+                // if temporal mv refs are disabled, we only need this
+                // for the primary ref; if segmentation is disabled, we
+                // don't even need that
+                lowest = p_b;
+            } else {
+                // +8 is postfilter-induced delay
+                const int y = lowest_px[n][0] == INT_MIN ? INT_MIN :
+                              lowest_px[n][0] + 8;
+                const int uv = lowest_px[n][1] == INT_MIN ? INT_MIN :
+                               lowest_px[n][1] * (1 << ss_ver) + 8;
+                const int max = imax(y, uv);
+                if (max == INT_MIN) continue;
+                lowest = iclip(max, 1, f->refp[n].p.p.h);
+            }
+            const unsigned p3 = atomic_load(&f->refp[n].progress[!tp]);
+            if (p3 < lowest) return 1;
+            atomic_fetch_or(&f->task_thread.error, p3 == FRAME_ERROR);
+        }
+    }
+    return 0;
+}
+
+static inline int get_frame_progress(const Dav1dContext *const c,
+                                     const Dav1dFrameContext *const f)
+{
+    unsigned frame_prog = c->n_fc > 1 ? atomic_load(&f->sr_cur.progress[1]) : 0;
+    if (frame_prog >= FRAME_ERROR)
+        return f->sbh - 1;
+    int idx = frame_prog >> (f->sb_shift + 7);
+    int prog;
+    do {
+        atomic_uint *state = &f->frame_thread.frame_progress[idx];
+        const unsigned val = ~atomic_load(state);
+        prog = val ? ctz(val) : 32;
+        if (prog != 32) break;
+        prog = 0;
+    } while (++idx < f->frame_thread.prog_sz);
+    return ((idx << 5) | prog) - 1;
+}
+
+static inline void abort_frame(Dav1dFrameContext *const f, const int error) {
+    atomic_store(&f->task_thread.error, error == DAV1D_ERR(EINVAL) ? 1 : -1);
+    atomic_store(&f->task_thread.task_counter, 0);
+    atomic_store(&f->task_thread.done[0], 1);
+    atomic_store(&f->task_thread.done[1], 1);
+    atomic_store(&f->sr_cur.progress[0], FRAME_ERROR);
+    atomic_store(&f->sr_cur.progress[1], FRAME_ERROR);
+    dav1d_decode_frame_exit(f, error);
+    f->n_tile_data = 0;
+    pthread_cond_signal(&f->task_thread.cond);
+}
+
+static inline void delayed_fg_task(const Dav1dContext *const c,
+                                   struct TaskThreadData *const ttd)
+{
+    const Dav1dPicture *const in = ttd->delayed_fg.in;
+    Dav1dPicture *const out = ttd->delayed_fg.out;
+#if CONFIG_16BPC
+    int off;
+    if (out->p.bpc != 8)
+        off = (out->p.bpc >> 1) - 4;
+#endif
+    switch (ttd->delayed_fg.type) {
+    case DAV1D_TASK_TYPE_FG_PREP:
+        ttd->delayed_fg.exec = 0;
+        if (atomic_load(&ttd->cond_signaled))
+            pthread_cond_signal(&ttd->cond);
+        pthread_mutex_unlock(&ttd->lock);
+        switch (out->p.bpc) {
+#if CONFIG_8BPC
+        case 8:
+            dav1d_prep_grain_8bpc(&c->dsp[0].fg, out, in,
+                                  ttd->delayed_fg.scaling_8bpc,
+                                  ttd->delayed_fg.grain_lut_8bpc);
+            break;
+#endif
+#if CONFIG_16BPC
+        case 10:
+        case 12:
+            dav1d_prep_grain_16bpc(&c->dsp[off].fg, out, in,
+                                   ttd->delayed_fg.scaling_16bpc,
+                                   ttd->delayed_fg.grain_lut_16bpc);
+            break;
+#endif
+        default: abort();
+        }
+        ttd->delayed_fg.type = DAV1D_TASK_TYPE_FG_APPLY;
+        pthread_mutex_lock(&ttd->lock);
+        ttd->delayed_fg.exec = 1;
+        // fall-through
+    case DAV1D_TASK_TYPE_FG_APPLY:;
+        int row = atomic_fetch_add(&ttd->delayed_fg.progress[0], 1);
+        pthread_mutex_unlock(&ttd->lock);
+        int progmax = (out->p.h + FG_BLOCK_SIZE - 1) / FG_BLOCK_SIZE;
+        while (row < progmax) {
+            if (row + 1 < progmax)
+                pthread_cond_signal(&ttd->cond);
+            else {
+                pthread_mutex_lock(&ttd->lock);
+                ttd->delayed_fg.exec = 0;
+                pthread_mutex_unlock(&ttd->lock);
+            }
+            switch (out->p.bpc) {
+#if CONFIG_8BPC
+            case 8:
+                dav1d_apply_grain_row_8bpc(&c->dsp[0].fg, out, in,
+                                           ttd->delayed_fg.scaling_8bpc,
+                                           ttd->delayed_fg.grain_lut_8bpc, row);
+                break;
+#endif
+#if CONFIG_16BPC
+            case 10:
+            case 12:
+                dav1d_apply_grain_row_16bpc(&c->dsp[off].fg, out, in,
+                                            ttd->delayed_fg.scaling_16bpc,
+                                            ttd->delayed_fg.grain_lut_16bpc, row);
+                break;
+#endif
+            default: abort();
+            }
+            row = atomic_fetch_add(&ttd->delayed_fg.progress[0], 1);
+            atomic_fetch_add(&ttd->delayed_fg.progress[1], 1);
+        }
+        pthread_mutex_lock(&ttd->lock);
+        ttd->delayed_fg.exec = 0;
+        int done = atomic_fetch_add(&ttd->delayed_fg.progress[1], 1) + 1;
+        progmax = atomic_load(&ttd->delayed_fg.progress[0]);
+        // signal for completion only once the last runner reaches this
+        if (done >= progmax) {
+            ttd->delayed_fg.finished = 1;
+            pthread_cond_signal(&ttd->delayed_fg.cond);
+        }
+        break;
+    default: abort();
+    }
+}
+
+void *dav1d_worker_task(void *data) {
+    Dav1dTaskContext *const tc = data;
+    const Dav1dContext *const c = tc->c;
+    struct TaskThreadData *const ttd = tc->task_thread.ttd;
+
+    dav1d_set_thread_name("dav1d-worker");
+
+    pthread_mutex_lock(&ttd->lock);
+    for (;;) {
+        if (tc->task_thread.die) break;
+        if (atomic_load(c->flush)) goto park;
+
+        merge_pending(c);
+        if (ttd->delayed_fg.exec) { // run delayed film grain first
+            delayed_fg_task(c, ttd);
+            continue;
+        }
+        Dav1dFrameContext *f;
+        Dav1dTask *t, *prev_t = NULL;
+        if (c->n_fc > 1) { // run init tasks second
+            for (unsigned i = 0; i < c->n_fc; i++) {
+                const unsigned first = atomic_load(&ttd->first);
+                f = &c->fc[(first + i) % c->n_fc];
+                if (atomic_load(&f->task_thread.init_done)) continue;
+                t = f->task_thread.task_head;
+                if (!t) continue;
+                if (t->type == DAV1D_TASK_TYPE_INIT) goto found;
+                if (t->type == DAV1D_TASK_TYPE_INIT_CDF) {
+                    // XXX This can be a simple else, if adding tasks of both
+                    // passes at once (in dav1d_task_create_tile_sbrow).
+                    // Adding the tasks to the pending Q can result in a
+                    // thread merging them before setting init_done.
+                    // We will need to set init_done before adding to the
+                    // pending Q, so maybe return the tasks, set init_done,
+                    // and add to pending Q only then.
+                    const int p1 = f->in_cdf.progress ?
+                        atomic_load(f->in_cdf.progress) : 1;
+                    if (p1) {
+                        atomic_fetch_or(&f->task_thread.error, p1 == TILE_ERROR);
+                        goto found;
+                    }
+                }
+            }
+        }
+        while (ttd->cur < c->n_fc) { // run decoding tasks last
+            const unsigned first = atomic_load(&ttd->first);
+            f = &c->fc[(first + ttd->cur) % c->n_fc];
+            merge_pending_frame(f);
+            prev_t = f->task_thread.task_cur_prev;
+            t = prev_t ? prev_t->next : f->task_thread.task_head;
+            while (t) {
+                if (t->type == DAV1D_TASK_TYPE_INIT_CDF) goto next;
+                else if (t->type == DAV1D_TASK_TYPE_TILE_ENTROPY ||
+                         t->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION)
+                {
+                    // if not bottom sbrow of tile, this task will be re-added
+                    // after it's finished
+                    if (!check_tile(t, f, c->n_fc > 1))
+                        goto found;
+                } else if (t->recon_progress) {
+                    const int p = t->type == DAV1D_TASK_TYPE_ENTROPY_PROGRESS;
+                    int error = atomic_load(&f->task_thread.error);
+                    assert(!atomic_load(&f->task_thread.done[p]) || error);
+                    const int tile_row_base = f->frame_hdr->tiling.cols *
+                                              f->frame_thread.next_tile_row[p];
+                    if (p) {
+                        atomic_int *const prog = &f->frame_thread.entropy_progress;
+                        const int p1 = atomic_load(prog);
+                        if (p1 < t->sby) goto next;
+                        atomic_fetch_or(&f->task_thread.error, p1 == TILE_ERROR);
+                    }
+                    for (int tc = 0; tc < f->frame_hdr->tiling.cols; tc++) {
+                        Dav1dTileState *const ts = &f->ts[tile_row_base + tc];
+                        const int p2 = atomic_load(&ts->progress[p]);
+                        if (p2 < t->recon_progress) goto next;
+                        atomic_fetch_or(&f->task_thread.error, p2 == TILE_ERROR);
+                    }
+                    if (t->sby + 1 < f->sbh) {
+                        // add sby+1 to list to replace this one
+                        Dav1dTask *next_t = &t[1];
+                        *next_t = *t;
+                        next_t->sby++;
+                        const int ntr = f->frame_thread.next_tile_row[p] + 1;
+                        const int start = f->frame_hdr->tiling.row_start_sb[ntr];
+                        if (next_t->sby == start)
+                            f->frame_thread.next_tile_row[p] = ntr;
+                        next_t->recon_progress = next_t->sby + 1;
+                        insert_task(f, next_t, 0);
+                    }
+                    goto found;
+                } else if (t->type == DAV1D_TASK_TYPE_CDEF) {
+                    atomic_uint *prog = f->frame_thread.copy_lpf_progress;
+                    const int p1 = atomic_load(&prog[(t->sby - 1) >> 5]);
+                    if (p1 & (1U << ((t->sby - 1) & 31)))
+                        goto found;
+                } else {
+                    assert(t->deblock_progress);
+                    const int p1 = atomic_load(&f->frame_thread.deblock_progress);
+                    if (p1 >= t->deblock_progress) {
+                        atomic_fetch_or(&f->task_thread.error, p1 == TILE_ERROR);
+                        goto found;
+                    }
+                }
+            next:
+                prev_t = t;
+                t = t->next;
+                f->task_thread.task_cur_prev = prev_t;
+            }
+            ttd->cur++;
+        }
+        if (reset_task_cur(c, ttd, UINT_MAX)) continue;
+        if (merge_pending(c)) continue;
+    park:
+        tc->task_thread.flushed = 1;
+        pthread_cond_signal(&tc->task_thread.td.cond);
+        // we want to be woken up next time progress is signaled
+        atomic_store(&ttd->cond_signaled, 0);
+        pthread_cond_wait(&ttd->cond, &ttd->lock);
+        tc->task_thread.flushed = 0;
+        reset_task_cur(c, ttd, UINT_MAX);
+        continue;
+
+    found:
+        // remove t from list
+        if (prev_t) prev_t->next = t->next;
+        else f->task_thread.task_head = t->next;
+        if (!t->next) f->task_thread.task_tail = prev_t;
+        if (t->type > DAV1D_TASK_TYPE_INIT_CDF && !f->task_thread.task_head)
+            ttd->cur++;
+        t->next = NULL;
+        // we don't need to check cond_signaled here, since we found a task
+        // after the last signal so we want to re-signal the next waiting thread
+        // and again won't need to signal after that
+        atomic_store(&ttd->cond_signaled, 1);
+        pthread_cond_signal(&ttd->cond);
+        pthread_mutex_unlock(&ttd->lock);
+    found_unlocked:;
+        const int flush = atomic_load(c->flush);
+        int error = atomic_fetch_or(&f->task_thread.error, flush) | flush;
+
+        // run it
+        tc->f = f;
+        int sby = t->sby;
+        switch (t->type) {
+        case DAV1D_TASK_TYPE_INIT: {
+            assert(c->n_fc > 1);
+            int res = dav1d_decode_frame_init(f);
+            int p1 = f->in_cdf.progress ? atomic_load(f->in_cdf.progress) : 1;
+            if (res || p1 == TILE_ERROR) {
+                pthread_mutex_lock(&ttd->lock);
+                abort_frame(f, res ? res : DAV1D_ERR(EINVAL));
+                reset_task_cur(c, ttd, t->frame_idx);
+            } else {
+                t->type = DAV1D_TASK_TYPE_INIT_CDF;
+                if (p1) goto found_unlocked;
+                add_pending(f, t);
+                pthread_mutex_lock(&ttd->lock);
+            }
+            continue;
+        }
+        case DAV1D_TASK_TYPE_INIT_CDF: {
+            assert(c->n_fc > 1);
+            int res = DAV1D_ERR(EINVAL);
+            if (!atomic_load(&f->task_thread.error))
+                res = dav1d_decode_frame_init_cdf(f);
+            if (f->frame_hdr->refresh_context && !f->task_thread.update_set) {
+                atomic_store(f->out_cdf.progress, res < 0 ? TILE_ERROR : 1);
+            }
+            if (!res) {
+                assert(c->n_fc > 1);
+                for (int p = 1; p <= 2; p++) {
+                    const int res = dav1d_task_create_tile_sbrow(f, p, 0);
+                    if (res) {
+                        pthread_mutex_lock(&ttd->lock);
+                        // memory allocation failed
+                        atomic_store(&f->task_thread.done[2 - p], 1);
+                        atomic_store(&f->task_thread.error, -1);
+                        atomic_fetch_sub(&f->task_thread.task_counter,
+                                         f->frame_hdr->tiling.cols *
+                                         f->frame_hdr->tiling.rows + f->sbh);
+                        atomic_store(&f->sr_cur.progress[p - 1], FRAME_ERROR);
+                        if (p == 2 && atomic_load(&f->task_thread.done[1])) {
+                            assert(!atomic_load(&f->task_thread.task_counter));
+                            dav1d_decode_frame_exit(f, DAV1D_ERR(ENOMEM));
+                            f->n_tile_data = 0;
+                            pthread_cond_signal(&f->task_thread.cond);
+                        } else {
+                            pthread_mutex_unlock(&ttd->lock);
+                        }
+                    }
+                }
+                pthread_mutex_lock(&ttd->lock);
+            } else {
+                pthread_mutex_lock(&ttd->lock);
+                abort_frame(f, res);
+                reset_task_cur(c, ttd, t->frame_idx);
+                atomic_store(&f->task_thread.init_done, 1);
+            }
+            continue;
+        }
+        case DAV1D_TASK_TYPE_TILE_ENTROPY:
+        case DAV1D_TASK_TYPE_TILE_RECONSTRUCTION: {
+            const int p = t->type == DAV1D_TASK_TYPE_TILE_ENTROPY;
+            const int tile_idx = (int)(t - f->task_thread.tile_tasks[p]);
+            Dav1dTileState *const ts = &f->ts[tile_idx];
+
+            tc->ts = ts;
+            tc->by = sby << f->sb_shift;
+            const int uses_2pass = c->n_fc > 1;
+            tc->frame_thread.pass = !uses_2pass ? 0 :
+                1 + (t->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION);
+            if (!error) error = dav1d_decode_tile_sbrow(tc);
+            const int progress = error ? TILE_ERROR : 1 + sby;
+
+            // signal progress
+            atomic_fetch_or(&f->task_thread.error, error);
+            if (((sby + 1) << f->sb_shift) < ts->tiling.row_end) {
+                t->sby++;
+                t->deps_skip = 0;
+                if (!check_tile(t, f, uses_2pass)) {
+                    atomic_store(&ts->progress[p], progress);
+                    reset_task_cur_async(ttd, t->frame_idx, c->n_fc);
+                    if (!atomic_fetch_or(&ttd->cond_signaled, 1))
+                        pthread_cond_signal(&ttd->cond);
+                    goto found_unlocked;
+                }
+                atomic_store(&ts->progress[p], progress);
+                add_pending(f, t);
+                pthread_mutex_lock(&ttd->lock);
+            } else {
+                pthread_mutex_lock(&ttd->lock);
+                atomic_store(&ts->progress[p], progress);
+                reset_task_cur(c, ttd, t->frame_idx);
+                error = atomic_load(&f->task_thread.error);
+                if (f->frame_hdr->refresh_context &&
+                    tc->frame_thread.pass <= 1 && f->task_thread.update_set &&
+                    f->frame_hdr->tiling.update == tile_idx)
+                {
+                    if (!error)
+                        dav1d_cdf_thread_update(f->frame_hdr, f->out_cdf.data.cdf,
+                                                &f->ts[f->frame_hdr->tiling.update].cdf);
+                    if (c->n_fc > 1)
+                        atomic_store(f->out_cdf.progress, error ? TILE_ERROR : 1);
+                }
+                if (atomic_fetch_sub(&f->task_thread.task_counter, 1) - 1 == 0 &&
+                    atomic_load(&f->task_thread.done[0]) &&
+                    (!uses_2pass || atomic_load(&f->task_thread.done[1])))
+                {
+                    error = atomic_load(&f->task_thread.error);
+                    dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
+                                            error ? DAV1D_ERR(ENOMEM) : 0);
+                    f->n_tile_data = 0;
+                    pthread_cond_signal(&f->task_thread.cond);
+                }
+                assert(atomic_load(&f->task_thread.task_counter) >= 0);
+                if (!atomic_fetch_or(&ttd->cond_signaled, 1))
+                    pthread_cond_signal(&ttd->cond);
+            }
+            continue;
+        }
+        case DAV1D_TASK_TYPE_DEBLOCK_COLS:
+            if (!atomic_load(&f->task_thread.error))
+                f->bd_fn.filter_sbrow_deblock_cols(f, sby);
+            if (ensure_progress(ttd, f, t, DAV1D_TASK_TYPE_DEBLOCK_ROWS,
+                                &f->frame_thread.deblock_progress,
+                                &t->deblock_progress)) continue;
+            // fall-through
+        case DAV1D_TASK_TYPE_DEBLOCK_ROWS:
+            if (!atomic_load(&f->task_thread.error))
+                f->bd_fn.filter_sbrow_deblock_rows(f, sby);
+            // signal deblock progress
+            if (f->frame_hdr->loopfilter.level_y[0] ||
+                f->frame_hdr->loopfilter.level_y[1])
+            {
+                error = atomic_load(&f->task_thread.error);
+                atomic_store(&f->frame_thread.deblock_progress,
+                             error ? TILE_ERROR : sby + 1);
+                reset_task_cur_async(ttd, t->frame_idx, c->n_fc);
+                if (!atomic_fetch_or(&ttd->cond_signaled, 1))
+                    pthread_cond_signal(&ttd->cond);
+            } else if (f->seq_hdr->cdef || f->lf.restore_planes) {
+                atomic_fetch_or(&f->frame_thread.copy_lpf_progress[sby >> 5],
+                                1U << (sby & 31));
+                // CDEF needs the top buffer to be saved by lr_copy_lpf of the
+                // previous sbrow
+                if (sby) {
+                    int prog = atomic_load(&f->frame_thread.copy_lpf_progress[(sby - 1) >> 5]);
+                    if (~prog & (1U << ((sby - 1) & 31))) {
+                        t->type = DAV1D_TASK_TYPE_CDEF;
+                        t->recon_progress = t->deblock_progress = 0;
+                        add_pending(f, t);
+                        pthread_mutex_lock(&ttd->lock);
+                        continue;
+                    }
+                }
+            }
+            // fall-through
+        case DAV1D_TASK_TYPE_CDEF:
+            if (f->seq_hdr->cdef) {
+                if (!atomic_load(&f->task_thread.error))
+                    f->bd_fn.filter_sbrow_cdef(tc, sby);
+                reset_task_cur_async(ttd, t->frame_idx, c->n_fc);
+                if (!atomic_fetch_or(&ttd->cond_signaled, 1))
+                    pthread_cond_signal(&ttd->cond);
+            }
+            // fall-through
+        case DAV1D_TASK_TYPE_SUPER_RESOLUTION:
+            if (f->frame_hdr->width[0] != f->frame_hdr->width[1])
+                if (!atomic_load(&f->task_thread.error))
+                    f->bd_fn.filter_sbrow_resize(f, sby);
+            // fall-through
+        case DAV1D_TASK_TYPE_LOOP_RESTORATION:
+            if (!atomic_load(&f->task_thread.error) && f->lf.restore_planes)
+                f->bd_fn.filter_sbrow_lr(f, sby);
+            // fall-through
+        case DAV1D_TASK_TYPE_RECONSTRUCTION_PROGRESS:
+            // dummy to cover for no post-filters
+        case DAV1D_TASK_TYPE_ENTROPY_PROGRESS:
+            // dummy to convert tile progress to frame
+            break;
+        default: abort();
+        }
+        // if task completed [typically LR], signal picture progress as per below
+        const int uses_2pass = c->n_fc > 1;
+        const int sbh = f->sbh;
+        const int sbsz = f->sb_step * 4;
+        if (t->type == DAV1D_TASK_TYPE_ENTROPY_PROGRESS) {
+            error = atomic_load(&f->task_thread.error);
+            const unsigned y = sby + 1 == sbh ? UINT_MAX : (unsigned)(sby + 1) * sbsz;
+            assert(c->n_fc > 1);
+            if (f->sr_cur.p.data[0] /* upon flush, this can be free'ed already */)
+                atomic_store(&f->sr_cur.progress[0], error ? FRAME_ERROR : y);
+            atomic_store(&f->frame_thread.entropy_progress,
+                         error ? TILE_ERROR : sby + 1);
+            if (sby + 1 == sbh)
+                atomic_store(&f->task_thread.done[1], 1);
+            pthread_mutex_lock(&ttd->lock);
+            const int num_tasks = atomic_fetch_sub(&f->task_thread.task_counter, 1) - 1;
+            if (sby + 1 < sbh && num_tasks) {
+                reset_task_cur(c, ttd, t->frame_idx);
+                continue;
+            }
+            if (!num_tasks && atomic_load(&f->task_thread.done[0]) &&
+                atomic_load(&f->task_thread.done[1]))
+            {
+                error = atomic_load(&f->task_thread.error);
+                dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
+                                        error ? DAV1D_ERR(ENOMEM) : 0);
+                f->n_tile_data = 0;
+                pthread_cond_signal(&f->task_thread.cond);
+            }
+            reset_task_cur(c, ttd, t->frame_idx);
+            continue;
+        }
+    // t->type != DAV1D_TASK_TYPE_ENTROPY_PROGRESS
+        atomic_fetch_or(&f->frame_thread.frame_progress[sby >> 5],
+                        1U << (sby & 31));
+        pthread_mutex_lock(&f->task_thread.lock);
+        sby = get_frame_progress(c, f);
+        error = atomic_load(&f->task_thread.error);
+        const unsigned y = sby + 1 == sbh ? UINT_MAX : (unsigned)(sby + 1) * sbsz;
+        if (c->n_fc > 1 && f->sr_cur.p.data[0] /* upon flush, this can be free'ed already */)
+            atomic_store(&f->sr_cur.progress[1], error ? FRAME_ERROR : y);
+        pthread_mutex_unlock(&f->task_thread.lock);
+        if (sby + 1 == sbh)
+            atomic_store(&f->task_thread.done[0], 1);
+        pthread_mutex_lock(&ttd->lock);
+        const int num_tasks = atomic_fetch_sub(&f->task_thread.task_counter, 1) - 1;
+        if (sby + 1 < sbh && num_tasks) {
+            reset_task_cur(c, ttd, t->frame_idx);
+            continue;
+        }
+        if (!num_tasks && atomic_load(&f->task_thread.done[0]) &&
+            (!uses_2pass || atomic_load(&f->task_thread.done[1])))
+        {
+            error = atomic_load(&f->task_thread.error);
+            dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
+                                    error ? DAV1D_ERR(ENOMEM) : 0);
+            f->n_tile_data = 0;
+            pthread_cond_signal(&f->task_thread.cond);
+        }
+        reset_task_cur(c, ttd, t->frame_idx);
+    }
+    pthread_mutex_unlock(&ttd->lock);
+
+    return NULL;
+}
diff --git a/media/libdav1d/src/src/thread_task.h b/media/libdav1d/src/src/thread_task.h
new file mode 100644
index 0000000000..257da1a470
--- /dev/null
+++ b/media/libdav1d/src/src/thread_task.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_THREAD_TASK_H
+#define DAV1D_SRC_THREAD_TASK_H
+
+#include 
+
+#include "src/internal.h"
+
+#define FRAME_ERROR (UINT_MAX - 1)
+#define TILE_ERROR (INT_MAX - 1)
+
+// these functions assume the task scheduling lock is already taken
+int dav1d_task_create_tile_sbrow(Dav1dFrameContext *f, int pass, int cond_signal);
+void dav1d_task_frame_init(Dav1dFrameContext *f);
+
+void dav1d_task_delayed_fg(Dav1dContext *c, Dav1dPicture *out, const Dav1dPicture *in);
+
+void *dav1d_worker_task(void *data);
+
+int dav1d_decode_frame_init(Dav1dFrameContext *f);
+int dav1d_decode_frame_init_cdf(Dav1dFrameContext *f);
+int dav1d_decode_frame_main(Dav1dFrameContext *f);
+void dav1d_decode_frame_exit(Dav1dFrameContext *f, int retval);
+int dav1d_decode_frame(Dav1dFrameContext *f);
+int dav1d_decode_tile_sbrow(Dav1dTaskContext *t);
+
+#endif /* DAV1D_SRC_THREAD_TASK_H */
diff --git a/media/libdav1d/src/src/warpmv.c b/media/libdav1d/src/src/warpmv.c
new file mode 100644
index 0000000000..439c4304c7
--- /dev/null
+++ b/media/libdav1d/src/src/warpmv.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+
+#include "common/intops.h"
+
+#include "src/warpmv.h"
+
+static const uint16_t div_lut[257] = {
+    16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768,
+    15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142,
+    15087, 15033, 14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614, 14564,
+    14513, 14463, 14413, 14364, 14315, 14266, 14218, 14170, 14122, 14075, 14028,
+    13981, 13935, 13888, 13843, 13797, 13752, 13707, 13662, 13618, 13574, 13530,
+    13487, 13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148, 13107, 13066,
+    13026, 12985, 12945, 12906, 12866, 12827, 12788, 12749, 12710, 12672, 12633,
+    12596, 12558, 12520, 12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
+    12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950, 11916, 11882, 11848,
+    11815, 11782, 11749, 11716, 11683, 11651, 11619, 11586, 11555, 11523, 11491,
+    11460, 11429, 11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185, 11155,
+    11125, 11096, 11067, 11038, 11009, 10980, 10951, 10923, 10894, 10866, 10838,
+    10810, 10782, 10755, 10727, 10700, 10673, 10645, 10618, 10592, 10565, 10538,
+    10512, 10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305, 10280, 10255,
+    10230, 10205, 10180, 10156, 10131, 10107, 10082, 10058, 10034, 10010,  9986,
+     9963,  9939,  9916,  9892,  9869,  9846,  9823,  9800,  9777,  9754,  9732,
+     9709,  9687,  9664,  9642,  9620,  9598,  9576,  9554,  9533,  9511,  9489,
+     9468,  9447,  9425,  9404,  9383,  9362,  9341,  9321,  9300,  9279,  9259,
+     9239,  9218,  9198,  9178,  9158,  9138,  9118,  9098,  9079,  9059,  9039,
+     9020,  9001,  8981,  8962,  8943,  8924,  8905,  8886,  8867,  8849,  8830,
+     8812,  8793,  8775,  8756,  8738,  8720,  8702,  8684,  8666,  8648,  8630,
+     8613,  8595,  8577,  8560,  8542,  8525,  8508,  8490,  8473,  8456,  8439,
+     8422,  8405,  8389,  8372,  8355,  8339,  8322,  8306,  8289,  8273,  8257,
+     8240,  8224,  8208,  8192,
+};
+
+static inline int iclip_wmp(const int v) {
+    const int cv = iclip(v, INT16_MIN, INT16_MAX);
+
+    return apply_sign((abs(cv) + 32) >> 6, cv) * (1 << 6);
+}
+
+static inline int resolve_divisor_32(const unsigned d, int *const shift) {
+    *shift = ulog2(d);
+    const int e = d - (1 << *shift);
+    const int f = *shift > 8 ? (e + (1 << (*shift - 9))) >> (*shift - 8) :
+                               e << (8 - *shift);
+    assert(f <= 256);
+    *shift += 14;
+    // Use f as lookup into the precomputed table of multipliers
+    return div_lut[f];
+}
+
+int dav1d_get_shear_params(Dav1dWarpedMotionParams *const wm) {
+    const int32_t *const mat = wm->matrix;
+
+    if (mat[2] <= 0) return 1;
+
+    wm->u.p.alpha = iclip_wmp(mat[2] - 0x10000);
+    wm->u.p.beta = iclip_wmp(mat[3]);
+
+    int shift;
+    const int y = apply_sign(resolve_divisor_32(abs(mat[2]), &shift), mat[2]);
+    const int64_t v1 = ((int64_t) mat[4] * 0x10000) * y;
+    const int rnd = (1 << shift) >> 1;
+    wm->u.p.gamma = iclip_wmp(apply_sign64((int) ((llabs(v1) + rnd) >> shift), v1));
+    const int64_t v2 = ((int64_t) mat[3] * mat[4]) * y;
+    wm->u.p.delta = iclip_wmp(mat[5] -
+                          apply_sign64((int) ((llabs(v2) + rnd) >> shift), v2) -
+                          0x10000);
+
+    return (4 * abs(wm->u.p.alpha) + 7 * abs(wm->u.p.beta) >= 0x10000) ||
+           (4 * abs(wm->u.p.gamma) + 4 * abs(wm->u.p.delta) >= 0x10000);
+}
+
+static int resolve_divisor_64(const uint64_t d, int *const shift) {
+    *shift = u64log2(d);
+    const int64_t e = d - (1LL << *shift);
+    const int64_t f = *shift > 8 ? (e + (1LL << (*shift - 9))) >> (*shift - 8) :
+                                   e << (8 - *shift);
+    assert(f <= 256);
+    *shift += 14;
+    // Use f as lookup into the precomputed table of multipliers
+    return div_lut[f];
+}
+
+static int get_mult_shift_ndiag(const int64_t px,
+                                const int idet, const int shift)
+{
+    const int64_t v1 = px * idet;
+    const int v2 = apply_sign64((int) ((llabs(v1) +
+                                        ((1LL << shift) >> 1)) >> shift),
+                                v1);
+    return iclip(v2, -0x1fff, 0x1fff);
+}
+
+static int get_mult_shift_diag(const int64_t px,
+                               const int idet, const int shift)
+{
+    const int64_t v1 = px * idet;
+    const int v2 = apply_sign64((int) ((llabs(v1) +
+                                        ((1LL << shift) >> 1)) >> shift),
+                                v1);
+    return iclip(v2, 0xe001, 0x11fff);
+}
+
+void dav1d_set_affine_mv2d(const int bw4, const int bh4,
+                           const mv mv, Dav1dWarpedMotionParams *const wm,
+                           const int bx4, const int by4)
+{
+    int32_t *const mat = wm->matrix;
+    const int rsuy = 2 * bh4 - 1;
+    const int rsux = 2 * bw4 - 1;
+    const int isuy = by4 * 4 + rsuy;
+    const int isux = bx4 * 4 + rsux;
+
+    mat[0] = iclip(mv.x * 0x2000 - (isux * (mat[2] - 0x10000) + isuy * mat[3]),
+                   -0x800000, 0x7fffff);
+    mat[1] = iclip(mv.y * 0x2000 - (isux * mat[4] + isuy * (mat[5] - 0x10000)),
+                   -0x800000, 0x7fffff);
+}
+
+int dav1d_find_affine_int(const int (*pts)[2][2], const int np,
+                          const int bw4, const int bh4,
+                          const mv mv, Dav1dWarpedMotionParams *const wm,
+                          const int bx4, const int by4)
+{
+    int32_t *const mat = wm->matrix;
+    int a[2][2] = { { 0, 0 }, { 0, 0 } };
+    int bx[2] = { 0, 0 };
+    int by[2] = { 0, 0 };
+    const int rsuy = 2 * bh4 - 1;
+    const int rsux = 2 * bw4 - 1;
+    const int suy = rsuy * 8;
+    const int sux = rsux * 8;
+    const int duy = suy + mv.y;
+    const int dux = sux + mv.x;
+    const int isuy = by4 * 4 + rsuy;
+    const int isux = bx4 * 4 + rsux;
+
+    for (int i = 0; i < np; i++) {
+        const int dx = pts[i][1][0] - dux;
+        const int dy = pts[i][1][1] - duy;
+        const int sx = pts[i][0][0] - sux;
+        const int sy = pts[i][0][1] - suy;
+        if (abs(sx - dx) < 256 && abs(sy - dy) < 256) {
+            a[0][0] += ((sx * sx) >> 2) + sx * 2 + 8;
+            a[0][1] += ((sx * sy) >> 2) + sx + sy + 4;
+            a[1][1] += ((sy * sy) >> 2) + sy * 2 + 8;
+            bx[0] += ((sx * dx) >> 2) + sx + dx + 8;
+            bx[1] += ((sy * dx) >> 2) + sy + dx + 4;
+            by[0] += ((sx * dy) >> 2) + sx + dy + 4;
+            by[1] += ((sy * dy) >> 2) + sy + dy + 8;
+        }
+    }
+
+    // compute determinant of a
+    const int64_t det = (int64_t) a[0][0] * a[1][1] - (int64_t) a[0][1] * a[0][1];
+    if (det == 0) return 1;
+    int shift, idet = apply_sign64(resolve_divisor_64(llabs(det), &shift), det);
+    shift -= 16;
+    if (shift < 0) {
+        idet <<= -shift;
+        shift = 0;
+    }
+
+    // solve the least-squares
+    mat[2] = get_mult_shift_diag((int64_t) a[1][1] * bx[0] -
+                                 (int64_t) a[0][1] * bx[1], idet, shift);
+    mat[3] = get_mult_shift_ndiag((int64_t) a[0][0] * bx[1] -
+                                  (int64_t) a[0][1] * bx[0], idet, shift);
+    mat[4] = get_mult_shift_ndiag((int64_t) a[1][1] * by[0] -
+                                  (int64_t) a[0][1] * by[1], idet, shift);
+    mat[5] = get_mult_shift_diag((int64_t) a[0][0] * by[1] -
+                                 (int64_t) a[0][1] * by[0], idet, shift);
+
+    mat[0] = iclip(mv.x * 0x2000 - (isux * (mat[2] - 0x10000) + isuy * mat[3]),
+                   -0x800000, 0x7fffff);
+    mat[1] = iclip(mv.y * 0x2000 - (isux * mat[4] + isuy * (mat[5] - 0x10000)),
+                   -0x800000, 0x7fffff);
+
+    return 0;
+}
diff --git a/media/libdav1d/src/src/warpmv.h b/media/libdav1d/src/src/warpmv.h
new file mode 100644
index 0000000000..08e841d1ca
--- /dev/null
+++ b/media/libdav1d/src/src/warpmv.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_WARPMV_H
+#define DAV1D_SRC_WARPMV_H
+
+#include "src/levels.h"
+
+int dav1d_get_shear_params(Dav1dWarpedMotionParams *wm);
+int dav1d_find_affine_int(const int (*pts)[2][2], int np, int bw4, int bh4,
+                          mv mv, Dav1dWarpedMotionParams *wm, int bx, int by);
+void dav1d_set_affine_mv2d(int bw4, int bh4,
+                           mv mv, Dav1dWarpedMotionParams *wm, int bx, int by);
+
+#endif /* DAV1D_SRC_WARPMV_H */
diff --git a/media/libdav1d/src/src/wedge.c b/media/libdav1d/src/src/wedge.c
new file mode 100644
index 0000000000..2bea1393a1
--- /dev/null
+++ b/media/libdav1d/src/src/wedge.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "common/intops.h"
+
+#include "src/wedge.h"
+
+enum WedgeDirectionType {
+    WEDGE_HORIZONTAL = 0,
+    WEDGE_VERTICAL = 1,
+    WEDGE_OBLIQUE27 = 2,
+    WEDGE_OBLIQUE63 = 3,
+    WEDGE_OBLIQUE117 = 4,
+    WEDGE_OBLIQUE153 = 5,
+    N_WEDGE_DIRECTIONS
+};
+
+typedef struct {
+    uint8_t /* enum WedgeDirectionType */ direction;
+    uint8_t x_offset;
+    uint8_t y_offset;
+} wedge_code_type;
+
+static const wedge_code_type wedge_codebook_16_hgtw[16] = {
+    { WEDGE_OBLIQUE27,  4, 4 }, { WEDGE_OBLIQUE63,  4, 4 },
+    { WEDGE_OBLIQUE117, 4, 4 }, { WEDGE_OBLIQUE153, 4, 4 },
+    { WEDGE_HORIZONTAL, 4, 2 }, { WEDGE_HORIZONTAL, 4, 4 },
+    { WEDGE_HORIZONTAL, 4, 6 }, { WEDGE_VERTICAL,   4, 4 },
+    { WEDGE_OBLIQUE27,  4, 2 }, { WEDGE_OBLIQUE27,  4, 6 },
+    { WEDGE_OBLIQUE153, 4, 2 }, { WEDGE_OBLIQUE153, 4, 6 },
+    { WEDGE_OBLIQUE63,  2, 4 }, { WEDGE_OBLIQUE63,  6, 4 },
+    { WEDGE_OBLIQUE117, 2, 4 }, { WEDGE_OBLIQUE117, 6, 4 },
+};
+
+static const wedge_code_type wedge_codebook_16_hltw[16] = {
+    { WEDGE_OBLIQUE27,  4, 4 }, { WEDGE_OBLIQUE63,  4, 4 },
+    { WEDGE_OBLIQUE117, 4, 4 }, { WEDGE_OBLIQUE153, 4, 4 },
+    { WEDGE_VERTICAL,   2, 4 }, { WEDGE_VERTICAL,   4, 4 },
+    { WEDGE_VERTICAL,   6, 4 }, { WEDGE_HORIZONTAL, 4, 4 },
+    { WEDGE_OBLIQUE27,  4, 2 }, { WEDGE_OBLIQUE27,  4, 6 },
+    { WEDGE_OBLIQUE153, 4, 2 }, { WEDGE_OBLIQUE153, 4, 6 },
+    { WEDGE_OBLIQUE63,  2, 4 }, { WEDGE_OBLIQUE63,  6, 4 },
+    { WEDGE_OBLIQUE117, 2, 4 }, { WEDGE_OBLIQUE117, 6, 4 },
+};
+
+static const wedge_code_type wedge_codebook_16_heqw[16] = {
+    { WEDGE_OBLIQUE27,  4, 4 }, { WEDGE_OBLIQUE63,  4, 4 },
+    { WEDGE_OBLIQUE117, 4, 4 }, { WEDGE_OBLIQUE153, 4, 4 },
+    { WEDGE_HORIZONTAL, 4, 2 }, { WEDGE_HORIZONTAL, 4, 6 },
+    { WEDGE_VERTICAL,   2, 4 }, { WEDGE_VERTICAL,   6, 4 },
+    { WEDGE_OBLIQUE27,  4, 2 }, { WEDGE_OBLIQUE27,  4, 6 },
+    { WEDGE_OBLIQUE153, 4, 2 }, { WEDGE_OBLIQUE153, 4, 6 },
+    { WEDGE_OBLIQUE63,  2, 4 }, { WEDGE_OBLIQUE63,  6, 4 },
+    { WEDGE_OBLIQUE117, 2, 4 }, { WEDGE_OBLIQUE117, 6, 4 },
+};
+
+Dav1dMasks dav1d_masks;
+
+static void insert_border(uint8_t *const dst, const uint8_t *const src,
+                          const int ctr)
+{
+    if (ctr > 4) memset(dst, 0, ctr - 4);
+    memcpy(dst + imax(ctr, 4) - 4, src + imax(4 - ctr, 0), imin(64 - ctr, 8));
+    if (ctr < 64 - 4)
+        memset(dst + ctr + 4, 64, 64 - 4 - ctr);
+}
+
+static void transpose(uint8_t *const dst, const uint8_t *const src) {
+    for (int y = 0, y_off = 0; y < 64; y++, y_off += 64)
+        for (int x = 0, x_off = 0; x < 64; x++, x_off += 64)
+            dst[x_off + y] = src[y_off + x];
+}
+
+static void hflip(uint8_t *const dst, const uint8_t *const src) {
+    for (int y = 0, y_off = 0; y < 64; y++, y_off += 64)
+        for (int x = 0; x < 64; x++)
+            dst[y_off + 64 - 1 - x] = src[y_off + x];
+}
+
+static void copy2d(uint8_t *dst, const uint8_t *src, int sign,
+                   const int w, const int h, const int x_off, const int y_off)
+{
+    src += y_off * 64 + x_off;
+    if (sign) {
+        for (int y = 0; y < h; y++) {
+            for (int x = 0; x < w; x++)
+                dst[x] = 64 - src[x];
+            src += 64;
+            dst += w;
+        }
+    } else {
+        for (int y = 0; y < h; y++) {
+            memcpy(dst, src, w);
+            src += 64;
+            dst += w;
+        }
+    }
+}
+
+#define MASK_OFFSET(x) ((uint16_t)(((uintptr_t)(x) - (uintptr_t)&dav1d_masks) >> 3))
+
+static COLD uint16_t init_chroma(uint8_t *chroma, const uint8_t *luma,
+                                 const int sign, const int w, const int h,
+                                 const int ss_ver)
+{
+    const uint16_t offset = MASK_OFFSET(chroma);
+    for (int y = 0; y < h; y += 1 + ss_ver) {
+        for (int x = 0; x < w; x += 2) {
+            int sum = luma[x] + luma[x + 1] + 1;
+            if (ss_ver) sum += luma[w + x] + luma[w + x + 1] + 1;
+            chroma[x >> 1] = (sum - sign) >> (1 + ss_ver);
+        }
+        luma += w << ss_ver;
+        chroma += w >> 1;
+    }
+    return offset;
+}
+
+static COLD void fill2d_16x2(const int w, const int h, const enum BlockSize bs,
+                             const uint8_t (*const master)[64 * 64],
+                             const wedge_code_type *const cb,
+                             uint8_t *masks_444, uint8_t *masks_422,
+                             uint8_t *masks_420, unsigned signs)
+{
+    const int n_stride_444 = (w * h);
+    const int n_stride_422 = n_stride_444 >> 1;
+    const int n_stride_420 = n_stride_444 >> 2;
+    const int sign_stride_422 = 16 * n_stride_422;
+    const int sign_stride_420 = 16 * n_stride_420;
+
+    // assign pointer offsets in lookup table
+    for (int n = 0; n < 16; n++) {
+        const int sign = signs & 1;
+
+        copy2d(masks_444, master[cb[n].direction], sign, w, h,
+               32 - (w * cb[n].x_offset >> 3), 32 - (h * cb[n].y_offset >> 3));
+
+        // not using !sign is intentional here, since 444 does not require
+        // any rounding since no chroma subsampling is applied.
+        dav1d_masks.offsets[0][bs].wedge[0][n] =
+        dav1d_masks.offsets[0][bs].wedge[1][n] = MASK_OFFSET(masks_444);
+
+        dav1d_masks.offsets[1][bs].wedge[0][n] =
+            init_chroma(&masks_422[ sign * sign_stride_422], masks_444, 0, w, h, 0);
+        dav1d_masks.offsets[1][bs].wedge[1][n] =
+            init_chroma(&masks_422[!sign * sign_stride_422], masks_444, 1, w, h, 0);
+        dav1d_masks.offsets[2][bs].wedge[0][n] =
+            init_chroma(&masks_420[ sign * sign_stride_420], masks_444, 0, w, h, 1);
+        dav1d_masks.offsets[2][bs].wedge[1][n] =
+            init_chroma(&masks_420[!sign * sign_stride_420], masks_444, 1, w, h, 1);
+
+        signs >>= 1;
+        masks_444 += n_stride_444;
+        masks_422 += n_stride_422;
+        masks_420 += n_stride_420;
+    }
+}
+
+static COLD void build_nondc_ii_masks(uint8_t *const mask_v, const int w,
+                                      const int h, const int step)
+{
+    static const uint8_t ii_weights_1d[32] = {
+        60, 52, 45, 39, 34, 30, 26, 22, 19, 17, 15, 13, 11, 10,  8,  7,
+         6,  6,  5,  4,  4,  3,  3,  2,  2,  2,  2,  1,  1,  1,  1,  1,
+    };
+
+    uint8_t *const mask_h  = &mask_v[w * h];
+    uint8_t *const mask_sm = &mask_h[w * h];
+    for (int y = 0, off = 0; y < h; y++, off += w) {
+        memset(&mask_v[off], ii_weights_1d[y * step], w);
+        for (int x = 0; x < w; x++) {
+            mask_sm[off + x] = ii_weights_1d[imin(x, y) * step];
+            mask_h[off + x] = ii_weights_1d[x * step];
+        }
+    }
+}
+
+COLD void dav1d_init_ii_wedge_masks(void) {
+    // This function is guaranteed to be called only once
+
+    enum WedgeMasterLineType {
+        WEDGE_MASTER_LINE_ODD,
+        WEDGE_MASTER_LINE_EVEN,
+        WEDGE_MASTER_LINE_VERT,
+        N_WEDGE_MASTER_LINES,
+    };
+    static const uint8_t wedge_master_border[N_WEDGE_MASTER_LINES][8] = {
+        [WEDGE_MASTER_LINE_ODD]  = {  1,  2,  6, 18, 37, 53, 60, 63 },
+        [WEDGE_MASTER_LINE_EVEN] = {  1,  4, 11, 27, 46, 58, 62, 63 },
+        [WEDGE_MASTER_LINE_VERT] = {  0,  2,  7, 21, 43, 57, 62, 64 },
+    };
+    uint8_t master[6][64 * 64];
+
+    // create master templates
+    for (int y = 0, off = 0; y < 64; y++, off += 64)
+        insert_border(&master[WEDGE_VERTICAL][off],
+                      wedge_master_border[WEDGE_MASTER_LINE_VERT], 32);
+    for (int y = 0, off = 0, ctr = 48; y < 64; y += 2, off += 128, ctr--)
+    {
+        insert_border(&master[WEDGE_OBLIQUE63][off],
+                      wedge_master_border[WEDGE_MASTER_LINE_EVEN], ctr);
+        insert_border(&master[WEDGE_OBLIQUE63][off + 64],
+                      wedge_master_border[WEDGE_MASTER_LINE_ODD], ctr - 1);
+    }
+
+    transpose(master[WEDGE_OBLIQUE27], master[WEDGE_OBLIQUE63]);
+    transpose(master[WEDGE_HORIZONTAL], master[WEDGE_VERTICAL]);
+    hflip(master[WEDGE_OBLIQUE117], master[WEDGE_OBLIQUE63]);
+    hflip(master[WEDGE_OBLIQUE153], master[WEDGE_OBLIQUE27]);
+
+#define fill(w, h, sz_422, sz_420, hvsw, signs) \
+    fill2d_16x2(w, h, BS_##w##x##h - BS_32x32, \
+                master, wedge_codebook_16_##hvsw, \
+                dav1d_masks.wedge_444_##w##x##h, \
+                dav1d_masks.wedge_422_##sz_422, \
+                dav1d_masks.wedge_420_##sz_420, signs)
+
+    fill(32, 32, 16x32, 16x16, heqw, 0x7bfb);
+    fill(32, 16, 16x16, 16x8,  hltw, 0x7beb);
+    fill(32,  8, 16x8,  16x4,  hltw, 0x6beb);
+    fill(16, 32,  8x32,  8x16, hgtw, 0x7beb);
+    fill(16, 16,  8x16,  8x8,  heqw, 0x7bfb);
+    fill(16,  8,  8x8,   8x4,  hltw, 0x7beb);
+    fill( 8, 32,  4x32,  4x16, hgtw, 0x7aeb);
+    fill( 8, 16,  4x16,  4x8,  hgtw, 0x7beb);
+    fill( 8,  8,  4x8,   4x4,  heqw, 0x7bfb);
+#undef fill
+
+    memset(dav1d_masks.ii_dc, 32, 32 * 32);
+    for (int c = 0; c < 3; c++) {
+        dav1d_masks.offsets[c][BS_32x32-BS_32x32].ii[II_DC_PRED] =
+        dav1d_masks.offsets[c][BS_32x16-BS_32x32].ii[II_DC_PRED] =
+        dav1d_masks.offsets[c][BS_16x32-BS_32x32].ii[II_DC_PRED] =
+        dav1d_masks.offsets[c][BS_16x16-BS_32x32].ii[II_DC_PRED] =
+        dav1d_masks.offsets[c][BS_16x8 -BS_32x32].ii[II_DC_PRED] =
+        dav1d_masks.offsets[c][BS_8x16 -BS_32x32].ii[II_DC_PRED] =
+        dav1d_masks.offsets[c][BS_8x8  -BS_32x32].ii[II_DC_PRED] =
+            MASK_OFFSET(dav1d_masks.ii_dc);
+    }
+
+#define BUILD_NONDC_II_MASKS(w, h, step) \
+    build_nondc_ii_masks(dav1d_masks.ii_nondc_##w##x##h, w, h, step)
+
+#define ASSIGN_NONDC_II_OFFSET(bs, w444, h444, w422, h422, w420, h420) \
+    dav1d_masks.offsets[0][bs-BS_32x32].ii[p + 1] = \
+        MASK_OFFSET(&dav1d_masks.ii_nondc_##w444##x##h444[p*w444*h444]); \
+    dav1d_masks.offsets[1][bs-BS_32x32].ii[p + 1] = \
+        MASK_OFFSET(&dav1d_masks.ii_nondc_##w422##x##h422[p*w422*h422]); \
+    dav1d_masks.offsets[2][bs-BS_32x32].ii[p + 1] = \
+        MASK_OFFSET(&dav1d_masks.ii_nondc_##w420##x##h420[p*w420*h420])
+
+    BUILD_NONDC_II_MASKS(32, 32, 1);
+    BUILD_NONDC_II_MASKS(16, 32, 1);
+    BUILD_NONDC_II_MASKS(16, 16, 2);
+    BUILD_NONDC_II_MASKS( 8, 32, 1);
+    BUILD_NONDC_II_MASKS( 8, 16, 2);
+    BUILD_NONDC_II_MASKS( 8,  8, 4);
+    BUILD_NONDC_II_MASKS( 4, 16, 2);
+    BUILD_NONDC_II_MASKS( 4,  8, 4);
+    BUILD_NONDC_II_MASKS( 4,  4, 8);
+    for (int p = 0; p < 3; p++) {
+        ASSIGN_NONDC_II_OFFSET(BS_32x32, 32, 32, 16, 32, 16, 16);
+        ASSIGN_NONDC_II_OFFSET(BS_32x16, 32, 32, 16, 16, 16, 16);
+        ASSIGN_NONDC_II_OFFSET(BS_16x32, 16, 32,  8, 32,  8, 16);
+        ASSIGN_NONDC_II_OFFSET(BS_16x16, 16, 16,  8, 16,  8,  8);
+        ASSIGN_NONDC_II_OFFSET(BS_16x8,  16, 16,  8,  8,  8,  8);
+        ASSIGN_NONDC_II_OFFSET(BS_8x16,   8, 16,  4, 16,  4,  8);
+        ASSIGN_NONDC_II_OFFSET(BS_8x8,    8,  8,  4,  8,  4,  4);
+    }
+}
diff --git a/media/libdav1d/src/src/wedge.h b/media/libdav1d/src/src/wedge.h
new file mode 100644
index 0000000000..244e04ad2a
--- /dev/null
+++ b/media/libdav1d/src/src/wedge.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_WEDGE_H
+#define DAV1D_SRC_WEDGE_H
+
+#include "src/levels.h"
+
+typedef struct {
+    /* Offsets, in units of 8 bytes, relative to the start of the struct. */
+    struct {
+        uint16_t wedge[2 /* sign */][16 /* wedge_idx */];
+        uint16_t ii[N_INTER_INTRA_PRED_MODES];
+    } offsets[3 /* 444, 422, 420 */][BS_8x8 - BS_32x32 + 1];
+
+    uint8_t ALIGN(wedge_444_32x32[    16 * 32 * 32], 64);
+    uint8_t ALIGN(wedge_444_32x16[    16 * 32 * 16], 64);
+    uint8_t ALIGN(wedge_444_32x8 [    16 * 32 *  8], 64);
+    uint8_t ALIGN(wedge_444_16x32[    16 * 16 * 32], 64);
+    uint8_t ALIGN(wedge_444_16x16[    16 * 16 * 16], 64);
+    uint8_t ALIGN(wedge_444_16x8 [    16 * 16 *  8], 64);
+    uint8_t ALIGN(wedge_444_8x32 [    16 *  8 * 32], 64);
+    uint8_t ALIGN(wedge_444_8x16 [    16 *  8 * 16], 64);
+    uint8_t ALIGN(wedge_444_8x8  [    16 *  8 *  8], 64);
+
+    uint8_t ALIGN(wedge_422_16x32[2 * 16 * 16 * 32], 64);
+    uint8_t ALIGN(wedge_422_16x16[2 * 16 * 16 * 16], 64);
+    uint8_t ALIGN(wedge_422_16x8 [2 * 16 * 16 *  8], 64);
+    uint8_t ALIGN(wedge_422_8x32 [2 * 16 *  8 * 32], 64);
+    uint8_t ALIGN(wedge_422_8x16 [2 * 16 *  8 * 16], 64);
+    uint8_t ALIGN(wedge_422_8x8  [2 * 16 *  8 *  8], 64);
+    uint8_t ALIGN(wedge_422_4x32 [2 * 16 *  4 * 32], 64);
+    uint8_t ALIGN(wedge_422_4x16 [2 * 16 *  4 * 16], 64);
+    uint8_t ALIGN(wedge_422_4x8  [2 * 16 *  4 *  8], 64);
+
+    uint8_t ALIGN(wedge_420_16x16[2 * 16 * 16 * 16], 64);
+    uint8_t ALIGN(wedge_420_16x8 [2 * 16 * 16 *  8], 64);
+    uint8_t ALIGN(wedge_420_16x4 [2 * 16 * 16 *  4], 64);
+    uint8_t ALIGN(wedge_420_8x16 [2 * 16 *  8 * 16], 64);
+    uint8_t ALIGN(wedge_420_8x8  [2 * 16 *  8 *  8], 64);
+    uint8_t ALIGN(wedge_420_8x4  [2 * 16 *  8 *  4], 64);
+    uint8_t ALIGN(wedge_420_4x16 [2 * 16 *  4 * 16], 64);
+    uint8_t ALIGN(wedge_420_4x8  [2 * 16 *  4 *  8], 64);
+    uint8_t ALIGN(wedge_420_4x4  [2 * 16 *  4 *  4], 64);
+
+    uint8_t ALIGN(ii_dc         [    32 * 32], 64);
+    uint8_t ALIGN(ii_nondc_32x32[3 * 32 * 32], 64);
+    uint8_t ALIGN(ii_nondc_16x32[3 * 16 * 32], 64);
+    uint8_t ALIGN(ii_nondc_16x16[3 * 16 * 16], 64);
+    uint8_t ALIGN(ii_nondc_8x32 [3 *  8 * 32], 64);
+    uint8_t ALIGN(ii_nondc_8x16 [3 *  8 * 16], 64);
+    uint8_t ALIGN(ii_nondc_8x8  [3 *  8 *  8], 64);
+    uint8_t ALIGN(ii_nondc_4x16 [3 *  4 * 16], 64);
+    uint8_t ALIGN(ii_nondc_4x8  [3 *  4 *  8], 32);
+    uint8_t ALIGN(ii_nondc_4x4  [3 *  4 *  4], 16);
+} Dav1dMasks;
+
+#define II_MASK(c, bs, b) \
+    ((const uint8_t*)((uintptr_t)&dav1d_masks + \
+    (size_t)((b)->interintra_type == INTER_INTRA_BLEND ? \
+    dav1d_masks.offsets[c][(bs)-BS_32x32].ii[(b)->interintra_mode] : \
+    dav1d_masks.offsets[c][(bs)-BS_32x32].wedge[0][(b)->wedge_idx]) * 8))
+
+#define WEDGE_MASK(c, bs, sign, idx) \
+    ((const uint8_t*)((uintptr_t)&dav1d_masks + \
+    (size_t)dav1d_masks.offsets[c][(bs)-BS_32x32].wedge[sign][idx] * 8))
+
+EXTERN Dav1dMasks dav1d_masks;
+
+void dav1d_init_ii_wedge_masks(void);
+
+#endif /* DAV1D_SRC_WEDGE_H */
diff --git a/media/libdav1d/src/src/win32/thread.c b/media/libdav1d/src/src/win32/thread.c
new file mode 100644
index 0000000000..b89bd6b165
--- /dev/null
+++ b/media/libdav1d/src/src/win32/thread.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if defined(_WIN32)
+
+#include 
+#include 
+#include 
+
+#include "common/attributes.h"
+
+#include "src/thread.h"
+
+static HRESULT (WINAPI *set_thread_description)(HANDLE, PCWSTR);
+
+COLD void dav1d_init_thread(void) {
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+    HANDLE kernel32 = GetModuleHandleW(L"kernel32.dll");
+    if (kernel32)
+        set_thread_description =
+            (void*)GetProcAddress(kernel32, "SetThreadDescription");
+#endif
+}
+
+#undef dav1d_set_thread_name
+COLD void dav1d_set_thread_name(const wchar_t *const name) {
+    if (set_thread_description) /* Only available since Windows 10 1607 */
+        set_thread_description(GetCurrentThread(), name);
+}
+
+static COLD unsigned __stdcall thread_entrypoint(void *const data) {
+    pthread_t *const t = data;
+    t->arg = t->func(t->arg);
+    return 0;
+}
+
+COLD int dav1d_pthread_create(pthread_t *const thread,
+                              const pthread_attr_t *const attr,
+                              void *(*const func)(void*), void *const arg)
+{
+    const unsigned stack_size = attr ? attr->stack_size : 0;
+    thread->func = func;
+    thread->arg = arg;
+    thread->h = (HANDLE)_beginthreadex(NULL, stack_size, thread_entrypoint, thread,
+                                       STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
+    return !thread->h;
+}
+
+COLD int dav1d_pthread_join(pthread_t *const thread, void **const res) {
+    if (WaitForSingleObject(thread->h, INFINITE))
+        return 1;
+
+    if (res)
+        *res = thread->arg;
+
+    return !CloseHandle(thread->h);
+}
+
+COLD int dav1d_pthread_once(pthread_once_t *const once_control,
+                            void (*const init_routine)(void))
+{
+    BOOL pending = FALSE;
+
+    if (InitOnceBeginInitialize(once_control, 0, &pending, NULL) != TRUE)
+        return 1;
+
+    if (pending == TRUE)
+        init_routine();
+
+    return !InitOnceComplete(once_control, 0, NULL);
+}
+
+#endif
diff --git a/media/libdav1d/src/src/x86/cdef.h b/media/libdav1d/src/src/x86/cdef.h
new file mode 100644
index 0000000000..553d650741
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cdef.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/cdef.h"
+
+#define decl_cdef_fns(ext) \
+    decl_cdef_fn(BF(dav1d_cdef_filter_4x4, ext)); \
+    decl_cdef_fn(BF(dav1d_cdef_filter_4x8, ext)); \
+    decl_cdef_fn(BF(dav1d_cdef_filter_8x8, ext))
+
+decl_cdef_fns(avx512icl);
+decl_cdef_fns(avx2);
+decl_cdef_fns(sse4);
+decl_cdef_fns(ssse3);
+decl_cdef_fns(sse2);
+
+decl_cdef_dir_fn(BF(dav1d_cdef_dir, avx2));
+decl_cdef_dir_fn(BF(dav1d_cdef_dir, sse4));
+decl_cdef_dir_fn(BF(dav1d_cdef_dir, ssse3));
+
+static ALWAYS_INLINE void cdef_dsp_init_x86(Dav1dCdefDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+#if BITDEPTH == 8
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSE2)) return;
+
+    c->fb[0] = BF(dav1d_cdef_filter_8x8, sse2);
+    c->fb[1] = BF(dav1d_cdef_filter_4x8, sse2);
+    c->fb[2] = BF(dav1d_cdef_filter_4x4, sse2);
+#endif
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSSE3)) return;
+
+    c->dir = BF(dav1d_cdef_dir, ssse3);
+    c->fb[0] = BF(dav1d_cdef_filter_8x8, ssse3);
+    c->fb[1] = BF(dav1d_cdef_filter_4x8, ssse3);
+    c->fb[2] = BF(dav1d_cdef_filter_4x4, ssse3);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSE41)) return;
+
+    c->dir = BF(dav1d_cdef_dir, sse4);
+#if BITDEPTH == 8
+    c->fb[0] = BF(dav1d_cdef_filter_8x8, sse4);
+    c->fb[1] = BF(dav1d_cdef_filter_4x8, sse4);
+    c->fb[2] = BF(dav1d_cdef_filter_4x4, sse4);
+#endif
+
+#if ARCH_X86_64
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2)) return;
+
+    c->dir = BF(dav1d_cdef_dir, avx2);
+    c->fb[0] = BF(dav1d_cdef_filter_8x8, avx2);
+    c->fb[1] = BF(dav1d_cdef_filter_4x8, avx2);
+    c->fb[2] = BF(dav1d_cdef_filter_4x4, avx2);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL)) return;
+
+    c->fb[0] = BF(dav1d_cdef_filter_8x8, avx512icl);
+    c->fb[1] = BF(dav1d_cdef_filter_4x8, avx512icl);
+    c->fb[2] = BF(dav1d_cdef_filter_4x4, avx512icl);
+#endif
+}
diff --git a/media/libdav1d/src/src/x86/cdef16_avx2.asm b/media/libdav1d/src/src/x86/cdef16_avx2.asm
new file mode 100644
index 0000000000..4c8d3bca43
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cdef16_avx2.asm
@@ -0,0 +1,877 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA
+
+%macro DIR_TABLE 1 ; stride
+    db  1 * %1 + 0,  2 * %1 + 0
+    db  1 * %1 + 0,  2 * %1 - 2
+    db -1 * %1 + 2, -2 * %1 + 4
+    db  0 * %1 + 2, -1 * %1 + 4
+    db  0 * %1 + 2,  0 * %1 + 4
+    db  0 * %1 + 2,  1 * %1 + 4
+    db  1 * %1 + 2,  2 * %1 + 4
+    db  1 * %1 + 0,  2 * %1 + 2
+    db  1 * %1 + 0,  2 * %1 + 0
+    db  1 * %1 + 0,  2 * %1 - 2
+    db -1 * %1 + 2, -2 * %1 + 4
+    db  0 * %1 + 2, -1 * %1 + 4
+%endmacro
+
+dir_table4: DIR_TABLE 16
+dir_table8: DIR_TABLE 32
+pri_taps:   dw  4, 4, 3, 3, 2, 2, 3, 3
+
+dir_shift:  times 2 dw 0x4000
+            times 2 dw 0x1000
+
+pw_2048:    times 2 dw 2048
+pw_m16384:  times 2 dw -16384
+
+cextern cdef_dir_8bpc_avx2.main
+
+SECTION .text
+
+%macro CDEF_FILTER 2 ; w, h
+    DEFINE_ARGS dst, stride, _, dir, pridmp, pri, sec, tmp
+    movifnidn     prid, r5m
+    movifnidn     secd, r6m
+    mov           dird, r7m
+    vpbroadcastd    m8, [base+pw_2048]
+    lea           dirq, [base+dir_table%1+dirq*2]
+    test          prid, prid
+    jz .sec_only
+%if WIN64
+    vpbroadcastw    m6, prim
+    movaps  [rsp+16*0], xmm9
+    movaps  [rsp+16*1], xmm10
+%else
+    movd           xm6, prid
+    vpbroadcastw    m6, xm6
+%endif
+    lzcnt      pridmpd, prid
+    rorx          tmpd, prid, 2
+    cmp     dword r10m, 0xfff ; if (bpc == 12)
+    cmove         prid, tmpd  ;     pri >>= 2
+    mov           tmpd, r8m   ; damping
+    and           prid, 4
+    sub           tmpd, 31
+    vpbroadcastd    m9, [base+pri_taps+priq+8*0]
+    vpbroadcastd   m10, [base+pri_taps+priq+8*1]
+    test          secd, secd
+    jz .pri_only
+%if WIN64
+    movaps         r8m, xmm13
+    vpbroadcastw   m13, secm
+    movaps         r4m, xmm11
+    movaps         r6m, xmm12
+%else
+    movd           xm0, secd
+    vpbroadcastw   m13, xm0
+%endif
+    lzcnt         secd, secd
+    xor           prid, prid
+    add        pridmpd, tmpd
+    cmovs      pridmpd, prid
+    add           secd, tmpd
+    lea           tmpq, [px]
+    mov    [pri_shift], pridmpq
+    mov    [sec_shift], secq
+%rep %1*%2/16
+    call mangle(private_prefix %+ _cdef_filter_%1x%1_16bpc %+ SUFFIX).pri_sec
+%endrep
+%if WIN64
+    movaps       xmm11, r4m
+    movaps       xmm12, r6m
+    movaps       xmm13, r8m
+%endif
+    jmp .pri_end
+.pri_only:
+    add        pridmpd, tmpd
+    cmovs      pridmpd, secd
+    lea           tmpq, [px]
+    mov    [pri_shift], pridmpq
+%rep %1*%2/16
+    call mangle(private_prefix %+ _cdef_filter_%1x%1_16bpc %+ SUFFIX).pri
+%endrep
+.pri_end:
+%if WIN64
+    movaps        xmm9, [rsp+16*0]
+    movaps       xmm10, [rsp+16*1]
+%endif
+.end:
+    RET
+.sec_only:
+    mov           tmpd, r8m ; damping
+%if WIN64
+    vpbroadcastw    m6, secm
+%else
+    movd           xm6, secd
+    vpbroadcastw    m6, xm6
+%endif
+    tzcnt         secd, secd
+    sub           tmpd, secd
+    mov    [sec_shift], tmpq
+    lea           tmpq, [px]
+%rep %1*%2/16
+    call mangle(private_prefix %+ _cdef_filter_%1x%1_16bpc %+ SUFFIX).sec
+%endrep
+    jmp .end
+%if %1 == %2
+ALIGN function_align
+.pri:
+    movsx         offq, byte [dirq+4]    ; off_k0
+%if %1 == 4
+    mova            m1, [tmpq+32*0]
+    punpcklqdq      m1, [tmpq+32*1]      ; 0 2 1 3
+    movu            m2, [tmpq+offq+32*0]
+    punpcklqdq      m2, [tmpq+offq+32*1] ; k0p0
+    neg           offq
+    movu            m3, [tmpq+offq+32*0]
+    punpcklqdq      m3, [tmpq+offq+32*1] ; k0p1
+%else
+    mova           xm1, [tmpq+32*0]
+    vinserti128     m1, [tmpq+32*1], 1
+    movu           xm2, [tmpq+offq+32*0]
+    vinserti128     m2, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm3, [tmpq+offq+32*0]
+    vinserti128     m3, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+5]    ; off_k1
+    psubw           m2, m1               ; diff_k0p0
+    psubw           m3, m1               ; diff_k0p1
+    pabsw           m4, m2               ; adiff_k0p0
+    psrlw           m5, m4, [pri_shift+gprsize]
+    psubusw         m0, m6, m5
+    pabsw           m5, m3               ; adiff_k0p1
+    pminsw          m0, m4
+    psrlw           m4, m5, [pri_shift+gprsize]
+    psignw          m0, m2               ; constrain(diff_k0p0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movu            m4, [tmpq+offq+32*0]
+    punpcklqdq      m4, [tmpq+offq+32*1] ; k1p0
+    neg           offq
+    movu            m5, [tmpq+offq+32*0]
+    punpcklqdq      m5, [tmpq+offq+32*1] ; k1p1
+%else
+    movu           xm4, [tmpq+offq+32*0]
+    vinserti128     m4, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm5, [tmpq+offq+32*0]
+    vinserti128     m5, [tmpq+offq+32*1], 1
+%endif
+    psubw           m4, m1               ; diff_k1p0
+    psubw           m5, m1               ; diff_k1p1
+    psignw          m2, m3               ; constrain(diff_k0p1)
+    pabsw           m3, m4               ; adiff_k1p0
+    paddw           m0, m2               ; constrain(diff_k0)
+    psrlw           m2, m3, [pri_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k1p1
+    pminsw          m7, m3
+    psrlw           m3, m2, [pri_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k1p0)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+    psignw          m4, m5               ; constrain(diff_k1p1)
+    paddw           m7, m4               ; constrain(diff_k1)
+    pmullw          m0, m9               ; pri_tap_k0
+    pmullw          m7, m10              ; pri_tap_k1
+    paddw           m0, m7               ; sum
+    psraw           m2, m0, 15
+    paddw           m0, m2
+    pmulhrsw        m0, m8
+    add           tmpq, 32*2
+    paddw           m0, m1
+%if %1 == 4
+    vextracti128   xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r9       ], xm1
+    lea           dstq, [dstq+strideq*4]
+%else
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea           dstq, [dstq+strideq*2]
+%endif
+    ret
+ALIGN function_align
+.sec:
+    movsx         offq, byte [dirq+8]    ; off1_k0
+%if %1 == 4
+    mova            m1, [tmpq+32*0]
+    punpcklqdq      m1, [tmpq+32*1]
+    movu            m2, [tmpq+offq+32*0]
+    punpcklqdq      m2, [tmpq+offq+32*1] ; k0s0
+    neg           offq
+    movu            m3, [tmpq+offq+32*0]
+    punpcklqdq      m3, [tmpq+offq+32*1] ; k0s1
+%else
+    mova           xm1, [tmpq+32*0]
+    vinserti128     m1, [tmpq+32*1], 1
+    movu           xm2, [tmpq+offq+32*0]
+    vinserti128     m2, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm3, [tmpq+offq+32*0]
+    vinserti128     m3, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+0]    ; off2_k0
+    psubw           m2, m1               ; diff_k0s0
+    psubw           m3, m1               ; diff_k0s1
+    pabsw           m4, m2               ; adiff_k0s0
+    psrlw           m5, m4, [sec_shift+gprsize]
+    psubusw         m0, m6, m5
+    pabsw           m5, m3               ; adiff_k0s1
+    pminsw          m0, m4
+    psrlw           m4, m5, [sec_shift+gprsize]
+    psignw          m0, m2               ; constrain(diff_k0s0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movu            m4, [tmpq+offq+32*0]
+    punpcklqdq      m4, [tmpq+offq+32*1] ; k0s2
+    neg           offq
+    movu            m5, [tmpq+offq+32*0]
+    punpcklqdq      m5, [tmpq+offq+32*1] ; k0s3
+%else
+    movu           xm4, [tmpq+offq+32*0]
+    vinserti128     m4, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm5, [tmpq+offq+32*0]
+    vinserti128     m5, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+9]    ; off1_k1
+    psubw           m4, m1               ; diff_k0s2
+    psubw           m5, m1               ; diff_k0s3
+    psignw          m2, m3               ; constrain(diff_k0s1)
+    pabsw           m3, m4               ; adiff_k0s2
+    paddw           m0, m2
+    psrlw           m2, m3, [sec_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k0s3
+    pminsw          m7, m3
+    psrlw           m3, m2, [sec_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k0s2)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+%if %1 == 4
+    movu            m2, [tmpq+offq+32*0]
+    punpcklqdq      m2, [tmpq+offq+32*1] ; k1s0
+    neg           offq
+    movu            m3, [tmpq+offq+32*0]
+    punpcklqdq      m3, [tmpq+offq+32*1] ; k1s1
+%else
+    movu           xm2, [tmpq+offq+32*0]
+    vinserti128     m2, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm3, [tmpq+offq+32*0]
+    vinserti128     m3, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+1]    ; off2_k1
+    paddw           m0, m7
+    psignw          m4, m5               ; constrain(diff_k0s3)
+    paddw           m0, m4               ; constrain(diff_k0)
+    psubw           m2, m1               ; diff_k1s0
+    psubw           m3, m1               ; diff_k1s1
+    paddw           m0, m0               ; sec_tap_k0
+    pabsw           m4, m2               ; adiff_k1s0
+    psrlw           m5, m4, [sec_shift+gprsize]
+    psubusw         m7, m6, m5
+    pabsw           m5, m3               ; adiff_k1s1
+    pminsw          m7, m4
+    psrlw           m4, m5, [sec_shift+gprsize]
+    psignw          m7, m2               ; constrain(diff_k1s0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movu            m4, [tmpq+offq+32*0]
+    punpcklqdq      m4, [tmpq+offq+32*1] ; k1s2
+    neg           offq
+    movu            m5, [tmpq+offq+32*0]
+    punpcklqdq      m5, [tmpq+offq+32*1] ; k1s3
+%else
+    movu           xm4, [tmpq+offq+32*0]
+    vinserti128     m4, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm5, [tmpq+offq+32*0]
+    vinserti128     m5, [tmpq+offq+32*1], 1
+%endif
+    paddw           m0, m7
+    psubw           m4, m1               ; diff_k1s2
+    psubw           m5, m1               ; diff_k1s3
+    psignw          m2, m3               ; constrain(diff_k1s1)
+    pabsw           m3, m4               ; adiff_k1s2
+    paddw           m0, m2
+    psrlw           m2, m3, [sec_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k1s3
+    pminsw          m7, m3
+    psrlw           m3, m2, [sec_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k1s2)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+    paddw           m0, m7
+    psignw          m4, m5               ; constrain(diff_k1s3)
+    paddw           m0, m4               ; sum
+    psraw           m2, m0, 15
+    paddw           m0, m2
+    pmulhrsw        m0, m8
+    add           tmpq, 32*2
+    paddw           m0, m1
+%if %1 == 4
+    vextracti128   xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r9       ], xm1
+    lea           dstq, [dstq+strideq*4]
+%else
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea           dstq, [dstq+strideq*2]
+%endif
+    ret
+ALIGN function_align
+.pri_sec:
+    movsx         offq, byte [dirq+8]    ; off2_k0
+%if %1 == 4
+    mova            m1, [tmpq+32*0]
+    punpcklqdq      m1, [tmpq+32*1]
+    movu            m2, [tmpq+offq+32*0]
+    punpcklqdq      m2, [tmpq+offq+32*1] ; k0s0
+    neg           offq
+    movu            m3, [tmpq+offq+32*0]
+    punpcklqdq      m3, [tmpq+offq+32*1] ; k0s1
+%else
+    mova           xm1, [dstq+strideq*0]
+    vinserti128     m1, [dstq+strideq*1], 1
+    movu           xm2, [tmpq+offq+32*0]
+    vinserti128     m2, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm3, [tmpq+offq+32*0]
+    vinserti128     m3, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+0]    ; off3_k0
+    pmaxsw         m11, m2, m3
+    pminuw         m12, m2, m3
+    psubw           m2, m1               ; diff_k0s0
+    psubw           m3, m1               ; diff_k0s1
+    pabsw           m4, m2               ; adiff_k0s0
+    psrlw           m5, m4, [sec_shift+gprsize]
+    psubusw         m0, m13, m5
+    pabsw           m5, m3               ; adiff_k0s1
+    pminsw          m0, m4
+    psrlw           m4, m5, [sec_shift+gprsize]
+    psignw          m0, m2               ; constrain(diff_k0s0)
+    psubusw         m2, m13, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movu            m4, [tmpq+offq+32*0]
+    punpcklqdq      m4, [tmpq+offq+32*1] ; k0s2
+    neg           offq
+    movu            m5, [tmpq+offq+32*0]
+    punpcklqdq      m5, [tmpq+offq+32*1] ; k0s3
+%else
+    movu           xm4, [tmpq+offq+32*0]
+    vinserti128     m4, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm5, [tmpq+offq+32*0]
+    vinserti128     m5, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+9]    ; off2_k1
+    psignw          m2, m3               ; constrain(diff_k0s1)
+    pmaxsw         m11, m4
+    pminuw         m12, m4
+    pmaxsw         m11, m5
+    pminuw         m12, m5
+    psubw           m4, m1               ; diff_k0s2
+    psubw           m5, m1               ; diff_k0s3
+    paddw           m0, m2
+    pabsw           m3, m4               ; adiff_k0s2
+    psrlw           m2, m3, [sec_shift+gprsize]
+    psubusw         m7, m13, m2
+    pabsw           m2, m5               ; adiff_k0s3
+    pminsw          m7, m3
+    psrlw           m3, m2, [sec_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k0s2)
+    psubusw         m4, m13, m3
+    pminsw          m4, m2
+%if %1 == 4
+    movu            m2, [tmpq+offq+32*0]
+    punpcklqdq      m2, [tmpq+offq+32*1] ; k1s0
+    neg           offq
+    movu            m3, [tmpq+offq+32*0]
+    punpcklqdq      m3, [tmpq+offq+32*1] ; k1s1
+%else
+    movu           xm2, [tmpq+offq+32*0]
+    vinserti128     m2, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm3, [tmpq+offq+32*0]
+    vinserti128     m3, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+1]    ; off3_k1
+    paddw           m0, m7
+    psignw          m4, m5               ; constrain(diff_k0s3)
+    pmaxsw         m11, m2
+    pminuw         m12, m2
+    pmaxsw         m11, m3
+    pminuw         m12, m3
+    paddw           m0, m4               ; constrain(diff_k0)
+    psubw           m2, m1               ; diff_k1s0
+    psubw           m3, m1               ; diff_k1s1
+    paddw           m0, m0               ; sec_tap_k0
+    pabsw           m4, m2               ; adiff_k1s0
+    psrlw           m5, m4, [sec_shift+gprsize]
+    psubusw         m7, m13, m5
+    pabsw           m5, m3               ; adiff_k1s1
+    pminsw          m7, m4
+    psrlw           m4, m5, [sec_shift+gprsize]
+    psignw          m7, m2               ; constrain(diff_k1s0)
+    psubusw         m2, m13, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movu            m4, [tmpq+offq+32*0]
+    punpcklqdq      m4, [tmpq+offq+32*1] ; k1s2
+    neg           offq
+    movu            m5, [tmpq+offq+32*0]
+    punpcklqdq      m5, [tmpq+offq+32*1] ; k1s3
+%else
+    movu           xm4, [tmpq+offq+32*0]
+    vinserti128     m4, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm5, [tmpq+offq+32*0]
+    vinserti128     m5, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+4]    ; off1_k0
+    paddw           m0, m7
+    psignw          m2, m3               ; constrain(diff_k1s1)
+    pmaxsw         m11, m4
+    pminuw         m12, m4
+    pmaxsw         m11, m5
+    pminuw         m12, m5
+    psubw           m4, m1               ; diff_k1s2
+    psubw           m5, m1               ; diff_k1s3
+    pabsw           m3, m4               ; adiff_k1s2
+    paddw           m0, m2
+    psrlw           m2, m3, [sec_shift+gprsize]
+    psubusw         m7, m13, m2
+    pabsw           m2, m5               ; adiff_k1s3
+    pminsw          m7, m3
+    psrlw           m3, m2, [sec_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k1s2)
+    psubusw         m4, m13, m3
+    pminsw          m4, m2
+    paddw           m0, m7
+%if %1 == 4
+    movu            m2, [tmpq+offq+32*0]
+    punpcklqdq      m2, [tmpq+offq+32*1] ; k0p0
+    neg           offq
+    movu            m3, [tmpq+offq+32*0]
+    punpcklqdq      m3, [tmpq+offq+32*1] ; k0p1
+%else
+    movu           xm2, [tmpq+offq+32*0]
+    vinserti128     m2, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm3, [tmpq+offq+32*0]
+    vinserti128     m3, [tmpq+offq+32*1], 1
+%endif
+    movsx         offq, byte [dirq+5]    ; off1_k1
+    psignw          m4, m5               ; constrain(diff_k1s3)
+    pmaxsw         m11, m2
+    pminuw         m12, m2
+    pmaxsw         m11, m3
+    pminuw         m12, m3
+    psubw           m2, m1               ; diff_k0p0
+    psubw           m3, m1               ; diff_k0p1
+    paddw           m0, m4
+    pabsw           m4, m2               ; adiff_k0p0
+    psrlw           m5, m4, [pri_shift+gprsize]
+    psubusw         m7, m6, m5
+    pabsw           m5, m3               ; adiff_k0p1
+    pminsw          m7, m4
+    psrlw           m4, m5, [pri_shift+gprsize]
+    psignw          m7, m2               ; constrain(diff_k0p0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movu            m4, [tmpq+offq+32*0]
+    punpcklqdq      m4, [tmpq+offq+32*1] ; k1p0
+    neg           offq
+    movu            m5, [tmpq+offq+32*0]
+    punpcklqdq      m5, [tmpq+offq+32*1] ; k1p1
+%else
+    movu           xm4, [tmpq+offq+32*0]
+    vinserti128     m4, [tmpq+offq+32*1], 1
+    neg           offq
+    movu           xm5, [tmpq+offq+32*0]
+    vinserti128     m5, [tmpq+offq+32*1], 1
+%endif
+    psignw          m2, m3               ; constrain(diff_k0p1)
+    paddw           m7, m2               ; constrain(diff_k0)
+    pmaxsw         m11, m4
+    pminuw         m12, m4
+    pmaxsw         m11, m5
+    pminuw         m12, m5
+    psubw           m4, m1               ; diff_k1p0
+    psubw           m5, m1               ; diff_k1p1
+    pabsw           m3, m4               ; adiff_k1p0
+    pmullw          m7, m9               ; pri_tap_k0
+    paddw           m0, m7
+    psrlw           m2, m3, [pri_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k1p1
+    pminsw          m7, m3
+    psrlw           m3, m2, [pri_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k1p0)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+    psignw          m4, m5               ; constrain(diff_k1p1)
+    paddw           m7, m4               ; constrain(diff_k1)
+    pmullw          m7, m10              ; pri_tap_k1
+    paddw           m0, m7               ; sum
+    psraw           m2, m0, 15
+    paddw           m0, m2
+    pmulhrsw        m0, m8
+    add           tmpq, 32*2
+    pmaxsw         m11, m1
+    pminuw         m12, m1
+    paddw           m0, m1
+    pminsw          m0, m11
+    pmaxsw          m0, m12
+%if %1 == 4
+    vextracti128   xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r9       ], xm1
+    lea           dstq, [dstq+strideq*4]
+%else
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea           dstq, [dstq+strideq*2]
+%endif
+    ret
+%endif
+%endmacro
+
+INIT_YMM avx2
+cglobal cdef_filter_4x4_16bpc, 5, 10, 9, 16*10, dst, stride, left, top, bot, \
+                                                pri, sec, edge
+%if WIN64
+    %define         px  rsp+16*6
+    %define       offq  r8
+    %define  pri_shift  rsp+16*2
+    %define  sec_shift  rsp+16*3
+%else
+    %define         px  rsp+16*4
+    %define       offq  r4
+    %define  pri_shift  rsp+16*0
+    %define  sec_shift  rsp+16*1
+%endif
+    %define       base  r8-dir_table4
+    mov          edged, r9m
+    lea             r8, [dir_table4]
+    movu           xm0, [dstq+strideq*0]
+    movu           xm1, [dstq+strideq*1]
+    lea             r9, [strideq*3]
+    movu           xm2, [dstq+strideq*2]
+    movu           xm3, [dstq+r9       ]
+    vpbroadcastd    m7, [base+pw_m16384]
+    mova   [px+16*0+0], xm0
+    mova   [px+16*1+0], xm1
+    mova   [px+16*2+0], xm2
+    mova   [px+16*3+0], xm3
+    test         edgeb, 4 ; HAVE_TOP
+    jz .no_top
+    movu           xm0, [topq+strideq*0]
+    movu           xm1, [topq+strideq*1]
+    mova   [px-16*2+0], xm0
+    mova   [px-16*1+0], xm1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .top_no_left
+    movd           xm0, [topq+strideq*0-4]
+    movd           xm1, [topq+strideq*1-4]
+    movd   [px-16*2-4], xm0
+    movd   [px-16*1-4], xm1
+    jmp .top_done
+.no_top:
+    mova   [px-16*2+0], m7
+.top_no_left:
+    movd   [px-16*2-4], xm7
+    movd   [px-16*1-4], xm7
+.top_done:
+    test         edgeb, 8 ; HAVE_BOTTOM
+    jz .no_bottom
+    movu           xm0, [botq+strideq*0]
+    movu           xm1, [botq+strideq*1]
+    mova   [px+16*4+0], xm0
+    mova   [px+16*5+0], xm1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .bottom_no_left
+    movd           xm0, [botq+strideq*0-4]
+    movd           xm1, [botq+strideq*1-4]
+    movd   [px+16*4-4], xm0
+    movd   [px+16*5-4], xm1
+    jmp .bottom_done
+.no_bottom:
+    mova   [px+16*4+0], m7
+.bottom_no_left:
+    movd   [px+16*4-4], xm7
+    movd   [px+16*5-4], xm7
+.bottom_done:
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .no_left
+    movd           xm0, [leftq+4*0]
+    movd           xm1, [leftq+4*1]
+    movd           xm2, [leftq+4*2]
+    movd           xm3, [leftq+4*3]
+    movd   [px+16*0-4], xm0
+    movd   [px+16*1-4], xm1
+    movd   [px+16*2-4], xm2
+    movd   [px+16*3-4], xm3
+    jmp .left_done
+.no_left:
+    REPX {movd [px+16*x-4], xm7}, 0, 1, 2, 3
+.left_done:
+    test         edgeb, 2 ; HAVE_RIGHT
+    jnz .padding_done
+    REPX {movd [px+16*x+8], xm7}, -2, -1, 0, 1, 2, 3, 4, 5
+.padding_done:
+    CDEF_FILTER      4, 4
+
+cglobal cdef_filter_4x8_16bpc, 5, 10, 9, 16*14, dst, stride, left, top, bot, \
+                                                pri, sec, edge
+    mov          edged, r9m
+    movu           xm0, [dstq+strideq*0]
+    movu           xm1, [dstq+strideq*1]
+    lea             r9, [strideq*3]
+    movu           xm2, [dstq+strideq*2]
+    movu           xm3, [dstq+r9       ]
+    lea             r6, [dstq+strideq*4]
+    movu           xm4, [r6  +strideq*0]
+    movu           xm5, [r6  +strideq*1]
+    movu           xm6, [r6  +strideq*2]
+    movu           xm7, [r6  +r9       ]
+    lea             r8, [dir_table4]
+    mova   [px+16*0+0], xm0
+    mova   [px+16*1+0], xm1
+    mova   [px+16*2+0], xm2
+    mova   [px+16*3+0], xm3
+    mova   [px+16*4+0], xm4
+    mova   [px+16*5+0], xm5
+    mova   [px+16*6+0], xm6
+    mova   [px+16*7+0], xm7
+    vpbroadcastd    m7, [base+pw_m16384]
+    test         edgeb, 4 ; HAVE_TOP
+    jz .no_top
+    movu           xm0, [topq+strideq*0]
+    movu           xm1, [topq+strideq*1]
+    mova   [px-16*2+0], xm0
+    mova   [px-16*1+0], xm1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .top_no_left
+    movd           xm0, [topq+strideq*0-4]
+    movd           xm1, [topq+strideq*1-4]
+    movd   [px-16*2-4], xm0
+    movd   [px-16*1-4], xm1
+    jmp .top_done
+.no_top:
+    mova   [px-16*2+0], m7
+.top_no_left:
+    movd   [px-16*2-4], xm7
+    movd   [px-16*1-4], xm7
+.top_done:
+    test         edgeb, 8 ; HAVE_BOTTOM
+    jz .no_bottom
+    movu           xm0, [botq+strideq*0]
+    movu           xm1, [botq+strideq*1]
+    mova   [px+16*8+0], xm0
+    mova   [px+16*9+0], xm1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .bottom_no_left
+    movd           xm0, [botq+strideq*0-4]
+    movd           xm1, [botq+strideq*1-4]
+    movd   [px+16*8-4], xm0
+    movd   [px+16*9-4], xm1
+    jmp .bottom_done
+.no_bottom:
+    mova   [px+16*8+0], m7
+.bottom_no_left:
+    movd   [px+16*8-4], xm7
+    movd   [px+16*9-4], xm7
+.bottom_done:
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .no_left
+    movd           xm0, [leftq+4*0]
+    movd           xm1, [leftq+4*1]
+    movd           xm2, [leftq+4*2]
+    movd           xm3, [leftq+4*3]
+    movd   [px+16*0-4], xm0
+    movd   [px+16*1-4], xm1
+    movd   [px+16*2-4], xm2
+    movd   [px+16*3-4], xm3
+    movd           xm0, [leftq+4*4]
+    movd           xm1, [leftq+4*5]
+    movd           xm2, [leftq+4*6]
+    movd           xm3, [leftq+4*7]
+    movd   [px+16*4-4], xm0
+    movd   [px+16*5-4], xm1
+    movd   [px+16*6-4], xm2
+    movd   [px+16*7-4], xm3
+    jmp .left_done
+.no_left:
+    REPX {movd [px+16*x-4], xm7}, 0, 1, 2, 3, 4, 5, 6, 7
+.left_done:
+    test         edgeb, 2 ; HAVE_RIGHT
+    jnz .padding_done
+    REPX {movd [px+16*x+8], xm7}, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+.padding_done:
+    CDEF_FILTER      4, 8
+
+cglobal cdef_filter_8x8_16bpc, 5, 9, 9, 32*13, dst, stride, left, top, bot, \
+                                               pri, sec, edge
+%if WIN64
+    %define         px  rsp+32*4
+%else
+    %define         px  rsp+32*3
+%endif
+    %define       base  r8-dir_table8
+    mov          edged, r9m
+    movu            m0, [dstq+strideq*0]
+    movu            m1, [dstq+strideq*1]
+    lea             r6, [dstq+strideq*2]
+    movu            m2, [r6  +strideq*0]
+    movu            m3, [r6  +strideq*1]
+    lea             r6, [r6  +strideq*2]
+    movu            m4, [r6  +strideq*0]
+    movu            m5, [r6  +strideq*1]
+    lea             r6, [r6  +strideq*2]
+    movu            m6, [r6  +strideq*0]
+    movu            m7, [r6  +strideq*1]
+    lea             r8, [dir_table8]
+    mova   [px+32*0+0], m0
+    mova   [px+32*1+0], m1
+    mova   [px+32*2+0], m2
+    mova   [px+32*3+0], m3
+    mova   [px+32*4+0], m4
+    mova   [px+32*5+0], m5
+    mova   [px+32*6+0], m6
+    mova   [px+32*7+0], m7
+    vpbroadcastd    m7, [base+pw_m16384]
+    test         edgeb, 4 ; HAVE_TOP
+    jz .no_top
+    movu            m0, [topq+strideq*0]
+    movu            m1, [topq+strideq*1]
+    mova   [px-32*2+0], m0
+    mova   [px-32*1+0], m1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .top_no_left
+    movd           xm0, [topq+strideq*0-4]
+    movd           xm1, [topq+strideq*1-4]
+    movd   [px-32*2-4], xm0
+    movd   [px-32*1-4], xm1
+    jmp .top_done
+.no_top:
+    mova   [px-32*2+0], m7
+    mova   [px-32*1+0], m7
+.top_no_left:
+    movd   [px-32*2-4], xm7
+    movd   [px-32*1-4], xm7
+.top_done:
+    test         edgeb, 8 ; HAVE_BOTTOM
+    jz .no_bottom
+    movu            m0, [botq+strideq*0]
+    movu            m1, [botq+strideq*1]
+    mova   [px+32*8+0], m0
+    mova   [px+32*9+0], m1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .bottom_no_left
+    movd           xm0, [botq+strideq*0-4]
+    movd           xm1, [botq+strideq*1-4]
+    movd   [px+32*8-4], xm0
+    movd   [px+32*9-4], xm1
+    jmp .bottom_done
+.no_bottom:
+    mova   [px+32*8+0], m7
+    mova   [px+32*9+0], m7
+.bottom_no_left:
+    movd   [px+32*8-4], xm7
+    movd   [px+32*9-4], xm7
+.bottom_done:
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .no_left
+    movd           xm0, [leftq+4*0]
+    movd           xm1, [leftq+4*1]
+    movd           xm2, [leftq+4*2]
+    movd           xm3, [leftq+4*3]
+    movd   [px+32*0-4], xm0
+    movd   [px+32*1-4], xm1
+    movd   [px+32*2-4], xm2
+    movd   [px+32*3-4], xm3
+    movd           xm0, [leftq+4*4]
+    movd           xm1, [leftq+4*5]
+    movd           xm2, [leftq+4*6]
+    movd           xm3, [leftq+4*7]
+    movd   [px+32*4-4], xm0
+    movd   [px+32*5-4], xm1
+    movd   [px+32*6-4], xm2
+    movd   [px+32*7-4], xm3
+    jmp .left_done
+.no_left:
+    REPX {movd [px+32*x-4], xm7}, 0, 1, 2, 3, 4, 5, 6, 7
+.left_done:
+    test         edgeb, 2 ; HAVE_RIGHT
+    jnz .padding_done
+    REPX {movd [px+32*x+16], xm7}, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+.padding_done:
+    CDEF_FILTER      8, 8
+
+cglobal cdef_dir_16bpc, 4, 7, 6, src, stride, var, bdmax
+    lea             r6, [dir_shift]
+    shr         bdmaxd, 11 ; 0 for 10bpc, 1 for 12bpc
+    vpbroadcastd    m4, [r6+bdmaxq*4]
+    lea             r6, [strideq*3]
+    mova           xm0, [srcq+strideq*0]
+    mova           xm1, [srcq+strideq*1]
+    mova           xm2, [srcq+strideq*2]
+    mova           xm3, [srcq+r6       ]
+    lea           srcq, [srcq+strideq*4]
+    vinserti128     m0, [srcq+r6       ], 1
+    vinserti128     m1, [srcq+strideq*2], 1
+    vinserti128     m2, [srcq+strideq*1], 1
+    vinserti128     m3, [srcq+strideq*0], 1
+    REPX {pmulhuw x, m4}, m0, m1, m2, m3
+    jmp mangle(private_prefix %+ _cdef_dir_8bpc %+ SUFFIX).main
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/cdef16_avx512.asm b/media/libdav1d/src/src/x86/cdef16_avx512.asm
new file mode 100644
index 0000000000..6d625a02a0
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cdef16_avx512.asm
@@ -0,0 +1,622 @@
+; Copyright © 2022, VideoLAN and dav1d authors
+; Copyright © 2022, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+cdef_perm:     db  2, 18, 16, 18, 24, 19,  0, 19, 25, 20,  1, 20, 26, 21,  2, 21
+               db  3, 26,  3, 26, 28, 27,  4, 27, 29, 28, -1, 28, 30, 29, -1, 29
+               db  0, 34, 17, 34, 16, 35,  8, 35, 17, 36,  9, 36, 18, 37, 10, 37
+               db  1, 42, 11, 42, 20, 43, 12, 43, 21, 44, -1, 44, 22, 45, -1, 45
+end_perm4:     db  1,  2,  5,  6,  9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30
+               db 33, 34, 37, 38, 41, 42, 45, 46, 49, 50, 53, 54, 57, 58, 61, 62
+edge_mask4:    dw 0xff99, 0xff88, 0xff11, 0xff00 ; 0100, 0101, 0110, 0111
+               dw 0x99ff, 0x88ff, 0x11ff, 0x00ff ; 1000, 1001, 1010, 1011
+               dw 0x9999, 0x8888, 0x1111, 0x0000 ; 1100, 1101, 1110, 1111
+pri_taps4:     dw 64, 32, 48, 48                 ; left-shifted by 4
+cdef_dirs4:    dw  8, 16,  8, 15, -7,-14,  1, -6
+               dw  1,  2,  1, 10,  9, 18,  8, 17
+               dw  8, 16,  8, 15, -7,-14,  1, -6
+deint_shuf:    db  0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+cdef_dirs8:    db 32, 64, 32, 62,-30,-60,  2,-28
+               db  2,  4,  2, 36, 34, 68, 32, 66
+               db 32, 64, 32, 62,-30,-60,  2,-28
+pri_taps8:     dw  4,  4,  2,  2,  3,  3,  3,  3
+sec_taps4:     dw 32, 16
+pw_m16384:     times 2 dw -16384
+pw_2048:       times 2 dw 2048
+pd_268435568:  dd 268435568                      ; (1 << 28) + (7 << 4)
+edge_mask8:    dw 0x2121, 0x2020, 0x0101
+
+SECTION .text
+
+%macro CONSTRAIN 7 ; dst, p, px, zero, tresh, shift, tmp
+    psubw           %1, %2, %3
+    pabsw           %1, %1
+    vpcmpgtw        k1, %3, %2
+    vpsrlvw         %7, %1, %6
+    psubusw         %7, %5, %7
+    pminsw          %1, %7
+    vpsubw      %1{k1}, %4, %1
+%endmacro
+
+; t0 t1 t2 t3 t4 t5 t6 t7   L4 L5 20 21 22 23 24 25
+; T0 T1 T2 T3 T4 T5 T6 T7   L6 L7 30 31 32 33 34 35
+; L0 L1 00 01 02 03 04 05   b0 b1 b2 b3 b4 b5 b6 b7
+; L2 L3 10 11 12 13 14 15   B0 B1 B2 B3 B4 B5 B6 B7
+
+INIT_ZMM avx512icl
+cglobal cdef_filter_4x4_16bpc, 5, 7, 16, dst, stride, left, top, bot, \
+                                         pri, sec, dir, damping, edge
+%define base r6-cdef_dirs4
+    lea             r6, [cdef_dirs4]
+    movu           xm3, [dstq+strideq*0]
+    vinserti32x4   ym3, [dstq+strideq*1], 1
+    mova           xm2, [leftq]
+    lea             r2, [dstq+strideq*2]
+    vinserti32x4    m3, [r2+strideq*0], 2
+    mova            m5, [base+cdef_perm]
+    vinserti32x4    m3, [r2+strideq*1], 3
+    vpermt2d        m2, m5, m3
+    vinserti32x4    m1, m2, [topq+strideq*0-4], 0
+    vinserti32x4    m1, [topq+strideq*1-4], 1
+    mov            r3d, edgem
+    movifnidn     prid, prim
+    punpcklwd       m3, m3     ; px
+    psrlw           m5, 8
+    vpbroadcastd    m0, [base+pd_268435568]
+    pxor           m12, m12
+    cmp            r3d, 0x0f
+    jne .mask_edges
+    vinserti32x4    m2, [botq+strideq*0-4], 2
+    vinserti32x4    m2, [botq+strideq*1-4], 3
+.main:
+    test          prid, prid
+    jz .sec_only
+    lzcnt          r4d, prid
+    rorx           r3d, prid, 2
+    vpbroadcastw   m13, prim
+    cmp     dword r10m, 0xfff  ; if (bpc == 12)
+    cmove         prid, r3d    ;     pri >>= 2
+    mov            r3d, dampingm
+    and           prid, 4
+    sub            r3d, 31
+    vpbroadcastd   m15, [base+pri_taps4+priq]
+    xor           prid, prid
+    add            r4d, r3d
+    cmovns        prid, r4d    ; pri_shift
+    mov            r4d, dirm
+    vpbroadcastw   m14, prid
+    mov            r5d, secm
+    vpbroadcastd    m9, [base+cdef_dirs4+(r4+2)*4]
+    call .constrain
+    test           r5d, r5d
+    jz .end_no_clip
+    lzcnt          r5d, r5d
+    vpbroadcastw   m13, secm
+    add            r3d, r5d
+    pminuw          m6, m3, m8
+    pmaxsw          m7, m3, m8
+    pminuw          m6, m9
+    pmaxsw          m7, m9
+    call .constrain_sec
+    pminuw          m6, m8
+    pmaxsw          m7, m8
+    pminuw          m6, m9
+    pmaxsw          m7, m9
+    vpbroadcastd    m9, [base+cdef_dirs4+(r4+0)*4]
+    call .constrain
+    pminuw          m6, m8
+    pmaxsw          m7, m8
+    pminuw          m6, m9
+    pmaxsw          m7, m9
+    psrldq          m8, m6, 2
+    vpshldd         m3, m0, 8
+    psrldq          m9, m7, 2
+    paddd           m0, m3
+    pminuw          m6, m8
+    psrldq          m0, 1
+    pmaxsw          m7, m9
+    pmaxsw          m0, m6
+    pminsw          m0, m7
+    vpmovdw        ym0, m0
+    jmp .end
+.sec_only:
+    tzcnt          r5d, secm
+    mov            r3d, dampingm
+    vpbroadcastw   m13, secm
+    mov            r4d, dirm
+    sub            r3d, r5d    ; sec_shift
+    call .constrain_sec
+    vpbroadcastd    m9, [base+cdef_dirs4+(r4+0)*4]
+    call .constrain
+.end_no_clip:
+    mova           ym1, [base+end_perm4]
+    vpshldd         m3, m0, 8  ; (px << 8) + ((sum > -8) << 4)
+    paddd           m0, m3     ; (px << 8) + ((sum + (sum > -8) + 7) << 4)
+    vpermb          m0, m1, m0
+.end:
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti32x4  xm0, ym0, 1
+    movq   [r2+strideq*0], xm0
+    movhps [r2+strideq*1], xm0
+    RET
+.mask_edges:
+    vpbroadcastd    m6, [base+pw_m16384]
+    test           r3b, 0x08
+    jz .mask_edges_no_bottom  ; avoid buffer overread
+    vinserti32x4    m2, [botq+strideq*0-4], 2
+    vinserti32x4    m2, [botq+strideq*1-4], 3
+    kmovw           k1, [base+edge_mask4-8+r3*2]
+    jmp .mask_edges_main
+.mask_edges_no_bottom:
+    kmovw           k1, [base+edge_mask4+8+r3*2]
+.mask_edges_main:
+    or             r3d, 0x04
+    vmovdqa32   m1{k1}, m6     ; edge pixels = -16384
+    kmovw           k1, [base+edge_mask4-8+r3*2]
+    vmovdqa32   m2{k1}, m6
+    jmp .main
+.constrain_sec:
+    vpbroadcastd    m9, [base+cdef_dirs4+(r4+4)*4]
+    vpbroadcastw   m14, r3d
+    vpbroadcastd   m15, [base+sec_taps4]
+.constrain:
+    paddw           m8, m5, m9
+    vpermi2w        m8, m1, m2 ; k0p0 k1p0
+    psubw           m9, m5, m9
+    vpermi2w        m9, m1, m2 ; k0p1 k1p1
+    CONSTRAIN      m10, m8, m3, m12, m13, m14, m11
+    vpdpwssd        m0, m10, m15
+    CONSTRAIN      m10, m9, m3, m12, m13, m14, m11
+    vpdpwssd        m0, m10, m15
+    ret
+
+; t0 t1 t2 t3 t4 t5 t6 t7   L4 L5 20 21 22 23 24 25   Lc Ld 60 61 62 63 64 65
+; T0 T1 T2 T3 T4 T5 T6 T7   L6 L7 30 31 32 33 34 35   Le Lf 70 71 72 73 74 75
+; L0 L1 00 01 02 03 04 05   L8 L9 40 41 42 43 44 45   b0 b1 b2 b3 b4 b5 b6 b7
+; L2 L3 10 11 12 13 14 15   La Lb 50 51 52 53 54 55   B0 B1 B2 B3 B4 B5 B6 B7
+
+cglobal cdef_filter_4x8_16bpc, 5, 7, 22, dst, stride, left, top, bot, \
+                                         pri, sec, dir, damping, edge
+    lea             r6, [cdef_dirs4]
+    movu          xm18, [dstq+strideq*0]
+    vinserti128   ym18, [dstq+strideq*1], 1
+    mova           xm1, [leftq+16*0]
+    mova           xm2, [leftq+16*1]
+    lea             r2, [strideq*3]
+    vinserti32x4   m18, [dstq+strideq*2], 2
+    mova            m5, [base+cdef_perm]
+    vinserti32x4   m18, [dstq+r2       ], 3
+    vpermt2d        m1, m5, m18
+    vinserti32x4    m0, m1, [topq+strideq*0-4], 0
+    vinserti32x4    m0, [topq+strideq*1-4], 1
+    lea             r3, [dstq+strideq*4]
+    movu          xm19, [r3+strideq*0]
+    vinserti128   ym19, [r3+strideq*1], 1
+    vinserti32x4   m19, [r3+strideq*2], 2
+    vinserti32x4   m19, [r3+r2       ], 3
+    mov            r3d, edgem
+    movifnidn     prid, prim
+    vpermt2d        m2, m5, m19
+    vpbroadcastd   m16, [base+pd_268435568]
+    pxor           m12, m12
+    punpcklwd      m18, m18    ; px (top)
+    psrlw           m5, 8
+    punpcklwd      m19, m19    ; px (bottom)
+    mova           m17, m16
+    vshufi32x4      m1, m2, q3210
+    cmp            r3d, 0x0f
+    jne .mask_edges
+    vinserti32x4    m2, [botq+strideq*0-4], 2
+    vinserti32x4    m2, [botq+strideq*1-4], 3
+.main:
+    test          prid, prid
+    jz .sec_only
+    lzcnt          r4d, prid
+    rorx           r3d, prid, 2
+    vpbroadcastw   m13, prim
+    cmp     dword r10m, 0xfff  ; if (bpc == 12)
+    cmove         prid, r3d    ;     pri >>= 2
+    mov            r3d, dampingm
+    and           prid, 4
+    sub            r3d, 31
+    vpbroadcastd   m15, [base+pri_taps4+priq]
+    xor           prid, prid
+    add            r4d, r3d
+    cmovns        prid, r4d    ; pri_shift
+    mov            r4d, dirm
+    vpbroadcastw   m14, prid
+    mov            r5d, secm
+    vpbroadcastd    m9, [base+cdef_dirs4+(r4+2)*4]
+    call .constrain
+    test           r5d, r5d
+    jz .end_no_clip
+    lzcnt          r5d, r5d
+    vpbroadcastw   m13, secm
+    add            r3d, r5d
+    pminuw          m3, m18, m6
+    pmaxsw          m4, m18, m6
+    pminuw         m20, m19, m7
+    pmaxsw         m21, m19, m7
+    pminuw          m3, m8
+    pmaxsw          m4, m8
+    pminuw         m20, m9
+    pmaxsw         m21, m9
+    call .constrain_sec
+    pminuw          m3, m6
+    pmaxsw          m4, m6
+    pminuw         m20, m7
+    pmaxsw         m21, m7
+    pminuw          m3, m8
+    pmaxsw          m4, m8
+    pminuw         m20, m9
+    pmaxsw         m21, m9
+    vpbroadcastd    m9, [base+cdef_dirs4+(r4+0)*4]
+    call .constrain
+    pminuw          m3, m6
+    pmaxsw          m4, m6
+    mov             r3, 0xcccccccccccccccc
+    pminuw         m20, m7
+    pmaxsw         m21, m7
+    kmovq           k1, r3
+    pminuw          m3, m8
+    pmaxsw          m4, m8
+    pminuw         m20, m9
+    pmaxsw         m21, m9
+    vbroadcasti32x4 m0, [base+deint_shuf]
+    vpshldd         m6, m20, m3, 16
+    vmovdqu8    m3{k1}, m20
+    vpshldd        m18, m16, 8
+    vpshldd         m7, m21, m4, 16
+    vmovdqu8    m4{k1}, m21
+    vpshldd        m19, m17, 8
+    pminuw          m3, m6
+    paddd          m16, m18
+    pmaxsw          m4, m7
+    paddd          m17, m19
+    psrldq         m16, 1
+    palignr    m16{k1}, m17, m17, 15
+    lea             r6, [dstq+strideq*4]
+    pmaxsw         m16, m3
+    pminsw         m16, m4
+    pshufb         m16, m0
+    movq   [dstq+strideq*0], xm16
+    movhps [r6  +strideq*0], xm16
+    vextracti128  xm17, ym16, 1
+    movq   [dstq+strideq*1], xm17
+    movhps [r6  +strideq*1], xm17
+    vextracti32x4  xm17, m16, 2
+    movq   [dstq+strideq*2], xm17
+    movhps [r6  +strideq*2], xm17
+    vextracti32x4  xm16, m16, 3
+    movq   [dstq+r2       ], xm16
+    movhps [r6  +r2       ], xm16
+    RET
+.sec_only:
+    mov            r4d, dirm
+    tzcnt          r5d, secm
+    mov            r3d, dampingm
+    vpbroadcastw   m13, secm
+    sub            r3d, r5d    ; sec_shift
+    call .constrain_sec
+    vpbroadcastd    m9, [base+cdef_dirs4+(r4+0)*4]
+    call .constrain
+.end_no_clip:
+    mova          ym20, [base+end_perm4]
+    vpshldd        m18, m16, 8 ; (px << 8) + ((sum > -8) << 4)
+    vpshldd        m19, m17, 8
+    paddd          m16, m18    ; (px << 8) + ((sum + (sum > -8) + 7) << 4)
+    paddd          m17, m19
+    vpermb         m16, m20, m16
+    vpermb         m17, m20, m17
+    movq   [dstq+strideq*0], xm16
+    movhps [dstq+strideq*1], xm16
+    vextracti128  xm16, ym16, 1
+    movq   [dstq+strideq*2], xm16
+    movhps [dstq+r2       ], xm16
+    lea           dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm17
+    movhps [dstq+strideq*1], xm17
+    vextracti128  xm17, ym17, 1
+    movq   [dstq+strideq*2], xm17
+    movhps [dstq+r2       ], xm17
+    RET
+.mask_edges:
+    vpbroadcastd    m6, [base+pw_m16384]
+    test           r3b, 0x08
+    jz .mask_edges_no_bottom   ; avoid buffer overread
+    vinserti32x4    m2, [botq+strideq*0-4], 2
+    vinserti32x4    m2, [botq+strideq*1-4], 3
+    kmovw           k1, [base+edge_mask4-8+r3*2]
+    jmp .mask_edges_main
+.mask_edges_no_bottom:
+    kmovw           k1, [base+edge_mask4+8+r3*2]
+.mask_edges_main:
+    mov            r4d, r3d
+    or             r3d, 0x0c
+    vmovdqa32   m0{k1}, m6     ; edge pixels = -16384
+    kmovw           k1, [base+edge_mask4-8+r3*2]
+    or             r4d, 0x04
+    vmovdqa32   m1{k1}, m6
+    kmovw           k1, [base+edge_mask4-8+r4*2]
+    vmovdqa32   m2{k1}, m6
+    jmp .main
+.constrain_sec:
+    vpbroadcastd    m9, [base+cdef_dirs4+(r4+4)*4]
+    vpbroadcastw   m14, r3d
+    vpbroadcastd   m15, [base+sec_taps4]
+.constrain:
+    paddw           m7, m5, m9
+    mova            m6, m0
+    vpermt2w        m6, m7, m1 ; k0p0 k1p0 (top)
+    psubw           m9, m5, m9
+    mova            m8, m0
+    vpermi2w        m7, m1, m2 ; k0p0 k1p0 (bottom)
+    CONSTRAIN      m10, m6, m18, m12, m13, m14, m11
+    vpermt2w        m8, m9, m1 ; k0p1 k1p1 (top)
+    vpdpwssd       m16, m10, m15
+    CONSTRAIN      m10, m7, m19, m12, m13, m14, m11
+    vpermi2w        m9, m1, m2 ; k0p1 k1p1 (bottom)
+    vpdpwssd       m17, m10, m15
+    CONSTRAIN      m10, m8, m18, m12, m13, m14, m11
+    vpdpwssd       m16, m10, m15
+    CONSTRAIN      m10, m9, m19, m12, m13, m14, m11
+    vpdpwssd       m17, m10, m15
+    ret
+
+cglobal cdef_filter_8x8_16bpc, 5, 7, 22, 64*6, dst, stride, left, top, bot, \
+                                               pri, sec, dir, damping, edge
+%define base r6-cdef_dirs8
+    lea             r6, [cdef_dirs8]
+    movu          ym17, [dstq+strideq*0]
+    vinserti32x8   m17, [dstq+strideq*1], 1
+    movq           xm4, [leftq+8*0]
+    movq           xm5, [leftq+8*1]
+    psrld           m2, [base+cdef_perm], 16
+    movq           xm6, [leftq+8*2]
+    movq           xm7, [leftq+8*3]
+    lea             r2, [strideq*3]
+    movu          ym16, [topq+strideq*0-4]
+    vinserti32x8   m16, [topq+strideq*1-4], 1
+    lea             r3, [dstq+strideq*4]
+    movu          ym18, [dstq+strideq*2]
+    vinserti32x8   m18, [dstq+r2       ], 1
+    movu          ym19, [r3+strideq*0]
+    vinserti32x8   m19, [r3+strideq*1], 1
+    movu          ym20, [r3+strideq*2]
+    vinserti32x8   m20, [r3+r2       ], 1
+    vshufi32x4      m0, m17, m18, q2020 ; px (top)
+    mov            r3d, edgem
+    vshufi32x4      m1, m19, m20, q2020 ; px (bottom)
+    movifnidn     prid, prim
+    vpermt2d       m17, m2, m4
+    vpermt2d       m18, m2, m5
+    pxor           m12, m12
+    vpermt2d       m19, m2, m6
+    vpermt2d       m20, m2, m7
+    cmp            r3d, 0x0f
+    jne .mask_edges
+    movu          ym21, [botq+strideq*0-4]
+    vinserti32x8   m21, [botq+strideq*1-4], 1
+.main:
+    mova    [rsp+64*0], m16    ; top
+    mova    [rsp+64*1], m17    ; 0 1
+    mova    [rsp+64*2], m18    ; 2 3
+    mova    [rsp+64*3], m19    ; 4 5
+    mova    [rsp+64*4], m20    ; 6 7
+    mova    [rsp+64*5], m21    ; bottom
+    test          prid, prid
+    jz .sec_only
+    lzcnt          r4d, prid
+    rorx           r3d, prid, 2
+    vpbroadcastw   m13, prim
+    cmp     dword r10m, 0xfff  ; if (bpc == 12)
+    cmove         prid, r3d    ;     pri >>= 2
+    mov            r3d, dampingm
+    and           prid, 4
+    sub            r3d, 31
+    add            r4d, r3d    ; pri_shift
+    vpbroadcastw   m14, r4d
+    mov            r4d, dirm
+    vpbroadcastd    m2, [base+pri_taps8+priq*2+0]
+    vpbroadcastd    m3, [base+pri_taps8+priq*2+4]
+    movsx           r5, byte [base+cdef_dirs8+(r4+2)*2+0] ; k0off1
+    pmaxsw         m14, m12
+    call .constrain
+    mov            r5d, secm
+    pmullw         m16, m8, m2
+    pmullw         m17, m9, m2
+    test           r5d, r5d
+    jnz .pri_sec
+    movsx           r5, byte [base+cdef_dirs8+(r4+2)*2+1] ; k1off1
+    call .constrain
+    pmullw          m8, m3
+    pmullw          m9, m3
+    jmp .end_no_clip
+.pri_sec:
+    lzcnt          r5d, r5d
+    add            r3d, r5d    ; sec_shift
+    movsx           r5, byte [base+cdef_dirs8+(r4+2)*2+1] ; k1off1
+    pminuw         m18, m0, m4
+    pmaxsw         m19, m0, m4
+    pminuw         m20, m1, m5
+    pmaxsw         m21, m1, m5
+    call .min_max_constrain2
+    movsx           r5, byte [base+cdef_dirs8+(r4+0)*2+0] ; k0off2
+    pmullw          m8, m3
+    pmullw          m9, m3
+    vpbroadcastw   m13, secm
+    vpbroadcastw   m14, r3d
+    paddw          m16, m8
+    paddw          m17, m9
+    call .min_max_constrain
+    movsx           r5, byte [base+cdef_dirs8+(r4+4)*2+0] ; k0off3
+    mova            m2, m8
+    mova            m3, m9
+    call .min_max_constrain
+    movsx           r5, byte [base+cdef_dirs8+(r4+0)*2+1] ; k1off2
+    paddw           m2, m8
+    paddw           m3, m9
+    call .min_max_constrain
+    movsx           r5, byte [base+cdef_dirs8+(r4+4)*2+1] ; k1off3
+    paddw           m2, m2
+    paddw           m3, m3
+    paddw          m16, m8
+    paddw          m17, m9
+    call .min_max_constrain
+    vpbroadcastd   m10, [base+pw_2048]
+    paddw          m16, m2
+    paddw          m17, m3
+    paddw          m16, m8
+    paddw          m17, m9
+    psraw           m8, m16, 15
+    psraw           m9, m17, 15
+    paddw          m16, m8
+    paddw          m17, m9
+    pmulhrsw       m16, m10
+    pmulhrsw       m17, m10
+    pminuw         m18, m4
+    pmaxsw         m19, m4
+    pminuw         m20, m5
+    pmaxsw         m21, m5
+    pminuw         m18, m6
+    pmaxsw         m19, m6
+    pminuw         m20, m7
+    pmaxsw         m21, m7
+    paddw          m16, m0
+    paddw          m17, m1
+    pmaxsw         m16, m18
+    pmaxsw         m17, m20
+    pminsw         m16, m19
+    pminsw         m17, m21
+    jmp .end
+.sec_only:
+    tzcnt          r5d, secm
+    mov            r4d, dirm
+    mov            r3d, dampingm
+    vpbroadcastw   m13, secm
+    sub            r3d, r5d
+    movsx           r5, byte [base+cdef_dirs8+(r4+0)*2+0]
+    vpbroadcastw   m14, r3d
+    call .constrain
+    movsx           r5, byte [base+cdef_dirs8+(r4+4)*2+0]
+    mova           m16, m8
+    mova           m17, m9
+    call .constrain
+    movsx           r5, byte [base+cdef_dirs8+(r4+0)*2+1]
+    paddw          m16, m8
+    paddw          m17, m9
+    call .constrain
+    movsx           r5, byte [base+cdef_dirs8+(r4+4)*2+1]
+    paddw          m16, m16
+    paddw          m17, m17
+    paddw          m16, m8
+    paddw          m17, m9
+    call .constrain
+.end_no_clip:
+    vpbroadcastd   m10, [base+pw_2048]
+    paddw          m16, m8
+    paddw          m17, m9
+    psraw           m8, m16, 15
+    psraw           m9, m17, 15
+    paddw          m16, m8
+    paddw          m17, m9
+    pmulhrsw       m16, m10
+    pmulhrsw       m17, m10
+    paddw          m16, m0
+    paddw          m17, m1
+.end:
+    mova          [dstq+strideq*0], xm16
+    vextracti128  [dstq+strideq*1], ym16, 1
+    vextracti32x4 [dstq+strideq*2], m16, 2
+    vextracti32x4 [dstq+r2       ], m16, 3
+    lea           dstq, [dstq+strideq*4]
+    mova          [dstq+strideq*0], xm17
+    vextracti128  [dstq+strideq*1], ym17, 1
+    vextracti32x4 [dstq+strideq*2], m17, 2
+    vextracti32x4 [dstq+r2       ], m17, 3
+    RET
+.mask_edges:
+    vpbroadcastd    m2, [base+pw_m16384]
+    test           r3b, 0x08
+    jz .mask_edges_no_bottom  ; avoid buffer overread
+    movu          ym21, [botq+strideq*0-4]
+    vinserti32x8   m21, [botq+strideq*1-4], 1
+    jmp .mask_edges_top
+.mask_edges_no_bottom:
+    mova           m21, m2
+.mask_edges_top:
+    test           r3b, 0x04
+    jnz .mask_edges_main
+    mova           m16, m2
+.mask_edges_main:
+    and            r3d, 0x03
+    cmp            r3d, 0x03
+    je .main
+    kmovw           k1, [base+edge_mask8+r3*2]
+    vmovdqa32  m16{k1}, m2     ; edge pixels = -16384
+    vmovdqa32  m17{k1}, m2
+    vmovdqa32  m18{k1}, m2
+    vmovdqa32  m19{k1}, m2
+    vmovdqa32  m20{k1}, m2
+    vmovdqa32  m21{k1}, m2
+    jmp .main
+ALIGN function_align
+.min_max_constrain:
+    pminuw         m18, m4
+    pmaxsw         m19, m4
+    pminuw         m20, m5
+    pmaxsw         m21, m5
+.min_max_constrain2:
+    pminuw         m18, m6
+    pmaxsw         m19, m6
+    pminuw         m20, m7
+    pmaxsw         m21, m7
+.constrain:
+    %define        tmp  rsp+gprsize+68
+    movu            m4, [tmp+r5+64*0]
+    vshufi32x4      m4, [tmp+r5+64*1], q2020 ; k0p0 (top)
+    movu            m5, [tmp+r5+64*2]
+    vshufi32x4      m5, [tmp+r5+64*3], q2020 ; k0p0 (bottom)
+    neg             r5
+    movu            m6, [tmp+r5+64*0]
+    vshufi32x4      m6, [tmp+r5+64*1], q2020 ; k0p1 (top)
+    movu            m7, [tmp+r5+64*2]
+    vshufi32x4      m7, [tmp+r5+64*3], q2020 ; k0p1 (bottom)
+    CONSTRAIN       m8, m4, m0, m12, m13, m14, m15
+    CONSTRAIN       m9, m5, m1, m12, m13, m14, m15
+    CONSTRAIN      m10, m6, m0, m12, m13, m14, m15
+    CONSTRAIN      m11, m7, m1, m12, m13, m14, m15
+    paddw           m8, m10
+    paddw           m9, m11
+    ret
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/cdef16_sse.asm b/media/libdav1d/src/src/x86/cdef16_sse.asm
new file mode 100644
index 0000000000..1bd67ace64
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cdef16_sse.asm
@@ -0,0 +1,1033 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; Copyright (c) 2017-2021, The rav1e contributors
+; Copyright (c) 2021, Nathan Egge
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA
+
+%macro DUP8 1-*
+    %rep %0
+        times 8 dw %1
+        %rotate 1
+    %endrep
+%endmacro
+
+pri_taps:  DUP8 4, 2, 3, 3
+dir_table: db  1 * 32 + 0,  2 * 32 + 0
+           db  1 * 32 + 0,  2 * 32 - 2
+           db -1 * 32 + 2, -2 * 32 + 4
+           db  0 * 32 + 2, -1 * 32 + 4
+           db  0 * 32 + 2,  0 * 32 + 4
+           db  0 * 32 + 2,  1 * 32 + 4
+           db  1 * 32 + 2,  2 * 32 + 4
+           db  1 * 32 + 0,  2 * 32 + 2
+           db  1 * 32 + 0,  2 * 32 + 0
+           db  1 * 32 + 0,  2 * 32 - 2
+           db -1 * 32 + 2, -2 * 32 + 4
+           db  0 * 32 + 2, -1 * 32 + 4
+
+dir_shift: times 4 dw 0x4000
+           times 4 dw 0x1000
+
+pw_128:    times 4 dw 128
+pw_2048:   times 8 dw 2048
+pw_m16384: times 8 dw -16384
+
+cextern cdef_dir_8bpc_ssse3.main
+cextern cdef_dir_8bpc_sse4.main
+cextern shufw_6543210x
+
+SECTION .text
+
+%if ARCH_X86_32
+DECLARE_REG_TMP 5, 3
+%elif WIN64
+DECLARE_REG_TMP 8, 4
+%else
+DECLARE_REG_TMP 8, 6
+%endif
+
+%macro CDEF_FILTER 2 ; w, h
+%if ARCH_X86_64
+    DEFINE_ARGS dst, stride, _, tmp, pridmp, pri, sec, dir
+    mova            m8, [base+pw_2048]
+%else
+    DEFINE_ARGS dst, pridmp, tmp, sec, pri, _, dir
+    %define         m8  [base+pw_2048]
+    %define         m9  [rsp+16*1+gprsize]
+    %define        m10  [rsp+16*2+gprsize]
+%endif
+    movifnidn     prid, r5m
+    movifnidn     secd, r6m
+    test          prid, prid
+    jz .sec_only
+    movd            m6, r5m
+%if ARCH_X86_32
+    mov       [rsp+24], pridmpd
+%endif
+    bsr        pridmpd, prid
+    lea           tmpd, [priq*4]
+    cmp     dword r10m, 0x3ff ; if (bpc == 10)
+    cmove         prid, tmpd  ;     pri <<= 2
+    mov           tmpd, r8m   ; damping
+    mov           dird, r7m
+    and           prid, 16
+    pshufb          m6, m7    ; splat
+    lea           dirq, [base+dir_table+dirq*2]
+    lea           priq, [base+pri_taps+priq*2]
+    test          secd, secd
+    jz .pri_only
+    mova         [rsp], m6
+    movd            m6, secd
+    tzcnt         secd, secd
+    sub        pridmpd, tmpd
+    sub           tmpd, secd
+    pshufb          m6, m7
+    xor           secd, secd
+    neg        pridmpd
+    cmovs      pridmpd, secd
+%if ARCH_X86_32
+    mov  [pri_shift+4], secd
+    mov  [sec_shift+4], secd
+%endif
+    mov  [pri_shift+0], pridmpq
+    mov  [sec_shift+0], tmpq
+    lea           tmpq, [px]
+%if WIN64
+    movaps         r4m, m9
+    movaps         r6m, m10
+%elif ARCH_X86_32
+    mov        pridmpd, [rsp+24]
+%endif
+%rep %1*%2/8
+    call mangle(private_prefix %+ _cdef_filter_%1x%1_16bpc %+ SUFFIX).pri_sec
+%endrep
+%if WIN64
+    movaps          m9, r4m
+    movaps         m10, r6m
+%endif
+    jmp .end
+.pri_only:
+    sub           tmpd, pridmpd
+    cmovs         tmpd, secd
+%if ARCH_X86_32
+    mov        pridmpd, [rsp+24]
+    mov  [pri_shift+4], secd
+%endif
+    mov  [pri_shift+0], tmpq
+    lea           tmpq, [px]
+%rep %1*%2/8
+    call mangle(private_prefix %+ _cdef_filter_%1x%1_16bpc %+ SUFFIX).pri
+%endrep
+.end:
+    RET
+.sec_only:
+    mov           tmpd, r8m ; damping
+    movd            m6, r6m
+    tzcnt         secd, secd
+    mov           dird, r7m
+    pshufb          m6, m7
+    sub           tmpd, secd
+    lea           dirq, [base+dir_table+dirq*2]
+%if ARCH_X86_32
+    mov  [sec_shift+4], prid
+%endif
+    mov  [sec_shift+0], tmpq
+    lea           tmpq, [px]
+%rep %1*%2/8
+    call mangle(private_prefix %+ _cdef_filter_%1x%1_16bpc %+ SUFFIX).sec
+%endrep
+    jmp .end
+%if %1 == %2
+ %if ARCH_X86_64
+  DEFINE_ARGS dst, stride, _, tmp, off, pri, _, dir
+ %else
+  DEFINE_ARGS dst, stride, tmp, off, pri, _, dir
+ %endif
+ALIGN function_align
+.pri:
+    movsx         offq, byte [dirq+4]    ; off_k0
+%if %1 == 4
+    movq            m1, [dstq+strideq*0]
+    movhps          m1, [dstq+strideq*1]
+    movq            m2, [tmpq+offq+32*0] ; k0p0
+    movhps          m2, [tmpq+offq+32*1]
+    neg           offq
+    movq            m3, [tmpq+offq+32*0] ; k0p1
+    movhps          m3, [tmpq+offq+32*1]
+%else
+    mova            m1, [dstq]
+    movu            m2, [tmpq+offq]
+    neg           offq
+    movu            m3, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+5]    ; off_k1
+    psubw           m2, m1               ; diff_k0p0
+    psubw           m3, m1               ; diff_k0p1
+    pabsw           m4, m2               ; adiff_k0p0
+    psrlw           m5, m4, [pri_shift+gprsize]
+    psubusw         m0, m6, m5
+    pabsw           m5, m3               ; adiff_k0p1
+    pminsw          m0, m4
+    psrlw           m4, m5, [pri_shift+gprsize]
+    psignw          m0, m2               ; constrain(diff_k0p0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movq            m4, [tmpq+offq+32*0] ; k1p0
+    movhps          m4, [tmpq+offq+32*1]
+    neg           offq
+    movq            m5, [tmpq+offq+32*0] ; k1p1
+    movhps          m5, [tmpq+offq+32*1]
+%else
+    movu            m4, [tmpq+offq]
+    neg           offq
+    movu            m5, [tmpq+offq]
+%endif
+    psubw           m4, m1               ; diff_k1p0
+    psubw           m5, m1               ; diff_k1p1
+    psignw          m2, m3               ; constrain(diff_k0p1)
+    pabsw           m3, m4               ; adiff_k1p0
+    paddw           m0, m2               ; constrain(diff_k0)
+    psrlw           m2, m3, [pri_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k1p1
+    pminsw          m7, m3
+    psrlw           m3, m2, [pri_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k1p0)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+    psignw          m4, m5               ; constrain(diff_k1p1)
+    paddw           m7, m4               ; constrain(diff_k1)
+    pmullw          m0, [priq+16*0]      ; pri_tap_k0
+    pmullw          m7, [priq+16*1]      ; pri_tap_k1
+    paddw           m0, m7               ; sum
+    psraw           m2, m0, 15
+    paddw           m0, m2
+    pmulhrsw        m0, m8
+    paddw           m0, m1
+%if %1 == 4
+    add           tmpq, 32*2
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea           dstq, [dstq+strideq*2]
+%else
+    add           tmpq, 32
+    mova        [dstq], m0
+    add           dstq, strideq
+%endif
+    ret
+ALIGN function_align
+.sec:
+    movsx         offq, byte [dirq+8]    ; off1_k0
+%if %1 == 4
+    movq            m1, [dstq+strideq*0]
+    movhps          m1, [dstq+strideq*1]
+    movq            m2, [tmpq+offq+32*0] ; k0s0
+    movhps          m2, [tmpq+offq+32*1]
+    neg           offq
+    movq            m3, [tmpq+offq+32*0] ; k0s1
+    movhps          m3, [tmpq+offq+32*1]
+%else
+    mova            m1, [dstq]
+    movu            m2, [tmpq+offq]
+    neg           offq
+    movu            m3, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+0]    ; off2_k0
+    psubw           m2, m1               ; diff_k0s0
+    psubw           m3, m1               ; diff_k0s1
+    pabsw           m4, m2               ; adiff_k0s0
+    psrlw           m5, m4, [sec_shift+gprsize]
+    psubusw         m0, m6, m5
+    pabsw           m5, m3               ; adiff_k0s1
+    pminsw          m0, m4
+    psrlw           m4, m5, [sec_shift+gprsize]
+    psignw          m0, m2               ; constrain(diff_k0s0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movq            m4, [tmpq+offq+32*0] ; k0s2
+    movhps          m4, [tmpq+offq+32*1]
+    neg           offq
+    movq            m5, [tmpq+offq+32*0] ; k0s3
+    movhps          m5, [tmpq+offq+32*1]
+%else
+    movu            m4, [tmpq+offq]
+    neg           offq
+    movu            m5, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+9]    ; off1_k1
+    psubw           m4, m1               ; diff_k0s2
+    psubw           m5, m1               ; diff_k0s3
+    psignw          m2, m3               ; constrain(diff_k0s1)
+    pabsw           m3, m4               ; adiff_k0s2
+    paddw           m0, m2
+    psrlw           m2, m3, [sec_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k0s3
+    pminsw          m7, m3
+    psrlw           m3, m2, [sec_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k0s2)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+%if %1 == 4
+    movq            m2, [tmpq+offq+32*0] ; k1s0
+    movhps          m2, [tmpq+offq+32*1]
+    neg           offq
+    movq            m3, [tmpq+offq+32*0] ; k1s1
+    movhps          m3, [tmpq+offq+32*1]
+%else
+    movu            m2, [tmpq+offq]
+    neg           offq
+    movu            m3, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+1]    ; off2_k1
+    paddw           m0, m7
+    psignw          m4, m5               ; constrain(diff_k0s3)
+    paddw           m0, m4               ; constrain(diff_k0)
+    psubw           m2, m1               ; diff_k1s0
+    psubw           m3, m1               ; diff_k1s1
+    paddw           m0, m0               ; sec_tap_k0
+    pabsw           m4, m2               ; adiff_k1s0
+    psrlw           m5, m4, [sec_shift+gprsize]
+    psubusw         m7, m6, m5
+    pabsw           m5, m3               ; adiff_k1s1
+    pminsw          m7, m4
+    psrlw           m4, m5, [sec_shift+gprsize]
+    psignw          m7, m2               ; constrain(diff_k1s0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movq            m4, [tmpq+offq+32*0] ; k1s2
+    movhps          m4, [tmpq+offq+32*1]
+    neg           offq
+    movq            m5, [tmpq+offq+32*0] ; k1s3
+    movhps          m5, [tmpq+offq+32*1]
+%else
+    movu            m4, [tmpq+offq]
+    neg           offq
+    movu            m5, [tmpq+offq]
+%endif
+    paddw           m0, m7
+    psubw           m4, m1               ; diff_k1s2
+    psubw           m5, m1               ; diff_k1s3
+    psignw          m2, m3               ; constrain(diff_k1s1)
+    pabsw           m3, m4               ; adiff_k1s2
+    paddw           m0, m2
+    psrlw           m2, m3, [sec_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k1s3
+    pminsw          m7, m3
+    psrlw           m3, m2, [sec_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k1s2)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+    paddw           m0, m7
+    psignw          m4, m5               ; constrain(diff_k1s3)
+    paddw           m0, m4               ; sum
+    psraw           m2, m0, 15
+    paddw           m0, m2
+    pmulhrsw        m0, m8
+    paddw           m0, m1
+%if %1 == 4
+    add           tmpq, 32*2
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea           dstq, [dstq+strideq*2]
+%else
+    add           tmpq, 32
+    mova        [dstq], m0
+    add           dstq, strideq
+%endif
+    ret
+ALIGN function_align
+.pri_sec:
+    movsx         offq, byte [dirq+8]    ; off2_k0
+%if %1 == 4
+    movq            m1, [dstq+strideq*0]
+    movhps          m1, [dstq+strideq*1]
+    movq            m2, [tmpq+offq+32*0] ; k0s0
+    movhps          m2, [tmpq+offq+32*1]
+    neg           offq
+    movq            m3, [tmpq+offq+32*0] ; k0s1
+    movhps          m3, [tmpq+offq+32*1]
+%else
+    mova            m1, [dstq]
+    movu            m2, [tmpq+offq]
+    neg           offq
+    movu            m3, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+0]    ; off3_k0
+    pabsw           m4, m2
+%if ARCH_X86_64
+    pabsw          m10, m3
+    pmaxsw          m9, m2, m3
+    pminsw         m10, m4
+%else
+    pabsw           m7, m3
+    pmaxsw          m5, m2, m3
+    pminsw          m4, m7
+    mova            m9, m5
+    mova           m10, m4
+%endif
+    psubw           m2, m1               ; diff_k0s0
+    psubw           m3, m1               ; diff_k0s1
+    pabsw           m4, m2               ; adiff_k0s0
+    psrlw           m5, m4, [sec_shift+gprsize]
+    psubusw         m0, m6, m5
+    pabsw           m5, m3               ; adiff_k0s1
+    pminsw          m0, m4
+    psrlw           m4, m5, [sec_shift+gprsize]
+    psignw          m0, m2               ; constrain(diff_k0s0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movq            m4, [tmpq+offq+32*0] ; k0s2
+    movhps          m4, [tmpq+offq+32*1]
+    neg           offq
+    movq            m5, [tmpq+offq+32*0] ; k0s3
+    movhps          m5, [tmpq+offq+32*1]
+%else
+    movu            m4, [tmpq+offq]
+    neg           offq
+    movu            m5, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+9]    ; off2_k1
+    pabsw           m7, m4
+    psignw          m2, m3
+    pabsw           m3, m5               ; constrain(diff_k0s1)
+%if ARCH_X86_64
+    pmaxsw          m9, m4
+    pminsw         m10, m7
+    pmaxsw          m9, m5
+    pminsw         m10, m3
+%else
+    pminsw          m7, m10
+    pminsw          m7, m3
+    pmaxsw          m3, m9, m4
+    pmaxsw          m3, m5
+    mova           m10, m7
+    mova            m9, m3
+%endif
+    psubw           m4, m1               ; diff_k0s2
+    psubw           m5, m1               ; diff_k0s3
+    paddw           m0, m2
+    pabsw           m3, m4               ; adiff_k0s2
+    psrlw           m2, m3, [sec_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k0s3
+    pminsw          m7, m3
+    psrlw           m3, m2, [sec_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k0s2)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+%if %1 == 4
+    movq            m2, [tmpq+offq+32*0] ; k1s0
+    movhps          m2, [tmpq+offq+32*1]
+    neg           offq
+    movq            m3, [tmpq+offq+32*0] ; k1s1
+    movhps          m3, [tmpq+offq+32*1]
+%else
+    movu            m2, [tmpq+offq]
+    neg           offq
+    movu            m3, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+1]    ; off3_k1
+    paddw           m0, m7
+    pabsw           m7, m2
+    psignw          m4, m5               ; constrain(diff_k0s3)
+    pabsw           m5, m3
+%if ARCH_X86_64
+    pmaxsw          m9, m2
+    pminsw         m10, m7
+    pmaxsw          m9, m3
+    pminsw         m10, m5
+%else
+    pminsw          m7, m10
+    pminsw          m7, m5
+    pmaxsw          m5, m9, m2
+    pmaxsw          m5, m3
+    mova           m10, m7
+    mova            m9, m5
+%endif
+    paddw           m0, m4               ; constrain(diff_k0)
+    psubw           m2, m1               ; diff_k1s0
+    psubw           m3, m1               ; diff_k1s1
+    paddw           m0, m0               ; sec_tap_k0
+    pabsw           m4, m2               ; adiff_k1s0
+    psrlw           m5, m4, [sec_shift+gprsize]
+    psubusw         m7, m6, m5
+    pabsw           m5, m3               ; adiff_k1s1
+    pminsw          m7, m4
+    psrlw           m4, m5, [sec_shift+gprsize]
+    psignw          m7, m2               ; constrain(diff_k1s0)
+    psubusw         m2, m6, m4
+    pminsw          m2, m5
+%if %1 == 4
+    movq            m4, [tmpq+offq+32*0] ; k1s2
+    movhps          m4, [tmpq+offq+32*1]
+    neg           offq
+    movq            m5, [tmpq+offq+32*0] ; k1s3
+    movhps          m5, [tmpq+offq+32*1]
+%else
+    movu            m4, [tmpq+offq]
+    neg           offq
+    movu            m5, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+4]    ; off1_k0
+    paddw           m0, m7
+    pabsw           m7, m4
+    psignw          m2, m3               ; constrain(diff_k1s1)
+    pabsw           m3, m5
+%if ARCH_X86_64
+    pmaxsw          m9, m4
+    pminsw         m10, m7
+    pmaxsw          m9, m5
+    pminsw         m10, m3
+%else
+    pminsw          m7, m10
+    pminsw          m7, m3
+    pmaxsw          m3, m9, m4
+    pmaxsw          m3, m5
+    mova           m10, m7
+    mova            m9, m3
+%endif
+    psubw           m4, m1               ; diff_k1s2
+    psubw           m5, m1               ; diff_k1s3
+    pabsw           m3, m4               ; adiff_k1s2
+    paddw           m0, m2
+    psrlw           m2, m3, [sec_shift+gprsize]
+    psubusw         m7, m6, m2
+    pabsw           m2, m5               ; adiff_k1s3
+    pminsw          m7, m3
+    psrlw           m3, m2, [sec_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k1s2)
+    psubusw         m4, m6, m3
+    pminsw          m4, m2
+    paddw           m0, m7
+%if %1 == 4
+    movq            m2, [tmpq+offq+32*0] ; k0p0
+    movhps          m2, [tmpq+offq+32*1]
+    neg           offq
+    movq            m3, [tmpq+offq+32*0] ; k0p1
+    movhps          m3, [tmpq+offq+32*1]
+%else
+    movu            m2, [tmpq+offq]
+    neg           offq
+    movu            m3, [tmpq+offq]
+%endif
+    movsx         offq, byte [dirq+5]    ; off1_k1
+    pabsw           m7, m2
+    psignw          m4, m5               ; constrain(diff_k1s3)
+    pabsw           m5, m3
+%if ARCH_X86_64
+    pmaxsw          m9, m2
+    pminsw         m10, m7
+    pmaxsw          m9, m3
+    pminsw         m10, m5
+%else
+    pminsw          m7, m10
+    pminsw          m7, m5
+    pmaxsw          m5, m9, m2
+    pmaxsw          m5, m3
+    mova           m10, m7
+    mova            m9, m5
+%endif
+    psubw           m2, m1               ; diff_k0p0
+    psubw           m3, m1               ; diff_k0p1
+    paddw           m0, m4
+    pabsw           m4, m2               ; adiff_k0p0
+    psrlw           m5, m4, [pri_shift+gprsize]
+    psubusw         m7, [rsp+gprsize], m5
+    pabsw           m5, m3               ; adiff_k0p1
+    pminsw          m7, m4
+    psrlw           m4, m5, [pri_shift+gprsize]
+    psignw          m7, m2               ; constrain(diff_k0p0)
+    psubusw         m2, [rsp+gprsize], m4
+    pminsw          m2, m5
+%if %1 == 4
+    movq            m4, [tmpq+offq+32*0] ; k1p0
+    movhps          m4, [tmpq+offq+32*1]
+    neg           offq
+    movq            m5, [tmpq+offq+32*0] ; k1p1
+    movhps          m5, [tmpq+offq+32*1]
+%else
+    movu            m4, [tmpq+offq]
+    neg           offq
+    movu            m5, [tmpq+offq]
+%endif
+    psignw          m2, m3               ; constrain(diff_k0p1)
+    pabsw           m3, m4
+    paddw           m7, m2               ; constrain(diff_k0)
+    pabsw           m2, m5
+%if ARCH_X86_64
+    pmaxsw          m9, m4
+    pminsw         m10, m3
+    pmaxsw          m9, m5
+    pminsw         m10, m2
+%else
+    pminsw          m3, m10
+    pminsw          m3, m2
+    pmaxsw          m2, m9, m4
+    pmaxsw          m2, m5
+    mova           m10, m3
+    mova            m9, m2
+%endif
+    psubw           m4, m1               ; diff_k1p0
+    psubw           m5, m1               ; diff_k1p1
+    pabsw           m3, m4               ; adiff_k1p0
+    pmullw          m7, [priq+16*0]      ; pri_tap_k0
+    paddw           m0, m7
+    psrlw           m2, m3, [pri_shift+gprsize]
+    psubusw         m7, [rsp+16*0+gprsize], m2
+    pabsw           m2, m5               ; adiff_k1p1
+    pminsw          m7, m3
+    psrlw           m3, m2, [pri_shift+gprsize]
+    psignw          m7, m4               ; constrain(diff_k1p0)
+    psubusw         m4, [rsp+16*0+gprsize], m3
+    pminsw          m4, m2
+    psignw          m4, m5               ; constrain(diff_k1p1)
+    paddw           m7, m4               ; constrain(diff_k1)
+    pmullw          m7, [priq+16*1]      ; pri_tap_k1
+    paddw           m0, m7               ; sum
+    psraw           m2, m0, 15
+    paddw           m0, m2
+    pmulhrsw        m0, m8
+    paddw           m0, m1
+%if ARCH_X86_64
+    pmaxsw          m9, m1
+    pminsw          m0, m9
+%else
+    pmaxsw          m2, m9, m1
+    pminsw          m0, m2
+%endif
+    pminsw          m1, m10
+    pmaxsw          m0, m1
+%if %1 == 4
+    add           tmpq, 32*2
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea           dstq, [dstq+strideq*2]
+%else
+    add           tmpq, 32
+    mova        [dstq], m0
+    add           dstq, strideq
+%endif
+    ret
+%endif
+%endmacro
+
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal cdef_filter_4x4_16bpc, 5, 9, 9, 32*10, dst, stride, left, top, bot, \
+                                               pri, sec, edge
+    %define         px  rsp+32*4
+%else
+cglobal cdef_filter_4x4_16bpc, 2, 7, 8, -32*11, dst, stride, edge, top, left
+    %define       botq  topq
+    %define         px  rsp+32*5
+%endif
+    %define       base  t0-dir_table
+    %define  pri_shift  px-16*6
+    %define  sec_shift  px-16*5
+    mov          edged, r9m
+    LEA             t0, dir_table
+    movu            m0, [dstq+strideq*0]
+    movu            m1, [dstq+strideq*1]
+    lea             t1, [dstq+strideq*2]
+    movu            m2, [t1  +strideq*0]
+    movu            m3, [t1  +strideq*1]
+    movddup         m7, [base+pw_m16384]
+    mova   [px+32*0+0], m0
+    mova   [px+32*1+0], m1
+    mova   [px+32*2+0], m2
+    mova   [px+32*3+0], m3
+    test         edgeb, 4 ; HAVE_TOP
+    jz .no_top
+    movifnidn     topq, topmp
+    movu            m0, [topq+strideq*0]
+    movu            m1, [topq+strideq*1]
+    mova   [px-32*2+0], m0
+    mova   [px-32*1+0], m1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .top_no_left
+    movd            m0, [topq+strideq*0-4]
+    movd            m1, [topq+strideq*1-4]
+    movd   [px-32*2-4], m0
+    movd   [px-32*1-4], m1
+    jmp .top_done
+.no_top:
+    mova   [px-32*2+0], m7
+    mova   [px-32*1+0], m7
+.top_no_left:
+    movd   [px-32*2-4], m7
+    movd   [px-32*1-4], m7
+.top_done:
+    test         edgeb, 8 ; HAVE_BOTTOM
+    jz .no_bottom
+    movifnidn     botq, r4mp
+    movu            m0, [botq+strideq*0]
+    movu            m1, [botq+strideq*1]
+    mova   [px+32*4+0], m0
+    mova   [px+32*5+0], m1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .bottom_no_left
+    movd            m0, [botq+strideq*0-4]
+    movd            m1, [botq+strideq*1-4]
+    movd   [px+32*4-4], m0
+    movd   [px+32*5-4], m1
+    jmp .bottom_done
+.no_bottom:
+    mova   [px+32*4+0], m7
+    mova   [px+32*5+0], m7
+.bottom_no_left:
+    movd   [px+32*4-4], m7
+    movd   [px+32*5-4], m7
+.bottom_done:
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .no_left
+    movifnidn    leftq, r2mp
+    movd            m0, [leftq+4*0]
+    movd            m1, [leftq+4*1]
+    movd            m2, [leftq+4*2]
+    movd            m3, [leftq+4*3]
+    movd   [px+32*0-4], m0
+    movd   [px+32*1-4], m1
+    movd   [px+32*2-4], m2
+    movd   [px+32*3-4], m3
+    jmp .left_done
+.no_left:
+    REPX {movd [px+32*x-4], m7}, 0, 1, 2, 3
+.left_done:
+    test         edgeb, 2 ; HAVE_RIGHT
+    jnz .padding_done
+    REPX {movd [px+32*x+8], m7}, -2, -1, 0, 1, 2, 3, 4, 5
+.padding_done:
+    CDEF_FILTER      4, 4
+
+%if ARCH_X86_64
+cglobal cdef_filter_4x8_16bpc, 5, 9, 9, 32*14, dst, stride, left, top, bot, \
+                                               pri, sec, edge
+%else
+cglobal cdef_filter_4x8_16bpc, 2, 7, 8, -32*15, dst, stride, edge, top, left
+%endif
+    mov          edged, r9m
+    LEA             t0, dir_table
+    movu            m0, [dstq+strideq*0]
+    movu            m1, [dstq+strideq*1]
+    lea             t1, [dstq+strideq*2]
+    movu            m2, [t1  +strideq*0]
+    movu            m3, [t1  +strideq*1]
+    lea             t1, [t1  +strideq*2]
+    movu            m4, [t1  +strideq*0]
+    movu            m5, [t1  +strideq*1]
+    lea             t1, [t1  +strideq*2]
+    movu            m6, [t1  +strideq*0]
+    movu            m7, [t1  +strideq*1]
+    mova   [px+32*0+0], m0
+    mova   [px+32*1+0], m1
+    mova   [px+32*2+0], m2
+    mova   [px+32*3+0], m3
+    mova   [px+32*4+0], m4
+    mova   [px+32*5+0], m5
+    mova   [px+32*6+0], m6
+    mova   [px+32*7+0], m7
+    movddup         m7, [base+pw_m16384]
+    test         edgeb, 4 ; HAVE_TOP
+    jz .no_top
+    movifnidn     topq, topmp
+    movu            m0, [topq+strideq*0]
+    movu            m1, [topq+strideq*1]
+    mova   [px-32*2+0], m0
+    mova   [px-32*1+0], m1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .top_no_left
+    movd            m0, [topq+strideq*0-4]
+    movd            m1, [topq+strideq*1-4]
+    movd   [px-32*2-4], m0
+    movd   [px-32*1-4], m1
+    jmp .top_done
+.no_top:
+    mova   [px-32*2+0], m7
+    mova   [px-32*1+0], m7
+.top_no_left:
+    movd   [px-32*2-4], m7
+    movd   [px-32*1-4], m7
+.top_done:
+    test         edgeb, 8 ; HAVE_BOTTOM
+    jz .no_bottom
+    movifnidn     botq, r4mp
+    movu            m0, [botq+strideq*0]
+    movu            m1, [botq+strideq*1]
+    mova   [px+32*8+0], m0
+    mova   [px+32*9+0], m1
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .bottom_no_left
+    movd            m0, [botq+strideq*0-4]
+    movd            m1, [botq+strideq*1-4]
+    movd   [px+32*8-4], m0
+    movd   [px+32*9-4], m1
+    jmp .bottom_done
+.no_bottom:
+    mova   [px+32*8+0], m7
+    mova   [px+32*9+0], m7
+.bottom_no_left:
+    movd   [px+32*8-4], m7
+    movd   [px+32*9-4], m7
+.bottom_done:
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .no_left
+    movifnidn    leftq, r2mp
+    movd            m0, [leftq+4*0]
+    movd            m1, [leftq+4*1]
+    movd            m2, [leftq+4*2]
+    movd            m3, [leftq+4*3]
+    movd   [px+32*0-4], m0
+    movd   [px+32*1-4], m1
+    movd   [px+32*2-4], m2
+    movd   [px+32*3-4], m3
+    movd            m0, [leftq+4*4]
+    movd            m1, [leftq+4*5]
+    movd            m2, [leftq+4*6]
+    movd            m3, [leftq+4*7]
+    movd   [px+32*4-4], m0
+    movd   [px+32*5-4], m1
+    movd   [px+32*6-4], m2
+    movd   [px+32*7-4], m3
+    jmp .left_done
+.no_left:
+    REPX {movd [px+32*x-4], m7}, 0, 1, 2, 3, 4, 5, 6, 7
+.left_done:
+    test         edgeb, 2 ; HAVE_RIGHT
+    jnz .padding_done
+    REPX {movd [px+32*x+8], m7}, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+.padding_done:
+    CDEF_FILTER      4, 8
+
+%if ARCH_X86_64
+cglobal cdef_filter_8x8_16bpc, 5, 9, 9, 32*14, dst, stride, left, top, bot, \
+                                               pri, sec, edge
+%else
+cglobal cdef_filter_8x8_16bpc, 2, 7, 8, -32*15, dst, stride, edge, top, left
+%endif
+    mov          edged, r9m
+    LEA             t0, dir_table
+    mova            m0, [dstq+strideq*0+ 0]
+    movd            m1, [dstq+strideq*0+16]
+    mova            m2, [dstq+strideq*1+ 0]
+    movd            m3, [dstq+strideq*1+16]
+    lea             t1, [dstq+strideq*2]
+    mova            m4, [t1  +strideq*0+ 0]
+    movd            m5, [t1  +strideq*0+16]
+    mova            m6, [t1  +strideq*1+ 0]
+    movd            m7, [t1  +strideq*1+16]
+    lea             t1, [t1  +strideq*2]
+    mova  [px+32*0+ 0], m0
+    movd  [px+32*0+16], m1
+    mova  [px+32*1+ 0], m2
+    movd  [px+32*1+16], m3
+    mova  [px+32*2+ 0], m4
+    movd  [px+32*2+16], m5
+    mova  [px+32*3+ 0], m6
+    movd  [px+32*3+16], m7
+    mova            m0, [t1  +strideq*0+ 0]
+    movd            m1, [t1  +strideq*0+16]
+    mova            m2, [t1  +strideq*1+ 0]
+    movd            m3, [t1  +strideq*1+16]
+    lea             t1, [t1  +strideq*2]
+    mova            m4, [t1  +strideq*0+ 0]
+    movd            m5, [t1  +strideq*0+16]
+    mova            m6, [t1  +strideq*1+ 0]
+    movd            m7, [t1  +strideq*1+16]
+    mova  [px+32*4+ 0], m0
+    movd  [px+32*4+16], m1
+    mova  [px+32*5+ 0], m2
+    movd  [px+32*5+16], m3
+    mova  [px+32*6+ 0], m4
+    movd  [px+32*6+16], m5
+    mova  [px+32*7+ 0], m6
+    movd  [px+32*7+16], m7
+    movddup         m7, [base+pw_m16384]
+    test         edgeb, 4 ; HAVE_TOP
+    jz .no_top
+    movifnidn     topq, topmp
+    mova            m0, [topq+strideq*0+ 0]
+    mova            m1, [topq+strideq*0+16]
+    mova            m2, [topq+strideq*1+ 0]
+    mova            m3, [topq+strideq*1+16]
+    mova  [px-32*2+ 0], m0
+    movd  [px-32*2+16], m1
+    mova  [px-32*1+ 0], m2
+    movd  [px-32*1+16], m3
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .top_no_left
+    movd            m0, [topq+strideq*0-4]
+    movd            m1, [topq+strideq*1-4]
+    movd   [px-32*2-4], m0
+    movd   [px-32*1-4], m1
+    jmp .top_done
+.no_top:
+    mova  [px-32*2+ 0], m7
+    movd  [px-32*2+16], m7
+    mova  [px-32*1+ 0], m7
+    movd  [px-32*1+16], m7
+.top_no_left:
+    movd  [px-32*2- 4], m7
+    movd  [px-32*1- 4], m7
+.top_done:
+    test         edgeb, 8 ; HAVE_BOTTOM
+    jz .no_bottom
+    movifnidn     botq, r4mp
+    mova            m0, [botq+strideq*0+ 0]
+    movd            m1, [botq+strideq*0+16]
+    mova            m2, [botq+strideq*1+ 0]
+    movd            m3, [botq+strideq*1+16]
+    mova  [px+32*8+ 0], m0
+    movd  [px+32*8+16], m1
+    mova  [px+32*9+ 0], m2
+    movd  [px+32*9+16], m3
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .bottom_no_left
+    movd            m0, [botq+strideq*0-4]
+    movd            m1, [botq+strideq*1-4]
+    movd  [px+32*8- 4], m0
+    movd  [px+32*9- 4], m1
+    jmp .bottom_done
+.no_bottom:
+    mova  [px+32*8+ 0], m7
+    movd  [px+32*8+16], m7
+    mova  [px+32*9+ 0], m7
+    movd  [px+32*9+16], m7
+.bottom_no_left:
+    movd  [px+32*8- 4], m7
+    movd  [px+32*9- 4], m7
+.bottom_done:
+    test         edgeb, 1 ; HAVE_LEFT
+    jz .no_left
+    movifnidn    leftq, r2mp
+    movd            m0, [leftq+4*0]
+    movd            m1, [leftq+4*1]
+    movd            m2, [leftq+4*2]
+    movd            m3, [leftq+4*3]
+    movd  [px+32*0- 4], m0
+    movd  [px+32*1- 4], m1
+    movd  [px+32*2- 4], m2
+    movd  [px+32*3- 4], m3
+    movd            m0, [leftq+4*4]
+    movd            m1, [leftq+4*5]
+    movd            m2, [leftq+4*6]
+    movd            m3, [leftq+4*7]
+    movd  [px+32*4- 4], m0
+    movd  [px+32*5- 4], m1
+    movd  [px+32*6- 4], m2
+    movd  [px+32*7- 4], m3
+    jmp .left_done
+.no_left:
+    REPX {movd [px+32*x- 4], m7}, 0, 1, 2, 3, 4, 5, 6, 7
+.left_done:
+    test         edgeb, 2 ; HAVE_RIGHT
+    jnz .padding_done
+    REPX {movd [px+32*x+16], m7}, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+.padding_done:
+    CDEF_FILTER      8, 8
+
+%macro CDEF_DIR 0
+%if ARCH_X86_64
+cglobal cdef_dir_16bpc, 4, 7, 16, src, stride, var, bdmax
+    lea             r6, [dir_shift]
+    shr         bdmaxd, 11 ; 0 for 10bpc, 1 for 12bpc
+    movddup         m7, [r6+bdmaxq*8]
+    lea             r6, [strideq*3]
+    mova            m0, [srcq+strideq*0]
+    mova            m1, [srcq+strideq*1]
+    mova            m2, [srcq+strideq*2]
+    mova            m3, [srcq+r6       ]
+    lea           srcq, [srcq+strideq*4]
+    mova            m4, [srcq+strideq*0]
+    mova            m5, [srcq+strideq*1]
+    mova            m6, [srcq+strideq*2]
+    REPX {pmulhuw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulhuw         m7, [srcq+r6       ]
+    pxor            m8, m8
+    packuswb        m9, m0, m1
+    packuswb       m10, m2, m3
+    packuswb       m11, m4, m5
+    packuswb       m12, m6, m7
+    REPX {psadbw x, m8}, m9, m10, m11, m12
+    packssdw        m9, m10
+    packssdw       m11, m12
+    packssdw        m9, m11
+    jmp mangle(private_prefix %+ _cdef_dir_8bpc %+ SUFFIX).main
+%else
+cglobal cdef_dir_16bpc, 2, 4, 8, 96, src, stride, var, bdmax
+    mov         bdmaxd, bdmaxm
+    LEA             r2, dir_shift
+    shr         bdmaxd, 11
+    movddup         m7, [r2+bdmaxq*8]
+    lea             r3, [strideq*3]
+    pmulhuw         m3, m7, [srcq+strideq*0]
+    pmulhuw         m4, m7, [srcq+strideq*1]
+    pmulhuw         m5, m7, [srcq+strideq*2]
+    pmulhuw         m6, m7, [srcq+r3       ]
+    movddup         m1, [r2-dir_shift+pw_128]
+    lea           srcq, [srcq+strideq*4]
+    pxor            m0, m0
+    packuswb        m2, m3, m4
+    psubw           m3, m1
+    psubw           m4, m1
+    mova    [esp+0x00], m3
+    mova    [esp+0x10], m4
+    packuswb        m3, m5, m6
+    psadbw          m2, m0
+    psadbw          m3, m0
+    psubw           m5, m1
+    psubw           m6, m1
+    packssdw        m2, m3
+    mova    [esp+0x20], m5
+    mova    [esp+0x50], m6
+    pmulhuw         m4, m7, [srcq+strideq*0]
+    pmulhuw         m5, m7, [srcq+strideq*1]
+    pmulhuw         m6, m7, [srcq+strideq*2]
+    pmulhuw         m7,     [srcq+r3       ]
+    packuswb        m3, m4, m5
+    packuswb        m1, m6, m7
+    psadbw          m3, m0
+    psadbw          m1, m0
+    packssdw        m3, m1
+    movddup         m1, [r2-dir_shift+pw_128]
+    LEA             r2, shufw_6543210x
+    jmp mangle(private_prefix %+ _cdef_dir_8bpc %+ SUFFIX).main
+%endif
+%endmacro
+
+INIT_XMM ssse3
+CDEF_DIR
+
+INIT_XMM sse4
+CDEF_DIR
diff --git a/media/libdav1d/src/src/x86/cdef_avx2.asm b/media/libdav1d/src/src/x86/cdef_avx2.asm
new file mode 100644
index 0000000000..95d35fc1c8
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cdef_avx2.asm
@@ -0,0 +1,1771 @@
+; Copyright © 2018, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+%macro JMP_TABLE 2-*
+ %xdefine %1_jmptable %%table
+ %xdefine %%base mangle(private_prefix %+ _%1_avx2)
+ %%table:
+ %rep %0 - 1
+    dd %%base %+ .%2 - %%table
+  %rotate 1
+ %endrep
+%endmacro
+
+%macro CDEF_FILTER_JMP_TABLE 1
+JMP_TABLE cdef_filter_%1_8bpc, \
+    d6k0, d6k1, d7k0, d7k1, \
+    d0k0, d0k1, d1k0, d1k1, d2k0, d2k1, d3k0, d3k1, \
+    d4k0, d4k1, d5k0, d5k1, d6k0, d6k1, d7k0, d7k1, \
+    d0k0, d0k1, d1k0, d1k1
+%endmacro
+
+SECTION_RODATA 32
+
+pd_47130256:   dd  4,  7,  1,  3,  0,  2,  5,  6
+blend_4x4:     dd 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00
+               dd 0x80, 0x00, 0x00
+blend_4x8_0:   dd 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
+blend_4x8_1:   dd 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
+               dd 0x00, 0x00
+blend_4x8_2:   dd 0x0000, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080
+               dd 0x0000
+blend_4x8_3:   dd 0x0000, 0x0000, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080
+               dd 0x0000, 0x0000
+blend_8x8_0:   dq 0x00, 0x00, 0x80, 0x80, 0x80, 0x80
+blend_8x8_1:   dq 0x0000, 0x0000, 0x8080, 0x8080, 0x8080, 0x8080, 0x0000, 0x0000
+div_table:     dd 840, 420, 280, 210, 168, 140, 120, 105, 420, 210, 140, 105
+shufw_6543210x:db 12, 13, 10, 11,  8,  9,  6,  7,  4,  5,  2,  3,  0,  1, 14, 15
+shufb_lohi:    db  0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+pw_128:        times 2 dw 128
+pw_2048:       times 2 dw 2048
+tap_table:     ; masks for 8 bit shifts
+               db 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01
+               ; weights
+               db  4,  2,  3,  3,  2,  1
+               db -1 * 16 + 1, -2 * 16 + 2
+               db  0 * 16 + 1, -1 * 16 + 2
+               db  0 * 16 + 1,  0 * 16 + 2
+               db  0 * 16 + 1,  1 * 16 + 2
+               db  1 * 16 + 1,  2 * 16 + 2
+               db  1 * 16 + 0,  2 * 16 + 1
+               db  1 * 16 + 0,  2 * 16 + 0
+               db  1 * 16 + 0,  2 * 16 - 1
+               ; the last 6 are repeats of the first 6 so we don't need to & 7
+               db -1 * 16 + 1, -2 * 16 + 2
+               db  0 * 16 + 1, -1 * 16 + 2
+               db  0 * 16 + 1,  0 * 16 + 2
+               db  0 * 16 + 1,  1 * 16 + 2
+               db  1 * 16 + 1,  2 * 16 + 2
+               db  1 * 16 + 0,  2 * 16 + 1
+
+CDEF_FILTER_JMP_TABLE 4x4
+CDEF_FILTER_JMP_TABLE 4x8
+CDEF_FILTER_JMP_TABLE 8x8
+
+SECTION .text
+
+%macro PREP_REGS 2 ; w, h
+    ; off1/2/3[k] [6 total] from [tapq+12+(dir+0/2/6)*2+k]
+    mov           dird, r7m
+    lea         tableq, [cdef_filter_%1x%2_8bpc_jmptable]
+    lea           dirq, [tableq+dirq*2*4]
+%if %1 == 4
+ %if %2 == 4
+  DEFINE_ARGS dst, stride, left, top, bot, pri, sec, \
+              table, dir, dirjmp, stride3, k
+ %else
+  DEFINE_ARGS dst, stride, left, top, bot, pri, sec, \
+              table, dir, dirjmp, dst4, stride3, k
+    lea          dst4q, [dstq+strideq*4]
+ %endif
+%else
+  DEFINE_ARGS dst, stride, h, top1, bot, pri, sec, \
+              table, dir, dirjmp, top2, stride3, k
+    mov             hq, -8
+    lea          top1q, [top1q+strideq*0]
+    lea          top2q, [top1q+strideq*1]
+%endif
+%if %1 == 4
+    lea       stride3q, [strideq*3]
+%endif
+%endmacro
+
+%macro LOAD_BLOCK 2-3 0 ; w, h, init_min_max
+    mov             kd, 1
+    pxor           m15, m15                     ; sum
+%if %2 == 8
+    pxor           m12, m12
+ %if %1 == 4
+    movd           xm4, [dstq +strideq*0]
+    movd           xm6, [dstq +strideq*1]
+    movd           xm5, [dstq +strideq*2]
+    movd           xm7, [dstq +stride3q ]
+    vinserti128     m4, [dst4q+strideq*0], 1
+    vinserti128     m6, [dst4q+strideq*1], 1
+    vinserti128     m5, [dst4q+strideq*2], 1
+    vinserti128     m7, [dst4q+stride3q ], 1
+    punpckldq       m4, m6
+    punpckldq       m5, m7
+ %else
+    movq           xm4, [dstq+strideq*0]
+    movq           xm5, [dstq+strideq*1]
+    vinserti128     m4, [dstq+strideq*2], 1
+    vinserti128     m5, [dstq+stride3q ], 1
+ %endif
+    punpcklqdq      m4, m5
+%else
+    movd           xm4, [dstq+strideq*0]
+    movd           xm5, [dstq+strideq*1]
+    vinserti128     m4, [dstq+strideq*2], 1
+    vinserti128     m5, [dstq+stride3q ], 1
+    punpckldq       m4, m5
+%endif
+%if %3 == 1
+    mova            m7, m4                      ; min
+    mova            m8, m4                      ; max
+%endif
+%endmacro
+
+%macro ACCUMULATE_TAP_BYTE 7-8 0 ; tap_offset, shift, mask, strength
+                                 ; mul_tap, w, h, clip
+    ; load p0/p1
+    movsxd     dirjmpq, [dirq+kq*4+%1*2*4]
+    add        dirjmpq, tableq
+    call       dirjmpq
+
+%if %8 == 1
+    pmaxub          m7, m5
+    pminub          m8, m5
+    pmaxub          m7, m6
+    pminub          m8, m6
+%endif
+
+    ; accumulate sum[m15] over p0/p1
+%if %7 == 4
+    punpcklbw       m5, m6
+    punpcklbw       m6, m4, m4
+    psubusb         m9, m5, m6
+    psubusb         m5, m6, m5
+    por             m9, m5     ; abs_diff_p01(p01 - px)
+    pcmpeqb         m5, m9
+    por             m5, %5
+    psignb          m6, %5, m5
+    psrlw           m5, m9, %2 ; emulate 8-bit shift
+    pand            m5, %3
+    psubusb         m5, %4, m5
+    pminub          m5, m9
+    pmaddubsw       m5, m6
+    paddw          m15, m5
+%else
+    psubusb         m9, m5, m4
+    psubusb         m5, m4, m5
+    psubusb        m11, m6, m4
+    psubusb         m6, m4, m6
+    por             m9, m5      ; abs_diff_p0(p0 - px)
+    por            m11, m6      ; abs_diff_p1(p1 - px)
+    pcmpeqb         m5, m9
+    pcmpeqb         m6, m11
+    punpckhbw      m10, m9, m11
+    punpcklbw       m9, m11
+    por             m5, %5
+    por            m11, m6, %5
+    punpckhbw       m6, m5, m11
+    punpcklbw       m5, m11
+    psignb         m11, %5, m6
+    psrlw           m6, m10, %2 ; emulate 8-bit shift
+    pand            m6, %3
+    psubusb         m6, %4, m6
+    pminub          m6, m10
+    pmaddubsw       m6, m11
+    paddw          m12, m6
+    psignb         m11, %5, m5
+    psrlw           m5, m9, %2  ; emulate 8-bit shift
+    pand            m5, %3
+    psubusb         m5, %4, m5
+    pminub          m5, m9
+    pmaddubsw       m5, m11
+    paddw          m15, m5
+%endif
+%endmacro
+
+%macro ADJUST_PIXEL 4-5 0 ; w, h, zero, pw_2048, clip
+%if %2 == 4
+ %if %5 == 1
+    punpcklbw       m4, %3
+ %endif
+    pcmpgtw         %3, m15
+    paddw          m15, %3
+    pmulhrsw       m15, %4
+ %if %5 == 0
+    packsswb       m15, m15
+    paddb           m4, m15
+ %else
+    paddw           m4, m15
+    packuswb        m4, m4 ; clip px in [0x0,0xff]
+    pminub          m4, m7
+    pmaxub          m4, m8
+ %endif
+    vextracti128   xm5, m4, 1
+    movd   [dstq+strideq*0], xm4
+    movd   [dstq+strideq*2], xm5
+    pextrd [dstq+strideq*1], xm4, 1
+    pextrd [dstq+stride3q ], xm5, 1
+%else
+    pcmpgtw         m6, %3, m12
+    pcmpgtw         m5, %3, m15
+    paddw          m12, m6
+    paddw          m15, m5
+ %if %5 == 1
+    punpckhbw       m5, m4, %3
+    punpcklbw       m4, %3
+ %endif
+    pmulhrsw       m12, %4
+    pmulhrsw       m15, %4
+ %if %5 == 0
+    packsswb       m15, m12
+    paddb           m4, m15
+ %else
+    paddw           m5, m12
+    paddw           m4, m15
+    packuswb        m4, m5 ; clip px in [0x0,0xff]
+    pminub          m4, m7
+    pmaxub          m4, m8
+ %endif
+    vextracti128   xm5, m4, 1
+ %if %1 == 4
+    movd   [dstq +strideq*0], xm4
+    movd   [dst4q+strideq*0], xm5
+    pextrd [dstq +strideq*1], xm4, 1
+    pextrd [dst4q+strideq*1], xm5, 1
+    pextrd [dstq +strideq*2], xm4, 2
+    pextrd [dst4q+strideq*2], xm5, 2
+    pextrd [dstq +stride3q ], xm4, 3
+    pextrd [dst4q+stride3q ], xm5, 3
+ %else
+    movq   [dstq+strideq*0], xm4
+    movq   [dstq+strideq*2], xm5
+    movhps [dstq+strideq*1], xm4
+    movhps [dstq+stride3q ], xm5
+ %endif
+%endif
+%endmacro
+
+%macro BORDER_PREP_REGS 2 ; w, h
+    ; off1/2/3[k] [6 total] from [tapq+12+(dir+0/2/6)*2+k]
+    mov           dird, r7m
+    lea           dirq, [tableq+dirq*2+14]
+%if %1*%2*2/mmsize > 1
+ %if %1 == 4
+    DEFINE_ARGS dst, stride, k, dir, stk, pri, sec, stride3, h, off
+ %else
+    DEFINE_ARGS dst, stride, k, dir, stk, pri, sec, h, off
+ %endif
+    mov             hd, %1*%2*2/mmsize
+%else
+    DEFINE_ARGS dst, stride, k, dir, stk, pri, sec, stride3, off
+%endif
+    lea           stkq, [px]
+    pxor           m11, m11
+%endmacro
+
+%macro BORDER_LOAD_BLOCK 2-3 0 ; w, h, init_min_max
+    mov             kd, 1
+%if %1 == 4
+    movq           xm4, [stkq+32*0]
+    movhps         xm4, [stkq+32*1]
+    movq           xm5, [stkq+32*2]
+    movhps         xm5, [stkq+32*3]
+    vinserti128     m4, xm5, 1
+%else
+    mova           xm4, [stkq+32*0]             ; px
+    vinserti128     m4, [stkq+32*1], 1
+%endif
+    pxor           m15, m15                     ; sum
+%if %3 == 1
+    mova            m7, m4                      ; max
+    mova            m8, m4                      ; min
+%endif
+%endmacro
+
+%macro ACCUMULATE_TAP_WORD 6-7 0 ; tap_offset, shift, mask, strength
+                                 ; mul_tap, w, clip
+    ; load p0/p1
+    movsx         offq, byte [dirq+kq+%1]       ; off1
+%if %6 == 4
+    movq           xm5, [stkq+offq*2+32*0]      ; p0
+    movq           xm6, [stkq+offq*2+32*2]
+    movhps         xm5, [stkq+offq*2+32*1]
+    movhps         xm6, [stkq+offq*2+32*3]
+    vinserti128     m5, xm6, 1
+%else
+    movu           xm5, [stkq+offq*2+32*0]      ; p0
+    vinserti128     m5, [stkq+offq*2+32*1], 1
+%endif
+    neg           offq                          ; -off1
+%if %6 == 4
+    movq           xm6, [stkq+offq*2+32*0]      ; p1
+    movq           xm9, [stkq+offq*2+32*2]
+    movhps         xm6, [stkq+offq*2+32*1]
+    movhps         xm9, [stkq+offq*2+32*3]
+    vinserti128     m6, xm9, 1
+%else
+    movu           xm6, [stkq+offq*2+32*0]      ; p1
+    vinserti128     m6, [stkq+offq*2+32*1], 1
+%endif
+%if %7 == 1
+    ; out of bounds values are set to a value that is a both a large unsigned
+    ; value and a negative signed value.
+    ; use signed max and unsigned min to remove them
+    pmaxsw          m7, m5                      ; max after p0
+    pminuw          m8, m5                      ; min after p0
+    pmaxsw          m7, m6                      ; max after p1
+    pminuw          m8, m6                      ; min after p1
+%endif
+
+    ; accumulate sum[m15] over p0/p1
+    ; calculate difference before converting
+    psubw           m5, m4                      ; diff_p0(p0 - px)
+    psubw           m6, m4                      ; diff_p1(p1 - px)
+
+    ; convert to 8-bits with signed saturation
+    ; saturating to large diffs has no impact on the results
+    packsswb        m5, m6
+
+    ; group into pairs so we can accumulate using maddubsw
+    pshufb          m5, m12
+    pabsb           m9, m5
+    psignb         m10, %5, m5
+    psrlw           m5, m9, %2                  ; emulate 8-bit shift
+    pand            m5, %3
+    psubusb         m5, %4, m5
+
+    ; use unsigned min since abs diff can equal 0x80
+    pminub          m5, m9
+    pmaddubsw       m5, m10
+    paddw          m15, m5
+%endmacro
+
+%macro BORDER_ADJUST_PIXEL 2-3 0 ; w, pw_2048, clip
+    pcmpgtw         m9, m11, m15
+    paddw          m15, m9
+    pmulhrsw       m15, %2
+    paddw           m4, m15
+%if %3 == 1
+    pminsw          m4, m7
+    pmaxsw          m4, m8
+%endif
+    packuswb        m4, m4
+    vextracti128   xm5, m4, 1
+%if %1 == 4
+    movd   [dstq+strideq*0], xm4
+    pextrd [dstq+strideq*1], xm4, 1
+    movd   [dstq+strideq*2], xm5
+    pextrd [dstq+stride3q ], xm5, 1
+%else
+    movq [dstq+strideq*0], xm4
+    movq [dstq+strideq*1], xm5
+%endif
+%endmacro
+
+%macro CDEF_FILTER 2 ; w, h
+INIT_YMM avx2
+cglobal cdef_filter_%1x%2_8bpc, 5, 11, 0, dst, stride, left, top, bot, \
+                                          pri, sec, dir, damping, edge
+    mov          edged, edgem
+    cmp          edged, 0xf
+    jne .border_block
+
+    PUSH           r11
+    PUSH           r12
+%if %2 == 4
+%assign regs_used 13
+    ALLOC_STACK   0x60, 16
+    pmovzxbw       xm0, [leftq+1]
+    vpermq          m0, m0, q0110
+    psrldq          m1, m0, 4
+    vpalignr        m2, m0, m0, 12
+    movu    [rsp+0x10], m0
+    movu    [rsp+0x28], m1
+    movu    [rsp+0x40], m2
+%elif %1 == 4
+%assign regs_used 14
+    PUSH           r13
+    ALLOC_STACK 8*2+%1*%2*1, 16
+    pmovzxwd        m0, [leftq]
+    mova    [rsp+0x10], m0
+%else
+%assign regs_used 15
+    PUSH           r13
+    PUSH           r14
+    ALLOC_STACK 8*4+%1*%2*2+32, 16
+    lea            r11, [strideq*3]
+    movu           xm4, [dstq+strideq*2]
+    pmovzxwq        m0, [leftq+0]
+    pmovzxwq        m1, [leftq+8]
+    vinserti128     m4, [dstq+r11], 1
+    pmovzxbd        m2, [leftq+1]
+    pmovzxbd        m3, [leftq+9]
+    mov       [rsp+16], botq
+    mova    [rsp+0x20], m0
+    mova    [rsp+0x40], m1
+    mova    [rsp+0x60], m2
+    mova    [rsp+0x80], m3
+    mova    [rsp+0xa0], m4
+    lea           botq, [dstq+strideq*4]
+%endif
+
+ DEFINE_ARGS dst, stride, left, top, bot, pri, secdmp, zero, pridmp, damping
+    mov       dampingd, r8m
+    xor          zerod, zerod
+    movifnidn     prid, prim
+    sub       dampingd, 31
+    movifnidn  secdmpd, secdmpm
+    test          prid, prid
+    jz .sec_only
+    movd           xm0, prid
+    lzcnt      pridmpd, prid
+    add        pridmpd, dampingd
+    cmovs      pridmpd, zerod
+    mov        [rsp+0], pridmpq                 ; pri_shift
+    test       secdmpd, secdmpd
+    jz .pri_only
+    movd           xm1, secdmpd
+    lzcnt      secdmpd, secdmpd
+    add        secdmpd, dampingd
+    mov        [rsp+8], secdmpq                 ; sec_shift
+
+ DEFINE_ARGS dst, stride, left, top, bot, pri, secdmp, table, pridmp
+    lea         tableq, [tap_table]
+    vpbroadcastb   m13, [tableq+pridmpq]        ; pri_shift_mask
+    vpbroadcastb   m14, [tableq+secdmpq]        ; sec_shift_mask
+
+    ; pri/sec_taps[k] [4 total]
+ DEFINE_ARGS dst, stride, left, top, bot, pri, sec, table, dir
+    vpbroadcastb    m0, xm0                     ; pri_strength
+    vpbroadcastb    m1, xm1                     ; sec_strength
+    and           prid, 1
+    lea           priq, [tableq+priq*2+8]       ; pri_taps
+    lea           secq, [tableq+12]             ; sec_taps
+
+    PREP_REGS       %1, %2
+%if %1*%2 > mmsize
+.v_loop:
+%endif
+    LOAD_BLOCK      %1, %2, 1
+.k_loop:
+    vpbroadcastb    m2, [priq+kq]                          ; pri_taps
+    vpbroadcastb    m3, [secq+kq]                          ; sec_taps
+    ACCUMULATE_TAP_BYTE 2, [rsp+0], m13, m0, m2, %1, %2, 1 ; dir + 0
+    ACCUMULATE_TAP_BYTE 4, [rsp+8], m14, m1, m3, %1, %2, 1 ; dir + 2
+    ACCUMULATE_TAP_BYTE 0, [rsp+8], m14, m1, m3, %1, %2, 1 ; dir - 2
+    dec             kq
+    jge .k_loop
+
+    vpbroadcastd   m10, [pw_2048]
+    pxor            m9, m9
+    ADJUST_PIXEL    %1, %2, m9, m10, 1
+%if %1*%2 > mmsize
+    lea           dstq, [dstq+strideq*4]
+    lea          top1q, [rsp+0xa0]
+    lea          top2q, [rsp+0xb0]
+    mov           botq, [rsp+16]
+    add             hq, 4
+    jl .v_loop
+%endif
+    RET
+
+.pri_only:
+ DEFINE_ARGS dst, stride, left, top, bot, pri, _, table, pridmp
+    lea         tableq, [tap_table]
+    vpbroadcastb   m13, [tableq+pridmpq]        ; pri_shift_mask
+    ; pri/sec_taps[k] [4 total]
+ DEFINE_ARGS dst, stride, left, top, bot, pri, _, table, dir
+    vpbroadcastb    m0, xm0                     ; pri_strength
+    and           prid, 1
+    lea           priq, [tableq+priq*2+8]       ; pri_taps
+    PREP_REGS       %1, %2
+    vpbroadcastd    m3, [pw_2048]
+    pxor            m1, m1
+%if %1*%2 > mmsize
+.pri_v_loop:
+%endif
+    LOAD_BLOCK      %1, %2
+.pri_k_loop:
+    vpbroadcastb    m2, [priq+kq]                       ; pri_taps
+    ACCUMULATE_TAP_BYTE 2, [rsp+0], m13, m0, m2, %1, %2 ; dir + 0
+    dec             kq
+    jge .pri_k_loop
+    ADJUST_PIXEL    %1, %2, m1, m3
+%if %1*%2 > mmsize
+    lea           dstq, [dstq+strideq*4]
+    lea          top1q, [rsp+0xa0]
+    lea          top2q, [rsp+0xb0]
+    mov           botq, [rsp+16]
+    add             hq, 4
+    jl .pri_v_loop
+%endif
+    RET
+
+.sec_only:
+ DEFINE_ARGS dst, stride, left, top, bot, _, secdmp, zero, _, damping
+    movd           xm1, secdmpd
+    lzcnt      secdmpd, secdmpd
+    add        secdmpd, dampingd
+    mov        [rsp+8], secdmpq                 ; sec_shift
+ DEFINE_ARGS dst, stride, left, top, bot, _, secdmp, table
+    lea         tableq, [tap_table]
+    vpbroadcastb   m14, [tableq+secdmpq]        ; sec_shift_mask
+    ; pri/sec_taps[k] [4 total]
+ DEFINE_ARGS dst, stride, left, top, bot, _, sec, table, dir
+    vpbroadcastb    m1, xm1                     ; sec_strength
+    lea           secq, [tableq+12]             ; sec_taps
+    PREP_REGS       %1, %2
+    vpbroadcastd    m2, [pw_2048]
+    pxor            m0, m0
+%if %1*%2 > mmsize
+.sec_v_loop:
+%endif
+    LOAD_BLOCK      %1, %2
+.sec_k_loop:
+    vpbroadcastb    m3, [secq+kq]                       ; sec_taps
+    ACCUMULATE_TAP_BYTE 4, [rsp+8], m14, m1, m3, %1, %2 ; dir + 2
+    ACCUMULATE_TAP_BYTE 0, [rsp+8], m14, m1, m3, %1, %2 ; dir - 2
+    dec             kq
+    jge .sec_k_loop
+    ADJUST_PIXEL    %1, %2, m0, m2
+%if %1*%2 > mmsize
+    lea           dstq, [dstq+strideq*4]
+    lea          top1q, [rsp+0xa0]
+    lea          top2q, [rsp+0xb0]
+    mov           botq, [rsp+16]
+    add             hq, 4
+    jl .sec_v_loop
+%endif
+    RET
+
+.d0k0:
+%if %1 == 4
+ %if %2 == 4
+    vpbroadcastq    m6, [dstq+strideq*1-1]
+    vpbroadcastq   m10, [dstq+strideq*2-1]
+    movd           xm5, [topq+strideq*1+1]
+    movd           xm9, [dstq+strideq*0+1]
+    psrldq         m11, m6, 2
+    psrldq         m12, m10, 2
+    vinserti128     m6, [dstq+stride3q -1], 1
+    vinserti128    m10, [botq          -1], 1
+    vpblendd        m5, m11, 0x10
+    vpblendd        m9, m12, 0x10
+    movu           m11, [blend_4x4+16]
+    punpckldq       m6, m10
+    punpckldq       m5, m9
+    vpblendvb       m6, [rsp+gprsize+0x28], m11
+ %else
+    movd           xm5, [topq +strideq*1+1]
+    movq           xm6, [dstq +strideq*1-1]
+    movq          xm10, [dstq +stride3q -1]
+    movq          xm11, [dst4q+strideq*1-1]
+    pinsrd         xm5, [dstq +strideq*0+1], 1
+    movhps         xm6, [dstq +strideq*2-1]
+    movhps        xm10, [dst4q+strideq*0-1]
+    movhps        xm11, [dst4q+strideq*2-1]
+    psrldq         xm9, xm6, 2
+    shufps         xm5, xm9, q2010   ; -1 +0 +1 +2
+    shufps         xm6, xm10, q2020  ; +1 +2 +3 +4
+    psrldq         xm9, xm11, 2
+    psrldq        xm10, 2
+    shufps        xm10, xm9, q2020   ; +3 +4 +5 +6
+    movd           xm9, [dst4q+stride3q -1]
+    pinsrd         xm9, [botq           -1], 1
+    shufps        xm11, xm9, q1020   ; +5 +6 +7 +8
+    pmovzxbw        m9, [leftq+3]
+    vinserti128     m6, xm11, 1
+    movu           m11, [blend_4x8_0+4]
+    vinserti128     m5, xm10, 1
+    vpblendvb       m6, m9, m11
+ %endif
+%else
+    lea            r13, [blend_8x8_0+16]
+    movq           xm5, [top2q         +1]
+    vbroadcasti128 m10, [dstq+strideq*1-1]
+    vbroadcasti128 m11, [dstq+strideq*2-1]
+    movhps         xm5, [dstq+strideq*0+1]
+    vinserti128     m6, m10, [dstq+stride3q-1], 1
+    vinserti128     m9, m11, [botq         -1], 1
+    psrldq         m10, 2
+    psrldq         m11, 2
+    punpcklqdq      m6, m9
+    movu            m9, [r13+hq*2*1+16*1]
+    punpcklqdq     m10, m11
+    vpblendd        m5, m10, 0xF0
+    vpblendvb       m6, [rsp+gprsize+0x60+hq*8+64+8*1], m9
+%endif
+    ret
+.d1k0:
+.d2k0:
+.d3k0:
+%if %1 == 4
+ %if %2 == 4
+    movq           xm6, [dstq+strideq*0-1]
+    movq           xm9, [dstq+strideq*1-1]
+    vinserti128     m6, [dstq+strideq*2-1], 1
+    vinserti128     m9, [dstq+stride3q -1], 1
+    movu           m11, [rsp+gprsize+0x10]
+    pcmpeqd        m12, m12
+    psrldq          m5, m6, 2
+    psrldq         m10, m9, 2
+    psrld          m12, 24
+    punpckldq       m6, m9
+    punpckldq       m5, m10
+    vpblendvb       m6, m11, m12
+ %else
+    movq           xm6, [dstq +strideq*0-1]
+    movq           xm9, [dstq +strideq*2-1]
+    movhps         xm6, [dstq +strideq*1-1]
+    movhps         xm9, [dstq +stride3q -1]
+    movq          xm10, [dst4q+strideq*0-1]
+    movhps        xm10, [dst4q+strideq*1-1]
+    psrldq         xm5, xm6, 2
+    psrldq        xm11, xm9, 2
+    shufps         xm5, xm11, q2020
+    movq          xm11, [dst4q+strideq*2-1]
+    movhps        xm11, [dst4q+stride3q -1]
+    shufps         xm6, xm9, q2020
+    shufps         xm9, xm10, xm11, q2020
+    vinserti128     m6, xm9, 1
+    pmovzxbw        m9, [leftq+1]
+    psrldq        xm10, 2
+    psrldq        xm11, 2
+    shufps        xm10, xm11, q2020
+    vpbroadcastd   m11, [blend_4x8_0+4]
+    vinserti128     m5, xm10, 1
+    vpblendvb       m6, m9, m11
+ %endif
+%else
+    movu           xm5, [dstq+strideq*0-1]
+    movu           xm9, [dstq+strideq*1-1]
+    vinserti128     m5, [dstq+strideq*2-1], 1
+    vinserti128     m9, [dstq+stride3q -1], 1
+    movu           m10, [blend_8x8_0+16]
+    punpcklqdq      m6, m5, m9
+    vpblendvb       m6, [rsp+gprsize+0x60+hq*8+64], m10
+    psrldq          m5, 2
+    psrldq          m9, 2
+    punpcklqdq      m5, m9
+%endif
+    ret
+.d4k0:
+%if %1 == 4
+ %if %2 == 4
+    vpbroadcastq   m10, [dstq+strideq*1-1]
+    vpbroadcastq   m11, [dstq+strideq*2-1]
+    movd           xm6, [topq+strideq*1-1]
+    movd           xm9, [dstq+strideq*0-1]
+    psrldq          m5, m10, 2
+    psrldq         m12, m11, 2
+    vpblendd        m6, m10, 0x10
+    vpblendd        m9, m11, 0x10
+    movu           m10, [blend_4x4]
+    vinserti128     m5, [dstq+stride3q +1], 1
+    vinserti128    m12, [botq          +1], 1
+    punpckldq       m6, m9
+    punpckldq       m5, m12
+    vpblendvb       m6, [rsp+gprsize+0x40], m10
+ %else
+    movd           xm6, [topq +strideq*1-1]
+    movq           xm9, [dstq +strideq*1-1]
+    movq          xm10, [dstq +stride3q -1]
+    movq          xm11, [dst4q+strideq*1-1]
+    pinsrd         xm6, [dstq +strideq*0-1], 1
+    movhps         xm9, [dstq +strideq*2-1]
+    movhps        xm10, [dst4q+strideq*0-1]
+    movhps        xm11, [dst4q+strideq*2-1]
+    psrldq         xm5, xm9, 2
+    shufps         xm6, xm9, q2010
+    psrldq         xm9, xm10, 2
+    shufps         xm5, xm9, q2020
+    shufps        xm10, xm11, q2020
+    movd           xm9, [dst4q+stride3q +1]
+    vinserti128     m6, xm10, 1
+    pinsrd         xm9, [botq           +1], 1
+    psrldq        xm11, 2
+    pmovzxbw       m10, [leftq-1]
+    shufps        xm11, xm9, q1020
+    movu            m9, [blend_4x8_0]
+    vinserti128     m5, xm11, 1
+    vpblendvb       m6, m10, m9
+ %endif
+%else
+    lea            r13, [blend_8x8_0+8]
+    movq           xm6, [top2q         -1]
+    vbroadcasti128  m5, [dstq+strideq*1-1]
+    vbroadcasti128  m9, [dstq+strideq*2-1]
+    movhps         xm6, [dstq+strideq*0-1]
+    movu           m11, [r13+hq*2*1+16*1]
+    punpcklqdq     m10, m5, m9
+    vinserti128     m5, [dstq+stride3q -1], 1
+    vinserti128     m9, [botq          -1], 1
+    vpblendd        m6, m10, 0xF0
+    vpblendvb       m6, [rsp+gprsize+0x60+hq*8+64-8*1], m11
+    psrldq          m5, 2
+    psrldq          m9, 2
+    punpcklqdq      m5, m9
+%endif
+    ret
+.d5k0:
+.d6k0:
+.d7k0:
+%if %1 == 4
+ %if %2 == 4
+    movd           xm6, [topq+strideq*1  ]
+    vpbroadcastd    m5, [dstq+strideq*1  ]
+    vpbroadcastd    m9, [dstq+strideq*2  ]
+    vpblendd       xm6, [dstq+strideq*0-4], 0x2
+    vpblendd        m5, m9, 0x22
+    vpblendd        m6, m5, 0x30
+    vinserti128     m5, [dstq+stride3q   ], 1
+    vpblendd        m5, [botq         -20], 0x20
+ %else
+    movd           xm6, [topq +strideq*1]
+    movd           xm5, [dstq +strideq*1]
+    movd           xm9, [dstq +stride3q ]
+    movd          xm10, [dst4q+strideq*1]
+    movd          xm11, [dst4q+stride3q ]
+    pinsrd         xm6, [dstq +strideq*0], 1
+    pinsrd         xm5, [dstq +strideq*2], 1
+    pinsrd         xm9, [dst4q+strideq*0], 1
+    pinsrd        xm10, [dst4q+strideq*2], 1
+    pinsrd        xm11, [botq           ], 1
+    punpcklqdq     xm6, xm5
+    punpcklqdq     xm5, xm9
+    punpcklqdq     xm9, xm10
+    punpcklqdq    xm10, xm11
+    vinserti128     m6, xm9, 1
+    vinserti128     m5, xm10, 1
+ %endif
+%else
+    movq           xm6, [top2q         ]
+    movq           xm5, [dstq+strideq*1]
+    movq           xm9, [dstq+stride3q ]
+    movhps         xm6, [dstq+strideq*0]
+    movhps         xm5, [dstq+strideq*2]
+    movhps         xm9, [botq          ]
+    vinserti128     m6, xm5, 1
+    vinserti128     m5, xm9, 1
+%endif
+    ret
+.d0k1:
+%if %1 == 4
+ %if %2 == 4
+    movd           xm6, [dstq+strideq*2-2]
+    movd           xm9, [dstq+stride3q -2]
+    movd           xm5, [topq+strideq*0+2]
+    movd          xm10, [topq+strideq*1+2]
+    pinsrw         xm6, [leftq+4], 0
+    pinsrw         xm9, [leftq+6], 0
+    vinserti128     m5, [dstq+strideq*0+2], 1
+    vinserti128    m10, [dstq+strideq*1+2], 1
+    vinserti128     m6, [botq+strideq*0-2], 1
+    vinserti128     m9, [botq+strideq*1-2], 1
+    punpckldq       m5, m10
+    punpckldq       m6, m9
+ %else
+    movq           xm6, [dstq +strideq*2-2]
+    movd          xm10, [dst4q+strideq*2-2]
+    movd           xm5, [topq +strideq*0+2]
+    movq           xm9, [dst4q+strideq*0-2]
+    movhps         xm6, [dstq +stride3q -2]
+    pinsrw        xm10, [dst4q+stride3q   ], 3
+    pinsrd         xm5, [topq +strideq*1+2], 1
+    movhps         xm9, [dst4q+strideq*1-2]
+    pinsrd        xm10, [botq +strideq*0-2], 2
+    pinsrd         xm5, [dstq +strideq*0+2], 2
+    pinsrd        xm10, [botq +strideq*1-2], 3
+    pinsrd         xm5, [dstq +strideq*1+2], 3
+    shufps        xm11, xm6, xm9, q3131
+    shufps         xm6, xm9, q2020
+    movu            m9, [blend_4x8_3+8]
+    vinserti128     m6, xm10, 1
+    vinserti128     m5, xm11, 1
+    vpblendvb       m6, [rsp+gprsize+0x10+8], m9
+ %endif
+%else
+    lea            r13, [blend_8x8_1+16]
+    movq           xm6, [dstq+strideq*2-2]
+    movq           xm9, [dstq+stride3q -2]
+    movq           xm5, [top1q         +2]
+    movq          xm10, [top2q         +2]
+    movu           m11, [r13+hq*2*2+16*2]
+    vinserti128     m6, [botq+strideq*0-2], 1
+    vinserti128     m9, [botq+strideq*1-2], 1
+    vinserti128     m5, [dstq+strideq*0+2], 1
+    vinserti128    m10, [dstq+strideq*1+2], 1
+    punpcklqdq      m6, m9
+    punpcklqdq      m5, m10
+    vpblendvb       m6, [rsp+gprsize+0x20+hq*8+64+8*2], m11
+%endif
+    ret
+.d1k1:
+%if %1 == 4
+ %if %2 == 4
+    vpbroadcastq    m6, [dstq+strideq*1-2]
+    vpbroadcastq    m9, [dstq+strideq*2-2]
+    movd           xm5, [topq+strideq*1+2]
+    movd          xm10, [dstq+strideq*0+2]
+    psrldq         m11, m6, 4
+    psrldq         m12, m9, 4
+    vpblendd        m5, m11, 0x10
+    movq          xm11, [leftq+2]
+    vinserti128     m6, [dstq+stride3q-2], 1
+    punpckldq     xm11, xm11
+    vpblendd       m10, m12, 0x10
+    pcmpeqd        m12, m12
+    pmovzxwd       m11, xm11
+    psrld          m12, 16
+    punpckldq       m6, m9
+    vpbroadcastd    m9, [botq-2]
+    vpblendvb       m6, m11, m12
+    punpckldq       m5, m10
+    vpblendd        m6, m9, 0x20
+ %else
+    movd           xm5, [topq +strideq*1+2]
+    movq           xm6, [dstq +strideq*1-2]
+    movq           xm9, [dstq +stride3q -2]
+    movq          xm10, [dst4q+strideq*1-2]
+    movd          xm11, [dst4q+stride3q -2]
+    pinsrd         xm5, [dstq +strideq*0+2], 1
+    movhps         xm6, [dstq +strideq*2-2]
+    movhps         xm9, [dst4q+strideq*0-2]
+    movhps        xm10, [dst4q+strideq*2-2]
+    pinsrd        xm11, [botq           -2], 1
+    shufps         xm5, xm6, q3110
+    shufps         xm6, xm9, q2020
+    shufps         xm9, xm10, q3131
+    shufps        xm10, xm11, q1020
+    movu           m11, [blend_4x8_2+4]
+    vinserti128     m6, xm10, 1
+    vinserti128     m5, xm9, 1
+    vpblendvb       m6, [rsp+gprsize+0x10+4], m11
+ %endif
+%else
+    lea            r13, [blend_8x8_1+16]
+    movq           xm5, [top2q         +2]
+    vbroadcasti128  m6, [dstq+strideq*1-2]
+    vbroadcasti128  m9, [dstq+strideq*2-2]
+    movhps         xm5, [dstq+strideq*0+2]
+    shufps         m10, m6, m9, q2121
+    vinserti128     m6, [dstq+stride3q -2], 1
+    vinserti128     m9, [botq          -2], 1
+    movu           m11, [r13+hq*2*1+16*1]
+    vpblendd        m5, m10, 0xF0
+    punpcklqdq      m6, m9
+    vpblendvb       m6, [rsp+gprsize+0x20+hq*8+64+8*1], m11
+%endif
+    ret
+.d2k1:
+%if %1 == 4
+ %if %2 == 4
+    movq          xm11, [leftq]
+    movq           xm6, [dstq+strideq*0-2]
+    movq           xm9, [dstq+strideq*1-2]
+    vinserti128     m6, [dstq+strideq*2-2], 1
+    vinserti128     m9, [dstq+stride3q -2], 1
+    punpckldq     xm11, xm11
+    psrldq          m5, m6, 4
+    psrldq         m10, m9, 4
+    pmovzxwd       m11, xm11
+    punpckldq       m6, m9
+    punpckldq       m5, m10
+    pblendw         m6, m11, 0x05
+ %else
+    movq           xm5, [dstq +strideq*0-2]
+    movq           xm9, [dstq +strideq*2-2]
+    movq          xm10, [dst4q+strideq*0-2]
+    movq          xm11, [dst4q+strideq*2-2]
+    movhps         xm5, [dstq +strideq*1-2]
+    movhps         xm9, [dstq +stride3q -2]
+    movhps        xm10, [dst4q+strideq*1-2]
+    movhps        xm11, [dst4q+stride3q -2]
+    shufps         xm6, xm5, xm9, q2020
+    shufps         xm5, xm9, q3131
+    shufps         xm9, xm10, xm11, q2020
+    shufps        xm10, xm11, q3131
+    pmovzxwd       m11, [leftq]
+    vinserti128     m6, xm9, 1
+    vinserti128     m5, xm10, 1
+    pblendw         m6, m11, 0x55
+ %endif
+%else
+    mova           m11, [rsp+gprsize+0x20+hq*8+64]
+    movu           xm5, [dstq+strideq*0-2]
+    movu           xm9, [dstq+strideq*1-2]
+    vinserti128     m5, [dstq+strideq*2-2], 1
+    vinserti128     m9, [dstq+stride3q -2], 1
+    shufps          m6, m5, m9, q1010
+    shufps          m5, m9, q2121
+    pblendw         m6, m11, 0x11
+%endif
+    ret
+.d3k1:
+%if %1 == 4
+ %if %2 == 4
+    vpbroadcastq   m11, [dstq+strideq*1-2]
+    vpbroadcastq   m12, [dstq+strideq*2-2]
+    movd           xm6, [topq+strideq*1-2]
+    movd           xm9, [dstq+strideq*0-2]
+    pblendw        m11, [leftq-16+2], 0x01
+    pblendw        m12, [leftq-16+4], 0x01
+    pinsrw         xm9, [leftq- 0+0], 0
+    psrldq          m5, m11, 4
+    psrldq         m10, m12, 4
+    vinserti128     m5, [dstq+stride3q +2], 1
+    vinserti128    m10, [botq          +2], 1
+    vpblendd        m6, m11, 0x10
+    vpblendd        m9, m12, 0x10
+    punpckldq       m6, m9
+    punpckldq       m5, m10
+ %else
+    movd           xm6, [topq +strideq*1-2]
+    movq           xm5, [dstq +strideq*1-2]
+    movq           xm9, [dstq +stride3q -2]
+    movq          xm10, [dst4q+strideq*1-2]
+    movd          xm11, [dst4q+stride3q +2]
+    pinsrw         xm6, [dstq +strideq*0  ], 3
+    movhps         xm5, [dstq +strideq*2-2]
+    movhps         xm9, [dst4q+strideq*0-2]
+    movhps        xm10, [dst4q+strideq*2-2]
+    pinsrd        xm11, [botq           +2], 1
+    shufps         xm6, xm5, q2010
+    shufps         xm5, xm9, q3131
+    shufps         xm9, xm10, q2020
+    shufps        xm10, xm11, q1031
+    movu           m11, [blend_4x8_2]
+    vinserti128     m6, xm9, 1
+    vinserti128     m5, xm10, 1
+    vpblendvb       m6, [rsp+gprsize+0x10-4], m11
+ %endif
+%else
+    lea            r13, [blend_8x8_1+8]
+    movq           xm6, [top2q         -2]
+    vbroadcasti128  m5, [dstq+strideq*1-2]
+    vbroadcasti128 m10, [dstq+strideq*2-2]
+    movhps         xm6, [dstq+strideq*0-2]
+    punpcklqdq      m9, m5, m10
+    vinserti128     m5, [dstq+stride3q -2], 1
+    vinserti128    m10, [botq          -2], 1
+    movu           m11, [r13+hq*2*1+16*1]
+    vpblendd        m6, m9, 0xF0
+    shufps          m5, m10, q2121
+    vpblendvb       m6, [rsp+gprsize+0x20+hq*8+64-8*1], m11
+%endif
+    ret
+.d4k1:
+%if %1 == 4
+ %if %2 == 4
+    vinserti128     m6, [dstq+strideq*0-2], 1
+    vinserti128     m9, [dstq+strideq*1-2], 1
+    movd           xm5, [dstq+strideq*2+2]
+    movd          xm10, [dstq+stride3q +2]
+    pblendw         m6, [leftq-16+0], 0x01
+    pblendw         m9, [leftq-16+2], 0x01
+    vinserti128     m5, [botq+strideq*0+2], 1
+    vinserti128    m10, [botq+strideq*1+2], 1
+    vpblendd        m6, [topq+strideq*0-2], 0x01
+    vpblendd        m9, [topq+strideq*1-2], 0x01
+    punpckldq       m5, m10
+    punpckldq       m6, m9
+ %else
+    movd           xm6, [topq +strideq*0-2]
+    movq           xm5, [dstq +strideq*2-2]
+    movq           xm9, [dst4q+strideq*0-2]
+    movd          xm10, [dst4q+strideq*2+2]
+    pinsrd         xm6, [topq +strideq*1-2], 1
+    movhps         xm5, [dstq +stride3q -2]
+    movhps         xm9, [dst4q+strideq*1-2]
+    pinsrd        xm10, [dst4q+stride3q +2], 1
+    pinsrd         xm6, [dstq +strideq*0-2], 2
+    pinsrd        xm10, [botq +strideq*0+2], 2
+    pinsrd         xm6, [dstq +strideq*1-2], 3
+    pinsrd        xm10, [botq +strideq*1+2], 3
+    shufps        xm11, xm5, xm9, q2020
+    shufps         xm5, xm9, q3131
+    movu            m9, [blend_4x8_3]
+    vinserti128     m6, xm11, 1
+    vinserti128     m5, xm10, 1
+    vpblendvb       m6, [rsp+gprsize+0x10-8], m9
+ %endif
+%else
+    lea            r13, [blend_8x8_1]
+    movu           m11, [r13+hq*2*2+16*2]
+    movq           xm6, [top1q         -2]
+    movq           xm9, [top2q         -2]
+    movq           xm5, [dstq+strideq*2+2]
+    movq          xm10, [dstq+stride3q +2]
+    vinserti128     m6, [dstq+strideq*0-2], 1
+    vinserti128     m9, [dstq+strideq*1-2], 1
+    vinserti128     m5, [botq+strideq*0+2], 1
+    vinserti128    m10, [botq+strideq*1+2], 1
+    punpcklqdq      m6, m9
+    vpblendvb       m6, [rsp+gprsize+0x20+hq*8+64-8*2], m11
+    punpcklqdq      m5, m10
+%endif
+    ret
+.d5k1:
+%if %1 == 4
+ %if %2 == 4
+    movd           xm6, [topq+strideq*0-1]
+    movd           xm9, [topq+strideq*1-1]
+    movd           xm5, [dstq+strideq*2+1]
+    movd          xm10, [dstq+stride3q +1]
+    pcmpeqd        m12, m12
+    pmovzxbw       m11, [leftq-8+1]
+    psrld          m12, 24
+    vinserti128     m6, [dstq+strideq*0-1], 1
+    vinserti128     m9, [dstq+strideq*1-1], 1
+    vinserti128     m5, [botq+strideq*0+1], 1
+    vinserti128    m10, [botq+strideq*1+1], 1
+    punpckldq       m6, m9
+    pxor            m9, m9
+    vpblendd       m12, m9, 0x0F
+    punpckldq       m5, m10
+    vpblendvb       m6, m11, m12
+ %else
+    movd           xm6, [topq +strideq*0-1]
+    movq           xm5, [dstq +strideq*2-1]
+    movq           xm9, [dst4q+strideq*0-1]
+    movd          xm10, [dst4q+strideq*2+1]
+    pinsrd         xm6, [topq +strideq*1-1], 1
+    movhps         xm5, [dstq +stride3q -1]
+    movhps         xm9, [dst4q+strideq*1-1]
+    pinsrd        xm10, [dst4q+stride3q +1], 1
+    pinsrd         xm6, [dstq +strideq*0-1], 2
+    pinsrd        xm10, [botq +strideq*0+1], 2
+    pinsrd         xm6, [dstq +strideq*1-1], 3
+    pinsrd        xm10, [botq +strideq*1+1], 3
+    shufps        xm11, xm5, xm9, q2020
+    vinserti128     m6, xm11, 1
+    pmovzxbw       m11, [leftq-3]
+    psrldq         xm5, 2
+    psrldq         xm9, 2
+    shufps         xm5, xm9, q2020
+    movu            m9, [blend_4x8_1]
+    vinserti128     m5, xm10, 1
+    vpblendvb       m6, m11, m9
+ %endif
+%else
+    lea            r13, [blend_8x8_0]
+    movu           m11, [r13+hq*2*2+16*2]
+    movq           xm6, [top1q         -1]
+    movq           xm9, [top2q         -1]
+    movq           xm5, [dstq+strideq*2+1]
+    movq          xm10, [dstq+stride3q +1]
+    vinserti128     m6, [dstq+strideq*0-1], 1
+    vinserti128     m9, [dstq+strideq*1-1], 1
+    vinserti128     m5, [botq+strideq*0+1], 1
+    vinserti128    m10, [botq+strideq*1+1], 1
+    punpcklqdq      m6, m9
+    punpcklqdq      m5, m10
+    vpblendvb       m6, [rsp+gprsize+0x60+hq*8+64-8*2], m11
+%endif
+    ret
+.d6k1:
+%if %1 == 4
+ %if %2 == 4
+    movd           xm6, [topq+strideq*0]
+    movd           xm9, [topq+strideq*1]
+    movd           xm5, [dstq+strideq*2]
+    movd          xm10, [dstq+stride3q ]
+    vinserti128     m6, [dstq+strideq*0], 1
+    vinserti128     m9, [dstq+strideq*1], 1
+    vinserti128     m5, [botq+strideq*0], 1
+    vinserti128    m10, [botq+strideq*1], 1
+    punpckldq       m6, m9
+    punpckldq       m5, m10
+ %else
+    movd           xm5, [dstq +strideq*2]
+    movd           xm6, [topq +strideq*0]
+    movd           xm9, [dst4q+strideq*2]
+    pinsrd         xm5, [dstq +stride3q ], 1
+    pinsrd         xm6, [topq +strideq*1], 1
+    pinsrd         xm9, [dst4q+stride3q ], 1
+    pinsrd         xm5, [dst4q+strideq*0], 2
+    pinsrd         xm6, [dstq +strideq*0], 2
+    pinsrd         xm9, [botq +strideq*0], 2
+    pinsrd         xm5, [dst4q+strideq*1], 3
+    pinsrd         xm6, [dstq +strideq*1], 3
+    pinsrd         xm9, [botq +strideq*1], 3
+    vinserti128     m6, xm5, 1
+    vinserti128     m5, xm9, 1
+ %endif
+%else
+    movq           xm5, [dstq+strideq*2]
+    movq           xm9, [botq+strideq*0]
+    movq           xm6, [top1q         ]
+    movq          xm10, [dstq+strideq*0]
+    movhps         xm5, [dstq+stride3q ]
+    movhps         xm9, [botq+strideq*1]
+    movhps         xm6, [top2q         ]
+    movhps        xm10, [dstq+strideq*1]
+    vinserti128     m5, xm9, 1
+    vinserti128     m6, xm10, 1
+%endif
+    ret
+.d7k1:
+%if %1 == 4
+ %if %2 == 4
+    movd           xm5, [dstq+strideq*2-1]
+    movd           xm9, [dstq+stride3q -1]
+    movd           xm6, [topq+strideq*0+1]
+    movd          xm10, [topq+strideq*1+1]
+    pinsrb         xm5, [leftq+ 5], 0
+    pinsrb         xm9, [leftq+ 7], 0
+    vinserti128     m6, [dstq+strideq*0+1], 1
+    vinserti128    m10, [dstq+strideq*1+1], 1
+    vinserti128     m5, [botq+strideq*0-1], 1
+    vinserti128     m9, [botq+strideq*1-1], 1
+    punpckldq       m6, m10
+    punpckldq       m5, m9
+ %else
+    movd           xm6, [topq +strideq*0+1]
+    movq           xm9, [dstq +strideq*2-1]
+    movq          xm10, [dst4q+strideq*0-1]
+    movd          xm11, [dst4q+strideq*2-1]
+    pinsrd         xm6, [topq +strideq*1+1], 1
+    movhps         xm9, [dstq +stride3q -1]
+    movhps        xm10, [dst4q+strideq*1-1]
+    pinsrd        xm11, [dst4q+stride3q -1], 1
+    pinsrd         xm6, [dstq +strideq*0+1], 2
+    pinsrd        xm11, [botq +strideq*0-1], 2
+    pinsrd         xm6, [dstq +strideq*1+1], 3
+    pinsrd        xm11, [botq +strideq*1-1], 3
+    shufps         xm5, xm9, xm10, q2020
+    vinserti128     m5, xm11, 1
+    pmovzxbw       m11, [leftq+5]
+    psrldq         xm9, 2
+    psrldq        xm10, 2
+    shufps         xm9, xm10, q2020
+    movu           m10, [blend_4x8_1+8]
+    vinserti128     m6, xm9, 1
+    vpblendvb       m5, m11, m10
+ %endif
+%else
+    lea            r13, [blend_8x8_0+16]
+    movq           xm5, [dstq+strideq*2-1]
+    movq           xm9, [botq+strideq*0-1]
+    movq           xm6, [top1q         +1]
+    movq          xm10, [dstq+strideq*0+1]
+    movhps         xm5, [dstq+stride3q -1]
+    movhps         xm9, [botq+strideq*1-1]
+    movhps         xm6, [top2q         +1]
+    movhps        xm10, [dstq+strideq*1+1]
+    movu           m11, [r13+hq*2*2+16*2]
+    vinserti128     m5, xm9, 1
+    vinserti128     m6, xm10, 1
+    vpblendvb       m5, [rsp+gprsize+0x60+hq*8+64+8*2], m11
+%endif
+    ret
+
+.border_block:
+ DEFINE_ARGS dst, stride, left, top, bot, pri, sec, stride3, dst4, edge
+    RESET_STACK_STATE
+    %assign stack_offset stack_offset - (regs_used - 11) * gprsize
+    %assign regs_used 11
+    ALLOC_STACK 2*16+(%2+4)*32, 16
+%define px rsp+2*16+2*32
+
+    pcmpeqw        m14, m14
+    psllw          m14, 15                  ; 0x8000
+
+    ; prepare pixel buffers - body/right
+%if %1 == 4
+    INIT_XMM avx2
+%endif
+%if %2 == 8
+    lea          dst4q, [dstq+strideq*4]
+%endif
+    lea       stride3q, [strideq*3]
+    test         edgeb, 2                   ; have_right
+    jz .no_right
+    pmovzxbw        m1, [dstq+strideq*0]
+    pmovzxbw        m2, [dstq+strideq*1]
+    pmovzxbw        m3, [dstq+strideq*2]
+    pmovzxbw        m4, [dstq+stride3q]
+    mova     [px+0*32], m1
+    mova     [px+1*32], m2
+    mova     [px+2*32], m3
+    mova     [px+3*32], m4
+%if %2 == 8
+    pmovzxbw        m1, [dst4q+strideq*0]
+    pmovzxbw        m2, [dst4q+strideq*1]
+    pmovzxbw        m3, [dst4q+strideq*2]
+    pmovzxbw        m4, [dst4q+stride3q]
+    mova     [px+4*32], m1
+    mova     [px+5*32], m2
+    mova     [px+6*32], m3
+    mova     [px+7*32], m4
+%endif
+    jmp .body_done
+.no_right:
+%if %1 == 4
+    movd           xm1, [dstq+strideq*0]
+    movd           xm2, [dstq+strideq*1]
+    movd           xm3, [dstq+strideq*2]
+    movd           xm4, [dstq+stride3q]
+    pmovzxbw       xm1, xm1
+    pmovzxbw       xm2, xm2
+    pmovzxbw       xm3, xm3
+    pmovzxbw       xm4, xm4
+    movq     [px+0*32], xm1
+    movq     [px+1*32], xm2
+    movq     [px+2*32], xm3
+    movq     [px+3*32], xm4
+%else
+    pmovzxbw       xm1, [dstq+strideq*0]
+    pmovzxbw       xm2, [dstq+strideq*1]
+    pmovzxbw       xm3, [dstq+strideq*2]
+    pmovzxbw       xm4, [dstq+stride3q]
+    mova     [px+0*32], xm1
+    mova     [px+1*32], xm2
+    mova     [px+2*32], xm3
+    mova     [px+3*32], xm4
+%endif
+    movd [px+0*32+%1*2], xm14
+    movd [px+1*32+%1*2], xm14
+    movd [px+2*32+%1*2], xm14
+    movd [px+3*32+%1*2], xm14
+%if %2 == 8
+ %if %1 == 4
+    movd           xm1, [dst4q+strideq*0]
+    movd           xm2, [dst4q+strideq*1]
+    movd           xm3, [dst4q+strideq*2]
+    movd           xm4, [dst4q+stride3q]
+    pmovzxbw       xm1, xm1
+    pmovzxbw       xm2, xm2
+    pmovzxbw       xm3, xm3
+    pmovzxbw       xm4, xm4
+    movq     [px+4*32], xm1
+    movq     [px+5*32], xm2
+    movq     [px+6*32], xm3
+    movq     [px+7*32], xm4
+ %else
+    pmovzxbw       xm1, [dst4q+strideq*0]
+    pmovzxbw       xm2, [dst4q+strideq*1]
+    pmovzxbw       xm3, [dst4q+strideq*2]
+    pmovzxbw       xm4, [dst4q+stride3q]
+    mova     [px+4*32], xm1
+    mova     [px+5*32], xm2
+    mova     [px+6*32], xm3
+    mova     [px+7*32], xm4
+ %endif
+    movd [px+4*32+%1*2], xm14
+    movd [px+5*32+%1*2], xm14
+    movd [px+6*32+%1*2], xm14
+    movd [px+7*32+%1*2], xm14
+%endif
+.body_done:
+
+    ; top
+    test         edgeb, 4                    ; have_top
+    jz .no_top
+    test         edgeb, 1                    ; have_left
+    jz .top_no_left
+    test         edgeb, 2                    ; have_right
+    jz .top_no_right
+    pmovzxbw        m1, [topq+strideq*0-(%1/2)]
+    pmovzxbw        m2, [topq+strideq*1-(%1/2)]
+    movu  [px-2*32-%1], m1
+    movu  [px-1*32-%1], m2
+    jmp .top_done
+.top_no_right:
+    pmovzxbw        m1, [topq+strideq*0-%1]
+    pmovzxbw        m2, [topq+strideq*1-%1]
+    movu [px-2*32-%1*2], m1
+    movu [px-1*32-%1*2], m2
+    movd [px-2*32+%1*2], xm14
+    movd [px-1*32+%1*2], xm14
+    jmp .top_done
+.top_no_left:
+    test         edgeb, 2                   ; have_right
+    jz .top_no_left_right
+    pmovzxbw        m1, [topq+strideq*0]
+    pmovzxbw        m2, [topq+strideq*1]
+    mova   [px-2*32+0], m1
+    mova   [px-1*32+0], m2
+    movd   [px-2*32-4], xm14
+    movd   [px-1*32-4], xm14
+    jmp .top_done
+.top_no_left_right:
+%if %1 == 4
+    movd           xm1, [topq+strideq*0]
+    pinsrd         xm1, [topq+strideq*1], 1
+    pmovzxbw       xm1, xm1
+    movq   [px-2*32+0], xm1
+    movhps [px-1*32+0], xm1
+%else
+    pmovzxbw       xm1, [topq+strideq*0]
+    pmovzxbw       xm2, [topq+strideq*1]
+    mova   [px-2*32+0], xm1
+    mova   [px-1*32+0], xm2
+%endif
+    movd   [px-2*32-4], xm14
+    movd   [px-1*32-4], xm14
+    movd [px-2*32+%1*2], xm14
+    movd [px-1*32+%1*2], xm14
+    jmp .top_done
+.no_top:
+    movu   [px-2*32-%1], m14
+    movu   [px-1*32-%1], m14
+.top_done:
+
+    ; left
+    test         edgeb, 1                   ; have_left
+    jz .no_left
+    pmovzxbw       xm1, [leftq+ 0]
+%if %2 == 8
+    pmovzxbw       xm2, [leftq+ 8]
+%endif
+    movd   [px+0*32-4], xm1
+    pextrd [px+1*32-4], xm1, 1
+    pextrd [px+2*32-4], xm1, 2
+    pextrd [px+3*32-4], xm1, 3
+%if %2 == 8
+    movd   [px+4*32-4], xm2
+    pextrd [px+5*32-4], xm2, 1
+    pextrd [px+6*32-4], xm2, 2
+    pextrd [px+7*32-4], xm2, 3
+%endif
+    jmp .left_done
+.no_left:
+    movd   [px+0*32-4], xm14
+    movd   [px+1*32-4], xm14
+    movd   [px+2*32-4], xm14
+    movd   [px+3*32-4], xm14
+%if %2 == 8
+    movd   [px+4*32-4], xm14
+    movd   [px+5*32-4], xm14
+    movd   [px+6*32-4], xm14
+    movd   [px+7*32-4], xm14
+%endif
+.left_done:
+
+    ; bottom
+ DEFINE_ARGS dst, stride, _, _, bot, pri, sec, stride3, _, edge
+    test         edgeb, 8                   ; have_bottom
+    jz .no_bottom
+    test         edgeb, 1                   ; have_left
+    jz .bottom_no_left
+    test         edgeb, 2                   ; have_right
+    jz .bottom_no_right
+    pmovzxbw        m1, [botq+strideq*0-(%1/2)]
+    pmovzxbw        m2, [botq+strideq*1-(%1/2)]
+    movu   [px+(%2+0)*32-%1], m1
+    movu   [px+(%2+1)*32-%1], m2
+    jmp .bottom_done
+.bottom_no_right:
+    pmovzxbw        m1, [botq+strideq*0-%1]
+    pmovzxbw        m2, [botq+strideq*1-%1]
+    movu  [px+(%2+0)*32-%1*2], m1
+    movu  [px+(%2+1)*32-%1*2], m2
+%if %1 == 8
+    movd  [px+(%2-1)*32+%1*2], xm14                ; overwritten by previous movu
+%endif
+    movd  [px+(%2+0)*32+%1*2], xm14
+    movd  [px+(%2+1)*32+%1*2], xm14
+    jmp .bottom_done
+.bottom_no_left:
+    test          edgeb, 2                  ; have_right
+    jz .bottom_no_left_right
+    pmovzxbw        m1, [botq+strideq*0]
+    pmovzxbw        m2, [botq+strideq*1]
+    mova   [px+(%2+0)*32+0], m1
+    mova   [px+(%2+1)*32+0], m2
+    movd   [px+(%2+0)*32-4], xm14
+    movd   [px+(%2+1)*32-4], xm14
+    jmp .bottom_done
+.bottom_no_left_right:
+%if %1 == 4
+    movd           xm1, [botq+strideq*0]
+    pinsrd         xm1, [botq+strideq*1], 1
+    pmovzxbw       xm1, xm1
+    movq   [px+(%2+0)*32+0], xm1
+    movhps [px+(%2+1)*32+0], xm1
+%else
+    pmovzxbw       xm1, [botq+strideq*0]
+    pmovzxbw       xm2, [botq+strideq*1]
+    mova   [px+(%2+0)*32+0], xm1
+    mova   [px+(%2+1)*32+0], xm2
+%endif
+    movd   [px+(%2+0)*32-4], xm14
+    movd   [px+(%2+1)*32-4], xm14
+    movd  [px+(%2+0)*32+%1*2], xm14
+    movd  [px+(%2+1)*32+%1*2], xm14
+    jmp .bottom_done
+.no_bottom:
+    movu   [px+(%2+0)*32-%1], m14
+    movu   [px+(%2+1)*32-%1], m14
+.bottom_done:
+
+    ; actual filter
+ INIT_YMM avx2
+ DEFINE_ARGS dst, stride, _, pridmp, damping, pri, secdmp, stride3, zero
+%undef edged
+    ; register to shuffle values into after packing
+    vbroadcasti128 m12, [shufb_lohi]
+
+    mov       dampingd, r8m
+    xor          zerod, zerod
+    movifnidn     prid, prim
+    sub       dampingd, 31
+    movifnidn  secdmpd, secdmpm
+    test          prid, prid
+    jz .border_sec_only
+    movd           xm0, prid
+    lzcnt      pridmpd, prid
+    add        pridmpd, dampingd
+    cmovs      pridmpd, zerod
+    mov        [rsp+0], pridmpq                 ; pri_shift
+    test       secdmpd, secdmpd
+    jz .border_pri_only
+    movd           xm1, secdmpd
+    lzcnt      secdmpd, secdmpd
+    add        secdmpd, dampingd
+    mov        [rsp+8], secdmpq                 ; sec_shift
+
+ DEFINE_ARGS dst, stride, _, pridmp, table, pri, secdmp, stride3
+    lea         tableq, [tap_table]
+    vpbroadcastb   m13, [tableq+pridmpq]        ; pri_shift_mask
+    vpbroadcastb   m14, [tableq+secdmpq]        ; sec_shift_mask
+
+    ; pri/sec_taps[k] [4 total]
+ DEFINE_ARGS dst, stride, _, dir, table, pri, sec, stride3
+    vpbroadcastb    m0, xm0                     ; pri_strength
+    vpbroadcastb    m1, xm1                     ; sec_strength
+    and           prid, 1
+    lea           priq, [tableq+priq*2+8]       ; pri_taps
+    lea           secq, [tableq+12]             ; sec_taps
+
+    BORDER_PREP_REGS %1, %2
+%if %1*%2*2/mmsize > 1
+.border_v_loop:
+%endif
+    BORDER_LOAD_BLOCK %1, %2, 1
+.border_k_loop:
+    vpbroadcastb    m2, [priq+kq]               ; pri_taps
+    vpbroadcastb    m3, [secq+kq]               ; sec_taps
+    ACCUMULATE_TAP_WORD 0*2, [rsp+0], m13, m0, m2, %1, 1
+    ACCUMULATE_TAP_WORD 2*2, [rsp+8], m14, m1, m3, %1, 1
+    ACCUMULATE_TAP_WORD 6*2, [rsp+8], m14, m1, m3, %1, 1
+    dec             kq
+    jge .border_k_loop
+
+    vpbroadcastd   m10, [pw_2048]
+    BORDER_ADJUST_PIXEL %1, m10, 1
+%if %1*%2*2/mmsize > 1
+ %define vloop_lines (mmsize/(%1*2))
+    lea           dstq, [dstq+strideq*vloop_lines]
+    add           stkq, 32*vloop_lines
+    dec             hd
+    jg .border_v_loop
+%endif
+    RET
+
+.border_pri_only:
+ DEFINE_ARGS dst, stride, _, pridmp, table, pri, _, stride3
+    lea         tableq, [tap_table]
+    vpbroadcastb   m13, [tableq+pridmpq]        ; pri_shift_mask
+ DEFINE_ARGS dst, stride, _, dir, table, pri, _, stride3
+    vpbroadcastb    m0, xm0                     ; pri_strength
+    and           prid, 1
+    lea           priq, [tableq+priq*2+8]       ; pri_taps
+    BORDER_PREP_REGS %1, %2
+    vpbroadcastd    m1, [pw_2048]
+%if %1*%2*2/mmsize > 1
+.border_pri_v_loop:
+%endif
+    BORDER_LOAD_BLOCK %1, %2
+.border_pri_k_loop:
+    vpbroadcastb    m2, [priq+kq]               ; pri_taps
+    ACCUMULATE_TAP_WORD 0*2, [rsp+0], m13, m0, m2, %1
+    dec             kq
+    jge .border_pri_k_loop
+    BORDER_ADJUST_PIXEL %1, m1
+%if %1*%2*2/mmsize > 1
+ %define vloop_lines (mmsize/(%1*2))
+    lea           dstq, [dstq+strideq*vloop_lines]
+    add           stkq, 32*vloop_lines
+    dec             hd
+    jg .border_pri_v_loop
+%endif
+    RET
+
+.border_sec_only:
+ DEFINE_ARGS dst, stride, _, _, damping, _, secdmp, stride3
+    movd           xm1, secdmpd
+    lzcnt      secdmpd, secdmpd
+    add        secdmpd, dampingd
+    mov        [rsp+8], secdmpq                 ; sec_shift
+ DEFINE_ARGS dst, stride, _, _, table, _, secdmp, stride3
+    lea         tableq, [tap_table]
+    vpbroadcastb   m14, [tableq+secdmpq]        ; sec_shift_mask
+ DEFINE_ARGS dst, stride, _, dir, table, _, sec, stride3
+    vpbroadcastb    m1, xm1                     ; sec_strength
+    lea           secq, [tableq+12]             ; sec_taps
+    BORDER_PREP_REGS %1, %2
+    vpbroadcastd    m0, [pw_2048]
+%if %1*%2*2/mmsize > 1
+.border_sec_v_loop:
+%endif
+    BORDER_LOAD_BLOCK %1, %2
+.border_sec_k_loop:
+    vpbroadcastb    m3, [secq+kq]               ; sec_taps
+    ACCUMULATE_TAP_WORD 2*2, [rsp+8], m14, m1, m3, %1
+    ACCUMULATE_TAP_WORD 6*2, [rsp+8], m14, m1, m3, %1
+    dec             kq
+    jge .border_sec_k_loop
+    BORDER_ADJUST_PIXEL %1, m0
+%if %1*%2*2/mmsize > 1
+ %define vloop_lines (mmsize/(%1*2))
+    lea           dstq, [dstq+strideq*vloop_lines]
+    add           stkq, 32*vloop_lines
+    dec             hd
+    jg .border_sec_v_loop
+%endif
+    RET
+%endmacro
+
+CDEF_FILTER 8, 8
+CDEF_FILTER 4, 8
+CDEF_FILTER 4, 4
+
+INIT_YMM avx2
+cglobal cdef_dir_8bpc, 3, 4, 6, src, stride, var, stride3
+    lea       stride3q, [strideq*3]
+    movq           xm0, [srcq+strideq*0]
+    movq           xm1, [srcq+strideq*1]
+    movq           xm2, [srcq+strideq*2]
+    movq           xm3, [srcq+stride3q ]
+    lea           srcq, [srcq+strideq*4]
+    vpbroadcastq    m4, [srcq+stride3q ]
+    vpbroadcastq    m5, [srcq+strideq*2]
+    vpblendd        m0, m4, 0xf0
+    vpblendd        m1, m5, 0xf0
+    vpbroadcastq    m4, [srcq+strideq*1]
+    vpbroadcastq    m5, [srcq+strideq*0]
+    vpblendd        m2, m4, 0xf0
+    vpblendd        m3, m5, 0xf0
+    pxor            m4, m4
+    punpcklbw       m0, m4
+    punpcklbw       m1, m4
+    punpcklbw       m2, m4
+    punpcklbw       m3, m4
+cglobal_label .main
+    vpbroadcastd    m4, [pw_128]
+    PROLOGUE 3, 4, 15
+    psubw           m0, m4
+    psubw           m1, m4
+    psubw           m2, m4
+    psubw           m3, m4
+
+    ; shuffle registers to generate partial_sum_diag[0-1] together
+    vperm2i128      m7, m0, m0, 0x01
+    vperm2i128      m6, m1, m1, 0x01
+    vperm2i128      m5, m2, m2, 0x01
+    vperm2i128      m4, m3, m3, 0x01
+
+    ; start with partial_sum_hv[0-1]
+    paddw           m8, m0, m1
+    paddw           m9, m2, m3
+    phaddw         m10, m0, m1
+    phaddw         m11, m2, m3
+    paddw           m8, m9
+    phaddw         m10, m11
+    vextracti128   xm9, m8, 1
+    vextracti128  xm11, m10, 1
+    paddw          xm8, xm9                 ; partial_sum_hv[1]
+    phaddw        xm10, xm11                ; partial_sum_hv[0]
+    vinserti128     m8, xm10, 1
+    vpbroadcastd    m9, [div_table+44]
+    pmaddwd         m8, m8
+    pmulld          m8, m9                  ; cost6[2a-d] | cost2[a-d]
+
+    ; create aggregates [lower half]:
+    ; m9 = m0:01234567+m1:x0123456+m2:xx012345+m3:xxx01234+
+    ;      m4:xxxx0123+m5:xxxxx012+m6:xxxxxx01+m7:xxxxxxx0
+    ; m10=             m1:7xxxxxxx+m2:67xxxxxx+m3:567xxxxx+
+    ;      m4:4567xxxx+m5:34567xxx+m6:234567xx+m7:1234567x
+    ; and [upper half]:
+    ; m9 = m0:xxxxxxx0+m1:xxxxxx01+m2:xxxxx012+m3:xxxx0123+
+    ;      m4:xxx01234+m5:xx012345+m6:x0123456+m7:01234567
+    ; m10= m0:1234567x+m1:234567xx+m2:34567xxx+m3:4567xxxx+
+    ;      m4:567xxxxx+m5:67xxxxxx+m6:7xxxxxxx
+    ; and then shuffle m11 [shufw_6543210x], unpcklwd, pmaddwd, pmulld, paddd
+
+    pslldq          m9, m1, 2
+    psrldq         m10, m1, 14
+    pslldq         m11, m2, 4
+    psrldq         m12, m2, 12
+    pslldq         m13, m3, 6
+    psrldq         m14, m3, 10
+    paddw           m9, m11
+    paddw          m10, m12
+    paddw           m9, m13
+    paddw          m10, m14
+    pslldq         m11, m4, 8
+    psrldq         m12, m4, 8
+    pslldq         m13, m5, 10
+    psrldq         m14, m5, 6
+    paddw           m9, m11
+    paddw          m10, m12
+    paddw           m9, m13
+    paddw          m10, m14
+    pslldq         m11, m6, 12
+    psrldq         m12, m6, 4
+    pslldq         m13, m7, 14
+    psrldq         m14, m7, 2
+    paddw           m9, m11
+    paddw          m10, m12
+    paddw           m9, m13
+    paddw          m10, m14                 ; partial_sum_diag[0/1][8-14,zero]
+    vbroadcasti128 m14, [shufw_6543210x]
+    vbroadcasti128 m13, [div_table+16]
+    vbroadcasti128 m12, [div_table+0]
+    paddw           m9, m0                  ; partial_sum_diag[0/1][0-7]
+    pshufb         m10, m14
+    punpckhwd      m11, m9, m10
+    punpcklwd       m9, m10
+    pmaddwd        m11, m11
+    pmaddwd         m9, m9
+    pmulld         m11, m13
+    pmulld          m9, m12
+    paddd           m9, m11                 ; cost0[a-d] | cost4[a-d]
+
+    ; merge horizontally and vertically for partial_sum_alt[0-3]
+    paddw          m10, m0, m1
+    paddw          m11, m2, m3
+    paddw          m12, m4, m5
+    paddw          m13, m6, m7
+    phaddw          m0, m4
+    phaddw          m1, m5
+    phaddw          m2, m6
+    phaddw          m3, m7
+
+    ; create aggregates [lower half]:
+    ; m4 = m10:01234567+m11:x0123456+m12:xx012345+m13:xxx01234
+    ; m11=              m11:7xxxxxxx+m12:67xxxxxx+m13:567xxxxx
+    ; and [upper half]:
+    ; m4 = m10:xxx01234+m11:xx012345+m12:x0123456+m13:01234567
+    ; m11= m10:567xxxxx+m11:67xxxxxx+m12:7xxxxxxx
+    ; and then pshuflw m11 3012, unpcklwd, pmaddwd, pmulld, paddd
+
+    pslldq          m4, m11, 2
+    psrldq         m11, 14
+    pslldq          m5, m12, 4
+    psrldq         m12, 12
+    pslldq          m6, m13, 6
+    psrldq         m13, 10
+    paddw           m4, m10
+    paddw          m11, m12
+    vpbroadcastd   m12, [div_table+44]
+    paddw           m5, m6
+    paddw          m11, m13                 ; partial_sum_alt[3/2] right
+    vbroadcasti128 m13, [div_table+32]
+    paddw           m4, m5                  ; partial_sum_alt[3/2] left
+    pshuflw         m5, m11, q3012
+    punpckhwd       m6, m11, m4
+    punpcklwd       m4, m5
+    pmaddwd         m6, m6
+    pmaddwd         m4, m4
+    pmulld          m6, m12
+    pmulld          m4, m13
+    paddd           m4, m6                  ; cost7[a-d] | cost5[a-d]
+
+    ; create aggregates [lower half]:
+    ; m5 = m0:01234567+m1:x0123456+m2:xx012345+m3:xxx01234
+    ; m1 =             m1:7xxxxxxx+m2:67xxxxxx+m3:567xxxxx
+    ; and [upper half]:
+    ; m5 = m0:xxx01234+m1:xx012345+m2:x0123456+m3:01234567
+    ; m1 = m0:567xxxxx+m1:67xxxxxx+m2:7xxxxxxx
+    ; and then pshuflw m1 3012, unpcklwd, pmaddwd, pmulld, paddd
+
+    pslldq          m5, m1, 2
+    psrldq          m1, 14
+    pslldq          m6, m2, 4
+    psrldq          m2, 12
+    pslldq          m7, m3, 6
+    psrldq          m3, 10
+    paddw           m5, m0
+    paddw           m1, m2
+    paddw           m6, m7
+    paddw           m1, m3                  ; partial_sum_alt[0/1] right
+    paddw           m5, m6                  ; partial_sum_alt[0/1] left
+    pshuflw         m0, m1, q3012
+    punpckhwd       m1, m5
+    punpcklwd       m5, m0
+    pmaddwd         m1, m1
+    pmaddwd         m5, m5
+    pmulld          m1, m12
+    pmulld          m5, m13
+    paddd           m5, m1                  ; cost1[a-d] | cost3[a-d]
+
+    mova           xm0, [pd_47130256+ 16]
+    mova            m1, [pd_47130256]
+    phaddd          m9, m8
+    phaddd          m5, m4
+    phaddd          m9, m5
+    vpermd          m0, m9                  ; cost[0-3]
+    vpermd          m1, m9                  ; cost[4-7] | cost[0-3]
+
+    ; now find the best cost
+    pmaxsd         xm2, xm0, xm1
+    pshufd         xm3, xm2, q1032
+    pmaxsd         xm2, xm3
+    pshufd         xm3, xm2, q2301
+    pmaxsd         xm2, xm3 ; best cost
+
+    ; find the idx using minpos
+    ; make everything other than the best cost negative via subtraction
+    ; find the min of unsigned 16-bit ints to sort out the negative values
+    psubd          xm4, xm1, xm2
+    psubd          xm3, xm0, xm2
+    packssdw       xm3, xm4
+    phminposuw     xm3, xm3
+
+    ; convert idx to 32-bits
+    psrld          xm3, 16
+    movd           eax, xm3
+
+    ; get idx^4 complement
+    vpermd          m3, m1
+    psubd          xm2, xm3
+    psrld          xm2, 10
+    movd        [varq], xm2
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/cdef_avx512.asm b/media/libdav1d/src/src/x86/cdef_avx512.asm
new file mode 100644
index 0000000000..b4f9c008ca
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cdef_avx512.asm
@@ -0,0 +1,860 @@
+; Copyright © 2020, VideoLAN and dav1d authors
+; Copyright © 2020, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+%macro DUP4 1-*
+    %rep %0
+        times 4 db %1
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro DIRS 16 ; cdef_directions[]
+    %rep 4 + 16 + 4 ; 6 7   0 1 2 3 4 5 6 7   0 1
+        ; masking away unused bits allows us to use a single vpaddd {1to16}
+        ; instruction instead of having to do vpbroadcastd + paddb
+        db %13 & 0x3f, -%13 & 0x3f
+        %rotate 1
+    %endrep
+%endmacro
+
+SECTION_RODATA 64
+
+lut_perm_4x4:  db 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79
+               db 16, 17,  0,  1,  2,  3,  4,  5, 18, 19,  8,  9, 10, 11, 12, 13
+               db 20, 21, 80, 81, 82, 83, 84, 85, 22, 23, 32, 33, 34, 35, 36, 37
+               db 98, 99,100,101,102,103,104,105, 50, 51, 52, 53, 54, 55, 56, 57
+lut_perm_4x8a: db 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79
+               db 96, 97,  0,  1,  2,  3,  4,  5, 98, 99,  8,  9, 10, 11, 12, 13
+lut_perm_4x8b:db 100,101, 16, 17, 18, 19, 20, 21,102,103, 24, 25, 26, 27, 28, 29
+              db 104,105, 32, 33, 34, 35, 36, 37,106,107, 40, 41, 42, 43, 44, 45
+              db 108,109, 48, 49, 50, 51, 52, 53,110,111, 56, 57, 58, 59, 60, 61
+               db 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
+pd_01234567:   dd  0,  1,  2,  3,  4,  5,  6,  7
+lut_perm_8x8a: db 32, 33, 34, 35, 36, 37, 38, 39, 48, 49, 50, 51, 52, 53, 54, 55
+               db 36, 37, 38, 39, 40, 41, 42, 43, 52, 53, 54, 55, 56, 57, 58, 59
+lut_perm_8x8b: db 12, 13,  0,  1,  2,  3,  4,  5, 14, 15, 16, 17, 18, 19, 20, 21
+               db  2,  3,  4,  5,  6,  7,  8,  9, 18, 19, 20, 21, 22, 23, 24, 25
+               db 28, 29, 32, 33, 34, 35, 36, 37, 30, 31, 48, 49, 50, 51, 52, 53
+               db 34, 35, 36, 37, 38, 39, 40, 41, 50, 51, 52, 53, 54, 55, 56, 57
+end_perm:      db  1,  5,  9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61
+               db  3,  7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63
+end_perm_clip: db  0,  4,  8, 12,  2,  6, 10, 14, 16, 20, 24, 28, 18, 22, 26, 30
+               db 32, 36, 40, 44, 34, 38, 42, 46, 48, 52, 56, 60, 50, 54, 58, 62
+               db  1,  5,  9, 13,  3,  7, 11, 15, 17, 21, 25, 29, 19, 23, 27, 31
+               db 33, 37, 41, 45, 35, 39, 43, 47, 49, 53, 57, 61, 51, 55, 59, 63
+edge_mask:     dq 0x00003c3c3c3c0000, 0x00003f3f3f3f0000 ; 0000, 0001
+               dq 0x0000fcfcfcfc0000, 0x0000ffffffff0000 ; 0010, 0011
+               dq 0x00003c3c3c3c3c3c, 0x00003f3f3f3f3f3f ; 0100, 0101
+               dq 0x0000fcfcfcfcfcfc, 0x0000ffffffffffff ; 0110, 0111
+               dq 0x3c3c3c3c3c3c0000, 0x3f3f3f3f3f3f0000 ; 1000, 1001
+               dq 0xfcfcfcfcfcfc0000, 0xffffffffffff0000 ; 1010, 1011
+               dq 0x3c3c3c3c3c3c3c3c, 0x3f3f3f3f3f3f3f3f ; 1100, 1101
+               dq 0xfcfcfcfcfcfcfcfc, 0xffffffffffffffff ; 1110, 1111
+px_idx:      DUP4 18, 19, 20, 21, 26, 27, 28, 29, 34, 35, 36, 37, 42, 43, 44, 45
+cdef_dirs:   DIRS -7,-14,  1, -6,  1,  2,  1, 10,  9, 18,  8, 17,  8, 16,  8, 15
+gf_shr:        dq 0x0102040810204080, 0x0102040810204080 ; >> 0, >> 0
+               dq 0x0204081020408000, 0x0408102040800000 ; >> 1, >> 2
+               dq 0x0810204080000000, 0x1020408000000000 ; >> 3, >> 4
+               dq 0x2040800000000000, 0x4080000000000000 ; >> 5, >> 6
+pri_tap:       db 64, 64, 32, 32, 48, 48, 48, 48         ; left-shifted by 4
+sec_tap:       db 32, 32, 16, 16
+pd_268435568:  dd 268435568
+
+SECTION .text
+
+%if WIN64
+DECLARE_REG_TMP 4
+%else
+DECLARE_REG_TMP 8
+%endif
+
+; lut:
+; t0 t1 t2 t3 t4 t5 t6 t7
+; T0 T1 T2 T3 T4 T5 T6 T7
+; L0 L1 00 01 02 03 04 05
+; L2 L3 10 11 12 13 14 15
+; L4 L5 20 21 22 23 24 25
+; L6 L7 30 31 32 33 34 35
+; b0 b1 b2 b3 b4 b5 b6 b7
+; B0 B1 B2 B3 B4 B5 B6 B7
+
+INIT_ZMM avx512icl
+cglobal cdef_filter_4x4_8bpc, 5, 8, 13, dst, stride, left, top, bot, \
+                                        pri, sec, dir, damping, edge
+%define base r7-edge_mask
+    movq         xmm0, [dstq+strideq*0]
+    movhps       xmm0, [dstq+strideq*1]
+    lea            r7, [edge_mask]
+    movq         xmm1, [topq+strideq*0-2]
+    movhps       xmm1, [topq+strideq*1-2]
+    mov           r6d, edgem
+    vinserti32x4  ym0, ymm0, [leftq], 1
+    lea            r2, [strideq*3]
+    vinserti32x4  ym1, ymm1, [dstq+strideq*2], 1
+    mova           m5, [base+lut_perm_4x4]
+    vinserti32x4   m0, [dstq+r2], 2
+    test          r6b, 0x08      ; avoid buffer overread
+    jz .main
+    vinserti32x4   m1, [botq+strideq*0-4], 2
+    vinserti32x4   m0, [botq+strideq*1-4], 3
+.main:
+    movifnidn    prid, prim
+    mov           t0d, dirm
+    mova           m3, [base+px_idx]
+    mov           r3d, dampingm
+    vpermi2b       m5, m0, m1    ; lut
+    vpbroadcastd   m0, [base+pd_268435568] ; (1 << 28) + (7 << 4)
+    pxor           m7, m7
+    lea            r3, [r7+r3*8] ; gf_shr + (damping - 30) * 8
+    vpermb         m6, m3, m5    ; px
+    cmp           r6d, 0x0f
+    jne .mask_edges              ; mask edges only if required
+    test         prid, prid
+    jz .sec_only
+    vpaddd         m1, m3, [base+cdef_dirs+(t0+2)*4] {1to16} ; dir
+    vpermb         m1, m1, m5    ; k0p0 k0p1 k1p0 k1p1
+%macro CDEF_FILTER_4x4_PRI 0
+    vpcmpub        k1, m6, m1, 6 ; px > pN
+    psubb          m2, m1, m6
+    lzcnt         r6d, prid
+    vpsubb     m2{k1}, m6, m1    ; abs(diff)
+    vpbroadcastb   m4, prid
+    and          prid, 1
+    vgf2p8affineqb m9, m2, [r3+r6*8] {1to8}, 0 ; abs(diff) >> shift
+    movifnidn    secd, secm
+    vpbroadcastd  m10, [base+pri_tap+priq*4]
+    vpsubb    m10{k1}, m7, m10   ; apply_sign(pri_tap)
+    psubusb        m4, m9        ; imax(0, pri_strength - (abs(diff) >> shift)))
+    pminub         m2, m4
+    vpdpbusd       m0, m2, m10   ; sum
+%endmacro
+    CDEF_FILTER_4x4_PRI
+    test         secd, secd
+    jz .end_no_clip
+    call .sec
+.end_clip:
+    pminub         m4, m6, m1
+    pmaxub         m1, m6
+    pminub         m5, m2, m3
+    pmaxub         m2, m3
+    pminub         m4, m5
+    pmaxub         m2, m1
+    psrldq         m1, m4, 2
+    psrldq         m3, m2, 2
+    pminub         m1, m4
+    vpcmpw         k1, m0, m7, 1
+    vpshldd        m6, m0, 8
+    pmaxub         m2, m3
+    pslldq         m3, m1, 1
+    psubw          m7, m0
+    paddusw        m0, m6     ; clip >0xff
+    vpsubusw   m0{k1}, m6, m7 ; clip <0x00
+    pslldq         m4, m2, 1
+    pminub         m1, m3
+    pmaxub         m2, m4
+    pmaxub         m0, m1
+    pminub         m0, m2
+    jmp .end
+.sec_only:
+    movifnidn    secd, secm
+    call .sec
+.end_no_clip:
+    vpshldd        m6, m0, 8  ; (px << 8) + ((sum > -8) << 4)
+    paddw          m0, m6     ; (px << 8) + ((sum + (sum > -8) + 7) << 4)
+.end:
+    mova          xm1, [base+end_perm]
+    vpermb         m0, m1, m0 ; output in bits 8-15 of each dword
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r2       ], xm0, 3
+    RET
+.mask_edges_sec_only:
+    movifnidn    secd, secm
+    call .mask_edges_sec
+    jmp .end_no_clip
+ALIGN function_align
+.mask_edges:
+    vpbroadcastq   m8, [base+edge_mask+r6*8]
+    test         prid, prid
+    jz .mask_edges_sec_only
+    vpaddd         m2, m3, [base+cdef_dirs+(t0+2)*4] {1to16}
+    vpshufbitqmb   k1, m8, m2 ; index in-range
+    mova           m1, m6
+    vpermb     m1{k1}, m2, m5
+    CDEF_FILTER_4x4_PRI
+    test         secd, secd
+    jz .end_no_clip
+    call .mask_edges_sec
+    jmp .end_clip
+.mask_edges_sec:
+    vpaddd         m4, m3, [base+cdef_dirs+(t0+4)*4] {1to16}
+    vpaddd         m9, m3, [base+cdef_dirs+(t0+0)*4] {1to16}
+    vpshufbitqmb   k1, m8, m4
+    mova           m2, m6
+    vpermb     m2{k1}, m4, m5
+    vpshufbitqmb   k1, m8, m9
+    mova           m3, m6
+    vpermb     m3{k1}, m9, m5
+    jmp .sec_main
+ALIGN function_align
+.sec:
+    vpaddd         m2, m3, [base+cdef_dirs+(t0+4)*4] {1to16} ; dir + 2
+    vpaddd         m3,     [base+cdef_dirs+(t0+0)*4] {1to16} ; dir - 2
+    vpermb         m2, m2, m5 ; k0s0 k0s1 k1s0 k1s1
+    vpermb         m3, m3, m5 ; k0s2 k0s3 k1s2 k1s3
+.sec_main:
+    vpbroadcastd   m8, [base+sec_tap]
+    vpcmpub        k1, m6, m2, 6
+    psubb          m4, m2, m6
+    vpbroadcastb  m12, secd
+    lzcnt        secd, secd
+    vpsubb     m4{k1}, m6, m2
+    vpcmpub        k2, m6, m3, 6
+    vpbroadcastq  m11, [r3+secq*8]
+    gf2p8affineqb m10, m4, m11, 0
+    psubb          m5, m3, m6
+    mova           m9, m8
+    vpsubb     m8{k1}, m7, m8
+    psubusb       m10, m12, m10
+    vpsubb     m5{k2}, m6, m3
+    pminub         m4, m10
+    vpdpbusd       m0, m4, m8
+    gf2p8affineqb m11, m5, m11, 0
+    vpsubb     m9{k2}, m7, m9
+    psubusb       m12, m11
+    pminub         m5, m12
+    vpdpbusd       m0, m5, m9
+    ret
+
+DECLARE_REG_TMP 2, 7
+
+;         lut top                lut bottom
+; t0 t1 t2 t3 t4 t5 t6 t7  L4 L5 20 21 22 23 24 25
+; T0 T1 T2 T3 T4 T5 T6 T7  L6 L7 30 31 32 33 34 35
+; L0 L1 00 01 02 03 04 05  L8 L9 40 41 42 43 44 45
+; L2 L3 10 11 12 13 14 15  La Lb 50 51 52 53 54 55
+; L4 L5 20 21 22 23 24 25  Lc Ld 60 61 62 63 64 65
+; L6 L7 30 31 32 33 34 35  Le Lf 70 71 72 73 74 75
+; L8 L9 40 41 42 43 44 45  b0 b1 b2 b3 b4 b5 b6 b7
+; La Lb 50 51 52 53 54 55  B0 B1 B2 B3 B4 B5 B6 B7
+
+cglobal cdef_filter_4x8_8bpc, 5, 9, 22, dst, stride, left, top, bot, \
+                                        pri, sec, dir, damping, edge
+%define base r8-edge_mask
+    vpbroadcastd ym21, strided
+    mov           r6d, edgem
+    lea            r8, [edge_mask]
+    movq          xm1, [topq+strideq*0-2]
+    pmulld       ym21, [base+pd_01234567]
+    kxnorb         k1, k1, k1
+    movq          xm2, [topq+strideq*1-2]
+    vpgatherdq m0{k1}, [dstq+ym21]  ; +0+1 +2+3 +4+5 +6+7
+    mova          m14, [base+lut_perm_4x8a]
+    movu          m15, [base+lut_perm_4x8b]
+    test          r6b, 0x08         ; avoid buffer overread
+    jz .main
+    vinserti32x4  ym1, [botq+strideq*0-2], 1
+    vinserti32x4  ym2, [botq+strideq*1-2], 1
+.main:
+    punpcklqdq    ym1, ym2
+    vinserti32x4   m1, [leftq], 2   ; -2-1 +8+9 left ____
+    movifnidn    prid, prim
+    mov           t0d, dirm
+    mova          m16, [base+px_idx]
+    mov           r3d, dampingm
+    vpermi2b      m14, m0, m1    ; lut top
+    vpermi2b      m15, m0, m1    ; lut bottom
+    vpbroadcastd   m0, [base+pd_268435568] ; (1 << 28) + (7 << 4)
+    pxor          m20, m20
+    lea            r3, [r8+r3*8] ; gf_shr + (damping - 30) * 8
+    vpermb         m2, m16, m14  ; pxt
+    vpermb         m3, m16, m15  ; pxb
+    mova           m1, m0
+    cmp           r6b, 0x0f
+    jne .mask_edges              ; mask edges only if required
+    test         prid, prid
+    jz .sec_only
+    vpaddd         m6, m16, [base+cdef_dirs+(t0+2)*4] {1to16} ; dir
+    vpermb         m4, m6, m14   ; pNt k0p0 k0p1 k1p0 k1p1
+    vpermb         m5, m6, m15   ; pNb
+%macro CDEF_FILTER_4x8_PRI 0
+    vpcmpub        k1, m2, m4, 6 ; pxt > pNt
+    vpcmpub        k2, m3, m5, 6 ; pxb > pNb
+    psubb          m6, m4, m2
+    psubb          m7, m5, m3
+    lzcnt         r6d, prid
+    vpsubb     m6{k1}, m2, m4    ; abs(diff_top)
+    vpsubb     m7{k2}, m3, m5    ; abs(diff_bottom)
+    vpbroadcastb  m13, prid
+    vpbroadcastq   m9, [r3+r6*8]
+    and          prid, 1
+    vpbroadcastd  m11, [base+pri_tap+priq*4]
+    vgf2p8affineqb m8, m6, m9, 0 ; abs(dt) >> shift
+    vgf2p8affineqb m9, m7, m9, 0 ; abs(db) >> shift
+    mova          m10, m11
+    movifnidn     t1d, secm
+    vpsubb    m10{k1}, m20, m11  ; apply_sign(pri_tap_top)
+    vpsubb    m11{k2}, m20, m11  ; apply_sign(pri_tap_bottom)
+    psubusb       m12, m13, m8   ; imax(0, pri_strength - (abs(dt) >> shift)))
+    psubusb       m13, m13, m9   ; imax(0, pri_strength - (abs(db) >> shift)))
+    pminub         m6, m12
+    pminub         m7, m13
+    vpdpbusd       m0, m6, m10   ; sum top
+    vpdpbusd       m1, m7, m11   ; sum bottom
+%endmacro
+    CDEF_FILTER_4x8_PRI
+    test          t1d, t1d       ; sec
+    jz .end_no_clip
+    call .sec
+.end_clip:
+    pminub        m10, m4, m2
+    pminub        m12, m6, m8
+    pminub        m11, m5, m3
+    pminub        m13, m7, m9
+    pmaxub         m4, m2
+    pmaxub         m6, m8
+    pmaxub         m5, m3
+    pmaxub         m7, m9
+    pminub        m10, m12
+    pminub        m11, m13
+    pmaxub         m4, m6
+    pmaxub         m5, m7
+    mov           r2d, 0xAAAAAAAA
+    kmovd          k1, r2d
+    kxnorb         k2, k2, k2       ;   hw   lw
+    vpshrdd       m12, m0, m1, 16   ;  m1lw m0hw
+    vpshrdd        m6, m10, m11, 16 ; m11lw m10hw
+    vpshrdd        m8, m4, m5, 16   ;  m5lw m4hw
+    vpblendmw  m7{k1}, m10, m11     ; m11hw m10lw
+    vpblendmw  m9{k1}, m4, m5       ;  m5hw m4lw
+    vpblendmw  m4{k1}, m0, m12      ;  m1lw m0lw
+    vpblendmw  m5{k1}, m12, m1      ;  m1hw m0hw
+    vpshrdd        m2, m3, 16
+    pminub         m6, m7
+    pmaxub         m8, m9
+    mova         ym14, [base+end_perm]
+    vpcmpw         k1, m4, m20, 1
+    vpshldw        m2, m5, 8
+    pslldq         m7, m6, 1
+    pslldq         m9, m8, 1
+    psubw          m5, m20, m4
+    paddusw        m0, m4, m2 ; clip >0xff
+    pminub         m6, m7
+    pmaxub         m8, m9
+    psubusw    m0{k1}, m2, m5 ; clip <0x00
+    pmaxub         m0, m6
+    pminub         m0, m8
+    vpermb         m0, m14, m0
+    vpscatterdd [dstq+ym21]{k2}, ym0
+    RET
+.sec_only:
+    movifnidn     t1d, secm
+    call .sec
+.end_no_clip:
+    mova          ym4, [base+end_perm]
+    kxnorb         k1, k1, k1
+    vpshldd        m2, m0, 8  ; (px << 8) + ((sum > -8) << 4)
+    vpshldd        m3, m1, 8
+    paddw          m0, m2     ; (px << 8) + ((sum + (sum > -8) + 7) << 4)
+    paddw          m1, m3
+    pslld          m0, 16
+    vpshrdd        m0, m1, 16
+    vpermb         m0, m4, m0 ; output in bits 8-15 of each word
+    vpscatterdd [dstq+ym21]{k1}, ym0
+    RET
+.mask_edges_sec_only:
+    movifnidn     t1d, secm
+    call .mask_edges_sec
+    jmp .end_no_clip
+ALIGN function_align
+.mask_edges:
+    mov           t1d, r6d
+    or            r6d, 8 ; top 4x4 has bottom
+    or            t1d, 4 ; bottom 4x4 has top
+    vpbroadcastq  m17, [base+edge_mask+r6*8]
+    vpbroadcastq  m18, [base+edge_mask+t1*8]
+    test         prid, prid
+    jz .mask_edges_sec_only
+    vpaddd         m6, m16, [base+cdef_dirs+(t0+2)*4] {1to16}
+    vpshufbitqmb   k1, m17, m6 ; index in-range
+    vpshufbitqmb   k2, m18, m6
+    mova           m4, m2
+    mova           m5, m3
+    vpermb     m4{k1}, m6, m14
+    vpermb     m5{k2}, m6, m15
+    CDEF_FILTER_4x8_PRI
+    test          t1d, t1d
+    jz .end_no_clip
+    call .mask_edges_sec
+    jmp .end_clip
+.mask_edges_sec:
+    vpaddd        m10, m16, [base+cdef_dirs+(t0+4)*4] {1to16}
+    vpaddd        m11, m16, [base+cdef_dirs+(t0+0)*4] {1to16}
+    vpshufbitqmb   k1, m17, m10
+    vpshufbitqmb   k2, m18, m10
+    vpshufbitqmb   k3, m17, m11
+    vpshufbitqmb   k4, m18, m11
+    mova           m6, m2
+    mova           m7, m3
+    mova           m8, m2
+    mova           m9, m3
+    vpermb     m6{k1}, m10, m14
+    vpermb     m7{k2}, m10, m15
+    vpermb     m8{k3}, m11, m14
+    vpermb     m9{k4}, m11, m15
+    jmp .sec_main
+ALIGN function_align
+.sec:
+    vpaddd         m8, m16, [base+cdef_dirs+(t0+4)*4] {1to16} ; dir + 2
+    vpaddd         m9, m16, [base+cdef_dirs+(t0+0)*4] {1to16} ; dir - 2
+    vpermb         m6, m8, m14 ; pNt k0s0 k0s1 k1s0 k1s1
+    vpermb         m7, m8, m15 ; pNb
+    vpermb         m8, m9, m14 ; pNt k0s2 k0s3 k1s2 k1s3
+    vpermb         m9, m9, m15 ; pNb
+.sec_main:
+    vpbroadcastb  m18, t1d
+    lzcnt         t1d, t1d
+    vpcmpub        k1, m2, m6, 6
+    vpcmpub        k2, m3, m7, 6
+    vpcmpub        k3, m2, m8, 6
+    vpcmpub        k4, m3, m9, 6
+    vpbroadcastq  m17, [r3+t1*8]
+    psubb         m10, m6, m2
+    psubb         m11, m7, m3
+    psubb         m12, m8, m2
+    psubb         m13, m9, m3
+    vpsubb    m10{k1}, m2, m6      ; abs(dt0)
+    vpsubb    m11{k2}, m3, m7      ; abs(db0)
+    vpsubb    m12{k3}, m2, m8      ; abs(dt1)
+    vpsubb    m13{k4}, m3, m9      ; abs(db1)
+    vpbroadcastd  m19, [base+sec_tap]
+    gf2p8affineqb m14, m10, m17, 0 ; abs(dt0) >> shift
+    gf2p8affineqb m15, m11, m17, 0 ; abs(db0) >> shift
+    gf2p8affineqb m16, m12, m17, 0 ; abs(dt1) >> shift
+    gf2p8affineqb m17, m13, m17, 0 ; abs(db1) >> shift
+    psubusb       m14, m18, m14    ; imax(0, sec_strength - (abs(dt0) >> shift)))
+    psubusb       m15, m18, m15    ; imax(0, sec_strength - (abs(db0) >> shift)))
+    psubusb       m16, m18, m16    ; imax(0, sec_strength - (abs(dt1) >> shift)))
+    psubusb       m17, m18, m17    ; imax(0, sec_strength - (abs(db1) >> shift)))
+    pminub        m10, m14
+    pminub        m11, m15
+    pminub        m12, m16
+    pminub        m13, m17
+    mova          m14, m19
+    mova          m15, m19
+    mova          m16, m19
+    vpsubb    m14{k1}, m20, m19    ; apply_sign(sec_tap_top_0)
+    vpsubb    m15{k2}, m20, m19    ; apply_sign(sec_tap_bottom_0)
+    vpsubb    m16{k3}, m20, m19    ; apply_sign(sec_tap_top_1)
+    vpsubb    m19{k4}, m20, m19    ; apply_sign(sec_tap_bottom_1)
+    vpdpbusd       m0, m10, m14
+    vpdpbusd       m1, m11, m15
+    vpdpbusd       m0, m12, m16
+    vpdpbusd       m1, m13, m19
+    ret
+
+;         lut tl                   lut tr
+; t0 t1 t2 t3 t4 t5 t6 t7  t4 t5 t6 t7 t8 t9 ta tb
+; T0 T1 T2 T3 T4 T5 T6 T7  T4 T5 T6 T7 T8 T9 Ta Tb
+; L0 L1 00 01 02 03 04 05  02 03 04 05 06 07 08 09
+; L2 L3 10 11 12 13 14 15  12 13 14 15 16 17 18 19
+; L4 L5 20 21 22 23 24 25  22 23 24 25 26 27 28 29
+; L6 L7 30 31 32 33 34 35  32 33 34 35 36 37 38 39
+; L8 L9 40 41 42 43 44 45  42 43 44 45 46 47 48 49
+; La Lb 50 51 52 53 54 55  52 53 54 55 56 57 58 59
+;         lut bl                   lut br
+; L4 L5 20 21 22 23 24 25  22 23 24 25 26 27 28 29
+; L6 L7 30 31 32 33 34 35  32 33 34 35 36 37 38 39
+; L8 L9 40 41 42 43 44 45  42 43 44 45 46 47 48 49
+; La Lb 50 51 52 53 54 55  52 53 54 55 56 57 58 59
+; Lc Ld 60 61 62 63 64 65  62 63 64 65 66 67 68 69
+; Le Lf 70 71 72 73 74 75  72 73 74 75 76 77 78 79
+; b0 b1 b2 b3 b4 b5 b6 b7  b4 b5 b6 b7 b8 b9 ba bb
+; B0 B1 B2 B3 B4 B5 B6 B7  B4 B5 B6 B7 B8 B9 Ba Bb
+
+cglobal cdef_filter_8x8_8bpc, 5, 11, 32, 4*64, dst, stride, left, top, bot, \
+                                               pri, sec, dir, damping, edge
+%define base r8-edge_mask
+    movu         xm16, [dstq+strideq*0]
+    pinsrd       xm16, [leftq+4*0], 3
+    mov           r6d, edgem
+    vinserti128  ym16, [dstq+strideq*1], 1
+    lea           r10, [dstq+strideq*4]
+    movu         xm17, [dstq+strideq*2]
+    vinserti32x4  m16, [topq+strideq*0-2], 2
+    lea            r9, [strideq*3]
+    pinsrd       xm17, [leftq+4*1], 3
+    vinserti32x4  m16, [topq+strideq*1-2], 3 ; 0 1 t T
+    lea            r8, [edge_mask]
+    vinserti128  ym17, [dstq+r9       ], 1
+    vpbroadcastd ym18, [leftq+4*2]
+    vpblendd     ym17, ym18, 0x80
+    movu         xm18, [r10 +strideq*2]
+    vinserti32x4  m17, [r10 +strideq*0], 2
+    pinsrd       xm18, [leftq+4*3], 3
+    vinserti32x4  m17, [r10 +strideq*1], 3   ; 2 3 4 5
+    vinserti128  ym18, [r10 +r9       ], 1
+    test          r6b, 0x08       ; avoid buffer overread
+    jz .main
+    vinserti32x4  m18, [botq+strideq*0-2], 2
+    vinserti32x4  m18, [botq+strideq*1-2], 3 ; 6 7 b B
+.main:
+    mova           m0, [base+lut_perm_8x8a]
+    movu           m1, [base+lut_perm_8x8b]
+    mova          m30, [base+px_idx]
+    vpermb        m16, m0, m16
+    movifnidn    prid, prim
+    vpermb        m17, m1, m17
+    mov           t0d, dirm
+    vpermb        m18, m0, m18
+    mov           r3d, dampingm
+    vshufi32x4    m12, m16, m17, q2020 ; lut tl
+    vshufi32x4    m13, m16, m17, q3131 ; lut tr
+    vshufi32x4    m14, m17, m18, q0220 ; lut bl
+    vshufi32x4    m15, m17, m18, q1331 ; lut br
+    vpbroadcastd   m0, [base+pd_268435568] ; (1 << 28) + (7 << 4)
+    pxor          m31, m31
+    lea            r3, [r8+r3*8]  ; gf_shr + (damping - 30) * 8
+    vpermb         m4, m30, m12   ; pxtl
+    mova           m1, m0
+    vpermb         m5, m30, m13   ; pxtr
+    mova           m2, m0
+    vpermb         m6, m30, m14   ; pxbl
+    mova           m3, m0
+    vpermb         m7, m30, m15   ; pxbr
+    cmp           r6b, 0x0f
+    jne .mask_edges               ; mask edges only if required
+    test         prid, prid
+    jz .sec_only
+    vpaddd        m11, m30, [base+cdef_dirs+(t0+2)*4] {1to16} ; dir
+    vpermb         m8, m11, m12   ; pNtl k0p0 k0p1 k1p0 k1p1
+    vpermb         m9, m11, m13   ; pNtr
+    vpermb        m10, m11, m14   ; pNbl
+    vpermb        m11, m11, m15   ; pNbr
+%macro CDEF_FILTER_8x8_PRI 0
+    vpcmpub        k1, m4, m8, 6  ; pxtl > pNtl
+    vpcmpub        k2, m5, m9, 6  ; pxtr > pNtr
+    vpcmpub        k3, m6, m10, 6 ; pxbl > pNbl
+    vpcmpub        k4, m7, m11, 6 ; pxbr > pNbr
+    psubb         m16, m8, m4
+    psubb         m17, m9, m5
+    psubb         m18, m10, m6
+    psubb         m19, m11, m7
+    lzcnt         r6d, prid
+    vpsubb    m16{k1}, m4, m8     ; abs(diff_tl)
+    vpsubb    m17{k2}, m5, m9     ; abs(diff_tr)
+    vpsubb    m18{k3}, m6, m10    ; abs(diff_bl)
+    vpsubb    m19{k4}, m7, m11    ; abs(diff_br)
+    vpbroadcastq  m28, [r3+r6*8]
+    vpbroadcastb  m29, prid
+    and          prid, 1
+    vpbroadcastd  m27, [base+pri_tap+priq*4]
+    vgf2p8affineqb m20, m16, m28, 0 ; abs(dtl) >> shift
+    vgf2p8affineqb m21, m17, m28, 0 ; abs(dtr) >> shift
+    vgf2p8affineqb m22, m18, m28, 0 ; abs(dbl) >> shift
+    vgf2p8affineqb m23, m19, m28, 0 ; abs(dbl) >> shift
+    mova          m24, m27
+    mova          m25, m27
+    mova          m26, m27
+    movifnidn     t1d, secm
+    vpsubb    m24{k1}, m31, m27   ; apply_sign(pri_tap_tl)
+    vpsubb    m25{k2}, m31, m27   ; apply_sign(pri_tap_tr)
+    vpsubb    m26{k3}, m31, m27   ; apply_sign(pri_tap_tl)
+    vpsubb    m27{k4}, m31, m27   ; apply_sign(pri_tap_tr)
+    psubusb       m20, m29, m20   ; imax(0, pri_strength - (abs(dtl) >> shift)))
+    psubusb       m21, m29, m21   ; imax(0, pri_strength - (abs(dtr) >> shift)))
+    psubusb       m22, m29, m22   ; imax(0, pri_strength - (abs(dbl) >> shift)))
+    psubusb       m23, m29, m23   ; imax(0, pri_strength - (abs(dbr) >> shift)))
+    pminub        m16, m20
+    pminub        m17, m21
+    pminub        m18, m22
+    pminub        m19, m23
+    vpdpbusd       m0, m16, m24   ; sum tl
+    vpdpbusd       m1, m17, m25   ; sum tr
+    vpdpbusd       m2, m18, m26   ; sum bl
+    vpdpbusd       m3, m19, m27   ; sum br
+%endmacro
+    CDEF_FILTER_8x8_PRI
+    test          t1d, t1d        ; sec
+    jz .end_no_clip
+    call .sec
+.end_clip:
+    pminub        m20, m8, m4
+    pminub        m24, m12, m16
+    pminub        m21, m9, m5
+    pminub        m25, m13, m17
+    pminub        m22, m10, m6
+    pminub        m26, m14, m18
+    pminub        m23, m11, m7
+    pminub        m27, m15, m19
+    pmaxub         m8, m4
+    pmaxub        m12, m16
+    pmaxub         m9, m5
+    pmaxub        m13, m17
+    pmaxub        m10, m6
+    pmaxub        m14, m18
+    pmaxub        m11, m7
+    pmaxub        m15, m19
+    pminub        m20, m24
+    pminub        m21, m25
+    pminub        m22, m26
+    pminub        m23, m27
+    pmaxub         m8, m12
+    pmaxub         m9, m13
+    pmaxub        m10, m14
+    pmaxub        m11, m15
+    mov           r2d, 0xAAAAAAAA
+    kmovd          k1, r2d
+    vpshrdd       m24,  m0,  m1, 16
+    vpshrdd       m25,  m2,  m3, 16
+    vpshrdd       m12, m20, m21, 16
+    vpshrdd       m14, m22, m23, 16
+    vpshrdd       m16,  m8,  m9, 16
+    vpshrdd       m18, m10, m11, 16
+    vpblendmw m13{k1}, m20, m21
+    vpblendmw m15{k1}, m22, m23
+    vpblendmw m17{k1},  m8, m9
+    vpblendmw m19{k1}, m10, m11
+    vpblendmw m20{k1},  m0, m24
+    vpblendmw m21{k1}, m24, m1
+    vpblendmw m22{k1},  m2, m25
+    vpblendmw m23{k1}, m25, m3
+    vpshrdd        m4, m5, 16
+    vpshrdd        m6, m7, 16
+    pminub        m12, m13
+    pminub        m14, m15
+    pmaxub        m16, m17
+    pmaxub        m18, m19
+    mova           m8, [base+end_perm_clip]
+    vpcmpw         k2, m20, m31, 1
+    vpcmpw         k3, m22, m31, 1
+    vpshldw        m4, m21, 8
+    vpshldw        m6, m23, 8
+    kunpckdq       k1, k1, k1
+    kxnorb         k4, k4, k4
+    vpshrdw       m11, m12, m14, 8
+    vpshrdw       m15, m16, m18, 8
+    vpblendmb m13{k1}, m12, m14
+    vpblendmb m17{k1}, m16, m18
+    psubw         m21, m31, m20
+    psubw         m23, m31, m22
+    paddusw        m0, m20, m4  ; clip >0xff
+    paddusw        m1, m22, m6
+    pminub        m11, m13
+    pmaxub        m15, m17
+    psubusw    m0{k2}, m4, m21  ; clip <0x00
+    psubusw    m1{k3}, m6, m23
+    psrlw          m0, 8
+    vmovdqu8   m0{k1}, m1
+    pmaxub         m0, m11
+    pminub         m0, m15
+    vpermb         m0, m8, m0
+    vextracti32x4 xm1, m0, 1
+    vextracti32x4 xm2, m0, 2
+    vextracti32x4 xm3, m0, 3
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*2], xm1
+    movq   [r10 +strideq*0], xm2
+    movq   [r10 +strideq*2], xm3
+    movhps [dstq+strideq*1], xm0
+    movhps [dstq+r9       ], xm1
+    movhps [r10 +strideq*1], xm2
+    movhps [r10 +r9       ], xm3
+    RET
+.sec_only:
+    movifnidn     t1d, secm
+    call .sec
+.end_no_clip:
+    mova          xm8, [base+end_perm]
+    kxnorb         k1, k1, k1
+    vpshldd        m4, m0, 8  ; (px << 8) + ((sum > -8) << 4)
+    vpshldd        m5, m1, 8
+    vpshldd        m6, m2, 8
+    vpshldd        m7, m3, 8
+    paddw          m0, m4     ; (px << 8) + ((sum + (sum > -8) + 7) << 4)
+    paddw          m1, m5
+    paddw          m2, m6
+    paddw          m3, m7
+    vpermb         m0, m8, m0
+    vpermb         m1, m8, m1
+    vpermb         m2, m8, m2
+    vpermb         m3, m8, m3
+    punpckldq      m4, m0, m1
+    punpckhdq      m0, m1
+    punpckldq      m5, m2, m3
+    punpckhdq      m2, m3
+    movq   [dstq+strideq*0], xm4
+    movq   [dstq+strideq*2], xm0
+    movq   [r10 +strideq*0], xm5
+    movq   [r10 +strideq*2], xm2
+    movhps [dstq+strideq*1], xm4
+    movhps [dstq+r9       ], xm0
+    movhps [r10 +strideq*1], xm5
+    movhps [r10 +r9       ], xm2
+    RET
+.mask_edges_sec_only:
+    movifnidn     t1d, secm
+    call .mask_edges_sec
+    jmp .end_no_clip
+ALIGN function_align
+.mask_edges:
+    mov           t0d, r6d
+    mov           t1d, r6d
+    or            t0d, 0xA ; top-left 4x4 has bottom and right
+    or            t1d, 0x9 ; top-right 4x4 has bottom and left
+    vpbroadcastq  m26, [base+edge_mask+t0*8]
+    vpbroadcastq  m27, [base+edge_mask+t1*8]
+    mov           t1d, r6d
+    or            r6d, 0x6 ; bottom-left 4x4 has top and right
+    or            t1d, 0x5 ; bottom-right 4x4 has top and left
+    vpbroadcastq  m28, [base+edge_mask+r6*8]
+    vpbroadcastq  m29, [base+edge_mask+t1*8]
+    mov           t0d, dirm
+    test         prid, prid
+    jz .mask_edges_sec_only
+    vpaddd        m20, m30, [base+cdef_dirs+(t0+2)*4] {1to16}
+    vpshufbitqmb   k1, m26, m20 ; index in-range
+    vpshufbitqmb   k2, m27, m20
+    vpshufbitqmb   k3, m28, m20
+    vpshufbitqmb   k4, m29, m20
+    mova           m8, m4
+    mova           m9, m5
+    mova          m10, m6
+    mova          m11, m7
+    vpermb     m8{k1}, m20, m12
+    vpermb     m9{k2}, m20, m13
+    vpermb    m10{k3}, m20, m14
+    vpermb    m11{k4}, m20, m15
+    mova   [rsp+0x00], m26
+    mova   [rsp+0x40], m27
+    mova   [rsp+0x80], m28
+    mova   [rsp+0xC0], m29
+    CDEF_FILTER_8x8_PRI
+    test          t1d, t1d
+    jz .end_no_clip
+    mova          m26, [rsp+0x00]
+    mova          m27, [rsp+0x40]
+    mova          m28, [rsp+0x80]
+    mova          m29, [rsp+0xC0]
+    call .mask_edges_sec
+    jmp .end_clip
+.mask_edges_sec:
+    vpaddd        m20, m30, [base+cdef_dirs+(t0+4)*4] {1to16}
+    vpaddd        m21, m30, [base+cdef_dirs+(t0+0)*4] {1to16}
+    vpshufbitqmb   k1, m26, m20
+    vpshufbitqmb   k2, m27, m20
+    vpshufbitqmb   k3, m28, m20
+    vpshufbitqmb   k4, m29, m20
+    mova          m16, m4
+    mova          m17, m5
+    mova          m18, m6
+    mova          m19, m7
+    vpermb    m16{k1}, m20, m12
+    vpermb    m17{k2}, m20, m13
+    vpermb    m18{k3}, m20, m14
+    vpermb    m19{k4}, m20, m15
+    vpshufbitqmb   k1, m26, m21
+    vpshufbitqmb   k2, m27, m21
+    vpshufbitqmb   k3, m28, m21
+    vpshufbitqmb   k4, m29, m21
+    vpermb        m12, m21, m12
+    vpermb        m13, m21, m13
+    vpermb        m14, m21, m14
+    vpermb        m15, m21, m15
+    vpblendmb m12{k1}, m4, m12
+    vpblendmb m13{k2}, m5, m13
+    vpblendmb m14{k3}, m6, m14
+    vpblendmb m15{k4}, m7, m15
+    jmp .sec_main
+ALIGN function_align
+.sec:
+    vpaddd        m20, m30, [base+cdef_dirs+(t0+4)*4] {1to16} ; dir + 2
+    vpaddd        m21, m30, [base+cdef_dirs+(t0+0)*4] {1to16} ; dir - 2
+    vpermb        m16, m20, m12 ; pNtl k0s0 k0s1 k1s0 k1s1
+    vpermb        m17, m20, m13 ; pNtr
+    vpermb        m18, m20, m14 ; pNbl
+    vpermb        m19, m20, m15 ; pNbr
+    vpermb        m12, m21, m12 ; pNtl k0s2 k0s3 k1s2 k1s3
+    vpermb        m13, m21, m13 ; pNtr
+    vpermb        m14, m21, m14 ; pNbl
+    vpermb        m15, m21, m15 ; pNbr
+.sec_main:
+%macro CDEF_FILTER_8x8_SEC 4-5 0 ; load constants
+    vpcmpub        k1, m4, %1, 6
+    vpcmpub        k2, m5, %2, 6
+    vpcmpub        k3, m6, %3, 6
+    vpcmpub        k4, m7, %4, 6
+    psubb         m20, %1, m4
+    psubb         m21, %2, m5
+    psubb         m22, %3, m6
+    psubb         m23, %4, m7
+%if %5
+    vpbroadcastb  m28, t1d
+    lzcnt         t1d, t1d
+    vpbroadcastq  m29, [r3+t1*8]
+%endif
+    vpsubb    m20{k1}, m4, %1
+    vpsubb    m21{k2}, m5, %2
+    vpsubb    m22{k3}, m6, %3
+    vpsubb    m23{k4}, m7, %4
+    gf2p8affineqb m24, m20, m29, 0
+    gf2p8affineqb m25, m21, m29, 0
+    gf2p8affineqb m26, m22, m29, 0
+    gf2p8affineqb m27, m23, m29, 0
+%if %5
+    vpbroadcastd  m30, [base+sec_tap]
+%endif
+    psubusb       m24, m28, m24
+    psubusb       m25, m28, m25
+    psubusb       m26, m28, m26
+    psubusb       m27, m28, m27
+    pminub        m20, m24
+    pminub        m21, m25
+    pminub        m22, m26
+    pminub        m23, m27
+    mova          m24, m30
+    mova          m25, m30
+    mova          m26, m30
+    mova          m27, m30
+    vpsubb    m24{k1}, m31, m30
+    vpsubb    m25{k2}, m31, m30
+    vpsubb    m26{k3}, m31, m30
+    vpsubb    m27{k4}, m31, m30
+    vpdpbusd       m0, m20, m24
+    vpdpbusd       m1, m21, m25
+    vpdpbusd       m2, m22, m26
+    vpdpbusd       m3, m23, m27
+%endmacro
+    CDEF_FILTER_8x8_SEC m16, m17, m18, m19, 1
+    CDEF_FILTER_8x8_SEC m12, m13, m14, m15
+    ret
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/cdef_sse.asm b/media/libdav1d/src/src/x86/cdef_sse.asm
new file mode 100644
index 0000000000..1b353121f4
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cdef_sse.asm
@@ -0,0 +1,1357 @@
+; Copyright © 2018, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; Copyright © 2019, VideoLabs
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 16
+
+%macro DUP8 1-*
+    %rep %0
+        times 8 db %1
+        %rotate 1
+    %endrep
+%endmacro
+
+div_table_sse4:  dd 840, 420, 280, 210, 168, 140, 120, 105
+                 dd 420, 210, 140, 105, 105, 105, 105, 105
+div_table_ssse3: dw 840, 840, 420, 420, 280, 280, 210, 210
+                 dw 168, 168, 140, 140, 120, 120, 105, 105
+                 dw 420, 420, 210, 210, 140, 140, 105, 105
+                 dw 105, 105, 105, 105, 105, 105, 105, 105
+const shufw_6543210x, \
+            db 12, 13, 10, 11,  8,  9,  6,  7,  4,  5,  2,  3,  0,  1, 14, 15
+shufb_lohi: db  0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+pw_8:      times 8 dw 8
+pw_128:    times 8 dw 128
+pw_256:    times 8 dw 256
+pw_2048:   times 8 dw 2048
+pw_0x7FFF: times 8 dw 0x7FFF
+pw_0x8000: times 8 dw 0x8000
+tap_table: ; masks for 8-bit shift emulation
+           DUP8 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80
+           ; weights
+           DUP8 4, 2, 3, 3, 2, 1
+           ; taps indices
+           db -1 * 16 + 1, -2 * 16 + 2
+           db  0 * 16 + 1, -1 * 16 + 2
+           db  0 * 16 + 1,  0 * 16 + 2
+           db  0 * 16 + 1,  1 * 16 + 2
+           db  1 * 16 + 1,  2 * 16 + 2
+           db  1 * 16 + 0,  2 * 16 + 1
+           db  1 * 16 + 0,  2 * 16 + 0
+           db  1 * 16 + 0,  2 * 16 - 1
+           ; the last 6 are repeats of the first 6 so we don't need to & 7
+           db -1 * 16 + 1, -2 * 16 + 2
+           db  0 * 16 + 1, -1 * 16 + 2
+           db  0 * 16 + 1,  0 * 16 + 2
+           db  0 * 16 + 1,  1 * 16 + 2
+           db  1 * 16 + 1,  2 * 16 + 2
+           db  1 * 16 + 0,  2 * 16 + 1
+
+SECTION .text
+
+%macro movif32 2
+ %if ARCH_X86_32
+    mov     %1, %2
+ %endif
+%endmacro
+
+%macro PMOVZXBW 2-3 0 ; %3 = half
+ %if cpuflag(sse4) && %3 == 0
+    pmovzxbw        %1, %2
+ %else
+  %if %3 == 1
+    movd            %1, %2
+  %else
+    movq            %1, %2
+  %endif
+    punpcklbw       %1, m7
+ %endif
+%endmacro
+
+%macro PSHUFB_0 2
+ %if cpuflag(ssse3)
+    pshufb          %1, %2
+ %else
+    punpcklbw       %1, %1
+    pshuflw         %1, %1, q0000
+    punpcklqdq      %1, %1
+ %endif
+%endmacro
+
+%macro MOVDDUP 2
+%if cpuflag(ssse3)
+    movddup         %1, %2
+%else
+    movq            %1, %2
+    punpcklqdq      %1, %1
+%endif
+%endmacro
+
+%macro ACCUMULATE_TAP 7 ; tap_offset, shift, shift_mask, strength, mul_tap, w, minmax
+    ; load p0/p1
+    movsx         offq, byte [dirq+kq+%1+14*8]  ; off1
+ %if %6 == 4
+    movq            m5, [stkq+offq*2+32*0]      ; p0
+    movhps          m5, [stkq+offq*2+32*1]
+ %else
+    movu            m5, [stkq+offq*2+32*0]      ; p0
+ %endif
+    neg           offq                          ; -off1
+ %if %6 == 4
+    movq            m6, [stkq+offq*2+32*0]      ; p1
+    movhps          m6, [stkq+offq*2+32*1]
+ %else
+    movu            m6, [stkq+offq*2+32*0]      ; p1
+ %endif
+ %if %7
+  %if cpuflag(sse4)
+    ; out of bounds values are set to a value that is a both a large unsigned
+    ; value and a negative signed value.
+    ; use signed max and unsigned min to remove them
+    pmaxsw          m7, m5
+    pminuw          m8, m5
+    pmaxsw          m7, m6
+    pminuw          m8, m6
+  %else
+    pcmpeqw         m3, m14, m5
+    pminsw          m8, m5     ; min after p0
+    pandn           m3, m5
+    pmaxsw          m7, m3     ; max after p0
+    pcmpeqw         m3, m14, m6
+    pminsw          m8, m6     ; min after p1
+    pandn           m3, m6
+    pmaxsw          m7, m3     ; max after p1
+  %endif
+ %endif
+
+    ; accumulate sum[m13] over p0/p1
+    psubw           m5, m4     ; diff_p0(p0 - px)
+    psubw           m6, m4     ; diff_p1(p1 - px)
+    packsswb        m5, m6     ; convert pixel diff to 8-bit
+ %if cpuflag(ssse3)
+    pshufb          m5, m13    ; group diffs p0 and p1 into pairs
+    pabsb           m6, m5
+    psignb          m3, %5, m5
+ %else
+    movlhps         m6, m5
+    punpckhbw       m6, m5
+    pxor            m5, m5
+    pcmpgtb         m5, m6
+    paddb           m6, m5
+    pxor            m6, m5
+    paddb           m3, %5, m5
+    pxor            m3, m5
+ %endif
+    pand            m9, %3, m6 ; emulate 8-bit shift
+    psrlw           m9, %2
+    psubusb         m5, %4, m9
+    pminub          m5, m6     ; constrain(diff_p)
+ %if cpuflag(ssse3)
+    pmaddubsw       m5, m3     ; constrain(diff_p) * taps
+ %else
+    psrlw           m9, m5, 8
+    psraw           m6, m3, 8
+    psllw           m5, 8
+    psllw           m3, 8
+    pmullw          m9, m6
+    pmulhw          m5, m3
+    paddw           m5, m9
+ %endif
+    paddw           m0, m5
+%endmacro
+
+%macro LOAD_BODY 3 ; dst, src, block_width
+ %if %3 == 4
+    PMOVZXBW        m0, [%2+strideq*0]
+    PMOVZXBW        m1, [%2+strideq*1]
+    PMOVZXBW        m2, [%2+strideq*2]
+    PMOVZXBW        m3, [%2+stride3q]
+    mova     [%1+32*0], m0
+    mova     [%1+32*1], m1
+    mova     [%1+32*2], m2
+    mova     [%1+32*3], m3
+ %else
+    movu            m0, [%2+strideq*0]
+    movu            m1, [%2+strideq*1]
+    movu            m2, [%2+strideq*2]
+    movu            m3, [%2+stride3q]
+    punpcklbw       m4, m0, m7
+    punpckhbw       m0, m7
+    mova  [%1+32*0+ 0], m4
+    mova  [%1+32*0+16], m0
+    punpcklbw       m4, m1, m7
+    punpckhbw       m1, m7
+    mova  [%1+32*1+ 0], m4
+    mova  [%1+32*1+16], m1
+    punpcklbw       m4, m2, m7
+    punpckhbw       m2, m7
+    mova  [%1+32*2+ 0], m4
+    mova  [%1+32*2+16], m2
+    punpcklbw       m4, m3, m7
+    punpckhbw       m3, m7
+    mova  [%1+32*3+ 0], m4
+    mova  [%1+32*3+16], m3
+ %endif
+%endmacro
+
+%macro CDEF_FILTER_END 2 ; w, minmax
+    pxor            m6, m6
+    pcmpgtw         m6, m0
+    paddw           m0, m6
+ %if cpuflag(ssse3)
+    pmulhrsw        m0, m15
+ %else
+    paddw           m0, m15
+    psraw           m0, 4
+ %endif
+    paddw           m4, m0
+ %if %2
+    pminsw          m4, m7
+    pmaxsw          m4, m8
+ %endif
+    packuswb        m4, m4
+ %if %1 == 4
+    movd [dstq+strideq*0], m4
+    psrlq           m4, 32
+    movd [dstq+strideq*1], m4
+    add           stkq, 32*2
+    lea           dstq, [dstq+strideq*2]
+ %else
+    movq        [dstq], m4
+    add           stkq, 32
+    add           dstq, strideq
+ %endif
+%endmacro
+
+%macro CDEF_FILTER 2 ; w, h
+ %if ARCH_X86_64
+cglobal cdef_filter_%1x%2_8bpc, 5, 9, 16, 3 * 16 + (%2+4)*32, \
+                                dst, stride, left, top, bot, pri, dst4, edge, \
+                                stride3
+  %define px rsp+3*16+2*32
+  %define base 0
+ %else
+cglobal cdef_filter_%1x%2_8bpc, 2, 7, 8, - 7 * 16 - (%2+4)*32, \
+                                dst, stride, left, edge, stride3
+    %define       topq  r2
+    %define       botq  r2
+    %define      dst4q  r2
+    LEA             r5, tap_table
+  %define px esp+7*16+2*32
+  %define base r5-tap_table
+ %endif
+    mov          edged, r9m
+ %if cpuflag(sse4)
+   %define OUT_OF_BOUNDS_MEM [base+pw_0x8000]
+ %else
+   %define OUT_OF_BOUNDS_MEM [base+pw_0x7FFF]
+ %endif
+    mova            m6, OUT_OF_BOUNDS_MEM
+    pxor            m7, m7
+
+    ; prepare pixel buffers - body/right
+ %if %2 == 8
+    lea          dst4q, [dstq+strideq*4]
+ %endif
+    lea       stride3q, [strideq*3]
+    test         edgeb, 2 ; have_right
+    jz .no_right
+    LOAD_BODY       px, dstq, %1
+ %if %2 == 8
+    LOAD_BODY  px+4*32, dst4q, %1
+ %endif
+    jmp .body_done
+.no_right:
+    PMOVZXBW        m0, [dstq+strideq*0], %1 == 4
+    PMOVZXBW        m1, [dstq+strideq*1], %1 == 4
+    PMOVZXBW        m2, [dstq+strideq*2], %1 == 4
+    PMOVZXBW        m3, [dstq+stride3q ], %1 == 4
+    mova     [px+32*0], m0
+    mova     [px+32*1], m1
+    mova     [px+32*2], m2
+    mova     [px+32*3], m3
+    movd [px+32*0+%1*2], m6
+    movd [px+32*1+%1*2], m6
+    movd [px+32*2+%1*2], m6
+    movd [px+32*3+%1*2], m6
+ %if %2 == 8
+    PMOVZXBW        m0, [dst4q+strideq*0], %1 == 4
+    PMOVZXBW        m1, [dst4q+strideq*1], %1 == 4
+    PMOVZXBW        m2, [dst4q+strideq*2], %1 == 4
+    PMOVZXBW        m3, [dst4q+stride3q ], %1 == 4
+    mova     [px+32*4], m0
+    mova     [px+32*5], m1
+    mova     [px+32*6], m2
+    mova     [px+32*7], m3
+    movd [px+32*4+%1*2], m6
+    movd [px+32*5+%1*2], m6
+    movd [px+32*6+%1*2], m6
+    movd [px+32*7+%1*2], m6
+ %endif
+.body_done:
+
+    ; top
+    movifnidn     topq, r3mp
+    test         edgeb, 4 ; have_top
+    jz .no_top
+    test         edgeb, 1 ; have_left
+    jz .top_no_left
+    test         edgeb, 2 ; have_right
+    jz .top_no_right
+ %if %1 == 4
+    PMOVZXBW        m0, [topq+strideq*0-2]
+    PMOVZXBW        m1, [topq+strideq*1-2]
+ %else
+    movu            m0, [topq+strideq*0-4]
+    movu            m1, [topq+strideq*1-4]
+    punpckhbw       m2, m0, m7
+    punpcklbw       m0, m7
+    punpckhbw       m3, m1, m7
+    punpcklbw       m1, m7
+    movu  [px-32*2+8], m2
+    movu  [px-32*1+8], m3
+ %endif
+    movu  [px-32*2-%1], m0
+    movu  [px-32*1-%1], m1
+    jmp .top_done
+.top_no_right:
+ %if %1 == 4
+    PMOVZXBW        m0, [topq+strideq*0-%1]
+    PMOVZXBW        m1, [topq+strideq*1-%1]
+    movu   [px-32*2-8], m0
+    movu   [px-32*1-8], m1
+ %else
+    movu            m0, [topq+strideq*0-%1]
+    movu            m1, [topq+strideq*1-%2]
+    punpckhbw       m2, m0, m7
+    punpcklbw       m0, m7
+    punpckhbw       m3, m1, m7
+    punpcklbw       m1, m7
+    mova  [px-32*2-16], m0
+    mova  [px-32*2+ 0], m2
+    mova  [px-32*1-16], m1
+    mova  [px-32*1+ 0], m3
+ %endif
+    movd [px-32*2+%1*2], m6
+    movd [px-32*1+%1*2], m6
+    jmp .top_done
+.top_no_left:
+    test         edgeb, 2 ; have_right
+    jz .top_no_left_right
+ %if %1 == 4
+    PMOVZXBW        m0, [topq+strideq*0]
+    PMOVZXBW        m1, [topq+strideq*1]
+ %else
+    movu            m0, [topq+strideq*0]
+    movu            m1, [topq+strideq*1]
+    punpckhbw       m2, m0, m7
+    punpcklbw       m0, m7
+    punpckhbw       m3, m1, m7
+    punpcklbw       m1, m7
+    movd  [px-32*2+16], m2
+    movd  [px-32*1+16], m3
+ %endif
+    movd  [px-32*2- 4], m6
+    movd  [px-32*1- 4], m6
+    mova  [px-32*2+ 0], m0
+    mova  [px-32*1+ 0], m1
+    jmp .top_done
+.top_no_left_right:
+    PMOVZXBW        m0, [topq+strideq*0], %1 == 4
+    PMOVZXBW        m1, [topq+strideq*1], %1 == 4
+    movd   [px-32*2-4], m6
+    movd   [px-32*1-4], m6
+    mova   [px-32*2+0], m0
+    mova   [px-32*1+0], m1
+    movd [px-32*2+%1*2], m6
+    movd [px-32*1+%1*2], m6
+    jmp .top_done
+.no_top:
+    movu  [px-32*2- 4], m6
+    movu  [px-32*1- 4], m6
+ %if %1 == 8
+    movq  [px-32*2+12], m6
+    movq  [px-32*1+12], m6
+ %endif
+.top_done:
+
+    ; left
+    test         edgeb, 1 ; have_left
+    jz .no_left
+    movifnidn    leftq, leftmp
+ %if %2 == 4
+    movq            m0, [leftq]
+ %else
+    movu            m0, [leftq]
+ %endif
+ %if %2 == 4
+    punpcklbw       m0, m7
+ %else
+    punpckhbw       m1, m0, m7
+    punpcklbw       m0, m7
+    movhlps         m3, m1
+    movd   [px+32*4-4], m1
+    movd   [px+32*6-4], m3
+    psrlq           m1, 32
+    psrlq           m3, 32
+    movd   [px+32*5-4], m1
+    movd   [px+32*7-4], m3
+ %endif
+    movhlps         m2, m0
+    movd   [px+32*0-4], m0
+    movd   [px+32*2-4], m2
+    psrlq           m0, 32
+    psrlq           m2, 32
+    movd   [px+32*1-4], m0
+    movd   [px+32*3-4], m2
+    jmp .left_done
+.no_left:
+    movd   [px+32*0-4], m6
+    movd   [px+32*1-4], m6
+    movd   [px+32*2-4], m6
+    movd   [px+32*3-4], m6
+ %if %2 == 8
+    movd   [px+32*4-4], m6
+    movd   [px+32*5-4], m6
+    movd   [px+32*6-4], m6
+    movd   [px+32*7-4], m6
+ %endif
+.left_done:
+
+    ; bottom
+    movifnidn     botq, r4mp
+    test         edgeb, 8 ; have_bottom
+    jz .no_bottom
+    test         edgeb, 1 ; have_left
+    jz .bottom_no_left
+    test         edgeb, 2 ; have_right
+    jz .bottom_no_right
+ %if %1 == 4
+    PMOVZXBW        m0, [botq+strideq*0-(%1/2)]
+    PMOVZXBW        m1, [botq+strideq*1-(%1/2)]
+ %else
+    movu            m0, [botq+strideq*0-4]
+    movu            m1, [botq+strideq*1-4]
+    punpckhbw       m2, m0, m7
+    punpcklbw       m0, m7
+    punpckhbw       m3, m1, m7
+    punpcklbw       m1, m7
+    movu [px+32*(%2+0)+8], m2
+    movu [px+32*(%2+1)+8], m3
+ %endif
+    movu [px+32*(%2+0)-%1], m0
+    movu [px+32*(%2+1)-%1], m1
+    jmp .bottom_done
+.bottom_no_right:
+ %if %1 == 4
+    PMOVZXBW        m0, [botq+strideq*0-4]
+    PMOVZXBW        m1, [botq+strideq*1-4]
+    movu [px+32*(%2+0)-8], m0
+    movu [px+32*(%2+1)-8], m1
+ %else
+    movu            m0, [botq+strideq*0-8]
+    movu            m1, [botq+strideq*1-8]
+    punpckhbw       m2, m0, m7
+    punpcklbw       m0, m7
+    punpckhbw       m3, m1, m7
+    punpcklbw       m1, m7
+    mova [px+32*(%2+0)-16], m0
+    mova [px+32*(%2+0)+ 0], m2
+    mova [px+32*(%2+1)-16], m1
+    mova [px+32*(%2+1)+ 0], m3
+    movd [px+32*(%2-1)+16], m6 ; overwritten by first mova
+ %endif
+    movd [px+32*(%2+0)+%1*2], m6
+    movd [px+32*(%2+1)+%1*2], m6
+    jmp .bottom_done
+.bottom_no_left:
+    test         edgeb, 2 ; have_right
+    jz .bottom_no_left_right
+ %if %1 == 4
+    PMOVZXBW        m0, [botq+strideq*0]
+    PMOVZXBW        m1, [botq+strideq*1]
+ %else
+    movu            m0, [botq+strideq*0]
+    movu            m1, [botq+strideq*1]
+    punpckhbw       m2, m0, m7
+    punpcklbw       m0, m7
+    punpckhbw       m3, m1, m7
+    punpcklbw       m1, m7
+    mova [px+32*(%2+0)+16], m2
+    mova [px+32*(%2+1)+16], m3
+ %endif
+    mova [px+32*(%2+0)+ 0], m0
+    mova [px+32*(%2+1)+ 0], m1
+    movd [px+32*(%2+0)- 4], m6
+    movd [px+32*(%2+1)- 4], m6
+    jmp .bottom_done
+.bottom_no_left_right:
+    PMOVZXBW        m0, [botq+strideq*0], %1 == 4
+    PMOVZXBW        m1, [botq+strideq*1], %1 == 4
+    mova [px+32*(%2+0)+ 0], m0
+    mova [px+32*(%2+1)+ 0], m1
+    movd [px+32*(%2+0)+%1*2], m6
+    movd [px+32*(%2+1)+%1*2], m6
+    movd [px+32*(%2+0)- 4], m6
+    movd [px+32*(%2+1)- 4], m6
+    jmp .bottom_done
+.no_bottom:
+    movu [px+32*(%2+0)- 4], m6
+    movu [px+32*(%2+1)- 4], m6
+ %if %1 == 8
+    movq [px+32*(%2+0)+12], m6
+    movq [px+32*(%2+1)+12], m6
+ %endif
+.bottom_done:
+
+    ; actual filter
+ %if ARCH_X86_64
+    DEFINE_ARGS dst, stride, _, pridmp, damping, pri, sec
+    mova           m13, [shufb_lohi]
+ %if cpuflag(ssse3)
+    mova           m15, [pw_2048]
+ %else
+    mova           m15, [pw_8]
+ %endif
+    mova           m14, m6
+ %else
+    DEFINE_ARGS dst, pridmp, sec, damping, pri, tap
+    %xdefine        m8  m1
+    %xdefine        m9  m2
+    %xdefine       m10  m0
+    %xdefine       m13  [base+shufb_lohi]
+    %xdefine       m14  OUT_OF_BOUNDS_MEM
+ %if cpuflag(ssse3)
+    %xdefine       m15  [base+pw_2048]
+ %else
+    %xdefine       m15  [base+pw_8]
+ %endif
+ %endif
+    movifnidn     prid, r5m
+    movifnidn     secd, r6m
+    mov       dampingd, r8m
+    movif32 [esp+0x3C], r1d
+    test          prid, prid
+    jz .sec_only
+    movd            m1, r5m
+    bsr        pridmpd, prid
+    test          secd, secd
+    jz .pri_only
+    movd           m10, r6m
+    tzcnt         secd, secd
+    and           prid, 1
+    sub        pridmpd, dampingd
+    sub           secd, dampingd
+    xor       dampingd, dampingd
+    add           prid, prid
+    neg        pridmpd
+    cmovs      pridmpd, dampingd
+    neg           secd
+    PSHUFB_0        m1, m7
+    PSHUFB_0       m10, m7
+ %if ARCH_X86_64
+    DEFINE_ARGS dst, stride, _, pridmp, tap, pri, sec
+    lea           tapq, [tap_table]
+    MOVDDUP        m11, [tapq+pridmpq*8] ; pri_shift_mask
+    MOVDDUP        m12, [tapq+secq*8]    ; sec_shift_mask
+    mov     [rsp+0x00], pridmpq          ; pri_shift
+    mov     [rsp+0x10], secq             ; sec_shift
+    DEFINE_ARGS dst, stride, h, dir, tap, pri, stk, k, off
+ %else
+    MOVDDUP         m2, [tapq+pridmpq*8]
+    MOVDDUP         m3, [tapq+secq*8]
+    mov     [esp+0x04], dampingd         ; zero upper 32 bits of psrlw
+    mov     [esp+0x34], dampingd         ; source operand in ACCUMULATE_TAP
+    mov     [esp+0x00], pridmpd
+    mov     [esp+0x30], secd
+    DEFINE_ARGS dst, stride, dir, stk, pri, tap, h
+  %define         offq  dstq
+  %define           kd  strided
+  %define           kq  strideq
+    mova    [esp+0x10], m2
+    mova    [esp+0x40], m3
+    mova    [esp+0x20], m1
+    mova    [esp+0x50], m10
+ %endif
+    mov           dird, r7m
+    lea           stkq, [px]
+    lea           priq, [tapq+8*8+priq*8] ; pri_taps
+    mov             hd, %1*%2/8
+    lea           dirq, [tapq+dirq*2]
+.v_loop:
+    movif32 [esp+0x38], dstd
+    mov             kd, 1
+ %if %1 == 4
+    movq            m4, [stkq+32*0]
+    movhps          m4, [stkq+32*1]
+ %else
+    mova            m4, [stkq+32*0]       ; px
+ %endif
+    pxor            m0, m0                ; sum
+    mova            m7, m4                ; max
+    mova            m8, m4                ; min
+.k_loop:
+    MOVDDUP         m2, [priq+kq*8]
+ %if ARCH_X86_64
+    ACCUMULATE_TAP 0*2, [rsp+0x00], m11, m1, m2, %1, 1
+    MOVDDUP         m2, [tapq+12*8+kq*8]
+    ACCUMULATE_TAP 2*2, [rsp+0x10], m12, m10, m2, %1, 1
+    ACCUMULATE_TAP 6*2, [rsp+0x10], m12, m10, m2, %1, 1
+ %else
+    ACCUMULATE_TAP 0*2, [esp+0x00], [esp+0x10], [esp+0x20], m2, %1, 1
+    MOVDDUP         m2, [tapq+12*8+kq*8]
+    ACCUMULATE_TAP 2*2, [esp+0x30], [esp+0x40], [esp+0x50], m2, %1, 1
+    MOVDDUP         m2, [tapq+12*8+kq*8]
+    ACCUMULATE_TAP 6*2, [esp+0x30], [esp+0x40], [esp+0x50], m2, %1, 1
+ %endif
+    dec             kd
+    jge .k_loop
+    movif32       dstq, [esp+0x38]
+    movif32    strideq, [esp+0x3C]
+    CDEF_FILTER_END %1, 1
+    dec             hd
+    jg .v_loop
+    RET
+
+.pri_only:
+%if ARCH_X86_64
+    DEFINE_ARGS dst, stride, zero, pridmp, damping, pri, tap
+    lea           tapq, [tap_table]
+ %else
+    DEFINE_ARGS dst, pridmp, zero, damping, pri, tap
+ %endif
+    and           prid, 1
+    xor          zerod, zerod
+    sub       dampingd, pridmpd
+    cmovs     dampingd, zerod
+    add           prid, prid
+    PSHUFB_0        m1, m7
+    MOVDDUP         m7, [tapq+dampingq*8]
+    mov     [rsp+0x00], dampingq
+ %if ARCH_X86_64
+    DEFINE_ARGS dst, stride, h, dir, stk, pri, tap, k, off
+ %else
+    mov     [rsp+0x04], zerod
+    DEFINE_ARGS dst, stride, dir, stk, pri, tap, h
+ %endif
+    mov           dird, r7m
+    lea           stkq, [px]
+    lea           priq, [tapq+8*8+priq*8]
+    mov             hd, %1*%2/8
+    lea           dirq, [tapq+dirq*2]
+.pri_v_loop:
+    movif32 [esp+0x38], dstd
+    mov             kd, 1
+ %if %1 == 4
+    movq            m4, [stkq+32*0]
+    movhps          m4, [stkq+32*1]
+ %else
+    mova            m4, [stkq+32*0]
+ %endif
+    pxor            m0, m0
+.pri_k_loop:
+    MOVDDUP         m2, [priq+kq*8]
+    ACCUMULATE_TAP 0*2, [rsp], m7, m1, m2, %1, 0
+    dec             kd
+    jge .pri_k_loop
+    movif32       dstq, [esp+0x38]
+    movif32    strideq, [esp+0x3C]
+    CDEF_FILTER_END %1, 0
+    dec             hd
+    jg .pri_v_loop
+    RET
+
+.sec_only:
+%if ARCH_X86_64
+    DEFINE_ARGS dst, stride, zero, dir, damping, tap, sec
+%else
+    DEFINE_ARGS dst, stride, sec, damping, dir, tap, zero
+%endif
+    movd            m1, r6m
+    tzcnt         secd, secd
+    mov           dird, r7m
+    xor          zerod, zerod
+    sub       dampingd, secd
+    cmovs     dampingd, zerod
+    PSHUFB_0        m1, m7
+ %if ARCH_X86_64
+    lea           tapq, [tap_table]
+ %else
+    mov     [rsp+0x04], zerod
+ %endif
+    mov     [rsp+0x00], dampingq
+    MOVDDUP         m7, [tapq+dampingq*8]
+    lea           dirq, [tapq+dirq*2]
+ %if ARCH_X86_64
+    DEFINE_ARGS dst, stride, h, dir, stk, tap, off, k
+ %else
+    DEFINE_ARGS dst, stride, off, stk, dir, tap, h
+ %endif
+    lea           stkq, [px]
+    mov             hd, %1*%2/8
+.sec_v_loop:
+    mov             kd, 1
+ %if %1 == 4
+    movq            m4, [stkq+32*0]
+    movhps          m4, [stkq+32*1]
+ %else
+    mova            m4, [stkq+32*0]
+ %endif
+    pxor            m0, m0
+.sec_k_loop:
+    MOVDDUP         m2, [tapq+12*8+kq*8]
+    ACCUMULATE_TAP 2*2, [rsp], m7, m1, m2, %1, 0
+ %if ARCH_X86_32
+    MOVDDUP         m2, [tapq+12*8+kq*8]
+ %endif
+    ACCUMULATE_TAP 6*2, [rsp], m7, m1, m2, %1, 0
+    dec             kd
+    jge .sec_k_loop
+    movif32    strideq, [esp+0x3C]
+    CDEF_FILTER_END %1, 0
+    dec             hd
+    jg .sec_v_loop
+    RET
+%endmacro
+
+%macro MULLD 2
+ %if cpuflag(sse4)
+    pmulld          %1, %2
+ %else
+  %if ARCH_X86_32
+   %define m15 m1
+  %endif
+    pmulhuw        m15, %1, %2
+    pmullw          %1, %2
+    pslld          m15, 16
+    paddd           %1, m15
+ %endif
+%endmacro
+
+%macro CDEF_DIR 0
+ %if ARCH_X86_64
+cglobal cdef_dir_8bpc, 3, 7, 16, src, stride, var
+    lea             r6, [strideq*3]
+    movq            m1, [srcq+strideq*0]
+    movhps          m1, [srcq+strideq*1]
+    movq            m3, [srcq+strideq*2]
+    movhps          m3, [srcq+r6       ]
+    lea           srcq, [srcq+strideq*4]
+    movq            m5, [srcq+strideq*0]
+    movhps          m5, [srcq+strideq*1]
+    movq            m7, [srcq+strideq*2]
+    movhps          m7, [srcq+r6       ]
+
+    pxor            m8, m8
+    psadbw          m9, m1, m8
+    psadbw          m2, m3, m8
+    psadbw          m4, m5, m8
+    psadbw          m6, m7, m8
+    packssdw        m9, m2
+    packssdw        m4, m6
+    packssdw        m9, m4
+
+    punpcklbw       m0, m1, m8
+    punpckhbw       m1, m8
+    punpcklbw       m2, m3, m8
+    punpckhbw       m3, m8
+    punpcklbw       m4, m5, m8
+    punpckhbw       m5, m8
+    punpcklbw       m6, m7, m8
+    punpckhbw       m7, m8
+cglobal_label .main
+    mova            m8, [pw_128]
+    psubw           m0, m8
+    psubw           m1, m8
+    psubw           m2, m8
+    psubw           m3, m8
+    psubw           m4, m8
+    psubw           m5, m8
+    psubw           m6, m8
+    psubw           m7, m8
+    psllw           m8, 3
+    psubw           m9, m8                  ; partial_sum_hv[0]
+
+    paddw           m8, m0, m1
+    paddw          m10, m2, m3
+    paddw           m8, m4
+    paddw          m10, m5
+    paddw           m8, m6
+    paddw          m10, m7
+    paddw           m8, m10                 ; partial_sum_hv[1]
+
+    pmaddwd         m8, m8
+    pmaddwd         m9, m9
+    phaddd          m9, m8
+    SWAP            m8, m9
+    MULLD           m8, [div_table%+SUFFIX+48]
+
+    pslldq          m9, m1, 2
+    psrldq         m10, m1, 14
+    pslldq         m11, m2, 4
+    psrldq         m12, m2, 12
+    pslldq         m13, m3, 6
+    psrldq         m14, m3, 10
+    paddw           m9, m0
+    paddw          m10, m12
+    paddw          m11, m13
+    paddw          m10, m14                 ; partial_sum_diag[0] top/right half
+    paddw           m9, m11                 ; partial_sum_diag[0] top/left half
+    pslldq         m11, m4, 8
+    psrldq         m12, m4, 8
+    pslldq         m13, m5, 10
+    psrldq         m14, m5, 6
+    paddw           m9, m11
+    paddw          m10, m12
+    paddw           m9, m13
+    paddw          m10, m14
+    pslldq         m11, m6, 12
+    psrldq         m12, m6, 4
+    pslldq         m13, m7, 14
+    psrldq         m14, m7, 2
+    paddw           m9, m11
+    paddw          m10, m12
+    paddw           m9, m13                 ; partial_sum_diag[0][0-7]
+    paddw          m10, m14                 ; partial_sum_diag[0][8-14,zero]
+    pshufb         m10, [shufw_6543210x]
+    punpckhwd      m11, m9, m10
+    punpcklwd       m9, m10
+    pmaddwd        m11, m11
+    pmaddwd         m9, m9
+    MULLD          m11, [div_table%+SUFFIX+16]
+    MULLD           m9, [div_table%+SUFFIX+0]
+    paddd           m9, m11                 ; cost[0a-d]
+
+    pslldq         m10, m0, 14
+    psrldq         m11, m0, 2
+    pslldq         m12, m1, 12
+    psrldq         m13, m1, 4
+    pslldq         m14, m2, 10
+    psrldq         m15, m2, 6
+    paddw          m10, m12
+    paddw          m11, m13
+    paddw          m10, m14
+    paddw          m11, m15
+    pslldq         m12, m3, 8
+    psrldq         m13, m3, 8
+    pslldq         m14, m4, 6
+    psrldq         m15, m4, 10
+    paddw          m10, m12
+    paddw          m11, m13
+    paddw          m10, m14
+    paddw          m11, m15
+    pslldq         m12, m5, 4
+    psrldq         m13, m5, 12
+    pslldq         m14, m6, 2
+    psrldq         m15, m6, 14
+    paddw          m10, m12
+    paddw          m11, m13
+    paddw          m10, m14
+    paddw          m11, m15                 ; partial_sum_diag[1][8-14,zero]
+    paddw          m10, m7                  ; partial_sum_diag[1][0-7]
+    pshufb         m11, [shufw_6543210x]
+    punpckhwd      m12, m10, m11
+    punpcklwd      m10, m11
+    pmaddwd        m12, m12
+    pmaddwd        m10, m10
+    MULLD          m12, [div_table%+SUFFIX+16]
+    MULLD          m10, [div_table%+SUFFIX+0]
+    paddd          m10, m12                 ; cost[4a-d]
+    phaddd          m9, m10                 ; cost[0a/b,4a/b]
+
+    paddw          m10, m0, m1
+    paddw          m11, m2, m3
+    paddw          m12, m4, m5
+    paddw          m13, m6, m7
+    phaddw          m0, m4
+    phaddw          m1, m5
+    phaddw          m2, m6
+    phaddw          m3, m7
+
+    ; m0-3 are horizontal sums (x >> 1), m10-13 are vertical sums (y >> 1)
+    pslldq          m4, m11, 2
+    psrldq          m5, m11, 14
+    pslldq          m6, m12, 4
+    psrldq          m7, m12, 12
+    pslldq         m14, m13, 6
+    psrldq         m15, m13, 10
+    paddw           m4, m10
+    paddw           m5, m7
+    paddw           m4, m6
+    paddw           m5, m15                 ; partial_sum_alt[3] right
+    paddw           m4, m14                 ; partial_sum_alt[3] left
+    pshuflw         m6, m5, q3012
+    punpckhwd       m5, m4
+    punpcklwd       m4, m6
+    pmaddwd         m5, m5
+    pmaddwd         m4, m4
+    MULLD           m5, [div_table%+SUFFIX+48]
+    MULLD           m4, [div_table%+SUFFIX+32]
+    paddd           m4, m5                  ; cost[7a-d]
+
+    pslldq          m5, m10, 6
+    psrldq          m6, m10, 10
+    pslldq          m7, m11, 4
+    psrldq         m10, m11, 12
+    pslldq         m11, m12, 2
+    psrldq         m12, 14
+    paddw           m5, m7
+    paddw           m6, m10
+    paddw           m5, m11
+    paddw           m6, m12
+    paddw           m5, m13
+    pshuflw         m7, m6, q3012
+    punpckhwd       m6, m5
+    punpcklwd       m5, m7
+    pmaddwd         m6, m6
+    pmaddwd         m5, m5
+    MULLD           m6, [div_table%+SUFFIX+48]
+    MULLD           m5, [div_table%+SUFFIX+32]
+    paddd           m5, m6                  ; cost[5a-d]
+
+    pslldq          m6, m1, 2
+    psrldq          m7, m1, 14
+    pslldq         m10, m2, 4
+    psrldq         m11, m2, 12
+    pslldq         m12, m3, 6
+    psrldq         m13, m3, 10
+    paddw           m6, m0
+    paddw           m7, m11
+    paddw           m6, m10
+    paddw           m7, m13                 ; partial_sum_alt[3] right
+    paddw           m6, m12                 ; partial_sum_alt[3] left
+    pshuflw        m10, m7, q3012
+    punpckhwd       m7, m6
+    punpcklwd       m6, m10
+    pmaddwd         m7, m7
+    pmaddwd         m6, m6
+    MULLD           m7, [div_table%+SUFFIX+48]
+    MULLD           m6, [div_table%+SUFFIX+32]
+    paddd           m6, m7                  ; cost[1a-d]
+
+    pshufd          m0, m0, q1032
+    pshufd          m1, m1, q1032
+    pshufd          m2, m2, q1032
+    pshufd          m3, m3, q1032
+
+    pslldq         m10, m0, 6
+    psrldq         m11, m0, 10
+    pslldq         m12, m1, 4
+    psrldq         m13, m1, 12
+    pslldq         m14, m2, 2
+    psrldq          m2, 14
+    paddw          m10, m12
+    paddw          m11, m13
+    paddw          m10, m14
+    paddw          m11, m2
+    paddw          m10, m3
+    pshuflw        m12, m11, q3012
+    punpckhwd      m11, m10
+    punpcklwd      m10, m12
+    pmaddwd        m11, m11
+    pmaddwd        m10, m10
+    MULLD          m11, [div_table%+SUFFIX+48]
+    MULLD          m10, [div_table%+SUFFIX+32]
+    paddd          m10, m11                 ; cost[3a-d]
+
+    phaddd          m9, m8                  ; cost[0,4,2,6]
+    phaddd          m6, m10
+    phaddd          m5, m4
+    phaddd          m6, m5                  ; cost[1,3,5,7]
+    pshufd          m4, m9, q3120
+
+    ; now find the best cost
+  %if cpuflag(sse4)
+    pmaxsd          m9, m6
+    pshufd          m0, m9, q1032
+    pmaxsd          m0, m9
+    pshufd          m1, m0, q2301
+    pmaxsd          m0, m1                  ; best cost
+  %else
+    pcmpgtd         m0, m9, m6
+    pand            m9, m0
+    pandn           m0, m6
+    por             m9, m0
+    pshufd          m1, m9, q1032
+    pcmpgtd         m0, m9, m1
+    pand            m9, m0
+    pandn           m0, m1
+    por             m9, m0
+    pshufd          m1, m9, q2301
+    pcmpgtd         m0, m9, m1
+    pand            m9, m0
+    pandn           m0, m1
+    por             m0, m9
+  %endif
+
+    ; get direction and variance
+    punpckhdq       m1, m4, m6
+    punpckldq       m4, m6
+    psubd           m2, m0, m1
+    psubd           m3, m0, m4
+%if WIN64
+    WIN64_RESTORE_XMM
+    %define tmp rsp+stack_offset+8
+%else
+    %define tmp rsp-40
+%endif
+    mova    [tmp+0x00], m2                  ; emulate ymm in stack
+    mova    [tmp+0x10], m3
+    pcmpeqd         m1, m0                  ; compute best cost mask
+    pcmpeqd         m4, m0
+    packssdw        m4, m1
+    pmovmskb       eax, m4                  ; get byte-idx from mask
+    tzcnt          eax, eax
+    mov            r1d, [tmp+rax*2]         ; get idx^4 complement from emulated ymm
+    shr            eax, 1                   ; get direction by converting byte-idx to word-idx
+    shr            r1d, 10
+    mov         [varq], r1d
+ %else
+cglobal cdef_dir_8bpc, 2, 4, 8, 96, src, stride, var, stride3
+%define base r2-shufw_6543210x
+    LEA             r2, shufw_6543210x
+    pxor            m0, m0
+    lea       stride3q, [strideq*3]
+    movq            m5, [srcq+strideq*0]
+    movhps          m5, [srcq+strideq*1]
+    movq            m7, [srcq+strideq*2]
+    movhps          m7, [srcq+stride3q]
+    mova            m1, [base+pw_128]
+    psadbw          m2, m5, m0
+    psadbw          m3, m7, m0
+    packssdw        m2, m3
+    punpcklbw       m4, m5, m0
+    punpckhbw       m5, m0
+    punpcklbw       m6, m7, m0
+    punpckhbw       m7, m0
+    psubw           m4, m1
+    psubw           m5, m1
+    psubw           m6, m1
+    psubw           m7, m1
+
+    mova    [esp+0x00], m4
+    mova    [esp+0x10], m5
+    mova    [esp+0x20], m6
+    mova    [esp+0x50], m7
+
+    lea           srcq, [srcq+strideq*4]
+    movq            m5, [srcq+strideq*0]
+    movhps          m5, [srcq+strideq*1]
+    movq            m7, [srcq+strideq*2]
+    movhps          m7, [srcq+stride3q]
+    psadbw          m3, m5, m0
+    psadbw          m0, m7
+    packssdw        m3, m0
+    pxor            m0, m0
+    punpcklbw       m4, m5, m0
+    punpckhbw       m5, m0
+    punpcklbw       m6, m7, m0
+    punpckhbw       m7, m0
+cglobal_label .main
+    psubw           m4, m1
+    psubw           m5, m1
+    psubw           m6, m1
+    psubw           m7, m1
+    packssdw        m2, m3
+    psllw           m1, 3
+    psubw           m2, m1                  ; partial_sum_hv[0]
+    pmaddwd         m2, m2
+
+    mova            m3, [esp+0x50]
+    mova            m0, [esp+0x00]
+    paddw           m0, [esp+0x10]
+    paddw           m1, m3, [esp+0x20]
+    paddw           m0, m4
+    paddw           m1, m5
+    paddw           m0, m6
+    paddw           m1, m7
+    paddw           m0, m1                  ; partial_sum_hv[1]
+    pmaddwd         m0, m0
+
+    phaddd          m2, m0
+    MULLD           m2, [base+div_table%+SUFFIX+48]
+    mova    [esp+0x30], m2
+
+    mova            m1, [esp+0x10]
+    pslldq          m0, m1, 2
+    psrldq          m1, 14
+    paddw           m0, [esp+0x00]
+    pslldq          m2, m3, 6
+    psrldq          m3, 10
+    paddw           m0, m2
+    paddw           m1, m3
+    mova            m3, [esp+0x20]
+    pslldq          m2, m3, 4
+    psrldq          m3, 12
+    paddw           m0, m2                  ; partial_sum_diag[0] top/left half
+    paddw           m1, m3                  ; partial_sum_diag[0] top/right half
+    pslldq          m2, m4, 8
+    psrldq          m3, m4, 8
+    paddw           m0, m2
+    paddw           m1, m3
+    pslldq          m2, m5, 10
+    psrldq          m3, m5, 6
+    paddw           m0, m2
+    paddw           m1, m3
+    pslldq          m2, m6, 12
+    psrldq          m3, m6, 4
+    paddw           m0, m2
+    paddw           m1, m3
+    pslldq          m2, m7, 14
+    psrldq          m3, m7, 2
+    paddw           m0, m2                  ; partial_sum_diag[0][0-7]
+    paddw           m1, m3                  ; partial_sum_diag[0][8-14,zero]
+    mova            m3, [esp+0x50]
+    pshufb          m1, [base+shufw_6543210x]
+    punpckhwd       m2, m0, m1
+    punpcklwd       m0, m1
+    pmaddwd         m2, m2
+    pmaddwd         m0, m0
+    MULLD           m2, [base+div_table%+SUFFIX+16]
+    MULLD           m0, [base+div_table%+SUFFIX+ 0]
+    paddd           m0, m2                  ; cost[0a-d]
+    mova    [esp+0x40], m0
+
+    mova            m1, [esp+0x00]
+    pslldq          m0, m1, 14
+    psrldq          m1, 2
+    paddw           m0, m7
+    pslldq          m2, m3, 8
+    psrldq          m3, 8
+    paddw           m0, m2
+    paddw           m1, m3
+    mova            m3, [esp+0x20]
+    pslldq          m2, m3, 10
+    psrldq          m3, 6
+    paddw           m0, m2
+    paddw           m1, m3
+    mova            m3, [esp+0x10]
+    pslldq          m2, m3, 12
+    psrldq          m3, 4
+    paddw           m0, m2
+    paddw           m1, m3
+    pslldq          m2, m4, 6
+    psrldq          m3, m4, 10
+    paddw           m0, m2
+    paddw           m1, m3
+    pslldq          m2, m5, 4
+    psrldq          m3, m5, 12
+    paddw           m0, m2
+    paddw           m1, m3
+    pslldq          m2, m6, 2
+    psrldq          m3, m6, 14
+    paddw           m0, m2                  ; partial_sum_diag[1][0-7]
+    paddw           m1, m3                  ; partial_sum_diag[1][8-14,zero]
+    mova            m3, [esp+0x50]
+    pshufb          m1, [base+shufw_6543210x]
+    punpckhwd       m2, m0, m1
+    punpcklwd       m0, m1
+    pmaddwd         m2, m2
+    pmaddwd         m0, m0
+    MULLD           m2, [base+div_table%+SUFFIX+16]
+    MULLD           m0, [base+div_table%+SUFFIX+ 0]
+    paddd           m0, m2                  ; cost[4a-d]
+    phaddd          m1, [esp+0x40], m0      ; cost[0a/b,4a/b]
+    phaddd          m1, [esp+0x30]          ; cost[0,4,2,6]
+    mova    [esp+0x30], m1
+
+    phaddw          m0, [esp+0x00], m4
+    phaddw          m1, [esp+0x10], m5
+    paddw           m4, m5
+    mova            m2, [esp+0x20]
+    paddw           m5, m2, m3
+    phaddw          m2, m6
+    paddw           m6, m7
+    phaddw          m3, m7
+    mova            m7, [esp+0x00]
+    paddw           m7, [esp+0x10]
+    mova    [esp+0x00], m0
+    mova    [esp+0x10], m1
+    mova    [esp+0x20], m2
+
+    pslldq          m1, m4, 4
+    pslldq          m2, m6, 6
+    pslldq          m0, m5, 2
+    paddw           m1, m2
+    paddw           m0, m7
+    psrldq          m2, m5, 14
+    paddw           m0, m1                  ; partial_sum_alt[3] left
+    psrldq          m1, m4, 12
+    paddw           m1, m2
+    psrldq          m2, m6, 10
+    paddw           m1, m2                  ; partial_sum_alt[3] right
+    pshuflw         m1, m1, q3012
+    punpckhwd       m2, m0, m1
+    punpcklwd       m0, m1
+    pmaddwd         m2, m2
+    pmaddwd         m0, m0
+    MULLD           m2, [base+div_table%+SUFFIX+48]
+    MULLD           m0, [base+div_table%+SUFFIX+32]
+    paddd           m0, m2                  ; cost[7a-d]
+    mova    [esp+0x40], m0
+
+    pslldq          m0, m7, 6
+    psrldq          m7, 10
+    pslldq          m1, m5, 4
+    psrldq          m5, 12
+    pslldq          m2, m4, 2
+    psrldq          m4, 14
+    paddw           m0, m6
+    paddw           m7, m5
+    paddw           m0, m1
+    paddw           m7, m4
+    paddw           m0, m2
+    pshuflw         m2, m7, q3012
+    punpckhwd       m7, m0
+    punpcklwd       m0, m2
+    pmaddwd         m7, m7
+    pmaddwd         m0, m0
+    MULLD           m7, [base+div_table%+SUFFIX+48]
+    MULLD           m0, [base+div_table%+SUFFIX+32]
+    paddd           m0, m7                  ; cost[5a-d]
+    mova    [esp+0x50], m0
+
+    mova            m7, [esp+0x10]
+    mova            m2, [esp+0x20]
+    pslldq          m0, m7, 2
+    psrldq          m7, 14
+    pslldq          m4, m2, 4
+    psrldq          m2, 12
+    pslldq          m5, m3, 6
+    psrldq          m6, m3, 10
+    paddw           m0, [esp+0x00]
+    paddw           m7, m2
+    paddw           m4, m5
+    paddw           m7, m6                  ; partial_sum_alt[3] right
+    paddw           m0, m4                  ; partial_sum_alt[3] left
+    pshuflw         m2, m7, q3012
+    punpckhwd       m7, m0
+    punpcklwd       m0, m2
+    pmaddwd         m7, m7
+    pmaddwd         m0, m0
+    MULLD           m7, [base+div_table%+SUFFIX+48]
+    MULLD           m0, [base+div_table%+SUFFIX+32]
+    paddd           m0, m7                  ; cost[1a-d]
+    SWAP            m0, m4
+
+    pshufd          m0, [esp+0x00], q1032
+    pshufd          m1, [esp+0x10], q1032
+    pshufd          m2, [esp+0x20], q1032
+    pshufd          m3, m3, q1032
+    mova    [esp+0x00], m4
+
+    pslldq          m4, m0, 6
+    psrldq          m0, 10
+    pslldq          m5, m1, 4
+    psrldq          m1, 12
+    pslldq          m6, m2, 2
+    psrldq          m2, 14
+    paddw           m4, m3
+    paddw           m0, m1
+    paddw           m5, m6
+    paddw           m0, m2
+    paddw           m4, m5
+    pshuflw         m2, m0, q3012
+    punpckhwd       m0, m4
+    punpcklwd       m4, m2
+    pmaddwd         m0, m0
+    pmaddwd         m4, m4
+    MULLD           m0, [base+div_table%+SUFFIX+48]
+    MULLD           m4, [base+div_table%+SUFFIX+32]
+    paddd           m4, m0                   ; cost[3a-d]
+
+    mova            m1, [esp+0x00]
+    mova            m2, [esp+0x50]
+    mova            m0, [esp+0x30]          ; cost[0,4,2,6]
+    phaddd          m1, m4
+    phaddd          m2, [esp+0x40]          ; cost[1,3,5,7]
+    phaddd          m1, m2
+    pshufd          m2, m0, q3120
+
+    ; now find the best cost
+  %if cpuflag(sse4)
+    pmaxsd          m0, m1
+    pshufd          m3, m0, q1032
+    pmaxsd          m3, m0
+    pshufd          m0, m3, q2301
+    pmaxsd          m0, m3
+  %else
+    pcmpgtd         m3, m0, m1
+    pand            m0, m3
+    pandn           m3, m1
+    por             m0, m3
+    pshufd          m4, m0, q1032
+    pcmpgtd         m3, m0, m4
+    pand            m0, m3
+    pandn           m3, m4
+    por             m0, m3
+    pshufd          m4, m0, q2301
+    pcmpgtd         m3, m0, m4
+    pand            m0, m3
+    pandn           m3, m4
+    por             m0, m3
+  %endif
+
+    ; get direction and variance
+    mov           vard, varm
+    punpckhdq       m3, m2, m1
+    punpckldq       m2, m1
+    psubd           m1, m0, m3
+    psubd           m4, m0, m2
+    mova    [esp+0x00], m1                  ; emulate ymm in stack
+    mova    [esp+0x10], m4
+    pcmpeqd         m3, m0                  ; compute best cost mask
+    pcmpeqd         m2, m0
+    packssdw        m2, m3
+    pmovmskb       eax, m2                  ; get byte-idx from mask
+    tzcnt          eax, eax
+    mov            r1d, [esp+eax*2]         ; get idx^4 complement from emulated ymm
+    shr            eax, 1                   ; get direction by converting byte-idx to word-idx
+    shr            r1d, 10
+    mov         [vard], r1d
+ %endif
+
+    RET
+%endmacro
+
+INIT_XMM sse4
+CDEF_FILTER 8, 8
+CDEF_FILTER 4, 8
+CDEF_FILTER 4, 4
+CDEF_DIR
+
+INIT_XMM ssse3
+CDEF_FILTER 8, 8
+CDEF_FILTER 4, 8
+CDEF_FILTER 4, 4
+CDEF_DIR
+
+INIT_XMM sse2
+CDEF_FILTER 8, 8
+CDEF_FILTER 4, 8
+CDEF_FILTER 4, 4
diff --git a/media/libdav1d/src/src/x86/cpu.c b/media/libdav1d/src/src/x86/cpu.c
new file mode 100644
index 0000000000..80f91e16eb
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cpu.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+
+#include "common/attributes.h"
+
+#include "src/cpu.h"
+#include "src/x86/cpu.h"
+
+typedef struct {
+    uint32_t eax, ebx, edx, ecx;
+} CpuidRegisters;
+
+void dav1d_cpu_cpuid(CpuidRegisters *regs, unsigned leaf, unsigned subleaf);
+uint64_t dav1d_cpu_xgetbv(unsigned xcr);
+
+#define X(reg, mask) (((reg) & (mask)) == (mask))
+
+COLD unsigned dav1d_get_cpu_flags_x86(void) {
+    union {
+        CpuidRegisters r;
+        struct {
+            uint32_t max_leaf;
+            char vendor[12];
+        };
+    } cpu;
+    dav1d_cpu_cpuid(&cpu.r, 0, 0);
+    unsigned flags = dav1d_get_default_cpu_flags();
+
+    if (cpu.max_leaf >= 1) {
+        CpuidRegisters r;
+        dav1d_cpu_cpuid(&r, 1, 0);
+        const unsigned family = ((r.eax >> 8) & 0x0f) + ((r.eax >> 20) & 0xff);
+
+        if (X(r.edx, 0x06008000)) /* CMOV/SSE/SSE2 */ {
+            flags |= DAV1D_X86_CPU_FLAG_SSE2;
+            if (X(r.ecx, 0x00000201)) /* SSE3/SSSE3 */ {
+                flags |= DAV1D_X86_CPU_FLAG_SSSE3;
+                if (X(r.ecx, 0x00080000)) /* SSE4.1 */
+                    flags |= DAV1D_X86_CPU_FLAG_SSE41;
+            }
+        }
+#if ARCH_X86_64
+        /* We only support >128-bit SIMD on x86-64. */
+        if (X(r.ecx, 0x18000000)) /* OSXSAVE/AVX */ {
+            const uint64_t xcr0 = dav1d_cpu_xgetbv(0);
+            if (X(xcr0, 0x00000006)) /* XMM/YMM */ {
+                if (cpu.max_leaf >= 7) {
+                    dav1d_cpu_cpuid(&r, 7, 0);
+                    if (X(r.ebx, 0x00000128)) /* BMI1/BMI2/AVX2 */ {
+                        flags |= DAV1D_X86_CPU_FLAG_AVX2;
+                        if (X(xcr0, 0x000000e0)) /* ZMM/OPMASK */ {
+                            if (X(r.ebx, 0xd0230000) && X(r.ecx, 0x00005f42))
+                                flags |= DAV1D_X86_CPU_FLAG_AVX512ICL;
+                        }
+                    }
+                }
+            }
+        }
+#endif
+        if (!memcmp(cpu.vendor, "AuthenticAMD", sizeof(cpu.vendor))) {
+            if ((flags & DAV1D_X86_CPU_FLAG_AVX2) && family <= 0x19) {
+                /* Excavator, Zen, Zen+, Zen 2, Zen 3, Zen 3+, Zen 4 */
+                flags |= DAV1D_X86_CPU_FLAG_SLOW_GATHER;
+            }
+        }
+    }
+
+    return flags;
+}
diff --git a/media/libdav1d/src/src/x86/cpu.h b/media/libdav1d/src/src/x86/cpu.h
new file mode 100644
index 0000000000..8529c77c9b
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cpu.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_X86_CPU_H
+#define DAV1D_SRC_X86_CPU_H
+
+enum CpuFlags {
+    DAV1D_X86_CPU_FLAG_SSE2        = 1 << 0,
+    DAV1D_X86_CPU_FLAG_SSSE3       = 1 << 1,
+    DAV1D_X86_CPU_FLAG_SSE41       = 1 << 2,
+    DAV1D_X86_CPU_FLAG_AVX2        = 1 << 3,
+    DAV1D_X86_CPU_FLAG_AVX512ICL   = 1 << 4, /* F/CD/BW/DQ/VL/VNNI/IFMA/VBMI/VBMI2/
+                                              * VPOPCNTDQ/BITALG/GFNI/VAES/VPCLMULQDQ */
+    DAV1D_X86_CPU_FLAG_SLOW_GATHER = 1 << 5, /* Flag CPUs where gather instructions are slow enough
+                                              * to cause performance regressions. */
+};
+
+unsigned dav1d_get_cpu_flags_x86(void);
+
+#endif /* DAV1D_SRC_X86_CPU_H */
diff --git a/media/libdav1d/src/src/x86/cpuid.asm b/media/libdav1d/src/src/x86/cpuid.asm
new file mode 100644
index 0000000000..e1d9228660
--- /dev/null
+++ b/media/libdav1d/src/src/x86/cpuid.asm
@@ -0,0 +1,55 @@
+; Copyright © 2018, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION .text
+
+cglobal cpu_cpuid, 0, 5, 0, regs, leaf, subleaf
+    mov        r4, regsmp
+    mov       eax, leafm
+    mov       ecx, subleafm
+%if ARCH_X86_64
+    mov        r5, rbx
+%endif
+    cpuid
+    mov  [r4+4*0], eax
+    mov  [r4+4*1], ebx
+    mov  [r4+4*2], edx
+    mov  [r4+4*3], ecx
+%if ARCH_X86_64
+    mov       rbx, r5
+%endif
+    RET
+
+cglobal cpu_xgetbv, 0, 0, 0, xcr
+    movifnidn ecx, xcrm
+    xgetbv
+%if ARCH_X86_64
+    shl       rdx, 32
+    or        rax, rdx
+%endif
+    RET
diff --git a/media/libdav1d/src/src/x86/filmgrain.h b/media/libdav1d/src/src/x86/filmgrain.h
new file mode 100644
index 0000000000..8f6ac8f828
--- /dev/null
+++ b/media/libdav1d/src/src/x86/filmgrain.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2018-2022, VideoLAN and dav1d authors
+ * Copyright © 2018-2022, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/filmgrain.h"
+
+#define decl_fg_fns(ext)                                         \
+decl_generate_grain_y_fn(BF(dav1d_generate_grain_y, ext));       \
+decl_generate_grain_uv_fn(BF(dav1d_generate_grain_uv_420, ext)); \
+decl_generate_grain_uv_fn(BF(dav1d_generate_grain_uv_422, ext)); \
+decl_generate_grain_uv_fn(BF(dav1d_generate_grain_uv_444, ext)); \
+decl_fgy_32x32xn_fn(BF(dav1d_fgy_32x32xn, ext));                 \
+decl_fguv_32x32xn_fn(BF(dav1d_fguv_32x32xn_i420, ext));          \
+decl_fguv_32x32xn_fn(BF(dav1d_fguv_32x32xn_i422, ext));          \
+decl_fguv_32x32xn_fn(BF(dav1d_fguv_32x32xn_i444, ext))
+
+decl_fg_fns(ssse3);
+decl_fg_fns(avx2);
+decl_fg_fns(avx512icl);
+
+static ALWAYS_INLINE void film_grain_dsp_init_x86(Dav1dFilmGrainDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSSE3)) return;
+
+    c->generate_grain_y = BF(dav1d_generate_grain_y, ssse3);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I420 - 1] = BF(dav1d_generate_grain_uv_420, ssse3);
+    c->fgy_32x32xn = BF(dav1d_fgy_32x32xn, ssse3);
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I420 - 1] = BF(dav1d_fguv_32x32xn_i420, ssse3);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I422 - 1] = BF(dav1d_generate_grain_uv_422, ssse3);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I444 - 1] = BF(dav1d_generate_grain_uv_444, ssse3);
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I422 - 1] = BF(dav1d_fguv_32x32xn_i422, ssse3);
+    c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I444 - 1] = BF(dav1d_fguv_32x32xn_i444, ssse3);
+
+#if ARCH_X86_64
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2)) return;
+
+    c->generate_grain_y = BF(dav1d_generate_grain_y, avx2);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I420 - 1] = BF(dav1d_generate_grain_uv_420, avx2);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I422 - 1] = BF(dav1d_generate_grain_uv_422, avx2);
+    c->generate_grain_uv[DAV1D_PIXEL_LAYOUT_I444 - 1] = BF(dav1d_generate_grain_uv_444, avx2);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SLOW_GATHER)) {
+        c->fgy_32x32xn = BF(dav1d_fgy_32x32xn, avx2);
+        c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I420 - 1] = BF(dav1d_fguv_32x32xn_i420, avx2);
+        c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I422 - 1] = BF(dav1d_fguv_32x32xn_i422, avx2);
+        c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I444 - 1] = BF(dav1d_fguv_32x32xn_i444, avx2);
+    }
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL)) return;
+
+    if (BITDEPTH == 8 || !(flags & DAV1D_X86_CPU_FLAG_SLOW_GATHER)) {
+        c->fgy_32x32xn = BF(dav1d_fgy_32x32xn, avx512icl);
+        c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I420 - 1] = BF(dav1d_fguv_32x32xn_i420, avx512icl);
+        c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I422 - 1] = BF(dav1d_fguv_32x32xn_i422, avx512icl);
+        c->fguv_32x32xn[DAV1D_PIXEL_LAYOUT_I444 - 1] = BF(dav1d_fguv_32x32xn_i444, avx512icl);
+    }
+#endif
+}
diff --git a/media/libdav1d/src/src/x86/filmgrain16_avx2.asm b/media/libdav1d/src/src/x86/filmgrain16_avx2.asm
new file mode 100644
index 0000000000..128d178bb0
--- /dev/null
+++ b/media/libdav1d/src/src/x86/filmgrain16_avx2.asm
@@ -0,0 +1,2229 @@
+; Copyright © 2021-2022, VideoLAN and dav1d authors
+; Copyright © 2021-2022, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+%include "x86/filmgrain_common.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 16
+pb_mask:       db  0,128,128,  0,128,  0,  0,128,128,  0,  0,128,  0,128,128,  0
+gen_shufA:     db  0,  1,  2,  3,  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9
+gen_shufB:     db  4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13
+next_upperbit_mask:    dw 0x100B, 0x2016, 0x402C, 0x8058
+pw_27_17_17_27:        dw 27, 17, 17, 27
+pw_23_22:              dw 23, 22, 0, 32
+pw_seed_xor:   times 2 dw 0xb524
+               times 2 dw 0x49d8
+gen_ar0_shift: times 4 db 128
+               times 4 db 64
+               times 4 db 32
+               times 4 db 16
+pd_16:                 dd 16
+pd_m65536:             dd -65536
+pb_1:          times 4 db 1
+grain_max:     times 2 dw  511
+               times 2 dw 2047
+grain_min:     times 2 dw -512
+               times 2 dw -2048
+fg_max:        times 2 dw 1023
+               times 2 dw 4095
+               times 2 dw 960
+               times 2 dw 3840
+               times 2 dw 940
+               times 2 dw 3760
+fg_min:        times 2 dw 0
+               times 2 dw 64
+               times 2 dw 256
+uv_offset_mul:         dd 256
+                       dd 1024
+hmul_bits:             dw 32768, 16384,  8192,  4096
+round:                 dw  2048,  1024,   512
+mul_bits:              dw   256,   128,    64,    32,    16,     8
+round_vals:            dw    32,    64,   128,   256,   512,  1024
+pb_8_9_0_1:            db 8, 9, 0, 1
+
+%macro JMP_TABLE 1-*
+    %xdefine %1_table %%table
+    %xdefine %%base %1_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1)
+    %%table:
+    %rep %0 - 1
+        dd %%prefix %+ .ar%2 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+JMP_TABLE generate_grain_y_16bpc_avx2, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_420_16bpc_avx2, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_422_16bpc_avx2, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_444_16bpc_avx2, 0, 1, 2, 3
+
+SECTION .text
+
+%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX)
+
+INIT_YMM avx2
+cglobal generate_grain_y_16bpc, 3, 9, 14, buf, fg_data, bdmax
+%define base r4-generate_grain_y_16bpc_avx2_table
+    lea              r4, [generate_grain_y_16bpc_avx2_table]
+    vpbroadcastw    xm0, [fg_dataq+FGData.seed]
+    mov             r6d, [fg_dataq+FGData.grain_scale_shift]
+    movq            xm1, [base+next_upperbit_mask]
+    mov              r3, -73*82*2
+    movsxd           r5, [fg_dataq+FGData.ar_coeff_lag]
+    lea             r7d, [bdmaxq+1]
+    movq            xm4, [base+mul_bits]
+    shr             r7d, 11             ; 0 for 10bpc, 2 for 12bpc
+    movq            xm5, [base+hmul_bits]
+    sub              r6, r7
+    mova            xm6, [base+pb_mask]
+    sub            bufq, r3
+    vpbroadcastw    xm7, [base+round+r6*2-2]
+    lea              r6, [gaussian_sequence]
+    movsxd           r5, [r4+r5*4]
+.loop:
+    pand            xm2, xm0, xm1
+    psrlw           xm3, xm2, 10
+    por             xm2, xm3            ; bits 0xf, 0x1e, 0x3c and 0x78 are set
+    pmullw          xm2, xm4            ; bits 0x0f00 are set
+    pmulhuw         xm0, xm5
+    pshufb          xm3, xm6, xm2       ; set 15th bit for next 4 seeds
+    psllq           xm2, xm3, 30
+    por             xm2, xm3
+    psllq           xm3, xm2, 15
+    por             xm2, xm0            ; aggregate each bit into next seed's high bit
+    por             xm3, xm2            ; 4 next output seeds
+    pshuflw         xm0, xm3, q3333
+    psrlw           xm3, 5
+    pand            xm2, xm0, xm1
+    movq             r7, xm3
+    psrlw           xm3, xm2, 10
+    por             xm2, xm3
+    pmullw          xm2, xm4
+    pmulhuw         xm0, xm5
+    movzx           r8d, r7w
+    pshufb          xm3, xm6, xm2
+    psllq           xm2, xm3, 30
+    por             xm2, xm3
+    psllq           xm3, xm2, 15
+    por             xm0, xm2
+    movd            xm2, [r6+r8*2]
+    rorx             r8, r7, 32
+    por             xm3, xm0
+    shr             r7d, 16
+    pinsrw          xm2, [r6+r7*2], 1
+    pshuflw         xm0, xm3, q3333
+    movzx           r7d, r8w
+    psrlw           xm3, 5
+    pinsrw          xm2, [r6+r7*2], 2
+    shr             r8d, 16
+    movq             r7, xm3
+    pinsrw          xm2, [r6+r8*2], 3
+    movzx           r8d, r7w
+    pinsrw          xm2, [r6+r8*2], 4
+    rorx             r8, r7, 32
+    shr             r7d, 16
+    pinsrw          xm2, [r6+r7*2], 5
+    movzx           r7d, r8w
+    pinsrw          xm2, [r6+r7*2], 6
+    shr             r8d, 16
+    pinsrw          xm2, [r6+r8*2], 7
+    paddw           xm2, xm2            ; otherwise bpc=12 w/ grain_scale_shift=0
+    pmulhrsw        xm2, xm7            ; shifts by 0, which pmulhrsw does not support
+    mova      [bufq+r3], xm2
+    add              r3, 8*2
+    jl .loop
+
+    ; auto-regression code
+    add              r5, r4
+    jmp              r5
+
+.ar1:
+    DEFINE_ARGS buf, fg_data, max, shift, val3, min, cf3, x, val0
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movsx          cf3d, byte [fg_dataq+FGData.ar_coeffs_y+3]
+    movd            xm4, [fg_dataq+FGData.ar_coeffs_y]
+    DEFINE_ARGS buf, h, max, shift, val3, min, cf3, x, val0
+    pinsrb          xm4, [base+pb_1], 3
+    pmovsxbw        xm4, xm4
+    pshufd          xm5, xm4, q1111
+    pshufd          xm4, xm4, q0000
+    vpbroadcastw    xm3, [base+round_vals+shiftq*2-12]    ; rnd
+    sub            bufq, 2*(82*73-(82*3+79))
+    mov              hd, 70
+    sar            maxd, 1
+    mov            mind, maxd
+    xor            mind, -1
+.y_loop_ar1:
+    mov              xq, -76
+    movsx         val3d, word [bufq+xq*2-2]
+.x_loop_ar1:
+    movu            xm0, [bufq+xq*2-82*2-2]     ; top/left
+    psrldq          xm2, xm0, 2                 ; top
+    psrldq          xm1, xm0, 4                 ; top/right
+    punpcklwd       xm0, xm2
+    punpcklwd       xm1, xm3
+    pmaddwd         xm0, xm4
+    pmaddwd         xm1, xm5
+    paddd           xm0, xm1
+.x_loop_ar1_inner:
+    movd          val0d, xm0
+    psrldq          xm0, 4
+    imul          val3d, cf3d
+    add           val3d, val0d
+    sarx          val3d, val3d, shiftd
+    movsx         val0d, word [bufq+xq*2]
+    add           val3d, val0d
+    cmp           val3d, maxd
+    cmovg         val3d, maxd
+    cmp           val3d, mind
+    cmovl         val3d, mind
+    mov word [bufq+xq*2], val3w
+    ; keep val3d in-place as left for next x iteration
+    inc              xq
+    jz .x_loop_ar1_end
+    test             xb, 3
+    jnz .x_loop_ar1_inner
+    jmp .x_loop_ar1
+.x_loop_ar1_end:
+    add            bufq, 82*2
+    dec              hd
+    jg .y_loop_ar1
+.ar0:
+    RET
+
+.ar2:
+    DEFINE_ARGS buf, fg_data, bdmax, shift
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movq            xm0, [fg_dataq+FGData.ar_coeffs_y+5]    ; cf5-11
+    vinserti128      m0, [fg_dataq+FGData.ar_coeffs_y+0], 1 ; cf0-4
+    vpbroadcastw   xm10, [base+round_vals-12+shiftq*2]
+    pxor             m1, m1
+    punpcklwd      xm10, xm1
+    pcmpgtb          m1, m0
+    punpcklbw        m0, m1                                 ; cf5-11,0-4
+    vpermq           m1, m0, q3333                          ; cf4
+    vbroadcasti128  m11, [base+gen_shufA]
+    pshufd           m6, m0, q0000                          ; cf[5,6], cf[0-1]
+    vbroadcasti128  m12, [base+gen_shufB]
+    pshufd           m7, m0, q1111                          ; cf[7,8], cf[2-3]
+    punpckhwd       xm1, xm0
+    pshufhw         xm9, xm0, q2121
+    pshufd          xm8, xm1, q0000                         ; cf[4,9]
+    sar          bdmaxd, 1
+    punpckhqdq      xm9, xm9                                ; cf[10,11]
+    movd            xm4, bdmaxd                             ; max_grain
+    pcmpeqd         xm5, xm5
+    sub            bufq, 2*(82*73-(82*3+79))
+    pxor            xm5, xm4                                ; min_grain
+    DEFINE_ARGS buf, fg_data, h, x
+    mov              hd, 70
+.y_loop_ar2:
+    mov              xq, -76
+.x_loop_ar2:
+    vbroadcasti128   m2, [bufq+xq*2-82*4-4]        ; y=-2,x=[-2,+5]
+    vinserti128      m1, m2, [bufq+xq*2-82*2-4], 0 ; y=-1,x=[-2,+5]
+    pshufb           m0, m1, m11                   ; y=-1/-2,x=[-2/-1,-1/+0,+0/+1,+1/+2]
+    pmaddwd          m0, m6
+    punpckhwd       xm2, xm1                       ; y=-2/-1 interleaved, x=[+2,+5]
+    pshufb           m1, m12                       ; y=-1/-2,x=[+0/+1,+1/+2,+2/+3,+3/+4]
+    pmaddwd          m1, m7
+    pmaddwd         xm2, xm8
+    paddd            m0, m1
+    vextracti128    xm1, m0, 1
+    paddd           xm0, xm10
+    paddd           xm2, xm0
+    movu            xm0, [bufq+xq*2-4]      ; y=0,x=[-2,+5]
+    paddd           xm2, xm1
+    pmovsxwd        xm1, [bufq+xq*2]        ; in dwords, y=0,x=[0,3]
+.x_loop_ar2_inner:
+    pmaddwd         xm3, xm9, xm0
+    psrldq          xm0, 2
+    paddd           xm3, xm2
+    psrldq          xm2, 4                  ; shift top to next pixel
+    psrad           xm3, [fg_dataq+FGData.ar_coeff_shift]
+    ; skip packssdw because we only care about one value
+    paddd           xm3, xm1
+    pminsd          xm3, xm4
+    psrldq          xm1, 4
+    pmaxsd          xm3, xm5
+    pextrw  [bufq+xq*2], xm3, 0
+    punpcklwd       xm3, xm3
+    pblendw         xm0, xm3, 0010b
+    inc              xq
+    jz .x_loop_ar2_end
+    test             xb, 3
+    jnz .x_loop_ar2_inner
+    jmp .x_loop_ar2
+.x_loop_ar2_end:
+    add            bufq, 82*2
+    dec              hd
+    jg .y_loop_ar2
+    RET
+
+.ar3:
+    DEFINE_ARGS buf, fg_data, bdmax, shift
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    sar          bdmaxd, 1
+    movq            xm7, [fg_dataq+FGData.ar_coeffs_y+ 0]    ; cf0-6
+    movd            xm0, [fg_dataq+FGData.ar_coeffs_y+14]    ; cf14-16
+    pinsrb          xm7, [fg_dataq+FGData.ar_coeffs_y+13], 7 ; cf0-6,13
+    pinsrb          xm0, [base+pb_1], 3                      ; cf14-16,pb_1
+    movd            xm1, [fg_dataq+FGData.ar_coeffs_y+21]    ; cf21-23
+    vinserti128      m7, [fg_dataq+FGData.ar_coeffs_y+ 7], 1 ; cf7-13
+    vinserti128      m0, [fg_dataq+FGData.ar_coeffs_y+17], 1 ; cf17-20
+    vpbroadcastw   xm11, [base+round_vals+shiftq*2-12]
+    movd           xm12, bdmaxd                              ; max_grain
+    punpcklbw        m7, m7                                  ; sign-extension
+    punpcklbw        m0, m0                                  ; sign-extension
+    punpcklbw       xm1, xm1
+    REPX   {psraw x, 8}, m7, m0, xm1
+    pshufd           m4, m7, q0000                           ; cf[0,1] | cf[7,8]
+    pshufd           m5, m7, q1111                           ; cf[2,3] | cf[9,10]
+    pshufd           m6, m7, q2222                           ; cf[4,5] | cf[11,12]
+    pshufd          xm7, xm7, q3333                          ; cf[6,13]
+    pshufd           m8, m0, q0000                           ; cf[14,15] | cf[17,18]
+    pshufd           m9, m0, q1111                           ; cf[16],pw_1 | cf[19,20]
+    paddw           xm0, xm11, xm11
+    pcmpeqd        xm13, xm13
+    pblendw        xm10, xm1, xm0, 00001000b
+    pxor           xm13, xm12                                ; min_grain
+    DEFINE_ARGS buf, fg_data, h, x
+    sub            bufq, 2*(82*73-(82*3+79))
+    mov              hd, 70
+.y_loop_ar3:
+    mov              xq, -76
+.x_loop_ar3:
+    movu            xm0, [bufq+xq*2-82*6-6+ 0]      ; y=-3,x=[-3,+4]
+    vinserti128      m0, [bufq+xq*2-82*4-6+ 0], 1   ; y=-3/-2,x=[-3,+4]
+    movq            xm1, [bufq+xq*2-82*6-6+16]      ; y=-3,x=[+5,+8]
+    vinserti128      m1, [bufq+xq*2-82*4-6+16], 1   ; y=-3/-2,x=[+5,+12]
+    palignr          m3, m1, m0, 2                  ; y=-3/-2,x=[-2,+5]
+    palignr          m1, m0, 12                     ; y=-3/-2,x=[+3,+6]
+    punpckhwd        m2, m0, m3                     ; y=-3/-2,x=[+1/+2,+2/+3,+3/+4,+4/+5]
+    punpcklwd        m0, m3                         ; y=-3/-2,x=[-3/-2,-2/-1,-1/+0,+0/+1]
+    shufps           m3, m0, m2, q1032              ; y=-3/-2,x=[-1/+0,+0/+1,+1/+2,+2/+3]
+    pmaddwd          m0, m4
+    pmaddwd          m2, m6
+    pmaddwd          m3, m5
+    paddd            m0, m2
+    movu            xm2, [bufq+xq*2-82*2-6+ 0]      ; y=-1,x=[-3,+4]
+    vinserti128      m2, [bufq+xq*2-82*2-6+ 6], 1   ; y=-1,x=[+1,+8]
+    paddd            m0, m3
+    psrldq           m3, m2, 2
+    punpcklwd        m3, m2, m3                     ; y=-1,x=[-3/-2,-2/-1,-1/+0,+0/+1]
+    pmaddwd          m3, m8                         ;      x=[+0/+1,+1/+2,+2/+3,+3/+4]
+    paddd            m0, m3
+    psrldq           m3, m2, 4
+    psrldq           m2, 6
+    vpblendd         m2, m11, 0x0f                  ; rounding constant
+    punpcklwd        m3, m2                         ; y=-1,x=[-1/rnd,+0/rnd,+1/rnd,+2/rnd]
+    pmaddwd          m3, m9                         ;      x=[+2/+3,+3/+4,+4/+5,+5,+6]
+    vextracti128    xm2, m1, 1
+    punpcklwd       xm1, xm2
+    pmaddwd         xm1, xm7                        ; y=-3/-2 interleaved,x=[+3,+4,+5,+6]
+    paddd            m0, m3
+    vextracti128    xm2, m0, 1
+    paddd           xm0, xm1
+    movu            xm1, [bufq+xq*2-6]        ; y=0,x=[-3,+4]
+    paddd           xm0, xm2
+.x_loop_ar3_inner:
+    pmaddwd         xm2, xm1, xm10
+    pshuflw         xm3, xm2, q1032
+    paddd           xm2, xm0                ; add top
+    paddd           xm2, xm3                ; left+cur
+    psrldq          xm0, 4
+    psrad           xm2, [fg_dataq+FGData.ar_coeff_shift]
+    ; skip packssdw because we only care about one value
+    pminsd          xm2, xm12
+    pmaxsd          xm2, xm13
+    pextrw  [bufq+xq*2], xm2, 0
+    pslldq          xm2, 4
+    psrldq          xm1, 2
+    pblendw         xm1, xm2, 0100b
+    inc              xq
+    jz .x_loop_ar3_end
+    test             xb, 3
+    jnz .x_loop_ar3_inner
+    jmp .x_loop_ar3
+.x_loop_ar3_end:
+    add            bufq, 82*2
+    dec              hd
+    jg .y_loop_ar3
+    RET
+
+%macro GEN_GRAIN_UV_FN 3 ; ss_name, ss_x, ss_y
+INIT_XMM avx2
+cglobal generate_grain_uv_%1_16bpc, 4, 11, 8, buf, bufy, fg_data, uv, bdmax
+%define base r8-generate_grain_uv_%1_16bpc_avx2_table
+    lea              r8, [generate_grain_uv_%1_16bpc_avx2_table]
+    movifnidn    bdmaxd, bdmaxm
+    vpbroadcastw    xm0, [fg_dataq+FGData.seed]
+    mov             r5d, [fg_dataq+FGData.grain_scale_shift]
+    movq            xm1, [base+next_upperbit_mask]
+    lea             r6d, [bdmaxq+1]
+    movq            xm4, [base+mul_bits]
+    shr             r6d, 11             ; 0 for 10bpc, 2 for 12bpc
+    movq            xm5, [base+hmul_bits]
+    sub              r5, r6
+    mova            xm6, [base+pb_mask]
+    vpbroadcastd    xm2, [base+pw_seed_xor+uvq*4]
+    vpbroadcastw    xm7, [base+round+r5*2-2]
+    pxor            xm0, xm2
+    lea              r6, [gaussian_sequence]
+%if %2
+    mov             r7d, 73-35*%3
+    add            bufq, 44*2
+.loop_y:
+    mov              r5, -44*2
+%else
+    mov              r5, -82*73*2
+    sub            bufq, r5
+%endif
+.loop_x:
+    pand            xm2, xm0, xm1
+    psrlw           xm3, xm2, 10
+    por             xm2, xm3            ; bits 0xf, 0x1e, 0x3c and 0x78 are set
+    pmullw          xm2, xm4            ; bits 0x0f00 are set
+    pmulhuw         xm0, xm5
+    pshufb          xm3, xm6, xm2       ; set 15th bit for next 4 seeds
+    psllq           xm2, xm3, 30
+    por             xm2, xm3
+    psllq           xm3, xm2, 15
+    por             xm2, xm0            ; aggregate each bit into next seed's high bit
+    por             xm2, xm3            ; 4 next output seeds
+    pshuflw         xm0, xm2, q3333
+    psrlw           xm2, 5
+    movq            r10, xm2
+    movzx           r9d, r10w
+    movd            xm2, [r6+r9*2]
+    rorx             r9, r10, 32
+    shr            r10d, 16
+    pinsrw          xm2, [r6+r10*2], 1
+    movzx          r10d, r9w
+    pinsrw          xm2, [r6+r10*2], 2
+    shr             r9d, 16
+    pinsrw          xm2, [r6+r9*2], 3
+    paddw           xm2, xm2            ; otherwise bpc=12 w/ grain_scale_shift=0
+    pmulhrsw        xm2, xm7            ; shifts by 0, which pmulhrsw does not support
+    movq      [bufq+r5], xm2
+    add              r5, 8
+    jl .loop_x
+%if %2
+    add            bufq, 82*2
+    dec             r7d
+    jg .loop_y
+%endif
+
+    ; auto-regression code
+    movsxd           r6, [fg_dataq+FGData.ar_coeff_lag]
+    movsxd           r6, [r8+r6*4]
+    add              r6, r8
+    jmp              r6
+
+INIT_YMM avx2
+.ar0:
+    DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift
+    imul            uvd, 28
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    vpbroadcastb     m0, [fg_dataq+FGData.ar_coeffs_uv+uvq]
+    sar          bdmaxd, 1
+    vpbroadcastd     m4, [base+gen_ar0_shift-24+shiftq*4]
+    movd            xm6, bdmaxd
+    pcmpeqw          m7, m7
+    pmaddubsw        m4, m0  ; ar_coeff << (14 - shift)
+    vpbroadcastw     m6, xm6 ; max_gain
+    pxor             m7, m6  ; min_grain
+    DEFINE_ARGS buf, bufy, h, x
+%if %2
+    vpbroadcastw     m5, [base+hmul_bits+2+%3*2]
+    sub            bufq, 2*(82*(73-35*%3)+82-(82*3+41))
+%else
+    sub            bufq, 2*(82*70-3)
+%endif
+    add           bufyq, 2*(3+82*3)
+    mov              hd, 70-35*%3
+.y_loop_ar0:
+%if %2
+    ; first 32 pixels
+    movu            xm0, [bufyq+16*0]
+    vinserti128      m0, [bufyq+16*2], 1
+    movu            xm1, [bufyq+16*1]
+    vinserti128      m1, [bufyq+16*3], 1
+%if %3
+    movu            xm2, [bufyq+82*2+16*0]
+    vinserti128      m2, [bufyq+82*2+16*2], 1
+    movu            xm3, [bufyq+82*2+16*1]
+    vinserti128      m3, [bufyq+82*2+16*3], 1
+    paddw            m0, m2
+    paddw            m1, m3
+%endif
+    phaddw           m0, m1
+    movu            xm1, [bufyq+16*4]
+    vinserti128      m1, [bufyq+16*6], 1
+    movu            xm2, [bufyq+16*5]
+    vinserti128      m2, [bufyq+16*7], 1
+%if %3
+    movu            xm3, [bufyq+82*2+16*4]
+    vinserti128      m3, [bufyq+82*2+16*6], 1
+    paddw            m1, m3
+    movu            xm3, [bufyq+82*2+16*5]
+    vinserti128      m3, [bufyq+82*2+16*7], 1
+    paddw            m2, m3
+%endif
+    phaddw           m1, m2
+    pmulhrsw         m0, m5
+    pmulhrsw         m1, m5
+%else
+    xor              xd, xd
+.x_loop_ar0:
+    movu             m0, [bufyq+xq*2]
+    movu             m1, [bufyq+xq*2+32]
+%endif
+    paddw            m0, m0
+    paddw            m1, m1
+    pmulhrsw         m0, m4
+    pmulhrsw         m1, m4
+%if %2
+    paddw            m0, [bufq+ 0]
+    paddw            m1, [bufq+32]
+%else
+    paddw            m0, [bufq+xq*2+ 0]
+    paddw            m1, [bufq+xq*2+32]
+%endif
+    pminsw           m0, m6
+    pminsw           m1, m6
+    pmaxsw           m0, m7
+    pmaxsw           m1, m7
+%if %2
+    movu      [bufq+ 0], m0
+    movu      [bufq+32], m1
+
+    ; last 6 pixels
+    movu            xm0, [bufyq+32*4]
+    movu            xm1, [bufyq+32*4+16]
+%if %3
+    paddw           xm0, [bufyq+32*4+82*2]
+    paddw           xm1, [bufyq+32*4+82*2+16]
+%endif
+    phaddw          xm0, xm1
+    movu            xm1, [bufq+32*2]
+    pmulhrsw        xm0, xm5
+    paddw           xm0, xm0
+    pmulhrsw        xm0, xm4
+    paddw           xm0, xm1
+    pminsw          xm0, xm6
+    pmaxsw          xm0, xm7
+    vpblendd        xm0, xm1, 0x08
+    movu    [bufq+32*2], xm0
+%else
+    movu [bufq+xq*2+ 0], m0
+    movu [bufq+xq*2+32], m1
+    add              xd, 32
+    cmp              xd, 64
+    jl .x_loop_ar0
+
+    ; last 12 pixels
+    movu             m0, [bufyq+64*2]
+    movu             m1, [bufq+64*2]
+    paddw            m0, m0
+    pmulhrsw         m0, m4
+    paddw            m0, m1
+    pminsw           m0, m6
+    pmaxsw           m0, m7
+    vpblendd         m0, m1, 0xc0
+    movu    [bufq+64*2], m0
+%endif
+    add            bufq, 82*2
+    add           bufyq, 82*2<<%3
+    dec              hd
+    jg .y_loop_ar0
+    RET
+
+INIT_XMM avx2
+.ar1:
+    DEFINE_ARGS buf, bufy, fg_data, uv, max, cf3, min, val3, x, shift
+    imul            uvd, 28
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movsx          cf3d, byte [fg_dataq+FGData.ar_coeffs_uv+uvq+3]
+    movd            xm4, [fg_dataq+FGData.ar_coeffs_uv+uvq]
+    pinsrb          xm4, [fg_dataq+FGData.ar_coeffs_uv+uvq+4], 3
+    DEFINE_ARGS buf, bufy, h, val0, max, cf3, min, val3, x, shift
+    pmovsxbw        xm4, xm4
+    pshufd          xm5, xm4, q1111
+    pshufd          xm4, xm4, q0000
+    pmovsxwd        xm3, [base+round_vals+shiftq*2-12]    ; rnd
+    vpbroadcastw    xm6, [base+hmul_bits+2+%3*2]
+    vpbroadcastd    xm3, xm3
+%if %2
+    sub            bufq, 2*(82*(73-35*%3)+44-(82*3+41))
+%else
+    sub            bufq, 2*(82*69+3)
+%endif
+    add           bufyq, 2*(79+82*3)
+    mov              hd, 70-35*%3
+    sar            maxd, 1
+    mov            mind, maxd
+    xor            mind, -1
+.y_loop_ar1:
+    mov              xq, -(76>>%2)
+    movsx         val3d, word [bufq+xq*2-2]
+.x_loop_ar1:
+    movu            xm0, [bufq+xq*2-82*2-2] ; top/left
+%if %2
+    movu            xm2, [bufyq+xq*4]
+%else
+    movq            xm2, [bufyq+xq*2]
+%endif
+%if %2
+%if %3
+    phaddw          xm2, [bufyq+xq*4+82*2]
+    punpckhqdq      xm1, xm2, xm2
+    paddw           xm2, xm1
+%else
+    phaddw          xm2, xm2
+%endif
+    pmulhrsw        xm2, xm6
+%endif
+    psrldq          xm1, xm0, 4             ; top/right
+    punpcklwd       xm1, xm2
+    psrldq          xm2, xm0, 2             ; top
+    punpcklwd       xm0, xm2
+    pmaddwd         xm1, xm5
+    pmaddwd         xm0, xm4
+    paddd           xm1, xm3
+    paddd           xm0, xm1
+.x_loop_ar1_inner:
+    movd          val0d, xm0
+    psrldq          xm0, 4
+    imul          val3d, cf3d
+    add           val3d, val0d
+    sarx          val3d, val3d, shiftd
+    movsx         val0d, word [bufq+xq*2]
+    add           val3d, val0d
+    cmp           val3d, maxd
+    cmovg         val3d, maxd
+    cmp           val3d, mind
+    cmovl         val3d, mind
+    mov word [bufq+xq*2], val3w
+    ; keep val3d in-place as left for next x iteration
+    inc              xq
+    jz .x_loop_ar1_end
+    test             xb, 3
+    jnz .x_loop_ar1_inner
+    jmp .x_loop_ar1
+.x_loop_ar1_end:
+    add            bufq, 82*2
+    add           bufyq, 82*2<<%3
+    dec              hd
+    jg .y_loop_ar1
+    RET
+
+INIT_YMM avx2
+.ar2:
+%if WIN64
+    %assign stack_size_padded 136
+    SUB             rsp, stack_size_padded
+    WIN64_PUSH_XMM 13 + %2, 8
+%endif
+    DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    imul            uvd, 28
+    vbroadcasti128  m10, [base+gen_shufA]
+    sar          bdmaxd, 1
+    vbroadcasti128  m11, [base+gen_shufB]
+    movd            xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 5]
+    pinsrb          xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+12], 4
+    pinsrb          xm7, [base+pb_1], 5
+    pinsrw          xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+10], 3
+    movhps          xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 0]
+    pinsrb          xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 9], 13
+    pmovsxbw         m7, xm7
+    movd            xm8, bdmaxd             ; max_grain
+    pshufd           m4, m7, q0000
+    vpbroadcastw   xm12, [base+round_vals-12+shiftq*2]
+    pshufd           m5, m7, q1111
+    pcmpeqd         xm9, xm9
+    pshufd           m6, m7, q2222
+    pxor            xm9, xm8                ; min_grain
+    pshufd          xm7, xm7, q3333
+    DEFINE_ARGS buf, bufy, fg_data, h, x
+%if %2
+    vpbroadcastw   xm13, [base+hmul_bits+2+%3*2]
+    sub            bufq, 2*(82*(73-35*%3)+44-(82*3+41))
+%else
+    sub            bufq, 2*(82*69+3)
+%endif
+    add           bufyq, 2*(79+82*3)
+    mov              hd, 70-35*%3
+.y_loop_ar2:
+    mov              xq, -(76>>%2)
+.x_loop_ar2:
+    vbroadcasti128   m3, [bufq+xq*2-82*2-4]        ; y=-1,x=[-2,+5]
+    vinserti128      m2, m3, [bufq+xq*2-82*4-4], 1 ; y=-2,x=[-2,+5]
+    pshufb           m0, m2, m10                   ; y=-1/-2,x=[-2/-1,-1/+0,+0/+1,+1/+2]
+    pmaddwd          m0, m4
+    pshufb           m1, m2, m11                   ; y=-1/-2,x=[+0/+1,+1/+2,+2/+3,+3/+4]
+    pmaddwd          m1, m5
+    punpckhwd        m2, m3                        ; y=-2/-1 interleaved, x=[+2,+5]
+%if %2
+    movu            xm3, [bufyq+xq*4]
+%if %3
+    paddw           xm3, [bufyq+xq*4+82*2]
+%endif
+    phaddw          xm3, xm3
+    pmulhrsw        xm3, xm13
+%else
+    movq            xm3, [bufyq+xq*2]
+%endif
+    punpcklwd       xm3, xm12                   ; luma, round interleaved
+    vpblendd         m2, m3, 0x0f
+    pmaddwd          m2, m6
+    paddd            m1, m0
+    movu            xm0, [bufq+xq*2-4]      ; y=0,x=[-2,+5]
+    paddd            m2, m1
+    vextracti128    xm1, m2, 1
+    paddd           xm2, xm1
+    pshufd          xm1, xm0, q3321
+    pmovsxwd        xm1, xm1                ; y=0,x=[0,3] in dword
+.x_loop_ar2_inner:
+    pmaddwd         xm3, xm7, xm0
+    paddd           xm3, xm2
+    psrldq          xm2, 4                  ; shift top to next pixel
+    psrad           xm3, [fg_dataq+FGData.ar_coeff_shift]
+    ; we do not need to packssdw since we only care about one value
+    paddd           xm3, xm1
+    psrldq          xm1, 4
+    pminsd          xm3, xm8
+    pmaxsd          xm3, xm9
+    pextrw  [bufq+xq*2], xm3, 0
+    psrldq          xm0, 2
+    pslldq          xm3, 2
+    pblendw         xm0, xm3, 00000010b
+    inc              xq
+    jz .x_loop_ar2_end
+    test             xb, 3
+    jnz .x_loop_ar2_inner
+    jmp .x_loop_ar2
+.x_loop_ar2_end:
+    add            bufq, 82*2
+    add           bufyq, 82*2<<%3
+    dec              hd
+    jg .y_loop_ar2
+    RET
+
+.ar3:
+%if WIN64
+    %assign stack_offset 32
+    %assign stack_size_padded 152
+    SUB             rsp, stack_size_padded
+    WIN64_PUSH_XMM 14 + %2, 8
+%endif
+    DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    imul            uvd, 28
+    vpbroadcastw   xm11, [base+round_vals-12+shiftq*2]
+    sar          bdmaxd, 1
+    movq            xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 0]
+    pinsrb          xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+24], 7 ; luma
+    movhps          xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 7]
+    pmovsxbw         m7, xm7
+%if %2
+    vpbroadcastw   xm14, [base+hmul_bits+2+%3*2]
+%endif
+    pshufd           m4, m7, q0000
+    pshufd           m5, m7, q1111
+    pshufd           m6, m7, q2222
+    pshufd           m7, m7, q3333
+    movd            xm0, [fg_dataq+FGData.ar_coeffs_uv+uvq+14]
+    pinsrb          xm0, [base+pb_1], 3
+    pinsrd          xm0, [fg_dataq+FGData.ar_coeffs_uv+uvq+21], 1
+    pinsrd          xm0, [fg_dataq+FGData.ar_coeffs_uv+uvq+17], 2
+    pmovsxbw         m0, xm0
+    movd           xm12, bdmaxd                 ; max_grain
+    pshufd           m8, m0, q0000
+    pshufd           m9, m0, q1111
+    pcmpeqd        xm13, xm13
+    punpckhqdq     xm10, xm0, xm0
+    pxor           xm13, xm12                   ; min_grain
+    pinsrw         xm10, [base+round_vals-10+shiftq*2], 3
+    DEFINE_ARGS buf, bufy, fg_data, h, unused, x
+%if %2
+    sub            bufq, 2*(82*(73-35*%3)+44-(82*3+41))
+%else
+    sub            bufq, 2*(82*69+3)
+%endif
+    add           bufyq, 2*(79+82*3)
+    mov              hd, 70-35*%3
+.y_loop_ar3:
+    mov              xq, -(76>>%2)
+.x_loop_ar3:
+    movu            xm2, [bufq+xq*2-82*6-6+ 0]    ; y=-3,x=[-3,+4]
+    vinserti128      m2, [bufq+xq*2-82*4-6+ 0], 1 ; y=-3/-2,x=[-3,+4]
+    movq            xm1, [bufq+xq*2-82*6-6+16]    ; y=-3,x=[+5,+8]
+    vinserti128      m1, [bufq+xq*2-82*4-6+16], 1 ; y=-3/-2,x=[+5,+12]
+    palignr          m3, m1, m2, 2                ; y=-3/-2,x=[-2,+5]
+    palignr          m1, m2, 12                   ; y=-3/-2,x=[+3,+6]
+    punpcklwd        m0, m2, m3                   ; y=-3/-2,x=[-3/-2,-2/-1,-1/+0,+0/+1]
+    punpckhwd        m2, m3                       ; y=-3/-2,x=[+1/+2,+2/+3,+3/+4,+4/+5]
+    shufps           m3, m0, m2, q1032            ; y=-3/-2,x=[-1/+0,+0/+1,+1/+2,+2/+3]
+    pmaddwd          m0, m4
+    pmaddwd          m2, m6
+    pmaddwd          m3, m5
+    paddd            m0, m2
+    paddd            m0, m3
+    movu            xm2, [bufq+xq*2-82*2-6+ 0]    ; y=-1,x=[-3,+4]
+    vinserti128      m2, [bufq+xq*2-82*2-6+ 6], 1 ; y=-1,x=[+1,+8]
+%if %2
+    movu            xm3, [bufyq+xq*4]
+%if %3
+    paddw           xm3, [bufyq+xq*4+82*2]
+%endif
+    phaddw          xm3, xm3
+    pmulhrsw        xm3, xm14
+%else
+    movq            xm3, [bufyq+xq*2]
+%endif
+    punpcklwd        m1, m3
+    pmaddwd          m1, m7
+    paddd            m0, m1
+    psrldq           m1, m2, 4
+    psrldq           m3, m2, 6
+    vpblendd         m3, m11, 0x0f                ; rounding constant
+    punpcklwd        m1, m3                       ; y=-1,x=[-1/rnd,+0/rnd,+1/rnd,+2/rnd]
+    pmaddwd          m1, m9                       ;      x=[+2/+3,+3/+4,+4/+5,+5,+6]
+    psrldq           m3, m2, 2
+    punpcklwd        m2, m3                       ; y=-1,x=[-3/-2,-2/-1,-1/+0,+0/+1]
+    pmaddwd          m2, m8                       ;      x=[+0/+1,+1/+2,+2/+3,+3/+4]
+    paddd            m0, m1
+    movu            xm1, [bufq+xq*2-6]            ; y=0,x=[-3,+4]
+    paddd            m0, m2
+    vextracti128    xm2, m0, 1
+    paddd           xm0, xm2
+.x_loop_ar3_inner:
+    pmaddwd         xm2, xm1, xm10
+    pshuflw         xm3, xm2, q1032
+    paddd           xm2, xm0                      ; add top
+    paddd           xm2, xm3                      ; left+cur
+    psrldq          xm0, 4
+    psrad           xm2, [fg_dataq+FGData.ar_coeff_shift]
+    psrldq          xm1, 2
+    ; no need to packssdw since we only care about one value
+    pminsd          xm2, xm12
+    pmaxsd          xm2, xm13
+    pextrw  [bufq+xq*2], xm2, 0
+    pslldq          xm2, 4
+    pblendw         xm1, xm2, 00000100b
+    inc              xq
+    jz .x_loop_ar3_end
+    test             xb, 3
+    jnz .x_loop_ar3_inner
+    jmp .x_loop_ar3
+.x_loop_ar3_end:
+    add            bufq, 82*2
+    add           bufyq, 82*2<<%3
+    dec              hd
+    jg .y_loop_ar3
+    RET
+%endmacro
+
+cglobal fgy_32x32xn_16bpc, 6, 14, 16, dst, src, stride, fg_data, w, scaling, \
+                                      grain_lut, unused, sby, see
+%define base r11-grain_min
+    lea             r11, [grain_min]
+    mov             r6d, r9m ; bdmax
+    mov             r9d, [fg_dataq+FGData.clip_to_restricted_range]
+    mov             r7d, [fg_dataq+FGData.scaling_shift]
+    mov            sbyd, sbym
+    vpbroadcastd     m8, r9m
+    shr             r6d, 11  ; is_12bpc
+    vpbroadcastd     m9, [base+grain_min+r6*4]
+    shlx           r10d, r9d, r6d
+    vpbroadcastd    m10, [base+grain_max+r6*4]
+    lea             r9d, [r6+r9*4]
+    vpbroadcastw    m11, [base+mul_bits+r7*2-12]
+    vpbroadcastd    m12, [base+fg_min+r10*4]
+    vpbroadcastd    m13, [base+fg_max+r9*4]
+    test           sbyd, sbyd
+    setnz           r7b
+    vpbroadcastd    m14, [base+pd_16]
+    test            [fg_dataq+FGData.overlap_flag], r7b
+    jnz .vertical_overlap
+
+    imul           seed, sbyd, (173 << 24) | 37
+    add            seed, (105 << 24) | 178
+    rorx           seed, seed, 24
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, src_bak
+
+    lea        src_bakq, [srcq+wq*2]
+    neg              wq
+    sub            dstq, srcq
+
+.loop_x:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyd, [offyq+offxq*2+747] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, src_bak
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+.loop_y:
+    ; scaling[src]
+    mova             m0, [srcq+ 0]
+    mova             m1, [srcq+32]
+    pand             m4, m8, m0
+    psrld            m3, m0, 16
+    mova             m6, m9
+    vpgatherdd       m2, [scalingq+m4-0], m9
+    pand             m3, m8
+    mova             m9, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pand             m5, m8, m1
+    mova             m6, m9
+    vpgatherdd       m3, [scalingq+m5-0], m9
+    pblendw          m4, m2, 0x55
+    psrld            m2, m1, 16
+    mova             m9, m6
+    pand             m2, m8
+    vpgatherdd       m5, [scalingq+m2-2], m6
+    pblendw          m5, m3, 0x55
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m4, m11
+    pmaddubsw        m5, m11
+    paddw            m4, m4
+    paddw            m5, m5
+    pmulhrsw         m4, [grain_lutq+offxyq*2]
+    pmulhrsw         m5, [grain_lutq+offxyq*2+32]
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m4
+    paddw            m1, m5
+    pmaxsw           m0, m12
+    pmaxsw           m1, m12
+    pminsw           m0, m13
+    pminsw           m1, m13
+    mova [dstq+srcq+ 0], m0
+    mova [dstq+srcq+32], m1
+
+    add            srcq, strideq
+    add      grain_lutq, 82*2
+    dec              hd
+    jg .loop_y
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq*2]
+    cmp byte [fg_dataq+FGData.overlap_flag], 0
+    je .loop_x
+    movq            xm7, [pw_27_17_17_27]
+    cmp       dword r8m, 0 ; sby
+    jne .loop_x_hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+.loop_x_h_overlap:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, src_bak, left_offxy
+
+    lea     left_offxyd, [offyq+32]         ; previous column's offy*stride+offx
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyd, [offyq+offxq*2+747] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, src_bak, left_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+.loop_y_h_overlap:
+    ; scaling[src]
+    mova             m0, [srcq+ 0]
+    mova             m1, [srcq+32]
+    pand             m4, m8, m0
+    psrld            m3, m0, 16
+    mova             m6, m9
+    vpgatherdd       m2, [scalingq+m4-0], m9
+    pand             m3, m8
+    mova             m9, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pand             m5, m8, m1
+    mova             m6, m9
+    vpgatherdd       m3, [scalingq+m5-0], m9
+    pblendw          m4, m2, 0x55
+    psrld            m2, m1, 16
+    mova             m9, m6
+    pand             m2, m8
+    vpgatherdd       m5, [scalingq+m2-2], m6
+    pblendw          m5, m3, 0x55
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq*2]
+    movd            xm6, [grain_lutq+left_offxyq*2]
+    punpcklwd       xm6, xm3
+    pmaddwd         xm6, xm7
+    paddd           xm6, xm14
+    psrad           xm6, 5
+    packssdw        xm6, xm6
+    pmaxsw          xm6, xm9
+    pminsw          xm6, xm10
+    vpblendd         m3, m6, 0x01
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m4, m11
+    pmaddubsw        m5, m11
+    paddw            m4, m4
+    paddw            m5, m5
+    pmulhrsw         m4, m3
+    pmulhrsw         m5, [grain_lutq+offxyq*2+32]
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m4
+    paddw            m1, m5
+    pmaxsw           m0, m12
+    pmaxsw           m1, m12
+    pminsw           m0, m13
+    pminsw           m1, m13
+    mova [dstq+srcq+ 0], m0
+    mova [dstq+srcq+32], m1
+
+    add            srcq, strideq
+    add      grain_lutq, 82*2
+    dec              hd
+    jg .loop_y_h_overlap
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq*2]
+    cmp       dword r8m, 0 ; sby
+    jne .loop_x_hv_overlap
+    jmp .loop_x_h_overlap
+
+.vertical_overlap:
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused1, \
+                sby, see, src_bak
+
+    movzx          sbyd, sbyb
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+    imul            r7d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             r7d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             r7d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, r7d
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    lea        src_bakq, [srcq+wq*2]
+    neg              wq
+    sub            dstq, srcq
+
+.loop_x_v_overlap:
+    vpbroadcastd    m15, [pw_27_17_17_27]
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, src_bak, unused, top_offxy
+
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*2+0x10001*747+32*82]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, src_bak, unused, top_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+.loop_y_v_overlap:
+    ; scaling[src]
+    mova             m0, [srcq+ 0]
+    mova             m1, [srcq+32]
+    pand             m4, m8, m0
+    psrld            m3, m0, 16
+    mova             m6, m9
+    vpgatherdd       m2, [scalingq+m4-0], m9
+    pand             m3, m8
+    mova             m9, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pand             m5, m8, m1
+    mova             m6, m9
+    vpgatherdd       m3, [scalingq+m5-0], m9
+    pblendw          m2, m4, 0xaa
+    psrld            m4, m1, 16
+    mova             m9, m6
+    pand             m4, m8
+    vpgatherdd       m5, [scalingq+m4-2], m6
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m6, [grain_lutq+offxyq*2]
+    movu             m5, [grain_lutq+top_offxyq*2]
+    punpcklwd        m4, m5, m6
+    punpckhwd        m5, m6
+    pmaddwd          m4, m15
+    pmaddwd          m5, m15
+    movu             m7, [grain_lutq+offxyq*2+32]
+    movu             m6, [grain_lutq+top_offxyq*2+32]
+    paddd            m4, m14
+    paddd            m5, m14
+    psrad            m4, 5
+    psrad            m5, 5
+    packssdw         m4, m5
+    punpcklwd        m5, m6, m7
+    punpckhwd        m6, m7
+    pmaddwd          m5, m15
+    pmaddwd          m6, m15
+    paddd            m5, m14
+    paddd            m6, m14
+    psrad            m5, 5
+    psrad            m6, 5
+    packssdw         m5, m6
+    pmaxsw           m4, m9
+    pmaxsw           m5, m9
+    pminsw           m4, m10
+    pminsw           m5, m10
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m2, m11
+    pmaddubsw        m3, m11
+    paddw            m2, m2
+    paddw            m3, m3
+    pmulhrsw         m4, m2
+    pmulhrsw         m5, m3
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m4
+    paddw            m1, m5
+    pmaxsw           m0, m12
+    pmaxsw           m1, m12
+    pminsw           m0, m13
+    pminsw           m1, m13
+    mova [dstq+srcq+ 0], m0
+    mova [dstq+srcq+32], m1
+
+    add            srcq, strideq
+    add      grain_lutq, 82*2
+    dec              hb
+    jz .end_y_v_overlap
+    vpbroadcastd    m15, [pw_27_17_17_27+4] ; swap weights for second v-overlap line
+    ; 2 lines get vertical overlap, then fall back to non-overlap code for
+    ; remaining (up to) 30 lines
+    add              hd, 0x80000000
+    jnc .loop_y_v_overlap
+    jmp .loop_y
+.end_y_v_overlap:
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq*2]
+
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump
+    ; back to .loop_x_v_overlap, and instead always fall-through to
+    ; h+v overlap
+
+.loop_x_hv_overlap:
+    vpbroadcastd    m15, [pw_27_17_17_27]
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, src_bak, left_offxy, top_offxy, topleft_offxy
+
+    lea  topleft_offxyd, [top_offxyq+32]
+    lea     left_offxyd, [offyq+32]
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*2+0x10001*747+32*82]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, src_bak, left_offxy, top_offxy, topleft_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+.loop_y_hv_overlap:
+    ; scaling[src]
+    mova             m0, [srcq+ 0]
+    mova             m1, [srcq+32]
+    pand             m4, m8, m0
+    psrld            m3, m0, 16
+    mova             m6, m9
+    vpgatherdd       m2, [scalingq+m4-0], m9
+    pand             m3, m8
+    mova             m9, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pand             m5, m8, m1
+    mova             m6, m9
+    vpgatherdd       m3, [scalingq+m5-0], m9
+    pblendw          m2, m4, 0xaa
+    psrld            m4, m1, 16
+    mova             m9, m6
+    pand             m4, m8
+    vpgatherdd       m5, [scalingq+m4-2], m6
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m7, [grain_lutq+offxyq*2]
+    movd            xm6, [grain_lutq+left_offxyq*2]
+    movu             m5, [grain_lutq+top_offxyq*2]
+    movd            xm4, [grain_lutq+topleft_offxyq*2]
+    ; do h interpolation first (so top | top/left -> top, left | cur -> cur)
+    punpcklwd       xm6, xm7
+    punpcklwd       xm4, xm5
+    punpcklqdq      xm6, xm4
+    movddup         xm4, [pw_27_17_17_27]
+    pmaddwd         xm6, xm4
+    paddd           xm6, xm14
+    psrad           xm6, 5
+    packssdw        xm6, xm6
+    pmaxsw          xm6, xm9
+    pminsw          xm6, xm10
+    pshuflw         xm4, xm6, q1032
+    vpblendd         m6, m7, 0xfe
+    vpblendd         m4, m5, 0xfe
+    ; followed by v interpolation (top | cur -> cur)
+    punpckhwd        m5, m7
+    pmaddwd          m5, m15
+    punpcklwd        m4, m6
+    pmaddwd          m4, m15
+    movu             m7, [grain_lutq+offxyq*2+32]
+    movu             m6, [grain_lutq+top_offxyq*2+32]
+    paddd            m5, m14
+    paddd            m4, m14
+    psrad            m5, 5
+    psrad            m4, 5
+    packssdw         m4, m5
+    punpcklwd        m5, m6, m7
+    punpckhwd        m6, m7
+    pmaddwd          m5, m15
+    pmaddwd          m6, m15
+    paddd            m5, m14
+    paddd            m6, m14
+    psrad            m5, 5
+    psrad            m6, 5
+    packssdw         m5, m6
+    pmaxsw           m4, m9
+    pmaxsw           m5, m9
+    pminsw           m4, m10
+    pminsw           m5, m10
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m2, m11
+    pmaddubsw        m3, m11
+    paddw            m2, m2
+    paddw            m3, m3
+    pmulhrsw         m4, m2
+    pmulhrsw         m5, m3
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m4
+    paddw            m1, m5
+    pmaxsw           m0, m12
+    pmaxsw           m1, m12
+    pminsw           m0, m13
+    pminsw           m1, m13
+    mova [dstq+srcq+ 0], m0
+    mova [dstq+srcq+32], m1
+
+    add            srcq, strideq
+    add      grain_lutq, 82*2
+    dec              hb
+    jz .end_y_hv_overlap
+    vpbroadcastd    m15, [pw_27_17_17_27+4] ; swap weights for second v-overlap line
+    ; 2 lines get vertical overlap, then fall back to non-overlap code for
+    ; remaining (up to) 30 lines
+    add              hd, 0x80000000
+    jnc .loop_y_hv_overlap
+    movq            xm7, [pw_27_17_17_27]
+    jmp .loop_y_h_overlap
+.end_y_hv_overlap:
+    add              wq, 32
+    lea            srcq, [src_bakq+wq*2]
+    jl .loop_x_hv_overlap
+.end:
+    RET
+
+%macro FGUV_FN 3 ; name, ss_hor, ss_ver
+cglobal fguv_32x32xn_i%1_16bpc, 6, 15, 16, dst, src, stride, fg_data, w, scaling, \
+                                           grain_lut, h, sby, luma, lstride, uv_pl, is_id
+%define base r12-grain_min
+    lea             r12, [grain_min]
+    mov             r9d, r13m               ; bdmax
+    mov             r7d, [fg_dataq+FGData.scaling_shift]
+    mov            r11d, is_idm
+    mov            sbyd, sbym
+    vpbroadcastw    m11, [base+mul_bits+r7*2-12]
+    mov             r6d, [fg_dataq+FGData.clip_to_restricted_range]
+    shr             r9d, 11                 ; is_12bpc
+    vpbroadcastd     m8, [base+grain_min+r9*4]
+    shlx           r10d, r6d, r9d
+    vpbroadcastd     m9, [base+grain_max+r9*4]
+    vpbroadcastw    m10, r13m
+    shlx            r6d, r6d, r11d
+    vpbroadcastd    m12, [base+fg_min+r10*4]
+    lea             r6d, [r9+r6*2]
+    vpbroadcastd    m13, [base+fg_max+r6*4]
+    test           sbyd, sbyd
+    setnz           r7b
+    cmp byte [fg_dataq+FGData.chroma_scaling_from_luma], 0
+    jne .csfl
+
+%macro %%FGUV_32x32xN_LOOP 3 ; not-csfl, ss_hor, ss_ver
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                unused, sby, see, overlap
+
+%if %1
+    mov             r6d, r11m
+    vpbroadcastd     m0, [base+pb_8_9_0_1]
+    vpbroadcastd     m1, [base+uv_offset_mul+r9*4]
+    vbroadcasti128  m14, [fg_dataq+FGData.uv_mult+r6*4]
+    vpbroadcastd    m15, [fg_dataq+FGData.uv_offset+r6*4]
+    pshufb          m14, m0 ; { uv_luma_mult, uv_mult }
+    pmaddwd         m15, m1
+%else
+%if %2
+    vpbroadcastq    m15, [base+pw_23_22]
+%else
+    vpbroadcastq    m15, [base+pw_27_17_17_27]
+%endif
+    vpbroadcastd    m14, [base+pd_16]
+%endif
+    test            [fg_dataq+FGData.overlap_flag], r7b
+    jnz %%vertical_overlap
+
+    imul           seed, sbyd, (173 << 24) | 37
+    add            seed, (105 << 24) | 178
+    rorx           seed, seed, 24
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                unused2, unused3, see, unused4, unused5, unused6, luma, lstride
+
+    mov           lumaq, r9mp
+    mov        lstrideq, r10mp
+    lea             r10, [srcq+wq*2]
+    lea             r11, [dstq+wq*2]
+    lea             r12, [lumaq+wq*(2<<%2)]
+    mov            r9mp, r10
+    mov           r11mp, r11
+    mov           r12mp, r12
+    neg              wq
+
+%%loop_x:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, unused1, unused2, unused3, luma, lstride
+
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyd, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+(3+(6>>%2))]  ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, unused1, unused2, unused3, luma, lstride
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+%%loop_y:
+    ; luma_src
+%if %2
+    mova            xm2, [lumaq+lstrideq*0+ 0]
+    vinserti128      m2, [lumaq+lstrideq*0+32], 1
+    mova            xm4, [lumaq+lstrideq*0+16]
+    vinserti128      m4, [lumaq+lstrideq*0+48], 1
+    mova            xm3, [lumaq+lstrideq*(1<<%3)+ 0]
+    vinserti128      m3, [lumaq+lstrideq*(1<<%3)+32], 1
+    mova            xm5, [lumaq+lstrideq*(1<<%3)+16]
+    vinserti128      m5, [lumaq+lstrideq*(1<<%3)+48], 1
+    phaddw           m2, m4
+    phaddw           m3, m5
+    pxor             m4, m4
+    pavgw            m2, m4
+    pavgw            m3, m4
+%elif %1
+    mova             m2, [lumaq+ 0]
+    mova             m3, [lumaq+32]
+%endif
+%if %1
+    mova             m0, [srcq]
+%if %2
+    mova             m1, [srcq+strideq]
+%else
+    mova             m1, [srcq+32]
+%endif
+    punpckhwd        m4, m2, m0
+    punpcklwd        m2, m0
+    punpckhwd        m5, m3, m1
+    punpcklwd        m3, m1                 ; { luma, chroma }
+    REPX {pmaddwd x, m14}, m4, m2, m5, m3
+    REPX {paddd   x, m15}, m4, m2, m5, m3
+    REPX {psrad   x, 6  }, m4, m2, m5, m3
+    packusdw         m2, m4
+    packusdw         m3, m5
+    pminuw           m2, m10
+    pminuw           m3, m10                ; clip_pixel()
+%elif %2
+    pand             m2, m10
+    pand             m3, m10
+%else
+    pand             m2, m10, [lumaq+ 0]
+    pand             m3, m10, [lumaq+32]
+%endif
+
+    ; scaling[luma_src]
+    vpbroadcastd     m7, [pd_m65536]
+    pandn            m4, m7, m2
+    mova             m6, m7
+    vpgatherdd       m5, [scalingq+m4-0], m7
+    psrld            m2, 16
+    mova             m7, m6
+    vpgatherdd       m4, [scalingq+m2-2], m6
+    pblendw          m4, m5, 0x55
+    pandn            m5, m7, m3
+    mova             m6, m7
+    vpgatherdd       m2, [scalingq+m5-0], m7
+    psrld            m3, 16
+    vpgatherdd       m5, [scalingq+m3-2], m6
+    pblendw          m5, m2, 0x55
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmaddubsw        m4, m11
+    pmaddubsw        m5, m11
+    paddw            m4, m4
+    paddw            m5, m5
+    pmulhrsw         m4, [grain_lutq+offxyq*2]
+%if %2
+    pmulhrsw         m5, [grain_lutq+offxyq*2+82*2]
+%else
+    pmulhrsw         m5, [grain_lutq+offxyq*2+32]
+%endif
+
+    ; dst = clip_pixel(src, noise)
+%if %1
+    paddw            m0, m4
+    paddw            m1, m5
+%else
+    paddw            m0, m4, [srcq]
+%if %2
+    paddw            m1, m5, [srcq+strideq]
+%else
+    paddw            m1, m5, [srcq+32]
+%endif
+%endif
+    pmaxsw           m0, m12
+    pmaxsw           m1, m12
+    pminsw           m0, m13
+    pminsw           m1, m13
+    mova         [dstq], m0
+%if %2
+    mova [dstq+strideq], m1
+    lea            srcq, [srcq+strideq*2]
+    lea            dstq, [dstq+strideq*2]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+%else
+    mova      [dstq+32], m1
+    add            srcq, strideq
+    add            dstq, strideq
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82*(2<<%2)
+%if %2
+    sub              hb, 2
+%else
+    dec              hb
+%endif
+    jg %%loop_y
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r9mp
+    mov            dstq, r11mp
+    mov           lumaq, r12mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+    cmp byte [fg_dataq+FGData.overlap_flag], 0
+    je %%loop_x
+    cmp       dword r8m, 0 ; sby
+    jne %%loop_x_hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+%%loop_x_h_overlap:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, unused1, unused2, luma, lstride
+
+    lea     left_offxyd, [offyq+(32>>%2)]         ; previous column's offy*stride+offx
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyd, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)]  ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, unused1, unused2, luma, lstride
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+%%loop_y_h_overlap:
+    ; luma_src
+%if %2
+    mova            xm2, [lumaq+lstrideq*0+ 0]
+    vinserti128      m2, [lumaq+lstrideq*0+32], 1
+    mova            xm4, [lumaq+lstrideq*0+16]
+    vinserti128      m4, [lumaq+lstrideq*0+48], 1
+    mova            xm3, [lumaq+lstrideq*(1<<%3)+ 0]
+    vinserti128      m3, [lumaq+lstrideq*(1<<%3)+32], 1
+    mova            xm5, [lumaq+lstrideq*(1<<%3)+16]
+    vinserti128      m5, [lumaq+lstrideq*(1<<%3)+48], 1
+    phaddw           m2, m4
+    phaddw           m3, m5
+    pxor             m4, m4
+    pavgw            m2, m4
+    pavgw            m3, m4
+%elif %1
+    mova             m2, [lumaq]
+    mova             m3, [lumaq+32]
+%endif
+%if %1
+    mova             m0, [srcq]
+%if %2
+    mova             m1, [srcq+strideq]
+%else
+    mova             m1, [srcq+32]
+%endif
+    punpckhwd        m4, m2, m0
+    punpcklwd        m2, m0
+    punpckhwd        m5, m3, m1
+    punpcklwd        m3, m1                 ; { luma, chroma }
+    REPX {pmaddwd x, m14}, m4, m2, m5, m3
+    REPX {paddd   x, m15}, m4, m2, m5, m3
+    REPX {psrad   x, 6  }, m4, m2, m5, m3
+    packusdw         m2, m4
+    packusdw         m3, m5
+    pminuw           m2, m10                ; clip_pixel()
+    pminuw           m3, m10
+%elif %2
+    pand             m2, m10
+    pand             m3, m10
+%else
+    pand             m2, m10, [lumaq+ 0]
+    pand             m3, m10, [lumaq+32]
+%endif
+
+    ; scaling[luma_src]
+    vpbroadcastd     m7, [pd_m65536]
+    pandn            m4, m7, m2
+    mova             m6, m7
+    vpgatherdd       m5, [scalingq+m4-0], m7
+    psrld            m2, 16
+    mova             m7, m6
+    vpgatherdd       m4, [scalingq+m2-2], m6
+    pblendw          m4, m5, 0x55
+    pandn            m5, m7, m3
+    mova             m6, m7
+    vpgatherdd       m2, [scalingq+m5-0], m7
+    psrld            m3, 16
+    vpgatherdd       m5, [scalingq+m3-2], m6
+    pblendw          m5, m2, 0x55
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m2, [grain_lutq+offxyq*2]
+%if %2
+    movu             m3, [grain_lutq+offxyq*2+82*2]
+%else
+    movu             m3, [grain_lutq+offxyq*2+32]
+%endif
+    movd            xm6, [grain_lutq+left_offxyq*2]
+%if %2
+    pinsrw          xm6, [grain_lutq+left_offxyq*2+82*2], 2 ; {left0, left1}
+    punpckldq       xm7, xm2, xm3           ; {cur0, cur1}
+    punpcklwd       xm6, xm7                ; {left0, cur0, left1, cur1}
+%else
+    punpcklwd       xm6, xm2
+%endif
+%if %1
+%if %2
+    vpbroadcastq    xm7, [pw_23_22]
+%else
+    movq            xm7, [pw_27_17_17_27]
+%endif
+    pmaddwd         xm6, xm7
+    vpbroadcastd    xm7, [pd_16]
+    paddd           xm6, xm7
+%else
+    pmaddwd         xm6, xm15
+    paddd           xm6, xm14
+%endif
+    psrad           xm6, 5
+    packssdw        xm6, xm6
+    pmaxsw          xm6, xm8
+    pminsw          xm6, xm9
+    vpblendd         m2, m6, 0x01
+%if %2
+    pshuflw         xm6, xm6, q1032
+    vpblendd         m3, m6, 0x01
+%endif
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmaddubsw        m4, m11
+    pmaddubsw        m5, m11
+    paddw            m4, m4
+    paddw            m5, m5
+    pmulhrsw         m2, m4
+    pmulhrsw         m3, m5
+
+    ; dst = clip_pixel(src, noise)
+%if %1
+    paddw            m0, m2
+    paddw            m1, m3
+%else
+    paddw            m0, m2, [srcq]
+%if %2
+    paddw            m1, m3, [srcq+strideq]
+%else
+    paddw            m1, m3, [srcq+32]
+%endif
+%endif
+    pmaxsw           m0, m12
+    pmaxsw           m1, m12
+    pminsw           m0, m13
+    pminsw           m1, m13
+    mova         [dstq], m0
+%if %2
+    mova [dstq+strideq], m1
+    lea            srcq, [srcq+strideq*2]
+    lea            dstq, [dstq+strideq*2]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+%else
+    mova      [dstq+32], m1
+    add            srcq, strideq
+    add            dstq, strideq
+    add           lumaq, r10mp
+%endif
+    add      grain_lutq, 82*(2<<%2)
+%if %2
+    sub              hb, 2
+%else
+    dec              hb
+%endif
+    jg %%loop_y_h_overlap
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r9mp
+    mov            dstq, r11mp
+    mov           lumaq, r12mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+    cmp       dword r8m, 0 ; sby
+    jne %%loop_x_hv_overlap
+    jmp %%loop_x_h_overlap
+
+%%vertical_overlap:
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused, \
+                sby, see, unused1, unused2, unused3, lstride
+
+    movzx          sbyd, sbyb
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+    imul            r7d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             r7d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             r7d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, r7d
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, unused1, top_offxy, unused2, luma, lstride
+
+    mov           lumaq, r9mp
+    mov        lstrideq, r10mp
+    lea             r10, [srcq+wq*2]
+    lea             r11, [dstq+wq*2]
+    lea             r12, [lumaq+wq*(2<<%2)]
+    mov            r9mp, r10
+    mov           r11mp, r11
+    mov           r12mp, r12
+    neg              wq
+
+%%loop_x_v_overlap:
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, unused1, top_offxy, unused2, luma, lstride
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+%if %2 == 0
+    lea             r10, [pw_27_17_17_27]
+%endif
+%%loop_y_v_overlap:
+    ; luma_src
+%if %2
+    mova            xm2, [lumaq+lstrideq*0+ 0]
+    vinserti128      m2, [lumaq+lstrideq*0+32], 1
+    mova            xm4, [lumaq+lstrideq*0+16]
+    vinserti128      m4, [lumaq+lstrideq*0+48], 1
+    mova            xm3, [lumaq+lstrideq*(1<<%3)+ 0]
+    vinserti128      m3, [lumaq+lstrideq*(1<<%3)+32], 1
+    mova            xm5, [lumaq+lstrideq*(1<<%3)+16]
+    vinserti128      m5, [lumaq+lstrideq*(1<<%3)+48], 1
+    phaddw           m2, m4
+    phaddw           m3, m5
+    pxor             m4, m4
+    pavgw            m2, m4
+    pavgw            m3, m4
+%elif %1
+    mova             m2, [lumaq]
+    mova             m3, [lumaq+32]
+%endif
+%if %1
+    mova             m0, [srcq]
+%if %2
+    mova             m1, [srcq+strideq]
+%else
+    mova             m1, [srcq+32]
+%endif
+    punpckhwd        m4, m2, m0
+    punpcklwd        m2, m0
+    punpckhwd        m5, m3, m1
+    punpcklwd        m3, m1                 ; { luma, chroma }
+    REPX {pmaddwd x, m14}, m4, m2, m5, m3
+    REPX {paddd   x, m15}, m4, m2, m5, m3
+    REPX {psrad   x, 6  }, m4, m2, m5, m3
+    packusdw         m2, m4
+    packusdw         m3, m5
+    pminuw           m2, m10                ; clip_pixel()
+    pminuw           m3, m10
+%elif %2
+    pand             m2, m10
+    pand             m3, m10
+%else
+    pand             m2, m10, [lumaq+ 0]
+    pand             m3, m10, [lumaq+32]
+%endif
+
+    ; scaling[luma_src]
+    vpbroadcastd     m7, [pd_m65536]
+    pandn            m4, m7, m2
+    mova             m6, m7
+    vpgatherdd       m5, [scalingq+m4-0], m7
+    psrld            m2, 16
+    mova             m7, m6
+    vpgatherdd       m4, [scalingq+m2-2], m6
+    pblendw          m4, m5, 0x55
+    pandn            m5, m7, m3
+    mova             m6, m7
+    vpgatherdd       m2, [scalingq+m5-0], m7
+    psrld            m3, 16
+    vpgatherdd       m5, [scalingq+m3-2], m6
+    pblendw          m5, m2, 0x55
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m6, [grain_lutq+offxyq*2]
+    movu             m3, [grain_lutq+top_offxyq*2]
+    punpcklwd        m2, m3, m6
+    punpckhwd        m3, m6                 ; { top, cur }
+%if %3
+    vpbroadcastd     m0, [pw_23_22]
+%elif %2
+    vpbroadcastd     m0, [pw_27_17_17_27]
+%else
+    vpbroadcastd     m0, [r10]
+%endif
+    REPX {pmaddwd x, m0}, m2, m3
+%if %1
+    vpbroadcastd     m1, [pd_16]
+    REPX  {paddd x, m1}, m2, m3
+%else
+    REPX {paddd x, m14}, m2, m3
+%endif
+    REPX   {psrad x, 5}, m2, m3
+    packssdw         m2, m3
+%if %2
+    movu             m3, [grain_lutq+offxyq*2+82*2]
+%else
+    movu             m3, [grain_lutq+offxyq*2+32]
+%endif
+%if %3
+    pmaxsw           m2, m8
+    pminsw           m2, m9
+%else
+%if %2
+    movu             m7, [grain_lutq+top_offxyq*2+82*2]
+    punpckhwd        m6, m3, m7             ; { cur, top }
+    punpcklwd        m3, m7
+%else
+    movu             m7, [grain_lutq+top_offxyq*2+32]
+    punpckhwd        m6, m7, m3
+    punpcklwd        m3, m7, m3             ; { top, cur }
+%endif
+    pmaddwd          m6, m0
+    pmaddwd          m3, m0
+%if %1
+    paddd            m6, m1
+    paddd            m3, m1
+%else
+    paddd            m6, m14
+    paddd            m3, m14
+%endif
+    psrad            m6, 5
+    psrad            m3, 5
+    packssdw         m3, m6
+    pmaxsw           m2, m8
+    pmaxsw           m3, m8
+    pminsw           m2, m9
+    pminsw           m3, m9
+%endif
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmaddubsw        m4, m11
+    pmaddubsw        m5, m11
+    paddw            m4, m4
+    paddw            m5, m5
+    pmulhrsw         m2, m4
+    pmulhrsw         m3, m5
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2, [srcq]
+%if %2
+    paddw            m1, m3, [srcq+strideq]
+%else
+    paddw            m1, m3, [srcq+32]
+%endif
+    pmaxsw           m0, m12
+    pmaxsw           m1, m12
+    pminsw           m0, m13
+    pminsw           m1, m13
+    mova         [dstq], m0
+%if %2
+    mova [dstq+strideq], m1
+    sub              hb, 2
+%else
+    mova      [dstq+32], m1
+    dec              hb
+%endif
+    jle %%end_y_v_overlap
+%if %2
+    lea            srcq, [srcq+strideq*2]
+    lea            dstq, [dstq+strideq*2]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+%else
+    add            srcq, strideq
+    add            dstq, strideq
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82*(2<<%2)
+%if %2
+    jmp %%loop_y
+%else
+    add              hd, 0x80000000
+    jc %%loop_y
+    add             r10, 4
+    jmp %%loop_y_v_overlap
+%endif
+%%end_y_v_overlap:
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r9mp
+    mov            dstq, r11mp
+    mov           lumaq, r12mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump
+    ; back to .loop_x_v_overlap, and instead always fall-through to
+    ; h+v overlap
+%%loop_x_hv_overlap:
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, top_offxy, topleft_offxy, luma, lstride
+
+%if %2 == 0
+    lea             r14, [pw_27_17_17_27]
+%endif
+    lea  topleft_offxyq, [top_offxyq+(32>>%2)]
+    lea     left_offxyq, [offyq+(32>>%2)]
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, top_offxy, topleft_offxy, luma, lstride
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+%%loop_y_hv_overlap:
+    ; luma_src
+%if %2
+    mova            xm2, [lumaq+lstrideq*0+ 0]
+    vinserti128      m2, [lumaq+lstrideq*0+32], 1
+    mova            xm4, [lumaq+lstrideq*0+16]
+    vinserti128      m4, [lumaq+lstrideq*0+48], 1
+    mova            xm3, [lumaq+lstrideq*(1<<%3)+ 0]
+    vinserti128      m3, [lumaq+lstrideq*(1<<%3)+32], 1
+    mova            xm5, [lumaq+lstrideq*(1<<%3)+16]
+    vinserti128      m5, [lumaq+lstrideq*(1<<%3)+48], 1
+    phaddw           m2, m4
+    phaddw           m3, m5
+    pxor             m4, m4
+    pavgw            m2, m4
+    pavgw            m3, m4
+%elif %1
+    mova             m2, [lumaq]
+    mova             m3, [lumaq+32]
+%endif
+%if %1
+    mova             m0, [srcq]
+%if %2
+    mova             m1, [srcq+strideq]
+%else
+    mova             m1, [srcq+32]
+%endif
+    punpckhwd        m4, m2, m0
+    punpcklwd        m2, m0
+    punpckhwd        m5, m3, m1
+    punpcklwd        m3, m1                 ; { luma, chroma }
+    REPX {pmaddwd x, m14}, m4, m2, m5, m3
+    REPX {paddd   x, m15}, m4, m2, m5, m3
+    REPX {psrad   x, 6  }, m4, m2, m5, m3
+    packusdw         m2, m4
+    packusdw         m3, m5
+    pminuw           m2, m10                ; clip_pixel()
+    pminuw           m3, m10
+%elif %2
+    pand             m2, m10
+    pand             m3, m10
+%else
+    pand             m2, m10, [lumaq+ 0]
+    pand             m3, m10, [lumaq+32]
+%endif
+
+    ; scaling[luma_src]
+    vpbroadcastd     m7, [pd_m65536]
+    pandn            m4, m7, m2
+    mova             m6, m7
+    vpgatherdd       m5, [scalingq+m4-0], m7
+    psrld            m2, 16
+    mova             m7, m6
+    vpgatherdd       m4, [scalingq+m2-2], m6
+    pblendw          m4, m5, 0x55
+    pandn            m5, m7, m3
+    mova             m6, m7
+    vpgatherdd       m2, [scalingq+m5-0], m7
+    psrld            m3, 16
+    vpgatherdd       m5, [scalingq+m3-2], m6
+    pblendw          m5, m2, 0x55
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m0, [grain_lutq+offxyq*2]
+    movd            xm2, [grain_lutq+left_offxyq*2]
+    movu             m6, [grain_lutq+top_offxyq*2]
+%if %2
+    pinsrw          xm2, [grain_lutq+left_offxyq*2+82*2], 2
+    movu             m3, [grain_lutq+offxyq*2+82*2]
+    punpckldq       xm1, xm0, xm3           ; { cur0, cur1 }
+%if %3
+    vinserti128      m2, [grain_lutq+topleft_offxyq*2], 1 ; { left0, left1, top/left }
+    vinserti128      m1, [grain_lutq+top_offxyq*2], 1     ; { cur0, cur1, top0 }
+%else
+    vinserti128      m2, [grain_lutq+topleft_offxyq*2+82*2], 1
+    vpbroadcastd     m7, [grain_lutq+topleft_offxyq*2]
+    vpblendd         m2, m7, 0x20
+    movd            xm7, [grain_lutq+top_offxyq*2+82*2]
+    punpckldq       xm7, xm6
+    vinserti128      m1, xm7, 1
+    movu             m7, [grain_lutq+top_offxyq*2+82*2]
+%endif
+    punpcklwd        m2, m1                 ; { cur, left }
+%if %1
+    vpbroadcastq     m1, [pw_23_22]
+    pmaddwd          m2, m1
+    vpbroadcastd     m1, [pd_16]
+    paddd            m2, m1
+    psrad            m2, 5
+    packssdw         m2, m2
+    vpermq           m2, m2, q3120
+%else
+    pmaddwd          m2, m15
+    paddd            m2, m14
+    psrad            m2, 5
+    vextracti128    xm1, m2, 1
+    packssdw        xm2, xm1
+%endif
+%else
+    pinsrd          xm2, [grain_lutq+topleft_offxyq*2], 1
+    movu             m3, [grain_lutq+offxyq*2+32]
+    movu             m7, [grain_lutq+top_offxyq*2+32]
+    punpckldq       xm1, xm0, xm6
+    punpcklwd       xm2, xm1                ; { cur, left }
+%if %1
+    movddup         xm1, [pw_27_17_17_27]
+    pmaddwd         xm2, xm1
+    vpbroadcastd     m1, [pd_16]
+    paddd           xm2, xm1
+%else
+    pmaddwd         xm2, xm15
+    paddd           xm2, xm14
+%endif
+    psrad           xm2, 5
+    packssdw        xm2, xm2
+%endif
+    pmaxsw          xm2, xm8
+    pminsw          xm2, xm9
+    vpblendd         m0, m2, 0x01
+%if %2
+    pshufd          xm2, xm2, q0321
+    vpblendd         m3, m2, 0x01
+%if %3 == 0
+    pshufd          xm2, xm2, q0321
+    vpblendd         m7, m2, 0x01
+%endif
+%endif
+    pshuflw         xm2, xm2, q1032
+    vpblendd         m2, m6, 0xfe
+    punpckhwd        m6, m0                 ; { top, cur }
+    punpcklwd        m2, m0
+%if %3
+    vpbroadcastd     m0, [pw_23_22]
+%elif %2
+    vpbroadcastd     m0, [pw_27_17_17_27]
+%else
+    vpbroadcastd     m0, [r14]
+%endif
+    pmaddwd          m6, m0
+    pmaddwd          m2, m0
+%if %1
+    paddd            m6, m1
+    paddd            m2, m1
+%else
+    paddd            m6, m14
+    paddd            m2, m14
+%endif
+    psrad            m6, 5
+    psrad            m2, 5
+    packssdw         m2, m6
+
+%if %3
+    pmaxsw           m2, m8
+    pminsw           m2, m9
+%else
+%if %2
+    punpckhwd        m6, m3, m7
+    punpcklwd        m3, m7                 ; { cur, top }
+%else
+    punpckhwd        m6, m7, m3
+    punpcklwd        m3, m7, m3             ; { top, cur }
+%endif
+    REPX {pmaddwd x, m0}, m6, m3
+%if %1
+    REPX  {paddd x, m1}, m6, m3
+%else
+    REPX {paddd x, m14}, m6, m3
+%endif
+    REPX   {psrad x, 5}, m6, m3
+    packssdw         m3, m6
+    pmaxsw           m2, m8
+    pmaxsw           m3, m8
+    pminsw           m2, m9
+    pminsw           m3, m9
+%endif
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmaddubsw        m4, m11
+    pmaddubsw        m5, m11
+    paddw            m4, m4
+    paddw            m5, m5
+    pmulhrsw         m2, m4
+    pmulhrsw         m3, m5
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2, [srcq]
+%if %2
+    paddw            m1, m3, [srcq+strideq]
+%else
+    paddw            m1, m3, [srcq+32]
+%endif
+    pmaxsw           m0, m12
+    pmaxsw           m1, m12
+    pminsw           m0, m13
+    pminsw           m1, m13
+    mova         [dstq], m0
+%if %2
+    mova [dstq+strideq], m1
+    lea            srcq, [srcq+strideq*2]
+    lea            dstq, [dstq+strideq*2]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+%else
+    mova      [dstq+32], m1
+    add            srcq, strideq
+    add            dstq, strideq
+    add           lumaq, r10mp
+%endif
+    add      grain_lutq, 82*(2<<%2)
+%if %2
+    sub              hb, 2
+    jg %%loop_y_h_overlap
+%else
+    dec              hb
+    jle %%end_y_hv_overlap
+    add              hd, 0x80000000
+    jc %%loop_y_h_overlap
+    add             r14, 4
+    jmp %%loop_y_hv_overlap
+%endif
+%%end_y_hv_overlap:
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r9mp
+    mov            dstq, r11mp
+    mov           lumaq, r12mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+    jmp %%loop_x_hv_overlap
+%endmacro
+
+    %%FGUV_32x32xN_LOOP 1, %2, %3
+.csfl:
+    %%FGUV_32x32xN_LOOP 0, %2, %3
+.end:
+    RET
+%endmacro
+
+GEN_GRAIN_UV_FN 420, 1, 1
+FGUV_FN 420,         1, 1
+GEN_GRAIN_UV_FN 422, 1, 0
+FGUV_FN 422,         1, 0
+GEN_GRAIN_UV_FN 444, 0, 0
+FGUV_FN 444,         0, 0
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/filmgrain16_avx512.asm b/media/libdav1d/src/src/x86/filmgrain16_avx512.asm
new file mode 100644
index 0000000000..d6d7ac2c47
--- /dev/null
+++ b/media/libdav1d/src/src/x86/filmgrain16_avx512.asm
@@ -0,0 +1,930 @@
+; Copyright © 2022, VideoLAN and dav1d authors
+; Copyright © 2022, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+%include "x86/filmgrain_common.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 16
+scale_mask:    db -1, -1,  0, -1, -1, -1,  4, -1, -1, -1,  8, -1, -1, -1, 12, -1
+scale_shift:           dw   7,   7,   6,   6,   5,   5,   4,   4
+pw_27_17_17_27:        dw 108,  68,  68, 108,  27,  17,  17,  27
+pw_23_22:              dw  92,  88,   0, 128,  23,  22,   0,  32
+fg_min:        times 2 dw 0
+               times 2 dw 64
+               times 2 dw 256
+fg_max:        times 2 dw 1023
+               times 2 dw 4095
+               times 2 dw 960
+               times 2 dw 3840
+               times 2 dw 940
+               times 2 dw 3760
+scale_rnd:             dd 64
+                       dd 16
+uv_offset_mul:         dd 256
+                       dd 1024
+pb_8_9_0_1:            db 8, 9, 0, 1
+
+cextern pb_0to63
+
+SECTION .text
+
+INIT_ZMM avx512icl
+cglobal fgy_32x32xn_16bpc, 6, 15, 21, dst, src, stride, fg_data, w, scaling, \
+                                      grain_lut, offx, sby, see, offy, src_bak
+%define base r11-fg_min
+    lea             r11, [fg_min]
+    mov             r6d, r9m    ; bdmax
+    mov             r9d, [fg_dataq+FGData.clip_to_restricted_range]
+    mov             r7d, [fg_dataq+FGData.scaling_shift]
+    mov            sbyd, sbym
+    vpbroadcastd     m6, r9m
+    shr             r6d, 11     ; is_12bpc
+    vbroadcasti32x4  m7, [base+scale_mask]
+    shlx           r10d, r9d, r6d
+    vpbroadcastd    m10, [base+scale_shift+r7*4-32]
+    lea             r9d, [r6+r9*4]
+    vpbroadcastd     m8, [base+fg_min+r10*4]
+    kxnorw           k1, k1, k1 ; 0xffff
+    vpbroadcastd     m9, [base+fg_max+r9*4]
+    mov             r12, 0xeeeeeeeeeeeeeeee
+    vpbroadcastd    m19, [base+scale_rnd+r6*4]
+    kshiftrb         k2, k1, 4  ; 0xf
+    vpbroadcastq   xm20, [base+pw_27_17_17_27+r6*8]
+    kmovq            k3, r12
+    vpbroadcastd    m11, [base+scale_shift+r6*8+4]
+    test           sbyd, sbyd
+    setnz           r7b
+    vpbroadcastd    m12, [base+pw_27_17_17_27+r6*8+0]
+    vpbroadcastd    m13, [base+pw_27_17_17_27+r6*8+4]
+    test            [fg_dataq+FGData.overlap_flag], r7b
+    jnz .v_overlap
+
+    imul           seed, sbyd, (173 << 24) | 37
+    add            seed, (105 << 24) | 178
+    rorx           seed, seed, 24
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+    lea        src_bakq, [srcq+wq*2]
+    neg              wq
+    sub            dstq, srcq
+
+.loop_x:
+    rorx             r6, seeq, 1
+    or             seed, 0xeff4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                 ; updated seed
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyd, [offyq+offxq*2+747] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, h, \
+                sby, see, offxy, src_bak
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+.loop_y:
+    movu             m4, [grain_lutq+offxyq*2+82*0]
+    movu             m5, [grain_lutq+offxyq*2+82*2]
+    call .add_noise
+    sub              hb, 2
+    jg .loop_y
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq*2]
+    cmp byte [fg_dataq+FGData.overlap_flag], 0
+    je .loop_x
+    test           sbyd, sbyd
+    jnz .hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+.loop_x_h_overlap:
+    rorx             r6, seeq, 1
+    or             seed, 0xeff4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                 ; updated seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, offx, \
+                sby, see, offy, src_bak, left_offxy
+
+    lea     left_offxyd, [offyq+73]          ; previous column's offy*stride+offx
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyd, [offyq+offxq*2+747] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, h, \
+                sby, see, offxy, src_bak, left_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+.loop_y_h_overlap:
+    movu             m4, [grain_lutq+offxyq*2+82*0]
+    movu             m5, [grain_lutq+offxyq*2+82*2]
+    movd           xm17, [grain_lutq+left_offxyq*2-82*1]
+    pinsrd         xm17, [grain_lutq+left_offxyq*2+82*1], 1
+    punpckldq      xm16, xm4, xm5
+    punpcklwd      xm17, xm16
+    mova           xm16, xm19
+    vpdpwssd       xm16, xm20, xm17
+    psrad          xm16, 1
+    packssdw       xm16, xm16
+    vpsravw        xm16, xm11
+    vmovdqu8     m4{k2}, m16
+    vpalignr     m5{k2}, m16, m16, 4
+    call .add_noise
+    sub              hb, 2
+    jg .loop_y_h_overlap
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq*2]
+    test           sbyd, sbyd
+    jnz .hv_overlap
+    jmp .loop_x_h_overlap
+
+.v_overlap:
+    movzx          sbyd, sbyb
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+    imul            r7d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             r7d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             r7d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, r7d
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+    lea        src_bakq, [srcq+wq*2]
+    neg              wq
+    sub            dstq, srcq
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, offx, \
+                sby, see, offy, src_bak, _, top_offxy
+
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*2+0x10001*747+32*82]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, h, \
+                sby, see, offxy, src_bak, _, top_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+
+    movu            m16, [grain_lutq+offxyq*2+82*0]
+    movu             m0, [grain_lutq+top_offxyq*2+82*0]
+    movu            m17, [grain_lutq+offxyq*2+82*2]
+    movu             m1, [grain_lutq+top_offxyq*2+82*2]
+    punpckhwd        m4, m0, m16
+    punpcklwd        m0, m16
+    punpckhwd        m5, m1, m17
+    punpcklwd        m1, m17
+    call .add_noise_v
+    sub              hb, 2
+    jg .loop_y
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq*2]
+
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump back
+    ; to .v_overlap, and instead always fall-through to .hv_overlap
+.hv_overlap:
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, offx, \
+                sby, see, offy, src_bak, left_offxy, top_offxy, topleft_offxy
+
+    lea  topleft_offxyd, [top_offxyq+73]
+    lea     left_offxyd, [offyq+73]
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*2+0x10001*747+32*82]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, h, \
+                sby, see, offxy, src_bak, left_offxy, top_offxy, topleft_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+
+    movu             m5, [grain_lutq+offxyq*2+82*0]
+    movu             m0, [grain_lutq+top_offxyq*2+82*0]
+    movd           xm17, [grain_lutq+left_offxyq*2-82*1]
+    pinsrd         xm17, [grain_lutq+topleft_offxyq*2-82*1], 1
+    movu             m2, [grain_lutq+offxyq*2+82*2]
+    movu             m1, [grain_lutq+top_offxyq*2+82*2]
+    movd           xm18, [grain_lutq+left_offxyq*2+82*1]
+    pinsrd         xm18, [grain_lutq+topleft_offxyq*2+82*1], 1
+    punpckldq      xm16, xm5, xm0
+    punpcklwd      xm17, xm16
+    mova           xm16, xm19
+    vpdpwssd       xm16, xm20, xm17
+    punpckldq      xm17, xm2, xm1
+    punpcklwd      xm18, xm17
+    mova           xm17, xm19
+    vpdpwssd       xm17, xm20, xm18
+    punpckhwd        m4, m0, m5
+    punpcklwd        m0, m5
+    punpckhwd        m5, m1, m2
+    punpcklwd        m1, m2
+    psrad          xm16, 1
+    psrad          xm17, 1
+    packssdw       xm16, xm17
+    vpsravw        xm16, xm11
+    vpshuflw     m0{k2}, m16, q1302
+    punpckhqdq     xm16, xm16
+    vpshuflw     m1{k2}, m16, q1302
+    call .add_noise_v
+    sub              hb, 2
+    jg .loop_y_h_overlap
+    add              wq, 32
+    lea            srcq, [src_bakq+wq*2]
+    jl .hv_overlap
+.end:
+    RET
+ALIGN function_align
+.add_noise_v:
+    mova             m2, m19
+    vpdpwssd         m2, m12, m4
+    mova             m3, m19
+    vpdpwssd         m3, m13, m5
+    mova             m4, m19
+    vpdpwssd         m4, m12, m0
+    mova             m5, m19
+    vpdpwssd         m5, m13, m1
+    REPX   {psrad x, 1}, m2, m3, m4, m5
+    packssdw         m4, m2
+    packssdw         m5, m3
+    vpsravw          m4, m11
+    vpsravw          m5, m11
+.add_noise:
+    mova             m0, [srcq+strideq*0]
+    mova             m1, [srcq+strideq*1]
+    kmovw            k4, k1
+    pand            m16, m6, m0
+    psrld            m3, m0, 16
+    vpgatherdd   m2{k4}, [scalingq+m16]
+    vpcmpud          k4, m3, m6, 2 ; px <= bdmax
+    vpgatherdd  m16{k4}, [scalingq+m3]
+    kmovw            k4, k1
+    pand            m17, m6, m1
+    vpgatherdd   m3{k4}, [scalingq+m17]
+    vpshufb      m2{k3}, m16, m7
+    psrld           m16, m1, 16
+    vpcmpud          k4, m16, m6, 2
+    vpgatherdd  m17{k4}, [scalingq+m16]
+    vpshufb      m3{k3}, m17, m7
+    vpsllvw          m2, m10
+    vpsllvw          m3, m10
+    pmulhrsw         m4, m2
+    pmulhrsw         m5, m3
+    add      grain_lutq, 82*4
+    paddw            m0, m4
+    paddw            m1, m5
+    pmaxsw           m0, m8
+    pmaxsw           m1, m8
+    pminsw           m0, m9
+    pminsw           m1, m9
+    mova    [dstq+srcq], m0
+    add            srcq, strideq
+    mova    [dstq+srcq], m1
+    add            srcq, strideq
+    ret
+
+%macro FGUV_FN 3 ; name, ss_hor, ss_ver
+cglobal fguv_32x32xn_i%1_16bpc, 6, 15, 22, dst, src, stride, fg_data, w, scaling, \
+                                           grain_lut, h, sby, luma, lstride, uv_pl, is_id
+%define base r12-fg_min
+    lea             r12, [fg_min]
+    mov             r9d, r13m            ; bdmax
+    mov             r7d, [fg_dataq+FGData.scaling_shift]
+    mov             r6d, [fg_dataq+FGData.clip_to_restricted_range]
+    mov            r11d, is_idm
+    kxnorw           k1, k1, k1          ; 0xffff
+    vpbroadcastd     m5, r13m
+    mov             r13, 0xeeeeeeeeeeeeeeee
+    vbroadcasti32x4  m6, [base+scale_mask]
+    shr             r9d, 11              ; is_12bpc
+    vpbroadcastd     m7, [base+scale_shift+r7*4-32]
+    shlx           r10d, r6d, r9d
+    mov            sbyd, sbym
+    shlx            r6d, r6d, r11d
+    vpbroadcastd     m8, [base+fg_min+r10*4]
+    lea             r6d, [r9+r6*2]
+    vpbroadcastd     m9, [base+fg_max+r6*4]
+    kmovq            k2, r13
+    vpbroadcastd    m20, [base+scale_rnd+r9*4]
+    packssdw         m4, m5, m5
+    vpbroadcastd    m21, [base+scale_shift+r9*8+4]
+%if %2
+    mova            m12, [pb_0to63] ; pw_even
+    mov            r13d, 0x0101
+    vpbroadcastq    m10, [base+pw_23_22+r9*8]
+    kmovw            k3, r13d
+%if %3
+    pshufd          m11, m10, q0000
+%else
+    vpbroadcastd   ym16, [base+pw_27_17_17_27+r9*8+0]
+    vpbroadcastd    m11, [base+pw_27_17_17_27+r9*8+4]
+    vmovdqu16   m11{k1}, m16
+%endif
+    psrlw           m13, m12, 8          ; pw_odd
+%else
+    vpbroadcastq    m10, [base+pw_27_17_17_27+r9*8]
+    kshiftrb         k3, k1, 7           ; 0x01
+    kshiftrb         k4, k1, 4           ; 0x0f
+    pshufd          m11, m10, q0000
+%endif
+    mov        lstrideq, r10mp
+    test           sbyd, sbyd
+    setnz           r7b
+    cmp byte [fg_dataq+FGData.chroma_scaling_from_luma], 0
+    jne .csfl
+
+%macro %%FGUV_32x32xN_LOOP 3 ; not-csfl, ss_hor, ss_ver
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                _, sby, see, lstride
+
+%if %1
+    mov             r6d, r11m
+    vpbroadcastd     m0, [base+uv_offset_mul+r9*4]
+    vpbroadcastd     m1, [base+pb_8_9_0_1]
+    vpbroadcastd    m14, [fg_dataq+FGData.uv_offset+r6*4]
+    vbroadcasti32x4 m15, [fg_dataq+FGData.uv_mult+r6*4]
+    pmaddwd         m14, m0
+    pshufb          m15, m1 ; { uv_luma_mult, uv_mult }
+%endif
+    test            [fg_dataq+FGData.overlap_flag], r7b
+    jnz %%v_overlap
+
+    imul           seed, sbyd, (173 << 24) | 37
+    add            seed, (105 << 24) | 178
+    rorx           seed, seed, 24
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, lstride, luma
+
+    mov           lumaq, r9mp
+    lea             r12, [srcq+wq*2]
+    lea             r13, [dstq+wq*2]
+    lea             r14, [lumaq+wq*(2<<%2)]
+    mov            r9mp, r12
+    mov           r10mp, r13
+    mov           r11mp, r14
+    neg              wq
+
+%%loop_x:
+    rorx             r6, seeq, 1
+    or             seed, 0xeff4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyd, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+(3+(6>>%2))] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, lstride, luma
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+%%loop_y:
+%if %2
+    movu           ym18, [grain_lutq+offxyq*2+82*0]
+    vinserti32x8    m18, [grain_lutq+offxyq*2+82*2], 1
+    movu           ym19, [grain_lutq+offxyq*2+82*4]
+    vinserti32x8    m19, [grain_lutq+offxyq*2+82*6], 1
+%else
+    movu            m18, [grain_lutq+offxyq*2+82*0]
+    movu            m19, [grain_lutq+offxyq*2+82*2]
+%endif
+    call %%add_noise
+    sub              hb, 2<<%2
+    jg %%loop_y
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r9mp
+    mov            dstq, r10mp
+    mov           lumaq, r11mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+    cmp byte [fg_dataq+FGData.overlap_flag], 0
+    je %%loop_x
+    cmp       dword r8m, 0 ; sby
+    jne %%hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+%%loop_x_h_overlap:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, lstride, luma, left_offxy
+
+    lea     left_offxyd, [offyq+(32>>%2)]  ; previous column's offy*stride+offx
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyd, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, lstride, luma, left_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+%%loop_y_h_overlap:
+%if %2
+    movu           ym18, [grain_lutq+offxyq*2+82*0]
+    vinserti32x8    m18, [grain_lutq+offxyq*2+82*2], 1
+    movu           ym19, [grain_lutq+offxyq*2+82*4]
+    vinserti32x8    m19, [grain_lutq+offxyq*2+82*6], 1
+    movd           xm16, [grain_lutq+left_offxyq*2+82*0]
+    vinserti32x4    m16, [grain_lutq+left_offxyq*2+82*2], 2
+    movd           xm17, [grain_lutq+left_offxyq*2+82*4]
+    vinserti32x4    m17, [grain_lutq+left_offxyq*2+82*6], 2
+    punpckldq       m16, m17
+    punpckldq       m17, m18, m19
+    punpcklwd       m16, m17
+    mova            m17, m20
+    vpdpwssd        m17, m16, m10
+    psrad           m17, 1
+    packssdw        m17, m17
+    vpsravw         m17, m21
+%else
+    movu            m18, [grain_lutq+offxyq*2+82*0]
+    movu            m19, [grain_lutq+offxyq*2+82*2]
+    movd           xm16, [grain_lutq+left_offxyq*2+82*0]
+    pinsrd         xm16, [grain_lutq+left_offxyq*2+82*2], 1
+    punpckldq      xm17, xm18, xm19
+    punpcklwd      xm16, xm17
+    mova           xm17, xm20
+    vpdpwssd       xm17, xm16, xm10
+    psrad          xm17, 1
+    packssdw       xm17, xm17
+    vpsravw        xm17, xm21
+%endif
+    vmovdqa32   m18{k3}, m17
+    vpshufd     m19{k3}, m17, q0321
+    call %%add_noise
+    sub              hb, 2<<%2
+    jg %%loop_y_h_overlap
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r9mp
+    mov            dstq, r10mp
+    mov           lumaq, r11mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+    cmp       dword r8m, 0 ; sby
+    jne %%hv_overlap
+    jmp %%loop_x_h_overlap
+
+%%v_overlap:
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                _, sby, see, lstride
+
+    movzx          sbyd, sbyb
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+    imul            r7d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             r7d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             r7d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, r7d
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, lstride, luma, _, top_offxy
+
+    mov           lumaq, r9mp
+    lea             r12, [srcq+wq*2]
+    lea             r13, [dstq+wq*2]
+    lea             r14, [lumaq+wq*(2<<%2)]
+    mov            r9mp, r12
+    mov           r10mp, r13
+    mov           r11mp, r14
+    neg              wq
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, lstride, luma, _, top_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+
+%if %3
+    movu           ym16, [grain_lutq+offxyq*2+82*0]
+    movu            ym1, [grain_lutq+top_offxyq*2+82*0]
+    vbroadcasti32x8 m18, [grain_lutq+offxyq*2+82*2]
+    movu           ym19, [grain_lutq+offxyq*2+82*4]
+    vinserti32x8    m19, [grain_lutq+offxyq*2+82*6], 1
+    punpcklwd      ym17, ym1, ym16
+    punpckhwd       ym1, ym16
+%elif %2
+    movu           ym18, [grain_lutq+offxyq*2+82*0]
+    vinserti32x8    m18, [grain_lutq+offxyq*2+82*2], 1
+    movu           ym17, [grain_lutq+top_offxyq*2+82*0]
+    vinserti32x8    m17, [grain_lutq+top_offxyq*2+82*2], 1
+    movu           ym19, [grain_lutq+offxyq*2+82*4]
+    vinserti32x8    m19, [grain_lutq+offxyq*2+82*6], 1
+    punpcklwd       m16, m17, m18
+    punpckhwd       m17, m18
+%else
+    movu            m18, [grain_lutq+offxyq*2+82*0]
+    movu            m19, [grain_lutq+top_offxyq*2+82*0]
+    movu             m2, [grain_lutq+offxyq*2+82*2]
+    movu            m16, [grain_lutq+top_offxyq*2+82*2]
+    punpckhwd        m1, m19, m18
+    punpcklwd       m19, m18
+    punpckhwd       m18, m2, m16
+    punpcklwd        m2, m16
+%endif
+    call %%add_noise_v
+    sub              hb, 2<<%2
+    jg %%loop_y
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r9mp
+    mov            dstq, r10mp
+    mov           lumaq, r11mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump back
+    ; to %%v_overlap, and instead always fall-through to %%hv_overlap
+%%hv_overlap:
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, lstride, luma, left_offxy, top_offxy, topleft_offxy
+
+    lea  topleft_offxyq, [top_offxyq+(32>>%2)]
+    lea     left_offxyq, [offyq+(32>>%2)]
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, lstride, luma, left_offxy, top_offxy, topleft_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+
+    ; grain = grain_lut[offy+y][offx+x]
+%if %2
+    movd           xm16, [grain_lutq+left_offxyq*2+82*0]
+    vinserti32x4    m16, [grain_lutq+left_offxyq*2+82*2], 2
+    movd           xm17, [grain_lutq+left_offxyq*2+82*4]
+    vinserti32x4    m17, [grain_lutq+left_offxyq*2+82*6], 2
+    movu           ym18, [grain_lutq+offxyq*2+82*0]
+    vinserti32x8    m18, [grain_lutq+offxyq*2+82*2], 1
+    movu           ym19, [grain_lutq+offxyq*2+82*4]
+    vinserti32x8    m19, [grain_lutq+offxyq*2+82*6], 1
+    punpckldq       m16, m17
+    punpckldq       m17, m18, m19
+    punpcklwd       m16, m17
+    movu            ym1, [grain_lutq+top_offxyq*2+82*0]
+    movd           xm17, [grain_lutq+topleft_offxyq*2+82*0]
+    mova             m0, m20
+    vpdpwssd         m0, m16, m10
+%if %3
+    punpcklwd      xm17, xm1
+    mova           xm16, xm20
+    vpdpwssd       xm16, xm17, xm10
+    psrad          xm16, 1
+%else
+    vinserti32x8     m1, [grain_lutq+top_offxyq*2+82*2], 1
+    vinserti32x4    m17, [grain_lutq+topleft_offxyq*2+82*2], 2
+    punpcklwd       m17, m1
+    mova            m16, m20
+    vpdpwssd        m16, m17, m10
+    psrad           m16, 1
+%endif
+    psrad            m0, 1
+    packssdw         m0, m16
+    vpsravw          m0, m21
+    vmovdqa32   m18{k3}, m0
+    vpshufd     m19{k3}, m0, q0321
+%if %3
+    vpunpckhdq  ym1{k3}, ym0, ym0
+    punpcklwd      ym17, ym1, ym18
+    punpckhwd       ym1, ym18
+%else
+    vpunpckhdq   m1{k3}, m0, m0
+    punpcklwd       m16, m1, m18
+    punpckhwd       m17, m1, m18
+%endif
+%else
+    movu            m18, [grain_lutq+offxyq*2+82*0]
+    movu            m19, [grain_lutq+top_offxyq*2+82*0]
+    movd           xm17, [grain_lutq+left_offxyq*2+82*0]
+    pinsrd         xm17, [grain_lutq+topleft_offxyq*2+82*0], 1
+    punpckldq      xm16, xm18, xm19
+    punpcklwd      xm17, xm16
+    movu             m2, [grain_lutq+offxyq*2+82*2]
+    movu             m0, [grain_lutq+top_offxyq*2+82*2]
+    movd           xm16, [grain_lutq+left_offxyq*2+82*2]
+    pinsrd         xm16, [grain_lutq+topleft_offxyq*2+82*2], 1
+    punpckldq       xm1, xm2, xm0
+    punpcklwd       xm1, xm16, xm1
+    mova           xm16, xm20
+    vpdpwssd       xm16, xm17, xm10
+    mova           xm17, xm20
+    vpdpwssd       xm17, xm1, xm10
+    punpckhwd        m1, m19, m18
+    punpcklwd       m19, m18
+    punpckhwd       m18, m2, m0
+    punpcklwd        m2, m0
+    psrad          xm16, 1
+    psrad          xm17, 1
+    packssdw       xm16, xm17
+    vpsravw        xm16, xm21
+    vpshuflw    m19{k4}, m16, q1302
+    punpckhqdq     xm16, xm16
+    vpshuflw     m2{k4}, m16, q3120
+%endif
+    call %%add_noise_v
+    sub              hb, 2<<%2
+    jg %%loop_y_h_overlap
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r9mp
+    mov            dstq, r10mp
+    mov           lumaq, r11mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+    jmp %%hv_overlap
+
+ALIGN function_align
+%%add_noise_v:
+%if %3
+    mova           ym16, ym20
+    vpdpwssd       ym16, ym17, ym11
+    mova           ym17, ym20
+    vpdpwssd       ym17, ym1, ym11
+    psrad          ym16, 1
+    psrad          ym17, 1
+    packssdw       ym16, ym17
+    vpsravw     m18{k1}, m16, m21
+%elif %2
+    mova            m18, m20
+    vpdpwssd        m18, m16, m11
+    mova            m16, m20
+    vpdpwssd        m16, m17, m11
+    psrad           m18, 1
+    psrad           m16, 1
+    packssdw        m18, m16
+    vpsravw         m18, m21
+%else
+    mova            m16, m20
+    vpdpwssd        m16, m1, m11
+    mova            m17, m20
+    vpdpwssd        m17, m18, m11
+    mova            m18, m20
+    vpdpwssd        m18, m19, m11
+    mova            m19, m20
+    vpdpwssd        m19, m2, m11
+    REPX   {psrad x, 1}, m16, m17, m18, m19
+    packssdw        m18, m16
+    packssdw        m19, m17
+    vpsravw         m18, m21
+    vpsravw         m19, m21
+%endif
+%%add_noise:
+%if %2
+    mova             m2, [lumaq+lstrideq*(0<<%3)]
+    mova             m0, [lumaq+lstrideq*(1<<%3)]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+    mova             m3, [lumaq+lstrideq*(0<<%3)]
+    mova             m1, [lumaq+lstrideq*(1<<%3)]
+    mova            m16, m12
+    vpermi2w        m16, m2, m0
+    vpermt2w         m2, m13, m0
+    mova            m17, m12
+    vpermi2w        m17, m3, m1
+    vpermt2w         m3, m13, m1
+    pavgw            m2, m16
+    pavgw            m3, m17
+%elif %1
+    mova             m2, [lumaq+lstrideq*0]
+    mova             m3, [lumaq+lstrideq*1]
+%endif
+%if %2
+    mova           ym16, [srcq+strideq*0]
+    vinserti32x8    m16, [srcq+strideq*1], 1
+    lea            srcq, [srcq+strideq*2]
+%else
+    mova            m16, [srcq+strideq*0]
+%endif
+%if %1
+    punpckhwd       m17, m2, m16
+    mova             m0, m14
+    vpdpwssd         m0, m17, m15
+    punpcklwd       m17, m2, m16
+    mova             m2, m14
+    vpdpwssd         m2, m17, m15
+%endif
+%if %2
+    mova           ym17, [srcq+strideq*0]
+    vinserti32x8    m17, [srcq+strideq*1], 1
+%else
+    mova            m17, [srcq+strideq*1]
+%endif
+%if %1
+    psrad            m0, 6
+    psrad            m2, 6
+    packusdw         m2, m0
+    punpckhwd        m0, m3, m17
+    mova             m1, m14
+    vpdpwssd         m1, m15, m0
+    punpcklwd        m0, m3, m17
+    mova             m3, m14
+    vpdpwssd         m3, m15, m0
+    psrad            m1, 6
+    psrad            m3, 6
+    packusdw         m3, m1
+    pminuw           m2, m4
+    pminuw           m3, m4
+
+.add_noise_main:
+    ; scaling[luma_src]
+    kmovw            k5, k1
+    pand             m1, m5, m2
+    vpgatherdd   m0{k5}, [scalingq+m1]
+    kmovw            k5, k1
+    psrld            m2, 16
+    vpgatherdd   m1{k5}, [scalingq+m2]
+    vpshufb      m0{k2}, m1, m6
+    kmovw            k5, k1
+    psrld            m1, m3, 16
+    vpgatherdd   m2{k5}, [scalingq+m1]
+    kmovw            k5, k1
+    pand             m3, m5
+    vpgatherdd   m1{k5}, [scalingq+m3]
+    vpshufb      m1{k2}, m2, m6
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    vpsllvw          m0, m7
+    vpsllvw          m1, m7
+    pmulhrsw        m18, m0
+    pmulhrsw        m19, m1
+    add      grain_lutq, 82*(4<<%2)
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+    lea            srcq, [srcq+strideq*2]
+    paddw           m16, m18
+    paddw           m17, m19
+    pmaxsw          m16, m8
+    pmaxsw          m17, m8
+    pminsw          m16, m9
+    pminsw          m17, m9
+%if %2
+    mova          [dstq+strideq*0], ym16
+    vextracti32x8 [dstq+strideq*1], m16, 1
+    lea            dstq, [dstq+strideq*2]
+    mova          [dstq+strideq*0], ym17
+    vextracti32x8 [dstq+strideq*1], m17, 1
+%else
+    mova [dstq+strideq*0], m16
+    mova [dstq+strideq*1], m17
+%endif
+    lea            dstq, [dstq+strideq*2]
+    ret
+%else
+%if %2
+    pand             m2, m4
+    pand             m3, m4
+%else
+    pand             m2, m4, [lumaq+lstrideq*0]
+    pand             m3, m4, [lumaq+lstrideq*1]
+%endif
+    jmp .add_noise_main
+%endif
+%endmacro
+
+    %%FGUV_32x32xN_LOOP 1, %2, %3
+.csfl:
+    %%FGUV_32x32xN_LOOP 0, %2, %3
+.end:
+    RET
+%endmacro
+
+FGUV_FN 420, 1, 1
+FGUV_FN 422, 1, 0
+FGUV_FN 444, 0, 0
+
+%endif
diff --git a/media/libdav1d/src/src/x86/filmgrain16_sse.asm b/media/libdav1d/src/src/x86/filmgrain16_sse.asm
new file mode 100644
index 0000000000..25d01caa19
--- /dev/null
+++ b/media/libdav1d/src/src/x86/filmgrain16_sse.asm
@@ -0,0 +1,3415 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+%include "x86/filmgrain_common.asm"
+
+SECTION_RODATA 16
+pd_16: times 4 dd 16
+pw_1: times 8 dw 1
+pw_16384: times 8 dw 16384
+pw_8192: times 8 dw 8192
+pw_23_22: dw 23, 22
+          times 3 dw 0, 32
+pb_mask: db 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0
+pw_27_17_17_27: dw 27, 17, 17, 27
+                times 2 dw 0, 32
+rnd_next_upperbit_mask: dw 0x100B, 0x2016, 0x402C, 0x8058
+pw_seed_xor: times 2 dw 0xb524
+             times 2 dw 0x49d8
+pb_1: times 4 db 1
+hmul_bits: dw 32768, 16384, 8192, 4096
+round: dw 2048, 1024, 512
+mul_bits: dw 256, 128, 64, 32, 16
+round_vals: dw 32, 64, 128, 256, 512, 1024
+max: dw 256*4-1, 240*4, 235*4, 256*16-1, 240*16, 235*16
+min: dw 0, 16*4, 16*16
+; these two should be next to each other
+pw_4: times 2 dw 4
+pw_16: times 2 dw 16
+
+%macro JMP_TABLE 1-*
+    %xdefine %1_table %%table
+    %xdefine %%base %1_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1)
+    %%table:
+    %rep %0 - 1
+        dd %%prefix %+ .ar%2 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+JMP_TABLE generate_grain_y_16bpc_ssse3, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_420_16bpc_ssse3, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_422_16bpc_ssse3, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_444_16bpc_ssse3, 0, 1, 2, 3
+
+SECTION .text
+
+%if ARCH_X86_32
+%undef base
+%define PIC_ptr(a) base+a
+%else
+%define PIC_ptr(a) a
+%endif
+
+%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX)
+
+%macro vpgatherdw 5-8 8, 1 ; dst, src, base, tmp_gpr[x2], cnt, stride, tmp_xmm_reg
+%assign %%idx 0
+%define %%tmp %2
+%if %0 == 8
+%define %%tmp %8
+%endif
+%rep (%6/2)
+%if %%idx == 0
+    movd        %5 %+ d, %2
+    pshuflw       %%tmp, %2, q3232
+%else
+    movd        %5 %+ d, %%tmp
+%if %6 == 8
+%if %%idx == 2
+    punpckhqdq    %%tmp, %%tmp
+%elif %%idx == 4
+    psrlq         %%tmp, 32
+%endif
+%endif
+%endif
+    movzx       %4 %+ d, %5 %+ w
+    shr         %5 %+ d, 16
+
+%if %%idx == 0
+    movd             %1, [%3+%4*%7]
+%else
+    pinsrw           %1, [%3+%4*%7], %%idx + 0
+%endif
+    pinsrw           %1, [%3+%5*%7], %%idx + 1
+%assign %%idx %%idx+2
+%endrep
+%endmacro
+
+%macro SPLATD 2 ; dst, src
+%ifnidn %1, %2
+    movd %1, %2
+%endif
+    pshufd %1, %1, q0000
+%endmacro
+
+%macro SPLATW 2 ; dst, src
+%ifnidn %1, %2
+    movd %1, %2
+%endif
+    pshuflw %1, %1, q0000
+    punpcklqdq %1, %1
+%endmacro
+
+
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal generate_grain_y_16bpc, 3, 8, 16, buf, fg_data, bdmax
+    lea              r4, [pb_mask]
+%define base r4-pb_mask
+%else
+cglobal generate_grain_y_16bpc, 3, 6, 8, buf, fg_data, bdmax
+    LEA              r4, $$
+%define base r4-$$
+%endif
+    movq             m1, [base+rnd_next_upperbit_mask]
+    movq             m4, [base+mul_bits]
+    movq             m7, [base+hmul_bits]
+    mov             r3d, [fg_dataq+FGData.grain_scale_shift]
+    lea             r5d, [bdmaxq+1]
+    shr             r5d, 11             ; 0 for 10bpc, 2 for 12bpc
+    sub              r3, r5
+    SPLATW           m6, [base+round+r3*2-2]
+    mova             m5, [base+pb_mask]
+    SPLATW           m0, [fg_dataq+FGData.seed]
+    mov              r3, -73*82*2
+    sub            bufq, r3
+%if ARCH_X86_64
+    lea              r6, [gaussian_sequence]
+%endif
+.loop:
+    pand             m2, m0, m1
+    psrlw            m3, m2, 10
+    por              m2, m3             ; bits 0xf, 0x1e, 0x3c and 0x78 are set
+    pmullw           m2, m4             ; bits 0x0f00 are set
+    pshufb           m3, m5, m2         ; set 15th bit for next 4 seeds
+    psllq            m2, m3, 30
+    por              m2, m3
+    psllq            m3, m2, 15
+    por              m2, m3             ; aggregate each bit into next seed's high bit
+    pmulhuw          m3, m0, m7
+    por              m2, m3             ; 4 next output seeds
+    pshuflw          m0, m2, q3333
+    psrlw            m2, 5
+%if ARCH_X86_64
+    vpgatherdw       m3, m2, r6, r5, r7, 4, 2
+%else
+    vpgatherdw       m3, m2, base+gaussian_sequence, r5, r2, 4, 2
+%endif
+    paddw            m3, m3             ; otherwise bpc=12 w/ grain_scale_shift=0
+                                        ; shifts by 0, which pmulhrsw does not support
+    pmulhrsw         m3, m6
+    movq      [bufq+r3], m3
+    add              r3, 4*2
+    jl .loop
+
+    ; auto-regression code
+    movsxd           r3, [fg_dataq+FGData.ar_coeff_lag]
+    movsxd           r3, [base+generate_grain_y_16bpc_ssse3_table+r3*4]
+    lea              r3, [r3+base+generate_grain_y_16bpc_ssse3_table]
+    jmp              r3
+
+.ar1:
+%if WIN64
+    DEFINE_ARGS shift, fg_data, max, buf, val3, min, cf3, x, val0
+    lea            bufq, [r0-2*(82*73-(82*3+79))]
+    PUSH             r8
+%else
+%if ARCH_X86_64
+    DEFINE_ARGS buf, fg_data, max, shift, val3, min, cf3, x, val0
+%else ; x86-32
+    DEFINE_ARGS buf, fg_data, min, val3, x, cf3, val0
+    PUSH             r6
+%define shiftd r1d
+%endif
+    sub            bufq, 2*(82*73-(82*3+79))
+%endif
+    movsx          cf3d, byte [fg_dataq+FGData.ar_coeffs_y+3]
+    movd             m4, [fg_dataq+FGData.ar_coeffs_y]
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+%if WIN64
+    DEFINE_ARGS shift, h, max, buf, val3, min, cf3, x, val0
+%elif ARCH_X86_64
+    DEFINE_ARGS buf, h, max, shift, val3, min, cf3, x, val0
+%else ; x86-32
+%undef shiftd
+    DEFINE_ARGS buf, shift, min, val3, x, cf3, val0
+%define hd dword r0m
+%define maxd dword minm
+%endif
+%if cpuflag(sse4)
+    pmovsxbw         m4, m4
+%else
+    pxor             m3, m3
+    pcmpgtb          m3, m4
+    punpcklbw        m4, m3
+%endif
+    pinsrw           m4, [base+pw_1], 3
+    pshufd           m5, m4, q1111
+    pshufd           m4, m4, q0000
+    SPLATW           m3, [base+round_vals+shiftq*2-12]    ; rnd
+    mov              hd, 70
+    sar            maxd, 1
+    mov            mind, maxd
+    xor            mind, -1
+.y_loop_ar1:
+    mov              xq, -76
+    movsx         val3d, word [bufq+xq*2-2]
+.x_loop_ar1:
+    movu             m0, [bufq+xq*2-82*2-2]     ; top/left
+    psrldq           m2, m0, 2                  ; top
+    psrldq           m1, m0, 4                  ; top/right
+    punpcklwd        m0, m2
+    punpcklwd        m1, m3
+    pmaddwd          m0, m4
+    pmaddwd          m1, m5
+    paddd            m0, m1
+.x_loop_ar1_inner:
+    movd          val0d, m0
+    psrldq           m0, 4
+    imul          val3d, cf3d
+    add           val3d, val0d
+    sar           val3d, shiftb
+    movsx         val0d, word [bufq+xq*2]
+    add           val3d, val0d
+    cmp           val3d, maxd
+    cmovg         val3d, maxd
+    cmp           val3d, mind
+    cmovl         val3d, mind
+    mov word [bufq+xq*2], val3w
+    ; keep val3d in-place as left for next x iteration
+    inc              xq
+    jz .x_loop_ar1_end
+    test             xq, 3
+    jnz .x_loop_ar1_inner
+    jmp .x_loop_ar1
+
+.x_loop_ar1_end:
+    add            bufq, 82*2
+    dec              hd
+    jg .y_loop_ar1
+%if WIN64
+    POP              r8
+%elif ARCH_X86_32
+    POP              r6
+%undef maxd
+%undef hd
+%endif
+.ar0:
+    RET
+
+.ar2:
+%if ARCH_X86_32
+    ALLOC_STACK -16*8
+%endif
+    DEFINE_ARGS buf, fg_data, bdmax, shift
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movd             m0, [base+round_vals-12+shiftq*2]
+    pshuflw          m0, m0, q0000
+    movu             m6, [fg_dataq+FGData.ar_coeffs_y+0]    ; cf0-11
+    pxor             m2, m2
+    punpcklwd        m0, m2
+    pcmpgtb          m2, m6
+    punpckhbw        m3, m6, m2
+    punpcklbw        m6, m2
+    pshufd           m2, m6, q3333
+    pshufd           m1, m6, q2222
+    pshufd           m7, m6, q1111
+    pshufd           m6, m6, q0000
+    pshufd           m4, m3, q1111
+    pshufd           m3, m3, q0000
+%if ARCH_X86_64
+    SWAP              0, 12
+    SWAP              1, 8
+    SWAP              2, 9
+    SWAP              3, 10
+    SWAP              4, 11
+%else
+%define m12 [rsp+0*16]
+%define m8 [rsp+1*16]
+%define m9 [rsp+2*16]
+%define m10 [rsp+3*16]
+%define m11 [rsp+4*16]
+    mova            m12, m0
+    mova             m8, m1
+    mova             m9, m2
+    mova            m10, m3
+    mova            m11, m4
+    mov          bdmaxd, bdmaxm
+%endif
+    sar          bdmaxd, 1
+    SPLATW           m0, bdmaxd                             ; max_grain
+    pcmpeqw          m1, m1
+%if !cpuflag(sse4)
+    pcmpeqw          m2, m2
+    psrldq           m2, 14
+    pslldq           m2, 2
+    pxor             m2, m1
+%endif
+    pxor             m1, m0                                 ; min_grain
+%if ARCH_X86_64
+    SWAP              0, 13
+    SWAP              1, 14
+    SWAP              2, 15
+%else
+%define m13 [rsp+5*16]
+%define m14 [rsp+6*16]
+    mova            m13, m0
+    mova            m14, m1
+%if !cpuflag(sse4)
+%define m15 [rsp+7*16]
+    mova            m15, m2
+%endif
+%endif
+    sub            bufq, 2*(82*73-(82*3+79))
+    DEFINE_ARGS buf, fg_data, h, x
+    mov              hd, 70
+.y_loop_ar2:
+    mov              xq, -76
+
+.x_loop_ar2:
+    movu             m0, [bufq+xq*2-82*4-4]     ; y=-2,x=[-2,+5]
+    movu             m1, [bufq+xq*2-82*2-4]     ; y=-1,x=[-2,+5]
+    psrldq           m2, m0, 2
+    psrldq           m3, m0, 4
+    psrldq           m4, m0, 6
+    psrldq           m5, m0, 8
+    punpcklwd        m0, m2
+    punpcklwd        m3, m4
+    punpcklwd        m5, m1
+    psrldq           m2, m1, 2
+    psrldq           m4, m1, 4
+    punpcklwd        m2, m4
+    psrldq           m4, m1, 6
+    psrldq           m1, 8
+    punpcklwd        m4, m1
+    pmaddwd          m0, m6
+    pmaddwd          m3, m7
+    pmaddwd          m5, m8
+    pmaddwd          m2, m9
+    pmaddwd          m4, m10
+    paddd            m0, m3
+    paddd            m5, m2
+    paddd            m0, m4
+    paddd            m0, m5                     ; accumulated top 2 rows
+    paddd            m0, m12
+
+    movu             m1, [bufq+xq*2-4]      ; y=0,x=[-2,+5]
+    pshufd           m4, m1, q3321
+    pxor             m2, m2
+    pcmpgtw          m2, m4
+    punpcklwd        m4, m2                 ; in dwords, y=0,x=[0,3]
+.x_loop_ar2_inner:
+    pmaddwd          m2, m1, m11
+    paddd            m2, m0
+    psrldq           m0, 4                  ; shift top to next pixel
+    psrad            m2, [fg_dataq+FGData.ar_coeff_shift]
+    paddd            m2, m4
+    packssdw         m2, m2
+    pminsw           m2, m13
+    pmaxsw           m2, m14
+    psrldq           m4, 4
+    pslldq           m2, 2
+    psrldq           m1, 2
+%if cpuflag(sse4)
+    pblendw          m1, m2, 00000010b
+%else
+    pand             m1, m15
+    pandn            m3, m15, m2
+    por              m1, m3
+%endif
+    ; overwrite previous pixel, this should be ok
+    movd  [bufq+xq*2-2], m1
+    inc              xq
+    jz .x_loop_ar2_end
+    test             xq, 3
+    jnz .x_loop_ar2_inner
+    jmp .x_loop_ar2
+
+.x_loop_ar2_end:
+    add            bufq, 82*2
+    dec              hd
+    jg .y_loop_ar2
+%if ARCH_X86_32
+%undef m8
+%undef m9
+%undef m10
+%undef m11
+%undef m12
+%undef m13
+%undef m14
+%undef m15
+%endif
+    RET
+
+.ar3:
+    DEFINE_ARGS buf, fg_data, bdmax, shift
+%if WIN64
+    mov              r6, rsp
+    and             rsp, ~15
+    sub             rsp, 64
+    %define         tmp  rsp
+%elif ARCH_X86_64
+    %define         tmp  rsp+stack_offset-72
+%else
+    ALLOC_STACK  -16*12
+    %define         tmp  rsp
+    mov          bdmaxd, bdmaxm
+%endif
+    sar          bdmaxd, 1
+    SPLATW           m7, bdmaxd                                 ; max_grain
+    pcmpeqw          m6, m6
+%if !cpuflag(sse4)
+    pcmpeqw          m4, m4
+    psrldq           m4, 14
+    pslldq           m4, 4
+    pxor             m4, m6
+%endif
+    pxor             m6, m7                                    ; min_grain
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+
+%if ARCH_X86_64
+    SWAP              6, 14
+    SWAP              7, 15
+%else
+%define m14 [rsp+10*16]
+%define m15 [esp+11*16]
+    mova            m14, m6
+    mova            m15, m7
+%endif
+
+    ; build cf0-1 until 18-19 in m5-12 and r0/1
+    pxor             m1, m1
+    movu             m0, [fg_dataq+FGData.ar_coeffs_y+ 0]       ; cf0-15
+    pcmpgtb          m1, m0
+    punpckhbw        m2, m0, m1
+    punpcklbw        m0, m1
+
+%if cpuflag(sse4)
+    pshufd           m4, m2, q3333
+%else
+    pshufd           m5, m2, q3333
+    mova       [tmp+48], m5
+%endif
+    pshufd           m3, m2, q2222
+    pshufd           m1, m2, q0000
+    pshufd           m2, m2, q1111
+    pshufd           m7, m0, q2222
+    pshufd           m6, m0, q1111
+    pshufd           m5, m0, q0000
+    pshufd           m0, m0, q3333
+
+%if ARCH_X86_64
+    SWAP              0, 8
+    SWAP              1, 9
+    SWAP              2, 10
+    SWAP              3, 11
+    SWAP              4, 12
+%else
+%define m8 [rsp+4*16]
+%define m9 [esp+5*16]
+%define m10 [rsp+6*16]
+%define m11 [esp+7*16]
+%define m12 [rsp+8*16]
+    mova             m8, m0
+    mova             m9, m1
+    mova            m10, m2
+    mova            m11, m3
+    mova            m12, m4
+%endif
+
+    ; build cf20,round in r2
+    ; build cf21-23,round*2 in m13
+    pxor             m1, m1
+    movq             m0, [fg_dataq+FGData.ar_coeffs_y+16]       ; cf16-23
+    pcmpgtb          m1, m0
+    punpcklbw        m0, m1
+    pshufd           m1, m0, q0000
+    pshufd           m2, m0, q1111
+    mova       [tmp+ 0], m1
+    mova       [tmp+16], m2
+    psrldq           m3, m0, 10
+    pinsrw           m3, [base+round_vals+shiftq*2-10], 3
+
+%if ARCH_X86_64
+    SWAP              3, 13
+%else
+%define m13 [esp+9*16]
+    mova            m13, m3
+%endif
+
+    pinsrw           m0, [base+round_vals+shiftq*2-12], 5
+    pshufd           m3, m0, q2222
+    mova       [tmp+32], m3
+
+    DEFINE_ARGS buf, fg_data, h, x
+    sub            bufq, 2*(82*73-(82*3+79))
+    mov              hd, 70
+.y_loop_ar3:
+    mov              xq, -76
+
+.x_loop_ar3:
+    movu             m0, [bufq+xq*2-82*6-6+ 0]      ; y=-3,x=[-3,+4]
+    movd             m1, [bufq+xq*2-82*6-6+16]      ; y=-3,x=[+5,+6]
+    palignr          m2, m1, m0, 2                  ; y=-3,x=[-2,+5]
+    palignr          m1, m1, m0, 12                 ; y=-3,x=[+3,+6]
+    punpckhwd        m3, m0, m2                     ; y=-3,x=[+1/+2,+2/+3,+3/+4,+4/+5]
+    punpcklwd        m0, m2                         ; y=-3,x=[-3/-2,-2/-1,-1/+0,+0/+1]
+    shufps           m2, m0, m3, q1032              ; y=-3,x=[-1/+0,+0/+1,+1/+2,+2/+3]
+
+    pmaddwd          m0, m5
+    pmaddwd          m2, m6
+    pmaddwd          m3, m7
+    paddd            m0, m2
+    paddd            m0, m3
+    ; m0 = top line first 6 multiplied by cf, m1 = top line last entry
+
+    movu             m2, [bufq+xq*2-82*4-6+ 0]      ; y=-2,x=[-3,+4]
+    movd             m3, [bufq+xq*2-82*4-6+16]      ; y=-2,x=[+5,+6]
+    punpcklwd        m1, m2                         ; y=-3/-2,x=[+3/-3,+4/-2,+5/-1,+6/+0]
+    palignr          m4, m3, m2, 2                  ; y=-3,x=[-2,+5]
+    palignr          m3, m3, m2, 4                  ; y=-3,x=[-1,+6]
+    punpckhwd        m2, m4, m3                     ; y=-2,x=[+2/+3,+3/+4,+4/+5,+5/+6]
+    punpcklwd        m4, m3                         ; y=-2,x=[-2/-1,-1/+0,+0/+1,+1/+2]
+    shufps           m3, m4, m2, q1032              ; y=-2,x=[+0/+1,+1/+2,+2/+3,+3/+4]
+
+    pmaddwd          m1, m8
+    pmaddwd          m4, m9
+    pmaddwd          m3, m10
+    pmaddwd          m2, m11
+    paddd            m1, m4
+    paddd            m3, m2
+    paddd            m0, m1
+    paddd            m0, m3
+    ; m0 = top 2 lines multiplied by cf
+
+    movu             m1, [bufq+xq*2-82*2-6+ 0]      ; y=-1,x=[-3,+4]
+    movd             m2, [bufq+xq*2-82*2-6+16]      ; y=-1,x=[+5,+6]
+    palignr          m3, m2, m1, 2                  ; y=-1,x=[-2,+5]
+    palignr          m2, m2, m1, 12                 ; y=-1,x=[+3,+6]
+    punpckhwd        m4, m1, m3                     ; y=-1,x=[+1/+2,+2/+3,+3/+4,+4/+5]
+    punpcklwd        m1, m3                         ; y=-1,x=[-3/-2,-2/-1,-1/+0,+0/+1]
+    shufps           m3, m1, m4, q1032              ; y=-1,x=[-1/+0,+0/+1,+1/+2,+2/+3]
+    punpcklwd        m2, [base+pw_1]
+
+%if cpuflag(sse4)
+    pmaddwd          m1, m12
+%else
+    pmaddwd          m1, [tmp+48]
+%endif
+    pmaddwd          m3, [tmp+ 0]
+    pmaddwd          m4, [tmp+16]
+    pmaddwd          m2, [tmp+32]
+    paddd            m1, m3
+    paddd            m4, m2
+    paddd            m0, m1
+    paddd            m0, m4
+    ; m0 = top 3 lines multiplied by cf plus rounding for downshift
+
+    movu             m1, [bufq+xq*2-6]      ; y=0,x=[-3,+4]
+.x_loop_ar3_inner:
+    pmaddwd          m2, m1, m13
+    pshufd           m3, m2, q1111
+    paddd            m2, m3                 ; left+cur
+    paddd            m2, m0                 ; add top
+    psrldq           m0, 4
+    psrad            m2, [fg_dataq+FGData.ar_coeff_shift]
+    packssdw         m2, m2
+    pminsw           m2, m15
+    pmaxsw           m2, m14
+    pslldq           m2, 4
+    psrldq           m1, 2
+%if cpuflag(sse4)
+    pblendw          m1, m2, 00000100b
+%else
+    pand             m1, m12
+    pandn            m3, m12, m2
+    por              m1, m3
+%endif
+    ; overwrite a couple of pixels, should be ok
+    movq  [bufq+xq*2-4], m1
+    inc              xq
+    jz .x_loop_ar3_end
+    test             xq, 3
+    jnz .x_loop_ar3_inner
+    jmp .x_loop_ar3
+
+.x_loop_ar3_end:
+    add            bufq, 82*2
+    dec              hd
+    jg .y_loop_ar3
+%if WIN64
+    mov             rsp, r6
+%elif ARCH_X86_32
+%undef m8
+%undef m9
+%undef m10
+%undef m11
+%undef m12
+%undef m13
+%undef m14
+%undef m15
+%endif
+    RET
+
+%macro generate_grain_uv_fn 3 ; ss_name, ss_x, ss_y
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal generate_grain_uv_%1_16bpc, 4, 11, 16, buf, bufy, fg_data, uv, bdmax, x, gaussian_reg, h, pic_reg
+%define base r8-pb_mask
+    lea              r8, [pb_mask]
+    movifnidn    bdmaxd, bdmaxm
+    lea             r6d, [bdmaxq+1]
+%else
+cglobal generate_grain_uv_%1_16bpc, 1, 7, 8, buf, x, pic_reg, fg_data, h
+%define base r2-$$
+    LEA              r2, $$
+    mov        fg_dataq, r2m
+    mov             r6d, r4m
+    inc             r6d
+%endif
+    movq             m1, [base+rnd_next_upperbit_mask]
+    movq             m4, [base+mul_bits]
+    movq             m7, [base+hmul_bits]
+    mov             r5d, [fg_dataq+FGData.grain_scale_shift]
+    shr             r6d, 11             ; 0 for 10bpc, 2 for 12bpc
+    sub              r5, r6
+    SPLATW           m6, [base+round+r5*2-2]
+    mova             m5, [base+pb_mask]
+    SPLATW           m0, [fg_dataq+FGData.seed]
+%if ARCH_X86_64
+    SPLATW           m2, [base+pw_seed_xor+uvq*4]
+%else
+    mov             r5d, r3m
+    SPLATW           m2, [base+pw_seed_xor+r5*4]
+%endif
+    pxor             m0, m2
+%if ARCH_X86_64
+    lea              r6, [gaussian_sequence]
+%endif
+%if %2
+    mov              hd, 73-35*%3
+    add            bufq, 44*2
+.loop_y:
+    mov              xq, -44
+%else
+    mov              xq, -82*73
+    add            bufq, 82*73*2
+%endif
+.loop_x:
+    pand             m2, m0, m1
+    psrlw            m3, m2, 10
+    por              m2, m3             ; bits 0xf, 0x1e, 0x3c and 0x78 are set
+    pmullw           m2, m4             ; bits 0x0f00 are set
+    pshufb           m3, m5, m2         ; set 15th bit for next 4 seeds
+    psllq            m2, m3, 30
+    por              m2, m3
+    psllq            m3, m2, 15
+    por              m2, m3             ; aggregate each bit into next seed's high bit
+    pmulhuw          m3, m0, m7
+    por              m2, m3             ; 4 next output seeds
+    pshuflw          m0, m2, q3333
+    psrlw            m2, 5
+%if ARCH_X86_64
+    vpgatherdw       m3, m2, r6, r9, r10, 4, 2
+%else
+    vpgatherdw       m3, m2, base+gaussian_sequence, r5, r6, 4, 2
+%endif
+    paddw            m3, m3             ; otherwise bpc=12 w/ grain_scale_shift=0
+                                        ; shifts by 0, which pmulhrsw does not support
+    pmulhrsw         m3, m6
+    movq    [bufq+xq*2], m3
+    add              xq, 4
+    jl .loop_x
+%if %2
+    add            bufq, 82*2
+    dec              hd
+    jg .loop_y
+%endif
+
+    ; auto-regression code
+    movsxd           r5, [fg_dataq+FGData.ar_coeff_lag]
+    movsxd           r5, [base+generate_grain_uv_%1_16bpc_ssse3_table+r5*4]
+    lea              r5, [r5+base+generate_grain_uv_%1_16bpc_ssse3_table]
+    jmp              r5
+
+.ar0:
+%if ARCH_X86_64
+    DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift
+%else
+    DEFINE_ARGS buf, bufy, pic_reg, fg_data, uv, shift
+    ALLOC_STACK  -16*2
+    mov           bufyq, r1m
+    mov             uvd, r3m
+%endif
+    imul            uvd, 28
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movd             m4, [fg_dataq+FGData.ar_coeffs_uv+uvq]
+    SPLATW           m3, [base+hmul_bits+shiftq*2-10]
+%if ARCH_X86_64
+    sar          bdmaxd, 1
+    SPLATW           m1, bdmaxd                     ; max_gain
+%else
+    SPLATW           m1, r4m
+    psraw            m1, 1
+%endif
+    pcmpeqw          m7, m7
+    pxor             m7, m1                         ; min_grain
+%if ARCH_X86_64
+    SWAP              1, 14
+    DEFINE_ARGS buf, bufy, h, x
+%else
+%define m14 [rsp+0*16]
+    mova            m14, m1
+    DEFINE_ARGS buf, bufy, pic_reg, h, x
+%endif
+    pxor             m5, m5
+    pcmpgtb          m5, m4
+    punpcklbw        m4, m5
+%if %2
+    SPLATW           m6, [base+hmul_bits+2+%3*2]
+%endif
+    SPLATW           m4, m4
+    pxor             m5, m5
+%if %2
+%if !cpuflag(sse4)
+    pcmpeqw          m2, m2
+    pslldq           m2, 12
+%if ARCH_X86_64
+    SWAP              2, 12
+%else
+%define m12 [rsp+1*16]
+    mova            m12, m2
+%endif
+%endif
+%endif
+%if %2
+    sub            bufq, 2*(82*(73-35*%3)+82-(82*3+41))
+%else
+    sub            bufq, 2*(82*70-3)
+%endif
+    add           bufyq, 2*(3+82*3)
+    mov              hd, 70-35*%3
+.y_loop_ar0:
+    ; first 32 pixels
+    xor              xd, xd
+.x_loop_ar0:
+    movu             m0, [bufyq+xq*(2<<%2)]
+%if %2
+%if %3
+    movu             m2, [bufyq+xq*4+82*2]
+    paddw            m0, m2
+%endif
+    movu             m1, [bufyq+xq*4     +16]
+%if %3
+    movu             m2, [bufyq+xq*4+82*2+16]
+    paddw            m1, m2
+%endif
+    phaddw           m0, m1
+    pmulhrsw         m0, m6
+%endif
+    punpckhwd        m1, m0, m5
+    punpcklwd        m0, m5
+    REPX {pmaddwd x, m4}, m0, m1
+    REPX {psrad x, 5}, m0, m1
+    packssdw         m0, m1
+    pmulhrsw         m0, m3
+    movu             m1, [bufq+xq*2]
+    paddw            m0, m1
+    pminsw           m0, m14
+    pmaxsw           m0, m7
+    cmp              xd, 72-40*%2
+    je .end
+    movu    [bufq+xq*2], m0
+    add              xd, 8
+    jmp .x_loop_ar0
+
+    ; last 6/4 pixels
+.end:
+%if %2
+%if cpuflag(sse4)
+    pblendw          m0, m1, 11000000b
+%else
+    pand             m1, m12
+    pandn            m2, m12, m0
+    por              m0, m1, m2
+%endif
+    movu    [bufq+xq*2], m0
+%else
+    movq    [bufq+xq*2], m0
+%endif
+
+    add            bufq, 82*2
+    add           bufyq, 82*(2<<%3)
+    dec              hd
+    jg .y_loop_ar0
+%if ARCH_X86_32
+%undef m12
+%undef m14
+%endif
+    RET
+
+.ar1:
+%if ARCH_X86_64
+    DEFINE_ARGS buf, bufy, fg_data, uv, max, cf3, min, val3, x
+%else
+    RESET_STACK_STATE
+    DEFINE_ARGS buf, shift, pic_reg, fg_data, uv, bufy, cf3
+    mov           bufyq, r1m
+    mov             uvd, r3m
+%endif
+    imul            uvd, 28
+    movsx          cf3d, byte [fg_dataq+FGData.ar_coeffs_uv+uvq+3]
+    movq             m4, [fg_dataq+FGData.ar_coeffs_uv+uvq]
+%if WIN64
+    DEFINE_ARGS shift, bufy, h, buf, max, cf3, min, val3, x, val0
+%if %2
+    lea            bufq, [r0-2*(82*(73-35*%3)+44-(82*3+41))]
+%else
+    lea            bufq, [r0-2*(82*69+3)]
+%endif
+%else
+%if ARCH_X86_64
+    DEFINE_ARGS buf, bufy, h, shift, max, cf3, min, val3, x, val0
+%else
+    DEFINE_ARGS buf, shift, pic_reg, fg_data, val0, bufy, cf3
+%define hd dword r1m
+%define mind dword r3m
+%define maxd dword r4m
+%endif
+%if %2
+    sub            bufq, 2*(82*(73-35*%3)+44-(82*3+41))
+%else
+    sub            bufq, 2*(82*69+3)
+%endif
+%endif
+%if ARCH_X86_64
+    mov          shiftd, [r2+FGData.ar_coeff_shift]
+%else
+    mov          shiftd, [r3+FGData.ar_coeff_shift]
+%endif
+    pxor             m5, m5
+    pcmpgtb          m5, m4
+    punpcklbw        m4, m5                 ; cf0-4 in words
+    pshuflw          m4, m4, q2100
+    psrldq           m4, 2                  ; cf0-3,4 in words
+    pshufd           m5, m4, q1111
+    pshufd           m4, m4, q0000
+    movd             m3, [base+round_vals+shiftq*2-12]    ; rnd
+    pxor             m6, m6
+    punpcklwd        m3, m6
+%if %2
+    SPLATW           m6, [base+hmul_bits+2+%3*2]
+%endif
+    SPLATD           m3, m3
+    add           bufyq, 2*(79+82*3)
+    mov              hd, 70-35*%3
+    sar            maxd, 1
+%if ARCH_X86_64
+    mov            mind, maxd
+    xor            mind, -1
+%else
+    DEFINE_ARGS buf, shift, val3, x, val0, bufy, cf3
+    mov              r2, maxd
+    xor              r2, -1
+    mov            mind, r2
+%endif
+.y_loop_ar1:
+    mov              xq, -(76>>%2)
+    movsx         val3d, word [bufq+xq*2-2]
+.x_loop_ar1:
+    movu             m0, [bufq+xq*2-82*2-2] ; top/left
+%if %2
+    movu             m7, [bufyq+xq*4]
+%if %3
+    movu             m1, [bufyq+xq*4+82*2]
+    phaddw           m7, m1
+%else
+    phaddw           m7, m7
+%endif
+%else
+    movq             m7, [bufyq+xq*2]
+%endif
+    psrldq           m2, m0, 2              ; top
+    psrldq           m1, m0, 4              ; top/right
+    punpcklwd        m0, m2
+%if %2
+%if %3
+    pshufd           m2, m7, q3232
+    paddw            m7, m2
+%endif
+    pmulhrsw         m7, m6
+%endif
+    punpcklwd        m1, m7
+    pmaddwd          m0, m4
+    pmaddwd          m1, m5
+    paddd            m0, m1
+    paddd            m0, m3
+.x_loop_ar1_inner:
+    movd          val0d, m0
+    psrldq           m0, 4
+    imul          val3d, cf3d
+    add           val3d, val0d
+    sar           val3d, shiftb
+    movsx         val0d, word [bufq+xq*2]
+    add           val3d, val0d
+    cmp           val3d, maxd
+    cmovg         val3d, maxd
+    cmp           val3d, mind
+    cmovl         val3d, mind
+    mov word [bufq+xq*2], val3w
+    ; keep val3d in-place as left for next x iteration
+    inc              xq
+    jz .x_loop_ar1_end
+    test             xq, 3
+    jnz .x_loop_ar1_inner
+    jmp .x_loop_ar1
+
+.x_loop_ar1_end:
+    add            bufq, 82*2
+    add           bufyq, 82*2<<%3
+    dec              hd
+    jg .y_loop_ar1
+%if ARCH_X86_32
+%undef maxd
+%undef mind
+%undef hd
+%endif
+    RET
+
+.ar2:
+%if ARCH_X86_64
+    DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift
+%else
+    DEFINE_ARGS buf, bufy, pic_reg, fg_data, uv, shift
+    ALLOC_STACK  -16*8
+    mov           bufyq, r1m
+    mov             uvd, r3m
+%endif
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    imul            uvd, 28
+%if ARCH_X86_64
+    sar          bdmaxd, 1
+    SPLATW           m5, bdmaxd                 ; max_grain
+%else
+    SPLATW           m5, r4m
+    psraw            m5, 1
+%endif
+    pcmpeqw          m6, m6
+%if !cpuflag(sse4)
+    pcmpeqw          m7, m7
+    psrldq           m7, 14
+    pslldq           m7, 2
+    pxor             m7, m6
+%endif
+    pxor             m6, m5                    ; min_grain
+%if %2 && cpuflag(sse4)
+    SPLATW           m7, [base+hmul_bits+2+%3*2]
+%endif
+
+%if ARCH_X86_64
+    SWAP              5, 13
+    SWAP              6, 14
+    SWAP              7, 15
+%else
+%define m13 [rsp+5*16]
+%define m14 [rsp+6*16]
+%define m15 [rsp+7*16]
+    mova            m13, m5
+    mova            m14, m6
+    mova            m15, m7
+%endif
+
+    ; coef values
+    movu             m0, [fg_dataq+FGData.ar_coeffs_uv+uvq+0]
+    pxor             m1, m1
+    pcmpgtb          m1, m0
+    punpckhbw        m2, m0, m1
+    punpcklbw        m0, m1
+    pinsrw           m2, [base+round_vals-12+shiftq*2], 5
+
+    pshufd           m6, m0, q0000
+    pshufd           m7, m0, q1111
+    pshufd           m1, m0, q3333
+    pshufd           m0, m0, q2222
+    pshufd           m3, m2, q1111
+    pshufd           m4, m2, q2222
+    pshufd           m2, m2, q0000
+
+%if ARCH_X86_64
+    SWAP              0, 8
+    SWAP              1, 9
+    SWAP              2, 10
+    SWAP              3, 11
+    SWAP              4, 12
+%else
+%define m8 [rsp+0*16]
+%define m9 [rsp+1*16]
+%define m10 [rsp+2*16]
+%define m11 [rsp+3*16]
+%define m12 [rsp+4*16]
+    mova             m8, m0
+    mova             m9, m1
+    mova            m10, m2
+    mova            m11, m3
+    mova            m12, m4
+%endif
+
+%if ARCH_X86_64
+    DEFINE_ARGS buf, bufy, fg_data, h, x
+%else
+    DEFINE_ARGS buf, bufy, pic_reg, fg_data, h, x
+%endif
+%if %2
+    sub            bufq, 2*(82*(73-35*%3)+44-(82*3+41))
+%else
+    sub            bufq, 2*(82*69+3)
+%endif
+    add           bufyq, 2*(79+82*3)
+    mov              hd, 70-35*%3
+.y_loop_ar2:
+    mov              xq, -(76>>%2)
+
+.x_loop_ar2:
+    movu             m0, [bufq+xq*2-82*4-4]     ; y=-2,x=[-2,+5]
+    movu             m5, [bufq+xq*2-82*2-4]     ; y=-1,x=[-2,+5]
+    psrldq           m4, m0, 2                  ; y=-2,x=[-1,+5]
+    psrldq           m1, m0, 4                  ; y=-2,x=[-0,+5]
+    psrldq           m3, m0, 6                  ; y=-2,x=[+1,+5]
+    psrldq           m2, m0, 8                  ; y=-2,x=[+2,+5]
+    punpcklwd        m0, m4                     ; y=-2,x=[-2/-1,-1/+0,+0/+1,+1/+2]
+    punpcklwd        m1, m3                     ; y=-2,x=[+0/+1,+1/+2,+2/+3,+3/+4]
+    punpcklwd        m2, m5                     ; y=-2/-1,x=[+2/-2,+3/-1,+4/+0,+5/+1]
+    pmaddwd          m0, m6
+    pmaddwd          m1, m7
+    pmaddwd          m2, m8
+    paddd            m0, m1
+    paddd            m0, m2
+    psrldq           m3, m5, 2                  ; y=-1,x=[-1,+5]
+    psrldq           m1, m5, 4                  ; y=-1,x=[-0,+5]
+    psrldq           m4, m5, 6                  ; y=-1,x=[+1,+5]
+    psrldq           m2, m5, 8                  ; y=-1,x=[+2,+5]
+    punpcklwd        m3, m1
+    punpcklwd        m4, m2
+    pmaddwd          m3, m9
+    pmaddwd          m4, m10
+    paddd            m3, m4
+    paddd            m0, m3
+
+    ; luma component & rounding
+%if %2
+    movu             m1, [bufyq+xq*4]
+%if %3
+    movu             m2, [bufyq+xq*4+82*2]
+    phaddw           m1, m2
+    pshufd           m2, m1, q3232
+    paddw            m1, m2
+%else
+    phaddw           m1, m1
+%endif
+%if cpuflag(sse4)
+    pmulhrsw         m1, m15
+%elif %3
+    pmulhrsw         m1, [base+pw_8192]
+%else
+    pmulhrsw         m1, [base+pw_16384]
+%endif
+%else
+    movq             m1, [bufyq+xq*2]
+%endif
+    punpcklwd        m1, [base+pw_1]
+    pmaddwd          m1, m12
+    paddd            m0, m1
+
+    movu             m1, [bufq+xq*2-4]      ; y=0,x=[-2,+5]
+    pshufd           m2, m1, q3321
+    pxor             m3, m3
+    pcmpgtw          m3, m2
+    punpcklwd        m2, m3                 ; y=0,x=[0,3] in dword
+.x_loop_ar2_inner:
+    pmaddwd          m3, m1, m11
+    paddd            m3, m0
+    psrldq           m0, 4                  ; shift top to next pixel
+    psrad            m3, [fg_dataq+FGData.ar_coeff_shift]
+    ; we do not need to packssdw since we only care about one value
+    paddd            m3, m2
+    packssdw         m3, m3
+    pminsw           m3, m13
+    pmaxsw           m3, m14
+    psrldq           m1, 2
+    pslldq           m3, 2
+    psrldq           m2, 4
+%if cpuflag(sse4)
+    pblendw          m1, m3, 00000010b
+%else
+    pand             m1, m15
+    pandn            m4, m15, m3
+    por              m1, m4
+%endif
+    ; overwrite previous pixel, should be ok
+    movd  [bufq+xq*2-2], m1
+    inc              xq
+    jz .x_loop_ar2_end
+    test             xq, 3
+    jnz .x_loop_ar2_inner
+    jmp .x_loop_ar2
+
+.x_loop_ar2_end:
+    add            bufq, 82*2
+    add           bufyq, 82*2<<%3
+    dec              hd
+    jg .y_loop_ar2
+%if ARCH_X86_32
+%undef m13
+%undef m14
+%undef m15
+%endif
+    RET
+
+.ar3:
+%if ARCH_X86_64
+    DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift
+%if WIN64
+    mov              r6, rsp
+    and             rsp, ~15
+    sub             rsp, 96
+    %define         tmp  rsp
+%else
+    %define         tmp  rsp+stack_offset-120
+%endif
+%else
+    DEFINE_ARGS buf, bufy, pic_reg, fg_data, uv, shift
+    ALLOC_STACK  -16*14
+    mov           bufyq, r1m
+    mov             uvd, r3m
+    %define         tmp  rsp
+%endif
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    imul            uvd, 28
+    SPLATW           m4, [base+round_vals-12+shiftq*2]
+    pxor             m5, m5
+    pcmpgtw          m5, m4
+    punpcklwd        m4, m5
+%if ARCH_X86_64
+    sar          bdmaxd, 1
+    SPLATW           m6, bdmaxd                 ; max_grain
+%else
+    SPLATW           m6, r4m
+    psraw            m6, 1
+%endif
+    pcmpeqw          m7, m7
+%if !cpuflag(sse4)
+    pcmpeqw          m3, m3
+    psrldq           m3, 14
+    pslldq           m3, 4
+    pxor             m3, m7
+%endif
+    pxor             m7, m6                     ; min_grain
+%if %2 && cpuflag(sse4)
+    SPLATW           m3, [base+hmul_bits+2+%3*2]
+%endif
+
+%if ARCH_X86_64
+    SWAP              3, 11
+    SWAP              4, 12
+    SWAP              6, 14
+    SWAP              7, 15
+%else
+%define m11 [rsp+ 9*16]
+%define m12 [rsp+10*16]
+%define m14 [rsp+12*16]
+%define m15 [rsp+13*16]
+    mova            m11, m3
+    mova            m12, m4
+    mova            m14, m6
+    mova            m15, m7
+%endif
+
+    ; cf from y=-3,x=-3 until y=-3,x=-2
+    movu             m0, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 0]
+    pxor             m1, m1
+    pcmpgtb          m1, m0
+    punpckhbw        m2, m0, m1
+    punpcklbw        m0, m1
+    pshufd           m1, m0, q0000
+    pshufd           m3, m0, q1111
+    pshufd           m4, m0, q2222
+    pshufd           m0, m0, q3333
+    pshufd           m5, m2, q0000
+    pshufd           m6, m2, q1111
+    mova     [tmp+16*0], m1
+    mova     [tmp+16*1], m3
+    mova     [tmp+16*2], m4
+    mova     [tmp+16*3], m0
+    mova     [tmp+16*4], m5
+    mova     [tmp+16*5], m6
+    pshufd           m6, m2, q2222
+    pshufd           m7, m2, q3333
+
+    ; cf from y=-1,x=-1 to y=0,x=-1 + luma component
+    movu             m0, [fg_dataq+FGData.ar_coeffs_uv+uvq+16]
+    pxor             m1, m1
+    pcmpgtb          m1, m0
+    punpckhbw        m2, m0, m1                 ; luma
+    punpcklbw        m0, m1
+    pshufd           m3, m0, q3232
+    psrldq           m5, m0, 10
+    ; y=0,x=[-3 to -1] + "1.0" for current pixel
+    pinsrw           m5, [base+round_vals-10+shiftq*2], 3
+    ; y=-1,x=[-1 to +2]
+    pshufd           m1, m0, q0000
+    pshufd           m0, m0, q1111
+    ; y=-1,x=+3 + luma
+    punpcklwd        m3, m2
+    pshufd           m3, m3, q0000
+
+%if ARCH_X86_64
+    SWAP              1, 8
+    SWAP              0, 9
+    SWAP              3, 10
+    SWAP              5, 13
+    DEFINE_ARGS buf, bufy, fg_data, h, x
+%else
+%define m8  [rsp+ 6*16]
+%define m9  [rsp+ 7*16]
+%define m10 [rsp+ 8*16]
+%define m13 [rsp+11*16]
+    mova             m8, m1
+    mova             m9, m0
+    mova            m10, m3
+    mova            m13, m5
+    DEFINE_ARGS buf, bufy, pic_reg, fg_data, h, x
+%endif
+%if %2
+    sub            bufq, 2*(82*(73-35*%3)+44-(82*3+41))
+%else
+    sub            bufq, 2*(82*69+3)
+%endif
+    add           bufyq, 2*(79+82*3)
+    mov              hd, 70-35*%3
+.y_loop_ar3:
+    mov              xq, -(76>>%2)
+
+.x_loop_ar3:
+    ; first line
+    movu             m0, [bufq+xq*2-82*6-6+ 0]      ; y=-3,x=[-3,+4]
+    movd             m1, [bufq+xq*2-82*6-6+16]      ; y=-3,x=[+5,+6]
+    palignr          m2, m1, m0, 2                  ; y=-3,x=[-2,+5]
+    palignr          m1, m1, m0, 12                 ; y=-3,x=[+3,+6]
+    punpckhwd        m3, m0, m2                     ; y=-3,x=[+1/+2,+2/+3,+3/+4,+4/+5]
+    punpcklwd        m0, m2                         ; y=-3,x=[-3/-2,-2/-1,-1/+0,+0/+1]
+    shufps           m2, m0, m3, q1032              ; y=-3,x=[-1/+0,+0/+1,+1/+2,+2/+3]
+
+    pmaddwd          m0, [tmp+0*16]
+    pmaddwd          m2, [tmp+1*16]
+    pmaddwd          m3, [tmp+2*16]
+    paddd            m0, m2
+    paddd            m0, m3                         ; first 6 x of top y
+
+    ; second line [m0/1 are busy]
+    movu             m2, [bufq+xq*2-82*4-6+ 0]      ; y=-2,x=[-3,+4]
+    movd             m3, [bufq+xq*2-82*4-6+16]      ; y=-2,x=[+5,+6]
+    punpcklwd        m1, m2                         ; y=-3/-2,x=[+3/-3,+4/-2,+5/-1,+6/+0]
+    palignr          m4, m3, m2, 2                  ; y=-2,x=[-2,+5]
+    palignr          m3, m3, m2, 4                  ; y=-2,x=[-2,+5]
+    punpckhwd        m5, m4, m3                     ; y=-2,x=[+2/+3,+3/+4,+4/+5,+5/+6]
+    punpcklwd        m4, m3                         ; y=-2,x=[-2/-1,-1/+0,+0/+1,+1/+2]
+    shufps           m3, m4, m5, q1032              ; t=-2,x=[+0/+1,+1/+2,+2/+3,+3/+4]
+    pmaddwd          m1, [tmp+3*16]
+    pmaddwd          m4, [tmp+4*16]
+    pmaddwd          m3, [tmp+5*16]
+    pmaddwd          m5, m6
+    paddd            m1, m4
+    paddd            m3, m5
+    paddd            m0, m1
+    paddd            m0, m3                         ; top 2 lines
+
+    ; third line [m0 is busy] & luma + round
+    movu             m1, [bufq+xq*2-82*2-6+ 0]      ; y=-1,x=[-3,+4]
+    movd             m2, [bufq+xq*2-82*2-6+16]      ; y=-1,x=[+5,+6]
+%if %2
+    movu             m5, [bufyq+xq*4]
+%if %3
+    movu             m4, [bufyq+xq*4+82*2]
+    phaddw           m5, m4
+%else
+    phaddw           m5, m5
+%endif
+%else
+    movq             m5, [bufyq+xq*2]
+%endif
+    palignr          m3, m2, m1, 2                  ; y=-1,x=[-2,+5]
+    palignr          m2, m2, m1, 12                 ; y=-1,x=[+3,+6]
+%if %3
+    pshufd           m4, m5, q3232
+    paddw            m5, m4
+%endif
+%if %2
+%if cpuflag(sse4)
+    pmulhrsw         m5, m11
+%elif %3
+    pmulhrsw         m5, [base+pw_8192]
+%else
+    pmulhrsw         m5, [base+pw_16384]
+%endif
+%endif
+    punpckhwd        m4, m1, m3                     ; y=-1,x=[+1/+2,+2/+3,+3/+4,+4/+5]
+    punpcklwd        m1, m3                         ; y=-1,x=[-3/-2,-2/-1,-1/+0,+0/+1]
+    shufps           m3, m1, m4, q1032              ; y=-1,x=[-1/+0,+0/+1,+1/+2,+2/+3]
+    punpcklwd        m2, m5
+    pmaddwd          m1, m7
+    pmaddwd          m3, m8
+    pmaddwd          m4, m9
+    pmaddwd          m2, m10
+    paddd            m1, m3
+    paddd            m4, m2
+    paddd            m0, m12                        ; += round
+    paddd            m1, m4
+    paddd            m0, m1
+
+    movu             m1, [bufq+xq*2-6]      ; y=0,x=[-3,+4]
+.x_loop_ar3_inner:
+    pmaddwd          m2, m1, m13
+    pshufd           m3, m2, q1111
+    paddd            m2, m3                 ; left+cur
+    paddd            m2, m0                 ; add top
+    psrldq           m0, 4
+    psrad            m2, [fg_dataq+FGData.ar_coeff_shift]
+    packssdw         m2, m2
+    pminsw           m2, m14
+    pmaxsw           m2, m15
+    pslldq           m2, 4
+    psrldq           m1, 2
+%if cpuflag(sse4)
+    pblendw          m1, m2, 00000100b
+%else
+    pand             m1, m11
+    pandn            m3, m11, m2
+    por              m1, m3
+%endif
+    ; overwrite previous pixels, should be ok
+    movq  [bufq+xq*2-4], m1
+    inc              xq
+    jz .x_loop_ar3_end
+    test             xq, 3
+    jnz .x_loop_ar3_inner
+    jmp .x_loop_ar3
+
+.x_loop_ar3_end:
+    add            bufq, 82*2
+    add           bufyq, 82*2<<%3
+    dec              hd
+    jg .y_loop_ar3
+%if WIN64
+    mov             rsp, r6
+%elif ARCH_X86_32
+%undef m8
+%undef m9
+%undef m10
+%undef m11
+%undef m12
+%undef m13
+%undef m14
+%undef m15
+%endif
+    RET
+%endmacro
+
+generate_grain_uv_fn 420, 1, 1
+generate_grain_uv_fn 422, 1, 0
+generate_grain_uv_fn 444, 0, 0
+
+%macro SCRATCH 3
+%if ARCH_X86_32
+    mova [rsp+%3*mmsize], m%1
+%define m%2 [rsp+%3*mmsize]
+%else
+    SWAP             %1, %2
+%endif
+%endmacro
+
+INIT_XMM ssse3
+%if ARCH_X86_32
+%if STACK_ALIGNMENT < mmsize
+cglobal fgy_32x32xn_16bpc, 0, 7, 8, 0-(8 * mmsize + 12 * gprsize), \
+        dst, src, scaling, unused1, fg_data, picptr, unused2
+    ; copy stack arguments to new position post-alignment, so that we
+    ; don't have to keep the old stack location in a separate register
+    mov              r0, r0m
+    mov              r1, r2m
+    mov              r2, r4m
+    mov              r3, r6m
+    mov              r4, r7m
+    mov              r5, r8m
+
+%define r0m [rsp+8*mmsize+ 3*gprsize]
+%define r2m [rsp+8*mmsize+ 5*gprsize]
+%define r4m [rsp+8*mmsize+ 7*gprsize]
+%define r6m [rsp+8*mmsize+ 9*gprsize]
+%define r7m [rsp+8*mmsize+10*gprsize]
+%define r8m [rsp+8*mmsize+11*gprsize]
+
+    mov             r0m, r0
+    mov             r2m, r1
+    mov             r4m, r2
+    mov             r6m, r3
+    mov             r7m, r4
+    mov             r8m, r5
+%else
+cglobal fgy_32x32xn_16bpc, 0, 7, 8, 8 * mmsize + 4 * gprsize, \
+        dst, src, scaling, unused1, fg_data, picptr, unused2
+%endif
+    mov            srcq, srcm
+    mov        scalingq, r5m
+    mov        fg_dataq, r3m
+%if STACK_ALIGNMENT < mmsize
+    mov              r6, r9m
+
+%define r9m [rsp+8*mmsize+ 4*gprsize]
+%define r3m [rsp+8*mmsize+ 6*gprsize]
+%define r5m [rsp+8*mmsize+ 8*gprsize]
+
+    mov             r9m, r6
+%endif
+    LEA              r5, $$
+%define base r5-$$
+    mov             r5m, picptrq
+%else
+cglobal fgy_32x32xn_16bpc, 6, 15, 16, dst, src, stride, fg_data, w, scaling, grain_lut
+    lea              r8, [pb_mask]
+%define base r8-pb_mask
+%endif
+    mov             r6d, [fg_dataq+FGData.scaling_shift]
+    SPLATW           m3, [base+mul_bits+r6*2-14]
+    mov             r6d, [fg_dataq+FGData.clip_to_restricted_range]
+%if ARCH_X86_32
+    DECLARE_REG_TMP   0, 3
+%else
+    DECLARE_REG_TMP   9, 10
+%endif
+    mov             t0d, r9m        ; bdmax
+    sar             t0d, 11         ; is_12bpc
+    inc             t0d
+    mov             t1d, r6d
+    imul            t1d, t0d
+    dec             t0d
+    SPLATW           m5, [base+min+t1*2]
+    lea             t0d, [t0d*3]
+    lea             t0d, [r6d*2+t0d]
+    SPLATW           m4, [base+max+t0*2]
+    SPLATW           m2, r9m
+
+    pcmpeqw          m1, m1
+    psraw            m7, m2, 1              ; max_grain
+    pxor             m1, m7                 ; min_grain
+    SPLATD           m6, [base+pd_16]
+
+    SCRATCH           1,  9, 0
+    SCRATCH           2, 10, 1
+    SCRATCH           3, 11, 2
+    SCRATCH           4, 12, 3
+    SCRATCH           5, 13, 4
+    SCRATCH           6, 14, 5
+    SCRATCH           7, 15, 6
+
+    mova             m6, [base+pw_27_17_17_27]   ; for horizontal filter
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, unused2
+    DECLARE_REG_TMP   0
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused1, \
+                sby, see
+    DECLARE_REG_TMP   7
+%endif
+
+    mov            sbyd, r8m
+    movzx           t0d, byte [fg_dataq+FGData.overlap_flag]
+    test            t0d, t0d
+    jz .no_vertical_overlap
+    test           sbyd, sbyd
+    jnz .vertical_overlap
+.no_vertical_overlap:
+    mov       dword r8m, t0d
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, see, fg_data, picptr, unused
+    imul           seed, (173 << 24) | 37
+%else
+    imul           seed, sbyd, (173 << 24) | 37
+%endif
+    add            seed, (105 << 24) | 178
+    rol            seed, 8
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, src_bak
+
+    mov             r3m, seed
+    mov              wq, r4m
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                unused1, unused2, see, src_bak
+%endif
+
+    lea        src_bakq, [srcq+wq*2]
+    mov            r9mp, src_bakq
+    neg              wq
+    sub           dstmp, srcq
+%if ARCH_X86_32
+    mov             r4m, wq
+%endif
+
+.loop_x:
+%if ARCH_X86_32
+    mov            seed, r3m
+%endif
+    mov             r6d, seed
+    or             seed, 0xEFF4
+    shr             r6d, 1
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, src_bak
+
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    shr           offxd, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyq, [offyq+offxq*2+747] ; offy*stride+offx
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, src_bak
+%endif
+
+.loop_x_odd:
+    movzx            hd, word r7m
+    mov      grain_lutq, grain_lutmp
+.loop_y:
+    ; src
+    pand             m0, m10, [srcq+ 0]
+    pand             m1, m10, [srcq+16]          ; m0-1: src as word
+
+    ; scaling[src]
+%if ARCH_X86_32
+    vpgatherdw       m2, m0, scalingq-1, r0, r5, 8, 1, m4
+    vpgatherdw       m3, m1, scalingq-1, r0, r5, 8, 1, m4
+%else
+    vpgatherdw       m2, m0, scalingq-1, r11, r13, 8, 1, m4
+    vpgatherdw       m3, m1, scalingq-1, r11, r13, 8, 1, m4
+%endif
+    REPX   {psrlw x, 8}, m2, m3
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m4, [grain_lutq+offxyq*2]
+    movu             m5, [grain_lutq+offxyq*2+16]
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    REPX {pmullw x, m11}, m2, m3
+    pmulhrsw         m4, m2
+    pmulhrsw         m5, m3
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m4
+    paddw            m1, m5
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    movifnidn      dstq, dstmp
+    mova [dstq+srcq+ 0], m0
+    mova [dstq+srcq+16], m1
+
+    add            srcq, r2mp               ; src += stride
+    add      grain_lutq, 82*2
+    dec              hd
+    jg .loop_y
+
+%if ARCH_X86_32
+    add            r4mp, 16
+%else
+    add              wq, 16
+%endif
+    jge .end
+%if ARCH_X86_32
+    mov            srcq, r9mp
+    add            srcq, r4mp
+    add            srcq, r4mp
+%else
+    mov        src_bakq, r9mp
+    lea            srcq, [src_bakq+wq*2]
+%endif
+    btc       dword r8m, 2
+    jc .next_blk
+    add          offxyd, 16
+    test      dword r8m, 2
+    jz .loop_x_odd
+%if ARCH_X86_32
+    add dword [rsp+8*mmsize+1*gprsize], 16
+%else
+    add            r12d, 16                 ; top_offxy += 16
+%endif
+    jmp .loop_x_odd_v_overlap
+
+.next_blk:
+    test      dword r8m, 1
+    jz .loop_x
+
+    ; r8m = sbym
+    test      dword r8m, 2
+    jnz .loop_x_hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+.loop_x_h_overlap:
+%if ARCH_X86_32
+    add          offxyd, 16
+    mov [rsp+8*mmsize+0*gprsize], offxyd
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, src_bak
+    mov            seed, r3m
+%endif
+
+    mov             r6d, seed
+    or             seed, 0xEFF4
+    shr             r6d, 1
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, h, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, src_bak, left_offxy
+
+    lea     left_offxyd, [offyd+16]         ; previous column's offy*stride+offx
+
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    shr           offxd, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyq, [offyq+offxq*2+747] ; offy*stride+offx
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, src_bak, left_offxy
+%endif
+
+    mov              hd, dword r7m
+    mov      grain_lutq, grain_lutmp
+.loop_y_h_overlap:
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m5, [grain_lutq+offxyq*2]
+%if ARCH_X86_32
+    mov              r5, [rsp+8*mmsize+0*gprsize]
+    movd             m4, [grain_lutq+r5*2]
+%else
+    movd             m4, [grain_lutq+left_offxyq*2]
+%endif
+    punpcklwd        m4, m5
+    pmaddwd          m4, m6
+    paddd            m4, m14
+    psrad            m4, 5
+    packssdw         m4, m4
+    pminsw           m4, m15
+    pmaxsw           m4, m9
+    shufps           m4, m5, q3210
+
+    ; src
+    pand             m0, m10, [srcq+ 0]
+    pand             m1, m10, [srcq+16]          ; m0-1: src as word
+
+    ; scaling[src]
+%if ARCH_X86_32
+    vpgatherdw       m2, m0, scalingq-1, r0, r5, 8, 1, m5
+    vpgatherdw       m3, m1, scalingq-1, r0, r5, 8, 1, m5
+%else
+    vpgatherdw       m2, m0, scalingq-1, r13, r14, 8, 1, m5
+    vpgatherdw       m3, m1, scalingq-1, r13, r14, 8, 1, m5
+%endif
+    REPX   {psrlw x, 8}, m2, m3
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    movu             m5, [grain_lutq+offxyq*2+16]
+    REPX {pmullw x, m11}, m2, m3
+    pmulhrsw         m4, m2
+    pmulhrsw         m5, m3
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m4
+    paddw            m1, m5
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    movifnidn      dstq, dstmp
+    mova [dstq+srcq+ 0], m0
+    mova [dstq+srcq+16], m1
+
+    add            srcq, r2mp
+    add      grain_lutq, 82*2
+    dec              hd
+    jg .loop_y_h_overlap
+
+%if ARCH_X86_32
+    add            r4mp, 16
+%else
+    add              wq, 16
+%endif
+    jge .end
+%if ARCH_X86_32
+    mov            srcq, r9mp
+    add            srcq, r4mp
+    add            srcq, r4mp
+%else
+    mov        src_bakq, r9mp
+    lea            srcq, [src_bakq+wq*2]
+%endif
+    or        dword r8m, 4
+    add          offxyd, 16
+
+    ; r8m = sbym
+    test      dword r8m, 2
+    jz .loop_x_odd
+%if ARCH_X86_32
+    add dword [rsp+8*mmsize+1*gprsize], 16
+%else
+    add            r12d, 16                 ; top_offxy += 16
+%endif
+    jmp .loop_x_odd_v_overlap
+
+.end:
+    RET
+
+.vertical_overlap:
+    or              t0d, 2
+    mov             r8m, t0d
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, unused
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused1, \
+                sby, see
+%endif
+
+    movzx          sbyd, sbyb
+%if ARCH_X86_32
+    imul             r4, [fg_dataq+FGData.seed], 0x00010001
+    DEFINE_ARGS dst, src, scaling, sby, see, picptr, unused
+%else
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+%endif
+    imul            t0d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             t0d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             t0d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, t0d
+%if ARCH_X86_32
+    xor            sbyd, seed
+
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, src_bak
+
+    mov             r3m, seed
+    mov              wq, r4m
+%else
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                unused1, unused2, see, src_bak
+%endif
+
+    lea        src_bakq, [srcq+wq*2]
+    mov            r9mp, src_bakq
+    neg              wq
+    sub           dstmp, srcq
+%if ARCH_X86_32
+    mov             r4m, wq
+%endif
+
+.loop_x_v_overlap:
+%if ARCH_X86_32
+    mov              r5, r5m
+    SPLATD           m7, [base+pw_27_17_17_27]
+    mov            seed, r3m
+%else
+    SPLATD           m7, [pw_27_17_17_27]
+%endif
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            t0b                     ; parity of top_seed
+    shr            seed, 16
+    shl             t0d, 16
+    test           seeb, seeh
+    setp            t0b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             t0d, r6d
+    mov            seed, t0d
+    ror            seed, 1                  ; updated (cur_seed << 16) | top_seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, src_bak, unused, top_offxy
+
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    ror           offxd, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyq, [offyq+offxq*2+0x10001*747+32*82]
+
+%if ARCH_X86_32
+    DEFINE_ARGS top_offxy, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, src_bak, unused, top_offxy
+%endif
+
+    movzx    top_offxyd, offxyw
+%if ARCH_X86_32
+    mov [rsp+8*mmsize+1*gprsize], top_offxyd
+
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+    shr          offxyd, 16
+
+.loop_x_odd_v_overlap:
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    SPLATD           m7, [PIC_ptr(pw_27_17_17_27)]
+    mov              hd, dword r7m
+    mov      grain_lutq, grain_lutmp
+.loop_y_v_overlap:
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq*2]
+%if ARCH_X86_32
+    mov              r5, [rsp+8*mmsize+1*gprsize]
+    movu             m2, [grain_lutq+r5*2]
+%else
+    movu             m2, [grain_lutq+top_offxyq*2]
+%endif
+    punpckhwd        m4, m2, m3
+    punpcklwd        m2, m3
+    REPX {pmaddwd x, m7}, m4, m2
+    REPX {paddd   x, m14}, m4, m2
+    REPX {psrad   x, 5}, m4, m2
+    packssdw         m2, m4
+    pminsw           m2, m15
+    pmaxsw           m2, m9
+    movu             m4, [grain_lutq+offxyq*2+16]
+%if ARCH_X86_32
+    movu             m3, [grain_lutq+r5*2+16]
+%else
+    movu             m3, [grain_lutq+top_offxyq*2+16]
+%endif
+    punpckhwd        m5, m3, m4
+    punpcklwd        m3, m4
+    REPX {pmaddwd x, m7}, m5, m3
+    REPX {paddd   x, m14}, m5, m3
+    REPX {psrad   x, 5}, m5, m3
+    packssdw         m3, m5
+    pminsw           m3, m15
+    pmaxsw           m3, m9
+
+    ; src
+    pand             m0, m10, [srcq+ 0]          ; m0-1: src as word
+    pand             m1, m10, [srcq+16]          ; m0-1: src as word
+
+    ; scaling[src]
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+%if ARCH_X86_32
+    vpgatherdw       m4, m0, scalingq-1, r0, r5, 8, 1, m5
+%else
+    vpgatherdw       m4, m0, scalingq-1, r11, r13, 8, 1, m5
+%endif
+    psrlw            m4, 8
+    pmullw           m4, m11
+    pmulhrsw         m4, m2
+%if ARCH_X86_32
+    vpgatherdw       m5, m1, scalingq-1, r0, r5, 8, 1, m2
+%else
+    vpgatherdw       m5, m1, scalingq-1, r11, r13, 8, 1, m2
+%endif
+    psrlw            m5, 8
+    pmullw           m5, m11
+    pmulhrsw         m5, m3
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m4
+    paddw            m1, m5
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    movifnidn      dstq, dstmp
+    mova [dstq+srcq+ 0], m0
+    mova [dstq+srcq+16], m1
+
+    add            srcq, r2mp
+    add      grain_lutq, 82*2
+    dec              hw
+    jz .end_y_v_overlap
+    ; 2 lines get vertical overlap, then fall back to non-overlap code for
+    ; remaining (up to) 30 lines
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    SPLATD           m7, [PIC_ptr(pw_27_17_17_27)+4]
+    xor              hd, 0x10000
+    test             hd, 0x10000
+    jnz .loop_y_v_overlap
+    jmp .loop_y
+
+.end_y_v_overlap:
+%if ARCH_X86_32
+    add            r4mp, 16
+%else
+    add              wq, 16
+%endif
+    jge .end_hv
+%if ARCH_X86_32
+    mov            srcq, r9mp
+    add            srcq, r4mp
+    add            srcq, r4mp
+%else
+    mov        src_bakq, r9mp
+    lea            srcq, [src_bakq+wq*2]
+%endif
+    btc       dword r8m, 2
+    jc .next_blk_v
+%if ARCH_X86_32
+    add dword [rsp+8*mmsize+1*gprsize], 16
+%else
+    add      top_offxyd, 16
+%endif
+    add          offxyd, 16
+    jmp .loop_x_odd_v_overlap
+
+.next_blk_v:
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump
+    ; back to .loop_x_v_overlap, and instead always fall-through to
+    ; h+v overlap
+
+.loop_x_hv_overlap:
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, src_bak
+
+    mov              r0, [rsp+8*mmsize+1*gprsize]
+    add              r3, 16
+    add              r0, 16
+    mov [rsp+8*mmsize+0*gprsize], r3 ; left_offxy
+    mov [rsp+8*mmsize+2*gprsize], r0 ; topleft_offxy
+
+    mov            seed, r3m
+    xor              r0, r0
+%else
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+%endif
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            t0b                     ; parity of top_seed
+    shr            seed, 16
+    shl             t0d, 16
+    test           seeb, seeh
+    setp            t0b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             t0d, r6d
+    mov            seed, t0d
+    ror            seed, 1                  ; updated (cur_seed << 16) | top_seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS  dst, src, scaling, offy, w, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, src_bak, left_offxy, top_offxy, topleft_offxy
+
+    lea  topleft_offxyq, [top_offxyq+16]
+    lea     left_offxyq, [offyq+16]
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    ror           offxd, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyq, [offyq+offxq*2+0x10001*747+32*82]
+
+%if ARCH_X86_32
+    DEFINE_ARGS top_offxy, src, scaling, offxy, w, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, src_bak, left_offxy, top_offxy, topleft_offxy
+%endif
+
+    movzx    top_offxyd, offxyw
+%if ARCH_X86_32
+    mov [rsp+8*mmsize+1*gprsize], top_offxyd
+
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+    shr          offxyd, 16
+
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    SPLATD           m7, [PIC_ptr(pw_27_17_17_27)]
+
+    movzx            hd, word r7m
+    mov      grain_lutq, grain_lutmp
+.loop_y_hv_overlap:
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m2, [grain_lutq+offxyq*2]
+%if ARCH_X86_32
+    mov              r0, [rsp+8*mmsize+1*gprsize] ; top_offxy
+    mov              r5, [rsp+8*mmsize+0*gprsize] ; left_offxy
+    movu             m4, [grain_lutq+r0*2]
+    movd             m5, [grain_lutq+r5*2]
+    mov              r5, [rsp+8*mmsize+2*gprsize] ; topleft_offxy
+    movd             m3, [grain_lutq+r5*2]
+%else
+    movu             m4, [grain_lutq+top_offxyq*2]
+    movd             m5, [grain_lutq+left_offxyq*2]
+    movd             m3, [grain_lutq+topleft_offxyq*2]
+%endif
+    ; do h interpolation first (so top | top/left -> top, left | cur -> cur)
+    punpcklwd        m5, m2
+    punpcklwd        m3, m4
+    REPX {pmaddwd x, m6}, m5, m3
+    REPX {paddd   x, m14}, m5, m3
+    REPX {psrad   x, 5}, m5, m3
+    packssdw         m5, m3
+    pminsw           m5, m15
+    pmaxsw           m5, m9
+    shufps           m3, m5, m2, q3210
+    shufps           m5, m4, q3232
+    ; followed by v interpolation (top | cur -> cur)
+    movu             m0, [grain_lutq+offxyq*2+16]
+%if ARCH_X86_32
+    movu             m1, [grain_lutq+r0*2+16]
+%else
+    movu             m1, [grain_lutq+top_offxyq*2+16]
+%endif
+    punpcklwd        m2, m5, m3
+    punpckhwd        m5, m3
+    punpcklwd        m3, m1, m0
+    punpckhwd        m1, m0
+    REPX {pmaddwd x, m7}, m2, m5, m3, m1
+    REPX {paddd   x, m14}, m2, m5, m3, m1
+    REPX {psrad   x, 5}, m2, m5, m3, m1
+    packssdw         m2, m5
+    packssdw         m3, m1
+    REPX {pminsw x, m15}, m2, m3
+    REPX {pmaxsw x, m9}, m2, m3
+
+    ; src
+    pand             m0, m10, [srcq+ 0]
+    pand             m1, m10, [srcq+16]          ; m0-1: src as word
+
+    ; scaling[src]
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+%if ARCH_X86_32
+    vpgatherdw       m4, m0, scalingq-1, r0, r5, 8, 1, m5
+%else
+    vpgatherdw       m4, m0, scalingq-1, r14, r10, 8, 1, m5
+%endif
+    psrlw            m4, 8
+    pmullw           m4, m11
+    pmulhrsw         m2, m4
+%if ARCH_X86_32
+    vpgatherdw       m5, m1, scalingq-1, r0, r5, 8, 1, m4
+%else
+    vpgatherdw       m5, m1, scalingq-1, r14, r10, 8, 1, m4
+%endif
+    psrlw            m5, 8
+    pmullw           m5, m11
+    pmulhrsw         m3, m5
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    movifnidn      dstq, dstmp
+    mova [dstq+srcq+ 0], m0
+    mova [dstq+srcq+16], m1
+
+    add            srcq, r2mp
+    add      grain_lutq, 82*2
+    dec              hw
+    jz .end_y_hv_overlap
+    ; 2 lines get vertical overlap, then fall back to non-overlap code for
+    ; remaining (up to) 30 lines
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    SPLATD           m7, [PIC_ptr(pw_27_17_17_27)+4]
+    xor              hd, 0x10000
+    test             hd, 0x10000
+    jnz .loop_y_hv_overlap
+    jmp .loop_y_h_overlap
+
+.end_y_hv_overlap:
+    or        dword r8m, 4
+%if ARCH_X86_32
+    add            r4mp, 16
+%else
+    add              wq, 16
+%endif
+    jge .end_hv
+%if ARCH_X86_32
+    mov              r5, r5m
+    add          offxyd, 16
+    add dword [rsp+8*mmsize+1*gprsize], 16 ; top_offxy += 16
+    mov            srcq, r9mp
+    add            srcq, r4mp
+    add            srcq, r4mp
+%else
+    add          offxyd, 16
+    add      top_offxyd, 16
+    mov        src_bakq, r9mp
+    lea            srcq, [src_bakq+wq*2]
+%endif
+    jmp .loop_x_odd_v_overlap
+
+.end_hv:
+    RET
+%if ARCH_X86_32
+    DECLARE_ARG 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+%endif
+
+%macro FGUV_FN 3 ; name, ss_hor, ss_ver
+INIT_XMM ssse3
+%if ARCH_X86_32
+%if STACK_ALIGNMENT < mmsize
+cglobal fguv_32x32xn_i%1_16bpc, 0, 7, 8, 0-(8 * mmsize + 16 * gprsize), \
+        tmp, src, scaling, h, fg_data, picptr, unused
+    mov              r0, r0m
+    mov              r1, r1m
+    mov              r2, r2m
+    mov              r4, r3m
+    mov              r3, r4m
+    mov              r5, r5m
+%define r0m [rsp+8*mmsize+ 3*gprsize]
+%define r1m [rsp+8*mmsize+ 4*gprsize]
+%define r2m [rsp+8*mmsize+ 5*gprsize]
+%define r3m [rsp+8*mmsize+ 6*gprsize]
+%define r4m [rsp+8*mmsize+ 7*gprsize]
+%define r5m [rsp+8*mmsize+ 8*gprsize]
+    mov             r0m, r0
+    mov             r2m, r2
+    mov             r4m, r3
+    mov             r5m, r5
+
+    mov              r0, r6m
+    mov              r2, r7m
+    mov              r3, r8m
+    mov              r5, r9m
+%define r6m [rsp+8*mmsize+ 9*gprsize]
+%define r7m [rsp+8*mmsize+10*gprsize]
+%define r8m [rsp+8*mmsize+11*gprsize]
+%define r9m [rsp+8*mmsize+12*gprsize]
+    mov             r6m, r0
+    mov             r7m, r2
+    mov             r8m, r3
+    mov             r9m, r5
+
+    mov              r2, r10m
+    mov              r3, r11m
+    mov              r5, r12m
+    mov              r0, r13m
+%define r10m [rsp+8*mmsize+13*gprsize]
+%define r11m [rsp+8*mmsize+14*gprsize]
+%define r12m [rsp+8*mmsize+15*gprsize]
+    mov            r10m, r2
+    mov            r11m, r3
+    mov            r12m, r5
+
+    SPLATW           m2, r13m
+%else
+cglobal fguv_32x32xn_i%1_16bpc, 0, 7, 8, 8 * mmsize + (4) * gprsize, \
+        tmp, src, scaling, h, fg_data, picptr, unused
+    mov            srcq, srcm
+    mov        fg_dataq, r3m
+%endif
+    LEA              r5, $$
+%define base r5-$$
+
+    DECLARE_REG_TMP   0, 2, 3
+%else
+cglobal fguv_32x32xn_i%1_16bpc, 6, 15, 16, dst, src, stride, fg_data, w, scaling, \
+                                      grain_lut, h, sby, luma, lstride, uv_pl, is_id
+%define base r8-pb_mask
+    lea              r8, [pb_mask]
+
+    DECLARE_REG_TMP   9, 10, 11
+%endif
+    mov             r6d, [fg_dataq+FGData.scaling_shift]
+    SPLATW           m3, [base+mul_bits+r6*2-14]
+    mov             r6d, [fg_dataq+FGData.clip_to_restricted_range]
+%if STACK_ALIGNMENT >= mmsize
+    mov             t0d, r13m               ; bdmax
+%endif
+    sar             t0d, 11                 ; is_12bpc
+    inc             t0d
+    mov             t1d, r6d
+    imul            t1d, t0d
+    dec             t0d
+    SPLATW           m5, [base+min+t1*2]
+    lea             t1d, [t0d*3]
+    mov             t2d, r12m
+    inc             t2d
+    imul            r6d, t2d
+    add             t1d, r6d
+    SPLATW           m4, [base+max+t1*2]
+%if STACK_ALIGNMENT >= mmsize
+    SPLATW           m2, r13m
+%endif
+
+    SCRATCH           2, 10, 2
+    SCRATCH           3, 11, 3
+    SCRATCH           4, 12, 4
+    SCRATCH           5, 13, 5
+
+%define mzero m7
+
+%if %3
+    SPLATD           m2, [base+pw_23_22]
+%endif
+
+%if ARCH_X86_32
+    mov        scalingq, r5m
+    mov             r5m, r5
+%else
+    mov           r13mp, strideq
+%endif
+
+    pcmpeqw          m0, m0
+    psraw            m1, m10, 1
+    pxor             m0, m1
+
+    SCRATCH           0,  8, 0
+    SCRATCH           1,  9, 1
+
+    cmp byte [fg_dataq+FGData.chroma_scaling_from_luma], 0
+    jne .csfl
+
+%macro %%FGUV_32x32xN_LOOP 3 ; not-csfl, ss_h, ss_v
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap
+
+    DECLARE_REG_TMP    0
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused, sby, see, overlap
+
+    DECLARE_REG_TMP    9
+%endif
+
+%if %1
+    mov             r6d, r11m
+    SPLATW           m0, [fg_dataq+FGData.uv_mult+r6*4]
+    SPLATW           m1, [fg_dataq+FGData.uv_luma_mult+r6*4]
+    punpcklwd        m6, m1, m0
+    SPLATW           m5, [fg_dataq+FGData.uv_offset+r6*4]
+    SPLATD           m7, [base+pw_4+t0*4]
+    pmullw           m5, m7
+%else
+    SPLATD           m6, [base+pd_16]
+%if %2
+    mova             m5, [base+pw_23_22]
+%else
+    mova             m5, [base+pw_27_17_17_27]
+%endif
+%endif
+
+    SCRATCH           6, 14, 6
+    SCRATCH           5, 15, 7
+
+%if ARCH_X86_32
+    DECLARE_REG_TMP   0
+%else
+    DECLARE_REG_TMP   7
+%endif
+
+    mov            sbyd, r8m
+    mov             t0d, [fg_dataq+FGData.overlap_flag]
+    test            t0d, t0d
+    jz %%no_vertical_overlap
+    test           sbyd, sbyd
+    jnz %%vertical_overlap
+
+%%no_vertical_overlap:
+    mov             r8m, t0d
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, see, fg_data, picptr, overlap
+    imul           seed, (173 << 24) | 37
+%else
+    imul           seed, sbyd, (173 << 24) | 37
+%endif
+    add            seed, (105 << 24) | 178
+    rol            seed, 8
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, luma
+
+    mov            dstq, r0mp
+    mov           lumaq, r9mp
+    mov              wq, r4m
+    lea              r3, [srcq+wq*2]
+    mov            r1mp, r3
+    lea              r3, [dstq+wq*2]
+    mov           r11mp, r3
+    lea              r3, [lumaq+wq*(2<<%2)]
+    mov           r12mp, r3
+%if %3
+    shl           r10mp, 1
+%endif
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                unused2, unused3, see, unused4, unused5, unused6, luma, lstride
+
+    mov        lstrideq, r10mp
+%if %3
+    add        lstrideq, lstrideq
+%endif
+    mov           lumaq, r9mp
+    lea             r10, [srcq+wq*2]
+    lea             r11, [dstq+wq*2]
+    lea             r12, [lumaq+wq*(2<<%2)]
+    mov           r10mp, r10
+    mov           r11mp, r11
+    mov           r12mp, r12
+%endif
+    neg              wq
+%if ARCH_X86_32
+    mov           r4mp, wq
+%endif
+
+%%loop_x:
+%if ARCH_X86_32
+    mov            seed, r3m
+%endif
+
+    mov             r6d, seed
+    or             seed, 0xEFF4
+    shr             r6d, 1
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, w, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, unused1, unused2, unused3, luma, lstride
+
+    mov           offxd, seed
+    mov           offyd, seed
+%endif
+    ror           offyd, 8
+    shr           offxd, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyq, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)]  ; offy*stride+offx
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, unused1, unused2, unused3, luma, lstride
+%endif
+
+%if %2 == 0
+%%loop_x_odd:
+%endif
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+%%loop_y:
+    ; src
+    mova             m0, [srcq]
+    mova             m1, [srcq+16]          ; m0-1: src as word
+
+    ; luma_src
+    pxor          mzero, mzero
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, luma, grain_lut
+
+    mov           lumaq, r9m
+%endif
+    mova             m4, [lumaq+ 0]
+    mova             m6, [lumaq+(16<<%2)]
+%if %2
+    phaddw           m4, [lumaq+16]
+    phaddw           m6, [lumaq+48]
+%endif
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov             r9m, lumaq
+%endif
+%if %2
+    pavgw            m4, mzero
+    pavgw            m6, mzero
+%endif
+
+%if %1
+    punpckhwd        m3, m4, m0
+    punpcklwd        m4, m0
+    punpckhwd        m5, m6, m1
+    punpcklwd        m6, m1                 ; { luma, chroma }
+    REPX {pmaddwd x, m14}, m3, m4, m5, m6
+    REPX {psrad   x, 6}, m3, m4, m5, m6
+    packssdw         m4, m3
+    packssdw         m6, m5
+    REPX {paddw x, m15}, m4, m6
+    REPX {pmaxsw x, mzero}, m4, m6
+    REPX {pminsw x, m10}, m4, m6             ; clip_pixel()
+%else
+    REPX  {pand x, m10}, m4, m6
+%endif
+
+    ; scaling[luma_src]
+%if ARCH_X86_32
+    vpgatherdw       m3, m4, scalingq-1, r0, r5, 8, 1
+    vpgatherdw       m5, m6, scalingq-1, r0, r5, 8, 1
+%else
+    vpgatherdw       m3, m4, scalingq-1, r10, r12, 8, 1
+    vpgatherdw       m5, m6, scalingq-1, r10, r12, 8, 1
+%endif
+    REPX   {psrlw x, 8}, m3, m5
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m4, [grain_lutq+offxyq*2]
+    movu             m6, [grain_lutq+offxyq*2+16]
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    REPX {pmullw x, m11}, m3, m5
+    pmulhrsw         m4, m3
+    pmulhrsw         m6, m5
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m4
+    paddw            m1, m6
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    movifnidn      dstq, dstmp
+    mova      [dstq+ 0], m0
+    mova      [dstq+16], m1
+
+%if ARCH_X86_32
+    add            srcq, r2mp
+    add            dstq, r2mp
+    mov           dstmp, dstq
+%else
+    add            srcq, r13mp
+    add            dstq, r13mp
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82*2
+    dec              hd
+    jg %%loop_y
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, w, picptr, luma
+
+    mov              wq, r4mp
+%endif
+    add              wq, 16
+    jge %%end
+%if ARCH_X86_32
+    mov            srcq, r1mp
+%else
+    mov            srcq, r10mp
+%endif
+    mov            dstq, r11mp
+    mov           lumaq, r12mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+%if ARCH_X86_32
+    mov             r0m, dstq
+    mov             r9m, lumaq
+    mov             r4m, wq
+%endif
+%if %2 == 0
+    btc       dword r8m, 2
+    jc %%next_blk
+    add          offxyd, 16
+    test      dword r8m, 2
+    jz %%loop_x_odd
+%if ARCH_X86_32
+    add dword [rsp+8*mmsize+1*gprsize], 16
+%else
+    add            r11d, 16
+%endif
+    jmp %%loop_x_odd_v_overlap
+%%next_blk:
+%endif
+    test      dword r8m, 1
+    je %%loop_x
+
+    ; r8m = sbym
+    test      dword r8m, 2
+    jnz %%loop_x_hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+%%loop_x_h_overlap:
+%if ARCH_X86_32
+    add          offxyd, 16
+    mov [rsp+8*mmsize+0*gprsize], offxyd
+
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, grain_lut
+
+    mov            seed, r3m
+%endif
+    mov             r6d, seed
+    or             seed, 0xEFF4
+    shr             r6d, 1
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, w, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, unused1, unused2, luma, lstride
+
+    lea     left_offxyd, [offyd+16]         ; previous column's offy*stride+offx
+    mov           offxd, seed
+    mov           offyd, seed
+%endif
+    ror           offyd, 8
+    shr           offxd, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyq, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)]  ; offy*stride+offx
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, unused1, unused2, luma, lstride
+%endif
+
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+%%loop_y_h_overlap:
+    mova             m0, [srcq]
+    mova             m1, [srcq+16]
+
+    ; luma_src
+    pxor          mzero, mzero
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, luma, grain_lut
+    mov           lumaq, r9m
+%endif
+    mova             m4, [lumaq+ 0]
+    mova             m6, [lumaq+(16<<%2)]
+%if %2
+    phaddw           m4, [lumaq+16]
+    phaddw           m6, [lumaq+48]
+%endif
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov             r9m, lumaq
+%endif
+%if %2
+    pavgw            m4, mzero
+    pavgw            m6, mzero
+%endif
+
+%if %1
+    punpckhwd        m3, m4, m0
+    punpcklwd        m4, m0
+    punpckhwd        m5, m6, m1
+    punpcklwd        m6, m1                 ; { luma, chroma }
+    REPX {pmaddwd x, m14}, m3, m4, m5, m6
+    REPX {psrad   x, 6}, m3, m4, m5, m6
+    packssdw         m4, m3
+    packssdw         m6, m5
+    REPX {paddw x, m15}, m4, m6
+    REPX {pmaxsw x, mzero}, m4, m6
+    REPX {pminsw x, m10}, m4, m6             ; clip_pixel()
+%else
+    REPX  {pand x, m10}, m4, m6
+%endif
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m7, [grain_lutq+offxyq*2]
+%if ARCH_X86_32
+    mov              r5, [rsp+8*mmsize+0*gprsize]
+    movd             m5, [grain_lutq+r5*2]
+%else
+    movd             m5, [grain_lutq+left_offxyq*2+ 0]
+%endif
+    punpcklwd        m5, m7                ; {left0, cur0}
+%if %1
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+%if %2
+    pmaddwd          m5, [PIC_ptr(pw_23_22)]
+%else
+    pmaddwd          m5, [PIC_ptr(pw_27_17_17_27)]
+%endif
+    paddd            m5, [PIC_ptr(pd_16)]
+%else
+    pmaddwd          m5, m15
+    paddd            m5, m14
+%endif
+    psrad            m5, 5
+    packssdw         m5, m5
+    pmaxsw           m5, m8
+    pminsw           m5, m9
+    shufps           m5, m7, q3210
+    movu             m3, [grain_lutq+offxyq*2+16]
+
+    ; scaling[luma_src]
+%if ARCH_X86_32
+    vpgatherdw       m7, m4, scalingq-1, r0, r5, 8, 1
+    vpgatherdw       m4, m6, scalingq-1, r0, r5, 8, 1
+%else
+    vpgatherdw       m7, m4, scalingq-1, r2, r12, 8, 1
+    vpgatherdw       m4, m6, scalingq-1, r2, r12, 8, 1
+%endif
+    REPX   {psrlw x, 8}, m7, m4
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    REPX {pmullw x, m11}, m7, m4
+    pmulhrsw         m5, m7
+    pmulhrsw         m3, m4
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m5
+    paddw            m1, m3
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    movifnidn      dstq, dstmp
+    mova      [dstq+ 0], m0
+    mova      [dstq+16], m1
+
+%if ARCH_X86_32
+    add            srcq, r2mp
+    add            dstq, r2mp
+    mov           dstmp, dstq
+%else
+    add            srcq, r13mp
+    add            dstq, r13mp
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82*2
+    dec              hd
+    jg %%loop_y_h_overlap
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, w, luma, grain_lut
+    mov              wq, r4mp
+%endif
+    add              wq, 16
+    jge %%end
+%if ARCH_X86_32
+    mov            srcq, r1mp
+%else
+    mov            srcq, r10mp
+%endif
+    mov            dstq, r11mp
+    mov           lumaq, r12mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+%if ARCH_X86_32
+    mov            r0mp, dstq
+    mov            r9mp, lumaq
+    mov             r4m, wq
+%endif
+
+%if %2
+    ; r8m = sbym
+    test      dword r8m, 2
+    jne %%loop_x_hv_overlap
+    jmp %%loop_x_h_overlap
+%else
+    or        dword r8m, 4
+    add          offxyd, 16
+
+    ; r8m = sbym
+    test      dword r8m, 2
+    jz %%loop_x_odd
+%if ARCH_X86_32
+    add dword [rsp+8*mmsize+1*gprsize], 16
+%else
+    add            r11d, 16                 ; top_offxy += 16
+%endif
+    jmp %%loop_x_odd_v_overlap
+%endif
+
+%%end:
+    RET
+
+%%vertical_overlap:
+    or              t0d, 2
+    mov             r8m, t0d
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused, \
+                sby, see, unused1, unused2, unused3, lstride
+%endif
+
+    movzx          sbyd, sbyb
+%if ARCH_X86_32
+    imul             r4, [fg_dataq+FGData.seed], 0x00010001
+
+    DEFINE_ARGS tmp, src, scaling, sby, see, picptr, unused
+%else
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+%endif
+    imul            t0d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             t0d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             t0d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, t0d
+%if ARCH_X86_32
+    xor            sbyd, seed
+
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, luma
+
+    mov             r3m, seed
+    mov            dstq, r0mp
+    mov           lumaq, r9mp
+    mov              wq, r4m
+    lea              r3, [srcq+wq*2]
+    mov            r1mp, r3
+    lea              r3, [dstq+wq*2]
+    mov           r11mp, r3
+    lea              r3, [lumaq+wq*(2<<%2)]
+    mov           r12mp, r3
+%if %3
+    shl           r10mp, 1
+%endif
+%else
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                unused1, unused2, see, unused3, unused4, unused5, luma, lstride
+
+    mov        lstrideq, r10mp
+%if %3
+    add        lstrideq, lstrideq
+%endif
+    mov           lumaq, r9mp
+    lea             r10, [srcq+wq*2]
+    lea             r11, [dstq+wq*2]
+    lea             r12, [lumaq+wq*(2<<%2)]
+    mov           r10mp, r10
+    mov           r11mp, r11
+    mov           r12mp, r12
+%endif
+    neg              wq
+%if ARCH_X86_32
+    mov             r4m, wq
+%endif
+
+%%loop_x_v_overlap:
+%if ARCH_X86_32
+    mov            seed, r3m
+    xor             t0d, t0d
+%else
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+%endif
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            t0b                     ; parity of top_seed
+    shr            seed, 16
+    shl             t0d, 16
+    test           seeb, seeh
+    setp            t0b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             t0d, r6d
+    mov            seed, t0d
+    ror            seed, 1                  ; updated (cur_seed << 16) | top_seed
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, w, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, unused1, top_offxy, unused2, luma, lstride
+
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    ror           offxd, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyq, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+%if ARCH_X86_32
+    DEFINE_ARGS top_offxy, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, unused1, top_offxy, unused2, luma, lstride
+%endif
+    movzx    top_offxyd, offxyw
+%if ARCH_X86_32
+    mov [rsp+8*mmsize+1*gprsize], top_offxyd
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+    shr          offxyd, 16
+
+%if %2 == 0
+%%loop_x_odd_v_overlap:
+%endif
+%if %3 == 0
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    SPLATD           m2, [PIC_ptr(pw_27_17_17_27)]
+%endif
+
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+%%loop_y_v_overlap:
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq*2]
+%if ARCH_X86_32
+    mov              r0, [rsp+mmsize*8+gprsize*1] ; top_offxy
+    movu             m5, [grain_lutq+r0*2]
+%else
+    movu             m5, [grain_lutq+top_offxyq*2]
+%endif
+    punpckhwd        m7, m5, m3
+    punpcklwd        m5, m3                 ; {top/cur interleaved}
+    REPX {pmaddwd x, m2}, m7, m5
+%if %1
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    REPX  {paddd x, [PIC_ptr(pd_16)]}, m7, m5
+%else
+    REPX  {paddd x, m14}, m7, m5
+%endif
+    REPX   {psrad x, 5}, m7, m5
+    packssdw         m3, m5, m7
+    pmaxsw           m3, m8
+    pminsw           m3, m9
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m4, [grain_lutq+offxyq*2+16]
+%if ARCH_X86_32
+    movu             m5, [grain_lutq+r0*2+16]
+%else
+    movu             m5, [grain_lutq+top_offxyq*2+16]
+%endif
+    punpckhwd        m7, m5, m4
+    punpcklwd        m5, m4                 ; {top/cur interleaved}
+    REPX {pmaddwd x, m2}, m7, m5
+%if %1
+    REPX  {paddd x, [PIC_ptr(pd_16)]}, m7, m5
+%else
+    REPX  {paddd x, m14}, m7, m5
+%endif
+    REPX   {psrad x, 5}, m7, m5
+    packssdw         m4, m5, m7
+    pmaxsw           m4, m8
+    pminsw           m4, m9
+
+    ; src
+    mova             m0, [srcq]
+    mova             m1, [srcq+16]
+
+    ; luma_src
+    pxor          mzero, mzero
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, luma, grain_lut
+
+    mov           lumaq, r9mp
+%endif
+    mova             m5, [lumaq+ 0]
+    mova             m6, [lumaq+(16<<%2)]
+%if %2
+    phaddw           m5, [lumaq+16]
+    phaddw           m6, [lumaq+48]
+%endif
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+%endif
+%if %2
+    pavgw            m5, mzero
+    pavgw            m6, mzero
+%endif
+
+%if %1
+    punpckhwd        m7, m5, m0
+    punpcklwd        m5, m0
+    REPX {pmaddwd x, m14}, m7, m5
+    REPX {psrad   x, 6}, m7, m5
+    packssdw         m5, m7
+    punpckhwd        m7, m6, m1
+    punpcklwd        m6, m1                 ; { luma, chroma }
+    REPX {pmaddwd x, m14}, m7, m6
+    REPX {psrad   x, 6}, m7, m6
+    packssdw         m6, m7
+    pxor          mzero, mzero
+    REPX {paddw x, m15}, m5, m6
+    REPX {pmaxsw x, mzero}, m5, m6
+    REPX {pminsw x, m10}, m5, m6            ; clip_pixel()
+%else
+    REPX  {pand x, m10}, m5, m6
+%endif
+
+    ; scaling[luma_src]
+%if ARCH_X86_32
+    vpgatherdw       m7, m5, scalingq-1, r0, r5, 8, 1
+    vpgatherdw       m5, m6, scalingq-1, r0, r5, 8, 1
+%else
+    vpgatherdw       m7, m5, scalingq-1, r10, r12, 8, 1
+    vpgatherdw       m5, m6, scalingq-1, r10, r12, 8, 1
+%endif
+    REPX   {psrlw x, 8}, m7, m5
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    REPX {pmullw x, m11}, m7, m5
+    pmulhrsw         m3, m7
+    pmulhrsw         m4, m5
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m3
+    paddw            m1, m4
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    movifnidn      dstq, dstmp
+    mova      [dstq+ 0], m0
+    mova      [dstq+16], m1
+
+    dec              hw
+    jle %%end_y_v_overlap
+%if ARCH_X86_32
+    add            srcq, r2mp
+    add            dstq, r2mp
+    mov           dstmp, dstq
+%else
+    add            srcq, r13mp
+    add            dstq, r13mp
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82*2
+%if %3
+    jmp %%loop_y
+%else
+    btc              hd, 16
+    jc %%loop_y
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    SPLATD           m2, [PIC_ptr(pw_27_17_17_27)+4]
+    jmp %%loop_y_v_overlap
+%endif
+
+%%end_y_v_overlap:
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, w, luma, grain_lut
+
+    mov              wq, r4m
+%endif
+    add              wq, 16
+    jge %%end_hv
+%if ARCH_X86_32
+    mov            srcq, r1mp
+%else
+    mov            srcq, r10mp
+%endif
+    mov            dstq, r11mp
+    mov           lumaq, r12mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+%if ARCH_X86_32
+    mov            r0mp, dstq
+    mov            r9mp, lumaq
+    mov             r4m, wq
+%endif
+
+%if %2
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump
+    ; back to .loop_x_v_overlap, and instead always fall-through to
+    ; h+v overlap
+%else
+    btc       dword r8m, 2
+    jc %%loop_x_hv_overlap
+    add          offxyd, 16
+%if ARCH_X86_32
+    add dword [rsp+8*mmsize+1*gprsize], 16
+%else
+    add            r11d, 16
+%endif
+    jmp %%loop_x_odd_v_overlap
+%endif
+
+%%loop_x_hv_overlap:
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, w, picptr, grain_lut
+
+    mov             t0d, [rsp+mmsize*8+gprsize*1] ; top_offxy
+    add          offxyd, 16
+    add             t0d, 16
+    mov [rsp+mmsize*8+gprsize*0], offxyd ; left_offxyd
+    mov [rsp+mmsize*8+gprsize*2], t0d ; topleft_offxyd
+
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, grain_lut
+
+    mov            seed, r3m
+    xor             t0d, t0d
+%else
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+%endif
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            t0b                     ; parity of top_seed
+    shr            seed, 16
+    shl             t0d, 16
+    test           seeb, seeh
+    setp            t0b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             t0d, r6d
+    mov            seed, t0d
+    ror            seed, 1                  ; updated (cur_seed << 16) | top_seed
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, w, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, top_offxy, topleft_offxy, luma, lstride
+
+    lea  topleft_offxyq, [top_offxyq+16]
+    lea     left_offxyq, [offyq+16]
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    ror           offxd, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyq, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, top_offxy
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, top_offxy, topleft_offxy, luma, lstride
+%endif
+    movzx    top_offxyd, offxyw
+%if ARCH_X86_32
+    mov [rsp+8*mmsize+1*gprsize], top_offxyd
+
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+    shr          offxyd, 16
+
+%if %3 == 0
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    SPLATD           m2, [PIC_ptr(pw_27_17_17_27)]
+%endif
+
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+%%loop_y_hv_overlap:
+    ; grain = grain_lut[offy+y][offx+x]
+%if ARCH_X86_32
+    mov              r5, [rsp+8*mmsize+0*gprsize] ; left_offxy
+    mov              r0, [rsp+8*mmsize+1*gprsize] ; top_offxy
+    movd             m5, [grain_lutq+r5*2]
+%else
+    movd             m5, [grain_lutq+left_offxyq*2]
+%endif
+    movu             m7, [grain_lutq+offxyq*2]
+%if ARCH_X86_32
+    mov              r5, [rsp+8*mmsize+2*gprsize]
+    movu             m4, [grain_lutq+r0*2]
+%if %2
+    pinsrw           m5, [grain_lutq+r5*2], 2
+%else
+    movd             m3, [grain_lutq+r5*2]
+%endif
+%else
+    movu             m4, [grain_lutq+top_offxyq*2]
+%if %2
+    pinsrw           m5, [grain_lutq+topleft_offxyq*2], 2 ; { left, _, top/left }
+%else
+    movd             m3, [grain_lutq+topleft_offxyq*2]
+%endif
+%endif
+%if %2 == 0
+    punpckldq        m5, m3
+%endif
+    punpckldq        m3, m7, m4             ; { cur0/1,top0/1,cur2/3,top2/3 }
+    punpcklwd        m5, m3                 ; { left/cur0,_/cur1,topleft/top0,_/top1 }
+%if %1
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+%if %2
+    movddup          m0, [PIC_ptr(pw_23_22)]
+%else
+    movddup          m0, [PIC_ptr(pw_27_17_17_27)]
+%endif
+%else
+    pshufd           m0, m15, q1010
+%endif
+    pmaddwd          m5, m0
+%if %1
+    paddd            m5, [PIC_ptr(pd_16)]
+%else
+    paddd            m5, m14
+%endif
+    psrad            m5, 5
+    packssdw         m5, m5
+    pmaxsw           m5, m8
+    pminsw           m5, m9
+    shufps           m5, m3, q3210          ; cur0/1,top0/1,cur2/3,top2/3
+    shufps           m3, m5, m7, q3220      ; cur0-7 post-h_filter
+    shufps           m5, m4, q3231          ; top0-7 post-h_filter
+
+    punpckhwd        m7, m5, m3
+    punpcklwd        m5, m3                 ; {top/cur interleaved}
+    REPX {pmaddwd x, m2}, m7, m5
+%if %1
+    REPX  {paddd x, [PIC_ptr(pd_16)]}, m5, m7
+%else
+    REPX  {paddd x, m14}, m5, m7
+%endif
+    REPX   {psrad x, 5}, m5, m7
+    packssdw         m3, m5, m7
+    pmaxsw           m3, m8
+    pminsw           m3, m9
+
+    ; right half
+    movu             m4, [grain_lutq+offxyq*2+16]
+%if ARCH_X86_32
+    movu             m0, [grain_lutq+r0*2+16]
+%else
+    movu             m0, [grain_lutq+top_offxyq*2+16]
+%endif
+    punpckhwd        m1, m0, m4
+    punpcklwd        m0, m4                 ; {top/cur interleaved}
+    REPX {pmaddwd x, m2}, m1, m0
+%if %1
+    REPX  {paddd x, [PIC_ptr(pd_16)]}, m1, m0
+%else
+    REPX  {paddd x, m14}, m1, m0
+%endif
+    REPX   {psrad x, 5}, m1, m0
+    packssdw         m4, m0, m1
+    pmaxsw           m4, m8
+    pminsw           m4, m9
+
+    ; src
+    mova             m0, [srcq]
+    mova             m1, [srcq+16]
+
+    ; luma_src
+    pxor          mzero, mzero
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, luma, grain_lut
+
+    mov           lumaq, r9mp
+%endif
+    mova             m6, [lumaq+ 0]
+    mova             m5, [lumaq+(16<<%2)]
+%if %2
+    phaddw           m6, [lumaq+16]
+    phaddw           m5, [lumaq+48]
+%endif
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+%endif
+%if %2
+    pavgw            m6, mzero
+    pavgw            m5, mzero
+%endif
+
+%if %1
+    punpckhwd        m7, m6, m0
+    punpcklwd        m6, m0
+    REPX {pmaddwd x, m14}, m7, m6
+    REPX {psrad   x, 6}, m7, m6
+    packssdw         m6, m7
+    punpckhwd        m7, m5, m1
+    punpcklwd        m5, m1                 ; { luma, chroma }
+    REPX {pmaddwd x, m14}, m7, m5
+    REPX {psrad   x, 6}, m7, m5
+    packssdw         m5, m7
+    pxor          mzero, mzero
+    REPX {paddw x, m15}, m6, m5
+    REPX {pmaxsw x, mzero}, m6, m5
+    REPX {pminsw x, m10}, m6, m5            ; clip_pixel()
+%else
+    REPX  {pand x, m10}, m6, m5
+%endif
+
+    ; scaling[luma_src]
+%if ARCH_X86_32
+    vpgatherdw       m7, m6, scalingq-1, r0, r5, 8, 1
+    vpgatherdw       m6, m5, scalingq-1, r0, r5, 8, 1
+%else
+%if %3 == 0
+    ; register shortage :)
+    push            r12
+%endif
+    vpgatherdw       m7, m6, scalingq-1, r2, r12, 8, 1
+    vpgatherdw       m6, m5, scalingq-1, r2, r12, 8, 1
+%if %3 == 0
+    pop             r12
+%endif
+%endif
+    REPX   {psrlw x, 8}, m7, m6
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    REPX {pmullw x, m11}, m7, m6
+    pmulhrsw         m3, m7
+    pmulhrsw         m4, m6
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m3
+    paddw            m1, m4
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    movifnidn      dstq, dstmp
+    mova      [dstq+ 0], m0
+    mova      [dstq+16], m1
+
+%if ARCH_X86_32
+    add            srcq, r2mp
+    add            dstq, r2mp
+    mov           dstmp, dstq
+%else
+    add            srcq, r13mp
+    add            dstq, r13mp
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82*2
+    dec              hw
+%if %3
+    jg %%loop_y_h_overlap
+%else
+    jle %%end_y_hv_overlap
+    btc              hd, 16
+    jc %%loop_y_h_overlap
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    SPLATD           m2, [PIC_ptr(pw_27_17_17_27)+4]
+    jmp %%loop_y_hv_overlap
+%%end_y_hv_overlap:
+%endif
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, w, luma, grain_lut
+
+    mov              wq, r4m
+%endif
+    add              wq, 16
+    jge %%end_hv
+%if ARCH_X86_32
+    mov            srcq, r1mp
+%else
+    mov            srcq, r10mp
+%endif
+    mov            dstq, r11mp
+    mov           lumaq, r12mp
+    lea            srcq, [srcq+wq*2]
+    lea            dstq, [dstq+wq*2]
+    lea           lumaq, [lumaq+wq*(2<<%2)]
+%if ARCH_X86_32
+    mov           dstmp, dstq
+    mov            r9mp, lumaq
+    mov             r4m, wq
+%endif
+%if %2
+    jmp %%loop_x_hv_overlap
+%else
+    or        dword r8m, 4
+    add          offxyd, 16
+%if ARCH_X86_32
+    add dword [rsp+8*mmsize+1*gprsize], 16
+%else
+    add            r11d, 16                 ; top_offxy += 16
+%endif
+    jmp %%loop_x_odd_v_overlap
+%endif
+
+%%end_hv:
+    RET
+%endmacro
+
+    %%FGUV_32x32xN_LOOP 1, %2, %3
+.csfl:
+    %%FGUV_32x32xN_LOOP 0, %2, %3
+
+%if STACK_ALIGNMENT < mmsize
+DECLARE_ARG 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+%endif
+%endmacro
+
+FGUV_FN 420, 1, 1
+FGUV_FN 422, 1, 0
+FGUV_FN 444, 0, 0
diff --git a/media/libdav1d/src/src/x86/filmgrain_avx2.asm b/media/libdav1d/src/src/x86/filmgrain_avx2.asm
new file mode 100644
index 0000000000..91d8ca5c14
--- /dev/null
+++ b/media/libdav1d/src/src/x86/filmgrain_avx2.asm
@@ -0,0 +1,2092 @@
+; Copyright © 2019-2022, VideoLAN and dav1d authors
+; Copyright © 2019-2022, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+%include "x86/filmgrain_common.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 32
+pb_mask:       db  0,128,128,  0,128,  0,  0,128,128,  0,  0,128,  0,128,128,  0
+gen_shufE:     db  0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+gen_shufA:     db  0,  1,  2,  3,  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9
+gen_shufB:     db  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11
+gen_shufC:     db  4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13
+gen_shufD:     db  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15
+; note: the order of (some of) the following constants matter
+pb_27_17:      times 2 db 27, 17
+byte_blend:            db  0,  0,  0, -1
+pb_27_17_17_27:        db 27, 17, 17, 27,  0, 32,  0, 32
+pb_17_27:      times 2 db 17, 27
+pb_1:          times 4 db 1
+pb_23_22:              db 23, 22,  0, 32,  0, 32,  0, 32
+next_upperbit_mask:    dw 0x100B, 0x2016, 0x402C, 0x8058
+pw_seed_xor:   times 2 dw 0xb524
+               times 2 dw 0x49d8
+fg_min:        times 4 db 0
+               times 4 db 16
+fg_max:        times 4 db 255
+               times 4 db 240
+               times 4 db 235
+pd_m65536:             dd -65536
+pw_8:          times 2 dw 8
+pw_1024:       times 2 dw 1024
+hmul_bits:             dw 32768, 16384,  8192,  4096
+round:                 dw  2048,  1024,   512
+mul_bits:              dw   256,   128,    64,    32,    16
+round_vals:            dw    32,    64,   128,   256,   512
+pw_1:                  dw 1
+
+%macro JMP_TABLE 2-*
+    %1_8bpc_%2_table:
+    %xdefine %%base %1_8bpc_%2_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1_8bpc_%2)
+    %rep %0 - 2
+        dd %%prefix %+ .ar%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+JMP_TABLE generate_grain_y,      avx2, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_420, avx2, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_422, avx2, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_444, avx2, 0, 1, 2, 3
+
+SECTION .text
+
+INIT_YMM avx2
+cglobal generate_grain_y_8bpc, 2, 9, 8, buf, fg_data
+%define base r4-generate_grain_y_8bpc_avx2_table
+    lea              r4, [generate_grain_y_8bpc_avx2_table]
+    vpbroadcastw    xm0, [fg_dataq+FGData.seed]
+    mov             r6d, [fg_dataq+FGData.grain_scale_shift]
+    movq            xm1, [base+next_upperbit_mask]
+    movsxd           r5, [fg_dataq+FGData.ar_coeff_lag]
+    movq            xm4, [base+mul_bits]
+    movq            xm5, [base+hmul_bits]
+    mov              r7, -73*82
+    mova            xm6, [base+pb_mask]
+    sub            bufq, r7
+    vpbroadcastw    xm7, [base+round+r6*2]
+    lea              r6, [gaussian_sequence]
+    movsxd           r5, [r4+r5*4]
+.loop:
+    pand            xm2, xm0, xm1
+    psrlw           xm3, xm2, 10
+    por             xm2, xm3            ; bits 0xf, 0x1e, 0x3c and 0x78 are set
+    pmullw          xm2, xm4            ; bits 0x0f00 are set
+    pmulhuw         xm0, xm5
+    pshufb          xm3, xm6, xm2       ; set 15th bit for next 4 seeds
+    psllq           xm2, xm3, 30
+    por             xm2, xm3
+    psllq           xm3, xm2, 15
+    por             xm2, xm0            ; aggregate each bit into next seed's high bit
+    por             xm3, xm2            ; 4 next output seeds
+    pshuflw         xm0, xm3, q3333
+    psrlw           xm3, 5
+    pand            xm2, xm0, xm1
+    movq             r2, xm3
+    psrlw           xm3, xm2, 10
+    por             xm2, xm3
+    pmullw          xm2, xm4
+    pmulhuw         xm0, xm5
+    movzx           r3d, r2w
+    pshufb          xm3, xm6, xm2
+    psllq           xm2, xm3, 30
+    por             xm2, xm3
+    psllq           xm3, xm2, 15
+    por             xm0, xm2
+    movd            xm2, [r6+r3*2]
+    rorx             r3, r2, 32
+    por             xm3, xm0
+    shr             r2d, 16
+    pinsrw          xm2, [r6+r2*2], 1
+    pshuflw         xm0, xm3, q3333
+    movzx           r2d, r3w
+    psrlw           xm3, 5
+    pinsrw          xm2, [r6+r2*2], 2
+    shr             r3d, 16
+    movq             r2, xm3
+    pinsrw          xm2, [r6+r3*2], 3
+    movzx           r3d, r2w
+    pinsrw          xm2, [r6+r3*2], 4
+    rorx             r3, r2, 32
+    shr             r2d, 16
+    pinsrw          xm2, [r6+r2*2], 5
+    movzx           r2d, r3w
+    pinsrw          xm2, [r6+r2*2], 6
+    shr             r3d, 16
+    pinsrw          xm2, [r6+r3*2], 7
+    pmulhrsw        xm2, xm7
+    packsswb        xm2, xm2
+    movq      [bufq+r7], xm2
+    add              r7, 8
+    jl .loop
+
+    ; auto-regression code
+    add              r5, r4
+    jmp              r5
+
+.ar1:
+    DEFINE_ARGS buf, fg_data, cf3, shift, val3, min, max, x, val0
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movsx          cf3d, byte [fg_dataq+FGData.ar_coeffs_y+3]
+    movd            xm5, [fg_dataq+FGData.ar_coeffs_y]
+    mova            xm2, [base+gen_shufC]
+    DEFINE_ARGS buf, h, cf3, shift, val3, min, max, x, val0
+    pinsrb          xm5, [base+pb_1], 3
+    vpbroadcastw    xm3, [base+round_vals+shiftq*2-12]    ; rnd
+    pmovsxbw        xm5, xm5
+    pshufd          xm4, xm5, q0000
+    pshufd          xm5, xm5, q1111
+    sub            bufq, 82*73-(82*3+79)
+    mov              hd, 70
+    mov            mind, -128
+    mov            maxd, 127
+.y_loop_ar1:
+    mov              xq, -76
+    movsx         val3d, byte [bufq+xq-1]
+.x_loop_ar1:
+    pmovsxbw        xm1, [bufq+xq-82-3]
+    pshufb          xm0, xm1, xm2
+    punpckhwd       xm1, xm3
+    pmaddwd         xm0, xm4
+    pmaddwd         xm1, xm5
+    paddd           xm0, xm1
+.x_loop_ar1_inner:
+    movd          val0d, xm0
+    psrldq          xm0, 4
+    imul          val3d, cf3d
+    add           val3d, val0d
+    movsx         val0d, byte [bufq+xq]
+    sarx          val3d, val3d, shiftd
+    add           val3d, val0d
+    cmp           val3d, maxd
+    cmovns        val3d, maxd
+    cmp           val3d, mind
+    cmovs         val3d, mind
+    mov       [bufq+xq], val3b
+    ; keep val3d in-place as left for next x iteration
+    inc              xq
+    jz .x_loop_ar1_end
+    test             xb, 3
+    jnz .x_loop_ar1_inner
+    jmp .x_loop_ar1
+.x_loop_ar1_end:
+    add            bufq, 82
+    dec              hd
+    jg .y_loop_ar1
+.ar0:
+    RET
+
+.ar2:
+%if WIN64
+    %assign stack_size_padded 168
+    SUB             rsp, stack_size_padded
+    WIN64_PUSH_XMM   16, 8
+%endif
+    DEFINE_ARGS buf, fg_data, h, x
+    mov             r6d, [fg_dataq+FGData.ar_coeff_shift]
+    pmovsxbw        xm7, [fg_dataq+FGData.ar_coeffs_y+0]    ; cf0-7
+    movd            xm9, [fg_dataq+FGData.ar_coeffs_y+8]    ; cf8-11
+    vpbroadcastd   xm10, [base+round_vals-14+r6*2]
+    movd           xm11, [base+byte_blend+1]
+    pmovsxbw        xm9, xm9
+    pshufd          xm4, xm7, q0000
+    mova           xm12, [base+gen_shufA]
+    pshufd          xm5, xm7, q3333
+    mova           xm13, [base+gen_shufB]
+    pshufd          xm6, xm7, q1111
+    mova           xm14, [base+gen_shufC]
+    pshufd          xm7, xm7, q2222
+    mova           xm15, [base+gen_shufD]
+    pshufd          xm8, xm9, q0000
+    psrld          xm10, 16
+    pshufd          xm9, xm9, q1111
+    sub            bufq, 82*73-(82*3+79)
+    mov              hd, 70
+.y_loop_ar2:
+    mov              xq, -76
+.x_loop_ar2:
+    pmovsxbw        xm0, [bufq+xq-82*2-2]   ; y=-2,x=[-2,+5]
+    pmovsxbw        xm1, [bufq+xq-82*1-2]   ; y=-1,x=[-2,+5]
+    pshufb          xm2, xm0, xm12
+    pmaddwd         xm2, xm4
+    pshufb          xm3, xm1, xm13
+    pmaddwd         xm3, xm5
+    paddd           xm2, xm3
+    pshufb          xm3, xm0, xm14
+    pmaddwd         xm3, xm6
+    punpckhqdq      xm0, xm0
+    punpcklwd       xm0, xm1
+    pmaddwd         xm0, xm7
+    pshufb          xm1, xm15
+    pmaddwd         xm1, xm8
+    paddd           xm2, xm10
+    paddd           xm2, xm3
+    paddd           xm0, xm1
+    paddd           xm2, xm0
+    movq            xm0, [bufq+xq-2]        ; y=0,x=[-2,+5]
+.x_loop_ar2_inner:
+    pmovsxbw        xm1, xm0
+    pmaddwd         xm3, xm9, xm1
+    psrldq          xm1, 4                  ; y=0,x=0
+    paddd           xm3, xm2
+    psrldq          xm2, 4                  ; shift top to next pixel
+    psrad           xm3, [fg_dataq+FGData.ar_coeff_shift]
+    ; don't packssdw since we only care about one value
+    paddw           xm3, xm1
+    packsswb        xm3, xm3
+    pextrb    [bufq+xq], xm3, 0
+    pslldq          xm3, 2
+    vpblendvb       xm0, xm3, xm11
+    psrldq          xm0, 1
+    inc              xq
+    jz .x_loop_ar2_end
+    test             xb, 3
+    jnz .x_loop_ar2_inner
+    jmp .x_loop_ar2
+.x_loop_ar2_end:
+    add            bufq, 82
+    dec              hd
+    jg .y_loop_ar2
+    RET
+
+INIT_YMM avx2
+.ar3:
+%if WIN64
+    ALLOC_STACK   16*14
+    %assign stack_size stack_size - 16*4
+    WIN64_PUSH_XMM   12, 8
+%else
+    ALLOC_STACK   16*12
+%endif
+    mov             r6d, [fg_dataq+FGData.ar_coeff_shift]
+    movd           xm11, [base+byte_blend]
+    pmovsxbw         m1, [fg_dataq+FGData.ar_coeffs_y+ 0]   ; cf0-15
+    pmovsxbw        xm2, [fg_dataq+FGData.ar_coeffs_y+16]   ; cf16-23
+    pshufd           m0, m1, q0000
+    mova    [rsp+16* 0], m0
+    pshufd           m0, m1, q1111
+    mova    [rsp+16* 2], m0
+    pshufd           m0, m1, q2222
+    mova    [rsp+16* 4], m0
+    pshufd           m1, m1, q3333
+    mova    [rsp+16* 6], m1
+    pshufd          xm0, xm2, q0000
+    mova    [rsp+16* 8], xm0
+    pshufd          xm0, xm2, q1111
+    mova    [rsp+16* 9], xm0
+    psrldq          xm7, xm2, 10
+    mova             m8, [base+gen_shufA]
+    pinsrw          xm2, [base+pw_1], 5
+    mova             m9, [base+gen_shufC]
+    pshufd          xm2, xm2, q2222
+    movu            m10, [base+gen_shufE]
+    vpbroadcastw    xm6, [base+round_vals-12+r6*2]
+    pinsrw          xm7, [base+round_vals+r6*2-10], 3
+    mova    [rsp+16*10], xm2
+    DEFINE_ARGS buf, fg_data, h, x
+    sub            bufq, 82*73-(82*3+79)
+    mov              hd, 70
+.y_loop_ar3:
+    mov              xq, -76
+.x_loop_ar3:
+    movu            xm5, [bufq+xq-82*3-3]    ; y=-3,x=[-3,+12]
+    vinserti128      m5, [bufq+xq-82*2-3], 1 ; y=-2,x=[-3,+12]
+    movu            xm4, [bufq+xq-82*1-3]    ; y=-1,x=[-3,+12]
+    punpcklbw        m3, m5, m5
+    punpckhwd        m5, m4
+    psraw            m3, 8
+    punpcklbw        m5, m5
+    psraw            m5, 8
+    punpcklbw       xm4, xm4
+    psraw           xm4, 8
+    pshufb           m0, m3, m8
+    pmaddwd          m0, [rsp+16*0]
+    pshufb           m1, m3, m9
+    pmaddwd          m1, [rsp+16*2]
+    shufps           m2, m3, m5, q1032
+    paddd            m0, m1
+    pshufb           m1, m2, m8
+    vperm2i128       m3, m4, 0x21
+    pmaddwd          m1, [rsp+16*4]
+    shufps          xm2, xm3, q1021
+    vpblendd         m2, m3, 0xf0
+    pshufb           m2, m10
+    paddd            m0, m1
+    pmaddwd          m2, [rsp+16*6]
+    pshufb          xm1, xm4, xm9
+    pmaddwd         xm1, [rsp+16*8]
+    shufps          xm4, xm5, q1132
+    paddd            m0, m2
+    pshufb          xm2, xm4, xm8
+    pshufd          xm4, xm4, q2121
+    pmaddwd         xm2, [rsp+16*9]
+    punpcklwd       xm4, xm6
+    pmaddwd         xm4, [rsp+16*10]
+    vextracti128    xm3, m0, 1
+    paddd           xm0, xm1
+    movq            xm1, [bufq+xq-3]        ; y=0,x=[-3,+4]
+    paddd           xm2, xm4
+    paddd           xm0, xm2
+    paddd           xm0, xm3
+.x_loop_ar3_inner:
+    pmovsxbw        xm2, xm1
+    pmaddwd         xm2, xm7
+    pshufd          xm3, xm2, q1111
+    paddd           xm2, xm0                ; add top
+    paddd           xm2, xm3                ; left+cur
+    psrldq          xm0, 4
+    psrad           xm2, [fg_dataq+FGData.ar_coeff_shift]
+    ; don't packssdw since we only care about one value
+    packsswb        xm2, xm2
+    pextrb    [bufq+xq], xm2, 0
+    pslldq          xm2, 3
+    vpblendvb       xm1, xm2, xm11
+    psrldq          xm1, 1
+    inc              xq
+    jz .x_loop_ar3_end
+    test             xb, 3
+    jnz .x_loop_ar3_inner
+    jmp .x_loop_ar3
+.x_loop_ar3_end:
+    add            bufq, 82
+    dec              hd
+    jg .y_loop_ar3
+    RET
+
+%macro GEN_GRAIN_UV_FN 3 ; ss_name, ss_x, ss_y
+INIT_XMM avx2
+cglobal generate_grain_uv_%1_8bpc, 4, 10, 16, buf, bufy, fg_data, uv
+%define base r4-generate_grain_uv_%1_8bpc_avx2_table
+    lea              r4, [generate_grain_uv_%1_8bpc_avx2_table]
+    vpbroadcastw    xm0, [fg_dataq+FGData.seed]
+    mov             r6d, [fg_dataq+FGData.grain_scale_shift]
+    movq            xm1, [base+next_upperbit_mask]
+    movq            xm4, [base+mul_bits]
+    movq            xm5, [base+hmul_bits]
+    mova            xm6, [base+pb_mask]
+    vpbroadcastw    xm7, [base+round+r6*2]
+    vpbroadcastd    xm2, [base+pw_seed_xor+uvq*4]
+    pxor            xm0, xm2
+    lea              r6, [gaussian_sequence]
+%if %2
+    mov             r7d, 73-35*%3
+    add            bufq, 44
+.loop_y:
+    mov              r5, -44
+%else
+    mov              r5, -73*82
+    sub            bufq, r5
+%endif
+.loop:
+    pand            xm2, xm0, xm1
+    psrlw           xm3, xm2, 10
+    por             xm2, xm3            ; bits 0xf, 0x1e, 0x3c and 0x78 are set
+    pmullw          xm2, xm4            ; bits 0x0f00 are set
+    pmulhuw         xm0, xm5
+    pshufb          xm3, xm6, xm2       ; set 15th bit for next 4 seeds
+    psllq           xm2, xm3, 30
+    por             xm2, xm3
+    psllq           xm3, xm2, 15
+    por             xm2, xm0            ; aggregate each bit into next seed's high bit
+    por             xm2, xm3            ; 4 next output seeds
+    pshuflw         xm0, xm2, q3333
+    psrlw           xm2, 5
+    movq             r8, xm2
+    movzx           r9d, r8w
+    movd            xm2, [r6+r9*2]
+    rorx             r9, r8, 32
+    shr             r8d, 16
+    pinsrw          xm2, [r6+r8*2], 1
+    movzx           r8d, r9w
+    pinsrw          xm2, [r6+r8*2], 2
+    shr             r9d, 16
+    pinsrw          xm2, [r6+r9*2], 3
+    pmulhrsw        xm2, xm7
+    packsswb        xm2, xm2
+    movd      [bufq+r5], xm2
+    add              r5, 4
+    jl .loop
+%if %2
+    add            bufq, 82
+    dec             r7d
+    jg .loop_y
+%endif
+
+    ; auto-regression code
+    movsxd           r6, [fg_dataq+FGData.ar_coeff_lag]
+    movsxd           r6, [base+generate_grain_uv_%1_8bpc_avx2_table+r6*4]
+    add              r6, r4
+    jmp              r6
+
+INIT_YMM avx2
+.ar0:
+    DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift
+    imul            uvd, 28
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movd            xm2, [fg_dataq+FGData.ar_coeffs_uv+uvq]
+    movd            xm3, [base+hmul_bits+shiftq*2]
+    DEFINE_ARGS buf, bufy, h
+    pmovsxbw        xm2, xm2
+%if %2
+    vpbroadcastd     m7, [base+pb_1]
+    vpbroadcastw     m6, [base+hmul_bits+2+%3*2]
+%endif
+    vpbroadcastw     m2, xm2
+    vpbroadcastw     m3, xm3
+    pxor            m12, m12
+%if %2
+    sub            bufq, 82*(73-35*%3)+82-(82*3+41)
+%else
+    sub            bufq, 82*70-3
+%endif
+    add           bufyq, 3+82*3
+    mov              hd, 70-35*%3
+.y_loop_ar0:
+%if %2
+    ; first 32 pixels
+    movu            xm4, [bufyq]
+    vinserti128      m4, [bufyq+32], 1
+%if %3
+    movu            xm0, [bufyq+82]
+    vinserti128      m0, [bufyq+82+32], 1
+%endif
+    movu            xm5, [bufyq+16]
+    vinserti128      m5, [bufyq+48], 1
+%if %3
+    movu            xm1, [bufyq+82+16]
+    vinserti128      m1, [bufyq+82+48], 1
+%endif
+    pmaddubsw        m4, m7, m4
+%if %3
+    pmaddubsw        m0, m7, m0
+%endif
+    pmaddubsw        m5, m7, m5
+%if %3
+    pmaddubsw        m1, m7, m1
+    paddw            m4, m0
+    paddw            m5, m1
+%endif
+    pmulhrsw         m4, m6
+    pmulhrsw         m5, m6
+%else
+    xor             r3d, r3d
+    ; first 32x2 pixels
+.x_loop_ar0:
+    movu             m4, [bufyq+r3]
+    pcmpgtb          m0, m12, m4
+    punpckhbw        m5, m4, m0
+    punpcklbw        m4, m0
+%endif
+    pmullw           m4, m2
+    pmullw           m5, m2
+    pmulhrsw         m4, m3
+    pmulhrsw         m5, m3
+%if %2
+    movu             m1, [bufq]
+%else
+    movu             m1, [bufq+r3]
+%endif
+    pcmpgtb          m8, m12, m1
+    punpcklbw        m0, m1, m8
+    punpckhbw        m1, m8
+    paddw            m0, m4
+    paddw            m1, m5
+    packsswb         m0, m1
+%if %2
+    movu         [bufq], m0
+%else
+    movu      [bufq+r3], m0
+    add             r3d, 32
+    cmp             r3d, 64
+    jl .x_loop_ar0
+%endif
+
+    ; last 6/12 pixels
+    movu            xm4, [bufyq+32*2]
+%if %2
+%if %3
+    movu            xm5, [bufyq+32*2+82]
+%endif
+    pmaddubsw       xm4, xm7, xm4
+%if %3
+    pmaddubsw       xm5, xm7, xm5
+    paddw           xm4, xm5
+%endif
+    movq            xm0, [bufq+32]
+    pmulhrsw        xm4, xm6
+    pmullw          xm4, xm2
+    pmulhrsw        xm4, xm3
+    pcmpgtb         xm5, xm12, xm0
+    punpcklbw       xm5, xm0, xm5
+    paddw           xm4, xm5
+    packsswb        xm4, xm4
+    pblendw         xm0, xm4, xm0, 1000b
+    movq      [bufq+32], xm0
+%else
+    movu            xm0, [bufq+64]
+    pcmpgtb         xm1, xm12, xm4
+    punpckhbw       xm5, xm4, xm1
+    punpcklbw       xm4, xm1
+    pmullw          xm5, xm2
+    pmullw          xm4, xm2
+    vpblendd        xm1, xm3, xm12, 0x0c
+    pmulhrsw        xm5, xm1
+    pmulhrsw        xm4, xm3
+    pcmpgtb         xm1, xm12, xm0
+    punpckhbw       xm8, xm0, xm1
+    punpcklbw       xm0, xm1
+    paddw           xm5, xm8
+    paddw           xm0, xm4
+    packsswb        xm0, xm5
+    movu      [bufq+64], xm0
+%endif
+    add            bufq, 82
+    add           bufyq, 82<<%3
+    dec              hd
+    jg .y_loop_ar0
+    RET
+
+INIT_XMM avx2
+.ar1:
+    DEFINE_ARGS buf, bufy, fg_data, uv, val3, cf3, min, max, x, shift
+    imul            uvd, 28
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movsx          cf3d, byte [fg_dataq+FGData.ar_coeffs_uv+uvq+3]
+    movd            xm4, [fg_dataq+FGData.ar_coeffs_uv+uvq]
+    pinsrb          xm4, [fg_dataq+FGData.ar_coeffs_uv+uvq+4], 3
+    DEFINE_ARGS buf, bufy, h, val0, val3, cf3, min, max, x, shift
+    pmovsxbw        xm4, xm4
+    pshufd          xm5, xm4, q1111
+    pshufd          xm4, xm4, q0000
+    pmovsxwd        xm3, [base+round_vals+shiftq*2-12]    ; rnd
+%if %2
+    vpbroadcastd    xm7, [base+pb_1]
+    vpbroadcastw    xm6, [base+hmul_bits+2+%3*2]
+%endif
+    vpbroadcastd    xm3, xm3
+%if %2
+    sub            bufq, 82*(73-35*%3)+44-(82*3+41)
+%else
+    sub            bufq, 82*70-(82-3)
+%endif
+    add           bufyq, 79+82*3
+    mov              hd, 70-35*%3
+    mov            mind, -128
+    mov            maxd, 127
+.y_loop_ar1:
+    mov              xq, -(76>>%2)
+    movsx         val3d, byte [bufq+xq-1]
+.x_loop_ar1:
+    pmovsxbw        xm0, [bufq+xq-82-1]     ; top/left
+%if %2
+    movq            xm8, [bufyq+xq*2]
+%if %3
+    movq            xm9, [bufyq+xq*2+82]
+%endif
+%endif
+    psrldq          xm2, xm0, 2             ; top
+    psrldq          xm1, xm0, 4             ; top/right
+%if %2
+    pmaddubsw       xm8, xm7, xm8
+%if %3
+    pmaddubsw       xm9, xm7, xm9
+    paddw           xm8, xm9
+%endif
+    pmulhrsw        xm8, xm6
+%else
+    pmovsxbw        xm8, [bufyq+xq]
+%endif
+    punpcklwd       xm0, xm2
+    punpcklwd       xm1, xm8
+    pmaddwd         xm0, xm4
+    pmaddwd         xm1, xm5
+    paddd           xm0, xm1
+    paddd           xm0, xm3
+.x_loop_ar1_inner:
+    movd          val0d, xm0
+    psrldq          xm0, 4
+    imul          val3d, cf3d
+    add           val3d, val0d
+    sarx          val3d, val3d, shiftd
+    movsx         val0d, byte [bufq+xq]
+    add           val3d, val0d
+    cmp           val3d, maxd
+    cmovns        val3d, maxd
+    cmp           val3d, mind
+    cmovs         val3d, mind
+    mov  byte [bufq+xq], val3b
+    ; keep val3d in-place as left for next x iteration
+    inc              xq
+    jz .x_loop_ar1_end
+    test             xq, 3
+    jnz .x_loop_ar1_inner
+    jmp .x_loop_ar1
+
+.x_loop_ar1_end:
+    add            bufq, 82
+    add           bufyq, 82<<%3
+    dec              hd
+    jg .y_loop_ar1
+    RET
+
+.ar2:
+    DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    imul            uvd, 28
+    vpbroadcastw   xm13, [base+round_vals-12+shiftq*2]
+    pmovsxbw        xm7, [fg_dataq+FGData.ar_coeffs_uv+uvq+0]   ; cf0-7
+    pmovsxbw        xm0, [fg_dataq+FGData.ar_coeffs_uv+uvq+8]   ; cf8-12
+    pinsrw          xm0, [base+pw_1], 5
+%if %2
+    vpbroadcastw   xm12, [base+hmul_bits+2+%3*2]
+    vpbroadcastd   xm11, [base+pb_1]
+%endif
+    DEFINE_ARGS buf, bufy, fg_data, h, unused, x
+    pshufd          xm4, xm7, q0000
+    pshufd          xm5, xm7, q3333
+    pshufd          xm6, xm7, q1111
+    pshufd          xm7, xm7, q2222
+    pshufd          xm8, xm0, q0000
+    pshufd          xm9, xm0, q1111
+    pshufd         xm10, xm0, q2222
+%if %2
+    sub            bufq, 82*(73-35*%3)+44-(82*3+41)
+%else
+    sub            bufq, 82*70-(82-3)
+%endif
+    add           bufyq, 79+82*3
+    mov              hd, 70-35*%3
+.y_loop_ar2:
+    mov              xq, -(76>>%2)
+
+.x_loop_ar2:
+    pmovsxbw        xm0, [bufq+xq-82*2-2]   ; y=-2,x=[-2,+5]
+    pmovsxbw        xm1, [bufq+xq-82*1-2]   ; y=-1,x=[-2,+5]
+    pshufb          xm2, xm0, [base+gen_shufA]
+    pmaddwd         xm2, xm4
+    pshufb          xm3, xm1, [base+gen_shufB]
+    pmaddwd         xm3, xm5
+    paddd           xm2, xm3
+    pshufb          xm3, xm0, [base+gen_shufC]
+    pmaddwd         xm3, xm6
+    punpckhqdq      xm0, xm0                 ; y=-2,x=[+2,+5]
+    punpcklwd       xm0, xm1
+    pmaddwd         xm0, xm7
+    pshufb          xm1, [gen_shufD]
+    pmaddwd         xm1, xm8
+    paddd           xm2, xm3
+    paddd           xm0, xm1
+    paddd           xm2, xm0
+
+%if %2
+    movq            xm0, [bufyq+xq*2]
+%if %3
+    movq            xm3, [bufyq+xq*2+82]
+%endif
+    pmaddubsw       xm0, xm11, xm0
+%if %3
+    pmaddubsw       xm3, xm11, xm3
+    paddw           xm0, xm3
+%endif
+    pmulhrsw        xm0, xm12
+%else
+    pmovsxbw        xm0, [bufyq+xq]
+%endif
+    punpcklwd       xm0, xm13
+    pmaddwd         xm0, xm10
+    paddd           xm2, xm0
+
+    movq            xm0, [bufq+xq-2]        ; y=0,x=[-2,+5]
+.x_loop_ar2_inner:
+    pmovsxbw        xm0, xm0
+    pmaddwd         xm3, xm0, xm9
+    psrldq          xm0, 2
+    paddd           xm3, xm2
+    psrldq          xm2, 4                  ; shift top to next pixel
+    psrad           xm3, [fg_dataq+FGData.ar_coeff_shift]
+    pslldq          xm3, 2
+    paddw           xm3, xm0
+    pblendw         xm0, xm3, 00000010b
+    packsswb        xm0, xm0
+    pextrb    [bufq+xq], xm0, 1
+    inc              xq
+    jz .x_loop_ar2_end
+    test             xb, 3
+    jnz .x_loop_ar2_inner
+    jmp .x_loop_ar2
+
+.x_loop_ar2_end:
+    add            bufq, 82
+    add           bufyq, 82<<%3
+    dec              hd
+    jg .y_loop_ar2
+    RET
+
+INIT_YMM avx2
+.ar3:
+    DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    imul            uvd, 28
+    pmovsxbw         m0, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 0] ; cf0-15
+    pmovsxbw        xm1, [fg_dataq+FGData.ar_coeffs_uv+uvq+16] ; cf16-23
+    vpbroadcastb    xm2, [fg_dataq+FGData.ar_coeffs_uv+uvq+24] ; cf24 [luma]
+    movd           xm13, [base+round_vals-10+shiftq*2]
+    vpbroadcastd   xm14, [base+round_vals-14+shiftq*2]
+    pshufd           m6, m0, q0000
+    pshufd           m7, m0, q1111
+    pshufd           m8, m0, q2222
+    pshufd           m9, m0, q3333
+    pshufd         xm10, xm1, q0000
+    pshufd         xm11, xm1, q1111
+    pshufhw        xm12, xm1, q0000
+    psraw           xm2, 8
+    palignr        xm13, xm1, 10
+    punpckhwd      xm12, xm2                     ; interleave luma cf
+    psrld          xm14, 16
+    DEFINE_ARGS buf, bufy, fg_data, h, unused, x
+%if %2
+    vpbroadcastw   xm15, [base+hmul_bits+2+%3*2]
+    sub            bufq, 82*(73-35*%3)+44-(82*3+41)
+%else
+    sub            bufq, 82*70-(82-3)
+%endif
+    add           bufyq, 79+82*3
+    mov              hd, 70-35*%3
+.y_loop_ar3:
+    mov              xq, -(76>>%2)
+.x_loop_ar3:
+    vbroadcasti128   m3, [bufq+xq-82*2-3]         ; y=-2,x=[-3,+12
+    palignr         xm1, xm3, [bufq+xq-82*3-9], 6 ; y=-3,x=[-3,+12]
+    vbroadcasti128   m4, [bufq+xq-82*1-3]    ; y=-1,x=[-3,+12]
+    vpblendd         m3, m1, 0x0f
+    pxor             m0, m0
+    pcmpgtb          m2, m0, m3
+    pcmpgtb          m0, m4
+    punpcklbw        m1, m3, m2
+    punpckhbw        m3, m2
+    punpcklbw        m2, m4, m0
+    punpckhbw       xm4, xm0
+    pshufb           m0, m1, [base+gen_shufA]
+    pmaddwd          m0, m6
+    pshufb           m5, m1, [base+gen_shufC]
+    pmaddwd          m5, m7
+    shufps           m1, m3, q1032
+    paddd            m0, m5
+    pshufb           m5, m1, [base+gen_shufA]
+    pmaddwd          m5, m8
+    shufps          xm1, xm3, q2121
+    vpblendd         m1, m2, 0xf0
+    pshufb           m1, [base+gen_shufE]
+    pmaddwd          m1, m9
+    paddd            m0, m5
+    pshufb          xm3, xm2, [base+gen_shufC]
+    paddd            m0, m1
+    pmaddwd         xm3, xm10
+    palignr         xm1, xm4, xm2, 2
+    punpckhwd       xm1, xm2, xm1
+    pmaddwd         xm1, xm11
+    palignr         xm4, xm2, 12
+    paddd           xm3, xm1
+%if %2
+    vpbroadcastd    xm5, [base+pb_1]
+    movq            xm1, [bufyq+xq*2]
+    pmaddubsw       xm1, xm5, xm1
+%if %3
+    movq            xm2, [bufyq+xq*2+82]
+    pmaddubsw       xm5, xm2
+    paddw           xm1, xm5
+%endif
+    pmulhrsw        xm1, xm15
+%else
+    pmovsxbw        xm1, [bufyq+xq]
+%endif
+    punpcklwd       xm4, xm1
+    pmaddwd         xm4, xm12
+    movq            xm1, [bufq+xq-3]        ; y=0,x=[-3,+4]
+    vextracti128    xm2, m0, 1
+    paddd           xm0, xm14
+    paddd           xm3, xm4
+    paddd           xm0, xm3
+    paddd           xm0, xm2
+.x_loop_ar3_inner:
+    pmovsxbw        xm1, xm1
+    pmaddwd         xm2, xm13, xm1
+    pshuflw         xm3, xm2, q1032
+    paddd           xm2, xm0                ; add top
+    paddd           xm2, xm3                ; left+cur
+    psrldq          xm0, 4
+    psrad           xm2, [fg_dataq+FGData.ar_coeff_shift]
+    psrldq          xm1, 2
+    ; don't packssdw, we only care about one value
+    punpckldq       xm2, xm2
+    pblendw         xm1, xm2, 0100b
+    packsswb        xm1, xm1
+    pextrb    [bufq+xq], xm1, 2
+    inc              xq
+    jz .x_loop_ar3_end
+    test             xb, 3
+    jnz .x_loop_ar3_inner
+    jmp .x_loop_ar3
+.x_loop_ar3_end:
+    add            bufq, 82
+    add           bufyq, 82<<%3
+    dec              hd
+    jg .y_loop_ar3
+    RET
+%endmacro
+
+INIT_YMM avx2
+cglobal fgy_32x32xn_8bpc, 6, 13, 15, dst, src, stride, fg_data, w, scaling, \
+                                     grain_lut, h, sby, see, overlap
+%define base r9-pd_m65536
+    lea              r9, [pd_m65536]
+    mov             r6d, [fg_dataq+FGData.scaling_shift]
+    mov             r7d, [fg_dataq+FGData.clip_to_restricted_range]
+    mov            sbyd, sbym
+    mov        overlapd, [fg_dataq+FGData.overlap_flag]
+    vpbroadcastd     m8, [base+pd_m65536]
+    vpbroadcastw     m9, [base+mul_bits+r6*2-14]
+    vpbroadcastd    m10, [base+fg_min+r7*4]
+    vpbroadcastd    m11, [base+fg_max+r7*8]
+    vpbroadcastd    m12, [base+pw_1024]
+    movq           xm13, [base+pb_27_17_17_27]
+    test           sbyd, sbyd
+    setnz           r7b
+    pxor             m7, m7
+    test            r7b, overlapb
+    jnz .vertical_overlap
+
+    imul           seed, sbyd, (173 << 24) | 37
+    add            seed, (105 << 24) | 178
+    rorx           seed, seed, 24
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                offx, offy, see, overlap
+
+    lea        src_bakq, [srcq+wq]
+    neg              wq
+    sub            dstq, srcq
+
+.loop_x:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyd, [offyq+offxq*2+747] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                h, offxy, see, overlap
+
+    mov              hd, hm
+    mov      grain_lutq, grain_lutmp
+.loop_y:
+    ; src
+    mova             m2, [srcq]
+    punpcklbw        m0, m2, m7
+    punpckhbw        m1, m2, m7
+
+    ; scaling[src]
+    pandn            m4, m8, m0
+    mova             m6, m8
+    vpgatherdd       m2, [scalingq+m4-0], m8
+    psrld            m3, m0, 16
+    mova             m8, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pandn            m5, m8, m1
+    mova             m6, m8
+    vpgatherdd       m3, [scalingq+m5-0], m8
+    pblendw          m2, m4, 0xaa
+    psrld            m4, m1, 16
+    mova             m8, m6
+    vpgatherdd       m5, [scalingq+m4-2], m6
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m5, [grain_lutq+offxyq]
+    punpcklbw        m4, m5, m7
+    punpckhbw        m5, m7
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m2, m4
+    pmaddubsw        m3, m5
+    pmulhrsw         m2, m9
+    pmulhrsw         m3, m9
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    packuswb         m0, m1
+    pmaxub           m0, m10
+    pminub           m0, m11
+    mova    [dstq+srcq], m0
+
+    add            srcq, strideq
+    add      grain_lutq, 82
+    dec              hd
+    jg .loop_y
+
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq]
+    test       overlapd, overlapd
+    jz .loop_x
+
+    ; r8m = sbym
+    cmp       dword r8m, 0
+    jne .loop_x_hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+.loop_x_h_overlap:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy
+
+    lea     left_offxyd, [offyq+32]         ; previous column's offy*stride+offx
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyd, [offyq+offxq*2+747] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+.loop_y_h_overlap:
+    ; src
+    mova             m2, [srcq]
+    punpcklbw        m0, m2, m7
+    punpckhbw        m1, m2, m7
+
+    ; scaling[src]
+    pandn            m4, m8, m0
+    mova             m6, m8
+    vpgatherdd       m2, [scalingq+m4-0], m8
+    psrld            m3, m0, 16
+    mova             m8, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pandn            m5, m8, m1
+    mova             m6, m8
+    vpgatherdd       m3, [scalingq+m5-0], m8
+    pblendw          m2, m4, 0xaa
+    psrld            m4, m1, 16
+    mova             m8, m6
+    vpgatherdd       m5, [scalingq+m4-2], m6
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m5, [grain_lutq+offxyq]
+    movd            xm4, [grain_lutq+left_offxyq]
+    punpcklbw       xm4, xm5
+    pmaddubsw       xm4, xm13, xm4
+    pmulhrsw        xm4, xm12
+    packsswb        xm4, xm4
+    vpblendd         m4, m5, 0xfe
+    punpckhbw        m5, m7
+    punpcklbw        m4, m7
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m2, m4
+    pmaddubsw        m3, m5
+    pmulhrsw         m2, m9
+    pmulhrsw         m3, m9
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    packuswb         m0, m1
+    pmaxub           m0, m10
+    pminub           m0, m11
+    mova    [dstq+srcq], m0
+
+    add            srcq, strideq
+    add      grain_lutq, 82
+    dec              hd
+    jg .loop_y_h_overlap
+
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq]
+
+    ; r8m = sbym
+    cmp       dword r8m, 0
+    jne .loop_x_hv_overlap
+    jmp .loop_x_h_overlap
+
+.vertical_overlap:
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                unused, sby, see, overlap
+
+    movzx          sbyd, sbyb
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+    imul            r7d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             r7d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             r7d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, r7d
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                offx, offy, see, overlap
+
+    lea        src_bakq, [srcq+wq]
+    neg              wq
+    sub            dstq, srcq
+
+.loop_x_v_overlap:
+    vpbroadcastd    m14, [pb_27_17]
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*2+0x10001*747+32*82]
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                h, offxy, see, overlap, top_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+.loop_y_v_overlap:
+    ; src
+    mova             m2, [srcq]
+    punpcklbw        m0, m2, m7
+    punpckhbw        m1, m2, m7
+
+    ; scaling[src]
+    pandn            m4, m8, m0
+    mova             m6, m8
+    vpgatherdd       m2, [scalingq+m4-0], m8
+    psrld            m3, m0, 16
+    mova             m8, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pandn            m5, m8, m1
+    mova             m6, m8
+    vpgatherdd       m3, [scalingq+m5-0], m8
+    pblendw          m2, m4, 0xaa
+    psrld            m4, m1, 16
+    mova             m8, m6
+    vpgatherdd       m5, [scalingq+m4-2], m6
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m6, [grain_lutq+offxyq]
+    movu             m4, [grain_lutq+top_offxyq]
+    punpcklbw        m5, m4, m6
+    punpckhbw        m4, m6
+    pmaddubsw        m5, m14, m5
+    pmaddubsw        m4, m14, m4
+    pmulhrsw         m5, m12
+    pmulhrsw         m4, m12
+    packsswb         m5, m4
+    punpcklbw        m4, m5, m7
+    punpckhbw        m5, m7
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m2, m4
+    pmaddubsw        m3, m5
+    pmulhrsw         m2, m9
+    pmulhrsw         m3, m9
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    packuswb         m0, m1
+    pmaxub           m0, m10
+    pminub           m0, m11
+    mova    [dstq+srcq], m0
+
+    add            srcq, strideq
+    add      grain_lutq, 82
+    dec              hb
+    jz .end_y_v_overlap
+    vpbroadcastd    m14, [pb_17_27] ; swap weights for second v-overlap line
+    ; 2 lines get vertical overlap, then fall back to non-overlap code for
+    ; remaining (up to) 30 lines
+    add              hd, 0x80000000
+    jnc .loop_y_v_overlap
+    jmp .loop_y
+.end_y_v_overlap:
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq]
+
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump
+    ; back to .loop_x_v_overlap, and instead always fall-through to
+    ; h+v overlap
+.loop_x_hv_overlap:
+    vpbroadcastd    m14, [pb_27_17]
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, top_offxy, topleft_offxy
+
+    lea  topleft_offxyd, [top_offxyq+32]
+    lea     left_offxyd, [offyq+32]
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*2+0x10001*747+32*82]
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, top_offxy, topleft_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+.loop_y_hv_overlap:
+    ; src
+    mova             m2, [srcq]
+    punpcklbw        m0, m2, m7
+    punpckhbw        m1, m2, m7
+
+    ; scaling[src]
+    pandn            m4, m8, m0
+    mova             m6, m8
+    vpgatherdd       m2, [scalingq+m4-0], m8
+    psrld            m3, m0, 16
+    mova             m8, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pandn            m5, m8, m1
+    mova             m6, m8
+    vpgatherdd       m3, [scalingq+m5-0], m8
+    pblendw          m2, m4, 0xaa
+    psrld            m4, m1, 16
+    mova             m8, m6
+    vpgatherdd       m5, [scalingq+m4-2], m6
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m6, [grain_lutq+offxyq]
+    movd            xm7, [grain_lutq+left_offxyq]
+    movu             m4, [grain_lutq+top_offxyq]
+    movd            xm5, [grain_lutq+topleft_offxyq]
+    ; do h interpolation first (so top | top/left -> top, left | cur -> cur)
+    punpcklbw       xm7, xm6
+    punpcklbw       xm5, xm4
+    pmaddubsw       xm7, xm13, xm7
+    pmaddubsw       xm5, xm13, xm5
+    pmulhrsw        xm7, xm12
+    pmulhrsw        xm5, xm12
+    packsswb        xm7, xm7
+    packsswb        xm5, xm5
+    vpblendd         m7, m6, 0xfe
+    vpblendd         m5, m4, 0xfe
+    ; followed by v interpolation (top | cur -> cur)
+    punpckhbw        m4, m6
+    punpcklbw        m5, m7
+    pmaddubsw        m4, m14, m4
+    pmaddubsw        m5, m14, m5
+    pmulhrsw         m4, m12
+    pmulhrsw         m5, m12
+    pxor             m7, m7
+    packsswb         m5, m4
+    punpcklbw        m4, m5, m7
+    punpckhbw        m5, m7
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m2, m4
+    pmaddubsw        m3, m5
+    pmulhrsw         m2, m9
+    pmulhrsw         m3, m9
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    packuswb         m0, m1
+    pmaxub           m0, m10
+    pminub           m0, m11
+    mova    [dstq+srcq], m0
+
+    add            srcq, strideq
+    add      grain_lutq, 82
+    dec              hb
+    jz .end_y_hv_overlap
+    vpbroadcastd    m14, [pb_17_27] ; swap weights for second v-overlap line
+    ; 2 lines get vertical overlap, then fall back to non-overlap code for
+    ; remaining (up to) 30 lines
+    add              hd, 0x80000000
+    jnc .loop_y_hv_overlap
+    jmp .loop_y_h_overlap
+.end_y_hv_overlap:
+    add              wq, 32
+    lea            srcq, [src_bakq+wq]
+    jl .loop_x_hv_overlap
+.end:
+    RET
+
+%macro FGUV_FN 3 ; name, ss_hor, ss_ver
+cglobal fguv_32x32xn_i%1_8bpc, 6, 15, 16, dst, src, stride, fg_data, w, scaling, \
+                                          grain_lut, h, sby, luma, overlap, uv_pl, is_id
+%define base r11-pd_m65536
+    lea             r11, [pd_m65536]
+    mov             r6d, [fg_dataq+FGData.scaling_shift]
+    mov             r7d, [fg_dataq+FGData.clip_to_restricted_range]
+    mov             r9d, is_idm
+    mov            sbyd, sbym
+    mov        overlapd, [fg_dataq+FGData.overlap_flag]
+    vpbroadcastd     m8, [base+pd_m65536]
+    vpbroadcastw     m9, [base+mul_bits+r6*2-14]
+    vpbroadcastd    m10, [base+fg_min+r7*4]
+    shlx            r7d, r7d, r9d
+    vpbroadcastd    m11, [base+fg_max+r7*4]
+    vpbroadcastd    m12, [base+pw_1024]
+    pxor             m7, m7
+    test           sbyd, sbyd
+    setnz           r7b
+    cmp byte [fg_dataq+FGData.chroma_scaling_from_luma], 0
+    jne .csfl
+
+%macro %%FGUV_32x32xN_LOOP 3 ; not-csfl, ss_hor, ss_ver
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, \
+                h, sby, see, overlap, uv_pl
+%if %1
+    mov             r6d, uv_plm
+    vpbroadcastd     m0, [base+pw_8]
+    vbroadcasti128  m14, [fg_dataq+FGData.uv_mult+r6*4]
+    vpbroadcastw    m15, [fg_dataq+FGData.uv_offset+r6*4]
+    pshufb          m14, m0 ; uv_luma_mult, uv_mult
+%elif %2
+    vpbroadcastq    m15, [base+pb_23_22]
+%else
+    vpbroadcastq   xm15, [base+pb_27_17_17_27]
+%endif
+%if %3
+    vpbroadcastw    m13, [base+pb_23_22]
+%elif %2
+    pshufd          m13, [base+pb_27_17], q0000 ; 8x27_17, 8x17_27
+%endif
+    test            r7b, overlapb
+    jnz %%vertical_overlap
+
+    imul           seed, sbyd, (173 << 24) | 37
+    add            seed, (105 << 24) | 178
+    rorx           seed, seed, 24
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                unused2, unused3, see, overlap, unused4, unused5, lstride
+
+    mov           lumaq, r9mp
+    lea             r12, [srcq+wq]
+    lea             r13, [dstq+wq]
+    lea             r14, [lumaq+wq*(1+%2)]
+    mov           r11mp, r12
+    mov           r12mp, r13
+    mov        lstrideq, r10mp
+    neg              wq
+
+%%loop_x:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, overlap, unused1, unused2, lstride
+
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyd, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)]  ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                h, offxy, see, overlap, unused1, unused2, lstride
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+%%loop_y:
+    ; src
+%if %2
+    mova            xm3, [lumaq+lstrideq*0+ 0]
+    vinserti128      m3, [lumaq+lstrideq*(1+%3) +0], 1
+    vpbroadcastd     m2, [pb_1]
+    mova            xm0, [lumaq+lstrideq*0+16]
+    vinserti128      m0, [lumaq+lstrideq*(1+%3)+16], 1
+    mova            xm1, [srcq]
+    vinserti128      m1, [srcq+strideq], 1
+    pmaddubsw        m3, m2
+    pmaddubsw        m0, m2
+    pavgw            m3, m7
+    pavgw            m0, m7
+%else
+    mova             m2, [lumaq]
+    mova             m1, [srcq]
+%endif
+%if %1
+%if %2
+    packuswb         m2, m3, m0             ; luma
+%endif
+    punpckhbw        m3, m2, m1
+    punpcklbw        m2, m1                 ; { luma, chroma }
+    pmaddubsw        m3, m14
+    pmaddubsw        m2, m14
+    psraw            m3, 6
+    psraw            m2, 6
+    paddw            m3, m15
+    paddw            m2, m15
+    packuswb         m2, m3                 ; pack+unpack = clip
+%endif
+%if %1 || %2 == 0
+    punpcklbw        m3, m2, m7
+    punpckhbw        m0, m2, m7
+%endif
+
+    ; scaling[luma_src]
+    pandn            m4, m8, m3
+    mova             m6, m8
+    vpgatherdd       m2, [scalingq+m4-0], m8
+    psrld            m3, 16
+    mova             m8, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pandn            m5, m8, m0
+    mova             m6, m8
+    vpgatherdd       m3, [scalingq+m5-0], m8
+    psrld            m0, 16
+    mova             m8, m6
+    vpgatherdd       m5, [scalingq+m0-2], m6
+    pblendw          m2, m4, 0xaa
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+%if %2
+    movu            xm5, [grain_lutq+offxyq+ 0]
+    vinserti128      m5, [grain_lutq+offxyq+82], 1
+%else
+    movu             m5, [grain_lutq+offxyq]
+%endif
+    punpcklbw        m4, m5, m7
+    punpckhbw        m5, m7
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmaddubsw        m2, m4
+    pmaddubsw        m3, m5
+    pmulhrsw         m2, m9
+    pmulhrsw         m3, m9
+
+    ; unpack chroma_source
+    punpcklbw        m0, m1, m7
+    punpckhbw        m1, m7
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    packuswb         m0, m1
+    pmaxub           m0, m10
+    pminub           m0, m11
+%if %2
+    mova         [dstq], xm0
+    vextracti128 [dstq+strideq], m0, 1
+%else
+    mova         [dstq], m0
+%endif
+
+%if %2
+    lea            srcq, [srcq+strideq*2]
+    lea            dstq, [dstq+strideq*2]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+%else
+    add            srcq, strideq
+    add            dstq, strideq
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82<<%2
+    sub              hb, 1+%2
+    jg %%loop_y
+
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r11mp
+    mov            dstq, r12mp
+    lea           lumaq, [r14+wq*(1+%2)]
+    add            srcq, wq
+    add            dstq, wq
+    test       overlapd, overlapd
+    jz %%loop_x
+
+    ; r8m = sbym
+    cmp       dword r8m, 0
+    jne %%loop_x_hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+%%loop_x_h_overlap:
+    rorx             r6, seeq, 1
+    or             seed, 0xEFF4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, unused1, unused2, lstride
+
+    lea     left_offxyd, [offyq+(32>>%2)]         ; previous column's offy*stride+offx
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyd, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)]  ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, unused1, unused2, lstride
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+%%loop_y_h_overlap:
+    ; src
+%if %2
+    mova            xm3, [lumaq+lstrideq*0+ 0]
+    vinserti128      m3, [lumaq+lstrideq*(1+%3)+ 0], 1
+    vpbroadcastd     m2, [pb_1]
+    mova            xm0, [lumaq+lstrideq*0+16]
+    vinserti128      m0, [lumaq+lstrideq*(1+%3)+16], 1
+    mova            xm1, [srcq]
+    vinserti128      m1, [srcq+strideq], 1
+    pmaddubsw        m3, m2
+    pmaddubsw        m0, m2
+    pavgw            m3, m7
+    pavgw            m0, m7
+%else
+    mova             m2, [lumaq]
+    mova             m1, [srcq]
+%endif
+%if %1
+%if %2
+    packuswb         m2, m3, m0             ; luma
+%endif
+    punpckhbw        m3, m2, m1
+    punpcklbw        m2, m1                 ; { luma, chroma }
+    pmaddubsw        m3, m14
+    pmaddubsw        m2, m14
+    psraw            m3, 6
+    psraw            m2, 6
+    paddw            m3, m15
+    paddw            m2, m15
+    packuswb         m2, m3                 ; pack+unpack = clip
+%endif
+%if %1 || %2 == 0
+    punpcklbw        m3, m2, m7
+    punpckhbw        m0, m2, m7
+%endif
+
+    ; scaling[luma_src]
+    pandn            m4, m8, m3
+    mova             m6, m8
+    vpgatherdd       m2, [scalingq+m4-0], m8
+    psrld            m3, 16
+    mova             m8, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pandn            m5, m8, m0
+    mova             m6, m8
+    vpgatherdd       m3, [scalingq+m5-0], m8
+    psrld            m0, 16
+    mova             m8, m6
+    vpgatherdd       m5, [scalingq+m0-2], m6
+    pblendw          m2, m4, 0xaa
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+%if %2
+    movu            xm5, [grain_lutq+offxyq+ 0]
+    vinserti128      m5, [grain_lutq+offxyq+82], 1
+    movd            xm4, [grain_lutq+left_offxyq+ 0]
+    vinserti128      m4, [grain_lutq+left_offxyq+82], 1
+    punpcklbw        m4, m5
+%if %1
+    vpbroadcastq     m0, [pb_23_22]
+    pmaddubsw        m4, m0, m4
+%else
+    pmaddubsw        m4, m15, m4
+%endif
+    pmulhrsw         m4, m12
+    packsswb         m4, m4
+    vpblendd         m4, m5, 0xee
+%else
+    movu             m5, [grain_lutq+offxyq]
+    movd            xm4, [grain_lutq+left_offxyq]
+    punpcklbw       xm4, xm5
+%if %1
+    movq            xm0, [pb_27_17_17_27]
+    pmaddubsw       xm4, xm0, xm4
+%else
+    pmaddubsw       xm4, xm15, xm4
+%endif
+    pmulhrsw        xm4, xm12
+    packsswb        xm4, xm4
+    vpblendd         m4, m5, 0xfe
+%endif
+    punpckhbw        m5, m7
+    punpcklbw        m4, m7
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmaddubsw        m2, m4
+    pmaddubsw        m3, m5
+    pmulhrsw         m2, m9
+    pmulhrsw         m3, m9
+
+    ; unpack chroma_source
+    punpcklbw        m0, m1, m7
+    punpckhbw        m1, m7
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    packuswb         m0, m1
+    pmaxub           m0, m10
+    pminub           m0, m11
+%if %2
+    mova         [dstq], xm0
+    vextracti128 [dstq+strideq], m0, 1
+%else
+    mova         [dstq], m0
+%endif
+
+%if %2
+    lea            srcq, [srcq+strideq*2]
+    lea            dstq, [dstq+strideq*2]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+%else
+    add            srcq, strideq
+    add            dstq, strideq
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82*(1+%2)
+    sub              hb, 1+%2
+    jg %%loop_y_h_overlap
+
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r11mp
+    mov            dstq, r12mp
+    lea           lumaq, [r14+wq*(1+%2)]
+    add            srcq, wq
+    add            dstq, wq
+
+    ; r8m = sbym
+    cmp       dword r8m, 0
+    jne %%loop_x_hv_overlap
+    jmp %%loop_x_h_overlap
+
+%%vertical_overlap:
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused, \
+                sby, see, overlap, unused1, unused2, lstride
+
+    movzx          sbyd, sbyb
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+    imul            r7d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             r7d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             r7d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, r7d
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                unused1, unused2, see, overlap, unused3, unused4, lstride
+
+    mov           lumaq, r9mp
+    lea             r12, [srcq+wq]
+    lea             r13, [dstq+wq]
+    lea             r14, [lumaq+wq*(1+%2)]
+    mov           r11mp, r12
+    mov           r12mp, r13
+    mov        lstrideq, r10mp
+    neg              wq
+
+%%loop_x_v_overlap:
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, overlap, top_offxy, unused, lstride
+
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                h, offxy, see, overlap, top_offxy, unused, lstride
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+%if %2 == 0
+    vpbroadcastd    m13, [pb_27_17]
+%endif
+%%loop_y_v_overlap:
+    ; src
+%if %2
+    mova            xm3, [lumaq+lstrideq*0+ 0]
+    vinserti128      m3, [lumaq+lstrideq*(1+%3)+ 0], 1
+    vpbroadcastd     m2, [pb_1]
+    mova            xm0, [lumaq+lstrideq*0+16]
+    vinserti128      m0, [lumaq+lstrideq*(1+%3)+16], 1
+    mova            xm1, [srcq]
+    vinserti128      m1, [srcq+strideq], 1
+    pmaddubsw        m3, m2
+    pmaddubsw        m0, m2
+    pavgw            m3, m7
+    pavgw            m0, m7
+%else
+    mova             m2, [lumaq]
+    mova             m1, [srcq]
+%endif
+%if %1
+%if %2
+    packuswb         m2, m3, m0             ; luma
+%endif
+    punpckhbw        m3, m2, m1
+    punpcklbw        m2, m1                 ; { luma, chroma }
+    pmaddubsw        m3, m14
+    pmaddubsw        m2, m14
+    psraw            m3, 6
+    psraw            m2, 6
+    paddw            m3, m15
+    paddw            m2, m15
+    packuswb         m2, m3                 ; pack+unpack = clip
+%endif
+%if %1 || %2 == 0
+    punpcklbw        m3, m2, m7
+    punpckhbw        m0, m2, m7
+%endif
+
+    ; scaling[luma_src]
+    pandn            m4, m8, m3
+    mova             m6, m8
+    vpgatherdd       m2, [scalingq+m4-0], m8
+    psrld            m3, 16
+    mova             m8, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pandn            m5, m8, m0
+    mova             m6, m8
+    vpgatherdd       m3, [scalingq+m5-0], m8
+    psrld            m0, 16
+    mova             m8, m6
+    vpgatherdd       m5, [scalingq+m0-2], m6
+    pblendw          m2, m4, 0xaa
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+%if %3 == 0
+%if %2
+    movu            xm0, [grain_lutq+offxyq]
+    vinserti128      m0, [grain_lutq+offxyq+82], 1
+    movu            xm4, [grain_lutq+top_offxyq]
+    vinserti128      m4, [grain_lutq+top_offxyq+82], 1
+%else
+    movu             m0, [grain_lutq+offxyq]
+    movu             m4, [grain_lutq+top_offxyq]
+%endif
+    punpcklbw        m5, m4, m0
+    punpckhbw        m4, m0
+    pmaddubsw        m5, m13, m5
+    pmaddubsw        m4, m13, m4
+    pmulhrsw         m5, m12
+    pmulhrsw         m4, m12
+    packsswb         m5, m4
+%else
+    movq            xm4, [grain_lutq+offxyq]
+    vinserti128      m4, [grain_lutq+offxyq+8], 1
+    movq            xm5, [grain_lutq+top_offxyq]
+    vinserti128      m5, [grain_lutq+top_offxyq+8], 1
+    punpcklbw        m5, m4
+    pmaddubsw        m5, m13, m5
+    pmulhrsw         m5, m12
+    vextracti128    xm4, m5, 1
+    packsswb        xm5, xm4
+    ; only interpolate first line, insert second line unmodified
+    vinserti128      m5, [grain_lutq+offxyq+82], 1
+%endif
+    punpcklbw        m4, m5, m7
+    punpckhbw        m5, m7
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmaddubsw        m2, m4
+    pmaddubsw        m3, m5
+    pmulhrsw         m2, m9
+    pmulhrsw         m3, m9
+
+    ; unpack chroma_source
+    punpcklbw        m0, m1, m7
+    punpckhbw        m1, m7
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    packuswb         m0, m1
+    pmaxub           m0, m10
+    pminub           m0, m11
+%if %2
+    mova         [dstq], xm0
+    vextracti128 [dstq+strideq], m0, 1
+%else
+    mova         [dstq], m0
+%endif
+
+    sub              hb, 1+%2
+    jle %%end_y_v_overlap
+%if %2
+    lea            srcq, [srcq+strideq*2]
+    lea            dstq, [dstq+strideq*2]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+%else
+    add            srcq, strideq
+    add            dstq, strideq
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82<<%2
+%if %2 == 0
+    vpbroadcastd    m13, [pb_17_27]
+    add              hd, 0x80000000
+    jnc %%loop_y_v_overlap
+%endif
+    jmp %%loop_y
+
+%%end_y_v_overlap:
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r11mp
+    mov            dstq, r12mp
+    lea           lumaq, [r14+wq*(1+%2)]
+    add            srcq, wq
+    add            dstq, wq
+
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump
+    ; back to .loop_x_v_overlap, and instead always fall-through to
+    ; h+v overlap
+
+%%loop_x_hv_overlap:
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b                     ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1             ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, top_offxy, topleft_offxy, lstride
+
+    lea  topleft_offxyd, [top_offxyq+(32>>%2)]
+    lea     left_offxyd, [offyq+(32>>%2)]
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, top_offxy, topleft_offxy, lstride
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+%if %2 == 0
+    vpbroadcastd    m13, [pb_27_17]
+%endif
+%%loop_y_hv_overlap:
+    ; src
+%if %2
+    mova            xm3, [lumaq+lstrideq*0+ 0]
+    vinserti128      m3, [lumaq+lstrideq*(1+%3)+ 0], 1
+    vpbroadcastd     m2, [pb_1]
+    mova            xm0, [lumaq+lstrideq*0+16]
+    vinserti128      m0, [lumaq+lstrideq*(1+%3)+16], 1
+    mova            xm1, [srcq]
+    vinserti128      m1, [srcq+strideq], 1
+    pmaddubsw        m3, m2
+    pmaddubsw        m0, m2
+    pavgw            m3, m7
+    pavgw            m0, m7
+%else
+    mova             m2, [lumaq]
+    mova             m1, [srcq]
+%endif
+%if %1
+%if %2
+    packuswb         m2, m3, m0             ; luma
+%endif
+    punpckhbw        m3, m2, m1
+    punpcklbw        m2, m1                 ; { luma, chroma }
+    pmaddubsw        m3, m14
+    pmaddubsw        m2, m14
+    psraw            m3, 6
+    psraw            m2, 6
+    paddw            m3, m15
+    paddw            m2, m15
+    packuswb         m2, m3                 ; pack+unpack = clip
+%endif
+%if %1 || %2 == 0
+    punpcklbw        m3, m2, m7
+    punpckhbw        m0, m2, m7
+%endif
+
+    ; scaling[luma_src]
+    pandn            m4, m8, m3
+    mova             m6, m8
+    vpgatherdd       m2, [scalingq+m4-0], m8
+    psrld            m3, 16
+    mova             m8, m6
+    vpgatherdd       m4, [scalingq+m3-2], m6
+    pandn            m5, m8, m0
+    mova             m6, m8
+    vpgatherdd       m3, [scalingq+m5-0], m8
+    psrld            m0, 16
+    mova             m8, m6
+    vpgatherdd       m5, [scalingq+m0-2], m6
+    pblendw          m2, m4, 0xaa
+    pblendw          m3, m5, 0xaa
+
+    ; grain = grain_lut[offy+y][offx+x]
+%if %2
+    movu            xm4, [grain_lutq+offxyq]
+    vinserti128      m4, [grain_lutq+offxyq+82], 1
+    movd            xm0, [grain_lutq+left_offxyq]
+    vinserti128      m0, [grain_lutq+left_offxyq+82], 1
+    movd            xm6, [grain_lutq+topleft_offxyq]
+%if %3
+    movq            xm5, [grain_lutq+top_offxyq]
+    vinserti128      m5, [grain_lutq+top_offxyq+8], 1
+%else
+    vinserti128      m6, [grain_lutq+topleft_offxyq+82], 1
+    movu            xm5, [grain_lutq+top_offxyq]
+    vinserti128      m5, [grain_lutq+top_offxyq+82], 1
+%endif
+
+    ; do h interpolation first (so top | top/left -> top, left | cur -> cur)
+    punpcklbw        m0, m4
+%if %3
+    punpcklbw       xm6, xm5
+%else
+    punpcklbw        m6, m5
+%endif
+    punpcklqdq       m0, m6
+%if %1
+    vpbroadcastq     m6, [pb_23_22]
+    pmaddubsw        m0, m6, m0
+%else
+    pmaddubsw        m0, m15, m0
+%endif
+    pmulhrsw         m0, m12
+    packsswb         m0, m0
+    vpblendd         m4, m0, 0x11
+%if %3
+    pshuflw         xm0, xm0, q1032
+    vpblendd         m5, m0, 0x01
+%else
+    pshuflw          m0, m0, q1032
+    vpblendd         m5, m0, 0x11
+%endif
+%else
+    movu             m4, [grain_lutq+offxyq]
+    movd            xm0, [grain_lutq+left_offxyq]
+    movu             m5, [grain_lutq+top_offxyq]
+    movd            xm6, [grain_lutq+topleft_offxyq]
+    punpcklbw       xm0, xm4
+    punpcklbw       xm6, xm5
+    punpcklqdq      xm0, xm6
+%if %1
+    vpbroadcastq    xm6, [pb_27_17_17_27]
+    pmaddubsw       xm0, xm6, xm0
+%else
+    pmaddubsw       xm0, xm15, xm0
+%endif
+    pmulhrsw        xm0, xm12
+    packsswb        xm0, xm0
+    vpblendd         m4, m0, 0x01
+    pshuflw         xm0, xm0, q1032
+    vpblendd         m5, m0, 0x01
+%endif
+
+    ; followed by v interpolation (top | cur -> cur)
+%if %3
+    vpermq           m0, m4, q3120
+    punpcklbw        m5, m0
+    pmaddubsw        m5, m13, m5
+    pmulhrsw         m5, m12
+    vextracti128    xm0, m5, 1
+    packsswb        xm5, xm0
+    vpblendd         m5, m4, 0xf0
+%else
+    punpckhbw        m0, m5, m4
+    punpcklbw        m5, m4
+    pmaddubsw        m4, m13, m0
+    pmaddubsw        m5, m13, m5
+    pmulhrsw         m4, m12
+    pmulhrsw         m5, m12
+    packsswb         m5, m4
+%endif
+    punpcklbw        m4, m5, m7
+    punpckhbw        m5, m7
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmaddubsw        m2, m4
+    pmaddubsw        m3, m5
+    pmulhrsw         m2, m9
+    pmulhrsw         m3, m9
+
+    ; unpack chroma source
+    punpcklbw        m0, m1, m7
+    punpckhbw        m1, m7
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    packuswb         m0, m1
+    pmaxub           m0, m10
+    pminub           m0, m11
+%if %2
+    mova         [dstq], xm0
+    vextracti128 [dstq+strideq], m0, 1
+%else
+    mova         [dstq], m0
+%endif
+
+%if %2
+    lea            srcq, [srcq+strideq*2]
+    lea            dstq, [dstq+strideq*2]
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+%else
+    add            srcq, strideq
+    add            dstq, strideq
+    add           lumaq, lstrideq
+%endif
+    add      grain_lutq, 82<<%2
+    sub              hb, 1+%2
+%if %2
+    jg %%loop_y_h_overlap
+%else
+    je %%end_y_hv_overlap
+    vpbroadcastd    m13, [pb_17_27]
+    add              hd, 0x80000000
+    jnc %%loop_y_hv_overlap
+    jmp %%loop_y_h_overlap
+%endif
+
+%%end_y_hv_overlap:
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r11mp
+    mov            dstq, r12mp
+    lea           lumaq, [r14+wq*(1+%2)]
+    add            srcq, wq
+    add            dstq, wq
+    jmp %%loop_x_hv_overlap
+%endmacro
+
+    %%FGUV_32x32xN_LOOP 1, %2, %3
+.csfl:
+    %%FGUV_32x32xN_LOOP 0, %2, %3
+.end:
+    RET
+%endmacro
+
+GEN_GRAIN_UV_FN 420, 1, 1
+FGUV_FN         420, 1, 1
+GEN_GRAIN_UV_FN 422, 1, 0
+FGUV_FN         422, 1, 0
+GEN_GRAIN_UV_FN 444, 0, 0
+FGUV_FN         444, 0, 0
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/filmgrain_avx512.asm b/media/libdav1d/src/src/x86/filmgrain_avx512.asm
new file mode 100644
index 0000000000..317ec118b3
--- /dev/null
+++ b/media/libdav1d/src/src/x86/filmgrain_avx512.asm
@@ -0,0 +1,813 @@
+; Copyright © 2022, VideoLAN and dav1d authors
+; Copyright © 2022, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+%include "x86/filmgrain_common.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+pb_even:       db  0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+               db 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62
+               db 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94
+               db 96, 98,100,102,104,106,108,110,112,114,116,118,120,122,124,126
+pb_odd:        db  1,  3,  5,  7,  9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31
+               db 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63
+               db 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95
+               db 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127
+interleave_hl: db  8,  0,  9,  1, 10,  2, 11,  3, 12,  4, 13,  5, 14,  6, 15,  7
+pb_27_17_17_27:        db 27, 17, 17, 27,  0, 32,  0, 32
+pb_23_22_0_32:         db 23, 22,  0, 32,  0, 32,  0, 32
+pb_27_17:      times 2 db 27, 17
+pb_23_22:      times 2 db 23, 22
+pw_8:          times 2 dw 8
+pw_1024:       times 2 dw 1024
+pb_17_27:      times 2 db 17, 27
+fg_max:        times 4 db 255
+               times 4 db 240
+               times 4 db 235
+fg_min:        times 4 db 0
+               times 4 db 16
+noise_rnd:     times 2 dw 128
+               times 2 dw 64
+               times 2 dw 32
+               times 2 dw 16
+
+SECTION .text
+
+INIT_ZMM avx512icl
+cglobal fgy_32x32xn_8bpc, 6, 13, 22, dst, src, stride, fg_data, w, scaling, \
+                                     grain_lut, h, sby, see, overlap
+%define base r11-fg_min
+    lea             r11, [fg_min]
+    mov             r6d, [fg_dataq+FGData.scaling_shift]
+    mov             r7d, [fg_dataq+FGData.clip_to_restricted_range]
+    mov            sbyd, sbym
+    mov        overlapd, [fg_dataq+FGData.overlap_flag]
+    mov             r12, 0x0000000f0000000f ; h_overlap mask
+    mova             m0, [scalingq+64*0]
+    mova             m1, [scalingq+64*1]
+    mova             m2, [scalingq+64*2]
+    mova             m3, [scalingq+64*3]
+    kmovq            k1, r12
+    vbroadcasti32x4  m4, [base+interleave_hl]
+    vpbroadcastd   ym16, [base+pb_27_17]
+    vpbroadcastd    m12, [base+pb_17_27]
+    vpbroadcastd     m6, [base+noise_rnd+r6*4-32]
+    test           sbyd, sbyd
+    setnz           r6b
+    vpbroadcastd     m7, [base+fg_min+r7*4]
+    vpbroadcastd     m8, [base+fg_max+r7*8]
+    pxor             m5, m5
+    vpbroadcastd     m9, [base+pw_1024]
+    vpbroadcastq    m10, [base+pb_27_17_17_27]
+    vmovdqa64   m12{k1}, m16
+    test            r6b, overlapb
+    jnz .v_overlap
+
+    imul           seed, sbyd, (173 << 24) | 37
+    add            seed, (105 << 24) | 178
+    rorx           seed, seed, 24
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, offx, offy, \
+                h, sby, see, overlap
+
+    lea        src_bakq, [srcq+wq]
+    neg              wq
+    sub            dstq, srcq
+.loop_x:
+    rorx             r6, seeq, 1
+    or             seed, 0xeff4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                 ; updated seed
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offxd, [offyq+offxq*2+829] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, offxy, grain_lut, \
+                h, sby, see, overlap
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+.loop_y:
+    movu           ym21, [grain_lutq+offxyq-82]
+    vinserti32x8    m21, [grain_lutq+offxyq+ 0], 1
+    call .add_noise
+    sub              hb, 2
+    jg .loop_y
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq]
+    test       overlapd, overlapd
+    jz .loop_x
+    test           sbyd, sbyd
+    jnz .hv_overlap
+
+.loop_x_h_overlap:
+    rorx             r6, seeq, 1
+    or             seed, 0xeff4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                 ; updated seed
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, offx, offy, \
+                h, sby, see, left_offxy
+
+    rorx          offyd, seed, 8
+    mov     left_offxyd, offxd               ; previous column's offy*stride
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offxd, [offyq+offxq*2+829] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, offxy, grain_lut, \
+                h, sby, see, left_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+.loop_y_h_overlap:
+    movu           ym20, [grain_lutq+offxyq-82]
+    vinserti32x8    m20, [grain_lutq+offxyq+ 0], 1
+    movd           xm19, [grain_lutq+left_offxyq-50]
+    vinserti32x4    m19, [grain_lutq+left_offxyq+32], 2
+    punpcklbw       m19, m20
+    pmaddubsw       m19, m10, m19
+    pmulhrsw        m19, m9
+    punpckhbw       m21, m20, m5
+    packsswb    m20{k1}, m19, m19
+    punpcklbw       m20, m5, m20
+    call .add_noise_h
+    sub              hb, 2
+    jg .loop_y_h_overlap
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq]
+    test           sbyd, sbyd
+    jnz .hv_overlap
+    jmp .loop_x_h_overlap
+
+.v_overlap:
+    DEFINE_ARGS dst, src, stride, fg_data, w, offy, offx, \
+                h, sby, see, overlap
+
+    movzx           r6d, sbyb
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+    imul            r7d, r6d, 173 * 0x00010001
+    imul            r6d, 37 * 0x01000100
+    add             r7d, (105 << 16) | 188
+    add             r6d, (178 << 24) | (141 << 8)
+    and             r7d, 0x00ff00ff
+    and             r6d, 0xff00ff00
+    xor            seed, r7d
+    xor            seed, r6d     ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, offx, offy, \
+                h, sby, see, overlap
+
+    lea        src_bakq, [srcq+wq]
+    neg              wq
+    sub            dstq, srcq
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b          ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b          ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1  ; updated (cur_seed << 16) | top_seed
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offxd, [offyq+offxq*2+0x10001*829+32*82]
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, offxy, grain_lut, \
+                h, sby, see, overlap, top_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+    movu           ym19, [grain_lutq+offxyq-82]
+    vinserti32x8    m19, [grain_lutq+offxyq+ 0], 1
+    movu           ym21, [grain_lutq+top_offxyq-82]
+    vinserti32x8    m21, [grain_lutq+top_offxyq+ 0], 1
+    punpckhbw       m20, m21, m19
+    punpcklbw       m21, m19
+    call .add_noise_v
+    sub              hb, 2
+    jg .loop_y
+    add              wq, 32
+    jge .end
+    lea            srcq, [src_bakq+wq]
+
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump back
+    ; to .v_overlap, and instead always fall-through to h+v overlap
+.hv_overlap:
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b          ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b          ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1  ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, offx, offy, \
+                h, sby, see, left_offxy, top_offxy, topleft_offxy
+
+    mov  topleft_offxyd, top_offxyd
+    rorx          offyd, seed, 8
+    mov     left_offxyd, offxd
+    rorx          offxd, seed, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offxd, [offyq+offxq*2+0x10001*829+32*82]
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, offxy, grain_lut, \
+                h, sby, see, left_offxy, top_offxy, topleft_offxy
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+    movu           ym19, [grain_lutq+offxyq-82]
+    vinserti32x8    m19, [grain_lutq+offxyq+ 0], 1
+    movd           xm16, [grain_lutq+left_offxyq-50]
+    vinserti32x4    m16, [grain_lutq+left_offxyq+32], 2
+    movu           ym21, [grain_lutq+top_offxyq-82]
+    vinserti32x8    m21, [grain_lutq+top_offxyq+ 0], 1
+    movd           xm17, [grain_lutq+topleft_offxyq-50]
+    vinserti32x4    m17, [grain_lutq+topleft_offxyq+32], 2
+    ; do h interpolation first (so top | top/left -> top, left | cur -> cur)
+    punpcklbw       m16, m19
+    pmaddubsw       m16, m10, m16
+    punpcklbw       m17, m21
+    pmaddubsw       m17, m10, m17
+    punpckhbw       m20, m21, m19
+    pmulhrsw        m16, m9
+    pmulhrsw        m17, m9
+    packsswb    m19{k1}, m16, m16
+    packsswb    m21{k1}, m17, m17
+    ; followed by v interpolation (top | cur -> cur)
+    punpcklbw       m21, m19
+    call .add_noise_v
+    sub              hb, 2
+    jg .loop_y_h_overlap
+    add              wq, 32
+    lea            srcq, [src_bakq+wq]
+    jl .hv_overlap
+.end:
+    RET
+ALIGN function_align
+.add_noise_v:
+    pmaddubsw       m20, m12, m20
+    pmaddubsw       m21, m12, m21
+    pmulhrsw        m20, m9
+    pmulhrsw        m21, m9
+    packsswb        m21, m20
+.add_noise:
+    punpcklbw       m20, m5, m21
+    punpckhbw       m21, m5
+.add_noise_h:
+    mova           ym18, [srcq+strideq*0]
+    vinserti32x8    m18, [srcq+strideq*1], 1
+    mova            m19, m0
+    punpcklbw       m16, m18, m5
+    vpermt2b        m19, m18, m1 ; scaling[  0..127]
+    vpmovb2m         k2, m18
+    punpckhbw       m17, m18, m5
+    vpermi2b        m18, m2, m3  ; scaling[128..255]
+    vmovdqu8    m19{k2}, m18     ; scaling[src]
+    pshufb          m19, m4
+    pmaddubsw       m18, m19, m20
+    pmaddubsw       m19, m21
+    add      grain_lutq, 82*2
+    pmulhrsw        m18, m6      ; noise
+    pmulhrsw        m19, m6
+    paddw           m16, m18
+    paddw           m17, m19
+    packuswb        m16, m17
+    pmaxub          m16, m7
+    pminub          m16, m8
+    mova    [dstq+srcq], ym16
+    add            srcq, strideq
+    vextracti32x8 [dstq+srcq], m16, 1
+    add            srcq, strideq
+    ret
+
+%macro FGUV_FN 3 ; name, ss_hor, ss_ver
+cglobal fguv_32x32xn_i%1_8bpc, 6, 14+%2, 22, dst, src, stride, fg_data, w, \
+                                             scaling, grain_lut, h, sby, luma, \
+                                             overlap, uv_pl, is_id, _, stride3
+    lea             r11, [fg_min]
+    mov             r6d, [fg_dataq+FGData.scaling_shift]
+    mov             r7d, [fg_dataq+FGData.clip_to_restricted_range]
+    mov             r9d, is_idm
+    mov            sbyd, sbym
+    mov        overlapd, [fg_dataq+FGData.overlap_flag]
+%if %2
+    mov             r12, 0x000f000f000f000f ; h_overlap mask
+    vpbroadcastq    m10, [base+pb_23_22_0_32]
+    lea        stride3q, [strideq*3]
+%else
+    mov             r12, 0x0000000f0000000f
+    vpbroadcastq    m10, [base+pb_27_17_17_27]
+%endif
+    mova             m0, [scalingq+64*0]
+    mova             m1, [scalingq+64*1]
+    mova             m2, [scalingq+64*2]
+    mova             m3, [scalingq+64*3]
+    kmovq            k1, r12
+    vbroadcasti32x4  m4, [base+interleave_hl]
+    vpbroadcastd     m6, [base+noise_rnd+r6*4-32]
+    vpbroadcastd     m7, [base+fg_min+r7*4]
+    shlx            r7d, r7d, r9d
+    vpbroadcastd     m8, [base+fg_max+r7*4]
+    test           sbyd, sbyd
+    setnz           r7b
+    vpbroadcastd     m9, [base+pw_1024]
+    mova            m11, [base+pb_even]
+    mova            m12, [base+pb_odd]
+    pxor             m5, m5
+    mov              r5, r10mp      ; lstride
+    cmp byte [fg_dataq+FGData.chroma_scaling_from_luma], 0
+    jne .csfl
+
+%macro %%FGUV_32x32xN_LOOP 3 ; not-csfl, ss_hor, ss_ver
+    DEFINE_ARGS dst, src, stride, fg_data, w, lstride, grain_lut, \
+                h, sby, see, overlap, uv_pl, _, _, stride3
+%if %1
+    mov             r6d, uv_plm
+    vpbroadcastd    m16, [base+pw_8]
+    vbroadcasti32x4 m14, [fg_dataq+FGData.uv_mult+r6*4]
+    vpbroadcastw    m15, [fg_dataq+FGData.uv_offset+r6*4]
+    pshufb          m14, m16     ; uv_luma_mult, uv_mult
+%endif
+    test            r7b, overlapb
+    jnz %%v_overlap
+
+    imul           seed, sbyd, (173 << 24) | 37
+    add            seed, (105 << 24) | 178
+    rorx           seed, seed, 24
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+    DEFINE_ARGS dst, src, stride, luma, w, lstride, grain_lut, \
+                offx, offy, see, overlap, _, _, _, stride3
+
+    mov           lumaq, r9mp
+    lea             r11, [srcq+wq]
+    lea             r12, [dstq+wq]
+    lea             r13, [lumaq+wq*(1+%2)]
+    mov           r11mp, r11
+    mov           r12mp, r12
+    neg              wq
+
+%%loop_x:
+    rorx             r6, seeq, 1
+    or             seed, 0xeff4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d     ; updated seed
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyd, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, luma, w, lstride, grain_lut, \
+                h, offxy, see, overlap, _, _, _, stride3
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+%%loop_y:
+%if %2
+    movu           xm21, [grain_lutq+offxyq+82*0]
+    vinserti128    ym21, [grain_lutq+offxyq+82*1], 1
+    vinserti32x4    m21, [grain_lutq+offxyq+82*2], 2
+    vinserti32x4    m21, [grain_lutq+offxyq+82*3], 3
+%else
+    movu           ym21, [grain_lutq+offxyq+82*0]
+    vinserti32x8    m21, [grain_lutq+offxyq+82*1], 1
+%endif
+    call %%add_noise
+    sub              hb, 2<<%2
+    jg %%loop_y
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r11mp
+    mov            dstq, r12mp
+    lea           lumaq, [r13+wq*(1<<%2)]
+    add            srcq, wq
+    add            dstq, wq
+    test       overlapd, overlapd
+    jz %%loop_x
+    cmp       dword r8m, 0       ; sby
+    jne %%hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+%%loop_x_h_overlap:
+    rorx             r6, seeq, 1
+    or             seed, 0xeff4
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d     ; updated seed
+
+    DEFINE_ARGS dst, src, stride, luma, w, lstride, grain_lut, \
+                offx, offy, see, left_offxy, _, _, _, stride3
+
+    lea     left_offxyd, [offyq+(32>>%2)]         ; previous column's offy*stride+offx
+    rorx          offyd, seed, 8
+    rorx          offxq, seeq, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyd, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)] ; offy*stride+offx
+
+    DEFINE_ARGS dst, src, stride, luma, w, lstride, grain_lut, \
+                h, offxy, see, left_offxy, _, _, _, stride3
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+%%loop_y_h_overlap:
+%if %2
+    movu           xm20, [grain_lutq+offxyq     +82*0]
+    movd           xm19, [grain_lutq+left_offxyq+82*0]
+    vinserti32x4   ym20, [grain_lutq+offxyq     +82*1], 1
+    vinserti32x4   ym19, [grain_lutq+left_offxyq+82*1], 1
+    vinserti32x4    m20, [grain_lutq+offxyq     +82*2], 2
+    vinserti32x4    m19, [grain_lutq+left_offxyq+82*2], 2
+    vinserti32x4    m20, [grain_lutq+offxyq     +82*3], 3
+    vinserti32x4    m19, [grain_lutq+left_offxyq+82*3], 3
+%else
+    movu           ym20, [grain_lutq+offxyq     + 0]
+    movd           xm19, [grain_lutq+left_offxyq+ 0]
+    vinserti32x8    m20, [grain_lutq+offxyq     +82], 1
+    vinserti32x4    m19, [grain_lutq+left_offxyq+82], 2
+%endif
+    punpcklbw       m19, m20
+    pmaddubsw       m19, m10, m19
+    punpckhbw       m21, m20, m5
+    pmulhrsw        m19, m9
+    vpacksswb   m20{k1}, m19, m19
+    punpcklbw       m20, m5, m20
+    call %%add_noise_h
+    sub              hb, 2<<%2
+    jg %%loop_y_h_overlap
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r11mp
+    mov            dstq, r12mp
+    lea           lumaq, [r13+wq*(1<<%2)]
+    add            srcq, wq
+    add            dstq, wq
+    cmp       dword r8m, 0       ; sby
+    jne %%hv_overlap
+    jmp %%loop_x_h_overlap
+
+%%v_overlap:
+    DEFINE_ARGS dst, src, stride, fg_data, w, lstride, grain_lut, \
+                _, sby, see, overlap, _, _, _, stride3
+
+    movzx          sbyd, sbyb
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+    imul            r7d, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add             r7d, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and             r7d, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, r7d
+    xor            seed, sbyd    ; (cur_seed << 16) | top_seed
+
+%if %3
+    vpbroadcastd    m13, [base+pb_23_22]
+    kxnorw           k3, k3, k3  ; v_overlap mask
+%elif %2
+    vbroadcasti32x8 m13, [base+pb_27_17]
+    kxnord           k3, k3, k3
+    pshufd          m13, m13, q0000 ; 8x27_17, 8x17_27
+%else
+    vpbroadcastd   ym16, [base+pb_27_17]
+    vpbroadcastd    m13, [base+pb_17_27]
+    vmovdqa64   m13{k1}, m16
+%endif
+
+    DEFINE_ARGS dst, src, stride, luma, w, lstride, grain_lut, \
+                offx, offy, see, overlap, top_offxy, _, _, stride3
+
+    mov           lumaq, r9mp
+    lea             r11, [srcq+wq]
+    lea             r12, [dstq+wq]
+    lea             r13, [lumaq+wq*(1<<%2)]
+    mov           r11mp, r11
+    mov           r12mp, r12
+    neg              wq
+
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b          ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b          ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1  ; updated (cur_seed << 16) | top_seed
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0x000f000f
+    and           offxd, 0x000f000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+    DEFINE_ARGS dst, src, stride, luma, w, lstride, grain_lut, \
+                h, offxy, see, overlap, top_offxy, _, _, stride3
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+
+%if %3
+    movu           xm18, [grain_lutq+offxyq+82*0]
+    movu           xm20, [grain_lutq+top_offxyq+82*0]
+    ; only interpolate first line, insert remaining line unmodified
+    vbroadcasti128 ym21, [grain_lutq+offxyq+82*1]
+    vinserti32x4    m21, [grain_lutq+offxyq+82*2], 2
+    vinserti32x4    m21, [grain_lutq+offxyq+82*3], 3
+    punpcklbw      xm19, xm20, xm18
+    punpckhbw      xm20, xm18
+%elif %2
+    movu           xm18, [grain_lutq+offxyq+82*0]
+    vinserti128    ym18, [grain_lutq+offxyq+82*1], 1
+    movu           xm20, [grain_lutq+top_offxyq+82*0]
+    vinserti32x4   ym20, [grain_lutq+top_offxyq+82*1], 1
+    vbroadcasti32x4 m21, [grain_lutq+offxyq+82*2]
+    vinserti32x4    m21, [grain_lutq+offxyq+82*3], 3
+    punpcklbw      ym19, ym20, ym18
+    punpckhbw      ym20, ym18
+%else
+    movu           ym21, [grain_lutq+offxyq+82*0]
+    vinserti32x8    m21, [grain_lutq+offxyq+82*1], 1
+    movu           ym20, [grain_lutq+top_offxyq+82*0]
+    vinserti32x8    m20, [grain_lutq+top_offxyq+82*1], 1
+%endif
+    call %%add_noise_v
+    sub              hb, 2<<%2
+    jg %%loop_y
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r11mp
+    mov            dstq, r12mp
+    lea           lumaq, [r13+wq*(1<<%2)]
+    add            srcq, wq
+    add            dstq, wq
+
+%%hv_overlap:
+    ; we assume from the block above that bits 8-15 of r7d are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp            r7b          ; parity of top_seed
+    shr            seed, 16
+    shl             r7d, 16
+    test           seeb, seeh
+    setp            r7b          ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor             r7d, r6d
+    rorx           seed, r7d, 1  ; updated (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, luma, w, lstride, grain_lut, \
+                offx, offy, see, left_offxy, top_offxy, topleft_offxy, _, stride3
+
+    lea  topleft_offxyd, [top_offxyq+(32>>%2)]
+    lea     left_offxyd, [offyq+(32>>%2)]
+    rorx          offyd, seed, 8
+    rorx          offxd, seed, 12
+    and           offyd, 0x000f000f
+    and           offxd, 0x000f000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyd, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+    DEFINE_ARGS dst, src, stride, luma, w, lstride, grain_lut, \
+                h, offxy, see, left_offxy, top_offxy, topleft_offxy, _, stride3
+
+    mov      grain_lutq, grain_lutmp
+    mov              hd, hm
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+
+%if %2
+    movu           xm21, [grain_lutq+offxyq+82*0]
+    movd           xm16, [grain_lutq+left_offxyq+82*0]
+    vinserti128    ym21, [grain_lutq+offxyq+82*1], 1
+    vinserti128    ym16, [grain_lutq+left_offxyq+82*1], 1
+    vinserti32x4    m21, [grain_lutq+offxyq+82*2], 2
+    vinserti32x4    m16, [grain_lutq+left_offxyq+82*2], 2
+    vinserti32x4    m21, [grain_lutq+offxyq+82*3], 3
+    vinserti32x4    m16, [grain_lutq+left_offxyq+82*3], 3
+    movd           xm18, [grain_lutq+topleft_offxyq+82*0]
+    movu           xm20, [grain_lutq+top_offxyq]
+    ; do h interpolation first (so top | top/left -> top, left | cur -> cur)
+    punpcklbw       m16, m21
+%if %3
+    punpcklbw      xm18, xm20
+%else
+    vinserti128    ym18, [grain_lutq+topleft_offxyq+82*1], 1
+    vinserti128    ym20, [grain_lutq+top_offxyq+82*1], 1
+    punpcklbw      ym18, ym20
+%endif
+    punpcklqdq      m16, m18
+    pmaddubsw       m16, m10, m16
+    pmulhrsw        m16, m9
+    packsswb        m16, m16
+    vmovdqu8    m21{k1}, m16
+%if %3
+    vpalignr   xm20{k1}, xm16, xm16, 4
+    punpcklbw      xm19, xm20, xm21
+    punpckhbw      xm20, xm21
+%else
+    vpalignr   ym20{k1}, ym16, ym16, 4
+    punpcklbw      ym19, ym20, ym21
+    punpckhbw      ym20, ym21
+%endif
+%else
+    movu           ym21, [grain_lutq+offxyq+82*0]
+    vinserti32x8    m21, [grain_lutq+offxyq+82*1], 1
+    movd           xm16, [grain_lutq+left_offxyq+82*0]
+    vinserti32x4    m16, [grain_lutq+left_offxyq+82*1], 2
+    movu           ym20, [grain_lutq+top_offxyq+82*0]
+    vinserti32x8    m20, [grain_lutq+top_offxyq+82*1], 1
+    movd           xm18, [grain_lutq+topleft_offxyq+82*0]
+    vinserti32x4    m18, [grain_lutq+topleft_offxyq+82*1], 2
+    punpcklbw       m16, m21
+    punpcklbw       m18, m20
+    punpcklqdq      m16, m18
+    pmaddubsw       m16, m10, m16
+    pmulhrsw        m16, m9
+    packsswb        m16, m16
+    vpalignr    m20{k1}, m16, m16, 4
+    vmovdqu8    m21{k1}, m16
+%endif
+    call %%add_noise_v
+    sub              hb, 2<<%2
+    jg %%loop_y_h_overlap
+    add              wq, 32>>%2
+    jge .end
+    mov            srcq, r11mp
+    mov            dstq, r12mp
+    lea           lumaq, [r13+wq*(1<<%2)]
+    add            srcq, wq
+    add            dstq, wq
+    jmp %%hv_overlap
+ALIGN function_align
+%%add_noise_v:
+%if %3
+    pmaddubsw      xm19, xm13, xm19
+    pmaddubsw      xm20, xm13, xm20
+    pmulhrsw       xm19, xm9
+    pmulhrsw       xm20, xm9
+    vpacksswb   m21{k3}, m19, m20
+%elif %2
+    pmaddubsw      ym19, ym13, ym19
+    pmaddubsw      ym20, ym13, ym20
+    pmulhrsw       ym19, ym9
+    pmulhrsw       ym20, ym9
+    vpacksswb   m21{k3}, m19, m20
+%else
+    punpcklbw       m19, m20, m21
+    punpckhbw       m20, m21
+    pmaddubsw       m19, m13, m19
+    pmaddubsw       m20, m13, m20
+    pmulhrsw        m19, m9
+    pmulhrsw        m20, m9
+    packsswb        m21, m19, m20
+%endif
+%%add_noise:
+    punpcklbw       m20, m5, m21
+    punpckhbw       m21, m5
+%%add_noise_h:
+    mova           ym18, [lumaq+lstrideq*(0<<%3)]
+    vinserti32x8    m18, [lumaq+lstrideq*(1<<%3)], 1
+%if %2
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+    mova           ym16, [lumaq+lstrideq*(0<<%3)]
+    vinserti32x8    m16, [lumaq+lstrideq*(1<<%3)], 1
+    mova           xm17, [srcq+strideq*0]
+    mova            m19, m11
+    vpermi2b        m19, m18, m16
+    vinserti128    ym17, [srcq+strideq*1], 1
+    vpermt2b        m18, m12, m16
+    vinserti32x4    m17, [srcq+strideq*2], 2
+    pavgb           m18, m19
+    vinserti32x4    m17, [srcq+stride3q ], 3
+%else
+    mova           ym17, [srcq+strideq*0]
+    vinserti32x8    m17, [srcq+strideq*1], 1
+%endif
+%if %1
+    punpckhbw       m19, m18, m17
+    punpcklbw       m18, m17     ; { luma, chroma }
+    pmaddubsw       m19, m14
+    pmaddubsw       m18, m14
+    psraw           m19, 6
+    psraw           m18, 6
+    paddw           m19, m15
+    paddw           m18, m15
+    packuswb        m18, m19
+.add_noise_main:
+    mova            m19, m0
+    vpermt2b        m19, m18, m1 ; scaling[  0..127]
+    vpmovb2m         k2, m18
+    vpermi2b        m18, m2, m3  ; scaling[128..255]
+    vmovdqu8    m19{k2}, m18     ; scaling[src]
+    pshufb          m19, m4
+    pmaddubsw       m18, m19, m20
+    pmaddubsw       m19, m21
+    add      grain_lutq, 82*2<<%2
+    lea           lumaq, [lumaq+lstrideq*(2<<%3)]
+    lea            srcq, [srcq+strideq*(2<<%2)]
+    pmulhrsw        m18, m6      ; noise
+    pmulhrsw        m19, m6
+    punpcklbw       m16, m17, m5 ; chroma
+    punpckhbw       m17, m5
+    paddw           m16, m18
+    paddw           m17, m19
+    packuswb        m16, m17
+    pmaxub          m16, m7
+    pminub          m16, m8
+%if %2
+    mova          [dstq+strideq*0], xm16
+    vextracti128  [dstq+strideq*1], ym16, 1
+    vextracti32x4 [dstq+strideq*2], m16, 2
+    vextracti32x4 [dstq+stride3q ], m16, 3
+%else
+    mova          [dstq+strideq*0], ym16
+    vextracti32x8 [dstq+strideq*1], m16, 1
+%endif
+    lea            dstq, [dstq+strideq*(2<<%2)]
+    ret
+%else
+    jmp .add_noise_main
+%endif
+%endmacro
+
+    %%FGUV_32x32xN_LOOP 1, %2, %3
+.csfl:
+    %%FGUV_32x32xN_LOOP 0, %2, %3
+.end:
+    RET
+%endmacro
+
+FGUV_FN 420, 1, 1
+FGUV_FN 422, 1, 0
+FGUV_FN 444, 0, 0
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/filmgrain_common.asm b/media/libdav1d/src/src/x86/filmgrain_common.asm
new file mode 100644
index 0000000000..74f7044e66
--- /dev/null
+++ b/media/libdav1d/src/src/x86/filmgrain_common.asm
@@ -0,0 +1,46 @@
+; Copyright © 2019-2022, VideoLAN and dav1d authors
+; Copyright © 2019-2022, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+struc FGData
+    .seed:                      resd 1
+    .num_y_points:              resd 1
+    .y_points:                  resb 14 * 2
+    .chroma_scaling_from_luma:  resd 1
+    .num_uv_points:             resd 2
+    .uv_points:                 resb 2 * 10 * 2
+    .scaling_shift:             resd 1
+    .ar_coeff_lag:              resd 1
+    .ar_coeffs_y:               resb 24
+    .ar_coeffs_uv:              resb 2 * 28 ; includes padding
+    .ar_coeff_shift:            resq 1
+    .grain_scale_shift:         resd 1
+    .uv_mult:                   resd 2
+    .uv_luma_mult:              resd 2
+    .uv_offset:                 resd 2
+    .overlap_flag:              resd 1
+    .clip_to_restricted_range:  resd 1
+endstruc
+
+cextern gaussian_sequence
diff --git a/media/libdav1d/src/src/x86/filmgrain_sse.asm b/media/libdav1d/src/src/x86/filmgrain_sse.asm
new file mode 100644
index 0000000000..d06e349a8c
--- /dev/null
+++ b/media/libdav1d/src/src/x86/filmgrain_sse.asm
@@ -0,0 +1,3223 @@
+; Copyright © 2019-2021, VideoLAN and dav1d authors
+; Copyright © 2019, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+%include "x86/filmgrain_common.asm"
+
+SECTION_RODATA
+
+pw_1024: times 8 dw 1024
+pb_27_17_17_27: db 27, 17, 17, 27
+                times 6 db 0, 32
+pb_23_22_h: db 23, 22
+            times 7 db 0, 32
+pb_27_17: times 8 db 27, 17
+pb_17_27: times 8 db 17, 27
+pb_23_22: times 8 db 23, 22
+pb_mask: db 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0
+rnd_next_upperbit_mask: dw 0x100B, 0x2016, 0x402C, 0x8058
+byte_blend: db 0, 0, 0, 0xff, 0, 0, 0, 0
+pw_seed_xor: times 2 dw 0xb524
+             times 2 dw 0x49d8
+pb_1: times 4 db 1
+hmul_bits: dw 32768, 16384, 8192, 4096
+round: dw 2048, 1024, 512
+mul_bits: dw 256, 128, 64, 32, 16
+round_vals: dw 32, 64, 128, 256, 512
+max: dw 255, 240, 235
+min: dw 0, 16
+pw_1: dw 1
+
+%macro JMP_TABLE 2-*
+    %xdefine %1_8bpc_%2_table %%table
+    %xdefine %%base %1_8bpc_%2_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1_8bpc_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%prefix %+ .ar%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+JMP_TABLE generate_grain_y, ssse3, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_420, ssse3, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_422, ssse3, 0, 1, 2, 3
+JMP_TABLE generate_grain_uv_444, ssse3, 0, 1, 2, 3
+
+SECTION .text
+
+%if ARCH_X86_32
+%define PIC_ptr(a) base+a
+%else
+%define PIC_ptr(a) a
+%endif
+
+%macro SCRATCH 3
+%if ARCH_X86_32
+    mova [rsp+%3*mmsize], m%1
+%define m%2 [rsp+%3*mmsize]
+%else
+    SWAP             %1, %2
+%endif
+%endmacro
+
+INIT_XMM ssse3
+cglobal generate_grain_y_8bpc, 2, 7 + 2 * ARCH_X86_64, 16, buf, fg_data
+    LEA              r4, $$
+%define base r4-$$
+    movq             m1, [base+rnd_next_upperbit_mask]
+    movq             m4, [base+mul_bits]
+    movq             m7, [base+hmul_bits]
+    mov             r2d, [fg_dataq+FGData.grain_scale_shift]
+    movd             m2, [base+round+r2*2]
+    movd             m0, [fg_dataq+FGData.seed]
+    mova             m5, [base+pb_mask]
+    pshuflw          m2, m2, q0000
+    pshuflw          m0, m0, q0000
+    mov              r2, -73*82
+    sub            bufq, r2
+    lea              r3, [base+gaussian_sequence]
+.loop:
+    pand             m6, m0, m1
+    psrlw            m3, m6, 10
+    por              m6, m3            ; bits 0xf, 0x1e, 0x3c and 0x78 are set
+    pmullw           m6, m4            ; bits 0x0f00 are set
+    pshufb           m3, m5, m6        ; set 15th bit for next 4 seeds
+    psllq            m6, m3, 30
+    por              m3, m6
+    psllq            m6, m3, 15
+    por              m3, m6            ; aggregate each bit into next seed's high bit
+    pmulhuw          m6, m0, m7
+    por              m3, m6            ; 4 next output seeds
+    pshuflw          m0, m3, q3333
+    psrlw            m3, 5
+%if ARCH_X86_64
+    movq             r6, m3
+    mov              r8, r6
+    movzx           r5d, r6w
+    shr             r6d, 16
+    shr              r8, 32
+    movzx            r7, r8w
+    shr              r8, 16
+
+    movd             m6, [r3+r5*2]
+    pinsrw           m6, [r3+r6*2], 1
+    pinsrw           m6, [r3+r7*2], 2
+    pinsrw           m6, [r3+r8*2], 3
+%else
+    movd             r6, m3
+    pshuflw          m3, m3, q3232
+    movzx            r5, r6w
+    shr              r6, 16
+
+    movd             m6, [r3+r5*2]
+    pinsrw           m6, [r3+r6*2], 1
+
+    movd             r6, m3
+    movzx            r5, r6w
+    shr              r6, 16
+
+    pinsrw           m6, [r3+r5*2], 2
+    pinsrw           m6, [r3+r6*2], 3
+%endif
+    pmulhrsw         m6, m2
+    packsswb         m6, m6
+    movd      [bufq+r2], m6
+    add              r2, 4
+    jl .loop
+
+    ; auto-regression code
+    movsxd           r2, [fg_dataq+FGData.ar_coeff_lag]
+    movsxd           r2, [base+generate_grain_y_8bpc_ssse3_table+r2*4]
+    lea              r2, [r2+base+generate_grain_y_8bpc_ssse3_table]
+    jmp              r2
+
+.ar1:
+%if ARCH_X86_32
+    DEFINE_ARGS buf, fg_data, cf3, unused, val3, min, max
+%elif WIN64
+    DEFINE_ARGS shift, fg_data, cf3, buf, val3, min, max, x, val0
+    mov            bufq, r0
+%else
+    DEFINE_ARGS buf, fg_data, cf3, shift, val3, min, max, x, val0
+%endif
+    movsx          cf3d, byte [fg_dataq+FGData.ar_coeffs_y+3]
+    movd             m4, [fg_dataq+FGData.ar_coeffs_y]
+    mov             ecx, [fg_dataq+FGData.ar_coeff_shift]
+%if ARCH_X86_32
+    mov             r1m, cf3d
+    DEFINE_ARGS buf, shift, val3, min, max, x, val0
+%define hd r0mp
+%define cf3d r1mp
+%elif WIN64
+    DEFINE_ARGS shift, h, cf3, buf, val3, min, max, x, val0
+%else
+    DEFINE_ARGS buf, h, cf3, shift, val3, min, max, x, val0
+%endif
+    pxor             m6, m6
+    pcmpgtb          m7, m6, m4
+    punpcklbw        m4, m7
+    pinsrw           m4, [base+pw_1], 3
+    pshufd           m5, m4, q1111
+    pshufd           m4, m4, q0000
+    movd             m3, [base+round_vals+shiftq*2-12]    ; rnd
+    pshuflw          m3, m3, q0000
+    sub            bufq, 82*73-(82*3+79)
+    mov              hd, 70
+    mov            mind, -128
+    mov            maxd, 127
+.y_loop_ar1:
+    mov              xq, -76
+    movsx         val3d, byte [bufq+xq-1]
+.x_loop_ar1:
+    movq             m0, [bufq+xq-82-1]     ; top/left
+    pcmpgtb          m7, m6, m0
+    punpcklbw        m0, m7
+    psrldq           m2, m0, 2              ; top
+    psrldq           m1, m0, 4              ; top/right
+    punpcklwd        m0, m2
+    punpcklwd        m1, m3
+    pmaddwd          m0, m4
+    pmaddwd          m1, m5
+    paddd            m0, m1
+.x_loop_ar1_inner:
+    movd          val0d, m0
+    psrldq           m0, 4
+    imul          val3d, cf3d
+    add           val3d, val0d
+    sar           val3d, shiftb
+    movsx         val0d, byte [bufq+xq]
+    add           val3d, val0d
+    cmp           val3d, maxd
+    cmovns        val3d, maxd
+    cmp           val3d, mind
+    cmovs         val3d, mind
+    mov  byte [bufq+xq], val3b
+    ; keep val3d in-place as left for next x iteration
+    inc              xq
+    jz .x_loop_ar1_end
+    test             xq, 3
+    jnz .x_loop_ar1_inner
+    jmp .x_loop_ar1
+
+.x_loop_ar1_end:
+    add            bufq, 82
+    dec              hd
+    jg .y_loop_ar1
+.ar0:
+    RET
+
+.ar2:
+%if ARCH_X86_32
+    ALLOC_STACK -16*8
+%endif
+    DEFINE_ARGS buf, fg_data, shift
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movd             m6, [base+round_vals-12+shiftq*2]
+    movd             m7, [base+byte_blend+1]
+    SCRATCH           7, 15, 7
+    movq             m0, [fg_dataq+FGData.ar_coeffs_y+0]    ; cf0-7
+    movd             m1, [fg_dataq+FGData.ar_coeffs_y+8]    ; cf8-11
+    pxor             m7, m7
+    pshuflw          m6, m6, q0000
+    punpcklwd        m6, m7
+    pcmpgtb          m4, m7, m0
+    pcmpgtb          m5, m7, m1
+    punpcklbw        m0, m4
+    punpcklbw        m1, m5
+    DEFINE_ARGS buf, fg_data, h, x
+    pshufd           m4, m1, q0000
+    pshufd           m5, m1, q1111
+    pshufd           m3, m0, q3333
+    pshufd           m2, m0, q2222
+    pshufd           m1, m0, q1111
+    pshufd           m0, m0, q0000
+    SCRATCH           0, 8,  0
+    SCRATCH           1, 9,  1
+    SCRATCH           2, 10, 2
+    SCRATCH           3, 11, 3
+    SCRATCH           4, 12, 4
+    SCRATCH           5, 13, 5
+    SCRATCH           6, 14, 6
+    sub            bufq, 82*73-(82*3+79)
+    mov              hd, 70
+.y_loop_ar2:
+    mov              xq, -76
+
+.x_loop_ar2:
+    movq             m0, [bufq+xq-82*2-2]   ; y=-2,x=[-2,+5]
+    movhps           m0, [bufq+xq-82*1-2]   ; y=-1,x=[-2,+5]
+    pcmpgtb          m2, m7, m0
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2
+    psrldq           m5, m0, 2              ; y=-2,x=[-1,+5]
+    psrldq           m3, m1, 2              ; y=-1,x=[-1,+5]
+    psrldq           m4, m1, 4              ; y=-1,x=[+0,+5]
+    punpcklwd        m2, m0, m5
+    punpcklwd        m3, m4
+    pmaddwd          m2, m8
+    pmaddwd          m3, m11
+    paddd            m2, m3
+
+    psrldq           m4, m0, 4              ; y=-2,x=[+0,+5]
+    psrldq           m5, m0, 6              ; y=-2,x=[+1,+5]
+    psrldq           m6, m0, 8              ; y=-2,x=[+2,+5]
+    punpcklwd        m4, m5
+    punpcklwd        m6, m1
+    psrldq           m5, m1, 6              ; y=-1,x=[+1,+5]
+    psrldq           m1, m1, 8              ; y=-1,x=[+2,+5]
+    punpcklwd        m5, m1
+    pmaddwd          m4, m9
+    pmaddwd          m6, m10
+    pmaddwd          m5, m12
+    paddd            m4, m6
+    paddd            m2, m5
+    paddd            m2, m4
+    paddd            m2, m14
+
+    movq             m0, [bufq+xq-2]        ; y=0,x=[-2,+5]
+.x_loop_ar2_inner:
+    pcmpgtb          m4, m7, m0
+    punpcklbw        m1, m0, m4
+    pmaddwd          m3, m1, m13
+    paddd            m3, m2
+    psrldq           m1, 4                  ; y=0,x=0
+    psrldq           m2, 4                  ; shift top to next pixel
+    psrad            m3, [fg_dataq+FGData.ar_coeff_shift]
+    ; don't packssdw since we only care about one value
+    paddw            m3, m1
+    packsswb         m3, m3
+    pslldq           m3, 2
+    pand             m3, m15
+    pandn            m1, m15, m0
+    por              m0, m1, m3
+    psrldq           m0, 1
+    ; overwrite 2 pixels, but that's ok
+    movd      [bufq+xq-1], m0
+    inc              xq
+    jz .x_loop_ar2_end
+    test             xq, 3
+    jnz .x_loop_ar2_inner
+    jmp .x_loop_ar2
+
+.x_loop_ar2_end:
+    add            bufq, 82
+    dec              hd
+    jg .y_loop_ar2
+    RET
+
+.ar3:
+    DEFINE_ARGS buf, fg_data, shift
+%if ARCH_X86_32
+    ALLOC_STACK  -16*14
+%elif WIN64
+    SUB             rsp, 16*6
+%assign stack_size_padded (stack_size_padded+16*6)
+%assign stack_size (stack_size+16*6)
+%else
+    ALLOC_STACK  -16*6
+%endif
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movd             m6, [base+round_vals-12+shiftq*2]
+    movd             m7, [base+byte_blend]
+    movu             m0, [fg_dataq+FGData.ar_coeffs_y+ 0]   ; cf0-15
+    movq             m2, [fg_dataq+FGData.ar_coeffs_y+16]   ; cf16-23
+    pxor             m3, m3
+    pcmpgtb          m4, m3, m0
+    pcmpgtb          m3, m2
+    pshuflw          m6, m6, q0000
+    SCRATCH           6, 14, 12
+    SCRATCH           7, 15, 13
+    punpckhbw        m1, m0, m4
+    punpcklbw        m0, m4
+    punpcklbw        m2, m3
+    pshufd           m3, m0, q1111
+    pshufd           m4, m0, q2222
+    pshufd           m5, m0, q3333
+    pshufd           m0, m0, q0000
+    mova    [rsp+ 0*16], m0
+    mova    [rsp+ 1*16], m3
+    mova    [rsp+ 2*16], m4
+    mova    [rsp+ 3*16], m5
+    pshufd           m6, m1, q1111
+    pshufd           m7, m1, q2222
+    pshufd           m5, m1, q3333
+    pshufd           m1, m1, q0000
+    pshufd           m3, m2, q1111
+    psrldq           m0, m2, 10
+    pinsrw           m2, [base+pw_1], 5
+    pshufd           m4, m2, q2222
+    pshufd           m2, m2, q0000
+    pinsrw           m0, [base+round_vals+shiftq*2-10], 3
+    mova    [rsp+ 4*16], m1
+    mova    [rsp+ 5*16], m6
+    SCRATCH           7, 8,  6
+    SCRATCH           5, 9,  7
+    SCRATCH           2, 10, 8
+    SCRATCH           3, 11, 9
+    SCRATCH           4, 12, 10
+    SCRATCH           0, 13, 11
+    DEFINE_ARGS buf, fg_data, h, x
+    sub            bufq, 82*73-(82*3+79)
+    mov              hd, 70
+.y_loop_ar3:
+    mov              xq, -76
+
+.x_loop_ar3:
+    movu             m0, [bufq+xq-82*3-3]   ; y=-3,x=[-3,+12]
+    pxor             m3, m3
+    pcmpgtb          m3, m0
+    punpckhbw        m2, m0, m3
+    punpcklbw        m0, m3
+
+    psrldq           m5, m0, 2
+    psrldq           m6, m0, 4
+    psrldq           m7, m0, 6
+    punpcklwd        m4, m0, m5
+    punpcklwd        m6, m7
+    pmaddwd          m4, [rsp+ 0*16]
+    pmaddwd          m6, [rsp+ 1*16]
+    paddd            m4, m6
+
+    movu             m1, [bufq+xq-82*2-3]   ; y=-2,x=[-3,+12]
+    pxor             m5, m5
+    pcmpgtb          m5, m1
+    punpckhbw        m3, m1, m5
+    punpcklbw        m1, m5
+    palignr          m6, m2, m0, 10
+    palignr          m7, m2, m0, 12
+    psrldq           m0, 8
+    punpcklwd        m0, m6
+    punpcklwd        m7, m1
+    pmaddwd          m0, [rsp+ 2*16]
+    pmaddwd          m7, [rsp+ 3*16]
+    paddd            m0, m7
+    paddd            m0, m4
+
+    psrldq           m4, m1, 2
+    psrldq           m5, m1, 4
+    psrldq           m6, m1, 6
+    psrldq           m7, m1, 8
+    punpcklwd        m4, m5
+    punpcklwd        m6, m7
+    pmaddwd          m4, [rsp+ 4*16]
+    pmaddwd          m6, [rsp+ 5*16]
+    paddd            m4, m6
+    paddd            m0, m4
+
+    movu             m2, [bufq+xq-82*1-3]   ; y=-1,x=[-3,+12]
+    pxor             m7, m7
+    pcmpgtb          m7, m2
+    punpckhbw        m5, m2, m7
+    punpcklbw        m2, m7
+    palignr          m7, m3, m1, 10
+    palignr          m3, m1, 12
+    psrldq           m1, m2, 2
+    punpcklwd        m7, m3
+    punpcklwd        m3, m2, m1
+    pmaddwd          m7, m8
+    pmaddwd          m3, m9
+    paddd            m7, m3
+    paddd            m0, m7
+
+    psrldq           m6, m2, 4
+    psrldq           m1, m2, 6
+    psrldq           m3, m2, 8
+    palignr          m4, m5, m2, 10
+    palignr          m5, m5, m2, 12
+
+    punpcklwd        m6, m1
+    punpcklwd        m3, m4
+    punpcklwd        m5, m14
+    pmaddwd          m6, m10
+    pmaddwd          m3, m11
+    pmaddwd          m5, m12
+    paddd            m0, m6
+    paddd            m3, m5
+    paddd            m0, m3
+
+    movq             m1, [bufq+xq-3]        ; y=0,x=[-3,+4]
+.x_loop_ar3_inner:
+    pxor             m5, m5
+    pcmpgtb          m5, m1
+    punpcklbw        m2, m1, m5
+    pmaddwd          m2, m13
+    pshufd           m3, m2, q1111
+    paddd            m2, m3                 ; left+cur
+    paddd            m2, m0                 ; add top
+    psrldq           m0, 4
+    psrad            m2, [fg_dataq+FGData.ar_coeff_shift]
+    ; don't packssdw since we only care about one value
+    packsswb         m2, m2
+    pslldq           m2, 3
+    pand             m2, m15
+    pandn            m3, m15, m1
+    por              m1, m2, m3
+    movd    [bufq+xq-3], m1
+    psrldq           m1, 1
+    inc              xq
+    jz .x_loop_ar3_end
+    test             xq, 3
+    jnz .x_loop_ar3_inner
+    jmp .x_loop_ar3
+
+.x_loop_ar3_end:
+    add            bufq, 82
+    dec              hd
+    jg .y_loop_ar3
+    RET
+
+%macro generate_grain_uv_fn 3 ; ss_name, ss_x, ss_y
+INIT_XMM ssse3
+cglobal generate_grain_uv_%1_8bpc, 1, 7 + 3 * ARCH_X86_64, 16, buf, bufy, fg_data, uv
+    movifnidn        r2, r2mp
+    movifnidn        r3, r3mp
+    LEA              r4, $$
+%define base r4-$$
+    movq             m1, [base+rnd_next_upperbit_mask]
+    movq             m4, [base+mul_bits]
+    movq             m7, [base+hmul_bits]
+    mov             r5d, [fg_dataq+FGData.grain_scale_shift]
+    movd             m6, [base+round+r5*2]
+    mova             m5, [base+pb_mask]
+    movd             m0, [fg_dataq+FGData.seed]
+    movd             m2, [base+pw_seed_xor+uvq*4]
+    pxor             m0, m2
+    pshuflw          m6, m6, q0000
+    pshuflw          m0, m0, q0000
+    lea              r6, [base+gaussian_sequence]
+%if %2
+%if ARCH_X86_64
+    mov             r7d, 73-35*%3
+%else
+    mov            r3mp, 73-35*%3
+%endif
+    add            bufq, 44
+.loop_y:
+    mov              r5, -44
+.loop_x:
+%else
+    mov              r5, -82*73
+    sub            bufq, r5
+.loop:
+%endif
+    pand             m2, m0, m1
+    psrlw            m3, m2, 10
+    por              m2, m3             ; bits 0xf, 0x1e, 0x3c and 0x78 are set
+    pmullw           m2, m4             ; bits 0x0f00 are set
+    pshufb           m3, m5, m2         ; set 15th bit for next 4 seeds
+    psllq            m2, m3, 30
+    por              m3, m2
+    psllq            m2, m3, 15
+    por              m3, m2             ; aggregate each bit into next seed's high bit
+    pmulhuw          m2, m0, m7
+    por              m2, m3             ; 4 next output seeds
+    pshuflw          m0, m2, q3333
+    psrlw            m2, 5
+%if ARCH_X86_64
+    movd            r9d, m2
+    pshuflw          m2, m2, q3232
+    movzx            r8, r9w
+    shr              r9, 16
+
+    movd             m3, [r6+r8*2]
+    pinsrw           m3, [r6+r9*2], 1
+
+    movd            r9d, m2
+    movzx            r8, r9w
+    shr              r9, 16
+
+    pinsrw           m3, [r6+r8*2], 2
+    pinsrw           m3, [r6+r9*2], 3
+%else
+    movd             r2, m2
+    pshuflw          m2, m2, q3232
+    movzx            r1, r2w
+    shr              r2, 16
+
+    movd             m3, [r6+r1*2]
+    pinsrw           m3, [r6+r2*2], 1
+
+    movd             r2, m2
+    movzx            r1, r2w
+    shr              r2, 16
+
+    pinsrw           m3, [r6+r1*2], 2
+    pinsrw           m3, [r6+r2*2], 3
+%endif
+    pmulhrsw         m3, m6
+    packsswb         m3, m3
+    movd      [bufq+r5], m3
+    add              r5, 4
+%if %2
+    jl .loop_x
+    add            bufq, 82
+%if ARCH_X86_64
+    dec             r7d
+%else
+    dec            r3mp
+%endif
+    jg .loop_y
+%else
+    jl .loop
+%endif
+
+%if ARCH_X86_32
+    mov              r2, r2mp
+%endif
+
+    ; auto-regression code
+    movsxd           r5, [fg_dataq+FGData.ar_coeff_lag]
+    movsxd           r5, [base+generate_grain_uv_%1_8bpc_ssse3_table+r5*4]
+    lea              r5, [r5+base+generate_grain_uv_%1_8bpc_ssse3_table]
+    jmp              r5
+
+.ar0:
+    DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift
+    movifnidn     bufyq, bufymp
+%if ARCH_X86_32
+    ALLOC_STACK   -2*16
+%endif
+    imul            uvd, 28
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movd             m5, [fg_dataq+FGData.ar_coeffs_uv+uvq]
+    movd             m4, [base+hmul_bits+shiftq*2]
+    DEFINE_ARGS buf, bufy, h, x
+    pxor             m0, m0
+    pcmpgtb          m0, m5
+    punpcklbw        m5, m0
+    movd             m7, [base+pb_1]
+%if %2
+    movd             m6, [base+hmul_bits+2+%3*2]
+%endif
+    pshuflw          m5, m5, q0000
+    pshuflw          m4, m4, q0000
+    pshufd           m7, m7, q0000
+%if %2
+    pshuflw          m6, m6, q0000
+%endif
+    punpcklqdq       m5, m5
+    punpcklqdq       m4, m4
+%if %2
+    punpcklqdq       m6, m6
+%endif
+    pcmpeqw          m1, m1
+    pslldq           m1, 12>>%2
+    SCRATCH           1, 8, 0
+    SCRATCH           4, 9, 1
+%if %2
+    sub            bufq, 82*(73-35*%3)+82-(82*3+41)
+%else
+    sub            bufq, 82*70-3
+%endif
+    add           bufyq, 3+82*3
+    mov              hd, 70-35*%3
+.y_loop_ar0:
+    xor              xd, xd
+.x_loop_ar0:
+    ; first 32 pixels
+%if %2
+    movu             m1, [bufyq+xq*2]
+%if %3
+    movu             m2, [bufyq+xq*2+82]
+%endif
+    movu             m3, [bufyq+xq*2+16]
+%if %3
+    movu             m4, [bufyq+xq*2+82+16]
+%endif
+    pmaddubsw        m0, m7, m1
+%if %3
+    pmaddubsw        m1, m7, m2
+%endif
+    pmaddubsw        m2, m7, m3
+%if %3
+    pmaddubsw        m3, m7, m4
+    paddw            m0, m1
+    paddw            m2, m3
+%endif
+    pmulhrsw         m0, m6
+    pmulhrsw         m2, m6
+%else
+    movu             m0, [bufyq+xq]
+    pxor             m6, m6
+    pcmpgtb          m6, m0
+    punpckhbw        m2, m0, m6
+    punpcklbw        m0, m6
+%endif
+    pmullw           m0, m5
+    pmullw           m2, m5
+    pmulhrsw         m0, m9
+    pmulhrsw         m2, m9
+    movu             m1, [bufq+xq]
+    pxor             m4, m4
+    pcmpgtb          m4, m1
+    punpckhbw        m3, m1, m4
+%if %2
+    punpcklbw        m1, m4
+    paddw            m2, m3
+    paddw            m0, m1
+%else
+    punpcklbw        m6, m1, m4
+    paddw            m2, m3
+    paddw            m0, m6
+%endif
+    packsswb         m0, m2
+%if %2
+    movu      [bufq+xq], m0
+    add              xd, 16
+    cmp              xd, 32
+    jl .x_loop_ar0
+
+    ; last 6/12 pixels
+    movu             m1, [bufyq+xq*(1+%2)]
+%if %3
+    movu             m2, [bufyq+xq*2+82]
+%endif
+    pmaddubsw        m0, m7, m1
+%if %3
+    pmaddubsw        m1, m7, m2
+    paddw            m0, m1
+%endif
+    pmulhrsw         m0, m6
+    pmullw           m0, m5
+    pmulhrsw         m0, m9
+    movq             m1, [bufq+xq]
+    pxor             m4, m4
+    pcmpgtb          m4, m1
+    punpcklbw        m2, m1, m4
+    paddw            m0, m2
+    packsswb         m0, m0
+    pandn            m2, m8, m0
+    pand             m1, m8
+    por              m2, m1
+    movq      [bufq+xq], m2
+%else
+    add              xd, 16
+    cmp              xd, 80
+    je .y_loop_final_ar0
+    movu   [bufq+xq-16], m0
+    jmp .x_loop_ar0
+.y_loop_final_ar0:
+    pandn            m2, m8, m0
+    pand             m1, m8
+    por              m2, m1
+    movu   [bufq+xq-16], m2
+%endif
+
+    add            bufq, 82
+    add           bufyq, 82<<%3
+    dec              hd
+    jg .y_loop_ar0
+    RET
+
+.ar1:
+%if ARCH_X86_32
+    RESET_STACK_STATE
+%endif
+    DEFINE_ARGS buf, bufy, fg_data, uv, val3, cf3, min, max, x
+    imul            uvd, 28
+    movsx          cf3d, byte [fg_dataq+FGData.ar_coeffs_uv+uvq+3]
+    movd             m4, [fg_dataq+FGData.ar_coeffs_uv+uvq-1]
+    pinsrw           m4, [fg_dataq+FGData.ar_coeffs_uv+uvq+4], 2
+%if ARCH_X86_32
+    mov            r3mp, cf3d
+    DEFINE_ARGS buf, shift, fg_data, val3, min, max, x
+%elif WIN64
+    DEFINE_ARGS shift, bufy, fg_data, buf, val3, cf3, min, max, x
+    mov            bufq, r0
+%else
+    DEFINE_ARGS buf, bufy, fg_data, shift, val3, cf3, min, max, x
+%endif
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    movd             m3, [base+round_vals+shiftq*2-12]    ; rnd
+%if %2
+    movd             m7, [base+pb_1]
+    movd             m6, [base+hmul_bits+2+%3*2]
+%endif
+    psrldq           m4, 1
+%if ARCH_X86_32
+    DEFINE_ARGS buf, shift, val0, val3, min, max, x
+%elif WIN64
+    DEFINE_ARGS shift, bufy, h, buf, val3, cf3, min, max, x, val0
+%else
+    DEFINE_ARGS buf, bufy, h, shift, val3, cf3, min, max, x, val0
+%endif
+    pxor             m5, m5
+    punpcklwd        m3, m5
+%if %2
+    punpcklwd        m6, m6
+%endif
+    pcmpgtb          m5, m4
+    punpcklbw        m4, m5
+    pshufd           m5, m4, q1111
+    pshufd           m4, m4, q0000
+    pshufd           m3, m3, q0000
+%if %2
+    pshufd           m7, m7, q0000
+    pshufd           m6, m6, q0000
+    sub            bufq, 82*(73-35*%3)+44-(82*3+41)
+%else
+    sub            bufq, 82*69+3
+%endif
+%if ARCH_X86_32
+    add            r1mp, 79+82*3
+    mov            r0mp, 70-35*%3
+%else
+    add           bufyq, 79+82*3
+    mov              hd, 70-35*%3
+%endif
+    mov            mind, -128
+    mov            maxd, 127
+.y_loop_ar1:
+    mov              xq, -(76>>%2)
+    movsx         val3d, byte [bufq+xq-1]
+.x_loop_ar1:
+%if %2
+%if ARCH_X86_32
+    mov              r2, r1mp
+    movq             m0, [r2+xq*2]
+%if %3
+    movq             m1, [r2+xq*2+82]
+%endif
+%else
+    movq             m0, [bufyq+xq*2]
+%if %3
+    movq             m1, [bufyq+xq*2+82]
+%endif
+%endif
+    pmaddubsw        m2, m7, m0
+%if %3
+    pmaddubsw        m0, m7, m1
+    paddw            m2, m0
+%endif
+    pmulhrsw         m2, m6
+%else
+%if ARCH_X86_32
+    mov              r2, r1mp
+    movd             m2, [r2+xq]
+%else
+    movd             m2, [bufyq+xq]
+%endif
+    pxor             m0, m0
+    pcmpgtb          m0, m2
+    punpcklbw        m2, m0
+%endif
+
+    movq             m0, [bufq+xq-82-1]     ; top/left
+    pxor             m1, m1
+    pcmpgtb          m1, m0
+    punpcklbw        m0, m1
+    psrldq           m1, m0, 4              ; top/right
+    punpcklwd        m1, m2
+    psrldq           m2, m0, 2              ; top
+    punpcklwd        m0, m2
+    pmaddwd          m0, m4
+    pmaddwd          m1, m5
+    paddd            m0, m1
+    paddd            m0, m3
+.x_loop_ar1_inner:
+    movd          val0d, m0
+    psrldq           m0, 4
+%if ARCH_X86_32
+    imul          val3d, r3mp
+%else
+    imul          val3d, cf3d
+%endif
+    add           val3d, val0d
+    sar           val3d, shiftb
+    movsx         val0d, byte [bufq+xq]
+    add           val3d, val0d
+    cmp           val3d, maxd
+    cmovns        val3d, maxd
+    cmp           val3d, mind
+    cmovs         val3d, mind
+    mov  byte [bufq+xq], val3b
+    ; keep val3d in-place as left for next x iteration
+    inc              xq
+    jz .x_loop_ar1_end
+    test             xq, 3
+    jnz .x_loop_ar1_inner
+    jmp .x_loop_ar1
+
+.x_loop_ar1_end:
+    add            bufq, 82
+%if ARCH_X86_32
+    add            r1mp, 82<<%3
+    dec            r0mp
+%else
+    add           bufyq, 82<<%3
+    dec              hd
+%endif
+    jg .y_loop_ar1
+    RET
+
+.ar2:
+%if ARCH_X86_32
+    ALLOC_STACK   -8*16
+%endif
+    DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift
+    movifnidn     bufyq, bufymp
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    imul            uvd, 28
+    movd             m7, [base+round_vals-12+shiftq*2]
+    movu             m0, [fg_dataq+FGData.ar_coeffs_uv+uvq+0]   ; cf0-12
+    pxor             m2, m2
+    pcmpgtb          m2, m0
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2
+    pinsrw           m1, [base+pw_1], 5
+    punpcklwd        m7, m7
+    pshufd           m7, m7, q0000
+    DEFINE_ARGS buf, bufy, fg_data, h, unused, x
+    pshufd           m4, m1, q0000
+    pshufd           m5, m1, q1111
+    pshufd           m6, m1, q2222
+    pshufd           m3, m0, q3333
+    pshufd           m2, m0, q2222
+    pshufd           m1, m0, q1111
+    pshufd           m0, m0, q0000
+    SCRATCH           0, 8,  0
+    SCRATCH           1, 9,  1
+    SCRATCH           2, 10, 2
+    SCRATCH           3, 11, 3
+    SCRATCH           4, 12, 4
+    SCRATCH           5, 13, 5
+    SCRATCH           6, 14, 6
+    SCRATCH           7, 15, 7
+%if %2
+    movd             m7, [base+hmul_bits+2+%3*2]
+    movd             m6, [base+pb_1]
+    punpcklwd        m7, m7
+    pshufd           m6, m6, q0000
+    pshufd           m7, m7, q0000
+    sub            bufq, 82*(73-35*%3)+44-(82*3+41)
+%else
+    sub            bufq, 82*69+3
+%endif
+    add           bufyq, 79+82*3
+    mov              hd, 70-35*%3
+.y_loop_ar2:
+    mov              xq, -(76>>%2)
+
+.x_loop_ar2:
+    pxor             m2, m2
+    movq             m0, [bufq+xq-82*2-2]   ; y=-2,x=[-2,+5]
+    movhps           m0, [bufq+xq-82*1-2]   ; y=-1,x=[-2,+5]
+    pcmpgtb          m2, m0
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2
+    psrldq           m5, m0, 2              ; y=-2,x=[-1,+5]
+    psrldq           m3, m1, 2              ; y=-1,x=[-1,+5]
+    psrldq           m4, m1, 4              ; y=-1,x=[+0,+5]
+    punpcklwd        m2, m0, m5
+    punpcklwd        m3, m4
+    pmaddwd          m2, m8
+    pmaddwd          m3, m11
+    paddd            m2, m3
+
+    psrldq           m4, m0, 4              ; y=-2,x=[+0,+5]
+    psrldq           m5, m0, 6              ; y=-2,x=[+1,+5]
+    psrldq           m0, 8                  ; y=-2,x=[+2,+5]
+    punpcklwd        m4, m5
+    punpcklwd        m0, m1
+    psrldq           m3, m1, 6              ; y=-1,x=[+1,+5]
+    psrldq           m1, m1, 8              ; y=-1,x=[+2,+5]
+    punpcklwd        m3, m1
+    pmaddwd          m4, m9
+    pmaddwd          m0, m10
+    pmaddwd          m3, m12
+    paddd            m4, m0
+    paddd            m2, m3
+    paddd            m2, m4
+
+%if %2
+    movq             m1, [bufyq+xq*2]
+%if %3
+    movq             m3, [bufyq+xq*2+82]
+%endif
+    pmaddubsw        m0, m6, m1
+%if %3
+    pmaddubsw        m1, m6, m3
+    paddw            m0, m1
+%endif
+    pmulhrsw         m0, m7
+%else
+    movd             m0, [bufyq+xq]
+    pxor             m1, m1
+    pcmpgtb          m1, m0
+    punpcklbw        m0, m1
+%endif
+    punpcklwd        m0, m15
+    pmaddwd          m0, m14
+    paddd            m2, m0
+
+    movq             m0, [bufq+xq-2]        ; y=0,x=[-2,+5]
+    pxor             m4, m4
+    movd             m5, [base+byte_blend+1]
+    punpcklbw        m5, m5
+.x_loop_ar2_inner:
+    pcmpgtb          m1, m4, m0
+    punpcklbw        m0, m1
+    pmaddwd          m3, m0, m13
+    paddd            m3, m2
+    psrldq           m2, 4                  ; shift top to next pixel
+    psrad            m3, [fg_dataq+FGData.ar_coeff_shift]
+    pslldq           m3, 4
+    pand             m3, m5
+    paddw            m0, m3
+    packsswb         m0, m0
+    movd    [bufq+xq-2], m0
+    psrldq           m0, 1
+    inc              xq
+    jz .x_loop_ar2_end
+    test             xq, 3
+    jnz .x_loop_ar2_inner
+    jmp .x_loop_ar2
+
+.x_loop_ar2_end:
+    add            bufq, 82
+    add           bufyq, 82<<%3
+    dec              hd
+    jg .y_loop_ar2
+    RET
+
+.ar3:
+%if ARCH_X86_32
+    RESET_STACK_STATE
+%endif
+    DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift
+    movifnidn     bufyq, bufymp
+%if ARCH_X86_32
+    ALLOC_STACK  -15*16
+%else
+    SUB             rsp, 16*7
+%assign stack_size_padded (stack_size_padded+16*7)
+%assign stack_size (stack_size+16*7)
+%endif
+    mov          shiftd, [fg_dataq+FGData.ar_coeff_shift]
+    imul            uvd, 28
+
+    movu             m0, [fg_dataq+FGData.ar_coeffs_uv+uvq+ 0]   ; cf0-15
+    pxor             m3, m3
+    pcmpgtb          m3, m0
+    punpckhbw        m1, m0, m3
+    punpcklbw        m0, m3
+    pshufd           m2, m0, q1111
+    pshufd           m3, m0, q2222
+    pshufd           m4, m0, q3333
+    pshufd           m0, m0, q0000
+    pshufd           m5, m1, q1111
+    pshufd           m6, m1, q2222
+    pshufd           m7, m1, q3333
+    pshufd           m1, m1, q0000
+    mova    [rsp+ 0*16], m0
+    mova    [rsp+ 1*16], m2
+    mova    [rsp+ 2*16], m3
+    mova    [rsp+ 3*16], m4
+    mova    [rsp+ 4*16], m1
+    mova    [rsp+ 5*16], m5
+    mova    [rsp+ 6*16], m6
+    SCRATCH           7, 8, 7
+
+    movu             m2, [fg_dataq+FGData.ar_coeffs_uv+uvq+16]   ; cf16-24 [24=luma]
+    pxor             m4, m4
+    pcmpgtb          m4, m2
+    punpckhbw        m5, m2, m4
+    punpcklbw        m2, m4
+    pshufd           m4, m2, q3232
+    punpcklwd        m3, m4, m5
+    pshuflw          m5, m4, q3321
+    pshufd           m4, m3, q0000
+    pshufd           m3, m2, q1111
+    pshufd           m2, m2, q0000
+    pinsrw           m5, [base+round_vals+shiftq*2-10], 3
+    SCRATCH           2, 9,  8
+    SCRATCH           3, 10, 9
+    SCRATCH           4, 11, 10
+    SCRATCH           5, 12, 11
+
+    movd             m2, [base+round_vals-12+shiftq*2]
+%if %2
+    movd             m1, [base+pb_1]
+    movd             m3, [base+hmul_bits+2+%3*2]
+%endif
+    pxor             m0, m0
+    punpcklwd        m2, m0
+%if %2
+    punpcklwd        m3, m3
+%endif
+    pshufd           m2, m2, q0000
+%if %2
+    pshufd           m1, m1, q0000
+    pshufd           m3, m3, q0000
+    SCRATCH           1, 13, 12
+%endif
+    SCRATCH           2, 14, 13
+%if %2
+    SCRATCH           3, 15, 14
+%endif
+
+    DEFINE_ARGS buf, bufy, fg_data, h, unused, x
+%if %2
+    sub            bufq, 82*(73-35*%3)+44-(82*3+41)
+%else
+    sub            bufq, 82*69+3
+%endif
+    add           bufyq, 79+82*3
+    mov              hd, 70-35*%3
+.y_loop_ar3:
+    mov              xq, -(76>>%2)
+
+.x_loop_ar3:
+    movu             m0, [bufq+xq-82*3-3]   ; y=-3,x=[-3,+12]
+    pxor             m4, m4
+    pcmpgtb          m4, m0
+    punpckhbw        m3, m0, m4
+    punpcklbw        m0, m4
+
+    psrldq           m5, m0, 2
+    psrldq           m6, m0, 4
+    psrldq           m7, m0, 6
+    punpcklwd        m4, m0, m5
+    punpcklwd        m6, m7
+    pmaddwd          m4, [rsp+ 0*16]
+    pmaddwd          m6, [rsp+ 1*16]
+    paddd            m4, m6
+
+    palignr          m2, m3, m0, 10
+    palignr          m3, m0, 12
+    psrldq           m0, 8
+
+    movu             m1, [bufq+xq-82*2-3]   ; y=-2,x=[-3,+12]
+    pxor             m6, m6
+    pcmpgtb          m6, m1
+    punpckhbw        m5, m1, m6
+    punpcklbw        m1, m6
+
+    punpcklwd        m0, m2
+    punpcklwd        m3, m1
+    pmaddwd          m0, [rsp+ 2*16]
+    pmaddwd          m3, [rsp+ 3*16]
+    paddd            m0, m3
+    paddd            m0, m4
+
+    movu             m2, [bufq+xq-82*1-3]   ; y=-1,x=[-3,+12]
+    pxor             m7, m7
+    pcmpgtb          m7, m2
+    punpckhbw        m6, m2, m7
+    punpcklbw        m2, m7
+
+    palignr          m3, m5, m1, 10
+    palignr          m5, m1, 12
+    psrldq           m4, m2, 2
+
+    punpcklwd        m3, m5
+    punpcklwd        m5, m2, m4
+    pmaddwd          m3, [rsp+ 6*16]
+    pmaddwd          m5, m8
+    paddd            m3, m5
+    paddd            m0, m3
+
+    psrldq           m3, m1, 2
+    psrldq           m4, m1, 4
+    psrldq           m5, m1, 6
+    psrldq           m1, 8
+
+    punpcklwd        m3, m4
+    punpcklwd        m5, m1
+    pmaddwd          m3, [rsp+ 4*16]
+    pmaddwd          m5, [rsp+ 5*16]
+    paddd            m3, m5
+    paddd            m0, m3
+
+%if %2
+    movq             m1, [bufyq+xq*2]
+%if %3
+    movq             m3, [bufyq+xq*2+82]
+%endif
+    pmaddubsw        m7, m13, m1
+%if %3
+    pmaddubsw        m5, m13, m3
+    paddw            m7, m5
+%endif
+    pmulhrsw         m7, m15
+%else
+    movd             m7, [bufyq+xq]
+    pxor             m1, m1
+    pcmpgtb          m1, m7
+    punpcklbw        m7, m1
+%endif
+
+    psrldq           m1, m2, 4
+    psrldq           m3, m2, 6
+    palignr          m4, m6, m2, 10
+    palignr          m6, m2, 12
+    psrldq           m2, 8
+
+    punpcklwd        m1, m3
+    punpcklwd        m2, m4
+    punpcklwd        m6, m7
+    pmaddwd          m1, m9
+    pmaddwd          m2, m10
+    pmaddwd          m6, m11
+    paddd            m1, m2
+    paddd            m0, m6
+    paddd            m0, m1
+    paddd            m0, m14
+
+    movq             m1, [bufq+xq-3]        ; y=0,x=[-3,+4]
+    pxor             m4, m4
+    movd             m5, [base+byte_blend]
+.x_loop_ar3_inner:
+    pcmpgtb          m2, m4, m1
+    punpcklbw        m3, m1, m2
+    pmaddwd          m2, m3, m12
+    pshufd           m3, m2, q1111
+    paddd            m2, m3                 ; left+cur
+    paddd            m2, m0                 ; add top
+    psrldq           m0, 4
+    psrad            m2, [fg_dataq+FGData.ar_coeff_shift]
+    ; don't packssdw, we only care about one value
+    packsswb         m2, m2
+    pandn            m3, m5, m1
+    pslld            m2, 24
+    pand             m2, m5
+    por              m1, m2, m3
+    movd    [bufq+xq-3], m1
+    psrldq           m1, 1
+    inc              xq
+    jz .x_loop_ar3_end
+    test             xq, 3
+    jnz .x_loop_ar3_inner
+    jmp .x_loop_ar3
+
+.x_loop_ar3_end:
+    add            bufq, 82
+    add           bufyq, 82<<%3
+    dec              hd
+    jg .y_loop_ar3
+    RET
+%endmacro
+
+generate_grain_uv_fn 420, 1, 1
+generate_grain_uv_fn 422, 1, 0
+generate_grain_uv_fn 444, 0, 0
+
+%macro vpgatherdw 5-6 ; dst, src, base, tmp_gpr[x2], tmp_xmm_reg
+%assign %%idx 0
+%define %%tmp %2
+%if %0 == 6
+%define %%tmp %6
+%endif
+%rep 4
+%if %%idx == 0
+    movd        %5 %+ d, %2
+    pshuflw       %%tmp, %2, q3232
+%else
+    movd        %5 %+ d, %%tmp
+%if %%idx == 2
+    punpckhqdq    %%tmp, %%tmp
+%elif %%idx == 4
+    psrlq         %%tmp, 32
+%endif
+%endif
+    movzx       %4 %+ d, %5 %+ w
+    shr         %5 %+ d, 16
+
+%if %%idx == 0
+    movd             %1, [%3+%4]
+%else
+    pinsrw           %1, [%3+%4], %%idx + 0
+%endif
+    pinsrw           %1, [%3+%5], %%idx + 1
+%assign %%idx %%idx+2
+%endrep
+%endmacro
+
+INIT_XMM ssse3
+; fgy_32x32xn(dst, src, stride, fg_data, w, scaling, grain_lut, h, sby)
+%if ARCH_X86_32
+%if STACK_ALIGNMENT < mmsize
+cglobal fgy_32x32xn_8bpc, 0, 7, 16, 0 - (5 * mmsize + 16 * gprsize), \
+        dst, src, scaling, unused1, fg_data, picptr, unused2
+    ; copy stack arguments to new position post-alignment, so that we
+    ; don't have to keep the old stack location in a separate register
+    mov              r0, r0m
+    mov              r1, r2m
+    mov              r2, r4m
+    mov              r3, r6m
+    mov              r4, r7m
+    mov              r5, r8m
+
+    mov [rsp+5*mmsize+ 4*gprsize], r0
+    mov [rsp+5*mmsize+ 6*gprsize], r1
+    mov [rsp+5*mmsize+ 8*gprsize], r2
+    mov [rsp+5*mmsize+10*gprsize], r3
+    mov [rsp+5*mmsize+11*gprsize], r4
+    mov [rsp+5*mmsize+12*gprsize], r5
+%else
+cglobal fgy_32x32xn_8bpc, 0, 7, 16, 5 * mmsize + 4 * gprsize, \
+        dst, src, scaling, unused1, fg_data, picptr, unused2
+%endif
+    mov            srcq, srcm
+    mov        fg_dataq, r3m
+    mov        scalingq, r5m
+%if STACK_ALIGNMENT < mmsize
+%define r0m [rsp+5*mmsize+ 4*gprsize]
+%define r1m [rsp+5*mmsize+ 5*gprsize]
+%define r2m [rsp+5*mmsize+ 6*gprsize]
+%define r3m [rsp+5*mmsize+ 7*gprsize]
+%define r4m [rsp+5*mmsize+ 8*gprsize]
+%define r5m [rsp+5*mmsize+ 9*gprsize]
+%define r6m [rsp+5*mmsize+10*gprsize]
+%define r7m [rsp+5*mmsize+11*gprsize]
+%define r8m [rsp+5*mmsize+12*gprsize]
+%endif
+    LEA              r5, pb_mask
+%define base r5-pb_mask
+    mov             r5m, picptrq
+%else
+cglobal fgy_32x32xn_8bpc, 6, 15, 16, dst, src, stride, fg_data, w, scaling, grain_lut
+    lea              r7, [pb_mask]
+%define base r7-pb_mask
+%endif
+    mov             r6d, [fg_dataq+FGData.scaling_shift]
+    movd             m3, [base+mul_bits+r6*2-14]
+    mov             r6d, [fg_dataq+FGData.clip_to_restricted_range]
+    movd             m4, [base+max+r6*4]
+    movd             m5, [base+min+r6*2]
+    punpcklwd        m3, m3
+    punpcklwd        m4, m4
+    punpcklwd        m5, m5
+    pshufd           m3, m3, q0000
+    pshufd           m4, m4, q0000
+    pshufd           m5, m5, q0000
+    SCRATCH           3, 11, 0
+    SCRATCH           4, 12, 1
+    SCRATCH           5, 13, 2
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused, sby, see, overlap
+%endif
+
+    mov            sbyd, r8m
+    mov        overlapd, [fg_dataq+FGData.overlap_flag] ; left_overlap: overlap & 1
+    test       overlapd, overlapd
+    jz .no_vertical_overlap
+    mova             m6, [base+pw_1024]
+    mova             m7, [base+pb_27_17_17_27]
+    SCRATCH           6, 14, 3
+    SCRATCH           7, 15, 4
+    test           sbyd, sbyd
+    jnz .vertical_overlap
+    ; fall-through
+
+.no_vertical_overlap:
+    mov             r8m, overlapd
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, see, fg_data, picptr, unused
+    imul           seed, (173 << 24) | 37
+%else
+    imul           seed, sbyd, (173 << 24) | 37
+%endif
+    add            seed, (105 << 24) | 178
+    rol            seed, 8
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, src_bak
+
+    mov             r3m, seed
+    mov              wq, r4m
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                unused1, unused2, see, unused3
+%endif
+
+    lea        src_bakq, [srcq+wq]
+    neg              wq
+    sub           dstmp, srcq
+%if ARCH_X86_32
+    mov             r1m, src_bakq
+    mov             r4m, wq
+    DEFINE_ARGS dst, src, scaling, see, unused1, unused2, unused3
+%endif
+
+.loop_x:
+%if ARCH_X86_32
+    mov            seed, r3m
+%endif
+    mov             r6d, seed
+    or             seed, 0xEFF4
+    shr             r6d, 1
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                offx, offy, see, unused
+
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    shr           offxd, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyq, [offyq+offxq*2+747] ; offy*stride+offx
+
+%if ARCH_X86_32
+    ; r0m=dst, r1m=src_bak, r2m=stride, r3m=see, r4m=w, r5m=picptr,
+    ; r6m=grain_lut, r7m=h, r8m=overlap_v|h
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                h, offxy, see, unused
+%endif
+
+.loop_x_odd:
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+.loop_y:
+    ; src
+    mova             m0, [srcq]
+    pxor             m2, m2
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2                 ; m0-1: src as word
+
+    ; scaling[src]
+%if ARCH_X86_32
+    vpgatherdw       m4, m0, scalingq-1, r0, r5, m3
+    vpgatherdw       m5, m1, scalingq-1, r0, r5, m3
+%else
+    vpgatherdw       m4, m0, scalingq-1, r12, r13, m3
+    vpgatherdw       m5, m1, scalingq-1, r12, r13, m3
+%endif
+    REPX {psrlw x, 8}, m4, m5
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq]
+    pcmpgtb          m7, m2, m3
+    punpcklbw        m2, m3, m7
+    punpckhbw        m3, m7
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmullw           m2, m4
+    pmullw           m3, m5
+    pmulhrsw         m2, m11
+    pmulhrsw         m3, m11
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    packuswb         m0, m1
+    movifnidn      dstq, dstmp
+    mova    [dstq+srcq], m0
+
+    add            srcq, r2mp
+    add      grain_lutq, 82
+    dec              hd
+    jg .loop_y
+
+%if ARCH_X86_32
+    add            r4mp, 16
+%else
+    add              wq, 16
+%endif
+    jge .end
+%if ARCH_X86_32
+    mov            srcq, r1mp
+    add            srcq, r4mp
+%else
+    lea            srcq, [src_bakq+wq]
+%endif
+    btc       dword r8m, 2
+    jc .next_blk
+
+    add          offxyd, 16
+    test      dword r8m, 2              ; r8m & 2 = have_top_overlap
+    jz .loop_x_odd
+
+%if ARCH_X86_32
+    add dword [rsp+5*mmsize+1*gprsize], 16
+%else
+    add            r11d, 16             ; top_offxyd
+%endif
+    jnz .loop_x_odd_v_overlap
+
+.next_blk:
+    test      dword r8m, 1
+    jz .loop_x
+
+    test      dword r8m, 2
+    jnz .loop_x_hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+.loop_x_h_overlap:
+%if ARCH_X86_32
+    ; r0m=dst, r1m=src_bak, r2m=stride, r3m=see, r4m=w, r5m=picptr,
+    ; r6m=grain_lut, r7m=h, r8m=overlap_v|h
+    DEFINE_ARGS dst, src, scaling, offxy, unused1, unused2, unused3
+
+    add          offxyd, 16                 ; left_offxyd
+    mov [rsp+5*mmsize+0*gprsize], offxyd
+
+    DEFINE_ARGS dst, src, scaling, see, unused1, unused2, unused3
+
+    mov            seed, r3m
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy
+
+    lea     left_offxyd, [offyd+16]         ; previous column's offy*stride+offx
+%endif
+
+    mov             r6d, seed
+    or             seed, 0xEFF4
+    shr             r6d, 1
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx
+
+    mov           offxd, offyd
+%else
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    shr           offxd, 12
+    and           offyd, 0xf
+    imul          offyd, 164
+    lea           offyq, [offyq+offxq*2+747] ; offy*stride+offx
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy
+%endif
+
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+.loop_y_h_overlap:
+    ; src
+    mova             m0, [srcq]
+    pxor             m2, m2
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2                 ; m0-1: src as word
+
+    ; scaling[src]
+%if ARCH_X86_32
+    vpgatherdw       m4, m0, scalingq-1, r0, r5, m3
+    vpgatherdw       m5, m1, scalingq-1, r0, r5, m3
+%else
+    vpgatherdw       m4, m0, scalingq-1, r12, r13, m3
+    vpgatherdw       m5, m1, scalingq-1, r12, r13, m3
+%endif
+    REPX {psrlw x, 8}, m4, m5
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq]
+%if ARCH_X86_32
+    mov              r5, [rsp+5*mmsize+0*gprsize]
+    movd             m7, [grain_lutq+r5]
+%else
+    movd             m7, [grain_lutq+left_offxyq]
+%endif
+    punpcklbw        m7, m3
+    pmaddubsw        m6, m15, m7
+    pmulhrsw         m6, m14
+    packsswb         m6, m6
+    shufps           m6, m3, q3210
+    pcmpgtb          m2, m6
+    punpcklbw        m7, m6, m2
+    punpckhbw        m6, m2
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmullw           m7, m4
+    pmullw           m6, m5
+    pmulhrsw         m7, m11
+    pmulhrsw         m6, m11
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m7
+    paddw            m1, m6
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    packuswb         m0, m1
+    movifnidn      dstq, dstmp
+    mova    [dstq+srcq], m0
+
+    add            srcq, r2mp
+    add      grain_lutq, 82
+    dec              hd
+    jg .loop_y_h_overlap
+
+%if ARCH_X86_32
+    add            r4mp, 16
+%else
+    add              wq, 16
+%endif
+    jge .end
+%if ARCH_X86_32
+    mov            srcq, r1m
+    add            srcq, r4m
+%else
+    lea            srcq, [src_bakq+wq]
+%endif
+    xor       dword r8m, 4
+    add          offxyd, 16
+
+    ; since this half-block had left-overlap, the next does not
+    test      dword r8m, 2              ; have_top_overlap
+    jz .loop_x_odd
+%if ARCH_X86_32
+    add dword [rsp+5*mmsize+1*gprsize], 16
+%else
+    add            r11d, 16             ; top_offxyd
+%endif
+    jmp .loop_x_odd_v_overlap
+
+.end:
+    RET
+
+.vertical_overlap:
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, tmp, sby, see, overlap
+%endif
+
+    or         overlapd, 2                  ; top_overlap: overlap & 2
+    mov             r8m, overlapd
+    movzx          sbyd, sbyb
+%if ARCH_X86_32
+    imul             r4, [fg_dataq+FGData.seed], 0x00010001
+    DEFINE_ARGS tmp, src, scaling, sby, see, picptr, unused
+%else
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+%endif
+    imul           tmpd, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add            tmpd, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and            tmpd, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, tmpd
+%if ARCH_X86_32
+    xor            sbyd, seed               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, scaling, see, w, picptr, src_bak
+
+    mov             r3m, seed
+    mov              wq, r4m
+%else
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                tmp, unused2, see, unused3
+%endif
+
+    lea        src_bakq, [srcq+wq]
+    neg              wq
+    sub           dstmp, srcq
+%if ARCH_X86_32
+    mov             r1m, src_bakq
+    mov             r4m, wq
+    DEFINE_ARGS tmp, src, scaling, see, unused1, picptr, unused2
+%endif
+
+.loop_x_v_overlap:
+%if ARCH_X86_32
+    mov            seed, r3m
+%endif
+    ; we assume from the block above that bits 8-15 of tmpd are zero'ed,
+    ; because of the 'and tmpd, 0x00ff00ff' above
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp           tmpb                     ; parity of top_seed
+    shr            seed, 16
+    shl            tmpd, 16
+    test           seeb, seeh
+    setp           tmpb                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor            tmpd, r6d
+    mov            seed, tmpd
+    ror            seed, 1                  ; updated (cur_seed << 16) | top_seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                offx, offy, see, unused, top_offxy
+
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+
+    ror           offyd, 8
+    ror           offxd, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyq, [offyq+offxq*2+0x10001*747+32*82]
+
+%if ARCH_X86_32
+    DEFINE_ARGS top_offxy, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                h, offxy, see, unused, top_offxy
+%endif
+
+    movzx    top_offxyd, offxyw
+%if ARCH_X86_32
+    mov [rsp+5*mmsize+1*gprsize], top_offxyd
+
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+    shr          offxyd, 16
+
+.loop_x_odd_v_overlap:
+%if ARCH_X86_32
+    mov              r5, r5m
+    lea              r5, [base+pb_27_17]
+    mov [rsp+5*mmsize+12], r5
+%else
+    mova             m8, [pb_27_17]
+%endif
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+.loop_y_v_overlap:
+    ; src
+    mova             m0, [srcq]
+    pxor             m2, m2
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2                 ; m0-1: src as word
+
+    ; scaling[src]
+%if ARCH_X86_32
+    vpgatherdw       m4, m0, scalingq-1, r0, r5, m3
+    vpgatherdw       m5, m1, scalingq-1, r0, r5, m3
+%else
+    vpgatherdw       m4, m0, scalingq-1, r12, r13, m3
+    vpgatherdw       m5, m1, scalingq-1, r12, r13, m3
+%endif
+    REPX {psrlw x, 8}, m4, m5
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq]
+%if ARCH_X86_32
+    mov              r5, [rsp+5*mmsize+1*gprsize]
+    movu             m7, [grain_lutq+r5]
+%else
+    movu             m7, [grain_lutq+top_offxyq]
+%endif
+    punpckhbw        m6, m7, m3
+    punpcklbw        m7, m3
+%if ARCH_X86_32
+    mov              r5, [rsp+5*mmsize+12]
+    pmaddubsw        m3, [r5], m6
+    pmaddubsw        m6, [r5], m7
+%else
+    pmaddubsw        m3, m8, m6
+    pmaddubsw        m6, m8, m7
+%endif
+    pmulhrsw         m3, m14
+    pmulhrsw         m6, m14
+    packsswb         m6, m3
+    pcmpgtb          m7, m2, m6
+    punpcklbw        m2, m6, m7
+    punpckhbw        m6, m7
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmullw           m2, m4
+    pmullw           m6, m5
+    pmulhrsw         m2, m11
+    pmulhrsw         m6, m11
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m6
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    packuswb         m0, m1
+    movifnidn      dstq, dstmp
+    mova    [dstq+srcq], m0
+
+%if ARCH_X86_32
+    add dword [rsp+5*mmsize+12], mmsize
+%else
+    mova             m8, [pb_17_27]
+%endif
+    add            srcq, r2mp
+    add      grain_lutq, 82
+    dec              hw
+    jz .end_y_v_overlap
+    ; 2 lines get vertical overlap, then fall back to non-overlap code for
+    ; remaining (up to) 30 lines
+    btc              hd, 16
+    jnc .loop_y_v_overlap
+    jmp .loop_y
+
+.end_y_v_overlap:
+%if ARCH_X86_32
+    add            r4mp, 16
+%else
+    add              wq, 16
+%endif
+    jge .end_hv
+%if ARCH_X86_32
+    mov            srcq, r1mp
+    add            srcq, r4mp
+%else
+    lea            srcq, [src_bakq+wq]
+%endif
+    btc       dword r8m, 2
+    jc .loop_x_hv_overlap
+    add          offxyd, 16
+%if ARCH_X86_32
+    add dword [rsp+5*mmsize+1*gprsize], 16
+%else
+    add      top_offxyd, 16
+%endif
+    jmp .loop_x_odd_v_overlap
+
+.loop_x_hv_overlap:
+%if ARCH_X86_32
+    mov              r5, r5m
+    lea              r5, [base+pb_27_17]
+    mov [rsp+5*mmsize+12], r5
+
+    DEFINE_ARGS tmp, src, scaling, offxy, w, picptr, src_bak
+
+    mov              r5, [rsp+5*mmsize+1*gprsize]
+    mov              r4, offxyd
+    add              r5, 16
+    add              r4, 16
+    mov [rsp+5*mmsize+2*gprsize], r5        ; topleft_offxy
+    mov [rsp+5*mmsize+0*gprsize], r4        ; left_offxy
+
+    DEFINE_ARGS tmp, src, scaling, see, w, picptr, src_bak
+
+    xor            tmpd, tmpd
+    mov            seed, r3m
+%else
+    mova             m8, [pb_27_17]
+
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                tmp, unused2, see, unused3
+
+    ; we assume from the block above that bits 8-15 of tmpd are zero'ed
+%endif
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp           tmpb                     ; parity of top_seed
+    shr            seed, 16
+    shl            tmpd, 16
+    test           seeb, seeh
+    setp           tmpb                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor            tmpd, r6d
+    mov            seed, tmpd
+    ror            seed, 1                  ; updated (cur_seed << 16) | top_seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, unused1, unused2, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, top_offxy, topleft_offxy
+
+    lea  topleft_offxyq, [top_offxyq+16]
+    lea     left_offxyq, [offyq+16]
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    ror           offxd, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyq, [offyq+offxq*2+0x10001*747+32*82]
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+
+    movzx            r5, offxyw             ; top_offxy
+    mov [rsp+5*mmsize+1*gprsize], r5
+%else
+    DEFINE_ARGS dst, src, stride, src_bak, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, top_offxy, topleft_offxy
+
+    movzx    top_offxyd, offxyw
+%endif
+    shr          offxyd, 16
+
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+.loop_y_hv_overlap:
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq]
+%if ARCH_X86_32
+    mov              r5, [rsp+5*mmsize+1*gprsize]   ; top_offxy
+    mov              r0, [rsp+5*mmsize+0*gprsize]   ; left_offxy
+    movu             m6, [grain_lutq+r5]
+    mov              r5, [rsp+5*mmsize+2*gprsize]   ; topleft_offxy
+    movd             m4, [grain_lutq+r0]
+    movd             m7, [grain_lutq+r5]
+%else
+    movu             m6, [grain_lutq+top_offxyq]
+    movd             m4, [grain_lutq+left_offxyq]
+    movd             m7, [grain_lutq+topleft_offxyq]
+%endif
+    ; do h interpolation first (so top | top/left -> top, left | cur -> cur)
+    punpcklbw        m4, m3
+    punpcklbw        m7, m6
+    pmaddubsw        m2, m15, m4
+    pmaddubsw        m4, m15, m7
+    pmulhrsw         m2, m14
+    pmulhrsw         m4, m14
+    packsswb         m2, m2
+    packsswb         m4, m4
+    shufps           m2, m3, q3210
+    shufps           m4, m6, q3210
+    ; followed by v interpolation (top | cur -> cur)
+    punpcklbw        m3, m4, m2
+    punpckhbw        m4, m2
+%if ARCH_X86_32
+    mov              r5, [rsp+5*mmsize+12]
+    pmaddubsw        m7, [r5], m4
+    pmaddubsw        m4, [r5], m3
+%else
+    pmaddubsw        m7, m8, m4
+    pmaddubsw        m4, m8, m3
+%endif
+    pmulhrsw         m7, m14
+    pmulhrsw         m4, m14
+    packsswb         m4, m7
+    pxor             m2, m2
+    pcmpgtb          m7, m2, m4
+    punpcklbw        m3, m4, m7
+    punpckhbw        m4, m7
+
+    ; src
+    mova             m0, [srcq]
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2                 ; m0-1: src as word
+
+    ; scaling[src]
+%if ARCH_X86_32
+    vpgatherdw       m5, m0, scalingq-1, r0, r5, m7
+    vpgatherdw       m6, m1, scalingq-1, r0, r5, m7
+%else
+    vpgatherdw       m5, m0, scalingq-1, r13, r14, m7
+    vpgatherdw       m6, m1, scalingq-1, r13, r14, m7
+%endif
+    REPX {psrlw x, 8}, m5, m6
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmullw           m3, m5
+    pmullw           m4, m6
+    pmulhrsw         m3, m11
+    pmulhrsw         m4, m11
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m3
+    paddw            m1, m4
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    packuswb         m0, m1
+    movifnidn      dstq, dstmp
+    mova    [dstq+srcq], m0
+
+%if ARCH_X86_32
+    add dword [rsp+5*mmsize+12], mmsize
+%else
+    mova             m8, [pb_17_27]
+%endif
+    add            srcq, r2mp
+    add      grain_lutq, 82
+    dec              hw
+    jz .end_y_hv_overlap
+    ; 2 lines get vertical overlap, then fall back to non-overlap code for
+    ; remaining (up to) 30 lines
+    btc              hd, 16
+    jnc .loop_y_hv_overlap
+    jmp .loop_y_h_overlap
+
+.end_y_hv_overlap:
+%if ARCH_X86_32
+    add            r4mp, 16
+%else
+    add              wq, 16
+%endif
+    jge .end_hv
+%if ARCH_X86_32
+    mov            srcq, r1m
+    add            srcq, r4m
+%else
+    lea            srcq, [src_bakq+wq]
+%endif
+    xor       dword r8m, 4
+    add          offxyd, 16
+%if ARCH_X86_32
+    add dword [rsp+5*mmsize+1*gprsize], 16
+%else
+    add      top_offxyd, 16
+%endif
+    jmp .loop_x_odd_v_overlap
+
+.end_hv:
+    RET
+
+%macro FGUV_FN 3 ; name, ss_hor, ss_ver
+INIT_XMM ssse3
+%if ARCH_X86_32
+; fguv_32x32xn_i420_ssse3(dst, src, stride, fg_data, w, scaling, grain_lut, h,
+;                         sby, luma, lstride, uv_pl, is_id)
+%if STACK_ALIGNMENT < mmsize
+DECLARE_ARG 0, 1, 2, 3, 4, 5, 6, 7, 8
+cglobal fguv_32x32xn_i%1_8bpc, 0, 7, 8, 0 - (7 * mmsize + (13 + 3) * gprsize), \
+        tmp, src, scaling, h, fg_data, picptr, unused
+    mov              r0, r0m
+    mov              r1, r2m
+    mov              r2, r4m
+    mov              r3, r6m
+    mov              r4, r7m
+    mov [rsp+7*mmsize+3*gprsize], r0
+    mov [rsp+7*mmsize+5*gprsize], r1
+    mov [rsp+7*mmsize+7*gprsize], r2
+    mov [rsp+7*mmsize+9*gprsize], r3
+    mov [rsp+7*mmsize+10*gprsize], r4
+
+    mov              r0, r8m
+    mov              r1, r9m
+    mov              r2, r10m
+    mov              r4, r11m
+    mov              r3, r12m
+    mov [rsp+7*mmsize+11*gprsize], r0
+    mov [rsp+7*mmsize+12*gprsize], r1
+    mov [rsp+7*mmsize+13*gprsize], r2
+    mov [rsp+7*mmsize+14*gprsize], r4
+%else
+cglobal fguv_32x32xn_i%1_8bpc, 0, 7, 8, 7 * mmsize + (4) * gprsize, \
+        tmp, src, scaling, h, fg_data, picptr, unused
+%endif
+    mov            srcq, srcm
+    mov        fg_dataq, r3m
+    mov        scalingq, r5m
+%if STACK_ALIGNMENT < mmsize
+%define r0m [rsp+7*mmsize+ 3*gprsize]
+%define r1m [rsp+7*mmsize+ 4*gprsize]
+%define r2m [rsp+7*mmsize+ 5*gprsize]
+%define r3m [rsp+7*mmsize+ 6*gprsize]
+%define r4m [rsp+7*mmsize+ 7*gprsize]
+%define r5m [rsp+7*mmsize+ 8*gprsize]
+%define r6m [rsp+7*mmsize+ 9*gprsize]
+%define r7m [rsp+7*mmsize+10*gprsize]
+%define r8m [rsp+7*mmsize+11*gprsize]
+%define r9m [rsp+7*mmsize+12*gprsize]
+%define r10m [rsp+7*mmsize+13*gprsize]
+%define r11m [rsp+7*mmsize+14*gprsize]
+%define r12m [rsp+7*mmsize+15*gprsize]
+%endif
+    LEA              r5, pb_mask
+%define base r5-pb_mask
+    mov             r5m, r5
+%else
+cglobal fguv_32x32xn_i%1_8bpc, 6, 15, 16, dst, src, stride, fg_data, w, scaling, \
+                                     grain_lut, tmp, sby, luma, lstride, uv_pl, is_id
+    lea              r8, [pb_mask]
+%define base r8-pb_mask
+%endif
+    mov             r6d, [fg_dataq+FGData.scaling_shift]
+    movd             m3, [base+mul_bits+r6*2-14]
+    mov             r6d, [fg_dataq+FGData.clip_to_restricted_range]
+    lea            tmpd, [r6d*2]
+%if ARCH_X86_32 && STACK_ALIGNMENT < mmsize
+    test             r3, r3
+%else
+    cmp      dword r12m, 0                      ; is_idm
+%endif
+    movd             m5, [base+min+r6*2]
+    cmovne          r6d, tmpd
+    movd             m4, [base+max+r6*2]
+    punpcklwd        m3, m3
+    punpcklwd        m5, m5
+    punpcklwd        m4, m4
+    pshufd           m3, m3, q0000
+    pshufd           m5, m5, q0000
+    pshufd           m4, m4, q0000
+    SCRATCH           3, 11, 0
+    SCRATCH           4, 12, 1
+    SCRATCH           5, 13, 2
+
+    cmp byte [fg_dataq+FGData.chroma_scaling_from_luma], 0
+    jne .csfl
+
+%macro %%FGUV_32x32xN_LOOP 3 ; not-csfl, ss_hor, ss_ver
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, unused, sby, see, overlap
+%endif
+
+%if %1
+    mov             r6d, dword r11m
+    movd             m0, [fg_dataq+FGData.uv_mult+r6*4]
+    movd             m1, [fg_dataq+FGData.uv_luma_mult+r6*4]
+    punpcklbw        m6, m1, m0
+    movd             m7, [fg_dataq+FGData.uv_offset+r6*4]
+    punpcklwd        m6, m6
+    punpcklwd        m7, m7
+    pshufd           m6, m6, q0000
+    pshufd           m7, m7, q0000
+    SCRATCH           6, 14, 3
+    SCRATCH           7, 15, 4
+%endif
+
+    mov            sbyd, r8m
+    mov        overlapd, [fg_dataq+FGData.overlap_flag] ; left_overlap: overlap & 1
+    test       overlapd, overlapd
+    jz %%no_vertical_overlap
+%if ARCH_X86_32
+%if %2
+    mova             m1, [base+pb_23_22_h]
+%else
+    mova             m1, [base+pb_27_17_17_27]
+%endif
+    mova             m0, [base+pw_1024]
+%else
+%if %2
+    mova             m1, [pb_23_22_h]
+%else
+    mova             m1, [pb_27_17_17_27]
+%endif
+    mova             m0, [pw_1024]
+%endif
+    SCRATCH           0, 8, 5
+    SCRATCH           1, 9, 6
+    test           sbyd, sbyd
+    jnz %%vertical_overlap
+    ; fall-through
+
+%%no_vertical_overlap:
+    mov             r8m, overlapd
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, see, fg_data, picptr, overlap
+    imul           seed, (173 << 24) | 37
+%else
+    imul           seed, sbyd, (173 << 24) | 37
+%endif
+    add            seed, (105 << 24) | 178
+    rol            seed, 8
+    movzx          seed, seew
+    xor            seed, [fg_dataq+FGData.seed]
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS luma, src, scaling, see, w, picptr, src_bak
+%define luma_bakq lumaq
+
+    mov              wq, r4m
+%if %3
+    shl           r10mp, 1
+%endif
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                unused2, unused3, see, overlap, unused4, src_bak, lstride, luma_bak
+
+    mov        lstrideq, r10mp
+%endif
+
+    mov           lumaq, r9mp
+    lea        src_bakq, [srcq+wq]
+    lea       luma_bakq, [lumaq+wq*(1+%2)]
+    neg              wq
+    sub            r0mp, srcq
+%if ARCH_X86_32
+    mov             r1m, src_bakq
+    mov            r11m, luma_bakq
+    mov             r4m, wq
+
+    DEFINE_ARGS tmp, src, scaling, see, unused1, picptr, unused2
+%else
+    mov           r11mp, src_bakq
+    mov           r12mp, strideq
+%endif
+
+%%loop_x:
+%if ARCH_X86_32
+    mov            seed, r3m
+%endif
+    mov             r6d, seed
+    or             seed, 0xEFF4
+    shr             r6d, 1
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d               ; updated seed
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, w, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, overlap, unused1, unused2, lstride
+
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    shr           offxd, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyq, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+(3+(6>>%2))]  ; offy*stride+offx
+
+%if ARCH_X86_32
+    DEFINE_ARGS luma, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                h, offxy, see, overlap, unused1, unused2, lstride, luma_bak
+%endif
+
+%%loop_x_odd:
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+%%loop_y:
+    ; src
+%if ARCH_X86_32
+    mov           lumaq, r9mp
+%endif
+%if %2
+    mova             m4, [lumaq+ 0]
+    mova             m6, [lumaq+16]
+    mova             m0, [srcq]
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+    mov              r5, r5m
+    movd             m7, [base+pb_1]
+%else
+    movd             m7, [pb_1]
+%endif
+    pshufd           m7, m7, q0000
+    pxor             m2, m2
+    pmaddubsw        m4, m7
+    pmaddubsw        m6, m7
+    pavgw            m4, m2
+    pavgw            m6, m2
+%else
+    mova             m4, [lumaq]
+    mova             m0, [srcq]
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+%endif
+    pxor             m2, m2
+%endif
+
+%if %1
+%if %2
+    packuswb         m4, m6                 ; luma
+%endif
+    punpckhbw        m6, m4, m0
+    punpcklbw        m4, m0                 ; { luma, chroma }
+    pmaddubsw        m6, m14
+    pmaddubsw        m4, m14
+    psraw            m6, 6
+    psraw            m4, 6
+    paddw            m6, m15
+    paddw            m4, m15
+    packuswb         m4, m6                 ; pack+unpack = clip
+    punpckhbw        m6, m4, m2
+    punpcklbw        m4, m2
+%elif %2 == 0
+    punpckhbw        m6, m4, m2
+    punpcklbw        m4, m2
+%endif
+
+    ; scaling[luma_src]
+%if ARCH_X86_32
+    vpgatherdw       m7, m4, scalingq-1, r0, r5
+    vpgatherdw       m5, m6, scalingq-1, r0, r5
+%else
+    vpgatherdw       m7, m4, scalingq-1, r12, r2
+    vpgatherdw       m5, m6, scalingq-1, r12, r2
+%endif
+    REPX {psrlw x, 8}, m7, m5
+
+    ; unpack chroma_source
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2                 ; m0-1: src as word
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq+ 0]
+    pcmpgtb          m6, m2, m3
+    punpcklbw        m2, m3, m6
+    punpckhbw        m3, m6
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmullw           m2, m7
+    pmullw           m3, m5
+    pmulhrsw         m2, m11
+    pmulhrsw         m3, m11
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    packuswb         m0, m1
+    movifnidn      dstq, dstmp
+    mova    [dstq+srcq], m0
+
+%if ARCH_X86_32
+    add            srcq, r2mp
+    ; we already incremented lumaq above
+%else
+    add            srcq, r12mp
+%if %3
+    lea           lumaq, [lumaq+lstrideq*2]
+%else
+    add           lumaq, lstrideq
+%endif
+%endif
+    add      grain_lutq, 82
+    dec              hw
+    jg %%loop_y
+
+%if ARCH_X86_32
+    DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut
+
+    mov              wq, r4m
+%endif
+    add              wq, 16
+    jge %%end
+%if ARCH_X86_32
+    mov            srcq, r1mp
+    mov           lumaq, r11mp
+%else
+    mov            srcq, r11mp
+%endif
+    lea           lumaq, [luma_bakq+wq*(1+%2)]
+    add            srcq, wq
+%if ARCH_X86_32
+    mov             r4m, wq
+    mov             r9m, lumaq
+%endif
+%if %2 == 0
+    ; adjust top_offxy
+%if ARCH_X86_32
+    add dword [rsp+7*mmsize+1*gprsize], 16
+%else
+    add            r11d, 16
+%endif
+    add          offxyd, 16
+    btc       dword r8m, 2
+    jc %%loop_x_even
+    test      dword r8m, 2
+    jz %%loop_x_odd
+    jmp %%loop_x_odd_v_overlap
+%%loop_x_even:
+%endif
+    test      dword r8m, 1
+    jz %%loop_x
+
+    ; r8m = sbym
+    test      dword r8m, 2
+    jne %%loop_x_hv_overlap
+
+    ; horizontal overlap (without vertical overlap)
+%%loop_x_h_overlap:
+%if ARCH_X86_32
+%if %2
+    lea              r6, [offxyd+16]
+    mov [rsp+7*mmsize+0*gprsize], r6
+%else
+    mov [rsp+7*mmsize+0*gprsize], offxyd
+%endif
+
+    DEFINE_ARGS luma, src, scaling, see, w, picptr, grain_lut
+
+    mov            seed, r3m
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, unused1, unused2, lstride
+
+%if %2
+    lea     left_offxyd, [offyd+16]         ; previous column's offy*stride+offx
+%else
+    mov     left_offxyd, offyd
+%endif
+%endif
+    mov             r6d, seed
+    or             seed, 0xEFF4
+    shr             r6d, 1
+    test           seeb, seeh
+    lea            seed, [r6+0x8000]
+    cmovp          seed, r6d                ; updated seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS luma, src, scaling, offy, w, picptr, offx
+
+    mov          offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, unused1, unused2, lstride
+
+    mov           offyd, seed
+    mov           offxd, seed
+%endif
+    ror           offyd, 8
+    shr           offxd, 12
+    and           offyd, 0xf
+    imul          offyd, 164>>%3
+    lea           offyq, [offyq+offxq*(2-%2)+(3+(6>>%3))*82+3+(6>>%2)]  ; offy*stride+offx
+
+%if ARCH_X86_32
+    DEFINE_ARGS luma, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, unused1, unused2, lstride, luma_bak
+%endif
+
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+%%loop_y_h_overlap:
+    ; src
+%if ARCH_X86_32
+    mov           lumaq, r9mp
+%endif
+%if %2
+    mova             m4, [lumaq+ 0]
+    mova             m6, [lumaq+16]
+    mova             m0, [srcq]
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+    mov              r5, r5m
+    movd             m7, [base+pb_1]
+%else
+    movd             m7, [pb_1]
+%endif
+    pshufd           m7, m7, q0000
+    pxor             m2, m2
+    pmaddubsw        m4, m7
+    pmaddubsw        m6, m7
+    pavgw            m4, m2
+    pavgw            m6, m2
+%else
+    mova             m4, [lumaq]
+    mova             m0, [srcq]
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+%endif
+    pxor             m2, m2
+%endif
+
+%if %1
+%if %2
+    packuswb         m4, m6                 ; luma
+%endif
+    punpckhbw        m6, m4, m0
+    punpcklbw        m4, m0                 ; { luma, chroma }
+    pmaddubsw        m6, m14
+    pmaddubsw        m4, m14
+    psraw            m6, 6
+    psraw            m4, 6
+    paddw            m6, m15
+    paddw            m4, m15
+    packuswb         m4, m6                 ; pack+unpack = clip
+    punpckhbw        m6, m4, m2
+    punpcklbw        m4, m2
+%elif %2 == 0
+    punpckhbw        m6, m4, m2
+    punpcklbw        m4, m2
+%endif
+
+    ; scaling[luma_src]
+%if ARCH_X86_32
+    vpgatherdw       m7, m4, scalingq-1, r0, r5
+    vpgatherdw       m5, m6, scalingq-1, r0, r5
+%else
+    vpgatherdw       m7, m4, scalingq-1, r12, r2
+    vpgatherdw       m5, m6, scalingq-1, r12, r2
+%endif
+    REPX {psrlw x, 8}, m7, m5
+
+    ; unpack chroma_source
+    punpckhbw        m1, m0, m2
+    punpcklbw        m0, m2                 ; m0-1: src as word
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m4, [grain_lutq+offxyq+ 0]
+%if ARCH_X86_32
+    mov              r0, [rsp+7*mmsize+0*gprsize]
+    movd             m2, [grain_lutq+r0+ 0]
+%else
+    movd             m2, [grain_lutq+left_offxyq+ 0]
+%endif
+    punpcklbw        m2, m4
+    pmaddubsw        m3, m9, m2
+    pmulhrsw         m3, m8
+    packsswb         m3, m3
+    shufps           m3, m4, q3210
+    pxor             m4, m4
+    pcmpgtb          m4, m3
+    punpcklbw        m2, m3, m4
+    punpckhbw        m3, m4
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmullw           m2, m7
+    pmullw           m3, m5
+    pmulhrsw         m2, m11
+    pmulhrsw         m3, m11
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m1, m3
+    pmaxsw           m0, m13
+    pmaxsw           m1, m13
+    pminsw           m0, m12
+    pminsw           m1, m12
+    packuswb         m0, m1
+    movifnidn      dstq, dstmp
+    mova    [dstq+srcq], m0
+
+%if ARCH_X86_32
+    add            srcq, r2mp
+    ; lumaq has already been incremented above
+%else
+    add            srcq, r12mp
+%if %3
+    lea           lumaq, [lumaq+lstrideq*2]
+%else
+    add           lumaq, lstrideq
+%endif
+%endif
+    add      grain_lutq, 82
+    dec              hw
+    jg %%loop_y_h_overlap
+
+%if ARCH_X86_32
+    DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut
+
+    mov              wq, r4m
+%endif
+    add              wq, 16
+    jge %%end
+%if ARCH_X86_32
+    mov            srcq, r1mp
+    mov           lumaq, r11mp
+%else
+    mov            srcq, r11mp
+%endif
+    lea           lumaq, [luma_bakq+wq*(1+%2)]
+    add            srcq, wq
+%if ARCH_X86_32
+    mov             r4m, wq
+    mov             r9m, lumaq
+%endif
+%if %2 == 0
+    xor       dword r8m, 4
+    ; adjust top_offxyd
+%if ARCH_X86_32
+    add dword [rsp+7*mmsize+1*gprsize], 16
+%else
+    add            r11d, 16
+%endif
+    add          offxyd, 16
+%endif
+
+    ; r8m = sbym
+    test      dword r8m, 2
+%if %2
+    jne %%loop_x_hv_overlap
+    jmp %%loop_x_h_overlap
+%else
+    jne %%loop_x_odd_v_overlap
+    jmp %%loop_x_odd
+%endif
+
+%%end:
+    RET
+
+%%vertical_overlap:
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, sby, fg_data, picptr, overlap
+%else
+    DEFINE_ARGS dst, src, stride, fg_data, w, scaling, grain_lut, tmp, sby, see, overlap
+%endif
+
+    or         overlapd, 2                  ; top_overlap: overlap & 2
+    mov             r8m, overlapd
+    movzx          sbyd, sbyb
+%if ARCH_X86_32
+    imul             r4, [fg_dataq+FGData.seed], 0x00010001
+    DEFINE_ARGS tmp, src, scaling, sby, see, picptr, unused
+%else
+    imul           seed, [fg_dataq+FGData.seed], 0x00010001
+%endif
+    imul           tmpd, sbyd, 173 * 0x00010001
+    imul           sbyd, 37 * 0x01000100
+    add            tmpd, (105 << 16) | 188
+    add            sbyd, (178 << 24) | (141 << 8)
+    and            tmpd, 0x00ff00ff
+    and            sbyd, 0xff00ff00
+    xor            seed, tmpd
+%if ARCH_X86_32
+    xor            sbyd, seed               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS luma, src, scaling, see, w, picptr, src_bak
+
+    mov             r3m, seed
+    mov              wq, r4m
+%if %3
+    shl           r10mp, 1
+%endif
+%else
+    xor            seed, sbyd               ; (cur_seed << 16) | top_seed
+
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                tmp, unused2, see, overlap, unused3, src_bak, lstride, luma_bak
+
+    mov        lstrideq, r10mp
+%endif
+
+    mov           lumaq, r9mp
+    lea        src_bakq, [srcq+wq]
+    lea       luma_bakq, [lumaq+wq*(1+%2)]
+    neg              wq
+    sub            r0mp, srcq
+%if ARCH_X86_32
+    mov             r1m, src_bakq
+    mov            r11m, luma_bakq
+    mov             r4m, wq
+
+    DEFINE_ARGS tmp, src, scaling, see, unused1, picptr, unused2
+%else
+    mov           r11mp, src_bakq
+    mov           r12mp, strideq
+%endif
+
+%%loop_x_v_overlap:
+%if ARCH_X86_32
+    mov            seed, r3m
+    xor            tmpd, tmpd
+%endif
+    ; we assume from the block above that bits 8-15 of tmpd are zero'ed
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp           tmpb                     ; parity of top_seed
+    shr            seed, 16
+    shl            tmpd, 16
+    test           seeb, seeh
+    setp           tmpb                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor            tmpd, r6d
+    mov            seed, tmpd
+    ror            seed, 1                  ; updated (cur_seed << 16) | top_seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS dst, src, scaling, offy, h, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, overlap, top_offxy, unused, lstride
+
+    mov           offxd, seed
+    mov           offyd, seed
+%endif
+    ror           offyd, 8
+    ror           offxd, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyq, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+%if ARCH_X86_32
+    DEFINE_ARGS tmp, src, scaling, offxy, h, picptr, top_offxy
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                h, offxy, see, overlap, top_offxy, unused, lstride, luma_bak
+%endif
+
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+%if ARCH_X86_32
+    mov [rsp+7*mmsize+1*gprsize], top_offxyd
+
+    DEFINE_ARGS luma, src, scaling, offxy, h, picptr, grain_lut
+%endif
+
+%%loop_x_odd_v_overlap:
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+%if %3
+    mova             m1, [PIC_ptr(pb_23_22)]
+%else
+    mova             m1, [PIC_ptr(pb_27_17)]
+%endif
+%%loop_y_v_overlap:
+%if ARCH_X86_32
+    mov           lumaq, r9mp
+%endif
+%if %2
+    mova             m4, [lumaq+ 0]
+    mova             m6, [lumaq+16]
+    mova             m0, [srcq]
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+    mov              r5, r5m
+    movd             m7, [base+pb_1]
+%else
+    movd             m7, [pb_1]
+%endif
+    pshufd           m7, m7, q0000
+    pxor             m2, m2
+    pmaddubsw        m4, m7
+    pmaddubsw        m6, m7
+    pavgw            m4, m2
+    pavgw            m6, m2
+%else
+    mova             m4, [lumaq]
+    mova             m0, [srcq]
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+%endif
+    pxor             m2, m2
+%endif
+
+%if %1
+%if %2
+    packuswb         m4, m6                 ; luma
+%endif
+    punpckhbw        m6, m4, m0
+    punpcklbw        m4, m0                 ; { luma, chroma }
+    pmaddubsw        m6, m14
+    pmaddubsw        m4, m14
+    psraw            m6, 6
+    psraw            m4, 6
+    paddw            m6, m15
+    paddw            m4, m15
+    packuswb         m4, m6                 ; pack+unpack = clip
+    punpckhbw        m6, m4, m2
+    punpcklbw        m4, m2
+%elif %2 == 0
+    punpckhbw        m6, m4, m2
+    punpcklbw        m4, m2
+%endif
+
+    ; scaling[luma_src]
+%if ARCH_X86_32
+    vpgatherdw       m7, m4, scalingq-1, r0, r5
+    vpgatherdw       m5, m6, scalingq-1, r0, r5
+%else
+    vpgatherdw       m7, m4, scalingq-1, r12, r2
+    vpgatherdw       m5, m6, scalingq-1, r12, r2
+%endif
+    REPX {psrlw x, 8}, m7, m5
+
+    ; grain = grain_lut[offy+y][offx+x]
+    movu             m3, [grain_lutq+offxyq]
+%if ARCH_X86_32
+    mov              r0, [rsp+7*mmsize+1*gprsize]
+    movu             m4, [grain_lutq+r0]
+%else
+    movu             m4, [grain_lutq+top_offxyq]
+%endif
+    punpckhbw        m6, m4, m3
+    punpcklbw        m4, m3
+    pmaddubsw        m2, m1, m6
+    pmaddubsw        m3, m1, m4
+    pmulhrsw         m2, m8
+    pmulhrsw         m3, m8
+    packsswb         m3, m2
+    pxor             m6, m6
+    pcmpgtb          m6, m3
+    punpcklbw        m2, m3, m6
+    punpckhbw        m3, m6
+
+    ; noise = round2(scaling[luma_src] * grain, scaling_shift)
+    pmullw           m2, m7
+    pmullw           m3, m5
+    pmulhrsw         m2, m11
+    pmulhrsw         m3, m11
+
+    ; unpack chroma_source
+    pxor             m4, m4
+    punpckhbw        m6, m0, m4
+    punpcklbw        m0, m4                 ; m0-1: src as word
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m6, m3
+    pmaxsw           m0, m13
+    pmaxsw           m6, m13
+    pminsw           m0, m12
+    pminsw           m6, m12
+    packuswb         m0, m6
+    movifnidn      dstq, dstmp
+    mova    [dstq+srcq], m0
+
+    dec              hw
+    je %%end_y_v_overlap
+%if ARCH_X86_32
+    add            srcq, r2mp
+    ; lumaq has already been incremented above
+%else
+    add            srcq, r12mp
+%if %3
+    lea           lumaq, [lumaq+lstrideq*2]
+%else
+    add           lumaq, lstrideq
+%endif
+%endif
+    add      grain_lutq, 82
+%if %3 == 0
+    btc              hd, 16
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    mova             m1, [PIC_ptr(pb_17_27)]
+    jnc %%loop_y_v_overlap
+%endif
+    jmp %%loop_y
+
+%%end_y_v_overlap:
+%if ARCH_X86_32
+    DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut
+
+    mov              wq, r4m
+%endif
+    add              wq, 16
+    jge %%end_hv
+%if ARCH_X86_32
+    mov            srcq, r1mp
+    mov           lumaq, r11mp
+%else
+    mov            srcq, r11mp
+%endif
+    lea           lumaq, [luma_bakq+wq*(1+%2)]
+    add            srcq, wq
+%if ARCH_X86_32
+    mov             r4m, wq
+    mov             r9m, lumaq
+%endif
+
+%if %2
+    ; since fg_dataq.overlap is guaranteed to be set, we never jump
+    ; back to .loop_x_v_overlap, and instead always fall-through to
+    ; h+v overlap
+%else
+%if ARCH_X86_32
+    add dword [rsp+7*mmsize+1*gprsize], 16
+%else
+    add      top_offxyd, 16
+%endif
+    add          offxyd, 16
+    btc       dword r8m, 2
+    jnc %%loop_x_odd_v_overlap
+%endif
+
+%%loop_x_hv_overlap:
+%if ARCH_X86_32
+    DEFINE_ARGS tmp, src, scaling, offxy, w, picptr, unused
+
+    mov              r6, [rsp+7*mmsize+1*gprsize]
+%if %2
+    lea              r0, [r3d+16]
+    add              r6, 16
+    mov [rsp+7*mmsize+0*gprsize], r0        ; left_offxy
+%else
+    mov [rsp+7*mmsize+0*gprsize], r3        ; left_offxy
+%endif
+    mov [rsp+7*mmsize+2*gprsize], r6        ; topleft_offxy
+
+    DEFINE_ARGS tmp, src, scaling, see, w, picptr, unused
+
+    mov            seed, r3m
+    xor            tmpd, tmpd
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                tmp, offxy, see, left_offxy, top_offxy, topleft_offxy, lstride
+
+%if %2
+    lea  topleft_offxyq, [top_offxyq+16]
+    lea     left_offxyq, [offxyq+16]
+%else
+    mov  topleft_offxyq, top_offxyq
+    mov     left_offxyq, offxyq
+%endif
+
+    ; we assume from the block above that bits 8-15 of tmpd are zero'ed
+%endif
+    mov             r6d, seed
+    or             seed, 0xeff4eff4
+    test           seeb, seeh
+    setp           tmpb                     ; parity of top_seed
+    shr            seed, 16
+    shl            tmpd, 16
+    test           seeb, seeh
+    setp           tmpb                     ; parity of cur_seed
+    or              r6d, 0x00010001
+    xor            tmpd, r6d
+    mov            seed, tmpd
+    ror            seed, 1                  ; updated (cur_seed << 16) | top_seed
+
+%if ARCH_X86_32
+    mov             r3m, seed
+
+    DEFINE_ARGS tmp, src, scaling, offy, w, picptr, offx
+
+    mov           offxd, offyd
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                offx, offy, see, left_offxy, top_offxy, topleft_offxy, lstride
+
+    mov           offxd, seed
+    mov           offyd, seed
+%endif
+    ror           offyd, 8
+    ror           offxd, 12
+    and           offyd, 0xf000f
+    and           offxd, 0xf000f
+    imul          offyd, 164>>%3
+    ; offxy=offy*stride+offx, (cur_offxy << 16) | top_offxy
+    lea           offyq, [offyq+offxq*(2-%2)+0x10001*((3+(6>>%3))*82+3+(6>>%2))+(32>>%3)*82]
+
+%if ARCH_X86_32
+    DEFINE_ARGS top_offxy, src, scaling, offxy, h, picptr, grain_lut
+%else
+    DEFINE_ARGS dst, src, stride, luma, w, scaling, grain_lut, \
+                h, offxy, see, left_offxy, top_offxy, topleft_offxy, lstride, luma_bak
+%endif
+
+    movzx    top_offxyd, offxyw
+    shr          offxyd, 16
+%if ARCH_X86_32
+    mov [rsp+7*mmsize+1*gprsize], top_offxyd
+%endif
+
+    mov              hd, r7m
+    mov      grain_lutq, grain_lutmp
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+%if %3
+    mova             m3, [PIC_ptr(pb_23_22)]
+%else
+    mova             m3, [PIC_ptr(pb_27_17)]
+%endif
+%%loop_y_hv_overlap:
+    ; grain = grain_lut[offy+y][offx+x]
+%if ARCH_X86_32
+    mov              r0, [rsp+7*mmsize+2*gprsize]       ; topleft_offxy
+    mov              r5, [rsp+7*mmsize+1*gprsize]       ; top_offxy
+    movd             m1, [grain_lutq+r0]
+    mov              r0, [rsp+7*mmsize+0*gprsize]       ; left_offxy
+%else
+    movd             m1, [grain_lutq+topleft_offxyq]
+%endif
+    movu             m2, [grain_lutq+offxyq]
+%if ARCH_X86_32
+    movu             m6, [grain_lutq+r5]
+    movd             m4, [grain_lutq+r0]
+%else
+    movu             m6, [grain_lutq+top_offxyq]
+    movd             m4, [grain_lutq+left_offxyq]
+%endif
+    ; do h interpolation first (so top | top/left -> top, left | cur -> cur)
+    punpcklbw        m1, m6
+    punpcklbw        m4, m2
+    pmaddubsw        m0, m9, m1
+    pmaddubsw        m1, m9, m4
+    REPX {pmulhrsw x, m8}, m0, m1
+    packsswb         m0, m1
+    shufps           m4, m0, m2, q3232
+    shufps           m0, m6, q3210
+    ; followed by v interpolation (top | cur -> cur)
+    punpcklbw        m2, m0, m4
+    punpckhbw        m0, m4
+    pmaddubsw        m4, m3, m0
+    pmaddubsw        m1, m3, m2
+    pmulhrsw         m4, m8
+    pmulhrsw         m1, m8
+    packsswb         m1, m4
+
+    ; src
+%if ARCH_X86_32
+    DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut
+
+    mov           lumaq, r9mp
+%endif
+%if %2
+    mova             m4, [lumaq+ 0]
+    mova             m6, [lumaq+16]
+    mova             m0, [srcq]
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+    mov              r5, r5m
+    movd             m7, [base+pb_1]
+%else
+    movd             m7, [pb_1]
+%endif
+    pshufd           m7, m7, q0000
+    pxor             m2, m2
+    pmaddubsw        m4, m7
+    pmaddubsw        m6, m7
+    pavgw            m4, m2
+    pavgw            m6, m2
+%else
+    mova             m4, [lumaq]
+    mova             m0, [srcq]
+%if ARCH_X86_32
+    add           lumaq, r10mp
+    mov            r9mp, lumaq
+%endif
+    pxor             m2, m2
+%endif
+
+%if %1
+%if %2
+    packuswb         m4, m6                 ; luma
+%endif
+    punpckhbw        m6, m4, m0
+    punpcklbw        m4, m0                 ; { luma, chroma }
+    pmaddubsw        m6, m14
+    pmaddubsw        m4, m14
+    psraw            m6, 6
+    psraw            m4, 6
+    paddw            m6, m15
+    paddw            m4, m15
+    packuswb         m4, m6                 ; pack+unpack = clip
+    punpckhbw        m6, m4, m2
+    punpcklbw        m4, m2
+%elif %2 == 0
+    punpckhbw        m6, m4, m2
+    punpcklbw        m4, m2
+%endif
+
+    ; scaling[src]
+%if ARCH_X86_32
+    vpgatherdw       m7, m4, scalingq-1, r0, r5
+    vpgatherdw       m5, m6, scalingq-1, r0, r5
+%else
+%if %3
+    vpgatherdw       m7, m4, scalingq-1, r2, r12
+    vpgatherdw       m5, m6, scalingq-1, r2, r12
+%else
+    vpgatherdw       m7, m4, scalingq-1, r2, r13
+    vpgatherdw       m5, m6, scalingq-1, r2, r13
+%endif
+%endif
+    REPX {psrlw x, 8}, m7, m5
+
+    ; unpack grain
+    pxor             m4, m4
+    pcmpgtb          m4, m1
+    punpcklbw        m2, m1, m4
+    punpckhbw        m1, m4
+
+    ; noise = round2(scaling[src] * grain, scaling_shift)
+    pmullw           m2, m7
+    pmullw           m1, m5
+    pmulhrsw         m2, m11
+    pmulhrsw         m1, m11
+
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, scaling, offxy, h, picptr, grain_lut
+%endif
+
+    ; unpack chroma source
+    pxor             m4, m4
+    punpckhbw        m5, m0, m4
+    punpcklbw        m0, m4                 ; m0-1: src as word
+
+    ; dst = clip_pixel(src, noise)
+    paddw            m0, m2
+    paddw            m5, m1
+    pmaxsw           m0, m13
+    pmaxsw           m5, m13
+    pminsw           m0, m12
+    pminsw           m5, m12
+    packuswb         m0, m5
+    movifnidn      dstq, dstmp
+    mova    [dstq+srcq], m0
+
+%if ARCH_X86_32
+    add            srcq, r2mp
+    ; lumaq has been adjusted above already
+%else
+    add            srcq, r12mp
+%if %3
+    lea           lumaq, [lumaq+lstrideq*(1+%2)]
+%else
+    add           lumaq, r10mp
+%endif
+%endif
+    add      grain_lutq, 82
+    dec              hw
+%if %3
+    jg %%loop_y_h_overlap
+%else
+    jle %%end_y_hv_overlap
+%if ARCH_X86_32
+    mov              r5, r5m
+%endif
+    mova             m3, [PIC_ptr(pb_17_27)]
+    btc              hd, 16
+    jnc %%loop_y_hv_overlap
+%if ARCH_X86_64
+    mov        lstrideq, r10mp
+%endif
+    jmp %%loop_y_h_overlap
+%%end_y_hv_overlap:
+%if ARCH_X86_64
+    mov        lstrideq, r10mp
+%endif
+%endif
+
+%if ARCH_X86_32
+    DEFINE_ARGS luma, src, scaling, offxy, w, picptr, grain_lut
+
+    mov              wq, r4m
+%endif
+    add              wq, 16
+    jge %%end_hv
+%if ARCH_X86_32
+    mov            srcq, r1mp
+    mov           lumaq, r11mp
+%else
+    mov            srcq, r11mp
+%endif
+    lea           lumaq, [luma_bakq+wq*(1+%2)]
+    add            srcq, wq
+%if ARCH_X86_32
+    mov             r4m, wq
+    mov             r9m, lumaq
+%endif
+%if %2
+    jmp %%loop_x_hv_overlap
+%else
+%if ARCH_X86_32
+    add dword [rsp+7*mmsize+1*gprsize], 16
+%else
+    add      top_offxyd, 16
+%endif
+    add          offxyd, 16
+    xor       dword r8m, 4
+    jmp %%loop_x_odd_v_overlap
+%endif
+
+%%end_hv:
+    RET
+%endmacro
+
+    %%FGUV_32x32xN_LOOP 1, %2, %3
+.csfl:
+    %%FGUV_32x32xN_LOOP 0, %2, %3
+%endmacro
+
+FGUV_FN 420, 1, 1
+
+%if STACK_ALIGNMENT < mmsize
+DECLARE_ARG 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+%endif
+
+FGUV_FN 422, 1, 0
+
+%if STACK_ALIGNMENT < mmsize
+DECLARE_ARG 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+%endif
+
+FGUV_FN 444, 0, 0
diff --git a/media/libdav1d/src/src/x86/ipred.h b/media/libdav1d/src/src/x86/ipred.h
new file mode 100644
index 0000000000..57aff0f38c
--- /dev/null
+++ b/media/libdav1d/src/src/x86/ipred.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/ipred.h"
+
+#define decl_fn(type, name) \
+    decl_##type##_fn(BF(dav1d_##name, ssse3)); \
+    decl_##type##_fn(BF(dav1d_##name, avx2)); \
+    decl_##type##_fn(BF(dav1d_##name, avx512icl))
+#define init_fn(type0, type1, name, suffix) \
+    c->type0[type1] = BF(dav1d_##name, suffix)
+
+#define init_angular_ipred_fn(type, name, suffix) \
+    init_fn(intra_pred, type, name, suffix)
+#define init_cfl_pred_fn(type, name, suffix) \
+    init_fn(cfl_pred, type, name, suffix)
+#define init_cfl_ac_fn(type, name, suffix) \
+    init_fn(cfl_ac, type, name, suffix)
+
+decl_fn(angular_ipred, ipred_dc);
+decl_fn(angular_ipred, ipred_dc_128);
+decl_fn(angular_ipred, ipred_dc_top);
+decl_fn(angular_ipred, ipred_dc_left);
+decl_fn(angular_ipred, ipred_h);
+decl_fn(angular_ipred, ipred_v);
+decl_fn(angular_ipred, ipred_paeth);
+decl_fn(angular_ipred, ipred_smooth);
+decl_fn(angular_ipred, ipred_smooth_h);
+decl_fn(angular_ipred, ipred_smooth_v);
+decl_fn(angular_ipred, ipred_z1);
+decl_fn(angular_ipred, ipred_z2);
+decl_fn(angular_ipred, ipred_z3);
+decl_fn(angular_ipred, ipred_filter);
+
+decl_fn(cfl_pred, ipred_cfl);
+decl_fn(cfl_pred, ipred_cfl_128);
+decl_fn(cfl_pred, ipred_cfl_top);
+decl_fn(cfl_pred, ipred_cfl_left);
+
+decl_fn(cfl_ac, ipred_cfl_ac_420);
+decl_fn(cfl_ac, ipred_cfl_ac_422);
+decl_fn(cfl_ac, ipred_cfl_ac_444);
+
+decl_fn(pal_pred, pal_pred);
+
+static ALWAYS_INLINE void intra_pred_dsp_init_x86(Dav1dIntraPredDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSSE3)) return;
+
+    init_angular_ipred_fn(DC_PRED,       ipred_dc,       ssse3);
+    init_angular_ipred_fn(DC_128_PRED,   ipred_dc_128,   ssse3);
+    init_angular_ipred_fn(TOP_DC_PRED,   ipred_dc_top,   ssse3);
+    init_angular_ipred_fn(LEFT_DC_PRED,  ipred_dc_left,  ssse3);
+    init_angular_ipred_fn(HOR_PRED,      ipred_h,        ssse3);
+    init_angular_ipred_fn(VERT_PRED,     ipred_v,        ssse3);
+    init_angular_ipred_fn(PAETH_PRED,    ipred_paeth,    ssse3);
+    init_angular_ipred_fn(SMOOTH_PRED,   ipred_smooth,   ssse3);
+    init_angular_ipred_fn(SMOOTH_H_PRED, ipred_smooth_h, ssse3);
+    init_angular_ipred_fn(SMOOTH_V_PRED, ipred_smooth_v, ssse3);
+    init_angular_ipred_fn(Z1_PRED,       ipred_z1,       ssse3);
+    init_angular_ipred_fn(Z2_PRED,       ipred_z2,       ssse3);
+    init_angular_ipred_fn(Z3_PRED,       ipred_z3,       ssse3);
+    init_angular_ipred_fn(FILTER_PRED,   ipred_filter,   ssse3);
+
+    init_cfl_pred_fn(DC_PRED,      ipred_cfl,      ssse3);
+    init_cfl_pred_fn(DC_128_PRED,  ipred_cfl_128,  ssse3);
+    init_cfl_pred_fn(TOP_DC_PRED,  ipred_cfl_top,  ssse3);
+    init_cfl_pred_fn(LEFT_DC_PRED, ipred_cfl_left, ssse3);
+
+    init_cfl_ac_fn(DAV1D_PIXEL_LAYOUT_I420 - 1, ipred_cfl_ac_420, ssse3);
+    init_cfl_ac_fn(DAV1D_PIXEL_LAYOUT_I422 - 1, ipred_cfl_ac_422, ssse3);
+    init_cfl_ac_fn(DAV1D_PIXEL_LAYOUT_I444 - 1, ipred_cfl_ac_444, ssse3);
+
+    c->pal_pred = BF(dav1d_pal_pred, ssse3);
+
+#if ARCH_X86_64
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2)) return;
+
+    init_angular_ipred_fn(DC_PRED,       ipred_dc,       avx2);
+    init_angular_ipred_fn(DC_128_PRED,   ipred_dc_128,   avx2);
+    init_angular_ipred_fn(TOP_DC_PRED,   ipred_dc_top,   avx2);
+    init_angular_ipred_fn(LEFT_DC_PRED,  ipred_dc_left,  avx2);
+    init_angular_ipred_fn(HOR_PRED,      ipred_h,        avx2);
+    init_angular_ipred_fn(VERT_PRED,     ipred_v,        avx2);
+    init_angular_ipred_fn(PAETH_PRED,    ipred_paeth,    avx2);
+    init_angular_ipred_fn(SMOOTH_PRED,   ipred_smooth,   avx2);
+    init_angular_ipred_fn(SMOOTH_H_PRED, ipred_smooth_h, avx2);
+    init_angular_ipred_fn(SMOOTH_V_PRED, ipred_smooth_v, avx2);
+    init_angular_ipred_fn(Z1_PRED,       ipred_z1,       avx2);
+    init_angular_ipred_fn(Z2_PRED,       ipred_z2,       avx2);
+    init_angular_ipred_fn(Z3_PRED,       ipred_z3,       avx2);
+    init_angular_ipred_fn(FILTER_PRED,   ipred_filter,   avx2);
+
+    init_cfl_pred_fn(DC_PRED,      ipred_cfl,      avx2);
+    init_cfl_pred_fn(DC_128_PRED,  ipred_cfl_128,  avx2);
+    init_cfl_pred_fn(TOP_DC_PRED,  ipred_cfl_top,  avx2);
+    init_cfl_pred_fn(LEFT_DC_PRED, ipred_cfl_left, avx2);
+
+    init_cfl_ac_fn(DAV1D_PIXEL_LAYOUT_I420 - 1, ipred_cfl_ac_420, avx2);
+    init_cfl_ac_fn(DAV1D_PIXEL_LAYOUT_I422 - 1, ipred_cfl_ac_422, avx2);
+    init_cfl_ac_fn(DAV1D_PIXEL_LAYOUT_I444 - 1, ipred_cfl_ac_444, avx2);
+
+    c->pal_pred = BF(dav1d_pal_pred, avx2);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL)) return;
+
+#if BITDEPTH == 8
+    init_angular_ipred_fn(DC_PRED,       ipred_dc,       avx512icl);
+    init_angular_ipred_fn(DC_128_PRED,   ipred_dc_128,   avx512icl);
+    init_angular_ipred_fn(TOP_DC_PRED,   ipred_dc_top,   avx512icl);
+    init_angular_ipred_fn(LEFT_DC_PRED,  ipred_dc_left,  avx512icl);
+    init_angular_ipred_fn(HOR_PRED,      ipred_h,        avx512icl);
+    init_angular_ipred_fn(VERT_PRED,     ipred_v,        avx512icl);
+    init_angular_ipred_fn(Z2_PRED,       ipred_z2,       avx512icl);
+#endif
+    init_angular_ipred_fn(PAETH_PRED,    ipred_paeth,    avx512icl);
+    init_angular_ipred_fn(SMOOTH_PRED,   ipred_smooth,   avx512icl);
+    init_angular_ipred_fn(SMOOTH_H_PRED, ipred_smooth_h, avx512icl);
+    init_angular_ipred_fn(SMOOTH_V_PRED, ipred_smooth_v, avx512icl);
+    init_angular_ipred_fn(Z1_PRED,       ipred_z1,       avx512icl);
+    init_angular_ipred_fn(Z2_PRED,       ipred_z2,       avx512icl);
+    init_angular_ipred_fn(Z3_PRED,       ipred_z3,       avx512icl);
+    init_angular_ipred_fn(FILTER_PRED,   ipred_filter,   avx512icl);
+
+    c->pal_pred = BF(dav1d_pal_pred, avx512icl);
+#endif
+}
diff --git a/media/libdav1d/src/src/x86/ipred16_avx2.asm b/media/libdav1d/src/src/x86/ipred16_avx2.asm
new file mode 100644
index 0000000000..7b52abaa10
--- /dev/null
+++ b/media/libdav1d/src/src/x86/ipred16_avx2.asm
@@ -0,0 +1,4987 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 64
+
+%macro SMOOTH_WEIGHTS 1-*
+const smooth_weights_1d_16bpc ; sm_weights[] << 7
+    %rep %0
+        dw %1*128
+        %rotate 1
+    %endrep
+const smooth_weights_2d_16bpc ; sm_weights[], 256 - sm_weights[]
+    %rep %0
+        dw %1, 256-%1
+        %rotate 1
+    %endrep
+%endmacro
+
+SMOOTH_WEIGHTS   0,   0, 255, 128, 255, 149,  85,  64, \
+               255, 197, 146, 105,  73,  50,  37,  32, \
+               255, 225, 196, 170, 145, 123, 102,  84, \
+                68,  54,  43,  33,  26,  20,  17,  16, \
+               255, 240, 225, 210, 196, 182, 169, 157, \
+               145, 133, 122, 111, 101,  92,  83,  74, \
+                66,  59,  52,  45,  39,  34,  29,  25, \
+                21,  17,  14,  12,  10,   9,   8,   8, \
+               255, 248, 240, 233, 225, 218, 210, 203, \
+               196, 189, 182, 176, 169, 163, 156, 150, \
+               144, 138, 133, 127, 121, 116, 111, 106, \
+               101,  96,  91,  86,  82,  77,  73,  69, \
+                65,  61,  57,  54,  50,  47,  44,  41, \
+                38,  35,  32,  29,  27,  25,  22,  20, \
+                18,  16,  15,  13,  12,  10,   9,   8, \
+                 7,   6,   6,   5,   5,   4,   4,   4
+
+%if ARCH_X86_64
+
+ipred_hv_shuf: db  6,  7,  6,  7,  0,  1,  2,  3,  2,  3,  2,  3,  8,  9, 10, 11
+               db  4,  5,  4,  5,  4,  5,  6,  7,  0,  1,  0,  1, 12, 13, 14, 15
+filter_shuf1:  db  8,  9,  0,  1,  2,  3,  4,  5,  6,  7, 14, 15, 12, 13, -1, -1
+filter_shuf2:  db  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,  4,  5,  2,  3, -1, -1
+filter_shuf3:  db 12, 13,  0,  1,  2,  3,  4,  5,  6,  7, 10, 11,  8,  9, -1, -1
+pal_pred_shuf: db  0,  2,  4,  6,  8, 10, 12, 14,  1,  3,  5,  7,  9, 11, 13, 15
+z_base_inc:    dw   0*64,   1*64,   2*64,   3*64,   4*64,   5*64,   6*64,   7*64
+               dw   8*64,   9*64,  10*64,  11*64,  12*64,  13*64,  14*64,  15*64
+z_filter_t0:   db 55,127, 39,127, 39,127,  7, 15, 31,  7, 15, 31,  0,  3, 31,  0
+z_filter_t1:   db 39, 63, 19, 47, 19, 47,  3,  3,  3,  3,  3,  3,  0,  0,  0,  0
+z_filter_wh:   db  7,  7, 11, 11, 15, 15, 19, 19, 19, 23, 23, 23, 31, 31, 31, 39
+               db 39, 39, 47, 47, 47, 63, 63, 63, 79, 79, 79, -1
+pw_m1024:      times 2 dw -1024
+pw_1to16:      dw  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16
+pw_16to1:      dw 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1
+z2_ymul:       dw  1,  2,  1,  2,  1,  2,  1,  2,  3,  4,  3,  4,  3,  4,  3,  4
+z2_ymul8:      dw  1,  2,  5,  6,  3,  4,  7,  8,  5,  6, 16, 16,  7,  8
+pb_90:         times 4 db 90
+z2_y_shuf_h4:  dd  3,  7,  2,  6,  1,  5,  0,  4
+z_upsample:    db  0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+z2_x_shuf:     db  0,  1,  2,  3,  4,  5,  6,  7,  2,  3,  4,  5,  6,  7,  8,  9
+z2_y_shuf:     db  6,  7, 14, 15,  4,  5, 12, 13,  4,  5, 12, 13,  2,  3, 10, 11
+z2_y_shuf_us:  db  6,  7, 14, 15,  2,  3, 10, 11,  4,  5, 12, 13,  0,  1,  8,  9
+z_filter_k:    dw  4,  4,  5,  5,  4,  4
+               dw  8,  8,  6,  6,  4,  4
+               dw  0,  0,  0,  0,  2,  2
+
+%define pw_2  (z_filter_k+32)
+%define pw_4  (z_filter_k+ 0)
+%define pw_16 (z2_ymul8  +20)
+
+pw_1:    times 2 dw 1
+pw_3:    times 2 dw 3
+pw_62:   times 2 dw 62
+pw_512:  times 2 dw 512
+pw_2048: times 2 dw 2048
+pd_8:    dd 8
+
+%macro JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - 2*4)
+    %xdefine %%base mangle(private_prefix %+ _%1_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%base %+ .%3 - (%%table - 2*4)
+        %rotate 1
+    %endrep
+%endmacro
+
+%define ipred_dc_splat_16bpc_avx2_table (ipred_dc_16bpc_avx2_table + 10*4)
+%define ipred_cfl_splat_16bpc_avx2_table (ipred_cfl_16bpc_avx2_table + 8*4)
+
+JMP_TABLE ipred_dc_16bpc,         avx2, h4, h8, h16, h32, h64, w4, w8, w16, w32, w64, \
+                                        s4-10*4, s8-10*4, s16-10*4, s32-10*4, s64-10*4
+JMP_TABLE ipred_dc_left_16bpc,    avx2, h4, h8, h16, h32, h64
+JMP_TABLE ipred_h_16bpc,          avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_paeth_16bpc,      avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_16bpc,     avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_h_16bpc,   avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_v_16bpc,   avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z1_16bpc,         avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z2_16bpc,         avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z3_16bpc,         avx2, h4, h8, h16, h32, h64
+JMP_TABLE ipred_filter_16bpc,     avx2, w4, w8, w16, w32
+JMP_TABLE ipred_cfl_16bpc,        avx2, h4, h8, h16, h32, w4, w8, w16, w32, \
+                                        s4-8*4, s8-8*4, s16-8*4, s32-8*4
+JMP_TABLE ipred_cfl_left_16bpc,   avx2, h4, h8, h16, h32
+JMP_TABLE ipred_cfl_ac_444_16bpc, avx2, w4, w8, w16, w32
+JMP_TABLE pal_pred_16bpc,         avx2, w4, w8, w16, w32, w64
+
+cextern dr_intra_derivative
+cextern filter_intra_taps
+
+SECTION .text
+
+INIT_YMM avx2
+cglobal ipred_dc_top_16bpc, 3, 7, 6, dst, stride, tl, w, h
+    movifnidn            hd, hm
+    add                 tlq, 2
+    movd                xm4, wd
+    pxor                xm3, xm3
+    pavgw               xm4, xm3
+    tzcnt                wd, wd
+    movd                xm5, wd
+    movu                 m0, [tlq]
+    lea                  r5, [ipred_dc_left_16bpc_avx2_table]
+    movsxd               r6, [r5+wq*4]
+    add                  r6, r5
+    add                  r5, ipred_dc_splat_16bpc_avx2_table-ipred_dc_left_16bpc_avx2_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+
+cglobal ipred_dc_left_16bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    mov                  hd, hm
+    sub                 tlq, hq
+    movd                xm4, hd
+    sub                 tlq, hq
+    pxor                xm3, xm3
+    pavgw               xm4, xm3
+    tzcnt               r6d, hd
+    movd                xm5, r6d
+    movu                 m0, [tlq]
+    lea                  r5, [ipred_dc_left_16bpc_avx2_table]
+    movsxd               r6, [r5+r6*4]
+    add                  r6, r5
+    add                  r5, ipred_dc_splat_16bpc_avx2_table-ipred_dc_left_16bpc_avx2_table
+    tzcnt                wd, wd
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+.h64:
+    paddw                m0, [tlq+96]
+    paddw                m0, [tlq+64]
+.h32:
+    paddw                m0, [tlq+32]
+.h16:
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm1
+.h8:
+    psrldq              xm1, xm0, 8
+    paddw               xm0, xm1
+.h4:
+    punpcklwd           xm0, xm3
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    paddd               xm0, xm4
+    psrld               xm0, xm5
+    lea            stride3q, [strideq*3]
+    vpbroadcastw         m0, xm0
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+    jmp                  wq
+
+cglobal ipred_dc_16bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    movifnidn            hd, hm
+    tzcnt               r6d, hd
+    lea                 r5d, [wq+hq]
+    movd                xm4, r5d
+    tzcnt               r5d, r5d
+    movd                xm5, r5d
+    lea                  r5, [ipred_dc_16bpc_avx2_table]
+    tzcnt                wd, wd
+    movsxd               r6, [r5+r6*4]
+    movsxd               wq, [r5+wq*4+5*4]
+    pxor                 m3, m3
+    psrlw               xm4, 1
+    add                  r6, r5
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  r6
+.h4:
+    movq                xm0, [tlq-8]
+    jmp                  wq
+.w4:
+    movq                xm1, [tlq+2]
+    paddw                m0, m4
+    paddw                m0, m1
+    psrlq                m1, m0, 32
+    paddw                m0, m1
+    psrld                m1, m0, 16
+    paddw                m0, m1
+    cmp                  hd, 4
+    jg .w4_mul
+    psrlw               xm0, 3
+    jmp .w4_end
+.w4_mul:
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm1
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0xAAAB6667
+    shrx                r6d, r6d, r2d
+    punpckhwd           xm1, xm0, xm3
+    punpcklwd           xm0, xm3
+    paddd               xm0, xm1
+    movd                xm1, r6d
+    psrld               xm0, 2
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w4_end:
+    vpbroadcastw        xm0, xm0
+.s4:
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm0
+    movq   [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s4
+    RET
+ALIGN function_align
+.h8:
+    mova                xm0, [tlq-16]
+    jmp                  wq
+.w8:
+    vextracti128        xm1, m0, 1
+    paddw               xm0, [tlq+2]
+    paddw               xm0, xm4
+    paddw               xm0, xm1
+    psrld               xm1, xm0, 16
+    paddw               xm0, xm1
+    pblendw             xm0, xm3, 0xAA
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    psrld               xm0, xm5
+    cmp                  hd, 8
+    je .w8_end
+    mov                 r6d, 0xAAAB
+    mov                 r2d, 0x6667
+    cmp                  hd, 32
+    cmovz               r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w8_end:
+    vpbroadcastw        xm0, xm0
+.s8:
+    mova   [dstq+strideq*0], xm0
+    mova   [dstq+strideq*1], xm0
+    mova   [dstq+strideq*2], xm0
+    mova   [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s8
+    RET
+ALIGN function_align
+.h16:
+    mova                 m0, [tlq-32]
+    jmp                  wq
+.w16:
+    paddw                m0, [tlq+2]
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm4
+    paddw               xm0, xm1
+    punpckhwd           xm1, xm0, xm3
+    punpcklwd           xm0, xm3
+    paddd               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    psrld               xm0, xm5
+    cmp                  hd, 16
+    je .w16_end
+    mov                 r6d, 0xAAAB
+    mov                 r2d, 0x6667
+    test                 hb, 8|32
+    cmovz               r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w16_end:
+    vpbroadcastw         m0, xm0
+.s16:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m0
+    mova   [dstq+strideq*2], m0
+    mova   [dstq+stride3q ], m0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s16
+    RET
+ALIGN function_align
+.h32:
+    mova                 m0, [tlq-64]
+    paddw                m0, [tlq-32]
+    jmp                  wq
+.w32:
+    paddw                m0, [tlq+ 2]
+    paddw                m0, [tlq+34]
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm4
+    paddw               xm0, xm1
+    punpcklwd           xm1, xm0, xm3
+    punpckhwd           xm0, xm3
+    paddd               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    psrld               xm0, xm5
+    cmp                  hd, 32
+    je .w32_end
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x6667AAAB
+    shrx                r6d, r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w32_end:
+    vpbroadcastw         m0, xm0
+    mova                 m1, m0
+.s32:
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*1+32*0], m0
+    mova [dstq+strideq*1+32*1], m1
+    mova [dstq+strideq*2+32*0], m0
+    mova [dstq+strideq*2+32*1], m1
+    mova [dstq+stride3q +32*0], m0
+    mova [dstq+stride3q +32*1], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s32
+    RET
+ALIGN function_align
+.h64:
+    mova                 m0, [tlq-128]
+    mova                 m1, [tlq- 96]
+    paddw                m0, [tlq- 64]
+    paddw                m1, [tlq- 32]
+    paddw                m0, m1
+    jmp                  wq
+.w64:
+    movu                 m1, [tlq+ 2]
+    paddw                m0, [tlq+34]
+    paddw                m1, [tlq+66]
+    paddw                m0, [tlq+98]
+    paddw                m0, m1
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm1
+    punpcklwd           xm1, xm0, xm3
+    punpckhwd           xm0, xm3
+    paddd               xm1, xm4
+    paddd               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    psrld               xm0, xm5
+    cmp                  hd, 64
+    je .w64_end
+    mov                 r6d, 0x6667AAAB
+    shrx                r6d, r6d, hd
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w64_end:
+    vpbroadcastw         m0, xm0
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+.s64:
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*0+32*2], m2
+    mova [dstq+strideq*0+32*3], m3
+    mova [dstq+strideq*1+32*0], m0
+    mova [dstq+strideq*1+32*1], m1
+    mova [dstq+strideq*1+32*2], m2
+    mova [dstq+strideq*1+32*3], m3
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .s64
+    RET
+
+cglobal ipred_dc_128_16bpc, 2, 7, 6, dst, stride, tl, w, h, stride3
+    mov                 r6d, r8m
+    shr                 r6d, 11
+    lea                  r5, [ipred_dc_splat_16bpc_avx2_table]
+    tzcnt                wd, wd
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    vpbroadcastd         m0, [r5-ipred_dc_splat_16bpc_avx2_table+pw_512+r6*4]
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+cglobal ipred_v_16bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    movifnidn            hd, hm
+    movu                 m0, [tlq+ 2]
+    movu                 m1, [tlq+34]
+    movu                 m2, [tlq+66]
+    movu                 m3, [tlq+98]
+    lea                  r5, [ipred_dc_splat_16bpc_avx2_table]
+    tzcnt                wd, wd
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+%macro IPRED_H 2 ; w, store_type
+    vpbroadcastw         m0, [tlq-2]
+    vpbroadcastw         m1, [tlq-4]
+    vpbroadcastw         m2, [tlq-6]
+    vpbroadcastw         m3, [tlq-8]
+    sub                 tlq, 8
+    mov%2  [dstq+strideq*0], m0
+    mov%2  [dstq+strideq*1], m1
+    mov%2  [dstq+strideq*2], m2
+    mov%2  [dstq+stride3q ], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w%1
+    RET
+ALIGN function_align
+%endmacro
+
+cglobal ipred_h_16bpc, 3, 6, 4, dst, stride, tl, w, h, stride3
+    movifnidn            hd, hm
+    lea                  r5, [ipred_h_16bpc_avx2_table]
+    tzcnt                wd, wd
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+INIT_XMM avx2
+.w4:
+    IPRED_H               4, q
+.w8:
+    IPRED_H               8, a
+INIT_YMM avx2
+.w16:
+    IPRED_H              16, a
+.w32:
+    vpbroadcastw         m0, [tlq-2]
+    vpbroadcastw         m1, [tlq-4]
+    vpbroadcastw         m2, [tlq-6]
+    vpbroadcastw         m3, [tlq-8]
+    sub                 tlq, 8
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m0
+    mova [dstq+strideq*1+32*0], m1
+    mova [dstq+strideq*1+32*1], m1
+    mova [dstq+strideq*2+32*0], m2
+    mova [dstq+strideq*2+32*1], m2
+    mova [dstq+stride3q +32*0], m3
+    mova [dstq+stride3q +32*1], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w32
+    RET
+.w64:
+    vpbroadcastw         m0, [tlq-2]
+    vpbroadcastw         m1, [tlq-4]
+    sub                 tlq, 4
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m0
+    mova [dstq+strideq*0+32*2], m0
+    mova [dstq+strideq*0+32*3], m0
+    mova [dstq+strideq*1+32*0], m1
+    mova [dstq+strideq*1+32*1], m1
+    mova [dstq+strideq*1+32*2], m1
+    mova [dstq+strideq*1+32*3], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w64
+    RET
+
+%macro PAETH 3 ; top, signed_ldiff, ldiff
+    paddw               m0, m%2, m1
+    psubw               m7, m3, m0  ; tldiff
+    psubw               m0, m%1     ; tdiff
+    pabsw               m7, m7
+    pabsw               m0, m0
+    pminsw              m7, m0
+    pcmpeqw             m0, m7
+    pcmpgtw             m7, m%3, m7
+    vpblendvb           m0, m3, m%1, m0
+    vpblendvb           m0, m1, m0, m7
+%endmacro
+
+cglobal ipred_paeth_16bpc, 3, 6, 8, dst, stride, tl, w, h
+%define base r5-ipred_paeth_16bpc_avx2_table
+    movifnidn           hd, hm
+    lea                 r5, [ipred_paeth_16bpc_avx2_table]
+    tzcnt               wd, wd
+    movsxd              wq, [r5+wq*4]
+    vpbroadcastw        m3, [tlq]   ; topleft
+    add                 wq, r5
+    jmp                 wq
+.w4:
+    vpbroadcastq        m2, [tlq+2] ; top
+    movsldup            m6, [base+ipred_hv_shuf]
+    lea                 r3, [strideq*3]
+    psubw               m4, m2, m3
+    pabsw               m5, m4
+.w4_loop:
+    sub                tlq, 8
+    vpbroadcastq        m1, [tlq]
+    pshufb              m1, m6      ; left
+    PAETH                2, 4, 5
+    vextracti128       xm1, m0, 1
+    movq  [dstq+strideq*0], xm0
+    movq  [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r3       ], xm1
+    lea               dstq, [dstq+strideq*4]
+    sub                 hd, 4
+    jg .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    vbroadcasti128      m2, [tlq+2]
+    movsldup            m6, [base+ipred_hv_shuf]
+    psubw               m4, m2, m3
+    pabsw               m5, m4
+.w8_loop:
+    sub                tlq, 4
+    vpbroadcastd        m1, [tlq]
+    pshufb              m1, m6
+    PAETH                2, 4, 5
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea               dstq, [dstq+strideq*2]
+    sub                 hd, 2
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    movu                m2, [tlq+2]
+    psubw               m4, m2, m3
+    pabsw               m5, m4
+.w16_loop:
+    sub                tlq, 2
+    vpbroadcastw        m1, [tlq]
+    PAETH                2, 4, 5
+    mova            [dstq], m0
+    add               dstq, strideq
+    dec                 hd
+    jg .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    movu                m2, [tlq+2]
+    movu                m6, [tlq+34]
+%if WIN64
+    movaps             r4m, xmm8
+    movaps             r6m, xmm9
+%endif
+    psubw               m4, m2, m3
+    psubw               m8, m6, m3
+    pabsw               m5, m4
+    pabsw               m9, m8
+.w32_loop:
+    sub                tlq, 2
+    vpbroadcastw        m1, [tlq]
+    PAETH                2, 4, 5
+    mova       [dstq+32*0], m0
+    PAETH                6, 8, 9
+    mova       [dstq+32*1], m0
+    add               dstq, strideq
+    dec                 hd
+    jg .w32_loop
+%if WIN64
+    movaps            xmm8, r4m
+    movaps            xmm9, r6m
+%endif
+    RET
+ALIGN function_align
+.w64:
+    WIN64_SPILL_XMM 16
+    movu                m2, [tlq+ 2]
+    movu                m6, [tlq+34]
+    movu               m10, [tlq+66]
+    movu               m13, [tlq+98]
+    psubw               m4, m2, m3
+    psubw               m8, m6, m3
+    psubw              m11, m10, m3
+    psubw              m14, m13, m3
+    pabsw               m5, m4
+    pabsw               m9, m8
+    pabsw              m12, m11
+    pabsw              m15, m14
+.w64_loop:
+    sub                tlq, 2
+    vpbroadcastw        m1, [tlq]
+    PAETH                2, 4, 5
+    mova       [dstq+32*0], m0
+    PAETH                6, 8, 9
+    mova       [dstq+32*1], m0
+    PAETH               10, 11, 12
+    mova       [dstq+32*2], m0
+    PAETH               13, 14, 15
+    mova       [dstq+32*3], m0
+    add               dstq, strideq
+    dec                 hd
+    jg .w64_loop
+    RET
+
+cglobal ipred_smooth_v_16bpc, 3, 7, 6, dst, stride, tl, w, h, weights
+%define base r6-ipred_smooth_v_16bpc_avx2_table
+    lea                  r6, [ipred_smooth_v_16bpc_avx2_table]
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    lea            weightsq, [base+smooth_weights_1d_16bpc+hq*4]
+    neg                  hq
+    vpbroadcastw         m5, [tlq+hq*2] ; bottom
+    add                  wq, r6
+    jmp                  wq
+.w4:
+    vpbroadcastq         m4, [tlq+2]    ; top
+    movsldup             m3, [base+ipred_hv_shuf]
+    lea                  r6, [strideq*3]
+    psubw                m4, m5         ; top - bottom
+.w4_loop:
+    vpbroadcastq         m0, [weightsq+hq*2]
+    pshufb               m0, m3
+    pmulhrsw             m0, m4
+    paddw                m0, m5
+    vextracti128        xm1, m0, 1
+    movhps [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movq   [dstq+r6       ], xm0
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w4_loop
+.ret:
+    RET
+.w8:
+    vbroadcasti128       m4, [tlq+2]
+    movsldup             m3, [base+ipred_hv_shuf]
+    lea                  r6, [strideq*3]
+    psubw                m4, m5
+.w8_loop:
+    vpbroadcastd         m0, [weightsq+hq*2+0]
+    vpbroadcastd         m1, [weightsq+hq*2+4]
+    pshufb               m0, m3
+    pshufb               m1, m3
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    paddw                m0, m5
+    paddw                m1, m5
+    vextracti128 [dstq+strideq*0], m0, 1
+    mova         [dstq+strideq*1], xm0
+    vextracti128 [dstq+strideq*2], m1, 1
+    mova         [dstq+r6       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w8_loop
+    RET
+.w16:
+    movu                 m4, [tlq+2]
+    lea                  r6, [strideq*3]
+    psubw                m4, m5
+.w16_loop:
+    vpbroadcastw         m0, [weightsq+hq*2+0]
+    vpbroadcastw         m1, [weightsq+hq*2+2]
+    vpbroadcastw         m2, [weightsq+hq*2+4]
+    vpbroadcastw         m3, [weightsq+hq*2+6]
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    REPX   {paddw    x, m5}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+r6       ], m3
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w16_loop
+    RET
+.w32:
+    WIN64_SPILL_XMM       7
+    movu                 m4, [tlq+ 2]
+    movu                 m6, [tlq+34]
+    psubw                m4, m5
+    psubw                m6, m5
+.w32_loop:
+    vpbroadcastw         m1, [weightsq+hq*2+0]
+    vpbroadcastw         m3, [weightsq+hq*2+2]
+    pmulhrsw             m0, m4, m1
+    pmulhrsw             m1, m6
+    pmulhrsw             m2, m4, m3
+    pmulhrsw             m3, m6
+    REPX      {paddw x, m5}, m0, m1, m2, m3
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*1+32*0], m2
+    mova [dstq+strideq*1+32*1], m3
+    lea                dstq, [dstq+strideq*2]
+    add                  hq, 2
+    jl .w32_loop
+    RET
+.w64:
+    WIN64_SPILL_XMM       8
+    movu                 m3, [tlq+ 2]
+    movu                 m4, [tlq+34]
+    movu                 m6, [tlq+66]
+    movu                 m7, [tlq+98]
+    REPX      {psubw x, m5}, m3, m4, m6, m7
+.w64_loop:
+    vpbroadcastw         m2, [weightsq+hq*2]
+    pmulhrsw             m0, m3, m2
+    pmulhrsw             m1, m4, m2
+    paddw                m0, m5
+    paddw                m1, m5
+    mova        [dstq+32*0], m0
+    pmulhrsw             m0, m6, m2
+    mova        [dstq+32*1], m1
+    pmulhrsw             m1, m7, m2
+    paddw                m0, m5
+    paddw                m1, m5
+    mova        [dstq+32*2], m0
+    mova        [dstq+32*3], m1
+    add                dstq, strideq
+    inc                  hq
+    jl .w64_loop
+    RET
+
+cglobal ipred_smooth_h_16bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+%define base r6-ipred_smooth_h_16bpc_avx2_table
+    lea                  r6, [ipred_smooth_h_16bpc_avx2_table]
+    mov                  wd, wm
+    movifnidn            hd, hm
+    vpbroadcastw         m5, [tlq+wq*2] ; right
+    tzcnt                wd, wd
+    add                  hd, hd
+    movsxd               wq, [r6+wq*4]
+    sub                 tlq, hq
+    lea            stride3q, [strideq*3]
+    add                  wq, r6
+    jmp                  wq
+.w4:
+    vpbroadcastq         m4, [base+smooth_weights_1d_16bpc+4*2]
+    movsldup             m3, [base+ipred_hv_shuf]
+.w4_loop:
+    vpbroadcastq         m0, [tlq+hq-8] ; left
+    pshufb               m0, m3
+    psubw                m0, m5         ; left - right
+    pmulhrsw             m0, m4
+    paddw                m0, m5
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4*2
+    jg .w4_loop
+    RET
+.w8:
+    vbroadcasti128       m4, [base+smooth_weights_1d_16bpc+8*2]
+    movsldup             m3, [base+ipred_hv_shuf]
+.w8_loop:
+    vpbroadcastd         m0, [tlq+hq-4]
+    vpbroadcastd         m1, [tlq+hq-8]
+    pshufb               m0, m3
+    pshufb               m1, m3
+    psubw                m0, m5
+    psubw                m1, m5
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    paddw                m0, m5
+    paddw                m1, m5
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova         [dstq+strideq*2], xm1
+    vextracti128 [dstq+stride3q ], m1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hq, 4*2
+    jg .w8_loop
+    RET
+.w16:
+    movu                 m4, [base+smooth_weights_1d_16bpc+16*2]
+.w16_loop:
+    vpbroadcastq         m3, [tlq+hq-8]
+    punpcklwd            m3, m3
+    psubw                m3, m5
+    pshufd               m0, m3, q3333
+    pshufd               m1, m3, q2222
+    pshufd               m2, m3, q1111
+    pshufd               m3, m3, q0000
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    REPX   {paddw    x, m5}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+stride3q ], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hq, 4*2
+    jg .w16_loop
+    RET
+.w32:
+    WIN64_SPILL_XMM       7
+    movu                 m4, [base+smooth_weights_1d_16bpc+32*2]
+    movu                 m6, [base+smooth_weights_1d_16bpc+32*3]
+.w32_loop:
+    vpbroadcastw         m1, [tlq+hq-2]
+    vpbroadcastw         m3, [tlq+hq-4]
+    psubw                m1, m5
+    psubw                m3, m5
+    pmulhrsw             m0, m4, m1
+    pmulhrsw             m1, m6
+    pmulhrsw             m2, m4, m3
+    pmulhrsw             m3, m6
+    REPX      {paddw x, m5}, m0, m1, m2, m3
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*1+32*0], m2
+    mova [dstq+strideq*1+32*1], m3
+    lea                dstq, [dstq+strideq*2]
+    sub                  hq, 2*2
+    jg .w32_loop
+    RET
+.w64:
+    WIN64_SPILL_XMM       8
+    movu                 m3, [base+smooth_weights_1d_16bpc+32*4]
+    movu                 m4, [base+smooth_weights_1d_16bpc+32*5]
+    movu                 m6, [base+smooth_weights_1d_16bpc+32*6]
+    movu                 m7, [base+smooth_weights_1d_16bpc+32*7]
+.w64_loop:
+    vpbroadcastw         m2, [tlq+hq-2]
+    psubw                m2, m5
+    pmulhrsw             m0, m3, m2
+    pmulhrsw             m1, m4, m2
+    paddw                m0, m5
+    paddw                m1, m5
+    mova        [dstq+32*0], m0
+    pmulhrsw             m0, m6, m2
+    mova        [dstq+32*1], m1
+    pmulhrsw             m1, m7, m2
+    paddw                m0, m5
+    paddw                m1, m5
+    mova        [dstq+32*2], m0
+    mova        [dstq+32*3], m1
+    add                dstq, strideq
+    sub                  hq, 1*2
+    jg .w64_loop
+    RET
+
+%macro SMOOTH_2D_END 6 ; src[1-2], mul[1-2], add[1-2]
+    pmaddwd             m0, m%1, m%3
+    pmaddwd             m1, m%2, m%4
+    paddd               m0, m%5
+    paddd               m1, m%6
+    psrld               m0, 8
+    psrld               m1, 8
+    packssdw            m0, m1
+    pavgw               m0, m5
+%endmacro
+
+cglobal ipred_smooth_16bpc, 3, 7, 6, dst, stride, tl, w, h, v_weights
+%define base r6-ipred_smooth_16bpc_avx2_table
+    lea                 r6, [ipred_smooth_16bpc_avx2_table]
+    mov                 wd, wm
+    vpbroadcastw        m4, [tlq+wq*2] ; right
+    tzcnt               wd, wd
+    mov                 hd, hm
+    sub                tlq, hq
+    sub                tlq, hq
+    movsxd              wq, [r6+wq*4]
+    pxor                m5, m5
+    add                 wq, r6
+    lea         v_weightsq, [base+smooth_weights_2d_16bpc+hq*4]
+    jmp                 wq
+.w4:
+    WIN64_SPILL_XMM     11
+    vpbroadcastw        m0, [tlq] ; bottom
+    vpbroadcastq        m6, [tlq+hq*2+2]
+    movsldup            m7, [base+ipred_hv_shuf]
+    movshdup            m9, [base+ipred_hv_shuf]
+    vbroadcasti128     m10, [base+smooth_weights_2d_16bpc+4*4]
+    punpcklwd           m6, m0 ; top, bottom
+    punpcklqdq          m8, m9, m9
+    punpckhqdq          m9, m9
+    lea                 r3, [strideq*3]
+.w4_loop:
+    vpbroadcastq        m3, [tlq+hq*2-8]
+    vbroadcasti128      m1, [v_weightsq]
+    pshufb              m3, m7
+    punpcklwd           m2, m3, m4 ; left, right
+    punpckhwd           m3, m4
+    pmaddwd             m2, m10
+    pmaddwd             m3, m10
+    pshufb              m0, m1, m8
+    pshufb              m1, m9
+    SMOOTH_2D_END        0, 1, 6, 6, 2, 3
+    vextracti128       xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r3       ], xm1
+    lea               dstq, [dstq+strideq*4]
+    add         v_weightsq, 16
+    sub                 hd, 4
+    jg .w4_loop
+    RET
+.w8:
+    WIN64_SPILL_XMM     12
+    vpbroadcastw        m0, [tlq] ; bottom
+    vbroadcasti128      m7, [tlq+hq*2+2]
+    movsldup            m8, [base+ipred_hv_shuf]
+    movshdup            m9, [base+ipred_hv_shuf]
+    vbroadcasti128     m10, [base+smooth_weights_2d_16bpc+8*4+16*0]
+    vbroadcasti128     m11, [base+smooth_weights_2d_16bpc+8*4+16*1]
+    punpcklwd           m6, m7, m0 ; top, bottom
+    punpckhwd           m7, m0
+.w8_loop:
+    vpbroadcastd        m3, [tlq+hq*2-4]
+    vpbroadcastq        m1, [v_weightsq]
+    pshufb              m3, m8
+    punpcklwd           m2, m3, m4 ; left, right
+    punpckhwd           m3, m4
+    pmaddwd             m2, m10
+    pmaddwd             m3, m11
+    pshufb              m1, m9
+    SMOOTH_2D_END        1, 1, 6, 7, 2, 3
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea               dstq, [dstq+strideq*2]
+    add         v_weightsq, 8
+    sub                 hd, 2
+    jg .w8_loop
+    RET
+.w16:
+    WIN64_SPILL_XMM     11
+    vpbroadcastw        m0, [tlq] ; bottom
+    movu                m7, [tlq+hq*2+2]
+    mova               xm8, [base+smooth_weights_2d_16bpc+16*4+16*0]
+    mova               xm9, [base+smooth_weights_2d_16bpc+16*4+16*1]
+    vinserti128         m8, [base+smooth_weights_2d_16bpc+16*4+16*2], 1
+    vinserti128         m9, [base+smooth_weights_2d_16bpc+16*4+16*3], 1
+    punpcklwd           m6, m7, m0 ; top, bottom
+    punpckhwd           m7, m0
+.w16_loop:
+    vpbroadcastd        m3, [tlq+hq*2-4]
+    vpbroadcastd        m1, [v_weightsq+0]
+    punpcklwd           m3, m4     ; left, right
+    pshufd              m2, m3, q1111
+    pmaddwd            m10, m8, m2
+    pmaddwd             m2, m9
+    pshufd              m3, m3, q0000
+    SMOOTH_2D_END        1, 1, 6, 7, 10, 2
+    vpbroadcastd        m1, [v_weightsq+4]
+    pmaddwd             m2, m8, m3
+    pmaddwd             m3, m9
+    mova  [dstq+strideq*0], m0
+    SMOOTH_2D_END        1, 1, 6, 7, 2, 3
+    mova  [dstq+strideq*1], m0
+    lea               dstq, [dstq+strideq*2]
+    add         v_weightsq, 8
+    sub                 hq, 2
+    jg .w16_loop
+    RET
+.w32:
+    WIN64_SPILL_XMM     15
+    vpbroadcastw        m0, [tlq] ; bottom
+    movu                m7, [tlq+hq*2+ 2]
+    movu                m9, [tlq+hq*2+34]
+    mova              xm10, [base+smooth_weights_2d_16bpc+32*4+16*0]
+    mova              xm11, [base+smooth_weights_2d_16bpc+32*4+16*1]
+    vinserti128        m10, [base+smooth_weights_2d_16bpc+32*4+16*2], 1
+    vinserti128        m11, [base+smooth_weights_2d_16bpc+32*4+16*3], 1
+    mova              xm12, [base+smooth_weights_2d_16bpc+32*4+16*4]
+    mova              xm13, [base+smooth_weights_2d_16bpc+32*4+16*5]
+    vinserti128        m12, [base+smooth_weights_2d_16bpc+32*4+16*6], 1
+    vinserti128        m13, [base+smooth_weights_2d_16bpc+32*4+16*7], 1
+    punpcklwd           m6, m7, m0
+    punpckhwd           m7, m0
+    punpcklwd           m8, m9, m0
+    punpckhwd           m9, m0
+.w32_loop:
+    vpbroadcastw        m3, [tlq+hq*2-2]
+    vpbroadcastd       m14, [v_weightsq]
+    punpcklwd           m3, m4
+    pmaddwd             m1, m10, m3
+    pmaddwd             m2, m11, m3
+    pmaddwd             m0, m6, m14
+    paddd               m0, m1
+    pmaddwd             m1, m7, m14
+    paddd               m1, m2
+    pmaddwd             m2, m12, m3
+    pmaddwd             m3, m13
+    psrld               m0, 8
+    psrld               m1, 8
+    packssdw            m0, m1
+    pavgw               m0, m5
+    mova       [dstq+32*0], m0
+    SMOOTH_2D_END       14, 14, 8, 9, 2, 3
+    mova       [dstq+32*1], m0
+    add               dstq, strideq
+    add         v_weightsq, 4
+    dec                 hd
+    jg .w32_loop
+    RET
+.w64:
+    PROLOGUE 0, 11, 16, dst, stride, tl, tl_base, h, v_weights, dummy, v_weights_base, x, y, dst_base
+    mov          dst_baseq, dstq
+    mov           tl_baseq, tlq
+    mov    v_weights_baseq, v_weightsq
+    xor                 xq, xq
+.w64_loop_x:
+    mov                 yq, hq
+    lea                tlq, [tl_baseq+hq*2]
+    vpbroadcastw        m0, [tl_baseq] ; bottom
+    movu                m7, [tlq+xq*2+ 2]
+    movu                m9, [tlq+xq*2+34]
+    mova              xm10, [base+smooth_weights_2d_16bpc+64*4+16*0]
+    mova              xm11, [base+smooth_weights_2d_16bpc+64*4+16*1]
+    vinserti128        m10, [base+smooth_weights_2d_16bpc+64*4+16*2], 1
+    vinserti128        m11, [base+smooth_weights_2d_16bpc+64*4+16*3], 1
+    mova              xm12, [base+smooth_weights_2d_16bpc+64*4+16*4]
+    mova              xm13, [base+smooth_weights_2d_16bpc+64*4+16*5]
+    vinserti128        m12, [base+smooth_weights_2d_16bpc+64*4+16*6], 1
+    vinserti128        m13, [base+smooth_weights_2d_16bpc+64*4+16*7], 1
+    punpcklwd           m6, m7, m0
+    punpckhwd           m7, m0
+    punpcklwd           m8, m9, m0
+    punpckhwd           m9, m0
+    lea                tlq, [tl_baseq-2]
+.w64_loop_y:
+    vpbroadcastw        m3, [tlq+yq*2]
+    vpbroadcastd        m1, [v_weightsq]
+    punpcklwd           m3, m4
+    pmaddwd            m14, m10, m3
+    pmaddwd            m15, m11, m3
+    pmaddwd             m2, m12, m3
+    pmaddwd             m3, m13
+    pmaddwd             m0, m6, m1
+    paddd               m0, m14
+    pmaddwd            m14, m7, m1
+    paddd              m14, m15
+    psrld               m0, 8
+    psrld              m14, 8
+    packssdw            m0, m14
+    pavgw               m0, m5
+    mova       [dstq+32*0], m0
+    SMOOTH_2D_END        8, 9, 1, 1, 2, 3
+    mova       [dstq+32*1], m0
+    add               dstq, strideq
+    add         v_weightsq, 4
+    dec                 yq
+    jg .w64_loop_y
+    lea               dstq, [dst_baseq+32*2]
+    add                 r6, 16*8
+    mov         v_weightsq, v_weights_baseq
+    add                 xq, 32
+    test                xb, 64
+    jz .w64_loop_x
+    RET
+
+cglobal ipred_z1_16bpc, 3, 8, 0, dst, stride, tl, w, h, angle, dx, maxbase
+    lea                  r6, [ipred_z1_16bpc_avx2_table]
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    movifnidn            hd, hm
+    lea                  r7, [dr_intra_derivative]
+    movsxd               wq, [r6+wq*4]
+    add                 tlq, 2
+    add                  wq, r6
+    mov                 dxd, angled
+    and                 dxd, 0x7e
+    add              angled, 165 ; ~90
+    movzx               dxd, word [r7+dxq]
+    xor              angled, 0x4ff ; d = 90 - angle
+    vpbroadcastd         m5, [pw_62]
+    jmp                  wq
+.w4:
+    ALLOC_STACK         -64, 7
+    cmp              angleb, 40
+    jae .w4_no_upsample
+    lea                 r3d, [angleq-1024]
+    sar                 r3d, 7
+    add                 r3d, hd
+    jg .w4_no_upsample ; !enable_intra_edge_filter || h > 8 || (h == 8 && is_sm)
+    vpbroadcastw        xm3, [tlq+14]
+    movu                xm1, [tlq+ 0]    ; 1 2 3 4 5 6 7 8
+    palignr             xm0, xm3, xm1, 4 ; 3 4 5 6 7 8 8 8
+    paddw               xm0, [tlq- 2]    ; 0 1 2 3 4 5 6 7
+    add                 dxd, dxd
+    palignr             xm2, xm3, xm1, 2 ; 2 3 4 5 6 7 8 8
+    paddw               xm2, xm1         ; -1 * a + 9 * b + 9 * c + -1 * d
+    psubw               xm0, xm2, xm0    ; = (b + c - a - d + (b + c) << 3 + 8) >> 4
+    psraw               xm0, 3           ; = ((b + c - a - d) >> 3 + b + c + 1) >> 1
+    pxor                xm4, xm4
+    paddw               xm2, xm0
+    vpbroadcastw        xm0, r8m         ; pixel_max
+    mova           [rsp+32], xm3
+    movd                xm3, dxd
+    pmaxsw              xm2, xm4
+    mov                 r3d, dxd
+    pavgw               xm2, xm4
+    vpbroadcastw         m3, xm3
+    pminsw              xm2, xm0
+    punpcklwd           xm0, xm1, xm2
+    punpckhwd           xm1, xm2
+    lea                  r5, [strideq*3]
+    pslldq               m2, m3, 8
+    mova           [rsp+ 0], xm0
+    mova           [rsp+16], xm1
+    paddw                m6, m3, m3
+    paddw                m3, m2
+    vpblendd             m4, m6, 0xf0
+    paddw                m6, m6
+    paddw                m3, m4 ; xpos0 xpos1 xpos2 xpos3
+    vbroadcasti128       m4, [z_upsample]
+.w4_upsample_loop:
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6 ; base0
+    movu                xm1, [rsp+r3*2]
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6 ; base1
+    movu                xm2, [rsp+r2*2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6 ; base2
+    vinserti128          m1, [rsp+r3*2], 1 ; 0 2
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6 ; base3
+    vinserti128          m2, [rsp+r2*2], 1 ; 1 3
+    pshufb               m1, m4
+    pshufb               m2, m4
+    punpcklqdq           m0, m1, m2
+    punpckhqdq           m1, m2
+    pand                 m2, m5, m3 ; frac
+    psllw                m2, 9      ; (a * (64 - frac) + b * frac + 32) >> 6
+    psubw                m1, m0     ; = a + (((b - a) * frac + 32) >> 6)
+    pmulhrsw             m1, m2     ; = a + (((b - a) * (frac << 9) + 16384) >> 15)
+    paddw                m3, m6     ; xpos += dx
+    paddw                m0, m1
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r5       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_upsample_loop
+    RET
+ALIGN function_align
+.filter_strength: ; w4/w8/w16
+%define base r3-z_filter_t0
+    movd                xm0, maxbased
+    lea                  r3, [z_filter_t0]
+    movd                xm1, angled
+    shr              angled, 8 ; is_sm << 1
+    vpbroadcastb         m0, xm0
+    vpbroadcastb         m1, xm1
+    pcmpeqb              m0, [base+z_filter_wh]
+    mova                xm2, [r3+angleq*8]
+    pand                 m0, m1
+    pcmpgtb              m0, m2
+    pmovmskb            r5d, m0
+    ret
+.w4_no_upsample:
+    mov            maxbased, 7
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w4_main
+    lea            maxbased, [hq+3]
+    call .filter_strength
+    mov            maxbased, 7
+    test                r5d, r5d
+    jz .w4_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    vpbroadcastw        xm3, [tlq+14]
+    mova                xm0, [tlq- 2]      ; 0 1 2 3 4 5 6 7
+    vpbroadcastd        xm1, [base+z_filter_k-4+r5*4+12*1]
+    vpbroadcastd        xm4, [base+z_filter_k-4+r5*4+12*0]
+    palignr             xm2, xm3, xm0, 4   ; 2 3 4 5 6 7 8 8
+    pmullw              xm1, [tlq+ 0]      ; 1 2 3 4 5 6 7 8
+    paddw               xm2, xm0
+    pmullw              xm2, xm4
+    movd           [rsp+16], xm3
+    cmp                 r5d, 3
+    jne .w4_3tap
+    paddw               xm1, xm2
+    palignr             xm2, xm3, xm0, 6   ; 3 4 5 6 7 8 8 8
+    pblendw             xm0, [tlq-4], 0xfe ; 0 0 1 2 3 4 5 6
+    movzx               r3d, word [tlq+14]
+    movzx               r2d, word [tlq+12]
+    inc            maxbased
+    paddw               xm2, xm0
+    sub                 r2d, r3d
+    paddw               xm2, xm2
+    lea                 r2d, [r2+r3*8+4]
+    shr                 r2d, 3 ; (1 * top[6] + 7 * top[7] + 4) >> 3
+    mov            [rsp+16], r2w
+.w4_3tap:
+    pxor                xm0, xm0
+    paddw               xm1, xm2
+    mov                 tlq, rsp
+    psrlw               xm1, 3
+    cmp                  hd, 8
+    sbb            maxbased, -1
+    pavgw               xm0, xm1
+    mova              [tlq], xm0
+.w4_main:
+    movd                xm3, dxd
+    vpbroadcastq         m1, [z_base_inc]
+    vpbroadcastw         m6, [tlq+maxbaseq*2] ; top[max_base_x]
+    shl            maxbased, 6
+    vpbroadcastw         m3, xm3
+    movd                xm0, maxbased
+    mov                 r3d, dxd      ; xpos
+    vpbroadcastw         m0, xm0
+    paddw                m4, m3, m3
+    psubw                m1, m0       ; -max_base_x
+    vpblendd             m3, m4, 0xcc
+    paddw                m0, m4, m3
+    vpblendd             m3, m0, 0xf0 ; xpos0 xpos1 xpos2 xpos3
+    paddw                m4, m4
+    paddw                m3, m1
+.w4_loop:
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base0
+    movu                xm1, [tlq+r3*2]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base1
+    movu                xm2, [tlq+r5*2]
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base2
+    vinserti128          m1, [tlq+r3*2], 1 ; 0 2
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base3
+    vinserti128          m2, [tlq+r5*2], 1 ; 1 3
+    punpcklqdq           m0, m1, m2
+    psrldq               m1, 2
+    pslldq               m2, 6
+    vpblendd             m1, m2, 0xcc
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    psraw                m2, m3, 15 ; xpos < max_base_x
+    paddw                m3, m4
+    paddw                m0, m1
+    vpblendvb            m0, m6, m0, m2
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    lea                dstq, [dstq+strideq*2]
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    sub                  hd, 4
+    jz .w4_end
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r3d, maxbased
+    jb .w4_loop
+    lea                  r6, [strideq*3]
+.w4_end_loop:
+    movq   [dstq+strideq*0], xm6
+    movq   [dstq+strideq*1], xm6
+    movq   [dstq+strideq*2], xm6
+    movq   [dstq+r6       ], xm6
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_end_loop
+.w4_end:
+    RET
+.w8:
+    ALLOC_STACK         -64, 7
+    lea                 r3d, [angleq+216]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || h > 8
+    movu                 m2, [tlq+2]    ; 2 3 4 5 6 7 8 9   a b c d e f g _
+    movu                 m0, [tlq+4]    ; 3 4 5 6 7 8 9 a   b c d e f g _ _
+    movu                 m1, [tlq+0]    ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    cmp                  hd, 4
+    jne .w8_upsample_h8 ; awkward single-pixel edge case
+    vpblendd             m0, m2, 0x20   ; 3 4 5 6 7 8 9 a   b c c _ _ _ _ _
+.w8_upsample_h8:
+    paddw                m2, m1
+    paddw                m0, [tlq-2]    ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    add                 dxd, dxd
+    psubw                m0, m2, m0
+    psraw                m0, 3
+    pxor                 m4, m4
+    paddw                m2, m0
+    vpbroadcastw         m0, r8m
+    movd                xm3, dxd
+    pmaxsw               m2, m4
+    mov                 r3d, dxd
+    pavgw                m2, m4
+    vpbroadcastw         m3, xm3
+    pminsw               m2, m0
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    vbroadcasti128       m4, [z_upsample]
+    mova           [rsp+ 0], xm0
+    mova           [rsp+16], xm1
+    paddw                m6, m3, m3
+    vextracti128   [rsp+32], m0, 1
+    vextracti128   [rsp+48], m1, 1
+    vpblendd             m3, m6, 0xf0 ; xpos0 xpos1
+.w8_upsample_loop:
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6 ; base0
+    movu                xm1, [rsp+r3*2]
+    movu                xm2, [rsp+r3*2+16]
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6 ; base1
+    vinserti128          m1, [rsp+r2*2], 1
+    vinserti128          m2, [rsp+r2*2+16], 1
+    pshufb               m1, m4
+    pshufb               m2, m4
+    punpcklqdq           m0, m1, m2
+    punpckhqdq           m1, m2
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m3, m6
+    paddw                m0, m1
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_upsample_loop
+    RET
+.w8_no_intra_edge_filter:
+    and            maxbased, 7
+    or             maxbased, 8 ; imin(h+7, 15)
+    jmp .w8_main
+.w8_no_upsample:
+    lea            maxbased, [hq+7]
+    test             angled, 0x400
+    jnz .w8_no_intra_edge_filter
+    call .filter_strength
+    test                r5d, r5d
+    jz .w8_main
+    popcnt              r5d, r5d
+    vpbroadcastd         m1, [base+z_filter_k-4+r5*4+12*1]
+    vpbroadcastd         m4, [base+z_filter_k-4+r5*4+12*0]
+    mova                 m0, [tlq-2]           ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    movu                 m2, [tlq+0]           ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    pmullw               m1, m2
+    cmp                  hd, 8
+    jl .w8_filter_h4
+    punpckhwd            m2, m2
+    vpblendd             m3, m2, [tlq+2], 0x7f ; 2 3 4 5 6 7 8 9   a b c d e f g g
+    je .w8_filter_end ; 8x4 and 8x8 are always 3-tap
+    movzx               r3d, word [tlq+30]
+    mov            maxbased, 16
+    mov            [rsp+32], r3d
+    cmp                 r5d, 3
+    jne .w8_filter_end
+    punpcklwd           xm6, xm0, xm0
+    vpblendd             m2, [tlq+4], 0x7f     ; 3 4 5 6 7 8 9 a   b c d e f g g g
+    vpblendd             m6, [tlq-4], 0xfe     ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    movzx               r5d, word [tlq+28]
+    mov            [rsp+34], r3w
+    paddw                m2, m6
+    sub                 r5d, r3d
+    inc            maxbased
+    paddw                m2, m2
+    lea                 r3d, [r5+r3*8+4]
+    paddw                m1, m2
+    shr                 r3d, 3
+    mov            [rsp+32], r3w
+    jmp .w8_filter_end
+.w8_filter_h4:
+    pshuflw              m3, m2, q3321
+    vinserti128          m3, [tlq+2], 0        ; 2 3 4 5 6 7 8 9   a b c c _ _ _ _
+.w8_filter_end:
+    paddw                m0, m3
+    pmullw               m0, m4
+    mov                 tlq, rsp
+    pxor                 m2, m2
+    paddw                m0, m1
+    psrlw                m0, 3
+    pavgw                m0, m2
+    mova              [tlq], m0
+.w8_main:
+    movd                xm3, dxd
+    vbroadcasti128       m1, [z_base_inc]
+    vpbroadcastw         m6, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m3, xm3
+    movd                xm0, maxbased
+    mov                 r3d, dxd
+    vpbroadcastw         m0, xm0
+    paddw                m4, m3, m3
+    psubw                m1, m0
+    vpblendd             m3, m4, 0xf0 ; xpos0 xpos1
+    paddw                m3, m1
+.w8_loop:
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6
+    movu                xm0, [tlq+r3*2]
+    movu                xm1, [tlq+r3*2+2]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6
+    vinserti128          m0, [tlq+r5*2], 1
+    vinserti128          m1, [tlq+r5*2+2], 1
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    psraw                m2, m3, 15
+    paddw                m3, m4
+    paddw                m0, m1
+    vpblendvb            m0, m6, m0, m2
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    sub                  hd, 2
+    jz .w8_end
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r3d, maxbased
+    jb .w8_loop
+.w8_end_loop:
+    mova   [dstq+strideq*0], xm6
+    mova   [dstq+strideq*1], xm6
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_end_loop
+.w8_end:
+    RET
+.w16_no_intra_edge_filter:
+    and            maxbased, 15
+    or             maxbased, 16 ; imin(h+15, 31)
+    jmp .w16_main
+.w16:
+    ALLOC_STACK         -96, 7
+    lea            maxbased, [hq+15]
+    test             angled, 0x400
+    jnz .w16_no_intra_edge_filter
+    call .filter_strength
+    test                r5d, r5d
+    jz .w16_main
+    popcnt              r5d, r5d
+    mova                 m0, [tlq-2]            ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    paddw                m1, m0, [tlq+2]        ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    cmp                 r5d, 3
+    jne .w16_filter_3tap
+    vpbroadcastd         m2, [base+pw_3]
+    punpcklwd           xm0, xm0
+    vpblendd             m0, [tlq-4], 0xfe      ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    paddw                m1, [tlq+0]            ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    paddw                m0, m2
+    pavgw                m0, [tlq+4]            ; 3 4 5 6 7 8 9 a   b c d e f g h i
+    paddw                m0, m1
+    psrlw                m0, 2
+    movu                 m3, [tlq+32]           ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    paddw                m2, [tlq+28]           ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    paddw                m1, m3, [tlq+30]       ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    cmp                  hd, 8
+    jl .w16_filter_5tap_h4
+    punpckhwd            m3, m3
+    je .w16_filter_5tap_h8
+    vpblendd             m4, m3, [tlq+36], 0x7f ; 4 5 6 7 8 9 a b   c d e f g h h h
+    vpblendd             m3, [tlq+34], 0x7f     ; 3 4 5 6 7 8 9 a   b c d e f g h h
+    movzx               r3d, word [tlq+62]
+    movzx               r2d, word [tlq+60]
+    pavgw                m2, m4
+    sub                 r2d, r3d
+    paddw                m1, m3
+    lea                 r2d, [r2+r3*8+4]
+    paddw                m1, m2
+    shr                 r2d, 3
+    psrlw                m1, 2
+    mov            [rsp+66], r3w
+    mov            [rsp+64], r2w
+    mov                 tlq, rsp
+    mov                 r3d, 33
+    cmp                  hd, 16
+    cmovg          maxbased, r3d
+    jmp .w16_filter_end2
+.w16_filter_5tap_h8:
+    vpblendd            xm4, xm3, [tlq+36], 0x07 ; 4 5 6 7 8 9 9 9
+    vpblendd            xm3, [tlq+34], 0x07      ; 3 4 5 6 7 8 9 9
+    pavgw               xm2, xm4
+    paddw               xm1, xm3
+    paddw               xm1, xm2
+    psrlw               xm1, 2
+    jmp .w16_filter_end2
+.w16_filter_5tap_h4:
+    pshuflw             xm4, xm3, q3332          ; 4 5 5 5
+    pshuflw             xm3, xm3, q3321          ; 3 4 5 5
+    pavgw               xm2, xm4
+    paddw               xm1, xm3
+    paddw               xm1, xm2
+    psrlw               xm1, 2
+    jmp .w16_filter_end2
+.w16_filter_3tap:
+    vpbroadcastd         m3, [base+z_filter_k-4+r5*4+12*1]
+    vpbroadcastd         m4, [base+z_filter_k-4+r5*4+12*0]
+    pmullw               m0, m3, [tlq+0]    ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    movu                 m2, [tlq+32]       ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    pmullw               m1, m4
+    pmullw               m3, m2
+    paddw                m0, m1
+    cmp                  hd, 8
+    je .w16_filter_3tap_h8
+    jl .w16_filter_3tap_h4
+    punpckhwd            m2, m2
+    vpblendd             m2, [tlq+34], 0x7f ; 2 3 4 5 6 7 8 9   a b c d e f g g
+    jmp .w16_filter_end
+.w16_filter_3tap_h4:
+    pshuflw             xm2, xm2, q3321     ; 2 3 4 4 _ _ _ _
+    jmp .w16_filter_end
+.w16_filter_3tap_h8:
+    psrldq              xm2, 2
+    pshufhw             xm2, xm2, q2210     ; 2 3 4 5 6 7 8 8
+.w16_filter_end:
+    paddw                m2, [tlq+30]       ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    pmullw               m2, m4
+    psrlw                m0, 3
+    pxor                 m1, m1
+    paddw                m2, m3
+    psrlw                m2, 3
+    pavgw                m0, m1
+    pavgw                m1, m2
+.w16_filter_end2:
+    mov                 tlq, rsp
+    mova           [tlq+ 0], m0
+    mova           [tlq+32], m1
+.w16_main:
+    movd                xm4, dxd
+    vpbroadcastw         m6, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m4, xm4
+    movd                xm0, maxbased
+    mov                 r3d, dxd
+    vpbroadcastw         m0, xm0
+    paddw                m3, m4, [z_base_inc]
+    psubw                m3, m0
+.w16_loop:
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6
+    movu                 m0, [tlq+r3*2]
+    movu                 m1, [tlq+r3*2+2]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    psraw                m2, m3, 15
+    paddw                m3, m4
+    paddw                m1, m0
+    movu                 m0, [tlq+r5*2]
+    vpblendvb            m2, m6, m1, m2
+    movu                 m1, [tlq+r5*2+2]
+    mova   [dstq+strideq*0], m2
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    psraw                m2, m3, 15
+    paddw                m3, m4
+    paddw                m0, m1
+    vpblendvb            m0, m6, m0, m2
+    mova   [dstq+strideq*1], m0
+    sub                  hd, 2
+    jz .w16_end
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r3d, maxbased
+    jb .w16_loop
+.w16_end_loop:
+    mova   [dstq+strideq*0], m6
+    mova   [dstq+strideq*1], m6
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_end_loop
+.w16_end:
+    RET
+.w32:
+    ALLOC_STACK        -160, 8
+    lea            maxbased, [hq+31]
+    mov                 r3d, 63
+    cmp                  hd, 32
+    cmova          maxbased, r3d
+    test             angled, 0x400
+    jnz .w32_main
+    vpbroadcastd         m2, [pw_3]
+    mova                 m0, [tlq-2]       ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    punpcklwd           xm1, xm0, xm0
+    vpblendd             m1, [tlq-4], 0xfe ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    paddw                m0, [tlq+0]       ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    paddw                m1, m2
+    paddw                m0, [tlq+2]       ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    pavgw                m1, [tlq+4]       ; 3 4 5 6 7 8 9 a   b c d e f g h i
+    mov                  r3, rsp
+    paddw                m0, m1
+    lea                 r5d, [maxbaseq-31]
+    psrlw                m0, 2
+    mova               [r3], m0
+.w32_filter_loop:
+    mova                 m0, [tlq+30]
+    paddw                m1, m2, [tlq+28]
+    add                 tlq, 32
+    paddw                m0, [tlq+0]
+    pavgw                m1, [tlq+4]
+    paddw                m0, [tlq+2]
+    add                  r3, 32
+    paddw                m0, m1
+    psrlw                m0, 2
+    mova               [r3], m0
+    sub                 r5d, 16
+    jg .w32_filter_loop
+    movu                 m0, [tlq+32]           ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    punpckhwd            m1, m0, m0
+    paddw                m2, [tlq+28]           ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    paddw                m0, [tlq+30]           ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    jl .w32_filter_h8
+    vpblendd             m3, m1, [tlq+36], 0x7f ; 4 5 6 7 8 9 a b   c d e f g h h h
+    vpblendd             m1, [tlq+34], 0x7f     ; 3 4 5 6 7 8 9 a   b c d e f g h h
+    movzx               r5d, word [tlq+62]
+    movzx               r2d, word [tlq+60]
+    pavgw                m2, m3
+    sub                 r2d, r5d
+    paddw                m0, m1
+    lea                 r2d, [r2+r5*8+4]
+    paddw                m0, m2
+    shr                 r2d, 3
+    psrlw                m0, 2
+    mova            [r3+32], m0
+    mov             [r3+66], r5w
+    mov             [r3+64], r2w
+    mov                 tlq, rsp
+    mov                 r3d, 65
+    cmp                  hd, 64
+    cmove          maxbased, r3d
+    jmp .w32_main
+.w32_filter_h8:
+    vpblendd            xm3, xm1, [tlq+36], 0x07 ; 4 5 6 7 8 9 9 9
+    vpblendd            xm1, [tlq+34], 0x07      ; 3 4 5 6 7 8 9 9
+    pavgw               xm2, xm3
+    paddw               xm0, xm1
+    mov                 tlq, rsp
+    paddw               xm0, xm2
+    psrlw               xm0, 2
+    mova            [r3+32], xm0
+.w32_main:
+    movd                xm4, dxd
+    vpbroadcastw         m6, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m4, xm4
+    movd                xm0, maxbased
+    mov                 r5d, dxd
+    vpbroadcastd         m7, [pw_m1024] ; -16 * 64
+    vpbroadcastw         m0, xm0
+    paddw                m3, m4, [z_base_inc]
+    psubw                m3, m0
+.w32_loop:
+    mov                 r3d, r5d
+    shr                 r3d, 6
+    movu                 m0, [tlq+r3*2]
+    movu                 m1, [tlq+r3*2+2]
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    psraw                m1, m3, 15
+    vpblendvb            m0, m6, m0, m1
+    mova        [dstq+32*0], m0
+    movu                 m0, [tlq+r3*2+32]
+    movu                 m1, [tlq+r3*2+34]
+    add                 r5d, dxd
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    pcmpgtw              m2, m7, m3
+    paddw                m3, m4
+    paddw                m0, m1
+    vpblendvb            m0, m6, m0, m2
+    mova        [dstq+32*1], m0
+    dec                  hd
+    jz .w32_end
+    add                dstq, strideq
+    cmp                 r5d, maxbased
+    jb .w32_loop
+.w32_end_loop:
+    mova        [dstq+32*0], m6
+    mova        [dstq+32*1], m6
+    add                dstq, strideq
+    dec                  hd
+    jg .w32_end_loop
+.w32_end:
+    RET
+.w64:
+    ALLOC_STACK        -256, 10
+    lea            maxbased, [hq+63]
+    test             angled, 0x400
+    jnz .w64_main
+    vpbroadcastd         m2, [pw_3]
+    mova                 m0, [tlq-2]       ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    punpcklwd           xm1, xm0, xm0
+    vpblendd             m1, [tlq-4], 0xfe ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    paddw                m0, [tlq+0]       ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    paddw                m1, m2
+    paddw                m0, [tlq+2]       ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    pavgw                m1, [tlq+4]       ; 3 4 5 6 7 8 9 a   b c d e f g h i
+    mov                  r3, rsp
+    paddw                m0, m1
+    lea                 r5d, [hq+32]
+    psrlw                m0, 2
+    mova               [r3], m0
+.w64_filter_loop:
+    mova                 m0, [tlq+30]
+    paddw                m1, m2, [tlq+28]
+    add                 tlq, 32
+    paddw                m0, [tlq+0]
+    pavgw                m1, [tlq+4]
+    paddw                m0, [tlq+2]
+    add                  r3, 32
+    paddw                m0, m1
+    psrlw                m0, 2
+    mova               [r3], m0
+    sub                 r5d, 16
+    jg .w64_filter_loop
+    movu                 m0, [tlq+32]           ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    punpckhwd            m1, m0, m0
+    paddw                m2, [tlq+28]           ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    paddw                m0, [tlq+30]           ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    vpblendd             m3, m1, [tlq+36], 0x7f ; 4 5 6 7 8 9 a b   c d e f g h h h
+    vpblendd             m1, [tlq+34], 0x7f     ; 3 4 5 6 7 8 9 a   b c d e f g h h
+    pavgw                m2, m3
+    paddw                m0, m1
+    paddw                m0, m2
+    mov                 tlq, rsp
+    psrlw                m0, 2
+    mova            [r3+32], m0
+.w64_main:
+    movd                xm4, dxd
+    vpbroadcastw         m6, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m4, xm4
+    movd                xm0, maxbased
+    mov                 r5d, dxd
+    vpbroadcastd         m7, [pw_m1024] ; -16 * 64
+    vpbroadcastw         m0, xm0
+    paddw                m3, m4, [z_base_inc]
+    paddw                m8, m7, m7     ; -32 * 64
+    psubw                m3, m0
+    paddw                m9, m8, m7     ; -48 * 64
+.w64_loop:
+    mov                 r3d, r5d
+    shr                 r3d, 6
+    movu                 m0, [tlq+r3*2]
+    movu                 m1, [tlq+r3*2+2]
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    psraw                m1, m3, 15
+    vpblendvb            m0, m6, m0, m1
+    mova        [dstq+32*0], m0
+    movu                 m0, [tlq+r3*2+32]
+    movu                 m1, [tlq+r3*2+34]
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    pcmpgtw              m1, m7, m3
+    vpblendvb            m0, m6, m0, m1
+    mova        [dstq+32*1], m0
+    movu                 m0, [tlq+r3*2+64]
+    movu                 m1, [tlq+r3*2+66]
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    pcmpgtw              m1, m8, m3
+    vpblendvb            m0, m6, m0, m1
+    mova        [dstq+32*2], m0
+    movu                 m0, [tlq+r3*2+96]
+    movu                 m1, [tlq+r3*2+98]
+    add                 r5d, dxd
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    pcmpgtw              m2, m9, m3
+    paddw                m3, m4
+    paddw                m0, m1
+    vpblendvb            m0, m6, m0, m2
+    mova        [dstq+32*3], m0
+    dec                  hd
+    jz .w64_end
+    add                dstq, strideq
+    cmp                 r5d, maxbased
+    jb .w64_loop
+.w64_end_loop:
+    mova        [dstq+32*0], m6
+    mova        [dstq+32*1], m6
+    mova        [dstq+32*2], m6
+    mova        [dstq+32*3], m6
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_end_loop
+.w64_end:
+    RET
+
+cglobal ipred_z2_16bpc, 3, 12, 12, 352, dst, stride, tl, w, h, angle, dx, dy
+%define base r9-z_filter_t0
+    lea                  r9, [ipred_z2_16bpc_avx2_table]
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    movifnidn            hd, hm
+    lea                 dxq, [dr_intra_derivative-90]
+    movsxd               wq, [r9+wq*4]
+    mova                 m1, [tlq-  0]
+    movzx               dyd, angleb
+    xor              angled, 0x400
+    mova                 m2, [tlq- 32]
+    mov                  r8, dxq
+    sub                 dxq, dyq
+    mova                 m3, [tlq- 64]
+    add                  wq, r9
+    add                  r9, z_filter_t0-ipred_z2_16bpc_avx2_table
+    mova                 m4, [tlq- 96]
+    and                 dyd, ~1
+    mova                 m5, [tlq-128]
+    and                 dxq, ~1
+    movzx               dyd, word [r8+dyq]  ; angle - 90
+    movzx               dxd, word [dxq+270] ; 180 - angle
+    vpbroadcastd        m11, [base+pw_62]
+    mova          [rsp+128], m1
+    mova          [rsp+ 96], m2
+    mova          [rsp+ 64], m3
+    neg                 dxd
+    mova          [rsp+ 32], m4
+    neg                 dyq
+    mova          [rsp+  0], m5
+    jmp                  wq
+.w4:
+    vbroadcasti128      m10, [base+z2_x_shuf]
+    vpbroadcastq         m6, [base+z_base_inc+2]
+    lea                 r8d, [dxq+(65<<6)] ; xpos
+    mov                r10d, (63-4)<<6
+    test             angled, 0x400
+    jnz .w4_main ; !enable_intra_edge_filter
+    lea                 r3d, [hq+2]
+    add              angled, 1022
+    shl                 r3d, 6
+    test                r3d, angled
+    jnz .w4_no_upsample_above ; angle >= 130 || h > 8 || (is_sm && h == 8)
+    movq                xm0, [tlq+2]    ; 1 2 3 4
+    movq                xm1, [tlq+0]    ; 0 1 2 3
+    pshuflw             xm2, xm0, q3321 ; 2 3 4 4
+    pshuflw             xm3, xm1, q2100 ; 0 0 1 2
+    vpbroadcastw        xm4, r8m        ; pixel_max
+    vbroadcasti128      m10, [base+z_upsample]
+    paddw               xm1, xm0
+    paddw               xm2, xm3
+    lea                 r8d, [r8+dxq+(1<<6)]
+    psubw               xm2, xm1, xm2
+    add                 dxd, dxd
+    psraw               xm2, 3
+    pxor                xm3, xm3
+    sub                r10d, 3<<6
+    paddw               xm1, xm2
+    paddw                m6, m6
+    pmaxsw              xm1, xm3
+    sub              angled, 1075 ; angle - 53
+    pavgw               xm1, xm3
+    lea                 r3d, [hq+3]
+    pminsw              xm1, xm4
+    xor              angled, 0x7f ; 180 - angle
+    punpcklwd           xm1, xm0
+    movu          [rsp+130], xm1
+    call .filter_strength
+    jmp .w4_filter_left
+ALIGN function_align
+.filter_strength:
+    movd                xm8, r3d
+    mov                 r3d, angled
+    movd                xm7, angled
+    vpbroadcastb         m8, xm8
+    shr                 r3d, 8 ; is_sm << 1
+    vpbroadcastb         m7, xm7
+    pcmpeqb              m8, [base+z_filter_wh]
+    mova                xm9, [r9+r3*8]
+    pand                 m0, m8, m7
+    pcmpgtb              m0, m9
+    pmovmskb            r3d, m0
+    ret
+ALIGN function_align
+.upsample_left: ; h4/h8
+    mova                xm0, [tlq-16]            ; 8 7 6 5 4 3 2 1
+    movu                xm1, [tlq-14]            ; 7 6 5 4 3 2 1 0
+    vpbroadcastw        xm4, r8m ; pixel_max
+    cmp                  hd, 8
+    je .upsample_left_h8
+    pshufhw             xm2, xm0, q2100          ; _ _ _ _ 4 4 3 2
+    pshufhw             xm3, xm1, q3321          ; _ _ _ _ 2 1 0 0
+    jmp .upsample_left_end
+.upsample_left_h8:
+    pblendw             xm2, xm0, [tlq-18], 0xfe ; 8 8 7 6 5 4 3 2
+    pblendw             xm3, xm1, [tlq-12], 0x7f ; 6 5 4 3 2 1 0 0
+.upsample_left_end:
+    paddw               xm1, xm0
+    paddw               xm2, xm3
+    psubw               xm2, xm1, xm2
+    add                 dyq, dyq
+    psraw               xm2, 3
+    pxor                xm3, xm3
+    paddw               xm1, xm2
+    pmaxsw              xm1, xm3
+    pavgw               xm1, xm3
+    pminsw              xm1, xm4
+    punpcklwd           xm2, xm0, xm1
+    punpckhwd           xm0, xm1
+    mova  [rsp+ 96+gprsize], xm2
+    mova  [rsp+112+gprsize], xm0
+    ret
+.w4_no_upsample_above:
+    lea                 r3d, [hq+3]
+    sub              angled, 1112 ; angle - 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w4_no_filter_above
+    popcnt              r3d, r3d
+    vpbroadcastd        xm4, [base+z_filter_k-4+r3*4+12*1]
+    vpbroadcastd        xm5, [base+z_filter_k-4+r3*4+12*0]
+    psrldq              xm0, xm1, 2     ; 1 2 3 4
+    pshuflw             xm2, xm1, q2100 ; 0 0 1 2
+    pmullw              xm4, xm0
+    pshuflw             xm3, xm0, q3321 ; 2 3 4 4
+    paddw               xm1, xm3
+    pshuflw             xm3, xm0, q3332 ; 3 4 4 4
+    pmullw              xm1, xm5
+    vpbroadcastd        xm5, [base+z_filter_k-4+r3*4+12*2]
+    paddw               xm2, xm3
+    vpbroadcastd        xm3, r6m ; max_width
+    pmullw              xm2, xm5
+    packssdw            xm3, xm3
+    paddw               xm1, xm4
+    paddw               xm1, xm2
+    psubw               xm3, [base+pw_1to16]
+    pxor                xm4, xm4
+    psrlw               xm1, 3
+    pminsw              xm3, xm11 ; clip to byte range since there's no variable word blend
+    pavgw               xm1, xm4
+    vpblendvb           xm1, xm0, xm3
+    movq          [rsp+130], xm1
+.w4_no_filter_above:
+    lea                 r3d, [hq+2]
+    add              angled, 973 ; angle + 883
+    shl                 r3d, 6
+    test                r3d, angled
+    jz .w4_upsample_left ; angle <= 140 || h > 8 || (is_sm && h == 8)
+    vpbroadcastd        xm0, [base+pb_90]
+    psubb               xm0, xm7 ; 180 - angle
+    pand                xm0, xm8 ; reuse from previous filter_strength call
+    pcmpgtb             xm0, xm9
+    pmovmskb            r3d, xm0
+.w4_filter_left:
+    test                r3d, r3d
+    jz .w4_main
+    popcnt              r3d, r3d
+    mova                 m0, [tlq-32]  ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    vpbroadcastd         m5, r7m ; max_height
+    cmp                 r3d, 3
+    je .w4_filter_left_s3
+    vpbroadcastd         m2, [base+z_filter_k-4+r3*4+12*1]
+    vpbroadcastd         m3, [base+z_filter_k-4+r3*4+12*0]
+    pmullw               m2, m0
+    cmp                  hd, 8
+    jl .w4_filter_left_h4
+    movu                 m4, [tlq-34]
+    punpcklwd            m1, m0, m0
+    vpblendd             m1, m4, 0xee  ; 0 0 1 2 3 4 5 6   8 8 9 a b c d e
+    je .w4_filter_left_end
+    vpblendd             m1, m4, 0x10  ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    jmp .w4_filter_left_end
+.w4_upsample_left:
+    call .upsample_left
+    mov                 r11, -16
+    vbroadcasti128       m9, [base+z_upsample]
+    jmp .w4_main_upsample_left
+.w4_filter_left_s3: ; can only be h16
+    movu                 m2, [tlq-30]           ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    vpbroadcastd         m4, [base+pw_3]
+    paddw                m1, m0, m2
+    punpckhwd            m2, m2
+    vpblendd             m2, [tlq-28], 0x7f     ; 2 3 4 5 6 7 8 9   a b c d e f g g
+    punpcklwd           xm3, xm0, xm0
+    paddw                m2, m4
+    vpblendd             m4, m3, [tlq-34], 0xfe ; 0 0 1 2 3 4 5 6   8 8 9 a b c d e
+    vpblendd             m3, [tlq-36], 0xfe     ; 0 0 0 1 2 3 4 5   6 8 8 9 a b c d
+    paddw                m1, m4
+    pavgw                m2, m3
+    paddw                m1, m2
+    psrlw                m1, 2
+    jmp .w4_filter_left_end2
+.w4_filter_left_h4:
+    pshufhw              m1, m0, q2100 ; _ _ _ _ _ _ _ _   _ _ _ _ c c d e
+.w4_filter_left_end:
+    paddw                m1, [tlq-30]  ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    pmullw               m1, m3
+    paddw                m1, m2
+    pxor                 m2, m2
+    psrlw                m1, 3
+    pavgw                m1, m2
+.w4_filter_left_end2:
+    packssdw             m5, m5
+    psubw                m5, [base+pw_16to1]
+    pminsw               m5, m11
+    vpblendvb            m1, m0, m5
+    mova           [rsp+96], m1
+.w4_main:
+    vbroadcasti128       m9, [base+z2_x_shuf]
+    mov                 r11, -8
+.w4_main_upsample_left:
+    movd                xm5, dyd
+    mova                 m4, [base+z2_y_shuf_h4]
+    mov                 r2d, r8d
+    movd                xm0, dxd
+    vpbroadcastw         m5, xm5
+    rorx                 r5, dyq, 5
+    lea                 r8d, [dyq*3]
+    pmullw               m5, [base+z2_ymul]
+    rorx                 r9, dyq, 4
+    sar                 dyd, 6
+    vpbroadcastw         m0, xm0
+    sar                 r8d, 6
+    pand                 m5, m11       ; frac_y
+    neg                 dyd
+    psllw                m5, 9
+    add                 r5d, dyd
+    add                 r8d, dyd
+    add                 r9d, dyd
+    paddw                m7, m0, m0
+    lea                 dyq, [rsp+dyq*2+126]
+    vpblendd             m0, m7, 0xcc
+    add                 dyq, r11
+    neg                 r5d
+    paddw                m1, m0, m7
+    neg                 r8d
+    vpblendd             m0, m1, 0xf0  ; xpos0 xpos1 xpos2 xpos3
+    neg                 r9d
+    paddw                m7, m7
+    paddw                m6, m0
+.w4_loop:
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6         ; base_x0
+    movu                xm1, [rsp+r2*2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6         ; base_x1
+    movu                xm3, [rsp+r3*2]
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6         ; base_x2
+    vinserti128          m1, [rsp+r2*2], 1
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6         ; base_x3
+    vinserti128          m3, [rsp+r3*2], 1
+    pshufb               m1, m10 ; a0 a1 a2 a3 A0 A1 A2 A3
+    pshufb               m3, m10 ; b0 b1 b2 b3 B0 B1 B2 B3
+    pand                 m2, m11, m6
+    punpcklqdq           m0, m1, m3
+    punpckhqdq           m1, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    cmp                 r3d, 64
+    jge .w4_toponly
+    movu                xm2, [dyq]
+    vinserti128          m2, [dyq+r8*2], 1
+    movu                xm3, [dyq+r5*2]
+    vinserti128          m3, [dyq+r9*2], 1
+    pshufb               m2, m9
+    pshufb               m3, m9
+    punpckhwd            m1, m2, m3 ; a3 b3 a2 b2 a1 b1 a0 b0
+    punpcklwd            m2, m3
+    psubw                m2, m1
+    pmulhrsw             m2, m5
+    psraw                m3, m6, 15 ; base_x < topleft
+    paddw                m1, m2
+    vpermd               m1, m4, m1 ; a0 b0 c0 d0 a1 b1 c1 d1   a2 b2 c2 d2 a3 b3 c3 d3
+    vpblendvb            m0, m1, m3
+.w4_toponly:
+    paddw                m6, m7     ; xpos += dx
+    lea                  r3, [strideq*3]
+    add                 dyq, r11
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r3       ], xm1
+    sub                  hd, 4
+    jz .w4_end
+    lea                dstq, [dstq+strideq*4]
+    cmp                 r2d, r10d
+    jge .w4_loop
+.w4_leftonly_loop:
+    movu                xm1, [dyq]
+    vinserti128          m1, [dyq+r8*2], 1
+    movu                xm2, [dyq+r5*2]
+    vinserti128          m2, [dyq+r9*2], 1
+    add                 dyq, r11
+    pshufb               m1, m9
+    pshufb               m2, m9
+    punpckhwd            m0, m1, m2
+    punpcklwd            m1, m2
+    psubw                m1, m0
+    pmulhrsw             m1, m5
+    paddw                m0, m1
+    vpermd               m0, m4, m0
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r3       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_leftonly_loop
+.w4_end:
+    RET
+.w8:
+    mov                r10d, hd
+    test             angled, 0x400
+    jnz .w8_main
+    lea                 r3d, [angleq+126]
+    xor                 r8d, r8d
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_no_upsample_above ; angle >= 130 || h > 8 || is_sm
+    movu                xm0, [tlq+2]            ; 1 2 3 4 5 6 7 8
+    mova                xm1, [tlq+0]            ; 0 1 2 3 4 5 6 7
+    pblendw             xm2, xm0, [tlq+4], 0x7f ; 2 3 4 5 6 7 8 8
+    pblendw             xm3, xm1, [tlq-2], 0xfe ; 0 0 1 2 3 4 5 6
+    vpbroadcastw        xm4, r8m ; pixel_max
+    paddw               xm1, xm0
+    paddw               xm2, xm3
+    not                 r8d
+    psubw               xm2, xm1, xm2
+    add                 dxd, dxd
+    psraw               xm2, 3
+    sub              angled, 53 ; angle - 53
+    pxor                xm3, xm3
+    paddw               xm2, xm1
+    lea                 r3d, [hq+7]
+    pmaxsw              xm2, xm3
+    xor              angled, 0x7f ; 180 - angle
+    pavgw               xm2, xm3
+    pminsw              xm2, xm4
+    punpcklwd           xm1, xm2, xm0
+    punpckhwd           xm2, xm0
+    movu          [rsp+130], xm1
+    movu          [rsp+146], xm2
+    call .filter_strength
+    jmp .w8_filter_left
+.w8_no_upsample_above:
+    lea                 r3d, [hq+7]
+    sub              angled, 90 ; angle - 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w8_no_filter_above
+    popcnt              r3d, r3d
+    vpbroadcastd        xm4, [base+z_filter_k-4+r3*4+12*1]
+    vpbroadcastd        xm5, [base+z_filter_k-4+r3*4+12*0]
+    vpbroadcastd        xm6, [base+z_filter_k-4+r3*4+12*2]
+    movu                xm0, [tlq+2]            ; 1 2 3 4 5 6 7 8 x
+    pblendw             xm2, xm1, [tlq-2], 0xfe ; 0 0 1 2 3 4 5 6 x
+    pmullw              xm4, xm0
+    pblendw             xm3, xm0, [tlq+4], 0x7f ; 2 3 4 5 6 7 8 8 x
+    paddw               xm1, xm3
+    vpblendd            xm3, [tlq+6], 0x07      ; 3 4 5 6 7 8 8 8 x
+    paddw               xm2, xm3
+    vpbroadcastd        xm3, r6m ; max_width
+    pmullw              xm1, xm5
+    pmullw              xm2, xm6
+    packssdw            xm3, xm3
+    paddw               xm1, xm4
+    paddw               xm1, xm2
+    psubw               xm3, [base+pw_1to16]
+    pxor                xm4, xm4
+    psrlw               xm1, 3
+    pminsw              xm3, xm11
+    pavgw               xm1, xm4
+    vpblendvb           xm1, xm0, xm3
+    movu          [rsp+130], xm1
+.w8_no_filter_above:
+    lea                 r3d, [angleq-51]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    jbe .w8_upsample_left ; angle > 140 && h <= 8 && !is_sm
+    vpbroadcastd         m0, [base+pb_90]
+    psubb                m0, m7
+    pand                 m0, m8
+    pcmpgtb              m0, m9
+    pmovmskb            r3d, m0
+.w8_filter_left:
+    test                r3d, r3d
+    jz .w8_main
+    popcnt              r3d, r3d
+    cmp                 r3d, 3
+    jne .w8_filter_left_s12
+    vpbroadcastd         m6, [base+pw_3]
+    vpbroadcastd         m7, [base+pw_16]
+    cmp                  hd, 16 ; flags needed for later
+    jmp .filter_left_s3b
+.w8_upsample_left:
+    call .upsample_left
+    vbroadcasti128       m7, [base+z2_y_shuf_us]
+    lea                 r11, [rsp+118]
+    mov                  r8, -8
+    jmp .w8_main_upsample_left
+.w16_filter_left_s12:
+    xor                 r8d, r8d
+.w8_filter_left_s12:
+    mova                 m0, [tlq-32]  ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    vpbroadcastd         m5, r7m ; max_height
+    vpbroadcastd         m2, [base+z_filter_k-4+r3*4+12*1]
+    vpbroadcastd         m3, [base+z_filter_k-4+r3*4+12*0]
+    pmullw               m2, m0
+    cmp                  hd, 8
+    jl .w8_filter_left_h4
+    movu                 m4, [tlq-34]
+    punpcklwd            m1, m0, m0
+    vpblendd             m1, m4, 0xee  ; 0 0 1 2 3 4 5 6   8 8 9 a b c d e
+    je .w8_filter_left_end
+    vpblendd             m1, m4, 0x10  ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    jmp .w8_filter_left_end
+.w8_filter_left_h4:
+    pshufhw              m1, m0, q2100 ; _ _ _ _ _ _ _ _   _ _ _ _ c c d e
+.w8_filter_left_end:
+    paddw                m1, [tlq-30]  ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    pmullw               m1, m3
+    paddw                m1, m2
+    pxor                 m2, m2
+    psrlw                m1, 3
+    pavgw                m1, m2
+    packssdw             m5, m5
+    psubw                m5, [base+pw_16to1]
+    pminsw               m5, m11
+    vpblendvb            m1, m0, m5
+    mova           [rsp+96], m1
+    test                r8d, r8d
+    jz .w8_main
+; upsample_main
+    vbroadcasti128      m10, [base+z_upsample]
+    vbroadcasti128       m7, [base+z2_y_shuf]
+    lea                  r5, [rsp+120]
+    movd                xm1, dyd
+    vbroadcasti128       m4, [base+z_base_inc+2]
+    movd                xm2, dxd
+    vpbroadcastw         m1, xm1
+    vpbroadcastw         m2, xm2
+    mov                  r7, dstq
+    paddw                m4, m4
+    pmullw               m0, m1, [base+z2_ymul8]
+    paddw                m5, m2, m2
+    psllw               xm1, 3
+    vpblendd             m2, m5, 0xf0
+    lea                 r2d, [dxq+(66<<6)] ; xpos
+    paddw                m4, m2
+    pshufd               m6, m0, q2020
+    psraw               xm0, 6
+    pxor                xm1, xm1
+    psubw               xm8, xm1, xm0
+    pand                 m6, m11
+    punpckhwd           xm9, xm8, xm1
+    psllw                m6, 9
+    punpcklwd           xm8, xm1
+.w8_upsample_above_loop:
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6
+    movu                xm1, [rsp+r2*2]
+    movu                xm2, [rsp+r2*2+16]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6
+    vinserti128          m1, [rsp+r3*2], 1
+    vinserti128          m2, [rsp+r3*2+16], 1
+    pshufb               m1, m10
+    pshufb               m2, m10
+    punpcklqdq           m0, m1, m2   ; a0 b0 c0 d0 e0 f0 g0 h0
+    punpckhqdq           m1, m2
+    pand                 m2, m11, m4
+    psubw                m1, m0
+    psllw                m2, 9
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    cmp                 r3d, 64
+    jge .w8_upsample_above_toponly
+    mova                 m1, m5
+    vpgatherdq           m3, [r5+xm9*2], m5
+    mova                 m5, m1
+    vpgatherdq           m2, [r5+xm8*2], m1
+    pshufb               m3, m7
+    pshufb               m2, m7
+    punpckldq            m1, m2, m3
+    punpckhdq            m2, m3
+    psubw                m2, m1
+    pmulhrsw             m2, m6
+    paddw                m1, m2
+    vpermq               m1, m1, q3120
+    psraw                m2, m4, 15
+    vpblendvb            m0, m1, m2
+.w8_upsample_above_toponly:
+    paddw                m4, m5
+    sub                  r5, 4
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    sub                  hd, 2
+    jz .w8_ret
+    lea                dstq, [dstq+strideq*2]
+    jmp .w8_upsample_above_loop
+.w8_main:
+    vbroadcasti128       m7, [base+z2_y_shuf]
+    lea                 r11, [rsp+120]
+    mov                  r8, -4
+.w8_main_upsample_left:
+    movd                xm1, dyd
+    vbroadcasti128       m4, [base+z_base_inc+2]
+    movd                xm2, dxd
+    vpbroadcastw         m1, xm1
+    vpbroadcastw         m2, xm2
+    mov                  r7, dstq
+    pmullw               m0, m1, [base+z2_ymul8]
+    paddw                m5, m2, m2
+    psllw               xm1, 3
+    vpblendd             m2, m5, 0xf0 ; xpos0 xpos1
+    lea                 r9d, [dxq+(65<<6)] ; xpos
+    paddw                m4, m2
+    movd          [rsp+284], xm1
+.w8_loop0:
+    mov                 r2d, r9d
+    mova          [rsp+288], m0
+    mov                  r5, r11
+    mova          [rsp+320], m4
+    pshufd               m6, m0, q2020
+    psraw               xm0, 6
+    pxor                xm1, xm1
+    psubw               xm8, xm1, xm0 ; base_y
+    pand                 m6, m11      ; frac_y
+    punpckhwd           xm9, xm8, xm1 ; base_y 2 3 6 7
+    psllw                m6, 9
+    punpcklwd           xm8, xm1      ; base_y 0 1 4 5
+.w8_loop:
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6        ; base_x0
+    movu                xm0, [rsp+r2*2]
+    movu                xm1, [rsp+r2*2+2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6        ; base_x1
+    vinserti128          m0, [rsp+r3*2], 1
+    vinserti128          m1, [rsp+r3*2+2], 1
+    pand                 m2, m11, m4
+    psubw                m1, m0
+    psllw                m2, 9
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    cmp                 r3d, 64
+    jge .w8_toponly
+    mova                 m1, m5
+    vpgatherdq           m3, [r5+xm9*2], m5
+    mova                 m5, m1
+    vpgatherdq           m2, [r5+xm8*2], m1
+    pshufb               m3, m7       ; c0 d0 c1 d1               g0 h0 g1 h1
+    pshufb               m2, m7       ; a0 b0 a1 b1               e0 f0 e1 f1
+    punpckldq            m1, m2, m3   ; a0 b0 c0 d0 a1 b1 c1 d1   e0 f0 g0 h0 e1 f1 g1 h1
+    punpckhdq            m2, m3
+    psubw                m2, m1
+    pmulhrsw             m2, m6
+    paddw                m1, m2
+    vpermq               m1, m1, q3120
+    psraw                m2, m4, 15   ; base_x < topleft
+    vpblendvb            m0, m1, m2
+.w8_toponly:
+    paddw                m4, m5       ; xpos += dx
+    add                  r5, r8
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    sub                  hd, 2
+    jz .w8_end
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r2d, (63-8)<<6
+    jge .w8_loop
+.w8_leftonly_loop:
+    mova                 m0, m5
+    vpgatherdq           m4, [r5+xm9*2], m5
+    mova                 m5, m0
+    vpgatherdq           m3, [r5+xm8*2], m0
+    add                  r5, r8
+    pshufb               m2, m4, m7
+    pshufb               m1, m3, m7
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    psubw                m1, m0
+    pmulhrsw             m1, m6
+    paddw                m0, m1
+    vpermq               m0, m0, q3120
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_leftonly_loop
+.w8_end:
+    sub                r10d, 1<<8
+    jl .w8_ret
+    vpbroadcastd         m0, [rsp+284]
+    add                  r7, 16
+    paddw                m0, [rsp+288] ; base_y += 8*dy
+    add                 r9d, 8<<6
+    vpbroadcastd         m4, [pw_512]
+    movzx                hd, r10b
+    paddw                m4, [rsp+320] ; base_x += 8*64
+    mov                dstq, r7
+    jmp .w8_loop0
+.w8_ret:
+    RET
+.w16:
+    movd                xm0, [tlq+32]
+    lea                r10d, [hq+(1<<8)]
+    movd          [rsp+160], xm0
+    test             angled, 0x400
+    jnz .w8_main
+    lea                 r3d, [hq+15]
+    sub              angled, 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w16_no_filter_above
+    popcnt              r3d, r3d
+    vpbroadcastd         m4, [base+z_filter_k-4+r3*4+12*1]
+    vpbroadcastd         m5, [base+z_filter_k-4+r3*4+12*0]
+    vpbroadcastd         m6, [base+z_filter_k-4+r3*4+12*2]
+    movu                 m0, [tlq+2]           ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    punpcklwd           xm2, xm1, xm1
+    vpblendd             m2, [tlq-2], 0xfe     ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    punpckhwd            m3, m0, m0
+    pmullw               m4, m0
+    vpblendd             m3, [tlq+4], 0x7f     ; 2 3 4 5 6 7 8 9   a b c d e f g g
+    paddw                m1, m3
+    vpblendd             m3, [tlq+6], 0x7f     ; 3 4 5 6 7 8 9 a   b c d e f g g g
+    paddw                m2, m3
+    vpbroadcastd         m3, r6m ; max_width
+    pmullw               m1, m5
+    pmullw               m2, m6
+    packssdw             m3, m3
+    paddw                m1, m4
+    paddw                m1, m2
+    psubw                m3, [base+pw_1to16]
+    pxor                 m4, m4
+    psrlw                m1, 3
+    pminsw               m3, m11
+    pavgw                m1, m4
+    vpblendvb            m1, m0, m3
+    movu          [rsp+130], m1
+.w16_no_filter_above:
+    vpbroadcastd         m0, [base+pb_90]
+    psubb                m0, m7
+    pand                 m0, m8
+    pcmpgtb              m0, m9
+    pmovmskb            r3d, m0
+    test                r3d, r3d
+    jz .w8_main
+    popcnt              r3d, r3d
+    cmp                 r3d, 3
+    jne .w16_filter_left_s12
+    vpbroadcastd         m6, [base+pw_3]
+    vpbroadcastd         m7, [base+pw_16]
+    cmp                  hd, 4
+    jne .filter_left_s3
+    movq                xm0, [tlq-8]    ; 0 1 2 3
+    movq                xm1, [tlq-6]    ; 1 2 3 4
+    vpbroadcastd        xm5, r7m ; max_height
+    movq                xm4, [base+pw_16to1+24] ; 4to1
+    pshuflw             xm2, xm0, q2100 ; 0 0 1 2
+    pshuflw             xm3, xm1, q3321 ; 2 3 4 4
+    paddw               xm1, xm0
+    paddw               xm1, xm2
+    pshuflw             xm2, xm0, q1000 ; 0 0 0 1
+    paddw               xm3, xm6
+    packssdw            xm5, xm5
+    pavgw               xm2, xm3
+    psubw               xm5, xm4
+    paddw               xm1, xm2
+    pminsw              xm5, xm11
+    psrlw               xm1, 2
+    vpblendvb           xm1, xm0, xm5
+    movq          [rsp+120], xm1
+    jmp .w8_main
+.w32:
+    mova                 m2, [tlq+32]
+    movd                xm0, [tlq+64]
+    lea                r10d, [hq+(3<<8)]
+    mova          [rsp+160], m2
+    movd          [rsp+192], xm0
+    test             angled, 0x400
+    jnz .w8_main
+    vpbroadcastd         m6, [base+pw_3]
+    vpbroadcastd         m0, r6m ; max_width
+    vpbroadcastd         m7, [base+pw_16]
+    mov                 r3d, 32
+    packssdw             m0, m0
+    psubw                m0, [base+pw_1to16]
+    pminsw               m8, m0, m11
+    psubw                m9, m8, m7
+.w32_filter_above:
+    movu                 m0, [tlq+2]
+    punpcklwd           xm4, xm1, xm1
+    paddw                m2, m6, [tlq+6]
+    paddw                m1, m0
+    vpblendd             m4, [tlq-2], 0xfe        ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    paddw                m1, [tlq+4]
+    movu                 m3, [tlq+r3+2]
+    paddw                m5, m6, [tlq+r3-2]
+    pavgw                m2, m4
+    punpckhwd            m4, m3, m3
+    paddw                m1, m2
+    vpblendd             m2, m4, [tlq+r3+6], 0x7f ; 4 5 6 7 8 9 a b   c d e f g h h h
+    vpblendd             m4, [tlq+r3+4], 0x7f     ; 3 4 5 6 7 8 9 a   b c d e f g h h
+    pavgw                m2, m5
+    paddw                m5, m3, [tlq+r3]
+    paddw                m4, m5
+    psrlw                m1, 2
+    paddw                m2, m4
+    vpblendvb            m1, m0, m8
+    psrlw                m2, 2
+    vpblendvb            m2, m3, m9
+    movu          [rsp+130], m1
+    movu       [rsp+r3+130], m2
+.filter_left_s3:
+    cmp                  hd, 16
+    jl .filter_left_s3_h8 ; h8
+.filter_left_s3b:
+    mova                 m0, [tlq-32]       ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    movu                 m2, [tlq-30]       ; 3 4 5 6 7 8 9 a   b c d e f g h i
+    vpbroadcastd         m5, r7m ; max_height
+    paddw                m1, m0, m2
+    punpckhwd            m2, m2
+    mov                 r3d, hd
+    vpblendd             m2, [tlq-28], 0x7f ; 4 5 6 7 8 9 a b   c d e f g h i i
+    packssdw             m5, m5
+    not                  r3
+    psubw                m5, [base+pw_16to1]
+    paddw                m2, m6
+    pminsw               m8, m11, m5
+    je .filter_left_s3_end ; h16
+    paddw                m1, [tlq-34]       ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    pavgw                m2, [tlq-36]       ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    paddw                m1, m2
+    psrlw                m1, 2
+    vpblendvb            m3, m1, m0, m8
+    mova                 m0, [tlq-64]       ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    paddw                m1, m0, [tlq-62]   ; 3 4 5 6 7 8 9 a   b c d e f g h i
+    paddw                m2, m6, [tlq-60]   ; 4 5 6 7 8 9 a b   c d e f g h i j
+    psubw                m8, m7
+    mova           [rsp+96], m3
+    jnp .filter_left_s3_end ; h32
+    mova                 m5, [tlq-96]
+    paddw                m1, [tlq-66]
+    pavgw                m2, [tlq-68]
+    paddw                m1, m2
+    paddw                m4, m5, [tlq-94]
+    paddw                m2, m6, [tlq-92]
+    psrlw                m1, 2
+    paddw                m4, [tlq- 98]
+    pavgw                m2, [tlq-100]
+    vpblendvb            m3, m1, m0, m8
+    mova                 m0, [tlq-128]
+    psubw                m8, m7
+    paddw                m4, m2
+    paddw                m1, m0, [tlq-126]
+    paddw                m2, m6, [tlq-124]
+    psrlw                m4, 2
+    mova           [rsp+64], m3
+    vpblendvb            m4, m5, m8
+    psubw                m8, m7
+    mova           [rsp+32], m4
+.filter_left_s3_end:
+    punpcklwd           xm3, xm0, xm0
+    vpblendd             m4, m3, [tlq+r3*2], 0xfe ; 2 2 3 4 5 6 7 8   9 a b c d e f g
+    vpblendd             m3, [tlq+r3*2-2], 0xfe   ; 2 2 2 3 4 5 6 7   8 9 a b c d e f
+    paddw                m1, m4
+    pavgw                m2, m3
+    paddw                m1, m2
+    psrlw                m1, 2
+    vpblendvb            m1, m0, m8
+    mova     [rsp+r3*2+130], m1
+    jmp .w8_main
+.filter_left_s3_h8:
+    mova                xm0, [tlq-16]            ; 0 1 2 3 4 5 6 7
+    movu                xm3, [tlq-14]            ; 1 2 3 4 5 6 7 8
+    pblendw             xm2, xm0, [tlq-18], 0xfe ; 0 0 1 2 3 4 5 6
+    vpbroadcastd        xm5, r7m ; max_height
+    paddw               xm1, xm0, xm3
+    pblendw             xm3, [tlq-12], 0x7f      ; 2 3 4 5 6 7 8 8
+    paddw               xm1, xm2
+    vpblendd            xm2, [tlq-20], 0x0e      ; 0 0 0 1 2 3 4 5
+    paddw               xm3, xm6
+    packssdw            xm5, xm5
+    pavgw               xm2, xm3
+    psubw               xm5, [base+pw_16to1+16] ; 8to1
+    paddw               xm1, xm2
+    pminsw              xm5, xm11
+    psrlw               xm1, 2
+    vpblendvb           xm1, xm0, xm5
+    mova          [rsp+112], xm1
+    jmp .w8_main
+.w64:
+    mova                 m2, [tlq+ 32]
+    mova                 m3, [tlq+ 64]
+    mova                 m4, [tlq+ 96]
+    movd                xm0, [tlq+128]
+    lea                r10d, [hq+(7<<8)]
+    mova          [rsp+160], m2
+    mova          [rsp+192], m3
+    mova          [rsp+224], m4
+    movd          [rsp+256], xm0
+    test             angled, 0x400
+    jnz .w8_main
+    vpbroadcastd         m6, [base+pw_3]
+    movu                 m0, [tlq+34]     ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    paddw                m2, m6, [tlq+30] ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    paddw                m5, m0, [tlq+32] ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    pavgw                m2, [tlq+38]     ; 4 5 6 7 8 9 a b   c d e f g h h h
+    paddw                m5, [tlq+36]     ; 3 4 5 6 7 8 9 a   b c d e f g h h
+    movu                 m4, [tlq+66]
+    paddw                m3, m6, [tlq+62]
+    paddw                m7, m4, [tlq+64]
+    pavgw                m3, [tlq+70]
+    paddw                m7, [tlq+68]
+    paddw                m2, m5
+    vpbroadcastd         m5, r6m ; max_width
+    mov                 r3d, 96
+    packssdw             m5, m5
+    paddw                m3, m7
+    psubw                m5, [base+pw_1to16]
+    psrlw                m2, 2
+    vpbroadcastd         m7, [base+pw_16]
+    psrlw                m3, 2
+    pminsw               m8, m11, m5
+    psubw                m9, m8, m7
+    vpblendvb            m2, m0, m9
+    psubw                m9, m7
+    vpblendvb            m3, m4, m9
+    psubw                m9, m7
+    movu          [rsp+162], m2
+    movu          [rsp+194], m3
+    jmp .w32_filter_above
+
+cglobal ipred_z3_16bpc, 4, 9, 0, dst, stride, tl, w, h, angle, dy, org_w, maxbase
+    lea                  r6, [ipred_z3_16bpc_avx2_table]
+    tzcnt                hd, hm
+    movifnidn        angled, anglem
+    lea                  r7, [dr_intra_derivative+45*2-1]
+    sub                 tlq, 2
+    movsxd               hq, [r6+hq*4]
+    sub              angled, 180
+    add                  hq, r6
+    mov                 dyd, angled
+    neg                 dyd
+    xor              angled, 0x400
+    or                  dyq, ~0x7e
+    movzx               dyd, word [r7+dyq]
+    vpbroadcastd         m5, [pw_62]
+    mov              org_wd, wd
+    jmp                  hq
+.h4:
+    ALLOC_STACK         -64, 7
+    lea                  r7, [strideq*3]
+    cmp              angleb, 40
+    jae .h4_no_upsample
+    lea                 r4d, [angleq-1024]
+    sar                 r4d, 7
+    add                 r4d, wd
+    jg .h4_no_upsample ; !enable_intra_edge_filter || w > 8 || (w == 8 && is_sm)
+    mova                xm2, [tlq-14]            ; 0 1 2 3 4 5 6 7
+    pblendw             xm1, xm2, [tlq-16], 0xfe ; 0 0 1 2 3 4 5 6
+    vpblendd            xm0, xm1, [tlq-18], 0x0e ; 0 0 0 1 2 3 4 5
+    pshufd              xm3, xm1, q0000
+    paddw               xm1, xm2
+    paddw               xm0, [tlq-12]            ; 1 2 3 4 5 6 7 8
+    vpbroadcastw        xm4, r8m ; pixel_max
+    add                 dyd, dyd
+    psubw               xm0, xm1, xm0
+    mova           [rsp+ 0], xm3
+    movd                xm3, dyd
+    psraw               xm0, 3
+    neg                 dyd
+    paddw               xm1, xm0
+    pxor                xm0, xm0
+    lea                 r2d, [dyq+(16<<6)+63] ; ypos
+    pmaxsw              xm1, xm0
+    pavgw               xm1, xm0
+    vpbroadcastw         m3, xm3
+    pminsw              xm1, xm4
+    punpckhwd           xm0, xm1, xm2
+    punpcklwd           xm1, xm2
+    paddw                m2, m3, m3
+    mova           [rsp+32], xm0
+    punpcklwd            m3, m2
+    mova           [rsp+16], xm1
+    paddw                m4, m2, m2
+    paddw                m2, m3
+    vpblendd             m3, m2, 0xf0 ; ypos0 ypos1   ypos2 ypos3
+.h4_upsample_loop:
+    lea                 r4d, [r2+dyq]
+    shr                 r2d, 6
+    movu                xm1, [rsp+r2*2]
+    lea                 r2d, [r4+dyq]
+    shr                 r4d, 6
+    movu                xm2, [rsp+r4*2]
+    lea                 r4d, [r2+dyq]
+    shr                 r2d, 6
+    vinserti128          m1, [rsp+r2*2], 1
+    lea                 r2d, [r4+dyq]
+    shr                 r4d, 6
+    vinserti128          m2, [rsp+r4*2], 1
+    psrld                m0, m1, 16
+    pblendw              m0, m2, 0xaa ; a3 b3 a2 b2 a1 b1 a0 b0   c3 d3 c2 d2 c1 d1 c0 d0
+    pslld                m2, 16
+    pblendw              m1, m2, 0xaa
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m3, m4
+    paddw                m1, m0
+    vextracti128        xm2, m1, 1
+    punpckhdq           xm0, xm1, xm2 ; a1 b1 c1 d1 a0 b0 c0 d0
+    punpckldq           xm1, xm2      ; a3 b3 c3 d3 a2 b2 c2 d2
+    movhps [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm0
+    movhps [dstq+strideq*2], xm1
+    movq   [dstq+r7       ], xm1
+    add                dstq, 8
+    sub                  wd, 4
+    jg .h4_upsample_loop
+    RET
+ALIGN function_align
+.filter_strength: ; h4/h8/h16
+%define base r4-z_filter_t0
+    lea                  r4, [z_filter_t0]
+    movd                xm0, maxbased
+    movd                xm1, angled
+    shr              angled, 8 ; is_sm << 1
+    vpbroadcastb         m0, xm0
+    vpbroadcastb         m1, xm1
+    pcmpeqb              m0, [base+z_filter_wh]
+    pand                 m0, m1
+    mova                xm1, [r4+angleq*8]
+    pcmpgtb              m0, m1
+    pmovmskb            r5d, m0
+    ret
+.h4_no_upsample:
+    mov            maxbased, 7
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h4_main
+    lea            maxbased, [wq+3]
+    call .filter_strength
+    mov            maxbased, 7
+    test                r5d, r5d
+    jz .h4_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    mova                xm0, [tlq-14]       ; 0 1 2 3 4 5 6 7
+    movu                xm3, [tlq-12]       ; 1 2 3 4 5 6 7 8
+    vpbroadcastd        xm2, [base+z_filter_k-4+r5*4+12*1]
+    vpbroadcastd        xm4, [base+z_filter_k-4+r5*4+12*0]
+    pmullw              xm2, xm0
+    pblendw             xm0, [tlq-16], 0xfe ; 0 0 1 2 3 4 5 6
+    paddw               xm1, xm0, xm3
+    movd           [rsp+12], xm0
+    pmullw              xm1, xm4
+    cmp                 r5d, 3
+    jne .h4_filter_3tap
+    pblendw             xm3, [tlq-10], 0x7f ; 2 3 4 5 6 7 8 8
+    vpblendd            xm0, [tlq-18], 0x0e ; 0 0 0 1 2 3 4 5
+    movzx               r4d, word [tlq-14]
+    movzx               r2d, word [tlq-12]
+    inc            maxbased
+    paddw               xm1, xm2
+    paddw               xm0, xm3
+    sub                 r2d, r4d
+    paddw               xm2, xm0, xm0
+    lea                 r2d, [r2+r4*8+4]
+    shr                 r2d, 3
+    mov            [rsp+14], r2w
+.h4_filter_3tap:
+    pxor                xm0, xm0
+    paddw               xm1, xm2
+    lea                 tlq, [rsp+30]
+    psrlw               xm1, 3
+    cmp                  wd, 8
+    sbb            maxbased, -1
+    pavgw               xm0, xm1
+    mova           [rsp+16], xm0
+.h4_main:
+    movd                xm3, dyd
+    neg            maxbaseq
+    vbroadcasti128       m1, [z_base_inc]
+    vpbroadcastw         m6, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m3, xm3
+    lea                 r4d, [maxbaseq+3*64]
+    neg                 dyq
+    movd                xm2, r4d
+    sub                 tlq, 8
+    lea                  r4, [dyq+63] ; ypos
+    punpcklwd            m1, m1
+    paddw                m0, m3, m3
+    vpbroadcastw         m2, xm2
+    punpcklwd            m3, m0
+    paddw                m4, m0, m0
+    paddw                m0, m3
+    psubw                m2, m1
+    vpblendd             m3, m0, 0xf0 ; ypos0 ypos1   ypos2 ypos3
+    or             maxbased, 63
+    paddw                m3, m2
+.h4_loop:
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6 ; base0
+    movu                xm1, [tlq+r4*2]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6 ; base1
+    movu                xm2, [tlq+r5*2]
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6 ; base2
+    vinserti128          m1, [tlq+r4*2], 1
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6 ; base3
+    vinserti128          m2, [tlq+r5*2], 1
+    punpckhwd            m0, m1, m2
+    punpcklwd            m1, m2
+    pand                 m2, m5, m3
+    palignr              m0, m1, 4    ; a3 b3 a2 b2 a1 b1 a0 b0   c3 d3 c2 d2 c1 d1 c0 d0
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    psraw                m2, m3, 15   ; ypos < max_base_y
+    paddw                m3, m4
+    paddw                m1, m0
+    vpblendvb            m1, m6, m1, m2
+    vextracti128        xm2, m1, 1
+    punpckhdq           xm0, xm1, xm2 ; a1 b1 c1 d1 a0 b0 c0 d0
+    punpckldq           xm1, xm2      ; a3 b3 c3 d3 a2 b2 c2 d2
+    movhps [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm0
+    movhps [dstq+strideq*2], xm1
+    movq   [dstq+r7       ], xm1
+    sub                  wd, 4
+    jz .h4_end
+    add                dstq, 8
+    cmp                 r4d, maxbased
+    jg .h4_loop
+.h4_end_loop:
+    movq   [dstq+strideq*0], xm6
+    movq   [dstq+strideq*1], xm6
+    movq   [dstq+strideq*2], xm6
+    movq   [dstq+r7       ], xm6
+    add                dstq, 8
+    sub                  wd, 4
+    jg .h4_end_loop
+.h4_end:
+    RET
+.h8:
+    lea                 r4d, [angleq+216]
+    ALLOC_STACK         -64, 8
+    mov                 r4b, wb
+    lea                  r7, [strideq*3]
+    cmp                 r4d, 8
+    ja .h8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || w > 8
+    mova                 m2, [tlq-30]     ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    paddw                m1, m2, [tlq-32] ; _ 0 1 2 3 4 5 6   7 8 9 a b c d e
+    movu                 m0, [tlq-34]     ; _ _ 0 1 2 3 4 5   6 7 8 9 a b c d
+    cmp                  wd, 8
+    je .h8_upsample_w8
+    pshufhw             xm3, xm2, q1000
+    vpblendd             m0, m3, 0x0f     ; _ _ _ _ 4 4 4 5   6 7 8 9 a b c d
+.h8_upsample_w8:
+    paddw                m0, [tlq-28]     ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    vpbroadcastw         m4, r8m ; pixel_max
+    add                 dyd, dyd
+    psubw                m0, m1, m0
+    movd                xm6, dyd
+    psraw                m0, 3
+    neg                 dyd
+    paddw                m1, m0
+    pxor                 m0, m0
+    pmaxsw               m1, m0
+    lea                 r4d, [dyq+(16<<6)+63] ; ypos
+    pavgw                m1, m0
+    vpbroadcastw         m6, xm6
+    pminsw               m1, m4
+    punpckhwd            m0, m1, m2
+    punpcklwd            m1, m2
+    vextracti128   [rsp+48], m0, 1
+    vextracti128   [rsp+32], m1, 1
+    paddw                m7, m6, m6
+    mova           [rsp+16], xm0
+    mova           [rsp+ 0], xm1
+    punpcklwd            m6, m7 ; ypos0 ypos1
+.h8_upsample_loop:
+    lea                 r2d, [r4+dyq]
+    shr                 r4d, 6 ; base0
+    movu                 m1, [rsp+r4*2]
+    lea                 r4d, [r2+dyq]
+    shr                 r2d, 6 ; base1
+    movu                 m2, [rsp+r2*2]
+    lea                 r2d, [r4+dyq]
+    shr                 r4d, 6 ; base2
+    movu                 m3, [rsp+r4*2]
+    lea                 r4d, [r2+dyq]
+    shr                 r2d, 6 ; base3
+    movu                 m4, [rsp+r2*2]
+    psrld                m0, m1, 16
+    pblendw              m0, m2, 0xaa ; a7 b7 a6 b6 a5 b5 a4 b4   a3 b3 a2 b2 a1 b1 a0 b0
+    pslld                m2, 16
+    pblendw              m1, m2, 0xaa
+    psrld                m2, m3, 16
+    pblendw              m2, m4, 0xaa ; c7 d7 c6 d6 c5 d5 c4 d4   c3 d3 c2 d2 c1 d1 c0 d0
+    pslld                m4, 16
+    pblendw              m3, m4, 0xaa
+    pand                 m4, m5, m6
+    paddw                m6, m7
+    psllw                m4, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m4
+    pand                 m4, m5, m6
+    psllw                m4, 9
+    psubw                m3, m2
+    pmulhrsw             m3, m4
+    paddw                m6, m7
+    lea                  r2, [dstq+strideq*4]
+    paddw                m1, m0
+    paddw                m3, m2
+    punpckhdq            m0, m1, m3   ; a5 b5 c5 d5 a4 b4 c4 d4   a1 b1 c1 d1 a0 b0 c0 d0
+    punpckldq            m1, m3       ; a7 b7 c7 d7 a6 b6 c6 d6   a3 b3 c3 d3 a2 b2 c2 d2
+    vextracti128        xm2, m0, 1
+    vextracti128        xm3, m1, 1
+    movhps [r2  +strideq*0], xm0
+    movq   [r2  +strideq*1], xm0
+    movhps [r2  +strideq*2], xm1
+    movq   [r2  +r7       ], xm1
+    movhps [dstq+strideq*0], xm2
+    movq   [dstq+strideq*1], xm2
+    movhps [dstq+strideq*2], xm3
+    movq   [dstq+r7       ], xm3
+    add                dstq, 8
+    sub                  wd, 4
+    jg .h8_upsample_loop
+    RET
+.h8_no_intra_edge_filter:
+    and            maxbased, 7
+    or             maxbased, 8 ; imin(w+7, 15)
+    jmp .h8_main
+.h8_no_upsample:
+    lea            maxbased, [wq+7]
+    test             angled, 0x400
+    jnz .h8_no_intra_edge_filter
+    call .filter_strength
+    test                r5d, r5d
+    jz .h8_main
+    popcnt              r5d, r5d
+    mova                 m0, [tlq-30]           ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    movu                 m3, [tlq-28]           ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    vpbroadcastd         m2, [base+z_filter_k-4+r5*4+12*1]
+    vpbroadcastd         m4, [base+z_filter_k-4+r5*4+12*0]
+    pmullw               m2, m0
+    cmp                  wd, 8
+    jl .h8_filter_w4
+    punpcklwd           xm0, xm0
+    vpblendd             m1, m0, [tlq-32], 0xfe ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    movd           [rsp+28], xm0
+    paddw                m1, m3
+    mov                 r4d, 16
+    pmullw               m1, m4
+    cmovg          maxbased, r4d
+    cmp                 r5d, 3
+    jne .h8_filter_3tap
+    punpckhwd            m3, m3
+    vpblendd             m0, [tlq-34], 0xfe     ; 0 0 0 1 2 3 4 5   6 7 8 9 a b c d
+    vpblendd             m3, [tlq-26], 0x7f     ; 2 3 4 5 6 7 8 9   a b c d e f g g
+    movzx               r4d, word [tlq-30]
+    movzx               r2d, word [tlq-28]
+    inc            maxbased
+    paddw                m1, m2
+    paddw                m0, m3
+    sub                 r2d, r4d
+    paddw                m2, m0, m0
+    lea                 r2d, [r2+r4*8+4]
+    shr                 r2d, 3
+    mov            [rsp+30], r2w
+    jmp .h8_filter_3tap
+.h8_filter_w4:
+    pshufhw             xm1, xm0, q2100
+    vinserti128          m1, [tlq-16], 1        ; _ _ _ _ 4 4 5 6   7 8 9 a b c d e
+    paddw                m1, m3
+    pmullw               m1, m4
+.h8_filter_3tap:
+    pxor                 m0, m0
+    paddw                m1, m2
+    lea                 tlq, [rsp+62]
+    psrlw                m1, 3
+    pavgw                m0, m1
+    mova           [rsp+32], m0
+.h8_main:
+    movd                xm4, dyd
+    neg            maxbaseq
+    vbroadcasti128       m1, [z_base_inc]
+    vpbroadcastw         m7, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m4, xm4
+    lea                 r4d, [maxbaseq+7*64]
+    neg                 dyq
+    movd                xm2, r4d
+    sub                 tlq, 16
+    lea                  r4, [dyq+63]
+    paddw                m6, m4, m4
+    vpbroadcastw         m2, xm2
+    vpblendd             m4, m6, 0xf0 ; ypos0 ypos1
+    psubw                m2, m1
+    or             maxbased, 63
+    paddw                m4, m2
+.h8_loop:
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6 ; base0
+    movu                xm0, [tlq+r4*2+2]
+    movu                xm1, [tlq+r4*2]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6 ; base1
+    vinserti128          m0, [tlq+r5*2+2], 1
+    vinserti128          m1, [tlq+r5*2], 1
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6 ; base2
+    pand                 m3, m5, m4
+    psllw                m3, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m3
+    psraw                m3, m4, 15
+    paddw                m4, m6
+    paddw                m0, m1
+    movu                xm1, [tlq+r4*2+2]
+    movu                xm2, [tlq+r4*2]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6 ; base3
+    vpblendvb            m0, m7, m0, m3
+    vinserti128          m1, [tlq+r5*2+2], 1
+    vinserti128          m2, [tlq+r5*2], 1
+    pand                 m3, m5, m4
+    psllw                m3, 9
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    psraw                m3, m4, 15
+    paddw                m4, m6
+    lea                  r5, [dstq+strideq*4]
+    paddw                m1, m2
+    vpblendvb            m1, m7, m1, m3
+    punpckhwd            m2, m0, m1   ; a3 c3 a2 c2 a1 c1 a0 c0   b3 d3 b2 d2 b1 d1 b0 d0
+    vextracti128        xm3, m2, 1
+    punpcklwd            m0, m1       ; a7 c7 a6 c6 a5 c5 a4 c5   b7 d7 b6 d6 b5 d5 b4 d4
+    punpckhwd           xm1, xm2, xm3 ; a1 b1 c1 d1 a0 b0 c0 d0
+    punpcklwd           xm2, xm3      ; a3 b3 c3 d3 a2 b2 c2 d2
+    vextracti128        xm3, m0, 1
+    movhps [dstq+strideq*0], xm1
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm2
+    movq   [dstq+r7       ], xm2
+    punpckhwd           xm1, xm0, xm3 ; a5 b5 c5 d5 a4 b4 c4 d4
+    punpcklwd           xm0, xm3      ; a7 b7 c7 d7 a6 b6 c6 d6
+    movhps [r5  +strideq*0], xm1
+    movq   [r5  +strideq*1], xm1
+    movhps [r5  +strideq*2], xm0
+    movq   [r5  +r7       ], xm0
+    sub                  wd, 4
+    jz .h8_end
+    add                dstq, 8
+    cmp                 r4d, maxbased
+    jg .h8_loop
+    lea                  r6, [strideq*5]
+    lea                  r2, [strideq+r7*2] ; stride*7
+    test                 wd, 4
+    jz .h8_end_loop
+    movq   [dstq+strideq*0], xm7
+    movq   [dstq+strideq*1], xm7
+    movq   [dstq+strideq*2], xm7
+    movq   [dstq+r7       ], xm7
+    movq   [dstq+strideq*4], xm7
+    movq   [dstq+r6       ], xm7
+    movq   [dstq+r7*2     ], xm7
+    movq   [dstq+r2       ], xm7
+    add                dstq, 8
+    sub                  wd, 4
+    jz .h8_end
+.h8_end_loop:
+    mova   [dstq+strideq*0], xm7
+    mova   [dstq+strideq*1], xm7
+    mova   [dstq+strideq*2], xm7
+    mova   [dstq+r7       ], xm7
+    mova   [dstq+strideq*4], xm7
+    mova   [dstq+r6       ], xm7
+    mova   [dstq+r7*2     ], xm7
+    mova   [dstq+r2       ], xm7
+    add                dstq, 16
+    sub                  wd, 8
+    jg .h8_end_loop
+.h8_end:
+    RET
+.h16_no_intra_edge_filter:
+    and            maxbased, 15
+    or             maxbased, 16 ; imin(w+15, 31)
+    jmp .h16_main
+ALIGN function_align
+.h16:
+    ALLOC_STACK         -96, 10
+    lea            maxbased, [wq+15]
+    lea                  r7, [strideq*3]
+    test             angled, 0x400
+    jnz .h16_no_intra_edge_filter
+    call .filter_strength
+    test                r5d, r5d
+    jz .h16_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    movu                 m0, [tlq-28]            ; 3 4 5 6 7 8 9 a   b c d e f g h i
+    paddw                m1, m0, [tlq-32]        ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    vpbroadcastd         m6, [base+z_filter_k-4+r5*4+12*1]
+    vpbroadcastd         m7, [base+z_filter_k-4+r5*4+12*0]
+    pmullw               m2, m6, [tlq-30]        ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    pmullw               m1, m7
+    paddw                m1, m2
+    cmp                  wd, 8
+    jg .h16_filter_w16
+    mova                xm3, [tlq-46]            ; 0 1 2 3 4 5 6 7
+    pmullw              xm6, xm3
+    jl .h16_filter_w4
+    pblendw             xm3, [tlq-48], 0xfe      ; 0 0 1 2 3 4 5 6
+    cmp                 r5d, 3
+    jne .h16_filter_w8_3tap
+    vpblendd            xm4, xm3, [tlq-50], 0x0e ; 0 0 0 1 2 3 4 5
+.h16_filter_w8_5tap:
+    punpckhwd            m0, m0
+    vpblendd             m0, [tlq-26], 0x7f      ; 4 5 6 7 8 9 a b   c d e f g h i i
+    paddw               xm4, [tlq-42]            ; 2 3 4 5 6 7 8 9
+    paddw                m0, [tlq-34]            ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    paddw               xm4, xm4
+    paddw                m0, m0
+    paddw               xm6, xm4
+    paddw                m1, m0
+.h16_filter_w8_3tap:
+    paddw               xm3, [tlq-44]            ; 1 2 3 4 5 6 7 8
+    pmullw              xm3, xm7
+    pxor                 m0, m0
+    paddw               xm3, xm6
+    psrlw               xm3, 3
+    pavgw               xm3, xm0
+    mova           [rsp+48], xm3
+    jmp .h16_filter_end
+.h16_filter_w4:
+    pshufhw             xm3, xm3, q2100          ; _ _ _ _ 4 4 5 6
+    cmp                 r5d, 3
+    jne .h16_filter_w8_3tap
+    pshufhw             xm4, xm3, q2100          ; _ _ _ _ 4 4 4 5
+    jmp .h16_filter_w8_5tap
+.h16_filter_w16:
+    mova                 m3, [tlq-62]            ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    pmullw               m6, m3
+    punpcklwd           xm3, xm3
+    vpblendd             m4, m3, [tlq-64], 0xfe  ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    paddw                m4, [tlq-60]            ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    mov                 r4d, 32
+    cmp                  wd, 16
+    cmovg          maxbased, r4d
+    movd           [rsp+28], xm3
+    pmullw               m4, m7
+    cmp                 r5d, 3
+    jne .h16_filter_w16_3tap
+    punpckhwd            m0, m0
+    vpblendd             m3, [tlq-66], 0xfe      ; 0 0 0 1 2 3 4 5   6 7 8 9 a b c d
+    vpblendd             m0, [tlq-26], 0x7f      ; 4 5 6 7 8 9 a b   c d e f g h i i
+    paddw                m3, [tlq-58]            ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    paddw                m0, [tlq-34]            ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    movzx               r4d, word [tlq-62]
+    movzx               r2d, word [tlq-60]
+    or             maxbased, 1
+    paddw                m3, m3
+    sub                 r2d, r4d
+    paddw                m0, m0
+    lea                 r2d, [r2+r4*8+4]
+    paddw                m4, m3
+    shr                 r2d, 3
+    paddw                m1, m0
+    mov            [rsp+30], r2w
+.h16_filter_w16_3tap:
+    pxor                 m0, m0
+    paddw                m4, m6
+    psrlw                m4, 3
+    pavgw                m4, m0
+    mova           [rsp+32], m4
+.h16_filter_end:
+    psrlw                m1, 3
+    lea                 tlq, [rsp+94]
+    pavgw                m1, m0
+    mova           [rsp+64], m1
+.h16_main:
+    movd                xm8, dyd
+    neg            maxbaseq
+    vpbroadcastw         m9, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m8, xm8
+    lea                 r4d, [maxbaseq+dyq+15*64]
+    neg                 dyq
+    movd                xm7, r4d
+    sub                 tlq, 32
+    lea                  r4, [dyq+63]
+    vpbroadcastw         m7, xm7
+    or             maxbased, 63
+    psubw                m7, [z_base_inc]
+.h16_loop:
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6 ; base0
+    movu                 m0, [tlq+r4*2+2]
+    movu                 m2, [tlq+r4*2]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6 ; base1
+    movu                 m1, [tlq+r5*2+2]
+    movu                 m3, [tlq+r5*2]
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6 ; base3
+    pand                 m6, m5, m7
+    psllw                m6, 9
+    psubw                m2, m0
+    pmulhrsw             m2, m6
+    psraw                m6, m7, 15
+    paddw                m7, m8
+    paddw                m0, m2
+    movu                 m2, [tlq+r4*2+2]
+    movu                 m4, [tlq+r4*2]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6 ; base3
+    vpblendvb            m0, m9, m0, m6
+    pand                 m6, m5, m7
+    psllw                m6, 9
+    psubw                m3, m1
+    pmulhrsw             m3, m6
+    psraw                m6, m7, 15
+    paddw                m7, m8
+    paddw                m1, m3
+    vpblendvb            m1, m9, m1, m6
+    pand                 m6, m5, m7
+    psllw                m6, 9
+    psubw                m4, m2
+    pmulhrsw             m4, m6
+    psraw                m6, m7, 15
+    paddw                m7, m8
+    paddw                m2, m4
+    movu                 m3, [tlq+r5*2+2]
+    movu                 m4, [tlq+r5*2]
+    vpblendvb            m2, m9, m2, m6
+    pand                 m6, m5, m7
+    psllw                m6, 9
+    psubw                m4, m3
+    pmulhrsw             m4, m6
+    psraw                m6, m7, 15
+    paddw                m7, m8
+    lea                  r5, [dstq+strideq*4]
+    paddw                m3, m4
+    vpblendvb            m3, m9, m3, m6
+    punpckhwd            m4, m0, m1 ; ab bb aa ba a9 b9 a8 b8   a3 b3 a2 b2 a1 b1 a0 b0
+    punpcklwd            m0, m1     ; af bf ae be ad bd ac bc   a7 b7 a6 b6 a5 b5 a4 b4
+    punpckhwd            m1, m2, m3 ; cb db ca da c9 d9 c8 d8   c3 d3 c2 d2 c1 d1 c0 d0
+    punpcklwd            m2, m3     ; cf df ce de cd dd cc dc   c7 d7 c6 d6 c5 d5 c4 d4
+    punpckhdq            m3, m4, m1 ; a9 b9 c9 d9 a8 b8 c8 d8   a1 b1 c1 d1 a0 b0 c0 d0
+    vextracti128        xm6, m3, 1
+    punpckldq            m4, m1     ; ab bb cb db aa ba ca da   a3 b3 c3 d3 a2 b2 c2 d2
+    punpckhdq            m1, m0, m2 ; ad bd cd dd ac bc cc dc   a5 b5 c5 d5 a4 b4 c4 d4
+    punpckldq            m0, m2     ; af bf cf df ae be ce de   a7 b7 c7 d7 a6 b6 c6 d6
+    vextracti128        xm2, m4, 1
+    movhps [dstq+strideq*0], xm6
+    movq   [dstq+strideq*1], xm6
+    vextracti128        xm6, m1, 1
+    movhps [dstq+strideq*2], xm2
+    movq   [dstq+r7       ], xm2
+    vextracti128        xm2, m0, 1
+    movhps [r5  +strideq*0], xm6
+    movq   [r5  +strideq*1], xm6
+    movhps [r5  +strideq*2], xm2
+    movq   [r5  +r7       ], xm2
+    lea                  r5, [dstq+strideq*8]
+    movhps [r5  +strideq*0], xm3
+    movq   [r5  +strideq*1], xm3
+    movhps [r5  +strideq*2], xm4
+    movq   [r5  +r7       ], xm4
+    lea                  r5, [r5+strideq*4]
+    movhps [r5  +strideq*0], xm1
+    movq   [r5  +strideq*1], xm1
+    movhps [r5  +strideq*2], xm0
+    movq   [r5  +r7       ], xm0
+    sub                  wd, 4
+    jz .h16_end
+    add                dstq, 8
+    cmp                 r4d, maxbased
+    jg .h16_loop
+    mov                  hd, 4
+.h16_end_loop0:
+    mov                 r6d, wd
+    mov                  r2, dstq
+    test                 wb, 4
+    jz .h16_end_loop
+    movq   [dstq+strideq*0], xm9
+    movq   [dstq+strideq*1], xm9
+    movq   [dstq+strideq*2], xm9
+    movq   [dstq+r7       ], xm9
+    and                 r6d, 120
+    jz .h16_end_w4
+    add                dstq, 8
+.h16_end_loop:
+    mova   [dstq+strideq*0], xm9
+    mova   [dstq+strideq*1], xm9
+    mova   [dstq+strideq*2], xm9
+    mova   [dstq+r7       ], xm9
+    add                dstq, 16
+    sub                 r6d, 8
+    jg .h16_end_loop
+.h16_end_w4:
+    lea                dstq, [r2+strideq*4]
+    dec                  hd
+    jg .h16_end_loop0
+.h16_end:
+    RET
+.h32:
+    ALLOC_STACK        -160, 9
+    lea            maxbased, [wq+31]
+    and            maxbased, 31
+    or             maxbased, 32 ; imin(w+31, 63)
+    test             angled, 0x400
+    jnz .h32_main
+    vpbroadcastd         m2, [pw_3]
+    movu                 m0, [tlq-28]       ; 3 4 5 6 7 8 9 a   b c d e f g h i
+    punpckhwd            m1, m0, m0
+    vpblendd             m1, [tlq-26], 0x7f ; 4 5 6 7 8 9 a b   c d e f g h i i
+    paddw                m0, [tlq-30]       ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    paddw                m1, m2
+    paddw                m0, [tlq-32]       ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    pavgw                m1, [tlq-34]       ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    lea                  r4, [rsp+128]
+    paddw                m0, m1
+    lea                 r5d, [maxbaseq-31]
+    psrlw                m0, 2
+    mova               [r4], m0
+.h32_filter_loop:
+    mova                 m0, [tlq-62]
+    paddw                m1, m2, [tlq-66]
+    paddw                m0, [tlq-64]
+    pavgw                m1, [tlq-58]
+    paddw                m0, [tlq-60]
+    sub                 tlq, 32
+    sub                  r4, 32
+    paddw                m0, m1
+    psrlw                m0, 2
+    mova               [r4], m0
+    sub                 r5d, 16
+    jg .h32_filter_loop
+    jl .h32_filter_h8
+    mova                 m0, [tlq-62]           ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    punpcklwd           xm1, xm0, xm0
+    paddw                m2, [tlq-58]           ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    paddw                m0, [tlq-60]           ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    vpblendd             m3, m1, [tlq-66], 0xfe ; 0 0 0 1 2 3 4 5   6 7 8 9 a b c d
+    vpblendd             m1, [tlq-64], 0xfe     ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    movzx               r5d, word [tlq-62]
+    movzx               r2d, word [tlq-60]
+    pavgw                m2, m3
+    sub                 r2d, r5d
+    paddw                m0, m1
+    lea                 r2d, [r2+r5*8+4]
+    paddw                m0, m2
+    shr                 r2d, 3
+    psrlw                m0, 2
+    mova            [r4-32], m0
+    mov             [r4-36], r5w
+    mov             [r4-34], r2w
+    lea                 tlq, [rsp+158]
+    mov                 r4d, 65
+    cmp                  wd, 64
+    cmove          maxbased, r4d
+    jmp .h32_main
+.h32_filter_h8:
+    mova                xm0, [tlq-46]            ; 0 1 2 3 4 5 6 7
+    pblendw             xm1, xm0, [tlq-48], 0xfe ; 0 0 1 2 3 4 5 6
+    paddw               xm2, [tlq-42]            ; 2 3 4 5 6 7 8 9
+    paddw               xm0, [tlq-44]            ; 1 2 3 4 5 6 7 8
+    vpblendd            xm3, xm1, [tlq-50], 0x0e ; 0 0 0 1 2 3 4 5
+    lea                 tlq, [rsp+158]
+    pavgw               xm2, xm3
+    paddw               xm0, xm1
+    paddw               xm0, xm2
+    psrlw               xm0, 2
+    mova            [r4-16], xm0
+.h32_main:
+    movd                xm6, dyd
+    neg            maxbaseq
+    vpbroadcastw         m7, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m6, xm6
+    lea                 r4d, [maxbaseq+dyq+15*64]
+    neg                 dyq
+    movd                xm4, r4d
+    vpbroadcastd         m8, [pw_m1024]
+    lea                  r4, [dyq+63]
+    vpbroadcastw         m4, xm4
+    or             maxbased, 63
+    psubw                m4, [z_base_inc]
+.h32_loop:
+    mov                  r5, r4
+    sar                  r5, 6
+    movu                 m1, [tlq+r5*2-64]
+    movu                 m0, [tlq+r5*2-62]
+    pand                 m3, m5, m4
+    psllw                m3, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m3
+    pcmpgtw              m2, m8, m4
+    paddw                m0, m1
+    vpblendvb            m0, m7, m0, m2
+    movu                 m2, [tlq+r5*2-32]
+    movu                 m1, [tlq+r5*2-30]
+    add                  r4, dyq
+    sub                 rsp, 64
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    psraw                m3, m4, 15
+    paddw                m4, m6
+    mova         [rsp+32*0], m0
+    paddw                m1, m2
+    vpblendvb            m1, m7, m1, m3
+    mova         [rsp+32*1], m1
+    dec                  wd
+    jz .h32_transpose
+    cmp                 r4d, maxbased
+    jg .h32_loop
+.h32_end_loop:
+    sub                 rsp, 64
+    mova         [rsp+32*0], m7
+    mova         [rsp+32*1], m7
+    dec                  wd
+    jg .h32_end_loop
+.h32_transpose:
+    lea                  r3, [strideq*3]
+    lea                  r4, [strideq*5]
+    mov                  r8, dstq
+    lea                  r5, [strideq+r3*2]
+.h32_transpose_loop0:
+    lea                  r6, [rsp+32]
+    lea                  r2, [r8+org_wq*2-16]
+.h32_transpose_loop:
+    mova                 m0, [r6+64*7]
+    mova                 m1, [r6+64*6]
+    mova                 m2, [r6+64*5]
+    mova                 m3, [r6+64*4]
+    mova                 m4, [r6+64*3]
+    mova                 m5, [r6+64*2]
+    mova                 m6, [r6+64*1]
+    mova                 m7, [r6+64*0]
+    punpckhwd            m8, m0, m1 ; a3 b3 a2 b2 a1 b1 a0 b0
+    punpcklwd            m0, m1     ; a7 b7 a6 b6 a5 b5 a4 b4
+    punpckhwd            m1, m2, m3 ; c3 d3 c2 d2 c1 d1 c0 d0
+    punpcklwd            m2, m3     ; c7 d7 c6 d6 c5 d5 c4 d4
+    punpckhwd            m3, m4, m5 ; e3 f3 e2 f2 e1 f1 e0 f0
+    punpcklwd            m4, m5     ; e7 f7 e6 f6 e5 f5 e4 f4
+    punpckhwd            m5, m6, m7 ; g3 h3 g2 h2 g1 h1 g0 h0
+    punpcklwd            m6, m7     ; g7 h7 g6 h6 g5 h5 g4 h4
+    lea                dstq, [r2+strideq*8]
+    sub                  r6, 32
+    punpckhdq            m7, m8, m1 ; a1 b1 c1 d1 a0 b0 c0 d0
+    punpckldq            m8, m1     ; a3 b3 c3 d3 a2 b2 c2 d2
+    punpckhdq            m1, m3, m5 ; e1 f1 g1 h1 e0 f0 g0 h0
+    punpckldq            m3, m5     ; e3 f3 g3 h3 e2 f2 g2 h2
+    punpckhqdq           m5, m7, m1 ;  8  0
+    vextracti128 [r2  +strideq*0], m5, 1
+    punpcklqdq           m7, m1     ;  9  1
+    mova         [dstq+strideq*0], xm5
+    punpckhqdq           m1, m8, m3 ; 10  2
+    vextracti128 [r2  +strideq*1], m7, 1
+    punpcklqdq           m8, m3     ; 11  3
+    mova         [dstq+strideq*1], xm7
+    punpckhdq            m3, m0, m2 ; a5 b5 c5 d5 a4 b4 c4 d4
+    vextracti128 [r2  +strideq*2], m1, 1
+    punpckldq            m0, m2     ; a7 b7 c7 d7 a6 b6 c6 d6
+    mova         [dstq+strideq*2], xm1
+    punpckhdq            m2, m4, m6 ; e5 f5 g5 h5 e4 f4 g4 h4
+    vextracti128 [r2  +r3       ], m8, 1
+    punpckldq            m4, m6     ; e7 f7 g7 h7 e6 f6 g6 h6
+    mova         [dstq+r3       ], xm8
+    punpckhqdq           m6, m3, m2 ; 12  4
+    vextracti128 [r2  +strideq*4], m6, 1
+    punpcklqdq           m3, m2     ; 13  5
+    mova         [dstq+strideq*4], xm6
+    punpckhqdq           m2, m0, m4 ; 14  6
+    vextracti128 [r2  +r4       ], m3, 1
+    punpcklqdq           m0, m4     ; 15  7
+    mova         [dstq+r4       ], xm3
+    vextracti128 [r2  +r3*2     ], m2, 1
+    mova         [dstq+r3*2     ], xm2
+    vextracti128 [r2  +r5       ], m0, 1
+    mova         [dstq+r5       ], xm0
+    lea                  r2, [dstq+strideq*8]
+    cmp                  r6, rsp
+    jae .h32_transpose_loop
+    add                 rsp, 64*8
+    sub              org_wd, 8
+    jg .h32_transpose_loop0
+.h32_end:
+    RET
+.h64:
+    ALLOC_STACK        -256, 10
+    lea            maxbased, [wq+63]
+    test             angled, 0x400
+    jnz .h64_main
+    vpbroadcastd         m2, [pw_3]
+    movu                 m0, [tlq-28]       ; 3 4 5 6 7 8 9 a   b c d e f g h i
+    punpckhwd            m1, m0, m0
+    vpblendd             m1, [tlq-26], 0x7f ; 4 5 6 7 8 9 a b   c d e f g h i i
+    paddw                m0, [tlq-30]       ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    paddw                m1, m2
+    paddw                m0, [tlq-32]       ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    pavgw                m1, [tlq-34]       ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    lea                  r4, [rsp+224]
+    paddw                m0, m1
+    lea                 r5d, [wq+32]
+    psrlw                m0, 2
+    mova               [r4], m0
+.h64_filter_loop:
+    mova                 m0, [tlq-62]
+    paddw                m1, m2, [tlq-66]
+    paddw                m0, [tlq-64]
+    pavgw                m1, [tlq-58]
+    paddw                m0, [tlq-60]
+    sub                 tlq, 32
+    sub                  r4, 32
+    paddw                m0, m1
+    psrlw                m0, 2
+    mova               [r4], m0
+    sub                 r5d, 16
+    jg .h64_filter_loop
+    mova                 m0, [tlq-62]           ; 0 1 2 3 4 5 6 7   8 9 a b c d e f
+    punpcklwd           xm1, xm0, xm0
+    paddw                m2, [tlq-58]           ; 2 3 4 5 6 7 8 9   a b c d e f g h
+    paddw                m0, [tlq-60]           ; 1 2 3 4 5 6 7 8   9 a b c d e f g
+    vpblendd             m3, m1, [tlq-66], 0xfe ; 0 0 0 1 2 3 4 5   6 7 8 9 a b c d
+    vpblendd             m1, [tlq-64], 0xfe     ; 0 0 1 2 3 4 5 6   7 8 9 a b c d e
+    lea                 tlq, [rsp+254]
+    pavgw                m2, m3
+    paddw                m0, m1
+    paddw                m0, m2
+    psrlw                m0, 2
+    mova            [r4-32], m0
+.h64_main:
+    neg            maxbaseq
+    movd                xm4, dyd
+    vpbroadcastw         m6, [tlq+maxbaseq*2]
+    shl            maxbased, 6
+    vpbroadcastw         m4, xm4
+    lea                 r4d, [maxbaseq+dyq+15*64]
+    neg                 dyq
+    vpbroadcastd         m7, [pw_m1024]
+    movd                xm3, r4d
+    lea                  r4, [dyq+63]
+    paddw                m8, m7, m7
+    vpbroadcastw         m3, xm3
+    or             maxbased, 63
+    paddw                m9, m8, m7
+    psubw                m3, [z_base_inc]
+.h64_loop:
+    mov                  r5, r4
+    sar                  r5, 6
+    movu                 m1, [tlq+r5*2-128]
+    movu                 m0, [tlq+r5*2-126]
+    pand                 m2, m5, m3
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    sub                 rsp, 128
+    paddw                m0, m1
+    pcmpgtw              m1, m9, m3
+    vpblendvb            m0, m6, m0, m1
+    mova         [rsp+32*0], m0
+    movu                 m1, [tlq+r5*2-96]
+    movu                 m0, [tlq+r5*2-94]
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    pcmpgtw              m1, m8, m3
+    vpblendvb            m0, m6, m0, m1
+    mova         [rsp+32*1], m0
+    movu                 m1, [tlq+r5*2-64]
+    movu                 m0, [tlq+r5*2-62]
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    pcmpgtw              m1, m7, m3
+    vpblendvb            m0, m6, m0, m1
+    mova         [rsp+32*2], m0
+    movu                 m1, [tlq+r5*2-32]
+    movu                 m0, [tlq+r5*2-30]
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    add                  r4, dyq
+    psraw                m2, m3, 15
+    paddw                m3, m4
+    paddw                m0, m1
+    vpblendvb            m0, m6, m0, m2
+    mova         [rsp+32*3], m0
+    dec                  wd
+    jz .h64_transpose
+    cmp                 r4d, maxbased
+    jg .h64_loop
+.h64_end_loop:
+    sub                 rsp, 128
+    mova         [rsp+32*0], m6
+    mova         [rsp+32*1], m6
+    mova         [rsp+32*2], m6
+    mova         [rsp+32*3], m6
+    dec                  wd
+    jg .h64_end_loop
+.h64_transpose:
+    lea                  r2, [strideq*3]
+    lea                  r3, [strideq*5]
+    mov                  r5, dstq
+    lea                  r4, [strideq+r2*2]
+.h64_transpose_loop0:
+    lea                  r6, [rsp+112]
+    lea                dstq, [r5+org_wq*2-32]
+.h64_transpose_loop:
+    mova                xm0, [r6+128*15]
+    vinserti128          m0, [r6+128* 7], 1
+    mova                xm1, [r6+128*14]
+    vinserti128          m1, [r6+128* 6], 1
+    mova                xm2, [r6+128*13]
+    vinserti128          m2, [r6+128* 5], 1
+    mova                xm3, [r6+128*12]
+    vinserti128          m3, [r6+128* 4], 1
+    mova                xm4, [r6+128*11]
+    vinserti128          m4, [r6+128* 3], 1
+    mova                xm5, [r6+128*10]
+    vinserti128          m5, [r6+128* 2], 1
+    mova                xm6, [r6+128* 9]
+    vinserti128          m6, [r6+128* 1], 1
+    mova                xm7, [r6+128* 8]
+    vinserti128          m7, [r6+128* 0], 1
+    punpckhwd            m8, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m4, m5
+    punpcklwd            m4, m5
+    punpckhwd            m5, m6, m7
+    punpcklwd            m6, m7
+    sub                  r6, 16
+    punpckhdq            m7, m8, m1
+    punpckldq            m8, m1
+    punpckhdq            m1, m3, m5
+    punpckldq            m3, m5
+    punpckhqdq           m5, m7, m1
+    punpcklqdq           m7, m1
+    punpckhqdq           m1, m8, m3
+    punpcklqdq           m8, m3
+    punpckhdq            m3, m0, m2
+    mova   [dstq+strideq*0], m5
+    punpckldq            m0, m2
+    mova   [dstq+strideq*1], m7
+    punpckhdq            m2, m4, m6
+    mova   [dstq+strideq*2], m1
+    punpckldq            m4, m6
+    mova   [dstq+r2       ], m8
+    punpckhqdq           m6, m3, m2
+    mova   [dstq+strideq*4], m6
+    punpcklqdq           m3, m2
+    mova   [dstq+r3       ], m3
+    punpckhqdq           m2, m0, m4
+    mova   [dstq+r2*2     ], m2
+    punpcklqdq           m0, m4
+    mova   [dstq+r4       ], m0
+    lea                dstq, [dstq+strideq*8]
+    cmp                  r6, rsp
+    jae .h64_transpose_loop
+    add                 rsp, 128*16
+    sub              org_wd, 16
+    jg .h64_transpose_loop0
+.h64_end:
+    RET
+
+%macro FILTER_1BLK 5 ; dst, src, tmp, shuf, bdmax
+%ifnum %4
+    pshufb             xm%2, xm%4
+%else
+    pshufb             xm%2, %4
+%endif
+    vinserti128         m%2, xm%2, 1
+    pshufd              m%1, m%2, q0000
+    pmaddwd             m%1, m2
+    pshufd              m%3, m%2, q1111
+    pmaddwd             m%3, m3
+    paddd               m%1, m1
+    paddd               m%1, m%3
+    pshufd              m%3, m%2, q2222
+    pmaddwd             m%3, m4
+    paddd               m%1, m%3
+    pshufd              m%3, m%2, q3333
+    pmaddwd             m%3, m5
+    paddd               m%1, m%3
+    psrad               m%1, 4
+    packusdw            m%1, m%1
+    pminsw              m%1, m%5
+%endmacro
+
+%macro FILTER_2BLK 7 ; dst, src, tmp_dst, tmp_src, tmp, shuf, bdmax
+    pshufb              m%2, m%6
+    vpermq              m%4, m%2, q3232
+    vinserti128         m%2, xm%2, 1
+    pshufd              m%1, m%2, q0000
+    pshufd              m%3, m%4, q0000
+    pmaddwd             m%1, m2
+    pmaddwd             m%3, m2
+    paddd               m%1, m1
+    paddd               m%3, m1
+    pshufd              m%5, m%2, q1111
+    pmaddwd             m%5, m3
+    paddd               m%1, m%5
+    pshufd              m%5, m%4, q1111
+    pmaddwd             m%5, m3
+    paddd               m%3, m%5
+    pshufd              m%5, m%2, q2222
+    pmaddwd             m%5, m4
+    paddd               m%1, m%5
+    pshufd              m%5, m%4, q2222
+    pmaddwd             m%5, m4
+    paddd               m%3, m%5
+    pshufd              m%5, m%2, q3333
+    pmaddwd             m%5, m5
+    paddd               m%1, m%5
+    pshufd              m%5, m%4, q3333
+    pmaddwd             m%5, m5
+    paddd               m%3, m%5
+    psrad               m%1, 4
+    psrad               m%3, 4
+    packusdw            m%1, m%3
+    pminsw              m%1, m%7
+%endmacro
+
+; The ipred_filter SIMD processes 4x2 blocks in the following order which
+; increases parallelism compared to doing things row by row. One redundant
+; block is calculated for w8 and w16, two for w32.
+;     w4     w8       w16             w32
+;     1     1 2     1 2 3 5     1 2 3 5 b c d f
+;     2     2 3     2 4 5 7     2 4 5 7 c e f h
+;     3     3 4     4 6 7 9     4 6 7 9 e g h j
+; ___ 4 ___ 4 5 ___ 6 8 9 a ___ 6 8 9 a g i j k ___
+;           5       8           8       i
+
+cglobal ipred_filter_16bpc, 3, 9, 0, dst, stride, tl, w, h, filter
+%define base r6-ipred_filter_16bpc_avx2_table
+    lea                  r6, [filter_intra_taps]
+    tzcnt                wd, wm
+%ifidn filterd, filterm
+    movzx           filterd, filterb
+%else
+    movzx           filterd, byte filterm
+%endif
+    shl             filterd, 6
+    add             filterq, r6
+    lea                  r6, [ipred_filter_16bpc_avx2_table]
+    vbroadcasti128       m0, [tlq-6]
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastd         m1, [base+pd_8]
+    pmovsxbw             m2, [filterq+16*0]
+    pmovsxbw             m3, [filterq+16*1]
+    pmovsxbw             m4, [filterq+16*2]
+    pmovsxbw             m5, [filterq+16*3]
+    add                  wq, r6
+    mov                  hd, hm
+    jmp                  wq
+.w4:
+    WIN64_SPILL_XMM      10
+    mova                xm8, [base+filter_shuf2]
+    vpbroadcastw         m9, r8m ; bitdepth_max
+    lea                  r7, [6+hq*2]
+    sub                 tlq, r7
+    jmp .w4_loop_start
+.w4_loop:
+    pinsrq              xm0, [tlq+hq*2], 0
+    lea                dstq, [dstq+strideq*2]
+.w4_loop_start:
+    FILTER_1BLK           6, 0, 7, 8, 9
+    vextracti128        xm0, m6, 1
+    movq   [dstq+strideq*0], xm6
+    movq   [dstq+strideq*1], xm0
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    WIN64_SPILL_XMM      16
+    vbroadcasti128      m14, [base+filter_shuf3]
+    vpbroadcastw        m15, r8m ; bitdepth_max
+    FILTER_1BLK          10, 0, 7, [base+filter_shuf2], 15
+    vpermq               m6, m10, q1302         ; ____ ____ | ____ 4321
+    pslldq               m8, m0, 4
+    psrldq               m7, m6, 2
+    psrldq               m0, m6, 10
+    punpcklwd            m7, m0
+    vpblendd             m8, m6, 0x33           ; _0__ 4321 | ____ 4321
+    vpblendd             m8, m7, 0x40           ; _056 4321 | ____ 4321
+    vpblendd             m8, [tlq-6], 0x30      ; _056 4321 | ____ 4321
+    lea                  r7, [16+hq*2]
+    sub                 tlq, r7
+    jmp .w8_loop_start
+.w8_loop:
+    vpermq               m8, m9, q1302          ; ____ 4321 | ____ 4321
+    vpermq               m6, m9, q2031
+    psrldq               m0, m6, 2
+    psrldq               m6, 10
+    punpcklwd            m6, m0
+    vpblendd             m8, m7, 0x80           ; _0__ 4321 | ____ 4321
+    vpblendd             m8, m6, 0x40           ; _056 4321 | ____ 4321
+    mova                m10, m9
+.w8_loop_start:
+    vpblendd             m8, [tlq+hq*2], 0x0C   ; _056 4321 | _056 4321
+    call .main
+    vpblendd            m10, m9, 0xCC
+    mova         [dstq+strideq*0], xm10
+    vextracti128 [dstq+strideq*1], m10, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    ALLOC_STACK          32, 16
+    vpbroadcastw        m15, r8m ; bitdepth_max
+    sub                  hd, 2
+    TAIL_CALL .w16_main, 0
+.w16_main:
+    mova               xm10, [base+filter_shuf2]
+    FILTER_1BLK          13, 0, 6, 10, 15
+    vpermq              m12, m13, q3120
+    mova               xm14, [base+filter_shuf3]
+    vinserti128         m14, [base+filter_shuf1], 1
+    vpbroadcastq         m0, [tlq+10]
+    vpblendd             m0, [tlq-16], 0x4C     ; ___0 4321 | _056 ____
+    psrldq               m6, m12, 8
+    vpblendd             m0, m6, 0x03           ; ___0 4321 | _056 4321
+    punpcklwd            m6, m12
+    vpblendd             m0, m6, 0x80           ; 56_0 4321 | _056 4321
+    FILTER_2BLK          12, 0, 6, 7, 8, 14, 15
+    vpblendd            m13, m12, 0xCC
+    vpermq              m12, m12, q2031         ; 6___ 5___
+    psrldq              xm6, xm12, 2
+    psrldq              xm8, xm12, 12
+    vpblendd            xm6, xm8, 0x01
+    pblendw             xm6, [tlq+10], 0xF8     ; 4321 056_
+    FILTER_1BLK          11, 6, 8, 10, 15
+    vpermq              m11, m11, q3120
+    pshufd               m9, m11, q1032
+    movu                 m8, [tlq+6]            ; __43 210_ | ____ ____
+    pshufd               m8, m8, q3021          ; __0_ 4321 | ____ ____
+    pshufhw              m8, m8, q3201          ; ___0 4321 | ____ ____
+    vpblendd             m9, m8, 0x70           ; ___0 4321 | ____ 4321
+    mova         [dstq+strideq*0], xm13
+    vextracti128 [dstq+strideq*1], m13, 1
+    lea                  r7, [20+hq*2]
+    sub                 tlq, r7
+    vpermq               m6, m12, q0123         ; ____ 4321 | ____ 4321
+    jmp .w16_loop_start
+.w16_loop:
+    vpermq              m13, m13, q3322
+    vpermq              m11,  m9, q2020
+    vpermq               m9,  m9, q1302
+    vpermq               m6, m12, q0123
+    psrldq               m7, 4
+    vpblendd            m13, m10, 0xCC
+    vpblendd             m9, m7, 0x40
+    mova                 m0, [rsp+8]
+    mova         [dstq+strideq*0], xm13
+    vextracti128 [dstq+strideq*1], m13, 1
+.w16_loop_start:
+    mova                m13, m12
+    vpblendd             m0, [tlq+hq*2], 0x0C
+    psrldq               m7, m12, 8
+    punpcklwd            m7, m12
+    vpblendd             m0, m6, 0x33           ; ___0 4321 | _056 4321
+    vpblendd             m0, m7, 0x80           ; 56_0 4321 | _056 4321
+    FILTER_2BLK          10, 0, 6, 7, 8, 14, 15
+    vpermq              m12, m10, q2031
+    mova            [rsp+8], m0
+    psrldq               m8, m11, 8
+    psrldq              xm6, xm12, 2
+    psrldq              xm7, xm12, 10
+    psrldq              xm0, xm13, 2
+    punpcklwd            m8, m11
+    punpcklwd           xm7, xm6
+    vpblendd             m8, m9, 0x73           ; 56_0 4321 | ____ 4321
+    vpblendd             m8, m7, 0x04           ; 56_0 4321 | __56 4321
+    vpblendd             m8, m0, 0x08           ; 56_0 4321 | _056 4321
+    call .main
+    vpermq               m8, m11, q3120
+    vpblendd             m6, m8, m9, 0xCC
+    mova         [dstq+strideq*0+16], xm6
+    vextracti128 [dstq+strideq*1+16], m6, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    vpermq               m8, m9, q3120
+    vextracti128        xm0, m8, 1              ; 4321 ____
+    pshufd             xm11, xm11, q1032
+    vpblendd            xm0, xm11, 0x02         ; 4321 0___
+    psrldq              xm6, xm8, 2
+    psrldq              xm7, xm8, 12
+    pblendw             xm0, xm6, 0x4           ; 4321 05__
+    pblendw             xm0, xm7, 0x2           ; 4321 056_
+    FILTER_1BLK           6, 0, 7, [base+filter_shuf2], 15
+    vpermq              m12, m13, q1302
+    vpblendd            m12, m10, 0xCC
+    vpblendd             m9, m6, 0xCC
+    mova         [dstq+strideq*0+ 0], xm12
+    mova         [dstq+strideq*0+16], xm9
+    vextracti128 [dstq+strideq*1+ 0], m12, 1
+    vextracti128 [dstq+strideq*1+16], m9, 1
+    ret
+ALIGN function_align
+.w32:
+    ALLOC_STACK          64, 16
+    vpbroadcastw        m15, r8m ; bitdepth_max
+    sub                  hd, 2
+    lea                  r3, [dstq+32]
+    lea                 r5d, [hd*2+20]
+    call .w16_main
+    mov                dstq, r3
+    lea                 tlq, [tlq+r5+32]
+    sub                 r5d, 20
+    shr                 r5d, 1
+    sub                 r5d, 2
+    lea                  r4, [dstq+strideq*2-2]
+DEFINE_ARGS dst, stride, tl, stride3, left, h
+    lea            stride3q, [strideq*3]
+    movu                 m8, [tlq-6]                        ; 4321 0___
+    mova               xm10, [base+filter_shuf2]
+    pinsrw              xm0, xm8, [dstq+strideq*0-2], 2
+    pinsrw              xm0, xm0, [dstq+strideq*1-2], 1     ; 4321 056_
+    pinsrw              xm9, [leftq+strideq*0], 5
+    pinsrw              xm9, [leftq+strideq*1], 4
+    FILTER_1BLK          13, 0, 6, 10, 15
+    vpermq              m12, m13, q3120
+    mova               xm14, [base+filter_shuf3]
+    vinserti128         m14, [base+filter_shuf1], 1
+    psrldq               m6, m12, 8
+    punpcklwd            m7, m6, m12
+    vpblendd             m0, m6, 0x03           ; ___0 ____ | _0__ 4321
+    vpblendd             m0, m7, 0x80           ; 56_0 ____ | _0__ 4321
+    vpblendd             m0, m8, 0x30           ; 56_0 4321 | _0__ 4321
+    vpblendd             m0, m9, 0x04           ; 56_0 4321 | _056 4321
+    FILTER_2BLK          12, 0, 6, 7, 8, 14, 15
+    vpblendd            m13, m12, 0xCC
+    pinsrw              xm9, [leftq+strideq*2], 3
+    pinsrw              xm9, [leftq+stride3q ], 2
+    lea               leftq, [leftq+strideq*4]
+    pinsrw              xm9, [leftq+strideq*0], 1
+    pinsrw              xm9, [leftq+strideq*1], 0
+    movq           [rsp+32], xm9
+    mov                 r7d, 1
+    pslldq               m8, m9, 4
+    vpblendd             m0, m8, 0x0C           ; ___0 ____ | _056 ____
+    vpermq              m12, m12, q2031         ; 6___ 5___
+    psrldq              xm6, xm12, 2
+    psrldq              xm7, xm12, 12
+    vpblendd            xm6, xm7, 0x01          ; ____ _56_
+    pblendw             xm6, [tlq+10], 0xF8     ; 4321 056_
+    FILTER_1BLK          11, 6, 7, 10, 15
+    vpermq              m11, m11, q3120
+    pshufd               m9, m11, q1032
+    vbroadcasti128       m8, [tlq+22]           ; __43 210_ | ____ ____
+    pshufd               m8, m8, q3021          ; __0_ 4321 | ____ ____
+    pshufhw              m8, m8, q3201          ; ___0 4321 | ____ ____
+    vpblendd             m9, m8, 0x70           ; ___0 4321 | ____ 4321
+    mova         [dstq+strideq*0], xm13
+    vextracti128 [dstq+strideq*1], m13, 1
+    vpermq               m6, m12, q0123         ; ____ 4321 | ____ 4321
+    jmp .w32_loop_start
+.w32_loop_last:
+    mova                 m0, [rsp+0]
+    jmp .w32_loop
+.w32_loop_left:
+    mova                 m0, [rsp+0]
+    vpblendd             m0, [rsp+32+r7*4-12], 0x0C
+    dec                 r7d
+    jg .w32_loop
+    cmp                  hd, 2
+    je .w32_loop
+    pinsrw              xm6, [rsp+32], 6
+    pinsrw              xm6, [leftq+strideq*2], 5
+    pinsrw              xm6, [leftq+stride3q ], 4
+    lea               leftq, [leftq+strideq*4]
+    pinsrw              xm6, [leftq+strideq*0], 3
+    pinsrw              xm6, [leftq+strideq*1], 2
+    pinsrw              xm6, [leftq+strideq*2], 1
+    pinsrw              xm6, [leftq+stride3q ], 0
+    lea               leftq, [leftq+strideq*4]
+    movu           [rsp+36], xm6
+    pinsrw              xm6, [leftq+strideq*0], 1
+    pinsrw              xm6, [leftq+strideq*1], 0
+    movd           [rsp+32], xm6
+    mov                 r7d, 4
+.w32_loop:
+    vpermq              m13, m13, q3322
+    vpermq              m11,  m9, q2020
+    vpermq               m9,  m9, q1302
+    vpermq               m6, m12, q0123
+    psrldq               m7, 4
+    vpblendd            m13, m10, 0xCC
+    vpblendd             m9, m7, 0x40           ; ___0 4321 | ____ 4321
+    mova         [dstq+strideq*0], xm13
+    vextracti128 [dstq+strideq*1], m13, 1
+.w32_loop_start:
+    mova                m13, m12
+    psrldq               m7, m12, 8
+    punpcklwd            m7, m12
+    vpblendd             m0, m6, 0x33           ; ___0 4321 | _056 4321
+    vpblendd             m0, m7, 0x80           ; 56_0 4321 | _056 4321
+    FILTER_2BLK          10, 0, 6, 7, 8, 14, 15
+    vpermq              m12, m10, q2031
+    mova            [rsp+0], m0
+    psrldq               m8, m11, 8
+    psrldq              xm6, xm12, 2
+    psrldq              xm7, xm12, 10
+    psrldq              xm0, xm13, 2
+    punpcklwd            m8, m11
+    punpcklwd           xm7, xm6
+    vpblendd             m8, m9, 0x73           ; 56_0 4321 | ____ 4321
+    vpblendd             m8, m7, 0x04           ; 56_0 4321 | __56 4321
+    vpblendd             m8, m0, 0x08           ; 56_0 4321 | _056 4321
+    call .main
+    vpermq               m8, m11, q3120
+    vpblendd             m6, m8, m9, 0xCC
+    mova         [dstq+strideq*0+16], xm6
+    vextracti128 [dstq+strideq*1+16], m6, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop_left
+    jz .w32_loop_last
+    vpermq               m8, m9, q3120
+    vextracti128        xm0, m8, 1              ; 4321 ____
+    pshufd             xm11, xm11, q1032
+    vpblendd            xm0, xm11, 0x02         ; 4321 0___
+    psrldq              xm6, xm8, 2
+    psrldq              xm7, xm8, 12
+    pblendw             xm0, xm6, 0x4           ; 4321 05__
+    pblendw             xm0, xm7, 0x2           ; 4321 056_
+    FILTER_1BLK           6, 0, 7, [base+filter_shuf2], 15
+    vpermq              m12, m13, q1302
+    vpblendd            m12, m10, 0xCC
+    vpblendd             m9, m6, 0xCC
+    mova         [dstq+strideq*0+ 0], xm12
+    mova         [dstq+strideq*0+16], xm9
+    vextracti128 [dstq+strideq*1+ 0], m12, 1
+    vextracti128 [dstq+strideq*1+16], m9, 1
+    RET
+.main:
+    FILTER_2BLK           9, 8, 6, 7, 0, 14, 15
+    ret
+
+%if WIN64
+DECLARE_REG_TMP 5
+%else
+DECLARE_REG_TMP 7
+%endif
+
+%macro IPRED_CFL 1 ; ac in, unpacked pixels out
+    psignw               m3, m%1, m1
+    pabsw               m%1, m%1
+    pmulhrsw            m%1, m2
+    psignw              m%1, m3
+    paddw               m%1, m0
+%endmacro
+
+cglobal ipred_cfl_top_16bpc, 3, 7, 8, dst, stride, tl, w, h, ac, alpha
+    movifnidn            hd, hm
+    add                 tlq, 2
+    movd                xm4, wd
+    pxor                 m6, m6
+    vpbroadcastw         m7, r7m
+    pavgw               xm4, xm6
+    tzcnt                wd, wd
+    movd                xm5, wd
+    movu                 m0, [tlq]
+    lea                  t0, [ipred_cfl_left_16bpc_avx2_table]
+    movsxd               r6, [t0+wq*4]
+    add                  r6, t0
+    add                  t0, ipred_cfl_splat_16bpc_avx2_table-ipred_cfl_left_16bpc_avx2_table
+    movsxd               wq, [t0+wq*4]
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+
+cglobal ipred_cfl_left_16bpc, 3, 7, 8, dst, stride, tl, w, h, ac, alpha
+    mov                  hd, hm ; zero upper half
+    sub                 tlq, hq
+    movd                xm4, hd
+    sub                 tlq, hq
+    pxor                 m6, m6
+    vpbroadcastw         m7, r7m
+    pavgw               xm4, xm6
+    tzcnt               r6d, hd
+    movd                xm5, r6d
+    movu                 m0, [tlq]
+    lea                  t0, [ipred_cfl_left_16bpc_avx2_table]
+    movsxd               r6, [t0+r6*4]
+    add                  r6, t0
+    add                  t0, ipred_cfl_splat_16bpc_avx2_table-ipred_cfl_left_16bpc_avx2_table
+    tzcnt                wd, wd
+    movsxd               wq, [t0+wq*4]
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+.h32:
+    paddw                m0, [tlq+32]
+.h16:
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm1
+.h8:
+    psrldq              xm1, xm0, 8
+    paddw               xm0, xm1
+.h4:
+    punpcklwd           xm0, xm6
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    paddd               xm0, xm4
+    psrld               xm0, xm5
+    vpbroadcastw         m0, xm0
+    jmp                  wq
+
+cglobal ipred_cfl_16bpc, 3, 7, 8, dst, stride, tl, w, h, ac, alpha
+    movifnidn            hd, hm
+    movifnidn            wd, wm
+    tzcnt               r6d, hd
+    lea                 t0d, [wq+hq]
+    movd                xm4, t0d
+    tzcnt               t0d, t0d
+    movd                xm5, t0d
+    lea                  t0, [ipred_cfl_16bpc_avx2_table]
+    tzcnt                wd, wd
+    movsxd               r6, [t0+r6*4]
+    movsxd               wq, [t0+wq*4+4*4]
+    psrlw               xm4, 1
+    pxor                 m6, m6
+    vpbroadcastw         m7, r7m
+    add                  r6, t0
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+.h4:
+    movq                xm0, [tlq-8]
+    jmp                  wq
+.w4:
+    movq                xm1, [tlq+2]
+    paddw                m0, m4
+    paddw                m0, m1
+    psrlq                m1, m0, 32
+    paddw                m0, m1
+    psrld                m1, m0, 16
+    paddw                m0, m1
+    cmp                  hd, 4
+    jg .w4_mul
+    psrlw               xm0, 3
+    jmp .w4_end
+.w4_mul:
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm1
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0xAAAB6667
+    shrx                r6d, r6d, r2d
+    punpckhwd           xm1, xm0, xm6
+    punpcklwd           xm0, xm6
+    paddd               xm0, xm1
+    movd                xm1, r6d
+    psrld               xm0, 2
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w4_end:
+    vpbroadcastw         m0, xm0
+.s4:
+    vpbroadcastw         m1, alpham
+    lea                  r6, [strideq*3]
+    pabsw                m2, m1
+    psllw                m2, 9
+.s4_loop:
+    mova                 m4, [acq]
+    IPRED_CFL             4
+    pmaxsw               m4, m6
+    pminsw               m4, m7
+    vextracti128        xm5, m4, 1
+    movq   [dstq+strideq*0], xm4
+    movq   [dstq+strideq*2], xm5
+    movhps [dstq+strideq*1], xm4
+    movhps [dstq+r6       ], xm5
+    lea                dstq, [dstq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 4
+    jg .s4_loop
+    RET
+ALIGN function_align
+.h8:
+    mova                xm0, [tlq-16]
+    jmp                  wq
+.w8:
+    vextracti128        xm1, m0, 1
+    paddw               xm0, [tlq+2]
+    paddw               xm0, xm4
+    paddw               xm0, xm1
+    psrld               xm1, xm0, 16
+    paddw               xm0, xm1
+    pblendw             xm0, xm6, 0xAA
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    psrld               xm0, xm5
+    cmp                  hd, 8
+    je .w8_end
+    mov                 r6d, 0xAAAB
+    mov                 r2d, 0x6667
+    cmp                  hd, 32
+    cmovz               r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w8_end:
+    vpbroadcastw         m0, xm0
+.s8:
+    vpbroadcastw         m1, alpham
+    lea                  r6, [strideq*3]
+    pabsw                m2, m1
+    psllw                m2, 9
+.s8_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+32]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    pmaxsw               m4, m6
+    pmaxsw               m5, m6
+    pminsw               m4, m7
+    pminsw               m5, m7
+    mova         [dstq+strideq*0], xm4
+    mova         [dstq+strideq*2], xm5
+    vextracti128 [dstq+strideq*1], m4, 1
+    vextracti128 [dstq+r6       ], m5, 1
+    lea                dstq, [dstq+strideq*4]
+    add                 acq, 64
+    sub                  hd, 4
+    jg .s8_loop
+    RET
+ALIGN function_align
+.h16:
+    mova                 m0, [tlq-32]
+    jmp                  wq
+.w16:
+    paddw                m0, [tlq+2]
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm4
+    paddw               xm0, xm1
+    punpckhwd           xm1, xm0, xm6
+    punpcklwd           xm0, xm6
+    paddd               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    psrld               xm0, xm5
+    cmp                  hd, 16
+    je .w16_end
+    mov                 r6d, 0xAAAB
+    mov                 r2d, 0x6667
+    test                 hb, 8|32
+    cmovz               r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w16_end:
+    vpbroadcastw         m0, xm0
+.s16:
+    vpbroadcastw         m1, alpham
+    pabsw                m2, m1
+    psllw                m2, 9
+.s16_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+32]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    pmaxsw               m4, m6
+    pmaxsw               m5, m6
+    pminsw               m4, m7
+    pminsw               m5, m7
+    mova   [dstq+strideq*0], m4
+    mova   [dstq+strideq*1], m5
+    lea                dstq, [dstq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .s16_loop
+    RET
+ALIGN function_align
+.h32:
+    mova                 m0, [tlq-64]
+    paddw                m0, [tlq-32]
+    jmp                  wq
+.w32:
+    paddw                m0, [tlq+ 2]
+    paddw                m0, [tlq+34]
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm4
+    paddw               xm0, xm1
+    punpcklwd           xm1, xm0, xm6
+    punpckhwd           xm0, xm6
+    paddd               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+    psrldq              xm1, xm0, 8
+    paddd               xm0, xm1
+    psrld               xm0, xm5
+    cmp                  hd, 32
+    je .w32_end
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x6667AAAB
+    shrx                r6d, r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+    psrlw               xm0, 1
+.w32_end:
+    vpbroadcastw         m0, xm0
+.s32:
+    vpbroadcastw         m1, alpham
+    pabsw                m2, m1
+    psllw                m2, 9
+.s32_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+32]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    pmaxsw               m4, m6
+    pmaxsw               m5, m6
+    pminsw               m4, m7
+    pminsw               m5, m7
+    mova        [dstq+32*0], m4
+    mova        [dstq+32*1], m5
+    add                dstq, strideq
+    add                 acq, 64
+    dec                  hd
+    jg .s32_loop
+    RET
+
+cglobal ipred_cfl_128_16bpc, 3, 7, 8, dst, stride, tl, w, h, ac, alpha
+    mov                 r6d, r7m
+    shr                 r6d, 11
+    lea                  t0, [ipred_cfl_splat_16bpc_avx2_table]
+    tzcnt                wd, wd
+    movifnidn            hd, hm
+    movsxd               wq, [t0+wq*4]
+    vpbroadcastd         m0, [t0-ipred_cfl_splat_16bpc_avx2_table+pw_512+r6*4]
+    pxor                 m6, m6
+    vpbroadcastw         m7, r7m
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  wq
+
+cglobal ipred_cfl_ac_420_16bpc, 4, 7, 6, ac, ypx, stride, wpad, hpad, w, h
+    movifnidn         hpadd, hpadm
+    vpbroadcastd         m5, [pw_2]
+    mov                  hd, hm
+    shl               hpadd, 2
+    pxor                 m4, m4
+    sub                  hd, hpadd
+    cmp            dword wm, 8
+    jg .w16
+    je .w8
+.w4:
+    lea                  r3, [strideq*3]
+    mov                  r5, acq
+.w4_loop:
+    mova                xm0, [ypxq+strideq*2]
+    mova                xm1, [ypxq+r3       ]
+    vinserti128          m0, [ypxq+strideq*0], 1
+    vinserti128          m1, [ypxq+strideq*1], 1
+    lea                ypxq, [ypxq+strideq*4]
+    pmaddwd              m0, m5
+    pmaddwd              m1, m5
+    paddd                m0, m1
+    vextracti128        xm1, m0, 1
+    paddd                m4, m0
+    packssdw            xm1, xm0
+    mova              [acq], xm1
+    add                 acq, 16
+    sub                  hd, 2
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz .dc
+    vpermq               m1, m1, q1111
+    pslld               xm0, 2
+.w4_hpad_loop:
+    mova              [acq], m1
+    paddd                m4, m0
+    add                 acq, 32
+    sub               hpadd, 4
+    jg .w4_hpad_loop
+    jmp .dc
+.w8:
+    mov                  r5, acq
+    test              wpadd, wpadd
+    jnz .w8_wpad1
+.w8_loop:
+    pmaddwd              m0, m5, [ypxq+strideq*0]
+    pmaddwd              m1, m5, [ypxq+strideq*1]
+    lea                ypxq, [ypxq+strideq*2]
+    paddd                m0, m1
+    vextracti128        xm1, m0, 1
+    paddd                m4, m0
+    packssdw            xm1, xm0, xm1
+    mova              [acq], xm1
+    add                 acq, 16
+    dec                  hd
+    jg .w8_loop
+.w8_hpad:
+    test              hpadd, hpadd
+    jz .dc
+    vinserti128          m1, xm1, 1
+    pslld                m0, 2
+    jmp .hpad
+.w8_wpad1:
+    pmaddwd             xm0, xm5, [ypxq+strideq*0]
+    pmaddwd             xm3, xm5, [ypxq+strideq*1]
+    lea                ypxq, [ypxq+strideq*2]
+    paddd               xm0, xm3
+    pshufd              xm3, xm0, q3333
+    packssdw            xm1, xm0, xm3
+    paddd               xm0, xm3
+    paddd               xm4, xm0
+    mova              [acq], xm1
+    add                 acq, 16
+    dec                  hd
+    jg .w8_wpad1
+    jmp .w8_hpad
+.w16_wpad:
+    mova                 m0, [ypxq+strideq*0+ 0]
+    mova                 m1, [ypxq+strideq*1+ 0]
+    cmp               wpadd, 2
+    jl .w16_wpad1
+    je .w16_wpad2
+    vpbroadcastd         m2, [ypxq+strideq*0+12]
+    vpbroadcastd         m3, [ypxq+strideq*1+12]
+    vpblendd             m0, m2, 0xf0
+    vpblendd             m1, m3, 0xf0
+    jmp .w16_wpad_end
+.w16_wpad2:
+    vpbroadcastd         m2, [ypxq+strideq*0+28]
+    vpbroadcastd         m3, [ypxq+strideq*1+28]
+    jmp .w16_wpad_end
+.w16_wpad1:
+    vpbroadcastd         m2, [ypxq+strideq*0+44]
+    vpbroadcastd         m3, [ypxq+strideq*1+44]
+    vinserti128          m2, [ypxq+strideq*0+32], 0
+    vinserti128          m3, [ypxq+strideq*1+32], 0
+.w16_wpad_end:
+    lea                ypxq, [ypxq+strideq*2]
+    REPX    {pmaddwd x, m5}, m0, m1, m2, m3
+    paddd                m0, m1
+    paddd                m2, m3
+    packssdw             m1, m0, m2
+    paddd                m0, m2
+    vpermq               m1, m1, q3120
+    paddd                m4, m0
+    mova              [acq], m1
+    add                 acq, 32
+    dec                  hd
+    jg .w16_wpad
+    jmp .w16_hpad
+.w16:
+    mov                  r5, acq
+    test              wpadd, wpadd
+    jnz .w16_wpad
+.w16_loop:
+    pmaddwd              m0, m5, [ypxq+strideq*0+ 0]
+    pmaddwd              m2, m5, [ypxq+strideq*0+32]
+    pmaddwd              m1, m5, [ypxq+strideq*1+ 0]
+    pmaddwd              m3, m5, [ypxq+strideq*1+32]
+    lea                ypxq, [ypxq+strideq*2]
+    paddd                m0, m1
+    paddd                m2, m3
+    packssdw             m1, m0, m2
+    paddd                m0, m2
+    vpermq               m1, m1, q3120
+    paddd                m4, m0
+    mova              [acq], m1
+    add                 acq, 32
+    dec                  hd
+    jg .w16_loop
+.w16_hpad:
+    add               hpadd, hpadd
+    jz .dc
+    paddd                m0, m0
+.hpad:
+    mova         [acq+32*0], m1
+    paddd                m4, m0
+    mova         [acq+32*1], m1
+    add                 acq, 32*2
+    sub               hpadd, 4
+    jg .hpad
+.dc:
+    vextracti128        xm1, m4, 1
+    sub                  r5, acq ; -w*h*2
+    tzcnt               r1d, r5d
+    paddd               xm4, xm1
+    sub                 r1d, 2
+    punpckhqdq          xm1, xm4, xm4
+    movd                xm0, r1d
+    paddd               xm1, xm4
+    pshuflw             xm4, xm1, q1032
+    paddd               xm1, xm4
+    psrld               xm1, xm0
+    pxor                xm0, xm0
+    pavgw               xm1, xm0
+    vpbroadcastw         m1, xm1
+.dc_loop:
+    mova                 m0, [acq+r5]
+    psubw                m0, m1
+    mova           [acq+r5], m0
+    add                  r5, 32
+    jl .dc_loop
+    RET
+
+cglobal ipred_cfl_ac_422_16bpc, 4, 7, 6, ac, ypx, stride, wpad, hpad, w, h
+    movifnidn         hpadd, hpadm
+    vpbroadcastd         m5, [pw_4]
+    mov                  hd, hm
+    shl               hpadd, 2
+    pxor                 m4, m4
+    sub                  hd, hpadd
+    cmp            dword wm, 8
+    jg .w16
+    je .w8
+.w4:
+    lea                  r3, [strideq*3]
+    mov                  r5, acq
+.w4_loop:
+    mova                xm0, [ypxq+strideq*0]
+    mova                xm1, [ypxq+strideq*1]
+    vinserti128          m0, [ypxq+strideq*2], 1
+    vinserti128          m1, [ypxq+r3       ], 1
+    lea                ypxq, [ypxq+strideq*4]
+    pmaddwd              m0, m5
+    pmaddwd              m1, m5
+    paddd                m4, m0
+    packssdw             m0, m1
+    paddd                m4, m1
+    mova              [acq], m0
+    add                 acq, 32
+    sub                  hd, 4
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+    vextracti128        xm1, m1, 1
+    vpermq               m0, m0, q3333
+    pslld               xm1, 2
+.w4_hpad_loop:
+    mova              [acq], m0
+    paddd                m4, m1
+    add                 acq, 32
+    sub               hpadd, 4
+    jg .w4_hpad_loop
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+.w8:
+    mov                  r5, acq
+    test              wpadd, wpadd
+    jnz .w8_wpad1
+.w8_loop:
+    pmaddwd              m1, m5, [ypxq+strideq*0]
+    pmaddwd              m0, m5, [ypxq+strideq*1]
+    lea                ypxq, [ypxq+strideq*2]
+    paddd                m4, m1
+    packssdw             m1, m0
+    paddd                m4, m0
+    vpermq               m2, m1, q3120
+    mova              [acq], m2
+    add                 acq, 32
+    sub                  hd, 2
+    jg .w8_loop
+.w8_hpad:
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+    vpermq               m1, m1, q3131
+    pslld                m0, 2
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).hpad
+.w8_wpad1:
+    vpbroadcastd         m1, [ypxq+strideq*0+12]
+    vpbroadcastd         m0, [ypxq+strideq*1+12]
+    vinserti128          m1, [ypxq+strideq*0+ 0], 0
+    vinserti128          m0, [ypxq+strideq*1+ 0], 0
+    lea                ypxq, [ypxq+strideq*2]
+    pmaddwd              m1, m5
+    pmaddwd              m0, m5
+    paddd                m4, m1
+    packssdw             m1, m0
+    paddd                m4, m0
+    vpermq               m2, m1, q3120
+    mova              [acq], m2
+    add                 acq, 32
+    sub                  hd, 2
+    jg .w8_wpad1
+    jmp .w8_hpad
+.w16:
+    mov                  r5, acq
+    test              wpadd, wpadd
+    jnz .w16_wpad
+.w16_loop:
+    pmaddwd              m2, m5, [ypxq+strideq*0+ 0]
+    pmaddwd              m1, m5, [ypxq+strideq*0+32]
+    pmaddwd              m0, m5, [ypxq+strideq*1+ 0]
+    pmaddwd              m3, m5, [ypxq+strideq*1+32]
+    lea                ypxq, [ypxq+strideq*2]
+    paddd                m4, m2
+    packssdw             m2, m1
+    paddd                m4, m1
+    packssdw             m1, m0, m3
+    paddd                m0, m3
+    vpermq               m2, m2, q3120
+    paddd                m4, m0
+    vpermq               m1, m1, q3120
+    mova         [acq+32*0], m2
+    mova         [acq+32*1], m1
+    add                 acq, 32*2
+    sub                  hd, 2
+    jg .w16_loop
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).w16_hpad
+.w16_wpad:
+    mova                 m2, [ypxq+strideq*0+ 0]
+    mova                 m0, [ypxq+strideq*1+ 0]
+    cmp               wpadd, 2
+    jl .w16_wpad1
+    je .w16_wpad2
+    vpbroadcastd         m1, [ypxq+strideq*0+12]
+    vpbroadcastd         m3, [ypxq+strideq*1+12]
+    vpblendd             m2, m1, 0xf0
+    vpblendd             m0, m3, 0xf0
+    jmp .w16_wpad_end
+.w16_wpad2:
+    vpbroadcastd         m1, [ypxq+strideq*0+28]
+    vpbroadcastd         m3, [ypxq+strideq*1+28]
+    jmp .w16_wpad_end
+.w16_wpad1:
+    vpbroadcastd         m1, [ypxq+strideq*0+44]
+    vpbroadcastd         m3, [ypxq+strideq*1+44]
+    vinserti128          m1, [ypxq+strideq*0+32], 0
+    vinserti128          m3, [ypxq+strideq*1+32], 0
+.w16_wpad_end:
+    lea                ypxq, [ypxq+strideq*2]
+    REPX    {pmaddwd x, m5}, m2, m0, m1, m3
+    paddd                m4, m2
+    packssdw             m2, m1
+    paddd                m4, m1
+    packssdw             m1, m0, m3
+    paddd                m0, m3
+    vpermq               m2, m2, q3120
+    paddd                m4, m0
+    vpermq               m1, m1, q3120
+    mova         [acq+32*0], m2
+    mova         [acq+32*1], m1
+    add                 acq, 32*2
+    sub                  hd, 2
+    jg .w16_wpad
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).w16_hpad
+
+cglobal ipred_cfl_ac_444_16bpc, 4, 7, 6, ac, ypx, stride, wpad, hpad, w, h
+    lea                  r6, [ipred_cfl_ac_444_16bpc_avx2_table]
+    tzcnt                wd, wm
+    movifnidn         hpadd, hpadm
+    vpbroadcastd         m5, [pw_1]
+    movsxd               wq, [r6+wq*4]
+    shl               hpadd, 2
+    add                  wq, r6
+    mov                  hd, hm
+    pxor                 m4, m4
+    sub                  hd, hpadd
+    jmp                  wq
+.w4:
+    lea                  r3, [strideq*3]
+    mov                  r5, acq
+.w4_loop:
+    movq                xm0, [ypxq+strideq*0]
+    movhps              xm0, [ypxq+strideq*1]
+    vpbroadcastq         m1, [ypxq+strideq*2]
+    vpbroadcastq         m2, [ypxq+r3       ]
+    lea                ypxq, [ypxq+strideq*4]
+    vpblendd             m0, m1, 0x30
+    vpblendd             m0, m2, 0xc0
+    psllw                m0, 3
+    pmaddwd              m1, m0, m5
+    mova              [acq], m0
+    add                 acq, 32
+    paddd                m4, m1
+    sub                  hd, 4
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+    vpermq               m0, m0, q3333
+    paddd                m1, m1
+    mova         [acq+32*0], m0
+    vpermq               m1, m1, q3333
+    mova         [acq+32*1], m0
+    add                 acq, 32*2
+    paddd                m4, m1
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+.w8:
+    lea                  r3, [strideq*3]
+    mov                  r5, acq
+.w8_loop:
+    mova                xm2, [ypxq+strideq*0]
+    vinserti128          m2, [ypxq+strideq*1], 1
+    mova                xm1, [ypxq+strideq*2]
+    vinserti128          m1, [ypxq+r3       ], 1
+    lea                ypxq, [ypxq+strideq*4]
+    psllw                m2, 3
+    psllw                m1, 3
+    mova         [acq+32*0], m2
+    pmaddwd              m2, m5
+    mova         [acq+32*1], m1
+    pmaddwd              m0, m1, m5
+    add                 acq, 32*2
+    paddd                m4, m2
+    paddd                m4, m0
+    sub                  hd, 4
+    jg .w8_loop
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+    vperm2i128           m1, m1, 0x11
+    pslld                m0, 2
+    pxor                 m2, m2
+    vpblendd             m0, m2, 0x0f
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).hpad
+.w16_wpad2:
+    vpbroadcastw         m3, [ypxq+strideq*0+14]
+    vpbroadcastw         m0, [ypxq+strideq*1+14]
+    vpblendd             m2, m3, 0xf0
+    vpblendd             m1, m0, 0xf0
+    jmp .w16_wpad_end
+.w16:
+    mov                  r5, acq
+.w16_loop:
+    mova                 m2, [ypxq+strideq*0]
+    mova                 m1, [ypxq+strideq*1]
+    test              wpadd, wpadd
+    jnz .w16_wpad2
+.w16_wpad_end:
+    lea                ypxq, [ypxq+strideq*2]
+    psllw                m2, 3
+    psllw                m1, 3
+    mova         [acq+32*0], m2
+    pmaddwd              m2, m5
+    mova         [acq+32*1], m1
+    pmaddwd              m0, m1, m5
+    add                 acq, 32*2
+    paddd                m4, m2
+    paddd                m4, m0
+    sub                  hd, 2
+    jg .w16_loop
+    add               hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+    paddd                m0, m0
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).hpad
+.w32:
+    mov                  r5, acq
+    test              wpadd, wpadd
+    jnz .w32_wpad
+.w32_loop:
+    mova                 m0, [ypxq+ 0]
+    mova                 m1, [ypxq+32]
+    add                ypxq, strideq
+    psllw                m0, 3
+    psllw                m1, 3
+    pmaddwd              m2, m0, m5
+    mova         [acq+32*0], m0
+    pmaddwd              m3, m1, m5
+    mova         [acq+32*1], m1
+    add                 acq, 32*2
+    paddd                m2, m3
+    paddd                m4, m2
+    dec                  hd
+    jg .w32_loop
+.w32_hpad:
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+    paddd                m2, m2
+.w32_hpad_loop:
+    mova         [acq+32*0], m0
+    mova         [acq+32*1], m1
+    paddd                m4, m2
+    mova         [acq+32*2], m0
+    mova         [acq+32*3], m1
+    add                 acq, 32*4
+    sub               hpadd, 2
+    jg .w32_hpad_loop
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_avx2).dc
+.w32_wpad:
+    mova                 m0, [ypxq+ 0]
+    cmp               wpadd, 4
+    jl .w32_wpad2
+    je .w32_wpad4
+    vpbroadcastw         m1, [ypxq+14]
+    vpblendd             m0, m1, 0xf0
+    jmp .w32_wpad_end
+.w32_wpad4:
+    vpbroadcastw         m1, [ypxq+30]
+    jmp .w32_wpad_end
+.w32_wpad2:
+    vpbroadcastw         m1, [ypxq+46]
+    vinserti128          m1, [ypxq+32], 0
+.w32_wpad_end:
+    add                ypxq, strideq
+    psllw                m0, 3
+    psllw                m1, 3
+    pmaddwd              m2, m0, m5
+    mova         [acq+32*0], m0
+    pmaddwd              m3, m1, m5
+    mova         [acq+32*1], m1
+    add                 acq, 32*2
+    paddd                m2, m3
+    paddd                m4, m2
+    dec                  hd
+    jg .w32_wpad
+    jmp .w32_hpad
+
+cglobal pal_pred_16bpc, 4, 6, 6, dst, stride, pal, idx, w, h
+    vbroadcasti128       m4, [palq]
+    lea                  r2, [pal_pred_16bpc_avx2_table]
+    tzcnt                wd, wm
+    vbroadcasti128       m5, [pal_pred_shuf]
+    movifnidn            hd, hm
+    movsxd               wq, [r2+wq*4]
+    pshufb               m4, m5
+    punpckhqdq           m5, m4, m4
+    add                  wq, r2
+DEFINE_ARGS dst, stride, stride3, idx, w, h
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    movq                xm0, [idxq]
+    add                idxq, 8
+    psrlw               xm1, xm0, 4
+    punpcklbw           xm0, xm1
+    pshufb              xm1, xm4, xm0
+    pshufb              xm2, xm5, xm0
+    punpcklbw           xm0, xm1, xm2
+    punpckhbw           xm1, xm2
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+strideq*1], xm0
+    movhps [dstq+stride3q ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    pmovzxbw             m2, [idxq]
+    add                idxq, 16
+    psllw                m1, m2, 4
+    por                  m2, m1
+    pshufb               m1, m4, m2
+    pshufb               m2, m5, m2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova         [dstq+strideq*0], xm0
+    mova         [dstq+strideq*1], xm1
+    vextracti128 [dstq+strideq*2], m0, 1
+    vextracti128 [dstq+stride3q ], m1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    pshufd               m3, [idxq], q3120
+    add                idxq, 32
+    vpermq               m3, m3, q3120
+    psrlw                m1, m3, 4
+    punpcklbw            m2, m3, m1
+    punpckhbw            m3, m1
+    pshufb               m1, m4, m2
+    pshufb               m2, m5, m2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    pshufb               m1, m4, m3
+    pshufb               m3, m5, m3
+    punpcklbw            m0, m1, m3
+    punpckhbw            m1, m3
+    mova   [dstq+strideq*2], m0
+    mova   [dstq+stride3q ], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16
+    RET
+.w32:
+    pshufd               m3, [idxq], q3120
+    add                idxq, 32
+    vpermq               m3, m3, q3120
+    psrlw                m1, m3, 4
+    punpcklbw            m2, m3, m1
+    punpckhbw            m3, m1
+    pshufb               m1, m4, m2
+    pshufb               m2, m5, m2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova          [dstq+ 0], m0
+    mova          [dstq+32], m1
+    pshufb               m1, m4, m3
+    pshufb               m3, m5, m3
+    punpcklbw            m0, m1, m3
+    punpckhbw            m1, m3
+    mova  [dstq+strideq+ 0], m0
+    mova  [dstq+strideq+32], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32
+    RET
+.w64:
+    pshufd               m3, [idxq], q3120
+    add                idxq, 32
+    vpermq               m3, m3, q3120
+    psrlw                m1, m3, 4
+    punpcklbw            m2, m3, m1
+    punpckhbw            m3, m1
+    pshufb               m1, m4, m2
+    pshufb               m2, m5, m2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    pshufb               m1, m4, m3
+    pshufb               m3, m5, m3
+    punpcklbw            m0, m1, m3
+    punpckhbw            m1, m3
+    mova        [dstq+32*2], m0
+    mova        [dstq+32*3], m1
+    add                 dstq, strideq
+    dec                   hd
+    jg .w64
+    RET
+
+%endif
diff --git a/media/libdav1d/src/src/x86/ipred16_avx512.asm b/media/libdav1d/src/src/x86/ipred16_avx512.asm
new file mode 100644
index 0000000000..69802614c7
--- /dev/null
+++ b/media/libdav1d/src/src/x86/ipred16_avx512.asm
@@ -0,0 +1,2659 @@
+; Copyright © 2022-2024, VideoLAN and dav1d authors
+; Copyright © 2022-2024, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+ipred_shuf:    db 14, 15, 14, 15,  0,  1,  2,  3,  6,  7,  6,  7,  0,  1,  2,  3
+               db 10, 11, 10, 11,  8,  9, 10, 11,  2,  3,  2,  3,  8,  9, 10, 11
+               db 12, 13, 12, 13,  4,  5,  6,  7,  4,  5,  4,  5,  4,  5,  6,  7
+               db  8,  9,  8,  9, 12, 13, 14, 15,  0,  1,  0,  1, 12, 13, 14, 15
+smooth_perm:   db  1,  2,  5,  6,  9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30
+               db 33, 34, 37, 38, 41, 42, 45, 46, 49, 50, 53, 54, 57, 58, 61, 62
+               db 65, 66, 69, 70, 73, 74, 77, 78, 81, 82, 85, 86, 89, 90, 93, 94
+               db 97, 98,101,102,105,106,109,110,113,114,117,118,121,122,125,126
+pal_pred_perm: db  0, 16, 32, 48,  1, 17, 33, 49,  2, 18, 34, 50,  3, 19, 35, 51
+               db  4, 20, 36, 52,  5, 21, 37, 53,  6, 22, 38, 54,  7, 23, 39, 55
+               db  8, 24, 40, 56,  9, 25, 41, 57, 10, 26, 42, 58, 11, 27, 43, 59
+               db 12, 28, 44, 60, 13, 29, 45, 61, 14, 30, 46, 62, 15, 31, 47, 63
+pw_31to0:      dw 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16
+               dw 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0
+pw_1to32:      dw  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16
+               dw 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+z_upsample:    dw  0, -1,  1,  0,  2,  1,  3,  2,  4,  3,  5,  4,  6,  5,  7,  6
+               dw  8,  7,  9,  8, 10,  9, 11, 10, 12, 11, 13, 12, 14, 13, 15, 14
+z_xpos_mul:    dw  1,  1,  1,  1,  2,  2,  1,  1,  3,  3,  2,  2,  4,  4,  2,  2
+               dw  5,  5,  3,  3,  6,  6,  3,  3,  7,  7,  4,  4,  8,  8,  4,  4
+z_ypos_mul:    dw  0,  0,  0,  0,  1,  1,  0,  0,  2,  2,  1,  1,  3,  3,  1,  1
+               dw  4,  4,  2,  2,  5,  5,  2,  2,  6,  6,  3,  3,  7,  7,  3,  3
+z_filter_t0:   db 55,127, 39,127, 39,127,  7, 15, 31,  7, 15, 31,  0,  3, 31,  0
+z_filter_t1:   db 39, 63, 19, 47, 19, 47,  3,  3,  3,  3,  3,  3,  0,  0,  0,  0
+z_xpos_off1a:  dw  30720,  30784,  30848,  30912,  30976,  31040,  31104,  31168
+z_xpos_off1b:  dw  30720,  30848,  30976,  31104,  31232,  31360,  31488,  31616
+filter_permA:  times 4 db  6,  7,  8,  9, 14, 15,  4,  5
+               times 4 db 10, 11, 12, 13,  2,  3, -1, -1
+filter_permB:  times 4 db 22, 23, 24, 25, 30, 31,  6,  7
+               times 4 db 26, 27, 28, 29, 14, 15, -1, -1
+filter_permC:          dd  8 ; dq  8, 10,  1, 11,  0,  9
+pw_1:          times 2 dw  1
+                       dd 10
+filter_rnd:            dd 32
+                       dd  1
+                       dd  8
+                       dd 11
+filter_shift:  times 2 dw  6
+                       dd  0
+               times 2 dw  4
+                       dd  9
+pd_65536:              dd 65536
+pal_unpack:    db  0,  8,  4, 12, 32, 40, 36, 44
+               db 16, 24, 20, 28, 48, 56, 52, 60
+z_filter_wh:   db  7,  7, 11, 11, 15, 15, 19, 19, 19, 23, 23, 23, 31, 31, 31, 39
+               db 39, 39, 47, 47, 47, 79, 79, 79
+z_filter_k:    dw  8,  8,  6,  6,  4,  4
+               dw  4,  4,  5,  5,  4,  4
+               dw  0,  0,  0,  0,  2,  2
+pb_90:         times 4 db 90
+pw_15:         times 2 dw 15
+pw_16:         times 2 dw 16
+pw_17:         times 2 dw 17
+pw_24:         times 2 dw 24
+pw_31:         times 2 dw 31
+pw_32:         times 2 dw 32
+pw_63:         times 2 dw 63
+pw_64:         times 2 dw 64
+pw_512:        times 2 dw 512
+pw_2048:       times 2 dw 2048
+pw_31806:      times 2 dw 31806
+pw_32640:      times 2 dw 32640
+pw_32672:      times 2 dw 32672
+pw_32704:      times 2 dw 32704
+pw_32735:      times 2 dw 32735
+pw_32736:      times 2 dw 32736
+
+%define pw_2 (z_xpos_mul+4* 2)
+%define pw_3 (z_xpos_mul+4* 4)
+%define pw_7 (z_xpos_mul+4*12)
+%define pw_0to31 (pw_1to32-2)
+
+%macro JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - 2*4)
+    %xdefine %%base mangle(private_prefix %+ _%1_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%base %+ .%3 - (%%table - 2*4)
+        %rotate 1
+    %endrep
+%endmacro
+
+JMP_TABLE ipred_paeth_16bpc,      avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_16bpc,     avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_h_16bpc,   avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_v_16bpc,   avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z1_16bpc,         avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z2_16bpc,         avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z3_16bpc,         avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE pal_pred_16bpc,         avx512icl, w4, w8, w16, w32, w64
+
+cextern smooth_weights_1d_16bpc
+cextern smooth_weights_2d_16bpc
+cextern dr_intra_derivative
+cextern filter_intra_taps
+
+SECTION .text
+
+%macro PAETH 3 ; top, signed_ldiff, ldiff
+    paddw               m0, m%2, m2
+    psubw               m1, m0, m3  ; tldiff
+    psubw               m0, m%1     ; tdiff
+    pabsw               m1, m1
+    pabsw               m0, m0
+    pcmpgtw             k1, m0, m1
+    pminsw              m0, m1
+    pcmpgtw             k2, m%3, m0
+    vpblendmw       m0{k1}, m%1, m3
+    vpblendmw       m0{k2}, m2, m0
+%endmacro
+
+INIT_ZMM avx512icl
+cglobal ipred_paeth_16bpc, 3, 7, 10, dst, stride, tl, w, h
+%define base r6-ipred_paeth_16bpc_avx512icl_table
+    lea                 r6, [ipred_paeth_16bpc_avx512icl_table]
+    tzcnt               wd, wm
+    movifnidn           hd, hm
+    movsxd              wq, [r6+wq*4]
+    vpbroadcastw        m3, [tlq]   ; topleft
+    add                 wq, r6
+    jmp                 wq
+.w4:
+    vpbroadcastq        m4, [tlq+2] ; top
+    movsldup            m7, [base+ipred_shuf]
+    lea                 r6, [strideq*3]
+    psubw               m5, m4, m3
+    pabsw               m6, m5
+.w4_loop:
+    sub                tlq, 16
+    vbroadcasti32x4     m2, [tlq]
+    pshufb              m2, m7      ; left
+    PAETH                4, 5, 6
+    vextracti32x4      xm1, m0, 2
+    vextracti32x4      xm8, ym0, 1
+    vextracti32x4      xm9, m0, 3
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm8
+    movq   [dstq+r6       ], xm9
+    sub                 hd, 8
+    jl .w4_end
+    lea               dstq, [dstq+strideq*4]
+    movhps [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm8
+    movhps [dstq+r6       ], xm9
+    lea               dstq, [dstq+strideq*4]
+    jg .w4_loop
+.w4_end:
+    RET
+.w8:
+    vbroadcasti32x4     m4, [tlq+2]
+    movsldup            m7, [base+ipred_shuf]
+    lea                 r6, [strideq*3]
+    psubw               m5, m4, m3
+    pabsw               m6, m5
+.w8_loop:
+    sub                tlq, 8
+    vpbroadcastq        m2, [tlq]
+    pshufb              m2, m7
+    PAETH                4, 5, 6
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+r6       ], m0, 3
+    lea               dstq, [dstq+strideq*4]
+    sub                 hd, 4
+    jg .w8_loop
+    RET
+.w16:
+    vbroadcasti32x8     m4, [tlq+2]
+    movsldup            m7, [base+ipred_shuf]
+    psubw               m5, m4, m3
+    pabsw               m6, m5
+.w16_loop:
+    sub                tlq, 4
+    vpbroadcastd        m2, [tlq]
+    pshufb              m2, m7
+    PAETH                4, 5, 6
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea               dstq, [dstq+strideq*2]
+    sub                 hd, 2
+    jg .w16_loop
+    RET
+.w32:
+    movu                m4, [tlq+2]
+    psubw               m5, m4, m3
+    pabsw               m6, m5
+.w32_loop:
+    sub                tlq, 2
+    vpbroadcastw        m2, [tlq]
+    PAETH                4, 5, 6
+    mova            [dstq], m0
+    add               dstq, strideq
+    dec                 hd
+    jg .w32_loop
+    RET
+.w64:
+    movu                m4, [tlq+ 2]
+    movu                m7, [tlq+66]
+    psubw               m5, m4, m3
+    psubw               m8, m7, m3
+    pabsw               m6, m5
+    pabsw               m9, m8
+.w64_loop:
+    sub                tlq, 2
+    vpbroadcastw        m2, [tlq]
+    PAETH                4, 5, 6
+    mova       [dstq+64*0], m0
+    PAETH                7, 8, 9
+    mova       [dstq+64*1], m0
+    add               dstq, strideq
+    dec                 hd
+    jg .w64_loop
+    RET
+
+cglobal ipred_smooth_v_16bpc, 3, 7, 7, dst, stride, tl, w, h, weights, stride3
+%define base r6-$$
+    lea                  r6, [$$]
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [base+ipred_smooth_v_16bpc_avx512icl_table+wq*4]
+    lea            weightsq, [base+smooth_weights_1d_16bpc+hq*4]
+    neg                  hq
+    vpbroadcastw         m6, [tlq+hq*2] ; bottom
+    lea                  wq, [base+ipred_smooth_v_16bpc_avx512icl_table+wq]
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    vpbroadcastq         m5, [tlq+2]    ; top
+    movsldup             m4, [ipred_shuf]
+    psubw                m5, m6         ; top - bottom
+.w4_loop:
+    vbroadcasti32x4      m3, [weightsq+hq*2]
+    pshufb               m3, m4
+    pmulhrsw             m3, m5
+    paddw                m3, m6
+    vextracti32x4       xm0, m3, 3
+    vextracti32x4       xm1, ym3, 1
+    vextracti32x4       xm2, m3, 2
+    movhps [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm3
+    add                  hq, 8
+    jg .end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm2
+    movq   [dstq+stride3q ], xm3
+    lea                dstq, [dstq+strideq*4]
+    jl .w4_loop
+.end:
+    RET
+.w8:
+    vbroadcasti32x4      m5, [tlq+2]    ; top
+    movsldup             m4, [ipred_shuf]
+    psubw                m5, m6         ; top - bottom
+.w8_loop:
+    vpbroadcastq         m0, [weightsq+hq*2]
+    pshufb               m0, m4
+    pmulhrsw             m0, m5
+    paddw                m0, m6
+    vextracti32x4 [dstq+strideq*0], m0, 3
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    mova          [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w8_loop
+    RET
+.w16:
+    vbroadcasti32x8      m5, [tlq+2]    ; top
+    movsldup             m4, [ipred_shuf]
+    psubw                m5, m6         ; top - bottom
+.w16_loop:
+    vpbroadcastd         m0, [weightsq+hq*2+0]
+    vpbroadcastd         m1, [weightsq+hq*2+4]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    paddw                m0, m6
+    paddw                m1, m6
+    vextracti32x8 [dstq+strideq*0], m0, 1
+    mova          [dstq+strideq*1], ym0
+    vextracti32x8 [dstq+strideq*2], m1, 1
+    mova          [dstq+stride3q ], ym1
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w16_loop
+    RET
+.w32:
+    movu                 m5, [tlq+2]
+    psubw                m5, m6
+.w32_loop:
+    vpbroadcastw         m0, [weightsq+hq*2+0]
+    vpbroadcastw         m1, [weightsq+hq*2+2]
+    vpbroadcastw         m2, [weightsq+hq*2+4]
+    vpbroadcastw         m3, [weightsq+hq*2+6]
+    REPX   {pmulhrsw x, m5}, m0, m1, m2, m3
+    REPX   {paddw    x, m6}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+stride3q ], m3
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w32_loop
+    RET
+.w64:
+    movu                 m4, [tlq+ 2]
+    movu                 m5, [tlq+66]
+    psubw                m4, m6
+    psubw                m5, m6
+.w64_loop:
+    vpbroadcastw         m1, [weightsq+hq*2+0]
+    vpbroadcastw         m3, [weightsq+hq*2+2]
+    pmulhrsw             m0, m4, m1
+    pmulhrsw             m1, m5
+    pmulhrsw             m2, m4, m3
+    pmulhrsw             m3, m5
+    REPX      {paddw x, m6}, m0, m1, m2, m3
+    mova [dstq+strideq*0+64*0], m0
+    mova [dstq+strideq*0+64*1], m1
+    mova [dstq+strideq*1+64*0], m2
+    mova [dstq+strideq*1+64*1], m3
+    lea                dstq, [dstq+strideq*2]
+    add                  hq, 2
+    jl .w64_loop
+    RET
+
+cglobal ipred_smooth_h_16bpc, 3, 7, 7, dst, stride, tl, w, h, stride3
+    lea                  r6, [$$]
+    mov                  wd, wm
+    movifnidn            hd, hm
+    vpbroadcastw         m6, [tlq+wq*2] ; right
+    tzcnt                wd, wd
+    add                  hd, hd
+    movsxd               wq, [base+ipred_smooth_h_16bpc_avx512icl_table+wq*4]
+    sub                 tlq, hq
+    lea            stride3q, [strideq*3]
+    lea                  wq, [base+ipred_smooth_h_16bpc_avx512icl_table+wq]
+    jmp                  wq
+.w4:
+    movsldup             m4, [base+ipred_shuf]
+    vpbroadcastq         m5, [base+smooth_weights_1d_16bpc+4*2]
+.w4_loop:
+    vbroadcasti32x4      m0, [tlq+hq-16] ; left
+    pshufb               m0, m4
+    psubw                m0, m6          ; left - right
+    pmulhrsw             m0, m5
+    paddw                m0, m6
+    vextracti32x4       xm1, m0, 2
+    vextracti32x4       xm2, ym0, 1
+    vextracti32x4       xm3, m0, 3
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm2
+    movq   [dstq+stride3q ], xm3
+    sub                  hd, 8*2
+    jl .end
+    lea                dstq, [dstq+strideq*4]
+    movhps [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm3
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.end:
+    RET
+.w8:
+    movsldup             m4, [base+ipred_shuf]
+    vbroadcasti32x4      m5, [base+smooth_weights_1d_16bpc+8*2]
+.w8_loop:
+    vpbroadcastq         m0, [tlq+hq-8] ; left
+    pshufb               m0, m4
+    psubw                m0, m6         ; left - right
+    pmulhrsw             m0, m5
+    paddw                m0, m6
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4*2
+    jg .w8_loop
+    RET
+.w16:
+    movsldup             m4, [base+ipred_shuf]
+    vbroadcasti32x8      m5, [base+smooth_weights_1d_16bpc+16*2]
+.w16_loop:
+    vpbroadcastd         m0, [tlq+hq-4]
+    vpbroadcastd         m1, [tlq+hq-8]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    psubw                m0, m6
+    psubw                m1, m6
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    paddw                m0, m6
+    paddw                m1, m6
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+stride3q ], m1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hq, 4*2
+    jg .w16_loop
+    RET
+.w32:
+    movu                 m5, [base+smooth_weights_1d_16bpc+32*2]
+.w32_loop:
+    vpbroadcastq         m3, [tlq+hq-8]
+    punpcklwd            m3, m3
+    psubw                m3, m6
+    pshufd               m0, m3, q3333
+    pshufd               m1, m3, q2222
+    pshufd               m2, m3, q1111
+    pshufd               m3, m3, q0000
+    REPX   {pmulhrsw x, m5}, m0, m1, m2, m3
+    REPX   {paddw    x, m6}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+stride3q ], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hq, 4*2
+    jg .w32_loop
+    RET
+.w64:
+    movu                 m4, [base+smooth_weights_1d_16bpc+64*2]
+    movu                 m5, [base+smooth_weights_1d_16bpc+64*3]
+.w64_loop:
+    vpbroadcastw         m1, [tlq+hq-2]
+    vpbroadcastw         m3, [tlq+hq-4]
+    psubw                m1, m6
+    psubw                m3, m6
+    pmulhrsw             m0, m4, m1
+    pmulhrsw             m1, m5
+    pmulhrsw             m2, m4, m3
+    pmulhrsw             m3, m5
+    REPX      {paddw x, m6}, m0, m1, m2, m3
+    mova [dstq+strideq*0+64*0], m0
+    mova [dstq+strideq*0+64*1], m1
+    mova [dstq+strideq*1+64*0], m2
+    mova [dstq+strideq*1+64*1], m3
+    lea                dstq, [dstq+strideq*2]
+    sub                  hq, 2*2
+    jg .w64_loop
+    RET
+
+cglobal ipred_smooth_16bpc, 3, 7, 16, dst, stride, tl, w, h, v_weights, stride3
+    lea                 r6, [$$]
+    mov                 wd, wm
+    movifnidn           hd, hm
+    vpbroadcastw       m13, [tlq+wq*2]   ; right
+    tzcnt               wd, wd
+    add                 hd, hd
+    movsxd              wq, [base+ipred_smooth_16bpc_avx512icl_table+wq*4]
+    mov                r5d, 0x55555555
+    sub                tlq, hq
+    mova               m14, [base+smooth_perm]
+    kmovd               k1, r5d
+    vpbroadcastw        m0, [tlq]        ; bottom
+    mov                 r5, 0x3333333333333333
+    pxor               m15, m15
+    lea                 wq, [base+ipred_smooth_16bpc_avx512icl_table+wq]
+    kmovq               k2, r5
+    lea         v_weightsq, [base+smooth_weights_2d_16bpc+hq*2]
+    jmp                 wq
+.w4:
+    vpbroadcastq        m5, [tlq+hq+2]
+    movshdup            m3, [base+ipred_shuf]
+    movsldup            m4, [base+ipred_shuf]
+    vbroadcasti32x4     m6, [base+smooth_weights_2d_16bpc+4*4]
+    lea           stride3q, [strideq*3]
+    punpcklwd           m5, m0           ; top, bottom
+.w4_loop:
+    vbroadcasti32x4     m0, [v_weightsq]
+    vpbroadcastq        m2, [tlq+hq-8]
+    mova                m1, m13
+    pshufb              m0, m3
+    pmaddwd             m0, m5
+    pshufb          m1{k2}, m2, m4       ; left, right
+    vpdpwssd            m0, m1, m6
+    vpermb              m0, m14, m0
+    pavgw              ym0, ym15
+    vextracti32x4      xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    lea               dstq, [dstq+strideq*4]
+    add         v_weightsq, 4*4
+    sub                 hd, 4*2
+    jg .w4_loop
+    RET
+.w8:
+    vbroadcasti32x4    ym5, [tlq+hq+2]
+    movshdup            m6, [base+ipred_shuf]
+    movsldup            m7, [base+ipred_shuf]
+    pmovzxwd            m5, ym5
+    vbroadcasti32x8     m8, [base+smooth_weights_2d_16bpc+8*4]
+    lea           stride3q, [strideq*3]
+    vpblendmw       m5{k1}, m0, m5       ; top, bottom
+.w8_loop:
+    vpbroadcastq        m0, [v_weightsq+0]
+    vpbroadcastq        m1, [v_weightsq+8]
+    vpbroadcastd        m3, [tlq+hq-4]
+    vpbroadcastd        m4, [tlq+hq-8]
+    pshufb              m0, m6
+    pmaddwd             m0, m5
+    pshufb              m1, m6
+    pmaddwd             m1, m5
+    mova                m2, m13
+    pshufb          m2{k2}, m3, m7       ; left, right
+    mova                m3, m13
+    pshufb          m3{k2}, m4, m7
+    vpdpwssd            m0, m2, m8
+    vpdpwssd            m1, m3, m8
+    add         v_weightsq, 4*4
+    vpermt2b            m0, m14, m1
+    pavgw               m0, m15
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea               dstq, [dstq+strideq*4]
+    sub                 hd, 4*2
+    jg .w8_loop
+    RET
+.w16:
+    pmovzxwd            m5, [tlq+hq+2]
+    mova                m6, [base+smooth_weights_2d_16bpc+16*4]
+    vpblendmw       m5{k1}, m0, m5       ; top, bottom
+.w16_loop:
+    vpbroadcastd        m0, [v_weightsq+0]
+    vpbroadcastd        m1, [v_weightsq+4]
+    pmaddwd             m0, m5
+    pmaddwd             m1, m5
+    mova                m2, m13
+    vpbroadcastw    m2{k1}, [tlq+hq-2] ; left, right
+    mova                m3, m13
+    vpbroadcastw    m3{k1}, [tlq+hq-4]
+    vpdpwssd            m0, m2, m6
+    vpdpwssd            m1, m3, m6
+    add         v_weightsq, 2*4
+    vpermt2b            m0, m14, m1
+    pavgw               m0, m15
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea               dstq, [dstq+strideq*2]
+    sub                 hq, 2*2
+    jg .w16_loop
+    RET
+.w32:
+    pmovzxwd            m5, [tlq+hq+ 2]
+    pmovzxwd            m6, [tlq+hq+34]
+    mova                m7, [base+smooth_weights_2d_16bpc+32*4]
+    mova                m8, [base+smooth_weights_2d_16bpc+32*6]
+    vpblendmw       m5{k1}, m0, m5       ; top, bottom
+    vpblendmw       m6{k1}, m0, m6
+.w32_loop:
+    vpbroadcastd        m2, [v_weightsq+0]
+    vpbroadcastd        m3, [v_weightsq+4]
+    pmaddwd             m0, m5, m2
+    pmaddwd             m2, m6
+    pmaddwd             m1, m5, m3
+    pmaddwd             m3, m6
+    mova                m4, m13
+    vpbroadcastw    m4{k1}, [tlq+hq-2] ; left, right
+    vpdpwssd            m0, m4, m7
+    vpdpwssd            m2, m4, m8
+    mova                m4, m13
+    vpbroadcastw    m4{k1}, [tlq+hq-4]
+    vpdpwssd            m1, m4, m7
+    vpdpwssd            m3, m4, m8
+    add         v_weightsq, 2*4
+    vpermt2b            m0, m14, m2
+    vpermt2b            m1, m14, m3
+    pavgw               m0, m15
+    pavgw               m1, m15
+    mova  [dstq+strideq*0], m0
+    mova  [dstq+strideq*1], m1
+    lea               dstq, [dstq+strideq*2]
+    sub                 hq, 2*2
+    jg .w32_loop
+    RET
+.w64:
+    pmovzxwd            m5, [tlq+hq+ 2]
+    pmovzxwd            m6, [tlq+hq+34]
+    pmovzxwd            m7, [tlq+hq+66]
+    pmovzxwd            m8, [tlq+hq+98]
+    mova                m9, [base+smooth_weights_2d_16bpc+64*4]
+    vpblendmw       m5{k1}, m0, m5       ; top, bottom
+    mova               m10, [base+smooth_weights_2d_16bpc+64*5]
+    vpblendmw       m6{k1}, m0, m6
+    mova               m11, [base+smooth_weights_2d_16bpc+64*6]
+    vpblendmw       m7{k1}, m0, m7
+    mova               m12, [base+smooth_weights_2d_16bpc+64*7]
+    vpblendmw       m8{k1}, m0, m8
+.w64_loop:
+    vpbroadcastd        m3, [v_weightsq]
+    mova                m4, m13
+    vpbroadcastw    m4{k1}, [tlq+hq-2] ; left, right
+    pmaddwd             m0, m5, m3
+    pmaddwd             m2, m6, m3
+    pmaddwd             m1, m7, m3
+    pmaddwd             m3, m8
+    vpdpwssd            m0, m4, m9
+    vpdpwssd            m2, m4, m10
+    vpdpwssd            m1, m4, m11
+    vpdpwssd            m3, m4, m12
+    add         v_weightsq, 1*4
+    vpermt2b            m0, m14, m2
+    vpermt2b            m1, m14, m3
+    pavgw               m0, m15
+    pavgw               m1, m15
+    mova       [dstq+64*0], m0
+    mova       [dstq+64*1], m1
+    add               dstq, strideq
+    sub                 hd, 1*2
+    jg .w64_loop
+    RET
+
+%if WIN64
+    DECLARE_REG_TMP 4
+%else
+    DECLARE_REG_TMP 8
+%endif
+
+cglobal ipred_z1_16bpc, 3, 8, 16, dst, stride, tl, w, h, angle, dx
+%define base r7-z_filter_t0
+    lea                  r7, [z_filter_t0]
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    lea                  t0, [dr_intra_derivative]
+    movsxd               wq, [base+ipred_z1_16bpc_avx512icl_table+wq*4]
+    add                 tlq, 2
+    mov                 dxd, angled
+    and                 dxd, 0x7e
+    add              angled, 165 ; ~90
+    movzx               dxd, word [t0+dxq]
+    lea                  wq, [base+ipred_z1_16bpc_avx512icl_table+wq]
+    movifnidn            hd, hm
+    xor              angled, 0x4ff ; d = 90 - angle
+    vpbroadcastd        m15, [base+pw_31806]
+    jmp                  wq
+.w4:
+    vpbroadcastw         m5, [tlq+14]
+    vinserti32x4         m5, [tlq], 0
+    cmp              angleb, 40
+    jae .w4_no_upsample
+    lea                 r3d, [angleq-1024]
+    sar                 r3d, 7
+    add                 r3d, hd
+    jg .w4_no_upsample ; !enable_intra_edge_filter || h > 8 || (h == 8 && is_sm)
+    call .upsample_top
+    vpbroadcastq         m0, [base+z_xpos_off1b]
+    jmp .w4_main2
+.w4_no_upsample:
+    test             angled, 0x400
+    jnz .w4_main ; !enable_intra_edge_filter
+    lea                 r3d, [hq+3]
+    vpbroadcastb        xm0, r3d
+    vpbroadcastb        xm1, angled
+    shr              angled, 8 ; is_sm << 1
+    vpcmpeqb             k1, xm0, [base+z_filter_wh]
+    vpcmpgtb         k1{k1}, xm1, [base+z_filter_t0+angleq*8]
+    kmovw               r5d, k1
+    test                r5d, r5d
+    jz .w4_main
+    call .w16_filter
+    mov                 r2d, 9
+    cmp                  hd, 4
+    cmovne              r3d, r2d
+    vpbroadcastw         m6, r3d
+    pminuw               m6, [base+pw_0to31]
+    vpermw               m5, m6, m5
+.w4_main:
+    vpbroadcastq         m0, [base+z_xpos_off1a]
+.w4_main2:
+    movsldup             m3, [base+z_xpos_mul]
+    vpbroadcastw         m4, dxd
+    lea                  r2, [strideq*3]
+    pmullw               m3, m4
+    vshufi32x4           m6, m5, m5, q3321
+    psllw                m4, 3       ; dx*8
+    paddsw               m3, m0      ; xpos
+    palignr              m6, m5, 2   ; top+1
+.w4_loop:
+    psrlw                m1, m3, 6   ; base_x
+    pand                 m2, m15, m3 ; frac
+    vpermw               m0, m1, m5  ; top[base_x]
+    vpermw               m1, m1, m6  ; top[base_x+1]
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r2       ], xm1
+    sub                  hd, 8
+    jl .w4_end
+    vextracti32x4       xm1, m0, 2
+    paddsw               m3, m4      ; xpos += dx
+    lea                dstq, [dstq+strideq*4]
+    vextracti32x4       xm0, m0, 3
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+r2       ], xm0
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.w4_end:
+    RET
+.upsample_top:
+    vinserti32x4         m5, [tlq-16], 3
+    mova                 m3, [base+z_upsample]
+    vpbroadcastd         m4, [base+pd_65536]
+    add                 dxd, dxd
+    vpermw               m0, m3, m5
+    paddw                m3, m4
+    vpermw               m1, m3, m5
+    paddw                m3, m4
+    vpermw               m2, m3, m5
+    paddw                m3, m4
+    vpermw               m3, m3, m5
+    vpbroadcastw         m5, r9m     ; pixel_max
+    paddw                m1, m2      ; b+c
+    paddw                m0, m3      ; a+d
+    psubw                m0, m1, m0
+    psraw                m0, 3
+    pxor                 m2, m2
+    paddw                m0, m1
+    pmaxsw               m0, m2
+    pavgw                m0, m2
+    pminsw               m5, m0
+    ret
+.w8:
+    lea                 r3d, [angleq+216]
+    movu                ym5, [tlq]
+    mov                 r3b, hb
+    movu                m10, [base+pw_0to31]
+    cmp                 r3d, 8
+    ja .w8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || h > 8
+    lea                 r3d, [hq+7]
+    vpbroadcastw         m6, r3d
+    add                 r3d, r3d
+    pminuw               m6, m10
+    vpermw               m5, m6, m5
+    call .upsample_top
+    vbroadcasti32x4      m0, [base+z_xpos_off1b]
+    jmp .w8_main2
+.w8_no_upsample:
+    lea                 r3d, [hq+7]
+    vpbroadcastb        ym0, r3d
+    and                 r3d, 7
+    or                  r3d, 8 ; imin(h+7, 15)
+    vpbroadcastw         m6, r3d
+    pminuw               m6, m10
+    vpermw               m5, m6, m5
+    test             angled, 0x400
+    jnz .w8_main
+    vpbroadcastb        ym1, angled
+    shr              angled, 8
+    vpcmpeqb             k1, ym0, [base+z_filter_wh]
+    mova                xm0, [base+z_filter_t0+angleq*8]
+    vpcmpgtb         k1{k1}, ym1, ym0
+    kmovd               r5d, k1
+    test                r5d, r5d
+    jz .w8_main
+    call .w16_filter
+    cmp                  hd, r3d
+    jl .w8_filter_end
+    pminud               m6, m10, [base+pw_17] {1to16}
+    add                 r3d, 2
+.w8_filter_end:
+    vpermw               m5, m6, m5
+.w8_main:
+    vbroadcasti32x4      m0, [base+z_xpos_off1a]
+.w8_main2:
+    movshdup             m3, [base+z_xpos_mul]
+    vpbroadcastw         m4, dxd
+    shl                 r3d, 6
+    lea                  r2, [strideq*3]
+    pmullw               m3, m4
+    vshufi32x4           m6, m5, m5, q3321
+    sub                 r3d, dxd
+    psllw                m4, 2       ; dx*4
+    shl                 dxd, 2
+    paddsw               m3, m0      ; xpos
+    palignr              m6, m5, 2   ; top+1
+.w8_loop:
+    psrlw                m1, m3, 6   ; base_x
+    pand                 m2, m15, m3 ; frac
+    vpermw               m0, m1, m5  ; top[base_x]
+    vpermw               m1, m1, m6  ; top[base_x+1]
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+r2       ], m0, 3
+    sub                  hd, 4
+    jz .w8_end
+    paddsw               m3, m4      ; xpos += dx
+    lea                dstq, [dstq+strideq*4]
+    sub                 r3d, dxd
+    jg .w8_loop
+    vextracti32x4       xm5, m5, 3
+.w8_end_loop:
+    mova   [dstq+strideq*0], xm5
+    mova   [dstq+strideq*1], xm5
+    mova   [dstq+strideq*2], xm5
+    mova   [dstq+r2       ], xm5
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_end_loop
+.w8_end:
+    RET
+.w16_filter:
+    vpbroadcastw         m1, [tlq-2]
+    popcnt              r5d, r5d
+    valignq              m3, m6, m5, 2
+    vpbroadcastd         m7, [base+z_filter_k+(r5-1)*4+12*0]
+    valignq              m1, m5, m1, 6
+    vpbroadcastd         m8, [base+z_filter_k+(r5-1)*4+12*1]
+    palignr              m2, m3, m5, 2
+    vpbroadcastd         m9, [base+z_filter_k+(r5-1)*4+12*2]
+    palignr              m0, m5, m1, 14
+    pmullw               m7, m5
+    palignr              m3, m5, 4
+    paddw                m0, m2
+    palignr              m5, m1, 12
+    pmullw               m0, m8
+    paddw                m5, m3
+    pmullw               m5, m9
+    pxor                 m1, m1
+    paddw                m0, m7
+    paddw                m5, m0
+    psrlw                m5, 3
+    pavgw                m5, m1
+    ret
+.w16:
+    lea                 r3d, [hq+15]
+    vpbroadcastb        ym0, r3d
+    and                 r3d, 15
+    or                  r3d, 16 ; imin(h+15, 31)
+    vpbroadcastw        m11, r3d
+    pminuw              m10, m11, [base+pw_0to31]
+    vpbroadcastw         m6, [tlq+r3*2]
+    vpermw               m5, m10, [tlq]
+    test             angled, 0x400
+    jnz .w16_main
+    vpbroadcastb        ym1, angled
+    shr              angled, 8
+    vpcmpeqb             k1, ym0, [base+z_filter_wh]
+    mova                xm0, [base+z_filter_t0+angleq*8]
+    vpcmpgtb         k1{k1}, ym1, ym0
+    kmovd               r5d, k1
+    test                r5d, r5d
+    jz .w16_main
+    call .w16_filter
+    cmp                  hd, 16
+    jg .w16_filter_h32
+    vpermw               m6, m11, m5
+    vpermw               m5, m10, m5
+    jmp .w16_main
+.w16_filter_h32:
+    movzx               r3d, word [tlq+62]
+    movzx               r2d, word [tlq+60]
+    lea                 r2d, [r2+r3*8+4]
+    sub                 r2d, r3d
+    mov                 r3d, 1
+    shr                 r2d, 3
+    kmovb                k1, r3d
+    movd                xm0, r2d
+    or                  r3d, 32
+    vmovdqu16        m6{k1}, m0
+.w16_main:
+    rorx                r2d, dxd, 23
+    mov                  r7, rsp
+    and                 rsp, ~63
+    vpbroadcastw         m3, r2d
+    sub                 rsp, 64*2
+    mov                 r2d, dxd
+    paddw                m4, m3, m3
+    mova         [rsp+64*0], m5
+    vinserti32x8         m3, ym4, 1
+    mova         [rsp+64*1], m6
+    shl                 r3d, 6
+.w16_loop:
+    lea                 r5d, [r2+dxq]
+    shr                 r2d, 6
+    movu                ym0, [rsp+r2*2]
+    movu                ym1, [rsp+r2*2+2]
+    lea                 r2d, [r5+dxq]
+    shr                 r5d, 6
+    vinserti32x8         m0, [rsp+r5*2], 1
+    vinserti32x8         m1, [rsp+r5*2+2], 1
+    pand                 m2, m15, m3 ; frac << 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    sub                  hd, 2
+    jz .w16_end
+    paddw                m3, m4
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r2d, r3d
+    jl .w16_loop
+    punpckhqdq          ym6, ym6
+.w16_end_loop:
+    mova   [dstq+strideq*0], ym6
+    mova   [dstq+strideq*1], ym6
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_end_loop
+.w16_end:
+    mov                 rsp, r7
+    RET
+.w32:
+    lea                 r3d, [hq+31]
+    movu                 m7, [tlq+64*0]
+    and                 r3d, 31
+    vpbroadcastw        m11, r3d
+    or                  r3d, 32 ; imin(h+31, 63)
+    pminuw              m10, m11, [base+pw_0to31]
+    vpbroadcastw         m9, [tlq+r3*2]
+    vpermw               m8, m10, [tlq+64*1]
+    test             angled, 0x400
+    jnz .w32_main
+    vpbroadcastd         m5, [base+pw_3]
+    mov                 r5d, ~1
+    movu                 m3, [tlq-2]
+    kmovd                k1, r5d
+    valignq              m2, m8, m7, 6
+    paddw                m7, m3
+    vmovdqu16        m3{k1}, [tlq-4]
+    valignq              m4, m9, m8, 2
+    paddw                m3, m5
+    paddw                m7, [tlq+2]
+    palignr              m1, m8, m2, 14
+    pavgw                m3, [tlq+4]
+    palignr              m2, m8, m2, 12
+    paddw                m7, m3
+    palignr              m3, m4, m8, 2
+    psrlw                m7, 2
+    palignr              m4, m8, 4
+    paddw                m8, m1
+    paddw                m2, m5
+    paddw                m8, m3
+    pavgw                m2, m4
+    paddw                m8, m2
+    psrlw                m8, 2
+    cmp                  hd, 64
+    je .w32_filter_h64
+    vpermw               m9, m11, m8
+    vpermw               m8, m10, m8
+    jmp .w32_main
+.w32_filter_h64:
+    movzx               r3d, word [tlq+126]
+    movzx               r2d, word [tlq+124]
+    lea                 r2d, [r2+r3*8+4]
+    sub                 r2d, r3d
+    mov                 r3d, 65
+    shr                 r2d, 3
+    movd                xm0, r2d
+    vpblendmw        m9{k1}, m0, m9
+.w32_main:
+    rorx                r2d, dxd, 23
+    mov                  r7, rsp
+    and                 rsp, ~63
+    vpbroadcastw         m5, r2d
+    sub                 rsp, 64*4
+    mov                 r2d, dxd
+    mova         [rsp+64*0], m7
+    shl                 r3d, 6
+    mova         [rsp+64*1], m8
+    mova                 m6, m5
+    mova         [rsp+64*2], m9
+    punpckhqdq           m9, m9
+    mova         [rsp+64*3], ym9
+.w32_loop:
+    lea                 r5d, [r2+dxq]
+    shr                 r2d, 6
+    movu                 m0, [rsp+r2*2]
+    movu                 m2, [rsp+r2*2+2]
+    lea                 r2d, [r5+dxq]
+    shr                 r5d, 6
+    movu                 m1, [rsp+r5*2]
+    movu                 m3, [rsp+r5*2+2]
+    pand                 m4, m15, m5
+    paddw                m5, m6
+    psubw                m2, m0
+    pmulhrsw             m2, m4
+    pand                 m4, m15, m5
+    psubw                m3, m1
+    pmulhrsw             m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    sub                  hd, 2
+    jz .w32_end
+    paddw                m5, m6
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r2d, r3d
+    jl .w32_loop
+.w32_end_loop:
+    mova   [dstq+strideq*0], m9
+    mova   [dstq+strideq*1], m9
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_end_loop
+.w32_end:
+    mov                 rsp, r7
+    RET
+.w64_filter96:
+    vpbroadcastd         m4, [base+pw_3]
+    mov                 r5d, ~1
+    movu                 m0, [tlq-2]
+    kmovd                k1, r5d
+    paddw                m7, m0
+    vmovdqu16        m0{k1}, [tlq-4]
+    paddw                m0, m4
+    paddw                m7, [tlq+2]
+    pavgw                m0, [tlq+4]
+    valignq              m1, m9, m8, 6
+    paddw                m8, [tlq+62]
+    paddw                m2, m4, [tlq+60]
+    valignq              m3, m10, m9, 2
+    paddw                m8, [tlq+66]
+    pavgw                m2, [tlq+68]
+    paddw                m7, m0
+    palignr              m0, m9, m1, 14
+    paddw                m8, m2
+    palignr              m1, m9, m1, 12
+    psrlw                m7, 2
+    palignr              m2, m3, m9, 2
+    psrlw                m8, 2
+    palignr              m3, m9, 4
+    paddw                m0, m9
+    paddw                m1, m4
+    paddw                m0, m2
+    pavgw                m1, m3
+    paddw                m0, m1
+    ret
+.w64:
+    movu                 m7, [tlq+64*0]
+    lea                 r3d, [hq-1]
+    movu                 m8, [tlq+64*1]
+    vpbroadcastw        m11, [tlq+r3*2+128]
+    movu                 m9, [tlq+64*2]
+    cmp                  hd, 64
+    je .w64_h64
+    vpbroadcastw        m13, r3d
+    or                  r3d, 64
+    pminuw              m12, m13, [base+pw_0to31]
+    mova                m10, m11
+    vpermw               m9, m12, m9
+    test             angled, 0x400
+    jnz .w64_main
+    call .w64_filter96
+    psrlw                m0, 2
+    vpermw               m9, m12, m0
+    vpermw              m10, m13, m0
+    mova                m11, m10
+    jmp .w64_main
+.w64_h64:
+    movu                m10, [tlq+64*3]
+    or                  r3d, 64
+    test             angled, 0x400
+    jnz .w64_main
+    call .w64_filter96
+    valignq              m1, m10, m9, 6
+    valignq              m3, m11, m10, 2
+    vpbroadcastd        m11, [base+pw_63]
+    psrlw                m9, m0, 2
+    palignr              m0, m10, m1, 14
+    palignr              m1, m10, m1, 12
+    palignr              m2, m3, m10, 2
+    palignr              m3, m10, 4
+    paddw               m10, m0
+    paddw                m1, m4
+    paddw               m10, m2
+    pavgw                m1, m3
+    paddw               m10, m1
+    psrlw               m10, 2
+    vpermw              m11, m11, m10
+.w64_main:
+    rorx                r2d, dxd, 23
+    mov                  r7, rsp
+    and                 rsp, ~63
+    vpbroadcastw         m5, r2d
+    sub                 rsp, 64*6
+    mova         [rsp+64*0], m7
+    mov                 r2d, dxd
+    mova         [rsp+64*1], m8
+    lea                  r5, [rsp+r3*2]
+    mova         [rsp+64*2], m9
+    shl                 r3d, 6
+    mova         [rsp+64*3], m10
+    sub                  r2, r3
+    mova         [rsp+64*4], m11
+    mova                 m6, m5
+    mova         [rsp+64*5], m11
+.w64_loop:
+    mov                  r3, r2
+    sar                  r3, 6
+    movu                 m0, [r5+r3*2+64*0]
+    movu                 m2, [r5+r3*2+64*0+2]
+    movu                 m1, [r5+r3*2+64*1]
+    movu                 m3, [r5+r3*2+64*1+2]
+    pand                 m4, m15, m5
+    psubw                m2, m0
+    pmulhrsw             m2, m4
+    psubw                m3, m1
+    pmulhrsw             m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    dec                  hd
+    jz .w64_end
+    paddw                m5, m6
+    add                dstq, strideq
+    add                  r2, dxq
+    jl .w64_loop
+.w64_end_loop:
+    mova        [dstq+64*0], m11
+    mova        [dstq+64*1], m11
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_end_loop
+.w64_end:
+    mov                 rsp, r7
+    RET
+
+cglobal ipred_z2_16bpc, 3, 9, 16, dst, stride, tl, w, h, angle, dx, _, dy
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    lea                 dxq, [dr_intra_derivative-90]
+    movzx               dyd, angleb
+    xor              angled, 0x400
+    mov                  r7, dxq
+    sub                 dxq, dyq
+    movifnidn            hd, hm
+    and                 dyd, ~1
+    vpbroadcastw        m12, [tlq]
+    and                 dxq, ~1
+    movzx               dyd, word [r7+dyq]  ; angle - 90
+    lea                  r7, [z_filter_t0]
+    movzx               dxd, word [dxq+270] ; 180 - angle
+    mova                 m0, [base+pw_31to0]
+    movsxd               wq, [base+ipred_z2_16bpc_avx512icl_table+wq*4]
+    movu                 m4, [tlq+2]
+    neg                 dyd
+    vpermw               m7, m0, [tlq-64*1]
+    lea                  wq, [base+ipred_z2_16bpc_avx512icl_table+wq]
+    vpbroadcastd        m14, [base+pw_31806]
+    vpbroadcastd        m15, [base+pw_1]
+    jmp                  wq
+.w4:
+    movq                xm3, [tlq]
+    vpbroadcastq         m8, [base+pw_1to32]
+    test             angled, 0x400
+    jnz .w4_main ; !enable_intra_edge_filter
+    lea                 r3d, [hq+2]
+    add              angled, 1022
+    shl                 r3d, 6
+    test                r3d, angled
+    jnz .w4_no_upsample_above ; angle >= 130 || h > 8 || (is_sm && h == 8)
+    pshuflw             xm0, xm4, q3321
+    sub              angled, 1075 ; angle - 53
+    lea                 r3d, [hq+3]
+    call .upsample_above
+    punpcklwd           xm4, xm3, xm4
+    palignr             xm3, xm4, xm12, 14
+    jmp .w4_main
+.w4_upsample_left:
+    call .upsample_left
+    movsldup             m1, [base+z_xpos_mul]
+    paddw                m1, m1
+    jmp .w4_main2
+.w4_no_upsample_above:
+    lea                 r3d, [hq+3]
+    vpbroadcastd        ym0, [base+pw_3]
+    sub              angled, 1112 ; angle - 90
+    call .filter_above2
+    lea                 r3d, [hq+2]
+    add              angled, 973 ; angle + 883
+    palignr             xm3, xm4, xm12, 14
+    shl                 r3d, 6
+    test                r3d, angled
+    jz .w4_upsample_left ; angle <= 140 || h > 8 || (is_sm && h == 8)
+    call .filter_left16
+.w4_main:
+    movsldup             m1, [base+z_xpos_mul]
+    psllw               m15, 3
+.w4_main2:
+    vpbroadcastq         m0, [base+pw_1to32]
+    vpbroadcastw        m11, dxd
+    movsldup             m2, [base+z_xpos_mul]
+    vpbroadcastw        m13, dyd
+    vpbroadcastd         m5, [tlq-2]
+    psllw               m10, m8, 6
+    valignq              m5, m7, m5, 6
+    pmullw               m2, m11
+    psubw               m10, m2       ; xpos
+    pmullw              m13, m0       ; ypos
+    palignr              m5, m7, m5, 14
+    psrlw               m12, m13, 6
+    psllw               m13, 9
+    paddw               m12, m1       ; base_y
+    pand                m13, m14      ; frac_y << 9
+    psllw               m11, 3
+    lea                  r5, [strideq*3]
+.w4_loop:
+    psrlw                m1, m10, 6   ; base_x
+    pand                 m2, m14, m10 ; frac
+    vpermw               m0, m1, m3   ; top[base_x]
+    vpermw               m1, m1, m4   ; top[base_x+1]
+    vpmovw2m             k1, m10      ; base_x < 0
+    psllw                m2, 9
+    vpermw           m0{k1}, m12, m5  ; left[base_y]
+    vpermw           m1{k1}, m12, m7  ; left[base_y+1]
+    vmovdqu16        m2{k1}, m13
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r5       ], xm1
+    sub                  hd, 8
+    jl .w4_end
+    vextracti32x8       ym0, m0, 1
+    psubw               m10, m11      ; base_x -= dx
+    lea                dstq, [dstq+strideq*4]
+    paddw               m12, m15      ; base_y++
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r5       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.w4_end:
+    RET
+.upsample_above: ; w4/w8
+    mova                ym9, [base+pw_1to32]
+    palignr             xm1, xm4, xm12, 12
+    paddw               xm3, xm4  ; b+c
+    xor              angled, 0x7f ; 180 - angle
+    paddw               xm0, xm1  ; a+d
+    vpbroadcastw        xm1, r9m  ; pixel_max
+    vpbroadcastb       xm11, r3d
+    psubw               xm0, xm3, xm0
+    vpbroadcastb        xm2, angled
+    psraw               xm0, 3
+    shr              angled, 8
+    paddw               xm3, xm0
+    pxor                xm0, xm0
+    vpcmpeqb             k2, xm11, [base+z_filter_wh]
+    pmaxsw              xm3, xm0
+    add                 dxd, dxd
+    pavgw               xm3, xm0
+    vpcmpgtb         k2{k2}, xm2, [base+z_filter_t0+angleq*8]
+    pminsw              xm3, xm1
+    paddw                m8, m8
+    jmp .filter_left16b
+.upsample_left: ; h4/h8
+    lea                 r3d, [hq-1]
+    palignr             xm2, xm7, xm12, 14
+    vpbroadcastw        xm0, r3d
+    palignr             xm1, xm7, xm12, 12
+    pminuw              xm0, xm9
+    paddw               xm2, xm7 ; b+c
+    vpermw              xm0, xm0, xm7
+    add                 dyd, dyd
+    paddw               xm0, xm1 ; a+d
+    vpbroadcastw        xm1, r9m ; pixel_max
+    psubw               xm0, xm2, xm0
+    psraw               xm0, 3
+    paddw               xm2, xm0
+    pxor                xm0, xm0
+    pmaxsw              xm2, xm0
+    pavgw               xm2, xm0
+    pminsw              xm2, xm1
+    punpckhwd           xm0, xm2, xm7
+    punpcklwd           xm7, xm2, xm7
+    vinserti32x4        ym7, xm0, 1
+    ret
+.filter_above:
+    sub              angled, 90
+.filter_above2:
+    vpbroadcastb        ym1, r3d
+    vpbroadcastb       ym10, angled
+    mov                 r3d, angled
+    shr                 r3d, 8
+    vpcmpeqb             k2, ym1, [base+z_filter_wh]
+    mova               xm11, [base+z_filter_t0+r3*8]
+    vpcmpgtb         k1{k2}, ym10, ym11
+    mova                 m9, [base+pw_1to32]
+    kmovd               r3d, k1
+    test                r3d, r3d
+    jz .filter_end
+    pminuw              ym0, ym9
+    popcnt              r3d, r3d
+    vpbroadcastd        ym6, r7m      ; max_w
+    kxnorw               k1, k1, k1
+    vpbroadcastd        ym5, [base+z_filter_k+(r3-1)*4+12*0]
+    kaddw                k1, k1, k1   ; ~1
+    vpbroadcastd       ym13, [base+z_filter_k+(r3-1)*4+12*1]
+    vpermw              ym2, ym0, ym4 ; +1
+    pmullw              ym5, ym4
+    paddw               ym1, ym2, ym3
+    vmovdqu16        m3{k1}, [tlq-2]  ; -2
+    vpermw              ym2, ym0, ym2 ; +2
+    vpbroadcastd        ym0, [base+z_filter_k+(r3-1)*4+12*2]
+    pmullw              ym1, ym13
+    movu                m13, [base+pw_0to31]
+    paddw               ym2, ym3
+    packssdw            ym6, ym6
+    pmullw              ym2, ym0
+    paddw               ym1, ym5
+    vpcmpgtw             k1, ym6, ym13
+    paddw               ym1, ym2
+    pxor                ym2, ym2
+    psrlw               ym1, 3
+    pavgw           ym4{k1}, ym1, ym2
+.filter_end:
+    ret
+.filter_left16:
+    vpbroadcastd        ym1, [base+pb_90]
+    psubb               ym1, ym10
+    vpcmpgtb         k2{k2}, ym1, ym11
+.filter_left16b:
+    kmovd               r3d, k2
+    test                r3d, r3d
+    jz .filter_end
+    lea                 r5d, [hq-1]
+    vinserti32x4        ym0, ym12, xm7, 1
+    vpbroadcastw        ym1, r5d
+    popcnt              r3d, r3d
+    vpbroadcastd        ym6, r8m          ; max_h
+    pminuw              ym9, ym1
+    vpbroadcastd        ym5, [base+z_filter_k+(r3-1)*4+12*0]
+    vpermw              ym2, ym9, ym7     ; +1
+    vpbroadcastd       ym10, [base+z_filter_k+(r3-1)*4+12*1]
+    palignr             ym1, ym7, ym0, 14 ; -1
+    pmullw              ym5, ym7
+    palignr             ym0, ym7, ym0, 12 ; -2
+    paddw               ym1, ym2
+    vpermw              ym2, ym9, ym2     ; +2
+    vpbroadcastd        ym9, [base+z_filter_k+(r3-1)*4+12*2]
+    pmullw              ym1, ym10
+    paddw               ym2, ym0
+    packssdw            ym6, ym6
+    pmullw              ym2, ym9
+    paddw               ym1, ym5
+    vpcmpgtw             k1, ym6, [base+pw_0to31]
+    paddw               ym1, ym2
+    pxor                ym2, ym2
+    psrlw               ym1, 3
+    pavgw           ym7{k1}, ym1, ym2
+    ret
+.filter_left:
+    cmp                  hd, 32
+    jl .filter_left16
+    vpbroadcastd         m5, [base+pw_3]
+    pminud               m0, m9, [base+pw_31] {1to16}
+.filter_left32:
+    vpbroadcastd         m6, r8m         ; max_h
+    valignq              m2, m7, m12, 6
+    packssdw             m6, m6
+    palignr              m1, m7, m2, 14  ; -1
+    paddw                m1, m7
+    palignr              m2, m7, m2, 12  ; -2
+    vpcmpgtw             k1, m6, m13
+    paddw                m2, m5
+    cmp                  hd, 64
+    je .filter_left64
+    lea                 r3d, [hq-1]
+    vpbroadcastw        m10, r3d
+    pminuw               m0, m10
+    vpermw              m10, m0, m7      ; +1
+    paddw                m1, m10
+    vpermw              m10, m0, m10     ; +2
+    pavgw                m2, m10
+    paddw                m1, m2
+    vpsrlw           m7{k1}, m1, 2
+    ret
+.filter_left64:
+    valignq             m10, m8, m7, 2
+    vpaddd              m13, [base+pw_32] {1to16}
+    palignr             m11, m10, m7, 2  ; +1
+    paddw                m1, m11
+    palignr             m11, m10, m7, 4  ; +2
+    valignq             m10, m8, m7, 6
+    pavgw               m11, m2
+    vpermw               m2, m0, m8      ; 32+1
+    paddw                m1, m11
+    vpsrlw           m7{k1}, m1, 2
+    palignr              m1, m8, m10, 14 ; 32-1
+    paddw                m1, m8
+    palignr             m10, m8, m10, 12 ; 32-2
+    paddw                m1, m2
+    vpermw               m2, m0, m2      ; 32+2
+    paddw               m10, m5
+    vpcmpgtw             k1, m6, m13
+    pavgw                m2, m10
+    paddw                m1, m2
+    vpsrlw           m8{k1}, m1, 2
+    ret
+.w8:
+    mova                xm3, [tlq]
+    vbroadcasti32x4      m8, [base+pw_1to32]
+    test             angled, 0x400
+    jnz .w8_main
+    lea                 r3d, [angleq+126]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_no_upsample_above ; angle >= 130 || h > 8 || is_sm
+    psrldq              xm0, xm4, 2
+    sub              angled, 53
+    pshufhw             xm0, xm0, q2210
+    lea                 r3d, [hq+7]
+    call .upsample_above
+    punpcklwd           xm0, xm3, xm4
+    punpckhwd           xm4, xm3, xm4
+    vinserti32x4        ym3, ym12, xm0, 1
+    vinserti32x4        ym4, ym0, xm4, 1
+    palignr             ym3, ym4, ym3, 14
+    jmp .w8_main
+.w8_upsample_left:
+    call .upsample_left
+    movshdup             m1, [base+z_xpos_mul]
+    psllw               m15, 3
+    paddw                m1, m1
+    jmp .w8_main2
+.w8_no_upsample_above:
+    lea                 r3d, [hq+7]
+    vpbroadcastd        ym0, [base+pw_7]
+    call .filter_above
+    lea                 r3d, [angleq-51]
+    mov                 r3b, hb
+    palignr             xm3, xm4, xm12, 14
+    cmp                 r3d, 8
+    jbe .w8_upsample_left ; angle > 140 && h <= 8 && !is_sm
+    call .filter_left
+.w8_main:
+    movshdup             m1, [base+z_xpos_mul]
+    psllw               m15, 2
+.w8_main2:
+    vbroadcasti32x4      m0, [base+pw_1to32]
+    vpbroadcastw        m11, dxd
+    movshdup             m2, [base+z_xpos_mul]
+    vpbroadcastw        m13, dyd
+    psllw               m10, m8, 6
+    valignq              m5, m7, m12, 6
+    pmullw               m2, m11
+    psubw               m10, m2       ; xpos
+    pmullw              m13, m0       ; ypos
+    palignr              m5, m7, m5, 14
+    psrlw               m12, m13, 6
+    psllw               m13, 9
+    mov                 r2d, 1<<6
+    paddw               m12, m1       ; base_y
+    lea                 r3d, [dxq-(8<<6)] ; left-only threshold
+    pand                m13, m14      ; frac_y << 9
+    shl                 dxd, 2
+    psllw               m11, 2
+    lea                  r5, [strideq*3]
+.w8_loop:
+    psrlw                m1, m10, 6
+    pand                 m2, m14, m10
+    vpermw               m0, m1, m3
+    vpermw               m1, m1, m4
+    psllw                m2, 9
+    sub                 r2d, dxd
+    jge .w8_toponly
+    vpmovw2m             k1, m10
+    vpermw           m0{k1}, m12, m5
+    vpermw           m1{k1}, m12, m7
+    vmovdqu16        m2{k1}, m13
+.w8_toponly:
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+r5       ], m0, 3
+    sub                  hd, 4
+    jz .w8_end
+    psubw               m10, m11      ; base_x -= dx
+    lea                dstq, [dstq+strideq*4]
+    paddw               m12, m15      ; base_y++
+    cmp                 r2d, r3d
+    jge .w8_loop
+.w8_leftonly_loop:
+    vpermw               m0, m12, m5
+    vpermw               m1, m12, m7
+    psubw                m1, m0
+    pmulhrsw             m1, m13
+    paddw               m12, m15
+    paddw                m0, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+r5       ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_leftonly_loop
+.w8_end:
+    RET
+.w16:
+    mova                ym3, [tlq]
+    vpermw               m8, m0, [tlq-64*2]
+    test             angled, 0x400
+    jnz .w16_main
+    lea                 r3d, [hq+15]
+    vpbroadcastd        ym0, [base+pw_15]
+    call .filter_above
+    call .filter_left
+    vinserti32x4        ym3, ym12, xm4, 1
+    palignr             ym3, ym4, ym3, 14
+.w16_main:
+    vbroadcasti32x8      m0, [base+pw_1to32]
+    vpbroadcastw        m11, dxd
+    vpbroadcastw        m13, dyd
+    kxnorw               k2, k2, k2
+    psllw               m10, m0, 6
+    valignq              m5, m7, m12, 6
+    psubw               m10, m11      ; xpos
+    valignq              m6, m8, m7, 6
+    pmullw              m13, m0       ; ypos
+    knotd                k1, k2
+    palignr              m5, m7, m5, 14
+    palignr              m6, m8, m6, 14
+    vpsubw          m10{k1}, m11
+    psrlw               m12, m13, 6
+    psllw               m13, 9
+    mov                 r2d, 1<<6
+    vpsubw          m12{k2}, m15      ; base_y
+    pand                m13, m14      ; frac_y << 9
+    lea                 r3d, [dxq-(16<<6)]
+    paddw               m11, m11
+    add                 dxd, dxd
+    paddw               m15, m15
+.w16_loop:
+    psrlw                m1, m10, 6
+    pand                 m2, m14, m10
+    vpermw               m0, m1, m3
+    vpermw               m1, m1, m4
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw               m12, m15      ; base_y++
+    paddw                m0, m1
+    sub                 r2d, dxd
+    jge .w16_toponly
+    mova                 m1, m5
+    vpermt2w             m1, m12, m6
+    mova                 m2, m7
+    vpermt2w             m2, m12, m8
+    vpmovw2m             k1, m10
+    psubw                m2, m1
+    pmulhrsw             m2, m13
+    vpaddw           m0{k1}, m1, m2
+.w16_toponly:
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    sub                  hd, 2
+    jz .w16_end
+    psubw               m10, m11      ; base_x -= dx
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r2d, r3d
+    jge .w16_loop
+    paddw               m12, m15
+    vpermt2w             m5, m12, m6
+    mova                 m1, m7
+    vpermt2w             m1, m12, m8
+    jmp .w16_leftonly_loop_start
+.w16_leftonly_loop:
+    mova                 m1, m7
+    vpermt2w             m1, m12, m8
+    vshufi32x4           m5, m1, q1032
+.w16_leftonly_loop_start:
+    psubw                m0, m1, m5
+    pmulhrsw             m0, m13
+    paddw               m12, m15
+    paddw                m0, m5
+    mova                 m5, m1
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_leftonly_loop
+.w16_end:
+    RET
+.w32:
+    mova                 m3, [tlq]
+    vpermw               m8, m0, [tlq-64*2]
+    mova                 m9, [base+pw_1to32]
+    test             angled, 0x400
+    jnz .w32_main
+    pminud               m0, m9, [base+pw_31] {1to16}
+    mov                 r3d, ~1
+    kmovd                k1, r3d
+    vpbroadcastd         m5, [base+pw_3]
+    vpbroadcastd         m6, r6m     ; max_w
+    vpermw               m2, m0, m4  ; +1
+    movu                m13, [base+pw_0to31]
+    paddw                m1, m4, m3
+    vmovdqu16        m3{k1}, [tlq-2] ; -2
+    packssdw             m6, m6
+    paddw                m1, m2
+    vpermw               m2, m0, m2  ; +2
+    paddw                m3, m5
+    vpcmpgtw             k1, m6, m13
+    pavgw                m2, m3
+    paddw                m1, m2
+    psrlw            m4{k1}, m1, 2
+    call .filter_left32
+.w32_main:
+    sub                 rsp, 64*2
+    call .w32_main1
+    add                 rsp, 64*2
+    RET
+.w32_main1:
+    vpbroadcastw        m11, dxd
+    movu           [rsp+64], m4
+    vpbroadcastw         m4, dyd
+    movd           [rsp+60], xm12
+    valignq              m5, m7, m12, 6
+    psllw                m3, m9, 6    ; xpos
+    valignq              m6, m8, m7, 6
+    pmullw               m9, m4       ; ypos
+    palignr              m5, m7, m5, 14
+    mov                 r2d, 33<<6
+    palignr              m6, m8, m6, 14
+    mova                m10, m3
+.w32_main2:
+    psllw               m13, m9, 9
+    sub                 r2d, dxd
+    psrlw               m12, m9, 6    ; base_y
+    mov                 r8d, hd
+    pand                m13, m14      ; frac_y << 9
+.w32_loop:
+    mov                 r3d, r2d
+    shr                 r3d, 6
+    psubw               m10, m11      ; base_x -= dx
+    movu                 m0, [rsp+r3*2-2]
+    pand                 m2, m10, m14 ; frac_x
+    movu                 m1, [rsp+r3*2]
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw               m12, m15      ; base_y++
+    paddw                m0, m1
+    cmp                 r2d, 32<<6
+    jge .w32_toponly
+    mova                 m1, m5
+    vpermt2w             m1, m12, m6
+    mova                 m2, m7
+    vpermt2w             m2, m12, m8
+    vpmovw2m             k1, m10
+    psubw                m2, m1
+    pmulhrsw             m2, m13
+    vpaddw           m0{k1}, m1, m2
+.w32_toponly:
+    mova             [dstq], m0
+    dec                 r8d
+    jz .w32_end
+    add                dstq, strideq
+    sub                 r2d, dxd
+    jge .w32_loop
+    paddw               m12, m15
+    mova                 m2, m5
+    vpermt2w             m2, m12, m6
+.w32_leftonly_loop:
+    mova                 m1, m7
+    vpermt2w             m1, m12, m8
+    psubw                m0, m1, m2
+    pmulhrsw             m0, m13
+    paddw               m12, m15
+    paddw                m0, m2
+    mova                 m2, m1
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                 r8d
+    jg .w32_leftonly_loop
+.w32_end:
+    ret
+.w64:
+    movu                 m3, [tlq+66]
+    vpermw               m8, m0, [tlq-64*2]
+    mova                 m9, [base+pw_1to32]
+    test             angled, 0x400
+    jnz .w64_main
+    mova                 m2, [tlq]        ; -1
+    mov                 r3d, ~1
+    vpbroadcastd         m5, [base+pw_3]
+    kmovd                k1, r3d
+    movu                m13, [base+pw_0to31]
+    vpbroadcastd         m6, r6m          ; max_w
+    pminud               m0, m9, [base+pw_31] {1to16}
+    paddw                m1, m4, m2
+    vmovdqu16        m2{k1}, [tlq-2]      ; -2
+    packssdw             m6, m6
+    paddw                m1, [tlq+4]      ; +1
+    paddw                m2, m5
+    vpcmpgtw             k1, m6, m13
+    pavgw                m2, [tlq+6]      ; +2
+    paddw                m1, m2
+    vpermw               m2, m0, m3       ; 32+1
+    psrlw            m4{k1}, m1, 2
+    paddw                m1, m3, [tlq+64] ; 32-1
+    vpaddd              m11, m13, [base+pw_32] {1to16}
+    paddw                m1, m2
+    vpermw               m2, m0, m2       ; 32+2
+    paddw               m10, m5, [tlq+62] ; 32-2
+    vpcmpgtw             k1, m6, m11
+    pavgw                m2, m10
+    paddw                m1, m2
+    psrlw            m3{k1}, m1, 2
+    call .filter_left32
+.w64_main:
+    sub                 rsp, 64*3
+    movu [rsp+64*2-gprsize], m3
+    mov                  r5, dstq
+    call .w32_main1
+    psllw                m4, 5
+    mov                 r2d, 65<<6
+    vpaddd              m10, m3, [base+pw_2048] {1to16} ; xpos
+    lea                dstq, [r5+64]
+    paddw                m9, m4 ; ypos
+    call .w32_main2
+    add                 rsp, 64*3
+    RET
+
+cglobal ipred_z3_16bpc, 3, 8, 16, dst, stride, tl, w, h, angle, dy
+    lea                  r7, [z_filter_t0]
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    lea                  t0, [dr_intra_derivative+45*2-1]
+    movsxd               wq, [base+ipred_z3_16bpc_avx512icl_table+wq*4]
+    sub              angled, 180
+    mov                 dyd, angled
+    neg                 dyd
+    xor              angled, 0x400
+    or                  dyq, ~0x7e
+    mova                 m0, [base+pw_31to0]
+    movzx               dyd, word [t0+dyq]
+    lea                  wq, [base+ipred_z3_16bpc_avx512icl_table+wq]
+    movifnidn            hd, hm
+    vpbroadcastd        m14, [base+pw_31806]
+    vpbroadcastd        m15, [base+pw_1]
+    jmp                  wq
+.w4:
+    lea                 r3d, [hq+3]
+    xor                 r3d, 31 ; 32 - (h + imin(w, h))
+    vpbroadcastw         m7, r3d
+    pmaxuw               m7, m0
+    vpermw               m6, m7, [tlq-64*1]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w4_main
+    cmp              angleb, 40
+    jae .w4_filter
+    lea                 r3d, [angleq-1024]
+    sar                 r3d, 7
+    add                 r3d, hd
+    jg .w4_filter ; h > 8 || (h == 8 && is_sm)
+    call .upsample
+    movsldup             m1, [base+z_ypos_mul]
+    paddw                m1, m1
+    jmp .w4_main2
+.w4_filter:
+    lea                 r3d, [hq+3]
+    call .filter32
+.w4_main:
+    movsldup             m1, [base+z_ypos_mul]
+.w4_main2:
+    vpbroadcastq         m0, [base+pw_1to32]
+    vpbroadcastw         m4, dyd
+    lea                 r2d, [hq+4]
+    shr                 r2d, 3
+    pmullw               m4, m0      ; ypos
+    vpbroadcastw         m0, r2d
+    imul                 r2, strideq ; stride * imax(height / 8, 1)
+    pmullw               m1, m0
+    lea                  r3, [r2*3]
+    paddd                m1, [base+pw_32736] {1to16}
+    psrlw                m2, m4, 6
+    psllw                m4, 9
+    paddsw               m2, m1      ; base+0
+    vpandd               m4, m14     ; frac << 9
+    vpermw               m3, m2, m6  ; left[base+0]
+.w4_loop:
+    paddsw               m2, m15     ; base+1
+    vpermw               m1, m2, m6  ; left[base+1]
+    psubw                m0, m1, m3
+    pmulhrsw             m0, m4
+    paddw                m0, m3
+    movq        [dstq+r2*0], xm0
+    movhps      [dstq+r2*1], xm0
+    vextracti32x4       xm3, ym0, 1
+    movq        [dstq+r2*2], xm3
+    movhps      [dstq+r3  ], xm3
+    sub                  hd, 8
+    jl .w4_end
+    lea                  r5, [dstq+r2*4]
+    vextracti32x8       ym0, m0, 1
+    mova                 m3, m1
+    movq          [r5+r2*0], xm0
+    movhps        [r5+r2*1], xm0
+    vextracti32x4       xm1, ym0, 1
+    movq          [r5+r2*2], xm1
+    movhps        [r5+r3  ], xm1
+    add                dstq, strideq
+    test                 hd, hd
+    jnz .w4_loop
+.w4_end:
+    RET
+.upsample:
+    vinserti32x4         m6, [tlq-14], 3
+    mova                 m3, [base+z_upsample]
+    vpbroadcastd         m4, [base+pd_65536]
+    add                 dyd, dyd
+    vpermw               m0, m3, m6
+    paddw                m3, m4
+    vpermw               m1, m3, m6
+    paddw                m3, m4
+    vpermw               m2, m3, m6
+    paddw                m3, m4
+    vpermw               m3, m3, m6
+    vpbroadcastw         m6, r9m     ; pixel_max
+    paddw                m1, m2      ; b+c
+    paddw                m0, m3      ; a+d
+    psubw                m0, m1, m0
+    psraw                m0, 3
+    pxor                 m2, m2
+    paddw                m0, m1
+    pmaxsw               m0, m2
+    pavgw                m0, m2
+    pminsw               m6, m0
+    ret
+.w8:
+    mova                 m6, [tlq-64*1]
+    cmp                  hd, 32
+    je .w8_h32
+    mov                 r3d, 8
+    cmp                  hd, 4
+    cmove               r3d, hd
+    lea                 r3d, [r3+hq-1]
+    xor                 r3d, 31 ; 32 - (h + imin(w, h))
+    vpbroadcastw         m1, r3d
+    vpermw               m7, m1, m6
+    pmaxuw               m1, m0
+    vpermw               m6, m1, m6
+    test             angled, 0x400
+    jnz .w8_main
+    lea                 r3d, [angleq+216]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_filter ; is_sm || d >= 40 || h > 8
+    call .upsample
+    movshdup             m1, [base+z_ypos_mul]
+    paddw                m1, m1
+    call .w8_main_setup
+.w8_upsample_loop:
+    vpermw               m3, m2, m6  ; left[base+0]
+    paddw                m2, m15     ; base+1
+    vpermw               m1, m2, m6  ; left[base+1]
+    psubw                m0, m1, m3
+    pmulhrsw             m0, m4
+    paddw                m2, m15     ; base+2
+    paddw                m0, m3
+    mova                 m3, m1
+    mova          [dstq+r2*0], xm0
+    vextracti32x4 [dstq+r2*1], ym0, 1
+    vextracti32x4 [dstq+r2*2], m0, 2
+    vextracti32x4 [dstq+r3  ], m0, 3
+    add                dstq, strideq
+    sub                  hd, 4
+    jg .w8_upsample_loop
+    RET
+.w8_main_setup:
+    vbroadcasti32x4      m0, [base+pw_1to32]
+    vpbroadcastw         m4, dyd
+    rorx                r2d, hd, 2
+    pmullw               m4, m0      ; ypos
+    vpbroadcastw         m0, r2d
+    imul                 r2, strideq ; stride * height / 4
+    lea                  r3, [r2*3]
+    pmullw               m1, m0      ; 0 1 2 3
+    paddd                m1, [base+pw_32704] {1to16}
+    psrlw                m2, m4, 6
+    psllw                m4, 9
+    paddsw               m2, m1      ; base+0
+    vpandd               m4, m14     ; frac << 9
+    ret
+.w8_h32:
+    pmaxud               m7, m0, [base+pw_24] {1to16}
+    vpermw               m6, m0, m6
+    vpermw               m7, m7, [tlq-64*2]
+    test             angled, 0x400
+    jnz .w8_main
+    call .filter64
+    vpbroadcastd         m0, [base+pw_7]
+    pminuw               m0, [base+pw_0to31]
+    vpermw               m7, m0, m7
+    jmp .w8_main
+.w8_filter:
+    lea                 r3d, [hq+7]
+    call .filter32
+.w8_main:
+    movshdup             m1, [base+z_ypos_mul]
+    call .w8_main_setup
+    mova                 m3, m6
+    vpermt2w             m3, m2, m7  ; left[base+0]
+.w8_loop:
+    paddsw               m2, m15     ; base+1
+    mova                 m1, m6
+    vpermt2w             m1, m2, m7  ; left[base+1]
+    psubw                m0, m1, m3
+    pmulhrsw             m0, m4
+    paddw                m0, m3
+    mova                 m3, m1
+    mova          [dstq+r2*0], xm0
+    vextracti32x4 [dstq+r2*1], ym0, 1
+    vextracti32x4 [dstq+r2*2], m0, 2
+    vextracti32x4 [dstq+r3  ], m0, 3
+    add                dstq, strideq
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.filter32:
+    vpbroadcastb       ym10, r3d
+    vpbroadcastb        ym1, angled
+    shr              angled, 8
+    vpcmpeqb             k1, ym10, [base+z_filter_wh]
+    mova                xm2, [base+z_filter_t0+angleq*8]
+    vpcmpgtb         k1{k1}, ym1, ym2
+    kmovd               r5d, k1
+    test                r5d, r5d
+    jz .filter32_end
+    vpbroadcastw         m2, [tlq]
+    popcnt              r5d, r5d
+    vpbroadcastd         m5, [base+z_filter_k+(r5-1)*4+12*0]
+    valignq              m2, m6, m2, 6
+    vpbroadcastd         m8, [base+z_filter_k+(r5-1)*4+12*1]
+    valignq              m4, m7, m6, 2
+    vpbroadcastd         m9, [base+z_filter_k+(r5-1)*4+12*2]
+    palignr              m1, m6, m2, 14
+    pmullw               m5, m6
+    palignr              m3, m4, m6, 2
+    paddw                m1, m3
+    palignr              m2, m6, m2, 12
+    pmullw               m1, m8
+    palignr              m4, m6, 4
+    paddw                m2, m4
+    pmullw               m2, m9
+    pmovzxbw            m10, ym10
+    pxor                 m6, m6
+    paddw                m5, m1
+    pminuw               m1, m10, [base+pw_0to31]
+    paddw                m5, m2
+    psrlw                m5, 3
+    pavgw                m6, m5
+    vpermw               m7, m10, m6
+    vpermw               m6, m1, m6
+.filter32_end:
+    ret
+.w16:
+    mova                 m6, [tlq-64*1]
+    cmp                  hd, 32
+    jl .w16_h16
+    pmaxud               m8, m0, [base+pw_16] {1to16}
+    mova                 m7, [tlq-64*2]
+    vpermw               m6, m0, m6
+    jg .w16_h64
+    vpermw               m7, m8, m7
+    test             angled, 0x400
+    jnz .w16_main
+    call .filter64
+    vpbroadcastd         m0, [base+pw_15]
+    vinserti32x8         m0, [base+pw_0to31], 0
+    vpermw               m7, m0, m7
+    jmp .w16_main
+.w16_h16:
+    lea                 r3d, [hq*2-1]
+    xor                 r3d, 31 ; 32 - (h + imin(w, h))
+    vpbroadcastw         m1, r3d
+    vpermw               m7, m1, m6
+    pmaxuw               m1, m0
+    vpermw               m6, m1, m6
+    test             angled, 0x400
+    jnz .w16_main
+    lea                 r3d, [hq+15]
+    call .filter32
+.w16_main:
+    vbroadcasti32x8      m0, [base+pw_1to32]
+    vpbroadcastw         m4, dyd
+    rorx                r2d, hd, 1
+    pmullw               m4, m0      ; ypos
+    vpbroadcastw        ym1, r2d
+    imul                 r2, strideq ; stride * height / 2
+    paddd                m1, [base+pw_32704] {1to16}
+    lea                  r3, [r2+strideq]
+    psrlw                m2, m4, 6
+    psllw                m4, 9
+    paddsw               m2, m1      ; base+0
+    vpandd               m4, m14     ; frac << 9
+    mova                 m3, m6
+    vpermt2w             m3, m2, m7  ; left[base+0]
+.w16_loop:
+    paddsw               m1, m2, m15 ; base+1
+    paddsw               m2, m1, m15 ; base+2
+    vpermi2w             m1, m6, m7  ; left[base+1]
+    psubw                m0, m1, m3
+    pmulhrsw             m0, m4
+    paddw                m0, m3
+    mova                 m3, m6
+    vpermt2w             m3, m2, m7  ; left[base+2]
+    vextracti32x8 [dstq+strideq*0], m0, 1
+    mova          [dstq+r2       ], ym0
+    psubw                m0, m3, m1
+    pmulhrsw             m0, m4
+    paddw                m0, m1
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+r3       ], ym0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w16_h64:
+    vpermw               m7, m0, m7
+    vpermw               m8, m8, [tlq-64*3]
+    test             angled, 0x400
+    jnz .w16_h64_main
+    valignq             m11, m8, m7, 6
+    call .filter64
+    vshufi32x4           m2, m8, m8, q3321
+    vpbroadcastd         m0, [base+pw_15]
+    palignr             ym3, ym8, ym11, 12
+    vinserti32x8         m0, [base+pw_0to31], 0
+    palignr             ym4, ym8, ym11, 14
+    palignr             ym1, ym2, ym8, 4
+    paddw               ym3, ym5
+    palignr             ym2, ym8, 2
+    paddw               ym8, ym4
+    pavgw               ym3, ym1
+    paddw               ym8, ym2
+    paddw               ym8, ym3
+    psrlw               ym8, 2
+    vpermw               m8, m0, m8
+.w16_h64_main:
+    vbroadcasti32x8      m0, [base+pw_1to32]
+    vpbroadcastw         m4, dyd
+    pmullw               m4, m0    ; ypos
+    vpbroadcastd        ym1, [base+pw_32]
+    paddd                m1, [base+pw_32672] {1to16}
+    mov                  r2, strideq
+    shl                  r2, 5      ; stride*32
+    vpbroadcastd         m9, [base+pw_32735]
+    lea                  r3, [r2+strideq]
+    psrlw                m2, m4, 6
+    psllw                m4, 9
+    paddsw               m2, m1     ; base+0
+    vpandd               m4, m14    ; frac << 9
+    mova                 m3, m7
+    vpermt2w             m3, m2, m6
+    vpcmpgtw             k1, m2, m9
+    vpermw           m3{k1}, m2, m8 ; left[base+0]
+.w16_h64_loop:
+    paddsw               m2, m15    ; base+1
+    mova                 m1, m7
+    vpermt2w             m1, m2, m6
+    vpcmpgtw             k1, m2, m9
+    vpermw           m1{k1}, m2, m8 ; left[base+1]
+    psubw                m0, m1, m3
+    pmulhrsw             m0, m4
+    paddsw               m2, m15    ; base+2
+    paddw                m0, m3
+    mova                 m3, m7
+    vpermt2w             m3, m2, m6
+    vpcmpgtw             k1, m2, m9
+    vpermw           m3{k1}, m2, m8 ; left[base+2]
+    vextracti32x8 [dstq+strideq*0], m0, 1
+    mova          [dstq+r2       ], ym0
+    psubw                m0, m3, m1
+    pmulhrsw             m0, m4
+    paddw                m0, m1
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+r3       ], ym0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 4
+    jg .w16_h64_loop
+    RET
+.filter64:
+    vpbroadcastw         m2, [tlq]
+    vpbroadcastd         m5, [base+pw_3]
+    valignq              m2, m6, m2, 6
+    valignq              m4, m7, m6, 2
+    valignq             m10, m7, m6, 6
+    palignr              m1, m6, m2, 12
+    palignr              m2, m6, m2, 14
+    palignr              m3, m4, m6, 4
+    paddw                m1, m5
+    palignr              m4, m6, 2
+    paddw                m6, m2
+    valignq              m2, m8, m7, 2
+    pavgw                m1, m3
+    palignr              m3, m7, m10, 12
+    paddw                m6, m4
+    palignr              m4, m7, m10, 14
+    paddw                m6, m1
+    palignr              m1, m2, m7, 4
+    psrlw                m6, 2
+    palignr              m2, m7, 2
+    paddw                m3, m5
+    paddw                m7, m4
+    pavgw                m3, m1
+    paddw                m7, m2
+    paddw                m7, m3
+    psrlw                m7, 2
+    ret
+.w32:
+    mova                 m6, [tlq-64*1]
+    cmp                  hd, 32
+    jl .w32_h16
+    mova                 m8, [tlq-64*2]
+    vpermw               m6, m0, m6
+    vpermw               m7, m0, m8
+    jg .w32_h64
+    test             angled, 0x400
+    jnz .w32_main
+    vpbroadcastw        xm8, xm8
+    jmp .w32_filter
+.w32_h16:
+    lea                 r3d, [hq*2-1]
+    xor                 r3d, 31 ; 32 - (h + imin(w, h))
+    vpbroadcastw         m1, r3d
+    vpermw               m7, m1, m6
+    pmaxuw               m1, m0
+    vpermw               m6, m1, m6
+    test             angled, 0x400
+    jnz .w32_main
+    vextracti32x4       xm8, m7, 3
+.w32_filter:
+    call .filter64
+.w32_main:
+    vpbroadcastw         m4, dyd
+    vpbroadcastd         m1, [base+pw_32704]
+    pmullw               m4, [base+pw_1to32] ; ypos
+    psrlw                m2, m4, 6
+    psllw                m4, 9
+    paddsw               m2, m1      ; base+0
+    vpandd               m4, m14     ; frac << 9
+    mova                 m3, m6
+    vpermt2w             m3, m2, m7  ; left[base+0]
+.w32_loop:
+    paddsw               m1, m2, m15 ; base+1
+    paddsw               m2, m1, m15 ; base+2
+    vpermi2w             m1, m6, m7  ; left[base+1]
+    psubw                m0, m1, m3
+    pmulhrsw             m0, m4
+    paddw                m0, m3
+    mova                 m3, m6
+    vpermt2w             m3, m2, m7  ; left[base+2]
+    mova   [dstq+strideq*0], m0
+    psubw                m0, m3, m1
+    pmulhrsw             m0, m4
+    paddw                m0, m1
+    mova   [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w32_h64:
+    mova                 m9, [tlq-64*3]
+    vpermw               m8, m0, m9
+    test             angled, 0x400
+    jnz .w32_h64_main
+    vpbroadcastw        xm9, xm9
+    call .filter96
+.w32_h64_main:
+    vpbroadcastw         m4, dyd
+    vpbroadcastd         m1, [base+pw_32672]
+    pmullw               m4, [base+pw_1to32] ; ypos
+    vpbroadcastd         m9, [base+pw_32735]
+    psrlw                m2, m4, 6
+    psllw                m4, 9
+    paddsw               m2, m1     ; base+0
+    vpandd               m4, m14    ; frac << 9
+    mova                 m3, m7
+    vpermt2w             m3, m2, m6
+    vpcmpgtw             k1, m2, m9
+    vpermw           m3{k1}, m2, m8 ; left[base+0]
+.w32_h64_loop:
+    paddsw               m2, m15    ; base+1
+    mova                 m1, m7
+    vpermt2w             m1, m2, m6
+    vpcmpgtw             k1, m2, m9
+    vpermw           m1{k1}, m2, m8 ; left[base+1]
+    psubw                m0, m1, m3
+    pmulhrsw             m0, m4
+    paddsw               m2, m15    ; base+2
+    paddw                m0, m3
+    mova                 m3, m7
+    vpermt2w             m3, m2, m6
+    vpcmpgtw             k1, m2, m9
+    vpermw           m3{k1}, m2, m8 ; left[base+2]
+    mova   [dstq+strideq*0], m0
+    psubw                m0, m3, m1
+    pmulhrsw             m0, m4
+    paddw                m0, m1
+    mova   [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_h64_loop
+    RET
+.filter96:
+    valignq             m11, m8, m7, 6
+    call .filter64
+    valignq              m2, m9, m8, 2
+    palignr              m3, m8, m11, 12
+    palignr              m4, m8, m11, 14
+    palignr              m1, m2, m8, 4
+    paddw                m3, m5
+    palignr              m2, m8, 2
+    paddw                m8, m4
+    pavgw                m3, m1
+    paddw                m8, m2
+    paddw                m8, m3
+    psrlw                m8, 2
+    ret
+.w64:
+    mova                 m7, [tlq-64*1]
+    vpermw               m6, m0, m7
+    cmp                  hd, 32
+    jl .w64_h16
+    mova                 m8, [tlq-64*2]
+    vpermw               m7, m0, m8
+    jg .w64_h64
+    test             angled, 0x400
+    jnz .w64_main
+    vpbroadcastw         m8, xm8
+    mova                 m9, m8
+    call .filter96
+    vshufi32x4           m9, m8, m8, q3333
+    jmp .w64_h64_main
+.w64_h16:
+    vpbroadcastw         m7, xm7
+    test             angled, 0x400
+    jnz .w64_main
+    mova                 m8, m7
+    call .filter64
+.w64_main:
+    vpbroadcastw        m11, dyd
+    vpbroadcastd         m1, [base+pw_32704]
+    pmullw              m10, m11, [base+pw_1to32] ; ypos
+    psllw               m11, 5
+    psrlw                m8, m10, 6
+    paddw               m11, m10
+    psllw               m10, 9
+    psrlw                m9, m11, 6
+    psllw               m11, 9
+    psubw                m9, m8
+    paddsw               m8, m1     ; base+0
+    vpandd              m10, m14    ; frac << 9
+    vpandd              m11, m14    ; frac << 9
+    mova                 m4, m6
+    vpermt2w             m4, m8, m7 ; left[base+0] ( 0..31)
+    paddsw               m5, m8, m9
+    vpermi2w             m5, m6, m7 ; left[base+0] (32..63)
+.w64_loop:
+    paddsw               m8, m15    ; base+1      ( 0..31)
+    mova                 m2, m6
+    vpermt2w             m2, m8, m7 ; left[base+1] ( 0..31)
+    paddsw               m3, m8, m9 ; base+1      (32..63)
+    vpermi2w             m3, m6, m7 ; left[base+1] (32..63)
+    psubw                m0, m2, m4
+    psubw                m1, m3, m5
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m11
+    paddw                m0, m4
+    paddw                m1, m5
+    mova                 m4, m2
+    mova        [dstq+64*0], m0
+    mova                 m5, m3
+    mova        [dstq+64*1], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+.w64_h64:
+    vpermw               m8, m0, [tlq-64*3]
+    mova                m13, [tlq-64*4]
+    vpermw               m9, m0, m13
+    test             angled, 0x400
+    jnz .w64_h64_main
+    valignq             m12, m9, m8, 6
+    call .filter96
+    vpbroadcastw        xm2, xm13
+    valignq              m2, m9, 2
+    palignr              m3, m9, m12, 12
+    palignr              m4, m9, m12, 14
+    palignr              m1, m2, m9, 4
+    paddw                m3, m5
+    palignr              m2, m9, 2
+    paddw                m9, m4
+    pavgw                m3, m1
+    paddw                m9, m2
+    paddw                m9, m3
+    psrlw                m9, 2
+.w64_h64_main:
+    vpbroadcastw        m11, dyd
+    vpbroadcastd         m1, [base+pw_32640]
+    pmullw              m10, m11, [base+pw_1to32] ; ypos
+    psllw               m11, 5
+    psrlw               m12, m10, 6
+    paddw               m11, m10
+    psllw               m10, 9
+    psrlw               m13, m11, 6
+    psllw               m11, 9
+    psubw               m13, m12
+    paddsw              m12, m1     ; base+0
+    vpandd              m10, m14    ; frac << 9
+    vpandd              m11, m14    ; frac << 9
+    vpbroadcastd        m14, [base+pw_64]
+    mova                 m4, m6
+    vpermt2w             m4, m12, m7
+    vptestmw             k1, m12, m14
+    mova                 m0, m8
+    vpermt2w             m0, m12, m9
+    paddsw               m1, m12, m13
+    mova                 m5, m6
+    vpermt2w             m5, m1, m7
+    vptestmw             k2, m1, m14
+    vpermi2w             m1, m8, m9
+    vmovdqu16        m4{k1}, m0     ; left[base+0] ( 0..31)
+    vmovdqu16        m5{k2}, m1     ; left[base+0] (32..63)
+.w64_h64_loop:
+    paddsw              m12, m15    ; base+1
+    mova                 m2, m6
+    vpermt2w             m2, m12, m7
+    vptestmw             k1, m12, m14
+    mova                 m0, m8
+    vpermt2w             m0, m12, m9
+    paddsw               m1, m12, m13
+    mova                 m3, m6
+    vpermt2w             m3, m1, m7
+    vptestmw             k2, m1, m14
+    vpermi2w             m1, m8, m9
+    vmovdqu16        m2{k1}, m0     ; left[base+1] ( 0..31)
+    vmovdqu16        m3{k2}, m1     ; left[base+1] (32..63)
+    psubw                m0, m2, m4
+    psubw                m1, m3, m5
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m11
+    paddw                m0, m4
+    paddw                m1, m5
+    mova                 m4, m2
+    mova        [dstq+64*0], m0
+    mova                 m5, m3
+    mova        [dstq+64*1], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_h64_loop
+    RET
+
+cglobal pal_pred_16bpc, 4, 7, 7, dst, stride, pal, idx, w, h, stride3
+    lea                  r6, [pal_pred_16bpc_avx512icl_table]
+    tzcnt                wd, wm
+    mova                 m3, [pal_pred_perm]
+    movifnidn            hd, hm
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastq         m4, [pal_unpack+0]
+    vpbroadcastq         m5, [pal_unpack+8]
+    add                  wq, r6
+    vbroadcasti32x4      m6, [palq]
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    pmovzxbd            ym0, [idxq]
+    add                idxq, 8
+    vpmultishiftqb      ym0, ym4, ym0
+    vpermw              ym0, ym0, ym6
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    pmovzxbd             m0, [idxq]
+    add                idxq, 16
+    vpmultishiftqb       m0, m4, m0
+    vpermw               m0, m0, m6
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    movu                ym1, [idxq]
+    add                idxq, 32
+    vpermb               m1, m3, m1
+    vpmultishiftqb       m1, m4, m1
+    vpermw               m0, m1, m6
+    psrlw                m1, 8
+    vpermw               m1, m1, m6
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+stride3q ], m1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16
+    RET
+.w32:
+    vpermb               m2, m3, [idxq]
+    add                idxq, 64
+    vpmultishiftqb       m1, m4, m2
+    vpmultishiftqb       m2, m5, m2
+    vpermw               m0, m1, m6
+    psrlw                m1, 8
+    vpermw               m1, m1, m6
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    vpermw               m0, m2, m6
+    psrlw                m2, 8
+    vpermw               m1, m2, m6
+    mova   [dstq+strideq*2], m0
+    mova   [dstq+stride3q ], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w32
+    RET
+.w64:
+    vpermb               m2, m3, [idxq]
+    add                idxq, 64
+    vpmultishiftqb       m1, m4, m2
+    vpmultishiftqb       m2, m5, m2
+    vpermw               m0, m1, m6
+    psrlw                m1, 8
+    vpermw               m1, m1, m6
+    mova          [dstq+ 0], m0
+    mova          [dstq+64], m1
+    vpermw               m0, m2, m6
+    psrlw                m2, 8
+    vpermw               m1, m2, m6
+    mova  [dstq+strideq+ 0], m0
+    mova  [dstq+strideq+64], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w64
+    RET
+
+; The ipred_filter SIMD processes 4x2 blocks in the following order which
+; increases parallelism compared to doing things row by row.
+;     w4     w8       w16             w32
+;     1     1 2     1 2 5 6     1 2 5 6 9 a d e
+;     2     2 3     2 3 6 7     2 3 6 7 a b e f
+;     3     3 4     3 4 7 8     3 4 7 8 b c f g
+;     4     4 5     4 5 8 9     4 5 8 9 c d g h
+
+cglobal ipred_filter_16bpc, 4, 7, 14, dst, stride, tl, w, h, filter, top
+%define base r6-$$
+    lea                  r6, [$$]
+%ifidn filterd, filterm
+    movzx           filterd, filterb
+%else
+    movzx           filterd, byte filterm
+%endif
+    shl             filterd, 6
+    movifnidn            hd, hm
+    movu                xm0, [tlq-6]
+    pmovsxbw             m7, [base+filter_intra_taps+filterq+32*0]
+    pmovsxbw             m8, [base+filter_intra_taps+filterq+32*1]
+    mov                 r5d, r8m ; bitdepth_max
+    movsldup             m9, [base+filter_permA]
+    movshdup            m10, [base+filter_permA]
+    shr                 r5d, 11  ; is_12bpc
+    jnz .12bpc
+    psllw                m7, 2   ; upshift multipliers so that packusdw
+    psllw                m8, 2   ; will perform clipping for free
+.12bpc:
+    vpbroadcastd         m5, [base+filter_rnd+r5*8]
+    vpbroadcastd         m6, [base+filter_shift+r5*8]
+    sub                  wd, 8
+    jl .w4
+.w8:
+    call .main4
+    movsldup            m11, [filter_permB]
+    lea                 r5d, [hq*2+2]
+    movshdup            m12, [filter_permB]
+    lea                topq, [tlq+2]
+    mova                m13, [filter_permC]
+    sub                  hd, 4
+    vinserti32x4        ym0, [topq], 1 ; a0 b0   t0 t1
+    sub                 tlq, r5
+%if WIN64
+    push                 r7
+    push                 r8
+%endif
+    mov                  r7, dstq
+    mov                 r8d, hd
+.w8_loop:
+    movlps              xm4, xm0, [tlq+hq*2]
+    call .main8
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jge .w8_loop
+    test                 wd, wd
+    jz .end
+    mov                 r2d, 0x0d
+    kmovb                k1, r2d
+    lea                  r2, [strideq*3]
+.w16:
+    movd               xmm0, [r7+strideq*1+12]
+    vpblendd           xmm0, [topq+8], 0x0e ; t1 t2
+    pinsrw              xm4, xmm0, [r7+strideq*0+14], 2
+    call .main8
+    add                  r7, 16
+    vinserti32x4        ym0, [topq+16], 1   ; a2 b2   t2 t3
+    mov                  hd, r8d
+    mov                dstq, r7
+    add                topq, 16
+.w16_loop:
+    movd               xmm1, [dstq+strideq*2-4]
+    punpcklwd           xm4, xmm1, xmm0
+    movd               xmm0, [dstq+r2-4]
+    shufps          xm4{k1}, xmm0, xm0, q3210
+    call .main8
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jge .w16_loop
+    sub                  wd, 8
+    jg .w16
+.end:
+    vpermb               m2, m11, m0
+    mova                ym1, ym5
+    vpdpwssd             m1, m2, m7
+    vpermb               m2, m12, m0
+    vpdpwssd             m1, m2, m8
+%if WIN64
+    pop                  r8
+    pop                  r7
+%endif
+    vextracti32x8       ym2, m1, 1
+    paddd               ym1, ym2
+    packusdw            ym1, ym1
+    vpsrlvw             ym1, ym6
+    vpermt2q             m0, m13, m1
+    vextracti32x4 [dstq+strideq*0], m0, 2
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    RET
+.w4_loop:
+    movlps              xm0, [tlq-10]
+    lea                dstq, [dstq+strideq*2]
+    sub                 tlq, 4
+.w4:
+    call .main4
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+ALIGN function_align
+.main4:
+    vpermb               m2, m9, m0
+    mova                ym1, ym5
+    vpdpwssd             m1, m2, m7
+    vpermb               m0, m10, m0
+    vpdpwssd             m1, m0, m8
+    vextracti32x8       ym0, m1, 1
+    paddd               ym0, ym1
+    vextracti32x4       xm1, ym0, 1
+    packusdw            xm0, xm1     ; clip
+    vpsrlvw             xm0, xm6
+    ret
+ALIGN function_align
+.main8:
+    vpermb               m3, m11, m0
+    mova                ym2, ym5
+    vpdpwssd             m2, m3, m7
+    vpermb               m3, m9, m4
+    mova                ym1, ym5
+    vpdpwssd             m1, m3, m7
+    vpermb               m3, m12, m0
+    vpdpwssd             m2, m3, m8
+    vpermb               m3, m10, m4
+    vpdpwssd             m1, m3, m8
+    vextracti32x8       ym4, m2, 1
+    vextracti32x8       ym3, m1, 1
+    paddd               ym2, ym4
+    paddd               ym1, ym3
+    packusdw            ym1, ym2     ; clip
+    vpsrlvw             ym1, ym6
+    vpermt2q             m0, m13, m1 ; c0 d0   b0 b1   a0 a1
+    vextracti32x4 [dstq+strideq*0], m0, 2
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    ret
+
+%endif
diff --git a/media/libdav1d/src/src/x86/ipred16_sse.asm b/media/libdav1d/src/src/x86/ipred16_sse.asm
new file mode 100644
index 0000000000..5a311b1442
--- /dev/null
+++ b/media/libdav1d/src/src/x86/ipred16_sse.asm
@@ -0,0 +1,4103 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA
+
+filter_shuf:   db  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,  4,  5,  2,  3, -1, -1
+pal_pred_shuf: db  0,  2,  4,  6,  8, 10, 12, 14,  1,  3,  5,  7,  9, 11, 13, 15
+z_base_inc:    dw   0*64,   1*64,   2*64,   3*64,   4*64,   5*64,   6*64,   7*64
+z_base_inc_z2: dw   7*64,   6*64,   5*64,   4*64,   3*64,   2*64,   1*64,   0*64
+z_upsample:    db  0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+z2_upsample_l: db -1, -1, -2, -1, -3, -1, -4, -1,  8,  9,  8,  9, 10, 11, 12, 13
+               db  0,  1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13
+z2_top_shufA:  db  0,  1,  2,  3,  4,  5,  6,  7,  2,  3,  4,  5,  6,  7,  8,  9
+z2_top_shufB:  db  0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+z2_left_shufA: db 14, 15, 12, 13, 10, 11,  8,  9, 12, 13, 10, 11,  8,  9,  6,  7
+z2_left_shufB: db 14, 15, 10, 11,  6,  7,  2,  3, 12, 13,  8,  9,  4,  5,  0,  1
+z_filt_wh16:   db 19, 19, 19, 23, 23, 23, 31, 31, 31, 47, 47, 47, 79, 79, 79, -1
+z_filt_t_w48:  db 55,127,  7,127, 15, 31, 39, 31,127, 39,127, 39,  7, 15, 31, 15
+               db 39, 63,  3, 63,  3,  3, 19,  3, 47, 19, 47, 19,  3,  3,  3,  3
+z_filt_t_w16:  db 15, 31,  7, 15, 31,  7,  3, 31,  3,  3,  3,  3,  3,  3,  0,  0
+z_filt_wh4:    db  7,  7, 19,  7,
+z_filt_wh8:    db 19, 19, 11, 19, 11, 15, 15, 15, 23, 23, 23, 23, 39, 39, 39, 39
+ALIGN 8
+pb_2_3:   times 4 db 2, 3
+z2_dy_offset:     dw 96*64, 96*64, 95*64, 95*64
+z_filt_k: times 4 dw 8
+          times 4 dw 6
+          times 4 dw 4
+          times 4 dw 5
+pw_m3584: times 4 dw -3584
+pw_m3072: times 4 dw -3072
+pw_m2560: times 4 dw -2560
+pw_m2048: times 4 dw -2048
+pw_m1536: times 4 dw -1536
+pw_m1024: times 4 dw -1024
+pw_m512:  times 4 dw -512
+pw_1:     times 4 dw 1
+pw_2:     times 4 dw 2
+pw_3:     times 4 dw 3
+pw_62:    times 4 dw 62
+pw_256:   times 4 dw 256
+pw_512:   times 4 dw 512
+pw_2048:  times 4 dw 2048
+
+%define pw_4 (z_filt_k+8*2)
+%define pw_8 (z_filt_k+8*0)
+%define pw_m1to4 z2_upsample_l
+
+%macro JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - 2*4)
+    %xdefine %%base mangle(private_prefix %+ _%1_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%base %+ .%3 - (%%table - 2*4)
+        %rotate 1
+    %endrep
+%endmacro
+
+%define ipred_dc_splat_16bpc_ssse3_table (ipred_dc_16bpc_ssse3_table + 10*4)
+%define ipred_dc_128_16bpc_ssse3_table   (ipred_dc_16bpc_ssse3_table + 15*4)
+%define ipred_cfl_splat_16bpc_ssse3_table (ipred_cfl_16bpc_ssse3_table + 8*4)
+
+JMP_TABLE ipred_dc_left_16bpc,    ssse3, h4, h8, h16, h32, h64
+JMP_TABLE ipred_dc_16bpc,         ssse3, h4, h8, h16, h32, h64, w4, w8, w16, w32, w64, \
+                                         s4-10*4, s8-10*4, s16-10*4, s32-10*4, s64-10*4, \
+                                         s4-15*4, s8-15*4, s16c-15*4, s32c-15*4, s64-15*4
+JMP_TABLE ipred_h_16bpc,          ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z1_16bpc,         ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z2_16bpc,         ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z3_16bpc,         ssse3, h4, h8, h16, h32, h64
+JMP_TABLE ipred_cfl_16bpc,        ssse3, h4, h8, h16, h32, w4, w8, w16, w32, \
+                                         s4-8*4, s8-8*4, s16-8*4, s32-8*4
+JMP_TABLE ipred_cfl_left_16bpc,   ssse3, h4, h8, h16, h32
+JMP_TABLE ipred_cfl_ac_444_16bpc, ssse3, w4, w8, w16, w32
+JMP_TABLE pal_pred_16bpc,         ssse3, w4, w8, w16, w32, w64
+
+cextern smooth_weights_1d_16bpc
+cextern smooth_weights_2d_16bpc
+cextern dr_intra_derivative
+cextern filter_intra_taps
+
+SECTION .text
+
+INIT_XMM ssse3
+cglobal ipred_dc_top_16bpc, 3, 7, 6, dst, stride, tl, w, h
+    LEA                  r5, ipred_dc_left_16bpc_ssse3_table
+    movd                 m4, wm
+    tzcnt                wd, wm
+    add                 tlq, 2
+    movifnidn            hd, hm
+    pxor                 m3, m3
+    pavgw                m4, m3
+    movd                 m5, wd
+    movu                 m0, [tlq]
+    movsxd               r6, [r5+wq*4]
+    add                  r6, r5
+    add                  r5, ipred_dc_128_16bpc_ssse3_table-ipred_dc_left_16bpc_ssse3_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+
+cglobal ipred_dc_left_16bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    LEA                  r5, ipred_dc_left_16bpc_ssse3_table
+    mov                  hd, hm
+    movd                 m4, hm
+    tzcnt               r6d, hd
+    sub                 tlq, hq
+    tzcnt                wd, wm
+    pxor                 m3, m3
+    sub                 tlq, hq
+    pavgw                m4, m3
+    movd                 m5, r6d
+    movu                 m0, [tlq]
+    movsxd               r6, [r5+r6*4]
+    add                  r6, r5
+    add                  r5, ipred_dc_128_16bpc_ssse3_table-ipred_dc_left_16bpc_ssse3_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+.h64:
+    movu                 m2, [tlq+112]
+    movu                 m1, [tlq+ 96]
+    paddw                m0, m2
+    movu                 m2, [tlq+ 80]
+    paddw                m1, m2
+    movu                 m2, [tlq+ 64]
+    paddw                m0, m2
+    paddw                m0, m1
+.h32:
+    movu                 m1, [tlq+ 48]
+    movu                 m2, [tlq+ 32]
+    paddw                m1, m2
+    paddw                m0, m1
+.h16:
+    movu                 m1, [tlq+ 16]
+    paddw                m0, m1
+.h8:
+    movhlps              m1, m0
+    paddw                m0, m1
+.h4:
+    punpcklwd            m0, m3
+    paddd                m4, m0
+    punpckhqdq           m0, m0
+    paddd                m0, m4
+    pshuflw              m4, m0, q1032
+    paddd                m0, m4
+    psrld                m0, m5
+    lea            stride3q, [strideq*3]
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+    jmp                  wq
+
+cglobal ipred_dc_16bpc, 4, 7, 6, dst, stride, tl, w, h, stride3
+    movifnidn            hd, hm
+    tzcnt               r6d, hd
+    lea                 r5d, [wq+hq]
+    movd                 m4, r5d
+    tzcnt               r5d, r5d
+    movd                 m5, r5d
+    LEA                  r5, ipred_dc_16bpc_ssse3_table
+    tzcnt                wd, wd
+    movsxd               r6, [r5+r6*4]
+    movsxd               wq, [r5+wq*4+5*4]
+    pxor                 m3, m3
+    psrlw                m4, 1
+    add                  r6, r5
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  r6
+.h4:
+    movq                 m0, [tlq-8]
+    jmp                  wq
+.w4:
+    movq                 m1, [tlq+2]
+    paddw                m1, m0
+    punpckhwd            m0, m3
+    punpcklwd            m1, m3
+    paddd                m0, m1
+    paddd                m4, m0
+    punpckhqdq           m0, m0
+    paddd                m0, m4
+    pshuflw              m1, m0, q1032
+    paddd                m0, m1
+    cmp                  hd, 4
+    jg .w4_mul
+    psrlw                m0, 3
+    jmp .w4_end
+.w4_mul:
+    mov                 r2d, 0xAAAB
+    mov                 r3d, 0x6667
+    cmp                  hd, 16
+    cmove               r2d, r3d
+    psrld                m0, 2
+    movd                 m1, r2d
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w4_end:
+    pshuflw              m0, m0, q0000
+.s4:
+    movq   [dstq+strideq*0], m0
+    movq   [dstq+strideq*1], m0
+    movq   [dstq+strideq*2], m0
+    movq   [dstq+stride3q ], m0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s4
+    RET
+.h8:
+    mova                 m0, [tlq-16]
+    jmp                  wq
+.w8:
+    movu                 m1, [tlq+2]
+    paddw                m0, m1
+    punpcklwd            m1, m0, m3
+    punpckhwd            m0, m3
+    paddd                m0, m1
+    paddd                m4, m0
+    punpckhqdq           m0, m0
+    paddd                m0, m4
+    pshuflw              m1, m0, q1032
+    paddd                m0, m1
+    psrld                m0, m5
+    cmp                  hd, 8
+    je .w8_end
+    mov                 r2d, 0xAAAB
+    mov                 r3d, 0x6667
+    cmp                  hd, 32
+    cmove               r2d, r3d
+    movd                 m1, r2d
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w8_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s8:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m0
+    mova   [dstq+strideq*2], m0
+    mova   [dstq+stride3q ], m0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s8
+    RET
+.h16:
+    mova                 m0, [tlq-32]
+    paddw                m0, [tlq-16]
+    jmp                  wq
+.w16:
+    movu                 m1, [tlq+ 2]
+    movu                 m2, [tlq+18]
+    paddw                m1, m2
+    paddw                m0, m1
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    paddd                m0, m1
+    paddd                m4, m0
+    punpckhqdq           m0, m0
+    paddd                m0, m4
+    pshuflw              m1, m0, q1032
+    paddd                m0, m1
+    psrld                m0, m5
+    cmp                  hd, 16
+    je .w16_end
+    mov                 r2d, 0xAAAB
+    mov                 r3d, 0x6667
+    test                 hd, 8|32
+    cmovz               r2d, r3d
+    movd                 m1, r2d
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w16_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s16c:
+    mova                 m1, m0
+.s16:
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*0+16*1], m1
+    mova [dstq+strideq*1+16*0], m0
+    mova [dstq+strideq*1+16*1], m1
+    mova [dstq+strideq*2+16*0], m0
+    mova [dstq+strideq*2+16*1], m1
+    mova [dstq+stride3q +16*0], m0
+    mova [dstq+stride3q +16*1], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s16
+    RET
+.h32:
+    mova                 m0, [tlq-64]
+    paddw                m0, [tlq-48]
+    paddw                m0, [tlq-32]
+    paddw                m0, [tlq-16]
+    jmp                  wq
+.w32:
+    movu                 m1, [tlq+ 2]
+    movu                 m2, [tlq+18]
+    paddw                m1, m2
+    movu                 m2, [tlq+34]
+    paddw                m0, m2
+    movu                 m2, [tlq+50]
+    paddw                m1, m2
+    paddw                m0, m1
+    punpcklwd            m1, m0, m3
+    punpckhwd            m0, m3
+    paddd                m0, m1
+    paddd                m4, m0
+    punpckhqdq           m0, m0
+    paddd                m0, m4
+    pshuflw              m1, m0, q1032
+    paddd                m0, m1
+    psrld                m0, m5
+    cmp                  hd, 32
+    je .w32_end
+    mov                 r2d, 0xAAAB
+    mov                 r3d, 0x6667
+    cmp                  hd, 8
+    cmove               r2d, r3d
+    movd                 m1, r2d
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w32_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s32c:
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+.s32:
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*0+16*1], m1
+    mova [dstq+strideq*0+16*2], m2
+    mova [dstq+strideq*0+16*3], m3
+    mova [dstq+strideq*1+16*0], m0
+    mova [dstq+strideq*1+16*1], m1
+    mova [dstq+strideq*1+16*2], m2
+    mova [dstq+strideq*1+16*3], m3
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .s32
+    RET
+.h64:
+    mova                 m0, [tlq-128]
+    mova                 m1, [tlq-112]
+    paddw                m0, [tlq- 96]
+    paddw                m1, [tlq- 80]
+    paddw                m0, [tlq- 64]
+    paddw                m1, [tlq- 48]
+    paddw                m0, [tlq- 32]
+    paddw                m1, [tlq- 16]
+    paddw                m0, m1
+    jmp                  wq
+.w64:
+    movu                 m1, [tlq+  2]
+    movu                 m2, [tlq+ 18]
+    paddw                m1, m2
+    movu                 m2, [tlq+ 34]
+    paddw                m0, m2
+    movu                 m2, [tlq+ 50]
+    paddw                m1, m2
+    movu                 m2, [tlq+ 66]
+    paddw                m0, m2
+    movu                 m2, [tlq+ 82]
+    paddw                m1, m2
+    movu                 m2, [tlq+ 98]
+    paddw                m0, m2
+    movu                 m2, [tlq+114]
+    paddw                m1, m2
+    paddw                m0, m1
+    punpcklwd            m1, m0, m3
+    punpckhwd            m0, m3
+    paddd                m0, m1
+    paddd                m4, m0
+    punpckhqdq           m0, m0
+    paddd                m0, m4
+    pshuflw              m1, m0, q1032
+    paddd                m0, m1
+    psrld                m0, m5
+    cmp                  hd, 64
+    je .w64_end
+    mov                 r2d, 0xAAAB
+    mov                 r3d, 0x6667
+    cmp                  hd, 16
+    cmove               r2d, r3d
+    movd                 m1, r2d
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w64_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s64:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m0
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m0
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m0
+    mova        [dstq+16*6], m0
+    mova        [dstq+16*7], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .s64
+    RET
+
+cglobal ipred_dc_128_16bpc, 2, 7, 6, dst, stride, tl, w, h, stride3
+    mov                 r6d, r8m
+    LEA                  r5, ipred_dc_128_16bpc_ssse3_table
+    tzcnt                wd, wm
+    shr                 r6d, 11
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    movddup              m0, [r5-ipred_dc_128_16bpc_ssse3_table+pw_512+r6*8]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+cglobal ipred_v_16bpc, 4, 7, 6, dst, stride, tl, w, h, stride3
+    LEA                  r5, ipred_dc_splat_16bpc_ssse3_table
+    movifnidn            hd, hm
+    movu                 m0, [tlq+  2]
+    movu                 m1, [tlq+ 18]
+    movu                 m2, [tlq+ 34]
+    movu                 m3, [tlq+ 50]
+    cmp                  wd, 64
+    je .w64
+    tzcnt                wd, wd
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w64:
+    WIN64_SPILL_XMM 8
+    movu                 m4, [tlq+ 66]
+    movu                 m5, [tlq+ 82]
+    movu                 m6, [tlq+ 98]
+    movu                 m7, [tlq+114]
+.w64_loop:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    mova        [dstq+16*2], m2
+    mova        [dstq+16*3], m3
+    mova        [dstq+16*4], m4
+    mova        [dstq+16*5], m5
+    mova        [dstq+16*6], m6
+    mova        [dstq+16*7], m7
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+
+cglobal ipred_h_16bpc, 3, 6, 4, dst, stride, tl, w, h, stride3
+%define base r5-ipred_h_16bpc_ssse3_table
+    tzcnt                wd, wm
+    LEA                  r5, ipred_h_16bpc_ssse3_table
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    movddup              m2, [base+pw_256]
+    movddup              m3, [base+pb_2_3]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    sub                 tlq, 8
+    movq                 m3, [tlq]
+    pshuflw              m0, m3, q3333
+    pshuflw              m1, m3, q2222
+    pshuflw              m2, m3, q1111
+    pshuflw              m3, m3, q0000
+    movq   [dstq+strideq*0], m0
+    movq   [dstq+strideq*1], m1
+    movq   [dstq+strideq*2], m2
+    movq   [dstq+stride3q ], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    sub                 tlq, 8
+    movq                 m3, [tlq]
+    punpcklwd            m3, m3
+    pshufd               m0, m3, q3333
+    pshufd               m1, m3, q2222
+    pshufd               m2, m3, q1111
+    pshufd               m3, m3, q0000
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+stride3q ], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    sub                 tlq, 4
+    movd                 m1, [tlq]
+    pshufb               m0, m1, m3
+    pshufb               m1, m2
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*0+16*1], m0
+    mova [dstq+strideq*1+16*0], m1
+    mova [dstq+strideq*1+16*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16
+    RET
+.w32:
+    sub                 tlq, 4
+    movd                 m1, [tlq]
+    pshufb               m0, m1, m3
+    pshufb               m1, m2
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*0+16*1], m0
+    mova [dstq+strideq*0+16*2], m0
+    mova [dstq+strideq*0+16*3], m0
+    mova [dstq+strideq*1+16*0], m1
+    mova [dstq+strideq*1+16*1], m1
+    mova [dstq+strideq*1+16*2], m1
+    mova [dstq+strideq*1+16*3], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32
+    RET
+.w64:
+    sub                 tlq, 2
+    movd                 m0, [tlq]
+    pshufb               m0, m2
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m0
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m0
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m0
+    mova        [dstq+16*6], m0
+    mova        [dstq+16*7], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64
+    RET
+
+cglobal ipred_paeth_16bpc, 4, 6, 8, dst, stride, tl, w, h, left
+%define base r5-ipred_paeth_16bpc_ssse3_table
+    movifnidn            hd, hm
+    pshuflw              m4, [tlq], q0000
+    mov               leftq, tlq
+    add                  hd, hd
+    punpcklqdq           m4, m4      ; topleft
+    sub               leftq, hq
+    and                  wd, ~7
+    jnz .w8
+    movddup              m5, [tlq+2] ; top
+    psubw                m6, m5, m4
+    pabsw                m7, m6
+.w4_loop:
+    movd                 m1, [leftq+hq-4]
+    punpcklwd            m1, m1
+    punpckldq            m1, m1      ; left
+%macro PAETH 0
+    paddw                m0, m6, m1
+    psubw                m2, m4, m0  ; tldiff
+    psubw                m0, m5      ; tdiff
+    pabsw                m2, m2
+    pabsw                m0, m0
+    pminsw               m2, m0
+    pcmpeqw              m0, m2
+    pand                 m3, m5, m0
+    pandn                m0, m4
+    por                  m0, m3
+    pcmpgtw              m3, m7, m2
+    pand                 m0, m3
+    pandn                m3, m1
+    por                  m0, m3
+%endmacro
+    PAETH
+    movhps [dstq+strideq*0], m0
+    movq   [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2*2
+    jg .w4_loop
+    RET
+.w8:
+%if ARCH_X86_32
+    PUSH                 r6
+    %define             r7d  hm
+    %assign regs_used     7
+%elif WIN64
+    movaps              r4m, m8
+    PUSH                 r7
+    %assign regs_used     8
+%endif
+%if ARCH_X86_64
+    movddup              m8, [pw_256]
+%endif
+    lea                 tlq, [tlq+wq*2+2]
+    neg                  wq
+    mov                 r7d, hd
+.w8_loop0:
+    movu                 m5, [tlq+wq*2]
+    mov                  r6, dstq
+    add                dstq, 16
+    psubw                m6, m5, m4
+    pabsw                m7, m6
+.w8_loop:
+    movd                 m1, [leftq+hq-2]
+%if ARCH_X86_64
+    pshufb               m1, m8
+%else
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+%endif
+    PAETH
+    mova               [r6], m0
+    add                  r6, strideq
+    sub                  hd, 1*2
+    jg .w8_loop
+    mov                  hd, r7d
+    add                  wq, 8
+    jl .w8_loop0
+%if WIN64
+    movaps               m8, r4m
+%endif
+    RET
+
+%if ARCH_X86_64
+DECLARE_REG_TMP 7
+%else
+DECLARE_REG_TMP 4
+%endif
+
+cglobal ipred_smooth_v_16bpc, 4, 6, 6, dst, stride, tl, w, h, weights
+    LEA            weightsq, smooth_weights_1d_16bpc
+    mov                  hd, hm
+    lea            weightsq, [weightsq+hq*4]
+    neg                  hq
+    movd                 m5, [tlq+hq*2] ; bottom
+    pshuflw              m5, m5, q0000
+    punpcklqdq           m5, m5
+    cmp                  wd, 4
+    jne .w8
+    movddup              m4, [tlq+2]    ; top
+    lea                  r3, [strideq*3]
+    psubw                m4, m5         ; top - bottom
+.w4_loop:
+    movq                 m1, [weightsq+hq*2]
+    punpcklwd            m1, m1
+    pshufd               m0, m1, q1100
+    punpckhdq            m1, m1
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    paddw                m0, m5
+    paddw                m1, m5
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movq   [dstq+strideq*2], m1
+    movhps [dstq+r3       ], m1
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w4_loop
+    RET
+.w8:
+%if ARCH_X86_32
+    PUSH                 r6
+    %assign regs_used     7
+    mov                  hm, hq
+    %define              hq  hm
+%elif WIN64
+    PUSH                 r7
+    %assign regs_used     8
+%endif
+.w8_loop0:
+    mov                  t0, hq
+    movu                 m4, [tlq+2]
+    add                 tlq, 16
+    mov                  r6, dstq
+    add                dstq, 16
+    psubw                m4, m5
+.w8_loop:
+    movq                 m3, [weightsq+t0*2]
+    punpcklwd            m3, m3
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    REPX   {paddw    x, m5}, m0, m1, m2, m3
+    mova     [r6+strideq*0], m0
+    mova     [r6+strideq*1], m1
+    lea                  r6, [r6+strideq*2]
+    mova     [r6+strideq*0], m2
+    mova     [r6+strideq*1], m3
+    lea                  r6, [r6+strideq*2]
+    add                  t0, 4
+    jl .w8_loop
+    sub                  wd, 8
+    jg .w8_loop0
+    RET
+
+cglobal ipred_smooth_h_16bpc, 3, 6, 6, dst, stride, tl, w, h, weights
+    LEA            weightsq, smooth_weights_1d_16bpc
+    mov                  wd, wm
+    movifnidn            hd, hm
+    movd                 m5, [tlq+wq*2] ; right
+    sub                 tlq, 8
+    add                  hd, hd
+    pshuflw              m5, m5, q0000
+    sub                 tlq, hq
+    punpcklqdq           m5, m5
+    cmp                  wd, 4
+    jne .w8
+    movddup              m4, [weightsq+4*2]
+    lea                  r3, [strideq*3]
+.w4_loop:
+    movq                 m1, [tlq+hq]   ; left
+    punpcklwd            m1, m1
+    psubw                m1, m5         ; left - right
+    pshufd               m0, m1, q3322
+    punpckldq            m1, m1
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    paddw                m0, m5
+    paddw                m1, m5
+    movhps [dstq+strideq*0], m0
+    movq   [dstq+strideq*1], m0
+    movhps [dstq+strideq*2], m1
+    movq   [dstq+r3       ], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4*2
+    jg .w4_loop
+    RET
+.w8:
+    lea            weightsq, [weightsq+wq*4]
+    neg                  wq
+%if ARCH_X86_32
+    PUSH                 r6
+    %assign regs_used     7
+    %define              hd  hm
+%elif WIN64
+    PUSH                 r7
+    %assign regs_used     8
+%endif
+.w8_loop0:
+    mov                 t0d, hd
+    mova                 m4, [weightsq+wq*2]
+    mov                  r6, dstq
+    add                dstq, 16
+.w8_loop:
+    movq                 m3, [tlq+t0*(1+ARCH_X86_32)]
+    punpcklwd            m3, m3
+    psubw                m3, m5
+    pshufd               m0, m3, q3333
+    pshufd               m1, m3, q2222
+    pshufd               m2, m3, q1111
+    pshufd               m3, m3, q0000
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    REPX   {paddw    x, m5}, m0, m1, m2, m3
+    mova     [r6+strideq*0], m0
+    mova     [r6+strideq*1], m1
+    lea                  r6, [r6+strideq*2]
+    mova     [r6+strideq*0], m2
+    mova     [r6+strideq*1], m3
+    lea                  r6, [r6+strideq*2]
+    sub                 t0d, 4*(1+ARCH_X86_64)
+    jg .w8_loop
+    add                  wq, 8
+    jl .w8_loop0
+    RET
+
+%if ARCH_X86_64
+DECLARE_REG_TMP 10
+%else
+DECLARE_REG_TMP 3
+%endif
+
+cglobal ipred_smooth_16bpc, 3, 7, 8, dst, stride, tl, w, h, \
+                                     h_weights, v_weights, top
+    LEA          h_weightsq, smooth_weights_2d_16bpc
+    mov                  wd, wm
+    mov                  hd, hm
+    movd                 m7, [tlq+wq*2] ; right
+    lea          v_weightsq, [h_weightsq+hq*8]
+    neg                  hq
+    movd                 m6, [tlq+hq*2] ; bottom
+    pshuflw              m7, m7, q0000
+    pshuflw              m6, m6, q0000
+    cmp                  wd, 4
+    jne .w8
+    movq                 m4, [tlq+2]    ; top
+    mova                 m5, [h_weightsq+4*4]
+    punpcklwd            m4, m6         ; top, bottom
+    pxor                 m6, m6
+.w4_loop:
+    movq                 m1, [v_weightsq+hq*4]
+    sub                 tlq, 4
+    movd                 m3, [tlq]      ; left
+    pshufd               m0, m1, q0000
+    pshufd               m1, m1, q1111
+    pmaddwd              m0, m4
+    punpcklwd            m3, m7         ; left, right
+    pmaddwd              m1, m4
+    pshufd               m2, m3, q1111
+    pshufd               m3, m3, q0000
+    pmaddwd              m2, m5
+    pmaddwd              m3, m5
+    paddd                m0, m2
+    paddd                m1, m3
+    psrld                m0, 8
+    psrld                m1, 8
+    packssdw             m0, m1
+    pavgw                m0, m6
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    add                  hq, 2
+    jl .w4_loop
+    RET
+.w8:
+%if ARCH_X86_32
+    lea          h_weightsq, [h_weightsq+wq*4]
+    mov                  t0, tlq
+    mov                 r1m, tlq
+    mov                 r2m, hq
+    %define              m8  [h_weightsq+16*0]
+    %define              m9  [h_weightsq+16*1]
+%else
+%if WIN64
+    movaps              r4m, m8
+    movaps              r6m, m9
+    PUSH                 r7
+    PUSH                 r8
+%endif
+    PUSH                 r9
+    PUSH                r10
+    %assign       regs_used  11
+    lea          h_weightsq, [h_weightsq+wq*8]
+    lea                topq, [tlq+wq*2]
+    neg                  wq
+    mov                  r8, tlq
+    mov                  r9, hq
+%endif
+    punpcklqdq           m6, m6
+.w8_loop0:
+%if ARCH_X86_32
+    movu                 m5, [t0+2]
+    add                  t0, 16
+    mov                 r0m, t0
+%else
+    movu                 m5, [topq+wq*2+2]
+    mova                 m8, [h_weightsq+wq*4+16*0]
+    mova                 m9, [h_weightsq+wq*4+16*1]
+%endif
+    mov                  t0, dstq
+    add                dstq, 16
+    punpcklwd            m4, m5, m6
+    punpckhwd            m5, m6
+.w8_loop:
+    movd                 m1, [v_weightsq+hq*4]
+    sub                 tlq, 2
+    movd                 m3, [tlq]      ; left
+    pshufd               m1, m1, q0000
+    pmaddwd              m0, m4, m1
+    pshuflw              m3, m3, q0000
+    pmaddwd              m1, m5
+    punpcklwd            m3, m7         ; left, right
+    pmaddwd              m2, m8, m3
+    pmaddwd              m3, m9
+    paddd                m0, m2
+    paddd                m1, m3
+    psrld                m0, 8
+    psrld                m1, 8
+    packssdw             m0, m1
+    pxor                 m1, m1
+    pavgw                m0, m1
+    mova               [t0], m0
+    add                  t0, strideq
+    inc                  hq
+    jl .w8_loop
+%if ARCH_X86_32
+    mov                  t0, r0m
+    mov                 tlq, r1m
+    add          h_weightsq, 16*2
+    mov                  hq, r2m
+    sub            dword wm, 8
+    jg .w8_loop0
+%else
+    mov                 tlq, r8
+    mov                  hq, r9
+    add                  wq, 8
+    jl .w8_loop0
+%endif
+%if WIN64
+    movaps               m8, r4m
+    movaps               m9, r6m
+%endif
+    RET
+
+%if ARCH_X86_64
+cglobal ipred_z1_16bpc, 3, 8, 8, 16*18, dst, stride, tl, w, h, angle, dx
+    %define            base  r7-$$
+    %define          bdmaxm  r8m
+    lea                  r7, [$$]
+%else
+cglobal ipred_z1_16bpc, 3, 7, 8, -16*18, dst, stride, tl, w, h, angle, dx
+    %define            base  r1-$$
+    %define        stridemp  [rsp+4*0]
+    %define          bdmaxm  [rsp+4*1]
+    mov                  r3, r8m
+    mov            stridemp, r1
+    mov              bdmaxm, r3
+    LEA                  r1, $$
+%endif
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    movifnidn            hd, hm
+    add                 tlq, 2
+    movsxd               wq, [base+ipred_z1_16bpc_ssse3_table+wq*4]
+    mov                 dxd, angled
+    movddup              m0, [base+pw_256]
+    and                 dxd, 0x7e
+    movddup              m7, [base+pw_62]
+    add              angled, 165 ; ~90
+    lea                  wq, [base+wq+ipred_z1_16bpc_ssse3_table]
+    movzx               dxd, word [base+dr_intra_derivative+dxq]
+    xor              angled, 0x4ff ; d = 90 - angle
+    jmp                  wq
+.w4:
+    lea                 r3d, [angleq+88]
+    test                r3d, 0x480
+    jnz .w4_no_upsample ; !enable_intra_edge_filter || angle >= 40
+    sar                 r3d, 9
+    add                 r3d, hd
+    cmp                 r3d, 8
+    jg .w4_no_upsample ; h > 8 || (w == h && is_sm)
+    movd                 m3, [tlq+14]
+    movu                 m2, [tlq+ 0]  ; 1 2 3 4 5 6 7 8
+    movd                 m1, bdmaxm
+    pshufb               m3, m0
+    palignr              m4, m3, m2, 4 ; 3 4 5 6 7 8 8 8
+    paddw                m4, [tlq- 2]  ; 0 1 2 3 4 5 6 7
+    add                 dxd, dxd
+    mova           [rsp+32], m3
+    palignr              m3, m2, 2     ; 2 3 4 5 6 7 8 8
+    pshufb               m1, m0
+    paddw                m3, m2        ; -1 * a + 9 * b + 9 * c + -1 * d
+    psubw                m5, m3, m4    ; = (b + c - a - d + (b + c) << 3 + 8) >> 4
+    movd                 m4, dxd
+    psraw                m5, 3         ; = ((b + c - a - d) >> 3 + b + c + 1) >> 1
+    paddw                m3, m5
+    pxor                 m5, m5
+    pmaxsw               m3, m5
+    mov                 r3d, dxd
+    pavgw                m3, m5
+    pshufb               m4, m0
+    pminsw               m3, m1
+    punpcklwd            m1, m2, m3
+    punpckhwd            m2, m3
+    mova                 m3, [base+z_upsample]
+    movifnidn       strideq, stridemp
+    mova           [rsp+ 0], m1
+    paddw                m5, m4, m4
+    mova           [rsp+16], m2
+    punpcklqdq           m4, m5 ; xpos0 xpos1
+.w4_upsample_loop:
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6 ; base0
+    movu                 m1, [rsp+r3*2]
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6 ; base1
+    movu                 m2, [rsp+r2*2]
+    pshufb               m1, m3
+    pshufb               m2, m3
+    punpcklqdq           m0, m1, m2
+    punpckhqdq           m1, m2
+    pand                 m2, m7, m4 ; frac
+    psllw                m2, 9      ; (a * (64 - frac) + b * frac + 32) >> 6
+    psubw                m1, m0     ; = a + (((b - a) * frac + 32) >> 6)
+    pmulhrsw             m1, m2     ; = a + (((b - a) * (frac << 9) + 16384) >> 15)
+    paddw                m4, m5     ; xpos += dx
+    paddw                m0, m1
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w4_upsample_loop
+    RET
+.w4_no_upsample:
+    mov                 r3d, 7     ; max_base
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w4_main
+    lea                 r3d, [hq+3]
+    movd                 m1, r3d
+    movd                 m3, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m2, m2
+    pshufb               m1, m2
+    pshufb               m3, m2
+    pcmpeqb              m1, [base+z_filt_wh4]
+    pand                 m1, m3
+    pcmpgtb              m1, [base+z_filt_t_w48+angleq*8]
+    pmovmskb            r5d, m1
+    mov                 r3d, 7
+    test                r5d, r5d
+    jz .w4_main ; filter_strength == 0
+    pshuflw              m1, [tlq-2], q0000
+    movu                 m2, [tlq+16*0]
+    imul                r5d, 0x55555555
+    movd                 m3, [tlq+r3*2]
+    shr                 r5d, 30 ; filter_strength
+    movd           [rsp+12], m1
+    pshuflw              m3, m3, q0000
+    mova         [rsp+16*1], m2
+    lea                 r2d, [r3+2]
+    movq      [rsp+r3*2+18], m3
+    cmp                  hd, 8
+    cmovae              r3d, r2d
+    lea                 tlq, [rsp+16*1]
+    call .filter_edge
+.w4_main:
+    lea                 tlq, [tlq+r3*2]
+    movd                 m4, dxd
+    movddup              m1, [base+z_base_inc] ; base_inc << 6
+    movd                 m6, [tlq] ; top[max_base_x]
+    shl                 r3d, 6
+    movd                 m3, r3d
+    pshufb               m4, m0
+    mov                 r5d, dxd ; xpos
+    pshufb               m6, m0
+    sub                  r5, r3
+    pshufb               m3, m0
+    paddw                m5, m4, m4
+    psubw                m3, m1 ; max_base_x
+    punpcklqdq           m4, m5 ; xpos0 xpos1
+    movifnidn       strideq, stridemp
+.w4_loop:
+    lea                  r3, [r5+dxq]
+    sar                  r5, 6      ; base0
+    movq                 m0, [tlq+r5*2+0]
+    movq                 m1, [tlq+r5*2+2]
+    lea                  r5, [r3+dxq]
+    sar                  r3, 6      ; base1
+    movhps               m0, [tlq+r3*2+0]
+    movhps               m1, [tlq+r3*2+2]
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    pcmpgtw              m2, m3, m4 ; xpos < max_base_x
+    paddw                m4, m5     ; xpos += dx
+    paddw                m0, m1
+    pand                 m0, m2
+    pandn                m2, m6
+    por                  m0, m2
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    sub                  hd, 2
+    jz .w4_end
+    lea                dstq, [dstq+strideq*2]
+    test                r5d, r5d
+    jl .w4_loop
+.w4_end_loop:
+    movq   [dstq+strideq*0], m6
+    movq   [dstq+strideq*1], m6
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w4_end_loop
+.w4_end:
+    RET
+.w8:
+    lea                 r3d, [angleq+88]
+    and                 r3d, ~0x7f
+    or                  r3d, hd
+    cmp                 r3d, 8
+    ja .w8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || h > 8
+    movu                 m1, [tlq+ 0]  ; 1 2 3 4 5 6 7 8
+    movu                 m5, [tlq+ 2]  ; 2 3 4 5 6 7 8 9
+    movu                 m3, [tlq+ 4]  ; 3 4 5 6 7 8 9 a
+    paddw                m5, m1
+    paddw                m3, [tlq- 2]  ; 0 1 2 3 4 5 6 7
+    psubw                m2, m5, m3
+    movu                 m6, [tlq+18]  ; a b c d e f g _
+    psraw                m2, 3
+    movu                 m3, [tlq+20]  ; b c d e f g _ _
+    paddw                m5, m2
+    movu                 m2, [tlq+16]  ; 9 a b c d e f g
+    paddw                m6, m2
+    add                 dxd, dxd
+    cmp                  hd, 4
+    jne .w8_upsample_h8 ; awkward single-pixel edge case
+    pshuflw              m3, m3, q1110 ; b c c _ _ _ _ _
+.w8_upsample_h8:
+    paddw                m3, [tlq+14]  ; 8 9 a b c d e f
+    psubw                m4, m6, m3
+    movd                 m3, bdmaxm
+    psraw                m4, 3
+    mov                 r3d, dxd
+    paddw                m6, m4
+    pxor                 m4, m4
+    pmaxsw               m5, m4
+    pmaxsw               m6, m4
+    pshufb               m3, m0
+    pavgw                m5, m4
+    pavgw                m6, m4
+    movd                 m4, dxd
+    pminsw               m5, m3
+    pminsw               m6, m3
+    mova                 m3, [base+z_upsample]
+    pshufb               m4, m0
+    movifnidn       strideq, stridemp
+    punpcklwd            m0, m1, m5
+    mova           [rsp+ 0], m0
+    punpckhwd            m1, m5
+    mova           [rsp+16], m1
+    punpcklwd            m0, m2, m6
+    mova           [rsp+32], m0
+    punpckhwd            m2, m6
+    mova           [rsp+48], m2
+    mova                 m5, m4
+.w8_upsample_loop:
+    mov                 r2d, r3d
+    shr                 r2d, 6
+    movu                 m1, [rsp+r2*2+ 0]
+    movu                 m2, [rsp+r2*2+16]
+    add                 r3d, dxd
+    pshufb               m1, m3
+    pshufb               m2, m3
+    punpcklqdq           m0, m1, m2
+    punpckhqdq           m1, m2
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m4, m5
+    paddw                m0, m1
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w8_upsample_loop
+    RET
+.w8_no_upsample:
+    lea                 r3d, [hq+7]
+    movd                 m1, r3d
+    and                 r3d, 7
+    or                  r3d, 8 ; imin(h+7, 15)
+    test             angled, 0x400
+    jnz .w8_main
+    movd                 m3, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m2, m2
+    pshufb               m1, m2
+    pshufb               m3, m2
+    movu                 m2, [base+z_filt_wh8]
+    psrldq               m4, [base+z_filt_t_w48+angleq*8], 4
+    pcmpeqb              m2, m1
+    pand                 m2, m3
+    pcmpgtb              m2, m4
+    pmovmskb            r5d, m2
+    test                r5d, r5d
+    jz .w8_main ; filter_strength == 0
+    pshuflw              m1, [tlq-2], q0000
+    movu                 m2, [tlq+16*0]
+    imul                r5d, 0x55555555
+    movu                 m3, [tlq+16*1]
+    movd                 m4, [tlq+r3*2]
+    shr                 r5d, 30 ; filter_strength
+    movd           [rsp+12], m1
+    mova         [rsp+16*1], m2
+    pshuflw              m4, m4, q0000
+    mova         [rsp+16*2], m3
+    lea                 r2d, [r3+2]
+    movq      [rsp+r3*2+18], m4
+    cmp                  hd, 16
+    cmovae              r3d, r2d
+    lea                 tlq, [rsp+16*1]
+    call .filter_edge
+.w8_main:
+    lea                 tlq, [tlq+r3*2]
+    movd                 m5, dxd
+    mova                 m4, [base+z_base_inc]
+    shl                 r3d, 6
+    movd                 m6, [tlq] ; top[max_base_x]
+    movd                 m1, r3d
+    pshufb               m5, m0
+    mov                 r5d, dxd ; xpos
+    pshufb               m1, m0
+    sub                  r5, r3
+    psubw                m4, m1 ; max_base_x
+    pshufb               m6, m0
+    paddw                m4, m5
+    movifnidn       strideq, stridemp
+.w8_loop:
+    mov                  r3, r5
+    sar                  r3, 6
+    movu                 m0, [tlq+r3*2+0]
+    movu                 m1, [tlq+r3*2+2]
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    psraw                m2, m4, 15 ; xpos < max_base_x
+    paddw                m4, m5     ; xpos += dx
+    paddw                m0, m1
+    pand                 m0, m2
+    pandn                m2, m6
+    por                  m0, m2
+    mova             [dstq], m0
+    dec                  hd
+    jz .w8_end
+    add                dstq, strideq
+    add                  r5, dxq
+    jl .w8_loop
+.w8_end_loop:
+    mova             [dstq], m6
+    add                dstq, strideq
+    dec                  hd
+    jg .w8_end_loop
+.w8_end:
+    RET
+.w16:
+%if ARCH_X86_32
+    %define         strideq  r3
+%endif
+    lea                 r3d, [hq+15]
+    movd                 m1, r3d
+    and                 r3d, 15
+    or                  r3d, 16 ; imin(h+15, 31)
+    test             angled, 0x400
+    jnz .w16_main
+    movd                 m3, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m2, m2
+    pshufb               m1, m2
+    pshufb               m3, m2
+    movq                 m4, [base+z_filt_t_w16+angleq*4]
+    pcmpeqb              m1, [base+z_filt_wh16]
+    pand                 m1, m3
+    pcmpgtb              m1, m4
+    pmovmskb            r5d, m1
+    test                r5d, r5d
+    jz .w16_main ; filter_strength == 0
+    pshuflw              m1, [tlq-2], q0000
+    movu                 m2, [tlq+16*0]
+    imul                r5d, 0x24924924
+    movu                 m3, [tlq+16*1]
+    movu                 m4, [tlq+16*2]
+    shr                 r5d, 30
+    movu                 m5, [tlq+16*3]
+    movd                 m6, [tlq+r3*2]
+    adc                 r5d, -1 ; filter_strength
+    movd           [rsp+12], m1
+    mova         [rsp+16*1], m2
+    mova         [rsp+16*2], m3
+    pshuflw              m6, m6, q0000
+    mova         [rsp+16*3], m4
+    mova         [rsp+16*4], m5
+    lea                 r2d, [r3+2]
+    movq      [rsp+r3*2+18], m6
+    cmp                  hd, 32
+    cmovae              r3d, r2d
+    lea                 tlq, [rsp+16*1]
+    call .filter_edge
+.w16_main:
+    lea                 tlq, [tlq+r3*2]
+    movd                 m5, dxd
+    mova                 m4, [base+z_base_inc]
+    shl                 r3d, 6
+    movd                 m6, [tlq] ; top[max_base_x]
+    movd                 m1, r3d
+    pshufb               m5, m0
+    mov                 r5d, dxd ; xpos
+    pshufb               m1, m0
+    sub                  r5, r3
+    psubw                m4, m1 ; max_base_x
+    pshufb               m6, m0
+    paddw                m4, m5
+.w16_loop:
+    mov                  r3, r5
+    sar                  r3, 6
+    movu                 m0, [tlq+r3*2+ 0]
+    movu                 m2, [tlq+r3*2+ 2]
+    pand                 m3, m7, m4
+    psllw                m3, 9
+    psubw                m2, m0
+    pmulhrsw             m2, m3
+    movu                 m1, [tlq+r3*2+16]
+    paddw                m0, m2
+    movu                 m2, [tlq+r3*2+18]
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    movddup              m3, [base+pw_m512]
+    paddw                m1, m2
+    psraw                m2, m4, 15
+    pcmpgtw              m3, m4
+    paddw                m4, m5
+    pand                 m0, m2
+    pandn                m2, m6
+    pand                 m1, m3
+    pandn                m3, m6
+    por                  m0, m2
+    mova        [dstq+16*0], m0
+    por                  m1, m3
+    mova        [dstq+16*1], m1
+    dec                  hd
+    jz .w16_end
+    movifnidn       strideq, stridemp
+    add                dstq, strideq
+    add                  r5, dxq
+    jl .w16_loop
+.w16_end_loop:
+    mova        [dstq+16*0], m6
+    mova        [dstq+16*1], m6
+    add                dstq, strideq
+    dec                  hd
+    jg .w16_end_loop
+.w16_end:
+    RET
+.w32:
+    lea                 r3d, [hq+31]
+    and                 r3d, 31
+    or                  r3d, 32    ; imin(h+31, 63)
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w32_main
+    call .filter_copy
+    lea                 r5d, [r3+2]
+    cmp                  hd, 64
+    cmove               r3d, r5d
+    call .filter_edge_s3
+.w32_main:
+    lea                 tlq, [tlq+r3*2]
+    movd                 m5, dxd
+    mova                 m4, [base+z_base_inc]
+    shl                 r3d, 6
+    movd                 m6, [tlq] ; top[max_base_x]
+    movd                 m1, r3d
+    pshufb               m5, m0
+    mov                 r5d, dxd ; xpos
+    pshufb               m1, m0
+    sub                  r5, r3
+    psubw                m4, m1 ; max_base_x
+    pshufb               m6, m0
+    paddw                m4, m5
+.w32_loop:
+    mov                  r3, r5
+    sar                  r3, 6
+    movu                 m0, [tlq+r3*2+ 0]
+    movu                 m2, [tlq+r3*2+ 2]
+    pand                 m3, m7, m4
+    psllw                m3, 9
+    psubw                m2, m0
+    pmulhrsw             m2, m3
+    movu                 m1, [tlq+r3*2+16]
+    paddw                m0, m2
+    movu                 m2, [tlq+r3*2+18]
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    paddw                m1, m2
+    psraw                m2, m4, 15
+    pand                 m0, m2
+    pandn                m2, m6
+    por                  m0, m2
+    movddup              m2, [base+pw_m512]
+    pcmpgtw              m2, m4
+    pand                 m1, m2
+    pandn                m2, m6
+    mova        [dstq+16*0], m0
+    por                  m1, m2
+    mova        [dstq+16*1], m1
+    movu                 m0, [tlq+r3*2+32]
+    movu                 m2, [tlq+r3*2+34]
+    psubw                m2, m0
+    pmulhrsw             m2, m3
+    movu                 m1, [tlq+r3*2+48]
+    paddw                m0, m2
+    movu                 m2, [tlq+r3*2+50]
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    paddw                m1, m2
+    movddup              m2, [base+pw_m1024]
+    movddup              m3, [base+pw_m1536]
+    pcmpgtw              m2, m4
+    pcmpgtw              m3, m4
+    paddw                m4, m5
+    pand                 m0, m2
+    pandn                m2, m6
+    pand                 m1, m3
+    pandn                m3, m6
+    por                  m0, m2
+    mova        [dstq+16*2], m0
+    por                  m1, m3
+    mova        [dstq+16*3], m1
+    dec                  hd
+    jz .w32_end
+    movifnidn       strideq, stridemp
+    add                dstq, strideq
+    add                  r5, dxq
+    jl .w32_loop
+.w32_end_loop:
+    REPX {mova [dstq+16*x], m6}, 0, 1, 2, 3
+    add                dstq, strideq
+    dec                  hd
+    jg .w32_end_loop
+.w32_end:
+    RET
+.w64:
+    lea                 r3d, [hq+63]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w64_main
+    call .filter_copy
+    call .filter_edge_s3
+.w64_main:
+    lea                 tlq, [tlq+r3*2]
+    movd                 m5, dxd
+    mova                 m4, [base+z_base_inc]
+    shl                 r3d, 6
+    movd                 m6, [tlq] ; top[max_base_x]
+    movd                 m1, r3d
+    pshufb               m5, m0
+    mov                 r5d, dxd ; xpos
+    pshufb               m1, m0
+    sub                  r5, r3
+    psubw                m4, m1 ; max_base_x
+    pshufb               m6, m0
+    paddw                m4, m5
+.w64_loop:
+    mov                  r3, r5
+    sar                  r3, 6
+    movu                 m0, [tlq+r3*2+ 0]
+    movu                 m2, [tlq+r3*2+ 2]
+    pand                 m3, m7, m4
+    psllw                m3, 9
+    psubw                m2, m0
+    pmulhrsw             m2, m3
+    movu                 m1, [tlq+r3*2+16]
+    paddw                m0, m2
+    movu                 m2, [tlq+r3*2+18]
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    paddw                m1, m2
+    psraw                m2, m4, 15
+    pand                 m0, m2
+    pandn                m2, m6
+    por                  m0, m2
+    movddup              m2, [base+pw_m512]
+    pcmpgtw              m2, m4
+    pand                 m1, m2
+    pandn                m2, m6
+    mova        [dstq+16*0], m0
+    por                  m1, m2
+    mova        [dstq+16*1], m1
+    movu                 m0, [tlq+r3*2+32]
+    movu                 m2, [tlq+r3*2+34]
+    psubw                m2, m0
+    pmulhrsw             m2, m3
+    movu                 m1, [tlq+r3*2+48]
+    paddw                m0, m2
+    movu                 m2, [tlq+r3*2+50]
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    paddw                m1, m2
+    movddup              m2, [base+pw_m1024]
+    pcmpgtw              m2, m4
+    pand                 m0, m2
+    pandn                m2, m6
+    por                  m0, m2
+    movddup              m2, [base+pw_m1536]
+    pcmpgtw              m2, m4
+    pand                 m1, m2
+    pandn                m2, m6
+    mova        [dstq+16*2], m0
+    por                  m1, m2
+    mova        [dstq+16*3], m1
+    movu                 m0, [tlq+r3*2+64]
+    movu                 m2, [tlq+r3*2+66]
+    psubw                m2, m0
+    pmulhrsw             m2, m3
+    movu                 m1, [tlq+r3*2+80]
+    paddw                m0, m2
+    movu                 m2, [tlq+r3*2+82]
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    paddw                m1, m2
+    movddup              m2, [base+pw_m2048]
+    pcmpgtw              m2, m4
+    pand                 m0, m2
+    pandn                m2, m6
+    por                  m0, m2
+    movddup              m2, [base+pw_m2560]
+    pcmpgtw              m2, m4
+    pand                 m1, m2
+    pandn                m2, m6
+    mova        [dstq+16*4], m0
+    por                  m1, m2
+    mova        [dstq+16*5], m1
+    movu                 m0, [tlq+r3*2+96]
+    movu                 m2, [tlq+r3*2+98]
+    psubw                m2, m0
+    pmulhrsw             m2, m3
+    movu                 m1, [tlq+r3*2+112]
+    paddw                m0, m2
+    movu                 m2, [tlq+r3*2+114]
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    paddw                m1, m2
+    movddup              m2, [base+pw_m3072]
+    movddup              m3, [base+pw_m3584]
+    pcmpgtw              m2, m4
+    pcmpgtw              m3, m4
+    paddw                m4, m5
+    pand                 m0, m2
+    pandn                m2, m6
+    pand                 m1, m3
+    pandn                m3, m6
+    por                  m0, m2
+    mova        [dstq+16*6], m0
+    por                  m1, m3
+    mova        [dstq+16*7], m1
+    dec                  hd
+    jz .w64_end
+    movifnidn       strideq, stridemp
+    add                dstq, strideq
+    add                  r5, dxq
+    jl .w64_loop
+.w64_end_loop:
+    REPX {mova [dstq+16*x], m6}, 0, 1, 2, 3, 4, 5, 6, 7
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_end_loop
+.w64_end:
+    RET
+ALIGN function_align
+.filter_copy:
+    pshuflw              m2, [tlq-2], q0000
+    pshuflw              m3, [tlq+r3*2], q0000
+    xor                 r5d, r5d
+    movd   [rsp+gprsize+12], m2
+.filter_copy_loop:
+    movu                 m1, [tlq+r5*2+16*0]
+    movu                 m2, [tlq+r5*2+16*1]
+    add                 r5d, 16
+    mova [rsp+r5*2+gprsize-16*1], m1
+    mova [rsp+r5*2+gprsize-16*0], m2
+    cmp                 r5d, r3d
+    jle .filter_copy_loop
+    lea                 tlq, [rsp+gprsize+16*1]
+    movq       [tlq+r3*2+2], m3
+    ret
+.filter_edge:
+    cmp                 r5d, 3
+    je .filter_edge_s3
+    movddup              m4, [base+z_filt_k+r5*8-8]
+    movddup              m5, [base+z_filt_k+r5*8+8]
+    xor                 r5d, r5d
+    movddup              m6, [base+pw_8]
+    movu                 m2, [tlq-2]
+    jmp .filter_edge_start
+.filter_edge_loop:
+    movu                 m2, [tlq+r5*2-2]
+    mova      [tlq+r5*2-16], m1
+.filter_edge_start:
+    pmullw               m1, m4, [tlq+r5*2]
+    movu                 m3, [tlq+r5*2+2]
+    paddw                m2, m3
+    pmullw               m2, m5
+    add                 r5d, 8
+    paddw                m1, m6
+    paddw                m1, m2
+    psrlw                m1, 4
+    cmp                 r5d, r3d
+    jl .filter_edge_loop
+    mova      [tlq+r5*2-16], m1
+    ret
+.filter_edge_s3:
+    movddup              m5, [base+pw_3]
+    xor                 r5d, r5d
+    movu                 m2, [tlq-2]
+    movu                 m3, [tlq-4]
+    jmp .filter_edge_s3_start
+.filter_edge_s3_loop:
+    movu                 m2, [tlq+r5*2-2]
+    movu                 m3, [tlq+r5*2-4]
+    mova      [tlq+r5*2-16], m1
+.filter_edge_s3_start:
+    paddw                m2, [tlq+r5*2+0]
+    paddw                m3, m5
+    movu                 m1, [tlq+r5*2+2]
+    movu                 m4, [tlq+r5*2+4]
+    add                 r5d, 8
+    paddw                m1, m2
+    pavgw                m3, m4
+    paddw                m1, m3
+    psrlw                m1, 2
+    cmp                 r5d, r3d
+    jl .filter_edge_s3_loop
+    mova      [tlq+r5*2-16], m1
+    ret
+
+%if ARCH_X86_64
+cglobal ipred_z2_16bpc, 4, 12, 11, 16*24, dst, stride, tl, w, h, angle, dx, _, dy
+    %define            base  r7-$$
+    %define           maxwm  r6m
+    %define           maxhm  r7m
+    %define          bdmaxm  r8m
+    lea                  r7, [$$]
+    mov                  hd, hm
+    movddup              m8, [base+pw_62]
+    lea                 r9d, [wq-4]
+    shl                 r9d, 6
+    mova                 m9, [base+z2_top_shufA]
+    or                  r9d, hd
+    mova                m10, [base+z2_left_shufA]
+%else
+cglobal ipred_z2_16bpc, 4, 7, 8, -16*27, dst, _, tl, w, h, angle, dx
+    %define            base  r1-$$
+    %define             r9b  byte  [rsp+16*26+4*0]
+    %define             r9d  dword [rsp+16*26+4*0]
+    %define            r10d  dword [rsp+16*26+4*1]
+    %define            r11d  dword [rsp+16*26+4*2]
+    %define           maxwm  [rsp+16*2+4*0]
+    %define           maxhm  [rsp+16*2+4*1]
+    %define          bdmaxm  [rsp+16*2+4*2]
+    %define        stridemp  [rsp+16*26+4*3]
+    %define         strideq  r3
+    %define             dyd  r4
+    %define             dyq  r4
+    mov            stridemp, r1
+    mov                 r1d, r6m
+    mov                 r4d, r7m
+    mov                 r5d, r8m
+    mov               maxwm, r1d
+    mov               maxhm, r4d
+    mov              bdmaxm, r5d
+    LEA                  r1, $$
+    lea                  hd, [wq-4]
+    mova                 m0, [base+z2_top_shufA]
+    shl                  hd, 6
+    mova                 m1, [base+z2_left_shufA]
+    or                   hd, hm
+    mova        [rsp+16*24], m0
+    mov                 r9d, hd
+    mova        [rsp+16*25], m1
+%endif
+    tzcnt                wd, wd
+    movifnidn        angled, anglem
+    mova                 m0, [tlq-16*8]
+    mova                 m1, [tlq-16*7]
+    mova                 m2, [tlq-16*6]
+    mova                 m3, [tlq-16*5]
+    movsxd               wq, [base+ipred_z2_16bpc_ssse3_table+wq*4]
+%if ARCH_X86_64
+    movzx               dxd, angleb
+%else
+    movzx               dxd, byte anglem
+%endif
+    mova                 m4, [tlq-16*4]
+    mova                 m5, [tlq-16*3]
+    mova                 m6, [tlq-16*2]
+    mova                 m7, [tlq-16*1]
+    mova        [rsp+16* 5], m0
+    xor              angled, 0x400
+    mova        [rsp+16* 6], m1
+    mov                 dyd, dxd
+    mova        [rsp+16* 7], m2
+    neg                 dxq
+    mova        [rsp+16* 8], m3
+    and                 dyd, ~1
+    mova        [rsp+16* 9], m4
+    and                 dxq, ~1
+    mova        [rsp+16*10], m5
+    lea                  wq, [base+ipred_z2_16bpc_ssse3_table+wq]
+    mova        [rsp+16*11], m6
+    pxor                 m3, m3
+    mova        [rsp+16*12], m7
+    movzx               dyd, word [base+dr_intra_derivative+dyq-90]  ; angle - 90
+    movzx               dxd, word [base+dr_intra_derivative+dxq+180] ; 180 - angle
+    movddup              m0, [base+pw_256] ; 4<<6
+    movd                 m4, [tlq]
+    movu                 m5, [tlq+16*0+2]
+    movu                 m6, [tlq+16*1+2]
+    movsldup             m1, [base+z2_dy_offset]
+    pshufb               m4, m0
+    movq                 m7, [base+z_base_inc+2]
+    mov                r11d, (112-4)<<6
+    mova        [rsp+16*13], m4
+    neg                 dxd
+    mova        [rsp+16*14], m5
+    or                  dyd, 4<<16
+    mova        [rsp+16*15], m6
+%if ARCH_X86_64
+    lea                r10d, [dxq+(112<<6)] ; xpos
+%else
+    mov           [rsp+8*3], dyd
+    lea                 r4d, [dxq+(112<<6)]
+    mov                r10d, r4d
+    movzx                hd, r9b
+%endif
+    movq          [rsp+8*0], m1
+    movq          [rsp+8*1], m0
+    movq          [rsp+8*2], m7
+    jmp                  wq
+.w4:
+    test             angled, 0x400
+    jnz .w4_main
+    lea                 r3d, [hq+2]
+    add              angled, 1022
+    pshuflw              m1, m5, q3333
+    shl                 r3d, 6
+    movq      [rsp+16*14+8], m1
+    test                r3d, angled
+    jnz .w4_no_upsample_above ; angle >= 130 || h > 8 || (is_sm && h == 8)
+    call .upsample_above
+    sub              angled, 1075 ; angle - 53
+    lea                 r3d, [hq+3]
+    xor              angled, 0x7f ; 180 - angle
+    movd                 m2, r3d
+    movd                 m7, angled
+    shr              angled, 8 ; is_sm << 1
+    pshufb               m2, m3
+    pshufb               m7, m3
+    pcmpeqb              m2, [base+z_filt_wh4]
+    pand                 m7, m2
+    pcmpgtb              m7, [base+z_filt_t_w48+angleq*8]
+    jmp .w8_filter_left
+.upsample_above: ; w4/w8
+    paddw                m2, m5, [tlq]
+    movu                 m1, [rsp+gprsize+16*14+2]
+    movu                 m4, [rsp+gprsize+16*14-4]
+%if ARCH_X86_64
+    movd                 m6, r9m ; bdmax, offset due to call
+%else
+    movd                 m6, [rsp+gprsize+16*2+4*2]
+%endif
+    paddw                m4, m1
+    psubw                m1, m2, m4
+    pshufb               m6, m0
+    psraw                m1, 3
+    paddw                m2, m1
+    add                 dxd, dxd
+    pmaxsw               m2, m3
+    paddw                m7, m7
+    pavgw                m2, m3
+    pminsw               m2, m6
+%if ARCH_X86_64
+    mova                 m9, [base+z2_top_shufB]
+    lea                r10d, [dxq+(113<<6)]
+    mov                r11d, (112-7)<<6
+%else
+    mova                 m1, [base+z2_top_shufB]
+    lea                 r3d, [dxq+(113<<6)]
+    mov dword [rsp+gprsize+16*26+4*2], (112-7)<<6
+    mov [rsp+gprsize+16*26+4*1], r3d
+    mova [rsp+gprsize+16*24], m1
+%endif
+    punpcklwd            m1, m2, m5
+    punpckhwd            m2, m5
+    movq  [rsp+gprsize+8*2], m7
+    mova [rsp+gprsize+16*14], m1
+    mova [rsp+gprsize+16*15], m2
+    ret
+.w4_no_upsample_above:
+    lea                 r3d, [hq+3]
+    mov          [rsp+16*4], angled
+    sub              angled, 1112 ; angle - 90
+    movd                 m2, r3d
+    mov                 r3d, 90
+    movd                 m1, angled
+    sub                 r3d, angled ; 180 - angle
+    shr              angled, 8 ; is_sm << 1
+    mova                 m4, [base+z_filt_wh4]
+    movd                 m7, r3d
+    mova                 m5, [base+z_filt_t_w48+angleq*8]
+    mov                 r3d, 4
+    call .w8_filter_top
+    mov              angled, [rsp+16*4]
+    lea                 r3d, [hq+2]
+    sub              angled, 139
+    shl                 r3d, 6
+    test                r3d, angled
+    jnz .w8_filter_left ; angle <= 140 || h > 8 || (is_sm && h == 8)
+.upsample_left: ; w4/w8
+    mova                 m2, [tlq-16]
+    lea                 r3d, [hq-4]
+    movu                 m3, [tlq-14]
+    movu                 m4, [rsp+16*12+4]
+    pshufb               m1, m2, [base+z2_upsample_l+r3*4]
+    movd                 m6, bdmaxm
+    pxor                 m5, m5
+    paddw                m3, m2
+    paddw                m4, m1
+    psubw                m1, m3, m4
+    movshdup             m4, [base+z2_dy_offset]
+    psraw                m1, 3
+    pshufb               m6, m0
+    paddw                m3, m1
+    pmaxsw               m3, m5
+    pavgw                m3, m5
+    pminsw               m3, m6
+%if ARCH_X86_64
+    mova                m10, [base+z2_left_shufB]
+    add                 dyd, dyd
+%else
+    mova                 m1, [base+z2_left_shufB]
+    shl     dword [rsp+8*3], 1
+    mova        [rsp+16*25], m1
+%endif
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    movq          [rsp+8*0], m4
+    mova        [rsp+16*12], m1
+    mova        [rsp+16*11], m2
+.w4_main:
+    movd                 m6, dxd
+%if ARCH_X86_64
+    movd                 m3, dyd
+%else
+    movd                 m3, [rsp+8*3]
+%endif
+    pshufb               m6, m0
+    movddup              m0, [rsp+8*2]
+    paddw                m7, m6, m6
+    movq                 m5, [base+pw_m1to4]
+    pshuflw              m4, m3, q0000
+    punpcklqdq           m6, m7
+    pmullw               m4, m5
+    pshuflw              m3, m3, q1111
+    paddw                m6, m0
+    mov                 r2d, r10d
+    pshuflw              m0, m4, q3333
+    psubw                m4, [rsp+8*0]
+    movq          [rsp+8*3], m3
+    movq          [rsp+8*5], m0 ; dy*4
+    mov                  r5, dstq
+.w4_loop0:
+    mova         [rsp+16*4], m6
+    movq          [rsp+8*4], m4
+%if ARCH_X86_64
+    pand                 m0, m8, m4
+%else
+    movq                 m0, [base+pw_62]
+    pand                 m0, m4
+%endif
+    psraw                m4, 6
+    psllw                m0, 9 ; frac_y << 9
+    movq          [rsp+8*7], m0
+    pabsw                m4, m4
+    movq          [rsp+8*6], m4
+    movzx                hd, r9b
+.w4_loop:
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6        ; base_x0
+    movu                 m2, [rsp+r2*2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6        ; base_x1
+    movu                 m1, [rsp+r3*2]
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6        ; base_x2
+    movu                 m3, [rsp+r2*2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6        ; base_x3
+    movu                 m4, [rsp+r3*2]
+%if ARCH_X86_64
+    REPX     {pshufb x, m9}, m2, m1, m3, m4
+%else
+    mova                 m0, [rsp+16*24]
+    REPX     {pshufb x, m0}, m2, m1, m3, m4
+%endif
+    punpcklqdq           m0, m2, m1
+    punpckhqdq           m2, m1
+    punpcklqdq           m1, m3, m4
+    punpckhqdq           m3, m4
+%if ARCH_X86_64
+    pand                 m5, m8, m6
+%else
+    movddup              m5, [base+pw_62]
+    pand                 m5, m6
+%endif
+    psllw                m5, 9
+    psubw                m2, m0
+    pmulhrsw             m2, m5
+    paddw                m5, m6, m7
+    psubw                m3, m1
+    paddw                m0, m2
+%if ARCH_X86_64
+    pand                 m2, m8, m5
+%else
+    movddup              m2, [base+pw_62]
+    pand                 m2, m5
+%endif
+    psllw                m2, 9
+    pmulhrsw             m3, m2
+    paddw                m1, m3
+    cmp                 r3d, 111 ; topleft
+    jge .w4_toponly
+    mova        [rsp+16*22], m0
+    mova        [rsp+16*23], m1
+    movzx               r3d, byte [rsp+8*6+0] ; base_y0
+    movu                 m3, [rsp+r3*2]
+    movzx               r3d, byte [rsp+8*6+2] ; base_y1
+    movu                 m2, [rsp+r3*2]
+    movzx               r3d, byte [rsp+8*6+4] ; base_y2
+    movu                 m4, [rsp+r3*2]
+    movzx               r3d, byte [rsp+8*6+6] ; base_y3
+    movu                 m0, [rsp+r3*2]
+%if ARCH_X86_64
+    REPX    {pshufb x, m10}, m3, m2, m4, m0
+%else
+    mova                 m1, [rsp+16*25]
+    REPX     {pshufb x, m1}, m3, m2, m4, m0
+%endif
+    punpcklwd            m1, m3, m2
+    punpckhwd            m3, m2     ; 01
+    punpcklwd            m2, m4, m0
+    punpckhwd            m4, m0     ; 23
+    punpckldq            m0, m1, m2 ; y0 d1
+    punpckhdq            m1, m2     ; y2 y3
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    movddup              m4, [rsp+8*7]
+    psubw                m2, m0
+    psubw                m3, m1
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    psraw                m6, 15       ; base_x < topleft
+    psraw                m4, m5, 15
+    paddw                m0, m2
+    paddw                m1, m3
+    pand                 m0, m6
+    pandn                m6, [rsp+16*22]
+    pand                 m1, m4
+    pandn                m4, [rsp+16*23]
+    por                  m0, m6
+    por                  m1, m4
+.w4_toponly:
+    movifnidn       strideq, stridemp
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    movq   [dstq+strideq*0], m1
+    movhps [dstq+strideq*1], m1
+    sub                  hd, 4
+    jz .w4_end
+    movq                 m4, [rsp+8*6]
+    paddsw               m6, m5, m7   ; xpos += dx
+    movq                 m5, [rsp+8*3]
+    psubw                m4, m5
+    lea                dstq, [dstq+strideq*2]
+    movq          [rsp+8*6], m4
+    cmp                 r2d, r11d
+    jge .w4_loop
+.w4_leftonly_loop:
+    movzx               r2d, byte [rsp+8*6+0] ; base_y0
+    movu                 m3, [rsp+r2*2]
+    movzx               r2d, byte [rsp+8*6+2] ; base_y1
+    movu                 m2, [rsp+r2*2]
+    movzx               r2d, byte [rsp+8*6+4] ; base_y2
+    movu                 m6, [rsp+r2*2]
+    movzx               r2d, byte [rsp+8*6+6] ; base_y3
+    movu                 m0, [rsp+r2*2]
+    psubw                m4, m5
+%if ARCH_X86_64
+    REPX    {pshufb x, m10}, m3, m2, m6, m0
+%else
+    mova                 m1, [rsp+16*25]
+    REPX     {pshufb x, m1}, m3, m2, m6, m0
+%endif
+    movq          [rsp+8*6], m4
+    punpcklwd            m1, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m6, m0
+    punpckhwd            m6, m0
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    punpckldq            m2, m3, m6
+    punpckhdq            m3, m6
+    movddup              m6, [rsp+8*7]
+    psubw                m2, m0
+    psubw                m3, m1
+    pmulhrsw             m2, m6
+    pmulhrsw             m3, m6
+    paddw                m0, m2
+    paddw                m1, m3
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    movq   [dstq+strideq*0], m1
+    movhps [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 4
+    jg .w4_leftonly_loop
+.w4_end:
+    sub                 r9d, 1<<8
+    jl .w4_ret
+    movq                 m4, [rsp+8*5]
+    add                  r5, 8
+    mov                dstq, r5
+    paddw                m4, [rsp+8*4] ; base_y += 4*dy
+    movzx               r2d, word [rsp+8*1]
+    movddup              m6, [rsp+8*1]
+    paddw                m6, [rsp+16*4] ; base_x += (4 << upsample_above)
+    add                 r2d, r10d
+    mov                r10d, r2d
+    jmp .w4_loop0
+.w4_ret:
+    RET
+.w8:
+    test             angled, 0x400
+    jnz .w4_main
+    lea                 r3d, [angleq+126]
+    pshufhw              m1, m5, q3333
+%if ARCH_X86_64
+    mov                 r3b, hb
+%else
+    xor                 r3b, r3b
+    or                  r3d, hd
+%endif
+    movhps      [rsp+16*15], m1
+    cmp                 r3d, 8
+    ja .w8_no_upsample_above ; angle >= 130 || h > 8 || is_sm
+    call .upsample_above
+    sub              angled, 53
+    lea                 r3d, [hq+7]
+    xor              angled, 0x7f ; 180 - angle
+    movu                 m1, [base+z_filt_wh8]
+    movd                 m2, r3d
+    movd                 m7, angled
+    shr              angled, 8 ; is_sm << 1
+    psrldq               m4, [base+z_filt_t_w48+angleq*8], 4
+    pshufb               m2, m3
+    pshufb               m7, m3
+    pcmpeqb              m2, m1
+    movq                 m1, [base+pw_512]
+    pand                 m7, m2
+    pcmpgtb              m7, m4
+    movq          [rsp+8*1], m1 ; 8<<6
+    jmp .w8_filter_left
+.w8_no_upsample_above:
+    lea                 r3d, [hq+7]
+    mov          [rsp+16*4], angled
+    sub              angled, 90
+    movd                 m2, r3d
+    mov                 r3d, 90
+    movd                 m1, angled
+    sub                 r3d, angled ; 180 - angle
+    shr              angled, 8 ; is_sm << 1
+    movu                 m4, [base+z_filt_wh8]
+    movd                 m7, r3d
+    psrldq               m5, [base+z_filt_t_w48+angleq*8], 4
+    mov                 r3d, 8
+    call .w8_filter_top
+    mov                 r3d, [rsp+16*4]
+    sub                 r3d, 141
+%if ARCH_X86_64
+    mov                 r3b, hb
+%else
+    xor                 r3b, r3b
+    or                  r3d, hd
+%endif
+    cmp                 r3d, 8
+    jbe .upsample_left ; angle > 140 && h <= 8 && !is_sm
+.w8_filter_left:
+    pmovmskb            r5d, m7
+    test                r5d, r5d
+    jz .w4_main
+    imul                r5d, 0x55555555
+    neg                  hq
+    mov                  r3, tlq
+    movd                 m1, [tlq+hq*2]
+    shr                 r5d, 30 ; filter_strength
+    lea                 tlq, [rsp+16*13-2]
+    pshuflw              m1, m1, q0000
+    movq       [tlq+hq*2-6], m1
+    call mangle(private_prefix %+ _ipred_z3_16bpc_ssse3).filter_edge
+    jmp .filter_left_end
+.w8_filter_top:
+    REPX     {pshufb x, m3}, m2, m1, m7
+    pcmpeqb              m2, m4
+    pand                 m1, m2
+    pand                 m7, m2
+    pcmpgtb              m1, m5
+    pcmpgtb              m7, m5
+    pmovmskb            r5d, m1
+    test                r5d, r5d
+    jz .w8_filter_top_end ; filter_strength == 0
+    imul                r5d, 0x55555555
+    mov              [dstq], tlq
+    lea                 tlq, [rsp+16*14+gprsize]
+    shr                 r5d, 30 ; filter_strength
+    call mangle(private_prefix %+ _ipred_z1_16bpc_ssse3).filter_edge
+%if ARCH_X86_64
+    mov                 r3d, r7m ; maxw, offset due to call
+%else
+    mov                 r3d, [rsp+16*2+4*1]
+%endif
+    mov                 tlq, [dstq]
+    cmp                 r3d, 8
+    jge .w8_filter_top_end
+    movu                 m1, [tlq+r3*2+16*0+2]
+    movu                 m2, [tlq+r3*2+16*1+2]
+    movu [rsp+r3*2+16*14+gprsize], m1
+    movu [rsp+r3*2+16*15+gprsize], m2
+.w8_filter_top_end:
+    ret
+.w16:
+    test             angled, 0x400
+    jnz .w4_main
+    lea                 r3d, [hq+15]
+    sub              angled, 90
+    movd                 m2, r3d
+    mov                 r3d, 90
+    movd                 m1, angled
+    sub                 r3d, angled ; 180 - angle
+    shr              angled, 8 ; is_sm << 1
+    movd                 m7, r3d
+    REPX     {pshufb x, m3}, m2, m1, m7
+    movq                 m4, [base+z_filt_t_w16+angleq*4]
+    pcmpeqb              m2, [base+z_filt_wh16]
+    pand                 m1, m2
+    pand                 m7, m2
+    pcmpgtb              m1, m4
+    pcmpgtb              m7, m4
+    pmovmskb            r5d, m1
+    test                r5d, r5d
+    jz .w16_filter_left ; filter_strength == 0
+    imul                r5d, 0x24924924
+    pshufhw              m6, m6, q3333
+    mov              [dstq], tlq
+    lea                 tlq, [rsp+16*14]
+    shr                 r5d, 30
+    movhps       [tlq+16*2], m6
+    adc                 r5d, -1 ; filter_strength
+    mov                 r3d, 16
+    call mangle(private_prefix %+ _ipred_z1_16bpc_ssse3).filter_edge
+    mov                 r3d, maxwm
+    mov                 tlq, [dstq]
+    cmp                 r3d, 16
+    jge .w16_filter_left
+    movu                 m1, [tlq+r3*2+16*0+2]
+    movu                 m2, [tlq+r3*2+16*1+2]
+    movu   [rsp+r3*2+16*14], m1
+    movu   [rsp+r3*2+16*15], m2
+.w16_filter_left:
+    pmovmskb            r5d, m7
+    test                r5d, r5d
+    jz .w4_main
+    imul                r5d, 0x24924924
+    neg                  hq
+    mov                  r3, tlq
+    movd                 m1, [tlq+hq*2]
+    shr                 r5d, 30
+    lea                 tlq, [rsp+16*13-2]
+    pshuflw              m1, m1, q0000
+    adc                 r5d, -1 ; filter_strength
+    movq       [tlq+hq*2-6], m1
+    call mangle(private_prefix %+ _ipred_z3_16bpc_ssse3).filter_edge
+    jmp .filter_left_end
+.w32:
+    movu                 m1, [tlq+16*2+2]
+    movu                 m2, [tlq+16*3+2]
+    mova        [rsp+16*16], m1
+    mova        [rsp+16*17], m2
+    test             angled, 0x400
+    jnz .w4_main
+    mov              [dstq], tlq
+    lea                 tlq, [rsp+16*14]
+    pshufhw              m2, m2, q3333
+    mov                 r3d, 32
+    movhps       [tlq+16*4], m2
+    call mangle(private_prefix %+ _ipred_z1_16bpc_ssse3).filter_edge_s3
+    mov                 r3d, maxwm
+    mov                 tlq, [dstq]
+    cmp                 r3d, 32
+    jge .filter_left
+    movu                 m1, [tlq+r3*2+16*0+2]
+    movu                 m2, [tlq+r3*2+16*1+2]
+    movu   [rsp+r3*2+16*14], m1
+    movu   [rsp+r3*2+16*15], m2
+    cmp                 r3d, 16
+    jge .filter_left
+    movu                 m1, [tlq+r3*2+16*2+2]
+    movu                 m2, [tlq+r3*2+16*3+2]
+    movu   [rsp+r3*2+16*16], m1
+    movu   [rsp+r3*2+16*17], m2
+.filter_left:
+    neg                  hq
+    mov                  r3, tlq
+    pshuflw              m1, [tlq+hq*2], q0000
+    lea                 tlq, [rsp+16*13-2]
+    movq       [tlq+hq*2-6], m1
+    call mangle(private_prefix %+ _ipred_z3_16bpc_ssse3).filter_edge_s3
+.filter_left_end:
+    mov                 r2d, maxhm
+    cmp                 r2d, hd
+    jge .w4_main
+    neg                  r2
+    movu                 m1, [r3+r2*2-16*1]
+    movu                 m2, [r3+r2*2-16*2]
+    movu   [rsp+r2*2+16*12], m1
+    movu   [rsp+r2*2+16*11], m2
+    cmp                 r2d, -48
+    jle .w4_main
+    movu                 m1, [r3+r2*2-16*3]
+    movu                 m2, [r3+r2*2-16*4]
+    movu   [rsp+r2*2+16*10], m1
+    movu   [rsp+r2*2+16* 9], m2
+    cmp                 r2d, -32
+    jle .w4_main
+    movu                 m1, [r3+r2*2-16*5]
+    movu                 m2, [r3+r2*2-16*6]
+    movu   [rsp+r2*2+16* 8], m1
+    movu   [rsp+r2*2+16* 7], m2
+    cmp                 r2d, -16
+    jle .w4_main
+    movu                 m1, [r3+r2*2-16*7]
+    movu                 m2, [r3+r2*2-16*8]
+    movu   [rsp+r2*2+16* 6], m1
+    movu   [rsp+r2*2+16* 5], m2
+    jmp .w4_main
+.w64:
+    movu                 m1, [tlq+16*2+2]
+    movu                 m2, [tlq+16*3+2]
+    movu                 m3, [tlq+16*4+2]
+    movu                 m4, [tlq+16*5+2]
+    movu                 m5, [tlq+16*6+2]
+    movu                 m6, [tlq+16*7+2]
+    mov              [dstq], tlq
+    lea                 tlq, [rsp+16*14]
+    mova         [tlq+16*2], m1
+    mova         [tlq+16*3], m2
+    mova         [tlq+16*4], m3
+    mova         [tlq+16*5], m4
+    mova         [tlq+16*6], m5
+    mova         [tlq+16*7], m6
+    test             angled, 0x400
+    jnz .w4_main
+    pshufhw              m6, m6, q3333
+    mov                 r3d, 64
+    movhps       [tlq+16*8], m6
+    call mangle(private_prefix %+ _ipred_z1_16bpc_ssse3).filter_edge_s3
+    mov                 r3d, maxwm
+    mov                 tlq, [dstq]
+    cmp                 r3d, 64
+    jge .filter_left
+    movu                 m1, [tlq+r3*2+16*0+2]
+    movu                 m2, [tlq+r3*2+16*1+2]
+    movu   [rsp+r3*2+16*14], m1
+    movu   [rsp+r3*2+16*15], m2
+    cmp                 r3d, 48
+    jge .filter_left
+    movu                 m1, [tlq+r3*2+16*2+2]
+    movu                 m2, [tlq+r3*2+16*3+2]
+    movu   [rsp+r3*2+16*16], m1
+    movu   [rsp+r3*2+16*17], m2
+    cmp                 r3d, 32
+    jge .filter_left
+    movu                 m1, [tlq+r3*2+16*4+2]
+    movu                 m2, [tlq+r3*2+16*5+2]
+    movu   [rsp+r3*2+16*18], m1
+    movu   [rsp+r3*2+16*19], m2
+    cmp                 r3d, 16
+    jge .filter_left
+    movu                 m1, [tlq+r3*2+16*6+2]
+    movu                 m2, [tlq+r3*2+16*7+2]
+    movu   [rsp+r3*2+16*20], m1
+    movu   [rsp+r3*2+16*21], m2
+    jmp .filter_left
+
+%if ARCH_X86_64
+cglobal ipred_z3_16bpc, 4, 9, 8, 16*18, dst, stride, tl, w, h, angle, dy, _, org_w
+    %define            base  r7-$$
+    lea                  r7, [$$]
+    mov              org_wd, wd
+%else
+cglobal ipred_z3_16bpc, 4, 7, 8, -16*18, dst, stride, tl, w, h, angle, dy
+    %define            base  r1-$$
+    %define          org_wd  r5
+    %define          org_wq  r5
+    movd                 m6, r8m ; pixel_max
+    mov          [dstq+4*0], strideq
+    LEA                  r1, $$
+    mov          [dstq+4*1], wd
+%endif
+    tzcnt                hd, hm
+    movifnidn        angled, anglem
+    sub                 tlq, 2
+    movsxd               hq, [base+ipred_z3_16bpc_ssse3_table+hq*4]
+    sub              angled, 180
+    movddup              m0, [base+pw_256]
+    mov                 dyd, angled
+    neg                 dyd
+    xor              angled, 0x400
+    movddup              m7, [base+pw_62]
+    or                  dyq, ~0x7e
+    lea                  hq, [base+ipred_z3_16bpc_ssse3_table+hq]
+    movzx               dyd, word [base+dr_intra_derivative+45*2-1+dyq]
+    jmp                  hq
+.h4:
+    lea                 r4d, [angleq+88]
+    test                r4d, 0x480
+    jnz .h4_no_upsample ; !enable_intra_edge_filter || angle >= 40
+    sar                 r4d, 9
+    add                 r4d, wd
+    cmp                 r4d, 8
+    jg .h4_no_upsample ; w > 8 || (w == 8 && is_sm)
+    mova                 m2, [tlq-14]   ; 7 6 5 4 3 2 1 0
+    movu                 m3, [tlq-12]   ; 8 7 6 5 4 3 2 1
+%if ARCH_X86_64
+    movd                 m6, r8m
+%endif
+    pshufb               m4, m2, m0
+    mov                 tlq, rsp
+    palignr              m1, m2, m4, 14 ; 8 8 7 6 5 4 3 2
+    add                 dyd, dyd
+    palignr              m5, m2, m4, 12 ; 8 8 8 7 6 5 4 3
+    paddw                m1, m2
+    paddw                m3, m5
+    psubw                m5, m1, m3
+    mova                 m3, [base+z_upsample]
+    mova           [tlq+ 0], m4
+    movd                 m4, dyd
+    psraw                m5, 3
+    neg                 dyd
+    paddw                m1, m5
+    pxor                 m5, m5
+    lea                 r5d, [dyq+(16<<6)+63] ; ypos
+    pmaxsw               m1, m5
+    pshufb               m6, m0
+    shl                  wd, 3
+    pavgw                m1, m5
+    pshufb               m4, m0
+    pminsw               m1, m6
+    sub                 rsp, wq
+    punpckhwd            m0, m1, m2
+    paddw                m5, m4, m4
+    punpcklwd            m1, m2
+    mova           [tlq+32], m0
+    movsd                m4, m5
+    mova           [tlq+16], m1
+.h4_upsample_loop:
+    lea                 r4d, [r5+dyq]
+    sar                 r5d, 6
+    movu                 m2, [tlq+r5*2]
+    lea                 r5d, [r4+dyq]
+    sar                 r4d, 6
+    movu                 m1, [tlq+r4*2]
+    pshufb               m2, m3
+    pshufb               m1, m3
+    punpckhqdq           m0, m1, m2
+    punpcklqdq           m1, m2
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m4, m5
+    paddw                m0, m1
+    mova        [rsp+wq-16], m0
+    sub                  wd, 16
+    jg .h4_upsample_loop
+    or                  r3d, 4*2
+    jmp .end_transpose
+.h4_no_upsample:
+    mov                 r4d, 7
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h4_main
+    lea                 r4d, [wq+3]
+    movd                 m1, r4d
+    movd                 m3, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m2, m2
+    pshufb               m1, m2
+    pshufb               m3, m2
+    pcmpeqb              m1, [base+z_filt_wh4]
+    pand                 m1, m3
+    pcmpgtb              m1, [base+z_filt_t_w48+angleq*8]
+    pmovmskb            r5d, m1
+    mov                 r4d, 7
+    test                r5d, r5d
+    jz .h4_main ; filter_strength == 0
+    pshuflw              m1, [tlq+2], q0000
+    imul                r5d, 0x55555555
+    mova                 m2, [tlq-14]
+    neg                  r4
+    movd                 m3, [tlq+r4*2]
+    shr                 r5d, 30
+    movd        [rsp+16*17], m1
+    pshuflw              m3, m3, q0000
+    mova        [rsp+16*16], m2
+    lea                  r2, [r4-2]
+    movq [rsp+16*17+r4*2-10], m3
+    cmp                  wd, 8
+    cmovae               r4, r2
+    lea                 tlq, [rsp+16*17-2]
+    call .filter_edge
+.h4_main:
+    movd                 m4, dyd
+    sub                 tlq, r4
+    movddup              m1, [base+z_base_inc_z2+8] ; base_inc << 6
+    sub                 tlq, r4
+    shl                 r4d, 6
+    movd                 m6, [tlq]
+    movd                 m3, r4d
+    pshufb               m4, m0
+    neg                 dyq
+    pshufb               m6, m0
+    lea                  r5, [dyq+r4+63] ; ypos
+    pshufb               m3, m0
+    shl                  wd, 3
+    paddw                m5, m4, m4
+    sub                 rsp, wq
+    psubw                m3, m1 ; max_base_y
+    movsd                m4, m5 ; ypos1 ypos0
+.h4_loop:
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6
+    movddup              m0, [tlq+r5*2-6]
+    movddup              m1, [tlq+r5*2-8]
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6
+    movlps               m0, [tlq+r4*2-6]
+    movlps               m1, [tlq+r4*2-8]
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    pcmpgtw              m2, m3, m4
+    paddw                m4, m5
+    paddw                m0, m1
+    pand                 m0, m2
+    pandn                m2, m6
+    por                  m0, m2
+    mova        [rsp+wq-16], m0
+    sub                  wd, 16
+    jz .h4_transpose
+    test                r5d, r5d
+    jg .h4_loop
+.h4_end_loop:
+    mova        [rsp+wq-16], m6
+    sub                  wd, 16
+    jg .h4_end_loop
+.h4_transpose:
+    or                  r3d, 4*2
+    jmp .end_transpose
+.h8:
+    lea                 r4d, [angleq+88]
+    and                 r4d, ~0x7f
+    or                  r4d, wd
+    cmp                 r4d, 8
+    ja .h8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || w > 8
+    mova                 m2, [tlq-30]  ; g f e d c b a 9
+    movu                 m1, [tlq-32]  ; _ g f e d c b a
+    movu                 m3, [tlq-16]  ; 9 8 7 6 5 4 3 2
+    paddw                m3, [tlq-14]  ; 8 7 6 5 4 3 2 1
+    pshufd               m4, m2, q2100 ; _ _ g f e d c b
+    paddw                m1, m2
+    movu                 m5, [tlq-28]  ; f e d c b a 9 8
+    add                 dyd, dyd
+    cmp                  wd, 8
+    je .h8_upsample_w8
+    pshufhw              m4, m2, q1000 ; _ _ _ _ c c c b
+.h8_upsample_w8:
+    paddw                m4, m5
+    psubw                m5, m1, m4
+    movu                 m4, [tlq-18]  ; a 9 8 7 6 5 4 3
+    psraw                m5, 3
+    paddw                m1, m5
+    movu                 m5, [tlq-12]  ; 7 6 5 4 3 2 1 0
+%if ARCH_X86_64
+    movd                 m6, r8m ; pixel_max
+%endif
+    paddw                m4, m5
+    shl                  wd, 4
+    psubw                m5, m3, m4
+    movd                 m4, dyd
+    psraw                m5, 3
+    neg                 dyd
+    paddw                m3, m5
+    pshufb               m6, m0
+    mova                 m5, [tlq-14]
+    pshufb               m4, m0
+    pxor                 m0, m0
+    pmaxsw               m1, m0
+    pmaxsw               m3, m0
+    mov                 tlq, rsp
+    pavgw                m1, m0
+    pavgw                m3, m0
+    sub                 rsp, wq
+    pminsw               m1, m6
+    pminsw               m6, m3
+    mova                 m3, [base+z_upsample]
+    lea                 r5d, [dyq+(16<<6)+63] ; ypos
+    punpcklwd            m0, m1, m2
+    mova         [tlq+16*0], m0
+    punpckhwd            m1, m2
+    mova         [tlq+16*1], m1
+    punpcklwd            m0, m6, m5
+    mova         [tlq+16*2], m0
+    punpckhwd            m6, m5
+    mova         [tlq+16*3], m6
+    mova                 m5, m4
+.h8_upsample_loop:
+    mov                 r4d, r5d
+    sar                 r4d, 6
+    movu                 m1, [tlq+r4*2+16*0]
+    movu                 m2, [tlq+r4*2+16*1]
+    add                 r5d, dyd
+    pshufb               m2, m3
+    pshufb               m1, m3
+    punpckhqdq           m0, m1, m2
+    punpcklqdq           m1, m2
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m4, m5
+    paddw                m0, m1
+    mova        [rsp+wq-16], m0
+    sub                  wd, 16
+    jg .h8_upsample_loop
+    or                  r3d, 8*2
+    jmp .end_transpose
+.h8_no_upsample:
+    lea                 r4d, [wq+7]
+    movd                 m1, r4d
+    and                 r4d, 7
+    or                  r4d, 8 ; imin(w+7, 15)
+    test             angled, 0x400
+    jnz .h8_main
+    movd                 m3, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m2, m2
+    pshufb               m1, m2
+    pshufb               m3, m2
+    movu                 m2, [base+z_filt_wh8]
+    psrldq               m4, [base+z_filt_t_w48+angleq*8], 4
+    pcmpeqb              m2, m1
+    pand                 m2, m3
+    pcmpgtb              m2, m4
+    pmovmskb            r5d, m2
+    test                r5d, r5d
+    jz .h8_main ; filter_strength == 0
+    pshuflw              m1, [tlq+2], q0000
+    imul                r5d, 0x55555555
+    mova                 m2, [tlq-16*1+2]
+    neg                  r4
+    mova                 m3, [tlq-16*2+2]
+    shr                 r5d, 30
+    movd                 m4, [tlq+r4*2]
+    movd        [rsp+16*17], m1
+    mova        [rsp+16*16], m2
+    pshuflw              m4, m4, q0000
+    mova        [rsp+16*15], m3
+    lea                  r2, [r4-2]
+    movq [rsp+16*17+r4*2-10], m4
+    cmp                  wd, 16
+    cmovae               r4, r2
+    lea                 tlq, [rsp+16*17-2]
+    call .filter_edge
+.h8_main:
+    sub                 tlq, r4
+    movd                 m4, dyd
+    sub                 tlq, r4
+    shl                 r4d, 6
+    movd                 m6, [tlq]
+    movd                 m3, r4d
+    pshufb               m4, m0
+    neg                 dyq
+    pshufb               m6, m0
+    lea                  r5, [dyq+r4+63]
+    pshufb               m3, m0
+    shl                  wd, 4
+    mova                 m5, m4
+    sub                 rsp, wq
+    psubw                m3, [base+z_base_inc_z2]
+.h8_loop:
+    mov                  r4, r5
+    sar                  r4, 6
+    movu                 m0, [tlq+r4*2-14]
+    movu                 m1, [tlq+r4*2-16]
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    pcmpgtw              m2, m3, m4
+    paddw                m4, m5
+    paddw                m0, m1
+    pand                 m0, m2
+    pandn                m2, m6
+    por                  m0, m2
+    mova        [rsp+wq-16], m0
+    sub                  wd, 8*2
+    jz .h8_transpose
+    add                  r5, dyq
+    jg .h8_loop
+.h8_end_loop:
+    mova        [rsp+wq-16], m6
+    sub                  wd, 8*2
+    jg .h8_end_loop
+.h8_transpose:
+    or                  r3d, 8*2
+    jmp .end_transpose
+.h16:
+    lea                 r4d, [wq+15]
+    movd                 m1, r4d
+    and                 r4d, 15
+    or                  r4d, 16 ; imin(w+15, 31)
+    test             angled, 0x400
+    jnz .h16_main
+    movd                 m3, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m2, m2
+    pshufb               m1, m2
+    pshufb               m3, m2
+    movq                 m4, [base+z_filt_t_w16+angleq*4]
+    pcmpeqb              m1, [base+z_filt_wh16]
+    pand                 m1, m3
+    pcmpgtb              m1, m4
+    pmovmskb            r5d, m1
+    test                r5d, r5d
+    jz .h16_main ; filter_strength == 0
+    pshuflw              m1, [tlq+2], q0000
+    mova                 m2, [tlq-16*1+2]
+    imul                r5d, 0x24924924
+    mova                 m3, [tlq-16*2+2]
+    neg                  r4
+    mova                 m4, [tlq-16*3+2]
+    shr                 r5d, 30
+    mova                 m5, [tlq-16*4+2]
+    movd                 m6, [tlq+r4*2]
+    adc                 r5d, -1 ; filter_strength
+    movd        [rsp+16*17], m1
+    mova        [rsp+16*16], m2
+    mova        [rsp+16*15], m3
+    pshuflw              m6, m6, q0000
+    mova        [rsp+16*14], m4
+    mova        [rsp+16*13], m5
+    lea                  r2, [r4-2]
+    movq [rsp+16*17+r4*2-10], m6
+    cmp                  wd, 32
+    cmovae               r4, r2
+    lea                 tlq, [rsp+16*17-2]
+    call .filter_edge
+.h16_main:
+    sub                 tlq, r4
+    movd                 m5, dyd
+    sub                 tlq, r4
+    shl                 r4d, 6
+    movd                 m6, [tlq]
+    movd                 m3, r4d
+    pshufb               m5, m0
+    neg                 dyq
+    pshufb               m6, m0
+    lea                  r5, [dyq+r4+63]
+    pshufb               m3, m0
+    shl                  wd, 5
+    paddw                m4, m5, [base+z_base_inc_z2]
+    sub                 rsp, wq
+    psubw                m4, m3
+.h16_loop:
+    mov                  r4, r5
+    sar                  r4, 6
+    movu                 m0, [tlq+r4*2-14]
+    movu                 m2, [tlq+r4*2-16]
+    pand                 m3, m7, m4
+    psllw                m3, 9
+    psubw                m2, m0
+    pmulhrsw             m2, m3
+    movu                 m1, [tlq+r4*2-30]
+    paddw                m0, m2
+    movu                 m2, [tlq+r4*2-32]
+    psubw                m2, m1
+    pmulhrsw             m2, m3
+    movddup              m3, [base+pw_m512]
+    paddw                m1, m2
+    psraw                m2, m4, 15
+    pcmpgtw              m3, m4
+    paddw                m4, m5
+    pand                 m0, m2
+    pandn                m2, m6
+    pand                 m1, m3
+    pandn                m3, m6
+    por                  m0, m2
+    mova      [rsp+wq-16*1], m0
+    por                  m1, m3
+    mova      [rsp+wq-16*2], m1
+    sub                  wd, 16*2
+    jz .h16_transpose
+    add                  r5, dyq
+    jg .h16_loop
+.h16_end_loop:
+    mova      [rsp+wq-16*1], m6
+    mova      [rsp+wq-16*2], m6
+    sub                  wd, 16*2
+    jg .h16_end_loop
+.h16_transpose:
+    or                  r3d, 16*2
+    jmp .end_transpose
+.h32:
+    lea                 r4d, [wq+31]
+    and                 r4d, 31
+    or                  r4d, 32 ; imin(w+31, 63)
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h32_main
+    call .filter_copy
+    lea                  r5, [r4-2]
+    cmp                  wd, 64
+    cmove                r4, r5
+    call .filter_edge_s3
+.h32_main:
+    sub                 tlq, r4
+    movd                 m5, dyd
+    sub                 tlq, r4
+    shl                 r4d, 6
+    movd                 m6, [tlq]
+    movd                 m3, r4d
+    pshufb               m5, m0
+    neg                 dyq
+    pshufb               m6, m0
+    lea                  r5, [dyq+r4+63]
+    pshufb               m3, m0
+    paddw                m4, m5, [base+z_base_inc_z2]
+    psubw                m4, m3
+.h32_loop:
+    mov                  r4, r5
+    sar                  r4, 6
+    movu                 m0, [tlq+r4*2-14]
+    movu                 m3, [tlq+r4*2-16]
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m3, m0
+    pmulhrsw             m3, m2
+    movu                 m1, [tlq+r4*2-30]
+    paddw                m0, m3
+    movu                 m3, [tlq+r4*2-32]
+    psubw                m3, m1
+    pmulhrsw             m3, m2
+    sub                 rsp, 16*4
+    paddw                m1, m3
+    psraw                m3, m4, 15
+    pand                 m0, m3
+    pandn                m3, m6
+    por                  m0, m3
+    movddup              m3, [base+pw_m512]
+    pcmpgtw              m3, m4
+    pand                 m1, m3
+    pandn                m3, m6
+    mova         [rsp+16*3], m0
+    por                  m1, m3
+    mova         [rsp+16*2], m1
+    movu                 m0, [tlq+r4*2-46]
+    movu                 m3, [tlq+r4*2-48]
+    psubw                m3, m0
+    pmulhrsw             m3, m2
+    movu                 m1, [tlq+r4*2-62]
+    paddw                m0, m3
+    movu                 m3, [tlq+r4*2-64]
+    psubw                m3, m1
+    pmulhrsw             m3, m2
+    movddup              m2, [base+pw_m1024]
+    paddw                m1, m3
+    movddup              m3, [base+pw_m1536]
+    pcmpgtw              m2, m4
+    pcmpgtw              m3, m4
+    paddw                m4, m5
+    pand                 m0, m2
+    pandn                m2, m6
+    pand                 m1, m3
+    pandn                m3, m6
+    por                  m0, m2
+    mova         [rsp+16*1], m0
+    por                  m1, m3
+    mova         [rsp+16*0], m1
+    dec                  wd
+    jz .h32_transpose
+    add                  r5, dyq
+    jg .h32_loop
+.h32_end_loop:
+    sub                 rsp, 16*4
+    REPX {mova [rsp+16*x], m6}, 3, 2, 1, 0
+    dec                  wd
+    jg .h32_end_loop
+.h32_transpose:
+    or                  r3d, 32*2
+    jmp .end_transpose
+.h64:
+    lea                 r4d, [wq+63]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h64_main
+    call .filter_copy
+    call .filter_edge_s3
+.h64_main:
+    sub                 tlq, r4
+    movd                 m5, dyd
+    sub                 tlq, r4
+    shl                 r4d, 6
+    movd                 m6, [tlq]
+    movd                 m3, r4d
+    pshufb               m5, m0
+    neg                 dyq
+    pshufb               m6, m0
+    lea                  r5, [dyq+r4+63]
+    pshufb               m3, m0
+    paddw                m4, m5, [base+z_base_inc_z2]
+    psubw                m4, m3
+.h64_loop:
+    mov                  r4, r5
+    sar                  r4, 6
+    movu                 m0, [tlq+r4*2- 14]
+    movu                 m3, [tlq+r4*2- 16]
+    pand                 m2, m7, m4
+    psllw                m2, 9
+    psubw                m3, m0
+    pmulhrsw             m3, m2
+    movu                 m1, [tlq+r4*2- 30]
+    paddw                m0, m3
+    movu                 m3, [tlq+r4*2- 32]
+    psubw                m3, m1
+    pmulhrsw             m3, m2
+    sub                 rsp, 16*8
+    paddw                m1, m3
+    psraw                m3, m4, 15
+    pand                 m0, m3
+    pandn                m3, m6
+    por                  m0, m3
+    movddup              m3, [base+pw_m512]
+    pcmpgtw              m3, m4
+    pand                 m1, m3
+    pandn                m3, m6
+    mova         [rsp+16*7], m0
+    por                  m1, m3
+    mova         [rsp+16*6], m1
+    movu                 m0, [tlq+r4*2- 46]
+    movu                 m3, [tlq+r4*2- 48]
+    psubw                m3, m0
+    pmulhrsw             m3, m2
+    movu                 m1, [tlq+r4*2- 62]
+    paddw                m0, m3
+    movu                 m3, [tlq+r4*2- 64]
+    psubw                m3, m1
+    pmulhrsw             m3, m2
+    paddw                m1, m3
+    movddup              m3, [base+pw_m1024]
+    pcmpgtw              m3, m4
+    pand                 m0, m3
+    pandn                m3, m6
+    por                  m0, m3
+    movddup              m3, [base+pw_m1536]
+    pcmpgtw              m3, m4
+    pand                 m1, m3
+    pandn                m3, m6
+    mova         [rsp+16*5], m0
+    por                  m1, m3
+    mova         [rsp+16*4], m1
+    movu                 m0, [tlq+r4*2- 78]
+    movu                 m3, [tlq+r4*2- 80]
+    psubw                m3, m0
+    pmulhrsw             m3, m2
+    movu                 m1, [tlq+r4*2- 94]
+    paddw                m0, m3
+    movu                 m3, [tlq+r4*2- 96]
+    psubw                m3, m1
+    pmulhrsw             m3, m2
+    paddw                m1, m3
+    movddup              m3, [base+pw_m2048]
+    pcmpgtw              m3, m4
+    pand                 m0, m3
+    pandn                m3, m6
+    por                  m0, m3
+    movddup              m3, [base+pw_m2560]
+    pcmpgtw              m3, m4
+    pand                 m1, m3
+    pandn                m3, m6
+    mova         [rsp+16*3], m0
+    por                  m1, m3
+    mova         [rsp+16*2], m1
+    movu                 m0, [tlq+r4*2-110]
+    movu                 m3, [tlq+r4*2-112]
+    psubw                m3, m0
+    pmulhrsw             m3, m2
+    movu                 m1, [tlq+r4*2-126]
+    paddw                m0, m3
+    movu                 m3, [tlq+r4*2-128]
+    psubw                m3, m1
+    pmulhrsw             m3, m2
+    movddup              m2, [base+pw_m3072]
+    paddw                m1, m3
+    movddup              m3, [base+pw_m3584]
+    pcmpgtw              m2, m4
+    pcmpgtw              m3, m4
+    paddw                m4, m5
+    pand                 m0, m2
+    pandn                m2, m6
+    pand                 m1, m3
+    pandn                m3, m6
+    por                  m0, m2
+    mova         [rsp+16*1], m0
+    por                  m1, m3
+    mova         [rsp+16*0], m1
+    dec                  wd
+    jz .h64_transpose
+    add                  r5, dyq
+    jg .h64_loop
+.h64_end_loop:
+    sub                 rsp, 16*8
+    REPX {mova [rsp+16*x], m6}, 7, 6, 5, 4, 3, 2, 1, 0
+    dec                  wd
+    jg .h64_end_loop
+.h64_transpose:
+    add                 r3d, 64*2
+.end_transpose:
+%if ARCH_X86_64
+    lea                  r7, [strideq*3]
+%else
+    mov             strideq, [dstq+4*0]
+    mov              org_wd, [dstq+4*1]
+%endif
+    lea                 r4d, [r3*3]
+.end_transpose_loop:
+    lea                  r2, [rsp+r3-8]
+    lea                  r6, [dstq+org_wq*2-8]
+.end_transpose_loop_y:
+    movq                 m0, [r2+r4  ]
+    movq                 m1, [r2+r3*2]
+    movq                 m2, [r2+r3*1]
+    movq                 m3, [r2+r3*0]
+    sub                  r2, 8
+    punpcklwd            m0, m1
+    punpcklwd            m2, m3
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    movhps   [r6+strideq*0], m1
+    movq     [r6+strideq*1], m1
+%if ARCH_X86_64
+    movhps   [r6+strideq*2], m0
+    movq     [r6+r7       ], m0
+    lea                  r6, [r6+strideq*4]
+%else
+    lea                  r6, [r6+strideq*2]
+    movhps   [r6+strideq*0], m0
+    movq     [r6+strideq*1], m0
+    lea                  r6, [r6+strideq*2]
+%endif
+    cmp                  r2, rsp
+    jae .end_transpose_loop_y
+    lea                 rsp, [rsp+r3*4]
+    sub              org_wd, 4
+    jg .end_transpose_loop
+    RET
+.filter_copy:
+    neg                  r4
+    pshuflw              m2, [tlq+2], q0000
+    xor                 r5d, r5d
+    pshuflw              m3, [tlq+r4*2], q0000
+    movq [rsp+gprsize+16*17], m2
+.filter_copy_loop:
+    mova                 m1, [tlq+r5*2-16*1+2]
+    mova                 m2, [tlq+r5*2-16*2+2]
+    sub                  r5, 16
+    mova [rsp+r5*2+gprsize+16*18], m1
+    mova [rsp+r5*2+gprsize+16*17], m2
+    cmp                 r5d, r4d
+    jg .filter_copy_loop
+    lea                 tlq, [rsp+gprsize+16*17-2]
+    movq       [tlq+r4*2-8], m3
+    ret
+.filter_edge:
+    cmp                 r5d, 3
+    je .filter_edge_s3
+    movddup              m4, [base+z_filt_k+r5*8-8]
+    movddup              m5, [base+z_filt_k+r5*8+8]
+    xor                 r5d, r5d
+    movddup              m6, [base+pw_8]
+    movu                 m2, [tlq-12]
+    jmp .filter_edge_start
+.filter_edge_loop:
+    movu                 m2, [tlq+r5*2-12]
+    mova       [tlq+r5*2+2], m1
+.filter_edge_start:
+    pmullw               m1, m4, [tlq+r5*2-14]
+    movu                 m3, [tlq+r5*2-16]
+    sub                  r5, 8
+    paddw                m2, m3
+    pmullw               m2, m5
+    paddw                m1, m6
+    paddw                m1, m2
+    psrlw                m1, 4
+    cmp                 r5d, r4d
+    jg .filter_edge_loop
+    mova       [tlq+r5*2+2], m1
+    neg                 r4d
+    ret
+.filter_edge_s3:
+    movddup              m5, [base+pw_3]
+    xor                 r5d, r5d
+    movu                 m2, [tlq-12]
+    movu                 m3, [tlq-10]
+    jmp .filter_edge_s3_start
+.filter_edge_s3_loop:
+    movu                 m2, [tlq+r5*2-12]
+    movu                 m3, [tlq+r5*2-10]
+    mova       [tlq+r5*2+2], m1
+.filter_edge_s3_start:
+    paddw                m2, [tlq+r5*2-14]
+    paddw                m3, m5
+    movu                 m1, [tlq+r5*2-16]
+    movu                 m4, [tlq+r5*2-18]
+    sub                  r5, 8
+    paddw                m1, m2
+    pavgw                m3, m4
+    paddw                m1, m3
+    psrlw                m1, 2
+    cmp                 r5d, r4d
+    jg .filter_edge_s3_loop
+    mova       [tlq+r5*2+2], m1
+    neg                 r4d
+    ret
+
+%if ARCH_X86_64
+cglobal ipred_filter_16bpc, 4, 7, 16, dst, stride, tl, w, h, filter
+%else
+cglobal ipred_filter_16bpc, 4, 7, 8, -16*8, dst, stride, tl, w, h, filter
+%define  m8 [esp+16*0]
+%define  m9 [esp+16*1]
+%define m10 [esp+16*2]
+%define m11 [esp+16*3]
+%define m12 [esp+16*4]
+%define m13 [esp+16*5]
+%define m14 [esp+16*6]
+%define m15 [esp+16*7]
+%endif
+%define base r6-$$
+    movifnidn            hd, hm
+    movd                 m6, r8m     ; bitdepth_max
+%ifidn filterd, filterm
+    movzx           filterd, filterb
+%else
+    movzx           filterd, byte filterm
+%endif
+    LEA                  r6, $$
+    shl             filterd, 6
+    movu                 m0, [tlq-6] ; __ l1 l0 tl t0 t1 t2 t3
+    mova                 m1, [base+filter_intra_taps+filterq+16*0]
+    mova                 m2, [base+filter_intra_taps+filterq+16*1]
+    mova                 m3, [base+filter_intra_taps+filterq+16*2]
+    mova                 m4, [base+filter_intra_taps+filterq+16*3]
+    pxor                 m5, m5
+%if ARCH_X86_64
+    punpcklbw            m8, m5, m1  ; place 8-bit coefficients in the upper
+    punpckhbw            m9, m5, m1  ; half of each 16-bit word to avoid
+    punpcklbw           m10, m5, m2  ; having to perform sign-extension.
+    punpckhbw           m11, m5, m2
+    punpcklbw           m12, m5, m3
+    punpckhbw           m13, m5, m3
+    punpcklbw           m14, m5, m4
+    punpckhbw           m15, m5, m4
+%else
+    punpcklbw            m7, m5, m1
+    mova                 m8, m7
+    punpckhbw            m7, m5, m1
+    mova                 m9, m7
+    punpcklbw            m7, m5, m2
+    mova                m10, m7
+    punpckhbw            m7, m5, m2
+    mova                m11, m7
+    punpcklbw            m7, m5, m3
+    mova                m12, m7
+    punpckhbw            m7, m5, m3
+    mova                m13, m7
+    punpcklbw            m7, m5, m4
+    mova                m14, m7
+    punpckhbw            m7, m5, m4
+    mova                m15, m7
+%endif
+    mova                 m7, [base+filter_shuf]
+    add                  hd, hd
+    mov                  r5, dstq
+    pshuflw              m6, m6, q0000
+    mov                  r6, tlq
+    punpcklqdq           m6, m6
+    sub                 tlq, hq
+.left_loop:
+    pshufb               m0, m7      ; tl t0 t1 t2 t3 l0 l1 __
+    pshufd               m1, m0, q0000
+    pmaddwd              m2, m8, m1
+    pmaddwd              m1, m9
+    pshufd               m4, m0, q1111
+    pmaddwd              m3, m10, m4
+    pmaddwd              m4, m11
+    paddd                m2, m3
+    paddd                m1, m4
+    pshufd               m4, m0, q2222
+    pmaddwd              m3, m12, m4
+    pmaddwd              m4, m13
+    paddd                m2, m3
+    paddd                m1, m4
+    pshufd               m3, m0, q3333
+    pmaddwd              m0, m14, m3
+    pmaddwd              m3, m15
+    paddd                m0, m2
+    paddd                m1, m3
+    psrad                m0, 11     ; x >> 3
+    psrad                m1, 11
+    packssdw             m0, m1
+    pmaxsw               m0, m5
+    pavgw                m0, m5     ; (x + 8) >> 4
+    pminsw               m0, m6
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movlps               m0, [tlq+hq-10]
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2*2
+    jg .left_loop
+    sub                  wd, 4
+    jz .end
+    sub                 tld, r6d     ; -h*2
+    sub                  r6, r5      ; tl-dst
+.right_loop0:
+    add                  r5, 8
+    mov                  hd, tld
+    movu                 m0, [r5+r6] ; tl t0 t1 t2 t3 __ __ __
+    mov                dstq, r5
+.right_loop:
+    pshufd               m2, m0, q0000
+    pmaddwd              m1, m8, m2
+    pmaddwd              m2, m9
+    pshufd               m4, m0, q1111
+    pmaddwd              m3, m10, m4
+    pmaddwd              m4, m11
+    pinsrw               m0, [dstq+strideq*0-2], 5
+    paddd                m1, m3
+    paddd                m2, m4
+    pshufd               m0, m0, q2222
+    movddup              m4, [dstq+strideq*1-8]
+    pmaddwd              m3, m12, m0
+    pmaddwd              m0, m13
+    paddd                m1, m3
+    paddd                m0, m2
+    pshuflw              m2, m4, q3333
+    punpcklwd            m2, m5
+    pmaddwd              m3, m14, m2
+    pmaddwd              m2, m15
+    paddd                m1, m3
+    paddd                m0, m2
+    psrad                m1, 11
+    psrad                m0, 11
+    packssdw             m0, m1
+    pmaxsw               m0, m5
+    pavgw                m0, m5
+    pminsw               m0, m6
+    movhps [dstq+strideq*0], m0
+    movq   [dstq+strideq*1], m0
+    palignr              m0, m4, 14
+    lea                dstq, [dstq+strideq*2]
+    add                  hd, 2*2
+    jl .right_loop
+    sub                  wd, 4
+    jg .right_loop0
+.end:
+    RET
+
+%if UNIX64
+DECLARE_REG_TMP 7
+%else
+DECLARE_REG_TMP 5
+%endif
+
+cglobal ipred_cfl_top_16bpc, 4, 7, 8, dst, stride, tl, w, h, ac
+    LEA                  t0, ipred_cfl_left_16bpc_ssse3_table
+    movd                 m4, wd
+    tzcnt                wd, wd
+    movifnidn            hd, hm
+    add                 tlq, 2
+    movsxd               r6, [t0+wq*4]
+    movd                 m5, wd
+    jmp mangle(private_prefix %+ _ipred_cfl_left_16bpc_ssse3.start)
+
+cglobal ipred_cfl_left_16bpc, 3, 7, 8, dst, stride, tl, w, h, ac, alpha
+    movifnidn            hd, hm
+    LEA                  t0, ipred_cfl_left_16bpc_ssse3_table
+    tzcnt                wd, wm
+    lea                 r6d, [hq*2]
+    movd                 m4, hd
+    sub                 tlq, r6
+    tzcnt               r6d, hd
+    movd                 m5, r6d
+    movsxd               r6, [t0+r6*4]
+.start:
+    movd                 m7, r7m
+    movu                 m0, [tlq]
+    add                  r6, t0
+    add                  t0, ipred_cfl_splat_16bpc_ssse3_table-ipred_cfl_left_16bpc_ssse3_table
+    movsxd               wq, [t0+wq*4]
+    pxor                 m6, m6
+    pshuflw              m7, m7, q0000
+    pcmpeqw              m3, m3
+    add                  wq, t0
+    movifnidn           acq, acmp
+    pavgw                m4, m6
+    punpcklqdq           m7, m7
+    jmp                  r6
+.h32:
+    movu                 m1, [tlq+48]
+    movu                 m2, [tlq+32]
+    paddw                m0, m1
+    paddw                m0, m2
+.h16:
+    movu                 m1, [tlq+16]
+    paddw                m0, m1
+.h8:
+    pshufd               m1, m0, q1032
+    paddw                m0, m1
+.h4:
+    pmaddwd              m0, m3
+    psubd                m4, m0
+    pshuflw              m0, m4, q1032
+    paddd                m0, m4
+    psrld                m0, m5
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+    jmp                  wq
+
+%macro IPRED_CFL 2 ; dst, src
+    pabsw               m%1, m%2
+    pmulhrsw            m%1, m2
+    psignw              m%2, m1
+    psignw              m%1, m%2
+    paddw               m%1, m0
+    pmaxsw              m%1, m6
+    pminsw              m%1, m7
+%endmacro
+
+cglobal ipred_cfl_16bpc, 4, 7, 8, dst, stride, tl, w, h, ac, alpha
+    movifnidn            hd, hm
+    tzcnt               r6d, hd
+    lea                 t0d, [wq+hq]
+    movd                 m4, t0d
+    tzcnt               t0d, t0d
+    movd                 m5, t0d
+    LEA                  t0, ipred_cfl_16bpc_ssse3_table
+    tzcnt                wd, wd
+    movd                 m7, r7m
+    movsxd               r6, [t0+r6*4]
+    movsxd               wq, [t0+wq*4+4*4]
+    psrlw                m4, 1
+    pxor                 m6, m6
+    pshuflw              m7, m7, q0000
+    add                  r6, t0
+    add                  wq, t0
+    movifnidn           acq, acmp
+    pcmpeqw              m3, m3
+    punpcklqdq           m7, m7
+    jmp                  r6
+.h4:
+    movq                 m0, [tlq-8]
+    jmp                  wq
+.w4:
+    movq                 m1, [tlq+2]
+    paddw                m0, m1
+    pmaddwd              m0, m3
+    psubd                m4, m0
+    pshufd               m0, m4, q1032
+    paddd                m0, m4
+    pshuflw              m4, m0, q1032
+    paddd                m0, m4
+    cmp                  hd, 4
+    jg .w4_mul
+    psrld                m0, 3
+    jmp .w4_end
+.w4_mul:
+    mov                 r6d, 0xAAAB
+    mov                 r2d, 0x6667
+    cmp                  hd, 16
+    cmove               r6d, r2d
+    movd                 m1, r6d
+    psrld                m0, 2
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w4_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s4:
+    movd                 m1, alpham
+    lea                  r6, [strideq*3]
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    pabsw                m2, m1
+    psllw                m2, 9
+.s4_loop:
+    mova                 m4, [acq+16*0]
+    mova                 m5, [acq+16*1]
+    add                 acq, 16*2
+    IPRED_CFL             3, 4
+    IPRED_CFL             4, 5
+    movq   [dstq+strideq*0], m3
+    movhps [dstq+strideq*1], m3
+    movq   [dstq+strideq*2], m4
+    movhps [dstq+r6       ], m4
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s4_loop
+    RET
+.h8:
+    mova                 m0, [tlq-16]
+    jmp                  wq
+.w8:
+    movu                 m1, [tlq+2]
+    paddw                m0, m1
+    pmaddwd              m0, m3
+    psubd                m4, m0
+    pshufd               m0, m4, q1032
+    paddd                m0, m4
+    pshuflw              m4, m0, q1032
+    paddd                m0, m4
+    psrld                m0, m5
+    cmp                  hd, 8
+    je .w8_end
+    mov                 r6d, 0xAAAB
+    mov                 r2d, 0x6667
+    cmp                  hd, 32
+    cmove               r6d, r2d
+    movd                 m1, r6d
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w8_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s8:
+    movd                 m1, alpham
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    pabsw                m2, m1
+    psllw                m2, 9
+.s8_loop:
+    mova                 m4, [acq+16*0]
+    mova                 m5, [acq+16*1]
+    add                 acq, 16*2
+    IPRED_CFL             3, 4
+    IPRED_CFL             4, 5
+    mova   [dstq+strideq*0], m3
+    mova   [dstq+strideq*1], m4
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .s8_loop
+    RET
+.h16:
+    mova                 m0, [tlq-32]
+    paddw                m0, [tlq-16]
+    jmp                  wq
+.w16:
+    movu                 m1, [tlq+ 2]
+    movu                 m2, [tlq+18]
+    paddw                m1, m2
+    paddw                m0, m1
+    pmaddwd              m0, m3
+    psubd                m4, m0
+    pshufd               m0, m4, q1032
+    paddd                m0, m4
+    pshuflw              m4, m0, q1032
+    paddd                m0, m4
+    psrld                m0, m5
+    cmp                  hd, 16
+    je .w16_end
+    mov                 r6d, 0xAAAB
+    mov                 r2d, 0x6667
+    test                 hd, 8|32
+    cmovz               r6d, r2d
+    movd                 m1, r6d
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w16_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s16:
+    movd                 m1, alpham
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    pabsw                m2, m1
+    psllw                m2, 9
+.s16_loop:
+    mova                 m4, [acq+16*0]
+    mova                 m5, [acq+16*1]
+    add                 acq, 16*2
+    IPRED_CFL             3, 4
+    IPRED_CFL             4, 5
+    mova        [dstq+16*0], m3
+    mova        [dstq+16*1], m4
+    add                dstq, strideq
+    dec                  hd
+    jg .s16_loop
+    RET
+.h32:
+    mova                 m0, [tlq-64]
+    paddw                m0, [tlq-48]
+    paddw                m0, [tlq-32]
+    paddw                m0, [tlq-16]
+    jmp                  wq
+.w32:
+    movu                 m1, [tlq+ 2]
+    movu                 m2, [tlq+18]
+    paddw                m1, m2
+    movu                 m2, [tlq+34]
+    paddw                m1, m2
+    movu                 m2, [tlq+50]
+    paddw                m1, m2
+    paddw                m0, m1
+    pmaddwd              m0, m3
+    psubd                m4, m0
+    pshufd               m0, m4, q1032
+    paddd                m0, m4
+    pshuflw              m4, m0, q1032
+    paddd                m0, m4
+    psrld                m0, m5
+    cmp                  hd, 32
+    je .w32_end
+    mov                 r6d, 0xAAAB
+    mov                 r2d, 0x6667
+    cmp                  hd, 8
+    cmove               r6d, r2d
+    movd                 m1, r6d
+    pmulhuw              m0, m1
+    psrlw                m0, 1
+.w32_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s32:
+    movd                 m1, alpham
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    pabsw                m2, m1
+    psllw                m2, 9
+.s32_loop:
+    mova                 m4, [acq+16*0]
+    mova                 m5, [acq+16*1]
+    IPRED_CFL             3, 4
+    IPRED_CFL             4, 5
+    mova        [dstq+16*0], m3
+    mova        [dstq+16*1], m4
+    mova                 m4, [acq+16*2]
+    mova                 m5, [acq+16*3]
+    add                 acq, 16*4
+    IPRED_CFL             3, 4
+    IPRED_CFL             4, 5
+    mova        [dstq+16*2], m3
+    mova        [dstq+16*3], m4
+    add                dstq, strideq
+    dec                  hd
+    jg .s32_loop
+    RET
+
+cglobal ipred_cfl_128_16bpc, 3, 7, 8, dst, stride, tl, w, h, ac
+    tzcnt                wd, wm
+    LEA                  t0, ipred_cfl_splat_16bpc_ssse3_table
+    mov                 r6d, r7m
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movd                 m7, r7m
+    movsxd               wq, [t0+wq*4]
+    movddup              m0, [t0-ipred_cfl_splat_16bpc_ssse3_table+pw_512+r6*8]
+    pshuflw              m7, m7, q0000
+    pxor                 m6, m6
+    add                  wq, t0
+    movifnidn           acq, acmp
+    punpcklqdq           m7, m7
+    jmp                  wq
+
+cglobal ipred_cfl_ac_420_16bpc, 3, 7, 6, ac, ypx, stride, wpad, hpad, w, h
+    movifnidn         hpadd, hpadm
+%if ARCH_X86_32 && PIC
+    pcmpeqw              m5, m5
+    pabsw                m5, m5
+    paddw                m5, m5
+%else
+    movddup              m5, [pw_2]
+%endif
+    mov                  hd, hm
+    shl               hpadd, 2
+    pxor                 m4, m4
+    sub                  hd, hpadd
+    cmp            dword wm, 8
+    mov                  r5, acq
+    jg .w16
+    je .w8
+    lea                  r3, [strideq*3]
+.w4_loop:
+    pmaddwd              m0, m5, [ypxq+strideq*0]
+    pmaddwd              m1, m5, [ypxq+strideq*1]
+    pmaddwd              m2, m5, [ypxq+strideq*2]
+    pmaddwd              m3, m5, [ypxq+r3       ]
+    lea                ypxq, [ypxq+strideq*4]
+    paddd                m0, m1
+    paddd                m2, m3
+    paddd                m4, m0
+    packssdw             m0, m2
+    paddd                m4, m2
+    mova              [acq], m0
+    add                 acq, 16
+    sub                  hd, 2
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz .dc
+    punpckhqdq           m0, m0
+    pslld                m2, 2
+.w4_hpad:
+    mova         [acq+16*0], m0
+    paddd                m4, m2
+    mova         [acq+16*1], m0
+    add                 acq, 16*2
+    sub               hpadd, 4
+    jg .w4_hpad
+    jmp .dc
+.w8:
+%if ARCH_X86_32
+    cmp         dword wpadm, 0
+%else
+    test              wpadd, wpadd
+%endif
+    jnz .w8_wpad1
+.w8_loop:
+    pmaddwd              m0, m5, [ypxq+strideq*0+16*0]
+    pmaddwd              m2, m5, [ypxq+strideq*1+16*0]
+    pmaddwd              m1, m5, [ypxq+strideq*0+16*1]
+    pmaddwd              m3, m5, [ypxq+strideq*1+16*1]
+    lea                ypxq, [ypxq+strideq*2]
+    paddd                m0, m2
+    paddd                m1, m3
+    paddd                m2, m0, m1
+    packssdw             m0, m1
+    paddd                m4, m2
+    mova              [acq], m0
+    add                 acq, 16
+    dec                  hd
+    jg .w8_loop
+.w8_hpad:
+    test              hpadd, hpadd
+    jz .dc
+    pslld                m2, 2
+    mova                 m1, m0
+    jmp .hpad
+.w8_wpad1:
+    pmaddwd              m0, m5, [ypxq+strideq*0]
+    pmaddwd              m1, m5, [ypxq+strideq*1]
+    lea                ypxq, [ypxq+strideq*2]
+    paddd                m0, m1
+    pshufd               m1, m0, q3333
+    paddd                m2, m0, m1
+    packssdw             m0, m1
+    paddd                m4, m2
+    mova              [acq], m0
+    add                 acq, 16
+    dec                  hd
+    jg .w8_wpad1
+    jmp .w8_hpad
+.w16_wpad3:
+    pshufd               m3, m0, q3333
+    mova                 m1, m3
+    mova                 m2, m3
+    jmp .w16_wpad_end
+.w16_wpad2:
+    pshufd               m1, m3, q3333
+    mova                 m2, m1
+    jmp .w16_wpad_end
+.w16_wpad1:
+    pshufd               m2, m1, q3333
+    jmp .w16_wpad_end
+.w16:
+    movifnidn         wpadd, wpadm
+    WIN64_SPILL_XMM       7
+.w16_loop:
+    pmaddwd              m0, m5, [ypxq+strideq*0+16*0]
+    pmaddwd              m6, m5, [ypxq+strideq*1+16*0]
+    paddd                m0, m6
+    cmp               wpadd, 2
+    jg .w16_wpad3
+    pmaddwd              m3, m5, [ypxq+strideq*0+16*1]
+    pmaddwd              m6, m5, [ypxq+strideq*1+16*1]
+    paddd                m3, m6
+    je .w16_wpad2
+    pmaddwd              m1, m5, [ypxq+strideq*0+16*2]
+    pmaddwd              m6, m5, [ypxq+strideq*1+16*2]
+    paddd                m1, m6
+    jp .w16_wpad1
+    pmaddwd              m2, m5, [ypxq+strideq*0+16*3]
+    pmaddwd              m6, m5, [ypxq+strideq*1+16*3]
+    paddd                m2, m6
+.w16_wpad_end:
+    lea                ypxq, [ypxq+strideq*2]
+    paddd                m6, m0, m3
+    packssdw             m0, m3
+    paddd                m6, m1
+    mova         [acq+16*0], m0
+    packssdw             m1, m2
+    paddd                m2, m6
+    mova         [acq+16*1], m1
+    add                 acq, 16*2
+    paddd                m4, m2
+    dec                  hd
+    jg .w16_loop
+    WIN64_RESTORE_XMM
+    add               hpadd, hpadd
+    jz .dc
+    paddd                m2, m2
+.hpad:
+    mova         [acq+16*0], m0
+    mova         [acq+16*1], m1
+    paddd                m4, m2
+    mova         [acq+16*2], m0
+    mova         [acq+16*3], m1
+    add                 acq, 16*4
+    sub               hpadd, 4
+    jg .hpad
+.dc:
+    sub                  r5, acq ; -w*h*2
+    pshufd               m2, m4, q1032
+    tzcnt               r1d, r5d
+    paddd                m2, m4
+    sub                 r1d, 2
+    pshufd               m4, m2, q2301
+    movd                 m0, r1d
+    paddd                m2, m4
+    psrld                m2, m0
+    pxor                 m0, m0
+    pavgw                m2, m0
+    packssdw             m2, m2
+.dc_loop:
+    mova                 m0, [acq+r5+16*0]
+    mova                 m1, [acq+r5+16*1]
+    psubw                m0, m2
+    psubw                m1, m2
+    mova      [acq+r5+16*0], m0
+    mova      [acq+r5+16*1], m1
+    add                  r5, 16*2
+    jl .dc_loop
+    RET
+
+cglobal ipred_cfl_ac_422_16bpc, 3, 7, 6, ac, ypx, stride, wpad, hpad, w, h
+    movifnidn         hpadd, hpadm
+%if ARCH_X86_32 && PIC
+    pcmpeqw              m5, m5
+    pabsw                m5, m5
+    psllw                m5, 2
+%else
+    movddup              m5, [pw_4]
+%endif
+    mov                  hd, hm
+    shl               hpadd, 2
+    pxor                 m4, m4
+    sub                  hd, hpadd
+    cmp            dword wm, 8
+    mov                  r5, acq
+    jg .w16
+    je .w8
+    lea                  r3, [strideq*3]
+.w4_loop:
+    pmaddwd              m0, m5, [ypxq+strideq*0]
+    pmaddwd              m3, m5, [ypxq+strideq*1]
+    pmaddwd              m1, m5, [ypxq+strideq*2]
+    pmaddwd              m2, m5, [ypxq+r3       ]
+    lea                ypxq, [ypxq+strideq*4]
+    paddd                m4, m0
+    packssdw             m0, m3
+    paddd                m3, m1
+    packssdw             m1, m2
+    paddd                m4, m2
+    paddd                m4, m3
+    mova         [acq+16*0], m0
+    mova         [acq+16*1], m1
+    add                 acq, 16*2
+    sub                  hd, 4
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+    punpckhqdq           m1, m1
+    pslld                m2, 3
+    mova         [acq+16*0], m1
+    mova         [acq+16*1], m1
+    paddd                m4, m2
+    mova         [acq+16*2], m1
+    mova         [acq+16*3], m1
+    add                 acq, 16*4
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+.w8:
+%if ARCH_X86_32
+    cmp         dword wpadm, 0
+%else
+    test              wpadd, wpadd
+%endif
+    jnz .w8_wpad1
+.w8_loop:
+    pmaddwd              m0, m5, [ypxq+strideq*0+16*0]
+    pmaddwd              m2, m5, [ypxq+strideq*0+16*1]
+    pmaddwd              m1, m5, [ypxq+strideq*1+16*0]
+    pmaddwd              m3, m5, [ypxq+strideq*1+16*1]
+    lea                ypxq, [ypxq+strideq*2]
+    paddd                m4, m0
+    packssdw             m0, m2
+    paddd                m4, m2
+    mova         [acq+16*0], m0
+    paddd                m2, m1, m3
+    packssdw             m1, m3
+    paddd                m4, m2
+    mova         [acq+16*1], m1
+    add                 acq, 16*2
+    sub                  hd, 2
+    jg .w8_loop
+.w8_hpad:
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+    pslld                m2, 2
+    mova                 m0, m1
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).hpad
+.w8_wpad1:
+    pmaddwd              m0, m5, [ypxq+strideq*0]
+    pmaddwd              m1, m5, [ypxq+strideq*1]
+    lea                ypxq, [ypxq+strideq*2]
+    pshufd               m2, m0, q3333
+    pshufd               m3, m1, q3333
+    paddd                m4, m0
+    packssdw             m0, m2
+    paddd                m4, m2
+    paddd                m2, m1, m3
+    packssdw             m1, m3
+    paddd                m4, m2
+    mova         [acq+16*0], m0
+    mova         [acq+16*1], m1
+    add                 acq, 16*2
+    sub                  hd, 2
+    jg .w8_wpad1
+    jmp .w8_hpad
+.w16_wpad3:
+    pshufd               m3, m0, q3333
+    mova                 m1, m3
+    mova                 m2, m3
+    jmp .w16_wpad_end
+.w16_wpad2:
+    pshufd               m1, m3, q3333
+    mova                 m2, m1
+    jmp .w16_wpad_end
+.w16_wpad1:
+    pshufd               m2, m1, q3333
+    jmp .w16_wpad_end
+.w16:
+    movifnidn         wpadd, wpadm
+    WIN64_SPILL_XMM       7
+.w16_loop:
+    pmaddwd              m0, m5, [ypxq+16*0]
+    cmp               wpadd, 2
+    jg .w16_wpad3
+    pmaddwd              m3, m5, [ypxq+16*1]
+    je .w16_wpad2
+    pmaddwd              m1, m5, [ypxq+16*2]
+    jp .w16_wpad1
+    pmaddwd              m2, m5, [ypxq+16*3]
+.w16_wpad_end:
+    add                ypxq, strideq
+    paddd                m6, m0, m3
+    packssdw             m0, m3
+    mova         [acq+16*0], m0
+    paddd                m6, m1
+    packssdw             m1, m2
+    paddd                m2, m6
+    mova         [acq+16*1], m1
+    add                 acq, 16*2
+    paddd                m4, m2
+    dec                  hd
+    jg .w16_loop
+    WIN64_RESTORE_XMM
+    add               hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+    paddd                m2, m2
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).hpad
+
+cglobal ipred_cfl_ac_444_16bpc, 3, 7, 6, ac, ypx, stride, wpad, hpad, w, h
+%define base r6-ipred_cfl_ac_444_16bpc_ssse3_table
+    LEA                  r6, ipred_cfl_ac_444_16bpc_ssse3_table
+    tzcnt                wd, wm
+    movifnidn         hpadd, hpadm
+    pxor                 m4, m4
+    movsxd               wq, [r6+wq*4]
+    movddup              m5, [base+pw_1]
+    add                  wq, r6
+    mov                  hd, hm
+    shl               hpadd, 2
+    sub                  hd, hpadd
+    jmp                  wq
+.w4:
+    lea                  r3, [strideq*3]
+    mov                  r5, acq
+.w4_loop:
+    movq                 m0, [ypxq+strideq*0]
+    movhps               m0, [ypxq+strideq*1]
+    movq                 m1, [ypxq+strideq*2]
+    movhps               m1, [ypxq+r3       ]
+    lea                ypxq, [ypxq+strideq*4]
+    psllw                m0, 3
+    psllw                m1, 3
+    mova         [acq+16*0], m0
+    pmaddwd              m0, m5
+    mova         [acq+16*1], m1
+    pmaddwd              m2, m5, m1
+    add                 acq, 16*2
+    paddd                m4, m0
+    paddd                m4, m2
+    sub                  hd, 4
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+    punpckhqdq           m1, m1
+    mova         [acq+16*0], m1
+    pslld                m2, 2
+    mova         [acq+16*1], m1
+    punpckhqdq           m2, m2
+    mova         [acq+16*2], m1
+    paddd                m4, m2
+    mova         [acq+16*3], m1
+    add                 acq, 16*4
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+.w8:
+    mov                  r5, acq
+.w8_loop:
+    mova                 m0, [ypxq+strideq*0]
+    mova                 m1, [ypxq+strideq*1]
+    lea                ypxq, [ypxq+strideq*2]
+    psllw                m0, 3
+    psllw                m1, 3
+    mova         [acq+16*0], m0
+    pmaddwd              m0, m5
+    mova         [acq+16*1], m1
+    pmaddwd              m2, m5, m1
+    add                 acq, 16*2
+    paddd                m4, m0
+    paddd                m4, m2
+    sub                  hd, 2
+    jg .w8_loop
+.w8_hpad:
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+    pslld                m2, 2
+    mova                 m0, m1
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).hpad
+.w16_wpad2:
+    pshufhw              m3, m2, q3333
+    pshufhw              m1, m0, q3333
+    punpckhqdq           m3, m3
+    punpckhqdq           m1, m1
+    jmp .w16_wpad_end
+.w16:
+    movifnidn         wpadd, wpadm
+    mov                  r5, acq
+.w16_loop:
+    mova                 m2, [ypxq+strideq*0+16*0]
+    mova                 m0, [ypxq+strideq*1+16*0]
+    psllw                m2, 3
+    psllw                m0, 3
+    test              wpadd, wpadd
+    jnz .w16_wpad2
+    mova                 m3, [ypxq+strideq*0+16*1]
+    mova                 m1, [ypxq+strideq*1+16*1]
+    psllw                m3, 3
+    psllw                m1, 3
+.w16_wpad_end:
+    lea                ypxq, [ypxq+strideq*2]
+    mova         [acq+16*0], m2
+    pmaddwd              m2, m5
+    mova         [acq+16*1], m3
+    pmaddwd              m3, m5
+    paddd                m4, m2
+    pmaddwd              m2, m5, m0
+    mova         [acq+16*2], m0
+    paddd                m4, m3
+    pmaddwd              m3, m5, m1
+    mova         [acq+16*3], m1
+    add                 acq, 16*4
+    paddd                m2, m3
+    paddd                m4, m2
+    sub                  hd, 2
+    jg .w16_loop
+    add               hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+    paddd                m2, m2
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).hpad
+.w32_wpad6:
+    pshufhw              m1, m0, q3333
+    punpckhqdq           m1, m1
+    mova                 m2, m1
+    mova                 m3, m1
+    jmp .w32_wpad_end
+.w32_wpad4:
+    pshufhw              m2, m1, q3333
+    punpckhqdq           m2, m2
+    mova                 m3, m2
+    jmp .w32_wpad_end
+.w32_wpad2:
+    pshufhw              m3, m2, q3333
+    punpckhqdq           m3, m3
+    jmp .w32_wpad_end
+.w32:
+    movifnidn         wpadd, wpadm
+    mov                  r5, acq
+    WIN64_SPILL_XMM       8
+.w32_loop:
+    mova                 m0, [ypxq+16*0]
+    psllw                m0, 3
+    cmp               wpadd, 4
+    jg .w32_wpad6
+    mova                 m1, [ypxq+16*1]
+    psllw                m1, 3
+    je .w32_wpad4
+    mova                 m2, [ypxq+16*2]
+    psllw                m2, 3
+    jnp .w32_wpad2
+    mova                 m3, [ypxq+16*3]
+    psllw                m3, 3
+.w32_wpad_end:
+    add                ypxq, strideq
+    pmaddwd              m6, m5, m0
+    mova         [acq+16*0], m0
+    pmaddwd              m7, m5, m1
+    mova         [acq+16*1], m1
+    paddd                m6, m7
+    pmaddwd              m7, m5, m2
+    mova         [acq+16*2], m2
+    paddd                m6, m7
+    pmaddwd              m7, m5, m3
+    mova         [acq+16*3], m3
+    add                 acq, 16*4
+    paddd                m6, m7
+    paddd                m4, m6
+    dec                  hd
+    jg .w32_loop
+%if WIN64
+    mova                 m5, m6
+    WIN64_RESTORE_XMM
+    SWAP                  5, 6
+%endif
+    test              hpadd, hpadd
+    jz mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+.w32_hpad_loop:
+    mova         [acq+16*0], m0
+    mova         [acq+16*1], m1
+    paddd                m4, m6
+    mova         [acq+16*2], m2
+    mova         [acq+16*3], m3
+    add                 acq, 16*4
+    dec               hpadd
+    jg .w32_hpad_loop
+    jmp mangle(private_prefix %+ _ipred_cfl_ac_420_16bpc_ssse3).dc
+
+cglobal pal_pred_16bpc, 4, 5, 6, dst, stride, pal, idx, w, h
+%define base r2-pal_pred_16bpc_ssse3_table
+%if ARCH_X86_32
+    %define              hd  r2d
+%endif
+    mova                 m4, [palq]
+    LEA                  r2, pal_pred_16bpc_ssse3_table
+    tzcnt                wd, wm
+    pshufb               m4, [base+pal_pred_shuf]
+    movsxd               wq, [r2+wq*4]
+    pshufd               m5, m4, q1032
+    add                  wq, r2
+    movifnidn            hd, hm
+    jmp                  wq
+.w4:
+    movq                 m0, [idxq]
+    add                idxq, 8
+    psrlw                m1, m0, 4
+    punpcklbw            m0, m1
+    pshufb               m1, m4, m0
+    pshufb               m2, m5, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    movq   [dstq+strideq*0], m1
+    movhps [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    movu                 m3, [idxq]
+    add                idxq, 16
+    psrlw                m1, m3, 4
+    punpcklbw            m0, m3, m1
+    punpckhbw            m3, m1
+    pshufb               m1, m4, m0
+    pshufb               m2, m5, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    pshufb               m1, m4, m3
+    pshufb               m2, m5, m3
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    movu                 m3, [idxq]
+    add                idxq, 16
+    psrlw                m1, m3, 4
+    punpcklbw            m0, m3, m1
+    punpckhbw            m3, m1
+    pshufb               m1, m4, m0
+    pshufb               m2, m5, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova          [dstq+ 0], m0
+    mova          [dstq+16], m1
+    pshufb               m1, m4, m3
+    pshufb               m2, m5, m3
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova  [dstq+strideq+ 0], m0
+    mova  [dstq+strideq+16], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16
+    RET
+.w32:
+    movu                 m3, [idxq]
+    add                idxq, 16
+    psrlw                m1, m3, 4
+    punpcklbw            m0, m3, m1
+    punpckhbw            m3, m1
+    pshufb               m1, m4, m0
+    pshufb               m2, m5, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    pshufb               m1, m4, m3
+    pshufb               m2, m5, m3
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w32
+    RET
+.w64:
+    movu                 m3, [idxq+16*0]
+    psrlw                m1, m3, 4
+    punpcklbw            m0, m3, m1
+    punpckhbw            m3, m1
+    pshufb               m1, m4, m0
+    pshufb               m2, m5, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    pshufb               m1, m4, m3
+    pshufb               m2, m5, m3
+    movu                 m3, [idxq+16*1]
+    add                idxq, 32
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    psrlw                m1, m3, 4
+    punpcklbw            m0, m3, m1
+    punpckhbw            m3, m1
+    pshufb               m1, m4, m0
+    pshufb               m2, m5, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m1
+    pshufb               m1, m4, m3
+    pshufb               m2, m5, m3
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+16*6], m0
+    mova        [dstq+16*7], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w64
+    RET
diff --git a/media/libdav1d/src/src/x86/ipred_avx2.asm b/media/libdav1d/src/src/x86/ipred_avx2.asm
new file mode 100644
index 0000000000..2956ffaf29
--- /dev/null
+++ b/media/libdav1d/src/src/x86/ipred_avx2.asm
@@ -0,0 +1,5362 @@
+; Copyright © 2018-2021, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+%macro SMOOTH_WEIGHT_TABLE 1-*
+    %rep %0
+        db %1-128, 127-%1
+        %rotate 1
+    %endrep
+%endmacro
+
+; sm_weights[], but modified to precalculate x and 256-x with offsets to
+; enable efficient use of pmaddubsw (which requires signed values)
+smooth_weights: SMOOTH_WEIGHT_TABLE         \
+      0,   0, 255, 128, 255, 149,  85,  64, \
+    255, 197, 146, 105,  73,  50,  37,  32, \
+    255, 225, 196, 170, 145, 123, 102,  84, \
+     68,  54,  43,  33,  26,  20,  17,  16, \
+    255, 240, 225, 210, 196, 182, 169, 157, \
+    145, 133, 122, 111, 101,  92,  83,  74, \
+     66,  59,  52,  45,  39,  34,  29,  25, \
+     21,  17,  14,  12,  10,   9,   8,   8, \
+    255, 248, 240, 233, 225, 218, 210, 203, \
+    196, 189, 182, 176, 169, 163, 156, 150, \
+    144, 138, 133, 127, 121, 116, 111, 106, \
+    101,  96,  91,  86,  82,  77,  73,  69, \
+     65,  61,  57,  54,  50,  47,  44,  41, \
+     38,  35,  32,  29,  27,  25,  22,  20, \
+     18,  16,  15,  13,  12,  10,   9,   8, \
+      7,   6,   6,   5,   5,   4,   4,   4
+
+pb_1to32:     db  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16
+              db 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+pb_32to1:     db 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17
+pb_16to1:     db 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1
+z_filter_wh:  db  7,  7, 11, 11, 15, 15, 19, 19, 19, 23, 23, 23, 31, 31, 31, 39
+              db 39, 39, 47, 47, 47, 63, 63, 63, 79, 79, 79, -1
+z_filter_k:   db  0, 16,  0, 16,  0, 20,  0, 20,  8, 16,  8, 16
+              db 32, 16, 32, 16, 24, 20, 24, 20, 16, 16, 16, 16
+              db  0,  0,  0,  0,  0,  0,  0,  0,  8,  0,  8,  0
+const \
+z_filter_s,   db  0,  0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7
+              db  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15
+              db 15, 15, 15, 15, 15, 15, 15, 15 ; should be in one cache line
+pb_128:       times 4 db 128 ; those are just placed here for alignment.
+pb_36_m4:     times 2 db 36, -4
+z3_shuf:      db  8,  7,  7,  6,  6,  5,  5,  4,  4,  3,  3,  2,  2,  1,  1,  0
+z_filter_t0:  db 55,127, 39,127, 39,127,  7, 15, 31,  7, 15, 31,  0,  3, 31,  0
+z_filter_t1:  db 39, 63, 19, 47, 19, 47,  3,  3,  3,  3,  3,  3,  0,  0,  0,  0
+z_upsample1:  db  1,  0,  2,  1,  3,  2,  4,  3,  5,  4,  6,  5,  7,  6,  8,  7
+z_upsample2:  db  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8,  8,  8,  8,  8
+z2_upsample:  db  7,  6, 15, 14,  5,  4, 13, 12,  3,  2, 11, 10,  1,  0,  9,  8
+z1_shuf_w4:   db  0,  1,  1,  2,  2,  3,  3,  4,  8,  9,  9, 10, 10, 11, 11, 12
+z2_shuf_h2:   db  3,  2,  7,  6, 11, 10, 15, 14,  2,  1,  6,  5, 10,  9, 14, 13
+z2_shuf_h4:   db  7,  6, 15, 14,  6,  5, 14, 13,  5,  4, 13, 12,  4,  3, 12, 11
+z3_shuf_w4:   db  4,  3,  3,  2,  2,  1,  1,  0, 12, 11, 11, 10, 10,  9,  9,  8
+z_transpose4: db  0,  4,  8, 12,  1,  5,  9, 13,  2,  6, 10, 14,  3,  7, 11, 15
+z_base_inc:   dw   0*64,   1*64,   2*64,   3*64,   4*64,   5*64,   6*64,   7*64
+              dw  16*64,  17*64,  18*64,  19*64,  20*64,  21*64,  22*64,  23*64
+z2_base_inc:  dw   1*64,   2*64,   3*64,   4*64,   5*64,   6*64,   7*64,   8*64
+              dw   9*64,  10*64,  11*64,  12*64,  13*64,  14*64,  15*64,  16*64
+z2_ymul:      dw  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16
+z2_y_shuf_h4: db 90, 90, 90, 90, 14, 14, 14, 14, 27, 27, 27, 27, 31, 31, 31, 31 ; 2, 6, 3, 7
+              db 32, 32, 32, 32, 12, 12, 12, 12,  1,  0,  1,  0,  5, -1, -1, -1 ; 0, 4, 1, 5
+; vpermd indices in bits 4..6 of filter_shuf1: 0, 2, 6, 4, 1, 3, 7, 5
+filter_shuf1: db 10,  4, 10,  4, 37,  6,  5,  6,103,  9,  7,  9, 72, -1,  8, -1
+              db 16,  4,  0,  4, 53,  6,  5,  6,119, 11,  7, 11, 95, -1, 15, -1
+filter_shuf2: db  3,  4,  3,  4,  5,  6,  5,  6,  7,  2,  7,  2,  1, -1,  1, -1
+filter_shuf3: db  3,  4,  3,  4,  5,  6,  5,  6,  7, 11,  7, 11; 15, -1, 15, -1
+pb_127_m127:  times 2 db 127, -127
+ipred_v_shuf: db  0,  1,  0,  1,  4,  5,  4,  5,  8,  9,  8,  9, 12, 13, 12, 13
+              db  2,  3,  2,  3,  6,  7,  6,  7, 10, 11, 10, 11, 14, 15, 14, 15
+ipred_h_shuf: db  7,  7,  7,  7,  3,  3,  3,  3,  5,  5,  5,  5,  1,  1,  1,  1
+              db  6,  6,  6,  6,  2,  2,  2,  2,  4,  4,  4,  4;  0,  0,  0,  0
+pw_64:        times 2 dw 64
+
+cfl_ac_444_w16_pad1_shuffle: db 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1
+                             times 9 db 7, -1
+cfl_ac_w16_pad_shuffle: ; w=16, w_pad=1
+                        db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+                        ; w=8, w_pad=1 as well as second half of previous one
+cfl_ac_w8_pad1_shuffle: db 0, 1, 2, 3, 4, 5
+                        times 5 db 6, 7
+                        ; w=16,w_pad=2
+                        db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+                        times 8 db 14, 15
+                        ; w=16,w_pad=3
+                        db 0, 1, 2, 3, 4, 5
+                        times 13 db 6, 7
+pb_15to0:               db 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+%define pb_0to15 cfl_ac_w16_pad_shuffle
+%define pb_1  (ipred_h_shuf+12)
+%define pb_2  (ipred_h_shuf+20)
+%define pb_3  (ipred_h_shuf+ 4)
+%define pb_4  (ipred_h_shuf+24)
+%define pb_5  (ipred_h_shuf+ 8)
+%define pb_7  (ipred_h_shuf+ 0)
+%define pb_8  (z_upsample2 +12)
+%define pb_12 (z2_y_shuf_h4+20)
+%define pb_14 (z2_y_shuf_h4+ 4)
+%define pb_15 (z_filter_s  +32)
+%define pb_27 (z2_y_shuf_h4+ 8)
+%define pb_31 (z2_y_shuf_h4+12)
+%define pb_32 (z2_y_shuf_h4+16)
+%define pb_90 (z2_y_shuf_h4+ 0)
+%define pw_1  (z2_y_shuf_h4+24)
+%define pw_8  (z_filter_k  +32)
+
+pw_62:    times 2 dw 62
+pw_128:   times 2 dw 128
+pw_255:   times 2 dw 255
+pw_512:   times 2 dw 512
+
+%macro JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - 2*4)
+    %xdefine %%base mangle(private_prefix %+ _%1_8bpc_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%base %+ .%3 - (%%table - 2*4)
+        %rotate 1
+    %endrep
+%endmacro
+
+%define ipred_dc_splat_avx2_table (ipred_dc_avx2_table + 10*4)
+%define ipred_cfl_splat_avx2_table (ipred_cfl_avx2_table + 8*4)
+
+JMP_TABLE ipred_smooth,     avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_v,   avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_h,   avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_paeth,      avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_filter,     avx2, w4, w8, w16, w32
+JMP_TABLE ipred_dc,         avx2, h4, h8, h16, h32, h64, w4, w8, w16, w32, w64, \
+                                  s4-10*4, s8-10*4, s16-10*4, s32-10*4, s64-10*4
+JMP_TABLE ipred_dc_left,    avx2, h4, h8, h16, h32, h64
+JMP_TABLE ipred_h,          avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z1,         avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z2,         avx2, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z3,         avx2, h4, h8, h16, h32, h64
+JMP_TABLE ipred_cfl,        avx2, h4, h8, h16, h32, w4, w8, w16, w32, \
+                                  s4-8*4, s8-8*4, s16-8*4, s32-8*4
+JMP_TABLE ipred_cfl_left,   avx2, h4, h8, h16, h32
+JMP_TABLE ipred_cfl_ac_420, avx2, w16_pad1, w16_pad2, w16_pad3
+JMP_TABLE ipred_cfl_ac_422, avx2, w16_pad1, w16_pad2, w16_pad3
+JMP_TABLE ipred_cfl_ac_444, avx2, w32_pad1, w32_pad2, w32_pad3, w4, w8, w16, w32
+JMP_TABLE pal_pred,         avx2, w4, w8, w16, w32, w64
+
+cextern dr_intra_derivative
+cextern filter_intra_taps
+
+SECTION .text
+
+INIT_YMM avx2
+cglobal ipred_dc_top_8bpc, 3, 7, 6, dst, stride, tl, w, h
+    lea                  r5, [ipred_dc_left_avx2_table]
+    tzcnt                wd, wm
+    inc                 tlq
+    movu                 m0, [tlq]
+    movifnidn            hd, hm
+    mov                 r6d, 0x8000
+    shrx                r6d, r6d, wd
+    movd                xm3, r6d
+    movsxd               r6, [r5+wq*4]
+    pcmpeqd              m2, m2
+    pmaddubsw            m0, m2
+    add                  r6, r5
+    add                  r5, ipred_dc_splat_avx2_table-ipred_dc_left_avx2_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+
+cglobal ipred_dc_left_8bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    mov                  hd, hm ; zero upper half
+    tzcnt               r6d, hd
+    sub                 tlq, hq
+    tzcnt                wd, wm
+    movu                 m0, [tlq]
+    mov                 r5d, 0x8000
+    shrx                r5d, r5d, r6d
+    movd                xm3, r5d
+    lea                  r5, [ipred_dc_left_avx2_table]
+    movsxd               r6, [r5+r6*4]
+    pcmpeqd              m2, m2
+    pmaddubsw            m0, m2
+    add                  r6, r5
+    add                  r5, ipred_dc_splat_avx2_table-ipred_dc_left_avx2_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+.h64:
+    movu                 m1, [tlq+32] ; unaligned when jumping here from dc_top
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+.h32:
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm1
+.h16:
+    punpckhqdq          xm1, xm0, xm0
+    paddw               xm0, xm1
+.h8:
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+.h4:
+    pmaddwd             xm0, xm2
+    pmulhrsw            xm0, xm3
+    lea            stride3q, [strideq*3]
+    vpbroadcastb         m0, xm0
+    mova                 m1, m0
+    jmp                  wq
+
+cglobal ipred_dc_8bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    movifnidn            hd, hm
+    movifnidn            wd, wm
+    tzcnt               r6d, hd
+    lea                 r5d, [wq+hq]
+    movd                xm4, r5d
+    tzcnt               r5d, r5d
+    movd                xm5, r5d
+    lea                  r5, [ipred_dc_avx2_table]
+    tzcnt                wd, wd
+    movsxd               r6, [r5+r6*4]
+    movsxd               wq, [r5+wq*4+5*4]
+    pcmpeqd              m3, m3
+    psrlw               xm4, 1
+    add                  r6, r5
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  r6
+.h4:
+    movd                xm0, [tlq-4]
+    pmaddubsw           xm0, xm3
+    jmp                  wq
+.w4:
+    movd                xm1, [tlq+1]
+    pmaddubsw           xm1, xm3
+    psubw               xm0, xm4
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    cmp                  hd, 4
+    jg .w4_mul
+    psrlw               xm0, 3
+    jmp .w4_end
+.w4_mul:
+    punpckhqdq          xm1, xm0, xm0
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x55563334
+    paddw               xm0, xm1
+    shrx                r6d, r6d, r2d
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    movd                xm1, r6d
+    psrlw               xm0, 2
+    pmulhuw             xm0, xm1
+.w4_end:
+    vpbroadcastb        xm0, xm0
+.s4:
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm0
+    movd   [dstq+strideq*2], xm0
+    movd   [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s4
+    RET
+ALIGN function_align
+.h8:
+    movq                xm0, [tlq-8]
+    pmaddubsw           xm0, xm3
+    jmp                  wq
+.w8:
+    movq                xm1, [tlq+1]
+    vextracti128        xm2, m0, 1
+    pmaddubsw           xm1, xm3
+    psubw               xm0, xm4
+    paddw               xm0, xm2
+    punpckhqdq          xm2, xm0, xm0
+    paddw               xm0, xm2
+    paddw               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    psrlw               xm0, xm5
+    cmp                  hd, 8
+    je .w8_end
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    cmp                  hd, 32
+    cmove               r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+.w8_end:
+    vpbroadcastb        xm0, xm0
+.s8:
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm0
+    movq   [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s8
+    RET
+ALIGN function_align
+.h16:
+    mova                xm0, [tlq-16]
+    pmaddubsw           xm0, xm3
+    jmp                  wq
+.w16:
+    movu                xm1, [tlq+1]
+    vextracti128        xm2, m0, 1
+    pmaddubsw           xm1, xm3
+    psubw               xm0, xm4
+    paddw               xm0, xm2
+    paddw               xm0, xm1
+    punpckhqdq          xm1, xm0, xm0
+    paddw               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    psrlw               xm0, xm5
+    cmp                  hd, 16
+    je .w16_end
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    test                 hb, 8|32
+    cmovz               r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+.w16_end:
+    vpbroadcastb        xm0, xm0
+.s16:
+    mova   [dstq+strideq*0], xm0
+    mova   [dstq+strideq*1], xm0
+    mova   [dstq+strideq*2], xm0
+    mova   [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s16
+    RET
+ALIGN function_align
+.h32:
+    mova                 m0, [tlq-32]
+    pmaddubsw            m0, m3
+    jmp                  wq
+.w32:
+    movu                 m1, [tlq+1]
+    pmaddubsw            m1, m3
+    paddw                m0, m1
+    vextracti128        xm1, m0, 1
+    psubw               xm0, xm4
+    paddw               xm0, xm1
+    punpckhqdq          xm1, xm0, xm0
+    paddw               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    psrlw               xm0, xm5
+    cmp                  hd, 32
+    je .w32_end
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x33345556
+    shrx                r6d, r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+.w32_end:
+    vpbroadcastb         m0, xm0
+.s32:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m0
+    mova   [dstq+strideq*2], m0
+    mova   [dstq+stride3q ], m0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s32
+    RET
+ALIGN function_align
+.h64:
+    mova                 m0, [tlq-64]
+    mova                 m1, [tlq-32]
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    paddw                m0, m1
+    jmp                  wq
+.w64:
+    movu                 m1, [tlq+ 1]
+    movu                 m2, [tlq+33]
+    pmaddubsw            m1, m3
+    pmaddubsw            m2, m3
+    paddw                m0, m1
+    paddw                m0, m2
+    vextracti128        xm1, m0, 1
+    psubw               xm0, xm4
+    paddw               xm0, xm1
+    punpckhqdq          xm1, xm0, xm0
+    paddw               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    psrlw               xm0, xm5
+    cmp                  hd, 64
+    je .w64_end
+    mov                 r6d, 0x33345556
+    shrx                r6d, r6d, hd
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+.w64_end:
+    vpbroadcastb         m0, xm0
+    mova                 m1, m0
+.s64:
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*1+32*0], m0
+    mova [dstq+strideq*1+32*1], m1
+    mova [dstq+strideq*2+32*0], m0
+    mova [dstq+strideq*2+32*1], m1
+    mova [dstq+stride3q +32*0], m0
+    mova [dstq+stride3q +32*1], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s64
+    RET
+
+cglobal ipred_dc_128_8bpc, 2, 7, 6, dst, stride, tl, w, h, stride3
+    lea                  r5, [ipred_dc_splat_avx2_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    vpbroadcastd         m0, [r5-ipred_dc_splat_avx2_table+pb_128]
+    mova                 m1, m0
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+cglobal ipred_v_8bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    lea                  r5, [ipred_dc_splat_avx2_table]
+    tzcnt                wd, wm
+    movu                 m0, [tlq+ 1]
+    movu                 m1, [tlq+33]
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+%macro IPRED_H 2 ; w, store_type
+    vpbroadcastb         m0, [tlq-1]
+    vpbroadcastb         m1, [tlq-2]
+    vpbroadcastb         m2, [tlq-3]
+    sub                 tlq, 4
+    vpbroadcastb         m3, [tlq+0]
+    mov%2  [dstq+strideq*0], m0
+    mov%2  [dstq+strideq*1], m1
+    mov%2  [dstq+strideq*2], m2
+    mov%2  [dstq+stride3q ], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w%1
+    RET
+ALIGN function_align
+%endmacro
+
+INIT_XMM avx2
+cglobal ipred_h_8bpc, 3, 6, 4, dst, stride, tl, w, h, stride3
+    lea                  r5, [ipred_h_avx2_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    IPRED_H               4, d
+.w8:
+    IPRED_H               8, q
+.w16:
+    IPRED_H              16, a
+INIT_YMM avx2
+.w32:
+    IPRED_H              32, a
+.w64:
+    vpbroadcastb         m0, [tlq-1]
+    vpbroadcastb         m1, [tlq-2]
+    vpbroadcastb         m2, [tlq-3]
+    sub                 tlq, 4
+    vpbroadcastb         m3, [tlq+0]
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m0
+    mova [dstq+strideq*1+32*0], m1
+    mova [dstq+strideq*1+32*1], m1
+    mova [dstq+strideq*2+32*0], m2
+    mova [dstq+strideq*2+32*1], m2
+    mova [dstq+stride3q +32*0], m3
+    mova [dstq+stride3q +32*1], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w64
+    RET
+
+%macro PAETH 2 ; top, ldiff
+    pavgb                m1, m%1, m3 ; Calculating tldiff normally requires
+    pxor                 m0, m%1, m3 ; 10-bit intermediates, but we can do it
+    pand                 m0, m4      ; in 8-bit with some tricks which avoids
+    psubusb              m2, m5, m1  ; having to unpack everything to 16-bit.
+    psubb                m1, m0
+    psubusb              m1, m5
+    por                  m1, m2
+    paddusb              m1, m1
+    por                  m1, m0      ; min(tldiff, 255)
+    psubusb              m2, m5, m3
+    psubusb              m0, m3, m5
+    por                  m2, m0      ; tdiff
+    pminub               m2, m%2
+    pcmpeqb              m0, m%2, m2 ; ldiff <= tdiff
+    vpblendvb            m0, m%1, m3, m0
+    pminub               m1, m2
+    pcmpeqb              m1, m2      ; ldiff <= tldiff || tdiff <= tldiff
+    vpblendvb            m0, m5, m0, m1
+%endmacro
+
+cglobal ipred_paeth_8bpc, 3, 6, 9, dst, stride, tl, w, h
+%define base r5-ipred_paeth_avx2_table
+    lea                  r5, [ipred_paeth_avx2_table]
+    tzcnt                wd, wm
+    vpbroadcastb         m5, [tlq]   ; topleft
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    vpbroadcastd         m4, [base+pb_1]
+    add                  wq, r5
+    jmp                  wq
+.w4:
+    vpbroadcastd         m6, [tlq+1] ; top
+    mova                 m8, [base+ipred_h_shuf]
+    lea                  r3, [strideq*3]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0      ; ldiff
+.w4_loop:
+    sub                 tlq, 8
+    vpbroadcastq         m3, [tlq]
+    pshufb               m3, m8      ; left
+    PAETH                 6, 7
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r3       ], xm1, 2
+    cmp                  hd, 4
+    je .ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm0, 3
+    pextrd [dstq+r3       ], xm1, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 8
+    jg .w4_loop
+.ret:
+    RET
+ALIGN function_align
+.w8:
+    vpbroadcastq         m6, [tlq+1]
+    mova                 m8, [base+ipred_h_shuf]
+    lea                  r3, [strideq*3]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w8_loop:
+    sub                 tlq, 4
+    vpbroadcastd         m3, [tlq]
+    pshufb               m3, m8
+    PAETH                 6, 7
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r3       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    vbroadcasti128       m6, [tlq+1]
+    mova                xm8, xm4 ; lower half = 1, upper half = 0
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w16_loop:
+    sub                 tlq, 2
+    vpbroadcastd         m3, [tlq]
+    pshufb               m3, m8
+    PAETH                 6, 7
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    movu                 m6, [tlq+1]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w32_loop:
+    dec                 tlq
+    vpbroadcastb         m3, [tlq]
+    PAETH                 6, 7
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w32_loop
+    RET
+ALIGN function_align
+.w64:
+    movu                 m6, [tlq+ 1]
+    movu                 m7, [tlq+33]
+%if WIN64
+    movaps              r4m, xmm9
+%endif
+    psubusb              m8, m5, m6
+    psubusb              m0, m6, m5
+    psubusb              m9, m5, m7
+    psubusb              m1, m7, m5
+    por                  m8, m0
+    por                  m9, m1
+.w64_loop:
+    dec                 tlq
+    vpbroadcastb         m3, [tlq]
+    PAETH                 6, 8
+    mova        [dstq+32*0], m0
+    PAETH                 7, 9
+    mova        [dstq+32*1], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+%if WIN64
+    movaps             xmm9, r4m
+%endif
+    RET
+
+%macro SMOOTH 6 ; src[1-2], mul[1-2], add[1-2]
+    ; w * a         = (w - 128) * a + 128 * a
+    ; (256 - w) * b = (127 - w) * b + 129 * b
+    pmaddubsw            m0, m%3, m%1
+    pmaddubsw            m1, m%4, m%2
+    paddw                m0, m%5
+    paddw                m1, m%6
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+%endmacro
+
+cglobal ipred_smooth_v_8bpc, 3, 7, 0, dst, stride, tl, w, h, weights
+%define base r6-ipred_smooth_v_avx2_table
+    lea                  r6, [ipred_smooth_v_avx2_table]
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastd         m0, [base+pb_127_m127]
+    vpbroadcastd         m1, [base+pw_128]
+    lea            weightsq, [base+smooth_weights+hq*4]
+    neg                  hq
+    vpbroadcastb         m5, [tlq+hq] ; bottom
+    add                  wq, r6
+    jmp                  wq
+.w4:
+    vpbroadcastd         m2, [tlq+1]
+    punpcklbw            m2, m5 ; top, bottom
+    mova                 m5, [base+ipred_v_shuf]
+    lea                  r3, [strideq*3]
+    punpckldq            m4, m5, m5
+    punpckhdq            m5, m5
+    pmaddubsw            m3, m2, m0
+    paddw                m1, m2 ;   1 * top + 256 * bottom + 128, overflow is ok
+    paddw                m3, m1 ; 128 * top + 129 * bottom + 128
+.w4_loop:
+    vbroadcasti128       m1, [weightsq+hq*2]
+    pshufb               m0, m1, m4
+    pshufb               m1, m5
+    SMOOTH                0, 1, 2, 2, 3, 3
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm1
+    pextrd [dstq+strideq*2], xm0, 1
+    pextrd [dstq+r3       ], xm1, 1
+    cmp                  hd, -4
+    je .ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm1, 2
+    pextrd [dstq+strideq*2], xm0, 3
+    pextrd [dstq+r3       ], xm1, 3
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 8
+    jl .w4_loop
+.ret:
+    RET
+ALIGN function_align
+.w8:
+    vpbroadcastq         m2, [tlq+1]
+    punpcklbw            m2, m5
+    mova                 m5, [base+ipred_v_shuf]
+    lea                  r3, [strideq*3]
+    pshufd               m4, m5, q0000
+    pshufd               m5, m5, q1111
+    pmaddubsw            m3, m2, m0
+    paddw                m1, m2
+    paddw                m3, m1
+.w8_loop:
+    vpbroadcastq         m1, [weightsq+hq*2]
+    pshufb               m0, m1, m4
+    pshufb               m1, m5
+    SMOOTH                0, 1, 2, 2, 3, 3
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r3       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    WIN64_SPILL_XMM       7
+    vbroadcasti128       m3, [tlq+1]
+    mova                 m6, [base+ipred_v_shuf]
+    punpcklbw            m2, m3, m5
+    punpckhbw            m3, m5
+    pmaddubsw            m4, m2, m0
+    pmaddubsw            m5, m3, m0
+    paddw                m0, m1, m2
+    paddw                m1, m3
+    paddw                m4, m0
+    paddw                m5, m1
+.w16_loop:
+    vpbroadcastd         m1, [weightsq+hq*2]
+    pshufb               m1, m6
+    SMOOTH                1, 1, 2, 3, 4, 5
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    add                  hq, 2
+    jl .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    WIN64_SPILL_XMM       6
+    movu                 m3, [tlq+1]
+    punpcklbw            m2, m3, m5
+    punpckhbw            m3, m5
+    pmaddubsw            m4, m2, m0
+    pmaddubsw            m5, m3, m0
+    paddw                m0, m1, m2
+    paddw                m1, m3
+    paddw                m4, m0
+    paddw                m5, m1
+.w32_loop:
+    vpbroadcastw         m1, [weightsq+hq*2]
+    SMOOTH                1, 1, 2, 3, 4, 5
+    mova             [dstq], m0
+    add                dstq, strideq
+    inc                  hq
+    jl .w32_loop
+    RET
+ALIGN function_align
+.w64:
+    WIN64_SPILL_XMM      11
+    movu                 m4, [tlq+ 1]
+    movu                 m8, [tlq+33]
+    punpcklbw            m3, m4, m5
+    punpckhbw            m4, m5
+    punpcklbw            m7, m8, m5
+    punpckhbw            m8, m5
+    pmaddubsw            m5, m3, m0
+    pmaddubsw            m6, m4, m0
+    pmaddubsw            m9, m7, m0
+    pmaddubsw           m10, m8, m0
+    paddw                m2, m1, m3
+    paddw                m5, m2
+    paddw                m2, m1, m4
+    paddw                m6, m2
+    paddw                m0, m1, m7
+    paddw                m9, m0
+    paddw                m1, m8
+    paddw               m10, m1
+.w64_loop:
+    vpbroadcastw         m2, [weightsq+hq*2]
+    SMOOTH                2, 2, 3, 4, 5, 6
+    mova        [dstq+32*0], m0
+    SMOOTH                2, 2, 7, 8, 9, 10
+    mova        [dstq+32*1], m0
+    add                dstq, strideq
+    inc                  hq
+    jl .w64_loop
+    RET
+
+cglobal ipred_smooth_h_8bpc, 3, 7, 0, dst, stride, tl, w, h
+%define base r5-ipred_smooth_h_avx2_table
+    lea                  r5, [ipred_smooth_h_avx2_table]
+    mov                  wd, wm
+    vpbroadcastb         m3, [tlq+wq] ; right
+    tzcnt                wd, wd
+    mov                  hd, hm
+    movsxd               wq, [r5+wq*4]
+    vpbroadcastd         m4, [base+pb_127_m127]
+    vpbroadcastd         m5, [base+pw_128]
+    add                  wq, r5
+    jmp                  wq
+.w4:
+    WIN64_SPILL_XMM       8
+    vpbroadcastq         m6, [base+smooth_weights+4*2]
+    mova                 m7, [base+ipred_h_shuf]
+    sub                 tlq, 8
+    sub                 tlq, hq
+    lea                  r3, [strideq*3]
+.w4_loop:
+    vpbroadcastq         m2, [tlq+hq]
+    pshufb               m2, m7
+    punpcklbw            m1, m2, m3 ; left, right
+    punpckhbw            m2, m3
+    pmaddubsw            m0, m1, m4 ; 127 * left - 127 * right
+    paddw                m0, m1     ; 128 * left + 129 * right
+    pmaddubsw            m1, m6
+    paddw                m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m4
+    paddw                m1, m2
+    pmaddubsw            m2, m6
+    paddw                m2, m5
+    paddw                m1, m2
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r3       ], xm1, 2
+    cmp                  hd, 4
+    je .ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm0, 3
+    pextrd [dstq+r3       ], xm1, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 8
+    jg .w4_loop
+.ret:
+    RET
+ALIGN function_align
+.w8:
+    WIN64_SPILL_XMM       8
+    vbroadcasti128       m6, [base+smooth_weights+8*2]
+    mova                 m7, [base+ipred_h_shuf]
+    sub                 tlq, 4
+    lea                  r3, [strideq*3]
+    sub                 tlq, hq
+.w8_loop:
+    vpbroadcastd         m2, [tlq+hq]
+    pshufb               m2, m7
+    punpcklbw            m1, m2, m3
+    punpckhbw            m2, m3
+    pmaddubsw            m0, m1, m4
+    paddw                m0, m1
+    pmaddubsw            m1, m6
+    paddw                m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m4
+    paddw                m1, m2
+    pmaddubsw            m2, m6
+    paddw                m2, m5
+    paddw                m1, m2
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r3       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    ALLOC_STACK        32*4, 8
+    lea                  r3, [rsp+64*2-4]
+    call .prep ; only worthwhile for for w16 and above
+    sub                 tlq, 2
+    vpbroadcastd        xm6, [base+pb_1]
+    mova                xm7, [base+ipred_v_shuf+16]
+    vinserti128          m7, [base+ipred_v_shuf+ 0], 1
+    vbroadcasti128       m4, [base+smooth_weights+16*2]
+    vbroadcasti128       m5, [base+smooth_weights+16*3]
+.w16_loop:
+    vpbroadcastd         m1, [tlq+hq]
+    vpbroadcastd         m2, [r3+hq*2]
+    pshufb               m1, m6
+    punpcklbw            m1, m3
+    pshufb               m2, m7
+    SMOOTH                4, 5, 1, 1, 2, 2
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    ALLOC_STACK        32*4
+    lea                  r3, [rsp+64*2-2]
+    call .prep
+    dec                 tlq
+    mova                xm4, [base+smooth_weights+16*4]
+    vinserti128          m4, [base+smooth_weights+16*6], 1
+    mova                xm5, [base+smooth_weights+16*5]
+    vinserti128          m5, [base+smooth_weights+16*7], 1
+.w32_loop:
+    vpbroadcastb         m1, [tlq+hq]
+    punpcklbw            m1, m3
+    vpbroadcastw         m2, [r3+hq*2]
+    SMOOTH                4, 5, 1, 1, 2, 2
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w32_loop
+    RET
+ALIGN function_align
+.w64:
+    ALLOC_STACK        32*4, 9
+    lea                  r3, [rsp+64*2-2]
+    call .prep
+    add                  r5, smooth_weights+16*15-ipred_smooth_h_avx2_table
+    dec                 tlq
+    mova                xm5, [r5-16*7]
+    vinserti128          m5, [r5-16*5], 1
+    mova                xm6, [r5-16*6]
+    vinserti128          m6, [r5-16*4], 1
+    mova                xm7, [r5-16*3]
+    vinserti128          m7, [r5-16*1], 1
+    mova                xm8, [r5-16*2]
+    vinserti128          m8, [r5-16*0], 1
+.w64_loop:
+    vpbroadcastb         m2, [tlq+hq]
+    punpcklbw            m2, m3
+    vpbroadcastw         m4, [r3+hq*2]
+    SMOOTH                5, 6, 2, 2, 4, 4
+    mova        [dstq+32*0], m0
+    SMOOTH                7, 8, 2, 2, 4, 4
+    mova        [dstq+32*1], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+ALIGN function_align
+.prep:
+    vpermq               m2, [tlq-32*1], q3120
+    punpckhbw            m1, m2, m3
+    punpcklbw            m2, m3
+    pmaddubsw            m0, m1, m4 ; 127 * left - 127 * right
+    paddw                m1, m5     ;   1 * left + 256 * right + 128
+    paddw                m0, m1     ; 128 * left + 129 * right + 128
+    pmaddubsw            m1, m2, m4
+    paddw                m2, m5
+    paddw                m1, m2
+    vpermq               m2, [tlq-32*2], q3120
+    mova [rsp+gprsize+32*3], m0
+    mova [rsp+gprsize+32*2], m1
+    punpckhbw            m1, m2, m3
+    punpcklbw            m2, m3
+    pmaddubsw            m0, m1, m4
+    paddw                m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m4
+    paddw                m2, m5
+    paddw                m1, m2
+    mova [rsp+gprsize+32*1], m0
+    mova [rsp+gprsize+32*0], m1
+    sub                  r3, hq
+    sub                 tlq, hq
+    sub                  r3, hq
+    ret
+
+%macro SMOOTH_2D_END 6 ; src[1-2], mul[1-2], add[1-2]
+    pmaddubsw            m0, m%3, m%1
+    pmaddubsw            m1, m%4, m%2
+%ifnum %5
+    paddw                m0, m%5
+%else
+    paddw                m0, %5
+%endif
+%ifnum %6
+    paddw                m1, m%6
+%else
+    paddw                m1, %6
+%endif
+    pavgw                m0, m2
+    pavgw                m1, m3
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+%endmacro
+
+cglobal ipred_smooth_8bpc, 3, 7, 0, dst, stride, tl, w, h, v_weights
+%define base r6-ipred_smooth_avx2_table
+    lea                  r6, [ipred_smooth_avx2_table]
+    mov                  wd, wm
+    vpbroadcastb         m4, [tlq+wq] ; right
+    tzcnt                wd, wd
+    mov                  hd, hm
+    mov                  r5, tlq
+    sub                  r5, hq
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastd         m5, [base+pb_127_m127]
+    vpbroadcastb         m0, [r5] ; bottom
+    vpbroadcastd         m3, [base+pw_255]
+    add                  wq, r6
+    lea          v_weightsq, [base+smooth_weights+hq*2]
+    jmp                  wq
+.w4:
+    WIN64_SPILL_XMM      12
+    mova                m10, [base+ipred_h_shuf]
+    vpbroadcastq        m11, [base+smooth_weights+4*2]
+    mova                 m7, [base+ipred_v_shuf]
+    vpbroadcastd         m8, [tlq+1]
+    sub                 tlq, 8
+    lea                  r3, [strideq*3]
+    sub                 tlq, hq
+    punpcklbw            m8, m0 ; top, bottom
+    pshufd               m6, m7, q2200
+    pshufd               m7, m7, q3311
+    pmaddubsw            m9, m8, m5
+    paddw                m3, m8 ;   1 * top + 255 * bottom + 255
+    paddw                m9, m3 ; 128 * top + 129 * bottom + 255
+.w4_loop:
+    vpbroadcastq         m1, [tlq+hq]
+    pshufb               m1, m10
+    punpcklbw            m0, m1, m4 ; left, right
+    punpckhbw            m1, m4
+    pmaddubsw            m2, m0, m5 ; 127 * left - 127 * right
+    pmaddubsw            m3, m1, m5
+    paddw                m2, m0     ; 128 * left + 129 * right
+    paddw                m3, m1
+    pmaddubsw            m0, m11
+    pmaddubsw            m1, m11
+    paddw                m2, m0
+    paddw                m3, m1
+    vbroadcasti128       m1, [v_weightsq]
+    add          v_weightsq, 16
+    pshufb               m0, m1, m6
+    pshufb               m1, m7
+    SMOOTH_2D_END         0, 1, 8, 8, 9, 9
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r3       ], xm1, 2
+    cmp                  hd, 4
+    je .ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm0, 3
+    pextrd [dstq+r3       ], xm1, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 8
+    jg .w4_loop
+.ret:
+    RET
+ALIGN function_align
+.w8:
+    WIN64_SPILL_XMM      12
+    mova                m10, [base+ipred_h_shuf]
+    vbroadcasti128      m11, [base+smooth_weights+8*2]
+    mova                 m7, [base+ipred_v_shuf]
+    vpbroadcastq         m8, [tlq+1]
+    sub                 tlq, 4
+    lea                  r3, [strideq*3]
+    sub                 tlq, hq
+    punpcklbw            m8, m0
+    pshufd               m6, m7, q0000
+    pshufd               m7, m7, q1111
+    pmaddubsw            m9, m8, m5
+    paddw                m3, m8
+    paddw                m9, m3
+.w8_loop:
+    vpbroadcastd         m1, [tlq+hq]
+    pshufb               m1, m10
+    punpcklbw            m0, m1, m4
+    punpckhbw            m1, m4
+    pmaddubsw            m2, m0, m5
+    pmaddubsw            m3, m1, m5
+    paddw                m2, m0
+    paddw                m3, m1
+    pmaddubsw            m0, m11
+    pmaddubsw            m1, m11
+    paddw                m2, m0
+    paddw                m3, m1
+    vpbroadcastq         m1, [v_weightsq]
+    add          v_weightsq, 8
+    pshufb               m0, m1, m6
+    pshufb               m1, m7
+    SMOOTH_2D_END         0, 1, 8, 8, 9, 9
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+r3       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    %assign regs_used 4
+    ALLOC_STACK       -32*4, 14
+    %assign regs_used 7
+    vbroadcasti128      m11, [tlq+1]
+    lea                  r3, [rsp+64*2-4]
+    punpcklbw           m10, m11, m0 ; top, bottom
+    punpckhbw           m11, m0
+    call .prep_v
+    sub                 tlq, 2
+    pmaddubsw           m12, m10, m5
+    pmaddubsw           m13, m11, m5
+    vpbroadcastd        xm5, [base+pb_1]
+    mova                 m9, [base+ipred_v_shuf]
+    vbroadcasti128       m6, [base+smooth_weights+16*2]
+    vbroadcasti128       m7, [base+smooth_weights+16*3]
+    vperm2i128           m8, m9, m9, 0x01
+    paddw                m0, m10, m3
+    paddw                m3, m11
+    paddw               m12, m0
+    paddw               m13, m3
+.w16_loop:
+    vpbroadcastd         m3, [tlq+hq]
+    vpbroadcastd         m0, [r3+hq*2]
+    vpbroadcastd         m1, [v_weightsq]
+    add          v_weightsq, 4
+    pshufb               m3, m5
+    punpcklbw            m3, m4 ; left, right
+    pmaddubsw            m2, m3, m6
+    pmaddubsw            m3, m7
+    pshufb               m0, m8
+    pshufb               m1, m9
+    paddw                m2, m0
+    paddw                m3, m0
+    SMOOTH_2D_END         1, 1, 10, 11, 12, 13
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    %assign regs_used 4
+    ALLOC_STACK       -32*4, 11
+    %assign regs_used 7
+    movu                 m8, [tlq+1]
+    lea                  r3, [rsp+64*2-2]
+    punpcklbw            m7, m8, m0
+    punpckhbw            m8, m0
+    call .prep_v
+    dec                 tlq
+    pmaddubsw            m9, m7, m5
+    pmaddubsw           m10, m8, m5
+    mova                xm5, [base+smooth_weights+16*4]
+    vinserti128          m5, [base+smooth_weights+16*6], 1
+    mova                xm6, [base+smooth_weights+16*5]
+    vinserti128          m6, [base+smooth_weights+16*7], 1
+    paddw                m0, m7, m3
+    paddw                m3, m8
+    paddw                m9, m0
+    paddw               m10, m3
+.w32_loop:
+    vpbroadcastb         m3, [tlq+hq]
+    punpcklbw            m3, m4
+    vpbroadcastw         m0, [r3+hq*2]
+    vpbroadcastw         m1, [v_weightsq]
+    add          v_weightsq, 2
+    pmaddubsw            m2, m3, m5
+    pmaddubsw            m3, m6
+    paddw                m2, m0
+    paddw                m3, m0
+    SMOOTH_2D_END         1, 1, 7, 8, 9, 10
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w32_loop
+    RET
+ALIGN function_align
+.w64:
+    %assign regs_used 4
+    ALLOC_STACK       -32*8, 16
+    %assign regs_used 7
+    movu                m13, [tlq+1 ]
+    movu                m15, [tlq+33]
+    add                  r6, smooth_weights+16*15-ipred_smooth_avx2_table
+    lea                  r3, [rsp+64*2-2]
+    punpcklbw           m12, m13, m0
+    punpckhbw           m13, m0
+    punpcklbw           m14, m15, m0
+    punpckhbw           m15, m0
+    call .prep_v
+    dec                 tlq
+    pmaddubsw            m0, m12, m5
+    pmaddubsw            m1, m13, m5
+    pmaddubsw            m2, m14, m5
+    pmaddubsw            m5, m15, m5
+    mova                xm8, [r6-16*7]
+    vinserti128          m8, [r6-16*5], 1
+    mova                xm9, [r6-16*6]
+    vinserti128          m9, [r6-16*4], 1
+    mova               xm10, [r6-16*3]
+    vinserti128         m10, [r6-16*1], 1
+    mova               xm11, [r6-16*2]
+    vinserti128         m11, [r6-16*0], 1
+    lea                  r6, [rsp+32*4]
+    paddw                m0, m3
+    paddw                m1, m3
+    paddw                m2, m3
+    paddw                m3, m5
+    paddw                m0, m12
+    paddw                m1, m13
+    paddw                m2, m14
+    paddw                m3, m15
+    mova          [r6+32*0], m0
+    mova          [r6+32*1], m1
+    mova          [r6+32*2], m2
+    mova          [r6+32*3], m3
+.w64_loop:
+    vpbroadcastb         m5, [tlq+hq]
+    punpcklbw            m5, m4
+    vpbroadcastw         m6, [r3+hq*2]
+    vpbroadcastw         m7, [v_weightsq]
+    add          v_weightsq, 2
+    pmaddubsw            m2, m5, m8
+    pmaddubsw            m3, m5, m9
+    paddw                m2, m6
+    paddw                m3, m6
+    SMOOTH_2D_END         7, 7, 12, 13, [r6+32*0], [r6+32*1]
+    mova        [dstq+32*0], m0
+    pmaddubsw            m2, m5, m10
+    pmaddubsw            m3, m5, m11
+    paddw                m2, m6
+    paddw                m3, m6
+    SMOOTH_2D_END         7, 7, 14, 15, [r6+32*2], [r6+32*3]
+    mova        [dstq+32*1], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+ALIGN function_align
+.prep_v:
+    vpermq               m2, [tlq-32*1], q3120
+    punpckhbw            m1, m2, m4
+    punpcklbw            m2, m4
+    pmaddubsw            m0, m1, m5 ; 127 * left - 127 * right
+    paddw                m0, m1     ; 128 * left + 129 * right
+    pmaddubsw            m1, m2, m5
+    paddw                m1, m2
+    vpermq               m2, [tlq-32*2], q3120
+    mova [rsp+gprsize+32*3], m0
+    mova [rsp+gprsize+32*2], m1
+    punpckhbw            m1, m2, m4
+    punpcklbw            m2, m4
+    pmaddubsw            m0, m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m5
+    paddw                m1, m2
+    mova [rsp+gprsize+32*1], m0
+    mova [rsp+gprsize+32*0], m1
+    sub                  r3, hq
+    sub                 tlq, hq
+    sub                  r3, hq
+    ret
+
+cglobal ipred_z1_8bpc, 3, 8, 0, dst, stride, tl, w, h, angle, dx, maxbase
+    lea                  r6, [ipred_z1_avx2_table]
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    movifnidn            hd, hm
+    lea                  r7, [dr_intra_derivative]
+    inc                 tlq
+    movsxd               wq, [r6+wq*4]
+    add                  wq, r6
+    mov                 dxd, angled
+    and                 dxd, 0x7e
+    add              angled, 165 ; ~90
+    movzx               dxd, word [r7+dxq]
+    xor              angled, 0x4ff ; d = 90 - angle
+    vpbroadcastd         m3, [pw_512]
+    vpbroadcastd         m4, [pw_62]
+    vpbroadcastd         m5, [pw_64]
+    jmp                  wq
+.w4:
+    cmp              angleb, 40
+    jae .w4_no_upsample
+    lea                 r3d, [angleq-1024]
+    sar                 r3d, 7
+    add                 r3d, hd
+    jg .w4_no_upsample ; !enable_intra_edge_filter || h > 8 || (h == 8 && is_sm)
+    ALLOC_STACK         -32, 8
+    mova                xm1, [tlq-1]
+    pshufb              xm0, xm1, [z_upsample1]
+    pshufb              xm1, [z_upsample2]
+    vpbroadcastd        xm2, [pb_36_m4] ; upshifted by 2 to be able to reuse
+    add                 dxd, dxd        ; pw_512 (which is already in m3)
+    pmaddubsw           xm0, xm2        ; for rounding instead of pw_2048
+    pextrd         [rsp+16], xm1, 3 ; top[max_base_x]
+    pmaddubsw           xm1, xm2
+    movd                xm7, dxd
+    mov                 r3d, dxd ; xpos
+    vpbroadcastw         m7, xm7
+    paddw               xm1, xm0
+    movq                xm0, [tlq]
+    pmulhrsw            xm1, xm3
+    pslldq               m6, m7, 8
+    paddw               xm2, xm7, xm7
+    lea                  r2, [strideq*3]
+    paddw                m6, m7
+    packuswb            xm1, xm1
+    paddw                m6, m2 ; xpos2 xpos3 xpos0 xpos1
+    punpcklbw           xm0, xm1
+    psllw                m7, 2
+    mova              [rsp], xm0
+.w4_upsample_loop:
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base0
+    vpbroadcastq         m1, [rsp+r3]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base1
+    vpbroadcastq         m2, [rsp+r5]
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base2
+    movq                xm0, [rsp+r3]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base3
+    movhps              xm0, [rsp+r5]
+    vpblendd             m1, m2, 0xc0
+    pand                 m2, m4, m6 ; frac
+    vpblendd             m0, m1, 0xf0
+    psubw                m1, m5, m2 ; 64-frac
+    psllw                m2, 8
+    por                  m1, m2     ; 64-frac, frac
+    pmaddubsw            m0, m1
+    paddw                m6, m7     ; xpos += dx
+    pmulhrsw             m0, m3
+    packuswb             m0, m0
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*2], xm0
+    pextrd [dstq+r2       ], xm0, 1
+    movd   [dstq+strideq*0], xm1
+    pextrd [dstq+strideq*1], xm1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_upsample_loop
+    RET
+ALIGN function_align
+.filter_strength: ; w4/w8/w16
+    ; The C version uses a lot of branches, but we can do all the comparisons
+    ; in parallel and use popcnt to get the final filter strength value.
+%define base r3-z_filter_t0
+    lea                  r3, [z_filter_t0]
+    movd                xm0, maxbased
+    movd                xm2, angled
+    shr              angled, 8 ; is_sm << 1
+    vpbroadcastb         m0, xm0
+    vpbroadcastb         m2, xm2
+    pcmpeqb              m1, m0, [base+z_filter_wh]
+    pand                 m1, m2
+    mova                xm2, [r3+angleq*8] ; upper ymm half zero in both cases
+    pcmpgtb              m1, m2
+    pmovmskb            r5d, m1
+    ret
+.w4_no_upsample:
+    ALLOC_STACK         -16, 11
+    mov            maxbased, 7
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w4_main
+    lea            maxbased, [hq+3]
+    call .filter_strength
+    mov            maxbased, 7
+    test                r5d, r5d
+    jz .w4_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    vpbroadcastd         m7, [base+pb_8]
+    vbroadcasti128       m2, [tlq-1]
+    pminub               m1, m7, [base+z_filter_s]
+    vpbroadcastd         m8, [base+z_filter_k-4+r5*4+12*0]
+    pminub               m7, [base+z_filter_s+8]
+    vpbroadcastd         m9, [base+z_filter_k-4+r5*4+12*1]
+    vpbroadcastd        m10, [base+z_filter_k-4+r5*4+12*2]
+    pshufb               m0, m2, m1
+    shufps               m1, m7, q2121
+    pmaddubsw            m0, m8
+    pshufb               m1, m2, m1
+    pmaddubsw            m1, m9
+    pshufb               m2, m7
+    pmaddubsw            m2, m10
+    paddw                m0, m1
+    paddw                m0, m2
+    pmulhrsw             m0, m3
+    mov                 r3d, 9
+    mov                 tlq, rsp
+    cmp                  hd, 4
+    cmovne         maxbased, r3d
+    vextracti128        xm1, m0, 1
+    packuswb            xm0, xm1
+    mova              [tlq], xm0
+.w4_main:
+    movd                xm6, dxd
+    vpbroadcastq         m0, [z_base_inc] ; base_inc << 6
+    vpbroadcastb         m7, [tlq+maxbaseq]
+    shl            maxbased, 6
+    vpbroadcastw         m6, xm6
+    mov                 r3d, dxd ; xpos
+    movd                xm9, maxbased
+    vpbroadcastw         m9, xm9
+    vbroadcasti128       m8, [z1_shuf_w4]
+    psrlw                m7, 8  ; top[max_base_x]
+    paddw               m10, m6, m6
+    psubw                m9, m0 ; max_base_x
+    vpblendd             m6, m10, 0xcc
+    mova                xm0, xm10
+    paddw                m6, m0 ; xpos2 xpos3 xpos0 xpos1
+    paddw               m10, m10
+.w4_loop:
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base0
+    vpbroadcastq         m1, [tlq+r3]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base1
+    vpbroadcastq         m2, [tlq+r5]
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base2
+    movq                xm0, [tlq+r3]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base3
+    movhps              xm0, [tlq+r5]
+    vpblendd             m1, m2, 0xc0
+    pand                 m2, m4, m6 ; frac
+    vpblendd             m0, m1, 0xf0
+    psubw                m1, m5, m2 ; 64-frac
+    psllw                m2, 8
+    pshufb               m0, m8
+    por                  m1, m2     ; 64-frac, frac
+    pmaddubsw            m0, m1
+    pcmpgtw              m1, m9, m6 ; base < max_base_x
+    pmulhrsw             m0, m3
+    paddw                m6, m10    ; xpos += dx
+    lea                  r5, [dstq+strideq*2]
+    vpblendvb            m0, m7, m0, m1
+    packuswb             m0, m0
+    vextracti128        xm1, m0, 1
+    movd   [r5  +strideq*0], xm0
+    pextrd [r5  +strideq*1], xm0, 1
+    movd   [dstq+strideq*0], xm1
+    pextrd [dstq+strideq*1], xm1, 1
+    sub                  hd, 4
+    jz .w4_end
+    lea                dstq, [dstq+strideq*4]
+    cmp                 r3d, maxbased
+    jb .w4_loop
+    packuswb            xm7, xm7
+    lea                  r6, [strideq*3]
+.w4_end_loop:
+    movd   [dstq+strideq*0], xm7
+    movd   [dstq+strideq*1], xm7
+    movd   [dstq+strideq*2], xm7
+    movd   [dstq+r6       ], xm7
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_end_loop
+.w4_end:
+    RET
+ALIGN function_align
+.w8:
+    lea                 r3d, [angleq+216]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || h > 8
+    ALLOC_STACK         -32, 8
+    movu                xm2, [z_filter_s+6]
+    mova                xm0, [tlq-1]
+    movd                xm6, hd
+    vinserti128          m0, [tlq+7], 1
+    vpbroadcastb        xm6, xm6
+    vbroadcasti128       m1, [z_upsample1]
+    pminub              xm6, xm2
+    vpbroadcastd         m7, [pb_36_m4]
+    vinserti128          m2, xm6, 1
+    add                 dxd, dxd
+    pshufb               m1, m0, m1
+    pshufb               m2, m0, m2
+    movd                xm6, dxd
+    pmaddubsw            m1, m7
+    pmaddubsw            m2, m7
+    vpbroadcastw         m6, xm6
+    mov                 r3d, dxd
+    psrldq               m0, 1
+    lea                  r2, [strideq*3]
+    paddw                m7, m6, m6
+    paddw                m1, m2
+    vpblendd             m6, m7, 0xf0
+    pmulhrsw             m1, m3
+    pslldq               m2, m7, 8
+    paddw                m7, m7
+    paddw                m6, m2
+    packuswb             m1, m1
+    punpcklbw            m0, m1
+    mova              [rsp], m0
+.w8_upsample_loop:
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base0
+    movu                xm0, [rsp+r3]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base1
+    vinserti128          m0, [rsp+r5], 1
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base2
+    pand                 m1, m4, m6
+    psubw                m2, m5, m1
+    psllw                m1, 8
+    por                  m2, m1
+    punpcklqdq           m1, m2, m2 ; frac0 frac1
+    pmaddubsw            m0, m1
+    movu                xm1, [rsp+r3]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base3
+    vinserti128          m1, [rsp+r5], 1
+    punpckhqdq           m2, m2 ; frac2 frac3
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m3
+    paddw                m6, m7
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*2], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+r2       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_upsample_loop
+    RET
+.w8_no_intra_edge_filter:
+    and            maxbased, 7
+    or             maxbased, 8 ; imin(h+7, 15)
+    jmp .w8_main
+.w8_no_upsample:
+    ALLOC_STACK         -32, 10
+    lea            maxbased, [hq+7]
+    test             angled, 0x400
+    jnz .w8_no_intra_edge_filter
+    call .filter_strength
+    test                r5d, r5d
+    jz .w8_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    movu                xm2, [tlq]
+    pminub              xm1, xm0, [base+z_filter_s+14]
+    vinserti128          m2, [tlq-1], 1
+    vinserti128          m1, [base+z_filter_s+ 0], 1
+    vpbroadcastd         m7, [base+z_filter_k-4+r5*4+12*0]
+    pminub              xm0, [base+z_filter_s+22]
+    vinserti128          m0, [base+z_filter_s+ 8], 1
+    pshufb               m6, m2, m1
+    pmaddubsw            m6, m7
+    vpbroadcastd         m7, [base+z_filter_k-4+r5*4+12*1]
+    movzx               r3d, byte [tlq+15]
+    shufps               m1, m0, q2121
+    pshufb               m1, m2, m1
+    pmaddubsw            m1, m7
+    paddw                m1, m6
+    sub                 r5d, 3
+    jnz .w8_3tap
+    ; filter_strength == 3 uses a 5-tap filter instead of a 3-tap one,
+    ; which also results in an awkward edge case where out[w*2] is
+    ; slightly different from out[max_base_x] when h > w.
+    vpbroadcastd         m7, [z_filter_k+4*8]
+    movzx               r2d, byte [tlq+14]
+    pshufb               m2, m0
+    pmaddubsw            m2, m7
+    sub                 r2d, r3d
+    lea                 r2d, [r2+r3*8+4]
+    shr                 r2d, 3 ; (tlq[w*2-2] + tlq[w*2-1]*7 + 4) >> 3
+    mov            [rsp+16], r2b
+    paddw                m1, m2
+.w8_3tap:
+    pmulhrsw             m1, m3
+    sar                 r5d, 1
+    mov                 tlq, rsp
+    add                 r5d, 17 ; w*2 + (filter_strength == 3)
+    cmp                  hd, 16
+    cmovns         maxbased, r5d
+    mov            [tlq+r5], r3b
+    vextracti128        xm0, m1, 1
+    packuswb            xm0, xm1
+    mova              [tlq], xm0
+.w8_main:
+    movd                xm2, dxd
+    vbroadcasti128       m0, [z_base_inc]
+    vpbroadcastw         m2, xm2
+    vpbroadcastb         m7, [tlq+maxbaseq]
+    shl            maxbased, 6
+    movd                xm9, maxbased
+    vbroadcasti128       m8, [z_filter_s+2]
+    vpbroadcastw         m9, xm9
+    psrlw                m7, 8
+    psubw                m9, m0
+    mov                 r3d, dxd
+    paddw                m6, m2, m2
+    vpblendd             m2, m6, 0xf0
+.w8_loop:
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6
+    pand                 m0, m4, m2
+    psubw                m1, m5, m0
+    psllw                m0, 8
+    por                  m1, m0
+    movu                xm0, [tlq+r3]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base1
+    vinserti128          m0, [tlq+r5], 1
+    pshufb               m0, m8
+    pmaddubsw            m0, m1
+    pcmpgtw              m1, m9, m2
+    paddw                m2, m6
+    pmulhrsw             m0, m3
+    vpblendvb            m0, m7, m0, m1
+    vextracti128        xm1, m0, 1
+    packuswb            xm0, xm1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    sub                  hd, 2
+    jz .w8_end
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r3d, maxbased
+    jb .w8_loop
+    packuswb            xm7, xm7
+.w8_end_loop:
+    movq   [dstq+strideq*0], xm7
+    movq   [dstq+strideq*1], xm7
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_end_loop
+.w8_end:
+    RET
+.w16_no_intra_edge_filter:
+    and            maxbased, 15
+    or             maxbased, 16 ; imin(h+15, 31)
+    jmp .w16_main
+ALIGN function_align
+.w16:
+    ALLOC_STACK         -64, 12
+    lea            maxbased, [hq+15]
+    test             angled, 0x400
+    jnz .w16_no_intra_edge_filter
+    call .filter_strength
+    test                r5d, r5d
+    jz .w16_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    vpbroadcastd         m1, [base+pb_12]
+    vbroadcasti128       m6, [base+z_filter_s+8]
+    vinserti128          m2, m6, [base+z_filter_s], 0
+    vinserti128          m6, [base+z_filter_s+16], 1
+    mova               xm10, [tlq-1]
+    vinserti128         m10, [tlq+3], 1
+    vpbroadcastd         m9, [base+z_filter_k-4+r5*4+12*0]
+    vbroadcasti128       m7, [base+z_filter_s+14]
+    vinserti128          m8, m7, [base+z_filter_s+6], 0
+    vinserti128          m7, [base+z_filter_s+22], 1
+    psubw                m0, m1
+    movu               xm11, [tlq+12]
+    vinserti128         m11, [tlq+16], 1
+    pminub               m8, m0
+    pminub               m7, m0
+    pshufb               m0, m10, m2
+    shufps               m2, m6, q2121
+    pmaddubsw            m0, m9
+    pshufb               m1, m11, m8
+    shufps               m8, m7, q2121
+    pmaddubsw            m1, m9
+    vpbroadcastd         m9, [base+z_filter_k-4+r5*4+12*1]
+    movzx               r3d, byte [tlq+31]
+    pshufb               m2, m10, m2
+    pmaddubsw            m2, m9
+    pshufb               m8, m11, m8
+    pmaddubsw            m8, m9
+    paddw                m0, m2
+    paddw                m1, m8
+    sub                 r5d, 3
+    jnz .w16_3tap
+    vpbroadcastd         m9, [z_filter_k+4*8]
+    movzx               r2d, byte [tlq+30]
+    pshufb              m10, m6
+    pmaddubsw           m10, m9
+    pshufb              m11, m7
+    pmaddubsw           m11, m9
+    sub                 r2d, r3d
+    lea                 r2d, [r2+r3*8+4]
+    shr                 r2d, 3
+    mov            [rsp+32], r2b
+    paddw                m0, m10
+    paddw                m1, m11
+.w16_3tap:
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    sar                 r5d, 1
+    mov                 tlq, rsp
+    add                 r5d, 33
+    cmp                  hd, 32
+    cmovns         maxbased, r5d
+    mov            [tlq+r5], r3b
+    packuswb             m0, m1
+    vpermq               m0, m0, q3120
+    mova              [tlq], m0
+.w16_main:
+    movd                xm6, dxd
+    vbroadcasti128       m0, [z_base_inc]
+    vpbroadcastb         m7, [tlq+maxbaseq]
+    shl            maxbased, 6
+    vpbroadcastw         m6, xm6
+    movd                xm9, maxbased
+    vbroadcasti128       m8, [z_filter_s+2]
+    vpbroadcastw         m9, xm9
+    mov                 r3d, dxd
+    psubw                m9, m0
+    paddw               m11, m6, m6
+    psubw               m10, m9, m3 ; 64*8
+    vpblendd             m6, m11, 0xf0
+.w16_loop:
+    lea                 r5d, [r3+dxq]
+    shr                 r3d, 6 ; base0
+    pand                 m1, m4, m6
+    psubw                m2, m5, m1
+    psllw                m1, 8
+    por                  m2, m1
+    movu                xm0, [tlq+r3+0]
+    movu                xm1, [tlq+r3+8]
+    lea                 r3d, [r5+dxq]
+    shr                 r5d, 6 ; base1
+    vinserti128          m0, [tlq+r5+0], 1
+    vinserti128          m1, [tlq+r5+8], 1
+    pshufb               m0, m8
+    pshufb               m1, m8
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    pcmpgtw              m1, m9, m6
+    pcmpgtw              m2, m10, m6
+    packsswb             m1, m2
+    paddw                m6, m11
+    vpblendvb            m0, m7, m0, m1
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    sub                  hd, 2
+    jz .w16_end
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r3d, maxbased
+    jb .w16_loop
+.w16_end_loop:
+    mova   [dstq+strideq*0], xm7
+    mova   [dstq+strideq*1], xm7
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_end_loop
+.w16_end:
+    RET
+ALIGN function_align
+.w32:
+    ALLOC_STACK         -96, 15
+    lea                 r3d, [hq+31]
+    mov            maxbased, 63
+    cmp                  hd, 32
+    cmovs          maxbased, r3d
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w32_main
+    vbroadcasti128       m0, [pb_0to15]
+    sub                 r3d, 29 ; h+2
+    movu               xm13, [tlq+29]    ; 32-39
+    movd                xm1, r3d
+    movu               xm14, [tlq+37]    ; 40-47
+    sub                 r3d, 8 ; h-6
+    vinserti128         m14, [tlq+51], 1 ; 56-63
+    vpbroadcastb        xm1, xm1
+    mova               xm11, [tlq- 1]    ;  0- 7
+    vinserti128         m11, [tlq+13], 1 ; 16-23
+    movd                xm2, r3d
+    movu               xm12, [tlq+ 5]    ;  8-15
+    vinserti128         m12, [tlq+19], 1 ; 24-31
+    pminub              xm1, xm0 ; clip 32x8
+    mova                 m7, [z_filter_s+0]
+    pshufb             xm13, xm1
+    vpbroadcastd         m1, [pb_12]
+    vpbroadcastb        xm2, xm2
+    vinserti128         m13, [tlq+43], 1 ; 48-55
+    vinserti128          m8, m7, [z_filter_s+4], 1
+    vpblendd             m2, m1, 0xf0
+    vinserti128          m7, [z_filter_s+12], 0
+    pminub               m2, m0 ; clip 32x16 and 32x(32|64)
+    vpbroadcastd         m9, [z_filter_k+4*2+12*0]
+    pshufb              m14, m2
+    pshufb               m0, m11, m8
+    shufps               m8, m7, q1021
+    pmaddubsw            m0, m9
+    pshufb               m2, m12, m8
+    pmaddubsw            m2, m9
+    pshufb               m1, m13, m8
+    pmaddubsw            m1, m9
+    pshufb               m6, m14, m8
+    pmaddubsw            m6, m9
+    vpbroadcastd         m9, [z_filter_k+4*2+12*1]
+    pshufb              m10, m11, m8
+    shufps               m8, m7, q2121
+    pmaddubsw           m10, m9
+    paddw                m0, m10
+    pshufb              m10, m12, m8
+    pmaddubsw           m10, m9
+    paddw                m2, m10
+    pshufb              m10, m13, m8
+    pmaddubsw           m10, m9
+    paddw                m1, m10
+    pshufb              m10, m14, m8
+    pmaddubsw           m10, m9
+    paddw                m6, m10
+    vpbroadcastd         m9, [z_filter_k+4*2+12*2]
+    pshufb              m11, m8
+    pmaddubsw           m11, m9
+    pshufb              m12, m7
+    pmaddubsw           m12, m9
+    movzx               r3d, byte [tlq+63]
+    movzx               r2d, byte [tlq+62]
+    paddw                m0, m11
+    paddw                m2, m12
+    pshufb              m13, m7
+    pmaddubsw           m13, m9
+    pshufb              m14, m7
+    pmaddubsw           m14, m9
+    paddw                m1, m13
+    paddw                m6, m14
+    sub                 r2d, r3d
+    lea                 r2d, [r2+r3*8+4] ; edge case for 32x64
+    pmulhrsw             m0, m3
+    pmulhrsw             m2, m3
+    pmulhrsw             m1, m3
+    pmulhrsw             m6, m3
+    shr                 r2d, 3
+    mov            [rsp+64], r2b
+    mov                 tlq, rsp
+    mov            [tlq+65], r3b
+    mov                 r3d, 65
+    cmp                  hd, 64
+    cmove          maxbased, r3d
+    packuswb             m0, m2
+    packuswb             m1, m6
+    mova           [tlq+ 0], m0
+    mova           [tlq+32], m1
+.w32_main:
+    movd                xm6, dxd
+    vpbroadcastb         m7, [tlq+maxbaseq]
+    shl            maxbased, 6
+    vpbroadcastw         m6, xm6
+    movd                xm9, maxbased
+    vbroadcasti128       m8, [z_filter_s+2]
+    vpbroadcastw         m9, xm9
+    mov                 r5d, dxd
+    psubw                m9, [z_base_inc]
+    mova                m11, m6
+    psubw               m10, m9, m3 ; 64*8
+.w32_loop:
+    mov                 r3d, r5d
+    shr                 r3d, 6
+    pand                 m1, m4, m6
+    psubw                m2, m5, m1
+    psllw                m1, 8
+    por                  m2, m1
+    movu                 m0, [tlq+r3+0]
+    movu                 m1, [tlq+r3+8]
+    add                 r5d, dxd
+    pshufb               m0, m8
+    pshufb               m1, m8
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    pcmpgtw              m1, m9, m6
+    pcmpgtw              m2, m10, m6
+    packsswb             m1, m2
+    paddw                m6, m11
+    vpblendvb            m0, m7, m0, m1
+    mova             [dstq], m0
+    dec                  hd
+    jz .w32_end
+    add                dstq, strideq
+    cmp                 r5d, maxbased
+    jb .w32_loop
+    test                 hb, 1
+    jz .w32_end_loop
+    mova             [dstq], m7
+    add                dstq, strideq
+    dec                  hd
+    jz .w32_end
+.w32_end_loop:
+    mova   [dstq+strideq*0], m7
+    mova   [dstq+strideq*1], m7
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_end_loop
+.w32_end:
+    RET
+ALIGN function_align
+.w64:
+    ALLOC_STACK        -128, 16
+    lea            maxbased, [hq+63]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w64_main
+    mova               xm11, [tlq- 1]    ;  0- 7
+    vinserti128         m11, [tlq+13], 1 ; 16-23
+    movu               xm12, [tlq+ 5]    ;  8-15
+    vinserti128         m12, [tlq+19], 1 ; 24-31
+    mova                 m7, [z_filter_s+0]
+    vinserti128          m8, m7, [z_filter_s+4], 1
+    vinserti128          m7, [z_filter_s+12], 0
+    vpbroadcastd         m9, [z_filter_k+4*2+12*0]
+    movu               xm13, [tlq+29]    ; 32-39
+    vinserti128         m13, [tlq+43], 1 ; 48-55
+    movu               xm14, [tlq+37]    ; 40-47
+    vinserti128         m14, [tlq+51], 1 ; 56-63
+    pshufb               m0, m11, m8
+    shufps               m8, m7, q1021
+    pmaddubsw            m0, m9
+    pshufb               m2, m12, m8
+    pmaddubsw            m2, m9
+    pshufb               m1, m13, m8
+    pmaddubsw            m1, m9
+    pshufb               m6, m14, m8
+    pmaddubsw            m6, m9
+    vpbroadcastd         m9, [z_filter_k+4*2+12*1]
+    pshufb              m10, m11, m8
+    shufps              m15, m8, m7, q2121
+    pmaddubsw           m10, m9
+    paddw                m0, m10
+    pshufb              m10, m12, m15
+    pmaddubsw           m10, m9
+    paddw                m2, m10
+    pshufb              m10, m13, m15
+    pmaddubsw           m10, m9
+    paddw                m1, m10
+    pshufb              m10, m14, m15
+    pmaddubsw           m10, m9
+    paddw                m6, m10
+    vpbroadcastd        m10, [z_filter_k+4*2+12*2]
+    pshufb              m11, m15
+    pmaddubsw           m11, m10
+    pshufb              m12, m7
+    pmaddubsw           m12, m10
+    pshufb              m13, m7
+    pmaddubsw           m13, m10
+    pshufb              m14, m7
+    pmaddubsw           m14, m10
+    paddw                m0, m11
+    paddw                m2, m12
+    paddw                m1, m13
+    paddw                m6, m14
+    movu               xm11, [tlq+ 61]    ;  64- 71
+    vinserti128         m11, [tlq+ 75], 1 ;  80- 87
+    movu               xm12, [tlq+ 69]    ;  72- 79
+    vinserti128         m12, [tlq+ 83], 1 ;  88- 95
+    movu               xm13, [tlq+ 93]    ;  96-103
+    vinserti128         m13, [tlq+107], 1 ; 112-119
+    movu               xm14, [tlq+101]    ; 104-111
+    vinserti128         m14, [tlq+115], 1 ; 120-127
+    pmulhrsw             m0, m3
+    pmulhrsw             m2, m3
+    pmulhrsw             m1, m3
+    pmulhrsw             m6, m3
+    lea                 r3d, [hq-20]
+    mov                 tlq, rsp
+    packuswb             m0, m2
+    packuswb             m1, m6
+    vpbroadcastd        xm2, [pb_14]
+    vbroadcasti128       m6, [pb_0to15]
+    mova         [tlq+32*0], m0
+    mova         [tlq+32*1], m1
+    movd                xm0, r3d
+    vpbroadcastd         m1, [pb_12]
+    vpbroadcastb         m0, xm0
+    paddb                m0, m2
+    pminub               m0, m6 ; clip 64x16 and 64x32
+    pshufb              m12, m0
+    pminub               m1, m6 ; clip 64x64
+    pshufb              m14, m1
+    pshufb               m0, m11, m7
+    pmaddubsw            m0, m10
+    pshufb               m2, m12, m7
+    pmaddubsw            m2, m10
+    pshufb               m1, m13, m7
+    pmaddubsw            m1, m10
+    pshufb               m6, m14, m7
+    pmaddubsw            m6, m10
+    pshufb               m7, m11, m15
+    pmaddubsw            m7, m9
+    pshufb              m10, m12, m15
+    pmaddubsw           m10, m9
+    paddw                m0, m7
+    pshufb               m7, m13, m15
+    pmaddubsw            m7, m9
+    paddw                m2, m10
+    pshufb              m10, m14, m15
+    pmaddubsw           m10, m9
+    paddw                m1, m7
+    paddw                m6, m10
+    vpbroadcastd         m9, [z_filter_k+4*2+12*0]
+    pshufb              m11, m8
+    pmaddubsw           m11, m9
+    pshufb              m12, m8
+    pmaddubsw           m12, m9
+    pshufb              m13, m8
+    pmaddubsw           m13, m9
+    pshufb              m14, m8
+    pmaddubsw           m14, m9
+    paddw                m0, m11
+    paddw                m2, m12
+    paddw                m1, m13
+    paddw                m6, m14
+    pmulhrsw             m0, m3
+    pmulhrsw             m2, m3
+    pmulhrsw             m1, m3
+    pmulhrsw             m6, m3
+    packuswb             m0, m2
+    packuswb             m1, m6
+    mova         [tlq+32*2], m0
+    mova         [tlq+32*3], m1
+.w64_main:
+    movd               xm12, dxd
+    vpbroadcastb         m7, [tlq+maxbaseq]
+    lea                 r3d, [dxq-64]
+    shl            maxbased, 6
+    vpbroadcastw        m12, xm12
+    sub                 r3d, maxbased
+    vbroadcasti128       m8, [z_filter_s+2]
+    movd                xm6, r3d
+    mov                 r5d, dxd
+    mova                m10, [pb_1to32]
+    vpbroadcastd        m11, [pb_32]
+    vpbroadcastw         m6, xm6
+.w64_loop:
+    mov                 r3d, r5d
+    shr                 r3d, 6
+    movu                 m0, [tlq+r3+ 0]
+    movu                 m1, [tlq+r3+ 8]
+    pand                 m2, m4, m6
+    psubw                m9, m5, m2
+    psllw                m2, 8
+    por                  m9, m2
+    pshufb               m0, m8
+    pshufb               m1, m8
+    pmaddubsw            m0, m9
+    pmaddubsw            m1, m9
+    psraw                m2, m6, 6
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packsswb             m2, m2
+    paddb                m2, m10
+    packuswb             m0, m1
+    vpblendvb            m0, m7, m0, m2
+    mova          [dstq+ 0], m0
+    movu                 m0, [tlq+r3+32]
+    movu                 m1, [tlq+r3+40]
+    add                 r5d, dxd
+    pshufb               m0, m8
+    pshufb               m1, m8
+    pmaddubsw            m0, m9
+    pmaddubsw            m1, m9
+    paddb                m2, m11
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    paddw                m6, m12
+    packuswb             m0, m1
+    vpblendvb            m0, m7, m0, m2
+    mova          [dstq+32], m0
+    dec                  hd
+    jz .w64_end
+    add                dstq, strideq
+    cmp                 r5d, maxbased
+    jb .w64_loop
+.w64_end_loop:
+    mova          [dstq+ 0], m7
+    mova          [dstq+32], m7
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_end_loop
+.w64_end:
+    RET
+
+cglobal ipred_z2_8bpc, 3, 10, 16, 224, dst, stride, tl, w, h, angle, dx, dy
+%define base r9-z_filter_t0
+    lea                  r9, [ipred_z2_avx2_table]
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    movifnidn            hd, hm
+    lea                 dxq, [dr_intra_derivative-90]
+    movsxd               wq, [r9+wq*4]
+    movzx               dyd, angleb
+    xor              angled, 0x400
+    mov                  r8, dxq
+    sub                 dxq, dyq
+    add                  wq, r9
+    add                  r9, z_filter_t0-ipred_z2_avx2_table
+    mova                 m2, [tlq-64]
+    mova                 m0, [tlq-32]
+    mova                 m1, [tlq]
+    and                 dyd, ~1
+    and                 dxq, ~1
+    movzx               dyd, word [r8+dyq]  ; angle - 90
+    movzx               dxd, word [dxq+270] ; 180 - angle
+    vpbroadcastd        m13, [base+pw_512]
+    vpbroadcastd        m14, [base+pw_62]
+    vpbroadcastd        m15, [base+pw_64]
+    mova           [rsp+ 0], m2
+    mova           [rsp+32], m0
+    mova           [rsp+64], m1
+    neg                 dxd
+    neg                 dyd
+    jmp                  wq
+.w4:
+    vpbroadcastq         m6, [base+z2_base_inc] ; base_inc << 6
+    vbroadcasti128      m10, [base+z1_shuf_w4]
+    vbroadcasti128      m11, [base+z2_shuf_h4]
+    lea                 r2d, [dxq+(65<<6)] ; xpos
+    movd                xm5, dyd
+    mov                 r8d, (63-4)<<6
+    mov                 dyq, -4
+    pshuflw             xm5, xm5, q0000
+    pmullw              xm5, [base+z2_ymul]
+    test             angled, 0x400
+    jnz .w4_main ; !enable_intra_edge_filter
+    lea                 r3d, [hq+2]
+    add              angled, 1022
+    shl                 r3d, 6
+    test                r3d, angled
+    jnz .w4_no_upsample_above ; angle >= 130 || h > 8 || (is_sm && h == 8)
+    vpbroadcastd        xm3, [base+pb_4]
+    call .upsample_above
+    sub              angled, 1075 ; angle - 53
+    lea                 r3d, [hq+3]
+    xor              angled, 0x7f ; 180 - angle
+    call .filter_strength
+    jmp .w4_filter_left
+ALIGN function_align
+.filter_strength:
+    movd                xm8, r3d
+    mov                 r3d, angled
+    movd                xm7, angled
+    vpbroadcastb         m8, xm8
+    shr                 r3d, 8 ; is_sm << 1
+    vpbroadcastb         m7, xm7
+    pcmpeqb              m8, [base+z_filter_wh]
+    mova                xm9, [r9+r3*8]
+    pand                 m0, m8, m7
+    pcmpgtb              m0, m9
+    pmovmskb            r3d, m0
+    ret
+ALIGN function_align
+.upsample_above: ; w4/w8
+    pshufb              xm2, xm1, [base+z_upsample1-2]
+    pminub              xm3, [base+z_filter_s+4]
+    vpbroadcastd        xm4, [base+pb_36_m4]
+    vbroadcasti128      m10, [base+pb_0to15]
+    pshufb              xm3, xm1, xm3
+    pmaddubsw           xm2, xm4
+    pmaddubsw           xm3, xm4
+    lea                 r2d, [r2+dxq+(1<<6)]
+    add                 dxd, dxd
+    paddw               xm2, xm3
+    pmulhrsw            xm2, xm13
+    sub                 r8d, 3<<6
+    paddw                m6, m6
+    packuswb            xm2, xm2
+    punpcklbw           xm1, xm2
+    mova   [rsp+gprsize+64], xm1
+    ret
+ALIGN function_align
+.upsample_left: ; h4/h8
+    mov                 r3d, hd
+    and                 r3d, 4
+    movd                xm2, [rsp+gprsize+64]
+    movddup             xm0, [rsp+gprsize+56]
+    movd                xm1, r3d
+    palignr             xm2, xm0, 1
+    vpbroadcastb        xm1, xm1
+    pshufb              xm2, [base+z_filter_s+18]
+    vpbroadcastd        xm3, [base+pb_36_m4]
+    pmaxub              xm1, [base+z_upsample1-2]
+    pshufb              xm1, xm0, xm1
+    pmaddubsw           xm2, xm3
+    pmaddubsw           xm1, xm3
+    paddw               xm5, xm5
+    add                 dyq, dyq
+    paddw               xm1, xm2
+    pmulhrsw            xm1, xm13
+    vbroadcasti128      m11, [base+z2_upsample]
+    paddw               xm5, xm15
+    packuswb            xm1, xm1
+    punpcklbw           xm0, xm1
+    mova   [rsp+gprsize+48], xm0
+    ret
+.w4_no_upsample_above:
+    lea                 r3d, [hq+3]
+    sub              angled, 1112 ; angle - 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w4_no_filter_above
+    popcnt              r3d, r3d
+    vpbroadcastd        xm2, [base+pb_4]
+    pminub              xm2, [base+z_filter_s]
+    vpbroadcastd        xm0, [base+z_filter_k-4+r3*4+12*0]
+    vpbroadcastd        xm4, [base+z_filter_k-4+r3*4+12*1]
+    pshufb              xm3, xm1, xm2 ; 00 01 12 23
+    pshufd              xm2, xm2, q0321
+    pmaddubsw           xm0, xm3, xm0
+    pshufb              xm2, xm1, xm2 ; 12 23 34 44
+    pmaddubsw           xm2, xm4
+    vpbroadcastd        xm4, [base+z_filter_k-4+r3*4+12*2]
+    punpckhqdq          xm3, xm3      ; 34 44 44 44
+    pmaddubsw           xm3, xm4
+    vpbroadcastd        xm4, r6m      ; max_width
+    packssdw            xm4, xm4
+    paddw               xm0, xm2
+    paddw               xm0, xm3
+    pmulhrsw            xm0, xm13
+    packsswb            xm4, xm4
+    psrlq               xm1, 8
+    psubb               xm4, [base+pb_1to32]
+    packuswb            xm0, xm0
+    vpblendvb           xm0, xm1, xm4
+    movd           [rsp+65], xm0
+.w4_no_filter_above:
+    lea                 r3d, [hq+2]
+    add              angled, 973 ; angle + 883
+    shl                 r3d, 6
+    test                r3d, angled
+    jz .w4_upsample_left ; angle <= 140 || h > 8 || (is_sm && h == 8)
+    vpbroadcastd        xm0, [base+pb_90]
+    psubb               xm0, xm7 ; 180 - angle
+    pand                xm0, xm8 ; reuse from previous filter_strength call
+    pcmpgtb             xm0, xm9
+    pmovmskb            r3d, xm0
+.w4_filter_left:
+    test                r3d, r3d
+    jz .w4_main
+    popcnt              r3d, r3d
+    mov                 r5d, 10
+    cmp                  hd, 16
+    movu                xm2, [rsp+49]
+    vinserti128          m2, [rsp+43], 1
+    cmovs               r5d, hd
+    xor                 r5d, 15 ; h == 16 ? 5 : 15 - h
+    movd                xm0, r5d
+    vbroadcasti128       m1, [base+z_filter_s+12]
+    vbroadcasti128       m4, [base+z_filter_s+16]
+    vinserti128          m3, m1, [z_filter_s+8], 1   ; 56 67 78 89 9a ab bc cd   55 55 56 67 78 89 9a ab
+    vpblendd             m1, m4, 0x0f                ; 78 89 9a ab bc cd de ef   56 67 78 89 9a ab bc cd
+    vinserti128          m4, [base+z_filter_s+20], 0 ; 9a ab bc cd de ef ff ff   78 89 9a ab bc cd de ef
+    vpbroadcastb         m0, xm0
+    pmaxub               m0, m3
+    vpbroadcastd         m3, [base+z_filter_k-4+r3*4+12*0]
+    pshufb               m0, m2, m0
+    pmaddubsw            m0, m3
+    vpbroadcastd         m3, [base+z_filter_k-4+r3*4+12*1]
+    pshufb               m1, m2, m1
+    pmaddubsw            m1, m3
+    vpbroadcastd         m3, [base+z_filter_k-4+r3*4+12*2]
+    pshufb               m2, m4
+    pmaddubsw            m2, m3
+    vpbroadcastd        xm4, r7m ; max_height
+    packssdw            xm4, xm4
+    paddw                m1, m0
+    paddw                m1, m2
+    pmulhrsw             m1, m13
+    packsswb            xm4, xm4
+    vextracti128        xm0, m1, 1
+    psubb               xm4, [base+pb_16to1]
+    packuswb            xm0, xm1
+    vpblendvb           xm0, [rsp+48], xm4
+    mova           [rsp+48], xm0
+    jmp .w4_main
+.w4_upsample_left:
+    call .upsample_left
+.w4_main:
+    movd                xm0, dxd
+    mova                m12, [base+z2_y_shuf_h4]
+    lea                  r5, [rsp+56]  ; left-7
+    vpbroadcastw         m0, xm0
+    lea                  r9, [strideq*3]
+    psraw               xm1, xm5, 6
+    pand                xm5, xm14      ; frac_y
+    pxor                xm2, xm2
+    paddw                m7, m0, m0
+    psubw               xm4, xm2, xm1  ; base_y
+    vpblendd             m0, m7, 0xcc
+    mova                xm1, xm7
+    punpcklwd           xm4, xm2
+    paddw                m0, m1        ; xpos2 xpos3 xpos0 xpos1
+    psubw               xm1, xm15, xm5 ; 64-frac_y
+    psllw               xm5, 8
+    paddw                m7, m7
+    paddw                m6, m0
+    por                 xm5, xm1       ; 64-frac_y, frac_y
+    vpbroadcastq         m5, xm5
+.w4_loop:
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6         ; base_x0
+    vpbroadcastq         m1, [rsp+r2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6         ; base_x1
+    vpbroadcastq         m2, [rsp+r3]
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6         ; base_x2
+    movq                xm0, [rsp+r2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6         ; base_x3
+    movhps              xm0, [rsp+r3]
+    vpblendd             m1, m2, 0xc0
+    pand                 m2, m14, m6   ; frac_x
+    vpblendd             m0, m1, 0xf0
+    psubw                m1, m15, m2   ; 64-frac_x
+    psllw                m2, 8
+    pshufb               m0, m10
+    por                  m1, m2        ; 64-frac_x, frac_x
+    pmaddubsw            m0, m1
+    cmp                 r3d, 64
+    jge .w4_toponly
+    mova                 m1, m7        ; arbitrary negative value
+    vpgatherdq           m3, [r5+xm4], m1
+    pshufb               m1, m3, m11
+    vpermd               m1, m12, m1
+    pmaddubsw            m1, m5
+    psraw                m2, m6, 15    ; base_x < topleft
+    vpblendvb            m0, m1, m2
+.w4_toponly:
+    pmulhrsw             m0, m13
+    paddw                m6, m7        ; xpos += dx
+    add                  r5, dyq
+    packuswb             m0, m0
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*2], xm0
+    pextrd [dstq+r9       ], xm0, 1
+    movd   [dstq+strideq*0], xm1
+    pextrd [dstq+strideq*1], xm1, 1
+    sub                  hd, 4
+    jz .w4_end
+    lea                dstq, [dstq+strideq*4]
+    cmp                 r2d, r8d
+    jge .w4_loop
+.w4_leftonly_loop:
+    mova                 m1, m7
+    vpgatherdq           m2, [r5+xm4], m1
+    add                  r5, dyq
+    pshufb               m0, m2, m11
+    vpermd               m0, m12, m0
+    pmaddubsw            m0, m5
+    pmulhrsw             m0, m13
+    packuswb             m0, m0
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*2], xm0
+    pextrd [dstq+r9       ], xm0, 1
+    movd   [dstq+strideq*0], xm1
+    pextrd [dstq+strideq*1], xm1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_leftonly_loop
+.w4_end:
+    RET
+.w8:
+    vbroadcasti128       m6, [base+z2_base_inc] ; base_inc << 6
+    movd                xm5, dyd
+    vbroadcasti128      m10, [base+z_filter_s+2]
+    vbroadcasti128      m11, [base+z2_shuf_h4]
+    lea                 r2d, [dxq+(65<<6)] ; xpos
+    vpbroadcastw        xm5, xm5
+    mov                 r8d, (63-8)<<6
+    mov                 dyq, -4
+    pmullw              xm5, [base+z2_ymul]
+    test             angled, 0x400
+    jnz .w8_main
+    lea                 r3d, [angleq+126]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_no_upsample_above ; angle >= 130 || h > 8 || is_sm
+    vpbroadcastd        xm3, [base+pb_8]
+    movhps         [rsp+80], xm1
+    call .upsample_above
+    sub              angled, 53 ; angle - 53
+    lea                 r3d, [hq+7]
+    xor              angled, 0x7f ; 180 - angle
+    call .filter_strength
+    jmp .w8_filter_left
+.w8_no_upsample_above:
+    lea                 r3d, [hq+7]
+    sub              angled, 90 ; angle - 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w8_no_filter_above
+    popcnt              r3d, r3d
+    vpbroadcastd        xm3, [base+pb_8]
+    pminub              xm3, [base+z_filter_s+8]
+    vpbroadcastd        xm0, [base+z_filter_k-4+r3*4+12*0]
+    vpbroadcastd        xm4, [base+z_filter_k-4+r3*4+12*1]
+    pshufb              xm2, xm1, [base+z_filter_s] ; 00 01 12 23 34 45 56 67
+    pmaddubsw           xm0, xm2, xm0
+    pshufb              xm3, xm1, xm3               ; 34 45 56 67 78 88 88 88
+    shufps              xm2, xm3, q2121             ; 12 23 34 45 56 67 78 88
+    pmaddubsw           xm2, xm4
+    vpbroadcastd        xm4, [base+z_filter_k-4+r3*4+12*2]
+    pmaddubsw           xm3, xm4
+    vpbroadcastd        xm4, r6m ; max_width
+    packssdw            xm4, xm4
+    paddw               xm0, xm2
+    paddw               xm0, xm3
+    pmulhrsw            xm0, xm13
+    packsswb            xm4, xm4
+    psrldq              xm1, 1
+    psubb               xm4, [base+pb_1to32]
+    packuswb            xm0, xm0
+    vpblendvb           xm0, xm1, xm4
+    movq           [rsp+65], xm0
+.w8_no_filter_above:
+    lea                 r3d, [angleq-51]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    jbe .w8_upsample_left ; angle > 140 && h <= 8 && !is_sm
+    vpbroadcastd         m0, [base+pb_90]
+    psubb                m0, m7
+    pand                 m0, m8
+    pcmpgtb              m0, m9
+    pmovmskb            r3d, m0
+.w8_filter_left:
+    test                r3d, r3d
+    jz .w8_main
+    popcnt              r3d, r3d
+    vpbroadcastd         m7, [base+z_filter_k-4+r3*4+12*0]
+    vpbroadcastd         m8, [base+z_filter_k-4+r3*4+12*1]
+    vpbroadcastd         m9, [base+z_filter_k-4+r3*4+12*2]
+    cmp                  hd, 32
+    jne .w8_filter_left_h16
+    movu                xm2, [rsp+27]
+    vinserti128          m2, [rsp+35], 1
+    vpbroadcastd        xm0, [base+pb_5]
+    vbroadcasti128       m3, [base+z_filter_s+ 8]
+    vbroadcasti128       m1, [base+z_filter_s+12]
+    vbroadcasti128       m4, [base+z_filter_s+16]
+    pmaxub               m3, m0
+    pshufb               m3, m2, m3
+    pmaddubsw            m3, m7
+    pshufb               m1, m2, m1
+    pmaddubsw            m1, m8
+    pshufb               m2, m4
+    pmaddubsw            m2, m9
+    paddw                m3, m1
+    paddw                m3, m2
+    pmulhrsw             m3, m13
+    jmp .w8_filter_left_top16
+.w8_filter_left_h16:
+    mov                 r5d, 10
+    cmp                  hd, 16
+    cmovs               r5d, hd
+    xor                 r5d, 15 ; h == 16 ? 5 : 15 - h
+    movd                xm0, r5d
+    vpbroadcastb         m0, xm0
+.w8_filter_left_top16:
+    vbroadcasti128       m1, [base+z_filter_s+12]
+    vinserti128          m2, m1, [base+z_filter_s+8], 1 ; 56 67 78 89 9a ab bc cd   55 55 56 67 78 89 9a ab
+    vbroadcasti128       m4, [base+z_filter_s+16]
+    vpblendd             m1, m4, 0x0f                   ; 78 89 9a ab bc cd de ef   56 67 78 89 9a ab bc cd
+    vinserti128          m4, [base+z_filter_s+20], 0    ; 9a ab bc cd de ef ff ff   78 89 9a ab bc cd de ef
+    pmaxub               m0, m2
+    movu                xm2, [rsp+49]
+    vinserti128          m2, [rsp+43], 1
+    pshufb               m0, m2, m0
+    pmaddubsw            m0, m7
+    vpbroadcastd         m7, r7m ; max_height
+    pshufb               m1, m2, m1
+    pmaddubsw            m1, m8
+    pshufb               m2, m4
+    pmaddubsw            m2, m9
+    packssdw             m7, m7
+    paddw                m1, m0
+    packsswb             m7, m7
+    paddw                m1, m2
+    pmulhrsw             m1, m13
+    psubb                m7, [base+pb_32to1]
+    packuswb             m3, m1
+    vpermq               m3, m3, q1320
+    vpblendvb            m3, [rsp+32], m7
+    mova           [rsp+32], m3
+    jmp .w8_main
+.w8_upsample_left:
+    call .upsample_left
+.w8_main:
+    movd                xm3, dxd
+    lea                  r5, [rsp+56]  ; left-7
+    pshufd              xm1, xm5, q3120
+    pand                xm5, xm14
+    vpbroadcastw         m3, xm3
+    pxor                xm0, xm0
+    psubw               xm2, xm15, xm5
+    psraw               xm1, 6
+    lea                  r9, [strideq*3]
+    paddw                m7, m3, m3
+    psubw               xm9, xm0, xm1  ; base_y
+    psllw               xm5, 8
+    punpcklwd           xm8, xm9, xm0  ; base_y 0, 1, 4, 5
+    vpblendd             m3, m7, 0xf0  ; xpos0 xpos1
+    por                 xm5, xm2       ; 64-frac_y, frac_y
+    punpckhwd           xm9, xm0       ; base_y 2, 3, 6, 7
+    paddw                m6, m3
+    vinserti128         m12, m5, xm5, 1
+.w8_loop:
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6         ; base_x0
+    movu                xm0, [rsp+r2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6         ; base_x1
+    vinserti128          m0, [rsp+r3], 1
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6         ; base_x2
+    movu                xm1, [rsp+r2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6         ; base_x3
+    vinserti128          m1, [rsp+r3], 1
+    pand                 m2, m14, m6
+    paddsw               m4, m6, m7
+    psubw                m5, m15, m2
+    psllw                m2, 8
+    pshufb               m0, m10
+    por                  m2, m5
+    pmaddubsw            m0, m2
+    pand                 m2, m14, m4
+    psubw                m5, m15, m2
+    psllw                m2, 8
+    pshufb               m1, m10
+    por                  m2, m5
+    pmaddubsw            m1, m2
+    cmp                 r3d, 64
+    jge .w8_toponly
+    mova                 m5, m7
+    vpgatherdq           m3, [r5+xm9], m7
+    mova                 m7, m5
+    vpgatherdq           m2, [r5+xm8], m5
+    pshufb               m3, m11
+    pshufb               m2, m11
+    punpckldq            m5, m2, m3    ; a0 b0 c0 d0 a1 b1 c1 d1   e0 f0 g0 h0 e1 f1 g1 h1
+    punpckhdq            m2, m3        ; a2 b2 c2 d2 a3 b3 c3 d3   e2 f2 g2 h2 e3 f3 g3 h3
+    vpermq               m5, m5, q3120 ; y0 y1
+    vpermq               m2, m2, q3120 ; y2 y3
+    pmaddubsw            m5, m12
+    pmaddubsw            m2, m12
+    psraw                m6, 15        ; base_x < topleft
+    vpblendvb            m0, m5, m6
+    psraw                m3, m4, 15
+    vpblendvb            m1, m2, m3
+.w8_toponly:
+    pmulhrsw             m0, m13
+    pmulhrsw             m1, m13
+    paddw                m6, m4, m7     ; xpos += dx
+    add                  r5, dyq
+    packuswb             m0, m1
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*2], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+r9       ], xm1
+    sub                  hd, 4
+    jz .w8_end
+    lea                dstq, [dstq+strideq*4]
+    cmp                 r2d, r8d
+    jge .w8_loop
+.w8_leftonly_loop:
+    mova                 m0, m7
+    vpgatherdq           m5, [r5+xm9], m7
+    mova                 m7, m0
+    vpgatherdq           m3, [r5+xm8], m0
+    add                  r5, dyq
+    pshufb               m2, m5, m11
+    pshufb               m1, m3, m11
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q3120
+    pmaddubsw            m0, m12
+    pmaddubsw            m1, m12
+    pmulhrsw             m0, m13
+    pmulhrsw             m1, m13
+    packuswb             m0, m1
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*2], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+r9       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_leftonly_loop
+.w8_end:
+    RET
+.w16:
+    mov                 r8d, hd
+    test             angled, 0x400
+    jnz .w16_main
+    lea                 r3d, [hq+15]
+    sub              angled, 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w16_no_filter_above
+    popcnt              r3d, r3d
+    vbroadcasti128       m6, [tlq+1]
+    mova                xm2, [base+z_filter_s]
+    vinserti128          m2, [base+z_filter_s+14], 1 ; 00 01 12 23 34 45 56 67   67 78 89 9a ab bc cd de
+    movu                xm3, [base+z_filter_s+8]
+    vinserti128          m3, [base+z_filter_s+22], 1 ; 34 45 56 67 78 89 9a ab   ab bc cd de ef ff ff ff
+    vpblendd             m1, m6, 0xf0
+    vpbroadcastd         m0, [base+z_filter_k-4+r3*4+12*0]
+    vpbroadcastd         m4, [base+z_filter_k-4+r3*4+12*1]
+    vpbroadcastd         m5, [base+z_filter_k-4+r3*4+12*2]
+    pshufb               m2, m1, m2
+    pshufb               m1, m3
+    pmaddubsw            m0, m2, m0
+    shufps               m2, m1, q2121                ; 12 23 34 45 56 67 78 89   89 9a ab bc cd de ef ff
+    pmaddubsw            m2, m4
+    pmaddubsw            m1, m5
+    vpbroadcastd        xm4, r6m ; max_width
+    packssdw            xm4, xm4
+    paddw                m0, m2
+    paddw                m0, m1
+    pmulhrsw             m0, m13
+    packsswb            xm4, xm4
+    vextracti128        xm2, m0, 1
+    psubb               xm4, [base+pb_1to32]
+    packuswb            xm0, xm2
+    vpblendvb           xm0, xm6, xm4
+    movu           [rsp+65], xm0
+.w16_no_filter_above:
+    vpbroadcastd         m0, [base+pb_90]
+    psubb                m0, m7
+    pand                 m0, m8
+    pcmpgtb              m0, m9
+    pmovmskb            r3d, m0
+    test                r3d, r3d
+    jz .w16_main
+    popcnt              r3d, r3d
+    vpbroadcastd         m7, [base+z_filter_k-4+r3*4+12*0]
+    vpbroadcastd         m8, [base+z_filter_k-4+r3*4+12*1]
+    vpbroadcastd         m9, [base+z_filter_k-4+r3*4+12*2]
+.w16_filter_left:
+    vpbroadcastd         m6, r7m ; max_height
+    packssdw             m6, m6
+    packsswb             m6, m6
+    cmp                  hd, 32
+    jl .w16_filter_left_h16
+    vpbroadcastd        xm0, [base+pb_5]
+    vbroadcasti128      m10, [base+z_filter_s+ 8]
+    vbroadcasti128      m11, [base+z_filter_s+12]
+    vbroadcasti128      m12, [base+z_filter_s+16]
+    je .w16_filter_left_h32
+    movu                 m3, [tlq-69]
+    movu                 m5, [tlq-61]
+    pmaxub               m1, m10, m0
+    pshufb               m1, m3, m1
+    pmaddubsw            m1, m7
+    pshufb               m2, m3, m11
+    pmaddubsw            m2, m8
+    pshufb               m3, m12
+    pmaddubsw            m3, m9
+    paddw                m1, m2
+    pshufb               m2, m5, m10
+    pmaddubsw            m2, m7
+    pshufb               m4, m5, m11
+    pmaddubsw            m4, m8
+    pshufb               m5, m12
+    pmaddubsw            m5, m9
+    paddw                m1, m3
+    vpbroadcastd         m3, [base+pb_32]
+    paddb                m3, [base+pb_32to1]
+    paddw                m2, m4
+    paddw                m2, m5
+    pmulhrsw             m1, m13
+    pmulhrsw             m2, m13
+    psubb                m3, m6, m3
+    packuswb             m1, m2
+    vpblendvb            m1, [tlq-64], m3
+    mova              [rsp], m1
+    jmp .w16_filter_left_top32
+.w16_filter_left_h32:
+    pmaxub              m10, m0
+.w16_filter_left_top32:
+    movu                xm2, [tlq-37]
+    vinserti128          m2, [tlq-29], 1
+    pshufb               m3, m2, m10
+    pshufb               m1, m2, m11
+    pshufb               m2, m12
+    pmaddubsw            m3, m7
+    pmaddubsw            m1, m8
+    pmaddubsw            m2, m9
+    paddw                m3, m1
+    paddw                m3, m2
+    pmulhrsw             m3, m13
+    jmp .w16_filter_left_top16
+.w16_filter_left_h16:
+    mov                 r5d, 10
+    cmp                  hd, 16
+    cmovs               r5d, hd
+    xor                 r5d, 15 ; h == 16 ? 5 : 15 - h
+    movd                xm0, r5d
+    vpbroadcastb         m0, xm0
+.w16_filter_left_top16:
+    movu                xm2, [tlq-15]
+    vinserti128          m2, [tlq-21], 1
+    vbroadcasti128       m1, [base+z_filter_s+12]
+    vbroadcasti128       m4, [base+z_filter_s+16]
+    vinserti128          m5, m1, [base+z_filter_s+8], 1 ; 56 67 78 89 9a ab bc cd   34 45 56 67 78 89 9a ab
+    vpblendd             m1, m4, 0x0f                   ; 78 89 9a ab bc cd de ef   56 67 78 89 9a ab bc cd
+    vinserti128          m4, [base+z_filter_s+20], 0    ; 9a ab bc cd de ef ff ff   78 89 9a ab bc cd de ef
+    pmaxub               m0, m5
+    pshufb               m0, m2, m0
+    pmaddubsw            m0, m7
+    pshufb               m1, m2, m1
+    pmaddubsw            m1, m8
+    pshufb               m2, m4
+    pmaddubsw            m2, m9
+    psubb                m6, [base+pb_32to1]
+    paddw                m1, m0
+    paddw                m1, m2
+    pmulhrsw             m1, m13
+    packuswb             m3, m1
+    vpermq               m3, m3, q1320
+    vpblendvb            m3, [tlq-32], m6
+    mova           [rsp+32], m3
+.w16_main:
+    movd                xm1, dyd
+    vbroadcasti128      m10, [base+z_filter_s+2]
+    movd                xm7, dxd
+    vbroadcasti128      m11, [base+z2_shuf_h2]
+    vpbroadcastw         m1, xm1
+    vpbroadcastw         m7, xm7
+    mov                  r7, dstq
+    pmullw               m0, m1, [base+z2_ymul]
+    psllw               xm1, 4
+    paddw                m6, m7, [base+z2_base_inc]
+    lea                 r9d, [dxq+(65<<6)] ; xpos
+    movd          [rsp+156], xm1
+.w16_loop0:
+    mov                 r2d, r9d
+    mova          [rsp+160], m0
+    lea                  r5, [rsp+60] ; left-3
+    mova          [rsp+192], m6
+    pxor                 m1, m1
+    psraw                m2, m0, 6
+    pand                 m0, m14
+    psubw                m9, m1, m2   ; base_y
+    psubw               m12, m15, m0
+    punpcklwd            m8, m9, m1   ; base_y  0,  1,  2,  3,     8,  9, 10, 11
+    psllw                m0, 8
+    punpckhwd            m9, m1       ; base_y  4,  5,  6,  7,    12, 13, 14, 15
+    por                 m12, m0       ; 64-frac_y, frac_y
+.w16_loop:
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6        ; base_x0
+    movu                xm0, [rsp+r2]
+    vinserti128          m0, [rsp+r2+8], 1
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6        ; base_x1
+    movu                xm1, [rsp+r3]
+    vinserti128          m1, [rsp+r3+8], 1
+    pand                 m2, m14, m6
+    paddsw               m5, m6, m7
+    psubw                m3, m15, m2
+    psllw                m2, 8
+    pshufb               m0, m10
+    por                  m2, m3
+    pmaddubsw            m0, m2
+    pand                 m2, m14, m5
+    psubw                m3, m15, m2
+    psllw                m2, 8
+    pshufb               m1, m10
+    por                  m2, m3
+    pmaddubsw            m1, m2
+    cmp                 r3d, 64
+    jge .w16_toponly
+    punpckhwd            m2, m5, m5   ; mask out unnecessary loads
+    vpgatherdd           m4, [r5+m9], m2
+    punpcklwd            m2, m5, m5
+    vpgatherdd           m3, [r5+m8], m2
+    pshufb               m4, m11      ; e0 f0 g0 h0 e1 f1 g1 h1   m0 n0 o0 p0 m1 n1 o1 p1
+    pshufb               m3, m11      ; a0 b0 c0 d0 a1 b1 c1 d1   i0 j0 k0 l0 i1 j1 k1 l1
+    punpcklqdq           m2, m3, m4   ; y0
+    punpckhqdq           m3, m4       ; y1
+    pmaddubsw            m2, m12
+    pmaddubsw            m3, m12
+    psraw                m6, 15       ; base_x < topleft
+    vpblendvb            m0, m2, m6
+    psraw                m6, m5, 15
+    vpblendvb            m1, m3, m6
+.w16_toponly:
+    pmulhrsw             m0, m13
+    pmulhrsw             m1, m13
+    paddw                m6, m5, m7   ; xpos += dx
+    sub                  r5, 2
+    packuswb             m0, m1
+    vpermq               m0, m0, q3120
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    sub                  hd, 2
+    jz .w16_end
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r2d, (63-16)<<6
+    jge .w16_loop
+.w16_leftonly_loop:
+    mova                 m0, m7
+    vpgatherdd           m4, [r5+m9], m7
+    mova                 m7, m0
+    vpgatherdd           m3, [r5+m8], m0
+    sub                  r5, 2
+    pshufb               m2, m4, m11
+    pshufb               m1, m3, m11
+    punpcklqdq           m0, m1, m2
+    punpckhqdq           m1, m2
+    pmaddubsw            m0, m12
+    pmaddubsw            m1, m12
+    pmulhrsw             m0, m13
+    pmulhrsw             m1, m13
+    packuswb             m0, m1
+    vpermq               m0, m0, q3120
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_leftonly_loop
+.w16_end:
+    sub                 r8d, 1<<8
+    jl .w16_ret
+    vpbroadcastd         m0, [rsp+156]
+    paddw                m0, [rsp+160] ; base_y += 16*dy
+    paddw                m6, m13, [rsp+192]
+    add                  r7, 16
+    add                 r9d, 16<<6
+    movzx                hd, r8b
+    mov                dstq, r7
+    paddw                m6, m13 ; base_x += 16*64
+    jmp .w16_loop0
+.w16_ret:
+    RET
+.w32:
+    mova                 m2, [tlq+32]
+    lea                 r8d, [hq+(1<<8)]
+    mova           [rsp+96], m2
+    test             angled, 0x400
+    jnz .w16_main
+    vpbroadcastd         m7, [base+z_filter_k+4*2+12*0]
+    vpbroadcastd         m8, [base+z_filter_k+4*2+12*1]
+    vpbroadcastd         m9, [base+z_filter_k+4*2+12*2]
+    mova                xm5, [base+z_filter_s]
+    vinserti128          m5, [base+z_filter_s+10], 1 ; 00 01 12 23 34 45 56 67   45 56 67 78 89 9a ab bc
+    vinserti128          m1, [tlq+11], 1
+    movu                xm6, [base+z_filter_s+12]
+    vinserti128          m6, [base+z_filter_s+22], 1 ; 56 67 78 89 9a ab bc cd   ab bc cd de ef ff ff ff
+    movu                xm3, [tlq+ 6]
+    vinserti128          m3, [tlq+17], 1
+    vpbroadcastd        m10, r6m ; max_width
+    packssdw            m10, m10
+    packsswb            m10, m10
+.w32_filter_above:
+    pshufb               m0, m1, m5
+    shufps               m4, m5, m6, q1021           ; 12 23 34 45 56 67 78 89   67 78 89 9a ab bc cd de
+    pmaddubsw            m0, m7
+    pshufb               m2, m1, m4
+    shufps               m5, m6, q2132               ; 34 45 56 67 78 89 9a ab   89 9a ab bc cd de ef ff
+    pmaddubsw            m2, m8
+    pshufb               m1, m5
+    pmaddubsw            m1, m9
+    paddw                m0, m2
+    paddw                m0, m1
+    pshufb               m1, m3, m4
+    pmaddubsw            m1, m7
+    pshufb               m2, m3, m5
+    pmaddubsw            m2, m8
+    pshufb               m3, m6
+    pmaddubsw            m3, m9
+    paddw                m1, m2
+    paddw                m1, m3
+    pmulhrsw             m0, m13
+    pmulhrsw             m1, m13
+    psubb               m10, [base+pb_1to32]
+    packuswb             m0, m1
+    vpblendvb            m0, [tlq+1], m10
+    movu           [rsp+65], m0
+    jmp .w16_filter_left
+.w64:
+    mova                 m2, [tlq+32]
+    mov                 r3d, [tlq+64]
+    lea                 r8d, [hq+(3<<8)]
+    mova          [rsp+ 96], m2
+    mov           [rsp+128], r3d
+    test             angled, 0x400
+    jnz .w16_main
+    vpbroadcastd         m7, [base+z_filter_k+4*2+12*0]
+    vpbroadcastd         m8, [base+z_filter_k+4*2+12*1]
+    vpbroadcastd         m9, [base+z_filter_k+4*2+12*2]
+    movu                xm6, [base+z_filter_s+ 4]
+    vinserti128          m6, [base+z_filter_s+10], 1 ; 12 23 34 45 56 67 78 89   45 56 67 78 89 9a ab bc
+    movu                xm3, [tlq+30]
+    vinserti128          m3, [tlq+43], 1
+    movu                xm5, [base+z_filter_s+16]
+    vinserti128          m5, [base+z_filter_s+22], 1 ; 78 89 9a ab bc cd de ef   ab bc cd de ef ff ff ff
+    pshufb               m0, m3, m6
+    shufps               m4, m6, m5, q1021           ; 34 45 56 67 78 89 9a ab   67 78 89 9a ab bc cd de
+    pmaddubsw            m0, m7
+    pshufb               m2, m3, m4
+    shufps               m6, m5, q2132               ; 56 67 78 89 9a ab bc cd   89 9a ab bc cd de ef ff
+    pmaddubsw            m2, m8
+    pshufb               m3, m6
+    pmaddubsw            m3, m9
+    paddw                m0, m2
+    paddw                m0, m3
+    movu                xm2, [tlq+36]
+    vinserti128          m2, [tlq+49], 1
+    vpbroadcastd        m10, r6m ; max_width
+    pshufb               m4, m2, m4
+    pmaddubsw            m4, m7
+    pshufb               m3, m2, m6
+    pmaddubsw            m3, m8
+    pshufb               m2, m5
+    pmaddubsw            m2, m9
+    packssdw            m10, m10
+    paddw                m3, m4
+    paddw                m2, m3
+    vpbroadcastd         m3, [base+pb_32]
+    pmulhrsw             m0, m13
+    pmulhrsw             m2, m13
+    packsswb            m10, m10
+    mova                xm5, [base+z_filter_s]
+    vinserti128          m5, [base+z_filter_s+6], 1
+    psubb                m3, m10, m3
+    psubb                m3, [base+pb_1to32]
+    vinserti128          m1, [tlq+13], 1
+    packuswb             m0, m2
+    vpblendvb            m0, [tlq+33], m3
+    movu                xm3, [tlq+ 6]
+    vinserti128          m3, [tlq+19], 1
+    movu           [rsp+97], m0
+    jmp .w32_filter_above
+
+cglobal ipred_z3_8bpc, 4, 9, 0, dst, stride, tl, w, h, angle, dy, org_w, maxbase
+    lea                  r6, [ipred_z3_avx2_table]
+    tzcnt                hd, hm
+    movifnidn        angled, anglem
+    lea                  r7, [dr_intra_derivative+45*2-1]
+    dec                 tlq
+    movsxd               hq, [r6+hq*4]
+    sub              angled, 180
+    add                  hq, r6
+    mov                 dyd, angled
+    neg                 dyd
+    xor              angled, 0x400
+    or                  dyq, ~0x7e
+    movzx               dyd, word [r7+dyq]
+    vpbroadcastd         m3, [pw_512]
+    vpbroadcastd         m4, [pw_62]
+    vpbroadcastd         m5, [pw_64]
+    mov              org_wd, wd
+    jmp                  hq
+.h4:
+    lea                  r7, [strideq*3]
+    cmp              angleb, 40
+    jae .h4_no_upsample
+    lea                 r4d, [angleq-1024]
+    sar                 r4d, 7
+    add                 r4d, wd
+    jg .h4_no_upsample ; !enable_intra_edge_filter || w > 8 || (w == 8 && is_sm)
+    ALLOC_STACK         -32, 9
+    movu                xm8, [tlq-7]
+    pshufb              xm0, xm8, [z_upsample1-4]
+    vpbroadcastb        xm2, xm8
+    pshufb              xm1, xm8, [z_filter_s+2]
+    mova           [rsp+16], xm2 ; top[max_base_y]
+    vpbroadcastd        xm2, [pb_36_m4]
+    add                 dyd, dyd
+    pmaddubsw           xm0, xm2
+    pmaddubsw           xm1, xm2
+    movd                xm7, dyd
+    mov                 r2d, dyd
+    vpbroadcastw         m7, xm7
+    paddw               xm1, xm0
+    pmulhrsw            xm1, xm3
+    pslldq               m6, m7, 8
+    paddw               xm2, xm7, xm7
+    paddw                m6, m7
+    packuswb            xm1, xm1
+    paddw                m6, m2
+    punpcklbw           xm1, xm8
+    mova                xm8, [z_transpose4]
+    psllw                m7, 2
+    pshufb              xm1, [pb_15to0]
+    mova              [rsp], xm1
+.h4_upsample_loop:
+    lea                 r4d, [r2+dyq]
+    shr                 r2d, 6
+    vpbroadcastq         m1, [rsp+r2]
+    lea                 r2d, [r4+dyq]
+    shr                 r4d, 6
+    vpbroadcastq         m2, [rsp+r4]
+    lea                 r4d, [r2+dyq]
+    shr                 r2d, 6
+    movq                xm0, [rsp+r2]
+    lea                 r2d, [r4+dyq]
+    shr                 r4d, 6
+    movhps              xm0, [rsp+r4]
+    vpblendd             m1, m2, 0xc0
+    pand                 m2, m4, m6
+    vpblendd             m0, m1, 0xf0
+    psubw                m1, m5, m2
+    psllw                m2, 8
+    por                  m1, m2
+    pmaddubsw            m0, m1
+    paddw                m6, m7
+    pmulhrsw             m0, m3
+    vextracti128        xm1, m0, 1
+    packuswb            xm1, xm0
+    pshufb              xm1, xm8
+    movd   [dstq+strideq*0], xm1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+r7       ], xm1, 3
+    add                dstq, 4
+    sub                  wd, 4
+    jg .h4_upsample_loop
+    RET
+ALIGN function_align
+.filter_strength: ; h4/h8/h16
+%define base r4-z_filter_t0
+    lea                  r4, [z_filter_t0]
+    movd                xm0, maxbased
+    movd                xm2, angled
+    shr              angled, 8 ; is_sm << 1
+    vpbroadcastb         m0, xm0
+    vpbroadcastb         m2, xm2
+    pcmpeqb              m1, m0, [base+z_filter_wh]
+    pand                 m1, m2
+    mova                xm2, [r4+angleq*8]
+    pcmpgtb              m1, m2
+    pmovmskb            r5d, m1
+    ret
+.h4_no_upsample:
+    ALLOC_STACK         -16, 12
+    mov            maxbased, 7
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h4_main
+    lea            maxbased, [wq+3]
+    call .filter_strength
+    mov            maxbased, 7
+    test                r5d, r5d
+    jz .h4_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    vpbroadcastd         m7, [base+pb_7]
+    vbroadcasti128       m2, [tlq-14]
+    pmaxub               m1, m7, [base+z_filter_s-4]
+    vpbroadcastd         m8, [base+z_filter_k-4+r5*4+12*0]
+    pmaxub               m7, [base+z_filter_s+4]
+    vpbroadcastd         m9, [base+z_filter_k-4+r5*4+12*1]
+    vpbroadcastd        m10, [base+z_filter_k-4+r5*4+12*2]
+    pshufb               m0, m2, m1
+    shufps               m1, m7, q2121
+    pmaddubsw            m0, m8
+    pshufb               m1, m2, m1
+    pmaddubsw            m1, m9
+    pshufb               m2, m7
+    pmaddubsw            m2, m10
+    paddw                m0, m1
+    paddw                m0, m2
+    pmulhrsw             m0, m3
+    mov                 r4d, 9
+    lea                 tlq, [rsp+15]
+    cmp                  wd, 4
+    cmovne         maxbased, r4d
+    vextracti128        xm1, m0, 1
+    packuswb            xm0, xm1
+    mova              [rsp], xm0
+.h4_main:
+    movd                xm6, dyd
+    vpbroadcastq         m0, [z_base_inc] ; base_inc << 6
+    mov                  r4, tlq
+    sub                 tlq, 4
+    neg                 dyq
+    vpbroadcastw         m6, xm6
+    sub                  r4, maxbaseq
+    shl            maxbased, 6
+    vpbroadcastb         m7, [r4]
+    lea                  r4, [dyq+63] ; ypos
+    movd                xm9, maxbased
+    not            maxbased
+    vbroadcasti128       m8, [z3_shuf_w4]
+    add            maxbased, 64
+    vpbroadcastw         m9, xm9
+    psrlw                m7, 8  ; top[max_base_y]
+    paddw               m10, m6, m6
+    psubw                m9, m0 ; max_base_y
+    vpblendd             m6, m10, 0xcc
+    mova                xm0, xm10
+    paddw                m6, m0 ; ypos2 ypos3 ypos0 ypos1
+    paddw               m10, m10
+    mova               xm11, [z_transpose4]
+.h4_loop:
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6 ; base0
+    vpbroadcastq         m1, [tlq+r4]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6 ; base1
+    vpbroadcastq         m2, [tlq+r5]
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6 ; base2
+    movq                xm0, [tlq+r4]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6 ; base3
+    movhps              xm0, [tlq+r5]
+    vpblendd             m1, m2, 0xc0
+    pand                 m2, m4, m6 ; frac
+    vpblendd             m0, m1, 0xf0
+    psubw                m1, m5, m2 ; 64-frac
+    psllw                m2, 8
+    pshufb               m0, m8
+    por                  m1, m2     ; 64-frac, frac
+    pmaddubsw            m0, m1
+    pcmpgtw              m1, m9, m6 ; base < max_base_y
+    pmulhrsw             m0, m3
+    paddw                m6, m10    ; ypos += dy
+    vpblendvb            m0, m7, m0, m1
+    vextracti128        xm1, m0, 1
+    packuswb            xm1, xm0
+    pshufb              xm1, xm11   ; transpose
+    movd   [dstq+strideq*0], xm1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+r7       ], xm1, 3
+    sub                  wd, 4
+    jz .h4_end
+    add                dstq, 4
+    cmp                 r4d, maxbased
+    jg .h4_loop
+    packuswb            xm7, xm7
+.h4_end_loop:
+    movd   [dstq+strideq*0], xm7
+    movd   [dstq+strideq*1], xm7
+    movd   [dstq+strideq*2], xm7
+    movd   [dstq+r7       ], xm7
+    add                dstq, 4
+    sub                  wd, 4
+    jg .h4_end_loop
+.h4_end:
+    RET
+ALIGN function_align
+.h8:
+    lea                 r4d, [angleq+216]
+    mov                 r4b, wb
+    cmp                 r4d, 8
+    ja .h8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || w > 8
+    ALLOC_STACK         -32, 8
+    and                 r4d, 4
+    mova                xm0, [tlq-15]
+    vinserti128          m0, [tlq- 9], 1
+    movd                xm1, r4d
+    movu                xm2, [z_filter_s+2]
+    vinserti128          m2, [z_filter_s+6], 1
+    vpbroadcastb        xm1, xm1 ; w & 4
+    vpbroadcastd         m7, [pb_36_m4]
+    pmaxub              xm1, [z_upsample1-4] ; clip 4x8
+    vinserti128          m1, [z_upsample1], 1
+    add                 dyd, dyd
+    pshufb               m1, m0, m1
+    pshufb               m2, m0, m2
+    vinserti128          m0, [tlq-7], 1
+    movd                xm6, dyd
+    pmaddubsw            m1, m7
+    pmaddubsw            m2, m7
+    vpbroadcastw         m6, xm6
+    mov                 r2d, dyd
+    lea                  r5, [strideq*3]
+    paddw                m7, m6, m6
+    paddw                m1, m2
+    vpblendd             m6, m7, 0xf0
+    pmulhrsw             m1, m3
+    pslldq               m2, m7, 8
+    paddw                m7, m7
+    paddw                m6, m2
+    vbroadcasti128       m2, [pb_15to0]
+    packuswb             m1, m1
+    punpcklbw            m1, m0
+    pshufb               m1, m2
+    vextracti128   [rsp+ 0], m1, 1
+    mova           [rsp+16], xm1
+.h8_upsample_loop:
+    lea                 r4d, [r2+dyq]
+    shr                 r2d, 6 ; base0
+    movu                xm0, [rsp+r2]
+    lea                 r2d, [r4+dyq]
+    shr                 r4d, 6 ; base1
+    vinserti128          m0, [rsp+r4], 1
+    lea                 r4d, [r2+dyq]
+    shr                 r2d, 6 ; base2
+    pand                 m1, m4, m6
+    psubw                m2, m5, m1
+    psllw                m1, 8
+    por                  m2, m1
+    punpcklqdq           m1, m2, m2 ; frac0 frac1
+    pmaddubsw            m0, m1
+    movu                xm1, [rsp+r2]
+    lea                 r2d, [r4+dyq]
+    shr                 r4d, 6 ; base3
+    vinserti128          m1, [rsp+r4], 1
+    punpckhqdq           m2, m2 ; frac2 frac3
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m3
+    paddw                m6, m7
+    pmulhrsw             m1, m3
+    lea                  r4, [dstq+strideq*4]
+    psllw                m1, 8
+    por                  m0, m1
+    vextracti128        xm1, m0, 1
+    punpcklbw           xm2, xm0, xm1
+    punpckhbw           xm0, xm1
+    movd   [dstq+strideq*0], xm2
+    pextrd [dstq+strideq*1], xm2, 1
+    pextrd [dstq+strideq*2], xm2, 2
+    pextrd [dstq+r5       ], xm2, 3
+    movd   [r4  +strideq*0], xm0
+    pextrd [r4  +strideq*1], xm0, 1
+    pextrd [r4  +strideq*2], xm0, 2
+    pextrd [r4  +r5       ], xm0, 3
+    add                dstq, 4
+    sub                  wd, 4
+    jg .h8_upsample_loop
+    RET
+.h8_no_intra_edge_filter:
+    and            maxbased, 7
+    or             maxbased, 8 ; imin(w+7, 15)
+    jmp .h8_main
+.h8_no_upsample:
+    ALLOC_STACK         -32, 10
+    lea            maxbased, [wq+7]
+    test             angled, 0x400
+    jnz .h8_no_intra_edge_filter
+    call .filter_strength
+    test                r5d, r5d
+    jz .h8_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    vpbroadcastd        xm6, [base+pb_15]
+    pcmpeqb             xm1, xm1
+    psubusb             xm6, xm0
+    psubb               xm6, xm1 ; w == 4 ? 5 : 1
+    movu                xm2, [tlq-16]
+    pmaxub              xm1, xm6, [base+z_filter_s]
+    vinserti128          m2, [tlq-14], 1
+    vinserti128          m1, [base+z_filter_s+12], 1
+    vpbroadcastd         m7, [base+z_filter_k-4+r5*4+12*0]
+    pmaxub              xm6, [base+z_filter_s+ 8]
+    vinserti128          m6, [base+z_filter_s+20], 1
+    pshufb               m0, m2, m1
+    pmaddubsw            m0, m7
+    vpbroadcastd         m7, [base+z_filter_k-4+r5*4+12*1]
+    movzx               r4d, byte [tlq-15]
+    shufps               m1, m6, q2121
+    pshufb               m1, m2, m1
+    pmaddubsw            m1, m7
+    paddw                m0, m1
+    sub                 r5d, 3
+    jnz .h8_3tap
+    vpbroadcastd         m7, [z_filter_k+4*8]
+    movzx               r2d, byte [tlq-14]
+    pshufb               m2, m6
+    pmaddubsw            m2, m7
+    sub                 r2d, r4d
+    lea                 r2d, [r2+r4*8+4]
+    shr                 r2d, 3
+    mov            [rsp+15], r2b
+    paddw                m0, m2
+.h8_3tap:
+    pmulhrsw             m0, m3
+    sar                 r5d, 1
+    lea                 tlq, [rsp+31]
+    add                 r5d, 17
+    cmp                  wd, 16
+    cmovns         maxbased, r5d
+    neg                  r5
+    mov            [tlq+r5], r4b
+    vextracti128        xm1, m0, 1
+    packuswb            xm0, xm1
+    mova           [tlq-15], xm0
+.h8_main:
+    movd                xm2, dyd
+    vbroadcasti128       m0, [z_base_inc]
+    mov                  r4, tlq
+    sub                 tlq, 8
+    neg                 dyq
+    vpbroadcastw         m2, xm2
+    sub                  r4, maxbaseq
+    shl            maxbased, 6
+    vpbroadcastb         m7, [r4]
+    lea                  r4, [dyq+63]
+    movd                xm9, maxbased
+    not            maxbased
+    vbroadcasti128       m8, [z3_shuf]
+    add            maxbased, 64
+    vpbroadcastw         m9, xm9
+    psrlw                m7, 8
+    psubw                m9, m0
+    paddw                m6, m2, m2
+    vpblendd             m2, m6, 0x0f
+.h8_loop:
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6
+    pand                 m0, m4, m2
+    psubw                m1, m5, m0
+    psllw                m0, 8
+    por                  m1, m0
+    vbroadcasti128       m0, [tlq+r4]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6
+    vinserti128          m0, [tlq+r5], 0
+    sub                 rsp, 8*2
+    pshufb               m0, m8
+    pmaddubsw            m0, m1
+    pcmpgtw              m1, m9, m2
+    paddw                m2, m6
+    pmulhrsw             m0, m3
+    vpblendvb            m0, m7, m0, m1
+    vextracti128        xm1, m0, 1
+    psllw               xm0, 8
+    por                 xm0, xm1 ; interleave rows (partial transpose)
+    mova              [rsp], xm0
+    sub                  wd, 2
+    jz .h8_transpose
+    cmp                 r4d, maxbased
+    jg .h8_loop
+    packuswb            xm0, xm7, xm7
+.h8_end_loop:
+    sub                 rsp, 8*2
+    mova              [rsp], xm0
+    sub                  wd, 2
+    jg .h8_end_loop
+.h8_transpose:
+    mova                xm2, [rsp+16*1]
+    sub              org_wd, 8
+    lea                  r2, [strideq*3]
+    lea                  r6, [dstq+org_wq]
+    cmovns             dstq, r6
+    punpcklwd           xm1, xm2, xm0
+    punpckhwd           xm2, xm0
+    lea                  r6, [dstq+strideq*4]
+    jge .h8_w8
+    add                 rsp, 16*2
+    movd   [dstq+strideq*0], xm1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+r2       ], xm1, 3
+    movd   [r6  +strideq*0], xm2
+    pextrd [r6  +strideq*1], xm2, 1
+    pextrd [r6  +strideq*2], xm2, 2
+    pextrd [r6  +r2       ], xm2, 3
+    jmp .h8_end
+.h8_w8_loop:
+    mova                xm0, [rsp+16*0]
+    mova                xm2, [rsp+16*1]
+    punpcklwd           xm1, xm2, xm0
+    punpckhwd           xm2, xm0
+.h8_w8: ; w8/w16/w32
+    mova                xm0, [rsp+16*2]
+    mova                xm4, [rsp+16*3]
+    add                 rsp, 16*4
+    punpcklwd           xm3, xm4, xm0
+    punpckhwd           xm4, xm0
+    punpckldq           xm0, xm3, xm1
+    punpckhdq           xm3, xm1
+    punpckldq           xm1, xm4, xm2
+    punpckhdq           xm4, xm2
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm3
+    movhps [dstq+r2       ], xm3
+    movq   [r6  +strideq*0], xm1
+    movhps [r6  +strideq*1], xm1
+    movq   [r6  +strideq*2], xm4
+    movhps [r6  +r2       ], xm4
+    sub                dstq, 8
+    sub                  r6, 8
+    sub              org_wd, 8
+    jge .h8_w8_loop
+.h8_end:
+    RET
+.h16_no_intra_edge_filter:
+    and            maxbased, 15
+    or             maxbased, 16 ; imin(w+15, 31)
+    jmp .h16_main
+ALIGN function_align
+.h16:
+    ALLOC_STACK         -64, 12
+    lea            maxbased, [wq+15]
+    test             angled, 0x400
+    jnz .h16_no_intra_edge_filter
+    call .filter_strength
+    test                r5d, r5d
+    jz .h16_main ; filter_strength == 0
+    popcnt              r5d, r5d
+    vpbroadcastd        m11, [base+pb_27]
+    vpbroadcastd         m1, [base+pb_1]
+    vbroadcasti128       m6, [base+z_filter_s+12]
+    vinserti128          m2, m6, [base+z_filter_s+4], 0
+    vinserti128          m6, [base+z_filter_s+20], 1
+    movu               xm10, [tlq-18]
+    vinserti128         m10, [tlq-14], 1
+    vpbroadcastd         m9, [base+z_filter_k-4+r5*4+12*0]
+    vbroadcasti128       m7, [base+z_filter_s+8]
+    vinserti128          m8, m7, [base+z_filter_s+0], 0
+    vinserti128          m7, [base+z_filter_s+16], 1
+    psubusb             m11, m0
+    por                  m1, m11
+    movu               xm11, [tlq-32]
+    vinserti128         m11, [tlq-28], 1
+    pmaxub               m8, m1
+    pmaxub               m7, m1
+    pshufb               m0, m10, m2
+    shufps               m2, m6, q2121
+    pmaddubsw            m0, m9
+    pshufb               m1, m11, m8
+    shufps               m8, m7, q2121
+    pmaddubsw            m1, m9
+    vpbroadcastd         m9, [base+z_filter_k-4+r5*4+12*1]
+    movzx               r4d, byte [tlq-31]
+    pshufb               m2, m10, m2
+    pmaddubsw            m2, m9
+    pshufb               m8, m11, m8
+    pmaddubsw            m8, m9
+    paddw                m0, m2
+    paddw                m1, m8
+    sub                 r5d, 3
+    jnz .h16_3tap
+    vpbroadcastd         m9, [z_filter_k+4*8]
+    movzx               r2d, byte [tlq-30]
+    pshufb              m10, m6
+    pmaddubsw           m10, m9
+    pshufb              m11, m7
+    pmaddubsw           m11, m9
+    sub                 r2d, r4d
+    lea                 r2d, [r2+r4*8+4]
+    shr                 r2d, 3
+    mov            [rsp+31], r2b
+    paddw                m0, m10
+    paddw                m1, m11
+.h16_3tap:
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    sar                 r5d, 1
+    lea                 tlq, [rsp+63]
+    add                 r5d, 33
+    cmp                  wd, 32
+    cmovns         maxbased, r5d
+    neg                  r5
+    mov            [tlq+r5], r4b
+    packuswb             m0, m1
+    vpermq               m0, m0, q2031
+    mova           [tlq-31], m0
+.h16_main:
+    movd                xm6, dyd
+    vbroadcasti128       m0, [z_base_inc]
+    mov                  r4, tlq
+    sub                 tlq, 8
+    neg                 dyq
+    vpbroadcastw         m6, xm6
+    sub                  r4, maxbaseq
+    shl            maxbased, 6
+    vpbroadcastb         m7, [r4]
+    lea                  r4, [dyq+63]
+    movd                xm9, maxbased
+    not            maxbased
+    vbroadcasti128       m8, [z3_shuf]
+    add            maxbased, 64
+    vpbroadcastw         m9, xm9
+    psubw                m9, m0
+    paddw               m11, m6, m6
+    psubw               m10, m9, m3 ; 64*8
+    vpblendd             m6, m11, 0xf0
+.h16_loop:
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6
+    pand                 m1, m4, m6
+    psubw                m2, m5, m1
+    psllw                m1, 8
+    por                  m2, m1
+    movu                xm0, [tlq+r4-0]
+    movu                xm1, [tlq+r4-8]
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6
+    vinserti128          m0, [tlq+r5-0], 1
+    vinserti128          m1, [tlq+r5-8], 1
+    sub                 rsp, 32
+    pshufb               m0, m8
+    pshufb               m1, m8
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    pcmpgtw              m1, m9, m6
+    pcmpgtw              m2, m10, m6
+    packsswb             m1, m2
+    paddw                m6, m11
+    vpblendvb            m0, m7, m0, m1
+    vpermq               m0, m0, q3120
+    mova              [rsp], m0
+    sub                  wd, 2
+    jz .h16_transpose
+    cmp                 r4d, maxbased
+    jg .h16_loop
+    mova                 m0, m7
+.h16_end_loop:
+    sub                 rsp, 32
+    mova              [rsp], m7
+    sub                  wd, 2
+    jg .h16_end_loop
+.h16_transpose:
+    mova                 m2, [rsp+32*1]
+    sub              org_wd, 8
+    lea                  r2, [strideq*3]
+    lea                  r6, [dstq+org_wq]
+    cmovns             dstq, r6
+    punpcklbw            m1, m2, m0
+    punpckhbw            m2, m0
+    lea                  r3, [strideq*5]
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    lea                  r4, [strideq+r2*2] ; stride*7
+    jge .h16_w8
+    add                 rsp, 32*2
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r2       ], xm0, 3
+    vextracti128        xm0, m0, 1
+    movd   [dstq+strideq*4], xm1
+    pextrd [dstq+r3       ], xm1, 1
+    pextrd [dstq+r2*2     ], xm1, 2
+    pextrd [dstq+r4       ], xm1, 3
+    lea                dstq, [dstq+strideq*8]
+    vextracti128        xm1, m1, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r2       ], xm0, 3
+    movd   [dstq+strideq*4], xm1
+    pextrd [dstq+r3       ], xm1, 1
+    pextrd [dstq+r2*2     ], xm1, 2
+    pextrd [dstq+r4       ], xm1, 3
+    jmp .h16_end
+.h16_w8_loop:
+    mova                 m0, [rsp+32*0]
+    mova                 m2, [rsp+32*1]
+    punpcklbw            m1, m2, m0
+    punpckhbw            m2, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+.h16_w8:
+    mova                 m2, [rsp+32*2]
+    mova                 m4, [rsp+32*3]
+    lea                  r6, [dstq+strideq*8]
+    add                 rsp, 32*4
+    punpcklbw            m3, m4, m2
+    punpckhbw            m4, m2
+    punpcklbw            m2, m3, m4
+    punpckhbw            m3, m4
+    punpckldq            m4, m2, m0
+    punpckhdq            m2, m0
+    punpckldq            m0, m3, m1
+    punpckhdq            m3, m1
+    movq   [dstq+strideq*0], xm4
+    movhps [dstq+strideq*1], xm4
+    vextracti128        xm4, m4, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+r2       ], xm2
+    vextracti128        xm2, m2, 1
+    movq   [dstq+strideq*4], xm0
+    movhps [dstq+r3       ], xm0
+    vextracti128        xm0, m0, 1
+    movq   [dstq+r2*2     ], xm3
+    movhps [dstq+r4       ], xm3
+    vextracti128        xm3, m3, 1
+    movq     [r6+strideq*0], xm4
+    movhps   [r6+strideq*1], xm4
+    movq     [r6+strideq*2], xm2
+    movhps   [r6+r2       ], xm2
+    movq     [r6+strideq*4], xm0
+    movhps   [r6+r3       ], xm0
+    movq     [r6+r2*2     ], xm3
+    movhps   [r6+r4       ], xm3
+    sub                dstq, 8
+    sub              org_wd, 8
+    jge .h16_w8_loop
+.h16_end:
+    RET
+ALIGN function_align
+.h32:
+    ALLOC_STACK         -96, 15
+    lea            maxbased, [wq+31]
+    and            maxbased, 31
+    or             maxbased, 32 ; imin(w+31, 63)
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h32_main
+    vbroadcasti128       m0, [pb_0to15]
+    mov                 r4d, 21
+    mov                 r5d, 3
+    movu               xm11, [tlq-66]    ; 56-63
+    vinserti128         m11, [tlq-52], 1 ; 40-47
+    sub                 r4d, wd ; 21-w
+    cmovns              r5d, r4d
+    movu               xm12, [tlq-58]    ; 48-55
+    vinserti128         m12, [tlq-44], 1 ; 32-39
+    sub                 r4d, 8 ; 13-w
+    movd                xm1, r5d
+    movu               xm13, [tlq-34]    ; 24-31
+    vinserti128         m13, [tlq-20], 1 ;  8-15
+    movd                xm2, r4d
+    vpbroadcastb         m1, xm1
+    movu               xm14, [tlq-28]    ; 16-23
+    vinserti128         m14, [tlq-14], 1 ;  0- 7
+    vpbroadcastb         m2, xm2
+    pmaxsb               m1, m0 ; clip 16x32 and (32|64)x32
+    movu                 m7, [z_filter_s+4]
+    pshufb              m11, m1
+    vinserti128          m8, m7, [z_filter_s+8], 1
+    vinserti128          m7, [z_filter_s+16], 0
+    pmaxsb               m2, m0 ; clip 8x32
+    vpbroadcastd         m9, [z_filter_k+4*2+12*0]
+    pshufb              m12, m2
+    pshufb               m0, m11, m8
+    pmaddubsw            m0, m9
+    pshufb               m2, m12, m8
+    pmaddubsw            m2, m9
+    pshufb               m1, m13, m8
+    pmaddubsw            m1, m9
+    shufps               m8, m7, q1021
+    pshufb               m6, m14, m8
+    pmaddubsw            m6, m9
+    vpbroadcastd         m9, [z_filter_k+4*2+12*1]
+    pshufb              m10, m11, m8
+    pmaddubsw           m10, m9
+    paddw                m0, m10
+    pshufb              m10, m12, m8
+    pmaddubsw           m10, m9
+    paddw                m2, m10
+    pshufb              m10, m13, m8
+    pmaddubsw           m10, m9
+    shufps               m8, m7, q2121
+    paddw                m1, m10
+    pshufb              m10, m14, m8
+    pmaddubsw           m10, m9
+    paddw                m6, m10
+    vpbroadcastd         m9, [z_filter_k+4*2+12*2]
+    pshufb              m11, m8
+    pmaddubsw           m11, m9
+    pshufb              m12, m8
+    pmaddubsw           m12, m9
+    movzx               r4d, byte [tlq-63]
+    movzx               r2d, byte [tlq-62]
+    paddw                m0, m11
+    paddw                m2, m12
+    pshufb              m13, m8
+    pmaddubsw           m13, m9
+    pshufb              m14, m7
+    pmaddubsw           m14, m9
+    paddw                m1, m13
+    paddw                m6, m14
+    sub                 r2d, r4d
+    lea                 r2d, [r2+r4*8+4] ; edge case for 64x32
+    pmulhrsw             m0, m3
+    pmulhrsw             m2, m3
+    pmulhrsw             m1, m3
+    pmulhrsw             m6, m3
+    shr                 r2d, 3
+    mov            [rsp+31], r2b
+    lea                 tlq, [rsp+95]
+    mov            [tlq-65], r4b
+    mov                 r4d, 65
+    cmp                  wd, 64
+    cmove          maxbased, r4d
+    packuswb             m0, m2
+    packuswb             m1, m6
+    mova           [tlq-63], m0
+    mova           [tlq-31], m1
+.h32_main:
+    movd                xm6, dyd
+    mov                  r4, tlq
+    sub                 tlq, 8
+    neg                 dyq
+    vpbroadcastw         m6, xm6
+    sub                  r4, maxbaseq
+    shl            maxbased, 6
+    vpbroadcastb         m7, [r4]
+    lea                  r4, [dyq+63]
+    movd                xm9, maxbased
+    not            maxbased
+    vbroadcasti128       m8, [z3_shuf]
+    add            maxbased, 64
+    vpbroadcastw         m9, xm9
+    psubw                m9, [z_base_inc]
+    mova                m11, m6
+    psubw               m10, m9, m3 ; 64*8
+.h32_loop:
+    mov                  r5, r4
+    sar                  r5, 6
+    pand                 m1, m4, m6
+    psubw                m2, m5, m1
+    psllw                m1, 8
+    por                  m2, m1
+    movu                xm0, [tlq+r5- 0]
+    vinserti128          m0, [tlq+r5-16], 1
+    movu                xm1, [tlq+r5- 8]
+    vinserti128          m1, [tlq+r5-24], 1
+    sub                 rsp, 32
+    add                  r4, dyq
+    pshufb               m0, m8
+    pshufb               m1, m8
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    pcmpgtw              m1, m9, m6
+    pcmpgtw              m2, m10, m6
+    packsswb             m1, m2
+    paddw                m6, m11
+    vpblendvb            m0, m7, m0, m1
+    mova              [rsp], m0
+    dec                  wd
+    jz .h32_transpose
+    cmp                 r4d, maxbased
+    jg .h32_loop
+.h32_end_loop:
+    sub                 rsp, 32
+    mova              [rsp], m7
+    dec                  wd
+    jg .h32_end_loop
+.h32_transpose:
+    lea                dstq, [dstq+org_wq-8]
+    lea                  r2, [strideq*3]
+    lea                  r3, [strideq*5]
+    lea                  r4, [strideq+r2*2] ; stride*7
+.h32_w8_loop:
+    mova                 m7, [rsp+32*0]
+    mova                 m6, [rsp+32*1]
+    mova                 m5, [rsp+32*2]
+    mova                 m4, [rsp+32*3]
+    mova                 m3, [rsp+32*4]
+    mova                 m2, [rsp+32*5]
+    mova                 m1, [rsp+32*6]
+    mova                 m0, [rsp+32*7]
+    lea                  r6, [dstq+strideq*8]
+    add                 rsp, 32*8
+    punpcklbw            m8, m0, m1
+    punpckhbw            m0, m1
+    punpcklbw            m1, m2, m3
+    punpckhbw            m2, m3
+    punpcklbw            m3, m4, m5
+    punpckhbw            m4, m5
+    punpcklbw            m5, m6, m7
+    punpckhbw            m6, m7
+    punpcklwd            m7, m8, m1
+    punpckhwd            m8, m1
+    punpcklwd            m1, m0, m2
+    punpckhwd            m0, m2
+    punpcklwd            m2, m3, m5
+    punpckhwd            m3, m5
+    punpcklwd            m5, m4, m6
+    punpckhwd            m4, m6
+    punpckldq            m6, m7, m2
+    punpckhdq            m7, m2
+    punpckldq            m2, m8, m3
+    punpckhdq            m8, m3
+    punpckldq            m3, m1, m5
+    punpckhdq            m1, m5
+    punpckldq            m5, m0, m4
+    punpckhdq            m0, m4
+    movq   [dstq+strideq*0], xm6
+    movhps [dstq+strideq*1], xm6
+    vextracti128        xm6, m6, 1
+    movq   [dstq+strideq*2], xm7
+    movhps [dstq+r2       ], xm7
+    vextracti128        xm7, m7, 1
+    movq   [dstq+strideq*4], xm2
+    movhps [dstq+r3       ], xm2
+    vextracti128        xm2, m2, 1
+    movq   [dstq+r2*2     ], xm8
+    movhps [dstq+r4       ], xm8
+    vextracti128        xm8, m8, 1
+    movq     [r6+strideq*0], xm3
+    movhps   [r6+strideq*1], xm3
+    vextracti128        xm3, m3, 1
+    movq     [r6+strideq*2], xm1
+    movhps   [r6+r2       ], xm1
+    vextracti128        xm1, m1, 1
+    movq     [r6+strideq*4], xm5
+    movhps   [r6+r3       ], xm5
+    vextracti128        xm5, m5, 1
+    movq     [r6+r2*2     ], xm0
+    movhps   [r6+r4       ], xm0
+    lea                  r6, [r6+strideq*8]
+    vextracti128        xm0, m0, 1
+    movq     [r6+strideq*0], xm6
+    movhps   [r6+strideq*1], xm6
+    movq     [r6+strideq*2], xm7
+    movhps   [r6+r2       ], xm7
+    movq     [r6+strideq*4], xm2
+    movhps   [r6+r3       ], xm2
+    movq     [r6+r2*2     ], xm8
+    movhps   [r6+r4       ], xm8
+    lea                  r6, [r6+strideq*8]
+    movq     [r6+strideq*0], xm3
+    movhps   [r6+strideq*1], xm3
+    movq     [r6+strideq*2], xm1
+    movhps   [r6+r2       ], xm1
+    movq     [r6+strideq*4], xm5
+    movhps   [r6+r3       ], xm5
+    movq     [r6+r2*2     ], xm0
+    movhps   [r6+r4       ], xm0
+    sub                dstq, 8
+    sub              org_wd, 8
+    jg .h32_w8_loop
+    RET
+ALIGN function_align
+.h64:
+    ALLOC_STACK        -128, 16
+    lea            maxbased, [wq+63]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h64_main
+    mov                 r4d, 21
+    vpbroadcastb       xm11, [tlq-127]
+    vpblendd           xm11, [tlq-130], 0x0e ; 120-127
+    sub                 r4d, wd ; 21-w
+    mov                 r5d, 3
+    vinserti128         m11, [tlq-116], 1    ; 104-111
+    movu                 m7, [z_filter_s+4]
+    cmp                  wd, 32
+    cmove               r4d, r5d
+    vinserti128          m8, m7, [z_filter_s+8], 1
+    vbroadcasti128       m6, [pb_0to15]
+    movd                xm1, r4d
+    vpbroadcastd         m9, [z_filter_k+4*2+12*0]
+    movu               xm12, [tlq-122]       ; 112-119
+    vinserti128         m12, [tlq-108], 1    ;  96-103
+    vpbroadcastb         m1, xm1
+    movu               xm13, [tlq- 98]       ;  88- 95
+    vinserti128         m13, [tlq- 84], 1    ;  72- 79
+    movu               xm14, [tlq- 90]       ;  80- 87
+    vinserti128         m14, [tlq- 76], 1    ;  64- 71
+    vinserti128          m7, [z_filter_s+16], 0
+    pshufb               m0, m11, m8
+    pmaddubsw            m0, m9
+    pshufb               m2, m12, m8
+    pmaddubsw            m2, m9
+    pmaxsb               m1, m6 ; clip (16|32)x64
+    pshufb              m13, m1
+    pshufb               m1, m13, m8
+    pmaddubsw            m1, m9
+    pshufb               m6, m14, m8
+    pmaddubsw            m6, m9
+    vpbroadcastd         m9, [z_filter_k+4*2+12*1]
+    shufps              m15, m8, m7, q1021
+    pshufb              m10, m11, m15
+    pmaddubsw           m10, m9
+    paddw                m0, m10
+    pshufb              m10, m12, m15
+    pmaddubsw           m10, m9
+    paddw                m2, m10
+    pshufb              m10, m13, m15
+    pmaddubsw           m10, m9
+    paddw                m1, m10
+    pshufb              m10, m14, m15
+    pmaddubsw           m10, m9
+    paddw                m6, m10
+    vpbroadcastd         m9, [z_filter_k+4*2+12*2]
+    shufps              m10, m8, m7, q2132
+    pshufb              m11, m10
+    pmaddubsw           m11, m9
+    pshufb              m12, m10
+    pmaddubsw           m12, m9
+    pshufb              m13, m10
+    pmaddubsw           m13, m9
+    pshufb              m14, m10
+    pmaddubsw           m14, m9
+    paddw                m0, m11
+    paddw                m2, m12
+    paddw                m1, m13
+    paddw                m6, m14
+    movu               xm11, [tlq-66]    ; 56-63
+    vinserti128         m11, [tlq-52], 1 ; 40-47
+    movu               xm12, [tlq-58]    ; 48-55
+    vinserti128         m12, [tlq-44], 1 ; 32-39
+    movu               xm13, [tlq-34]    ; 24-31
+    vinserti128         m13, [tlq-20], 1 ;  8-15
+    movu               xm14, [tlq-28]    ; 16-23
+    vinserti128         m14, [tlq-14], 1 ;  0- 7
+    pmulhrsw             m0, m3
+    pmulhrsw             m2, m3
+    pmulhrsw             m1, m3
+    pmulhrsw             m6, m3
+    lea                 tlq, [rsp+127]
+    packuswb             m0, m2
+    packuswb             m1, m6
+    mova          [tlq-127], m0
+    mova          [tlq- 95], m1
+    pshufb               m0, m11, m10
+    pmaddubsw            m0, m9
+    pshufb               m2, m12, m10
+    pmaddubsw            m2, m9
+    pshufb               m1, m13, m10
+    pmaddubsw            m1, m9
+    pshufb               m6, m14, m7
+    pmaddubsw            m6, m9
+    vpbroadcastd         m9, [z_filter_k+4*2+12*1]
+    pshufb               m7, m11, m15
+    pmaddubsw            m7, m9
+    paddw                m0, m7
+    pshufb               m7, m12, m15
+    pmaddubsw            m7, m9
+    paddw                m2, m7
+    pshufb               m7, m13, m15
+    pmaddubsw            m7, m9
+    paddw                m1, m7
+    pshufb               m7, m14, m10
+    pmaddubsw            m7, m9
+    paddw                m6, m7
+    vpbroadcastd         m9, [z_filter_k+4*2+12*0]
+    pshufb              m11, m8
+    pmaddubsw           m11, m9
+    pshufb              m12, m8
+    pmaddubsw           m12, m9
+    pshufb              m13, m8
+    pmaddubsw           m13, m9
+    pshufb              m14, m15
+    pmaddubsw           m14, m9
+    paddw                m0, m11
+    paddw                m2, m12
+    paddw                m1, m13
+    paddw                m6, m14
+    pmulhrsw             m0, m3
+    pmulhrsw             m2, m3
+    pmulhrsw             m1, m3
+    pmulhrsw             m6, m3
+    packuswb             m0, m2
+    packuswb             m1, m6
+    mova           [tlq-63], m0
+    mova           [tlq-31], m1
+.h64_main:
+    movd               xm12, dyd
+    neg            maxbaseq
+    vbroadcasti128       m8, [z3_shuf]
+    vpbroadcastb         m7, [tlq+maxbaseq]
+    shl            maxbased, 6
+    vpbroadcastw        m12, xm12
+    lea                 r5d, [dyq+maxbaseq-64]
+    neg                 dyq
+    or             maxbased, 63
+    lea                  r4, [dyq+63]
+    movd                xm6, r5d
+    mova               xm10, [pb_1to32+16]
+    vinserti128         m10, [pb_1to32], 1
+    vpbroadcastd        m11, [pb_32]
+    vpbroadcastw         m6, xm6
+.h64_loop:
+    mov                  r5, r4
+    sar                  r5, 6
+    movu                 m0, [tlq+r5-24]
+    movu                 m1, [tlq+r5-32]
+    pand                 m2, m4, m6
+    psubw                m9, m5, m2
+    psllw                m2, 8
+    por                  m9, m2
+    pshufb               m0, m8
+    pshufb               m1, m8
+    pmaddubsw            m0, m9
+    pmaddubsw            m1, m9
+    psraw                m2, m6, 6
+    sub                 rsp, 64
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packsswb             m2, m2
+    paddb                m2, m10
+    packuswb             m0, m1
+    vpblendvb            m0, m7, m0, m2
+    mova           [rsp+32], m0
+    movu                 m0, [tlq+r5-56]
+    movu                 m1, [tlq+r5-64]
+    add                  r4, dyq
+    pshufb               m0, m8
+    pshufb               m1, m8
+    pmaddubsw            m0, m9
+    pmaddubsw            m1, m9
+    paddb                m2, m11
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    paddw                m6, m12
+    packuswb             m0, m1
+    vpblendvb            m0, m7, m0, m2
+    mova              [rsp], m0
+    dec                  wd
+    jz .h64_transpose
+    cmp                 r4d, maxbased
+    jg .h64_loop
+.h64_end_loop:
+    sub                 rsp, 64
+    mova           [rsp+32], m7
+    mova           [rsp+ 0], m7
+    dec                  wd
+    jg .h64_end_loop
+.h64_transpose:
+    lea                  r2, [strideq*3]
+    lea                  r3, [strideq*5]
+    imul                 r5, strideq, -8
+    lea                dstq, [dstq+org_wq-16]
+    lea                  r4, [strideq+r2*2] ; stride*7
+.h64_transpose_loop0:
+    lea                  r6, [rsp+16*3]
+.h64_transpose_loop:
+    mova                xm0, [r6+64*15]
+    vinserti128          m0, [r6+64* 7], 1
+    mova                xm1, [r6+64*14]
+    vinserti128          m1, [r6+64* 6], 1
+    mova                xm2, [r6+64*13]
+    vinserti128          m2, [r6+64* 5], 1
+    mova                xm3, [r6+64*12]
+    vinserti128          m3, [r6+64* 4], 1
+    mova                xm4, [r6+64*11]
+    vinserti128          m4, [r6+64* 3], 1
+    mova                xm5, [r6+64*10]
+    vinserti128          m5, [r6+64* 2], 1
+    mova                xm6, [r6+64* 9]
+    vinserti128          m6, [r6+64* 1], 1
+    mova                xm7, [r6+64* 8]
+    vinserti128          m7, [r6+64* 0], 1
+    sub                  r6, 16
+    punpcklbw            m8, m0, m1
+    punpckhbw            m0, m1
+    punpcklbw            m1, m2, m3
+    punpckhbw            m2, m3
+    punpcklbw            m3, m4, m5
+    punpckhbw            m4, m5
+    punpcklbw            m5, m6, m7
+    punpckhbw            m6, m7
+    punpcklwd            m7, m8, m1
+    punpckhwd            m8, m1
+    punpcklwd            m1, m0, m2
+    punpckhwd            m0, m2
+    punpcklwd            m2, m3, m5
+    punpckhwd            m3, m5
+    punpcklwd            m5, m4, m6
+    punpckhwd            m4, m6
+    punpckldq            m6, m7, m2
+    punpckhdq            m7, m2
+    punpckldq            m2, m8, m3
+    punpckhdq            m8, m3
+    punpckldq            m3, m1, m5
+    punpckhdq            m1, m5
+    punpckldq            m5, m0, m4
+    punpckhdq            m0, m4
+    vpermq               m6, m6, q3120
+    vpermq               m7, m7, q3120
+    vpermq               m2, m2, q3120
+    vpermq               m8, m8, q3120
+    vpermq               m3, m3, q3120
+    vpermq               m1, m1, q3120
+    vpermq               m5, m5, q3120
+    vpermq               m0, m0, q3120
+    mova         [dstq+strideq*0], xm6
+    vextracti128 [dstq+strideq*1], m6, 1
+    mova         [dstq+strideq*2], xm7
+    vextracti128 [dstq+r2       ], m7, 1
+    mova         [dstq+strideq*4], xm2
+    vextracti128 [dstq+r3       ], m2, 1
+    mova         [dstq+r2*2     ], xm8
+    vextracti128 [dstq+r4       ], m8, 1
+    sub               dstq, r5
+    mova         [dstq+strideq*0], xm3
+    vextracti128 [dstq+strideq*1], m3, 1
+    mova         [dstq+strideq*2], xm1
+    vextracti128 [dstq+r2       ], m1, 1
+    mova         [dstq+strideq*4], xm5
+    vextracti128 [dstq+r3       ], m5, 1
+    mova         [dstq+r2*2     ], xm0
+    vextracti128 [dstq+r4       ], m0, 1
+    sub                dstq, r5
+    cmp                  r6, rsp
+    jae .h64_transpose_loop
+    add                 rsp, 64*16
+    lea                dstq, [dstq+r5*8-16]
+    sub              org_wd, 16
+    jg .h64_transpose_loop0
+.h64_end:
+    RET
+
+%macro FILTER_XMM 4 ; dst, src, tmp, shuf
+%ifnum %4
+    pshufb             xm%2, xm%4
+%else
+    pshufb             xm%2, %4
+%endif
+    pshufd             xm%1, xm%2, q0000 ; p0 p1
+    pmaddubsw          xm%1, xm2
+    pshufd             xm%3, xm%2, q1111 ; p2 p3
+    pmaddubsw          xm%3, xm3
+    paddw              xm%1, xm1
+    paddw              xm%1, xm%3
+    pshufd             xm%3, xm%2, q2222 ; p4 p5
+    pmaddubsw          xm%3, xm4
+    paddw              xm%1, xm%3
+    pshufd             xm%3, xm%2, q3333 ; p6 __
+    pmaddubsw          xm%3, xm5
+    paddw              xm%1, xm%3
+    psraw              xm%1, 4
+    packuswb           xm%1, xm%1
+%endmacro
+
+%macro FILTER_YMM 4 ; dst, src, tmp, shuf
+    pshufb              m%2, m%4
+    pshufd              m%1, m%2, q0000
+    pmaddubsw           m%1, m2
+    pshufd              m%3, m%2, q1111
+    pmaddubsw           m%3, m3
+    paddw               m%1, m1
+    paddw               m%1, m%3
+    pshufd              m%3, m%2, q2222
+    pmaddubsw           m%3, m4
+    paddw               m%1, m%3
+    pshufd              m%3, m%2, q3333
+    pmaddubsw           m%3, m5
+    paddw               m%1, m%3
+    psraw               m%1, 4
+    vperm2i128          m%3, m%1, m%1, 0x01
+    packuswb            m%1, m%3
+%endmacro
+
+; The ipred_filter SIMD processes 4x2 blocks in the following order which
+; increases parallelism compared to doing things row by row. One redundant
+; block is calculated for w8 and w16, two for w32.
+;     w4     w8       w16             w32
+;     1     1 2     1 2 3 5     1 2 3 5 b c d f
+;     2     2 3     2 4 5 7     2 4 5 7 c e f h
+;     3     3 4     4 6 7 9     4 6 7 9 e g h j
+; ___ 4 ___ 4 5 ___ 6 8 9 a ___ 6 8 9 a g i j k ___
+;           5       8           8       i
+
+cglobal ipred_filter_8bpc, 3, 7, 0, dst, stride, tl, w, h, filter
+%define base r6-ipred_filter_avx2_table
+    lea                  r6, [filter_intra_taps]
+    tzcnt                wd, wm
+%ifidn filterd, filterm
+    movzx           filterd, filterb
+%else
+    movzx           filterd, byte filterm
+%endif
+    shl             filterd, 6
+    WIN64_SPILL_XMM       9, 15
+    add             filterq, r6
+    lea                  r6, [ipred_filter_avx2_table]
+    movq                xm0, [tlq-3] ; _ 6 5 0 1 2 3 4
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastd         m1, [base+pw_8]
+    vbroadcasti128       m2, [filterq+16*0]
+    vbroadcasti128       m3, [filterq+16*1]
+    vbroadcasti128       m4, [filterq+16*2]
+    vbroadcasti128       m5, [filterq+16*3]
+    add                  wq, r6
+    mov                  hd, hm
+    jmp                  wq
+.w4:
+    mova                xm8, [base+filter_shuf2]
+    sub                 tlq, 3
+    sub                 tlq, hq
+    jmp .w4_loop_start
+.w4_loop:
+    pinsrd              xm0, xm6, [tlq+hq], 0
+    lea                dstq, [dstq+strideq*2]
+.w4_loop_start:
+    FILTER_XMM            6, 0, 7, 8
+    movd   [dstq+strideq*0], xm6
+    pextrd [dstq+strideq*1], xm6, 1
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    WIN64_PUSH_XMM       10
+    mova                 m8, [base+filter_shuf1]
+    FILTER_XMM            7, 0, 6, [base+filter_shuf2]
+    vpbroadcastd         m0, [tlq+4]
+    vpbroadcastd         m6, [tlq+5]
+    sub                 tlq, 4
+    sub                 tlq, hq
+    vpbroadcastq         m7, xm7
+    vpblendd             m7, m6, 0x20
+.w8_loop:
+    vpbroadcastd        xm6, [tlq+hq]
+    palignr              m6, m0, 12
+    vpblendd             m0, m6, m7, 0xeb     ; _ _ _ _ 1 2 3 4 6 5 0 _ _ _ _ _
+                                              ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    mova                xm6, xm7
+    call .main
+    vpblendd            xm6, xm7, 0x0c
+    pshufd              xm6, xm6, q3120
+    movq   [dstq+strideq*0], xm6
+    movhps [dstq+strideq*1], xm6
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    sub                  hd, 2
+    call .w16_main
+%if WIN64
+    jmp .end
+%else
+    RET
+%endif
+.w16_main:
+    ; The spills are into the callers stack frame
+    %assign stack_size stack_size + gprsize
+    WIN64_PUSH_XMM       15, 9
+    %assign stack_size stack_size - gprsize
+    FILTER_XMM           12, 0, 7, [base+filter_shuf2]
+    vpbroadcastd         m0, [tlq+5]
+    vpblendd             m0, [tlq-12], 0x14
+    mova                 m8, [base+filter_shuf1]
+    vpbroadcastq         m7, xm12
+    vpblendd             m0, m7, 0xc2         ; _ _ _ _ 1 2 3 4 6 5 0 _ _ _ _ _
+                                              ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    call .main                                ; c0 d0 a1 b1   a1 b1 c0 d0
+    movlps              xm9, xm7, [tlq+5]     ; _ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    vinserti128         m14, m8, [base+filter_shuf3], 0
+    vpblendd           xm12, xm7, 0x0c        ; a0 b0 a1 b1
+    FILTER_XMM            6, 9, 10, 14
+    vpbroadcastq         m6, xm6              ; a2 b2 __ __ __ __ a2 b2
+    vpbroadcastd         m9, [tlq+13]
+    vpbroadcastd        m10, [tlq+12]
+    psrld               m11, m8, 4
+    vpblendd             m6, m9, 0x20         ; top
+    sub                 tlq, 6
+    sub                 tlq, hq
+.w16_loop:
+    vpbroadcastd        xm9, [tlq+hq]
+    palignr              m9, m0, 12
+    vpblendd             m0, m9, m7, 0xe2     ; _ _ _ _ 1 2 3 4 6 5 0 _ _ _ _ _
+                                              ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    mova               xm13, xm7
+    call .main                                ; e0 f0 c1 d1   c1 d1 e0 f0
+    vpblendd             m9, m12, m10, 0xf0
+    vpblendd            m12, m6, 0xc0
+    pshufd               m9, m9, q3333
+    vpblendd             m9, m6, 0xee
+    vpblendd            m10, m9, m7, 0x0c     ; _ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+                                              ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    FILTER_YMM            6, 10, 9, 14        ; c2 d2 a3 b3   a3 b3 c2 d2
+    vpblendd            m12, m6, 0x30         ; a0 b0 a1 b1   a3 b3 a2 b2
+    vpermd               m9, m11, m12         ; a0 a1 a2 a3   b0 b1 b2 b3
+    vpblendd           xm12, xm13, xm7, 0x0c  ; c0 d0 c1 d1
+    mova         [dstq+strideq*0], xm9
+    vextracti128 [dstq+strideq*1], m9, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    vpblendd            xm7, xm6, xm10, 0x04  ; _ _ _ 5 _ _ _ 6 0 _ _ _ 1 2 3 4
+    pshufd              xm7, xm7, q1032       ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    FILTER_XMM            0, 7, 9, [base+filter_shuf1+16]
+    vpblendd            xm6, xm0, 0x0c        ; c2 d2 c3 d3
+    shufps              xm0, xm12, xm6, q2020 ; c0 c1 c2 c3
+    shufps              xm6, xm12, xm6, q3131 ; d0 d1 d2 d3
+    mova   [dstq+strideq*0], xm0
+    mova   [dstq+strideq*1], xm6
+    ret
+ALIGN function_align
+.w32:
+    sub                  hd, 2
+    lea                  r3, [dstq+16]
+    lea                 r5d, [hq-2]
+    call .w16_main
+    add                 tlq, r5
+    mov                dstq, r3
+    lea                  r3, [strideq-4]
+    lea                  r4, [r3+strideq*2]
+    movq                xm0, [tlq+21]
+    pinsrd              xm0, [dstq-4], 2
+    pinsrd              xm0, [dstq+r3*1], 3
+    FILTER_XMM           12, 0, 7, 14         ; a0 b0 a0 b0
+    movq                xm7, [dstq+r3*2]
+    pinsrd              xm7, [dstq+r4], 2
+    palignr             xm7, xm0, 12          ; 0 _ _ _ _ _ _ _ _ _ _ 5 _ _ _ 6
+    vpbroadcastd         m0, [tlq+28]
+    vpbroadcastd         m9, [tlq+29]
+    vbroadcasti128       m8, [base+filter_shuf1+16]
+    vpblendd             m0, m9, 0x20
+    vpblendd             m0, m7, 0x0f
+    vpbroadcastq         m7, xm12
+    vpblendd             m0, m7, 0xc2         ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    call .main                                ; c0 d0 a1 b1   a1 b1 c0 d0
+    add                  r3, 2
+    lea                  r4, [r4+strideq*2]
+    movlps              xm9, xm7, [tlq+29]    ; _ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    vpblendd           xm12, xm7, 0x0c        ; a0 b0 a1 b1
+    FILTER_XMM            6, 9, 10, 14
+    vpbroadcastq         m6, xm6              ; a2 b2 __ __ __ __ a2 b2
+    vpbroadcastd         m9, [tlq+37]
+    vpbroadcastd        m10, [tlq+36]
+    vpblendd             m6, m9, 0x20         ; top
+.w32_loop:
+    movq                xm9, [dstq+r3*4]
+    pinsrd              xm9, [dstq+r4], 2
+.w32_loop_last:
+    palignr              m9, m0, 12
+    vpblendd             m0, m9, m7, 0xe2     ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    mova               xm13, xm7              ; c0 d0
+    call .main                                ; e0 f0 c1 d1   c1 d1 e0 f0
+    vpblendd             m9, m12, m10, 0xf0
+    vpblendd            m12, m6, 0xc0
+    pshufd               m9, m9, q3333
+    vpblendd             m9, m6, 0xee
+    vpblendd            m10, m9, m7, 0x0c     ; _ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+                                              ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    FILTER_YMM            6, 10, 9, 14        ; c2 d2 a3 b3   a3 b3 c2 d2
+    vpblendd            m12, m6, 0x30         ; a0 b0 a1 b1   a3 b3 a2 b2
+    vpermd               m9, m11, m12         ; a0 a1 a2 a3   b0 b1 b2 b3
+    vpblendd           xm12, xm13, xm7, 0x0c  ; c0 d0 c1 d1
+    mova         [dstq+strideq*0], xm9
+    vextracti128 [dstq+strideq*1], m9, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r5d, 2
+    jg .w32_loop
+    jz .w32_loop_last
+    vpblendd            xm7, xm6, xm10, 0x04  ; _ _ _ 5 _ _ _ 6 0 _ _ _ 1 2 3 4
+    pshufd              xm7, xm7, q1032       ; 0 _ _ _ 1 2 3 4 _ _ _ 5 _ _ _ 6
+    FILTER_XMM            0, 7, 9, [base+filter_shuf1+16]
+    vpblendd            xm6, xm0, 0x0c        ; c2 d2 c3 d3
+    shufps              xm0, xm12, xm6, q2020 ; c0 c1 c2 c3
+    shufps              xm6, xm12, xm6, q3131 ; d0 d1 d2 d3
+    mova   [dstq+strideq*0], xm0
+    mova   [dstq+strideq*1], xm6
+.end:
+    RET
+ALIGN function_align
+.main:
+    FILTER_YMM            7, 0, 9, 8
+    ret
+
+%if WIN64
+DECLARE_REG_TMP 5
+%else
+DECLARE_REG_TMP 7
+%endif
+
+%macro IPRED_CFL 1 ; ac in, unpacked pixels out
+    psignw               m3, m%1, m1
+    pabsw               m%1, m%1
+    pmulhrsw            m%1, m2
+    psignw              m%1, m3
+    paddw               m%1, m0
+%endmacro
+
+cglobal ipred_cfl_top_8bpc, 3, 7, 6, dst, stride, tl, w, h, ac, alpha
+    lea                  t0, [ipred_cfl_left_avx2_table]
+    tzcnt                wd, wm
+    inc                 tlq
+    movu                 m0, [tlq]
+    movifnidn            hd, hm
+    mov                 r6d, 0x8000
+    shrx                r6d, r6d, wd
+    movd                xm3, r6d
+    movsxd               r6, [t0+wq*4]
+    pcmpeqd              m2, m2
+    pmaddubsw            m0, m2
+    add                  r6, t0
+    add                  t0, ipred_cfl_splat_avx2_table-ipred_cfl_left_avx2_table
+    movsxd               wq, [t0+wq*4]
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+
+cglobal ipred_cfl_left_8bpc, 3, 7, 6, dst, stride, tl, w, h, ac, alpha
+    mov                  hd, hm ; zero upper half
+    tzcnt               r6d, hd
+    sub                 tlq, hq
+    tzcnt                wd, wm
+    movu                 m0, [tlq]
+    mov                 t0d, 0x8000
+    shrx                t0d, t0d, r6d
+    movd                xm3, t0d
+    lea                  t0, [ipred_cfl_left_avx2_table]
+    movsxd               r6, [t0+r6*4]
+    pcmpeqd              m2, m2
+    pmaddubsw            m0, m2
+    add                  r6, t0
+    add                  t0, ipred_cfl_splat_avx2_table-ipred_cfl_left_avx2_table
+    movsxd               wq, [t0+wq*4]
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+.h32:
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm1
+.h16:
+    punpckhqdq          xm1, xm0, xm0
+    paddw               xm0, xm1
+.h8:
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+.h4:
+    pmaddwd             xm0, xm2
+    pmulhrsw            xm0, xm3
+    vpbroadcastw         m0, xm0
+    jmp                  wq
+
+cglobal ipred_cfl_8bpc, 3, 7, 6, dst, stride, tl, w, h, ac, alpha
+    movifnidn            hd, hm
+    movifnidn            wd, wm
+    tzcnt               r6d, hd
+    lea                 t0d, [wq+hq]
+    movd                xm4, t0d
+    tzcnt               t0d, t0d
+    movd                xm5, t0d
+    lea                  t0, [ipred_cfl_avx2_table]
+    tzcnt                wd, wd
+    movsxd               r6, [t0+r6*4]
+    movsxd               wq, [t0+wq*4+4*4]
+    pcmpeqd              m3, m3
+    psrlw               xm4, 1
+    add                  r6, t0
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+.h4:
+    movd                xm0, [tlq-4]
+    pmaddubsw           xm0, xm3
+    jmp                  wq
+.w4:
+    movd                xm1, [tlq+1]
+    pmaddubsw           xm1, xm3
+    psubw               xm0, xm4
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    cmp                  hd, 4
+    jg .w4_mul
+    psrlw               xm0, 3
+    jmp .w4_end
+.w4_mul:
+    punpckhqdq          xm1, xm0, xm0
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x55563334
+    paddw               xm0, xm1
+    shrx                r6d, r6d, r2d
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    movd                xm1, r6d
+    psrlw               xm0, 2
+    pmulhuw             xm0, xm1
+.w4_end:
+    vpbroadcastw         m0, xm0
+.s4:
+    vpbroadcastw         m1, alpham
+    lea                  r6, [strideq*3]
+    pabsw                m2, m1
+    psllw                m2, 9
+.s4_loop:
+    mova                 m4, [acq]
+    IPRED_CFL             4
+    packuswb             m4, m4
+    vextracti128        xm5, m4, 1
+    movd   [dstq+strideq*0], xm4
+    pextrd [dstq+strideq*1], xm4, 1
+    movd   [dstq+strideq*2], xm5
+    pextrd [dstq+r6       ], xm5, 1
+    lea                dstq, [dstq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 4
+    jg .s4_loop
+    RET
+ALIGN function_align
+.h8:
+    movq                xm0, [tlq-8]
+    pmaddubsw           xm0, xm3
+    jmp                  wq
+.w8:
+    movq                xm1, [tlq+1]
+    vextracti128        xm2, m0, 1
+    pmaddubsw           xm1, xm3
+    psubw               xm0, xm4
+    paddw               xm0, xm2
+    punpckhqdq          xm2, xm0, xm0
+    paddw               xm0, xm2
+    paddw               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    psrlw               xm0, xm5
+    cmp                  hd, 8
+    je .w8_end
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    cmp                  hd, 32
+    cmove               r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+.w8_end:
+    vpbroadcastw         m0, xm0
+.s8:
+    vpbroadcastw         m1, alpham
+    lea                  r6, [strideq*3]
+    pabsw                m2, m1
+    psllw                m2, 9
+.s8_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+32]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    vextracti128        xm5, m4, 1
+    movq   [dstq+strideq*0], xm4
+    movq   [dstq+strideq*1], xm5
+    movhps [dstq+strideq*2], xm4
+    movhps [dstq+r6       ], xm5
+    lea                dstq, [dstq+strideq*4]
+    add                 acq, 64
+    sub                  hd, 4
+    jg .s8_loop
+    RET
+ALIGN function_align
+.h16:
+    mova                xm0, [tlq-16]
+    pmaddubsw           xm0, xm3
+    jmp                  wq
+.w16:
+    movu                xm1, [tlq+1]
+    vextracti128        xm2, m0, 1
+    pmaddubsw           xm1, xm3
+    psubw               xm0, xm4
+    paddw               xm0, xm2
+    paddw               xm0, xm1
+    punpckhqdq          xm1, xm0, xm0
+    paddw               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    psrlw               xm0, xm5
+    cmp                  hd, 16
+    je .w16_end
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    test                 hb, 8|32
+    cmovz               r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+.w16_end:
+    vpbroadcastw         m0, xm0
+.s16:
+    vpbroadcastw         m1, alpham
+    pabsw                m2, m1
+    psllw                m2, 9
+.s16_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+32]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    vpermq               m4, m4, q3120
+    mova         [dstq+strideq*0], xm4
+    vextracti128 [dstq+strideq*1], m4, 1
+    lea                dstq, [dstq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .s16_loop
+    RET
+ALIGN function_align
+.h32:
+    mova                 m0, [tlq-32]
+    pmaddubsw            m0, m3
+    jmp                  wq
+.w32:
+    movu                 m1, [tlq+1]
+    pmaddubsw            m1, m3
+    paddw                m0, m1
+    vextracti128        xm1, m0, 1
+    psubw               xm0, xm4
+    paddw               xm0, xm1
+    punpckhqdq          xm1, xm0, xm0
+    paddw               xm0, xm1
+    psrlq               xm1, xm0, 32
+    paddw               xm0, xm1
+    pmaddwd             xm0, xm3
+    psrlw               xm0, xm5
+    cmp                  hd, 32
+    je .w32_end
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x33345556
+    shrx                r6d, r6d, r2d
+    movd                xm1, r6d
+    pmulhuw             xm0, xm1
+.w32_end:
+    vpbroadcastw         m0, xm0
+.s32:
+    vpbroadcastw         m1, alpham
+    pabsw                m2, m1
+    psllw                m2, 9
+.s32_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+32]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    vpermq               m4, m4, q3120
+    mova             [dstq], m4
+    add                dstq, strideq
+    add                 acq, 64
+    dec                  hd
+    jg .s32_loop
+    RET
+
+cglobal ipred_cfl_128_8bpc, 3, 7, 6, dst, stride, tl, w, h, ac, alpha
+    lea                  t0, [ipred_cfl_splat_avx2_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [t0+wq*4]
+    vpbroadcastd         m0, [t0-ipred_cfl_splat_avx2_table+pw_128]
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  wq
+
+cglobal ipred_cfl_ac_420_8bpc, 4, 9, 5, ac, y, stride, wpad, hpad, w, h, sz, ac_bak
+    movifnidn         hpadd, hpadm
+    movifnidn            wd, wm
+    mov                  hd, hm
+    mov                 szd, wd
+    mov             ac_bakq, acq
+    imul                szd, hd
+    shl               hpadd, 2
+    sub                  hd, hpadd
+    vpbroadcastd         m2, [pb_2]
+    pxor                 m4, m4
+    cmp                  wd, 8
+    jg .w16
+    je .w8
+    ; fall-through
+
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h, sz, ac_bak
+.w4:
+    lea            stride3q, [strideq*3]
+.w4_loop:
+    movq                xm0, [yq]
+    movq                xm1, [yq+strideq]
+    movhps              xm0, [yq+strideq*2]
+    movhps              xm1, [yq+stride3q]
+    pmaddubsw           xm0, xm2
+    pmaddubsw           xm1, xm2
+    paddw               xm0, xm1
+    mova              [acq], xm0
+    paddw               xm4, xm0
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 16
+    sub                  hd, 2
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+    vpermq               m0, m0, q1111
+.w4_hpad_loop:
+    mova              [acq], m0
+    paddw                m4, m0
+    add                 acq, 32
+    sub               hpadd, 4
+    jg .w4_hpad_loop
+    jmp .calc_avg
+
+.w8:
+    lea            stride3q, [strideq*3]
+    test              wpadd, wpadd
+    jnz .w8_wpad
+.w8_loop:
+    mova                xm0, [yq]
+    mova                xm1, [yq+strideq]
+    vinserti128          m0, [yq+strideq*2], 1
+    vinserti128          m1, [yq+stride3q], 1
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    mova              [acq], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 2
+    jg .w8_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+    jmp .w8_hpad
+.w8_wpad:
+    vbroadcasti128       m3, [cfl_ac_w8_pad1_shuffle]
+.w8_wpad_loop:
+    movq                xm0, [yq]
+    movq                xm1, [yq+strideq]
+    vinserti128          m0, [yq+strideq*2], 1
+    vinserti128          m1, [yq+stride3q], 1
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    pshufb               m0, m3
+    mova              [acq], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 2
+    jg .w8_wpad_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+.w8_hpad:
+    vpermq               m0, m0, q3232
+.w8_hpad_loop:
+    mova              [acq], m0
+    paddw                m4, m0
+    add                 acq, 32
+    sub               hpadd, 2
+    jg .w8_hpad_loop
+    jmp .calc_avg
+
+.w16:
+    test              wpadd, wpadd
+    jnz .w16_wpad
+.w16_loop:
+    mova                 m0, [yq]
+    mova                 m1, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    mova              [acq], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 32
+    dec                  hd
+    jg .w16_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+    jmp .w16_hpad_loop
+.w16_wpad:
+    DEFINE_ARGS ac, y, stride, wpad, hpad, iptr, h, sz, ac_bak
+    lea               iptrq, [ipred_cfl_ac_420_avx2_table]
+    shl               wpadd, 2
+    mova                 m3, [iptrq+cfl_ac_w16_pad_shuffle- \
+                              ipred_cfl_ac_420_avx2_table+wpadq*8-32]
+    movsxd            wpadq, [iptrq+wpadq+4]
+    add               iptrq, wpadq
+    jmp iptrq
+.w16_pad3:
+    vpbroadcastq         m0, [yq]
+    vpbroadcastq         m1, [yq+strideq]
+    jmp .w16_wpad_end
+.w16_pad2:
+    vbroadcasti128       m0, [yq]
+    vbroadcasti128       m1, [yq+strideq]
+    jmp .w16_wpad_end
+.w16_pad1:
+    mova                 m0, [yq]
+    mova                 m1, [yq+strideq]
+    ; fall-through
+.w16_wpad_end:
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    pshufb               m0, m3
+    mova              [acq], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 32
+    dec                  hd
+    jz .w16_wpad_done
+    jmp iptrq
+.w16_wpad_done:
+    test              hpadd, hpadd
+    jz .calc_avg
+.w16_hpad_loop:
+    mova              [acq], m0
+    paddw                m4, m0
+    add                 acq, 32
+    dec               hpadd
+    jg .w16_hpad_loop
+    ; fall-through
+
+.calc_avg:
+    vpbroadcastd         m2, [pw_1]
+    pmaddwd              m0, m4, m2
+    vextracti128        xm1, m0, 1
+    tzcnt               r1d, szd
+    paddd               xm0, xm1
+    movd                xm2, r1d
+    movd                xm3, szd
+    punpckhqdq          xm1, xm0, xm0
+    paddd               xm0, xm1
+    psrad               xm3, 1
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm3
+    paddd               xm0, xm1
+    psrad               xm0, xm2
+    vpbroadcastw         m0, xm0
+.sub_loop:
+    mova                 m1, [ac_bakq]
+    psubw                m1, m0
+    mova          [ac_bakq], m1
+    add             ac_bakq, 32
+    sub                 szd, 16
+    jg .sub_loop
+    RET
+
+cglobal ipred_cfl_ac_422_8bpc, 4, 9, 6, ac, y, stride, wpad, hpad, w, h, sz, ac_bak
+    movifnidn         hpadd, hpadm
+    movifnidn            wd, wm
+    mov                  hd, hm
+    mov                 szd, wd
+    mov             ac_bakq, acq
+    imul                szd, hd
+    shl               hpadd, 2
+    sub                  hd, hpadd
+    vpbroadcastd         m2, [pb_4]
+    pxor                 m4, m4
+    pxor                 m5, m5
+    cmp                  wd, 8
+    jg .w16
+    je .w8
+    ; fall-through
+
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h, sz, ac_bak
+.w4:
+    lea            stride3q, [strideq*3]
+.w4_loop:
+    movq                xm1, [yq]
+    movhps              xm1, [yq+strideq]
+    movq                xm0, [yq+strideq*2]
+    movhps              xm0, [yq+stride3q]
+    pmaddubsw           xm0, xm2
+    pmaddubsw           xm1, xm2
+    mova              [acq], xm1
+    mova           [acq+16], xm0
+    paddw               xm4, xm0
+    paddw               xm5, xm1
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 4
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+    vpermq               m0, m0, q1111
+.w4_hpad_loop:
+    mova              [acq], m0
+    paddw                m4, m0
+    add                 acq, 32
+    sub               hpadd, 4
+    jg .w4_hpad_loop
+    jmp .calc_avg
+
+.w8:
+    lea            stride3q, [strideq*3]
+    test              wpadd, wpadd
+    jnz .w8_wpad
+.w8_loop:
+    mova                xm1, [yq]
+    vinserti128          m1, [yq+strideq], 1
+    mova                xm0, [yq+strideq*2]
+    vinserti128          m0, [yq+stride3q], 1
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m4, m0
+    paddw                m5, m1
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 64
+    sub                  hd, 4
+    jg .w8_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+    jmp .w8_hpad
+.w8_wpad:
+    vbroadcasti128       m3, [cfl_ac_w8_pad1_shuffle]
+.w8_wpad_loop:
+    movq                xm1, [yq]
+    vinserti128          m1, [yq+strideq], 1
+    movq                xm0, [yq+strideq*2]
+    vinserti128          m0, [yq+stride3q], 1
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pshufb               m0, m3
+    pshufb               m1, m3
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m4, m0
+    paddw                m5, m1
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 64
+    sub                  hd, 4
+    jg .w8_wpad_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+.w8_hpad:
+    vpermq               m0, m0, q3232
+.w8_hpad_loop:
+    mova              [acq], m0
+    paddw                m4, m0
+    add                 acq, 32
+    sub               hpadd, 2
+    jg .w8_hpad_loop
+    jmp .calc_avg
+
+.w16:
+    test              wpadd, wpadd
+    jnz .w16_wpad
+.w16_loop:
+    mova                 m1, [yq]
+    mova                 m0, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m4, m0
+    paddw                m5, m1
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+    jmp .w16_hpad_loop
+.w16_wpad:
+    DEFINE_ARGS ac, y, stride, wpad, hpad, iptr, h, sz, ac_bak
+    lea               iptrq, [ipred_cfl_ac_422_avx2_table]
+    shl               wpadd, 2
+    mova                 m3, [iptrq+cfl_ac_w16_pad_shuffle- \
+                              ipred_cfl_ac_422_avx2_table+wpadq*8-32]
+    movsxd            wpadq, [iptrq+wpadq+4]
+    add               iptrq, wpadq
+    jmp iptrq
+.w16_pad3:
+    vpbroadcastq         m1, [yq]
+    vpbroadcastq         m0, [yq+strideq]
+    jmp .w16_wpad_end
+.w16_pad2:
+    vbroadcasti128       m1, [yq]
+    vbroadcasti128       m0, [yq+strideq]
+    jmp .w16_wpad_end
+.w16_pad1:
+    mova                 m1, [yq]
+    mova                 m0, [yq+strideq]
+    ; fall-through
+.w16_wpad_end:
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pshufb               m0, m3
+    pshufb               m1, m3
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m4, m0
+    paddw                m5, m1
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jz .w16_wpad_done
+    jmp iptrq
+.w16_wpad_done:
+    test              hpadd, hpadd
+    jz .calc_avg
+.w16_hpad_loop:
+    mova              [acq], m0
+    mova           [acq+32], m0
+    paddw                m4, m0
+    paddw                m5, m0
+    add                 acq, 64
+    sub               hpadd, 2
+    jg .w16_hpad_loop
+    ; fall-through
+
+.calc_avg:
+    vpbroadcastd         m2, [pw_1]
+    pmaddwd              m5, m5, m2
+    pmaddwd              m0, m4, m2
+    paddd                m0, m5
+    vextracti128        xm1, m0, 1
+    tzcnt               r1d, szd
+    paddd               xm0, xm1
+    movd                xm2, r1d
+    movd                xm3, szd
+    punpckhqdq          xm1, xm0, xm0
+    paddd               xm0, xm1
+    psrad               xm3, 1
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm3
+    paddd               xm0, xm1
+    psrad               xm0, xm2
+    vpbroadcastw         m0, xm0
+.sub_loop:
+    mova                 m1, [ac_bakq]
+    psubw                m1, m0
+    mova          [ac_bakq], m1
+    add             ac_bakq, 32
+    sub                 szd, 16
+    jg .sub_loop
+    RET
+
+cglobal ipred_cfl_ac_444_8bpc, 4, 9, 6, ac, y, stride, wpad, hpad, w, h, sz, ac_bak
+    movifnidn         hpadd, hpadm
+    movifnidn            wd, wm
+    mov                  hd, hm
+    mov                 szd, wd
+    imul                szd, hd
+    shl               hpadd, 2
+    sub                  hd, hpadd
+    pxor                 m4, m4
+    vpbroadcastd         m5, [pw_1]
+    tzcnt               r8d, wd
+    lea                  r5, [ipred_cfl_ac_444_avx2_table]
+    movsxd               r8, [r5+r8*4+12]
+    add                  r5, r8
+
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h, sz, ac_bak
+    mov             ac_bakq, acq
+    jmp                  r5
+
+.w4:
+    lea            stride3q, [strideq*3]
+    pxor                xm2, xm2
+.w4_loop:
+    movd                xm1, [yq]
+    movd                xm0, [yq+strideq*2]
+    pinsrd              xm1, [yq+strideq], 1
+    pinsrd              xm0, [yq+stride3q], 1
+    punpcklbw           xm1, xm2
+    punpcklbw           xm0, xm2
+    psllw               xm1, 3
+    psllw               xm0, 3
+    mova              [acq], xm1
+    mova           [acq+16], xm0
+    paddw               xm1, xm0
+    paddw               xm4, xm1
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 4
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz .calc_avg_mul
+    pshufd              xm0, xm0, q3232
+    paddw               xm1, xm0, xm0
+.w4_hpad_loop:
+    mova              [acq], xm0
+    mova           [acq+16], xm0
+    paddw               xm4, xm1
+    add                 acq, 32
+    sub               hpadd, 4
+    jg .w4_hpad_loop
+    jmp .calc_avg_mul
+
+.w8:
+    lea            stride3q, [strideq*3]
+    pxor                 m2, m2
+.w8_loop:
+    movq                xm1, [yq]
+    movq                xm0, [yq+strideq*2]
+    vinserti128          m1, [yq+strideq], 1
+    vinserti128          m0, [yq+stride3q], 1
+    punpcklbw            m1, m2
+    punpcklbw            m0, m2
+    psllw                m1, 3
+    psllw                m0, 3
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m1, m0
+    paddw                m4, m1
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 64
+    sub                  hd, 4
+    jg .w8_loop
+    test              hpadd, hpadd
+    jz .calc_avg_mul
+    vpermq               m0, m0, q3232
+    paddw                m1, m0, m0
+.w8_hpad_loop:
+    mova              [acq], m0
+    mova           [acq+32], m0
+    paddw                m4, m1
+    add                 acq, 64
+    sub               hpadd, 4
+    jg .w8_hpad_loop
+    jmp .calc_avg_mul
+
+.w16:
+    test              wpadd, wpadd
+    jnz .w16_wpad
+.w16_loop:
+    pmovzxbw             m1, [yq]
+    pmovzxbw             m0, [yq+strideq]
+    psllw                m1, 3
+    psllw                m0, 3
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m1, m0
+    pmaddwd              m1, m5
+    paddd                m4, m1
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+    jmp .w16_hpad
+.w16_wpad:
+    mova                 m3, [cfl_ac_444_w16_pad1_shuffle]
+.w16_wpad_loop:
+    vpbroadcastq         m1, [yq]
+    vpbroadcastq         m0, [yq+strideq]
+    pshufb               m1, m3
+    pshufb               m0, m3
+    psllw                m1, 3
+    psllw                m0, 3
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m1, m0
+    pmaddwd              m1, m5
+    paddd                m4, m1
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_wpad_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+.w16_hpad:
+    paddw                m1, m0, m0
+    pmaddwd              m1, m5
+.w16_hpad_loop:
+    mova              [acq], m0
+    mova           [acq+32], m0
+    paddd                m4, m1
+    add                 acq, 64
+    sub               hpadd, 2
+    jg .w16_hpad_loop
+    jmp .calc_avg
+
+.w32:
+    test              wpadd, wpadd
+    jnz .w32_wpad
+.w32_loop:
+    pmovzxbw             m1, [yq]
+    pmovzxbw             m0, [yq+16]
+    psllw                m1, 3
+    psllw                m0, 3
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m2, m1, m0
+    pmaddwd              m2, m5
+    paddd                m4, m2
+    add                  yq, strideq
+    add                 acq, 64
+    dec                  hd
+    jg .w32_loop
+    test              hpadd, hpadd
+    jz .calc_avg
+    jmp .w32_hpad_loop
+.w32_wpad:
+    DEFINE_ARGS ac, y, stride, wpad, hpad, iptr, h, sz, ac_bak
+    lea               iptrq, [ipred_cfl_ac_444_avx2_table]
+    add               wpadd, wpadd
+    mova                 m3, [iptrq+cfl_ac_444_w16_pad1_shuffle-ipred_cfl_ac_444_avx2_table]
+    movsxd            wpadq, [iptrq+wpadq+4]
+    add               iptrq, wpadq
+    jmp iptrq
+.w32_pad3:
+    vpbroadcastq         m1, [yq]
+    pshufb               m1, m3
+    vpermq               m0, m1, q3232
+    jmp .w32_wpad_end
+.w32_pad2:
+    pmovzxbw             m1, [yq]
+    pshufhw              m0, m1, q3333
+    vpermq               m0, m0, q3333
+    jmp .w32_wpad_end
+.w32_pad1:
+    pmovzxbw             m1, [yq]
+    vpbroadcastq         m0, [yq+16]
+    pshufb               m0, m3
+    ; fall-through
+.w32_wpad_end:
+    psllw                m1, 3
+    psllw                m0, 3
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddw                m2, m1, m0
+    pmaddwd              m2, m5
+    paddd                m4, m2
+    add                  yq, strideq
+    add                 acq, 64
+    dec                  hd
+    jz .w32_wpad_done
+    jmp iptrq
+.w32_wpad_done:
+    test              hpadd, hpadd
+    jz .calc_avg
+.w32_hpad_loop:
+    mova              [acq], m1
+    mova           [acq+32], m0
+    paddd                m4, m2
+    add                 acq, 64
+    dec               hpadd
+    jg .w32_hpad_loop
+    jmp .calc_avg
+
+.calc_avg_mul:
+    pmaddwd              m4, m5
+.calc_avg:
+    vextracti128        xm1, m4, 1
+    tzcnt               r1d, szd
+    paddd               xm0, xm4, xm1
+    movd                xm2, r1d
+    movd                xm3, szd
+    punpckhqdq          xm1, xm0, xm0
+    paddd               xm0, xm1
+    psrad               xm3, 1
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm3
+    paddd               xm0, xm1
+    psrad               xm0, xm2
+    vpbroadcastw         m0, xm0
+.sub_loop:
+    mova                 m1, [ac_bakq]
+    psubw                m1, m0
+    mova          [ac_bakq], m1
+    add             ac_bakq, 32
+    sub                 szd, 16
+    jg .sub_loop
+    RET
+
+cglobal pal_pred_8bpc, 4, 6, 5, dst, stride, pal, idx, w, h
+    vpbroadcastq         m4, [palq]
+    lea                  r2, [pal_pred_avx2_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r2+wq*4]
+    add                  wq, r2
+    lea                  r2, [strideq*3]
+    jmp                  wq
+.w4:
+    movq                xm0, [idxq]
+    add                idxq, 8
+    psrlw               xm1, xm0, 4
+    punpcklbw           xm0, xm1
+    pshufb              xm0, xm4, xm0
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r2       ], xm0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    movu                xm2, [idxq]
+    add                idxq, 16
+    pshufb              xm1, xm4, xm2
+    psrlw               xm2, 4
+    pshufb              xm2, xm4, xm2
+    punpcklbw           xm0, xm1, xm2
+    punpckhbw           xm1, xm2
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r2       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    movu                 m2, [idxq]
+    add                idxq, 32
+    pshufb               m1, m4, m2
+    psrlw                m2, 4
+    pshufb               m2, m4, m2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova         [dstq+strideq*0], xm0
+    mova         [dstq+strideq*1], xm1
+    vextracti128 [dstq+strideq*2], m0, 1
+    vextracti128 [dstq+r2       ], m1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16
+    RET
+.w32:
+    vpermq               m2, [idxq], q3120
+    add                idxq, 32
+    pshufb               m1, m4, m2
+    psrlw                m2, 4
+    pshufb               m2, m4, m2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32
+    RET
+.w64:
+    vpermq               m2, [idxq], q3120
+    add                idxq, 32
+    pshufb               m1, m4, m2
+    psrlw                m2, 4
+    pshufb               m2, m4, m2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w64
+    RET
+
+%endif
diff --git a/media/libdav1d/src/src/x86/ipred_avx512.asm b/media/libdav1d/src/src/x86/ipred_avx512.asm
new file mode 100644
index 0000000000..de953deba3
--- /dev/null
+++ b/media/libdav1d/src/src/x86/ipred_avx512.asm
@@ -0,0 +1,3143 @@
+; Copyright © 2020, VideoLAN and dav1d authors
+; Copyright © 2020, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+%macro SMOOTH_WEIGHT_TABLE 1-*
+    %rep %0
+        db %1-128, 127-%1
+        %rotate 1
+    %endrep
+%endmacro
+
+smooth_weights: SMOOTH_WEIGHT_TABLE         \
+      0,   0, 255, 128, 255, 149,  85,  64, \
+    255, 197, 146, 105,  73,  50,  37,  32, \
+    255, 225, 196, 170, 145, 123, 102,  84, \
+     68,  54,  43,  33,  26,  20,  17,  16, \
+    255, 240, 225, 210, 196, 182, 169, 157, \
+    145, 133, 122, 111, 101,  92,  83,  74, \
+     66,  59,  52,  45,  39,  34,  29,  25, \
+     21,  17,  14,  12,  10,   9,   8,   8, \
+    255, 248, 240, 233, 225, 218, 210, 203, \
+    196, 189, 182, 176, 169, 163, 156, 150, \
+    144, 138, 133, 127, 121, 116, 111, 106, \
+    101,  96,  91,  86,  82,  77,  73,  69, \
+     65,  61,  57,  54,  50,  47,  44,  41, \
+     38,  35,  32,  29,  27,  25,  22,  20, \
+     18,  16,  15,  13,  12,  10,   9,   8, \
+      7,   6,   6,   5,   5,   4,   4,   4
+
+; dav1d_filter_intra_taps[], reordered for VNNI: p1 p2 p3 p4, p6 p5 p0 __
+filter_taps:  db 10,  0,  0,  0,  2, 10,  0,  0,  1,  1, 10,  0,  1,  1,  2, 10
+              db  6,  0,  0,  0,  2,  6,  0,  0,  2,  2,  6,  0,  1,  2,  2,  6
+              db  0, 12, -6,  0,  0,  9, -5,  0,  0,  7, -3,  0,  0,  5, -3,  0
+              db 12,  2, -4,  0,  9,  2, -3,  0,  7,  2, -3,  0,  5,  3, -3,  0
+              db 16,  0,  0,  0,  0, 16,  0,  0,  0,  0, 16,  0,  0,  0,  0, 16
+              db 16,  0,  0,  0,  0, 16,  0,  0,  0,  0, 16,  0,  0,  0,  0, 16
+              db  0, 10,-10,  0,  0,  6, -6,  0,  0,  4, -4,  0,  0,  2, -2,  0
+              db 10,  0,-10,  0,  6,  0, -6,  0,  4,  0, -4,  0,  2,  0, -2,  0
+              db  8,  0,  0,  0,  0,  8,  0,  0,  0,  0,  8,  0,  0,  0,  0,  8
+              db  4,  0,  0,  0,  0,  4,  0,  0,  0,  0,  4,  0,  0,  0,  0,  4
+              db  0, 16, -8,  0,  0, 16, -8,  0,  0, 16, -8,  0,  0, 16, -8,  0
+              db 16,  0, -4,  0, 16,  0, -4,  0, 16,  0, -4,  0, 16,  0, -4,  0
+              db  8,  0,  0,  0,  3,  8,  0,  0,  2,  3,  8,  0,  1,  2,  3,  8
+              db  4,  0,  0,  0,  3,  4,  0,  0,  2,  3,  4,  0,  2,  2,  3,  4
+              db  0, 10, -2,  0,  0,  6, -1,  0,  0,  4, -1,  0,  0,  2,  0,  0
+              db 10,  3, -1,  0,  6,  4, -1,  0,  4,  4, -1,  0,  3,  3, -1,  0
+              db 14,  0,  0,  0,  0, 14,  0,  0,  0,  0, 14,  0,  0,  0,  0, 14
+              db 12,  0,  0,  0,  1, 12,  0,  0,  0,  0, 12,  0,  0,  0,  1, 12
+              db  0, 14,-12,  0,  0, 12,-10,  0,  0, 11, -9,  0,  0, 10, -8,  0
+              db 14,  0,-10,  0, 12,  0, -9,  0, 11,  1, -8,  0,  9,  1, -7,  0
+filter_perm:  db  0,  1,  2,  3, 24, 25, 26, 27,  4,  5,  6,  7, 28, 29, 30, 31
+              db 15, 11,  7,  3, 15, 11,  7,  3, 15, 11,  7,  3, 15, 11,  7,131
+              db 31, 27, 23, 19, 31, 27, 23, 19, 31, 27, 23, 19, 31, 27, 23,147
+              db 47, 43, 39, 35, 47, 43, 39, 35, 47, 43, 39, 35, 47, 43, 39,163
+filter_end:   dd  2,  3, 16, 17, -1, -1, 20, 21,  0,  6, 24, 30,  1,  7, 25, 31
+smooth_shuf:  db  7,  7,  7,  7,  0,  1,  0,  1,  3,  3,  3,  3,  8,  9,  8,  9
+              db  5,  5,  5,  5,  4,  5,  4,  5,  1,  1,  1,  1, 12, 13, 12, 13
+              db  6,  6,  6,  6,  2,  3,  2,  3,  2,  2,  2,  2, 10, 11, 10, 11
+              db  4,  4,  4,  4,  6,  7,  6,  7,  0,  0,  0,  0, 14, 15, 14, 15
+smooth_endA:  db  1,  3,  5,  7,  9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31
+              db 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63
+              db 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95
+              db 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127
+smooth_endB:  db  1,  3,  5,  7,  9, 11, 13, 15, 65, 67, 69, 71, 73, 75, 77, 79
+              db 17, 19, 21, 23, 25, 27, 29, 31, 81, 83, 85, 87, 89, 91, 93, 95
+              db 33, 35, 37, 39, 41, 43, 45, 47, 97, 99,101,103,105,107,109,111
+              db 49, 51, 53, 55, 57, 59, 61, 63,113,115,117,119,121,123,125,127
+ipred_h_shuf: db  7,  7,  7,  7,  6,  6,  6,  6,  5,  5,  5,  5,  4,  4,  4,  4
+              db  3,  3,  3,  3,  2,  2,  2,  2,  1,  1,  1,  1,  0,  0,  0,  0
+pal_unpack:   db  0,  4,  8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60
+pal_perm:     db  0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+pb_63to0:     db 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48
+              db 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32
+              db 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16
+              db 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0
+z_frac_table: db 64,  0, 62,  2, 60,  4, 58,  6, 56,  8, 54, 10, 52, 12, 50, 14
+              db 48, 16, 46, 18, 44, 20, 42, 22, 40, 24, 38, 26, 36, 28, 34, 30
+              db 32, 32, 30, 34, 28, 36, 26, 38, 24, 40, 22, 42, 20, 44, 18, 46
+              db 16, 48, 14, 50, 12, 52, 10, 54,  8, 56,  6, 58,  4, 60,  2, 62
+z_filter_s1:  db -1, -1, -1,  0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6
+              db 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22
+              db 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38
+              db 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54
+z_filter_s5:  db 10,  9, 11, 10, 12, 11, 13, 12, 14, 13, 15, 14, 16, 15, 17, 16
+              db 26, 25, 27, 26, 28, 27, 29, 28, 30, 29, 31, 30, 32, 31, 33, 32
+              db 42, 41, 43, 42, 44, 43, 45, 44, 46, 45, 47, 46, 48, 47, 49, 48
+              db 58, 57, 59, 58, 60, 59, 61, 60, 62, 61, 63, 62, 64, 63, 65, 64
+z_filter_s3:  db  0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+z_filter_s2:  db  6,  7,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14
+z_filter_s4:  db  2,  1,  3,  2,  4,  3,  5,  4,  6,  5,  7,  6,  8,  7,  9,  8
+z_xpos_bc:    db 17, 17, 17, 17, 33, 33, 33, 33,  9,  9,  9,  9,  9,  9,  9,  9
+z_filter4_s1: db  0,  0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7
+              db  7,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8
+z_xpos_off1a: db 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72
+z_xpos_off1b: db 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80
+z_xpos_off2a: db  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8
+              db 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24
+              db 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40
+              db 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56
+z_xpos_off2b: db  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16
+              db 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32
+              db 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48
+              db 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64
+z_xpos_mul:   dw  4,  4,  4,  4,  8,  8,  4,  4, 12, 12,  8,  8, 16, 16,  8,  8
+              dw 20, 20, 12, 12, 24, 24, 12, 12, 28, 28, 16, 16, 32, 32, 16, 16
+z_ypos_off1:  db 64, 65, 64, 65, 64, 65, 64, 65, 65, 66, 65, 66, 66, 67, 66, 67
+              db 66, 67, 66, 67, 68, 69, 68, 69, 67, 68, 67, 68, 70, 71, 70, 71
+              db 68, 69, 68, 69, 72, 73, 72, 73, 69, 70, 69, 70, 74, 75, 74, 75
+              db 70, 71, 70, 71, 76, 77, 76, 77, 71, 72, 71, 72, 78, 79, 78, 79
+z_ypos_off2:  db 64, 65, 64, 65,  0,  0,  0,  0, 64, 65, 64, 65,  0,  0,  0,  0
+              db 65, 66, 65, 66,  1,  1,  1,  1, 65, 66, 65, 66,  1,  1,  1,  1
+              db 66, 67, 66, 67,  2,  2,  2,  2, 66, 67, 66, 67,  2,  2,  2,  2
+              db 67, 68, 67, 68,  3,  3,  3,  3, 67, 68, 67, 68,  3,  3,  3,  3
+z_ypos_off3:  db  1,  2,  1,  2,  1,  1,  1,  1,  3,  4,  3,  4,  1,  1,  1,  1
+              db  5,  6,  5,  6,  3,  3,  3,  3,  7,  8,  7,  8,  3,  3,  3,  3
+              db  9, 10,  9, 10,  5,  5,  5,  5, 11, 12, 11, 12,  5,  5,  5,  5
+              db 13, 14, 13, 14,  7,  7,  7,  7, 15, 16, 15, 16,  7,  7,  7,  7
+z_ypos_mul1a: dw  1,  2,  3,  4,  5,  6,  7,  8, 17, 18, 19, 20, 21, 22, 23, 24
+              dw 33, 34, 35, 36, 37, 38, 39, 40, 49, 50, 51, 52, 53, 54, 55, 56
+z_ypos_mul1b: dw  9, 10, 11, 12, 13, 14, 15, 16, 25, 26, 27, 28, 29, 30, 31, 32
+              dw 41, 42, 43, 44, 45, 46, 47, 48, 57, 58, 59, 60, 61, 62, 63, 64
+z_ypos_mul2a: dw  1*512,  2*512,  3*512,  4*512,  5*512,  6*512,  7*512,  8*512
+              dw 17*512, 18*512, 19*512, 20*512, 21*512, 22*512, 23*512, 24*512
+              dw 33*512, 34*512, 35*512, 36*512, 37*512, 38*512, 39*512, 40*512
+              dw 49*512, 50*512, 51*512, 52*512, 53*512, 54*512, 55*512, 56*512
+z_ypos_mul2b: dw  9*512, 10*512, 11*512, 12*512, 13*512, 14*512, 15*512, 16*512
+              dw 25*512, 26*512, 27*512, 28*512, 29*512, 30*512, 31*512, 32*512
+              dw 41*512, 42*512, 43*512, 44*512, 45*512, 46*512, 47*512, 48*512
+              dw 57*512, 58*512, 59*512, 60*512, 61*512, 62*512, 63*512, 64*512
+z_filter_t0:  db 55,127, 39,127, 39,127,  7, 15, 31,  7, 15, 31,  0,  3, 31,  0
+z_filter_t1:  db 39, 63, 19, 47, 19, 47,  3,  3,  3,  3,  3,  3,  0,  0,  0,  0
+z3_upsample:  db 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16
+              db 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,  9,  8
+z_filter_wh:  db  7,  7, 11, 11, 15, 15, 19, 19, 19, 23, 23, 23, 31, 31, 31, 39
+              db 39, 39, 47, 47, 47, 79, 79, 79
+z_filter_k:   db  0, 16,  0, 16,  0, 20,  0, 20,  8, 16,  8, 16
+              db 32,  0, 32,  0, 24,  0, 24,  0, 16,  0, 16,  0
+              db  0, 32,  0, 32,  0, 24,  0, 24,  0, 16,  0, 16
+
+pb_8_56_0_0:  db  8, 56,  0,  0
+pb_m4_36:     times 2 db -4, 36
+pb_127_m127:  times 2 db 127, -127
+pb_8:         times 4 db 8
+pb_15:        times 4 db 15
+pb_16:        times 4 db 16
+pb_31:        times 4 db 31
+pb_63:        times 4 db 63
+pb_90:        times 4 db 90
+pb_128:       times 4 db 128
+pw_128:       times 2 dw 128
+pw_255:       times 2 dw 255
+pw_512:       times 2 dw 512
+
+%define pb_1  (ipred_h_shuf+24)
+%define pb_2  (ipred_h_shuf+20)
+%define pb_3  (ipred_h_shuf+16)
+%define pb_4  (smooth_shuf +48)
+%define pb_7  (ipred_h_shuf+ 0)
+%define pb_9  (z_xpos_bc   + 8)
+%define pb_17 (z_xpos_bc   + 0)
+%define pb_33 (z_xpos_bc   + 4)
+%define pd_8  (filter_taps+128)
+
+%macro JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - 2*4)
+    %xdefine %%base mangle(private_prefix %+ _%1_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%base %+ .%3 - (%%table - 2*4)
+        %rotate 1
+    %endrep
+%endmacro
+
+%define ipred_dc_splat_8bpc_avx512icl_table (ipred_dc_8bpc_avx512icl_table + 10*4)
+
+JMP_TABLE ipred_h_8bpc,          avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_paeth_8bpc,      avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_8bpc,     avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_v_8bpc,   avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_h_8bpc,   avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z1_8bpc,         avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z2_8bpc,         avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z3_8bpc,         avx512icl, w4, w8, w16, w32, w64
+JMP_TABLE ipred_dc_8bpc,         avx512icl, h4, h8, h16, h32, h64, w4, w8, w16, w32, w64, \
+                                       s4-10*4, s8-10*4, s16-10*4, s32-10*4, s64-10*4
+JMP_TABLE ipred_dc_left_8bpc,    avx512icl, h4, h8, h16, h32, h64
+
+cextern dr_intra_derivative
+cextern pb_0to63
+
+SECTION .text
+
+INIT_ZMM avx512icl
+cglobal ipred_dc_top_8bpc, 3, 7, 5, dst, stride, tl, w, h
+    lea                  r5, [ipred_dc_left_8bpc_avx512icl_table]
+    movd                xm0, wm
+    tzcnt                wd, wm
+    inc                 tlq
+    movifnidn            hd, hm
+    movu                ym1, [tlq]
+    movd               xmm3, wd
+    movsxd               r6, [r5+wq*4]
+    vpbroadcastd        ym2, [r5-ipred_dc_left_8bpc_avx512icl_table+pb_1]
+    psrld               xm0, 1
+    vpdpbusd            ym0, ym1, ym2
+    add                  r6, r5
+    add                  r5, ipred_dc_splat_8bpc_avx512icl_table-ipred_dc_left_8bpc_avx512icl_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+
+cglobal ipred_dc_left_8bpc, 3, 7, 5, dst, stride, tl, w, h, stride3
+    lea                  r5, [ipred_dc_left_8bpc_avx512icl_table]
+    mov                  hd, hm
+    tzcnt               r6d, hd
+    sub                 tlq, hq
+    tzcnt                wd, wm
+    movd                xm0, hm
+    movu                ym1, [tlq]
+    movd               xmm3, r6d
+    movsxd               r6, [r5+r6*4]
+    vpbroadcastd        ym2, [r5-ipred_dc_left_8bpc_avx512icl_table+pb_1]
+    psrld               xm0, 1
+    vpdpbusd            ym0, ym1, ym2
+    add                  r6, r5
+    add                  r5, ipred_dc_splat_8bpc_avx512icl_table-ipred_dc_left_8bpc_avx512icl_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+.h64:
+    movu                ym1, [tlq+32] ; unaligned when jumping here from dc_top
+    vpdpbusd            ym0, ym1, ym2
+.h32:
+    vextracti32x4       xm1, ym0, 1
+    paddd               xm0, xm1
+.h16:
+    punpckhqdq          xm1, xm0, xm0
+    paddd               xm0, xm1
+.h8:
+    psrlq               xm1, xm0, 32
+    paddd               xm0, xm1
+.h4:
+    vpsrlvd             xm0, xmm3
+    lea            stride3q, [strideq*3]
+    vpbroadcastb         m0, xm0
+    jmp                  wq
+
+cglobal ipred_dc_8bpc, 3, 7, 5, dst, stride, tl, w, h, stride3
+    movifnidn            hd, hm
+    movifnidn            wd, wm
+    tzcnt               r6d, hd
+    lea                 r5d, [wq+hq]
+    movd                xm0, r5d
+    tzcnt               r5d, r5d
+    movd               xmm4, r5d
+    lea                  r5, [ipred_dc_8bpc_avx512icl_table]
+    tzcnt                wd, wd
+    movsxd               r6, [r5+r6*4]
+    movsxd               wq, [r5+wq*4+5*4]
+    vpbroadcastd        ym3, [r5-ipred_dc_8bpc_avx512icl_table+pb_1]
+    psrld               xm0, 1
+    add                  r6, r5
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  r6
+.h4:
+    movd               xmm1, [tlq-4]
+    vpdpbusd            xm0, xmm1, xm3
+    jmp                  wq
+.w4:
+    movd               xmm1, [tlq+1]
+    vpdpbusd            xm0, xmm1, xm3
+    cmp                  hd, 4
+    jg .w4_mul
+    psrlw              xmm0, xm0, 3
+    jmp .w4_end
+.w4_mul:
+    punpckhqdq         xmm1, xm0, xm0
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x55563334
+    paddd              xmm1, xm0
+    shrx                r6d, r6d, r2d
+    psrlq              xmm0, xmm1, 32
+    paddd              xmm0, xmm1
+    movd               xmm1, r6d
+    psrld              xmm0, 2
+    pmulhuw            xmm0, xmm1
+.w4_end:
+    vpbroadcastb        xm0, xmm0
+.s4:
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm0
+    movd   [dstq+strideq*2], xm0
+    movd   [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s4
+    RET
+.h8:
+    movq               xmm1, [tlq-8]
+    vpdpbusd            xm0, xmm1, xm3
+    jmp                  wq
+.w8:
+    movq               xmm1, [tlq+1]
+    vextracti32x4       xm2, ym0, 1
+    vpdpbusd            xm0, xmm1, xm3
+    paddd              xmm2, xm2, xm0
+    punpckhqdq         xmm0, xmm2, xmm2
+    paddd              xmm0, xmm2
+    psrlq              xmm1, xmm0, 32
+    paddd              xmm0, xmm1
+    vpsrlvd            xmm0, xmm4
+    cmp                  hd, 8
+    je .w8_end
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    cmp                  hd, 32
+    cmove               r6d, r2d
+    movd               xmm1, r6d
+    pmulhuw            xmm0, xmm1
+.w8_end:
+    vpbroadcastb        xm0, xmm0
+.s8:
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm0
+    movq   [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s8
+    RET
+.h16:
+    mova               xmm1, [tlq-16]
+    vpdpbusd            xm0, xmm1, xm3
+    jmp                  wq
+.w16:
+    movu               xmm1, [tlq+1]
+    vextracti32x4       xm2, ym0, 1
+    vpdpbusd            xm0, xmm1, xm3
+    paddd              xmm2, xm2, xm0
+    punpckhqdq         xmm0, xmm2, xmm2
+    paddd              xmm0, xmm2
+    psrlq              xmm1, xmm0, 32
+    paddd              xmm0, xmm1
+    vpsrlvd            xmm0, xmm4
+    cmp                  hd, 16
+    je .w16_end
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    test                 hb, 8|32
+    cmovz               r6d, r2d
+    movd               xmm1, r6d
+    pmulhuw            xmm0, xmm1
+.w16_end:
+    vpbroadcastb        xm0, xmm0
+.s16:
+    mova   [dstq+strideq*0], xm0
+    mova   [dstq+strideq*1], xm0
+    mova   [dstq+strideq*2], xm0
+    mova   [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s16
+    RET
+.h32:
+    mova                ym1, [tlq-32]
+    vpdpbusd            ym0, ym1, ym3
+    jmp                  wq
+.w32:
+    movu                ym1, [tlq+1]
+    vpdpbusd            ym0, ym1, ym3
+    vextracti32x4       xm1, ym0, 1
+    paddd              xmm1, xm1, xm0
+    punpckhqdq         xmm0, xmm1, xmm1
+    paddd              xmm0, xmm1
+    psrlq              xmm1, xmm0, 32
+    paddd              xmm0, xmm1
+    vpsrlvd            xmm0, xmm4
+    cmp                  hd, 32
+    je .w32_end
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x33345556
+    shrx                r6d, r6d, r2d
+    movd               xmm1, r6d
+    pmulhuw            xmm0, xmm1
+.w32_end:
+    vpbroadcastb        ym0, xmm0
+.s32:
+    mova   [dstq+strideq*0], ym0
+    mova   [dstq+strideq*1], ym0
+    mova   [dstq+strideq*2], ym0
+    mova   [dstq+stride3q ], ym0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s32
+    RET
+.h64:
+    mova                ym1, [tlq-64]
+    mova                ym2, [tlq-32]
+    vpdpbusd            ym0, ym1, ym3
+    vpdpbusd            ym0, ym2, ym3
+    jmp                  wq
+.w64:
+    movu                ym1, [tlq+ 1]
+    movu                ym2, [tlq+33]
+    vpdpbusd            ym0, ym1, ym3
+    vpdpbusd            ym0, ym2, ym3
+    vextracti32x4       xm1, ym0, 1
+    paddd              xmm1, xm1, xm0
+    punpckhqdq         xmm0, xmm1, xmm1
+    paddd              xmm0, xmm1
+    psrlq              xmm1, xmm0, 32
+    paddd              xmm0, xmm1
+    vpsrlvd            xmm0, xmm4
+    cmp                  hd, 64
+    je .w64_end
+    mov                 r6d, 0x33345556
+    shrx                r6d, r6d, hd
+    movd               xmm1, r6d
+    pmulhuw            xmm0, xmm1
+.w64_end:
+    vpbroadcastb         m0, xmm0
+.s64:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m0
+    mova   [dstq+strideq*2], m0
+    mova   [dstq+stride3q ], m0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .s64
+    RET
+
+cglobal ipred_dc_128_8bpc, 2, 7, 5, dst, stride, tl, w, h, stride3
+    lea                  r5, [ipred_dc_splat_8bpc_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    vpbroadcastd         m0, [r5-ipred_dc_splat_8bpc_avx512icl_table+pb_128]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+cglobal ipred_v_8bpc, 3, 7, 5, dst, stride, tl, w, h, stride3
+    lea                  r5, [ipred_dc_splat_8bpc_avx512icl_table]
+    tzcnt                wd, wm
+    movu                 m0, [tlq+1]
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+cglobal ipred_h_8bpc, 3, 7, 8, dst, stride, tl, w, h, stride3
+%define base r6-ipred_h_8bpc_avx512icl_table
+    lea                  r6, [ipred_h_8bpc_avx512icl_table]
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    lea            stride3q, [strideq*3]
+    sub                 tlq, hq
+    add                  wq, r6
+    jmp                  wq
+.w4:
+    mova               xmm1, [base+ipred_h_shuf+16]
+.w4_loop:
+    movd               xmm0, [tlq+hq-4]
+    pshufb             xmm0, xmm1
+    movd   [dstq+strideq*0], xmm0
+    pextrd [dstq+strideq*1], xmm0, 1
+    pextrd [dstq+strideq*2], xmm0, 2
+    pextrd [dstq+stride3q ], xmm0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+.w8:
+    movsldup           xmm2, [base+ipred_h_shuf+16]
+    movshdup           xmm3, [base+ipred_h_shuf+16]
+.w8_loop:
+    movd               xmm1, [tlq+hq-4]
+    pshufb             xmm0, xmm1, xmm2
+    pshufb             xmm1, xmm3
+    movq   [dstq+strideq*0], xmm0
+    movq   [dstq+strideq*1], xmm1
+    movhps [dstq+strideq*2], xmm0
+    movhps [dstq+stride3q ], xmm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.w16:
+    movsldup             m1, [base+smooth_shuf]
+.w16_loop:
+    vpbroadcastd         m0, [tlq+hq-4]
+    pshufb               m0, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16
+    RET
+.w32:
+    vpbroadcastd        ym3, [base+pb_1]
+    vpord                m2, m3, [base+pb_2] {1to16}
+.w32_loop:
+    vpbroadcastd         m1, [tlq+hq-4]
+    pshufb               m0, m1, m2
+    pshufb               m1, m3
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+stride3q ], m1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w32_loop
+    RET
+.w64:
+    vpbroadcastd         m4, [base+pb_3]
+    vpbroadcastd         m5, [base+pb_2]
+    vpbroadcastd         m6, [base+pb_1]
+    pxor                 m7, m7
+.w64_loop:
+    vpbroadcastd         m3, [tlq+hq-4]
+    pshufb               m0, m3, m4
+    pshufb               m1, m3, m5
+    pshufb               m2, m3, m6
+    pshufb               m3, m7
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+stride3q ], m3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w64_loop
+    RET
+
+%macro PAETH 0
+    psubusb              m1, m5, m4
+    psubusb              m0, m4, m5
+    por                  m1, m0           ; tdiff
+    pavgb                m2, m6, m4
+    vpcmpub              k1, m1, m7, 1    ; tdiff < ldiff
+    vpblendmb        m0{k1}, m4, m6
+    vpternlogd           m4, m6, m8, 0x28 ; (m4 ^ m6) & m8
+    psubusb              m3, m5, m2
+    psubb                m2, m4
+    psubusb              m2, m5
+    por                  m2, m3
+    pminub               m1, m7
+    paddusb              m2, m2
+    por                  m2, m4           ; min(tldiff, 255)
+    vpcmpub              k1, m2, m1, 1    ; tldiff < ldiff && tldiff < tdiff
+    vmovdqu8         m0{k1}, m5
+%endmacro
+
+cglobal ipred_paeth_8bpc, 3, 7, 10, dst, stride, tl, w, h, top, stride3
+    lea                  r6, [ipred_paeth_8bpc_avx512icl_table]
+    tzcnt                wd, wm
+    vpbroadcastb         m5, [tlq] ; topleft
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastd         m8, [r6-ipred_paeth_8bpc_avx512icl_table+pb_1]
+    lea                topq, [tlq+1]
+    sub                 tlq, hq
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+INIT_YMM avx512icl
+.w4:
+    vpbroadcastd         m6, [topq]
+    mova                 m9, [ipred_h_shuf]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0 ; ldiff
+.w4_loop:
+    vpbroadcastq         m4, [tlq+hq-8]
+    pshufb               m4, m9 ; left
+    PAETH
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+stride3q ], xm0, 3
+    sub                  hd, 8
+    jl .w4_ret
+    vextracti32x4       xm0, m0, 1
+    lea                dstq, [dstq+strideq*4]
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+stride3q ], xm0, 3
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.w4_ret:
+    RET
+INIT_ZMM avx512icl
+.w8:
+    vpbroadcastq         m6, [topq]
+    movsldup             m9, [smooth_shuf]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w8_loop:
+    vpbroadcastq         m4, [tlq+hq-8]
+    pshufb               m4, m9
+    PAETH
+    vextracti32x4       xm1, m0, 2
+    vextracti32x4       xm2, ym0, 1
+    vextracti32x4       xm3, m0, 3
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm2
+    movq   [dstq+stride3q ], xm3
+    sub                  hd, 8
+    jl .w8_ret
+    lea                dstq, [dstq+strideq*4]
+    movhps [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm3
+    lea                dstq, [dstq+strideq*4]
+    jg .w8_loop
+.w8_ret:
+    RET
+.w16:
+    vbroadcasti32x4      m6, [topq]
+    movsldup             m9, [smooth_shuf]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w16_loop:
+    vpbroadcastd         m4, [tlq+hq-4]
+    pshufb               m4, m9
+    PAETH
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32:
+    vbroadcasti32x8      m6, [topq]
+    mova                ym9, ym8
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w32_loop:
+    vpbroadcastd         m4, [tlq+hq-2]
+    pshufb               m4, m9
+    PAETH
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64:
+    movu                 m6, [topq]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w64_loop:
+    vpbroadcastb         m4, [tlq+hq-1]
+    PAETH
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+
+cglobal ipred_smooth_v_8bpc, 3, 7, 7, dst, stride, tl, w, h, weights, stride3
+%define base r6-ipred_smooth_v_8bpc_avx512icl_table
+    lea                  r6, [ipred_smooth_v_8bpc_avx512icl_table]
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastd         m0, [base+pb_127_m127]
+    vpbroadcastd         m1, [base+pw_128]
+    lea            weightsq, [base+smooth_weights+hq*4]
+    neg                  hq
+    vpbroadcastb         m4, [tlq+hq] ; bottom
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    vpbroadcastd         m2, [tlq+1]
+    movshdup             m5, [smooth_shuf]
+    mova                ym6, [smooth_endA]
+    punpcklbw            m2, m4 ; top, bottom
+    pmaddubsw            m3, m2, m0
+    paddw                m1, m2 ;   1 * top + 256 * bottom + 128, overflow is ok
+    paddw                m3, m1 ; 128 * top + 129 * bottom + 128
+.w4_loop:
+    vbroadcasti32x4      m0, [weightsq+hq*2]
+    pshufb               m0, m5
+    pmaddubsw            m0, m2, m0
+    paddw                m0, m3
+    vpermb               m0, m6, m0
+    vextracti32x4       xm1, ym0, 1
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+stride3q ], xm1, 2
+    add                  hq, 8
+    jg .ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm0, 3
+    pextrd [dstq+stride3q ], xm1, 3
+    lea                dstq, [dstq+strideq*4]
+    jl .w4_loop
+.ret:
+    RET
+.w8:
+    vpbroadcastq         m2, [tlq+1]
+    movshdup             m5, [smooth_shuf]
+    mova                ym6, [smooth_endA]
+    punpcklbw            m2, m4
+    pmaddubsw            m3, m2, m0
+    paddw                m1, m2
+    paddw                m3, m1
+.w8_loop:
+    vpbroadcastq         m0, [weightsq+hq*2]
+    pshufb               m0, m5
+    pmaddubsw            m0, m2, m0
+    paddw                m0, m3
+    vpermb               m0, m6, m0
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w8_loop
+    RET
+.w16:
+    vbroadcasti32x4      m3, [tlq+1]
+    movshdup             m6, [smooth_shuf]
+    mova                 m7, [smooth_endB]
+    punpcklbw            m2, m3, m4
+    punpckhbw            m3, m4
+    pmaddubsw            m4, m2, m0
+    pmaddubsw            m5, m3, m0
+    paddw                m0, m1, m2
+    paddw                m1, m3
+    paddw                m4, m0
+    paddw                m5, m1
+.w16_loop:
+    vpbroadcastq         m1, [weightsq+hq*2]
+    pshufb               m1, m6
+    pmaddubsw            m0, m2, m1
+    pmaddubsw            m1, m3, m1
+    paddw                m0, m4
+    paddw                m1, m5
+    vpermt2b             m0, m7, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w16_loop
+    RET
+.w32:
+    vbroadcasti32x8      m3, [tlq+1]
+    movshdup             m6, [smooth_shuf]
+    mova                 m7, [smooth_endB]
+    punpcklbw            m2, m3, m4
+    punpckhbw            m3, m4
+    pmaddubsw            m4, m2, m0
+    pmaddubsw            m5, m3, m0
+    paddw                m0, m1, m2
+    paddw                m1, m3
+    paddw                m4, m0
+    paddw                m5, m1
+.w32_loop:
+    vpbroadcastd         m1, [weightsq+hq*2]
+    pshufb               m1, m6
+    pmaddubsw            m0, m2, m1
+    pmaddubsw            m1, m3, m1
+    paddw                m0, m4
+    paddw                m1, m5
+    vpermt2b             m0, m7, m1
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    add                  hq, 2
+    jl .w32_loop
+    RET
+.w64:
+    movu                 m3, [tlq+1]
+    mova                 m6, [smooth_endB]
+    punpcklbw            m2, m3, m4
+    punpckhbw            m3, m4
+    pmaddubsw            m4, m2, m0
+    pmaddubsw            m5, m3, m0
+    paddw                m0, m1, m2
+    paddw                m1, m3
+    paddw                m4, m0
+    paddw                m5, m1
+.w64_loop:
+    vpbroadcastw         m1, [weightsq+hq*2]
+    pmaddubsw            m0, m2, m1
+    pmaddubsw            m1, m3, m1
+    paddw                m0, m4
+    paddw                m1, m5
+    vpermt2b             m0, m6, m1
+    mova             [dstq], m0
+    add                dstq, strideq
+    inc                  hq
+    jl .w64_loop
+    RET
+
+cglobal ipred_smooth_h_8bpc, 4, 7, 11, dst, stride, tl, w, h, stride3
+%define base r5-ipred_smooth_h_8bpc_avx512icl_table
+    lea                  r5, [ipred_smooth_h_8bpc_avx512icl_table]
+    mov                 r6d, wd
+    tzcnt                wd, wd
+    vpbroadcastb         m4, [tlq+r6] ; right
+    mov                  hd, hm
+    movsxd               wq, [r5+wq*4]
+    vpbroadcastd         m5, [base+pb_127_m127]
+    vpbroadcastd         m6, [base+pw_128]
+    sub                 tlq, hq
+    add                  wq, r5
+    vpmovb2m             k1, m6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    movsldup             m3, [smooth_shuf]
+    vpbroadcastq         m7, [smooth_weights+4*2]
+    mova                ym8, [smooth_endA]
+.w4_loop:
+    vpbroadcastq         m0, [tlq+hq-8]
+    mova                 m2, m4
+    vpshufb          m2{k1}, m0, m3 ; left, right
+    pmaddubsw            m0, m2, m5
+    pmaddubsw            m1, m2, m7
+    paddw                m2, m6
+    paddw                m0, m2
+    paddw                m0, m1
+    vpermb               m0, m8, m0
+    vextracti32x4       xm1, ym0, 1
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+stride3q ], xm1, 2
+    sub                  hd, 8
+    jl .ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm0, 3
+    pextrd [dstq+stride3q ], xm1, 3
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.ret:
+    RET
+.w8:
+    movsldup             m3, [smooth_shuf]
+    vbroadcasti32x4      m7, [smooth_weights+8*2]
+    mova                ym8, [smooth_endA]
+.w8_loop:
+    vpbroadcastd         m0, [tlq+hq-4]
+    mova                 m2, m4
+    vpshufb          m2{k1}, m0, m3
+    pmaddubsw            m0, m2, m5
+    pmaddubsw            m1, m2, m7
+    paddw                m2, m6
+    paddw                m0, m2
+    paddw                m0, m1
+    vpermb               m0, m8, m0
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.w16:
+    movsldup             m7, [smooth_shuf]
+    vbroadcasti32x4      m8, [smooth_weights+16*2]
+    vbroadcasti32x4      m9, [smooth_weights+16*3]
+    mova                m10, [smooth_endB]
+.w16_loop:
+    vpbroadcastd         m0, [tlq+hq-4]
+    mova                 m3, m4
+    vpshufb          m3{k1}, m0, m7
+    pmaddubsw            m2, m3, m5
+    pmaddubsw            m0, m3, m8
+    pmaddubsw            m1, m3, m9
+    paddw                m3, m6
+    paddw                m2, m3
+    paddw                m0, m2
+    paddw                m1, m2
+    vpermt2b             m0, m10, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32:
+    mova                m10, [smooth_endA]
+    vpbroadcastd        ym7, [pb_1]
+    vbroadcasti32x8      m8, [smooth_weights+32*2]
+    vbroadcasti32x8      m9, [smooth_weights+32*3]
+    vshufi32x4          m10, m10, q3120
+.w32_loop:
+    vpbroadcastd         m0, [tlq+hq-2]
+    mova                 m3, m4
+    vpshufb          m3{k1}, m0, m7
+    pmaddubsw            m2, m3, m5
+    pmaddubsw            m0, m3, m8
+    pmaddubsw            m1, m3, m9
+    paddw                m3, m6
+    paddw                m2, m3
+    paddw                m0, m2
+    paddw                m1, m2
+    vpermt2b             m0, m10, m1
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64:
+    mova                 m7, [smooth_weights+64*2]
+    mova                 m8, [smooth_weights+64*3]
+    mova                 m9, [smooth_endA]
+.w64_loop:
+    mova                 m3, m4
+    vpbroadcastb     m3{k1}, [tlq+hq-1]
+    pmaddubsw            m2, m3, m5
+    pmaddubsw            m0, m3, m7
+    pmaddubsw            m1, m3, m8
+    paddw                m3, m6
+    paddw                m2, m3
+    paddw                m0, m2
+    paddw                m1, m2
+    vpermt2b             m0, m9, m1
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+
+cglobal ipred_smooth_8bpc, 4, 7, 16, dst, stride, tl, w, h, v_weights, stride3
+%define base r5-ipred_smooth_8bpc_avx512icl_table
+    lea                  r5, [ipred_smooth_8bpc_avx512icl_table]
+    mov                 r6d, wd
+    tzcnt                wd, wd
+    mov                  hd, hm
+    vpbroadcastb         m6, [tlq+r6] ; right
+    sub                 tlq, hq
+    movsxd               wq, [r5+wq*4]
+    vpbroadcastd         m7, [base+pb_127_m127]
+    vpbroadcastb         m0, [tlq]    ; bottom
+    vpbroadcastd         m1, [base+pw_255]
+    add                  wq, r5
+    lea          v_weightsq, [base+smooth_weights+hq*2]
+    vpmovb2m             k1, m1
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    vpbroadcastd         m8, [tlq+hq+1]
+    movsldup             m4, [smooth_shuf]
+    movshdup             m5, [smooth_shuf]
+    vpbroadcastq         m9, [smooth_weights+4*2]
+    mova               ym11, [smooth_endA]
+
+    punpcklbw            m8, m0     ; top, bottom
+    pmaddubsw           m10, m8, m7
+    paddw                m1, m8     ;   1 * top + 256 * bottom + 255
+    paddw               m10, m1     ; 128 * top + 129 * bottom + 255
+.w4_loop:
+    vpbroadcastq         m1, [tlq+hq-8]
+    vbroadcasti32x4      m0, [v_weightsq]
+    add          v_weightsq, 16
+    mova                 m2, m6
+    vpshufb          m2{k1}, m1, m4 ; left, right
+    pmaddubsw            m1, m2, m7 ; 127 * left - 127 * right
+    pshufb               m0, m5
+    pmaddubsw            m0, m8, m0
+    paddw                m1, m2     ; 128 * left + 129 * right
+    pmaddubsw            m2, m9
+    paddw                m0, m10
+    paddw                m1, m2
+    pavgw                m0, m1
+    vpermb               m0, m11, m0
+    vextracti32x4       xm1, ym0, 1
+    movd   [dstq+strideq*0], xm0
+    movd   [dstq+strideq*1], xm1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+stride3q ], xm1, 2
+    sub                  hd, 8
+    jl .ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 1
+    pextrd [dstq+strideq*1], xm1, 1
+    pextrd [dstq+strideq*2], xm0, 3
+    pextrd [dstq+stride3q ], xm1, 3
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.ret:
+    RET
+.w8:
+    vpbroadcastq         m8, [tlq+hq+1]
+    movsldup             m4, [smooth_shuf]
+    movshdup             m5, [smooth_shuf]
+    vbroadcasti32x4      m9, [smooth_weights+8*2]
+    mova               ym11, [smooth_endA]
+    punpcklbw            m8, m0
+    pmaddubsw           m10, m8, m7
+    paddw                m1, m8
+    paddw               m10, m1
+.w8_loop:
+    vpbroadcastd         m1, [tlq+hq-4]
+    vpbroadcastq         m0, [v_weightsq]
+    add          v_weightsq, 8
+    mova                 m2, m6
+    vpshufb          m2{k1}, m1, m4
+    pmaddubsw            m1, m2, m7
+    pshufb               m0, m5
+    pmaddubsw            m0, m8, m0
+    paddw                m1, m2
+    pmaddubsw            m2, m9
+    paddw                m0, m10
+    paddw                m1, m2
+    pavgw                m0, m1
+    vpermb               m0, m11, m0
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.w16:
+    vbroadcasti32x4      m9, [tlq+hq+1]
+    movsldup             m5, [smooth_shuf]
+    movshdup            m10, [smooth_shuf]
+    vbroadcasti32x4     m11, [smooth_weights+16*2]
+    vbroadcasti32x4     m12, [smooth_weights+16*3]
+    mova                m15, [smooth_endB]
+    punpcklbw            m8, m9, m0
+    punpckhbw            m9, m0
+    pmaddubsw           m13, m8, m7
+    pmaddubsw           m14, m9, m7
+    paddw                m0, m1, m8
+    paddw                m1, m9
+    paddw               m13, m0
+    paddw               m14, m1
+.w16_loop:
+    vpbroadcastd         m0, [tlq+hq-4]
+    vpbroadcastq         m1, [v_weightsq]
+    add          v_weightsq, 8
+    mova                 m4, m6
+    vpshufb          m4{k1}, m0, m5
+    pmaddubsw            m2, m4, m7
+    pshufb               m1, m10
+    pmaddubsw            m0, m8, m1
+    pmaddubsw            m1, m9, m1
+    paddw                m2, m4
+    pmaddubsw            m3, m4, m11
+    pmaddubsw            m4, m12
+    paddw                m0, m13
+    paddw                m1, m14
+    paddw                m3, m2
+    paddw                m4, m2
+    pavgw                m0, m3
+    pavgw                m1, m4
+    vpermt2b             m0, m15, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32:
+    vbroadcasti32x8      m9, [tlq+hq+1]
+    movshdup            m10, [smooth_shuf]
+    mova                m12, [smooth_weights+32*2]
+    vpbroadcastd        ym5, [pb_1]
+    mova                m15, [smooth_endB]
+    punpcklbw            m8, m9, m0
+    punpckhbw            m9, m0
+    pmaddubsw           m13, m8, m7
+    pmaddubsw           m14, m9, m7
+    vshufi32x4          m11, m12, m12, q2020
+    vshufi32x4          m12, m12, q3131
+    paddw                m0, m1, m8
+    paddw                m1, m9
+    paddw               m13, m0
+    paddw               m14, m1
+.w32_loop:
+    vpbroadcastd         m0, [tlq+hq-2]
+    vpbroadcastd         m1, [v_weightsq]
+    add          v_weightsq, 4
+    mova                 m4, m6
+    vpshufb          m4{k1}, m0, m5
+    pmaddubsw            m2, m4, m7
+    pshufb               m1, m10
+    pmaddubsw            m0, m8, m1
+    pmaddubsw            m1, m9, m1
+    paddw                m2, m4
+    pmaddubsw            m3, m4, m11
+    pmaddubsw            m4, m12
+    paddw                m0, m13
+    paddw                m1, m14
+    paddw                m3, m2
+    paddw                m4, m2
+    pavgw                m0, m3
+    pavgw                m1, m4
+    vpermt2b             m0, m15, m1
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64:
+    movu                 m9, [tlq+hq+1]
+    mova                m11, [smooth_weights+64*2]
+    mova                 m2, [smooth_weights+64*3]
+    mova                m14, [smooth_endB]
+    punpcklbw            m8, m9, m0
+    punpckhbw            m9, m0
+    pmaddubsw           m12, m8, m7
+    pmaddubsw           m13, m9, m7
+    vshufi32x4          m10, m11, m2, q2020
+    vshufi32x4          m11, m2, q3131
+    paddw                m0, m1, m8
+    paddw                m1, m9
+    paddw               m12, m0
+    paddw               m13, m1
+.w64_loop:
+    mova                 m4, m6
+    vpbroadcastb     m4{k1}, [tlq+hq-1]
+    vpbroadcastw         m1, [v_weightsq]
+    add          v_weightsq, 2
+    pmaddubsw            m2, m4, m7
+    pmaddubsw            m0, m8, m1
+    pmaddubsw            m1, m9, m1
+    paddw                m2, m4
+    pmaddubsw            m3, m4, m10
+    pmaddubsw            m4, m11
+    paddw                m0, m12
+    paddw                m1, m13
+    paddw                m3, m2
+    paddw                m4, m2
+    pavgw                m0, m3
+    pavgw                m1, m4
+    vpermt2b             m0, m14, m1
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+
+cglobal pal_pred_8bpc, 4, 7, 6, dst, stride, pal, idx, w, h, stride3
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    lea            stride3q, [strideq*3]
+    cmp                  wd, 8
+    jg .w32
+    movq               xmm3, [palq]
+    je .w8
+.w4:
+    movq               xmm0, [idxq]
+    add                idxq, 8
+    psrlw              xmm1, xmm0, 4
+    punpcklbw          xmm0, xmm1
+    pshufb             xmm0, xmm3, xmm0
+    movd   [dstq+strideq*0], xmm0
+    pextrd [dstq+strideq*1], xmm0, 1
+    pextrd [dstq+strideq*2], xmm0, 2
+    pextrd [dstq+stride3q ], xmm0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    movu               xmm2, [idxq]
+    add                idxq, 16
+    pshufb             xmm1, xmm3, xmm2
+    psrlw              xmm2, 4
+    pshufb             xmm2, xmm3, xmm2
+    punpcklbw          xmm0, xmm1, xmm2
+    punpckhbw          xmm1, xmm2
+    movq   [dstq+strideq*0], xmm0
+    movhps [dstq+strideq*1], xmm0
+    movq   [dstq+strideq*2], xmm1
+    movhps [dstq+stride3q ], xmm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    pmovzxdq             m0, [idxq]
+    add                idxq, 32
+    vpmultishiftqb       m0, m3, m0
+    pshufb               m0, m5, m0
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16
+    RET
+.w32:
+    vpbroadcastq         m3, [pal_unpack+0]
+    vpbroadcastq         m5, [palq]
+    cmp                  wd, 32
+    jl .w16
+    pmovzxbd             m2, [pal_perm]
+    vpbroadcastq         m4, [pal_unpack+8]
+    jg .w64
+.w32_loop:
+    vpermd               m1, m2, [idxq]
+    add                idxq, 64
+    vpmultishiftqb       m0, m3, m1
+    vpmultishiftqb       m1, m4, m1
+    pshufb               m0, m5, m0
+    pshufb               m1, m5, m1
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+stride3q ], m1, 1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w32_loop
+    RET
+.w64:
+    vpermd               m1, m2, [idxq]
+    add                idxq, 64
+    vpmultishiftqb       m0, m3, m1
+    vpmultishiftqb       m1, m4, m1
+    pshufb               m0, m5, m0
+    pshufb               m1, m5, m1
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w64
+    RET
+
+%if WIN64
+    DECLARE_REG_TMP 4
+%else
+    DECLARE_REG_TMP 8
+%endif
+
+cglobal ipred_z1_8bpc, 3, 8, 16, dst, stride, tl, w, h, angle, dx
+%define base r7-z_filter_t0
+    lea                  r7, [z_filter_t0]
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    lea                  t0, [dr_intra_derivative]
+    movsxd               wq, [base+ipred_z1_8bpc_avx512icl_table+wq*4]
+    inc                 tlq
+    mov                 dxd, angled
+    and                 dxd, 0x7e
+    add              angled, 165 ; ~90
+    movzx               dxd, word [t0+dxq]
+    lea                  wq, [base+ipred_z1_8bpc_avx512icl_table+wq]
+    movifnidn            hd, hm
+    xor              angled, 0x4ff ; d = 90 - angle
+    mova                m14, [base+z_frac_table]
+    vpbroadcastd        m15, [base+pw_512]
+    jmp                  wq
+.w4:
+    mova                 m9, [pb_0to63]
+    pminud               m8, m9, [base+pb_7] {1to16}
+    vpbroadcastq         m7, [tlq]
+    pshufb               m7, m8
+    cmp              angleb, 40
+    jae .w4_no_upsample
+    lea                 r3d, [angleq-1024]
+    sar                 r3d, 7
+    add                 r3d, hd
+    jg .w4_no_upsample ; !enable_intra_edge_filter || h > 8 || (h == 8 && is_sm)
+    pshufb             xmm0, xm7, [base+z_filter_s4]
+    mova               xmm1, [tlq-1]
+    pshufb             xmm1, [base+z_xpos_off2a]
+    vpbroadcastd       xmm2, [base+pb_m4_36]
+    vpbroadcastq         m4, [pb_0to63]
+    pmaddubsw          xmm0, xmm2
+    pmaddubsw          xmm1, xmm2
+    add                 dxd, dxd
+    kxnorw               k1, k1, k1
+    paddw              xmm0, xmm1
+    pmulhrsw            xm0, xmm0, xm15
+    packuswb            xm0, xm0
+    punpcklbw       ym7{k1}, ym0
+    jmp .w4_main2
+.w4_no_upsample:
+    test             angled, 0x400
+    jnz .w4_main ; !enable_intra_edge_filter
+    lea                 r3d, [hq+3]
+    vpbroadcastb        xm0, r3d
+    vpbroadcastb        xm1, angled
+    shr              angled, 8 ; is_sm << 1
+    vpcmpeqb             k1, xm0, [base+z_filter_wh]
+    vpcmpgtb         k1{k1}, xm1, [base+z_filter_t0+angleq*8]
+    kmovw               r5d, k1
+    test                r5d, r5d
+    jz .w4_main
+    vbroadcasti32x4     ym0, [tlq-1]
+    pshufb              ym0, [base+z_filter4_s1]
+    popcnt              r5d, r5d ; filter_strength
+    pshufb              ym1, ym7, [z_filter_s4]
+    pshufb              ym7, [base+z_filter_s3]
+    vpbroadcastd       ym11, [base+z_filter_k+(r5-1)*4+12*0]
+    vpbroadcastd       ym12, [base+z_filter_k+(r5-1)*4+12*1]
+    pmaddubsw           ym0, ym11
+    pmaddubsw           ym1, ym11
+    pmaddubsw           ym7, ym12
+    paddw               ym0, ym1
+    paddw               ym7, ym0
+    pmulhrsw            ym7, ym15
+    cmp                  hd, 4
+    je .w4_filter_end
+    vpbroadcastd         m8, [base+pb_9]
+    pminub               m8, m9
+.w4_filter_end:
+    paddb                m8, m8
+    vpermb               m7, m8, m7
+.w4_main:
+    vpbroadcastq         m4, [base+z_xpos_off1a]
+.w4_main2:
+    movsldup             m2, [base+z_xpos_mul]
+    vpbroadcastw         m5, dxd
+    vbroadcasti32x4      m3, [base+z_xpos_bc]
+    lea                  r2, [strideq*3]
+    pmullw               m2, m5      ; xpos
+    psllw                m5, 5       ; dx*8
+.w4_loop:
+    psrlw                m1, m2, 3
+    pshufb               m0, m2, m3
+    vpermw               m1, m1, m14 ; 64-frac, frac
+    paddsb               m0, m4      ; base, base+1
+    vpermb               m0, m0, m7  ; top[base], top[base+1]
+    paddsw               m2, m5      ; xpos += dx
+    pmaddubsw            m0, m1      ; v
+    pmulhrsw             m0, m15
+    packuswb             m0, m0
+    vextracti32x4       xm1, ym0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+r2       ], xm1, 1
+    sub                  hd, 8
+    jl .w4_end
+    vextracti32x4       xm1, m0, 2 ; top[max_base_x]
+    lea                dstq, [dstq+strideq*4]
+    vextracti32x4       xm0, m0, 3
+    movd   [dstq+strideq*0], xm1
+    pextrd [dstq+strideq*1], xm1, 1
+    movd   [dstq+strideq*2], xm0
+    pextrd [dstq+r2       ], xm0, 1
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.w4_end:
+    RET
+.w8_filter:
+    mova                ym0, [base+z_filter_s1]
+    popcnt              r5d, r5d
+    vbroadcasti32x4     ym1, [base+z_filter_s2]
+    vbroadcasti32x4     ym3, [base+z_filter_s3]
+    vbroadcasti32x4     ym4, [base+z_filter_s4]
+    vpermi2b            ym0, ym7, ym2 ; al bl
+    mova                ym5, [base+z_filter_s5]
+    pshufb              ym1, ym7, ym1 ; ah bh
+    vpbroadcastd       ym11, [base+z_filter_k+(r5-1)*4+12*0]
+    pshufb              ym3, ym7, ym3 ; cl ch
+    vpbroadcastd       ym12, [base+z_filter_k+(r5-1)*4+12*1]
+    pshufb              ym4, ym7, ym4 ; el dl
+    vpbroadcastd       ym13, [base+z_filter_k+(r5-1)*4+12*2]
+    vpermb              ym5, ym5, ym7 ; eh dh
+    pmaddubsw           ym0, ym11
+    pmaddubsw           ym1, ym11
+    pmaddubsw           ym2, ym3, ym12
+    pmaddubsw           ym3, ym13
+    pmaddubsw           ym4, ym11
+    pmaddubsw           ym5, ym11
+    paddw               ym0, ym2
+    paddw               ym1, ym3
+    paddw               ym0, ym4
+    paddw               ym1, ym5
+    pmulhrsw            ym0, ym15
+    pmulhrsw            ym1, ym15
+    packuswb            ym0, ym1
+    ret
+.w8:
+    lea                 r3d, [angleq+216]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || h > 8
+    lea                 r3d, [hq-1]
+    mova                xm1, [base+z_filter_s4]
+    vpbroadcastb        xm2, r3d
+    mova                xm7, [tlq-1]
+    vinserti32x4        ym7, [tlq+7], 1
+    vbroadcasti32x4     ym0, [base+z_xpos_off1a]
+    vpbroadcastd        ym3, [base+pb_m4_36]
+    pminub              xm2, xm1
+    pshufb              ym0, ym7, ym0
+    vinserti32x4        ym1, xm2, 1
+    psrldq              ym7, 1
+    pshufb              ym1, ym7, ym1
+    pmaddubsw           ym0, ym3
+    pmaddubsw           ym1, ym3
+    vbroadcasti32x4      m8, [pb_0to63]
+    add                 dxd, dxd
+    paddw               ym0, ym1
+    pmulhrsw            ym0, ym15
+    packuswb            ym0, ym0
+    punpcklbw           ym7, ym0
+    jmp .w8_main2
+.w8_no_upsample:
+    lea                 r3d, [hq+7]
+    mova                 m9, [pb_0to63]
+    vpbroadcastb        ym0, r3d
+    and                 r3d, 7
+    vbroadcasti32x4      m7, [tlq]
+    or                  r3d, 8 ; imin(h+7, 15)
+    vpbroadcastb         m8, r3d
+    pminub               m8, m9
+    pshufb               m7, m8
+    test             angled, 0x400
+    jnz .w8_main
+    vpbroadcastb        ym1, angled
+    shr              angled, 8
+    vpcmpeqb             k1, ym0, [base+z_filter_wh]
+    mova                xm0, [base+z_filter_t0+angleq*8]
+    vpcmpgtb         k1{k1}, ym1, ym0
+    kmovd               r5d, k1
+    test                r5d, r5d
+    jz .w8_main
+    vpbroadcastd        ym2, [tlq-4]
+    call .w8_filter
+    cmp                  hd, 8
+    jle .w8_filter_end
+    vpbroadcastd         m8, [base+pb_17]
+    add                 r3d, 2
+    pminub               m8, m9
+.w8_filter_end:
+    vpermb               m7, m8, m0
+.w8_main:
+    vbroadcasti32x4      m8, [base+z_xpos_off1a]
+.w8_main2:
+    movsldup             m4, [base+z_xpos_mul]
+    vpbroadcastw         m9, dxd
+    shl                 r3d, 6
+    vpbroadcastd         m5, [base+z_xpos_bc+8*0]
+    pmullw               m4, m9 ; xpos
+    vpbroadcastd         m6, [base+z_xpos_bc+8*1]
+    sub                 r3d, dxd
+    shl                 dxd, 3
+    psllw                m9, 5 ; dx*8
+    lea                  r2, [strideq*3]
+.w8_loop:
+    psrlw                m3, m4, 3
+    pshufb               m0, m4, m5
+    pshufb               m1, m4, m6
+    vpermw               m3, m3, m14
+    paddsb               m0, m8
+    paddsb               m1, m8
+    vpermb               m0, m0, m7
+    vpermb               m1, m1, m7
+    paddsw               m4, m9
+    punpcklqdq           m2, m3, m3
+    pmaddubsw            m0, m2
+    punpckhqdq           m3, m3
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    packuswb             m0, m1
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r2       ], xm1
+    sub                  hd, 8
+    jl .w8_end
+    vextracti32x8       ym0, m0, 1
+    lea                dstq, [dstq+strideq*4]
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r2       ], xm1
+    jz .w8_end
+    lea                dstq, [dstq+strideq*4]
+    sub                 r3d, dxd
+    jg .w8_loop
+    vextracti32x4       xm7, m7, 3
+.w8_end_loop:
+    movq   [dstq+strideq*0], xm7
+    movq   [dstq+strideq*1], xm7
+    movq   [dstq+strideq*2], xm7
+    movq   [dstq+r2       ], xm7
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_end_loop
+.w8_end:
+    RET
+.w16_filter:
+    mova                 m0, [base+z_filter_s1]
+    popcnt              r5d, r5d
+    vbroadcasti32x4      m1, [base+z_filter_s2]
+    vbroadcasti32x4      m3, [base+z_filter_s3]
+    vbroadcasti32x4      m4, [base+z_filter_s4]
+    vpermi2b             m0, m7, m2 ; al bl
+    mova                 m5, [base+z_filter_s5]
+    pshufb               m1, m7, m1 ; ah bh
+    vpbroadcastd        m11, [base+z_filter_k+(r5-1)*4+12*0]
+    pshufb               m3, m7, m3 ; cl ch
+    vpbroadcastd        m12, [base+z_filter_k+(r5-1)*4+12*1]
+    pshufb               m4, m7, m4 ; el dl
+    vpbroadcastd        m13, [base+z_filter_k+(r5-1)*4+12*2]
+    vpermb               m5, m5, m7 ; eh dh
+    pmaddubsw            m0, m11
+    pmaddubsw            m1, m11
+    pmaddubsw            m2, m3, m12
+    pmaddubsw            m3, m13
+    pmaddubsw            m4, m11
+    pmaddubsw            m5, m11
+    paddw                m0, m2
+    paddw                m1, m3
+    paddw                m0, m4
+    paddw                m1, m5
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    packuswb             m0, m1
+    ret
+.w16:
+    lea                 r3d, [hq+15]
+    mova                 m9, [pb_0to63]
+    vpbroadcastb        ym0, r3d
+    and                 r3d, 15
+    movu                ym7, [tlq]
+    or                  r3d, 16 ; imin(h+15, 31)
+    vpbroadcastb         m8, r3d
+    pminub               m8, m9
+    vpermb               m7, m8, m7
+    test             angled, 0x400
+    jnz .w16_main
+    vpbroadcastb        ym1, angled
+    shr              angled, 8
+    vpcmpeqb             k1, ym0, [base+z_filter_wh]
+    mova                xm0, [base+z_filter_t0+angleq*8]
+    vpcmpgtb         k1{k1}, ym1, ym0
+    kmovd               r5d, k1
+    test                r5d, r5d
+    jz .w16_main
+    vpbroadcastd         m2, [tlq-4]
+    call .w16_filter
+    cmp                  hd, 16
+    jle .w16_filter_end
+    vpbroadcastd         m8, [base+pb_33]
+    add                 r3d, 2
+    pminub               m8, m9
+.w16_filter_end:
+    vpermb               m7, m8, m0
+.w16_main:
+    movshdup             m3, [base+z_xpos_mul]
+    vpbroadcastw         m8, dxd
+    shl                 r3d, 6
+    vpbroadcastd         m4, [base+z_xpos_bc]
+    pmullw               m3, m8 ; xpos
+    vbroadcasti32x4      m5, [base+z_xpos_off1a]
+    sub                 r3d, dxd
+    shl                 dxd, 2
+    vbroadcasti32x4      m6, [base+z_xpos_off1b]
+    psllw                m8, 4 ; dx*4
+    lea                  r2, [strideq*3]
+.w16_loop:
+    pshufb               m1, m3, m4
+    psrlw                m2, m3, 3
+    paddsb               m0, m1, m5
+    vpermw               m2, m2, m14
+    paddsb               m1, m6
+    vpermb               m0, m0, m7
+    vpermb               m1, m1, m7
+    paddsw               m3, m8
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    packuswb             m0, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+r2       ], m0, 3
+    sub                  hd, 4
+    jz .w16_end
+    lea                dstq, [dstq+strideq*4]
+    sub                 r3d, dxd
+    jg .w16_loop
+    vextracti32x4       xm7, m7, 3
+.w16_end_loop:
+    mova   [dstq+strideq*0], xm7
+    mova   [dstq+strideq*1], xm7
+    mova   [dstq+strideq*2], xm7
+    mova   [dstq+r2       ], xm7
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16_end_loop
+.w16_end:
+    RET
+.w32_filter:
+    mova                 m0, [base+z_filter_s1]
+    vbroadcasti32x4      m1, [base+z_filter_s2]
+    vbroadcasti32x4      m3, [base+z_filter_s3]
+    vbroadcasti32x4      m4, [base+z_filter_s4]
+    vpermi2b             m0, m7, m2 ; al bl
+    mova                 m5, [base+z_filter_s5]
+    pshufb               m1, m7, m1 ; ah bh
+    vpbroadcastd        m11, [base+z_filter_k+4*2+12*0]
+    pshufb               m3, m7, m3 ; cl ch
+    vpbroadcastd        m12, [base+z_filter_k+4*2+12*1]
+    pshufb               m4, m7, m4 ; el dl
+    vpbroadcastd        m13, [base+z_filter_k+4*2+12*2]
+    vpermi2b             m5, m7, m8 ; eh dh
+    pmaddubsw            m0, m11
+    pmaddubsw            m1, m11
+    pmaddubsw            m2, m3, m12
+    pmaddubsw            m3, m13
+    pmaddubsw            m4, m11
+    pmaddubsw            m5, m11
+    paddw                m0, m2
+    paddw                m1, m3
+    paddw                m0, m4
+    paddw                m1, m5
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    packuswb             m7, m0, m1
+    ret
+.w32:
+    lea                 r3d, [hq+31]
+    vpbroadcastb         m9, r3d
+    and                 r3d, 31
+    pminub              m10, m9, [pb_0to63]
+    or                  r3d, 32 ; imin(h+31, 63)
+    vpermb               m7, m10, [tlq]
+    vpbroadcastb         m8, [tlq+r3]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w32_main
+    vpbroadcastd         m2, [tlq-4]
+    call .w32_filter
+    cmp                  hd, 64
+    je .w32_h64_filter_end
+    vpermb               m8, m9, m7
+    vpermb               m7, m10, m7
+    jmp .w32_main
+.w32_h64_filter_end: ; edge case for 32x64
+    movd               xmm0, [tlq+r3-1]
+    movd               xmm1, [base+pb_8_56_0_0]
+    add                 r3d, 2
+    pmaddubsw          xmm0, xmm1
+    vptestmw             k1, xmm1, xmm1 ; 0x01
+    pmulhrsw            xm0, xmm0, xm15
+    vmovdqu8         m8{k1}, m0
+.w32_main:
+    rorx                r2d, dxd, 30
+    vpbroadcastd         m4, [base+z_xpos_bc]
+    vpbroadcastw         m3, r2d
+    vbroadcasti32x8      m5, [base+z_xpos_off2a]
+    shl                 r3d, 6
+    vbroadcasti32x8      m6, [base+z_xpos_off2b]
+    sub                 r3d, dxd
+    paddw                m9, m3, m3
+    add                 dxd, dxd
+    vinserti32x8         m3, ym9, 1
+.w32_loop:
+    pshufb               m1, m3, m4
+    psrlw                m2, m3, 3
+    paddsb               m0, m1, m5
+    vpermw               m2, m2, m14
+    paddsb               m1, m6
+    vpermi2b             m0, m7, m8
+    vpermi2b             m1, m7, m8
+    paddsw               m3, m9
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    packuswb             m0, m1
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    sub                  hd, 2
+    jz .w32_end
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, dxd
+    jg .w32_loop
+    punpckhqdq          ym8, ym8
+.w32_end_loop:
+    mova   [dstq+strideq*0], ym8
+    mova   [dstq+strideq*1], ym8
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_end_loop
+.w32_end:
+    RET
+.w64_filter:
+    vbroadcasti32x4      m3, [base+z_filter_s2]
+    mova                 m1, [base+z_filter_s1]
+    pshufb               m0, m3      ; al bl
+    vpermi2b             m1, m7, m2
+    vbroadcasti32x4      m4, [base+z_filter_s4]
+    pshufb               m6, m8, m4  ; el dl
+    pshufb               m9, m7, m4
+    pminub              m10, m13, [base+z_filter_s5]
+    pshufb               m2, m8, m3  ; ah bh
+    pshufb               m3, m7, m3
+    vbroadcasti32x4      m5, [base+z_filter_s3]
+    vpermb              m10, m10, m8 ; eh dh
+    pshufb              m11, m4
+    vpbroadcastd         m4, [base+z_filter_k+4*2+12*0]
+    pshufb               m8, m5      ; cl ch
+    pshufb               m7, m5
+    vpbroadcastd         m5, [base+z_filter_k+4*2+12*1]
+    REPX  {pmaddubsw x, m4}, m0, m1, m6, m9, m2, m3, m10, m11
+    pmaddubsw            m4, m8, m5
+    pmaddubsw            m5, m7, m5
+    paddw                m0, m6
+    vpbroadcastd         m6, [base+z_filter_k+4*2+12*2]
+    paddw                m1, m9
+    pmaddubsw            m7, m6
+    pmaddubsw            m8, m6
+    paddw                m2, m10
+    paddw                m3, m11
+    paddw                m0, m4
+    paddw                m1, m5
+    paddw                m2, m8
+    paddw                m3, m7
+    REPX  {pmulhrsw x, m15}, m0, m2, m1, m3
+    packuswb             m0, m2
+    packuswb             m7, m1, m3
+    vpermb               m8, m12, m0
+    ret
+.w64:
+    lea                 r3d, [hq-1]
+    movu                 m7, [tlq+64*0]
+    vpbroadcastb        m13, r3d
+    pminub              m12, m13, [pb_0to63]
+    or                  r3d, 64
+    vpermb               m8, m12, [tlq+64*1]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w64_main
+    movu                 m0, [tlq+56]
+    vpbroadcastd         m2, [tlq-4]
+    movu                m11, [tlq+8]
+    call .w64_filter
+.w64_main:
+    rorx                r2d, dxd, 30
+    vpbroadcastd         m4, [base+z_xpos_bc]
+    vpbroadcastw         m3, r2d
+    mova                 m5, [base+z_xpos_off2a]
+    shl                 r3d, 6
+    mova                 m6, [base+z_xpos_off2b]
+    sub                 r3d, dxd
+    mova                 m9, m3
+.w64_loop:
+    pshufb               m1, m3, m4
+    psrlw                m2, m3, 3
+    paddsb               m0, m1, m5
+    vpermw               m2, m2, m14
+    paddsb               m1, m6
+    vpermi2b             m0, m7, m8
+    vpermi2b             m1, m7, m8
+    paddsw               m3, m9
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    packuswb             m0, m1
+    mova             [dstq], m0
+    dec                  hd
+    jz .w64_end
+    add                dstq, strideq
+    sub                 r3d, dxd
+    jg .w64_loop
+    vpermb               m8, m13, m8
+.w64_end_loop:
+    mova             [dstq], m8
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_end_loop
+.w64_end:
+    RET
+
+cglobal ipred_z2_8bpc, 3, 9, 18, dst, stride, tl, w, h, angle, dx, _, dy
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    lea                 dxq, [dr_intra_derivative-90]
+    movzx               dyd, angleb
+    xor              angled, 0x400
+    mov                  r7, dxq
+    sub                 dxq, dyq
+    movifnidn            hd, hm
+    and                 dyd, ~1
+    and                 dxq, ~1
+    movzx               dyd, word [r7+dyq]  ; angle - 90
+    lea                  r7, [z_filter_t0]
+    movzx               dxd, word [dxq+270] ; 180 - angle
+    movsxd               wq, [base+ipred_z2_8bpc_avx512icl_table+wq*4]
+    mova                 m8, [base+pb_63to0]
+    neg                 dyd
+    vpermb               m8, m8, [tlq-64] ; left
+    lea                  wq, [base+ipred_z2_8bpc_avx512icl_table+wq]
+    mova                m14, [base+z_frac_table]
+    inc                 tlq
+    vpbroadcastd        m15, [base+pw_512]
+    neg                 dxd
+    jmp                  wq
+.w4:
+    movd                xm7, [tlq]
+    vpbroadcastq        m10, [base+z_xpos_off2a]
+    test             angled, 0x400
+    jnz .w4_main ; !enable_intra_edge_filter
+    lea                 r3d, [hq+2]
+    add              angled, 1022
+    shl                 r3d, 6
+    test                r3d, angled
+    jnz .w4_no_upsample_above ; angle >= 130 || h > 8 || (is_sm && h == 8)
+    vpbroadcastd        xm2, [base+pb_4]
+    sub              angled, 1075 ; angle - 53
+    call .upsample_above
+    lea                 r3d, [hq+3]
+    vpbroadcastq        m10, [pb_0to63+1]
+    punpcklbw           xm7, xm0, xm7
+    call .filter_strength
+    jmp .w4_filter_left
+.w4_upsample_left:
+    call .upsample_left
+    movsldup            m16, [base+z_ypos_off3]
+    vpbroadcastd         m9, [base+pb_16]
+    punpcklbw           xm8, xm0, xm8
+    jmp .w4_main2
+.w4_no_upsample_above:
+    lea                 r3d, [hq+3]
+    sub              angled, 1112 ; angle - 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w4_no_filter_above
+    vpbroadcastd        xm5, [base+pb_3]
+    call .filter_top_w16
+.w4_no_filter_above:
+    lea                 r3d, [hq+2]
+    add              angled, 973 ; angle + 883
+    shl                 r3d, 6
+    test                r3d, angled
+    jz .w4_upsample_left ; angle <= 140 || h > 8 || (is_sm && h == 8)
+    vpbroadcastd        ym0, [base+pb_90]
+    psubb               ym0, ym17
+    vpcmpgtb         k2{k2}, ym0, ym16
+    kmovd               r3d, k2
+.w4_filter_left:
+    test                r3d, r3d
+    jz .w4_main
+    popcnt              r3d, r3d
+    call .filter_left_h16
+.w4_main:
+    movsldup            m16, [base+z_ypos_off1]
+    vpbroadcastd         m9, [base+pb_8]
+.w4_main2:
+    vpbroadcastq         m3, [base+z_ypos_mul1a]
+    vpbroadcastw         m0, dyd
+    movsldup             m1, [base+z_xpos_mul]
+    vpbroadcastw         m5, dxd
+    vinserti32x4         m7, [tlq-16], 3
+    vinserti32x4         m8, [tlq-16], 3
+    pmullw               m3, m0
+    vbroadcasti32x4      m2, [base+z_xpos_bc]
+    pmullw               m1, m5      ; xpos0..3
+    psllw                m5, 5       ; dx*8
+    psraw                m4, m3, 6
+    psrlw                m3, 1
+    packsswb             m4, m4
+    vpermw               m3, m3, m14 ; 64-frac, frac
+    punpcklbw            m4, m4
+    lea                  r2, [strideq*3]
+    paddb                m4, m16     ; base, base+1
+.w4_loop:
+    pshufb              m16, m1, m2
+    psrlw                m0, m1, 3
+    paddb               m16, m10
+    vpermw               m0, m0, m14
+    vpmovw2m             k1, m16     ; base_x < 0
+    vpermb              m16, m16, m7
+    pmaddubsw           m16, m0
+    vpermb               m0, m4, m8
+    pmaddubsw       m16{k1}, m0, m3
+    pmulhrsw            m16, m15
+    vpmovwb            ym16, m16
+    movd   [dstq+strideq*0], xm16
+    pextrd [dstq+strideq*1], xm16, 1
+    pextrd [dstq+strideq*2], xm16, 2
+    pextrd [dstq+r2       ], xm16, 3
+    sub                  hd, 8
+    jl .w4_end
+    paddsw               m1, m5
+    vextracti128       xm16, ym16, 1
+    lea                dstq, [dstq+strideq*4]
+    paddb                m4, m9
+    movd   [dstq+strideq*0], xm16
+    pextrd [dstq+strideq*1], xm16, 1
+    pextrd [dstq+strideq*2], xm16, 2
+    pextrd [dstq+r2       ], xm16, 3
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.w4_end:
+    RET
+.upsample_above: ; w4/w8
+    mova                xm0, [tlq-1]
+    xor              angled, 0x7f ; 180 - angle
+    add                 dxd, dxd
+    jmp .upsample
+.upsample_left: ; h4/h8
+    palignr             xm0, xm8, [tlq-16], 15
+    vpbroadcastb        xm2, hd
+    add                 dyd, dyd
+.upsample:
+    pshufb              xm1, xm0, [base+z_filter4_s1]
+    pminub              xm2, [base+z_filter_s4]
+    vpbroadcastd        xm3, [base+pb_m4_36]
+    pshufb              xm0, xm2
+    pmaddubsw           xm1, xm3
+    pmaddubsw           xm0, xm3
+    paddw               xm0, xm1
+    pmulhrsw            xm0, xm15
+    packuswb            xm0, xm0
+    ret
+.filter_strength:
+    vpbroadcastb       ym16, r3d
+    mov                 r3d, angled
+    vpbroadcastd         m2, [tlq-4]
+    vpbroadcastb       ym17, angled
+    shr                 r3d, 8
+    vpcmpeqb             k2, ym16, [base+z_filter_wh]
+    mova               xm16, [base+z_filter_t0+r3*8]
+    vpcmpgtb         k1{k2}, ym17, ym16
+    mova                 m9, [pb_0to63]
+    kmovd               r3d, k1
+    ret
+.w8:
+    movq                xm7, [tlq]
+    vbroadcasti32x4     m10, [base+z_xpos_off2a]
+    test             angled, 0x400
+    jnz .w8_main
+    lea                 r3d, [angleq+126]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_no_upsample_above ; angle >= 130 || h > 8 || is_sm
+    vpbroadcastd        xm2, [base+pb_8]
+    sub              angled, 53 ; angle - 53
+    call .upsample_above
+    lea                 r3d, [hq+7]
+    vbroadcasti32x4     m10, [pb_0to63+1]
+    punpcklbw           xm7, xm0, xm7
+    call .filter_strength
+    jmp .w8_filter_left
+.w8_upsample_left:
+    call .upsample_left
+    movshdup            m16, [base+z_ypos_off3]
+    vpbroadcastd         m9, [base+pb_8]
+    punpcklbw           xm8, xm0, xm8
+    jmp .w8_main2
+.w8_no_upsample_above:
+    lea                 r3d, [hq+7]
+    sub              angled, 90 ; angle - 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w8_no_filter_above
+    vpbroadcastd        xm5, [base+pb_7]
+    call .filter_top_w16
+.w8_no_filter_above:
+    lea                 r3d, [angleq-51]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    jbe .w8_upsample_left ; angle > 140 && h <= 8 && !is_sm
+    vpbroadcastd        ym0, [base+pb_90]
+    psubb               ym0, ym17
+    vpcmpgtb         k2{k2}, ym0, ym16
+    kmovd               r3d, k2
+.w8_filter_left:
+    test                r3d, r3d
+    jz .w8_main
+    cmp                  hd, 32
+    je .w8_filter_left_h32
+    popcnt              r3d, r3d
+    call .filter_left_h16
+    jmp .w8_main
+.w8_filter_left_h32:
+    call .filter_left_h64
+.w8_main:
+    movshdup            m16, [base+z_ypos_off2]
+    vpbroadcastd         m9, [base+pb_4]
+.w8_main2:
+    vbroadcasti32x4      m3, [base+z_ypos_mul1a]
+    vpbroadcastw         m0, dyd
+    movshdup             m1, [base+z_xpos_mul]
+    vpbroadcastw         m5, dxd
+    vinserti32x4         m7, [tlq-16], 3
+    vinserti32x4         m8, [tlq-16], 3
+    pmullw               m3, m0
+    vpbroadcastd         m2, [base+pb_1]
+    pmullw               m1, m5      ; xpos0..3
+    psllw                m5, 4       ; dx*4
+    psraw                m4, m3, 6
+    psrlw                m3, 1
+    packsswb             m4, m4
+    vpermw               m3, m3, m14 ; 64-frac, frac
+    lea                 r3d, [dxq+(8<<6)]
+    paddsb               m4, m16
+    shl                 dxd, 2
+    paddsb               m0, m4, m2
+    lea                  r2, [strideq*3]
+    punpcklbw            m4, m0      ; base, base+1
+.w8_loop:
+    pshufb              m16, m1, m2
+    psrlw                m0, m1, 3
+    paddb               m16, m10
+    vpermw               m0, m0, m14
+    vpmovw2m             k1, m16     ; base_x < 0
+    vpermb              m16, m16, m7
+    pmaddubsw           m16, m0
+    vpermb               m0, m4, m8
+    pmaddubsw       m16{k1}, m0, m3
+    pmulhrsw            m16, m15
+    vpmovwb            ym16, m16
+    vextracti128       xm17, ym16, 1
+    movq   [dstq+strideq*0], xm16
+    movhps [dstq+strideq*1], xm16
+    movq   [dstq+strideq*2], xm17
+    movhps [dstq+r2       ], xm17
+    sub                  hd, 4
+    jz .w8_end
+    paddw                m1, m5
+    lea                dstq, [dstq+strideq*4]
+    paddb                m4, m9
+    add                 r3d, dxd
+    jge .w8_loop
+.w8_leftonly_loop:
+    vpermb              m16, m4, m8
+    pmaddubsw           m16, m3
+    paddb                m4, m9
+    pmulhrsw            m16, m15
+    vpmovwb            ym16, m16
+    vextracti128       xm17, ym16, 1
+    movq   [dstq+strideq*0], xm16
+    movhps [dstq+strideq*1], xm16
+    movq   [dstq+strideq*2], xm17
+    movhps [dstq+r2       ], xm17
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_leftonly_loop
+.w8_end:
+    RET
+.filter_top_w16:
+    mova                xm0, [base+z_filter_s1]
+    popcnt              r3d, r3d
+    pminub              xm4, xm5, [base+z_filter_s4]
+    vpermi2b            xm0, xm7, xm2
+    pminub              xm5, [base+z_filter_s5]
+    pshufb              xm1, xm7, [base+z_filter_s2]
+    vpbroadcastd       xm11, [base+z_filter_k+(r3-1)*4+12*0]
+    pshufb              xm3, xm7, [base+z_filter_s3]
+    vpbroadcastd       xm12, [base+z_filter_k+(r3-1)*4+12*1]
+    pshufb              xm4, xm7, xm4
+    vpbroadcastd       xm13, [base+z_filter_k+(r3-1)*4+12*2]
+    pshufb              xm5, xm7, xm5
+    pmaddubsw           xm0, xm11
+    pmaddubsw           xm1, xm11
+    pmaddubsw           xm6, xm3, xm12
+    vpbroadcastd       xm12, r7m ; max_width
+    pmaddubsw           xm3, xm13
+    pmaddubsw           xm4, xm11
+    pmaddubsw           xm5, xm11
+    packssdw           xm12, xm12
+    paddw               xm0, xm6
+    paddw               xm1, xm3
+    paddw               xm0, xm4
+    paddw               xm1, xm5
+    packsswb           xm12, xm12
+    pmulhrsw            xm0, xm15
+    pmulhrsw            xm1, xm15
+    vpcmpgtb             k1, xm12, xm9 ; x < max_width
+    packuswb        xm7{k1}, xm0, xm1
+    ret
+.filter_left_h16:
+    lea                 r5d, [hq-1]
+    mova                xm0, [base+z_filter_s1]
+    vpbroadcastb        xm5, r5d
+    vpermi2b            xm0, xm8, xm2
+    pminub              xm4, xm5, [base+z_filter_s4]
+    pshufb              xm1, xm8, [base+z_filter_s2]
+    pminub              xm5, [base+z_filter_s5]
+    pshufb              xm3, xm8, [base+z_filter_s3]
+    vpbroadcastd       xm11, [base+z_filter_k+(r3-1)*4+12*0]
+    pshufb              xm4, xm8, xm4
+    vpbroadcastd       xm12, [base+z_filter_k+(r3-1)*4+12*1]
+    pshufb              xm5, xm8, xm5
+    vpbroadcastd       xm13, [base+z_filter_k+(r3-1)*4+12*2]
+    pmaddubsw           xm0, xm11
+    pmaddubsw           xm1, xm11
+    pmaddubsw           xm6, xm3, xm12
+    vpbroadcastd       xm12, r8m ; max_height
+    pmaddubsw           xm3, xm13
+    pmaddubsw           xm4, xm11
+    pmaddubsw           xm5, xm11
+    packssdw           xm12, xm12
+    paddw               xm0, xm6
+    paddw               xm1, xm3
+    paddw               xm0, xm4
+    paddw               xm1, xm5
+    packsswb           xm12, xm12
+    pmulhrsw            xm0, xm15
+    pmulhrsw            xm1, xm15
+    vpcmpgtb             k1, xm12, xm9 ; y < max_height
+    packuswb        xm8{k1}, xm0, xm1
+    ret
+.w16:
+    movu                xm7, [tlq] ; top
+    test             angled, 0x400
+    jnz .w16_main
+    lea                 r3d, [hq+15]
+    sub              angled, 90
+    call .filter_strength
+    test                r3d, r3d
+    jz .w16_no_filter_above
+    vpbroadcastd        xm5, [base+pb_15]
+    call .filter_top_w16
+.w16_no_filter_above:
+    cmp                  hd, 16
+    jg .w16_filter_left_h64
+    vpbroadcastd        ym0, [base+pb_90]
+    psubb               ym0, ym17
+    vpcmpgtb         k2{k2}, ym0, ym16
+    kmovd               r3d, k2
+    test                r3d, r3d
+    jz .w16_main
+    popcnt              r3d, r3d
+    call .filter_left_h16
+    jmp .w16_main
+.w16_filter_left_h64:
+    call .filter_left_h64
+.w16_main:
+    vbroadcasti32x4      m6, [base+z_ypos_mul1a] ; 1.. 8
+    vbroadcasti32x4      m5, [base+z_ypos_mul1b] ; 9..15
+    vpbroadcastw         m0, dyd
+    vinserti32x4         m7, [tlq-16], 3
+    vpbroadcastd         m2, [base+pb_1]
+    vpbroadcastw        m12, dxd
+    movshdup             m1, [base+z_xpos_mul]
+    pmullw               m6, m0
+    vbroadcasti32x4      m3, [base+z_xpos_off2a]
+    pmullw               m5, m0
+    vbroadcasti32x4      m4, [base+z_xpos_off2b]
+    pmullw               m1, m12      ; xpos0 xpos1 xpos2 xpos3
+    vpbroadcastd         m9, [base+pb_4]
+    psllw               m12, 4        ; dx*4
+    movshdup            m16, [base+z_ypos_off2]
+    psrlw               m10, m6, 1
+    psrlw               m11, m5, 1
+    vpermw              m10, m10, m14 ; 64-frac, frac
+    psraw                m6, 6
+    vpermw              m11, m11, m14
+    psraw                m5, 6
+    mov                 r5d, -(16<<6) ; 15 to avoid top, +1 to avoid topleft
+    packsswb             m6, m5
+    mov                 r3d, 1<<6
+    paddsb               m6, m16
+    sub                 r5d, dxd      ; left-only threshold
+    paddsb               m0, m6, m2
+    shl                 dxd, 2
+    punpcklbw            m5, m6, m0   ; base, base+1
+    lea                  r2, [strideq*3]
+    punpckhbw            m6, m0
+.w16_loop:
+    pshufb              m17, m1, m2
+    psrlw                m0, m1, 3
+    paddb               m16, m3, m17
+    vpermw               m0, m0, m14
+    paddb               m17, m4
+    vpmovw2m             k1, m16
+    vpermb              m16, m16, m7
+    vpmovw2m             k2, m17
+    vpermb              m17, m17, m7
+    pmaddubsw           m16, m0
+    pmaddubsw           m17, m0
+    add                 r3d, dxd
+    jge .w16_toponly
+    mova                 m0, m8
+    vpermt2b             m0, m5, m7
+    pmaddubsw       m16{k1}, m0, m10
+    mova                 m0, m8
+    vpermt2b             m0, m6, m7
+    pmaddubsw       m17{k2}, m0, m11
+.w16_toponly:
+    pmulhrsw            m16, m15
+    pmulhrsw            m17, m15
+    packuswb            m16, m17
+    mova          [dstq+strideq*0], xm16
+    vextracti128  [dstq+strideq*1], ym16, 1
+    vextracti32x4 [dstq+strideq*2], m16, 2
+    vextracti32x4 [dstq+r2       ], m16, 3
+    sub                  hd, 4
+    jz .w16_end
+    paddw                m1, m12
+    lea                dstq, [dstq+strideq*4]
+    paddb                m5, m9
+    paddb                m6, m9
+    cmp                 r3d, r5d
+    jge .w16_loop
+.w16_leftonly_loop:
+    vpermb              m16, m5, m8
+    vpermb              m17, m6, m8
+    pmaddubsw           m16, m10
+    pmaddubsw           m17, m11
+    paddb                m5, m9
+    paddb                m6, m9
+    pmulhrsw            m16, m15
+    pmulhrsw            m17, m15
+    packuswb            m16, m17
+    mova          [dstq+strideq*0], xm16
+    vextracti128  [dstq+strideq*1], ym16, 1
+    vextracti32x4 [dstq+strideq*2], m16, 2
+    vextracti32x4 [dstq+r2       ], m16, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16_leftonly_loop
+.w16_end:
+    RET
+.w32:
+    movu                ym7, [tlq]
+    test             angled, 0x400
+    jnz .w32_main
+    vpbroadcastd         m2, [tlq-4]
+    mova                ym0, [base+z_filter_s1]
+    vbroadcasti32x4     ym1, [base+z_filter_s2]
+    vbroadcasti32x4     ym3, [base+z_filter_s3]
+    vbroadcasti32x4     ym4, [base+z_filter_s4]
+    vpermi2b            ym0, ym7, ym2 ; al bl
+    vpbroadcastd        ym5, [base+pb_31]
+    pminub              ym5, [base+z_filter_s5]
+    pshufb              ym1, ym7, ym1 ; ah bh
+    vpbroadcastd       ym11, [base+z_filter_k+4*2+12*0]
+    pshufb              ym3, ym7, ym3 ; cl ch
+    vpbroadcastd       ym12, [base+z_filter_k+4*2+12*1]
+    pshufb              ym4, ym7, ym4 ; el dl
+    vpbroadcastd       ym13, [base+z_filter_k+4*2+12*2]
+    vpermb              ym5, ym5, ym7 ; eh dh
+    pmaddubsw           ym0, ym11
+    pmaddubsw           ym1, ym11
+    pmaddubsw           ym6, ym3, ym12
+    vpbroadcastd       ym12, r6m
+    pmaddubsw           ym3, ym13
+    pmaddubsw           ym4, ym11
+    pmaddubsw           ym5, ym11
+    mova                 m9, [pb_0to63]
+    packssdw           ym12, ym12
+    paddw               ym0, ym6
+    paddw               ym1, ym3
+    paddw               ym0, ym4
+    paddw               ym1, ym5
+    packsswb           ym12, ym12
+    pmulhrsw            ym0, ym15
+    pmulhrsw            ym1, ym15
+    vpcmpgtb             k1, ym12, ym9 ; x < max_width
+    packuswb        ym7{k1}, ym0, ym1
+    cmp                  hd, 16
+    jg .w32_filter_h64
+    mov                 r3d, 3
+    call .filter_left_h16
+    jmp .w32_main
+.w32_filter_h64:
+    call .filter_left_h64
+.w32_main:
+    vbroadcasti32x8      m6, [base+z_ypos_mul1a] ; 1.. 8
+    vbroadcasti32x8      m5, [base+z_ypos_mul1b] ; 9..15
+    vpbroadcastw         m0, dyd
+    vinserti32x4         m7, [tlq-16], 3
+    rorx                r2q, dxq, 62 ; dx << 2
+    vpbroadcastd         m2, [base+pb_1]
+    vpbroadcastw         m1, r2d
+    pmullw               m6, m0
+    vbroadcasti32x8      m3, [base+z_xpos_off2a]
+    pmullw               m5, m0
+    vbroadcasti32x8      m4, [base+z_xpos_off2b]
+    mova                ym0, ym1
+    paddw               m12, m1, m1
+    vpbroadcastd         m9, [base+pb_2]
+    paddw                m1, m0       ; xpos1 xpos0
+    mova                ym0, ym2
+    psrlw               m10, m6, 1
+    psrlw               m11, m5, 1
+    vpermw              m10, m10, m14 ; 64-frac, frac
+    psraw                m6, 6
+    vpermw              m11, m11, m14
+    psraw                m5, 6
+    mov                 r5d, -(32<<6) ; 31 to avoid top, +1 to avoid topleft
+    packsswb             m6, m5
+    mov                 r3d, 1<<6
+    paddsb               m6, m0
+    sub                 r5d, dxd      ; left-only threshold
+    paddsb               m0, m6, m2
+    add                 dxd, dxd
+    punpcklbw            m5, m6, m0   ; base, base+1
+    punpckhbw            m6, m0
+.w32_loop:
+    pshufb              m17, m1, m2
+    psrlw                m0, m1, 3
+    paddb               m16, m3, m17
+    vpermw               m0, m0, m14
+    paddb               m17, m4
+    vpmovw2m             k1, m16
+    vpermb              m16, m16, m7
+    vpmovw2m             k2, m17
+    vpermb              m17, m17, m7
+    pmaddubsw           m16, m0
+    pmaddubsw           m17, m0
+    add                 r3d, dxd
+    jge .w32_toponly
+    mova                 m0, m8
+    vpermt2b             m0, m5, m7
+    pmaddubsw       m16{k1}, m0, m10
+    mova                 m0, m8
+    vpermt2b             m0, m6, m7
+    pmaddubsw       m17{k2}, m0, m11
+.w32_toponly:
+    pmulhrsw            m16, m15
+    pmulhrsw            m17, m15
+    packuswb            m16, m17
+    vextracti32x8 [dstq+strideq*0], m16, 1
+    mova          [dstq+strideq*1], ym16
+    sub                  hd, 2
+    jz .w32_end
+    paddw                m1, m12
+    lea                dstq, [dstq+strideq*2]
+    paddb                m5, m9
+    paddb                m6, m9
+    cmp                 r3d, r5d
+    jge .w32_loop
+.w32_leftonly_loop:
+    vpermb              m16, m5, m8
+    vpermb              m17, m6, m8
+    pmaddubsw           m16, m10
+    pmaddubsw           m17, m11
+    paddb                m5, m9
+    paddb                m6, m9
+    pmulhrsw            m16, m15
+    pmulhrsw            m17, m15
+    packuswb            m16, m17
+    vextracti32x8 [dstq+strideq*0], m16, 1
+    mova          [dstq+strideq*1], ym16
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_leftonly_loop
+.w32_end:
+    RET
+.filter_left_h64:
+    mova                 m0, [base+z_filter_s1]
+    lea                 r3d, [hq-1]
+    vbroadcasti32x4      m4, [base+z_filter_s4]
+    vpbroadcastb         m5, r3d
+    vbroadcasti32x4      m1, [base+z_filter_s2]
+    vbroadcasti32x4      m3, [base+z_filter_s3]
+    vpermi2b             m0, m8, m2 ; al bl
+    pminub               m5, [base+z_filter_s5]
+    pshufb               m1, m8, m1 ; ah bh
+    vpbroadcastd        m11, [base+z_filter_k+4*2+12*0]
+    pshufb               m3, m8, m3 ; cl ch
+    vpbroadcastd        m12, [base+z_filter_k+4*2+12*1]
+    pshufb               m4, m8, m4 ; el dl
+    vpbroadcastd        m13, [base+z_filter_k+4*2+12*2]
+    vpermb               m5, m5, m8 ; eh dh
+    pmaddubsw            m0, m11
+    pmaddubsw            m1, m11
+    pmaddubsw            m6, m3, m12
+    vpbroadcastd        m12, r8m    ; max_height
+    pmaddubsw            m3, m13
+    pmaddubsw            m4, m11
+    pmaddubsw            m5, m11
+    packssdw            m12, m12
+    paddw                m0, m6
+    paddw                m1, m3
+    paddw                m0, m4
+    paddw                m1, m5
+    packsswb            m12, m12
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    vpcmpgtb             k1, m12, m9 ; y < max_height
+    packuswb         m8{k1}, m0, m1
+    ret
+.w64:
+    movu                 m7, [tlq]
+    test             angled, 0x400
+    jnz .w64_main
+    vpbroadcastd         m2, [tlq-4]
+    mova                 m0, [base+z_filter_s1]
+    vbroadcasti32x4      m1, [base+z_filter_s2]
+    vbroadcasti32x4      m3, [base+z_filter_s3]
+    vbroadcasti32x4      m4, [base+z_filter_s4]
+    vpermi2b             m0, m7, m2 ; al bl
+    vpbroadcastd         m5, [base+pb_63]
+    pminub               m5, [base+z_filter_s5]
+    pshufb               m1, m7, m1 ; ah bh
+    vpbroadcastd        m11, [base+z_filter_k+4*2+12*0]
+    pshufb               m3, m7, m3 ; cl ch
+    vpbroadcastd        m12, [base+z_filter_k+4*2+12*1]
+    pshufb               m4, m7, m4 ; el dl
+    vpbroadcastd        m13, [base+z_filter_k+4*2+12*2]
+    vpermb               m5, m5, m7 ; eh dh
+    pmaddubsw            m0, m11
+    pmaddubsw            m1, m11
+    pmaddubsw            m6, m3, m12
+    vpbroadcastd        m12, r6m
+    pmaddubsw            m3, m13
+    pmaddubsw            m4, m11
+    pmaddubsw            m5, m11
+    mova                 m9, [pb_0to63]
+    packssdw            m12, m12
+    paddw                m0, m6
+    paddw                m1, m3
+    paddw                m0, m4
+    paddw                m1, m5
+    packsswb            m12, m12
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    vpcmpgtb             k1, m12, m9 ; x < max_width
+    packuswb         m7{k1}, m0, m1
+    call .filter_left_h64 ; always filter the full 64 pixels for simplicity
+.w64_main:
+    vpbroadcastw         m5, dyd
+    vpbroadcastd         m9, [tlq-4]
+    rorx                r2q, dxq, 62 ; dx << 2
+    pmullw               m6, m5, [base+z_ypos_mul1a] ; can overflow, but it doesn't matter as such
+    pmullw               m5, [base+z_ypos_mul1b]     ; pixels aren't selected from the left edge
+    vpbroadcastw         m1, r2d     ; xpos
+    mova                 m3, [base+z_xpos_off2a]
+    mova                 m4, [base+z_xpos_off2b]
+    mova                m12, m1
+    vpbroadcastd         m2, [base+pb_1]
+    psrlw               m10, m6, 1
+    psrlw               m11, m5, 1
+    vpermw              m10, m10, m14 ; 64-frac, frac
+    psraw                m6, 6
+    vpermw              m11, m11, m14
+    psraw                m5, 6
+    mov                 r5d, -(64<<6) ; 63 to avoid top, +1 to avoid topleft
+    packsswb             m6, m5
+    mov                 r3d, 1<<6
+    paddsb               m0, m6, m2
+    sub                 r5d, dxd      ; left-only threshold
+    punpcklbw            m5, m6, m0   ; base, base+1
+    punpckhbw            m6, m0
+.w64_loop:
+    pshufb              m17, m1, m2
+    psrlw                m0, m1, 3
+    paddb               m16, m3, m17
+    vpermw               m0, m0, m14
+    paddb               m17, m4
+    vpmovw2m             k1, m16      ; base_x < 0
+    vpermi2b            m16, m7, m9
+    vpmovw2m             k2, m17
+    vpermi2b            m17, m7, m9
+    pmaddubsw           m16, m0
+    pmaddubsw           m17, m0
+    add                 r3d, dxd
+    jge .w64_toponly
+    mova                 m0, m8
+    vpermt2b             m0, m5, m9
+    pmaddubsw       m16{k1}, m0, m10
+    mova                 m0, m8
+    vpermt2b             m0, m6, m9
+    pmaddubsw       m17{k2}, m0, m11
+.w64_toponly:
+    pmulhrsw            m16, m15
+    pmulhrsw            m17, m15
+    packuswb            m16, m17
+    mova             [dstq], m16
+    dec                  hd
+    jz .w64_end
+    paddw                m1, m12
+    add                dstq, strideq
+    paddb                m5, m2
+    paddb                m6, m2
+    cmp                 r3d, r5d
+    jge .w64_loop
+.w64_leftonly_loop:
+    vpermb              m16, m5, m8
+    vpermb              m17, m6, m8
+    pmaddubsw           m16, m10
+    pmaddubsw           m17, m11
+    paddb                m5, m2
+    paddb                m6, m2
+    pmulhrsw            m16, m15
+    pmulhrsw            m17, m15
+    packuswb            m16, m17
+    mova             [dstq], m16
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_leftonly_loop
+.w64_end:
+    RET
+
+cglobal ipred_z3_8bpc, 3, 8, 16, dst, stride, tl, w, h, angle, dy
+    lea                  r7, [z_filter_t0]
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    lea                  t0, [dr_intra_derivative+45*2-1]
+    movsxd               wq, [base+ipred_z3_8bpc_avx512icl_table+wq*4]
+    sub              angled, 180
+    mov                 dyd, angled
+    neg                 dyd
+    xor              angled, 0x400
+    or                  dyq, ~0x7e
+    mova                 m0, [base+pb_63to0]
+    movzx               dyd, word [t0+dyq]
+    lea                  wq, [base+ipred_z3_8bpc_avx512icl_table+wq]
+    movifnidn            hd, hm
+    mova                m14, [base+z_frac_table]
+    shl                 dyd, 6
+    vpbroadcastd        m15, [base+pw_512]
+    jmp                  wq
+.w4:
+    cmp              angleb, 40
+    jae .w4_no_upsample
+    lea                 r3d, [angleq-1024]
+    sar                 r3d, 7
+    add                 r3d, hd
+    jg .w4_no_upsample ; !enable_intra_edge_filter || h > 8 || (h == 8 && is_sm)
+    lea                 r3d, [hq+4]
+    call .upsample
+    movshdup             m1, [base+z_ypos_off1]
+    vpbroadcastd         m6, [base+pb_16]
+    jmp .w4_main2
+.w4_no_upsample:
+    lea                 r3d, [hq+3]
+    vpbroadcastb         m9, r3d
+    vpxord               m1, m9, [base+pb_63] {1to16} ; 63 - (h + 4)
+    pmaxub               m1, m0
+    vpermb               m7, m1, [tlq-64*1]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w4_main
+    vpbroadcastb        xm1, angled
+    shr              angled, 8
+    vpcmpeqb             k1, xm9, [base+z_filter_wh]
+    vpbroadcastd         m2, [tlq-3]
+    vpcmpgtb         k1{k1}, xm1, [base+z_filter_t0+angleq*8]
+    kmovw               r5d, k1
+    test                r5d, r5d
+    jz .w4_main
+    pminub               m9, [pb_0to63]
+    call mangle(private_prefix %+ _ipred_z1_8bpc_avx512icl).w8_filter
+    vpermb               m7, m9, m0
+.w4_main:
+    movsldup             m1, [base+z_ypos_off1]
+    vpbroadcastd         m6, [base+pb_8]
+.w4_main2:
+    vpbroadcastw         m0, dyd
+    vpbroadcastq         m2, [base+z_ypos_mul2a] ; 1..4
+    pmulhuw              m2, m0 ; ypos >> 1
+    lea                  r2, [strideq*3]
+    vpermw               m3, m2, m14 ; 64-frac, frac
+    psrlw                m2, 5
+    packsswb             m2, m2
+    punpcklbw            m2, m2
+    paddsb               m2, m1 ; base, base+1
+.w4_loop:
+    vpermb               m0, m2, m7
+    pmaddubsw            m0, m3
+    paddsb               m2, m6
+    pmulhrsw             m0, m15
+    vpmovwb             ym0, m0
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r2       ], xm0, 3
+    sub                  hd, 8
+    jl .w4_end
+    vextracti32x4       xm0, ym0, 1
+    lea                dstq, [dstq+strideq*4]
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    pextrd [dstq+strideq*2], xm0, 2
+    pextrd [dstq+r2       ], xm0, 3
+    lea                dstq, [dstq+strideq*4]
+    jg .w4_loop
+.w4_end:
+    RET
+.upsample:
+    xor                 r3d, 31 ; 31 - (h + imin(w, h))
+    vbroadcasti32x4     ym0, [base+z_xpos_off2a]
+    vpbroadcastb        ym7, r3d
+    pmaxub              ym7, [base+z3_upsample]
+    vbroadcasti32x4     ym1, [base+z_filter_s4]
+    vpermb              ym7, ym7, [tlq-31]
+    vpbroadcastd        ym2, [base+pb_m4_36]
+    pshufb              ym0, ym7, ym0
+    psrldq              ym7, 1
+    pshufb              ym1, ym7, ym1
+    pmaddubsw           ym0, ym2
+    pmaddubsw           ym1, ym2
+    add                 dyd, dyd
+    paddw               ym0, ym1
+    pmulhrsw            ym0, ym15
+    packuswb            ym0, ym0
+    punpcklbw           ym7, ym0
+    ret
+.w8:
+    lea                 r3d, [angleq+216]
+    mov                 r3b, hb
+    cmp                 r3d, 8
+    ja .w8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || h > 8
+    lea                 r3d, [hq*2]
+    call .upsample
+    pshufd               m1, [base+z_ypos_off1], q0000
+    vpbroadcastd         m6, [base+pb_8]
+    jmp .w8_main2
+.w8_no_upsample:
+    mov                 r3d, 8
+    cmp                  hd, 4
+    cmove               r3d, hd
+    lea                 r3d, [r3+hq-1]
+    xor                 r3d, 63 ; 63 - (h + imin(w, h))
+    vpbroadcastb         m1, wd
+    pmaxub               m1, m0
+    vpermb               m7, m1, [tlq-64*1]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w8_main
+    lea                 r3d, [hq+7]
+    call .filter_strength
+    test                r5d, r5d
+    jz .w8_main
+    call mangle(private_prefix %+ _ipred_z1_8bpc_avx512icl).w16_filter
+    vpermb               m7, m10, m0
+.w8_main:
+    movsldup             m1, [base+z_ypos_off2]
+    vpbroadcastd         m6, [base+pb_4]
+.w8_main2:
+    vpbroadcastw         m0, dyd
+    vbroadcasti32x4      m2, [base+z_ypos_mul2a] ; 1..8
+    pmulhuw              m2, m0 ; ypos >> 1
+    lea                  r2, [strideq*3]
+    vpermw               m3, m2, m14 ; 64-frac, frac
+    psrlw                m2, 5
+    packsswb             m2, m2
+    punpcklbw            m2, m2
+    paddsb               m2, m1 ; base, base+1
+.w8_loop:
+    vpermb               m0, m2, m7
+    pmaddubsw            m0, m3
+    paddsb               m2, m6
+    pmulhrsw             m0, m15
+    vpmovwb             ym0, m0
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r2       ], xm1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.filter_strength:
+    vpbroadcastd         m2, [tlq-3]
+.filter_strength2:
+    vpbroadcastb         m9, r3d
+    vpbroadcastb        ym1, angled
+    shr              angled, 8
+    vpcmpeqb             k1, ym9, [base+z_filter_wh]
+    mova                xm0, [base+z_filter_t0+angleq*8]
+    vpcmpgtb         k1{k1}, ym1, ym0
+    pminub              m10, m9, [pb_0to63]
+    kmovd               r5d, k1
+    ret
+.w16_load:
+    cmp                 r3d, hd
+    cmovae              r3d, hd
+    add                 r3d, hd
+    mova                 m7, [tlq-64*1]
+    neg                 r3d ; -(h + imin(w, h))
+    and                 r3d, 63
+    vpbroadcastb         m1, r3d
+    pmaxub               m2, m0, m1
+    cmp                  hd, 64
+    je .w16_load_h64
+    vpermb               m8, m1, m7
+    vpermb               m7, m2, m7
+    ret
+.w16_load_h64:
+    vpermb               m7, m0, m7
+    vpermb               m8, m2, [tlq-64*2]
+    ret
+.w16:
+    mov                 r3d, 16
+    call .w16_load
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w16_main
+    vpbroadcastd         m2, [tlq-3]
+    cmp                  hd, 64
+    je .w16_filter64
+    lea                 r3d, [hq+15]
+    call .filter_strength2
+    test                r5d, r5d
+    jz .w16_main
+    call mangle(private_prefix %+ _ipred_z1_8bpc_avx512icl).w16_filter
+    pminub              m10, m9, [pb_0to63]
+    vpermb               m8, m9, m0
+    vpermb               m7, m10, m0
+    jmp .w16_main
+.w16_filter64:
+    vpbroadcastd        m13, [base+pb_15]
+    valignq              m0, m8, m7, 7
+    pminub              m12, m13, [pb_0to63]
+    valignq             m11, m8, m7, 1
+    call mangle(private_prefix %+ _ipred_z1_8bpc_avx512icl).w64_filter
+.w16_main:
+    vbroadcasti32x4      m3, [base+z_ypos_mul2a] ; 1.. 8
+    vbroadcasti32x4      m2, [base+z_ypos_mul2b] ; 9..15
+    vpbroadcastw         m0, dyd
+    vpbroadcastd         m6, [base+pb_4]
+    pmulhuw              m3, m0 ; ypos >> 1
+    pmulhuw              m2, m0
+    movshdup             m0, [base+z_ypos_off2]
+    lea                  r2, [strideq*3]
+    vpbroadcastd         m1, [base+pb_1]
+    vpermw               m4, m3, m14 ; 64-frac, frac
+    psrlw                m3, 5
+    vpermw               m5, m2, m14
+    psrlw                m2, 5
+    packsswb             m3, m2
+    paddsb               m3, m0
+    paddsb               m1, m3
+    punpcklbw            m2, m3, m1 ; base, base+1
+    punpckhbw            m3, m1
+.w16_loop:
+%macro Z3_PERM2 0
+    mova                 m0, m7
+    vpermt2b             m0, m2, m8
+    mova                 m1, m7
+    vpermt2b             m1, m3, m8
+    pmaddubsw            m0, m4
+    pmaddubsw            m1, m5
+    paddsb               m2, m6
+    paddsb               m3, m6
+    pmulhrsw             m0, m15
+    pmulhrsw             m1, m15
+    packuswb             m0, m1
+%endmacro
+    Z3_PERM2
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+r2       ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32:
+    mov                  r3d, 32
+    call .w16_load
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w32_main
+    vpbroadcastd         m2, [tlq-3]
+    cmp                  hd, 64
+    je .w32_filter64
+    lea                 r3d, [hq+31]
+    vpbroadcastb         m9, r3d
+    call mangle(private_prefix %+ _ipred_z1_8bpc_avx512icl).w32_filter
+    vpermb               m8, m9, m7
+    jmp .w32_main
+.w32_filter64:
+    vpbroadcastd        m13, [base+pb_31]
+    valignq              m0, m8, m7, 7
+    pminub              m12, m13, [pb_0to63]
+    valignq             m11, m8, m7, 1
+    call mangle(private_prefix %+ _ipred_z1_8bpc_avx512icl).w64_filter
+.w32_main:
+    vbroadcasti32x8      m3, [base+z_ypos_mul2a] ; 1.. 8
+    vbroadcasti32x8      m2, [base+z_ypos_mul2b] ; 9..15
+    vpbroadcastw         m0, dyd
+    vpbroadcastd         m1, [base+pb_1]
+    pmulhuw              m3, m0 ; ypos >> 1
+    pmulhuw              m2, m0
+    vpbroadcastd         m6, [base+pb_2]
+    mova                ym0, ym1
+    vpermw               m4, m3, m14 ; 64-frac, frac
+    psrlw                m3, 5
+    vpermw               m5, m2, m14
+    psrlw                m2, 5
+    packsswb             m3, m2
+    paddsb               m3, m0
+    paddsb               m1, m3
+    punpcklbw            m2, m3, m1 ; base, base+1
+    punpckhbw            m3, m1
+.w32_loop:
+    Z3_PERM2
+    vextracti32x8 [dstq+strideq*0], m0, 1
+    mova          [dstq+strideq*1], ym0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64:
+    mova                 m7, [tlq-64*1]
+    cmp                  hd, 64
+    je .w64_h64
+    lea                 r3d, [hq*2-1]
+    xor                 r3d, 63 ; -(h + imin(w, h)) & 63
+    vpbroadcastb         m1, r3d
+    pmaxub               m0, m1
+    vpermb               m8, m1, m7
+    jmp .w64_filter
+.w64_h64:
+    vpermb               m8, m0, [tlq-64*2]
+.w64_filter:
+    vpermb               m7, m0, m7
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w64_main
+    lea                 r3d, [hq-1]
+    vpbroadcastd         m2, [tlq-3]
+    vpbroadcastb        m13, r3d
+    valignq              m0, m8, m7, 7
+    pminub              m12, m13, [pb_0to63]
+    valignq             m11, m8, m7, 1
+    call mangle(private_prefix %+ _ipred_z1_8bpc_avx512icl).w64_filter
+.w64_main:
+    vpbroadcastw         m2, dyd
+    pmulhuw              m3, m2, [base+z_ypos_mul2a]
+    pmulhuw              m2, [base+z_ypos_mul2b]
+    vpbroadcastd         m6, [base+pb_1]
+    vpermw               m4, m3, m14 ; 64-frac, frac
+    psrlw                m3, 5
+    vpermw               m5, m2, m14
+    psrlw                m2, 5
+    packsswb             m3, m2
+    paddsb               m1, m3, m6
+    punpcklbw            m2, m3, m1 ; base, base+1
+    punpckhbw            m3, m1
+.w64_loop:
+    Z3_PERM2
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+
+; The ipred_filter code processes 4x2 blocks in the following order
+; which increases parallelism compared to doing things row by row.
+; Some redundant blocks are calculated for w > 4.
+;     w4     w8       w16             w32
+;     1     1 2     1 2 3 4     1 2 3 4 9 a b c
+;     2     2 3     2 3 4 5     2 3 4 5 a b c d
+;     3     3 4     3 4 5 6     3 4 5 6 b c d e
+;     4     4 5     4 5 6 7     4 5 6 7 c d e f
+;     5     5 6     5 6 7 8     5 6 7 8 d e f g
+;     6     6 7     6 7 8 9     6 7 8 9 e f g h
+;     7     7 8     7 8 9 a     7 8 9 a f g h i
+; ___ 8 ___ 8 9 ___ 8 9 a b ___ 8 9 a b g h i j ___
+;           9       9 a b               h i j
+;                   a b                 i j
+;                   b                   j
+
+cglobal ipred_filter_8bpc, 4, 7, 14, dst, stride, tl, w, h, flt
+%define base r6-filter_taps
+    lea                  r6, [filter_taps]
+%ifidn fltd, fltm
+    movzx              fltd, fltb
+%else
+    movzx              fltd, byte fltm
+%endif
+    vpbroadcastd       xmm2, [tlq+1]        ; t0 t0 t0 t0
+    movifnidn            hd, hm
+    shl                fltd, 6
+    vpbroadcastd         m6, [base+pd_8]
+    vpbroadcastd       xmm3, [tlq-2]        ; l1 l0 tl __
+    vbroadcasti32x4      m7, [r6+fltq+16*0] ; p1 p2 p3 p4
+    vbroadcasti32x4      m8, [r6+fltq+16*1]
+    vbroadcasti32x4      m9, [r6+fltq+16*2] ; p6 p5 p0 __
+    vbroadcasti32x4     m10, [r6+fltq+16*3]
+    mova               xmm0, xm6
+    vpdpbusd           xmm0, xmm2, xm7
+    mova               xmm1, xm6
+    vpdpbusd           xmm1, xmm2, xm8
+    vpdpbusd           xmm0, xmm3, xm9
+    vpdpbusd           xmm1, xmm3, xm10
+    packssdw           xmm0, xmm1
+    cmp                  wd, 8
+    jb .w4
+    vpbroadcastd        ym2, [tlq+5]
+    mova                m11, [base+filter_perm]
+    mov                  r5, 0xffffffffffff000f
+    psrldq             xmm2, 1           ; __ t0
+    kmovq                k1, r5          ; 0x000f
+    psraw               xm5, xmm0, 4
+    packuswb           xmm2, xm5         ; __ t0 a0 b0
+    pshufd          ym2{k1}, ymm2, q3333 ; b0 b0 b0 b0   t1 t1 t1 t1
+    je .w8
+    kxnorb               k3, k3, k3      ; 0x00ff
+    vpbroadcastd        xm3, [tlq-4]
+    kandnq               k2, k3, k1      ; 0xffffffffffff0000
+    vpermb          ym3{k2}, ym11, ymm2  ; l3 l2 l1 __   b3 a3 t3 __
+    mova                ym0, ym6
+    vpdpbusd            ym0, ym2, ym7
+    mova                ym1, ym6
+    vpdpbusd            ym1, ym2, ym8
+    pshufb          ym5{k2}, ym2, ym11   ; a0 b0   __ t0
+    vpbroadcastd         m2, [tlq+9]
+    vpdpbusd            ym0, ym3, ym9
+    vpdpbusd            ym1, ym3, ym10
+    vpbroadcastd        xm3, [tlq-6]     ; l5 l4 l3 __
+    kunpckbw             k4, k1, k3      ; 0x0fff
+    packssdw            ym0, ym1
+    psraw               ym0, 4           ; a0 d0         a1 b1
+    packuswb            ym5, ym0         ; a0 b0 c0 d0   __ t1 a1 b1
+    pshufd           m2{k3}, m5, q3333   ; d0 d0 d0 d0   b1 b1 b1 b1   t2 t2 t2 t2
+    vpermb           m3{k2}, m11, m5     ; l5 l4 l3 __   d3 c3 b3 __   b7 a7 t7 __
+    mova                 m4, m6
+    vpdpbusd             m4, m2, m7
+    mova                 m1, m6
+    vpdpbusd             m1, m2, m8
+    psrldq               m0, m2, 1       ; __ d0         __ b0         __ t0
+    vpbroadcastd         m2, [tlq+13]
+    vpdpbusd             m4, m3, m9
+    vpdpbusd             m1, m3, m10
+    mova                m12, [base+filter_end]
+    lea                 r5d, [hq-6]
+    mov                  r6, dstq
+    cmovp                hd, r5d         ; w == 16 ? h : h - 6
+    packssdw             m4, m1
+    psraw                m4, 4           ; e0 f0         c1 d1         a2 b2
+    packuswb             m0, m4          ; __ d0 e0 f0   __ b1 c1 d1   __ t2 a2 b2
+    pshufd           m2{k4}, m0, q3333   ; f0 f0 f0 f0   d1 d1 d1 d1   b2 b2 b2 b2   t3 t3 t3 t3
+.w16_loop:
+    vpbroadcastd        xm3, [tlq-8]
+    vpermb           m3{k2}, m11, m0     ; l7 l6 l5 __   f3 e3 d3 __   d7 c7 b7 __   bb ab tb __
+    mova                 m1, m6
+    vpdpbusd             m1, m2, m7
+    mova                 m0, m6
+    vpdpbusd             m0, m2, m8
+    sub                 tlq, 2
+    vpdpbusd             m1, m3, m9
+    vpdpbusd             m0, m3, m10
+    packssdw             m1, m0
+    mova                 m0, m4
+    psraw                m4, m1, 4       ; g0 h0         e1 f1         c2 d2         a3 b3
+    packuswb             m0, m4          ; e0 f0 g0 h0   c1 d1 e1 f1   a2 b2 c2 d2   __ __ a3 b3
+    pshufd               m2, m0, q3333   ; h0 h0 h0 h0   f1 f1 f1 f1   d2 d2 d2 d2   b3 b3 b3 b3
+    vpermt2d             m5, m12, m0     ; c0 d0 e0 f0   __ __ c1 d1   a0 a1 a2 a3   b0 b1 b2 b3
+    vextracti32x4 [dstq+strideq*0], m5, 2
+    vextracti32x4 [dstq+strideq*1], m5, 3
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    cmp                  wd, 16
+    je .ret
+    mova               xm13, [filter_perm+16]
+    mova               xmm3, [r6+strideq*0]
+    punpckhdq          xmm3, [r6+strideq*1]
+    vpbroadcastd     m2{k1}, [tlq+r5+17] ; t4 t4 t4 t4   f1 f1 f1 f1   d2 d2 d2 d2   b3 b3 b3 b3
+    pinsrb              xm3, xmm3, [tlq+r5+16], 7
+    pshufb              xm3, xm13
+    vpermb           m3{k2}, m11, m0     ; bf af tf __   h3 g3 f3 __   f7 e7 d7 __   db cb bb __
+    mova                 m0, m6
+    vpdpbusd             m0, m2, m7
+    mova                 m1, m6
+    vpdpbusd             m1, m2, m8
+    kunpckbw             k5, k3, k1      ; 0xff0f
+    lea                  r3, [strideq*3]
+    vpdpbusd             m0, m3, m9
+    vpdpbusd             m1, m3, m10
+    packssdw             m0, m1
+    psraw                m0, 4           ; a4 b4         g1 h1         e2 f2         c3 d3
+    packuswb             m4, m0          ; g0 h0 a4 b4   e1 f1 g1 h1   c2 d2 e2 f2   __ __ c3 d3
+    vpblendmb        m1{k3}, m4, m2      ; __ t4 a4 b4   e1 f1 g1 h1   c2 d2 e2 f2   __ __ c3 d3
+    vpbroadcastd        ym2, [tlq+r5+21]
+    pshufd           m2{k5}, m4, q3333   ; b4 b4 b4 b4   t5 t5 t5 t5   f2 f2 f2 f2   d3 d3 d3 d3
+    vpermt2d             m5, m12, m4     ; e0 f0 g0 h0   __ __ e1 f1   c0 c1 c2 c3   d0 d1 d2 d3
+    vextracti32x4 [dstq+strideq*0], m5, 2
+    vextracti32x4 [dstq+strideq*1], m5, 3
+    punpckhqdq         xmm3, [r6+r3]
+    pinsrb             xmm3, [r6+strideq*2+15], 11
+    pshufb              xm3, xmm3, xm13
+    vpermb           m3{k2}, m11, m1     ; df cf bf __   bj aj tj __   h7 g7 f7 __   fb eb db __
+    mova                 m4, m6
+    vpdpbusd             m4, m2, m7
+    mova                 m1, m6
+    vpdpbusd             m1, m2, m8
+    kxnord               k3, k3, k4      ; 0xfffff0ff
+    lea                  r4, [strideq*5]
+    vpdpbusd             m4, m3, m9
+    vpdpbusd             m1, m3, m10
+    packssdw             m4, m1
+    psraw                m4, 4           ; c4 d4         a5 b5         g2 h2         e3 f3
+    packuswb             m0, m4          ; a4 b4 c4 d4   g1 h1 a5 b5   e2 f2 g2 h2   __ __ e3 f3
+    vpblendmw        m1{k3}, m2, m0      ; a4 b4 c4 d4   __ t5 a5 b5   e2 f2 g2 h2   __ __ e3 f3
+    vpbroadcastd         m2, [tlq+r5+25]
+    pshufd           m2{k3}, m0, q3333   ; d4 d4 d4 d4   b5 b5 b5 b5   t6 t6 t6 t6   f3 f3 f3 f3
+    vpermt2d             m5, m12, m0     ; g0 h0 a4 b4   __ __ g1 h1   e0 e1 e2 e3   f0 f1 f2 f3
+    vextracti32x4 [dstq+strideq*2], m5, 2
+    vextracti32x4 [dstq+r3       ], m5, 3
+    punpckhqdq         xmm3, [r6+r4]
+    pinsrb             xmm3, [r6+strideq*4+15], 11
+    pshufb              xm3, xmm3, xm13
+    vpermb           m3{k2}, m11, m1     ; ff ef df __   dj cj bj __   bn an tn __   hb hb fb __
+    mova                 m0, m6
+    vpdpbusd             m0, m2, m7
+    mova                 m1, m6
+    vpdpbusd             m1, m2, m8
+    kunpckwd             k1, k1, k2      ; 0x000f0000
+    vpdpbusd             m0, m3, m9
+    vpdpbusd             m1, m3, m10
+    packssdw             m0, m1
+    psraw                m0, 4           ; e4 f4         c5 d5         a6 b6         g3 h3
+    packuswb             m4, m0          ; c4 d4 e4 f4   a5 b5 c5 d5   g2 h2 a6 b6   __ __ g3 h3
+    vpblendmw        m1{k1}, m4, m2      ; c4 d4 e4 f4   a5 b5 c5 d5   __ t6 a6 b6   __ __ g3 h3
+    vpbroadcastd         m2, [tlq+r5+29]
+    pshufd           m2{k4}, m4, q3333   ; f4 f4 f4 f4   d5 d5 d5 d5   b6 b6 b6 b6   t7 t7 t7 t7
+    vpermt2d             m5, m12, m4     ; a4 b4 c4 d4   __ __ a5 b5   g0 g1 g2 g3   h0 h1 h2 h3
+    vextracti32x4 [dstq+strideq*4], m5, 2
+    vextracti32x4 [dstq+r4       ], m5, 3
+    lea                  r0, [strideq+r3*2]
+.w32_loop:
+    punpckhqdq         xmm3, [r6+r0]
+    pinsrb             xmm3, [r6+r3*2+15], 11
+    pshufb              xm3, xmm3, xm13
+    vpermb           m3{k2}, m11, m1     ; hf gf ff __   fj ej dj __   dn cn bn __   br ar tr __
+.w32_loop_tail:
+    mova                 m4, m6
+    vpdpbusd             m4, m2, m7
+    mova                 m1, m6
+    vpdpbusd             m1, m2, m8
+    vpdpbusd             m4, m3, m9
+    vpdpbusd             m1, m3, m10
+    packssdw             m4, m1
+    mova                 m1, m0
+    psraw                m0, m4, 4       ; g4 h4         e5 f5         c6 d6         a7 b7
+    packuswb             m1, m0          ; e4 f4 g4 h4   c5 d5 e5 f5   a6 b6 c6 d6   __ __ a7 b7
+    pshufd               m2, m1, q3333   ; h4 h4 h4 h4   f5 f5 f5 f5   d6 d6 d6 d6   b7 b7 b7 b7
+    vpermt2d             m5, m12, m1     ; c4 d4 e4 f4   __ __ c5 d5   a4 a5 a6 a7   b4 b5 b6 b7
+    vextracti32x4 [r6+strideq*0+16], m5, 2
+    vextracti32x4 [r6+strideq*1+16], m5, 3
+    lea                  r6, [r6+strideq*2]
+    sub                 r5d, 2
+    jg .w32_loop
+    vpermb               m3, m11, m1
+    cmp                 r5d, -6
+    jg .w32_loop_tail
+.ret:
+    RET
+.w8:
+    vpermb              ym3, ym11, ymm2
+.w8_loop:
+    vpbroadcastd    ym3{k1}, [tlq-4]     ; l3 l2 l1 __   b3 a3 t3 __
+    mova                ym0, ym6
+    vpdpbusd            ym0, ym2, ym7
+    mova                ym1, ym6
+    vpdpbusd            ym1, ym2, ym8
+    sub                 tlq, 2
+    vpdpbusd            ym0, ym3, ym9
+    vpdpbusd            ym1, ym3, ym10
+    mova                ym3, ym5
+    packssdw            ym0, ym1
+    psraw               ym5, ym0, 4      ; c0 d0         a1 b1
+    packuswb            ym3, ym5         ; a0 b0 c0 d0   __ __ a1 b1
+    pshufd              ym2, ym3, q3333  ; d0 d0 d0 d0   b1 b1 b1 b1
+    vpermb              ym3, ym11, ym3   ; a0 a1 b0 b1
+    movq   [dstq+strideq*0], xm3
+    movhps [dstq+strideq*1], xm3
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w4_loop:
+    vpbroadcastd       xmm3, [tlq-4]     ; l3 l2 l1 __
+    mova               xmm0, xm6
+    vpdpbusd           xmm0, xmm2, xm7
+    mova               xmm1, xm6
+    vpdpbusd           xmm1, xmm2, xm8
+    sub                 tlq, 2
+    vpdpbusd           xmm0, xmm3, xm9
+    vpdpbusd           xmm1, xmm3, xm10
+    packssdw           xmm0, xmm1
+.w4:
+    psraw              xmm0, 4           ; a0 b0
+    packuswb           xmm0, xmm0
+    movd   [dstq+strideq*0], xmm0
+    pshufd             xmm2, xmm0, q1111 ; b0 b0 b0 b0
+    movd   [dstq+strideq*1], xmm2
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/ipred_sse.asm b/media/libdav1d/src/src/x86/ipred_sse.asm
new file mode 100644
index 0000000000..f6b0cad001
--- /dev/null
+++ b/media/libdav1d/src/src/x86/ipred_sse.asm
@@ -0,0 +1,5402 @@
+; Copyright © 2018-2021, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 16
+
+%macro SMOOTH_WEIGHT_TABLE 1-*
+    %rep %0
+        db %1-128, 127-%1
+        %rotate 1
+    %endrep
+%endmacro
+
+; sm_weights[], but modified to precalculate x and 256-x with offsets to
+; enable efficient use of pmaddubsw (which requires signed values)
+smooth_weights: SMOOTH_WEIGHT_TABLE         \
+      0,   0, 255, 128, 255, 149,  85,  64, \
+    255, 197, 146, 105,  73,  50,  37,  32, \
+    255, 225, 196, 170, 145, 123, 102,  84, \
+     68,  54,  43,  33,  26,  20,  17,  16, \
+    255, 240, 225, 210, 196, 182, 169, 157, \
+    145, 133, 122, 111, 101,  92,  83,  74, \
+     66,  59,  52,  45,  39,  34,  29,  25, \
+     21,  17,  14,  12,  10,   9,   8,   8, \
+    255, 248, 240, 233, 225, 218, 210, 203, \
+    196, 189, 182, 176, 169, 163, 156, 150, \
+    144, 138, 133, 127, 121, 116, 111, 106, \
+    101,  96,  91,  86,  82,  77,  73,  69, \
+     65,  61,  57,  54,  50,  47,  44,  41, \
+     38,  35,  32,  29,  27,  25,  22,  20, \
+     18,  16,  15,  13,  12,  10,   9,   8, \
+      7,   6,   6,   5,   5,   4,   4,   4
+
+ipred_v_shuf:     db  0,  1,  0,  1,  2,  3,  2,  3,  4,  5,  4,  5,  6,  7,  6,  7
+ipred_h_shuf:     db  3,  3,  3,  3,  2,  2,  2,  2,  1,  1,  1,  1,  0,  0,  0,  0
+ipred_paeth_shuf: db  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0
+z_upsample1:      db  1,  0,  2,  1,  3,  2,  4,  3,  5,  4,  6,  5,  7,  6,  8,  7
+z_upsample2:      db  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8,  8,  8,  8,  8
+z_transpose4:     db  8, 12,  0,  4,  9, 13,  1,  5, 10, 14,  2,  6, 11, 15,  3,  7
+z3_shuf:          db  1,  0,  2,  1,  3,  2,  4,  3,  5,  4,  6,  5,  7,  6,  8,  7
+z3_shuf_h4:       db  4,  3,  3,  2,  2,  1,  1,  0, 12, 11, 11, 10, 10,  9,  9,  8
+filter_shuf1:     db  3,  4,  3,  4,  5,  6,  5,  6,  7,  2,  7,  2,  1, -1,  1, -1
+filter_shuf2:     db  3,  4,  3,  4,  5,  6,  5,  6,  7, 11,  7, 11, 15, -1, 15, -1
+z_filter_wh4:     db  7,  7, 19,  7,
+z_filter_wh8:     db 19, 19, 11, 19, 11, 15, 15, 15, 23, 23, 23, 23, 39, 39, 39, 39
+pd_32768:         dd 32768
+z3_filter_k_tail: db 64,  0, 64,  0, 64,  0, 56,  8
+z1_shuf_w4:       db  0,  1,  1,  2,  2,  3,  3,  4,  8,  9,  9, 10, 10, 11, 11, 12
+pb_0to15:         db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+pb_15to0:         db 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0
+z_base_inc:       dw   0*64,   1*64,   2*64,   3*64,   4*64,   5*64,   6*64,   7*64
+z3_base_inc:      dw   7*64,   6*64,   5*64,   4*64,   3*64,   2*64,   1*64,   0*64
+z_filter_wh16:    db 19, 19, 19, 23, 23, 23, 31, 31, 31, 47, 47, 47, 79, 79, 79, -1
+z_filter_t_w48:   db 55,127,  7,127, 15, 31, 39, 31,127, 39,127, 39,  7, 15, 31, 15
+                  db 39, 63,  3, 63,  3,  3, 19,  3, 47, 19, 47, 19,  3,  3,  3,  3
+z_filter_t_w16:   db 15, 31,  7, 15, 31,  7,  3, 31,  3,  3,  3,  3,  3,  3,  0,  0
+z_filter_s:       db  0,  0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7
+                  db  7,  8,  8,  9,  9, 10, 10, 11
+z_filter_k_tail:  db  0, 64,  0, 64,  8, 56,  0, 64
+z2_h_shuf:        db  7,  6, 15, 14,  6,  5, 14, 13,  5,  4, 13, 12,  4,  3, 12, 11
+z2_upsample:      db  7,  6, 15, 14,  5,  4, 13, 12,  3,  2, 11, 10,  1,  0,  9,  8
+z2_dy_offset:     dw 88*64, 88*64, 87*64, 87*64
+pw_m1to4:         dw -1, -2, -3, -4
+z_filter_k:       times  4 db  0, 16
+                  times  4 db  0, 20
+                  times  4 db  8, 16
+                  times  4 db 32, 16
+                  times  4 db 24, 20
+                  times  4 db 16, 16
+                  times  4 db  0,  0
+                  times  4 db  0,  0
+pw_8:             times  8 db  8,  0
+pb_3:             times 16 db 3
+pb_16:            times 16 db 16
+pw_62:            times  8 dw 62
+pw_64:            times  8 dw 64
+pw_256:           times  8 dw 256
+pw_512:           times  8 dw 512
+pw_m256:          times  8 dw -256
+pb_2:             times  8 db 2
+pb_4:             times  8 db 4
+pb_8:             times  8 db 8
+pb_128:           times  8 db 128
+pb_m16:           times  8 db -16
+pw_128:           times  4 dw 128
+pw_255:           times  4 dw 255
+pb_36_m4:         times  4 db 36, -4
+pb_127_m127:      times  4 db 127, -127
+
+%macro JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - 2*4)
+    %xdefine %%base mangle(private_prefix %+ _%1_8bpc_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%base %+ .%3 - (%%table - 2*4)
+        %rotate 1
+    %endrep
+%endmacro
+
+%define ipred_dc_splat_ssse3_table (ipred_dc_ssse3_table + 10*4)
+%define ipred_cfl_splat_ssse3_table (ipred_cfl_ssse3_table + 8*4)
+
+JMP_TABLE ipred_h,          ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_dc,         ssse3, h4, h8, h16, h32, h64, w4, w8, w16, w32, w64, \
+                                s4-10*4, s8-10*4, s16-10*4, s32-10*4, s64-10*4
+JMP_TABLE ipred_dc_left,    ssse3, h4, h8, h16, h32, h64
+JMP_TABLE ipred_smooth,     ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_v,   ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_smooth_h,   ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_paeth,      ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z1,         ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z2,         ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_z3,         ssse3, h4, h8, h16, h32, h64
+JMP_TABLE pal_pred,         ssse3, w4, w8, w16, w32, w64
+JMP_TABLE ipred_cfl,        ssse3, h4, h8, h16, h32, w4, w8, w16, w32, \
+                                s4-8*4, s8-8*4, s16-8*4, s32-8*4
+JMP_TABLE ipred_cfl_left,   ssse3, h4, h8, h16, h32
+JMP_TABLE ipred_filter,     ssse3, w4, w8, w16, w32
+
+cextern dr_intra_derivative
+cextern filter_intra_taps
+
+SECTION .text
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_h_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+%macro IPRED_SET   3                                          ; width, stride, stride size pshuflw_imm8
+    pshuflw                      m1, m0, %3                   ; extend 8 byte for 2 pos
+    punpcklqdq                   m1, m1
+    mova           [dstq +      %2], m1
+%if %1 > 16
+    mova           [dstq + 16 + %2], m1
+%endif
+%if %1 > 32
+    mova           [dstq + 32 + %2], m1
+    mova           [dstq + 48 + %2], m1
+%endif
+%endmacro
+
+%macro IPRED_H 1                                            ; width
+    sub                         tlq, 4
+    movd                         m0, [tlq]                  ; get 4 bytes of topleft data
+    punpcklbw                    m0, m0                     ; extend 2 byte
+%if %1 == 4
+    pshuflw                      m1, m0, q2233
+    movd           [dstq+strideq*0], m1
+    psrlq                        m1, 32
+    movd           [dstq+strideq*1], m1
+    pshuflw                      m0, m0, q0011
+    movd           [dstq+strideq*2], m0
+    psrlq                        m0, 32
+    movd           [dstq+stride3q ], m0
+
+%elif %1 == 8
+    punpcklwd                    m0, m0
+    punpckhdq                    m1, m0, m0
+    punpckldq                    m0, m0
+    movq           [dstq+strideq*1], m1
+    movhps         [dstq+strideq*0], m1
+    movq           [dstq+stride3q ], m0
+    movhps         [dstq+strideq*2], m0
+%else
+    IPRED_SET                    %1,         0, q3333
+    IPRED_SET                    %1,   strideq, q2222
+    IPRED_SET                    %1, strideq*2, q1111
+    IPRED_SET                    %1,  stride3q, q0000
+%endif
+    lea                        dstq, [dstq+strideq*4]
+    sub                          hd, 4
+    jg .w%1
+    RET
+%endmacro
+
+INIT_XMM ssse3
+cglobal ipred_h_8bpc, 3, 6, 2, dst, stride, tl, w, h, stride3
+    LEA                          r5, ipred_h_ssse3_table
+    tzcnt                        wd, wm
+    movifnidn                    hd, hm
+    movsxd                       wq, [r5+wq*4]
+    add                          wq, r5
+    lea                    stride3q, [strideq*3]
+    jmp                          wq
+.w4:
+    IPRED_H                       4
+.w8:
+    IPRED_H                       8
+.w16:
+    IPRED_H                      16
+.w32:
+    IPRED_H                      32
+.w64:
+    IPRED_H                      64
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_v_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+cglobal ipred_v_8bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    LEA                  r5, ipred_dc_splat_ssse3_table
+    tzcnt                wd, wm
+    movu                 m0, [tlq+ 1]
+    movu                 m1, [tlq+17]
+    movu                 m2, [tlq+33]
+    movu                 m3, [tlq+49]
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_dc_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+cglobal ipred_dc_8bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    movifnidn                    hd, hm
+    movifnidn                    wd, wm
+    tzcnt                       r6d, hd
+    lea                         r5d, [wq+hq]
+    movd                         m4, r5d
+    tzcnt                       r5d, r5d
+    movd                         m5, r5d
+    LEA                          r5, ipred_dc_ssse3_table
+    tzcnt                        wd, wd
+    movsxd                       r6, [r5+r6*4]
+    movsxd                       wq, [r5+wq*4+20]
+    pcmpeqd                      m3, m3
+    psrlw                        m4, 1                             ; dc = (width + height) >> 1;
+    add                          r6, r5
+    add                          wq, r5
+    lea                    stride3q, [strideq*3]
+    jmp r6
+.h4:
+    movd                         m0, [tlq-4]
+    pmaddubsw                    m0, m3
+    jmp                          wq
+.w4:
+    movd                         m1, [tlq+1]
+    pmaddubsw                    m1, m3
+    psubw                        m0, m4
+    paddw                        m0, m1
+    pmaddwd                      m0, m3
+    cmp                          hd, 4
+    jg .w4_mul
+    psrlw                        m0, 3                             ; dc >>= ctz(width + height);
+    jmp .w4_end
+.w4_mul:
+    punpckhqdq                   m1, m0, m0
+    paddw                        m0, m1
+    psrlq                        m1, m0, 32
+    paddw                        m0, m1
+    psrlw                        m0, 2
+    mov                         r6d, 0x5556
+    mov                         r2d, 0x3334
+    test                         hd, 8
+    cmovz                       r6d, r2d
+    movd                         m5, r6d
+    pmulhuw                      m0, m5
+.w4_end:
+    pxor                         m1, m1
+    pshufb                       m0, m1
+.s4:
+    movd           [dstq+strideq*0], m0
+    movd           [dstq+strideq*1], m0
+    movd           [dstq+strideq*2], m0
+    movd           [dstq+stride3q ], m0
+    lea                        dstq, [dstq+strideq*4]
+    sub                          hd, 4
+    jg .s4
+    RET
+ALIGN function_align
+.h8:
+    movq                         m0, [tlq-8]
+    pmaddubsw                    m0, m3
+    jmp                          wq
+.w8:
+    movq                         m1, [tlq+1]
+    pmaddubsw                    m1, m3
+    psubw                        m4, m0
+    punpckhqdq                   m0, m0
+    psubw                        m0, m4
+    paddw                        m0, m1
+    pshuflw                      m1, m0, q1032                  ; psrlq  m1, m0, 32
+    paddw                        m0, m1
+    pmaddwd                      m0, m3
+    psrlw                        m0, m5
+    cmp                          hd, 8
+    je .w8_end
+    mov                         r6d, 0x5556
+    mov                         r2d, 0x3334
+    cmp                          hd, 32
+    cmovz                       r6d, r2d
+    movd                         m1, r6d
+    pmulhuw                      m0, m1
+.w8_end:
+    pxor                         m1, m1
+    pshufb                       m0, m1
+.s8:
+    movq           [dstq+strideq*0], m0
+    movq           [dstq+strideq*1], m0
+    movq           [dstq+strideq*2], m0
+    movq           [dstq+stride3q ], m0
+    lea                        dstq, [dstq+strideq*4]
+    sub                          hd, 4
+    jg .s8
+    RET
+ALIGN function_align
+.h16:
+    mova                         m0, [tlq-16]
+    pmaddubsw                    m0, m3
+    jmp                          wq
+.w16:
+    movu                         m1, [tlq+1]
+    pmaddubsw                    m1, m3
+    paddw                        m0, m1
+    psubw                        m4, m0
+    punpckhqdq                   m0, m0
+    psubw                        m0, m4
+    pshuflw                      m1, m0, q1032                  ; psrlq  m1, m0, 32
+    paddw                        m0, m1
+    pmaddwd                      m0, m3
+    psrlw                        m0, m5
+    cmp                          hd, 16
+    je .w16_end
+    mov                         r6d, 0x5556
+    mov                         r2d, 0x3334
+    test                         hd, 8|32
+    cmovz                       r6d, r2d
+    movd                         m1, r6d
+    pmulhuw                      m0, m1
+.w16_end:
+    pxor                         m1, m1
+    pshufb                       m0, m1
+.s16:
+    mova           [dstq+strideq*0], m0
+    mova           [dstq+strideq*1], m0
+    mova           [dstq+strideq*2], m0
+    mova           [dstq+stride3q ], m0
+    lea                        dstq, [dstq+strideq*4]
+    sub                          hd, 4
+    jg .s16
+    RET
+ALIGN function_align
+.h32:
+    mova                         m0, [tlq-32]
+    pmaddubsw                    m0, m3
+    mova                         m2, [tlq-16]
+    pmaddubsw                    m2, m3
+    paddw                        m0, m2
+    jmp wq
+.w32:
+    movu                         m1, [tlq+1]
+    pmaddubsw                    m1, m3
+    movu                         m2, [tlq+17]
+    pmaddubsw                    m2, m3
+    paddw                        m1, m2
+    paddw                        m0, m1
+    psubw                        m4, m0
+    punpckhqdq                   m0, m0
+    psubw                        m0, m4
+    pshuflw                      m1, m0, q1032                   ; psrlq  m1, m0, 32
+    paddw                        m0, m1
+    pmaddwd                      m0, m3
+    psrlw                        m0, m5
+    cmp                          hd, 32
+    je .w32_end
+    lea                         r2d, [hq*2]
+    mov                         r6d, 0x5556
+    mov                         r2d, 0x3334
+    test                         hd, 64|16
+    cmovz                       r6d, r2d
+    movd                         m1, r6d
+    pmulhuw                      m0, m1
+.w32_end:
+    pxor                         m1, m1
+    pshufb                       m0, m1
+    mova                         m1, m0
+.s32:
+    mova                     [dstq], m0
+    mova                  [dstq+16], m1
+    mova             [dstq+strideq], m0
+    mova          [dstq+strideq+16], m1
+    mova           [dstq+strideq*2], m0
+    mova        [dstq+strideq*2+16], m1
+    mova            [dstq+stride3q], m0
+    mova         [dstq+stride3q+16], m1
+    lea                        dstq, [dstq+strideq*4]
+    sub                          hd, 4
+    jg .s32
+    RET
+ALIGN function_align
+.h64:
+    mova                         m0, [tlq-64]
+    mova                         m1, [tlq-48]
+    pmaddubsw                    m0, m3
+    pmaddubsw                    m1, m3
+    paddw                        m0, m1
+    mova                         m1, [tlq-32]
+    pmaddubsw                    m1, m3
+    paddw                        m0, m1
+    mova                         m1, [tlq-16]
+    pmaddubsw                    m1, m3
+    paddw                        m0, m1
+    jmp wq
+.w64:
+    movu                         m1, [tlq+ 1]
+    movu                         m2, [tlq+17]
+    pmaddubsw                    m1, m3
+    pmaddubsw                    m2, m3
+    paddw                        m1, m2
+    movu                         m2, [tlq+33]
+    pmaddubsw                    m2, m3
+    paddw                        m1, m2
+    movu                         m2, [tlq+49]
+    pmaddubsw                    m2, m3
+    paddw                        m1, m2
+    paddw                        m0, m1
+    psubw                        m4, m0
+    punpckhqdq                   m0, m0
+    psubw                        m0, m4
+    pshuflw                      m1, m0, q1032                   ; psrlq  m1, m0, 32
+    paddw                        m0, m1
+    pmaddwd                      m0, m3
+    psrlw                        m0, m5
+    cmp                          hd, 64
+    je .w64_end
+    mov                         r6d, 0x5556
+    mov                         r2d, 0x3334
+    test                         hd, 32
+    cmovz                       r6d, r2d
+    movd                         m1, r6d
+    pmulhuw                      m0, m1
+.w64_end:
+    pxor                         m1, m1
+    pshufb                       m0, m1
+    mova                         m1, m0
+    mova                         m2, m0
+    mova                         m3, m0
+.s64:
+    mova                     [dstq], m0
+    mova                  [dstq+16], m1
+    mova                  [dstq+32], m2
+    mova                  [dstq+48], m3
+    mova             [dstq+strideq], m0
+    mova          [dstq+strideq+16], m1
+    mova          [dstq+strideq+32], m2
+    mova          [dstq+strideq+48], m3
+    lea                        dstq, [dstq+strideq*2]
+    sub                          hd, 2
+    jg .s64
+    RET
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_dc_left_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+cglobal ipred_dc_left_8bpc, 3, 7, 6, dst, stride, tl, w, h, stride3
+    LEA                  r5, ipred_dc_left_ssse3_table
+    mov                  hd, hm                ; zero upper half
+    tzcnt               r6d, hd
+    sub                 tlq, hq
+    tzcnt                wd, wm
+    movu                 m0, [tlq]
+    movd                 m3, [r5-ipred_dc_left_ssse3_table+pd_32768]
+    movd                 m2, r6d
+    psrld                m3, m2
+    movsxd               r6, [r5+r6*4]
+    pcmpeqd              m2, m2
+    pmaddubsw            m0, m2
+    add                  r6, r5
+    add                  r5, ipred_dc_splat_ssse3_table-ipred_dc_left_ssse3_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+.h64:
+    movu                 m1, [tlq+48]                           ; unaligned when jumping here from dc_top
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    movu                 m1, [tlq+32]                           ; unaligned when jumping here from dc_top
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+.h32:
+    movu                 m1, [tlq+16]                           ; unaligned when jumping here from dc_top
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+.h16:
+    pshufd               m1, m0, q3232                          ; psrlq               m1, m0, 16
+    paddw                m0, m1
+.h8:
+    pshuflw              m1, m0, q1032                          ; psrlq               m1, m0, 32
+    paddw                m0, m1
+.h4:
+    pmaddwd              m0, m2
+    pmulhrsw             m0, m3
+    lea            stride3q, [strideq*3]
+    pxor                 m1, m1
+    pshufb               m0, m1
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+    jmp                  wq
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_dc_128_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+cglobal ipred_dc_128_8bpc, 2, 7, 6, dst, stride, tl, w, h, stride3
+    LEA                  r5, ipred_dc_splat_ssse3_table
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    movddup              m0, [r5-ipred_dc_splat_ssse3_table+pb_128]
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+    add                  wq, r5
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_dc_top_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+cglobal ipred_dc_top_8bpc, 3, 7, 6, dst, stride, tl, w, h
+    LEA                  r5, ipred_dc_left_ssse3_table
+    tzcnt                wd, wm
+    inc                 tlq
+    movu                 m0, [tlq]
+    movifnidn            hd, hm
+    movd                 m3, [r5-ipred_dc_left_ssse3_table+pd_32768]
+    movd                 m2, wd
+    psrld                m3, m2
+    movsxd               r6, [r5+wq*4]
+    pcmpeqd              m2, m2
+    pmaddubsw            m0, m2
+    add                  r6, r5
+    add                  r5, ipred_dc_splat_ssse3_table-ipred_dc_left_ssse3_table
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  r6
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_smooth_v_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+%macro SMOOTH 6 ; src[1-2], mul[1-2], add[1-2]
+                ;            w * a         = (w - 128) * a + 128 * a
+                ;            (256 - w) * b = (127 - w) * b + 129 * b
+                ; => w * a + (256 - w) * b = [(w - 128) * a + (127 - w) * b] + [128 * a + 129 * b]
+    pmaddubsw            m6, m%3, m%1
+    pmaddubsw            m0, m%4, m%2                    ; (w - 128) * a + (127 - w) * b
+    paddw                m6, m%5
+    paddw                m0, m%6                         ; [(w - 128) * a + (127 - w) * b] + [128 * a + 129 * b + 128]
+    psrlw                m6, 8
+    psrlw                m0, 8
+    packuswb             m6, m0
+%endmacro
+
+cglobal ipred_smooth_v_8bpc, 3, 7, 7, dst, stride, tl, w, h, weights
+%define base r6-ipred_smooth_v_ssse3_table
+    LEA                  r6, ipred_smooth_v_ssse3_table
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    movddup              m0, [base+pb_127_m127]
+    movddup              m1, [base+pw_128]
+    lea            weightsq, [base+smooth_weights+hq*4]
+    neg                  hq
+    movd                 m5, [tlq+hq]
+    pxor                 m2, m2
+    pshufb               m5, m2
+    add                  wq, r6
+    jmp                  wq
+.w4:
+    movd                 m2, [tlq+1]
+    punpckldq            m2, m2
+    punpcklbw            m2, m5                          ; top, bottom
+    lea                  r3, [strideq*3]
+    mova                 m4, [base+ipred_v_shuf]
+    mova                 m5, m4
+    punpckldq            m4, m4
+    punpckhdq            m5, m5
+    pmaddubsw            m3, m2, m0                      ; m3: 127 * top - 127 * bottom
+    paddw                m1, m2                          ; m1:   1 * top + 256 * bottom + 128, overflow is ok
+    paddw                m3, m1                          ; m3: 128 * top + 129 * bottom + 128
+.w4_loop:
+    movu                 m1, [weightsq+hq*2]
+    pshufb               m0, m1, m4                      ;m2, m3, m4 and m5 should be stable in loop
+    pshufb               m1, m5
+    SMOOTH                0, 1, 2, 2, 3, 3
+    movd   [dstq+strideq*0], m6
+    pshuflw              m1, m6, q1032
+    movd   [dstq+strideq*1], m1
+    punpckhqdq           m6, m6
+    movd   [dstq+strideq*2], m6
+    psrlq                m6, 32
+    movd   [dstq+r3       ], m6
+    lea                dstq, [dstq+strideq*4]
+    add                  hq, 4
+    jl .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    movq                 m2, [tlq+1]
+    punpcklbw            m2, m5
+    mova                 m5, [base+ipred_v_shuf]
+    lea                  r3, [strideq*3]
+    pshufd               m4, m5, q0000
+    pshufd               m5, m5, q1111
+    pmaddubsw            m3, m2, m0
+    paddw                m1, m2
+    paddw                m3, m1                           ; m3 is output for loop
+.w8_loop:
+    movq                 m1, [weightsq+hq*2]
+    pshufb               m0, m1, m4
+    pshufb               m1, m5
+    SMOOTH                0, 1, 2, 2, 3, 3
+    movq   [dstq+strideq*0], m6
+    movhps [dstq+strideq*1], m6
+    lea                dstq, [dstq+strideq*2]
+    add                  hq, 2
+    jl .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    movu                 m3, [tlq+1]
+    punpcklbw            m2, m3, m5
+    punpckhbw            m3, m5
+    pmaddubsw            m4, m2, m0
+    pmaddubsw            m5, m3, m0
+    paddw                m0, m1, m2
+    paddw                m1, m3
+    paddw                m4, m0
+    paddw                m5, m1                           ; m4 and m5 is output for loop
+.w16_loop:
+    movd                 m1, [weightsq+hq*2]
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    SMOOTH 1, 1, 2, 3, 4, 5
+    mova             [dstq], m6
+    add                dstq, strideq
+    add                  hq, 1
+    jl .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    WIN64_PUSH_XMM        8, 7
+    mova                 m7, m5
+.w32_loop_init:
+    mov                 r3d, 2
+.w32_loop:
+    movddup              m0, [base+pb_127_m127]
+    movddup              m1, [base+pw_128]
+    movu                 m3, [tlq+1]
+    punpcklbw            m2, m3, m7
+    punpckhbw            m3, m7
+    pmaddubsw            m4, m2, m0
+    pmaddubsw            m5, m3, m0
+    paddw                m0, m1, m2
+    paddw                m1, m3
+    paddw                m4, m0
+    paddw                m5, m1
+    movd                 m1, [weightsq+hq*2]
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    SMOOTH                1, 1, 2, 3, 4, 5
+    mova             [dstq], m6
+    add                 tlq, 16
+    add                dstq, 16
+    dec                 r3d
+    jg .w32_loop
+    lea                dstq, [dstq-32+strideq]
+    sub                 tlq, 32
+    add                  hq, 1
+    jl .w32_loop_init
+    RET
+ALIGN function_align
+.w64:
+    WIN64_PUSH_XMM        8, 7
+    mova                 m7, m5
+.w64_loop_init:
+    mov                 r3d, 4
+.w64_loop:
+    movddup              m0, [base+pb_127_m127]
+    movddup              m1, [base+pw_128]
+    movu                 m3, [tlq+1]
+    punpcklbw            m2, m3, m7
+    punpckhbw            m3, m7
+    pmaddubsw            m4, m2, m0
+    pmaddubsw            m5, m3, m0
+    paddw                m0, m1, m2
+    paddw                m1, m3
+    paddw                m4, m0
+    paddw                m5, m1
+    movd                 m1, [weightsq+hq*2]
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    SMOOTH                1, 1, 2, 3, 4, 5
+    mova             [dstq], m6
+    add                 tlq, 16
+    add                dstq, 16
+    dec                 r3d
+    jg .w64_loop
+    lea                dstq, [dstq-64+strideq]
+    sub                 tlq, 64
+    add                  hq, 1
+    jl .w64_loop_init
+    RET
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_smooth_h_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+cglobal ipred_smooth_h_8bpc, 3, 7, 8, dst, stride, tl, w, h
+%define base r6-ipred_smooth_h_ssse3_table
+    LEA                  r6, ipred_smooth_h_ssse3_table
+    mov                  wd, wm
+    movd                 m3, [tlq+wq]
+    pxor                 m1, m1
+    pshufb               m3, m1                          ; right
+    tzcnt                wd, wd
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    movddup              m4, [base+pb_127_m127]
+    movddup              m5, [base+pw_128]
+    add                  wq, r6
+    jmp                  wq
+.w4:
+    movddup              m6, [base+smooth_weights+4*2]
+    mova                 m7, [base+ipred_h_shuf]
+    sub                 tlq, 4
+    sub                 tlq, hq
+    lea                  r3, [strideq*3]
+.w4_loop:
+    movd                 m2, [tlq+hq]                    ; left
+    pshufb               m2, m7
+    punpcklbw            m1, m2, m3                      ; left, right
+    punpckhbw            m2, m3
+    pmaddubsw            m0, m1, m4                      ; 127 * left - 127 * right
+    paddw                m0, m1                          ; 128 * left + 129 * right
+    pmaddubsw            m1, m6
+    paddw                m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m4
+    paddw                m1, m2
+    pmaddubsw            m2, m6
+    paddw                m2, m5
+    paddw                m1, m2
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    punpckhqdq           m0, m0
+    movd   [dstq+strideq*2], m0
+    psrlq                m0, 32
+    movd   [dstq+r3       ], m0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    mova                 m6, [base+smooth_weights+8*2]
+    mova                 m7, [base+ipred_h_shuf]
+    sub                 tlq, 4
+    sub                 tlq, hq
+    punpckldq            m7, m7
+.w8_loop:
+    movd                 m2, [tlq+hq]                    ; left
+    pshufb               m2, m7
+    punpcklbw            m1, m2, m3                      ; left, right
+    punpckhbw            m2, m3
+    pmaddubsw            m0, m1, m4                      ; 127 * left - 127 * right
+    paddw                m0, m1                          ; 128 * left + 129 * right
+    pmaddubsw            m1, m6
+    paddw                m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m4
+    paddw                m1, m2
+    pmaddubsw            m2, m6
+    paddw                m2, m5
+    paddw                m1, m2
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    mova                 m6, [base+smooth_weights+16*2]
+    mova                 m7, [base+smooth_weights+16*3]
+    sub                 tlq, 1
+    sub                 tlq, hq
+.w16_loop:
+    pxor                 m1, m1
+    movd                 m2, [tlq+hq]                    ; left
+    pshufb               m2, m1
+    punpcklbw            m1, m2, m3                      ; left, right
+    punpckhbw            m2, m3
+    pmaddubsw            m0, m1, m4                      ; 127 * left - 127 * right
+    paddw                m0, m1                          ; 128 * left + 129 * right
+    pmaddubsw            m1, m6
+    paddw                m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m4
+    paddw                m1, m2
+    pmaddubsw            m2, m7
+    paddw                m2, m5
+    paddw                m1, m2
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+    mova             [dstq], m0
+    lea                dstq, [dstq+strideq]
+    sub                  hd, 1
+    jg .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    sub                 tlq, 1
+    sub                 tlq, hq
+    pxor                 m6, m6
+.w32_loop_init:
+    mov                  r5, 2
+    lea                  r3, [base+smooth_weights+16*4]
+.w32_loop:
+    mova                 m7, [r3]
+    add                  r3, 16
+    movd                 m2, [tlq+hq]                    ; left
+    pshufb               m2, m6
+    punpcklbw            m1, m2, m3                      ; left, right
+    punpckhbw            m2, m3
+    pmaddubsw            m0, m1, m4                      ; 127 * left - 127 * right
+    paddw                m0, m1                          ; 128 * left + 129 * right
+    pmaddubsw            m1, m7
+    paddw                m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m4
+    paddw                m1, m2
+    mova                 m7, [r3]
+    add                  r3, 16
+    pmaddubsw            m2, m7
+    paddw                m2, m5
+    paddw                m1, m2
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, 16
+    dec                  r5
+    jg .w32_loop
+    lea                dstq, [dstq-32+strideq]
+    sub                  hd, 1
+    jg .w32_loop_init
+    RET
+ALIGN function_align
+.w64:
+    sub                 tlq, 1
+    sub                 tlq, hq
+    pxor                 m6, m6
+.w64_loop_init:
+    mov                  r5, 4
+    lea                  r3, [base+smooth_weights+16*8]
+.w64_loop:
+    mova                 m7, [r3]
+    add                  r3, 16
+    movd                 m2, [tlq+hq]                    ; left
+    pshufb               m2, m6
+    punpcklbw            m1, m2, m3                      ; left, right
+    punpckhbw            m2, m3
+    pmaddubsw            m0, m1, m4                      ; 127 * left - 127 * right
+    paddw                m0, m1                          ; 128 * left + 129 * right
+    pmaddubsw            m1, m7
+    paddw                m1, m5
+    paddw                m0, m1
+    pmaddubsw            m1, m2, m4
+    paddw                m1, m2
+    mova                 m7, [r3]
+    add                  r3, 16
+    pmaddubsw            m2, m7
+    paddw                m2, m5
+    paddw                m1, m2
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, 16
+    dec                  r5
+    jg .w64_loop
+    lea                dstq, [dstq-64+strideq]
+    sub                  hd, 1
+    jg .w64_loop_init
+    RET
+
+;---------------------------------------------------------------------------------------
+;int dav1d_ipred_smooth_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                                    const int width, const int height, const int a);
+;---------------------------------------------------------------------------------------
+%macro SMOOTH_2D_END  7                                  ; src[1-2], mul[1-2], add[1-2], m3
+    pmaddubsw            m6, m%3, m%1
+    mova                 m0, m6
+    pmaddubsw            m6, m%4, m%2
+    mova                 m1, m6
+%ifnum %5
+    paddw                m0, m%5
+%else
+    paddw                m0, %5
+%endif
+%ifnum %6
+    paddw                m1, m%6
+%else
+    paddw                m1, %6
+%endif
+%ifnum %7
+%else
+    mova                 m3, %7
+%endif
+    pavgw                m0, m2
+    pavgw                m1, m3
+    psrlw                m0, 8
+    psrlw                m1, 8
+    packuswb             m0, m1
+%endmacro
+
+%macro SMOOTH_OUTPUT_16B  12      ; m1, [buffer1, buffer2, buffer3, buffer4,] [w1, w2,] m3, m7, [m0, m4, m5]
+    mova                 m1, [rsp+16*%1]                  ; top
+    punpckhbw            m6, m1, m0                       ; top, bottom
+    punpcklbw            m1, m0                           ; top, bottom
+    pmaddubsw            m2, m1, m5
+    mova        [rsp+16*%2], m1
+    paddw                m1, m3                           ;   1 * top + 255 * bottom + 255
+    paddw                m2, m1                           ; 128 * top + 129 * bottom + 255
+    mova        [rsp+16*%3], m2
+    pmaddubsw            m2, m6, m5
+    mova        [rsp+16*%4], m6
+    paddw                m6, m3                           ;   1 * top + 255 * bottom + 255
+    paddw                m2, m6                           ; 128 * top + 129 * bottom + 255
+    mova        [rsp+16*%5], m2
+    movd                 m1, [tlq+hq]                     ; left
+    pshufb               m1, [base+pb_3]                  ; topleft[-(1 + y)]
+    punpcklbw            m1, m4                           ; left, right
+    pmaddubsw            m2, m1, m5                       ; 127 * left - 127 * right
+    paddw                m2, m1                           ; 128 * left + 129 * right
+    mova                 m3, m2
+    pmaddubsw            m0, m1, %6                       ; weights_hor = &dav1d_sm_weights[width];
+    pmaddubsw            m1, %7
+    paddw                m2, m3, m0
+    paddw                m3, m1
+    movd                 m1, [v_weightsq]                 ; weights_ver = &dav1d_sm_weights[height];
+    mova                 m7, [rsp+16*%9]
+    pshufb               m1, m7
+    mova        [rsp+16*%8], m3
+    mova                 m4, [rsp+16*%2]
+    mova                 m5, [rsp+16*%3]
+    mova                 m3, [rsp+16*%4]
+    mova                 m7, [rsp+16*%5]
+    SMOOTH_2D_END         1, 1, 4, 3, 5, 7, [rsp+16*%8]
+    mova             [dstq], m0
+    movddup              m3, [base+pw_255]                ; recovery
+    mova                 m0, [rsp+16*%10]                 ; recovery
+    mova                 m4, [rsp+16*%11]                 ; recovery
+    mova                 m5, [rsp+16*%12]                 ; recovery
+%endmacro
+
+cglobal ipred_smooth_8bpc, 3, 7, 8, -13*16, dst, stride, tl, w, h, v_weights
+%define base r6-ipred_smooth_ssse3_table
+    mov                  wd, wm
+    mov                  hd, hm
+    LEA                  r6, ipred_smooth_ssse3_table
+    movd                 m4, [tlq+wq]                     ; right
+    pxor                 m2, m2
+    pshufb               m4, m2
+    tzcnt                wd, wd
+    mov                  r5, tlq
+    sub                  r5, hq
+    movsxd               wq, [r6+wq*4]
+    movddup              m5, [base+pb_127_m127]
+    movd                 m0, [r5]
+    pshufb               m0, m2                           ; bottom
+    movddup              m3, [base+pw_255]
+    add                  wq, r6
+    lea          v_weightsq, [base+smooth_weights+hq*2]   ; weights_ver = &dav1d_sm_weights[height]
+    jmp                  wq
+.w4:
+    mova                 m7, [base+ipred_v_shuf]
+    movd                 m1, [tlq+1]                      ; left
+    pshufd               m1, m1, q0000
+    sub                 tlq, 4
+    lea                  r3, [strideq*3]
+    sub                 tlq, hq
+    punpcklbw            m1, m0                           ; top, bottom
+    pshufd               m6, m7, q1100
+    pshufd               m7, m7, q3322
+    pmaddubsw            m2, m1, m5
+    paddw                m3, m1                           ;   1 * top + 255 * bottom + 255
+    paddw                m2, m3                           ; 128 * top + 129 * bottom + 255
+    mova         [rsp+16*0], m1
+    mova         [rsp+16*1], m2
+    movq                 m1,  [base+smooth_weights+4*2]   ; weights_hor = &dav1d_sm_weights[width];
+    punpcklqdq           m1, m1
+    mova         [rsp+16*2], m1
+    mova         [rsp+16*3], m4
+    mova         [rsp+16*4], m6
+    mova         [rsp+16*5], m5
+.w4_loop:
+    movd                 m1, [tlq+hq]                 ; left
+    pshufb               m1, [base+ipred_h_shuf]
+    punpcklbw            m0, m1, m4                   ; left, right
+    punpckhbw            m1, m4
+    pmaddubsw            m2, m0, m5                   ; 127 * left - 127 * right
+    pmaddubsw            m3, m1, m5
+    paddw                m2, m0                       ; 128 * left + 129 * right
+    paddw                m3, m1
+    mova                 m4, [rsp+16*2]
+    pmaddubsw            m0, m4
+    pmaddubsw            m1, m4
+    paddw                m2, m0
+    paddw                m3, m1
+    movq                 m1, [v_weightsq]             ; weights_ver = &dav1d_sm_weights[height];
+    add          v_weightsq, 8
+    pshufb               m0, m1, m6
+    pshufb               m1, m7
+    mova                 m4, [rsp+16*0]
+    mova                 m5, [rsp+16*1]
+    SMOOTH_2D_END         0, 1, 4, 4, 5, 5, 3
+    mova                 m4, [rsp+16*3]
+    mova                 m6, [rsp+16*4]
+    mova                 m5, [rsp+16*5]
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    punpckhqdq           m0, m0
+    movd   [dstq+strideq*2], m0
+    psrlq                m0, 32
+    movd   [dstq+r3       ], m0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    mova                 m7, [base+ipred_v_shuf]
+    movq                 m1, [tlq+1]                  ; left
+    punpcklqdq           m1, m1
+    sub                 tlq, 4
+    sub                 tlq, hq
+    punpcklbw            m1, m0
+    pshufd               m6, m7, q0000
+    pshufd               m7, m7, q1111
+    pmaddubsw            m2, m1, m5
+    paddw                m3, m1
+    paddw                m2, m3
+    mova         [rsp+16*0], m1
+    mova         [rsp+16*1], m2
+    mova                 m1, [base+smooth_weights+8*2] ; weights_hor = &dav1d_sm_weights[width];
+    mova         [rsp+16*2], m1
+    mova         [rsp+16*3], m4
+    mova         [rsp+16*4], m6
+    mova         [rsp+16*5], m5
+.w8_loop:
+    movd                 m1, [tlq+hq]                  ; left
+    pshufb               m1, [base+ipred_h_shuf]
+    pshufd               m1, m1, q1100
+    punpcklbw            m0, m1, m4
+    punpckhbw            m1, m4
+    pmaddubsw            m2, m0, m5
+    pmaddubsw            m3, m1, m5
+    paddw                m2, m0
+    paddw                m3, m1
+    mova                 m4,  [rsp+16*2]
+    pmaddubsw            m0, m4
+    pmaddubsw            m1, m4
+    paddw                m2, m0
+    paddw                m3, m1
+    movd                 m1, [v_weightsq]              ; weights_ver = &dav1d_sm_weights[height];
+    add          v_weightsq, 4
+    pshufb               m0, m1, m6
+    pshufb               m1, m7
+    mova                 m4, [rsp+16*0]
+    mova                 m5, [rsp+16*1]
+    SMOOTH_2D_END 0, 1, 4, 4, 5, 5, 3
+    mova                 m4, [rsp+16*3]
+    mova                 m6, [rsp+16*4]
+    mova                 m5, [rsp+16*5]
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    mova                 m7, [base+ipred_v_shuf]
+    movu                 m1, [tlq+1]                     ; left
+    sub                 tlq, 4
+    sub                 tlq, hq
+    punpckhbw            m6, m1, m0                      ; top, bottom
+    punpcklbw            m1, m0                          ; top, bottom
+    pshufd               m7, m7, q0000
+    mova         [rsp+16*2], m7
+    pmaddubsw            m2, m6, m5
+    mova         [rsp+16*5], m6
+    paddw                m6, m3                          ;   1 * top + 255 * bottom + 255
+    paddw                m2, m6                          ; 128 * top + 129 * bottom + 255
+    mova         [rsp+16*6], m2
+    pmaddubsw            m2, m1, m5
+    paddw                m3, m1                          ;   1 * top + 255 * bottom + 255
+    mova         [rsp+16*0], m1
+    paddw                m2, m3                          ; 128 * top + 129 * bottom + 255
+    mova         [rsp+16*1], m2
+    mova         [rsp+16*3], m4
+    mova         [rsp+16*4], m5
+.w16_loop:
+    movd                 m1, [tlq+hq]                    ; left
+    pshufb               m1, [base+pb_3]                 ; topleft[-(1 + y)]
+    punpcklbw            m1, m4                          ; left, right
+    pmaddubsw            m2, m1, m5                      ; 127 * left - 127 * right
+    paddw                m2, m1                          ; 128 * left + 129 * right
+    mova                 m0, m1
+    mova                 m3, m2
+    pmaddubsw            m0, [base+smooth_weights+16*2]  ; weights_hor = &dav1d_sm_weights[width];
+    pmaddubsw            m1, [base+smooth_weights+16*3]
+    paddw                m2, m0
+    paddw                m3, m1
+    movd                 m1, [v_weightsq]                ; weights_ver = &dav1d_sm_weights[height];
+    add          v_weightsq, 2
+    mova                 m7, [rsp+16*2]
+    pshufb               m1, m7
+    mova         [rsp+16*7], m3
+    mova                 m4, [rsp+16*0]
+    mova                 m5, [rsp+16*1]
+    mova                 m3, [rsp+16*5]
+    mova                 m7, [rsp+16*6]
+    SMOOTH_2D_END 1, 1, 4, 3, 5, 7, [rsp+16*7]
+    mova                 m4, [rsp+16*3]
+    mova                 m5, [rsp+16*4]
+    mova             [dstq], m0
+    lea                dstq, [dstq+strideq]
+    sub                  hd, 1
+    jg .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    movu                 m1, [tlq+1]                     ; top     topleft[1 + x]
+    movu                 m2, [tlq+17]                    ; top
+    mova         [rsp+16*0], m1
+    mova         [rsp+16*1], m2
+    sub                 tlq, 4
+    sub                 tlq, hq
+    mova                 m7, [base+ipred_v_shuf]
+    pshufd               m7, m7, q0000
+    mova         [rsp+16*2], m7
+    mova         [rsp+16*3], m0
+    mova         [rsp+16*4], m4
+    mova         [rsp+16*5], m5
+.w32_loop:
+    SMOOTH_OUTPUT_16B 0, 6, 7, 8, 9, [base+smooth_weights+16*4], [base+smooth_weights+16*5], 10, 2, 3, 4, 5
+    add                dstq, 16
+    SMOOTH_OUTPUT_16B 1, 6, 7, 8, 9, [base+smooth_weights+16*6], [base+smooth_weights+16*7], 10, 2, 3, 4, 5
+    lea                dstq, [dstq-16+strideq]
+    add          v_weightsq, 2
+    sub                  hd, 1
+    jg .w32_loop
+    RET
+ALIGN function_align
+.w64:
+    movu                 m1, [tlq+1]                     ; top     topleft[1 + x]
+    movu                 m2, [tlq+17]                    ; top
+    mova         [rsp+16*0], m1
+    mova         [rsp+16*1], m2
+    movu                 m1, [tlq+33]                    ; top
+    movu                 m2, [tlq+49]                    ; top
+    mova        [rsp+16*11], m1
+    mova        [rsp+16*12], m2
+    sub                 tlq, 4
+    sub                 tlq, hq
+    mova                 m7, [base+ipred_v_shuf]
+    pshufd               m7, m7, q0000
+    mova         [rsp+16*2], m7
+    mova         [rsp+16*3], m0
+    mova         [rsp+16*4], m4
+    mova         [rsp+16*5], m5
+.w64_loop:
+    SMOOTH_OUTPUT_16B  0, 6, 7, 8, 9,  [base+smooth_weights+16*8],  [base+smooth_weights+16*9], 10, 2, 3, 4, 5
+    add                dstq, 16
+    SMOOTH_OUTPUT_16B  1, 6, 7, 8, 9, [base+smooth_weights+16*10], [base+smooth_weights+16*11], 10, 2, 3, 4, 5
+    add                dstq, 16
+    SMOOTH_OUTPUT_16B 11, 6, 7, 8, 9, [base+smooth_weights+16*12], [base+smooth_weights+16*13], 10, 2, 3, 4, 5
+    add                dstq, 16
+    SMOOTH_OUTPUT_16B 12, 6, 7, 8, 9, [base+smooth_weights+16*14], [base+smooth_weights+16*15], 10, 2, 3, 4, 5
+    lea                dstq, [dstq-48+strideq]
+    add          v_weightsq, 2
+    sub                  hd, 1
+    jg .w64_loop
+    RET
+
+%if ARCH_X86_64
+cglobal ipred_z1_8bpc, 3, 8, 11, 16*12, dst, stride, tl, w, h, angle, dx
+    %define            base  r7-$$
+    lea                  r7, [$$]
+    mova                 m8, [base+pw_62]
+    mova                 m9, [base+pw_64]
+    mova                m10, [base+pw_512]
+%else
+cglobal ipred_z1_8bpc, 3, 7, 8, -16*13, dst, _, tl, w, h, angle, dx
+    %define            base  r1-$$
+    %define              m8  [base+pw_62]
+    %define              m9  [base+pw_64]
+    %define             m10  [base+pw_512]
+    %define         strideq  r3
+    %define        stridemp  dword [rsp+16*12]
+    mov            stridemp, r1
+    LEA                  r1, $$
+%endif
+    tzcnt                wd, wm
+    movifnidn        angled, anglem
+    movifnidn            hd, hm
+    inc                 tlq
+    movsxd               wq, [base+ipred_z1_ssse3_table+wq*4]
+    mov                 dxd, angled
+    and                 dxd, 0x7e
+    add              angled, 165 ; ~90
+    lea                  wq, [base+wq+ipred_z1_ssse3_table]
+    movzx               dxd, word [base+dr_intra_derivative+dxq]
+    xor              angled, 0x4ff ; d = 90 - angle
+    jmp                  wq
+.w4:
+    lea                 r3d, [angleq+88]
+    test                r3d, 0x480
+    jnz .w4_no_upsample ; !enable_intra_edge_filter || angle >= 40
+    sar                 r3d, 9
+    add                 r3d, hd
+    cmp                 r3d, 8
+    jg .w4_no_upsample ; h > 8 || (w == h && is_sm)
+    mova                 m1, [tlq-1]
+    pshufb               m0, m1, [base+z_upsample1]
+    pshufb               m1, [base+z_upsample2]
+    movddup              m2, [base+pb_36_m4]
+    add                 dxd, dxd
+    pmaddubsw            m0, m2
+    pshufd               m7, m1, q3333
+    movd           [rsp+16], m7 ; top[max_base_x]
+    pmaddubsw            m1, m2
+    movd                 m6, dxd
+    mov                 r5d, dxd ; xpos
+    pshufb               m6, [base+pw_256]
+    paddw                m1, m0
+    movq                 m0, [tlq]
+    pmulhrsw             m1, m10
+    paddw                m7, m6, m6
+    punpcklqdq           m6, m7 ; xpos0 xpos1
+    packuswb             m1, m1
+    punpcklbw            m0, m1
+    movifnidn       strideq, stridemp
+    mova              [rsp], m0
+.w4_upsample_loop:
+    lea                 r2d, [r5+dxq]
+    shr                 r5d, 6      ; base0
+    movq                 m0, [rsp+r5]
+    lea                 r5d, [r2+dxq]
+    shr                 r2d, 6      ; base1
+    movhps               m0, [rsp+r2]
+    pand                 m2, m8, m6 ; frac
+    psubw                m1, m9, m2 ; 64-frac
+    psllw                m2, 8
+    por                  m1, m2     ; 64-frac, frac
+    pmaddubsw            m0, m1
+    paddw                m6, m7     ; xpos += dx
+    pmulhrsw             m0, m10
+    packuswb             m0, m0
+    movd   [dstq+strideq*0], m0
+    pshuflw              m0, m0, q1032
+    movd   [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w4_upsample_loop
+    RET
+.w4_no_upsample:
+    mov                 r3d, 7     ; max_base
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w4_main
+    lea                 r3d, [hq+3]
+    movd                 m0, r3d
+    movd                 m2, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m1, m1
+    pshufb               m0, m1
+    pshufb               m2, m1
+    pcmpeqb              m1, m0, [base+z_filter_wh4]
+    pand                 m1, m2
+    pcmpgtb              m1, [base+z_filter_t_w48+angleq*8]
+    pmovmskb            r5d, m1
+    mov                 r3d, 7
+    test                r5d, r5d
+    jz .w4_main ; filter_strength == 0
+    mova                 m3, [tlq-1]
+    imul                r5d, 0x55555555
+    movu                 m7, [base+z_filter_s+8]
+    shr                 r5d, 30 ; filter_strength
+    movddup              m0, [base+pb_8]
+    pminub               m7, m0
+    pshufb               m0, m3, [base+z_filter_s]
+    movddup              m4, [base+z_filter_k-8+r5*8+24*0]
+    pshufb               m3, m7
+    movddup              m5, [base+z_filter_k-8+r5*8+24*1]
+    shufps               m2, m0, m3, q2121
+    movddup              m6, [base+z_filter_k-8+r5*8+24*2]
+    pmaddubsw            m0, m4
+    pmaddubsw            m1, m2, m4
+    pmaddubsw            m2, m5
+    paddd                m5, m6
+    pmaddubsw            m4, m3, m5
+    pmaddubsw            m3, m6
+    paddw                m0, m2
+    paddw                m1, m4
+    paddw                m0, m3
+    pshufd               m1, m1, q3333
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    mov                 r5d, 9
+    mov                 tlq, rsp
+    cmp                  hd, 4
+    cmovne              r3d, r5d
+    packuswb             m0, m1
+    mova              [tlq], m0
+.w4_main:
+    add                 tlq, r3
+    movd                 m5, dxd
+    movddup              m0, [base+z_base_inc] ; base_inc << 6
+    movd                 m7, [tlq] ; top[max_base_x]
+    shl                 r3d, 6
+    movd                 m4, r3d
+    pshufb               m5, [base+pw_256]
+    mov                 r5d, dxd ; xpos
+    pshufb               m7, [base+pw_m256]
+    sub                  r5, r3
+    pshufb               m4, [base+pw_256]
+    mova                 m3, [base+z1_shuf_w4]
+    paddw                m6, m5, m5
+    psubw                m4, m0 ; max_base_x
+    punpcklqdq           m5, m6 ; xpos0 xpos1
+.w4_loop:
+    lea                  r3, [r5+dxq]
+    sar                  r5, 6      ; base0
+    movq                 m0, [tlq+r5]
+    lea                  r5, [r3+dxq]
+    sar                  r3, 6      ; base1
+    movhps               m0, [tlq+r3]
+    pand                 m2, m8, m5 ; frac
+    psubw                m1, m9, m2 ; 64-frac
+    psllw                m2, 8
+    pshufb               m0, m3
+    por                  m1, m2     ; 64-frac, frac
+    pmaddubsw            m0, m1
+    movifnidn       strideq, stridemp
+    pcmpgtw              m1, m4, m5 ; base < max_base_x
+    pmulhrsw             m0, m10
+    paddw                m5, m6     ; xpos += dx
+    pand                 m0, m1
+    pandn                m1, m7
+    por                  m0, m1
+    packuswb             m0, m0
+    movd   [dstq+strideq*0], m0
+    pshuflw              m0, m0, q1032
+    movd   [dstq+strideq*1], m0
+    sub                  hd, 2
+    jz .w4_end
+    lea                dstq, [dstq+strideq*2]
+    test                r5d, r5d
+    jl .w4_loop
+    packuswb             m7, m7
+.w4_end_loop:
+    movd   [dstq+strideq*0], m7
+    movd   [dstq+strideq*1], m7
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w4_end_loop
+.w4_end:
+    RET
+.w8:
+    lea                 r3d, [angleq+88]
+    and                 r3d, ~0x7f
+    or                  r3d, hd
+    cmp                 r3d, 8
+    ja .w8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || h > 8
+    mova                 m5, [base+z_upsample1]
+    movu                 m3, [base+z_filter_s+6]
+    movd                 m4, hd
+    mova                 m0, [tlq-1]
+    movu                 m1, [tlq+7]
+    pxor                 m7, m7
+    pshufb               m4, m7
+    movddup              m7, [base+pb_36_m4]
+    pminub               m4, m3
+    add                 dxd, dxd
+    pshufb               m2, m0, m5
+    pmaddubsw            m2, m7
+    pshufb               m0, m3
+    pmaddubsw            m0, m7
+    movd                 m6, dxd
+    pshufb               m3, m1, m5
+    pmaddubsw            m3, m7
+    pshufb               m1, m4
+    pmaddubsw            m1, m7
+    pshufb               m6, [base+pw_256]
+    mov                 r5d, dxd
+    paddw                m2, m0
+    paddw                m7, m6, m6
+    paddw                m3, m1
+    punpcklqdq           m6, m7 ; xpos0 xpos1
+    movu                 m1, [tlq]
+    pmulhrsw             m2, m10
+    pmulhrsw             m3, m10
+    packuswb             m2, m3
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    movifnidn       strideq, stridemp
+    mova         [rsp+16*0], m0
+    mova         [rsp+16*1], m1
+.w8_upsample_loop:
+    lea                 r2d, [r5+dxq]
+    shr                 r5d, 6 ; base0
+    movu                 m0, [rsp+r5]
+    lea                 r5d, [r2+dxq]
+    shr                 r2d, 6 ; base1
+    movu                 m1, [rsp+r2]
+    pand                 m2, m8, m6
+    psubw                m3, m9, m2
+    psllw                m2, 8
+    por                  m3, m2
+    punpcklqdq           m2, m3, m3 ; frac0
+    pmaddubsw            m0, m2
+    punpckhqdq           m3, m3     ; frac1
+    pmaddubsw            m1, m3
+    paddw                m6, m7
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packuswb             m0, m1
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_upsample_loop
+    RET
+.w8_no_upsample:
+    lea                 r3d, [hq+7]
+    movd                 m0, r3d
+    and                 r3d, 7
+    or                  r3d, 8 ; imin(h+7, 15)
+    test             angled, 0x400
+    jnz .w8_main
+    movd                 m2, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m1, m1
+    pshufb               m0, m1
+    pshufb               m2, m1
+    movu                 m1, [base+z_filter_wh8]
+    psrldq               m3, [base+z_filter_t_w48+angleq*8], 4
+    pcmpeqb              m1, m0
+    pand                 m1, m2
+    pcmpgtb              m1, m3
+    pmovmskb            r5d, m1
+    test                r5d, r5d
+    jz .w8_main ; filter_strength == 0
+    movd                 m3, [tlq-1]
+    movu                 m0, [tlq+16*0]
+    imul                r5d, 0x55555555
+    movu                 m1, [tlq+16*1]
+    shr                 r5d, 30 ; filter_strength
+    movd                 m2, [tlq+r3]
+    lea                 tlq, [rsp+16*4]
+    sub                  r5, 3
+    mova         [tlq-16*1], m0
+    pxor                 m7, m7
+    mova         [tlq+16*0], m1
+    pshufb               m3, m7
+    pshufb               m2, m7
+    mova         [tlq-16*2], m3
+    movq        [tlq+r3-15], m2
+    call .filter_edge
+    sar                 r5d, 1
+    add                 r5d, 17
+    cmp                  hd, 8
+    cmova               r3d, r5d
+.w8_main:
+    add                 tlq, r3
+    movd                 m5, dxd
+    movd                 m7, [tlq]
+    shl                 r3d, 6
+    movu                 m3, [base+z_filter_s+2]
+    movd                 m4, r3d
+    pshufb               m5, [base+pw_256]
+    mov                 r5d, dxd
+    pshufb               m7, [base+pw_m256]
+    sub                  r5, r3
+    pshufb               m4, [base+pw_256]
+    psubw                m4, [base+z_base_inc]
+    mova                 m6, m5
+.w8_loop:
+    mov                  r3, r5
+    sar                  r3, 6
+    movu                 m0, [tlq+r3]
+    pand                 m1, m8, m5
+    psubw                m2, m9, m1
+    psllw                m1, 8
+    pshufb               m0, m3
+    por                  m1, m2
+    pmaddubsw            m0, m1
+    pcmpgtw              m1, m4, m5
+    paddw                m5, m6
+    pmulhrsw             m0, m10
+    pand                 m0, m1
+    pandn                m1, m7
+    por                  m0, m1
+    packuswb             m0, m0
+    movq             [dstq], m0
+    dec                  hd
+    jz .w8_end
+    movifnidn       strideq, stridemp
+    add                dstq, strideq
+    add                  r5, dxq
+    jl .w8_loop
+    packuswb             m7, m7
+.w8_end_loop:
+    movq             [dstq], m7
+    add                dstq, strideq
+    dec                  hd
+    jg .w8_end_loop
+.w8_end:
+    RET
+.w16:
+    lea                 r3d, [hq+15]
+    movd                 m0, r3d
+    and                 r3d, 15
+    or                  r3d, 16 ; imin(h+15, 31)
+    test             angled, 0x400
+    jnz .w16_main
+    movd                 m2, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m1, m1
+    pshufb               m0, m1
+    pshufb               m2, m1
+    movq                 m3, [base+z_filter_t_w16+angleq*4]
+    pcmpeqb              m0, [base+z_filter_wh16]
+    pand                 m0, m2
+    pcmpgtb              m0, m3
+    pmovmskb            r5d, m0
+    test                r5d, r5d
+    jz .w16_main ; filter_strength == 0
+    movd                 m4, [tlq-1]
+    movu                 m0, [tlq+16*0]
+    imul                r5d, 0x24924924
+    movu                 m1, [tlq+16*1]
+    shr                 r5d, 30
+    movd                 m2, [tlq+30]
+    adc                  r5, -4 ; filter_strength-3
+    movd                 m3, [tlq+r3]
+    lea                 tlq, [rsp+16*4]
+    mova         [tlq-16*1], m0
+    pxor                 m7, m7
+    mova         [tlq+16*0], m1
+    pshufb               m4, m7
+    movd              [rsp], m2
+    pshufb               m3, m7
+    mova         [tlq-16*2], m4
+    movd        [tlq+r3-16], m3
+    call .filter_edge
+    cmp                  hd, 16
+    jle .w16_main
+    pshuflw              m0, [rsp], q0000
+    sar                  r5, 1
+    movd                 m1, [base+z_filter_k_tail+4+r5*4]
+    lea                 r3d, [r5+33]
+    pmaddubsw            m0, m1
+%if ARCH_X86_64
+    pmulhrsw             m0, m10
+%else
+    pmulhrsw             m0, m4
+%endif
+    packuswb             m0, m0
+    movd           [tlq+32], m0
+.w16_main:
+    add                 tlq, r3
+    movd                 m5, dxd
+    movd                 m7, [tlq]
+    movd                 m4, r3d
+    shl                 r3d, 6
+    pshufb               m5, [base+pw_256]
+    pxor                 m6, m6
+    pshufb               m7, m6
+    mov                 r5d, dxd
+    pshufb               m4, m6
+    sub                  r5, r3
+    psubb                m4, [base+pb_0to15]
+    mova                 m6, m5
+.w16_loop:
+    mov                  r3, r5
+    sar                  r3, 6
+    movu                 m1, [tlq+r3+0]
+    pand                 m0, m8, m5
+    movu                 m2, [tlq+r3+1]
+    psubw                m3, m9, m0
+    psllw                m0, 8
+    por                  m3, m0
+    punpcklbw            m0, m1, m2
+    pmaddubsw            m0, m3
+    punpckhbw            m1, m2
+    pmaddubsw            m1, m3
+    psrlw                m3, m5, 6
+    packsswb             m3, m3
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    paddw                m5, m6
+    pcmpgtb              m2, m4, m3
+    packuswb             m0, m1
+    pand                 m0, m2
+    pandn                m2, m7
+    por                  m0, m2
+    mova             [dstq], m0
+    dec                  hd
+    jz .w16_end
+    movifnidn       strideq, stridemp
+    add                dstq, strideq
+    add                  r5, dxq
+    jl .w16_loop
+.w16_end_loop:
+    mova             [dstq], m7
+    add                dstq, strideq
+    dec                  hd
+    jg .w16_end_loop
+.w16_end:
+    RET
+.w32:
+    lea                 r3d, [hq+31]
+    and                 r3d, 31
+    or                  r3d, 32    ; imin(h+31, 63)
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w32_main
+    movd                 m6, [tlq-1]
+    movu                 m0, [tlq+16*0]
+    movu                 m1, [tlq+16*1]
+    movu                 m2, [tlq+16*2]
+    movu                 m3, [tlq+16*3]
+    movd                 m4, [tlq+62]
+    movd                 m5, [tlq+r3]
+    lea                 tlq, [rsp+16*6]
+    mova         [tlq-16*3], m0
+    pxor                 m7, m7
+    mova         [tlq-16*2], m1
+    pshufb               m6, m7
+    mova         [tlq-16*1], m2
+    xor                 r5d, r5d ; filter_strength = 3
+    mova         [tlq+16*0], m3
+    movd              [rsp], m4
+    pshufb               m5, m7
+    mova         [tlq-16*4], m6
+    movd        [tlq+r3-48], m5
+    call .filter_edge
+    sub                 tlq, 16*2
+    call .filter_edge
+    cmp                  hd, 32
+    jle .w32_main
+    pshuflw              m0, [rsp], q0000
+    movd                 m1, [base+z_filter_k_tail+4]
+    add                 r3d, 2
+    pmaddubsw            m0, m1
+%if ARCH_X86_64
+    pmulhrsw             m0, m10
+%else
+    pmulhrsw             m0, m4
+%endif
+    packuswb             m0, m0
+    movd           [tlq+64], m0
+.w32_main:
+    add                 tlq, r3
+    movd                 m0, r3d
+    movd                 m7, [tlq]
+    shl                 r3d, 6
+    movd                 m5, dxd
+    pxor                 m6, m6
+    mov                 r5d, dxd
+    pshufb               m0, m6
+    pshufb               m5, [base+pw_256]
+    sub                  r5, r3
+    pshufb               m7, m6
+    psubb                m0, [base+pb_0to15]
+    movddup              m1, [base+pb_m16]
+    mova         [rsp+16*0], m0
+    paddb                m0, m1
+    mova         [rsp+16*1], m0
+    mova                 m6, m5
+.w32_loop:
+    mov                  r3, r5
+    sar                  r3, 6
+    movu                 m1, [tlq+r3+16*0+0]
+    pand                 m0, m8, m5
+    movu                 m2, [tlq+r3+16*0+1]
+    psubw                m3, m9, m0
+    psllw                m0, 8
+    por                  m3, m0
+    punpcklbw            m0, m1, m2
+    pmaddubsw            m0, m3
+    punpckhbw            m1, m2
+    pmaddubsw            m1, m3
+    psrlw                m4, m5, 6
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packsswb             m4, m4
+    pcmpgtb              m2, [rsp+16*0], m4
+    packuswb             m0, m1
+    pand                 m0, m2
+    pandn                m2, m7
+    por                  m0, m2
+    movu                 m1, [tlq+r3+16*1+0]
+    movu                 m2, [tlq+r3+16*1+1]
+    mova        [dstq+16*0], m0
+    punpcklbw            m0, m1, m2
+    pmaddubsw            m0, m3
+    punpckhbw            m1, m2
+    pmaddubsw            m1, m3
+    paddw                m5, m6
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    pcmpgtb              m2, [rsp+16*1], m4
+    packuswb             m0, m1
+    pand                 m0, m2
+    pandn                m2, m7
+    por                  m0, m2
+    mova        [dstq+16*1], m0
+    dec                  hd
+    jz .w32_end
+    movifnidn       strideq, stridemp
+    add                dstq, strideq
+    add                  r5, dxq
+    jl .w32_loop
+.w32_end_loop:
+    mova        [dstq+16*0], m7
+    mova        [dstq+16*1], m7
+    add                dstq, strideq
+    dec                  hd
+    jg .w32_end_loop
+.w32_end:
+    RET
+.w64:
+    lea                 r3d, [hq+63]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .w64_main
+    movd                 m4, [tlq-1]
+    movu                 m0, [tlq+16*0]
+    movu                 m1, [tlq+16*1]
+    movu                 m2, [tlq+16*2]
+    movu                 m3, [tlq+16*3]
+    mova         [rsp+16*3], m0
+    pxor                 m7, m7
+    mova         [rsp+16*4], m1
+    pshufb               m4, m7
+    mova         [rsp+16*5], m2
+    mova         [rsp+16*6], m3
+    mova         [rsp+16*2], m4
+    movu                 m0, [tlq+16*4]
+    movu                 m1, [tlq+16*5]
+    movu                 m2, [tlq+16*6]
+    movu                 m3, [tlq+16*7]
+    movd                 m4, [tlq+r3]
+    lea                 tlq, [rsp+16*10]
+    mova         [tlq-16*3], m0
+    xor                 r5d, r5d ; filter_strength = 3
+    mova         [tlq-16*2], m1
+    pshufb               m4, m7
+    mova         [tlq-16*1], m2
+    mova         [tlq+16*0], m3
+    movd      [tlq+r3-16*7], m4
+    cmp                  hd, 64
+    jl .w64_filter96 ; skip one call if the last 32 bytes aren't used
+    call .filter_edge
+.w64_filter96:
+    sub                 tlq, 16*2
+    call .filter_edge
+    sub                 tlq, 16*2
+    call .filter_edge
+    sub                 tlq, 16*2
+    call .filter_edge
+.w64_main:
+    add                 tlq, r3
+    movd                 m0, r3d
+    movd                 m7, [tlq]
+    shl                 r3d, 6
+    movd                 m5, dxd
+    pxor                 m6, m6
+    mov                 r5d, dxd
+    pshufb               m0, m6
+    sub                  r5, r3
+    pshufb               m5, [base+pw_256]
+    pshufb               m7, m6
+    psubb                m0, [base+pb_0to15]
+    movddup              m1, [base+pb_m16]
+    mova         [rsp+16*0], m0
+    paddb                m0, m1
+    mova         [rsp+16*1], m0
+    paddb                m0, m1
+    mova         [rsp+16*2], m0
+    paddb                m0, m1
+    mova         [rsp+16*3], m0
+    mova                 m6, m5
+.w64_loop:
+    mov                  r3, r5
+    sar                  r3, 6
+    movu                 m1, [tlq+r3+16*0+0]
+    pand                 m0, m8, m5
+    movu                 m2, [tlq+r3+16*0+1]
+    psubw                m3, m9, m0
+    psllw                m0, 8
+    por                  m3, m0
+    punpcklbw            m0, m1, m2
+    pmaddubsw            m0, m3
+    punpckhbw            m1, m2
+    pmaddubsw            m1, m3
+    psrlw                m4, m5, 6
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packsswb             m4, m4
+    pcmpgtb              m2, [rsp+16*0], m4
+    packuswb             m0, m1
+    pand                 m0, m2
+    pandn                m2, m7
+    por                  m0, m2
+    movu                 m1, [tlq+r3+16*1+0]
+    movu                 m2, [tlq+r3+16*1+1]
+    mova        [dstq+16*0], m0
+    punpcklbw            m0, m1, m2
+    pmaddubsw            m0, m3
+    punpckhbw            m1, m2
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    pcmpgtb              m2, [rsp+16*1], m4
+    packuswb             m0, m1
+    pand                 m0, m2
+    pandn                m2, m7
+    por                  m0, m2
+    movu                 m1, [tlq+r3+16*2+0]
+    movu                 m2, [tlq+r3+16*2+1]
+    mova        [dstq+16*1], m0
+    punpcklbw            m0, m1, m2
+    pmaddubsw            m0, m3
+    punpckhbw            m1, m2
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    pcmpgtb              m2, [rsp+16*2], m4
+    packuswb             m0, m1
+    pand                 m0, m2
+    pandn                m2, m7
+    por                  m0, m2
+    movu                 m1, [tlq+r3+16*3+0]
+    movu                 m2, [tlq+r3+16*3+1]
+    mova        [dstq+16*2], m0
+    punpcklbw            m0, m1, m2
+    pmaddubsw            m0, m3
+    punpckhbw            m1, m2
+    pmaddubsw            m1, m3
+    paddw                m5, m6
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    pcmpgtb              m2, [rsp+16*3], m4
+    packuswb             m0, m1
+    pand                 m0, m2
+    pandn                m2, m7
+    por                  m0, m2
+    mova        [dstq+16*3], m0
+    dec                  hd
+    jz .w64_end
+    movifnidn       strideq, stridemp
+    add                dstq, strideq
+    add                  r5, dxq
+    jl .w64_loop
+.w64_end_loop:
+    mova        [dstq+16*0], m7
+    mova        [dstq+16*1], m7
+    mova        [dstq+16*2], m7
+    mova        [dstq+16*3], m7
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_end_loop
+.w64_end:
+    RET
+ALIGN function_align
+.filter_edge: ; 32 pixels/iteration
+    movddup              m7, [base+z_filter_k+8*2+r5*8+24*0]
+    movu                 m2, [tlq-18]
+    movu                 m1, [tlq-17]
+    movu                 m3, [tlq- 2]
+    movu                 m4, [tlq- 1]
+    punpcklbw            m0, m2, m1
+    pmaddubsw            m0, m7
+    punpckhbw            m2, m1
+    pmaddubsw            m2, m7
+    punpcklbw            m1, m3, m4
+    pmaddubsw            m1, m7
+    punpckhbw            m3, m4
+    pmaddubsw            m3, m7
+    movddup              m7, [base+z_filter_k+8*2+r5*8+24*1]
+    mova                 m5, [tlq-16]
+    movu                 m6, [tlq-15]
+    punpcklbw            m4, m5, m6
+    pmaddubsw            m4, m7
+    punpckhbw            m5, m6
+    pmaddubsw            m5, m7
+    paddw                m0, m4
+    paddw                m2, m5
+    mova                 m5, [tlq+ 0]
+    movu                 m6, [tlq+ 1]
+    punpcklbw            m4, m5, m6
+    pmaddubsw            m4, m7
+    punpckhbw            m5, m6
+    pmaddubsw            m5, m7
+    paddw                m1, m4
+    paddw                m3, m5
+    test                r5d, r5d
+    jnz .filter_end ; 3-tap
+    movddup              m7, [base+z_filter_k+8*8]
+    movu                 m5, [tlq-14]
+    movu                 m6, [tlq+ 2]
+    punpcklbw            m4, m5, m5
+    pmaddubsw            m4, m7
+    punpckhbw            m5, m5
+    pmaddubsw            m5, m7
+    paddw                m0, m4
+    paddw                m2, m5
+    punpcklbw            m5, m6, m6
+    pmaddubsw            m5, m7
+    punpckhbw            m6, m6
+    pmaddubsw            m6, m7
+    paddw                m1, m5
+    paddw                m3, m6
+.filter_end:
+%if ARCH_X86_64
+    REPX  {pmulhrsw x, m10}, m0, m2, m1, m3
+%else
+    mova                 m4, m10
+    REPX  {pmulhrsw x, m4 }, m0, m2, m1, m3
+%endif
+    packuswb             m0, m2
+    packuswb             m1, m3
+    mova         [tlq+16*0], m0
+    mova         [tlq+16*1], m1
+    ret
+
+%if ARCH_X86_64
+cglobal ipred_z2_8bpc, 4, 12, 13, 16*16, dst, stride, tl, w, h, angle, dx, _, dy
+    %define            base  r7-$$
+    %define           maxwm  r6m
+    %define           maxhm  r7m
+    lea                  r7, [$$]
+    mov                  hd, hm
+    mova                 m8, [base+pw_62]
+    mova                 m9, [base+pw_64]
+    lea                 r9d, [wq-4]
+    mova                m10, [base+pw_512]
+    shl                 r9d, 6
+    mova                m11, [base+z1_shuf_w4]
+    or                  r9d, hd
+    mova                m12, [base+z2_h_shuf]
+%else
+cglobal ipred_z2_8bpc, 4, 7, 8, -16*20, dst, _, tl, w, h, angle, dx
+    %define            base  r1-$$
+    %define              m8  [base+pw_62]
+    %define              m9  [base+pw_64]
+    %define             m10  [base+pw_512]
+    %define             m11  [rsp+16*16]
+    %define             m12  [rsp+16*17]
+    %define             r9b  byte [rsp+16*18+4*0]
+    %define             r9d  dword [rsp+16*18+4*0]
+    %define            r10d  dword [rsp+16*18+4*1]
+    %define            r11d  dword [rsp+16*18+4*2]
+    %define           maxwm  [rsp+16*18+4*3]
+    %define           maxhm  [rsp+16*19+4*0]
+    %define        stridemp  [rsp+16*19+4*1]
+    %define         strideq  r3
+    %define             dyd  r4
+    %define             dyq  r4
+    mov            stridemp, r1
+    mov                 r1d, r6m
+    mov                 r4d, r7m
+    mov               maxwm, r1d
+    mov               maxhm, r4d
+    LEA                  r1, $$
+    lea                  hd, [wq-4]
+    mova                 m0, [base+z1_shuf_w4]
+    shl                  hd, 6
+    mova                 m1, [base+z2_h_shuf]
+    or                   hd, hm
+    mova                m11, m0
+    mov                 r9d, hd
+    mova                m12, m1
+%endif
+    tzcnt                wd, wd
+    movifnidn        angled, anglem
+    movsxd               wq, [base+ipred_z2_ssse3_table+wq*4]
+%if ARCH_X86_64
+    movzx               dxd, angleb
+%else
+    movzx               dxd, byte anglem
+%endif
+    xor              angled, 0x400
+    mova                 m0, [tlq-16*4]
+    mov                 dyd, dxd
+    mova                 m1, [tlq-16*3]
+    neg                 dxq
+    mova                 m2, [tlq-16*2]
+    and                 dyd, ~1
+    mova                 m3, [tlq-16*1]
+    and                 dxq, ~1
+    movd                 m4, [tlq]
+    movu                 m5, [tlq+16*0+1]
+    movu                 m6, [tlq+16*1+1]
+    movzx               dyd, word [base+dr_intra_derivative+dyq-90]  ; angle - 90
+    movzx               dxd, word [base+dr_intra_derivative+dxq+180] ; 180 - angle
+    mova         [rsp+16*2], m0
+    pxor                 m7, m7
+    mova         [rsp+16*3], m1
+    pshufb               m4, m7
+    mova         [rsp+16*4], m2
+    lea                  wq, [base+ipred_z2_ssse3_table+wq]
+    mova         [rsp+16*5], m3
+    neg                 dxd
+    mova         [rsp+16*6], m4
+    or                  dyd, 4<<16
+    mova         [rsp+16*7], m4
+    mova         [rsp+16*8], m5
+    mova         [rsp+16*9], m6
+    movq                 m0, [base+z_base_inc+2]
+    movsldup             m1, [base+z2_dy_offset]
+    movq                 m2, [base+pw_256] ; 4<<6
+    movq    [rsp+16*14+8*0], m0
+    movq    [rsp+16*15+8*0], m1
+    movq    [rsp+16*15+8*1], m2
+%if ARCH_X86_64
+    lea                r10d, [dxq+(128<<6)] ; xpos
+%else
+    mov      [rsp+16*7+4*1], dyd
+    lea                 r4d, [dxq+(128<<6)]
+    mov                r10d, r4d
+    movzx                hd, r9b
+%endif
+    mov                r11d, (128-4)<<6
+    jmp                  wq
+.w4:
+    test             angled, 0x400
+    jnz .w4_main
+    movd                 m5, [tlq+4]
+    lea                 r3d, [hq+2]
+    add              angled, 1022
+    pshufb               m5, m7
+    shl                 r3d, 6
+    movd       [rsp+16*8+4], m5
+    test                r3d, angled
+    jnz .w4_no_upsample_above ; angle >= 130 || h > 8 || (is_sm && h == 8)
+    call .upsample_above
+    sub              angled, 1075 ; angle - 53
+    lea                 r3d, [hq+3]
+    xor              angled, 0x7f ; 180 - angle
+    movd                 m0, r3d
+    movd                 m6, angled
+    shr              angled, 8 ; is_sm << 1
+    pshufb               m0, m7
+    pshufb               m6, m7
+    pcmpeqb              m0, [base+z_filter_wh4]
+    pand                 m6, m0
+    pcmpgtb              m6, [base+z_filter_t_w48+angleq*8]
+    jmp .w8_filter_left
+.upsample_above: ; w4/w8
+    movq                 m3, [rsp+gprsize+16*8-2]
+    movq                 m1, [rsp+gprsize+16*8-1]
+    movq                 m0, [rsp+gprsize+16*8+0]
+    movq                 m4, [rsp+gprsize+16*8+1]
+    movddup              m5, [base+pb_36_m4]
+    punpcklbw            m1, m3
+    punpcklbw            m2, m0, m4
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+%if ARCH_X86_64
+    mova                m11, [base+pb_0to15]
+    lea                r10d, [r10+dxq+(1<<6)]
+    mov                r11d, (128-7)<<6
+%else
+    mova                 m3, [base+pb_0to15]
+    mov                 r3d, [rsp+gprsize+16*18+4*1]
+    mov dword [rsp+gprsize+16*18+4*2], (128-7)<<6
+    lea                 r3d, [r3+dxq+(1<<6)]
+    mov [rsp+gprsize+16*18+4*1], r3d
+    mova [rsp+gprsize+16*16], m3
+%endif
+    add                 dxd, dxd
+    paddw                m1, m2
+    pmulhrsw             m1, m10
+    movq                 m2, [rsp+gprsize+16*14]
+    paddw                m2, m2
+    movq [rsp+gprsize+16*14], m2
+    packuswb             m1, m1
+    punpcklbw            m1, m0
+    mova [rsp+gprsize+16*8], m1
+    ret
+.w4_no_upsample_above:
+    lea                 r3d, [hq+3]
+    mov               [rsp], angled
+    sub              angled, 1112 ; angle - 90
+    movd                 m0, r3d
+    mov                 r3d, 90
+    movd                 m1, angled
+    sub                 r3d, angled ; 180 - angle
+    shr              angled, 8 ; is_sm << 1
+    movu                 m3, [base+z_filter_wh4]
+    mova                 m4, [base+z_filter_t_w48+angleq*8]
+    call .w8_filter_top
+    mov              angled, [rsp]
+    lea                 r3d, [hq+2]
+    sub              angled, 139
+    shl                 r3d, 6
+    test                r3d, angled
+    jnz .w8_filter_left ; angle <= 140 || h > 8 || (is_sm && h == 8)
+.upsample_left: ; w4/w8
+    neg                  hq
+    movd                 m0, [tlq+hq]
+    pshufb               m0, m7
+    movd    [rsp+16*6+hq-4], m0
+    movq                 m3, [rsp+16*5+7]
+    movq                 m0, [rsp+16*5+8]
+    movq                 m2, [rsp+16*5+9]
+    movq                 m4, [rsp+16*5+10]
+    movddup              m5, [base+pb_36_m4]
+    punpcklbw            m1, m0, m3
+    punpcklbw            m2, m4
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    movshdup             m3, [base+z2_dy_offset]
+%if ARCH_X86_64
+    mova                m12, [base+z2_upsample]
+    add                 dyd, dyd
+%else
+    mova                 m4, [base+z2_upsample]
+    shl dword [rsp+16*7+4*1], 1
+    mova                m12, m4
+%endif
+    paddw                m1, m2
+    pmulhrsw             m1, m10
+    movq        [rsp+16*15], m3
+    packuswb             m1, m1
+    punpcklbw            m0, m1
+    mova         [rsp+16*5], m0
+.w4_main:
+    movd                 m6, dxd
+%if ARCH_X86_64
+    movd                 m3, dyd
+%else
+    movd                 m3, [rsp+16*7+4*1]
+%endif
+    movddup              m0, [rsp+16*14+8*0]
+    pshufb               m6, [base+pw_256]
+    paddw                m7, m6, m6
+    movq                 m5, [base+pw_m1to4]
+    pshuflw              m4, m3, q0000
+    punpcklqdq           m6, m7
+    pmullw               m4, m5
+    pshuflw              m3, m3, q1111
+    paddw                m6, m0
+    mov                 r2d, r10d
+    pshuflw              m0, m4, q3333
+    psubw                m4, [rsp+16*15]
+    movq     [rsp+16*6+8*1], m3
+    movq          [rsp+8*1], m0 ; dy*4
+    mov                  r5, dstq
+.w4_loop0:
+    mova        [rsp+16*12], m6
+    movq          [rsp+8*0], m4
+    pand                 m0, m4, m8
+    psraw                m4, 6
+    psubw                m1, m9, m0
+    psllw                m0, 8
+    por                  m0, m1       ; 64-frac_y, frac_y
+    movq          [rsp+8*3], m0
+    pabsw                m4, m4
+    movq          [rsp+8*2], m4
+    movzx                hd, r9b
+.w4_loop:
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6        ; base_x0
+    movq                 m0, [rsp+r2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6        ; base_x1
+    movhps               m0, [rsp+r3]
+    lea                 r3d, [r2+dxq]
+    shr                 r2d, 6        ; base_x2
+    movq                 m1, [rsp+r2]
+    lea                 r2d, [r3+dxq]
+    shr                 r3d, 6        ; base_x3
+    movhps               m1, [rsp+r3]
+    pand                 m2, m8, m6
+    paddsw               m5, m6, m7
+    psubw                m3, m9, m2
+    psllw                m2, 8
+    pshufb               m0, m11
+    por                  m2, m3
+    pmaddubsw            m0, m2
+    pand                 m2, m8, m5
+    psubw                m3, m9, m2
+    psllw                m2, 8
+    pshufb               m1, m11
+    por                  m2, m3
+    pmaddubsw            m1, m2
+    cmp                 r3d, 127 ; topleft
+    jge .w4_toponly
+    movzx               r3d, byte [rsp+8*2+0] ; base_y0
+    movq                 m3, [rsp+r3]
+    movzx               r3d, byte [rsp+8*2+2] ; base_y1
+    movhps               m3, [rsp+r3]
+    movzx               r3d, byte [rsp+8*2+4] ; base_y2
+    movq                 m4, [rsp+r3]
+    movzx               r3d, byte [rsp+8*2+6] ; base_y3
+    movhps               m4, [rsp+r3]
+    pshufb               m3, m12
+    pshufb               m4, m12
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    movddup              m4, [rsp+8*3]
+    pmaddubsw            m2, m4
+    pmaddubsw            m3, m4
+    psraw                m6, 15       ; base_x < topleft
+    pand                 m2, m6
+    pandn                m6, m0
+    por                  m0, m2, m6
+    psraw                m6, m5, 15
+    pand                 m3, m6
+    pandn                m6, m1
+    por                  m1, m3, m6
+.w4_toponly:
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    movifnidn       strideq, stridemp
+    packuswb             m0, m1
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    punpckhqdq           m0, m0
+    movd   [dstq+strideq*0], m0
+    psrlq                m0, 32
+    movd   [dstq+strideq*1], m0
+    sub                  hd, 4
+    jz .w4_end
+    movq                 m4, [rsp+8*2]
+    movq                 m3, [rsp+16*6+8*1]
+    paddw                m6, m5, m7   ; xpos += dx
+    psubw                m4, m3
+    movq          [rsp+8*2], m4
+    lea                dstq, [dstq+strideq*2]
+    cmp                 r2d, r11d
+    jge .w4_loop
+    movddup              m5, [rsp+8*3]
+.w4_leftonly_loop:
+    movzx               r2d, byte [rsp+8*2+0] ; base_y0
+    movq                 m1, [rsp+r2]
+    movzx               r2d, byte [rsp+8*2+2] ; base_y1
+    movhps               m1, [rsp+r2]
+    movzx               r2d, byte [rsp+8*2+4] ; base_y2
+    movq                 m2, [rsp+r2]
+    movzx               r2d, byte [rsp+8*2+6] ; base_y3
+    movhps               m2, [rsp+r2]
+    psubw                m4, m3
+    pshufb               m1, m12
+    pshufb               m2, m12
+    movq          [rsp+8*2], m4
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packuswb             m0, m1
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    punpckhqdq           m0, m0
+    movd   [dstq+strideq*0], m0
+    psrlq                m0, 32
+    movd   [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 4
+    jg .w4_leftonly_loop
+.w4_end:
+    sub                 r9d, 1<<8
+    jl .w4_ret
+    movq                 m4, [rsp+8*1]
+    add                  r5, 4
+    mov                dstq, r5
+    paddw                m4, [rsp+8*0] ; base_y += 4*dy
+    movzx               r2d, word [rsp+16*15+8*1]
+    movddup              m6, [rsp+16*15+8*1]
+    paddw                m6, [rsp+16*12] ; base_x += (4 << upsample_above)
+    add                 r2d, r10d
+    mov                r10d, r2d
+    jmp .w4_loop0
+.w4_ret:
+    RET
+.w8:
+    test             angled, 0x400
+    jnz .w4_main
+    movd                 m5, [tlq+8]
+    lea                 r3d, [angleq+126]
+    pshufb               m5, m7
+%if ARCH_X86_64
+    mov                 r3b, hb
+%else
+    xor                 r3b, r3b
+    or                  r3d, hd
+%endif
+    movd       [rsp+16*8+8], m5
+    cmp                 r3d, 8
+    ja .w8_no_upsample_above ; angle >= 130 || h > 8 || is_sm
+    call .upsample_above
+    sub              angled, 53
+    lea                 r3d, [hq+7]
+    xor              angled, 0x7f ; 180 - angle
+    movu                 m1, [base+z_filter_wh8]
+    movd                 m0, r3d
+    movd                 m6, angled
+    shr              angled, 8 ; is_sm << 1
+    psrldq               m2, [base+z_filter_t_w48+angleq*8], 4
+    pshufb               m0, m7
+    pshufb               m6, m7
+    pcmpeqb              m0, m1
+    pand                 m6, m0
+    pcmpgtb              m6, m2
+%if ARCH_X86_64
+    movq    [rsp+16*15+8*1], m10 ; 8<<6
+%else
+    movq                 m0, m10
+    movq    [rsp+16*15+8*1], m0
+%endif
+    jmp .w8_filter_left
+.w8_no_upsample_above:
+    lea                 r3d, [hq+7]
+    mov               [rsp], angled
+    sub              angled, 90
+    movd                 m0, r3d
+    mov                 r3d, 90
+    movd                 m1, angled
+    sub                 r3d, angled ; 180 - angle
+    shr              angled, 8 ; is_sm << 1
+    movu                 m3, [base+z_filter_wh8]
+    psrldq               m4, [base+z_filter_t_w48+angleq*8], 4
+    call .w8_filter_top
+    mov                 r3d, [rsp]
+    sub                 r3d, 141
+%if ARCH_X86_64
+    mov                 r3b, hb
+%else
+    xor                 r3b, r3b
+    or                  r3d, hd
+%endif
+    cmp                 r3d, 8
+    jbe .upsample_left ; angle > 140 && h <= 8 && !is_sm
+.w8_filter_left:
+    pmovmskb            r5d, m6
+    test                r5d, r5d
+    jz .w4_main
+    imul                r5d, 0x55555555
+    mov                  r3, tlq
+    shr                 r5d, 30
+    sub                  r5, 3 ; filter_strength-3
+    jmp .filter_left
+.w8_filter_top:
+    movd                 m6, r3d
+    REPX     {pshufb x, m7}, m0, m1, m6
+    pcmpeqb              m0, m3
+    pand                 m1, m0
+    pand                 m6, m0
+    pcmpgtb              m1, m4
+    pcmpgtb              m6, m4
+    pmovmskb            r5d, m1
+    test                r5d, r5d
+    jz .w8_filter_top_end ; filter_strength == 0
+    imul                r5d, 0x55555555
+    movq                 m0, [rsp+gprsize+16*8-2]
+    shr                 r5d, 30
+    movq                 m1, [rsp+gprsize+16*8-1]
+    sub                  r5, 3 ; filter_strength-3
+    movddup              m7, [base+z_filter_k+8*2+r5*8+24*0]
+    punpcklbw            m0, m1
+    pmaddubsw            m0, m7
+    movq                 m1, [rsp+gprsize+16*8+0]
+    movq                 m2, [rsp+gprsize+16*8+1]
+    movddup              m7, [base+z_filter_k+8*2+r5*8+24*1]
+    punpcklbw            m1, m2
+    pmaddubsw            m1, m7
+    movq                 m2, [rsp+gprsize+16*8+2]
+    movddup              m7, [base+z_filter_k+8*2+r5*8+24*2]
+    punpcklbw            m2, m2
+    pmaddubsw            m2, m7
+    paddw                m0, m1
+    paddw                m0, m2
+%if ARCH_X86_64
+    mov                 r3d, r7m ; maxw, offset due to call
+%else
+    mov                 r3d, [rsp+gprsize+16*18+4*3]
+%endif
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packuswb             m0, m1
+    movq [rsp+gprsize+16*8], m0
+    cmp                 r3d, 8
+    jge .w8_filter_top_end
+    movq                 m0, [tlq+r3+1]
+    movq [rsp+gprsize+r3+16*8], m0
+.w8_filter_top_end:
+    ret
+.w16:
+    test             angled, 0x400
+    jnz .w4_main
+    lea                 r3d, [hq+15]
+    sub              angled, 90
+    movd                 m0, r3d
+    mov                 r3d, 90
+    movd                 m1, angled
+    sub                 r3d, angled ; 180 - angle
+    shr              angled, 8 ; is_sm << 1
+    movd                 m6, r3d
+    REPX     {pshufb x, m7}, m0, m1, m6
+    movq                 m3, [base+z_filter_t_w16+angleq*4]
+    pcmpeqb              m0, [base+z_filter_wh16]
+    pand                 m1, m0
+    pand                 m6, m0
+    pcmpgtb              m1, m3
+    pcmpgtb              m6, m3
+    pmovmskb            r5d, m1
+    mov                  r3, tlq
+    test                r5d, r5d
+    jz .w16_filter_left ; filter_strength == 0
+    imul                r5d, 0x24924924
+    pshufb               m5, [base+z_filter_t_w16] ; tlq[16]
+    shr                 r5d, 30
+    adc                  r5, -4 ; filter_strength-3
+    movd         [rsp+16*9], m5
+    movddup              m7, [base+z_filter_k+8*2+r5*8+24*0]
+    movu                 m1, [rsp+16*8-2]
+    movu                 m2, [rsp+16*8-1]
+    punpcklbw            m0, m1, m2
+    pmaddubsw            m0, m7
+    punpckhbw            m1, m2
+    pmaddubsw            m1, m7
+    movddup              m7, [base+z_filter_k+8*2+r5*8+24*1]
+    mova                 m3, [rsp+16*8+0]
+    movu                 m4, [rsp+16*8+1]
+    punpcklbw            m2, m3, m4
+    pmaddubsw            m2, m7
+    punpckhbw            m3, m4
+    pmaddubsw            m3, m7
+    paddw                m0, m2
+    paddw                m1, m3
+    test                r5d, r5d
+    jnz .w16_filter_end ; 3-tap
+    movddup              m7, [base+z_filter_k+8*8]
+    movu                 m3, [rsp+16*8+2]
+    punpcklbw            m2, m3, m3
+    pmaddubsw            m2, m7
+    punpckhbw            m3, m3
+    pmaddubsw            m3, m7
+    paddw                m0, m2
+    paddw                m1, m3
+.w16_filter_end:
+    mov                 r2d, maxwm
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packuswb             m0, m1
+    mova         [rsp+16*8], m0
+    cmp                 r2d, 16
+    jge .w16_filter_left
+    movu                 m0, [r3+r2+1]
+    movu      [rsp+r2+16*8], m0
+.w16_filter_left:
+    pmovmskb            r5d, m6
+    test                r5d, r5d
+    jz .w4_main
+    imul                r5d, 0x24924924
+    shr                 r5d, 30
+    adc                  r5, -4 ; filter_strength-3
+    jmp .filter_left
+.w32:
+    test             angled, 0x400
+    jnz .w4_main
+    pshufb               m6, [base+z_filter_t_w16] ; tlq[32]
+    mov                  r3, tlq
+    lea                 tlq, [rsp+16*9]
+    movd         [tlq+16*1], m6
+    xor                 r5d, r5d ; filter_strength = 3
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    mova                 m0, [tlq+16*0]
+    mova                 m1, [tlq+16*1]
+    mov                 r2d, maxwm
+    mova         [rsp+16*8], m0
+    mova         [rsp+16*9], m1
+    cmp                 r2d, 32
+    jge .filter_left
+    movu                 m0, [r3+r2+16*0+1]
+    movu                 m1, [r3+r2+16*1+1]
+    movu      [rsp+r2+16*8], m0
+    movu      [rsp+r2+16*9], m1
+    jmp .filter_left
+.w64:
+    movu                 m0, [tlq+16*2+1]
+    movu                 m1, [tlq+16*3+1]
+    mova        [rsp+16*10], m0
+    mova        [rsp+16*11], m1
+    test             angled, 0x400
+    jnz .w4_main
+    pshufb               m1, [base+z_filter_t_w16] ; tlq[64]
+    mov                  r3, tlq
+    lea                 tlq, [rsp+16*11]
+    movd         [tlq+16*1], m1
+    xor                 r5d, r5d ; filter_strength = 3
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    sub                 tlq, 16*2
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    mova                 m0, [tlq+16*0]
+    mova                 m1, [tlq+16*1]
+    mova                 m2, [tlq+16*2]
+    mova                 m3, [tlq+16*3]
+    mov                 r2d, maxwm
+    mova        [rsp+16* 8], m0
+    mova        [rsp+16* 9], m1
+    mova        [rsp+16*10], m2
+    mova        [rsp+16*11], m3
+    cmp                 r2d, 64
+    jge .filter_left
+    movu                 m0, [r3+r2+16*0+1]
+    movu                 m1, [r3+r2+16*1+1]
+    movu     [rsp+r2+16* 8], m0
+    movu     [rsp+r2+16* 9], m1
+    cmp                 r2d, 32
+    jge .filter_left
+    movu                 m0, [r3+r2+16*2+1]
+    movu                 m1, [r3+r2+16*3+1]
+    movu     [rsp+r2+16*10], m0
+    movu     [rsp+r2+16*11], m1
+.filter_left:
+    neg                  hq
+    movd                 m0, [r3+hq]
+    pxor                 m1, m1
+    pshufb               m0, m1
+    movd    [rsp+16*6+hq-4], m0
+    lea                 tlq, [rsp+16*5]
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    cmp                  hd, -32
+    jge .filter_left_end
+    sub                 tlq, 16*2
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    mova                 m0, [tlq+16*0]
+    mova                 m1, [tlq+16*1]
+    mova         [rsp+16*2], m0
+    mova         [rsp+16*3], m1
+.filter_left_end:
+    mov                 r2d, maxhm
+    mova                 m0, [rsp+16*5]
+    mova                 m1, [rsp+16*6]
+    mova                 m2, [rsp+16*7]
+    neg                  r2
+    mova         [rsp+16*4], m0
+    mova         [rsp+16*5], m1
+    mova         [rsp+16*6], m2
+    cmp                 r2d, hd
+    jle .w4_main
+    movu                 m0, [r3+r2-16*2]
+    movu                 m1, [r3+r2-16*1]
+    movu      [rsp+r2+16*4], m0
+    movu      [rsp+r2+16*5], m1
+    cmp                 r2d, -32
+    jle .w4_main
+    movu                 m0, [r3+r2-16*4]
+    movu                 m1, [r3+r2-16*3]
+    movu      [rsp+r2+16*2], m0
+    movu      [rsp+r2+16*3], m1
+    jmp .w4_main
+
+%if ARCH_X86_64
+cglobal ipred_z3_8bpc, 4, 9, 11, 16*10, dst, stride, tl, w, h, angle, dy, _, org_w
+    %define            base  r7-$$
+    lea                  r7, [$$]
+    mova                 m8, [base+pw_62]
+    mova                 m9, [base+pw_64]
+    mova                m10, [base+pw_512]
+    mov              org_wd, wd
+%else
+cglobal ipred_z3_8bpc, 4, 7, 8, -16*10, dst, stride, tl, w, h, angle, dy
+    %define            base  r1-$$
+    %define              m8  [base+pw_62]
+    %define              m9  [base+pw_64]
+    %define             m10  [base+pw_512]
+    %define          org_wd  r5
+    %define          org_wq  r5
+    mov    [dstq+strideq*0], strideq
+    mov    [dstq+strideq*1], wd
+    LEA                  r1, $$
+%endif
+    tzcnt                hd, hm
+    movifnidn        angled, anglem
+    dec                 tlq
+    movsxd               hq, [base+ipred_z3_ssse3_table+hq*4]
+    sub              angled, 180
+    mov                 dyd, angled
+    neg                 dyd
+    xor              angled, 0x400
+    or                  dyq, ~0x7e
+    lea                  hq, [base+ipred_z3_ssse3_table+hq]
+    movzx               dyd, word [base+dr_intra_derivative+45*2-1+dyq]
+    jmp                  hq
+.h4:
+    lea                 r4d, [angleq+88]
+    test                r4d, 0x480
+    jnz .h4_no_upsample ; !enable_intra_edge_filter || angle >= 40
+    sar                 r4d, 9
+    add                 r4d, wd
+    cmp                 r4d, 8
+    jg .h4_no_upsample ; w > 8 || (w == 8 && is_sm)
+    movu                 m3, [tlq-7]
+    movu                 m1, [base+z_upsample1-4]
+    movu                 m4, [base+z_filter_s+2]
+    pshufb               m0, m3, m1
+    pxor                 m1, m1
+    pshufb               m2, m3, m1
+    pshufb               m1, m3, m4
+    mova           [rsp+16], m2 ; top[max_base_y]
+    movddup              m2, [base+pb_36_m4]
+    add                 dyd, dyd
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    movd                 m5, dyd
+    mov                 r5d, dyd
+    pshufb               m5, [base+pw_256]
+    paddw                m0, m1
+    pmulhrsw             m0, m10
+    shl                  wd, 2
+    mov                 tlq, rsp
+    sub                 rsp, wq
+    packuswb             m0, m0
+    punpcklbw            m0, m3
+    paddw                m6, m5, m5
+    punpcklqdq           m5, m6
+    pshufb               m0, [base+pb_15to0]
+    mova              [tlq], m0
+.h4_upsample_loop:
+    lea                 r4d, [r5+dyq]
+    shr                 r5d, 6
+    movq                 m0, [tlq+r5]
+    lea                 r5d, [r4+dyq]
+    shr                 r4d, 6
+    movhps               m0, [tlq+r4]
+    pand                 m2, m8, m5
+    psubw                m1, m9, m2
+    psllw                m2, 8
+    por                  m1, m2
+    pmaddubsw            m0, m1
+    paddw                m5, m6
+    pmulhrsw             m0, m10
+    packuswb             m0, m0
+    movq         [rsp+wq-8], m0
+    sub                  wd, 8
+    jg .h4_upsample_loop
+    jmp .h4_transpose
+.h4_no_upsample:
+    mov                 r4d, 7
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h4_main
+    lea                 r4d, [wq+3]
+    movd                 m0, r4d
+    movd                 m2, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m1, m1
+    pshufb               m0, m1
+    pshufb               m2, m1
+    pcmpeqb              m1, m0, [base+z_filter_wh4]
+    pand                 m1, m2
+    pcmpgtb              m1, [base+z_filter_t_w48+angleq*8]
+    pmovmskb            r5d, m1
+    mov                 r4d, 7
+    test                r5d, r5d
+    jz .h4_main ; filter_strength == 0
+    movu                 m2, [tlq-7]
+    imul                r5d, 0x55555555
+    movu                 m3, [base+z_filter_s-2]
+    shr                 r5d, 30 ; filter_strength
+    mova                 m4, [base+z_upsample2]
+    movddup              m5, [base+z_filter_k-8+r5*8+24*0]
+    movddup              m6, [base+z_filter_k-8+r5*8+24*1]
+    movddup              m7, [base+z_filter_k-8+r5*8+24*2]
+    pshufb               m0, m2, m3
+    shufps               m3, m4, q2121
+    pmaddubsw            m1, m0, m5
+    pmaddubsw            m0, m6
+    pshufb               m5, m2, m3
+    pmaddubsw            m3, m5, m6
+    pmaddubsw            m5, m7
+    pshufb               m2, m4
+    pmaddubsw            m2, m7
+    paddw                m0, m1
+    paddw                m1, m3
+    paddw                m0, m5
+    paddw                m1, m2
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    lea                 r2d, [r4+2]
+    cmp                  wd, 4
+    cmovne              r4d, r2d
+    pshufd               m0, m0, q0000
+    lea                 tlq, [rsp+15]
+    packuswb             m0, m1
+    mova              [rsp], m0
+.h4_main:
+    movd                 m5, dyd
+    movddup              m0, [base+z_base_inc] ; base_inc << 6
+    sub                 tlq, r4
+    shl                 r4d, 6
+    movd                 m7, [tlq]
+    movd                 m4, r4d
+    pshufb               m5, [base+pw_256]
+    neg                 dyq
+    pshufb               m7, [base+pw_m256]
+    mova                 m3, [base+z3_shuf_h4]
+    lea                  r5, [dyq+r4+63] ; ypos
+    pshufb               m4, [base+pw_256]
+    psubw                m4, m0 ; max_base_y
+    shl                  wd, 2
+    paddw                m6, m5, m5
+    sub                 rsp, wq
+    punpcklqdq           m5, m6
+.h4_loop:
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6
+    movq                 m0, [tlq+r5-4]
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6
+    movhps               m0, [tlq+r4-4]
+    pand                 m2, m8, m5
+    psubw                m1, m9, m2
+    psllw                m2, 8
+    pshufb               m0, m3
+    por                  m1, m2
+    pmaddubsw            m0, m1
+    pcmpgtw              m1, m4, m5
+    paddw                m5, m6
+    pmulhrsw             m0, m10
+    pand                 m0, m1
+    pandn                m1, m7
+    por                  m0, m1
+    packuswb             m0, m0
+    movq         [rsp+wq-8], m0
+    sub                  wd, 8
+    jz .h4_transpose
+    test                r5d, r5d
+    jg .h4_loop
+    packuswb             m7, m7
+.h4_end_loop:
+    movq         [rsp+wq-8], m7
+    sub                  wd, 8
+    jg .h4_end_loop
+.h4_transpose:
+    mova                 m1, [base+z_transpose4]
+%if ARCH_X86_32
+    mov             strideq, [dstq]
+    mov              org_wd, [dstq+strideq]
+%endif
+    lea                  r2, [strideq*3]
+    lea                dstq, [dstq+org_wq-4]
+.h4_transpose_loop:
+    mova                 m0, [rsp]
+    add                 rsp, 16
+    pshufb               m0, m1
+    movd   [dstq+strideq*0], m0
+    pshuflw              m2, m0, q1032
+    movd   [dstq+strideq*1], m2
+    punpckhqdq           m0, m0
+    movd   [dstq+strideq*2], m0
+    psrlq                m0, 32
+    movd   [dstq+r2       ], m0
+    sub                dstq, 4
+    sub              org_wd, 4
+    jg .h4_transpose_loop
+    RET
+.h8:
+    lea                 r4d, [angleq+88]
+    and                 r4d, ~0x7f
+    or                  r4d, wd
+    cmp                 r4d, 8
+    ja .h8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || w > 8
+    mova                 m4, [tlq-15]
+    and                 r4d, 4
+    movu                 m3, [tlq- 9]
+    movd                 m1, r4d
+    movu                 m2, [base+z_filter_s+2]
+    pxor                 m0, m0
+    movu                 m5, [base+z_filter_s+6]
+    movddup              m7, [base+pb_36_m4]
+    pshufb               m1, m0 ; w & 4
+    movu                 m0, [base+z_upsample1-4]
+    pmaxub               m1, m0 ; clip 4x8
+    add                 dyd, dyd
+    pshufb               m0, m4, m1
+    pmaddubsw            m0, m7
+    pshufb               m1, m4, m2
+    pmaddubsw            m1, m7
+    pshufb               m2, m3, [base+z_upsample1]
+    pmaddubsw            m2, m7
+    pshufb               m3, m5
+    pmaddubsw            m3, m7
+    movd                 m5, dyd
+    neg                 dyq
+    paddw                m1, m0
+    paddw                m2, m3
+    pmulhrsw             m1, m10
+    pmulhrsw             m2, m10
+    shl                  wd, 3
+    lea                 tlq, [rsp+16]
+    pshufb               m5, [base+pw_256]
+    sub                 rsp, wq
+    packuswb             m1, m2
+    lea                  r5, [dyq+63]
+    punpcklbw            m0, m1, m4
+    punpckhbw            m1, m4
+    mova         [tlq-16*1], m0
+    mova         [tlq-16*0], m1
+    paddw                m6, m5, m5
+    punpcklqdq           m5, m6
+.h8_upsample_loop:
+    lea                  r4, [r5+dyq]
+    sar                  r5, 6
+    movu                 m0, [tlq+r5]
+    lea                  r5, [r4+dyq]
+    sar                  r4, 6
+    movu                 m1, [tlq+r4]
+    pand                 m3, m8, m5
+    psubw                m2, m9, m3
+    psllw                m2, 8
+    por                  m3, m2
+    pshufd               m2, m3, q1010
+    pmaddubsw            m0, m2
+    punpckhqdq           m3, m3
+    pmaddubsw            m1, m3
+    paddw                m5, m6
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packuswb             m1, m0
+    mova        [rsp+wq-16], m1
+    sub                  wd, 16
+    jg .h8_upsample_loop
+    jmp .h8_transpose
+.h8_no_upsample:
+    lea                 r4d, [wq+7]
+    movd                 m0, r4d
+    and                 r4d, 7
+    or                  r4d, 8 ; imin(w+7, 15)
+    test             angled, 0x400
+    jnz .h8_main
+    movd                 m2, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m1, m1
+    pshufb               m0, m1
+    pshufb               m2, m1
+    movu                 m1, [base+z_filter_wh8]
+    psrldq               m3, [base+z_filter_t_w48+angleq*8], 4
+    pcmpeqb              m1, m0
+    pand                 m1, m2
+    pcmpgtb              m1, m3
+    pmovmskb            r5d, m1
+    test                r5d, r5d
+    jz .h8_main ; filter_strength == 0
+    mova                 m0, [tlq-15]
+    imul                r5d, 0x55555555
+    movd                 m1, [tlq+1]
+    neg                  r4
+    movd                 m2, [tlq+r4]
+    shr                 r5d, 30
+    pxor                 m7, m7
+    lea                 tlq, [rsp+16*2]
+    sub                  r5, 3 ; filter_strength-3
+    mova         [tlq+16*0], m0
+    pshufb               m1, m7
+    mova         [tlq+16*1], m1
+    pshufb               m2, m7
+    movq         [tlq+r4+8], m2
+    neg                 r4d
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    sar                 r5d, 1
+    add                 tlq, 31
+    add                 r5d, 17
+    cmp                  wd, 8
+    cmova               r4d, r5d
+.h8_main:
+    movd                 m5, dyd
+    sub                 tlq, r4
+    shl                 r4d, 6
+    movd                 m7, [tlq]
+    movd                 m4, r4d
+    pshufb               m5, [base+pw_256]
+    neg                 dyq
+    pshufb               m7, [base+pw_m256]
+    mova                 m3, [base+z3_shuf]
+    lea                  r5, [dyq+r4+63]
+    pshufb               m4, [base+pw_256]
+    psubw                m4, [base+z3_base_inc]
+    shl                  wd, 3
+    mova                 m6, m5
+    sub                 rsp, wq
+.h8_loop:
+    mov                  r4, r5
+    sar                  r4, 6
+    movu                 m0, [tlq+r4-8]
+    pand                 m2, m8, m5
+    psubw                m1, m9, m2
+    psllw                m2, 8
+    pshufb               m0, m3
+    por                  m1, m2
+    pmaddubsw            m0, m1
+    pcmpgtw              m1, m4, m5
+    paddw                m5, m6
+    pmulhrsw             m0, m10
+    pand                 m0, m1
+    pandn                m1, m7
+    por                  m0, m1
+    packuswb             m0, m0
+    movq         [rsp+wq-8], m0
+    sub                  wd, 8
+    jz .h8_transpose
+    add                  r5, dyq
+    jg .h8_loop
+    packuswb             m7, m7
+.h8_end_loop:
+    movq         [rsp+wq-8], m7
+    sub                  wd, 8
+    jg .h8_end_loop
+.h8_transpose:
+%if ARCH_X86_32
+    mov             strideq, [dstq]
+    mov              org_wd, [dstq+strideq]
+%endif
+    or                  r3d, 8
+    cmp              org_wd, 4
+%if ARCH_X86_64
+    jne .end_transpose_main
+%else
+    jne .end_transpose_loop
+%endif
+    mova                 m1, [rsp+16*1]
+    mova                 m0, [rsp+16*0]
+    lea                  r2, [strideq*3]
+    add                 rsp, 16*2
+    punpcklbw            m2, m1, m0
+    punpckhbw            m1, m0
+    punpckhbw            m0, m1, m2
+    punpcklbw            m1, m2
+.write_4x8_end:
+    call .write_4x8
+    RET
+.write_4x8:
+    movd   [dstq+r2       ], m0
+    pshuflw              m4, m0, q1032
+    movd   [dstq+strideq*2], m4
+    punpckhqdq           m0, m0
+    movd   [dstq+strideq*1], m0
+    psrlq                m0, 32
+    movd   [dstq+strideq*0], m0
+    lea                dstq, [dstq+strideq*4]
+    movd   [dstq+r2       ], m1
+    pshuflw              m4, m1, q1032
+    movd   [dstq+strideq*2], m4
+    punpckhqdq           m1, m1
+    movd   [dstq+strideq*1], m1
+    psrlq                m1, 32
+    movd   [dstq+strideq*0], m1
+    ret
+.h16:
+    lea                 r4d, [wq+15]
+    movd                 m0, r4d
+    and                 r4d, 15
+    or                  r4d, 16 ; imin(w+15, 31)
+    test             angled, 0x400
+    jnz .h16_main
+    movd                 m2, angled
+    shr              angled, 8 ; is_sm << 1
+    pxor                 m1, m1
+    pshufb               m0, m1
+    pshufb               m2, m1
+    movq                 m3, [base+z_filter_t_w16+angleq*4]
+    pcmpeqb              m1, m0, [base+z_filter_wh16]
+    pand                 m1, m2
+    pcmpgtb              m1, m3
+    pmovmskb            r5d, m1
+    test                r5d, r5d
+    jz .h16_main ; filter_strength == 0
+    mova                 m0, [tlq-16*2+1]
+    imul                r5d, 0x24924924
+    mova                 m1, [tlq-16*1+1]
+    neg                  r4
+    movd                 m2, [tlq-16*0+1]
+    shr                 r5d, 30
+    movd                 m3, [tlq+r4]
+    adc                  r5, -4 ; filter_strength-3
+    pxor                 m7, m7
+    lea                 tlq, [rsp+16*2]
+    mova         [tlq-16*1], m0
+    pshufb               m2, m7
+    mova         [tlq+16*0], m1
+    pshufb               m3, m7
+    mova         [tlq+16*1], m2
+    movq         [tlq+r4+8], m3
+    neg                 r4d
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    add                 tlq, 31
+    cmp                  wd, 16
+    jle .h16_main
+    pshuflw              m0, [tlq-47], q0000
+    sar                  r5, 1
+    movq                 m1, [base+z3_filter_k_tail+r5*4]
+    lea                 r4d, [r5+33]
+    pmaddubsw            m0, m1
+%if ARCH_X86_64
+    pmulhrsw             m0, m10
+%else
+    pmulhrsw             m0, m4
+%endif
+    packuswb             m0, m0
+    movd           [tlq-35], m0
+.h16_main:
+    movd                 m5, dyd
+    sub                 tlq, r4
+    movd                 m4, r4d
+    shl                 r4d, 6
+    movd                 m7, [tlq]
+    pxor                 m6, m6
+    pshufb               m5, [base+pw_256]
+    neg                 dyq
+    pshufb               m7, m6
+    mova                 m3, [base+z3_shuf]
+    lea                  r5, [dyq+r4+63]
+    pshufb               m4, m6
+    psubb                m4, [base+pb_15to0]
+    shl                  wd, 4
+    mova                 m6, m5
+    sub                 rsp, wq
+.h16_loop:
+    mov                  r4, r5
+    pand                 m2, m8, m5
+    sar                  r4, 6
+    psubw                m1, m9, m2
+    psllw                m2, 8
+    movu                 m0, [tlq+r4-8*2]
+    por                  m2, m1
+    movu                 m1, [tlq+r4-8*1]
+    pshufb               m0, m3
+    pmaddubsw            m0, m2
+    pshufb               m1, m3
+    pmaddubsw            m1, m2
+    psrlw                m2, m5, 6
+    paddw                m5, m6
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packsswb             m2, m2
+    packuswb             m0, m1
+    pcmpgtb              m1, m4, m2
+    pand                 m0, m1
+    pandn                m1, m7
+    por                  m0, m1
+    mova        [rsp+wq-16], m0
+    sub                  wd, 16
+    jz .h16_transpose
+    add                  r5, dyq
+    jg .h16_loop
+.h16_end_loop:
+    mova        [rsp+wq-16], m7
+    sub                  wd, 16
+    jg .h16_end_loop
+.h16_transpose:
+%if ARCH_X86_32
+    mov             strideq, [dstq]
+    mov              org_wd, [dstq+strideq]
+%endif
+    or                  r3d, 16
+    cmp              org_wd, 4
+%if ARCH_X86_64
+    jne .end_transpose_main
+%else
+    jne .end_transpose_loop
+%endif
+.h16_transpose_w4:
+    mova                 m2, [rsp+16*3]
+    mova                 m4, [rsp+16*2]
+    mova                 m3, [rsp+16*1]
+    mova                 m0, [rsp+16*0]
+    lea                  r2, [strideq*3]
+    add                 rsp, 16*4
+    punpckhbw            m1, m2, m4
+    punpcklbw            m2, m4
+    punpckhbw            m4, m3, m0
+    punpcklbw            m3, m0
+    punpckhwd            m0, m1, m4
+    punpcklwd            m1, m4
+    call .write_4x8
+    lea                dstq, [dstq+strideq*4]
+    punpckhwd            m0, m2, m3
+    punpcklwd            m1, m2, m3
+    jmp .write_4x8_end
+.h32:
+    lea                 r4d, [wq+31]
+    and                 r4d, 31
+    or                  r4d, 32 ; imin(w+31, 63)
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h32_main
+    mova                 m0, [tlq-16*4+1]
+    mova                 m1, [tlq-16*3+1]
+    mova                 m2, [tlq-16*2+1]
+    mova                 m3, [tlq-16*1+1]
+    movd                 m4, [tlq-16*0+1]
+    neg                  r4
+    movd                 m5, [tlq+r4]
+    pxor                 m7, m7
+    lea                 tlq, [rsp+16*4]
+    mova         [tlq-16*3], m0
+    mova         [tlq-16*2], m1
+    xor                 r5d, r5d ; filter_strength = 3
+    mova         [tlq-16*1], m2
+    pshufb               m4, m7
+    mova         [tlq+16*0], m3
+    pshufb               m5, m7
+    mova         [tlq+16*1], m4
+    movq         [tlq+r4+8], m5
+    neg                 r4d
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    sub                 tlq, 16*2
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    add                 tlq, 63
+    cmp                  wd, 32
+    jle .h32_main
+    pshuflw              m0, [tlq-79], q0000
+    movq                 m1, [base+z3_filter_k_tail]
+    add                 r4d, 2
+    pmaddubsw            m0, m1
+%if ARCH_X86_64
+    pmulhrsw             m0, m10
+%else
+    pmulhrsw             m0, m4
+%endif
+    packuswb             m0, m0
+    movd           [tlq-67], m0
+.h32_main:
+    movd                 m5, dyd
+    sub                 tlq, r4
+    movd                 m4, r4d
+    shl                 r4d, 6
+    movd                 m7, [tlq]
+    pxor                 m6, m6
+    pshufb               m5, [base+pw_256]
+    neg                 dyq
+    pshufb               m7, m6
+    mova                 m3, [base+z3_shuf]
+    lea                  r5, [dyq+r4+63]
+    pshufb               m4, m6
+    psubb                m4, [base+pb_15to0]
+    mova                 m6, m5
+.h32_loop:
+    mov                  r4, r5
+    pand                 m2, m8, m5
+    sar                  r4, 6
+    psubw                m1, m9, m2
+    psllw                m2, 8
+    movu                 m0, [tlq+r4-8*4]
+    por                  m2, m1
+    movu                 m1, [tlq+r4-8*3]
+    pshufb               m0, m3
+    pmaddubsw            m0, m2
+    pshufb               m1, m3
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    sub                 rsp, 32
+    packuswb             m0, m1
+    mova         [rsp+16*0], m0
+    movu                 m0, [tlq+r4-8*2]
+    movu                 m1, [tlq+r4-8*1]
+    pshufb               m0, m3
+    pshufb               m1, m3
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    psrlw                m2, m5, 6
+    paddw                m5, m6
+    packsswb             m2, m2
+    packuswb             m0, m1
+    pcmpgtb              m1, m4, m2
+    paddsb               m2, [base+pb_16]
+    pand                 m0, m1
+    pandn                m1, m7
+    por                  m0, m1
+    pcmpgtb              m1, m4, m2
+    mova         [rsp+16*1], m0
+    pand                 m0, m1, [rsp+16*0]
+    pandn                m1, m7
+    por                  m0, m1
+    mova         [rsp+16*0], m0
+    dec                  wd
+    jz .h32_transpose
+    add                  r5, dyq
+    jg .h32_loop
+.h32_end_loop:
+    sub                 rsp, 32
+    mova         [rsp+16*1], m7
+    mova         [rsp+16*0], m7
+    dec                  wd
+    jg .h32_end_loop
+.h32_transpose:
+    or                  r3d, 32
+    jmp .end_transpose_main
+.h64:
+    lea                 r4d, [wq+63]
+    test             angled, 0x400 ; !enable_intra_edge_filter
+    jnz .h64_main
+    mova                 m0, [tlq-16*8+1]
+    mova                 m1, [tlq-16*7+1]
+    mova                 m2, [tlq-16*6+1]
+    mova                 m3, [tlq-16*5+1]
+    mova         [rsp+16*1], m0
+    mova         [rsp+16*2], m1
+    mova         [rsp+16*3], m2
+    mova         [rsp+16*4], m3
+    mova                 m0, [tlq-16*4+1]
+    mova                 m1, [tlq-16*3+1]
+    mova                 m2, [tlq-16*2+1]
+    mova                 m3, [tlq-16*1+1]
+    movd                 m4, [tlq-16*0+1]
+    neg                  r4
+    movd                 m5, [tlq+r4]
+    pxor                 m7, m7
+    lea                 tlq, [rsp+16*8]
+    mova         [tlq-16*3], m0
+    mova         [tlq-16*2], m1
+    xor                 r5d, r5d ; filter_strength = 3
+    mova         [tlq-16*1], m2
+    pshufb               m4, m7
+    mova         [tlq+16*0], m3
+    pshufb               m5, m7
+    mova         [tlq+16*1], m4
+    movq         [tlq+r4+8], m5
+    neg                 r4d
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    sub                 tlq, 16*2
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    sub                 tlq, 16*2
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+    sub                 tlq, 16*2
+    cmp                  wd, 64
+    jl .h64_filter96 ; skip one call if the last 32 bytes aren't used
+    call mangle(private_prefix %+ _ipred_z1_8bpc_ssse3).filter_edge
+.h64_filter96:
+    add                 tlq, 127
+.h64_main:
+    movd                 m5, dyd
+    sub                 tlq, r4
+    movd                 m4, r4d
+    shl                 r4d, 6
+    movd                 m7, [tlq]
+    pxor                 m6, m6
+    pshufb               m5, [base+pw_256]
+    neg                 dyq
+    pshufb               m7, m6
+    mova                 m3, [base+z3_shuf]
+    lea                  r5, [dyq+r4+63]
+    pshufb               m4, m6
+    psubb                m4, [base+pb_15to0]
+    mova                 m6, m5
+.h64_loop:
+    mov                  r4, r5
+    pand                 m2, m8, m5
+    sar                  r4, 6
+    psubw                m1, m9, m2
+    psllw                m2, 8
+    movu                 m0, [tlq+r4-8*8]
+    por                  m2, m1
+    movu                 m1, [tlq+r4-8*7]
+    pshufb               m0, m3
+    pmaddubsw            m0, m2
+    pshufb               m1, m3
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    sub                 rsp, 64
+    packuswb             m0, m1
+    mova         [rsp+16*0], m0
+    movu                 m0, [tlq+r4-8*6]
+    movu                 m1, [tlq+r4-8*5]
+    pshufb               m0, m3
+    pshufb               m1, m3
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packuswb             m0, m1
+    mova         [rsp+16*1], m0
+    movu                 m0, [tlq+r4-8*4]
+    movu                 m1, [tlq+r4-8*3]
+    pshufb               m0, m3
+    pshufb               m1, m3
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    packuswb             m0, m1
+    mova         [rsp+16*2], m0
+    movu                 m0, [tlq+r4-8*2]
+    movu                 m1, [tlq+r4-8*1]
+    pshufb               m0, m3
+    pshufb               m1, m3
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    psrlw                m2, m5, 6
+    paddw                m5, m6
+    packsswb             m2, m2
+    packuswb             m0, m1
+    pcmpgtb              m1, m4, m2
+    paddsb               m2, [base+pb_16]
+    pand                 m0, m1
+    pandn                m1, m7
+    por                  m0, m1
+    pcmpgtb              m1, m4, m2
+    paddsb               m2, [base+pb_16]
+    mova         [rsp+16*3], m0
+    pand                 m0, m1, [rsp+16*2]
+    pandn                m1, m7
+    por                  m0, m1
+    pcmpgtb              m1, m4, m2
+    paddsb               m2, [base+pb_16]
+    mova         [rsp+16*2], m0
+    pand                 m0, m1, [rsp+16*1]
+    pandn                m1, m7
+    por                  m0, m1
+    pcmpgtb              m1, m4, m2
+    mova         [rsp+16*1], m0
+    pand                 m0, m1, [rsp+16*0]
+    pandn                m1, m7
+    por                  m0, m1
+    mova         [rsp+16*0], m0
+    dec                  wd
+    jz .h64_transpose
+    add                  r5, dyq
+    jg .h64_loop
+.h64_end_loop:
+    sub                 rsp, 64
+    mova         [rsp+16*3], m7
+    mova         [rsp+16*2], m7
+    mova         [rsp+16*1], m7
+    mova         [rsp+16*0], m7
+    dec                  wd
+    jg .h64_end_loop
+.h64_transpose:
+    or                  r3d, 64
+.end_transpose_main:
+%if ARCH_X86_64
+    lea                  r5, [r3*3]
+    lea                  r7, [strideq*3]
+%else
+    mov             strideq, [dstq]
+    mov              org_wd, [dstq+strideq]
+%endif
+.end_transpose_loop:
+    lea                  r4, [rsp+r3-8]
+    lea                  r6, [dstq+org_wq-8]
+.end_transpose_loop_y:
+    movq                 m0, [r4+r3*1]
+    movq                 m4, [r4+r3*0]
+%if ARCH_X86_64
+    movq                 m1, [r4+r5  ]
+    movq                 m5, [r4+r3*2]
+    lea                  r2, [r4+r3*4]
+%else
+    lea                  r2, [r4+r3*2]
+    movq                 m1, [r2+r3*1]
+    movq                 m5, [r2+r3*0]
+    lea                  r2, [r2+r3*2]
+%endif
+    movq                 m2, [r2+r3*1]
+    movq                 m6, [r2+r3*0]
+%if ARCH_X86_64
+    movq                 m3, [r2+r5  ]
+    movq                 m7, [r2+r3*2]
+%else
+    lea                  r2, [r2+r3*2]
+    movq                 m3, [r2+r3*1]
+    movq                 m7, [r2+r3*0]
+%endif
+    sub                  r4, 8
+    punpcklbw            m0, m4
+    punpcklbw            m1, m5
+    punpcklbw            m2, m6
+    punpcklbw            m3, m7
+    punpckhwd            m4, m1, m0
+    punpcklwd            m1, m0
+    punpckhwd            m0, m3, m2
+    punpcklwd            m3, m2
+    punpckhdq            m2, m3, m1
+    punpckldq            m3, m1
+    punpckldq            m1, m0, m4
+    punpckhdq            m0, m4
+    movhps   [r6+strideq*0], m0
+    movq     [r6+strideq*1], m0
+%if ARCH_X86_64
+    movhps   [r6+strideq*2], m1
+    movq     [r6+r7       ], m1
+    lea                  r6, [r6+strideq*4]
+%else
+    lea                  r6, [r6+strideq*2]
+    movhps   [r6+strideq*0], m1
+    movq     [r6+strideq*1], m1
+    lea                  r6, [r6+strideq*2]
+%endif
+    movhps   [r6+strideq*0], m2
+    movq     [r6+strideq*1], m2
+%if ARCH_X86_64
+    movhps   [r6+strideq*2], m3
+    movq     [r6+r7       ], m3
+    lea                  r6, [r6+strideq*4]
+%else
+    lea                  r6, [r6+strideq*2]
+    movhps   [r6+strideq*0], m3
+    movq     [r6+strideq*1], m3
+    lea                  r6, [r6+strideq*2]
+%endif
+    cmp                  r4, rsp
+    jae .end_transpose_loop_y
+    lea                 rsp, [rsp+r3*8]
+    sub              org_wd, 8
+    jg .end_transpose_loop
+    RET
+
+;-------------------------------------------------------------------------------
+;int dav1d_pal_pred_ssse3(pixel *dst, ptrdiff_t stride, const pixel *pal,
+;                         const uint8_t *idx, int w, int h);
+;-------------------------------------------------------------------------------
+cglobal pal_pred_8bpc, 4, 6, 5, dst, stride, pal, idx, w, h
+    movq                 m4, [palq]
+    LEA                  r2, pal_pred_ssse3_table
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r2+wq*4]
+    add                  wq, r2
+    lea                  r2, [strideq*3]
+    jmp                  wq
+.w4:
+    movq                 m1, [idxq]
+    add                idxq, 8
+    psrlw                m0, m1, 4
+    punpcklbw            m1, m0
+    pshufb               m0, m4, m1
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    punpckhqdq           m0, m0
+    movd   [dstq+strideq*2], m0
+    psrlq                m0, 32
+    movd   [dstq+r2       ], m0
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    movu                 m0, [idxq]
+    add                idxq, 16
+    pshufb               m1, m4, m0
+    psrlw                m0, 4
+    pshufb               m2, m4, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movq   [dstq+strideq*2], m1
+    movhps [dstq+r2       ], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    movu                 m0, [idxq]
+    add                idxq, 16
+    pshufb               m1, m4, m0
+    psrlw                m0, 4
+    pshufb               m2, m4, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w16
+    RET
+.w32:
+    movu                 m0, [idxq]
+    add                idxq, 16
+    pshufb               m1, m4, m0
+    psrlw                m0, 4
+    pshufb               m2, m4, m0
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w32
+    RET
+.w64:
+    movu                 m0, [idxq+16*0]
+    movu                 m2, [idxq+16*1]
+    add                idxq, 32
+    pshufb               m1, m4, m0
+    psrlw                m0, 4
+    pshufb               m3, m4, m0
+    punpcklbw            m0, m1, m3
+    punpckhbw            m1, m3
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    pshufb               m1, m4, m2
+    psrlw                m2, 4
+    pshufb               m3, m4, m2
+    punpcklbw            m0, m1, m3
+    punpckhbw            m1, m3
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    add                dstq, strideq
+    sub                  hd, 1
+    jg .w64
+    RET
+
+;---------------------------------------------------------------------------------------
+;void dav1d_ipred_cfl_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                           const int width, const int height, const int16_t *ac, const int alpha);
+;---------------------------------------------------------------------------------------
+%macro IPRED_CFL 1                   ; ac in, unpacked pixels out
+    psignw               m3, m%1, m1
+    pabsw               m%1, m%1
+    pmulhrsw            m%1, m2
+    psignw              m%1, m3
+    paddw               m%1, m0
+%endmacro
+
+%if UNIX64
+DECLARE_REG_TMP 7
+%else
+DECLARE_REG_TMP 5
+%endif
+
+cglobal ipred_cfl_8bpc, 3, 7, 6, dst, stride, tl, w, h, ac, alpha
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    tzcnt               r6d, hd
+    lea                 t0d, [wq+hq]
+    movd                 m4, t0d
+    tzcnt               t0d, t0d
+    movd                 m5, t0d
+    LEA                  t0, ipred_cfl_ssse3_table
+    tzcnt                wd, wd
+    movsxd               r6, [t0+r6*4]
+    movsxd               wq, [t0+wq*4+16]
+    pcmpeqd              m3, m3
+    psrlw                m4, 1
+    add                  r6, t0
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+.h4:
+    movd                 m0, [tlq-4]
+    pmaddubsw            m0, m3
+    jmp                  wq
+.w4:
+    movd                 m1, [tlq+1]
+    pmaddubsw            m1, m3
+    psubw                m0, m4
+    paddw                m0, m1
+    pmaddwd              m0, m3
+    cmp                  hd, 4
+    jg .w4_mul
+    psrlw                m0, 3                             ; dc >>= ctz(width + height);
+    jmp .w4_end
+.w4_mul:
+    punpckhqdq           m1, m0, m0
+    paddw                m0, m1
+    pshuflw              m1, m0, q1032                     ; psrlq                m1, m0, 32
+    paddw                m0, m1
+    psrlw                m0, 2
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    test                 hd, 8
+    cmovz               r6d, r2d
+    movd                 m5, r6d
+    pmulhuw              m0, m5
+.w4_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s4:
+    movd                 m1, alpham
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    lea                  r6, [strideq*3]
+    pabsw                m2, m1
+    psllw                m2, 9
+.s4_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+16]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    movd   [dstq+strideq*0], m4
+    pshuflw              m4, m4, q1032
+    movd   [dstq+strideq*1], m4
+    punpckhqdq           m4, m4
+    movd   [dstq+strideq*2], m4
+    psrlq                m4, 32
+    movd   [dstq+r6       ], m4
+    lea                dstq, [dstq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 4
+    jg .s4_loop
+    RET
+ALIGN function_align
+.h8:
+    movq                 m0, [tlq-8]
+    pmaddubsw            m0, m3
+    jmp                  wq
+.w8:
+    movq                 m1, [tlq+1]
+    pmaddubsw            m1, m3
+    psubw                m4, m0
+    punpckhqdq           m0, m0
+    psubw                m0, m4
+    paddw                m0, m1
+    pshuflw              m1, m0, q1032                  ; psrlq  m1, m0, 32
+    paddw                m0, m1
+    pmaddwd              m0, m3
+    psrlw                m0, m5
+    cmp                  hd, 8
+    je .w8_end
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    cmp                  hd, 32
+    cmovz               r6d, r2d
+    movd                 m1, r6d
+    pmulhuw              m0, m1
+.w8_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s8:
+    movd                 m1, alpham
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    lea                  r6, [strideq*3]
+    pabsw                m2, m1
+    psllw                m2, 9
+.s8_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+16]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    movq   [dstq          ], m4
+    movhps [dstq+strideq  ], m4
+    mova                 m4, [acq+32]
+    mova                 m5, [acq+48]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    movq   [dstq+strideq*2], m4
+    movhps [dstq+r6       ], m4
+    lea                dstq, [dstq+strideq*4]
+    add                 acq, 64
+    sub                  hd, 4
+    jg .s8_loop
+    RET
+ALIGN function_align
+.h16:
+    mova                 m0, [tlq-16]
+    pmaddubsw            m0, m3
+    jmp                  wq
+.w16:
+    movu                 m1, [tlq+1]
+    pmaddubsw            m1, m3
+    paddw                m0, m1
+    psubw                m4, m0
+    punpckhqdq           m0, m0
+    psubw                m0, m4
+    pshuflw              m1, m0, q1032                  ; psrlq  m1, m0, 32
+    paddw                m0, m1
+    pmaddwd              m0, m3
+    psrlw                m0, m5
+    cmp                  hd, 16
+    je .w16_end
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    test                 hd, 8|32
+    cmovz               r6d, r2d
+    movd                 m1, r6d
+    pmulhuw              m0, m1
+.w16_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s16:
+    movd                 m1, alpham
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    pabsw                m2, m1
+    psllw                m2, 9
+.s16_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+16]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    mova             [dstq], m4
+    mova                 m4, [acq+32]
+    mova                 m5, [acq+48]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    mova     [dstq+strideq], m4
+    lea                dstq, [dstq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .s16_loop
+    RET
+ALIGN function_align
+.h32:
+    mova                 m0, [tlq-32]
+    pmaddubsw            m0, m3
+    mova                 m2, [tlq-16]
+    pmaddubsw            m2, m3
+    paddw                m0, m2
+    jmp                  wq
+.w32:
+    movu                 m1, [tlq+1]
+    pmaddubsw            m1, m3
+    movu                 m2, [tlq+17]
+    pmaddubsw            m2, m3
+    paddw                m1, m2
+    paddw                m0, m1
+    psubw                m4, m0
+    punpckhqdq           m0, m0
+    psubw                m0, m4
+    pshuflw              m1, m0, q1032                   ; psrlq  m1, m0, 32
+    paddw                m0, m1
+    pmaddwd              m0, m3
+    psrlw                m0, m5
+    cmp                  hd, 32
+    je .w32_end
+    lea                 r2d, [hq*2]
+    mov                 r6d, 0x5556
+    mov                 r2d, 0x3334
+    test                 hd, 64|16
+    cmovz               r6d, r2d
+    movd                 m1, r6d
+    pmulhuw              m0, m1
+.w32_end:
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+.s32:
+    movd                 m1, alpham
+    pshuflw              m1, m1, q0000
+    punpcklqdq           m1, m1
+    pabsw                m2, m1
+    psllw                m2, 9
+.s32_loop:
+    mova                 m4, [acq]
+    mova                 m5, [acq+16]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    mova             [dstq], m4
+    mova                 m4, [acq+32]
+    mova                 m5, [acq+48]
+    IPRED_CFL             4
+    IPRED_CFL             5
+    packuswb             m4, m5
+    mova          [dstq+16], m4
+    add                dstq, strideq
+    add                 acq, 64
+    dec                  hd
+    jg .s32_loop
+    RET
+
+;---------------------------------------------------------------------------------------
+;void dav1d_ipred_cfl_left_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                           const int width, const int height, const int16_t *ac, const int alpha);
+;---------------------------------------------------------------------------------------
+cglobal ipred_cfl_left_8bpc, 3, 7, 6, dst, stride, tl, w, h, ac, alpha
+    mov                  hd, hm                                 ; zero upper half
+    tzcnt               r6d, hd
+    sub                 tlq, hq
+    tzcnt                wd, wm
+    movu                 m0, [tlq]
+    mov                 t0d, 0x8000
+    movd                 m3, t0d
+    movd                 m2, r6d
+    psrld                m3, m2
+    LEA                  t0, ipred_cfl_left_ssse3_table
+    movsxd               r6, [t0+r6*4]
+    pcmpeqd              m2, m2
+    pmaddubsw            m0, m2
+    add                  r6, t0
+    add                  t0, ipred_cfl_splat_ssse3_table-ipred_cfl_left_ssse3_table
+    movsxd               wq, [t0+wq*4]
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+.h32:
+    movu                 m1, [tlq+16]                           ; unaligned when jumping here from dc_top
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+.h16:
+    pshufd               m1, m0, q3232                          ; psrlq               m1, m0, 16
+    paddw                m0, m1
+.h8:
+    pshuflw              m1, m0, q1032                          ; psrlq               m1, m0, 32
+    paddw                m0, m1
+.h4:
+    pmaddwd              m0, m2
+    pmulhrsw             m0, m3
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+    jmp                  wq
+
+;---------------------------------------------------------------------------------------
+;void dav1d_ipred_cfl_top_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                           const int width, const int height, const int16_t *ac, const int alpha);
+;---------------------------------------------------------------------------------------
+cglobal ipred_cfl_top_8bpc, 3, 7, 6, dst, stride, tl, w, h, ac, alpha
+    LEA                  t0, ipred_cfl_left_ssse3_table
+    tzcnt                wd, wm
+    inc                 tlq
+    movu                 m0, [tlq]
+    movifnidn            hd, hm
+    mov                 r6d, 0x8000
+    movd                 m3, r6d
+    movd                 m2, wd
+    psrld                m3, m2
+    movsxd               r6, [t0+wq*4]
+    pcmpeqd              m2, m2
+    pmaddubsw            m0, m2
+    add                  r6, t0
+    add                  t0, ipred_cfl_splat_ssse3_table-ipred_cfl_left_ssse3_table
+    movsxd               wq, [t0+wq*4]
+    add                  wq, t0
+    movifnidn           acq, acmp
+    jmp                  r6
+
+;---------------------------------------------------------------------------------------
+;void dav1d_ipred_cfl_128_ssse3(pixel *dst, const ptrdiff_t stride, const pixel *const topleft,
+;                           const int width, const int height, const int16_t *ac, const int alpha);
+;---------------------------------------------------------------------------------------
+cglobal ipred_cfl_128_8bpc, 3, 7, 6, dst, stride, tl, w, h, ac, alpha
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    LEA                  r6, ipred_cfl_splat_ssse3_table
+    movsxd               wq, [r6+wq*4]
+    movddup              m0, [r6-ipred_cfl_splat_ssse3_table+pw_128]
+    add                  wq, r6
+    movifnidn           acq, acmp
+    jmp                  wq
+
+%macro RELOAD_ACQ_32 1
+    mov                 acq, ac_bakq       ; restore acq
+%endmacro
+
+%if ARCH_X86_64
+cglobal ipred_cfl_ac_420_8bpc, 4, 8, 7, ac, y, stride, wpad, hpad, w, h, ac_bak
+DECLARE_REG_TMP 7
+    movddup              m2, [pb_2]
+%else
+cglobal ipred_cfl_ac_420_8bpc, 4, 7, 7, ac, y, stride, wpad, hpad, w, h
+DECLARE_REG_TMP 4
+%define ac_bakq acmp
+    mov                 t0d, 0x02020202
+    movd                 m2, t0d
+    pshufd               m2, m2, q0000
+%endif
+    movifnidn            wd, wm
+    mov                 t0d, hm
+    mov                  hd, t0d
+    imul                t0d, wd
+    movd                 m5, t0d
+    movifnidn         hpadd, hpadm
+%if ARCH_X86_64
+    mov             ac_bakq, acq
+%endif
+    shl               hpadd, 2
+    sub                  hd, hpadd
+    pxor                 m4, m4
+    cmp                  wd, 8
+    jg .w16
+    je .w8
+    ; fall-through
+%if ARCH_X86_64
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h, ac_bak
+%else
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h
+%endif
+.w4:
+    lea            stride3q, [strideq*3]
+.w4_loop:
+    movq                 m0, [yq]
+    movq                 m1, [yq+strideq]
+    movhps               m0, [yq+strideq*2]
+    movhps               m1, [yq+stride3q]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    mova              [acq], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 16
+    sub                  hd, 2
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz .calc_avg_4_8
+    punpckhqdq           m0, m0
+.w4_hpad_loop:
+    mova              [acq], m0
+    paddw                m4, m0
+    add                 acq, 16
+    sub               hpadd, 2
+    jg .w4_hpad_loop
+    jmp .calc_avg_4_8
+.w8:
+    lea            stride3q, [strideq*3]
+    test              wpadd, wpadd
+    jnz .w8_wpad
+.w8_loop:
+    mova                 m0, [yq]
+    mova                 m1, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    mova              [acq], m0
+    paddw                m4, m0
+    mova                 m0, [yq+strideq*2]
+    mova                 m1, [yq+stride3q]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    mova           [acq+16], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 2
+    jg .w8_loop
+    test              hpadd, hpadd
+    jz .calc_avg_4_8
+    jmp .w8_hpad
+.w8_wpad:                                              ; wpadd=1
+    movddup              m0, [yq]
+    movddup              m1, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    pshufhw              m0, m0, q3333
+    mova              [acq], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 16
+    sub                  hd, 1
+    jg .w8_wpad
+    test              hpadd, hpadd
+    jz .calc_avg_4_8
+.w8_hpad:
+    mova              [acq], m0
+    paddw                m4, m0
+    add                 acq, 16
+    sub               hpadd, 1
+    jg .w8_hpad
+    jmp .calc_avg_4_8
+.w16:
+    test              wpadd, wpadd
+    jnz .w16_wpad
+.w16_loop:
+    mova                 m0, [yq]
+    mova                 m1, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    mova              [acq], m0
+    paddw                m4, m0
+    mova                 m6, [yq+16]
+    mova                 m1, [yq+strideq+16]
+    pmaddubsw            m6, m2
+    pmaddubsw            m1, m2
+    paddw                m6, m1
+    mova           [acq+16], m6
+    paddw                m4, m6
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 32
+    dec                  hd
+    jg .w16_loop
+    test              hpadd, hpadd
+    jz .calc_avg16
+    jmp .w16_hpad_loop
+.w16_wpad:
+    cmp               wpadd, 2
+    jl .w16_pad1
+    je .w16_pad2
+.w16_pad3:
+    movddup              m0, [yq]
+    movddup              m1, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    pshufhw              m0, m0, q3333
+    mova              [acq], m0
+    paddw                m4, m0
+    mova                 m6, m0
+    punpckhqdq           m6, m0, m0
+    mova           [acq+16], m6
+    paddw                m4, m6
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 32
+    dec                  hd
+    jg .w16_pad3
+    jmp .w16_wpad_done
+.w16_pad2:
+    mova                 m0, [yq]
+    mova                 m1, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    mova              [acq], m0
+    paddw                m4, m0
+    pshufhw              m6, m0, q3333
+    punpckhqdq           m6, m6
+    mova           [acq+16], m6
+    paddw                m4, m6
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 32
+    dec                  hd
+    jg .w16_pad2
+    jmp .w16_wpad_done
+.w16_pad1:
+    mova                 m0, [yq]
+    mova                 m1, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    paddw                m0, m1
+    mova              [acq], m0
+    paddw                m4, m0
+    movddup              m6, [yq+16]
+    movddup              m1, [yq+strideq+16]
+    pmaddubsw            m6, m2
+    pmaddubsw            m1, m2
+    paddw                m6, m1
+    pshufhw              m6, m6, q3333
+    mova           [acq+16], m6
+    paddw                m4, m6
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 32
+    dec                  hd
+    jg .w16_pad1
+.w16_wpad_done:
+    test              hpadd, hpadd
+    jz .calc_avg16
+.w16_hpad_loop:
+    mova              [acq], m0
+    paddw                m4, m0
+    mova           [acq+16], m6
+    paddw                m4, m6
+    add                 acq, 32
+    dec               hpadd
+    jg .w16_hpad_loop
+    jmp .calc_avg16
+
+%if ARCH_X86_64
+    DEFINE_ARGS ac, y, iptr, wpad, hpad, sz, h, ac_bak
+%else
+    DEFINE_ARGS ac, y, iptr, wpad, hpad, sz, h
+%endif
+.calc_avg_4_8:
+    psrlw                m2, 9
+    pmaddwd              m4, m2
+    jmp .calc_avg
+.calc_avg16:
+    psrld                m0, m4, 16
+    pslld                m4, 16
+    psrld                m4, 16
+    paddd                m4, m0
+.calc_avg:
+    movd                szd, m5
+    psrad                m5, 1
+    tzcnt               r1d, szd
+    paddd                m4, m5
+    movd                 m1, r1d
+    pshufd               m0, m4, q2301
+    paddd                m0, m4
+    pshufd               m4, m0, q1032
+    paddd                m0, m4
+    psrad                m0, m1                        ; sum >>= log2sz;
+    packssdw             m0, m0
+    RELOAD_ACQ_32       acq
+.sub_loop:
+    mova                 m1, [acq]
+    psubw                m1, m0                        ; ac[x] -= sum;
+    mova              [acq], m1
+    add                 acq, 16
+    sub                 szd, 8
+    jg .sub_loop
+    RET
+
+%if ARCH_X86_64
+cglobal ipred_cfl_ac_422_8bpc, 4, 8, 7, ac, y, stride, wpad, hpad, w, h, ac_bak
+    movddup              m2, [pb_4]
+%else
+cglobal ipred_cfl_ac_422_8bpc, 4, 7, 7, ac, y, stride, wpad, hpad, w, h
+    mov                 t0d, 0x04040404
+    movd                 m2, t0d
+    pshufd               m2, m2, q0000
+%endif
+    movifnidn            wd, wm
+    mov                 t0d, hm
+    mov                  hd, t0d
+    imul                t0d, wd
+    movd                 m6, t0d
+    movifnidn         hpadd, hpadm
+%if ARCH_X86_64
+    mov             ac_bakq, acq
+%endif
+    shl               hpadd, 2
+    sub                  hd, hpadd
+    pxor                 m4, m4
+    pxor                 m5, m5
+    cmp                  wd, 8
+    jg .w16
+    je .w8
+    ; fall-through
+
+%if ARCH_X86_64
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h, ac_bak
+%else
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h
+%endif
+.w4:
+    lea            stride3q, [strideq*3]
+.w4_loop:
+    movq                 m1, [yq]
+    movhps               m1, [yq+strideq]
+    movq                 m0, [yq+strideq*2]
+    movhps               m0, [yq+stride3q]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    mova           [acq+16], m0
+    paddw                m4, m0
+    paddw                m5, m1
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 4
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz .calc_avg_4
+    punpckhqdq           m0, m0
+.w4_hpad_loop:
+    mova              [acq], m0
+    paddw                m4, m0
+    add                 acq, 16
+    sub               hpadd, 2
+    jg .w4_hpad_loop
+    jmp .calc_avg_4
+.w8:
+    lea            stride3q, [strideq*3]
+    test              wpadd, wpadd
+    jnz .w8_wpad
+.w8_loop:
+    mova                 m1, [yq]
+    mova                 m0, [yq+strideq]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    mova           [acq+16], m0
+    paddw                m4, m0
+    paddw                m5, m1
+    mova                 m1, [yq+strideq*2]
+    mova                 m0, [yq+stride3q]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    mova           [acq+48], m0
+    paddw                m4, m0
+    paddw                m5, m1
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 64
+    sub                  hd, 4
+    jg .w8_loop
+    test              hpadd, hpadd
+    jz .calc_avg_8_16
+    jmp .w8_hpad
+.w8_wpad:
+    movddup              m1, [yq]
+    pmaddubsw            m1, m2
+    pshufhw              m1, m1, q3333
+    mova              [acq], m1
+    paddw                m5, m1
+    movddup              m0, [yq+strideq]
+    pmaddubsw            m0, m2
+    pshufhw              m0, m0, q3333
+    mova           [acq+16], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 32
+    sub                  hd, 2
+    jg .w8_wpad
+    test              hpadd, hpadd
+    jz .calc_avg_8_16
+.w8_hpad:
+    mova              [acq], m0
+    paddw                m4, m0
+    mova           [acq+16], m0
+    paddw                m4, m0
+    add                 acq, 32
+    sub               hpadd, 2
+    jg .w8_hpad
+    jmp .calc_avg_8_16
+.w16:
+    test              wpadd, wpadd
+    jnz .w16_wpad
+.w16_loop:
+    mova                 m1, [yq]
+    mova                 m0, [yq+16]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    mova           [acq+16], m0
+    paddw                m5, m0
+    paddw                m5, m1
+    mova                 m1, [yq+strideq]
+    mova                 m0, [yq+strideq+16]
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    mova           [acq+48], m0
+    paddw                m4, m0
+    paddw                m4, m1
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_loop
+    test              hpadd, hpadd
+    jz .calc_avg_8_16
+    jmp .w16_hpad_loop
+.w16_wpad:
+    cmp               wpadd, 2
+    jl .w16_pad1
+    je .w16_pad2
+.w16_pad3:
+    movddup              m1, [yq]
+    pmaddubsw            m1, m2
+    pshufhw              m1, m1, q3333
+    mova              [acq], m1
+    paddw                m5, m1
+    punpckhqdq           m1, m1
+    mova           [acq+16], m1
+    paddw                m5, m1
+    movddup              m1, [yq+strideq]
+    pmaddubsw            m1, m2
+    pshufhw              m1, m1, q3333
+    mova           [acq+32], m1
+    paddw                m4, m1
+    punpckhqdq           m0, m1, m1
+    mova           [acq+48], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_pad3
+    jmp .w16_wpad_done
+.w16_pad2:
+    mova                 m1, [yq]
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1
+    pshufhw              m1, m1, q3333
+    punpckhqdq           m1, m1
+    mova           [acq+16], m1
+    paddw                m5, m1
+    mova                 m1, [yq+strideq]
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    paddw                m4, m1
+    mova                 m0, m1
+    pshufhw              m0, m0, q3333
+    punpckhqdq           m0, m0
+    mova           [acq+48], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_pad2
+    jmp .w16_wpad_done
+.w16_pad1:
+    mova                 m1, [yq]
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1
+    movddup              m0, [yq+16]
+    pmaddubsw            m0, m2
+    pshufhw              m0, m0, q3333
+    mova           [acq+16], m0
+    paddw                m5, m0
+    mova                 m1, [yq+strideq]
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    paddw                m4, m1
+    movddup              m0, [yq+strideq+16]
+    pmaddubsw            m0, m2
+    pshufhw              m0, m0, q3333
+    mova           [acq+48], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_pad1
+.w16_wpad_done:
+    test              hpadd, hpadd
+    jz .calc_avg_8_16
+.w16_hpad_loop:
+    mova              [acq], m1
+    mova           [acq+16], m0
+    paddw                m4, m1
+    paddw                m5, m0
+    mova           [acq+32], m1
+    mova           [acq+48], m0
+    paddw                m4, m1
+    paddw                m5, m0
+    add                 acq, 64
+    sub               hpadd, 2
+    jg .w16_hpad_loop
+    jmp .calc_avg_8_16
+
+%if ARCH_X86_64
+    DEFINE_ARGS ac, y, iptr, wpad, hpad, sz, h, ac_bak
+%else
+    DEFINE_ARGS ac, y, iptr, wpad, hpad, sz, h
+%endif
+.calc_avg_4:
+    psrlw                m2, 10
+    pmaddwd              m5, m2
+    pmaddwd              m0, m4, m2
+    jmp .calc_avg
+.calc_avg_8_16:
+    mova                 m0, m5
+    psrld                m5, 16
+    pslld                m0, 16
+    psrld                m0, 16
+    paddd                m5, m0
+    mova                 m0, m4
+    psrld                m0, 16
+    pslld                m4, 16
+    psrld                m4, 16
+    paddd                m0, m4
+.calc_avg:
+    paddd                m5, m0
+    movd                szd, m6
+    psrad                m6, 1
+    tzcnt               r1d, szd                       ; const int log2sz = ctz(width) + ctz(height);
+    paddd                m5, m6
+    movd                 m1, r1d
+    pshufd               m0, m5, q2301
+    paddd                m0, m5
+    pshufd               m5, m0, q1032
+    paddd                m0, m5
+    psrad                m0, m1                        ; sum >>= log2sz;
+    packssdw             m0, m0
+    RELOAD_ACQ_32       acq                            ; ac = ac_orig
+.sub_loop:
+    mova                 m1, [acq]
+    psubw                m1, m0
+    mova              [acq], m1
+    add                 acq, 16
+    sub                 szd, 8
+    jg .sub_loop
+    RET
+
+%if ARCH_X86_64
+cglobal ipred_cfl_ac_444_8bpc, 4, 8, 7, -4*16, ac, y, stride, wpad, hpad, w, h, ac_bak
+    movddup              m2, [pb_4]
+%else
+cglobal ipred_cfl_ac_444_8bpc, 4, 7, 7, -5*16, ac, y, stride, wpad, hpad, w, h
+%define ac_bakq [rsp+16*4]
+    mov                 t0d, 0x04040404
+    movd                 m2, t0d
+    pshufd               m2, m2, q0000
+%endif
+    movifnidn            wd, wm
+    movifnidn         hpadd, hpadm
+    movd                 m0, hpadd
+    mov                 t0d, hm
+    mov                  hd, t0d
+    imul                t0d, wd
+    movd                 m6, t0d
+    movd              hpadd, m0
+    mov             ac_bakq, acq
+    shl               hpadd, 2
+    sub                  hd, hpadd
+    pxor                 m5, m5
+    pxor                 m4, m4
+    cmp                  wd, 16
+    jg .w32
+    cmp                  wd, 8
+    jg .w16
+    je .w8
+    ; fall-through
+
+%if ARCH_X86_64
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h, ac_bak
+%else
+    DEFINE_ARGS ac, y, stride, wpad, hpad, stride3, h
+%endif
+.w4:
+    lea            stride3q, [strideq*3]
+.w4_loop:
+    movd                 m1, [yq]
+    movd                 m3, [yq+strideq]
+    punpckldq            m1, m3
+    punpcklbw            m1, m1
+    movd                 m0, [yq+strideq*2]
+    movd                 m3, [yq+stride3q]
+    punpckldq            m0, m3
+    punpcklbw            m0, m0
+    pmaddubsw            m1, m2
+    pmaddubsw            m0, m2
+    mova              [acq], m1
+    mova           [acq+16], m0
+    paddw                m5, m0
+    paddw                m5, m1
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 32
+    sub                  hd, 4
+    jg .w4_loop
+    test              hpadd, hpadd
+    jz .calc_avg_4
+    punpckhqdq           m0, m0
+.w4_hpad_loop:
+    mova              [acq], m0
+    paddw                m5, m0
+    add                 acq, 16
+    sub               hpadd, 2
+    jg .w4_hpad_loop
+.calc_avg_4:
+    psrlw                m2, 10
+    pmaddwd              m5, m2
+    jmp .calc_avg
+
+.w8:
+    lea            stride3q, [strideq*3]
+    test              wpadd, wpadd
+    jnz .w8_wpad
+.w8_loop:
+    movq                 m1, [yq]
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1
+    movq                 m0, [yq+strideq]
+    punpcklbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0
+    movq                 m1, [yq+strideq*2]
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    paddw                m4, m1
+    movq                 m0, [yq+stride3q]
+    punpcklbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+48], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*4]
+    add                 acq, 64
+    sub                  hd, 4
+    jg .w8_loop
+    test              hpadd, hpadd
+    jz .calc_avg_8_16
+    jmp .w8_hpad
+.w8_wpad:
+    movd                 m1, [yq]
+    punpcklbw            m1, m1
+    punpcklqdq           m1, m1
+    pmaddubsw            m1, m2
+    pshufhw              m1, m1, q3333
+    mova              [acq], m1
+    paddw                m5, m1
+    movd                 m0, [yq+strideq]
+    punpcklbw            m0, m0
+    punpcklqdq           m0, m0
+    pmaddubsw            m0, m2
+    pshufhw              m0, m0, q3333
+    mova           [acq+16], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 32
+    sub                  hd, 2
+    jg .w8_wpad
+    test              hpadd, hpadd
+    jz .calc_avg_8_16
+.w8_hpad:
+    mova              [acq], m0
+    paddw                m5, m0
+    mova           [acq+16], m0
+    paddw                m4, m0
+    add                 acq, 32
+    sub               hpadd, 2
+    jg .w8_hpad
+    jmp .calc_avg_8_16
+
+.w16:
+    test              wpadd, wpadd
+    jnz .w16_wpad
+.w16_loop:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1
+    punpckhbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0
+    mova                 m0, [yq+strideq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    paddw                m4, m1
+    punpckhbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+48], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_loop
+    test              hpadd, hpadd
+    jz .calc_avg_8_16
+    jmp .w16_hpad_loop
+.w16_wpad:
+    cmp               wpadd, 2
+    jl .w16_pad1
+    je .w16_pad2
+.w16_pad3:
+    movd                 m1, [yq]
+    punpcklbw            m1, m1
+    punpcklqdq           m1, m1
+    pshufhw              m1, m1, q3333
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1
+    punpckhqdq           m1, m1
+    mova           [acq+16], m1
+    paddw                m5, m1
+    movd                 m1, [yq+strideq]
+    punpcklbw            m1, m1
+    punpcklqdq           m1, m1
+    pshufhw              m1, m1, q3333
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    paddw                m4, m1
+    punpckhqdq           m0, m1, m1
+    mova           [acq+48], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_pad3
+    jmp .w16_wpad_done
+.w16_pad2:
+    movq                 m1, [yq]
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1
+    pshufhw              m1, m1, q3333
+    punpckhqdq           m1, m1
+    mova           [acq+16], m1
+    paddw                m5, m1
+    movq                 m1, [yq+strideq]
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    paddw                m4, m1
+    mova                 m0, m1
+    pshufhw              m0, m0, q3333
+    punpckhqdq           m0, m0
+    mova           [acq+48], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_pad2
+    jmp .w16_wpad_done
+.w16_pad1:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1
+    punpckhbw            m0, m0
+    punpcklqdq           m0, m0
+    pshufhw              m0, m0, q3333
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0
+    mova                 m0, [yq+strideq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova           [acq+32], m1
+    paddw                m4, m1
+    punpckhbw            m0, m0
+    punpcklqdq           m0, m0
+    pshufhw              m0, m0, q3333
+    pmaddubsw            m0, m2
+    mova           [acq+48], m0
+    paddw                m4, m0
+    lea                  yq, [yq+strideq*2]
+    add                 acq, 64
+    sub                  hd, 2
+    jg .w16_pad1
+.w16_wpad_done:
+    test              hpadd, hpadd
+    jz .calc_avg_8_16
+.w16_hpad_loop:
+    mova              [acq], m1
+    mova           [acq+16], m0
+    paddw                m4, m1
+    paddw                m5, m0
+    mova           [acq+32], m1
+    mova           [acq+48], m0
+    paddw                m4, m1
+    paddw                m5, m0
+    add                 acq, 64
+    sub               hpadd, 2
+    jg .w16_hpad_loop
+.calc_avg_8_16:
+    mova                 m0, m5
+    psrld                m5, 16
+    pslld                m0, 16
+    psrld                m0, 16
+    paddd                m5, m0
+    mova                 m0, m4
+    psrld                m0, 16
+    pslld                m4, 16
+    psrld                m4, 16
+    paddd                m0, m4
+    paddd                m5, m0
+    jmp .calc_avg
+
+.w32:
+    pxor                 m0, m0
+    mova           [rsp   ], m0
+    mova           [rsp+16], m0
+    mova           [rsp+32], m0
+    mova           [rsp+48], m0
+    test              wpadd, wpadd
+    jnz .w32_wpad
+.w32_loop:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1, [rsp]
+    mova           [rsp   ], m5
+    punpckhbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    mova                 m4, [yq+16]
+    mova                 m3, m4
+    punpcklbw            m3, m3
+    pmaddubsw            m3, m2
+    mova           [acq+32], m3
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    punpckhbw            m4, m4
+    pmaddubsw            m4, m2
+    mova           [acq+48], m4
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    lea                  yq, [yq+strideq]
+    add                 acq, 64
+    sub                  hd, 1
+    jg .w32_loop
+    test              hpadd, hpadd
+    jz .calc_avg_32
+    jmp .w32_hpad_loop
+.w32_wpad:
+    cmp               wpadd, 2
+    jl .w32_pad1
+    je .w32_pad2
+    cmp               wpadd, 4
+    jl .w32_pad3
+    je .w32_pad4
+    cmp               wpadd, 6
+    jl .w32_pad5
+    je .w32_pad6
+.w32_pad7:
+    movd                 m1, [yq]
+    punpcklbw            m1, m1
+    punpcklqdq           m1, m1
+    pshufhw              m1, m1, q3333
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1, [rsp]
+    mova           [rsp   ], m5
+    mova                 m0, m1
+    punpckhqdq           m0, m0
+    mova           [acq+16], m0
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    mova                 m3, m0
+    mova           [acq+32], m3
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    mova                 m4, m3
+    mova           [acq+48], m4
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    lea                  yq, [yq+strideq]
+    add                 acq, 64
+    sub                  hd, 1
+    jg .w32_pad7
+    jmp .w32_wpad_done
+.w32_pad6:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1, [rsp]
+    mova           [rsp   ], m5
+    pshufhw              m0, m1, q3333
+    punpckhqdq           m0, m0
+    mova           [acq+16], m0
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    mova                 m3, m0
+    mova           [acq+32], m3
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    mova                 m4, m3
+    mova           [acq+48], m4
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    lea                  yq, [yq+strideq]
+    add                 acq, 64
+    sub                  hd, 1
+    jg .w32_pad6
+    jmp .w32_wpad_done
+.w32_pad5:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    mova                 m5, [rsp]
+    paddw                m5, m1
+    mova           [rsp   ], m5
+    punpckhbw            m0, m0
+    punpcklqdq           m0, m0
+    pshufhw              m0, m0, q3333
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    mova                 m3, m0
+    punpckhqdq           m3, m3
+    mova           [acq+32], m3
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    mova                 m4, m3
+    mova           [acq+48], m4
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    lea                  yq, [yq+strideq]
+    add                 acq, 64
+    sub                  hd, 1
+    jg .w32_pad5
+    jmp .w32_wpad_done
+.w32_pad4:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1, [rsp]
+    mova           [rsp   ], m5
+    punpckhbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    mova                 m3, m0
+    pshufhw              m3, m3, q3333
+    punpckhqdq           m3, m3
+    mova           [acq+32], m3
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    mova                 m4, m3
+    mova           [acq+48], m4
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    lea                  yq, [yq+strideq]
+    add                 acq, 64
+    sub                  hd, 1
+    jg .w32_pad4
+    jmp .w32_wpad_done
+.w32_pad3:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1, [rsp]
+    mova           [rsp   ], m5
+    punpckhbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    movd                 m3, [yq+16]
+    punpcklbw            m3, m3
+    punpcklqdq           m3, m3
+    pshufhw              m3, m3, q3333
+    pmaddubsw            m3, m2
+    mova           [acq+32], m3
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    mova                 m4, m3
+    punpckhqdq           m4, m4
+    mova           [acq+48], m4
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    lea                  yq, [yq+strideq]
+    add                 acq, 64
+    sub                  hd, 1
+    jg .w32_pad3
+    jmp .w32_wpad_done
+.w32_pad2:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1, [rsp]
+    mova           [rsp   ], m5
+    punpckhbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    mova                 m3, [yq+16]
+    punpcklbw            m3, m3
+    pmaddubsw            m3, m2
+    mova           [acq+32], m3
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    pshufhw              m4, m3, q3333
+    punpckhqdq           m4, m4
+    mova           [acq+48], m4
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    lea                  yq, [yq+strideq]
+    add                 acq, 64
+    sub                  hd, 1
+    jg .w32_pad2
+    jmp .w32_wpad_done
+.w32_pad1:
+    mova                 m0, [yq]
+    mova                 m1, m0
+    punpcklbw            m1, m1
+    pmaddubsw            m1, m2
+    mova              [acq], m1
+    paddw                m5, m1, [rsp]
+    mova           [rsp   ], m5
+    punpckhbw            m0, m0
+    pmaddubsw            m0, m2
+    mova           [acq+16], m0
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    mova                 m4, [yq+16]
+    mova                 m3, m4
+    punpcklbw            m3, m3
+    pmaddubsw            m3, m2
+    mova           [acq+32], m3
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    punpckhbw            m4, m4
+    punpcklqdq           m4, m4
+    pshufhw              m4, m4, q3333
+    pmaddubsw            m4, m2
+    mova           [acq+48], m4
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    lea                  yq, [yq+strideq]
+    add                 acq, 64
+    sub                  hd, 1
+    jg .w32_pad1
+.w32_wpad_done:
+    test              hpadd, hpadd
+    jz .calc_avg_32
+.w32_hpad_loop:
+    mova              [acq], m1
+    mova           [acq+16], m0
+    paddw                m5, m1, [rsp]
+    mova           [rsp   ], m5
+    paddw                m5, m0, [rsp+16]
+    mova           [rsp+16], m5
+    mova           [acq+32], m3
+    mova           [acq+48], m4
+    paddw                m5, m3, [rsp+32]
+    mova           [rsp+32], m5
+    paddw                m5, m4, [rsp+48]
+    mova           [rsp+48], m5
+    add                 acq, 64
+    sub               hpadd, 1
+    jg .w32_hpad_loop
+
+%if ARCH_X86_64
+    DEFINE_ARGS ac, y, iptr, wpad, hpad, sz, h, ac_bak
+%else
+    DEFINE_ARGS ac, y, iptr, wpad, hpad, sz, h
+%endif
+
+.calc_avg_32:
+    mova                 m5, [rsp]
+    mova                 m0, m5
+    psrld                m5, 16
+    pslld                m0, 16
+    psrld                m0, 16
+    paddd                m5, m0
+    mova                 m0, [rsp+16]
+    mova                 m3, m0
+    psrld                m0, 16
+    pslld                m3, 16
+    psrld                m3, 16
+    paddd                m0, m3
+    paddd                m5, m0
+    mova                 m0, [rsp+32]
+    mova                 m3, m0
+    psrld                m0, 16
+    pslld                m3, 16
+    psrld                m3, 16
+    paddd                m0, m3
+    mova                 m1, [rsp+48]
+    mova                 m3, m1
+    psrld                m1, 16
+    pslld                m3, 16
+    psrld                m3, 16
+    paddd                m1, m3
+    paddd                m1, m0
+    paddd                m5, m1
+.calc_avg:
+    movd                szd, m6
+    psrad                m6, 1
+    tzcnt               r1d, szd                       ; const int log2sz = ctz(width) + ctz(height);
+    paddd                m5, m6
+    movd                 m1, r1d
+    pshufd               m0, m5, q2301
+    paddd                m0, m5
+    pshufd               m5, m0, q1032
+    paddd                m0, m5
+    psrad                m0, m1                        ; sum >>= log2sz;
+    packssdw             m0, m0
+    RELOAD_ACQ_32       acq                            ; ac = ac_orig
+.sub_loop:
+    mova                 m1, [acq]
+    psubw                m1, m0
+    mova              [acq], m1
+    add                 acq, 16
+    sub                 szd, 8
+    jg .sub_loop
+    RET
+
+; %1 simd register that hold the mask and will hold the result
+; %2 simd register that holds the "true" values
+; %3 location of the "false" values (simd register/memory)
+%macro BLEND 3 ; mask, true, false
+    pand  %2, %1
+    pandn %1, %3
+    por   %1, %2
+%endmacro
+
+%macro PAETH 2                                 ; top, ldiff
+    pavgb                m1, m%1, m3
+    pxor                 m0, m%1, m3
+    pand                 m0, m4
+    psubusb              m2, m5, m1
+    psubb                m1, m0
+    psubusb              m1, m5
+    por                  m1, m2
+    paddusb              m1, m1
+    por                  m1, m0               ; min(tldiff, 255)
+    psubusb              m2, m5, m3
+    psubusb              m0, m3, m5
+    por                  m2, m0               ; tdiff
+%ifnum %2
+    pminub               m2, m%2
+    pcmpeqb              m0, m%2, m2          ; ldiff <= tdiff
+%else
+    mova                 m0, %2
+    pminub               m2, m0
+    pcmpeqb              m0, m2
+%endif
+    pminub               m1, m2
+    pcmpeqb              m1, m2               ; ldiff <= tldiff && tdiff <= tldiff
+    mova                 m2, m3
+    BLEND                m0, m2, m%1
+    BLEND                m1, m0, m5
+%endmacro
+
+cglobal ipred_paeth_8bpc, 3, 6, 8, -7*16, dst, stride, tl, w, h
+%define base r5-ipred_paeth_ssse3_table
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    pxor                 m0, m0
+    movd                 m5, [tlq]
+    pshufb               m5, m0
+    LEA                  r5, ipred_paeth_ssse3_table
+    movsxd               wq, [r5+wq*4]
+    movddup              m4, [base+ipred_paeth_shuf]
+    add                  wq, r5
+    jmp                  wq
+.w4:
+    movd                 m6, [tlq+1]            ; top
+    pshufd               m6, m6, q0000
+    lea                  r3, [strideq*3]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0                 ; ldiff
+.w4_loop:
+    sub                 tlq, 4
+    movd                 m3, [tlq]
+    mova                 m1, [base+ipred_h_shuf]
+    pshufb               m3, m1                 ; left
+    PAETH                 6, 7
+    movd   [dstq          ], m1
+    pshuflw              m0, m1, q1032
+    movd   [dstq+strideq  ], m0
+    punpckhqdq           m1, m1
+    movd   [dstq+strideq*2], m1
+    psrlq                m1, 32
+    movd   [dstq+r3       ], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    movddup              m6, [tlq+1]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w8_loop:
+    sub                 tlq, 2
+    movd                 m3, [tlq]
+    pshufb               m3, [base+ipred_paeth_shuf]
+    PAETH                 6, 7
+    movq     [dstq        ], m1
+    movhps   [dstq+strideq], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    movu                 m6, [tlq+1]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+.w16_loop:
+    sub                 tlq, 1
+    movd                 m3, [tlq]
+    pxor                 m1, m1
+    pshufb               m3, m1
+    PAETH                 6, 7
+    mova             [dstq], m1
+    add                dstq, strideq
+    sub                  hd, 1
+    jg .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    movu                 m6, [tlq+1]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+    mova           [rsp   ], m6
+    mova           [rsp+16], m7
+    movu                 m6, [tlq+17]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+    mova           [rsp+32], m6
+.w32_loop:
+    dec                 tlq
+    movd                 m3, [tlq]
+    pxor                 m1, m1
+    pshufb               m3, m1
+    mova                 m6, [rsp]
+    PAETH                 6, [rsp+16]
+    mova          [dstq   ], m1
+    mova                 m6, [rsp+32]
+    PAETH                 6, 7
+    mova          [dstq+16], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w32_loop
+    RET
+ALIGN function_align
+.w64:
+    movu                 m6, [tlq+1]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+    mova           [rsp   ], m6
+    mova           [rsp+16], m7
+    movu                 m6, [tlq+17]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+    mova           [rsp+32], m6
+    mova           [rsp+48], m7
+    movu                 m6, [tlq+33]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+    mova           [rsp+64], m6
+    mova           [rsp+80], m7
+    movu                 m6, [tlq+49]
+    psubusb              m7, m5, m6
+    psubusb              m0, m6, m5
+    por                  m7, m0
+    mova           [rsp+96], m6
+.w64_loop:
+    dec                 tlq
+    movd                 m3, [tlq]
+    pxor                 m1, m1
+    pshufb               m3, m1
+    mova                 m6, [rsp]
+    PAETH                 6, [rsp+16]
+    mova          [dstq   ], m1
+    mova                 m6, [rsp+32]
+    PAETH                 6, [rsp+48]
+    mova          [dstq+16], m1
+    mova                 m6, [rsp+64]
+    PAETH                 6, [rsp+80]
+    mova          [dstq+32], m1
+    mova                 m6, [rsp+96]
+    PAETH                 6, 7
+    mova          [dstq+48], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+
+
+%macro FILTER 4  ;dst, src, tmp, shuf
+%ifnum %4
+    pshufb               m%2, m%4
+%else
+    pshufb               m%2, %4
+%endif
+    pshufd               m%1, m%2, q0000           ;p0 p1
+    pmaddubsw            m%1, m2
+    pshufd               m%3, m%2, q1111           ;p2 p3
+    pmaddubsw            m%3, m3
+    paddw                m%1, [base+pw_8]
+    paddw                m%1, m%3
+    pshufd               m%3, m%2, q2222           ;p4 p5
+    pmaddubsw            m%3, m4
+    paddw                m%1, m%3
+    pshufd               m%3, m%2, q3333           ;p6 __
+    pmaddubsw            m%3, m5
+    paddw                m%1, m%3
+    psraw                m%1, 4
+    packuswb             m%1, m%1
+%endmacro
+
+cglobal ipred_filter_8bpc, 3, 7, 8, dst, stride, tl, w, h, filter
+%define base r6-$$
+    LEA                   r6, $$
+    tzcnt                 wd, wm
+%ifidn filterd, filterm
+    movzx            filterd, filterb
+%else
+    movzx            filterd, byte filterm
+%endif
+    shl              filterd, 6
+    lea              filterq, [base+filter_intra_taps+filterq]
+    movq                  m0, [tlq-3]                     ;_ 6 5 0 1 2 3 4
+    movsxd                wq, [base+ipred_filter_ssse3_table+wq*4]
+    mova                  m2, [filterq+16*0]
+    mova                  m3, [filterq+16*1]
+    mova                  m4, [filterq+16*2]
+    mova                  m5, [filterq+16*3]
+    lea                   wq, [base+ipred_filter_ssse3_table+wq]
+    mov                   hd, hm
+    jmp                   wq
+.w4:
+    mova                  m1, [base+filter_shuf1]
+    sub                  tlq, 3
+    sub                  tlq, hq
+    jmp .w4_loop_start
+.w4_loop:
+    movd                  m0, [tlq+hq]
+    punpckldq             m0, m6
+    lea                 dstq, [dstq+strideq*2]
+.w4_loop_start:
+    FILTER                 6, 0, 7, 1
+    movd    [dstq+strideq*0], m6
+    pshuflw               m6, m6, q1032
+    movd    [dstq+strideq*1], m6
+    sub                   hd, 2
+    jg .w4_loop
+    RET
+
+ALIGN function_align
+.w8:
+    movq                  m6, [tlq+1]                   ;_ _ _ 0 1 2 3 4
+    sub                  tlq, 5
+    sub                  tlq, hq
+
+.w8_loop:
+    FILTER                 7, 0, 1, [base+filter_shuf1]
+    punpcklqdq            m6, m7                        ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    FILTER                 0, 6, 1, [base+filter_shuf2]
+
+    punpckldq             m6, m7, m0
+    movq    [dstq+strideq*0], m6
+    punpckhqdq            m6, m6
+    movq    [dstq+strideq*1], m6
+
+    movd                  m0, [tlq+hq]                  ;_ 6 5 0
+    punpckldq             m0, m6                        ;_ 6 5 0 1 2 3 4
+
+    lea                 dstq, [dstq+strideq*2]
+    sub                   hd, 2
+    jg .w8_loop
+    RET
+
+ALIGN function_align
+.w16:
+    movu                  m6, [tlq+1]                   ;top row
+    sub                  tlq, 5
+    sub                  tlq, hq
+
+.w16_loop:
+    FILTER                 7, 0, 1, [base+filter_shuf1]
+    punpcklqdq            m0, m6, m7                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd    [dstq+strideq*0], m7
+    psrlq                 m7, 32
+    palignr               m7, m6, 4
+
+    FILTER                 6, 0, 1, [base+filter_shuf2]
+    punpcklqdq            m0, m7, m6                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd  [dstq+4+strideq*0], m6
+    psrlq                 m6, 32
+    palignr               m6, m7, 4
+
+    FILTER                 7, 0, 1, [base+filter_shuf2]
+    punpcklqdq            m0, m6, m7                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd  [dstq+8+strideq*0], m7
+    psrlq                 m7, 32
+    palignr               m7, m6, 4
+
+    FILTER                 6, 0, 1, [base+filter_shuf2]
+    movd [dstq+12+strideq*0], m6
+    psrlq                 m6, 32
+    palignr               m6, m7, 4
+    mova    [dstq+strideq*1], m6
+
+    movd                  m0, [tlq+hq]                  ;_ 6 5 0
+    punpckldq             m0, m6                        ;_ 6 5 0 1 2 3 4
+
+    lea                 dstq, [dstq+strideq*2]
+    sub                   hd, 2
+    jg .w16_loop
+    RET
+
+ALIGN function_align
+.w32:
+    movu                  m6, [tlq+1]                   ;top row
+    lea              filterq, [tlq+17]
+    sub                  tlq, 5
+    sub                  tlq, hq
+
+.w32_loop:
+    FILTER                 7, 0, 1, [base+filter_shuf1]
+    punpcklqdq            m0, m6, m7                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd    [dstq+strideq*0], m7
+    psrlq                 m7, 32
+    palignr               m7, m6, 4
+
+    FILTER                 6, 0, 1, [base+filter_shuf2]
+    punpcklqdq            m0, m7, m6                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd  [dstq+4+strideq*0], m6
+    psrlq                 m6, 32
+    palignr               m6, m7, 4
+
+    FILTER                 7, 0, 1, [base+filter_shuf2]
+    punpcklqdq            m0, m6, m7                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd  [dstq+8+strideq*0], m7
+    psrlq                 m7, 32
+    palignr               m7, m6, 4
+
+    FILTER                 6, 0, 1, [base+filter_shuf2]
+    movu                  m1, [filterq]
+    punpckldq             m0, m7, m1                    ;_ _ _ 0 1 2 3 4 _ _ _ _ _ _ _ _
+    punpcklqdq            m0, m6                        ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd [dstq+12+strideq*0], m6
+    psrlq                 m6, 32
+    palignr               m6, m7, 4
+    mova    [dstq+strideq*1], m6
+
+    mova                  m6, m1
+
+    FILTER                 7, 0, 6, [base+filter_shuf2]
+    punpcklqdq            m0, m1, m7                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd [dstq+16+strideq*0], m7
+    psrlq                 m7, 32
+    palignr               m7, m1, 4
+
+    FILTER                 6, 0, 1, [base+filter_shuf2]
+    punpcklqdq            m0, m7, m6                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd [dstq+20+strideq*0], m6
+    psrlq                 m6, 32
+    palignr               m6, m7, 4
+
+    FILTER                 7, 0, 1, [base+filter_shuf2]
+    punpcklqdq            m0, m6, m7                    ;_ _ _ 0 1 2 3 4 _ _ _ 5 _ _ _ 6
+    movd [dstq+24+strideq*0], m7
+    psrlq                 m7, 32
+    palignr               m7, m6, 4
+
+    FILTER                 6, 0, 1, [base+filter_shuf2]
+    movd [dstq+28+strideq*0], m6
+    psrlq                 m6, 32
+    palignr               m6, m7, 4
+    mova [dstq+16+strideq*1], m6
+
+    mova                  m6, [dstq+strideq*1]
+    movd                  m0, [tlq+hq]                  ;_ 6 5 0
+    punpckldq             m0, m6                        ;_ 6 5 0 1 2 3 4
+    lea              filterq, [dstq+16+strideq*1]
+    lea                 dstq, [dstq+strideq*2]
+    sub                   hd, 2
+    jg .w32_loop
+    RET
diff --git a/media/libdav1d/src/src/x86/itx.h b/media/libdav1d/src/src/x86/itx.h
new file mode 100644
index 0000000000..a8a490fa47
--- /dev/null
+++ b/media/libdav1d/src/src/x86/itx.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright © 2018-2023, VideoLAN and dav1d authors
+ * Copyright © 2018-2023, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/itx.h"
+
+#define BF_BPC(x, bits, suffix) x##_##bits##bpc_##suffix
+
+#define decl_itx_fns(ext) \
+decl_itx17_fns( 4,  4, ext); \
+decl_itx16_fns( 4,  8, ext); \
+decl_itx16_fns( 4, 16, ext); \
+decl_itx16_fns( 8,  4, ext); \
+decl_itx16_fns( 8,  8, ext); \
+decl_itx16_fns( 8, 16, ext); \
+decl_itx2_fns ( 8, 32, ext); \
+decl_itx16_fns(16,  4, ext); \
+decl_itx16_fns(16,  8, ext); \
+decl_itx12_fns(16, 16, ext); \
+decl_itx2_fns (16, 32, ext); \
+decl_itx2_fns (32,  8, ext); \
+decl_itx2_fns (32, 16, ext); \
+decl_itx2_fns (32, 32, ext); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_16x64, ext)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_32x64, ext)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x16, ext)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x32, ext)); \
+decl_itx_fn(BF(dav1d_inv_txfm_add_dct_dct_64x64, ext))
+
+
+#define decl_itx2_bpc_fns(w, h, bpc, opt) \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_dct_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_identity_identity_##w##x##h, bpc, opt))
+
+#define decl_itx12_bpc_fns(w, h, bpc, opt) \
+decl_itx2_bpc_fns(w, h, bpc, opt); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_adst_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_flipadst_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_identity_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_adst_dct_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_adst_adst_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_adst_flipadst_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_flipadst_dct_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_flipadst_adst_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_flipadst_flipadst_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_identity_dct_##w##x##h, bpc, opt))
+
+#define decl_itx16_bpc_fns(w, h, bpc, opt) \
+decl_itx12_bpc_fns(w, h, bpc, opt); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_adst_identity_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_flipadst_identity_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_identity_adst_##w##x##h, bpc, opt)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_identity_flipadst_##w##x##h, bpc, opt))
+
+#define decl_itx_bpc_fns(bpc, ext) \
+decl_itx16_bpc_fns( 4,  4, bpc, ext); \
+decl_itx16_bpc_fns( 4,  8, bpc, ext); \
+decl_itx16_bpc_fns( 4, 16, bpc, ext); \
+decl_itx16_bpc_fns( 8,  4, bpc, ext); \
+decl_itx16_bpc_fns( 8,  8, bpc, ext); \
+decl_itx16_bpc_fns( 8, 16, bpc, ext); \
+decl_itx2_bpc_fns ( 8, 32, bpc, ext); \
+decl_itx16_bpc_fns(16,  4, bpc, ext); \
+decl_itx16_bpc_fns(16,  8, bpc, ext); \
+decl_itx12_bpc_fns(16, 16, bpc, ext); \
+decl_itx2_bpc_fns (16, 32, bpc, ext); \
+decl_itx2_bpc_fns (32,  8, bpc, ext); \
+decl_itx2_bpc_fns (32, 16, bpc, ext); \
+decl_itx2_bpc_fns (32, 32, bpc, ext); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_dct_16x64, bpc, ext)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_dct_32x64, bpc, ext)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_dct_64x16, bpc, ext)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_dct_64x32, bpc, ext)); \
+decl_itx_fn(BF_BPC(dav1d_inv_txfm_add_dct_dct_64x64, bpc, ext))
+
+decl_itx_fns(avx512icl);
+decl_itx_bpc_fns(10, avx512icl);
+decl_itx_fns(avx2);
+decl_itx_bpc_fns(10, avx2);
+decl_itx_bpc_fns(12, avx2);
+decl_itx_fns(sse4);
+decl_itx_fns(ssse3);
+decl_itx_fn(dav1d_inv_txfm_add_wht_wht_4x4_16bpc_avx2);
+decl_itx_fn(BF(dav1d_inv_txfm_add_wht_wht_4x4, sse2));
+
+static ALWAYS_INLINE void itx_dsp_init_x86(Dav1dInvTxfmDSPContext *const c,
+                                           const int bpc, int *const all_simd)
+{
+#define assign_itx_bpc_fn(pfx, w, h, type, type_enum, bpc, ext) \
+    c->itxfm_add[pfx##TX_##w##X##h][type_enum] = \
+        BF_BPC(dav1d_inv_txfm_add_##type##_##w##x##h, bpc, ext)
+
+#define assign_itx1_bpc_fn(pfx, w, h, bpc, ext) \
+    assign_itx_bpc_fn(pfx, w, h, dct_dct,           DCT_DCT,           bpc, ext)
+
+#define assign_itx2_bpc_fn(pfx, w, h, bpc, ext) \
+    assign_itx1_bpc_fn(pfx, w, h, bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, identity_identity, IDTX,              bpc, ext)
+
+#define assign_itx12_bpc_fn(pfx, w, h, bpc, ext) \
+    assign_itx2_bpc_fn(pfx, w, h, bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, dct_adst,          ADST_DCT,          bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, dct_flipadst,      FLIPADST_DCT,      bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, dct_identity,      H_DCT,             bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, adst_dct,          DCT_ADST,          bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, adst_adst,         ADST_ADST,         bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, adst_flipadst,     FLIPADST_ADST,     bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, flipadst_dct,      DCT_FLIPADST,      bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, flipadst_adst,     ADST_FLIPADST,     bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, flipadst_flipadst, FLIPADST_FLIPADST, bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, identity_dct,      V_DCT,             bpc, ext)
+
+#define assign_itx16_bpc_fn(pfx, w, h, bpc, ext) \
+    assign_itx12_bpc_fn(pfx, w, h, bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, adst_identity,     H_ADST,            bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, flipadst_identity, H_FLIPADST,        bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, identity_adst,     V_ADST,            bpc, ext); \
+    assign_itx_bpc_fn(pfx, w, h, identity_flipadst, V_FLIPADST,        bpc, ext)
+
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSE2)) return;
+
+    assign_itx_fn(, 4, 4, wht_wht, WHT_WHT, sse2);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSSE3)) return;
+
+#if BITDEPTH == 8
+    assign_itx16_fn(,   4,  4, ssse3);
+    assign_itx16_fn(R,  4,  8, ssse3);
+    assign_itx16_fn(R,  8,  4, ssse3);
+    assign_itx16_fn(,   8,  8, ssse3);
+    assign_itx16_fn(R,  4, 16, ssse3);
+    assign_itx16_fn(R, 16,  4, ssse3);
+    assign_itx16_fn(R,  8, 16, ssse3);
+    assign_itx16_fn(R, 16,  8, ssse3);
+    assign_itx12_fn(,  16, 16, ssse3);
+    assign_itx2_fn (R,  8, 32, ssse3);
+    assign_itx2_fn (R, 32,  8, ssse3);
+    assign_itx2_fn (R, 16, 32, ssse3);
+    assign_itx2_fn (R, 32, 16, ssse3);
+    assign_itx2_fn (,  32, 32, ssse3);
+    assign_itx1_fn (R, 16, 64, ssse3);
+    assign_itx1_fn (R, 32, 64, ssse3);
+    assign_itx1_fn (R, 64, 16, ssse3);
+    assign_itx1_fn (R, 64, 32, ssse3);
+    assign_itx1_fn ( , 64, 64, ssse3);
+    *all_simd = 1;
+#endif
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSE41)) return;
+
+#if BITDEPTH == 16
+    if (bpc == 10) {
+        assign_itx16_fn(,   4,  4, sse4);
+        assign_itx16_fn(R,  4,  8, sse4);
+        assign_itx16_fn(R,  4, 16, sse4);
+        assign_itx16_fn(R,  8,  4, sse4);
+        assign_itx16_fn(,   8,  8, sse4);
+        assign_itx16_fn(R,  8, 16, sse4);
+        assign_itx16_fn(R, 16,  4, sse4);
+        assign_itx16_fn(R, 16,  8, sse4);
+        assign_itx12_fn(,  16, 16, sse4);
+        assign_itx2_fn (R,  8, 32, sse4);
+        assign_itx2_fn (R, 32,  8, sse4);
+        assign_itx2_fn (R, 16, 32, sse4);
+        assign_itx2_fn (R, 32, 16, sse4);
+        assign_itx2_fn (,  32, 32, sse4);
+        assign_itx1_fn (R, 16, 64, sse4);
+        assign_itx1_fn (R, 32, 64, sse4);
+        assign_itx1_fn (R, 64, 16, sse4);
+        assign_itx1_fn (R, 64, 32, sse4);
+        assign_itx1_fn (,  64, 64, sse4);
+        *all_simd = 1;
+    }
+#endif
+
+#if ARCH_X86_64
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2)) return;
+
+    assign_itx_fn(, 4, 4, wht_wht, WHT_WHT, avx2);
+
+#if BITDEPTH == 8
+    assign_itx16_fn( ,  4,  4, avx2);
+    assign_itx16_fn(R,  4,  8, avx2);
+    assign_itx16_fn(R,  4, 16, avx2);
+    assign_itx16_fn(R,  8,  4, avx2);
+    assign_itx16_fn( ,  8,  8, avx2);
+    assign_itx16_fn(R,  8, 16, avx2);
+    assign_itx2_fn (R,  8, 32, avx2);
+    assign_itx16_fn(R, 16,  4, avx2);
+    assign_itx16_fn(R, 16,  8, avx2);
+    assign_itx12_fn( , 16, 16, avx2);
+    assign_itx2_fn (R, 16, 32, avx2);
+    assign_itx1_fn (R, 16, 64, avx2);
+    assign_itx2_fn (R, 32,  8, avx2);
+    assign_itx2_fn (R, 32, 16, avx2);
+    assign_itx2_fn ( , 32, 32, avx2);
+    assign_itx1_fn (R, 32, 64, avx2);
+    assign_itx1_fn (R, 64, 16, avx2);
+    assign_itx1_fn (R, 64, 32, avx2);
+    assign_itx1_fn ( , 64, 64, avx2);
+#else
+    if (bpc == 10) {
+        assign_itx16_bpc_fn( ,  4,  4, 10, avx2);
+        assign_itx16_bpc_fn(R,  4,  8, 10, avx2);
+        assign_itx16_bpc_fn(R,  4, 16, 10, avx2);
+        assign_itx16_bpc_fn(R,  8,  4, 10, avx2);
+        assign_itx16_bpc_fn( ,  8,  8, 10, avx2);
+        assign_itx16_bpc_fn(R,  8, 16, 10, avx2);
+        assign_itx2_bpc_fn (R,  8, 32, 10, avx2);
+        assign_itx16_bpc_fn(R, 16,  4, 10, avx2);
+        assign_itx16_bpc_fn(R, 16,  8, 10, avx2);
+        assign_itx12_bpc_fn( , 16, 16, 10, avx2);
+        assign_itx2_bpc_fn (R, 16, 32, 10, avx2);
+        assign_itx1_bpc_fn (R, 16, 64, 10, avx2);
+        assign_itx2_bpc_fn (R, 32,  8, 10, avx2);
+        assign_itx2_bpc_fn (R, 32, 16, 10, avx2);
+        assign_itx2_bpc_fn ( , 32, 32, 10, avx2);
+        assign_itx1_bpc_fn (R, 32, 64, 10, avx2);
+        assign_itx1_bpc_fn (R, 64, 16, 10, avx2);
+        assign_itx1_bpc_fn (R, 64, 32, 10, avx2);
+        assign_itx1_bpc_fn ( , 64, 64, 10, avx2);
+    } else {
+        assign_itx16_bpc_fn( ,  4,  4, 12, avx2);
+        assign_itx16_bpc_fn(R,  4,  8, 12, avx2);
+        assign_itx16_bpc_fn(R,  4, 16, 12, avx2);
+        assign_itx16_bpc_fn(R,  8,  4, 12, avx2);
+        assign_itx16_bpc_fn( ,  8,  8, 12, avx2);
+        assign_itx16_bpc_fn(R,  8, 16, 12, avx2);
+        assign_itx2_bpc_fn (R,  8, 32, 12, avx2);
+        assign_itx16_bpc_fn(R, 16,  4, 12, avx2);
+        assign_itx16_bpc_fn(R, 16,  8, 12, avx2);
+        assign_itx12_bpc_fn( , 16, 16, 12, avx2);
+        assign_itx2_bpc_fn (R, 32,  8, 12, avx2);
+        assign_itx_bpc_fn(R, 16, 32, identity_identity, IDTX, 12, avx2);
+        assign_itx_bpc_fn(R, 32, 16, identity_identity, IDTX, 12, avx2);
+        assign_itx_bpc_fn( , 32, 32, identity_identity, IDTX, 12, avx2);
+    }
+#endif
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL)) return;
+
+#if BITDEPTH == 8
+    assign_itx16_fn( ,  4,  4, avx512icl); // no wht
+    assign_itx16_fn(R,  4,  8, avx512icl);
+    assign_itx16_fn(R,  4, 16, avx512icl);
+    assign_itx16_fn(R,  8,  4, avx512icl);
+    assign_itx16_fn( ,  8,  8, avx512icl);
+    assign_itx16_fn(R,  8, 16, avx512icl);
+    assign_itx2_fn (R,  8, 32, avx512icl);
+    assign_itx16_fn(R, 16,  4, avx512icl);
+    assign_itx16_fn(R, 16,  8, avx512icl);
+    assign_itx12_fn( , 16, 16, avx512icl);
+    assign_itx2_fn (R, 16, 32, avx512icl);
+    assign_itx1_fn (R, 16, 64, avx512icl);
+    assign_itx2_fn (R, 32,  8, avx512icl);
+    assign_itx2_fn (R, 32, 16, avx512icl);
+    assign_itx2_fn ( , 32, 32, avx512icl);
+    assign_itx1_fn (R, 32, 64, avx512icl);
+    assign_itx1_fn (R, 64, 16, avx512icl);
+    assign_itx1_fn (R, 64, 32, avx512icl);
+    assign_itx1_fn ( , 64, 64, avx512icl);
+#else
+    if (bpc == 10) {
+        assign_itx16_bpc_fn( ,  8,  8, 10, avx512icl);
+        assign_itx16_bpc_fn(R,  8, 16, 10, avx512icl);
+        assign_itx2_bpc_fn (R,  8, 32, 10, avx512icl);
+        assign_itx16_bpc_fn(R, 16,  8, 10, avx512icl);
+        assign_itx12_bpc_fn( , 16, 16, 10, avx512icl);
+        assign_itx2_bpc_fn (R, 16, 32, 10, avx512icl);
+        assign_itx2_bpc_fn (R, 32,  8, 10, avx512icl);
+        assign_itx2_bpc_fn (R, 32, 16, 10, avx512icl);
+        assign_itx2_bpc_fn ( , 32, 32, 10, avx512icl);
+        assign_itx1_bpc_fn (R, 16, 64, 10, avx512icl);
+        assign_itx1_bpc_fn (R, 32, 64, 10, avx512icl);
+        assign_itx1_bpc_fn (R, 64, 16, 10, avx512icl);
+        assign_itx1_bpc_fn (R, 64, 32, 10, avx512icl);
+        assign_itx1_bpc_fn ( , 64, 64, 10, avx512icl);
+    }
+#endif
+#endif
+}
diff --git a/media/libdav1d/src/src/x86/itx16_avx2.asm b/media/libdav1d/src/src/x86/itx16_avx2.asm
new file mode 100644
index 0000000000..0da970a1c6
--- /dev/null
+++ b/media/libdav1d/src/src/x86/itx16_avx2.asm
@@ -0,0 +1,8599 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; Copyright © 2021, Matthias Dressel
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 32
+itx4_shuf:       dd 0x50401600, 0xd0c09284, 0x70603422, 0xf0e0b0a6
+                 dd 0x50401701, 0xd0c09385, 0x70603523, 0xf0e0b1a7
+idct4_12_shuf:   dd 0, 2, 4, 6, 1, 3, 5, 7
+idct4_12_shuf2:  dd 2, 0, 6, 4, 3, 1, 7, 5
+iadst8_12_shuf:  dd 0, 4, 1, 5, 2, 6, 3, 7
+idct16_12_shuf:  dd 0, 4, 1, 5, 3, 7, 2, 6
+iadst16_12_shuf: dd 3, 7, 0, 4, 2, 6, 1, 5
+pw_2048_m2048:   dw  2048,  2048,  2048,  2048, -2048, -2048, -2048, -2048
+idct4_shuf:   db  0,  1,  4,  5, 12, 13,  8,  9,  2,  3,  6,  7, 14, 15, 10, 11
+idct32_shuf:  db  0,  1,  8,  9,  4,  5, 12, 13,  2,  3, 10, 11,  6,  7, 14, 15
+
+%macro COEF_PAIR 2-3 0
+pd_%1_%2: dd %1, %1, %2, %2
+%define pd_%1 (pd_%1_%2 + 4*0)
+%define pd_%2 (pd_%1_%2 + 4*2)
+%if %3
+dd -%2, -%2
+%define pd_%2_m%2 pd_%2
+%endif
+%endmacro
+
+COEF_PAIR  201,  995
+COEF_PAIR  401, 1931
+COEF_PAIR  799, 3406
+COEF_PAIR 1380,  601
+COEF_PAIR 1751, 2440
+COEF_PAIR 2598, 1189
+COEF_PAIR 2751, 2106
+COEF_PAIR 2896, 1567, 1
+COEF_PAIR 2896, 3784, 1
+COEF_PAIR 3035, 3513
+COEF_PAIR 3166, 3920
+COEF_PAIR 3703, 3290
+COEF_PAIR 3857, 4052
+COEF_PAIR 4017, 2276
+COEF_PAIR 4076, 3612
+COEF_PAIR 4091, 3973
+
+pd_8:      dd     8
+pd_m601:   dd  -601
+pd_m1189:  dd -1189
+pd_m1380:  dd -1380
+pd_m2106:  dd -2106
+pd_m2598:  dd -2598
+pd_m2751:  dd -2751
+pd_m3344:  dd -3344
+pd_1024:   dd  1024
+pd_1321:   dd  1321
+pd_1448:   dd  1448
+pd_1697:   dd  1697
+pd_2482:   dd  2482
+pd_3072:   dd  3072 ; 1024 + 2048
+pd_3803:   dd  3803
+pd_5119:   dd  5119 ; 1024 + 4096 - 1
+pd_5120:   dd  5120 ; 1024 + 4096
+pd_5793:   dd  5793
+pd_6144:   dd  6144 ; 2048 + 4096
+pd_17408:  dd 17408 ; 1024 + 16384
+
+pixel_10bpc_max: times 2 dw 0x03ff
+pixel_12bpc_max: times 2 dw 0x0fff
+dconly_10bpc:    times 2 dw 0x7c00
+dconly_12bpc:    times 2 dw 0x7000
+clip_18b_min:  dd -0x20000
+clip_18b_max:  dd  0x1ffff
+clip_20b_min:  dd -0x80000
+clip_20b_max:  dd  0x7ffff
+
+const idct64_mul_16bpc
+dd 4095,  101, 2967, -2824,  3745, 1660, 3822, -1474,   401,  4076,   799,  4017
+dd -700, 4036, 2359,  3349, -2191, 3461,  897,  3996, -2598, -3166, -4017,  -799
+dd 4065,  501, 3229, -2520,  3564, 2019, 3948, -1092,  1931,  3612,  3406,  2276
+dd -301, 4085, 2675,  3102, -1842, 3659, 1285,  3889, -1189, -3920, -2276, -3406
+
+cextern deint_shuf
+cextern idct64_mul
+cextern pw_1697x8
+cextern pw_1697x16
+cextern pw_1567_3784
+cextern pw_m1567_m3784
+cextern pw_m3784_1567
+cextern pw_2896_2896
+cextern pw_m2896_2896
+cextern pw_5
+cextern pw_2048
+cextern pw_4096
+cextern pw_8192
+cextern pw_16384
+cextern pw_2896x8
+cextern pd_2048
+
+cextern idct_4x8_internal_8bpc_avx2.main
+cextern idct_4x16_internal_8bpc_avx2.main
+cextern idct_8x8_internal_8bpc_avx2.main
+cextern idct_8x16_internal_8bpc_avx2.main
+cextern idct_16x4_internal_8bpc_avx2.main
+cextern idct_16x8_internal_8bpc_avx2.main
+cextern idct_16x16_internal_8bpc_avx2.main
+cextern inv_txfm_add_dct_dct_8x32_8bpc_avx2.main
+cextern inv_txfm_add_dct_dct_8x32_8bpc_avx2.main_fast
+cextern inv_txfm_add_dct_dct_16x32_8bpc_avx2.main_oddhalf
+cextern inv_txfm_add_dct_dct_16x32_8bpc_avx2.main_oddhalf_fast
+cextern inv_txfm_add_dct_dct_16x64_8bpc_avx2.main_part1
+cextern inv_txfm_add_dct_dct_16x64_8bpc_avx2.main_part2_internal
+
+cextern iadst_4x4_internal_8bpc_avx2.main
+cextern iadst_4x8_internal_8bpc_avx2.main_pass2
+cextern iadst_4x16_internal_8bpc_avx2.main2
+cextern iadst_8x4_internal_8bpc_avx2.main
+cextern iadst_8x8_internal_8bpc_avx2.main_pass2
+cextern iadst_8x16_internal_8bpc_avx2.main
+cextern iadst_8x16_internal_8bpc_avx2.main_pass2_end
+cextern iadst_16x4_internal_8bpc_avx2.main
+cextern iadst_16x8_internal_8bpc_avx2.main
+cextern iadst_16x8_internal_8bpc_avx2.main_pass2_end
+cextern iadst_16x16_internal_8bpc_avx2.main
+cextern iadst_16x16_internal_8bpc_avx2.main_pass2_end
+
+SECTION .text
+
+%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX)
+
+%macro WRAP_XMM 1+
+    INIT_XMM cpuname
+    %1
+    INIT_YMM cpuname
+%endmacro
+
+%macro IWHT4_1D_PACKED 0
+    ; m0 = in0 in2, m1 = in1 in3
+    psubd                m2, m0, m1 ; t2
+    paddd               xm0, xm1    ; t0
+    vpermq               m2, m2, q3322
+    vpermq               m0, m0, q1100
+    vpermq               m1, m1, q3120
+    psubd                m3, m0, m2
+    psrad                m3, 1
+    psubd                m3, m1     ; t1 t3
+    psubd                m0, m3     ; ____ out0
+    paddd                m2, m3     ; out3 ____
+%endmacro
+
+INIT_YMM avx2
+cglobal inv_txfm_add_wht_wht_4x4_16bpc, 3, 7, 6, dst, stride, c, eob, bdmax
+    mova                xm0, [cq+16*0]
+    vinserti128          m0, [cq+16*2], 1
+    mova                xm1, [cq+16*1]
+    vinserti128          m1, [cq+16*3], 1
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    lea                  r6, [dstq+strideq*2]
+    psrad                m0, 2
+    psrad                m1, 2
+    IWHT4_1D_PACKED
+    punpckhdq            m0, m3
+    punpckldq            m3, m2
+    punpckhqdq           m1, m0, m3
+    punpcklqdq           m0, m3
+    IWHT4_1D_PACKED
+    vpblendd             m0, m2, 0x33
+    packssdw             m0, m3
+    vextracti128        xm2, m0, 1
+    punpckhdq           xm1, xm0, xm2 ; out2 out1
+    punpckldq           xm0, xm2      ; out3 out0
+    movq                xm2, [r6  +strideq*1]
+    movhps              xm2, [dstq+strideq*0]
+    movq                xm3, [r6  +strideq*0]
+    movhps              xm3, [dstq+strideq*1]
+%ifidn bdmaxd, bdmaxm
+    movd                xm5, bdmaxd
+    vpbroadcastw        xm5, xm5
+%else   ; win64: load from stack
+    vpbroadcastw        xm5, bdmaxm
+%endif
+    paddsw              xm0, xm2
+    paddsw              xm1, xm3
+    pmaxsw              xm0, xm4
+    pmaxsw              xm1, xm4
+    pminsw              xm0, xm5
+    pminsw              xm1, xm5
+    movhps [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm1
+    movq   [r6  +strideq*0], xm1
+    movq   [r6  +strideq*1], xm0
+    RET
+
+; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12
+; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12
+; flags: 1 = packed, 2 = inv_dst2
+; skip round/shift if rnd is not a number
+%macro ITX_MULSUB_2D 8-9 0 ; dst/src[1-2], tmp[1-3], rnd, coef[1-2], flags
+%if %8 < 32
+    pmulld              m%4, m%1, m%8
+    pmulld              m%3, m%2, m%8
+%else
+%if %9 & 1
+    vbroadcasti128      m%3, [pd_%8]
+%else
+    vpbroadcastd        m%3, [pd_%8]
+%endif
+    pmulld              m%4, m%1, m%3
+    pmulld              m%3, m%2
+%endif
+%if %7 < 32
+    pmulld              m%1, m%7
+    pmulld              m%2, m%7
+%else
+%if %9 & 1
+    vbroadcasti128      m%5, [pd_%7]
+%else
+    vpbroadcastd        m%5, [pd_%7]
+%endif
+    pmulld              m%1, m%5
+    pmulld              m%2, m%5
+%endif
+%if %9 & 2
+    psubd               m%4, m%6, m%4
+    psubd               m%2, m%4, m%2
+%else
+%ifnum %6
+    paddd               m%4, m%6
+%endif
+    paddd               m%2, m%4
+%endif
+%ifnum %6
+    paddd               m%1, m%6
+%endif
+    psubd               m%1, m%3
+%ifnum %6
+    psrad               m%2, 12
+    psrad               m%1, 12
+%endif
+%endmacro
+
+%macro INV_TXFM_FN 4-5 10 ; type1, type2, eob_offset, size, bitdepth
+cglobal inv_txfm_add_%1_%2_%4_%5bpc, 4, 5, 0, dst, stride, c, eob, tx2
+    %define %%p1 m(i%1_%4_internal_%5bpc)
+    ; Jump to the 1st txfm function if we're not taking the fast path, which
+    ; in turn performs an indirect jump to the 2nd txfm function.
+    lea tx2q, [m(i%2_%4_internal_%5bpc).pass2]
+%ifidn %1_%2, dct_dct
+    test               eobd, eobd
+    jnz %%p1
+%else
+%if %3
+    add                eobd, %3
+%endif
+    ; jump to the 1st txfm function unless it's located directly after this
+    times ((%%end - %%p1) >> 31) & 1 jmp %%p1
+ALIGN function_align
+%%end:
+%endif
+%endmacro
+
+%macro INV_TXFM_4X4_FN 2-3 10 ; type1, type2, bitdepth
+    INV_TXFM_FN          %1, %2, 0, 4x4, %3
+%ifidn %1_%2, dct_dct
+    vpbroadcastd        xm2, [dconly_%3bpc]
+%if %3 = 10
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 4
+.dconly2:
+    add                 r6d, 128
+    sar                 r6d, 8
+.dconly3:
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    movd                xm0, r6d
+    paddsw              xm0, xm2
+    vpbroadcastw        xm0, xm0
+.dconly_loop:
+    movq                xm1, [dstq+strideq*0]
+    movhps              xm1, [dstq+strideq*1]
+    paddsw              xm1, xm0
+    psubusw             xm1, xm2
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    WRAP_XMM RET
+%else
+    jmp m(inv_txfm_add_dct_dct_4x4_10bpc).dconly
+%endif
+%endif
+%endmacro
+
+%macro IDCT4_1D_PACKED 6 ; dst/src[1-2], tmp[1-3], rnd
+    ITX_MULSUB_2D        %1, %2, %3, %4, %5, %6, 2896_1567, 2896_3784, 1
+    punpckhqdq          m%3, m%2, m%1 ; t3 t2
+    punpcklqdq          m%2, m%1      ; t0 t1
+    paddd               m%1, m%2, m%3 ; out0 out1
+    psubd               m%2, m%3      ; out3 out2
+%endmacro
+
+%macro IDCT4_1D_PACKED_WORD 6 ; dst/src[1-2], tmp[1-3], rnd
+    vpbroadcastd        m%5, [pw_m3784_1567]
+    punpckhwd           m%3, m%2, m%1
+    vpbroadcastd        m%4, [pw_1567_3784]
+    punpcklwd           m%2, m%1
+    vpbroadcastd        m%1, [pw_m2896_2896]
+    pmaddwd             m%5, m%3
+    pmaddwd             m%3, m%4
+    vpbroadcastd        m%4, [pw_2896_2896]
+    pmaddwd             m%1, m%2
+    pmaddwd             m%2, m%4
+    REPX     {paddd x, m%6}, m%5, m%3, m%1, m%2
+    REPX     {psrad x, 12 }, m%5, m%3, m%1, m%2
+    packssdw            m%3, m%5      ; t3 t2
+    packssdw            m%2, m%1      ; t0 t1
+    paddsw              m%1, m%2, m%3 ; out0 out1
+    psubsw              m%2, m%3      ; out3 out2
+%endmacro
+
+INV_TXFM_4X4_FN dct, dct
+INV_TXFM_4X4_FN dct, identity
+INV_TXFM_4X4_FN dct, adst
+INV_TXFM_4X4_FN dct, flipadst
+
+cglobal idct_4x4_internal_10bpc, 0, 7, 6, dst, stride, c, eob, tx2
+    call .main
+    vbroadcasti128       m2, [idct4_shuf]
+    packssdw             m0, m1
+    pshufb               m0, m2
+    jmp                tx2q
+.pass2:
+    vextracti128        xm1, m0, 1
+    WRAP_XMM IDCT4_1D_PACKED_WORD 0, 1, 2, 3, 4, 5
+    packssdw            xm5, xm5 ; pw_2048
+    pmulhrsw            xm0, xm5
+    pmulhrsw            xm1, xm5
+    movq                xm2, [dstq+strideq*0]
+    movhps              xm2, [dstq+strideq*1]
+    lea                  r6, [dstq+strideq*2]
+    movq                xm3, [r6  +strideq*1]
+    movhps              xm3, [r6  +strideq*0]
+    vpbroadcastd        xm5, [pixel_10bpc_max]
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    paddw               xm0, xm2
+    paddw               xm1, xm3
+    pmaxsw              xm0, xm4
+    pmaxsw              xm1, xm4
+    pminsw              xm0, xm5
+    pminsw              xm1, xm5
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movhps [r6  +strideq*0], xm1
+    movq   [r6  +strideq*1], xm1
+    RET
+ALIGN function_align
+.main:
+    vpermq               m0, [cq+32*0], q3120
+    vpermq               m1, [cq+32*1], q3120
+    vpbroadcastd         m5, [pd_2048]
+.main2:
+    IDCT4_1D_PACKED       0, 1, 2, 3, 4, 5
+    ret
+
+INV_TXFM_4X4_FN adst, dct
+INV_TXFM_4X4_FN adst, adst
+INV_TXFM_4X4_FN adst, flipadst
+INV_TXFM_4X4_FN adst, identity
+
+%macro IADST4_1D 0
+    vpbroadcastd         m5, [pd_1321]
+    vpbroadcastd         m7, [pd_2482]
+    pmulld               m4, m0, m5    ; 1321*in0
+    pmulld               m6, m3, m7    ; 2482*in3
+    paddd                m4, m6        ; 1321*in0 + 2482*in3
+    pmulld               m6, m0, m7    ; 2482*in0
+    paddd                m0, m3        ; in0 + in3
+    paddd                m7, m5        ; pd_3803
+    pmulld               m5, m2        ; 1321*in2
+    pmulld               m3, m7        ; 3803*in3
+    pmulld               m7, m2        ; 3803*in2
+    psubd                m2, m0        ; in2 - in0 - in3
+    vpbroadcastd         m0, [pd_m3344]
+    pmulld               m1, m0        ; -t3
+    pmulld               m2, m0        ; out2 (unrounded)
+    psubd                m6, m5        ; 2482*in0 - 1321*in2
+    paddd                m4, m7        ;  t0
+    psubd                m6, m3        ;  t1
+    paddd                m3, m4, m6
+    psubd                m4, m1        ; out0 (unrounded)
+    psubd                m6, m1        ; out1 (unrounded)
+    paddd                m3, m1        ; out3 (unrounded)
+%endmacro
+
+cglobal iadst_4x4_internal_10bpc, 0, 7, 6, dst, stride, c, eob, tx2
+    call .main
+    vinserti128          m0, m4, xm6, 1
+    vinserti128          m1, m2, xm3, 1
+.pass1_end:
+    vpbroadcastd         m5, [pd_2048]
+    mova                 m2, [itx4_shuf]
+    paddd                m0, m5
+    paddd                m1, m5
+    psrad                m0, 12
+    psrad                m1, 12
+    packssdw             m0, m1
+    vpermd               m0, m2, m0
+    psrld                m2, 4
+    pshufb               m0, m2
+%if WIN64
+    movaps             xmm6, [rsp+ 8]
+    movaps             xmm7, [rsp+24]
+%endif
+    jmp                tx2q
+.pass2:
+    lea                  r6, [deint_shuf+128]
+    vextracti128        xm1, m0, 1
+    call m(iadst_4x4_internal_8bpc).main
+.end:
+    vpbroadcastd        xm4, [pw_2048]
+    movq                xm2, [dstq+strideq*0]
+    movhps              xm2, [dstq+strideq*1]
+    lea                  r6, [dstq+strideq*2]
+    movq                xm3, [r6  +strideq*0]
+    movhps              xm3, [r6  +strideq*1]
+    vpbroadcastd        xm5, [pixel_10bpc_max]
+    pmulhrsw            xm0, xm4
+    pmulhrsw            xm1, xm4
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    paddw               xm0, xm2
+    paddw               xm1, xm3
+    pmaxsw              xm0, xm4
+    pmaxsw              xm1, xm4
+    pminsw              xm0, xm5
+    pminsw              xm1, xm5
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [r6  +strideq*0], xm1
+    movhps [r6  +strideq*1], xm1
+    RET
+ALIGN function_align
+.main:
+    mova                xm0, [cq+16*0]
+    mova                xm1, [cq+16*1]
+    mova                xm2, [cq+16*2]
+    mova                xm3, [cq+16*3]
+%if WIN64
+    movaps         [rsp+16], xmm6
+    movaps         [rsp+32], xmm7
+%endif
+.main2:
+    WRAP_XMM IADST4_1D
+    ret
+
+INV_TXFM_4X4_FN flipadst, dct
+INV_TXFM_4X4_FN flipadst, adst
+INV_TXFM_4X4_FN flipadst, flipadst
+INV_TXFM_4X4_FN flipadst, identity
+
+cglobal iflipadst_4x4_internal_10bpc, 0, 7, 6, dst, stride, c, eob, tx2
+    call m(iadst_4x4_internal_10bpc).main
+    vinserti128          m0, m3, xm2, 1
+    vinserti128          m1, m6, xm4, 1
+    jmp m(iadst_4x4_internal_10bpc).pass1_end
+.pass2:
+    lea                  r6, [deint_shuf+128]
+    vextracti128        xm1, m0, 1
+    call m(iadst_4x4_internal_8bpc).main
+    vpbroadcastd        xm4, [pw_2048]
+    movq                xm3, [dstq+strideq*1]
+    movhps              xm3, [dstq+strideq*0]
+    lea                  r6, [dstq+strideq*2]
+    movq                xm2, [r6  +strideq*1]
+    movhps              xm2, [r6  +strideq*0]
+    vpbroadcastd        xm5, [pixel_10bpc_max]
+    pmulhrsw            xm0, xm4
+    pmulhrsw            xm1, xm4
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    paddw               xm0, xm2
+    paddw               xm1, xm3
+    pmaxsw              xm0, xm4
+    pmaxsw              xm1, xm4
+    pminsw              xm0, xm5
+    pminsw              xm1, xm5
+    movhps [dstq+strideq*0], xm1
+    movq   [dstq+strideq*1], xm1
+    movhps [r6  +strideq*0], xm0
+    movq   [r6  +strideq*1], xm0
+    RET
+
+INV_TXFM_4X4_FN identity, dct
+INV_TXFM_4X4_FN identity, adst
+INV_TXFM_4X4_FN identity, flipadst
+INV_TXFM_4X4_FN identity, identity
+
+cglobal iidentity_4x4_internal_10bpc, 0, 7, 6, dst, stride, c, eob, tx2
+    vpbroadcastd         m1, [pd_5793]
+    pmulld               m0, m1, [cq+32*0]
+    pmulld               m1,     [cq+32*1]
+    vpbroadcastd         m5, [pd_2048]
+    mova                 m3, [itx4_shuf]
+    paddd                m0, m5
+    paddd                m1, m5
+    psrad                m0, 12
+    psrad                m1, 12
+    packssdw             m0, m1
+    vpermd               m0, m3, m0
+    psrld                m3, 4
+    pshufb               m0, m3
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m1, [pw_1697x8]
+    movq                xm2, [dstq+strideq*0]
+    movhps              xm2, [dstq+strideq*1]
+    lea                  r6, [dstq+strideq*2]
+    pmulhrsw             m1, m0
+    paddsw               m0, m1
+    movq                xm3, [r6  +strideq*0]
+    movhps              xm3, [r6  +strideq*1]
+    vpbroadcastd        xm4, [pixel_10bpc_max]
+    packssdw             m5, m5 ; pw_2048
+    pmulhrsw             m0, m5
+    pxor                 m5, m5
+    mova          [cq+32*0], m5
+    mova          [cq+32*1], m5
+    vextracti128        xm1, m0, 1
+    paddw               xm0, xm2
+    paddw               xm1, xm3
+    pmaxsw              xm0, xm5
+    pmaxsw              xm1, xm5
+    pminsw              xm0, xm4
+    pminsw              xm1, xm4
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [r6  +strideq*0], xm1
+    movhps [r6  +strideq*1], xm1
+    RET
+
+INV_TXFM_4X4_FN dct, dct,      12
+INV_TXFM_4X4_FN dct, identity, 12
+INV_TXFM_4X4_FN dct, adst,     12
+INV_TXFM_4X4_FN dct, flipadst, 12
+
+cglobal idct_4x4_internal_12bpc, 0, 7, 8, dst, stride, c, eob, tx2
+    call m(idct_4x4_internal_10bpc).main
+    mova                 m3, [idct4_12_shuf]
+    mova                 m4, [idct4_12_shuf2]
+    vpermd               m2, m4, m1
+    vpermd               m1, m3, m0
+    jmp m(iadst_4x4_internal_12bpc).pass1_end2
+.pass2:
+    vpbroadcastd         m5, [pd_2048]
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q3120
+    call m(idct_4x4_internal_10bpc).main2
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    jmp m(iadst_4x4_internal_12bpc).end
+
+INV_TXFM_4X4_FN adst, dct,      12
+INV_TXFM_4X4_FN adst, adst,     12
+INV_TXFM_4X4_FN adst, flipadst, 12
+INV_TXFM_4X4_FN adst, identity, 12
+
+cglobal iadst_4x4_internal_12bpc, 0, 7, 8, dst, stride, c, eob, tx2
+    call m(iadst_4x4_internal_10bpc).main
+    vinserti128          m1, m4, xm6, 1
+    vinserti128          m2, xm3, 1
+.pass1_end:
+    mova                 m3, [itx4_shuf]
+    vpbroadcastd         m5, [pd_1024]
+    psrad                m1, 1
+    psrad                m2, 1
+    vpermd               m1, m3, m1
+    vpermd               m2, m3, m2
+    paddd                m1, m5
+    paddd                m2, m5
+    psrad                m1, 11
+    psrad                m2, 11
+.pass1_end2:
+    vpbroadcastd         m3, [clip_18b_min]
+    vpbroadcastd         m4, [clip_18b_max]
+    punpcklqdq           m0, m1, m2
+    punpckhqdq           m1, m2
+    pmaxsd               m0, m3
+    pmaxsd               m1, m3
+    pminsd               m0, m4
+    pminsd               m1, m4
+    jmp                tx2q
+.pass2:
+    call .main_pass2
+    vinserti128          m0, m4, xm6, 1
+    vinserti128          m1, m2, xm3, 1
+.pass2_end:
+    vpbroadcastd         m5, [pd_2048]
+    paddd                m0, m5
+    paddd                m1, m5
+    psrad                m0, 12
+    psrad                m1, 12
+.end:
+%if WIN64
+    WIN64_RESTORE_XMM_INTERNAL
+    %assign xmm_regs_used 6
+%endif
+.end2:
+    vpbroadcastd         m4, [pw_16384]
+    movq                xm2, [dstq+strideq*0]
+    movq                xm3, [dstq+strideq*1]
+    lea                  r6, [dstq+strideq*2]
+    movhps              xm2, [r6  +strideq*0]   ; dst0 dst2
+    movhps              xm3, [r6  +strideq*1]   ; dst1 dst3
+    vpbroadcastd         m5, [pixel_12bpc_max]
+    vinserti128          m2, xm3, 1
+    psrad                m0, 3
+    psrad                m1, 3
+    packssdw             m0, m1     ; t0 t2 t1 t3
+    pmulhrsw             m0, m4
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    paddw                m0, m2     ; out0 out2 out1 out3
+    pmaxsw               m0, m4
+    pminsw               m0, m5
+    vextracti128        xm1, m0, 1  ; out1 out3
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [r6  +strideq*0], xm0
+    movhps [r6  +strideq*1], xm1
+    RET
+.main_pass2:
+    vextracti128        xm3, m1, 1
+    mova                xm2, xm1
+    vextracti128        xm1, m0, 1
+    jmp m(iadst_4x4_internal_10bpc).main2
+
+INV_TXFM_4X4_FN flipadst, dct,      12
+INV_TXFM_4X4_FN flipadst, adst,     12
+INV_TXFM_4X4_FN flipadst, flipadst, 12
+INV_TXFM_4X4_FN flipadst, identity, 12
+
+cglobal iflipadst_4x4_internal_12bpc, 0, 7, 8, dst, stride, c, eob, tx2
+    call m(iadst_4x4_internal_10bpc).main
+    vinserti128          m1, m3, xm2, 1
+    vinserti128          m2, m6, xm4, 1
+    jmp m(iadst_4x4_internal_12bpc).pass1_end
+.pass2:
+    call m(iadst_4x4_internal_12bpc).main_pass2
+    vinserti128          m0, m3, xm2, 1
+    vinserti128          m1, m6, xm4, 1
+    jmp m(iadst_4x4_internal_12bpc).pass2_end
+
+INV_TXFM_4X4_FN identity, dct,      12
+INV_TXFM_4X4_FN identity, adst,     12
+INV_TXFM_4X4_FN identity, flipadst, 12
+INV_TXFM_4X4_FN identity, identity, 12
+
+cglobal iidentity_4x4_internal_12bpc, 0, 7, 8, dst, stride, c, eob, tx2
+    mova                 m2, [itx4_shuf]
+    vpbroadcastd         m3, [pd_1697]
+    vpermd               m0, m2, [cq+32*0]
+    vpermd               m2, m2, [cq+32*1]
+    vpbroadcastd         m5, [pd_2048]
+    pmulld               m1, m3, m0
+    pmulld               m3, m2
+    paddd                m1, m5
+    paddd                m3, m5
+    psrad                m1, 12
+    psrad                m3, 12
+    paddd                m1, m0
+    paddd                m2, m3
+    jmp m(iadst_4x4_internal_12bpc).pass1_end2
+.pass2:
+    ; m0 = in0 in1
+    ; m1 = in2 in3
+    vpbroadcastd         m3, [pd_5793]
+    vpbroadcastd         m5, [pd_2048]
+    pmulld               m0, m3
+    pmulld               m1, m3
+    paddd                m0, m5 ; 2048
+    paddd                m1, m5
+    psrad                m0, 12
+    psrad                m1, 12
+    jmp m(iadst_4x4_internal_12bpc).end
+
+%macro INV_TXFM_4X8_FN 2-3 10 ; type1, type2, bitdepth
+    INV_TXFM_FN          %1, %2, 0, 4x8, %3
+%ifidn %1_%2, dct_dct
+    vpbroadcastd        xm2, [dconly_%3bpc]
+%if %3 = 10
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 8
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    jmp m(inv_txfm_add_dct_dct_4x4_10bpc).dconly2
+%else
+    jmp m(inv_txfm_add_dct_dct_4x8_10bpc).dconly
+%endif
+%endif
+%endmacro
+
+%macro IDCT4_1D 8 ; src[1-4], tmp[1-3], rnd
+    ITX_MULSUB_2D        %2, %4, %5, %6, %7, %8, 1567, 3784 ; t2, t3
+    vpbroadcastd        m%5, [pd_2896]
+    pmulld              m%1, m%5
+    pmulld              m%3, m%5
+    paddd               m%1, m%8
+    paddd               m%5, m%1, m%3
+    psubd               m%1, m%3
+    psrad               m%5, 12 ; t0
+    psrad               m%1, 12 ; t1
+    psubd               m%3, m%1, m%2
+    paddd               m%2, m%1
+    paddd               m%1, m%5, m%4
+    psubd               m%4, m%5, m%4
+%endmacro
+
+INV_TXFM_4X8_FN dct, dct
+INV_TXFM_4X8_FN dct, identity
+INV_TXFM_4X8_FN dct, adst
+INV_TXFM_4X8_FN dct, flipadst
+
+cglobal idct_4x8_internal_10bpc, 0, 7, 8, dst, stride, c, eob, tx2
+.pass1:
+    vpbroadcastd         m3, [pd_2896]
+    pmulld               m0, m3, [cq+32*0]
+    pmulld               m1, m3, [cq+32*1]
+    pmulld               m2, m3, [cq+32*2]
+    pmulld               m3, m3, [cq+32*3]
+    vpbroadcastd         m7, [pd_2048]
+    REPX      {paddd x, m7}, m0, m1, m2, m3
+    REPX      {psrad x, 12}, m0, m1, m2, m3
+    IDCT4_1D              0, 1, 2, 3, 4, 5, 6, 7
+    jmp                tx2q
+.pass2:
+    packssdw             m0, m2
+    packssdw             m1, m3
+    lea                  r6, [deint_shuf+128]
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhdq            m1, m0, m2 ; 2 3
+    punpckldq            m0, m2     ; 0 1
+    vextracti128        xm2, m0, 1  ; 4 5
+    vextracti128        xm3, m1, 1  ; 6 7
+    call m(idct_4x8_internal_8bpc).main
+    vpbroadcastd        xm4, [pw_2048]
+    REPX  {pmulhrsw x, xm4}, xm0, xm1, xm2, xm3
+    lea                  r3, [strideq*3]
+    lea                  r6, [dstq+strideq*4]
+    movq                xm4, [dstq+strideq*0]
+    movhps              xm4, [dstq+strideq*1]
+    movq                xm5, [dstq+r3       ]
+    movhps              xm5, [dstq+strideq*2]
+    movq                xm6, [r6  +strideq*0]
+    movhps              xm6, [r6  +strideq*1]
+    movq                xm7, [r6  +r3       ]
+    movhps              xm7, [r6  +strideq*2]
+    paddw               xm0, xm4 ; 0 1
+    paddw               xm1, xm5 ; 3 2
+    paddw               xm2, xm6 ; 4 5
+    paddw               xm3, xm7 ; 7 6
+    vpbroadcastd        xm5, [pixel_10bpc_max]
+    pxor                 m4, m4
+    REPX {mova [cq+32*x], m4}, 0, 1, 2, 3
+    REPX    {pmaxsw x, xm4}, xm0, xm1, xm2, xm3
+    REPX    {pminsw x, xm5}, xm0, xm1, xm2, xm3
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movhps [dstq+strideq*2], xm1
+    movq   [dstq+r3       ], xm1
+    movq   [r6  +strideq*0], xm2
+    movhps [r6  +strideq*1], xm2
+    movhps [r6  +strideq*2], xm3
+    movq   [r6  +r3       ], xm3
+    RET
+
+INV_TXFM_4X8_FN adst, dct
+INV_TXFM_4X8_FN adst, adst
+INV_TXFM_4X8_FN adst, flipadst
+INV_TXFM_4X8_FN adst, identity
+
+cglobal iadst_4x8_internal_10bpc, 0, 7, 8, dst, stride, c, eob, tx2
+    call m(iadst_8x4_internal_10bpc).main
+    vpbroadcastd         m5, [pd_2048]
+    paddd                m0, m5, m4
+    paddd                m1, m5, m6
+    paddd                m2, m5
+    paddd                m3, m5
+.pass1_end:
+    REPX      {psrad x, 12}, m0, m1, m2, m3
+    jmp                tx2q
+.pass2:
+    call .pass2_main
+    mova                xm4, [pw_2048_m2048]
+    REPX  {pmulhrsw x, xm4}, xm0, xm1, xm2, xm3
+.end:
+    lea                  r3, [strideq*3]
+    lea                  r6, [dstq+strideq*4]
+    movq                xm4, [dstq+strideq*0]
+    movhps              xm4, [dstq+strideq*1]
+    movq                xm5, [dstq+strideq*2]
+    movhps              xm5, [dstq+r3       ]
+    movq                xm6, [r6  +strideq*0]
+    movhps              xm6, [r6  +strideq*1]
+    movq                xm7, [r6  +strideq*2]
+    movhps              xm7, [r6  +r3       ]
+    paddw               xm0, xm4 ; 0 1
+    paddw               xm1, xm5 ; 2 3
+    paddw               xm2, xm6 ; 4 5
+    paddw               xm3, xm7 ; 6 7
+    vpbroadcastd        xm5, [pixel_10bpc_max]
+    pxor                 m4, m4
+    REPX {mova [cq+32*x], m4}, 0, 1, 2, 3
+    REPX    {pmaxsw x, xm4}, xm0, xm1, xm2, xm3
+    REPX    {pminsw x, xm5}, xm0, xm1, xm2, xm3
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r3       ], xm1
+    movq   [r6  +strideq*0], xm2
+    movhps [r6  +strideq*1], xm2
+    movq   [r6  +strideq*2], xm3
+    movhps [r6  +r3       ], xm3
+    RET
+ALIGN function_align
+.pass2_main:
+    packssdw             m0, m2
+    packssdw             m1, m3
+    lea                  r6, [deint_shuf+128]
+    punpcklwd            m4, m0, m1
+    punpckhwd            m0, m1
+    punpckhdq            m5, m4, m0
+    punpckldq            m4, m0
+    vextracti128        xm2, m4, 1      ; 4 5
+    vextracti128        xm3, m5, 1      ; 6 7
+    pshufd              xm4, xm4, q1032 ; 1 0
+    pshufd              xm5, xm5, q1032 ; 3 2
+    jmp m(iadst_4x8_internal_8bpc).main_pass2
+ALIGN function_align
+.main:
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+.main2:
+    vbroadcasti128       m0, [cq+16*0]
+    vbroadcasti128       m2, [cq+16*2]
+    vbroadcasti128       m3, [cq+16*5]
+    vbroadcasti128       m1, [cq+16*7]
+    vpbroadcastd         m6, [pd_2896]
+    shufpd               m0, m2, 0x0c ; 0 2
+    shufpd               m1, m3, 0x0c ; 7 5
+    vbroadcasti128       m2, [cq+16*4]
+    vbroadcasti128       m4, [cq+16*6]
+    vbroadcasti128       m5, [cq+16*1]
+    vbroadcasti128       m3, [cq+16*3]
+    vpbroadcastd         m7, [pd_2048]
+    shufpd               m2, m4, 0x0c ; 4 6
+    shufpd               m3, m5, 0x0c ; 3 1
+    REPX {pmulld x, m6}, m0, m1, m2, m3
+    REPX {paddd  x, m7}, m0, m1, m2, m3
+    REPX {psrad  x, 12}, m0, m1, m2, m3
+.main3:
+    ITX_MULSUB_2D         1, 0, 4, 5, 6, 7,  401_1931, 4076_3612, 1
+    ITX_MULSUB_2D         3, 2, 4, 5, 6, 7, 3166_3920, 2598_1189, 1
+    psubd                m4, m0, m2   ; t4  t6
+    paddd                m0, m2       ; t0  t2
+    psubd                m2, m1, m3   ; t5  t7
+    paddd                m1, m3       ; t1  t3
+    REPX     {pmaxsd x, m8}, m4, m2, m0, m1
+    REPX     {pminsd x, m9}, m4, m2, m0, m1
+    pxor                 m5, m5
+    psubd                m5, m4
+    vpblendd             m4, m2, 0xcc ; t4  t7
+    vpblendd             m2, m5, 0xcc ; t5 -t6
+    ITX_MULSUB_2D         4, 2, 3, 5, 6, 7, 1567, 3784
+    vpbroadcastd         m5, [pd_2896]
+    vbroadcasti128       m6, [pw_2048_m2048] ; + + - -
+    punpckhqdq           m3, m0, m1
+    punpcklqdq           m0, m1
+    psubd                m1, m0, m3   ; t2  t3
+    paddd                m0, m3       ;  out0 -out7
+    punpckhqdq           m3, m4, m2   ; t7a t6a
+    punpcklqdq           m4, m2       ; t5a t4a
+    psubd                m2, m4, m3   ; t7  t6
+    paddd                m4, m3       ;  out6 -out1
+    REPX     {pmaxsd x, m8}, m1, m2
+    REPX     {pminsd x, m9}, m1, m2
+    vpblendd             m3, m1, m2, 0xcc
+    shufpd               m1, m2, 0x05
+    pmulld               m3, m5
+    pmulld               m5, m1
+    psignd               m0, m6       ;  out0  out7
+    psignd               m4, m6       ;  out6  out1
+    paddd                m3, m7
+    psubd                m2, m3, m5
+    paddd                m5, m3
+    psrad                m2, 12       ;  out4 -out5
+    psrad                m5, 12       ; -out3  out2
+    ret
+
+INV_TXFM_4X8_FN flipadst, dct
+INV_TXFM_4X8_FN flipadst, adst
+INV_TXFM_4X8_FN flipadst, flipadst
+INV_TXFM_4X8_FN flipadst, identity
+
+cglobal iflipadst_4x8_internal_10bpc, 0, 7, 8, dst, stride, c, eob, tx2
+    call m(iadst_8x4_internal_10bpc).main
+    vpbroadcastd         m5, [pd_2048]
+    paddd                m0, m5, m3
+    paddd                m1, m5, m2
+    paddd                m2, m5, m6
+    paddd                m3, m5, m4
+    jmp m(iadst_4x8_internal_10bpc).pass1_end
+.pass2:
+    call m(iadst_4x8_internal_10bpc).pass2_main
+    mova                xm4, [pw_2048_m2048]
+    REPX  {pmulhrsw x, xm4}, xm3, xm2, xm1, xm0
+    lea                  r3, [strideq*3]
+    lea                  r6, [dstq+strideq*4]
+    movq                xm4, [dstq+strideq*1]
+    movhps              xm4, [dstq+strideq*0]
+    movq                xm5, [dstq+r3       ]
+    movhps              xm5, [dstq+strideq*2]
+    movq                xm6, [r6  +strideq*1]
+    movhps              xm6, [r6  +strideq*0]
+    movq                xm7, [r6  +r3       ]
+    movhps              xm7, [r6  +strideq*2]
+    paddw               xm3, xm4 ; 1 0
+    paddw               xm2, xm5 ; 3 2
+    paddw               xm1, xm6 ; 5 4
+    paddw               xm0, xm7 ; 7 6
+    vpbroadcastd        xm5, [pixel_10bpc_max]
+    pxor                 m4, m4
+    REPX {mova [cq+32*x], m4}, 0, 1, 2, 3
+    REPX    {pmaxsw x, xm4}, xm3, xm2, xm1, xm0
+    REPX    {pminsw x, xm5}, xm3, xm2, xm1, xm0
+    movhps [dstq+strideq*0], xm3
+    movq   [dstq+strideq*1], xm3
+    movhps [dstq+strideq*2], xm2
+    movq   [dstq+r3       ], xm2
+    movhps [r6  +strideq*0], xm1
+    movq   [r6  +strideq*1], xm1
+    movhps [r6  +strideq*2], xm0
+    movq   [r6  +r3       ], xm0
+    RET
+
+INV_TXFM_4X8_FN identity, dct
+INV_TXFM_4X8_FN identity, adst
+INV_TXFM_4X8_FN identity, flipadst
+INV_TXFM_4X8_FN identity, identity
+
+cglobal iidentity_4x8_internal_10bpc, 0, 7, 8, dst, stride, c, eob, tx2
+.pass1:
+    vpbroadcastd         m3, [pd_2896]
+    pmulld               m0, m3, [cq+32*0]
+    pmulld               m1, m3, [cq+32*1]
+    pmulld               m2, m3, [cq+32*2]
+    pmulld               m3,     [cq+32*3]
+    vpbroadcastd         m5, [pd_2048]
+    vpbroadcastd         m4, [pd_5793]
+    REPX     {paddd  x, m5}, m0, m1, m2, m3
+    REPX     {psrad  x, 12}, m0, m1, m2, m3
+    REPX     {pmulld x, m4}, m0, m1, m2, m3
+    REPX     {paddd  x, m5}, m0, m1, m2, m3
+    REPX     {psrad  x, 12}, m0, m1, m2, m3
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m6, [pixel_10bpc_max]
+    call .pass2_end
+    RET
+ALIGN function_align
+.pass2_end:
+    vpbroadcastd         m4, [pw_4096]
+    packssdw             m0, m2
+    packssdw             m1, m3
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    pmulhrsw             m2, m4
+    pmulhrsw             m0, m4
+    punpckhdq            m1, m0, m2 ; 2 3 6 7
+    punpckldq            m0, m2     ; 0 1 4 5
+    lea                  r3, [strideq*3]
+    lea                  r6, [dstq+strideq*4]
+    movq                xm2, [dstq+strideq*0]
+    movhps              xm2, [dstq+strideq*1]
+    vpbroadcastq         m4, [r6  +strideq*0]
+    vpbroadcastq         m5, [r6  +strideq*1]
+    movq                xm3, [dstq+strideq*2]
+    movhps              xm3, [dstq+r3       ]
+    vpblendd             m2, m4, 0x30
+    vpblendd             m2, m5, 0xc0
+    vpbroadcastq         m4, [r6  +strideq*2]
+    vpbroadcastq         m5, [r6  +r3       ]
+    vpblendd             m3, m4, 0x30
+    vpblendd             m3, m5, 0xc0
+    pxor                 m4, m4
+    REPX {mova [cq+32*x], m4}, 0, 1, 2, 3
+    paddw                m0, m2 ; out0 out1 out4 out5
+    paddw                m1, m3 ; out2 out3 out6 out7
+    pmaxsw               m0, m4
+    pmaxsw               m1, m4
+    pminsw               m0, m6
+    pminsw               m1, m6
+    vextracti128        xm2, m0, 1  ; out4 out5
+    vextracti128        xm3, m1, 1  ; out6 out7
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r3       ], xm1
+    movq   [r6  +strideq*0], xm2
+    movhps [r6  +strideq*1], xm2
+    movq   [r6  +strideq*2], xm3
+    movhps [r6  +r3       ], xm3
+    ret
+
+INV_TXFM_4X8_FN dct, dct,      12
+INV_TXFM_4X8_FN dct, identity, 12
+INV_TXFM_4X8_FN dct, adst,     12
+INV_TXFM_4X8_FN dct, flipadst, 12
+
+cglobal idct_4x8_internal_12bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    jmp m(idct_4x8_internal_10bpc).pass1
+.pass2:
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+    REPX     {pmaxsd x, m8}, m0, m1, m2, m3
+    REPX     {pminsd x, m9}, m0, m1, m2, m3
+    ; transpose & interleave
+    pshufd               m0, m0, q1320
+    pshufd               m1, m1, q1320
+    pshufd               m2, m2, q1320
+    pshufd               m3, m3, q1320
+    punpckldq            m4, m0, m1
+    punpckhdq            m0, m1
+    punpckldq            m5, m2, m3
+    punpckhdq            m2, m3
+    vpermq               m0, m0, q3102
+    vpermq               m2, m2, q3102
+    vperm2i128           m1, m0, m2, 0x31   ; 1 5 (interleaved)
+    vperm2i128           m3, m0, m2, 0x20   ; 7 3 (interleaved)
+    vperm2i128           m0, m4, m5, 0x20   ; 0 2 (interleaved)
+    vperm2i128           m2, m4, m5, 0x31   ; 4 6 (interleaved)
+    vpbroadcastd         m7, [pd_2048]
+    call m(idct_8x4_internal_10bpc).main
+    psubd                m3, m0, m4  ; out7 out6
+    paddd                m0, m4      ; out0 out1
+    paddd                m1, m2, m5  ; out3 out2
+    psubd                m2, m5      ; out4 out5
+    pshufd               m1, m1, q1032
+    pshufd               m3, m3, q1032
+    jmp m(iadst_4x8_internal_12bpc).end
+
+INV_TXFM_4X8_FN adst, dct,      12
+INV_TXFM_4X8_FN adst, adst,     12
+INV_TXFM_4X8_FN adst, flipadst, 12
+INV_TXFM_4X8_FN adst, identity, 12
+
+cglobal iadst_4x8_internal_12bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    call m(iadst_8x4_internal_10bpc).main
+    psrad                m0, m4, 1
+    psrad                m1, m6, 1
+    psrad                m2, 1
+    psrad                m3, 1
+.pass1_end:
+    vpbroadcastd         m5, [pd_1024]
+    REPX      {paddd x, m5}, m0, m1, m2, m3
+    REPX      {psrad x, 11}, m0, m1, m2, m3
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+    REPX     {pmaxsd x, m8}, m0, m1, m2, m3
+    REPX     {pminsd x, m9}, m0, m1, m2, m3
+    call .pass2_main
+    vpblendd             m3, m0, m4, 0x33 ; out6 out7
+    vpblendd             m0, m4, 0xcc     ; out0 out1
+    pshufd               m1, m5, q1032
+    psignd               m2, m6           ; out4 out5
+    psignd               m1, m6           ; out2 out3
+.end:
+    vpbroadcastd         m4, [pw_16384]
+    REPX       {psrad x, 3}, m0, m1, m2, m3
+    packssdw             m0, m2     ; 0 1 4 5 (interleaved)
+    packssdw             m1, m3     ; 2 3 6 7 (interleaved)
+    mova                 m2, [iadst8_12_shuf]
+    vpermd               m0, m2, m0 ; 0 1 4 5
+    vpermd               m1, m2, m1 ; 2 3 6 7
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    lea                  r3, [strideq*3]
+    lea                  r6, [dstq+strideq*4]
+    movq                xm4, [dstq+strideq*0]
+    movhps              xm4, [dstq+strideq*1]
+    movq                xm5, [dstq+strideq*2]
+    movhps              xm5, [dstq+r3       ]
+    movq                xm6, [r6  +strideq*0]
+    movhps              xm6, [r6  +strideq*1]
+    vinserti128          m4, xm6, 1
+    movq                xm7, [r6  +strideq*2]
+    movhps              xm7, [r6  +r3       ]
+    vinserti128          m5, xm7, 1
+    paddw                m0, m4 ; 0 1 4 5
+    paddw                m1, m5 ; 2 3 6 7
+    vpbroadcastd         m5, [pixel_12bpc_max]
+    pxor                 m4, m4
+    REPX {mova [cq+32*x], m4}, 0, 1, 2, 3
+    REPX    {pmaxsw x,  m4}, m0, m1
+    REPX    {pminsw x,  m5}, m0, m1
+    vextracti128        xm2, m0, 1  ; out4 out5
+    vextracti128        xm3, m1, 1  ; out6 out7
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+r3       ], xm1
+    movq   [r6  +strideq*0], xm2
+    movhps [r6  +strideq*1], xm2
+    movq   [r6  +strideq*2], xm3
+    movhps [r6  +r3       ], xm3
+    RET
+ALIGN function_align
+.pass2_main:
+    ; transpose & interleave
+    pshufd               m0, m0, q1320
+    pshufd               m1, m1, q1320
+    pshufd               m2, m2, q1320
+    pshufd               m3, m3, q1320
+    punpckldq            m4, m0, m1
+    punpckhdq            m0, m1
+    punpckldq            m5, m2, m3
+    punpckhdq            m2, m3
+    vperm2i128           m1, m0, m2, 0x31   ; 7 5 (interleaved)
+    vperm2i128           m3, m0, m2, 0x20   ; 3 1 (interleaved)
+    vperm2i128           m0, m4, m5, 0x20   ; 0 2 (interleaved)
+    vperm2i128           m2, m4, m5, 0x31   ; 4 6 (interleaved)
+    vpbroadcastd         m7, [pd_2048]
+    jmp m(iadst_4x8_internal_10bpc).main3
+
+INV_TXFM_4X8_FN flipadst, dct,      12
+INV_TXFM_4X8_FN flipadst, adst,     12
+INV_TXFM_4X8_FN flipadst, flipadst, 12
+INV_TXFM_4X8_FN flipadst, identity, 12
+
+cglobal iflipadst_4x8_internal_12bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    call m(iadst_8x4_internal_10bpc).main
+    psrad                m0, m3, 1
+    psrad                m1, m2, 1
+    psrad                m2, m6, 1
+    psrad                m3, m4, 1
+    jmp m(iadst_4x8_internal_12bpc).pass1_end
+.pass2:
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+    REPX     {pmaxsd x, m8}, m0, m1, m2, m3
+    REPX     {pminsd x, m9}, m0, m1, m2, m3
+    call m(iadst_4x8_internal_12bpc).pass2_main
+    shufpd               m3, m4, m0, 0x05 ; out1 out0
+    shufpd               m0, m4, 0x05     ; out7 out6
+    psignd               m2, m6
+    pshufd               m6, m6, q1032
+    pshufd               m1, m2, q1032    ; out5 out4
+    psignd               m2, m5, m6       ; out3 out2
+    jmp m(iadst_4x8_internal_12bpc).end
+
+INV_TXFM_4X8_FN identity, dct,      12
+INV_TXFM_4X8_FN identity, adst,     12
+INV_TXFM_4X8_FN identity, flipadst, 12
+INV_TXFM_4X8_FN identity, identity, 12
+
+cglobal iidentity_4x8_internal_12bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    jmp m(iidentity_4x8_internal_10bpc).pass1
+.pass2:
+    ; m0 = in0 in1
+    ; m1 = in2 in3
+    ; m2 = in4 in5
+    ; m3 = in6 in7
+    vpbroadcastd         m6, [pixel_12bpc_max]
+    call m(iidentity_4x8_internal_10bpc).pass2_end
+    RET
+
+%macro INV_TXFM_4X16_FN 2-3 10 ; type1, type2, bitdepth
+    INV_TXFM_FN          %1, %2, 0, 4x16, %3
+%ifidn %1_%2, dct_dct
+    imul                r6d, [cq], 181
+    vpbroadcastd        xm2, [dconly_%3bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 16
+    add                 r6d, 384
+    sar                 r6d, 9
+    jmp m(inv_txfm_add_dct_dct_4x4_10bpc).dconly3
+%endif
+%endmacro
+
+INV_TXFM_4X16_FN dct, dct
+INV_TXFM_4X16_FN dct, identity
+INV_TXFM_4X16_FN dct, adst
+INV_TXFM_4X16_FN dct, flipadst
+
+cglobal idct_4x16_internal_10bpc, 0, 7, 11, dst, stride, c, eob, tx2
+.pass1:
+    vpbroadcastd        m10, [pd_3072]
+    mova                 m1, [cq+32*2]
+    mova                 m3, [cq+32*6]
+    mova                 m5, [cq+32*3]
+    mova                 m7, [cq+32*7]
+    call .pass1_main
+    pmulld               m0, m6, [cq+32*0]
+    pmulld               m2, m6, [cq+32*4]
+    pmulld               m4, m6, [cq+32*1]
+    pmulld               m6,     [cq+32*5]
+    call .pass1_main2
+    REPX       {psrad x, 1}, m0, m1, m2, m3, m4, m5, m6, m7
+    jmp                tx2q
+.pass2:
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    lea                  r6, [deint_shuf+128]
+    punpcklwd            m4, m2, m3
+    punpckhwd            m2, m3
+    punpckhwd            m5, m0, m1
+    punpcklwd            m0, m1
+    punpckhdq            m1, m0, m4     ; 2 3
+    punpckldq            m0, m4         ; 0 1
+    punpckldq            m4, m5, m2     ; 8 9
+    punpckhdq            m5, m2         ; a b
+    vextracti128        xm2, m0, 1      ; 4 5
+    vextracti128        xm3, m1, 1      ; 6 7
+    vextracti128        xm6, m4, 1      ; c d
+    vextracti128        xm7, m5, 1      ; e f
+    call m(idct_4x16_internal_8bpc).main
+    vpbroadcastd         m9, [pw_2048]
+    vinserti128          m0, m0, xm1, 1 ; 0 1   3 2
+    vinserti128          m1, m2, xm3, 1 ; 4 5   7 6
+    vinserti128          m2, m4, xm5, 1 ; 8 9   b a
+    vinserti128          m3, m6, xm7, 1 ; c d   f e
+    vpbroadcastd         m8, [pixel_10bpc_max]
+    call .pass2_end
+    RET
+ALIGN function_align
+.pass1_main:
+    vpbroadcastd         m4, [pd_3784]
+    vpbroadcastd         m8, [pd_1567]
+    vpbroadcastd         m9, [pd_2048]
+    vpbroadcastd         m6, [pd_1448]
+    ITX_MULSUB_2D         1, 3, 0, 2, _, 9, 8, 4 ; t2l, t3l
+    ITX_MULSUB_2D         5, 7, 4, 2, _, 9, 8, 4 ; t2h, t3h
+    ret
+ALIGN function_align
+.pass1_main2:
+    paddd                m0, m10
+    paddd                m4, m10
+    paddd                m8, m0, m2
+    psubd                m0, m2
+    paddd                m9, m4, m6
+    psubd                m4, m6
+    REPX      {psrad x, 11}, m8, m0, m9, m4 ; t0l, t1l, t0h, t1h
+    psubd                m2, m0, m1
+    paddd                m1, m0
+    psubd                m6, m4, m5
+    paddd                m5, m4
+    paddd                m0, m8, m3
+    psubd                m3, m8, m3
+    paddd                m4, m9, m7
+    psubd                m7, m9, m7
+    ret
+ALIGN function_align
+.pass2_end:
+    lea                  r6, [strideq*3]
+    pxor                 m7, m7
+    pmulhrsw             m0, m9
+    call .write_4x4
+    pmulhrsw             m0, m1, m9
+    call .write_4x4
+    pmulhrsw             m0, m2, m9
+    call .write_4x4
+    pmulhrsw             m0, m3, m9
+    call .write_4x4
+    ret
+ALIGN function_align
+.write_4x4:
+    movq                xm4, [dstq+strideq*0]
+    movhps              xm4, [dstq+strideq*1]
+    vpbroadcastq         m5, [dstq+strideq*2]
+    vpbroadcastq         m6, [dstq+r6       ]
+    mova          [cq+32*0], m7
+    mova          [cq+32*1], m7
+    add                  cq, 32*2
+    vpblendd             m4, m5, 0xc0
+    vpblendd             m4, m6, 0x30
+    paddw                m4, m0
+    pmaxsw               m4, m7
+    pminsw               m4, m8
+    vextracti128        xm5, m4, 1
+    movq   [dstq+strideq*0], xm4
+    movhps [dstq+strideq*1], xm4
+    movhps [dstq+strideq*2], xm5
+    movq   [dstq+r6       ], xm5
+    lea                dstq, [dstq+strideq*4]
+    ret
+
+INV_TXFM_4X16_FN adst, dct
+INV_TXFM_4X16_FN adst, adst
+INV_TXFM_4X16_FN adst, flipadst
+INV_TXFM_4X16_FN adst, identity
+
+cglobal iadst_4x16_internal_10bpc, 0, 7, 11, dst, stride, c, eob, tx2
+    call m(iadst_16x4_internal_10bpc).main
+    vpbroadcastd         m6, [pd_6144]
+    call m(iadst_16x4_internal_10bpc).main_end
+    psrad                m0, m4, 13
+    psrad                m1, m5, 13
+    psrad                m2, 13
+    psrad                m3, 13
+    psrad                m4, m8, 13
+    psrad                m5, m9, 13
+    psrad                m6, 13
+    psrad                m7, 13
+    jmp                tx2q
+.pass2:
+    call .pass2_main
+    vpbroadcastd         m5, [pw_2048]
+    vpbroadcastd         m8, [pixel_10bpc_max]
+    lea                  r6, [strideq*3]
+    vpblendd             m4, m3, m0, 0xcc ; -out3   out0   out2  -out1
+    pshufd               m2, m2, q1032    ; -out11  out8   out10 -out9
+    vpblendd             m3, m0, 0x33     ; -out15  out12  out14 -out13
+    pxor                 m7, m7
+    psubw                m9, m7, m5
+    vpblendd             m9, m5, 0x3c     ; -2048   2048   2048  -2048
+    pmulhrsw             m0, m4, m9
+    call .write_4x4
+    pmulhrsw             m0, m1, m9
+    call .write_4x4
+    pmulhrsw             m0, m2, m9
+    call .write_4x4
+    pmulhrsw             m0, m3, m9
+    call .write_4x4
+    RET
+ALIGN function_align
+.write_4x4:
+    movq                xm4, [dstq+r6       ]
+    movhps              xm4, [dstq+strideq*0]
+    vpbroadcastq         m5, [dstq+strideq*1]
+    vpbroadcastq         m6, [dstq+strideq*2]
+    mova          [cq+32*0], m7
+    mova          [cq+32*1], m7
+    add                  cq, 32*2
+    vpblendd             m4, m5, 0xc0
+    vpblendd             m4, m6, 0x30
+    paddw                m4, m0
+    pmaxsw               m4, m7
+    pminsw               m4, m8
+    vextracti128        xm5, m4, 1
+    movhps [dstq+strideq*0], xm4
+    movhps [dstq+strideq*1], xm5
+    movq   [dstq+strideq*2], xm5
+    movq   [dstq+r6       ], xm4
+    lea                dstq, [dstq+strideq*4]
+    ret
+ALIGN function_align
+.pass2_main:
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    lea                  r6, [deint_shuf+128]
+    punpcklwd            m4, m2, m3
+    punpckhwd            m2, m3
+    punpckhwd            m5, m0, m1
+    punpcklwd            m0, m1
+    punpckhdq            m1, m0, m4
+    punpckldq            m0, m4
+    punpckldq            m4, m5, m2
+    punpckhdq            m5, m2
+    vpblendd             m3, m0, m1, 0x33
+    vpblendd             m0, m1, 0xcc
+    shufpd               m2, m5, m4, 0x05
+    shufpd               m4, m5, 0x05
+    vperm2i128           m1, m0, m3, 0x31 ; 4 7   6 5
+    vinserti128          m0, xm3, 1       ; 0 3   2 1
+    vperm2i128           m3, m2, m4, 0x31 ; c f   e d ; ????
+    vinserti128          m2, xm4, 1       ; b 8   9 a
+    call m(iadst_4x16_internal_8bpc).main2
+    vpbroadcastd         m5, [pw_2896x8]
+    paddsw               m1, m2, m4
+    psubsw               m2, m4
+    pmulhrsw             m1, m5           ; -out7   out4   out6  -out5
+    pmulhrsw             m2, m5           ;  out8  -out11 -out9   out10
+    ret
+ALIGN function_align
+.main:
+    vbroadcasti128       m0, [cq+16* 0]
+    vbroadcasti128       m4, [cq+16* 2]
+    vbroadcasti128       m1, [cq+16*15]
+    vbroadcasti128       m5, [cq+16*13]
+    vbroadcasti128       m2, [cq+16* 4]
+    vbroadcasti128       m6, [cq+16* 6]
+    vbroadcasti128       m3, [cq+16*11]
+    vbroadcasti128       m7, [cq+16* 9]
+    shufpd               m0, m4, 0x0c ;  0  2
+    shufpd               m1, m5, 0x0c ; 15 13
+    shufpd               m2, m6, 0x0c ;  4  6
+    shufpd               m3, m7, 0x0c ; 11  9
+    vbroadcasti128       m4, [cq+16* 8]
+    vbroadcasti128       m6, [cq+16*10]
+    vbroadcasti128       m5, [cq+16* 7]
+    vbroadcasti128       m7, [cq+16* 5]
+    shufpd               m4, m6, 0x0c ;  8 10
+    shufpd               m5, m7, 0x0c ;  7  5
+    vbroadcasti128       m6, [cq+16*12]
+    vbroadcasti128       m7, [cq+16*14]
+    shufpd               m6, m7, 0x0c ; 12 14
+    vbroadcasti128       m7, [cq+16* 3]
+    vbroadcasti128       m8, [cq+16* 1]
+    shufpd               m7, m8, 0x0c ;  3  1
+.main2:
+    ; expects: m12 = clip_min   m13 = clip_max
+    vpbroadcastd        m11, [pd_2048]
+    ITX_MULSUB_2D         1, 0, 8, 9, 10, 11,  201_995,  4091_3973, 1
+    ITX_MULSUB_2D         3, 2, 8, 9, 10, 11, 1751_2440, 3703_3290, 1
+    ITX_MULSUB_2D         5, 4, 8, 9, 10, 11, 3035_3513, 2751_2106, 1
+    ITX_MULSUB_2D         7, 6, 8, 9, 10, 11, 3857_4052, 1380_601,  1
+    psubd                m8, m0, m4 ; t8a  t10a
+    paddd                m0, m4     ; t0a  t2a
+    psubd                m4, m1, m5 ; t9a  t11a
+    paddd                m1, m5     ; t1a  t3a
+    psubd                m5, m2, m6 ; t12a t14a
+    paddd                m2, m6     ; t4a  t6a
+    psubd                m6, m3, m7 ; t13a t15a
+    paddd                m3, m7     ; t5a  t7a
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m8
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m8
+    ITX_MULSUB_2D         8, 4, 7, 9, 10, 11,  799_3406, 4017_2276, 1
+    ITX_MULSUB_2D         6, 5, 7, 9, 10, 11, 4017_2276, 10,        1
+    psubd                m7, m0, m2 ; t4   t6
+    paddd                m0, m2     ; t0   t2
+    psubd                m2, m1, m3 ; t5   t7
+    paddd                m1, m3     ; t1   t3
+    psubd                m3, m4, m6 ; t12a t14a
+    paddd                m4, m6     ; t8a  t10a
+    psubd                m6, m8, m5 ; t13a t15a
+    paddd                m8, m5     ; t9a  t11a
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m6, m7, m8
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m6, m7, m8
+    punpcklqdq           m5, m3, m7 ; t12a t4
+    punpckhqdq           m3, m7     ; t14a t6
+    punpckhqdq           m7, m6, m2 ; t15a t7
+    punpcklqdq           m6, m2     ; t13a t5
+    ITX_MULSUB_2D         7, 3, 2, 9, 10, 11, 3784, 1567
+    ITX_MULSUB_2D         5, 6, 2, 9, 10, 11, 1567, 10
+    vpbroadcastd        m10, [pd_2896]
+    vbroadcasti128       m9, [pw_2048_m2048] ; + + - -
+    punpckhqdq           m2, m4, m0 ; t10a t2
+    punpcklqdq           m4, m0     ; t8a  t0
+    punpckhqdq           m0, m8, m1 ; t11a t3
+    punpcklqdq           m8, m1     ; t9a  t1
+    paddd                m1, m6, m7 ; out2   -out3
+    psubd                m6, m7     ; t14a t6
+    paddd                m7, m5, m3 ; -out13  out12
+    psubd                m5, m3     ; t15a t7
+    psubd                m3, m8, m0 ; t11  t3a
+    paddd                m8, m0     ; out14  -out15
+    paddd                m0, m4, m2 ; -out1   out0
+    psubd                m4, m2     ; t10  t2a
+    REPX    {pmaxsd x, m12}, m6, m5, m3, m4
+    REPX    {pminsd x, m13}, m6, m5, m3, m4
+    REPX    {pmulld x, m10}, m6, m5, m3, m4
+    paddd                m6, m11
+    paddd                m4, m11
+    paddd                m2, m6, m5 ; -out5   out4
+    psubd                m6, m5     ;  out10 -out11
+    psubd                m5, m4, m3 ; -out9   out8
+    paddd                m3, m4     ;  out6  -out7
+    REPX     {psrad  x, 12}, m2, m3, m5, m6
+    REPX     {psignd x, m9}, m1, m8, m3, m6
+    pshufd               m9, m9, q1032
+    REPX     {psignd x, m9}, m0, m7, m2, m5
+    ret
+
+INV_TXFM_4X16_FN flipadst, dct
+INV_TXFM_4X16_FN flipadst, adst
+INV_TXFM_4X16_FN flipadst, flipadst
+INV_TXFM_4X16_FN flipadst, identity
+
+cglobal iflipadst_4x16_internal_10bpc, 0, 7, 11, dst, stride, c, eob, tx2
+.pass1:
+    call m(iadst_16x4_internal_10bpc).main
+    vpbroadcastd         m6, [pd_6144]
+    call m(iadst_16x4_internal_10bpc).main_end
+    psrad                m0, m3, 13
+    psrad                m1, m2, 13
+    psrad                m2, m5, 13
+    psrad                m3, m4, 13
+    psrad                m4, m7, 13
+    psrad                m5, m6, 13
+    psrad                m6, m9, 13
+    psrad                m7, m8, 13
+    jmp                tx2q
+.pass2:
+    call m(iadst_4x16_internal_10bpc).pass2_main
+    vpbroadcastd         m5, [pw_2048]
+    vpbroadcastd         m8, [pixel_10bpc_max]
+    lea                  r6, [strideq*3]
+    vpblendd             m4, m3, m0, 0x33 ; -out0   out3   out1  -out2
+    pshufd               m2, m2, q1032    ; -out11  out8   out10 -out9
+    vpblendd             m3, m0, 0xcc     ; -out12  out15  out13 -out14
+    pxor                 m7, m7
+    psubw                m9, m7, m5
+    vpblendd             m9, m5, 0x3c     ; -2048   2048   2048  -2048
+    pmulhrsw             m0, m4, m9
+    call .write_4x4
+    pmulhrsw             m0, m2, m9
+    call .write_4x4
+    pmulhrsw             m0, m1, m9
+    call .write_4x4
+    pmulhrsw             m0, m3, m9
+    call .write_4x4
+    RET
+ALIGN function_align
+.write_4x4:
+    movq                xm4, [dstq+strideq*0]
+    movhps              xm4, [dstq+r6       ]
+    vpbroadcastq         m5, [dstq+strideq*1]
+    vpbroadcastq         m6, [dstq+strideq*2]
+    mova          [cq+32*0], m7
+    mova          [cq+32*1], m7
+    add                  cq, 32*2
+    vpblendd             m4, m5, 0x30
+    vpblendd             m4, m6, 0xc0
+    paddw                m4, m0
+    pmaxsw               m4, m7
+    pminsw               m4, m8
+    vextracti128        xm5, m4, 1
+    movq   [dstq+strideq*0], xm4
+    movq   [dstq+strideq*1], xm5
+    movhps [dstq+strideq*2], xm5
+    movhps [dstq+r6       ], xm4
+    lea                dstq, [dstq+strideq*4]
+    ret
+
+INV_TXFM_4X16_FN identity, dct
+INV_TXFM_4X16_FN identity, adst
+INV_TXFM_4X16_FN identity, flipadst
+INV_TXFM_4X16_FN identity, identity
+
+cglobal iidentity_4x16_internal_10bpc, 0, 7, 11, dst, stride, c, eob, tx2
+    vpbroadcastd         m7, [pd_5793]
+    pmulld               m0, m7, [cq+32*0]
+    pmulld               m4, m7, [cq+32*1]
+    pmulld               m1, m7, [cq+32*2]
+    pmulld               m5, m7, [cq+32*3]
+    pmulld               m2, m7, [cq+32*4]
+    pmulld               m6, m7, [cq+32*5]
+    pmulld               m3, m7, [cq+32*6]
+    pmulld               m7,     [cq+32*7]
+    vpbroadcastd         m8, [pd_6144]
+    REPX      {paddd x, m8}, m0, m4, m1, m5, m2, m6, m3, m7
+    REPX      {psrad x, 13}, m0, m4, m1, m5, m2, m6, m3, m7
+    jmp                tx2q
+.pass2:
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    vpbroadcastd         m7, [pw_1697x16]
+    vpbroadcastd         m8, [pw_2048]
+    pmulhrsw             m4, m7, m0
+    pmulhrsw             m5, m7, m1
+    pmulhrsw             m6, m7, m2
+    pmulhrsw             m7, m3
+    REPX      {paddsw x, x}, m0, m1, m2, m3
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    vpbroadcastd         m4, [pixel_10bpc_max]
+    call .pass2_end
+    RET
+ALIGN function_align
+.pass2_end:
+    punpckhwd            m7, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    lea                  r6, [strideq*5]
+    pxor                 m3, m3
+    punpckhdq            m5, m0, m2 ; 2 3   6 7
+    punpckldq            m0, m2     ; 0 1   4 5
+    punpckldq            m6, m7, m1 ; 8 9   c d
+    punpckhdq            m7, m1     ; a b   e f
+    pmulhrsw             m0, m8
+    call .write_2x4x2
+    pmulhrsw             m0, m5, m8
+    call .write_2x4x2
+    pmulhrsw             m0, m6, m8
+    lea                dstq, [dstq+strideq*4]
+    call .write_2x4x2
+    pmulhrsw             m0, m7, m8
+    call .write_2x4x2
+    ret
+ALIGN function_align
+.write_2x4x2:
+    movq                xm1, [dstq+strideq*0]
+    movhps              xm1, [dstq+strideq*1]
+    vpbroadcastq         m2, [dstq+strideq*4]
+    vpblendd             m1, m2, 0x30
+    vpbroadcastq         m2, [dstq+r6       ]
+    vpblendd             m1, m2, 0xc0
+    mova          [cq+32*0], m3
+    mova          [cq+32*1], m3
+    add                  cq, 32*2
+    paddw                m1, m0
+    pmaxsw               m1, m3
+    pminsw               m1, m4
+    vextracti128        xm2, m1, 1
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    movq   [dstq+strideq*4], xm2
+    movhps [dstq+r6       ], xm2
+    lea                dstq, [dstq+strideq*2]
+    ret
+
+INV_TXFM_4X16_FN dct, dct,      12
+INV_TXFM_4X16_FN dct, identity, 12
+INV_TXFM_4X16_FN dct, adst,     12
+INV_TXFM_4X16_FN dct, flipadst, 12
+
+cglobal idct_4x16_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    jmp m(idct_4x16_internal_10bpc).pass1
+.pass2:
+    punpckldq            m8, m0, m1
+    punpckhdq            m0, m1
+    punpckldq            m9, m2, m3
+    punpckhdq            m2, m3
+    punpckldq            m1, m4, m5
+    punpckhdq            m4, m5
+    punpckldq            m3, m6, m7
+    punpckhdq            m6, m7
+    punpcklqdq           m5, m0, m2         ;  2  6
+    punpckhqdq          m12, m0, m2         ;  3  7
+    punpcklqdq           m0, m8, m9         ;  0  4
+    punpckhqdq          m10, m8, m9         ;  1  5
+    punpcklqdq           m2, m1, m3         ;  8 12
+    punpckhqdq          m13, m1, m3         ;  9 13
+    punpcklqdq           m9, m4, m6         ; 10 14
+    punpckhqdq           m4, m6             ; 11 15
+    vperm2i128           m1,  m5,  m9, 0x20 ;  2 10
+    vperm2i128           m3,  m9,  m5, 0x31 ; 14  6
+    vpermq              m11,  m4, q1302     ; 15 11
+    ; interleave
+    REPX {vpermq x, x, q3120}, m0, m1, m2, m3, m10
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+    REPX     {pmaxsd x, m8}, m0, m1, m2, m3, m10, m11, m12, m13
+    REPX     {pminsd x, m9}, m0, m1, m2, m3, m10, m11, m12, m13
+    call m(idct_16x4_internal_10bpc).pass1_main
+    vpermq               m6, m12, q1302 ;  7  3
+    vpermq               m5, m13, q3120 ;  9 13
+    call m(idct_16x4_internal_10bpc).pass1_main2
+    call m(idct_16x4_internal_10bpc).pass1_main3
+    REPX       {psrad x, 3}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m1, m2, m3
+    packssdw             m2, m4, m5
+    packssdw             m3, m6, m7
+    mova                 m4, [idct16_12_shuf]
+    REPX  {vpermd x, m4, x}, m0, m1, m2, m3
+    vpbroadcastd         m9, [pw_16384]
+    vpbroadcastd         m8, [pixel_12bpc_max]
+    call m(idct_4x16_internal_10bpc).pass2_end
+    RET
+
+INV_TXFM_4X16_FN adst, dct,      12
+INV_TXFM_4X16_FN adst, adst,     12
+INV_TXFM_4X16_FN adst, flipadst, 12
+INV_TXFM_4X16_FN adst, identity, 12
+
+cglobal iadst_4x16_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    call .main_pass1
+    psrad                m0, m4, 12
+    psrad                m1, m5, 12
+    psrad                m2, 12
+    psrad                m3, 12
+    psrad                m4, m8, 12
+    psrad                m5, m9, 12
+    psrad                m6, 12
+    psrad                m7, 12
+    jmp                tx2q
+.pass2:
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call .transpose_16x4
+    call m(iadst_4x16_internal_10bpc).main2
+    pshufd               m4, m5, q1032
+    psrad                m5, m6, 3
+    pshufd               m6, m7, q1032
+    psrad                m7, m8, 3
+    REPX {pshufd x, x, q1032}, m0, m2
+    REPX       {psrad x, 3}, m0, m1, m2, m3, m4, m6
+.pass2_end:
+    packssdw             m0, m1
+    packssdw             m1, m2, m3
+    packssdw             m2, m4, m5
+    packssdw             m3, m6, m7
+    mova                 m4, [iadst16_12_shuf]
+    REPX  {vpermd x, m4, x}, m0, m1, m2, m3
+    vpbroadcastd         m9, [pw_16384]
+    vpbroadcastd         m8, [pixel_12bpc_max]
+    lea                  r6, [strideq*3]
+    pxor                 m7, m7
+    pmulhrsw             m0, m9
+    call m(iadst_4x16_internal_10bpc).write_4x4
+    pmulhrsw             m0, m9, m1
+    call m(iadst_4x16_internal_10bpc).write_4x4
+    pmulhrsw             m0, m9, m2
+    call m(iadst_4x16_internal_10bpc).write_4x4
+    pmulhrsw             m0, m9, m3
+    call m(iadst_4x16_internal_10bpc).write_4x4
+    RET
+ALIGN function_align
+.transpose_16x4:
+    ; transpose & interleave
+    punpckldq            m8, m0, m1
+    punpckhdq            m0, m1
+    punpckldq            m9, m2, m3
+    punpckhdq            m2, m3
+    punpckldq            m1, m4, m5
+    punpckhdq            m4, m5
+    punpckldq            m3, m6, m7
+    punpckhdq            m6, m7
+    punpcklqdq          m10, m8, m0
+    punpckhqdq           m0, m8
+    punpcklqdq          m11, m9, m2
+    punpckhqdq           m2, m9
+    punpcklqdq           m8, m1, m4
+    punpckhqdq           m4, m1
+    punpcklqdq           m9, m3, m6
+    punpckhqdq           m6, m3
+    vperm2i128           m5,  m0,  m2, 0x31   ;  7  5
+    vperm2i128           m7,  m0,  m2, 0x20   ;  3  1
+    vperm2i128           m0, m10, m11, 0x20   ;  0  2
+    vperm2i128           m2, m10, m11, 0x31   ;  4  6
+    vperm2i128           m1,  m4,  m6, 0x31   ; 15 13
+    vperm2i128           m3,  m4,  m6, 0x20   ; 11  9
+    vperm2i128           m4,  m8,  m9, 0x20   ;  8 10
+    vperm2i128           m6,  m8,  m9, 0x31   ; 12 14
+    ret
+ALIGN function_align
+.main_pass1:
+    call m(iadst_16x4_internal_10bpc).main
+    vpbroadcastd         m6, [pd_3072]
+    paddd               m10, m4, m5
+    psubd                m4, m3
+    psubd                m5, m3
+    paddd                m3, m10
+    psubd                m8, m7, m1
+    paddd                m7, m9
+    psubd                m9, m1
+    paddd                m7, m1
+    REPX      {psrad x, 1 }, m4, m5, m2, m3, m8, m9, m0, m7
+    REPX      {paddd x, m6}, m4, m5, m2, m3, m8, m9, m7
+    paddd                m6, m0
+    ret
+
+INV_TXFM_4X16_FN flipadst, dct,      12
+INV_TXFM_4X16_FN flipadst, adst,     12
+INV_TXFM_4X16_FN flipadst, flipadst, 12
+INV_TXFM_4X16_FN flipadst, identity, 12
+
+cglobal iflipadst_4x16_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    call m(iadst_4x16_internal_12bpc).main_pass1
+    psrad                m0, m3, 12
+    psrad                m1, m2, 12
+    psrad                m2, m5, 12
+    psrad                m3, m4, 12
+    psrad                m4, m7, 12
+    psrad                m5, m6, 12
+    psrad                m6, m9, 12
+    psrad                m7, m8, 12
+    jmp                tx2q
+.pass2:
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(iadst_4x16_internal_12bpc).transpose_16x4
+    call m(iadst_4x16_internal_10bpc).main2
+    pshufd               m4, m3, q1032
+    psrad                m3, m5, 3
+    psrad                m5, m2, 3
+    pshufd               m2, m6, q1032
+    pshufd               m6, m1, q1032
+    psrad                m1, m7, 3
+    psrad                m7, m0, 3
+    pshufd               m0, m8, q1032
+    REPX       {psrad x, 3}, m0, m2, m4, m6
+    jmp m(iadst_4x16_internal_12bpc).pass2_end
+
+INV_TXFM_4X16_FN identity, dct,      12
+INV_TXFM_4X16_FN identity, adst,     12
+INV_TXFM_4X16_FN identity, flipadst, 12
+INV_TXFM_4X16_FN identity, identity, 12
+
+cglobal iidentity_4x16_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [pd_1697]
+    mova                 m0, [cq+32*0]
+    mova                 m4, [cq+32*1]
+    mova                 m1, [cq+32*2]
+    mova                 m5, [cq+32*3]
+    vpbroadcastd         m9, [pd_6144]
+    pmulld               m2, m8, m0
+    pmulld               m6, m8, m4
+    pmulld               m3, m8, m1
+    pmulld               m7, m8, m5
+    mova                m10, [cq+32*4]
+    mova                m11, [cq+32*5]
+    mova                m12, [cq+32*6]
+    mova                m13, [cq+32*7]
+    REPX     {paddd  x, m9}, m2, m6, m3, m7
+    REPX     {psrad  x, 12}, m2, m6, m3, m7
+    paddd                m0, m2
+    pmulld               m2, m8, m10
+    paddd                m4, m6
+    pmulld               m6, m8, m11
+    paddd                m1, m3
+    pmulld               m3, m8, m12
+    paddd                m5, m7
+    pmulld               m7, m8, m13
+    REPX     {psrad  x, 1 }, m0, m4, m1, m5
+    REPX     {paddd  x, m9}, m2, m6, m3, m7
+    REPX     {psrad  x, 12}, m2, m6, m3, m7
+    paddd                m2, m10
+    paddd                m6, m11
+    paddd                m3, m12
+    paddd                m7, m13
+    REPX     {psrad  x, 1 }, m2, m6, m3, m7
+    jmp                tx2q
+.pass2:
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    vpbroadcastd         m8, [pd_5793]
+    vpbroadcastd         m9, [pd_1024]
+    REPX     {pmulld x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {paddd  x, m9}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad  x, 14}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    vpbroadcastd         m8, [pw_16384]
+    vpbroadcastd         m4, [pixel_12bpc_max]
+    call m(iidentity_4x16_internal_10bpc).pass2_end
+    RET
+
+%macro INV_TXFM_8X4_FN 2-3 10 ; type1, type2, bitdepth
+    INV_TXFM_FN          %1, %2, 0, 8x4, %3
+%ifidn %1_%2, dct_dct
+    vpbroadcastd         m2, [dconly_%3bpc]
+%if %3 = 10
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 4
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 128
+    sar                 r6d, 8
+    jmp m(inv_txfm_add_dct_dct_8x8_10bpc).dconly3
+%else
+    jmp m(inv_txfm_add_dct_dct_8x4_10bpc).dconly
+%endif
+%endif
+%endmacro
+
+INV_TXFM_8X4_FN dct, dct
+INV_TXFM_8X4_FN dct, identity
+INV_TXFM_8X4_FN dct, adst
+INV_TXFM_8X4_FN dct, flipadst
+
+cglobal idct_8x4_internal_10bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+.pass1:
+    vbroadcasti128       m1, [cq+16*1]
+    vbroadcasti128       m0, [cq+16*5]
+    vbroadcasti128       m2, [cq+16*3]
+    vbroadcasti128       m3, [cq+16*7]
+    vpbroadcastd         m6, [pd_2896]
+    shufpd               m1, m0, 0x0c ; 1 5
+    shufpd               m3, m2, 0x0c ; 7 3
+    vbroadcasti128       m0, [cq+16*0]
+    vbroadcasti128       m4, [cq+16*2]
+    vbroadcasti128       m2, [cq+16*4]
+    vbroadcasti128       m5, [cq+16*6]
+    vpbroadcastd         m7, [pd_2048]
+    shufpd               m0, m4, 0x0c ; 0 2
+    shufpd               m2, m5, 0x0c ; 4 6
+    REPX {pmulld x, m6}, m1, m3, m0, m2
+    REPX {paddd  x, m7}, m1, m3, m0, m2
+    REPX {psrad  x, 12}, m1, m3, m0, m2
+    call .main
+    psubd                m3, m0, m4  ; out7 out6 (interleaved)
+    paddd                m0, m4      ; out0 out1 (interleaved)
+    paddd                m1, m2, m5  ; out3 out2 (interleaved)
+    psubd                m2, m5      ; out4 out5 (interleaved)
+    pshufd               m1, m1, q1032
+    pshufd               m3, m3, q1032
+    jmp                tx2q
+.pass2:
+    vbroadcasti128       m4, [deint_shuf]
+    packssdw             m0, m1
+    packssdw             m2, m3
+    vperm2i128           m1, m0, m2, 0x31
+    vinserti128          m0, xm2, 1
+    pshufb               m0, m4
+    pshufb               m1, m4
+    IDCT4_1D_PACKED_WORD  0, 1, 2, 3, 4, 7
+    vpermq               m0, m0, q3120 ; out0 out1
+    vpermq               m2, m1, q2031 ; out2 out3
+    jmp m(iadst_8x4_internal_10bpc).end
+ALIGN function_align
+.main:
+    ITX_MULSUB_2D         1, 3, 4, 5, 6, 7, 799_3406, 4017_2276, 1
+    IDCT4_1D_PACKED       0, 2, 4, 5, 6, 7
+    vpbroadcastd         m6, [pd_2896]
+    punpcklqdq           m4, m1, m3   ; t4a  t7a
+    punpckhqdq           m1, m3       ; t5a  t6a
+    psubd                m3, m4, m1   ; t5a  t6a
+    paddd                m4, m1       ; t4   t7
+    REPX     {pmaxsd x, m8}, m3, m4, m0, m2
+    REPX     {pminsd x, m9}, m3, m4, m0, m2
+    pmulld               m3, m6
+    pshufd               m1, m3, q1032
+    paddd                m3, m7
+    psubd                m5, m3, m1
+    paddd                m1, m3
+    psrad                m5, 12
+    psrad                m1, 12
+    vpblendd             m5, m4, 0x33 ; t4   t5
+    punpckhqdq           m4, m1       ; t7   t6
+    ret
+
+INV_TXFM_8X4_FN adst, dct
+INV_TXFM_8X4_FN adst, adst
+INV_TXFM_8X4_FN adst, flipadst
+INV_TXFM_8X4_FN adst, identity
+
+cglobal iadst_8x4_internal_10bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    call m(iadst_4x8_internal_10bpc).main
+    vpblendd             m3, m0, m4, 0x33 ; out6 out7
+    vpblendd             m0, m4, 0xcc     ; out0 out1
+    pshufd               m1, m5, q1032
+    psignd               m2, m6           ; out4 out5
+    psignd               m1, m6           ; out2 out3
+    jmp                tx2q
+.pass2:
+    call .pass2_main
+    vpermq               m0, m0, q3120 ; out0 out1
+    vpermq               m2, m1, q3120 ; out2 out3
+.end:
+    vpbroadcastd         m1, [pw_2048]
+    pmulhrsw             m0, m1
+    pmulhrsw             m1, m2
+    vpbroadcastd         m5, [pixel_10bpc_max]
+.end2:
+    mova                xm2, [dstq+strideq*0]
+    vinserti128          m2, [dstq+strideq*1], 1
+    lea                  r6, [dstq+strideq*2]
+    mova                xm3, [r6  +strideq*0]
+    vinserti128          m3, [r6  +strideq*1], 1
+    pxor                 m4, m4
+    REPX {mova [cq+32*x], m4}, 0, 1, 2, 3
+    paddw                m0, m2
+    paddw                m1, m3
+    pmaxsw               m0, m4
+    pmaxsw               m1, m4
+    pminsw               m0, m5
+    pminsw               m1, m5
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova         [r6  +strideq*0], xm1
+    vextracti128 [r6  +strideq*1], m1, 1
+    RET
+ALIGN function_align
+.pass2_main:
+    vbroadcasti128       m4, [deint_shuf]
+    packssdw             m0, m1
+    packssdw             m2, m3
+    lea                  r6, [deint_shuf+128]
+    vperm2i128           m1, m0, m2, 0x31
+    vinserti128          m0, xm2, 1
+    pshufb               m0, m4
+    pshufb               m1, m4
+    jmp m(iadst_8x4_internal_8bpc).main
+ALIGN function_align
+.main:
+    vpbroadcastd         m1, [pd_2896]
+    pmulld               m0, m1, [cq+32*0]
+    pmulld               m3, m1, [cq+32*3]
+    pmulld               m2, m1, [cq+32*2]
+    pmulld               m1,     [cq+32*1]
+    vpbroadcastd         m4, [pd_2048]
+    REPX      {paddd x, m4}, m0, m3, m2, m1
+    REPX      {psrad x, 12}, m0, m3, m2, m1
+.main2:
+    IADST4_1D
+    ret
+
+INV_TXFM_8X4_FN flipadst, dct
+INV_TXFM_8X4_FN flipadst, adst
+INV_TXFM_8X4_FN flipadst, flipadst
+INV_TXFM_8X4_FN flipadst, identity
+
+cglobal iflipadst_8x4_internal_10bpc, 0, 5, 10, dst, stride, c, eob, tx2
+    call m(iadst_4x8_internal_10bpc).main
+    shufpd               m3, m4, m0, 0x05
+    shufpd               m0, m4, 0x05
+    psignd               m2, m6
+    pshufd               m6, m6, q1032
+    pshufd               m1, m2, q1032
+    psignd               m2, m5, m6
+    jmp                tx2q
+.pass2:
+    call m(iadst_8x4_internal_10bpc).pass2_main
+    vpermq               m2, m0, q2031
+    vpermq               m0, m1, q2031
+    jmp m(iadst_8x4_internal_10bpc).end
+
+INV_TXFM_8X4_FN identity, dct
+INV_TXFM_8X4_FN identity, adst
+INV_TXFM_8X4_FN identity, flipadst
+INV_TXFM_8X4_FN identity, identity
+
+cglobal iidentity_8x4_internal_10bpc, 0, 7, 10, dst, stride, c, eob, tx2
+.pass1:
+    vpbroadcastd         m4, [pd_2896]
+    vpermq               m0, [cq+32*0], q3120
+    vpermq               m1, [cq+32*1], q3120
+    vpermq               m2, [cq+32*2], q3120
+    vpermq               m3, [cq+32*3], q3120
+    vpbroadcastd         m7, [pd_2048]
+    REPX     {pmulld x, m4}, m0, m1, m2, m3
+    REPX     {paddd  x, m7}, m0, m1, m2, m3
+    REPX     {psrad  x, 12}, m0, m1, m2, m3
+    REPX     {paddd  x, x }, m0, m1, m2, m3
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m5, [pixel_10bpc_max]
+    vpbroadcastd         m4, [pw_1697x8]
+    packssdw             m0, m1
+    packssdw             m2, m3
+    pmulhrsw             m1, m4, m0
+    pmulhrsw             m4, m2
+    paddsw               m0, m1
+    paddsw               m2, m4
+    packssdw             m7, m7 ; pw_2048
+.pass2_end:
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    lea                  r6, [dstq+strideq*2]
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    pmulhrsw             m2, m7
+    pmulhrsw             m0, m7
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    mova                xm2, [dstq+strideq*0]
+    vinserti128          m2, [r6  +strideq*0], 1
+    mova                xm3, [dstq+strideq*1]
+    vinserti128          m3, [r6  +strideq*1], 1
+    pxor                 m4, m4
+    REPX {mova [cq+32*x], m4}, 0, 1, 2, 3
+    paddw                m0, m2
+    paddw                m1, m3
+    pmaxsw               m0, m4
+    pmaxsw               m1, m4
+    pminsw               m0, m5
+    pminsw               m1, m5
+    mova         [dstq+strideq*0], xm0
+    mova         [dstq+strideq*1], xm1
+    vextracti128 [r6  +strideq*0], m0, 1
+    vextracti128 [r6  +strideq*1], m1, 1
+    RET
+
+INV_TXFM_8X4_FN dct, dct,      12
+INV_TXFM_8X4_FN dct, identity, 12
+INV_TXFM_8X4_FN dct, adst,     12
+INV_TXFM_8X4_FN dct, flipadst, 12
+
+cglobal idct_8x4_internal_12bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [clip_20b_min]
+    vpbroadcastd         m9, [clip_20b_max]
+    jmp m(idct_8x4_internal_10bpc).pass1
+.pass2:
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+    REPX     {pmaxsd x, m8}, m0, m1, m2, m3
+    REPX     {pminsd x, m9}, m0, m1, m2, m3
+    call m(iadst_8x4_internal_12bpc).transpose_4x8
+    IDCT4_1D              0, 1, 2, 3, 4, 5, 6, 7
+    jmp m(iadst_8x4_internal_12bpc).end
+
+INV_TXFM_8X4_FN adst, dct,      12
+INV_TXFM_8X4_FN adst, adst,     12
+INV_TXFM_8X4_FN adst, flipadst, 12
+INV_TXFM_8X4_FN adst, identity, 12
+
+cglobal iadst_8x4_internal_12bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [clip_20b_min]
+    vpbroadcastd         m9, [clip_20b_max]
+    call m(iadst_4x8_internal_10bpc).main2
+    vpblendd             m3, m0, m4, 0x33 ; out6 out7
+    vpblendd             m0, m4, 0xcc     ; out0 out1
+    pshufd               m1, m5, q1032
+    psignd               m2, m6           ; out4 out5
+    psignd               m1, m6           ; out2 out3
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+    REPX     {pmaxsd x, m8}, m0, m1, m2, m3
+    REPX     {pminsd x, m9}, m0, m1, m2, m3
+    call .pass2_main
+    vpbroadcastd         m5, [pd_2048]
+    paddd                m0, m5, m4
+    paddd                m1, m5, m6
+    paddd                m2, m5
+    paddd                m3, m5
+.pass2_end:
+    REPX      {psrad x, 12}, m0, m1, m2, m3
+.end:
+    vpbroadcastd         m4, [pw_16384]
+    REPX       {psrad x, 3}, m0, m1, m2, m3
+    packssdw             m0, m1
+    packssdw             m2, m3
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m2, m4
+    vpermq               m0, m0, q3120 ; out0 out1
+    vpermq               m1, m1, q3120 ; out2 out3
+    vpbroadcastd         m5, [pixel_12bpc_max]
+    jmp m(iadst_8x4_internal_10bpc).end2
+ALIGN function_align
+.pass2_main:
+    call .transpose_4x8
+    jmp m(iadst_8x4_internal_10bpc).main2
+ALIGN function_align
+.transpose_4x8:
+    ; deinterleave
+    pshufd               m0, m0, q3120
+    pshufd               m1, m1, q3120
+    pshufd               m2, m2, q3120
+    pshufd               m3, m3, q3120
+    ; transpose
+    punpcklqdq           m4, m0, m1
+    punpckhqdq           m0, m1
+    punpcklqdq           m5, m2, m3
+    punpckhqdq           m2, m3
+    vperm2i128           m1, m0, m2, 0x20   ; out1
+    vperm2i128           m3, m0, m2, 0x31   ; out3
+    vperm2i128           m2, m4, m5, 0x31   ; out2
+    vperm2i128           m0, m4, m5, 0x20   ; out0
+    ret
+
+INV_TXFM_8X4_FN flipadst, dct,      12
+INV_TXFM_8X4_FN flipadst, adst,     12
+INV_TXFM_8X4_FN flipadst, flipadst, 12
+INV_TXFM_8X4_FN flipadst, identity, 12
+
+cglobal iflipadst_8x4_internal_12bpc, 0, 5, 10, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [clip_20b_min]
+    vpbroadcastd         m9, [clip_20b_max]
+    call m(iadst_4x8_internal_10bpc).main2
+    shufpd               m3, m4, m0, 0x05
+    shufpd               m0, m4, 0x05
+    psignd               m2, m6
+    pshufd               m6, m6, q1032
+    pshufd               m1, m2, q1032
+    psignd               m2, m5, m6
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+    REPX     {pmaxsd x, m8}, m0, m1, m2, m3
+    REPX     {pminsd x, m9}, m0, m1, m2, m3
+    call m(iadst_8x4_internal_12bpc).pass2_main
+    vpbroadcastd         m5, [pd_2048]
+    paddd                m0, m5, m3
+    paddd                m1, m5, m2
+    paddd                m3, m5, m4
+    paddd                m2, m5, m6
+    jmp m(iadst_8x4_internal_12bpc).pass2_end
+
+INV_TXFM_8X4_FN identity, dct,      12
+INV_TXFM_8X4_FN identity, adst,     12
+INV_TXFM_8X4_FN identity, flipadst, 12
+INV_TXFM_8X4_FN identity, identity, 12
+
+cglobal iidentity_8x4_internal_12bpc, 0, 7, 10, dst, stride, c, eob, tx2
+    jmp m(iidentity_8x4_internal_10bpc).pass1
+.pass2:
+    ; m0 = in0 in1 (interleaved)
+    ; m1 = in2 in3 (interleaved)
+    ; m2 = in4 in5 (interleaved)
+    ; m3 = in6 in7 (interleaved)
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+    REPX     {pmaxsd x, m8}, m0, m1, m2, m3
+    REPX     {pminsd x, m9}, m0, m1, m2, m3
+    vpbroadcastd         m4, [pd_5793]
+    REPX     {pmulld x, m4}, m0, m1, m2, m3
+    REPX     {paddd  x, m7}, m0, m1, m2, m3
+    REPX     {psrad  x, 15}, m0, m1, m2, m3
+    vpbroadcastd         m5, [pixel_12bpc_max]
+    vpbroadcastd         m7, [pw_16384]
+    packssdw             m0, m1
+    packssdw             m2, m3
+    jmp m(iidentity_8x4_internal_10bpc).pass2_end
+
+%macro INV_TXFM_8X8_FN 2-3 10 ; type1, type2, bitdepth
+    INV_TXFM_FN          %1, %2, 0, 8x8, %3
+%ifidn %1_%2, dct_dct
+    vpbroadcastd         m2, [dconly_%3bpc]
+%if %3 = 10
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 8
+.dconly2:
+    add                 r6d, 384
+    sar                 r6d, 9
+.dconly3:
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    movd                xm0, r6d
+    paddsw              xm0, xm2
+    vpbroadcastw         m0, xm0
+.dconly_loop:
+    mova                xm1, [dstq+strideq*0]
+    vinserti128          m1, [dstq+strideq*1], 1
+    paddsw               m1, m0
+    psubusw              m1, m2
+    mova         [dstq+strideq*0], xm1
+    vextracti128 [dstq+strideq*1], m1, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    RET
+%else
+    jmp m(inv_txfm_add_dct_dct_8x8_10bpc).dconly
+%endif
+%endif
+%endmacro
+
+%macro IADST8_1D 14 ; src[1-8], tmp[1-3], pd_2048, clip[1-2]
+    ITX_MULSUB_2D        %8, %1, %9, %10, %11, %12,  401, 4076 ; t1a, t0a
+    ITX_MULSUB_2D        %2, %7, %9, %10, %11, %12, 3920, 1189 ; t7a, t6a
+    ITX_MULSUB_2D        %6, %3, %9, %10, %11, %12, 1931, 3612 ; t3a, t2a
+    ITX_MULSUB_2D        %4, %5, %9, %10, %11, %12, 3166, 2598 ; t5a, t4a
+    psubd               m%9, m%3, m%7 ; t6
+    paddd               m%3, m%7      ; t2
+    psubd               m%7, m%1, m%5 ; t4
+    paddd               m%1, m%5      ; t0
+    psubd               m%5, m%6, m%2 ; t7
+    paddd               m%6, m%2      ; t3
+    psubd               m%2, m%8, m%4 ; t5
+    paddd               m%8, m%4      ; t1
+    REPX   {pmaxsd x, m%13}, m%7, m%2, m%9, m%5, m%3, m%1, m%6, m%8
+    REPX   {pminsd x, m%14}, m%7, m%2, m%9, m%5, m%3, m%1, m%6, m%8
+    ITX_MULSUB_2D        %7, %2, %4, %10, %11, %12, 1567, 3784 ; t5a, t4a
+    ITX_MULSUB_2D        %5, %9, %4, %10, %11, %12, 3784, %11  ; t6a, t7a
+    psubd              m%10, m%7, m%9 ;  t7
+    paddd               m%7, m%9      ;  out6
+    vpbroadcastd        m%9, [pd_1448]
+    psubd               m%4, m%8, m%6 ;  t3
+    paddd               m%8, m%6      ; -out7
+    psubd               m%6, m%1, m%3 ;  t2
+    paddd               m%1, m%3      ;  out0
+    psubd               m%3, m%2, m%5 ;  t6
+    paddd               m%2, m%5      ; -out1
+    REPX   {pmaxsd x, m%13}, m%6, m%4, m%3, m%10
+    REPX   {pminsd x, m%14}, m%6, m%4, m%3, m%10
+    REPX   {pmulld x, m%9 }, m%6, m%4, m%3, m%10
+    psubd               m%5, m%6, m%4  ; (t2 - t3) * 1448
+    paddd               m%4, m%6       ; (t2 + t3) * 1448
+    psubd               m%6, m%3, m%10 ; (t6 - t7) * 1448
+    paddd               m%3, m%10      ; (t6 + t7) * 1448
+%endmacro
+
+INV_TXFM_8X8_FN dct, dct
+INV_TXFM_8X8_FN dct, identity
+INV_TXFM_8X8_FN dct, adst
+INV_TXFM_8X8_FN dct, flipadst
+
+cglobal idct_8x8_internal_10bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    mova                 m0, [cq+32*0]
+    mova                 m1, [cq+32*1]
+    mova                 m2, [cq+32*2]
+    mova                 m3, [cq+32*3]
+    mova                 m4, [cq+32*4]
+    mova                 m5, [cq+32*5]
+    mova                 m6, [cq+32*6]
+    mova                 m7, [cq+32*7]
+    vpbroadcastd        m11, [pd_2048]
+    call .main
+    call .round_shift1
+    jmp                tx2q
+.pass2:
+    call .transpose_8x8_packed
+    call m(idct_8x8_internal_8bpc).main
+    vpbroadcastd        m12, [pw_2048]
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    vpermq               m2, m2, q3120
+    vpermq               m3, m3, q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call .write_8x4_start
+    pmulhrsw             m0, m2, m12
+    pmulhrsw             m1, m3, m12
+    call .write_8x4
+    RET
+ALIGN function_align
+.write_8x4_start:
+    vpbroadcastd        m11, [pixel_10bpc_max]
+    lea                  r6, [strideq*3]
+    pxor                m10, m10
+.write_8x4:
+    mova                xm8, [dstq+strideq*0]
+    vinserti128          m8, [dstq+strideq*1], 1
+    mova                xm9, [dstq+strideq*2]
+    vinserti128          m9, [dstq+r6       ], 1
+    mova          [cq+32*0], m10
+    mova          [cq+32*1], m10
+    mova          [cq+32*2], m10
+    mova          [cq+32*3], m10
+    add                  cq, 32*4
+    paddw                m0, m8
+    paddw                m1, m9
+    pmaxsw               m0, m10
+    pmaxsw               m1, m10
+    pminsw               m0, m11
+    pminsw               m1, m11
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova         [dstq+strideq*2], xm1
+    vextracti128 [dstq+r6       ], m1, 1
+    lea                dstq, [dstq+strideq*4]
+    ret
+ALIGN function_align
+.transpose_8x8_packed:
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    lea                  r6, [deint_shuf+128]
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckhdq            m2, m4, m1
+    punpckldq            m4, m1
+    vinserti128          m1, m3, xm2, 1
+    vperm2i128           m3, m2, 0x31
+    vperm2i128           m2, m0, m4, 0x31
+    vinserti128          m0, xm4, 1
+    ret
+ALIGN function_align
+.main_rect2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+.main:
+    ITX_MULSUB_2D         5, 3, 8, 9, 10, 11, 3406, 2276 ; t5a t6a
+    ITX_MULSUB_2D         1, 7, 8, 9, 10, 11,  799, 4017 ; t4a t7a
+    ITX_MULSUB_2D         2, 6, 8, 9, 10, 11, 1567, 3784 ; t2  t3
+    paddd                m8, m1, m5 ; t4
+    psubd                m1, m5     ; t5a
+    paddd                m9, m7, m3 ; t7
+    psubd                m7, m3     ; t6a
+    vpbroadcastd         m3, [pd_2896]
+    REPX    {pmaxsd x, m12}, m1, m8, m7, m9
+    REPX    {pminsd x, m13}, m1, m8, m7, m9
+    REPX    {pmulld x, m3 }, m0, m4, m7, m1
+    paddd                m0, m11
+    paddd                m7, m11
+    psubd                m5, m0, m4
+    paddd                m0, m4
+    psubd                m4, m7, m1
+    paddd                m7, m1
+    REPX    {psrad  x, 12 }, m5, m0, m4, m7
+    psubd                m3, m0, m6 ; dct4 out3
+    paddd                m0, m6     ; dct4 out0
+    paddd                m6, m5, m2 ; dct4 out1
+    psubd                m5, m2     ; dct4 out2
+    REPX    {pmaxsd x, m12}, m0, m6, m5, m3
+    REPX    {pminsd x, m13}, m0, m6, m5, m3
+    ret
+ALIGN function_align
+.round_shift1:
+    pcmpeqd              m1, m1
+    REPX      {psubd x, m1}, m0, m6, m5, m3
+    paddd                m1, m6, m7 ; out1
+    psubd                m6, m7     ; out6
+    psubd                m7, m0, m9 ; out7
+    paddd                m0, m9     ; out0
+    paddd                m2, m5, m4 ; out2
+    psubd                m5, m4     ; out5
+    psubd                m4, m3, m8 ; out4
+    paddd                m3, m8     ; out3
+    REPX      {psrad x, 1 }, m0, m1, m2, m3, m4, m5, m6, m7
+    ret
+
+INV_TXFM_8X8_FN adst, dct
+INV_TXFM_8X8_FN adst, adst
+INV_TXFM_8X8_FN adst, flipadst
+INV_TXFM_8X8_FN adst, identity
+
+cglobal iadst_8x8_internal_10bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    call .main
+    call .main_end
+    jmp                tx2q
+.pass2:
+    call m(idct_8x8_internal_10bpc).transpose_8x8_packed
+    pshufd               m4, m0, q1032
+    pshufd               m5, m1, q1032
+    call m(iadst_8x8_internal_8bpc).main_pass2
+    vpbroadcastd         m5, [pw_2048]
+    vpbroadcastd       xm12, [pw_4096]
+    psubw               m12, m5
+    REPX {vpermq x, x, q3120}, m0, m1, m2, m3
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4_start
+    pmulhrsw             m0, m2, m12
+    pmulhrsw             m1, m3, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [cq+32*0]
+    mova                 m7, [cq+32*7]
+    mova                 m1, [cq+32*1]
+    mova                 m6, [cq+32*6]
+    mova                 m2, [cq+32*2]
+    mova                 m5, [cq+32*5]
+    mova                 m3, [cq+32*3]
+    mova                 m4, [cq+32*4]
+    vpbroadcastd        m11, [pd_2048]
+.main2:
+    IADST8_1D             0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
+    psrld                m8, 10 ; pd_1
+    vpbroadcastd         m9, [pd_3072]
+    ret
+ALIGN function_align
+.main_end:
+    paddd                m0, m8
+    psubd                m1, m8, m1
+    paddd                m6, m8
+    psubd                m7, m8, m7
+    REPX      {psrad x, 1 }, m0, m1, m6, m7
+    ; (1 + ((x + 1024) >> 11)) >> 1 = (3072 + x) >> 12
+    ; (1 - ((x + 1024) >> 11)) >> 1 = (3071 - x) >> 12
+    psubd                m8, m9, m8 ; pd_3071
+    paddd                m2, m9
+    psubd                m3, m8, m3
+    paddd                m4, m9
+    psubd                m5, m8, m5
+    REPX      {psrad x, 12}, m2, m3, m4, m5
+    ret
+
+INV_TXFM_8X8_FN flipadst, dct
+INV_TXFM_8X8_FN flipadst, adst
+INV_TXFM_8X8_FN flipadst, flipadst
+INV_TXFM_8X8_FN flipadst, identity
+
+cglobal iflipadst_8x8_internal_10bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    call m(iadst_8x8_internal_10bpc).main
+    call .main_end
+    jmp                tx2q
+.pass2:
+    call m(idct_8x8_internal_10bpc).transpose_8x8_packed
+    pshufd               m4, m0, q1032
+    pshufd               m5, m1, q1032
+    call m(iadst_8x8_internal_8bpc).main_pass2
+    vpbroadcastd        m12, [pw_2048]
+    vpbroadcastd        xm5, [pw_4096]
+    psubw               m12, m5
+    vpermq               m8, m3, q2031
+    vpermq               m9, m2, q2031
+    vpermq               m2, m1, q2031
+    vpermq               m3, m0, q2031
+    pmulhrsw             m0, m8, m12
+    pmulhrsw             m1, m9, m12
+    call m(idct_8x8_internal_10bpc).write_8x4_start
+    pmulhrsw             m0, m2, m12
+    pmulhrsw             m1, m3, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    RET
+ALIGN function_align
+.main_end:
+    paddd               m10, m8, m0
+    psubd                m0, m8, m7
+    psubd                m7, m8, m1
+    paddd                m1, m8, m6
+    psrad                m0, 1
+    psrad                m1, 1
+    psrad                m6, m7, 1
+    psrad                m7, m10, 1
+    psubd                m8, m9, m8 ; pd_6143
+    psubd               m10, m8, m5
+    paddd                m5, m9, m2
+    psubd                m2, m8, m3
+    paddd                m3, m9, m4
+    psrad                m4, m2, 12
+    psrad                m2, m10, 12
+    psrad                m3, 12
+    psrad                m5, 12
+    ret
+
+INV_TXFM_8X8_FN identity, dct
+INV_TXFM_8X8_FN identity, adst
+INV_TXFM_8X8_FN identity, flipadst
+INV_TXFM_8X8_FN identity, identity
+
+cglobal iidentity_8x8_internal_10bpc, 0, 7, 14, dst, stride, c, eob, tx2
+.pass1:
+    mova                 m0, [cq+32*0]
+    mova                 m1, [cq+32*1]
+    mova                 m2, [cq+32*2]
+    mova                 m3, [cq+32*3]
+    mova                 m4, [cq+32*4]
+    mova                 m5, [cq+32*5]
+    mova                 m6, [cq+32*6]
+    mova                 m7, [cq+32*7]
+    jmp                tx2q
+.pass2:
+    packssdw             m3, m7
+    vpbroadcastd         m7, [pixel_10bpc_max]
+.pass2_main:
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    vpbroadcastd        m12, [pw_4096]
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m4, m1
+    punpckhdq            m4, m1
+    punpckhqdq           m1, m0, m2 ; 1 5
+    punpcklqdq           m0, m2     ; 0 4
+    punpcklqdq           m2, m3, m4 ; 2 6
+    punpckhqdq           m3, m4     ; 3 7
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call .write_2x8x2_start
+    pmulhrsw             m0, m2, m12
+    pmulhrsw             m1, m3, m12
+    call .write_2x8x2_zero
+    RET
+.write_2x8x2_start:
+    lea                  r6, [strideq*5]
+    pxor                 m6, m6
+.write_2x8x2_zero:
+    mova          [cq+32*0], m6
+    mova          [cq+32*1], m6
+    mova          [cq+32*2], m6
+    mova          [cq+32*3], m6
+    add                  cq, 32*4
+.write_2x8x2:
+    mova                xm4, [dstq+strideq*0]
+    vinserti128          m4, [dstq+strideq*4], 1
+    mova                xm5, [dstq+strideq*1]
+    vinserti128          m5, [dstq+r6       ], 1
+    paddw                m0, m4
+    paddw                m1, m5
+    pmaxsw               m0, m6
+    pmaxsw               m1, m6
+    pminsw               m0, m7
+    pminsw               m1, m7
+    mova         [dstq+strideq*0], xm0
+    mova         [dstq+strideq*1], xm1
+    vextracti128 [dstq+strideq*4], m0, 1
+    vextracti128 [dstq+r6       ], m1, 1
+    lea                dstq, [dstq+strideq*2]
+    ret
+
+%macro TRANSPOSE_8X8_DWORD 12 ; src/dst[1-8], tmp[1-4]
+    punpckldq            m%9,  m%1,  m%2 ; aibj emfn
+    punpckhdq            m%1,  m%2       ; ckdl gohp
+    punpckldq           m%10,  m%3,  m%4 ; qyrz uCvD
+    punpckhdq            m%3,  m%4       ; sAtB wExF
+    punpckldq           m%11,  m%5,  m%6 ; GOHP KSLT
+    punpckhdq            m%5,  m%6       ; IQJR MUNV
+    punpckldq           m%12,  m%7,  m%8 ; WeXf aibj
+    punpckhdq            m%7,  m%8       ; YgZh ckdl
+    punpcklqdq           m%2,  m%9, m%10 ; aiqy emuC
+    punpckhqdq           m%9, m%10       ; bjrz fnvD
+    punpcklqdq           m%4,  m%1,  m%3 ; cksA gowE
+    punpckhqdq          m%10,  m%1,  m%3 ; dltB hpxF
+    punpcklqdq           m%6, m%11, m%12 ; GOWe KSai
+    punpckhqdq          m%11, m%12       ; HPXf LTbj
+    punpcklqdq           m%8,  m%5,  m%7 ; IQYg MUck
+    punpckhqdq          m%12,  m%5,  m%7 ; JRZh NVdl
+    vperm2i128           m%1,  m%2,  m%6, 0x20   ; out0
+    vperm2i128           m%5,  m%2,  m%6, 0x31   ; out4
+    vperm2i128           m%2,  m%9, m%11, 0x20   ; out1
+    vperm2i128           m%6,  m%9, m%11, 0x31   ; out5
+    vperm2i128           m%3,  m%4,  m%8, 0x20   ; out2
+    vperm2i128           m%7,  m%4,  m%8, 0x31   ; out6
+    vperm2i128           m%4, m%10, m%12, 0x20   ; out3
+    vperm2i128           m%8, m%10, m%12, 0x31   ; out7
+%endmacro
+
+INV_TXFM_8X8_FN dct, dct,      12
+INV_TXFM_8X8_FN dct, identity, 12
+INV_TXFM_8X8_FN dct, adst,     12
+INV_TXFM_8X8_FN dct, flipadst, 12
+
+cglobal idct_8x8_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(idct_8x8_internal_10bpc).pass1
+.pass2:
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call .transpose_8x8
+    vpbroadcastd        m11, [pd_2048]
+    call m(idct_8x8_internal_10bpc).main
+    call .round_shift4
+    jmp m(iadst_8x8_internal_12bpc).pass2_end
+ALIGN function_align
+.write_8x4_start:
+    vpbroadcastd        m11, [pixel_12bpc_max]
+    lea                  r6, [strideq*3]
+    pxor                m10, m10
+    ret
+ALIGN function_align
+.transpose_8x8:
+    TRANSPOSE_8X8_DWORD 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+    ret
+ALIGN function_align
+.round_shift4:
+    vpbroadcastd         m1, [pd_8]
+    REPX      {paddd x, m1}, m0, m6, m5, m3
+    paddd                m1, m6, m7 ; out1
+    psubd                m6, m7     ; out6
+    psubd                m7, m0, m9 ; out7
+    paddd                m0, m9     ; out0
+    paddd                m2, m5, m4 ; out2
+    psubd                m5, m4     ; out5
+    psubd                m4, m3, m8 ; out4
+    paddd                m3, m8     ; out3
+    REPX       {psrad x, 4}, m0, m1, m2, m3, m4, m5, m6, m7
+    ret
+
+INV_TXFM_8X8_FN adst, dct,      12
+INV_TXFM_8X8_FN adst, adst,     12
+INV_TXFM_8X8_FN adst, flipadst, 12
+INV_TXFM_8X8_FN adst, identity, 12
+
+cglobal iadst_8x8_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(iadst_8x8_internal_10bpc).pass1
+.pass2:
+    call .pass2_main
+.pass2_end:
+    packssdw             m0, m1
+    packssdw             m1, m2, m3
+    REPX {vpermq x, x, q3120}, m0, m1
+    call m(idct_8x8_internal_12bpc).write_8x4_start
+    call m(idct_8x8_internal_10bpc).write_8x4
+    packssdw             m0, m4, m5
+    packssdw             m1, m6, m7
+    REPX {vpermq x, x, q3120}, m0, m1
+    call m(idct_8x8_internal_10bpc).write_8x4
+    RET
+ALIGN function_align
+.pass2_main:
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_8x8_internal_12bpc).transpose_8x8
+    vpbroadcastd        m11, [pd_2048]
+.pass2_main2:
+    call m(iadst_8x8_internal_10bpc).main2
+    pslld                m9, m8, 3  ; pd_8
+    paddd                m0, m9
+    psubd                m1, m9, m1 ; 8+x
+    paddd                m6, m9
+    psubd                m7, m9, m7
+    REPX       {psrad x, 4}, m0, m1, m6, m7
+    vpbroadcastd         m9, [pd_17408]
+    psubd                m8, m9, m8 ; 17407
+    paddd                m2, m9
+    psubd                m3, m8, m3
+    paddd                m4, m9
+    psubd                m5, m8, m5
+    REPX      {psrad x, 15}, m2, m3, m4, m5
+    ret
+
+INV_TXFM_8X8_FN flipadst, dct,      12
+INV_TXFM_8X8_FN flipadst, adst,     12
+INV_TXFM_8X8_FN flipadst, flipadst, 12
+INV_TXFM_8X8_FN flipadst, identity, 12
+
+cglobal iflipadst_8x8_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(iflipadst_8x8_internal_10bpc).pass1
+.pass2:
+    call m(iadst_8x8_internal_12bpc).pass2_main
+    packssdw             m7, m7, m6
+    packssdw             m6, m1, m0
+    packssdw             m1, m5, m4
+    vpermq               m0, m7, q3120
+    vpermq               m1, m1, q3120
+    call m(idct_8x8_internal_12bpc).write_8x4_start
+    call m(idct_8x8_internal_10bpc).write_8x4
+    packssdw             m0, m3, m2
+    vpermq               m0, m0, q3120
+    vpermq               m1, m6, q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    RET
+
+INV_TXFM_8X8_FN identity, dct,      12
+INV_TXFM_8X8_FN identity, adst,     12
+INV_TXFM_8X8_FN identity, flipadst, 12
+INV_TXFM_8X8_FN identity, identity, 12
+
+cglobal iidentity_8x8_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    jmp m(iidentity_8x8_internal_10bpc).pass1
+.pass2:
+    packssdw             m3, m7
+    vpbroadcastd         m7, [pixel_12bpc_max]
+    jmp m(iidentity_8x8_internal_10bpc).pass2_main
+
+%macro INV_TXFM_8X16_FN 2-4 0,10 ; type1, type2, eob_offset, bitdepth
+    INV_TXFM_FN          %1, %2, %3, 8x16, %4
+%ifidn %1_%2, dct_dct
+    imul                r6d, [cq], 181
+    vpbroadcastd         m2, [dconly_%4bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 16
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    jmp m(inv_txfm_add_dct_dct_8x8_10bpc).dconly2
+%endif
+%endmacro
+
+INV_TXFM_8X16_FN dct, dct
+INV_TXFM_8X16_FN dct, identity, 35
+INV_TXFM_8X16_FN dct, adst
+INV_TXFM_8X16_FN dct, flipadst
+
+cglobal idct_8x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    vpbroadcastd        m14, [pd_2896]
+    vpbroadcastd        m11, [pd_2048]
+    cmp                eobd, 43
+    jl .fast
+    add                  cq, 32
+    call .pass1_main
+    sub                  cq, 32
+    mova         [cq+32* 1], m0
+    mova         [cq+32* 3], m1
+    mova         [cq+32* 5], m2
+    mova         [cq+32* 7], m3
+    mova         [cq+32* 9], m4
+    mova         [cq+32*11], m5
+    mova         [cq+32*13], m6
+    mova                m15, m7
+    call .pass1_main
+    mova                 m8, [cq+32* 1]
+    mova                 m9, [cq+32* 3]
+    mova                m10, [cq+32* 5]
+    mova                m11, [cq+32* 7]
+    mova                m12, [cq+32* 9]
+    mova                m13, [cq+32*11]
+    mova                m14, [cq+32*13]
+    jmp                tx2q
+.fast:
+    call .pass1_main
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, m15
+    jmp                tx2q
+.pass2:
+    call .transpose
+    call m(idct_8x16_internal_8bpc).main
+    vpbroadcastd        m12, [pw_2048]
+    REPX {vpermq x, x, q3120}, m0, m2, m4, m6
+    REPX {vpermq x, x, q2031}, m1, m3, m5, m7
+.end:
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4_start
+    pmulhrsw             m0, m2, m12
+    pmulhrsw             m1, m3, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    pmulhrsw             m0, m4, m12
+    pmulhrsw             m1, m5, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    pmulhrsw             m0, m6, m12
+    pmulhrsw             m1, m7, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    RET
+ALIGN function_align
+.transpose:
+    packssdw             m0, m8
+    packssdw             m1, m9
+    packssdw             m2, m10
+    packssdw             m3, m11
+    packssdw             m4, m12
+    packssdw             m5, m13
+    packssdw             m6, m14
+    packssdw             m7, m15
+    lea                  r6, [deint_shuf+128]
+    punpckhwd            m8, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpcklwd            m3, m4, m5
+    punpckhwd            m4, m5
+    punpckhwd            m5, m6, m7
+    punpcklwd            m6, m7
+    punpckhdq            m7, m3, m6
+    punpckldq            m3, m6
+    punpckhdq            m6, m4, m5
+    punpckldq            m4, m5
+    punpckhdq            m5, m8, m1
+    punpckldq            m8, m1
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    vperm2i128           m2, m0, m3, 0x31
+    vinserti128          m0, xm3, 1
+    vperm2i128           m3, m1, m7, 0x31
+    vinserti128          m1, xm7, 1
+    vperm2i128           m7, m5, m6, 0x31
+    vinserti128          m5, xm6, 1
+    vperm2i128           m6, m8, m4, 0x31
+    vinserti128          m4, m8, xm4, 1
+    ret
+ALIGN function_align
+.pass1_main:
+    pmulld               m0, m14, [cq+32* 0]
+    pmulld               m1, m14, [cq+32* 2]
+    pmulld               m2, m14, [cq+32* 4]
+    pmulld               m3, m14, [cq+32* 6]
+    pmulld               m4, m14, [cq+32* 8]
+    pmulld               m5, m14, [cq+32*10]
+    pmulld               m6, m14, [cq+32*12]
+    pmulld               m7, m14, [cq+32*14]
+    call m(idct_8x8_internal_10bpc).main_rect2
+    jmp  m(idct_8x8_internal_10bpc).round_shift1
+ALIGN function_align
+.main_evenhalf:
+    paddd                m1, m6, m7  ; idct8 out1
+    psubd                m6, m7      ; idct8 out6
+    psubd                m7, m0, m9  ; idct8 out7
+    paddd                m0, m9      ; idct8 out0
+    paddd                m2, m5, m4  ; idct8 out2
+    psubd                m5, m4      ; idct8 out5
+    psubd                m4, m3, m8  ; idct8 out4
+    paddd                m3, m8      ; idct8 out3
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    ret
+.main_oddhalf_fast_rect2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+.main_oddhalf_fast: ; lower half zero
+    vpbroadcastd         m7, [pd_4076]
+    vpbroadcastd         m8, [pd_401]
+    vpbroadcastd         m6, [pd_m1189]
+    vpbroadcastd         m9, [pd_3920]
+    vpbroadcastd         m5, [pd_3612]
+    vpbroadcastd        m10, [pd_1931]
+    vpbroadcastd         m4, [pd_m2598]
+    vpbroadcastd        m15, [pd_3166]
+    pmulld               m7, m0
+    pmulld               m0, m8
+    pmulld               m6, m1
+    pmulld               m1, m9
+    pmulld               m5, m2
+    pmulld               m2, m10
+    pmulld               m4, m3
+    pmulld               m3, m15
+    jmp .main_oddhalf_fast2
+.main_oddhalf_rect2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+.main_oddhalf:
+    ITX_MULSUB_2D         0, 7, 8, 9, 10, _,  401, 4076 ; t8a,  t15a
+    ITX_MULSUB_2D         6, 1, 8, 9, 10, _, 3920, 1189 ; t11a, t12a
+    ITX_MULSUB_2D         2, 5, 8, 9, 10, _, 1931, 3612 ; t10a, t13a
+    ITX_MULSUB_2D         4, 3, 8, 9, 10, _, 3166, 2598 ; t9a,  t14a
+.main_oddhalf_fast2:
+    REPX     {paddd x, m11}, m0, m7, m6, m1, m2, m5, m4, m3
+    REPX     {psrad x, 12 }, m0, m4, m6, m2, m1, m5, m7, m3
+    psubd                m8, m0, m4 ; t9
+    paddd                m0, m4     ; t8
+    psubd                m4, m6, m2 ; t10
+    paddd                m2, m6     ; t11
+    psubd                m6, m1, m5 ; t13
+    paddd                m5, m1     ; t12
+    psubd                m1, m7, m3 ; t14
+    paddd                m7, m3     ; t15
+    REPX    {pmaxsd x, m12}, m8, m1, m4, m6, m0, m2, m5, m7
+    REPX    {pminsd x, m13}, m8, m1, m4, m6, m0, m2, m5, m7
+    vpbroadcastd        m15, [pd_3784]
+    vpbroadcastd        m10, [pd_1567]
+    ITX_MULSUB_2D         1, 8, 3, 9, _, 11, 10, 15
+    ITX_MULSUB_2D         6, 4, 3, 9, _, 11, 10, 15, 2
+    psubd                m3, m1, m4 ; t10
+    paddd                m1, m4     ; t9
+    psubd                m4, m0, m2 ; t11a
+    paddd                m0, m2     ; t8a
+    psubd                m2, m8, m6 ; t13
+    paddd                m6, m8     ; t14
+    psubd                m8, m7, m5 ; t12a
+    paddd                m7, m5     ; t15a
+    REPX    {pmaxsd x, m12}, m2, m8, m3, m4, m0, m1, m6, m7
+    REPX    {pminsd x, m13}, m2, m8, m3, m4, m0, m1, m6, m7
+    REPX    {pmulld x, m14}, m2, m8, m3, m4
+    paddd                m2, m11
+    paddd                m8, m11
+    paddd                m5, m2, m3 ; t13a
+    psubd                m2, m3     ; t10a
+    psubd                m3, m8, m4 ; t11
+    paddd                m4, m8     ; t12
+    REPX      {psrad x, 12}, m5, m2, m3, m4
+    mova          [r6-32*4], m7
+    mova          [r6-32*3], m6
+    mova          [r6-32*2], m5
+    mova          [r6-32*1], m4
+    mova          [r6+32*0], m3
+    mova          [r6+32*1], m2
+    mova          [r6+32*2], m1
+    mova          [r6+32*3], m0
+    ret
+
+INV_TXFM_8X16_FN adst, dct
+INV_TXFM_8X16_FN adst, adst
+INV_TXFM_8X16_FN adst, flipadst
+INV_TXFM_8X16_FN adst, identity, 35
+
+cglobal iadst_8x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    vpbroadcastd        m14, [pd_2896]
+    vpbroadcastd        m11, [pd_2048]
+    cmp                eobd, 43
+    jl .fast
+    add                  cq, 32
+    call .pass1_main
+    call m(iadst_8x8_internal_10bpc).main_end
+    sub                  cq, 32
+    mova         [cq+32* 1], m0
+    mova         [cq+32* 3], m1
+    mova         [cq+32* 5], m2
+    mova         [cq+32* 7], m3
+    mova         [cq+32* 9], m4
+    mova         [cq+32*11], m5
+    mova         [cq+32*13], m6
+    mova                m15, m7
+    call .pass1_main
+    call m(iadst_8x8_internal_10bpc).main_end
+    mova                 m8, [cq+32* 1]
+    mova                 m9, [cq+32* 3]
+    mova                m10, [cq+32* 5]
+    mova                m11, [cq+32* 7]
+    mova                m12, [cq+32* 9]
+    mova                m13, [cq+32*11]
+    mova                m14, [cq+32*13]
+    jmp                tx2q
+.fast:
+    call .pass1_main
+    call m(iadst_8x8_internal_10bpc).main_end
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, m15
+    jmp                tx2q
+.pass2:
+    call m(idct_8x16_internal_10bpc).transpose
+    call m(iadst_8x16_internal_8bpc).main
+    call m(iadst_8x16_internal_8bpc).main_pass2_end
+    vpbroadcastd         m8, [pw_2048]
+    vpbroadcastd       xm12, [pw_4096]
+    REPX {vpermq x, x, q2031}, m0, m1, m2, m3
+    REPX {vpermq x, x, q3120}, m4, m5, m6, m7
+    psubw               m12, m8
+    jmp m(idct_8x16_internal_10bpc).end
+ALIGN function_align
+.pass1_main:
+    pmulld               m0, m14, [cq+32* 0]
+    pmulld               m7, m14, [cq+32*14]
+    pmulld               m1, m14, [cq+32* 2]
+    pmulld               m6, m14, [cq+32*12]
+    pmulld               m2, m14, [cq+32* 4]
+    pmulld               m5, m14, [cq+32*10]
+    pmulld               m3, m14, [cq+32* 6]
+    pmulld               m4, m14, [cq+32* 8]
+    REPX     {paddd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+    jmp m(iadst_8x8_internal_10bpc).main2
+
+INV_TXFM_8X16_FN flipadst, dct
+INV_TXFM_8X16_FN flipadst, adst
+INV_TXFM_8X16_FN flipadst, flipadst
+INV_TXFM_8X16_FN flipadst, identity, 35
+
+cglobal iflipadst_8x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    vpbroadcastd        m14, [pd_2896]
+    vpbroadcastd        m11, [pd_2048]
+    cmp                eobd, 43
+    jl .fast
+    add                  cq, 32
+    call m(iadst_8x16_internal_10bpc).pass1_main
+    call m(iflipadst_8x8_internal_10bpc).main_end
+    sub                  cq, 32
+    mova         [cq+32* 1], m0
+    mova         [cq+32* 3], m1
+    mova         [cq+32* 5], m2
+    mova         [cq+32* 7], m3
+    mova         [cq+32* 9], m4
+    mova         [cq+32*11], m5
+    mova         [cq+32*13], m6
+    mova                m15, m7
+    call m(iadst_8x16_internal_10bpc).pass1_main
+    call m(iflipadst_8x8_internal_10bpc).main_end
+    mova                 m8, [cq+32* 1]
+    mova                 m9, [cq+32* 3]
+    mova                m10, [cq+32* 5]
+    mova                m11, [cq+32* 7]
+    mova                m12, [cq+32* 9]
+    mova                m13, [cq+32*11]
+    mova                m14, [cq+32*13]
+    jmp                tx2q
+.fast:
+    call m(iadst_8x16_internal_10bpc).pass1_main
+    call m(iflipadst_8x8_internal_10bpc).main_end
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, m15
+    jmp                tx2q
+.pass2:
+    call m(idct_8x16_internal_10bpc).transpose
+    call m(iadst_8x16_internal_8bpc).main
+    call m(iadst_8x16_internal_8bpc).main_pass2_end
+    vpbroadcastd        m12, [pw_2048]
+    vpbroadcastd       xm13, [pw_4096]
+    mova                m11, m0
+    vpermq               m0, m7, q2031
+    mova                m10, m1
+    vpermq               m1, m6, q2031
+    mova                 m9, m2
+    vpermq               m2, m5, q2031
+    mova                 m8, m3
+    vpermq               m3, m4, q2031
+    vpermq               m4, m8, q3120
+    vpermq               m5, m9, q3120
+    vpermq               m6, m10, q3120
+    vpermq               m7, m11, q3120
+    psubw               m12, m13
+    jmp m(idct_8x16_internal_10bpc).end
+
+INV_TXFM_8X16_FN identity, dct
+INV_TXFM_8X16_FN identity, adst
+INV_TXFM_8X16_FN identity, flipadst
+INV_TXFM_8X16_FN identity, identity
+
+%macro IDTX16 3-4 ; src/dst, tmp, pw_1697x16, [pw_16384]
+    pmulhrsw            m%2, m%3, m%1
+%if %0 == 4 ; if downshifting by 1
+%ifnum %4
+    pmulhrsw            m%2, m%4
+%else ; without rounding
+    psraw               m%2, 1
+%endif
+%else
+    paddsw              m%1, m%1
+%endif
+    paddsw              m%1, m%2
+%endmacro
+
+cglobal iidentity_8x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+.pass1:
+    vpbroadcastd        m15, [pd_2896]
+    pmulld               m0, m15, [cq+32* 0]
+    pmulld               m8, m15, [cq+32* 1]
+    pmulld               m1, m15, [cq+32* 2]
+    pmulld               m9, m15, [cq+32* 3]
+    pmulld               m2, m15, [cq+32* 4]
+    pmulld              m10, m15, [cq+32* 5]
+    pmulld               m3, m15, [cq+32* 6]
+    pmulld              m11, m15, [cq+32* 7]
+    pmulld               m4, m15, [cq+32* 8]
+    pmulld              m12, m15, [cq+32* 9]
+    pmulld               m5, m15, [cq+32*10]
+    pmulld              m13, m15, [cq+32*11]
+    pmulld               m6, m15, [cq+32*12]
+    pmulld              m14, m15, [cq+32*13]
+    pmulld               m7, m15, [cq+32*14]
+    pmulld              m15,      [cq+32*15]
+    mova               [cq], m7
+    vpbroadcastd         m7, [pd_2048]
+    REPX     {paddd  x, m7}, m0,  m1,  m2,  m3,  m4,  m5,  m6, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    paddd                m7, [cq]
+    REPX     {psrad  x, 12}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    jmp                tx2q
+.pass2:
+    packssdw             m0, m8
+    packssdw             m1, m9
+    packssdw             m2, m10
+    packssdw             m3, m11
+    packssdw             m4, m12
+    packssdw             m5, m13
+    packssdw             m6, m14
+    packssdw            m13, m7, m15
+    vpbroadcastd         m8, [pw_1697x16]
+    REPX {IDTX16   x, 9, 8}, 0, 1, 2, 3, 4, 5, 6, 13
+    vpbroadcastd         m7, [pixel_10bpc_max]
+    vpbroadcastd        m12, [pw_2048]
+    call .pass2_end
+    RET
+ALIGN function_align
+.pass2_end:
+    punpckhwd            m9, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m6, m13
+    punpcklwd            m6, m13
+    punpckhwd           m13, m4, m5
+    punpcklwd            m4, m5
+    punpcklwd            m5, m2, m3
+    punpckhwd            m2, m3
+    punpckhdq            m3, m0, m5
+    punpckldq            m0, m5
+    punpckhdq           m11, m9, m2
+    punpckldq            m9, m2
+    punpckldq            m2, m4, m6
+    punpckhdq            m4, m6
+    punpckldq            m6, m13, m1
+    punpckhdq           m13, m1
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    punpcklqdq           m8, m9, m6
+    punpckhqdq           m9, m6
+    punpcklqdq          m10, m11, m13
+    punpckhqdq          m11, m13
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(iidentity_8x8_internal_10bpc).write_2x8x2_start
+    pmulhrsw             m0, m12, m2
+    pmulhrsw             m1, m12, m3
+    call m(iidentity_8x8_internal_10bpc).write_2x8x2_zero
+    pmulhrsw             m0, m12, m8
+    pmulhrsw             m1, m12, m9
+    lea                dstq, [dstq+strideq*4]
+    call m(iidentity_8x8_internal_10bpc).write_2x8x2_zero
+    pmulhrsw             m0, m12, m10
+    pmulhrsw             m1, m12, m11
+    call m(iidentity_8x8_internal_10bpc).write_2x8x2_zero
+    ret
+
+INV_TXFM_8X16_FN dct, dct,       0, 12
+INV_TXFM_8X16_FN dct, identity, 35, 12
+INV_TXFM_8X16_FN dct, adst,      0, 12
+INV_TXFM_8X16_FN dct, flipadst,  0, 12
+
+cglobal idct_8x16_internal_12bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(idct_8x16_internal_10bpc).pass1
+.pass2:
+    lea                  r6, [rsp+32*4]
+    call .transpose
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    mova         [cq+32* 8], m0
+    mova         [cq+32*10], m2
+    mova         [cq+32*12], m4
+    mova         [cq+32*14], m6
+    pmaxsd               m0, m12, [cq+32* 1]
+    pmaxsd               m4, m12, m1
+    pmaxsd               m1, m12, [cq+32* 3]
+    pmaxsd               m2, m12, [cq+32* 5]
+    pmaxsd               m6, m12, m5
+    pmaxsd               m5, m12, m3
+    pmaxsd               m3, m12, [cq+32* 7]
+    pmaxsd               m7, m12
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m14, [pd_2896]
+    call m(idct_8x16_internal_10bpc).main_oddhalf
+    pmaxsd               m0, m12, [cq+32* 0]
+    pmaxsd               m1, m12, [cq+32* 2]
+    pmaxsd               m2, m12, [cq+32* 4]
+    pmaxsd               m3, m12, [cq+32* 6]
+    pmaxsd               m4, m12, [cq+32* 8]
+    pmaxsd               m5, m12, [cq+32*10]
+    pmaxsd               m6, m12, [cq+32*12]
+    pmaxsd               m7, m12, [cq+32*14]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    vpbroadcastd        m11, [pd_8]
+    REPX    {paddd  x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_16x8_internal_10bpc).pass1_rotations
+    REPX       {psrad x, 4}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+.end:
+    packssdw             m0, m1
+    packssdw             m1, m2, m3
+    packssdw             m2, m4, m5
+    packssdw             m3, m6, m7
+    packssdw             m4, m8, m9
+    packssdw             m5, m10, m11
+    packssdw             m6, m12, m13
+    packssdw             m7, m14, m15
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q3120
+    call m(idct_8x8_internal_12bpc).write_8x4_start
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m2, q3120
+    vpermq               m1, m3, q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m4, q3120
+    vpermq               m1, m5, q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m6, q3120
+    vpermq               m1, m7, q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    RET
+ALIGN function_align
+.transpose:
+    mova         [cq+32* 8], m8
+    mova         [cq+32* 9], m9
+    mova         [cq+32*10], m10
+    mova         [cq+32*11], m11
+    call m(idct_8x8_internal_12bpc).transpose_8x8
+    mova         [cq+32* 0], m0
+    mova         [cq+32* 1], m1
+    mova         [cq+32* 2], m2
+    mova         [cq+32* 3], m3
+    mova         [cq+32* 4], m4
+    mova         [cq+32* 5], m5
+    mova         [cq+32* 6], m6
+    mova         [cq+32* 7], m7
+    mova                 m0, [cq+32* 8]
+    mova                 m1, [cq+32* 9]
+    mova                 m2, [cq+32*10]
+    mova                 m3, [cq+32*11]
+    mova                 m4, m12
+    mova                 m5, m13
+    mova                 m6, m14
+    mova                 m7, m15
+    jmp m(idct_8x8_internal_12bpc).transpose_8x8
+
+INV_TXFM_8X16_FN adst, dct,       0, 12
+INV_TXFM_8X16_FN adst, adst,      0, 12
+INV_TXFM_8X16_FN adst, flipadst,  0, 12
+INV_TXFM_8X16_FN adst, identity, 35, 12
+
+cglobal iadst_8x16_internal_12bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(iadst_8x16_internal_10bpc).pass1
+.pass2:
+    lea                  r6, [rsp+32*4]
+    call .pass2_main
+    call m(iadst_16x8_internal_10bpc).pass1_rotations
+.pass2_end:
+    REPX      {psrad x, 4 }, m0,  m1,  m2,  m3,  m12, m13, m14, m15
+    REPX      {psrad x, 15}, m4,  m5,  m6,  m7,  m8,  m9,  m10, m11
+    jmp m(idct_8x16_internal_12bpc).end
+ALIGN function_align
+.pass2_main:
+    call m(idct_8x16_internal_12bpc).transpose
+    vpbroadcastd        m13, [clip_18b_min]
+    vpbroadcastd        m14, [clip_18b_max]
+    mova         [cq+32* 8], m0
+    mova         [cq+32*11], m3
+    mova         [cq+32*12], m4
+    mova         [cq+32*15], m7
+    pmaxsd               m0, m13, [cq+32* 2] ;  2
+    pmaxsd               m3, m13, m1         ;  9
+    pmaxsd               m1, m13, m5         ; 13
+    pmaxsd               m4, m13, m2         ; 10
+    pmaxsd               m2, m13, [cq+32* 6] ;  6
+    pmaxsd               m5, m13, [cq+32* 5] ;  5
+    pmaxsd               m6, m13, m6         ; 14
+    pmaxsd               m7, m13, [cq+32* 1] ;  1
+    REPX    {pminsd x, m14}, m0, m1, m2, m3, m4, m5, m6, m7
+    vpbroadcastd        m12, [pd_2048]
+    vpbroadcastd        m15, [pd_2896]
+    call m(iadst_16x8_internal_10bpc).main_part1
+    pmaxsd               m0, m13, [cq+32* 0] ;  0
+    pmaxsd               m1, m13, [cq+32*15] ; 15
+    pmaxsd               m2, m13, [cq+32* 4] ;  4
+    pmaxsd               m3, m13, [cq+32*11] ; 11
+    pmaxsd               m4, m13, [cq+32* 8] ;  8
+    pmaxsd               m5, m13, [cq+32* 7] ;  7
+    pmaxsd               m6, m13, [cq+32*12] ; 12
+    pmaxsd               m7, m13, [cq+32* 3] ;  3
+    REPX    {pminsd x, m14}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(iadst_16x8_internal_10bpc).main_part2
+    vpbroadcastd        m14, [pd_17408]
+    psrld               m15, 11              ; pd_1
+    psubd               m13, m14, m15        ; pd_17407
+    pslld               m15, 3               ; pd_8
+    ret
+
+INV_TXFM_8X16_FN flipadst, dct,       0, 12
+INV_TXFM_8X16_FN flipadst, adst,      0, 12
+INV_TXFM_8X16_FN flipadst, flipadst,  0, 12
+INV_TXFM_8X16_FN flipadst, identity, 35, 12
+
+cglobal iflipadst_8x16_internal_12bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(iflipadst_8x16_internal_10bpc).pass1
+.pass2:
+    lea                  r6, [rsp+32*4]
+    call m(iadst_8x16_internal_12bpc).pass2_main
+    call m(iflipadst_16x8_internal_10bpc).pass1_rotations
+    jmp m(iadst_8x16_internal_12bpc).pass2_end
+
+INV_TXFM_8X16_FN identity, dct,      0, 12
+INV_TXFM_8X16_FN identity, adst,     0, 12
+INV_TXFM_8X16_FN identity, flipadst, 0, 12
+INV_TXFM_8X16_FN identity, identity, 0, 12
+
+cglobal iidentity_8x16_internal_12bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    jmp m(iidentity_8x16_internal_10bpc).pass1
+.pass2:
+    call .pass2_main
+    packssdw             m0, m8
+    packssdw             m1, m9
+    packssdw             m2, m10
+    packssdw             m3, m11
+    packssdw             m4, m12
+    packssdw             m5, m13
+    packssdw             m6, m14
+    packssdw            m13, m7, m15
+    vpbroadcastd         m7, [pixel_12bpc_max]
+    vpbroadcastd        m12, [pw_16384]
+    call m(iidentity_8x16_internal_10bpc).pass2_end
+    RET
+ALIGN function_align
+.pass2_main:
+    mova               [cq], m7
+    vpbroadcastd         m7, [clip_18b_min]
+    REPX     {pmaxsd x, m7}, m0,  m1,  m2,  m3,  m4,  m5,  m6, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    pmaxsd               m7, [cq]
+    mova               [cq], m15
+    vpbroadcastd        m15, [clip_18b_max]
+    REPX    {pminsd x, m15}, m0,  m1,  m2,  m3,  m4,  m5,  m6, m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14
+    pminsd              m15, [cq]
+    mova               [cq], m7
+    vpbroadcastd         m7, [pd_5793]
+    REPX     {pmulld x, m7}, m0,  m1,  m2,  m3,  m4,  m5,  m6, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    pmulld               m7, [cq]
+    mova               [cq], m15
+    vpbroadcastd        m15, [pd_1024]
+    REPX    {paddd  x, m15}, m0,  m1,  m2,  m3,  m4,  m5,  m6, m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14
+    paddd               m15, [cq]
+    REPX     {psrad  x, 14}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    ret
+
+%macro INV_TXFM_16X4_FN 2-3 10 ; type1, type2, bitdepth
+    INV_TXFM_FN          %1, %2, 0, 16x4, %3
+%ifidn %1_%2, dct_dct
+    vpbroadcastd         m3, [dconly_%3bpc]
+%if %3 = 10
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 4
+.dconly2:
+    add                 r6d, 384
+    sar                 r6d, 9
+.dconly3:
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    movd                xm0, r6d
+    paddsw              xm0, xm3
+    vpbroadcastw         m0, xm0
+.dconly_loop:
+    paddsw               m1, m0, [dstq+strideq*0]
+    paddsw               m2, m0, [dstq+strideq*1]
+    psubusw              m1, m3
+    psubusw              m2, m3
+    mova   [dstq+strideq*0], m1
+    mova   [dstq+strideq*1], m2
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    RET
+%else
+    jmp m(inv_txfm_add_dct_dct_16x4_10bpc).dconly
+%endif
+%endif
+%endmacro
+
+INV_TXFM_16X4_FN dct, dct
+INV_TXFM_16X4_FN dct, identity
+INV_TXFM_16X4_FN dct, adst
+INV_TXFM_16X4_FN dct, flipadst
+
+cglobal idct_16x4_internal_10bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [clip_18b_min]
+    vpbroadcastd         m9, [clip_18b_max]
+.pass1:
+    vbroadcasti128       m0, [cq+16* 0]
+    vbroadcasti128       m4, [cq+16* 4]
+    vbroadcasti128       m1, [cq+16* 2]
+    vbroadcasti128       m7, [cq+16* 6]
+    vbroadcasti128       m5, [cq+16*10]
+    vbroadcasti128       m2, [cq+16* 8]
+    vbroadcasti128       m6, [cq+16*12]
+    vbroadcasti128       m3, [cq+16*14]
+    shufpd               m0, m4, 0x0c ;  0  4
+    shufpd               m1, m5, 0x0c ;  2 10
+    shufpd               m2, m6, 0x0c ;  8 12
+    shufpd               m3, m7, 0x0c ; 14  6
+    call .pass1_main
+    vbroadcasti128      m10, [cq+16* 1]
+    vbroadcasti128       m4, [cq+16* 5]
+    vbroadcasti128      m11, [cq+16*15]
+    vbroadcasti128       m5, [cq+16*11]
+    shufpd              m10, m4, 0x0c ;  1  5
+    shufpd              m11, m5, 0x0c ; 15 11
+    vbroadcasti128       m5, [cq+16* 9]
+    vbroadcasti128       m4, [cq+16*13]
+    shufpd               m5, m4, 0x0c ;  9 13
+    vbroadcasti128       m6, [cq+16* 7]
+    vbroadcasti128       m4, [cq+16* 3]
+    shufpd               m6, m4, 0x0c ;  7  3
+    call .pass1_main2
+    pcmpeqd              m4, m4
+    REPX      {psubd x, m4}, m0, m1, m2, m3
+    call .pass1_main3
+    REPX      {psrad x, 1 }, m0, m1, m2, m3, m4, m5, m6, m7
+    jmp                tx2q
+.pass2:
+    call .transpose_4x16_packed
+    lea                  r6, [deint_shuf+128]
+    call m(idct_16x4_internal_8bpc).main
+.end:
+    vpbroadcastd         m4, [pw_2048]
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    vpbroadcastd         m5, [pixel_10bpc_max]
+.end2:
+    paddw                m0, [dstq+strideq*0]
+    paddw                m1, [dstq+strideq*1]
+.end3:
+    lea                  r6, [dstq+strideq*2]
+    paddw                m2, [r6  +strideq*0]
+    paddw                m3, [r6  +strideq*1]
+    pxor                 m4, m4
+    REPX {mova [cq+32*x], m4}, 0, 1, 2, 3, 4, 5, 6, 7
+    REPX     {pmaxsw x, m4}, m0, m1, m2, m3
+    REPX     {pminsw x, m5}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [r6  +strideq*0], m2
+    mova   [r6  +strideq*1], m3
+    RET
+ALIGN function_align
+.pass1_main:
+    vpbroadcastd         m7, [pd_2048]
+    call m(idct_8x4_internal_10bpc).main
+    psubd                m3, m0, m4   ; idct8 out7 out6
+    paddd                m0, m4       ; idct8 out0 out1
+    paddd                m1, m2, m5   ; idct8 out3 out2
+    psubd                m2, m5       ; idct8 out4 out5
+    ret
+ALIGN function_align
+.pass1_main2:
+    ITX_MULSUB_2D        10, 11, 4, 12, 13, 7,  401_1931, 4076_3612, 1
+    ITX_MULSUB_2D         5,  6, 4, 12, 13, 7, 3166_3920, 2598_1189, 1
+    vbroadcasti128      m12, [pd_3784_m3784]
+    psubd                m4, m10, m5
+    paddd               m10, m5       ;  t8  t11
+    psignd               m4, m12      ;  t9  t10
+    psubd                m5, m11, m6
+    paddd               m11, m6       ; t15  t12
+    psignd               m5, m12      ; t14  t13
+    vpbroadcastd         m6, [pd_1567]
+    vpbroadcastd        m13, [pd_3784]
+    REPX     {pmaxsd x, m8}, m5, m4
+    REPX     {pminsd x, m9}, m5, m4
+    pmulld              m12, m5
+    pmulld               m5, m6
+    vbroadcasti128       m6, [pd_1567_m1567]
+    pmulld              m13, m4
+    pmulld               m4, m6
+    REPX     {pmaxsd x, m8}, m10, m11, m0, m1
+    REPX     {pminsd x, m9}, m10, m11, m0, m1
+    paddd               m12, m7
+    paddd                m5, m7
+    paddd                m4, m12
+    psubd                m5, m13
+    psrad                m4, 12       ; t14a t10a
+    psrad                m5, 12       ; t9a  t13a
+    vpbroadcastd        m12, [pd_2896]
+    punpckhqdq           m6, m11, m5
+    punpcklqdq          m11, m4
+    punpckhqdq           m4, m10, m4
+    punpcklqdq          m10, m5
+    psubd                m5, m11, m6  ; t12a t13
+    paddd               m11, m6       ; t15a t14
+    psubd                m6, m10, m4  ; t11a t10
+    paddd               m10, m4       ; t8a  t9
+    REPX     {pmaxsd x, m8}, m5, m6
+    REPX     {pminsd x, m9}, m5, m6
+    pmulld               m5, m12
+    pmulld               m6, m12
+    REPX     {pmaxsd x, m8}, m2, m3, m11, m10
+    REPX     {pminsd x, m9}, m2, m3, m11, m10
+    ret
+ALIGN function_align
+.pass1_main3:
+    paddd                m5, m7
+    psubd                m4, m5, m6
+    paddd                m5, m6
+    psrad                m4, 12      ; t11 t10a
+    psrad                m5, 12      ; t12 t13a
+    psubd                m7, m0, m11 ; out15 out14
+    paddd                m0, m11     ; out0  out1
+    psubd                m6, m1, m5  ; out12 out13
+    paddd                m1, m5      ; out3  out2
+    psubd                m5, m2, m4  ; out11 out10
+    paddd                m2, m4      ; out4  out5
+    psubd                m4, m3, m10 ; out8  out9
+    paddd                m3, m10     ; out7  out6
+    REPX {pshufd x, x, q1032}, m1, m3, m5, m7
+    ret
+ALIGN function_align
+.transpose_4x16_packed:
+    vbroadcasti128       m8, [deint_shuf]
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    REPX     {pshufb x, m8}, m0, m2, m4, m6
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpckhqdq           m2, m4, m6
+    punpcklqdq           m4, m6
+    vperm2i128           m3, m1, m2, 0x31
+    vinserti128          m1, xm2, 1
+    vperm2i128           m2, m0, m4, 0x31
+    vinserti128          m0, xm4, 1
+    ret
+
+INV_TXFM_16X4_FN adst, dct
+INV_TXFM_16X4_FN adst, adst
+INV_TXFM_16X4_FN adst, flipadst
+INV_TXFM_16X4_FN adst, identity
+
+cglobal iadst_16x4_internal_10bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    call m(iadst_4x16_internal_10bpc).main
+    psrad               m11, 11 ; pd_1
+    REPX     {paddd x, m11}, m0, m1, m2, m3
+    paddd                m4, m5, m11
+    paddd                m5, m6, m11
+    paddd                m6, m7, m11
+    paddd                m7, m8, m11
+.pass1_end:
+    REPX {pshufd x, x, q1032}, m0, m2, m4, m6
+    REPX       {psrad x, 1}, m0, m1, m2, m3, m4, m5, m6, m7
+    jmp                tx2q
+.pass2:
+    call m(idct_16x4_internal_10bpc).transpose_4x16_packed
+    lea                  r6, [deint_shuf+128]
+    call m(iadst_16x4_internal_8bpc).main
+    jmp m(idct_16x4_internal_10bpc).end
+ALIGN function_align
+.main:
+    vpbroadcastd         m6, [pd_1321]
+    mova                 m0, [cq+32*0]
+    mova                 m1, [cq+32*1]
+    vpbroadcastd         m7, [pd_2482]
+    mova                 m2, [cq+32*6]
+    mova                 m3, [cq+32*7]
+    pmulld               m4, m0, m6
+    pmulld               m5, m1, m6    ; 1321*in0
+    pmulld               m9, m2, m7
+    pmulld               m8, m3, m7    ; 2482*in3
+    paddd                m4, m9
+    paddd                m8, m5        ; 1321*in0 + 2482*in3
+    pmulld               m5, m0, m7
+    pmulld               m9, m1, m7    ; 2482*in0
+    paddd                m0, m2
+    paddd                m1, m3        ; in0 + in3
+    paddd                m7, m6        ; pd_3803
+    pmulld               m2, m7
+    pmulld               m3, m7        ; 3803*in3
+    psubd                m5, m2
+    psubd                m9, m3        ; 2482*in0 - 3803*in3
+    mova                 m2, [cq+32*4]
+    pmulld              m10, m7, m2
+    pmulld               m3, m6, m2
+    psubd                m2, m0
+    mova                 m0, [cq+32*5]
+    pmulld               m7, m0        ; 3803*in2
+    pmulld               m6, m0        ; 1321*in2
+    psubd                m0, m1        ; in2 - in0 - in3
+    vpbroadcastd         m1, [pd_m3344]
+    paddd                m4, m10
+    paddd                m7, m8        ; t0
+    psubd                m5, m3
+    psubd                m9, m6        ; t1
+    pmulld               m2, m1
+    pmulld               m0, m1        ; t2
+    pmulld               m3, m1, [cq+32*2]
+    pmulld               m1, [cq+32*3] ; -t3
+    ret
+ALIGN function_align
+.main_end:
+    ; expects: m6 = rnd
+    paddd                m5, m6
+    paddd                m9, m6
+    paddd               m10, m4, m5
+    paddd                m4, m6
+    paddd                m8, m7, m6
+    paddd                m7, m9
+    psubd                m4, m3        ; out0 (unshifted)
+    psubd                m5, m3        ; out1 (unshifted)
+    paddd                m2, m6        ; out2 (unshifted)
+    paddd                m3, m10       ; out3 (unshifted)
+    psubd                m8, m1        ; out4 (unshifted)
+    psubd                m9, m1        ; out5 (unshifted)
+    paddd                m6, m0        ; out6 (unshifted)
+    paddd                m7, m1        ; out7 (unshifted)
+    ret
+
+INV_TXFM_16X4_FN flipadst, dct
+INV_TXFM_16X4_FN flipadst, adst
+INV_TXFM_16X4_FN flipadst, flipadst
+INV_TXFM_16X4_FN flipadst, identity
+
+cglobal iflipadst_16x4_internal_10bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    call m(iadst_4x16_internal_10bpc).main
+    psrad               m11, 11 ; pd_1
+    paddd                m4, m3, m11
+    paddd                m3, m5, m11
+    paddd                m5, m2, m11
+    paddd                m2, m6, m11
+    paddd                m6, m1, m11
+    paddd                m1, m7, m11
+    paddd                m7, m0, m11
+    paddd                m0, m8, m11
+    jmp m(iadst_16x4_internal_10bpc).pass1_end
+.pass2:
+    call m(idct_16x4_internal_10bpc).transpose_4x16_packed
+    lea                  r6, [deint_shuf+128]
+    call m(iadst_16x4_internal_8bpc).main
+    vpbroadcastd         m4, [pw_2048]
+    pmulhrsw             m5, m3, m4
+    pmulhrsw             m6, m2, m4
+    pmulhrsw             m2, m1, m4
+    pmulhrsw             m3, m0, m4
+    paddw                m0, m5, [dstq+strideq*0]
+    paddw                m1, m6, [dstq+strideq*1]
+    vpbroadcastd         m5, [pixel_10bpc_max]
+    jmp m(idct_16x4_internal_10bpc).end3
+
+INV_TXFM_16X4_FN identity, dct
+INV_TXFM_16X4_FN identity, adst
+INV_TXFM_16X4_FN identity, flipadst
+INV_TXFM_16X4_FN identity, identity
+
+cglobal iidentity_16x4_internal_10bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [pd_5793]
+    vpermq               m0, [cq+32*0], q3120 ; 0 1
+    vpermq               m1, [cq+32*1], q3120 ; 2 3
+    vpermq               m2, [cq+32*2], q3120 ; 4 5
+    vpermq               m3, [cq+32*3], q3120 ; 6 7
+    vpermq               m4, [cq+32*4], q3120 ; 8 9
+    vpermq               m5, [cq+32*5], q3120 ; a b
+    vpermq               m6, [cq+32*6], q3120 ; c d
+    vpermq               m7, [cq+32*7], q3120 ; e f
+    vpbroadcastd         m9, [pd_3072]
+    REPX     {pmulld x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {paddd  x, m9}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad  x, 12}, m0, m1, m2, m3, m4, m5, m6, m7
+    jmp                tx2q
+.pass2:
+    call m(idct_16x4_internal_10bpc).transpose_4x16_packed
+    vpbroadcastd         m7, [pw_1697x8]
+    pmulhrsw             m4, m7, m0
+    pmulhrsw             m5, m7, m1
+    pmulhrsw             m6, m7, m2
+    pmulhrsw             m7, m3
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    jmp m(idct_16x4_internal_10bpc).end
+
+INV_TXFM_16X4_FN dct, dct,      12
+INV_TXFM_16X4_FN dct, identity, 12
+INV_TXFM_16X4_FN dct, adst,     12
+INV_TXFM_16X4_FN dct, flipadst, 12
+
+cglobal idct_16x4_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [clip_20b_min]
+    vpbroadcastd         m9, [clip_20b_max]
+    jmp m(idct_16x4_internal_10bpc).pass1
+.pass2:
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    ; deinterleave
+    REPX {pshufd x, x, q3120}, m0, m1, m2, m3, m4, m5, m6, m7
+    ; transpose
+    punpcklqdq           m8, m0, m1
+    punpckhqdq           m0, m1
+    punpcklqdq           m9, m2, m3
+    punpckhqdq           m2, m3
+    punpcklqdq          m10, m4, m5
+    punpckhqdq           m4, m5
+    punpcklqdq          m11, m6, m7
+    punpckhqdq           m6, m7
+    vperm2i128           m3,  m0,  m2, 0x31   ; out6
+    vperm2i128           m1,  m0,  m2, 0x20   ; out2
+    vperm2i128           m7,  m4,  m6, 0x31   ; out7
+    vperm2i128           m5,  m4,  m6, 0x20   ; out3
+    vperm2i128          m13, m10, m11, 0x31   ; out5
+    vperm2i128          m12, m10, m11, 0x20   ; out1
+    vperm2i128          m11,  m8,  m9, 0x31   ; out4
+    vperm2i128          m10,  m8,  m9, 0x20   ; out0
+    call m(idct_4x16_internal_10bpc).pass1_main
+    pmulld               m0, m6, m10
+    pmulld               m2, m6, m11
+    pmulld               m4, m6, m12
+    pmulld               m6, m13
+    vpbroadcastd        m10, [pd_17408]
+    call m(idct_4x16_internal_10bpc).pass1_main2
+    REPX       {psrad x, 4}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    vpbroadcastd         m5, [pixel_12bpc_max]
+    REPX {vpermq x, x, q3120}, m0, m1, m2, m3
+    jmp m(idct_16x4_internal_10bpc).end2
+
+INV_TXFM_16X4_FN adst, dct,      12
+INV_TXFM_16X4_FN adst, adst,     12
+INV_TXFM_16X4_FN adst, flipadst, 12
+INV_TXFM_16X4_FN adst, identity, 12
+
+cglobal iadst_16x4_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(iadst_16x4_internal_10bpc).pass1
+.pass2:
+    call .pass2_main
+    REPX {vpermq x, x, q3120}, m0, m1, m2, m3
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    jmp m(idct_16x4_internal_10bpc).end2
+ALIGN function_align
+.pass2_main:
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m6, m7
+    pmaxsd               m8, m4, m12
+    pmaxsd               m9, m5, m12
+    REPX    {pminsd x, m13}, m0, m1, m2, m3
+    call m(iadst_8x4_internal_12bpc).transpose_4x8
+    mova          [cq+32*0], m0
+    mova          [cq+32*2], m1
+    mova          [cq+32*4], m2
+    mova          [cq+32*6], m3
+    pminsd               m0, m8, m13
+    pminsd               m1, m9, m13
+    pminsd               m2, m6, m13
+    pminsd               m3, m7, m13
+    call m(iadst_8x4_internal_12bpc).transpose_4x8
+    mova          [cq+32*1], m0
+    mova          [cq+32*3], m1
+    mova          [cq+32*5], m2
+    mova          [cq+32*7], m3
+    call m(iadst_16x4_internal_10bpc).main
+    vpbroadcastd         m6, [pd_2048]
+    call m(iadst_16x4_internal_10bpc).main_end
+    psrad                m0, m4, 15
+    psrad                m1, m5, 15
+    psrad                m2, 15
+    psrad                m3, 15
+    psrad                m4, m8, 15
+    psrad                m5, m9, 15
+    psrad                m6, 15
+    psrad                m7, 15
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    vpbroadcastd         m4, [pw_16384]
+    vpbroadcastd         m5, [pixel_12bpc_max]
+    ret
+
+INV_TXFM_16X4_FN flipadst, dct,      12
+INV_TXFM_16X4_FN flipadst, adst,     12
+INV_TXFM_16X4_FN flipadst, flipadst, 12
+INV_TXFM_16X4_FN flipadst, identity, 12
+
+cglobal iflipadst_16x4_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(iflipadst_16x4_internal_10bpc).pass1
+.pass2:
+    call m(iadst_16x4_internal_12bpc).pass2_main
+    vpermq               m7, m0, q3120
+    vpermq               m6, m1, q3120
+    vpermq               m1, m2, q3120
+    vpermq               m0, m3, q3120
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    pmulhrsw             m2, m6, m4
+    pmulhrsw             m3, m7, m4
+    jmp m(idct_16x4_internal_10bpc).end2
+
+INV_TXFM_16X4_FN identity, dct,      12
+INV_TXFM_16X4_FN identity, adst,     12
+INV_TXFM_16X4_FN identity, flipadst, 12
+INV_TXFM_16X4_FN identity, identity, 12
+
+cglobal iidentity_16x4_internal_12bpc, 0, 7, 14, dst, stride, c, eob, tx2
+    vpbroadcastd         m8, [pd_1697]
+    vpermq               m0, [cq+32*0], q3120 ; 0 1
+    vpermq               m1, [cq+32*1], q3120 ; 2 3
+    vpermq               m2, [cq+32*2], q3120 ; 4 5
+    vpermq               m3, [cq+32*3], q3120 ; 6 7
+    vpbroadcastd         m9, [pd_3072]
+    pmulld               m4, m8, m0
+    pmulld               m5, m8, m1
+    pmulld               m6, m8, m2
+    pmulld               m7, m8, m3
+    vpermq              m10, [cq+32*4], q3120 ; 8 9
+    vpermq              m11, [cq+32*5], q3120 ; a b
+    vpermq              m12, [cq+32*6], q3120 ; c d
+    vpermq              m13, [cq+32*7], q3120 ; e f
+    REPX     {paddd  x, m9}, m4, m5, m6, m7
+    REPX     {psrad  x, 12}, m4, m5, m6, m7
+    paddd                m0, m4
+    pmulld               m4, m8, m10
+    paddd                m1, m5
+    pmulld               m5, m8, m11
+    paddd                m2, m6
+    pmulld               m6, m8, m12
+    paddd                m3, m7
+    pmulld               m7, m8, m13
+    REPX     {paddd  x, m9}, m4, m5, m6, m7
+    REPX     {psrad  x, 12}, m4, m5, m6, m7
+    paddd                m4, m10
+    paddd                m5, m11
+    paddd                m6, m12
+    paddd                m7, m13
+    jmp                tx2q
+.pass2:
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    vpbroadcastd         m8, [pd_5793]
+    vpbroadcastd         m9, [pd_2048]
+    REPX     {pmulld x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {paddd  x, m9}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad  x, 15}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_16x4_internal_10bpc).transpose_4x16_packed
+    vpbroadcastd         m4, [pw_16384]
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    vpbroadcastd         m5, [pixel_12bpc_max]
+    jmp m(idct_16x4_internal_10bpc).end2
+
+%macro INV_TXFM_16X8_FN 2-3 10 ; type1, type2, bitdepth
+    INV_TXFM_FN          %1, %2, 0, 16x8, %3
+%ifidn %1_%2, dct_dct
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_%3bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 8
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    jmp m(inv_txfm_add_dct_dct_16x4_10bpc).dconly2
+%endif
+%endmacro
+
+INV_TXFM_16X8_FN dct, dct
+INV_TXFM_16X8_FN dct, identity
+INV_TXFM_16X8_FN dct, adst
+INV_TXFM_16X8_FN dct, flipadst
+
+cglobal idct_16x8_internal_10bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    vpbroadcastd        m14, [pd_2896]
+    pmulld               m0, m14, [cq+32* 1]
+    pmulld               m1, m14, [cq+32* 3]
+    pmulld               m2, m14, [cq+32* 5]
+    pmulld               m3, m14, [cq+32* 7]
+    pmulld               m4, m14, [cq+32* 9]
+    pmulld               m5, m14, [cq+32*11]
+    pmulld               m6, m14, [cq+32*13]
+    pmulld               m7, m14, [cq+32*15]
+    vpbroadcastd        m11, [pd_2048]
+    lea                  r6, [rsp+32*4]
+    call m(idct_8x16_internal_10bpc).main_oddhalf_rect2
+    pmulld               m0, m14, [cq+32* 0]
+    pmulld               m1, m14, [cq+32* 2]
+    pmulld               m2, m14, [cq+32* 4]
+    pmulld               m3, m14, [cq+32* 6]
+    pmulld               m4, m14, [cq+32* 8]
+    pmulld               m5, m14, [cq+32*10]
+    pmulld               m6, m14, [cq+32*12]
+    pmulld               m7, m14, [cq+32*14]
+    call m(idct_8x8_internal_10bpc).main_rect2
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    psrld               m11, 11 ; pd_1
+    REPX    {paddd  x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    call .pass1_rotations
+    REPX       {psrad x, 1}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    jmp                tx2q
+.pass2:
+    call .transpose
+    call m(idct_16x8_internal_8bpc).main
+    vpbroadcastd        m10, [pw_2048]
+.end:
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    pmulhrsw             m2, m10
+    pmulhrsw             m3, m10
+    call .write_16x4_start
+.end2:
+    pmulhrsw             m0, m4, m10
+    pmulhrsw             m1, m5, m10
+    pmulhrsw             m2, m6, m10
+    pmulhrsw             m3, m7, m10
+    call .write_16x4_zero
+    RET
+ALIGN function_align
+.pass1_rotations:
+    mova                m14, [r6-32*4]
+    mova                m13, [r6-32*3]
+    mova                m12, [r6-32*2]
+    mova                m11, [r6-32*1]
+    mova                m10, [r6+32*0]
+    mova                 m9, [r6+32*1]
+    mova                 m8, [r6+32*2]
+    psubd               m15, m0, m14       ; out15
+    paddd                m0, m14           ; out0
+    psubd               m14, m1, m13       ; out14
+    paddd                m1, m13           ; out1
+    psubd               m13, m2, m12       ; out13
+    paddd                m2, m12           ; out2
+    psubd               m12, m3, m11       ; out12
+    paddd                m3, m11           ; out3
+    psubd               m11, m4, m10       ; out11
+    paddd                m4, m10           ; out4
+    psubd               m10, m5, m9        ; out10
+    paddd                m5, m9            ; out5
+    psubd                m9, m6, m8        ; out9
+    paddd                m6, m8            ; out6
+    psubd                m8, m7, [r6+32*3] ; out8
+    paddd                m7, [r6+32*3]     ; out7
+    ret
+ALIGN function_align
+.transpose:
+    lea                  r6, [deint_shuf+128]
+.transpose2:
+    packssdw             m0, m8
+    packssdw             m1, m9
+    packssdw             m2, m10
+    packssdw             m3, m11
+    packssdw             m4, m12
+    packssdw             m5, m13
+    packssdw             m6, m14
+    packssdw             m7, m15
+.transpose3:
+    punpckhwd            m8, m0, m1
+    punpcklwd            m0, m1
+    punpcklwd            m1, m2, m3
+    punpckhwd            m2, m3
+    punpckhwd            m3, m4, m5
+    punpcklwd            m4, m5
+    punpckhwd            m5, m6, m7
+    punpcklwd            m6, m7
+    punpckhdq            m7, m4, m6
+    punpckldq            m4, m6
+    punpckldq            m6, m8, m2
+    punpckhdq            m8, m2
+    punpckhdq            m2, m0, m1
+    punpckldq            m0, m1
+    punpckhdq            m1, m3, m5
+    punpckldq            m3, m5
+    punpcklqdq           m5, m6, m3
+    punpckhqdq           m6, m3
+    punpckhqdq           m3, m2, m7
+    punpcklqdq           m2, m7
+    punpcklqdq           m7, m8, m1
+    punpckhqdq           m8, m1
+    punpckhqdq           m1, m0, m4
+    punpcklqdq           m0, m4
+    vperm2i128           m4, m0, m5, 0x31
+    vinserti128          m0, xm5, 1
+    vperm2i128           m5, m1, m6, 0x31
+    vinserti128          m1, xm6, 1
+    vperm2i128           m6, m2, m7, 0x31
+    vinserti128          m2, xm7, 1
+    vperm2i128           m7, m3, m8, 0x31
+    vinserti128          m3, xm8, 1
+    ret
+ALIGN function_align
+.write_16x4_start:
+    vpbroadcastd         m9, [pixel_10bpc_max]
+    lea                  r3, [strideq*3]
+    pxor                 m8, m8
+.write_16x4_zero:
+    REPX {mova [cq+32*x], m8}, 0, 1, 2, 3, 4, 5, 6, 7
+    add                  cq, 32*8
+.write_16x4:
+    paddw                m0, [dstq+strideq*0]
+    paddw                m1, [dstq+strideq*1]
+    paddw                m2, [dstq+strideq*2]
+    paddw                m3, [dstq+r3       ]
+    REPX     {pmaxsw x, m8}, m0, m1, m2, m3
+    REPX     {pminsw x, m9}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+r3       ], m3
+    lea                dstq, [dstq+strideq*4]
+    ret
+
+INV_TXFM_16X8_FN adst, dct
+INV_TXFM_16X8_FN adst, adst
+INV_TXFM_16X8_FN adst, flipadst
+INV_TXFM_16X8_FN adst, identity
+
+cglobal iadst_16x8_internal_10bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m13, [clip_18b_min]
+    vpbroadcastd        m14, [clip_18b_max]
+.pass1:
+    lea                  r6, [rsp+32*4]
+    call .main
+    vpbroadcastd        m14, [pd_3072]
+    psrld               m15, 11       ; pd_1
+    psubd               m13, m14, m15 ; pd_3071
+    call .pass1_rotations
+.pass1_end:
+    REPX      {psrad x, 1 }, m0,  m1,  m2,  m3,  m12, m13, m14, m15
+    REPX      {psrad x, 12}, m4,  m5,  m6,  m7,  m8,  m9,  m10, m11
+    jmp                tx2q
+.pass2:
+    call m(idct_16x8_internal_10bpc).transpose
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass2_end
+    vpbroadcastd        m10, [pw_2048]
+    pxor                m11, m11
+    psubw               m11, m10
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m11
+    pmulhrsw             m2, m10
+    pmulhrsw             m3, m11
+    call m(idct_16x8_internal_10bpc).write_16x4_start
+    pmulhrsw             m0, m4, m10
+    pmulhrsw             m1, m5, m11
+    pmulhrsw             m2, m6, m10
+    pmulhrsw             m3, m7, m11
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    RET
+ALIGN function_align
+.pass1_rotations:
+    paddd                m0, m15
+    psubd                m1, m15, m1
+    paddd                m2, m15
+    psubd                m3, m15, m3
+    paddd                m4, m14
+    psubd                m5, m13, m5
+    paddd                m6, m14
+    psubd                m7, m13, m7
+    paddd                m8, m14, m9
+    psubd                m9, m13, m10
+    paddd               m10, m14, m11
+    psubd               m11, m13, m12
+    paddd               m12, m15, [r6-32*1]
+    psubd               m13, m15, [r6-32*2]
+    paddd               m14, m15, [r6-32*3]
+    psubd               m15,      [r6-32*4]
+    ret
+ALIGN function_align
+.main:
+    ; expects: m13 = clip_min   m14 = clip_max
+    vpbroadcastd        m15, [pd_2896]
+    pmulld               m0, m15, [cq+32* 2]
+    pmulld               m1, m15, [cq+32*13]
+    pmulld               m2, m15, [cq+32* 6]
+    pmulld               m3, m15, [cq+32* 9]
+    pmulld               m4, m15, [cq+32*10]
+    pmulld               m5, m15, [cq+32* 5]
+    pmulld               m6, m15, [cq+32*14]
+    pmulld               m7, m15, [cq+32* 1]
+    vpbroadcastd        m12, [pd_2048]
+    REPX     {paddd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+    call .main_part1
+    pmulld               m0, m15, [cq+32* 0]
+    pmulld               m1, m15, [cq+32*15]
+    pmulld               m2, m15, [cq+32* 4]
+    pmulld               m3, m15, [cq+32*11]
+    pmulld               m4, m15, [cq+32* 8]
+    pmulld               m5, m15, [cq+32* 7]
+    pmulld               m6, m15, [cq+32*12]
+    pmulld               m7, m15, [cq+32* 3]
+    REPX     {paddd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+.main_part2:
+    ITX_MULSUB_2D         1, 0, 8, 9, 10, 12,  201, 4091
+    ITX_MULSUB_2D         3, 2, 8, 9, 10, 12, 1751, 3703
+    ITX_MULSUB_2D         5, 4, 8, 9, 10, 12, 3035, 2751
+    ITX_MULSUB_2D         7, 6, 8, 9, 10, 12, 3857, 1380
+    psubd                m8, m0, m4 ; t8a
+    paddd                m0, m4     ; t0a
+    psubd                m4, m1, m5 ; t9a
+    paddd                m1, m5     ; t1a
+    psubd                m5, m2, m6 ; t12a
+    paddd                m2, m6     ; t4a
+    psubd                m6, m3, m7 ; t13a
+    paddd                m7, m3     ; t5a
+    REPX    {pmaxsd x, m13}, m8, m4, m5, m6, m0, m1, m2, m7
+    REPX    {pminsd x, m14}, m8, m4, m5, m6, m0, m1, m2, m7
+    vpbroadcastd        m11, [pd_4017]
+    vpbroadcastd        m10, [pd_799]
+    ITX_MULSUB_2D         8, 4, 3, 9, _, 12, 10, 11
+    ITX_MULSUB_2D         6, 5, 3, 9, _, 12, 11, 10
+    psubd                m3, m0, m2 ; t4
+    paddd                m0, m2     ; t0
+    psubd                m2, m1, m7 ; t5
+    paddd                m1, m7     ; t1
+    psubd                m7, m4, m6 ; t12a
+    paddd                m4, m6     ; t8a
+    psubd                m6, m8, m5 ; t13a
+    paddd                m5, m8     ; t9a
+    REPX    {pmaxsd x, m13}, m3, m2, m7, m6, m0, m1, m4, m5
+    REPX    {pminsd x, m14}, m3, m2, m7, m6, m0, m1, m4, m5
+    vpbroadcastd        m11, [pd_3784]
+    vpbroadcastd        m10, [pd_1567]
+    ITX_MULSUB_2D         3, 2, 8, 9, _, 12, 10, 11
+    ITX_MULSUB_2D         7, 6, 8, 9, _, 12, 10, 11
+    pminsd              m10, m14, [r6-32*4] ;  t2
+    pminsd               m8, m14, [r6-32*3] ;  t3
+    psubd                m9, m0, m10        ;  t2a
+    paddd                m0, m10            ;  out0
+    psubd               m10, m1, m8         ;  t3a
+    paddd                m1, m8             ; -out15
+    pmaxsd               m9, m13
+    pmaxsd              m10, m13
+    pminsd               m9, m14
+    pminsd              m10, m14
+    mova          [r6-32*4], m1
+    mova                m11, [r6-32*1]      ;  t7a
+    mova                 m1, [r6-32*2]      ;  t6a
+    psubd                m8, m3, m11        ;  t7
+    paddd               m11, m3             ;  out12
+    paddd                m3, m2, m1         ; -out3
+    psubd                m2, m1             ;  t6
+    pmaxsd               m8, m13
+    pmaxsd               m2, m13
+    pminsd               m8, m14
+    pminsd               m2, m14
+    mova          [r6-32*1], m11
+    mova          [r6-32*3], m2
+    mova                 m1, [r6+32*3]      ;  t15
+    mova                 m2, [r6+32*2]      ;  t14
+    paddd               m12, m7, m1         ; -out13
+    psubd                m7, m1             ;  t15a
+    psubd               m11, m6, m2         ;  t14a
+    paddd                m2, m6             ;  out2
+    pmaxsd               m7, m13
+    pmaxsd              m11, m13
+    pminsd               m7, m14
+    pminsd              m11, m14
+    mova          [r6-32*2], m12
+    pminsd               m1, m14, [r6+32*0] ;  t10a
+    pminsd              m12, m14, [r6+32*1] ;  t11a
+    psubd                m6, m4, m1         ;  t10
+    paddd                m1, m4             ; -out1
+    psubd                m4, m5, m12        ;  t11
+    paddd                m5, m12            ;  out14
+    vpbroadcastd        m12, [pd_1448]
+    pmaxsd               m6, m13
+    pmaxsd               m4, m13
+    pminsd               m6, m14
+    pminsd               m4, m14
+    REPX    {pmulld x, m12}, m9, m10, m8, m7, m11, m6, m4
+    pmulld              m12, [r6-32*3]      ;  t6
+    mova          [r6-32*3], m5
+    paddd                m5, m11, m7        ; -out5  (unshifted)
+    psubd               m11, m7             ;  out10 (unshifted)
+    paddd                m7, m9, m10        ; -out7  (unshifted)
+    psubd                m9, m10            ;  out8  (unshifted)
+    psubd               m10, m6, m4         ; -out9  (unshifted)
+    paddd                m6, m4             ;  out6  (unshifted)
+    paddd                m4, m12, m8        ;  out4  (unshifted)
+    psubd               m12, m8             ; -out11 (unshifted)
+    ret
+.main_part1:
+    ITX_MULSUB_2D         1, 0, 8, 9, 10, 12,  995, 3973
+    ITX_MULSUB_2D         3, 2, 8, 9, 10, 12, 2440, 3290
+    ITX_MULSUB_2D         5, 4, 8, 9, 10, 12, 3513, 2106
+    ITX_MULSUB_2D         7, 6, 8, 9, 10, 12, 4052,  601
+    psubd                m8, m0, m4 ; t10a
+    paddd                m0, m4     ; t2a
+    psubd                m4, m1, m5 ; t11a
+    paddd                m1, m5     ; t3a
+    psubd                m5, m2, m6 ; t14a
+    paddd                m2, m6     ; t6a
+    psubd                m6, m3, m7 ; t15a
+    paddd                m7, m3     ; t7a
+    REPX    {pmaxsd x, m13}, m8, m4, m5, m6, m0, m1, m2, m7
+    REPX    {pminsd x, m14}, m8, m4, m5, m6, m0, m1, m2, m7
+    vpbroadcastd        m11, [pd_2276]
+    vpbroadcastd        m10, [pd_3406]
+    ITX_MULSUB_2D         8, 4, 3, 9, _, 12, 10, 11
+    ITX_MULSUB_2D         6, 5, 3, 9, _, 12, 11, 10
+    psubd                m3, m0, m2 ; t6
+    paddd                m0, m2     ; t2
+    psubd                m2, m1, m7 ; t7
+    paddd                m1, m7     ; t3
+    psubd                m7, m4, m6 ; t14a
+    paddd                m4, m6     ; t10a
+    psubd                m6, m8, m5 ; t15a
+    paddd                m5, m8     ; t11a
+    REPX    {pmaxsd x, m13}, m3, m2, m7, m6, m0, m1, m4, m5
+    REPX    {pminsd x, m14}, m3, m2, m7, m6 ; clip the rest later
+    vpbroadcastd        m11, [pd_1567]
+    vpbroadcastd        m10, [pd_3784]
+    ITX_MULSUB_2D         2, 3, 8, 9, _, 12, 10, 11
+    ITX_MULSUB_2D         6, 7, 8, 9, _, 12, 10, 11
+    mova          [r6-32*4], m0
+    mova          [r6-32*3], m1
+    mova          [r6+32*0], m4
+    mova          [r6+32*1], m5
+    mova          [r6-32*2], m2
+    mova          [r6-32*1], m3
+    mova          [r6+32*2], m6
+    mova          [r6+32*3], m7
+    ret
+
+INV_TXFM_16X8_FN flipadst, dct
+INV_TXFM_16X8_FN flipadst, adst
+INV_TXFM_16X8_FN flipadst, flipadst
+INV_TXFM_16X8_FN flipadst, identity
+
+cglobal iflipadst_16x8_internal_10bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m13, [clip_18b_min]
+    vpbroadcastd        m14, [clip_18b_max]
+.pass1:
+    lea                  r6, [rsp+32*4]
+    call m(iadst_16x8_internal_10bpc).main
+    vpbroadcastd        m14, [pd_3072]
+    psrld               m15, 11
+    psubd               m13, m14, m15
+    call .pass1_rotations
+    jmp m(iadst_16x8_internal_10bpc).pass1_end
+.pass2:
+    call m(idct_16x8_internal_10bpc).transpose
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass2_end
+    vpbroadcastd        m10, [pw_2048]
+    pxor                m11, m11
+    psubw               m11, m10
+    mova                m12, m0
+    pmulhrsw             m0, m7, m11
+    mova                 m7, m1
+    pmulhrsw             m1, m6, m10
+    mova                 m6, m2
+    pmulhrsw             m2, m5, m11
+    mova                 m5, m3
+    pmulhrsw             m3, m4, m10
+    call m(idct_16x8_internal_10bpc).write_16x4_start
+    pmulhrsw             m0, m5, m11
+    pmulhrsw             m1, m6, m10
+    pmulhrsw             m2, m7, m11
+    pmulhrsw             m3, m12, m10
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    RET
+ALIGN function_align
+.pass1_rotations:
+    psubd                m8, m13, m7
+    paddd                m7, m14, m9
+    paddd                m9, m14, m6
+    psubd                m6, m13, m10
+    psubd               m10, m13, m5
+    paddd                m5, m14, m11
+    paddd               m11, m14, m4
+    psubd                m4, m13, m12
+    psubd               m12, m15, m3
+    paddd                m3, m15, [r6-32*1]
+    paddd               m13, m15, m2
+    psubd                m2, m15, [r6-32*2]
+    psubd               m14, m15, m1
+    mova                 m1, m15
+    paddd               m15, m0
+    psubd                m0, m1, [r6-32*4]
+    paddd                m1,     [r6-32*3]
+    ret
+
+INV_TXFM_16X8_FN identity, dct
+INV_TXFM_16X8_FN identity, adst
+INV_TXFM_16X8_FN identity, flipadst
+INV_TXFM_16X8_FN identity, identity
+
+cglobal iidentity_16x8_internal_10bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+.pass1:
+    vpbroadcastd        m15, [pd_2896]
+    pmulld               m0, m15, [cq+32* 0]
+    pmulld               m1, m15, [cq+32* 1]
+    pmulld               m2, m15, [cq+32* 2]
+    pmulld               m3, m15, [cq+32* 3]
+    pmulld               m4, m15, [cq+32* 4]
+    pmulld               m5, m15, [cq+32* 5]
+    pmulld               m6, m15, [cq+32* 6]
+    pmulld               m7, m15, [cq+32* 7]
+    pmulld               m8, m15, [cq+32* 8]
+    pmulld               m9, m15, [cq+32* 9]
+    pmulld              m10, m15, [cq+32*10]
+    pmulld              m11, m15, [cq+32*11]
+    pmulld              m12, m15, [cq+32*12]
+    pmulld              m13, m15, [cq+32*13]
+    pmulld              m14, m15, [cq+32*14]
+    pmulld              m15,      [cq+32*15]
+    mova              [rsp], m7
+    vpbroadcastd         m7, [pd_2048]
+    REPX    {paddd  x, m7 }, m0,  m1,  m2,  m3,  m4,  m5,  m6, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    paddd                m7, [rsp]
+    REPX    {psrad  x, 12 }, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    mova              [rsp], m15
+    vpbroadcastd        m15, [pd_5793]
+    REPX    {pmulld x, m15}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14
+    pmulld              m15, [rsp]
+    mova              [rsp], m7
+    vpbroadcastd         m7, [pd_3072]
+    REPX    {paddd  x, m7 }, m0,  m1,  m2,  m3,  m4,  m5,  m6, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    paddd                m7, [rsp]
+    REPX    {psrad  x, 12 }, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    jmp                tx2q
+.pass2:
+    call m(idct_16x8_internal_10bpc).transpose
+    vpbroadcastd        m10, [pw_4096]
+    jmp m(idct_16x8_internal_10bpc).end
+
+INV_TXFM_16X8_FN dct, dct,      12
+INV_TXFM_16X8_FN dct, identity, 12
+INV_TXFM_16X8_FN dct, adst,     12
+INV_TXFM_16X8_FN dct, flipadst, 12
+
+cglobal idct_16x8_internal_12bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(idct_16x8_internal_10bpc).pass1
+.pass2:
+    call .pass2_main
+    RET
+ALIGN function_align
+.pass2_main:
+    call m(idct_8x16_internal_12bpc).transpose
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    vpbroadcastd        m11, [pd_2048]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x8_internal_12bpc).round_shift4
+    mova         [cq+32* 8], m0
+    mova         [cq+32* 9], m1
+    mova         [cq+32*10], m2
+    mova         [cq+32*11], m3
+    mova         [cq+32*12], m4
+    mova         [cq+32*13], m5
+    mova         [cq+32*14], m6
+    mova         [cq+32*15], m7
+    pmaxsd               m0, m12, [cq+32*0]
+    pmaxsd               m1, m12, [cq+32*1]
+    pmaxsd               m2, m12, [cq+32*2]
+    pmaxsd               m3, m12, [cq+32*3]
+    pmaxsd               m4, m12, [cq+32*4]
+    pmaxsd               m5, m12, [cq+32*5]
+    pmaxsd               m6, m12, [cq+32*6]
+    pmaxsd               m7, m12, [cq+32*7]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x8_internal_12bpc).round_shift4
+.end:
+    packssdw             m0, [cq+32* 8]
+    packssdw             m1, [cq+32* 9]
+    packssdw             m2, [cq+32*10]
+    packssdw             m3, [cq+32*11]
+    packssdw             m4, [cq+32*12]
+    packssdw             m5, [cq+32*13]
+    packssdw             m6, [cq+32*14]
+    packssdw             m7, [cq+32*15]
+    REPX {vpermq x, x, q3120}, m0, m1, m2, m3
+    call .write_16x4_start
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    vpermq               m0, m4, q3120
+    vpermq               m1, m5, q3120
+    vpermq               m2, m6, q3120
+    vpermq               m3, m7, q3120
+    jmp m(idct_16x8_internal_10bpc).write_16x4_zero
+ALIGN function_align
+.write_16x4_start:
+    vpbroadcastd         m9, [pixel_12bpc_max]
+    lea                  r3, [strideq*3]
+    pxor                 m8, m8
+    ret
+
+INV_TXFM_16X8_FN adst, dct,      12
+INV_TXFM_16X8_FN adst, adst,     12
+INV_TXFM_16X8_FN adst, flipadst, 12
+INV_TXFM_16X8_FN adst, identity, 12
+
+cglobal iadst_16x8_internal_12bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m13, [clip_20b_min]
+    vpbroadcastd        m14, [clip_20b_max]
+    jmp m(iadst_16x8_internal_10bpc).pass1
+.pass2:
+    call .pass2_main
+    call m(idct_16x8_internal_12bpc).end
+    RET
+ALIGN function_align
+.pass2_main:
+    call m(idct_8x16_internal_12bpc).transpose
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    vpbroadcastd        m11, [pd_2048]
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(iadst_8x8_internal_12bpc).pass2_main2
+    mova         [cq+32* 8], m0
+    mova         [cq+32* 9], m1
+    mova         [cq+32*10], m2
+    mova         [cq+32*11], m3
+    mova         [cq+32*12], m4
+    mova         [cq+32*13], m5
+    mova         [cq+32*14], m6
+    mova         [cq+32*15], m7
+    pmaxsd               m0, m12, [cq+32*0]
+    pmaxsd               m1, m12, [cq+32*1]
+    pmaxsd               m2, m12, [cq+32*2]
+    pmaxsd               m3, m12, [cq+32*3]
+    pmaxsd               m4, m12, [cq+32*4]
+    pmaxsd               m5, m12, [cq+32*5]
+    pmaxsd               m6, m12, [cq+32*6]
+    pmaxsd               m7, m12, [cq+32*7]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(iadst_8x8_internal_12bpc).pass2_main2
+    ret
+
+INV_TXFM_16X8_FN flipadst, dct,      12
+INV_TXFM_16X8_FN flipadst, adst,     12
+INV_TXFM_16X8_FN flipadst, flipadst, 12
+INV_TXFM_16X8_FN flipadst, identity, 12
+
+cglobal iflipadst_16x8_internal_12bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    vpbroadcastd        m13, [clip_20b_min]
+    vpbroadcastd        m14, [clip_20b_max]
+    jmp m(iflipadst_16x8_internal_10bpc).pass1
+.pass2:
+    call m(iadst_16x8_internal_12bpc).pass2_main
+    packssdw            m13, m0, [cq+32* 8]
+    packssdw            m12, m1, [cq+32* 9]
+    packssdw            m11, m2, [cq+32*10]
+    packssdw            m10, m3, [cq+32*11]
+    packssdw             m3, m4, [cq+32*12]
+    packssdw             m2, m5, [cq+32*13]
+    packssdw             m1, m6, [cq+32*14]
+    packssdw             m0, m7, [cq+32*15]
+    REPX {vpermq x, x, q3120}, m0, m1, m2, m3
+    call m(idct_16x8_internal_12bpc).write_16x4_start
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    vpermq               m0, m10, q3120
+    vpermq               m1, m11, q3120
+    vpermq               m2, m12, q3120
+    vpermq               m3, m13, q3120
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    RET
+
+INV_TXFM_16X8_FN identity, dct,      12
+INV_TXFM_16X8_FN identity, adst,     12
+INV_TXFM_16X8_FN identity, flipadst, 12
+INV_TXFM_16X8_FN identity, identity, 12
+
+cglobal iidentity_16x8_internal_12bpc, 0, 7, 16, 32*8, dst, stride, c, eob, tx2
+    jmp m(iidentity_16x8_internal_10bpc).pass1
+.pass2:
+    call m(idct_16x8_internal_10bpc).transpose2
+    vpbroadcastd        m10, [pw_4096]
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    pmulhrsw             m2, m10
+    pmulhrsw             m3, m10
+    call m(idct_16x8_internal_12bpc).write_16x4_start
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    jmp m(idct_16x8_internal_10bpc).end2
+
+%macro INV_TXFM_16X16_FN 2-4 0,10 ; type1, type2, eob_offset, bitdepth
+    INV_TXFM_FN          %1, %2, %3, 16x16, %4
+%ifidn %1_%2, dct_dct
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_%4bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 16
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_16x4_10bpc).dconly3
+%endif
+%endmacro
+
+INV_TXFM_16X16_FN dct, dct
+INV_TXFM_16X16_FN dct, identity, 28
+INV_TXFM_16X16_FN dct, adst
+INV_TXFM_16X16_FN dct, flipadst
+
+cglobal idct_16x16_internal_10bpc, 0, 7, 16, 32*24, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+.pass1:
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m14, [pd_2896]
+    lea                  r6, [rsp+32*4]
+    sub                eobd, 36
+    jl .fast
+    add                  cq, 32
+    call .main
+    sub                  cq, 32
+    mova                m10, [r6-32*4]
+    mova                 m9, [r6-32*3]
+    mova                 m8, [r6-32*2]
+    psubd               m15, m0, m10 ; out15
+    paddd                m0, m10     ; out0
+    psubd               m10, m1, m9  ; out14
+    paddd                m1, m9      ; out1
+    psubd                m9, m2, m8  ; out13
+    paddd                m2, m8      ; out2
+    REPX       {psrad x, 2}, m0, m1, m2
+    mova          [r6-32*4], m0
+    mova          [r6-32*3], m1
+    mova          [r6-32*2], m2
+    mova                 m2, [r6-32*1]
+    mova                 m1, [r6+32*0]
+    mova                 m0, [r6+32*1]
+    REPX       {psrad x, 2}, m9, m10, m15
+    psubd                m8, m3, m2 ; out12
+    paddd                m3, m2     ; out3
+    psubd                m2, m4, m1 ; out11
+    paddd                m4, m1     ; out4
+    psubd                m1, m5, m0 ; out10
+    paddd                m5, m0     ; out5
+    REPX       {psrad x, 2}, m3, m4, m5
+    mova          [r6-32*1], m3
+    mova          [r6+32*0], m4
+    mova          [r6+32*1], m5
+    mova                 m4, [r6+32*2]
+    mova                 m3, [r6+32*3]
+    REPX       {psrad x, 2}, m1, m2, m8
+    psubd                m5, m6, m4 ; out9
+    paddd                m6, m4     ; out6
+    psubd                m4, m7, m3 ; out8
+    paddd                m7, m3     ; out7
+    REPX       {psrad x, 2}, m6, m7, m4, m5
+    mova          [r6+32*2], m6
+    mova          [r6+32*3], m7
+    add                  r6, 32*8
+    mova          [r6-32*4], m4
+    mova          [r6-32*3], m5
+    mova          [r6-32*2], m1
+    mova          [r6-32*1], m2
+    mova          [r6+32*0], m8
+    mova          [r6+32*1], m9
+    mova          [r6+32*2], m10
+    mova          [r6+32*3], m15
+.fast:
+    add                  r6, 32*8
+    call .main
+    mova                m14, [r6-32*4]
+    mova                m13, [r6-32*3]
+    mova                m12, [r6-32*2]
+    mova                m11, [r6-32*1]
+    mova                m10, [r6+32*0]
+    mova                 m9, [r6+32*1]
+    mova                 m8, [r6+32*2]
+    psubd               m15, m0, m14       ; out15
+    paddd                m0, m14           ; out0
+    psubd               m14, m1, m13       ; out14
+    paddd                m1, m13           ; out1
+    psubd               m13, m2, m12       ; out13
+    paddd                m2, m12           ; out2
+    psubd               m12, m3, m11       ; out12
+    paddd                m3, m11           ; out3
+    psubd               m11, m4, m10       ; out11
+    paddd                m4, m10           ; out4
+    psubd               m10, m5, m9        ; out10
+    paddd                m5, m9            ; out5
+    psubd                m9, m6, m8        ; out9
+    paddd                m6, m8            ; out6
+    psubd                m8, m7, [r6+32*3] ; out8
+    paddd                m7, [r6+32*3]     ; out7
+    sub                  r6, 32*8
+    REPX       {psrad x, 2}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    jmp                tx2q
+.pass2:
+    call .transpose
+    lea                  r6, [pw_5+128]
+    mova              [rsp], m15
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+.end:
+    call .write_16x16
+    RET
+ALIGN function_align
+.write_16x16:
+    mova [rsp+gprsize+32*0], m8
+    mova [rsp+gprsize+32*1], m9
+    mova [rsp+gprsize+32*2], m12
+    vpbroadcastd        m12, [pw_2048]
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    pmulhrsw             m2, m12
+    pmulhrsw             m3, m12
+    call m(idct_16x8_internal_10bpc).write_16x4_start
+.write_16x16_2:
+    pmulhrsw             m0, m12, m4
+    pmulhrsw             m1, m12, m5
+    pmulhrsw             m2, m12, m6
+    pmulhrsw             m3, m12, m7
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    pmulhrsw             m0, m12, [rsp+gprsize+32*0]
+    pmulhrsw             m1, m12, [rsp+gprsize+32*1]
+    pmulhrsw             m2, m12, m10
+    pmulhrsw             m3, m12, m11
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    pmulhrsw             m0, m12, [rsp+gprsize+32*2]
+    pmulhrsw             m1, m12, m13
+    pmulhrsw             m2, m12, m14
+    pmulhrsw             m3, m12, m15
+    jmp m(idct_16x8_internal_10bpc).write_16x4_zero
+ALIGN function_align
+.transpose:
+    test               eobd, eobd
+    jl .transpose_fast
+    packssdw             m8, [r6-32*4]
+    packssdw             m9, [r6-32*3]
+    packssdw            m10, [r6-32*2]
+    packssdw            m11, [r6-32*1]
+    packssdw            m12, [r6+32*0]
+    packssdw            m13, [r6+32*1]
+    packssdw            m14, [r6+32*2]
+    packssdw            m15, [r6+32*3]
+    sub                  r6, 32*8
+    packssdw             m0, [r6-32*4]
+    packssdw             m1, [r6-32*3]
+    packssdw             m2, [r6-32*2]
+    packssdw             m3, [r6-32*1]
+    packssdw             m4, [r6+32*0]
+    packssdw             m5, [r6+32*1]
+    packssdw             m6, [r6+32*2]
+    packssdw             m7, [r6+32*3]
+    mova               [r6], m8
+    punpckhwd            m8, m0, m1
+    punpcklwd            m0, m1
+    punpcklwd            m1, m2, m3
+    punpckhwd            m2, m3
+    punpckhwd            m3, m6, m7
+    punpcklwd            m6, m7
+    punpcklwd            m7, m4, m5
+    punpckhwd            m4, m5
+    punpckldq            m5, m8, m2
+    punpckhdq            m8, m2
+    punpckhdq            m2, m0, m1
+    punpckldq            m0, m1
+    punpckhdq            m1, m7, m6
+    punpckldq            m7, m6
+    punpckhdq            m6, m4, m3
+    punpckldq            m4, m3
+    punpckhqdq           m3, m2, m1
+    punpcklqdq           m2, m1
+    punpckhqdq           m1, m0, m7
+    punpcklqdq           m0, m7
+    punpcklqdq           m7, m8, m6
+    punpckhqdq           m8, m6
+    punpckhqdq           m6, m5, m4
+    punpcklqdq           m5, m4
+    mova                 m4, [r6]
+    mova               [r6], m8
+    punpcklwd            m8, m4, m9
+    punpckhwd            m4, m9
+    punpcklwd            m9, m10, m11
+    punpckhwd           m10, m11
+    punpckhwd           m11, m14, m15
+    punpcklwd           m14, m15
+    punpckhwd           m15, m12, m13
+    punpcklwd           m12, m13
+    punpckldq           m13, m4, m10
+    punpckhdq            m4, m10
+    punpckhdq           m10, m8, m9
+    punpckldq            m8, m9
+    punpckhdq            m9, m12, m14
+    punpckldq           m12, m14
+    punpckhdq           m14, m15, m11
+    punpckldq           m15, m11
+    punpckhqdq          m11, m10, m9
+    punpcklqdq          m10, m9
+    punpckhqdq           m9, m8, m12
+    punpcklqdq           m8, m12
+    punpcklqdq          m12, m13, m15
+    punpckhqdq          m13, m15
+    punpckhqdq          m15, m4, m14
+    punpcklqdq          m14, m4, m14
+    vperm2i128           m4, m0, m8, 0x31
+    vinserti128          m0, xm8, 1
+    vinserti128          m8, m5, xm12, 1
+    vperm2i128          m12, m5, 0x13
+    vperm2i128           m5, m1, m9, 0x31
+    vinserti128          m1, xm9, 1
+    vinserti128          m9, m6, xm13, 1
+    vperm2i128          m13, m6, 0x13
+    vperm2i128           m6, m2, m10, 0x31
+    vinserti128          m2, xm10, 1
+    vinserti128         m10, m7, xm14, 1
+    vperm2i128          m14, m7, 0x13
+    vperm2i128           m7, m3, m11, 0x31
+    vinserti128          m3, xm11, 1
+    mova               xm11, [r6]
+    vinserti128         m11, xm15, 1
+    vinserti128         m15, [r6+16], 0
+    ret
+.transpose_fast:
+    call m(idct_16x8_internal_10bpc).transpose2
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, m15
+    ret
+ALIGN function_align
+.main:
+    mova                 m0, [cq+64* 1]
+    mova                 m1, [cq+64* 3]
+    mova                 m2, [cq+64* 5]
+    mova                 m3, [cq+64* 7]
+    mova                 m4, [cq+64* 9]
+    mova                 m5, [cq+64*11]
+    mova                 m6, [cq+64*13]
+    mova                 m7, [cq+64*15]
+    call m(idct_8x16_internal_10bpc).main_oddhalf
+    mova                 m0, [cq+64* 0]
+    mova                 m1, [cq+64* 2]
+    mova                 m2, [cq+64* 4]
+    mova                 m3, [cq+64* 6]
+    mova                 m4, [cq+64* 8]
+    mova                 m5, [cq+64*10]
+    mova                 m6, [cq+64*12]
+    mova                 m7, [cq+64*14]
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    psrld               m10, m11, 10 ; pd_2
+    REPX    {paddd  x, m10}, m0, m1, m2, m3, m4, m5, m6, m7
+    ret
+
+INV_TXFM_16X16_FN adst, dct
+INV_TXFM_16X16_FN adst, adst
+INV_TXFM_16X16_FN adst, flipadst
+
+cglobal iadst_16x16_internal_10bpc, 0, 7, 16, 32*24, dst, stride, c, eob, tx2
+    vpbroadcastd        m13, [clip_18b_min]
+    vpbroadcastd        m14, [clip_18b_max]
+.pass1:
+    vpbroadcastd        m15, [pd_2896]
+    lea                  r6, [rsp+32*4]
+    sub                eobd, 36
+    jl .fast
+    add                  cq, 32
+    call .main
+    sub                  cq, 32
+    vpbroadcastd         m8, [pd_5120]
+    paddd                m4, m8
+    paddd                m6, m8
+    paddd                m9, m8
+    paddd               m11, m8
+    vpbroadcastd         m8, [pd_5119]
+    psubd                m5, m8, m5
+    psubd                m7, m8, m7
+    psubd               m10, m8, m10
+    psubd               m12, m8, m12
+    REPX      {psrad x, 13}, m4, m5, m6, m7, m9, m10, m11, m12
+    mova          [r6+32*0], m4
+    mova          [r6+32*1], m5
+    mova          [r6+32*2], m6
+    mova          [r6+32*3], m7
+    psrld                m4, m15, 10 ; pd_2
+    paddd                m0, m4
+    psubd                m1, m4, m1
+    paddd                m2, m4
+    psubd                m3, m4, m3
+    psubd                m7, m4, [r6-32*4]
+    paddd                m6, m4, [r6-32*3]
+    psubd                m5, m4, [r6-32*2]
+    paddd                m4,     [r6-32*1]
+    REPX      {psrad x, 2 }, m0, m1, m2, m3, m4, m5, m6, m7
+    mova          [r6-32*4], m0
+    mova          [r6-32*3], m1
+    mova          [r6-32*2], m2
+    mova          [r6-32*1], m3
+    add                  r6, 32*8
+    mova          [r6-32*4], m9
+    mova          [r6-32*3], m10
+    mova          [r6-32*2], m11
+    mova          [r6-32*1], m12
+    mova          [r6+32*0], m4
+    mova          [r6+32*1], m5
+    mova          [r6+32*2], m6
+    mova          [r6+32*3], m7
+.fast:
+    add                  r6, 32*8
+    call .main
+    vpbroadcastd        m14, [pd_5120]
+    vpbroadcastd        m13, [pd_5119]
+    psrld               m15, 10 ; pd_2
+    paddd                m0, m15
+    psubd                m1, m15, m1
+    paddd                m2, m15
+    psubd                m3, m15, m3
+    paddd                m4, m14
+    psubd                m5, m13, m5
+    paddd                m6, m14
+    psubd                m7, m13, m7
+    paddd                m8, m14, m9
+    psubd                m9, m13, m10
+    paddd               m10, m14, m11
+    psubd               m11, m13, m12
+    paddd               m12, m15, [r6-32*1]
+    psubd               m13, m15, [r6-32*2]
+    paddd               m14, m15, [r6-32*3]
+    psubd               m15,      [r6-32*4]
+.pass1_end:
+    REPX      {psrad x, 2 }, m0,  m1,  m2,  m3,  m12, m13, m14, m15
+    REPX      {psrad x, 13}, m4,  m5,  m6,  m7,  m8,  m9,  m10, m11
+    sub                  r6, 32*8
+    jmp                tx2q
+.pass2:
+    call m(idct_16x16_internal_10bpc).transpose
+    lea                  r6, [pw_5+128]
+    mova              [rsp], m15
+    call m(iadst_16x16_internal_8bpc).main
+    call m(iadst_16x16_internal_8bpc).main_pass2_end
+    mova         [rsp+32*0], m8
+    mova         [rsp+32*2], m12
+    mova         [rsp+32*3], m13
+    vpbroadcastd        m12, [pw_2048]
+    pxor                m13, m13
+    psubw               m13, m12
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m13, [rsp+32*1]
+    mova         [rsp+32*1], m9
+    pmulhrsw             m2, m12
+    pmulhrsw             m3, m13
+    call m(idct_16x8_internal_10bpc).write_16x4_start
+    pmulhrsw             m0, m12, m4
+    pmulhrsw             m1, m13, m5
+    pmulhrsw             m2, m12, m6
+    pmulhrsw             m3, m13, m7
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    pmulhrsw             m0, m12, [rsp+32*0]
+    pmulhrsw             m1, m13, [rsp+32*1]
+    pmulhrsw             m2, m12, m10
+    pmulhrsw             m3, m13, m11
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    pmulhrsw             m0, m12, [rsp+32*2]
+    pmulhrsw             m1, m13, [rsp+32*3]
+    pmulhrsw             m2, m12, m14
+    pmulhrsw             m3, m13, m15
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [cq+64* 2]
+    mova                 m1, [cq+64*13]
+    mova                 m2, [cq+64* 6]
+    mova                 m3, [cq+64* 9]
+    mova                 m4, [cq+64*10]
+    mova                 m5, [cq+64* 5]
+    mova                 m6, [cq+64*14]
+    mova                 m7, [cq+64* 1]
+    vpbroadcastd        m12, [pd_2048]
+    call m(iadst_16x8_internal_10bpc).main_part1
+    mova                 m0, [cq+64* 0]
+    mova                 m1, [cq+64*15]
+    mova                 m2, [cq+64* 4]
+    mova                 m3, [cq+64*11]
+    mova                 m4, [cq+64* 8]
+    mova                 m5, [cq+64* 7]
+    mova                 m6, [cq+64*12]
+    mova                 m7, [cq+64* 3]
+    jmp m(iadst_16x8_internal_10bpc).main_part2
+
+INV_TXFM_16X16_FN flipadst, dct
+INV_TXFM_16X16_FN flipadst, adst
+INV_TXFM_16X16_FN flipadst, flipadst
+
+cglobal iflipadst_16x16_internal_10bpc, 0, 7, 16, 32*24, dst, stride, c, eob, tx2
+    vpbroadcastd        m13, [clip_18b_min]
+    vpbroadcastd        m14, [clip_18b_max]
+.pass1:
+    vpbroadcastd        m15, [pd_2896]
+    lea                  r6, [rsp+32*4]
+    sub                eobd, 36
+    jl .fast
+    add                  cq, 32
+    call m(iadst_16x16_internal_10bpc).main
+    sub                  cq, 32
+    vpbroadcastd         m8, [pd_5120]
+    paddd               m11, m8
+    paddd                m9, m8
+    paddd                m6, m8
+    paddd                m4, m8
+    vpbroadcastd         m8, [pd_5119]
+    psubd               m12, m8, m12
+    psubd               m10, m8, m10
+    psubd                m7, m8, m7
+    psubd                m5, m8, m5
+    REPX      {psrad x, 13}, m12, m11, m10, m9, m7, m6, m5, m4
+    mova          [r6+32*0], m12
+    mova          [r6+32*1], m11
+    mova          [r6+32*2], m10
+    mova          [r6+32*3], m9
+    psrld                m9, m15, 10 ; pd_2
+    psubd                m3, m9, m3
+    paddd                m2, m9
+    psubd                m1, m9, m1
+    paddd                m0, m9
+    psubd               m12, m9, [r6-32*4]
+    paddd               m11, m9, [r6-32*3]
+    psubd               m10, m9, [r6-32*2]
+    paddd                m9,     [r6-32*1]
+    REPX      {psrad x, 2 }, m12, m11, m10, m9, m3, m2, m1, m0
+    mova          [r6-32*4], m12
+    mova          [r6-32*3], m11
+    mova          [r6-32*2], m10
+    mova          [r6-32*1], m9
+    add                  r6, 32*8
+    mova          [r6-32*4], m7
+    mova          [r6-32*3], m6
+    mova          [r6-32*2], m5
+    mova          [r6-32*1], m4
+    mova          [r6+32*0], m3
+    mova          [r6+32*1], m2
+    mova          [r6+32*2], m1
+    mova          [r6+32*3], m0
+.fast:
+    add                  r6, 32*8
+    call m(iadst_16x16_internal_10bpc).main
+    vpbroadcastd        m14, [pd_5120]
+    vpbroadcastd        m13, [pd_5119]
+    psrld               m15, 10 ; pd_2
+    psubd                m8, m13, m7
+    paddd                m7, m14, m9
+    paddd                m9, m14, m6
+    psubd                m6, m13, m10
+    psubd               m10, m13, m5
+    paddd                m5, m14, m11
+    paddd               m11, m14, m4
+    psubd                m4, m13, m12
+    psubd               m12, m15, m3
+    paddd                m3, m15, [r6-32*1]
+    paddd               m13, m15, m2
+    psubd                m2, m15, [r6-32*2]
+    psubd               m14, m15, m1
+    mova                 m1, m15
+    paddd               m15, m0
+    psubd                m0, m1, [r6-32*4]
+    paddd                m1,     [r6-32*3]
+    jmp m(iadst_16x16_internal_10bpc).pass1_end
+.pass2:
+    call m(idct_16x16_internal_10bpc).transpose
+    lea                  r6, [pw_5+128]
+    mova              [rsp], m15
+    call m(iadst_16x16_internal_8bpc).main
+    call m(iadst_16x16_internal_8bpc).main_pass2_end
+    mova         [rsp+32*3], m3
+    mova         [rsp+32*2], m2
+    mova         [rsp+32*0], m0
+    mova                 m2, m13
+    mova                 m3, m12
+    vpbroadcastd        m12, [pw_2048]
+    pxor                m13, m13
+    psubw               m13, m12
+    pmulhrsw             m0, m13, m15
+    pmulhrsw             m1, m12, m14
+    pmulhrsw             m2, m13
+    pmulhrsw             m3, m12
+    mova                m14, m8
+    mova                m15, m9
+    call m(idct_16x8_internal_10bpc).write_16x4_start
+    pmulhrsw             m0, m13, m11
+    pmulhrsw             m1, m12, m10
+    pmulhrsw             m2, m13, m15
+    pmulhrsw             m3, m12, m14
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    pmulhrsw             m0, m13, m7
+    pmulhrsw             m1, m12, m6
+    pmulhrsw             m2, m13, m5
+    pmulhrsw             m3, m12, m4
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    pmulhrsw             m0, m13, [rsp+32*3]
+    pmulhrsw             m1, m12, [rsp+32*2]
+    pmulhrsw             m2, m13, [rsp+32*1]
+    pmulhrsw             m3, m12, [rsp+32*0]
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    RET
+
+INV_TXFM_16X16_FN identity, dct, -92
+INV_TXFM_16X16_FN identity, identity
+
+cglobal iidentity_16x16_internal_10bpc, 0, 7, 16, 32*24, dst, stride, c, eob, tx2
+    vpbroadcastd        m15, [pd_5793]
+    vpbroadcastd         m7, [pd_5120]
+    lea                  r6, [rsp+32*4]
+    sub                eobd, 36
+    jl .fast
+    mov                  r3, -32*8*4
+.righthalf:
+    pmulld               m0, m15, [cq+r3+32*33]
+    pmulld               m1, m15, [cq+r3+32*35]
+    pmulld               m2, m15, [cq+r3+32*37]
+    pmulld               m3, m15, [cq+r3+32*39]
+    add                  r6, 32*4
+    REPX      {paddd x, m7}, m0, m1, m2, m3
+    REPX      {psrad x, 13}, m0, m1, m2, m3
+    mova          [r6+32*0], m0
+    mova          [r6+32*1], m1
+    mova          [r6+32*2], m2
+    mova          [r6+32*3], m3
+    add                  r3, 32*8
+    jl .righthalf
+.fast:
+    pmulld               m0, m15, [cq+64* 0]
+    pmulld               m1, m15, [cq+64* 1]
+    pmulld               m2, m15, [cq+64* 2]
+    pmulld               m3, m15, [cq+64* 3]
+    pmulld               m4, m15, [cq+64* 4]
+    pmulld               m5, m15, [cq+64* 5]
+    pmulld               m6, m15, [cq+64* 6]
+    pmulld               m8, m15, [cq+64* 7]
+    mova               [cq], m8
+    pmulld               m8, m15, [cq+64* 8]
+    pmulld               m9, m15, [cq+64* 9]
+    pmulld              m10, m15, [cq+64*10]
+    pmulld              m11, m15, [cq+64*11]
+    pmulld              m12, m15, [cq+64*12]
+    pmulld              m13, m15, [cq+64*13]
+    pmulld              m14, m15, [cq+64*14]
+    pmulld              m15,      [cq+64*15]
+    REPX      {paddd x, m7}, m0,  m1,  m2,  m3,  m4,  m5,  m6, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    paddd                m7, [cq]
+    REPX      {psrad x, 13}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    jmp                tx2q
+.pass2:
+    call m(idct_16x16_internal_10bpc).transpose
+
+    mova          [cq+32*0], m15
+    mova          [cq+32*1], m0
+    vpbroadcastd        m15, [pw_1697x16]
+
+    REPX  {IDTX16 x, 0, 15},  1,  2,  3,  4,  5,  6,  7, \
+                              8,  9, 10, 11, 12, 13, 14
+    mova                 m0, [cq+32*1]
+    mova          [cq+32*1], m1
+    IDTX16                0, 1, 15
+    mova                 m1, [cq+32*0]
+    pmulhrsw            m15, m1
+    paddsw               m1, m1
+    paddsw              m15, m1
+    mova                 m1, [cq+32*1]
+    jmp m(idct_16x16_internal_10bpc).end
+
+INV_TXFM_16X16_FN dct, dct,       0, 12
+INV_TXFM_16X16_FN dct, identity, 28, 12
+INV_TXFM_16X16_FN dct, adst,      0, 12
+INV_TXFM_16X16_FN dct, flipadst,  0, 12
+
+cglobal idct_16x16_internal_12bpc, 0, 7, 16, 32*24, dst, stride, c, eob, tx2
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    jmp m(idct_16x16_internal_10bpc).pass1
+.pass2:
+    mova         [cq+32* 8], m8
+    mova         [cq+32* 9], m9
+    mova         [cq+32*10], m10
+    mova         [cq+32*11], m11
+    mova         [cq+32*12], m12
+    mova         [cq+32*13], m13
+    mova         [cq+32*14], m14
+    mova         [cq+32*15], m15
+    call .pass2_main
+    packssdw             m0,  m1
+    packssdw             m1,  m2,  m3
+    packssdw             m2,  m4,  m5
+    packssdw             m3,  m6,  m7
+    packssdw             m4,  m8,  m9
+    packssdw             m5, m10, m11
+    packssdw             m6, m12, m13
+    packssdw             m7, m14, m15
+    mova          [r6-32*4], m0
+    mova          [r6-32*3], m1
+    mova          [r6-32*2], m2
+    mova          [r6-32*1], m3
+    mova          [r6+32*0], m4
+    mova          [r6+32*1], m5
+    mova          [r6+32*2], m6
+    mova          [r6+32*3], m7
+    mova                 m0, [cq+32* 8]
+    mova                 m1, [cq+32* 9]
+    mova                 m2, [cq+32*10]
+    mova                 m3, [cq+32*11]
+    mova                 m4, [cq+32*12]
+    mova                 m5, [cq+32*13]
+    mova                 m6, [cq+32*14]
+    mova                 m7, [cq+32*15]
+    mov                  r5, r6
+    add                  r6, 32*16
+    call .pass2_main
+    jmp m(iadst_16x16_internal_12bpc).end
+ALIGN function_align
+.write_16x16:
+    mova [rsp+gprsize+32*0], m8
+    mova [rsp+gprsize+32*1], m9
+    mova [rsp+gprsize+32*2], m12
+    vpbroadcastd        m12, [pw_16384]
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    pmulhrsw             m2, m12
+    pmulhrsw             m3, m12
+    call m(idct_16x8_internal_12bpc).write_16x4_start
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    jmp m(idct_16x16_internal_10bpc).write_16x16_2
+ALIGN function_align
+.pass2_main:
+    call m(idct_8x8_internal_12bpc).transpose_8x8
+    mova         [cq+32* 0], m0
+    mova         [cq+32* 1], m2
+    mova         [cq+32* 2], m4
+    mova         [cq+32* 3], m6
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    pmaxsd               m0, m12, m1
+    pmaxsd               m1, m12, m3
+    pmaxsd               m2, m12, m5
+    pmaxsd               m3, m12, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3
+    test               eobd, eobd
+    jge .pass2_slow
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    jmp .pass2_fast
+.pass2_slow:
+    sub                  r6, 32*8
+    mova                 m8, [r6-32*4]
+    mova                 m4, [r6-32*3]
+    mova                m10, [r6-32*2]
+    mova                 m5, [r6-32*1]
+    mova                m12, [r6+32*0]
+    mova                 m6, [r6+32*1]
+    mova                m14, [r6+32*2]
+    mova                 m7, [r6+32*3]
+    TRANSPOSE_8X8_DWORD 8, 4, 10, 5, 12, 6, 14, 7, 9, 11, 13, 15
+    mova         [cq+32* 4], m8
+    mova         [cq+32* 5], m10
+    mova         [cq+32* 6], m12
+    mova         [cq+32* 7], m14
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    REPX    {pmaxsd x, m12}, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m4, m5, m6, m7
+.pass2_fast:
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m14, [pd_2896]
+    call m(idct_8x16_internal_10bpc).main_oddhalf
+    pmaxsd               m0, m12, [cq+32* 0]
+    pmaxsd               m1, m12, [cq+32* 1]
+    pmaxsd               m2, m12, [cq+32* 2]
+    pmaxsd               m3, m12, [cq+32* 3]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3
+    test               eobd, eobd
+    jge .pass2_slow2
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    jmp .pass2_fast2
+.pass2_slow2:
+    pmaxsd               m4, m12, [cq+32* 4]
+    pmaxsd               m5, m12, [cq+32* 5]
+    pmaxsd               m6, m12, [cq+32* 6]
+    pmaxsd               m7, m12, [cq+32* 7]
+    REPX    {pminsd x, m13}, m4, m5, m6, m7
+.pass2_fast2:
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    psrad               m11, 8  ; pd_8
+    REPX    {paddd  x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_16x8_internal_10bpc).pass1_rotations
+    REPX       {psrad x, 4}, m0, m1, m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8, m9, m10, m11, m12, m13, m14, m15
+    ret
+
+INV_TXFM_16X16_FN adst, dct,      0, 12
+INV_TXFM_16X16_FN adst, adst,     0, 12
+INV_TXFM_16X16_FN adst, flipadst, 0, 12
+
+cglobal iadst_16x16_internal_12bpc, 0, 7, 16, 32*24, dst, stride, c, eob, tx2
+    vpbroadcastd        m13, [clip_20b_min]
+    vpbroadcastd        m14, [clip_20b_max]
+    jmp m(iadst_16x16_internal_10bpc).pass1
+.pass2:
+    call .pass2_part1
+    call m(iadst_16x8_internal_10bpc).pass1_rotations
+    call .pass2_part2
+    call m(iadst_16x8_internal_10bpc).pass1_rotations
+.pass2_part3:
+    REPX      {psrad x, 4 }, m0, m1, m2, m3, m12, m13, m14, m15
+    REPX      {psrad x, 15}, m4, m5, m6, m7, m8,  m9,  m10, m11
+.end:
+    packssdw            m15, m14
+    packssdw            m14, m13, m12
+    packssdw            m13, m11, m10
+    packssdw            m12,  m9,  m8
+    packssdw            m11,  m7,  m6
+    packssdw            m10,  m5,  m4
+    packssdw             m7,  m3,  m2
+    packssdw             m6,  m1,  m0
+    vpblendd             m0, m6, [r5-32*4], 0x33
+    vpblendd             m1, m6, [r5-32*4], 0xcc
+    vpblendd             m2, m7, [r5-32*3], 0x33
+    vpblendd             m3, m7, [r5-32*3], 0xcc
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    vpermq               m2, m2, q3120
+    vpermq               m3, m3, q2031
+    call m(idct_16x8_internal_12bpc).write_16x4_start
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    vpblendd             m0, m10, [r5-32*2], 0x33
+    vpblendd             m1, m10, [r5-32*2], 0xcc
+    vpblendd             m2, m11, [r5-32*1], 0x33
+    vpblendd             m3, m11, [r5-32*1], 0xcc
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    vpermq               m2, m2, q3120
+    vpermq               m3, m3, q2031
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    vpblendd             m0, m12, [r5+32*0], 0x33
+    vpblendd             m1, m12, [r5+32*0], 0xcc
+    vpblendd             m2, m13, [r5+32*1], 0x33
+    vpblendd             m3, m13, [r5+32*1], 0xcc
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    vpermq               m2, m2, q3120
+    vpermq               m3, m3, q2031
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    vpblendd             m0, m14, [r5+32*2], 0x33
+    vpblendd             m1, m14, [r5+32*2], 0xcc
+    vpblendd             m2, m15, [r5+32*3], 0x33
+    vpblendd             m3, m15, [r5+32*3], 0xcc
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    vpermq               m2, m2, q3120
+    vpermq               m3, m3, q2031
+    call m(idct_16x8_internal_10bpc).write_16x4_zero
+    RET
+ALIGN function_align
+.pass2_part1:
+    mova         [cq+32* 8], m8
+    mova         [cq+32* 9], m9
+    mova         [cq+32*10], m10
+    mova         [cq+32*11], m11
+    mova         [cq+32*12], m12
+    mova         [cq+32*13], m13
+    mova         [cq+32*14], m14
+    mova         [cq+32*15], m15
+.pass2_main:
+    call m(idct_8x8_internal_12bpc).transpose_8x8
+    mova         [cq+32* 0], m0
+    mova         [cq+32* 1], m3
+    mova         [cq+32* 2], m4
+    mova         [cq+32* 3], m7
+    vpbroadcastd        m13, [clip_18b_min]
+    vpbroadcastd        m14, [clip_18b_max]
+    pmaxsd               m0, m13, m2
+    pmaxsd               m2, m13, m6
+    pmaxsd               m5, m13, m5
+    pmaxsd               m7, m13, m1
+    REPX    {pminsd x, m14}, m0, m2, m5, m7
+    test               eobd, eobd
+    jge .pass2_slow
+    pxor                 m1, m1
+    REPX       {mova x, m1}, m3, m4, m6
+    jmp .pass2_fast
+.pass2_slow:
+    sub                  r6, 32*8
+    mova                 m8, [r6-32*4]
+    mova                 m3, [r6-32*3]
+    mova                 m4, [r6-32*2]
+    mova                m11, [r6-32*1]
+    mova                m12, [r6+32*0]
+    mova                 m1, [r6+32*1]
+    mova                 m6, [r6+32*2]
+    mova                m15, [r6+32*3]
+    TRANSPOSE_8X8_DWORD 8, 3, 4, 11, 12, 1, 6, 15, 13, 9, 10, 14
+    mova         [cq+32* 4], m8
+    mova         [cq+32* 5], m11
+    mova         [cq+32* 6], m12
+    mova         [cq+32* 7], m15
+    vpbroadcastd        m13, [clip_18b_min]
+    vpbroadcastd        m14, [clip_18b_max]
+    REPX    {pmaxsd x, m13}, m1, m3, m4, m6
+    REPX    {pminsd x, m14}, m1, m3, m4, m6
+.pass2_fast:
+    vpbroadcastd        m12, [pd_2048]
+    vpbroadcastd        m15, [pd_2896]
+    call m(iadst_16x8_internal_10bpc).main_part1
+    pmaxsd               m0, m13, [cq+32* 0] ;  0
+    pmaxsd               m7, m13, [cq+32* 1] ;  3
+    pmaxsd               m2, m13, [cq+32* 2] ;  4
+    pmaxsd               m5, m13, [cq+32* 3] ;  7
+    REPX    {pminsd x, m14}, m0, m2, m5, m7
+    test               eobd, eobd
+    jge .pass2_slow2
+    pxor                 m1, m1
+    REPX       {mova x, m1}, m3, m4, m6
+    jmp .pass2_fast2
+.pass2_slow2:
+    pmaxsd               m4, m13, [cq+32* 4] ;  8
+    pmaxsd               m3, m13, [cq+32* 5] ; 11
+    pmaxsd               m6, m13, [cq+32* 6] ; 12
+    pmaxsd               m1, m13, [cq+32* 7] ; 15
+    REPX    {pminsd x, m14}, m1, m3, m4, m6
+.pass2_fast2:
+    call m(iadst_16x8_internal_10bpc).main_part2
+    vpbroadcastd        m14, [pd_17408]
+    psrld               m15, 11              ; pd_1
+    psubd               m13, m14, m15        ; pd_17407
+    pslld               m15, 3               ; pd_8
+    ret
+ALIGN function_align
+.pass2_part2:
+    REPX      {psrad x, 4 }, m0, m1, m2, m3, m12, m13, m14, m15
+    REPX      {psrad x, 15}, m4, m5, m6, m7, m8,  m9,  m10, m11
+    packssdw             m0,  m1
+    packssdw             m1,  m2,  m3
+    packssdw             m2,  m4,  m5
+    packssdw             m3,  m6,  m7
+    packssdw             m4,  m8,  m9
+    packssdw             m5, m10, m11
+    packssdw             m6, m12, m13
+    packssdw             m7, m14, m15
+    mova          [r6-32*4], m0
+    mova          [r6-32*3], m1
+    mova          [r6-32*2], m2
+    mova          [r6-32*1], m3
+    mova          [r6+32*0], m4
+    mova          [r6+32*1], m5
+    mova          [r6+32*2], m6
+    mova          [r6+32*3], m7
+    mova                 m0, [cq+32* 8]
+    mova                 m1, [cq+32* 9]
+    mova                 m2, [cq+32*10]
+    mova                 m3, [cq+32*11]
+    mova                 m4, [cq+32*12]
+    mova                 m5, [cq+32*13]
+    mova                 m6, [cq+32*14]
+    mova                 m7, [cq+32*15]
+    mov                  r5, r6
+    add                  r6, 32*16
+    jmp .pass2_main
+
+INV_TXFM_16X16_FN flipadst, dct,      0, 12
+INV_TXFM_16X16_FN flipadst, adst,     0, 12
+INV_TXFM_16X16_FN flipadst, flipadst, 0, 12
+
+cglobal iflipadst_16x16_internal_12bpc, 0, 7, 16, 32*24, dst, stride, c, eob, tx2
+    vpbroadcastd        m13, [clip_20b_min]
+    vpbroadcastd        m14, [clip_20b_max]
+    jmp m(iflipadst_16x16_internal_10bpc).pass1
+.pass2:
+    call m(iadst_16x16_internal_12bpc).pass2_part1
+    call m(iflipadst_16x8_internal_10bpc).pass1_rotations
+    call m(iadst_16x16_internal_12bpc).pass2_part2
+    call m(iflipadst_16x8_internal_10bpc).pass1_rotations
+    jmp m(iadst_16x16_internal_12bpc).pass2_part3
+
+INV_TXFM_16X16_FN identity, dct,    -92, 12
+INV_TXFM_16X16_FN identity, identity, 0, 12
+
+%macro IDTX16_12BPC 1 ; src
+    pmulld               m6, m7, m%1
+    paddd                m6, m15
+    psrad                m6, 12
+    paddd                m6, m%1
+    psrad               m%1, m6, 1
+%endmacro
+
+cglobal iidentity_16x16_internal_12bpc, 0, 7, 16, 32*24, dst, stride, c, eob, tx2
+    vpbroadcastd         m7, [pd_1697]
+    vpbroadcastd        m15, [pd_5120]
+    lea                  r6, [rsp+32*4]
+    sub                eobd, 36
+    jl .fast
+    mov                  r3, -32*8*4
+.righthalf:
+    mova                m10, [cq+r3+32*33]
+    mova                m11, [cq+r3+32*35]
+    mova                m12, [cq+r3+32*37]
+    mova                m13, [cq+r3+32*39]
+    add                  r6, 32*4
+    pmulld               m0, m7, m10
+    pmulld               m1, m7, m11
+    pmulld               m2, m7, m12
+    pmulld               m3, m7, m13
+    REPX     {paddd x, m15}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+    paddd                m0, m10
+    paddd                m1, m11
+    paddd                m2, m12
+    paddd                m3, m13
+    REPX     {psrad x, 1  }, m0, m1, m2, m3
+    mova          [r6+32*0], m0
+    mova          [r6+32*1], m1
+    mova          [r6+32*2], m2
+    mova          [r6+32*3], m3
+    add                  r3, 32*8
+    jl .righthalf
+.fast:
+    mova                 m0, [cq+64* 0]
+    mova                 m1, [cq+64* 1]
+    mova                 m2, [cq+64* 2]
+    mova                 m3, [cq+64* 3]
+    mova                 m4, [cq+64* 4]
+    mova                 m5, [cq+64* 5]
+    mova                 m8, [cq+64* 6]
+    mova                 m9, [cq+64* 7]
+    REPX   {IDTX16_12BPC x}, 0, 1, 2, 3, 4, 5, 8, 9
+    mova          [cq+64*0], m8
+    mova          [cq+64*1], m9
+    mova                 m8, [cq+64* 8]
+    mova                 m9, [cq+64* 9]
+    mova                m10, [cq+64*10]
+    mova                m11, [cq+64*11]
+    mova                m12, [cq+64*12]
+    mova                m13, [cq+64*13]
+    mova                m14, [cq+64*14]
+    REPX   {IDTX16_12BPC x}, 8, 9, 10, 11, 12, 13, 14
+    mova                 m6, [cq+64*15]
+    pmulld               m7, m6
+    paddd                m7, m15
+    psrad                m7, 12
+    paddd                m7, m6
+    mova                 m6, [cq+64*0]
+    psrad               m15, m7, 1
+    mova                 m7, [cq+64*1]
+    jmp                tx2q
+.pass2:
+    call m(iidentity_8x16_internal_12bpc).pass2_main
+    call m(idct_16x16_internal_10bpc).transpose_fast
+    test               eobd, eobd
+    jl .pass2_fast
+    mova         [cq+32* 8], m0
+    mova         [cq+32* 9], m1
+    mova         [cq+32*10], m2
+    mova         [cq+32*11], m3
+    mova         [cq+32*12], m4
+    mova         [cq+32*13], m5
+    mova         [cq+32*14], m6
+    mova         [cq+32*15], m7
+    mova                 m8, [r6-32*4]
+    mova                 m9, [r6-32*3]
+    mova                m10, [r6-32*2]
+    mova                m11, [r6-32*1]
+    mova                m12, [r6+32*0]
+    mova                m13, [r6+32*1]
+    mova                m14, [r6+32*2]
+    mova                m15, [r6+32*3]
+    sub                  r6, 32*8
+    mova                 m0, [r6-32*4]
+    mova                 m1, [r6-32*3]
+    mova                 m2, [r6-32*2]
+    mova                 m3, [r6-32*1]
+    mova                 m4, [r6+32*0]
+    mova                 m5, [r6+32*1]
+    mova                 m6, [r6+32*2]
+    mova                 m7, [r6+32*3]
+    call m(iidentity_8x16_internal_12bpc).pass2_main
+    call m(idct_16x8_internal_10bpc).transpose2
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+    mova                m11, m3
+    mova                m12, m4
+    mova                m13, m5
+    mova                m14, m6
+    mova                m15, m7
+    mova                 m0, [cq+32* 8]
+    mova                 m1, [cq+32* 9]
+    mova                 m2, [cq+32*10]
+    mova                 m3, [cq+32*11]
+    mova                 m4, [cq+32*12]
+    mova                 m5, [cq+32*13]
+    mova                 m6, [cq+32*14]
+    mova                 m7, [cq+32*15]
+.pass2_fast:
+    call m(idct_16x16_internal_12bpc).write_16x16
+    RET
+
+%macro IDCT32_END 6-7 1 ; in/out1, out2, tmp[1-3], shift, pack
+    mova                m%4, [r6+32*(%1-4)]
+    mova                m%2, [r5+32*(3-%1)]
+    mova                m%5, [r4+32*(%1-4)]
+    psubd               m%3, m%1, m%4 ; idct16 out15 - n
+    paddd               m%1, m%4      ; idct16 out0  + n
+    pmaxsd              m%1, m12
+    pmaxsd              m%3, m12
+    pminsd              m%1, m13
+    pminsd              m%3, m13
+    paddd               m%1, m11
+    paddd               m%3, m11
+    psubd               m%4, m%1, m%2 ; out31 - n
+    paddd               m%1, m%2      ; out0  + n
+    paddd               m%2, m%3, m%5 ; out15 - n
+    psubd               m%3, m%5      ; out16 + n
+    REPX      {psrad x, %6}, m%1, m%3, m%2, m%4
+%if %7 & 1
+    packssdw            m%1, m%3      ; out0  + n, out16 + n
+    packssdw            m%2, m%4      ; out15 - n, out31 - n
+%endif
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_8x32_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 7, 16, 32*12, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    vbroadcasti128      m14, [idct32_shuf]
+    mov                  r4, cq
+    call .pass1_main
+    mova         [rsp+32*0], m2
+    mova         [rsp+32*1], m3
+    cmp                eobd, 43
+    jge .eob43
+    pxor                 m4, m4
+    REPX       {mova x, m4}, [rsp+32*2], m2, m3, m11
+    jmp .pass1_end_fast
+.eob43:
+    lea                  r6, [rsp+32*8]
+    mova          [r6-32*4], m0
+    mova          [r6-32*3], m1
+    call .pass1_main
+    mova         [rsp+32*2], m2
+    cmp                eobd, 107
+    jge .eob107
+    mova                m11, m3
+    mova                 m2, m0
+    mova                 m3, m1
+    mova                 m0, [r6-32*4]
+    mova                 m1, [r6-32*3]
+    pxor                 m4, m4
+.pass1_end_fast:
+    vpbroadcastd        m10, [pw_2048]
+    lea                  r6, [deint_shuf+128]
+    REPX       {mova x, m4}, m5, m6, m7
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main_fast
+    jmp .end
+.eob107:
+    mova         [rsp+32*3], m3
+    mova          [r6-32*2], m0
+    mova          [r6-32*1], m1
+    call .pass1_main
+    cmp                eobd, 171
+    jge .eob171
+    pshufd              m12, m2, q1032
+    pshufd              m13, m3, q1032
+    mova                 m4, m0
+    mova                 m5, m1
+    pxor                 m6, m6
+    REPX       {mova x, m6}, m7, m14, m15
+    jmp .pass1_end
+.eob171:
+    mova          [r6+32*0], m0
+    mova          [r6+32*1], m1
+    mova          [r6+32*2], m2
+    mova          [r6+32*3], m3
+    call .pass1_main
+    pshufd              m12, [r6+32*2], q1032 ; out19 out17
+    pshufd              m13, [r6+32*3], q1032 ; out23 out21
+    mova                 m4, [r6+32*0]        ; out16 out18
+    mova                 m5, [r6+32*1]        ; out20 out22
+    pshufd              m14, m2, q1032        ; out27 out25
+    pshufd              m15, m3, q1032        ; out31 out29
+    mova                 m6, m0               ; out24 out26
+    mova                 m7, m1               ; out28 out30
+.pass1_end:
+    mova                 m0, [r6-32*4]        ; out0  out2
+    mova                 m1, [r6-32*3]        ; out4  out6
+    mova                 m2, [r6-32*2]        ; out8  out10
+    mova                 m3, [r6-32*1]        ; out12 out14
+    lea                  r6, [deint_shuf+128]
+    mova                m11, [rsp+32*3]       ; out13 out15
+    vpbroadcastd        m10, [pw_2048]
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main
+.end: ; [rsp+0*32] = m12
+    vpbroadcastd        m12, [pw_2048]
+    mov                  cq, r4
+    mova         [rsp+32*1], m8
+    mova         [rsp+32*2], m9
+    mova         [rsp+32*3], m10
+    mova         [rsp+32*4], m11
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4_start
+    vpermq               m0, m2, q3120
+    vpermq               m1, m3, q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m4, q3120
+    vpermq               m1, m5, q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m6, q3120
+    vpermq               m1, m7, q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, [rsp+32*1], q3120
+    vpermq               m1, [rsp+32*2], q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, [rsp+32*3], q3120
+    vpermq               m1, [rsp+32*4], q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, [rsp+32*0], q3120
+    vpermq               m1, m13, q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m14, q3120
+    vpermq               m1, m15, q2031
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    call m(idct_8x8_internal_10bpc).write_8x4
+    RET
+.dconly:
+    imul                r6d, [cq], 181
+    vpbroadcastd         m2, [dconly_10bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 32
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_8x8_10bpc).dconly3
+ALIGN function_align
+.pass1_main_part1:
+    mova                 m0, [cq+128*0]
+    mova                 m1, [cq+128*1]
+    mova                 m2, [cq+128*2]
+    mova                 m3, [cq+128*3]
+    mova                 m4, [cq+128*4]
+    mova                 m5, [cq+128*5]
+    mova                 m6, [cq+128*6]
+    mova                 m7, [cq+128*7]
+    call m(idct_8x8_internal_10bpc).main
+    psrld                m1, m11, 10 ; pd_2
+    REPX      {paddd x, m1}, m0, m6, m5, m3
+    paddd                m1, m6, m7  ; out1
+    psubd                m6, m7      ; out6
+    psubd                m7, m0, m9  ; out7
+    paddd                m0, m9      ; out0
+    paddd                m2, m5, m4  ; out2
+    psubd                m5, m4      ; out5
+    psubd                m4, m3, m8  ; out4
+    paddd                m3, m8      ; out3
+    REPX      {psrad x, 2 }, m0, m1, m2, m3, m4, m5, m6, m7
+    ret
+ALIGN function_align
+.pass1_main:
+    call .pass1_main_part1
+    add                  cq, 32
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    pshufb               m0, m14
+    pshufb               m2, m14
+    pshufb               m4, m14
+    pshufb               m6, m14
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m4, m6
+    punpckhdq            m4, m6
+    vperm2i128           m1, m0, m2, 0x31 ; 4 6
+    vinserti128          m0, xm2, 1       ; 0 2
+    vinserti128          m2, m3, xm4, 1   ; 1 3
+    vperm2i128           m3, m4, 0x31     ; 5 7
+    ret
+.main_oddhalf_part1_fast_rect2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+.main_oddhalf_part1_fast: ; lower half zero
+    vpbroadcastd         m7, [pd_4091]
+    vpbroadcastd         m8, [pd_201]
+    vpbroadcastd         m6, [pd_m1380]
+    vpbroadcastd         m9, [pd_3857]
+    vpbroadcastd         m5, [pd_3703]
+    vpbroadcastd        m10, [pd_1751]
+    vpbroadcastd         m4, [pd_m2751]
+    vpbroadcastd        m15, [pd_3035]
+    pmulld               m7, m0
+    pmulld               m0, m8
+    pmulld               m6, m1
+    pmulld               m1, m9
+    pmulld               m5, m2
+    pmulld               m2, m10
+    pmulld               m4, m3
+    pmulld               m3, m15
+    jmp .main_oddhalf_part1_fast2
+.main_oddhalf_part1_rect2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+.main_oddhalf_part1: ; in1, in7, in9, in15, in17, in23, in25, in31
+    ITX_MULSUB_2D         0, 7, 8, 9, 10, _,  201, 4091 ; t16a, t31a
+    ITX_MULSUB_2D         6, 1, 8, 9, 10, _, 3857, 1380 ; t19a, t28a
+    ITX_MULSUB_2D         2, 5, 8, 9, 10, _, 1751, 3703 ; t18a, t29a
+    ITX_MULSUB_2D         4, 3, 8, 9, 10, _, 3035, 2751 ; t17a, t30a
+.main_oddhalf_part1_fast2:
+    REPX     {paddd x, m11}, m0, m7, m6, m1, m2, m5, m4, m3
+    REPX     {psrad x, 12 }, m0, m4, m6, m2, m1, m5, m7, m3
+    psubd                m8, m0, m4 ; t17
+    paddd                m0, m4     ; t16
+    psubd                m4, m6, m2 ; t18
+    paddd                m6, m2     ; t19
+    psubd                m2, m1, m5 ; t29
+    paddd                m1, m5     ; t28
+    psubd                m5, m7, m3 ; t30
+    paddd                m7, m3     ; t31
+    REPX    {pmaxsd x, m12}, m8, m5, m4, m2, m0, m6, m1, m7
+    REPX    {pminsd x, m13}, m8, m5, m4, m2, m0, m6, m1, m7
+    vpbroadcastd        m15, [pd_4017]
+    vpbroadcastd        m10, [pd_799]
+    ITX_MULSUB_2D         5, 8, 3, 9, _, 11, 10, 15    ; t17a, t30a
+    ITX_MULSUB_2D         2, 4, 3, 9, _, 11, 10, 15, 2 ; t29a, t18a
+    psubd                m3, m0, m6 ; t19a
+    paddd                m0, m6     ; t16a
+    psubd                m6, m7, m1 ; t28a
+    paddd                m7, m1     ; t31a
+    psubd                m1, m5, m4 ; t18
+    paddd                m5, m4     ; t17
+    psubd                m4, m8, m2 ; t29
+    paddd                m8, m2     ; t30
+    REPX    {pmaxsd x, m12}, m3, m6, m1, m4, m0, m7, m5, m8
+    REPX    {pminsd x, m13}, m3, m6, m1, m4, m0, m7, m5, m8
+    vpbroadcastd        m15, [pd_3784]
+    vpbroadcastd        m10, [pd_1567]
+    ITX_MULSUB_2D         4, 1, 2, 9, _, 11, 10, 15 ; t18a, t29a
+    ITX_MULSUB_2D         6, 3, 2, 9, _, 11, 10, 15 ; t19,  t28
+    mova          [r6-32*4], m0
+    mova          [r6-32*3], m5
+    mova          [r6-32*2], m4
+    mova          [r6-32*1], m6
+    mova          [r6+32*0], m3
+    mova          [r6+32*1], m1
+    mova          [r6+32*2], m8
+    mova          [r6+32*3], m7
+    ret
+.main_oddhalf_part2_fast_rect2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+.main_oddhalf_part2_fast: ; lower half zero
+    vpbroadcastd         m7, [pd_m601]
+    vpbroadcastd         m8, [pd_4052]
+    vpbroadcastd         m6, [pd_3973]
+    vpbroadcastd         m9, [pd_995]
+    vpbroadcastd         m5, [pd_m2106]
+    vpbroadcastd        m10, [pd_3513]
+    vpbroadcastd         m4, [pd_3290]
+    vpbroadcastd        m15, [pd_2440]
+    pmulld               m7, m0
+    pmulld               m0, m8
+    pmulld               m6, m1
+    pmulld               m1, m9
+    pmulld               m5, m2
+    pmulld               m2, m10
+    pmulld               m4, m3
+    pmulld               m3, m15
+    jmp .main_oddhalf_part2_fast2
+.main_oddhalf_part2_rect2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+.main_oddhalf_part2: ; in3, in5, in11, in13, in19, in21, in27, in29
+    ITX_MULSUB_2D         7, 0, 8, 9, 10, _, 4052,  601 ; t23a, t24a
+    ITX_MULSUB_2D         1, 6, 8, 9, 10, _,  995, 3973 ; t20a, t27a
+    ITX_MULSUB_2D         5, 2, 8, 9, 10, _, 3513, 2106 ; t21a, t26a
+    ITX_MULSUB_2D         3, 4, 8, 9, 10, _, 2440, 3290 ; t22a, t25a
+.main_oddhalf_part2_fast2:
+    REPX     {paddd x, m11}, m0, m7, m6, m1, m2, m5, m4, m3
+    REPX     {psrad x, 12 }, m0, m4, m6, m2, m1, m5, m7, m3
+    psubd                m8, m0, m4 ; t25
+    paddd                m0, m4     ; t24
+    psubd                m4, m6, m2 ; t26
+    paddd                m6, m2     ; t27
+    psubd                m2, m1, m5 ; t21
+    paddd                m1, m5     ; t20
+    psubd                m5, m7, m3 ; t22
+    paddd                m7, m3     ; t23
+    REPX    {pmaxsd x, m12}, m8, m5, m4, m2, m0, m6, m1, m7
+    REPX    {pminsd x, m13}, m8, m5, m4, m2, m0, m6, m1, m7
+    vpbroadcastd        m15, [pd_2276]
+    vpbroadcastd        m10, [pd_3406]
+    ITX_MULSUB_2D         4, 2, 3, 9, _, 11, 10, 15    ; t21a, t26a
+    ITX_MULSUB_2D         8, 5, 3, 9, _, 11, 10, 15, 2 ; t25a, t22a
+    psubd                m3, m0, m6 ; t27a
+    paddd                m0, m6     ; t24a
+    psubd                m6, m7, m1 ; t20a
+    paddd                m7, m1     ; t23a
+    psubd                m1, m5, m4 ; t21
+    paddd                m5, m4     ; t22
+    psubd                m4, m8, m2 ; t26
+    paddd                m8, m2     ; t25
+    REPX    {pmaxsd x, m12}, m3, m6, m1, m4, m0, m7, m5, m8
+    REPX    {pminsd x, m13}, m3, m6, m1, m4, m0, m7, m5, m8
+    vpbroadcastd        m15, [pd_3784]
+    vpbroadcastd        m10, [pd_1567]
+    ITX_MULSUB_2D         4, 1, 2, 9, _, 11, 10, 15, 2 ; t26a, t21a
+    ITX_MULSUB_2D         3, 6, 2, 9, _, 11, 10, 15, 2 ; t27,  t20
+    mova                 m9, [r6-32*4] ; t16a
+    mova                m10, [r6-32*3] ; t17
+    psubd                m2, m9, m7    ; t23
+    paddd                m9, m7        ; t16
+    psubd                m7, m10, m5   ; t22a
+    paddd               m10, m5        ; t17a
+    REPX    {pmaxsd x, m12}, m9, m10, m2, m7
+    REPX    {pminsd x, m13}, m9, m10, m2, m7
+    mova          [r6-32*4], m9
+    mova          [r6-32*3], m10
+    mova                 m9, [r6-32*2] ; t18a
+    mova                m10, [r6-32*1] ; t19
+    psubd                m5, m9, m1    ; t21
+    paddd                m9, m1        ; t18
+    psubd                m1, m10, m6   ; t20a
+    paddd               m10, m6        ; t19a
+    REPX    {pmaxsd x, m12}, m9, m10, m5, m1
+    REPX    {pminsd x, m13}, m9, m10, m5, m1
+    mova          [r6-32*2], m9
+    mova          [r6-32*1], m10
+    mova                 m9, [r6+32*0] ; t28
+    mova                m10, [r6+32*1] ; t29a
+    psubd                m6, m9, m3    ; t27a
+    paddd                m9, m3        ; t28a
+    psubd                m3, m10, m4   ; t26
+    paddd               m10, m4        ; t29
+    REPX    {pmaxsd x, m12}, m9, m10, m6, m3
+    REPX    {pminsd x, m13}, m9, m10, m6, m3
+    REPX    {pmulld x, m14}, m6, m3, m1, m5
+    paddd                m6, m11
+    paddd                m3, m11
+    psubd                m4, m6, m1    ; t20
+    paddd                m6, m1        ; t27
+    psubd                m1, m3, m5    ; t21a
+    paddd                m3, m5        ; t26a
+    REPX    {psrad  x, 12 }, m4, m1, m3, m6
+    mova          [r6+32*0], m4
+    mova          [r6+32*1], m1
+    mova                 m4, [r6+32*2] ; t30
+    mova                 m1, [r6+32*3] ; t31a
+    psubd                m5, m4, m8    ; t25a
+    paddd                m4, m8        ; t30a
+    psubd                m8, m1, m0    ; t24
+    paddd                m1, m0        ; t31
+    REPX    {pmaxsd x, m12}, m8, m5, m4, m1
+    REPX    {pminsd x, m13}, m8, m5, m4, m1
+    REPX    {pmulld x, m14}, m5, m8, m7, m2
+    paddd                m5, m11
+    paddd                m8, m11
+    psubd                m0, m5, m7    ; t22
+    paddd                m5, m7        ; t25
+    psubd                m7, m8, m2    ; t23a
+    paddd                m2, m8        ; t24a
+    REPX    {psrad  x, 12 }, m0, m7, m2, m5
+    mova          [r6+32*2], m0
+    mova          [r6+32*3], m7
+    mov                  r4, r6
+    add                  r6, 32*8
+    mova          [r6-32*4], m2
+    mova          [r6-32*3], m5
+    mova          [r6-32*2], m3
+    mova          [r6-32*1], m6
+    mova          [r6+32*0], m9
+    mova          [r6+32*1], m10
+    mova          [r6+32*2], m4
+    mova          [r6+32*3], m1
+    mov                  r5, r6
+    add                  r6, 32*8
+    ret
+ALIGN function_align
+.main_end:
+    psrld               m11, 10 ; pd_2
+    IDCT32_END            0, 15, 8, 9, 10, 2
+    IDCT32_END            1, 14, 8, 9, 10, 2
+    punpckhwd            m8, m0, m1   ; 16 17
+    punpcklwd            m0, m1       ;  0  1
+    punpcklwd            m1, m14, m15 ; 14 15
+    punpckhwd           m14, m15      ; 30 31
+    mova          [r5+32*3], m8
+    mova          [r5+32*2], m14
+    IDCT32_END            2, 15, 8, 9, 10, 2
+    IDCT32_END            3, 14, 8, 9, 10, 2
+    punpckhwd            m8, m2, m3   ; 18 19
+    punpcklwd            m2, m3       ;  2  3
+    punpcklwd            m3, m14, m15 ; 12 13
+    punpckhwd           m14, m15      ; 28 29
+    mova          [r5+32*1], m8
+    mova          [r5+32*0], m14
+    IDCT32_END            4, 15, 8, 9, 10, 2
+    IDCT32_END            5, 14, 8, 9, 10, 2
+    punpckhwd            m8, m4, m5   ; 20 21
+    punpcklwd            m4, m5       ;  4  5
+    punpcklwd            m5, m14, m15 ; 10 11
+    punpckhwd           m14, m15      ; 26 27
+    mova          [r5-32*1], m8
+    mova          [r5-32*2], m14
+    IDCT32_END            6, 15, 8, 9, 10, 2
+    IDCT32_END            7, 14, 8, 9, 10, 2
+    punpckhwd            m8, m6, m7   ; 22 23
+    punpcklwd            m6, m7       ;  6  7
+    punpcklwd            m7, m14, m15 ;  8  9
+    punpckhwd           m14, m15      ; 24 25
+    mova          [r5-32*3], m8
+    mova          [r5-32*4], m14
+.transpose:
+    punpckhdq           m15, m3, m1
+    punpckldq            m3, m1
+    punpckhdq            m1, m4, m6
+    punpckldq            m4, m6
+    punpckhdq            m6, m0, m2
+    punpckldq            m0, m2
+    punpckhdq            m2, m7, m5
+    punpckldq            m7, m5
+    punpcklqdq           m5, m2, m15
+    punpckhqdq           m2, m15
+    punpckhqdq          m15, m7, m3
+    punpcklqdq           m7, m3
+    punpckhqdq           m3, m6, m1
+    punpcklqdq           m6, m1
+    punpckhqdq           m1, m0, m4
+    punpcklqdq           m0, m4
+    vperm2i128           m4, m0, m7, 0x31
+    vinserti128          m0, xm7, 1
+    vperm2i128           m7, m3, m2, 0x31
+    vinserti128          m3, xm2, 1
+    vinserti128          m2, m6, xm5, 1
+    vperm2i128           m6, m5, 0x31
+    vperm2i128           m5, m1, m15, 0x31
+    vinserti128          m1, xm15, 1
+    ret
+
+cglobal inv_txfm_add_identity_identity_8x32_10bpc, 4, 7, 8, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_10bpc_max]
+.pass1:
+    vpbroadcastd         m5, [pw_5]
+    pxor                 m6, m6
+    mov                 r6d, eobd
+    add                eobb, 21
+    cmovc              eobd, r6d ; 43, 107, 171 -> 64, 128, 192
+    lea                  r6, [strideq*3]
+    lea                  r5, [strideq*5]
+    lea                  r4, [strideq+r6*2] ; strideq*7
+.loop:
+    mova                 m0, [cq+128*0]
+    packssdw             m0, [cq+128*1]
+    mova                 m1, [cq+128*2]
+    packssdw             m1, [cq+128*3]
+    mova                 m2, [cq+128*4]
+    packssdw             m2, [cq+128*5]
+    mova                 m3, [cq+128*6]
+    packssdw             m3, [cq+128*7]
+    REPX     {paddsw x, m5}, m0, m1, m2, m3
+    REPX     {psraw  x, 3 }, m0, m1, m2, m3
+    call .main_zero
+    add                  cq, 32
+    lea                dstq, [dstq+strideq*8]
+    sub                eobd, 64
+    jge .loop
+    RET
+ALIGN function_align
+.main_zero:
+    REPX {mova [cq+128*x], m6}, 0, 1, 2, 3, 4, 5, 6, 7
+.main:
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m0, m4
+    punpcklwd            m0, m4
+    punpckhwd            m4, m2, m1
+    punpcklwd            m2, m1
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    mova                xm4, [dstq+strideq*0]
+    vinserti128          m4, [dstq+strideq*4], 1
+    paddw                m0, m4
+    mova                xm4, [dstq+strideq*1]
+    vinserti128          m4, [dstq+r5       ], 1
+    paddw                m1, m4
+    mova                xm4, [dstq+strideq*2]
+    vinserti128          m4, [dstq+r6*2     ], 1
+    paddw                m2, m4
+    mova                xm4, [dstq+r6       ]
+    vinserti128          m4, [dstq+r4       ], 1
+    paddw                m3, m4
+    REPX     {pmaxsw x, m6}, m0, m1, m2, m3
+    REPX     {pminsw x, m7}, m0, m1, m2, m3
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*4], m0, 1
+    mova         [dstq+strideq*1], xm1
+    vextracti128 [dstq+r5       ], m1, 1
+    mova         [dstq+strideq*2], xm2
+    vextracti128 [dstq+r6*2     ], m2, 1
+    mova         [dstq+r6       ], xm3
+    vextracti128 [dstq+r4       ], m3, 1
+    ret
+
+cglobal inv_txfm_add_dct_dct_8x32_12bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 7, 16, 32*24, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    mov                  r4, cq
+    lea                  r6, [rsp+32*4]
+    call .pass1_main
+    cmp                eobd, 43
+    jge .eob43
+    jmp .pass2_fast
+.eob43:
+    call .pass1_main
+    cmp                eobd, 107
+    jge .eob107
+.pass2_fast:
+    mov                  cq, r4
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    pmaxsd               m0, m12, [cq+128*1+ 0]
+    pmaxsd               m1, m12, [cq+128*7+ 0]
+    pmaxsd               m2, m12, [cq+128*1+32]
+    pmaxsd               m3, m12, [cq+128*7+32]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3
+    vpbroadcastd        m14, [pd_2896]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1_fast
+    pmaxsd               m0, m12, [cq+128*3+ 0]
+    pmaxsd               m1, m12, [cq+128*5+ 0]
+    pmaxsd               m2, m12, [cq+128*3+32]
+    pmaxsd               m3, m12, [cq+128*5+32]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2_fast
+    pmaxsd               m0, m12, [cq+128*2+ 0]
+    pmaxsd               m1, m12, [cq+128*6+ 0]
+    pmaxsd               m2, m12, [cq+128*2+32]
+    pmaxsd               m3, m12, [cq+128*6+32]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3
+    call m(idct_8x16_internal_10bpc).main_oddhalf_fast
+    pmaxsd               m0, m12, [cq+128*0+ 0]
+    pmaxsd               m1, m12, [cq+128*4+ 0]
+    pmaxsd               m2, m12, [cq+128*0+32]
+    pmaxsd               m3, m12, [cq+128*4+32]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    jmp .pass2_end
+.eob107:
+    call .pass1_main
+    cmp                eobd, 171
+    jge .eob171
+    jmp .pass2
+.eob171:
+    call .pass1_main
+.pass2:
+    mov                  cq, r4
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    pmaxsd               m0, m12, [cq+128*1+ 0]
+    pmaxsd               m1, m12, [cq+128*7+ 0]
+    pmaxsd               m2, m12, [cq+128*1+32]
+    pmaxsd               m3, m12, [cq+128*7+32]
+    pmaxsd               m4, m12, [cq+128*1+64]
+    pmaxsd               m5, m12, [cq+128*7+64]
+    pmaxsd               m6, m12, [cq+128*1+96]
+    pmaxsd               m7, m12, [cq+128*7+96]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    vpbroadcastd        m14, [pd_2896]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1
+    pmaxsd               m0, m12, [cq+128*3+ 0]
+    pmaxsd               m1, m12, [cq+128*5+ 0]
+    pmaxsd               m2, m12, [cq+128*3+32]
+    pmaxsd               m3, m12, [cq+128*5+32]
+    pmaxsd               m4, m12, [cq+128*3+64]
+    pmaxsd               m5, m12, [cq+128*5+64]
+    pmaxsd               m6, m12, [cq+128*3+96]
+    pmaxsd               m7, m12, [cq+128*5+96]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2
+    pmaxsd               m0, m12, [cq+128*2+ 0]
+    pmaxsd               m1, m12, [cq+128*6+ 0]
+    pmaxsd               m2, m12, [cq+128*2+32]
+    pmaxsd               m3, m12, [cq+128*6+32]
+    pmaxsd               m4, m12, [cq+128*2+64]
+    pmaxsd               m5, m12, [cq+128*6+64]
+    pmaxsd               m6, m12, [cq+128*2+96]
+    pmaxsd               m7, m12, [cq+128*6+96]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_8x16_internal_10bpc).main_oddhalf
+    pmaxsd               m0, m12, [cq+128*0+ 0]
+    pmaxsd               m1, m12, [cq+128*4+ 0]
+    pmaxsd               m2, m12, [cq+128*0+32]
+    pmaxsd               m3, m12, [cq+128*4+32]
+    pmaxsd               m4, m12, [cq+128*0+64]
+    pmaxsd               m5, m12, [cq+128*4+64]
+    pmaxsd               m6, m12, [cq+128*0+96]
+    pmaxsd               m7, m12, [cq+128*4+96]
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+.pass2_end:
+    psrld               m11, 8 ; pd_8
+    IDCT32_END            0, 15, 8, 9, 10, 4
+    IDCT32_END            1, 14, 8, 9, 10, 4
+    punpckhqdq           m8, m0, m1   ; 16 17 (interleaved)
+    punpcklqdq           m0, m1       ;  0  1 (interleaved)
+    punpcklqdq           m1, m14, m15 ; 14 15 (interleaved)
+    punpckhqdq          m14, m15      ; 30 31 (interleaved)
+    mova          [r5+32*3], m8
+    mova          [r5+32*2], m14
+    IDCT32_END            2, 15, 8, 9, 10, 4
+    IDCT32_END            3, 14, 8, 9, 10, 4
+    punpckhqdq            m8, m2, m3   ; 18 19 (interleaved)
+    punpcklqdq            m2, m3       ;  2  3 (interleaved)
+    punpcklqdq            m3, m14, m15 ; 12 13 (interleaved)
+    punpckhqdq           m14, m15      ; 28 29 (interleaved)
+    mova          [r5+32*1], m8
+    mova          [r5+32*0], m14
+    IDCT32_END            4, 15, 8, 9, 10, 4
+    IDCT32_END            5, 14, 8, 9, 10, 4
+    punpckhqdq            m8, m4, m5   ; 20 21 (interleaved)
+    punpcklqdq            m4, m5       ;  4  5 (interleaved)
+    punpcklqdq            m5, m14, m15 ; 10 11 (interleaved)
+    punpckhqdq           m14, m15      ; 26 27 (interleaved)
+    mova          [r5-32*1], m8
+    mova          [r5-32*2], m14
+    IDCT32_END            6, 15, 8, 9, 10, 4
+    IDCT32_END            7, 14, 8, 9, 10, 4
+    punpckhqdq            m8, m6, m7   ; 22 23 (interleaved)
+    punpcklqdq            m6, m7       ;  6  7 (interleaved)
+    punpcklqdq            m7, m14, m15 ;  8  9 (interleaved)
+    punpckhqdq           m14, m15      ; 24 25 (interleaved)
+    mova          [r5-32*3], m8
+    mova          [r5-32*4], m14
+    mova                m15, m1
+.end:
+    vpermq               m0, m0, q3120
+    vpermq               m1, m2, q3120
+    call m(idct_8x8_internal_12bpc).write_8x4_start
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m4, q3120
+    vpermq               m1, m6, q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m7, q3120
+    vpermq               m1, m5, q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, m3, q3120
+    vpermq               m1, m15, q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, [r5+32*3], q3120
+    vpermq               m1, [r5+32*1], q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, [r5-32*1], q3120
+    vpermq               m1, [r5-32*3], q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, [r5-32*4], q3120
+    vpermq               m1, [r5-32*2], q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    vpermq               m0, [r5+32*0], q3120
+    vpermq               m1, [r5+32*2], q3120
+    call m(idct_8x8_internal_10bpc).write_8x4
+    RET
+.dconly:
+    imul                r6d, [cq], 181
+    vpbroadcastd         m2, [dconly_12bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 32
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_8x8_10bpc).dconly3
+ALIGN function_align
+.pass1_main:
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).pass1_main_part1
+    TRANSPOSE_8X8_DWORD   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15
+    mova         [cq+128*0], m0
+    mova         [cq+128*1], m1
+    mova         [cq+128*2], m2
+    mova         [cq+128*3], m3
+    mova         [cq+128*4], m4
+    mova         [cq+128*5], m5
+    mova         [cq+128*6], m6
+    mova         [cq+128*7], m7
+    add                  cq, 32
+    ret
+ALIGN function_align
+.main_end:
+    psrld               m11, 10 ; pd_2
+    IDCT32_END            0, 15, 8, 9, 10, 2, 0
+    mova         [cq+32*16], m8
+    mova         [cq+32*31], m9
+    IDCT32_END            1, 14, 8, 9, 10, 2, 0
+    mova         [cq+32*17], m8
+    mova         [cq+32*30], m9
+    mova         [cq+32*14], m14
+    IDCT32_END            2, 14, 8, 9, 10, 2, 0
+    mova         [cq+32*18], m8
+    mova         [cq+32*29], m9
+    mova         [cq+32*13], m14
+    IDCT32_END            3, 14, 8, 9, 10, 2, 0
+    mova         [cq+32*19], m8
+    mova         [cq+32*28], m9
+    mova         [cq+32*12], m14
+    IDCT32_END            4, 14, 8, 9, 10, 2, 0
+    mova         [cq+32*20], m8
+    mova         [cq+32*27], m9
+    mova         [cq+32* 0], m0
+    mova         [cq+32* 1], m1
+    mova         [cq+32* 2], m2
+    IDCT32_END            5, 10, 0, 1, 2, 2, 0
+    mova         [cq+32*21], m0
+    mova         [cq+32*26], m1
+    IDCT32_END            6, 9, 0, 1, 2, 2, 0
+    mova         [cq+32*22], m0
+    mova         [cq+32*25], m1
+    IDCT32_END            7, 8, 0, 1, 2, 2, 0
+    mova         [cq+32*23], m0
+    mova         [cq+32*24], m1
+    mova                 m0, [cq+32* 0]
+    mova                 m1, [cq+32* 1]
+    mova                 m2, [cq+32* 2]
+    mova                m11, m14
+    mova                m12, [cq+32*12]
+    mova                m13, [cq+32*13]
+    mova                m14, [cq+32*14]
+    ret
+
+cglobal inv_txfm_add_identity_identity_8x32_12bpc, 4, 7, 8, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_12bpc_max]
+    jmp m(inv_txfm_add_identity_identity_8x32_10bpc).pass1
+
+cglobal inv_txfm_add_dct_dct_32x8_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jnz .full
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_10bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 8
+.dconly:
+    add                 r6d, 640
+    sar                 r6d, 10
+.dconly2:
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    movd                xm0, r6d
+    paddsw              xm0, xm3
+    vpbroadcastw         m0, xm0
+.dconly_loop:
+    paddsw               m1, m0, [dstq+32*0]
+    paddsw               m2, m0, [dstq+32*1]
+    psubusw              m1, m3
+    psubusw              m2, m3
+    mova        [dstq+32*0], m1
+    mova        [dstq+32*1], m2
+    add                dstq, strideq
+    dec                 r3d
+    jg .dconly_loop
+    RET
+.full:
+    PROLOGUE              0, 7, 16, 32*24, dst, stride, c, eob
+    lea                  r6, [rsp+32*4]
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    call .pass1
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_end
+    lea                  r6, [deint_shuf+128]
+    vpbroadcastd        m11, [pw_2048]
+    mov                  r4, dstq
+    call .pass2
+    mova                 m0, [r5+32*3] ; 16 17
+    mova                 m1, [r5+32*2] ; 30 31
+    mova                 m2, [r5+32*1] ; 18 19
+    mova                 m3, [r5+32*0] ; 28 29
+    mova                 m4, [r5-32*1] ; 20 21
+    mova                 m5, [r5-32*2] ; 26 27
+    mova                 m6, [r5-32*3] ; 22 23
+    mova                 m7, [r5-32*4] ; 24 25
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).transpose
+    lea                dstq, [r4+32]
+    call .pass2
+    RET
+ALIGN function_align
+.pass2:
+    call m(idct_16x8_internal_8bpc).main
+    REPX  {pmulhrsw x, m11}, m0, m1, m2, m3
+    call m(idct_16x8_internal_10bpc).write_16x4_start
+    pmulhrsw             m0, m11, m4
+    pmulhrsw             m1, m11, m5
+    pmulhrsw             m2, m11, m6
+    pmulhrsw             m3, m11, m7
+    jmp m(idct_16x8_internal_10bpc).write_16x4_zero
+ALIGN function_align
+.pass1:
+    mova                 m0, [cq+32* 1]
+    mova                 m1, [cq+32* 7]
+    mova                 m2, [cq+32* 9]
+    mova                 m3, [cq+32*15]
+    mova                 m4, [cq+32*17]
+    mova                 m5, [cq+32*23]
+    mova                 m6, [cq+32*25]
+    mova                 m7, [cq+32*31]
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m14, [pd_2896]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1
+    mova                 m0, [cq+32* 3]
+    mova                 m1, [cq+32* 5]
+    mova                 m2, [cq+32*11]
+    mova                 m3, [cq+32*13]
+    mova                 m4, [cq+32*19]
+    mova                 m5, [cq+32*21]
+    mova                 m6, [cq+32*27]
+    mova                 m7, [cq+32*29]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2
+    mova                 m0, [cq+32* 2]
+    mova                 m1, [cq+32* 6]
+    mova                 m2, [cq+32*10]
+    mova                 m3, [cq+32*14]
+    mova                 m4, [cq+32*18]
+    mova                 m5, [cq+32*22]
+    mova                 m6, [cq+32*26]
+    mova                 m7, [cq+32*30]
+    call m(idct_8x16_internal_10bpc).main_oddhalf
+    mova                 m0, [cq+32* 0]
+    mova                 m1, [cq+32* 4]
+    mova                 m2, [cq+32* 8]
+    mova                 m3, [cq+32*12]
+    mova                 m4, [cq+32*16]
+    mova                 m5, [cq+32*20]
+    mova                 m6, [cq+32*24]
+    mova                 m7, [cq+32*28]
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    ret
+
+cglobal inv_txfm_add_identity_identity_32x8_10bpc, 4, 7, 8, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_10bpc_max]
+.pass1:
+    vpbroadcastd         m5, [pw_4096]
+    pxor                 m6, m6
+    mov                 r6d, eobd
+    add                eobb, 21
+    cmovc              eobd, r6d
+    lea                  r6, [strideq*3]
+    lea                  r5, [strideq*5]
+    lea                  r4, [strideq+r6*2] ; strideq*7
+.loop:
+    mova                 m0, [cq+32*0]
+    packssdw             m0, [cq+32*1]
+    mova                 m1, [cq+32*2]
+    packssdw             m1, [cq+32*3]
+    REPX {mova [cq+32*x], m6}, 0, 1, 2, 3
+    add                  cq, 32*8
+    mova                 m2, [cq-32*4]
+    packssdw             m2, [cq-32*3]
+    mova                 m3, [cq-32*2]
+    packssdw             m3, [cq-32*1]
+    REPX   {pmulhrsw x, m5}, m0, m1, m2, m3
+    REPX {mova [cq+32*x], m6}, -4, -3, -2, -1
+    call m(inv_txfm_add_identity_identity_8x32_10bpc).main
+    add                dstq, 16
+    sub                eobd, 64
+    jge .loop
+    RET
+
+cglobal inv_txfm_add_dct_dct_32x8_12bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jnz .full
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_12bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 8
+    jmp m(inv_txfm_add_dct_dct_32x8_10bpc).dconly
+.full:
+    PROLOGUE              0, 7, 16, 32*24, dst, stride, c, eob
+    lea                  r6, [rsp+32*4]
+    vpbroadcastd        m12, [clip_20b_min]
+    vpbroadcastd        m13, [clip_20b_max]
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).pass1
+    call m(inv_txfm_add_dct_dct_8x32_12bpc).main_end
+    mov                  r4, dstq
+    call m(idct_16x8_internal_12bpc).pass2_main
+    mova                 m0, [cq+32* 0] ; 16
+    mova                 m1, [cq+32* 1] ; 17
+    mova                 m2, [cq+32* 2] ; 18
+    mova                 m3, [cq+32* 3] ; 19
+    mova                 m4, [cq+32* 4] ; 20
+    mova                 m5, [cq+32* 5] ; 21
+    mova                 m6, [cq+32* 6] ; 22
+    mova                 m7, [cq+32* 7] ; 23
+    mova                 m8, [cq+32* 8] ; 24
+    mova                 m9, [cq+32* 9] ; 25
+    mova                m10, [cq+32*10] ; 26
+    mova                m11, [cq+32*11] ; 27
+    mova                m12, [cq+32*12] ; 28
+    mova                m13, [cq+32*13] ; 29
+    mova                m14, [cq+32*14] ; 30
+    mova                m15, [cq+32*15] ; 31
+    lea                dstq, [r4+32]
+    call m(idct_16x8_internal_12bpc).pass2_main
+    RET
+
+cglobal inv_txfm_add_identity_identity_32x8_12bpc, 4, 7, 8, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_12bpc_max]
+    jmp m(inv_txfm_add_identity_identity_32x8_10bpc).pass1
+
+%macro IDCT32_PASS2_END 6 ; coefs[1-2], tmp[1-2], offset[1-2]
+    mova                m%4, [%2]
+    paddsw              m%3, m%1, m%4
+    psubsw              m%1, m%4
+%if %1 == 0
+    pxor                 m6, m6
+%endif
+    pmulhrsw            m%3, m15
+    pmulhrsw            m%1, m15
+    paddw               m%3, [dstq+%5]
+    paddw               m%1, [r2+%6]
+    pmaxsw              m%3, m6
+    pmaxsw              m%1, m6
+    pminsw              m%3, m7
+    pminsw              m%1, m7
+    mova          [dstq+%5], m%3
+    mova            [r2+%6], m%1
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_16x32_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 8, 16, 32*36, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    vpbroadcastd        m14, [pd_2896]
+    lea                  r6, [rsp+32*16]
+    lea                  r4, [r6+32*8]
+    lea                  r5, [r6+32*16]
+    call .main
+    sub                eobd, 44
+    jge .eob44
+    vperm2i128           m2, m0, m3, 0x31 ;  5
+    vinserti128          m0, xm3, 1       ;  1
+    vperm2i128           m3, m1, m4, 0x31 ;  7
+    vinserti128          m1, xm4, 1       ;  3
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    REPX {mova [r6+32*x], m4}, 0, 1, 2, 3
+    jmp .fast
+.dconly:
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_10bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 32
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    jmp m(inv_txfm_add_dct_dct_16x4_10bpc).dconly2
+.eob44:
+    mova          [r4+16*0], xm0
+    mova          [r4+16*1], xm3
+    mova          [r4+16*2], xm1
+    mova          [r4+16*3], xm4
+    vextracti128  [r4+16*4], m0, 1
+    vextracti128  [r4+16*5], m3, 1
+    vextracti128  [r4+16*6], m1, 1
+    vextracti128  [r4+16*7], m4, 1
+    call .main
+    sub                eobd, 107
+    jge .eob151
+    vperm2i128           m7, m1, m4, 0x31 ; 15
+    vinserti128          m5, m1, xm4, 1   ; 11
+    vperm2i128           m6, m0, m3, 0x31 ; 13
+    vinserti128          m4, m0, xm3, 1   ;  9
+    mova                 m0, [r4+32*0]
+    mova                 m1, [r4+32*1]
+    mova                 m2, [r4+32*2]
+    mova                 m3, [r4+32*3]
+.fast:
+    lea                  r6, [pw_5+128]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, m15
+    jmp .idct16
+.eob151:
+    mova          [r4-16*8], xm0
+    mova          [r4-16*7], xm3
+    mova          [r4-16*6], xm1
+    mova          [r4-16*5], xm4
+    vextracti128  [r4-16*4], m0, 1
+    vextracti128  [r4-16*3], m3, 1
+    vextracti128  [r4-16*2], m1, 1
+    vextracti128  [r4-16*1], m4, 1
+    call .main
+    sub                eobd, 128
+    jge .eob279
+    vperm2i128          m10, m0, m3, 0x31 ; 21
+    vinserti128          m8, m0, xm3, 1   ; 17
+    vperm2i128          m11, m1, m4, 0x31 ; 23
+    vinserti128          m9, m1, xm4, 1   ; 19
+    pxor                m12, m12
+    REPX      {mova x, m12}, m13, m14, m15
+    REPX {mova [r6+32*x], m12}, 0, 1, 2, 3
+    jmp .full
+.eob279:
+    mova          [r5+16*0], xm0
+    mova          [r5+16*1], xm3
+    mova          [r5+16*2], xm1
+    mova          [r5+16*3], xm4
+    vextracti128  [r5+16*4], m0, 1
+    vextracti128  [r5+16*5], m3, 1
+    vextracti128  [r5+16*6], m1, 1
+    vextracti128  [r5+16*7], m4, 1
+    call .main
+    vperm2i128          m14, m0, m3, 0x31 ; 29
+    vinserti128         m12, m0, xm3, 1   ; 25
+    vperm2i128          m15, m1, m4, 0x31 ; 31
+    vinserti128         m13, m1, xm4, 1   ; 27
+    mova                 m8, [r5+32*0]
+    mova                 m9, [r5+32*1]
+    mova                m10, [r5+32*2]
+    mova                m11, [r5+32*3]
+.full:
+    mova                 m0, [r4+32*0]
+    mova                 m1, [r4+32*1]
+    mova                 m2, [r4+32*2]
+    mova                 m3, [r4+32*3]
+    mova                 m4, [r4-32*4]
+    mova                 m5, [r4-32*3]
+    mova                 m6, [r4-32*2]
+    mova                 m7, [r4-32*1]
+    lea                  r6, [pw_5 + 128]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    lea                  r3, [rsp+32*8]
+    mova                 m8, [r3+32*0]
+    mova                 m9, [r3+32*1]
+    mova                m10, [r3+32*2]
+    mova                m11, [r3+32*3]
+    mova                m12, [r3-32*4]
+    mova                m13, [r3-32*3]
+    mova                m14, [r3-32*2]
+    mova                m15, [r3-32*1]
+.idct16:
+    lea                  r3, [rsp+32*16]
+    mova                 m0, [r3+32*0]
+    mova                 m1, [r3+32*1]
+    mova                 m2, [r3+32*2]
+    mova                 m3, [r3+32*3]
+    mova                 m4, [r3-32*4]
+    mova                 m5, [r3-32*3]
+    mova                 m6, [r3-32*2]
+    mova                 m7, [r3-32*1]
+    mova              [rsp], m15
+    call m(idct_16x16_internal_8bpc).main
+    imul                 r2, strideq, 19
+    lea                  r3, [strideq*3]
+    add                  r2, dstq
+    call .pass2_end
+    RET
+ALIGN function_align
+.main:
+    pmulld               m0, m14, [cq+128* 1]
+    pmulld               m1, m14, [cq+128* 3]
+    pmulld               m2, m14, [cq+128* 5]
+    pmulld               m3, m14, [cq+128* 7]
+    pmulld               m4, m14, [cq+128* 9]
+    pmulld               m5, m14, [cq+128*11]
+    pmulld               m6, m14, [cq+128*13]
+    pmulld               m7, m14, [cq+128*15]
+    call m(idct_8x16_internal_10bpc).main_oddhalf_rect2
+    pmulld               m0, m14, [cq+128* 0]
+    pmulld               m1, m14, [cq+128* 2]
+    pmulld               m2, m14, [cq+128* 4]
+    pmulld               m3, m14, [cq+128* 6]
+    pmulld               m4, m14, [cq+128* 8]
+    pmulld               m5, m14, [cq+128*10]
+    pmulld               m6, m14, [cq+128*12]
+    pmulld               m7, m14, [cq+128*14]
+    call m(idct_8x8_internal_10bpc).main_rect2
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    psrld               m15, m11, 11 ; pd_1
+    mova                 m8, [r6-32*4]
+    mova                 m9, [r6-32*3]
+    REPX     {paddd x, m15}, m0, m1, m2, m3, m4, m5, m6, m7
+    psubd               m10, m0, m8 ; out15
+    paddd                m0, m8     ; out0
+    mova                 m8, [r6-32*2]
+    paddd               m15, m1, m9 ; out1
+    psubd                m1, m9     ; out14
+    mova                 m9, [r6-32*1]
+    REPX       {psrad x, 1}, m0, m15, m10, m1
+    packssdw             m0, m15
+    packssdw             m1, m10
+    psubd               m10, m2, m8 ; out13
+    paddd                m2, m8     ; out2
+    mova                 m8, [r6+32*0]
+    paddd               m15, m3, m9 ; out3
+    psubd                m3, m9     ; out12
+    mova                 m9, [r6+32*1]
+    REPX       {psrad x, 1}, m2, m15, m10, m3
+    packssdw             m2, m15
+    packssdw             m3, m10
+    psubd               m10, m4, m8 ; out11
+    paddd                m4, m8     ; out4
+    mova                 m8, [r6+32*2]
+    paddd               m15, m5, m9 ; out5
+    psubd                m5, m9     ; out10
+    mova                 m9, [r6+32*3]
+    REPX       {psrad x, 1}, m4, m10, m15, m5
+    packssdw             m4, m15
+    packssdw             m5, m10
+    psubd               m10, m6, m8 ; out9
+    paddd                m6, m8     ; out6
+    paddd               m15, m7, m9 ; out7
+    psubd                m7, m9     ; out8
+    REPX       {psrad x, 1}, m6, m10, m15, m7
+    packssdw             m6, m15
+    packssdw             m7, m10
+    punpckhwd            m8, m0, m2
+    punpcklwd            m0, m2
+    punpckhwd            m2, m3, m1
+    punpcklwd            m3, m1
+    punpckhwd            m1, m4, m6
+    punpcklwd            m4, m6
+    punpcklwd            m6, m7, m5
+    punpckhwd            m7, m5
+    pxor                 m5, m5
+    mov                 r7d, 128*13
+.main_zero_loop:
+    mova      [cq+r7-128*1], m5
+    mova      [cq+r7+128*0], m5
+    mova      [cq+r7+128*1], m5
+    mova      [cq+r7+128*2], m5
+    sub                 r7d, 128*4
+    jg .main_zero_loop
+    add                  cq, 32
+    punpcklwd            m5, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m4, m1
+    punpckhwd            m4, m1
+    punpckhwd            m1, m0, m8
+    punpcklwd            m0, m8
+    punpckhwd            m8, m6, m7
+    punpcklwd            m6, m7
+    punpcklqdq           m7, m1, m4
+    punpckhqdq           m1, m4
+    punpckhqdq           m4, m8, m3
+    punpcklqdq           m8, m3
+    punpckhqdq           m3, m6, m5
+    punpcklqdq           m6, m5
+    punpcklqdq           m5, m0, m2
+    punpckhqdq           m0, m2
+    mova          [r6+16*0], xm5
+    mova          [r6+16*1], xm6
+    mova          [r6+16*2], xm7
+    mova          [r6+16*3], xm8
+    vextracti128  [r6+16*4], m5, 1
+    vextracti128  [r6+16*5], m6, 1
+    vextracti128  [r6+16*6], m7, 1
+    vextracti128  [r6+16*7], m8, 1
+    sub                  r6, 32*4
+    ret
+ALIGN function_align
+.pass2_end:
+    mova [rsp+gprsize+32*0], m6
+    mova [rsp+gprsize+32*2], m7
+    mova [rsp+gprsize+32*3], m15
+    vpbroadcastd        m15, [pw_2048]
+    vpbroadcastd         m7, [pixel_10bpc_max]
+    IDCT32_PASS2_END      0, r5+32*3, 1, 6, strideq*0, r3*4
+    IDCT32_PASS2_END      4, r5-32*1, 0, 1, strideq*4, strideq*8
+    IDCT32_PASS2_END      8, r4+32*3, 0, 4, strideq*8, strideq*4
+    IDCT32_PASS2_END     12, r4-32*1, 0, 4, r3*4,      strideq*0
+    add                dstq, strideq
+    sub                  r2, strideq
+    mova                 m1, [rsp+gprsize+32*1]
+    IDCT32_PASS2_END      1, r5+32*2, 0, 4, strideq*0, r3*4
+    IDCT32_PASS2_END      5, r5-32*2, 0, 4, strideq*4, strideq*8
+    IDCT32_PASS2_END      9, r4+32*2, 0, 4, strideq*8, strideq*4
+    IDCT32_PASS2_END     13, r4-32*2, 0, 4, r3*4,      strideq*0
+    add                dstq, strideq
+    sub                  r2, strideq
+    mova                 m1, [rsp+gprsize+32*0]
+    IDCT32_PASS2_END      2, r5+32*1, 0, 4, strideq*0, r3*4
+    IDCT32_PASS2_END      1, r5-32*3, 0, 4, strideq*4, strideq*8
+    IDCT32_PASS2_END     10, r4+32*1, 0, 4, strideq*8, strideq*4
+    IDCT32_PASS2_END     14, r4-32*3, 0, 4, r3*4,      strideq*0
+    add                dstq, strideq
+    sub                  r2, strideq
+    mova                 m1, [rsp+gprsize+32*2]
+    mova                 m2, [rsp+gprsize+32*3]
+    IDCT32_PASS2_END      3, r5+32*0, 0, 4, strideq*0, r3*4
+    IDCT32_PASS2_END      1, r5-32*4, 0, 4, strideq*4, strideq*8
+    IDCT32_PASS2_END     11, r4+32*0, 0, 4, strideq*8, strideq*4
+    IDCT32_PASS2_END      2, r4-32*4, 0, 4, r3*4,      strideq*0
+    ret
+
+cglobal inv_txfm_add_identity_identity_16x32_10bpc, 4, 7, 12, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_10bpc_max]
+.pass1:
+    vpbroadcastd         m8, [pw_2896x8]
+    vpbroadcastd         m9, [pw_1697x16]
+    vpbroadcastd        m11, [pw_8192]
+    lea                  r6, [strideq*5]
+    pxor                 m6, m6
+    paddw               m10, m11, m11 ; pw_16384
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 36
+    jl .ret
+    add                  cq, 128*8
+    lea                dstq, [r5+16]
+    call .main
+    sub                  cq, 128*8-32
+    lea                dstq, [r5+strideq*8]
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 107 ; eob < 143
+    jl .ret
+    add                  cq, 128*8
+    lea                dstq, [r5+16]
+    call .main
+    sub                  cq, 128*8-32
+    lea                dstq, [r5+strideq*8]
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 128 ; eob < 271
+    jl .ret
+    add                  cq, 128*8
+    lea                dstq, [r5+16]
+    call .main
+    sub                  cq, 128*8-32
+    lea                dstq, [r5+strideq*8]
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 128 ; eob < 399
+    jl .ret
+    add                  cq, 128*8
+    lea                dstq, [r5+16]
+    call .main
+.ret:
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [cq+128*0]
+    packssdw             m0, [cq+128*1]
+    mova                 m1, [cq+128*2]
+    packssdw             m1, [cq+128*3]
+    mova                 m2, [cq+128*4]
+    packssdw             m2, [cq+128*5]
+    mova                 m3, [cq+128*6]
+    packssdw             m3, [cq+128*7]
+    REPX  {pmulhrsw x, m8 }, m0, m1, m2, m3
+    REPX {IDTX16 x, 4, 9, 10}, 0, 1, 2, 3
+    REPX  {pmulhrsw x, m11}, m0, m1, m2, m3
+    REPX {mova [cq+128*x], m6}, 0, 1, 2, 3, 4, 5, 6, 7
+.main2:
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m0, m4
+    punpcklwd            m0, m4
+    punpcklwd            m4, m2, m1
+    punpckhwd            m2, m1
+    punpckhqdq           m1, m0, m4
+    punpcklqdq           m0, m4
+    call m(iidentity_8x8_internal_10bpc).write_2x8x2
+    punpcklqdq           m0, m3, m2
+    punpckhqdq           m1, m3, m2
+    jmp m(iidentity_8x8_internal_10bpc).write_2x8x2
+
+cglobal inv_txfm_add_identity_identity_16x32_12bpc, 4, 7, 12, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_12bpc_max]
+    jmp m(inv_txfm_add_identity_identity_16x32_10bpc).pass1
+
+cglobal inv_txfm_add_dct_dct_32x16_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 8, 16, 32*40, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    lea                  r6, [rsp+32*4]
+    call .main
+    cmp                eobd, 36
+    jge .full
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).transpose
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, [rsp]
+    lea                  r6, [pw_5+128]
+    mov                  r7, dstq
+    call m(idct_16x16_internal_8bpc).main
+    call .write_16x16
+    mova                 m0, [r5+32*3]
+    mova                 m1, [r5+32*2]
+    mova                 m2, [r5+32*1]
+    mova                 m3, [r5+32*0]
+    mova                 m4, [r5-32*1]
+    mova                 m5, [r5-32*2]
+    mova                 m6, [r5-32*3]
+    mova                 m7, [r5-32*4]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).transpose
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, [rsp]
+    jmp .end
+.dconly:
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_10bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 16
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 384
+    sar                 r6d, 9
+    jmp m(inv_txfm_add_dct_dct_32x8_10bpc).dconly2
+.full:
+    add                  cq, 32
+    mova          [r4+32*3], m0
+    mova          [r4+32*2], m1
+    mova          [r4+32*1], m2
+    mova          [r4+32*0], m3
+    mova          [r4-32*1], m4
+    mova          [r4-32*2], m5
+    mova          [r4-32*3], m6
+    mova          [r4-32*4], m7
+    call .main
+    sub                  r4, 32*16 ; topleft 16x8
+    call .transpose_16x16
+    lea                  r6, [pw_5+128]
+    mov                  r7, dstq
+    call m(idct_16x16_internal_8bpc).main
+    call .write_16x16
+    mova                 m0, [r5+32*3]
+    mova                 m1, [r5+32*2]
+    mova                 m2, [r5+32*1]
+    mova                 m3, [r5+32*0]
+    mova                 m4, [r5-32*1]
+    mova                 m5, [r5-32*2]
+    mova                 m6, [r5-32*3]
+    mova                 m7, [r5-32*4]
+    add                  r4, 32*8 ; bottomleft 16x8
+    call .transpose_16x16
+.end:
+    lea                dstq, [r7+32]
+    call m(idct_16x16_internal_8bpc).main
+    call .write_16x16
+    RET
+ALIGN function_align
+.transpose_16x16:
+    punpckhdq            m8, m3, m1
+    punpckldq            m3, m1
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    punpckhdq            m2, m7, m5
+    punpckldq            m7, m5
+    punpckhdq            m5, m4, m6
+    punpckldq            m4, m6
+    punpckhqdq           m6, m0, m4
+    punpcklqdq           m0, m4
+    punpckhqdq           m4, m1, m5
+    punpcklqdq           m1, m5
+    punpckhqdq           m5, m7, m3
+    punpcklqdq           m7, m3
+    punpckhqdq           m3, m2, m8
+    punpcklqdq           m2, m8
+    vinserti128          m8, m0, xm7, 1
+    vperm2i128          m12, m0, m7, 0x31
+    vinserti128          m9, m6, xm5, 1
+    vperm2i128          m13, m6, m5, 0x31
+    vinserti128         m10, m1, xm2, 1
+    vperm2i128          m14, m1, m2, 0x31
+    vinserti128         m11, m4, xm3, 1
+    vperm2i128          m15, m4, m3, 0x31
+    mova                 m0, [r4+32*3]
+    mova                 m1, [r4+32*2]
+    mova                 m2, [r4+32*1]
+    mova                 m3, [r4+32*0]
+    mova                 m4, [r4-32*1]
+    mova                 m5, [r4-32*2]
+    mova                 m6, [r4-32*3]
+    mova                 m7, [r4-32*4]
+    mova      [rsp+gprsize], m15
+    jmp m(inv_txfm_add_dct_dct_8x32_10bpc).transpose
+ALIGN function_align
+.main:
+    vpbroadcastd        m14, [pd_2896]
+    vpbroadcastd        m11, [pd_2048]
+    pmulld               m0, m14, [cq+64* 1]
+    pmulld               m1, m14, [cq+64* 7]
+    pmulld               m2, m14, [cq+64* 9]
+    pmulld               m3, m14, [cq+64*15]
+    pmulld               m4, m14, [cq+64*17]
+    pmulld               m5, m14, [cq+64*23]
+    pmulld               m6, m14, [cq+64*25]
+    pmulld               m7, m14, [cq+64*31]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1_rect2
+    pmulld               m0, m14, [cq+64* 3]
+    pmulld               m1, m14, [cq+64* 5]
+    pmulld               m2, m14, [cq+64*11]
+    pmulld               m3, m14, [cq+64*13]
+    pmulld               m4, m14, [cq+64*19]
+    pmulld               m5, m14, [cq+64*21]
+    pmulld               m6, m14, [cq+64*27]
+    pmulld               m7, m14, [cq+64*29]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2_rect2
+    pmulld               m0, m14, [cq+64* 2]
+    pmulld               m1, m14, [cq+64* 6]
+    pmulld               m2, m14, [cq+64*10]
+    pmulld               m3, m14, [cq+64*14]
+    pmulld               m4, m14, [cq+64*18]
+    pmulld               m5, m14, [cq+64*22]
+    pmulld               m6, m14, [cq+64*26]
+    pmulld               m7, m14, [cq+64*30]
+    call m(idct_8x16_internal_10bpc).main_oddhalf_rect2
+    pmulld               m0, m14, [cq+64* 0]
+    pmulld               m1, m14, [cq+64* 4]
+    pmulld               m2, m14, [cq+64* 8]
+    pmulld               m3, m14, [cq+64*12]
+    pmulld               m4, m14, [cq+64*16]
+    pmulld               m5, m14, [cq+64*20]
+    pmulld               m6, m14, [cq+64*24]
+    pmulld               m7, m14, [cq+64*28]
+    call m(idct_8x8_internal_10bpc).main_rect2
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    pxor                 m8, m8
+    mov                 r7d, 64*30
+.main_zero_loop:
+    mova       [cq+r7-64*2], m8
+    mova       [cq+r7-64*1], m8
+    mova       [cq+r7+64*0], m8
+    mova       [cq+r7+64*1], m8
+    sub                 r7d, 64*4
+    jg .main_zero_loop
+.main_end:
+    psrld               m11, 11 ; pd_1
+    IDCT32_END            0, 15, 8, 9, 10, 1
+    IDCT32_END            1, 14, 8, 9, 10, 1
+    punpckhwd            m8, m0, m1   ; 16 17
+    punpcklwd            m0, m1       ;  0  1
+    punpcklwd            m1, m14, m15 ; 14 15
+    punpckhwd           m14, m15      ; 30 31
+    mova          [r5+32*3], m8
+    mova          [r5+32*2], m14
+    IDCT32_END            2, 15, 8, 9, 10, 1
+    IDCT32_END            3, 14, 8, 9, 10, 1
+    punpckhwd            m8, m2, m3   ; 18 19
+    punpcklwd            m2, m3       ;  2  3
+    punpcklwd            m3, m14, m15 ; 12 13
+    punpckhwd           m14, m15      ; 28 29
+    mova          [r5+32*1], m8
+    mova          [r5+32*0], m14
+    IDCT32_END            4, 15, 8, 9, 10, 1
+    IDCT32_END            5, 14, 8, 9, 10, 1
+    punpckhwd            m8, m4, m5   ; 20 21
+    punpcklwd            m4, m5       ;  4  5
+    punpcklwd            m5, m14, m15 ; 10 11
+    punpckhwd           m14, m15      ; 26 27
+    mova          [r5-32*1], m8
+    mova          [r5-32*2], m14
+    IDCT32_END            6, 15, 8, 9, 10, 1
+    IDCT32_END            7, 14, 8, 9, 10, 1
+    punpckhwd            m8, m6, m7   ; 22 23
+    punpcklwd            m6, m7       ;  6  7
+    punpcklwd            m7, m14, m15 ;  8  9
+    punpckhwd           m14, m15      ; 24 25
+    mova          [r5-32*3], m8
+    mova          [r5-32*4], m14
+    ret
+ALIGN function_align
+.write_16x16:
+    mova                 m1, [rsp+gprsize+32*1]
+    mova [rsp+gprsize+32*0], m8
+    mova [rsp+gprsize+32*1], m9
+    mova [rsp+gprsize+32*2], m12
+    vpbroadcastd        m12, [pw_2048]
+    vpbroadcastd         m9, [pixel_10bpc_max]
+    lea                  r3, [strideq*3]
+    pxor                 m8, m8
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    pmulhrsw             m2, m12
+    pmulhrsw             m3, m12
+    call m(idct_16x8_internal_10bpc).write_16x4
+    pmulhrsw             m0, m12, m4
+    pmulhrsw             m1, m12, m5
+    pmulhrsw             m2, m12, m6
+    pmulhrsw             m3, m12, m7
+    call m(idct_16x8_internal_10bpc).write_16x4
+    pmulhrsw             m0, m12, [rsp+gprsize+32*0]
+    pmulhrsw             m1, m12, [rsp+gprsize+32*1]
+    pmulhrsw             m2, m12, m10
+    pmulhrsw             m3, m12, m11
+    call m(idct_16x8_internal_10bpc).write_16x4
+    pmulhrsw             m0, m12, [rsp+gprsize+32*2]
+    pmulhrsw             m1, m12, m13
+    pmulhrsw             m2, m12, m14
+    pmulhrsw             m3, m12, m15
+    jmp m(idct_16x8_internal_10bpc).write_16x4
+
+cglobal inv_txfm_add_identity_identity_32x16_10bpc, 4, 7, 11, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_10bpc_max]
+.pass1:
+    vpbroadcastd         m8, [pw_2896x8]
+    vpbroadcastd         m9, [pw_1697x16]
+    vpbroadcastd        m10, [pw_4096]
+    lea                  r6, [strideq*5]
+    pxor                 m6, m6
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 36
+    jl .ret
+    add                  cq, 32
+    lea                dstq, [dstq+strideq*4]
+    call .main
+    add                  cq, 64*8-32
+    lea                dstq, [r5+16*1]
+    call .main
+    sub                eobd, 107 ; eob < 143
+    jl .ret
+    add                  cq, 32
+    lea                dstq, [dstq+strideq*4]
+    call .main
+    add                  cq, 64*8-32
+    lea                dstq, [r5+16*2]
+    call .main
+    sub                eobd, 128 ; eob < 271
+    jl .ret
+    add                  cq, 32
+    lea                dstq, [dstq+strideq*4]
+    call .main
+    add                  cq, 64*8-32
+    lea                dstq, [r5+16*3]
+    call .main
+    sub                eobd, 128 ; eob < 399
+    jl .ret
+    add                  cq, 32
+    lea                dstq, [dstq+strideq*4]
+    call .main
+.ret:
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [cq+64*0]
+    packssdw             m0, [cq+64*1]
+    mova                 m1, [cq+64*2]
+    packssdw             m1, [cq+64*3]
+    mova                 m2, [cq+64*4]
+    packssdw             m2, [cq+64*5]
+    mova                 m3, [cq+64*6]
+    packssdw             m3, [cq+64*7]
+    REPX  {pmulhrsw x, m8 }, m0, m1, m2, m3
+    REPX  {paddsw   x, x  }, m0, m1, m2, m3
+    REPX  {IDTX16 x, 4, 9, _ }, 0, 1, 2, 3
+    REPX  {pmulhrsw x, m10}, m0, m1, m2, m3
+    REPX {mova [cq+64*x], m6}, 0, 1, 2, 3, 4, 5, 6, 7
+    jmp m(inv_txfm_add_identity_identity_16x32_10bpc).main2
+
+cglobal inv_txfm_add_identity_identity_32x16_12bpc, 4, 7, 11, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_12bpc_max]
+    jmp m(inv_txfm_add_identity_identity_32x16_10bpc).pass1
+
+cglobal inv_txfm_add_dct_dct_32x32_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 8, 16, 32*83, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    lea                  r6, [rsp+32*7]
+    call .main
+    cmp                eobd, 36
+    jl .fast
+    call .main
+    cmp                eobd, 136
+    jl .fast
+    call .main
+    cmp                eobd, 300
+    jl .fast
+    call .main
+    jmp .pass2
+.dconly:
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_10bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 32
+    jmp m(inv_txfm_add_dct_dct_32x8_10bpc).dconly
+.fast:
+    lea                  r4, [rsp+32*71]
+    pxor                 m0, m0
+.fast_loop:
+    REPX {mova [r6+32*x], m0}, -4, -3, -2, -1, 0, 1, 2, 3
+    add                  r6, 32*8
+    cmp                  r6, r4
+    jl .fast_loop
+.pass2:
+    lea                  r3, [rsp+32*3]
+    mov                  r4, r6
+    lea                  r5, [r6+32*8]
+    lea                  r6, [pw_5+128]
+    call .pass2_oddhalf
+    call .pass2_evenhalf
+    imul                 r2, strideq, 19
+    lea                  r3, [strideq*3]
+    add                  r2, dstq
+    call m(inv_txfm_add_dct_dct_16x32_10bpc).pass2_end
+    sub                dstq, r3
+    lea                  r2, [r2+r3+32]
+    add                dstq, 32
+    lea                  r3, [rsp+32*11]
+    call .pass2_oddhalf
+    call .pass2_evenhalf
+    lea                  r3, [strideq*3]
+    call m(inv_txfm_add_dct_dct_16x32_10bpc).pass2_end
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [cq+128* 1]
+    mova                 m1, [cq+128* 7]
+    mova                 m2, [cq+128* 9]
+    mova                 m3, [cq+128*15]
+    mova                 m4, [cq+128*17]
+    mova                 m5, [cq+128*23]
+    mova                 m6, [cq+128*25]
+    mova                 m7, [cq+128*31]
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m14, [pd_2896]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1
+    mova                 m0, [cq+128* 3]
+    mova                 m1, [cq+128* 5]
+    mova                 m2, [cq+128*11]
+    mova                 m3, [cq+128*13]
+    mova                 m4, [cq+128*19]
+    mova                 m5, [cq+128*21]
+    mova                 m6, [cq+128*27]
+    mova                 m7, [cq+128*29]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2
+    mova                 m0, [cq+128* 2]
+    mova                 m1, [cq+128* 6]
+    mova                 m2, [cq+128*10]
+    mova                 m3, [cq+128*14]
+    mova                 m4, [cq+128*18]
+    mova                 m5, [cq+128*22]
+    mova                 m6, [cq+128*26]
+    mova                 m7, [cq+128*30]
+    call m(idct_8x16_internal_10bpc).main_oddhalf
+    mova                 m0, [cq+128* 0]
+    mova                 m1, [cq+128* 4]
+    mova                 m2, [cq+128* 8]
+    mova                 m3, [cq+128*12]
+    mova                 m4, [cq+128*16]
+    mova                 m5, [cq+128*20]
+    mova                 m6, [cq+128*24]
+    mova                 m7, [cq+128*28]
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_end
+    pxor                m15, m15
+    mov                 r7d, 128*29
+.main_zero_loop:
+    mova      [cq+r7-128*1], m15
+    mova      [cq+r7+128*0], m15
+    mova      [cq+r7+128*1], m15
+    mova      [cq+r7+128*2], m15
+    sub                 r7d, 128*4
+    jg .main_zero_loop
+    add                  cq, 32
+    mova          [r4-32*4], m0
+    mova          [r4-32*3], m1
+    mova          [r4-32*2], m2
+    mova          [r4-32*1], m3
+    mova          [r4+32*0], m4
+    mova          [r4+32*1], m5
+    mova          [r4+32*2], m6
+    mova          [r4+32*3], m7
+    mova                 m0, [r5+32*3]
+    mova                 m1, [r5+32*2]
+    mova                 m2, [r5+32*1]
+    mova                 m3, [r5+32*0]
+    mova                 m4, [r5-32*1]
+    mova                 m5, [r5-32*2]
+    mova                 m6, [r5-32*3]
+    mova                 m7, [r5-32*4]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).transpose
+    mova          [r5-32*4], m0
+    mova          [r5-32*3], m1
+    mova          [r5-32*2], m2
+    mova          [r5-32*1], m3
+    mova          [r5+32*0], m4
+    mova          [r5+32*1], m5
+    mova          [r5+32*2], m6
+    mova          [r5+32*3], m7
+    ret
+ALIGN function_align
+.pass2_oddhalf:
+    mova                 m0, [r3+32* 1] ;  1
+    mova                 m1, [r3+32* 3] ;  3
+    mova                 m2, [r3+32* 5] ;  5
+    mova                 m3, [r3+32* 7] ;  7
+    mova                 m4, [r3+32*17] ;  9
+    mova                 m5, [r3+32*19] ; 11
+    mova                 m6, [r3+32*21] ; 13
+    mova                 m7, [r3+32*23] ; 15
+    mova                 m8, [r3+32*33] ; 17
+    mova                 m9, [r3+32*35] ; 19
+    mova                m10, [r3+32*37] ; 21
+    mova                m11, [r3+32*39] ; 23
+    mova                m12, [r3+32*49] ; 25
+    mova                m13, [r3+32*51] ; 27
+    mova                m14, [r3+32*53] ; 29
+    mova                m15, [r3+32*55] ; 31
+    jmp m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+ALIGN function_align
+.pass2_evenhalf:
+    mova                 m0, [r3+32* 0] ;  0
+    mova                 m1, [r3+32* 2] ;  2
+    mova                 m2, [r3+32* 4] ;  4
+    mova                 m3, [r3+32* 6] ;  6
+    mova                 m4, [r3+32*16] ;  8
+    mova                 m5, [r3+32*18] ; 10
+    mova                 m6, [r3+32*20] ; 12
+    mova                 m7, [r3+32*22] ; 14
+    mova                 m8, [r3+32*32] ; 16
+    mova                 m9, [r3+32*34] ; 18
+    mova                m10, [r3+32*36] ; 20
+    mova                m11, [r3+32*38] ; 22
+    mova                m12, [r3+32*48] ; 24
+    mova                m13, [r3+32*50] ; 26
+    mova                m14, [r3+32*52] ; 28
+    mova                m15, [r3+32*54] ; 30
+    mova      [rsp+gprsize], m15
+    jmp m(idct_16x16_internal_8bpc).main
+
+cglobal inv_txfm_add_identity_identity_32x32_10bpc, 4, 8, 8, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd         m7, [pixel_10bpc_max]
+.pass1:
+    vpbroadcastd         m5, [pw_8192]
+    pxor                 m6, m6
+    lea                  r6, [strideq*3]
+    lea                  r5, [strideq*5]
+    lea                  r4, [strideq+r6*2] ; strideq*7
+    call .main                              ; 0
+    cmp                eobd, 36
+    jl .ret
+    add                  cq, 128*8          ; 0 1
+    mov                  r7, dstq           ; 1
+    add                dstq, 16
+    call .main
+    call .main2
+    cmp                eobd, 136
+    jl .ret
+    add                  cq, 128*16-32      ; 0 1 2
+    lea                dstq, [r7+16*2]      ; 1 2
+    call .main                              ; 2
+    call .main2
+    call .main2
+    cmp                eobd, 300
+    jl .ret
+    add                  cq, 128*24-64      ; 0 1 2 3
+    add                  r7, 16*3           ; 1 2 3
+    mov                dstq, r7             ; 2 3
+    call .main                              ; 3
+    call .main2
+    call .main2
+    call .main2
+    cmp                eobd, 535
+    jl .ret
+    add                  cq, 128*24-64      ; 0 1 2 3
+    lea                dstq, [r7+strideq*8] ; 1 2 3 4
+    mov                  r7, dstq           ; 2 3 4
+    call .main                              ; 3 4
+    call .main2
+    call .main2
+    cmp                eobd, 755
+    jl .ret
+    add                  cq, 128*16-32      ; 0 1 2 3
+    lea                dstq, [r7+strideq*8] ; 1 2 3 4
+    call .main                              ; 2 3 4 5
+    call .main2                             ; 3 4 5
+    cmp                eobd, 911
+    jl .ret
+    add                  cq, 128*8          ; 0 1 2 3
+    add                dstq, 16             ; 1 2 3 4
+    call .main                              ; 2 3 4 5
+.ret:                                       ; 3 4 5 6
+    RET
+ALIGN function_align
+.main2:
+    sub                  cq, 128*8-32
+    lea                dstq, [dstq+strideq*8-16]
+.main:
+    mova                 m0, [cq+128*0]
+    packssdw             m0, [cq+128*1]
+    mova                 m1, [cq+128*2]
+    packssdw             m1, [cq+128*3]
+    mova                 m2, [cq+128*4]
+    packssdw             m2, [cq+128*5]
+    mova                 m3, [cq+128*6]
+    packssdw             m3, [cq+128*7]
+    REPX   {pmulhrsw x, m5}, m0, m1, m2, m3
+    jmp m(inv_txfm_add_identity_identity_8x32_10bpc).main_zero
+
+cglobal inv_txfm_add_identity_identity_32x32_12bpc, 4, 8, 8, dst, stride, c, eob
+    vpbroadcastd         m7, [pixel_12bpc_max]
+    jmp m(inv_txfm_add_identity_identity_32x32_10bpc).pass1
+
+%macro IDCT64_PART2_END 6-10 ; out, src[1-2], tmp[1-3], (offset[1-4])
+%if %1 & 1
+    mova                m%5, [r5-32*(51-%1)] ; idct16 out 0+n
+    mova                m%4, [r4-32*(14+%1)] ; idct32 out31-n
+%else
+    mova                m%5, [r4-32*(45-%1)]
+    mova                m%4, [r5-32*(20+%1)]
+%endif
+    paddsw              m%6, m%5, m%4 ; idct32 out 0+n
+    psubsw              m%5, m%4      ; idct32 out31-n
+    paddsw              m%4, m%5, m%3 ; out31-n
+    psubsw              m%5, m%3      ; out32+n
+    paddsw              m%3, m%6, m%2 ; out 0+n
+    psubsw              m%6, m%2      ; out63-n
+    REPX  {pmulhrsw x, m14}, m%5, m%6, m%4, m%3
+%if %1 & 1
+    %define %%d0 r2
+    %define %%d1 dstq
+%else
+    %define %%d0 dstq
+    %define %%d1 r2
+%endif
+    paddw               m%3, [%%d0+%7 ]
+    paddw               m%4, [%%d1+%8 ]
+    paddw               m%5, [%%d0+%9 ]
+    paddw               m%6, [%%d1+%10]
+    pxor                m%2, m%2
+    REPX    {pmaxsw x, m%2}, m%3, m%4, m%5, m%6
+    vpbroadcastd        m%2, [pixel_10bpc_max]
+    REPX    {pminsw x, m%2}, m%3, m%4, m%5, m%6
+    mova         [%%d0+%7 ], m%3
+    mova         [%%d1+%8 ], m%4
+    mova         [%%d0+%9 ], m%5
+    mova         [%%d1+%10], m%6
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_16x64_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 10, 16, 32*98, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    vpbroadcastd        m14, [pd_2896]
+    lea                  r6, [rsp+32*6]
+    call .main
+    sub                eobd, 44
+    jl .fast
+    call .main
+    sub                eobd, 107
+    jl .fast
+    call .main
+    sub                eobd, 128
+    jl .fast
+    call .main
+    jmp .pass2
+.dconly:
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_10bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 64
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_16x4_10bpc).dconly3
+.fast:
+    lea                  r4, [rsp+32*38]
+    pxor                 m0, m0
+.fast_loop:
+    REPX {mova [r6+32*x], m0}, -4, -3, -2, -1, 0, 1, 2, 3
+    add                  r6, 32*8
+    cmp                  r6, r4
+    jl .fast_loop
+.pass2:
+    lea                  r6, [pw_5+128]
+    mova                 m0, [rsp+32* 2] ; in0
+    mova                 m1, [rsp+32* 6] ; in4
+    mova                 m2, [rsp+32*10] ; in8
+    mova                 m3, [rsp+32*14] ; in12
+    mova                 m4, [rsp+32*18] ; in16
+    mova                 m5, [rsp+32*22] ; in20
+    mova                 m6, [rsp+32*26] ; in24
+    mova                 m7, [rsp+32*30] ; in28
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    lea                  r4, [rsp+32*38]
+    mova          [r4-32*4], m0
+    mova          [r4-32*3], m1
+    mova          [r4-32*2], m2
+    mova          [r4-32*1], m3
+    mova          [r4+32*0], m4
+    mova          [r4+32*1], m5
+    mova          [r4+32*2], m6
+    mova          [r4+32*3], m7
+    add                  r4, 32*8
+    mova          [r4-32*4], m8
+    mova          [r4-32*3], m9
+    mova          [r4-32*2], m10
+    mova          [r4-32*1], m11
+    mova          [r4+32*0], m12
+    mova          [r4+32*1], m13
+    mova          [r4+32*2], m14
+    mova          [r4+32*3], m15
+    mova                 m0, [rsp+32* 4] ; in2
+    mova                 m1, [rsp+32* 8] ; in6
+    mova                 m2, [rsp+32*12] ; in10
+    mova                 m3, [rsp+32*16] ; in14
+    mova                 m4, [rsp+32*20] ; in18
+    mova                 m5, [rsp+32*24] ; in22
+    mova                 m6, [rsp+32*28] ; in26
+    mova                 m7, [rsp+32*32] ; in30
+    lea                  r5, [r4+32*16]
+    add                  r4, 32*8
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    mova                 m0, [rsp+32* 3] ; in1
+    mova                 m1, [rsp+32*33] ; in31
+    mova                 m2, [rsp+32*19] ; in17
+    mova                 m3, [rsp+32*17] ; in15
+    mova                 m4, [rsp+32*11] ; in9
+    mova                 m5, [rsp+32*25] ; in23
+    mova                 m6, [rsp+32*27] ; in25
+    mova                 m7, [rsp+32* 9] ; in7
+    lea                  r6, [idct64_mul - 8]
+    add                  r4, 32*16
+    add                  r5, 32*32
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    mova                 m0, [rsp+32* 7] ; in5
+    mova                 m1, [rsp+32*29] ; in27
+    mova                 m2, [rsp+32*23] ; in21
+    mova                 m3, [rsp+32*13] ; in11
+    mova                 m4, [rsp+32*15] ; in13
+    mova                 m5, [rsp+32*21] ; in19
+    mova                 m6, [rsp+32*31] ; in29
+    mova                 m7, [rsp+32* 5] ; in3
+    add                  r6, 8
+    add                  r4, 32*8
+    sub                  r5, 32*8
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    lea                  r8, [strideq*4]
+    lea                  r9, [strideq*5]
+    lea                  r3, [r9+strideq*1] ; stride*6
+    lea                  r7, [r9+strideq*2] ; stride*7
+    call .main_part2_pass2
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [cq+128* 1]
+    mova                 m1, [cq+128* 3]
+    mova                 m2, [cq+128* 5]
+    mova                 m3, [cq+128* 7]
+    mova                 m4, [cq+128* 9]
+    mova                 m5, [cq+128*11]
+    mova                 m6, [cq+128*13]
+    mova                 m7, [cq+128*15]
+    call m(idct_8x16_internal_10bpc).main_oddhalf
+    mova                 m0, [cq+128* 0]
+    mova                 m1, [cq+128* 2]
+    mova                 m2, [cq+128* 4]
+    mova                 m3, [cq+128* 6]
+    mova                 m4, [cq+128* 8]
+    mova                 m5, [cq+128*10]
+    mova                 m6, [cq+128*12]
+    mova                 m7, [cq+128*14]
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    pxor                m15, m15
+    mov                 r7d, 128*13
+.main_zero_loop:
+    mova      [cq+r7-128*1], m15
+    mova      [cq+r7+128*0], m15
+    mova      [cq+r7+128*1], m15
+    mova      [cq+r7+128*2], m15
+    sub                 r7d, 128*4
+    jg .main_zero_loop
+    add                  cq, 32
+    psrld               m15, m11, 10 ; pd_2
+    mova                 m8, [r6-32*4]
+    mova                 m9, [r6+32*3]
+    REPX     {paddd x, m15}, m0, m1, m2, m3, m4, m5, m6, m7
+    psubd               m10, m0, m8 ; out15
+    paddd                m0, m8     ; out0
+    mova                 m8, [r6-32*3]
+    psubd               m15, m7, m9 ; out8
+    paddd                m7, m9     ; out7
+    mova                 m9, [r6+32*2]
+    REPX       {psrad x, 2}, m0, m15, m10, m7
+    packssdw             m0, m15
+    packssdw             m7, m10
+    psubd               m10, m1, m8 ; out14
+    paddd                m1, m8     ; out1
+    mova                 m8, [r6-32*2]
+    psubd               m15, m6, m9 ; out9
+    paddd                m6, m9     ; out6
+    mova                 m9, [r6+32*1]
+    REPX       {psrad x, 2}, m1, m15, m10, m6
+    packssdw             m1, m15
+    packssdw             m6, m10
+    psubd               m10, m2, m8 ; out13
+    paddd                m2, m8     ; out2
+    mova                 m8, [r6-32*1]
+    psubd               m15, m5, m9 ; out10
+    paddd                m5, m9     ; out5
+    mova                 m9, [r6+32*0]
+    REPX       {psrad x, 2}, m2, m15, m10, m5
+    packssdw             m2, m15
+    packssdw             m5, m10
+    psubd               m10, m3, m8 ; out12
+    paddd                m3, m8     ; out3
+    psubd               m15, m4, m9 ; out11
+    paddd                m4, m9     ; out4
+    REPX       {psrad x, 2}, m3, m15, m10, m4
+    packssdw             m3, m15
+    packssdw             m4, m10
+    call m(idct_16x8_internal_10bpc).transpose3
+    mova          [r6-32*4], m0
+    mova          [r6-32*3], m1
+    mova          [r6-32*2], m2
+    mova          [r6-32*1], m3
+    mova          [r6+32*0], m4
+    mova          [r6+32*1], m5
+    mova          [r6+32*2], m6
+    mova          [r6+32*3], m7
+    add                  r6, 32*8
+    ret
+.main_part2_pass2:
+    vpbroadcastd        m11, [pw_1567_3784]
+    vpbroadcastd        m12, [pw_m3784_1567]
+    vpbroadcastd        m13, [pw_2896_2896]
+    lea                  r6, [pw_5+128]
+    lea                  r2, [dstq+r7]
+.main_part2_pass2_loop:
+    vpbroadcastd        m14, [pw_m2896_2896]
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part2_internal
+    vpbroadcastd        m14, [pw_2048]
+    IDCT64_PART2_END      0,  7,  0,  6,  9, 10, strideq*0, r3*4, r8*8, r7*8
+    IDCT64_PART2_END      7,  8,  5,  0,  6,  7, strideq*0, r3*4, r8*8, r7*8
+    IDCT64_PART2_END      8,  2,  1,  0,  6,  7, strideq*8, r8*4, r9*8, r3*8
+    IDCT64_PART2_END     15,  3,  4,  0,  6,  7, strideq*8, r8*4, r9*8, r3*8
+    add                dstq, strideq
+    sub                  r2, strideq
+    cmp                  r4, r5
+    jne .main_part2_pass2_loop
+    ret
+ALIGN function_align
+.main_part1_rect2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+.main_part1: ; idct64 steps 1-5
+    ; in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+    ; in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+    ; in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+    ; in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+    vpbroadcastd         m7, [r5+4*0]
+    vpbroadcastd         m8, [r5+4*1]
+    vpbroadcastd         m6, [r5+4*2]
+    vpbroadcastd         m9, [r5+4*3]
+    vpbroadcastd         m5, [r5+4*4]
+    vpbroadcastd        m10, [r5+4*5]
+    vpbroadcastd         m4, [r5+4*6]
+    vpbroadcastd        m15, [r5+4*7]
+    pmulld               m7, m0     ; t63a
+    pmulld               m0, m8     ; t32a
+    pmulld               m6, m1     ; t62a
+    pmulld               m1, m9     ; t33a
+    pmulld               m5, m2     ; t61a
+    pmulld               m2, m10    ; t34a
+    pmulld               m4, m3     ; t60a
+    pmulld               m3, m15    ; t35a
+    vpbroadcastd        m10, [r5+4*8]
+    vpbroadcastd        m15, [r5+4*9]
+    REPX     {paddd x, m11}, m7, m0, m6, m1, m5, m2, m4, m3
+    REPX     {psrad x, 12 }, m0, m1, m7, m6, m2, m3, m5, m4
+    psubd                m8, m0, m1 ; t33
+    paddd                m0, m1     ; t32
+    psubd                m1, m7, m6 ; t62
+    paddd                m7, m6     ; t63
+    psubd                m6, m3, m2 ; t34
+    paddd                m3, m2     ; t35
+    psubd                m2, m4, m5 ; t61
+    paddd                m4, m5     ; t60
+    REPX    {pmaxsd x, m12}, m8, m1, m6, m2
+    REPX    {pminsd x, m13}, m8, m1, m6, m2
+    ITX_MULSUB_2D         1, 8, 5, 9, _, 11, 10, 15    ; t33a, t62a
+    ITX_MULSUB_2D         2, 6, 5, 9, _, 11, 10, 15, 2 ; t61a, t34a
+    REPX    {pmaxsd x, m12}, m0, m3, m7, m4
+    REPX    {pminsd x, m13}, m0, m3, m7, m4
+    vpbroadcastd        m10, [r5+4*10]
+    vpbroadcastd        m15, [r5+4*11]
+    psubd                m5, m0, m3 ; t35a
+    paddd                m0, m3     ; t32a
+    psubd                m3, m7, m4 ; t60a
+    paddd                m7, m4     ; t63a
+    psubd                m4, m1, m6 ; t34
+    paddd                m1, m6     ; t33
+    psubd                m6, m8, m2 ; t61
+    paddd                m8, m2     ; t62
+    REPX    {pmaxsd x, m12}, m5, m3, m4, m6
+    REPX    {pminsd x, m13}, m5, m3, m4, m6
+    ITX_MULSUB_2D         3, 5, 2, 9, _, 11, 10, 15 ; t35,  t60
+    ITX_MULSUB_2D         6, 4, 2, 9, _, 11, 10, 15 ; t34a, t61a
+    REPX    {pmaxsd x, m12}, m0, m7, m1, m8
+    REPX    {pminsd x, m13}, m0, m7, m1, m8
+    add                  r5, 4*12
+    mova          [r6-32*4], m0
+    mova          [r6+32*3], m7
+    mova          [r6-32*3], m1
+    mova          [r6+32*2], m8
+    mova          [r6-32*2], m6
+    mova          [r6+32*1], m4
+    mova          [r6-32*1], m3
+    mova          [r6+32*0], m5
+    add                  r6, 32*8
+    ret
+.main_part2: ; idct64 steps 6-9
+    lea                  r5, [r6+32*3]
+    sub                  r6, 32*4
+    vpbroadcastd        m10, [pd_1567]
+    vpbroadcastd        m15, [pd_3784]
+.main_part2_loop:
+    mova                 m0, [r6-32*32] ; t32a
+    mova                 m1, [r5-32*24] ; t39a
+    mova                 m2, [r5-32*32] ; t63a
+    mova                 m3, [r6-32*24] ; t56a
+    mova                 m4, [r6-32*16] ; t40a
+    mova                 m5, [r5-32* 8] ; t47a
+    mova                 m6, [r5-32*16] ; t55a
+    mova                 m7, [r6-32* 8] ; t48a
+    psubd                m8, m0, m1 ; t39
+    paddd                m0, m1     ; t32
+    psubd                m1, m2, m3 ; t56
+    paddd                m2, m3     ; t63
+    psubd                m3, m5, m4 ; t40
+    paddd                m5, m4     ; t47
+    psubd                m4, m7, m6 ; t55
+    paddd                m7, m6     ; t48
+    REPX    {pmaxsd x, m12}, m8, m1, m3, m4
+    REPX    {pminsd x, m13}, m8, m1, m3, m4
+    ITX_MULSUB_2D         1, 8, 6, 9, _, 11, 10, 15    ; t39a, t56a
+    ITX_MULSUB_2D         4, 3, 6, 9, _, 11, 10, 15, 2 ; t55a, t40a
+    REPX    {pmaxsd x, m12}, m0, m2, m5, m7
+    REPX    {pminsd x, m13}, m0, m5, m2, m7
+    psubd                m6, m2, m7 ; t48a
+    paddd                m2, m7     ; t63a
+    psubd                m7, m0, m5 ; t47a
+    paddd                m0, m5     ; t32a
+    psubd                m5, m8, m4 ; t55
+    paddd                m8, m4     ; t56
+    psubd                m4, m1, m3 ; t40
+    paddd                m1, m3     ; t39
+    REPX    {pmaxsd x, m12}, m6, m7, m5, m4
+    REPX    {pminsd x, m13}, m6, m7, m5, m4
+    REPX    {pmulld x, m14}, m6, m7, m5, m4
+    REPX    {pmaxsd x, m12}, m2, m0, m8, m1
+    REPX    {pminsd x, m13}, m2, m0, m8, m1
+    paddd                m6, m11
+    paddd                m5, m11
+    psubd                m3, m6, m7 ; t47
+    paddd                m6, m7     ; t48
+    psubd                m7, m5, m4 ; t40a
+    paddd                m5, m4     ; t55a
+    REPX      {psrad x, 12}, m3, m6, m7, m5
+    mova         [r5-32* 8], m2
+    mova         [r6-32*32], m0
+    mova         [r6-32* 8], m8
+    mova         [r5-32*32], m1
+    mova         [r5-32*24], m3
+    mova         [r6-32*16], m6
+    mova         [r6-32*24], m7
+    mova         [r5-32*16], m5
+    add                  r6, 32
+    sub                  r5, 32
+    cmp                  r6, r5
+    jl .main_part2_loop
+    ret
+
+cglobal inv_txfm_add_dct_dct_32x64_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 11, 16, 32*134, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    lea                  r6, [rsp+32*6]
+    call .main
+    cmp                eobd, 36
+    jl .fast
+    call .main
+    cmp                eobd, 136
+    jl .fast
+    call .main
+    cmp                eobd, 300
+    jl .fast
+    call .main
+    jmp .pass2
+.dconly:
+    imul                r6d, [cq], 181
+    vpbroadcastd         m3, [dconly_10bpc]
+    mov                [cq], eobd ; 0
+    or                  r3d, 64
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 384
+    sar                 r6d, 9
+    jmp m(inv_txfm_add_dct_dct_32x8_10bpc).dconly2
+.fast:
+    lea                  r4, [rsp+32*70]
+    pxor                 m0, m0
+.fast_loop:
+    REPX {mova [r6+32*x], m0}, -4, -3, -2, -1, 0, 1, 2, 3
+    add                  r6, 32*8
+    cmp                  r6, r4
+    jl .fast_loop
+.pass2:
+    lea                  r6, [pw_5 + 128]
+    mov                 r10, rsp
+    lea                  r8, [strideq*4]
+    lea                  r9, [strideq*5]
+    lea                  r3, [r9+strideq*1] ; stride*6
+    lea                  r7, [r9+strideq*2] ; stride*7
+.pass2_loop:
+    mova                 m0, [r10+32* 2] ; in0
+    mova                 m1, [r10+32* 6] ; in4
+    mova                 m2, [r10+32*18] ; in8
+    mova                 m3, [r10+32*22] ; in12
+    mova                 m4, [r10+32*34] ; in16
+    mova                 m5, [r10+32*38] ; in20
+    mova                 m6, [r10+32*50] ; in24
+    mova                 m7, [r10+32*54] ; in28
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    lea                  r4, [rsp+32*70]
+    mova          [r4-32*4], m0
+    mova          [r4-32*3], m1
+    mova          [r4-32*2], m2
+    mova          [r4-32*1], m3
+    mova          [r4+32*0], m4
+    mova          [r4+32*1], m5
+    mova          [r4+32*2], m6
+    mova          [r4+32*3], m7
+    add                  r4, 32*8
+    mova          [r4-32*4], m8
+    mova          [r4-32*3], m9
+    mova          [r4-32*2], m10
+    mova          [r4-32*1], m11
+    mova          [r4+32*0], m12
+    mova          [r4+32*1], m13
+    mova          [r4+32*2], m14
+    mova          [r4+32*3], m15
+    mova                 m0, [r10+32* 4] ; in2
+    mova                 m1, [r10+32* 8] ; in6
+    mova                 m2, [r10+32*20] ; in10
+    mova                 m3, [r10+32*24] ; in14
+    mova                 m4, [r10+32*36] ; in18
+    mova                 m5, [r10+32*40] ; in22
+    mova                 m6, [r10+32*52] ; in26
+    mova                 m7, [r10+32*56] ; in30
+    lea                  r5, [r4+32*16]
+    add                  r4, 32*8
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    mova                 m0, [r10+32* 3] ; in1
+    mova                 m1, [r10+32*57] ; in31
+    mova                 m2, [r10+32*35] ; in17
+    mova                 m3, [r10+32*25] ; in15
+    mova                 m4, [r10+32*19] ; in9
+    mova                 m5, [r10+32*41] ; in23
+    mova                 m6, [r10+32*51] ; in25
+    mova                 m7, [r10+32* 9] ; in7
+    lea                  r6, [idct64_mul - 8]
+    add                  r4, 32*16
+    add                  r5, 32*32
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    mova                 m0, [r10+32* 7] ; in5
+    mova                 m1, [r10+32*53] ; in27
+    mova                 m2, [r10+32*39] ; in21
+    mova                 m3, [r10+32*21] ; in11
+    mova                 m4, [r10+32*23] ; in13
+    mova                 m5, [r10+32*37] ; in19
+    mova                 m6, [r10+32*55] ; in29
+    mova                 m7, [r10+32* 5] ; in3
+    add                  r6, 8
+    add                  r4, 32*8
+    sub                  r5, 32*8
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part2_pass2
+    add                 r10, 32*8
+    sub                  r4, 32*98 ; rsp+32*16
+    sub                dstq, r8
+    add                dstq, 32
+    cmp                 r10, r4
+    jl .pass2_loop
+    RET
+ALIGN function_align
+.main:
+    vpbroadcastd        m14, [pd_2896]
+    vpbroadcastd        m11, [pd_2048]
+    pmulld               m0, m14, [cq+128* 1]
+    pmulld               m1, m14, [cq+128* 7]
+    pmulld               m2, m14, [cq+128* 9]
+    pmulld               m3, m14, [cq+128*15]
+    pmulld               m4, m14, [cq+128*17]
+    pmulld               m5, m14, [cq+128*23]
+    pmulld               m6, m14, [cq+128*25]
+    pmulld               m7, m14, [cq+128*31]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1_rect2
+    pmulld               m0, m14, [cq+128* 3]
+    pmulld               m1, m14, [cq+128* 5]
+    pmulld               m2, m14, [cq+128*11]
+    pmulld               m3, m14, [cq+128*13]
+    pmulld               m4, m14, [cq+128*19]
+    pmulld               m5, m14, [cq+128*21]
+    pmulld               m6, m14, [cq+128*27]
+    pmulld               m7, m14, [cq+128*29]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2_rect2
+    pmulld               m0, m14, [cq+128* 2]
+    pmulld               m1, m14, [cq+128* 6]
+    pmulld               m2, m14, [cq+128*10]
+    pmulld               m3, m14, [cq+128*14]
+    pmulld               m4, m14, [cq+128*18]
+    pmulld               m5, m14, [cq+128*22]
+    pmulld               m6, m14, [cq+128*26]
+    pmulld               m7, m14, [cq+128*30]
+    call m(idct_8x16_internal_10bpc).main_oddhalf_rect2
+    pmulld               m0, m14, [cq+128* 0]
+    pmulld               m1, m14, [cq+128* 4]
+    pmulld               m2, m14, [cq+128* 8]
+    pmulld               m3, m14, [cq+128*12]
+    pmulld               m4, m14, [cq+128*16]
+    pmulld               m5, m14, [cq+128*20]
+    pmulld               m6, m14, [cq+128*24]
+    pmulld               m7, m14, [cq+128*28]
+    pxor                m15, m15
+    mov                 r7d, 128*29
+.main_zero_loop:
+    mova      [cq+r7-128*1], m15
+    mova      [cq+r7+128*0], m15
+    mova      [cq+r7+128*1], m15
+    mova      [cq+r7+128*2], m15
+    sub                 r7d, 128*4
+    jg .main_zero_loop
+    add                  cq, 32
+    call m(idct_8x8_internal_10bpc).main_rect2
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_end
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).transpose
+    mova          [r4-32*4], m0
+    mova          [r4-32*3], m1
+    mova          [r4-32*2], m2
+    mova          [r4-32*1], m3
+    mova          [r4+32*0], m4
+    mova          [r4+32*1], m5
+    mova          [r4+32*2], m6
+    mova          [r4+32*3], m7
+    mova                 m0, [r5+32*3]
+    mova                 m1, [r5+32*2]
+    mova                 m2, [r5+32*1]
+    mova                 m3, [r5+32*0]
+    mova                 m4, [r5-32*1]
+    mova                 m5, [r5-32*2]
+    mova                 m6, [r5-32*3]
+    mova                 m7, [r5-32*4]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).transpose
+    mova          [r5-32*4], m0
+    mova          [r5-32*3], m1
+    mova          [r5-32*2], m2
+    mova          [r5-32*1], m3
+    mova          [r5+32*0], m4
+    mova          [r5+32*1], m5
+    mova          [r5+32*2], m6
+    mova          [r5+32*3], m7
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x16_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jnz .normal
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 16
+.dconly:
+    add                 r6d, 640
+    sar                 r6d, 10
+.dconly2:
+    vpbroadcastd         m5, [dconly_10bpc]
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    movd                xm0, r6d
+    paddsw              xm0, xm5
+    vpbroadcastw         m0, xm0
+.dconly_loop:
+    paddsw               m1, m0, [dstq+32*0]
+    paddsw               m2, m0, [dstq+32*1]
+    paddsw               m3, m0, [dstq+32*2]
+    paddsw               m4, m0, [dstq+32*3]
+    REPX    {psubusw x, m5}, m1, m2, m3, m4
+    mova        [dstq+32*0], m1
+    mova        [dstq+32*1], m2
+    mova        [dstq+32*2], m3
+    mova        [dstq+32*3], m4
+    add                dstq, strideq
+    dec                 r3d
+    jg .dconly_loop
+    RET
+.normal:
+    PROLOGUE              0, 8, 16, 32*96, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    vpbroadcastd        m14, [pd_2896]
+    lea                  r6, [rsp+32*4]
+    call .main
+    call .shift_transpose
+    cmp                eobd, 36
+    jl .fast
+    call .main
+    call .shift_transpose
+    jmp .pass2
+.fast:
+    pxor                 m0, m0
+    mov                 r3d, 4
+.fast_loop:
+    REPX {mova [r6+32*x], m0}, -4, -3, -2, -1, 0, 1, 2, 3
+    add                  r6, 32*8
+    dec                 r3d
+    jg .fast_loop
+.pass2:
+    lea                  r7, [r6-32*64]
+    lea                  r4, [r6-32*32]
+    lea                  r6, [pw_5+128]
+    mov                  r5, dstq
+.pass2_loop:
+    mova                 m0, [r7-32*4]
+    mova                 m1, [r7-32*3]
+    mova                 m2, [r7-32*2]
+    mova                 m3, [r7-32*1]
+    mova                 m4, [r7+32*0]
+    mova                 m5, [r7+32*1]
+    mova                 m6, [r7+32*2]
+    mova                 m7, [r7+32*3]
+    add                  r7, 32*32
+    mova                 m8, [r7-32*4]
+    mova                 m9, [r7-32*3]
+    mova                m10, [r7-32*2]
+    mova                m11, [r7-32*1]
+    mova                m12, [r7+32*0]
+    mova                m13, [r7+32*1]
+    mova                m14, [r7+32*2]
+    mova                m15, [r7+32*3]
+    sub                  r7, 32*24
+    mova              [rsp], m15
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).write_16x16
+    add                  r5, 32
+    mov                dstq, r5
+    cmp                  r7, r4
+    jl .pass2_loop
+    RET
+ALIGN function_align
+.main:
+    lea                  r5, [idct64_mul_16bpc]
+    mova                 m0, [cq+64* 1]
+    mova                 m1, [cq+64*31]
+    mova                 m2, [cq+64*17]
+    mova                 m3, [cq+64*15]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1
+    mova                 m0, [cq+64* 7]
+    mova                 m1, [cq+64*25]
+    mova                 m2, [cq+64*23]
+    mova                 m3, [cq+64* 9]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1
+    mova                 m0, [cq+64* 5]
+    mova                 m1, [cq+64*27]
+    mova                 m2, [cq+64*21]
+    mova                 m3, [cq+64*11]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1
+    mova                 m0, [cq+64* 3]
+    mova                 m1, [cq+64*29]
+    mova                 m2, [cq+64*19]
+    mova                 m3, [cq+64*13]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part2
+    mova                 m0, [cq+64* 2]
+    mova                 m1, [cq+64*14]
+    mova                 m2, [cq+64*18]
+    mova                 m3, [cq+64*30]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1_fast
+    mova                 m0, [cq+64* 6]
+    mova                 m1, [cq+64*10]
+    mova                 m2, [cq+64*22]
+    mova                 m3, [cq+64*26]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2_fast
+    mova                 m0, [cq+64* 4]
+    mova                 m1, [cq+64*12]
+    mova                 m2, [cq+64*20]
+    mova                 m3, [cq+64*28]
+    call m(idct_8x16_internal_10bpc).main_oddhalf_fast
+    mova                 m0, [cq+64* 0]
+    mova                 m1, [cq+64* 8]
+    mova                 m2, [cq+64*16]
+    mova                 m3, [cq+64*24]
+    pxor                m15, m15
+    mov                 r7d, 64*30
+.main_zero_loop:
+    mova       [cq+r7-64*2], m15
+    mova       [cq+r7-64*1], m15
+    mova       [cq+r7+64*0], m15
+    mova       [cq+r7+64*1], m15
+    sub                 r7d, 64*4
+    jg .main_zero_loop
+.main_end:
+    psrld               m15, m11, 10 ; pd_2
+.main_end2:
+    add                  cq, 32
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    call m(idct_8x8_internal_10bpc).main
+    add                  r6, 32*8
+    call m(idct_8x16_internal_10bpc).main_evenhalf
+    mova          [r6+32*2], m1
+    mova          [r6+32*1], m2
+    mova          [r6+32*0], m3
+    mova          [r6-32*1], m4
+    mova          [r6-32*2], m5
+    mova          [r6-32*3], m6
+    mova          [r6-32*4], m7
+    jmp .main_end_loop_start
+.main_end_loop:
+    mova                 m0, [r6+32* 3] ; idct8  0  + n
+.main_end_loop_start:
+    mova                 m1, [r5+32* 4] ; idct16 15 - n
+    mova                 m2, [r5-32*12] ; idct32 16 + n
+    mova                 m3, [r6-32*13] ; idct32 31 - n
+    mova                 m4, [r6-32*29] ; idct64 63 - n
+    mova                 m5, [r5-32*28] ; idct64 48 + n
+    mova                 m6, [r6-32*45] ; idct64 47 - n
+    mova                 m7, [r5-32*44] ; idct64 32 + n
+    paddd                m8, m0, m1     ; idct16 out0  + n
+    psubd                m0, m1         ; idct16 out15 - n
+    REPX    {pmaxsd x, m12}, m8, m0
+    REPX    {pminsd x, m13}, m8, m0
+    paddd                m1, m8, m3     ; idct32 out0  + n
+    psubd                m8, m3         ; idct32 out31 - n
+    paddd                m3, m0, m2     ; idct32 out15 - n
+    psubd                m0, m2         ; idct32 out16 + n
+    REPX    {pmaxsd x, m12}, m1, m8, m3, m0
+    REPX    {pminsd x, m13}, m1, m3, m8, m0
+    REPX    {paddd  x, m15}, m1, m3, m0, m8
+    paddd                m2, m1, m4     ; idct64 out0  + n (unshifted)
+    psubd                m1, m4         ; idct64 out63 - n (unshifted)
+    paddd                m4, m3, m5     ; idct64 out15 - n (unshifted)
+    psubd                m3, m5         ; idct64 out48 + n (unshifted)
+    paddd                m5, m0, m6     ; idct64 out16 + n (unshifted)
+    psubd                m0, m6         ; idct64 out47 - n (unshifted)
+    paddd                m6, m8, m7     ; idct64 out31 - n (unshifted)
+    psubd                m8, m7         ; idct64 out32 + n (unshifted)
+    mova         [r5-32*44], m2
+    mova         [r6+32* 3], m1
+    mova         [r6-32*45], m4
+    mova         [r5+32* 4], m3
+    mova         [r5-32*28], m5
+    mova         [r6-32*13], m0
+    mova         [r6-32*29], m6
+    mova         [r5-32*12], m8
+    add                  r5, 32
+    sub                  r6, 32
+    cmp                  r5, r6
+    jl .main_end_loop
+    ret
+.shift_transpose:
+%macro IDCT64_SHIFT_TRANSPOSE 1 ; shift
+    sub                  r6, 32*48
+    mov                  r5, r6
+%%loop:
+    mova                 m0, [r6-32* 4]
+    mova                 m4, [r6+32* 4]
+    mova                 m1, [r6-32* 3]
+    mova                 m5, [r6+32* 5]
+    mova                 m2, [r6-32* 2]
+    mova                 m6, [r6+32* 6]
+    mova                 m3, [r6-32* 1]
+    mova                 m7, [r6+32* 7]
+    REPX      {psrad x, %1}, m0, m4, m1, m5, m2, m6, m3, m7
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    mova                 m4, [r6+32* 0]
+    mova                 m6, [r6+32* 8]
+    mova                 m5, [r6+32* 1]
+    mova                 m7, [r6+32* 9]
+    REPX      {psrad x, %1}, m4, m6, m5, m7
+    packssdw             m4, m6
+    packssdw             m5, m7
+    mova                 m6, [r6+32* 2]
+    mova                 m8, [r6+32*10]
+    mova                 m7, [r6+32* 3]
+    mova                 m9, [r6+32*11]
+    REPX      {psrad x, %1}, m6, m8, m7, m9
+    packssdw             m6, m8
+    packssdw             m7, m9
+    call m(idct_16x8_internal_10bpc).transpose3
+    mova          [r5-32*4], m0
+    mova          [r5-32*3], m1
+    mova          [r5-32*2], m2
+    mova          [r5-32*1], m3
+    mova          [r5+32*0], m4
+    mova          [r5+32*1], m5
+    mova          [r5+32*2], m6
+    mova          [r5+32*3], m7
+    add                  r6, 32*16
+    add                  r5, 32*8
+    cmp                  r5, r4
+    jl %%loop
+    mov                  r6, r4
+%endmacro
+    IDCT64_SHIFT_TRANSPOSE 2
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x32_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 8, 16, 32*163, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    vpbroadcastd        m14, [pd_2896]
+    lea                  r6, [rsp+32*7]
+    call .main
+    cmp                eobd, 36
+    jl .fast
+    call .main
+    cmp                eobd, 136
+    jl .fast
+    call .main
+    cmp                eobd, 300
+    jl .fast
+    call .main
+    jmp .pass2
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 32
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 384
+    sar                 r6d, 9
+    jmp m(inv_txfm_add_dct_dct_64x16_10bpc).dconly2
+.fast:
+    pxor                 m0, m0
+    lea                  r4, [rsp+32*135]
+.fast_loop:
+    REPX {mova [r6+32*x], m0}, -4, -3, -2, -1, 0, 1, 2, 3
+    add                  r6, 32*8
+    cmp                  r6, r4
+    jl .fast_loop
+.pass2:
+    lea                  r7, [r6-32*32]
+    lea                  r5, [r6+32*8]
+    lea                  r6, [pw_5+128]
+    imul                 r2, strideq, 19
+    lea                  r3, [strideq*3]
+    add                  r2, dstq
+.pass2_loop:
+    mova                 m0, [r7-32*99]
+    mova                 m1, [r7-32*97]
+    mova                 m2, [r7-32*95]
+    mova                 m3, [r7-32*93]
+    mova                 m4, [r7-32*67]
+    mova                 m5, [r7-32*65]
+    mova                 m6, [r7-32*63]
+    mova                 m7, [r7-32*61]
+    mova                 m8, [r7-32*35]
+    mova                 m9, [r7-32*33]
+    mova                m10, [r7-32*31]
+    mova                m11, [r7-32*29]
+    mova                m12, [r7-32* 3]
+    mova                m13, [r7-32* 1]
+    mova                m14, [r7+32* 1]
+    mova                m15, [r7+32* 3]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    mova                 m0, [r7-32*100]
+    mova                 m1, [r7-32*98]
+    mova                 m2, [r7-32*96]
+    mova                 m3, [r7-32*94]
+    mova                 m4, [r7-32*68]
+    mova                 m5, [r7-32*66]
+    mova                 m6, [r7-32*64]
+    mova                 m7, [r7-32*62]
+    mova                 m8, [r7-32*36]
+    mova                 m9, [r7-32*34]
+    mova                m10, [r7-32*32]
+    mova                m11, [r7-32*30]
+    mova                m12, [r7-32* 4]
+    mova                m13, [r7-32* 2]
+    mova                m14, [r7+32* 0]
+    mova                m15, [r7+32* 2]
+    add                  r7, 32*8
+    mova              [rsp], m15
+    call m(idct_16x16_internal_8bpc).main
+    call m(inv_txfm_add_dct_dct_16x32_10bpc).pass2_end
+    sub                dstq, r3
+    lea                  r2, [r2+r3+32]
+    add                dstq, 32
+    cmp                  r7, r4
+    jl .pass2_loop
+    RET
+ALIGN function_align
+.main:
+    lea                  r5, [idct64_mul_16bpc]
+    pmulld               m0, m14, [cq+128* 1]
+    pmulld               m1, m14, [cq+128*31]
+    pmulld               m2, m14, [cq+128*17]
+    pmulld               m3, m14, [cq+128*15]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1_rect2
+    pmulld               m0, m14, [cq+128* 7]
+    pmulld               m1, m14, [cq+128*25]
+    pmulld               m2, m14, [cq+128*23]
+    pmulld               m3, m14, [cq+128* 9]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1_rect2
+    pmulld               m0, m14, [cq+128* 5]
+    pmulld               m1, m14, [cq+128*27]
+    pmulld               m2, m14, [cq+128*21]
+    pmulld               m3, m14, [cq+128*11]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1_rect2
+    pmulld               m0, m14, [cq+128* 3]
+    pmulld               m1, m14, [cq+128*29]
+    pmulld               m2, m14, [cq+128*19]
+    pmulld               m3, m14, [cq+128*13]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1_rect2
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part2
+    pmulld               m0, m14, [cq+128* 2]
+    pmulld               m1, m14, [cq+128*14]
+    pmulld               m2, m14, [cq+128*18]
+    pmulld               m3, m14, [cq+128*30]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1_fast_rect2
+    pmulld               m0, m14, [cq+128* 6]
+    pmulld               m1, m14, [cq+128*10]
+    pmulld               m2, m14, [cq+128*22]
+    pmulld               m3, m14, [cq+128*26]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2_fast_rect2
+    pmulld               m0, m14, [cq+128* 4]
+    pmulld               m1, m14, [cq+128*12]
+    pmulld               m2, m14, [cq+128*20]
+    pmulld               m3, m14, [cq+128*28]
+    call m(idct_8x16_internal_10bpc).main_oddhalf_fast_rect2
+    pmulld               m0, m14, [cq+128* 0]
+    pmulld               m1, m14, [cq+128* 8]
+    pmulld               m2, m14, [cq+128*16]
+    pmulld               m3, m14, [cq+128*24]
+    pxor                m15, m15
+    mov                 r7d, 128*29
+.main_zero_loop:
+    mova      [cq+r7-128*1], m15
+    mova      [cq+r7+128*0], m15
+    mova      [cq+r7+128*1], m15
+    mova      [cq+r7+128*2], m15
+    sub                 r7d, 128*4
+    jg .main_zero_loop
+    psrld               m15, m11, 11 ; pd_1
+    REPX     {paddd x, m11}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_end2
+    IDCT64_SHIFT_TRANSPOSE 1
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x64_10bpc, 4, 7, 0, dst, stride, c, eob
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 11, 16, 32*195, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m11, [pd_2048]
+    vpbroadcastd        m12, [clip_18b_min]
+    vpbroadcastd        m13, [clip_18b_max]
+    vpbroadcastd        m14, [pd_2896]
+    lea                  r6, [rsp+32*7]
+    call .main
+    cmp                eobd, 36
+    jl .fast
+    call .main
+    cmp                eobd, 136
+    jl .fast
+    call .main
+    cmp                eobd, 300
+    jl .fast
+    call .main
+    jmp .pass2
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 64
+    jmp m(inv_txfm_add_dct_dct_64x16_10bpc).dconly
+.fast:
+    pxor                 m0, m0
+    lea                  r4, [rsp+32*135]
+.fast_loop:
+    REPX {mova [r6+32*x], m0}, -4, -3, -2, -1, 0, 1, 2, 3
+    add                  r6, 32*8
+    cmp                  r6, r4
+    jl .fast_loop
+.pass2:
+    lea                 r10, [r6-32*32]
+    lea                  r6, [pw_5+128]
+    lea                  r8, [strideq*4]
+    lea                  r9, [strideq*5]
+    lea                  r3, [r9+strideq*1] ; stride*6
+    lea                  r7, [r9+strideq*2] ; stride*7
+.pass2_loop:
+    mova                 m0, [r10-32*100] ; in0
+    mova                 m1, [r10-32*96]  ; in4
+    mova                 m2, [r10-32*68]  ; in8
+    mova                 m3, [r10-32*64]  ; in12
+    mova                 m4, [r10-32*36]  ; in16
+    mova                 m5, [r10-32*32]  ; in20
+    mova                 m6, [r10-32* 4]  ; in24
+    mova                 m7, [r10+32* 0]  ; in28
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    mova          [r4-32*4], m0
+    mova          [r4-32*3], m1
+    mova          [r4-32*2], m2
+    mova          [r4-32*1], m3
+    mova          [r4+32*0], m4
+    mova          [r4+32*1], m5
+    mova          [r4+32*2], m6
+    mova          [r4+32*3], m7
+    add                  r4, 32*8
+    mova          [r4-32*4], m8
+    mova          [r4-32*3], m9
+    mova          [r4-32*2], m10
+    mova          [r4-32*1], m11
+    mova          [r4+32*0], m12
+    mova          [r4+32*1], m13
+    mova          [r4+32*2], m14
+    mova          [r4+32*3], m15
+    mova                 m0, [r10-32*98] ; in2
+    mova                 m1, [r10-32*94] ; in6
+    mova                 m2, [r10-32*66] ; in10
+    mova                 m3, [r10-32*62] ; in14
+    mova                 m4, [r10-32*34] ; in18
+    mova                 m5, [r10-32*30] ; in22
+    mova                 m6, [r10-32* 2] ; in26
+    mova                 m7, [r10+32* 2] ; in30
+    lea                  r5, [r4+32*16]
+    add                  r4, 32*8
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    mova                 m0, [r10-32*99] ; in1
+    mova                 m1, [r10+32* 3] ; in31
+    mova                 m2, [r10-32*35] ; in17
+    mova                 m3, [r10-32*61] ; in15
+    mova                 m4, [r10-32*67] ; in9
+    mova                 m5, [r10-32*29] ; in23
+    mova                 m6, [r10-32* 3] ; in25
+    mova                 m7, [r10-32*93] ; in7
+    lea                  r6, [idct64_mul - 8]
+    add                  r4, 32*16
+    add                  r5, 32*32
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    mova                 m0, [r10-32*95] ; in5
+    mova                 m1, [r10-32* 1] ; in27
+    mova                 m2, [r10-32*31] ; in21
+    mova                 m3, [r10-32*65] ; in11
+    mova                 m4, [r10-32*63] ; in13
+    mova                 m5, [r10-32*33] ; in19
+    mova                 m6, [r10+32* 1] ; in29
+    mova                 m7, [r10-32*97] ; in3
+    add                  r6, 8
+    add                  r4, 32*8
+    sub                  r5, 32*8
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part2_pass2
+    add                 r10, 32*8
+    sub                dstq, r8
+    sub                  r4, 32*44
+    add                dstq, 32
+    cmp                 r10, r4
+    jl .pass2_loop
+    RET
+ALIGN function_align
+.main:
+    lea                  r5, [idct64_mul_16bpc]
+    mova                 m0, [cq+128* 1]
+    mova                 m1, [cq+128*31]
+    mova                 m2, [cq+128*17]
+    mova                 m3, [cq+128*15]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1
+    mova                 m0, [cq+128* 7]
+    mova                 m1, [cq+128*25]
+    mova                 m2, [cq+128*23]
+    mova                 m3, [cq+128* 9]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1
+    mova                 m0, [cq+128* 5]
+    mova                 m1, [cq+128*27]
+    mova                 m2, [cq+128*21]
+    mova                 m3, [cq+128*11]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1
+    mova                 m0, [cq+128* 3]
+    mova                 m1, [cq+128*29]
+    mova                 m2, [cq+128*19]
+    mova                 m3, [cq+128*13]
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_10bpc).main_part2
+    mova                 m0, [cq+128* 2]
+    mova                 m1, [cq+128*14]
+    mova                 m2, [cq+128*18]
+    mova                 m3, [cq+128*30]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part1_fast
+    mova                 m0, [cq+128* 6]
+    mova                 m1, [cq+128*10]
+    mova                 m2, [cq+128*22]
+    mova                 m3, [cq+128*26]
+    call m(inv_txfm_add_dct_dct_8x32_10bpc).main_oddhalf_part2_fast
+    mova                 m0, [cq+128* 4]
+    mova                 m1, [cq+128*12]
+    mova                 m2, [cq+128*20]
+    mova                 m3, [cq+128*28]
+    call m(idct_8x16_internal_10bpc).main_oddhalf_fast
+    mova                 m0, [cq+128* 0]
+    mova                 m1, [cq+128* 8]
+    mova                 m2, [cq+128*16]
+    mova                 m3, [cq+128*24]
+    pxor                m15, m15
+    mov                 r7d, 128*29
+.main_zero_loop:
+    mova      [cq+r7-128*1], m15
+    mova      [cq+r7+128*0], m15
+    mova      [cq+r7+128*1], m15
+    mova      [cq+r7+128*2], m15
+    sub                 r7d, 128*4
+    jg .main_zero_loop
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_end
+    jmp m(inv_txfm_add_dct_dct_64x16_10bpc).shift_transpose
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/itx16_avx512.asm b/media/libdav1d/src/src/x86/itx16_avx512.asm
new file mode 100644
index 0000000000..9f5f909a5f
--- /dev/null
+++ b/media/libdav1d/src/src/x86/itx16_avx512.asm
@@ -0,0 +1,6056 @@
+; Copyright © 2022-2023, VideoLAN and dav1d authors
+; Copyright © 2022-2023, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+idct8x8p:      db  0,  1,  4,  5,  2,  3,  6,  7, 16, 17, 20, 21, 18, 19, 22, 23
+               db  8,  9, 12, 13, 10, 11, 14, 15, 24, 25, 28, 29, 26, 27, 30, 31
+               db 32, 33, 36, 37, 34, 35, 38, 39, 48, 49, 52, 53, 50, 51, 54, 55
+               db 40, 41, 44, 45, 42, 43, 46, 47, 56, 57, 60, 61, 58, 59, 62, 63
+idtx8x8p:      db  0,  1, 32, 33,  2,  3, 34, 35,  4,  5, 36, 37,  6,  7, 38, 39
+               db  8,  9, 40, 41, 10, 11, 42, 43, 12, 13, 44, 45, 14, 15, 46, 47
+               db 16, 17, 48, 49, 18, 19, 50, 51, 20, 21, 52, 53, 22, 23, 54, 55
+               db 24, 25, 56, 57, 26, 27, 58, 59, 28, 29, 60, 61, 30, 31, 62, 63
+idct8x16p:     db 54, 55,  2,  3, 22, 23, 34, 35, 38, 39, 18, 19,  6,  7, 50, 51
+               db 62, 63, 10, 11, 30, 31, 42, 43, 46, 47, 26, 27, 14, 15, 58, 59
+               db 52, 53,  4,  5, 20, 21, 36, 37, 32, 33,  0,  1, 48, 49, 16, 17
+               db 60, 61, 12, 13, 28, 29, 44, 45, 40, 41,  8,  9, 56, 57, 24, 25
+iadst8x16p:    db  0,  1, 54, 55, 48, 49,  6,  7, 16, 17, 38, 39, 32, 33, 22, 23
+               db  8,  9, 62, 63, 56, 57, 14, 15, 24, 25, 46, 47, 40, 41, 30, 31
+               db  4,  5, 50, 51, 52, 53,  2,  3, 20, 21, 34, 35, 36, 37, 18, 19
+               db 12, 13, 58, 59, 60, 61, 10, 11, 28, 29, 42, 43, 44, 45, 26, 27
+permA:         db  0,  1,  0,  8,  4,  5,  1,  9,  8,  9,  4, 12, 12, 13,  5, 13
+               db 16, 17, 16, 24, 20, 21, 17, 25, 24, 25, 20, 28, 28, 29, 21, 29
+               db  2,  3,  2, 10,  6,  7,  3, 11, 10, 11,  6, 14, 14, 15,  7, 15
+               db 18, 19, 18, 26, 22, 23, 19, 27, 26, 27, 22, 30, 30, 31, 23, 31
+permB:         db  4,  2,  1,  8,  0,  0,  1,  0, 12,  3,  3, 10,  8,  1,  3,  2
+               db  5, 10,  5, 12,  1,  8,  5,  4, 13, 11,  7, 14,  9,  9,  7,  6
+               db  6,  6, 13,  4,  2,  4,  4,  5, 14,  7, 15,  6, 10,  5,  6,  7
+               db  7, 14,  9,  0,  3, 12,  0,  1, 15, 15, 11,  2, 11, 13,  2,  3
+permC:         db  0,  9,  0,  0,  0,  1,  4,  4,  2, 11,  2,  2,  2,  3,  6,  6
+               db  1,  8,  1,  8,  4,  5,  5, 12,  3, 10,  3, 10,  6,  7,  7, 14
+               db  9,  1,  8,  1,  1,  0, 12,  5, 11,  3, 10,  3,  3,  2, 14,  7
+               db  8,  0,  9,  9,  5,  4, 13, 13, 10,  2, 11, 11,  7,  6, 15, 15
+idct8x32p:     db  0,  1,  4,  5, 16, 17, 20, 21, 32, 33, 36, 37, 48, 49, 52, 53
+               db  8,  9, 12, 13, 24, 25, 28, 29, 40, 41, 44, 45, 56, 57, 60, 61
+               db  2,  3,  6,  7, 18, 19, 22, 23, 34, 35, 38, 39, 50, 51, 54, 55
+               db 10, 11, 14, 15, 26, 27, 30, 31, 42, 43, 46, 47, 58, 59, 62, 63
+idct32x8p:     db  2, 18,  0, 16,  3, 19,  1, 17, 10, 26,  8, 24, 11, 27,  9, 25
+               db 34, 50, 32, 48, 35, 51, 33, 49, 42, 58, 40, 56, 43, 59, 41, 57
+               db  6, 22,  4, 20,  7, 23,  5, 21, 14, 30, 12, 28, 15, 31, 13, 29
+               db 38, 54, 36, 52, 39, 55, 37, 53, 46, 62, 44, 60, 47, 63, 45, 61
+idtx32x8p:     db  0,  8, 16, 24,  4, 12, 20, 28,  2, 10, 18, 26,  6, 14, 22, 30
+               db 32, 40, 48, 56, 36, 44, 52, 60, 34, 42, 50, 58, 38, 46, 54, 62
+               db  1,  9, 17, 25,  5, 13, 21, 29,  3, 11, 19, 27,  7, 15, 23, 31
+               db 33, 41, 49, 57, 37, 45, 53, 61, 35, 43, 51, 59, 39, 47, 55, 63
+
+pw_2048_m2048: times 16 dw  2048
+pw_m2048_2048: times 16 dw -2048
+pw_2048:       times 16 dw  2048
+
+; flags: 0 = ++, 1 = +-, 2 = -+, 3 = ++-, 4=--
+%macro COEF_PAIR 2-3 0 ; a, b, flags
+%if %3 == 1
+pd_%1_m%2: dd %1, %1, -%2, -%2
+%define pd_%1  (pd_%1_m%2 + 4*0)
+%define pd_m%2 (pd_%1_m%2 + 4*2)
+%elif %3 == 2
+pd_m%1_%2: dd -%1, -%1, %2, %2
+%define pd_m%1 (pd_m%1_%2 + 4*0)
+%define pd_%2  (pd_m%1_%2 + 4*2)
+%elif %3 == 4
+pd_m%1_m%2: dd -%1, -%1, -%2, -%2
+%define pd_m%1 (pd_m%1_m%2 + 4*0)
+%define pd_m%2 (pd_m%1_m%2 + 4*2)
+%else
+pd_%1_%2: dd %1, %1, %2, %2
+%define pd_%1  (pd_%1_%2 + 4*0)
+%define pd_%2  (pd_%1_%2 + 4*2)
+%if %3 == 3
+%define pd_%2_m%2 pd_%2
+dd -%2, -%2
+%endif
+%endif
+%endmacro
+
+COEF_PAIR  101,  501
+COEF_PAIR  201,  601, 1
+COEF_PAIR  201,  995
+COEF_PAIR  401, 1189, 1
+COEF_PAIR  401, 1931
+COEF_PAIR  401, 3920
+COEF_PAIR  401, 4076
+COEF_PAIR  700,  301, 4
+COEF_PAIR  799, 2276, 1
+COEF_PAIR  799, 3406
+COEF_PAIR  799, 4017
+COEF_PAIR 1380,  601
+COEF_PAIR 1751, 2440
+COEF_PAIR 2598, 1189
+COEF_PAIR 2598, 1931, 2
+COEF_PAIR 2598, 3612
+COEF_PAIR 2751, 2106
+COEF_PAIR 2896, 1567, 3
+COEF_PAIR 2896, 3784, 3
+COEF_PAIR 3035, 3513
+COEF_PAIR 3166, 1931
+COEF_PAIR 3166, 3612
+COEF_PAIR 3166, 3920
+COEF_PAIR 3703, 3290
+COEF_PAIR 3857, 4052
+COEF_PAIR 4017, 2276
+COEF_PAIR 4017, 3406
+COEF_PAIR 4036, 4085
+COEF_PAIR 4076, 1189
+COEF_PAIR 4076, 3612
+COEF_PAIR 4076, 3920
+COEF_PAIR 4091, 3973
+COEF_PAIR 4091, 4052
+COEF_PAIR 4095, 4065
+
+pb_32:           times 4 db 32
+pw_5:            times 2 dw 5
+pw_4096:         times 2 dw 4096
+pw_8192:         times 2 dw 8192
+pw_1697x16:      times 2 dw 1697*16
+pw_2896x8:       times 2 dw 2896*8
+pixel_10bpc_max: times 2 dw 0x03ff
+dconly_10bpc:    times 2 dw 0x7c00
+clip_18b_min:    dd -0x20000
+clip_18b_max:    dd  0x1ffff
+pd_1:            dd 1
+pd_2:            dd 2
+pd_1448:         dd 1448
+pd_2048:         dd 2048
+pd_3071:         dd 3071 ; 1024 + 2048 - 1
+pd_3072:         dd 3072 ; 1024 + 2048
+pd_5119:         dd 5119 ; 1024 + 4096 - 1
+pd_5120:         dd 5120 ; 1024 + 4096
+pd_5793:         dd 5793
+
+cextern dup16_perm
+cextern int8_permA
+cextern idct64_mul_16bpc
+cextern idct_8x8_internal_8bpc_avx512icl.main
+cextern iadst_8x8_internal_8bpc_avx512icl.main_pass2
+cextern idct_8x16_internal_8bpc_avx512icl.main
+cextern idct_8x16_internal_8bpc_avx512icl.main2
+cextern idct_8x16_internal_8bpc_avx512icl.main_fast
+cextern idct_8x16_internal_8bpc_avx512icl.main_fast2
+cextern iadst_8x16_internal_8bpc_avx512icl.main2
+cextern idct_16x8_internal_8bpc_avx512icl.main
+cextern iadst_16x8_internal_8bpc_avx512icl.main_pass2
+cextern idct_16x16_internal_8bpc_avx512icl.main
+cextern idct_16x16_internal_8bpc_avx512icl.main2
+cextern idct_16x16_internal_8bpc_avx512icl.main_fast
+cextern idct_16x16_internal_8bpc_avx512icl.main_fast2
+cextern iadst_16x16_internal_8bpc_avx512icl.main_pass2b
+cextern inv_txfm_add_dct_dct_8x32_8bpc_avx512icl.main
+cextern inv_txfm_add_dct_dct_8x32_8bpc_avx512icl.main_fast
+cextern inv_txfm_add_dct_dct_8x32_8bpc_avx512icl.main_fast2
+cextern inv_txfm_add_dct_dct_8x32_8bpc_avx512icl.main_end
+cextern inv_txfm_add_dct_dct_16x32_8bpc_avx512icl.main_oddhalf
+cextern inv_txfm_add_dct_dct_16x32_8bpc_avx512icl.main_oddhalf_fast
+cextern inv_txfm_add_dct_dct_16x32_8bpc_avx512icl.main_oddhalf_fast2
+cextern inv_txfm_add_dct_dct_32x8_8bpc_avx512icl.main
+cextern inv_txfm_add_dct_dct_32x16_8bpc_avx512icl.main_oddhalf
+cextern inv_txfm_add_dct_dct_32x16_8bpc_avx512icl.main_oddhalf_fast
+cextern inv_txfm_add_dct_dct_32x16_8bpc_avx512icl.main_oddhalf_fast2
+cextern inv_txfm_add_dct_dct_32x16_8bpc_avx512icl.main_oddhalf_fast3
+cextern inv_txfm_add_dct_dct_32x32_8bpc_avx512icl.main_oddhalf
+cextern inv_txfm_add_dct_dct_32x32_8bpc_avx512icl.main_oddhalf_fast
+cextern inv_txfm_add_dct_dct_32x32_8bpc_avx512icl.main_oddhalf_fast2
+cextern inv_txfm_add_dct_dct_32x32_8bpc_avx512icl.main_oddhalf_fast3
+cextern inv_txfm_add_dct_dct_16x64_8bpc_avx512icl.main_oddhalf
+cextern inv_txfm_add_dct_dct_16x64_8bpc_avx512icl.main_oddhalf_fast
+cextern inv_txfm_add_dct_dct_32x64_8bpc_avx512icl.main_part1
+cextern inv_txfm_add_dct_dct_32x64_8bpc_avx512icl.main_part1_fast
+cextern inv_txfm_add_dct_dct_32x64_8bpc_avx512icl.main_part1_fast2
+cextern inv_txfm_add_dct_dct_32x64_8bpc_avx512icl.main_part2
+
+SECTION .text
+
+%define o_base (pw_2048+4*128)
+%define o_base_8bpc (int8_permA+64*18)
+%define o(x) (r5 - o_base + (x))
+%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX)
+
+INIT_ZMM avx512icl
+
+; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12
+; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12
+; flags: 1 = inv_dst1, 2 = inv_dst2
+; skip round/shift if rnd is not a number
+%macro ITX_MULSUB_2D 8-9 0 ; dst/src[1-2], tmp[1-3], rnd, coef[1-2], flags
+%if %8 < 32
+    pmulld              m%4, m%1, m%8
+    pmulld              m%3, m%2, m%8
+%else
+%if %8 < 4096
+    vpbroadcastd        m%3, [o(pd_%8)]
+%else
+    vbroadcasti32x4     m%3, [o(pd_%8)]
+%endif
+    pmulld              m%4, m%1, m%3
+    pmulld              m%3, m%2
+%endif
+%if %7 < 32
+    pmulld              m%1, m%7
+    pmulld              m%2, m%7
+%else
+%if %7 < 4096
+    vpbroadcastd        m%5, [o(pd_%7)]
+%else
+    vbroadcasti32x4     m%5, [o(pd_%7)]
+%endif
+    pmulld              m%1, m%5
+    pmulld              m%2, m%5
+%endif
+%if %9 & 2
+    psubd               m%4, m%6, m%4
+    psubd               m%2, m%4, m%2
+%else
+%ifnum %6
+    paddd               m%4, m%6
+%endif
+    paddd               m%2, m%4
+%endif
+%ifnum %6
+    paddd               m%1, m%6
+%endif
+%if %9 & 1
+    psubd               m%1, m%3, m%1
+%else
+    psubd               m%1, m%3
+%endif
+%ifnum %6
+    psrad               m%2, 12
+    psrad               m%1, 12
+%endif
+%endmacro
+
+%macro INV_TXFM_FN 4 ; type1, type2, eob_offset, size
+cglobal inv_txfm_add_%1_%2_%4_10bpc, 4, 7, 0, dst, stride, c, eob, tx2
+    %define %%p1 m(i%1_%4_internal_10bpc)
+    lea                  r5, [o_base]
+    ; Jump to the 1st txfm function if we're not taking the fast path, which
+    ; in turn performs an indirect jump to the 2nd txfm function.
+    lea tx2q, [m(i%2_%4_internal_10bpc).pass2]
+%ifidn %1_%2, dct_dct
+    test               eobd, eobd
+    jnz %%p1
+%else
+%if %3
+    add                eobd, %3
+%endif
+    ; jump to the 1st txfm function unless it's located directly after this
+    times ((%%end - %%p1) >> 31) & 1 jmp %%p1
+ALIGN function_align
+%%end:
+%endif
+%endmacro
+
+%macro INV_TXFM_8X8_FN 2-3 0 ; type1, type2, eob_offset
+    INV_TXFM_FN          %1, %2, %3, 8x8
+%ifidn %1_%2, dct_dct
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 8
+.dconly:
+    add                 r6d, 384
+    sar                 r6d, 9
+.dconly2:
+    vpbroadcastd        ym2, [o(dconly_10bpc)]
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    vpbroadcastw        ym1, r6d
+    paddsw              ym1, ym2
+.dconly_loop:
+    mova                xm0, [dstq+strideq*0]
+    vinserti32x4        ym0, [dstq+strideq*1], 1
+    paddsw              ym0, ym1
+    psubusw             ym0, ym2
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    RET
+%endif
+%endmacro
+
+INV_TXFM_8X8_FN dct, dct
+INV_TXFM_8X8_FN dct, adst
+INV_TXFM_8X8_FN dct, flipadst
+INV_TXFM_8X8_FN dct, identity
+
+cglobal idct_8x8_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+    call .load
+    vpermi2q             m1, m0, m2 ; 1 5
+    vpermi2q             m3, m6, m4 ; 7 3
+    vpermt2q             m0, m5, m4 ; 0 2
+    vpermt2q             m2, m5, m6 ; 4 6
+    call .main
+    call .main_end
+    mova                 m4, [o(idct8x8p)]
+    packssdw             m0, m2     ; 0 1 4 5
+    packssdw             m1, m3     ; 3 2 7 6
+    vpermb               m0, m4, m0
+    vprolq               m1, 32
+    vpermb               m2, m4, m1
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    jmp                tx2q
+.pass2:
+    lea                  r5, [o_base_8bpc]
+    vextracti32x8       ym2, m0, 1
+    vextracti32x8       ym3, m1, 1
+    call m(idct_8x8_internal_8bpc).main
+    mova                m10, [permC]
+    vpbroadcastd        m12, [pw_2048]
+.end:
+    vpermt2q             m0, m10, m1
+    vpermt2q             m2, m10, m3
+.end2:
+    vpbroadcastd        m11, [pixel_10bpc_max]
+    lea                  r6, [strideq*3]
+    pxor                m10, m10
+    pmulhrsw             m8, m12, m0
+    call .write_8x4_start
+    pmulhrsw             m8, m12, m2
+.write_8x4:
+    lea                dstq, [dstq+strideq*4]
+    add                  cq, 64*2
+.write_8x4_start:
+    mova                xm9, [dstq+strideq*0]
+    vinserti32x4        ym9, [dstq+strideq*1], 1
+    vinserti32x4         m9, [dstq+strideq*2], 2
+    vinserti32x4         m9, [dstq+r6       ], 3
+    mova          [cq+64*0], m10
+    mova          [cq+64*1], m10
+    paddw                m9, m8
+    pmaxsw               m9, m10
+    pminsw               m9, m11
+    mova          [dstq+strideq*0], xm9
+    vextracti32x4 [dstq+strideq*1], ym9, 1
+    vextracti32x4 [dstq+strideq*2], m9, 2
+    vextracti32x4 [dstq+r6       ], m9, 3
+    ret
+ALIGN function_align
+.load:
+    mova                 m0, [cq+64*0] ; 0 1
+    mova                 m4, [cq+64*1] ; 2 3
+    mova                 m1, [o(permB)]
+    mova                 m2, [cq+64*2] ; 4 5
+    mova                 m6, [cq+64*3] ; 6 7
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    psrlq                m5, m1, 32
+    vpbroadcastd        m12, [o(pd_2896)]
+    mova                 m3, m1
+    vpbroadcastd        m11, [o(pd_1)]
+    ret
+ALIGN function_align
+.main_fast: ; bottom half is zero
+    vbroadcasti32x4      m3, [o(pd_4017_3406)]
+    vbroadcasti32x4      m8, [o(pd_799_m2276)]
+    vbroadcasti32x4      m2, [o(pd_2896_3784)]
+    vbroadcasti32x4      m9, [o(pd_2896_1567)]
+    pmulld               m3, m1     ; t4a  t5a
+    pmulld               m1, m8     ; t7a  t6a
+    pmulld               m2, m0     ; t0   t3
+    pmulld               m0, m9     ; t1   t2
+    jmp .main2
+.main:
+    ITX_MULSUB_2D         1, 3, 8, 9, 10, _,  799_3406, 4017_2276
+    ITX_MULSUB_2D         0, 2, 8, 9, 10, _, 2896_1567, 2896_3784
+.main2:
+    REPX     {paddd x, m13}, m1, m3, m0, m2
+    REPX     {psrad x, 12 }, m1, m3, m0, m2
+    punpcklqdq           m8, m1, m3 ; t4a  t7a
+    punpckhqdq           m1, m3     ; t5a  t6a
+    psubd                m3, m8, m1 ; t5a  t6a
+    paddd                m8, m1     ; t4   t7
+    pmaxsd               m3, m14
+    punpckhqdq           m1, m2, m0 ; t3   t2
+    pminsd               m3, m15
+    punpcklqdq           m2, m0     ; t0   t1
+    pmulld               m3, m12
+    paddd                m0, m2, m1 ; dct4 out0 out1
+    psubd                m2, m1     ; dct4 out3 out2
+    REPX    {pmaxsd x, m14}, m8, m0, m2
+    REPX    {pminsd x, m15}, m8, m0, m2
+.main3:
+    pshufd               m1, m3, q1032
+    paddd                m3, m13
+    psubd                m9, m3, m1
+    paddd                m3, m1
+    psrad                m9, 12
+    psrad                m3, 12
+    punpckhqdq           m1, m8, m3   ; t7   t6
+    shufpd               m8, m9, 0xaa ; t4   t5
+    ret
+.main_end:
+    paddd                m0, m11
+    paddd                m2, m11
+    psubd                m3, m0, m1 ; out7 out6
+    paddd                m0, m1     ; out0 out1
+    paddd                m1, m2, m8 ; out3 out2
+    psubd                m2, m8     ; out4 out5
+    REPX   {vpsravd x, m11}, m0, m2, m3, m1
+    ret
+
+INV_TXFM_8X8_FN adst, dct
+INV_TXFM_8X8_FN adst, flipadst
+INV_TXFM_8X8_FN adst, identity
+INV_TXFM_8X8_FN adst, adst
+
+cglobal iadst_8x8_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+    call m(idct_8x8_internal_10bpc).load
+    vpermi2q             m1, m6, m2 ; 7 5
+    vpermi2q             m3, m4, m0 ; 3 1
+    vpermt2q             m0, m5, m4 ; 0 2
+    vpermt2q             m2, m5, m6 ; 4 6
+    call .main
+    punpckldq            m1, m2, m4 ;  out4  out6
+    punpckhdq            m2, m0     ; -out5 -out7
+    punpckldq            m0, m3     ;  out0  out2
+    punpckhdq            m4, m3     ; -out1 -out3
+    paddd                m1, m11
+    psubd                m3, m11, m2
+    paddd                m0, m11
+    psubd                m4, m11, m4
+.pass1_end:
+    REPX       {psrad x, 1}, m1, m0, m3, m4
+    packssdw             m0, m1     ; 0 2 4 6
+    packssdw             m4, m3     ; 1 3 5 7
+    psrlq                m1, [o(permB)], 8
+    punpckhwd            m3, m0, m4
+    punpcklwd            m0, m4
+    psrlq                m2, m1, 32
+    vpermi2q             m1, m0, m3
+    vpermt2q             m0, m2, m3
+    jmp                tx2q
+.pass2:
+    call .main_pass2
+    movu                m10, [permC+2]
+    vbroadcasti32x8     m12, [pw_2048_m2048+16]
+    jmp m(idct_8x8_internal_10bpc).end
+.main_pass2:
+    vextracti32x8       ym2, m0, 1
+    vextracti32x8       ym3, m1, 1
+    lea                  r5, [o_base_8bpc]
+    pshufd              ym4, ym0, q1032
+    pshufd              ym5, ym1, q1032
+    jmp m(iadst_8x8_internal_8bpc).main_pass2
+ALIGN function_align
+.main:
+    ITX_MULSUB_2D         1, 0, 4, 5, 6, 13,  401_1931, 4076_3612
+    ITX_MULSUB_2D         3, 2, 4, 5, 6, 13, 3166_3920, 2598_1189
+    psubd                m4, m0, m2   ; t4  t6
+    paddd                m0, m2       ; t0  t2
+    psubd                m2, m1, m3   ; t5  t7
+    paddd                m1, m3       ; t1  t3
+    REPX    {pmaxsd x, m14}, m4, m2, m0, m1
+    REPX    {pminsd x, m15}, m4, m2, m0, m1
+    pxor                 m5, m5
+    psubd                m5, m4
+    shufpd               m4, m2, 0xaa ; t4  t7
+    shufpd               m2, m5, 0xaa ; t5 -t6
+    ITX_MULSUB_2D         4, 2, 3, 5, 6, 13, 1567, 3784
+    punpckhqdq           m3, m0, m1
+    punpcklqdq           m0, m1
+    psubd                m1, m0, m3   ; t2  t3
+    paddd                m0, m3       ; out0 -out7
+    punpckhqdq           m3, m4, m2   ; t7a t6a
+    punpcklqdq           m4, m2       ; t5a t4a
+    psubd                m2, m4, m3   ; t7  t6
+    paddd                m4, m3       ; out6 -out1
+    REPX    {pmaxsd x, m14}, m1, m2
+    REPX    {pminsd x, m15}, m1, m2
+    shufpd               m3, m1, m2, 0xaa
+    shufpd               m1, m2, 0x55
+    pmulld               m3, m12
+    pmulld               m1, m12
+    paddd                m3, m13
+    psubd                m2, m3, m1
+    paddd                m3, m1
+    psrad                m2, 12       ; out4 -out5
+    pshufd               m3, m3, q1032
+    psrad                m3, 12       ; out2 -out3
+    ret
+
+INV_TXFM_8X8_FN flipadst, dct
+INV_TXFM_8X8_FN flipadst, adst
+INV_TXFM_8X8_FN flipadst, identity
+INV_TXFM_8X8_FN flipadst, flipadst
+
+cglobal iflipadst_8x8_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+    call m(idct_8x8_internal_10bpc).load
+    vpermi2q             m1, m6, m2 ; 7 5
+    vpermi2q             m3, m4, m0 ; 3 1
+    vpermt2q             m0, m5, m4 ; 0 2
+    vpermt2q             m2, m5, m6 ; 4 6
+    call m(iadst_8x8_internal_10bpc).main
+    punpckhdq            m1, m3, m4 ; -out3 -out1
+    punpckldq            m3, m0     ;  out2  out0
+    punpckhdq            m0, m2     ; -out7 -out5
+    punpckldq            m4, m2     ;  out6  out4
+    psubd                m1, m11, m1
+    paddd                m3, m11
+    psubd                m0, m11, m0
+    paddd                m4, m11
+    jmp m(iadst_8x8_internal_10bpc).pass1_end
+.pass2:
+    call m(iadst_8x8_internal_10bpc).main_pass2
+    movu                m10, [permC+1]
+    vbroadcasti32x8     m12, [pw_m2048_2048+16]
+    lea                  r6, [strideq*3]
+    vpermt2q             m0, m10, m1 ; 7 6 5 4
+    vpbroadcastd        m11, [pixel_10bpc_max]
+    vpermt2q             m2, m10, m3 ; 3 2 1 0
+    pxor                m10, m10
+    pmulhrsw             m8, m12, m2
+    call m(idct_8x8_internal_10bpc).write_8x4_start
+    pmulhrsw             m8, m12, m0
+    jmp m(idct_8x8_internal_10bpc).write_8x4
+
+INV_TXFM_8X8_FN identity, dct
+INV_TXFM_8X8_FN identity, adst
+INV_TXFM_8X8_FN identity, flipadst
+INV_TXFM_8X8_FN identity, identity
+
+cglobal iidentity_8x8_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+    mova                 m1, [cq+64*0]
+    packssdw             m1, [cq+64*2] ; 0 4   1 5
+    mova                 m2, [cq+64*1] ; 2 6   3 7
+    packssdw             m2, [cq+64*3]
+    mova                 m0, [o(idtx8x8p)]
+    vpermb               m1, m0, m1
+    vpermb               m2, m0, m2
+    punpckldq            m0, m1, m2    ; 0 1   4 5
+    punpckhdq            m1, m2        ; 2 3   6 7
+    jmp                tx2q
+.pass2:
+    movu                 m3, [o(permC+2)]
+    vpbroadcastd        m12, [o(pw_4096)]
+    psrlq                m2, m3, 32
+    vpermi2q             m2, m0, m1
+    vpermt2q             m0, m3, m1
+    jmp m(idct_8x8_internal_10bpc).end2
+
+%macro INV_TXFM_8X16_FN 2-3 0 ; type1, type2, eob_offset
+    INV_TXFM_FN          %1, %2, %3, 8x16
+%ifidn %1_%2, dct_dct
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 16
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    jmp m(inv_txfm_add_dct_dct_8x8_10bpc).dconly
+%endif
+%endmacro
+
+INV_TXFM_8X16_FN dct, dct
+INV_TXFM_8X16_FN dct, identity, 35
+INV_TXFM_8X16_FN dct, flipadst
+INV_TXFM_8X16_FN dct, adst
+
+cglobal idct_8x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    cmp                eobd, 43
+    jl .fast
+    call .load
+    call .main
+    call .main_end
+.pass1_end:
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    jmp                tx2q
+.pass2:
+    mova                 m8, [o(idct8x16p)]
+    REPX  {vpermb x, m8, x}, m0, m1, m2, m3
+    punpckhdq            m5, m0, m1
+    punpckldq            m0, m1
+    punpckhdq            m4, m2, m3
+    punpckldq            m2, m3
+    punpcklqdq           m8, m0, m2 ; 15  1
+    punpckhqdq           m0, m2     ;  7  9
+    punpckhqdq           m1, m5, m4 ;  3 13
+    punpcklqdq           m5, m4     ; 11  5
+    lea                  r5, [o_base_8bpc]
+    vextracti32x8       ym7, m8, 1  ; 14  2
+    vextracti32x8       ym3, m0, 1  ;  6 10
+    vextracti32x8       ym6, m1, 1  ; 12  4
+    vextracti32x8       ym9, m5, 1  ;  8  0
+    call m(idct_8x16_internal_8bpc).main2
+    mova                 m8, [permC]
+    vpbroadcastd        m12, [pw_2048]
+    vpermt2q             m0, m8, m1
+    lea                  r6, [strideq*3]
+    vpermt2q             m2, m8, m3
+    vpbroadcastd        m11, [pixel_10bpc_max]
+    vpermt2q             m4, m8, m5
+    pxor                m10, m10
+    vpermt2q             m6, m8, m7
+    pmulhrsw             m8, m12, m0
+    call m(idct_8x8_internal_10bpc).write_8x4_start
+    pmulhrsw             m8, m12, m2
+    call m(idct_8x8_internal_10bpc).write_8x4
+    pmulhrsw             m8, m12, m4
+    call m(idct_8x8_internal_10bpc).write_8x4
+    pmulhrsw             m8, m12, m6
+    jmp m(idct_8x8_internal_10bpc).write_8x4
+.fast:
+    mova                ym0, [cq+64*0]
+    mova                ym4, [cq+64*2]
+    mova                ym1, [cq+64*1]
+    mova                ym5, [cq+64*5]
+    mova                ym2, [cq+64*4]
+    mova                ym6, [cq+64*6]
+    mova                ym3, [cq+64*7]
+    mova                ym7, [cq+64*3]
+    call .round_input_fast
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x8_internal_10bpc).main_end
+    movu                 m6, [o(permC+3)]
+    packssdw             m3, m1, m3
+    packssdw             m1, m0, m2
+    vprolq               m3, 32
+    vpermd               m1, m6, m1
+    vpermd               m3, m6, m3
+    mova                ym0, ym1    ; 0 4
+    vextracti32x8       ym1, m1, 1  ; 1 5
+    mova                ym2, ym3    ; 2 6
+    vextracti32x8       ym3, m3, 1  ; 3 7
+    jmp                tx2q
+ALIGN function_align
+.round_input_fast:
+    movshdup             m8, [o(permB)]
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpermt2q             m0, m8, m4
+    vpermt2q             m1, m8, m5
+    vpermt2q             m2, m8, m6
+    vpermt2q             m3, m8, m7
+    vpbroadcastd        m13, [o(pd_2048)]
+    REPX    {pmulld x, m12}, m0, m1, m2, m3
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    REPX    {paddd  x, m13}, m0, m1, m2, m3
+    vpbroadcastd        m11, [o(pd_1)]
+    REPX    {psrad  x, 12 }, m0, m1, m2, m3
+    ret
+ALIGN function_align
+.load:
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+.load2:
+    vpbroadcastd        m12, [o(pd_2896)]
+    pmulld               m0, m12, [cq+64*0]
+    pmulld               m1, m12, [cq+64*1]
+    pmulld               m2, m12, [cq+64*2]
+    pmulld               m3, m12, [cq+64*3]
+    vpbroadcastd        m13, [o(pd_2048)]
+    pmulld               m4, m12, [cq+64*4]
+    pmulld               m5, m12, [cq+64*5]
+    pmulld               m6, m12, [cq+64*6]
+    pmulld               m7, m12, [cq+64*7]
+.round:
+    REPX     {paddd x, m13}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+    REPX     {paddd x, m13}, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m4, m5, m6, m7
+    ret
+ALIGN function_align
+.main_fast2_rect2:
+    REPX     {paddd x, m13}, m0, m1
+    REPX     {psrad x, 12 }, m0, m1
+.main_fast2:
+    pmulld               m0, m12
+    pmulld               m6, m1, [o(pd_4017)] {1to16} ; t7a
+    pmulld               m8, m1, [o(pd_799)] {1to16}  ; t4a
+    REPX    {paddd  x, m13}, m0, m6, m8
+    REPX    {psrad  x, 12 }, m0, m6, m8
+    pmulld               m5, m6, m12
+    pmulld               m1, m8, m12
+    paddd                m5, m13
+    psubd                m4, m5, m1
+    paddd                m5, m1
+    REPX    {psrad  x, 12 }, m4, m5
+    REPX    {mova   x, m0 }, m1, m2, m3
+    ret
+.main_fast_rect2:
+    REPX     {paddd x, m13}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+.main_fast:
+    pmulld               m0, m12
+    pmulld               m5, m3, [o(pd_2276)] {1to16} ; t5a
+    pmulld               m3, [o(pd_3406)] {1to16}     ; t6a
+    pmulld               m7, m1, [o(pd_4017)] {1to16} ; t7a
+    pmulld               m1, [o(pd_799)] {1to16}      ; t4a
+    pmulld               m6, m2, [o(pd_3784)] {1to16} ; t3
+    pmulld               m2, [o(pd_1567)] {1to16}     ; t2
+    paddd                m0, m13
+    psubd                m5, m13, m5
+    psrad                m0, 12                       ; t0
+    mova                 m9, m0                       ; t1
+    jmp .main2
+.main_rect2:
+    call .round
+.main:
+    pmulld               m0, m12
+    ITX_MULSUB_2D         5, 3, 8, 9, 10, _, 3406, 2276 ; t5a t6a
+    ITX_MULSUB_2D         1, 7, 8, 9, 10, _,  799, 4017 ; t4a t7a
+    ITX_MULSUB_2D         2, 6, 8, 9, 10, _, 1567, 3784 ; t2  t3
+    pmulld               m4, m12
+    paddd                m0, m13
+    paddd                m5, m13
+    psubd                m9, m0, m4 ; t1
+    paddd                m0, m4     ; t0
+    psrad                m9, 12
+    psrad                m0, 12
+.main2:
+    REPX    {paddd  x, m13}, m3, m1, m7
+    REPX    {psrad  x, 12 }, m5, m1, m3, m7
+    paddd                m8, m1, m5 ; t4
+    psubd                m1, m5     ; t5a
+    psubd                m5, m7, m3 ; t6a
+    paddd                m7, m3     ; t7
+    pmaxsd               m5, m14
+    pmaxsd               m1, m14
+    paddd                m2, m13
+    paddd                m6, m13
+    pminsd               m5, m15
+    pminsd               m1, m15
+    pmulld               m5, m12
+    pmulld               m1, m12
+    pmaxsd               m8, m14
+    pmaxsd               m7, m14
+    pminsd               m8, m15
+    paddd                m5, m13
+    psubd                m4, m5, m1
+    paddd                m5, m1
+    REPX    {psrad  x, 12 }, m2, m6, m5, m4
+    paddd                m1, m9, m2 ; dct4 out1
+    psubd                m2, m9, m2 ; dct4 out2
+    psubd                m3, m0, m6 ; dct4 out3
+    paddd                m0, m6     ; dct4 out0
+    pminsd               m6, m15, m7
+    REPX    {pmaxsd x, m14}, m0, m1, m2, m3
+    REPX    {pminsd x, m15}, m0, m1, m2, m3
+    ret
+.main_end:
+    vpbroadcastd        m11, [o(pd_1)]
+.main_end2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3
+    psubd                m7, m0, m6 ; out7
+    paddd                m0, m6     ; out0
+    psubd                m6, m1, m5 ; out6
+    paddd                m1, m5     ; out1
+    psubd                m5, m2, m4 ; out5
+    paddd                m2, m4     ; out2
+    psubd                m4, m3, m8 ; out4
+    paddd                m3, m8     ; out3
+    REPX   {vpsravd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    ret
+
+INV_TXFM_8X16_FN adst, dct
+INV_TXFM_8X16_FN adst, identity, 35
+INV_TXFM_8X16_FN adst, flipadst
+INV_TXFM_8X16_FN adst, adst
+
+cglobal iadst_8x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    cmp                eobd, 43
+    jl .fast
+    call m(idct_8x16_internal_10bpc).load
+    call .main
+    psrad                m0, 1
+    psrad                m1, 1
+    psrad                m6, m10, 1
+    psrad                m7, m11, 1
+    psrad                m2, 12
+    psrad                m3, 12
+    psrad                m4, m8, 12
+    psrad                m5, m9, 12
+    jmp m(idct_8x16_internal_10bpc).pass1_end
+.fast:
+    call .fast_main
+    punpcklqdq           m1, m2, m4 ;  out4  out6
+    punpckhqdq           m2, m0     ; -out5 -out7
+    punpcklqdq           m0, m3     ;  out0  out2
+    punpckhqdq           m4, m3     ; -out1 -out3
+    paddd                m1, m11
+    psubd                m3, m11, m2
+    paddd                m0, m11
+    psubd                m4, m11, m4
+.fast_end:
+    movu                 m5, [o(permC+3)]
+    REPX       {psrad x, 1}, m1, m0, m3, m4
+    packssdw             m2, m0, m1 ; 0 2 4 6
+    packssdw             m3, m4, m3 ; 1 3 5 7
+    vpermd               m2, m5, m2
+    vpermd               m3, m5, m3
+    mova                ym0, ym2
+    vextracti32x8       ym2, m2, 1
+    mova                ym1, ym3
+    vextracti32x8       ym3, m3, 1
+    jmp                tx2q
+.pass2:
+    call .pass2_main
+    movu                 m4, [permB+2]
+    vbroadcasti32x8     m12, [pw_2048_m2048+16]
+    psrlq                m7, m4, 8
+    vpermi2q             m4, m0, m3 ;  0  1  2  3
+    psrlq                m5, m7, 24
+    vpermi2q             m7, m0, m3 ; 12 13 14 15
+    psrlq                m6, m5, 8
+    vpermq               m5, m5, m1 ;  4  5  6  7
+    vpermq               m6, m6, m2 ;  8  9 10 11
+.pass2_end:
+    vpbroadcastd        m11, [pixel_10bpc_max]
+    pxor                m10, m10
+    lea                  r6, [strideq*3]
+    pmulhrsw             m8, m12, m4
+    call m(idct_8x8_internal_10bpc).write_8x4_start
+    pmulhrsw             m8, m12, m5
+    call m(idct_8x8_internal_10bpc).write_8x4
+    pmulhrsw             m8, m12, m6
+    call m(idct_8x8_internal_10bpc).write_8x4
+    pmulhrsw             m8, m12, m7
+    jmp m(idct_8x8_internal_10bpc).write_8x4
+ALIGN function_align
+.main:
+    ITX_MULSUB_2D         7, 0, 8, 9, 10, 13,  401, 4076 ; t1a, t0a
+    ITX_MULSUB_2D         1, 6, 8, 9, 10, 13, 3920, 1189 ; t7a, t6a
+    ITX_MULSUB_2D         5, 2, 8, 9, 10, 13, 1931, 3612 ; t3a, t2a
+    ITX_MULSUB_2D         3, 4, 8, 9, 10, 13, 3166, 2598 ; t5a, t4a
+    psubd                m8, m2, m6 ; t6
+    paddd                m2, m6     ; t2
+    psubd                m6, m0, m4 ; t4
+    paddd                m0, m4     ; t0
+    psubd                m4, m5, m1 ; t7
+    paddd                m5, m1     ; t3
+    psubd                m1, m7, m3 ; t5
+    paddd                m7, m3     ; t1
+    REPX    {pmaxsd x, m14}, m6, m1, m8, m4, m2, m0, m5, m7
+    REPX    {pminsd x, m15}, m6, m1, m8, m4, m2, m0, m5, m7
+    vpbroadcastd        m10, [o(pd_1567)]
+    vpbroadcastd        m11, [o(pd_3784)]
+    ITX_MULSUB_2D         6, 1, 3, 9, _, 13, 10, 11 ; t5a, t4a
+    ITX_MULSUB_2D         4, 8, 3, 9, _, 13, 11, 10 ; t6a, t7a
+    vpbroadcastd        m12, [o(pd_1448)]
+    psubd                m9, m6, m8 ;  t7
+    paddd                m6, m8     ;  out6
+    psubd                m3, m7, m5 ;  t3
+    paddd                m7, m5     ; -out7
+    psubd                m5, m0, m2 ;  t2
+    paddd                m0, m2     ;  out0
+    psubd                m2, m1, m4 ;  t6
+    paddd                m1, m4     ; -out1
+    REPX    {pmaxsd x, m14}, m5, m3, m2, m9
+    REPX    {pminsd x, m15}, m5, m3, m2, m9
+    REPX    {pmulld x, m12}, m5, m3, m2, m9
+    vpbroadcastd         m4, [o(pd_1)]
+    psubd                m8, m5, m3 ; (t2 - t3) * 1448
+    paddd                m3, m5     ; (t2 + t3) * 1448
+    psubd                m5, m2, m9 ; (t6 - t7) * 1448
+    paddd                m2, m9     ; (t6 + t7) * 1448
+    vpbroadcastd         m9, [o(pd_3072)]
+    paddd                m0, m4
+    psubd                m1, m4, m1
+    paddd               m10, m6, m4
+    psubd               m11, m4, m7
+    paddd                m2, m9
+    paddd                m8, m9
+    vpbroadcastd         m9, [o(pd_3071)]
+    psubd                m3, m9, m3
+    psubd                m9, m5
+    ret
+ALIGN function_align
+.fast_main:
+    mova                ym0, [cq+64*0]
+    mova                ym4, [cq+64*2]
+    mova                ym1, [cq+64*7]
+    mova                ym5, [cq+64*5]
+    mova                ym2, [cq+64*4]
+    mova                ym6, [cq+64*6]
+    mova                ym3, [cq+64*3]
+    mova                ym7, [cq+64*1]
+    call m(idct_8x16_internal_10bpc).round_input_fast
+    jmp m(iadst_8x8_internal_10bpc).main
+ALIGN function_align
+.pass2_main:
+    mova                 m8, [o(iadst8x16p)]
+    REPX  {vpermb x, m8, x}, m0, m1, m2, m3
+    vpbroadcastd        m10, [o(pw_2896x8)]
+    punpckhdq            m5, m0, m1
+    punpckldq            m0, m1
+    punpckhdq            m1, m2, m3
+    punpckldq            m2, m3
+    lea                  r5, [o_base_8bpc]
+    punpckhqdq           m4, m0, m2 ; 12  3   14  1
+    punpcklqdq           m0, m2     ;  0 15    2 13
+    punpckhqdq           m6, m5, m1 ;  8  7   10  5
+    punpcklqdq           m5, m1     ;  4 11    6  9
+    call m(iadst_8x16_internal_8bpc).main2
+    paddsw               m1, m2, m4
+    psubsw               m2, m4
+    pmulhrsw             m1, m10    ; -out7   out4   out6  -out5
+    pmulhrsw             m2, m10    ;  out8  -out11 -out9   out10
+    ret
+
+INV_TXFM_8X16_FN flipadst, dct
+INV_TXFM_8X16_FN flipadst, identity, 35
+INV_TXFM_8X16_FN flipadst, adst
+INV_TXFM_8X16_FN flipadst, flipadst
+
+cglobal iflipadst_8x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    cmp                eobd, 43
+    jl .fast
+    call m(idct_8x16_internal_10bpc).load
+    call m(iadst_8x16_internal_10bpc).main
+    psrad                m7, m0, 1
+    psrad                m0, m11, 1
+    psrad                m6, m1, 1
+    psrad                m1, m10, 1
+    psrad                m5, m2, 12
+    psrad                m2, m9, 12
+    psrad                m4, m3, 12
+    psrad                m3, m8, 12
+    jmp m(idct_8x16_internal_10bpc).pass1_end
+.fast:
+    call m(iadst_8x16_internal_10bpc).fast_main
+    punpckhqdq           m1, m3, m4 ; -out3 -out1
+    punpcklqdq           m3, m0     ;  out2  out0
+    punpckhqdq           m0, m2     ; -out7 -out5
+    punpcklqdq           m4, m2     ;  out6  out4
+    psubd                m1, m11, m1
+    paddd                m3, m11
+    psubd                m0, m11, m0
+    paddd                m4, m11
+    jmp m(iadst_8x16_internal_10bpc).fast_end
+.pass2:
+    call m(iadst_8x16_internal_10bpc).pass2_main
+    movu                 m7, [permB+2]
+    vbroadcasti32x8     m12, [pw_m2048_2048+16]
+    psrlq                m4, m7, 8
+    vpermi2q             m7, m3, m0 ;  3  2  1  0
+    psrlq                m5, m4, 24
+    vpermi2q             m4, m3, m0 ; 15 14 13 12
+    psrlq                m6, m5, 8
+    vpermq               m5, m5, m2 ; 11 10  9  8
+    vpermq               m6, m6, m1 ;  7  6  5  4
+    jmp m(iadst_8x16_internal_10bpc).pass2_end
+
+INV_TXFM_8X16_FN identity, dct
+INV_TXFM_8X16_FN identity, adst
+INV_TXFM_8X16_FN identity, flipadst
+INV_TXFM_8X16_FN identity, identity
+
+cglobal iidentity_8x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+    call m(idct_8x16_internal_10bpc).load2
+    jmp m(idct_8x16_internal_10bpc).pass1_end
+.pass2:
+    vpbroadcastd         m8, [o(pw_1697x16)]
+    pmulhrsw             m4, m8, m0
+    pmulhrsw             m5, m8, m1
+    pmulhrsw             m6, m8, m2
+    pmulhrsw             m7, m8, m3
+    REPX      {paddsw x, x}, m0, m1, m2, m3
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    vpbroadcastd         m7, [o(pw_2048)]
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    vpbroadcastd         m6, [o(pixel_10bpc_max)]
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m4, m1
+    punpckhdq            m4, m1
+    pxor                 m5, m5
+    punpckhqdq           m1, m0, m2 ;  1  5  9 13
+    punpcklqdq           m0, m2     ;  0  4  8 12
+    punpcklqdq           m2, m3, m4 ;  2  6 10 14
+    punpckhqdq           m3, m4     ;  3  7 11 15
+    lea                  r6, [strideq*3]
+    pmulhrsw             m0, m7
+    call .write_8x4_start
+    pmulhrsw             m0, m7, m1
+    call .write_8x4
+    pmulhrsw             m0, m7, m2
+    call .write_8x4
+    pmulhrsw             m0, m7, m3
+.write_8x4:
+    add                dstq, strideq
+    add                  cq, 64*2
+.write_8x4_start:
+    mova                xm4, [dstq+strideq*0]
+    vinserti32x4        ym4, [dstq+strideq*4], 1
+    vinserti32x4         m4, [dstq+strideq*8], 2
+    vinserti32x4         m4, [dstq+r6*4     ], 3
+    mova          [cq+64*0], m5
+    mova          [cq+64*1], m5
+    paddw                m4, m0
+    pmaxsw               m4, m5
+    pminsw               m4, m6
+    mova          [dstq+strideq*0], xm4
+    vextracti32x4 [dstq+strideq*4], ym4, 1
+    vextracti32x4 [dstq+strideq*8], m4, 2
+    vextracti32x4 [dstq+r6*4     ], m4, 3
+    ret
+
+%macro INV_TXFM_16X8_FN 2-3 0 ; type1, type2, eob_offset
+    INV_TXFM_FN          %1, %2, %3, 16x8
+%ifidn %1_%2, dct_dct
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 8
+.dconly:
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 384
+    sar                 r6d, 9
+.dconly2:
+    vpbroadcastd         m2, [o(dconly_10bpc)]
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    vpbroadcastw         m1, r6d
+    paddsw               m1, m2
+.dconly_loop:
+    mova                ym0, [dstq+strideq*0]
+    vinserti32x8         m0, [dstq+strideq*1], 1
+    paddsw               m0, m1
+    psubusw              m0, m2
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    RET
+%endif
+%endmacro
+
+INV_TXFM_16X8_FN dct, dct
+INV_TXFM_16X8_FN dct, identity, -21
+INV_TXFM_16X8_FN dct, flipadst
+INV_TXFM_16X8_FN dct, adst
+
+cglobal idct_16x8_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    vpbroadcastd        m12, [o(pd_2896)]
+    pmulld               m4, m12, [cq+64*0] ;  0  1
+    pmulld               m9, m12, [cq+64*1] ;  2  3
+    pmulld               m8, m12, [cq+64*2] ;  4  5
+    pmulld               m7, m12, [cq+64*3] ;  6  7
+    vpbroadcastd        m13, [o(pd_2048)]
+    pxor                 m2, m2
+    mova                m15, [o(permB)]
+    REPX {mova [cq+64*x], m2}, 0, 1, 2, 3
+    psrlq                m0, m15, 32
+    REPX     {paddd x, m13}, m4, m9, m8, m7
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    REPX     {psrad x, 12 }, m4, m8, m9, m7
+    mova                 m1, m0
+    vpermi2q             m0, m4, m8   ;  0  4
+    cmp                eobd, 43
+    jl .fast
+    pmulld               m5, m12, [cq+64*4] ;  8  9
+    pmulld              m10, m12, [cq+64*5] ; 10 11
+    pmulld              m11, m12, [cq+64*6] ; 12 13
+    pmulld               m6, m12, [cq+64*7] ; 14 15
+    REPX {mova [cq+64*x], m2}, 4, 5, 6, 7
+    REPX     {paddd x, m13}, m5, m10, m11, m6
+    REPX     {psrad x, 12 }, m10, m5, m11, m6
+    mova                 m2, m1
+    vpermi2q             m1, m9, m10  ;  2 10
+    mova                 m3, m2
+    vpermi2q             m2, m5, m11  ;  8 12
+    vpermi2q             m3, m6, m7   ; 14  6
+    vpermt2q             m4, m15, m11 ;  1 13
+    vpermt2q             m6, m15, m9  ; 15  3
+    vpermt2q             m5, m15, m8  ;  9  5
+    vpermt2q             m7, m15, m10 ;  7 11
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    call m(idct_8x8_internal_10bpc).main
+    call .main
+    jmp .pass1_end
+.fast:
+    vpermi2q             m1, m9, m7   ;  2  6
+    vpermt2q             m4, m15, m9  ;  1  3
+    vpermt2q             m7, m15, m8  ;  7  5
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    call m(idct_8x8_internal_10bpc).main_fast
+    call .main_fast
+.pass1_end:
+    call m(idct_8x16_internal_10bpc).main_end
+    mova                 m8, [o(permA)]
+    psrlq                m9, m8, 8
+.pass1_end2:
+    mova                m10, m9
+    mova                m11, m8
+    call .transpose_16x8
+    jmp                tx2q
+.pass2:
+    lea                  r5, [o_base_8bpc]
+    call m(idct_16x8_internal_8bpc).main
+    movshdup             m4, [permC]
+    vpbroadcastd        m11, [pw_2048]
+    psrlq                m5, m4, 8
+.end:
+    vpbroadcastd        m13, [pixel_10bpc_max]
+    pxor                m12, m12
+    vpermq               m8, m4, m0
+    vpermq               m9, m5, m1
+    lea                  r6, [strideq*3]
+    call .write_16x4
+    vpermq               m8, m4, m2
+    vpermq               m9, m5, m3
+.write_16x4:
+    pmulhrsw             m8, m11
+    pmulhrsw             m9, m11
+.write_16x4_noround:
+    mova               ym10, [dstq+strideq*0]
+    vinserti32x8        m10, [dstq+strideq*1], 1
+    paddw                m8, m10
+    mova               ym10, [dstq+strideq*2]
+    vinserti32x8        m10, [dstq+r6       ], 1
+    paddw                m9, m10
+    pmaxsw               m8, m12
+    pmaxsw               m9, m12
+    pminsw               m8, m13
+    pminsw               m9, m13
+    mova          [dstq+strideq*0], ym8
+    vextracti32x8 [dstq+strideq*1], m8, 1
+    mova          [dstq+strideq*2], ym9
+    vextracti32x8 [dstq+r6       ], m9, 1
+    lea                dstq, [dstq+strideq*4]
+    ret
+ALIGN function_align
+.main_fast: ; bottom half is zero
+    vbroadcasti32x4      m6, [o(pd_4076_3920)]
+    vbroadcasti32x4      m3, [o(pd_401_m1189)]
+    vbroadcasti32x4      m5, [o(pd_m2598_1931)]
+    vbroadcasti32x4      m9, [o(pd_3166_3612)]
+    pmulld               m6, m4    ; t15a t12a
+    pmulld               m4, m3    ; t8a  t11a
+    pmulld               m5, m7    ; t9a  t10a
+    pmulld               m7, m9    ; t14a t13a
+    jmp .main2
+.main:
+    ITX_MULSUB_2D         4, 6, 3, 9, 10, _,  401_3920, 4076_1189
+    ITX_MULSUB_2D         5, 7, 3, 9, 10, _, 3166_1931, 2598_3612
+.main2:
+    REPX     {paddd x, m13}, m4, m6, m5, m7
+    REPX     {psrad x, 12 }, m4, m5, m6, m7
+    paddd                m9, m4, m5 ; t8   t11
+    psubd                m4, m5     ; t9   t10
+    psubd                m5, m6, m7 ; t14  t13
+    paddd                m6, m7     ; t15  t12
+    REPX    {pmaxsd x, m14}, m5, m4, m9, m6
+    REPX    {pminsd x, m15}, m5, m4, m9, m6
+.main3:
+    psubd                m3, m0, m1 ; dct8 out7 out6
+    paddd                m0, m1     ; dct8 out0 out1
+    vbroadcasti32x4      m7, [o(pd_3784_m3784)]
+    pmulld               m7, m5
+    vpmulld              m5, [o(pd_1567)] {1to16}
+    paddd                m1, m2, m8 ; dct8 out3 out2
+    psubd                m2, m8     ; dct8 out4 out5
+    vbroadcasti32x4      m8, [o(pd_1567_m1567)]
+    pmulld               m8, m4
+    vpmulld              m4, [o(pd_3784)] {1to16}
+    REPX    {pmaxsd x, m14}, m0, m1
+    REPX    {pminsd x, m15}, m0, m1
+    paddd                m7, m13
+    paddd                m5, m13
+    paddd                m7, m8
+    psubd                m5, m4
+    psrad                m7, 12     ; t14a t10a
+    psrad                m5, 12     ; t9a  t13a
+    punpckhqdq           m4, m9, m7
+    punpcklqdq           m8, m9, m5
+    punpckhqdq           m5, m6, m5
+    punpcklqdq           m6, m7
+    psubd                m7, m8, m4 ; t11a t10
+    paddd                m8, m4     ; t8a  t9
+    psubd                m4, m6, m5 ; t12a t13
+    paddd                m6, m5     ; t15a t14
+    REPX    {pmaxsd x, m14}, m4, m7
+    REPX    {pminsd x, m15}, m4, m7
+    pmulld               m4, m12
+    pmulld               m7, m12
+    REPX    {pmaxsd x, m14}, m2, m3, m6, m8
+    REPX    {pminsd x, m15}, m2, m3, m6, m8
+    paddd                m4, m13
+    paddd                m5, m4, m7
+    psubd                m4, m7
+    psrad                m4, 12     ; t11 t10a
+    psrad                m5, 12     ; t12 t13a
+    ret
+ALIGN function_align
+.transpose_16x8:
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    vpermi2d             m8, m0, m2
+    vpermt2d             m0, m9, m2
+    vpermi2d            m10, m1, m3
+    vpermi2d            m11, m1, m3
+    punpckhwd            m3, m8, m0
+    punpcklwd            m1, m8, m0
+    punpckhwd            m4, m10, m11
+    punpcklwd            m2, m10, m11
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    ret
+
+INV_TXFM_16X8_FN adst, dct
+INV_TXFM_16X8_FN adst, identity, -21
+INV_TXFM_16X8_FN adst, flipadst
+INV_TXFM_16X8_FN adst, adst
+
+cglobal iadst_16x8_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    call .main_pass1
+    vpbroadcastd         m9, [o(pd_1)]
+    paddd                m0, m9
+    psubd                m1, m9, m1
+    paddd                m2, m9
+    psubd                m3, m9, m3
+    paddd                m4, m9, m5
+    psubd                m5, m9, m6
+    paddd                m6, m9, m7
+    psubd                m7, m9, m8
+.pass1_end:
+    mova                 m9, [o(permA)]
+    psrlq                m8, m9, 8
+    REPX       {psrad x, 1}, m0, m4, m1, m5, m2, m6, m3, m7
+    jmp m(idct_16x8_internal_10bpc).pass1_end2
+.pass2:
+    call .main_pass2
+    vpermq               m8, m11, m0
+    vpermq               m9, m11, m1
+    call m(idct_16x8_internal_10bpc).write_16x4_noround
+    vpermq               m8, m11, m2
+    vpermq               m9, m11, m3
+    jmp m(idct_16x8_internal_10bpc).write_16x4_noround
+ALIGN function_align
+.main_pass1:
+    vpbroadcastd        m12, [o(pd_2896)]
+    pmulld               m2, m12, [cq+64*0]
+    pmulld               m7, m12, [cq+64*1]
+    pmulld               m1, m12, [cq+64*2]
+    pmulld               m5, m12, [cq+64*3]
+    vpbroadcastd        m13, [o(pd_2048)]
+    pxor                 m4, m4
+    mova                m10, [o(permB)]
+    REPX {mova [cq+64*x], m4}, 0, 1, 2, 3
+    REPX     {paddd x, m13}, m2, m7, m1, m5
+    psrlq                m6, m10, 32
+    REPX     {psrad x, 12 }, m2, m7, m1, m5
+    mova                 m0, m6
+    vpermi2q             m0, m2, m7  ;  0  2
+    vpermt2q             m7, m10, m2 ;  3  1
+    mova                 m2, m6
+    vpermi2q             m2, m1, m5  ;  4  6
+    vpermt2q             m5, m10, m1 ;  7  5
+    cmp                eobd, 43
+    jl .main_fast
+    pmulld               m8, m12, [cq+64*4]
+    pmulld               m3, m12, [cq+64*5]
+    pmulld               m9, m12, [cq+64*6]
+    pmulld               m1, m12, [cq+64*7]
+    REPX {mova [cq+64*x], m4}, 4, 5, 6, 7
+    REPX     {paddd x, m13}, m8, m3, m9, m1
+    REPX     {psrad x, 12 }, m8, m3, m9, m1
+    mova                 m4, m6
+    vpermi2q             m4, m8, m3  ;  8 10
+    vpermt2q             m3, m10, m8 ; 11  9
+    vpermi2q             m6, m9, m1  ; 12 14
+    vpermt2q             m1, m10, m9 ; 15 13
+.main:
+    ITX_MULSUB_2D         1, 0, 8, 9, 10, _,  201_995,  4091_3973, 1
+    ITX_MULSUB_2D         3, 2, 8, 9, 10, _, 1751_2440, 3703_3290, 1
+    ITX_MULSUB_2D         5, 4, 8, 9, 10, _, 3035_3513, 2751_2106
+    ITX_MULSUB_2D         7, 6, 8, 9, 10, _, 3857_4052, 1380_601
+    jmp .main2
+.main_fast:
+    vbroadcasti32x4      m1, [o(pd_4091_3973)]
+    vbroadcasti32x4      m8, [o(pd_201_995)]
+    vbroadcasti32x4      m3, [o(pd_3703_3290)]
+    vbroadcasti32x4      m9, [o(pd_1751_2440)]
+    vbroadcasti32x4      m4, [o(pd_2751_2106)]
+    vbroadcasti32x4     m10, [o(pd_3035_3513)]
+    vbroadcasti32x4      m6, [o(pd_1380_601)]
+    vbroadcasti32x4     m11, [o(pd_3857_4052)]
+    pmulld               m1, m0
+    pmulld               m0, m8
+    pmulld               m3, m2
+    pmulld               m2, m9
+    pmulld               m4, m5
+    pmulld               m5, m10
+    pmulld               m6, m7
+    pmulld               m7, m11
+.main2:
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    REPX  {psubd x, m13, x}, m1, m3
+    REPX  {paddd x, m13   }, m0, m2, m4, m5, m6, m7
+    REPX  {psrad x, 12    }, m0, m4, m1, m5, m2, m6, m3, m7
+    psubd                m8, m0, m4 ; t8a  t10a
+    paddd                m0, m4     ; t0a  t2a
+    psubd                m4, m1, m5 ; t9a  t11a
+    paddd                m1, m5     ; t1a  t3a
+    psubd                m5, m2, m6 ; t12a t14a
+    paddd                m2, m6     ; t4a  t6a
+    psubd                m6, m3, m7 ; t13a t15a
+    paddd                m3, m7     ; t5a  t7a
+    REPX    {pmaxsd x, m14}, m8, m4, m5, m6
+    REPX    {pminsd x, m15}, m8, m4, m5, m6
+    vbroadcasti32x4     m11, [o(pd_4017_2276)]
+    vbroadcasti32x4     m10, [o(pd_799_3406)]
+    ITX_MULSUB_2D         8, 4, 7, 9, _, 13, 10, 11
+    ITX_MULSUB_2D         6, 5, 7, 9, _, 13, 11, 10
+    REPX    {pmaxsd x, m14}, m0, m2, m1, m3
+    REPX    {pminsd x, m15}, m0, m2, m1, m3
+    psubd                m7, m0, m2 ; t4   t6
+    paddd                m0, m2     ; t0   t2
+    psubd                m2, m1, m3 ; t5   t7
+    paddd                m1, m3     ; t1   t3
+    psubd                m3, m4, m6 ; t12a t14a
+    paddd                m4, m6     ; t8a  t10a
+    psubd                m6, m8, m5 ; t13a t15a
+    paddd                m8, m5     ; t9a  t11a
+    REPX    {pmaxsd x, m14}, m7, m3, m2, m6
+    REPX    {pminsd x, m15}, m7, m3, m2, m6
+    punpcklqdq           m5, m3, m7 ; t12a t4
+    punpckhqdq           m3, m7     ; t14a t6
+    punpckhqdq           m7, m6, m2 ; t15a t7
+    punpcklqdq           m6, m2     ; t13a t5
+    vpbroadcastd        m11, [o(pd_1567)]
+    vpbroadcastd        m10, [o(pd_3784)]
+    ITX_MULSUB_2D         7, 3, 2, 9, 10, 13, 10, 11
+    ITX_MULSUB_2D         5, 6, 2, 9, 10, 13, 11, 10
+    REPX    {pmaxsd x, m14}, m0, m4, m1, m8
+    REPX    {pminsd x, m15}, m0, m4, m1, m8
+    punpckhqdq           m2, m4, m0 ; t10a t2
+    punpcklqdq           m4, m0     ; t8a  t0
+    punpckhqdq           m0, m8, m1 ; t11a t3
+    punpcklqdq           m8, m1     ; t9a  t1
+    paddd                m1, m6, m7 ;  out2  -out3
+    psubd                m6, m7     ; t14a t6
+    paddd                m7, m5, m3 ; -out13  out12
+    psubd                m5, m3     ; t15a t7
+    psubd                m3, m8, m0 ; t11  t3a
+    paddd                m8, m0     ;  out14 -out15
+    paddd                m0, m4, m2 ; -out1   out0
+    psubd                m4, m2     ; t10  t2a
+    REPX    {pmaxsd x, m14}, m6, m5, m3, m4
+    mov                 r6d, 0x3333
+    REPX    {pminsd x, m15}, m6, m5, m3, m4
+    kmovw                k1, r6d
+    REPX    {pmulld x, m12}, m6, m5, m3, m4
+    pxor                 m9, m9
+    REPX {vpsubd x{k1}, m9, x}, m0, m1, m7, m8
+    paddd                m6, m13
+    paddd                m4, m13
+    paddd                m2, m6, m5 ; -out5   out4
+    psubd                m6, m5     ;  out10 -out11
+    psubd                m5, m4, m3 ; -out9   out8
+    paddd                m3, m4     ;  out6  -out7
+    REPX     {psrad  x, 12}, m2, m3, m5, m6
+    REPX {vpsubd x{k1}, m9, x}, m2, m3, m5, m6
+    ret
+ALIGN function_align
+.main_pass2:
+    lea                  r5, [o_base_8bpc]
+    pshufd               m4, m0, q1032
+    pshufd               m5, m1, q1032
+    call m(iadst_16x8_internal_8bpc).main_pass2
+    movshdup            m11, [permC]
+    pmulhrsw             m0, m6
+    pmulhrsw             m1, m6
+    vpbroadcastd        m13, [pixel_10bpc_max]
+    pxor                m12, m12
+    lea                  r6, [strideq*3]
+    ret
+
+INV_TXFM_16X8_FN flipadst, dct
+INV_TXFM_16X8_FN flipadst, identity, -21
+INV_TXFM_16X8_FN flipadst, adst
+INV_TXFM_16X8_FN flipadst, flipadst
+
+cglobal iflipadst_16x8_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+    call m(iadst_16x8_internal_10bpc).main_pass1
+    vpbroadcastd         m9, [o(pd_1)]
+    psubd                m4, m9, m3
+    paddd                m3, m9, m5
+    paddd                m5, m9, m2
+    psubd                m2, m9, m6
+    psubd                m6, m9, m1
+    paddd                m1, m9, m7
+    paddd                m7, m9, m0
+    psubd                m0, m9, m8
+    jmp m(iadst_16x8_internal_10bpc).pass1_end
+.pass2:
+    call m(iadst_16x8_internal_10bpc).main_pass2
+    psrlq               m11, 8
+    vpermq               m8, m11, m3
+    vpermq               m9, m11, m2
+    call m(idct_16x8_internal_10bpc).write_16x4_noround
+    vpermq               m8, m11, m1
+    vpermq               m9, m11, m0
+    jmp m(idct_16x8_internal_10bpc).write_16x4_noround
+
+INV_TXFM_16X8_FN identity, dct
+INV_TXFM_16X8_FN identity, adst
+INV_TXFM_16X8_FN identity, flipadst
+INV_TXFM_16X8_FN identity, identity
+
+cglobal iidentity_16x8_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+    call m(idct_8x16_internal_10bpc).load2
+    vpbroadcastd         m8, [o(pd_5793)]
+    vpbroadcastd        m13, [o(pd_3072)]
+    pxor                m10, m10
+    REPX     {pmulld x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX {mova [cq+64*x], m10}, 0, 1, 2, 3, 4, 5, 6, 7
+    call m(idct_8x16_internal_10bpc).round
+    psrlq                m8, [o(permA)], 16
+    psrlq                m9, m8, 8
+    mova                m10, m8
+    mova                m11, m9
+    call m(idct_16x8_internal_10bpc).transpose_16x8
+    jmp                tx2q
+.pass2:
+    movshdup             m4, [o(permC)]
+    vpbroadcastd        m11, [o(pw_4096)]
+    mova                 m5, m4
+    jmp m(idct_16x8_internal_10bpc).end
+
+%macro INV_TXFM_16X16_FN 2-3 0 ; type1, type2, eob_offset
+    INV_TXFM_FN          %1, %2, %3, 16x16
+%ifidn %1_%2, dct_dct
+    imul                r6d, [cq], 181
+    mov                [cq], eobd ; 0
+    or                  r3d, 16
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_16x8_10bpc).dconly2
+%endif
+%endmacro
+
+INV_TXFM_16X16_FN dct, dct
+INV_TXFM_16X16_FN dct, identity, 28
+INV_TXFM_16X16_FN dct, flipadst
+INV_TXFM_16X16_FN dct, adst
+
+cglobal idct_16x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    cmp                eobd, 36
+    jl .fast
+    mova                 m0, [cq+64* 0]
+    mova                 m1, [cq+64* 2]
+    mova                 m2, [cq+64* 4]
+    mova                 m3, [cq+64* 6]
+    mova                 m4, [cq+64* 8]
+    mova                 m5, [cq+64*10]
+    mova                 m6, [cq+64*12]
+    mova                 m7, [cq+64*14]
+%if WIN64
+    movaps        [cq+16*0], xmm6
+    movaps        [cq+16*1], xmm7
+%endif
+    call m(idct_8x16_internal_10bpc).main
+    mova                m16, [cq+64* 1]
+    mova                m17, [cq+64* 3]
+    mova                m18, [cq+64* 5]
+    mova                m19, [cq+64* 7]
+    mova                m20, [cq+64* 9]
+    mova                m21, [cq+64*11]
+    mova                m22, [cq+64*13]
+    mova                m23, [cq+64*15]
+    call .main
+    call .main_end
+.pass1_end:
+%if WIN64
+    movaps             xmm6, [cq+16*0]
+    movaps             xmm7, [cq+16*1]
+%endif
+    vzeroupper
+.pass1_end2:
+    call .main_end3
+.pass1_end3:
+    mov                 r6d, 64*12
+    pxor                 m8, m8
+.zero_loop:
+    mova       [cq+r6+64*3], m8
+    mova       [cq+r6+64*2], m8
+    mova       [cq+r6+64*1], m8
+    mova       [cq+r6+64*0], m8
+    sub                 r6d, 64*4
+    jge .zero_loop
+    jmp                tx2q
+.pass2:
+    lea                  r5, [o_base_8bpc]
+    call m(idct_16x16_internal_8bpc).main
+    movshdup            m12, [permC]
+    vpbroadcastd        m11, [pw_2048]
+    psrlq               m13, m12, 8
+    vpermq               m8, m12, m0
+    vpermq               m0, m13, m7
+    vpermq               m7, m13, m1
+    vpermq               m1, m12, m6
+    vpermq               m6, m12, m2
+    vpermq               m2, m13, m5
+    vpermq               m5, m13, m3
+    vpermq               m3, m12, m4
+.pass2_end:
+    lea                  r6, [strideq*3]
+    vpbroadcastd        m13, [pixel_10bpc_max]
+    pxor                m12, m12
+    pmulhrsw             m8, m11, m8
+    pmulhrsw             m9, m11, m7
+    call m(idct_16x8_internal_10bpc).write_16x4_noround
+    pmulhrsw             m8, m11, m6
+    pmulhrsw             m9, m11, m5
+    call m(idct_16x8_internal_10bpc).write_16x4_noround
+    pmulhrsw             m8, m11, m3
+    pmulhrsw             m9, m11, m2
+    call m(idct_16x8_internal_10bpc).write_16x4_noround
+    pmulhrsw             m8, m11, m1
+    pmulhrsw             m9, m11, m0
+    jmp m(idct_16x8_internal_10bpc).write_16x4_noround
+.fast:
+    mova                ym0, [cq+64*0]
+    mova                ym2, [cq+64*4]
+    movshdup             m8, [o(permB)]
+    mova                ym1, [cq+64*2]
+    mova                ym3, [cq+64*6]
+    mova                ym4, [cq+64*1]
+    mova                ym5, [cq+64*3]
+    mova                ym6, [cq+64*5]
+    mova                ym7, [cq+64*7]
+    vpermt2q             m0, m8, m2 ; 0 4
+    vpermt2q             m1, m8, m3 ; 2 6
+    vpermt2q             m4, m8, m5 ; 1 3
+    vpermt2q             m7, m8, m6 ; 7 5
+    call m(idct_8x8_internal_10bpc).main_fast
+    call m(idct_16x8_internal_10bpc).main_fast
+    vpbroadcastd        m11, [o(pd_2)]
+    call m(idct_8x16_internal_10bpc).main_end2
+    mova                 m8, [o(permA)]
+    psrlq                m9, m8, 8
+    jmp m(iadst_16x16_internal_10bpc).pass1_fast_end2
+ALIGN function_align
+.main_fast2_rect2:
+    REPX     {paddd x, m13}, m16, m17
+    REPX     {psrad x, 12 }, m16, m17
+.main_fast2:
+    pmulld              m22, m16, [o(pd_4076)] {1to16} ; t15a
+    pmulld               m9, m16, [o(pd_401)] {1to16}  ; t8a
+    pmulld              m18, m17, [o(pd_1189)] {1to16} ; t11a
+    pmulld              m17, [o(pd_3920)] {1to16}      ; t12a
+    psubd               m18, m13, m18
+    REPX    {paddd  x, m13}, m22, m9, m17
+    REPX    {psrad  x, 12 }, m18, m22, m9, m17
+
+    mova                m20, m9
+    mova                m16, m18
+    mova                m23, m22
+    mova                m19, m17
+    jmp .main3
+.main_fast_rect2:
+    REPX     {paddd x, m13}, m16, m17, m18, m19
+    REPX     {psrad x, 12 }, m16, m17, m18, m19
+.main_fast:
+    pmulld              m23, m16, [o(pd_4076)] {1to16} ; t15a
+    pmulld              m16, [o(pd_401)] {1to16}       ; t8a
+    pmulld              m20, m19, [o(pd_2598)] {1to16} ; t9a
+    pmulld              m19, [o(pd_3166)] {1to16}      ; t14a
+    pmulld              m22, m17, [o(pd_1189)] {1to16} ; t11a
+    pmulld              m17, [o(pd_3920)] {1to16}      ; t12a
+    pmulld              m21, m18, [o(pd_3612)] {1to16} ; t13a
+    pmulld              m18, [o(pd_1931)] {1to16}      ; t10a
+    psubd               m20, m13, m20
+    psubd               m22, m13, m22
+    call .round2
+    jmp .main2
+.main_rect2:
+    call .round
+.main:
+    ITX_MULSUB_2D        16, 23, 7, 9, 10, _,  401, 4076 ; t8a,  t15a
+    ITX_MULSUB_2D        20, 19, 7, 9, 10, _, 3166, 2598 ; t9a,  t14a
+    ITX_MULSUB_2D        22, 17, 7, 9, 10, _, 3920, 1189 ; t11a, t12a
+    ITX_MULSUB_2D        18, 21, 7, 9, 10, _, 1931, 3612 ; t10a, t13a
+    call .round
+.main2:
+    paddd                m9, m20, m16 ; t8
+    psubd               m20, m16, m20 ; t9
+    psubd               m16, m22, m18 ; t10
+    paddd               m18, m22      ; t11
+    paddd               m22, m23, m19 ; t15
+    psubd               m23, m19      ; t14
+    psubd               m19, m17, m21 ; t13
+    paddd               m17, m21      ; t12
+    REPX    {pmaxsd x, m14}, m20, m23, m16, m19
+    REPX    {pminsd x, m15}, m20, m23, m16, m19
+    REPX    {pmaxsd x, m14}, m9, m18, m22, m17
+    REPX    {pminsd x, m15}, m9, m18, m22, m17
+.main3:
+    vpbroadcastd        m11, [o(pd_3784)]
+    vpbroadcastd        m10, [o(pd_1567)]
+    ITX_MULSUB_2D        23, 20, 21, 7, _, 13, 10, 11
+    ITX_MULSUB_2D        19, 16, 21, 7, _, 13, 10, 11, 2
+    paddd               m21, m20, m19 ; t14
+    psubd               m20, m19      ; t13
+    psubd               m19, m9, m18  ; t11a
+    paddd                m9, m18      ; t8a
+    psubd               m18, m23, m16 ; t10
+    paddd               m16, m23      ; t9
+    psubd               m23, m22, m17 ; t12a
+    paddd               m22, m17      ; t15a
+    REPX    {pmaxsd x, m14}, m20, m23, m18, m19
+    REPX    {pminsd x, m15}, m20, m23, m18, m19
+    REPX    {pmulld x, m12}, m20, m23, m18, m19
+    psubd                m7, m0, m6   ; dct8 out7
+    paddd                m0, m6       ; dct8 out0
+    psubd                m6, m1, m5   ; dct8 out6
+    paddd                m1, m5       ; dct8 out1
+    REPX    {pmaxsd x, m14}, m7, m0, m6, m1
+    psubd                m5, m2, m4   ; dct8 out5
+    paddd                m2, m4       ; dct8 out2
+    REPX    {pminsd x, m15}, m7, m0, m6, m1
+    psubd                m4, m3, m8   ; dct8 out4
+    paddd                m3, m8       ; dct8 out3
+    REPX    {pmaxsd x, m14}, m5, m2, m4, m3
+    paddd               m20, m13
+    paddd               m23, m13
+    REPX    {pminsd x, m15}, m5, m2, m4, m3
+    psubd               m17, m20, m18 ; t10a
+    paddd               m20, m18      ; t13a
+    REPX    {pmaxsd x, m14}, m22, m21, m16, m9
+    psubd               m18, m23, m19 ; t11
+    paddd               m19, m23      ; t12
+    REPX    {pminsd x, m15}, m22, m21, m16, m9
+    REPX    {psrad  x, 12 }, m20, m19, m18, m17
+    ret
+.main_end:
+    vpbroadcastd        m11, [o(pd_2)]
+.main_end2:
+    REPX    {paddd  x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    psubd               m23, m0, m22 ; out15
+    paddd                m0, m22     ; out0
+    psubd               m22, m1, m21 ; out14
+    paddd                m1, m21     ; out1
+    psubd               m21, m2, m20 ; out13
+    paddd                m2, m20     ; out2
+    psubd               m20, m3, m19 ; out12
+    paddd                m3, m19     ; out3
+    psubd               m19, m4, m18 ; out11
+    paddd                m4, m18     ; out4
+    psubd               m18, m5, m17 ; out10
+    paddd                m5, m17     ; out5
+    psubd               m17, m6, m16 ; out9
+    paddd                m6, m16     ; out6
+    psubd               m16, m7, m9  ; out8
+    paddd                m7, m9      ; out7
+    REPX   {vpsravd x, m11}, m0, m16, m1, m17, m2, m18, m3, m19, \
+                             m4, m20, m5, m21, m6, m22, m7, m23
+    packssdw             m0, m16
+    packssdw             m1, m17
+    packssdw             m2, m18
+    packssdw             m3, m19
+    packssdw             m4, m20
+    packssdw             m5, m21
+    packssdw             m6, m22
+    packssdw             m7, m23
+    ret
+.main_end3:
+    punpckhwd            m8, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m4, m5
+    punpcklwd            m4, m5
+    punpcklwd            m5, m6, m7
+    punpckhwd            m6, m7
+    punpckhdq            m7, m0, m2
+    punpckldq            m0, m2
+    punpckhdq            m2, m8, m1
+    punpckldq            m8, m1
+    punpckhdq            m1, m4, m5
+    punpckldq            m4, m5
+    punpckhdq            m5, m3, m6
+    punpckldq            m3, m6
+    vshufi32x4           m6, m0, m4, q3232
+    vinserti32x8         m0, ym4, 1
+    vinserti32x8         m4, m8, ym3, 1
+    vshufi32x4           m8, m3, q3232
+    vinserti32x8         m3, m7, ym1, 1
+    vshufi32x4           m7, m1, q3232
+    vshufi32x4           m1, m2, m5, q3232
+    vinserti32x8         m2, ym5, 1
+    vshufi32x4           m5, m7, m1, q2020 ; 10 11
+    vshufi32x4           m7, m1, q3131     ; 14 15
+    vshufi32x4           m1, m3, m2, q2020 ;  2  3
+    vshufi32x4           m3, m2, q3131     ;  6  7
+    vshufi32x4           m2, m0, m4, q3131 ;  4  5
+    vshufi32x4           m0, m4, q2020     ;  0  1
+    vshufi32x4           m4, m6, m8, q2020 ;  8  9
+    vshufi32x4           m6, m8, q3131     ; 12 13
+    ret
+ALIGN function_align
+.round:
+    paddd               m20, m13
+    paddd               m22, m13
+.round2:
+    paddd               m16, m13
+    paddd               m18, m13
+.round3:
+    REPX     {psrad x, 12 }, m16, m18, m20, m22
+    REPX     {paddd x, m13}, m17, m19, m21, m23
+    REPX     {psrad x, 12 }, m17, m19, m21, m23
+    ret
+
+INV_TXFM_16X16_FN adst, dct
+INV_TXFM_16X16_FN adst, flipadst
+INV_TXFM_16X16_FN adst, adst
+
+cglobal iadst_16x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    cmp                eobd, 36
+    jl .fast
+    call .main_pass1
+    packssdw             m0, m16
+    packssdw             m1, m17
+    packssdw             m2, m18
+    packssdw             m3, m19
+    packssdw             m4, m5, m20
+    packssdw             m5, m6, m21
+    packssdw             m6, m7, m22
+    packssdw             m7, m8, m23
+    jmp m(idct_16x16_internal_10bpc).pass1_end
+.fast:
+    call .main_pass1_fast
+    vpbroadcastd         m9, [o(pd_2)]
+    paddd                m0, m9
+    psubd                m1, m9, m1
+    paddd                m2, m9
+    psubd                m3, m9, m3
+    paddd                m4, m9, m5
+    psubd                m5, m9, m6
+    paddd                m6, m9, m7
+    psubd                m7, m9, m8
+.pass1_fast_end:
+    mova                 m9, [o(permA)]
+    psrlq                m8, m9, 8
+    REPX       {psrad x, 2}, m0, m1, m2, m3, m4, m5, m6, m7
+.pass1_fast_end2:
+    mova                m10, m9
+    mova                m11, m8
+    call m(idct_16x8_internal_10bpc).transpose_16x8
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    REPX {mova [cq+64*x], ym4}, 0, 1, 2, 3, 4, 5, 6, 7
+    jmp                tx2q
+.pass2:
+    lea                  r5, [o_base_8bpc]
+    call m(iadst_16x16_internal_8bpc).main_pass2b
+    movshdup            m12, [permC]
+    mova                m11, [pw_2048_m2048]
+    psrlq               m13, m12, 8
+    vpermq               m8, m13, m0
+    vpermq               m0, m12, m7
+    vpermq               m7, m13, m1
+    vpermq               m1, m12, m6
+    vpermq               m6, m13, m2
+    vpermq               m2, m12, m5
+    vpermq               m5, m13, m3
+    vpermq               m3, m12, m4
+    jmp m(idct_16x16_internal_10bpc).pass2_end
+ALIGN function_align
+.main_pass1:
+    mova                 m0, [cq+64* 0]
+%if WIN64
+    movaps        [cq+16*0], xmm6
+    movaps        [cq+16*1], xmm7
+%endif
+    mova                m23, [cq+64*15]
+    vpbroadcastd        m13, [o(pd_2048)]
+    ITX_MULSUB_2D        23,  0, 8, 9, 10, 13,  201, 4091 ; t1  t0
+    mova                 m7, [cq+64* 7]
+    mova                m16, [cq+64* 8]
+    ITX_MULSUB_2D         7, 16, 8, 9, 10, 13, 3035, 2751 ; t9  t8
+    mova                 m2, [cq+64* 2]
+    mova                m21, [cq+64*13]
+    ITX_MULSUB_2D        21,  2, 8, 9, 10, 13,  995, 3973 ; t3  t2
+    mova                 m5, [cq+64* 5]
+    mova                m18, [cq+64*10]
+    ITX_MULSUB_2D         5, 18, 8, 9, 10, 13, 3513, 2106 ; t11 t10
+    mova                 m4, [cq+64* 4]
+    mova                m19, [cq+64*11]
+    ITX_MULSUB_2D        19,  4, 8, 9, 10, 13, 1751, 3703 ; t5  t4
+    mova                 m3, [cq+64* 3]
+    mova                m20, [cq+64*12]
+    ITX_MULSUB_2D         3, 20, 8, 9, 10, 13, 3857, 1380 ; t13 t12
+    mova                 m6, [cq+64* 6]
+    mova                m17, [cq+64* 9]
+    ITX_MULSUB_2D        17,  6, 8, 9, 10, 13, 2440, 3290 ; t7  t6
+    mova                 m1, [cq+64* 1]
+    mova                m22, [cq+64*14]
+    ITX_MULSUB_2D         1, 22, 8, 9, 10, 13, 4052,  601 ; t15 t14
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    psubd                m9, m23, m7  ; t9a
+    paddd               m23, m7       ; t1a
+    psubd                m7, m2, m18  ; t10a
+    paddd               m18, m2       ; t2a
+    REPX    {pmaxsd x, m14}, m9, m23, m7, m18
+    psubd                m2, m17, m1  ; t15a
+    paddd               m17, m1       ; t7a
+    REPX    {pminsd x, m15}, m9, m23, m7, m18
+    psubd                m1, m21, m5  ; t11a
+    paddd               m21, m5       ; t3a
+    REPX    {pmaxsd x, m14}, m2, m17, m1, m21
+    psubd                m5, m4, m20  ; t12a
+    paddd                m4, m20      ; t4a
+    REPX    {pminsd x, m15}, m2, m17, m1, m21
+    psubd               m20, m19, m3  ; t13a
+    paddd               m19, m3       ; t5a
+    REPX    {pmaxsd x, m14}, m5, m4, m20, m19
+    psubd                m8, m6, m22  ; t14a
+    paddd                m6, m22      ; t6a
+    REPX    {pminsd x, m15}, m5, m4, m20, m19
+    psubd               m22, m0, m16  ; t8a
+    paddd               m16, m0       ; t0a
+    REPX    {pmaxsd x, m14}, m8, m6, m22, m16
+    vpbroadcastd        m11, [o(pd_4017)]
+    vpbroadcastd        m10, [o(pd_799)]
+    REPX    {pminsd x, m15}, m8, m6, m22, m16
+    ITX_MULSUB_2D        22,  9, 0, 3, _, 13, 10, 11 ; t9  t8
+    ITX_MULSUB_2D        20,  5, 0, 3, _, 13, 11, 10 ; t12 t13
+    vpbroadcastd        m11, [o(pd_2276)]
+    vpbroadcastd        m10, [o(pd_3406)]
+    ITX_MULSUB_2D         7,  1, 0, 3, _, 13, 10, 11 ; t11 t10
+    ITX_MULSUB_2D         2,  8, 0, 3, _, 13, 11, 10 ; t14 t15
+    paddd                m0, m16, m4  ; t0
+    psubd               m16, m4       ; t4
+    psubd                m3, m23, m19 ; t5
+    paddd               m23, m19      ; t1
+    REPX    {pmaxsd x, m14}, m0, m16, m3, m23
+    psubd               m19, m18, m6  ; t6
+    paddd               m18, m6       ; t2
+    REPX    {pminsd x, m15}, m0, m16, m3, m23
+    psubd                m6, m21, m17 ; t7
+    paddd               m21, m17      ; t3
+    REPX    {pmaxsd x, m14}, m19, m18, m6, m21
+    paddd               m17, m9, m20  ; t8a
+    psubd                m9, m20      ; t12a
+    REPX    {pminsd x, m15}, m19, m18, m6, m21
+    psubd               m20, m22, m5  ; t13a
+    paddd               m22, m5       ; t9a
+    REPX    {pmaxsd x, m14}, m17, m9, m20, m22
+    psubd                m5, m1, m2   ; t14a
+    paddd                m1, m2       ; t10a
+    REPX    {pminsd x, m15}, m17, m9, m20, m22
+    psubd                m2, m7, m8   ; t15a
+    paddd                m7, m8       ; t11a
+    REPX    {pmaxsd x, m14}, m5, m1, m2, m7
+    vpbroadcastd        m11, [o(pd_3784)]
+    vpbroadcastd        m10, [o(pd_1567)]
+    REPX    {pminsd x, m15}, m5, m1, m2, m7
+    ITX_MULSUB_2D        16,  3, 4, 8, _, 13, 10, 11 ; t5a t4a
+    ITX_MULSUB_2D         6, 19, 4, 8, _, 13, 11, 10 ; t6a t7a
+    ITX_MULSUB_2D         9, 20, 4, 8, _, 13, 10, 11 ; t13 t12
+    ITX_MULSUB_2D         2,  5, 4, 8, _, 13, 11, 10 ; t14 t15
+    psubd                m8, m0, m18  ; t2a
+    paddd                m0, m18      ;  out0
+    psubd               m18, m23, m21 ; t3a
+    paddd               m23, m21      ; -out15
+    paddd               m21, m9, m5   ; -out13
+    psubd                m9, m5       ; t15a
+    psubd                m5, m3, m6   ; t6
+    paddd                m3, m6       ; -out3
+    REPX    {pmaxsd x, m14}, m8, m18, m9, m5
+    psubd                m6, m20, m2  ; t14a
+    paddd                m2, m20      ;  out2
+    paddd               m20, m16, m19 ;  out12
+    psubd               m16, m19      ; t7
+    REPX    {pminsd x, m15}, m8, m18, m9, m5
+    psubd               m19, m22, m7  ; t11
+    paddd               m22, m7       ;  out14
+    psubd                m7, m17, m1  ; t10
+    paddd                m1, m17      ; -out1
+    REPX    {pmaxsd x, m14}, m6, m16, m19, m7
+    vpbroadcastd        m12, [o(pd_1448)]
+    vpbroadcastd         m4, [o(pd_2)]
+    vpbroadcastd        m10, [o(pd_5120)]
+    vpbroadcastd        m11, [o(pd_5119)]
+    REPX    {pminsd x, m15}, m6, m16, m19, m7
+    psubd               m17, m7, m19  ; -out9
+    paddd                m7, m19      ;  out6
+    psubd               m19, m5, m16  ; -out11
+    paddd                m5, m16      ;  out4
+    REPX    {pmulld x, m12}, m17, m7, m19, m5
+    psubd               m16, m8, m18  ;  out8
+    paddd                m8, m18      ; -out7
+    psubd               m18, m6, m9   ;  out10
+    paddd                m6, m9       ; -out5
+    REPX    {pmulld x, m12}, m16, m8, m18, m6
+    REPX  {paddd x, m4    }, m0, m2, m20, m22
+    REPX  {psubd x, m4,  x}, m1, m3, m21, m23
+    REPX  {paddd x, m10   }, m7, m5, m16, m18
+    REPX  {psubd x, m11, x}, m17, m19, m8, m6
+    REPX      {psrad x, 2 }, m20, m22, m0, m2, m21, m23, m1, m3
+    REPX      {psrad x, 13}, m17, m19, m5, m7, m16, m18, m6, m8
+    ret
+ALIGN function_align
+.main_pass1_fast:
+    mova                ym0, [cq+64*0]
+    mova                ym1, [cq+64*2]
+    movshdup             m8, [o(permB)]
+    mova                ym6, [cq+64*1]
+    mova                ym7, [cq+64*3]
+    mova                ym2, [cq+64*4]
+    mova                ym3, [cq+64*6]
+    mova                ym4, [cq+64*5]
+    mova                ym5, [cq+64*7]
+    vpermt2q             m0, m8, m1 ; 0 2
+    vpermt2q             m7, m8, m6 ; 3 1
+    vpermt2q             m2, m8, m3 ; 4 6
+    vpermt2q             m5, m8, m4 ; 7 5
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m12, [o(pd_2896)]
+    jmp m(iadst_16x8_internal_10bpc).main_fast
+
+INV_TXFM_16X16_FN flipadst, dct
+INV_TXFM_16X16_FN flipadst, adst
+INV_TXFM_16X16_FN flipadst, flipadst
+
+cglobal iflipadst_16x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    cmp                eobd, 36
+    jl .fast
+    call m(iadst_16x16_internal_10bpc).main_pass1
+    packssdw             m4, m19, m3
+    packssdw             m3, m20, m5
+    packssdw             m5, m18, m2
+    packssdw             m2, m21, m6
+    packssdw             m6, m17, m1
+    packssdw             m1, m22, m7
+    packssdw             m7, m16, m0
+    packssdw             m0, m23, m8
+    jmp m(idct_16x16_internal_10bpc).pass1_end
+.fast:
+    call m(iadst_16x16_internal_10bpc).main_pass1_fast
+    vpbroadcastd         m9, [o(pd_2)]
+    psubd                m4, m9, m3
+    paddd                m3, m9, m5
+    paddd                m5, m9, m2
+    psubd                m2, m9, m6
+    psubd                m6, m9, m1
+    paddd                m1, m9, m7
+    paddd                m7, m9, m0
+    psubd                m0, m9, m8
+    jmp m(iadst_16x16_internal_10bpc).pass1_fast_end
+.pass2:
+    lea                  r5, [o_base_8bpc]
+    call m(iadst_16x16_internal_8bpc).main_pass2b
+    movshdup            m12, [permC]
+    movu                m11, [pw_m2048_2048]
+    psrlq               m13, m12, 8
+    vpermq               m8, m13, m7
+    vpermq               m7, m13, m6
+    vpermq               m6, m13, m5
+    vpermq               m5, m13, m4
+    vpermq               m3, m12, m3
+    vpermq               m2, m12, m2
+    vpermq               m1, m12, m1
+    vpermq               m0, m12, m0
+    jmp m(idct_16x16_internal_10bpc).pass2_end
+
+INV_TXFM_16X16_FN identity, dct, -92
+INV_TXFM_16X16_FN identity, identity
+
+cglobal iidentity_16x16_internal_10bpc, 0, 7, 16, dst, stride, c, eob, tx2
+%undef cmp
+    vpbroadcastd        m10, [o(pd_5793)]
+    vpbroadcastd        m11, [o(pd_5120)]
+    mov                  r6, cq
+    cmp                eobd, 36
+    jl .fast
+    call .pass1_main
+    packssdw             m0, m6, m8
+    packssdw             m1, m7, m9
+    call .pass1_main
+    packssdw             m2, m6, m8
+    packssdw             m3, m7, m9
+    call .pass1_main
+    packssdw             m4, m6, m8
+    packssdw             m5, m7, m9
+    call .pass1_main
+    packssdw             m6, m8
+    packssdw             m7, m9
+    jmp m(idct_16x16_internal_10bpc).pass1_end2
+.fast:
+    call .pass1_main_fast
+    packssdw             m0, m6, m7
+    call .pass1_main_fast
+    packssdw             m1, m6, m7
+    call .pass1_main_fast
+    packssdw             m2, m6, m7
+    call .pass1_main_fast
+    packssdw             m3, m6, m7
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckldq            m3, m4, m1
+    punpckhdq            m4, m1
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    pxor                 m7, m7
+    vshufi32x4           m2, m0, m3, q3131
+    vshufi32x4           m0, m3, q2020
+    vshufi32x4           m3, m1, m4, q3131
+    vshufi32x4           m1, m4, q2020
+    REPX       {mova x, m7}, m4, m5, m6
+    jmp m(idct_16x16_internal_10bpc).pass1_end3
+.pass2:
+    movshdup            m14, [o(permC)]
+    vpbroadcastd        m15, [o(pw_1697x16)]
+    lea                  r6, [strideq*3]
+    vpbroadcastd        m11, [o(pw_2048)]
+    pxor                m12, m12
+    vpbroadcastd        m13, [pixel_10bpc_max]
+    vpermq               m8, m14, m0
+    vpermq               m9, m14, m1
+    call .pass2_main
+    vpermq               m8, m14, m2
+    vpermq               m9, m14, m3
+    call .pass2_main
+    vpermq               m8, m14, m4
+    vpermq               m9, m14, m5
+    call .pass2_main
+    vpermq               m8, m14, m6
+    vpermq               m9, m14, m7
+.pass2_main:
+    pmulhrsw             m0, m15, m8
+    pmulhrsw             m1, m15, m9
+    paddsw               m8, m8
+    paddsw               m9, m9
+    paddsw               m8, m0
+    paddsw               m9, m1
+    jmp m(idct_16x8_internal_10bpc).write_16x4
+ALIGN function_align
+.pass1_main:
+    pmulld               m6, m10, [r6+64*0]
+    pmulld               m7, m10, [r6+64*1]
+    pmulld               m8, m10, [r6+64*8]
+    pmulld               m9, m10, [r6+64*9]
+    add                  r6, 64*2
+    REPX    {paddd  x, m11}, m6, m7, m8, m9
+    REPX    {psrad  x, 13 }, m6, m8, m7, m9
+    ret
+ALIGN function_align
+.pass1_main_fast:
+    mova                ym6, [r6+64* 0]
+    vinserti32x8         m6, [r6+64* 4], 1
+    mova                ym7, [r6+64* 8]
+    vinserti32x8         m7, [r6+64*12], 1
+    add                  r6, 64
+    REPX    {pmulld x, m10}, m6, m7
+    REPX    {paddd  x, m11}, m6, m7
+    REPX    {psrad  x, 13 }, m6, m7
+    ret
+
+cglobal inv_txfm_add_dct_dct_8x32_10bpc, 4, 7, 22, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    vpbroadcastd        m11, [o(pd_2)]
+    mova                m20, [o(idct8x32p)]
+    pxor                m21, m21
+    cmp                eobd, 43
+    jl .fast
+    call .pass1_main
+    punpcklwd           m16, m0, m1
+    punpcklwd           m17, m2, m3
+    punpckhwd           m18, m0, m1
+    punpckhwd           m19, m2, m3
+    cmp                eobd, 107
+    jge .full
+    punpckldq            m0, m16, m17 ;  0  2
+    punpckhdq            m1, m16, m17 ;  4  6
+    punpckldq            m2, m18, m19 ;  8 10
+    punpckhdq            m3, m18, m19 ; 12 14
+    lea                  r5, [o_base_8bpc]
+    vextracti32x8      ym14, m0, 1
+    vextracti32x8      ym15, m1, 1
+    vextracti32x8      ym16, m2, 1
+    vextracti32x8      ym17, m3, 1
+    call m(idct_8x16_internal_8bpc).main_fast
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main_fast
+    jmp .end
+.full:
+    add                  cq, 64
+    call .pass1_main
+    punpcklwd            m5, m0, m1
+    punpcklwd            m6, m2, m3
+    punpckhwd            m7, m0, m1
+    punpckhwd            m8, m2, m3
+    punpckldq            m0, m16, m17 ;  0  2
+    punpckhdq            m1, m16, m17 ;  4  6
+    punpckldq            m2, m18, m19 ;  8 10
+    punpckhdq            m3, m18, m19 ; 12 14
+    punpckldq            m4, m5, m6   ; 16 18
+    punpckhdq            m5, m6       ; 20 22
+    punpckldq            m6, m7, m8   ; 24 26
+    punpckhdq            m7, m8       ; 28 30
+    lea                  r5, [o_base_8bpc]
+    vextracti32x8      ym14, m0, 1
+    vextracti32x8      ym15, m1, 1
+    vextracti32x8      ym16, m2, 1
+    vextracti32x8      ym17, m3, 1
+    vextracti32x8      ym18, m4, 1
+    vextracti32x8      ym19, m5, 1
+    vextracti32x8      ym20, m6, 1
+    vextracti32x8      ym21, m7, 1
+    call m(idct_8x16_internal_8bpc).main
+    REPX {pshufd x, x, q1032}, ym18, ym19, ym20, ym21
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main
+    jmp .end
+.fast:
+    movshdup             m8, [o(permB)]
+    mova                ym1, [cq+128*1]
+    mova                ym5, [cq+128*5]
+    mova                ym7, [cq+128*3]
+    mova                ym3, [cq+128*7]
+    mova                ym0, [cq+128*0]
+    mova                ym4, [cq+128*2]
+    mova                ym2, [cq+128*4]
+    mova                ym6, [cq+128*6]
+    vpermt2q             m1, m8, m5 ; 1 5
+    vpermt2q             m3, m8, m7 ; 7 3
+    vpermt2q             m0, m8, m4 ; 0 2
+    vpermt2q             m2, m8, m6 ; 4 6
+    mova         [cq+128*0], ym21
+    REPX {vmovdqa32 [cq+128*x], ym21}, 1, 2, 3, 4, 5, 6, 7
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_8x8_internal_10bpc).main_end
+    packssdw             m0, m2
+    packssdw             m1, m3
+    vpermb               m0, m20, m0
+    vprold              m20, 16
+    vpermb               m2, m20, m1
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    lea                  r5, [o_base_8bpc]
+    vextracti32x8      ym14, m0, 1
+    vextracti32x8      ym15, m1, 1
+    call m(idct_8x16_internal_8bpc).main_fast2
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main_fast2
+.end:
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main_end ; performs vzeroupper
+    lea                  r3, [strideq*2]
+    vpbroadcastd        m12, [pixel_10bpc_max]
+    lea                  r6, [strideq*3]
+    pxor                m11, m11
+    lea                  r3, [dstq+r3*8]
+    pmulhrsw             m0, m10
+    pmulhrsw             m1, m10
+    call .write_8x4x2
+    pmulhrsw             m0, m10, m2
+    pmulhrsw             m1, m10, m3
+    call .write_8x4x2
+    pmulhrsw             m0, m10, m4
+    pmulhrsw             m1, m10, m5
+    call .write_8x4x2
+    pmulhrsw             m0, m10, m6
+    pmulhrsw             m1, m10, m7
+.write_8x4x2:
+    mova                xm8, [dstq+strideq*0]
+    vinserti32x4        ym8, [dstq+strideq*1], 1
+    vinserti32x4         m8, [dstq+strideq*2], 2
+    vinserti32x4         m8, [dstq+r6       ], 3
+    mova                xm9, [r3  +r6       ]
+    vinserti32x4        ym9, [r3  +strideq*2], 1
+    vinserti32x4         m9, [r3  +strideq*1], 2
+    vinserti32x4         m9, [r3  +strideq*0], 3
+    paddw                m8, m0
+    paddw                m9, m1
+    pmaxsw               m8, m11
+    pmaxsw               m9, m11
+    pminsw               m8, m12
+    pminsw               m9, m12
+    mova          [dstq+strideq*0], xm8
+    vextracti32x4 [dstq+strideq*1], ym8, 1
+    vextracti32x4 [dstq+strideq*2], m8, 2
+    vextracti32x4 [dstq+r6       ], m8, 3
+    lea                dstq, [dstq+strideq*4]
+    vextracti32x4 [r3  +strideq*0], m9, 3
+    vextracti32x4 [r3  +strideq*1], m9, 2
+    vextracti32x4 [r3  +strideq*2], ym9, 1
+    mova          [r3  +r6       ], xm9
+    lea                  r3, [r3+strideq*4]
+    ret
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 32
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_8x8_10bpc).dconly2
+ALIGN function_align
+.pass1_main:
+    mova                 m0, [cq+128*0]
+    mova                 m1, [cq+128*1]
+    mova                 m2, [cq+128*2]
+    mova                 m3, [cq+128*3]
+    mova                 m4, [cq+128*4]
+    mova                 m5, [cq+128*5]
+    mova                 m6, [cq+128*6]
+    mova                 m7, [cq+128*7]
+    REPX {mova [cq+128*x], m21}, 0, 1, 2, 3, 4, 5, 6, 7
+    call m(idct_8x16_internal_10bpc).main
+    call m(idct_8x16_internal_10bpc).main_end2
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    REPX {vpermb x, m20, x}, m0, m1, m2, m3
+    ret
+
+cglobal inv_txfm_add_identity_identity_8x32_10bpc, 4, 8, 12, dst, stride, c, eob
+    vpbroadcastd         m9, [pw_5]
+    lea                  r4, [strideq*3]
+    pxor                m10, m10
+    lea                  r5, [strideq*5]
+    vpbroadcastd        m11, [pixel_10bpc_max]
+    sub                eobd, 107
+    lea                  r6, [strideq+r4*2]
+.loop:
+    mova                 m0, [cq+128*0]
+    packssdw             m0, [cq+128*1]
+    mova                 m1, [cq+128*2]
+    packssdw             m1, [cq+128*3]
+    mova                 m2, [cq+128*4]
+    packssdw             m2, [cq+128*5]
+    mova                 m3, [cq+128*6]
+    packssdw             m3, [cq+128*7]
+    lea                  r7, [dstq+strideq*8]
+    REPX {mova [cq+128*x], m10}, 0, 1, 2, 3
+    REPX     {paddsw x, m9}, m0, m1, m2, m3
+    REPX {mova [cq+128*x], m10}, 4, 5, 6, 7
+    REPX     {psraw  x, 3 }, m0, m1, m2, m3
+    add                  cq, 64
+    mova                xm4, [dstq+strideq*0]
+    mova                xm5, [dstq+strideq*1]
+    mova                xm6, [dstq+strideq*2]
+    mova                xm7, [dstq+r4     *1]
+    punpckhwd            m8, m0, m1
+    vinserti32x4        ym4, [dstq+strideq*4], 1
+    punpcklwd            m0, m1
+    vinserti32x4        ym5, [dstq+r5     *1], 1
+    punpckhwd            m1, m2, m3
+    vinserti32x4        ym6, [dstq+r4     *2], 1
+    punpcklwd            m2, m3
+    vinserti32x4        ym7, [dstq+r6     *1], 1
+    punpckhwd            m3, m0, m8
+    vinserti32x4         m4, [r7  +strideq*0], 2
+    punpcklwd            m0, m8
+    vinserti32x4         m5, [r7  +strideq*1], 2
+    punpckhwd            m8, m2, m1
+    vinserti32x4         m6, [r7  +strideq*2], 2
+    punpcklwd            m2, m1
+    vinserti32x4         m7, [r7  +r4     *1], 2
+    punpckhqdq           m1, m0, m2
+    vinserti32x4         m4, [r7  +strideq*4], 3
+    punpcklqdq           m0, m2
+    vinserti32x4         m5, [r7  +r5     *1], 3
+    punpcklqdq           m2, m3, m8
+    vinserti32x4         m6, [r7  +r4     *2], 3
+    punpckhqdq           m3, m8
+    vinserti32x4         m7, [r7  +r6     *1], 3
+    paddw                m0, m4
+    paddw                m1, m5
+    paddw                m2, m6
+    paddw                m3, m7
+    REPX    {pmaxsw x, m10}, m0, m1, m2, m3
+    REPX    {pminsw x, m11}, m0, m1, m2, m3
+    mova          [dstq+strideq*0], xm0
+    mova          [dstq+strideq*1], xm1
+    mova          [dstq+strideq*2], xm2
+    mova          [dstq+r4     *1], xm3
+    vextracti32x4 [dstq+strideq*4], ym0, 1
+    vextracti32x4 [dstq+r5     *1], ym1, 1
+    vextracti32x4 [dstq+r4     *2], ym2, 1
+    vextracti32x4 [dstq+r6     *1], ym3, 1
+    lea                dstq, [r7+strideq*8]
+    vextracti32x4 [r7  +strideq*0], m0, 2
+    vextracti32x4 [r7  +strideq*1], m1, 2
+    vextracti32x4 [r7  +strideq*2], m2, 2
+    vextracti32x4 [r7  +r4     *1], m3, 2
+    vextracti32x4 [r7  +strideq*4], m0, 3
+    vextracti32x4 [r7  +r5     *1], m1, 3
+    vextracti32x4 [r7  +r4     *2], m2, 3
+    vextracti32x4 [r7  +r6     *1], m3, 3
+    add                eobd, 0x80000000
+    jnc .loop
+    RET
+
+cglobal inv_txfm_add_dct_dct_32x8_10bpc, 4, 7, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    mova                m11, [o(permB)]
+    mova                 m0, [cq+64* 0] ;  0  1
+    mova                 m4, [cq+64* 1] ;  2  3
+    mova                 m1, [cq+64* 2] ;  4  5
+    mova                 m8, [cq+64* 3] ;  6  7
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    psrlq               m10, m11, 32
+%if WIN64
+    movaps        [cq+16*0], xmm6
+    movaps        [cq+16*1], xmm7
+%endif
+    mova                m16, m11
+    vpermi2q            m16, m0, m1     ;  1  5
+    mova                m17, m11
+    vpermi2q            m17, m8, m4     ;  7  3
+    cmp                eobd, 43
+    jl .fast
+    mova                m18, [cq+64* 4] ;  8  9
+    mova                m20, [cq+64* 5] ; 10 11
+    mova                 m6, [cq+64* 6] ; 12 13
+    mova                 m7, [cq+64* 7] ; 14 15
+    vpermt2q             m0, m10, m18   ;  0  8
+    vpermt2q            m18, m11, m6    ;  9 13
+    mova                m19, m11
+    vpermi2q            m19, m7, m20    ; 15 11
+    cmp                eobd, 107
+    jge .full
+    vpermt2q             m1, m10, m6    ;  4 12
+    vpermt2q             m4, m10, m8    ;  2  6
+    vpermt2q             m7, m10, m20   ; 14 10
+    mov                 r6d, 64*1
+    call m(idct_8x8_internal_10bpc).main_fast
+    call m(idct_16x8_internal_10bpc).main_fast
+    call .main_fast
+    call m(idct_16x16_internal_10bpc).main_end
+    jmp .end
+.full:
+    mova                 m2, [cq+64* 8] ; 16 17
+    mova                 m5, [cq+64* 9] ; 18 19
+    mova                 m9, [cq+64*10] ; 20 21
+    mova                m21, [cq+64*11] ; 22 23
+    vpermt2q             m1, m10, m9    ;  4 20
+    vpermt2q             m7, m10, m21   ; 14 22
+    vpermt2q            m21, m11, m5    ; 23 19
+    vpermt2q             m5, m10, m20   ; 18 10
+    mova                m20, m11
+    vpermi2q            m20, m2, m9     ; 17 21
+    mova                m22, [cq+64*12] ; 24 25
+    mova                 m9, [cq+64*13] ; 26 27
+    mova                 m3, [cq+64*14] ; 28 29
+    mova                m23, [cq+64*15] ; 30 31
+    vpermt2q             m2, m10, m22   ; 16 24
+    vpermt2q            m22, m11, m3    ; 25 29
+    vpermt2q             m3, m10, m6    ; 28 12
+    vpermt2q             m4, m10, m9    ;  2 26
+    mova                 m6, m10
+    vpermi2q             m6, m23, m8    ; 30  6
+    vpermt2q            m23, m11, m9    ; 31 27
+    mov                 r6d, 64*3
+    call m(idct_8x8_internal_10bpc).main
+    call m(idct_16x8_internal_10bpc).main
+    call .main
+    call m(idct_16x16_internal_10bpc).main_end
+    jmp .end
+.fast:
+    vpermq               m0, m10, m0    ;  0  0
+    vpermq               m1, m10, m1    ;  4  4
+    vpermt2q             m4, m10, m8    ;  2  6
+    xor                 r6d, r6d
+    call .main_fast2
+    call m(idct_16x16_internal_10bpc).main_end
+.end:
+%if WIN64
+    movaps             xmm6, [cq+16*0]
+    movaps             xmm7, [cq+16*1]
+%endif
+    vzeroupper
+    call .transpose_8x32
+    pxor                m14, m14
+.zero_loop:
+    mova     [cq+r6*4+64*3], m14
+    mova     [cq+r6*4+64*2], m14
+    mova     [cq+r6*4+64*1], m14
+    mova     [cq+r6*4+64*0], m14
+    sub                 r6d, 64
+    jge .zero_loop
+    lea                  r5, [o_base_8bpc]
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    punpcklqdq           m4, m5, m7
+    punpckhqdq           m5, m7
+    punpckhqdq           m7, m6, m8
+    punpcklqdq           m6, m8
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    pxor                m12, m12
+.write_32x8_start:
+    vpbroadcastd        m11, [pw_2048]
+    vpbroadcastd        m13, [pixel_10bpc_max]
+    lea                  r3, [strideq*3]
+.write_32x8:
+    pmulhrsw             m0, m11
+    pmulhrsw             m1, m11
+    pmulhrsw             m2, m11
+    pmulhrsw             m3, m11
+    call .write_32x4
+    pmulhrsw             m0, m11, m4
+    pmulhrsw             m1, m11, m5
+    pmulhrsw             m2, m11, m6
+    pmulhrsw             m3, m11, m7
+.write_32x4:
+    paddw                m0, [dstq+strideq*0]
+    paddw                m1, [dstq+strideq*1]
+    paddw                m2, [dstq+strideq*2]
+    paddw                m3, [dstq+r3       ]
+    REPX    {pmaxsw x, m12}, m0, m1, m2, m3
+    REPX    {pminsw x, m13}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+r3       ], m3
+    lea                dstq, [dstq+strideq*4]
+    ret
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 8
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_32x16_10bpc).dconly2
+ALIGN function_align
+.main_fast3:
+    ; assuming m0=in0 in0, m4=in2 in2, and m16=in1 in3
+    vbroadcasti32x4      m5, [o(pd_401_4076)]
+    pmulld               m3, m0, m12
+    pmulld               m4, m5
+    REPX    {paddd  x, m13}, m3, m4
+    REPX    {psrad  x, 12 }, m3, m4     ; m3=idct8:t0-7, m4=t8a t15a
+
+    ; t8a t15a -> t8/9 t14/15
+
+    vbroadcasti32x4      m5, [o(pd_3784_m3784)]
+    pshufd               m7, m4, q1032
+    pmulld               m6, m4, [o(pd_1567)]{bcstd}
+    pmulld               m5, m7
+    paddd                m6, m13
+    paddd                m5, m6
+    psrad                m5, 12         ; m5=t9a t14a
+
+    ; t14a t9a -> t13/14 t9/10 [m5] & t8 15 -> t8/11a t12/15a [m4]
+
+    shufps               m6, m4, m5, q1032     ; t12  t13
+    shufps               m8, m4, m5, q3210     ; t11a t10
+    pmulld               m9, m6, m12
+    pmulld               m7, m8, m12
+    paddd                m9, m13
+    paddd                m5, m9, m7     ; t12 t13a
+    psubd                m4, m9, m7     ; t11 t10a
+    REPX    {psrad  x, 12 }, m5, m4
+
+    psubd                m7, m3, m6   ; dct16 out15 out14
+    paddd                m0, m3, m6   ; dct16 out0  out1
+    psubd                m6, m3, m5   ; dct16 out12 out13
+    paddd                m1, m3, m5   ; dct16 out3  out2
+    psubd                m5, m3, m4   ; dct16 out11 out10
+    paddd                m2, m3, m4   ; dct16 out4  out5
+    psubd                m4, m3, m8   ; dct16 out8  out9
+    paddd                m3, m8       ; dct16 out7  out6
+    REPX    {pmaxsd x, m14}, m7, m0, m6, m1, m5, m2, m4, m3
+    REPX    {pminsd x, m15}, m0, m1, m2, m3, m4, m5, m6, m7
+
+    ; idct32_bottomhalf
+    vbroadcasti32x4     m18, [o(pd_201_m601)]
+    vbroadcasti32x4     m19, [o(pd_4091_4052)]
+    pmulld              m17, m16, m19
+    pmulld              m16, m18
+    REPX    {paddd  x, m13}, m17, m16
+    REPX    {psrad  x, 12 }, m17, m16
+
+    ; m17: t31a t24a -> t30/31 t24/25, m16: t16a t23a -> t16/17 t22/23 [step2]
+
+    vbroadcasti32x4     m10, [o(pd_799_m2276)]
+    vbroadcasti32x4     m11, [o(pd_4017_3406)]
+    pmulld              m18, m17, m10
+    pmulld              m19, m17, m11
+    pmulld               m8, m16, m11
+    pmulld               m9, m16, m10
+    REPX    {paddd  x, m13}, m18, m19
+    psubd               m18, m8
+    paddd               m19, m9
+    REPX    {psrad  x, 12 }, m18, m19
+
+    ; m17=t31  t24  -> t28/31a t24/27a, m16=t16  t23  -> t16/19a t20/23a
+    ; m18=t17a t22a -> t17/18  t21/22,  m19=t30a t25a -> t29/30  t25/26
+
+    punpckhqdq          m23, m17, m19   ; t24a t25 [or t27a t26]
+    punpcklqdq          m20, m16, m18   ; t16a t17 [or t19a t18]
+    punpckhqdq          m22, m16, m18   ; t23a t22 [or t20a t21]
+    punpcklqdq          m16, m17, m19   ; t28a t29 [or t31a t30]
+    mova                m21, m23
+    mova                m18, m20
+    mova                m17, m22
+    mova                m19, m16
+
+    jmp .main4
+.main_fast2: ; bottom three-quarters are zero
+    vbroadcasti32x4      m8, [o(pd_799_4017)]
+    pmulld               m8, m1     ; t4  t7
+    vpmulld              m0, [o(pd_2896)] {1to16} ; t0 t1
+    REPX     {paddd x, m13}, m8, m0
+    REPX     {psrad x, 12 }, m8, m0
+    pmulld               m3, m8, m12
+    mova                 m2, m0       ;  t3   t2
+    call m(idct_8x8_internal_10bpc).main3
+    vbroadcasti32x4      m6, [o(pd_4076_3920)]
+    vbroadcasti32x4      m3, [o(pd_401_m1189)]
+    pmulld               m6, m4       ;  t15  t12
+    pmulld               m4, m3       ;  t9   t10
+    REPX     {paddd x, m13}, m6, m4
+    REPX     {psrad x, 12 }, m6, m4
+    mova                 m5, m6       ;  t14  t13
+    mova                 m9, m4       ;  t8   t11
+    call m(idct_16x8_internal_10bpc).main3
+    vbroadcasti32x4     m23, [o(pd_4091_3973)]
+    vbroadcasti32x4      m7, [o(pd_201_995)]
+    vbroadcasti32x4     m22, [o(pd_1380_601)]
+    vbroadcasti32x4      m9, [o(pd_3857_4052)]
+    pmulld              m23, m16      ;  t16  t20
+    pmulld              m16, m7       ;  t31  t27
+    pmulld              m22, m17      ; -t19 -t25
+    pmulld              m17, m9       ;  t28  t24
+    REPX    {paddd  x, m13}, m23, m16, m17
+    psubd               m22, m13, m22
+    REPX    {psrad  x, 12 }, m23, m16, m22, m17
+    mova                m20, m23      ;  t30  t26
+    mova                 m9, m16      ;  t17  t21
+    mova                m19, m22      ;  t18  t22
+    mova                m18, m17      ;  t29  t25
+    jmp .main3
+.main_fast: ; bottom half is zero
+    vbroadcasti32x4     m23, [o(pd_4091_3973)]
+    vbroadcasti32x4      m7, [o(pd_201_995)]
+    vbroadcasti32x4     m20, [o(pd_2751_2106)]
+    vbroadcasti32x4      m9, [o(pd_3035_3513)]
+    vbroadcasti32x4     m21, [o(pd_3703_3290)]
+    vbroadcasti32x4     m10, [o(pd_1751_2440)]
+    vbroadcasti32x4     m22, [o(pd_1380_601)]
+    vbroadcasti32x4     m11, [o(pd_3857_4052)]
+    pmulld              m23, m16      ;  t16a  t20a
+    pmulld              m16, m7       ;  t31a  t27a
+    pmulld              m20, m19      ; -t17a -t21a
+    pmulld              m19, m9       ;  t30a  t26a
+    pmulld              m21, m18      ;  t18a  t22a
+    pmulld              m18, m10      ;  t29a  t25a
+    pmulld              m22, m17      ; -t19a -t25a
+    pmulld              m17, m11      ;  t28a  t24a
+    psubd               m20, m13, m20
+    psubd               m22, m13, m22
+    jmp .main2
+.main:
+    ITX_MULSUB_2D        16, 23, 7, 9, 10, _,  201_995,  4091_3973
+    ITX_MULSUB_2D        20, 19, 7, 9, 10, _, 3035_3513, 2751_2106
+    ITX_MULSUB_2D        18, 21, 7, 9, 10, _, 1751_2440, 3703_3290
+    ITX_MULSUB_2D        22, 17, 7, 9, 10, _, 3857_4052, 1380_601
+    paddd               m20, m13
+    paddd               m22, m13
+.main2:
+    REPX    {paddd  x, m13}, m16, m23, m19
+    REPX    {psrad  x, 12 }, m16, m20, m23, m19
+    psubd                m9, m16, m20 ; t17  t21
+    paddd               m16, m20      ; t16  t20
+    psubd               m20, m23, m19 ; t30  t26
+    paddd               m23, m19      ; t31  t27
+    REPX    {pmaxsd x, m14}, m9, m16, m20, m23
+    REPX    {paddd  x, m13}, m21, m18, m17
+    REPX    {psrad  x, 12 }, m18, m22, m21, m17
+    psubd               m19, m22, m18 ; t18  t22
+    paddd               m22, m18      ; t19  t23
+    psubd               m18, m17, m21 ; t29  t25
+    paddd               m17, m21      ; t28  t24
+    REPX    {pmaxsd x, m14}, m19, m22, m18, m17
+    REPX    {pminsd x, m15}, m20, m9, m18, m19, m16, m23, m22, m17
+.main3:
+    vbroadcasti32x4     m11, [o(pd_4017_2276)]
+    vbroadcasti32x4     m10, [o(pd_799_3406)]
+    psubd                m7, m0, m6   ; dct16 out15 out14
+    paddd                m0, m6       ; dct16 out0  out1
+    psubd                m6, m1, m5   ; dct16 out12 out13
+    paddd                m1, m5       ; dct16 out3  out2
+    psubd                m5, m2, m4   ; dct16 out11 out10
+    paddd                m2, m4       ; dct16 out4  out5
+    psubd                m4, m3, m8   ; dct16 out8  out9
+    paddd                m3, m8       ; dct16 out7  out6
+    ITX_MULSUB_2D        20,  9, 8, 21, _, 13, 10, 11
+    ITX_MULSUB_2D        18, 19, 8, 21, _, 13, 10, 11, 2
+    REPX    {pmaxsd x, m14}, m7, m0, m6, m1, m5, m2, m4, m3
+    punpckhqdq          m21, m16, m20 ; t20  t21a
+    punpcklqdq          m16, m20      ; t16  t17a
+    punpcklqdq          m20, m22, m19 ; t19  t18a
+    punpckhqdq          m22, m19      ; t23  t22a
+    REPX    {pminsd x, m15}, m0, m1, m2, m3, m4, m5, m6, m7
+    punpcklqdq          m19, m23, m9  ; t31  t30a
+    punpckhqdq          m23, m9       ; t27  t26a
+    punpckhqdq           m9, m17, m18 ; t24  t25a
+    punpcklqdq          m17, m18      ; t28  t29a
+    psubd               m18, m16, m20 ; t19a t18
+    paddd               m20, m16      ; t16a t17
+    psubd               m16, m19, m17 ; t28a t29
+    paddd               m19, m17      ; t31a t30
+    psubd               m17, m22, m21 ; t20a t21
+    paddd               m22, m21      ; t23a t22
+    psubd               m21, m9, m23  ; t27a t26
+    paddd               m23, m9       ; t24a t25
+    REPX    {pmaxsd x, m14}, m18, m16, m17, m21
+    REPX    {pminsd x, m15}, m16, m18, m21, m17
+    REPX    {pmaxsd x, m14}, m20, m22, m19, m23
+    REPX    {pminsd x, m15}, m20, m22, m19, m23
+.main4:
+    vpbroadcastd        m11, [o(pd_3784)]
+    vpbroadcastd        m10, [o(pd_1567)]
+    ITX_MULSUB_2D        16, 18, 8, 9, _, 13, 10, 11
+    ITX_MULSUB_2D        21, 17, 8, 9, _, 13, 10, 11, 2
+    paddd                m9, m20, m22 ; t16  t17a
+    psubd               m20, m22      ; t23  t22a
+    paddd               m22, m19, m23 ; t31  t30a
+    psubd               m19, m23      ; t24  t25a
+    psubd               m23, m16, m17 ; t20a t21
+    paddd               m16, m17      ; t19a t18
+    psubd               m17, m18, m21 ; t27a t26
+    paddd               m21, m18      ; t28a t29
+    REPX    {pmaxsd x, m14}, m20, m19, m23, m17
+    REPX    {pminsd x, m15}, m19, m20, m17, m23
+    REPX    {pmulld x, m12}, m19, m20, m17, m23
+    REPX    {pmaxsd x, m14}, m22, m21, m16, m9
+    paddd               m19, m13
+    paddd               m17, m13
+    REPX    {pminsd x, m15}, m22, m21, m16, m9
+    psubd               m18, m19, m20 ; t23a t22
+    paddd               m19, m20      ; t24a t25
+    paddd               m20, m17, m23 ; t27  t26a
+    psubd               m17, m23      ; t20  t21a
+    REPX    {psrad  x, 12 }, m20, m19, m18, m17
+    ret
+.transpose_8x32:
+    mova                m10, [o(idct32x8p)]
+    psrlw                m8, m10, 8
+    mova                 m9, m8
+    vpermi2w             m8, m1, m5
+    vpermt2w             m1, m10, m5
+    vprold               m5, m9, 16
+    vpermi2w             m9, m3, m7
+    vpermt2w             m3, m10, m7
+    vprold              m10, 16
+    mova                 m7, m5
+    vpermi2w             m5, m0, m4
+    vpermt2w             m0, m10, m4
+    vpermi2w             m7, m2, m6
+    vpermt2w             m2, m10, m6
+    punpckhdq            m6, m5, m8
+    punpckldq            m5, m8
+    punpckhdq            m8, m7, m9
+    punpckldq            m7, m9
+    punpckhdq            m4, m2, m3
+    punpckldq            m2, m3
+    punpckhdq            m3, m0, m1
+    punpckldq            m0, m1
+    ret
+
+cglobal inv_txfm_add_identity_identity_32x8_10bpc, 4, 7, 10, dst, stride, c, eob
+    vpbroadcastd         m5, [pw_4096]
+    lea                  r4, [strideq*3]
+    mova                 m6, [idtx32x8p]
+    lea                  r5, [strideq*5]
+    vpbroadcastd         m9, [pixel_10bpc_max]
+    lea                  r6, [strideq+r4*2]
+    pxor                 m8, m8
+    sub                eobd, 107
+    psrlw                m7, m6, 8
+.loop:
+    mova                 m0, [cq+64*0]
+    packssdw             m0, [cq+64*1] ; 02 13
+    mova                 m1, [cq+64*2]
+    packssdw             m1, [cq+64*3] ; 46 57
+    mova                 m2, [cq+64*4]
+    packssdw             m2, [cq+64*5] ; 8a 9b
+    mova                 m3, [cq+64*6]
+    packssdw             m3, [cq+64*7] ; ce df
+    REPX   {pmulhrsw x, m5}, m0, m1, m2, m3
+    REPX {mova [cq+64*x], m8}, 0, 1, 2, 3
+    mova                 m4, m6
+    vpermi2w             m4, m1, m3
+    vpermt2w             m1, m7, m3
+    REPX {mova [cq+64*x], m8}, 4, 5, 6, 7
+    mova                 m3, m7
+    vpermi2w             m3, m0, m2
+    vpermt2w             m0, m6, m2
+    add                  cq, 64*8
+    punpcklqdq           m2, m3, m1 ; 4 5
+    punpckhqdq           m3, m1     ; 6 7
+    punpckhqdq           m1, m0, m4 ; 2 3
+    punpcklqdq           m0, m4     ; 0 1
+    mova                ym4, [dstq+strideq*0]
+    vinserti32x8         m4, [dstq+strideq*1], 1
+    paddw                m0, m4
+    mova                ym4, [dstq+strideq*2]
+    vinserti32x8         m4, [dstq+r4     *1], 1
+    paddw                m1, m4
+    mova                ym4, [dstq+strideq*4]
+    vinserti32x8         m4, [dstq+r5     *1], 1
+    paddw                m2, m4
+    mova                ym4, [dstq+r4     *2]
+    vinserti32x8         m4, [dstq+r6     *1], 1
+    paddw                m3, m4
+    REPX     {pmaxsw x, m8}, m0, m1, m2, m3
+    REPX     {pminsw x, m9}, m0, m1, m2, m3
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+r4     *1], m1, 1
+    mova          [dstq+strideq*4], ym2
+    vextracti32x8 [dstq+r5     *1], m2, 1
+    mova          [dstq+r4     *2], ym3
+    vextracti32x8 [dstq+r6     *1], m3, 1
+    add                dstq, 32
+    add                eobd, 0x80000000
+    jnc .loop
+    RET
+
+cglobal inv_txfm_add_dct_dct_16x32_10bpc, 4, 7, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+%if WIN64
+    movaps         [rsp+ 8], xmm6
+    movaps         [rsp+24], xmm7
+%endif
+    cmp                eobd, 36
+    jl .fast
+    call .pass1
+    cmp                eobd, 151
+    jge .full
+    lea                  r5, [o_base_8bpc]
+    pxor                 m9, m9
+    punpcklwd            m8, m1, m1 ;  2
+    punpckhwd           m14, m1, m1 ;  3
+    punpcklwd            m1, m3, m3 ;  6
+    punpckhwd           m15, m3, m3 ;  7
+    punpcklwd            m3, m6, m6 ; 12
+    punpckhwd           m19, m6, m6 ; 13
+    punpcklwd            m6, m9, m4 ; __  8
+    punpckhwd           m20, m4, m4 ;  9
+    punpckhwd           m16, m5, m5 ; 11
+    punpcklwd            m5, m5     ; 10
+    punpcklwd            m9, m0     ; __  0
+    punpckhwd           m21, m0, m0 ;  1
+    punpcklwd            m0, m7, m7 ; 14
+    punpckhwd           m17, m7, m7 ; 15
+    punpcklwd            m7, m2, m2 ;  4
+    punpckhwd           m18, m2, m2 ;  5
+    call m(idct_16x16_internal_8bpc).main_fast
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    mov                 r6d, 64*3
+    pxor                 m8, m8
+.zero_loop:
+    REPX {mova [cq+r6*8+128*x], m8}, 3, 2, 1, 0
+    sub                 r6d, 64
+    jge .zero_loop
+    jmp .pass2_end
+.full:
+    mova         [cq+128*0], m0
+    mova         [cq+128*1], m1
+    mova         [cq+128*2], m2
+    mova         [cq+128*3], m3
+    mova         [cq+128*4], m4
+    mova         [cq+128*5], m5
+    mova         [cq+128*6], m6
+    mova         [cq+128*7], m7
+    add                  cq, 64
+    call .pass1
+    mova                 m9, [cq-64* 1] ;  0  1
+    mova                m14, [cq+64* 1] ;  2  3
+    mova                m18, [cq+64* 3] ;  4  5
+    mova                m15, [cq+64* 5] ;  6  7
+    mova                m20, [cq+64* 7] ;  8  9
+    mova                m16, [cq+64* 9] ; 10 11
+    mova                m22, [cq+64*11] ; 12 13
+    mova                m19, [cq+64*13] ; 14 15
+    lea                  r5, [o_base_8bpc]
+    punpcklwd            m8, m7, m14   ; 30  2
+    punpckhwd           m21, m7, m9    ; 31  1
+    punpcklwd            m7, m6, m18   ; 28  4
+    punpckhwd           m14, m6        ;  3 29
+    punpcklwd            m9, m0, m9    ; 16  0
+    punpckhwd           m17, m19, m0   ; 15 17
+    punpcklwd            m0, m19, m1   ; 14 18
+    punpckhwd           m19, m1, m22   ; 19 13
+    punpcklwd            m1, m15, m5   ;  6 26
+    punpckhwd           m18, m5, m18   ; 27  5
+    punpcklwd            m6, m4, m20   ; 24  8
+    punpckhwd           m15, m4        ;  7 25
+    punpcklwd            m5, m3, m16   ; 22 10
+    punpckhwd           m20, m3, m20   ; 23  9
+    punpcklwd            m3, m22, m2   ; 12 20
+    punpckhwd           m16, m2        ; 11 21
+    call m(idct_16x16_internal_8bpc).main2
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    mov                 r6d, 32*7
+    pxor                 m8, m8
+.full_zero_loop:
+    REPX {mova [cq+r6*8+64*x], m8}, 2, 1, 0, -1
+    sub                 r6d, 32
+    jge .full_zero_loop
+    jmp .pass2_end
+.fast:
+    mova                ym0, [cq+128*0]
+    mova                ym2, [cq+128*4]
+    movshdup             m8, [o(permB)]
+    mova                ym1, [cq+128*2]
+    mova                ym3, [cq+128*6]
+    mova                ym4, [cq+128*1]
+    mova                ym5, [cq+128*3]
+    mova                ym6, [cq+128*5]
+    mova                ym7, [cq+128*7]
+    vpermt2q             m0, m8, m2 ; 0 4
+    vpermt2q             m1, m8, m3 ; 2 6
+    vpermt2q             m4, m8, m5 ; 1 3
+    vpermt2q             m7, m8, m6 ; 7 5
+    REPX    {pmulld x, m12}, m0, m1, m4, m7
+    pxor               ym16, ym16
+    mova         [cq+128*0], ym16
+    REPX {vmovdqa32 [cq+128*x], ym16}, 1, 2, 3, 4, 5, 6, 7
+    REPX    {paddd  x, m13}, m0, m1, m4, m7
+    REPX    {psrad  x, 12 }, m0, m1, m4, m7
+    call m(idct_8x8_internal_10bpc).main_fast
+    call m(idct_16x8_internal_10bpc).main_fast
+    vpbroadcastd        m11, [o(pd_1)]
+    call m(idct_8x16_internal_10bpc).main_end2
+    mova                 m8, [o(idct8x32p)]
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    mova                 m6, [dup16_perm]
+    vpermb               m0, m8, m0
+    vpermb               m2, m8, m2
+    vprold               m8, 16
+    vpermb               m1, m8, m1
+    vpermb               m3, m8, m3
+    punpckldq            m4, m0, m2
+    punpckhdq            m0, m2
+    punpckldq            m2, m1, m3
+    punpckhdq            m1, m3
+    punpckldq           m21, m4, m2
+    punpckhdq           m14, m4, m2
+    punpckldq           m18, m0, m1
+    punpckhdq           m15, m0, m1
+    vpermb               m8, m6, m14 ; 2
+    vpermb               m1, m6, m15 ; 6
+    vpermb               m7, m6, m18 ; 4
+    pmovzxwd             m9, ym21    ; 0
+    vpord                m6, [o(pb_32)] {1to16}
+    lea                  r5, [o_base_8bpc]
+    vpermb              m21, m6, m21 ; 1
+    vpermb              m15, m6, m15 ; 7
+    vpermb              m18, m6, m18 ; 5
+    vpermb              m14, m6, m14 ; 3
+    pslld                m9, 16
+    call m(idct_16x16_internal_8bpc).main_fast2
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast2
+.pass2_end:
+    movshdup            m22, [permC]
+    vpbroadcastd        m11, [pw_2048]
+    vpbroadcastd        m13, [pixel_10bpc_max]
+    lea                  r6, [strideq*3]
+    pxor                m12, m12
+    psrlq               m23, m22, 8
+    vpermq               m8, m22, m0
+    vpermq               m9, m23, m1
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m22, m2
+    vpermq               m9, m23, m3
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m22, m4
+    vpermq               m9, m23, m5
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m22, m6
+    vpermq               m9, m23, m7
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m22, m14
+    vpermq               m9, m23, m15
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m22, m16
+    vpermq               m9, m23, m17
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m22, m18
+    vpermq               m9, m23, m19
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m22, m20
+    vpermq               m9, m23, m21
+%if WIN64
+    movaps             xmm6, [rsp+ 8]
+    movaps             xmm7, [rsp+24]
+%endif
+    vzeroupper
+    jmp m(idct_16x8_internal_10bpc).write_16x4
+.pass1:
+    pmulld               m0, m12, [cq+128* 0]
+    pmulld               m1, m12, [cq+128* 2]
+    pmulld               m2, m12, [cq+128* 4]
+    pmulld               m3, m12, [cq+128* 6]
+    pmulld               m4, m12, [cq+128* 8]
+    pmulld               m5, m12, [cq+128*10]
+    pmulld               m6, m12, [cq+128*12]
+    pmulld               m7, m12, [cq+128*14]
+    call m(idct_8x16_internal_10bpc).main_rect2
+    pmulld              m16, m12, [cq+128* 1]
+    pmulld              m17, m12, [cq+128* 3]
+    pmulld              m18, m12, [cq+128* 5]
+    pmulld              m19, m12, [cq+128* 7]
+    pmulld              m20, m12, [cq+128* 9]
+    pmulld              m21, m12, [cq+128*11]
+    pmulld              m22, m12, [cq+128*13]
+    pmulld              m23, m12, [cq+128*15]
+    call m(idct_16x16_internal_10bpc).main_rect2
+    vpbroadcastd        m11, [o(pd_1)]
+    call m(idct_16x16_internal_10bpc).main_end2
+    jmp m(idct_16x16_internal_10bpc).main_end3
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 32
+    jmp m(inv_txfm_add_dct_dct_16x8_10bpc).dconly
+
+cglobal inv_txfm_add_identity_identity_16x32_10bpc, 4, 7, 16, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m10, [pw_2896x8]
+    vpbroadcastd        m11, [pw_1697x16]
+    vpbroadcastd        m13, [pw_8192]
+    vpbroadcastd        m15, [pixel_10bpc_max]
+    lea                  r6, [strideq*9]
+    pxor                m14, m14
+    paddw               m12, m13, m13 ; pw_16384
+    cmp                eobd, 151
+    jl .main
+    call .main
+    add                  cq, 64-128*4
+    lea                dstq, [dstq+strideq*8]
+.main:
+    call .main_internal
+    add                  cq, 128*4
+    pmulhrsw             m1, m13, m2
+    pmulhrsw             m3, m13, m4
+    pmulhrsw             m5, m13, m6
+    pmulhrsw             m7, m13, m8
+    call .main_internal
+.main2:
+    pmulhrsw             m2, m13
+    pmulhrsw             m4, m13
+    pmulhrsw             m6, m13
+    pmulhrsw             m8, m13
+    punpcklqdq           m0, m1, m2 ;  0  8
+    punpckhqdq           m1, m2     ;  1  9
+    call .write_16x2x2
+    punpcklqdq           m0, m3, m4 ;  2 10
+    punpckhqdq           m1, m3, m4 ;  3 11
+    call .write_16x2x2
+    punpcklqdq           m0, m5, m6 ;  4 12
+    punpckhqdq           m1, m5, m6 ;  5 13
+    call .write_16x2x2
+    punpcklqdq           m0, m7, m8 ;  6 14
+    punpckhqdq           m1, m7, m8 ;  7 15
+.write_16x2x2:
+    mova                ym2, [dstq+strideq*0]
+    vinserti32x8         m2, [dstq+strideq*8], 1
+    mova                ym9, [dstq+strideq*1]
+    vinserti32x8         m9, [dstq+r6       ], 1
+    paddw                m0, m2
+    paddw                m1, m9
+    pmaxsw               m0, m14
+    pmaxsw               m1, m14
+    pminsw               m0, m15
+    pminsw               m1, m15
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*8], m0, 1
+    mova          [dstq+strideq*1], ym1
+    vextracti32x8 [dstq+r6       ], m1, 1
+    lea                dstq, [dstq+strideq*2]
+    ret
+.main_internal:
+    mova                 m8, [cq+128* 0]
+    packssdw             m8, [cq+128* 8]
+    mova                 m6, [cq+128* 1]
+    packssdw             m6, [cq+128* 9]
+    mova                 m0, [cq+128* 2]
+    packssdw             m0, [cq+128*10]
+    mova                 m2, [cq+128* 3]
+    packssdw             m2, [cq+128*11]
+    REPX  {pmulhrsw x, m10}, m8, m6, m0, m2
+    REPX {vpermq x, x, q3120}, m8, m6, m0, m2
+    pmulhrsw             m4, m11, m8
+    pmulhrsw             m9, m11, m6
+    REPX {mova [cq+128*x], m14}, 0, 1, 2, 3
+    pmulhrsw             m4, m12
+    pmulhrsw             m9, m12
+    paddsw               m8, m4
+    paddsw               m6, m9
+    pmulhrsw             m4, m11, m0
+    pmulhrsw             m9, m11, m2
+    REPX {mova [cq+128*x], m14}, 8, 9, 10, 11
+    pmulhrsw             m4, m12
+    pmulhrsw             m9, m12
+    paddsw               m0, m4
+    paddsw               m2, m9
+    punpcklwd            m4, m8, m6
+    punpckhwd            m8, m6
+    punpcklwd            m6, m0, m2
+    punpckhwd            m0, m2
+    punpckldq            m2, m4, m6 ; 0 1
+    punpckhdq            m4, m6     ; 2 3
+    punpckldq            m6, m8, m0 ; 4 5
+    punpckhdq            m8, m0     ; 6 7
+    ret
+
+cglobal inv_txfm_add_dct_dct_32x16_10bpc, 4, 7, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+%if WIN64
+    movaps         [rsp+ 8], xmm6
+    movaps         [rsp+24], xmm7
+%endif
+    mov                 r6d, 8*12
+    cmp                eobd, 36
+    jl .fast
+    pmulld               m0, m12, [cq+64* 0]
+    pmulld               m1, m12, [cq+64* 4]
+    pmulld               m2, m12, [cq+64* 8]
+    pmulld               m3, m12, [cq+64*12]
+    pmulld              m16, m12, [cq+64* 2]
+    pmulld              m17, m12, [cq+64* 6]
+    pmulld              m18, m12, [cq+64*10]
+    pmulld              m19, m12, [cq+64*14]
+    cmp                eobd, 151
+    jge .full
+    call m(idct_8x16_internal_10bpc).main_fast_rect2
+    call m(idct_16x16_internal_10bpc).main_fast_rect2
+    call .idct16_sumsub
+    call .pass1_load_spill
+    call .main_fast_rect2
+    jmp .pass1_end
+.full:
+    pmulld               m4, m12, [cq+64*16]
+    pmulld               m5, m12, [cq+64*20]
+    pmulld               m6, m12, [cq+64*24]
+    pmulld               m7, m12, [cq+64*28]
+    pmulld              m20, m12, [cq+64*18]
+    pmulld              m21, m12, [cq+64*22]
+    pmulld              m22, m12, [cq+64*26]
+    pmulld              m23, m12, [cq+64*30]
+    add                 r6d, 8*16
+    call m(idct_8x16_internal_10bpc).main_rect2
+    call m(idct_16x16_internal_10bpc).main_rect2
+    call .idct16_sumsub
+    call .pass1_load_spill
+    pmulld              m16, m12, [cq+64*17]
+    pmulld              m17, m12, [cq+64*19]
+    pmulld              m18, m12, [cq+64*21]
+    pmulld              m19, m12, [cq+64*23]
+    pmulld              m20, m12, [cq+64*25]
+    pmulld              m21, m12, [cq+64*27]
+    pmulld              m22, m12, [cq+64*29]
+    pmulld              m23, m12, [cq+64*31]
+    call .main_rect2
+.pass1_end:
+    vpbroadcastd        m11, [o(pd_1)]
+    lea                  r4, [cq+64]
+    call .idct32_pass1_end
+    lea                  r5, [o_base_8bpc]
+    punpckhqdq          m19, m5, m16  ; 11
+    punpcklqdq           m5, m16      ; 10
+    punpckhqdq          m16, m2, m1   ;  5
+    punpcklqdq           m2, m1       ;  4
+    punpcklqdq           m1, m15, m4  ;  2
+    punpckhqdq          m15, m4       ;  3
+    punpcklqdq           m4, m14, m18 ;  8
+    punpckhqdq          m18, m14, m18 ;  9
+    punpckhqdq          m14, m0, m20  ;  1
+    punpcklqdq           m0, m20      ;  0
+    punpckhqdq          m20, m6, m17  ; 13
+    punpcklqdq           m6, m17      ; 12
+    punpckhqdq          m17, m3, m21  ;  7
+    punpcklqdq           m3, m21      ;  6
+    punpckhqdq          m21, m7, m8   ; 15
+    punpcklqdq           m7, m8       ; 14
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    jmp .end
+.fast:
+    pmulld              ym0, ym12, [cq+64*0]
+    pmulld              ym1, ym12, [cq+64*4]
+    movshdup             m7, [o(permB)]
+    mova                ym4, [cq+64*2]
+    mova                ym5, [cq+64*6]
+    mova               ym16, [cq+64*1]
+    mova                ym2, [cq+64*5]
+    mova                ym3, [cq+64*3]
+    mova               ym17, [cq+64*7]
+    vpermt2q             m4, m7, m5 ;  2  6
+    vpermt2q            m16, m7, m2 ;  1  5
+    vpermt2q            m17, m7, m3 ;  7  3
+    paddd               ym0, ym13
+    paddd               ym1, ym13
+    psrad               ym0, 12
+    psrad               ym1, 12
+    vpermq               m0, m7, m0 ;  0  0
+    vpermq               m1, m7, m1 ;  4  4
+    REPX    {pmulld x, m12}, m4, m16, m17
+    REPX    {paddd  x, m13}, m4, m16, m17
+    REPX    {psrad  x, 12 }, m4, m16, m17
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).main_fast2
+    vpbroadcastd        m11, [o(pd_1)]
+    call m(idct_16x16_internal_10bpc).main_end2
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).transpose_8x32
+    lea                  r5, [o_base_8bpc]
+    punpckhqdq          m14, m0, m2 ; 1
+    punpcklqdq           m0, m2     ; 0
+    punpcklqdq           m1, m3, m4 ; 2
+    punpckhqdq          m15, m3, m4 ; 3
+    punpcklqdq           m2, m5, m7 ; 4
+    punpckhqdq          m16, m5, m7 ; 5
+    punpcklqdq           m3, m6, m8 ; 6
+    punpckhqdq          m17, m6, m8 ; 7
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+.end:
+%if WIN64
+    movaps             xmm6, [rsp+ 8]
+    movaps             xmm7, [rsp+24]
+%endif
+    pxor                m12, m12
+.zero_loop:
+    mova     [cq+r6*8+64*3], m12
+    mova     [cq+r6*8+64*2], m12
+    mova     [cq+r6*8+64*1], m12
+    mova     [cq+r6*8+64*0], m12
+    sub                 r6d, 8*4
+    jge .zero_loop
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x8_start
+    pmulhrsw             m0, m11, m14
+    pmulhrsw             m1, m11, m15
+    pmulhrsw             m2, m11, m16
+    pmulhrsw             m3, m11, m17
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x4
+    pmulhrsw             m0, m11, m18
+    pmulhrsw             m1, m11, m19
+    pmulhrsw             m2, m11, m20
+    pmulhrsw             m3, m11, m21
+    vzeroupper
+    jmp m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x4
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 16
+.dconly3:
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 384
+    sar                 r6d, 9
+.dconly2:
+    vpbroadcastd         m3, [o(dconly_10bpc)]
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    vpbroadcastw         m2, r6d
+    paddsw               m2, m3
+.dconly_loop:
+    paddsw               m0, m2, [dstq+strideq*0]
+    paddsw               m1, m2, [dstq+strideq*1]
+    psubusw              m0, m3
+    psubusw              m1, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    RET
+ALIGN function_align
+.idct16_sumsub:
+    psubd               m23, m0, m22 ; t15
+    paddd                m0, m22     ; t0
+    psubd               m22, m1, m21 ; t14
+    paddd                m1, m21     ; t1
+    REPX    {pmaxsd x, m14}, m23, m0, m22, m1
+    psubd               m21, m2, m20 ; t13
+    paddd                m2, m20     ; t2
+    REPX    {pminsd x, m15}, m23, m0, m22, m1
+    psubd               m20, m3, m19 ; t12
+    paddd                m3, m19     ; t3
+    REPX    {pmaxsd x, m14}, m21, m2, m20, m3
+    psubd               m19, m4, m18 ; t11
+    paddd                m4, m18     ; t4
+    REPX    {pminsd x, m15}, m21, m2, m20, m3
+    psubd               m18, m5, m17 ; t10
+    paddd                m5, m17     ; t5
+    REPX    {pmaxsd x, m14}, m19, m4, m18, m5
+    psubd               m17, m6, m16 ; t9
+    paddd                m6, m16     ; t6
+    REPX    {pminsd x, m15}, m19, m4, m18, m5
+    psubd               m16, m7, m9  ; t8
+    paddd                m7, m9      ; t7
+    REPX    {pmaxsd x, m14}, m17, m6, m16, m7
+    REPX    {pminsd x, m15}, m17, m6, m16, m7
+    ret
+.idct32_pass1_end:
+    psrlq               m12, [o(permC)], 24 ;  0  2  8 10  1  3  9 11
+    psrlq               m13, m12, 32        ;  4  6 12 14  5  7 13 15
+%macro IDCT32_PASS1_END 2 ; low, high
+    paddd                m8, m11, [r4+128*%1]
+    paddd                m9, m11, [cq+128*%1]
+    psubd               m10, m8, m%1  ; out 16+n
+    paddd                m8, m%1      ; out 15-n
+    paddd               m%1, m9, m%2  ; out  0+n
+    psubd                m9, m%2      ; out 31-n
+    REPX   {vpsravd x, m11}, m10, m%1, m8, m9
+    packssdw            m%1, m10      ;  0+n 16+n
+    packssdw            m%2, m8, m9   ; 15-n 31-n
+%endmacro
+    IDCT32_PASS1_END      0, 23       ;  0 16, 15 31
+    IDCT32_PASS1_END      7, 16       ;  7 23,  8 24
+    IDCT32_PASS1_END      1, 22       ;  1 17, 14 30
+    IDCT32_PASS1_END      6, 17       ;  6 22,  9 25
+    IDCT32_PASS1_END      2, 21       ;  2 18, 13 29
+    IDCT32_PASS1_END      5, 18       ;  5 21, 10 26
+    IDCT32_PASS1_END      3, 20       ;  3 19, 12 28
+    IDCT32_PASS1_END      4, 19       ;  4 20, 11 27
+.transpose_16x32:
+    mova                m14, m13
+    vpermi2q            m14, m0, m16
+    vpermt2q             m0, m12, m16
+    mova                m15, m13
+    vpermi2q            m15, m1, m17
+    vpermt2q             m1, m12, m17
+    mova                m16, m13
+    vpermi2q            m16, m2, m18
+    vpermt2q             m2, m12, m18
+    mova                m17, m13
+    vpermi2q            m17, m3, m19
+    vpermt2q             m3, m12, m19
+    mova                m18, m13
+    vpermi2q            m18, m4, m20
+    vpermt2q             m4, m12, m20
+    mova                m19, m13
+    vpermi2q            m19, m5, m21
+    vpermt2q             m5, m12, m21
+    mova                m20, m13
+    vpermi2q            m20, m6, m22
+    vpermt2q             m6, m12, m22
+    mova                m21, m13
+    vpermi2q            m21, m7, m23
+    vpermt2q             m7, m12, m23
+    punpckhwd            m8, m2, m3   ; c04 d04 c05 d05 c06 d06 c07 d07
+    punpcklwd            m2, m3       ; c00 d00 c01 d01 c02 d02 c03 d03
+    punpckhwd            m3, m0, m1   ; a04 b04 a05 b05 a06 b06 a07 b07
+    punpcklwd            m0, m1       ; a00 b00 a01 b01 a02 b02 a03 b03
+    punpckhwd            m1, m4, m5   ; e04 f04 e05 f05 e06 f06 e07 f07
+    punpcklwd            m4, m5       ; e00 f00 e01 f01 e02 f02 e03 f03
+    punpckhwd            m5, m6, m7   ; g04 h04 g05 h05 g06 h06 g07 h07
+    punpcklwd            m6, m7       ; g00 h00 g01 h01 g02 h02 g03 h03
+    punpckhwd            m7, m14, m15 ; a12 b12 a13 b13 a14 b14 a15 b15
+    punpcklwd           m14, m15      ; a08 b08 a09 b09 a10 b10 a11 b11
+    punpckhwd           m15, m16, m17 ; c12 d12 c13 d13 c14 d14 c15 d15
+    punpcklwd           m16, m17      ; c08 d08 c09 d09 c10 d10 c11 d11
+    punpckhwd           m17, m18, m19 ; e12 f12 e13 f13 e14 f14 e15 f15
+    punpcklwd           m18, m19      ; e08 f08 e09 f09 e10 f10 e11 f11
+    punpckhwd           m19, m20, m21 ; g12 h12 g13 h13 g14 h14 g15 h15
+    punpcklwd           m20, m21      ; g08 h08 g09 h09 g10 h10 g11 h11
+    punpckhdq           m21, m1, m5   ; e06 f06 g06 h06 e07 f07 g07 h07
+    punpckldq            m1, m5       ; e04 f04 g04 h04 e05 f05 g05 h05
+    punpckhdq            m5, m14, m16 ; a10 b10 c10 d10 a11 b11 c11 d11
+    punpckldq           m14, m16      ; a08 b08 c08 d08 a09 b09 c09 d09
+    punpckhdq           m16, m18, m20 ; e10 f10 g10 h10 e11 f11 g11 h11
+    punpckldq           m18, m20      ; e08 f08 g08 h08 e09 f09 g09 h09
+    punpckldq           m20, m4, m6   ; e00 f00 g00 h00 e01 f01 g01 h01
+    punpckhdq            m4, m6       ; e02 f02 g02 h02 e03 f03 g03 h03
+    punpckldq            m6, m7, m15  ; a12 b12 c12 d12 a13 b13 c13 d13
+    punpckhdq            m7, m15      ; a14 b14 c14 d14 a15 b15 c15 d15
+    punpckhdq           m15, m0, m2   ; a02 b02 c02 d02 a03 b03 c03 d03
+    punpckldq            m0, m2       ; a00 b00 c00 d00 a01 b01 c01 d01
+    punpckldq            m2, m3, m8   ; a04 b04 c04 d04 a05 b05 c05 d05
+    punpckhdq            m3, m8       ; a06 b06 c06 d06 a07 b07 c07 d07
+    punpckhdq            m8, m17, m19 ; e14 f14 g14 h14 e15 f15 g15 h15
+    punpckldq           m17, m19      ; e12 f12 g12 h12 e13 f13 g13 h13
+    ret
+.pass1_load_spill:
+    mova         [cq+64* 0], m0
+    mova         [cq+64* 2], m1
+    mova         [cq+64* 4], m2
+    mova         [cq+64* 6], m3
+    mova         [cq+64* 8], m4
+    mova         [cq+64*10], m5
+    mova         [cq+64*12], m6
+    mova         [cq+64*14], m7
+    pmulld               m0, m12, [cq+64* 1]
+    pmulld               m1, m12, [cq+64* 3]
+    pmulld               m2, m12, [cq+64* 5]
+    pmulld               m3, m12, [cq+64* 7]
+    pmulld               m4, m12, [cq+64* 9]
+    pmulld               m5, m12, [cq+64*11]
+    pmulld               m6, m12, [cq+64*13]
+    pmulld               m7, m12, [cq+64*15]
+    mova         [cq+64* 1], m23
+    mova         [cq+64* 3], m22
+    mova         [cq+64* 5], m21
+    mova         [cq+64* 7], m20
+    mova         [cq+64* 9], m19
+    mova         [cq+64*11], m18
+    mova         [cq+64*13], m17
+    mova         [cq+64*15], m16
+    ret
+.main_fast2_rect2:
+    REPX     {paddd x, m13}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+.main_fast2: ; bottom 3/4 is zero
+    pmulld              m23, m0, [o(pd_4091)] {1to16} ; t31a
+    pmulld               m0, [o(pd_201)] {1to16}      ; t16a
+    pmulld              m20, m3, [o(pd_1380)] {1to16} ; t19a
+    pmulld               m3, [o(pd_3857)] {1to16}     ; t28a
+    pmulld              m21, m2, [o(pd_3973)] {1to16} ; t27a
+    pmulld               m2, [o(pd_995)] {1to16}      ; t20a
+    pmulld               m6, m1, [o(pd_601)] {1to16}  ; t23a
+    pmulld              m17, m1, [o(pd_4052)] {1to16} ; t24a
+    REPX  {psubd x, m13, x}, m20, m6
+    REPX    {paddd  x, m13}, m23, m0, m3, m21, m2, m17
+    REPX    {psrad  x, 12 }, m20, m6, m23, m0, m3, m21, m2, m17
+    mova                 m8, m0
+    mova                m16, m23
+    mova                 m7, m20
+    mova                 m4, m3
+    mova                m19, m2
+    mova                m18, m21
+    mova                 m5, m6
+    mova                m22, m17
+    jmp .main3
+.main_fast_rect2:
+    call m(idct_8x16_internal_10bpc).round
+.main_fast: ; bottom half is zero
+    pmulld              m23, m0, [o(pd_4091)] {1to16} ; t31a
+    pmulld               m0, [o(pd_201)] {1to16}      ; t16a
+    pmulld              m16, m7, [o(pd_2751)] {1to16} ; t17a
+    pmulld               m7, [o(pd_3035)] {1to16}     ; t30a
+    pmulld              m19, m4, [o(pd_3703)] {1to16} ; t29a
+    pmulld               m4, [o(pd_1751)] {1to16}     ; t18a
+    pmulld              m20, m3, [o(pd_1380)] {1to16} ; t19a
+    pmulld               m3, [o(pd_3857)] {1to16}     ; t28a
+    pmulld              m21, m2, [o(pd_3973)] {1to16} ; t27a
+    pmulld               m2, [o(pd_995)] {1to16}      ; t20a
+    pmulld              m18, m5, [o(pd_2106)] {1to16} ; t21a
+    pmulld               m5, [o(pd_3513)] {1to16}     ; t26a
+    pmulld              m17, m6, [o(pd_3290)] {1to16} ; t25a
+    pmulld               m6, [o(pd_2440)] {1to16}     ; t22a
+    pmulld              m22, m1, [o(pd_601)] {1to16}  ; t23a
+    pmulld               m1, [o(pd_4052)] {1to16}     ; t24a
+    REPX  {psubd x, m13, x}, m16, m20, m18, m22
+    call m(idct_16x16_internal_10bpc).round3
+    jmp .main2
+.main_rect2:
+    call m(idct_8x16_internal_10bpc).round
+    call m(idct_16x16_internal_10bpc).round
+.main:
+    ITX_MULSUB_2D         0, 23,  8,  9, 10, _,  201, 4091 ; t16a, t31a
+    ITX_MULSUB_2D        16,  7,  8,  9, 10, _, 3035, 2751 ; t17a, t30a
+    ITX_MULSUB_2D         4, 19,  8,  9, 10, _, 1751, 3703 ; t18a, t29a
+    ITX_MULSUB_2D        20,  3,  8,  9, 10, _, 3857, 1380 ; t19a, t28a
+    ITX_MULSUB_2D         2, 21,  8,  9, 10, _,  995, 3973 ; t20a, t27a
+    ITX_MULSUB_2D        18,  5,  8,  9, 10, _, 3513, 2106 ; t21a, t26a
+    ITX_MULSUB_2D         6, 17,  8,  9, 10, _, 2440, 3290 ; t22a, t25a
+    ITX_MULSUB_2D        22,  1,  8,  9, 10, _, 4052,  601 ; t23a, t24a
+    call m(idct_16x16_internal_10bpc).round
+.main2:
+    call m(idct_8x16_internal_10bpc).round
+    psubd                m8, m0, m16  ; t17
+    paddd                m0, m16      ; t16
+    psubd               m16, m23, m7  ; t30
+    paddd               m23, m7       ; t31
+    REPX    {pmaxsd x, m14}, m8, m0, m16, m23
+    paddd                m7, m20, m4  ; t19
+    psubd               m20, m4       ; t18
+    REPX    {pminsd x, m15}, m8, m0, m16, m23
+    paddd                m4, m3, m19  ; t28
+    psubd                m3, m19      ; t29
+    REPX    {pmaxsd x, m14}, m7, m20, m4, m3
+    psubd               m19, m2, m18  ; t21
+    paddd                m2, m18      ; t20
+    REPX    {pminsd x, m15}, m7, m20, m4, m3
+    psubd               m18, m21, m5  ; t26
+    paddd               m21, m5       ; t27
+    REPX    {pmaxsd x, m14}, m19, m2, m18, m21
+    psubd                m5, m22, m6  ; t22
+    paddd                m6, m22      ; t23
+    REPX    {pminsd x, m15}, m19, m2, m18, m21
+    psubd               m22, m1, m17  ; t25
+    paddd               m17, m1       ; t24
+    REPX    {pmaxsd x, m14}, m5, m6, m22, m17
+    REPX    {pminsd x, m15}, m5, m6, m22, m17
+.main3:
+    vpbroadcastd        m11, [o(pd_4017)]
+    vpbroadcastd        m10, [o(pd_799)]
+    ITX_MULSUB_2D        16,  8, 9, 1, _, 13, 10, 11    ; t17a, t30a
+    ITX_MULSUB_2D         3, 20, 9, 1, _, 13, 10, 11, 2 ; t29a, t18a
+    vpbroadcastd        m11, [o(pd_2276)]
+    vpbroadcastd        m10, [o(pd_3406)]
+    ITX_MULSUB_2D        18, 19, 9, 1, _, 13, 10, 11    ; t21a, t26a
+    ITX_MULSUB_2D        22,  5, 9, 1, _, 13, 10, 11, 2 ; t25a, t22a
+    paddd                m1, m6, m2   ; t23a
+    psubd                m6, m2       ; t20a
+    psubd                m2, m17, m21 ; t27a
+    paddd               m17, m21      ; t24a
+    REPX    {pmaxsd x, m14}, m1, m6, m2, m17
+    psubd               m21, m23, m4  ; t28a
+    paddd               m23, m4       ; t31a
+    REPX    {pminsd x, m15}, m1, m6, m2, m17
+    psubd                m4, m16, m20 ; t18
+    paddd               m16, m20      ; t17
+    REPX    {pmaxsd x, m14}, m21, m23, m4, m16
+    psubd               m20, m0, m7   ; t19a
+    paddd                m0, m7       ; t16a
+    REPX    {pminsd x, m15}, m21, m23, m4, m16
+    psubd                m7, m8, m3   ; t29
+    paddd                m3, m8       ; t30
+    REPX    {pmaxsd x, m14}, m20, m0, m7, m3
+    paddd                m8, m5, m18  ; t22
+    psubd                m5, m18      ; t21
+    REPX    {pminsd x, m15}, m20, m0, m7, m3
+    psubd               m18, m22, m19 ; t26
+    paddd               m22, m19      ; t25
+    REPX    {pmaxsd x, m14}, m8, m5, m18, m22
+    vpbroadcastd        m11, [o(pd_3784)]
+    vpbroadcastd        m10, [o(pd_1567)]
+    REPX    {pminsd x, m15}, m8, m5, m18, m22
+    ITX_MULSUB_2D        21, 20, 9, 19, _, 13, 10, 11    ; t19,  t28
+    ITX_MULSUB_2D         2,  6, 9, 19, _, 13, 10, 11, 2 ; t27,  t20
+    ITX_MULSUB_2D         7,  4, 9, 19, _, 13, 10, 11    ; t18a, t29a
+    ITX_MULSUB_2D        18,  5, 9, 19, _, 13, 10, 11, 2 ; t26a, t21a
+    psubd               m19, m0, m1   ; t23
+    paddd                m0, m1       ; t16
+    paddd                m1, m8, m16  ; t17a
+    psubd                m8, m16, m8  ; t22a
+    REPX    {pmaxsd x, m14}, m19, m0, m1, m8
+    psubd               m16, m23, m17 ; t24
+    paddd               m23, m17      ; t31
+    REPX    {pminsd x, m15}, m19, m0, m1, m8
+    psubd               m17, m3, m22  ; t25a
+    paddd               m22, m3       ; t30a
+    REPX    {pmaxsd x, m14}, m16, m23, m17, m22
+    paddd                m3, m6, m21  ; t19a
+    psubd                m6, m21, m6  ; t20a
+    REPX    {pminsd x, m15}, m16, m23, m17, m22
+    paddd               m21, m18, m4  ; t29
+    psubd               m18, m4, m18  ; t26
+    REPX    {pmaxsd x, m14}, m3, m6, m21, m18
+    psubd                m4, m20, m2  ; t27a
+    paddd               m20, m2       ; t28a
+    REPX    {pminsd x, m15}, m3, m6, m21, m18
+    paddd                m2, m7, m5   ; t18
+    psubd                m7, m5       ; t21
+    REPX    {pmaxsd x, m14}, m4, m20, m2, m7
+    REPX    {pminsd x, m15}, m4, m20, m2, m7
+    REPX    {pmulld x, m12}, m18, m16, m4, m17, m7, m19, m6, m8
+    REPX    {paddd  x, m13}, m18, m16, m4, m17
+    psubd                m5, m18, m7  ; t21a
+    paddd               m18, m7       ; t26a
+    psubd                m7, m16, m19 ; t23a
+    paddd               m16, m19      ; t24a
+    REPX    {psrad  x, 12 }, m5, m18, m7, m16
+    paddd               m19, m4, m6   ; t27
+    psubd                m4, m6       ; t20
+    psubd                m6, m17, m8  ; t22
+    paddd               m17, m8       ; t25
+    REPX    {psrad  x, 12 }, m19, m4, m6, m17
+    ret
+
+cglobal inv_txfm_add_identity_identity_32x16_10bpc, 4, 7, 16, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m10, [pw_2896x8]
+    vpbroadcastd        m11, [pw_1697x16]
+    vpbroadcastd        m13, [pw_2048]
+    vpbroadcastd        m15, [pixel_10bpc_max]
+    lea                  r6, [strideq*9]
+    pxor                m14, m14
+    cmp                eobd, 151
+    jl .main
+    mov                  r4, dstq
+    call .main
+    add                  cq, 64*12
+    lea                dstq, [r4+32]
+.main:
+    call .main_internal
+    add                  cq, 64*4
+    pmulhrsw             m1, m13, m2
+    pmulhrsw             m3, m13, m4
+    pmulhrsw             m5, m13, m6
+    pmulhrsw             m7, m13, m8
+    call .main_internal
+    jmp m(inv_txfm_add_identity_identity_16x32_10bpc).main2
+.main_internal:
+    mova                 m8, [cq+64* 0]
+    packssdw             m8, [cq+64* 8]
+    mova                 m6, [cq+64* 1]
+    packssdw             m6, [cq+64* 9]
+    mova                 m0, [cq+64* 2]
+    packssdw             m0, [cq+64*10]
+    mova                 m2, [cq+64* 3]
+    packssdw             m2, [cq+64*11]
+    REPX  {pmulhrsw x, m10}, m8, m6, m0, m2
+    REPX  {paddsw   x, x  }, m8, m6, m0, m2
+    REPX {vpermq x, x, q3120}, m8, m6, m0, m2
+    pmulhrsw             m4, m11, m8
+    pmulhrsw             m9, m11, m6
+    paddsw               m8, m8
+    paddsw               m6, m6
+    REPX {mova [cq+64*x], m14}, 0, 1, 2, 3
+    paddsw               m8, m4
+    paddsw               m6, m9
+    pmulhrsw             m4, m11, m0
+    pmulhrsw             m9, m11, m2
+    paddsw               m0, m0
+    paddsw               m2, m2
+    REPX {mova [cq+64*x], m14}, 8, 9, 10, 11
+    paddsw               m0, m4
+    paddsw               m2, m9
+    punpcklwd            m4, m8, m6
+    punpckhwd            m8, m6
+    punpcklwd            m6, m0, m2
+    punpckhwd            m0, m2
+    punpckldq            m2, m4, m6 ; 0 1
+    punpckhdq            m4, m6     ; 2 3
+    punpckldq            m6, m8, m0 ; 4 5
+    punpckhdq            m8, m0     ; 6 7
+    ret
+
+cglobal inv_txfm_add_dct_dct_32x32_10bpc, 4, 7, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    WIN64_SPILL_XMM      30
+    cmp                eobd, 136
+    jl .fast
+    add                  cq, 64
+    cmp                eobd, 543
+    jge .full
+    call .pass1_fast ; bottomright 16x16 zero
+    mov                 r6d, 16*12
+    jmp .lefthalf
+.full:
+    call .pass1
+    mov                 r6d, 16*28
+.lefthalf:
+    mova        [cq+128* 0], m0
+    mova        [cq+128* 1], m1
+    mova        [cq+128* 2], m2
+    mova        [cq+128* 3], m3
+    mova        [cq+128* 4], m14
+    mova        [cq+128* 5], m15
+    mova        [cq+128* 6], m16
+    mova        [cq+128* 7], m17
+    mova        [cq+128* 8], m22
+    mova        [cq+128* 9], m23
+    mova        [cq+128*10], m24
+    mova        [cq+128*11], m25
+    mova        [cq+128*12], m26
+    mova        [cq+128*13], m27
+    mova        [cq+128*14], m28
+    mova        [cq+128*15], m29
+    sub                  cq, 64
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    call .pass1
+    lea                  r5, [o_base_8bpc]
+    call .pass2_start
+    pxor                m12, m12
+.right_zero_loop:
+    mova [cq+r6*8+64+128*3], m12
+    mova [cq+r6*8+64+128*2], m12
+    mova [cq+r6*8+64+128*1], m12
+    mova [cq+r6*8+64+128*0], m12
+    sub                 r6d, 16*4
+    jge .right_zero_loop
+    mov                 r6d, 16*28
+    jmp .end2
+.pass2_start:
+    mova                 m4, [cq+64+128* 0]
+    mova                 m5, [cq+64+128* 1]
+    mova                 m6, [cq+64+128* 2]
+    mova                 m7, [cq+64+128* 3]
+    mova                m18, [cq+64+128* 4]
+    mova                m19, [cq+64+128* 5]
+    mova                m20, [cq+64+128* 6]
+    mova                m21, [cq+64+128* 7]
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    mova         [cq+128*0], m14
+    mova         [cq+128*1], m15
+    mova         [cq+128*2], m16
+    mova         [cq+128*3], m17
+    mova         [cq+128*4], m18
+    mova         [cq+128*5], m19
+    mova         [cq+128*6], m20
+    mova         [cq+128*7], m21
+    mova                m14, [cq+64+128* 8]
+    mova                m15, [cq+64+128* 9]
+    mova                m16, [cq+64+128*10]
+    mova                m17, [cq+64+128*11]
+    mova                m18, [cq+64+128*12]
+    mova                m19, [cq+64+128*13]
+    mova                m20, [cq+64+128*14]
+    mova                m21, [cq+64+128*15]
+    jmp m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf
+.fast: ; topleft 16x16 nonzero
+    cmp                eobd, 36
+    jl .fast2
+    call .pass1_fast
+    lea                  r5, [o_base_8bpc]
+    call .pass2_fast_start
+    jmp .end
+.pass2_fast_start:
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+    mova         [cq+128*0], m14
+    mova         [cq+128*1], m15
+    mova         [cq+128*2], m16
+    mova         [cq+128*3], m17
+    mova         [cq+128*4], m18
+    mova         [cq+128*5], m19
+    mova         [cq+128*6], m20
+    mova         [cq+128*7], m21
+    jmp m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast
+.fast2: ; topleft 8x8 nonzero
+    movshdup             m7, [o(permB)]
+    mova                ym0, [cq+128*0]
+    mova                ym1, [cq+128*4]
+    mova                ym4, [cq+128*2]
+    mova                ym5, [cq+128*6]
+    mova               ym16, [cq+128*1]
+    mova                ym2, [cq+128*5]
+    mova                ym3, [cq+128*3]
+    mova               ym17, [cq+128*7]
+    mov                 r6d, 16*4
+    vpermq               m0, m7, m0 ;  0  0
+    vpermq               m1, m7, m1 ;  4  4
+    vpermt2q             m4, m7, m5 ;  2  6
+    vpermt2q            m16, m7, m2 ;  1  5
+    vpermt2q            m17, m7, m3 ;  7  3
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).main_fast2
+    call m(idct_16x16_internal_10bpc).main_end
+    call .pass2_fast2_start
+.end:
+    pxor                m12, m12
+.end2:
+    call .pass2_end
+.zero_loop:
+    mova    [cq+r6*8+128*3], m12
+    mova    [cq+r6*8+128*2], m12
+    mova    [cq+r6*8+128*1], m12
+    mova    [cq+r6*8+128*0], m12
+    sub                 r6d, 16*4
+    jge .zero_loop
+    WIN64_RESTORE_XMM
+    vzeroupper
+    ret
+.pass2_fast2_start:
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).transpose_8x32
+    lea                  r5, [o_base_8bpc]
+    punpckhqdq          m22, m0, m2 ; 1
+    punpcklqdq           m0, m2     ; 0
+    punpcklqdq           m1, m5, m7 ; 4
+    punpckhqdq          m24, m5, m7 ; 5
+    punpcklqdq          m14, m3, m4 ; 2
+    punpckhqdq          m23, m3, m4 ; 3
+    punpcklqdq          m15, m6, m8 ; 6
+    punpckhqdq          m25, m6, m8 ; 7
+    mova                m10, m13
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast2
+    mova         [cq+128*0], m14
+    mova         [cq+128*1], m15
+    mova         [cq+128*2], m16
+    mova         [cq+128*3], m17
+    mova         [cq+128*4], m18
+    mova         [cq+128*5], m19
+    mova         [cq+128*6], m20
+    mova         [cq+128*7], m21
+    jmp m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast2
+.pass2_end:
+    psubsw               m9, m0, m29 ; out31
+    paddsw               m0, m29     ; out0
+    psubsw              m29, m1, m28 ; out30
+    paddsw               m1, m28     ; out1
+    psubsw              m28, m2, m27 ; out29
+    paddsw               m2, m27     ; out2
+    psubsw              m27, m3, m26 ; out28
+    paddsw               m3, m26     ; out3
+    psubsw              m26, m4, m25 ; out27
+    paddsw               m4, m25     ; out4
+    psubsw              m25, m5, m24 ; out26
+    paddsw               m5, m24     ; out5
+    psubsw              m24, m6, m23 ; out25
+    paddsw               m6, m23     ; out6
+    psubsw              m23, m7, m22 ; out24
+    paddsw               m7, m22     ; out7
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x8_start
+    mova                 m0, [cq+128*0]
+    mova                 m1, [cq+128*1]
+    mova                 m2, [cq+128*2]
+    mova                 m3, [cq+128*3]
+    mova                 m4, [cq+128*4]
+    mova                 m5, [cq+128*5]
+    mova                 m6, [cq+128*6]
+    mova                 m7, [cq+128*7]
+    psubsw              m22, m0, m21 ; out23
+    paddsw               m0, m21     ; out8
+    psubsw              m21, m1, m20 ; out22
+    paddsw               m1, m20     ; out9
+    psubsw              m20, m2, m19 ; out21
+    paddsw               m2, m19     ; out10
+    psubsw              m19, m3, m18 ; out20
+    paddsw               m3, m18     ; out11
+    psubsw              m18, m4, m17 ; out19
+    paddsw               m4, m17     ; out12
+    psubsw              m17, m5, m16 ; out18
+    paddsw               m5, m16     ; out13
+    psubsw              m16, m6, m15 ; out17
+    paddsw               m6, m15     ; out14
+    psubsw              m15, m7, m14 ; out16
+    paddsw               m7, m14     ; out15
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x8
+    pmulhrsw             m0, m11, m15
+    pmulhrsw             m1, m11, m16
+    pmulhrsw             m2, m11, m17
+    pmulhrsw             m3, m11, m18
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x4
+    pmulhrsw             m0, m11, m19
+    pmulhrsw             m1, m11, m20
+    pmulhrsw             m2, m11, m21
+    pmulhrsw             m3, m11, m22
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x4
+    pmulhrsw             m0, m11, m23
+    pmulhrsw             m1, m11, m24
+    pmulhrsw             m2, m11, m25
+    pmulhrsw             m3, m11, m26
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x4
+    pmulhrsw             m0, m11, m27
+    pmulhrsw             m1, m11, m28
+    pmulhrsw             m2, m11, m29
+    pmulhrsw             m3, m11, m9
+    jmp m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x4
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 32
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_32x16_10bpc).dconly2
+.pass1_fast:
+    mova                 m0, [cq+128* 0]
+    mova                 m1, [cq+128* 4]
+    mova                 m2, [cq+128* 8]
+    mova                 m3, [cq+128*12]
+    mov                 r6d, 16*12
+    call m(idct_8x16_internal_10bpc).main_fast
+    mova                m16, [cq+128* 2]
+    mova                m17, [cq+128* 6]
+    mova                m18, [cq+128*10]
+    mova                m19, [cq+128*14]
+    call m(idct_16x16_internal_10bpc).main_fast
+    call .pass1_load_spill
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_fast
+    jmp .pass1_end
+.pass1:
+    mova                 m0, [cq+128* 0]
+    mova                 m1, [cq+128* 4]
+    mova                 m2, [cq+128* 8]
+    mova                 m3, [cq+128*12]
+    mova                 m4, [cq+128*16]
+    mova                 m5, [cq+128*20]
+    mova                 m6, [cq+128*24]
+    mova                 m7, [cq+128*28]
+    call m(idct_8x16_internal_10bpc).main
+    mova                m16, [cq+128* 2]
+    mova                m17, [cq+128* 6]
+    mova                m18, [cq+128*10]
+    mova                m19, [cq+128*14]
+    mova                m20, [cq+128*18]
+    mova                m21, [cq+128*22]
+    mova                m22, [cq+128*26]
+    mova                m23, [cq+128*30]
+    call m(idct_16x16_internal_10bpc).main
+    call .pass1_load_spill
+    mova                m16, [cq+128*17]
+    mova                m17, [cq+128*19]
+    mova                m18, [cq+128*21]
+    mova                m19, [cq+128*23]
+    mova                m20, [cq+128*25]
+    mova                m21, [cq+128*27]
+    mova                m22, [cq+128*29]
+    mova                m23, [cq+128*31]
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main
+.pass1_end:
+    vpbroadcastd        m11, [o(pd_2)]
+    lea                  r4, [cq+128*8]
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).idct32_pass1_end
+    punpckhqdq          m22, m0, m20  ;  1
+    punpcklqdq           m0, m20      ;  0
+    punpckhqdq          m24, m2, m1   ;  5
+    punpcklqdq           m1, m2, m1   ;  4
+    punpcklqdq           m2, m14, m18 ;  8
+    punpckhqdq          m26, m14, m18 ;  9
+    punpcklqdq          m14, m15, m4  ;  2
+    punpckhqdq          m23, m15, m4  ;  3
+    punpckhqdq          m25, m3, m21  ;  7
+    punpcklqdq          m15, m3, m21  ;  6
+    punpckhqdq          m28, m6, m17  ; 13
+    punpcklqdq           m3, m6, m17  ; 12
+    punpckhqdq          m27, m5, m16  ; 11
+    punpcklqdq          m16, m5, m16  ; 10
+    punpckhqdq          m29, m7, m8   ; 15
+    punpcklqdq          m17, m7, m8   ; 14
+    ret
+.pass1_load_spill:
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).idct16_sumsub
+    mova        [cq+128* 0], m0
+    mova                 m0, [cq+128* 1]
+    mova        [cq+128* 1], m1
+    mova        [cq+128* 2], m2
+    mova                 m1, [cq+128* 3]
+    mova                 m2, [cq+128* 5]
+    mova        [cq+128* 3], m3
+    mova        [cq+128* 4], m4
+    mova                 m3, [cq+128* 7]
+    mova                 m4, [cq+128* 9]
+    mova        [cq+128* 5], m5
+    mova        [cq+128* 6], m6
+    mova        [cq+128* 7], m7
+    mova                 m5, [cq+128*11]
+    mova                 m6, [cq+128*13]
+    mova                 m7, [cq+128*15]
+    mova        [cq+128* 8], m23
+    mova        [cq+128* 9], m22
+    mova        [cq+128*10], m21
+    mova        [cq+128*11], m20
+    mova        [cq+128*12], m19
+    mova        [cq+128*13], m18
+    mova        [cq+128*14], m17
+    mova        [cq+128*15], m16
+    ret
+
+cglobal inv_txfm_add_identity_identity_32x32_10bpc, 4, 7, 16, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m13, [pw_8192]
+    vpbroadcastd        m15, [pixel_10bpc_max]
+    pxor                m14, m14
+    lea                  r6, [strideq*9]
+    cmp                eobd, 136
+    jl .main
+    mov                  r4, dstq
+    call .main
+    add                  cq, 64-128*4
+    lea                dstq, [dstq+strideq*8]
+    call .main
+    add                  cq, 128*12-64
+    lea                dstq, [r4+32]
+    cmp                eobd, 543
+    jl .main
+    call .main
+    add                  cq, 64-128*4
+    lea                dstq, [dstq+strideq*8]
+.main:
+    call .main_internal
+    add                  cq, 128*4
+    pmulhrsw             m1, m13, m2
+    pmulhrsw             m3, m13, m4
+    pmulhrsw             m5, m13, m6
+    pmulhrsw             m7, m13, m8
+    call .main_internal
+    jmp m(inv_txfm_add_identity_identity_16x32_10bpc).main2
+.main_internal:
+    mova                 m8, [cq+128* 0]
+    packssdw             m8, [cq+128* 8]
+    mova                 m6, [cq+128* 1]
+    packssdw             m6, [cq+128* 9]
+    mova                 m0, [cq+128* 2]
+    packssdw             m0, [cq+128*10]
+    mova                 m2, [cq+128* 3]
+    packssdw             m2, [cq+128*11]
+    REPX {vpermq x, x, q3120}, m8, m6, m0, m2
+    REPX {mova [cq+128*x], m14}, 0, 1, 2, 3
+    punpcklwd            m4, m8, m6
+    punpckhwd            m8, m6
+    punpcklwd            m6, m0, m2
+    punpckhwd            m0, m2
+    REPX {mova [cq+128*x], m14}, 8, 9, 10, 11
+    punpckldq            m2, m4, m6 ; 0 1
+    punpckhdq            m4, m6     ; 2 3
+    punpckldq            m6, m8, m0 ; 4 5
+    punpckhdq            m8, m0     ; 6 7
+    ret
+
+cglobal inv_txfm_add_dct_dct_16x64_10bpc, 4, 7, 0, dst, stride, c, eob
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+
+    PROLOGUE 4, 7, 32, -8*mmsize, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    cmp                eobd, 36
+    jl .fast
+    call .pass1
+    cmp                eobd, 151
+    jge .full
+    lea                  r5, [o_base_8bpc]
+
+    punpckhwd           m22, m0, m0
+    punpckhwd           m23, m1, m1
+    punpckhwd           m24, m2, m2
+    punpckhwd           m25, m3, m3
+    punpckhwd           m26, m4, m4
+    punpckhwd           m27, m5, m5
+    punpckhwd           m28, m6, m6
+    punpckhwd           m29, m7, m7
+    punpcklwd           m21, m1, m1
+    punpcklwd           m14, m3, m3
+    punpcklwd           m18, m5, m5
+    punpcklwd           m15, m7, m7
+    pxor                 m9, m9
+    punpcklwd            m9, m9, m0
+    punpcklwd            m8, m2, m2
+    punpcklwd            m7, m4, m4
+    punpcklwd            m1, m6, m6
+    call m(idct_16x16_internal_8bpc).main_fast2
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast2
+    mova     [rsp+mmsize*0], m14
+    mova     [rsp+mmsize*1], m15
+    mova     [rsp+mmsize*2], m16
+    mova     [rsp+mmsize*3], m17
+    mova     [rsp+mmsize*4], m18
+    mova     [rsp+mmsize*5], m19
+    mova     [rsp+mmsize*6], m20
+    mova     [rsp+mmsize*7], m21
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_oddhalf_fast
+
+    pxor                m12, m12
+    mov                 r3d, 64*3
+.zero_loop:
+    REPX {mova [cq+r3*8+128*x], m12}, 0, 1, 2, 3
+    sub                 r3d, 64
+    jge .zero_loop
+
+    jmp .pass2_end
+.full:
+    mova         [cq+128*0], m0
+    mova         [cq+128*1], m1
+    mova         [cq+128*2], m2
+    mova         [cq+128*3], m3
+    mova         [cq+128*4], m4
+    mova         [cq+128*5], m5
+    mova         [cq+128*6], m6
+    mova         [cq+128*7], m7
+    add                  cq, 64
+    call .pass1
+    sub                  cq, 64
+    mova                m22, [cq+128*0] ;  0  1
+    mova                m23, [cq+128*1] ;  2  3
+    mova                m24, [cq+128*2] ;  4  5
+    mova                m25, [cq+128*3] ;  6  7
+    mova                m26, [cq+128*4] ;  8  9
+    mova                m27, [cq+128*5] ; 10 11
+    mova                m28, [cq+128*6] ; 12 13
+    mova                m29, [cq+128*7] ; 14 15
+    mova         [cq+64* 8], m0
+    mova         [cq+64* 9], m1
+    mova         [cq+64*10], m2
+    mova         [cq+64*11], m3
+    mova         [cq+64*12], m4
+    mova         [cq+64*13], m5
+    mova         [cq+64*14], m6
+    mova         [cq+64*15], m7
+    lea                  r5, [o_base_8bpc]
+
+    punpcklwd           m20, m1, m1
+    punpcklwd           m16, m3, m3
+    punpcklwd           m19, m5, m5
+    punpcklwd           m17, m7, m7
+    punpcklwd            m8, m24, m24 ;  4
+    punpcklwd            m5, m2, m2   ; 20
+    punpcklwd            m1, m28, m28 ; 12
+    punpcklwd            m7, m26, m26 ;  8
+    punpcklwd            m3, m4, m4   ; 24
+    punpcklwd            m4, m6, m6   ; 28
+    pxor                 m9, m9
+    punpcklwd            m6, m9, m0   ; __ 16
+    mova                 m0, m4
+    punpcklwd            m9, m9, m22  ; __  0
+    call m(idct_16x16_internal_8bpc).main_fast
+    punpcklwd           m21, m23, m23 ;  2
+    punpcklwd           m15, m29, m29 ; 14
+    punpcklwd           m18, m27, m27 ; 10
+    punpcklwd           m14, m25, m25 ;  6
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    mova     [rsp+mmsize*0], m14
+    mova     [rsp+mmsize*1], m15
+    mova     [rsp+mmsize*2], m16
+    mova     [rsp+mmsize*3], m17
+    mova     [rsp+mmsize*4], m18
+    mova     [rsp+mmsize*5], m19
+    mova     [rsp+mmsize*6], m20
+    mova     [rsp+mmsize*7], m21
+    mova                m21, [cq+64*15]
+    mova                m14, [cq+64* 8]
+    mova                m17, [cq+64*11]
+    mova                m18, [cq+64*12]
+    mova                m19, [cq+64*13]
+    mova                m16, [cq+64*10]
+    mova                m15, [cq+64* 9]
+    mova                m20, [cq+64*14]
+    REPX   {punpckhwd x, x}, m22, m21, m14, m29, m26, m17, m18, m25, \
+                             m24, m19, m16, m27, m28, m15, m20, m23
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_oddhalf
+
+    pxor                m12, m12
+    mov                 r3d, 32*7
+.full_zero_loop:
+    REPX {mova [cq+r3*8+64*x], m12}, 0, 1, 2, 3
+    sub                 r3d, 32
+    jge .full_zero_loop
+
+    jmp .pass2_end
+.fast:
+    mova                ym0, [cq+128*0]
+    mova                ym2, [cq+128*4]
+    movshdup             m8, [o(permB)]
+    mova                ym1, [cq+128*2]
+    mova                ym3, [cq+128*6]
+    mova                ym4, [cq+128*1]
+    mova                ym5, [cq+128*3]
+    mova                ym6, [cq+128*5]
+    mova                ym7, [cq+128*7]
+    vpermt2q             m0, m8, m2 ; 0 4
+    vpermt2q             m1, m8, m3 ; 2 6
+    vpermt2q             m4, m8, m5 ; 1 3
+    vpermt2q             m7, m8, m6 ; 7 5
+    call m(idct_8x8_internal_10bpc).main_fast
+    call m(idct_16x8_internal_10bpc).main_fast
+    vpbroadcastd        m11, [o(pd_2)]
+    call m(idct_8x16_internal_10bpc).main_end2
+    mova                 m8, [o(idct8x32p)]
+    packssdw             m0, m4
+    packssdw             m1, m5
+    packssdw             m2, m6
+    packssdw             m3, m7
+    mova                 m6, [dup16_perm]
+    vpermb               m0, m8, m0
+    vpermb               m2, m8, m2
+    vprold               m8, 16
+    vpermb               m1, m8, m1
+    vpermb               m3, m8, m3
+    punpckldq            m4, m0, m2
+    punpckhdq            m0, m2
+    punpckldq            m2, m1, m3
+    punpckhdq            m1, m3
+    punpckldq           m21, m4, m2
+    punpckhdq           m14, m4, m2
+    punpckldq           m18, m0, m1
+    punpckhdq           m15, m0, m1
+    vpord                m7, m6, [o(pb_32)] {1to16}
+    vpermb              m22, m7, m21 ; 1
+    pmovzxwd             m9, ym21    ; 0
+    vpermb               m8, m6, m18 ; 4
+    vpermb              m24, m7, m18 ; 5
+    vpermb              m21, m6, m14 ; 2
+    vpermb              m23, m7, m14 ; 3
+    vpermb              m14, m6, m15 ; 6
+    vpermb              m25, m7, m15 ; 7
+    lea                  r5, [o_base_8bpc]
+    pslld                m9, 16
+
+    pxor                 m7, m7
+    REPX {mova x, m7}, m1, m18, m15, m26, m27, m28, m29
+
+    call m(idct_16x16_internal_8bpc).main_fast2
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast2
+    mova     [rsp+mmsize*0], m14
+    mova     [rsp+mmsize*1], m15
+    mova     [rsp+mmsize*2], m16
+    mova     [rsp+mmsize*3], m17
+    mova     [rsp+mmsize*4], m18
+    mova     [rsp+mmsize*5], m19
+    mova     [rsp+mmsize*6], m20
+    mova     [rsp+mmsize*7], m21
+
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_oddhalf_fast
+
+    pxor                m12, m12
+    REPX {mova [cq+128*x], ym12}, 0, 1, 2, 3, 4, 5, 6, 7
+.pass2_end:
+    movshdup            m30, [permC]
+    vpbroadcastd        m11, [pw_2048]
+    vpbroadcastd        m13, [pixel_10bpc_max]
+    lea                  r6, [strideq*3]
+    psrlq               m31, m30, 8
+    vpermq               m8, m30, m0
+    vpermq               m9, m31, m1
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m2
+    vpermq               m9, m31, m3
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m4
+    vpermq               m9, m31, m5
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m6
+    vpermq               m9, m31, m7
+    call m(idct_16x8_internal_10bpc).write_16x4
+
+    mova                 m1, [rsp+mmsize*0]
+    mova                 m2, [rsp+mmsize*1]
+    mova                 m3, [rsp+mmsize*2]
+    mova                 m4, [rsp+mmsize*3]
+    mova                 m5, [rsp+mmsize*4]
+    mova                 m6, [rsp+mmsize*5]
+    mova                 m7, [rsp+mmsize*6]
+    mova                 m8, [rsp+mmsize*7]
+
+    paddsw               m0, m1, m21
+    psubsw              m21, m1, m21
+    paddsw               m1, m2, m20
+    psubsw              m20, m2, m20
+    paddsw               m2, m3, m19
+    psubsw              m19, m3, m19
+    paddsw               m3, m4, m18
+    psubsw              m18, m4, m18
+    paddsw               m4, m5, m17
+    psubsw              m17, m5, m17
+    paddsw               m5, m6, m16
+    psubsw              m16, m6, m16
+    paddsw               m6, m7, m15
+    psubsw              m15, m7, m15
+    paddsw               m7, m8, m14
+    psubsw              m14, m8, m14
+
+    vpermq               m8, m30, m0
+    vpermq               m9, m31, m1
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m2
+    vpermq               m9, m31, m3
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m4
+    vpermq               m9, m31, m5
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m6
+    vpermq               m9, m31, m7
+    call m(idct_16x8_internal_10bpc).write_16x4
+
+    vpermq               m8, m30, m14
+    vpermq               m9, m31, m15
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m16
+    vpermq               m9, m31, m17
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m18
+    vpermq               m9, m31, m19
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m20
+    vpermq               m9, m31, m21
+    call m(idct_16x8_internal_10bpc).write_16x4
+
+    vpermq               m8, m30, m22
+    vpermq               m9, m31, m23
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m24
+    vpermq               m9, m31, m25
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m26
+    vpermq               m9, m31, m27
+    call m(idct_16x8_internal_10bpc).write_16x4
+    vpermq               m8, m30, m28
+    vpermq               m9, m31, m29
+    call m(idct_16x8_internal_10bpc).write_16x4
+    RET
+.pass1:
+    mova                 m0, [cq+128* 0]
+    mova                 m1, [cq+128* 2]
+    mova                 m2, [cq+128* 4]
+    mova                 m3, [cq+128* 6]
+    mova                 m4, [cq+128* 8]
+    mova                 m5, [cq+128*10]
+    mova                 m6, [cq+128*12]
+    mova                 m7, [cq+128*14]
+    call m(idct_8x16_internal_10bpc).main
+    mova                m16, [cq+128* 1]
+    mova                m17, [cq+128* 3]
+    mova                m18, [cq+128* 5]
+    mova                m19, [cq+128* 7]
+    mova                m20, [cq+128* 9]
+    mova                m21, [cq+128*11]
+    mova                m22, [cq+128*13]
+    mova                m23, [cq+128*15]
+    call m(idct_16x16_internal_10bpc).main
+    call m(idct_16x16_internal_10bpc).main_end
+    jmp m(idct_16x16_internal_10bpc).main_end3
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 64
+    add                 r6d, 640
+    sar                 r6d, 10
+    jmp m(inv_txfm_add_dct_dct_16x8_10bpc).dconly2
+
+cglobal inv_txfm_add_dct_dct_32x64_10bpc, 4, 7, 0, dst, stride, c, eob
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE 4, 7, 32, -64*40, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    cmp                eobd, 136
+    jl .fast
+    add                  cq, 64
+    cmp                eobd, 543
+    jge .full
+    call .pass1_fast ; bottomright 16x16 zero
+    jmp .lefthalf
+.full:
+    call .pass1
+    mov                 r3d, 16*28
+.lefthalf:
+    mova        [cq+128* 0], m27
+    mova        [cq+128* 1], m14
+    mova        [cq+128* 2], m28
+    mova        [cq+128* 3], m15
+    mova        [cq+128* 4], m22
+    mova        [cq+128* 5], m23
+    mova        [cq+128* 6], m24
+    mova        [cq+128* 7], m25
+    mova        [cq+128* 8], m0
+    mova        [cq+128* 9], m26
+    mova        [cq+128*10], m20
+    mova        [cq+128*11], m21
+    mova        [cq+128*12], m18
+    mova        [cq+128*13], m16
+    mova        [cq+128*14], m17
+    mova        [cq+128*15], m3
+    sub                  cq, 64
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    call .pass1
+    call .pass2_start
+
+    pxor                m31, m31
+.right_zero_loop:
+    REPX {mova [cq+r3*8+64+128*x], m31}, 0, 1, 2, 3
+    sub                 r3d, 16*4
+    jge .right_zero_loop
+    mov                 r3d, 16*28
+    jmp .left_zero_loop
+.pass2_start:
+    vpbroadcastd        m10, [o(pd_2048)]
+    lea                  r5, [o_base_8bpc]
+
+    lea                  r4, [rsp+gprsize]
+    mova                 m1, [cq+128*15+64]
+    mova                 m2, [cq+128* 8+64]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    mova                 m0, m21
+    mova                 m1, [cq+128*12+64]
+    mova                 m2, [cq+128*11+64]
+    mova                 m3, m18
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    mova                 m0, m20
+    mova                 m1, [cq+128*13+64]
+    mova                 m2, [cq+128*10+64]
+    mova                 m3, m16
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    mova                 m0, m26
+    mova                 m1, [cq+128*14+64]
+    mova                 m2, [cq+128* 9+64]
+    mova                 m3, m17
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part2
+
+    mova                 m0, m27
+    mova                 m1, m28
+    mova                 m2, [cq+128* 0+64]
+    mova                 m3, [cq+128* 2+64]
+    mova                m16, [cq+128* 1+64]
+    mova                m17, [cq+128* 3+64]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+    mova                m26, [cq+128* 4+64]
+    mova                m27, [cq+128* 5+64]
+    mova                m28, [cq+128* 6+64]
+    mova                m29, [cq+128* 7+64]
+    mova        [rsp+64*32+gprsize], m14
+    mova        [rsp+64*33+gprsize], m15
+    mova        [rsp+64*34+gprsize], m16
+    mova        [rsp+64*35+gprsize], m17
+    mova        [rsp+64*36+gprsize], m18
+    mova        [rsp+64*37+gprsize], m19
+    mova        [rsp+64*38+gprsize], m20
+    mova        [rsp+64*39+gprsize], m21
+    jmp m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast
+.fast: ; topleft 16x16 nonzero
+    cmp                eobd, 36
+    jl .fast2
+    call .pass1_fast
+    vpbroadcastd        m10, [o(pd_2048)]
+    call .pass2_fast_start
+    jmp .end
+.fast2: ; topleft 8x8 nonzero
+    movshdup             m7, [o(permB)]
+    mova                ym0, [cq+128*0]
+    mova                ym1, [cq+128*4]
+    mova                ym4, [cq+128*2]
+    mova                ym5, [cq+128*6]
+    mova               ym16, [cq+128*1]
+    mova                ym2, [cq+128*5]
+    mova                ym3, [cq+128*3]
+    mova               ym17, [cq+128*7]
+    mov                 r3d, 16*4
+    vpermq               m0, m7, m0 ;  0  0
+    vpermq               m1, m7, m1 ;  4  4
+    vpermt2q             m4, m7, m5 ;  2  6
+    vpermt2q            m16, m7, m2 ;  1  5
+    vpermt2q            m17, m7, m3 ;  7  3
+    REPX    {pmulld x, m12}, m0, m1, m4, m16, m17
+    REPX    {paddd  x, m13}, m0, m1, m4, m16, m17
+    REPX    {psrad  x, 12 }, m0, m1, m4, m16, m17
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).main_fast2
+    vpbroadcastd        m11, [o(pd_1)]
+    call m(idct_16x16_internal_10bpc).main_end2
+
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).transpose_8x32
+    punpcklqdq          m27, m0, m2 ; 0
+    punpckhqdq           m0, m2     ; 1
+    punpcklqdq          m22, m3, m4 ; 2
+    punpckhqdq          m26, m3, m4 ; 3
+    punpcklqdq          m14, m5, m7 ; 4
+    punpckhqdq          m20, m5, m7 ; 5
+    punpcklqdq          m23, m6, m8 ; 6
+    punpckhqdq          m21, m6, m8 ; 7
+
+    mova                m10, m13
+    call .pass2_fast2_start
+.end:
+
+    pxor                m31, m31
+
+.left_zero_loop:
+    REPX {mova [cq+r3*8+128*x], m31}, 0, 1, 2, 3
+    sub                 r3d, 16*4
+    jge .left_zero_loop
+
+    call .pass2_end
+    RET
+.pass2_end:
+    DEFINE_ARGS dst, stride, _, dst2, stride32, stklo, stkhi
+    vpbroadcastd        m30, [pixel_10bpc_max]
+    vpbroadcastd        m13, [pw_2048]
+
+    mov           stride32q, strideq
+    shl           stride32q, 5
+    lea              stkhiq, [rsp+31*mmsize+gprsize]
+    lea               dst2q, [dstq+stride32q]
+    lea              stkloq, [rsp+gprsize]
+    sub               dst2q, strideq    ; dst31
+
+    paddsw               m8, m0, m29    ; t0[idct32]
+    psubsw               m9, m0, m29    ; t31[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m1, m28    ; t1[idct32]
+    psubsw               m9, m1, m28    ; t30[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m2, m27    ; t2[idct32]
+    psubsw               m9, m2, m27    ; t29[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m3, m26    ; t3[idct32]
+    psubsw               m9, m3, m26    ; t28[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m4, m25    ; t4[idct32]
+    psubsw               m9, m4, m25    ; t27[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m5, m24    ; t5[idct32]
+    psubsw               m9, m5, m24    ; t26[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m6, m23    ; t6[idct32]
+    psubsw               m9, m6, m23    ; t25[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m7, m22    ; t7[idct32]
+    psubsw               m9, m7, m22    ; t24[idct32]
+    call .end_sumsub_write
+    mova                 m0, [rsp+64*32+gprsize]
+    mova                 m1, [rsp+64*33+gprsize]
+    mova                 m2, [rsp+64*34+gprsize]
+    mova                 m3, [rsp+64*35+gprsize]
+    mova                 m4, [rsp+64*36+gprsize]
+    mova                 m5, [rsp+64*37+gprsize]
+    mova                 m6, [rsp+64*38+gprsize]
+    mova                 m7, [rsp+64*39+gprsize]
+    paddsw               m8, m0, m21    ; t8[idct32]
+    psubsw               m9, m0, m21    ; t23[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m1, m20    ; t9[idct32]
+    psubsw               m9, m1, m20    ; t22[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m2, m19    ; t10[idct32]
+    psubsw               m9, m2, m19    ; t21[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m3, m18    ; t11[idct32]
+    psubsw               m9, m3, m18    ; t20[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m4, m17    ; t12[idct32]
+    psubsw               m9, m4, m17    ; t19[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m5, m16    ; t13[idct32]
+    psubsw               m9, m5, m16    ; t18[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m6, m15    ; t14[idct32]
+    psubsw               m9, m6, m15    ; t17[idct32]
+    call .end_sumsub_write
+    paddsw               m8, m7, m14    ; t15[idct32]
+    psubsw               m9, m7, m14    ; t16[idct32]
+    ; fall-through
+.end_sumsub_write:
+    mova                m10, [stkhiq]   ; t63-n
+    mova                m12, [stkloq]   ; t32+n
+    psubsw              m11, m8, m10    ; out63-n
+    paddsw               m8, m10        ; out0 +n
+    psubsw              m10, m9, m12    ; out32+n
+    paddsw               m9, m12        ; out32-n
+    REPX  {pmulhrsw x, m13}, m11, m8, m10, m9
+    paddw                m8, [dstq]
+    paddw                m9, [dst2q]
+    paddw               m10, [dstq+stride32q]
+    paddw               m11, [dst2q+stride32q]
+    REPX  {pminsw   x, m30}, m11, m8, m10, m9
+    REPX  {pmaxsw   x, m31}, m11, m8, m10, m9
+    mova  [dstq           ], m8
+    mova  [dst2q          ], m9
+    mova  [dstq +stride32q], m10
+    mova  [dst2q+stride32q], m11
+    add              stkloq, mmsize
+    sub              stkhiq, mmsize
+    add                dstq, strideq
+    sub               dst2q, strideq
+    ret
+.pass2_fast_start:
+    lea                  r5, [o_base_8bpc]
+    lea                  r4, [rsp+gprsize]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast
+    mova                 m0, m21
+    mova                 m3, m18
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast
+    mova                 m0, m20
+    mova                 m3, m16
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast
+    mova                 m0, m26
+    mova                 m3, m17
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part2
+
+    mova                 m0, m27
+    mova                 m1, m28
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast2
+    mova        [rsp+64*32+gprsize], m14
+    mova        [rsp+64*33+gprsize], m15
+    mova        [rsp+64*34+gprsize], m16
+    mova        [rsp+64*35+gprsize], m17
+    mova        [rsp+64*36+gprsize], m18
+    mova        [rsp+64*37+gprsize], m19
+    mova        [rsp+64*38+gprsize], m20
+    mova        [rsp+64*39+gprsize], m21
+    jmp m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast2
+.pass2_fast2_start:
+    lea                  r5, [o_base_8bpc]
+    lea                  r4, [rsp+gprsize]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast2
+    mova                 m0, m21
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast2
+    mova                 m0, m20
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast2
+    mova                 m0, m26
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast2
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part2
+
+    mova                 m0, m27
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast3
+    mova        [rsp+64*32+gprsize], m14
+    mova        [rsp+64*33+gprsize], m15
+    mova        [rsp+64*34+gprsize], m16
+    mova        [rsp+64*35+gprsize], m17
+    mova        [rsp+64*36+gprsize], m18
+    mova        [rsp+64*37+gprsize], m19
+    mova        [rsp+64*38+gprsize], m20
+    mova        [rsp+64*39+gprsize], m21
+    jmp m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast3
+.dconly:
+    DEFINE_ARGS dst, stride, c, eob
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 64
+    jmp m(inv_txfm_add_dct_dct_32x16_10bpc).dconly3
+.pass1_fast:
+    pmulld               m0, m12, [cq+128* 0]
+    pmulld               m1, m12, [cq+128* 4]
+    pmulld               m2, m12, [cq+128* 8]
+    pmulld               m3, m12, [cq+128*12]
+    mov                 r3d, 16*12
+    call m(idct_8x16_internal_10bpc).main_fast_rect2
+    pmulld              m16, m12, [cq+128* 2]
+    pmulld              m17, m12, [cq+128* 6]
+    pmulld              m18, m12, [cq+128*10]
+    pmulld              m19, m12, [cq+128*14]
+    call m(idct_16x16_internal_10bpc).main_fast_rect2
+    call .pass1_load_spill
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_fast_rect2
+    jmp .pass1_end
+.pass1:
+    pmulld               m0, m12, [cq+128* 0]
+    pmulld               m1, m12, [cq+128* 4]
+    pmulld               m2, m12, [cq+128* 8]
+    pmulld               m3, m12, [cq+128*12]
+    pmulld               m4, m12, [cq+128*16]
+    pmulld               m5, m12, [cq+128*20]
+    pmulld               m6, m12, [cq+128*24]
+    pmulld               m7, m12, [cq+128*28]
+    call m(idct_8x16_internal_10bpc).main_rect2
+    pmulld              m16, m12, [cq+128* 2]
+    pmulld              m17, m12, [cq+128* 6]
+    pmulld              m18, m12, [cq+128*10]
+    pmulld              m19, m12, [cq+128*14]
+    pmulld              m20, m12, [cq+128*18]
+    pmulld              m21, m12, [cq+128*22]
+    pmulld              m22, m12, [cq+128*26]
+    pmulld              m23, m12, [cq+128*30]
+    call m(idct_16x16_internal_10bpc).main_rect2
+    call .pass1_load_spill
+    pmulld              m16, m12, [cq+128*17]
+    pmulld              m17, m12, [cq+128*19]
+    pmulld              m18, m12, [cq+128*21]
+    pmulld              m19, m12, [cq+128*23]
+    pmulld              m20, m12, [cq+128*25]
+    pmulld              m21, m12, [cq+128*27]
+    pmulld              m22, m12, [cq+128*29]
+    pmulld              m23, m12, [cq+128*31]
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_rect2
+.pass1_end:
+    vpbroadcastd        m11, [o(pd_1)]
+    lea                  r4, [cq+128*8]
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).idct32_pass1_end
+    punpcklqdq          m27, m0, m20  ;  0
+    punpckhqdq           m0, m20      ;  1
+    punpcklqdq          m24, m5, m16  ; 10
+    punpckhqdq          m16, m5, m16  ; 11
+    punpcklqdq          m23, m3, m21  ;  6
+    punpckhqdq          m21, m3, m21  ;  7
+    punpcklqdq          m25, m7, m8   ; 14
+    punpckhqdq           m3, m7, m8   ; 15
+    punpcklqdq          m22, m15, m4  ;  2
+    punpckhqdq          m26, m15, m4  ;  3
+    punpcklqdq          m15, m6, m17  ; 12
+    punpckhqdq          m17, m6, m17  ; 13
+    punpcklqdq          m28, m14, m18 ;  8
+    punpckhqdq          m18, m14, m18 ;  9
+    punpcklqdq          m14, m2, m1   ;  4
+    punpckhqdq          m20, m2, m1   ;  5
+    ret
+.pass1_load_spill:
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).idct16_sumsub
+    mova        [cq+128* 0], m0
+    pmulld               m0, m12, [cq+128* 1]
+    mova        [cq+128* 1], m1
+    mova        [cq+128* 2], m2
+    pmulld               m1, m12, [cq+128* 3]
+    pmulld               m2, m12, [cq+128* 5]
+    mova        [cq+128* 3], m3
+    mova        [cq+128* 4], m4
+    pmulld               m3, m12, [cq+128* 7]
+    pmulld               m4, m12, [cq+128* 9]
+    mova        [cq+128* 5], m5
+    mova        [cq+128* 6], m6
+    mova        [cq+128* 7], m7
+    pmulld               m5, m12, [cq+128*11]
+    pmulld               m6, m12, [cq+128*13]
+    pmulld               m7, m12, [cq+128*15]
+    mova        [cq+128* 8], m23
+    mova        [cq+128* 9], m22
+    mova        [cq+128*10], m21
+    mova        [cq+128*11], m20
+    mova        [cq+128*12], m19
+    mova        [cq+128*13], m18
+    mova        [cq+128*14], m17
+    mova        [cq+128*15], m16
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x16_10bpc, 4, 7, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+
+    PROLOGUE 4, 7, 32, -64*32, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    cmp                eobd, 36
+    jl .fast ; 8x8
+    cmp                eobd, 151
+    jge .full ; 16x16
+    lea                  r4, [idct64_mul_16bpc]
+    lea                  r6, [rsp+4*64]
+    mova                 m0, [cq+64* 1]
+    mova                 m3, [cq+64*15]
+    call .main_part1_fast
+    mova                 m0, [cq+64* 7]
+    mova                 m3, [cq+64* 9]
+    call .main_part1_fast
+    mova                 m0, [cq+64* 5]
+    mova                 m3, [cq+64*11]
+    call .main_part1_fast
+    mova                 m0, [cq+64* 3]
+    mova                 m3, [cq+64*13]
+    call .main_part1_fast
+    call .main_part2
+    mova                 m0, [cq+64* 0]
+    mova                 m1, [cq+64* 8]
+    mova                m16, [cq+64* 4]
+    mova                m17, [cq+64*12]
+    call m(idct_8x16_internal_10bpc).main_fast2
+    call m(idct_16x16_internal_10bpc).main_fast2
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).idct16_sumsub
+    call .pass1_load_spill
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_fast2
+    mov                 r6d, 12*8
+    jmp .idct64_end
+.full:
+    lea                  r4, [idct64_mul_16bpc]
+    lea                  r6, [rsp+4*64]
+    mova                 m0, [cq+64* 1]
+    mova                 m1, [cq+64*31]
+    mova                 m2, [cq+64*17]
+    mova                 m3, [cq+64*15]
+    call .main_part1
+    mova                 m0, [cq+64* 7]
+    mova                 m1, [cq+64*25]
+    mova                 m2, [cq+64*23]
+    mova                 m3, [cq+64* 9]
+    call .main_part1
+    mova                 m0, [cq+64* 5]
+    mova                 m1, [cq+64*27]
+    mova                 m2, [cq+64*21]
+    mova                 m3, [cq+64*11]
+    call .main_part1
+    mova                 m0, [cq+64* 3]
+    mova                 m1, [cq+64*29]
+    mova                 m2, [cq+64*19]
+    mova                 m3, [cq+64*13]
+    call .main_part1
+    call .main_part2
+    mova                 m0, [cq+64* 0]
+    mova                 m1, [cq+64* 8]
+    mova                 m2, [cq+64*16]
+    mova                 m3, [cq+64*24]
+    mova                m16, [cq+64* 4]
+    mova                m17, [cq+64*12]
+    mova                m18, [cq+64*20]
+    mova                m19, [cq+64*28]
+    call m(idct_8x16_internal_10bpc).main_fast
+    call m(idct_16x16_internal_10bpc).main_fast
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).idct16_sumsub
+    call .pass1_load_spill
+    mova                 m4, [cq+64*18]
+    mova                 m5, [cq+64*22]
+    mova                 m6, [cq+64*26]
+    mova                 m7, [cq+64*30]
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_fast
+    mov                 r6d, 28*8
+    jmp .idct64_end
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 16
+.dconly1:
+    add                 r6d, 640
+    sar                 r6d, 10
+.dconly2:
+    vpbroadcastd         m3, [o(dconly_10bpc)]
+    imul                r6d, 181
+    add                 r6d, 2176
+    sar                 r6d, 12
+    vpbroadcastw         m2, r6d
+    paddsw               m2, m3
+.dconly_loop:
+    paddsw               m0, m2, [dstq+64*0]
+    paddsw               m1, m2, [dstq+64*1]
+    psubusw              m0, m3
+    psubusw              m1, m3
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    add                dstq, strideq
+    dec                 r3d
+    jg .dconly_loop
+    ret
+.pass1_load_spill:
+    mova         [cq+64* 0], m0
+    mova                 m0, [cq+64* 2]
+    mova         [cq+64* 2], m1
+    mova                 m1, [cq+64* 6]
+    mova         [cq+64* 4], m2
+    mova         [cq+64* 6], m3
+    mova                 m2, [cq+64*10]
+    mova                 m3, [cq+64*14]
+    mova         [cq+64* 8], m4
+    mova         [cq+64*10], m5
+    mova         [cq+64*12], m6
+    mova         [cq+64*14], m7
+    mova         [cq+64* 1], m23
+    mova         [cq+64* 3], m22
+    mova         [cq+64* 5], m21
+    mova         [cq+64* 7], m20
+    mova         [cq+64* 9], m19
+    mova         [cq+64*11], m18
+    mova         [cq+64*13], m17
+    mova         [cq+64*15], m16
+    ret
+ALIGN function_align
+.main_part1_fast_rect2:
+    REPX     {paddd x, m13}, m0, m3
+    REPX     {psrad x, 12 }, m0, m3
+.main_part1_fast:
+    pmulld               m7, m0, [r4+4*0]{bcstd}    ; t63a
+    pmulld               m0, [r4+4*1]{bcstd}        ; t32a
+    pmulld               m4, m3, [r4+4*6]{bcstd}    ; t60a
+    pmulld               m3, [r4+4*7]{bcstd}        ; t35a
+    vpbroadcastd        m10, [r4+4*8]
+    vpbroadcastd        m11, [r4+4*9]
+    REPX     {paddd x, m13}, m7, m0, m4, m3
+    REPX     {psrad x, 12 }, m7, m0, m4, m3
+    mova                 m8, m0
+    mova                 m1, m7
+    mova                 m6, m3
+    mova                 m2, m4
+    jmp .main_part1b
+.main_part1_rect2:
+    REPX     {paddd x, m13}, m0, m1, m2, m3
+    REPX     {psrad x, 12 }, m0, m1, m2, m3
+.main_part1: ; idct64 steps 1-5
+    ; in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+    ; in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+    ; in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+    ; in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+    pmulld               m7, m0, [r4+4*0]{bcstd}    ; t63a
+    pmulld               m0, [r4+4*1]{bcstd}        ; t32a
+    pmulld               m6, m1, [r4+4*2]{bcstd}    ; t62a
+    pmulld               m1, [r4+4*3]{bcstd}        ; t33a
+    pmulld               m5, m2, [r4+4*4]{bcstd}    ; t61a
+    pmulld               m2, [r4+4*5]{bcstd}        ; t34a
+    pmulld               m4, m3, [r4+4*6]{bcstd}    ; t60a
+    pmulld               m3, [r4+4*7]{bcstd}        ; t35a
+    vpbroadcastd        m10, [r4+4*8]
+    vpbroadcastd        m11, [r4+4*9]
+    REPX     {paddd x, m13}, m7, m0, m6, m1, m5, m2, m4, m3
+    REPX     {psrad x, 12 }, m0, m1, m7, m6, m2, m3, m5, m4
+    psubd                m8, m0, m1 ; t33
+    paddd                m0, m1     ; t32
+    psubd                m1, m7, m6 ; t62
+    paddd                m7, m6     ; t63
+    psubd                m6, m3, m2 ; t34
+    paddd                m3, m2     ; t35
+    psubd                m2, m4, m5 ; t61
+    paddd                m4, m5     ; t60
+.main_part1b:
+    REPX    {pmaxsd x, m14}, m8, m1, m6, m2
+    REPX    {pminsd x, m15}, m8, m1, m6, m2
+    ITX_MULSUB_2D         1, 8, 5, 9, _, 13, 10, 11    ; t33a, t62a
+    ITX_MULSUB_2D         2, 6, 5, 9, _, 13, 10, 11, 2 ; t61a, t34a
+    REPX    {pmaxsd x, m14}, m0, m3, m7, m4
+    REPX    {pminsd x, m15}, m0, m3, m7, m4
+    vpbroadcastd        m10, [r4+4*10]
+    vpbroadcastd        m11, [r4+4*11]
+    psubd                m5, m0, m3 ; t35a
+    paddd                m0, m3     ; t32a
+    psubd                m3, m7, m4 ; t60a
+    paddd                m7, m4     ; t63a
+    psubd                m4, m1, m6 ; t34
+    paddd                m1, m6     ; t33
+    psubd                m6, m8, m2 ; t61
+    paddd                m8, m2     ; t62
+    REPX    {pmaxsd x, m14}, m5, m3, m4, m6
+    REPX    {pminsd x, m15}, m5, m3, m4, m6
+    ITX_MULSUB_2D         3, 5, 2, 9, _, 13, 10, 11 ; t35,  t60
+    ITX_MULSUB_2D         6, 4, 2, 9, _, 13, 10, 11 ; t34a, t61a
+    REPX    {pmaxsd x, m14}, m0, m7, m1, m8
+    REPX    {pminsd x, m15}, m0, m7, m1, m8
+    add                  r4, 4*12
+    mova          [r6-64*4], m0
+    mova          [r6+64*3], m7
+    mova          [r6-64*3], m1
+    mova          [r6+64*2], m8
+    mova          [r6-64*2], m6
+    mova          [r6+64*1], m4
+    mova          [r6-64*1], m3
+    mova          [r6+64*0], m5
+    add                  r6, 64*8
+    ret
+.main_part2: ; idct64 steps 6-9
+    lea                  r4, [r6+64*3]
+    sub                  r6, 64*4
+    vpbroadcastd        m10, [pd_1567]
+    vpbroadcastd        m11, [pd_3784]
+.main_part2_loop:
+    mova                 m0, [r6-64*32] ; t32a
+    mova                 m1, [r4-64*24] ; t39a
+    mova                 m2, [r4-64*32] ; t63a
+    mova                 m3, [r6-64*24] ; t56a
+    mova                 m4, [r6-64*16] ; t40a
+    mova                 m5, [r4-64* 8] ; t47a
+    mova                 m6, [r4-64*16] ; t55a
+    mova                 m7, [r6-64* 8] ; t48a
+    psubd                m8, m0, m1 ; t39
+    paddd                m0, m1     ; t32
+    psubd                m1, m2, m3 ; t56
+    paddd                m2, m3     ; t63
+    psubd                m3, m5, m4 ; t40
+    paddd                m5, m4     ; t47
+    psubd                m4, m7, m6 ; t55
+    paddd                m7, m6     ; t48
+    REPX    {pmaxsd x, m14}, m8, m1, m3, m4
+    REPX    {pminsd x, m15}, m8, m1, m3, m4
+    ITX_MULSUB_2D         1, 8, 6, 9, _, 13, 10, 11    ; t39a, t56a
+    ITX_MULSUB_2D         4, 3, 6, 9, _, 13, 10, 11, 2 ; t55a, t40a
+    REPX    {pmaxsd x, m14}, m0, m2, m5, m7
+    REPX    {pminsd x, m15}, m0, m5, m2, m7
+    psubd                m6, m2, m7 ; t48a
+    paddd                m2, m7     ; t63a
+    psubd                m7, m0, m5 ; t47a
+    paddd                m0, m5     ; t32a
+    psubd                m5, m8, m4 ; t55
+    paddd                m8, m4     ; t56
+    psubd                m4, m1, m3 ; t40
+    paddd                m1, m3     ; t39
+    REPX    {pmaxsd x, m14}, m6, m7, m5, m4
+    REPX    {pminsd x, m15}, m6, m7, m5, m4
+    REPX    {pmulld x, m12}, m6, m7, m5, m4
+    REPX    {pmaxsd x, m14}, m2, m0, m8, m1
+    REPX    {pminsd x, m15}, m2, m0, m8, m1
+    paddd                m6, m13
+    paddd                m5, m13
+    psubd                m3, m6, m7 ; t47
+    paddd                m6, m7     ; t48
+    psubd                m7, m5, m4 ; t40a
+    paddd                m5, m4     ; t55a
+    REPX      {psrad x, 12}, m3, m6, m7, m5
+    mova         [r4-64* 8], m2
+    mova         [r6-64*32], m0
+    mova         [r6-64* 8], m8
+    mova         [r4-64*32], m1
+    mova         [r4-64*24], m3
+    mova         [r6-64*16], m6
+    mova         [r6-64*24], m7
+    mova         [r4-64*16], m5
+    add                  r6, 64
+    sub                  r4, 64
+    cmp                  r6, r4
+    jl .main_part2_loop
+    ret
+.idct64_main_end:
+%macro IDCT64_PASS1_END 9
+    mova                m%5, [%9+%1*128]    ; t0+n [idct32] + idct64 rounding
+    psubd               m%6, m%5, m%2       ; out31-n [idct32] = t31-n [idct64]
+    paddd               m%5, m%2            ; out0+n [idct32] = t0+n [idct64]
+    REPX    {pmaxsd x, m14}, m%6, m%5
+    REPX    {pminsd x, m15}, m%6, m%5
+    REPX    {paddd  x, m11}, m%6, m%5
+    mova                m%2, [r3+%3*64]     ; t32+n [idct64]
+    mova                m%7, [r3+%4*64]     ; t63-n [idct64]
+    psubd               m%8, m%5, m%7       ; out63-n
+    paddd               m%5, m%7            ; out0+n
+    psubd               m%7, m%6, m%2       ; out32+n
+    paddd               m%6, m%2            ; out31-n
+    REPX   {vpsravd x, m11}, m%8, m%5, m%7, m%6
+%endmacro
+
+%macro IDCT64_PASS1_ENDx4 1
+%assign %%m1 %1         ; t32+n
+%assign %%m2 (7-%1)     ; t39-n
+%assign %%m3 (8+%1)     ; t40+n
+%assign %%m4 (15-%1)    ; t47-n
+%assign %%m5 (16+%1)    ; t48+n
+%assign %%m6 (23-%1)    ; t55-n
+%assign %%m7 (24+%1)    ; t56+n
+%assign %%m8 (31-%1)    ; t63-n
+
+%assign %%r1 %1         ; t16+n
+%assign %%r2 (7-%1)     ; t23-n
+%assign %%r3 (16+%1)    ; t24-n
+%assign %%r4 (23-%1)    ; t31-n
+
+%assign %%c1 (%1)       ; t0/8+n
+%assign %%c2 (7-%1)     ; t7/15-n
+
+    IDCT64_PASS1_END   %%c1, %%r4, %%m1, %%m8, 24, 25, 26, 27, cq ; out0/31/32/63
+    IDCT64_PASS1_END   %%c1, %%r1, %%m4, %%m5, 28, 29, 30, 31, r4 ; out15/16/47/48
+    packssdw      m %+ %%r1, m24, m29
+    packssdw      m %+ %%r4, m28, m25
+    packssdw            m26, m31
+    packssdw            m30, m27
+    mova   [r3+%%m5*mmsize], m26
+    mova   [r3+%%m8*mmsize], m30
+    IDCT64_PASS1_END   %%c2, %%r3, %%m2, %%m7, 24, 25, 26, 27, cq ; out7/24/39/56
+    IDCT64_PASS1_END   %%c2, %%r2, %%m3, %%m6, 28, 29, 30, 31, r4 ; out8/23/40/55
+    packssdw      m %+ %%r2, m24, m29
+    packssdw      m %+ %%r3, m28, m25
+    packssdw            m26, m31
+    packssdw            m30, m27
+    mova   [r3+%%m6*mmsize], m26
+    mova   [r3+%%m7*mmsize], m30
+%endmacro
+    IDCT64_PASS1_ENDx4    0
+    IDCT64_PASS1_ENDx4    1
+    IDCT64_PASS1_ENDx4    2
+    IDCT64_PASS1_ENDx4    3
+    ret
+.idct64_end:
+    vpbroadcastd        m11, [o(pd_2)]
+    lea                  r4, [cq+64]
+    mov                  r3, rsp
+    lea                  r5, [o_base_8bpc]
+    call .idct64_main_end
+
+    pxor                m12, m12
+.zero_loop:
+    REPX {mova [cq+r6*8+64*x], m12}, 0, 1, 2, 3
+    sub                 r6d, 8*4
+    jge .zero_loop
+
+    lea                  r3, [strideq*3]
+    mov                  r4, dstq
+    call .pass2
+    mova                 m0, [rsp+16*mmsize]
+    mova                 m1, [rsp+17*mmsize]
+    mova                 m2, [rsp+18*mmsize]
+    mova                 m3, [rsp+19*mmsize]
+    mova                 m4, [rsp+20*mmsize]
+    mova                 m5, [rsp+21*mmsize]
+    mova                 m6, [rsp+22*mmsize]
+    mova                 m7, [rsp+23*mmsize]
+    mova                m16, [rsp+24*mmsize]
+    mova                m17, [rsp+25*mmsize]
+    mova                m18, [rsp+26*mmsize]
+    mova                m19, [rsp+27*mmsize]
+    mova                m20, [rsp+28*mmsize]
+    mova                m21, [rsp+29*mmsize]
+    mova                m22, [rsp+30*mmsize]
+    mova                m23, [rsp+31*mmsize]
+    lea                dstq, [r4+64]
+    call .pass2
+    RET
+.pass2:
+    psrlq               m12, [permC], 24    ;  0  2  8 10  1  3  9 11
+    psrlq               m13, m12, 32        ;  4  6 12 14  5  7 13 15
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).transpose_16x32
+
+    punpckhqdq          m19, m5, m16  ; 11
+    punpcklqdq           m5, m16      ; 10
+    punpckhqdq          m16, m2, m1   ;  5
+    punpcklqdq           m2, m1       ;  4
+    punpcklqdq           m1, m15, m4  ;  2
+    punpckhqdq          m15, m4       ;  3
+    punpcklqdq           m4, m14, m18 ;  8
+    punpckhqdq          m18, m14, m18 ;  9
+    punpckhqdq          m14, m0, m20  ;  1
+    punpcklqdq           m0, m20      ;  0
+    punpckhqdq          m20, m6, m17  ; 13
+    punpcklqdq           m6, m17      ; 12
+    punpckhqdq          m17, m3, m21  ;  7
+    punpcklqdq           m3, m21      ;  6
+    punpckhqdq          m21, m7, m8   ; 15
+    punpcklqdq           m7, m8       ; 14
+
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+.write:
+    vpbroadcastd        m11, [pw_2048]
+    pxor                m12, m12
+    vpbroadcastd        m13, [pixel_10bpc_max]
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x8
+    pmulhrsw             m0, m11, m14
+    pmulhrsw             m1, m11, m15
+    pmulhrsw             m2, m11, m16
+    pmulhrsw             m3, m11, m17
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x4
+    pmulhrsw             m0, m11, m18
+    pmulhrsw             m1, m11, m19
+    pmulhrsw             m2, m11, m20
+    pmulhrsw             m3, m11, m21
+    jmp m(inv_txfm_add_dct_dct_32x8_10bpc).write_32x4
+.fast: ; 8x8 packed
+    movshdup             m7, [o(permB)]
+    mova                ym0, [cq+64*1]
+    mova                ym2, [cq+64*5]
+    mova                ym3, [cq+64*3]
+    mova                ym1, [cq+64*7]
+    vpermt2q             m0, m7, m2 ;  1  5
+    vpermt2q             m1, m7, m3 ;  7  3
+    call .main_oddhalf_packed
+    mova    [rsp+ 0*mmsize], m0
+    mova    [rsp+ 1*mmsize], m1
+    mova    [rsp+ 2*mmsize], m2
+    mova    [rsp+ 3*mmsize], m3
+    mova    [rsp+ 4*mmsize], m4
+    mova    [rsp+ 5*mmsize], m5
+    mova    [rsp+ 6*mmsize], m6
+    mova    [rsp+ 7*mmsize], m7
+    mova    [rsp+ 8*mmsize], m16
+    mova    [rsp+ 9*mmsize], m17
+    mova    [rsp+10*mmsize], m18
+    mova    [rsp+11*mmsize], m19
+    mova    [rsp+12*mmsize], m20
+    mova    [rsp+13*mmsize], m21
+    mova    [rsp+14*mmsize], m22
+    mova    [rsp+15*mmsize], m23
+
+    movshdup             m7, [o(permB)]
+    mova                ym0, [cq+64*0]
+    mova                ym4, [cq+64*4]
+    mova               ym16, [cq+64*2]
+    mova                ym5, [cq+64*6]
+    vpermt2q            m16, m7, m5 ;  2  6
+    vpermq               m0, m7, m0 ;  0  0
+    vpermq               m4, m7, m4 ;  4  4
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).main_fast3
+    ; m0-7,9,16-22 contain un-sumsub'ed dct32 output data
+
+    ; zero input coefs
+    pxor                m12, m12
+    REPX {mova [cq+x*64], ym12}, 0, 1, 2, 3, 4, 5, 6, 7
+
+    vpbroadcastd        m11, [o(pd_2)]
+    call .main_end
+    lea                  r3, [strideq*3]
+    mov                  r4, dstq
+    call .pass2_fast
+    mova                 m0, m24
+    mova                 m1, m25
+    mova                 m2, m26
+    mova                 m3, m27
+    mova                 m4, m28
+    mova                 m5, m29
+    mova                 m6, m30
+    mova                 m7, m31
+    lea                dstq, [r4+64]
+    lea                  r5, [o_base]
+    call .pass2_fast
+    RET
+.pass2_fast:
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).transpose_8x32
+    lea                  r5, [o_base_8bpc]
+    punpckhqdq          m14, m0, m2 ; 1
+    punpcklqdq           m0, m2     ; 0
+    punpcklqdq           m1, m3, m4 ; 2
+    punpckhqdq          m15, m3, m4 ; 3
+    punpcklqdq           m2, m5, m7 ; 4
+    punpckhqdq          m16, m5, m7 ; 5
+    punpcklqdq           m3, m6, m8 ; 6
+    punpckhqdq          m17, m6, m8 ; 7
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+    jmp .write
+.main_end:
+
+%macro IDCT64_PASS1_PACKED_END 7
+    psubd               m%5, m%1, m%2       ; out31-n [idct32] = t31-n [idct64]
+    paddd               m%1, m%2            ; out0+n [idct32] = t0+n [idct64]
+    REPX    {pmaxsd x, m14}, m%5, m%1
+    REPX    {pminsd x, m15}, m%5, m%1
+    REPX    {paddd  x, m11}, m%5, m%1
+    mova                m%2, [rsp+%6*64+gprsize]    ; t32+n [idct64]
+    mova                m%3, [rsp+%7*64+gprsize]    ; t63-n [idct64]
+    psubd               m%4, m%1, m%3       ; out63-n
+    paddd               m%1, m%3            ; out0+n
+    psubd               m%3, m%5, m%2       ; out32+n
+    paddd               m%2, m%5            ; out31-n
+    REPX   {vpsravd x, m11}, m%4, m%1, m%3, m%2
+%endmacro
+
+    IDCT64_PASS1_PACKED_END  0, 22, 24, 10, 12, 0, 15   ; out0/1,31/30,32/33,63/62
+    IDCT64_PASS1_PACKED_END  7,  9, 31, 13, 12, 7,  8   ; out15/14,16/17,47/46,48/49
+    packssdw             m0, m9
+    packssdw             m7, m22
+    packssdw            m24, m13
+    packssdw            m31, m10
+    IDCT64_PASS1_PACKED_END  1, 21, 25, 10, 12, 1, 14   ; out3/2,28/29,35/34,60/61
+    IDCT64_PASS1_PACKED_END  6, 16, 30, 13, 12, 6,  9   ; out12/13,19/18,44/45,51/50
+    packssdw             m1, m16
+    packssdw             m6, m21
+    packssdw            m25, m13
+    packssdw            m30, m10
+    IDCT64_PASS1_PACKED_END  2, 20, 26, 10, 12, 2, 13   ; out4/5,27/26,36/37,59/58
+    IDCT64_PASS1_PACKED_END  5, 17, 29, 13, 12, 5, 10   ; out11/10,20/21,43/42,52/53
+    packssdw             m2, m17
+    packssdw             m5, m20
+    packssdw            m26, m13
+    packssdw            m29, m10
+    IDCT64_PASS1_PACKED_END  3, 19, 27, 10, 12, 3, 12   ; out7/6,24/25,39/38,56/57
+    IDCT64_PASS1_PACKED_END  4, 18, 28, 13, 12, 4, 11   ; out8/9,23/22,40/41,55/54
+    packssdw             m3, m18
+    packssdw             m4, m19
+    packssdw            m27, m13
+    packssdw            m28, m10
+    ret
+.main_oddhalf_packed_rect2:
+    REPX    {paddd  x, m13}, m0, m1
+    REPX    {psrad  x, 12 }, m0, m1
+.main_oddhalf_packed:
+    ; m0=in1 in5, m1=in7 in3
+    vbroadcasti32x4      m2, [o(pd_101_501)]
+    vbroadcasti32x4      m3, [o(pd_m700_m301)]
+    vbroadcasti32x4      m4, [o(pd_4095_4065)]
+    vbroadcasti32x4      m5, [o(pd_4036_4085)]
+    pmulld               m2, m0
+    pmulld               m3, m1
+    pmulld               m0, m4
+    pmulld               m1, m5
+    REPX    {paddd  x, m13}, m2, m3, m0, m1
+    REPX    {psrad  x, 12 }, m2, m3, m0, m1
+
+    ; m2=t32a t40a -> t32/33 t40/41, m3=t39a t47a -> t38/39 t46/47
+    ; m0=t63a t55a -> t62/63 t54/55, m1=t56a t48a -> t56/57 t48/49
+    ; end of step 1-2
+
+    vbroadcasti32x4     m10, [o(pd_401_1931)]
+    vbroadcasti32x4     m11, [o(pd_4076_3612)]
+    mova                 m4, m0
+    mova                 m5, m2
+    ITX_MULSUB_2D         4, 5, 8, 9, _, 13, 10, 11
+    vbroadcasti32x4     m10, [o(pd_3166_3920)]
+    vbroadcasti32x4     m11, [o(pd_2598_1189)]
+    mova                 m6, m3
+    mova                 m7, m1
+    ITX_MULSUB_2D         7, 6, 8, 9, _, 13, 10, 11, 2
+
+    ; m4=t33a t41a -> t41/42  t33/34,  m5=t63a t54a -> t61/62  t53/54
+    ; m6=t38a t46a -> t37/38  t45/46,  m7=t57a t49a -> t57/58  t49/50
+    ; and from earlier:
+    ; m0=t63  t55  -> t60/63a t52/55a, m1=t56  t48  -> t56/59a t48/51a
+    ; m2=t32  t40  -> t32/35a t40/43a, m3=t39  t47  -> t36/39a t44/47a
+    ; end of step 3-4
+
+    punpcklqdq          m22, m2, m4     ; t32a/33 or t35a/34
+    punpcklqdq          m21, m3, m6     ; t36a/37 or t39a/38
+    punpckhqdq          m18, m2, m4     ; t40a/41 or t43a/42
+    punpckhqdq          m17, m3, m6     ; t44a/45 or t47a/46
+    punpckhqdq           m6, m1, m7     ; t48a/49 or t51a/50
+    punpckhqdq          m19, m0, m5     ; t52a/53 or t55a/54
+    punpcklqdq           m8, m1, m7     ; t56a/57 or t59a/58
+    punpcklqdq          m23, m0, m5     ; t60a/61 or t63a/62
+    mova                 m0, m22
+    mova                 m7, m21
+    mova                 m3, m18
+    mova                m16, m17
+    mova                 m5, m6
+    mova                 m4, m19
+    mova                 m2, m8
+    mova                 m1, m23
+    ; m0/22/7/21,18/3/17/16,6/5/19/4,2/8/1/23: t32-63[a]
+
+    ; step5
+    vpbroadcastd        m10, [o(pd_799)]
+    vpbroadcastd        m11, [o(pd_4017)]
+    ITX_MULSUB_2D         1, 22, 20, 9, _, 13, 10, 11    ; t35/34a, t60/61a
+    ITX_MULSUB_2D         8,  7, 20, 9, _, 13, 10, 11, 2 ; t59/58a, t36/37a
+    vpbroadcastd        m10, [o(pd_3406)]
+    vpbroadcastd        m11, [o(pd_2276)]
+    ITX_MULSUB_2D        19,  3, 20, 9, _, 13, 10, 11    ; t43/42a, t52/53a
+    ITX_MULSUB_2D         5, 17, 20, 9, _, 13, 10, 11, 2 ; t51/50a, t44/45a
+    ; m0-1/7/21: t32-39[a], m18-19/17-16: t40-47[a]
+    ; m6-5/3-4: t48-55[a], m2/8/22-23: t56-63[a]
+
+    ; step6
+    psubd               m20, m0, m21    ; t39/38a
+    paddd                m0, m21        ; t32/33a
+    psubd               m21, m1, m7     ; t36a/37
+    paddd                m1, m7         ; t35a/34
+    REPX    {pmaxsd x, m14}, m20, m0, m21, m1
+    psubd                m7, m16, m18   ; t40/41a
+    paddd               m16, m18        ; t47/46a
+    REPX    {pminsd x, m15}, m20, m0, m21, m1
+    psubd               m18, m17, m19   ; t43a/42
+    paddd               m17, m19        ; t44a/45
+    REPX    {pmaxsd x, m14}, m7, m16, m18, m17
+    psubd               m19, m6, m4     ; t55/54a
+    paddd                m6, m4         ; t48/49a
+    REPX    {pminsd x, m15}, m7, m16, m18, m17
+    psubd                m4, m5, m3     ; t52a/53
+    paddd                m5, m3         ; t51a/50
+    REPX    {pmaxsd x, m14}, m19, m6, m4, m5
+    psubd                m3, m23, m2    ; t56/57a
+    paddd               m23, m2         ; t63/62a
+    REPX    {pminsd x, m15}, m19, m6, m4, m5
+    psubd                m2, m22, m8    ; t59a/58
+    paddd               m22, m8         ; t60a/61
+    REPX    {pmaxsd x, m14}, m3, m23, m2, m22
+    REPX    {pminsd x, m15}, m3, m23, m2, m22
+    ; m0-1: t32-35[a], m17-16: t44-47[a], m6-5: t48-51[a], m22-23: t60-63[a]
+    ; m21-20: t36-39[a], m7/18: t40-43[a], m4/19: t52-55[a], m3-2: t56-59[a]
+
+    ; step7
+    vpbroadcastd        m10, [o(pd_1567)]
+    vpbroadcastd        m11, [o(pd_3784)]
+    ITX_MULSUB_2D         2, 21, 8, 9, _, 13, 10, 11    ; t36/37a, t59/58a
+    ITX_MULSUB_2D         3, 20, 8, 9, _, 13, 10, 11    ; t39a/38, t56a/57
+    ITX_MULSUB_2D        19,  7, 8, 9, _, 13, 10, 11, 2 ; t55a/54, t40a/41
+    ITX_MULSUB_2D         4, 18, 8, 9, _, 13, 10, 11, 2 ; t52/53a, t43/42a
+    ; m0-3: t32-39[a], m7,18-16: t40-47[a], m6-4,19: t48-55[a], m20-23: t56-63[a]
+
+    ; step8
+    psubd                m8, m0, m16    ; t47a/46
+    paddd                m0, m16        ; t32a/33
+    psubd               m16, m1, m17    ; t44/45a
+    paddd                m1, m17        ; t35/34a
+    REPX    {pmaxsd x, m14}, m8, m0, m16, m1
+    psubd               m17, m2, m18    ; t43a/42
+    paddd                m2, m18        ; t36a/37
+    REPX    {pminsd x, m15}, m8, m0, m16, m1
+    psubd               m18, m3, m7     ; t40/41a
+    paddd                m3, m7         ; t39/38a
+    REPX    {pmaxsd x, m14}, m17, m2, m18, m3
+    psubd                m7, m23, m6    ; t48a/49
+    paddd               m23, m6         ; t63a/62
+    REPX    {pminsd x, m15}, m17, m2, m18, m3
+    psubd                m6, m22, m5    ; t51/50a
+    paddd               m22, m5         ; t60/61a
+    REPX    {pmaxsd x, m14}, m7, m23, m6, m22
+    psubd                m5, m21, m4    ; t52a/53
+    paddd               m21, m4         ; t59a/58
+    REPX    {pminsd x, m15}, m7, m23, m6, m22
+    psubd                m4, m20, m19   ; t55/54a
+    paddd               m20, m19        ; t56/57a
+    REPX    {pmaxsd x, m14}, m5, m21, m4, m20
+    REPX    {pminsd x, m15}, m5, m21, m4, m20
+    ; m0-3=t32-39[a], m18-16,8: t40-47[a], m7-4=t48-55[a], m20-23=t56-63[a]
+
+    ; step9
+    REPX    {pmulld x, m12}, m4, m18, m5, m17, m6, m16, m7, m8
+    REPX    {paddd  x, m13}, m4, m5, m6, m7
+    paddd               m19, m4, m18    ; t55a/54
+    psubd                m4, m18        ; t40a/41
+    paddd               m18, m5, m17    ; t52/53a
+    psubd                m5, m17        ; t43/42a
+    paddd               m17, m6, m16    ; t51a/50
+    psubd                m6, m16        ; t44a/45
+    paddd               m16, m7, m8     ; t48/49a
+    psubd                m7, m8         ; t47/46a
+    REPX    {psrad  x, 12 }, m19, m4, m18, m5, m17, m6, m16, m7
+    ; m4-7=t40-47[a], m16-19=t48-55[a]
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x32_10bpc, 4, 7, 0, dst, stride, c, eob
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+
+    PROLOGUE 4, 8, 32, -64*32, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    cmp                eobd, 136
+    jl .fast
+    add                  cq, 64
+    cmp                eobd, 543
+    jge .full
+    call .pass1_fast ; bottomright 16x16 zero
+    mov                 r7d, 16*12
+    jmp .lefthalf
+.full:
+    call .pass1
+    mov                 r7d, 16*28
+.lefthalf:
+    mova        [cq+128* 0], m0
+    mova        [cq+128* 1], m1
+    mova        [cq+128* 2], m2
+    mova        [cq+128* 3], m3
+    mova        [cq+128* 4], m14
+    mova        [cq+128* 5], m15
+    mova        [cq+128* 6], m16
+    mova        [cq+128* 7], m17
+    mova        [cq+128* 8], m22
+    mova        [cq+128* 9], m23
+    mova        [cq+128*10], m24
+    mova        [cq+128*11], m25
+    mova        [cq+128*12], m26
+    mova        [cq+128*13], m27
+    mova        [cq+128*14], m28
+    mova        [cq+128*15], m29
+    sub                  cq, 64
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    sub                 rsp, 16*64
+    call .pass1
+    add                 rsp, 16*64
+    lea                  r5, [o_base_8bpc]
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_start
+    mov                  r4, dstq
+    pxor                m12, m12
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_end
+    lea                dstq, [r4+64]
+    mova                 m0, [rsp+16*mmsize]
+    mova                 m1, [rsp+17*mmsize]
+    mova                 m2, [rsp+18*mmsize]
+    mova                 m3, [rsp+19*mmsize]
+    mova                 m4, [rsp+20*mmsize]
+    mova                 m5, [rsp+21*mmsize]
+    mova                 m6, [rsp+22*mmsize]
+    mova                 m7, [rsp+23*mmsize]
+    mova                m16, [rsp+24*mmsize]
+    mova                m17, [rsp+25*mmsize]
+    mova                m18, [rsp+26*mmsize]
+    mova                m19, [rsp+27*mmsize]
+    mova                m20, [rsp+28*mmsize]
+    mova                m21, [rsp+29*mmsize]
+    mova                m22, [rsp+30*mmsize]
+    mova                m23, [rsp+31*mmsize]
+    call .transpose
+    mova     [cq+128* 0+64], m0
+    mova     [cq+128* 1+64], m1
+    mova     [cq+128* 2+64], m2
+    mova     [cq+128* 3+64], m3
+    mova     [cq+128* 4+64], m14
+    mova     [cq+128* 5+64], m15
+    mova     [cq+128* 6+64], m16
+    mova     [cq+128* 7+64], m17
+    mova     [cq+128* 8+64], m22
+    mova     [cq+128* 9+64], m23
+    mova     [cq+128*10+64], m24
+    mova     [cq+128*11+64], m25
+    mova     [cq+128*12+64], m26
+    mova     [cq+128*13+64], m27
+    mova     [cq+128*14+64], m28
+    mova     [cq+128*15+64], m29
+    mova                 m0, [rsp+ 0*mmsize]
+    mova                 m1, [rsp+ 1*mmsize]
+    mova                 m2, [rsp+ 2*mmsize]
+    mova                 m3, [rsp+ 3*mmsize]
+    mova                 m4, [rsp+ 4*mmsize]
+    mova                 m5, [rsp+ 5*mmsize]
+    mova                 m6, [rsp+ 6*mmsize]
+    mova                 m7, [rsp+ 7*mmsize]
+    mova                m16, [rsp+ 8*mmsize]
+    mova                m17, [rsp+ 9*mmsize]
+    mova                m18, [rsp+10*mmsize]
+    mova                m19, [rsp+11*mmsize]
+    mova                m20, [rsp+12*mmsize]
+    mova                m21, [rsp+13*mmsize]
+    mova                m22, [rsp+14*mmsize]
+    mova                m23, [rsp+15*mmsize]
+    call .transpose
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_start
+    pxor                m12, m12
+.right_zero_loop:
+    mova [cq+r7*8+64+128*3], m12
+    mova [cq+r7*8+64+128*2], m12
+    mova [cq+r7*8+64+128*1], m12
+    mova [cq+r7*8+64+128*0], m12
+    sub                 r7d, 16*4
+    jge .right_zero_loop
+    mov                 r7d, 16*28
+    jmp .end
+.fast: ; topleft 16x16 nonzero
+    cmp                eobd, 36
+    jl .fast2
+    call .pass1_fast
+    lea                  r5, [o_base_8bpc]
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_fast_start
+    mov                  r4, dstq
+    pxor                m12, m12
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_end
+    lea                dstq, [r4+64]
+    mova                 m0, [rsp+16*mmsize]
+    mova                 m1, [rsp+17*mmsize]
+    mova                 m2, [rsp+18*mmsize]
+    mova                 m3, [rsp+19*mmsize]
+    mova                 m4, [rsp+20*mmsize]
+    mova                 m5, [rsp+21*mmsize]
+    mova                 m6, [rsp+22*mmsize]
+    mova                 m7, [rsp+23*mmsize]
+    mova                m16, [rsp+24*mmsize]
+    mova                m17, [rsp+25*mmsize]
+    mova                m18, [rsp+26*mmsize]
+    mova                m19, [rsp+27*mmsize]
+    mova                m20, [rsp+28*mmsize]
+    mova                m21, [rsp+29*mmsize]
+    mova                m22, [rsp+30*mmsize]
+    mova                m23, [rsp+31*mmsize]
+    call .transpose
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_fast_start
+    mov                 r7d, 16*12
+    pxor                m12, m12
+    jmp .end
+.fast2: ; topleft 8x8 nonzero
+    movshdup             m7, [o(permB)]
+    mova                ym0, [cq+128*1]
+    mova                ym2, [cq+128*5]
+    mova                ym3, [cq+128*3]
+    mova                ym1, [cq+128*7]
+    vpermt2q             m0, m7, m2 ;  1  5
+    vpermt2q             m1, m7, m3 ;  7  3
+    REPX    {pmulld x, m12}, m0, m1
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_oddhalf_packed_rect2
+    mova    [rsp+ 0*mmsize], m0
+    mova    [rsp+ 1*mmsize], m1
+    mova    [rsp+ 2*mmsize], m2
+    mova    [rsp+ 3*mmsize], m3
+    mova    [rsp+ 4*mmsize], m4
+    mova    [rsp+ 5*mmsize], m5
+    mova    [rsp+ 6*mmsize], m6
+    mova    [rsp+ 7*mmsize], m7
+    mova    [rsp+ 8*mmsize], m16
+    mova    [rsp+ 9*mmsize], m17
+    mova    [rsp+10*mmsize], m18
+    mova    [rsp+11*mmsize], m19
+    mova    [rsp+12*mmsize], m20
+    mova    [rsp+13*mmsize], m21
+    mova    [rsp+14*mmsize], m22
+    mova    [rsp+15*mmsize], m23
+
+    movshdup             m7, [o(permB)]
+    pmulld              ym0, ym12, [cq+128*0]
+    pmulld              ym4, ym12, [cq+128*4]
+    mova               ym16, [cq+128*2]
+    mova                ym5, [cq+128*6]
+    REPX    {paddd x, ym13}, ym0, ym4
+    REPX    {psrad x, 12  }, ym0, ym4
+    vpermt2q            m16, m7, m5 ;  2  6
+    vpermq               m0, m7, m0 ;  0  0
+    vpermq               m4, m7, m4 ;  4  4
+    pmulld              m16, m12
+    paddd               m16, m13
+    psrad               m16, 12
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).main_fast3
+
+    vpbroadcastd        m11, [o(pd_1)]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_end
+    mova    [rsp+16*mmsize], m24
+    mova    [rsp+17*mmsize], m25
+    mova    [rsp+18*mmsize], m26
+    mova    [rsp+19*mmsize], m27
+    mova    [rsp+20*mmsize], m28
+    mova    [rsp+21*mmsize], m29
+    mova    [rsp+22*mmsize], m30
+    mova    [rsp+23*mmsize], m31
+    vpbroadcastd        m13, [o(pd_2048)]
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_fast2_start
+    mov                 r7d, 16*4
+    mov                  r4, dstq
+    pxor                m12, m12
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_end
+    lea                dstq, [r4+64]
+    mova                 m0, [rsp+16*mmsize]
+    mova                 m1, [rsp+17*mmsize]
+    mova                 m2, [rsp+18*mmsize]
+    mova                 m3, [rsp+19*mmsize]
+    mova                 m4, [rsp+20*mmsize]
+    mova                 m5, [rsp+21*mmsize]
+    mova                 m6, [rsp+22*mmsize]
+    mova                 m7, [rsp+23*mmsize]
+    lea                  r5, [o_base]
+    vpbroadcastd        m13, [o(pd_2048)]
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_fast2_start
+    pxor                m12, m12
+.end:
+    call m(inv_txfm_add_dct_dct_32x32_10bpc).pass2_end
+.zero_loop:
+    mova    [cq+r7*8+128*3], m12
+    mova    [cq+r7*8+128*2], m12
+    mova    [cq+r7*8+128*1], m12
+    mova    [cq+r7*8+128*0], m12
+    sub                 r7d, 16*4
+    jge .zero_loop
+    RET
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 32
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 384
+    sar                 r6d, 9
+    jmp m(inv_txfm_add_dct_dct_64x16_10bpc).dconly2
+.pass1_fast:
+    lea                  r4, [idct64_mul_16bpc]
+    lea                  r6, [rsp+4*64+gprsize]
+    pmulld               m0, m12, [cq+128* 1]
+    pmulld               m3, m12, [cq+128*15]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_fast_rect2
+    pmulld               m0, m12, [cq+128* 7]
+    pmulld               m3, m12, [cq+128* 9]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_fast_rect2
+    pmulld               m0, m12, [cq+128* 5]
+    pmulld               m3, m12, [cq+128*11]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_fast_rect2
+    pmulld               m0, m12, [cq+128* 3]
+    pmulld               m3, m12, [cq+128*13]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_fast_rect2
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part2
+    pmulld               m0, m12, [cq+128* 0]
+    pmulld               m1, m12, [cq+128* 8]
+    pmulld              m16, m12, [cq+128* 4]
+    pmulld              m17, m12, [cq+128*12]
+    call m(idct_8x16_internal_10bpc).main_fast2_rect2
+    call m(idct_16x16_internal_10bpc).main_fast2_rect2
+    call .pass1_load_spill
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_fast2_rect2
+    jmp .pass1_end
+.pass1:
+    lea                  r4, [idct64_mul_16bpc]
+    lea                  r6, [rsp+4*64+gprsize]
+    pmulld               m0, m12, [cq+128* 1]
+    pmulld               m1, m12, [cq+128*31]
+    pmulld               m2, m12, [cq+128*17]
+    pmulld               m3, m12, [cq+128*15]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_rect2
+    pmulld               m0, m12, [cq+128* 7]
+    pmulld               m1, m12, [cq+128*25]
+    pmulld               m2, m12, [cq+128*23]
+    pmulld               m3, m12, [cq+128* 9]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_rect2
+    pmulld               m0, m12, [cq+128* 5]
+    pmulld               m1, m12, [cq+128*27]
+    pmulld               m2, m12, [cq+128*21]
+    pmulld               m3, m12, [cq+128*11]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_rect2
+    pmulld               m0, m12, [cq+128* 3]
+    pmulld               m1, m12, [cq+128*29]
+    pmulld               m2, m12, [cq+128*19]
+    pmulld               m3, m12, [cq+128*13]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_rect2
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part2
+    pmulld               m0, m12, [cq+128* 0]
+    pmulld               m1, m12, [cq+128* 8]
+    pmulld               m2, m12, [cq+128*16]
+    pmulld               m3, m12, [cq+128*24]
+    pmulld              m16, m12, [cq+128* 4]
+    pmulld              m17, m12, [cq+128*12]
+    pmulld              m18, m12, [cq+128*20]
+    pmulld              m19, m12, [cq+128*28]
+    call m(idct_8x16_internal_10bpc).main_fast_rect2
+    call m(idct_16x16_internal_10bpc).main_fast_rect2
+    call .pass1_load_spill
+    pmulld               m4, m12, [cq+128*18]
+    pmulld               m5, m12, [cq+128*22]
+    pmulld               m6, m12, [cq+128*26]
+    pmulld               m7, m12, [cq+128*30]
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_fast_rect2
+.pass1_end:
+    vpbroadcastd        m11, [o(pd_1)]
+    lea                  r3, [rsp+gprsize]
+    lea                  r4, [cq+8*128]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).idct64_main_end
+    ; transpose one half immediately, we can transpose lower half later
+.transpose:
+    ; transpose m0-7,16-23
+    psrlq               m12, [permC], 24    ;  0  2  8 10  1  3  9 11
+    psrlq               m13, m12, 32        ;  4  6 12 14  5  7 13 15
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).transpose_16x32
+    punpckhqdq          m22, m0, m20  ;  1
+    punpcklqdq           m0, m20      ;  0
+    punpckhqdq          m24, m2, m1   ;  5
+    punpcklqdq           m1, m2, m1   ;  4
+    punpcklqdq           m2, m14, m18 ;  8
+    punpckhqdq          m26, m14, m18 ;  9
+    punpcklqdq          m14, m15, m4  ;  2
+    punpckhqdq          m23, m15, m4  ;  3
+    punpckhqdq          m25, m3, m21  ;  7
+    punpcklqdq          m15, m3, m21  ;  6
+    punpckhqdq          m28, m6, m17  ; 13
+    punpcklqdq           m3, m6, m17  ; 12
+    punpckhqdq          m27, m5, m16  ; 11
+    punpcklqdq          m16, m5, m16  ; 10
+    punpckhqdq          m29, m7, m8   ; 15
+    punpcklqdq          m17, m7, m8   ; 14
+    ret
+.pass1_load_spill:
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).idct16_sumsub
+    mova        [cq+128* 0], m0
+    mova        [cq+128* 1], m1
+    pmulld               m0, m12, [cq+128* 2]
+    pmulld               m1, m12, [cq+128* 6]
+    mova        [cq+128* 2], m2
+    mova        [cq+128* 3], m3
+    pmulld               m2, m12, [cq+128*10]
+    pmulld               m3, m12, [cq+128*14]
+    mova        [cq+128* 4], m4
+    mova        [cq+128* 5], m5
+    mova        [cq+128* 6], m6
+    mova        [cq+128* 7], m7
+    mova        [cq+128* 8], m23
+    mova        [cq+128* 9], m22
+    mova        [cq+128*10], m21
+    mova        [cq+128*11], m20
+    mova        [cq+128*12], m19
+    mova        [cq+128*13], m18
+    mova        [cq+128*14], m17
+    mova        [cq+128*15], m16
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x64_10bpc, 4, 7, 0, dst, stride, c, eob
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+
+    PROLOGUE 4, 9, 32, -64*32, dst, stride, c, eob
+%undef cmp
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    cmp                eobd, 136
+    jl .fast
+    add                  cq, 64
+    cmp                eobd, 543
+    jge .full
+    call .pass1_fast ; bottomright 16x16 zero
+    mov                 r7d, 16*12
+    jmp .lefthalf
+.full:
+    call .pass1
+    mov                 r7d, 16*28
+.lefthalf:
+    mova        [cq+128* 0], m27
+    mova        [cq+128* 1], m14
+    mova        [cq+128* 2], m28
+    mova        [cq+128* 3], m15
+    mova        [cq+128* 4], m22
+    mova        [cq+128* 5], m23
+    mova        [cq+128* 6], m24
+    mova        [cq+128* 7], m25
+    mova        [cq+128* 8], m0
+    mova        [cq+128* 9], m26
+    mova        [cq+128*10], m20
+    mova        [cq+128*11], m21
+    mova        [cq+128*12], m18
+    mova        [cq+128*13], m16
+    mova        [cq+128*14], m17
+    mova        [cq+128*15], m3
+    sub                  cq, 64
+    vpbroadcastd        m12, [o(pd_2896)]
+    vpbroadcastd        m13, [o(pd_2048)]
+    vpbroadcastd        m14, [o(clip_18b_min)]
+    vpbroadcastd        m15, [o(clip_18b_max)]
+    sub                 rsp, 16*64
+    call .pass1
+    sub                 rsp, 24*64
+    call m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_start
+    mov                  r8, dstq
+    pxor                m31, m31
+    call m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_end
+    lea                dstq, [r8+64]
+    mova                 m0, [rsp+56*mmsize]
+    mova                 m1, [rsp+57*mmsize]
+    mova                 m2, [rsp+58*mmsize]
+    mova                 m3, [rsp+59*mmsize]
+    mova                 m4, [rsp+60*mmsize]
+    mova                 m5, [rsp+61*mmsize]
+    mova                 m6, [rsp+62*mmsize]
+    mova                 m7, [rsp+63*mmsize]
+    mova                m16, [rsp+64*mmsize]
+    mova                m17, [rsp+65*mmsize]
+    mova                m18, [rsp+66*mmsize]
+    mova                m19, [rsp+67*mmsize]
+    mova                m20, [rsp+68*mmsize]
+    mova                m21, [rsp+69*mmsize]
+    mova                m22, [rsp+70*mmsize]
+    mova                m23, [rsp+71*mmsize]
+    call .transpose
+    mova     [cq+128* 0+64], m27
+    mova     [cq+128* 1+64], m14
+    mova     [cq+128* 2+64], m28
+    mova     [cq+128* 3+64], m15
+    mova     [cq+128* 4+64], m22
+    mova     [cq+128* 5+64], m23
+    mova     [cq+128* 6+64], m24
+    mova     [cq+128* 7+64], m25
+    mova     [cq+128* 8+64], m0
+    mova     [cq+128* 9+64], m26
+    mova     [cq+128*10+64], m20
+    mova     [cq+128*11+64], m21
+    mova     [cq+128*12+64], m18
+    mova     [cq+128*13+64], m16
+    mova     [cq+128*14+64], m17
+    mova     [cq+128*15+64], m3
+    mova                 m0, [rsp+40*mmsize]
+    mova                 m1, [rsp+41*mmsize]
+    mova                 m2, [rsp+42*mmsize]
+    mova                 m3, [rsp+43*mmsize]
+    mova                 m4, [rsp+44*mmsize]
+    mova                 m5, [rsp+45*mmsize]
+    mova                 m6, [rsp+46*mmsize]
+    mova                 m7, [rsp+47*mmsize]
+    mova                m16, [rsp+48*mmsize]
+    mova                m17, [rsp+49*mmsize]
+    mova                m18, [rsp+50*mmsize]
+    mova                m19, [rsp+51*mmsize]
+    mova                m20, [rsp+52*mmsize]
+    mova                m21, [rsp+53*mmsize]
+    mova                m22, [rsp+54*mmsize]
+    mova                m23, [rsp+55*mmsize]
+    add                 rsp, 32*64
+    call .transpose
+    lea                  r5, [o_base]
+    call m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_start
+.right_zero_loop:
+    REPX {mova [cq+r7*8+64+128*x], m31}, 0, 1, 2, 3
+    sub                 r7d, 16*4
+    jge .right_zero_loop
+    mov                 r7d, 16*28
+    jmp .end
+.fast: ; topleft 16x16 nonzero
+    cmp                eobd, 36
+    jl .fast2
+    call .pass1_fast
+    sub                 rsp, 24*64
+    vpbroadcastd        m10, [o(pd_2048)]
+    call m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_fast_start
+    mov                  r8, dstq
+    pxor                m31, m31
+    call m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_end
+    lea                dstq, [r8+64]
+    mova                 m0, [rsp+40*mmsize]
+    mova                 m1, [rsp+41*mmsize]
+    mova                 m2, [rsp+42*mmsize]
+    mova                 m3, [rsp+43*mmsize]
+    mova                 m4, [rsp+44*mmsize]
+    mova                 m5, [rsp+45*mmsize]
+    mova                 m6, [rsp+46*mmsize]
+    mova                 m7, [rsp+47*mmsize]
+    mova                m16, [rsp+48*mmsize]
+    mova                m17, [rsp+49*mmsize]
+    mova                m18, [rsp+50*mmsize]
+    mova                m19, [rsp+51*mmsize]
+    mova                m20, [rsp+52*mmsize]
+    mova                m21, [rsp+53*mmsize]
+    mova                m22, [rsp+54*mmsize]
+    mova                m23, [rsp+55*mmsize]
+    add                 rsp, 16*64
+    call .transpose
+    lea                  r5, [o_base]
+    vpbroadcastd        m10, [o(pd_2048)]
+    call m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_fast_start
+    mov                 r7d, 16*12
+    jmp .end
+.fast2: ; topleft 8x8 nonzero
+    movshdup             m7, [o(permB)]
+    mova                ym0, [cq+128*1]
+    mova                ym2, [cq+128*5]
+    mova                ym3, [cq+128*3]
+    mova                ym1, [cq+128*7]
+    vpermt2q             m0, m7, m2 ;  1  5
+    vpermt2q             m1, m7, m3 ;  7  3
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_oddhalf_packed
+    mova    [rsp+ 0*mmsize], m0
+    mova    [rsp+ 1*mmsize], m1
+    mova    [rsp+ 2*mmsize], m2
+    mova    [rsp+ 3*mmsize], m3
+    mova    [rsp+ 4*mmsize], m4
+    mova    [rsp+ 5*mmsize], m5
+    mova    [rsp+ 6*mmsize], m6
+    mova    [rsp+ 7*mmsize], m7
+    mova    [rsp+ 8*mmsize], m16
+    mova    [rsp+ 9*mmsize], m17
+    mova    [rsp+10*mmsize], m18
+    mova    [rsp+11*mmsize], m19
+    mova    [rsp+12*mmsize], m20
+    mova    [rsp+13*mmsize], m21
+    mova    [rsp+14*mmsize], m22
+    mova    [rsp+15*mmsize], m23
+
+    movshdup             m7, [o(permB)]
+    mova                ym0, [cq+128*0]
+    mova                ym4, [cq+128*4]
+    mova               ym16, [cq+128*2]
+    mova                ym5, [cq+128*6]
+    vpermt2q            m16, m7, m5 ;  2  6
+    vpermq               m0, m7, m0 ;  0  0
+    vpermq               m4, m7, m4 ;  4  4
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).main_fast3
+
+    vpbroadcastd        m11, [o(pd_2)]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_end
+    sub                 rsp, 16*64
+    mova    [rsp+40*mmsize], m24
+    mova    [rsp+41*mmsize], m25
+    mova    [rsp+42*mmsize], m26
+    mova    [rsp+43*mmsize], m27
+    mova    [rsp+44*mmsize], m28
+    mova    [rsp+45*mmsize], m29
+    mova    [rsp+46*mmsize], m30
+    mova    [rsp+47*mmsize], m31
+    call .pass2_fast2_start
+    mov                 r7d, 16*4
+    mov                  r8, dstq
+    pxor                m31, m31
+    call m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_end
+    lea                dstq, [r8+64]
+    mova                 m0, [rsp+40*mmsize]
+    mova                 m1, [rsp+41*mmsize]
+    mova                 m2, [rsp+42*mmsize]
+    mova                 m3, [rsp+43*mmsize]
+    mova                 m4, [rsp+44*mmsize]
+    mova                 m5, [rsp+45*mmsize]
+    mova                 m6, [rsp+46*mmsize]
+    mova                 m7, [rsp+47*mmsize]
+    add                 rsp, 8*64
+    lea                  r5, [o_base]
+    call .pass2_fast2_start
+.end:
+    pxor                m31, m31
+.zero_loop:
+    REPX {mova [cq+r7*8+128*x], m31}, 0, 1, 2, 3
+    sub                 r7d, 16*4
+    jge .zero_loop
+    call m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_end
+    add                 rsp, 8*64  ; FIXME adjust stack_size_padded instead?
+    RET
+.pass2_fast2_start:
+    call m(inv_txfm_add_dct_dct_32x8_10bpc).transpose_8x32
+    punpcklqdq          m27, m0, m2 ; 0
+    punpckhqdq           m0, m2     ; 1
+    punpcklqdq          m22, m3, m4 ; 2
+    punpckhqdq          m26, m3, m4 ; 3
+    punpcklqdq          m14, m5, m7 ; 4
+    punpckhqdq          m20, m5, m7 ; 5
+    punpcklqdq          m23, m6, m8 ; 6
+    punpckhqdq          m21, m6, m8 ; 7
+    vpbroadcastd        m10, [o(pd_2048)]
+    jmp m(inv_txfm_add_dct_dct_32x64_10bpc).pass2_fast2_start
+.dconly:
+    imul                r6d, [cq], 181
+    mov                [cq], eobd
+    or                  r3d, 64
+    jmp m(inv_txfm_add_dct_dct_64x16_10bpc).dconly1
+.pass1_fast:
+    lea                  r4, [idct64_mul_16bpc]
+    lea                  r6, [rsp+4*64+gprsize]
+    mova                 m0, [cq+128* 1]
+    mova                 m3, [cq+128*15]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_fast
+    mova                 m0, [cq+128* 7]
+    mova                 m3, [cq+128* 9]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_fast
+    mova                 m0, [cq+128* 5]
+    mova                 m3, [cq+128*11]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_fast
+    mova                 m0, [cq+128* 3]
+    mova                 m3, [cq+128*13]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1_fast
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part2
+    mova                 m0, [cq+128* 0]
+    mova                 m1, [cq+128* 8]
+    mova                m16, [cq+128* 4]
+    mova                m17, [cq+128*12]
+    call m(idct_8x16_internal_10bpc).main_fast2
+    call m(idct_16x16_internal_10bpc).main_fast2
+    call .pass1_load_spill
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_fast2
+    jmp .pass1_end
+.pass1:
+    lea                  r4, [idct64_mul_16bpc]
+    lea                  r6, [rsp+4*64+gprsize]
+    mova                 m0, [cq+128* 1]
+    mova                 m1, [cq+128*31]
+    mova                 m2, [cq+128*17]
+    mova                 m3, [cq+128*15]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1
+    mova                 m0, [cq+128* 7]
+    mova                 m1, [cq+128*25]
+    mova                 m2, [cq+128*23]
+    mova                 m3, [cq+128* 9]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1
+    mova                 m0, [cq+128* 5]
+    mova                 m1, [cq+128*27]
+    mova                 m2, [cq+128*21]
+    mova                 m3, [cq+128*11]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1
+    mova                 m0, [cq+128* 3]
+    mova                 m1, [cq+128*29]
+    mova                 m2, [cq+128*19]
+    mova                 m3, [cq+128*13]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part1
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).main_part2
+    mova                 m0, [cq+128* 0]
+    mova                 m1, [cq+128* 8]
+    mova                 m2, [cq+128*16]
+    mova                 m3, [cq+128*24]
+    mova                m16, [cq+128* 4]
+    mova                m17, [cq+128*12]
+    mova                m18, [cq+128*20]
+    mova                m19, [cq+128*28]
+    call m(idct_8x16_internal_10bpc).main_fast
+    call m(idct_16x16_internal_10bpc).main_fast
+    call .pass1_load_spill
+    mova                 m4, [cq+128*18]
+    mova                 m5, [cq+128*22]
+    mova                 m6, [cq+128*26]
+    mova                 m7, [cq+128*30]
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).main_fast
+.pass1_end:
+    vpbroadcastd        m11, [o(pd_2)]
+    lea                  r3, [rsp+gprsize]
+    lea                  r4, [cq+8*128]
+    call m(inv_txfm_add_dct_dct_64x16_10bpc).idct64_main_end
+    ; transpose one half immediately, we can transpose lower half later
+.transpose:
+    ; transpose m0-7,16-23
+    psrlq               m12, [permC], 24 ;  0  2  8 10  1  3  9 11
+    psrlq               m13, m12, 32        ;  4  6 12 14  5  7 13 15
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).transpose_16x32
+    punpcklqdq          m27, m0, m20  ;  0
+    punpckhqdq           m0, m20      ;  1
+    punpcklqdq          m24, m5, m16  ; 10
+    punpckhqdq          m16, m5, m16  ; 11
+    punpcklqdq          m23, m3, m21  ;  6
+    punpckhqdq          m21, m3, m21  ;  7
+    punpcklqdq          m25, m7, m8   ; 14
+    punpckhqdq           m3, m7, m8   ; 15
+    punpcklqdq          m22, m15, m4  ;  2
+    punpckhqdq          m26, m15, m4  ;  3
+    punpcklqdq          m15, m6, m17  ; 12
+    punpckhqdq          m17, m6, m17  ; 13
+    punpcklqdq          m28, m14, m18 ;  8
+    punpckhqdq          m18, m14, m18 ;  9
+    punpcklqdq          m14, m2, m1   ;  4
+    punpckhqdq          m20, m2, m1   ;  5
+    ret
+.pass1_load_spill:
+    call m(inv_txfm_add_dct_dct_32x16_10bpc).idct16_sumsub
+    mova        [cq+128* 0], m0
+    mova        [cq+128* 1], m1
+    mova                 m0, [cq+128* 2]
+    mova                 m1, [cq+128* 6]
+    mova        [cq+128* 2], m2
+    mova        [cq+128* 3], m3
+    mova                 m2, [cq+128*10]
+    mova                 m3, [cq+128*14]
+    mova        [cq+128* 4], m4
+    mova        [cq+128* 5], m5
+    mova        [cq+128* 6], m6
+    mova        [cq+128* 7], m7
+    mova        [cq+128* 8], m23
+    mova        [cq+128* 9], m22
+    mova        [cq+128*10], m21
+    mova        [cq+128*11], m20
+    mova        [cq+128*12], m19
+    mova        [cq+128*13], m18
+    mova        [cq+128*14], m17
+    mova        [cq+128*15], m16
+    ret
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/itx16_sse.asm b/media/libdav1d/src/src/x86/itx16_sse.asm
new file mode 100644
index 0000000000..3833e17c99
--- /dev/null
+++ b/media/libdav1d/src/src/x86/itx16_sse.asm
@@ -0,0 +1,8135 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; Copyright © 2017-2021, The rav1e contributors
+; Copyright © 2020, Nathan Egge
+; Copyright © 2021, Matthias Dressel
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA
+%macro COEF 1-2
+pd_%1: times 4 dd %1
+%if %0 == 2
+pd_m%1: times 4 dd -%1
+%endif
+%endmacro
+
+COEF  201
+COEF  401
+COEF  601, 1
+COEF  799
+COEF  995
+COEF 1189, 1
+COEF 1380, 1
+COEF 1567
+COEF 1751
+COEF 1931
+COEF 2106, 1
+COEF 2276, 1
+COEF 2440
+COEF 2598, 1
+COEF 2751, 1
+COEF 2896
+COEF 3035
+COEF 3166
+COEF 3290
+COEF 3406
+COEF 3513
+COEF 3612
+COEF 3703
+COEF 3784
+COEF 3857
+COEF 3920
+COEF 3973
+COEF 4017
+COEF 4052
+COEF 4076
+COEF 4091
+
+deint_shuf:  db  0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+
+%if ARCH_X86_32
+pd_1:            times 4 dd     1
+%endif
+pd_2:            times 4 dd     2
+pw_5:            times 8 dw     5
+pd_1321:         times 4 dd  1321
+pd_2482:         times 4 dd  2482
+pd_m3344:        times 4 dd -3344
+pd_2048:         times 4 dd  2048
+pw_4x2048_4xm2048: times 4 dw 2048
+                   times 4 dw -2048
+pw_4xm2048_4x2048: times 4 dw -2048
+                   times 4 dw 2048
+pw_2048:         times 8 dw  2048
+pw_m2048:        times 8 dw  -2048
+pd_3803:         times 4 dd  3803
+pw_4096:         times 8 dw  4096
+pd_5793:         times 4 dd  5793
+pd_6144:         times 4 dd  6144
+pw_8192:         times 8 dw  8192
+pd_10240:        times 4 dd 10240
+pd_11586:        times 4 dd 11586
+pw_1697x8:       times 8 dw  1697*8
+pw_2896x8:       times 8 dw  2896*8
+pw_1697x16:      times 8 dw  1697*16
+pw_16384:        times 8 dw 16384
+pixel_10bpc_max: times 8 dw  0x03ff
+
+pw_1567_3784:    times 4 dw  1567,  3784
+pw_m3784_1567:   times 4 dw -3784,  1567
+pw_2896_2896:    times 4 dw  2896,  2896
+pw_m2896_2896:   times 4 dw -2896,  2896
+
+clip_18b_min: times 4 dd -0x20000
+clip_18b_max: times 4 dd  0x1ffff
+
+idct64_mul_16bpc:
+dd 4095,  101, 2967, -2824,  3745, 1660, 3822, -1474,   401,  4076,   799,  4017
+dd -700, 4036, 2359,  3349, -2191, 3461,  897,  3996, -2598, -3166, -4017,  -799
+dd 4065,  501, 3229, -2520,  3564, 2019, 3948, -1092,  1931,  3612,  3406,  2276
+dd -301, 4085, 2675,  3102, -1842, 3659, 1285,  3889, -1189, -3920, -2276, -3406
+
+cextern inv_txfm_add_dct_dct_4x4_8bpc_ssse3
+cextern iadst_4x4_internal_8bpc_ssse3.main
+cextern idct_4x8_internal_8bpc_ssse3.main
+cextern iadst_4x8_internal_8bpc_ssse3.main
+cextern idct_16x4_internal_8bpc_ssse3.main
+cextern iadst_16x4_internal_8bpc_ssse3.main
+cextern iadst_16x4_internal_8bpc_ssse3.main_pass2_end
+cextern idct_8x4_internal_8bpc_ssse3.main
+cextern iadst_8x4_internal_8bpc_ssse3.main
+cextern idct_8x8_internal_8bpc_ssse3.main
+cextern idct_8x8_internal_8bpc_ssse3.pass1_end3
+cextern iadst_8x8_internal_8bpc_ssse3.main
+cextern iadst_8x8_internal_8bpc_ssse3.main_pass2_end
+cextern idct_16x8_internal_8bpc_ssse3.main
+cextern iadst_16x8_internal_8bpc_ssse3.main
+cextern iadst_16x8_internal_8bpc_ssse3.main_pass2_end
+cextern idct_8x32_internal_8bpc_ssse3.main
+cextern idct_8x32_internal_8bpc_ssse3.main_fast
+cextern idct_8x32_internal_8bpc_ssse3.main_veryfast
+cextern idct_16x64_internal_8bpc_ssse3.main
+cextern idct_16x64_internal_8bpc_ssse3.main_fast
+
+tbl_4x16_2d: db 0, 13, 29, 45
+tbl_4x16_h: db 0, 16, 32, 48
+tbl_4x16_v: db 0, 4, 8, 12
+
+tbl_8x16_2d: db 0, 14, 30, 46
+tbl_8x16_v: db 0, 4, 8, 12
+tbl_8x16_h: db 0, 32, 64, 96
+
+tbl_16x16_2d: db 0, 10, 36, 78
+tbl_16x16_v: db 0, 4, 8, 12
+tbl_16x16_h: db 0, 64, 128, 192
+
+tbl_8x32_2d: dw 0, 14, 43, 75, 107, 139, 171, 203
+
+tbl_16x32_2d: dw 0, 14, 44, 90, 151, 215, 279, 343
+
+tbl_32x16_2d: ; first 4 entries of 32x32 are identical to this one
+tbl_32x32_2d: dw 0, 10, 36, 78, 136, 210, 300, 406
+
+tbl_Nx32_odd_offset: db 2*16, 2*23
+                     db 2*20, 2*19
+                     db 2*18, 2*21
+                     db 2*22, 2*17
+                     db 2*30, 2*25
+                     db 2*26, 2*29
+                     db 2*28, 2*27
+                     db 2*24, 2*31
+
+tbl_Nx64_offset: db 2* 0, 2*32, 2*16, 2*46
+                 db 2* 8, 2*40, 2*23, 2*38
+                 db 2* 1, 2*36, 2*20, 2*42
+                 db 2* 9, 2*44, 2*19, 2*34
+                 db 2* 2, 2*60, 2*18, 2*50
+                 db 2*10, 2*52, 2*21, 2*58
+                 db 2* 3, 2*56, 2*22, 2*54
+                 db 2*11, 2*48, 2*17, 2*62
+
+SECTION .text
+
+%define m_suffix(x, sfx) mangle(private_prefix %+ _ %+ x %+ sfx)
+%define m(x) m_suffix(x, SUFFIX)
+
+; This refers to the first function in itx_sse i.e. the start of the text section
+; which is needed as a base pointer for constants.
+%define itx8_start m_suffix(inv_txfm_add_dct_dct_4x4_8bpc, _ssse3)
+
+%if ARCH_X86_64
+%define o(x) x
+%else
+%define o(x) r6-$$+x ; PIC
+%endif
+
+%macro IWHT4_1D 0
+    ; m0 = in0,  m1 = in1,  m2 = in2,  m3 = in3
+    paddd                m0, m1      ; in0 += in1
+    psubd                m4, m2, m3  ; tmp0 = in2 - in3
+    psubd                m5, m0, m4  ; tmp1 = (in0 - tmp0) >> 1
+    psrad                m5, 1
+    psubd                m2, m5, m1  ; in2 = tmp1 - in1
+    psubd                m5, m3      ; in1 = tmp1 - in3
+    psubd                m0, m5      ; in0 -= in1
+    paddd                m4, m2      ; in3 = tmp0 + in2
+    ; m0 = out0,  m1 = in1,  m2 = out2,  m3 = in3
+    ; m4 = out3,  m5 = out1
+%endmacro
+
+INIT_XMM sse2
+cglobal inv_txfm_add_wht_wht_4x4_16bpc, 3, 3, 6, dst, stride, c, eob, bdmax
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    mova                 m2, [cq+16*2]
+    mova                 m3, [cq+16*3]
+    REPX       {psrad x, 2}, m0, m1, m2, m3
+    IWHT4_1D
+    punpckldq            m1, m0, m5
+    punpckhdq            m3, m0, m5
+    punpckldq            m5, m2, m4
+    punpckhdq            m2, m4
+    punpcklqdq           m0, m1, m5
+    punpckhqdq           m1, m5
+    punpcklqdq           m4, m3, m2
+    punpckhqdq           m3, m2
+    mova                 m2, m4
+    IWHT4_1D
+    packssdw             m0, m4 ; low: out3,  high: out0
+    packssdw             m2, m5 ; low: out2,  high: out1
+    pxor                 m4, m4
+    mova          [cq+16*0], m4
+    mova          [cq+16*1], m4
+    mova          [cq+16*2], m4
+    mova          [cq+16*3], m4
+    lea                  r2, [dstq+strideq*2]
+    movq                 m1, [dstq+strideq*0]
+    movhps               m1, [r2  +strideq*1]
+    movq                 m3, [r2  +strideq*0]
+    movhps               m3, [dstq+strideq*1]
+    movd                 m5, bdmaxm
+    pshuflw              m5, m5, q0000  ; broadcast
+    punpcklqdq           m5, m5         ; broadcast
+    paddsw               m0, m1
+    paddsw               m2, m3
+    pmaxsw               m0, m4
+    pmaxsw               m2, m4
+    pminsw               m0, m5
+    pminsw               m2, m5
+    movhps [r2  +strideq*1], m0 ; write out0
+    movhps [dstq+strideq*1], m2 ; write out1
+    movq   [r2  +strideq*0], m2 ; write out2
+    movq   [dstq+strideq*0], m0 ; write out3
+    RET
+
+; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12
+; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12
+; flags: 2 = inv_dst1, 4 = inv_dst2
+; skip round/shift if rnd is not a number
+%macro ITX_MULSUB_2D 8-9 0 ; dst/src[1-2], tmp[1-3], rnd, coef[1-2], flags
+; %1 dst/src[1]
+; %2 dst/src[2]
+; %3 tmp[1]
+; %4 tmp[2]
+; %5 tmp[3]
+; %6 rnd
+; %7 coef[1]
+; %8 coef[2]
+; %9 flags
+%ifnidn %7,%8   ; optimize when coef1 == coef2
+%if %8 < 32
+    pmulld              m%4, m%1, m%8
+    pmulld              m%3, m%2, m%8
+%else
+    mova                m%3, [o(pd_%8)]
+    pmulld              m%4, m%1, m%3
+    pmulld              m%3, m%2
+%endif
+%endif
+%if %7 < 32
+    pmulld              m%1, m%7
+    pmulld              m%2, m%7
+%else
+    mova                m%5, [o(pd_%7)]
+    pmulld              m%1, m%5
+    pmulld              m%2, m%5
+%endif
+%if %9 & 4  ; invert dst2
+    paddd               m%4, m%2
+    psubd               m%2, m%6, m%4
+%else
+%ifnum %6
+%ifnidn %7,%8
+    paddd               m%4, m%6
+%else
+    paddd               m%1, m%6
+%endif
+%endif
+%ifnidn %7,%8
+    paddd               m%2, m%4
+%else
+    mova                m%3, m%2
+    paddd               m%2, m%1
+%endif
+%endif
+%if %9 & 2  ; invert dst1
+    psubd               m%3, m%1
+    paddd               m%1, m%3, m%6
+%else
+%ifnum %6
+%ifnidn %7,%8
+    paddd               m%1, m%6
+%endif
+%endif
+    psubd               m%1, m%3
+%endif
+%ifnum %6
+    psrad               m%2, 12
+    psrad               m%1, 12
+%endif
+%endmacro
+
+%macro INV_TXFM_FN 4-5+ 8 ; type1, type2, eob_offset, size, mmsize/stack
+cglobal inv_txfm_add_%1_%2_%4_16bpc, 4, 7, %5, dst, stride, c, eob, tx2
+    %define %%p1 m(i%1_%4_internal_16bpc)
+%if ARCH_X86_32
+    LEA                  r6, $$
+%endif
+%if has_epilogue
+%ifidn %1_%2, dct_dct
+    test               eobd, eobd
+    jz %%end
+%endif
+    lea                tx2q, [o(m(i%2_%4_internal_16bpc).pass2)]
+%ifnum %3
+%if %3
+    add                eobd, %3
+%endif
+%else
+    lea                  r5, [o(%3)]
+%endif
+    call %%p1
+    RET
+%%end:
+%else
+    ; Jump to the 1st txfm function if we're not taking the fast path, which
+    ; in turn performs an indirect jump to the 2nd txfm function.
+    lea                tx2q, [o(m(i%2_%4_internal_16bpc).pass2)]
+%ifnum %3
+%if %3
+    add                eobd, %3
+%endif
+%else
+    lea                  r5, [o(%3)]
+%endif
+%ifidn %1_%2, dct_dct
+    test               eobd, eobd
+    jnz %%p1
+%else
+    ; jump to the 1st txfm function unless it's located directly after this
+    times ((%%end - %%p1) >> 31) & 1 jmp %%p1
+ALIGN function_align
+%%end:
+%endif
+%endif
+%endmacro
+
+%macro INV_TXFM_4X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 0, 4x4
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 4
+.dconly:
+    add                 r5d, 128
+    sar                 r5d, 8
+.dconly2:
+    imul                r5d, 2896
+    mova                 m2, [o(pixel_10bpc_max)]
+    add                 r5d, 34816
+    movd                 m0, r5d
+    pshuflw              m0, m0, q1111
+    pxor                 m3, m3
+    punpcklqdq           m0, m0
+.dconly_loop:
+    movq                 m1, [dstq+strideq*0]
+    movhps               m1, [dstq+strideq*1]
+    paddw                m1, m0
+    pminsw               m1, m2
+    pmaxsw               m1, m3
+    movq   [dstq+strideq*0], m1
+    movhps [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    RET
+%endif
+%endmacro
+
+%macro IDCT4_1D 8 ; src[1-4], tmp[1-3], rnd
+    ; butterfly rotation
+    ITX_MULSUB_2D        %1, %3, %5, %6, %7, %8, 2896, 2896 ; %1 out1  %3 out0
+    ITX_MULSUB_2D        %2, %4, %5, %6, %7, %8, 1567, 3784 ; %2 out2  %4 out3
+    ; Hadamard rotation
+    psubd               m%5, m%1, m%2
+    paddd               m%2, m%1
+    paddd               m%1, m%3, m%4
+    psubd               m%3, m%4
+    ; %1 (src1) = out0
+    ; %2 (src2) = out1
+    ; %3 (src3) = out3
+    ; $5 (tmp1) = out2
+%endmacro
+
+INIT_XMM sse4
+
+INV_TXFM_4X4_FN dct, dct
+INV_TXFM_4X4_FN dct, identity
+INV_TXFM_4X4_FN dct, adst
+INV_TXFM_4X4_FN dct, flipadst
+
+cglobal idct_4x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    mova                 m2, [cq+16*2]
+    mova                 m3, [cq+16*3]
+    mova                 m5, [o(pd_2048)]
+    call .pass1_main
+    packssdw             m0, m1     ; out0 out1
+    packssdw             m4, m2     ; out2 out3
+    ; transpose
+    punpckhwd            m2, m0, m4
+    punpcklwd            m0, m4
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    ; m0 = out0 out1
+    ; m1 = out2 out3
+    ; m5 = pd_2048
+    jmp                tx2q
+.pass1_main:
+    IDCT4_1D              0, 1, 2, 3, 4, 6, 7, 5
+    ret
+.pass2:
+    ; m0 = in0 in1
+    ; m1 = in2 in3
+    ; m5 = pd_2048
+    punpckhwd            m2, m1, m0
+    punpcklwd            m1, m0
+    pmaddwd              m4, m2, [o(pw_m3784_1567)]
+    pmaddwd              m2, [o(pw_1567_3784)]
+    pmaddwd              m0, m1, [o(pw_m2896_2896)]
+    pmaddwd              m1, [o(pw_2896_2896)]
+    REPX      {paddd x, m5}, m4, m2, m0, m1
+    packssdw             m5, m5     ; pw_2048
+    REPX      {psrad x, 12}, m4, m2, m0, m1
+    packssdw             m2, m4     ; t3 t2
+    packssdw             m1, m0     ; t0 t1
+    paddsw               m0, m1, m2 ; out0 out1
+    psubsw               m1, m2     ; out3 out2
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    movq                 m2, [dstq+strideq*0]
+    movhps               m2, [dstq+strideq*1]
+    lea                  r5, [dstq+strideq*2]
+    movq                 m3, [r5  +strideq*1]
+    movhps               m3, [r5  +strideq*0]
+    mova                 m5, [o(pixel_10bpc_max)]
+    pxor                 m4, m4
+    mova          [cq+16*0], m4
+    mova          [cq+16*1], m4
+    mova          [cq+16*2], m4
+    mova          [cq+16*3], m4
+    paddw                m0, m2
+    paddw                m1, m3
+    pmaxsw               m0, m4
+    pmaxsw               m1, m4
+    pminsw               m0, m5
+    pminsw               m1, m5
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movhps [r5  +strideq*0], m1
+    movq   [r5  +strideq*1], m1
+    RET
+
+INV_TXFM_4X4_FN adst, dct
+INV_TXFM_4X4_FN adst, adst
+INV_TXFM_4X4_FN adst, flipadst
+INV_TXFM_4X4_FN adst, identity
+
+cglobal iadst_4x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    call .main
+    packssdw             m0, m2            ; out0 out1
+    packssdw             m1, m4            ; out2 out3
+    ; transpose
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    ; m0 = out0 out1
+    ; m1 = out2 out3
+    ; m5 = pd_2048
+    jmp                tx2q
+.pass2:
+    ; m0 = in0 in1
+    ; m1 = in2 in3
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_4x4_internal_8bpc, _ssse3).main
+.end:
+    mova                 m4, [o(pw_2048)]
+    movq                 m2, [dstq+strideq*0]
+    movhps               m2, [dstq+strideq*1]
+    lea                  r5, [dstq+strideq*2]
+    movq                 m3, [r5  +strideq*0]
+    movhps               m3, [r5  +strideq*1]
+    mova                 m5, [o(pixel_10bpc_max)]
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    pxor                 m4, m4
+    mova          [cq+16*0], m4
+    mova          [cq+16*1], m4
+    mova          [cq+16*2], m4
+    mova          [cq+16*3], m4
+    paddw                m0, m2
+    paddw                m1, m3
+    pmaxsw               m0, m4
+    pmaxsw               m1, m4
+    pminsw               m0, m5
+    pminsw               m1, m5
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movq   [r5  +strideq*0], m1
+    movhps [r5  +strideq*1], m1
+    RET
+ALIGN function_align
+.main:
+    mova                 m1, [cq+16*2]
+    mova                 m3, [cq+16*3]
+    mova                 m5, [cq+16*0]
+    lea                  r3, [cq+16*1]
+.main2:
+    mova                 m0, [o(pd_1321)]  ; SINPI_1_9
+    mova                 m2, [o(pd_2482)]  ; SINPI_2_9
+    mova                 m6, [o(pd_3803)]  ; SINPI_4_9
+    pmulld               m4, m0, m1        ; s[4] = SINPI_1_9 * T[2]
+    pmulld               m7, m3, m6        ; s[6] = SINPI_4_9 * T[3]
+    pmulld               m6, m1            ; s[3] = SINPI_4_9 * T[2]
+    pmulld               m0, m5            ; s[0] = SINPI_1_9 * T[0]
+    psubd                m1, m3            ; T[2] - T[3]
+    pmulld               m3, m2            ; s[5] = SINPI_2_9 * T[3]
+    pmulld               m2, m5            ; s[1] = SINPI_2_9 * T[0]
+    paddd                m0, m6            ; s[0] += s[3]
+    paddd                m0, m3            ; s[0] += s[5]
+    mova                 m3, [o(pd_m3344)] ; -SINPI_3_9
+    psubd                m2, m4            ; s[1] -= s[4]
+    psubd                m2, m7            ; s[1] -= s[6]
+    psubd                m1, m5            ; -b7 = (T[2] -T[3]) - T[0]
+    pmulld               m1, m3            ; s[2]  = -SINPI_3_9 * -b7
+    pmulld               m3, [r3]          ; -s[3] = -SINPI_3_9 * T[1]
+    mova                 m5, [o(pd_2048)]
+    REPX      {paddd x, m5}, m0, m1        ; {s[0], s[2]} + 2048
+    paddd                m4, m0, m2        ; x[3]  = s[0] + s[1]
+    psubd                m2, m3            ; x[1]  = s[1] + s[3]
+    psubd                m0, m3            ; x[0]  = s[0] + s[3]
+    paddd                m4, m3            ; x[3] -= s[3]
+    paddd                m2, m5            ; x[1] + 2048
+    REPX      {psrad x, 12}, m0, m2, m1, m4
+    ret
+
+
+INV_TXFM_4X4_FN flipadst, dct
+INV_TXFM_4X4_FN flipadst, adst
+INV_TXFM_4X4_FN flipadst, flipadst
+INV_TXFM_4X4_FN flipadst, identity
+
+cglobal iflipadst_4x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    call m(iadst_4x4_internal_16bpc).main
+    packssdw             m0, m2            ; out0 out1
+    packssdw             m1, m4            ; out2 out3
+    ; transpose
+    punpcklwd            m2, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    ; m0 = out0 out1
+    ; m1 = out2 out3
+    ; m5 = pd_2048
+    jmp                tx2q
+.pass2:
+    ; m0 = in0 in1
+    ; m1 = in2 in3
+%if ARCH_X86_32
+    lea                 r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_4x4_internal_8bpc, _ssse3).main
+    mova                 m4, [o(pw_2048)]
+    movq                 m3, [dstq+strideq*1]
+    movhps               m3, [dstq+strideq*0]
+    lea                  r5, [dstq+strideq*2]
+    movq                 m2, [r5  +strideq*1]
+    movhps               m2, [r5  +strideq*0]
+    mova                 m5, [o(pixel_10bpc_max)]
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    pxor                 m4, m4
+    mova          [cq+16*0], m4
+    mova          [cq+16*1], m4
+    mova          [cq+16*2], m4
+    mova          [cq+16*3], m4
+    paddw                m0, m2
+    paddw                m1, m3
+    pmaxsw               m0, m4
+    pmaxsw               m1, m4
+    pminsw               m0, m5
+    pminsw               m1, m5
+    movhps [dstq+strideq*0], m1
+    movq   [dstq+strideq*1], m1
+    movhps [r5  +strideq*0], m0
+    movq   [r5  +strideq*1], m0
+    RET
+
+INV_TXFM_4X4_FN identity, dct
+INV_TXFM_4X4_FN identity, adst
+INV_TXFM_4X4_FN identity, flipadst
+INV_TXFM_4X4_FN identity, identity
+
+cglobal iidentity_4x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    mova                 m3, [o(pd_5793)]
+    pmulld               m0, m3, [cq+16*0]
+    pmulld               m1, m3, [cq+16*1]
+    pmulld               m2, m3, [cq+16*2]
+    pmulld               m3,     [cq+16*3]
+    mova                 m5, [o(pd_2048)]
+    REPX      {paddd x, m5}, m0, m1, m2, m3
+    REPX      {psrad x, 12}, m0, m1, m2, m3
+    packssdw             m0, m1
+    packssdw             m2, m3
+    ; transpose
+    punpckhwd            m3, m0, m2
+    punpcklwd            m0, m2
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    ; m0 = out0 out1
+    ; m1 = out2 out3
+    ; m5 = pd_2048
+    jmp                tx2q
+.pass2:
+    ; m0 = in0 in1
+    ; m1 = in2 in3
+    ; m5 = pd_2048
+    mova                 m4, [o(pw_1697x8)]
+    movq                 m2, [dstq+strideq*0]
+    movhps               m2, [dstq+strideq*1]
+    lea                  r5, [dstq+strideq*2]
+    pmulhrsw             m3, m4, m0
+    pmulhrsw             m4, m1
+    paddsw               m0, m3
+    paddsw               m1, m4
+    movq                 m3, [r5  +strideq*0]
+    movhps               m3, [r5  +strideq*1]
+    mova                 m4, [o(pixel_10bpc_max)]
+    packssdw             m5, m5 ; pw_2048
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    pxor                 m5, m5
+    mova          [cq+16*0], m5
+    mova          [cq+16*1], m5
+    mova          [cq+16*2], m5
+    mova          [cq+16*3], m5
+    paddw                m0, m2
+    paddw                m1, m3
+    pmaxsw               m0, m5
+    pmaxsw               m1, m5
+    pminsw               m0, m4
+    pminsw               m1, m4
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movq   [r5  +strideq*0], m1
+    movhps [r5  +strideq*1], m1
+    RET
+
+%macro INV_TXFM_4X8_FN 2-3 0 ; type1, type2, eob_offset
+    INV_TXFM_FN          %1, %2, %3, 4x8
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 8
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 181
+    jmp m(inv_txfm_add_dct_dct_4x4_16bpc).dconly
+%endif
+%endmacro
+
+INV_TXFM_4X8_FN dct, dct
+INV_TXFM_4X8_FN dct, identity, 9
+INV_TXFM_4X8_FN dct, adst
+INV_TXFM_4X8_FN dct, flipadst
+
+cglobal idct_4x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%undef cmp
+    mova                 m5, [o(pd_2048)]
+%if ARCH_X86_64
+    xor                 r5d, r5d
+    cmp                eobd, 13
+    setge               r5b
+%else
+    mov                 r5d, 1
+    cmp                eobd, 13
+    sbb                 r5d, 0
+%endif
+    shl                 r5d, 4
+.loop_pass1:
+    mova                 m3, [o(pd_2896)]
+    pmulld               m0, m3, [cq+32*0+r5]
+    pmulld               m1, m3, [cq+32*1+r5]
+    pmulld               m2, m3, [cq+32*2+r5]
+    pmulld               m3, [cq+32*3+r5]
+    REPX      {paddd x, m5}, m0, m1, m2, m3
+    REPX      {psrad x, 12}, m0, m1, m2, m3
+    call m(idct_4x4_internal_16bpc).pass1_main
+    packssdw             m0, m1     ; out0 out1
+    packssdw             m4, m2     ; out2 out3
+    test                r5d, r5d
+    jz .end_pass1
+    mova       [cq+32*0+16], m0
+    mova       [cq+32*1+16], m4
+    xor                 r5d, r5d
+    jmp .loop_pass1
+.end_pass1:
+    punpckhwd            m2, m0, m4
+    punpcklwd            m0, m4
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    mova                 m2, [cq+32*0+16]
+    mova                 m6, [cq+32*1+16]
+    punpckhwd            m4, m2, m6
+    punpcklwd            m2, m6
+    punpckhwd            m3, m2, m4
+    punpcklwd            m2, m4
+    ; m0-3 = packed & transposed output
+    jmp                tx2q
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(idct_4x8_internal_8bpc, _ssse3).main
+    ; m0-3 is now out0/1,3/2,4/5,7/6
+    mova                 m4, [o(pw_2048)]
+    shufps               m1, m1, q1032
+    shufps               m3, m3, q1032
+.end:
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    pxor                 m4, m4
+    REPX {mova [cq+16*x], m4}, 0, 1, 2, 3, 4, 5, 6, 7
+    mova                 m7, [o(pixel_10bpc_max)]
+    lea                  r2, [strideq*3]
+    movq                 m5, [dstq+strideq*0]
+    movq                 m6, [dstq+strideq*2]
+    movhps               m5, [dstq+strideq*1]
+    movhps               m6, [dstq+r2]
+    lea                  r4, [dstq+strideq*4]
+    paddw                m0, m5
+    paddw                m1, m6
+    movq                 m5, [r4+strideq*0]
+    movq                 m6, [r4+strideq*2]
+    movhps               m5, [r4+strideq*1]
+    movhps               m6, [r4+r2]
+    paddw                m2, m5
+    paddw                m3, m6
+    REPX     {pminsw x, m7}, m0, m1, m2, m3
+    REPX     {pmaxsw x, m4}, m0, m1, m2, m3
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movq   [dstq+strideq*2], m1
+    movhps [dstq+r2       ], m1
+    movq   [r4  +strideq*0], m2
+    movhps [r4  +strideq*1], m2
+    movq   [r4  +strideq*2], m3
+    movhps [r4  +r2       ], m3
+    RET
+
+INV_TXFM_4X8_FN adst, dct
+INV_TXFM_4X8_FN adst, adst
+INV_TXFM_4X8_FN adst, flipadst
+INV_TXFM_4X8_FN adst, identity, 9
+
+cglobal iadst_4x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    call .pass1_main
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    mova                 m2, [cq+32*2+16]
+    mova                 m6, [cq+32*3+16]
+    punpckhwd            m4, m2, m6
+    punpcklwd            m2, m6
+    punpckhwd            m3, m2, m4
+    punpcklwd            m2, m4
+    ; m0-3 = packed & transposed output
+    jmp                tx2q
+.pass1_main:
+%undef cmp
+%if ARCH_X86_64
+    xor                 r5d, r5d
+    cmp                eobd, 13
+    setge               r5b
+%else
+    mov                 r5d, 1
+    cmp                eobd, 13
+    sbb                 r5d, 0
+%endif
+    shl                 r5d, 4
+    lea                  r3, [cq+32*1+16]
+.loop_pass1:
+    mova                 m0, [o(pd_2048)]
+    mova                 m3, [o(pd_2896)]
+    pmulld               m5, m3, [cq+32*0+r5]
+    pmulld               m2, m3, [cq+32*1+r5]
+    pmulld               m1, m3, [cq+32*2+r5]
+    pmulld               m3, [cq+32*3+r5]
+    REPX      {paddd x, m0}, m5, m2, m1, m3
+    REPX      {psrad x, 12}, m5, m2, m1, m3
+    mova               [r3], m2
+    call m(iadst_4x4_internal_16bpc).main2
+    packssdw             m0, m2            ; out0 out1
+    packssdw             m1, m4            ; out2 out3
+    test                r5d, r5d
+    jz .end_pass1
+    mova       [cq+32*2+16], m0
+    mova       [cq+32*3+16], m1
+    xor                 r5d, r5d
+    jmp .loop_pass1
+.end_pass1:
+    ret
+.pass2:
+    shufps               m0, m0, q1032
+    shufps               m1, m1, q1032
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_4x8_internal_8bpc, _ssse3).main
+    mova                 m4, [o(pw_4x2048_4xm2048)]
+    jmp m(idct_4x8_internal_16bpc).end
+
+INV_TXFM_4X8_FN flipadst, dct
+INV_TXFM_4X8_FN flipadst, adst
+INV_TXFM_4X8_FN flipadst, flipadst
+INV_TXFM_4X8_FN flipadst, identity, 9
+
+cglobal iflipadst_4x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    call m(iadst_4x8_internal_16bpc).pass1_main
+    punpcklwd            m2, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    mova                 m6, [cq+32*2+16]
+    mova                 m2, [cq+32*3+16]
+    punpcklwd            m4, m2, m6
+    punpckhwd            m2, m6
+    punpckhwd            m3, m2, m4
+    punpcklwd            m2, m4
+    ; m0-3 = packed & transposed output
+    jmp                tx2q
+.pass2:
+    shufps               m0, m0, q1032
+    shufps               m1, m1, q1032
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_4x8_internal_8bpc, _ssse3).main
+    mova                 m4, m0
+    mova                 m5, m1
+    pshufd               m0, m3, q1032
+    pshufd               m1, m2, q1032
+    pshufd               m2, m5, q1032
+    pshufd               m3, m4, q1032
+    mova                 m4, [o(pw_4xm2048_4x2048)]
+    jmp m(idct_4x8_internal_16bpc).end
+
+INV_TXFM_4X8_FN identity, dct
+INV_TXFM_4X8_FN identity, adst
+INV_TXFM_4X8_FN identity, flipadst
+INV_TXFM_4X8_FN identity, identity, 3
+
+cglobal iidentity_4x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%undef cmp
+    mova                 m5, [o(pd_2048)]
+    mova                 m4, [o(pd_2896)]
+    mova                 m6, [o(pd_5793)]
+    ; clear m7 in case we skip the bottom square
+    pxor                 m7, m7
+%if ARCH_X86_64
+    xor                 r5d, r5d
+    cmp                eobd, 16
+    setge               r5b
+%else
+    mov                 r5d, 1
+    cmp                eobd, 16
+    sbb                 r5d, 0
+%endif
+    shl                 r5d, 4
+.loop_pass1:
+    pmulld               m0, m4, [cq+32*0+r5]
+    pmulld               m1, m4, [cq+32*1+r5]
+    pmulld               m2, m4, [cq+32*2+r5]
+    pmulld               m3, m4, [cq+32*3+r5]
+    REPX      {paddd x, m5}, m0, m1, m2, m3
+    REPX      {psrad x, 12}, m0, m1, m2, m3
+    REPX     {pmulld x, m6}, m0, m1, m2, m3
+    REPX      {paddd x, m5}, m0, m1, m2, m3
+    REPX      {psrad x, 12}, m0, m1, m2, m3
+    packssdw             m0, m1
+    packssdw             m2, m3
+    test                r5d, r5d
+    jz .end_pass1
+    mova       [cq+32*0+16], m0
+    mova                 m7, m2
+    xor                 r5d, r5d
+    jmp .loop_pass1
+.end_pass1:
+    punpckhwd            m4, m0, m2
+    punpcklwd            m0, m2
+    punpckhwd            m1, m0, m4
+    punpcklwd            m0, m4
+    mova                 m2, [cq+32*0+16]
+    punpckhwd            m4, m2, m7
+    punpcklwd            m2, m7
+    punpckhwd            m3, m2, m4
+    punpcklwd            m2, m4
+    ; m0-3 = packed & transposed output
+    jmp                tx2q
+.pass2:
+    mova                 m4, [o(pw_4096)]
+    jmp m(idct_4x8_internal_16bpc).end
+
+%macro INV_TXFM_4X16_FN 2-3 2d ; type1, type2, eob_tbl_suffix
+    INV_TXFM_FN          %1, %2, tbl_4x16_%3, 4x16
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 16
+    add                 r5d, 384
+    sar                 r5d, 9
+    jmp m(inv_txfm_add_dct_dct_4x4_16bpc).dconly2
+%endif
+%endmacro
+
+INV_TXFM_4X16_FN dct, dct
+INV_TXFM_4X16_FN dct, identity, v
+INV_TXFM_4X16_FN dct, adst
+INV_TXFM_4X16_FN dct, flipadst
+
+cglobal idct_4x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%undef cmp
+%if ARCH_X86_32
+    mov                 r5m, r6d
+%endif
+    mov                 r6d, 4
+.zero_loop:
+    dec                 r6d
+    cmp                eobb, byte [r5+r6]
+    jl .zero_loop
+    mov                 r5d, r6d
+    shl                 r5d, 4
+%if ARCH_X86_32
+    ; restore pic-ptr
+    mov                  r6, r5m
+%endif
+    mova                 m5, [o(pd_2048)]
+.loop_pass1:
+    mova                 m0, [cq+64*0+r5]
+    mova                 m1, [cq+64*1+r5]
+    mova                 m2, [cq+64*2+r5]
+    mova                 m3, [cq+64*3+r5]
+    call m(idct_4x4_internal_16bpc).pass1_main
+    pcmpeqd              m3, m3
+    REPX      {psubd x, m3}, m0, m1, m4, m2
+    REPX       {psrad x, 1}, m0, m1, m4, m2
+    packssdw             m0, m1     ; out0 out1
+    packssdw             m4, m2     ; out2 out3
+    punpckhwd            m2, m0, m4
+    punpcklwd            m0, m4
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    test                r5d, r5d
+    jz .end_pass1
+    mova       [cq+64*0+r5], m0
+    mova       [cq+64*1+r5], m1
+    sub                 r5d, 16
+    jmp .loop_pass1
+.end_pass1:
+    mova                 m2, [cq+64*0+16]
+    mova                 m3, [cq+64*1+16]
+    mova                 m4, [cq+64*0+32]
+    mova                 m5, [cq+64*1+32]
+    mova                 m6, [cq+64*0+48]
+    mova                 m7, [cq+64*1+48]
+    ; m0-7 = packed & transposed output
+    jmp                tx2q
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(idct_16x4_internal_8bpc, _ssse3).main
+    ; m0-6 is out0-13 [with odd registers having inversed output]
+    ; [coeffq+16*7] has out15/14
+    mova                 m7, [o(pw_2048)]
+    REPX   {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulhrsw             m7, [cq+16*7]
+    REPX {shufps x, x, q1032}, m1, m3, m5, m7
+    mova          [cq+16*0], m4
+    mova          [cq+16*1], m5
+    mova          [cq+16*2], m6
+    mova          [cq+16*3], m7
+.end:
+    pxor                 m4, m4
+    REPX {mova [cq+16*x], m4}, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+    mova                 m7, [o(pixel_10bpc_max)]
+    mov                 r5d, 2
+    lea                  r3, [strideq*3]
+.loop:
+    movq                 m5, [dstq+strideq*0]
+    movq                 m6, [dstq+strideq*2]
+    movhps               m5, [dstq+strideq*1]
+    movhps               m6, [dstq+r3]
+    lea                  r4, [dstq+strideq*4]
+    paddw                m0, m5
+    paddw                m1, m6
+    movq                 m5, [r4+strideq*0]
+    movq                 m6, [r4+strideq*2]
+    movhps               m5, [r4+strideq*1]
+    movhps               m6, [r4+r3]
+    paddw                m2, m5
+    paddw                m3, m6
+    REPX     {pminsw x, m7}, m0, m1, m2, m3
+    REPX     {pmaxsw x, m4}, m0, m1, m2, m3
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movq   [dstq+strideq*2], m1
+    movhps [dstq+r3       ], m1
+    movq   [r4  +strideq*0], m2
+    movhps [r4  +strideq*1], m2
+    movq   [r4  +strideq*2], m3
+    movhps [r4  +r3       ], m3
+    dec                 r5d
+    jz .end2
+    lea                dstq, [dstq+strideq*8]
+    mova                 m0, [cq+0*16]
+    mova                 m1, [cq+1*16]
+    mova                 m2, [cq+2*16]
+    mova                 m3, [cq+3*16]
+    REPX {mova [cq+x*16], m4}, 0, 1, 2, 3
+    jmp .loop
+.end2:
+    RET
+
+INV_TXFM_4X16_FN adst, dct
+INV_TXFM_4X16_FN adst, adst
+INV_TXFM_4X16_FN adst, flipadst
+INV_TXFM_4X16_FN adst, identity, v
+
+cglobal iadst_4x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%undef cmp
+%if ARCH_X86_32
+    mov                 r5m, r6d
+%endif
+    mov                 r6d, 4
+.zero_loop:
+    dec                 r6d
+    cmp                eobb, byte [r6+r5]
+    jl .zero_loop
+    mov                 r5d, r6d
+    shl                 r5d, 4
+%if ARCH_X86_32
+    ; restore pic-ptr
+    mov                  r6, r5m
+%endif
+.loop_pass1:
+    mova                 m5, [cq+64*0+r5]
+    lea                  r3, [cq+64*1+r5]
+    mova                 m1, [cq+64*2+r5]
+    mova                 m3, [cq+64*3+r5]
+    call m(iadst_4x4_internal_16bpc).main2
+    pcmpeqd              m3, m3
+    REPX      {psubd x, m3}, m0, m2, m1, m4
+    REPX       {psrad x, 1}, m0, m2, m1, m4
+    packssdw             m0, m2            ; out0 out1
+    packssdw             m1, m4            ; out2 out3
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    test                r5d, r5d
+    jz m(idct_4x16_internal_16bpc).end_pass1
+    mova       [cq+64*0+r5], m0
+    mova       [cq+64*1+r5], m1
+    sub                 r5d, 16
+    jmp .loop_pass1
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_16x4_internal_8bpc, _ssse3).main
+    call m_suffix(iadst_16x4_internal_8bpc, _ssse3).main_pass2_end
+    ; m7/5/2/4 = out4/-11,-5/10,6/-9,-7/8
+    ; m0/3 & cq6/7 = out0/-15,-3/12,-1/14,2/-13
+    mova                 m1, [o(pw_4x2048_4xm2048)]
+    REPX   {pmulhrsw x, m1}, m7, m2, m0
+    pshufd               m6, m1, q1032  ; 4x-2048,4x2048
+    pmulhrsw             m1, [cq+16*7]
+    REPX   {pmulhrsw x, m6}, m5, m4, m3
+    pmulhrsw             m6, [cq+16*6]
+    ; m7/5/2/4 = out4/11,5/10,6/9,7/8
+    ; m0/3/6/1 = out0/15,3/12,1/14,2/13
+    ; output should be as 0-3 for out0-7, and cq+0-3*16 for out8-15
+    movhps         [cq+0*8], m4
+    movhps         [cq+1*8], m2
+    movhps         [cq+2*8], m5
+    movhps         [cq+3*8], m7
+    movhps         [cq+4*8], m3
+    movhps         [cq+5*8], m1
+    movhps         [cq+6*8], m6
+    movhps         [cq+7*8], m0
+    punpcklqdq           m0, m6
+    punpcklqdq           m1, m3
+    punpcklqdq           m3, m2, m4
+    punpcklqdq           m2, m7, m5
+    jmp m(idct_4x16_internal_16bpc).end
+
+INV_TXFM_4X16_FN flipadst, dct
+INV_TXFM_4X16_FN flipadst, adst
+INV_TXFM_4X16_FN flipadst, flipadst
+INV_TXFM_4X16_FN flipadst, identity, v
+
+cglobal iflipadst_4x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%undef cmp
+%if ARCH_X86_32
+    mov                 r5m, r6d
+%endif
+    mov                 r6d, 4
+.zero_loop:
+    dec                 r6d
+    cmp                eobb, byte [r5+r6]
+    jl .zero_loop
+    mov                 r5d, r6d
+    shl                 r5d, 4
+%if ARCH_X86_32
+    ; restore pic-ptr
+    mov                  r6, r5m
+%endif
+.loop_pass1:
+    mova                 m5, [cq+64*0+r5]
+    lea                  r3, [cq+64*1+r5]
+    mova                 m1, [cq+64*2+r5]
+    mova                 m3, [cq+64*3+r5]
+    call m(iadst_4x4_internal_16bpc).main2
+    pcmpeqd              m3, m3
+    REPX      {psubd x, m3}, m0, m2, m1, m4
+    REPX       {psrad x, 1}, m0, m2, m1, m4
+    packssdw             m0, m2            ; out3 out2
+    packssdw             m1, m4            ; out1 out0
+    punpcklwd            m2, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    test                r5d, r5d
+    jz m(idct_4x16_internal_16bpc).end_pass1
+    mova       [cq+64*0+r5], m0
+    mova       [cq+64*1+r5], m1
+    sub                 r5d, 16
+    jmp .loop_pass1
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_16x4_internal_8bpc, _ssse3).main
+    call m_suffix(iadst_16x4_internal_8bpc, _ssse3).main_pass2_end
+    ; m7/5/2/4 = out11/-4,-10/5,9/-6,-8/7
+    ; m0/3 & cq6/7 = out15/-0,-12/3,-14/1,13/-2
+    mova                 m1, [o(pw_4x2048_4xm2048)]
+    REPX   {pmulhrsw x, m1}, m7, m2, m0
+    pshufd               m6, m1, q1032  ; 4x-2048,4x2048
+    pmulhrsw             m1, [cq+16*7]
+    REPX   {pmulhrsw x, m6}, m5, m4, m3
+    pmulhrsw             m6, [cq+16*6]
+    ; m7/5/2/4 = out11/4,10/5,9/6,8/7
+    ; m0/3/6/1 = out15/0,12/3,14/1,13/2
+    ; output should be as 0-3 for out0-7, and cq+0-3*16 for out8-15
+    movq           [cq+0*8], m4
+    movq           [cq+1*8], m2
+    movq           [cq+2*8], m5
+    movq           [cq+3*8], m7
+    movq           [cq+4*8], m3
+    movq           [cq+5*8], m1
+    movq           [cq+6*8], m6
+    movq           [cq+7*8], m0
+    punpckhqdq           m0, m6
+    punpckhqdq           m1, m3
+    punpckhqdq           m3, m2, m4
+    punpckhqdq           m2, m7, m5
+    jmp m(idct_4x16_internal_16bpc).end
+
+INV_TXFM_4X16_FN identity, dct, h
+INV_TXFM_4X16_FN identity, adst, h
+INV_TXFM_4X16_FN identity, flipadst, h
+INV_TXFM_4X16_FN identity, identity
+
+cglobal iidentity_4x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%undef cmp
+%if ARCH_X86_32
+    mov                 r5m, r6d
+%endif
+    mov                 r6d, 4
+.zero_loop:
+    dec                 r6d
+    cmp                eobb, byte [r5+r6]
+    jl .zero_loop
+    mov                 r5d, r6d
+    shl                 r5d, 4
+%if ARCH_X86_32
+    ; restore pic-ptr
+    mov                  r6, r5m
+%endif
+    mova                 m5, [o(pd_6144)]
+    mova                 m4, [o(pd_5793)]
+.loop_pass1:
+    pmulld               m0, m4, [cq+64*0+r5]
+    pmulld               m1, m4, [cq+64*1+r5]
+    pmulld               m2, m4, [cq+64*2+r5]
+    pmulld               m3, m4, [cq+64*3+r5]
+    REPX      {paddd x, m5}, m0, m1, m2, m3
+    REPX      {psrad x, 13}, m0, m1, m2, m3
+    packssdw             m0, m1
+    packssdw             m2, m3
+    punpckhwd            m3, m0, m2
+    punpcklwd            m0, m2
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    test                r5d, r5d
+    jz m(idct_4x16_internal_16bpc).end_pass1
+    mova       [cq+64*0+r5], m0
+    mova       [cq+64*1+r5], m1
+    sub                 r5d, 16
+    jmp .loop_pass1
+.pass2:
+    mova          [cq+16*4], m0
+    mova          [cq+16*5], m1
+    mova          [cq+16*6], m2
+    mova          [cq+16*7], m7
+    mova                 m0, [o(pw_1697x16)]
+    mova                 m7, [o(pw_2048)]
+    pmulhrsw             m1, m0, m4
+    pmulhrsw             m2, m0, m5
+    REPX      {paddsw x, x}, m4, m5
+    paddsw               m4, m1
+    paddsw               m5, m2
+    REPX   {pmulhrsw x, m7}, m4, m5
+    mova          [cq+16*0], m4
+    mova          [cq+16*1], m5
+    mova                 m4, [cq+16*7]
+    pmulhrsw             m1, m0, m6
+    pmulhrsw             m2, m0, m4
+    REPX      {paddsw x, x}, m6, m4
+    paddsw               m6, m1
+    paddsw               m4, m2
+    REPX   {pmulhrsw x, m7}, m6, m4
+    mova          [cq+16*2], m6
+    mova          [cq+16*3], m4
+    mova                 m4, [cq+16*4]
+    mova                 m1, [cq+16*5]
+    mova                 m2, [cq+16*6]
+    pmulhrsw             m5, m0, m2
+    pmulhrsw             m6, m0, m3
+    REPX      {paddsw x, x}, m2, m3
+    paddsw               m2, m5
+    paddsw               m3, m6
+    pmulhrsw             m6, m0, m1
+    pmulhrsw             m0, m4
+    REPX      {paddsw x, x}, m1, m4
+    paddsw               m1, m6
+    paddsw               m0, m4
+    REPX   {pmulhrsw x, m7}, m2, m3, m1, m0
+    jmp m(idct_4x16_internal_16bpc).end
+
+%macro INV_TXFM_8X4_FN 2 ; type1, type2
+%if ARCH_X86_64
+    INV_TXFM_FN          %1, %2, 0, 8x4, 15
+%else
+    INV_TXFM_FN          %1, %2, 0, 8x4, 8, 0-4*16
+%endif
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 181
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 2896
+    add                 r5d, 34816
+    movd                 m0, r5d
+    pshuflw              m0, m0, q1111
+    punpcklqdq           m0, m0
+    mova                 m6, [o(pixel_10bpc_max)]
+    pxor                 m5, m5
+    lea                  r2, [strideq*3]
+    mova                 m1, [dstq+strideq*0]
+    mova                 m2, [dstq+strideq*1]
+    mova                 m3, [dstq+strideq*2]
+    mova                 m4, [dstq+r2]
+    REPX      {paddw x, m0}, m1, m2, m3, m4
+    REPX     {pmaxsw x, m5}, m1, m2, m3, m4
+    REPX     {pminsw x, m6}, m1, m2, m3, m4
+    mova   [dstq+strideq*0], m1
+    mova   [dstq+strideq*1], m2
+    mova   [dstq+strideq*2], m3
+    mova   [dstq+r2       ], m4
+    RET
+%endif
+%endmacro
+
+INV_TXFM_8X4_FN dct, dct
+INV_TXFM_8X4_FN dct, identity
+INV_TXFM_8X4_FN dct, adst
+INV_TXFM_8X4_FN dct, flipadst
+
+cglobal idct_8x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    lea                  r5, [o(.main)]
+.pass1_entry:
+%if ARCH_X86_32
+    lea                  r3, [rsp+gprsize]
+%else
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+0*16]
+    mova                 m1, [cq+1*16]
+    mova                 m2, [cq+2*16]
+    mova                 m3, [cq+3*16]
+    mova                 m4, [cq+4*16]
+    mova                 m5, [cq+5*16]
+    mova                 m6, [cq+6*16]
+    mova                 m7, [cq+7*16]
+    call .rect2_mul
+    call                 r5
+    call .transpose4x8packed
+    ; m0-3 = packed & transposed output
+    jmp                tx2q
+.transpose4x8packed:
+    ; transpose
+    punpcklwd            m1, m2, m6
+    punpckhwd            m2, m6
+    punpckhwd            m6, m0, m4
+    punpcklwd            m0, m4
+
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m4, m6, m2
+    punpcklwd            m6, m2
+
+    punpcklwd            m2, m3, m4
+    punpckhwd            m3, m4
+    punpckhwd            m1, m0, m6
+    punpcklwd            m0, m6
+    ret
+.main:
+    call .main_pass1
+    call .round
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    ret
+.rect2_mul:
+%if ARCH_X86_64
+    REPX    {pmulld x, m14}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {paddd  x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+%else
+    mova               [r3], m7
+    mova                 m7, [o(pd_2896)]
+    REPX     {pmulld x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulld               m7, [r3]
+    mova               [r3], m7
+    mova                 m7, [o(pd_2048)]
+    REPX      {paddd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    paddd                m7, [r3]
+%endif
+    REPX      {psrad x, 12}, m0, m1, m2, m3, m4, m5, m6, m7
+    ret
+%if ARCH_X86_64
+.main_pass1_fast:
+    pmulld               m5, m3, [o(pd_m2276)]
+    pmulld               m3, [o(pd_3406)]
+    pmulld               m7, m1, [o(pd_4017)]
+    pmulld               m1, [o(pd_799)]
+    pmulld               m6, m2, [o(pd_3784)]
+    pmulld               m2, [o(pd_1567)]
+    pmulld               m0, m14
+    pxor                 m4, m4
+    jmp .main_pass1_fast2
+.main_pass1:
+    ITX_MULSUB_2D         5, 3, 8, 9, 10, _, 3406, 2276 ; t5a t6a
+    ITX_MULSUB_2D         1, 7, 8, 9, 10, _,  799, 4017 ; t4a t7a
+    ITX_MULSUB_2D         2, 6, 8, 9, 10, _, 1567, 3784 ; t2  t3
+    REPX    {pmulld x, m14}, m0, m4
+.main_pass1_fast2:
+    REPX     {paddd x, m11}, m1, m2, m3, m5, m6, m7
+    REPX     {psrad x, 12 }, m1, m2, m3, m5, m6, m7
+    paddd                m8, m1, m5 ; t4
+    psubd                m1, m5     ; t5a
+    paddd                m9, m7, m3 ; t7
+    psubd                m7, m3     ; t6a
+    REPX    {pmaxsd x, m12}, m1, m8, m7, m9
+    REPX    {pminsd x, m13}, m1, m8, m7, m9
+    REPX    {pmulld x, m14}, m7, m1
+    paddd                m0, m11
+    paddd                m7, m11
+    psubd                m5, m0, m4
+    paddd                m0, m4
+    psubd                m4, m7, m1
+    paddd                m7, m1
+    REPX    {psrad  x, 12 }, m5, m0, m4, m7
+    psubd                m3, m0, m6 ; dct4 out3
+    paddd                m0, m6     ; dct4 out0
+    paddd                m6, m5, m2 ; dct4 out1
+    psubd                m5, m2     ; dct4 out2
+    REPX    {pmaxsd x, m12}, m0, m6, m5, m3
+    REPX    {pminsd x, m13}, m0, m6, m5, m3
+    ret
+.round:
+    paddd                m1, m6, m7 ; out1
+    psubd                m6, m7     ; out6
+    psubd                m7, m0, m9 ; out7
+    paddd                m0, m9     ; out0
+    paddd                m2, m5, m4 ; out2
+    psubd                m5, m4     ; out5
+    psubd                m4, m3, m8 ; out4
+    paddd                m3, m8     ; out3
+%else
+.main_pass1_fast:
+    pmulld               m5, m3, [o(pd_m2276)]
+    pmulld               m3, [o(pd_3406)]
+    pmulld               m7, m1, [o(pd_4017)]
+    pmulld               m1, [o(pd_799)]
+    pmulld               m6, m2, [o(pd_3784)]
+    pmulld               m2, [o(pd_1567)]
+    mova                 m4, [o(pd_2048)]
+    mova          [r3+0*16], m2
+    REPX      {paddd x, m4}, m5, m3, m7, m1
+    REPX      {psrad x, 12}, m5, m3, m7, m1
+    paddd                m2, m1, m5 ; t4
+    psubd                m1, m5     ; t5a
+    pmulld               m5, m0, [o(pd_2896)]
+    mova                 m0, m4
+    paddd                m4, m7, m3 ; t7
+    psubd                m7, m3     ; t6a
+    mova                 m3, [o(clip_18b_min)]
+    REPX    {pmaxsd x, m3 }, m1, m2, m7, m4
+    mova                 m3, [o(clip_18b_max)]
+    REPX    {pminsd x, m3 }, m1, m2, m7, m4
+    mova          [r3+3*16], m2
+    mova          [r3+1*16], m4
+    pxor                 m4, m4
+    mova                 m2, [r3+0*16]
+    mova                 m3, [o(pd_2896)]
+    jmp .main_pass1_fast2
+.main_pass1:
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m2
+    mova          [r3+2*16], m4
+    mova          [r3+3*16], m6
+    mova                 m0, [o(pd_2048)]
+    ITX_MULSUB_2D         5, 3, 2, 4, 6, 0, 3406, 2276 ; t5a t6a
+    ITX_MULSUB_2D         1, 7, 2, 4, 6, 0,  799, 4017 ; t4a t7a
+    paddd                m2, m1, m5 ; t4
+    psubd                m1, m5     ; t5a
+    paddd                m4, m7, m3 ; t7
+    psubd                m7, m3     ; t6a
+    mova                 m6, [o(clip_18b_min)]
+    REPX    {pmaxsd x, m6 }, m1, m2, m7, m4
+    mova                 m6, [o(clip_18b_max)]
+    REPX    {pminsd x, m6 }, m1, m2, m7, m4
+    mova                 m6, [r3+3*16]
+    mova          [r3+3*16], m2
+    mova                 m2, [r3+1*16]
+    mova          [r3+1*16], m4
+
+    ITX_MULSUB_2D         2, 6, 4, 3, 5, _, 1567, 3784 ; t2  t3
+    mova                 m3, [o(pd_2896)]
+    mova                 m5, [r3+0*16]
+    mova                 m4, [r3+2*16]
+    REPX    {pmulld x, m3 }, m5, m4
+.main_pass1_fast2:
+    REPX    {paddd  x, m0 }, m2, m6
+    REPX    {psrad  x, 12 }, m2, m6
+    REPX    {pmulld x, m3 }, m7, m1
+    paddd                m7, m0
+    paddd                m0, m5
+
+    psubd                m5, m0, m4
+    paddd                m0, m4
+    psubd                m4, m7, m1
+    paddd                m7, m1
+    REPX    {psrad  x, 12 }, m5, m0, m4, m7
+    psubd                m3, m0, m6 ; dct4 out3
+    paddd                m0, m6     ; dct4 out0
+    paddd                m6, m5, m2 ; dct4 out1
+    psubd                m5, m2     ; dct4 out2
+
+    mova                 m1, [o(clip_18b_min)]
+    REPX    {pmaxsd x, m1 }, m0, m6, m5, m3
+    mova                 m1, [o(clip_18b_max)]
+    REPX    {pminsd x, m1 }, m0, m6, m5, m3
+    ret
+.round:
+    paddd                m1, m6, m7 ; out1
+    psubd                m6, m7     ; out6
+    mova          [r3+0*16], m6
+    mova                 m6, [r3+1*16]
+    psubd                m7, m0, m6 ; out7
+    paddd                m0, m6     ; out0
+    paddd                m2, m5, m4 ; out2
+    psubd                m5, m4     ; out5
+    mova                 m6, [r3+3*16]
+    psubd                m4, m3, m6 ; out4
+    paddd                m3, m6     ; out3
+    mova                 m6, [r3+0*16]
+%endif
+    ret
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(idct_8x4_internal_8bpc, _ssse3).main
+.end:
+    lea                  r3, [strideq*3]
+    call .round2_and_write_8x4
+    REPX {mova [cq+16*x], m6}, 0, 1, 2, 3, 4, 5, 6, 7
+    RET
+.round2_and_write_8x4:
+    pxor                 m6, m6
+    mova                 m5, [o(pixel_10bpc_max)]
+    mova                 m4, [o(pw_2048)]
+.round1_and_write_8x4:
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+.write_8x4:
+    paddw                m0, [dstq+strideq*0]
+    paddw                m1, [dstq+strideq*1]
+    paddw                m2, [dstq+strideq*2]
+    paddw                m3, [dstq+r3]
+    REPX     {pminsw x, m5}, m0, m1, m2, m3
+    REPX     {pmaxsw x, m6}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+r3       ], m3
+    ret
+
+INV_TXFM_8X4_FN adst, dct
+INV_TXFM_8X4_FN adst, adst
+INV_TXFM_8X4_FN adst, flipadst
+INV_TXFM_8X4_FN adst, identity
+
+cglobal iadst_8x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    lea                  r5, [o(.main)]
+    jmp m(idct_8x4_internal_16bpc).pass1_entry
+.main:
+    call .main_pass1
+    call .round
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    ret
+.main_pass1:
+%if ARCH_X86_64
+    ITX_MULSUB_2D         7, 0, 8, 9, 10, 11,  401, 4076 ; t1a, t0a
+    ITX_MULSUB_2D         1, 6, 8, 9, 10, 11, 3920, 1189 ; t7a, t6a
+    ITX_MULSUB_2D         5, 2, 8, 9, 10, 11, 1931, 3612 ; t3a, t2a
+    ITX_MULSUB_2D         3, 4, 8, 9, 10, 11, 3166, 2598 ; t5a, t4a
+    psubd                m8, m2, m6 ; t6
+    paddd                m2, m6     ; t2
+    psubd                m6, m0, m4 ; t4
+    paddd                m0, m4     ; t0
+    psubd                m4, m5, m1 ; t7
+    paddd                m5, m1     ; t3
+    psubd                m1, m7, m3 ; t5
+    paddd                m7, m3     ; t1
+    REPX    {pmaxsd x, m12}, m6, m1, m8, m4, m2, m0, m5, m7
+    REPX    {pminsd x, m13}, m6, m1, m8, m4, m2, m0, m5, m7
+    ITX_MULSUB_2D         6, 1, 3, 9, 10, 11, 1567, 3784 ; t5a, t4a
+    ITX_MULSUB_2D         4, 8, 3, 9, 10, 11, 3784, 10   ; t6a, t7a
+    psubd                m9, m6, m8 ;  t7
+    paddd                m6, m8     ;  out6
+    mova                 m8, [o(pd_2896)]
+    psubd                m3, m7, m5 ;  t3
+    paddd                m7, m5     ; -out7
+    psubd                m5, m0, m2 ;  t2
+    paddd                m0, m2     ;  out0
+    psubd                m2, m1, m4 ;  t6
+    paddd                m1, m4     ; -out1
+    REPX    {pmaxsd x, m12}, m5, m3, m2, m9
+    REPX    {pminsd x, m13}, m5, m3, m2, m9
+    REPX    {pmulld x, m14}, m5, m3, m2, m9
+    psubd               m4, m5, m3 ; (t2 - t3) * 2896
+    paddd               m3, m5     ; (t2 + t3) * 2896
+    psubd               m5, m2, m9 ; (t6 - t7) * 2896
+    paddd               m2, m9     ; (t6 + t7) * 2896
+    ret
+.round:
+
+    ; m0=out0,m1=-out1,m6=out6,m7=-out7
+
+    pcmpeqd              m8, m8
+    REPX     {pxor  x, m8 }, m1, m7, m3, m5
+    REPX     {psubd x, m8 }, m1, m7
+    REPX     {paddd x, m11}, m2, m3, m4, m5
+    REPX     {psrad x, 12 }, m2, m3, m4, m5
+%else
+    mova          [r3+0*16], m2
+    mova          [r3+1*16], m3
+    mova          [r3+2*16], m4
+    mova          [r3+3*16], m5
+    mova                 m5, [o(pd_2048)]
+
+    ITX_MULSUB_2D         7, 0, 2, 3, 4, 5,  401, 4076 ; t1a, t0a
+    ITX_MULSUB_2D         1, 6, 2, 3, 4, 5, 3920, 1189 ; t7a, t6a
+    mova                 m2, [r3+0*16]
+    mova                 m3, [r3+1*16]
+    mova                 m4, [r3+2*16]
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m1
+    mova          [r3+2*16], m6
+    mova                 m1, [r3+3*16]
+    mova          [r3+3*16], m7
+    ITX_MULSUB_2D         1, 2, 0, 6, 7, 5, 1931, 3612 ; t3a, t2a
+    ITX_MULSUB_2D         3, 4, 0, 6, 7, 5, 3166, 2598 ; t5a, t4a
+    mova                 m0, [r3+0*16]
+    mova                 m6, [r3+2*16]
+    psubd                m7, m2, m6 ; t6
+    paddd                m2, m6     ; t2
+    psubd                m6, m0, m4 ; t4
+    paddd                m0, m4     ; t0
+    mova          [r3+0*16], m7
+    mova                 m5, [r3+1*16]
+    mova                 m7, [r3+3*16]
+    psubd                m4, m1, m5 ; t7
+    paddd                m5, m1     ; t3
+    psubd                m1, m7, m3 ; t5
+    paddd                m7, m3     ; t1
+    mova                 m3, [o(clip_18b_min)]
+    REPX    {pmaxsd x, m3 }, m6, m1, m4, m2, m0, m5, m7
+    mova          [r3+1*16], m7
+    mova                 m7, [o(clip_18b_max)]
+    pmaxsd               m3, [r3+0*16]
+    REPX    {pminsd x, m7 }, m6, m1, m3, m4, m2, m0, m5
+    pminsd               m7, [r3+1*16]
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m2
+    mova          [r3+2*16], m5
+    mova          [r3+3*16], m7
+    mova                 m0, [o(pd_2048)]
+    ITX_MULSUB_2D         6, 1, 2, 5, 7, 0, 1567, 3784 ; t5a, t4a
+    ITX_MULSUB_2D         4, 3, 2, 5, 7, 0, 3784, 7    ; t6a, t7a
+    mova                 m5, [r3+2*16]
+    mova                 m7, [r3+3*16]
+    psubd                m2, m6, m3 ;  t7
+    paddd                m6, m3     ;  out6
+    mova          [r3+3*16], m6
+    mova                 m0, [r3+0*16]
+    mova                 m6, [r3+1*16]
+    psubd                m3, m7, m5 ;  t3
+    paddd                m7, m5     ; -out7
+    psubd                m5, m0, m6 ;  t2
+    paddd                m0, m6     ;  out0
+    psubd                m6, m1, m4 ;  t6
+    paddd                m1, m4     ; -out1
+    mova                 m4, [o(clip_18b_min)]
+    REPX    {pmaxsd x, m4 }, m5, m3, m6, m2
+    mova                 m4, [o(clip_18b_max)]
+    REPX    {pminsd x, m4 }, m5, m3, m6, m2
+    mova                 m4, [o(pd_2896)]
+    REPX    {pmulld x, m4 }, m5, m3, m6, m2
+    psubd               m4, m5, m3 ; (t2 - t3) * 2896
+    paddd               m3, m5     ; (t2 + t3) * 2896
+    psubd               m5, m6, m2 ; (t6 - t7) * 2896
+    paddd               m2, m6     ; (t6 + t7) * 2896
+    ret
+.round:
+    mova          [r3+2*16], m0
+
+    pcmpeqd              m0, m0
+    mova                 m6, [o(pd_2048)]
+    REPX     {pxor  x, m0 }, m1, m7, m3, m5
+    REPX     {psubd x, m0 }, m1, m7
+    REPX     {paddd x, m6 }, m2, m3, m4, m5
+    REPX     {psrad x, 12 }, m2, m3, m4, m5
+
+    mova                 m6, [r3+3*16]
+    mova                 m0, [r3+2*16]
+%endif
+    ret
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_8x4_internal_8bpc, _ssse3).main
+    jmp m(idct_8x4_internal_16bpc).end
+
+INV_TXFM_8X4_FN flipadst, dct
+INV_TXFM_8X4_FN flipadst, adst
+INV_TXFM_8X4_FN flipadst, flipadst
+INV_TXFM_8X4_FN flipadst, identity
+
+cglobal iflipadst_8x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    lea                  r5, [o(.main)]
+    jmp m(idct_8x4_internal_16bpc).pass1_entry
+.main:
+    call m(iadst_8x4_internal_16bpc).main_pass1
+    call m(iadst_8x4_internal_16bpc).round
+    packssdw             m7, m6
+    packssdw             m5, m4
+    packssdw             m3, m2
+    packssdw             m1, m0
+    mova                 m0, m7
+    mova                 m2, m5
+    mova                 m4, m3
+    mova                 m6, m1
+    ret
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_8x4_internal_8bpc, _ssse3).main
+    lea                  r3, [strideq*3]
+    add                dstq, r3
+    neg             strideq
+    jmp m(idct_8x4_internal_16bpc).end
+
+INV_TXFM_8X4_FN identity, dct
+INV_TXFM_8X4_FN identity, adst
+INV_TXFM_8X4_FN identity, flipadst
+INV_TXFM_8X4_FN identity, identity
+
+cglobal iidentity_8x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    lea                  r5, [o(.main)]
+    jmp m(idct_8x4_internal_16bpc).pass1_entry
+.main:
+    REPX       {paddd x, x}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    ret
+.pass2:
+    mova                 m7, [o(pw_1697x8)]
+    pmulhrsw             m4, m7, m0
+    pmulhrsw             m5, m7, m1
+    pmulhrsw             m6, m7, m2
+    pmulhrsw             m7, m3
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    jmp m(idct_8x4_internal_16bpc).end
+
+%macro INV_TXFM_8X8_FN 2-3 0 ; type1, type2, eob_offset
+%if ARCH_X86_64
+    INV_TXFM_FN          %1, %2, %3, 8x8, 15, 0-3*16
+%else
+    INV_TXFM_FN          %1, %2, %3, 8x8, 8, 0-5*16
+%endif
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 2
+.end:
+    add                 r5d, 384
+    sar                 r5d, 9
+.end2:
+    imul                r5d, 2896
+    add                 r5d, 34816
+    movd                 m0, r5d
+    pshuflw              m0, m0, q1111
+    punpcklqdq           m0, m0
+    mova                 m6, [o(pixel_10bpc_max)]
+    pxor                 m5, m5
+    lea                  r2, [strideq*3]
+.loop:
+    mova                 m1, [dstq+strideq*0]
+    mova                 m2, [dstq+strideq*1]
+    mova                 m3, [dstq+strideq*2]
+    mova                 m4, [dstq+r2]
+    REPX      {paddw x, m0}, m1, m2, m3, m4
+    REPX     {pmaxsw x, m5}, m1, m2, m3, m4
+    REPX     {pminsw x, m6}, m1, m2, m3, m4
+    mova   [dstq+strideq*0], m1
+    mova   [dstq+strideq*1], m2
+    mova   [dstq+strideq*2], m3
+    mova   [dstq+r2       ], m4
+    lea                dstq, [dstq+strideq*4]
+    dec                 r3d
+    jg .loop
+    RET
+%endif
+%endmacro
+
+INV_TXFM_8X8_FN dct, dct
+INV_TXFM_8X8_FN dct, identity, 6
+INV_TXFM_8X8_FN dct, adst
+INV_TXFM_8X8_FN dct, flipadst
+
+cglobal idct_8x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_32
+    DECLARE_REG_TMP 1
+    mov [rsp+4*16+1*gprsize], r1
+%else
+    DECLARE_REG_TMP 6
+%endif
+    lea                  t0, [o(.pass1_main)]
+
+.pass1_full:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+%undef cmp
+%if ARCH_X86_64
+    xor                 r5d, r5d
+    cmp                eobd, 10
+    setge               r5b
+%else
+    mov                 r5d, 1
+    cmp                eobd, 10
+    sbb                 r5d, 0
+%endif
+    shl                 r5d, 4
+%if ARCH_X86_32
+    lea                  r3, [rsp+gprsize]
+%endif
+.loop_pass1:
+    mova                 m0, [cq+0*32+r5]
+    mova                 m1, [cq+1*32+r5]
+    mova                 m2, [cq+2*32+r5]
+    mova                 m3, [cq+3*32+r5]
+    mova                 m4, [cq+4*32+r5]
+    mova                 m5, [cq+5*32+r5]
+    mova                 m6, [cq+6*32+r5]
+    mova                 m7, [cq+7*32+r5]
+    call                 t0
+
+    test                r5d, r5d
+    jz .end_pass1
+
+    mova       [cq+0*32+16], m0
+    mova       [cq+1*32+16], m1
+    mova       [cq+2*32+16], m2
+    mova       [cq+3*32+16], m3
+
+    sub                 r5d, 16
+    jmp .loop_pass1
+.end_pass1:
+    mova                 m4, [cq+0*32+16]
+    mova                 m5, [cq+1*32+16]
+    mova                 m6, [cq+2*32+16]
+    mova                 m7, [cq+3*32+16]
+%if ARCH_X86_32
+    mov                  r1, [rsp+4*16+1*gprsize]
+%endif
+    jmp                tx2q
+.pass1_main:
+    call m(idct_8x4_internal_16bpc).main_pass1
+    pcmpeqd              m1, m1
+    REPX      {psubd x, m1}, m0, m6, m5, m3
+    call m(idct_8x4_internal_16bpc).round
+    REPX      {psrad x, 1 }, m0, m1, m2, m3, m4, m5, m6, m7
+.pack_and_transpose:
+    packssdw             m2, m3
+    packssdw             m6, m7
+    packssdw             m0, m1
+    packssdw             m4, m5
+    jmp m(idct_8x4_internal_16bpc).transpose4x8packed
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(idct_8x8_internal_8bpc, _ssse3).main
+    lea                  r3, [strideq*3]
+%if ARCH_X86_64
+    mova                m10, [o(pixel_10bpc_max)]
+    pxor                 m9, m9
+%endif
+    call .round3_and_write_8x8
+.zero:
+%if ARCH_X86_64
+%define mzero m9
+%else
+%define mzero m7
+    pxor                 m7, m7
+%endif
+    REPX {mova [cq+16*x], mzero}, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+%undef mzero
+    RET
+
+    ; round (rounded right-shift by 5) before writing
+    ; data in m0-7
+    ; on x86-64, pw_2048 is in m8
+    ; .round1 is for m0-7
+    ; .round2 is for m0-6 & [rsp+gprsize*2]
+    ; .round3 is same, but without using m8 on x86-64 (.round2/3 are identical on x86-32)
+    ; .round4 is x86-32-only, it is similar to .round2 but with constant already in m7
+%if ARCH_X86_32
+.round1_and_write_8x8:
+    mova    [rsp+gprsize*2], m7
+.round2_and_write_8x8:
+%endif
+.round3_and_write_8x8:
+    mova                 m7, [o(pw_2048)]
+%if ARCH_X86_32
+.round4_and_write_8x8:
+%endif
+    REPX   {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulhrsw             m7, [rsp+gprsize*2]
+%if ARCH_X86_64
+    jmp .write_8x8
+.round2_and_write_8x8:
+    mova                 m7, [rsp+gprsize*2]
+.round1_and_write_8x8:
+    REPX   {pmulhrsw x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+%endif
+
+    ; m0-7 have to-be-written data [pre-rounded]
+    ; on x86-64, m9-10 contain a zero/pixel_max
+    ; on x86-32, these are runtime-generated, and [rsp+gprsize*2] is scratch
+    ; r0,1,3 contain dstq/strideq/stride3q
+    ; r5 is a scratch register
+.write_8x8:
+    lea                  r5, [dstq+strideq*4]
+    paddw                m0, [dstq+strideq*0]
+    paddw                m1, [dstq+strideq*1]
+    paddw                m2, [dstq+strideq*2]
+    paddw                m3, [dstq+r3]
+    paddw                m4, [r5  +strideq*0]
+    paddw                m5, [r5  +strideq*1]
+    paddw                m6, [r5  +strideq*2]
+    paddw                m7, [r5  +r3]
+%if ARCH_X86_64
+    REPX    {pmaxsw x, m9 }, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsw x, m10}, m0, m1, m2, m3, m4, m5, m6, m7
+%else
+    mova    [rsp+gprsize*2], m7
+    pxor                 m7, m7
+    REPX     {pmaxsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmaxsw               m7, [rsp+gprsize*2]
+    mova    [rsp+gprsize*2], m7
+    mova                 m7, [o(pixel_10bpc_max)]
+    REPX     {pminsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pminsw               m7, [rsp+gprsize*2]
+%endif
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+r3       ], m3
+    mova   [r5  +strideq*0], m4
+    mova   [r5  +strideq*1], m5
+    mova   [r5  +strideq*2], m6
+    mova   [r5  +r3       ], m7
+    ret
+
+INV_TXFM_8X8_FN adst, dct
+INV_TXFM_8X8_FN adst, adst
+INV_TXFM_8X8_FN adst, flipadst
+INV_TXFM_8X8_FN adst, identity, 6
+
+cglobal iadst_8x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_32
+    mov [rsp+4*16+1*gprsize], r1
+%endif
+    lea                  t0, [o(.pass1_main)]
+    jmp m(idct_8x8_internal_16bpc).pass1_full
+.pass1_main:
+    call m(iadst_8x4_internal_16bpc).main_pass1
+    call .round
+    jmp m(idct_8x8_internal_16bpc).pack_and_transpose
+.round:
+%if ARCH_X86_64
+    pcmpeqd              m8, m8         ; -1
+    REPX     {psubd x, m8 }, m0, m6
+    REPX     {pxor  x, m8 }, m1, m7, m3, m5
+    REPX     {psrad x, 1  }, m0, m1, m6, m7
+    REPX     {psubd x, m8 }, m1, m7
+    mova                 m8, [o(pd_6144)]
+    REPX     {paddd x, m8 }, m2, m3, m4, m5
+    REPX     {psrad x, 13 }, m2, m3, m4, m5
+%else
+    mova          [r3+2*16], m0
+
+    pcmpeqd              m0, m0         ; -1
+    mova                 m6, [o(pd_6144)]
+    REPX     {pxor  x, m0 }, m1, m7, m3, m5
+    REPX     {psrad x, 1  }, m1, m7
+    REPX     {psubd x, m0 }, m1, m7
+    REPX     {paddd x, m6 }, m2, m3, m4, m5
+    REPX     {psrad x, 13 }, m2, m3, m4, m5
+
+    mova                 m0, [r3+2*16]
+    psrld                m6, 12         ; +1
+    paddd                m0, m6
+    paddd                m6, [r3+3*16]
+    REPX     {psrad x, 1  }, m0, m6
+%endif
+    ret
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_8x8_internal_8bpc, _ssse3).main
+    call m_suffix(iadst_8x8_internal_8bpc, _ssse3).main_pass2_end
+    lea                  r3, [strideq*3]
+%if ARCH_X86_64
+    mova                m10, [o(pixel_10bpc_max)]
+    pxor                 m9, m9
+%endif
+    call .round3_and_write_8x8
+    jmp m(idct_8x8_internal_16bpc).zero
+
+    ; round (rounded right-shift by 5) before writing; odd registers are negated
+    ; data in m0-7
+    ; on x86-64, pw_2048 is in m8 and pw_m2048 is in m11
+    ; .round1 is for m0-7
+    ; .round2 is for m0-6 & [rsp+gprsize*2]
+    ; .round3 is same, but without using m8 on x86-64 (.round2/3 are identical on x86-32)
+%if ARCH_X86_64
+.round2_and_write_8x8:
+    mova                 m7, [rsp+gprsize*2]
+.round1_and_write_8x8:
+    REPX  {pmulhrsw x, m8 }, m0, m2, m4, m6
+    REPX  {pmulhrsw x, m11}, m1, m3, m5, m7
+    jmp m(idct_8x8_internal_16bpc).write_8x8
+%else
+.round1_and_write_8x8:
+    mova    [rsp+gprsize*2], m7
+.round2_and_write_8x8:
+%endif
+.round3_and_write_8x8:
+    mova                 m7, [o(pw_2048)]
+    REPX   {pmulhrsw x, m7}, m0, m2, m4, m6
+    mova                 m7, [o(pw_m2048)]
+    REPX   {pmulhrsw x, m7}, m1, m3, m5
+    pmulhrsw             m7, [rsp+gprsize*2]
+    jmp m(idct_8x8_internal_16bpc).write_8x8
+
+INV_TXFM_8X8_FN flipadst, dct
+INV_TXFM_8X8_FN flipadst, adst
+INV_TXFM_8X8_FN flipadst, flipadst
+INV_TXFM_8X8_FN flipadst, identity, 6
+
+cglobal iflipadst_8x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_32
+    mov [rsp+4*16+1*gprsize], r1
+%endif
+    lea                  t0, [o(.pass1_main)]
+    jmp m(idct_8x8_internal_16bpc).pass1_full
+.pass1_main:
+    call m(iadst_8x4_internal_16bpc).main_pass1
+    call m(iadst_8x8_internal_16bpc).round
+    ; invert registers
+    packssdw             m7, m6
+    packssdw             m5, m4
+    packssdw             m3, m2
+    packssdw             m1, m0
+    mova                 m0, m7
+    mova                 m2, m5
+    mova                 m4, m3
+    mova                 m6, m1
+    jmp m(idct_8x4_internal_16bpc).transpose4x8packed
+
+.pass2:
+    lea                dstq, [dstq+strideq*8]
+    sub                dstq, strideq
+    neg             strideq
+    jmp m(iadst_8x8_internal_16bpc).pass2
+
+INV_TXFM_8X8_FN identity, dct
+INV_TXFM_8X8_FN identity, adst
+INV_TXFM_8X8_FN identity, flipadst
+INV_TXFM_8X8_FN identity, identity
+
+cglobal iidentity_8x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    mova                 m0, [cq+0*32]
+    mova                 m1, [cq+1*32]
+    mova                 m2, [cq+2*32]
+    mova                 m3, [cq+3*32]
+    mova                 m4, [cq+4*32]
+    mova                 m5, [cq+5*32]
+    mova                 m6, [cq+6*32]
+    mova                 m7, [cq+7*32]
+    packssdw             m0, [cq+0*32+16]
+    packssdw             m1, [cq+1*32+16]
+    packssdw             m2, [cq+2*32+16]
+    packssdw             m3, [cq+3*32+16]
+    packssdw             m4, [cq+4*32+16]
+    packssdw             m5, [cq+5*32+16]
+    packssdw             m6, [cq+6*32+16]
+    packssdw             m7, [cq+7*32+16]
+    mova [rsp+gprsize+16*1], m6
+    jmp m_suffix(idct_8x8_internal_8bpc, _ssse3).pass1_end3
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    lea                  r3, [strideq*3]
+%if ARCH_X86_64
+    mova                m10, [o(pixel_10bpc_max)]
+    pxor                 m9, m9
+    mova                 m8, [o(pw_4096)]
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+%else
+    mova      [rsp+gprsize], m7
+    mova                 m7, [o(pw_4096)]
+    call m(idct_8x8_internal_16bpc).round4_and_write_8x8
+%endif
+    jmp m(idct_8x8_internal_16bpc).zero
+
+%macro INV_TXFM_8X16_FN 2-3 2d ; type1, type2, eob_tbl_suffix
+%if ARCH_X86_64
+    INV_TXFM_FN          %1, %2, tbl_8x16_%3, 8x16, 15, 0-16*16
+%else
+    INV_TXFM_FN          %1, %2, tbl_8x16_%3, 8x16, 8, 0-17*16
+%endif
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 181
+    mov                 r3d, 4
+%if stack_size_padded > 0
+    ; adjust to caller's stack allocation
+    add                 rsp, (12+ARCH_X86_64)*16
+%endif
+    jmp m(inv_txfm_add_dct_dct_8x8_16bpc).end
+%endif
+%endmacro
+
+INV_TXFM_8X16_FN dct, dct
+INV_TXFM_8X16_FN dct, identity, v
+INV_TXFM_8X16_FN dct, adst
+INV_TXFM_8X16_FN dct, flipadst
+
+%if ARCH_X86_64
+DECLARE_REG_TMP 7
+%endif
+
+cglobal idct_8x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if WIN64
+    PUSH                 r7
+%elif ARCH_X86_32
+    mov [rsp+16*16+gprsize*1], r1
+    mov [rsp+16*16+gprsize*2], r6
+%endif
+    lea                  t0, [o(m(idct_8x8_internal_16bpc).pass1_main)]
+.pass1_full:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+%undef cmp
+    mov                 r6d, 4
+.zero_loop:
+    dec                 r6d
+    cmp                eobb, byte [r5+r6]
+    jl .zero_loop
+    mov                 r5d, r6d
+    shl                 r5d, 4
+%if ARCH_X86_32
+    ; restore pic-ptr
+    mov                  r6, [rsp+16*16+2*gprsize]
+    ; setup stack pointer
+    lea                  r3, [rsp+gprsize]
+%endif
+.loop_pass1:
+    mova                 m0, [cq+0*64+r5]
+    mova                 m1, [cq+1*64+r5]
+    mova                 m2, [cq+2*64+r5]
+    mova                 m3, [cq+3*64+r5]
+    mova                 m4, [cq+4*64+r5]
+    mova                 m5, [cq+5*64+r5]
+    mova                 m6, [cq+6*64+r5]
+    mova                 m7, [cq+7*64+r5]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call                 t0
+
+    mova       [cq+0*64+r5], m0
+    mova       [cq+1*64+r5], m1
+    mova       [cq+2*64+r5], m2
+    mova       [cq+3*64+r5], m3
+    sub                 r5d, 16
+    jge .loop_pass1
+%if WIN64
+    POP                  r7
+%elif ARCH_X86_32
+    mov                  r1, [rsp+16*16+1*gprsize]
+%endif
+    jmp                tx2q
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+
+    ; input is in cqN*16, where N=0/4/8/12/1/5/9/13/2/6/10/14/3/7/11/15
+    ; some are still pre-loaded from the final loop iteration in pass=1
+
+    mova                 m1, m2
+    mova                 m2, [cq+ 1*16]
+    mova                 m3, [cq+ 9*16]
+    mova                 m4, [cq+ 2*16]
+    mova                 m5, [cq+10*16]
+    mova                 m6, [cq+ 3*16]
+    mova                 m7, [cq+11*16]
+    call m_suffix(idct_8x8_internal_8bpc, _ssse3).main
+    mova [rsp+gprsize+3*16], m0
+    mova [rsp+gprsize+4*16], m1
+    mova [rsp+gprsize+5*16], m2
+    mova [rsp+gprsize+6*16], m3
+    mova [rsp+gprsize+7*16], m4
+    mova [rsp+gprsize+8*16], m5
+    mova [rsp+gprsize+9*16], m6
+    ; m7 is already stored in [rsp+gprsize+0*16]
+    mova                 m0, [cq+ 4*16]
+    mova                 m1, [cq+12*16]
+    mova                 m2, [cq+ 5*16]
+    mova                 m3, [cq+13*16]
+    mova                 m4, [cq+ 6*16]
+    mova                 m5, [cq+14*16]
+    mova                 m6, [cq+ 7*16]
+    mova                 m7, [cq+15*16]
+    call m_suffix(idct_16x8_internal_8bpc, _ssse3).main
+
+    ; out0-7 is in rsp+gprsize+3-10*mmsize
+    ; out8-14 is in m0-6, and out15 is in m7 as well as rsp+gprsize+0*mmsize
+
+%if ARCH_X86_64
+    mova                 m8, [o(pw_2048)]
+    mova                m10, [o(pixel_10bpc_max)]
+    pxor                 m9, m9
+    mov                  r6, dstq
+%else
+    mov [rsp+16*16+gprsize*1], dstq
+%endif
+    lea                  r3, [strideq*3]
+    lea                dstq, [dstq+strideq*8]
+    call m(idct_8x8_internal_16bpc).round2_and_write_8x8
+%if ARCH_X86_64
+%define mzero m9
+%else
+%define mzero m7
+    pxor                 m7, m7
+%endif
+    REPX {mova [cq+x*16], mzero}, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \
+                     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+%undef mzero
+    mova                 m0, [rsp+gprsize+ 3*16]
+    mova                 m1, [rsp+gprsize+ 4*16]
+    mova                 m2, [rsp+gprsize+ 5*16]
+    mova                 m3, [rsp+gprsize+ 6*16]
+    mova                 m4, [rsp+gprsize+ 7*16]
+    mova                 m5, [rsp+gprsize+ 8*16]
+    mova                 m6, [rsp+gprsize+ 9*16]
+    mova                 m7, [rsp+gprsize+10*16]
+%if ARCH_X86_64
+    mov                dstq, r6
+%else
+    mov                dstq, [rsp+16*16+gprsize*1]
+%endif
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+    RET
+
+INV_TXFM_8X16_FN adst, dct
+INV_TXFM_8X16_FN adst, adst
+INV_TXFM_8X16_FN adst, flipadst
+INV_TXFM_8X16_FN adst, identity, v
+
+cglobal iadst_8x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if WIN64
+    PUSH                 r7
+%elif ARCH_X86_32
+    mov [rsp+16*16+gprsize*1], r1
+    mov [rsp+16*16+gprsize*2], r6
+%endif
+    lea                  t0, [o(m(iadst_8x8_internal_16bpc).pass1_main)]
+    jmp m(idct_8x16_internal_16bpc).pass1_full
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    mova                 m4, [cq+ 9*16]
+    mova                 m5, [cq+13*16]
+    mova [rsp+gprsize+7*16], m0
+    mova [rsp+gprsize+8*16], m1
+    mova [rsp+gprsize+5*16], m4
+    mova [rsp+gprsize+6*16], m5
+    mova                 m0, m2
+    mova                 m1, m3
+    mova                 m2, [cq+ 1*16]
+    mova                 m3, [cq+ 5*16]
+    mova                 m4, [cq+ 2*16]
+    mova                 m5, [cq+ 6*16]
+    mova                 m6, [cq+11*16]
+    mova                 m7, [cq+15*16]
+    mova [rsp+gprsize+ 3*16], m4
+    mova [rsp+gprsize+ 4*16], m5
+    mova [rsp+gprsize+ 9*16], m6
+    mova [rsp+gprsize+10*16], m7
+    mova                 m4, [cq+10*16]
+    mova                 m5, [cq+14*16]
+    mova                 m6, [cq+ 3*16]
+    mova                 m7, [cq+ 7*16]
+    call m_suffix(iadst_16x8_internal_8bpc, _ssse3).main
+    call m_suffix(iadst_16x8_internal_8bpc, _ssse3).main_pass2_end
+
+%if ARCH_X86_64
+    mova                m11, [o(pw_m2048)]
+    mova                 m8, [o(pw_2048)]
+    mova                m10, [o(pixel_10bpc_max)]
+    pxor                 m9, m9
+    mov                  r6, dstq
+%else
+    mov [rsp+16*16+gprsize*1], dstq
+%endif
+    lea                  r3, [strideq*3]
+    lea                dstq, [dstq+strideq*8]
+    call m(iadst_8x8_internal_16bpc).round2_and_write_8x8
+%if ARCH_X86_64
+%define mzero m9
+%else
+%define mzero m7
+    pxor                 m7, m7
+%endif
+    REPX {mova [cq+x*16], mzero}, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \
+                     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+%undef mzero
+    mova                 m0, [rsp+gprsize+ 3*16]
+    mova                 m1, [rsp+gprsize+ 4*16]
+    mova                 m2, [rsp+gprsize+ 5*16]
+    mova                 m3, [rsp+gprsize+ 6*16]
+    mova                 m4, [rsp+gprsize+ 7*16]
+    mova                 m5, [rsp+gprsize+ 8*16]
+    mova                 m6, [rsp+gprsize+ 9*16]
+    mova                 m7, [rsp+gprsize+10*16]
+%if ARCH_X86_64
+    mov                dstq, r6
+%else
+    mov                dstq, [rsp+16*16+gprsize*1]
+%endif
+    call m(iadst_8x8_internal_16bpc).round1_and_write_8x8
+    RET
+
+INV_TXFM_8X16_FN flipadst, dct
+INV_TXFM_8X16_FN flipadst, adst
+INV_TXFM_8X16_FN flipadst, flipadst
+INV_TXFM_8X16_FN flipadst, identity, v
+
+cglobal iflipadst_8x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if WIN64
+    PUSH                 r7
+%elif ARCH_X86_32
+    mov [rsp+16*16+gprsize*1], r1
+    mov [rsp+16*16+gprsize*2], r6
+%endif
+    lea                  t0, [o(m(iflipadst_8x8_internal_16bpc).pass1_main)]
+    jmp m(idct_8x16_internal_16bpc).pass1_full
+
+.pass2:
+    lea                  r3, [strideq*3]
+    lea                  r3, [r3*5]
+    add                dstq, r3
+    neg             strideq
+    jmp m(iadst_8x16_internal_16bpc).pass2
+
+INV_TXFM_8X16_FN identity, dct, h
+INV_TXFM_8X16_FN identity, adst, h
+INV_TXFM_8X16_FN identity, flipadst, h
+INV_TXFM_8X16_FN identity, identity
+
+cglobal iidentity_8x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if WIN64
+    PUSH                 r7
+%elif ARCH_X86_32
+    mov [rsp+16*16+gprsize*1], r1
+    mov [rsp+16*16+gprsize*2], r6
+%endif
+    lea                  t0, [o(m(idct_8x8_internal_16bpc).pack_and_transpose)]
+    jmp m(idct_8x16_internal_16bpc).pass1_full
+
+.pass2:
+%if ARCH_X86_64
+    mova                 m4, [o(pw_2048)]
+    mova                 m5, [o(pixel_10bpc_max)]
+    pxor                 m6, m6
+    mova                 m7, [o(pw_1697x16)]
+%endif
+    mov                 r5d, 4
+    lea                  r3, [strideq*3]
+.pass2_loop:
+    call .main
+%if ARCH_X86_64
+    call m(idct_8x4_internal_16bpc).round1_and_write_8x4
+%else
+    call m(idct_8x4_internal_16bpc).round2_and_write_8x4
+%endif
+    REPX {mova [cq+x*16], m6}, 0, 4, 8, 12, 16, 20, 24, 28
+    dec                 r5d
+    jle .end
+    add                  cq, 16
+    lea                dstq, [dstq+strideq*4]
+    mova                 m0, [cq+ 0*16]
+    mova                 m1, [cq+ 4*16]
+    mova                 m2, [cq+ 8*16]
+    mova                 m3, [cq+12*16]
+    jmp .pass2_loop
+.end:
+    RET
+.main:
+    ; y = pmulhrsw(x, pw_1697x16); x = paddsw(x, x); x = paddsw(x, y)
+%if ARCH_X86_32
+    mova                 m7, [o(pw_1697x16)]
+    pmulhrsw             m4, m7, m0
+    pmulhrsw             m5, m7, m1
+    pmulhrsw             m6, m7, m2
+    pmulhrsw             m7, m3
+%else
+    pmulhrsw             m8, m7, m0
+    pmulhrsw             m9, m7, m1
+    pmulhrsw            m10, m7, m2
+    pmulhrsw            m11, m7, m3
+%endif
+    REPX      {paddsw x, x}, m0, m1, m2, m3
+%if ARCH_X86_64
+    paddsw               m0, m8
+    paddsw               m1, m9
+    paddsw               m2, m10
+    paddsw               m3, m11
+%else
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+%endif
+    ret
+
+%macro INV_TXFM_16X4_FN 2 ; type1, type2
+%if ARCH_X86_64
+    INV_TXFM_FN          %1, %2, 0, 16x4, 16, 0-8*16
+%else
+    INV_TXFM_FN          %1, %2, 0, 16x4, 8, 0-12*16
+%endif
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 4
+.dconly:
+    add                 r5d, 384
+    sar                 r5d, 9
+.dconly2:
+    imul                r5d, 2896
+    add                 r5d, 34816
+    movd                 m0, r5d
+    pshuflw              m0, m0, q1111
+    punpcklqdq           m0, m0
+    mova                 m3, [o(pixel_10bpc_max)]
+    pxor                 m4, m4
+.loop:
+    mova                 m1, [dstq+ 0]
+    mova                 m2, [dstq+16]
+    REPX     {paddw  x, m0}, m1, m2
+    REPX     {pminsw x, m3}, m1, m2
+    REPX     {pmaxsw x, m4}, m1, m2
+    mova          [dstq+ 0], m1
+    mova          [dstq+16], m2
+    add                dstq, strideq
+    dec                 r3d
+    jg .loop
+    RET
+%endif
+%endmacro
+
+INV_TXFM_16X4_FN dct, dct
+INV_TXFM_16X4_FN dct, identity
+INV_TXFM_16X4_FN dct, adst
+INV_TXFM_16X4_FN dct, flipadst
+
+cglobal idct_16x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    ; setup stack pointer
+    lea                  r3, [rsp+gprsize]
+
+    mova                 m0, [cq+ 1*16]
+    mova                 m1, [cq+ 3*16]
+    mova                 m2, [cq+ 5*16]
+    mova                 m3, [cq+ 7*16]
+    mova                 m4, [cq+ 9*16]
+    mova                 m5, [cq+11*16]
+    mova                 m6, [cq+13*16]
+    mova                 m7, [cq+15*16]
+    call .main_oddhalf
+    mova                 m0, [cq+ 0*16]
+    mova                 m1, [cq+ 2*16]
+    mova                 m2, [cq+ 4*16]
+    mova                 m3, [cq+ 6*16]
+    mova                 m4, [cq+ 8*16]
+    mova                 m5, [cq+10*16]
+    mova                 m6, [cq+12*16]
+    mova                 m7, [cq+14*16]
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    ; t0-7 is in m0-7
+
+    call .round
+
+%if ARCH_X86_64
+.pack_transpose:
+    ; transpose in two parts
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+.transpose:
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    call .transpose4x8packed_hi
+%else
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m1
+    mova          [r3+2*16], m2
+    mova          [r3+3*16], m3
+    mova                 m0, [r3+ 8*16]
+    mova                 m2, [r3+ 9*16]
+    mova                 m4, [r3+10*16]
+    mova                 m6, [r3+11*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+%endif
+    jmp                tx2q
+%if ARCH_X86_64
+.transpose4x8packed_hi:
+    punpcklwd            m9, m10, m14
+    punpckhwd           m10, m14
+    punpckhwd           m14, m8, m12
+    punpcklwd            m8, m12
+
+    punpckhwd           m11, m8, m9
+    punpcklwd            m8, m9
+    punpckhwd           m12, m14, m10
+    punpcklwd           m14, m10
+
+    punpcklwd           m10, m11, m12
+    punpckhwd           m11, m12
+    punpckhwd            m9, m8, m14
+    punpcklwd            m8, m14
+    ret
+%endif
+.main_oddhalf_fast: ; lower half zero
+    pmulld               m7, m0, [o(pd_4076)]
+    pmulld               m0, [o(pd_401)]
+    pmulld               m6, m1, [o(pd_m1189)]
+    pmulld               m1, [o(pd_3920)]
+%if ARCH_X86_32
+    mova                 m4, [o(pd_2048)]
+    REPX      {paddd x, m4}, m1, m6
+    REPX      {psrad x, 12}, m1, m6
+    mova          [r3+1*16], m1
+%endif
+    pmulld               m5, m2, [o(pd_3612)]
+    pmulld               m2, [o(pd_1931)]
+%if ARCH_X86_32
+    pmulld               m1, m3, [o(pd_m2598)]
+%else
+    pmulld               m4, m3, [o(pd_m2598)]
+%endif
+    pmulld               m3, [o(pd_3166)]
+    jmp .main_oddhalf_fast2
+.main_oddhalf:
+%if ARCH_X86_64
+    ITX_MULSUB_2D         0, 7, 8, 9, 10, _,  401, 4076 ; t8a,  t15a
+    ITX_MULSUB_2D         6, 1, 8, 9, 10, _, 3920, 1189 ; t11a, t12a
+    ITX_MULSUB_2D         2, 5, 8, 9, 10, _, 1931, 3612 ; t10a, t13a
+    ITX_MULSUB_2D         4, 3, 8, 9, 10, _, 3166, 2598 ; t9a,  t14a
+.main_oddhalf_fast2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+    psubd                m8, m0, m4 ; t9
+    paddd                m0, m4     ; t8
+    psubd                m4, m6, m2 ; t10
+    paddd                m2, m6     ; t11
+    psubd                m6, m1, m5 ; t13
+    paddd                m5, m1     ; t12
+    psubd                m1, m7, m3 ; t14
+    paddd                m7, m3     ; t15
+    REPX    {pmaxsd x, m12}, m8, m1, m4, m6, m0, m2, m5, m7
+    REPX    {pminsd x, m13}, m8, m1, m4, m6, m0, m2, m5, m7
+    mova                m15, [o(pd_3784)]
+    mova                m10, [o(pd_1567)]
+    ITX_MULSUB_2D         1, 8, 3, 9, _, 11, 10, 15
+    ITX_MULSUB_2D         6, 4, 3, 9, _, 11, 10, 15, 4
+    psubd                m3, m1, m4 ; t10
+    paddd                m1, m4     ; t9
+    psubd                m4, m0, m2 ; t11a
+    paddd                m0, m2     ; t8a
+    psubd                m2, m8, m6 ; t13
+    paddd                m6, m8     ; t14
+    psubd                m8, m7, m5 ; t12a
+    paddd                m7, m5     ; t15a
+    REPX    {pmaxsd x, m12}, m2, m8, m3, m4, m0, m1, m6, m7
+    REPX    {pminsd x, m13}, m2, m8, m3, m4, m0, m1, m6, m7
+    REPX    {pmulld x, m14}, m2, m8, m3, m4
+    paddd                m2, m11
+    paddd                m8, m11
+    paddd                m5, m2, m3 ; t13a
+    psubd                m2, m3     ; t10a
+    psubd                m3, m8, m4 ; t11
+    paddd                m4, m8     ; t12
+    REPX      {psrad x, 12}, m5, m2, m3, m4
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m1
+    mova          [r3+2*16], m2
+    mova          [r3+3*16], m3
+    mova          [r3+4*16], m4
+    mova          [r3+5*16], m5
+    mova          [r3+6*16], m6
+    mova          [r3+7*16], m7
+%else
+    mova          [r3+0*16], m2
+    mova          [r3+1*16], m3
+    mova          [r3+2*16], m4
+    mova          [r3+3*16], m5
+    mova                 m4, [o(pd_2048)]
+
+    ITX_MULSUB_2D         0, 7, 2, 3, 5, _,  401, 4076 ; t8a,  t15a
+    ITX_MULSUB_2D         6, 1, 2, 3, 5, 4, 3920, 1189 ; t11a, t12a
+
+    mova                 m2, [r3+0*16]
+    mova                 m3, [r3+1*16]
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m1
+    mova                 m1, [r3+2*16]
+    mova                 m5, [r3+3*16]
+    mova          [r3+2*16], m6
+    mova          [r3+3*16], m7
+
+    ITX_MULSUB_2D         2, 5, 0, 6, 7, _, 1931, 3612 ; t10a, t13a
+    ITX_MULSUB_2D         1, 3, 0, 6, 7, _, 3166, 2598 ; t9a,  t14a
+
+    mova                 m0, [r3+0*16]
+    mova                 m6, [r3+2*16]
+    mova                 m7, [r3+3*16]
+.main_oddhalf_fast2:
+    REPX      {paddd x, m4}, m0, m7, m2, m5, m1, m3
+    REPX      {psrad x, 12}, m0, m7, m2, m5, m1, m3
+    psubd                m4, m0, m1 ; t9
+    paddd                m0, m1     ; t8
+    mova                 m1, [r3+1*16]
+    mova          [r3+0*16], m4
+    psubd                m4, m6, m2 ; t10
+    paddd                m2, m6     ; t11
+    psubd                m6, m1, m5 ; t13
+    paddd                m5, m1     ; t12
+    psubd                m1, m7, m3 ; t14
+    paddd                m7, m3     ; t15
+    mova                 m3, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m3}, m1, m4, m6, m0, m2, m5, m7
+    pmaxsd               m3, [r3+0*16]
+    mova          [r3+0*16], m3
+    mova                 m3, [o(clip_18b_max)]
+    REPX     {pminsd x, m3}, m1, m4, m6, m0, m2, m5, m7
+    pminsd               m3, [r3+0*16]
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m2
+    mova          [r3+2*16], m5
+    mova          [r3+3*16], m7
+    mova                m7, [o(pd_2048)]
+    ITX_MULSUB_2D         1, 3, 0, 2, 5, 7, 1567, 3784
+    ITX_MULSUB_2D         6, 4, 0, 2, _, 7,    5, 3784, 4
+    mova                 m0, [r3+0*16]
+    mova                 m2, [r3+1*16]
+    psubd                m5, m1, m4 ; t10
+    mova          [r3+1*16], m5
+    paddd                m1, m4     ; t9
+    psubd                m4, m0, m2 ; t11a
+    paddd                m0, m2     ; t8a
+    mova                 m5, [r3+2*16]
+    mova                 m7, [r3+3*16]
+    psubd                m2, m3, m6 ; t13
+    paddd                m6, m3     ; t14
+    paddd                m3, m7, m5 ; t15a
+    psubd                m7, m5     ; t12a
+    mova          [r3+0*16], m3
+    mova                 m3, [r3+1*16]
+    mova                 m5, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m5}, m2, m7, m3, m4, m0, m1, m6
+    pmaxsd               m5, [r3+0*16]
+    mova          [r3+0*16], m5
+    mova                 m5, [o(clip_18b_max)]
+    REPX     {pminsd x, m5}, m2, m7, m3, m4, m0, m1, m6
+    pminsd               m5, [r3+0*16]
+    mova          [r3+0*16], m5
+    mova                 m5, [o(pd_2896)]
+    REPX     {pmulld x, m5}, m2, m7, m3, m4
+    mova                 m5, [o(pd_2048)]
+    REPX     {paddd  x, m5}, m2, m7
+    paddd                m5, m2, m3 ; t13a
+    psubd                m2, m3     ; t10a
+    psubd                m3, m7, m4 ; t11
+    paddd                m4, m7     ; t12
+    REPX      {psrad x, 12}, m5, m2, m3, m4
+    mova                 m7, [r3+0*16]
+    mova         [r3+11*16], m0
+    mova         [r3+10*16], m1
+    mova          [r3+9*16], m2
+    mova          [r3+8*16], m3
+    mova          [r3+7*16], m4
+    mova          [r3+6*16], m5
+    mova          [r3+5*16], m6
+    mova          [r3+4*16], m7
+%endif
+    ret
+.round:
+%if ARCH_X86_64
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    pcmpeqd              m8, m8
+    REPX      {psubd x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    mova                 m8, [r3+1*16]
+    mova                 m9, [r3+2*16]
+    mova                m10, [r3+3*16]
+    mova                m11, [r3+4*16]
+    mova                m12, [r3+5*16]
+    mova                m13, [r3+6*16]
+    mova                m14, [r3+7*16]
+    psubd               m15, m0, m14       ; out15
+    paddd                m0, m14           ; out0
+    psubd               m14, m1, m13       ; out14
+    paddd                m1, m13           ; out1
+    psubd               m13, m2, m12       ; out13
+    paddd                m2, m12           ; out2
+    psubd               m12, m3, m11       ; out12
+    paddd                m3, m11           ; out3
+    psubd               m11, m4, m10       ; out11
+    paddd                m4, m10           ; out4
+    psubd               m10, m5, m9        ; out10
+    paddd                m5, m9            ; out5
+    psubd                m9, m6, m8        ; out9
+    paddd                m6, m8            ; out6
+    psubd                m8, m7, [r3+0*16] ; out8
+    paddd                m7, [r3+0*16]     ; out7
+    REPX       {psrad x, 1}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    ; and out0-15 is now in m0-15
+%else
+    mova         [r3+ 0*16], m0
+    mova                 m0, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m0}, m1, m2, m3, m4, m5, m6, m7
+    pmaxsd               m0, [r3+ 0*16]
+    mova         [r3+ 0*16], m7
+    mova                 m7, [o(clip_18b_max)]
+    REPX     {pminsd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pminsd               m7, [r3+ 0*16]
+    mova         [r3+ 0*16], m0
+    pcmpeqd              m0, m0
+    REPX      {psubd x, m0}, m1, m2, m3, m4, m5, m6, m7
+    mova         [r3+ 1*16], m1
+    mova         [r3+ 2*16], m2
+    mova                 m1, [r3+ 0*16]
+    psubd                m1, m0
+    mova         [r3+ 0*16], m1
+    mova                 m1, [r3+11*16]
+    mova                 m2, [r3+10*16]
+    psubd                m0, m7, m1
+    paddd                m7, m1
+    psubd                m1, m6, m2
+    paddd                m6, m2
+    REPX       {psrad x, 1}, m0, m1, m6, m7
+    packssdw             m0, m1     ; out8-9
+    packssdw             m6, m7     ; out6-7
+    mova         [r3+11*16], m6
+    mova                 m1, [r3+9*16]
+    mova                 m7, [r3+8*16]
+    psubd                m2, m5, m1
+    paddd                m5, m1
+    psubd                m1, m4, m7
+    paddd                m4, m7
+    REPX       {psrad x, 1}, m2, m1, m4, m5
+    packssdw             m2, m1     ; out10-11
+    packssdw             m4, m5     ; out4-5
+    mova                 m1, [r3+2*16]
+    mova         [r3+10*16], m4
+    mova                 m6, [r3+7*16]
+    mova                 m7, [r3+6*16]
+    psubd                m4, m3, m6
+    paddd                m3, m6
+    psubd                m6, m1, m7
+    paddd                m1, m7
+    REPX       {psrad x, 1}, m4, m6, m1, m3
+    packssdw             m4, m6     ; out12-13
+    packssdw             m1, m3     ; out2-3
+    mova                 m3, [r3+1*16]
+    mova          [r3+9*16], m1
+    mova                 m1, [r3+0*16]
+    mova                 m5, [r3+5*16]
+    mova                 m7, [r3+4*16]
+    psubd                m6, m3, m5
+    paddd                m3, m5
+    psubd                m5, m1, m7
+    paddd                m1, m7
+    REPX       {psrad x, 1}, m6, m5, m1, m3
+    packssdw             m6, m5     ; out14-15
+    packssdw             m1, m3     ; out0-1
+    mova          [r3+8*16], m1
+%endif
+    ret
+
+.pass2:
+    lea                  r4, [o(m_suffix(idct_8x4_internal_8bpc, _ssse3).main)]
+.pass2_loop:
+    lea                  r3, [strideq*3]
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call                 r4
+    call m(idct_8x4_internal_16bpc).round2_and_write_8x4
+    REPX {mova [cq+x*16], m6}, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+%if ARCH_X86_64
+    mova                 m0, m8
+    mova                 m1, m9
+    mova                 m2, m10
+    mova                 m3, m11
+%else
+    mova                 m0, [rsp+gprsize+0*16]
+    mova                 m1, [rsp+gprsize+1*16]
+    mova                 m2, [rsp+gprsize+2*16]
+    mova                 m3, [rsp+gprsize+3*16]
+%endif
+    add                dstq, 16
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call                 r4
+    call m(idct_8x4_internal_16bpc).round2_and_write_8x4
+    RET
+
+INV_TXFM_16X4_FN adst, dct
+INV_TXFM_16X4_FN adst, adst
+INV_TXFM_16X4_FN adst, flipadst
+INV_TXFM_16X4_FN adst, identity
+
+cglobal iadst_16x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    ; setup stack pointer
+    lea                  r3, [rsp+gprsize]
+    call .main
+%if ARCH_X86_64
+    jmp m(idct_16x4_internal_16bpc).pack_transpose
+%else
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova [rsp+gprsize+0*16], m0
+    mova [rsp+gprsize+1*16], m1
+    mova [rsp+gprsize+2*16], m2
+    mova [rsp+gprsize+3*16], m3
+    mova                 m0, [rsp+gprsize+ 8*16]
+    mova                 m2, [rsp+gprsize+ 9*16]
+    mova                 m4, [rsp+gprsize+10*16]
+    mova                 m6, [rsp+gprsize+11*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    jmp                tx2q
+%endif
+
+.main:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+ 2*16]
+    mova                 m1, [cq+13*16]
+    mova                 m2, [cq+ 6*16]
+    mova                 m3, [cq+ 9*16]
+    mova                 m4, [cq+10*16]
+    mova                 m5, [cq+ 5*16]
+    mova                 m6, [cq+14*16]
+    mova                 m7, [cq+ 1*16]
+    call .main_part1
+    mova                 m0, [cq+ 0*16]
+    mova                 m1, [cq+15*16]
+    mova                 m2, [cq+ 4*16]
+    mova                 m3, [cq+11*16]
+    mova                 m4, [cq+ 8*16]
+    mova                 m5, [cq+ 7*16]
+    mova                 m6, [cq+12*16]
+    mova                 m7, [cq+ 3*16]
+    call .main_part2
+.round:
+%if ARCH_X86_64
+    mova                m15, [o(pd_6144)]
+    psrld               m14, 11       ; pd_1
+    pcmpeqd              m8, m8       ; -1
+    psubd               m13, m15, m14 ; pd_6143
+    REPX     {paddd x, m14}, m0, m2
+    REPX     {paddd x, m15}, m4, m6
+    REPX     {pxor  x, m8 }, m1, m3, m5, m7
+    REPX     {psrad x, 1  }, m1, m3
+    REPX     {paddd x, m15}, m5, m7
+    REPX     {psubd x, m8 }, m1, m3
+    paddd                m8, m15, m9
+    psubd                m9, m13, m10
+    paddd               m10, m15, m11
+    psubd               m11, m13, m12
+    paddd               m12, m14, [r3+3*16]
+    psubd               m13, m14, [r3+2*16]
+    psubd               m15, m14, [r3+0*16]
+    paddd               m14, [r3+1*16]
+    REPX      {psrad x, 1 }, m0,  m2,  m12, m13, m14, m15
+    REPX      {psrad x, 13}, m4,  m5,  m6,  m7,  m8,  m9,  m10, m11
+%else
+    mova          [r3+8*16], m1
+    mova          [r3+9*16], m3
+    mova                 m3, [o(pd_6144)]
+    pcmpeqd              m1, m1
+    REPX      {pxor  x, m1}, m5, m7
+    REPX      {paddd x, m3}, m4, m5, m6, m7
+    REPX      {psrad x, 13}, m4, m5, m6, m7
+    packssdw             m4, m5
+    packssdw             m6, m7
+    mova         [r3+10*16], m4
+    mova         [r3+11*16], m6
+    mova                 m4, [r3+4*16]
+    mova                 m5, [r3+5*16]
+    mova                 m6, [r3+6*16]
+    mova                 m7, [r3+7*16]
+    REPX      {pxor  x, m1}, m5, m7
+    REPX      {psubd x, m1}, m4, m6
+    REPX      {psrad x, 1 }, m4, m5, m6, m7
+    REPX      {psubd x, m1}, m5, m7
+    packssdw             m4, m5
+    packssdw             m6, m7
+    mova                 m5, [r3+8*16]
+    mova                 m7, [r3+9*16]
+    mova          [r3+8*16], m4
+    mova          [r3+9*16], m6
+    REPX      {pxor  x, m1}, m5, m7
+    REPX      {paddd x, m3}, m0, m5, m2, m7
+    REPX      {psrad x, 13}, m0, m5, m2, m7
+    packssdw             m0, m5
+    packssdw             m2, m7
+    mova                 m4, [r3+0*16]
+    mova                 m5, [r3+1*16]
+    mova                 m6, [r3+2*16]
+    mova                 m7, [r3+3*16]
+    REPX      {psubd x, m1}, m4, m6
+    REPX      {pxor  x, m1}, m5, m7
+    REPX      {psrad x, 1 }, m4, m5, m6, m7
+    REPX      {psubd x, m1}, m5, m7
+    packssdw             m4, m5
+    packssdw             m6, m7
+%endif
+    ret
+
+.main_part2:
+%if ARCH_X86_64
+    ITX_MULSUB_2D         1, 0, 8, 9, 10, 11,  201, 4091
+    ITX_MULSUB_2D         3, 2, 8, 9, 10, 11, 1751, 3703
+    ITX_MULSUB_2D         5, 4, 8, 9, 10, 11, 3035, 2751
+    ITX_MULSUB_2D         7, 6, 8, 9, 10, 11, 3857, 1380
+    psubd                m8, m0, m4 ; t8a
+    paddd                m0, m4     ; t0a
+    psubd                m4, m1, m5 ; t9a
+    paddd                m1, m5     ; t1a
+    psubd                m5, m2, m6 ; t12a
+    paddd                m2, m6     ; t4a
+    psubd                m6, m3, m7 ; t13a
+    paddd                m7, m3     ; t5a
+    REPX    {pmaxsd x, m12}, m8, m4, m5, m6, m0, m1, m2, m7
+    REPX    {pminsd x, m13}, m8, m4, m5, m6, m0, m1, m2, m7
+    mova                m15, [o(pd_4017)]
+    mova                m10, [o(pd_799)]
+    ITX_MULSUB_2D         8, 4, 3, 9, _, 11, 10, 15
+    ITX_MULSUB_2D         6, 5, 3, 9, _, 11, 15, 10
+    psubd                m3, m0, m2 ; t4
+    paddd                m0, m2     ; t0
+    psubd                m2, m1, m7 ; t5
+    paddd                m1, m7     ; t1
+    psubd                m7, m4, m6 ; t12a
+    paddd                m4, m6     ; t8a
+    psubd                m6, m8, m5 ; t13a
+    paddd                m5, m8     ; t9a
+    REPX    {pmaxsd x, m12}, m3, m2, m7, m6, m0, m1, m4, m5
+    REPX    {pminsd x, m13}, m3, m2, m7, m6, m0, m1, m4, m5
+    mova                m15, [o(pd_3784)]
+    mova                m10, [o(pd_1567)]
+    ITX_MULSUB_2D         3, 2, 8, 9, _, 11, 10, 15
+    ITX_MULSUB_2D         7, 6, 8, 9, _, 11, 10, 15
+    mova                m10, [r3+0*16]      ;  t2
+    mova                 m8, [r3+1*16]      ;  t3
+    psubd                m9, m0, m10        ;  t2a
+    paddd                m0, m10            ;  out0
+    psubd               m10, m1, m8         ;  t3a
+    paddd                m1, m8             ; -out15
+    mova          [r3+0*16], m1
+    mova                m15, [r3+3*16]      ;  t7a
+    mova                 m1, [r3+2*16]      ;  t6a
+    psubd                m8, m3, m15        ;  t7
+    paddd               m15, m3             ;  out12
+    paddd                m3, m2, m1         ; -out3
+    psubd                m2, m1             ;  t6
+    mova          [r3+3*16], m15
+    mova          [r3+1*16], m2
+    mova                 m1, [r3+7*16]      ;  t15
+    mova                 m2, [r3+6*16]      ;  t14
+    paddd               m15, m7, m1         ; -out13
+    psubd                m7, m1             ;  t15a
+    psubd               m11, m6, m2         ;  t14a
+    paddd                m2, m6             ;  out2
+    mova          [r3+2*16], m15
+    mova                 m1, [r3+4*16]      ;  t10a
+    mova                m15, [r3+5*16]      ;  t11a
+    psubd                m6, m4, m1         ;  t10
+    paddd                m1, m4             ; -out1
+    psubd                m4, m5, m15        ;  t11
+    paddd                m5, m15            ;  out14
+    REPX    {pmaxsd x, m12}, m11, m7, m9, m10, m6, m4, m8
+    pmaxsd              m12, [r3+1*16]      ;  t6
+    mova          [r3+1*16], m5
+    REPX    {pminsd x, m13}, m11, m7, m9, m10, m6, m4, m12, m8
+    REPX    {pmulld x, m14}, m11, m7, m9, m10, m6, m4, m12, m8
+    paddd                m5, m11, m7        ; -out5  (unshifted)
+    psubd               m11, m7             ;  out10 (unshifted)
+    paddd                m7, m9, m10        ; -out7  (unshifted)
+    psubd                m9, m10            ;  out8  (unshifted)
+    psubd               m10, m6, m4         ; -out9  (unshifted)
+    paddd                m6, m4             ;  out6  (unshifted)
+    paddd                m4, m12, m8        ;  out4  (unshifted)
+    psubd               m12, m8             ; -out11 (unshifted)
+%else
+    mova          [r3+8*16], m0
+    mova          [r3+9*16], m1
+    mova         [r3+10*16], m2
+    mova         [r3+11*16], m3
+    mova                 m3, [o(pd_2048)]
+    ITX_MULSUB_2D         5, 4, 0, 1, 2, 3, 3035, 2751
+    ITX_MULSUB_2D         7, 6, 0, 1, 2, 3, 3857, 1380
+    mova                 m0, [r3+8*16]
+    mova                 m1, [r3+9*16]
+    mova          [r3+8*16], m4
+    mova                 m4, [r3+10*16]
+    mova          [r3+9*16], m5
+    mova         [r3+10*16], m6
+    mova                 m5, [r3+11*16]
+    mova         [r3+11*16], m7
+    ITX_MULSUB_2D         1, 0, 2, 6, 7, 3,  201, 4091
+    ITX_MULSUB_2D         5, 4, 2, 6, 7, 3, 1751, 3703
+    mova                 m2, [r3+8*16]
+    mova                 m6, [r3+9*16]
+    psubd                m3, m0, m2 ; t8a
+    paddd                m0, m2     ; t0a
+    mova          [r3+8*16], m3
+    psubd                m2, m1, m6 ; t9a
+    paddd                m1, m6     ; t1a
+    mova                 m3, [r3+10*16]
+    psubd                m6, m4, m3 ; t12a
+    paddd                m4, m3     ; t4a
+    mova                 m3, [r3+11*16]
+    psubd                m7, m5, m3 ; t13a
+    paddd                m5, m3     ; t5a
+    mova                 m3, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m3}, m2, m6, m7, m0, m1, m4, m5
+    pmaxsd               m3, [r3+8*16]
+    mova          [r3+8*16], m3
+    mova                 m3, [o(clip_18b_max)]
+    REPX     {pminsd x, m3}, m2, m6, m7, m0, m1, m4, m5
+    pminsd               m3, [r3+8*16]
+    mova          [r3+8*16], m3
+    psubd                m3, m0, m4 ; t4
+    paddd                m0, m4     ; t0
+    psubd                m4, m1, m5 ; t5
+    paddd                m1, m5     ; t1
+    mova                 m5, [o(pd_2048)]
+    mova          [r3+9*16], m1
+    mova         [r3+10*16], m4
+    mova         [r3+11*16], m3
+    mova                 m3, [r3+8*16]
+    mova          [r3+8*16], m0
+    ITX_MULSUB_2D         3, 2, 0, 1, 4, 5,  799, 4017
+    ITX_MULSUB_2D         7, 6, 0, 1, 4, 5, 4017,    4
+    psubd                m5, m2, m7 ; t12a
+    paddd                m2, m7     ; t8a
+    psubd                m7, m3, m6 ; t13a
+    paddd                m6, m3     ; t9a
+    mova                 m0, [r3+8*16]
+    mova                 m1, [r3+9*16]
+    mova                 m4, [r3+10*16]
+    mova                 m3, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m3}, m4, m5, m7, m0, m1, m2, m6
+    pmaxsd               m3, [r3+11*16]
+    mova          [r3+8*16], m3
+    mova                 m3, [o(clip_18b_max)]
+    REPX     {pminsd x, m3}, m4, m5, m7, m0, m1, m2, m6
+    pminsd               m3, [r3+8*16]
+    mova          [r3+8*16], m0
+    mova          [r3+9*16], m1
+    mova         [r3+10*16], m2
+    mova         [r3+11*16], m6
+    mova                 m0, [o(pd_2048)]
+    ITX_MULSUB_2D         3, 4, 1, 2, 6, 0, 1567, 3784
+    ITX_MULSUB_2D         5, 7, 1, 2, 6, 0,    6, 3784
+    mova                 m0, [r3+7*16]      ;  t7a
+    mova                 m2, [r3+6*16]      ;  t6a
+    psubd                m1, m3, m0         ;  t7
+    paddd                m0, m3             ;  out12
+    paddd                m3, m4, m2         ; -out3
+    psubd                m4, m2             ;  t6
+    mova          [r3+7*16], m3
+    mova                 m3, [r3+3*16]      ;  t15
+    mova                 m2, [r3+2*16]      ;  t14
+    paddd                m6, m5, m3         ; -out13
+    psubd                m5, m3             ;  t15a
+    psubd                m3, m7, m2         ;  t14a
+    paddd                m2, m7             ;  out2
+    mova          [r3+6*16], m2
+    mova                 m7, [r3+0*16]      ;  t10a
+    mova                 m2, [r3+1*16]      ;  t11a
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m6
+    mova                 m6, [r3+11*16]
+    psubd                m0, m6, m2         ;  t11
+    paddd                m6, m2             ;  out14
+    mova          [r3+2*16], m6
+    mova                 m2, [r3+10*16]
+    psubd                m6, m2, m7         ;  t10
+    paddd                m2, m7             ; -out1
+    mova                 m7, [r3+5*16]      ;  t3
+    mova          [r3+5*16], m2
+    mova         [r3+10*16], m1
+    mova                 m1, [r3+9*16]
+    psubd                m2, m1, m7         ;  t3a
+    paddd                m1, m7             ; -out15
+    mova          [r3+3*16], m1
+    mova                 m1, [r3+4*16]      ;  t2
+    mova                 m7, [r3+8*16]
+    psubd                m7, m1             ;  t2a
+    paddd                m1, [r3+8*16]      ;  out0
+    mova          [r3+4*16], m1
+    mova                 m1, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m1}, m0, m2, m3, m4, m5, m6, m7
+    pmaxsd               m1, [r3+10*16]
+    mova         [r3+10*16], m1
+    mova                 m1, [o(clip_18b_max)]
+    REPX     {pminsd x, m1}, m0, m2, m3, m4, m5, m6, m7
+    pminsd               m1, [r3+10*16]
+    mova         [r3+10*16], m1
+    mova                 m1, [o(pd_2896)]
+    REPX     {pmulld x, m1}, m0, m2, m3, m4, m5, m6, m7
+    pmulld               m1, [r3+10*16]
+    mova         [r3+11*16], m3
+    psubd                m3, m4, m1         ; -out11 (unshifted)
+    paddd                m4, m1             ;  out4  (unshifted)
+    psubd                m1, m6, m0         ; -out9  (unshifted)
+    paddd                m6, m0             ;  out6  (unshifted)
+    psubd                m0, m7, m2         ;  out8  (unshifted)
+    paddd                m7, m2             ; -out7  (unshifted)
+    mova                 m2, [r3+11*16]
+    mova         [r3+11*16], m5
+    paddd                m5, m2             ; -out5  (unshifted)
+    psubd                m2, [r3+11*16]     ;  out10 (unshifted)
+    ; m0-3 contain out8-11 (unshifted), m4-7 contain out4-7 (unshifted)
+    ; r[-4,3] contain out0-3 and out12-15
+%endif
+    ret
+.main_part1:
+%if ARCH_X86_64
+    ITX_MULSUB_2D         1, 0, 8, 9, 10, 11,  995, 3973
+    ITX_MULSUB_2D         3, 2, 8, 9, 10, 11, 2440, 3290
+    ITX_MULSUB_2D         5, 4, 8, 9, 10, 11, 3513, 2106
+    ITX_MULSUB_2D         7, 6, 8, 9, 10, 11, 4052,  601
+    psubd                m8, m0, m4 ; t10a
+    paddd                m0, m4     ; t2a
+    psubd                m4, m1, m5 ; t11a
+    paddd                m1, m5     ; t3a
+    psubd                m5, m2, m6 ; t14a
+    paddd                m2, m6     ; t6a
+    psubd                m6, m3, m7 ; t15a
+    paddd                m7, m3     ; t7a
+    REPX    {pmaxsd x, m12}, m8, m4, m5, m6, m0, m1, m2, m7
+    REPX    {pminsd x, m13}, m8, m4, m5, m6, m0, m1, m2, m7
+    mova                m15, [o(pd_2276)]
+    mova                m10, [o(pd_3406)]
+    ITX_MULSUB_2D         8, 4, 3, 9, _, 11, 10, 15
+    ITX_MULSUB_2D         6, 5, 3, 9, _, 11, 15, 10
+    psubd                m3, m0, m2 ; t6
+    paddd                m0, m2     ; t2
+    psubd                m2, m1, m7 ; t7
+    paddd                m1, m7     ; t3
+    psubd                m7, m4, m6 ; t14a
+    paddd                m4, m6     ; t10a
+    psubd                m6, m8, m5 ; t15a
+    paddd                m5, m8     ; t11a
+    REPX    {pmaxsd x, m12}, m3, m2, m7, m6, m0, m1, m4, m5
+    REPX    {pminsd x, m13}, m3, m2, m7, m6, m0, m1, m4, m5
+    mova                m15, [o(pd_1567)]
+    mova                m10, [o(pd_3784)]
+    ITX_MULSUB_2D         2, 3, 8, 9, _, 11, 10, 15
+    ITX_MULSUB_2D         6, 7, 8, 9, _, 11, 10, 15
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m1
+    mova          [r3+4*16], m4
+    mova          [r3+5*16], m5
+    mova          [r3+2*16], m2
+    mova          [r3+3*16], m3
+    mova          [r3+6*16], m6
+    mova          [r3+7*16], m7
+%else
+    mova          [r3+4*16], m0
+    mova          [r3+5*16], m1
+    mova          [r3+6*16], m2
+    mova          [r3+7*16], m3
+    mova                 m3, [o(pd_2048)]
+    ITX_MULSUB_2D         5, 4, 0, 1, 2, 3, 3513, 2106
+    ITX_MULSUB_2D         7, 6, 0, 1, 2, 3, 4052,  601
+    mova          [r3+0*16], m4
+    mova          [r3+1*16], m5
+    mova          [r3+2*16], m6
+    mova          [r3+3*16], m7
+    mova                 m0, [r3+4*16]
+    mova                 m1, [r3+5*16]
+    mova                 m2, [r3+6*16]
+    mova                 m7, [r3+7*16]
+    ITX_MULSUB_2D         1, 0, 4, 5, 6, 3,  995, 3973
+    ITX_MULSUB_2D         7, 2, 4, 5, 6, 3, 2440, 3290
+    mova                 m4, [r3+0*16]
+    mova                 m5, [r3+1*16]
+    psubd                m6, m0, m4 ; t10a
+    paddd                m0, m4     ; t2a
+    mova          [r3+4*16], m6
+    mova                 m6, [r3+2*16]
+    mova                 m3, [r3+3*16]
+    psubd                m4, m1, m5 ; t11a
+    paddd                m1, m5     ; t3a
+    psubd                m5, m2, m6 ; t14a
+    paddd                m2, m6     ; t6a
+    psubd                m6, m7, m3 ; t15a
+    paddd                m7, m3     ; t7a
+    mova                 m3, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m3}, m4, m5, m6, m0, m1, m2, m7
+    pmaxsd               m3, [r3+4*16]
+    mova          [r3+4*16], m3
+    mova                 m3, [o(clip_18b_max)]
+    REPX     {pminsd x, m3}, m4, m5, m6, m0, m1, m2, m7
+    pminsd               m3, [r3+4*16]
+    mova          [r3+4*16], m3
+    psubd                m3, m0, m2 ; t6
+    paddd                m0, m2     ; t2
+    psubd                m2, m1, m7 ; t7
+    paddd                m1, m7     ; t3
+    mova          [r3+5*16], m1
+    mova          [r3+6*16], m3
+    mova          [r3+7*16], m2
+    mova                 m1, [r3+4*16]
+    mova          [r3+4*16], m0
+    mova                 m3, [o(pd_2048)]
+    ITX_MULSUB_2D         1, 4, 0, 7, 2, 3, 3406, 2276
+    ITX_MULSUB_2D         6, 5, 0, 7, 2, 3, 2276,    2
+    psubd                m7, m4, m6 ; t14a
+    paddd                m4, m6     ; t10a
+    psubd                m6, m1, m5 ; t15a
+    paddd                m5, m1     ; t11a
+    mova                 m1, [r3+5*16]
+    mova                 m3, [r3+6*16]
+    mova                 m2, [r3+7*16]
+    mova                 m0, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m0}, m3, m2, m7, m6, m1, m4, m5
+    pmaxsd               m0, [r3+4*16]
+    mova          [r3+4*16], m0
+    mova                 m0, [o(clip_18b_max)]
+    REPX     {pminsd x, m0}, m3, m2, m7, m6, m1, m4, m5
+    pminsd               m0, [r3+4*16]
+    mova          [r3+4*16], m0
+    mova          [r3+5*16], m1
+    mova          [r3+0*16], m4
+    mova          [r3+1*16], m5
+    mova                 m0, [o(pd_2048)]
+    ITX_MULSUB_2D         2, 3, 1, 4, 5, 0, 3784, 1567
+    ITX_MULSUB_2D         6, 7, 1, 4, 5, 0,    5, 1567
+    mova          [r3+6*16], m2
+    mova          [r3+7*16], m3
+    mova          [r3+2*16], m6
+    mova          [r3+3*16], m7
+%endif
+    ret
+
+.pass2:
+    lea                  r4, [o(m_suffix(iadst_8x4_internal_8bpc, _ssse3).main)]
+    jmp m(idct_16x4_internal_16bpc).pass2_loop
+
+INV_TXFM_16X4_FN flipadst, dct
+INV_TXFM_16X4_FN flipadst, adst
+INV_TXFM_16X4_FN flipadst, flipadst
+INV_TXFM_16X4_FN flipadst, identity
+
+cglobal iflipadst_16x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+    lea                  r3, [rsp+gprsize]
+    call m(iadst_16x4_internal_16bpc).main
+%if ARCH_X86_64
+    packssdw             m1, m0
+    packssdw             m3, m2
+    packssdw             m5, m4
+    packssdw             m7, m6
+    packssdw             m9, m8
+    packssdw            m11, m10
+    packssdw            m13, m12
+    packssdw            m15, m14
+    mova                 m0, m15
+    mova                 m2, m13
+    mova                 m4, m11
+    mova                 m6, m9
+    mova                 m8, m7
+    mova                m10, m5
+    mova                m12, m3
+    mova                m14, m1
+    jmp m(idct_16x4_internal_16bpc).transpose
+%else
+    mova [rsp+gprsize+4*16], m0
+    mova [rsp+gprsize+5*16], m2
+    mova [rsp+gprsize+6*16], m4
+    mova [rsp+gprsize+7*16], m6
+    pshufd               m6, [rsp+gprsize+ 8*16], q1032
+    pshufd               m4, [rsp+gprsize+ 9*16], q1032
+    pshufd               m2, [rsp+gprsize+10*16], q1032
+    pshufd               m0, [rsp+gprsize+11*16], q1032
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova [rsp+gprsize+0*16], m0
+    mova [rsp+gprsize+1*16], m1
+    mova [rsp+gprsize+2*16], m2
+    mova [rsp+gprsize+3*16], m3
+    pshufd               m6, [rsp+gprsize+ 4*16], q1032
+    pshufd               m4, [rsp+gprsize+ 5*16], q1032
+    pshufd               m2, [rsp+gprsize+ 6*16], q1032
+    pshufd               m0, [rsp+gprsize+ 7*16], q1032
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    jmp                tx2q
+%endif
+
+.pass2:
+    lea                  r3, [strideq*3]
+    lea                dstq, [dstq+r3]
+    neg             strideq
+    lea                  r4, [o(m_suffix(iadst_8x4_internal_8bpc, _ssse3).main)]
+    jmp m(idct_16x4_internal_16bpc).pass2_loop
+
+INV_TXFM_16X4_FN identity, dct
+INV_TXFM_16X4_FN identity, adst
+INV_TXFM_16X4_FN identity, flipadst
+INV_TXFM_16X4_FN identity, identity
+
+cglobal iidentity_16x4_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_64
+    mova                m15, [o(pd_11586)]
+    pmulld               m0, m15, [cq+ 0*16]
+    pmulld               m1, m15, [cq+ 1*16]
+    pmulld               m2, m15, [cq+ 2*16]
+    pmulld               m3, m15, [cq+ 3*16]
+    pmulld               m4, m15, [cq+ 4*16]
+    pmulld               m5, m15, [cq+ 5*16]
+    pmulld               m6, m15, [cq+ 6*16]
+    pmulld               m7, m15, [cq+ 7*16]
+    pmulld               m8, m15, [cq+ 8*16]
+    pmulld               m9, m15, [cq+ 9*16]
+    pmulld              m10, m15, [cq+10*16]
+    pmulld              m11, m15, [cq+11*16]
+    pmulld              m12, m15, [cq+12*16]
+    pmulld              m13, m15, [cq+13*16]
+    pmulld              m14, m15, [cq+14*16]
+    pmulld              m15, [cq+15*16]
+    mova         [cq+ 0*16], m15
+    mova                m15, [o(pd_6144)]
+    REPX     {paddd x, m15}, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14
+    paddd               m15, [cq+ 0*16]
+    REPX     {psrad x, 13 }, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14, m15
+    jmp m(idct_16x4_internal_16bpc).pack_transpose
+%else
+    add                  cq, 8*16
+    mov                 r5d, 2
+.loop_pass1:
+    mova                 m7, [o(pd_11586)]
+    pmulld               m0, m7, [cq+0*16]
+    pmulld               m1, m7, [cq+1*16]
+    pmulld               m2, m7, [cq+2*16]
+    pmulld               m3, m7, [cq+3*16]
+    pmulld               m4, m7, [cq+4*16]
+    pmulld               m5, m7, [cq+5*16]
+    pmulld               m6, m7, [cq+6*16]
+    pmulld               m7, [cq+7*16]
+    mova          [cq+7*16], m7
+    mova                 m7, [o(pd_6144)]
+    REPX      {paddd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    paddd                m7, [cq+7*16]
+    REPX      {psrad x, 13}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    dec                 r5d
+    jz .end_pass1
+    mova [rsp+gprsize+0*16], m0
+    mova [rsp+gprsize+1*16], m1
+    mova [rsp+gprsize+2*16], m2
+    mova [rsp+gprsize+3*16], m3
+    sub                  cq, 8*16
+    jmp .loop_pass1
+.end_pass1:
+    jmp                tx2q
+%endif
+
+.pass2:
+%if ARCH_X86_64
+    mova                m12, [o(pw_1697x8)]
+%endif
+    lea                  r4, [o(.main)]
+    jmp m(idct_16x4_internal_16bpc).pass2_loop
+.main:
+%if ARCH_X86_64
+    pmulhrsw             m4, m0, m12
+    pmulhrsw             m5, m1, m12
+    pmulhrsw             m6, m2, m12
+    pmulhrsw             m7, m3, m12
+%else
+    mova                 m7, [o(pw_1697x8)]
+    pmulhrsw             m4, m0, m7
+    pmulhrsw             m5, m1, m7
+    pmulhrsw             m6, m2, m7
+    pmulhrsw             m7, m3
+%endif
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    ret
+
+%macro INV_TXFM_16X8_FN 2-3 0 ; type1, type2, eob_offset
+%if ARCH_X86_64
+    INV_TXFM_FN          %1, %2, %3, 16x8, 16, 0-8*16
+%else
+    INV_TXFM_FN          %1, %2, %3, 16x8, 8, 0-13*16
+%endif
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 8
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 181
+%if ARCH_X86_32
+    add                 rsp, 1*16
+%endif
+    jmp m(inv_txfm_add_dct_dct_16x4_16bpc).dconly
+%endif
+%endmacro
+
+INV_TXFM_16X8_FN dct, dct
+INV_TXFM_16X8_FN dct, identity, 6
+INV_TXFM_16X8_FN dct, adst
+INV_TXFM_16X8_FN dct, flipadst
+
+cglobal idct_16x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_64
+    DECLARE_REG_TMP 6, 4, 6
+%else
+    mov [rsp+gprsize+12*16], r1
+    DECLARE_REG_TMP 1, 4, 3
+%endif
+    lea                  t0, [o(.main)]
+.loop_main:
+%undef cmp
+%if ARCH_X86_64
+    xor                 r5d, r5d
+    cmp                eobd, 10
+    setge               r5b
+%else
+    mov                 r5d, 1
+    cmp                eobd, 10
+    sbb                 r5d, 0
+%endif
+    shl                 r5d, 4
+
+    lea                  r3, [rsp+gprsize]
+.loop_pass1:
+    call                 t0
+%if ARCH_X86_64
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova       [cq+4*32+r5], m8
+    mova       [cq+5*32+r5], m9
+    mova       [cq+6*32+r5], m10
+    mova       [cq+7*32+r5], m11
+%else
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova       [cq+4*32+r5], m0
+    mova       [cq+5*32+r5], m1
+    mova       [cq+6*32+r5], m2
+    mova       [cq+7*32+r5], m3
+    mova                 m0, [rsp+gprsize+ 8*16]
+    mova                 m2, [rsp+gprsize+ 9*16]
+    mova                 m4, [rsp+gprsize+10*16]
+    mova                 m6, [rsp+gprsize+11*16]
+%endif
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    pxor                 m7, m7
+    REPX {mova [cq+x*32+r5], m7}, 8, 9, 10, 11, 12, 13, 14, 15
+    test                r5d, r5d
+    jz .end
+    mova       [cq+0*32+r5], m0
+    mova       [cq+1*32+r5], m1
+    mova       [cq+2*32+r5], m2
+    mova       [cq+3*32+r5], m3
+    xor                 r5d, r5d
+    jmp .loop_pass1
+.end:
+
+    jmp                tx2q
+.main:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+ 1*32+r5]
+    mova                 m1, [cq+ 3*32+r5]
+    mova                 m2, [cq+ 5*32+r5]
+    mova                 m3, [cq+ 7*32+r5]
+    mova                 m4, [cq+ 9*32+r5]
+    mova                 m5, [cq+11*32+r5]
+    mova                 m6, [cq+13*32+r5]
+    mova                 m7, [cq+15*32+r5]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(idct_16x4_internal_16bpc).main_oddhalf
+
+    mova                 m0, [cq+ 0*32+r5]
+    mova                 m1, [cq+ 2*32+r5]
+    mova                 m2, [cq+ 4*32+r5]
+    mova                 m3, [cq+ 6*32+r5]
+    mova                 m4, [cq+ 8*32+r5]
+    mova                 m5, [cq+10*32+r5]
+    mova                 m6, [cq+12*32+r5]
+    mova                 m7, [cq+14*32+r5]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    call m(idct_16x4_internal_16bpc).round
+%if ARCH_X86_64
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+%endif
+    ret
+
+.pass2:
+%if ARCH_X86_32
+    mov             strideq, [rsp+gprsize+12*16]
+%endif
+    mov                 r4d, 2
+.pass2_main:
+%if ARCH_X86_64
+    mova                 m8, [o(pw_2048)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+%endif
+    lea                  r3, [strideq*3]
+    jmp .loop_pass2_entry
+.loop_pass2:
+    mova                 m0, [cq+0*32+ 0]
+    mova                 m1, [cq+1*32+ 0]
+    mova                 m2, [cq+2*32+ 0]
+    mova                 m3, [cq+3*32+ 0]
+.loop_pass2_entry:
+    mova                 m4, [cq+0*32+16]
+    mova                 m5, [cq+1*32+16]
+    mova                 m6, [cq+2*32+16]
+    mova                 m7, [cq+3*32+16]
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(idct_8x8_internal_8bpc, _ssse3).main
+    call m(idct_8x8_internal_16bpc).round2_and_write_8x8
+%if ARCH_X86_64
+%define mzero m9
+%else
+%define mzero m7
+    pxor                 m7, m7
+%endif
+    REPX {mova [cq+x*16], mzero}, 0, 1, 2, 3, 4, 5, 6, 7
+    add                dstq, 16
+    add                  cq, 4*32
+    dec                 r4d
+    jg .loop_pass2
+    RET
+
+INV_TXFM_16X8_FN adst, dct
+INV_TXFM_16X8_FN adst, adst
+INV_TXFM_16X8_FN adst, flipadst
+INV_TXFM_16X8_FN adst, identity, 6
+
+cglobal iadst_16x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_32
+    mov [rsp+gprsize+12*16], r1
+%endif
+    lea                  t0, [o(.main)]
+    jmp m(idct_16x8_internal_16bpc).loop_main
+
+.main:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+ 2*32+r5]
+    mova                 m1, [cq+13*32+r5]
+    mova                 m2, [cq+ 6*32+r5]
+    mova                 m3, [cq+ 9*32+r5]
+    mova                 m4, [cq+10*32+r5]
+    mova                 m5, [cq+ 5*32+r5]
+    mova                 m6, [cq+14*32+r5]
+    mova                 m7, [cq+ 1*32+r5]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(iadst_16x4_internal_16bpc).main_part1
+    mova                 m0, [cq+ 0*32+r5]
+    mova                 m1, [cq+15*32+r5]
+    mova                 m2, [cq+ 4*32+r5]
+    mova                 m3, [cq+11*32+r5]
+    mova                 m4, [cq+ 8*32+r5]
+    mova                 m5, [cq+ 7*32+r5]
+    mova                 m6, [cq+12*32+r5]
+    mova                 m7, [cq+ 3*32+r5]
+%if ARCH_X86_32
+    add                  r3, 8*16
+%endif
+    call m(idct_8x4_internal_16bpc).rect2_mul
+%if ARCH_X86_32
+    sub                  r3, 8*16
+%endif
+    call m(iadst_16x4_internal_16bpc).main_part2
+    call m(iadst_16x4_internal_16bpc).round
+%if ARCH_X86_64
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+%endif
+    ret
+
+.pass2:
+%if ARCH_X86_32
+    mov             strideq, [rsp+gprsize+12*16]
+%endif
+    mov                 r4d, 2
+%if ARCH_X86_64
+    mova                 m8, [o(pw_2048)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+    mova                m11, [o(pw_m2048)]
+%endif
+    lea                  r3, [strideq*3]
+    jmp .loop_pass2_entry
+.loop_pass2:
+    mova                 m0, [cq+0*32+ 0]
+    mova                 m1, [cq+1*32+ 0]
+    mova                 m2, [cq+2*32+ 0]
+    mova                 m3, [cq+3*32+ 0]
+.loop_pass2_entry:
+    mova                 m4, [cq+0*32+16]
+    mova                 m5, [cq+1*32+16]
+    mova                 m6, [cq+2*32+16]
+    mova                 m7, [cq+3*32+16]
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    call m_suffix(iadst_8x8_internal_8bpc, _ssse3).main
+    call m_suffix(iadst_8x8_internal_8bpc, _ssse3).main_pass2_end
+    call m(iadst_8x8_internal_16bpc).round2_and_write_8x8
+%if ARCH_X86_64
+%define mzero m9
+%else
+%define mzero m7
+    pxor                 m7, m7
+%endif
+    REPX {mova [cq+x*16], mzero}, 0, 1, 2, 3, 4, 5, 6, 7
+    add                dstq, 16
+    add                  cq, 4*32
+    dec                 r4d
+    jg .loop_pass2
+    RET
+
+INV_TXFM_16X8_FN flipadst, dct
+INV_TXFM_16X8_FN flipadst, adst
+INV_TXFM_16X8_FN flipadst, flipadst
+INV_TXFM_16X8_FN flipadst, identity, 6
+
+cglobal iflipadst_16x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_32
+    mov [rsp+gprsize+12*16], r1
+%endif
+    lea                  t0, [o(.main)]
+    jmp m(idct_16x8_internal_16bpc).loop_main
+.main:
+    call m(iadst_16x8_internal_16bpc).main
+%if ARCH_X86_64
+    pshufd               m1, m0, q1032
+    pshufd               m3, m2, q1032
+    pshufd               m5, m4, q1032
+    pshufd               m7, m6, q1032
+    pshufd               m0, m14, q1032
+    pshufd               m2, m12, q1032
+    pshufd               m4, m10, q1032
+    pshufd               m6, m8, q1032
+    mova                m14, m1
+    mova                m12, m3
+    mova                m10, m5
+    mova                 m8, m7
+%else
+    pshufd               m1, m0, q1032
+    pshufd               m3, m2, q1032
+    pshufd               m5, m4, q1032
+    pshufd               m7, m6, q1032
+    pshufd               m0, [r3+11*16], q1032
+    pshufd               m2, [r3+10*16], q1032
+    pshufd               m4, [r3+9*16], q1032
+    pshufd               m6, [r3+8*16], q1032
+    mova          [r3+8*16], m7
+    mova          [r3+9*16], m5
+    mova         [r3+10*16], m3
+    mova         [r3+11*16], m1
+%endif
+    ret
+
+.pass2:
+%if ARCH_X86_32
+    mov             strideq, [rsp+gprsize+12*16]
+%endif
+    lea                dstq, [dstq+strideq*8]
+    neg             strideq
+    add                dstq, strideq
+%if ARCH_X86_32
+    mov [rsp+gprsize+12*16], strideq
+%endif
+    jmp m(iadst_16x8_internal_16bpc).pass2
+
+INV_TXFM_16X8_FN identity, dct, -54
+INV_TXFM_16X8_FN identity, adst, -54
+INV_TXFM_16X8_FN identity, flipadst, -54
+INV_TXFM_16X8_FN identity, identity
+
+cglobal iidentity_16x8_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_32
+    mov [rsp+gprsize+12*16], r1
+%endif
+    lea                  t0, [o(.main)]
+    jmp m(idct_16x8_internal_16bpc).loop_main
+.main:
+%if ARCH_X86_64
+    mova                m15, [o(pd_2896)]
+    pmulld               m0, m15, [cq+ 0*32+r5]
+    pmulld               m1, m15, [cq+ 1*32+r5]
+    pmulld               m2, m15, [cq+ 2*32+r5]
+    pmulld               m3, m15, [cq+ 3*32+r5]
+    pmulld               m4, m15, [cq+ 4*32+r5]
+    pmulld               m5, m15, [cq+ 5*32+r5]
+    pmulld               m6, m15, [cq+ 6*32+r5]
+    pmulld               m7, m15, [cq+ 7*32+r5]
+    pmulld               m8, m15, [cq+ 8*32+r5]
+    pmulld               m9, m15, [cq+ 9*32+r5]
+    pmulld              m10, m15, [cq+10*32+r5]
+    pmulld              m11, m15, [cq+11*32+r5]
+    pmulld              m12, m15, [cq+12*32+r5]
+    pmulld              m13, m15, [cq+13*32+r5]
+    pmulld              m14, m15, [cq+14*32+r5]
+    pmulld              m15, [cq+15*32+r5]
+    mova               [r3], m15
+    mova                m15, [o(pd_2048)]
+    REPX     {paddd x, m15}, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14
+    paddd               m15, [r3]
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14, m15
+    mova               [r3], m15
+    mova                m15, [o(pd_11586)]
+    REPX    {pmulld x, m15}, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14
+    pmulld              m15, [r3]
+    mova               [r3], m15
+    mova                m15, [o(pd_6144)]
+    REPX     {paddd x, m15}, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14
+    paddd               m15, [r3]
+    REPX     {psrad x, 13 }, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14, m15
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+%else
+    mova                 m0, [cq+ 0*32+r5]
+    mova                 m1, [cq+ 1*32+r5]
+    mova                 m2, [cq+ 2*32+r5]
+    mova                 m3, [cq+ 3*32+r5]
+    mova                 m4, [cq+ 4*32+r5]
+    mova                 m5, [cq+ 5*32+r5]
+    mova                 m6, [cq+ 6*32+r5]
+    mova                 m7, [cq+ 7*32+r5]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    mova               [r3], m7
+    mova                 m7, [o(pd_11586)]
+    REPX      {pmulld x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulld               m7, [r3]
+    mova               [r3], m7
+    mova                 m7, [o(pd_6144)]
+    REPX      {paddd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    paddd                m7, [r3]
+    REPX      {psrad x, 13}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    mova         [r3+ 8*16], m0
+    mova         [r3+ 9*16], m2
+    mova         [r3+10*16], m4
+    mova         [r3+11*16], m6
+    mova                 m0, [cq+ 8*32+r5]
+    mova                 m1, [cq+ 9*32+r5]
+    mova                 m2, [cq+10*32+r5]
+    mova                 m3, [cq+11*32+r5]
+    mova                 m4, [cq+12*32+r5]
+    mova                 m5, [cq+13*32+r5]
+    mova                 m6, [cq+14*32+r5]
+    mova                 m7, [cq+15*32+r5]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    mova               [r3], m7
+    mova                 m7, [o(pd_11586)]
+    REPX      {pmulld x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulld               m7, [r3]
+    mova               [r3], m7
+    mova                 m7, [o(pd_6144)]
+    REPX      {paddd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    paddd                m7, [r3]
+    REPX      {psrad x, 13}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+%endif
+    ret
+.pass2:
+%if ARCH_X86_32
+    mov             strideq, [rsp+gprsize+12*16]
+%endif
+    mov                 r4d, 2
+%if ARCH_X86_64
+    mova                 m8, [o(pw_4096)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+%endif
+    lea                  r3, [strideq*3]
+    jmp .loop_pass2_entry
+.loop_pass2:
+    mova                 m0, [cq+0*32+ 0]
+    mova                 m1, [cq+1*32+ 0]
+    mova                 m2, [cq+2*32+ 0]
+    mova                 m3, [cq+3*32+ 0]
+.loop_pass2_entry:
+    mova                 m4, [cq+0*32+16]
+    mova                 m5, [cq+1*32+16]
+    mova                 m6, [cq+2*32+16]
+    mova                 m7, [cq+3*32+16]
+%if ARCH_X86_64
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+%else
+    mova      [rsp+gprsize], m7
+    mova                 m7, [o(pw_4096)]
+    call m(idct_8x8_internal_16bpc).round4_and_write_8x8
+%endif
+%if ARCH_X86_64
+%define mzero m9
+%else
+%define mzero m7
+    pxor                 m7, m7
+%endif
+    REPX {mova [cq+x*16], mzero}, 0, 1, 2, 3, 4, 5, 6, 7
+    add                dstq, 16
+    add                  cq, 4*32
+    dec                 r4d
+    jg .loop_pass2
+    RET
+
+%macro INV_TXFM_16X16_FN 2-3 2d ; type1, type2, eob_tbl_suffix
+%if ARCH_X86_64
+    INV_TXFM_FN          %1, %2, tbl_16x16_%3, 16x16, 16, 0-(16+WIN64)*16
+%else
+    INV_TXFM_FN          %1, %2, tbl_16x16_%3, 16x16, 8, 0-17*16
+%endif
+%ifidn %1_%2, dct_dct
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 16
+    add                 r5d, 640
+    sar                 r5d, 10
+    add                 rsp, (5+ARCH_X86_64*3+WIN64)*16
+    jmp m(inv_txfm_add_dct_dct_16x4_16bpc).dconly2
+%endif
+%endmacro
+
+INV_TXFM_16X16_FN dct, dct
+INV_TXFM_16X16_FN dct, identity, v
+INV_TXFM_16X16_FN dct, adst
+INV_TXFM_16X16_FN dct, flipadst
+
+cglobal idct_16x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if ARCH_X86_64
+    DECLARE_REG_TMP       6, 7
+%if WIN64
+    mov [rsp+16*16+gprsize], r7
+%endif
+%elif ARCH_X86_32
+    DECLARE_REG_TMP       1, 6
+    mov [rsp+16*16+gprsize*1], r1
+    mov [rsp+16*16+gprsize*2], r6
+%endif
+    lea                  t0, [o(.main)]
+.pass1_full:
+%undef cmp
+    mov                 t1d, 4
+.zero_loop:
+    dec                 t1d
+    cmp                eobb, byte [r5+t1]
+    jb .zero_loop
+    mov                 r5d, t1d
+    shl                 r5d, 4
+%if ARCH_X86_32
+    ; restore pic-ptr
+    mov                  r6, [rsp+16*16+2*gprsize]
+%endif
+    ; setup stack pointer
+    lea                  r3, [rsp+gprsize]
+.loop_pass1:
+    call                 t0
+%if ARCH_X86_64
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova       [cq+4*64+r5], m8
+    mova       [cq+5*64+r5], m9
+    mova       [cq+6*64+r5], m10
+    mova       [cq+7*64+r5], m11
+%else
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova       [cq+4*64+r5], m0
+    mova       [cq+5*64+r5], m1
+    mova       [cq+6*64+r5], m2
+    mova       [cq+7*64+r5], m3
+    mova                 m0, [rsp+gprsize+ 8*16]
+    mova                 m2, [rsp+gprsize+ 9*16]
+    mova                 m4, [rsp+gprsize+10*16]
+    mova                 m6, [rsp+gprsize+11*16]
+%endif
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova       [cq+0*64+r5], m0
+    mova       [cq+1*64+r5], m1
+    mova       [cq+2*64+r5], m2
+    mova       [cq+3*64+r5], m3
+    pxor                 m0, m0
+    REPX {mova [cq+x*64+r5], m0}, 8, 9, 10, 11, 12, 13, 14, 15
+    sub                 r5d, 16
+    jge .loop_pass1
+
+%if ARCH_X86_32
+    ; restore pic-ptr
+    mov                  r1, [rsp+16*16+1*gprsize]
+%endif
+    jmp                tx2q
+.main:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+
+    mova                 m0, [cq+ 1*64+r5]
+    mova                 m1, [cq+ 3*64+r5]
+    mova                 m2, [cq+ 5*64+r5]
+    mova                 m3, [cq+ 7*64+r5]
+    mova                 m4, [cq+ 9*64+r5]
+    mova                 m5, [cq+11*64+r5]
+    mova                 m6, [cq+13*64+r5]
+    mova                 m7, [cq+15*64+r5]
+    call m(idct_16x4_internal_16bpc).main_oddhalf
+
+    mova                 m0, [cq+ 0*64+r5]
+    mova                 m1, [cq+ 2*64+r5]
+    mova                 m2, [cq+ 4*64+r5]
+    mova                 m3, [cq+ 6*64+r5]
+    mova                 m4, [cq+ 8*64+r5]
+    mova                 m5, [cq+10*64+r5]
+    mova                 m6, [cq+12*64+r5]
+    mova                 m7, [cq+14*64+r5]
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    call .round
+%if ARCH_X86_64
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+%endif
+    ret
+.round:
+%if ARCH_X86_64
+    REPX    {pmaxsd x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX    {pminsd x, m13}, m0, m1, m2, m3, m4, m5, m6, m7
+    psrld                m8, m11, 10        ; 2
+    REPX      {paddd x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    mova                 m8, [r3+1*16]
+    mova                 m9, [r3+2*16]
+    mova                m10, [r3+3*16]
+    mova                m11, [r3+4*16]
+    mova                m12, [r3+5*16]
+    mova                m13, [r3+6*16]
+    mova                m14, [r3+7*16]
+    psubd               m15, m0, m14       ; out15
+    paddd                m0, m14           ; out0
+    psubd               m14, m1, m13       ; out14
+    paddd                m1, m13           ; out1
+    psubd               m13, m2, m12       ; out13
+    paddd                m2, m12           ; out2
+    psubd               m12, m3, m11       ; out12
+    paddd                m3, m11           ; out3
+    psubd               m11, m4, m10       ; out11
+    paddd                m4, m10           ; out4
+    psubd               m10, m5, m9        ; out10
+    paddd                m5, m9            ; out5
+    psubd                m9, m6, m8        ; out9
+    paddd                m6, m8            ; out6
+    psubd                m8, m7, [r3+0*16] ; out8
+    paddd                m7, [r3+0*16]     ; out7
+    REPX       {psrad x, 2}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11, m12, m13, m14, m15
+    ; and out0-15 is now in m0-15
+%else
+    mova         [r3+ 0*16], m0
+    mova                 m0, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m0}, m1, m2, m3, m4, m5, m6, m7
+    pmaxsd               m0, [r3+ 0*16]
+    mova         [r3+ 0*16], m7
+    mova                 m7, [o(clip_18b_max)]
+    REPX     {pminsd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pminsd               m7, [r3+ 0*16]
+    mova         [r3+ 0*16], m0
+    mova                 m0, [o(pd_2)]
+    REPX      {paddd x, m0}, m1, m2, m3, m4, m5, m6, m7
+    paddd                m0, [r3+ 0*16]
+    mova         [r3+ 0*16], m0
+    mova         [r3+ 1*16], m1
+    mova         [r3+ 2*16], m2
+    mova                 m1, [r3+11*16]
+    mova                 m2, [r3+10*16]
+    psubd                m0, m7, m1
+    paddd                m7, m1
+    psubd                m1, m6, m2
+    paddd                m6, m2
+    REPX       {psrad x, 2}, m0, m1, m6, m7
+    packssdw             m0, m1     ; out8-9
+    packssdw             m6, m7     ; out6-7
+    mova         [r3+11*16], m6
+    mova                 m1, [r3+9*16]
+    mova                 m7, [r3+8*16]
+    psubd                m2, m5, m1
+    paddd                m5, m1
+    psubd                m1, m4, m7
+    paddd                m4, m7
+    REPX       {psrad x, 2}, m2, m1, m4, m5
+    packssdw             m2, m1     ; out10-11
+    packssdw             m4, m5     ; out4-5
+    mova                 m1, [r3+2*16]
+    mova         [r3+10*16], m4
+    mova                 m6, [r3+7*16]
+    mova                 m7, [r3+6*16]
+    psubd                m4, m3, m6
+    paddd                m3, m6
+    psubd                m6, m1, m7
+    paddd                m1, m7
+    REPX       {psrad x, 2}, m4, m6, m1, m3
+    packssdw             m4, m6     ; out12-13
+    packssdw             m1, m3     ; out2-3
+    mova                 m3, [r3+1*16]
+    mova          [r3+9*16], m1
+    mova                 m1, [r3+0*16]
+    mova                 m5, [r3+5*16]
+    mova                 m7, [r3+4*16]
+    psubd                m6, m3, m5
+    paddd                m3, m5
+    psubd                m5, m1, m7
+    paddd                m1, m7
+    REPX       {psrad x, 2}, m6, m5, m1, m3
+    packssdw             m6, m5     ; out14-15
+    packssdw             m1, m3     ; out0-1
+    mova          [r3+8*16], m1
+%endif
+    ret
+
+.pass2:
+%if ARCH_X86_64
+    mova                 m8, [o(pw_2048)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+    mov                  r7, dstq
+%else
+    mov [rsp+2*gprsize+16*16], dstq
+%endif
+    lea                  r3, [strideq*3]
+    mov                 r4d, 2
+.loop_pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    mova                 m0, [cq+0*64+ 0]
+    mova                 m1, [cq+2*64+ 0]
+    mova                 m2, [cq+0*64+16]
+    mova                 m3, [cq+2*64+16]
+    mova                 m4, [cq+0*64+32]
+    mova                 m5, [cq+2*64+32]
+    mova                 m6, [cq+0*64+48]
+    mova                 m7, [cq+2*64+48]
+    call m_suffix(idct_8x8_internal_8bpc, _ssse3).main
+    mova [rsp+gprsize+3*16], m0
+    mova [rsp+gprsize+4*16], m1
+    mova [rsp+gprsize+5*16], m2
+    mova [rsp+gprsize+6*16], m3
+    mova [rsp+gprsize+7*16], m4
+    mova [rsp+gprsize+8*16], m5
+    mova [rsp+gprsize+9*16], m6
+    ; m7 is already stored in [rsp+gprsize+0*16]
+    mova                 m0, [cq+1*64+ 0]
+    mova                 m1, [cq+3*64+ 0]
+    mova                 m2, [cq+1*64+16]
+    mova                 m3, [cq+3*64+16]
+    mova                 m4, [cq+1*64+32]
+    mova                 m5, [cq+3*64+32]
+    mova                 m6, [cq+1*64+48]
+    mova                 m7, [cq+3*64+48]
+    call m_suffix(idct_16x8_internal_8bpc, _ssse3).main
+
+    ; out0-7 is in rsp+gprsize+3-10*mmsize
+    ; out8-14 is in m0-6, and out15 is in m7 as well as rsp+gprsize+0*mmsize
+
+%if ARCH_X86_64
+    lea                dstq, [r7+strideq*8]
+%else
+    mov                dstq, [rsp+2*gprsize+16*16]
+    lea                dstq, [dstq+strideq*8]
+%endif
+    call m(idct_8x8_internal_16bpc).round2_and_write_8x8
+%if ARCH_X86_64
+    mov                dstq, r7
+%else
+    mov                dstq, [rsp+2*gprsize+16*16]
+%endif
+    mova                 m0, [rsp+gprsize+ 3*16]
+    mova                 m1, [rsp+gprsize+ 4*16]
+    mova                 m2, [rsp+gprsize+ 5*16]
+    mova                 m3, [rsp+gprsize+ 6*16]
+    mova                 m4, [rsp+gprsize+ 7*16]
+    mova                 m5, [rsp+gprsize+ 8*16]
+    mova                 m6, [rsp+gprsize+ 9*16]
+    mova                 m7, [rsp+gprsize+10*16]
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+%if ARCH_X86_64
+    add                  r7, 16
+%define mzero m9
+%else
+    add dword [rsp+2*gprsize+16*16], 16
+%define mzero m7
+    pxor                 m7, m7
+%endif
+    REPX {mova [cq+x*16], mzero}, 0, 1, 2, 3, 4, 5, 6, 7
+    add                  cq, 64*4
+    REPX {mova [cq+x*16], mzero}, -8, -7, -6, -5, -4, -3, -2, -1
+%undef mzero
+    dec                 r4d
+    jg .loop_pass2
+%if WIN64
+    mov                  r7, [rsp+16*16+gprsize]
+%endif
+    RET
+
+INV_TXFM_16X16_FN adst, dct
+INV_TXFM_16X16_FN adst, adst
+INV_TXFM_16X16_FN adst, flipadst
+
+cglobal iadst_16x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if WIN64
+    mov [rsp+16*16+gprsize], r7
+%elif ARCH_X86_32
+    mov [rsp+16*16+gprsize*1], r1
+    mov [rsp+16*16+gprsize*2], r6
+%endif
+    lea                  t0, [o(.main)]
+    jmp m(idct_16x16_internal_16bpc).pass1_full
+
+.main:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+ 2*64+r5]
+    mova                 m1, [cq+13*64+r5]
+    mova                 m2, [cq+ 6*64+r5]
+    mova                 m3, [cq+ 9*64+r5]
+    mova                 m4, [cq+10*64+r5]
+    mova                 m5, [cq+ 5*64+r5]
+    mova                 m6, [cq+14*64+r5]
+    mova                 m7, [cq+ 1*64+r5]
+    call m(iadst_16x4_internal_16bpc).main_part1
+    mova                 m0, [cq+ 0*64+r5]
+    mova                 m1, [cq+15*64+r5]
+    mova                 m2, [cq+ 4*64+r5]
+    mova                 m3, [cq+11*64+r5]
+    mova                 m4, [cq+ 8*64+r5]
+    mova                 m5, [cq+ 7*64+r5]
+    mova                 m6, [cq+12*64+r5]
+    mova                 m7, [cq+ 3*64+r5]
+    call m(iadst_16x4_internal_16bpc).main_part2
+    call .round
+%if ARCH_X86_64
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+%endif
+    ret
+.round:
+%if ARCH_X86_64
+    pcmpeqd              m8, m8         ; -1
+    mova                m15, [o(pd_10240)]
+    psrld               m14, 10         ; +2
+    psubd               m13, m14, m8    ; +3
+    REPX     {pxor  x, m8 }, m1, m3, m5, m7
+    REPX     {paddd x, m14}, m0, m2
+    REPX     {paddd x, m13}, m1, m3
+    REPX     {paddd x, m15}, m4, m5, m6, m7
+    paddd               m13, m15, m8    ; +10239
+    paddd                m8, m15, m9
+    psubd                m9, m13, m10
+    paddd               m10, m15, m11
+    psubd               m11, m13, m12
+    paddd               m12, m14, [r3+3*16]
+    psubd               m13, m14, [r3+2*16]
+    psubd               m15, m14, [r3+0*16]
+    paddd               m14, [r3+1*16]
+    REPX      {psrad x, 2 }, m0,  m1,  m2,  m3,  m12, m13, m14, m15
+    REPX      {psrad x, 14}, m4,  m5,  m6,  m7,  m8,  m9,  m10, m11
+%else
+    mova          [r3+8*16], m1
+    mova          [r3+9*16], m3
+    mova                 m3, [o(pd_10240)]
+    pcmpeqd              m1, m1
+    REPX      {pxor  x, m1}, m5, m7
+    REPX      {paddd x, m3}, m4, m5, m6, m7
+    REPX      {psrad x, 14}, m4, m5, m6, m7
+    packssdw             m4, m5
+    packssdw             m6, m7
+    mova         [r3+10*16], m4
+    mova         [r3+11*16], m6
+    mova                 m4, [r3+4*16]
+    mova                 m5, [r3+5*16]
+    mova                 m6, [r3+6*16]
+    mova                 m7, [r3+7*16]
+    mova                 m3, [o(pd_2)]
+    REPX      {pxor  x, m1}, m5, m7
+    REPX      {paddd x, m3}, m4, m6
+    psubd                m3, m1
+    REPX      {paddd x, m3}, m5, m7
+    REPX      {psrad x, 2 }, m4, m5, m6, m7
+    packssdw             m4, m5
+    packssdw             m6, m7
+    mova                 m5, [r3+8*16]
+    mova                 m7, [r3+9*16]
+    mova          [r3+8*16], m4
+    mova          [r3+9*16], m6
+    mova                 m3, [o(pd_10240)]
+    REPX      {pxor  x, m1}, m5, m7
+    REPX      {paddd x, m3}, m0, m5, m2, m7
+    REPX      {psrad x, 14}, m0, m5, m2, m7
+    packssdw             m0, m5
+    packssdw             m2, m7
+    mova                 m4, [r3+0*16]
+    mova                 m5, [r3+1*16]
+    mova                 m6, [r3+2*16]
+    mova                 m7, [r3+3*16]
+    mova                 m3, [o(pd_2)]
+    REPX      {pxor  x, m1}, m5, m7
+    REPX      {paddd x, m3}, m4, m6
+    psubd                m3, m1
+    REPX      {paddd x, m3}, m5, m7
+    REPX      {psrad x, 2 }, m4, m5, m6, m7
+    packssdw             m4, m5
+    packssdw             m6, m7
+%endif
+    ret
+.pass2:
+%if ARCH_X86_64
+    mova                 m8, [o(pw_2048)]
+    mova                m11, [o(pw_m2048)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+    mov                  r7, dstq
+%else
+    mov [rsp+2*gprsize+16*16], dstq
+%endif
+    lea                  r3, [strideq*3]
+    mov                 r4d, 2
+.loop_pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    mova                 m0, [cq+0*64+32]
+    mova                 m1, [cq+1*64+32]
+    mova                 m2, [cq+2*64+16]
+    mova                 m3, [cq+3*64+16]
+    mova                 m4, [cq+0*64+ 0]
+    mova                 m5, [cq+1*64+ 0]
+    mova                 m6, [cq+2*64+48]
+    mova                 m7, [cq+3*64+48]
+    mova [rsp+gprsize+3*16], m0
+    mova [rsp+gprsize+4*16], m1
+    mova [rsp+gprsize+5*16], m2
+    mova [rsp+gprsize+6*16], m3
+    mova [rsp+gprsize+7*16], m4
+    mova [rsp+gprsize+8*16], m5
+    mova [rsp+gprsize+9*16], m6
+    mova [rsp+gprsize+10*16], m7
+    mova                 m0, [cq+2*64+ 0]
+    mova                 m1, [cq+3*64+ 0]
+    mova                 m2, [cq+0*64+16]
+    mova                 m3, [cq+1*64+16]
+    mova                 m4, [cq+2*64+32]
+    mova                 m5, [cq+3*64+32]
+    mova                 m6, [cq+0*64+48]
+    mova                 m7, [cq+1*64+48]
+    call m_suffix(iadst_16x8_internal_8bpc, _ssse3).main
+    call m_suffix(iadst_16x8_internal_8bpc, _ssse3).main_pass2_end
+
+    ; out0-7 is in rsp+gprsize+3-10*mmsize
+    ; out8-14 is in m0-6, and out15 is in m7 as well as rsp+gprsize+0*mmsize
+
+%if ARCH_X86_64
+    lea                dstq, [r7+strideq*8]
+%else
+    mov                dstq, [rsp+2*gprsize+16*16]
+    lea                dstq, [dstq+strideq*8]
+%endif
+    call m(iadst_8x8_internal_16bpc).round2_and_write_8x8
+%if ARCH_X86_64
+    mov                dstq, r7
+%else
+    mov                dstq, [rsp+2*gprsize+16*16]
+%endif
+    mova                 m0, [rsp+gprsize+ 3*16]
+    mova                 m1, [rsp+gprsize+ 4*16]
+    mova                 m2, [rsp+gprsize+ 5*16]
+    mova                 m3, [rsp+gprsize+ 6*16]
+    mova                 m4, [rsp+gprsize+ 7*16]
+    mova                 m5, [rsp+gprsize+ 8*16]
+    mova                 m6, [rsp+gprsize+ 9*16]
+    mova                 m7, [rsp+gprsize+10*16]
+    call m(iadst_8x8_internal_16bpc).round1_and_write_8x8
+%if ARCH_X86_64
+    add                  r7, 16
+%define mzero m9
+%else
+    add dword [rsp+2*gprsize+16*16], 16
+%define mzero m7
+    pxor                 m7, m7
+%endif
+    REPX {mova [cq+x*16], mzero}, 0, 1, 2, 3, 4, 5, 6, 7
+    add                  cq, 64*4
+    REPX {mova [cq+x*16], mzero}, -8, -7, -6, -5, -4, -3, -2, -1
+%undef mzero
+    dec                 r4d
+    jg .loop_pass2
+%if WIN64
+    mov                  r7, [rsp+16*16+gprsize]
+%endif
+    RET
+
+INV_TXFM_16X16_FN flipadst, dct
+INV_TXFM_16X16_FN flipadst, adst
+INV_TXFM_16X16_FN flipadst, flipadst
+
+cglobal iflipadst_16x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if WIN64
+    mov [rsp+16*16+gprsize], r7
+%elif ARCH_X86_32
+    mov [rsp+16*16+gprsize*1], r1
+    mov [rsp+16*16+gprsize*2], r6
+%endif
+    lea                  t0, [o(.main)]
+    jmp m(idct_16x16_internal_16bpc).pass1_full
+
+.main:
+    call m(iadst_16x16_internal_16bpc).main
+%if ARCH_X86_64
+    mova                 m1, m0
+    mova                 m3, m2
+    mova                 m5, m4
+    mova                 m7, m6
+    pshufd               m0, m14, q1032
+    pshufd               m2, m12, q1032
+    pshufd               m4, m10, q1032
+    pshufd               m6, m8, q1032
+    pshufd               m8, m7, q1032
+    pshufd              m10, m5, q1032
+    pshufd              m12, m3, q1032
+    pshufd              m14, m1, q1032
+%else
+    pshufd               m1, m0, q1032
+    pshufd               m3, m2, q1032
+    pshufd               m5, m4, q1032
+    pshufd               m7, m6, q1032
+    pshufd               m0, [r3+11*16], q1032
+    pshufd               m2, [r3+10*16], q1032
+    pshufd               m4, [r3+9*16], q1032
+    pshufd               m6, [r3+8*16], q1032
+    mova         [r3+11*16], m1
+    mova         [r3+10*16], m3
+    mova         [r3+ 9*16], m5
+    mova         [r3+ 8*16], m7
+%endif
+    ret
+
+.pass2:
+    lea                  r3, [strideq*3]
+    lea                  r3, [r3*5]
+    add                dstq, r3
+    neg             strideq
+    jmp m(iadst_16x16_internal_16bpc).pass2
+
+INV_TXFM_16X16_FN identity, dct, h
+INV_TXFM_16X16_FN identity, identity
+
+cglobal iidentity_16x16_internal_16bpc, 0, 0, 0, dst, stride, c, eob, tx2
+%if WIN64
+    mov [rsp+16*16+gprsize], r7
+%elif ARCH_X86_32
+    mov [rsp+16*16+gprsize*1], r1
+    mov [rsp+16*16+gprsize*2], r6
+%endif
+    lea                  t0, [o(.main)]
+    jmp m(idct_16x16_internal_16bpc).pass1_full
+
+.main:
+%if ARCH_X86_64
+    mova                m15, [o(pd_11586)]
+    pmulld               m0, m15, [cq+ 0*64+r5]
+    pmulld               m1, m15, [cq+ 1*64+r5]
+    pmulld               m2, m15, [cq+ 2*64+r5]
+    pmulld               m3, m15, [cq+ 3*64+r5]
+    pmulld               m4, m15, [cq+ 4*64+r5]
+    pmulld               m5, m15, [cq+ 5*64+r5]
+    pmulld               m6, m15, [cq+ 6*64+r5]
+    pmulld               m7, m15, [cq+ 7*64+r5]
+    pmulld               m8, m15, [cq+ 8*64+r5]
+    pmulld               m9, m15, [cq+ 9*64+r5]
+    pmulld              m10, m15, [cq+10*64+r5]
+    pmulld              m11, m15, [cq+11*64+r5]
+    pmulld              m12, m15, [cq+12*64+r5]
+    pmulld              m13, m15, [cq+13*64+r5]
+    pmulld              m14, m15, [cq+14*64+r5]
+    pmulld              m15, [cq+15*64+r5]
+    mova               [r3], m15
+    mova                m15, [o(pd_10240)]
+    REPX     {paddd x, m15}, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14
+    paddd               m15, [r3]
+    REPX     {psrad x, 14 }, m0, m1, m2, m3, m4, m5, m6, m7, \
+                         m8, m9, m10, m11, m12, m13, m14, m15
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+%else
+    mova                 m7, [o(pd_11586)]
+    pmulld               m0, m7, [cq+ 0*64+r5]
+    pmulld               m1, m7, [cq+ 1*64+r5]
+    pmulld               m2, m7, [cq+ 2*64+r5]
+    pmulld               m3, m7, [cq+ 3*64+r5]
+    pmulld               m4, m7, [cq+ 4*64+r5]
+    pmulld               m5, m7, [cq+ 5*64+r5]
+    pmulld               m6, m7, [cq+ 6*64+r5]
+    pmulld               m7, [cq+ 7*64+r5]
+    mova               [r3], m7
+    mova                 m7, [o(pd_10240)]
+    REPX      {paddd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    paddd                m7, [r3]
+    REPX      {psrad x, 14}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    mova          [r3+8*16], m0
+    mova          [r3+9*16], m2
+    mova         [r3+10*16], m4
+    mova         [r3+11*16], m6
+    mova                 m7, [o(pd_11586)]
+    pmulld               m0, m7, [cq+ 8*64+r5]
+    pmulld               m1, m7, [cq+ 9*64+r5]
+    pmulld               m2, m7, [cq+10*64+r5]
+    pmulld               m3, m7, [cq+11*64+r5]
+    pmulld               m4, m7, [cq+12*64+r5]
+    pmulld               m5, m7, [cq+13*64+r5]
+    pmulld               m6, m7, [cq+14*64+r5]
+    pmulld               m7, [cq+15*64+r5]
+    mova               [r3], m7
+    mova                 m7, [o(pd_10240)]
+    REPX      {paddd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    paddd                m7, [r3]
+    REPX      {psrad x, 14}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+%endif
+    ret
+
+.pass2:
+%if ARCH_X86_64
+    mova                 m4, [o(pw_2048)]
+    mova                 m5, [o(pixel_10bpc_max)]
+    pxor                 m6, m6
+    mova                 m7, [o(pw_1697x16)]
+    mov                  r7, dstq
+%else
+    mov [rsp+2*gprsize+16*16], dstq
+%endif
+    mov                 r5d, 4
+    lea                  r3, [strideq*3]
+.pass2_loop:
+    mova                 m0, [cq+0*64+0]
+    mova                 m1, [cq+1*64+0]
+    mova                 m2, [cq+2*64+0]
+    mova                 m3, [cq+3*64+0]
+    call m(iidentity_8x16_internal_16bpc).main
+%if ARCH_X86_64
+    call m(idct_8x4_internal_16bpc).round1_and_write_8x4
+%else
+    call m(idct_8x4_internal_16bpc).round2_and_write_8x4
+%endif
+    REPX {mova [cq+x*16], m6}, 0, 4, 8, 12
+    add                  cq, 16
+    lea                dstq, [dstq+strideq*4]
+    dec                 r5w
+    jg .pass2_loop
+    add                  cq, 64*3
+    btc                 r5d, 16
+    jc .end
+%if ARCH_X86_64
+    lea                dstq, [r7+16]
+%else
+    mov                dstq, [rsp+2*gprsize+16*16]
+    add                dstq, 16
+%endif
+    add                 r5d, 4
+    jmp .pass2_loop
+.end:
+%if WIN64
+    mov                  r7, [rsp+16*16+gprsize]
+%endif
+    RET
+
+cglobal inv_txfm_add_identity_identity_8x32_16bpc, 4, 7, 8, dst, stride, c, eob
+%if ARCH_X86_32
+    LEA                  r6, $$
+%endif
+    mova                 m5, [o(pw_5)]
+    mova                 m7, [o(pixel_10bpc_max)]
+    pxor                 m6, m6
+    mov                 r5d, eobd
+    add                eobb, 21
+    cmovc              eobd, r5d ; 43, 107, 171 -> 64, 128, 192
+    lea                  r4, [strideq*3]
+.loop:
+    mova                 m0, [cq+128*0]
+    packssdw             m0, [cq+128*1]
+    mova                 m1, [cq+128*2]
+    packssdw             m1, [cq+128*3]
+    mova                 m2, [cq+128*4]
+    packssdw             m2, [cq+128*5]
+    mova                 m3, [cq+128*6]
+    packssdw             m3, [cq+128*7]
+    REPX     {paddsw x, m5}, m0, m1, m2, m3
+    REPX     {psraw  x, 3 }, m0, m1, m2, m3
+    call .main_zero
+    add                  cq, 16
+    lea                dstq, [dstq+strideq*4]
+    btc                eobd, 16
+    jnc .loop
+    sub                eobd, 64
+    jge .loop
+    RET
+ALIGN function_align
+.main_zero:
+    REPX {mova [cq+128*x], m6}, 0, 1, 2, 3, 4, 5, 6, 7
+.main:
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m0, m4
+    punpcklwd            m0, m4
+    punpckhwd            m4, m2, m1
+    punpcklwd            m2, m1
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    paddw                m0, [dstq+strideq*0]
+    paddw                m1, [dstq+strideq*1]
+    paddw                m2, [dstq+strideq*2]
+    paddw                m3, [dstq+r4       ]
+    REPX     {pmaxsw x, m6}, m0, m1, m2, m3
+    REPX     {pminsw x, m7}, m0, m1, m2, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+r4       ], m3
+    ret
+
+cglobal inv_txfm_add_identity_identity_32x8_16bpc, 4, 7, 8, dst, stride, c, eob
+%if ARCH_X86_32
+    LEA                  r6, $$
+%endif
+    mova                 m5, [o(pw_4096)]
+    mova                 m7, [o(pixel_10bpc_max)]
+    pxor                 m6, m6
+    mov                 r4d, eobd
+    add                eobb, 21
+    cmovc              eobd, r4d
+    lea                  r4, [strideq*3]
+    mov                  r5, dstq
+.loop:
+    mova                 m0, [cq+32*0]
+    packssdw             m0, [cq+32*1]
+    mova                 m1, [cq+32*2]
+    packssdw             m1, [cq+32*3]
+    mova                 m2, [cq+32*4]
+    packssdw             m2, [cq+32*5]
+    mova                 m3, [cq+32*6]
+    packssdw             m3, [cq+32*7]
+    REPX {mova [cq+32*x], m6}, 0, 1, 2, 3, 4, 5, 6, 7
+    REPX   {pmulhrsw x, m5}, m0, m1, m2, m3
+    call m(inv_txfm_add_identity_identity_8x32_16bpc).main
+    lea                dstq, [dstq+strideq*4]
+    add                  cq, 16
+    btc                eobd, 16
+    jnc .loop
+    add                  cq, 32*8-32
+    add                  r5, 16
+    mov                dstq, r5
+    sub                eobd, 64
+    jge .loop
+    RET
+
+cglobal inv_txfm_add_identity_identity_16x32_16bpc, 4, 7, 12, dst, stride, c, eob
+%if ARCH_X86_32
+    LEA                  r6, $$
+%else
+    mova                 m8, [o(pw_2896x8)]
+    mova                 m9, [o(pw_1697x16)]
+    mova                m11, [o(pw_8192)]
+%endif
+    mova                 m7, [o(pixel_10bpc_max)]
+    lea                  r4, [strideq*3]
+    pxor                 m6, m6
+%if ARCH_X86_64
+    paddw               m10, m11, m11 ; pw_16384
+%endif
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 36
+    jl .ret
+    add                  cq, 128*8-32
+    lea                dstq, [r5+16]
+    call .main
+    sub                  cq, 128*8
+    lea                dstq, [r5+strideq*8]
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 107 ; eob < 143
+    jl .ret
+    add                  cq, 128*8-32
+    lea                dstq, [r5+16]
+    call .main
+    sub                  cq, 128*8
+    lea                dstq, [r5+strideq*8]
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 128 ; eob < 271
+    jl .ret
+    add                  cq, 128*8-32
+    lea                dstq, [r5+16]
+    call .main
+    sub                  cq, 128*8
+    lea                dstq, [r5+strideq*8]
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 128 ; eob < 399
+    jl .ret
+    add                  cq, 128*8-32
+    lea                dstq, [r5+16]
+    call .main
+.ret:
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [cq+128*0]
+    packssdw             m0, [cq+128*1]
+    mova                 m1, [cq+128*2]
+    packssdw             m1, [cq+128*3]
+    mova                 m2, [cq+128*4]
+    packssdw             m2, [cq+128*5]
+    mova                 m3, [cq+128*6]
+    packssdw             m3, [cq+128*7]
+%if ARCH_X86_64
+    REPX  {pmulhrsw x, m8 }, m0, m1, m2, m3
+    pmulhrsw             m4, m9, m0
+    pmulhrsw             m5, m9, m1
+    REPX  {pmulhrsw x, m10}, m4, m5
+%else
+    mova                 m6, [o(pw_2896x8)]
+    REPX  {pmulhrsw x, m6 }, m0, m1, m2, m3
+    mova                 m5, [o(pw_1697x16)]
+    pmulhrsw             m4, m5, m0
+    pmulhrsw             m5, m1
+    mova                 m6, [o(pw_16384)]
+    REPX  {pmulhrsw x, m6 }, m4, m5
+%endif
+    paddsw               m0, m4
+    paddsw               m1, m5
+%if ARCH_X86_64
+    pmulhrsw             m4, m9, m2
+    pmulhrsw             m5, m9, m3
+    REPX  {pmulhrsw x, m10}, m4, m5
+%else
+    mova                 m5, [o(pw_1697x16)]
+    pmulhrsw             m4, m5, m2
+    pmulhrsw             m5, m3
+    REPX  {pmulhrsw x, m6 }, m4, m5
+%endif
+    paddsw               m2, m4
+    paddsw               m3, m5
+%if ARCH_X86_64
+    REPX  {pmulhrsw x, m11}, m0, m1, m2, m3
+%else
+    psrlw                m6, 1          ; pw_8192
+    REPX  {pmulhrsw x, m6 }, m0, m1, m2, m3
+    pxor                 m6, m6
+%endif
+    call m(inv_txfm_add_identity_identity_8x32_16bpc).main_zero
+    lea                dstq, [dstq+strideq*4]
+    add                  cq, 16
+    btc                eobd, 16
+    jnc .main
+    ret
+
+cglobal inv_txfm_add_identity_identity_32x16_16bpc, 4, 7, 11, dst, stride, c, eob
+%if ARCH_X86_32
+    LEA                  r6, $$
+%else
+    mova                 m8, [o(pw_2896x8)]
+    mova                 m9, [o(pw_1697x16)]
+    mova                m10, [o(pw_2048)]
+%endif
+    mova                 m7, [o(pixel_10bpc_max)]
+    lea                  r4, [strideq*3]
+    pxor                 m6, m6
+    mov                  r5, dstq
+    call .main
+    sub                eobd, 36
+    jl .ret
+    call .main
+    add                  cq, 64*8-64
+    lea                dstq, [r5+16*1]
+    call .main
+    sub                eobd, 107 ; eob < 143
+    jl .ret
+    call .main
+    add                  cq, 64*8-64
+    lea                dstq, [r5+16*2]
+    call .main
+    sub                eobd, 128 ; eob < 271
+    jl .ret
+    call .main
+    add                  cq, 64*8-64
+    lea                dstq, [r5+16*3]
+    call .main
+    sub                eobd, 128 ; eob < 399
+    jl .ret
+    call .main
+.ret:
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [cq+64*0]
+    packssdw             m0, [cq+64*1]
+    mova                 m1, [cq+64*2]
+    packssdw             m1, [cq+64*3]
+    mova                 m2, [cq+64*4]
+    packssdw             m2, [cq+64*5]
+    mova                 m3, [cq+64*6]
+    packssdw             m3, [cq+64*7]
+%if ARCH_X86_64
+    REPX  {pmulhrsw x, m8 }, m0, m1, m2, m3
+%else
+    mova                 m6, [o(pw_2896x8)]
+    REPX  {pmulhrsw x, m6 }, m0, m1, m2, m3
+%endif
+    REPX  {paddsw   x, x  }, m0, m1, m2, m3
+%if ARCH_X86_64
+    pmulhrsw             m4, m9, m0
+    pmulhrsw             m5, m9, m1
+%else
+    mova                 m6, [o(pw_1697x16)]
+    pmulhrsw             m4, m6, m0
+    pmulhrsw             m5, m6, m1
+%endif
+    REPX  {paddsw   x, x  }, m0, m1
+    paddsw               m0, m4
+    paddsw               m1, m5
+%if ARCH_X86_64
+    pmulhrsw             m4, m9, m2
+    pmulhrsw             m5, m9, m3
+%else
+    pmulhrsw             m4, m6, m2
+    pmulhrsw             m6, m3
+%endif
+    REPX  {paddsw   x, x  }, m2, m3
+    paddsw               m2, m4
+%if ARCH_X86_64
+    paddsw               m3, m5
+    REPX  {pmulhrsw x, m10}, m0, m1, m2, m3
+%else
+    paddsw               m3, m6
+    mova                 m6, [o(pw_2048)]
+    REPX  {pmulhrsw x, m6 }, m0, m1, m2, m3
+    pxor                 m6, m6
+%endif
+    REPX {mova [cq+64*x], m6}, 0, 1, 2, 3, 4, 5, 6, 7
+    call m(inv_txfm_add_identity_identity_8x32_16bpc).main
+    lea                dstq, [dstq+strideq*4]
+    add                  cq, 16
+    btc                eobd, 16
+    jnc .main
+    ret
+
+cglobal inv_txfm_add_identity_identity_32x32_16bpc, 4, 7, 8, dst, stride, c, eob
+%undef cmp
+%if ARCH_X86_32
+    LEA                  r6, $$
+%endif
+    mova                 m5, [o(pw_8192)]
+    mova                 m7, [o(pixel_10bpc_max)]
+    pxor                 m6, m6
+    lea                  r4, [strideq*3]
+    mov                  r5, dstq
+    call .main                              ; 0
+    cmp                eobd, 36
+    jl .ret
+    add                  cq, 128*8-32       ; 0 1
+    lea                dstq, [r5+16]        ; 1
+    call .main
+    call .main2
+    cmp                eobd, 136
+    jl .ret
+    add                  cq, 128*16-64      ; 0 1 2
+    lea                dstq, [r5+16*2]      ; 1 2
+    call .main                              ; 2
+    call .main2
+    call .main2
+    cmp                eobd, 300
+    jl .ret
+    add                  cq, 128*24-96      ; 0 1 2 3
+    add                  r5, 16*3           ; 1 2 3
+    mov                dstq, r5             ; 2 3
+    call .main                              ; 3
+    call .main2
+    call .main2
+    call .main2
+    cmp                eobd, 535
+    jl .ret
+    add                  cq, 128*24-96      ; 0 1 2 3
+    lea                dstq, [r5+strideq*8] ; 1 2 3 4
+    mov                  r5, dstq           ; 2 3 4
+    call .main                              ; 3 4
+    call .main2
+    call .main2
+    cmp                eobd, 755
+    jl .ret
+    add                  cq, 128*16-64      ; 0 1 2 3
+    lea                dstq, [r5+strideq*8] ; 1 2 3 4
+    mov                  r5, dstq           ; 2 3 4 5
+    call .main                              ; 3 4 5
+    call .main2
+    cmp                eobd, 911
+    jl .ret
+    add                  cq, 128*8-32       ; 0 1 2 3
+    lea                dstq, [r5+strideq*8] ; 1 2 3 4
+    call .main                              ; 2 3 4 5
+.ret:                                       ; 3 4 5 6
+    RET
+ALIGN function_align
+.main2:
+    sub                  cq, 128*8
+    sub                dstq, 16
+.main:
+    mova                 m0, [cq+128*0]
+    packssdw             m0, [cq+128*1]
+    mova                 m1, [cq+128*2]
+    packssdw             m1, [cq+128*3]
+    mova                 m2, [cq+128*4]
+    packssdw             m2, [cq+128*5]
+    mova                 m3, [cq+128*6]
+    packssdw             m3, [cq+128*7]
+    REPX   {pmulhrsw x, m5}, m0, m1, m2, m3
+    call m(inv_txfm_add_identity_identity_8x32_16bpc).main_zero
+    lea                dstq, [dstq+strideq*4]
+    add                  cq, 16
+    btc                eobd, 16
+    jnc .main
+    ret
+
+cglobal inv_txfm_add_dct_dct_8x32_16bpc, 4, 7, 15, 0-36*16, \
+                                         dst, stride, c, eob
+%if ARCH_X86_32
+    LEA                  r6, $$
+%define base $$
+    DECLARE_REG_TMP       0, 4
+%else
+    lea                  r6, [tbl_Nx32_odd_offset]
+%define base tbl_Nx32_odd_offset
+    DECLARE_REG_TMP       4, 7
+%if WIN64
+    mov [rsp+gprsize*1+35*16], r7
+%endif
+%endif
+%define o2(x) r6-base+x
+    test               eobd, eobd
+    jz .dconly
+
+%if ARCH_X86_32
+    mov [rsp+gprsize*1+35*16], r0
+%endif
+%undef cmp
+    ; remove entirely-zero iterations
+    mov                 r5d, 7*2
+    cmp                eobw, word [o2(tbl_8x32_2d)+r5]
+    jge .end_zero_loop
+    pxor                 m0, m0
+.zero_loop:
+    movzx               t0d, word [o2(tbl_Nx32_odd_offset)+r5]
+    movzx               t1d, t0b
+    shr                 t0d, 8
+    mova   [rsp+ 3*16+r5*8], m0
+    mova   [rsp+11*16+r5*8], m0
+    mova   [rsp+ 3*16+t0*8], m0
+    mova   [rsp+ 3*16+t1*8], m0
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_8x32_2d)+r5]
+    jl .zero_loop
+.end_zero_loop:
+    ; actual first pass after skipping all-zero data
+    mov [rsp+gprsize*0+35*16], eobd
+    mov                  r3, rsp
+.loop_pass1:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+0*128+r5*8]
+    mova                 m1, [cq+1*128+r5*8]
+    mova                 m2, [cq+2*128+r5*8]
+    mova                 m3, [cq+3*128+r5*8]
+    mova                 m4, [cq+4*128+r5*8]
+    mova                 m5, [cq+5*128+r5*8]
+    mova                 m6, [cq+6*128+r5*8]
+    mova                 m7, [cq+7*128+r5*8]
+    call m(idct_8x4_internal_16bpc).main_pass1
+    mova                 m1, [o(pd_2)]
+    REPX      {paddd x, m1}, m0, m6, m5, m3
+    call m(idct_8x4_internal_16bpc).round
+    REPX      {psrad x, 2 }, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+
+    movzx               t0d, word [o2(tbl_Nx32_odd_offset)+r5]
+    movzx               t1d, t0b
+    shr                 t0d, 8
+    mova    [r3+ 3*16+r5*8], m0
+    mova    [r3+11*16+r5*8], m2
+    mova    [r3+ 3*16+t1*8], m1
+    mova    [r3+ 3*16+t0*8], m3
+    pxor                 m7, m7
+    REPX {mova [cq+x*128+r5*8], m7}, 0, 1, 2, 3, 4, 5, 6, 7
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass 2 code starts here
+    ; m0 is already loaded from last iteration of first pass
+%if ARCH_X86_32
+    mov                  r0, [rsp+gprsize*1+35*16]
+%endif
+    mov                eobd, [rsp+gprsize*0+35*16]
+    cmp                eobd, 43
+    jl .load_veryfast
+    cmp                eobd, 107
+    jl .load_fast
+    ; load normal
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main)]
+    jmp .run
+.load_fast:
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_fast)]
+    jmp .run
+.load_veryfast:
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_veryfast)]
+    ; fall-through
+.run:
+    call .pass2
+%if WIN64
+    mov                  r7, [rsp+gprsize*1+35*16]
+%endif
+    RET
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    mova                 m1, [rsp+gprsize+16* 4]
+    mova                 m2, [rsp+gprsize+16* 5]
+    mova                 m3, [rsp+gprsize+16* 6]
+    mova                 m4, [rsp+gprsize+16* 7]
+    mova                 m5, [rsp+gprsize+16* 8]
+    mova                 m6, [rsp+gprsize+16* 9]
+    mova                 m7, [rsp+gprsize+16*10]
+    call m_suffix(idct_8x8_internal_8bpc, _ssse3).main
+    mova [rsp+gprsize+ 3*16], m0
+    mova [rsp+gprsize+ 4*16], m1
+    mova [rsp+gprsize+ 5*16], m2
+    mova [rsp+gprsize+ 6*16], m3
+    mova [rsp+gprsize+ 7*16], m4
+    mova [rsp+gprsize+ 8*16], m5
+    mova [rsp+gprsize+ 9*16], m6
+    mova                 m0, [rsp+gprsize+11*16]
+    mova                 m1, [rsp+gprsize+12*16]
+    mova                 m2, [rsp+gprsize+13*16]
+    mova                 m3, [rsp+gprsize+14*16]
+    mova                 m4, [rsp+gprsize+15*16]
+    mova                 m5, [rsp+gprsize+16*16]
+    mova                 m6, [rsp+gprsize+17*16]
+    mova                 m7, [rsp+gprsize+18*16]
+    call m_suffix(idct_16x8_internal_8bpc, _ssse3).main
+    mova                 m7, [rsp+gprsize+ 0*16]
+    mova [rsp+gprsize+11*16], m0
+    mova [rsp+gprsize+12*16], m1
+    mova [rsp+gprsize+13*16], m2
+    mova [rsp+gprsize+14*16], m3
+    mova [rsp+gprsize+15*16], m4
+    mova [rsp+gprsize+16*16], m5
+    mova [rsp+gprsize+17*16], m6
+    mova [rsp+gprsize+18*16], m7
+    call                 r4
+%if ARCH_X86_64
+    mova                 m8, [o(pw_2048)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+%endif
+    lea                  r3, [strideq*3]
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+    lea                dstq, [dstq+strideq*8]
+    mova                 m0, [rsp+gprsize+11*16]
+    mova                 m1, [rsp+gprsize+12*16]
+    mova                 m2, [rsp+gprsize+13*16]
+    mova                 m3, [rsp+gprsize+14*16]
+    mova                 m4, [rsp+gprsize+15*16]
+    mova                 m5, [rsp+gprsize+16*16]
+    mova                 m6, [rsp+gprsize+17*16]
+    mova                 m7, [rsp+gprsize+18*16]
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+    lea                dstq, [dstq+strideq*8]
+    mova                 m0, [rsp+gprsize+19*16]
+    mova                 m1, [rsp+gprsize+20*16]
+    mova                 m2, [rsp+gprsize+21*16]
+    mova                 m3, [rsp+gprsize+22*16]
+    mova                 m4, [rsp+gprsize+23*16]
+    mova                 m5, [rsp+gprsize+24*16]
+    mova                 m6, [rsp+gprsize+25*16]
+    mova                 m7, [rsp+gprsize+26*16]
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+    lea                dstq, [dstq+strideq*8]
+    mova                 m0, [rsp+gprsize+27*16]
+    mova                 m1, [rsp+gprsize+28*16]
+    mova                 m2, [rsp+gprsize+29*16]
+    mova                 m3, [rsp+gprsize+30*16]
+    mova                 m4, [rsp+gprsize+31*16]
+    mova                 m5, [rsp+gprsize+32*16]
+    mova                 m6, [rsp+gprsize+33*16]
+    mova                 m7, [rsp+gprsize+34*16]
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+    ret
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 8
+    add                 r5d, 640
+    sar                 r5d, 10
+    add                 rsp, (31+2*ARCH_X86_64)*16
+    jmp m(inv_txfm_add_dct_dct_8x8_16bpc).end2
+
+cglobal inv_txfm_add_dct_dct_16x32_16bpc, 4, 7, 16, 0-77*16, \
+                                          dst, stride, c, eob
+    LEA                  r6, base
+    test               eobd, eobd
+    jz .dconly
+
+%if ARCH_X86_32
+    mov [rsp+gprsize*1+76*16], r0
+%elif WIN64
+    mov [rsp+gprsize*1+76*16], r7
+%endif
+%undef cmp
+    ; remove entirely-zero iterations
+    mov                 r5d, 7*2
+    cmp                eobw, word [o2(tbl_16x32_2d)+r5]
+    jge .end_zero_loop
+    pxor                 m0, m0
+.zero_loop:
+    movzx               t0d, word [o2(tbl_Nx32_odd_offset)+r5]
+    movzx               t1d, t0b
+    shr                 t0d, 8
+    mova   [rsp+12*16+r5*8], m0
+    mova   [rsp+20*16+r5*8], m0
+    mova   [rsp+12*16+t0*8], m0
+    mova   [rsp+12*16+t1*8], m0
+    mova   [rsp+44*16+r5*8], m0
+    mova   [rsp+52*16+r5*8], m0
+    mova   [rsp+44*16+t0*8], m0
+    mova   [rsp+44*16+t1*8], m0
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_16x32_2d)+r5]
+    jl .zero_loop
+.end_zero_loop:
+    ; actual first pass after skipping all-zero data
+    mov [rsp+gprsize*0+76*16], eobd
+    mov                  r3, rsp
+.loop_pass1:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+ 1*128+r5*8]
+    mova                 m1, [cq+ 3*128+r5*8]
+    mova                 m2, [cq+ 5*128+r5*8]
+    mova                 m3, [cq+ 7*128+r5*8]
+    mova                 m4, [cq+ 9*128+r5*8]
+    mova                 m5, [cq+11*128+r5*8]
+    mova                 m6, [cq+13*128+r5*8]
+    mova                 m7, [cq+15*128+r5*8]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(idct_16x4_internal_16bpc).main_oddhalf
+
+    mova                 m0, [cq+ 0*128+r5*8]
+    mova                 m1, [cq+ 2*128+r5*8]
+    mova                 m2, [cq+ 4*128+r5*8]
+    mova                 m3, [cq+ 6*128+r5*8]
+    mova                 m4, [cq+ 8*128+r5*8]
+    mova                 m5, [cq+10*128+r5*8]
+    mova                 m6, [cq+12*128+r5*8]
+    mova                 m7, [cq+14*128+r5*8]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    call m(idct_16x4_internal_16bpc).round
+%if ARCH_X86_64
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+%endif
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    movzx               t0d, word [o2(tbl_Nx32_odd_offset)+r5]
+    movzx               t1d, t0b
+    shr                 t0d, 8
+%if ARCH_X86_64
+    mova   [rsp+12*16+r5*8], m0
+    mova   [rsp+20*16+r5*8], m2
+    mova   [rsp+12*16+t1*8], m1
+    mova   [rsp+12*16+t0*8], m3
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova   [rsp+44*16+r5*8], m8
+    mova   [rsp+52*16+r5*8], m10
+    mova   [rsp+44*16+t1*8], m9
+    mova   [rsp+44*16+t0*8], m11
+%else
+    mova   [rsp+44*16+r5*8], m0
+    mova   [rsp+52*16+r5*8], m2
+    mova   [rsp+44*16+t1*8], m1
+    mova   [rsp+44*16+t0*8], m3
+    mova                 m0, [r3+ 8*16]
+    mova                 m2, [r3+ 9*16]
+    mova                 m4, [r3+10*16]
+    mova                 m6, [r3+11*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova   [rsp+12*16+r5*8], m0
+    mova   [rsp+20*16+r5*8], m2
+    mova   [rsp+12*16+t1*8], m1
+    mova   [rsp+12*16+t0*8], m3
+%endif
+    pxor                 m7, m7
+    REPX {mova [cq+x*128+r5*8], m7}, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass=2
+    add                 rsp, 9*16
+%if ARCH_X86_64
+    mov                  r6, dstq
+%else
+    mov                dstq, [rsp+gprsize*1+67*16]
+%endif
+    mov                eobd, [rsp+gprsize*0+67*16]
+    cmp                eobd, 44
+    jl .load_veryfast
+    cmp                eobd, 151
+    jl .load_fast
+    ; load normal
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main)]
+    jmp .run
+.load_fast:
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_fast)]
+    jmp .run
+.load_veryfast:
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_veryfast)]
+    ; fall-through
+.run:
+%if ARCH_X86_64
+    lea                  r2, [dstq+32]
+    mov                  r7, -4
+%else
+    lea                  r2, [rsp+67*16]
+    mov dword [r2+0*gprsize], 2
+%endif
+    jmp .loop_pass2_entry
+.loop_pass2:
+    mova                 m0, [rsp+16* 3]
+.loop_pass2_entry:
+%if ARCH_X86_32
+    mov                dstq, [r2+1*gprsize]
+%endif
+    call m(inv_txfm_add_dct_dct_8x32_16bpc).pass2
+    add                 rsp, 32*16
+%if ARCH_X86_64
+    add                  r7, 2
+    lea                dstq, [r2+r7*8]
+    jl .loop_pass2
+%if WIN64
+    mov                  r7, [rsp+gprsize*1+3*16]
+%endif
+%else
+    add dword [r2+1*gprsize], 16
+    dec dword [r2+0*gprsize]
+    jg .loop_pass2
+%endif
+%assign stack_size (stack_size-73*16)
+%if STACK_ALIGNMENT >= 16
+%assign stack_size_padded (stack_size_padded-73*16)
+%assign stack_offset (stack_offset-73*16)
+%else
+%xdefine rstkm [rsp + stack_size]
+%endif
+    RET
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 32
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 181
+    add                 rsp, (65+4*ARCH_X86_64)*16
+    jmp m(inv_txfm_add_dct_dct_16x4_16bpc).dconly
+
+cglobal inv_txfm_add_dct_dct_32x8_16bpc, 4, 7, 16, 0-(24+8*ARCH_X86_32)*16, \
+                                         dst, stride, c, eob
+%if ARCH_X86_32
+    LEA                  r6, $$
+%endif
+    test               eobd, eobd
+    jz .dconly
+
+    ; remove entirely-zero iterations
+%undef cmp
+%if ARCH_X86_64
+    xor                 r5d, r5d
+    cmp                eobd, 10
+    setge               r5b
+%else
+    mov                 r5d, 1
+    cmp                eobd, 10
+    sbb                 r5d, 0
+%endif
+    add                 r5d, r5d
+
+    ; actual first pass after skipping all-zero data
+.loop_pass1:
+    mova                 m0, [cq+32* 1+r5*8]
+    mova                 m1, [cq+32* 7+r5*8]
+    mova                 m2, [cq+32* 9+r5*8]
+    mova                 m3, [cq+32*15+r5*8]
+    mova                 m4, [cq+32*17+r5*8]
+    mova                 m5, [cq+32*23+r5*8]
+    mova                 m6, [cq+32*25+r5*8]
+    mova                 m7, [cq+32*31+r5*8]
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mov                  r3, rsp
+    call .main_oddhalf_part1
+    mova                 m0, [cq+32* 3+r5*8]
+    mova                 m1, [cq+32* 5+r5*8]
+    mova                 m2, [cq+32*11+r5*8]
+    mova                 m3, [cq+32*13+r5*8]
+    mova                 m4, [cq+32*19+r5*8]
+    mova                 m5, [cq+32*21+r5*8]
+    mova                 m6, [cq+32*27+r5*8]
+    mova                 m7, [cq+32*29+r5*8]
+    call .main_oddhalf_part2
+    mova                 m0, [cq+32* 2+r5*8]
+    mova                 m1, [cq+32* 6+r5*8]
+    mova                 m2, [cq+32*10+r5*8]
+    mova                 m3, [cq+32*14+r5*8]
+    mova                 m4, [cq+32*18+r5*8]
+    mova                 m5, [cq+32*22+r5*8]
+    mova                 m6, [cq+32*26+r5*8]
+    mova                 m7, [cq+32*30+r5*8]
+    add                  r3, 16*(16+4*ARCH_X86_32)
+    call m(idct_16x4_internal_16bpc).main_oddhalf
+    mova                 m0, [cq+32* 0+r5*8]
+    mova                 m1, [cq+32* 4+r5*8]
+    mova                 m2, [cq+32* 8+r5*8]
+    mova                 m3, [cq+32*12+r5*8]
+    mova                 m4, [cq+32*16+r5*8]
+    mova                 m5, [cq+32*20+r5*8]
+    mova                 m6, [cq+32*24+r5*8]
+    mova                 m7, [cq+32*28+r5*8]
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    sub                  r3, 16*(16+4*ARCH_X86_32)
+    call .round_dct32
+%if ARCH_X86_64
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova    [cq+32* 8+r5*8], m8
+    mova    [cq+32* 9+r5*8], m9
+    mova    [cq+32*10+r5*8], m10
+    mova    [cq+32*11+r5*8], m11
+    mova                 m8, [r3+16* 9] ;  8  9
+    mova                m10, [r3+16*11] ; 10 11
+    mova                m12, [r3+16*13] ; 12 13
+    mova                m14, [r3+16*15] ; 14 15
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova    [cq+32* 4+r5*8], m8
+    mova    [cq+32* 5+r5*8], m9
+    mova    [cq+32* 6+r5*8], m10
+    mova    [cq+32* 7+r5*8], m11
+    mova                 m8, [r3+16* 8] ; 24 25
+    mova                m10, [r3+16*10] ; 26 27
+    mova                m12, [r3+16*12] ; 28 29
+    mova                m14, [r3+16*14] ; 30 31
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova    [cq+32*12+r5*8], m8
+    mova    [cq+32*13+r5*8], m9
+    mova    [cq+32*14+r5*8], m10
+    mova    [cq+32*15+r5*8], m11
+%else
+    sub                  r3, 8*16
+    mova                 m0, [r3+ 8*16]
+    mova                 m2, [r3+10*16]
+    mova                 m4, [r3+12*16]
+    mova                 m6, [r3+14*16]
+    packssdw             m0, [r3+ 9*16]
+    packssdw             m2, [r3+11*16]
+    packssdw             m4, [r3+13*16]
+    packssdw             m6, [r3+15*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova    [cq+32* 4+r5*8], m0
+    mova    [cq+32* 5+r5*8], m1
+    mova    [cq+32* 6+r5*8], m2
+    mova    [cq+32* 7+r5*8], m3
+    mova                 m0, [r3+16*16]
+    mova                 m2, [r3+18*16]
+    mova                 m4, [r3+20*16]
+    mova                 m6, [r3+22*16]
+    packssdw             m0, [r3+17*16]
+    packssdw             m2, [r3+19*16]
+    packssdw             m4, [r3+21*16]
+    packssdw             m6, [r3+23*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova    [cq+32* 8+r5*8], m0
+    mova    [cq+32* 9+r5*8], m1
+    mova    [cq+32*10+r5*8], m2
+    mova    [cq+32*11+r5*8], m3
+    mova                 m0, [r3+31*16]
+    mova                 m2, [r3+29*16]
+    mova                 m4, [r3+27*16]
+    mova                 m6, [r3+25*16]
+    packssdw             m0, [r3+30*16]
+    packssdw             m2, [r3+28*16]
+    packssdw             m4, [r3+26*16]
+    packssdw             m6, [r3+24*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova    [cq+32*12+r5*8], m0
+    mova    [cq+32*13+r5*8], m1
+    mova    [cq+32*14+r5*8], m2
+    mova    [cq+32*15+r5*8], m3
+    mova                 m0, [r3+ 0*16]
+    mova                 m2, [r3+ 2*16]
+    mova                 m4, [r3+ 4*16]
+    mova                 m6, [r3+ 6*16]
+    packssdw             m0, [r3+ 1*16]
+    packssdw             m2, [r3+ 3*16]
+    packssdw             m4, [r3+ 5*16]
+    packssdw             m6, [r3+ 7*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+%endif
+    pxor                 m7, m7
+    ; clear lower half of [cq]
+    REPX {mova [cq+x*32+r5*8], m7}, 16, 17, 18, 19, 20, 21, 22, 23, \
+                                    24, 25, 26, 27, 28, 29, 30, 31
+    test                r5d, r5d
+    jz .end_pass1
+    mova    [cq+32* 0+r5*8], m0
+    mova    [cq+32* 1+r5*8], m1
+    mova    [cq+32* 2+r5*8], m2
+    mova    [cq+32* 3+r5*8], m3
+    sub                 r5d, 2
+    jmp .loop_pass1
+.end_pass1:
+
+    ; pass=2, we need to call this otherwise the stack pointer has
+    ; the wrong offset in the 8-bit code
+    mov                 r4d, 4
+    call m(idct_16x8_internal_16bpc).pass2_main
+    RET
+
+.main_oddhalf_part1_fast: ; lower half zero
+    pmulld               m7, m0, [o(pd_4091)]
+    pmulld               m0, [o(pd_201)]
+    pmulld               m4, m3, [o(pd_m2751)]
+%if ARCH_X86_32
+    pmulld               m3, [o(pd_3035)]
+    mova                 m5, [o(pd_2048)]
+    REPX      {paddd x, m5}, m0, m7
+    REPX      {psrad x, 12}, m0, m7
+    mova          [r3+3*16], m7
+    mova                 m7, m3
+    mova                 m3, m5
+%else
+    pmulld               m3, [o(pd_3035)]
+%endif
+    pmulld               m6, m1, [o(pd_m1380)]
+    pmulld               m1, [o(pd_3857)]
+    pmulld               m5, m2, [o(pd_3703)]
+    pmulld               m2, [o(pd_1751)]
+    jmp .main_oddhalf_part1_fast2
+.main_oddhalf_part1: ; in1, in7, in9, in15, in17, in23, in25, in31
+%if ARCH_X86_64
+    ITX_MULSUB_2D         0, 7, 8, 9, 10, _,  201, 4091 ; t16a, t31a
+    ITX_MULSUB_2D         6, 1, 8, 9, 10, _, 3857, 1380 ; t19a, t28a
+    ITX_MULSUB_2D         2, 5, 8, 9, 10, _, 1751, 3703 ; t18a, t29a
+    ITX_MULSUB_2D         4, 3, 8, 9, 10, _, 3035, 2751 ; t17a, t30a
+.main_oddhalf_part1_fast2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+    psubd                m8, m0, m4 ; t17
+    paddd                m0, m4     ; t16
+    psubd                m4, m6, m2 ; t18
+    paddd                m6, m2     ; t19
+    psubd                m2, m1, m5 ; t29
+    paddd                m1, m5     ; t28
+    psubd                m5, m7, m3 ; t30
+    paddd                m7, m3     ; t31
+    REPX    {pmaxsd x, m12}, m8, m5, m4, m2, m0, m6, m1, m7
+    REPX    {pminsd x, m13}, m8, m5, m4, m2, m0, m6, m1, m7
+    mova                m15, [o(pd_4017)]
+    mova                m10, [o(pd_799)]
+    ITX_MULSUB_2D         5, 8, 3, 9, _, 11, 10, 15    ; t17a, t30a
+    ITX_MULSUB_2D         2, 4, 3, 9, _, 11, 10, 15, 4 ; t29a, t18a
+    psubd                m3, m0, m6 ; t19a
+    paddd                m0, m6     ; t16a
+    psubd                m6, m7, m1 ; t28a
+    paddd                m7, m1     ; t31a
+    psubd                m1, m5, m4 ; t18
+    paddd                m5, m4     ; t17
+    psubd                m4, m8, m2 ; t29
+    paddd                m8, m2     ; t30
+    REPX    {pmaxsd x, m12}, m3, m6, m1, m4, m0, m7, m5, m8
+    REPX    {pminsd x, m13}, m3, m6, m1, m4, m0, m7, m5, m8
+    mova                m15, [o(pd_3784)]
+    mova                m10, [o(pd_1567)]
+    ITX_MULSUB_2D         4, 1, 2, 9, _, 11, 10, 15 ; t18a, t29a
+    ITX_MULSUB_2D         6, 3, 2, 9, _, 11, 10, 15 ; t19,  t28
+    mova          [r3+16*0], m0
+    mova          [r3+16*1], m5
+    mova          [r3+16*2], m4
+    mova          [r3+16*3], m6
+    mova          [r3+16*4], m3
+    mova          [r3+16*5], m1
+    mova          [r3+16*6], m8
+    mova          [r3+16*7], m7
+%else
+    mova          [r3+0*16], m2
+    mova          [r3+1*16], m3
+    mova          [r3+2*16], m4
+    mova          [r3+3*16], m5
+    mova                  m3, [o(pd_2048)]
+    ITX_MULSUB_2D         0, 7, 2, 4, 5, 3,  201, 4091 ; t16a, t31a
+    ITX_MULSUB_2D         6, 1, 2, 4, 5, _, 3857, 1380 ; t19a, t28a
+    mova                 m4, [r3+2*16]
+    mova                 m5, [r3+3*16]
+    mova          [r3+2*16], m6
+    mova          [r3+3*16], m7
+    mova                 m2, [r3+0*16]
+    mova                 m7, [r3+1*16]
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m1
+    ITX_MULSUB_2D         2, 5, 0, 1, 6, _, 1751, 3703 ; t18a, t29a
+    ITX_MULSUB_2D         4, 7, 0, 1, 6, _, 3035, 2751 ; t17a, t30a
+    mova                 m0, [r3+0*16]
+    mova                 m1, [r3+1*16]
+    mova                 m6, [r3+2*16]
+.main_oddhalf_part1_fast2:
+    REPX      {paddd x, m3}, m1, m2, m4, m5, m6, m7
+    REPX      {psrad x, 12}, m1, m2, m4, m5, m6, m7
+    psubd                m3, m0, m4 ; t17
+    mova          [r3+0*16], m3
+    mova                 m3, [r3+3*16]
+    paddd                m0, m4     ; t16
+    psubd                m4, m6, m2 ; t18
+    paddd                m6, m2     ; t19
+    psubd                m2, m1, m5 ; t29
+    paddd                m1, m5     ; t28
+    psubd                m5, m3, m7 ; t30
+    paddd                m7, m3     ; t31
+    mova                 m3, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m3}, m5, m4, m2, m0, m6, m1, m7
+    pmaxsd               m3, [r3+0*16]
+    mova          [r3+0*16], m3
+    mova                 m3, [o(clip_18b_max)]
+    REPX     {pminsd x, m3}, m5, m4, m2, m0, m6, m1, m7
+    pminsd               m3, [r3+0*16]
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m1
+    mova          [r3+2*16], m6
+    mova          [r3+3*16], m7
+    mova                 m0, [o(pd_2048)]
+    ITX_MULSUB_2D         5, 3, 1, 6, 7, 0,  799, 4017    ; t17a, t30a
+    ITX_MULSUB_2D         2, 4, 1, 6, _, 0,    7, 4017, 4 ; t29a, t18a
+    psubd                m1, m5, m4 ; t18
+    paddd                m5, m4     ; t17
+    psubd                m4, m3, m2 ; t29
+    paddd                m3, m2     ; t30
+    mova                 m0, [r3+0*16]
+    mova                 m2, [r3+1*16]
+    mova                 m6, [r3+2*16]
+    mova                 m7, [r3+3*16]
+    mova          [r3+0*16], m3
+    psubd                m3, m0, m6 ; t19a
+    paddd                m0, m6     ; t16a
+    psubd                m6, m7, m2 ; t28a
+    paddd                m7, m2     ; t31a
+    mova                 m2, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m2}, m3, m6, m1, m4, m0, m7, m5
+    pmaxsd               m2, [r3+0*16]
+    mova          [r3+0*16], m2
+    mova                 m2, [o(clip_18b_max)]
+    REPX     {pminsd x, m2}, m3, m6, m1, m4, m0, m7, m5
+    pminsd               m2, [r3+0*16]
+    mova          [r3+16*0], m0
+    mova          [r3+16*1], m5
+    mova          [r3+16*6], m2
+    mova          [r3+16*7], m7
+    mova                 m7, [o(pd_2048)]
+    ITX_MULSUB_2D         4, 1, 0, 5, 2, 7, 1567, 3784 ; t18a, t29a
+    ITX_MULSUB_2D         6, 3, 0, 5, 2, 7,    2, 3784 ; t19,  t28
+    mova          [r3+16*2], m4
+    mova          [r3+16*3], m6
+    mova          [r3+16*4], m3
+    mova          [r3+16*5], m1
+%endif
+    ret
+.main_oddhalf_part2_fast: ; lower half zero
+    pmulld               m7, m0, [o(pd_m601)]
+    pmulld               m0, [o(pd_4052)]
+    pmulld               m4, m3, [o(pd_3290)]
+%if ARCH_X86_32
+    pmulld               m3, [o(pd_2440)]
+    mova                 m5, [o(pd_2048)]
+    REPX      {paddd x, m5}, m0, m7
+    REPX      {psrad x, 12}, m0, m7
+    mova         [r3+11*16], m7
+    mova                 m7, m3
+    mova                 m3, m5
+%else
+    pmulld               m3, [o(pd_2440)]
+%endif
+    pmulld               m6, m1, [o(pd_3973)]
+    pmulld               m1, [o(pd_995)]
+    pmulld               m5, m2, [o(pd_m2106)]
+    pmulld               m2, [o(pd_3513)]
+    jmp .main_oddhalf_part2_fast2
+.main_oddhalf_part2: ; in3, in5, in11, in13, in19, in21, in27, in29
+%if ARCH_X86_64
+    ITX_MULSUB_2D         7, 0, 8, 9, 10, _, 4052,  601 ; t23a, t24a
+    ITX_MULSUB_2D         1, 6, 8, 9, 10, _,  995, 3973 ; t20a, t27a
+    ITX_MULSUB_2D         5, 2, 8, 9, 10, _, 3513, 2106 ; t21a, t26a
+    ITX_MULSUB_2D         3, 4, 8, 9, 10, _, 2440, 3290 ; t22a, t25a
+.main_oddhalf_part2_fast2:
+    REPX     {paddd x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX     {psrad x, 12 }, m0, m1, m2, m3, m4, m5, m6, m7
+    psubd                m8, m0, m4 ; t25
+    paddd                m0, m4     ; t24
+    psubd                m4, m6, m2 ; t26
+    paddd                m6, m2     ; t27
+    psubd                m2, m1, m5 ; t21
+    paddd                m1, m5     ; t20
+    psubd                m5, m7, m3 ; t22
+    paddd                m7, m3     ; t23
+    REPX    {pmaxsd x, m12}, m8, m5, m4, m2, m0, m6, m1, m7
+    REPX    {pminsd x, m13}, m8, m5, m4, m2, m0, m6, m1, m7
+    mova                m15, [o(pd_2276)]
+    mova                m10, [o(pd_3406)]
+    ITX_MULSUB_2D         4, 2, 3, 9, _, 11, 10, 15    ; t21a, t26a
+    ITX_MULSUB_2D         8, 5, 3, 9, _, 11, 10, 15, 4 ; t25a, t22a
+    psubd                m3, m0, m6 ; t27a
+    paddd                m0, m6     ; t24a
+    psubd                m6, m7, m1 ; t20a
+    paddd                m7, m1     ; t23a
+    psubd                m1, m5, m4 ; t21
+    paddd                m5, m4     ; t22
+    psubd                m4, m8, m2 ; t26
+    paddd                m8, m2     ; t25
+    REPX    {pmaxsd x, m12}, m3, m6, m1, m4, m0, m7, m5, m8
+    REPX    {pminsd x, m13}, m3, m6, m1, m4, m0, m7, m5, m8
+    mova                m15, [o(pd_3784)]
+    mova                m10, [o(pd_1567)]
+    ITX_MULSUB_2D         4, 1, 2, 9, _, 11, 10, 15, 4 ; t26a, t21a
+    ITX_MULSUB_2D         3, 6, 2, 9, _, 11, 10, 15, 4 ; t27,  t20
+    mova                 m9, [r3+16*0] ; t16a
+    mova                m10, [r3+16*1] ; t17
+    psubd                m2, m9, m7    ; t23
+    paddd                m9, m7        ; t16
+    psubd                m7, m10, m5   ; t22a
+    paddd               m10, m5        ; t17a
+    REPX    {pmaxsd x, m12}, m9, m10, m2, m7
+    REPX    {pminsd x, m13}, m9, m10, m2, m7
+    mova          [r3+16*0], m9
+    mova          [r3+16*1], m10
+    mova                 m9, [r3+16*2] ; t18a
+    mova                m10, [r3+16*3] ; t19
+    psubd                m5, m9, m1    ; t21
+    paddd                m9, m1        ; t18
+    psubd                m1, m10, m6   ; t20a
+    paddd               m10, m6        ; t19a
+    REPX    {pmaxsd x, m12}, m9, m10, m5, m1
+    REPX    {pminsd x, m13}, m9, m10, m5, m1
+    mova          [r3+16*2], m9
+    mova          [r3+16*3], m10
+    mova                 m9, [r3+16*4] ; t28
+    mova                m10, [r3+16*5] ; t29a
+    psubd                m6, m9, m3    ; t27a
+    paddd                m9, m3        ; t28a
+    psubd                m3, m10, m4   ; t26
+    paddd               m10, m4        ; t29
+    REPX    {pmaxsd x, m12}, m9, m10, m6, m3
+    REPX    {pminsd x, m13}, m9, m10, m6, m3
+    REPX    {pmulld x, m14}, m6, m3, m1, m5
+    paddd                m6, m11
+    paddd                m3, m11
+    psubd                m4, m6, m1    ; t20
+    paddd                m6, m1        ; t27
+    psubd                m1, m3, m5    ; t21a
+    paddd                m3, m5        ; t26a
+    REPX    {psrad  x, 12 }, m4, m1, m3, m6
+    mova          [r3+16*4], m4
+    mova          [r3+16*5], m1
+    mova                 m4, [r3+16*6] ; t30
+    mova                 m1, [r3+16*7] ; t31a
+    psubd                m5, m4, m8    ; t25a
+    paddd                m4, m8        ; t30a
+    psubd                m8, m1, m0    ; t24
+    paddd                m1, m0        ; t31
+    REPX    {pmaxsd x, m12}, m8, m5, m4, m1
+    REPX    {pminsd x, m13}, m8, m5, m4, m1
+    REPX    {pmulld x, m14}, m5, m8, m7, m2
+    paddd                m5, m11
+    paddd                m8, m11
+    psubd                m0, m5, m7    ; t22
+    paddd                m5, m7        ; t25
+    psubd                m7, m8, m2    ; t23a
+    paddd                m2, m8        ; t24a
+    REPX    {psrad  x, 12 }, m0, m7, m2, m5
+    mova          [r3+16*6], m0
+    mova          [r3+16*7], m7
+    mova          [r3+16*8], m2
+    mova          [r3+16*9], m5
+    mova         [r3+16*10], m3
+    mova         [r3+16*11], m6
+    mova         [r3+16*12], m9
+    mova         [r3+16*13], m10
+    mova         [r3+16*14], m4
+    mova         [r3+16*15], m1
+%else
+    mova         [r3+ 8*16], m2
+    mova         [r3+ 9*16], m3
+    mova         [r3+10*16], m4
+    mova         [r3+11*16], m5
+    mova                 m3, [o(pd_2048)]
+    ITX_MULSUB_2D         7, 0, 2, 4, 5, 3, 4052,  601 ; t23a, t24a
+    ITX_MULSUB_2D         1, 6, 2, 4, 5, _,  995, 3973 ; t20a, t27a
+    mova                 m2, [r3+ 8*16]
+    mova                 m4, [r3+10*16]
+    mova                 m5, [r3+11*16]
+    mova         [r3+ 8*16], m0
+    mova         [r3+10*16], m6
+    mova         [r3+11*16], m7
+    mova                 m7, [r3+ 9*16]
+    mova         [r3+ 9*16], m1
+    ITX_MULSUB_2D         5, 2, 0, 6, 1, _, 3513, 2106 ; t21a, t26a
+    ITX_MULSUB_2D         7, 4, 0, 6, 1, _, 2440, 3290 ; t22a, t25a
+    mova                 m0, [r3+ 8*16]
+    mova                 m1, [r3+ 9*16]
+    mova                 m6, [r3+10*16]
+.main_oddhalf_part2_fast2:
+    REPX      {paddd x, m3}, m1, m2, m7, m4, m5, m6
+    REPX      {psrad x, 12}, m1, m2, m7, m4, m5, m6
+    psubd                m3, m0, m4 ; t25
+    mova         [r3+ 8*16], m3
+    mova                 m3, [r3+11*16]
+    paddd                m0, m4     ; t24
+    psubd                m4, m6, m2 ; t26
+    paddd                m6, m2     ; t27
+    psubd                m2, m1, m5 ; t21
+    paddd                m1, m5     ; t20
+    psubd                m5, m3, m7 ; t22
+    paddd                m7, m3     ; t23
+    mova                 m3, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m3}, m5, m4, m2, m0, m6, m1, m7
+    pmaxsd               m3, [r3+ 8*16]
+    mova         [r3+ 8*16], m3
+    mova                 m3, [o(clip_18b_max)]
+    REPX     {pminsd x, m3}, m5, m4, m2, m0, m6, m1, m7
+    pminsd               m3, [r3+ 8*16]
+    mova         [r3+ 8*16], m0
+    mova         [r3+ 9*16], m1
+    mova         [r3+10*16], m6
+    mova         [r3+11*16], m7
+    mova                 m7, [o(pd_2048)]
+    ITX_MULSUB_2D         4, 2, 0, 1, 6, 7, 3406, 2276    ; t21a, t26a
+    ITX_MULSUB_2D         3, 5, 0, 1, _, 7,    6, 2276, 4 ; t25a, t22a
+    psubd                m1, m5, m4 ; t21
+    paddd                m5, m4     ; t22
+    psubd                m4, m3, m2 ; t26
+    paddd                m3, m2     ; t25
+    mova                 m0, [r3+ 8*16]
+    mova                 m2, [r3+ 9*16]
+    mova                 m6, [r3+10*16]
+    mova                 m7, [r3+11*16]
+    mova         [r3+ 8*16], m3
+    psubd                m3, m0, m6 ; t27a
+    paddd                m0, m6     ; t24a
+    psubd                m6, m7, m2 ; t20a
+    paddd                m7, m2     ; t23a
+    mova                 m2, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m2}, m3, m6, m1, m4, m0, m7, m5
+    pmaxsd               m2, [r3+ 8*16]
+    mova         [r3+ 8*16], m2
+    mova                 m2, [o(clip_18b_max)]
+    REPX     {pminsd x, m2}, m3, m6, m1, m4, m0, m7, m5
+    pminsd               m2, [r3+ 8*16]
+    mova         [r3+ 8*16], m0
+    mova         [r3+ 9*16], m2
+    mova         [r3+14*16], m5
+    mova         [r3+15*16], m7
+    mova                 m0, [o(pd_2048)]
+    ITX_MULSUB_2D         4, 1, 2, 5, 7, 0, 1567, 3784, 4 ; t26a, t21a
+    ITX_MULSUB_2D         3, 6, 2, 5, _, 0,    7, 3784, 4 ; t27,  t20
+    mova         [r3+10*16], m3
+    mova                 m0, [o(clip_18b_min)]
+    mova                 m2, [o(clip_18b_max)]
+    mova                 m5, [r3+16*2] ; t18a
+    mova                 m7, [r3+16*3] ; t19
+    psubd                m3, m5, m1    ; t21
+    paddd                m5, m1        ; t18
+    psubd                m1, m7, m6    ; t20a
+    paddd                m7, m6        ; t19a
+    REPX     {pmaxsd x, m0}, m5, m7, m3, m1
+    REPX     {pminsd x, m2}, m5, m7, m3, m1
+    mova          [r3+16*2], m5
+    mova          [r3+16*3], m7
+    mova         [r3+11*16], m3
+    mova                 m3, [r3+10*16]
+    mova                 m5, [r3+16*4] ; t28
+    mova                 m7, [r3+16*5] ; t29a
+    psubd                m6, m5, m3    ; t27a
+    paddd                m5, m3        ; t28a
+    psubd                m3, m7, m4    ; t26
+    paddd                m7, m4        ; t29
+    REPX     {pmaxsd x, m0}, m5, m7, m6, m3
+    REPX     {pminsd x, m2}, m5, m7, m6, m3
+    mova         [r3+16*12], m5
+    mova         [r3+16*13], m7
+    mova                 m5, [o(pd_2048)]
+    mova                 m7, [o(pd_2896)]
+    mova                 m4, [r3+11*16]
+    REPX     {pmulld x, m7}, m6, m3, m1, m4
+    paddd                m6, m5
+    paddd                m3, m5
+    psubd                m5, m6, m1    ; t20
+    paddd                m6, m1        ; t27
+    psubd                m1, m3, m4    ; t21a
+    paddd                m3, m4        ; t26a
+    REPX     {psrad  x, 12}, m5, m1, m3, m6
+    mova          [r3+16*4], m5
+    mova          [r3+16*5], m1
+    mova         [r3+16*10], m3
+    mova         [r3+16*11], m6
+
+    mova                 m5, [r3+14*16]
+    mova                 m6, [r3+15*16]
+    mova                 m3, [r3+16*0] ; t16a
+    mova                 m4, [r3+16*1] ; t17
+    psubd                m1, m3, m6    ; t23
+    paddd                m3, m6        ; t16
+    psubd                m6, m4, m5    ; t22a
+    paddd                m4, m5        ; t17a
+    REPX     {pmaxsd x, m0}, m3, m4, m1, m6
+    REPX     {pminsd x, m2}, m3, m4, m1, m6
+    mova          [r3+16*0], m3
+    mova          [r3+16*1], m4
+    mova                 m5, [r3+ 8*16]
+    mova                 m3, [r3+ 9*16]
+    mova         [r3+ 8*16], m1
+    mova         [r3+ 9*16], m6
+    mova                 m4, [r3+16*6] ; t30
+    mova                 m1, [r3+16*7] ; t31a
+    psubd                m6, m1, m5    ; t24
+    paddd                m1, m5        ; t31
+    psubd                m5, m4, m3    ; t25a
+    paddd                m4, m3        ; t30a
+    REPX     {pmaxsd x, m0}, m6, m5, m4, m1
+    REPX     {pminsd x, m2}, m6, m5, m4, m1
+    mova         [r3+16*14], m4
+    mova         [r3+16*15], m1
+    mova                 m4, [o(pd_2048)]
+    mova                 m1, [r3+ 9*16]
+    mova                 m2, [r3+ 8*16]
+    REPX     {pmulld x, m7}, m5, m6, m1, m2
+    paddd                m5, m4
+    paddd                m6, m4
+    psubd                m0, m5, m1    ; t22
+    paddd                m5, m1        ; t25
+    psubd                m1, m6, m2    ; t23a
+    paddd                m2, m6        ; t24a
+    REPX     {psrad  x, 12}, m0, m1, m2, m5
+    mova          [r3+16*6], m0
+    mova          [r3+16*7], m1
+    mova          [r3+16*8], m2
+    mova          [r3+16*9], m5
+%endif
+    ret
+
+    ; final sumsub for idct16 as well as idct32, plus final downshift
+%macro IDCT32_END 6 ; in/out1, out2-4, tmp, shift, idx
+    mova                m%4, [r3+16*(23-%1)]
+    pmaxsd              m%1, m12
+    pminsd              m%1, m13
+    psubd               m%3, m%1, m%4 ; idct16 out15 - n
+    paddd               m%1, m%4      ; idct16 out0  + n
+    pmaxsd              m%1, m12
+    pmaxsd              m%3, m12
+    pminsd              m%1, m13
+    pminsd              m%3, m13
+    paddd               m%1, m11
+    paddd               m%3, m11
+    mova                m%5, [r3+16*( 0+%1)]
+    mova                m%2, [r3+16*(15-%1)]
+    psubd               m%4, m%1, m%2 ; out31 - n
+    paddd               m%1, m%2      ; out0  + n
+    paddd               m%2, m%3, m%5 ; out15 - n
+    psubd               m%3, m%5      ; out16 + n
+    REPX      {psrad x, %6}, m%1, m%3, m%2, m%4
+%endmacro
+
+.round_dct32:
+%if ARCH_X86_64
+    psrld               m11, 10 ; pd_2
+    IDCT32_END            0, 15, 8, 9, 10, 2    ; 0 15 16 31
+    mova         [r3+ 0*16], m6
+    mova         [r3+23*16], m7
+    IDCT32_END            1, 14, 6, 7, 10, 2    ; 1 14 17 30
+    packssdw             m0, m1       ;  0  1
+    packssdw            m14, m15      ; 14 15
+    packssdw             m8, m6       ; 16 17
+    packssdw             m7, m9       ; 30 31
+    mova         [r3+16*15], m14
+    mova         [r3+16*14], m7
+    IDCT32_END            2, 15, 10, 7, 6, 2    ; 2 13 18 29
+    IDCT32_END            3, 14,  1, 9, 6, 2    ; 3 12 19 28
+    packssdw             m2, m3       ;  2  3
+    packssdw            m14, m15      ; 12 13
+    packssdw            m10, m1       ; 18 19
+    packssdw             m9, m7       ; 28 29
+    mova         [r3+16*13], m14
+    mova         [r3+16*12], m9
+    IDCT32_END            4, 15, 1, 7, 6, 2     ; 4 11 20 27
+    IDCT32_END            5, 14, 3, 9, 6, 2     ; 5 10 21 26
+    packssdw             m4, m5       ;  4  5
+    packssdw            m14, m15      ; 10 11
+    packssdw             m1, m3       ; 20 21
+    packssdw             m9, m7       ; 26 27
+    mova         [r3+16*11], m14
+    mova         [r3+16*10], m9
+    mova                 m6, [r3+ 0*16]
+    mova                 m7, [r3+23*16]
+    IDCT32_END            6, 15, 14, 5,  3, 2   ; 6 9 22 25
+    IDCT32_END            7, 11,  3, 9, 13, 2   ; 7 8 23 24
+    packssdw             m6, m7       ;  6  7
+    packssdw            m11, m15      ;  8  9
+    packssdw            m14, m3       ; 22 23
+    packssdw             m9, m5       ; 24 25
+    mova          [r3+16*9], m11
+    mova          [r3+16*8], m9
+    mova                m12, m1
+    ret
+%else
+    mova         [r3+16*16], m0
+    mova         [r3+17*16], m1
+    mova         [r3+18*16], m2
+    mova         [r3+19*16], m3
+    mova         [r3+20*16], m4
+    mova         [r3+21*16], m5
+    mova         [r3+22*16], m6
+    mova         [r3+23*16], m7
+    mova                 m1, [o(pd_2)]
+    mova                 m2, [o(clip_18b_min)]
+    mova                 m3, [o(clip_18b_max)]
+
+    mov                  r4, 15*16
+.loop_dct32_end:
+    mova                 m0, [r3+16*16]
+    mova                 m6, [r3+16*24]
+    pmaxsd               m0, m2
+    pminsd               m0, m3
+    psubd                m5, m0, m6 ; idct16 out15 - n
+    paddd                m0, m6     ; idct16 out0  + n
+    pmaxsd               m0, m2
+    pmaxsd               m5, m2
+    pminsd               m0, m3
+    pminsd               m5, m3
+    paddd                m0, m1
+    paddd                m5, m1
+    mova                 m7, [r3]
+    mova                 m4, [r3+r4]
+    psubd                m6, m0, m4 ; out31 - n
+    paddd                m0, m4     ; out0  + n
+    paddd                m4, m5, m7 ; out15 - n
+    psubd                m5, m7     ; out16 + n
+    REPX       {psrad x, 2}, m0, m5, m4, m6
+    mova               [r3], m0
+    mova            [r3+r4], m4
+    mova         [r3+16*16], m5
+    mova         [r3+24*16], m6
+    add                  r3, 16
+    sub                  r4, 32
+    jg .loop_dct32_end
+    ret
+%endif
+
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 8
+.dconly1:
+    add                 r5d, 640
+    sar                 r5d, 10
+.dconly2:
+    imul                r5d, 2896
+    add                 r5d, 34816
+    movd                 m0, r5d
+    pshuflw              m0, m0, q1111
+    punpcklqdq           m0, m0
+    mova                 m6, [o(pixel_10bpc_max)]
+    pxor                 m5, m5
+.dconly_loop:
+    mova                 m1, [dstq+16*0]
+    mova                 m2, [dstq+16*1]
+    mova                 m3, [dstq+16*2]
+    mova                 m4, [dstq+16*3]
+    REPX     {paddw  x, m0}, m1, m2, m3, m4
+    REPX     {pminsw x, m6}, m1, m2, m3, m4
+    REPX     {pmaxsw x, m5}, m1, m2, m3, m4
+    mova        [dstq+16*0], m1
+    mova        [dstq+16*1], m2
+    mova        [dstq+16*2], m3
+    mova        [dstq+16*3], m4
+    add                dstq, strideq
+    dec                 r3d
+    jg .dconly_loop
+    RET
+
+cglobal inv_txfm_add_dct_dct_32x16_16bpc, 4, 7, 16, 0-(24+8*ARCH_X86_32)*16, \
+                                         dst, stride, c, eob
+    LEA                  r6, base
+    test               eobd, eobd
+    jz .dconly
+
+    ; remove entirely-zero iterations
+%undef cmp
+    mov                 r5d, 8
+.zero_loop:
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_32x16_2d)+r5]
+    jl .zero_loop
+
+    ; actual first pass after skipping all-zero data
+.loop_pass1:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+64* 1+r5*8]
+    mova                 m1, [cq+64* 7+r5*8]
+    mova                 m2, [cq+64* 9+r5*8]
+    mova                 m3, [cq+64*15+r5*8]
+    mova                 m4, [cq+64*17+r5*8]
+    mova                 m5, [cq+64*23+r5*8]
+    mova                 m6, [cq+64*25+r5*8]
+    mova                 m7, [cq+64*31+r5*8]
+    mov                  r3, rsp
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part1
+
+    mova                 m0, [cq+64* 3+r5*8]
+    mova                 m1, [cq+64* 5+r5*8]
+    mova                 m2, [cq+64*11+r5*8]
+    mova                 m3, [cq+64*13+r5*8]
+    mova                 m4, [cq+64*19+r5*8]
+    mova                 m5, [cq+64*21+r5*8]
+    mova                 m6, [cq+64*27+r5*8]
+    mova                 m7, [cq+64*29+r5*8]
+%if ARCH_X86_32
+    add                  r3, 16*8
+%endif
+    call m(idct_8x4_internal_16bpc).rect2_mul
+%if ARCH_X86_32
+    sub                  r3, 16*8
+%endif
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part2
+    add                  r3, 16*(16+4*ARCH_X86_32)
+
+    mova                 m0, [cq+64* 2+r5*8]
+    mova                 m1, [cq+64* 6+r5*8]
+    mova                 m2, [cq+64*10+r5*8]
+    mova                 m3, [cq+64*14+r5*8]
+    mova                 m4, [cq+64*18+r5*8]
+    mova                 m5, [cq+64*22+r5*8]
+    mova                 m6, [cq+64*26+r5*8]
+    mova                 m7, [cq+64*30+r5*8]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(idct_16x4_internal_16bpc).main_oddhalf
+
+    mova                 m0, [cq+64* 0+r5*8]
+    mova                 m1, [cq+64* 4+r5*8]
+    mova                 m2, [cq+64* 8+r5*8]
+    mova                 m3, [cq+64*12+r5*8]
+    mova                 m4, [cq+64*16+r5*8]
+    mova                 m5, [cq+64*20+r5*8]
+    mova                 m6, [cq+64*24+r5*8]
+    mova                 m7, [cq+64*28+r5*8]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    sub                  r3, 16*(16+4*ARCH_X86_32)
+    call .round_dct32
+
+%if ARCH_X86_64
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova    [cq+64* 8+r5*8], m8
+    mova    [cq+64* 9+r5*8], m9
+    mova    [cq+64*10+r5*8], m10
+    mova    [cq+64*11+r5*8], m11
+    mova                 m8, [r3+16* 9] ;  8  9
+    mova                m10, [r3+16*11] ; 10 11
+    mova                m12, [r3+16*13] ; 12 13
+    mova                m14, [r3+16*15] ; 14 15
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova    [cq+64* 4+r5*8], m8
+    mova    [cq+64* 5+r5*8], m9
+    mova    [cq+64* 6+r5*8], m10
+    mova    [cq+64* 7+r5*8], m11
+    mova                 m8, [r3+16* 8] ; 24 25
+    mova                m10, [r3+16*10] ; 26 27
+    mova                m12, [r3+16*12] ; 28 29
+    mova                m14, [r3+16*14] ; 30 31
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova    [cq+64*12+r5*8], m8
+    mova    [cq+64*13+r5*8], m9
+    mova    [cq+64*14+r5*8], m10
+    mova    [cq+64*15+r5*8], m11
+%else
+    sub                  r3, 8*16
+    mova                 m0, [r3+ 8*16]
+    mova                 m2, [r3+10*16]
+    mova                 m4, [r3+12*16]
+    mova                 m6, [r3+14*16]
+    packssdw             m0, [r3+ 9*16]
+    packssdw             m2, [r3+11*16]
+    packssdw             m4, [r3+13*16]
+    packssdw             m6, [r3+15*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova    [cq+64* 4+r5*8], m0
+    mova    [cq+64* 5+r5*8], m1
+    mova    [cq+64* 6+r5*8], m2
+    mova    [cq+64* 7+r5*8], m3
+    mova                 m0, [r3+16*16]
+    mova                 m2, [r3+18*16]
+    mova                 m4, [r3+20*16]
+    mova                 m6, [r3+22*16]
+    packssdw             m0, [r3+17*16]
+    packssdw             m2, [r3+19*16]
+    packssdw             m4, [r3+21*16]
+    packssdw             m6, [r3+23*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova    [cq+64* 8+r5*8], m0
+    mova    [cq+64* 9+r5*8], m1
+    mova    [cq+64*10+r5*8], m2
+    mova    [cq+64*11+r5*8], m3
+    mova                 m0, [r3+31*16]
+    mova                 m2, [r3+29*16]
+    mova                 m4, [r3+27*16]
+    mova                 m6, [r3+25*16]
+    packssdw             m0, [r3+30*16]
+    packssdw             m2, [r3+28*16]
+    packssdw             m4, [r3+26*16]
+    packssdw             m6, [r3+24*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova    [cq+64*12+r5*8], m0
+    mova    [cq+64*13+r5*8], m1
+    mova    [cq+64*14+r5*8], m2
+    mova    [cq+64*15+r5*8], m3
+    mova                 m0, [r3+ 0*16]
+    mova                 m2, [r3+ 2*16]
+    mova                 m4, [r3+ 4*16]
+    mova                 m6, [r3+ 6*16]
+    packssdw             m0, [r3+ 1*16]
+    packssdw             m2, [r3+ 3*16]
+    packssdw             m4, [r3+ 5*16]
+    packssdw             m6, [r3+ 7*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+%endif
+    mova    [cq+64* 0+r5*8], m0
+    mova    [cq+64* 1+r5*8], m1
+    mova    [cq+64* 2+r5*8], m2
+    mova    [cq+64* 3+r5*8], m3
+    pxor                 m0, m0
+    REPX {mova [cq+x*64+r5*8], m0}, 16, 17, 18, 19, 20, 21, 22, 23, \
+                                    24, 25, 26, 27, 28, 29, 30, 31
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass=2, we need to call this otherwise the stack pointer has
+    ; the wrong offset in the 8-bit code
+    call .pass2
+    RET
+
+.pass2:
+%if ARCH_X86_64
+    mova                 m8, [o(pw_2048)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+%if WIN64
+    mov [rsp+16*16+gprsize], r7
+%endif
+    mov                  r7, dstq
+%else
+    mov [rsp+2*gprsize+16*16], dstq
+%endif
+    lea                  r3, [strideq*3]
+    mov                 r4d, 4
+    jmp m(idct_16x16_internal_16bpc).loop_pass2
+
+.round_dct32:
+%if ARCH_X86_64
+    psrld               m11, 11 ; pd_1
+    IDCT32_END            0, 15, 8, 9, 10, 1    ; 0 15 16 31
+    mova         [r3+ 0*16], m6
+    mova         [r3+23*16], m7
+    IDCT32_END            1, 14, 6, 7, 10, 1    ; 1 14 17 30
+    packssdw             m0, m1       ;  0  1
+    packssdw            m14, m15      ; 14 15
+    packssdw             m8, m6       ; 16 17
+    packssdw             m7, m9       ; 30 31
+    mova         [r3+16*15], m14
+    mova         [r3+16*14], m7
+    IDCT32_END            2, 15, 10, 7, 6, 1    ; 2 13 18 29
+    IDCT32_END            3, 14,  1, 9, 6, 1    ; 3 12 19 28
+    packssdw             m2, m3       ;  2  3
+    packssdw            m14, m15      ; 12 13
+    packssdw            m10, m1       ; 18 19
+    packssdw             m9, m7       ; 28 29
+    mova         [r3+16*13], m14
+    mova         [r3+16*12], m9
+    IDCT32_END            4, 15, 1, 7, 6, 1     ; 4 11 20 27
+    IDCT32_END            5, 14, 3, 9, 6, 1     ; 5 10 21 26
+    packssdw             m4, m5       ;  4  5
+    packssdw            m14, m15      ; 10 11
+    packssdw             m1, m3       ; 20 21
+    packssdw             m9, m7       ; 26 27
+    mova         [r3+16*11], m14
+    mova         [r3+16*10], m9
+    mova                 m6, [r3+ 0*16]
+    mova                 m7, [r3+23*16]
+    IDCT32_END            6, 15, 14, 5,  3, 1   ; 6 9 22 25
+    IDCT32_END            7, 11,  3, 9, 13, 1   ; 7 8 23 24
+    packssdw             m6, m7       ;  6  7
+    packssdw            m11, m15      ;  8  9
+    packssdw            m14, m3       ; 22 23
+    packssdw             m9, m5       ; 24 25
+    mova          [r3+16*9], m11
+    mova          [r3+16*8], m9
+    mova                m12, m1
+    ret
+%else
+    mova         [r3+16*16], m0
+    mova         [r3+17*16], m1
+    mova         [r3+18*16], m2
+    mova         [r3+19*16], m3
+    mova         [r3+20*16], m4
+    mova         [r3+21*16], m5
+    mova         [r3+22*16], m6
+    mova         [r3+23*16], m7
+    pcmpeqd              m1, m1     ; -1
+    mova                 m2, [o(clip_18b_min)]
+    mova                 m3, [o(clip_18b_max)]
+
+    mov                  r4, 15*16
+.loop_dct32_end:
+    mova                 m0, [r3+16*16]
+    mova                 m6, [r3+16*24]
+    psubd                m5, m0, m6 ; idct16 out15 - n
+    paddd                m0, m6     ; idct16 out0  + n
+    pmaxsd               m0, m2
+    pmaxsd               m5, m2
+    pminsd               m0, m3
+    pminsd               m5, m3
+    psubd                m0, m1
+    psubd                m5, m1
+    mova                 m7, [r3]
+    mova                 m4, [r3+r4]
+    psubd                m6, m0, m4 ; out31 - n
+    paddd                m0, m4     ; out0  + n
+    paddd                m4, m5, m7 ; out15 - n
+    psubd                m5, m7     ; out16 + n
+    REPX       {psrad x, 1}, m0, m5, m4, m6
+    mova               [r3], m0
+    mova            [r3+r4], m4
+    mova         [r3+16*16], m5
+    mova         [r3+24*16], m6
+    add                  r3, 16
+    sub                  r4, 32
+    jg .loop_dct32_end
+    ret
+%endif
+
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 16
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 181
+    add                 r5d, 384
+    sar                 r5d, 9
+    jmp m(inv_txfm_add_dct_dct_32x8_16bpc).dconly2
+
+cglobal inv_txfm_add_dct_dct_32x32_16bpc, 4, 7, 16, 0-(5*32+1)*16, \
+                                          dst, stride, c, eob
+    LEA                  r6, base
+    test               eobd, eobd
+    jz .dconly
+
+    ; remove entirely-zero iterations
+%if ARCH_X86_32
+    mov [rsp+5*32*16+1*gprsize], dstq
+%elif WIN64
+    mov [rsp+5*32*16+1*gprsize], r7
+%endif
+%undef cmp
+    mov                 r5d, 14
+    cmp                eobw, word [o2(tbl_32x32_2d)+r5]
+    jge .end_zero_loop
+    pxor                 m0, m0
+.zero_loop:
+    movzx               t0d, word [o2(tbl_Nx32_odd_offset)+r5]
+    movzx               t1d, t0b
+    shr                 t0d, 8
+    mova   [rsp+32*16+r5*8+0*32*16], m0
+    mova   [rsp+40*16+r5*8+0*32*16], m0
+    mova   [rsp+32*16+t0*8+0*32*16], m0
+    mova   [rsp+32*16+t1*8+0*32*16], m0
+    mova   [rsp+32*16+r5*8+1*32*16], m0
+    mova   [rsp+40*16+r5*8+1*32*16], m0
+    mova   [rsp+32*16+t0*8+1*32*16], m0
+    mova   [rsp+32*16+t1*8+1*32*16], m0
+    mova   [rsp+32*16+r5*8+2*32*16], m0
+    mova   [rsp+40*16+r5*8+2*32*16], m0
+    mova   [rsp+32*16+t0*8+2*32*16], m0
+    mova   [rsp+32*16+t1*8+2*32*16], m0
+    mova   [rsp+32*16+r5*8+3*32*16], m0
+    mova   [rsp+40*16+r5*8+3*32*16], m0
+    mova   [rsp+32*16+t0*8+3*32*16], m0
+    mova   [rsp+32*16+t1*8+3*32*16], m0
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_32x32_2d)+r5]
+    jl .zero_loop
+.end_zero_loop:
+
+    ; actual first pass after skipping all-zero data
+    mov [rsp+gprsize*0+5*32*16], eobd
+.loop_pass1:
+    mova                 m0, [cq+128* 1+r5*8]
+    mova                 m1, [cq+128* 7+r5*8]
+    mova                 m2, [cq+128* 9+r5*8]
+    mova                 m3, [cq+128*15+r5*8]
+    mova                 m4, [cq+128*17+r5*8]
+    mova                 m5, [cq+128*23+r5*8]
+    mova                 m6, [cq+128*25+r5*8]
+    mova                 m7, [cq+128*31+r5*8]
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mov                  r3, rsp
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part1
+    mova                 m0, [cq+128* 3+r5*8]
+    mova                 m1, [cq+128* 5+r5*8]
+    mova                 m2, [cq+128*11+r5*8]
+    mova                 m3, [cq+128*13+r5*8]
+    mova                 m4, [cq+128*19+r5*8]
+    mova                 m5, [cq+128*21+r5*8]
+    mova                 m6, [cq+128*27+r5*8]
+    mova                 m7, [cq+128*29+r5*8]
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part2
+    mova                 m0, [cq+128* 2+r5*8]
+    mova                 m1, [cq+128* 6+r5*8]
+    mova                 m2, [cq+128*10+r5*8]
+    mova                 m3, [cq+128*14+r5*8]
+    mova                 m4, [cq+128*18+r5*8]
+    mova                 m5, [cq+128*22+r5*8]
+    mova                 m6, [cq+128*26+r5*8]
+    mova                 m7, [cq+128*30+r5*8]
+    add                  r3, 16*(16+4*ARCH_X86_32)
+    call m(idct_16x4_internal_16bpc).main_oddhalf
+    mova                 m0, [cq+128* 0+r5*8]
+    mova                 m1, [cq+128* 4+r5*8]
+    mova                 m2, [cq+128* 8+r5*8]
+    mova                 m3, [cq+128*12+r5*8]
+    mova                 m4, [cq+128*16+r5*8]
+    mova                 m5, [cq+128*20+r5*8]
+    mova                 m6, [cq+128*24+r5*8]
+    mova                 m7, [cq+128*28+r5*8]
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    sub                  r3, 16*(16+4*ARCH_X86_32)
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).round_dct32
+    movzx               t0d, word [o2(tbl_Nx32_odd_offset)+r5]
+    movzx               t1d, t0b
+    shr                 t0d, 8
+%if ARCH_X86_64
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova   [rsp+32*16+r5*8+2*32*16], m8
+    mova   [rsp+40*16+r5*8+2*32*16], m10
+    mova   [rsp+32*16+t1*8+2*32*16], m9
+    mova   [rsp+32*16+t0*8+2*32*16], m11
+    mova                 m8, [r3+16* 9] ;  8  9
+    mova                m10, [r3+16*11] ; 10 11
+    mova                m12, [r3+16*13] ; 12 13
+    mova                m14, [r3+16*15] ; 14 15
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova   [rsp+32*16+r5*8+1*32*16], m8
+    mova   [rsp+40*16+r5*8+1*32*16], m10
+    mova   [rsp+32*16+t1*8+1*32*16], m9
+    mova   [rsp+32*16+t0*8+1*32*16], m11
+    mova                 m8, [r3+16* 8] ; 24 25
+    mova                m10, [r3+16*10] ; 26 27
+    mova                m12, [r3+16*12] ; 28 29
+    mova                m14, [r3+16*14] ; 30 31
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova   [rsp+32*16+r5*8+3*32*16], m8
+    mova   [rsp+40*16+r5*8+3*32*16], m10
+    mova   [rsp+32*16+t1*8+3*32*16], m9
+    mova   [rsp+32*16+t0*8+3*32*16], m11
+%else
+    sub                  r3, 8*16
+    mova                 m0, [r3+ 8*16]
+    mova                 m2, [r3+10*16]
+    mova                 m4, [r3+12*16]
+    mova                 m6, [r3+14*16]
+    packssdw             m0, [r3+ 9*16]
+    packssdw             m2, [r3+11*16]
+    packssdw             m4, [r3+13*16]
+    packssdw             m6, [r3+15*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova   [rsp+32*16+r5*8+1*32*16], m0
+    mova   [rsp+40*16+r5*8+1*32*16], m2
+    mova   [rsp+32*16+t1*8+1*32*16], m1
+    mova   [rsp+32*16+t0*8+1*32*16], m3
+    mova                 m0, [r3+16*16]
+    mova                 m2, [r3+18*16]
+    mova                 m4, [r3+20*16]
+    mova                 m6, [r3+22*16]
+    packssdw             m0, [r3+17*16]
+    packssdw             m2, [r3+19*16]
+    packssdw             m4, [r3+21*16]
+    packssdw             m6, [r3+23*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova   [rsp+32*16+r5*8+2*32*16], m0
+    mova   [rsp+40*16+r5*8+2*32*16], m2
+    mova   [rsp+32*16+t1*8+2*32*16], m1
+    mova   [rsp+32*16+t0*8+2*32*16], m3
+    mova                 m0, [r3+31*16]
+    mova                 m2, [r3+29*16]
+    mova                 m4, [r3+27*16]
+    mova                 m6, [r3+25*16]
+    packssdw             m0, [r3+30*16]
+    packssdw             m2, [r3+28*16]
+    packssdw             m4, [r3+26*16]
+    packssdw             m6, [r3+24*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova   [rsp+32*16+r5*8+3*32*16], m0
+    mova   [rsp+40*16+r5*8+3*32*16], m2
+    mova   [rsp+32*16+t1*8+3*32*16], m1
+    mova   [rsp+32*16+t0*8+3*32*16], m3
+    mova                 m0, [r3+ 0*16]
+    mova                 m2, [r3+ 2*16]
+    mova                 m4, [r3+ 4*16]
+    mova                 m6, [r3+ 6*16]
+    packssdw             m0, [r3+ 1*16]
+    packssdw             m2, [r3+ 3*16]
+    packssdw             m4, [r3+ 5*16]
+    packssdw             m6, [r3+ 7*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+%endif
+    pxor                 m7, m7
+    ; clear lower half of [cq]
+    REPX {mova [cq+x*128+r5*8], m7}, 0, 1, 2, 3, 4, 5, 6, 7, \
+                                     8, 9, 10, 11, 12, 13, 14, 15, \
+                                     16, 17, 18, 19, 20, 21, 22, 23, \
+                                     24, 25, 26, 27, 28, 29, 30, 31
+    mova   [rsp+32*16+r5*8+0*32*16], m0
+    mova   [rsp+40*16+r5*8+0*32*16], m2
+    mova   [rsp+32*16+t1*8+0*32*16], m1
+    mova   [rsp+32*16+t0*8+0*32*16], m3
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass=2 code starts here
+    mov                eobd, [rsp+gprsize*0+5*32*16]
+    add                 rsp, 29*16
+    cmp                eobd, 36
+    jl .load_veryfast
+    cmp                eobd, 136
+    jl .load_fast
+    ; load normal
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main)]
+    jmp .run
+.load_fast:
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_fast)]
+    jmp .run
+.load_veryfast:
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_veryfast)]
+    ; fall-through
+.run:
+%if ARCH_X86_64
+    lea                  r2, [dstq+64]
+    mov                  r7, -8
+%else
+    lea                  r2, [rsp+(4*32+3)*16]
+    mov dword [r2+0*gprsize], 4
+%endif
+    jmp m(inv_txfm_add_dct_dct_16x32_16bpc).loop_pass2_entry
+
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 32
+    add                 rsp, (5*32+1-(24+8*ARCH_X86_32))*16
+    jmp m(inv_txfm_add_dct_dct_32x8_16bpc).dconly1
+
+cglobal inv_txfm_add_dct_dct_16x64_16bpc, 4, 7, 16, \
+                                          0-(12+2*64)*16-(4+4*ARCH_X86_32)*gprsize, \
+                                          dst, stride, c, eob
+    LEA                  r6, base
+    test               eobd, eobd
+    jz .dconly
+
+%if ARCH_X86_32
+    DECLARE_REG_TMP 4, 1, 2, 0
+    mov [rsp+gprsize*1+(64*2+12)*16], r0
+    mov [rsp+gprsize*2+(64*2+12)*16], r1
+    mov [rsp+gprsize*3+(64*2+12)*16], r2
+%else
+    DECLARE_REG_TMP 8, 9, 4, 7
+    mov [rsp+gprsize*1+(64*2+12)*16], r9
+%if WIN64
+    mov [rsp+gprsize*2+(64*2+12)*16], r7
+    mov [rsp+gprsize*3+(64*2+12)*16], r8
+%endif
+%endif
+%undef cmp
+    ; remove entirely-zero iterations
+    mov                 r5d, 7*2
+    cmp                eobw, word [o2(tbl_16x32_2d)+r5]
+    jge .end_zero_loop
+    pxor                 m0, m0
+.zero_loop:
+    movzx               t1d, word [o2(tbl_Nx64_offset)+r5*2+0]
+    movzx               t3d, word [o2(tbl_Nx64_offset)+r5*2+2]
+    movzx               t0d, t1b
+    movzx               t2d, t3b
+    shr                 t1d, 8
+    shr                 t3d, 8
+    mova   [rsp+12*16+t0*8], m0
+    mova   [rsp+12*16+t1*8], m0
+    mova   [rsp+12*16+t2*8], m0
+    mova   [rsp+12*16+t3*8], m0
+    mova   [rsp+76*16+t0*8], m0
+    mova   [rsp+76*16+t1*8], m0
+    mova   [rsp+76*16+t2*8], m0
+    mova   [rsp+76*16+t3*8], m0
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_16x32_2d)+r5]
+    jl .zero_loop
+.end_zero_loop:
+    ; actual first pass after skipping all-zero data
+    mov [rsp+gprsize*0+(64*2+12)*16], eobd
+    mov                  r3, rsp
+%if ARCH_X86_32
+    DECLARE_REG_TMP 4, 1, 6, 0
+    mov                  r2, [rsp+gprsize*3+(64*2+12)*16]
+    mov [rsp+gprsize*3+(64*2+12)*16], r6
+%endif
+.loop_pass1:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+ 1*128+r5*8]
+    mova                 m1, [cq+ 3*128+r5*8]
+    mova                 m2, [cq+ 5*128+r5*8]
+    mova                 m3, [cq+ 7*128+r5*8]
+    mova                 m4, [cq+ 9*128+r5*8]
+    mova                 m5, [cq+11*128+r5*8]
+    mova                 m6, [cq+13*128+r5*8]
+    mova                 m7, [cq+15*128+r5*8]
+    call m(idct_16x4_internal_16bpc).main_oddhalf
+
+    mova                 m0, [cq+ 0*128+r5*8]
+    mova                 m1, [cq+ 2*128+r5*8]
+    mova                 m2, [cq+ 4*128+r5*8]
+    mova                 m3, [cq+ 6*128+r5*8]
+    mova                 m4, [cq+ 8*128+r5*8]
+    mova                 m5, [cq+10*128+r5*8]
+    mova                 m6, [cq+12*128+r5*8]
+    mova                 m7, [cq+14*128+r5*8]
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    call m(idct_16x16_internal_16bpc).round
+%if ARCH_X86_64
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    packssdw             m8, m9
+    packssdw            m10, m11
+    packssdw            m12, m13
+    packssdw            m14, m15
+%endif
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    movzx               t1d, word [o2(tbl_Nx64_offset)+r5*2+0]
+    movzx               t3d, word [o2(tbl_Nx64_offset)+r5*2+2]
+    movzx               t0d, t1b
+    movzx               t2d, t3b
+    shr                 t1d, 8
+    shr                 t3d, 8
+%if ARCH_X86_64
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova   [rsp+76*16+t0*8], m8
+    mova   [rsp+76*16+t1*8], m9
+    mova   [rsp+76*16+t2*8], m10
+    mova   [rsp+76*16+t3*8], m11
+%else
+    mova   [rsp+76*16+t0*8], m0
+    mova   [rsp+76*16+t1*8], m1
+    mova   [rsp+76*16+t2*8], m2
+    mova   [rsp+76*16+t3*8], m3
+    mova                 m0, [rsp+ 8*16]
+    mova                 m2, [rsp+ 9*16]
+    mova                 m4, [rsp+10*16]
+    mova                 m6, [rsp+11*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+%endif
+    mova   [rsp+12*16+t0*8], m0
+    mova   [rsp+12*16+t1*8], m1
+    mova   [rsp+12*16+t2*8], m2
+    mova   [rsp+12*16+t3*8], m3
+%if ARCH_X86_32
+    mov                  r6, [rsp+gprsize*3+(64*2+12)*16]
+%endif
+    pxor                 m7, m7
+    REPX {mova [cq+x*128+r5*8], m7}, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass=2
+    mov                eobd, [rsp+gprsize*0+(64*2+12)*16]
+    cmp                eobd, 151
+    jl .fast
+    ; fall-through
+%if ARCH_X86_64
+    DECLARE_REG_TMP 8, 9
+%else
+    DECLARE_REG_TMP 1, 5
+%endif
+    lea                  t0, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_fast)]
+    lea                  t1, [o(m_suffix(idct_16x64_internal_8bpc, _ssse3).main)]
+    jmp .run
+.fast:
+    lea                  t0, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_veryfast)]
+    lea                  t1, [o(m_suffix(idct_16x64_internal_8bpc, _ssse3).main_fast)]
+.run:
+    add                 rsp, 9*16
+
+%if ARCH_X86_64
+    lea                  r2, [dstq+32]
+    mov                  r7, -4
+%else
+    lea                  r2, [rsp+(64*2+3)*16]
+    mov      [r2+4*gprsize], t0
+    mov      [r2+5*gprsize], t1
+    mov                  r1, [r2+2*gprsize]
+    mov dword [r2+0*gprsize], 2
+%endif
+.loop_pass2:
+%if ARCH_X86_32
+    mov                dstq, [r2+1*gprsize]
+%endif
+    call .pass2
+    add                 rsp, 64*16
+%if ARCH_X86_64
+    add                  r7, 2
+    lea                dstq, [r2+r7*8]
+    jl .loop_pass2
+%else
+    add dword [r2+1*gprsize], 16
+    dec dword [r2+0*gprsize]
+    jg .loop_pass2
+%endif
+%assign stack_size (stack_size-(64*2+9)*16)
+%if STACK_ALIGNMENT >= 16
+%assign stack_size_padded (stack_size_padded-(64*2+9)*16)
+%assign stack_offset (stack_offset-(64*2+9)*16)
+%else
+%xdefine rstkm [rsp + stack_size]
+%endif
+%if ARCH_X86_64
+    mov                  r9, [rsp+gprsize*1+3*16]
+%if WIN64
+    mov                  r7, [rsp+gprsize*2+3*16]
+    mov                  r8, [rsp+gprsize*3+3*16]
+%endif
+%endif
+    RET
+
+.pass2:
+%if ARCH_X86_32
+    lea                  r5, [o(itx8_start)]
+%endif
+    mova                 m0, [rsp+gprsize+16* 3]
+    mova                 m1, [rsp+gprsize+16* 4]
+    mova                 m2, [rsp+gprsize+16* 5]
+    mova                 m3, [rsp+gprsize+16* 6]
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    call m_suffix(idct_8x8_internal_8bpc, _ssse3).main
+    mova [rsp+gprsize+ 3*16], m0
+    mova [rsp+gprsize+ 4*16], m1
+    mova [rsp+gprsize+ 5*16], m2
+    mova [rsp+gprsize+ 6*16], m3
+    mova [rsp+gprsize+ 7*16], m4
+    mova [rsp+gprsize+ 8*16], m5
+    mova [rsp+gprsize+ 9*16], m6
+    mova [rsp+gprsize+10*16], m7
+    mova                 m0, [rsp+gprsize+16*11]
+    mova                 m1, [rsp+gprsize+16*12]
+    mova                 m2, [rsp+gprsize+16*13]
+    mova                 m3, [rsp+gprsize+16*14]
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    call m_suffix(idct_16x8_internal_8bpc, _ssse3).main
+    mova                 m7, [rsp+gprsize+ 0*16]
+    mova [rsp+gprsize+11*16], m0
+    mova [rsp+gprsize+12*16], m1
+    mova [rsp+gprsize+13*16], m2
+    mova [rsp+gprsize+14*16], m3
+    mova [rsp+gprsize+15*16], m4
+    mova [rsp+gprsize+16*16], m5
+    mova [rsp+gprsize+17*16], m6
+    mova [rsp+gprsize+18*16], m7
+%if ARCH_X86_64
+    call                  r8
+%else
+    call      [r2+4*gprsize]
+%endif
+    mova [rsp+gprsize+ 3*16], m0
+    mova [rsp+gprsize+ 5*16], m2
+    mova [rsp+gprsize+ 8*16], m5
+    mova [rsp+gprsize+10*16], m7
+%if ARCH_X86_64
+    call                 r9
+    mova                 m8, [o(pw_2048)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+%else
+    call     [r2+5*gprsize]
+%endif
+    lea                  r3, [strideq*3]
+    lea                  r4, [rsp+gprsize+ 3*16]
+%if ARCH_X86_64
+    mov                 r6d, 8
+%else
+    mov dword [r2+2*gprsize], 8
+%endif
+.loop_write:
+    mova                 m0, [r4+0*16]
+    mova                 m1, [r4+1*16]
+    mova                 m2, [r4+2*16]
+    mova                 m3, [r4+3*16]
+    mova                 m4, [r4+4*16]
+    mova                 m5, [r4+5*16]
+    mova                 m6, [r4+6*16]
+    mova                 m7, [r4+7*16]
+    call m(idct_8x8_internal_16bpc).round1_and_write_8x8
+    lea                dstq, [dstq+strideq*8]
+    add                  r4, 8*16
+%if ARCH_X86_64
+    dec                 r6d
+%else
+    dec dword [r2+2*gprsize]
+%endif
+    jg .loop_write
+    ret
+
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 64
+    add                 r5d, 640
+    sar                 r5d, 10
+    add                 rsp, (12+2*64)*16+(4+4*ARCH_X86_32)*gprsize-(8+4*ARCH_X86_32)*16
+    jmp m(inv_txfm_add_dct_dct_16x4_16bpc).dconly2
+
+cglobal inv_txfm_add_dct_dct_32x64_16bpc, 4, 7, 16, \
+                                          0-(32+4*64)*16-(4+4*ARCH_X86_32)*gprsize, \
+                                          dst, stride, c, eob
+    LEA                  r6, base
+    test               eobd, eobd
+    jz .dconly
+
+%if ARCH_X86_32
+    DECLARE_REG_TMP 4, 1, 2, 0
+    mov [rsp+gprsize*1+(64*4+32)*16], r0
+    mov [rsp+gprsize*2+(64*4+32)*16], r1
+    mov [rsp+gprsize*3+(64*4+32)*16], r2
+%else
+    DECLARE_REG_TMP 8, 9, 4, 7
+    mov [rsp+gprsize*1+(64*4+32)*16], r9
+%if WIN64
+    mov [rsp+gprsize*2+(64*4+32)*16], r7
+    mov [rsp+gprsize*3+(64*4+32)*16], r8
+%endif
+%endif
+%undef cmp
+    ; remove entirely-zero iterations
+    mov                 r5d, 7*2
+    cmp                eobw, word [o2(tbl_32x32_2d)+r5]
+    jge .end_zero_loop
+    pxor                 m0, m0
+.zero_loop:
+    movzx               t1d, word [o2(tbl_Nx64_offset)+r5*2+0]
+    movzx               t3d, word [o2(tbl_Nx64_offset)+r5*2+2]
+    movzx               t0d, t1b
+    movzx               t2d, t3b
+    shr                 t1d, 8
+    shr                 t3d, 8
+    mova  [rsp+ 32*16+t0*8], m0
+    mova  [rsp+ 32*16+t1*8], m0
+    mova  [rsp+ 32*16+t2*8], m0
+    mova  [rsp+ 32*16+t3*8], m0
+    mova  [rsp+ 96*16+t0*8], m0
+    mova  [rsp+ 96*16+t1*8], m0
+    mova  [rsp+ 96*16+t2*8], m0
+    mova  [rsp+ 96*16+t3*8], m0
+    mova  [rsp+160*16+t0*8], m0
+    mova  [rsp+160*16+t1*8], m0
+    mova  [rsp+160*16+t2*8], m0
+    mova  [rsp+160*16+t3*8], m0
+    mova  [rsp+224*16+t0*8], m0
+    mova  [rsp+224*16+t1*8], m0
+    mova  [rsp+224*16+t2*8], m0
+    mova  [rsp+224*16+t3*8], m0
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_32x32_2d)+r5]
+    jl .zero_loop
+.end_zero_loop:
+    ; actual first pass after skipping all-zero data
+    mov [rsp+gprsize*0+(64*4+32)*16], eobd
+    mov                  r3, rsp
+%if ARCH_X86_32
+    DECLARE_REG_TMP 4, 1, 6, 0
+    mov                  r2, [rsp+gprsize*3+(64*4+32)*16]
+    mov [rsp+gprsize*3+(64*4+32)*16], r6
+%endif
+.loop_pass1:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+    mova                 m0, [cq+128* 1+r5*8]
+    mova                 m1, [cq+128* 7+r5*8]
+    mova                 m2, [cq+128* 9+r5*8]
+    mova                 m3, [cq+128*15+r5*8]
+    mova                 m4, [cq+128*17+r5*8]
+    mova                 m5, [cq+128*23+r5*8]
+    mova                 m6, [cq+128*25+r5*8]
+    mova                 m7, [cq+128*31+r5*8]
+    mov                  r3, rsp
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part1
+
+    mova                 m0, [cq+128* 3+r5*8]
+    mova                 m1, [cq+128* 5+r5*8]
+    mova                 m2, [cq+128*11+r5*8]
+    mova                 m3, [cq+128*13+r5*8]
+    mova                 m4, [cq+128*19+r5*8]
+    mova                 m5, [cq+128*21+r5*8]
+    mova                 m6, [cq+128*27+r5*8]
+    mova                 m7, [cq+128*29+r5*8]
+%if ARCH_X86_32
+    add                  r3, 16*8
+%endif
+    call m(idct_8x4_internal_16bpc).rect2_mul
+%if ARCH_X86_32
+    sub                  r3, 16*8
+%endif
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part2
+    add                  r3, 16*(16+4*ARCH_X86_32)
+
+    mova                 m0, [cq+128* 2+r5*8]
+    mova                 m1, [cq+128* 6+r5*8]
+    mova                 m2, [cq+128*10+r5*8]
+    mova                 m3, [cq+128*14+r5*8]
+    mova                 m4, [cq+128*18+r5*8]
+    mova                 m5, [cq+128*22+r5*8]
+    mova                 m6, [cq+128*26+r5*8]
+    mova                 m7, [cq+128*30+r5*8]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(idct_16x4_internal_16bpc).main_oddhalf
+
+    mova                 m0, [cq+128* 0+r5*8]
+    mova                 m1, [cq+128* 4+r5*8]
+    mova                 m2, [cq+128* 8+r5*8]
+    mova                 m3, [cq+128*12+r5*8]
+    mova                 m4, [cq+128*16+r5*8]
+    mova                 m5, [cq+128*20+r5*8]
+    mova                 m6, [cq+128*24+r5*8]
+    mova                 m7, [cq+128*28+r5*8]
+    call m(idct_8x4_internal_16bpc).rect2_mul
+    call m(idct_8x4_internal_16bpc).main_pass1
+    call m(idct_8x4_internal_16bpc).round
+    sub                  r3, 16*(16+4*ARCH_X86_32)
+    call m(inv_txfm_add_dct_dct_32x16_16bpc).round_dct32
+
+    movzx               t1d, word [o2(tbl_Nx64_offset)+r5*2+0]
+    movzx               t3d, word [o2(tbl_Nx64_offset)+r5*2+2]
+    movzx               t0d, t1b
+    movzx               t2d, t3b
+    shr                 t1d, 8
+    shr                 t3d, 8
+%if ARCH_X86_64
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova  [rsp+160*16+t0*8], m8
+    mova  [rsp+160*16+t1*8], m9
+    mova  [rsp+160*16+t2*8], m10
+    mova  [rsp+160*16+t3*8], m11
+    mova                 m8, [r3+16* 9] ;  8  9
+    mova                m10, [r3+16*11] ; 10 11
+    mova                m12, [r3+16*13] ; 12 13
+    mova                m14, [r3+16*15] ; 14 15
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova  [rsp+ 96*16+t0*8], m8
+    mova  [rsp+ 96*16+t1*8], m9
+    mova  [rsp+ 96*16+t2*8], m10
+    mova  [rsp+ 96*16+t3*8], m11
+    mova                 m8, [r3+16* 8] ; 24 25
+    mova                m10, [r3+16*10] ; 26 27
+    mova                m12, [r3+16*12] ; 28 29
+    mova                m14, [r3+16*14] ; 30 31
+    call m(idct_16x4_internal_16bpc).transpose4x8packed_hi
+    mova  [rsp+224*16+t0*8], m8
+    mova  [rsp+224*16+t1*8], m9
+    mova  [rsp+224*16+t2*8], m10
+    mova  [rsp+224*16+t3*8], m11
+%else
+    sub                  r3, 8*16
+    mova                 m0, [r3+ 8*16]
+    mova                 m2, [r3+10*16]
+    mova                 m4, [r3+12*16]
+    mova                 m6, [r3+14*16]
+    packssdw             m0, [r3+ 9*16]
+    packssdw             m2, [r3+11*16]
+    packssdw             m4, [r3+13*16]
+    packssdw             m6, [r3+15*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova  [rsp+ 96*16+t0*8], m0
+    mova  [rsp+ 96*16+t1*8], m1
+    mova  [rsp+ 96*16+t2*8], m2
+    mova  [rsp+ 96*16+t3*8], m3
+    mova                 m0, [r3+16*16]
+    mova                 m2, [r3+18*16]
+    mova                 m4, [r3+20*16]
+    mova                 m6, [r3+22*16]
+    packssdw             m0, [r3+17*16]
+    packssdw             m2, [r3+19*16]
+    packssdw             m4, [r3+21*16]
+    packssdw             m6, [r3+23*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova  [rsp+160*16+t0*8], m0
+    mova  [rsp+160*16+t1*8], m1
+    mova  [rsp+160*16+t2*8], m2
+    mova  [rsp+160*16+t3*8], m3
+    mova                 m0, [r3+31*16]
+    mova                 m2, [r3+29*16]
+    mova                 m4, [r3+27*16]
+    mova                 m6, [r3+25*16]
+    packssdw             m0, [r3+30*16]
+    packssdw             m2, [r3+28*16]
+    packssdw             m4, [r3+26*16]
+    packssdw             m6, [r3+24*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova  [rsp+224*16+t0*8], m0
+    mova  [rsp+224*16+t1*8], m1
+    mova  [rsp+224*16+t2*8], m2
+    mova  [rsp+224*16+t3*8], m3
+    mova                 m0, [r3+ 0*16]
+    mova                 m2, [r3+ 2*16]
+    mova                 m4, [r3+ 4*16]
+    mova                 m6, [r3+ 6*16]
+    packssdw             m0, [r3+ 1*16]
+    packssdw             m2, [r3+ 3*16]
+    packssdw             m4, [r3+ 5*16]
+    packssdw             m6, [r3+ 7*16]
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+%endif
+    mova  [rsp+ 32*16+t0*8], m0
+    mova  [rsp+ 32*16+t1*8], m1
+    mova  [rsp+ 32*16+t2*8], m2
+    mova  [rsp+ 32*16+t3*8], m3
+    pxor                 m0, m0
+    REPX {mova [cq+x*128+r5*8], m0}, 0, 1, 2, 3, 4, 5, 6, 7, \
+                                     8, 9, 10, 11, 12, 13, 14, 15, \
+                                     16, 17, 18, 19, 20, 21, 22, 23, \
+                                     24, 25, 26, 27, 28, 29, 30, 31
+%if ARCH_X86_32
+    mov                  r6, [rsp+gprsize*3+(64*4+32)*16]
+%endif
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass=2
+    mov                eobd, [rsp+gprsize*0+(64*4+32)*16]
+    cmp                eobd, 136
+    jl .fast
+    ; fall-through
+%if ARCH_X86_64
+    DECLARE_REG_TMP 8, 9
+%else
+    DECLARE_REG_TMP 1, 5
+%endif
+    lea                  t0, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_fast)]
+    lea                  t1, [o(m_suffix(idct_16x64_internal_8bpc, _ssse3).main)]
+    jmp .run
+.fast:
+    lea                  t0, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_veryfast)]
+    lea                  t1, [o(m_suffix(idct_16x64_internal_8bpc, _ssse3).main_fast)]
+.run:
+    add                 rsp, 29*16
+
+%if ARCH_X86_64
+    lea                  r2, [dstq+64]
+    mov                  r7, -8
+%else
+    lea                  r2, [rsp+(64*4+3)*16]
+    mov      [r2+4*gprsize], t0
+    mov      [r2+5*gprsize], t1
+    mov                  r1, [r2+2*gprsize]
+    mov dword [r2+0*gprsize], 4
+%endif
+    jmp m(inv_txfm_add_dct_dct_16x64_16bpc).loop_pass2
+
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 64
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 181
+    add                 r5d, 384
+    sar                 r5d, 9
+    add                 rsp, (32+4*64)*16+(4+4*ARCH_X86_32)*gprsize-(24+8*ARCH_X86_32)*16
+    jmp m(inv_txfm_add_dct_dct_32x8_16bpc).dconly2
+
+cglobal inv_txfm_add_dct_dct_64x16_16bpc, 4, 7, 16, 0-(64+8*ARCH_X86_32)*16, \
+                                         dst, stride, c, eob
+    LEA                  r6, base
+    test               eobd, eobd
+    jz .dconly
+
+    ; remove entirely-zero iterations
+%undef cmp
+    mov                 r5d, 8
+.zero_loop:
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_32x16_2d)+r5]
+    jl .zero_loop
+
+    ; actual first pass after skipping all-zero data
+.loop_pass1:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+
+    mov                  r3, rsp
+    lea                  r4, [o(idct64_mul_16bpc)]
+    mova                 m0, [cq+64* 1+r5*8]
+    mova                 m1, [cq+64*31+r5*8]
+    mova                 m2, [cq+64*17+r5*8]
+    mova                 m3, [cq+64*15+r5*8]
+    call .main_part1
+    mova                 m0, [cq+64* 7+r5*8]
+    mova                 m1, [cq+64*25+r5*8]
+    mova                 m2, [cq+64*23+r5*8]
+    mova                 m3, [cq+64* 9+r5*8]
+    call .main_part1
+    mova                 m0, [cq+64* 5+r5*8]
+    mova                 m1, [cq+64*27+r5*8]
+    mova                 m2, [cq+64*21+r5*8]
+    mova                 m3, [cq+64*11+r5*8]
+    call .main_part1
+    mova                 m0, [cq+64* 3+r5*8]
+    mova                 m1, [cq+64*29+r5*8]
+    mova                 m2, [cq+64*19+r5*8]
+    mova                 m3, [cq+64*13+r5*8]
+    call .main_part1
+    call .main_part2
+
+    mova                 m0, [cq+64* 2+r5*8]
+    mova                 m1, [cq+64*14+r5*8]
+    mova                 m2, [cq+64*18+r5*8]
+    mova                 m3, [cq+64*30+r5*8]
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part1_fast
+
+    mova                 m0, [cq+64* 6+r5*8]
+    mova                 m1, [cq+64*10+r5*8]
+    mova                 m2, [cq+64*22+r5*8]
+    mova                 m3, [cq+64*26+r5*8]
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part2_fast
+    add                  r3, 16*(24+4*ARCH_X86_32)
+
+    mova                 m0, [cq+64* 4+r5*8]
+    mova                 m1, [cq+64*12+r5*8]
+    mova                 m2, [cq+64*20+r5*8]
+    mova                 m3, [cq+64*28+r5*8]
+    call m(idct_16x4_internal_16bpc).main_oddhalf_fast
+
+    mova                 m0, [cq+64* 0+r5*8]
+    mova                 m1, [cq+64* 8+r5*8]
+    mova                 m2, [cq+64*16+r5*8]
+    mova                 m3, [cq+64*24+r5*8]
+    call m(idct_8x4_internal_16bpc).main_pass1_fast
+    call m(idct_8x4_internal_16bpc).round
+    mova [r3-(7+4*ARCH_X86_32)*16], m1
+    mova [r3-(6+4*ARCH_X86_32)*16], m2
+    mova [r3-(5+4*ARCH_X86_32)*16], m3
+    mova [r3-(4+4*ARCH_X86_32)*16], m4
+    mova [r3-(3+4*ARCH_X86_32)*16], m5
+    mova [r3-(2+4*ARCH_X86_32)*16], m6
+    mova [r3-(1+4*ARCH_X86_32)*16], m7
+    sub                  r3, 16*(40+4*ARCH_X86_32-4)
+
+%if ARCH_X86_64
+    psrld               m15, m11, 10 ; pd_2
+%else
+    mova                 m7, [o(pd_2)]
+%endif
+    call .main_end_loop_start
+
+    lea                  r3, [rsp+56*16]
+    lea                  r4, [cq+r5*8+64*28]
+    call .shift_transpose
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass=2, we need to call this otherwise the stack pointer has
+    ; the wrong offset in the 8-bit code
+    call .pass2
+    RET
+
+.pass2:
+%if ARCH_X86_64
+    mova                 m8, [o(pw_2048)]
+    pxor                 m9, m9
+    mova                m10, [o(pixel_10bpc_max)]
+%if WIN64
+    mov [rsp+16*16+gprsize], r7
+%endif
+    mov                  r7, dstq
+%else
+    mov [rsp+2*gprsize+16*16], dstq
+%endif
+    lea                  r3, [strideq*3]
+    mov                 r4d, 8
+    jmp m(idct_16x16_internal_16bpc).loop_pass2
+
+.main_part1: ; idct64 steps 1-5
+    ; in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+    ; in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+    ; in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+    ; in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+%if ARCH_X86_64
+    movd                 m7, [r4+4*0]
+    movd                 m8, [r4+4*1]
+    movd                 m6, [r4+4*2]
+    movd                 m9, [r4+4*3]
+    movd                 m5, [r4+4*4]
+    movd                m10, [r4+4*5]
+    movd                 m4, [r4+4*6]
+    movd                m15, [r4+4*7]
+    REPX {pshufd x, x, q0000}, m7, m8, m6, m9, m5, m10, m4, m15
+    pmulld               m7, m0     ; t63a
+    pmulld               m0, m8     ; t32a
+    pmulld               m6, m1     ; t62a
+    pmulld               m1, m9     ; t33a
+    pmulld               m5, m2     ; t61a
+    pmulld               m2, m10    ; t34a
+    pmulld               m4, m3     ; t60a
+    pmulld               m3, m15    ; t35a
+    movd                m10, [r4+4*8]
+    movd                m15, [r4+4*9]
+    REPX {pshufd x, x, q0000}, m10, m15
+    REPX     {paddd x, m11}, m7, m0, m6, m1, m5, m2, m4, m3
+    REPX     {psrad x, 12 }, m0, m1, m7, m6, m2, m3, m5, m4
+    psubd                m8, m0, m1 ; t33
+    paddd                m0, m1     ; t32
+    psubd                m1, m7, m6 ; t62
+    paddd                m7, m6     ; t63
+    psubd                m6, m3, m2 ; t34
+    paddd                m3, m2     ; t35
+    psubd                m2, m4, m5 ; t61
+    paddd                m4, m5     ; t60
+    REPX    {pmaxsd x, m12}, m8, m1, m6, m2
+    REPX    {pminsd x, m13}, m8, m1, m6, m2
+    ITX_MULSUB_2D         1, 8, 5, 9, _, 11, 10, 15    ; t33a, t62a
+    ITX_MULSUB_2D         2, 6, 5, 9, _, 11, 10, 15, 4 ; t61a, t34a
+    REPX    {pmaxsd x, m12}, m0, m3, m7, m4
+    REPX    {pminsd x, m13}, m0, m3, m7, m4
+    movd                m10, [r4+4*10]
+    movd                m15, [r4+4*11]
+    REPX {pshufd x, x, q0000}, m10, m15
+    psubd                m5, m0, m3 ; t35a
+    paddd                m0, m3     ; t32a
+    psubd                m3, m7, m4 ; t60a
+    paddd                m7, m4     ; t63a
+    psubd                m4, m1, m6 ; t34
+    paddd                m1, m6     ; t33
+    psubd                m6, m8, m2 ; t61
+    paddd                m8, m2     ; t62
+    REPX    {pmaxsd x, m12}, m5, m3, m4, m6
+    REPX    {pminsd x, m13}, m5, m3, m4, m6
+    ITX_MULSUB_2D         3, 5, 2, 9, _, 11, 10, 15 ; t35,  t60
+    ITX_MULSUB_2D         6, 4, 2, 9, _, 11, 10, 15 ; t34a, t61a
+    REPX    {pmaxsd x, m12}, m0, m7, m1, m8
+    REPX    {pminsd x, m13}, m0, m7, m1, m8
+    add                  r4, 4*12
+    mova          [r3+16*0], m0
+    mova          [r3+16*7], m7
+    mova          [r3+16*1], m1
+    mova          [r3+16*6], m8
+    mova          [r3+16*2], m6
+    mova          [r3+16*5], m4
+    mova          [r3+16*3], m3
+    mova          [r3+16*4], m5
+%else
+    movd                 m7, [r4+4*0]
+    movd                 m6, [r4+4*2]
+    movd                 m5, [r4+4*4]
+    movd                 m4, [r4+4*6]
+    REPX {pshufd x, x, q0000}, m7, m6, m5, m4
+    pmulld               m7, m0     ; t63a
+    pmulld               m6, m1     ; t62a
+    pmulld               m5, m2     ; t61a
+    pmulld               m4, m3     ; t60a
+    mova          [r3+0*16], m6
+    mova          [r3+1*16], m7
+    movd                 m6, [r4+4*1]
+    movd                 m7, [r4+4*3]
+    REPX {pshufd x, x, q0000}, m7, m6
+    pmulld               m0, m6     ; t32a
+    pmulld               m1, m7     ; t33a
+    movd                 m6, [r4+4*5]
+    movd                 m7, [r4+4*7]
+    REPX {pshufd x, x, q0000}, m7, m6
+    pmulld               m2, m6     ; t34a
+    pmulld               m3, m7     ; t35a
+    mova                 m6, [r3+0*16]
+    mova                 m7, [o(pd_2048)]
+    REPX      {paddd x, m7}, m0, m1, m2, m3, m4, m5, m6
+    paddd                m7, [r3+1*16]
+    REPX      {psrad x, 12}, m0, m1, m7, m6, m2, m3, m5, m4
+    mova           [r3+0*16], m5
+    psubd                m5, m0, m1 ; t33
+    paddd                m0, m1     ; t32
+    mova           [r3+1*16], m0
+    mova                 m0, [r3+0*16]
+    psubd                m1, m7, m6 ; t62
+    paddd                m7, m6     ; t63
+    psubd                m6, m3, m2 ; t34
+    paddd                m3, m2     ; t35
+    psubd                m2, m4, m0 ; t61
+    paddd                m4, m0     ; t60
+    mova                 m0, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m0}, m5, m1, m7, m6, m3, m2, m4
+    pmaxsd               m0, [r3+1*16]
+    mova          [r3+0*16], m0
+    mova                 m0, [o(clip_18b_max)]
+    REPX     {pminsd x, m0}, m5, m1, m7, m6, m3, m2, m4
+    pminsd               m0, [r3+0*16]
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m3
+    mova          [r3+2*16], m4
+    mova          [r3+3*16], m7
+    mova                 m0, [o(pd_2048)]
+    movd                 m3, [r4+4*8]
+    movd                 m4, [r4+4*9]
+    REPX {pshufd x, x, q0000}, m3, m4
+    mova          [r3+4*16], m2
+    ITX_MULSUB_2D         1, 5, 2, 7, _, 0, 3, 4    ; t33a, t62a
+    mova                 m2, [r3+4*16]
+    mova          [r3+4*16], m5
+    ITX_MULSUB_2D         2, 6, 5, 7, _, 0, 3, 4, 4 ; t61a, t34a
+    mova                 m0, [r3+0*16]
+    mova                 m3, [r3+1*16]
+    mova                 m4, [r3+2*16]
+    mova                 m7, [r3+3*16]
+    psubd                m5, m0, m3 ; t35a
+    paddd                m0, m3     ; t32a
+    mova          [r3+0*16], m5
+    mova                 m5, [r3+4*16]
+    psubd                m3, m7, m4 ; t60a
+    paddd                m7, m4     ; t63a
+    psubd                m4, m1, m6 ; t34
+    paddd                m1, m6     ; t33
+    psubd                m6, m5, m2 ; t61
+    paddd                m2, m5     ; t62
+    mova                 m5, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m5}, m0, m3, m7, m4, m1, m6, m2
+    pmaxsd               m5, [r3+0*16]
+    mova          [r3+0*16], m5
+    mova                 m5, [o(clip_18b_max)]
+    REPX     {pminsd x, m5}, m0, m3, m7, m4, m1, m6, m2
+    pminsd               m5, [r3+0*16]
+    mova          [r3+16*0], m0
+    mova          [r3+16*7], m7
+    mova          [r3+16*1], m1
+    mova          [r3+16*6], m2
+    mova          [r3+16*2], m4
+    mova                 m7, [o(pd_2048)]
+    movd                 m0, [r4+4*10]
+    movd                 m1, [r4+4*11]
+    REPX {pshufd x, x, q0000}, m0, m1
+    ITX_MULSUB_2D         3, 5, 2, 4, _, 7, 0, 1 ; t35,  t60
+    mova          [r3+16*3], m3
+    mova          [r3+16*4], m5
+    mova                 m4, [r3+2*16]
+    ITX_MULSUB_2D         6, 4, 2, 3, _, 7, 0, 1 ; t34a, t61a
+    add                  r4, 4*12
+    mova          [r3+16*2], m6
+    mova          [r3+16*5], m4
+%endif
+    add                  r3, 16*8
+    ret
+
+.main_part2: ; idct64 steps 6-9
+    lea                  r4, [r3+16*7]
+%if ARCH_X86_64
+    mova                m10, [o(pd_1567)]
+    mova                m15, [o(pd_3784)]
+.main_part2_loop:
+    mova                 m0, [r3-16*32] ; t32a
+    mova                 m1, [r4-16*24] ; t39a
+    mova                 m2, [r4-16*32] ; t63a
+    mova                 m3, [r3-16*24] ; t56a
+    mova                 m4, [r3-16*16] ; t40a
+    mova                 m5, [r4-16* 8] ; t47a
+    mova                 m6, [r4-16*16] ; t55a
+    mova                 m7, [r3-16* 8] ; t48a
+    psubd                m8, m0, m1 ; t39
+    paddd                m0, m1     ; t32
+    psubd                m1, m2, m3 ; t56
+    paddd                m2, m3     ; t63
+    psubd                m3, m5, m4 ; t40
+    paddd                m5, m4     ; t47
+    psubd                m4, m7, m6 ; t55
+    paddd                m7, m6     ; t48
+    REPX    {pmaxsd x, m12}, m8, m1, m3, m4
+    REPX    {pminsd x, m13}, m8, m1, m3, m4
+    ITX_MULSUB_2D         1, 8, 6, 9, _, 11, 10, 15    ; t39a, t56a
+    ITX_MULSUB_2D         4, 3, 6, 9, _, 11, 10, 15, 4 ; t55a, t40a
+    REPX    {pmaxsd x, m12}, m0, m2, m5, m7
+    REPX    {pminsd x, m13}, m0, m5, m2, m7
+    psubd                m6, m2, m7 ; t48a
+    paddd                m2, m7     ; t63a
+    psubd                m7, m0, m5 ; t47a
+    paddd                m0, m5     ; t32a
+    psubd                m5, m8, m4 ; t55
+    paddd                m8, m4     ; t56
+    psubd                m4, m1, m3 ; t40
+    paddd                m1, m3     ; t39
+    REPX    {pmaxsd x, m12}, m6, m7, m5, m4
+    REPX    {pminsd x, m13}, m6, m7, m5, m4
+    REPX    {pmulld x, m14}, m6, m7, m5, m4
+    REPX    {pmaxsd x, m12}, m2, m0, m8, m1
+    REPX    {pminsd x, m13}, m2, m0, m8, m1
+    paddd                m6, m11
+    paddd                m5, m11
+    psubd                m3, m6, m7 ; t47
+    paddd                m6, m7     ; t48
+    psubd                m7, m5, m4 ; t40a
+    paddd                m5, m4     ; t55a
+    REPX      {psrad x, 12}, m3, m6, m7, m5
+    mova         [r4-16* 8], m2
+    mova         [r3-16*32], m0
+    mova         [r3-16* 8], m8
+    mova         [r4-16*32], m1
+    mova         [r4-16*24], m3
+    mova         [r3-16*16], m6
+    mova         [r3-16*24], m7
+    mova         [r4-16*16], m5
+%else
+.main_part2_loop:
+    mova                 m0, [r3-16*32] ; t32a
+    mova                 m1, [r4-16*24] ; t39a
+    mova                 m2, [r4-16*32] ; t63a
+    mova                 m3, [r3-16*24] ; t56a
+    mova                 m4, [r3-16*16] ; t40a
+    mova                 m5, [r4-16* 8] ; t47a
+    mova                 m6, [r4-16*16] ; t55a
+    psubd                m7, m0, m1 ; t39
+    paddd                m0, m1     ; t32
+    mova          [r3+0*16], m7
+    mova                 m7, [r3-16* 8] ; t48a
+    psubd                m1, m2, m3 ; t56
+    paddd                m2, m3     ; t63
+    psubd                m3, m5, m4 ; t40
+    paddd                m5, m4     ; t47
+    psubd                m4, m7, m6 ; t55
+    paddd                m7, m6     ; t48
+    mova                 m6, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m6}, m0, m1, m2, m3, m5, m4, m7
+    pmaxsd               m6, [r3+0*16]
+    mova          [r3+0*16], m6
+    mova                 m6, [o(clip_18b_max)]
+    REPX     {pminsd x, m6}, m0, m1, m2, m3, m5, m4, m7
+    pminsd               m6, [r3+0*16]
+    mova          [r3+0*16], m0
+    mova          [r3+1*16], m2
+    mova          [r3+2*16], m5
+    mova          [r3+3*16], m7
+    mova                 m0, [o(pd_2048)]
+    ITX_MULSUB_2D         1, 6, 2, 5, 7, 0, 1567, 3784    ; t39a, t56a
+    ITX_MULSUB_2D         4, 3, 2, 5, _, 0,    7, 3784, 4 ; t55a, t40a
+    mova                 m2, [r3+1*16]
+    mova                 m7, [r3+3*16]
+    psubd                m5, m2, m7 ; t48a
+    paddd                m2, m7     ; t63a
+    mova          [r3+1*16], m5
+    mova                 m0, [r3+0*16]
+    mova                 m5, [r3+2*16]
+    psubd                m7, m0, m5 ; t47a
+    paddd                m0, m5     ; t32a
+    psubd                m5, m6, m4 ; t55
+    paddd                m6, m4     ; t56
+    psubd                m4, m1, m3 ; t40
+    paddd                m1, m3     ; t39
+    mova                 m3, [o(clip_18b_min)]
+    REPX     {pmaxsd x, m3}, m2, m7, m0, m5, m6, m4, m1
+    pmaxsd               m3, [r3+1*16]
+    mova          [r3+0*16], m3
+    mova                 m3, [o(clip_18b_max)]
+    REPX     {pminsd x, m3}, m2, m7, m0, m5, m6, m4, m1
+    pminsd               m3, [r3+0*16]
+    mova         [r4-16* 8], m2
+    mova         [r3-16*32], m0
+    mova         [r3-16* 8], m6
+    mova         [r4-16*32], m1
+    mova                 m0, [o(pd_2896)]
+    mova                 m1, [o(pd_2048)]
+    REPX     {pmulld x, m0}, m3, m7, m5, m4
+    REPX     {paddd  x, m1}, m3, m5
+    psubd                m6, m3, m7 ; t47
+    paddd                m3, m7     ; t48
+    psubd                m7, m5, m4 ; t40a
+    paddd                m5, m4     ; t55a
+    REPX      {psrad x, 12}, m6, m3, m7, m5
+    mova         [r4-16*24], m6
+    mova         [r3-16*16], m3
+    mova         [r3-16*24], m7
+    mova         [r4-16*16], m5
+%endif
+    add                  r3, 16
+    sub                  r4, 16
+    cmp                  r3, r4
+    jl .main_part2_loop
+    sub                  r3, 4*16
+    ret
+
+.main_end_loop:
+    mova                 m0, [r3+16*28] ; idct8  0  + n
+.main_end_loop_start:
+    mova                 m2, [r3+16*12] ; idct32 16 + n
+    mova                 m3, [r4+16*12] ; idct32 31 - n
+%if ARCH_X86_64
+    mova                 m1, [r4+16*28] ; idct16 15 - n
+    mova                 m4, [r4-16* 4] ; idct64 63 - n
+    mova                 m5, [r3-16* 4] ; idct64 48 + n
+    mova                 m6, [r4-16*20] ; idct64 47 - n
+    mova                 m7, [r3-16*20] ; idct64 32 + n
+    pmaxsd               m0, m12
+    pminsd               m0, m13
+    paddd                m8, m0, m1     ; idct16 out0  + n
+    psubd                m0, m1         ; idct16 out15 - n
+    REPX    {pmaxsd x, m12}, m8, m0
+    REPX    {pminsd x, m13}, m8, m0
+    paddd                m1, m8, m3     ; idct32 out0  + n
+    psubd                m8, m3         ; idct32 out31 - n
+    paddd                m3, m0, m2     ; idct32 out15 - n
+    psubd                m0, m2         ; idct32 out16 + n
+    REPX    {pmaxsd x, m12}, m1, m8, m3, m0
+    REPX    {pminsd x, m13}, m1, m3, m8, m0
+    REPX    {paddd  x, m15}, m1, m3, m0, m8
+    paddd                m2, m1, m4     ; idct64 out0  + n (unshifted)
+    psubd                m1, m4         ; idct64 out63 - n (unshifted)
+    paddd                m4, m3, m5     ; idct64 out15 - n (unshifted)
+    psubd                m3, m5         ; idct64 out48 + n (unshifted)
+    paddd                m5, m0, m6     ; idct64 out16 + n (unshifted)
+    psubd                m0, m6         ; idct64 out47 - n (unshifted)
+    paddd                m6, m8, m7     ; idct64 out31 - n (unshifted)
+    psubd                m8, m7         ; idct64 out32 + n (unshifted)
+    mova         [r3-16*20], m2
+    mova         [r4+16*28], m1
+    mova         [r4-16*20], m4
+    mova         [r3+16*28], m3
+    mova         [r3-16* 4], m5
+    mova         [r4+16*12], m0
+    mova         [r4-16* 4], m6
+    mova         [r3+16*12], m8
+%else
+    mova                 m5, [o(clip_18b_min)]
+    mova                 m6, [o(clip_18b_max)]
+    mova                 m1, [r3+16*44] ; idct16 15 - n
+    pmaxsd               m0, m5
+    pminsd               m0, m6
+    paddd                m4, m0, m1     ; idct16 out0  + n
+    psubd                m0, m1         ; idct16 out15 - n
+    REPX     {pmaxsd x, m5}, m4, m0
+    REPX     {pminsd x, m6}, m4, m0
+    paddd                m1, m4, m3     ; idct32 out0  + n
+    psubd                m4, m3         ; idct32 out31 - n
+    paddd                m3, m0, m2     ; idct32 out15 - n
+    psubd                m0, m2         ; idct32 out16 + n
+    REPX     {pmaxsd x, m5}, m1, m4, m3, m0
+    REPX     {pminsd x, m6}, m1, m3, m4, m0
+    REPX     {paddd  x, m7}, m1, m3, m0, m4
+    mova                 m5, [r4-16* 4] ; idct64 63 - n
+    mova                 m6, [r3-16* 4] ; idct64 48 + n
+    paddd                m2, m1, m5     ; idct64 out0  + n (unshifted)
+    psubd                m1, m5         ; idct64 out63 - n (unshifted)
+    paddd                m5, m3, m6     ; idct64 out15 - n (unshifted)
+    psubd                m3, m6         ; idct64 out48 + n (unshifted)
+    mova         [r4+16*28], m1
+    mova         [r3+16*28], m3
+    mova                 m6, [r4-16*20] ; idct64 47 - n
+    mova                 m1, [r3-16*20] ; idct64 32 + n
+    mova         [r3-16*20], m2
+    mova         [r4-16*20], m5
+    paddd                m5, m0, m6     ; idct64 out16 + n (unshifted)
+    psubd                m0, m6         ; idct64 out47 - n (unshifted)
+    paddd                m6, m4, m1     ; idct64 out31 - n (unshifted)
+    psubd                m4, m1         ; idct64 out32 + n (unshifted)
+    mova         [r3-16* 4], m5
+    mova         [r4+16*12], m0
+    mova         [r4-16* 4], m6
+    mova         [r3+16*12], m4
+%endif
+    sub                  r4, 16
+    add                  r3, 16
+    cmp                  r3, r4
+    jl .main_end_loop
+    ret
+
+.shift_transpose:
+    mova                 m0, [r3+0*16]
+    mova                 m1, [r3+1*16]
+    mova                 m2, [r3+2*16]
+    mova                 m3, [r3+3*16]
+    mova                 m4, [r3+4*16]
+    mova                 m5, [r3+5*16]
+    mova                 m6, [r3+6*16]
+    mova                 m7, [r3+7*16]
+    REPX       {psrad x, 2}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova          [r4+0*64], m0
+    mova          [r4+1*64], m1
+    mova          [r4+2*64], m2
+    mova          [r4+3*64], m3
+    sub                  r4, 4*64
+    sub                  r3, 8*16
+    cmp                  r3, rsp
+    jg .shift_transpose
+    ret
+
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 16
+.dconly1:
+    add                 r5d, 640
+    sar                 r5d, 10
+.dconly2:
+    imul                r5d, 2896
+    add                 r5d, 34816
+    movd                 m0, r5d
+    pshuflw              m0, m0, q1111
+    punpcklqdq           m0, m0
+    mova                 m6, [o(pixel_10bpc_max)]
+    pxor                 m5, m5
+.dconly_loop:
+    paddw                m1, m0, [dstq+16*0]
+    paddw                m2, m0, [dstq+16*1]
+    paddw                m3, m0, [dstq+16*2]
+    paddw                m4, m0, [dstq+16*3]
+    REPX     {pmaxsw x, m5}, m1, m2, m3, m4
+    REPX     {pminsw x, m6}, m1, m2, m3, m4
+    mova        [dstq+16*0], m1
+    mova        [dstq+16*1], m2
+    mova        [dstq+16*2], m3
+    mova        [dstq+16*3], m4
+    add                dstq, 64
+    btc                 r3d, 16
+    jnc .dconly_loop
+    lea                dstq, [dstq+strideq-128]
+    dec                 r3d
+    jg .dconly_loop
+    RET
+
+cglobal inv_txfm_add_dct_dct_64x32_16bpc, 4, 7, 16, \
+                                         0-(1+64+8*ARCH_X86_32+8*32+1*WIN64)*16, \
+                                         dst, stride, c, eob
+    LEA                  r6, base
+    test               eobd, eobd
+    jz .dconly
+
+%if ARCH_X86_32
+    DECLARE_REG_TMP 0, 4, 1
+    mov [rsp+(8*32+64+8)*16+1*gprsize], dstq
+    mov [rsp+(8*32+64+8)*16+2*gprsize], strideq
+%else
+    DECLARE_REG_TMP 4, 7, 8
+%if WIN64
+    mov [rsp+(8*32+64+1)*16+1*gprsize], r7
+    mov [rsp+64*16+0*gprsize], r8
+%endif
+%endif
+%undef cmp
+    ; remove entirely-zero iterations
+    mov                 r5d, 14
+    cmp                eobw, word [o2(tbl_32x32_2d)+r5]
+    jge .end_zero_loop
+    pxor                 m0, m0
+.zero_loop:
+    movzx               t0d, word [o2(tbl_Nx32_odd_offset)+r5]
+    movzx               t1d, t0b
+    shr                 t0d, 8
+    lea                  t2, [rsp+7*32*16]
+.zero_loop_inner:
+    mova [t2+(64+8*ARCH_X86_32+1*WIN64)*16+r5*8], m0
+    mova [t2+(72+8*ARCH_X86_32+1*WIN64)*16+r5*8], m0
+    mova [t2+(64+8*ARCH_X86_32+1*WIN64)*16+t0*8], m0
+    mova [t2+(64+8*ARCH_X86_32+1*WIN64)*16+t1*8], m0
+    sub                  t2, 32*16
+    cmp                  t2, rsp
+    jge .zero_loop_inner
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_32x32_2d)+r5]
+    jl .zero_loop
+.end_zero_loop:
+    mov [rsp+(8*32+64+8*ARCH_X86_32+1*WIN64)*16+0*gprsize], eobd
+    ; actual first pass after skipping all-zero data
+.loop_pass1:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+
+    mov                  r3, rsp
+    lea                  r4, [o(idct64_mul_16bpc)]
+    mova                 m0, [cq+128* 1+r5*8]
+    mova                 m1, [cq+128*31+r5*8]
+    mova                 m2, [cq+128*17+r5*8]
+    mova                 m3, [cq+128*15+r5*8]
+    call .rect2_mul_fast
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part1
+    mova                 m0, [cq+128* 7+r5*8]
+    mova                 m1, [cq+128*25+r5*8]
+    mova                 m2, [cq+128*23+r5*8]
+    mova                 m3, [cq+128* 9+r5*8]
+    call .rect2_mul_fast
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part1
+    mova                 m0, [cq+128* 5+r5*8]
+    mova                 m1, [cq+128*27+r5*8]
+    mova                 m2, [cq+128*21+r5*8]
+    mova                 m3, [cq+128*11+r5*8]
+    call .rect2_mul_fast
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part1
+    mova                 m0, [cq+128* 3+r5*8]
+    mova                 m1, [cq+128*29+r5*8]
+    mova                 m2, [cq+128*19+r5*8]
+    mova                 m3, [cq+128*13+r5*8]
+    call .rect2_mul_fast
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part1
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part2
+
+    mova                 m0, [cq+128* 2+r5*8]
+    mova                 m1, [cq+128*14+r5*8]
+    mova                 m2, [cq+128*18+r5*8]
+    mova                 m3, [cq+128*30+r5*8]
+    call .rect2_mul_fast
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part1_fast
+
+    mova                 m0, [cq+128* 6+r5*8]
+    mova                 m1, [cq+128*10+r5*8]
+    mova                 m2, [cq+128*22+r5*8]
+    mova                 m3, [cq+128*26+r5*8]
+    call .rect2_mul_fast
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part2_fast
+    add                  r3, 16*(24+4*ARCH_X86_32)
+
+    mova                 m0, [cq+128* 4+r5*8]
+    mova                 m1, [cq+128*12+r5*8]
+    mova                 m2, [cq+128*20+r5*8]
+    mova                 m3, [cq+128*28+r5*8]
+    call .rect2_mul_fast
+    call m(idct_16x4_internal_16bpc).main_oddhalf_fast
+
+    mova                 m0, [cq+128* 0+r5*8]
+    mova                 m1, [cq+128* 8+r5*8]
+    mova                 m2, [cq+128*16+r5*8]
+    mova                 m3, [cq+128*24+r5*8]
+    call .rect2_mul_fast
+    call m(idct_8x4_internal_16bpc).main_pass1_fast
+    call m(idct_8x4_internal_16bpc).round
+    mova [r3-(7+4*ARCH_X86_32)*16], m1
+    mova [r3-(6+4*ARCH_X86_32)*16], m2
+    mova [r3-(5+4*ARCH_X86_32)*16], m3
+    mova [r3-(4+4*ARCH_X86_32)*16], m4
+    mova [r3-(3+4*ARCH_X86_32)*16], m5
+    mova [r3-(2+4*ARCH_X86_32)*16], m6
+    mova [r3-(1+4*ARCH_X86_32)*16], m7
+    sub                  r3, 16*(40+4*ARCH_X86_32-4)
+
+%if ARCH_X86_64
+    psrld               m15, m11, 11 ; pd_1
+%else
+    mova                 m7, [o(pd_1)]
+%endif
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_end_loop_start
+
+    lea                  r3, [rsp+56*16]
+    lea                  t2, [rsp+7*32*16+(64+8*ARCH_X86_32+1*WIN64)*16]
+    movzx               t0d, word [o2(tbl_Nx32_odd_offset)+r5]
+    movzx               t1d, t0b
+    shr                 t0d, 8
+    call .shift_transpose
+    ; zero cq
+    pxor                 m7, m7
+    lea                  r4, [cq+30*128+r5*8]
+.zero_cq_loop:
+    REPX {mova [r4+x*128], m7}, -2, -1, 0, 1
+    sub                  r4, 4*128
+    cmp                  r4, cq
+    jg .zero_cq_loop
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass=2 code starts here
+    mov                eobd, [rsp+gprsize*0+(8*32+64+8*ARCH_X86_32+1*WIN64)*16]
+%if ARCH_X86_32
+    mov             strideq, [rsp+gprsize*2+(8*32+64+8)*16]
+%elif WIN64
+    mov                  r8, [rsp+gprsize*0+64*16]
+%endif
+    add                 rsp, (64+8*ARCH_X86_32+1*WIN64-3)*16
+    cmp                eobd, 36
+    jl .load_veryfast
+    cmp                eobd, 136
+    jl .load_fast
+    ; load normal
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main)]
+    jmp .run
+.load_fast:
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_fast)]
+    jmp .run
+.load_veryfast:
+    lea                  r4, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_veryfast)]
+    ; fall-through
+.run:
+%if ARCH_X86_64
+    lea                  r2, [dstq+128]
+    mov                  r7, -16
+%else
+    lea                  r2, [rsp+(8*32+3)*16]
+    mov dword [r2+0*gprsize], 8
+%endif
+    jmp m(inv_txfm_add_dct_dct_16x32_16bpc).loop_pass2_entry
+
+.rect2_mul_fast:
+%if ARCH_X86_64
+    REPX    {pmulld x, m14}, m0, m1, m2, m3
+    REPX    {paddd  x, m11}, m0, m1, m2, m3
+%else
+    mova                 m4, [o(pd_2896)]
+    mova                 m5, [o(pd_2048)]
+    REPX    {pmulld x, m4 }, m0, m1, m2, m3
+    REPX    {paddd  x, m5 }, m0, m1, m2, m3
+%endif
+    REPX    {psrad  x, 12 }, m0, m1, m2, m3
+    ret
+
+.shift_transpose:
+    mova                 m0, [r3+0*16]
+    mova                 m1, [r3+1*16]
+    mova                 m2, [r3+2*16]
+    mova                 m3, [r3+3*16]
+    mova                 m4, [r3+4*16]
+    mova                 m5, [r3+5*16]
+    mova                 m6, [r3+6*16]
+    mova                 m7, [r3+7*16]
+    REPX       {psrad x, 1}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova     [t2+0*16+r5*8], m0
+    mova     [t2+8*16+r5*8], m2
+    mova     [t2+0*16+t0*8], m3
+    mova     [t2+0*16+t1*8], m1
+    sub                  t2, 16*32
+    sub                  r3, 8*16
+    cmp                  r3, rsp
+    jg .shift_transpose
+    ret
+
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 32
+    add                 r5d, 128
+    sar                 r5d, 8
+    imul                r5d, 181
+    add                 r5d, 384
+    sar                 r5d, 9
+    add                 rsp, (1+8*32+1*WIN64)*16
+    jmp m(inv_txfm_add_dct_dct_64x16_16bpc).dconly2
+
+cglobal inv_txfm_add_dct_dct_64x64_16bpc, 4, 7, 16, \
+                                         0-(64+8*ARCH_X86_32+8*64+1*ARCH_X86_64)*16-(4+4*ARCH_X86_32)*gprsize, \
+                                         dst, stride, c, eob
+    LEA                  r6, base
+    test               eobd, eobd
+    jz .dconly
+
+%if ARCH_X86_32
+    DECLARE_REG_TMP 4, 1, 2, 0, 6
+    mov [rsp+gprsize*1+(64*9+8)*16], r0
+    mov [rsp+gprsize*2+(64*9+8)*16], r1
+    mov [rsp+gprsize*3+(64*9+8)*16], r2
+    mov [rsp+gprsize*4+(64*9+8)*16], r6
+%else
+    DECLARE_REG_TMP 8, 9, 4, 7, 0
+    mov [rsp+gprsize*1+(64*9+1)*16], r9
+    mov [rsp+gprsize*0+64*16], r0
+%if WIN64
+    mov [rsp+gprsize*2+(64*9+1)*16], r7
+    mov [rsp+gprsize*3+(64*9+1)*16], r8
+%endif
+%endif
+%undef cmp
+
+    ; remove entirely-zero iterations
+    mov                 r5d, 14
+    cmp                eobw, word [o2(tbl_32x32_2d)+r5]
+    jge .end_zero_loop
+    pxor                 m0, m0
+.zero_loop:
+    movzx               t1d, word [o2(tbl_Nx64_offset)+r5*2+0]
+    movzx               t3d, word [o2(tbl_Nx64_offset)+r5*2+2]
+    movzx               t0d, t1b
+    movzx               t2d, t3b
+    shr                 t1d, 8
+    shr                 t3d, 8
+    lea                  t4, [rsp+7*64*16]
+.zero_loop_inner:
+    mova [t4+(64+8*ARCH_X86_32+1*ARCH_X86_64)*16+t0*8], m0
+    mova [t4+(64+8*ARCH_X86_32+1*ARCH_X86_64)*16+t1*8], m0
+    mova [t4+(64+8*ARCH_X86_32+1*ARCH_X86_64)*16+t2*8], m0
+    mova [t4+(64+8*ARCH_X86_32+1*ARCH_X86_64)*16+t3*8], m0
+    sub                  t4, 64*16
+    cmp                  t4, rsp
+    jge .zero_loop_inner
+%if ARCH_X86_32
+    mov                  r6, [rsp+gprsize*4+(64*9+8)*16]
+%endif
+    sub                 r5d, 2
+    cmp                eobw, word [o2(tbl_32x32_2d)+r5]
+    jl .zero_loop
+.end_zero_loop:
+    mov [rsp+gprsize*0+(9*64+8*ARCH_X86_32+1*ARCH_X86_64)*16], eobd
+%if ARCH_X86_32
+    mov                  cq, [rsp+gprsize*3+(64*9+8)*16]
+%endif
+    ; actual first pass after skipping all-zero data
+.loop_pass1:
+%if ARCH_X86_64
+    mova                m11, [o(pd_2048)]
+    mova                m12, [o(clip_18b_min)]
+    mova                m13, [o(clip_18b_max)]
+    mova                m14, [o(pd_2896)]
+%endif
+
+    mov                  r3, rsp
+    lea                  r4, [o(idct64_mul_16bpc)]
+    mova                 m0, [cq+128* 1+r5*8]
+    mova                 m1, [cq+128*31+r5*8]
+    mova                 m2, [cq+128*17+r5*8]
+    mova                 m3, [cq+128*15+r5*8]
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part1
+    mova                 m0, [cq+128* 7+r5*8]
+    mova                 m1, [cq+128*25+r5*8]
+    mova                 m2, [cq+128*23+r5*8]
+    mova                 m3, [cq+128* 9+r5*8]
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part1
+    mova                 m0, [cq+128* 5+r5*8]
+    mova                 m1, [cq+128*27+r5*8]
+    mova                 m2, [cq+128*21+r5*8]
+    mova                 m3, [cq+128*11+r5*8]
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part1
+    mova                 m0, [cq+128* 3+r5*8]
+    mova                 m1, [cq+128*29+r5*8]
+    mova                 m2, [cq+128*19+r5*8]
+    mova                 m3, [cq+128*13+r5*8]
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part1
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_part2
+
+    mova                 m0, [cq+128* 2+r5*8]
+    mova                 m1, [cq+128*14+r5*8]
+    mova                 m2, [cq+128*18+r5*8]
+    mova                 m3, [cq+128*30+r5*8]
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part1_fast
+
+    mova                 m0, [cq+128* 6+r5*8]
+    mova                 m1, [cq+128*10+r5*8]
+    mova                 m2, [cq+128*22+r5*8]
+    mova                 m3, [cq+128*26+r5*8]
+    call m(inv_txfm_add_dct_dct_32x8_16bpc).main_oddhalf_part2_fast
+    add                  r3, 16*(24+4*ARCH_X86_32)
+
+    mova                 m0, [cq+128* 4+r5*8]
+    mova                 m1, [cq+128*12+r5*8]
+    mova                 m2, [cq+128*20+r5*8]
+    mova                 m3, [cq+128*28+r5*8]
+    call m(idct_16x4_internal_16bpc).main_oddhalf_fast
+
+    mova                 m0, [cq+128* 0+r5*8]
+    mova                 m1, [cq+128* 8+r5*8]
+    mova                 m2, [cq+128*16+r5*8]
+    mova                 m3, [cq+128*24+r5*8]
+    call m(idct_8x4_internal_16bpc).main_pass1_fast
+    call m(idct_8x4_internal_16bpc).round
+    mova [r3-(7+4*ARCH_X86_32)*16], m1
+    mova [r3-(6+4*ARCH_X86_32)*16], m2
+    mova [r3-(5+4*ARCH_X86_32)*16], m3
+    mova [r3-(4+4*ARCH_X86_32)*16], m4
+    mova [r3-(3+4*ARCH_X86_32)*16], m5
+    mova [r3-(2+4*ARCH_X86_32)*16], m6
+    mova [r3-(1+4*ARCH_X86_32)*16], m7
+    sub                  r3, 16*(40+4*ARCH_X86_32-4)
+
+%if ARCH_X86_64
+    psrld               m15, m11, 10 ; pd_2
+%else
+    mova                 m7, [o(pd_2)]
+%endif
+    call m(inv_txfm_add_dct_dct_64x16_16bpc).main_end_loop_start
+
+    lea                  r3, [rsp+56*16]
+    movzx               t1d, word [o2(tbl_Nx64_offset)+r5*2+0]
+    movzx               t3d, word [o2(tbl_Nx64_offset)+r5*2+2]
+    movzx               t0d, t1b
+    movzx               t2d, t3b
+    shr                 t1d, 8
+    shr                 t3d, 8
+    lea                  t4, [rsp+7*64*16+(64+8*ARCH_X86_32+1*ARCH_X86_64)*16]
+    call .shift_transpose
+    ; zero cq
+    pxor                 m7, m7
+%if ARCH_X86_32
+    mov                  cq, [rsp+gprsize*3+(64*9+8)*16]
+%endif
+    lea                  r4, [cq+30*128+r5*8]
+.zero_cq_loop:
+    REPX {mova [r4+x*128], m7}, -2, -1, 0, 1
+    sub                  r4, 4*128
+    cmp                  r4, cq
+    jg .zero_cq_loop
+%if ARCH_X86_32
+    mov                  r6, [rsp+gprsize*4+(64*9+8)*16]
+%endif
+    sub                 r5d, 2
+    jge .loop_pass1
+
+    ; pass=2 code starts here
+    mov                eobd, [rsp+gprsize*0+(9*64+8*ARCH_X86_32+1*ARCH_X86_64)*16]
+%if ARCH_X86_32
+    mov             strideq, [rsp+gprsize*2+(9*64+8)*16]
+%else
+    mov                  r0, [rsp+gprsize*0+64*16]
+%endif
+    add                 rsp, (64+8*ARCH_X86_32+1*ARCH_X86_64-3)*16
+    cmp                eobd, 151
+    jl .fast
+    ; fall-through
+%if ARCH_X86_64
+    DECLARE_REG_TMP 8, 9
+%else
+    DECLARE_REG_TMP 1, 5
+%endif
+    lea                  t0, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_fast)]
+    lea                  t1, [o(m_suffix(idct_16x64_internal_8bpc, _ssse3).main)]
+    jmp .run
+.fast:
+    lea                  t0, [o(m_suffix(idct_8x32_internal_8bpc, _ssse3).main_veryfast)]
+    lea                  t1, [o(m_suffix(idct_16x64_internal_8bpc, _ssse3).main_fast)]
+.run:
+
+%if ARCH_X86_64
+    lea                  r2, [dstq+128]
+    mov                  r7, -16
+%else
+    lea                  r2, [rsp+(64*8+3)*16]
+    mov      [r2+4*gprsize], t0
+    mov      [r2+5*gprsize], t1
+    mov                  r1, [r2+2*gprsize]
+    mov dword [r2+0*gprsize], 8
+%endif
+    jmp m(inv_txfm_add_dct_dct_16x64_16bpc).loop_pass2
+
+    ; copy of pass=1 tmp-regs
+%if ARCH_X86_32
+    DECLARE_REG_TMP 4, 1, 2, 0, 6
+%else
+    DECLARE_REG_TMP 8, 9, 4, 7, 0
+%endif
+
+.shift_transpose:
+    mova                 m0, [r3+0*16]
+    mova                 m1, [r3+1*16]
+    mova                 m2, [r3+2*16]
+    mova                 m3, [r3+3*16]
+    mova                 m4, [r3+4*16]
+    mova                 m5, [r3+5*16]
+    mova                 m6, [r3+6*16]
+    mova                 m7, [r3+7*16]
+    REPX       {psrad x, 2}, m0, m1, m2, m3, m4, m5, m6, m7
+    packssdw             m0, m1
+    packssdw             m2, m3
+    packssdw             m4, m5
+    packssdw             m6, m7
+    call m(idct_8x4_internal_16bpc).transpose4x8packed
+    mova          [t4+t0*8], m0
+    mova          [t4+t1*8], m1
+    mova          [t4+t2*8], m2
+    mova          [t4+t3*8], m3
+    sub                  t4, 16*64
+    sub                  r3, 8*16
+    cmp                  r3, rsp
+    jg .shift_transpose
+    ret
+
+.dconly:
+    imul                r5d, [cq], 181
+    mov                [cq], eobd ; 0
+    mov                 r3d, 64
+    add                 rsp, (64+8*ARCH_X86_32+8*64+1*ARCH_X86_64)*16 + \
+                             (4+4*ARCH_X86_32)*gprsize - (64+8*ARCH_X86_32)*16
+    jmp m(inv_txfm_add_dct_dct_64x16_16bpc).dconly1
diff --git a/media/libdav1d/src/src/x86/itx_avx2.asm b/media/libdav1d/src/src/x86/itx_avx2.asm
new file mode 100644
index 0000000000..a67f053a61
--- /dev/null
+++ b/media/libdav1d/src/src/x86/itx_avx2.asm
@@ -0,0 +1,5542 @@
+; Copyright © 2018-2021, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 16
+
+; Note: The order of (at least some of) those constants matter!
+
+const deint_shuf, db  0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+
+%macro COEF_PAIR 2
+pw_%1_%2:  dw  %1, %2
+pw_m%2_%1: dw -%2, %1
+%endmacro
+
+; ADST-only
+pw_3803_1321:   dw  3803,  1321
+pw_m1321_2482:  dw -1321,  2482
+pw_2482_3344:   dw  2482,  3344
+pw_m3344_3344:  dw -3344,  3344
+pw_m3803_3344:  dw -3803,  3344
+pw_m3803_m6688: dw -3803, -6688
+pw_2896_m2896:  dw  2896, -2896
+
+const pw_5,       times 2 dw 5
+const pw_2048,    times 2 dw 2048
+const pw_4096,    times 2 dw 4096
+const pw_8192,    times 2 dw 8192
+const pw_16384,   times 2 dw 16384
+const pw_1697x16, times 2 dw 1697*16
+const pw_1697x8,  times 2 dw 1697*8
+const pw_2896x8,  times 2 dw 2896*8
+const pd_2048,    dd 2048
+
+const pw_2896_2896,  dw  2896, 2896
+const pw_m2896_2896, dw -2896, 2896
+const pw_1567_3784,  dw  1567, 3784
+const pw_m3784_1567, dw -3784, 1567
+COEF_PAIR 3784, 1567
+COEF_PAIR  201, 4091
+COEF_PAIR  995, 3973
+COEF_PAIR 1751, 3703
+COEF_PAIR 2440, 3290
+COEF_PAIR 3035, 2751
+COEF_PAIR 3513, 2106
+COEF_PAIR 3857, 1380
+COEF_PAIR 4052,  601
+COEF_PAIR  401, 4076
+COEF_PAIR 1931, 3612
+COEF_PAIR 3166, 2598
+COEF_PAIR 3920, 1189
+COEF_PAIR  799, 4017
+COEF_PAIR 3406, 2276
+pw_m799_m4017:  dw  -799, -4017
+const pw_m1567_m3784, dw -1567, -3784
+pw_m3406_m2276: dw -3406, -2276
+pw_m401_m4076:  dw  -401, -4076
+pw_m3166_m2598: dw -3166, -2598
+pw_m1931_m3612: dw -1931, -3612
+pw_m3920_m1189: dw -3920, -1189
+COEF_PAIR 2276, 3406
+COEF_PAIR 4017,  799
+
+%macro COEF_X8 1-*
+%rep %0
+    dw %1*8, %1*8
+    %rotate 1
+%endrep
+%endmacro
+
+pw_3703x8:  COEF_X8  3703
+pw_1751x8:  COEF_X8  1751
+pw_m1380x8: COEF_X8 -1380
+pw_3857x8:  COEF_X8  3857
+pw_3973x8:  COEF_X8  3973
+pw_995x8:   COEF_X8   995
+pw_m2106x8: COEF_X8 -2106
+pw_3513x8:  COEF_X8  3513
+pw_3290x8:  COEF_X8  3290
+pw_2440x8:  COEF_X8  2440
+pw_m601x8:  COEF_X8  -601
+pw_4052x8:  COEF_X8  4052
+
+const idct64_mul
+COEF_X8  4095,   101,  4065,   501,  2967, -2824,  3229, -2520
+COEF_X8  3745,  1660,  3564,  2019,  3822, -1474,  3948, -1092
+COEF_X8  3996,   897,  3889,  1285,  3461, -2191,  3659, -1842
+COEF_X8  3349,  2359,  3102,  2675,  4036,  -700,  4085,  -301
+
+pw_201_4091x8:   dw   201*8, 4091*8
+pw_m601_4052x8:  dw  -601*8, 4052*8
+pw_995_3973x8:   dw   995*8, 3973*8
+pw_m1380_3857x8: dw -1380*8, 3857*8
+pw_1751_3703x8:  dw  1751*8, 3703*8
+pw_m2106_3513x8: dw -2106*8, 3513*8
+pw_2440_3290x8:  dw  2440*8, 3290*8
+pw_m2751_3035x8: dw -2751*8, 3035*8
+
+%define o_idct64_offset idct64_mul - (o_base) - 8
+
+SECTION .text
+
+; Code size reduction trickery: Instead of using rip-relative loads with
+; mandatory 4-byte offsets everywhere, we can set up a base pointer with a
+; single rip-relative lea and then address things relative from that with
+; 1-byte offsets as long as data is within +-128 bytes of the base pointer.
+%define o_base deint_shuf + 128
+%define o(x) (r6 - (o_base) + (x))
+%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX)
+
+; flags: 1 = swap, 2 = interleave, 4: coef_regs
+%macro ITX_MUL2X_PACK 6-7 0 ; dst/src, tmp[1-2], rnd, coef[1-2], flags
+%if %7 & 4
+    pmaddwd             m%2, m%5, m%1
+    pmaddwd             m%1, m%6
+%else
+%if %7 & 1
+    vpbroadcastd        m%2, [o(pw_%5_%6)]
+    vpbroadcastd        m%3, [o(pw_m%6_%5)]
+%else
+    vpbroadcastd        m%2, [o(pw_m%6_%5)]
+    vpbroadcastd        m%3, [o(pw_%5_%6)]
+%endif
+    pmaddwd             m%2, m%1
+    pmaddwd             m%1, m%3
+%endif
+    paddd               m%2, m%4
+    paddd               m%1, m%4
+%if %7 & 2
+    pslld               m%2, 4
+    psrld               m%1, 12
+    pblendw             m%1, m%2, 0xaa
+%else
+    psrad               m%2, 12
+    psrad               m%1, 12
+    packssdw            m%1, m%2
+%endif
+%endmacro
+
+; flags: 1 = swap, 2 = interleave, 4 = coef_regs
+%macro ITX_MUL4X_PACK 9-10 0 ; dst/src, tmp[1-3], rnd, coef[1-4], flags
+%if %10 & 1
+    vpbroadcastd        m%3, [o(pw_%8_%9)]
+    vpbroadcastd        m%4, [o(pw_m%9_%8)]
+    vpbroadcastd       xm%2, [o(pw_%6_%7)]
+    vpblendd            m%2, m%3, 0xf0
+    vpbroadcastd       xm%3, [o(pw_m%7_%6)]
+%else
+    vpbroadcastd        m%3, [o(pw_m%9_%8)]
+    vpbroadcastd        m%4, [o(pw_%8_%9)]
+    vpbroadcastd       xm%2, [o(pw_m%7_%6)]
+    vpblendd            m%2, m%3, 0xf0
+    vpbroadcastd       xm%3, [o(pw_%6_%7)]
+%endif
+    vpblendd            m%3, m%4, 0xf0
+    ITX_MUL2X_PACK       %1, %4, _, %5, %2, %3, (4|%10)
+%endmacro
+
+; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12
+; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12
+%macro ITX_MULSUB_2W 7-8 ; dst/src[1-2], tmp[1-2], rnd, coef[1-2], dst2
+    punpckhwd           m%3, m%2, m%1
+    punpcklwd           m%2, m%1
+%if %7 < 32
+    pmaddwd             m%1, m%7, m%2
+    pmaddwd             m%4, m%7, m%3
+%else
+    vpbroadcastd        m%1, [o(pw_m%7_%6)]
+    pmaddwd             m%4, m%3, m%1
+    pmaddwd             m%1, m%2
+%endif
+    paddd               m%4, m%5
+    paddd               m%1, m%5
+    psrad               m%4, 12
+    psrad               m%1, 12
+    packssdw            m%1, m%4
+%if %7 < 32
+    pmaddwd             m%3, m%6
+    pmaddwd             m%2, m%6
+%else
+    vpbroadcastd        m%4, [o(pw_%6_%7)]
+    pmaddwd             m%3, m%4
+    pmaddwd             m%2, m%4
+%endif
+    paddd               m%3, m%5
+    paddd               m%2, m%5
+    psrad               m%3, 12
+    psrad               m%2, 12
+%if %0 == 8
+    packssdw            m%8, m%2, m%3
+%else
+    packssdw            m%2, m%3
+%endif
+%endmacro
+
+%macro IDCT4_1D 7 ; src[1-4], tmp[1-2], pd_2048
+    ITX_MULSUB_2W        %2, %4, %5, %6, %7, 1567, 3784, %5 ; t2, t3
+    ITX_MULSUB_2W        %1, %3, %4, %6, %7, 2896, 2896, %4 ; t1, t0
+    psubsw              m%3, m%1, m%2
+    paddsw              m%2, m%1
+    paddsw              m%1, m%4, m%5
+    psubsw              m%4, m%5
+%endmacro
+
+%macro IDCT8_1D 11 ; src[1-8], tmp[1-2], pd_2048
+    ITX_MULSUB_2W        %6, %4, %9, %10, %11, 3406, 2276 ; t5a, t6a
+    ITX_MULSUB_2W        %2, %8, %9, %10, %11,  799, 4017 ; t4a, t7a
+    ITX_MULSUB_2W        %3, %7, %9, %10, %11, 1567, 3784 ; t2, t3
+    paddsw              m%9, m%2, m%6  ; t4
+    psubsw              m%2, m%6       ; t5a
+    paddsw             m%10, m%8, m%4  ; t7
+    psubsw              m%8, m%4       ; t6a
+    ITX_MULSUB_2W        %1, %5, %4, %6, %11, 2896, 2896 ; t1, t0
+    ITX_MULSUB_2W        %8, %2, %4, %6, %11, 2896, 2896 ; t5, t6
+    psubsw              m%6, m%1, m%3  ; dct4 out2
+    paddsw              m%3, m%1       ; dct4 out1
+    paddsw              m%1, m%5, m%7  ; dct4 out0
+    psubsw              m%5, m%7       ; dct4 out3
+    psubsw              m%7, m%3, m%2  ; out6
+    paddsw              m%2, m%3       ; out1
+    paddsw              m%3, m%6, m%8  ; out2
+    psubsw              m%6, m%8       ; out5
+    psubsw              m%8, m%1, m%10 ; out7
+    paddsw              m%1, m%10      ; out0
+    paddsw              m%4, m%5, m%9  ; out3
+    psubsw              m%5, m%9       ; out4
+%endmacro
+
+; in1 = %1, in3  = %2, in5  = %3, in7  = %4
+; in9 = %5, in11 = %6, in13 = %7, in15 = %8
+%macro IDCT16_1D_ODDHALF 11 ; src[1-8], tmp[1-2], pd_2048
+    ITX_MULSUB_2W        %1, %8, %9, %10, %11,  401, 4076 ; t8a,  t15a
+    ITX_MULSUB_2W        %5, %4, %9, %10, %11, 3166, 2598 ; t9a,  t14a
+    ITX_MULSUB_2W        %3, %6, %9, %10, %11, 1931, 3612 ; t10a, t13a
+    ITX_MULSUB_2W        %7, %2, %9, %10, %11, 3920, 1189 ; t11a, t12a
+    psubsw              m%9, m%2, m%6 ; t13
+    paddsw              m%6, m%2      ; t12
+    psubsw              m%2, m%8, m%4 ; t14
+    paddsw              m%8, m%4      ; t15
+    psubsw              m%4, m%7, m%3 ; t10
+    paddsw              m%3, m%7      ; t11
+    psubsw              m%7, m%1, m%5 ; t9
+    paddsw              m%1, m%5      ; t8
+    ITX_MULSUB_2W        %2, %7, %5, %10, %11,  1567, 3784 ; t9a,  t14a
+    ITX_MULSUB_2W        %9, %4, %5, %10, %11, m3784, 1567 ; t10a, t13a
+    psubsw              m%5, m%1, m%3 ; t11a
+    paddsw              m%1, m%3      ; t8a
+    psubsw              m%3, m%7, m%4 ; t13
+    paddsw              m%7, m%4      ; t14
+    psubsw              m%4, m%8, m%6 ; t12a
+    paddsw              m%8, m%6      ; t15a
+    psubsw              m%6, m%2, m%9 ; t10
+    paddsw              m%2, m%9      ; t9
+    ITX_MULSUB_2W        %3, %6, %9, %10, %11, 2896, 2896 ; t10a, t13a
+    ITX_MULSUB_2W        %4, %5, %9, %10, %11, 2896, 2896 ; t11,  t12
+%endmacro
+
+%macro WRAP_XMM 1+
+    INIT_XMM cpuname
+    %1
+    INIT_YMM cpuname
+%endmacro
+
+%macro ITX4_END 4-5 2048 ; row[1-4], rnd
+%if %5
+    vpbroadcastd         m2, [o(pw_%5)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+%endif
+    lea                  r2, [dstq+strideq*2]
+%assign %%i 1
+%rep 4
+    %if %1 & 2
+        CAT_XDEFINE %%row_adr, %%i, r2   + strideq*(%1&1)
+    %else
+        CAT_XDEFINE %%row_adr, %%i, dstq + strideq*(%1&1)
+    %endif
+    %assign %%i %%i + 1
+    %rotate 1
+%endrep
+    movd                 m2, [%%row_adr1]
+    pinsrd               m2, [%%row_adr2], 1
+    movd                 m3, [%%row_adr3]
+    pinsrd               m3, [%%row_adr4], 1
+    pmovzxbw             m2, m2
+    pmovzxbw             m3, m3
+    paddw                m0, m2
+    paddw                m1, m3
+    packuswb             m0, m1
+    movd       [%%row_adr1], m0
+    pextrd     [%%row_adr2], m0, 1
+    pextrd     [%%row_adr3], m0, 2
+    pextrd     [%%row_adr4], m0, 3
+    ret
+%endmacro
+
+%macro IWHT4_1D_PACKED 0
+    punpckhqdq           m3, m0, m1 ; in1 in3
+    punpcklqdq           m0, m1     ; in0 in2
+    psubw                m2, m0, m3
+    paddw                m0, m3
+    punpckhqdq           m2, m2     ; t2 t2
+    punpcklqdq           m0, m0     ; t0 t0
+    psubw                m1, m0, m2
+    psraw                m1, 1
+    psubw                m1, m3     ; t1 t3
+    psubw                m0, m1     ; ____ out0
+    paddw                m2, m1     ; out3 ____
+%endmacro
+
+INIT_XMM avx2
+cglobal inv_txfm_add_wht_wht_4x4_8bpc, 3, 3, 4, dst, stride, c
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    pxor                 m2, m2
+    mova          [cq+16*0], m2
+    mova          [cq+16*1], m2
+    psraw                m0, 2
+    psraw                m1, 2
+    IWHT4_1D_PACKED
+    punpckhwd            m0, m1
+    punpcklwd            m3, m1, m2
+    punpckhdq            m1, m0, m3
+    punpckldq            m0, m3
+    IWHT4_1D_PACKED
+    vpblendd             m0, m2, 0x03
+    ITX4_END              3, 0, 2, 1, 0
+
+%macro INV_TXFM_FN 3 ; type1, type2, size
+cglobal inv_txfm_add_%1_%2_%3_8bpc, 4, 5, 0, dst, stride, c, eob, tx2
+    %define %%p1 m(i%1_%3_internal_8bpc)
+    lea                  r6, [o_base]
+    ; Jump to the 1st txfm function if we're not taking the fast path, which
+    ; in turn performs an indirect jump to the 2nd txfm function.
+    lea                tx2q, [m(i%2_%3_internal_8bpc).pass2]
+%ifidn %1_%2, dct_dct
+    test               eobd, eobd
+    jnz %%p1
+%else
+    ; jump to the 1st txfm function unless it's located directly after this
+    times ((%%end - %%p1) >> 31) & 1 jmp %%p1
+ALIGN function_align
+%%end:
+%endif
+%endmacro
+
+%macro INV_TXFM_4X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x4
+%ifidn %1_%2, dct_dct
+    vpbroadcastw         m0, [cq]
+    vpbroadcastd         m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1
+    mov                [cq], eobd ; 0
+    pmulhrsw             m0, m1
+    mova                 m1, m0
+    jmp m(iadst_4x4_internal_8bpc).end2
+%endif
+%endmacro
+
+%macro IDCT4_1D_PACKED 0
+    vpbroadcastd         m4, [o(pd_2048)]
+    punpckhwd            m2, m1, m0
+    punpcklwd            m1, m0
+    ITX_MUL2X_PACK        2, 0, 3, 4, 1567, 3784
+    ITX_MUL2X_PACK        1, 0, 3, 4, 2896, 2896
+    paddsw               m0, m1, m2 ; out0 out1
+    psubsw               m1, m2     ; out3 out2
+%endmacro
+
+%macro IADST4_1D_PACKED 0
+    punpcklwd            m2, m1, m0
+    punpckhwd            m3, m1, m0
+    vpbroadcastd         m5, [o(pw_m3344_3344)]
+    vpbroadcastd         m0, [o(pw_3803_1321)]
+    vpbroadcastd         m4, [o(pw_m1321_2482)]
+    pmaddwd              m1, m5, m2 ; 3344*in3 - 3344*in2
+    psrld                m5, 16
+    pmaddwd              m0, m2
+    pmaddwd              m2, m4
+    pmaddwd              m5, m3 ; 3344*in0
+    paddd                m1, m5 ; 3344*in0 - 3344*in2 + 3344*in3
+    vpbroadcastd         m4, [o(pw_2482_3344)]
+    vpbroadcastd         m5, [o(pw_m3803_3344)]
+    pmaddwd              m4, m3
+    pmaddwd              m5, m3
+    paddd                m4, m0 ; 1321*in0 + 3344*in1 + 3803*in2 + 2482*in3
+    vpbroadcastd         m0, [o(pw_m3803_m6688)]
+    pmaddwd              m3, m0
+    vpbroadcastd         m0, [o(pd_2048)]
+    paddd                m2, m0
+    paddd                m1, m0
+    paddd                m0, m4
+    paddd                m5, m2 ; 2482*in0 + 3344*in1 - 1321*in2 - 3803*in3
+    paddd                m2, m4
+    paddd                m2, m3
+    REPX      {psrad x, 12}, m1, m2, m0, m5
+    packssdw             m0, m5 ; out0 out1
+    packssdw             m1, m2 ; out2 out3
+%endmacro
+
+INV_TXFM_4X4_FN dct, dct
+INV_TXFM_4X4_FN dct, adst
+INV_TXFM_4X4_FN dct, flipadst
+INV_TXFM_4X4_FN dct, identity
+
+cglobal idct_4x4_internal_8bpc, 0, 5, 6, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    IDCT4_1D_PACKED
+    mova                 m2, [o(deint_shuf)]
+    shufps               m3, m0, m1, q1331
+    shufps               m0, m1, q0220
+    pshufb               m0, m2
+    pshufb               m1, m3, m2
+    jmp                tx2q
+.pass2:
+    IDCT4_1D_PACKED
+    pxor                 m2, m2
+    mova          [cq+16*0], m2
+    mova          [cq+16*1], m2
+    ITX4_END              0, 1, 3, 2
+
+INV_TXFM_4X4_FN adst, dct
+INV_TXFM_4X4_FN adst, adst
+INV_TXFM_4X4_FN adst, flipadst
+INV_TXFM_4X4_FN adst, identity
+
+cglobal iadst_4x4_internal_8bpc, 0, 5, 6, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    call .main
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    jmp                tx2q
+.pass2:
+    call .main
+.end:
+    pxor                 m2, m2
+    mova          [cq+16*0], m2
+    mova          [cq+16*1], m2
+.end2:
+    ITX4_END              0, 1, 2, 3
+ALIGN function_align
+cglobal_label .main
+    IADST4_1D_PACKED
+    ret
+
+INV_TXFM_4X4_FN flipadst, dct
+INV_TXFM_4X4_FN flipadst, adst
+INV_TXFM_4X4_FN flipadst, flipadst
+INV_TXFM_4X4_FN flipadst, identity
+
+cglobal iflipadst_4x4_internal_8bpc, 0, 5, 6, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    call m(iadst_4x4_internal_8bpc).main
+    punpcklwd            m2, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    jmp                tx2q
+.pass2:
+    call m(iadst_4x4_internal_8bpc).main
+.end:
+    pxor                 m2, m2
+    mova          [cq+16*0], m2
+    mova          [cq+16*1], m2
+.end2:
+    ITX4_END              3, 2, 1, 0
+
+INV_TXFM_4X4_FN identity, dct
+INV_TXFM_4X4_FN identity, adst
+INV_TXFM_4X4_FN identity, flipadst
+INV_TXFM_4X4_FN identity, identity
+
+cglobal iidentity_4x4_internal_8bpc, 0, 5, 6, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    vpbroadcastd         m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    jmp m(iadst_4x4_internal_8bpc).end
+
+%macro WRITE_4X8 2 ; coefs[1-2]
+    movd                xm4, [dstq+strideq*0]
+    pinsrd              xm4, [dstq+strideq*1], 1
+    movd                xm5, [dstq+strideq*2]
+    pinsrd              xm5, [dstq+r3       ], 1
+    pinsrd              xm4, [r2  +strideq*0], 2
+    pinsrd              xm4, [r2  +strideq*1], 3
+    pinsrd              xm5, [r2  +strideq*2], 2
+    pinsrd              xm5, [r2  +r3       ], 3
+    pmovzxbw             m4, xm4
+    pmovzxbw             m5, xm5
+    paddw                m4, m%1
+    paddw                m5, m%2
+    packuswb             m4, m5
+    vextracti128        xm5, m4, 1
+    movd   [dstq+strideq*0], xm4
+    pextrd [dstq+strideq*1], xm4, 1
+    pextrd [dstq+strideq*2], xm4, 2
+    pextrd [dstq+r3       ], xm4, 3
+    movd   [r2  +strideq*0], xm5
+    pextrd [r2  +strideq*1], xm5, 1
+    pextrd [r2  +strideq*2], xm5, 2
+    pextrd [r2  +r3       ], xm5, 3
+%endmacro
+
+%macro INV_TXFM_4X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x8
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_2048)]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm1
+    pmulhrsw            xm0, xm1
+    pmulhrsw            xm0, xm2
+    vpbroadcastw         m0, xm0
+    mova                 m1, m0
+    jmp m(iadst_4x8_internal_8bpc).end3
+%endif
+%endmacro
+
+%macro IDCT8_1D_PACKED 0
+    vpbroadcastd         m6, [o(pd_2048)]
+    punpckhwd            m5, m3, m0 ; in7 in1
+    punpckhwd            m4, m1, m2 ; in3 in5
+    punpcklwd            m3, m1     ; in6 in2
+    punpcklwd            m2, m0     ; in4 in0
+    ITX_MUL2X_PACK        5, 0, 1, 6,  799, 4017, 3 ; t4a t7a
+    ITX_MUL2X_PACK        4, 0, 1, 6, 3406, 2276, 3 ; t5a t6a
+    ITX_MUL2X_PACK        3, 0, 1, 6, 1567, 3784    ; t3 t2
+    psubsw               m0, m5, m4 ; t5a t6a (interleaved)
+    paddsw               m4, m5     ; t4  t7  (interleaved)
+    ITX_MUL2X_PACK        2, 1, 5, 6, 2896, 2896    ; t0 t1
+    vpbroadcastd         m1, [o(pw_m2896_2896)]
+    ITX_MUL2X_PACK        0, 1, _, 6, 1, 5, 4 ; t6 t5
+%if mmsize > 16
+    vbroadcasti128       m1, [o(deint_shuf)]
+    pshufb               m4, m1
+%else
+    pshufb               m4, [o(deint_shuf)]
+%endif
+    psubsw               m1, m2, m3 ; tmp3 tmp2
+    paddsw               m3, m2     ; tmp0 tmp1
+    shufps               m2, m4, m0, q1032 ; t7 t6
+    vpblendd             m4, m0, 0xcc      ; t4 t5
+    paddsw               m0, m3, m2 ; out0 out1
+    psubsw               m3, m2     ; out7 out6
+    psubsw               m2, m1, m4 ; out4 out5
+    paddsw               m1, m4     ; out3 out2
+%endmacro
+
+%macro IADST8_1D_PACKED 1 ; pass
+    vpbroadcastd         m6, [o(pd_2048)]
+    punpckhwd            m0, m4, m3 ; 0 7
+    punpckhwd            m1, m5, m2 ; 2 5
+    punpcklwd            m2, m5     ; 4 3
+    punpcklwd            m3, m4     ; 6 1
+%if %1 == 1
+    ITX_MUL2X_PACK        0, 4, 5, 6,  401, 4076, 3 ; t1a t0a
+    ITX_MUL2X_PACK        1, 4, 5, 6, 1931, 3612, 2 ; t2a t3a
+    ITX_MUL2X_PACK        2, 4, 5, 6, 3166, 2598, 3 ; t5a t4a
+    ITX_MUL2X_PACK        3, 4, 5, 6, 3920, 1189, 2 ; t6a t7a
+    psubsw               m4, m0, m2 ; t5 t4
+    paddsw               m0, m2     ; t1 t0
+    psubsw               m5, m1, m3 ; t6 t7
+    paddsw               m1, m3     ; t2 t3
+    ITX_MUL2X_PACK        4, 2, 3, 6, 1567, 3784, 3 ; t5a t4a
+    ITX_MUL2X_PACK        5, 2, 3, 6, 3784, 1567, 2 ; t7a t6a
+%if mmsize > 16
+    vbroadcasti128       m2, [o(deint_shuf)]
+%else
+    mova                 m2, [o(deint_shuf)]
+%endif
+    pshuflw              m1, m1, q2301
+    pshufhw              m1, m1, q2301
+    psubsw               m3, m0, m1        ; t3 t2
+    paddsw               m0, m1            ; -out7  out0
+    psubsw               m1, m4, m5        ; t7 t6
+    paddsw               m4, m5            ;  out6 -out1
+    pshufb               m0, m2
+    pshufb               m4, m2
+    vpbroadcastd         m5, [o(pw_m2896_2896)]
+    pmaddwd              m2, m5, m3
+    pmaddwd              m5, m1
+    paddd                m2, m6
+    paddd                m5, m6
+    psrad                m2, 12
+    psrad                m5, 12
+    packssdw             m2, m5            ; out4 -out5
+    vpbroadcastd         m5, [o(pw_2896_2896)]
+    pmaddwd              m3, m5
+    pmaddwd              m1, m5
+    paddd                m3, m6
+    paddd                m1, m6
+    psrad                m3, 12
+    psrad                m1, 12
+    packssdw             m1, m3            ; out2 -out3
+    punpcklqdq           m3, m4, m0        ; out6 -out7
+    punpckhqdq           m0, m4            ; out0 -out1
+%else
+    ITX_MUL2X_PACK        0, 4, 5, 6,  401, 4076 ; t0a t1a
+    ITX_MUL2X_PACK        1, 4, 5, 6, 1931, 3612 ; t2a t3a
+    ITX_MUL2X_PACK        2, 4, 5, 6, 3166, 2598 ; t4a t5a
+    ITX_MUL2X_PACK        3, 4, 5, 6, 3920, 1189 ; t6a t7a
+    psubsw               m4, m0, m2 ; t4 t5
+    paddsw               m0, m2     ; t0 t1
+    psubsw               m5, m1, m3 ; t6 t7
+    paddsw               m1, m3     ; t2 t3
+    shufps               m2, m5, m4, q1032
+    punpckhwd            m4, m2
+    punpcklwd            m5, m2
+    ITX_MUL2X_PACK        4, 2, 3, 6, 1567, 3784, 1 ; t5a t4a
+    ITX_MUL2X_PACK        5, 2, 3, 6, 3784, 1567    ; t7a t6a
+    psubsw               m2, m0, m1        ; t2 t3
+    paddsw               m0, m1            ; out0 -out7
+    psubsw               m1, m4, m5        ; t7 t6
+    paddsw               m4, m5            ; out6 -out1
+    vpbroadcastd         m5, [o(pw_2896x8)]
+    vpblendd             m3, m0, m4, 0x33  ; out6 -out7
+    vpblendd             m0, m4, 0xcc      ; out0 -out1
+    shufps               m4, m2, m1, q1032 ; t3 t7
+    vpblendd             m1, m2, 0x33      ; t2 t6
+    psubsw               m2, m1, m4        ; t2-t3 t6-t7
+    paddsw               m1, m4            ; t2+t3 t6+t7
+    pmulhrsw             m2, m5            ; out4 -out5
+    pshufd               m1, m1, q1032
+    pmulhrsw             m1, m5            ; out2 -out3
+%endif
+%endmacro
+
+INIT_YMM avx2
+INV_TXFM_4X8_FN dct, dct
+INV_TXFM_4X8_FN dct, adst
+INV_TXFM_4X8_FN dct, flipadst
+INV_TXFM_4X8_FN dct, identity
+
+cglobal idct_4x8_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q3120
+    vpermq               m1, [cq+32*1], q3120
+    vpbroadcastd         m2, [o(pw_2896x8)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    IDCT4_1D_PACKED
+    vbroadcasti128       m2, [o(deint_shuf)]
+    shufps               m3, m0, m1, q1331
+    shufps               m0, m1, q0220
+    pshufb               m0, m2
+    pshufb               m1, m3, m2
+    jmp                tx2q
+.pass2:
+    vextracti128        xm2, m0, 1
+    vextracti128        xm3, m1, 1
+    call .main
+    vpbroadcastd         m4, [o(pw_2048)]
+    vinserti128          m0, xm2, 1
+    vinserti128          m1, xm3, 1
+    pshufd               m1, m1, q1032
+    jmp m(iadst_4x8_internal_8bpc).end2
+ALIGN function_align
+cglobal_label .main
+    WRAP_XMM IDCT8_1D_PACKED
+    ret
+
+INV_TXFM_4X8_FN adst, dct
+INV_TXFM_4X8_FN adst, adst
+INV_TXFM_4X8_FN adst, flipadst
+INV_TXFM_4X8_FN adst, identity
+
+cglobal iadst_4x8_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q3120
+    vpermq               m1, [cq+32*1], q3120
+    vpbroadcastd         m2, [o(pw_2896x8)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    call m(iadst_8x4_internal_8bpc).main
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    jmp                tx2q
+.pass2:
+    vextracti128        xm2, m0, 1
+    vextracti128        xm3, m1, 1
+    pshufd              xm4, xm0, q1032
+    pshufd              xm5, xm1, q1032
+    call .main_pass2
+    vpbroadcastd         m4, [o(pw_2048)]
+    vinserti128          m0, xm2, 1
+    vinserti128          m1, xm3, 1
+    pxor                 m5, m5
+    psubw                m5, m4
+.end:
+    vpblendd             m4, m5, 0xcc
+.end2:
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    WIN64_RESTORE_XMM
+    pxor                 m2, m2
+    mova          [cq+32*0], m2
+    mova          [cq+32*1], m2
+.end3:
+    lea                  r2, [dstq+strideq*4]
+    lea                  r3, [strideq*3]
+    WRITE_4X8             0, 1
+    RET
+ALIGN function_align
+.main_pass1:
+    WRAP_XMM IADST8_1D_PACKED 1
+    ret
+ALIGN function_align
+cglobal_label .main_pass2
+    WRAP_XMM IADST8_1D_PACKED 2
+    ret
+
+INV_TXFM_4X8_FN flipadst, dct
+INV_TXFM_4X8_FN flipadst, adst
+INV_TXFM_4X8_FN flipadst, flipadst
+INV_TXFM_4X8_FN flipadst, identity
+
+cglobal iflipadst_4x8_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q3120
+    vpermq               m1, [cq+32*1], q3120
+    vpbroadcastd         m2, [o(pw_2896x8)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    call m(iadst_8x4_internal_8bpc).main
+    punpcklwd            m3, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m1, m3
+    punpckhwd            m1, m3
+    jmp                tx2q
+.pass2:
+    vextracti128        xm2, m0, 1
+    vextracti128        xm3, m1, 1
+    pshufd              xm4, xm0, q1032
+    pshufd              xm5, xm1, q1032
+    call m(iadst_4x8_internal_8bpc).main_pass2
+    vpbroadcastd         m5, [o(pw_2048)]
+    vinserti128          m3, xm1, 1
+    vinserti128          m2, xm0, 1
+    pxor                 m4, m4
+    psubw                m4, m5
+    pshufd               m0, m3, q1032
+    pshufd               m1, m2, q1032
+    jmp m(iadst_4x8_internal_8bpc).end
+
+INV_TXFM_4X8_FN identity, dct
+INV_TXFM_4X8_FN identity, adst
+INV_TXFM_4X8_FN identity, flipadst
+INV_TXFM_4X8_FN identity, identity
+
+cglobal iidentity_4x8_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpermq               m2, [cq+32*0], q3120
+    vpermq               m0, [cq+32*1], q3120
+    vpbroadcastd         m3, [o(pw_2896x8)]
+    vpbroadcastd         m4, [o(pw_1697x8)]
+    punpcklwd            m1, m2, m0
+    punpckhwd            m2, m0
+    pmulhrsw             m1, m3
+    pmulhrsw             m2, m3
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    pmulhrsw             m2, m4, m0
+    pmulhrsw             m4, m1
+    paddsw               m0, m2
+    paddsw               m1, m4
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m4, [o(pw_4096)]
+    jmp m(iadst_4x8_internal_8bpc).end2
+
+%macro INV_TXFM_4X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x16
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    movd                xm3, [o(pw_2048)]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm2
+    pmulhrsw            xm0, xm1
+    pmulhrsw            xm0, xm3
+    vpbroadcastw         m0, xm0
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+    jmp m(iadst_4x16_internal_8bpc).end3
+%endif
+%endmacro
+
+%macro IDCT16_1D_PACKED 0
+    vpbroadcastd        m10, [o(pd_2048)]
+.main2:
+    punpckhwd            m8, m7, m0 ; dct16 in15 in1
+    punpcklwd            m9, m4, m0 ; dct4  in2  in0
+    punpckhwd            m0, m3, m4 ; dct16 in7  in9
+    punpcklwd            m7, m1     ; dct8  in7  in1
+    punpckhwd            m1, m6     ; dct16 in3  in13
+    punpcklwd            m3, m5     ; dct8  in3  in5
+    punpckhwd            m5, m2     ; dct16 in11 in5
+    punpcklwd            m6, m2     ; dct4  in3  in1
+    ITX_MUL2X_PACK        8, 2, 4, 10,  401, 4076, 3 ; t8a  t15a
+    ITX_MUL2X_PACK        0, 2, 4, 10, 3166, 2598, 3 ; t9a  t14a
+    ITX_MUL2X_PACK        1, 2, 4, 10, 3920, 1189, 3 ; t11a t12a
+    ITX_MUL2X_PACK        5, 2, 4, 10, 1931, 3612, 3 ; t10a t13a
+    ITX_MUL2X_PACK        7, 2, 4, 10,  799, 4017, 3 ; t4a  t7a
+    ITX_MUL2X_PACK        3, 2, 4, 10, 3406, 2276, 3 ; t5a  t6a
+    ITX_MUL2X_PACK        6, 2, 4, 10, 1567, 3784    ; t3   t2
+    psubsw               m2, m8, m0 ; t9  t14
+    paddsw               m8, m0     ; t8  t15
+    psubsw               m0, m1, m5 ; t10 t13
+    paddsw               m1, m5     ; t11 t12
+    vpbroadcastd         m5, [o(pw_m3784_1567)]  ; reuse pw_1567_3784
+    ITX_MUL2X_PACK        2, 4, _, 10, 4, 5, 6   ; t9a  t14a
+    vpbroadcastd         m4, [o(pw_m1567_m3784)] ; reuse pw_m3784_1567
+    ITX_MUL2X_PACK        0, 5, _, 10, 5, 4, 6   ; t10a t13a
+    psubsw               m4, m8, m1 ; t11a t12a
+    paddsw               m8, m1     ; t8a  t15a
+    psubsw               m1, m7, m3 ; t5a  t6a
+    paddsw               m7, m3     ; t4   t7
+    paddsw               m3, m2, m0 ; t9   t14
+    psubsw               m2, m0     ; t10  t13
+%if mmsize > 16
+    vbroadcasti128       m0, [o(deint_shuf)]
+%else
+    mova                 m0, [o(deint_shuf)]
+%endif
+    pshufb               m8, m0
+    pshufb               m7, m0
+    pshufb               m3, m0
+    ITX_MUL2X_PACK        9, 0, 5, 10, 2896, 2896 ; t0   t1
+    vpbroadcastd         m0, [o(pw_m2896_2896)]
+    ITX_MUL2X_PACK        4, 5, _, 10, 5, 0, 4    ; t11  t12
+    vpbroadcastd         m5, [o(pw_2896_2896)]
+    ITX_MUL2X_PACK        1, 0, _, 10, 0, 5, 4    ; t6   t5
+    vpbroadcastd         m0, [o(pw_m2896_2896)]
+    ITX_MUL2X_PACK        2, 0, _, 10, 0, 5, 4    ; t13a t10a
+    punpckhqdq           m0, m8, m3        ; t15a t14
+    punpcklqdq           m8, m3            ; t8a  t9
+    shufps               m5, m4, m2, q1032 ; t12  t13a
+    vpblendd             m4, m2, 0xcc      ; t11  t10a
+    shufps               m2, m7, m1, q1032 ; t7 t6
+    vpblendd             m7, m1, 0xcc      ; t4 t5
+    psubsw               m1, m9, m6 ; dct4 out3 out2
+    paddsw               m9, m6     ; dct4 out0 out1
+    psubsw               m3, m9, m2 ; dct8 out7 out6
+    paddsw               m9, m2     ; dct8 out0 out1
+    psubsw               m2, m1, m7 ; dct8 out4 out5
+    paddsw               m1, m7     ; dct8 out3 out2
+    psubsw               m7, m9, m0 ; out15 out14
+    paddsw               m0, m9     ; out0  out1
+    psubsw               m6, m1, m5 ; out12 out13
+    paddsw               m1, m5     ; out3  out2
+    psubsw               m5, m2, m4 ; out11 out10
+    paddsw               m2, m4     ; out4  out5
+    psubsw               m4, m3, m8 ; out8  out9
+    paddsw               m3, m8     ; out7  out6
+%endmacro
+
+INV_TXFM_4X16_FN dct, dct
+INV_TXFM_4X16_FN dct, adst
+INV_TXFM_4X16_FN dct, flipadst
+INV_TXFM_4X16_FN dct, identity
+
+cglobal idct_4x16_internal_8bpc, 0, 5, 11, dst, stride, c, eob, tx2
+    mova                 m0, [cq+32*0]
+    mova                 m1, [cq+32*1]
+    mova                 m2, [cq+32*2]
+    mova                 m3, [cq+32*3]
+    call m(idct_16x4_internal_8bpc).main
+    vpbroadcastd         m5, [o(pw_16384)]
+    punpckhwd            m4, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+    REPX   {pmulhrsw x, m5}, m0, m4, m2, m3
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    jmp                tx2q
+.pass2:
+    vextracti128        xm4, m0, 1
+    vextracti128        xm5, m1, 1
+    vextracti128        xm6, m2, 1
+    vextracti128        xm7, m3, 1
+    call .main
+    vinserti128          m0, xm4, 1
+    vinserti128          m1, xm5, 1
+    vpbroadcastd         m5, [o(pw_2048)]
+    vinserti128          m2, xm6, 1
+    vinserti128          m3, xm7, 1
+    pshufd               m1, m1, q1032
+    pshufd               m3, m3, q1032
+    jmp m(iadst_4x16_internal_8bpc).end2
+ALIGN function_align
+cglobal_label .main
+    WRAP_XMM IDCT16_1D_PACKED
+    ret
+
+INV_TXFM_4X16_FN adst, dct
+INV_TXFM_4X16_FN adst, adst
+INV_TXFM_4X16_FN adst, flipadst
+INV_TXFM_4X16_FN adst, identity
+
+cglobal iadst_4x16_internal_8bpc, 0, 5, 11, dst, stride, c, eob, tx2
+    mova                 m0, [cq+32*0]
+    mova                 m1, [cq+32*1]
+    mova                 m2, [cq+32*2]
+    mova                 m3, [cq+32*3]
+    call m(iadst_16x4_internal_8bpc).main
+    vpbroadcastd         m5, [o(pw_16384)]
+    punpckhwd            m4, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+    REPX   {pmulhrsw x, m5}, m4, m2, m3, m0
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    jmp                tx2q
+.pass2:
+    call .main
+    vpbroadcastd         m5, [o(pw_2896x8)]
+    paddsw               m1, m2, m4
+    psubsw               m2, m4
+    pmulhrsw             m1, m5     ; -out7   out4   out6  -out5
+    pmulhrsw             m2, m5     ;  out8  -out11 -out9   out10
+    vpbroadcastd         m5, [o(pw_2048)]
+    pshufd               m1, m1, q1032
+    vpblendd             m4, m1, m0, 0x33
+    vpblendd             m0, m2, 0x33
+    vpblendd             m2, m3, 0x33
+    vpblendd             m3, m1, 0x33
+    vpermq               m0, m0, q2031
+    vpermq               m1, m2, q1302
+    vpermq               m2, m3, q3120
+    vpermq               m3, m4, q0213
+    psubw                m6, m7, m5
+.end:
+    vpblendd             m5, m6, 0xcc
+.end2:
+    REPX   {pmulhrsw x, m5}, m0, m1, m2, m3
+    WIN64_RESTORE_XMM
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    mova          [cq+32*2], m4
+    mova          [cq+32*3], m4
+.end3:
+    lea                  r2, [dstq+strideq*8]
+    lea                  r3, [strideq*3]
+    WRITE_4X8             0, 1
+    lea                dstq, [dstq+strideq*4]
+    lea                  r2, [r2  +strideq*4]
+    WRITE_4X8             2, 3
+    RET
+ALIGN function_align
+.main:
+    vpblendd             m4, m1, m0, 0xcc
+    vpblendd             m1, m0, 0x33
+    vpblendd             m5, m2, m3, 0xcc
+    vpblendd             m2, m3, 0x33
+    vperm2i128           m3, m5, m2, 0x31
+    vinserti128          m0, m1, xm4, 1 ; in0  in3  in2  in1
+    vperm2i128           m4, m1, m4, 0x31
+    vinserti128          m1, m5, xm2, 1 ; in4  in7  in6  in5
+    pshufd               m3, m3, q1032  ; in15 in12 in13 in14
+    pshufd               m2, m4, q1032  ; in11 in8  in9  in10
+cglobal_label .main2
+    vpbroadcastd         m8, [o(pd_2048)]
+    pxor                 m7, m7
+    punpckhwd            m4, m3, m0 ; in12 in3  in14 in1
+    punpcklwd            m0, m3     ; in0  in15 in2  in13
+    punpckhwd            m3, m2, m1 ; in8  in7  in10 in5
+    punpcklwd            m1, m2     ; in4  in11 in6  in9
+    ITX_MUL4X_PACK        0, 2, 5, 6, 8,  201, 4091,  995, 3973, 3
+    ITX_MUL4X_PACK        1, 2, 5, 6, 8, 1751, 3703, 2440, 3290, 3
+    ITX_MUL4X_PACK        3, 2, 5, 6, 8, 3035, 2751, 3513, 2106, 3
+    ITX_MUL4X_PACK        4, 2, 5, 6, 8, 3857, 1380, 4052,  601, 3
+    psubsw               m2, m0, m3 ; t9a  t8a  t11a t10a
+    paddsw               m0, m3     ; t1a  t0a  t3a  t2a
+    psubsw               m3, m1, m4 ; t13a t12a t15a t14a
+    paddsw               m1, m4     ; t5a  t4a  t7a  t6a
+    ITX_MUL4X_PACK        2, 4, 5, 6, 8,  799, 4017, 3406, 2276, 3
+    psubw                m6, m7, m5
+    ITX_MUL2X_PACK        3, 5, _, 8, 6, 4, 6
+    vpbroadcastd         m6, [o(pw_m3784_1567)]
+    vpbroadcastd         m5, [o(pw_1567_3784)]
+    psubsw               m4, m0, m1 ; t5   t4   t7   t6
+    paddsw               m0, m1     ; t1   t0   t3   t2
+    psubsw               m1, m2, m3 ; t13a t12a t15a t14a
+    paddsw               m2, m3     ; t9a  t8a  t11a t10a
+    psubw                m3, m7, m6 ; pw_3784_m1567
+    vpblendd             m6, m3, 0xf0
+    ITX_MUL2X_PACK        4, 3, _, 8, 6, 5, 4 ; t4a t5a t7a t6a
+    ITX_MUL2X_PACK        1, 3, _, 8, 6, 5, 4 ; t12 t13 t15 t14
+    vbroadcasti128       m5, [o(deint_shuf)]
+    pshufb               m0, m5
+    pshufb               m2, m5
+    vperm2i128           m3, m0, m2, 0x31  ; t3   t2   t11a t10a
+    vinserti128          m0, xm2, 1        ; t1   t0   t9a  t8a
+    vperm2i128           m2, m4, m1, 0x31  ; t7a  t6a  t15  t14
+    vinserti128          m4, xm1, 1        ; t4a  t5a  t12  t13
+    pshufd               m2, m2, q1032     ; t6a  t7a  t14  t15
+    psubsw               m1, m0, m3        ; t3a t2a t11 t10
+    paddsw               m0, m3     ; -out15  out0   out14 -out1
+    paddsw               m3, m4, m2 ; -out3   out12  out2  -out13
+    psubsw               m4, m2            ; t6 t7 t14a t15a
+    shufps               m2, m1, m4, q1032 ; t2a t6  t10 t14a
+    vpblendd             m4, m1, 0x33      ; t3a t7  t11 t15a
+    ret
+ALIGN function_align
+.main_pass1_end:
+    vpbroadcastd         m5, [o(pw_m2896_2896)]
+    vpbroadcastd         m6, [o(pw_2896_2896)]
+    punpcklwd            m1, m4, m2
+    punpckhwd            m4, m2
+    pmaddwd              m2, m5, m4
+    pmaddwd              m4, m6
+    pmaddwd              m5, m1
+    pmaddwd              m1, m6
+    REPX      {paddd x, m8}, m5, m1, m2, m4
+    REPX      {psrad x, 12}, m5, m2, m1, m4
+    packssdw             m2, m5     ; -out11  out8   out10 -out9
+    packssdw             m1, m4     ; -out7   out4   out6  -out5
+    ret
+
+INV_TXFM_4X16_FN flipadst, dct
+INV_TXFM_4X16_FN flipadst, adst
+INV_TXFM_4X16_FN flipadst, flipadst
+INV_TXFM_4X16_FN flipadst, identity
+
+cglobal iflipadst_4x16_internal_8bpc, 0, 5, 11, dst, stride, c, eob, tx2
+    mova                 m0, [cq+32*0]
+    mova                 m1, [cq+32*1]
+    mova                 m2, [cq+32*2]
+    mova                 m3, [cq+32*3]
+    call m(iadst_16x4_internal_8bpc).main
+    vpbroadcastd         m5, [o(pw_16384)]
+    punpcklwd            m4, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m3, m2
+    punpckhwd            m3, m2
+    REPX   {pmulhrsw x, m5}, m4, m1, m0, m3
+    punpckldq            m2, m3, m1
+    punpckhdq            m3, m1
+    punpckhdq            m1, m0, m4
+    punpckldq            m0, m4
+    jmp                tx2q
+.pass2:
+    call m(iadst_4x16_internal_8bpc).main
+    vpbroadcastd         m5, [o(pw_2896x8)]
+    paddsw               m1, m2, m4
+    psubsw               m2, m4
+    pmulhrsw             m1, m5     ; -out7   out4   out6  -out5
+    pmulhrsw             m2, m5     ;  out8  -out11 -out9   out10
+    vpbroadcastd         m6, [o(pw_2048)]
+    pshufd               m1, m1, q1032
+    vpblendd             m4, m0, m2, 0x33
+    vpblendd             m0, m1, 0xcc
+    vpblendd             m1, m3, 0xcc
+    vpblendd             m2, m3, 0x33
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q0213
+    vpermq               m2, m2, q2031
+    vpermq               m3, m4, q1302
+    psubw                m5, m7, m6
+    jmp m(iadst_4x16_internal_8bpc).end
+
+INV_TXFM_4X16_FN identity, dct
+INV_TXFM_4X16_FN identity, adst
+INV_TXFM_4X16_FN identity, flipadst
+INV_TXFM_4X16_FN identity, identity
+
+cglobal iidentity_4x16_internal_8bpc, 0, 5, 11, dst, stride, c, eob, tx2
+    mova                 m3, [cq+32*0]
+    mova                 m2, [cq+32*1]
+    mova                 m4, [cq+32*2]
+    mova                 m5, [cq+32*3]
+    vpbroadcastd         m8, [o(pw_1697x8)]
+    pcmpeqw              m0, m0 ; -1
+    punpcklwd            m1, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m4, m5
+    punpckhwd            m4, m5
+    pmulhrsw             m5, m8, m1
+    pmulhrsw             m6, m8, m2
+    pmulhrsw             m7, m8, m3
+    pmulhrsw             m8, m4
+    pcmpeqw              m9, m0, m1 ; we want to do a signed avg, but pavgw is
+    pxor                 m1, m9     ; unsigned. as long as both signs are equal
+    pcmpeqw              m9, m0, m2 ; it still works, but if the input is -1 the
+    pxor                 m2, m9     ; pmulhrsw result will become 0 which causes
+    pcmpeqw              m9, m0, m3 ; pavgw to output -32768 instead of 0 unless
+    pxor                 m3, m9     ; we explicitly deal with that case here.
+    pcmpeqw              m0, m4
+    pxor                 m4, m0
+    pavgw                m1, m5
+    pavgw                m2, m6
+    pavgw                m3, m7
+    pavgw                m4, m8
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m8, [o(pw_1697x16)]
+    vpbroadcastd         m5, [o(pw_2048)]
+    pmulhrsw             m4, m8, m0
+    pmulhrsw             m6, m8, m1
+    pmulhrsw             m7, m8, m2
+    pmulhrsw             m8, m3
+    REPX      {paddsw x, x}, m0, m1, m2, m3
+    paddsw               m0, m4
+    paddsw               m1, m6
+    paddsw               m2, m7
+    paddsw               m3, m8
+    jmp m(iadst_4x16_internal_8bpc).end2
+
+%macro WRITE_8X4 4-7 strideq*1, strideq*2, r3 ; coefs[1-2], tmp[1-2], off[1-3]
+    movq               xm%3, [dstq   ]
+    movhps             xm%3, [dstq+%5]
+    movq               xm%4, [dstq+%6]
+    movhps             xm%4, [dstq+%7]
+    pmovzxbw            m%3, xm%3
+    pmovzxbw            m%4, xm%4
+%ifnum %1
+    paddw               m%3, m%1
+%else
+    paddw               m%3, %1
+%endif
+%ifnum %2
+    paddw               m%4, m%2
+%else
+    paddw               m%4, %2
+%endif
+    packuswb            m%3, m%4
+    vextracti128       xm%4, m%3, 1
+    movq          [dstq   ], xm%3
+    movhps        [dstq+%6], xm%3
+    movq          [dstq+%5], xm%4
+    movhps        [dstq+%7], xm%4
+%endmacro
+
+%macro INV_TXFM_8X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x4
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm1
+    jmp m(inv_txfm_add_dct_dct_8x8_8bpc).dconly2
+%endif
+%endmacro
+
+INV_TXFM_8X4_FN dct, dct
+INV_TXFM_8X4_FN dct, adst
+INV_TXFM_8X4_FN dct, flipadst
+INV_TXFM_8X4_FN dct, identity
+
+cglobal idct_8x4_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpbroadcastd        xm3, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm3, [cq+16*0]
+    pmulhrsw            xm1, xm3, [cq+16*1]
+    pmulhrsw            xm2, xm3, [cq+16*2]
+    pmulhrsw            xm3,      [cq+16*3]
+    call m(idct_4x8_internal_8bpc).main
+    vbroadcasti128       m4, [o(deint_shuf)]
+    vinserti128          m3, m1, xm3, 1
+    vinserti128          m1, m0, xm2, 1
+    shufps               m0, m1, m3, q0220
+    shufps               m1, m3, q1331
+    pshufb               m0, m4
+    pshufb               m1, m4
+    jmp                tx2q
+.pass2:
+    IDCT4_1D_PACKED
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    jmp m(iadst_8x4_internal_8bpc).end2
+
+INV_TXFM_8X4_FN adst, dct
+INV_TXFM_8X4_FN adst, adst
+INV_TXFM_8X4_FN adst, flipadst
+INV_TXFM_8X4_FN adst, identity
+
+cglobal iadst_8x4_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpbroadcastd        xm0, [o(pw_2896x8)]
+    pshufd              xm4,      [cq+16*0], q1032
+    pmulhrsw            xm3, xm0, [cq+16*3]
+    pshufd              xm5,      [cq+16*1], q1032
+    pmulhrsw            xm2, xm0, [cq+16*2]
+    pmulhrsw            xm4, xm0
+    pmulhrsw            xm5, xm0
+    call m(iadst_4x8_internal_8bpc).main_pass1
+    vinserti128        m0, xm2, 1
+    vinserti128        m1, xm3, 1
+    punpckhwd          m2, m0, m1
+    punpcklwd          m0, m1
+    pxor               m3, m3
+    psubsw             m3, m2
+    punpckhwd          m1, m0, m3
+    punpcklwd          m0, m3
+    jmp              tx2q
+.pass2:
+    call .main
+.end:
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q3120
+.end2:
+    vpbroadcastd         m2, [o(pw_2048)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    WIN64_RESTORE_XMM
+.end3:
+    pxor                 m2, m2
+    mova          [cq+32*0], m2
+    mova          [cq+32*1], m2
+    lea                  r3, [strideq*3]
+    WRITE_8X4             0, 1, 4, 5
+    RET
+ALIGN function_align
+cglobal_label .main
+    IADST4_1D_PACKED
+    ret
+
+INV_TXFM_8X4_FN flipadst, dct
+INV_TXFM_8X4_FN flipadst, adst
+INV_TXFM_8X4_FN flipadst, flipadst
+INV_TXFM_8X4_FN flipadst, identity
+
+cglobal iflipadst_8x4_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpbroadcastd        xm0, [o(pw_2896x8)]
+    pshufd              xm4,      [cq+16*0], q1032
+    pmulhrsw            xm3, xm0, [cq+16*3]
+    pshufd              xm5,      [cq+16*1], q1032
+    pmulhrsw            xm2, xm0, [cq+16*2]
+    pmulhrsw            xm4, xm0
+    pmulhrsw            xm5, xm0
+    call m(iadst_4x8_internal_8bpc).main_pass1
+    vinserti128          m3, xm1, 1
+    vinserti128          m2, xm0, 1
+    punpckhwd            m1, m3, m2
+    punpcklwd            m3, m2
+    pxor                 m0, m0
+    psubsw               m0, m1
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    jmp                tx2q
+.pass2:
+    call m(iadst_8x4_internal_8bpc).main
+    mova                 m2, m1
+    vpermq               m1, m0, q2031
+    vpermq               m0, m2, q2031
+    jmp m(iadst_8x4_internal_8bpc).end2
+
+INV_TXFM_8X4_FN identity, dct
+INV_TXFM_8X4_FN identity, adst
+INV_TXFM_8X4_FN identity, flipadst
+INV_TXFM_8X4_FN identity, identity
+
+cglobal iidentity_8x4_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    mova                xm2, [cq+16*0]
+    mova                xm0, [cq+16*1]
+    vinserti128          m2, [cq+16*2], 1
+    vinserti128          m0, [cq+16*3], 1
+    vpbroadcastd         m3, [o(pw_2896x8)]
+    punpcklwd            m1, m2, m0
+    punpckhwd            m2, m0
+    pmulhrsw             m1, m3
+    pmulhrsw             m2, m3
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    paddsw               m0, m0
+    paddsw               m1, m1
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    jmp m(iadst_8x4_internal_8bpc).end
+
+%macro INV_TXFM_8X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x8
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    mov                [cq], eobd
+    or                  r3d, 8
+.dconly:
+    pmulhrsw            xm0, xm2
+.dconly2:
+    movd                xm2, [pw_2048]
+    pmulhrsw            xm0, xm1
+    lea                  r2, [strideq*3]
+    pmulhrsw            xm0, xm2
+    vpbroadcastw         m0, xm0
+.dconly_loop:
+    WRITE_8X4             0, 0, 1, 2, strideq*1, strideq*2, r2
+    lea                dstq, [dstq+strideq*4]
+    sub                 r3d, 4
+    jg .dconly_loop
+    RET
+%endif
+%endmacro
+
+INV_TXFM_8X8_FN dct, dct
+INV_TXFM_8X8_FN dct, adst
+INV_TXFM_8X8_FN dct, flipadst
+INV_TXFM_8X8_FN dct, identity
+
+cglobal idct_8x8_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q3120 ; 0 1
+    vpermq               m3, [cq+32*3], q3120 ; 6 7
+    vpermq               m2, [cq+32*2], q3120 ; 4 5
+    vpermq               m1, [cq+32*1], q3120 ; 2 3
+    call .main
+    shufps               m4, m0, m1, q0220
+    shufps               m5, m0, m1, q1331
+    shufps               m1, m2, m3, q0220
+    shufps               m3, m2, m3, q1331
+    vbroadcasti128       m0, [o(deint_shuf)]
+    vpbroadcastd         m2, [o(pw_16384)]
+    REPX   {pshufb   x, m0}, m4, m5, m1, m3
+    REPX   {pmulhrsw x, m2}, m4, m5, m1, m3
+    vinserti128          m0, m4, xm1, 1
+    vperm2i128           m2, m4, m1, 0x31
+    vinserti128          m1, m5, xm3, 1
+    vperm2i128           m3, m5, m3, 0x31
+    jmp                tx2q
+.pass2:
+    call .main
+    vpbroadcastd         m4, [o(pw_2048)]
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    vpermq               m2, m2, q3120
+    vpermq               m3, m3, q2031
+    jmp m(iadst_8x8_internal_8bpc).end2
+ALIGN function_align
+cglobal_label .main
+    IDCT8_1D_PACKED
+    ret
+
+INV_TXFM_8X8_FN adst, dct
+INV_TXFM_8X8_FN adst, adst
+INV_TXFM_8X8_FN adst, flipadst
+INV_TXFM_8X8_FN adst, identity
+
+cglobal iadst_8x8_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpermq               m4, [cq+32*0], q1302 ; 1 0
+    vpermq               m3, [cq+32*3], q3120 ; 6 7
+    vpermq               m5, [cq+32*1], q1302 ; 3 2
+    vpermq               m2, [cq+32*2], q3120 ; 4 5
+    call .main_pass1
+    vpbroadcastd         m5, [o(pw_16384)]
+    punpcklwd            m4, m0, m1
+    punpckhwd            m0, m1
+    punpcklwd            m1, m2, m3
+    punpckhwd            m2, m3
+    pxor                 m3, m3
+    psubw                m3, m5 ; negate odd elements during rounding
+    pmulhrsw             m4, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m5
+    pmulhrsw             m2, m3
+    punpcklwd            m3, m4, m0
+    punpckhwd            m4, m0
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    vperm2i128           m2, m3, m0, 0x31
+    vinserti128          m0, m3, xm0, 1
+    vperm2i128           m3, m4, m1, 0x31
+    vinserti128          m1, m4, xm1, 1
+    jmp                tx2q
+.pass2:
+    pshufd               m4, m0, q1032
+    pshufd               m5, m1, q1032
+    call .main_pass2
+    vpbroadcastd         m5, [o(pw_2048)]
+    vpbroadcastd        xm4, [o(pw_4096)]
+    psubw                m4, m5 ; lower half = 2048, upper half = -2048
+.end:
+    REPX {vpermq x, x, q3120}, m0, m1, m2, m3
+.end2:
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+.end3:
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    WIN64_RESTORE_XMM
+.end4:
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    mova          [cq+32*2], m4
+    mova          [cq+32*3], m4
+    lea                  r3, [strideq*3]
+    WRITE_8X4             0, 1, 4, 5
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4             2, 3, 4, 5
+    RET
+ALIGN function_align
+.main_pass1:
+    IADST8_1D_PACKED 1
+    ret
+ALIGN function_align
+cglobal_label .main_pass2
+    IADST8_1D_PACKED 2
+    ret
+
+INV_TXFM_8X8_FN flipadst, dct
+INV_TXFM_8X8_FN flipadst, adst
+INV_TXFM_8X8_FN flipadst, flipadst
+INV_TXFM_8X8_FN flipadst, identity
+
+cglobal iflipadst_8x8_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    vpermq               m4, [cq+32*0], q1302 ; 1 0
+    vpermq               m3, [cq+32*3], q3120 ; 6 7
+    vpermq               m5, [cq+32*1], q1302 ; 3 2
+    vpermq               m2, [cq+32*2], q3120 ; 4 5
+    call m(iadst_8x8_internal_8bpc).main_pass1
+    vpbroadcastd         m5, [o(pw_16384)]
+    punpckhwd            m4, m3, m2
+    punpcklwd            m3, m2
+    punpckhwd            m2, m1, m0
+    punpcklwd            m1, m0
+    pxor                 m0, m0
+    psubw                m0, m5
+    pmulhrsw             m4, m0
+    pmulhrsw             m3, m5
+    pmulhrsw             m2, m0
+    pmulhrsw             m1, m5
+    punpckhwd            m0, m4, m3
+    punpcklwd            m4, m3
+    punpckhwd            m3, m2, m1
+    punpcklwd            m2, m1
+    vinserti128          m1, m0, xm3, 1
+    vperm2i128           m3, m0, m3, 0x31
+    vinserti128          m0, m4, xm2, 1
+    vperm2i128           m2, m4, m2, 0x31
+    jmp                tx2q
+.pass2:
+    pshufd               m4, m0, q1032
+    pshufd               m5, m1, q1032
+    call m(iadst_8x8_internal_8bpc).main_pass2
+    vpbroadcastd         m4, [o(pw_2048)]
+    vpbroadcastd        xm5, [o(pw_4096)]
+    psubw                m4, m5 ; lower half = -2048, upper half = 2048
+    vpermq               m5, m3, q2031
+    vpermq               m3, m0, q2031
+    vpermq               m0, m2, q2031
+    vpermq               m2, m1, q2031
+    pmulhrsw             m1, m0, m4
+    pmulhrsw             m0, m5, m4
+    jmp m(iadst_8x8_internal_8bpc).end3
+
+INV_TXFM_8X8_FN identity, dct
+INV_TXFM_8X8_FN identity, adst
+INV_TXFM_8X8_FN identity, flipadst
+INV_TXFM_8X8_FN identity, identity
+
+cglobal iidentity_8x8_internal_8bpc, 0, 5, 7, dst, stride, c, eob, tx2
+    mova                xm3, [cq+16*0]
+    mova                xm2, [cq+16*1]
+    vinserti128          m3, [cq+16*4], 1
+    vinserti128          m2, [cq+16*5], 1
+    mova                xm4, [cq+16*2]
+    mova                xm0, [cq+16*3]
+    vinserti128          m4, [cq+16*6], 1
+    vinserti128          m0, [cq+16*7], 1
+    punpcklwd            m1, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m4, m0
+    punpckhwd            m4, m0
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m4, [o(pw_4096)]
+    jmp m(iadst_8x8_internal_8bpc).end
+
+%macro INV_TXFM_8X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x16
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm1
+    or                  r3d, 16
+    jmp m(inv_txfm_add_dct_dct_8x8_8bpc).dconly
+%endif
+%endmacro
+
+%macro ITX_8X16_LOAD_COEFS 0
+    vpbroadcastd         m4, [o(pw_2896x8)]
+    pmulhrsw             m0, m4, [cq+32*0]
+    add                  cq, 32*4
+    pmulhrsw             m7, m4, [cq+32*3]
+    pmulhrsw             m1, m4, [cq-32*3]
+    pmulhrsw             m6, m4, [cq+32*2]
+    pmulhrsw             m2, m4, [cq-32*2]
+    pmulhrsw             m5, m4, [cq+32*1]
+    pmulhrsw             m3, m4, [cq-32*1]
+    pmulhrsw             m4,     [cq+32*0]
+%endmacro
+
+INV_TXFM_8X16_FN dct, dct
+INV_TXFM_8X16_FN dct, adst
+INV_TXFM_8X16_FN dct, flipadst
+INV_TXFM_8X16_FN dct, identity
+
+cglobal idct_8x16_internal_8bpc, 0, 5, 13, dst, stride, c, eob, tx2
+    ITX_8X16_LOAD_COEFS
+    call m(idct_16x8_internal_8bpc).main
+    vpbroadcastd        m10, [o(pw_16384)]
+.pass1_end:
+    vperm2i128           m9, m3, m7, 0x31
+    vinserti128          m3, xm7, 1
+    vperm2i128           m8, m2, m6, 0x31
+    vinserti128          m2, xm6, 1
+    vperm2i128           m6, m1, m5, 0x31
+    vinserti128          m1, xm5, 1
+    vperm2i128           m5, m0, m4, 0x31
+    vinserti128          m0, xm4, 1
+    punpckhwd            m4, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+.pass1_end2:
+    punpckhwd            m7, m5, m6
+    punpcklwd            m5, m6
+    punpcklwd            m6, m8, m9
+    punpckhwd            m8, m9
+    REPX  {pmulhrsw x, m10}, m2, m0, m4, m3, m5, m6, m7, m8
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    punpckldq            m4, m5, m6
+    punpckhdq            m5, m6
+    punpckldq            m6, m7, m8
+    punpckhdq            m7, m8
+    jmp                tx2q
+.pass2:
+    call .main
+    REPX {vpermq x, x, q3120}, m0, m2, m4, m6
+    REPX {vpermq x, x, q2031}, m1, m3, m5, m7
+.end:
+    vpbroadcastd         m8, [o(pw_2048)]
+.end2:
+    REPX   {pmulhrsw x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+.end3:
+    pxor                 m8, m8
+    REPX {mova [cq+32*x], m8}, -4, -3, -2, -1, 0, 1, 2, 3
+    lea                  r3, [strideq*3]
+    WRITE_8X4             0, 1, 8, 9
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4             2, 3, 0, 1
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4             4, 5, 0, 1
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4             6, 7, 0, 1
+    RET
+ALIGN function_align
+cglobal_label .main
+    IDCT16_1D_PACKED
+    ret
+
+INV_TXFM_8X16_FN adst, dct
+INV_TXFM_8X16_FN adst, adst
+INV_TXFM_8X16_FN adst, flipadst
+INV_TXFM_8X16_FN adst, identity
+
+cglobal iadst_8x16_internal_8bpc, 0, 5, 13, dst, stride, c, eob, tx2
+    ITX_8X16_LOAD_COEFS
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass1_end
+    vpbroadcastd        m10, [o(pw_16384)]
+    pslld                m9, m10, 17
+    psubw               m10, m9 ; 16384, -16384
+    jmp m(idct_8x16_internal_8bpc).pass1_end
+ALIGN function_align
+.pass2:
+    call .main
+    call .main_pass2_end
+    vpbroadcastd         m9, [o(pw_2048)]
+    vpbroadcastd        xm8, [o(pw_4096)]
+    psubw                m8, m9
+    REPX {vpermq x, x, q2031}, m0, m1, m2, m3
+    REPX {vpermq x, x, q3120}, m4, m5, m6, m7
+    jmp m(idct_8x16_internal_8bpc).end2
+ALIGN function_align
+cglobal_label .main
+    REPX {pshufd x, x, q1032}, m7, m1, m5, m3
+.main2:
+    vpbroadcastd        m10, [o(pd_2048)]
+    punpckhwd            m8, m7, m0 ; in14 in1
+    punpcklwd            m0, m7     ; in0  in15
+    punpcklwd            m7, m6, m1 ; in12 in3
+    punpckhwd            m1, m6     ; in2  in13
+    punpckhwd            m6, m5, m2 ; in10 in5
+    punpcklwd            m2, m5     ; in4  in11
+    punpcklwd            m5, m4, m3 ; in8  in7
+    punpckhwd            m3, m4     ; in6  in9
+    ITX_MUL2X_PACK        0, 4, 9, 10,  201, 4091, 3 ; t0  t1
+    ITX_MUL2X_PACK        1, 4, 9, 10,  995, 3973, 3 ; t2  t3
+    ITX_MUL2X_PACK        2, 4, 9, 10, 1751, 3703, 3 ; t4  t5
+    ITX_MUL2X_PACK        3, 4, 9, 10, 2440, 3290, 3 ; t6  t7
+    ITX_MUL2X_PACK        5, 4, 9, 10, 3035, 2751, 3 ; t8  t9
+    ITX_MUL2X_PACK        6, 4, 9, 10, 3513, 2106, 3 ; t10 t11
+    ITX_MUL2X_PACK        7, 4, 9, 10, 3857, 1380, 3 ; t12 t13
+    ITX_MUL2X_PACK        8, 4, 9, 10, 4052,  601, 3 ; t14 t15
+    psubsw               m4, m0, m5 ; t9a  t8a
+    paddsw               m0, m5     ; t1a  t0a
+    psubsw               m5, m1, m6 ; t11a t10a
+    paddsw               m1, m6     ; t3a  t2a
+    psubsw               m6, m2, m7 ; t13a t12a
+    paddsw               m2, m7     ; t5a  t4a
+    psubsw               m7, m3, m8 ; t15a t14a
+    paddsw               m3, m8     ; t7a  t6a
+    vpbroadcastd        m11, [o(pw_m4017_799)]
+    vpbroadcastd        m12, [o(pw_799_4017)]
+    pxor                 m9, m9
+    ITX_MUL2X_PACK        4, 8, _, 10, 11, 12, 6 ; t8  t9
+    psubw                m8, m9, m11 ; pw_4017_m799
+    ITX_MUL2X_PACK        6, 12, _, 10, 12, 8, 6 ; t12 t13
+    vpbroadcastd        m11, [o(pw_m2276_3406)]
+    vpbroadcastd        m12, [o(pw_3406_2276)]
+    ITX_MUL2X_PACK        5, 8, _, 10, 11, 12, 6 ; t10 t11
+    psubw                m8, m9, m11 ; pw_2276_m3406
+    ITX_MUL2X_PACK        7, 12, _, 10, 12, 8, 6 ; t14 t15
+    psubsw               m8, m1, m3 ; t7   t6
+    paddsw               m1, m3     ; t3   t2
+    psubsw               m3, m0, m2 ; t5   t4
+    paddsw               m0, m2     ; t1   t0
+    psubsw               m2, m5, m7 ; t14a t15a
+    paddsw               m7, m5     ; t10a t11a
+    psubsw               m5, m4, m6 ; t12a t13a
+    paddsw               m4, m6     ; t8a  t9a
+    vpbroadcastd        m11, [o(pw_m3784_1567)]
+    vpbroadcastd        m12, [o(pw_1567_3784)]
+    ITX_MUL2X_PACK        3, 6, _, 10, 12, 11, 6 ; t5a t4a
+    psubw                m6, m9, m11 ; pw_3784_m1567
+    ITX_MUL2X_PACK        8, 6, _, 10, 6, 12, 6  ; t7a t6a
+    vpbroadcastd        m11, [o(pw_m1567_3784)]
+    vpbroadcastd        m12, [o(pw_3784_1567)]
+    ITX_MUL2X_PACK        2, 6, _, 10, 11, 12, 6 ; t15 t14
+    psubw                m6, m9, m11 ; pw_1567_m3784
+    ITX_MUL2X_PACK        5, 12, _, 10, 12, 6, 6 ; t13 t12
+    vbroadcasti128      m12, [o(deint_shuf)]
+    paddsw               m6, m4, m7        ; -out1  out14
+    psubsw               m4, m7            ;  t10    t11
+    psubsw              m11, m3, m8        ;  t7     t6
+    paddsw               m8, m3            ;  out12 -out3
+    psubsw               m3, m0, m1        ;  t3a    t2a
+    paddsw               m0, m1            ; -out15  out0
+    paddsw               m1, m2, m5        ; -out13  out2
+    psubsw               m5, m2            ;  t15a   t14a
+    pshufb               m0, m12
+    pshufb               m6, m12
+    pshufb               m8, m12
+    pshufb               m1, m12
+    shufps               m7, m6, m0, q1032 ;  out14 -out15
+    vpblendd             m0, m6, 0x33      ; -out1   out0
+    punpcklqdq           m6, m8, m1        ;  out12 -out13
+    punpckhqdq           m1, m8, m1        ; -out3   out2
+    ret
+ALIGN function_align
+.main_pass1_end:
+    vpbroadcastd         m8, [o(pw_m2896_2896)]
+    vpbroadcastd        m12, [o(pw_2896_2896)]
+    pmaddwd              m9, m8, m11       ; -out11
+    pmaddwd              m2, m12, m5       ; -out5
+    pmaddwd              m5, m8            ;  out10
+    pmaddwd             m11, m12           ;  out4
+    REPX     {paddd x, m10}, m9, m5, m2, m11
+    REPX     {psrad x, 12 }, m9, m5, m2, m11
+    packssdw             m5, m9            ;  out10 -out11
+    packssdw             m2, m11           ; -out5   out4
+    pmaddwd             m11, m8, m3        ;  out8
+    vpbroadcastd         m8, [o(pw_2896_m2896)]
+    pmaddwd              m3, m12           ; -out7
+    pmaddwd              m8, m4            ; -out9
+    pmaddwd              m4, m12           ;  out6
+    REPX     {paddd x, m10}, m11, m3, m8, m4
+    REPX     {psrad x, 12 }, m11, m3, m8, m4
+    packssdw             m3, m4            ; -out7   out6
+    packssdw             m4, m11, m8       ;  out8  -out9
+    vpbroadcastd        m10, [o(pw_16384)]
+    pxor                 m9, m9
+    ret
+ALIGN function_align
+cglobal_label .main_pass2_end
+    vpbroadcastd         m8, [o(pw_2896x8)]
+    pshufb               m2, m11, m12
+    pshufb               m5, m12
+    pshufb               m3, m12
+    pshufb               m4, m12
+    punpcklqdq          m11, m5, m2        ;  t15a   t7
+    punpckhqdq           m5, m2            ;  t14a   t6
+    shufps               m2, m3, m4, q1032 ;  t2a    t10
+    vpblendd             m3, m4, 0xcc      ;  t3a    t11
+    psubsw               m4, m2, m3        ;  out8  -out9
+    paddsw               m3, m2            ; -out7   out6
+    paddsw               m2, m5, m11       ; -out5   out4
+    psubsw               m5, m11           ;  out10 -out11
+    REPX   {pmulhrsw x, m8}, m2, m3, m4, m5
+    ret
+
+INV_TXFM_8X16_FN flipadst, dct
+INV_TXFM_8X16_FN flipadst, adst
+INV_TXFM_8X16_FN flipadst, flipadst
+INV_TXFM_8X16_FN flipadst, identity
+
+cglobal iflipadst_8x16_internal_8bpc, 0, 5, 13, dst, stride, c, eob, tx2
+    ITX_8X16_LOAD_COEFS
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass1_end
+    vpbroadcastd         m9, [o(pw_16384)]
+    pslld               m10, m9, 17
+    psubw               m10, m9 ; -16384, 16384
+    vperm2i128           m9, m4, m0, 0x31
+    vinserti128          m0, m4, xm0, 1
+    vperm2i128           m8, m5, m1, 0x31
+    vinserti128          m4, m5, xm1, 1
+    vperm2i128           m5, m7, m3, 0x31
+    vinserti128          m3, m7, xm3, 1
+    vinserti128          m1, m6, xm2, 1
+    vperm2i128           m6, m6, m2, 0x31
+    punpcklwd            m2, m4, m0
+    punpckhwd            m4, m0
+    punpcklwd            m0, m3, m1
+    punpckhwd            m3, m1
+    jmp m(idct_8x16_internal_8bpc).pass1_end2
+.pass2:
+    call m(iadst_8x16_internal_8bpc).main
+    call m(iadst_8x16_internal_8bpc).main_pass2_end
+    vpbroadcastd         m8, [o(pw_2048)]
+    vpbroadcastd        xm9, [o(pw_4096)]
+    psubw                m8, m9
+    vpermq               m9, m0, q3120
+    vpermq               m0, m7, q2031
+    vpermq               m7, m1, q3120
+    vpermq               m1, m6, q2031
+    vpermq               m6, m2, q3120
+    vpermq               m2, m5, q2031
+    vpermq               m5, m3, q3120
+    vpermq               m3, m4, q2031
+    pmulhrsw             m0, m8
+    pmulhrsw             m1, m8
+    pmulhrsw             m2, m8
+    pmulhrsw             m3, m8
+    pmulhrsw             m4, m5, m8
+    pmulhrsw             m5, m6, m8
+    pmulhrsw             m6, m7, m8
+    pmulhrsw             m7, m9, m8
+    jmp m(idct_8x16_internal_8bpc).end3
+
+INV_TXFM_8X16_FN identity, dct
+INV_TXFM_8X16_FN identity, adst
+INV_TXFM_8X16_FN identity, flipadst
+INV_TXFM_8X16_FN identity, identity
+
+%macro IDTX16 3-4 ; src/dst, tmp, pw_1697x16, [pw_16394]
+    pmulhrsw            m%2, m%3, m%1
+%if %0 == 4 ; if downshifting by 1
+    pmulhrsw            m%2, m%4
+%else
+    paddsw              m%1, m%1
+%endif
+    paddsw              m%1, m%2
+%endmacro
+
+cglobal iidentity_8x16_internal_8bpc, 0, 5, 13, dst, stride, c, eob, tx2
+    mova                xm3, [cq+16*0]
+    mova                xm2, [cq+16*2]
+    add                  cq, 16*8
+    vinserti128          m3, [cq+16*0], 1
+    vinserti128          m2, [cq+16*2], 1
+    vpbroadcastd         m9, [o(pw_2896x8)]
+    mova                xm4, [cq-16*4]
+    mova                xm5, [cq-16*2]
+    vinserti128          m4, [cq+16*4], 1
+    vinserti128          m5, [cq+16*6], 1
+    mova                xm7, [cq-16*7]
+    mova                xm6, [cq-16*5]
+    vinserti128          m7, [cq+16*1], 1
+    vinserti128          m6, [cq+16*3], 1
+    mova                xm8, [cq-16*3]
+    mova                xm0, [cq-16*1]
+    vinserti128          m8, [cq+16*5], 1
+    vinserti128          m0, [cq+16*7], 1
+    punpcklwd            m1, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m4, m5
+    punpckhwd            m4, m5
+    punpcklwd            m5, m7, m6
+    punpckhwd            m7, m6
+    punpcklwd            m6, m8, m0
+    punpckhwd            m8, m0
+    REPX   {pmulhrsw x, m9}, m1, m2, m3, m4, m5, m6, m7, m8
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    punpckldq            m4, m5, m6
+    punpckhdq            m5, m6
+    punpckldq            m6, m7, m8
+    punpckhdq            m7, m8
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m8, [o(pw_1697x16)]
+    REPX {vpermq   x, x, q3120}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX {IDTX16   x, 9, 8}, 0, 1, 2, 3, 4, 5, 6, 7
+    jmp m(idct_8x16_internal_8bpc).end
+
+%macro WRITE_16X2 6 ; coefs[1-2], tmp[1-2], offset[1-2]
+    pmovzxbw            m%3, [dstq+%5]
+%ifnum %1
+    paddw               m%3, m%1
+%else
+    paddw               m%3, %1
+%endif
+    pmovzxbw            m%4, [dstq+%6]
+%ifnum %2
+    paddw               m%4, m%2
+%else
+    paddw               m%4, %2
+%endif
+    packuswb            m%3, m%4
+    vpermq              m%3, m%3, q3120
+    mova          [dstq+%5], xm%3
+    vextracti128  [dstq+%6], m%3, 1
+%endmacro
+
+%macro INV_TXFM_16X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x4
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    mov                [cq], eobd
+    or                  r3d, 4
+.dconly:
+    pmulhrsw            xm0, xm2
+    movd                xm2, [pw_2048] ; intentionally rip-relative
+    pmulhrsw            xm0, xm1
+    pmulhrsw            xm0, xm2
+    vpbroadcastw         m0, xm0
+    pxor                 m3, m3
+.dconly_loop:
+    mova                xm1, [dstq+strideq*0]
+    vinserti128          m1, [dstq+strideq*1], 1
+    punpckhbw            m2, m1, m3
+    punpcklbw            m1, m3
+    paddw                m2, m0
+    paddw                m1, m0
+    packuswb             m1, m2
+    mova         [dstq+strideq*0], xm1
+    vextracti128 [dstq+strideq*1], m1, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    RET
+%endif
+%endmacro
+
+INV_TXFM_16X4_FN dct, dct
+INV_TXFM_16X4_FN dct, adst
+INV_TXFM_16X4_FN dct, flipadst
+INV_TXFM_16X4_FN dct, identity
+
+cglobal idct_16x4_internal_8bpc, 0, 5, 11, dst, stride, c, eob, tx2
+    mova                xm0, [cq+16*0]
+    mova                xm1, [cq+16*1]
+    mova                xm2, [cq+16*2]
+    mova                xm3, [cq+16*3]
+    mova                xm4, [cq+16*4]
+    mova                xm5, [cq+16*5]
+    mova                xm6, [cq+16*6]
+    mova                xm7, [cq+16*7]
+    call m(idct_4x16_internal_8bpc).main
+    vinserti128          m6, m2, xm6, 1
+    vinserti128          m2, m0, xm4, 1
+    vinserti128          m0, m1, xm5, 1
+    vinserti128          m1, m3, xm7, 1
+    punpcklwd            m3, m2, m6
+    punpckhwd            m2, m6
+    vpbroadcastd         m6, [o(pw_16384)]
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    mova                 m1, m6
+    jmp m(iadst_16x4_internal_8bpc).pass1_end
+.pass2:
+    call .main
+    jmp m(iadst_16x4_internal_8bpc).end
+ALIGN function_align
+cglobal_label .main
+    vpbroadcastd         m6, [o(pd_2048)]
+    IDCT4_1D              0, 1, 2, 3, 4, 5, 6
+    ret
+
+INV_TXFM_16X4_FN adst, dct
+INV_TXFM_16X4_FN adst, adst
+INV_TXFM_16X4_FN adst, flipadst
+INV_TXFM_16X4_FN adst, identity
+
+cglobal iadst_16x4_internal_8bpc, 0, 5, 11, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q1230
+    vpermq               m3, [cq+32*3], q2103
+    vpermq               m1, [cq+32*1], q1230
+    vpermq               m2, [cq+32*2], q2103
+    call m(iadst_4x16_internal_8bpc).main2
+    call m(iadst_4x16_internal_8bpc).main_pass1_end
+    punpcklwd            m4, m3, m1
+    punpcklwd            m5, m2, m0
+    punpckhwd            m0, m1
+    punpckhwd            m2, m3
+    vpbroadcastd         m1, [o(pw_16384)]
+    vinserti128          m3, m0, xm2, 1
+    vperm2i128           m2, m0, m2, 0x31
+    vinserti128          m0, m4, xm5, 1
+    vperm2i128           m4, m4, m5, 0x31
+    psubw                m6, m7, m1
+.pass1_end:
+    pmulhrsw             m3, m1
+    pmulhrsw             m2, m6
+    pmulhrsw             m4, m1
+    pmulhrsw             m0, m6
+    punpcklwd            m1, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m4, m0
+    punpckhwd            m4, m0
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    jmp                tx2q
+.pass2:
+    call .main
+.end:
+    vpbroadcastd         m4, [o(pw_2048)]
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    WIN64_RESTORE_XMM
+.end2:
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    mova          [cq+32*2], m4
+    mova          [cq+32*3], m4
+.end3:
+    WRITE_16X2            0, 1, 4, 5, strideq*0, strideq*1
+    lea                dstq, [dstq+strideq*2]
+    WRITE_16X2            2, 3, 4, 5, strideq*0, strideq*1
+    RET
+ALIGN function_align
+cglobal_label .main
+    vpbroadcastd         m6, [o(pw_m3344_3344)]
+    vpbroadcastd         m7, [o(pw_3803_1321)]
+    vpbroadcastd         m8, [o(pw_m1321_2482)]
+    vpbroadcastd         m9, [o(pw_2482_3344)]
+    punpcklwd            m4, m2, m0 ; in2 in0 l
+    punpckhwd            m2, m0     ; in2 in0 h
+    psrld                m5, m6, 16
+    pmaddwd             m10, m6, m4 ; t2:02 l
+    pmaddwd              m6, m2     ; t2:02 h
+    pmaddwd              m0, m7, m4 ; t0:02 l
+    pmaddwd              m7, m2     ; t0:02 h
+    pmaddwd              m4, m8     ; t1:02 l
+    pmaddwd              m8, m2     ; t1:02 h
+    punpckhwd            m2, m3, m1 ; in3 in1 h
+    punpcklwd            m3, m1     ; in3 in1 l
+    pmaddwd              m1, m5, m2 ; t2:3 h
+    pmaddwd              m5, m3     ; t2:3 l
+    paddd                m6, m1
+    vpbroadcastd         m1, [o(pd_2048)]
+    paddd               m10, m5
+    pmaddwd              m5, m9, m3
+    pmaddwd              m9, m2
+    paddd                m0, m1
+    paddd                m7, m1
+    paddd                m0, m5     ; t0 + t3 + 2048 l
+    paddd                m7, m9     ; t0 + t3 + 2048 h
+    vpbroadcastd         m9, [o(pw_m3803_3344)]
+    pmaddwd              m5, m9, m2
+    pmaddwd              m9, m3
+    paddd               m10, m1     ; t2 + 2048 l
+    paddd                m6, m1     ; t2 + 2048 h
+    paddd                m5, m1     ; t1:13 + 2048 h
+    paddd                m1, m9     ; t1:13 + 2048 l
+    vpbroadcastd         m9, [o(pw_m3803_m6688)]
+    pmaddwd              m2, m9
+    pmaddwd              m3, m9
+    paddd                m5, m8     ; t1 + t3 + 2048 h
+    paddd                m1, m4     ; t1 + t3 + 2048 l
+    paddd                m8, m7
+    paddd                m4, m0
+    paddd                m2, m8     ; t0 + t1 - t3 + 2048 h
+    paddd                m3, m4     ; t0 + t1 - t3 + 2048 l
+    REPX      {psrad x, 12}, m10, m6, m0, m7, m5, m1, m2, m3
+    packssdw             m0, m7
+    packssdw             m1, m5
+    packssdw             m3, m2
+    packssdw             m2, m10, m6
+    ret
+
+INV_TXFM_16X4_FN flipadst, dct
+INV_TXFM_16X4_FN flipadst, adst
+INV_TXFM_16X4_FN flipadst, flipadst
+INV_TXFM_16X4_FN flipadst, identity
+
+cglobal iflipadst_16x4_internal_8bpc, 0, 5, 11, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q1230
+    vpermq               m3, [cq+32*3], q2103
+    vpermq               m1, [cq+32*1], q1230
+    vpermq               m2, [cq+32*2], q2103
+    call m(iadst_4x16_internal_8bpc).main2
+    call m(iadst_4x16_internal_8bpc).main_pass1_end
+    punpckhwd            m4, m3, m2
+    punpckhwd            m5, m1, m0
+    punpcklwd            m0, m2
+    punpcklwd            m1, m3
+    vpbroadcastd         m6, [o(pw_16384)]
+    vinserti128          m3, m0, xm1, 1
+    vperm2i128           m2, m0, m1, 0x31
+    vinserti128          m0, m4, xm5, 1
+    vperm2i128           m4, m4, m5, 0x31
+    psubw                m1, m7, m6
+    jmp m(iadst_16x4_internal_8bpc).pass1_end
+ALIGN function_align
+.pass2:
+    call m(iadst_16x4_internal_8bpc).main
+    vpbroadcastd         m4, [o(pw_2048)]
+    REPX   {pmulhrsw x, m4}, m3, m2, m1, m0
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    mova          [cq+32*2], m4
+    mova          [cq+32*3], m4
+    WRITE_16X2            3, 2, 4, 5, strideq*0, strideq*1
+    lea                dstq, [dstq+strideq*2]
+    WRITE_16X2            1, 0, 4, 5, strideq*0, strideq*1
+    RET
+
+INV_TXFM_16X4_FN identity, dct
+INV_TXFM_16X4_FN identity, adst
+INV_TXFM_16X4_FN identity, flipadst
+INV_TXFM_16X4_FN identity, identity
+
+cglobal iidentity_16x4_internal_8bpc, 0, 5, 11, dst, stride, c, eob, tx2
+    mova                xm2, [cq+16*0]
+    mova                xm4, [cq+16*1]
+    vinserti128          m2, [cq+16*4], 1
+    vinserti128          m4, [cq+16*5], 1
+    mova                xm0, [cq+16*2]
+    mova                xm1, [cq+16*3]
+    vinserti128          m0, [cq+16*6], 1
+    vinserti128          m1, [cq+16*7], 1
+    vpbroadcastd         m7, [o(pw_1697x16)]
+    vpbroadcastd         m8, [o(pw_16384)]
+    punpcklwd            m3, m2, m4
+    punpckhwd            m2, m4
+    punpcklwd            m4, m0, m1
+    punpckhwd            m0, m1
+    punpcklwd            m1, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m4, m0
+    punpckhwd            m4, m0
+    pmulhrsw             m0, m7, m1
+    pmulhrsw             m5, m7, m2
+    pmulhrsw             m6, m7, m3
+    pmulhrsw             m7, m4
+    REPX   {pmulhrsw x, m8}, m0, m5, m6, m7
+    paddsw               m1, m0
+    paddsw               m2, m5
+    paddsw               m3, m6
+    paddsw               m4, m7
+    punpcklqdq           m0, m1, m2
+    punpckhqdq           m1, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m7, [o(pw_1697x8)]
+    pmulhrsw             m4, m7, m0
+    pmulhrsw             m5, m7, m1
+    pmulhrsw             m6, m7, m2
+    pmulhrsw             m7, m3
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    jmp m(iadst_16x4_internal_8bpc).end
+
+%macro INV_TXFM_16X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x8
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm1
+    or                  r3d, 8
+    jmp m(inv_txfm_add_dct_dct_16x4_8bpc).dconly
+%endif
+%endmacro
+
+%macro ITX_16X8_LOAD_COEFS 1 ; shuf_odd
+    vpbroadcastd         m8, [o(pw_2896x8)]
+    vpermq               m0, [cq+32*0], q3120
+    add                  cq, 32*4
+    vpermq               m7, [cq+32*3], q%1
+    vpermq               m1, [cq-32*3], q%1
+    vpermq               m6, [cq+32*2], q3120
+    vpermq               m2, [cq-32*2], q3120
+    vpermq               m5, [cq+32*1], q%1
+    vpermq               m3, [cq-32*1], q%1
+    vpermq               m4, [cq+32*0], q3120
+    REPX   {pmulhrsw x, m8}, m0, m7, m1, m6, m2, m5, m3, m4
+%endmacro
+
+INV_TXFM_16X8_FN dct, dct
+INV_TXFM_16X8_FN dct, adst
+INV_TXFM_16X8_FN dct, flipadst
+INV_TXFM_16X8_FN dct, identity
+
+cglobal idct_16x8_internal_8bpc, 0, 5, 13, dst, stride, c, eob, tx2
+    ITX_16X8_LOAD_COEFS 3120
+    call m(idct_8x16_internal_8bpc).main
+    vpbroadcastd        m10, [o(pw_16384)]
+    punpckhwd            m8, m0, m2
+    punpcklwd            m0, m2
+    punpckhwd            m2, m1, m3
+    punpcklwd            m1, m3
+    punpcklwd            m9, m4, m6
+    punpckhwd            m4, m6
+    punpcklwd            m6, m5, m7
+    punpckhwd            m5, m7
+    REPX  {pmulhrsw x, m10}, m8, m1, m4, m6
+.pass1_end:
+    REPX  {pmulhrsw x, m10}, m0, m2, m9, m5
+    punpckhwd            m3, m0, m8
+    punpcklwd            m0, m8
+    punpckhwd            m8, m2, m1
+    punpcklwd            m2, m1
+    punpcklwd            m7, m9, m4
+    punpckhwd            m9, m4
+    punpcklwd            m4, m5, m6
+    punpckhwd            m5, m6
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m3, m8
+    punpckhdq            m3, m8
+    punpckldq            m6, m7, m4
+    punpckhdq            m7, m4
+    punpckldq            m8, m9, m5
+    punpckhdq            m9, m5
+    vperm2i128           m4, m0, m6, 0x31
+    vinserti128          m0, xm6, 1
+    vperm2i128           m5, m1, m7, 0x31
+    vinserti128          m1, xm7, 1
+    vperm2i128           m6, m2, m8, 0x31
+    vinserti128          m2, xm8, 1
+    vperm2i128           m7, m3, m9, 0x31
+    vinserti128          m3, xm9, 1
+    jmp                tx2q
+.pass2:
+    call .main
+    vpbroadcastd         m8, [o(pw_2048)]
+.end:
+    REPX   {pmulhrsw x, m8}, m0, m2, m4, m6
+.end2:
+    REPX   {pmulhrsw x, m8}, m1, m3, m5, m7
+    lea                  r3, [strideq*3]
+    WRITE_16X2            0, 1, 8, 0, strideq*0, strideq*1
+    WRITE_16X2            2, 3, 0, 1, strideq*2, r3
+.end3:
+    pxor                 m0, m0
+    REPX {mova [cq+32*x], m0}, -4, -3, -2, -1, 0, 1, 2, 3
+.end4:
+    lea                dstq, [dstq+strideq*4]
+    WRITE_16X2            4, 5, 0, 1, strideq*0, strideq*1
+    WRITE_16X2            6, 7, 0, 1, strideq*2, r3
+    RET
+ALIGN function_align
+cglobal_label .main
+    vpbroadcastd        m10, [o(pd_2048)]
+.main2:
+    IDCT8_1D              0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
+    ret
+
+INV_TXFM_16X8_FN adst, dct
+INV_TXFM_16X8_FN adst, adst
+INV_TXFM_16X8_FN adst, flipadst
+INV_TXFM_16X8_FN adst, identity
+
+cglobal iadst_16x8_internal_8bpc, 0, 5, 13, dst, stride, c, eob, tx2
+    ITX_16X8_LOAD_COEFS 1302
+    call m(iadst_8x16_internal_8bpc).main2
+    call m(iadst_8x16_internal_8bpc).main_pass1_end
+    psubw               m11, m9, m10
+    punpcklwd            m8, m0, m2
+    punpckhwd            m0, m2
+    punpckhwd            m2, m1, m3
+    punpcklwd            m1, m3
+    punpcklwd            m9, m4, m6
+    punpckhwd            m4, m6
+    punpckhwd            m6, m5, m7
+    punpcklwd            m5, m7
+    REPX  {pmulhrsw x, m11}, m8, m1, m4, m6
+    jmp m(idct_16x8_internal_8bpc).pass1_end
+ALIGN function_align
+.pass2:
+    call .main
+    call .main_pass2_end
+    pxor                 m8, m8
+    psubw                m8, m9
+    REPX   {pmulhrsw x, m9}, m0, m2, m4, m6
+    jmp m(idct_16x8_internal_8bpc).end2
+ALIGN function_align
+cglobal_label .main
+    vpbroadcastd        m10, [o(pd_2048)]
+    ITX_MULSUB_2W         7, 0, 8, 9, 10,  401, 4076 ; t1a, t0a
+    ITX_MULSUB_2W         3, 4, 8, 9, 10, 3166, 2598 ; t5a, t4a
+    ITX_MULSUB_2W         1, 6, 8, 9, 10, 3920, 1189 ; t7a, t6a
+    ITX_MULSUB_2W         5, 2, 8, 9, 10, 1931, 3612 ; t3a, t2a
+    psubsw               m8, m2, m6 ; t6
+    paddsw               m2, m6     ; t2
+    psubsw               m6, m0, m4 ; t4
+    paddsw               m0, m4     ; t0
+    psubsw               m4, m5, m1 ; t7
+    paddsw               m5, m1     ; t3
+    psubsw               m1, m7, m3 ; t5
+    paddsw               m7, m3     ; t1
+    ITX_MULSUB_2W         6, 1, 3, 9, 10, 1567, 3784 ; t5a, t4a
+    ITX_MULSUB_2W         4, 8, 3, 9, 10, 3784, 1567 ; t6a, t7a
+    psubsw               m9, m6, m8 ;  t7
+    paddsw               m6, m8     ;  out6
+    psubsw               m3, m7, m5 ;  t3
+    paddsw               m7, m5     ; -out7
+    psubsw               m5, m0, m2 ;  t2
+    paddsw               m0, m2     ;  out0
+    psubsw               m2, m1, m4 ;  t6
+    paddsw               m1, m4     ; -out1
+    ret
+ALIGN function_align
+.main_pass1_end:
+    vpbroadcastd        m11, [o(pw_m2896_2896)]
+    vpbroadcastd        m12, [o(pw_2896_2896)]
+    punpckhwd            m4, m3, m5
+    punpcklwd            m3, m5
+    pmaddwd              m5, m11, m4
+    pmaddwd              m4, m12
+    pmaddwd              m8, m11, m3
+    pmaddwd              m3, m12
+    REPX     {paddd x, m10}, m5, m4, m8, m3
+    REPX     {psrad x, 12 }, m5, m8, m4, m3
+    packssdw             m3, m4     ; -out3
+    packssdw             m4, m8, m5 ;  out4
+    punpcklwd            m5, m9, m2
+    punpckhwd            m9, m2
+    pmaddwd              m2, m12, m5
+    pmaddwd              m5, m11
+    pmaddwd             m12, m9
+    pmaddwd             m11, m9
+    REPX     {paddd x, m10}, m2, m5, m12, m11
+    REPX     {psrad x, 12 }, m2, m12, m5, m11
+    packssdw             m2, m12    ;  out2
+    packssdw             m5, m11    ; -out5
+    ret
+ALIGN function_align
+cglobal_label .main_pass2_end
+    vpbroadcastd         m8, [o(pw_2896x8)]
+    psubsw               m4, m5, m3
+    paddsw               m3, m5
+    psubsw               m5, m2, m9
+    paddsw               m2, m9
+    pmulhrsw             m2, m8     ;  out2
+    pmulhrsw             m3, m8     ; -out3
+    pmulhrsw             m4, m8     ;  out4
+    pmulhrsw             m5, m8     ; -out5
+    vpbroadcastd         m9, [o(pw_2048)]
+    ret
+
+INV_TXFM_16X8_FN flipadst, dct
+INV_TXFM_16X8_FN flipadst, adst
+INV_TXFM_16X8_FN flipadst, flipadst
+INV_TXFM_16X8_FN flipadst, identity
+
+cglobal iflipadst_16x8_internal_8bpc, 0, 5, 13, dst, stride, c, eob, tx2
+    ITX_16X8_LOAD_COEFS 1302
+    call m(iadst_8x16_internal_8bpc).main2
+    call m(iadst_8x16_internal_8bpc).main_pass1_end
+    psubw                m9, m10
+    punpcklwd            m8, m6, m4
+    punpckhwd            m6, m4
+    punpcklwd            m4, m7, m5
+    punpckhwd            m7, m5
+    punpckhwd            m5, m3, m1
+    punpcklwd            m3, m1
+    punpckhwd            m1, m2, m0
+    punpcklwd            m2, m0
+    REPX  {pmulhrsw x, m10}, m8, m4, m5, m1
+    REPX  {pmulhrsw x, m9 }, m6, m7, m3, m2
+    punpcklwd            m0, m7, m4
+    punpckhwd            m7, m4
+    punpckhwd            m4, m6, m8
+    punpcklwd            m6, m8
+    punpckhwd            m8, m3, m5
+    punpcklwd            m3, m5
+    punpcklwd            m5, m2, m1
+    punpckhwd            m2, m1
+    punpckhdq            m1, m0, m6
+    punpckldq            m0, m6
+    punpckldq            m6, m7, m4
+    punpckhdq            m7, m4
+    punpckhdq            m4, m3, m5
+    punpckldq            m3, m5
+    punpckldq            m5, m8, m2
+    punpckhdq            m8, m2
+    vinserti128          m2, m6, xm5, 1
+    vperm2i128           m6, m5, 0x31
+    vperm2i128           m5, m1, m4, 0x31
+    vinserti128          m1, xm4, 1
+    vperm2i128           m4, m0, m3, 0x31
+    vinserti128          m0, xm3, 1
+    vinserti128          m3, m7, xm8, 1
+    vperm2i128           m7, m8, 0x31
+    jmp                tx2q
+.pass2:
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass2_end
+    pxor                 m8, m8
+    psubw                m8, m9
+    pmulhrsw            m10, m7, m8
+    pmulhrsw             m7, m0, m9
+    pmulhrsw             m0, m6, m9
+    pmulhrsw             m6, m1, m8
+    pmulhrsw             m1, m5, m8
+    pmulhrsw             m5, m2, m9
+    pmulhrsw             m2, m4, m9
+    pmulhrsw             m4, m3, m8
+    lea                  r3, [strideq*3]
+    WRITE_16X2           10, 0, 8, 9, strideq*0, strideq*1
+    WRITE_16X2            1, 2, 0, 1, strideq*2, r3
+    jmp m(idct_16x8_internal_8bpc).end3
+
+INV_TXFM_16X8_FN identity, dct
+INV_TXFM_16X8_FN identity, adst
+INV_TXFM_16X8_FN identity, flipadst
+INV_TXFM_16X8_FN identity, identity
+
+cglobal iidentity_16x8_internal_8bpc, 0, 5, 13, dst, stride, c, eob, tx2
+    mova                xm7, [cq+16*0]
+    mova                xm2, [cq+16*1]
+    add                  cq, 16*8
+    vpbroadcastd         m3, [o(pw_2896x8)]
+    vinserti128          m7, [cq+16*0], 1
+    vinserti128          m2, [cq+16*1], 1
+    mova                xm6, [cq-16*6]
+    mova                xm4, [cq-16*5]
+    vinserti128          m6, [cq+16*2], 1
+    vinserti128          m4, [cq+16*3], 1
+    mova                xm8, [cq-16*4]
+    mova                xm5, [cq-16*3]
+    vinserti128          m8, [cq+16*4], 1
+    vinserti128          m5, [cq+16*5], 1
+    mova                xm0, [cq-16*2]
+    mova                xm1, [cq-16*1]
+    vinserti128          m0, [cq+16*6], 1
+    vinserti128          m1, [cq+16*7], 1
+    vpbroadcastd        m10, [o(pw_1697x16)]
+    vpbroadcastd        m11, [o(pw_16384)]
+    REPX   {pmulhrsw x, m3}, m7, m2, m6, m4, m8, m5, m0, m1
+    punpcklwd            m3, m7, m2
+    punpckhwd            m7, m2
+    punpcklwd            m2, m6, m4
+    punpckhwd            m6, m4
+    punpcklwd            m4, m8, m5
+    punpckhwd            m8, m5
+    punpcklwd            m5, m0, m1
+    punpckhwd            m0, m1
+    punpckldq            m1, m3, m2
+    punpckhdq            m3, m2
+    punpckldq            m2, m4, m5
+    punpckhdq            m4, m5
+    punpckldq            m5, m7, m6
+    punpckhdq            m7, m6
+    punpckldq            m6, m8, m0
+    punpckhdq            m8, m0
+    REPX {IDTX16 x, 0, 10, 11}, 1, 3, 2, 4, 5, 7, 6, 8
+    punpcklqdq           m0, m1, m2
+    punpckhqdq           m1, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    punpcklqdq           m4, m5, m6
+    punpckhqdq           m5, m6
+    punpcklqdq           m6, m7, m8
+    punpckhqdq           m7, m8
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m8, [o(pw_4096)]
+    jmp m(idct_16x8_internal_8bpc).end
+
+%define o_base pw_5 + 128
+
+%macro INV_TXFM_16X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x16
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_8192)]
+    mov                [cq], eobd
+    or                  r3d, 16
+    jmp m(inv_txfm_add_dct_dct_16x4_8bpc).dconly
+%endif
+%endmacro
+
+%macro ITX_16X16_LOAD_COEFS 0
+    mova                 m0, [cq+32*0]
+    mova                 m1, [cq+32*1]
+    mova                 m2, [cq+32*2]
+    mova                 m3, [cq+32*3]
+    add                  cq, 32*8
+    mova                 m4, [cq-32*4]
+    mova                 m5, [cq-32*3]
+    mova                 m6, [cq-32*2]
+    mova                 m7, [cq-32*1]
+    mova                 m8, [cq+32*0]
+    mova                 m9, [cq+32*1]
+    mova                m10, [cq+32*2]
+    mova                m11, [cq+32*3]
+    mova                m12, [cq+32*4]
+    mova                m13, [cq+32*5]
+    mova                m14, [cq+32*6]
+    mova                m15, [cq+32*7]
+    mova              [rsp], m15
+%endmacro
+
+INV_TXFM_16X16_FN dct, dct
+INV_TXFM_16X16_FN dct, adst
+INV_TXFM_16X16_FN dct, flipadst
+INV_TXFM_16X16_FN dct, identity
+
+cglobal idct_16x16_internal_8bpc, 0, 5, 16, 32*3, dst, stride, c, eob, tx2
+    ITX_16X16_LOAD_COEFS
+    call .main
+.pass1_end:
+    vpbroadcastd         m1, [o(pw_8192)]
+    REPX   {pmulhrsw x, m1}, m0, m2, m4, m6, m8, m10, m12, m14
+    vextracti128 [rsp+16*5], m8, 1
+    mova         [rsp+16*1], xm8
+.pass1_end2:
+    vextracti128 [rsp+16*4], m0, 1
+    mova         [rsp+16*0], xm0
+    REPX   {pmulhrsw x, m1}, m3, m5, m7, m9, m11, m13, m15
+    pmulhrsw             m1, [rsp+32*1]
+    vperm2i128           m8, m1, m9, 0x31
+    vinserti128          m1, xm9, 1
+    vperm2i128           m9, m2, m10, 0x31
+    vinserti128          m2, xm10, 1
+    vperm2i128          m10, m3, m11, 0x31
+    vinserti128          m3, xm11, 1
+    vperm2i128          m11, m4, m12, 0x31
+    vinserti128          m4, xm12, 1
+    vperm2i128          m12, m5, m13, 0x31
+    vinserti128          m5, xm13, 1
+    vperm2i128          m13, m6, m14, 0x31
+    vinserti128          m6, xm14, 1
+    vperm2i128          m14, m7, m15, 0x31
+    vinserti128          m7, xm15, 1
+    mova                m15, [rsp+32*2]
+.pass1_end3:
+    punpcklwd            m0, m9, m10
+    punpckhwd            m9, m10
+    punpcklwd           m10, m15, m8
+    punpckhwd           m15, m8
+    punpckhwd            m8, m11, m12
+    punpcklwd           m11, m12
+    punpckhwd           m12, m13, m14
+    punpcklwd           m13, m14
+    punpckhdq           m14, m11, m13
+    punpckldq           m11, m13
+    punpckldq           m13, m15, m9
+    punpckhdq           m15, m9
+    punpckldq            m9, m10, m0
+    punpckhdq           m10, m0
+    punpckhdq            m0, m8, m12
+    punpckldq            m8, m12
+    punpcklqdq          m12, m13, m8
+    punpckhqdq          m13, m8
+    punpcklqdq           m8, m9, m11
+    punpckhqdq           m9, m11
+    punpckhqdq          m11, m10, m14
+    punpcklqdq          m10, m14
+    punpcklqdq          m14, m15, m0
+    punpckhqdq          m15, m0
+    mova                 m0, [rsp]
+    mova              [rsp], m15
+    punpckhwd           m15, m4, m5
+    punpcklwd            m4, m5
+    punpckhwd            m5, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m6, m7
+    punpcklwd            m6, m7
+    punpckhwd            m7, m2, m3
+    punpcklwd            m2, m3
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m4, m6
+    punpckhdq            m4, m6
+    punpckhdq            m6, m5, m7
+    punpckldq            m5, m7
+    punpckldq            m7, m15, m1
+    punpckhdq           m15, m1
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    punpcklqdq           m4, m5, m7
+    punpckhqdq           m5, m7
+    punpckhqdq           m7, m6, m15
+    punpcklqdq           m6, m15
+    jmp                tx2q
+.pass2:
+    call .main
+.end:
+    vpbroadcastd         m1, [o(pw_2048)]
+    REPX   {pmulhrsw x, m1}, m0, m2, m4, m6, m8, m10, m12, m14
+    mova              [rsp], m6
+.end2:
+    REPX   {pmulhrsw x, m1}, m3, m5, m7, m9, m11, m13, m15
+    pmulhrsw             m1, [rsp+32*1]
+    lea                  r3, [strideq*3]
+    WRITE_16X2            0,  1,  6,  0, strideq*0, strideq*1
+    WRITE_16X2            2,  3,  0,  1, strideq*2, r3
+    lea                dstq, [dstq+strideq*4]
+    WRITE_16X2            4,  5,  0,  1, strideq*0, strideq*1
+    WRITE_16X2        [rsp],  7,  0,  1, strideq*2, r3
+.end3:
+    pxor                 m2, m2
+    REPX {mova [cq+32*x], m2}, -8, -7, -6, -5, -4, -3, -2, -1
+    lea                dstq, [dstq+strideq*4]
+    WRITE_16X2            8,  9,  0,  1, strideq*0, strideq*1
+    WRITE_16X2           10, 11,  0,  1, strideq*2, r3
+    REPX {mova [cq+32*x], m2},  0,  1,  2,  3,  4,  5,  6,  7
+    lea                dstq, [dstq+strideq*4]
+    WRITE_16X2           12, 13,  0,  1, strideq*0, strideq*1
+    WRITE_16X2           14, 15,  0,  1, strideq*2, r3
+    RET
+ALIGN function_align
+cglobal_label .main
+    vpbroadcastd        m15, [o(pd_2048)]
+    mova [rsp+gprsize+32*1], m1
+    mova [rsp+gprsize+32*2], m9
+    IDCT8_1D              0,  2,  4,  6,  8, 10, 12, 14,  1,  9, 15
+    mova                 m1, [rsp+gprsize+32*2] ; in9
+    mova [rsp+gprsize+32*2], m14 ; tmp7
+    mova                 m9, [rsp+gprsize+32*1] ; in1
+    mova [rsp+gprsize+32*1], m10 ; tmp5
+    mova                m14, [rsp+gprsize+32*0] ; in15
+    mova [rsp+gprsize+32*0], m6  ; tmp3
+    IDCT16_1D_ODDHALF     9,  3,  5,  7,  1, 11, 13, 14,  6, 10, 15
+    mova                 m6, [rsp+gprsize+32*1] ; tmp5
+    psubsw              m15, m0, m14  ; out15
+    paddsw               m0, m14      ; out0
+    psubsw              m14, m2, m13  ; out14
+    paddsw               m2, m13      ; out1
+    mova [rsp+gprsize+32*1], m2
+    psubsw              m13, m4, m11  ; out13
+    paddsw               m2, m4, m11  ; out2
+    psubsw              m11, m8, m7   ; out11
+    paddsw               m4, m8, m7   ; out4
+    mova                 m7, [rsp+gprsize+32*2] ; tmp7
+    psubsw              m10, m6, m5   ; out10
+    paddsw               m5, m6       ; out5
+    psubsw               m8, m7, m9   ; out8
+    paddsw               m7, m9       ; out7
+    psubsw               m9, m12, m3  ; out9
+    paddsw               m6, m12, m3  ; out6
+    mova                 m3, [rsp+gprsize+32*0] ; tmp3
+    psubsw              m12, m3, m1   ; out12
+    paddsw               m3, m1       ; out3
+    ret
+
+INV_TXFM_16X16_FN adst, dct
+INV_TXFM_16X16_FN adst, adst
+INV_TXFM_16X16_FN adst, flipadst
+
+cglobal iadst_16x16_internal_8bpc, 0, 5, 16, 32*3, dst, stride, c, eob, tx2
+    ITX_16X16_LOAD_COEFS
+    call .main
+    call .main_pass1_end
+    pmulhrsw             m0, m1, [cq+32*0]
+    pmulhrsw             m2, m1, [cq+32*1]
+    REPX   {pmulhrsw x, m1}, m4, m6, m8, m10
+    pmulhrsw            m12, m1, [cq+32*2]
+    pmulhrsw            m14, m1, [cq+32*3]
+    vextracti128 [rsp+16*5], m8, 1
+    mova         [rsp+16*1], xm8
+    pxor                 m8, m8
+    psubw                m1, m8, m1
+    jmp m(idct_16x16_internal_8bpc).pass1_end2
+ALIGN function_align
+.pass2:
+    call .main
+    call .main_pass2_end
+    REPX   {pmulhrsw x, m1}, m0, m2, m4, m6, m8, m10, m12, m14
+    mova         [rsp+32*0], m6
+    pxor                 m6, m6
+    psubw                m1, m6, m1
+    jmp m(idct_16x16_internal_8bpc).end2
+ALIGN function_align
+cglobal_label .main
+    vpbroadcastd        m15, [o(pd_2048)]
+    mova [rsp+gprsize+32*1], m0
+    mova [rsp+gprsize+32*2], m4
+    ITX_MULSUB_2W        13,  2,  0,  4, 15,  995, 3973 ; t3,  t2
+    ITX_MULSUB_2W         9,  6,  0,  4, 15, 2440, 3290 ; t7,  t6
+    ITX_MULSUB_2W         5, 10,  0,  4, 15, 3513, 2106 ; t11, t10
+    ITX_MULSUB_2W         1, 14,  0,  4, 15, 4052,  601 ; t15, t14
+    psubsw               m0, m2, m10  ; t10a
+    paddsw               m2, m10      ; t2a
+    psubsw              m10, m13, m5  ; t11a
+    paddsw              m13, m5       ; t3a
+    psubsw               m5, m6, m14  ; t14a
+    paddsw               m6, m14      ; t6a
+    psubsw              m14, m9, m1   ; t15a
+    paddsw               m9, m1       ; t7a
+    ITX_MULSUB_2W         0, 10,  1,  4, 15, 3406, 2276 ; t11, t10
+    ITX_MULSUB_2W        14,  5,  1,  4, 15, 2276, 3406 ; t14, t15
+    psubsw               m1, m10, m14 ; t14a
+    paddsw              m10, m14      ; t10a
+    psubsw              m14, m0, m5   ; t15a
+    paddsw               m0, m5       ; t11a
+    psubsw               m5, m2, m6   ; t6
+    paddsw               m2, m6       ; t2
+    psubsw               m6, m13, m9  ; t7
+    paddsw              m13, m9       ; t3
+    ITX_MULSUB_2W         6,  5,  4,  9, 15, 3784, 1567 ; t6a, t7a
+    ITX_MULSUB_2W        14,  1,  4,  9, 15, 3784, 1567 ; t14, t15
+    mova                 m9, [rsp+gprsize+32*0] ; in15
+    mova [rsp+gprsize+32*0], m10 ; t10a
+    mova                 m4, [rsp+gprsize+32*1] ; in0
+    mova [rsp+gprsize+32*1], m6  ; t6a
+    mova                 m6, [rsp+gprsize+32*2] ; in4
+    mova [rsp+gprsize+32*2], m2  ; t2
+    ITX_MULSUB_2W         9,  4,  2, 10, 15,  201, 4091 ; t1,  t0
+    ITX_MULSUB_2W        11,  6,  2, 10, 15, 1751, 3703 ; t5,  t4
+    ITX_MULSUB_2W         7,  8,  2, 10, 15, 3035, 2751 ; t9,  t8
+    ITX_MULSUB_2W         3, 12,  2, 10, 15, 3857, 1380 ; t13, t12
+    psubsw              m10, m4, m8  ; t8a
+    paddsw               m8, m4      ; t0a
+    psubsw               m4, m9, m7  ; t9a
+    paddsw               m9, m7      ; t1a
+    psubsw               m7, m6, m12 ; t12a
+    paddsw               m6, m12     ; t4a
+    psubsw              m12, m11, m3 ; t13a
+    paddsw              m11, m3      ; t5a
+    ITX_MULSUB_2W        10,  4,  2,  3, 15,  799, 4017 ; t9,  t8
+    ITX_MULSUB_2W        12,  7,  2,  3, 15, 4017,  799 ; t12, t13
+    psubsw               m3, m9, m11 ; t5
+    paddsw               m9, m11     ; t1
+    psubsw              m11, m4, m12 ; t12a
+    paddsw               m4, m12     ; t8a
+    paddsw              m12, m8, m6  ; t0
+    psubsw               m8, m6      ; t4
+    paddsw               m6, m10, m7 ; t9a
+    psubsw              m10, m7      ; t13a
+    ITX_MULSUB_2W         8,  3,  2,  7, 15, 1567, 3784 ; t5a, t4a
+    ITX_MULSUB_2W        11, 10,  2,  7, 15, 1567, 3784 ; t13, t12
+    mova                 m7, [rsp+gprsize+32*0] ; t10a
+    mova                 m2, [rsp+gprsize+32*1] ; t6a
+    paddsw              m15, m9, m13  ; -out15
+    psubsw               m9, m13      ;  t3a
+    paddsw              m13, m11, m1  ; -out13
+    psubsw              m11, m1       ;  t15a
+    psubsw               m1, m4, m7   ;  t10
+    paddsw               m7, m4       ; -out1
+    psubsw               m4, m3, m2   ;  t6
+    paddsw               m3, m2       ; -out3
+    paddsw               m2, m10, m14 ;  out2
+    psubsw              m10, m14      ;  t14a
+    paddsw              m14, m6, m0   ;  out14
+    psubsw               m6, m0       ;  t11
+    mova                 m0, [rsp+gprsize+32*2] ; t2
+    mova [rsp+gprsize+32*1], m7
+    psubsw               m7, m12, m0  ;  t2a
+    paddsw               m0, m12      ;  out0
+    paddsw              m12, m8, m5   ;  out12
+    psubsw               m8, m5       ;  t7
+    ret
+ALIGN function_align
+.main_pass1_end:
+    mova          [cq+32*0], m0
+    mova          [cq+32*1], m2
+    mova          [cq+32*2], m12
+    mova          [cq+32*3], m14
+    vpbroadcastd        m14, [pw_m2896_2896]
+    vpbroadcastd        m12, [pw_2896_2896]
+    vpbroadcastd         m2, [pd_2048]
+    punpcklwd            m5, m11, m10
+    punpckhwd           m11, m10
+    pmaddwd             m10, m14, m5
+    pmaddwd              m0, m14, m11
+    pmaddwd              m5, m12
+    pmaddwd             m11, m12
+    REPX      {paddd x, m2}, m10, m0, m5, m11
+    REPX      {psrad x, 12}, m10, m0, m5, m11
+    packssdw            m10, m0  ;  out10
+    packssdw             m5, m11 ; -out5
+    punpcklwd           m11, m8, m4
+    punpckhwd            m8, m4
+    pmaddwd              m4, m12, m11
+    pmaddwd              m0, m12, m8
+    pmaddwd             m11, m14
+    pmaddwd              m8, m14
+    REPX      {paddd x, m2}, m4, m0, m11, m8
+    REPX      {psrad x, 12}, m4, m0, m11, m8
+    packssdw             m4, m0  ;  out4
+    packssdw            m11, m8  ; -out11
+    punpcklwd            m8, m9, m7
+    punpckhwd            m9, m7
+    pmaddwd              m7, m12, m8
+    pmaddwd              m0, m12, m9
+    pmaddwd              m8, m14
+    pmaddwd              m9, m14
+    REPX      {paddd x, m2}, m7, m0, m8, m9
+    REPX      {psrad x, 12}, m7, m0, m8, m9
+    packssdw             m7, m0  ; -out7
+    packssdw             m8, m9  ;  out8
+    punpckhwd            m0, m6, m1
+    punpcklwd            m6, m1
+    pmaddwd              m1, m14, m0
+    pmaddwd              m9, m14, m6
+    pmaddwd              m0, m12
+    pmaddwd              m6, m12
+    REPX      {paddd x, m2}, m1, m9, m0, m6
+    REPX      {psrad x, 12}, m1, m9, m0, m6
+    packssdw             m9, m1  ; -out7
+    packssdw             m6, m0  ;  out8
+    vpbroadcastd         m1, [o(pw_8192)]
+    ret
+ALIGN function_align
+cglobal_label .main_pass2_end
+    ; In pass 2 we're going to clip to pixels afterwards anyway, so clipping to
+    ; 16-bit here will produce the same result as using 32-bit intermediates.
+    paddsw               m5, m10, m11 ; -out5
+    psubsw              m10, m11      ;  out10
+    psubsw              m11, m4, m8   ; -out11
+    paddsw               m4, m8       ;  out4
+    psubsw               m8, m7, m9   ;  out8
+    paddsw               m7, m9       ; -out7
+    psubsw               m9, m1, m6   ; -out9
+    paddsw               m6, m1       ;  out6
+    vpbroadcastd         m1, [o(pw_2896x8)]
+    REPX   {pmulhrsw x, m1}, m4, m5, m6, m7, m8, m9, m10, m11
+    vpbroadcastd         m1, [o(pw_2048)]
+    ret
+
+INV_TXFM_16X16_FN flipadst, dct
+INV_TXFM_16X16_FN flipadst, adst
+INV_TXFM_16X16_FN flipadst, flipadst
+
+cglobal iflipadst_16x16_internal_8bpc, 0, 5, 16, 32*3, dst, stride, c, eob, tx2
+    ITX_16X16_LOAD_COEFS
+    call m(iadst_16x16_internal_8bpc).main
+    call m(iadst_16x16_internal_8bpc).main_pass1_end
+    pmulhrsw             m6, m1
+    pmulhrsw             m2, m1, m8
+    mova         [rsp+32*2], m6
+    pmulhrsw             m6, m1, m4
+    pmulhrsw             m4, m1, m10
+    pmulhrsw             m8, m1, [cq+32*3]
+    pmulhrsw            m10, m1, [cq+32*2]
+    pmulhrsw            m12, m1, [cq+32*1]
+    pmulhrsw            m14, m1, [cq+32*0]
+    pxor                 m0, m0
+    psubw                m0, m1
+    REPX   {pmulhrsw x, m0}, m3, m5, m7, m11, m15
+    pmulhrsw             m1, m0, m9
+    pmulhrsw             m9, m0, m13
+    pmulhrsw             m0, [rsp+32*1]
+    mova         [rsp+16*0], xm15
+    mova         [rsp+16*1], xm7
+    vperm2i128          m15, m15, m7, 0x31
+    vinserti128          m7, m2, xm14, 1
+    vperm2i128          m14, m2, m14, 0x31
+    vinserti128          m2, m9, xm5, 1
+    vperm2i128           m9, m9, m5, 0x31
+    vinserti128          m5, m4, xm12, 1
+    vperm2i128          m12, m4, m12, 0x31
+    vinserti128          m4, m11, xm3, 1
+    vperm2i128          m11, m11, m3, 0x31
+    vinserti128          m3, m10, xm6, 1
+    vperm2i128          m10, m10, m6, 0x31
+    vinserti128          m6, m1, xm0, 1
+    vperm2i128          m13, m1, m0, 0x31
+    vinserti128          m1, m8, [rsp+32*2], 1
+    vperm2i128           m8, m8, [rsp+32*2], 0x31
+    jmp m(idct_16x16_internal_8bpc).pass1_end3
+.pass2:
+    call m(iadst_16x16_internal_8bpc).main
+    call m(iadst_16x16_internal_8bpc).main_pass2_end
+    pmulhrsw             m0, m1
+    pmulhrsw             m8, m1
+    mova         [rsp+32*0], m0
+    mova         [rsp+32*2], m8
+    pxor                 m0, m0
+    psubw                m0, m1
+    pmulhrsw             m8, m0, m7
+    pmulhrsw             m7, m0, m9
+    pmulhrsw             m9, m1, m6
+    pmulhrsw             m6, m1, m10
+    pmulhrsw            m10, m0, m5
+    pmulhrsw             m5, m0, m11
+    pmulhrsw            m11, m1, m4
+    pmulhrsw             m4, m1, m12
+    pmulhrsw            m12, m0, m3
+    pmulhrsw             m3, m0, m13
+    pmulhrsw            m13, m1, m2
+    pmulhrsw             m1, m14
+    pmulhrsw            m14, m0, [rsp+32*1]
+    pmulhrsw             m0, m15
+    lea                  r3, [strideq*3]
+    WRITE_16X2            0,  1,  2,  0, strideq*0, strideq*1
+    mova                m15, [rsp+32*0]
+    WRITE_16X2            3,  4,  0,  1, strideq*2, r3
+    lea                dstq, [dstq+strideq*4]
+    WRITE_16X2            5,  6,  0,  1, strideq*0, strideq*1
+    WRITE_16X2            7, [rsp+32*2],  0,  1, strideq*2, r3
+    jmp m(idct_16x16_internal_8bpc).end3
+
+%macro IDTX16B 3 ; src/dst, tmp, pw_1697x16
+    pmulhrsw            m%2, m%3, m%1
+    psraw               m%2, 1
+    pavgw               m%1, m%2 ; signs are guaranteed to be equal
+%endmacro
+
+INV_TXFM_16X16_FN identity, dct
+INV_TXFM_16X16_FN identity, identity
+
+cglobal iidentity_16x16_internal_8bpc, 0, 5, 16, 32*3, dst, stride, c, eob, tx2
+    vpbroadcastd         m7, [o(pw_1697x16)]
+    mova                xm0, [cq+16* 0]
+    vinserti128          m0, [cq+16*16], 1
+    mova               xm15, [cq+16* 1]
+    vinserti128         m15, [cq+16*17], 1
+    mova                xm1, [cq+16* 2]
+    vinserti128          m1, [cq+16*18], 1
+    mova                xm8, [cq+16* 3]
+    vinserti128          m8, [cq+16*19], 1
+    mova                xm2, [cq+16* 4]
+    vinserti128          m2, [cq+16*20], 1
+    mova                xm9, [cq+16* 5]
+    vinserti128          m9, [cq+16*21], 1
+    mova                xm3, [cq+16* 6]
+    vinserti128          m3, [cq+16*22], 1
+    mova               xm10, [cq+16* 7]
+    add                  cq, 16*16
+    vinserti128         m10, [cq+16* 7], 1
+    mova                xm4, [cq-16* 8]
+    vinserti128          m4, [cq+16* 8], 1
+    mova               xm11, [cq-16* 7]
+    vinserti128         m11, [cq+16* 9], 1
+    mova                xm5, [cq-16* 6]
+    vinserti128          m5, [cq+16*10], 1
+    mova               xm12, [cq-16* 5]
+    vinserti128         m12, [cq+16*11], 1
+    mova               xm13, [cq-16* 3]
+    vinserti128         m13, [cq+16*13], 1
+    mova               xm14, [cq-16* 1]
+    vinserti128         m14, [cq+16*15], 1
+    REPX  {IDTX16B x, 6, 7},  0, 15,  1,  8,  2,  9,  3, \
+                             10,  4, 11,  5, 12, 13, 14
+    mova                xm6, [cq-16* 4]
+    vinserti128          m6, [cq+16*12], 1
+    mova              [rsp], m0
+    IDTX16B               6, 0, 7
+    mova                xm0, [cq-16* 2]
+    vinserti128          m0, [cq+16*14], 1
+    pmulhrsw             m7, m0
+    psraw                m7, 1
+    pavgw                m7, m0
+    jmp m(idct_16x16_internal_8bpc).pass1_end3
+ALIGN function_align
+.pass2:
+    vpbroadcastd        m15, [o(pw_1697x16)]
+    mova         [rsp+32*1], m0
+    REPX  {IDTX16 x, 0, 15},  1,  2,  3,  4,  5,  6,  7, \
+                              8,  9, 10, 11, 12, 13, 14
+    mova                 m0, [rsp+32*1]
+    mova         [rsp+32*1], m1
+    IDTX16                0, 1, 15
+    mova                 m1, [rsp+32*0]
+    pmulhrsw            m15, m1
+    paddsw               m1, m1
+    paddsw              m15, m1
+    jmp m(idct_16x16_internal_8bpc).end
+
+%define o_base deint_shuf + 128
+
+%macro LOAD_8ROWS 2-3 0 ; src, stride, is_rect2
+%if %3
+    vpbroadcastd        m15, [o(pw_2896x8)]
+    pmulhrsw             m0, m15, [%1+%2*0]
+    pmulhrsw             m1, m15, [%1+%2*1]
+    pmulhrsw             m2, m15, [%1+%2*2]
+    pmulhrsw             m3, m15, [%1+%2*3]
+    pmulhrsw             m4, m15, [%1+%2*4]
+    pmulhrsw             m5, m15, [%1+%2*5]
+    pmulhrsw             m6, m15, [%1+%2*6]
+    pmulhrsw             m7, m15, [%1+%2*7]
+%else
+    mova                 m0, [%1+%2*0]
+    mova                 m1, [%1+%2*1]
+    mova                 m2, [%1+%2*2]
+    mova                 m3, [%1+%2*3]
+    mova                 m4, [%1+%2*4]
+    mova                 m5, [%1+%2*5]
+    mova                 m6, [%1+%2*6]
+    mova                 m7, [%1+%2*7]
+%endif
+%endmacro
+
+%macro LOAD_8ROWS_H 2-3 0 ; src, stride, is_rect2
+%if %3
+%if %3 == 1
+    vpbroadcastd        m15, [o(pw_2896x8)]
+%endif
+    pmulhrsw             m8, m15, [%1+%2*0]
+    pmulhrsw             m9, m15, [%1+%2*1]
+    pmulhrsw            m10, m15, [%1+%2*2]
+    pmulhrsw            m11, m15, [%1+%2*3]
+    pmulhrsw            m12, m15, [%1+%2*4]
+    pmulhrsw            m13, m15, [%1+%2*5]
+    pmulhrsw            m14, m15, [%1+%2*6]
+    pmulhrsw            m15,      [%1+%2*7]
+%else
+    mova                 m8, [%1+%2*0]
+    mova                 m9, [%1+%2*1]
+    mova                m10, [%1+%2*2]
+    mova                m11, [%1+%2*3]
+    mova                m12, [%1+%2*4]
+    mova                m13, [%1+%2*5]
+    mova                m14, [%1+%2*6]
+    mova                m15, [%1+%2*7]
+%endif
+%endmacro
+
+%macro ITX_UNPACK_MULHRSW 7 ; dst1, dst2/src, tmp, coef[1-4]
+    vpbroadcastd        m%3, [r5-pw_201_4091x8+pw_%4_%5x8]
+    punpcklwd           m%1, m%2, m%2
+    pmulhrsw            m%1, m%3
+    vpbroadcastd        m%3, [r5-pw_201_4091x8+pw_%6_%7x8]
+    punpckhwd           m%2, m%2
+    pmulhrsw            m%2, m%3
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_8x32_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 4, 16, 32*3, dst, stride, c, eob
+    %undef cmp
+    cmp                eobd, 106
+    jle .fast
+    LOAD_8ROWS      cq+32*1, 32*2
+    call m(idct_16x8_internal_8bpc).main
+    vperm2i128          m11, m0, m4, 0x31
+    vinserti128          m0, xm4, 1
+    vperm2i128           m4, m1, m5, 0x31
+    vinserti128          m1, xm5, 1
+    vperm2i128           m5, m2, m6, 0x31
+    vinserti128          m2, xm6, 1
+    vperm2i128           m6, m3, m7, 0x31
+    vinserti128          m3, xm7, 1
+    pxor                 m7, m7
+    REPX {mova [cq+32*x], m7}, 1, 3, 5, 7, 9, 11, 13, 15
+    punpckhwd            m7, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpcklwd            m3, m11, m4
+    punpckhwd           m11, m4
+    punpckhwd            m4, m5, m6
+    punpcklwd            m5, m6
+    punpckhdq            m6, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m3, m5
+    punpckhdq            m3, m5
+    punpckhdq            m5, m11, m4
+    punpckldq           m11, m4
+    punpckldq            m4, m7, m1
+    punpckhdq            m7, m1
+    punpckhqdq          m12, m6, m0
+    punpcklqdq           m0, m6     ; out4
+    punpckhqdq          m13, m7, m4
+    punpcklqdq           m4, m7     ; out5
+    punpckhqdq          m14, m3, m2
+    punpcklqdq           m2, m3     ; out6
+    punpckhqdq          m15, m5, m11
+    punpcklqdq          m11, m5     ; out7
+    mova         [rsp+32*0], m0
+    mova         [rsp+32*1], m4
+    mova         [rsp+32*2], m2
+.fast:
+    LOAD_8ROWS      cq+32*0, 32*2
+    call m(idct_16x8_internal_8bpc).main
+    vperm2i128           m8, m0, m4, 0x31
+    vinserti128          m0, xm4, 1
+    vperm2i128           m4, m1, m5, 0x31
+    vinserti128          m1, xm5, 1
+    vperm2i128           m5, m2, m6, 0x31
+    vinserti128          m2, xm6, 1
+    vperm2i128           m6, m3, m7, 0x31
+    vinserti128          m3, xm7, 1
+    vpbroadcastd         m9, [o(pw_8192)]
+    pxor                 m7, m7
+    REPX {mova [cq+32*x], m7}, 0, 2, 4, 6, 8, 10, 12, 14
+    punpckhwd            m7, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m8, m4
+    punpcklwd            m8, m4
+    punpckhwd            m4, m5, m6
+    punpcklwd            m5, m6
+    punpckhdq            m6, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m8, m5
+    punpckhdq            m8, m5
+    punpckhdq            m5, m3, m4
+    punpckldq            m3, m4
+    punpckhdq            m4, m7, m1
+    punpckldq            m7, m1
+    punpcklqdq           m1, m7, m4
+    punpckhqdq           m7, m4     ; out9
+    punpckhqdq           m4, m2, m8 ; out10
+    punpcklqdq           m2, m8
+    punpckhqdq           m8, m3, m5
+    punpcklqdq           m3, m5
+    punpckhqdq           m5, m0, m6 ; out8
+    punpcklqdq           m0, m6
+    REPX   {pmulhrsw x, m9}, m0, m1, m2, m3, m4, m5, m7
+    cmp                eobd, 106
+    jg .full
+    mova         [rsp+32*0], m5
+    mova         [rsp+32*1], m7
+    mova         [rsp+32*2], m4
+    pmulhrsw            m11, m9, m8
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    call .main_fast
+    jmp .pass2
+.dconly:
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_8192)]
+    mov                [cq], eobd
+    or                  r3d, 32
+    jmp m(inv_txfm_add_dct_dct_8x8_8bpc).dconly
+.full:
+    REPX   {pmulhrsw x, m9}, m12, m13, m14, m15
+    pmulhrsw             m6, m9, [rsp+32*2]
+    mova         [rsp+32*2], m4
+    pmulhrsw             m4, m9, [rsp+32*0]
+    mova         [rsp+32*0], m5
+    pmulhrsw             m5, m9, [rsp+32*1]
+    mova         [rsp+32*1], m7
+    pmulhrsw             m7, m9, m11
+    pmulhrsw            m11, m9, m8
+    call .main
+.pass2:
+    vpbroadcastd        m12, [o(pw_2048)]
+    REPX  {pmulhrsw x, m12}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                             m8,  m9,  m10, m11,      m13, m14, m15
+    pmulhrsw            m12, [rsp]
+    REPX {vpermq x, x, q3120}, m0, m2, m4, m6, m8, m10, m12, m14
+    REPX {vpermq x, x, q2031}, m1, m3, m5, m7, m9, m11, m13, m15
+    mova         [rsp+32*0], m4
+    mova         [rsp+32*1], m6
+    lea                  r3, [strideq*3]
+    WRITE_8X4             0,  1,  4,  6
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4             2,  3,  4,  6
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4    [rsp+32*0],  5,  4,  6
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4    [rsp+32*1],  7,  4,  6
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4             8,  9,  4,  6
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4            10, 11,  4,  6
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4            12, 13,  4,  6
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4            14, 15,  4,  6
+    RET
+ALIGN function_align
+cglobal_label .main_fast ; bottom half is zero
+    call m(idct_8x16_internal_8bpc).main
+    mova                 m8, [rsp+gprsize+0*32]
+    mova [rsp+gprsize+0*32], m0
+    mova                 m9, [rsp+gprsize+1*32]
+    mova [rsp+gprsize+1*32], m1
+    mova                 m0, [rsp+gprsize+2*32]
+    mova [rsp+gprsize+2*32], m6
+    lea                  r5, [r6-(o_base)+pw_201_4091x8]
+    ITX_UNPACK_MULHRSW    1,  8,  6,  201, 4091,  m601, 4052 ; t16a, t31a, t23a, t24a
+    ITX_UNPACK_MULHRSW   15,  9,  6,  995, 3973, m1380, 3857 ; t20a, t27a, t19a, t28a
+    ITX_UNPACK_MULHRSW   14,  0,  6, 1751, 3703, m2106, 3513 ; t18a, t29a, t21a, t26a
+    ITX_UNPACK_MULHRSW   13, 11,  6, 2440, 3290, m2751, 3035 ; t22a, t25a, t17a, t30a
+    jmp .main2
+ALIGN function_align
+cglobal_label .main
+    call m(idct_8x16_internal_8bpc).main
+    mova                 m8, [rsp+gprsize+0*32]
+    mova [rsp+gprsize+0*32], m0
+    mova                 m9, [rsp+gprsize+1*32]
+    mova [rsp+gprsize+1*32], m1
+    mova                 m0, [rsp+gprsize+2*32]
+    mova [rsp+gprsize+2*32], m6
+    punpcklwd            m1, m15, m8  ; in31 in1
+    punpckhwd            m8, m15      ; in3  in29
+    punpcklwd           m15, m14, m9  ; in27 in5
+    punpckhwd            m9, m14      ; in7  in25
+    punpcklwd           m14, m13, m0  ; in23 in9
+    punpckhwd            m0, m13      ; in11 in21
+    punpcklwd           m13, m12, m11 ; in19 in13
+    punpckhwd           m11, m12      ; in15 in17
+    ITX_MUL2X_PACK        1,  6, 12, 10,  201, 4091, 3 ; t16a, t31a
+    ITX_MUL2X_PACK        8,  6, 12, 10, 4052,  601, 3 ; t23a, t24a
+    ITX_MUL2X_PACK       15,  6, 12, 10,  995, 3973, 3 ; t20a, t27a
+    ITX_MUL2X_PACK        9,  6, 12, 10, 3857, 1380, 3 ; t19a, t28a
+    ITX_MUL2X_PACK       14,  6, 12, 10, 1751, 3703, 3 ; t18a, t29a
+    ITX_MUL2X_PACK        0,  6, 12, 10, 3513, 2106, 3 ; t21a, t26a
+    ITX_MUL2X_PACK       13,  6, 12, 10, 2440, 3290, 3 ; t22a, t25a
+    ITX_MUL2X_PACK       11,  6, 12, 10, 3035, 2751, 3 ; t17a, t30a
+.main2:
+    psubsw               m6, m1, m11  ; t17 t30
+    paddsw               m1, m11      ; t16 t31
+    psubsw              m11, m9, m14  ; t18 t29
+    paddsw               m9, m14      ; t19 t28
+    psubsw              m14, m15, m0  ; t21 t26
+    paddsw              m15, m0       ; t20 t27
+    psubsw               m0, m8, m13  ; t22 t25
+    paddsw               m8, m13      ; t23 t24
+    ITX_MUL2X_PACK        6, 12, 13, 10,   799, 4017, 3 ; t17a t30a
+    ITX_MUL2X_PACK       11, 12, 13, 10, m4017,  799, 3 ; t18a t29a
+    ITX_MUL2X_PACK       14, 12, 13, 10,  3406, 2276, 3 ; t21a t26a
+    ITX_MUL2X_PACK        0, 12, 13, 10, m2276, 3406, 3 ; t22a t25a
+    psubsw              m13, m1, m9   ; t19a t28a
+    paddsw               m1, m9       ; t16a t31a
+    psubsw               m9, m8, m15  ; t20a t27a
+    paddsw               m8, m15      ; t23a t24a
+    psubsw              m15, m6, m11  ; t18  t29
+    paddsw               m6, m11      ; t17  t30
+    psubsw              m11, m0, m14  ; t21  t26
+    paddsw               m0, m14      ; t22  t25
+    ITX_MUL2X_PACK       15, 12, 14, 10,  1567, 3784, 3 ; t18a t29a
+    ITX_MUL2X_PACK       13, 12, 14, 10,  1567, 3784, 3 ; t19  t28
+    ITX_MUL2X_PACK        9, 12, 14, 10, m3784, 1567, 3 ; t20  t27
+    ITX_MUL2X_PACK       11, 12, 14, 10, m3784, 1567, 3 ; t21a t26a
+    vbroadcasti128      m12, [o(deint_shuf)]
+    psubsw              m14, m1, m8   ; t23  t24
+    paddsw               m1, m8       ; t16  t31
+    psubsw               m8, m6, m0   ; t22a t25a
+    paddsw               m6, m0       ; t17a t30a
+    psubsw               m0, m15, m11 ; t21  t26
+    paddsw              m15, m11      ; t18  t29
+    psubsw              m11, m13, m9  ; t20a t27a
+    paddsw              m13, m9       ; t19a t28a
+    REPX    {pshufb x, m12}, m1, m6, m15, m13
+    ITX_MUL2X_PACK       14,  9, 12, 10, 2896, 2896 ; t24a t23a
+    vpbroadcastd         m9, [o(pw_m2896_2896)]
+    ITX_MUL2X_PACK        8, 12,  _, 10, 12,  9, 4  ; t22  t25
+    vpbroadcastd        m12, [o(pw_2896_2896)]
+    ITX_MUL2X_PACK        0, 12,  _, 10, 12,  9, 4  ; t21a t26a
+    vpbroadcastd        m12, [o(pw_2896_2896)]
+    ITX_MUL2X_PACK       11,  9,  _, 10,  9, 12, 4  ; t27  t20
+    shufps               m9, m14, m8, q1032 ; t23a t22
+    vpblendd            m14, m8, 0xcc       ; t24a t25
+    shufps               m8, m11, m0, q1032 ; t20  t21a
+    vpblendd            m11, m0, 0xcc       ; t27  t26a
+    punpcklqdq           m0, m1, m6   ; t16  t17a
+    punpckhqdq           m1, m6       ; t31  t30a
+    psubsw              m10, m5, m8   ; out20 out21
+    paddsw               m5, m8       ; out11 out10
+    psubsw               m6, m3, m14  ; out24 out25
+    paddsw               m3, m14      ; out7  out6
+    psubsw               m8, m7, m0   ; out16 out17
+    paddsw               m7, m0       ; out15 out14
+    mova                 m0, [rsp+gprsize+0*32]
+    punpcklqdq          m12, m13, m15 ; t19a t18
+    punpckhqdq          m13, m15      ; t28a t29
+    psubsw              m15, m0, m1   ; out31 out30
+    paddsw               m0, m1       ; out0  out1
+    mova                 m1, [rsp+gprsize+1*32]
+    mova [rsp+gprsize+0*32], m6
+    mova                 m6, [rsp+gprsize+2*32]
+    psubsw              m14, m1, m13  ; out28 out29
+    paddsw               m1, m13      ; out3  out2
+    psubsw              m13, m2, m11  ; out27 out26
+    paddsw               m2, m11      ; out4  out5
+    psubsw              m11, m4, m9   ; out23 out22
+    paddsw               m4, m9       ; out8  out9
+    psubsw               m9, m6, m12  ; out19 out18
+    paddsw               m6, m12      ; out12 out13
+    ret
+
+%macro LOAD_PACKED_16X2 4 ; dst, tmp, row[1-2]
+    vbroadcasti128      m%1, [cq+16*%3]
+    vbroadcasti128      m%2, [cq+16*%4]
+    shufpd              m%1, m%2, 0x0c
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_32x8_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_8192)]
+    mov                [cq], eobd
+    or                  r3d, 8
+.dconly:
+    pmulhrsw            xm0, xm2
+    movd                xm2, [pw_2048] ; intentionally rip-relative
+    pmulhrsw            xm0, xm1
+    pmulhrsw            xm0, xm2
+    vpbroadcastw         m0, xm0
+    pxor                 m3, m3
+.dconly_loop:
+    mova                 m1, [dstq]
+    punpckhbw            m2, m1, m3
+    punpcklbw            m1, m3
+    paddw                m2, m0
+    paddw                m1, m0
+    packuswb             m1, m2
+    mova             [dstq], m1
+    add                dstq, strideq
+    dec                 r3d
+    jg .dconly_loop
+    RET
+.normal:
+    PROLOGUE              0, 4, 16, 32*3, dst, stride, c, eob
+    %undef cmp
+    LOAD_PACKED_16X2      0,  7,  0,  2 ; in0  in2
+    LOAD_PACKED_16X2      4,  7,  1,  3 ; in1  in3
+    LOAD_PACKED_16X2      1,  7,  4,  6 ; in4  in6
+    LOAD_PACKED_16X2      5,  7,  5,  7 ; in5  in7
+    pxor                 m8, m8
+    REPX {mova [cq+32*x], m8},  0,  1,  2,  3
+    add                  cq, 16*16
+    LOAD_PACKED_16X2      2,  7, -8, -6 ; in8  in10
+    LOAD_PACKED_16X2      6,  7, -7, -5 ; in9  in11
+    LOAD_PACKED_16X2      3,  7, -4, -2 ; in12 in14
+    LOAD_PACKED_16X2     11,  7, -3, -1 ; in13 in15
+    REPX {mova [cq+32*x], m8}, -4, -3, -2, -1
+    mova         [rsp+32*0], m4
+    mova         [rsp+32*1], m5
+    mova         [rsp+32*2], m6
+    cmp                eobd, 106
+    jg .full
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main_fast
+    jmp .pass2
+.full:
+    LOAD_PACKED_16X2      4,  7,  0,  2 ; in16 in18
+    LOAD_PACKED_16X2     12,  7,  3,  1 ; in19 in17
+    LOAD_PACKED_16X2      5,  7,  4,  6 ; in20 in22
+    LOAD_PACKED_16X2     13,  7,  7,  5 ; in23 in21
+    REPX {mova [cq+32*x], m8},  0,  1,  2,  3
+    add                  cq, 16*8
+    LOAD_PACKED_16X2      6,  7,  0,  2 ; in24 in26
+    LOAD_PACKED_16X2     14,  7,  3,  1 ; in27 in25
+    LOAD_PACKED_16X2      7,  8,  4,  6 ; in28 in30
+    LOAD_PACKED_16X2     15,  8,  7,  5 ; in31 in29
+    pxor                 m8, m8
+    REPX {mova [cq+32*x], m8},  0,  1,  2,  3
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main
+.pass2:
+    vpbroadcastd        m12, [o(pw_8192)]
+    REPX  {pmulhrsw x, m12}, m8, m9, m10, m11, m13, m14, m15
+    mova         [rsp+32*1], m9
+    mova         [rsp+32*2], m10
+    punpckhwd            m9, m0, m2
+    punpcklwd            m0, m2
+    punpckhwd            m2, m1, m3
+    punpcklwd            m1, m3
+    punpcklwd           m10, m4, m6
+    punpckhwd            m4, m6
+    punpcklwd            m6, m5, m7
+    punpckhwd            m5, m7
+    punpckhwd            m3, m0, m9
+    punpcklwd            m0, m9
+    punpckhwd            m9, m2, m1
+    punpcklwd            m2, m1
+    punpcklwd            m7, m10, m4
+    punpckhwd           m10, m4
+    punpcklwd            m4, m5, m6
+    punpckhwd            m5, m6
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m3, m9
+    punpckhdq            m3, m9
+    punpckldq            m6, m7, m4
+    punpckhdq            m7, m4
+    punpckldq            m9, m10, m5
+    punpckhdq           m10, m5
+    REPX  {pmulhrsw x, m12}, m0, m1, m2, m3, m6, m7, m9, m10
+    pmulhrsw            m12, [rsp+32*0]
+    mova         [rsp+32*0], m8
+    vperm2i128           m4, m0, m6, 0x31
+    vinserti128          m0, xm6, 1
+    vperm2i128           m5, m1, m7, 0x31
+    vinserti128          m1, xm7, 1
+    vperm2i128           m6, m2, m9, 0x31
+    vinserti128          m2, xm9, 1
+    vperm2i128           m7, m3, m10, 0x31
+    vinserti128          m3, xm10, 1
+    call m(idct_16x8_internal_8bpc).main
+    vpbroadcastd         m8, [o(pw_2048)]
+    REPX   {pmulhrsw x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    lea                  r2, [strideq*3]
+    WRITE_16X2            0,  1,  8,  0, strideq*0, strideq*1
+    WRITE_16X2            2,  3,  0,  1, strideq*2, r2
+    lea                  r3, [dstq+strideq*4]
+    %define dstq r3
+    WRITE_16X2            4,  5,  0,  1, strideq*0, strideq*1
+    WRITE_16X2            6,  7,  0,  1, strideq*2, r2
+    mova                 m0, [rsp+32*0]
+    mova                 m1, [rsp+32*1]
+    mova                 m2, [rsp+32*2]
+    punpckhwd            m7, m0, m2
+    punpcklwd            m0, m2
+    punpckhwd            m2, m1, m11
+    punpcklwd            m1, m11
+    punpckhwd            m4, m12, m14
+    punpcklwd           m12, m14
+    punpckhwd            m5, m13, m15
+    punpcklwd           m13, m15
+    punpckhwd            m3, m0, m7
+    punpcklwd            m0, m7
+    punpckhwd            m9, m2, m1
+    punpcklwd            m2, m1
+    punpcklwd            m7, m12, m4
+    punpckhwd           m12, m4
+    punpcklwd            m4, m5, m13
+    punpckhwd            m5, m13
+    punpckhdq            m1, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m3, m9
+    punpckhdq            m3, m9
+    punpckldq            m6, m7, m4
+    punpckhdq            m7, m4
+    punpckldq            m9, m12, m5
+    punpckhdq           m12, m5
+    vperm2i128           m4, m0, m6, 0x31
+    vinserti128          m0, xm6, 1
+    vperm2i128           m5, m1, m7, 0x31
+    vinserti128          m1, xm7, 1
+    vperm2i128           m6, m2, m9, 0x31
+    vinserti128          m2, xm9, 1
+    vperm2i128           m7, m3, m12, 0x31
+    vinserti128          m3, xm12, 1
+    call m(idct_16x8_internal_8bpc).main2
+    vpbroadcastd         m8, [o(pw_2048)]
+    REPX   {pmulhrsw x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    add                  r0, 16
+    add                  r3, 16
+    %define dstq r0
+    WRITE_16X2            0,  1,  8,  0, strideq*0, strideq*1
+    WRITE_16X2            2,  3,  0,  1, strideq*2, r2
+    %define dstq r3
+    WRITE_16X2            4,  5,  0,  1, strideq*0, strideq*1
+    WRITE_16X2            6,  7,  0,  1, strideq*2, r2
+    RET
+
+cglobal inv_txfm_add_identity_identity_8x32_8bpc, 4, 5, 11, dst, stride, c, eob
+    vpbroadcastd         m9, [pw_5]
+    lea                  r4, [strideq*3]
+    sub                eobd, 107 ; loop_iterations = 1 + (eobd >= 107)
+.loop:
+    mova                xm0,[cq+16* 0]
+    mova                xm1, [cq+16* 4]
+    vinserti128          m0, [cq+16* 1], 1
+    vinserti128          m1, [cq+16* 5], 1
+    pxor                 m8, m8
+    mova          [cq+32*0], m8
+    mova          [cq+32*2], m8
+    add                  cq, 16*16
+    mova                xm2, [cq-16* 8]
+    mova                xm3, [cq-16* 4]
+    vinserti128          m2, [cq-16* 7], 1
+    vinserti128          m3, [cq-16* 3], 1
+    mova                xm4, [cq+16* 0]
+    mova                xm5, [cq+16* 4]
+    vinserti128          m4, [cq+16* 1], 1
+    vinserti128          m5, [cq+16* 5], 1
+    mova                xm6, [cq+16* 8]
+    mova                xm7, [cq+16*12]
+    vinserti128          m6, [cq+16* 9], 1
+    vinserti128          m7, [cq+16*13], 1
+    REPX {mova [cq+32*x], m8}, -4, -2,  0,  2,  4,  6
+    REPX  {paddsw    x, m9}, m0, m1, m2, m3, m4, m5, m6, m7
+    call .transpose8x8
+    REPX  {psraw     x, 3 }, m0, m1, m2, m3, m4, m5, m6, m7
+    WRITE_8X4             0,  4,  8, 10, strideq*8, strideq*4, r4*4
+    add                dstq, strideq
+    WRITE_8X4             1,  5,  0,  4, strideq*8, strideq*4, r4*4
+    add                dstq, strideq
+    WRITE_8X4             2,  6,  0,  4, strideq*8, strideq*4, r4*4
+    add                dstq, strideq
+    WRITE_8X4             3,  7,  0,  4, strideq*8, strideq*4, r4*4
+    add                dstq, strideq
+    sub                  cq, 16*16-32
+    lea                dstq, [dstq+r4*4]
+    add                eobd, 0x80000000
+    jnc .loop
+    RET
+ALIGN function_align
+.transpose8x8:
+    punpckhwd            m8, m4, m5
+    punpcklwd            m4, m5
+    punpckhwd            m5, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m6, m7
+    punpcklwd            m6, m7
+    punpckhwd            m7, m2, m3
+    punpcklwd            m2, m3
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m4, m6
+    punpckhdq            m4, m6
+    punpckhdq            m6, m5, m7
+    punpckldq            m5, m7
+    punpckldq            m7, m8, m1
+    punpckhdq            m8, m1
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    punpcklqdq           m4, m5, m7
+    punpckhqdq           m5, m7
+    punpckhqdq           m7, m6, m8
+    punpcklqdq           m6, m8
+    ret
+
+cglobal inv_txfm_add_identity_identity_32x8_8bpc, 4, 6, 10, dst, stride, c, eob
+    add                  cq, 16*8
+    vpbroadcastd         m9, [pw_4096]
+    lea                  r4, [strideq*3]
+    lea                  r5, [dstq+strideq*4]
+    sub                eobd, 107
+.loop:
+    mova                xm0, [cq-16*8]
+    mova                xm1, [cq-16*7]
+    vinserti128          m0, [cq+16*0], 1
+    vinserti128          m1, [cq+16*1], 1
+    mova                xm2, [cq-16*6]
+    mova                xm3, [cq-16*5]
+    vinserti128          m2, [cq+16*2], 1
+    vinserti128          m3, [cq+16*3], 1
+    mova                xm4, [cq-16*4]
+    mova                xm5, [cq-16*3]
+    vinserti128          m4, [cq+16*4], 1
+    vinserti128          m5, [cq+16*5], 1
+    mova                xm6, [cq-16*2]
+    mova                xm7, [cq-16*1]
+    vinserti128          m6, [cq+16*6], 1
+    vinserti128          m7, [cq+16*7], 1
+    pxor                 m8, m8
+    REPX {mova [cq+32*x], m8}, -4, -3, -2, -1,  0,  1,  2,  3
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    REPX   {pmulhrsw x, m9}, m0, m1, m2, m3, m4, m5, m6, m7
+    WRITE_16X2            0,  1,  8,  0, strideq*0, strideq*1
+    WRITE_16X2            2,  3,  0,  1, strideq*2, r4
+    %define dstq r5
+    WRITE_16X2            4,  5,  0,  1, strideq*0, strideq*1
+    WRITE_16X2            6,  7,  0,  1, strideq*2, r4
+    add                  cq, 16*16
+    add                  r0, 16
+    add                  r5, 16
+    add                eobd, 0x80000000
+    jnc .loop
+    RET
+
+%define o_base pw_5 + 128
+
+%macro LOAD_16ROWS 2-4 0, 1 ; src, stride, is_rect2, zero_coefs
+%if %3
+    vpbroadcastd        m15, [o(pw_2896x8)]
+    pmulhrsw             m0, m15, [%1+%2* 0]
+    pmulhrsw             m1, m15, [%1+%2* 1]
+    pmulhrsw             m2, m15, [%1+%2* 2]
+    pmulhrsw             m3, m15, [%1+%2* 3]
+    pmulhrsw             m4, m15, [%1+%2* 4]
+    pmulhrsw             m5, m15, [%1+%2* 5]
+    pmulhrsw             m6, m15, [%1+%2* 6]
+    pmulhrsw             m7, m15, [%1+%2* 7]
+    pmulhrsw             m8, m15, [%1+%2* 8]
+    pmulhrsw             m9, m15, [%1+%2* 9]
+    pmulhrsw            m10, m15, [%1+%2*10]
+    pmulhrsw            m11, m15, [%1+%2*11]
+    pmulhrsw            m12, m15, [%1+%2*12]
+    pmulhrsw            m13, m15, [%1+%2*13]
+    pmulhrsw            m14, m15, [%1+%2*14]
+    pmulhrsw            m15,      [%1+%2*15]
+%else
+    mova                 m0, [%1+%2* 0]
+    mova                 m1, [%1+%2* 1]
+    mova                 m2, [%1+%2* 2]
+    mova                 m3, [%1+%2* 3]
+    mova                 m4, [%1+%2* 4]
+    mova                 m5, [%1+%2* 5]
+    mova                 m6, [%1+%2* 6]
+    mova                 m7, [%1+%2* 7]
+    mova                 m8, [%1+%2* 8]
+    mova                 m9, [%1+%2* 9]
+    mova                m10, [%1+%2*10]
+    mova                m11, [%1+%2*11]
+    mova                m12, [%1+%2*12]
+    mova                m13, [%1+%2*13]
+    mova                m14, [%1+%2*14]
+    mova                m15, [%1+%2*15]
+%endif
+    mova              [rsp], m15
+%if %4
+    pxor                m15, m15
+    REPX {mova [%1+%2*x], m15}, 0,  1,  2,  3,  4,  5,  6,  7, \
+                                8,  9, 10, 11, 12, 13, 14, 15
+%endif
+%endmacro
+
+%macro IDCT32_PASS2_END 7 ; coefs[1-2], tmp[1-2], rnd, offset[1-2]
+    mova                m%4, [%2]
+    paddsw              m%3, m%1, m%4
+    psubsw              m%1, m%4
+    pmovzxbw            m%4, [dstq+%6]
+    pmulhrsw            m%3, m%5
+    pmulhrsw            m%1, m%5
+    paddw               m%3, m%4
+    pmovzxbw            m%4, [r2+%7]
+    paddw               m%1, m%4
+    packuswb            m%3, m%1
+    vpermq              m%3, m%3, q3120
+    mova          [dstq+%6], xm%3
+    vextracti128    [r2+%7], m%3, 1
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_16x32_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 8, 16, 32*35, dst, stride, c, eob, tmp1, tmp2, \
+                                           base, tmp3
+    %undef cmp
+    LOAD_16ROWS          cq, 64, 1
+    call m(idct_16x16_internal_8bpc).main
+    lea               tmp1q, [rsp+32*7]
+    lea               tmp2q, [tmp1q+32*8]
+    lea               tmp3q, [tmp1q+32*16]
+    mova                 m1, [rsp+32*1]
+    mova         [rsp+32*0], m6
+    mova         [rsp+32*1], m7
+    vpbroadcastd         m7, [o(pw_16384)]
+    call .transpose_2x8x8_round
+    mova                m15, [rsp+32*0]
+    mova         [tmp3q-32*4+ 0], xm0
+    vextracti128 [tmp3q+32*0+ 0], m0, 1
+    mova         [tmp3q-32*3+ 0], xm2
+    vextracti128 [tmp3q+32*1+ 0], m2, 1
+    mova         [tmp3q-32*2+ 0], xm4
+    vextracti128 [tmp3q+32*2+ 0], m4, 1
+    mova         [tmp3q-32*1+ 0], xm6
+    vextracti128 [tmp3q+32*3+ 0], m6, 1
+    mova         [tmp3q-32*4+16], xm8
+    vextracti128 [tmp3q+32*0+16], m8, 1
+    mova         [tmp3q-32*3+16], xm10
+    vextracti128 [tmp3q+32*1+16], m10, 1
+    mova         [tmp3q-32*2+16], xm12
+    vextracti128 [tmp3q+32*2+16], m12, 1
+    mova         [tmp3q-32*1+16], xm14
+    vextracti128 [tmp3q+32*3+16], m14, 1
+    cmp                eobd, 150
+    jg .full
+    vinserti128          m0, m1, xm9, 1
+    vperm2i128           m4, m1, m9, 0x31
+    vinserti128          m2, m5, xm13, 1
+    vperm2i128           m6, m5, m13, 0x31
+    vinserti128          m1, m3, xm11, 1
+    vperm2i128           m5, m3, m11, 0x31
+    vinserti128          m3, m7, xm15, 1
+    vperm2i128           m7, m7, m15, 0x31
+    call .main_oddhalf_fast
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, m15
+    jmp .idct16
+.dconly:
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm1
+    or                  r3d, 32
+    jmp m(inv_txfm_add_dct_dct_16x4_8bpc).dconly
+.full:
+    mova       [tmp1q-32*4], m1
+    mova       [tmp1q-32*3], m3
+    mova       [tmp1q-32*2], m5
+    mova       [tmp1q-32*1], m7
+    mova       [tmp1q+32*0], m9
+    mova       [tmp1q+32*1], m11
+    mova       [tmp1q+32*2], m13
+    mova       [tmp1q+32*3], m15
+    LOAD_16ROWS       cq+32, 64, 1
+    call m(idct_16x16_internal_8bpc).main
+    lea                  r2, [tmp3q+32*8]
+    mova                 m1, [rsp+32*1]
+    mova         [rsp+32*0], m6
+    mova         [rsp+32*1], m7
+    vpbroadcastd         m7, [o(pw_16384)]
+    call .transpose_2x8x8_round
+    mova                m15, [rsp+32*0]
+    mova         [r2-32*4+ 0], xm0
+    vextracti128 [r2+32*0+ 0], m0, 1
+    mova         [r2-32*3+ 0], xm2
+    vextracti128 [r2+32*1+ 0], m2, 1
+    mova         [r2-32*2+ 0], xm4
+    vextracti128 [r2+32*2+ 0], m4, 1
+    mova         [r2-32*1+ 0], xm6
+    vextracti128 [r2+32*3+ 0], m6, 1
+    mova         [r2-32*4+16], xm8
+    vextracti128 [r2+32*0+16], m8, 1
+    mova         [r2-32*3+16], xm10
+    vextracti128 [r2+32*1+16], m10, 1
+    mova         [r2-32*2+16], xm12
+    vextracti128 [r2+32*2+16], m12, 1
+    mova         [r2-32*1+16], xm14
+    vextracti128 [r2+32*3+16], m14, 1
+    vinserti128          m8, m1, xm9, 1
+    vperm2i128          m12, m1, m9, 0x31
+    mova                xm0, [tmp1q-32*4]
+    mova                xm1, [tmp1q-32*3]
+    vinserti128          m0, [tmp1q+32*0], 1
+    vinserti128          m1, [tmp1q+32*1], 1
+    vinserti128         m10, m5, xm13, 1
+    vperm2i128          m14, m5, m13, 0x31
+    mova                xm4, [tmp1q-32*4+16]
+    mova                xm5, [tmp1q-32*3+16]
+    vinserti128          m4, [tmp1q+32*0+16], 1
+    vinserti128          m5, [tmp1q+32*1+16], 1
+    vinserti128          m9, m3, xm11, 1
+    vperm2i128          m13, m3, m11, 0x31
+    mova                xm2, [tmp1q-32*2]
+    mova                xm3, [tmp1q-32*1]
+    vinserti128          m2, [tmp1q+32*2], 1
+    vinserti128          m3, [tmp1q+32*3], 1
+    vinserti128         m11, m7, xm15, 1
+    vperm2i128          m15, m7, m15, 0x31
+    mova                xm6, [tmp1q-32*2+16]
+    mova                xm7, [tmp1q-32*1+16]
+    vinserti128          m6, [tmp1q+32*2+16], 1
+    vinserti128          m7, [tmp1q+32*3+16], 1
+    call .main_oddhalf
+    LOAD_8ROWS_H    r2-32*4, 32
+.idct16:
+    LOAD_8ROWS   tmp3q-32*4, 32
+    mova              [rsp], m15
+    call m(idct_16x16_internal_8bpc).main
+    imul                 r2, strideq, 19
+    lea                  r3, [strideq*3]
+    add                  r2, dstq
+    call .pass2_end
+    RET
+ALIGN function_align
+cglobal_label .main_oddhalf_fast ; lower half is zero
+    mova [rsp+gprsize+32*1], m7
+    pxor                 m7, m7
+    mova [rsp+gprsize+32*0], m7
+    mova [rsp+gprsize+32*2], m7
+    vpbroadcastd        m11, [o(pw_3703x8)]
+    vpbroadcastd         m7, [o(pw_1751x8)]
+    vpbroadcastd        m12, [o(pw_m1380x8)]
+    vpbroadcastd         m8, [o(pw_3857x8)]
+    vpbroadcastd        m13, [o(pw_3973x8)]
+    vpbroadcastd        m15, [o(pw_995x8)]
+    pmulhrsw            m11, m4  ; t29a
+    pmulhrsw             m4, m7  ; t18a
+    pmulhrsw            m12, m3  ; t19a
+    pmulhrsw             m3, m8  ; t28a
+    pmulhrsw            m13, m2  ; t27a
+    pmulhrsw             m2, m15 ; t20a
+    vpbroadcastd        m10, [o(pw_m2106x8)]
+    vpbroadcastd         m7, [o(pw_3513x8)]
+    vpbroadcastd         m9, [o(pw_3290x8)]
+    vpbroadcastd         m8, [o(pw_2440x8)]
+    vpbroadcastd        m14, [o(pw_m601x8)]
+    vpbroadcastd        m15, [o(pw_4052x8)]
+    pmulhrsw            m10, m5  ; t21a
+    pmulhrsw             m5, m7  ; t26a
+    pmulhrsw             m9, m6  ; t25a
+    pmulhrsw             m6, m8  ; t22a
+    pmulhrsw            m14, m1  ; t23a
+    pmulhrsw             m1, m15 ; t24a
+    vpbroadcastd        m15, [o(pd_2048)]
+    jmp .main2
+ALIGN function_align
+cglobal_label .main_oddhalf
+    mova [rsp+gprsize+32*0], m15
+    mova [rsp+gprsize+32*1], m7
+    mova [rsp+gprsize+32*2], m8
+    vpbroadcastd        m15, [o(pd_2048)]
+    ITX_MULSUB_2W         4, 11,  7,  8, 15, 1751, 3703 ; t18a, t29a
+    ITX_MULSUB_2W        12,  3,  7,  8, 15, 3857, 1380 ; t19a, t28a
+    ITX_MULSUB_2W         2, 13,  7,  8, 15,  995, 3973 ; t20a, t27a
+    ITX_MULSUB_2W        10,  5,  7,  8, 15, 3513, 2106 ; t21a, t26a
+    ITX_MULSUB_2W         6,  9,  7,  8, 15, 2440, 3290 ; t22a, t25a
+    ITX_MULSUB_2W        14,  1,  7,  8, 15, 4052,  601 ; t23a, t24a
+.main2:
+    psubsw               m7, m12, m4  ; t18
+    paddsw              m12, m4       ; t19
+    psubsw               m4, m2, m10  ; t21
+    paddsw               m2, m10      ; t20
+    psubsw              m10, m14, m6  ; t22
+    paddsw              m14, m6       ; t23
+    psubsw               m6, m1, m9   ; t25
+    paddsw               m1, m9       ; t24
+    psubsw               m9, m13, m5  ; t26
+    paddsw              m13, m5       ; t27
+    psubsw               m5, m3, m11  ; t29
+    paddsw               m3, m11      ; t28
+    ITX_MULSUB_2W         5,  7,  8, 11, 15, m4017,  799 ; t18a, t29a
+    ITX_MULSUB_2W         9,  4,  8, 11, 15,  3406, 2276 ; t21a, t26a
+    ITX_MULSUB_2W         6, 10,  8, 11, 15, m2276, 3406 ; t22a, t25a
+    psubsw               m8, m14, m2  ; t20a
+    paddsw              m14, m2       ; t23a
+    psubsw               m2, m1, m13  ; t27a
+    paddsw               m1, m13      ; t24a
+    psubsw              m13, m6, m9   ; t21
+    paddsw               m6, m9       ; t22
+    psubsw               m9, m10, m4  ; t26
+    paddsw              m10, m4       ; t25
+    ITX_MULSUB_2W         2,  8,  4, 11, 15, m3784, 1567 ; t20,  t27
+    ITX_MULSUB_2W         9, 13,  4, 11, 15, m3784, 1567 ; t21a, t26a
+    mova                 m4, [rsp+gprsize+32*0] ; in31
+    mova [rsp+gprsize+32*0], m6  ; t22
+    mova                 m6, [rsp+gprsize+32*1] ; in15
+    mova [rsp+gprsize+32*1], m14 ; t23a
+    mova                m14, [rsp+gprsize+32*2] ; in17
+    mova [rsp+gprsize+32*2], m1  ; t24a
+    ITX_MULSUB_2W         0,  4,  1, 11, 15,  201, 4091 ; t16a, t31a
+    ITX_MULSUB_2W        14,  6,  1, 11, 15, 3035, 2751 ; t17a, t30a
+    psubsw               m1, m0, m14  ; t17
+    paddsw               m0, m14      ; t16
+    psubsw              m14, m4, m6   ; t30
+    paddsw               m4, m6       ; t31
+    ITX_MULSUB_2W        14,  1,  6, 11, 15,  799, 4017 ; t17a, t30a
+    psubsw               m6, m0, m12  ; t19a
+    paddsw               m0, m12      ; t16a
+    psubsw              m12, m4, m3   ; t28a
+    paddsw               m4, m3       ; t31a
+    psubsw               m3, m14, m5  ; t18
+    paddsw              m14, m5       ; t17
+    psubsw               m5, m1, m7   ; t29
+    paddsw               m1, m7       ; t30
+    ITX_MULSUB_2W         5,  3,  7, 11, 15, 1567, 3784 ; t18a, t29a
+    ITX_MULSUB_2W        12,  6,  7, 11, 15, 1567, 3784 ; t19,  t28
+    psubsw               m7, m1, m10  ; t25a
+    paddsw               m1, m10      ; t30a
+    psubsw              m10, m5, m9   ; t21
+    paddsw               m5, m9       ; t18
+    psubsw               m9, m12, m2  ; t20a
+    paddsw              m12, m2       ; t19a
+    psubsw               m2, m3, m13  ; t26
+    paddsw               m3, m13      ; t29
+    psubsw              m13, m6, m8   ; t27a
+    paddsw               m6, m8       ; t28a
+    mova       [tmp1q-32*2], m5
+    mova       [tmp1q-32*1], m12
+    mova       [tmp2q+32*0], m6
+    mova       [tmp2q+32*1], m3
+    mova       [tmp2q+32*2], m1
+    mova                 m5, [rsp+gprsize+32*0] ; t22
+    mova                 m6, [rsp+gprsize+32*1] ; t23
+    mova                 m3, [rsp+gprsize+32*2] ; t24a
+    psubsw               m1, m14, m5  ; t22a
+    paddsw              m14, m5       ; t17a
+    psubsw               m5, m0, m6   ; t23
+    paddsw               m0, m6       ; t16
+    psubsw               m6, m4, m3   ; t24
+    paddsw               m4, m3       ; t31
+    vpbroadcastd         m8, [o(pw_m2896_2896)]
+    vpbroadcastd         m3, [o(pw_2896_2896)]
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m14
+    mova       [tmp2q+32*3], m4
+    ITX_MULSUB_2W        13,  9,  0,  4, 15,  3,  8 ; t20,  t27
+    ITX_MULSUB_2W         2, 10,  0,  4, 15,  3,  8 ; t21a, t26a
+    ITX_MULSUB_2W         7,  1,  0,  4, 15,  3,  8 ; t22,  t25
+    ITX_MULSUB_2W         6,  5,  0,  4, 15,  3,  8 ; t23a, t24a
+    mova       [tmp1q+32*0], m13
+    mova       [tmp1q+32*1], m2
+    mova       [tmp1q+32*2], m7
+    mova       [tmp1q+32*3], m6
+    mova       [tmp2q-32*4], m5
+    mova       [tmp2q-32*3], m1
+    mova       [tmp2q-32*2], m10
+    mova       [tmp2q-32*1], m9
+    ret
+ALIGN function_align
+.transpose_2x8x8_round:
+    punpckhwd            m6, m12, m13
+    punpcklwd           m12, m13
+    punpckhwd           m13, m8, m9
+    punpcklwd            m8, m9
+    punpckhwd            m9, m14, m15
+    punpcklwd           m14, m15
+    punpckhwd           m15, m10, m11
+    punpcklwd           m10, m11
+    REPX   {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5
+    punpckhdq           m11, m8, m10
+    punpckldq            m8, m10
+    punpckldq           m10, m12, m14
+    punpckhdq           m12, m14
+    punpckhdq           m14, m13, m15
+    punpckldq           m13, m15
+    punpckldq           m15, m6, m9
+    punpckhdq            m6, m9
+    punpckhqdq           m9, m8, m10
+    punpcklqdq           m8, m10
+    punpcklqdq          m10, m11, m12
+    punpckhqdq          m11, m12
+    punpcklqdq          m12, m13, m15
+    punpckhqdq          m13, m15
+    punpckhqdq          m15, m14, m6
+    punpcklqdq          m14, m6
+    pmulhrsw             m6, m7, [rsp+gprsize+32*0]
+    REPX   {pmulhrsw x, m7}, m8, m9, m10, m11, m12, m13, m14, m15
+    pmulhrsw             m7, [rsp+gprsize+32*1]
+    mova [rsp+gprsize+32*0], m15
+    punpckhwd           m15, m4, m5
+    punpcklwd            m4, m5
+    punpckhwd            m5, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m6, m7
+    punpcklwd            m6, m7
+    punpckhwd            m7, m2, m3
+    punpcklwd            m2, m3
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m4, m6
+    punpckhdq            m4, m6
+    punpckhdq            m6, m5, m7
+    punpckldq            m5, m7
+    punpckldq            m7, m15, m1
+    punpckhdq           m15, m1
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    punpcklqdq           m4, m5, m7
+    punpckhqdq           m5, m7
+    punpckhqdq           m7, m6, m15
+    punpcklqdq           m6, m15
+    ret
+ALIGN function_align
+.pass2_end:
+    mova [rsp+gprsize+32*0], m7
+    mova [rsp+gprsize+32*2], m15
+    vpbroadcastd        m15, [o(pw_2048)]
+    IDCT32_PASS2_END      0, tmp2q+32*3, 1, 7, 15, strideq*0, r3*4
+    IDCT32_PASS2_END      4, tmp2q-32*1, 0, 7, 15, strideq*4, strideq*8
+    IDCT32_PASS2_END      8, tmp1q+32*3, 0, 4, 15, strideq*8, strideq*4
+    IDCT32_PASS2_END     12, tmp1q-32*1, 0, 4, 15, r3*4,      strideq*0
+    add                dstq, strideq
+    sub                  r2, strideq
+    mova                 m1, [rsp+gprsize+32*1]
+    IDCT32_PASS2_END      1, tmp2q+32*2, 0, 4, 15, strideq*0, r3*4
+    IDCT32_PASS2_END      5, tmp2q-32*2, 0, 4, 15, strideq*4, strideq*8
+    IDCT32_PASS2_END      9, tmp1q+32*2, 0, 4, 15, strideq*8, strideq*4
+    IDCT32_PASS2_END     13, tmp1q-32*2, 0, 4, 15, r3*4,      strideq*0
+    add                dstq, strideq
+    sub                  r2, strideq
+    IDCT32_PASS2_END      2, tmp2q+32*1, 0, 4, 15, strideq*0, r3*4
+    IDCT32_PASS2_END      6, tmp2q-32*3, 0, 4, 15, strideq*4, strideq*8
+    IDCT32_PASS2_END     10, tmp1q+32*1, 0, 4, 15, strideq*8, strideq*4
+    IDCT32_PASS2_END     14, tmp1q-32*3, 0, 4, 15, r3*4,      strideq*0
+    add                dstq, strideq
+    sub                  r2, strideq
+    mova                 m7, [rsp+gprsize+32*0]
+    mova                 m1, [rsp+gprsize+32*2]
+    IDCT32_PASS2_END      3, tmp2q+32*0, 0, 4, 15, strideq*0, r3*4
+    IDCT32_PASS2_END      7, tmp2q-32*4, 0, 4, 15, strideq*4, strideq*8
+    IDCT32_PASS2_END     11, tmp1q+32*0, 0, 4, 15, strideq*8, strideq*4
+    IDCT32_PASS2_END      1, tmp1q-32*4, 0, 4, 15, r3*4,      strideq*0
+    ret
+
+; Perform the final sumsub step and YMM lane shuffling
+%macro IDCT32_PASS1_END 4 ; row[1-2], tmp[1-2]
+    mova                m%3, [tmp2q+32*( 3-%1)]
+    psubsw              m%4, m%1, m%3
+    paddsw              m%1, m%3
+    mova                m%3, [tmp1q+32*(11-%2)]
+    mova         [tmp1q+32*(11-%2)+16], xm%4
+    vextracti128 [tmp2q+32*( 3-%1)+16], m%4, 1
+    paddsw              m%4, m%2, m%3
+    psubsw              m%2, m%3
+    mova         [tmp1q+32*(11-%2)], xm%2
+    vextracti128 [tmp2q+32*( 3-%1)], m%2, 1
+    vperm2i128          m%2, m%1, m%4, 0x31
+    vinserti128         m%1, xm%4, 1
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_32x16_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm1
+    or                  r3d, 16
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).dconly
+.normal:
+    PROLOGUE              0, 6, 16, 32*19, dst, stride, c, eob, tmp1, tmp2
+    vpbroadcastd        m15, [o(pw_2896x8)]
+    pmulhrsw             m0, m15, [cq+32* 1]
+    pmulhrsw             m1, m15, [cq+32* 3]
+    pmulhrsw             m2, m15, [cq+32* 5]
+    pmulhrsw             m3, m15, [cq+32* 7]
+    pmulhrsw             m4, m15, [cq+32* 9]
+    pmulhrsw             m5, m15, [cq+32*11]
+    pmulhrsw             m6, m15, [cq+32*13]
+    pmulhrsw             m7, m15, [cq+32*15]
+    pmulhrsw             m8, m15, [cq+32*17]
+    pmulhrsw             m9, m15, [cq+32*19]
+    pmulhrsw            m10, m15, [cq+32*21]
+    pmulhrsw            m11, m15, [cq+32*23]
+    pmulhrsw            m12, m15, [cq+32*25]
+    pmulhrsw            m13, m15, [cq+32*27]
+    pmulhrsw            m14, m15, [cq+32*29]
+    pmulhrsw            m15,      [cq+32*31]
+    lea               tmp1q, [rsp+32*7]
+    lea               tmp2q, [tmp1q+32*8]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    LOAD_16ROWS     cq+32*0, 32*2, 1, 0
+    pxor                m15, m15
+    mov                 r3d, 8
+.zero_loop:
+    mova          [cq+32*0], m15
+    mova          [cq+32*1], m15
+    mova          [cq+32*2], m15
+    mova          [cq+32*3], m15
+    add                  cq, 32*4
+    dec                 r3d
+    jg .zero_loop
+    call m(idct_16x16_internal_8bpc).main
+    call .pass1_end
+    lea                  r2, [strideq*3]
+    mov                  r3, dstq
+.pass2:
+    vpbroadcastd         m7, [o(pw_16384)]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).transpose_2x8x8_round
+    call m(idct_16x16_internal_8bpc).main
+    mova         [rsp+32*2], m15
+    vpbroadcastd        m15, [o(pw_2048)]
+    REPX  {pmulhrsw x, m15}, m2, m3, m0
+    WRITE_16X2            2,  3,  1,  2, strideq*2, r2
+    pmulhrsw             m1, m15, [rsp+32*1]
+    WRITE_16X2            0,  1,  2,  3, strideq*0, strideq*1
+    lea                dstq, [dstq+strideq*4]
+    REPX  {pmulhrsw x, m15}, m4, m5, m6, m7
+    WRITE_16X2            4,  5,  2,  3, strideq*0, strideq*1
+    WRITE_16X2            6,  7,  2,  3, strideq*2, r2
+    lea                dstq, [dstq+strideq*4]
+    REPX  {pmulhrsw x, m15}, m8, m9, m10, m11
+    WRITE_16X2            8,  9,  2,  3, strideq*0, strideq*1
+    WRITE_16X2           10, 11,  2,  3, strideq*2, r2
+    lea                dstq, [dstq+strideq*4]
+    REPX  {pmulhrsw x, m15}, m11, m12, m13, m14
+    pmulhrsw            m15, [rsp+32*2]
+    WRITE_16X2           12, 13,  2,  3, strideq*0, strideq*1
+    WRITE_16X2           14, 15,  2,  3, strideq*2, r2
+    test                 r3, r3
+    jnz .right_half
+    RET
+.right_half:
+    LOAD_8ROWS   tmp1q-32*4, 32
+    LOAD_8ROWS_H tmp2q-32*4, 32
+    lea                dstq, [r3+16]
+    xor                 r3d, r3d
+    mova         [rsp+32*0], m6
+    mova         [rsp+32*1], m7
+    jmp .pass2
+ALIGN function_align
+.pass1_end:
+    mova [rsp+gprsize+32*0], m9
+    IDCT32_PASS1_END      0,  8,  1,  9
+    IDCT32_PASS1_END      2, 10,  1,  9
+    IDCT32_PASS1_END      3, 11,  1,  9
+    IDCT32_PASS1_END      4, 12,  1,  9
+    IDCT32_PASS1_END      5, 13,  1,  9
+    IDCT32_PASS1_END      6, 14,  1,  9
+    IDCT32_PASS1_END      7, 15,  1,  9
+    mova                 m1, [rsp+gprsize+32*1]
+    mova                 m9, [rsp+gprsize+32*0]
+    mova [rsp+gprsize+32*0], m6
+    mova [rsp+gprsize+32*1], m7
+    IDCT32_PASS1_END      1,  9,  6,  7
+    ret
+
+cglobal inv_txfm_add_identity_identity_16x32_8bpc, 4, 5, 13, dst, stride, c, eob
+%undef cmp
+    lea                  r6, [o_base]
+    vpbroadcastd         m9, [o(pw_2896x8)]
+    vpbroadcastd        m10, [o(pw_1697x16)]
+    vpbroadcastd        m12, [o(pw_8192)]
+    cmp                eobd, 43   ; if (eob > 43)
+    setg                r4b       ;   iteration_count++
+    cmp                eobd, 150  ; if (eob > 150)
+    setg                 al       ;   iteration_count++
+    add                eobd, -279 ; if (eob > 278)
+    adc                 r4b, al   ;   iteration_count++
+    lea                  r3, [strideq*3]
+    mov                  r6, cq
+    paddw               m11, m12, m12 ; pw_16384
+.loop:
+    mova                xm0, [cq+64* 0]
+    mova                xm1, [cq+64* 1]
+    vinserti128          m0, [cq+64* 8], 1
+    vinserti128          m1, [cq+64* 9], 1
+    mova                xm2, [cq+64* 2]
+    mova                xm3, [cq+64* 3]
+    vinserti128          m2, [cq+64*10], 1
+    vinserti128          m3, [cq+64*11], 1
+    mova                xm4, [cq+64* 4]
+    mova                xm5, [cq+64* 5]
+    vinserti128          m4, [cq+64*12], 1
+    vinserti128          m5, [cq+64*13], 1
+    mova                xm6, [cq+64* 6]
+    mova                xm7, [cq+64* 7]
+    vinserti128          m6, [cq+64*14], 1
+    vinserti128          m7, [cq+64*15], 1
+    REPX  {pmulhrsw x, m9 }, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX  {IDTX16 x, 8, 10, 11}, 0, 1, 2, 3, 4, 5, 6, 7
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    REPX  {pmulhrsw x, m12}, m0, m1, m2, m3, m4, m5, m6, m7
+    WRITE_16X2            0,  1,  8,  0, strideq*0, strideq*1
+    WRITE_16X2            2,  3,  0,  1, strideq*2, r3
+    lea                dstq, [dstq+strideq*4]
+    WRITE_16X2            4,  5,  0,  1, strideq*0, strideq*1
+    WRITE_16X2            6,  7,  0,  1, strideq*2, r3
+    lea                dstq, [dstq+strideq*4]
+    add                  cq, 16
+    dec                 r4b
+    jge .loop
+    sub                  cq, 32
+    pxor                 m0, m0
+    mov                 r0d, 8
+    cmp                  cq, r6
+    ja .zero_loop
+.zero_loop_half:
+    mova          [r6+64*0], m0
+    mova          [r6+64*1], m0
+    add                  r6, 64*4
+    mova          [r6-64*2], m0
+    mova          [r6-64*1], m0
+    sub                 r0d, 2
+    jg .zero_loop_half
+    RET
+.zero_loop:
+    mova          [r6+32*0], m0
+    mova          [r6+32*1], m0
+    mova          [r6+32*2], m0
+    mova          [r6+32*3], m0
+    add                  r6, 32*4
+    dec                 r0d
+    jg .zero_loop
+    RET
+
+cglobal inv_txfm_add_identity_identity_32x16_8bpc, 4, 6, 12, dst, stride, c, eob
+%undef cmp
+    lea                  r6, [o_base]
+    vpbroadcastd         m9, [o(pw_2896x8)]
+    vpbroadcastd        m10, [o(pw_1697x16)]
+    vpbroadcastd        m11, [o(pw_2048)]
+    cmp                eobd, 35  ; if (eob > 35)
+    setg                r4b      ;   iteration_count++
+    cmp                eobd, 150 ; if (eob > 150)
+    setg                r3b      ;   iteration_count += 2
+    lea                 r4d, [r4+r3*2]
+    lea                  r3, [strideq*3]
+    mov                  r5, dstq
+    mov                  r6, cq
+.loop:
+    mova                xm0, [cq+32* 0]
+    mova                xm1, [cq+32* 1]
+    vinserti128          m0, [cq+32* 8], 1
+    vinserti128          m1, [cq+32* 9], 1
+    mova                xm2, [cq+32* 2]
+    mova                xm3, [cq+32* 3]
+    vinserti128          m2, [cq+32*10], 1
+    vinserti128          m3, [cq+32*11], 1
+    mova                xm4, [cq+32* 4]
+    mova                xm5, [cq+32* 5]
+    vinserti128          m4, [cq+32*12], 1
+    vinserti128          m5, [cq+32*13], 1
+    mova                xm6, [cq+32* 6]
+    mova                xm7, [cq+32* 7]
+    vinserti128          m6, [cq+32*14], 1
+    vinserti128          m7, [cq+32*15], 1
+    REPX  {pmulhrsw x, m9 }, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX  {paddsw   x, x  }, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    REPX  {IDTX16 x, 8, 10}, 0, 1, 2, 3, 4, 5, 6, 7
+    REPX  {pmulhrsw x, m11}, m0, m1, m2, m3, m4, m5, m6, m7
+    WRITE_16X2            0,  1,  8,  0, strideq*0, strideq*1
+    WRITE_16X2            2,  3,  0,  1, strideq*2, r3
+    lea                dstq, [dstq+strideq*4]
+    WRITE_16X2            4,  5,  0,  1, strideq*0, strideq*1
+    WRITE_16X2            6,  7,  0,  1, strideq*2, r3
+    lea                dstq, [dstq+strideq*4]
+    add                  cq, 16
+    dec                 r4b
+    jl .ret
+    test                r4b, 1
+    jz .loop
+    add                  cq, 32*15
+    lea                dstq, [r5+16]
+    jmp .loop
+.ret:
+    sub                  cd, eax
+    pxor                 m0, m0
+    add                  cd, 384
+.zero_loop:
+    mova          [r6+32*0], m0
+    mova          [r6+32*1], m0
+    mova          [r6+32*2], m0
+    mova          [r6+32*3], m0
+    add                  r6, 32*4
+    sub                  cd, 128
+    jge .zero_loop
+    RET
+
+cglobal inv_txfm_add_dct_dct_32x32_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_8192)]
+    mov                [cq], eobd
+    or                  r3d, 32
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).dconly
+.normal:
+    PROLOGUE              0, 9, 16, 32*67, dst, stride, c, eob, tmp1, tmp2, \
+                                           base, tmp3, tmp4
+    %undef cmp
+    lea               tmp1q, [rsp+32*7]
+    lea               tmp2q, [tmp1q+32*8]
+    sub                eobd, 136
+    mov               tmp4d, eobd
+.pass1_loop:
+    LOAD_8ROWS      cq+64*1, 64*2
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 1, 3, 5, 7, 9, 11, 13, 15
+    test              tmp4d, tmp4d
+    jl .fast
+    LOAD_8ROWS_H   cq+64*17, 64*2
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    LOAD_8ROWS_H   cq+64*16, 64*2
+    pxor                 m0, m0
+    REPX {mova [cq+64*x], m0}, 16, 17, 18, 19, 20, 21, 22, 23, \
+                               24, 25, 26, 27, 28, 29, 30, 31
+    mova              [rsp], m15
+    jmp .idct16
+.fast:
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+.idct16:
+    LOAD_8ROWS      cq+64*0, 64*2
+    pxor                m15, m15
+    REPX {mova [cq+64*x], m15}, 0, 2, 4, 6, 8, 10, 12, 14
+    call m(idct_16x16_internal_8bpc).main
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).pass1_end
+    vpbroadcastd         m7, [o(pw_8192)]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).transpose_2x8x8_round
+    lea               tmp3q, [tmp1q+32*32]
+    mova                m15, [rsp]
+    mova       [tmp3q-32*4], m0
+    mova       [tmp3q-32*3], m2
+    mova       [tmp3q-32*2], m4
+    mova       [tmp3q-32*1], m6
+    mova       [tmp3q+32*0], m8
+    mova       [tmp3q+32*1], m10
+    mova       [tmp3q+32*2], m12
+    mova       [tmp3q+32*3], m14
+    add               tmp3q, 32*8
+    mova       [tmp3q-32*4], m1
+    mova       [tmp3q-32*3], m3
+    mova       [tmp3q-32*2], m5
+    mova       [tmp3q-32*1], m7
+    mova       [tmp3q+32*0], m9
+    mova       [tmp3q+32*1], m11
+    mova       [tmp3q+32*2], m13
+    mova       [tmp3q+32*3], m15
+    vpbroadcastd         m9, [o(pw_8192)]
+    pmulhrsw             m0, m9, [tmp1q-32*4]
+    pmulhrsw             m1, m9, [tmp1q-32*3]
+    pmulhrsw             m2, m9, [tmp1q-32*2]
+    pmulhrsw             m3, m9, [tmp1q-32*1]
+    pmulhrsw             m4, m9, [tmp1q+32*0]
+    pmulhrsw             m5, m9, [tmp1q+32*1]
+    pmulhrsw             m6, m9, [tmp1q+32*2]
+    pmulhrsw             m7, m9, [tmp1q+32*3]
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    mova       [tmp1q-32*4], m0
+    pmulhrsw             m0, m9, [tmp2q-32*4]
+    mova       [tmp2q-32*4], m1
+    pmulhrsw             m1, m9, [tmp2q-32*3]
+    mova       [tmp1q-32*3], m2
+    pmulhrsw             m2, m9, [tmp2q-32*2]
+    mova       [tmp2q-32*3], m3
+    pmulhrsw             m3, m9, [tmp2q-32*1]
+    mova       [tmp1q-32*2], m4
+    pmulhrsw             m4, m9, [tmp2q+32*0]
+    mova       [tmp2q-32*2], m5
+    pmulhrsw             m5, m9, [tmp2q+32*1]
+    mova       [tmp1q-32*1], m6
+    pmulhrsw             m6, m9, [tmp2q+32*2]
+    mova       [tmp2q-32*1], m7
+    pmulhrsw             m7, m9, [tmp2q+32*3]
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    mova       [tmp1q+32*0], m0
+    mova       [tmp2q+32*0], m1
+    mova       [tmp1q+32*1], m2
+    mova       [tmp2q+32*1], m3
+    mova       [tmp1q+32*2], m4
+    mova       [tmp2q+32*2], m5
+    mova       [tmp1q+32*3], m6
+    mova       [tmp2q+32*3], m7
+    add                  cq, 32
+    add               tmp1q, 32*16
+    add               tmp2q, 32*16
+    add                eobd, 0x80000000
+    jnc .pass1_loop
+    add               tmp1q, 32*24
+    imul                 r2, strideq, 19
+    lea                  r3, [strideq*3]
+    add                  r2, dstq
+    test              tmp4d, tmp4d
+    jge .pass2_loop
+    add               tmp1q, 32*16
+    add               tmp2q, 32*16
+    add               tmp3q, 32*16
+.pass2_loop:
+    LOAD_8ROWS   tmp2q-32*4, 32
+    test              tmp4d, tmp4d
+    jl .fast2
+    LOAD_8ROWS_H tmp3q-32*4, 32
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    sub               tmp3q, 32*8
+    LOAD_8ROWS_H tmp3q-32*4, 32
+    sub               tmp3q, 32*16
+    jmp .pass2_loop_end
+.fast2:
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    sub               tmp3q, 32*24
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14, m15
+.pass2_loop_end:
+    LOAD_8ROWS   tmp3q-32*4, 32
+    mova              [rsp], m15
+    call m(idct_16x16_internal_8bpc).main
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).pass2_end
+    lea               tmp3q, [tmp1q-32*32]
+    cmp               tmp2q, tmp3q
+    jb .ret
+    sub               tmp2q, 32*32
+    sub                dstq, r3
+    lea                  r2, [r2+r3+16]
+    add                dstq, 16
+    jmp .pass2_loop
+.ret:
+    RET
+
+cglobal inv_txfm_add_identity_identity_32x32_8bpc, 4, 6, 10, dst, stride, c, eob
+    %undef cmp
+    vpbroadcastd         m9, [pw_8192]
+    sub                eobd, 136 ; if (eob < 136)
+    shr                eobd, 30  ;     topleft 16x16 only
+    lea                eobd, [eobq*2-8]
+    lea                  r4, [strideq*3]
+    mov                  r5, dstq
+    lea                  r6, [cq+32]
+.loop:
+    mova                xm0, [cq+64* 0]
+    mova                xm1, [cq+64* 1]
+    vinserti128          m0, [cq+64* 8], 1
+    vinserti128          m1, [cq+64* 9], 1
+    mova                xm2, [cq+64* 2]
+    mova                xm3, [cq+64* 3]
+    vinserti128          m2, [cq+64*10], 1
+    vinserti128          m3, [cq+64*11], 1
+    mova                xm4, [cq+64* 4]
+    mova                xm5, [cq+64* 5]
+    vinserti128          m4, [cq+64*12], 1
+    vinserti128          m5, [cq+64*13], 1
+    mova                xm6, [cq+64* 6]
+    mova                xm7, [cq+64* 7]
+    vinserti128          m6, [cq+64*14], 1
+    vinserti128          m7, [cq+64*15], 1
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    REPX   {pmulhrsw x, m9}, m0, m1, m2, m3, m4, m5, m6, m7
+    WRITE_16X2            0,  1,  8,  0, strideq*0, strideq*1
+    WRITE_16X2            2,  3,  0,  1, strideq*2, r4
+    lea                dstq, [dstq+strideq*4]
+    WRITE_16X2            4,  5,  0,  1, strideq*0, strideq*1
+    WRITE_16X2            6,  7,  0,  1, strideq*2, r4
+    lea                dstq, [dstq+strideq*4]
+    add                  cq, 16
+    inc                eobd
+    jz .ret
+    test               eobd, 3
+    jnz .loop
+    add                  cq, 64*15
+    lea                dstq, [r5+16]
+    jmp .loop
+.ret:
+    pxor                 m0, m0
+    mov                 r0d, 16
+    cmp                  cq, r6
+    jne .zero_loop
+.zero_loop_topleft:
+    mova          [r6-32*1], m0
+    mova          [r6+32*1], m0
+    mova          [r6+32*3], m0
+    mova          [r6+32*5], m0
+    add                  r6, 64*4
+    sub                 r0d, 4
+    jg .zero_loop_topleft
+    RET
+.zero_loop:
+    mova          [r6-32*1], m0
+    mova          [r6+32*0], m0
+    mova          [r6+32*1], m0
+    mova          [r6+32*2], m0
+    add                  r6, 32*4
+    dec                 r0d
+    jg .zero_loop
+    RET
+
+%macro IDCT64_PART2_END 6-10 ; out, src[1-2], tmp[1-3], (offset[1-4])
+%if %1 & 1
+    mova                m%5, [tmp2q-32*(51-%1)] ; idct16 out 0+n
+    mova                m%4, [tmp1q-32*(14+%1)] ; idct32 out31-n
+%else
+    mova                m%5, [tmp1q-32*(45-%1)]
+    mova                m%4, [tmp2q-32*(20+%1)]
+%endif
+    psubsw              m%6, m%5, m%4 ; idct32 out31-n
+    paddsw              m%5, m%4      ; idct32 out 0+n
+    psubsw              m%4, m%6, m%3 ; out32+n
+    paddsw              m%6, m%3      ; out31-n
+    psubsw              m%3, m%5, m%2 ; out63-n
+    paddsw              m%5, m%2      ; out 0+n
+%if %0 == 6 ; pass 1
+%if %1 & 1
+    mova [tmp2q-32*(19-%1)], m%4
+    mova [tmp1q-32*(14+%1)], m%6
+    mova [tmp1q+32*(18-%1)], m%3
+    mova [tmp2q-32*(51-%1)], m%5
+%else
+    mova [tmp1q-32*(13-%1)], m%4
+    mova [tmp2q-32*(20+%1)], m%6
+    mova [tmp2q+32*(12-%1)], m%3
+    mova [tmp1q-32*(45-%1)], m%5
+%endif
+%else ; pass 2
+    REPX  {pmulhrsw x, m14}, m%4, m%6, m%3, m%5
+%if %1 & 1
+    %define %%d0 r2
+    %define %%d1 dstq
+%else
+    %define %%d0 dstq
+    %define %%d1 r2
+%endif
+    pmovzxbw            m%2, [%%d0+%9 ]
+    paddw               m%2, m%4
+    pmovzxbw            m%4, [%%d1+%8 ]
+    paddw               m%4, m%6
+    pmovzxbw            m%6, [%%d1+%10]
+    paddw               m%3, m%6
+    pmovzxbw            m%6, [%%d0+%7 ]
+    paddw               m%5, m%6
+    packuswb            m%2, m%4
+    packuswb            m%3, m%5
+    vpermq              m%2, m%2, q3120
+    vpermq              m%3, m%3, q3120
+    mova         [%%d0+%9 ], xm%2
+    vextracti128 [%%d1+%8 ], m%2, 1
+    mova         [%%d1+%10], xm%3
+    vextracti128 [%%d0+%7 ], m%3, 1
+%endif
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_16x64_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_8192)]
+    mov                [cq], eobd
+    or                  r3d, 64
+    jmp m(inv_txfm_add_dct_dct_16x4_8bpc).dconly
+.normal:
+    PROLOGUE              0, 10, 16, 32*67, dst, stride, c, eob, tmp1, tmp2
+    %undef cmp
+    lea               tmp1q, [rsp+32*23]
+    lea               tmp2q, [tmp1q+32*24]
+    sub                eobd, 151
+    mov                 r7d, eobd
+.pass1_loop:
+    LOAD_16ROWS          cq, 64
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    mova         [rsp+32*0], m6
+    mova         [rsp+32*1], m7
+    vpbroadcastd         m7, [o(pw_8192)]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).transpose_2x8x8_round
+    mova                m15, [rsp+32*0]
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m2
+    mova       [tmp1q-32*2], m4
+    mova       [tmp1q-32*1], m6
+    mova       [tmp1q+32*0], m8
+    mova       [tmp1q+32*1], m10
+    mova       [tmp1q+32*2], m12
+    mova       [tmp1q+32*3], m14
+    mova       [tmp2q-32*4], m1
+    mova       [tmp2q-32*3], m3
+    mova       [tmp2q-32*2], m5
+    mova       [tmp2q-32*1], m7
+    mova       [tmp2q+32*0], m9
+    mova       [tmp2q+32*1], m11
+    mova       [tmp2q+32*2], m13
+    mova       [tmp2q+32*3], m15
+    add                  cq, 32
+    add               tmp1q, 32*8
+    add               tmp2q, 32*8
+    add                eobd, 0x80000000
+    jnc .pass1_loop
+    lea                  r2, [rsp+32*23]
+    mova                xm0, [r2-32*4+ 0]
+    mova                xm1, [r2-32*2+ 0]
+    vinserti128          m0, [r2+32*0+ 0], 1
+    vinserti128          m1, [r2+32*2+ 0], 1
+    mova                xm2, [r2-32*4+16]
+    mova                xm3, [r2-32*2+16]
+    vinserti128          m2, [r2+32*0+16], 1
+    vinserti128          m3, [r2+32*2+16], 1
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14
+    test                r7d, r7d
+    jl .fast
+    lea                  r3, [r2+32*8]
+    mova                xm4, [r3-32*4+ 0]
+    mova                xm5, [r3-32*2+ 0]
+    vinserti128          m4, [r3+32*0+ 0], 1
+    vinserti128          m5, [r3+32*2+ 0], 1
+    mova                xm6, [r3-32*4+16]
+    mova                xm7, [r3-32*2+16]
+    vinserti128          m6, [r3+32*0+16], 1
+    vinserti128          m7, [r3+32*2+16], 1
+.fast:
+    mova              [rsp], m8
+    lea               tmp1q, [rsp+32*7]
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m1
+    mova       [tmp1q-32*2], m2
+    mova       [tmp1q-32*1], m3
+    mova       [tmp1q+32*0], m4
+    mova       [tmp1q+32*1], m5
+    mova       [tmp1q+32*2], m6
+    mova       [tmp1q+32*3], m7
+    add               tmp1q, 32*8
+    mova       [tmp1q-32*4], m8
+    mova       [tmp1q-32*3], m9
+    mova       [tmp1q-32*2], m10
+    mova       [tmp1q-32*1], m11
+    mova       [tmp1q+32*0], m12
+    mova       [tmp1q+32*1], m13
+    mova       [tmp1q+32*2], m14
+    mova       [tmp1q+32*3], m15
+    mova                xm0, [r2-32*3+ 0]
+    mova                xm1, [r2-32*1+ 0]
+    vinserti128          m0, [r2+32*1+ 0], 1
+    vinserti128          m1, [r2+32*3+ 0], 1
+    mova                xm2, [r2-32*3+16]
+    mova                xm3, [r2-32*1+16]
+    vinserti128          m2, [r2+32*1+16], 1
+    vinserti128          m3, [r2+32*3+16], 1
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    test                r7d, r7d
+    jl .fast2
+    mova                xm4, [r3-32*3+ 0]
+    mova                xm5, [r3-32*1+ 0]
+    vinserti128          m4, [r3+32*1+ 0], 1
+    vinserti128          m5, [r3+32*3+ 0], 1
+    mova                xm6, [r3-32*3+16]
+    mova                xm7, [r3-32*1+16]
+    vinserti128          m6, [r3+32*1+16], 1
+    vinserti128          m7, [r3+32*3+16], 1
+.fast2:
+    add               tmp1q, 32*8
+    lea               tmp2q, [tmp1q+32*8]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    add                  r2, 32*24
+    vpbroadcastd        m15, [o(pd_2048)]
+    add               tmp1q, 32*16
+    add               tmp2q, 32*32
+    mova                xm0, [r2-32*4+ 0]
+    mova                xm3, [r2-32*1+16]
+    vinserti128          m0, [r2+32*0+ 0], 1
+    vinserti128          m3, [r2+32*3+16], 1
+    mova                xm4, [r2-32*4+16]
+    mova                xm7, [r2-32*1+ 0]
+    vinserti128          m4, [r2+32*0+16], 1
+    vinserti128          m7, [r2+32*3+ 0], 1
+    pxor                 m1, m1
+    REPX       {mova x, m1}, m2, m5, m6
+    test                r7d, r7d
+    jl .fast3
+    add                  r3, 32*24
+    mova                xm1, [r3-32*1+16]
+    mova                xm2, [r3-32*4+ 0]
+    vinserti128          m1, [r3+32*3+16], 1
+    vinserti128          m2, [r3+32*0+ 0], 1
+    mova                xm5, [r3-32*1+ 0]
+    mova                xm6, [r3-32*4+16]
+    vinserti128          m5, [r3+32*3+ 0], 1
+    vinserti128          m6, [r3+32*0+16], 1
+.fast3:
+    add                  r6, o_idct64_offset
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    add                  r6, 8
+    add               tmp1q, 32*8
+    sub               tmp2q, 32*8
+    mova                xm0, [r2-32*2+ 0]
+    mova                xm3, [r2-32*3+16]
+    vinserti128          m0, [r2+32*2+ 0], 1
+    vinserti128          m3, [r2+32*1+16], 1
+    mova                xm4, [r2-32*2+16]
+    mova                xm7, [r2-32*3+ 0]
+    vinserti128          m4, [r2+32*2+16], 1
+    vinserti128          m7, [r2+32*1+ 0], 1
+    pxor                 m1, m1
+    REPX       {mova x, m1}, m2, m5, m6
+    test                r7d, r7d
+    jl .fast4
+    mova                xm1, [r3-32*3+16]
+    mova                xm2, [r3-32*2+ 0]
+    vinserti128          m1, [r3+32*1+16], 1
+    vinserti128          m2, [r3+32*2+ 0], 1
+    mova                xm5, [r3-32*3+ 0]
+    mova                xm6, [r3-32*2+16]
+    vinserti128          m5, [r3+32*1+ 0], 1
+    vinserti128          m6, [r3+32*2+16], 1
+.fast4:
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part2_pass2
+    RET
+ALIGN function_align
+%define o_base idct64_mul - 8
+cglobal_label .main_part1
+    ; idct64 steps 1-5:
+    ; in1/31/17/15/ 9/23/25/ 7 ->
+    ;     t32a/33/34a/35/36/37a/38/39a/56a/57/58a/59/60/61a/62/63a
+    ; in5/27/21/11/13/19/29/ 3 ->
+    ;     t40a/41/42a/43/44/45a/46/47a/48a/49/50a/51/52/53a/54/55a
+    vpbroadcastd        m11, [o(idct64_mul+4* 0)]
+    vpbroadcastd        m13, [o(idct64_mul+4* 1)]
+    vpbroadcastd        m10, [o(idct64_mul+4* 4)]
+    vpbroadcastd        m12, [o(idct64_mul+4* 5)]
+    pmulhrsw            m11, m0  ; t63a
+    pmulhrsw             m0, m13 ; t32a
+    pmulhrsw            m10, m1  ; t62a
+    pmulhrsw             m1, m12 ; t33a
+    vpbroadcastd         m9, [o(idct64_mul+4* 8)]
+    vpbroadcastd        m13, [o(idct64_mul+4* 9)]
+    vpbroadcastd         m8, [o(idct64_mul+4*12)]
+    vpbroadcastd        m12, [o(idct64_mul+4*13)]
+    pmulhrsw             m9, m2  ; t61a
+    pmulhrsw             m2, m13 ; t34a
+    pmulhrsw             m8, m3  ; t60a
+    pmulhrsw             m3, m12 ; t35a
+    psubsw              m12, m0, m1   ; t33
+    paddsw               m0, m1       ; t32
+    psubsw               m1, m3, m2   ; t34
+    paddsw               m3, m2       ; t35
+    psubsw               m2, m8, m9   ; t61
+    paddsw               m8, m9       ; t60
+    psubsw               m9, m11, m10 ; t62
+    paddsw              m11, m10      ; t63
+    ITX_MULSUB_2W         2,  1, 10, 13, 15, m4076, 401 ; t34a, t61a
+    vpbroadcastd        m14, [o(pw_401_4076)]
+    ITX_MULSUB_2W         9, 12, 10, 13, 15, 14, 13 ; t33a, t62a
+    psubsw              m10, m0, m3  ; t35a
+    paddsw               m0, m3      ; t32a
+    psubsw               m3, m11, m8 ; t60a
+    paddsw              m11, m8      ; t63a
+    psubsw               m8, m9, m2  ; t34
+    paddsw               m9, m2      ; t33
+    psubsw               m2, m12, m1 ; t61
+    paddsw              m12, m1      ; t62
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m9
+    mova       [tmp2q+32*2], m12
+    mova       [tmp2q+32*3], m11
+    vpbroadcastd        m13, [o(pw_m4017_799)]
+    vpbroadcastd        m14, [o(pw_799_4017)]
+    ITX_MULSUB_2W         2,  8,  0,  1, 15, 14, 13 ; t34a, t61a
+    ITX_MULSUB_2W         3, 10,  0,  1, 15, 14, 13 ; t35,  t60
+    mova       [tmp1q-32*2], m2
+    mova       [tmp1q-32*1], m3
+    mova       [tmp2q+32*0], m10
+    mova       [tmp2q+32*1], m8
+    vpbroadcastd         m3, [o(idct64_mul+4*16)]
+    vpbroadcastd        m11, [o(idct64_mul+4*17)]
+    vpbroadcastd         m2, [o(idct64_mul+4*20)]
+    vpbroadcastd        m10, [o(idct64_mul+4*21)]
+    vpbroadcastd         m1, [o(idct64_mul+4*24)]
+    vpbroadcastd         m9, [o(idct64_mul+4*25)]
+    vpbroadcastd         m0, [o(idct64_mul+4*28)]
+    vpbroadcastd         m8, [o(idct64_mul+4*29)]
+    pmulhrsw             m3, m4  ; t59a
+    pmulhrsw             m4, m11 ; t36a
+    pmulhrsw             m2, m5  ; t58a
+    pmulhrsw             m5, m10 ; t37a
+    pmulhrsw             m1, m6  ; t57a
+    pmulhrsw             m6, m9  ; t38a
+    pmulhrsw             m0, m7  ; t56a
+    pmulhrsw             m7, m8  ; t39a
+    psubsw               m8, m4, m5 ; t37
+    paddsw               m4, m5     ; t36
+    psubsw               m5, m7, m6 ; t38
+    paddsw               m7, m6     ; t39
+    psubsw               m6, m0, m1 ; t57
+    paddsw               m0, m1     ; t56
+    psubsw               m1, m3, m2 ; t58
+    paddsw               m3, m2     ; t59
+    ITX_MULSUB_2W         6,  5,  2,  9, 15, m2598, 3166 ; t38a, t57a
+    vpbroadcastd        m10, [o(pw_3166_2598)]
+    ITX_MULSUB_2W         1,  8,  2,  9, 15, 10,  9 ; t37a, t58a
+    psubsw               m2, m7, m4 ; t36a
+    paddsw               m7, m4     ; t39a
+    psubsw               m4, m0, m3 ; t59a
+    paddsw               m0, m3     ; t56a
+    psubsw               m3, m6, m1 ; t37
+    paddsw               m6, m1     ; t38
+    psubsw               m1, m5, m8 ; t58
+    paddsw               m5, m8     ; t57
+    mova       [tmp1q+32*2], m6
+    mova       [tmp1q+32*3], m7
+    mova       [tmp2q-32*4], m0
+    mova       [tmp2q-32*3], m5
+    vpbroadcastd         m6, [o(pw_m799_m4017)]
+    vpbroadcastd         m7, [o(pw_m4017_799)]
+    ITX_MULSUB_2W         4,  2,  0,  5, 15,  7,  6 ; t36,  t59
+    ITX_MULSUB_2W         1,  3,  0,  5, 15,  7,  6 ; t37a, t58a
+    mova       [tmp1q+32*0], m4
+    mova       [tmp1q+32*1], m1
+    mova       [tmp2q-32*2], m3
+    mova       [tmp2q-32*1], m2
+    ret
+%define o_base pw_5 + 128
+.main_part2_pass1: ; idct64 steps 6-9 + idct16/32/64 sumsub
+    sub                  r6, o_idct64_offset + 8
+    vpbroadcastd        m11, [o(pw_1567_3784)]
+    vpbroadcastd        m12, [o(pw_m3784_1567)]
+    vpbroadcastd        m13, [o(pw_2896_2896)]
+    vpbroadcastd        m14, [o(pw_m2896_2896)]
+.main_part2_pass1_loop:
+    call .main_part2_internal
+    IDCT64_PART2_END      0,  7,  0,  6,  9, 10
+    IDCT64_PART2_END      7,  8,  5,  0,  6,  7
+    IDCT64_PART2_END      8,  2,  1,  0,  6,  7
+    IDCT64_PART2_END     15,  3,  4,  0,  6,  7
+    cmp               tmp1q, tmp2q
+    jne .main_part2_pass1_loop
+    ret
+cglobal_label .main_part2_internal
+    mova                 m0, [tmp1q-32*12] ; t32a
+    mova                 m6, [tmp2q-32*13] ; t39a
+    mova                 m1, [tmp1q-32* 4] ; t40a
+    mova                 m5, [tmp2q+32* 3] ; t55a
+    add               tmp1q, 32
+    sub               tmp2q, 32
+    mova                 m2, [tmp1q+32* 3] ; t48a
+    mova                 m4, [tmp2q-32* 4] ; t47a
+    mova                 m3, [tmp1q+32*11] ; t56a
+    mova                 m7, [tmp2q+32*12] ; t63a
+    psubsw               m8, m0, m6 ; t39
+    paddsw               m0, m6     ; t32
+    psubsw               m6, m4, m1 ; t40
+    paddsw               m4, m1     ; t47
+    psubsw               m1, m2, m5 ; t55
+    paddsw               m2, m5     ; t48
+    psubsw               m5, m7, m3 ; t56
+    paddsw               m7, m3     ; t63
+    ITX_MULSUB_2W         5,  8,  3,  9, 15, 11, 12 ; t39a, t56a
+    vpbroadcastd         m9, [o(pw_m1567_m3784)]
+    ITX_MULSUB_2W         1,  6,  3,  9, 15, 12,  9 ; t40a, t55a
+    psubsw               m3, m0, m4 ; t47a
+    paddsw               m0, m4     ; t32a
+    psubsw               m4, m7, m2 ; t48a
+    paddsw               m7, m2     ; t63a
+    psubsw               m2, m5, m1 ; t40
+    paddsw               m5, m1     ; t39
+    psubsw               m1, m8, m6 ; t55
+    paddsw               m8, m6     ; t56
+    ITX_MULSUB_2W         4,  3,  6,  9, 15, 13, 14 ; t47,  t48
+    ITX_MULSUB_2W         1,  2,  6,  9, 15, 13, 14 ; t40a, t55a
+    ret
+.main_part2_pass2:
+    sub                  r6, o_idct64_offset + 8
+    vpbroadcastd        m11, [o(pw_1567_3784)]
+    vpbroadcastd        m12, [o(pw_m3784_1567)]
+    vpbroadcastd        m13, [o(pw_2896_2896)]
+    lea                  r9, [strideq*5]    ; stride*5
+    lea                  r3, [r9+strideq*1] ; stride*6
+    lea                  r7, [r9+strideq*2] ; stride*7
+    lea                  r8, [r3+strideq*2] ; stride*8
+    lea                  r2, [dstq+r7]
+.main_part2_pass2_loop:
+    vpbroadcastd        m14, [o(pw_m2896_2896)]
+    call .main_part2_internal
+    vpbroadcastd        m14, [o(pw_2048)]
+    IDCT64_PART2_END      0,  7,  0,  6,  9, 10, strideq*0, r3*4, r8*4, r7*8
+    IDCT64_PART2_END      7,  8,  5,  0,  6,  7, strideq*0, r3*4, r8*4, r7*8
+    IDCT64_PART2_END      8,  2,  1,  0,  6,  7, strideq*8, r8*2, r9*8, r3*8
+    IDCT64_PART2_END     15,  3,  4,  0,  6,  7, strideq*8, r8*2, r9*8, r3*8
+    add                dstq, strideq
+    sub                  r2, strideq
+    cmp               tmp1q, tmp2q
+    jne .main_part2_pass2_loop
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x16_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_8192)]
+    mov                [cq], eobd
+    or                  r3d, 16
+.dconly:
+    pmulhrsw            xm0, xm2
+    movd                xm2, [o(pw_2048)]
+    pmulhrsw            xm0, xm1
+    pmulhrsw            xm0, xm2
+    vpbroadcastw         m0, xm0
+    pxor                 m1, m1
+.dconly_loop:
+    mova                 m2, [dstq+32*0]
+    mova                 m3, [dstq+32*1]
+    punpckhbw            m4, m2, m1
+    punpcklbw            m2, m1
+    punpckhbw            m5, m3, m1
+    punpcklbw            m3, m1
+    paddw                m4, m0
+    paddw                m2, m0
+    paddw                m5, m0
+    paddw                m3, m0
+    packuswb             m2, m4
+    packuswb             m3, m5
+    mova        [dstq+32*0], m2
+    mova        [dstq+32*1], m3
+    add                dstq, strideq
+    dec                 r3d
+    jg .dconly_loop
+    RET
+.normal:
+    PROLOGUE              0, 7, 16, 32*67, dst, stride, c, eob, tmp1, tmp2
+    LOAD_8ROWS      cq+32*0, 32*4
+    pxor                 m8, m8
+    REPX {mova [cq+32*x], m8}, 0, 4, 8, 12, 16, 20, 24, 28
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+    lea               tmp1q, [rsp+32*7]
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m1
+    mova       [tmp1q-32*2], m2
+    mova       [tmp1q-32*1], m3
+    mova       [tmp1q+32*0], m4
+    mova       [tmp1q+32*1], m5
+    mova       [tmp1q+32*2], m6
+    mova       [tmp1q+32*3], m7
+    add               tmp1q, 32*8
+    mova       [tmp1q-32*4], m8
+    mova       [tmp1q-32*3], m9
+    mova       [tmp1q-32*2], m10
+    mova       [tmp1q-32*1], m11
+    mova       [tmp1q+32*0], m12
+    mova       [tmp1q+32*1], m13
+    mova       [tmp1q+32*2], m14
+    mova       [tmp1q+32*3], m15
+    LOAD_8ROWS      cq+32*2, 32*4
+    pxor                 m8, m8
+    REPX {mova [cq+32*x], m8}, 2, 6, 10, 14, 18, 22, 26, 30
+    add               tmp1q, 32*8
+    lea               tmp2q, [tmp1q+32*8]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    vpbroadcastd        m15, [o(pd_2048)]
+    add               tmp1q, 32*16
+    add               tmp2q, 32*32
+    mova                 m0, [cq+32* 1]
+    mova                 m1, [cq+32*31]
+    mova                 m2, [cq+32*17]
+    mova                 m3, [cq+32*15]
+    mova                 m4, [cq+32* 9]
+    mova                 m5, [cq+32*23]
+    mova                 m6, [cq+32*25]
+    mova                 m7, [cq+32* 7]
+    pxor                 m8, m8
+    REPX {mova [cq+32*x], m8}, 1, 31, 17, 15, 9, 23, 25, 7
+    add                  r6, o_idct64_offset
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    add                  r6, 8
+    add               tmp1q, 32*8
+    sub               tmp2q, 32*8
+    mova                 m0, [cq+32* 5]
+    mova                 m1, [cq+32*27]
+    mova                 m2, [cq+32*21]
+    mova                 m3, [cq+32*11]
+    mova                 m4, [cq+32*13]
+    mova                 m5, [cq+32*19]
+    mova                 m6, [cq+32*29]
+    mova                 m7, [cq+32* 3]
+    pxor                 m8, m8
+    REPX {mova [cq+32*x], m8}, 5, 27, 21, 11, 13, 19, 29, 3
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part2_pass1
+    sub               tmp1q, 32*36
+    lea                  r2, [strideq*3]
+    mov               tmp2d, 4
+.pass2_loop:
+    lea                  r3, [tmp1q-32*8]
+    mova                xm0, [r3   -32*4]
+    mova                xm1, [r3   -32*3]
+    vinserti128          m0, [tmp1q-32*4], 1
+    vinserti128          m1, [tmp1q-32*3], 1
+    mova                xm2, [r3   -32*2]
+    mova                xm3, [r3   -32*1]
+    vinserti128          m2, [tmp1q-32*2], 1
+    vinserti128          m3, [tmp1q-32*1], 1
+    mova                xm4, [r3   +32*0]
+    mova                xm5, [r3   +32*1]
+    vinserti128          m4, [tmp1q+32*0], 1
+    vinserti128          m5, [tmp1q+32*1], 1
+    mova                xm6, [r3   +32*2]
+    mova                xm7, [r3   +32*3]
+    vinserti128          m6, [tmp1q+32*2], 1
+    vinserti128          m7, [tmp1q+32*3], 1
+    mova                xm8, [r3   -32*4+16]
+    mova                xm9, [r3   -32*3+16]
+    vinserti128          m8, [tmp1q-32*4+16], 1
+    vinserti128          m9, [tmp1q-32*3+16], 1
+    mova               xm10, [r3   -32*2+16]
+    mova               xm11, [r3   -32*1+16]
+    vinserti128         m10, [tmp1q-32*2+16], 1
+    vinserti128         m11, [tmp1q-32*1+16], 1
+    mova               xm12, [r3   +32*0+16]
+    mova               xm13, [r3   +32*1+16]
+    vinserti128         m12, [tmp1q+32*0+16], 1
+    vinserti128         m13, [tmp1q+32*1+16], 1
+    mova               xm14, [r3   +32*2+16]
+    mova               xm15, [r3   +32*3+16]
+    vinserti128         m14, [tmp1q+32*2+16], 1
+    vinserti128         m15, [tmp1q+32*3+16], 1
+    mova         [rsp+32*0], m6
+    mova         [rsp+32*1], m7
+    vpbroadcastd         m7, [o(pw_8192)]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).transpose_2x8x8_round
+    call m(idct_16x16_internal_8bpc).main
+    mova         [rsp+32*0], m15
+    vpbroadcastd        m15, [o(pw_2048)]
+    REPX  {pmulhrsw x, m15}, m0, m2, m3, m4, m5, m6, m7
+    WRITE_16X2            2,  3,  1,  2, strideq*2, r2
+    pmulhrsw             m1, m15, [rsp+32*1]
+    WRITE_16X2            0,  1,  2,  3, strideq*0, strideq*1
+    lea                  r3, [dstq+strideq*4]
+    %define dstq r3
+    WRITE_16X2            4,  5,  2,  3, strideq*0, strideq*1
+    WRITE_16X2            6,  7,  2,  3, strideq*2, r2
+    REPX  {pmulhrsw x, m15}, m8, m9, m10, m11, m12, m13, m14
+    lea                  r3, [r3+strideq*4]
+    WRITE_16X2            8,  9,  2,  3, strideq*0, strideq*1
+    WRITE_16X2           10, 11,  2,  3, strideq*2, r2
+    pmulhrsw            m15, [rsp+32*0]
+    lea                  r3, [r3+strideq*4]
+    WRITE_16X2           12, 13,  2,  3, strideq*0, strideq*1
+    WRITE_16X2           14, 15,  2,  3, strideq*2, r2
+    add               tmp1q, 32*16
+    add                  r0, 16
+    dec               tmp2d
+    jg .pass2_loop
+    RET
+
+cglobal inv_txfm_add_dct_dct_32x64_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm1
+    or                  r3d, 64
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).dconly
+.normal:
+    PROLOGUE              0, 11, 16, 32*99, dst, stride, c, eob, tmp1, tmp2
+    lea               tmp1q, [rsp+32*7]
+    lea                r10d, [eobq-136]
+    sar                r10d, 31
+.pass1_loop:
+    lea               tmp2q, [tmp1q+32*16]
+    LOAD_8ROWS      cq+64*1, 64*2, 1
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 1, 3, 5, 7, 9, 11, 13, 15
+    test               r10b, r10b
+    jnz .fast
+    LOAD_8ROWS_H   cq+64*17, 64*2, 2
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    LOAD_8ROWS_H   cq+64*16, 64*2, 1
+    mova              [rsp], m15
+    pxor                m15, m15
+    REPX {mova [cq+64*x], m15}, 16, 17, 18, 19, 20, 21, 22, 23, \
+                                24, 25, 26, 27, 28, 29, 30, 31
+    jmp .idct16
+.fast:
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+.idct16:
+    LOAD_8ROWS      cq+64*0, 64*2, 1
+    pxor                m15, m15
+    REPX {mova [cq+64*x], m15}, 0, 2, 4, 6, 8, 10, 12, 14
+    call m(idct_16x16_internal_8bpc).main
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).pass1_end
+    vpbroadcastd         m7, [o(pw_16384)]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).transpose_2x8x8_round
+    lea                  r3, [tmp1q+32*48]
+    mova                m15, [rsp]
+    mova          [r3-32*4], m0
+    mova          [r3-32*3], m2
+    mova          [r3-32*2], m4
+    mova          [r3-32*1], m6
+    mova          [r3+32*0], m8
+    mova          [r3+32*1], m10
+    mova          [r3+32*2], m12
+    mova          [r3+32*3], m14
+    add                  r3, 32*24
+    mova          [r3-32*4], m1
+    mova          [r3-32*3], m3
+    mova          [r3-32*2], m5
+    mova          [r3-32*1], m7
+    mova          [r3+32*0], m9
+    mova          [r3+32*1], m11
+    mova          [r3+32*2], m13
+    mova          [r3+32*3], m15
+    vpbroadcastd         m9, [o(pw_16384)]
+    pmulhrsw             m0, m9, [tmp1q-32*4]
+    pmulhrsw             m1, m9, [tmp1q-32*3]
+    pmulhrsw             m2, m9, [tmp1q-32*2]
+    pmulhrsw             m3, m9, [tmp1q-32*1]
+    pmulhrsw             m4, m9, [tmp1q+32*0]
+    pmulhrsw             m5, m9, [tmp1q+32*1]
+    pmulhrsw             m6, m9, [tmp1q+32*2]
+    pmulhrsw             m7, m9, [tmp1q+32*3]
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    mova       [tmp1q-32*4], m0
+    pmulhrsw             m0, m9, [tmp2q-32*4]
+    mova       [tmp2q-32*4], m1
+    pmulhrsw             m1, m9, [tmp2q-32*3]
+    mova       [tmp1q-32*3], m2
+    pmulhrsw             m2, m9, [tmp2q-32*2]
+    mova       [tmp2q-32*3], m3
+    pmulhrsw             m3, m9, [tmp2q-32*1]
+    mova       [tmp1q-32*2], m4
+    pmulhrsw             m4, m9, [tmp2q+32*0]
+    mova       [tmp2q-32*2], m5
+    pmulhrsw             m5, m9, [tmp2q+32*1]
+    mova       [tmp1q-32*1], m6
+    pmulhrsw             m6, m9, [tmp2q+32*2]
+    mova       [tmp2q-32*1], m7
+    pmulhrsw             m7, m9, [tmp2q+32*3]
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    mova       [tmp1q+32*0], m0
+    mova       [tmp2q+32*0], m1
+    mova       [tmp1q+32*1], m2
+    mova       [tmp2q+32*1], m3
+    mova       [tmp1q+32*2], m4
+    mova       [tmp2q+32*2], m5
+    mova       [tmp1q+32*3], m6
+    mova       [tmp2q+32*3], m7
+    add                  cq, 32
+    add               tmp1q, 32*8
+    add                r10d, 0x80000000
+    jnc .pass1_loop
+    lea                  r2, [rsp+32*55]
+    lea                  r7, [r2+32*24]
+.pass2_loop:
+    lea                  r3, [r2+32*8]
+    lea                  r8, [r7+32*8]
+    mova                 m0, [r2-32*4]
+    mova                 m1, [r2-32*2]
+    mova                 m2, [r2+32*0]
+    mova                 m3, [r2+32*2]
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14
+    test               r10b, r10b
+    jnz .fast2
+    mova                 m4, [r3-32*4]
+    mova                 m5, [r3-32*2]
+    mova                 m6, [r3+32*0]
+    mova                 m7, [r3+32*2]
+.fast2:
+    mova              [rsp], m8
+    lea               tmp1q, [rsp+32*39]
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m1
+    mova       [tmp1q-32*2], m2
+    mova       [tmp1q-32*1], m3
+    mova       [tmp1q+32*0], m4
+    mova       [tmp1q+32*1], m5
+    mova       [tmp1q+32*2], m6
+    mova       [tmp1q+32*3], m7
+    add               tmp1q, 32*8
+    mova       [tmp1q-32*4], m8
+    mova       [tmp1q-32*3], m9
+    mova       [tmp1q-32*2], m10
+    mova       [tmp1q-32*1], m11
+    mova       [tmp1q+32*0], m12
+    mova       [tmp1q+32*1], m13
+    mova       [tmp1q+32*2], m14
+    mova       [tmp1q+32*3], m15
+    mova                 m0, [r2-32*3]
+    mova                 m1, [r2-32*1]
+    mova                 m2, [r2+32*1]
+    mova                 m3, [r2+32*3]
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    test               r10b, r10b
+    jnz .fast3
+    mova                 m4, [r3-32*3]
+    mova                 m5, [r3-32*1]
+    mova                 m6, [r3+32*1]
+    mova                 m7, [r3+32*3]
+.fast3:
+    add               tmp1q, 32*8
+    lea               tmp2q, [tmp1q+32*8]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    vpbroadcastd        m15, [o(pd_2048)]
+    add               tmp1q, 32*16
+    add               tmp2q, 32*32
+    mova                 m0, [r7-32*4]
+    mova                 m3, [r7+32*3]
+    mova                 m4, [r7+32*0]
+    mova                 m7, [r7-32*1]
+    pxor                 m1, m1
+    REPX       {mova x, m1}, m2, m5, m6
+    test               r10b, r10b
+    jnz .fast4
+    mova                 m1, [r8+32*3]
+    mova                 m2, [r8-32*4]
+    mova                 m5, [r8-32*1]
+    mova                 m6, [r8+32*0]
+.fast4:
+    add                  r6, o_idct64_offset
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    add                  r6, 8
+    add               tmp1q, 32*8
+    sub               tmp2q, 32*8
+    mova                 m0, [r7-32*2]
+    mova                 m3, [r7+32*1]
+    mova                 m4, [r7+32*2]
+    mova                 m7, [r7-32*3]
+    pxor                 m1, m1
+    REPX       {mova x, m1}, m2, m5, m6
+    test               r10b, r10b
+    jnz .fast5
+    mova                 m1, [r8+32*1]
+    mova                 m2, [r8-32*2]
+    mova                 m5, [r8-32*3]
+    mova                 m6, [r8+32*2]
+.fast5:
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part2_pass2
+    add                r10d, 0x80000000
+    jc .ret
+    lea                  r2, [rsp+32*7]
+    lea                  r7, [r2+32*16]
+    sub                dstq, r8
+    lea                dstq, [dstq+strideq*4+16]
+    jmp .pass2_loop
+.ret:
+    RET
+
+cglobal inv_txfm_add_dct_dct_64x32_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_16384)]
+    mov                [cq], eobd
+    pmulhrsw            xm0, xm1
+    or                  r3d, 32
+    jmp m(inv_txfm_add_dct_dct_64x16_8bpc).dconly
+.normal:
+    PROLOGUE              0, 9, 16, 32*131, dst, stride, c, eob, tmp1, tmp2, \
+                                            base, tmp3, tmp4
+    lea               tmp1q, [rsp+32*7]
+    lea               tmp4d, [eobq-136]
+.pass1_loop:
+    LOAD_8ROWS      cq+64*0, 64*4, 1
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 0, 4, 8, 12, 16, 20, 24, 28
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m1
+    mova       [tmp1q-32*2], m2
+    mova       [tmp1q-32*1], m3
+    mova       [tmp1q+32*0], m4
+    mova       [tmp1q+32*1], m5
+    mova       [tmp1q+32*2], m6
+    mova       [tmp1q+32*3], m7
+    add               tmp1q, 32*8
+    mova       [tmp1q-32*4], m8
+    mova       [tmp1q-32*3], m9
+    mova       [tmp1q-32*2], m10
+    mova       [tmp1q-32*1], m11
+    mova       [tmp1q+32*0], m12
+    mova       [tmp1q+32*1], m13
+    mova       [tmp1q+32*2], m14
+    mova       [tmp1q+32*3], m15
+    LOAD_8ROWS      cq+64*2, 64*4, 1
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 2, 6, 10, 14, 18, 22, 26, 30
+    add               tmp1q, 32*8
+    lea               tmp2q, [tmp1q+32*8]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    vpbroadcastd        m15, [o(pd_2048)]
+    add               tmp1q, 32*16
+    add               tmp2q, 32*32
+    vpbroadcastd         m7, [o(pw_2896x8)]
+    pmulhrsw             m0, m7, [cq+64* 1]
+    pmulhrsw             m1, m7, [cq+64*31]
+    pmulhrsw             m2, m7, [cq+64*17]
+    pmulhrsw             m3, m7, [cq+64*15]
+    pmulhrsw             m4, m7, [cq+64* 9]
+    pmulhrsw             m5, m7, [cq+64*23]
+    pmulhrsw             m6, m7, [cq+64*25]
+    pmulhrsw             m7,     [cq+64* 7]
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 1, 31, 17, 15, 9, 23, 25, 7
+    add                  r6, o_idct64_offset
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    vpbroadcastd         m7, [o(pw_2896x8-(o_idct64_offset))]
+    add                  r6, 8
+    add               tmp1q, 32*8
+    sub               tmp2q, 32*8
+    pmulhrsw             m0, m7, [cq+64* 5]
+    pmulhrsw             m1, m7, [cq+64*27]
+    pmulhrsw             m2, m7, [cq+64*21]
+    pmulhrsw             m3, m7, [cq+64*11]
+    pmulhrsw             m4, m7, [cq+64*13]
+    pmulhrsw             m5, m7, [cq+64*19]
+    pmulhrsw             m6, m7, [cq+64*29]
+    pmulhrsw             m7,     [cq+64* 3]
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 5, 27, 21, 11, 13, 19, 29, 3
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part2_pass1
+    sub               tmp1q, 32*44
+    vpbroadcastd        m10, [o(pw_16384)]
+    call m(inv_txfm_add_dct_dct_64x32_8bpc).transpose_round_interleave
+    add                  cq, 32
+    add               tmp4d, 0x80000000
+    jnc .pass1_loop
+    lea               tmp1q, [rsp+32*15]
+    imul                 r2, strideq, 19
+    lea                  r3, [strideq*3]
+    add                  r2, dstq
+    mov               tmp4b, 4
+.pass2_loop:
+    lea               tmp2q, [tmp1q+32*64]
+    LOAD_8ROWS   tmp1q-32*4, 32
+    test              tmp4d, 0x40000000
+    jnz .fast
+    LOAD_8ROWS_H tmp2q-32*4, 32
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    lea               tmp3q, [tmp2q-32*8]
+    LOAD_8ROWS_H tmp3q-32*4, 32
+    mova              [rsp], m15
+    jmp .idct16
+.fast:
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    pxor                 m8, m8
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+.idct16:
+    lea               tmp3q, [tmp1q-32*8]
+    LOAD_8ROWS   tmp3q-32*4, 32
+    call m(idct_16x16_internal_8bpc).main
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).pass2_end
+    add               tmp1q, 32*16
+    sub                dstq, r3
+    lea                  r2, [r2+r3+16]
+    add                dstq, 16
+    dec               tmp4b
+    jg .pass2_loop
+    RET
+ALIGN function_align
+.transpose_round_interleave:
+    mov               tmp3d, 4
+.loop:
+    lea               tmp2q, [tmp1q+32*8]
+    mova                xm0, [tmp1q-32*4]
+    mova                xm1, [tmp1q-32*3]
+    vinserti128          m0, [tmp2q-32*4], 1
+    vinserti128          m1, [tmp2q-32*3], 1
+    mova                xm2, [tmp1q-32*2]
+    mova                xm3, [tmp1q-32*1]
+    vinserti128          m2, [tmp2q-32*2], 1
+    vinserti128          m3, [tmp2q-32*1], 1
+    mova                xm4, [tmp1q+32*0]
+    mova                xm5, [tmp1q+32*1]
+    vinserti128          m4, [tmp2q+32*0], 1
+    vinserti128          m5, [tmp2q+32*1], 1
+    mova                xm6, [tmp1q+32*2]
+    mova                xm7, [tmp1q+32*3]
+    vinserti128          m6, [tmp2q+32*2], 1
+    vinserti128          m7, [tmp2q+32*3], 1
+    REPX  {pmulhrsw x, m10}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    mova                xm8, [tmp1q-32*4+16]
+    mova                xm9, [tmp1q-32*3+16]
+    vinserti128          m8, [tmp2q-32*4+16], 1
+    vinserti128          m9, [tmp2q-32*3+16], 1
+    mova       [tmp1q-32*4], m0
+    mova       [tmp2q-32*4], m1
+    mova       [tmp1q-32*3], m2
+    mova       [tmp2q-32*3], m3
+    mova                xm2, [tmp1q-32*2+16]
+    mova                xm3, [tmp1q-32*1+16]
+    vinserti128          m2, [tmp2q-32*2+16], 1
+    vinserti128          m3, [tmp2q-32*1+16], 1
+    mova       [tmp1q-32*2], m4
+    mova       [tmp2q-32*2], m5
+    mova       [tmp1q-32*1], m6
+    mova       [tmp2q-32*1], m7
+    mova                xm4, [tmp1q+32*0+16]
+    mova                xm5, [tmp1q+32*1+16]
+    vinserti128          m4, [tmp2q+32*0+16], 1
+    vinserti128          m5, [tmp2q+32*1+16], 1
+    mova                xm6, [tmp1q+32*2+16]
+    mova                xm7, [tmp1q+32*3+16]
+    vinserti128          m6, [tmp2q+32*2+16], 1
+    vinserti128          m7, [tmp2q+32*3+16], 1
+    pmulhrsw             m0, m8, m10
+    pmulhrsw             m1, m9, m10
+    REPX  {pmulhrsw x, m10}, m2, m3, m4, m5, m6, m7
+    call m(inv_txfm_add_identity_identity_8x32_8bpc).transpose8x8
+    mova       [tmp1q+32*0], m0
+    mova       [tmp2q+32*0], m1
+    mova       [tmp1q+32*1], m2
+    mova       [tmp2q+32*1], m3
+    mova       [tmp1q+32*2], m4
+    mova       [tmp2q+32*2], m5
+    mova       [tmp1q+32*3], m6
+    mova       [tmp2q+32*3], m7
+    add               tmp1q, 32*16
+    dec               tmp3d
+    jg .loop
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x64_8bpc, 4, 4, 0, dst, stride, c, eob
+    lea                  r6, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_8192)]
+    mov                [cq], eobd
+    or                  r3d, 64
+    jmp m(inv_txfm_add_dct_dct_64x16_8bpc).dconly
+.normal:
+    PROLOGUE              0, 11, 16, 32*199, dst, stride, c, eob, tmp1, tmp2
+    lea               tmp1q, [rsp+32*71]
+    lea                r10d, [eobq-136]
+.pass1_loop:
+    LOAD_8ROWS      cq+64*0, 64*4
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 0, 4, 8, 12, 16, 20, 24, 28
+    REPX       {mova x, m8}, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m8
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m1
+    mova       [tmp1q-32*2], m2
+    mova       [tmp1q-32*1], m3
+    mova       [tmp1q+32*0], m4
+    mova       [tmp1q+32*1], m5
+    mova       [tmp1q+32*2], m6
+    mova       [tmp1q+32*3], m7
+    add               tmp1q, 32*8
+    mova       [tmp1q-32*4], m8
+    mova       [tmp1q-32*3], m9
+    mova       [tmp1q-32*2], m10
+    mova       [tmp1q-32*1], m11
+    mova       [tmp1q+32*0], m12
+    mova       [tmp1q+32*1], m13
+    mova       [tmp1q+32*2], m14
+    mova       [tmp1q+32*3], m15
+    LOAD_8ROWS      cq+64*2, 64*4
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 2, 6, 10, 14, 18, 22, 26, 30
+    add               tmp1q, 32*8
+    lea               tmp2q, [tmp1q+32*8]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    vpbroadcastd        m15, [o(pd_2048)]
+    add               tmp1q, 32*16
+    add               tmp2q, 32*32
+    mova                 m0, [cq+64* 1]
+    mova                 m1, [cq+64*31]
+    mova                 m2, [cq+64*17]
+    mova                 m3, [cq+64*15]
+    mova                 m4, [cq+64* 9]
+    mova                 m5, [cq+64*23]
+    mova                 m6, [cq+64*25]
+    mova                 m7, [cq+64* 7]
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 1, 31, 17, 15, 9, 23, 25, 7
+    add                  r6, o_idct64_offset
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    add                  r6, 8
+    add               tmp1q, 32*8
+    sub               tmp2q, 32*8
+    mova                 m0, [cq+64* 5]
+    mova                 m1, [cq+64*27]
+    mova                 m2, [cq+64*21]
+    mova                 m3, [cq+64*11]
+    mova                 m4, [cq+64*13]
+    mova                 m5, [cq+64*19]
+    mova                 m6, [cq+64*29]
+    mova                 m7, [cq+64* 3]
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 5, 27, 21, 11, 13, 19, 29, 3
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part2_pass1
+    sub               tmp1q, 32*44
+    vpbroadcastd        m10, [o(pw_8192)]
+    call m(inv_txfm_add_dct_dct_64x32_8bpc).transpose_round_interleave
+    add                  cq, 32
+    add                r10d, 0x80000000
+    jnc .pass1_loop
+    lea               tmp1q, [rsp+32*7]
+    mov                r10b, 4
+.pass2_loop:
+    lea                  r2, [tmp1q+32*64]
+    mova                 m0, [r2-32*4]
+    mova                 m1, [r2-32*2]
+    mova                 m2, [r2+32*0]
+    mova                 m3, [r2+32*2]
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14
+    mova              [rsp], m4
+    test               r10d, 0x40000000
+    jnz .fast
+    lea                  r3, [r2+32*64]
+    mova                 m4, [r3-32*4]
+    mova                 m5, [r3-32*2]
+    mova                 m6, [r3+32*0]
+    mova                 m7, [r3+32*2]
+.fast:
+    call m(idct_16x16_internal_8bpc).main
+    mova                 m1, [rsp+32*1]
+    mova       [tmp1q-32*4], m0
+    mova       [tmp1q-32*3], m1
+    mova       [tmp1q-32*2], m2
+    mova       [tmp1q-32*1], m3
+    mova       [tmp1q+32*0], m4
+    mova       [tmp1q+32*1], m5
+    mova       [tmp1q+32*2], m6
+    mova       [tmp1q+32*3], m7
+    add               tmp1q, 32*8
+    mova       [tmp1q-32*4], m8
+    mova       [tmp1q-32*3], m9
+    mova       [tmp1q-32*2], m10
+    mova       [tmp1q-32*1], m11
+    mova       [tmp1q+32*0], m12
+    mova       [tmp1q+32*1], m13
+    mova       [tmp1q+32*2], m14
+    mova       [tmp1q+32*3], m15
+    mova                 m0, [r2-32*3]
+    mova                 m1, [r2-32*1]
+    mova                 m2, [r2+32*1]
+    mova                 m3, [r2+32*3]
+    pxor                 m4, m4
+    REPX       {mova x, m4}, m5, m6, m7
+    test               r10d, 0x40000000
+    jnz .fast2
+    mova                 m4, [r3-32*3]
+    mova                 m5, [r3-32*1]
+    mova                 m6, [r3+32*1]
+    mova                 m7, [r3+32*3]
+.fast2:
+    add               tmp1q, 32*8
+    lea               tmp2q, [tmp1q+32*8]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    vpbroadcastd        m15, [o(pd_2048)]
+    add                  r2, 32*8
+    add                  r3, 32*8
+    add               tmp1q, 32*16
+    add               tmp2q, 32*32
+    mova                 m0, [r2-32*4] ;  1
+    mova                 m3, [r2+32*3] ; 15
+    mova                 m4, [r2+32*0] ;  9
+    mova                 m7, [r2-32*1] ;  7
+    pxor                 m1, m1
+    REPX       {mova x, m1}, m2, m5, m6
+    test               r10d, 0x40000000
+    jnz .fast3
+    mova                 m1, [r3+32*3] ; 31
+    mova                 m2, [r3-32*4] ; 17
+    mova                 m5, [r3-32*1] ; 23
+    mova                 m6, [r3+32*0] ; 25
+.fast3:
+    add                  r6, o_idct64_offset
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    add                  r6, 8
+    add               tmp1q, 32*8
+    sub               tmp2q, 32*8
+    mova                 m0, [r2-32*2] ;  5
+    mova                 m3, [r2+32*1] ; 11
+    mova                 m4, [r2+32*2] ; 13
+    mova                 m7, [r2-32*3] ;  3
+    pxor                 m1, m1
+    REPX       {mova x, m1}, m2, m5, m6
+    test               r10d, 0x40000000
+    jnz .fast4
+    mova                 m1, [r3+32*1] ; 27
+    mova                 m2, [r3-32*2] ; 21
+    mova                 m5, [r3-32*3] ; 19
+    mova                 m6, [r3+32*2] ; 29
+.fast4:
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_part2_pass2
+    sub               tmp1q, 32*28
+    sub                dstq, r8
+    lea                dstq, [dstq+strideq*4+16]
+    dec                r10b
+    jg .pass2_loop
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/itx_avx512.asm b/media/libdav1d/src/src/x86/itx_avx512.asm
new file mode 100644
index 0000000000..a3f25d37e5
--- /dev/null
+++ b/media/libdav1d/src/src/x86/itx_avx512.asm
@@ -0,0 +1,7507 @@
+; Copyright © 2020-2023, VideoLAN and dav1d authors
+; Copyright © 2020-2023, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+const \
+dup16_perm,  db  0,  1,  0,  1,  2,  3,  2,  3,  4,  5,  4,  5,  6,  7,  6,  7
+             db  8,  9,  8,  9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15, 14, 15
+             db 16, 17, 16, 17, 18, 19, 18, 19, 20, 21, 20, 21, 22, 23, 22, 23
+             db 24, 25, 24, 25, 26, 27, 26, 27, 28, 29, 28, 29, 30, 31, 30, 31
+const \
+int8_permA,  db  0,  1, 16, 17, 32, 33, 48, 49,  2,  3, 18, 19, 34, 35, 50, 51
+             db  4,  5, 20, 21, 36, 37, 52, 53,  6,  7, 22, 23, 38, 39, 54, 55
+             db  8,  9, 24, 25, 40, 41, 56, 57, 10, 11, 26, 27, 42, 43, 58, 59
+             db 12, 13, 28, 29, 44, 45, 60, 61, 14, 15, 30, 31, 46, 47, 62, 63
+int8_permB:  db  0,  1, 16, 17, 32, 33, 48, 49,  2,  3, 18, 19, 34, 35, 50, 51
+             db  8,  9, 24, 25, 40, 41, 56, 57, 10, 11, 26, 27, 42, 43, 58, 59
+             db  4,  5, 20, 21, 36, 37, 52, 53,  6,  7, 22, 23, 38, 39, 54, 55
+             db 12, 13, 28, 29, 44, 45, 60, 61, 14, 15, 30, 31, 46, 47, 62, 63
+int16_perm:  db  0,  1, 32, 33,  2,  3, 34, 35,  4,  5, 36, 37,  6,  7, 38, 39
+             db  8,  9, 40, 41, 10, 11, 42, 43, 12, 13, 44, 45, 14, 15, 46, 47
+             db 16, 17, 48, 49, 18, 19, 50, 51, 20, 21, 52, 53, 22, 23, 54, 55
+             db 24, 25, 56, 57, 26, 27, 58, 59, 28, 29, 60, 61, 30, 31, 62, 63
+idtx_16x4p:  db  0,  1,  4,  5, 16, 17, 20, 21,  2,  3,  6,  7, 18, 19, 22, 23
+             db 32, 33, 36, 37, 48, 49, 52, 53, 34, 35, 38, 39, 50, 51, 54, 55
+             db  8,  9, 12, 13, 24, 25, 28, 29, 10, 11, 14, 15, 26, 27, 30, 31
+             db 40, 41, 44, 45, 56, 57, 60, 61, 42, 43, 46, 47, 58, 59, 62, 63
+idct_8x32p:  db 60, 61,  4,  5, 32, 33,  0,  1, 28, 29, 36, 37, 56, 57,  8,  9
+             db 12, 13, 52, 53, 24, 25, 40, 41, 44, 45, 20, 21, 48, 49, 16, 17
+             db 62, 63,  2,  3,  6,  7, 58, 59, 54, 55, 10, 11, 14, 15, 50, 51
+             db 46, 47, 18, 19, 22, 23, 42, 43, 38, 39, 26, 27, 30, 31, 34, 35
+idct_16x32p: db  6,  7, 58, 59, 38, 39, 26, 27, 32, 33,  0,  1, 30, 31, 34, 35
+             db 46, 47, 18, 19, 22, 23, 42, 43, 24, 25, 40, 41, 44, 45, 20, 21
+             db 62, 63,  2,  3, 48, 49, 16, 17, 56, 57,  8,  9, 14, 15, 50, 51
+             db 54, 55, 10, 11, 60, 61,  4,  5, 12, 13, 52, 53, 28, 29, 36, 37
+end_16x32p:  db  0, 32,  1, 48,  2, 36,  3, 52, 16, 40, 17, 56, 18, 44, 19, 60
+             db  4, 33,  5, 49,  6, 37,  7, 53, 20, 41, 21, 57, 22, 45, 23, 61
+             db  8, 35,  9, 51, 10, 39, 11, 55, 24, 43, 25, 59, 26, 47, 27, 63
+             db 12, 34, 13, 50, 14, 38, 15, 54, 28, 42, 29, 58, 30, 46, 31, 62
+
+; packed 4-bit qword shuffle indices
+permA:       dq 0x1c0d0d1ce0d94040, 0x5849495868fb6262
+             dq 0x3e2f2f3ef1c85151, 0x7a6b6b7a79ea7373
+             dq 0x94858594a451c8d9, 0xd0c1c1d02c73eafb
+             dq 0xb6a7a7b6b540d9c8, 0xf2e3e3f23d62fbea
+permB:       dq 0x40acbd0fcadb0f40, 0x518e9f3ce8f99604
+             dq 0xc824352d56128751, 0xd906171e74301e15
+             dq 0x6271604b03472d62, 0x735342782165b426
+             dq 0xeaf9e8699f8ea573, 0xfbdbca5abdac3c37
+permC:       dq 0x9d409d041551c2e0, 0xbf62bf263773a486
+             dq 0xc88c8c15409dd3f1, 0xeaaeae3762bfb597
+             dq 0x04d9158c8cc84a68, 0x26fb37aeaeea2c0e
+             dq 0x5115049dd9045b79, 0x733726bffb263d1f
+permD:       dq 0x0cda098800041504, 0x0edb09b2028c3726
+             dq 0x0f11fa9c01150415, 0x0988f326039d2637
+             dq 0x05640f1108269d8c, 0x05290edb0aaebfae
+             dq 0x0005000509378c9d, 0xffffffff0bbfaebf
+
+pd_0to15:    dd  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+gather8a:    dd  0,  2,  1,  3,  8, 10,  9, 11
+gather8b:    dd  0,  1,  4,  5,  8,  9, 12, 13
+gather8c:    dd  0,  4,  2,  6, 12,  8, 14, 10
+gather8d:    dd  0, 19,  1, 18,  2, 17,  3, 16
+
+int_shuf1:   db  0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+int_shuf2:   db  8,  9,  0,  1, 10, 11,  2,  3, 12, 13,  4,  5, 14, 15,  6,  7
+int_shuf3:   db  0,  1,  8,  9,  4,  5, 12, 13,  2,  3, 10, 11,  6,  7, 14, 15
+int_shuf4:   db  8,  9,  0,  1, 12, 13,  4,  5, 10, 11,  2,  3, 14, 15,  6,  7
+deint_shuf:  db  0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+int_mshift:  db 12, 20,  0,  0, 44, 52,  0,  0
+
+pb_32:           times 4 db 32
+pw_2048:         times 2 dw 2048
+pw_4096:         times 2 dw 4096
+pw_8192:         times 2 dw 8192
+pw_16384:        times 2 dw 16384
+pw_1697x16:      times 2 dw 1697*16
+pw_1697x8:       times 2 dw 1697*8
+pw_2896x8:       times 2 dw 2896*8
+pd_2048:         dd  2048
+
+%define pw_5          (permD+52)
+%define pd_m1         (permD+60)
+%define pw_3803_1321  (permD+44)
+%define pw_2482_3803  (permD+12)
+%define pw_2440_3290  (permD+ 4)
+%define pw_m3290_2440 (permD+28)
+%define pw_3857_1380  (permD+36)
+%define pw_m1380_3857 (permD+20)
+
+pw_8192_m8192:   dw   8192,  -8192
+pw_m8192_8192:   dw  -8192,   8192
+pw_16384_m16384: dw  16384, -16384
+pw_m16384_16384: dw -16384,  16384
+
+pw_m1321_2482:   dw  -1321,  2482
+pw_m3344_3344:   dw  -3344,  3344
+pw_2482_3344:    dw   2482,  3344
+pw_m3803_3344:   dw  -3803,  3344
+pd_3344:         dd   3344
+pw_m1321_m3344:  dw  -1321, -3344
+pw_2896_m2896:   dw   2896, -2896
+
+pw_1567_m3784:   dw   1567, -3784
+pw_3784_m1567:   dw   3784, -1567
+pw_4017_m799:    dw   4017,  -799
+pw_2276_m3406:   dw   2276, -3406
+pw_m799_m4017:   dw   -799, -4017
+pw_m3406_m2276:  dw  -3406, -2276
+
+%macro COEF_PAIR 2-3 0
+pw_%1_%2:   dw  %1,  %2
+pw_m%2_%1:  dw -%2,  %1
+%if %3
+pw_m%1_m%2: dw -%1, -%2
+%endif
+%endmacro
+
+COEF_PAIR 2896, 2896
+COEF_PAIR 1567, 3784, 1
+COEF_PAIR 3784, 1567
+COEF_PAIR  201, 4091
+COEF_PAIR  995, 3973
+COEF_PAIR 1751, 3703
+COEF_PAIR 3035, 2751
+COEF_PAIR 3513, 2106
+COEF_PAIR 4052,  601
+COEF_PAIR 3166, 2598, 1
+COEF_PAIR 3920, 1189, 1
+COEF_PAIR 2276, 3406
+COEF_PAIR 4017,  799
+
+%macro COEF_X8 1-*
+%rep %0
+    dw %1*8, %1*8
+    %rotate 1
+%endrep
+%endmacro
+
+pw_m2276x8: COEF_X8 -2276
+pw_3406x8:  COEF_X8  3406
+pw_4017x8:  COEF_X8  4017
+pw_799x8:   COEF_X8   799
+pw_3784x8:  COEF_X8  3784
+pw_1567x8:  COEF_X8  1567
+
+pw_4076x8:  COEF_X8  4076
+pw_401x8:   COEF_X8   401
+pw_m2598x8: COEF_X8 -2598
+pw_3166x8:  COEF_X8  3166
+pw_3612x8:  COEF_X8  3612
+pw_1931x8:  COEF_X8  1931
+pw_m1189x8: COEF_X8 -1189
+pw_3920x8:  COEF_X8  3920
+
+pw_4091x8:  COEF_X8  4091
+pw_201x8:   COEF_X8   201
+pw_m2751x8: COEF_X8 -2751
+pw_3035x8:  COEF_X8  3035
+pw_3703x8:  COEF_X8  3703
+pw_1751x8:  COEF_X8  1751
+pw_m1380x8: COEF_X8 -1380
+pw_3857x8:  COEF_X8  3857
+pw_3973x8:  COEF_X8  3973
+pw_995x8:   COEF_X8   995
+pw_m2106x8: COEF_X8 -2106
+pw_3513x8:  COEF_X8  3513
+pw_3290x8:  COEF_X8  3290
+pw_2440x8:  COEF_X8  2440
+pw_m601x8:  COEF_X8  -601
+pw_4052x8:  COEF_X8  4052
+
+pw_401_4076x8:   dw   401*8, 4076*8
+pw_m2598_3166x8: dw -2598*8, 3166*8
+pw_1931_3612x8:  dw  1931*8, 3612*8
+pw_m1189_3920x8: dw -1189*8, 3920*8
+pw_799_4017x8:   dw   799*8, 4017*8
+pw_m2276_3406x8: dw -2276*8, 3406*8
+
+pw_201_4091x8:   dw   201*8, 4091*8
+pw_m601_4052x8:  dw  -601*8, 4052*8
+pw_995_3973x8:   dw   995*8, 3973*8
+pw_m1380_3857x8: dw -1380*8, 3857*8
+pw_1751_3703x8:  dw  1751*8, 3703*8
+pw_m2106_3513x8: dw -2106*8, 3513*8
+pw_2440_3290x8:  dw  2440*8, 3290*8
+pw_m2751_3035x8: dw -2751*8, 3035*8
+
+pw_101_4095x8:   dw   101*8, 4095*8
+pw_m2824_2967x8: dw -2824*8, 2967*8
+pw_1660_3745x8:  dw  1660*8, 3745*8
+pw_m1474_3822x8: dw -1474*8, 3822*8
+pw_897_3996x8:   dw   897*8, 3996*8
+pw_m2191_3461x8: dw -2191*8, 3461*8
+pw_2359_3349x8:  dw  2359*8, 3349*8
+pw_m700_4036x8:  dw  -700*8, 4036*8
+pw_501_4065x8:   dw   501*8, 4065*8
+pw_m2520_3229x8: dw -2520*8, 3229*8
+pw_2019_3564x8:  dw  2019*8, 3564*8
+pw_m1092_3948x8: dw -1092*8, 3948*8
+pw_1285_3889x8:  dw  1285*8, 3889*8
+pw_m1842_3659x8: dw -1842*8, 3659*8
+pw_2675_3102x8:  dw  2675*8, 3102*8
+pw_m301_4085x8:  dw  -301*8, 4085*8
+
+idct64_mul: COEF_X8  4095,   101,  2967, -2824,  3745,  1660,  3822, -1474
+COEF_PAIR  401, 4076, 1
+COEF_PAIR  799, 4017
+            COEF_X8  -700,  4036,  2359,  3349, -2191,  3461,   897,  3996
+dw    -2598, -3166,  3166, -2598,  2598,  3166, -4017,  -799,   799, -4017
+            COEF_X8  4065,   501,  3229, -2520,  3564,  2019,  3948, -1092
+COEF_PAIR 1931, 3612, 1
+COEF_PAIR 3406, 2276
+            COEF_X8  -301,  4085,  2675,  3102, -1842,  3659,  1285,  3889
+dw    -1189, -3920,  3920, -1189,  1189,  3920, -2276, -3406,  3406, -2276
+
+SECTION .text
+
+%define o_base int8_permA+64*18
+%define o(x) (r5 - (o_base) + (x))
+%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX)
+
+; flags: 1 = swap, 2 = interleave (l), 4 = interleave (t), 8 = no_pack,
+;        16 = special_mul1, 32 = special_mul2
+%macro ITX_MUL2X_PACK 6-7 0 ; dst/src, tmp[1-2], rnd, coef[1-2], flags
+    mova                m%2, m%4
+%if %7 & 16
+    vpdpwssd            m%2, m%1, [o(pw_%5)] {bcstd}
+    mova                m%3, m%4
+%if %7 & 32
+    vpdpwssd            m%3, m%1, [o(pw_%6)] {bcstd}
+%else
+    vpdpwssd            m%3, m%1, m%6
+%endif
+%elif %7 & 32
+    vpdpwssd            m%2, m%1, m%5
+    mova                m%3, m%4
+    vpdpwssd            m%3, m%1, [o(pw_%6)] {bcstd}
+%elif %6 < 32
+    vpdpwssd            m%2, m%1, m%5
+    mova                m%3, m%4
+    vpdpwssd            m%3, m%1, m%6
+%elif %7 & 1
+    vpdpwssd            m%2, m%1, [o(pw_%5_%6)] {bcstd}
+    mova                m%3, m%4
+    vpdpwssd            m%3, m%1, [o(pw_m%6_%5)] {bcstd}
+%else
+    vpdpwssd            m%2, m%1, [o(pw_m%6_%5)] {bcstd}
+    mova                m%3, m%4
+    vpdpwssd            m%3, m%1, [o(pw_%5_%6)] {bcstd}
+%endif
+%if %7 & 2
+    psrld               m%2, 12
+    pslld               m%3, 4
+    vpshrdd             m%1, m%3, m%2, 16
+%elif %7 & 4
+    ; compared to using shifts (as above) this has better throughput,
+    ; but worse latency and requires setting up the opmask/index
+    ; registers, so only use this method for the larger transforms
+    pslld               m%1, m%2, 4
+    vpmultishiftqb  m%1{k7}, m13, m%3
+%else
+    psrad               m%2, 12
+    psrad               m%3, 12
+%if %7 & 8 == 0
+    packssdw            m%1, m%3, m%2
+%endif
+%endif
+%endmacro
+
+; flags: same as ITX_MUL2X_PACK
+%macro ITX_MUL4X_PACK 10-11 0 ; dst/src, tmp[1-2], coef_tmp[1-2], rnd, coef[1-4], flags
+%if %11 & 1
+    vpbroadcastd        m%4, [o(pw_%9_%10)]
+    vpbroadcastd    m%4{k1}, [o(pw_%7_%8)]
+    vpbroadcastd        m%5, [o(pw_m%10_%9)]
+    vpbroadcastd    m%5{k1}, [o(pw_m%8_%7)]
+%else
+    vpbroadcastd        m%4, [o(pw_m%10_%9)]
+    vpbroadcastd    m%4{k1}, [o(pw_m%8_%7)]
+    vpbroadcastd        m%5, [o(pw_%9_%10)]
+    vpbroadcastd    m%5{k1}, [o(pw_%7_%8)]
+%endif
+    ITX_MUL2X_PACK       %1, %2, %3, %6, %4, %5, %11
+%endmacro
+
+; dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12
+; dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12
+%macro ITX_MULSUB_2W 7-8 ; dst/src[1-2], tmp[1-2], rnd, coef[1-2], dst2
+    punpcklwd           m%3, m%2, m%1
+    punpckhwd           m%2, m%1
+%if %7 < 32
+    mova                m%1, m%5
+    vpdpwssd            m%1, m%3, m%7
+    mova                m%4, m%5
+    vpdpwssd            m%4, m%2, m%7
+%else
+    mova                m%1, m%5
+    vpdpwssd            m%1, m%3, [o(pw_m%7_%6)] {bcstd}
+    mova                m%4, m%5
+    vpdpwssd            m%4, m%2, [o(pw_m%7_%6)] {bcstd}
+%endif
+    psrad               m%1, 12
+    psrad               m%4, 12
+    packssdw            m%1, m%4
+    mova                m%4, m%5
+%if %7 < 32
+    vpdpwssd            m%4, m%2, m%6
+    mova                m%2, m%5
+    vpdpwssd            m%2, m%3, m%6
+%else
+    vpdpwssd            m%4, m%2, [o(pw_%6_%7)] {bcstd}
+    mova                m%2, m%5
+    vpdpwssd            m%2, m%3, [o(pw_%6_%7)] {bcstd}
+%endif
+    psrad               m%4, 12
+    psrad               m%2, 12
+%if %0 == 8
+    packssdw            m%8, m%2, m%4
+%else
+    packssdw            m%2, m%4
+%endif
+%endmacro
+
+%macro WRAP_XMM 1+
+    %xdefine %%reset RESET_MM_PERMUTATION
+    INIT_XMM cpuname
+    DEFINE_MMREGS xmm
+    AVX512_MM_PERMUTATION
+    %1
+    %%reset
+%endmacro
+
+%macro WRAP_YMM 1+
+    INIT_YMM cpuname
+    %1
+    INIT_ZMM cpuname
+%endmacro
+
+%macro ITX4_END 4-5 2048 ; row[1-4], rnd
+%if %5
+    vpbroadcastd         m2, [o(pw_%5)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+%endif
+    lea                  r2, [dstq+strideq*2]
+%assign %%i 1
+%rep 4
+    %if %1 & 2
+        CAT_XDEFINE %%row_adr, %%i, r2   + strideq*(%1&1)
+    %else
+        CAT_XDEFINE %%row_adr, %%i, dstq + strideq*(%1&1)
+    %endif
+    %assign %%i %%i + 1
+    %rotate 1
+%endrep
+    movd                 m2, [%%row_adr1]
+    pinsrd               m2, [%%row_adr2], 1
+    movd                 m3, [%%row_adr3]
+    pinsrd               m3, [%%row_adr4], 1
+    pmovzxbw             m2, m2
+    pmovzxbw             m3, m3
+    paddw                m0, m2
+    paddw                m1, m3
+    packuswb             m0, m1
+    movd       [%%row_adr1], m0
+    pextrd     [%%row_adr2], m0, 1
+    pextrd     [%%row_adr3], m0, 2
+    pextrd     [%%row_adr4], m0, 3
+    ret
+%endmacro
+
+%macro INV_TXFM_FN 3 ; type1, type2, size
+cglobal inv_txfm_add_%1_%2_%3_8bpc, 4, 6, 0, dst, stride, c, eob, tx2, base
+    %define %%p1 m(i%1_%3_internal_8bpc)
+    lea               baseq, [o_base]
+    ; Jump to the 1st txfm function if we're not taking the fast path, which
+    ; in turn performs an indirect jump to the 2nd txfm function.
+    lea tx2q, [m(i%2_%3_internal_8bpc).pass2]
+%ifidn %1_%2, dct_dct
+    test               eobd, eobd
+    jnz %%p1
+%else
+    ; jump to the 1st txfm function unless it's located directly after this
+    times ((%%end - %%p1) >> 31) & 1 jmp %%p1
+ALIGN function_align
+%%end:
+%endif
+%endmacro
+
+%macro INV_TXFM_4X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x4
+%ifidn %1_%2, dct_dct
+    vpbroadcastw         m0, [cq]
+    vpbroadcastd         m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1
+    mov                [cq], eobd
+    pmulhrsw             m0, m1
+    mova                 m1, m0
+    jmp m(iadst_4x4_internal_8bpc).end2
+%endif
+%endmacro
+
+%macro IDCT4_1D_PACKED 0
+    vpbroadcastd         m4, [o(pd_2048)]
+    punpckhwd            m2, m1, m0
+    punpcklwd            m1, m0
+    ITX_MUL2X_PACK        2, 0, 3, 4, 1567, 3784
+    ITX_MUL2X_PACK        1, 0, 3, 4, 2896, 2896
+    paddsw               m0, m1, m2 ; out0 out1
+    psubsw               m1, m2     ; out3 out2
+%endmacro
+
+%macro IADST4_1D_PACKED 0
+    punpcklwd            m4, m1, m0 ; in2 in0
+    punpckhwd            m5, m1, m0 ; in3 in1
+.main2:
+    vpbroadcastd         m3, [o(pd_2048)]
+    mova                 m0, m3
+    vpdpwssd             m0, m4, [o(pw_3803_1321)] {bcstd}
+    mova                 m2, m3
+    vpdpwssd             m2, m4, [o(pw_m1321_2482)] {bcstd}
+    mova                 m1, m3
+    vpdpwssd             m1, m4, [o(pw_m3344_3344)] {bcstd}
+    vpdpwssd             m3, m4, [o(pw_2482_3803)] {bcstd}
+    vpdpwssd             m0, m5, [o(pw_2482_3344)] {bcstd}
+    vpdpwssd             m2, m5, [o(pw_m3803_3344)] {bcstd}
+    vpdpwssd             m1, m5, [o(pd_3344)] {bcstd}
+    vpdpwssd             m3, m5, [o(pw_m1321_m3344)] {bcstd}
+    REPX      {psrad x, 12}, m0, m2, m1, m3
+    packssdw             m0, m2 ; out0 out1
+    packssdw             m1, m3 ; out2 out3
+%endmacro
+
+INIT_XMM avx512icl
+INV_TXFM_4X4_FN dct, dct
+INV_TXFM_4X4_FN dct, adst
+INV_TXFM_4X4_FN dct, flipadst
+INV_TXFM_4X4_FN dct, identity
+
+cglobal idct_4x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    IDCT4_1D_PACKED
+    mova                 m2, [o(deint_shuf)]
+    shufps               m3, m0, m1, q1331
+    shufps               m0, m0, m1, q0220
+    pshufb               m0, m2
+    pshufb               m1, m3, m2
+    jmp                tx2q
+.pass2:
+    IDCT4_1D_PACKED
+    pxor              ymm16, ymm16
+    mova               [cq], ymm16
+    ITX4_END              0, 1, 3, 2
+
+INV_TXFM_4X4_FN adst, dct
+INV_TXFM_4X4_FN adst, adst
+INV_TXFM_4X4_FN adst, flipadst
+INV_TXFM_4X4_FN adst, identity
+
+cglobal iadst_4x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    call .main
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    jmp                tx2q
+.pass2:
+    call .main
+.end:
+    pxor              ymm16, ymm16
+    mova               [cq], ymm16
+.end2:
+    ITX4_END              0, 1, 2, 3
+ALIGN function_align
+.main:
+    IADST4_1D_PACKED
+    ret
+
+INV_TXFM_4X4_FN flipadst, dct
+INV_TXFM_4X4_FN flipadst, adst
+INV_TXFM_4X4_FN flipadst, flipadst
+INV_TXFM_4X4_FN flipadst, identity
+
+cglobal iflipadst_4x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    call m(iadst_4x4_internal_8bpc).main
+    punpcklwd            m2, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    jmp                tx2q
+.pass2:
+    call m(iadst_4x4_internal_8bpc).main
+.end:
+    pxor              ymm16, ymm16
+    mova               [cq], ymm16
+.end2:
+    ITX4_END              3, 2, 1, 0
+
+INV_TXFM_4X4_FN identity, dct
+INV_TXFM_4X4_FN identity, adst
+INV_TXFM_4X4_FN identity, flipadst
+INV_TXFM_4X4_FN identity, identity
+
+cglobal iidentity_4x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m0, [cq+16*0]
+    mova                 m1, [cq+16*1]
+    vpbroadcastd         m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    jmp m(iadst_4x4_internal_8bpc).end
+
+%macro INV_TXFM_4X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x8
+%ifidn %1_%2, dct_dct
+    movd               xmm1, [o(pw_2896x8)]
+    pmulhrsw           xmm0, xmm1, [cq]
+    movd               xmm2, [o(pw_2048)]
+    pmulhrsw           xmm0, xmm1
+    pmulhrsw           xmm0, xmm1
+    pmulhrsw           xmm0, xmm2
+    vpbroadcastw        ym0, xmm0
+    mova                ym1, ym0
+    jmp m(iadst_4x8_internal_8bpc).end3
+%endif
+%endmacro
+
+%macro IDCT8_1D_PACKED 0
+    punpckhwd            m5, m3, m0 ; in7 in1
+    punpckhwd            m4, m1, m2 ; in3 in5
+    punpcklwd            m3, m1     ; in6 in2
+    punpcklwd            m2, m0     ; in4 in0
+.main2:
+    vpbroadcastd         m6, [o(pd_2048)]
+    ITX_MUL2X_PACK        5, 0, 1, 6,  799, 4017, 3 ; t4a t7a
+    ITX_MUL2X_PACK        4, 0, 1, 6, 3406, 2276, 3 ; t5a t6a
+    ITX_MUL2X_PACK        3, 0, 1, 6, 1567, 3784    ; t3 t2
+    psubsw               m0, m5, m4 ; t5a t6a (interleaved)
+    paddsw               m4, m5     ; t4  t7  (interleaved)
+    ITX_MUL2X_PACK        2, 1, 5, 6, 2896, 2896    ; t0 t1
+    ITX_MUL2X_PACK        0, 1, 5, 6, 2896, 2896, 1 ; t6 t5
+%if mmsize > 16
+    vbroadcasti32x4      m1, [o(deint_shuf)]
+    pshufb               m4, m1
+%else
+    pshufb               m4, [o(deint_shuf)]
+%endif
+    psubsw               m1, m2, m3 ; tmp3 tmp2
+    paddsw               m3, m2     ; tmp0 tmp1
+    punpckhqdq           m2, m4, m0 ; t7 t6
+    punpcklqdq           m4, m0     ; t4 t5
+    paddsw               m0, m3, m2 ; out0 out1
+    psubsw               m3, m2     ; out7 out6
+    psubsw               m2, m1, m4 ; out4 out5
+    paddsw               m1, m4     ; out3 out2
+%endmacro
+
+%macro IADST8_1D_PACKED 1 ; pass
+    vpbroadcastd         m6, [o(pd_2048)]
+%if %1 == 1
+    ITX_MUL2X_PACK        0, 4, 5, 6,  401, 4076, 3 ; t1a t0a
+    ITX_MUL2X_PACK        1, 4, 5, 6, 1931, 3612, 2 ; t2a t3a
+    ITX_MUL2X_PACK        2, 4, 5, 6, 3166, 2598, 3 ; t5a t4a
+    ITX_MUL2X_PACK        3, 4, 5, 6, 3920, 1189, 2 ; t6a t7a
+    psubsw               m4, m0, m2 ; t5 t4
+    paddsw               m0, m2     ; t1 t0
+    psubsw               m5, m1, m3 ; t6 t7
+    paddsw               m1, m3     ; t2 t3
+    ITX_MUL2X_PACK        4, 2, 3, 6, 1567, 3784, 3 ; t5a t4a
+    ITX_MUL2X_PACK        5, 2, 3, 6, 3784, 1567, 2 ; t7a t6a
+%if mmsize > 16
+    vbroadcasti32x4      m2, [o(deint_shuf)]
+%else
+    mova                 m2, [o(deint_shuf)]
+%endif
+    vprord               m1, 16
+    psubsw               m3, m0, m1 ; t3 t2
+    paddsw               m0, m1     ; -out7  out0
+    psubsw               m1, m4, m5 ; t7 t6
+    paddsw               m4, m5     ;  out6 -out1
+    pshufb               m0, m2
+    pshufb               m4, m2
+    mova                 m2, m6
+    vpdpwssd             m2, m3, [o(pw_m2896_2896)] {bcstd}
+    mova                 m5, m6
+    vpdpwssd             m5, m1, [o(pw_m2896_2896)] {bcstd}
+    psrad                m2, 12
+    psrad                m5, 12
+    packssdw             m2, m5     ; out4 -out5
+    mova                 m5, m6
+    vpdpwssd             m5, m3, [o(pw_2896_2896)] {bcstd}
+    mova                 m3, m6
+    vpdpwssd             m3, m1, [o(pw_2896_2896)] {bcstd}
+    psrad                m5, 12
+    psrad                m3, 12
+    packssdw             m1, m3, m5 ; out2 -out3
+%else
+    punpckhwd            m0, m4, m3 ; 0 7
+    punpckhwd            m1, m5, m2 ; 2 5
+    punpcklwd            m2, m5     ; 4 3
+    punpcklwd            m3, m4     ; 6 1
+    ITX_MUL2X_PACK        0, 4, 5, 6,  401, 4076 ; t0a t1a
+    ITX_MUL2X_PACK        1, 4, 5, 6, 1931, 3612 ; t2a t3a
+    ITX_MUL2X_PACK        2, 4, 5, 6, 3166, 2598 ; t4a t5a
+    ITX_MUL2X_PACK        3, 4, 5, 6, 3920, 1189 ; t6a t7a
+    psubsw               m4, m0, m2 ; t4 t5
+    paddsw               m0, m2     ; t0 t1
+    psubsw               m5, m1, m3 ; t6 t7
+    paddsw               m1, m3     ; t2 t3
+    shufps               m2, m5, m4, q1032
+    punpckhwd            m4, m2
+    punpcklwd            m5, m2
+    ITX_MUL2X_PACK        4, 2, 3, 6, 1567, 3784    ; t4a t5a
+    ITX_MUL2X_PACK        5, 2, 3, 6, 3784, 1567, 1 ; t6a t7a
+    psubsw               m2, m0, m1 ; t2 t3
+    paddsw               m0, m1     ; out0 -out7
+    psubsw               m1, m4, m5 ; t6 t7
+    paddsw               m4, m5     ; -out1 out6
+    vpbroadcastd         m5, [o(pw_2896x8)]
+    punpckhqdq           m3, m2, m1 ; t3 t7
+    punpcklqdq           m2, m1     ; t2 t6
+    paddsw               m1, m2, m3 ; t2+t3 t6+t7
+    psubsw               m2, m3     ; t2-t3 t6-t7
+    punpckhqdq           m3, m4, m0 ; out6 -out7
+    punpcklqdq           m0, m4     ; out0 -out1
+    pmulhrsw             m2, m5     ; out4 -out5
+    pshufd               m1, m1, q1032
+    pmulhrsw             m1, m5     ; out2 -out3
+%endif
+%endmacro
+
+INIT_YMM avx512icl
+INV_TXFM_4X8_FN dct, dct
+INV_TXFM_4X8_FN dct, identity
+INV_TXFM_4X8_FN dct, adst
+INV_TXFM_4X8_FN dct, flipadst
+
+cglobal idct_4x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q3120
+    vpermq               m1, [cq+32*1], q3120
+    vpbroadcastd         m2, [o(pw_2896x8)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    IDCT4_1D_PACKED
+    vbroadcasti32x4      m2, [o(deint_shuf)]
+    shufps               m3, m0, m1, q1331
+    shufps               m0, m0, m1, q0220
+    pshufb               m0, m2
+    pshufb               m1, m3, m2
+    jmp                tx2q
+.pass2:
+    vextracti32x4       xm2, m0, 1
+    vextracti32x4       xm3, m1, 1
+    call .main
+    vpbroadcastd         m4, [o(pw_2048)]
+    vinserti32x4         m0, m0, xm2, 1
+    vinserti32x4         m1, m1, xm3, 1
+    pshufd               m1, m1, q1032
+    jmp m(iadst_4x8_internal_8bpc).end2
+ALIGN function_align
+.main:
+    WRAP_XMM IDCT8_1D_PACKED
+    ret
+
+INV_TXFM_4X8_FN adst, dct
+INV_TXFM_4X8_FN adst, adst
+INV_TXFM_4X8_FN adst, flipadst
+INV_TXFM_4X8_FN adst, identity
+
+cglobal iadst_4x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q3120
+    vpermq               m1, [cq+32*1], q3120
+    vpbroadcastd         m2, [o(pw_2896x8)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    call m(iadst_8x4_internal_8bpc).main
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    jmp                tx2q
+.pass2:
+    vextracti32x4       xm2, m0, 1
+    vextracti32x4       xm3, m1, 1
+    pshufd              xm4, xm0, q1032
+    pshufd              xm5, xm1, q1032
+    call .main_pass2
+    vpbroadcastd         m4, [o(pw_2048)]
+    vinserti32x4         m0, xm2, 1
+    vinserti32x4         m1, xm3, 1
+    pxor                 m5, m5
+    psubw                m5, m4
+.end:
+    punpcklqdq           m4, m5
+.end2:
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+.end3:
+    vpbroadcastd         m3, strided
+    pmulld               m5, m3, [o(pd_0to15)]
+    kxnorb               k1, k1, k1
+    kmovb                k2, k1
+    vpgatherdd       m3{k1}, [dstq+m5]
+    pxor                 m4, m4
+    mova               [cq], zmm20
+    punpcklbw            m2, m3, m4
+    punpckhbw            m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    packuswb             m0, m1
+    vpscatterdd [dstq+m5]{k2}, m0
+    RET
+ALIGN function_align
+.main_pass1:
+    punpckhwd           xm0, xm4, xm3 ; 0 7
+    punpckhwd           xm1, xm5, xm2 ; 2 5
+    punpcklwd           xm2, xm5      ; 4 3
+    punpcklwd           xm3, xm4      ; 6 1
+    WRAP_XMM IADST8_1D_PACKED 1
+    punpcklqdq          xm3, xm4, xm0 ; out6 -out7
+    punpckhqdq          xm0, xm4      ; out0 -out1
+    ret
+ALIGN function_align
+.main_pass2:
+    WRAP_XMM IADST8_1D_PACKED 2
+    ret
+
+INV_TXFM_4X8_FN flipadst, dct
+INV_TXFM_4X8_FN flipadst, adst
+INV_TXFM_4X8_FN flipadst, flipadst
+INV_TXFM_4X8_FN flipadst, identity
+
+cglobal iflipadst_4x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q3120
+    vpermq               m1, [cq+32*1], q3120
+    vpbroadcastd         m2, [o(pw_2896x8)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    call m(iadst_8x4_internal_8bpc).main
+    punpcklwd            m3, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m1, m3
+    punpckhwd            m1, m3
+    jmp                tx2q
+.pass2:
+    vextracti32x4       xm2, m0, 1
+    vextracti32x4       xm3, m1, 1
+    pshufd              xm4, xm0, q1032
+    pshufd              xm5, xm1, q1032
+    call m(iadst_4x8_internal_8bpc).main_pass2
+    vpbroadcastd         m5, [o(pw_2048)]
+    vinserti32x4         m3, xm1, 1
+    vinserti32x4         m2, xm0, 1
+    pxor                 m4, m4
+    psubw                m4, m5
+    pshufd               m0, m3, q1032
+    pshufd               m1, m2, q1032
+    jmp m(iadst_4x8_internal_8bpc).end
+
+INIT_ZMM avx512icl
+INV_TXFM_4X8_FN identity, dct
+INV_TXFM_4X8_FN identity, adst
+INV_TXFM_4X8_FN identity, flipadst
+INV_TXFM_4X8_FN identity, identity
+
+cglobal iidentity_4x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpbroadcastd         m0, [o(pw_2896x8)]
+    pmulhrsw             m0, [cq]
+    mova                 m1, [o(int8_permB)]
+    vpbroadcastd         m2, [o(pw_1697x8)]
+    vpermb               m0, m1, m0
+    pmulhrsw             m2, m0
+    paddsw               m0, m2
+    vextracti32x8       ym1, m0, 1
+    jmp                tx2q
+.pass2:
+    vpbroadcastd        ym4, [o(pw_4096)]
+    jmp m(iadst_4x8_internal_8bpc).end2
+
+%macro INV_TXFM_4X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x16
+%ifidn %1_%2, dct_dct
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    imul                r6d, 181
+    add                 r6d, 128+256
+    sar                 r6d, 8+1
+    imul                r6d, 181
+    add                 r6d, 128+2048
+    sar                 r6d, 8+4
+    vpbroadcastw         m0, r6d
+    mova                 m1, m0
+    jmp m(iadst_4x16_internal_8bpc).end3
+%endif
+%endmacro
+
+%macro IDCT16_1D_PACKED 0
+    punpckhwd            m8, m7, m0 ; dct16 in15 in1
+    punpcklwd            m9, m4, m0 ; dct4  in2  in0
+    punpckhwd            m0, m3, m4 ; dct16 in7  in9
+    punpcklwd            m7, m1     ; dct8  in7  in1
+    punpckhwd            m1, m6     ; dct16 in3  in13
+    punpcklwd            m3, m5     ; dct8  in3  in5
+    punpckhwd            m5, m2     ; dct16 in11 in5
+    punpcklwd            m6, m2     ; dct4  in3  in1
+cglobal_label .main2
+    vpbroadcastd        m10, [o(pd_2048)]
+.main3:
+    vpbroadcastq        m13, [o(int_mshift)]
+    vpcmpub              k7, m13, m10, 6 ; 0x33...
+    ITX_MUL2X_PACK        8, 2, 4, 10,  401, 4076, 5 ; t8a  t15a
+    ITX_MUL2X_PACK        0, 2, 4, 10, 3166, 2598, 5 ; t9a  t14a
+    ITX_MUL2X_PACK        5, 2, 4, 10, 1931, 3612, 5 ; t10a t13a
+    ITX_MUL2X_PACK        1, 2, 4, 10, 3920, 1189, 5 ; t11a t12a
+    ITX_MUL2X_PACK        7, 2, 4, 10,  799, 4017, 5 ; t4a  t7a
+    ITX_MUL2X_PACK        3, 2, 4, 10, 3406, 2276, 5 ; t5a  t6a
+.main4:
+    psubsw               m2, m8, m0 ; t9  t14
+    paddsw               m8, m0     ; t8  t15
+    psubsw               m4, m1, m5 ; t10 t13
+    paddsw               m1, m5     ; t11 t12
+    ITX_MUL2X_PACK        6, 0, 5, 10, 1567,  3784    ; t3   t2
+    psubsw               m0, m8, m1 ; t11a t12a
+    paddsw               m8, m1     ; t8a  t15a
+    psubsw               m1, m7, m3 ; t5a  t6a
+    paddsw               m7, m3     ; t4   t7
+.main5:
+    ITX_MUL2X_PACK        2, 3, 5, 10, 1567,  3784, 5 ; t9a  t14a
+    ITX_MUL2X_PACK        4, 3, 5, 10, m3784, 1567, 5 ; t10a t13a
+%if mmsize > 16
+    vbroadcasti32x4      m5, [o(deint_shuf)]
+%else
+    mova                 m5, [o(deint_shuf)]
+%endif
+    vpbroadcastd        m11, [o(pw_m2896_2896)]
+    vpbroadcastd        m12, [o(pw_2896_2896)]
+    paddsw               m3, m2, m4 ; t9   t14
+    psubsw               m2, m4     ; t10  t13
+    pshufb               m8, m5
+    pshufb               m7, m5
+    pshufb               m3, m5
+    ITX_MUL2X_PACK        9, 4,  5, 10, 11, 12    ; t0   t1
+    ITX_MUL2X_PACK        1, 4,  5, 10, 12, 11    ; t5   t6
+    ITX_MUL2X_PACK        0, 4,  5, 10, 11, 12, 8 ; t11  t12
+    ITX_MUL2X_PACK        2, 0, 11, 10, 11, 12, 8 ; t10a t13a
+    punpckhqdq           m2, m7, m1 ; t7 t6
+    punpcklqdq           m7, m1     ; t4 t5
+    psubsw               m1, m9, m6 ; dct4 out3 out2
+    paddsw               m9, m6     ; dct4 out0 out1
+    packssdw             m5, m11    ; t12  t13a
+    packssdw             m4, m0     ; t11  t10a
+    punpckhqdq           m0, m8, m3 ; t15a t14
+    punpcklqdq           m8, m3     ; t8a  t9
+    psubsw               m3, m9, m2 ; dct8 out7 out6
+    paddsw               m9, m2     ; dct8 out0 out1
+    psubsw               m2, m1, m7 ; dct8 out4 out5
+    paddsw               m1, m7     ; dct8 out3 out2
+    psubsw               m7, m9, m0 ; out15 out14
+    paddsw               m0, m9     ; out0  out1
+    psubsw               m6, m1, m5 ; out12 out13
+    paddsw               m1, m5     ; out3  out2
+    psubsw               m5, m2, m4 ; out11 out10
+    paddsw               m2, m4     ; out4  out5
+    psubsw               m4, m3, m8 ; out8  out9
+    paddsw               m3, m8     ; out7  out6
+%endmacro
+
+INV_TXFM_4X16_FN dct, dct
+INV_TXFM_4X16_FN dct, identity
+INV_TXFM_4X16_FN dct, adst
+INV_TXFM_4X16_FN dct, flipadst
+
+cglobal idct_4x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                ym1, [cq+32*2]
+    vinserti32x8         m1, [cq+32*0], 1
+    mova                 m0, [o(int16_perm)]
+    mova                ym2, [cq+32*3]
+    vinserti32x8         m2, [cq+32*1], 1
+    vpbroadcastd         m4, [o(pd_2048)]
+    vpermb               m1, m0, m1 ; c0 a0 c1 a1 c2 a2 c3 a3
+    vpermb               m2, m0, m2 ; d0 b0 d1 b1 d2 b2 d3 b3
+    ITX_MUL2X_PACK        1, 0, 3, 4, 2896, 2896, 2
+    ITX_MUL2X_PACK        2, 0, 3, 4, 1567, 3784, 2
+    vpbroadcastd         m4, [o(pw_16384)]
+    psubsw               m3, m1, m2
+    paddsw               m1, m2     ; out0 out1
+    vprord               m3, 16     ; out2 out3
+    punpckldq            m0, m1, m3
+    punpckhdq            m1, m3
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    jmp                tx2q
+.pass2:
+    vextracti32x4       xm2, ym0, 1
+    vextracti32x4       xm3, ym1, 1
+    vextracti32x4       xm4, m0, 2
+    vextracti32x4       xm5, m1, 2
+    vextracti32x4       xm6, m0, 3
+    vextracti32x4       xm7, m1, 3
+    call .main
+    vinserti32x4        ym0, xm2, 1
+    vinserti32x4        ym1, xm3, 1
+    vinserti32x4        ym4, xm6, 1
+    vinserti32x4        ym5, xm7, 1
+    vinserti32x8         m0, ym4, 1
+    vinserti32x8         m1, ym5, 1
+    vpbroadcastd         m5, [o(pw_2048)]
+    pshufd               m1, m1, q1032
+    jmp m(iadst_4x16_internal_8bpc).end2
+ALIGN function_align
+.main:
+    WRAP_XMM IDCT16_1D_PACKED
+    ret
+
+INV_TXFM_4X16_FN adst, dct
+INV_TXFM_4X16_FN adst, adst
+INV_TXFM_4X16_FN adst, flipadst
+INV_TXFM_4X16_FN adst, identity
+
+cglobal iadst_4x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m1, [o(permB)]
+    vpermq               m0, m1, [cq+64*0]
+    vpermq               m1, m1, [cq+64*1]
+    call m(iadst_16x4_internal_8bpc).main
+    vpbroadcastd         m3, [o(pw_16384)]
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    pmulhrsw             m2, m3
+    pmulhrsw             m0, m3
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    jmp                tx2q
+.pass2:
+    call .main
+    vpbroadcastd         m5, [o(pw_2048)]
+    psrlq               m10, 4
+    psubw                m6, m8, m5
+.end:
+    vpbroadcastd         m7, [o(pw_2896x8)]
+    paddsw              ym1, ym2, ym4
+    psubsw              ym2, ym4
+    vinserti32x8         m1, ym2, 1
+    pmulhrsw             m1, m7      ; -out7   out4   out6  -out5   out8  -out11 -out9   out10
+    psrlq                m0, m10, 4
+    vpermi2q             m0, m1, m3  ; 0 1   4 5   8 9   c d
+    vpermt2q             m1, m10, m3 ; 2 3   6 7   a b   e f
+    punpcklqdq           m5, m6
+.end2:
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+.end3:
+    vpbroadcastd         m3, strided
+    pmulld               m5, m3, [o(pd_0to15)]
+    kxnorw               k1, k1, k1
+    kmovw                k2, k1
+    vpgatherdd       m3{k1}, [dstq+m5]
+    pxor                 m4, m4
+    mova          [cq+64*0], m4
+    mova          [cq+64*1], m4
+    punpcklbw            m2, m3, m4
+    punpckhbw            m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    packuswb             m0, m1
+    vpscatterdd [dstq+m5]{k2}, m0
+    RET
+ALIGN function_align
+.main:
+    movu                 m3, [o(permB+1)]
+    psrlq               m10, m3, 4
+.main2:
+    vpermi2q             m3, m0, m1  ; in15 in12 in13 in14 in11 in8  in9  in10
+    vpermt2q             m0, m10, m1 ; in0  in3  in2  in1  in4  in7  in6  in5
+    vpbroadcastd         m9, [o(pd_2048)]
+    vpbroadcastq       ym13, [o(int_mshift)]
+    kxnorb               k1, k1, k1
+    punpckhwd            m4, m3, m0  ; in12 in3  in14 in1
+    punpcklwd            m0, m3      ; in0  in15 in2  in13
+    kshiftrb             k1, k1, 4
+    vextracti32x8       ym3, m4, 1   ; in8  in7  in10 in5
+    vextracti32x8       ym1, m0, 1   ; in4  in11 in6  in9
+INIT_YMM avx512icl
+    vpcmpub              k7, m13, m9, 6 ; 0x33...
+    pxor                 m8, m8
+    ITX_MUL4X_PACK        0, 2, 5, 6, 7, 9,  201, 4091,  995, 3973, 5
+    ITX_MUL4X_PACK        1, 2, 5, 6, 7, 9, 1751, 3703, 2440, 3290, 5
+    ITX_MUL4X_PACK        3, 2, 5, 6, 7, 9, 3035, 2751, 3513, 2106, 5
+    ITX_MUL4X_PACK        4, 2, 5, 6, 7, 9, 3857, 1380, 4052,  601, 5
+    psubsw               m2, m0, m3 ; t9a  t8a  t11a t10a
+    paddsw               m0, m3     ; t1a  t0a  t3a  t2a
+    psubsw               m3, m1, m4 ; t13a t12a t15a t14a
+    paddsw               m4, m1     ; t5a  t4a  t7a  t6a
+    ITX_MUL4X_PACK        2, 1, 5, 6, 7, 9,  799, 4017, 3406, 2276, 5
+    psubw                m7, m8, m7
+    ITX_MUL2X_PACK        3, 1, 5, 9, 7, 6, 4
+    vpbroadcastd         m6, [o(pw_3784_m1567)]
+    vpbroadcastd     m6{k1}, [o(pw_m3784_1567)]
+    psubsw               m1, m0, m4 ; t5   t4   t7   t6
+    paddsw               m0, m4     ; t1   t0   t3   t2
+    psubsw               m4, m2, m3 ; t13a t12a t15a t14a
+    paddsw               m2, m3     ; t9a  t8a  t11a t10a
+    ITX_MUL2X_PACK        1, 3, 5, 9, 1567_3784, 6, 16 ; t4a t5a t7a t6a
+    ITX_MUL2X_PACK        4, 3, 5, 9, 1567_3784, 6, 16 ; t12 t13 t15 t14
+    vbroadcasti32x4      m5, [o(deint_shuf)]
+    pshufb               m0, m5
+    pshufb               m2, m5
+    vshufi32x4           m3, m0, m2, 0x03  ; t3   t2   t11a t10a
+    vinserti32x4         m0, xm2, 1        ; t1   t0   t9a  t8a
+    vshufi32x4           m2, m1, m4, 0x03  ; t7a  t6a  t15  t14
+    vinserti32x4         m1, xm4, 1        ; t4a  t5a  t12  t13
+    pshufd               m2, m2, q1032     ; t6a  t7a  t14  t15
+    psubsw               m4, m0, m3        ; t3a t2a t11 t10
+    paddsw               m0, m3            ; -out15  out0   out14 -out1
+    paddsw               m3, m1, m2        ;  out12 -out3  -out13  out2
+    psubsw               m1, m2            ; t7 t6 t15a t14a
+    punpckhqdq           m2, m4, m1        ; t2a t6  t10 t14a
+    punpcklqdq           m4, m1            ; t3a t7  t11 t15a
+INIT_ZMM avx512icl
+    vinserti32x8         m3, ym0, 1        ; out12 -out3  -out13  out2  -out15  out0   out14 -out1
+    ret
+
+INV_TXFM_4X16_FN flipadst, dct
+INV_TXFM_4X16_FN flipadst, adst
+INV_TXFM_4X16_FN flipadst, flipadst
+INV_TXFM_4X16_FN flipadst, identity
+
+cglobal iflipadst_4x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m1, [o(permB)]
+    vpermq               m0, m1, [cq+64*0]
+    vpermq               m1, m1, [cq+64*1]
+    call m(iadst_16x4_internal_8bpc).main
+    vpbroadcastd         m3, [o(pw_16384)]
+    punpcklwd            m2, m1, m0
+    punpckhwd            m1, m0
+    pmulhrsw             m2, m3
+    pmulhrsw             m1, m3
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    jmp                tx2q
+.pass2:
+    call m(iadst_4x16_internal_8bpc).main
+    vpbroadcastd         m6, [o(pw_2048)]
+    psrlq               m10, 12
+    psubw                m5, m8, m6
+    jmp m(iadst_4x16_internal_8bpc).end
+
+INV_TXFM_4X16_FN identity, dct
+INV_TXFM_4X16_FN identity, adst
+INV_TXFM_4X16_FN identity, flipadst
+INV_TXFM_4X16_FN identity, identity
+
+cglobal iidentity_4x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m2, [o(int16_perm)]
+    vpermb               m1, m2, [cq+64*0]
+    vpermb               m2, m2, [cq+64*1]
+    vpbroadcastd         m4, [o(pw_1697x8)]
+    vpbroadcastd         m0, [o(pd_m1)]
+    pmulhrsw             m3, m4, m1    ; we want to do a signed avg, but pavgw is
+    vpcmpw               k1, m1, m0, 4 ; unsigned. as long as both signs are equal
+    pmulhrsw             m4, m2        ; it still works, but if the input is -1 the
+    vpcmpw               k2, m2, m0, 4 ; pmulhrsw result will become 0 which causes
+    vpavgw        m1{k1}{z}, m3        ; pavgw to output -32768 instead of 0 unless
+    vpavgw        m2{k2}{z}, m4        ; we explicitly deal with that case here.
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m3, [o(pw_1697x16)]
+    vpbroadcastd         m5, [o(pw_2048)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m0
+    paddsw               m1, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    jmp m(iadst_4x16_internal_8bpc).end2
+
+%macro WRITE_8X4 4-7 strideq*1, strideq*2, r6 ; coefs[1-2], tmp[1-2], off[1-3]
+    movq               xm%3, [dstq   ]
+    movhps             xm%3, [dstq+%5]
+    movq               xm%4, [dstq+%6]
+    movhps             xm%4, [dstq+%7]
+    pmovzxbw            m%3, xm%3
+    pmovzxbw            m%4, xm%4
+%ifnum %1
+    paddw               m%3, m%1
+%else
+    paddw               m%3, %1
+%endif
+%ifnum %2
+    paddw               m%4, m%2
+%else
+    paddw               m%4, %2
+%endif
+    packuswb            m%3, m%4
+    vextracti32x4      xm%4, m%3, 1
+    movq          [dstq   ], xm%3
+    movhps        [dstq+%6], xm%3
+    movq          [dstq+%5], xm%4
+    movhps        [dstq+%7], xm%4
+%endmacro
+
+%macro INV_TXFM_8X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x4
+%ifidn %1_%2, dct_dct
+    movd                xm1, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm1, [cq]
+    movd                xm2, [o(pw_2048)]
+    pmulhrsw            xm0, xm1
+    pmulhrsw            xm0, xm1
+    pmulhrsw            xm0, xm2
+    vpbroadcastw         m0, xm0
+    mova                 m1, m0
+    jmp m(iadst_8x4_internal_8bpc).end3
+%endif
+%endmacro
+
+INIT_YMM avx512icl
+INV_TXFM_8X4_FN dct, dct
+INV_TXFM_8X4_FN dct, adst
+INV_TXFM_8X4_FN dct, flipadst
+INV_TXFM_8X4_FN dct, identity
+
+cglobal idct_8x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpbroadcastd        xm3, [o(pw_2896x8)]
+    pmulhrsw            xm0, xm3, [cq+16*0]
+    pmulhrsw            xm1, xm3, [cq+16*1]
+    pmulhrsw            xm2, xm3, [cq+16*2]
+    pmulhrsw            xm3,      [cq+16*3]
+    call m(idct_4x8_internal_8bpc).main
+    vbroadcasti32x4      m4, [o(deint_shuf)]
+    vinserti32x4         m3, m1, xm3, 1
+    vinserti32x4         m1, m0, xm2, 1
+    shufps               m0, m1, m3, q0220
+    shufps               m1, m3, q1331
+    pshufb               m0, m4
+    pshufb               m1, m4
+    jmp                tx2q
+.pass2:
+    IDCT4_1D_PACKED
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    jmp m(iadst_8x4_internal_8bpc).end2
+
+INV_TXFM_8X4_FN adst, dct
+INV_TXFM_8X4_FN adst, adst
+INV_TXFM_8X4_FN adst, flipadst
+INV_TXFM_8X4_FN adst, identity
+
+cglobal iadst_8x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpbroadcastd        xm0, [o(pw_2896x8)]
+    pshufd              xm4,      [cq+16*0], q1032
+    pmulhrsw            xm3, xm0, [cq+16*3]
+    pshufd              xm5,      [cq+16*1], q1032
+    pmulhrsw            xm2, xm0, [cq+16*2]
+    pmulhrsw            xm4, xm0
+    pmulhrsw            xm5, xm0
+    call m(iadst_4x8_internal_8bpc).main_pass1
+    vinserti32x4         m0, xm2, 1
+    vinserti32x4         m1, xm3, 1
+    pxor                 m3, m3
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    psubsw               m3, m2
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    jmp                tx2q
+.pass2:
+    call .main
+.end:
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q3120
+.end2:
+    vpbroadcastd         m2, [o(pw_2048)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+.end3:
+    pxor                 m2, m2
+    mova               [cq], zmm18
+    lea                  r6, [strideq*3]
+    WRITE_8X4             0, 1, 4, 5
+    RET
+ALIGN function_align
+.main:
+    IADST4_1D_PACKED
+    ret
+
+INV_TXFM_8X4_FN flipadst, dct
+INV_TXFM_8X4_FN flipadst, adst
+INV_TXFM_8X4_FN flipadst, flipadst
+INV_TXFM_8X4_FN flipadst, identity
+
+cglobal iflipadst_8x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpbroadcastd        xm0, [o(pw_2896x8)]
+    pshufd              xm4,      [cq+16*0], q1032
+    pmulhrsw            xm3, xm0, [cq+16*3]
+    pshufd              xm5,      [cq+16*1], q1032
+    pmulhrsw            xm2, xm0, [cq+16*2]
+    pmulhrsw            xm4, xm0
+    pmulhrsw            xm5, xm0
+    call m(iadst_4x8_internal_8bpc).main_pass1
+    vinserti32x4         m3, m3, xm1, 1
+    vinserti32x4         m2, m2, xm0, 1
+    punpckhwd            m1, m3, m2
+    punpcklwd            m3, m2
+    pxor                 m0, m0
+    psubsw               m0, m1
+    punpckhwd            m1, m0, m3
+    punpcklwd            m0, m3
+    jmp                tx2q
+.pass2:
+    call m(iadst_8x4_internal_8bpc).main
+    mova                 m2, m1
+    vpermq               m1, m0, q2031
+    vpermq               m0, m2, q2031
+    jmp m(iadst_8x4_internal_8bpc).end2
+
+INV_TXFM_8X4_FN identity, dct
+INV_TXFM_8X4_FN identity, adst
+INV_TXFM_8X4_FN identity, flipadst
+INV_TXFM_8X4_FN identity, identity
+
+cglobal iidentity_8x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                xm2, [cq+16*0]
+    mova                xm0, [cq+16*1]
+    vinserti32x4         m2, [cq+16*2], 1
+    vinserti32x4         m0, [cq+16*3], 1
+    vpbroadcastd         m3, [o(pw_2896x8)]
+    punpcklwd            m1, m2, m0
+    punpckhwd            m2, m0
+    pmulhrsw             m1, m3
+    pmulhrsw             m2, m3
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    paddsw               m0, m0
+    paddsw               m1, m1
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    jmp m(iadst_8x4_internal_8bpc).end
+
+%macro INV_TXFM_8X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x8
+%ifidn %1_%2, dct_dct
+INIT_ZMM avx512icl
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+.dconly:
+    imul                r6d, 181
+    add                 r6d, 128+256
+    sar                 r6d, 8+1
+.dconly2:
+    vpbroadcastd        ym2, strided
+    imul                r6d, 181
+    pmulld              ym5, ym2, [o(pd_0to15)]
+    kxnorb               k1, k1, k1
+    add                 r6d, 128+2048
+    sar                 r6d, 8+4
+    pxor                 m3, m3
+    vpbroadcastw         m4, r6d
+.dconly_loop:
+    kmovb                k2, k1
+    vpgatherdq       m2{k1}, [dstq+ym5]
+    punpcklbw            m0, m2, m3
+    punpckhbw            m1, m2, m3
+    paddw                m0, m4
+    paddw                m1, m4
+    packuswb             m0, m1
+    kmovb                k1, k2
+    vpscatterdq [dstq+ym5]{k2}, m0
+    lea                dstq, [dstq+strideq*8]
+    sub                 r3d, 8
+    jg .dconly_loop
+    RET
+INIT_YMM avx512icl
+%endif
+%endmacro
+
+INV_TXFM_8X8_FN dct, dct
+INV_TXFM_8X8_FN dct, identity
+INV_TXFM_8X8_FN dct, adst
+INV_TXFM_8X8_FN dct, flipadst
+
+cglobal idct_8x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpermq               m0, [cq+32*0], q3120 ; 0 1
+    vpermq               m3, [cq+32*3], q3120 ; 6 7
+    vpermq               m2, [cq+32*2], q3120 ; 4 5
+    vpermq               m1, [cq+32*1], q3120 ; 2 3
+    call .main
+    shufps               m4, m0, m1, q0220
+    shufps               m5, m0, m1, q1331
+    shufps               m1, m2, m3, q0220
+    shufps               m3, m2, m3, q1331
+    vbroadcasti32x4      m0, [o(deint_shuf)]
+    vpbroadcastd         m2, [o(pw_16384)]
+    REPX   {pshufb   x, m0}, m4, m5, m1, m3
+    REPX   {pmulhrsw x, m2}, m4, m5, m1, m3
+    vinserti32x4         m0, m4, xm1, 1
+    vshufi32x4           m2, m4, m1, 0x03
+    vinserti32x4         m1, m5, xm3, 1
+    vshufi32x4           m3, m5, m3, 0x03
+    jmp                tx2q
+.pass2:
+    call .main
+    vpbroadcastd         m4, [o(pw_2048)]
+    vpermq               m0, m0, q3120
+    vpermq               m1, m1, q2031
+    vpermq               m2, m2, q3120
+    vpermq               m3, m3, q2031
+    jmp m(iadst_8x8_internal_8bpc).end2
+ALIGN function_align
+cglobal_label .main
+    IDCT8_1D_PACKED
+    ret
+
+INV_TXFM_8X8_FN adst, dct
+INV_TXFM_8X8_FN adst, adst
+INV_TXFM_8X8_FN adst, flipadst
+INV_TXFM_8X8_FN adst, identity
+
+cglobal iadst_8x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpermq               m4, [cq+32*0], q1302 ; 1 0
+    vpermq               m3, [cq+32*3], q3120 ; 6 7
+    vpermq               m5, [cq+32*1], q1302 ; 3 2
+    vpermq               m2, [cq+32*2], q3120 ; 4 5
+    call .main_pass1
+    vpbroadcastd         m5, [o(pw_16384_m16384)]
+    punpcklwd            m4, m0, m1
+    punpckhwd            m0, m1
+    punpcklwd            m1, m2, m3
+    punpckhwd            m2, m3
+    punpcklwd            m3, m4, m0
+    punpckhwd            m4, m0
+    punpcklwd            m0, m1, m2
+    punpckhwd            m1, m2
+    REPX   {pmulhrsw x, m5}, m3, m4, m0, m1
+    vshufi32x4           m2, m3, m0, 0x03
+    vinserti32x4         m0, m3, xm0, 1
+    vshufi32x4           m3, m4, m1, 0x03
+    vinserti32x4         m1, m4, xm1, 1
+    jmp                tx2q
+.pass2:
+    pshufd               m4, m0, q1032
+    pshufd               m5, m1, q1032
+    call .main_pass2
+    vpbroadcastd         m5, [o(pw_2048)]
+    vpbroadcastd        xm4, [o(pw_4096)]
+    psubw                m4, m5 ; lower half = 2048, upper half = -2048
+.end:
+    REPX {vpermq x, x, q3120}, m0, m1, m2, m3
+.end2:
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+.end3:
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+.end4:
+    pxor                 m4, m4
+    mova          [cq+32*0], m4
+    mova          [cq+32*1], m4
+    mova          [cq+32*2], m4
+    mova          [cq+32*3], m4
+    lea                  r6, [strideq*3]
+    WRITE_8X4             0, 1, 4, 5
+    lea                dstq, [dstq+strideq*4]
+    WRITE_8X4             2, 3, 4, 5
+    RET
+ALIGN function_align
+.main_pass1:
+    punpckhwd            m0, m4, m3 ; 0 7
+    punpckhwd            m1, m5, m2 ; 2 5
+    punpcklwd            m2, m5     ; 4 3
+    punpcklwd            m3, m4     ; 6 1
+    IADST8_1D_PACKED 1
+    punpcklqdq           m3, m4, m0        ; out6 -out7
+    punpckhqdq           m0, m4            ; out0 -out1
+    ret
+ALIGN function_align
+cglobal_label .main_pass2
+    IADST8_1D_PACKED 2
+    ret
+
+INV_TXFM_8X8_FN flipadst, dct
+INV_TXFM_8X8_FN flipadst, adst
+INV_TXFM_8X8_FN flipadst, flipadst
+INV_TXFM_8X8_FN flipadst, identity
+
+cglobal iflipadst_8x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpermq               m4, [cq+32*0], q1302 ; 1 0
+    vpermq               m3, [cq+32*3], q3120 ; 6 7
+    vpermq               m5, [cq+32*1], q1302 ; 3 2
+    vpermq               m2, [cq+32*2], q3120 ; 4 5
+    call m(iadst_8x8_internal_8bpc).main_pass1
+    vpbroadcastd         m5, [o(pw_m16384_16384)]
+    punpckhwd            m4, m3, m2
+    punpcklwd            m3, m2
+    punpckhwd            m2, m1, m0
+    punpcklwd            m1, m0
+    punpckhwd            m0, m4, m3
+    punpcklwd            m4, m3
+    punpckhwd            m3, m2, m1
+    punpcklwd            m2, m1
+    REPX   {pmulhrsw x, m5}, m0, m4, m3, m2
+    vinserti32x4         m1, m0, xm3, 1
+    vshufi32x4           m3, m0, m3, 0x03
+    vinserti32x4         m0, m4, xm2, 1
+    vshufi32x4           m2, m4, m2, 0x03
+    jmp                tx2q
+.pass2:
+    pshufd               m4, m0, q1032
+    pshufd               m5, m1, q1032
+    call m(iadst_8x8_internal_8bpc).main_pass2
+    vpbroadcastd         m4, [o(pw_2048)]
+    vpbroadcastd        xm5, [o(pw_4096)]
+    psubw                m4, m5 ; lower half = -2048, upper half = 2048
+    vpermq               m5, m3, q2031
+    vpermq               m3, m0, q2031
+    vpermq               m0, m2, q2031
+    vpermq               m2, m1, q2031
+    pmulhrsw             m1, m0, m4
+    pmulhrsw             m0, m5, m4
+    jmp m(iadst_8x8_internal_8bpc).end3
+
+INV_TXFM_8X8_FN identity, dct
+INV_TXFM_8X8_FN identity, adst
+INV_TXFM_8X8_FN identity, flipadst
+INV_TXFM_8X8_FN identity, identity
+
+cglobal iidentity_8x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                xm3, [cq+16*0]
+    mova                xm2, [cq+16*1]
+    vinserti32x4         m3, [cq+16*4], 1
+    vinserti32x4         m2, [cq+16*5], 1
+    mova                xm4, [cq+16*2]
+    mova                xm0, [cq+16*3]
+    vinserti32x4         m4, [cq+16*6], 1
+    vinserti32x4         m0, [cq+16*7], 1
+    punpcklwd            m1, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m4, m0
+    punpckhwd            m4, m0
+    punpckldq            m0, m1, m2
+    punpckhdq            m1, m2
+    punpckldq            m2, m3, m4
+    punpckhdq            m3, m4
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m4, [o(pw_4096)]
+    jmp m(iadst_8x8_internal_8bpc).end
+
+%macro INV_TXFM_8X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x16
+%ifidn %1_%2, dct_dct
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 16
+    imul                r6d, 181
+    add                 r6d, 128
+    sar                 r6d, 8
+    jmp m(inv_txfm_add_dct_dct_8x8_8bpc).dconly
+%endif
+%endmacro
+
+%macro ITX_8X16_LOAD_COEFS 0
+    vpbroadcastd         m4, [o(pw_2896x8)]
+    pmulhrsw             m0, m4, [cq+32*0]
+    add                  cq, 32*4
+    pmulhrsw             m7, m4, [cq+32*3]
+    pmulhrsw             m1, m4, [cq-32*3]
+    pmulhrsw             m6, m4, [cq+32*2]
+    pmulhrsw             m2, m4, [cq-32*2]
+    pmulhrsw             m5, m4, [cq+32*1]
+    pmulhrsw             m3, m4, [cq-32*1]
+    pmulhrsw             m4,     [cq+32*0]
+%endmacro
+
+INIT_ZMM avx512icl
+INV_TXFM_8X16_FN dct, dct
+INV_TXFM_8X16_FN dct, identity
+INV_TXFM_8X16_FN dct, adst
+INV_TXFM_8X16_FN dct, flipadst
+
+cglobal idct_8x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m3, [o(permB)]
+    vpermq               m0, m3, [cq+64*0]
+    vpbroadcastd         m4, [o(pw_2896x8)]
+    vpermq               m1, m3, [cq+64*1]
+    vpermq               m2, m3, [cq+64*2]
+    vpermq               m3, m3, [cq+64*3]
+    REPX   {pmulhrsw x, m4}, m0, m1, m2, m3
+    call m(idct_16x8_internal_8bpc).main
+    vpbroadcastd         m5, [o(pw_16384)]
+    punpckhwd            m4, m0, m2 ; b0 f0 b1 f1 b2 f2 b3 f3
+    punpcklwd            m0, m2     ; a0 e0 a1 e1 a2 e2 a3 e3
+    punpckhwd            m2, m1, m3 ; c0 g0 c1 g1 c2 g2 c3 g3
+    punpcklwd            m1, m3     ; d0 h0 d1 h1 d2 h2 d3 h3
+    REPX   {pmulhrsw x, m5}, m4, m0, m2, m1
+    punpckhwd            m3, m0, m4 ; a2 b2 e2 f2 a3 b3 e3 f3
+    punpcklwd            m0, m4     ; a0 b0 e0 f0 a1 b1 e1 f1
+    punpckhwd            m4, m2, m1 ; c2 d2 g2 h2 c3 d3 g3 h3
+    punpcklwd            m2, m1     ; c0 d0 g0 h0 c1 d1 g1 h1
+    punpckhdq            m1, m0, m2 ;  1  5  9 13
+    punpckldq            m0, m2     ;  0  4  8 12
+    punpckldq            m2, m3, m4 ;  2  6 10 14
+    punpckhdq            m3, m4     ;  3  7 11 15
+    jmp                tx2q
+.pass2:
+    vprord               m5, [o(int16_perm)], 16
+    vshufi32x4           m2, m2, q1320     ;  2 10 14  6
+    vshufi32x4           m4, m1, m3, q2310 ;  1  5 15 11
+    vshufi32x4           m1, m3, q0132     ;  9 13  7  3
+    vpermb               m9, m5, m0
+    vpermb               m7, m5, m2
+    vpermb               m8, m5, m4
+    vpermb               m0, m5, m1
+    vextracti32x8       ym6, m9, 1
+    vextracti32x8       ym3, m7, 1
+    vextracti32x8       ym5, m8, 1
+    vextracti32x8       ym1, m0, 1
+    call .main2
+    mova                ym8, [o(gather8a)]
+    lea                  r3, [dstq+strideq*4]
+    pmovzxdq             m9, ym8
+    pshufd              ym8, ym8, q1230
+    vpermt2q             m0, m9, m4
+    vpermt2q             m1, m9, m5
+    vpermt2q             m2, m9, m6
+    vpermt2q             m3, m9, m7
+.end:
+    vpbroadcastd         m7, [o(pw_2048)]
+.end2:
+    pmulhrsw             m0, m7
+    pmulhrsw             m1, m7
+.end3:
+    pmulhrsw             m2, m7
+    pmulhrsw             m3, m7
+.end4:
+    vpbroadcastd        ym6, strided
+    kxnorb               k1, k1, k1
+    pxor                 m4, m4
+    pmulld              ym8, ym6
+    kmovb                k2, k1
+    vpgatherdq       m6{k1}, [dstq+ym8]
+    kmovb                k1, k2
+    vpgatherdq       m7{k2}, [r3+ym8]
+    mova          [cq+64*0], m4
+    mova          [cq+64*1], m4
+    kmovb                k2, k1
+    mova          [cq+64*2], m4
+    mova          [cq+64*3], m4
+    punpcklbw            m5, m6, m4
+    punpckhbw            m6, m4
+    paddw                m0, m5
+    paddw                m1, m6
+    packuswb             m0, m1
+    vpscatterdq [dstq+ym8]{k1}, m0
+    punpcklbw            m6, m7, m4
+    punpckhbw            m7, m4
+    paddw                m2, m6
+    paddw                m3, m7
+    packuswb             m2, m3
+    vpscatterdq [r3+ym8]{k2}, m2
+    RET
+ALIGN function_align
+cglobal_label .main_fast2 ; bottom three-quarters are zero
+    vpbroadcastd       ym10, [o(pd_2048)]
+    vpbroadcastq       ym13, [o(int_mshift)]
+    vpbroadcastd        ym3, [o(pw_401_4076x8)]
+    vpbroadcastd        ym5, [o(pw_799_4017x8)]
+    vpbroadcastd        ym4, [o(pw_m1189_3920x8)]
+    pxor                ym6, ym6
+    punpckhwd           ym2, ym0, ym0
+    pmulhrsw            ym2, ym3      ; t8a  t15a
+    punpcklwd           ym7, ym1, ym1
+    pmulhrsw            ym7, ym5      ; t4a  t7a
+    punpckhwd           ym1, ym1
+    pmulhrsw            ym4, ym1      ; t11a t12a
+    vpcmpub              k7, ym13, ym10, 6
+    punpcklwd           ym9, ym6, ym0
+    psubsw              ym0, ym2, ym4 ; t11a t12a
+    paddsw              ym8, ym2, ym4 ; t8a  t15a
+    mova                ym1, ym7
+    jmp .main5
+ALIGN function_align
+cglobal_label .main_fast ; bottom half is zero
+    vpbroadcastd       ym10, [o(pd_2048)]
+    vpbroadcastq       ym13, [o(int_mshift)]
+    pxor                ym6, ym6
+    punpckhwd           ym8, ym0, ym0
+    punpckhwd           ym4, ym3, ym3
+    punpckhwd           ym5, ym2, ym2
+    punpcklwd           ym7, ym1, ym1
+    punpckhwd           ym1, ym1
+    punpcklwd           ym3, ym3
+    punpcklwd           ym9, ym6, ym0
+    punpcklwd           ym6, ym2
+    vpbroadcastd        ym2, [o(pw_401_4076x8)]
+    vpbroadcastd        ym0, [o(pw_m2598_3166x8)]
+    vpbroadcastd       ym11, [o(pw_1931_3612x8)]
+    vpbroadcastd       ym12, [o(pw_m1189_3920x8)]
+    pmulhrsw            ym8, ym2  ; t8a  t15a
+    vpbroadcastd        ym2, [o(pw_799_4017x8)]
+    pmulhrsw            ym0, ym4  ; t9a  t14a
+    vpbroadcastd        ym4, [o(pw_m2276_3406x8)]
+    pmulhrsw            ym5, ym11 ; t10a t13a
+    pmulhrsw            ym1, ym12 ; t11a t12a
+    pmulhrsw            ym7, ym2  ; t4a  t7a
+    pmulhrsw            ym3, ym4  ; t5a  t6a
+    vpcmpub              k7, ym13, ym10, 6
+    jmp .main4
+ALIGN function_align
+cglobal_label .main
+    WRAP_YMM IDCT16_1D_PACKED
+    ret
+
+INV_TXFM_8X16_FN adst, dct
+INV_TXFM_8X16_FN adst, adst
+INV_TXFM_8X16_FN adst, flipadst
+INV_TXFM_8X16_FN adst, identity
+
+cglobal iadst_8x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    call m(iadst_16x8_internal_8bpc).main_pass1
+    vbroadcasti32x4      m6, [o(int_shuf1)]
+    vpbroadcastd         m7, [o(pw_16384_m16384)]
+    punpckhwd            m3, m0, m4 ; a0 b0 a1 b1 a2 b2 a3 b3
+    punpcklwd            m4, m0     ; g0 h0 g1 h1 g2 h2 g3 h3
+    pshufb               m5, m1, m6 ; c0 d0 c1 d1 c2 d2 c3 d3
+    pshufb               m2, m6     ; e0 f0 e1 f1 e2 f2 e3 f3
+.pass1_end:
+    REPX   {pmulhrsw x, m7}, m3, m5, m4, m2
+    punpckldq            m0, m3, m5 ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckhdq            m3, m5     ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpckhdq            m5, m2, m4 ; e2 f2 g2 h2 e3 f3 g3 h3
+    punpckldq            m2, m4     ; e0 f0 g0 h0 e1 f1 g1 h1
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m5
+    punpckhqdq           m3, m5
+    jmp                tx2q
+.pass2:
+    call .main_pass2
+    vpbroadcastd         m6, [o(pw_2048)]
+    psrlq               m10, 4
+    psubw                m7, m8, m6
+.pass2_end:
+    vpbroadcastd         m5, [o(pw_2896x8)]
+    paddsw               m1, m2, m4
+    psubsw               m2, m4
+    pmulhrsw             m1, m5      ; -out7   out4   out6  -out5
+    pmulhrsw             m5, m2      ;  out8  -out11 -out9   out10
+    mova                ym8, [o(gather8c)]
+    lea                  r3, [dstq+strideq]
+    psrlq                m2, m10, 4
+    vpermi2q             m2, m0, m3  ;  1  3 13 15
+    vpermt2q             m0, m10, m3 ;  0  2 12 14
+    psrlq                m3, m10, 8
+    vpermi2q             m3, m1, m5  ;  5  7  9 11
+    psrlq               m10, 12
+    vpermt2q             m1, m10, m5 ;  4  6  8 10
+    pmulhrsw             m0, m6
+    pmulhrsw             m1, m6
+    jmp m(idct_8x16_internal_8bpc).end3
+ALIGN function_align
+.main_pass1:
+    vpbroadcastd         m2, [o(pw_2896x8)]
+    pmulhrsw             m5, m2, [cq+64*0]
+    pmulhrsw             m3, m2, [cq+64*3]
+    pmulhrsw             m1, m2, [cq+64*1]
+    pmulhrsw             m2,     [cq+64*2]
+    movu                 m4, [o(permA+3)]
+    psrlq               m10, m4, 4
+    mova                 m6, m4
+    vpermi2q             m4, m5, m3  ; in0  in12 in2  in14
+    vpermt2q             m5, m10, m3 ; in15 in3  in13 in1
+    vpermi2q             m6, m1, m2  ; in4  in8  in6  in10
+    vpermt2q             m1, m10, m2 ; in11 in7  in9  in5
+    jmp .main
+ALIGN function_align
+.main_pass2:
+    mova                 m4, [o(permC)]
+    psrlq                m5, m4, 4
+    vpermi2q             m4, m0, m2  ; in0  in12 in2  in14
+    psrlq                m6, m5, 4
+    vpermi2q             m5, m1, m3  ; in15 in3  in13 in1
+    psrlq               m10, m6, 4
+    vpermi2q             m6, m0, m2  ; in4  in8  in6  in10
+    vpermt2q             m1, m10, m3 ; in11 in7  in9  in5
+.main:
+    punpcklwd            m0, m4, m5  ; in0  in15 in2  in13
+    punpckhwd            m4, m5      ; in12 in3  in14 in1
+    punpcklwd            m5, m6, m1  ; in4  in11 in6  in9
+    punpckhwd            m6, m1      ; in8  in7  in10 in5
+cglobal_label .main2
+    vpbroadcastd         m9, [o(pd_2048)]
+    vpbroadcastq        m13, [o(int_mshift)]
+    kxnorb               k1, k1, k1
+    vpcmpub              k7, m13, m9, 6 ; 0x33...
+    pxor                 m8, m8
+    ITX_MUL4X_PACK        0, 1, 2, 3, 7, 9,  201, 4091,  995, 3973, 5
+    ITX_MUL4X_PACK        6, 1, 2, 3, 7, 9, 3035, 2751, 3513, 2106, 5
+    ITX_MUL4X_PACK        4, 1, 2, 3, 7, 9, 3857, 1380, 4052,  601, 5
+    ITX_MUL4X_PACK        5, 1, 2, 3, 7, 9, 1751, 3703, 2440, 3290, 5
+    psubsw               m2, m0, m6 ; t9a  t8a  t11a t10a
+    paddsw               m0, m6     ; t1a  t0a  t3a  t2a
+    psubsw               m3, m5, m4 ; t13a t12a t15a t14a
+    paddsw               m5, m4     ; t5a  t4a  t7a  t6a
+    ITX_MUL4X_PACK        2, 4, 1, 6, 7, 9,  799, 4017, 3406, 2276, 5
+    psubw                m7, m8, m7
+    ITX_MUL2X_PACK        3, 4, 1, 9, 7, 6, 4
+    vpbroadcastd         m6, [o(pw_3784_m1567)]
+    vpbroadcastd     m6{k1}, [o(pw_m3784_1567)]
+    psubsw               m1, m0, m5 ; t5   t4   t7   t6
+    paddsw               m0, m5     ; t1   t0   t3   t2
+    psubsw               m4, m2, m3 ; t13a t12a t15a t14a
+    paddsw               m2, m3     ; t9a  t8a  t11a t10a
+    ITX_MUL2X_PACK        1, 3, 5, 9, 1567_3784, 6, 16 ; t5a t4a t6a t7a
+    ITX_MUL2X_PACK        4, 3, 5, 9, 1567_3784, 6, 16 ; t13 t12 t14 t15
+    vbroadcasti32x4      m5, [o(deint_shuf)]
+    pshufb               m0, m5
+    pshufb               m2, m5
+    vshufi32x4           m3, m0, m2, q3232 ; t3   t2   t11a t10a
+    vinserti32x8         m0, ym2, 1        ; t1   t0   t9a  t8a
+    vshufi32x4           m2, m1, m4, q3232 ; t6a  t7a  t14  t15
+    vinserti32x8         m1, ym4, 1        ; t5a  t4a  t13  t12
+    pshufd               m2, m2, q1032     ; t7a  t6a  t15  t14
+    psubsw               m4, m0, m3        ; t3a t2a t11 t10
+    paddsw               m0, m3            ; -out15  out0   out14 -out1
+    paddsw               m3, m1, m2        ;  out12 -out3  -out13  out2
+    psubsw               m1, m2            ; t7 t6 t15a t14a
+    punpckhqdq           m2, m4, m1        ; t2a t6  t10 t14a
+    punpcklqdq           m4, m1            ; t3a t7  t11 t15a
+    ret
+
+INV_TXFM_8X16_FN flipadst, dct
+INV_TXFM_8X16_FN flipadst, adst
+INV_TXFM_8X16_FN flipadst, flipadst
+INV_TXFM_8X16_FN flipadst, identity
+
+cglobal iflipadst_8x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    call m(iadst_16x8_internal_8bpc).main_pass1
+    vbroadcasti32x4      m6, [o(int_shuf2)]
+    vpbroadcastd         m7, [o(pw_m16384_16384)]
+    punpcklwd            m3, m0, m4 ; a0 b0 a1 b1 a2 b2 a3 b3
+    punpckhwd            m4, m0     ; g0 h0 g1 h1 g2 h2 g3 h3
+    pshufb               m5, m2, m6 ; c0 d0 c1 d1 c2 d2 c3 d3
+    pshufb               m2, m1, m6 ; e0 f0 e1 f1 e2 f2 e3 f3
+    jmp m(iadst_8x16_internal_8bpc).pass1_end
+.pass2:
+    call m(iadst_8x16_internal_8bpc).main_pass2
+    vpbroadcastd         m7, [o(pw_2048)]
+    psrlq               m10, 36
+    psubw                m6, m8, m7
+    jmp m(iadst_8x16_internal_8bpc).pass2_end
+
+INV_TXFM_8X16_FN identity, dct
+INV_TXFM_8X16_FN identity, adst
+INV_TXFM_8X16_FN identity, flipadst
+INV_TXFM_8X16_FN identity, identity
+
+cglobal iidentity_8x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m0, [o(int16_perm)]
+    vpermb               m3, m0, [cq+64*0] ; a0 b0 a1 b1 a2 b2 a3 b3
+    vpermb               m2, m0, [cq+64*1] ; c0 d0 c1 d1 c2 d2 c3 d3
+    vpermb               m4, m0, [cq+64*2] ; e0 f0 e1 f1 e2 f2 e3 f3
+    vpermb               m0, m0, [cq+64*3] ; g0 h0 g1 h1 g2 h2 g3 h3
+    vpbroadcastd         m5, [o(pw_2896x8)]
+    punpckldq            m1, m3, m2        ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckhdq            m3, m2            ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpckldq            m2, m4, m0        ; e0 f0 g0 h0 a1 f1 g1 h1
+    punpckhdq            m4, m0            ; e2 f2 g2 h2 e3 f3 g3 h3
+    REPX   {pmulhrsw x, m5}, m1, m2, m3, m4
+    punpcklqdq           m0, m1, m2        ; a0 b0 c0 d0 e0 f0 g0 h0
+    punpckhqdq           m1, m2            ; a1 b1 c1 d1 e1 f1 g1 h1
+    punpcklqdq           m2, m3, m4        ; a2 b2 c2 d2 e2 f2 g2 h2
+    punpckhqdq           m3, m4            ; a3 b3 c3 d3 e3 f3 g3 h3
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m7, [o(pw_1697x16)]
+    mova                ym8, [o(gather8b)]
+    lea                  r3, [dstq+strideq*2]
+    pmulhrsw             m4, m7, m0
+    pmulhrsw             m5, m7, m1
+    pmulhrsw             m6, m7, m2
+    pmulhrsw             m7, m3
+    REPX      {paddsw x, x}, m0, m1, m2, m3
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    jmp m(idct_8x16_internal_8bpc).end
+
+%macro WRITE_16X2 6 ; coefs[1-2], tmp[1-2], offset[1-2]
+    pmovzxbw            m%3, [dstq+%5]
+%ifnum %1
+    paddw               m%3, m%1
+%else
+    paddw               m%3, %1
+%endif
+    pmovzxbw            m%4, [dstq+%6]
+%ifnum %2
+    paddw               m%4, m%2
+%else
+    paddw               m%4, %2
+%endif
+    packuswb            m%3, m%4
+    vpermq              m%3, m%3, q3120
+    mova          [dstq+%5], xm%3
+    vextracti32x4 [dstq+%6], m%3, 1
+%endmacro
+
+%macro INV_TXFM_16X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x4
+%ifidn %1_%2, dct_dct
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    jmp m(inv_txfm_add_dct_dct_16x8_8bpc).dconly2
+%endif
+%endmacro
+
+INIT_ZMM avx512icl
+INV_TXFM_16X4_FN dct, dct
+INV_TXFM_16X4_FN dct, adst
+INV_TXFM_16X4_FN dct, flipadst
+INV_TXFM_16X4_FN dct, identity
+
+cglobal idct_16x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                xm0, [cq+16*0]
+    mova                xm1, [cq+16*1]
+    mova                xm2, [cq+16*2]
+    mova                xm3, [cq+16*3]
+    mova                xm4, [cq+16*4]
+    mova                xm5, [cq+16*5]
+    mova                xm6, [cq+16*6]
+    mova                xm7, [cq+16*7]
+    call m(idct_4x16_internal_8bpc).main
+    vpbroadcastd         m8, [o(pw_16384)]
+    vinserti32x4        ym1, xm3, 1 ; 3 2   7 6
+    vinserti32x4        ym5, xm7, 1 ; b a   f e
+    vinserti32x4        ym0, xm2, 1 ; 0 1   4 5
+    vinserti32x4        ym4, xm6, 1 ; 8 9   c d
+    vinserti32x8         m1, ym5, 1 ; 3 2   7 6   b a   f e
+    vinserti32x8         m0, ym4, 1 ; 0 1   4 5   8 9   c d
+    pmulhrsw             m1, m8
+    pmulhrsw             m0, m8
+    pshufd               m1, m1, q1032
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    jmp                tx2q
+.pass2:
+    IDCT4_1D_PACKED
+    mova                 m2, [o(permA)]
+    jmp m(iadst_16x4_internal_8bpc).end
+
+INV_TXFM_16X4_FN adst, dct
+INV_TXFM_16X4_FN adst, adst
+INV_TXFM_16X4_FN adst, flipadst
+INV_TXFM_16X4_FN adst, identity
+
+cglobal iadst_16x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m0, [cq+64*0]
+    mova                 m1, [cq+64*1]
+    movshdup             m3, [o(permB)]
+    psrlq               m10, m3, 4
+    call m(iadst_4x16_internal_8bpc).main2
+    vpbroadcastd         m6, [o(pw_16384_m16384)]
+    psrlq                m0, m10, 4
+    psrlq               m10, 8
+.pass1_end:
+    punpcklwd           ym5, ym4, ym2
+    punpckhwd           ym4, ym2
+    vinserti32x8         m5, ym4, 1
+    mova                 m1, m9
+    vpdpwssd             m1, m5, [o(pw_m2896_2896)] {1to16}
+    mova                 m4, m9
+    vpdpwssd             m4, m5, [o(pw_2896_2896)] {1to16}
+    psrad                m1, 12
+    psrad                m4, 12
+    packssdw             m1, m4 ;  out8  -out7  -out9   out6  -out11  out4   out10 -out5
+    vpermi2q             m0, m1, m3  ; 0 1   4 5   8 9   c d
+    vpermt2q             m1, m10, m3 ; 2 3   6 7   a b   e f
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2
+    punpcklwd            m0, m2
+    pmulhrsw             m0, m6
+    pmulhrsw             m1, m6
+    jmp                tx2q
+.pass2:
+    call .main
+    movu                 m2, [o(permA+1)]
+.end:
+    vpbroadcastd         m3, [o(pw_2048)]
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+.end2:
+    psrlq                m3, m2, 4
+    vpermi2q             m2, m0, m1
+    vpermi2q             m3, m0, m1
+.end3:
+    lea                  r3, [dstq+strideq*2]
+    mova                xm1, [dstq+strideq*0]
+    vinserti32x4        ym1, [dstq+strideq*1], 1
+    vinserti32x4         m1, [r3  +strideq*0], 2
+    vinserti32x4         m1, [r3  +strideq*1], 3
+    pxor                 m4, m4
+    mova          [cq+64*0], m4
+    mova          [cq+64*1], m4
+    punpcklbw            m0, m1, m4
+    punpckhbw            m1, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    packuswb             m0, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [r3  +strideq*0], m0, 2
+    vextracti32x4 [r3  +strideq*1], m0, 3
+    RET
+ALIGN function_align
+.main:
+    IADST4_1D_PACKED
+    ret
+
+INV_TXFM_16X4_FN flipadst, dct
+INV_TXFM_16X4_FN flipadst, adst
+INV_TXFM_16X4_FN flipadst, flipadst
+INV_TXFM_16X4_FN flipadst, identity
+
+cglobal iflipadst_16x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m0, [cq+64*0]
+    mova                 m1, [cq+64*1]
+    movshdup             m3, [o(permB)]
+    psrlq               m10, m3, 4
+    call m(iadst_4x16_internal_8bpc).main2
+    vpbroadcastd         m6, [o(pw_m16384_16384)]
+    psrlq                m0, m10, 12
+    psrlq               m10, 16
+    jmp m(iadst_16x4_internal_8bpc).pass1_end
+.pass2:
+    call m(iadst_16x4_internal_8bpc).main
+    movu                m2, [o(permA+2)]
+    jmp m(iadst_16x4_internal_8bpc).end
+
+INV_TXFM_16X4_FN identity, dct
+INV_TXFM_16X4_FN identity, adst
+INV_TXFM_16X4_FN identity, flipadst
+INV_TXFM_16X4_FN identity, identity
+
+cglobal iidentity_16x4_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m1, [cq+64*0]
+    mova                 m2, [cq+64*1]
+    vpbroadcastd         m3, [o(pw_1697x16)]
+    vpbroadcastd         m4, [o(pw_16384)]
+    mova                 m5, [o(idtx_16x4p)]
+    shufps               m0, m1, m2, q2020
+    shufps               m1, m2, q3131
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    paddsw               m0, m2
+    paddsw               m1, m3
+    vpermb               m0, m5, m0
+    vpermb               m1, m5, m1
+    jmp                tx2q
+.pass2:
+    vpbroadcastd         m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    movu                 m2, [o(permA+1)]
+    jmp m(iadst_16x4_internal_8bpc).end
+
+%macro INV_TXFM_16X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x8
+%ifidn %1_%2, dct_dct
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 8
+.dconly:
+    imul                r6d, 181
+    add                 r6d, 128
+    sar                 r6d, 8
+.dconly2:
+    imul                r6d, 181
+    add                 r6d, 128+256
+    sar                 r6d, 8+1
+.dconly3:
+    imul                r6d, 181
+    lea                  r2, [strideq*3]
+    add                 r6d, 128+2048
+    sar                 r6d, 8+4
+    pxor                 m2, m2
+    vpbroadcastw         m3, r6d
+.dconly_loop:
+    mova                xm1, [dstq+strideq*0]
+    vinserti32x4        ym1, [dstq+strideq*1], 1
+    vinserti32x4         m1, [dstq+strideq*2], 2
+    vinserti32x4         m1, [dstq+r2       ], 3
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    paddw                m0, m3
+    paddw                m1, m3
+    packuswb             m0, m1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+r2       ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                 r3d, 4
+    jg .dconly_loop
+    RET
+%endif
+%endmacro
+
+%macro ITX_16X8_LOAD_COEFS 1 ; shuf_odd
+    vpbroadcastd         m8, [o(pw_2896x8)]
+    vpermq               m0, [cq+32*0], q3120
+    add                  cq, 32*4
+    vpermq               m7, [cq+32*3], q%1
+    vpermq               m1, [cq-32*3], q%1
+    vpermq               m6, [cq+32*2], q3120
+    vpermq               m2, [cq-32*2], q3120
+    vpermq               m5, [cq+32*1], q%1
+    vpermq               m3, [cq-32*1], q%1
+    vpermq               m4, [cq+32*0], q3120
+    REPX   {pmulhrsw x, m8}, m0, m7, m1, m6, m2, m5, m3, m4
+%endmacro
+
+INV_TXFM_16X8_FN dct, dct
+INV_TXFM_16X8_FN dct, identity
+INV_TXFM_16X8_FN dct, adst
+INV_TXFM_16X8_FN dct, flipadst
+
+cglobal idct_16x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpbroadcastd         m1, [o(pw_2896x8)]
+    vpermq               m0, [cq+64*0], q3120
+    vpermq               m2, [cq+64*1], q3120
+    vpermq               m4, [cq+64*2], q3120
+    vpermq               m6, [cq+64*3], q3120
+    REPX   {pmulhrsw x, m1}, m0, m2, m4, m6
+    vextracti32x8       ym1, m0, 1
+    vextracti32x8       ym3, m2, 1
+    vextracti32x8       ym5, m4, 1
+    vextracti32x8       ym7, m6, 1
+    call m(idct_8x16_internal_8bpc).main
+    vbroadcasti32x4      m8, [o(int_shuf1)]
+    vbroadcasti32x4      m9, [o(int_shuf2)]
+    vinserti32x8         m0, ym2, 1 ; a0 a1 a2 a3 b0 b1 b2 b3
+    vinserti32x8         m1, ym3, 1 ; d0 d1 d2 d3 c0 c1 c2 c3
+    vinserti32x8         m4, ym6, 1 ; i0 i1 i2 i3 j0 j1 j2 j3
+    vinserti32x8         m5, ym7, 1 ; l0 l1 l2 l3 k0 k1 k2 k3
+    vpbroadcastd         m2, [o(pw_16384)]
+    pshufb               m0, m8     ; a0 b0 a1 b1 a2 b2 a3 b3
+    pshufb               m1, m9     ; c0 d0 c1 d1 c2 d2 c3 d3
+    pshufb               m6, m4, m8 ; i0 j0 i1 j1 i2 j2 i3 j3
+    pshufb               m7, m5, m9 ; m0 n0 m1 n1 m2 n2 m3 n3
+    REPX   {pmulhrsw x, m2}, m0, m1, m6, m7
+    punpckldq            m2, m0, m1 ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckhdq            m3, m0, m1 ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpckldq            m4, m6, m7 ; i0 j0 k0 l0 i1 j1 k1 l1
+    punpckhdq            m5, m6, m7 ; i2 j2 k2 l2 i3 j3 k3 l3
+    jmp                tx2q
+.pass2:
+    vshufi32x4           m0, m2, m4, q2020 ; 0 1
+    vshufi32x4           m2, m4, q3131     ; 4 5
+    vshufi32x4           m1, m3, m5, q2020 ; 2 3
+    vshufi32x4           m3, m5, q3131     ; 6 7
+    call .main
+    movshdup             m4, [o(permC)]
+    psrlq                m6, m4, 4
+    vpermq               m5, m4, q1032
+    vpermi2q             m4, m0, m2 ; a2 a3   b2 b3   e2 e3   f2 f3
+    vpermt2q             m0, m6, m2 ; a0 a1   b0 b1   e0 e1   f0 f1
+    psrlq                m6, m5, 4
+    vpermi2q             m5, m1, m3 ; c2 c3   d2 d3   g2 g3   h2 h3
+    vpermt2q             m1, m6, m3 ; c0 c1   d0 d1   g0 g1   h0 h1
+    vpbroadcastd         m6, [o(pw_2048)]
+.end:
+    REPX   {pmulhrsw x, m6}, m0, m4, m1, m5
+.end2:
+    lea                  r3, [dstq+strideq*4]
+    lea                  r4, [strideq*3]
+    mova                xm3, [dstq+strideq*0]
+    mova                xm6, [dstq+strideq*2]
+    vinserti32x4        ym3, [dstq+strideq*1], 1
+    vinserti32x4        ym6, [dstq+r4       ], 1
+    vinserti32x4         m3, [r3  +strideq*0], 2
+    vinserti32x4         m6, [r3  +strideq*2], 2
+    vinserti32x4         m3, [r3  +strideq*1], 3
+    vinserti32x4         m6, [r3  +r4       ], 3
+    pxor                 m7, m7
+    mova          [cq+64*0], m7
+    mova          [cq+64*1], m7
+    mova          [cq+64*2], m7
+    mova          [cq+64*3], m7
+    punpcklbw            m2, m3, m7
+    punpckhbw            m3, m7
+    paddw                m0, m2
+    paddw                m4, m3
+    packuswb             m0, m4
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [r3  +strideq*0], m0, 2
+    vextracti32x4 [r3  +strideq*1], m0, 3
+    punpcklbw            m3, m6, m7
+    punpckhbw            m6, m7
+    paddw                m1, m3
+    paddw                m5, m6
+    packuswb             m1, m5
+    mova          [dstq+strideq*2], xm1
+    vextracti32x4 [dstq+r4       ], ym1, 1
+    vextracti32x4 [r3  +strideq*2], m1, 2
+    vextracti32x4 [r3  +r4       ], m1, 3
+    RET
+ALIGN function_align
+cglobal_label .main
+    IDCT8_1D_PACKED
+    ret
+
+INV_TXFM_16X8_FN adst, dct
+INV_TXFM_16X8_FN adst, adst
+INV_TXFM_16X8_FN adst, flipadst
+INV_TXFM_16X8_FN adst, identity
+
+cglobal iadst_16x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    call m(iadst_8x16_internal_8bpc).main_pass1
+    vpbroadcastd         m7, [o(pw_16384_m16384)]
+    psrlq               m10, 4
+.pass1_end:
+    punpcklwd            m5, m4, m2
+    punpckhwd            m4, m2
+    mova                 m1, m9
+    vpdpwssd             m1, m5, [o(pw_m2896_2896)] {1to16}
+    mova                 m6, m9
+    vpdpwssd             m6, m5, [o(pw_2896_2896)] {1to16}
+    mova                 m2, m9
+    vpdpwssd             m2, m4, [o(pw_m2896_2896)] {1to16}
+    vpdpwssd             m9, m4, [o(pw_2896_2896)] {1to16}
+    psrad                m1, 12
+    psrad                m6, 12
+    packssdw             m1, m6 ;  out8  -out7  -out9   out6
+    psrad                m2, 12
+    psrad                m9, 12
+    packssdw             m2, m9 ; -out11  out4   out10 -out5
+    psrlq                m4, m10, 4
+    vpermi2q             m4, m0, m2
+    vpermt2q             m0, m10, m2
+    psrlq                m5, m10, 8
+    vpermi2q             m5, m1, m3
+    psrlq               m10, 12
+    vpermt2q             m1, m10, m3
+    punpcklwd            m3, m4, m5 ; a0 c0 a1 c1 a2 c2 a3 c3
+    punpckhwd            m4, m5     ; b0 d0 b1 d1 b2 d2 b3 d3
+    punpcklwd            m5, m1, m0 ; i0 k0 i1 k1 2i k2 i3 k3
+    punpckhwd            m1, m0     ; j0 l0 j1 l1 j2 l2 j3 l3
+    punpcklwd            m2, m3, m4 ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckhwd            m3, m4     ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpcklwd            m4, m5, m1 ; i0 j0 k0 l0 i1 j1 k1 l1
+    punpckhwd            m5, m1     ; i2 j2 k2 l2 i3 j3 k3 l3
+    REPX   {pmulhrsw x, m7}, m2, m3, m4, m5
+    jmp                tx2q
+.pass2:
+    vshufi32x4           m0, m2, m4, q2020
+    vshufi32x4           m2, m4, q3131     ; 4 5
+    vshufi32x4           m1, m3, m5, q2020
+    vshufi32x4           m3, m5, q3131     ; 6 7
+    pshufd               m4, m0, q1032     ; 1 0
+    pshufd               m5, m1, q1032     ; 3 2
+    call .main_pass2
+    movshdup             m4, [o(permC)]
+    pmulhrsw             m0, m6
+    pmulhrsw             m1, m6
+    psrlq                m6, m4, 4
+    mova                 m5, m4
+    vpermi2q             m4, m0, m2
+    vpermt2q             m0, m6, m2
+    vpermi2q             m5, m1, m3
+    vpermt2q             m1, m6, m3
+    jmp m(idct_16x8_internal_8bpc).end2
+ALIGN function_align
+.main_pass1:
+    vpbroadcastd         m4, [o(pw_2896x8)]
+    pmulhrsw             m3, m4, [cq+64*0]
+    pmulhrsw             m1, m4, [cq+64*3]
+    pmulhrsw             m2, m4, [cq+64*1]
+    pmulhrsw             m4, [cq+64*2]
+    mova                 m5, [o(int16_perm)]
+    kxnorb               k1, k1, k1
+    vpblendmd        m0{k1}, m1, m3 ; 0 7
+    vmovdqa32        m3{k1}, m1     ; 6 1
+    vpblendmd        m1{k1}, m4, m2 ; 2 5
+    vmovdqa32        m2{k1}, m4     ; 4 3
+    REPX  {vpermb x, m5, x}, m0, m1, m2, m3
+    IADST8_1D_PACKED 1
+    ret
+ALIGN function_align
+cglobal_label .main_pass2
+    IADST8_1D_PACKED 2
+    pxor                 m5, m5
+    psubd                m5, m6
+    packssdw             m6, m5
+    pmulhrsw             m2, m6
+    pmulhrsw             m3, m6
+    ret
+
+INV_TXFM_16X8_FN flipadst, dct
+INV_TXFM_16X8_FN flipadst, adst
+INV_TXFM_16X8_FN flipadst, flipadst
+INV_TXFM_16X8_FN flipadst, identity
+
+cglobal iflipadst_16x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    call m(iadst_8x16_internal_8bpc).main_pass1
+    vpbroadcastd         m7, [o(pw_m16384_16384)]
+    psrlq               m10, 20
+    jmp m(iadst_16x8_internal_8bpc).pass1_end
+.pass2:
+    vshufi32x4           m0, m2, m4, q2020
+    vshufi32x4           m2, m4, q3131     ; 4 5
+    vshufi32x4           m1, m3, m5, q2020
+    vshufi32x4           m3, m5, q3131     ; 6 7
+    pshufd               m4, m0, q1032     ; 1 0
+    pshufd               m5, m1, q1032     ; 3 2
+    call m(iadst_16x8_internal_8bpc).main_pass2
+    movshdup             m4, [o(permC)]
+    pmulhrsw             m5, m6, m0
+    pmulhrsw             m0, m6, m1
+    psrlq                m1, m4, 12
+    psrlq                m4, 8
+    mova                 m7, m4
+    vpermi2q             m4, m0, m3
+    vpermt2q             m0, m1, m3
+    vpermi2q             m1, m5, m2
+    vpermt2q             m5, m7, m2
+    jmp m(idct_16x8_internal_8bpc).end2
+
+INV_TXFM_16X8_FN identity, dct
+INV_TXFM_16X8_FN identity, adst
+INV_TXFM_16X8_FN identity, flipadst
+INV_TXFM_16X8_FN identity, identity
+
+cglobal iidentity_16x8_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    vpbroadcastd         m0, [o(pw_2896x8)]
+    pmulhrsw             m3, m0, [cq+64*0]
+    pmulhrsw             m4, m0, [cq+64*1]
+    pmulhrsw             m5, m0, [cq+64*2]
+    pmulhrsw             m0,     [cq+64*3]
+    vpbroadcastd         m7, [o(pw_1697x16)]
+    vpbroadcastd         m8, [o(pw_16384)]
+    shufps               m2, m3, m4, q2020 ; a0 a1 a4 a5 e0 e1 e4 e5
+    shufps               m3, m4, q3131     ; a2 a3 a6 a7 e2 e3 e6 e7
+    shufps               m4, m5, m0, q2020 ; i0 i1 i4 i5 m0 m1 m4 m5
+    shufps               m5, m0, q3131     ; i2 i3 i6 i7 m2 m3 m6 m7
+    mova                 m9, [o(int8_permA)]
+    pmulhrsw             m0, m7, m2
+    pmulhrsw             m1, m7, m3
+    pmulhrsw             m6, m7, m4
+    pmulhrsw             m7, m5
+    REPX   {pmulhrsw x, m8}, m0, m1, m6, m7
+    paddsw               m2, m0
+    paddsw               m3, m1
+    paddsw               m4, m6
+    paddsw               m5, m7
+    REPX  {vpermb x, m9, x}, m2, m3, m4, m5
+    jmp                tx2q
+.pass2:
+    mova                 m7, [o(permB)]
+    vpbroadcastd         m6, [o(pw_4096)]
+    vpermq               m0, m7, m2
+    vpermq               m4, m7, m4
+    vpermq               m1, m7, m3
+    vpermq               m5, m7, m5
+    jmp m(idct_16x8_internal_8bpc).end
+
+%macro INV_TXFM_16X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x16
+%ifidn %1_%2, dct_dct
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 16
+    imul                r6d, 181
+    add                 r6d, 128+512
+    sar                 r6d, 8+2
+    jmp m(inv_txfm_add_dct_dct_16x8_8bpc).dconly3
+%endif
+%endmacro
+
+INV_TXFM_16X16_FN dct, dct
+INV_TXFM_16X16_FN dct, identity
+INV_TXFM_16X16_FN dct, adst
+INV_TXFM_16X16_FN dct, flipadst
+
+cglobal idct_16x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m7, [o(permB)]
+    vpermq               m0, m7, [cq+64*0]
+    vpermq               m1, m7, [cq+64*1]
+    vpermq               m2, m7, [cq+64*2]
+    vpermq               m3, m7, [cq+64*3]
+    vpermq               m4, m7, [cq+64*4]
+    vpermq               m5, m7, [cq+64*5]
+    vpermq               m6, m7, [cq+64*6]
+    vpermq               m7, m7, [cq+64*7]
+    call .main
+    vbroadcasti32x4     m12, [o(int_shuf1)]
+    vbroadcasti32x4     m11, [o(int_shuf2)]
+    vpbroadcastd        m13, [o(pw_8192)]
+    pshufb               m0, m12
+    pshufb               m8, m1, m11
+    pshufb               m2, m12
+    pshufb               m9, m3, m11
+    pshufb               m4, m12
+    pshufb              m10, m5, m11
+    pshufb               m6, m12
+    pshufb              m11, m7, m11
+    REPX  {pmulhrsw x, m13}, m0, m8, m2, m9, m4, m10, m6, m11
+    punpckhdq            m1, m0, m8
+    punpckldq            m0, m8
+    punpckhdq            m3, m2, m9
+    punpckldq            m2, m9
+    punpckhdq            m5, m4, m10
+    punpckldq            m4, m10
+    punpckhdq            m7, m6, m11
+    punpckldq            m6, m11
+    jmp                tx2q
+.pass2:
+    vshufi32x4           m8, m4, m6, q3232 ; i8 ic m8 mc
+    vinserti32x8         m4, ym6, 1        ; i0 i4 m0 m4
+    vshufi32x4           m6, m0, m2, q3232 ; a8 ac e8 ec
+    vinserti32x8         m0, ym2, 1        ; a0 a4 e0 e4
+    vshufi32x4           m9, m5, m7, q3232 ; ia ie ma me
+    vinserti32x8         m5, ym7, 1        ; i2 i6 m2 m6
+    vshufi32x4           m7, m1, m3, q3232 ; aa ae ea ee
+    vinserti32x8         m1, ym3, 1        ; a2 a6 e2 e6
+    vshufi32x4           m2, m0, m4, q3131 ;  4  5
+    vshufi32x4           m0, m4, q2020     ;  0  1
+    vshufi32x4           m4, m6, m8, q2020 ;  8  9
+    vshufi32x4           m6, m8, q3131     ; 12 13
+    vshufi32x4           m3, m1, m5, q3131 ;  6  7
+    vshufi32x4           m1, m5, q2020     ;  2  3
+    vshufi32x4           m5, m7, m9, q2020 ; 10 11
+    vshufi32x4           m7, m9, q3131     ; 14 15
+    call .main
+    mova                  m8, [o(permD)]
+    psrlq                m12, m8, 4
+    psrlq                 m9, m8, 8
+    psrlq                m13, m8, 12
+    mova                 m10, m8
+    vpermi2q              m8, m0, m2 ;  0  1  4  5
+    vpermt2q              m0, m12, m2
+    mova                 m11, m9
+    vpermi2q              m9, m1, m3 ;  2  3  6  7
+    vpermt2q              m1, m13, m3
+    vpermi2q             m10, m4, m6 ;  8  9 12 13
+    vpermt2q              m4, m12, m6
+    vpermi2q             m11, m5, m7 ; 10 11 14 15
+    vpermt2q              m5, m13, m7
+.end:
+    vpbroadcastd        m12, [o(pw_2048)]
+.end2:
+    REPX  {pmulhrsw x, m12}, m0, m1, m4, m5
+.end3:
+    REPX  {pmulhrsw x, m12}, m8, m9, m10, m11
+    lea                  r3, [strideq*3]
+    lea                  r4, [dstq+strideq*4]
+    lea                  r5, [dstq+strideq*8]
+    lea                  r6, [r4  +strideq*8]
+    mova                xm3, [dstq+strideq*0]
+    mova                xm6, [dstq+strideq*2]
+    vinserti32x4        ym3, [dstq+strideq*1], 1
+    vinserti32x4        ym6, [dstq+r3       ], 1
+    vinserti32x4         m3, [r4+strideq*0], 2
+    vinserti32x4         m6, [r4+strideq*2], 2
+    vinserti32x4         m3, [r4+strideq*1], 3
+    vinserti32x4         m6, [r4+r3       ], 3
+    mova               xm12, [r5+strideq*0]
+    mova               xm13, [r5+strideq*2]
+    vinserti32x4       ym12, [r5+strideq*1], 1
+    vinserti32x4       ym13, [r5+r3       ], 1
+    vinserti32x4        m12, [r6+strideq*0], 2
+    vinserti32x4        m13, [r6+strideq*2], 2
+    vinserti32x4        m12, [r6+strideq*1], 3
+    vinserti32x4        m13, [r6+r3       ], 3
+    pxor                 m7, m7
+    REPX {mova [cq+64*x], m7}, 0, 1, 2, 3, 4, 5, 6, 7
+    punpcklbw            m2, m3, m7
+    punpckhbw            m3, m7
+    paddw                m0, m2
+    paddw                m8, m3
+    packuswb             m0, m8
+    punpcklbw            m2, m6, m7
+    punpckhbw            m6, m7
+    paddw                m1, m2
+    paddw                m9, m6
+    packuswb             m1, m9
+    punpcklbw            m2, m12, m7
+    punpckhbw           m12, m7
+    paddw                m2, m4
+    paddw               m10, m12
+    packuswb             m2, m10
+    punpcklbw            m3, m13, m7
+    punpckhbw           m13, m7
+    paddw                m3, m5
+    paddw               m11, m13
+    packuswb             m3, m11
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    mova          [dstq+strideq*2], xm1
+    vextracti32x4 [dstq+r3       ], ym1, 1
+    vextracti32x4 [r4+strideq*0], m0, 2
+    vextracti32x4 [r4+strideq*1], m0, 3
+    vextracti32x4 [r4+strideq*2], m1, 2
+    vextracti32x4 [r4+r3       ], m1, 3
+    mova          [r5+strideq*0], xm2
+    vextracti32x4 [r5+strideq*1], ym2, 1
+    mova          [r5+strideq*2], xm3
+    vextracti32x4 [r5+r3       ], ym3, 1
+    vextracti32x4 [r6+strideq*0], m2, 2
+    vextracti32x4 [r6+strideq*1], m2, 3
+    vextracti32x4 [r6+strideq*2], m3, 2
+    vextracti32x4 [r6+r3       ], m3, 3
+    RET
+ALIGN function_align
+cglobal_label .main_fast2 ; bottom three-quarters are zero
+    vpbroadcastd        m10, [o(pd_2048)]
+    vpbroadcastq        m13, [o(int_mshift)]
+    vpcmpub              k7, m13, m10, 6
+.main_fast4:
+    vpbroadcastd         m2, [o(pw_401_4076x8)]
+    vpbroadcastd         m4, [o(pw_m1189_3920x8)]
+    vpbroadcastd         m3, [o(pw_799_4017x8)]
+    pmulhrsw             m2, m8     ; t8a  t15a
+    pmulhrsw             m4, m1     ; t11a t12a
+    pmulhrsw             m7, m3     ; t4a  t7a
+    pxor                 m6, m6
+    psubsw               m0, m2, m4 ; t11a t12a
+    paddsw               m8, m2, m4 ; t8a  t15a
+    mova                 m1, m7
+    jmp .main5
+ALIGN function_align
+cglobal_label .main_fast ; bottom half is zero
+    vpbroadcastd        m10, [o(pd_2048)]
+.main_fast3:
+    vpbroadcastq        m13, [o(int_mshift)]
+    vpcmpub              k7, m13, m10, 6
+.main_fast5:
+    vpbroadcastd         m2, [o(pw_401_4076x8)]
+    vpbroadcastd         m4, [o(pw_m2598_3166x8)]
+    vpbroadcastd        m11, [o(pw_1931_3612x8)]
+    vpbroadcastd        m12, [o(pw_m1189_3920x8)]
+    pmulhrsw             m8, m2  ; t8a  t15a
+    vpbroadcastd         m2, [o(pw_799_4017x8)]
+    pmulhrsw             m0, m4  ; t9a  t14a
+    vpbroadcastd         m4, [o(pw_m2276_3406x8)]
+    pmulhrsw             m5, m11 ; t10a t13a
+    pmulhrsw             m1, m12 ; t11a t12a
+    pmulhrsw             m7, m2  ; t4a  t7a
+    pmulhrsw             m3, m4  ; t5a  t6a
+    jmp .main4
+ALIGN function_align
+cglobal_label .main
+    IDCT16_1D_PACKED
+    ret
+
+INV_TXFM_16X16_FN adst, dct
+INV_TXFM_16X16_FN adst, adst
+INV_TXFM_16X16_FN adst, flipadst
+
+cglobal iadst_16x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    call .main_pass1
+    vpbroadcastd        m10, [o(pw_8192_m8192)]
+    punpcklwd            m8, m0, m1 ; b0 d0 b1 d1 b2 d2 b3 d3
+    punpckhwd            m0, m1     ; a0 c0 a1 c1 a2 c2 a3 c3
+    punpckhwd            m1, m0, m8 ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpcklwd            m0, m8     ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpcklwd            m8, m2, m3 ; f0 h0 f1 h1 f2 h2 f3 h3
+    punpckhwd            m2, m3     ; e0 g0 e1 g1 e2 g2 e3 g3
+    punpckhwd            m3, m2, m8 ; e2 f2 g2 h2 e3 f3 g3 h3
+    punpcklwd            m2, m8     ; e0 f0 g0 h0 e1 f1 g1 h1
+    punpckhwd            m8, m4, m5 ; i0 k0 i1 k1 i2 k2 i3 k3
+    punpcklwd            m4, m5     ; j0 l0 j1 l1 j2 l2 j3 l3
+    punpckhwd            m5, m4, m8 ; i2 j2 k2 l2 i3 j3 k3 l3
+    punpcklwd            m4, m8     ; i0 j0 k0 l0 i1 j1 k1 l1
+    punpckhwd            m8, m6, m7 ; m0 o0 m1 o1 m2 o2 m3 o3
+    punpcklwd            m6, m7     ; n0 p0 n1 p1 n2 p2 n3 p3
+    punpckhwd            m7, m6, m8 ; m2 n2 o2 p2 m3 n3 o3 p3
+    punpcklwd            m6, m8     ; m0 n0 o0 p0 m1 n1 o1 p1
+.pass1_end:
+    REPX  {pmulhrsw x, m10}, m0, m1, m2, m3, m4, m5, m6, m7
+    jmp                tx2q
+.pass2:
+    call .main_pass2
+    mova                m10, [o(permD)]
+    psrlq                m8, m10, 8
+    psrlq               m12, m10, 12
+    psrlq               m13, m10, 4
+    mova                 m9, m8
+    vpermi2q             m8, m0, m2 ;  0  1  4  5
+    vpermt2q             m0, m12, m2
+    vpermi2q             m9, m1, m3 ;  2  3  6  7
+    vpermt2q             m1, m12, m3
+    vpbroadcastd        m12, [o(pw_2048)]
+    mov                 r3d, 0xff00ff00
+    mova                m11, m10
+    vpermi2q            m10, m4, m6 ;  8  9 12 13
+    vpermt2q             m4, m13, m6
+    kmovd                k1, r3d
+    vpermi2q            m11, m5, m7 ; 10 11 14 15
+    vpermt2q             m5, m13, m7
+    pxor                 m7, m7
+    vpsubw          m12{k1}, m7, m12
+    jmp m(idct_16x16_internal_8bpc).end2
+ALIGN function_align
+.main_pass1:
+    mova                 m4, [o(permB)]
+    psrlq                m3, m4, 4
+    vpermq               m0, m4, [cq+64*0]
+    vpermq               m7, m3, [cq+64*7]
+    vpermq               m6, m4, [cq+64*6]
+    vpermq               m1, m3, [cq+64*1]
+    vpermq               m2, m4, [cq+64*2]
+    vpermq               m5, m3, [cq+64*5]
+    vpermq               m4, m4, [cq+64*4]
+    vpermq               m3, m3, [cq+64*3]
+    call .main
+    vpbroadcastd        m13, [o(pw_2896_2896)]
+    vpbroadcastd        m12, [o(pw_m2896_2896)]
+    mova                 m2, m10
+    vpdpwssd             m2, m5, m13       ; -out5
+    mova                 m8, m10
+    vpdpwssd             m8, m11, m13      ;  out4
+    mova                 m9, m10
+    vpdpwssd             m9, m5, m12       ;  out10
+    mova                 m5, m10
+    vpdpwssd             m5, m11, m12      ; -out11
+    mova                m11, m10
+    vpdpwssd            m11, m3, m13       ; -out7
+    mova                m14, m10
+    vpdpwssd            m14, m4, m13       ;  out6
+    mova                m13, m10
+    vpdpwssd            m13, m3, m12       ;  out8
+    vpdpwssd            m10, m4, [o(pw_2896_m2896)] {1to16} ; -out9
+    REPX      {psrad x, 12}, m2, m8, m9, m5, m11, m14, m13, m10
+    packssdw             m2, m8            ; -out5   out4
+    packssdw             m5, m9, m5        ;  out10 -out11
+    packssdw             m3, m11, m14      ; -out7   out6
+    packssdw             m4, m13, m10      ;  out8  -out9
+    ret
+ALIGN function_align
+.main_pass2:
+    vshufi32x4           m8, m4, m6, q3232 ; i8 ic m8 mc
+    vinserti32x8         m4, ym6, 1        ; i0 i4 m0 m4
+    vshufi32x4           m6, m0, m2, q3232 ; a8 ac e8 ec
+    vinserti32x8         m0, ym2, 1        ; a0 a4 e0 e4
+    vshufi32x4           m9, m5, m7, q3232 ; ia ie ma me
+    vinserti32x8         m5, ym7, 1        ; i2 i6 m2 m6
+    vshufi32x4           m7, m1, m3, q3232 ; aa ae ea ee
+    vinserti32x8         m1, ym3, 1        ; a2 a6 e2 e6
+    vshufi32x4           m2, m0, m4, q3131 ;  4  5
+    vshufi32x4           m0, m4, q2020     ;  0  1
+    vshufi32x4           m4, m6, m8, q2020 ;  8  9
+    vshufi32x4           m6, m8, q3131     ; 12 13
+    vshufi32x4           m3, m1, m5, q3131 ;  6  7
+    vshufi32x4           m1, m5, q2020     ;  2  3
+    vshufi32x4           m5, m7, m9, q2020 ; 10 11
+    vshufi32x4           m7, m9, q3131     ; 14 15
+cglobal_label .main_pass2b
+    REPX {pshufd x, x, q1032}, m1, m3, m5, m7
+    call .main
+    vpbroadcastd         m8, [o(pw_2896x8)]
+    pshufb               m2, m11, m12
+    pshufb               m5, m12
+    pshufb               m3, m12
+    pshufb               m4, m12
+    punpcklqdq           m9, m5, m2        ;  t15a   t7
+    punpckhqdq           m5, m2            ;  t14a   t6
+    shufps               m2, m3, m4, q1032 ;  t2a    t10
+    shufps               m3, m4, q3210     ;  t3a    t11
+    psubsw               m4, m2, m3        ;  out8  -out9
+    paddsw               m3, m2            ; -out7   out6
+    paddsw               m2, m5, m9        ; -out5   out4
+    psubsw               m5, m9            ;  out10 -out11
+    REPX   {pmulhrsw x, m8}, m2, m3, m4, m5
+    ret
+ALIGN function_align
+.main:
+    vpbroadcastd        m10, [o(pd_2048)]
+    vpbroadcastq        m13, [o(int_mshift)]
+    punpckhwd            m8, m7, m0 ; in14 in1
+    punpcklwd            m0, m7     ; in0  in15
+    punpcklwd            m7, m6, m1 ; in12 in3
+    punpckhwd            m1, m6     ; in2  in13
+    punpckhwd            m6, m5, m2 ; in10 in5
+    punpcklwd            m2, m5     ; in4  in11
+    punpcklwd            m5, m4, m3 ; in8  in7
+    punpckhwd            m3, m4     ; in6  in9
+    vpcmpub              k7, m13, m10, 6 ; 0x33...
+    ITX_MUL2X_PACK        0, 4, 9, 10,  201, 4091, 5 ; t0  t1
+    ITX_MUL2X_PACK        1, 4, 9, 10,  995, 3973, 5 ; t2  t3
+    ITX_MUL2X_PACK        2, 4, 9, 10, 1751, 3703, 5 ; t4  t5
+    ITX_MUL2X_PACK        3, 4, 9, 10, 2440, 3290, 5 ; t6  t7
+    ITX_MUL2X_PACK        5, 4, 9, 10, 3035, 2751, 5 ; t8  t9
+    ITX_MUL2X_PACK        6, 4, 9, 10, 3513, 2106, 5 ; t10 t11
+    ITX_MUL2X_PACK        7, 4, 9, 10, 3857, 1380, 5 ; t12 t13
+    ITX_MUL2X_PACK        8, 4, 9, 10, 4052,  601, 5 ; t14 t15
+    psubsw               m4, m0, m5 ; t9a  t8a
+    paddsw               m0, m5     ; t1a  t0a
+    psubsw               m5, m1, m6 ; t11a t10a
+    paddsw               m1, m6     ; t3a  t2a
+    psubsw               m6, m2, m7 ; t13a t12a
+    paddsw               m2, m7     ; t5a  t4a
+    psubsw               m7, m3, m8 ; t15a t14a
+    paddsw               m3, m8     ; t7a  t6a
+    ITX_MUL2X_PACK        4, 8, 9, 10, 799,       4017,        4 ; t8  t9
+    ITX_MUL2X_PACK        6, 8, 9, 10, 799_4017,  4017_m799,  52 ; t12 t13
+    ITX_MUL2X_PACK        5, 8, 9, 10, 3406,      2276,        4 ; t10 t11
+    ITX_MUL2X_PACK        7, 8, 9, 10, 3406_2276, 2276_m3406, 52 ; t14 t15
+    psubsw               m8, m1, m3 ; t7   t6
+    paddsw               m1, m3     ; t3   t2
+    psubsw               m3, m0, m2 ; t5   t4
+    paddsw               m0, m2     ; t1   t0
+    psubsw               m2, m5, m7 ; t14a t15a
+    paddsw               m7, m5     ; t10a t11a
+    psubsw               m5, m4, m6 ; t12a t13a
+    paddsw               m4, m6     ; t8a  t9a
+    ITX_MUL2X_PACK        3, 6, 9, 10, 1567,       3784,        5 ; t5a t4a
+    ITX_MUL2X_PACK        8, 6, 9, 10, 3784_m1567, 1567_3784,  52 ; t7a t6a
+    ITX_MUL2X_PACK        2, 6, 9, 10, 3784,       1567,        4 ; t15 t14
+    ITX_MUL2X_PACK        5, 6, 9, 10, 3784_1567,  1567_m3784, 52 ; t13 t12
+    vbroadcasti32x4     m12, [o(deint_shuf)]
+    paddsw               m6, m4, m7        ; -out1  out14
+    psubsw               m4, m7            ;  t10    t11
+    psubsw              m11, m3, m8        ;  t7     t6
+    paddsw               m8, m3            ;  out12 -out3
+    psubsw               m3, m0, m1        ;  t3a    t2a
+    paddsw               m0, m1            ; -out15  out0
+    paddsw               m1, m2, m5        ; -out13  out2
+    psubsw               m5, m2            ;  t15a   t14a
+    pshufb               m0, m12
+    pshufb               m6, m12
+    pshufb               m8, m12
+    pshufb               m1, m12
+    shufps               m7, m6, m0, q1032 ;  out14 -out15
+    shufps               m0, m6, m0, q3210 ; -out1   out0
+    punpcklqdq           m6, m8, m1        ;  out12 -out13
+    punpckhqdq           m1, m8, m1        ; -out3   out2
+    ret
+
+INV_TXFM_16X16_FN flipadst, dct
+INV_TXFM_16X16_FN flipadst, adst
+INV_TXFM_16X16_FN flipadst, flipadst
+
+cglobal iflipadst_16x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    call m(iadst_16x16_internal_8bpc).main_pass1
+    vpbroadcastd        m10, [o(pw_m8192_8192)]
+    punpcklwd            m8, m1, m0 ; m0 o0 m1 o1 m2 o2 m3 o3
+    punpckhwd            m9, m1, m0 ; n0 p0 n1 p1 n2 p2 n3 p3
+    punpckhwd            m1, m7, m6 ; a0 c0 a1 c1 a2 c2 a3 c3
+    punpcklwd            m7, m6     ; b0 d0 b1 d1 b2 d2 b3 d3
+    punpcklwd            m0, m1, m7 ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckhwd            m1, m7     ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpcklwd            m6, m8, m9 ; m0 n0 o0 p0 m1 n1 o1 p1
+    punpckhwd            m7, m8, m9 ; m2 n2 o2 p2 m3 n3 o3 p3
+    punpcklwd            m8, m3, m2 ; i0 k0 i1 k1 i2 k2 i3 k3
+    punpckhwd            m9, m3, m2 ; j0 l0 j1 l1 j2 l2 j3 l3
+    punpckhwd            m3, m5, m4 ; e0 g0 e1 g1 e2 g2 e3 g3
+    punpcklwd            m5, m4     ; f0 h0 f1 h1 f2 h2 f3 h3
+    punpcklwd            m2, m3, m5 ; e0 f0 g0 h0 e1 f1 g1 h1
+    punpckhwd            m3, m5     ; e2 f2 g2 h2 e3 f3 g3 h3
+    punpcklwd            m4, m8, m9 ; i0 j0 k0 l0 i1 j1 k1 l1
+    punpckhwd            m5, m8, m9 ; i2 j2 k2 l2 i3 j3 k3 l3
+    jmp m(iadst_16x16_internal_8bpc).pass1_end
+.pass2:
+    call m(iadst_16x16_internal_8bpc).main_pass2
+    mova                m10, [o(permD)]
+    psrlq                m8, m10, 8
+    psrlq               m12, m10, 12
+    psrlq               m13, m10, 4
+    mova                 m9, m8
+    vpermi2q             m8, m7, m5 ;  0  1  4  5
+    vpermt2q             m7, m12, m5
+    vpermi2q             m9, m6, m4 ;  2  3  6  7
+    vpermt2q             m6, m12, m4
+    vpbroadcastd        m12, [o(pw_2048)]
+    mov                 r3d, 0x00ff00ff
+    mova                m11, m10
+    vpermi2q            m10, m3, m1 ;  8  9 12 13
+    vpermt2q             m3, m13, m1
+    kmovd                k1, r3d
+    vpermi2q            m11, m2, m0 ; 10 11 14 15
+    vpermt2q             m2, m13, m0
+    pxor                 m0, m0
+    vpsubw          m12{k1}, m0, m12
+    pmulhrsw             m0, m7, m12
+    pmulhrsw             m1, m6, m12
+    pmulhrsw             m4, m3, m12
+    pmulhrsw             m5, m2, m12
+    jmp m(idct_16x16_internal_8bpc).end3
+
+INV_TXFM_16X16_FN identity, dct
+INV_TXFM_16X16_FN identity, identity
+
+cglobal iidentity_16x16_internal_8bpc, 0, 6, 0, dst, stride, c, eob, tx2
+    mova                 m8, [o(int16_perm)]
+    vpermb               m1, m8, [cq+64*0] ; a0 b0 a1 b1 a2 b2 a3 b3
+    vpermb               m2, m8, [cq+64*1] ; c0 d0 c1 d1 c2 d2 c3 d3
+    vpbroadcastd         m0, [o(pw_1697x16)]
+    vpermb               m3, m8, [cq+64*2] ; e0 f0 e1 f1 e2 f2 e3 f3
+    vpermb               m4, m8, [cq+64*3] ; g0 h0 g1 h1 g2 h2 g3 h3
+    vpermb               m5, m8, [cq+64*4] ; i0 j0 i1 j1 i2 j2 i3 j3
+    vpermb               m6, m8, [cq+64*5] ; k0 l0 k1 l1 k2 l2 k3 l3
+    vpermb               m7, m8, [cq+64*6] ; m0 n0 m1 n1 m2 n2 m3 n3
+    vpermb               m8, m8, [cq+64*7] ; o0 p0 o1 p1 o2 p2 o3 p3
+    pmulhrsw             m9, m0, m1
+    pmulhrsw            m10, m0, m2
+    pmulhrsw            m11, m0, m3
+    pmulhrsw            m12, m0, m4
+    pmulhrsw            m13, m0, m5
+    pmulhrsw            m14, m0, m6
+    pmulhrsw            m15, m0, m7
+    pmulhrsw             m0, m8
+    REPX       {psraw x, 1}, m9, m10, m11, m12
+    pavgw                m1, m9
+    pavgw                m2, m10
+    pavgw                m3, m11
+    pavgw                m4, m12
+    REPX       {psraw x, 1}, m13, m14, m15, m0
+    pavgw                m5, m13
+    pavgw                m6, m14
+    pavgw                m7, m15
+    pavgw                m8, m0
+    punpckldq            m0, m1, m2 ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckhdq            m1, m2     ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpckldq            m2, m3, m4 ; e0 f0 g0 h0 e1 f1 g1 h1
+    punpckhdq            m3, m4     ; e2 f2 g2 h2 e3 f3 g3 h3
+    punpckldq            m4, m5, m6 ; i0 j0 k0 l0 i1 j1 k1 l1
+    punpckhdq            m5, m6     ; i2 j2 k2 l2 i3 j3 k3 l3
+    punpckldq            m6, m7, m8 ; m0 n0 o0 p0 m1 n1 o1 p1
+    punpckhdq            m7, m8     ; m2 n2 o2 p2 m3 n3 o3 p3
+    jmp                tx2q
+ALIGN function_align
+.pass2:
+    vpbroadcastd        m11, [o(pw_1697x16)]
+    pmulhrsw            m12, m11, m0
+    pmulhrsw            m13, m11, m1
+    pmulhrsw            m14, m11, m2
+    pmulhrsw            m15, m11, m3
+    pmulhrsw             m8, m11, m4
+    pmulhrsw             m9, m11, m5
+    pmulhrsw            m10, m11, m6
+    pmulhrsw            m11, m7
+    REPX      {paddsw x, x}, m0, m1, m2, m3, m4, m5, m6, m7
+    paddsw               m0, m12
+    paddsw               m1, m13
+    paddsw               m2, m14
+    paddsw               m3, m15
+    paddsw               m8, m4
+    movu                 m4, [o(permD+2)]
+    paddsw               m9, m5
+    paddsw               m6, m10
+    paddsw               m7, m11
+    psrlq               m12, m4, 4
+    mova                 m5, m4
+    mova                m10, m4
+    mova                m11, m4
+    vpermi2q             m4, m0, m2  ;  8  9 12 13
+    vpermt2q             m0, m12, m2 ;  0  1  4  5
+    vpermi2q             m5, m1, m3  ; 10 11 14 15
+    vpermt2q             m1, m12, m3 ;  2  3  6  7
+    vpermi2q            m10, m8, m6
+    vpermt2q             m8, m12, m6
+    vpermi2q            m11, m9, m7
+    vpermt2q             m9, m12, m7
+    jmp m(idct_16x16_internal_8bpc).end
+
+%macro ITX_UNPACK_MULHRSW 8 ; dst[1-2], src, tmp, coef[1-4]
+    vpbroadcastd        m%4, [o(pw_%5_%6x8)]
+    punpcklwd           m%1, m%3, m%3
+    pmulhrsw            m%1, m%4
+    vpbroadcastd        m%4, [o(pw_%7_%8x8)]
+    punpckhwd           m%2, m%3, m%3
+    pmulhrsw            m%2, m%4
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_8x32_8bpc, 4, 4, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    cmp                eobd, 107
+    jb .fast
+    mova                 m5, [cq+64*5]
+    mova                 m3, [cq+64*3]
+    mova                 m1, [cq+64*1]
+    mova                 m7, [cq+64*7]
+    mova                 m2, [cq+64*2]
+    mova                 m6, [cq+64*6]
+    mova                 m0, [cq+64*0]
+    mova                 m4, [cq+64*4]
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    mova                 m8, [o(idct_8x32p)]
+    vpbroadcastd         m9, [o(pw_8192)]
+    REPX  {vpermb x, m8, x}, m0, m1, m2, m3, m4, m5, m6, m7
+    punpckldq            m8, m0, m1 ; ab
+    punpckhdq            m0, m1
+    punpckldq            m1, m2, m3 ; cd
+    punpckhdq            m2, m3
+    punpckldq            m3, m4, m5 ; ef
+    punpckhdq            m4, m5
+    punpckldq            m5, m6, m7 ; gh
+    punpckhdq            m6, m7
+    REPX   {pmulhrsw x, m9}, m8, m0, m1, m2, m3, m4, m5, m6
+    punpcklqdq          m18, m8, m1 ; 30  2    6 26   31  1   23  9
+    punpckhqdq          m14, m8, m1 ; 16  0   12 20    3 29   11 21
+    punpcklqdq          m21, m0, m2 ; 14 18   22 10   27  5   19 13
+    punpckhqdq          m15, m0, m2 ; 18  4   24  8    7 25   15 17
+    punpcklqdq          m20, m3, m5
+    punpckhqdq          m16, m3, m5
+    punpcklqdq          m19, m4, m6
+    punpckhqdq          m17, m4, m6
+    vinserti32x4        ym8, ym18, xm20, 1
+    vshufi32x4          ym1, ym18, ym20, 0x03
+    vinserti32x4        ym9, ym14, xm16, 1
+    vshufi32x4          ym3, ym14, ym16, 0x03
+    vinserti32x4        ym0, ym21, xm19, 1
+    vshufi32x4          ym5, ym21, ym19, 0x03
+    vinserti32x4        ym7, ym15, xm17, 1
+    vshufi32x4          ym6, ym15, ym17, 0x03
+    call m(idct_8x16_internal_8bpc).main2
+    psrlq               m12, [o(permB)], 60
+    vpermt2q            m14, m12, m16
+    vpermt2q            m21, m12, m19
+    vpermt2q            m15, m12, m17
+    vpermi2q            m12, m18, m20
+    vextracti32x8      ym16, m14, 1
+    vextracti32x8      ym19, m21, 1
+    vextracti32x8      ym17, m15, 1
+    vextracti32x8      ym20, m12, 1
+    call .main2
+    jmp .end
+.fast: ; right half is zero
+    mova                 m0, [o(int16_perm)]
+    mova                ym2, [cq+64*4]
+    vinserti32x8         m2, [cq+64*0], 1
+    mova                ym3, [cq+64*6]
+    vinserti32x8         m3, [cq+64*2], 1
+    mova                ym4, [cq+64*3]
+    vinserti32x8         m4, [cq+64*5], 1
+    mova                ym5, [cq+64*7]
+    vinserti32x8         m5, [cq+64*1], 1
+    REPX  {vpermb x, m0, x}, m2, m3, m4, m5
+    call m(idct_16x8_internal_8bpc).main2
+    vbroadcasti32x4      m4, [o(int_shuf3)]
+    vbroadcasti32x4      m5, [o(int_shuf4)]
+    pshufb               m2, m4     ; e0 f0 e2 f2 e1 f1 e3 f3
+    pshufb               m3, m5     ; g0 h0 g2 h2 g1 h1 g3 h3
+    pshufb               m0, m4     ; a0 b0 a2 b2 a1 b1 a3 b3
+    pshufb               m1, m5     ; c0 d0 c2 d2 c1 d1 c3 d3
+    vpbroadcastd         m4, [o(pw_8192)]
+    psrlq                m5, [o(permB)], 60
+    punpckldq            m6, m2, m3 ; e0 f0 g0 h0 e2 f2 g2 h2
+    punpckhdq           m17, m2, m3 ; e1 f1 g1 h1 e3 f3 g3 h3
+    punpckldq            m2, m0, m1 ; a0 b0 c0 d0 a2 b2 c2 d2
+    punpckhdq           m16, m0, m1 ; a1 b1 c1 d1 a3 b3 c3 d3
+    REPX   {pmulhrsw x, m4}, m6, m17, m2, m16
+    vinserti32x4        ym0, ym2, xm6, 1      ;  0  2
+    vshufi32x4          ym1, ym2, ym6, 0x03   ;  4  6
+    vinserti32x4       ym14, ym16, xm17, 1    ;  1  3
+    vshufi32x4         ym15, ym16, ym17, 0x03 ;  5  7
+    vpermt2q             m2, m5, m6           ;  8 10
+    vpermt2q            m16, m5, m17          ;  9 11
+    vextracti32x8       ym3, m2, 1            ; 12 14
+    vextracti32x8      ym17, m16, 1           ; 13 15
+    call m(idct_8x16_internal_8bpc).main_fast
+    call .main_fast
+.end:
+    vpbroadcastd        ym8, strided
+    pmulld              ym8, [o(gather8d)]
+    call .main_end
+    lea                  r3, [dstq+strideq*4]
+    kxnorb               k1, k1, k1
+    lea                  r4, [dstq+strideq*8]
+    pxor                 m9, m9
+    lea                  r1, [r3+strideq*8]
+    kmovb                k2, k1
+    vpgatherdq      m12{k1}, [r0+ym8]
+    kmovb                k1, k2
+    vpgatherdq      m13{k2}, [r3+ym8]
+    kmovb                k2, k1
+    vpgatherdq      m14{k1}, [r4+ym8]
+    kmovb                k1, k2
+    vpgatherdq      m15{k2}, [r1+ym8]
+    REPX  {pmulhrsw x, m10}, m0, m1, m2, m3, m4, m5, m6, m7
+    REPX {mova [cq+64*x], m9}, 0, 1, 2, 3, 4, 5, 6, 7
+    punpcklbw           m11, m12, m9
+    punpckhbw           m12, m9
+    paddw                m0, m11
+    paddw                m1, m12
+    packuswb             m0, m1
+    kmovb                k2, k1
+    vpscatterdq [r0+ym8]{k1}, m0
+    punpcklbw           m12, m13, m9
+    punpckhbw           m13, m9
+    paddw                m2, m12
+    paddw                m3, m13
+    packuswb             m2, m3
+    kmovb                k1, k2
+    vpscatterdq [r3+ym8]{k2}, m2
+    punpcklbw           m13, m14, m9
+    punpckhbw           m14, m9
+    paddw                m4, m13
+    paddw                m5, m14
+    packuswb             m4, m5
+    kmovb                k2, k1
+    vpscatterdq [r4+ym8]{k1}, m4
+    punpcklbw           m14, m15, m9
+    punpckhbw           m15, m9
+    paddw                m6, m14
+    paddw                m7, m15
+    packuswb             m6, m7
+    vpscatterdq [r1+ym8]{k2}, m6
+    RET
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 32
+    imul                r6d, 181
+    add                 r6d, 128+512
+    sar                 r6d, 8+2
+    jmp m(inv_txfm_add_dct_dct_8x8_8bpc).dconly2
+INIT_YMM avx512icl
+ALIGN function_align
+cglobal_label .main_fast2 ; bottom three-quarters are zero
+    ITX_UNPACK_MULHRSW   12, 14, 14, 8,  201, 4091,  m601, 4052 ; t16a, t31a, t23a, t24a
+    ITX_UNPACK_MULHRSW   21, 20, 15, 8,  995, 3973, m1380, 3857 ; t20a, t27a, t19a, t28a
+    mova                m11, m12
+    mova                m17, m20
+    mova                m15, m21
+    mova                m16, m14
+    jmp .main4
+ALIGN function_align
+cglobal_label .main_fast ; bottom half is zero
+    ITX_UNPACK_MULHRSW   12, 14, 14, 8,  201, 4091,  m601, 4052 ; t16a, t31a, t23a, t24a
+    ITX_UNPACK_MULHRSW   21, 15, 15, 8,  995, 3973, m1380, 3857 ; t20a, t27a, t19a, t28a
+    ITX_UNPACK_MULHRSW   20, 16, 16, 8, 1751, 3703, m2106, 3513 ; t18a, t29a, t21a, t26a
+    ITX_UNPACK_MULHRSW   19, 17, 17, 8, 2440, 3290, m2751, 3035 ; t22a, t25a, t17a, t30a
+    jmp .main3
+ALIGN function_align
+cglobal_label .main
+    punpcklwd           m12, m21, m14 ; in31 in1
+    punpckhwd           m14, m21      ; in3  in29
+    punpcklwd           m21, m20, m15 ; in27 in5
+    punpckhwd           m15, m20      ; in7  in25
+    punpcklwd           m20, m19, m16 ; in23 in9
+    punpckhwd           m16, m19      ; in11 in21
+    punpcklwd           m19, m18, m17 ; in19 in13
+    punpckhwd           m17, m18      ; in15 in17
+.main2:
+    ITX_MUL2X_PACK       12, 8, 9, 10,  201, 4091, 5 ; t16a, t31a
+    ITX_MUL2X_PACK       14, 8, 9, 10, 4052,  601, 5 ; t23a, t24a
+    ITX_MUL2X_PACK       21, 8, 9, 10,  995, 3973, 5 ; t20a, t27a
+    ITX_MUL2X_PACK       15, 8, 9, 10, 3857, 1380, 5 ; t19a, t28a
+    ITX_MUL2X_PACK       20, 8, 9, 10, 1751, 3703, 5 ; t18a, t29a
+    ITX_MUL2X_PACK       16, 8, 9, 10, 3513, 2106, 5 ; t21a, t26a
+    ITX_MUL2X_PACK       19, 8, 9, 10, 2440, 3290, 5 ; t22a, t25a
+    ITX_MUL2X_PACK       17, 8, 9, 10, 3035, 2751, 5 ; t17a, t30a
+.main3:
+    psubsw              m11, m12, m17 ; t17 t30
+    paddsw              m12, m17      ; t16 t31
+    psubsw              m17, m15, m20 ; t18 t29
+    paddsw              m20, m15      ; t19 t28
+    psubsw              m15, m21, m16 ; t21 t26
+    paddsw              m21, m16      ; t20 t27
+    psubsw              m16, m14, m19 ; t22 t25
+    paddsw              m14, m19      ; t23 t24
+.main4:
+    ITX_MUL2X_PACK       11, 18, 19, 10,   799, 4017, 5 ; t17a t30a
+    ITX_MUL2X_PACK       17, 18, 19, 10, m4017,  799, 5 ; t18a t29a
+    ITX_MUL2X_PACK       15, 18, 19, 10,  3406, 2276, 5 ; t21a t26a
+    ITX_MUL2X_PACK       16, 18, 19, 10, m2276, 3406, 5 ; t22a t25a
+    vpbroadcastd         m8, [o(pw_m3784_1567)]
+    psubsw              m19, m12, m20 ; t19a t28a
+    paddsw              m20, m12      ; t16a t31a
+    psubsw              m12, m14, m21 ; t20a t27a
+    paddsw              m14, m21      ; t23a t24a
+    psubsw              m21, m11, m17 ; t18  t29
+    paddsw              m11, m17      ; t17  t30
+    psubsw              m17, m16, m15 ; t21  t26
+    paddsw              m16, m15      ; t22  t25
+    ITX_MUL2X_PACK       21, 18, 15, 10, 1567_3784, 8,   20 ; t18a t29a
+    ITX_MUL2X_PACK       19, 18, 15, 10, 1567_3784, 8,   20 ; t19  t28
+    ITX_MUL2X_PACK       12, 18, 15, 10, 8, m1567_m3784, 36 ; t20  t27
+    ITX_MUL2X_PACK       17, 18, 15, 10, 8, m1567_m3784, 36 ; t21a t26a
+    vbroadcasti32x4     m18, [o(deint_shuf)]
+    vpbroadcastd         m8, [o(pw_m2896_2896)]
+    vpbroadcastd         m9, [o(pw_2896_2896)]
+    psubsw              m15, m20, m14 ; t23  t24
+    paddsw              m20, m14      ; t16  t31
+    psubsw              m14, m11, m16 ; t22a t25a
+    paddsw              m11, m16      ; t17a t30a
+    psubsw              m16, m21, m17 ; t21  t26
+    paddsw              m21, m17      ; t18  t29
+    psubsw              m17, m19, m12 ; t20a t27a
+    paddsw              m19, m12      ; t19a t28a
+    REPX    {pshufb x, m18}, m20, m11, m21, m19
+    ITX_MUL2X_PACK       15, 18, 12, 10, 8, 9, 8 ; t23a t22a
+    ITX_MUL2X_PACK       14, 13, 15, 10, 8, 9, 8 ; t22  t25
+    packssdw            m18, m13      ; t23a t22
+    packssdw            m12, m15      ; t24a t25
+    ITX_MUL2X_PACK       16, 13, 15, 10, 8, 9, 8 ; t21a t26a
+    ITX_MUL2X_PACK       17, 16, 14, 10, 8, 9, 8 ; t20  t27
+    packssdw            m16, m13      ; t20  t21a
+    packssdw            m14, m15      ; t27  t26a
+    punpcklqdq          m13, m19, m21 ; t19a t18
+    punpckhqdq          m19, m21      ; t28a t29
+    punpcklqdq          m21, m20, m11 ; t16  t17a
+    punpckhqdq          m20, m11      ; t31  t30a
+INIT_ZMM avx512icl
+    mova                m15, [o(permA)]
+    ret
+cglobal_label .main_end
+    vpbroadcastd        m10, [o(pw_2048)]
+    vpermt2q             m0, m15, m1  ; t0   t1   t2   t3
+    vpermt2q            m20, m15, m19 ; t31  t30a t29  t28a
+    vpermt2q             m2, m15, m3  ; t4   t5   t6   t7
+    vpermt2q            m14, m15, m12 ; t27  t26a t25  t24a
+    vpermt2q             m4, m15, m5  ; t8   t9   t10  t11
+    vpermt2q            m18, m15, m16 ; t23a t22  t21a t20
+    vpermt2q             m6, m15, m7  ; t12  t13  t14  t15
+    vpermt2q            m13, m15, m21 ; t19a t18  t17a t16
+    psubsw               m7, m0, m20  ; out31 out30 out29 out28
+    paddsw               m0, m20      ; out0  out1  out2  out3
+    psubsw               m5, m2, m14  ; out27 out26 out25 out24
+    paddsw               m2, m14      ; out4  out5  out6  out7
+    psubsw               m3, m4, m18  ; out23 out22 out21 out20
+    paddsw               m4, m18      ; out8  out9  out10 out11
+    psubsw               m1, m6, m13  ; out19 out18 out17 out16
+    paddsw               m6, m13      ; out12 out13 out14 out15
+    vzeroupper
+    ret
+
+%macro LOAD_PACKED_16X2 3 ; dst, row[1-2]
+    vbroadcasti32x4    ym%1, [cq+16*%2]
+    vbroadcasti32x4     ym8, [cq+16*%3]
+    shufpd             ym%1, ym8, 0x0c
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_32x8_8bpc, 4, 4, 0, dst, stride, c, eob
+%undef cmp
+    test               eobd, eobd
+    jz .dconly
+    lea                  r5, [o_base]
+    LOAD_PACKED_16X2      0,  0,  2 ; in0  in2
+    LOAD_PACKED_16X2      1,  4,  6 ; in4  in6
+    LOAD_PACKED_16X2      2,  8, 10 ; in8  in10
+    LOAD_PACKED_16X2      3, 12, 14 ; in12 in14
+    LOAD_PACKED_16X2     14,  1,  3 ; in1  in3
+    LOAD_PACKED_16X2     15,  5,  7 ; in5  in7
+    LOAD_PACKED_16X2     16,  9, 11 ; in9  in11
+    LOAD_PACKED_16X2     17, 13, 15 ; in13 in15
+    pxor                 m4, m4
+    REPX {mova [cq+64*x], m4}, 0, 1, 2, 3
+    cmp                eobd, 107
+    jb .fast
+    LOAD_PACKED_16X2      4, 16, 18 ; in16 in18
+    LOAD_PACKED_16X2      5, 20, 22 ; in20 in22
+    LOAD_PACKED_16X2      6, 24, 26 ; in24 in26
+    LOAD_PACKED_16X2      7, 28, 30 ; in28 in30
+    call m(idct_8x16_internal_8bpc).main
+    LOAD_PACKED_16X2     18, 19, 17 ; in19 in17
+    LOAD_PACKED_16X2     19, 23, 21 ; in23 in21
+    LOAD_PACKED_16X2     20, 27, 25 ; in27 in25
+    LOAD_PACKED_16X2     21, 31, 29 ; in31 in29
+    pxor                 m8, m8
+    REPX {mova [cq+64*x], m8}, 4, 5, 6, 7
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main
+    jmp .pass2
+.fast: ; bottom half is zero
+    mova                ym5, ym4
+    mova                ym6, ym4
+    mova                ym7, ym4
+    call m(idct_8x16_internal_8bpc).main
+    call m(inv_txfm_add_dct_dct_8x32_8bpc).main_fast
+.pass2:
+    vpbroadcastd        m10, [o(pw_8192)]
+    vpermt2q             m0, m15, m4       ; t0   t1   t9   t8
+    vpermt2q            m20, m15, m18      ; t31  t30a t23a t22
+    vpermt2q             m3, m15, m7       ; t7   t6   t14  t15
+    vpermt2q            m12, m15, m21      ; t25  t24a t17a t16
+    vpermt2q             m2, m15, m6       ; t4   t5   t13  t12
+    vpermt2q            m14, m15, m13      ; t23a t22  t21a t20
+    vpermt2q             m1, m15, m5       ; t3   t2   t10  t11
+    vpermt2q            m19, m15, m16      ; t27  t26a t19a t18
+    psubsw               m8, m0, m20       ; out31 out30 out22 out23
+    paddsw               m0, m20           ; out0  out1  out9  out8
+    paddsw               m6, m3, m12       ; out7  out6  out14 out15
+    psubsw               m3, m12           ; out24 out25 out17 out16
+    psubsw               m5, m2, m14       ; out27 out26 out18 out19
+    paddsw               m4, m2, m14       ; out4  out5  out13 out12
+    psubsw               m7, m1, m19       ; out28 out29 out21 out20
+    paddsw               m2, m1, m19       ; out3  out2  out10 out11
+    vzeroupper
+    vshufi32x4           m1, m0, m3, q1221 ; out1  out9  out17 out25
+    vshufi32x4           m0, m3, q0330     ; out0  out8  out16 out24
+    vshufi32x4           m3, m2, m5, q0330 ; out3  out11 out19 out27
+    vshufi32x4           m2, m5, q1221     ; out2  out10 out18 out26
+    vshufi32x4           m5, m4, m7, q1221 ; out5  out13 out21 out29
+    vshufi32x4           m4, m7, q0330     ; out4  out12 out20 out28
+    vshufi32x4           m7, m6, m8, q0330 ; out7  out15 out23 out31
+    vshufi32x4           m6, m8, q1221     ; out6  out14 out22 out30
+    REPX  {pmulhrsw x, m10}, m0, m1, m2, m3, m4, m5, m6, m7
+    call m(inv_txfm_add_dct_dct_64x32_8bpc).transpose_8x8
+    call .main
+    vpbroadcastd         m8, [o(pw_2048)]
+    REPX   {pmulhrsw x, m8}, m0, m1, m2, m3, m4, m5, m6, m7
+    lea                  r2, [strideq*3]
+    lea                  r3, [dstq+strideq*4]
+    movshdup            m12, [o(permD)]
+    pmovzxbw             m8, [dstq+strideq*0]
+    pmovzxbw             m9, [dstq+strideq*1]
+    pmovzxbw            m10, [dstq+strideq*2]
+    pmovzxbw            m11, [dstq+r2       ]
+    paddw                m0, m8
+    paddw                m1, m9
+    paddw                m2, m10
+    paddw                m3, m11
+    pmovzxbw             m8, [r3+strideq*0]
+    pmovzxbw             m9, [r3+strideq*1]
+    pmovzxbw            m10, [r3+strideq*2]
+    pmovzxbw            m11, [r3+r2       ]
+    paddw                m4, m8
+    paddw                m5, m9
+    paddw                m6, m10
+    paddw                m7, m11
+    packuswb             m0, m1
+    packuswb             m2, m3
+    vpermq               m0, m12, m0
+    vpermq               m2, m12, m2
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym2
+    vextracti32x8 [dstq+r2       ], m2, 1
+    packuswb             m4, m5
+    packuswb             m6, m7
+    vpermq               m4, m12, m4
+    vpermq               m6, m12, m6
+    mova          [r3+strideq*0], ym4
+    vextracti32x8 [r3+strideq*1], m4, 1
+    mova          [r3+strideq*2], ym6
+    vextracti32x8 [r3+r2       ], m6, 1
+    RET
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 8
+.dconly2:
+    imul                r6d, 181
+    add                 r6d, 128+512
+    sar                 r6d, 8+2
+.dconly3:
+    imul                r6d, 181
+    add                 r6d, 128+2048
+    sar                 r6d, 8+4
+    pxor                 m2, m2
+    vpbroadcastw         m3, r6d
+.dconly_loop:
+    mova                ym1, [dstq+strideq*0]
+    vinserti32x8         m1, [dstq+strideq*1], 1
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    paddw                m0, m3
+    paddw                m1, m3
+    packuswb             m0, m1
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                 r3d, 2
+    jg .dconly_loop
+    RET
+ALIGN function_align
+cglobal_label .main
+    vpbroadcastd       m10, [o(pd_2048)]
+.main2:
+    ITX_MULSUB_2W        5, 3, 8, 9, 10, 3406, 2276 ; t5a, t6a
+    ITX_MULSUB_2W        1, 7, 8, 9, 10,  799, 4017 ; t4a, t7a
+    ITX_MULSUB_2W        2, 6, 8, 9, 10, 1567, 3784 ; t2, t3
+    vpbroadcastd       m11, [o(pw_2896_2896)]
+    vpbroadcastd       m12, [o(pw_m2896_2896)]
+    ITX_MULSUB_2W        0, 4, 8, 9, 10, 11, 12 ; t1, t0
+.main3:
+    paddsw              m8, m1, m5 ; t4
+    psubsw              m1, m5     ; t5a
+    paddsw              m9, m7, m3 ; t7
+    psubsw              m7, m3     ; t6a
+    ITX_MULSUB_2W        7, 1, 3, 5, 10, 11, 12 ; t5, t6
+    psubsw              m5, m0, m2 ; dct4 out2
+    paddsw              m2, m0     ; dct4 out1
+    paddsw              m0, m4, m6 ; dct4 out0
+    psubsw              m4, m6     ; dct4 out3
+    psubsw              m6, m2, m1 ; out6
+    paddsw              m1, m2     ; out1
+    paddsw              m2, m5, m7 ; out2
+    psubsw              m5, m7     ; out5
+    psubsw              m7, m0, m9 ; out7
+    paddsw              m0, m9     ; out0
+    paddsw              m3, m4, m8 ; out3
+    psubsw              m4, m8     ; out4
+    ret
+
+cglobal inv_txfm_add_identity_identity_8x32_8bpc, 3, 5, 0, dst, stride, c
+    vpbroadcastd         m7, [pw_5]
+    paddsw               m0, m7, [cq+64*0]
+    paddsw               m1, m7, [cq+64*1]
+    vpbroadcastd        ym9, strided
+    paddsw               m2, m7, [cq+64*2]
+    paddsw               m3, m7, [cq+64*3]
+    paddsw               m4, m7, [cq+64*4]
+    paddsw               m5, m7, [cq+64*5]
+    paddsw               m6, m7, [cq+64*6]
+    paddsw               m7,     [cq+64*7]
+    pmulld             ym14, ym9, [pd_0to15]
+    lea                  r3, [dstq+strideq*1]
+    lea                  r4, [dstq+strideq*2]
+    kxnorb               k1, k1, k1
+    pxor                m13, m13
+    add                  r1, r4 ; dstq+strideq*3
+    kmovb                k2, k1
+    vpgatherdq       m9{k1}, [r0+ym14*4]
+    kmovb                k1, k2
+    vpgatherdq      m10{k2}, [r3+ym14*4]
+    kmovb                k2, k1
+    call m(inv_txfm_add_dct_dct_64x32_8bpc).transpose_8x8
+    REPX       {psraw x, 3}, m0, m1, m2, m3, m4, m5, m6, m7
+    vpgatherdq      m11{k1}, [r4+ym14*4]
+    kmovb                k1, k2
+    vpgatherdq      m12{k2}, [r1+ym14*4]
+    REPX {mova [cq+64*x], m13}, 0, 1, 2, 3, 4, 5, 6, 7
+    punpcklbw            m8, m9, m13  ;  0  8 16 24
+    punpckhbw            m9, m13      ;  4 12 20 28
+    paddw                m0, m8
+    paddw                m4, m9
+    packuswb             m0, m4
+    kmovb                k2, k1
+    vpscatterdq [r0+ym14*4]{k1}, m0
+    punpcklbw            m8, m10, m13 ;  1  9 17 25
+    punpckhbw           m10, m13      ;  5 13 21 29
+    paddw                m1, m8
+    paddw                m5, m10
+    packuswb             m1, m5
+    kmovb                k1, k2
+    vpscatterdq [r3+ym14*4]{k2}, m1
+    punpcklbw            m8, m11, m13 ;  2 10 18 26
+    punpckhbw           m11, m13      ;  6 14 22 30
+    paddw                m2, m8
+    paddw                m6, m11
+    packuswb             m2, m6
+    kmovb                k2, k1
+    vpscatterdq [r4+ym14*4]{k1}, m2
+    punpcklbw            m8, m12, m13 ;  3 11 19 27
+    punpckhbw           m12, m13      ;  7 15 23 31
+    paddw                m3, m8
+    paddw                m7, m12
+    packuswb             m3, m7
+    vpscatterdq [r1+ym14*4]{k2}, m3
+    RET
+
+cglobal inv_txfm_add_identity_identity_32x8_8bpc, 3, 5, 0, dst, stride, c
+    vpbroadcastd         m0, [pw_4096]
+    pmulhrsw             m3, m0, [cq+64*0]
+    pmulhrsw             m4, m0, [cq+64*4]
+    pmulhrsw             m6, m0, [cq+64*1]
+    pmulhrsw             m5, m0, [cq+64*5]
+    pmulhrsw             m7, m0, [cq+64*2]
+    pmulhrsw             m2, m0, [cq+64*6]
+    pmulhrsw             m8, m0, [cq+64*3]
+    pmulhrsw             m0,     [cq+64*7]
+    mova                m13, [int8_permA]
+    lea                  r3, [strideq*3]
+    lea                  r4, [dstq+strideq*4]
+    punpckldq            m1, m3, m4
+    punpckhdq            m3, m4
+    punpckldq            m4, m6, m5
+    punpckhdq            m6, m5
+    punpckldq            m5, m7, m2
+    punpckhdq            m7, m2
+    punpckldq            m2, m8, m0
+    punpckhdq            m8, m0
+    mova                ym9, [dstq+strideq*0]
+    vinserti32x8         m9, [dstq+strideq*2], 1
+    mova               ym10, [dstq+strideq*1]
+    vinserti32x8        m10, [dstq+r3       ], 1
+    mova               ym11, [r4+strideq*0]
+    vinserti32x8        m11, [r4+strideq*2], 1
+    mova               ym12, [r4+strideq*1]
+    vinserti32x8        m12, [r4+r3       ], 1
+    REPX {vpermb x, m13, x}, m1, m4, m5, m2, m3, m6, m7, m8
+    pxor                m13, m13
+    REPX {mova [cq+64*x], m13}, 0, 1, 2, 3, 4, 5, 6, 7
+    punpcklqdq           m0, m1, m4 ; a0 a2   c0 c2
+    punpckhqdq           m1, m4     ; b0 b2   d0 d2
+    punpcklqdq           m4, m5, m2 ; a1 a3   c1 c3
+    punpckhqdq           m5, m2     ; b1 b3   d1 d3
+    punpcklqdq           m2, m3, m6 ; e0 e2   g0 g2
+    punpckhqdq           m3, m6     ; f0 f2   h0 h2
+    punpcklqdq           m6, m7, m8 ; e1 e3   g1 g3
+    punpckhqdq           m7, m8     ; f1 f3   h1 h3
+    punpcklbw            m8, m9, m13
+    punpckhbw            m9, m13
+    paddw                m0, m8
+    paddw                m4, m9
+    packuswb             m0, m4
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*2], m0, 1
+    punpcklbw            m8, m10, m13
+    punpckhbw           m10, m13
+    paddw                m1, m8
+    paddw                m5, m10
+    packuswb             m1, m5
+    mova          [dstq+strideq*1], ym1
+    vextracti32x8 [dstq+r3       ], m1, 1
+    punpcklbw            m8, m11, m13
+    punpckhbw           m11, m13
+    paddw                m2, m8
+    paddw                m6, m11
+    packuswb             m2, m6
+    mova          [r4+strideq*0], ym2
+    vextracti32x8 [r4+strideq*2], m2, 1
+    punpcklbw            m8, m12, m13
+    punpckhbw           m12, m13
+    paddw                m3, m8
+    paddw                m7, m12
+    packuswb             m3, m7
+    mova          [r4+strideq*1], ym3
+    vextracti32x8 [r4+r3       ], m3, 1
+    RET
+
+%macro IDCT_16x32_END 3 ; src[1-2], row
+    mova                xm8, [dstq+strideq*0]
+    vinserti32x4        ym8, [dstq+strideq*1], 1
+    mova                xm9, [dstq+r3       ]
+    vinserti32x4        ym9, [dstq+strideq*2], 1
+    pmulhrsw            m%1, m10
+    pmulhrsw            m%2, m10
+    vpermb               m8, m11, m8
+    vpermb               m9, m11, m9
+    mova   [cq+64*(%3*2+0)], m13
+    mova   [cq+64*(%3*2+1)], m13
+    paddw                m8, m%1
+    paddw                m9, m%2
+    packuswb             m8, m9
+    vpermd               m8, m12, m8
+    mova          [dstq+strideq*0], xm8
+    vextracti32x4 [dstq+strideq*1], ym8, 1
+    vextracti32x4 [dstq+strideq*2], m8, 2
+    vextracti32x4 [dstq+r3       ], m8, 3
+%if %1 != 20
+    lea                dstq, [dstq+strideq*4]
+%endif
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_16x32_8bpc, 4, 4, 22, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    vpbroadcastd        m15, [o(pw_2896x8)]
+    cmp                eobd, 151
+    jb .fast
+    pmulhrsw             m5, m15, [cq+64*10]
+    pmulhrsw             m3, m15, [cq+64* 6]
+    pmulhrsw             m1, m15, [cq+64* 2]
+    pmulhrsw             m7, m15, [cq+64*14]
+    pmulhrsw             m2, m15, [cq+64* 4]
+    pmulhrsw             m6, m15, [cq+64*12]
+    pmulhrsw             m0, m15, [cq+64* 0]
+    pmulhrsw             m4, m15, [cq+64* 8]
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    pmulhrsw            m14, m15, [cq+64* 1]
+    pmulhrsw            m21, m15, [cq+64*15]
+    pmulhrsw            m18, m15, [cq+64* 9]
+    pmulhrsw            m17, m15, [cq+64* 7]
+    pmulhrsw            m16, m15, [cq+64* 5]
+    pmulhrsw            m19, m15, [cq+64*11]
+    pmulhrsw            m20, m15, [cq+64*13]
+    pmulhrsw            m15,      [cq+64* 3]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    mova                 m8, [o(idct_16x32p)]
+    vpbroadcastd         m9, [o(pw_16384)]
+    REPX {vpermb x, m8, x}, m0,  m1,  m2,  m3,  m4,  m5,  m6,  m7, \
+                            m14, m15, m16, m17, m18, m19, m20, m21
+    punpckldq            m8, m0, m1
+    punpckhdq            m0, m1
+    punpckldq            m1, m2, m3
+    punpckhdq            m2, m3
+    REPX   {pmulhrsw x, m9}, m8, m0, m1, m2
+    punpckldq            m3, m4, m5
+    punpckhdq            m4, m5
+    punpckldq            m5, m6, m7
+    punpckhdq            m6, m7
+    REPX   {pmulhrsw x, m9}, m3, m4, m5, m6
+    punpckldq            m7, m14, m15
+    punpckhdq           m14, m15
+    punpckldq           m15, m16, m17
+    punpckhdq           m16, m17
+    REPX   {pmulhrsw x, m9}, m7, m14, m15, m16
+    punpckldq           m17, m18, m19
+    punpckhdq           m18, m19
+    punpckldq           m19, m20, m21
+    punpckhdq           m20, m21
+    REPX   {pmulhrsw x, m9}, m17, m18, m19, m20
+    punpcklqdq          m21, m8, m1
+    punpckhqdq           m8, m1
+    punpcklqdq           m1, m0, m2
+    punpckhqdq           m0, m2
+    punpcklqdq           m2, m3, m5
+    punpckhqdq           m3, m5
+    punpcklqdq           m5, m4, m6
+    punpckhqdq           m4, m6
+    punpcklqdq           m6, m7, m15
+    punpckhqdq           m7, m15
+    punpcklqdq          m15, m14, m16
+    punpckhqdq          m14, m16
+    punpcklqdq          m16, m17, m19
+    punpckhqdq          m17, m19
+    punpcklqdq          m19, m18, m20
+    punpckhqdq          m18, m20
+    vinserti32x8        m20, m21, ym2, 1
+    vshufi32x4          m21, m2, q3232
+    vinserti32x8         m2, m8, ym3, 1
+    vshufi32x4           m8, m3, q3232
+    vinserti32x8         m3, m1, ym5, 1
+    vshufi32x4           m1, m5, q3232
+    vinserti32x8         m5, m0, ym4, 1
+    vshufi32x4           m0, m4, q3232
+    vinserti32x8         m4, m6, ym16, 1
+    vshufi32x4           m6, m16, q3232
+    vinserti32x8        m16, m7, ym17, 1
+    vshufi32x4           m7, m17, q3232
+    vinserti32x8        m17, m15, ym19, 1
+    vshufi32x4          m15, m19, q3232
+    vinserti32x8        m19, m14, ym18, 1
+    vshufi32x4          m14, m18, q3232
+    vshufi32x4          m18, m21, m6, q3131 ; 27  5
+    vshufi32x4          m21, m6, q2020      ; 31  1
+    vshufi32x4           m6, m8, m7, q2020  ; 24  8
+    vshufi32x4           m8, m7, q3131      ; 30  2
+    vshufi32x4           m7, m1, m15, q2020 ; 28  4
+    vshufi32x4           m1, m15, q3131     ;  6 26
+    vshufi32x4          m15, m0, m14, q2020 ;  7 25
+    vshufi32x4           m0, m14, q3131     ; 14 18
+    vshufi32x4          m14, m20, m4, q2020 ;  3 29
+    vshufi32x4          m20, m4, q3131      ; 23  9
+    vshufi32x4           m9, m3, m17, q2020 ; 16  0
+    vshufi32x4           m3, m17, q3131     ; 12 20
+    vshufi32x4          m17, m5, m19, q2020 ; 15 17
+    vshufi32x4           m5, m19, q3131     ; 22 10
+    vshufi32x4          m19, m2, m16, q2020 ; 19 13
+    vshufi32x4          m16, m2, m16, q3131 ; 11 21
+    call m(idct_16x16_internal_8bpc).main3
+    call .main_oddhalf
+    jmp .pass2
+.fast: ; right half is zero
+    mova                ym8, [cq+64*15]
+    vinserti32x8         m8, [cq+64* 1], 1
+    mova                 m2, [o(int16_perm)]
+    mova                ym9, [cq+64* 8]
+    vinserti32x8         m9, [cq+64* 0], 1
+    mova                ym0, [cq+64* 7]
+    vinserti32x8         m0, [cq+64* 9], 1
+    mova                ym7, [cq+64*14]
+    vinserti32x8         m7, [cq+64* 2], 1
+    mova                ym1, [cq+64* 3]
+    vinserti32x8         m1, [cq+64*13], 1
+    mova                ym3, [cq+64* 6]
+    vinserti32x8         m3, [cq+64*10], 1
+    mova                ym5, [cq+64*11]
+    vinserti32x8         m5, [cq+64* 5], 1
+    mova                ym6, [cq+64*12]
+    vinserti32x8         m6, [cq+64* 4], 1
+    REPX  {pmulhrsw x, m15}, m8, m9, m0, m7, m1, m3, m5, m6
+    REPX  {vpermb x, m2, x}, m8, m9, m0, m7, m1, m3, m5, m6
+    call m(idct_16x16_internal_8bpc).main2
+    vbroadcasti32x4      m8, [o(int_shuf3)]
+    vbroadcasti32x4      m9, [o(int_shuf4)]
+    vpbroadcastd        m11, [o(pw_16384)]
+    pshufb               m0, m8
+    pshufb               m1, m9
+    pshufb               m2, m8
+    pshufb               m3, m9
+    REPX  {pmulhrsw x, m11}, m0, m1, m2, m3
+    pshufb               m4, m8
+    pshufb               m5, m9
+    pshufb               m6, m8
+    pshufb               m7, m9
+    REPX  {pmulhrsw x, m11}, m4, m5, m6, m7
+    punpckhdq           m17, m0, m1
+    punpckldq            m0, m1
+    punpckhdq           m16, m2, m3
+    punpckldq            m2, m3
+    punpckhdq           m18, m4, m5
+    punpckldq            m4, m5
+    punpckhdq            m5, m6, m7
+    punpckldq            m6, m7
+    vinserti32x8         m1, m0, ym2, 1
+    vshufi32x4           m3, m0, m2, q3232
+    vinserti32x8         m2, m4, ym6, 1
+    vshufi32x4           m4, m6, q3232
+    vinserti32x8        m15, m17, ym16, 1
+    vshufi32x4          m17, m16, q3232
+    vinserti32x8        m16, m18, ym5, 1
+    vshufi32x4          m18, m5, q3232
+    vshufi32x4           m0, m1, m2, q2020   ;  0  2
+    vshufi32x4           m1, m2, q3131       ;  4  6
+    vshufi32x4           m2, m3, m4, q2020   ;  8 10
+    vshufi32x4           m3, m4, q3131       ; 12 14
+    vshufi32x4          m14, m15, m16, q2020 ;  1  3
+    vshufi32x4          m15, m16, q3131      ;  5  7
+    vshufi32x4          m16, m17, m18, q2020 ;  9 11
+    vshufi32x4          m17, m18, q3131      ; 13 15
+    pxor                 m6, m6
+    punpckhwd            m8, m0, m0
+    punpcklwd            m9, m6, m0
+    punpckhwd            m0, m3, m3
+    punpckhwd            m5, m2, m2
+    punpcklwd            m7, m1, m1
+    punpckhwd            m1, m1
+    punpcklwd            m3, m3
+    punpcklwd            m6, m2
+    call m(idct_16x16_internal_8bpc).main_fast5
+    punpcklwd           m21, m14, m14
+    punpckhwd           m14, m14
+    punpcklwd           m18, m15, m15
+    punpckhwd           m15, m15
+    punpcklwd           m20, m16, m16
+    punpckhwd           m16, m16
+    punpcklwd           m19, m17, m17
+    punpckhwd           m17, m17
+    call .main_oddhalf_fast
+.pass2:
+    vpbroadcastd        m10, [o(pw_2048)]
+    mova                m11, [o(end_16x32p)]
+    lea                  r3, [strideq*3]
+    pxor                m13, m13
+    psrld               m12, m11, 8
+    IDCT_16x32_END        0,  1,  0
+    IDCT_16x32_END        2,  3,  1
+    IDCT_16x32_END        4,  5,  2
+    IDCT_16x32_END        6,  7,  3
+    IDCT_16x32_END       14, 15,  4
+    IDCT_16x32_END       16, 17,  5
+    IDCT_16x32_END       18, 19,  6
+    IDCT_16x32_END       20, 21,  7
+    RET
+ALIGN function_align
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 32
+    jmp m(inv_txfm_add_dct_dct_16x8_8bpc).dconly
+ALIGN function_align
+cglobal_label .main_oddhalf_fast2 ; bottom three-quarters are zero
+    vpbroadcastd         m8, [o(pw_201_4091x8)]
+    vpbroadcastd        m20, [o(pw_m1380_3857x8)]
+    vpbroadcastd         m9, [o(pw_995_3973x8)]
+    vpbroadcastd        m16, [o(pw_m601_4052x8)]
+    pmulhrsw            m21, m8  ; t16a, t31a
+    pmulhrsw            m20, m15 ; t19a, t28a
+    pmulhrsw            m18, m9  ; t20a, t27a
+    pmulhrsw            m14, m16 ; t23a, t24a
+    mova                 m8, m21
+    mova                m17, m20
+    mova                m15, m18
+    mova                m16, m14
+    jmp .main3
+ALIGN function_align
+cglobal_label .main_oddhalf_fast ; bottom half is zero
+    vpbroadcastd         m8, [o(pw_201_4091x8)]
+    vpbroadcastd         m9, [o(pw_m2751_3035x8)]
+    vpbroadcastd        m11, [o(pw_1751_3703x8)]
+    vpbroadcastd        m12, [o(pw_m1380_3857x8)]
+    pmulhrsw            m21, m8  ; t16a, t31a
+    vpbroadcastd         m8, [o(pw_995_3973x8)]
+    pmulhrsw            m17, m9  ; t17a, t30a
+    vpbroadcastd         m9, [o(pw_m2106_3513x8)]
+    pmulhrsw            m20, m11 ; t18a, t29a
+    vpbroadcastd        m11, [o(pw_2440_3290x8)]
+    pmulhrsw            m15, m12 ; t19a, t28a
+    vpbroadcastd        m12, [o(pw_m601_4052x8)]
+    pmulhrsw            m18, m8  ; t20a, t27a
+    pmulhrsw            m16, m9  ; t21a, t26a
+    pmulhrsw            m19, m11 ; t22a, t25a
+    pmulhrsw            m14, m12 ; t23a, t24a
+    jmp .main2
+ALIGN function_align
+cglobal_label .main_oddhalf
+    ITX_MUL2X_PACK       21, 8, 9, 10,  201, 4091, 5 ; t16a, t31a
+    ITX_MUL2X_PACK       17, 8, 9, 10, 3035, 2751, 5 ; t17a, t30a
+    ITX_MUL2X_PACK       20, 8, 9, 10, 1751, 3703, 5 ; t18a, t29a
+    ITX_MUL2X_PACK       15, 8, 9, 10, 3857, 1380, 5 ; t19a, t28a
+    ITX_MUL2X_PACK       18, 8, 9, 10,  995, 3973, 5 ; t20a, t27a
+    ITX_MUL2X_PACK       16, 8, 9, 10, 3513, 2106, 5 ; t21a, t26a
+    ITX_MUL2X_PACK       19, 8, 9, 10, 2440, 3290, 5 ; t22a, t25a
+    ITX_MUL2X_PACK       14, 8, 9, 10, 4052,  601, 5 ; t23a, t24a
+.main2:
+    psubsw               m8, m21, m17 ; t17 t30
+    paddsw              m21, m17      ; t16 t31
+    psubsw              m17, m15, m20 ; t18 t29
+    paddsw              m20, m15      ; t19 t28
+    psubsw              m15, m18, m16 ; t21 t26
+    paddsw              m18, m16      ; t20 t27
+    psubsw              m16, m14, m19 ; t22 t25
+    paddsw              m14, m19      ; t23 t24
+.main3:
+    ITX_MUL2X_PACK        8, 9, 19, 10,   799, 4017, 5 ; t17a t30a
+    ITX_MUL2X_PACK       17, 9, 19, 10, m4017,  799, 5 ; t18a t29a
+    ITX_MUL2X_PACK       15, 9, 19, 10,  3406, 2276, 5 ; t21a t26a
+    ITX_MUL2X_PACK       16, 9, 19, 10, m2276, 3406, 5 ; t22a t25a
+    vpbroadcastd        m11, [o(pw_m3784_1567)]
+    psubsw              m19, m21, m20 ; t19a t28a
+    paddsw              m21, m20      ; t16a t31a
+    psubsw              m20, m14, m18 ; t20a t27a
+    paddsw              m14, m18      ; t23a t24a
+    psubsw              m18, m8, m17  ; t18  t29
+    paddsw               m8, m17      ; t17  t30
+    psubsw              m17, m16, m15 ; t21  t26
+    paddsw              m15, m16      ; t22  t25
+    ITX_MUL2X_PACK       18, 9, 16, 10, 1567_3784, 11,   20 ; t18a t29a
+    ITX_MUL2X_PACK       19, 9, 16, 10, 1567_3784, 11,   20 ; t19  t28
+    ITX_MUL2X_PACK       20, 9, 16, 10, 11, m1567_m3784, 36 ; t20  t27
+    ITX_MUL2X_PACK       17, 9, 16, 10, 11, m1567_m3784, 36 ; t21a t26a
+    vbroadcasti32x4      m9, [o(deint_shuf)]
+    psubsw              m16, m21, m14 ; t23  t24
+    paddsw              m14, m21      ; t16  t31
+    psubsw              m21, m8, m15  ; t22a t25a
+    paddsw              m15, m8       ; t17a t30a
+    psubsw               m8, m18, m17 ; t21  t26
+    paddsw              m18, m17      ; t18  t29
+    paddsw              m17, m19, m20 ; t19a t28a
+    psubsw              m19, m20      ; t20a t27a
+    vpbroadcastd        m11, [o(pw_m2896_2896)]
+    vpbroadcastd        m12, [o(pw_2896_2896)]
+    REPX     {pshufb x, m9}, m14, m15, m18, m17
+    mova                 m9, m10
+    vpdpwssd             m9, m16, m11
+    mova                m20, m10
+    vpdpwssd            m20, m21, m11
+    psrad                m9, 12
+    psrad               m20, 12
+    packssdw             m9, m20      ; t23a t22
+    mova                m20, m10
+    vpdpwssd            m20, m16, m12
+    mova                m16, m10
+    vpdpwssd            m16, m21, m12
+    psrad               m20, 12
+    psrad               m16, 12
+    packssdw            m16, m20, m16 ; t24a t25
+    ITX_MUL2X_PACK        8, 21, 20, 10, 11, 12, 8 ; t21a t26a
+    ITX_MUL2X_PACK       19,  8, 11, 10, 11, 12, 8 ; t20  t27
+    packssdw            m11, m20      ; t27  t26a
+    packssdw             m8, m21      ; t20  t21a
+    punpcklqdq          m20, m14, m15 ; t16  t17a
+    punpckhqdq          m14, m15      ; t31  t30a
+    punpckhqdq          m15, m17, m18 ; t28a t29
+    punpcklqdq          m17, m18      ; t19a t18
+    psubsw              m21, m0, m14  ; out31 out30
+    paddsw               m0, m14      ; out0  out1
+    psubsw              m14, m7, m20  ; out16 out17
+    paddsw               m7, m20      ; out15 out14
+    psubsw              m20, m1, m15  ; out28 out29
+    paddsw               m1, m15      ; out3  out2
+    psubsw              m15, m6, m17  ; out19 out18
+    paddsw               m6, m17      ; out12 out13
+    psubsw              m17, m4, m9   ; out23 out22
+    paddsw               m4, m9       ; out8  out9
+    psubsw              m18, m3, m16  ; out24 out25
+    paddsw               m3, m16      ; out7  out6
+    psubsw              m16, m5, m8   ; out20 out21
+    paddsw               m5, m8       ; out11 out10
+    psubsw              m19, m2, m11  ; out27 out26
+    paddsw               m2, m11      ; out4  out5
+    ret
+
+cglobal inv_txfm_add_dct_dct_32x16_8bpc, 4, 6, 22, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    mova                m21, [o(permB)]
+    vpermq               m1, m21, [cq+64* 0] ;  0  1
+    vpermq              m14, m21, [cq+64* 1] ;  2  3
+    vpermq              m20, m21, [cq+64* 2] ;  4  5
+    vpermq              m15, m21, [cq+64* 3] ;  6  7
+    vpbroadcastd         m8, [o(pw_2896x8)]
+    vpermq               m2, m21, [cq+64* 4] ;  8  9
+    vpermq              m16, m21, [cq+64* 5] ; 10 11
+    vpermq               m3, m21, [cq+64* 6] ; 12 13
+    vpermq              m17, m21, [cq+64* 7] ; 14 15
+    REPX   {pmulhrsw x, m8}, m1, m14, m20, m15, m2, m16, m3, m17
+    pxor                m12, m12
+    REPX {mova [cq+64*x], m12}, 0, 1, 2, 3, 4, 5, 6, 7
+    cmp                eobd, 151
+    jb .fast
+    vpermq               m9, m21, [cq+64* 8] ; 16 17
+    vpermq              m19, m21, [cq+64* 9] ; 18 19
+    vpermq               m4, m21, [cq+64*10] ; 20 21
+    vpermq               m5, m21, [cq+64*11] ; 22 23
+    vpermq               m6, m21, [cq+64*12] ; 24 25
+    vpermq              m18, m21, [cq+64*13] ; 26 27
+    vpermq               m7, m21, [cq+64*14] ; 28 29
+    vpermq              m21, m21, [cq+64*15] ; 30 31
+    REPX   {pmulhrsw x, m8}, m9, m19, m4, m5, m6, m18, m7, m21
+    REPX {mova [cq+64*x], m12}, 8, 9, 10, 11, 12, 13, 14, 15
+    punpcklwd            m8, m21, m14 ; 30  2
+    punpckhwd           m21, m1       ; 31  1
+    punpcklwd            m0, m17, m19 ; 14 18
+    punpckhwd           m17, m9       ; 15 17
+    punpcklwd            m9, m1       ; 16  0
+    punpckhwd           m14, m7       ;  3 29
+    punpcklwd            m1, m15, m18 ;  6 26
+    punpckhwd           m15, m6       ;  7 25
+    punpcklwd            m6, m2       ; 24  8
+    punpckhwd           m19, m3       ; 19 13
+    punpcklwd            m3, m4       ; 12 20
+    punpckhwd           m18, m20      ; 27  5
+    punpcklwd            m7, m20      ; 28  4
+    punpckhwd           m20, m5, m2   ; 23  9
+    punpcklwd            m5, m16      ; 22 10
+    punpckhwd           m16, m4       ; 11 21
+    call m(idct_16x16_internal_8bpc).main2
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf
+    jmp .pass2
+.fast: ; bottom half zero
+    punpcklwd            m8, m14, m14 ;  2
+    punpcklwd            m0, m17, m17 ; 14
+    punpcklwd            m5, m16, m16 ; 10
+    punpcklwd            m9, m12, m1  ; __  0
+    punpckhwd           m21, m1, m1   ;  1
+    punpcklwd            m1, m15, m15 ;  6
+    punpcklwd            m7, m20, m20 ;  4
+    punpckhwd           m19, m3, m3   ; 13
+    punpcklwd            m3, m3       ; 12
+    punpcklwd            m6, m12, m2  ; __  8
+    punpckhwd           m18, m20, m20 ;  5
+    punpckhwd           m20, m2, m2   ;  9
+    call m(idct_16x16_internal_8bpc).main_fast
+    punpckhwd           m15, m15      ;  7
+    punpckhwd           m14, m14      ;  3
+    punpckhwd           m16, m16      ; 11
+    punpckhwd           m17, m17      ; 15
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+.pass2:
+    vpbroadcastd         m9, [o(pw_16384)]
+    call .transpose_round
+    vshufi32x4          m16, m14, m2, q3131 ;  5
+    vshufi32x4          m14, m2, q2020      ;  1
+    vshufi32x4           m2, m0, m3, q3131  ;  4
+    vshufi32x4           m0, m3, q2020      ;  0
+    vshufi32x4           m3, m1, m18, q3131 ;  6
+    vshufi32x4           m1, m18, q2020     ;  2
+    vshufi32x4          m18, m20, m6, q2020 ;  9
+    vshufi32x4          m20, m6, q3131      ; 13
+    vshufi32x4           m6, m21, m4, q3131 ; 12
+    vshufi32x4           m4, m21, m4, q2020 ;  8
+    vshufi32x4          m21, m19, m7, q3131 ; 15
+    vshufi32x4          m19, m7, q2020      ; 11
+    vshufi32x4           m7, m5, m15, q3131 ; 14
+    vshufi32x4           m5, m15, q2020     ; 10
+    vshufi32x4          m15, m17, m9, q2020 ;  3
+    vshufi32x4          m17, m9, q3131      ;  7
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main2
+    call .main_oddhalf
+    vpbroadcastd        m12, [o(pw_2048)]
+    movshdup            m13, [o(permD)]
+    lea                  r2, [strideq*3]
+    pmovzxbw             m8, [dstq+strideq*0]
+    pmovzxbw             m9, [dstq+strideq*1]
+    pmovzxbw            m10, [dstq+strideq*2]
+    pmovzxbw            m11, [dstq+r2       ]
+    REPX  {pmulhrsw x, m12}, m0, m1, m2, m3
+    lea                  r3, [dstq+strideq*4]
+    paddw                m0, m8
+    paddw                m1, m9
+    paddw                m2, m10
+    paddw                m3, m11
+    pmovzxbw             m8, [r3+strideq*0]
+    pmovzxbw             m9, [r3+strideq*1]
+    pmovzxbw            m10, [r3+strideq*2]
+    pmovzxbw            m11, [r3+r2       ]
+    REPX  {pmulhrsw x, m12}, m4, m5, m6, m7
+    lea                  r4, [dstq+strideq*8]
+    packuswb             m0, m1
+    paddw                m4, m8
+    paddw                m5, m9
+    packuswb             m2, m3
+    paddw                m6, m10
+    paddw                m7, m11
+    pmovzxbw             m8, [r4+strideq*0]
+    pmovzxbw             m9, [r4+strideq*1]
+    pmovzxbw            m10, [r4+strideq*2]
+    pmovzxbw            m11, [r4+r2       ]
+    REPX  {pmulhrsw x, m12}, m14, m15, m16, m17
+    lea                  r5, [r3+strideq*8]
+    packuswb             m4, m5
+    paddw               m14, m8
+    paddw               m15, m9
+    packuswb             m6, m7
+    paddw               m16, m10
+    paddw               m17, m11
+    pmovzxbw             m8, [r5+strideq*0]
+    pmovzxbw             m9, [r5+strideq*1]
+    pmovzxbw            m10, [r5+strideq*2]
+    pmovzxbw            m11, [r5+r2       ]
+    REPX  {pmulhrsw x, m12}, m18, m19, m20, m21
+    packuswb            m14, m15
+    paddw               m18, m8
+    paddw               m19, m9
+    packuswb            m16, m17
+    paddw               m20, m10
+    paddw               m21, m11
+    packuswb            m18, m19
+    packuswb            m20, m21
+    REPX {vpermq x, m13, x}, m0, m2, m4, m6, m14, m16, m18, m20
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym2
+    vextracti32x8 [dstq+r2       ], m2, 1
+    mova          [r3+strideq*0], ym4
+    vextracti32x8 [r3+strideq*1], m4, 1
+    mova          [r3+strideq*2], ym6
+    vextracti32x8 [r3+r2       ], m6, 1
+    mova          [r4+strideq*0], ym14
+    vextracti32x8 [r4+strideq*1], m14, 1
+    mova          [r4+strideq*2], ym16
+    vextracti32x8 [r4+r2       ], m16, 1
+    mova          [r5+strideq*0], ym18
+    vextracti32x8 [r5+strideq*1], m18, 1
+    mova          [r5+strideq*2], ym20
+    vextracti32x8 [r5+r2       ], m20, 1
+    RET
+ALIGN function_align
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 16
+    imul                r6d, 181
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 128+256
+    sar                 r6d, 8+1
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).dconly3
+ALIGN function_align
+cglobal_label .main_oddhalf_fast3 ; bottom seven-eights are zero
+    vpbroadcastd         m8, [o(pw_2896x8)]
+    vpbroadcastd         m4, [o(pw_4076x8)]
+    vpbroadcastd         m3, [o(pw_401x8)]
+    pmulhrsw             m8, m0  ; t0
+    pmulhrsw             m4, m14 ; t15a
+    pmulhrsw             m3, m14 ; t8a
+    punpcklwd            m9, m3, m4
+    punpckhwd            m5, m3, m4
+    mova                 m2, m10
+    vpdpwssd             m2, m9, [o(pw_m3784_1567)] {bcstd}
+    mova                 m1, m10
+    vpdpwssd             m1, m5, [o(pw_m3784_1567)] {bcstd}
+    mova                 m6, m10
+    vpdpwssd             m6, m5, [o(pw_1567_3784)] {bcstd}
+    mova                 m5, m10
+    vpdpwssd             m5, m9, [o(pw_1567_3784)] {bcstd}
+    vpbroadcastd        m11, [o(pw_2896_2896)]
+    vpbroadcastd        m12, [o(pw_m2896_2896)]
+    psubsw              m21, m8, m4 ; out15
+    paddsw               m0, m8, m4 ; out0
+    psubsw              m14, m8, m3 ; out8
+    paddsw               m7, m8, m3 ; out7
+    REPX      {psrad x, 12}, m2, m1, m6, m5
+    packssdw             m2, m1     ; t9a
+    packssdw             m5, m6     ; t14a
+    ITX_MULSUB_2W         4, 3, 16, 17, 10, 11, 12 ; t11,  t12
+    psubsw              m20, m8, m5 ; out14
+    paddsw               m1, m8, m5 ; out1
+    psubsw              m15, m8, m2 ; out9
+    paddsw               m6, m8, m2 ; out6
+    ITX_MULSUB_2W         5, 2, 16, 17, 10, 11, 12 ; t10a, t13a
+    psubsw              m18, m8, m3 ; out12
+    paddsw               m3, m8     ; out3
+    psubsw              m17, m8, m4 ; out11
+    paddsw               m4, m8     ; out4
+    psubsw              m19, m8, m2 ; out13
+    paddsw               m2, m8     ; out2
+    psubsw              m16, m8, m5 ; out10
+    paddsw               m5, m8     ; out5
+    ret
+cglobal_label .main_oddhalf_fast2 ; bottom three-quarters are zero
+    vpbroadcastd         m9, [o(pw_2896x8)]
+    vpbroadcastd         m2, [o(pw_4017x8)]
+    vpbroadcastd         m3, [o(pw_799x8)]
+    vpbroadcastd        m18, [o(pw_4076x8)]
+    vpbroadcastd        m19, [o(pw_401x8)]
+    vpbroadcastd        m20, [o(pw_m1189x8)]
+    vpbroadcastd        m16, [o(pw_3920x8)]
+    pmulhrsw             m9, m0  ; t0
+    pmulhrsw             m2, m1  ; t7a
+    pmulhrsw             m1, m3  ; t4a
+    pmulhrsw            m18, m14 ; t15a
+    pmulhrsw            m14, m19 ; t8a
+    pmulhrsw            m20, m15 ; t11a
+    pmulhrsw            m15, m16 ; t12a
+    psubsw               m7, m9, m2 ; idct8 out7
+    paddsw               m0, m9, m2 ; idct8 out0
+    psubsw               m4, m9, m1 ; idct8 out4
+    paddsw               m3, m9, m1 ; idct8 out3
+    ITX_MULSUB_2W         2, 1, 5, 6, 10, 2896, 2896 ; t5, t6
+    mova                m21, m18
+    mova                m19, m14
+    mova                m16, m15
+    mova                 m8, m20
+    psubsw               m6, m9, m1 ; idct8 out6
+    paddsw               m1, m9     ; idct8 out1
+    psubsw               m5, m9, m2 ; idct8 out5
+    paddsw               m2, m9     ; idct8 out2
+    jmp .main3
+ALIGN function_align
+cglobal_label .main_oddhalf_fast ; bottom half is zero
+    vpbroadcastd         m5, [o(pw_m2276x8)]
+    vpbroadcastd        m11, [o(pw_3406x8)]
+    vpbroadcastd         m7, [o(pw_4017x8)]
+    vpbroadcastd        m12, [o(pw_799x8)]
+    vpbroadcastd         m6, [o(pw_3784x8)]
+    vpbroadcastd        m10, [o(pw_1567x8)]
+    vpbroadcastd         m4, [o(pw_2896x8)]
+    pmulhrsw             m5, m3  ; t5a
+    pmulhrsw             m3, m11 ; t6a
+    pmulhrsw             m7, m1  ; t7a
+    pmulhrsw             m1, m12 ; t4a
+    pmulhrsw             m6, m2  ; t3
+    pmulhrsw             m2, m10 ; t2
+    pmulhrsw             m4, m0  ; t0
+    vpbroadcastd        m11, [o(pw_2896_2896)]
+    vpbroadcastd        m12, [o(pw_m2896_2896)]
+    vpbroadcastd        m10, [o(pd_2048)]
+    mova                 m0, m4  ; t1
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main3
+    vpbroadcastd        m21, [o(pw_4076x8)]
+    vpbroadcastd         m8, [o(pw_401x8)]
+    vpbroadcastd        m18, [o(pw_m2598x8)]
+    vpbroadcastd         m9, [o(pw_3166x8)]
+    vpbroadcastd        m19, [o(pw_3612x8)]
+    vpbroadcastd        m11, [o(pw_1931x8)]
+    vpbroadcastd        m20, [o(pw_m1189x8)]
+    vpbroadcastd        m12, [o(pw_3920x8)]
+    pmulhrsw            m21, m14 ; t15a
+    pmulhrsw            m14, m8  ; t8a
+    pmulhrsw            m18, m17 ; t9a
+    pmulhrsw            m17, m9  ; t14a
+    pmulhrsw            m19, m16 ; t13a
+    pmulhrsw            m16, m11 ; t10a
+    pmulhrsw            m20, m15 ; t11a
+    pmulhrsw            m15, m12 ; t12a
+    jmp .main2
+ALIGN function_align
+cglobal_label .main_oddhalf
+    ITX_MULSUB_2W        14, 21, 8, 9, 10,  401, 4076 ; t8a,  t15a
+    ITX_MULSUB_2W        18, 17, 8, 9, 10, 3166, 2598 ; t9a,  t14a
+    ITX_MULSUB_2W        16, 19, 8, 9, 10, 1931, 3612 ; t10a, t13a
+    ITX_MULSUB_2W        20, 15, 8, 9, 10, 3920, 1189 ; t11a, t12a
+.main2:
+    paddsw               m8, m20, m16 ; t11
+    psubsw              m20, m16      ; t10
+    paddsw              m16, m15, m19 ; t12
+    psubsw              m15, m19      ; t13
+    psubsw              m19, m14, m18 ; t9
+    paddsw              m14, m18      ; t8
+    psubsw              m18, m21, m17 ; t14
+    paddsw              m21, m17      ; t15
+.main3:
+    vpbroadcastd        m11, [o(pw_1567_3784)]
+    vpbroadcastd        m12, [o(pw_m3784_1567)]
+    ITX_MULSUB_2W        18, 19, 9, 17, 10, 11, 12 ; t9a,  t14a
+    vpbroadcastd        m11, [o(pw_m1567_m3784)]
+    ITX_MULSUB_2W        15, 20, 9, 17, 10, 12, 11 ; t10a, t13a
+    vpbroadcastd        m11, [o(pw_2896_2896)]
+    vpbroadcastd        m12, [o(pw_m2896_2896)]
+    psubsw              m17, m14, m8  ; t11a
+    paddsw               m8, m14      ; t8a
+    paddsw              m14, m18, m15 ; t9
+    psubsw              m18, m15      ; t10
+    psubsw              m15, m19, m20 ; t13
+    paddsw              m19, m20      ; t14
+    paddsw              m20, m21, m16 ; t15a
+    psubsw              m16, m21, m16 ; t12a
+    ITX_MULSUB_2W        15, 18, 9, 21, 10, 11, 12 ; t10a, t13a
+    ITX_MULSUB_2W        16, 17, 9, 21, 10, 11, 12 ; t11,  t12
+    psubsw              m21, m0, m20 ; out15
+    paddsw               m0, m20     ; out0
+    psubsw              m20, m1, m19 ; out14
+    paddsw               m1, m19     ; out1
+    psubsw              m19, m2, m18 ; out13
+    paddsw               m2, m18     ; out2
+    psubsw              m18, m3, m17 ; out12
+    paddsw               m3, m17     ; out3
+    psubsw              m17, m4, m16 ; out11
+    paddsw               m4, m16     ; out4
+    psubsw              m16, m5, m15 ; out10
+    paddsw               m5, m15     ; out5
+    psubsw              m15, m6, m14 ; out9
+    paddsw               m6, m14     ; out6
+    psubsw              m14, m7, m8  ; out8
+    paddsw               m7, m8      ; out7
+    ret
+.transpose_round:
+    punpcklwd            m8, m0, m2
+    punpckhwd            m0, m2
+    punpcklwd            m2, m1, m3
+    punpckhwd            m1, m3
+    punpcklwd            m3, m4, m6
+    punpckhwd            m4, m6
+    punpcklwd            m6, m5, m7
+    punpckhwd            m5, m7
+    punpcklwd            m7, m14, m16
+    punpckhwd           m14, m16
+    punpcklwd           m16, m15, m17
+    punpckhwd           m15, m17
+    punpcklwd           m17, m19, m21
+    punpckhwd           m19, m21
+    punpckhwd           m21, m18, m20
+    punpcklwd           m18, m20
+    punpcklwd           m20, m8, m1
+    punpckhwd            m8, m1
+    punpcklwd            m1, m0, m2
+    punpckhwd            m0, m2
+    punpcklwd            m2, m3, m5
+    punpckhwd            m3, m5
+    punpcklwd            m5, m4, m6
+    punpckhwd            m4, m6
+    REPX   {pmulhrsw x, m9}, m20, m8, m1, m0
+    punpcklwd            m6, m7, m15
+    punpckhwd            m7, m15
+    punpcklwd           m15, m14, m16
+    punpckhwd           m14, m16
+    REPX   {pmulhrsw x, m9}, m2, m3, m5, m4
+    punpckhwd           m16, m18, m19
+    punpcklwd           m18, m19
+    punpcklwd           m19, m21, m17
+    punpckhwd           m21, m17
+    REPX   {pmulhrsw x, m9}, m6, m7, m15, m14
+    punpcklwd           m17, m8, m0         ; a2   a6   aa   ae
+    punpckhwd            m8, m0             ; a3   a7   ab   af
+    punpcklwd            m0, m20, m1        ; a0   a4   a8   ac
+    punpckhwd           m20, m1             ; a1   a5   a9   ad
+    REPX   {pmulhrsw x, m9}, m16, m18, m19, m21
+    punpcklwd            m1, m2, m5         ; b0   b4   b8   bc
+    punpckhwd            m2, m5             ; b1   b5   b9   bd
+    punpcklwd            m5, m3, m4         ; b2   b6   ba   be
+    punpckhwd            m3, m4             ; b3   b7   bb   bf
+    punpcklwd            m4, m6, m15        ; c0   c4   c8   cc
+    punpckhwd            m6, m15            ; c1   c5   c9   cd
+    punpcklwd           m15, m7, m14        ; c2   c6   ca   ce
+    punpckhwd            m7, m14            ; c3   c7   cb   cf
+    punpcklwd           m14, m18, m19       ; d0   d4   d8   dc
+    punpckhwd           m18, m19            ; d1   d5   d9   dd
+    punpcklwd            m9, m16, m21       ; d2   d6   da   de
+    punpckhwd           m16, m21            ; d3   d7   db   df
+    vshufi32x4          m21, m0, m1, q3232  ; a8   ac   b8   bc
+    vinserti32x8         m0, ym1, 1         ; a0   a4   b0   b4
+    vinserti32x8         m1, m17, ym5, 1    ; a2   a6   b2   b6
+    vshufi32x4           m5, m17, m5, q3232 ; aa   ae   ba   be
+    vinserti32x8        m17, m8, ym3, 1     ; a3   a7   b3   b7
+    vshufi32x4          m19, m8, m3, q3232  ; ab   af   bb   bf
+    vinserti32x8         m3, m4, ym14, 1    ; c0   c4   d0   d4
+    vshufi32x4           m4, m14, q3232     ; c8   cc   d8   dc
+    vinserti32x8        m14, m20, ym2, 1    ; a1   a5   b1   b5
+    vshufi32x4          m20, m2, q3232      ; a9   ad   b9   bd
+    vinserti32x8         m2, m6, ym18, 1    ; c1   c5   d1   d5
+    vshufi32x4           m6, m18, q3232     ; c9   cd   d9   dd
+    vinserti32x8        m18, m15, ym9, 1    ; c2   c6   d2   d6
+    vshufi32x4          m15, m9, q3232      ; ca   ce   da   de
+    vinserti32x8         m9, m7, ym16, 1    ; c3   c7   d3   d7
+    vshufi32x4           m7, m16, q3232     ; cb   cf   db   df
+    ret
+
+%macro IDTX_16x32 4 ; src/dst[1-4]
+    pmulhrsw            m%1, m15, [cq+64*%1]
+    pmulhrsw            m%2, m15, [cq+64*%2]
+    pmulhrsw            m%3, m15, [cq+64*%3]
+    pmulhrsw            m%4, m15, [cq+64*%4]
+    pmulhrsw            m18, m16, m%1
+    pmulhrsw            m19, m16, m%2
+    pmulhrsw            m20, m16, m%3
+    pmulhrsw            m21, m16, m%4
+    REPX  {pmulhrsw x, m17}, m18, m19, m20, m21
+    paddsw              m%1, m18
+    paddsw              m%2, m19
+    paddsw              m%3, m20
+    paddsw              m%4, m21
+%endmacro
+
+%macro IDTX_16x32_STORE 2 ; src[1-2]
+    mova               xm17, [dstq+r3*0]
+    vinserti128        ym17, [dstq+r3*4], 1
+    vinserti32x4        m17, [dstq+r3*8], 2
+    vinserti32x4        m17, [dstq+r4*8], 3
+    mova   [cq+64*(%1*2+0)], m18
+    mova   [cq+64*(%1*2+1)], m18
+    punpcklbw           m16, m17, m18
+    punpckhbw           m17, m18
+    paddw               m16, m%1
+    paddw               m17, m%2
+    packuswb            m16, m17
+    mova          [dstq+r3*0], xm16
+    vextracti128  [dstq+r3*4], ym16, 1
+    vextracti32x4 [dstq+r3*8], m16, 2
+    vextracti32x4 [dstq+r4*8], m16, 3
+%if %1 != 7
+    add                dstq, strideq
+%endif
+%endmacro
+
+cglobal inv_txfm_add_identity_identity_16x32_8bpc, 3, 5, 22, dst, stride, c
+    vpbroadcastd        m15, [pw_2896x8]
+    vpbroadcastd        m16, [pw_1697x16]
+    vpbroadcastd        m17, [pw_16384]
+    IDTX_16x32            0,  1,  2,  3
+    IDTX_16x32            4,  5,  6,  7
+    IDTX_16x32            8,  9, 10, 11
+    IDTX_16x32           12, 13, 14, 15
+    vpbroadcastd        m16, [pw_8192]
+    call .transpose_2x8x8_round
+    lea                  r3, [strideq*2]
+    lea                  r4, [strideq*3]
+    pxor                m18, m18
+    IDTX_16x32_STORE      0,  8
+    IDTX_16x32_STORE      1,  9
+    IDTX_16x32_STORE      2, 10
+    IDTX_16x32_STORE      3, 11
+    IDTX_16x32_STORE      4, 12
+    IDTX_16x32_STORE      5, 13
+    IDTX_16x32_STORE      6, 14
+    IDTX_16x32_STORE      7, 15
+    RET
+ALIGN function_align
+.transpose_2x8x8_round:
+    punpckhwd           m17, m4, m5
+    punpcklwd            m4, m5
+    punpckhwd            m5, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m6, m7
+    punpcklwd            m6, m7
+    punpckhwd            m7, m2, m3
+    punpcklwd            m2, m3
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m4, m6
+    punpckhdq            m4, m6
+    punpckhdq            m6, m5, m7
+    punpckldq            m5, m7
+    punpckldq            m7, m17, m1
+    punpckhdq           m17, m1
+    REPX  {pmulhrsw x, m16}, m0, m2, m3, m4, m5, m7, m6, m17
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    punpcklqdq           m4, m5, m7
+    punpckhqdq           m5, m7
+    punpckhqdq           m7, m6, m17
+    punpcklqdq           m6, m17
+    punpckhwd           m17, m12, m13
+    punpcklwd           m12, m13
+    punpckhwd           m13, m8, m9
+    punpcklwd            m8, m9
+    punpckhwd            m9, m14, m15
+    punpcklwd           m14, m15
+    punpckhwd           m15, m10, m11
+    punpcklwd           m10, m11
+    punpckhdq           m11, m8, m10
+    punpckldq            m8, m10
+    punpckldq           m10, m12, m14
+    punpckhdq           m12, m14
+    punpckhdq           m14, m13, m15
+    punpckldq           m13, m15
+    punpckldq           m15, m17, m9
+    punpckhdq           m17, m9
+    REPX  {pmulhrsw x, m16}, m8, m10, m11, m12, m13, m15, m14, m17
+    punpckhqdq           m9, m8, m10
+    punpcklqdq           m8, m10
+    punpcklqdq          m10, m11, m12
+    punpckhqdq          m11, m12
+    punpcklqdq          m12, m13, m15
+    punpckhqdq          m13, m15
+    punpckhqdq          m15, m14, m17
+    punpcklqdq          m14, m17
+    ret
+
+%macro IDTX_32x16 4 ; dst[1-4]
+    pmulhrsw            m%2, m12, [cq+32*(%1+ 0)]
+    pmulhrsw            m18, m12, [cq+32*(%1+16)]
+    pmulhrsw            m%4, m12, [cq+32*(%3+ 0)]
+    pmulhrsw            m19, m12, [cq+32*(%3+16)]
+    REPX      {paddsw x, x}, m%2, m18, m%4, m19
+    mova                m%1, m14
+    vpermi2q            m%1, m%2, m18
+    vpermt2q            m%2, m16, m18
+%if %3 != 14
+    mova                m%3, m14
+%endif
+    vpermi2q            m%3, m%4, m19
+    vpermt2q            m%4, m16, m19
+    pmulhrsw            m18, m17, m%1
+    pmulhrsw            m19, m17, m%2
+    pmulhrsw            m20, m17, m%3
+    pmulhrsw            m21, m17, m%4
+    REPX      {paddsw x, x}, m%1, m%2, m%3, m%4
+    paddsw              m%1, m18
+    paddsw              m%2, m19
+    paddsw              m%3, m20
+    paddsw              m%4, m21
+%endmacro
+
+%macro IDTX_32x16_STORE 2-3 0 ; src[1-2], 32x32
+    mova               ym19, [dstq+strideq*0]
+    vinserti32x8        m19, [dstq+strideq*8], 1
+%if %3 == 0
+    mova   [cq+64*(%1*2+0)], m20
+    mova   [cq+64*(%1*2+1)], m20
+%endif
+    punpcklbw           m18, m19, m20
+    punpckhbw           m19, m20
+    paddw               m18, m%1
+    paddw               m19, m%2
+    packuswb            m18, m19
+    mova          [dstq+strideq*0], ym18
+    vextracti32x8 [dstq+strideq*8], m18, 1
+%if %3 || %1 != 7
+    add                dstq, strideq
+%endif
+%endmacro
+
+cglobal inv_txfm_add_identity_identity_32x16_8bpc, 3, 3, 22, dst, stride, c
+    vpbroadcastd        m12, [pw_2896x8]
+    movu                m14, [permB+7]
+    vpbroadcastd        m17, [pw_1697x16]
+    psrlq               m16, m14, 4
+    IDTX_32x16            0,  1,  2,  3
+    IDTX_32x16            4,  5,  6,  7
+    IDTX_32x16            8,  9, 10, 11
+    IDTX_32x16           12, 13, 14, 15
+    vpbroadcastd        m16, [pw_2048]
+    call m(inv_txfm_add_identity_identity_16x32_8bpc).transpose_2x8x8_round
+    pxor                m20, m20
+    IDTX_32x16_STORE      0,  8
+    IDTX_32x16_STORE      1,  9
+    IDTX_32x16_STORE      2, 10
+    IDTX_32x16_STORE      3, 11
+    IDTX_32x16_STORE      4, 12
+    IDTX_32x16_STORE      5, 13
+    IDTX_32x16_STORE      6, 14
+    IDTX_32x16_STORE      7, 15
+    RET
+
+%macro IDCT_32x32_END 4 ; src, mem, stride[1-2]
+    pmovzxbw            m10, [dstq+%3]
+    pmovzxbw            m11, [r3  +%4]
+%if %2 < 8
+    paddsw               m8, m%2, m%1
+    psubsw               m9, m%2, m%1
+%else
+    mova                 m9, [cq+64*(%2*2-16)]
+    paddsw               m8, m9, m%1
+    psubsw               m9, m%1
+%endif
+    pmulhrsw             m8, m12
+    pmulhrsw             m9, m12
+%if %2 >= 8
+%if %2 == 8
+    pxor                 m0, m0
+%endif
+    mova  [cq+64*(%2*2-16)], m0
+    mova  [cq+64*(%2*2-15)], m0
+%endif
+    paddw                m8, m10
+    paddw                m9, m11
+    packuswb             m8, m9
+    vpermq               m8, m13, m8
+    mova          [dstq+%3], ym8
+    vextracti32x8 [r3  +%4], m8, 1
+%if %2 == 3 || %2 == 7 || %2 == 11
+    add                dstq, r5
+    sub                  r3, r5
+%endif
+%endmacro
+
+cglobal inv_txfm_add_dct_dct_32x32_8bpc, 4, 6, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    WIN64_SPILL_XMM      30
+    cmp                eobd, 136
+    jb .fast
+    mova                 m5, [cq+64*20]
+    mova                 m3, [cq+64*12]
+    mova                 m1, [cq+64* 4]
+    mova                 m7, [cq+64*28]
+    mova                 m2, [cq+64* 8]
+    mova                 m6, [cq+64*24]
+    mova                 m0, [cq+64* 0]
+    mova                 m4, [cq+64*16]
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    mova                m14, [cq+64* 2]
+    mova                m21, [cq+64*30]
+    mova                m18, [cq+64*18]
+    mova                m17, [cq+64*14]
+    mova                m16, [cq+64*10]
+    mova                m19, [cq+64*22]
+    mova                m20, [cq+64*26]
+    mova                m15, [cq+64* 6]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 2], m15
+    mova         [cq+64* 4], m16
+    mova         [cq+64* 6], m17
+    mova         [cq+64* 8], m18
+    mova         [cq+64*10], m19
+    mova         [cq+64*12], m20
+    mova         [cq+64*14], m21
+    mova                m22, [cq+64* 1]
+    mova                m21, [cq+64*31]
+    mova                m14, [cq+64*17]
+    mova                m29, [cq+64*15]
+    mova                m26, [cq+64* 9]
+    mova                m17, [cq+64*23]
+    mova                m18, [cq+64*25]
+    mova                m25, [cq+64* 7]
+    mova                m24, [cq+64* 5]
+    mova                m19, [cq+64*27]
+    mova                m16, [cq+64*21]
+    mova                m27, [cq+64*11]
+    mova                m28, [cq+64*13]
+    mova                m15, [cq+64*19]
+    mova                m20, [cq+64*29]
+    mova                m23, [cq+64* 3]
+    call .main_oddhalf
+    vpbroadcastd        m10, [o(pw_8192)]
+    psubsw              m13, m0, m29 ; 31
+    paddsw               m0, m29     ;  0
+    psubsw              m29, m1, m28 ; 30
+    paddsw               m1, m28     ;  1
+    psubsw              m28, m2, m27 ; 29
+    paddsw               m2, m27     ;  2
+    psubsw              m27, m3, m26 ; 28
+    paddsw               m3, m26     ;  3
+    psubsw              m26, m4, m25 ; 27
+    paddsw               m4, m25     ;  4
+    psubsw              m25, m5, m24 ; 26
+    paddsw               m5, m24     ;  5
+    psubsw              m24, m6, m23 ; 25
+    paddsw               m6, m23     ;  6
+    psubsw              m23, m7, m22 ; 24
+    paddsw               m7, m22     ;  7
+    pxor                 m9, m9
+    punpckhwd            m8, m0, m1 ; a4 b4 a5 b5 a6 b6 a7 b7
+    punpcklwd            m0, m1     ; a0 b0 a1 b1 a2 b2 a3 b3
+    punpckhwd            m1, m2, m3 ; c4 d4 c5 d5 c6 d6 c7 d7
+    punpcklwd            m2, m3     ; c0 d0 c1 d1 c2 d2 c3 d3
+    REPX {mova [cq+64*x], m9}, 16, 17, 18, 19
+    punpckhwd           m22, m4, m5 ; e4 f4 e5 f5 e6 f6 e7 f7
+    punpcklwd            m4, m5     ; e0 f0 e1 f1 e2 f2 e3 f3
+    punpckhwd            m5, m6, m7 ; g4 h4 g5 h5 g6 h6 g7 h7
+    punpcklwd            m6, m7     ; g0 h0 g1 h1 g2 h2 g3 h3
+    REPX {mova [cq+64*x], m9}, 20, 21, 22, 23
+    punpckhwd            m3, m23, m24
+    punpcklwd           m23, m24
+    punpckhwd           m24, m25, m26
+    punpcklwd           m25, m26
+    REPX {mova [cq+64*x], m9}, 24, 25, 26, 27
+    punpckhwd           m26, m27, m28
+    punpcklwd           m27, m28
+    punpckhwd           m28, m29, m13
+    punpcklwd           m29, m13
+    REPX {mova [cq+64*x], m9}, 28, 29, 30, 31
+    punpckhdq            m7, m0, m2  ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpckldq            m0, m2      ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckhdq            m2, m4, m6  ; e2 f2 g2 h2 e3 f3 g3 h3
+    punpckldq            m4, m6      ; e0 f0 g0 h0 e1 f1 g1 h1
+    punpckhdq            m6, m8, m1  ; a6 b6 c6 d6 a7 b7 c7 d7
+    punpckldq            m8, m1      ; a4 b4 c4 d4 a5 b5 c5 d5
+    punpckhdq            m1, m22, m5 ; e6 f6 g6 h6 e7 f7 g7 h7
+    punpckldq           m22, m5      ; e4 f4 g4 h5 e5 f5 g5 h5
+    REPX  {pmulhrsw x, m10}, m0, m4, m8, m22
+    punpckhdq           m13, m23, m25
+    punpckldq           m23, m25
+    punpckhdq           m25, m27, m29
+    punpckldq           m27, m29
+    REPX  {pmulhrsw x, m10}, m13, m23, m25, m27
+    punpckhdq            m9, m3, m24
+    punpckldq            m3, m24
+    punpckhdq           m24, m26, m28
+    punpckldq           m26, m28
+    punpcklqdq           m5, m23, m27 ; d00 d08 d16 d24
+    punpckhqdq          m23, m27      ; d01 d09 d17 d25
+    punpckhqdq          m27, m13, m25 ; d03 d11 d19 d27
+    punpcklqdq          m13, m25      ; d02 d10 d18 d26
+    punpckhqdq          m25, m3, m26  ; d05 d13 d21 d29
+    punpcklqdq           m3, m26      ; d04 d12 d20 d28
+    punpckhqdq          m26, m9, m24  ; d07 d15 d23 d31
+    punpcklqdq           m9, m24      ; d06 d14 d22 d30
+    REPX  {pmulhrsw x, m10}, m25, m3, m26
+    mova         [cq+64* 9], m23
+    mova         [cq+64*11], m27
+    mova         [cq+64*13], m25
+    mova         [cq+64*15], m26
+    punpckhqdq          m24, m8, m22  ; a05 a13 a21 a29
+    punpcklqdq           m8, m22      ; a04 a12 a20 a28
+    punpckhqdq          m22, m0, m4   ; a01 a09 a17 a25
+    punpcklqdq           m0, m4       ; a00 a08 a16 a24
+    punpckhqdq          m23, m7, m2   ; a03 a11 a19 a27
+    punpcklqdq           m7, m2       ; a02 a10 a18 a26
+    punpckhqdq          m25, m6, m1   ; a07 a15 a23 a31
+    punpcklqdq           m6, m1       ; a06 a14 a22 a30
+    mova                 m2, [cq+64* 0]
+    mova                m11, [cq+64* 2]
+    mova                m12, [cq+64* 4]
+    mova                m29, [cq+64* 6]
+    mova                m27, [cq+64* 8]
+    mova                m26, [cq+64*10]
+    mova                 m4, [cq+64*12]
+    mova                m28, [cq+64*14]
+    psubsw               m1, m2, m21  ; 23
+    paddsw               m2, m21      ;  8
+    psubsw              m21, m11, m20 ; 22
+    paddsw              m11, m20      ;  9
+    psubsw              m20, m12, m19 ; 21
+    paddsw              m12, m19      ; 10
+    psubsw              m19, m29, m18 ; 20
+    paddsw              m29, m18      ; 11
+    psubsw              m18, m27, m17 ; 19
+    paddsw              m27, m17      ; 12
+    psubsw              m17, m26, m16 ; 18
+    paddsw              m26, m16      ; 13
+    paddsw              m16, m4, m15  ; 14
+    psubsw               m4, m15      ; 17
+    pmulhrsw            m15, m6, m10
+    psubsw               m6, m28, m14 ; 16
+    paddsw              m28, m14      ; 15
+    pmulhrsw            m14, m7, m10
+    punpcklwd            m7, m6, m4
+    punpckhwd            m6, m4
+    punpckhwd            m4, m17, m18
+    punpcklwd           m17, m18
+    punpckhwd           m18, m19, m20
+    punpcklwd           m19, m20
+    punpckhwd           m20, m21, m1
+    punpcklwd           m21, m1
+    punpckhwd            m1, m2, m11  ; i4 j4 i5 j5 i6 j6 i7 j7
+    punpcklwd            m2, m11      ; i0 j1 i1 j1 i2 j2 i3 j3
+    punpckhwd           m11, m12, m29 ; k4 l4 k5 l5 k6 l6 k7 l7
+    punpcklwd           m12, m29      ; k0 l0 k1 l1 k2 l2 k3 l3
+    punpckhwd           m29, m27, m26 ; m4 n4 m5 n5 m6 n6 m7 n7
+    punpcklwd           m27, m26      ; m0 n0 m1 n1 m2 n2 m3 n3
+    punpckhwd           m26, m16, m28 ; o4 p4 o5 p5 o6 p6 o7 p7
+    punpcklwd           m16, m28      ; o0 p0 o1 p1 o2 p2 o3 p3
+    pmulhrsw            m23, m10
+    pmulhrsw            m25, m10
+    punpckhdq           m28, m2, m12  ; i2 j2 k2 l2 i3 j3 k3 l3
+    punpckldq            m2, m12      ; i0 j0 k0 l0 i1 j1 k1 l1
+    punpckhdq           m12, m27, m16 ; m2 n2 o2 p2 m3 n3 o3 p3
+    punpckldq           m27, m16      ; m0 n0 o0 p0 m1 n1 o1 p1
+    REPX  {pmulhrsw x, m10}, m28, m2, m12, m27
+    punpckhdq           m16, m1, m11  ; i6 j6 k6 l6 i7 j7 k7 l7
+    punpckldq            m1, m11      ; i4 j4 k4 l4 i5 j5 k5 l5
+    punpckhdq           m11, m29, m26 ; m6 n6 o6 p6 m7 n7 o7 p7
+    punpckldq           m29, m26      ; m4 n4 o4 p4 m5 n5 o5 p5
+    REPX  {pmulhrsw x, m10}, m16, m1, m11, m29
+    punpckhdq           m26, m19, m21
+    punpckldq           m19, m21
+    punpckhdq           m21, m6, m4
+    punpckldq            m6, m4
+    REPX  {pmulhrsw x, m10}, m26, m19, m21, m6
+    punpckhdq            m4, m18, m20
+    punpckldq           m18, m20
+    punpckhdq           m20, m7, m17
+    punpckldq            m7, m17
+    REPX  {pmulhrsw x, m10}, m4, m18, m20, m7
+    punpcklqdq          m17, m28, m12 ; b02 b10 b18 b26
+    punpckhqdq          m28, m12      ; b03 b11 b19 b27
+    punpckhqdq          m12, m2, m27  ; b01 b09 b17 b25
+    punpcklqdq           m2, m27      ; b00 b08 b16 b24
+    punpckhqdq          m27, m1, m29  ; b05 b13 b21 b29
+    punpcklqdq           m1, m29      ; b04 b12 b20 b28
+    punpckhqdq          m29, m16, m11 ; b07 b15 b23 b31
+    punpcklqdq          m16, m11      ; b06 b14 b22 b30
+    mova         [cq+64* 1], m12
+    mova         [cq+64* 3], m28
+    mova         [cq+64* 5], m27
+    mova         [cq+64* 7], m29
+    punpckhqdq          m27, m20, m26 ; c03 c11 c19 c27
+    punpcklqdq          m20, m26      ; c02 c10 c18 c26
+    punpckhqdq          m26, m7, m19  ; c01 c09 c17 c25
+    punpcklqdq           m7, m19      ; c00 c08 c16 c24
+    punpckhqdq          m28, m6, m18  ; c05 c13 c21 c29
+    punpcklqdq           m6, m18      ; c04 c12 c20 c28
+    punpckhqdq          m29, m21, m4  ; c07 c15 c23 c31
+    punpcklqdq          m21, m4       ; c06 c14 c22 c30
+    pmulhrsw            m19, m9, m10
+    vshufi32x4           m4, m0, m2, q3232   ; a16 a24 b16 b24
+    vinserti32x8         m0, ym2, 1          ; a00 a08 b00 b08
+    vshufi32x4           m2, m7, m5, q3232   ; c16 c24 d16 d24
+    vinserti32x8         m7, ym5, 1          ; c00 c08 d00 d08
+    vshufi32x4           m5, m8, m1, q3232   ; a20 a28 b20 b28
+    vinserti32x8         m1, m8, ym1, 1      ; a04 a12 b04 b12
+    vshufi32x4           m8, m6, m3, q3232   ; c20 c28 d20 d28
+    vinserti32x8         m6, ym3, 1          ; c04 c12 d04 d12
+    vshufi32x4           m3, m1, m6, q3131   ; 12
+    vshufi32x4           m1, m6, q2020       ;  4
+    vshufi32x4           m6, m4, m2, q3131   ; 24
+    vshufi32x4           m4, m2, q2020       ; 16
+    vshufi32x4           m2, m0, m7, q3131   ;  8
+    vshufi32x4           m0, m7, q2020       ;  0
+    vshufi32x4           m7, m5, m8, q3131   ; 28
+    vshufi32x4           m5, m8, q2020       ; 20
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    vshufi32x4          m18, m14, m17, q3232 ; a18 a26 b18 b26
+    vinserti32x8        m14, ym17, 1         ; a02 a10 b02 b10
+    vshufi32x4          m17, m20, m13, q3232 ; c18 c26 d18 d26
+    vinserti32x8        m20, ym13, 1         ; c02 c10 d02 d10
+    vshufi32x4          m13, m21, m19, q3232 ; c22 c30 d22 d30
+    vinserti32x8        m21, ym19, 1         ; c06 c14 d06 d14
+    vshufi32x4          m19, m15, m16, q3232 ; a22 a30 b22 b30
+    vinserti32x8        m15, ym16, 1         ; a06 a14 b06 b14
+    vshufi32x4          m16, m14, m20, q3131 ; 10
+    vshufi32x4          m14, m20, q2020      ;  2
+    vshufi32x4          m20, m18, m17, q3131 ; 26
+    vshufi32x4          m18, m17, q2020      ; 18
+    vshufi32x4          m17, m15, m21, q3131 ; 14
+    vshufi32x4          m15, m21, q2020      ;  6
+    vshufi32x4          m21, m19, m13, q3131 ; 30
+    vshufi32x4          m19, m13, q2020      ; 22
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 2], m15
+    mova         [cq+64* 4], m16
+    mova         [cq+64* 6], m17
+    mova         [cq+64* 8], m18
+    mova         [cq+64*10], m19
+    mova         [cq+64*12], m20
+    mova         [cq+64*14], m21
+    mova                m15, [cq+64* 1]
+    mova                m16, [cq+64* 3]
+    mova                m17, [cq+64* 5]
+    mova                m19, [cq+64* 7]
+    mova                m20, [cq+64* 9]
+    mova                m21, [cq+64*11]
+    mova                m13, [cq+64*13]
+    mova                m18, [cq+64*15]
+    vshufi32x4          m14, m22, m15, q3232 ; a17 a25 b17 b25
+    vinserti32x8        m22, ym15, 1         ; a01 a09 b01 b09
+    vshufi32x4          m15, m23, m16, q3232 ; a19 a27 b19 b27
+    vinserti32x8        m23, ym16, 1         ; a03 a11 b03 b11
+    vshufi32x4          m16, m24, m17, q3232 ; a21 a29 b21 b29
+    vinserti32x8        m24, ym17, 1         ; a05 a13 b05 b13
+    vshufi32x4          m17, m25, m19, q3232 ; a23 a31 b23 b31
+    vinserti32x8        m25, ym19, 1         ; a07 a15 b07 b15
+    vinserti32x8         m8, m26, ym20, 1    ; c01 c09 d01 d09
+    vshufi32x4          m26, m20, q3232      ; c17 c25 d17 d25
+    vinserti32x8         m9, m27, ym21, 1    ; c03 c11 d03 d11
+    vshufi32x4          m27, m21, q3232      ; c19 c27 d19 d27
+    vinserti32x8        m11, m28, ym13, 1    ; c05 c13 d05 d13
+    vshufi32x4          m28, m13, q3232      ; c21 c29 d21 d29
+    vinserti32x8        m12, m29, ym18, 1    ; c07 c15 d07 d15
+    vshufi32x4          m29, m18, q3232      ; c23 c31 d23 d31
+    vshufi32x4          m18, m14, m26, q3131 ; 25
+    vshufi32x4          m14, m26, q2020      ; 17
+    vshufi32x4          m19, m15, m27, q3131 ; 27
+    vshufi32x4          m15, m27, q2020      ; 19
+    vshufi32x4          m20, m16, m28, q3131 ; 29
+    vshufi32x4          m16, m28, q2020      ; 21
+    vshufi32x4          m21, m17, m29, q3131 ; 31
+    vshufi32x4          m17, m29, q2020      ; 23
+    vshufi32x4          m26, m22, m8, q3131  ;  9
+    vshufi32x4          m22, m8, q2020       ;  1
+    vshufi32x4          m27, m23, m9, q3131  ; 11
+    vshufi32x4          m23, m9, q2020       ;  3
+    vshufi32x4          m28, m24, m11, q3131 ; 13
+    vshufi32x4          m24, m11, q2020      ;  5
+    vshufi32x4          m29, m25, m12, q3131 ; 15
+    vshufi32x4          m25, m12, q2020      ;  7
+    call .main_oddhalf
+    jmp .end
+.fast: ; bottom/right halves are zero
+    mova                m14, [o(dup16_perm)]
+    pmovzxwd             m9,       [cq+64* 0]
+    pmovzxwd             m6,       [cq+64* 8]
+    vpermb               m8, m14,  [cq+64* 2]
+    vpermb              ym0, ym14, [cq+64*14]
+    vpermb              ym5, ym14, [cq+64*10]
+    vpermb               m1, m14,  [cq+64* 6]
+    vpermb               m7, m14,  [cq+64* 4]
+    vpermb              ym3, ym14, [cq+64*12]
+    pslld                m9, 16
+    pslld                m6, 16
+    call m(idct_16x16_internal_8bpc).main_fast
+    vpermb              m21, m14,  [cq+64* 1]
+    vpermb             ym17, ym14, [cq+64*15]
+    vpermb             ym20, ym14, [cq+64* 9]
+    vpermb              m15, m14,  [cq+64* 7]
+    vpermb              m18, m14,  [cq+64* 5]
+    vpermb             ym16, ym14, [cq+64*11]
+    vpermb             ym19, ym14, [cq+64*13]
+    vpermb              m14, m14,  [cq+64* 3]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    vpbroadcastd         m9, [o(pw_8192)]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).transpose_round
+    vshufi32x4          m22, m14, m2, q2020 ;  1
+    vshufi32x4          m24, m14, m2, q3131 ;  5
+    vshufi32x4          m23, m17, m9, q2020 ;  3
+    vshufi32x4          m25, m17, m9, q3131 ;  7
+    vshufi32x4          m16, m5, m15, q2020 ; 10
+    vshufi32x4          m17, m5, m15, q3131 ; 14
+    vshufi32x4          m14, m1, m18, q2020 ;  2
+    vshufi32x4          m15, m1, m18, q3131 ;  6
+    vshufi32x4           m1, m0, m3, q3131  ;  4
+    vshufi32x4           m0, m3, q2020      ;  0
+    vshufi32x4           m3, m21, m4, q3131 ; 12
+    vshufi32x4           m2, m21, m4, q2020 ;  8
+    vshufi32x4          m26, m20, m6, q2020 ;  9
+    vshufi32x4          m28, m20, m6, q3131 ; 13
+    vshufi32x4          m27, m19, m7, q2020 ; 11
+    vshufi32x4          m29, m19, m7, q3131 ; 15
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 2], m15
+    mova         [cq+64* 4], m16
+    mova         [cq+64* 6], m17
+    mova         [cq+64* 8], m18
+    mova         [cq+64*10], m19
+    mova         [cq+64*12], m20
+    mova         [cq+64*14], m21
+    call .main_oddhalf_fast
+.end:
+    lea                  r4, [strideq*3]
+    vpbroadcastd        m12, [o(pw_2048)]
+    movshdup            m13, [o(permD)]
+    lea                  r3, [dstq+r4*8]
+    lea                  r5, [strideq+r4] ; stride*4
+    add                  r3, r5           ; dst+stride*28
+    IDCT_32x32_END       29,  0, strideq*0, r4
+    IDCT_32x32_END       28,  1, strideq*1, strideq*2
+    IDCT_32x32_END       27,  2, strideq*2, strideq*1
+    IDCT_32x32_END       26,  3, r4       , strideq*0
+    IDCT_32x32_END       25,  4, strideq*0, r4
+    IDCT_32x32_END       24,  5, strideq*1, strideq*2
+    IDCT_32x32_END       23,  6, strideq*2, strideq*1
+    IDCT_32x32_END       22,  7, r4       , strideq*0
+    IDCT_32x32_END       21,  8, strideq*0, r4
+    IDCT_32x32_END       20,  9, strideq*1, strideq*2
+    IDCT_32x32_END       19, 10, strideq*2, strideq*1
+    IDCT_32x32_END       18, 11, r4       , strideq*0
+    IDCT_32x32_END       17, 12, strideq*0, r4
+    IDCT_32x32_END       16, 13, strideq*1, strideq*2
+    IDCT_32x32_END       15, 14, strideq*2, strideq*1
+    IDCT_32x32_END       14, 15, r4       , strideq*0
+    RET
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 32
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).dconly2
+ALIGN function_align
+cglobal_label .main_oddhalf_fast3 ; bottom seven-eights are zero
+    vpbroadcastd        m21, [o(pw_4091x8)]
+    vpbroadcastd         m8, [o(pw_201x8)]
+    vpbroadcastd        m24, [o(pw_m601x8)]
+    vpbroadcastd        m12, [o(pw_4052x8)]
+    pmulhrsw            m21, m22 ; t31a
+    pmulhrsw            m22, m8  ; t16a
+    pmulhrsw            m24, m23 ; t23a
+    pmulhrsw            m23, m12 ; t24a
+
+    punpcklwd            m9, m22, m21
+    punpckhwd            m8, m22, m21
+    mova                m15, m10
+    vpdpwssd            m15, m9, [o(pw_m4017_799)] {bcstd}
+    mova                m17, m10
+    vpdpwssd            m17, m8, [o(pw_m4017_799)] {bcstd}
+    REPX      {psrad x, 12}, m15, m17
+    packssdw            m15, m17
+    mova                m17, m10
+    vpdpwssd            m17, m8, [o(pw_799_4017)] {bcstd}
+    mova                 m8, m10
+    vpdpwssd             m8, m9, [o(pw_799_4017)] {bcstd}
+    REPX      {psrad x, 12}, m17, m8
+    packssdw             m8, m17
+
+    punpcklwd            m9, m24, m23
+    punpckhwd           m16, m24, m23
+    mova                m20, m10
+    vpdpwssd            m20, m9, [o(pw_m3406_m2276)] {bcstd}
+    mova                m17, m10
+    vpdpwssd            m17, m16, [o(pw_m3406_m2276)] {bcstd}
+    REPX      {psrad x, 12}, m20, m17
+    packssdw            m20, m17
+    mova                m17, m10
+    vpdpwssd            m17, m16, [o(pw_m2276_3406)] {bcstd}
+    mova                m16, m10
+    vpdpwssd            m16, m9, [o(pw_m2276_3406)] {bcstd}
+    REPX      {psrad x, 12}, m17, m16
+    packssdw            m16, m17
+
+    mova                m17, m21
+    mova                m27, m15
+    mova                m25, m20
+    mova                m29, m8
+    mova                m18, m22
+    mova                m14, m24
+    mova                m28, m16
+    mova                m26, m23
+    jmp .main4
+cglobal_label .main_oddhalf_fast2 ; bottom three-quarters are zero
+    vpbroadcastd        m21, [o(pw_4091x8)]
+    vpbroadcastd         m8, [o(pw_201x8)]
+    vpbroadcastd        m18, [o(pw_m1380x8)]
+    vpbroadcastd         m9, [o(pw_3857x8)]
+    vpbroadcastd        m19, [o(pw_3973x8)]
+    vpbroadcastd        m11, [o(pw_995x8)]
+    vpbroadcastd        m28, [o(pw_m601x8)]
+    vpbroadcastd        m12, [o(pw_4052x8)]
+    pmulhrsw            m21, m22 ; t31a
+    pmulhrsw            m22, m8  ; t16a
+    pmulhrsw            m18, m25 ; t19a
+    pmulhrsw            m25, m9 ; t28a
+    pmulhrsw            m19, m24 ; t27a
+    pmulhrsw            m24, m11 ; t20a
+    pmulhrsw            m28, m23 ; t23a
+    pmulhrsw            m23, m12 ; t24a
+    mova                m15, m21
+    mova                 m8, m22
+    mova                m14, m18
+    mova                m27, m25
+    mova                m29, m19
+    mova                m26, m24
+    mova                m16, m28
+    mova                m20, m23
+    jmp .main3
+ALIGN function_align
+cglobal_label .main_oddhalf_fast ; bottom half is zero
+    vpbroadcastd        m21, [o(pw_4091x8)]
+    vpbroadcastd         m8, [o(pw_201x8)]
+    vpbroadcastd        m14, [o(pw_m2751x8)]
+    vpbroadcastd         m9, [o(pw_3035x8)]
+    vpbroadcastd        m17, [o(pw_3703x8)]
+    vpbroadcastd        m11, [o(pw_1751x8)]
+    vpbroadcastd        m18, [o(pw_m1380x8)]
+    vpbroadcastd        m12, [o(pw_3857x8)]
+    pmulhrsw            m21, m22 ; t31a
+    vpbroadcastd        m19, [o(pw_3973x8)]
+    pmulhrsw            m22, m8  ; t16a
+    vpbroadcastd         m8, [o(pw_995x8)]
+    pmulhrsw            m14, m29 ; t30a
+    vpbroadcastd        m16, [o(pw_m2106x8)]
+    pmulhrsw            m29, m9  ; t17a
+    vpbroadcastd         m9, [o(pw_3513x8)]
+    pmulhrsw            m17, m26 ; t29a
+    vpbroadcastd        m15, [o(pw_3290x8)]
+    pmulhrsw            m26, m11 ; t18a
+    vpbroadcastd        m11, [o(pw_2440x8)]
+    pmulhrsw            m18, m25 ; t19a
+    vpbroadcastd        m20, [o(pw_m601x8)]
+    pmulhrsw            m25, m12 ; t28a
+    vpbroadcastd        m12, [o(pw_4052x8)]
+    pmulhrsw            m19, m24 ; t27a
+    pmulhrsw            m24, m8  ; t20a
+    pmulhrsw            m16, m27 ; t21a
+    pmulhrsw            m27, m9  ; t26a
+    pmulhrsw            m15, m28 ; t25a
+    pmulhrsw            m28, m11 ; t22a
+    pmulhrsw            m20, m23 ; t23a
+    pmulhrsw            m23, m12 ; t24a
+    jmp .main2
+ALIGN function_align
+cglobal_label .main_oddhalf
+    ITX_MULSUB_2W        22, 21,  8,  9, 10,  201, 4091 ; t16a, t31a
+    ITX_MULSUB_2W        14, 29,  8,  9, 10, 3035, 2751 ; t17a, t30a
+    ITX_MULSUB_2W        26, 17,  8,  9, 10, 1751, 3703 ; t18a, t29a
+    ITX_MULSUB_2W        18, 25,  8,  9, 10, 3857, 1380 ; t19a, t28a
+    ITX_MULSUB_2W        24, 19,  8,  9, 10,  995, 3973 ; t20a, t27a
+    ITX_MULSUB_2W        16, 27,  8,  9, 10, 3513, 2106 ; t21a, t26a
+    ITX_MULSUB_2W        28, 15,  8,  9, 10, 2440, 3290 ; t22a, t25a
+    ITX_MULSUB_2W        20, 23,  8,  9, 10, 4052,  601 ; t23a, t24a
+.main2:
+    psubsw               m8, m22, m14 ; t17
+    paddsw              m22, m14      ; t16
+    paddsw              m14, m18, m26 ; t19
+    psubsw              m18, m26      ; t18
+    psubsw              m26, m24, m16 ; t21
+    paddsw              m24, m16      ; t20
+    psubsw              m16, m20, m28 ; t22
+    paddsw              m28, m20      ; t23
+    psubsw              m20, m23, m15 ; t25
+    paddsw              m23, m15      ; t24
+    psubsw              m15, m21, m29 ; t30
+    paddsw              m21, m29      ; t31
+    psubsw              m29, m19, m27 ; t26
+    paddsw              m19, m27      ; t27
+    paddsw              m27, m25, m17 ; t28
+    psubsw              m25, m17      ; t29
+.main3:
+    ITX_MULSUB_2W        15,  8,  9, 17, 10,   799, 4017 ; t17a, t30a
+    ITX_MULSUB_2W        25, 18,  9, 17, 10, m4017,  799 ; t18a, t29a
+    ITX_MULSUB_2W        29, 26,  9, 17, 10,  3406, 2276 ; t21a, t26a
+    ITX_MULSUB_2W        20, 16,  9, 17, 10, m2276, 3406 ; t22a, t25a
+    psubsw              m17, m21, m27 ; t28a
+    paddsw              m21, m27      ; t31a
+    psubsw              m27, m15, m25 ; t18
+    paddsw              m15, m25      ; t17
+    psubsw              m25, m20, m29 ; t21
+    paddsw              m20, m29      ; t22
+    psubsw              m29, m8, m18  ; t29
+    paddsw               m8, m18      ; t30
+    psubsw              m18, m22, m14 ; t19a
+    paddsw              m22, m14      ; t16a
+    psubsw              m14, m28, m24 ; t20a
+    paddsw              m24, m28      ; t23a
+    paddsw              m28, m16, m26 ; t25
+    psubsw              m16, m26      ; t26
+    psubsw              m26, m23, m19 ; t27a
+    paddsw              m23, m19      ; t24a
+.main4:
+    vpbroadcastd        m12, [o(pw_m3784_1567)]
+    vpbroadcastd        m11, [o(pw_1567_3784)]
+    ITX_MULSUB_2W        29, 27,  9, 19, 10, 11, 12 ; t18a, t29a
+    ITX_MULSUB_2W        17, 18,  9, 19, 10, 11, 12 ; t19,  t28
+    vpbroadcastd        m11, [o(pw_m1567_m3784)]
+    ITX_MULSUB_2W        16, 25,  9, 19, 10, 12, 11 ; t21a, t26a
+    ITX_MULSUB_2W        26, 14,  9, 19, 10, 12, 11 ; t20,  t27
+    vpbroadcastd        m12, [o(pw_m2896_2896)]
+    vpbroadcastd        m11, [o(pw_2896_2896)]
+    psubsw              m19, m27, m25 ; t26
+    paddsw              m27, m25      ; t29
+    psubsw              m25, m17, m26 ; t20a
+    paddsw              m17, m26      ; t19a
+    paddsw              m26, m18, m14 ; t28a
+    psubsw              m18, m14      ; t27a
+    paddsw              m14, m22, m24 ; t16
+    psubsw              m22, m24      ; t23
+    psubsw              m24, m29, m16 ; t21
+    paddsw              m16, m29      ; t18
+    paddsw              m29, m21, m23 ; t31
+    psubsw              m21, m23      ; t24
+    psubsw              m23, m15, m20 ; t22a
+    paddsw              m15, m20      ; t17a
+    psubsw              m20, m8, m28  ; t25a
+    paddsw              m28, m8       ; t30a
+    ITX_MULSUB_2W        18, 25,  8,  9, 10, 11, 12 ; t20,  t27
+    ITX_MULSUB_2W        19, 24,  8,  9, 10, 11, 12 ; t21a, t26a
+    ITX_MULSUB_2W        21, 22,  8,  9, 10, 11, 12 ; t23a, t24a
+    ITX_MULSUB_2W        20, 23,  8,  9, 10, 11, 12 ; t22,  t25
+    ret
+
+%macro IDTX_32x32 2 ; dst[1-2]
+    vmovdqa32           ym%1, [cq+64*(%1+ 0)] ; force EVEX encoding, which
+    vmovdqa32           ym17, [cq+64*(%1+16)] ; reduces code size due to
+    vmovdqa32           ym%2, [cq+64*(%2+ 0)] ; compressed displacements
+    vmovdqa32           ym18, [cq+64*(%2+16)]
+    vpermt2q             m%1, m21, m17
+    vpermt2q             m%2, m21, m18
+%endmacro
+
+cglobal inv_txfm_add_identity_identity_32x32_8bpc, 3, 3, 22, dst, stride, c
+    movu                 m21, [permB+7]
+    vpbroadcastd         m16, [pw_8192]
+    pxor                 m20, m20
+.loop:
+    IDTX_32x32            0,  1
+    IDTX_32x32            2,  3
+    IDTX_32x32            4,  5
+    IDTX_32x32            6,  7
+    IDTX_32x32            8,  9
+    IDTX_32x32           10, 11
+    IDTX_32x32           12, 13
+    IDTX_32x32           14, 15
+    call m(inv_txfm_add_identity_identity_16x32_8bpc).transpose_2x8x8_round
+    IDTX_32x16_STORE      0,  8, 1
+    IDTX_32x16_STORE      1,  9, 1
+    IDTX_32x16_STORE      2, 10, 1
+    IDTX_32x16_STORE      3, 11, 1
+    IDTX_32x16_STORE      4, 12, 1
+    IDTX_32x16_STORE      5, 13, 1
+    IDTX_32x16_STORE      6, 14, 1
+    IDTX_32x16_STORE      7, 15, 1
+    lea                dstq, [dstq+strideq*8]
+    btc                  cq, 5
+    jnc .loop
+    mov                 r0d, 8
+.zero_loop:
+    mova          [cq+64*0], m20
+    mova          [cq+64*1], m20
+    mova          [cq+64*2], m20
+    mova          [cq+64*3], m20
+    add                  cq, 64*4
+    dec                 r0d
+    jg .zero_loop
+    RET
+
+cglobal inv_txfm_add_dct_dct_16x64_8bpc, 4, 7, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    WIN64_SPILL_XMM      30
+    cmp                eobd, 151
+    jb .fast
+    mova                 m5, [cq+64*10]
+    mova                 m3, [cq+64* 6]
+    mova                 m1, [cq+64* 2]
+    mova                 m7, [cq+64*14]
+    mova                 m2, [cq+64* 4]
+    mova                 m6, [cq+64*12]
+    mova                 m0, [cq+64* 0]
+    mova                 m4, [cq+64* 8]
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    mova                m14, [cq+64* 1]
+    mova                m21, [cq+64*15]
+    mova                m18, [cq+64* 9]
+    mova                m17, [cq+64* 7]
+    mova                m16, [cq+64* 5]
+    mova                m19, [cq+64*11]
+    mova                m20, [cq+64*13]
+    mova                m15, [cq+64* 3]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    vpbroadcastd         m9, [o(pw_8192)]
+%macro TRANSPOSE_8x4_ROUND 4
+    punpckhwd            m8, m%3, m%4 ; c4 d4 c5 d5 c6 d6 c7 d7
+    punpcklwd           m%3, m%4      ; c0 d0 c1 d1 c2 d2 c3 d3
+    punpckhwd           m%4, m%1, m%2 ; a4 b4 a5 b5 a6 b6 a7 b7
+    punpcklwd           m%1, m%2      ; a0 b0 a1 b1 a2 b2 a3 b3
+    punpckhdq           m%2, m%1, m%3 ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpckldq           m%1, m%3      ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckldq           m%3, m%4, m8  ; a4 b4 c4 d4 a5 b5 c5 d5
+    punpckhdq           m%4, m8       ; a6 b6 c6 d6 a7 b7 c7 d7
+    REPX   {pmulhrsw x, m9}, m%2, m%1, m%3, m%4
+%endmacro
+    TRANSPOSE_8x4_ROUND   0,  1,  2,  3
+    TRANSPOSE_8x4_ROUND   4,  5,  6,  7
+    TRANSPOSE_8x4_ROUND  14, 15, 16, 17
+    TRANSPOSE_8x4_ROUND  18, 19, 20, 21
+    vinserti32x8        m26, m0, ym4, 1     ; a0  a4  b0  b4
+    vshufi32x4           m0, m4, q3232      ; a8  a12 b8  b12
+    vinserti32x8        m27, m1, ym5, 1     ; a1  a5  b1  b5
+    vshufi32x4           m1, m5, q3232      ; a9  a13 b9  b13
+    vinserti32x8        m28, m2, ym6, 1     ; a2  a6  b2  b6
+    vshufi32x4           m2, m6, q3232      ; a10 a14 b10 b14
+    vinserti32x8        m29, m3, ym7, 1     ; a3  a7  b3  b7
+    vshufi32x4           m8, m3, m7, q3232  ; a11 a15 b11 b15
+    vinserti32x8         m4, m14, ym18, 1   ; c0  c4  d0  d4
+    vshufi32x4          m14, m18, q3232     ; c8  c12 d8  d12
+    vinserti32x8         m5, m15, ym19, 1   ; c1  c5  d1  d5
+    vshufi32x4          m15, m19, q3232     ; c9  c13 d9  d13
+    vinserti32x8         m6, m16, ym20, 1   ; c2  c6  d2  d6
+    vshufi32x4          m16, m20, q3232     ; c10 c14 d10 d14
+    vinserti32x8         m7, m17, ym21, 1   ; c3  c7  d3  d7
+    vshufi32x4          m17, m21, q3232     ; c11 c15 d11 d15
+    vshufi32x4          m22, m26, m4, q2020 ;  0  1
+    vshufi32x4          m26, m4, q3131      ;  8  9
+    vshufi32x4          m23, m27, m5, q2020 ;  2  3
+    vshufi32x4          m27, m5, q3131      ; 10 11
+    vshufi32x4          m24, m28, m6, q2020 ;  4  5
+    vshufi32x4          m28, m6, q3131      ; 12 13
+    vshufi32x4          m25, m29, m7, q2020 ;  6  7
+    vshufi32x4          m29, m7, q3131      ; 14 15
+    vshufi32x4           m4, m0, m14, q2020 ; 16 17
+    vshufi32x4           m3, m0, m14, q3131 ; 24 25
+    vshufi32x4          m20, m1, m15, q2020 ; 18 19
+    vshufi32x4          m19, m1, m15, q3131 ; 26 27
+    vshufi32x4           m5, m2, m16, q2020 ; 20 21
+    vshufi32x4           m0, m2, m16, q3131 ; 28 29
+    vshufi32x4          m16, m8, m17, q2020 ; 22 23
+    vshufi32x4          m17, m8, m17, q3131 ; 30 31
+    pxor                 m6, m6
+    mova         [cq+64* 0], m4
+    mova         [cq+64* 2], m5
+    mova         [cq+64* 4], m3
+    mova         [cq+64* 6], m0
+    punpcklwd            m8, m24, m24 ;  4
+    punpcklwd            m0, m0       ; 28
+    punpcklwd            m5, m5       ; 20
+    punpcklwd            m1, m28, m28 ; 12
+    punpcklwd            m7, m26, m26 ;  8
+    punpcklwd            m3, m3       ; 24
+    punpcklwd            m9, m6, m22  ; __  0
+    punpcklwd            m6, m4       ; __ 16
+    call m(idct_16x16_internal_8bpc).main_fast3
+    mova         [cq+64* 1], m20
+    mova         [cq+64* 3], m16
+    mova         [cq+64* 5], m19
+    mova         [cq+64* 7], m17
+    punpcklwd           m21, m23, m23 ;  2
+    punpcklwd           m17, m17      ; 30
+    punpcklwd           m20, m20      ; 18
+    punpcklwd           m15, m29, m29 ; 14
+    punpcklwd           m18, m27, m27 ; 10
+    punpcklwd           m16, m16      ; 22
+    punpcklwd           m19, m19      ; 26
+    punpcklwd           m14, m25, m25 ;  6
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    mova         [cq+64* 8], m14
+    mova         [cq+64* 9], m15
+    mova         [cq+64*10], m16
+    mova         [cq+64*11], m17
+    mova         [cq+64*12], m18
+    mova         [cq+64*13], m19
+    mova         [cq+64*14], m20
+    mova         [cq+64*15], m21
+    mova                m21, [cq+64* 7]
+    mova                m14, [cq+64* 0]
+    mova                m17, [cq+64* 3]
+    mova                m18, [cq+64* 4]
+    mova                m19, [cq+64* 5]
+    mova                m16, [cq+64* 2]
+    mova                m15, [cq+64* 1]
+    mova                m20, [cq+64* 6]
+    REPX   {punpckhwd x, x}, m22, m21, m14, m29, m26, m17, m18, m25, \
+                             m24, m19, m16, m27, m28, m15, m20, m23
+    call .main_oddhalf
+    jmp .end
+.fast: ; right half is zero
+    mova                ym8, [cq+64*15]
+    vinserti32x8         m8, [cq+64* 1], 1
+    mova                 m2, [o(int16_perm)]
+    mova                ym9, [cq+64* 8]
+    vinserti32x8         m9, [cq+64* 0], 1
+    mova                ym0, [cq+64* 7]
+    vinserti32x8         m0, [cq+64* 9], 1
+    mova                ym7, [cq+64*14]
+    vinserti32x8         m7, [cq+64* 2], 1
+    mova                ym1, [cq+64* 3]
+    vinserti32x8         m1, [cq+64*13], 1
+    mova                ym3, [cq+64* 6]
+    vinserti32x8         m3, [cq+64*10], 1
+    mova                ym5, [cq+64*11]
+    vinserti32x8         m5, [cq+64* 5], 1
+    mova                ym6, [cq+64*12]
+    vinserti32x8         m6, [cq+64* 4], 1
+    REPX  {vpermb x, m2, x}, m8, m9, m0, m7, m1, m3, m5, m6
+    call m(idct_16x16_internal_8bpc).main2
+    vbroadcasti32x4      m8, [o(int_shuf3)]
+    vbroadcasti32x4      m9, [o(int_shuf4)]
+    vpbroadcastd        m11, [o(pw_8192)]
+    pshufb               m0, m8
+    pshufb               m1, m9
+    pshufb               m2, m8
+    pshufb               m3, m9
+    REPX  {pmulhrsw x, m11}, m0, m1, m2, m3
+    pshufb               m4, m8
+    pshufb               m5, m9
+    pshufb               m6, m8
+    pshufb               m7, m9
+    REPX  {pmulhrsw x, m11}, m4, m5, m6, m7
+    punpckhdq           m28, m0, m1
+    punpckldq            m0, m1
+    punpckhdq           m27, m2, m3
+    punpckldq            m2, m3
+    punpckhdq           m22, m4, m5
+    punpckldq            m4, m5
+    punpckhdq           m23, m6, m7
+    punpckldq            m6, m7
+    vinserti32x8        m14, m0, ym2, 1
+    vshufi32x4          m15, m0, m2, q3232
+    vinserti32x8         m2, m4, ym6, 1
+    vshufi32x4           m4, m6, q3232
+    vshufi32x4          m21, m14, m2, q2020 ;  0  2
+    vshufi32x4          m14, m2, q3131      ;  4  6
+    vshufi32x4          m18, m15, m4, q2020 ;  8 10
+    vshufi32x4          m15, m4, q3131      ; 12 14
+    pxor                 m9, m9
+    punpcklwd            m8, m14, m14 ;  4
+    punpcklwd            m1, m15, m15 ; 12
+    punpcklwd            m7, m18, m18 ;  8
+    punpcklwd            m9, m21      ; __  0
+    call m(idct_16x16_internal_8bpc).main_fast4
+    punpckhwd           m21, m21      ;  2
+    punpckhwd           m15, m15      ; 14
+    punpckhwd           m18, m18      ; 10
+    punpckhwd           m14, m14      ;  6
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast2
+    vinserti32x8        m24, m28, ym27, 1
+    vshufi32x4          m28, m27, q3232
+    vinserti32x8        m27, m22, ym23, 1
+    vshufi32x4          m22, m23, q3232
+    vshufi32x4          m23, m24, m27, q2020 ;  1  3
+    vshufi32x4          m24, m27, q3131      ;  5  7
+    vshufi32x4          m27, m28, m22, q2020 ;  9 11
+    vshufi32x4          m28, m22, q3131      ; 13 15
+    punpcklwd           m22, m23, m23 ;  1
+    punpckhwd           m29, m28, m28 ; 15
+    punpcklwd           m26, m27, m27 ;  9
+    punpckhwd           m25, m24, m24 ;  7
+    mova         [cq+64* 8], m14
+    mova         [cq+64* 9], m15
+    mova         [cq+64*10], m16
+    mova         [cq+64*11], m17
+    punpcklwd           m24, m24      ;  5
+    punpckhwd           m27, m27      ; 11
+    punpcklwd           m28, m28      ; 13
+    punpckhwd           m23, m23      ;  3
+    mova         [cq+64*12], m18
+    mova         [cq+64*13], m19
+    mova         [cq+64*14], m20
+    mova         [cq+64*15], m21
+    call .main_oddhalf_fast
+.end:
+    imul                 r6, strideq, 60
+    mova                m10, [o(end_16x32p)]
+    vpbroadcastd        m11, [o(pw_2048)]
+    lea                  r3, [strideq*3]
+    pxor                m12, m12
+    add                  r6, dstq         ; dst+stride*60
+    psrldq              m13, m10, 1
+    lea                  r4, [strideq+r3] ; stride*4
+%macro IDCT_16x64_END 3 ; idct32, idct64, tmp
+%if %1 & 1
+    %define %%s0 r3
+    %define %%s1 strideq*2
+    %define %%s2 strideq*1
+    %define %%s3 strideq*0
+%else
+    %define %%s0 strideq*0
+    %define %%s1 strideq*1
+    %define %%s2 strideq*2
+    %define %%s3 r3
+%if %1
+    add                dstq, r4
+    sub                  r6, r4
+%endif
+%endif
+%if %1 < 8
+    pmulhrsw             m8, m11, m%1
+    pmulhrsw             m9, m11, m%2
+%else
+    mova                 m9, [cq+64*%1]
+    paddsw               m8, m9, m%2 ; out  0+n,  1+n
+    psubsw               m9, m%2     ; out 63-n, 62-n
+    pmulhrsw             m8, m11
+    pmulhrsw             m9, m11
+%endif
+    mova               xm29, [dstq+%%s0]
+    vinserti128        ym29, [dstq+%%s1], 1
+    mova               xm%3, [r6  +%%s3]
+    vinserti128        ym%3, [r6  +%%s2], 1
+    vpermb              m29, m10, m29
+    vpermb              m%3, m10, m%3
+    mova         [cq+64*%1], m12
+    paddw               m29, m8
+    paddw               m%3, m9
+    packuswb            m29, m%3
+    vpermd              m29, m13, m29
+    mova          [dstq+%%s0], xm29
+    vextracti128  [dstq+%%s1], ym29, 1
+    vextracti32x4 [r6  +%%s2], m29, 2
+    vextracti32x4 [r6  +%%s3], m29, 3
+%endmacro
+    IDCT_16x64_END        0, 29,  0
+    IDCT_16x64_END        1, 28, 28
+    IDCT_16x64_END        2, 27, 28
+    IDCT_16x64_END        3, 26, 28
+    IDCT_16x64_END        4, 25, 28
+    IDCT_16x64_END        5, 24, 28
+    IDCT_16x64_END        6, 23, 28
+    IDCT_16x64_END        7, 22, 28
+    IDCT_16x64_END        8, 21, 28
+    IDCT_16x64_END        9, 20, 28
+    IDCT_16x64_END       10, 19, 28
+    IDCT_16x64_END       11, 18, 28
+    IDCT_16x64_END       12, 17, 28
+    IDCT_16x64_END       13, 16, 28
+    IDCT_16x64_END       14, 15, 28
+    IDCT_16x64_END       15, 14, 28
+    RET
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 64
+    imul                r6d, 181
+    add                 r6d, 128+512
+    sar                 r6d, 8+2
+    jmp m(inv_txfm_add_dct_dct_16x8_8bpc).dconly3
+ALIGN function_align
+cglobal_label .main_oddhalf_fast ; bottom three-quarters are zero
+    vpbroadcastd         m8, [o(pw_101_4095x8)]
+    vpbroadcastd        m21, [o(pw_m1474_3822x8)]
+    vpbroadcastd        m14, [o(pw_897_3996x8)]
+    vpbroadcastd        m17, [o(pw_m700_4036x8)]
+    vpbroadcastd        m18, [o(pw_501_4065x8)]
+    vpbroadcastd        m19, [o(pw_m1092_3948x8)]
+    vpbroadcastd        m16, [o(pw_1285_3889x8)]
+    vpbroadcastd        m15, [o(pw_m301_4085x8)]
+    pmulhrsw             m8, m22 ; t32a t63a
+    pmulhrsw            m21, m29 ; t35a t60a
+    pmulhrsw            m14, m26 ; t36a t59a
+    pmulhrsw            m17, m25 ; t39a t56
+    pmulhrsw            m18, m24 ; t40a t55a
+    pmulhrsw            m19, m27 ; t43a t52a
+    pmulhrsw            m16, m28 ; t44a t51a
+    pmulhrsw            m15, m23 ; t47a t48a
+    mova                m22, m8
+    mova                m29, m21
+    mova                m26, m14
+    mova                m25, m17
+    mova                m24, m18
+    mova                m27, m19
+    mova                m28, m16
+    mova                m20, m15
+    jmp .main_oddhalf2
+ALIGN function_align
+cglobal_label .main_oddhalf
+    vpbroadcastd         m8, [o(pw_101_4095x8)]
+    vpbroadcastd         m9, [o(pw_m2824_2967x8)]
+    vpbroadcastd        m11, [o(pw_1660_3745x8)]
+    vpbroadcastd        m12, [o(pw_m1474_3822x8)]
+    pmulhrsw            m22, m8       ; t32a t63a
+    vpbroadcastd         m8, [o(pw_897_3996x8)]
+    pmulhrsw            m21, m9       ; t33a t62a
+    vpbroadcastd         m9, [o(pw_m2191_3461x8)]
+    pmulhrsw            m14, m11      ; t34a t61a
+    vpbroadcastd        m11, [o(pw_2359_3349x8)]
+    pmulhrsw            m29, m12      ; t35a t60a
+    vpbroadcastd        m12, [o(pw_m700_4036x8)]
+    pmulhrsw            m26, m8       ; t36a t59a
+    vpbroadcastd         m8, [o(pw_501_4065x8)]
+    pmulhrsw            m17, m9       ; t37a t58a
+    vpbroadcastd         m9, [o(pw_m2520_3229x8)]
+    pmulhrsw            m18, m11      ; t38a t57a
+    vpbroadcastd        m11, [o(pw_2019_3564x8)]
+    pmulhrsw            m25, m12      ; t39a t56a
+    vpbroadcastd        m12, [o(pw_m1092_3948x8)]
+    pmulhrsw            m24, m8       ; t40a t55a
+    vpbroadcastd         m8, [o(pw_1285_3889x8)]
+    pmulhrsw            m19, m9       ; t41a t54a
+    vpbroadcastd         m9, [o(pw_m1842_3659x8)]
+    pmulhrsw            m16, m11      ; t42a t53a
+    vpbroadcastd        m11, [o(pw_2675_3102x8)]
+    pmulhrsw            m27, m12      ; t43a t52a
+    vpbroadcastd        m12, [o(pw_m301_4085x8)]
+    pmulhrsw            m28, m8       ; t44a t51a
+    pmulhrsw            m15, m9       ; t45a t50a
+    pmulhrsw            m20, m11      ; t46a t49a
+    pmulhrsw            m23, m12      ; t47a t48a
+    psubsw               m8, m22, m21 ; t33  t62
+    paddsw              m22, m21      ; t32  t63
+    psubsw              m21, m29, m14 ; t34  t61
+    paddsw              m29, m14      ; t35  t60
+    psubsw              m14, m26, m17 ; t37  t58
+    paddsw              m26, m17      ; t36  t59
+    psubsw              m17, m25, m18 ; t38  t57
+    paddsw              m25, m18      ; t39  t56
+    psubsw              m18, m24, m19 ; t41  t54
+    paddsw              m24, m19      ; t40  t55
+    psubsw              m19, m27, m16 ; t42  t53
+    paddsw              m27, m16      ; t43  t52
+    psubsw              m16, m28, m15 ; t45  t50
+    paddsw              m28, m15      ; t44  t51
+    psubsw              m15, m23, m20 ; t46  t49
+    paddsw              m20, m23      ; t47  t48
+.main_oddhalf2:
+    ITX_MUL2X_PACK        8, 9, 23, 10,   401, 4076, 5 ; t33a t62a
+    ITX_MUL2X_PACK       21, 9, 23, 10, m4076,  401, 5 ; t34a t61a
+    ITX_MUL2X_PACK       14, 9, 23, 10,  3166, 2598, 5 ; t37a t58a
+    ITX_MUL2X_PACK       17, 9, 23, 10, m2598, 3166, 5 ; t38a t57a
+    ITX_MUL2X_PACK       18, 9, 23, 10,  1931, 3612, 5 ; t41a t54a
+    ITX_MUL2X_PACK       19, 9, 23, 10, m3612, 1931, 5 ; t42a t53a
+    ITX_MUL2X_PACK       16, 9, 23, 10,  3920, 1189, 5 ; t45a t50a
+    ITX_MUL2X_PACK       15, 9, 23, 10, m1189, 3920, 5 ; t46a t49a
+    vpbroadcastd        m11, [o(pw_m4017_799)]
+    psubsw              m23, m25, m26 ; t36a t59a
+    paddsw              m25, m26      ; t39a t56a
+    psubsw              m26, m24, m27 ; t43a t52a
+    paddsw              m27, m24      ; t40a t55a
+    psubsw              m24, m20, m28 ; t44a t51a
+    paddsw              m20, m28      ; t47a t48a
+    psubsw              m28, m8, m21  ; t34  t61
+    paddsw               m8, m21      ; t33  t62
+    psubsw              m21, m17, m14 ; t37  t58
+    paddsw              m17, m14      ; t38  t57
+    psubsw              m14, m18, m19 ; t42  t53
+    paddsw              m18, m19      ; t41  t54
+    psubsw              m19, m15, m16 ; t45  t50
+    paddsw              m15, m16      ; t46  t49
+    psubsw              m16, m22, m29 ; t35a t60a
+    paddsw              m22, m29      ; t32a t63a
+    ITX_MUL2X_PACK       16, 9, 29, 10, 799_4017, 11,    20 ; t35  t60
+    ITX_MUL2X_PACK       28, 9, 29, 10, 799_4017, 11,    20 ; t34a t61a
+    ITX_MUL2X_PACK       23, 9, 29, 10, 11, m799_m4017,  36 ; t36  t59
+    ITX_MUL2X_PACK       21, 9, 29, 10, 11, m799_m4017,  36 ; t37a t58a
+    vpbroadcastd        m11, [o(pw_m2276_3406)]
+    ITX_MUL2X_PACK       26, 9, 29, 10, 3406_2276, 11,   20 ; t43  t52
+    ITX_MUL2X_PACK       14, 9, 29, 10, 3406_2276, 11,   20 ; t42a t53a
+    ITX_MUL2X_PACK       24, 9, 29, 10, 11, m3406_m2276, 36 ; t44  t51
+    ITX_MUL2X_PACK       19, 9, 29, 10, 11, m3406_m2276, 36 ; t45a t50a
+    vpbroadcastd        m11, [o(pw_1567_3784)]
+    vpbroadcastd        m12, [o(pw_m3784_1567)]
+    psubsw              m29, m22, m25 ; t39  t56
+    paddsw              m22, m25      ; t32  t63
+    psubsw              m25, m20, m27 ; t40  t55
+    paddsw              m20, m27      ; t47  t48
+    psubsw              m27, m8, m17  ; t38a t57a
+    paddsw               m8, m17      ; t33a t62a
+    psubsw              m17, m15, m18 ; t41a t54a
+    paddsw              m15, m18      ; t46a t49a
+    paddsw              m18, m16, m23 ; t35a t60a
+    psubsw              m16, m23      ; t36a t59a
+    psubsw              m23, m24, m26 ; t43a t52a
+    paddsw              m24, m26      ; t44a t51a
+    paddsw              m26, m28, m21 ; t34  t61
+    psubsw              m28, m21      ; t37  t58
+    psubsw              m21, m19, m14 ; t42  t53
+    paddsw              m19, m14      ; t45  t50
+    ITX_MUL2X_PACK       29, 9, 14, 10, 11, 12, 4 ; t39a t56a
+    ITX_MUL2X_PACK       27, 9, 14, 10, 11, 12, 4 ; t38  t57
+    ITX_MUL2X_PACK       16, 9, 14, 10, 11, 12, 4 ; t36  t59
+    ITX_MUL2X_PACK       28, 9, 14, 10, 11, 12, 4 ; t37a t58a
+    vpbroadcastd        m11, [o(pw_m1567_m3784)]
+    ITX_MUL2X_PACK       25, 9, 14, 10, 12, 11, 4 ; t40a t55a
+    ITX_MUL2X_PACK       17, 9, 14, 10, 12, 11, 4 ; t41  t54
+    ITX_MUL2X_PACK       23, 9, 14, 10, 12, 11, 4 ; t43  t52
+    ITX_MUL2X_PACK       21, 9, 14, 10, 12, 11, 4 ; t42a t53a
+    vbroadcasti32x4     m13, [o(deint_shuf)]
+    vpbroadcastd        m11, [o(pw_2896_2896)]
+    vpbroadcastd        m12, [o(pw_m2896_2896)]
+    paddsw              m14, m22, m20 ; t32a t63a
+    psubsw              m22, m20      ; t47a t48a
+    psubsw              m20, m8, m15  ; t46  t49
+    paddsw               m8, m15      ; t33  t62
+    paddsw              m15, m18, m24 ; t35  t60
+    psubsw              m18, m24      ; t44  t51
+    psubsw              m24, m26, m19 ; t45a t50a
+    paddsw              m26, m19      ; t34a t61a
+    REPX    {pshufb x, m13}, m14, m8, m15, m26
+    psubsw              m19, m29, m25 ; t40  t55
+    paddsw              m25, m29      ; t39  t56
+    psubsw              m29, m27, m17 ; t41a t54a
+    paddsw              m27, m17      ; t38a t57a
+    psubsw              m17, m16, m23 ; t43a t52a
+    paddsw              m16, m23      ; t36a t59a
+    psubsw               m9, m28, m21 ; t42  t53
+    paddsw              m28, m21      ; t37  t58
+    REPX    {pshufb x, m13}, m25, m27, m16, m28
+    ITX_MUL2X_PACK       22, 13, 21, 10, 11, 12, 8 ; t47  t48
+    ITX_MUL2X_PACK       20, 23, 22, 10, 11, 12, 8 ; t46a t49a
+    packssdw            m21, m22      ; t47  t46a
+    packssdw            m13, m23      ; t48  t49a
+    ITX_MUL2X_PACK       18, 22, 20, 10, 11, 12, 8 ; t44a t51a
+    ITX_MUL2X_PACK       24, 23, 18, 10, 11, 12, 8 ; t45  t50
+    packssdw            m20, m18      ; t44a t45
+    packssdw            m22, m23      ; t51a t50
+    ITX_MUL2X_PACK       19, 24, 18, 10, 11, 12, 8 ; t40a t55a
+    ITX_MUL2X_PACK       29, 23, 19, 10, 11, 12, 8 ; t41  t54
+    packssdw            m18, m19      ; t40a t41
+    packssdw            m24, m23      ; t55a t54
+    ITX_MUL2X_PACK       17, 23, 19, 10, 11, 12, 8 ; t43  t52
+    ITX_MUL2X_PACK        9, 29, 17, 10, 11, 12, 8 ; t42a t53a
+    packssdw            m19, m17      ; t43  t42a
+    packssdw            m23, m29      ; t52  t53a
+    punpcklqdq          m17, m25, m27 ; t39  t38a
+    punpckhqdq          m25, m27      ; t56  t57a
+    punpckhqdq          m27, m15, m26 ; t60  t61a
+    punpcklqdq          m15, m26      ; t35  t34a
+    punpckhqdq          m26, m16, m28 ; t59a t58
+    punpcklqdq          m16, m28      ; t36a t37
+    punpckhqdq          m28, m14, m8  ; t63a t62
+    punpcklqdq          m14, m8       ; t32a t33
+    psubsw              m29, m0, m28  ; out63 out62
+    paddsw               m0, m28      ; out0  out1
+    psubsw              m28, m1, m27  ; out60 out61
+    paddsw               m1, m27      ; out3  out2
+    psubsw              m27, m2, m26  ; out59 out58
+    paddsw               m2, m26      ; out4  out5
+    psubsw              m26, m3, m25  ; out56 out57
+    paddsw               m3, m25      ; out7  out6
+    psubsw              m25, m4, m24  ; out55 out54
+    paddsw               m4, m24      ; out8  out9
+    psubsw              m24, m5, m23  ; out52 out53
+    paddsw               m5, m23      ; out11 out10
+    psubsw              m23, m6, m22  ; out51 out50
+    paddsw               m6, m22      ; out12 out13
+    psubsw              m22, m7, m13  ; out48 out49
+    paddsw               m7, m13      ; out15 out14
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x16_8bpc, 4, 7, 0, dst, stride, c, eob
+%undef cmp
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jnz .normal
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 16
+.dconly:
+    imul                r6d, 181
+    add                 r6d, 128+512
+    sar                 r6d, 8+2
+.dconly2:
+    imul                r6d, 181
+    add                 r6d, 128+2048
+    sar                 r6d, 8+4
+    pxor                 m2, m2
+    vpbroadcastw         m3, r6d
+.dconly_loop:
+    mova                 m1, [dstq]
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    paddw                m0, m3
+    paddw                m1, m3
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                 r3d
+    jg .dconly_loop
+    RET
+.normal:
+    WIN64_SPILL_XMM      31
+    mova                m19, [o(dup16_perm)]
+    mova                m24, [cq+64* 2]
+    mova                m28, [cq+64* 6]
+    mova                m26, [cq+64* 4]
+    mova                m22, [cq+64* 0]
+    mova                m23, [cq+64* 1]
+    mova                m29, [cq+64* 7]
+    mova                m27, [cq+64* 5]
+    mova                m25, [cq+64* 3]
+    vpermb               m8, m19, m24        ;  4
+    vpermb               m1, m19, m28        ; 12
+    vpermb               m7, m19, m26        ;  8
+    vpermb               m9, m19, m22        ; __  0
+    vpermb              m21, m19, m23        ;  2
+    vpermb              m15, m19, m29        ; 14
+    vpermb              m18, m19, m27        ; 10
+    vpermb              m14, m19, m25        ;  6
+    pslld                m9, 16
+    vpord               m30, m19, [o(pb_32)] {1to16}
+    REPX {vpermb x, m30, x}, m22, m29, m26, m25, m24, m27, m28, m23
+    cmp                eobd, 151
+    jb .fast
+    vpermb               m0, m19, [cq+64*14] ; 28
+    vpermb               m5, m19, [cq+64*10] ; 20
+    vpermb               m3, m19, [cq+64*12] ; 24
+    vpermb               m6, m19, [cq+64* 8] ; __ 16
+    pslld                m6, 16
+    call m(idct_16x16_internal_8bpc).main_fast
+    vpermb              m17, m19, [cq+64*15] ; 30
+    vpermb              m20, m19, [cq+64* 9] ; 18
+    vpermb              m16, m19, [cq+64*11] ; 22
+    vpermb              m19, m19, [cq+64*13] ; 26
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 1], m15
+    mova         [cq+64* 2], m16
+    mova         [cq+64* 3], m17
+    mova         [cq+64* 4], m18
+    mova         [cq+64* 5], m19
+    mova         [cq+64* 6], m20
+    mova         [cq+64* 7], m21
+    vpermb              m21, m30, [cq+64*15]
+    vpermb              m14, m30, [cq+64* 8]
+    vpermb              m17, m30, [cq+64*11]
+    vpermb              m18, m30, [cq+64*12]
+    vpermb              m19, m30, [cq+64*13]
+    vpermb              m16, m30, [cq+64*10]
+    vpermb              m15, m30, [cq+64* 9]
+    vpermb              m20, m30, [cq+64*14]
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_oddhalf
+    jmp .end
+.fast: ; bottom half is zero
+    call m(idct_16x16_internal_8bpc).main_fast2
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast2
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 1], m15
+    mova         [cq+64* 2], m16
+    mova         [cq+64* 3], m17
+    mova         [cq+64* 4], m18
+    mova         [cq+64* 5], m19
+    mova         [cq+64* 6], m20
+    mova         [cq+64* 7], m21
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_oddhalf_fast
+.end:
+    mova         [cq+64* 8], m4
+    mova         [cq+64* 9], m5
+    mova         [cq+64*10], m6
+    mova         [cq+64*11], m7
+    mova         [cq+64*12], m26
+    mova         [cq+64*13], m27
+    mova         [cq+64*14], m28
+    mova         [cq+64*15], m29
+    vpbroadcastd        m13, [o(pw_8192)]
+    call .pass1_end
+    call .pass2
+    mova         [cq+64* 0], m0
+    mova         [cq+64* 1], m1
+    mova         [cq+64* 2], m2
+    mova         [cq+64* 3], m3
+    mova         [cq+64* 4], m4
+    mova         [cq+64* 5], m5
+    mova         [cq+64* 6], m6
+    mova         [cq+64* 7], m7
+    pmulhrsw             m0, m13, [cq+64* 8]
+    pmulhrsw             m1, m13, [cq+64* 9]
+    pmulhrsw             m2, m13, [cq+64*10]
+    pmulhrsw             m3, m13, [cq+64*11]
+    vpbroadcastd        m30, [o(pw_2048)]
+    pmulhrsw             m4, m13, m22
+    pmulhrsw             m5, m13, m23
+    pmulhrsw             m6, m13, m24
+    pmulhrsw             m7, m13, m25
+    pmulhrsw            m22, m30, m14
+    pmulhrsw            m14, m13, m26
+    pmulhrsw            m23, m30, m15
+    pmulhrsw            m15, m13, m27
+    pmulhrsw            m24, m30, m16
+    pmulhrsw            m16, m13, m28
+    pmulhrsw            m25, m30, m17
+    pmulhrsw            m17, m13, m29
+    pmulhrsw            m26, m30, m18
+    pmulhrsw            m18, m13, [cq+64*12]
+    pmulhrsw            m27, m30, m19
+    pmulhrsw            m19, m13, [cq+64*13]
+    pmulhrsw            m28, m30, m20
+    pmulhrsw            m20, m13, [cq+64*14]
+    pmulhrsw            m29, m30, m21
+    pmulhrsw            m21, m13, [cq+64*15]
+    call .transpose_round
+    call .pass2
+    pxor                m10, m10
+    lea                  r3, [strideq*3]
+%macro IDCT_64x16_END 4
+    mova                 m9, [dstq+%4]
+%if %1 < 8
+    pmulhrsw            m%3, m30, [cq+64*%1]
+%endif
+    pmulhrsw            m%2, m30
+    mova         [cq+64*%1], m10
+    punpcklbw            m8, m9, m10
+    punpckhbw            m9, m10
+    paddw                m8, m%3
+    paddw                m9, m%2
+    packuswb             m8, m9
+    mova          [dstq+%4], m8
+%if %1 == 3 || %1 == 7 || %1 == 11
+    lea                dstq, [dstq+strideq*4]
+%endif
+%endmacro
+    IDCT_64x16_END        0,  0, 11, strideq*0
+    IDCT_64x16_END        1,  1, 11, strideq*1
+    IDCT_64x16_END        2,  2, 11, strideq*2
+    IDCT_64x16_END        3,  3, 11, r3
+    IDCT_64x16_END        4,  4, 11, strideq*0
+    IDCT_64x16_END        5,  5, 11, strideq*1
+    IDCT_64x16_END        6,  6, 11, strideq*2
+    IDCT_64x16_END        7,  7, 11, r3
+    IDCT_64x16_END        8, 14, 22, strideq*0
+    IDCT_64x16_END        9, 15, 23, strideq*1
+    IDCT_64x16_END       10, 16, 24, strideq*2
+    IDCT_64x16_END       11, 17, 25, r3
+    IDCT_64x16_END       12, 18, 26, strideq*0
+    IDCT_64x16_END       13, 19, 27, strideq*1
+    IDCT_64x16_END       14, 20, 28, strideq*2
+    IDCT_64x16_END       15, 21, 29, r3
+    RET
+ALIGN function_align
+.pass1_end:
+    mova                 m4, [cq+64* 0]
+    mova                 m5, [cq+64* 1]
+    mova                 m6, [cq+64* 2]
+    mova                 m7, [cq+64* 3]
+    mova                 m8, [cq+64* 4]
+    mova                 m9, [cq+64* 5]
+    mova                m11, [cq+64* 6]
+    mova                m12, [cq+64* 7]
+    psubsw              m29, m4, m21  ; out47 out46
+    paddsw               m4, m21      ; out16 out17
+    psubsw              m28, m5, m20  ; out44 out45
+    paddsw               m5, m20      ; out19 out18
+    REPX  {pmulhrsw x, m13}, m0, m1, m2, m3
+    psubsw              m27, m6, m19  ; out43 out42
+    paddsw               m6, m19      ; out20 out21
+    psubsw              m26, m7, m18  ; out40 out41
+    paddsw               m7, m18      ; out23 out22
+    pmulhrsw            m18, m13, m22
+    pmulhrsw            m19, m13, m23
+    pmulhrsw            m20, m13, m24
+    pmulhrsw            m21, m13, m25
+    paddsw              m25, m12, m14 ; out31 out30
+    psubsw              m14, m12, m14 ; out32 out33
+    paddsw              m24, m11, m15 ; out28 out29
+    psubsw              m15, m11, m15 ; out35 out34
+    REPX  {pmulhrsw x, m13}, m4, m5, m6, m7
+    paddsw              m23, m9, m16  ; out27 out26
+    psubsw              m16, m9, m16  ; out36 out37
+    paddsw              m22, m8, m17  ; out24 out25
+    psubsw              m17, m8, m17  ; out39 out38
+    REPX  {pmulhrsw x, m13}, m14, m15, m16, m17
+.transpose_round:
+%macro TRANSPOSE_8x4_PACKED 4
+    punpckhwd            m8, m%1, m%3 ; b0 f0 b1 f1 b2 f2 b3 f3
+    punpcklwd           m%1, m%3      ; a0 e0 a1 e1 a2 e2 a3 e3
+    punpcklwd           m%3, m%2, m%4 ; d0 h0 d1 h1 d2 h2 d3 h3
+    punpckhwd           m%2, m%4      ; c0 g0 c1 g1 c2 g2 c3 g3
+    punpckhwd           m%4, m%1, m%2 ; a2 c2 e2 g2 a3 c3 e3 g3
+    punpcklwd           m%1, m%2      ; a0 c0 e0 g0 a1 c1 e1 g1
+    punpckhwd           m%2, m8, m%3  ; b2 d2 f2 h2 b3 d3 f3 h3
+    punpcklwd            m8, m%3      ; b0 d0 f0 h0 b1 d1 f1 h1
+    punpcklwd           m%3, m%4, m%2 ; 2
+    punpckhwd           m%4, m%2      ; 3
+    punpckhwd           m%2, m%1, m8  ; 1
+    punpcklwd           m%1, m8       ; 0
+%endmacro
+    TRANSPOSE_8x4_PACKED  0,  1,  2,  3
+    TRANSPOSE_8x4_PACKED 18, 19, 20, 21
+    TRANSPOSE_8x4_PACKED  4,  5,  6,  7
+    TRANSPOSE_8x4_PACKED 14, 15, 16, 17
+    vshufi32x4           m8, m0, m4, q3232   ; a02 a03 b02 b03
+    vinserti32x8         m0, ym4, 1          ; a00 a01 b00 b01
+    vshufi32x4           m4, m1, m5, q3232   ; a12 a13 b12 b13
+    vinserti32x8         m9, m1, ym5, 1      ; a10 a11 b10 b11
+    vshufi32x4           m5, m2, m6, q3232   ; a22 a23 b22 b23
+    vinserti32x8         m1, m2, ym6, 1      ; a20 a21 b20 b21
+    vshufi32x4           m6, m3, m7, q3232   ; a32 a33 b32 b33
+    vinserti32x8        m11, m3, ym7, 1      ; a30 a31 b30 b31
+    vshufi32x4           m2, m14, m18, q3232 ; c02 c03 d02 d03
+    vinserti32x8         m3, m14, ym18, 1    ; c00 c01 d00 d01
+    vshufi32x4          m18, m15, m19, q3232 ; c12 c13 d12 d13
+    vinserti32x8        m15, ym19, 1         ; c10 c11 d10 d11
+    vshufi32x4          m19, m16, m20, q3232 ; c22 c23 d22 d23
+    vinserti32x8        m16, ym20, 1         ; c20 c21 d20 d21
+    vshufi32x4          m20, m17, m21, q3232 ; c32 c33 d32 d33
+    vinserti32x8        m17, ym21, 1         ; c30 c31 d30 d31
+    ret
+.pass2:
+    vshufi32x4           m7, m5, m19, q3131  ; 14
+    vshufi32x4           m5, m19, q2020      ; 10
+    vshufi32x4          m21, m6, m20, q3131  ; 15
+    vshufi32x4          m19, m6, m20, q2020  ; 11
+    vshufi32x4          m20, m4, m18, q3131  ; 13
+    vshufi32x4          m18, m4, m18, q2020  ;  9
+    vshufi32x4           m6, m8, m2, q3131   ; 12
+    vshufi32x4           m4, m8, m2, q2020   ;  8
+    vshufi32x4           m2, m0, m3, q3131   ;  4
+    vshufi32x4           m0, m3, q2020       ;  0
+    vshufi32x4           m3, m1, m16, q3131  ;  6
+    vshufi32x4           m1, m16, q2020      ;  2
+    vshufi32x4          m16, m9, m15, q3131  ;  5
+    vshufi32x4          m14, m9, m15, q2020  ;  1
+    vshufi32x4          m15, m11, m17, q2020 ;  3
+    vshufi32x4          m17, m11, m17, q3131 ;  7
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main2
+    jmp m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+
+cglobal inv_txfm_add_dct_dct_32x64_8bpc, 4, 7, 0, dst, stride, c, eob
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 9, 30, 64*32, dst, stride, c, eob
+    vpbroadcastd        m23, [o(pw_2896x8)]
+%undef cmp
+    cmp                eobd, 136
+    jb .fast
+    pmulhrsw             m5, m23, [cq+64*20]
+    pmulhrsw             m3, m23, [cq+64*12]
+    pmulhrsw             m1, m23, [cq+64* 4]
+    pmulhrsw             m7, m23, [cq+64*28]
+    pmulhrsw             m2, m23, [cq+64* 8]
+    pmulhrsw             m6, m23, [cq+64*24]
+    pmulhrsw             m0, m23, [cq+64* 0]
+    pmulhrsw             m4, m23, [cq+64*16]
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    pmulhrsw            m14, m23, [cq+64* 2]
+    pmulhrsw            m21, m23, [cq+64*30]
+    pmulhrsw            m18, m23, [cq+64*18]
+    pmulhrsw            m17, m23, [cq+64*14]
+    pmulhrsw            m16, m23, [cq+64*10]
+    pmulhrsw            m19, m23, [cq+64*22]
+    pmulhrsw            m20, m23, [cq+64*26]
+    pmulhrsw            m15, m23, [cq+64* 6]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 2], m15
+    mova         [cq+64* 4], m16
+    mova         [cq+64* 6], m17
+    mova         [cq+64* 8], m18
+    mova         [cq+64*10], m19
+    mova         [cq+64*12], m20
+    mova         [cq+64*14], m21
+    pmulhrsw            m22, m23, [cq+64* 1]
+    pmulhrsw            m21, m23, [cq+64*31]
+    pmulhrsw            m14, m23, [cq+64*17]
+    pmulhrsw            m29, m23, [cq+64*15]
+    pmulhrsw            m26, m23, [cq+64* 9]
+    pmulhrsw            m17, m23, [cq+64*23]
+    pmulhrsw            m18, m23, [cq+64*25]
+    pmulhrsw            m25, m23, [cq+64* 7]
+    pmulhrsw            m24, m23, [cq+64* 5]
+    pmulhrsw            m19, m23, [cq+64*27]
+    pmulhrsw            m16, m23, [cq+64*21]
+    pmulhrsw            m27, m23, [cq+64*11]
+    pmulhrsw            m28, m23, [cq+64*13]
+    pmulhrsw            m15, m23, [cq+64*19]
+    pmulhrsw            m20, m23, [cq+64*29]
+    pmulhrsw            m23,      [cq+64* 3]
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf
+    vpbroadcastd        m12, [o(pw_16384)]
+    psubsw              m13, m0, m29 ; 31
+    paddsw               m0, m29     ;  0
+    psubsw              m29, m1, m28 ; 30
+    paddsw               m1, m28     ;  1
+    psubsw              m28, m2, m27 ; 29
+    paddsw               m2, m27     ;  2
+    psubsw              m27, m3, m26 ; 28
+    paddsw               m3, m26     ;  3
+    psubsw              m26, m4, m25 ; 27
+    paddsw               m4, m25     ;  4
+    psubsw              m25, m5, m24 ; 26
+    paddsw               m5, m24     ;  5
+    psubsw              m24, m6, m23 ; 25
+    paddsw               m6, m23     ;  6
+    psubsw              m23, m7, m22 ; 24
+    paddsw               m7, m22     ;  7
+    pxor                 m9, m9
+    punpckhwd            m8, m0, m1 ; a4 b4 a5 b5 a6 b6 a7 b7
+    punpcklwd            m0, m1     ; a0 b0 a1 b1 a2 b2 a3 b3
+    punpckhwd            m1, m2, m3 ; c4 d4 c5 d5 c6 d6 c7 d7
+    punpcklwd            m2, m3     ; c0 d0 c1 d1 c2 d2 c3 d3
+    REPX {mova [cq+64*x], m9}, 16, 17, 18, 19
+    punpckhwd           m22, m4, m5 ; e4 f4 e5 f5 e6 f6 e7 f7
+    punpcklwd            m4, m5     ; e0 f0 e1 f1 e2 f2 e3 f3
+    punpckhwd            m5, m6, m7 ; g4 h4 g5 h5 g6 h6 g7 h7
+    punpcklwd            m6, m7     ; g0 h0 g1 h1 g2 h2 g3 h3
+    REPX {mova [cq+64*x], m9}, 20, 21, 22, 23
+    punpckhwd            m3, m23, m24
+    punpcklwd           m23, m24
+    punpckhwd           m24, m25, m26
+    punpcklwd           m25, m26
+    REPX {mova [cq+64*x], m9}, 24, 25, 26, 27
+    punpckhwd           m26, m27, m28
+    punpcklwd           m27, m28
+    punpckhwd           m28, m29, m13
+    punpcklwd           m29, m13
+    REPX {mova [cq+64*x], m9}, 28, 29, 30, 31
+    punpckhdq            m7, m0, m2  ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpckldq            m0, m2      ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckhdq            m2, m4, m6  ; e2 f2 g2 h2 e3 f3 g3 h3
+    punpckldq            m4, m6      ; e0 f0 g0 h0 e1 f1 g1 h1
+    REPX  {pmulhrsw x, m12}, m7, m0, m2, m4
+    punpckhdq            m6, m8, m1  ; a6 b6 c6 d6 a7 b7 c7 d7
+    punpckldq            m8, m1      ; a4 b4 c4 d4 a5 b5 c5 d5
+    punpckhdq            m1, m22, m5 ; e6 f6 g6 h6 e7 f7 g7 h7
+    punpckldq           m22, m5      ; e4 f4 g4 h5 e5 f5 g5 h5
+    REPX  {pmulhrsw x, m12}, m6, m8, m1, m22
+    punpckhdq           m13, m23, m25
+    punpckldq           m23, m25
+    punpckhdq           m25, m27, m29
+    punpckldq           m27, m29
+    REPX  {pmulhrsw x, m12}, m13, m23, m25, m27
+    punpckhdq            m9, m3, m24
+    punpckldq            m3, m24
+    punpckhdq           m24, m26, m28
+    punpckldq           m26, m28
+    REPX  {pmulhrsw x, m12}, m9, m3, m24, m26
+    punpckhqdq           m5, m23, m27 ; d01 d09 d17 d25
+    punpcklqdq          m23, m27      ; d00 d08 d16 d24
+    punpcklqdq          m27, m13, m25 ; d02 d10 d18 d26
+    punpckhqdq          m13, m25      ; d03 d11 d19 d27
+    punpcklqdq          m25, m3, m26  ; d04 d12 d20 d28
+    punpckhqdq           m3, m26      ; d05 d13 d21 d29
+    punpcklqdq          m26, m9, m24  ; d06 d14 d22 d30
+    punpckhqdq           m9, m24      ; d07 d15 d23 d31
+    mova         [cq+64* 3], m23
+    mova         [cq+64*13], m27
+    mova         [cq+64* 7], m25
+    mova         [cq+64*15], m26
+    punpckhqdq          m24, m8, m22  ; a05 a13 a21 a29
+    punpcklqdq           m8, m22      ; a04 a12 a20 a28
+    punpckhqdq          m22, m0, m4   ; a01 a09 a17 a25
+    punpcklqdq           m0, m4       ; a00 a08 a16 a24
+    punpckhqdq          m23, m7, m2   ; a03 a11 a19 a27
+    punpcklqdq           m7, m2       ; a02 a10 a18 a26
+    punpckhqdq          m25, m6, m1   ; a07 a15 a23 a31
+    punpcklqdq           m6, m1       ; a06 a14 a22 a30
+    mova         [cq+64* 1], m0
+    mova         [cq+64* 9], m7
+    mova         [cq+64* 5], m8
+    mova         [cq+64*11], m6
+    mova                 m2, [cq+64* 0]
+    mova                m11, [cq+64* 2]
+    mova                 m8, [cq+64* 4]
+    mova                m29, [cq+64* 6]
+    mova                m27, [cq+64* 8]
+    mova                m26, [cq+64*10]
+    mova                 m4, [cq+64*12]
+    mova                m28, [cq+64*14]
+    psubsw               m1, m2, m21  ; 23
+    paddsw               m2, m21      ;  8
+    psubsw              m21, m11, m20 ; 22
+    paddsw              m11, m20      ;  9
+    psubsw              m20, m8, m19  ; 21
+    paddsw               m8, m19      ; 10
+    psubsw              m19, m29, m18 ; 20
+    paddsw              m29, m18      ; 11
+    psubsw              m18, m27, m17 ; 19
+    paddsw              m27, m17      ; 12
+    psubsw              m17, m26, m16 ; 18
+    paddsw              m26, m16      ; 13
+    psubsw              m16, m4, m15  ; 17
+    paddsw               m4, m15      ; 14
+    psubsw              m15, m28, m14 ; 16
+    paddsw              m28, m14      ; 15
+    punpcklwd           m14, m15, m16
+    punpckhwd           m15, m16
+    punpckhwd           m16, m17, m18
+    punpcklwd           m17, m18
+    punpckhwd           m18, m19, m20
+    punpcklwd           m19, m20
+    punpckhwd           m20, m21, m1
+    punpcklwd           m21, m1
+    punpckhwd            m1, m2, m11  ; i4 j4 i5 j5 i6 j6 i7 j7
+    punpcklwd            m2, m11      ; i0 j1 i1 j1 i2 j2 i3 j3
+    punpckhwd           m11, m8, m29  ; k4 l4 k5 l5 k6 l6 k7 l7
+    punpcklwd            m8, m29      ; k0 l0 k1 l1 k2 l2 k3 l3
+    punpckhwd           m29, m27, m26 ; m4 n4 m5 n5 m6 n6 m7 n7
+    punpcklwd           m27, m26      ; m0 n0 m1 n1 m2 n2 m3 n3
+    punpckhwd           m26, m4, m28  ; o4 p4 o5 p5 o6 p6 o7 p7
+    punpcklwd            m4, m28      ; o0 p0 o1 p1 o2 p2 o3 p3
+    punpckhdq           m28, m2, m8   ; i2 j2 k2 l2 i3 j3 k3 l3
+    punpckldq            m2, m8       ; i0 j0 k0 l0 i1 j1 k1 l1
+    punpckhdq            m8, m27, m4  ; m2 n2 o2 p2 m3 n3 o3 p3
+    punpckldq           m27, m4       ; m0 n0 o0 p0 m1 n1 o1 p1
+    REPX  {pmulhrsw x, m12}, m28, m2, m8, m27
+    punpckhdq            m4, m1, m11  ; i6 j6 k6 l6 i7 j7 k7 l7
+    punpckldq            m1, m11      ; i4 j4 k4 l4 i5 j5 k5 l5
+    punpckhdq           m11, m29, m26 ; m6 n6 o6 p6 m7 n7 o7 p7
+    punpckldq           m29, m26      ; m4 n4 o4 p4 m5 n5 o5 p5
+    REPX  {pmulhrsw x, m12}, m4, m1, m11, m29
+    punpckhdq           m26, m19, m21
+    punpckldq           m19, m21
+    punpckhdq           m21, m15, m16
+    punpckldq           m15, m16
+    REPX  {pmulhrsw x, m12}, m26, m19, m21, m15
+    punpckhdq           m16, m18, m20
+    punpckldq           m18, m20
+    punpckhdq           m20, m14, m17
+    punpckldq           m14, m17
+    REPX  {pmulhrsw x, m12}, m16, m18, m20, m14
+    punpckhqdq          m17, m28, m8  ; b03 b11 b19 b27
+    punpcklqdq          m28, m8       ; b02 b10 b18 b26
+    punpckhqdq           m8, m2, m27  ; b01 b09 b17 b25
+    punpcklqdq           m2, m27      ; b00 b08 b16 b24
+    punpcklqdq          m27, m1, m29  ; b04 b12 b20 b28
+    punpckhqdq           m1, m29      ; b05 b13 b21 b29
+    punpcklqdq          m29, m4, m11  ; b06 b14 b22 b30
+    punpckhqdq           m4, m11      ; b07 b15 b23 b31
+    mova         [cq+64* 0], m2
+    mova         [cq+64* 8], m28
+    mova         [cq+64* 4], m27
+    mova         [cq+64*10], m29
+    punpckhqdq          m27, m20, m26 ; c03 c11 c19 c27
+    punpcklqdq          m20, m26      ; c02 c10 c18 c26
+    punpckhqdq          m26, m14, m19 ; c01 c09 c17 c25
+    punpcklqdq          m14, m19      ; c00 c08 c16 c24
+    punpckhqdq          m28, m15, m18 ; c05 c13 c21 c29
+    punpcklqdq          m15, m18      ; c04 c12 c20 c28
+    punpckhqdq          m29, m21, m16 ; c07 c15 c23 c31
+    punpcklqdq          m21, m16      ; c06 c14 c22 c30
+    mova         [cq+64* 2], m14
+    mova         [cq+64*12], m20
+    mova         [cq+64* 6], m15
+    mova         [cq+64*14], m21
+    vshufi32x4          m14, m22, m8, q3232  ; a17 a25 b17 b25
+    vinserti32x8        m22, ym8, 1          ; a01 a09 b01 b09
+    vshufi32x4          m15, m23, m17, q3232 ; a19 a27 b19 b27
+    vinserti32x8        m23, ym17, 1         ; a03 a11 b03 b11
+    vshufi32x4          m16, m24, m1, q3232  ; a21 a29 b21 b29
+    vinserti32x8        m24, ym1, 1          ; a05 a13 b05 b13
+    vshufi32x4          m17, m25, m4, q3232  ; a23 a31 b23 b31
+    vinserti32x8        m25, ym4, 1          ; a07 a15 b07 b15
+    vinserti32x8        m19, m26, ym5, 1     ; c01 c09 d01 d09
+    vshufi32x4          m26, m5, q3232       ; c17 c25 d17 d25
+    vinserti32x8        m20, m27, ym13, 1    ; c03 c11 d03 d11
+    vshufi32x4          m27, m13, q3232      ; c19 c27 d19 d27
+    vinserti32x8        m21, m28, ym3, 1     ; c05 c13 d05 d13
+    vshufi32x4          m28, m3, q3232       ; c21 c29 d21 d29
+    vinserti32x8        m18, m29, ym9, 1     ; c07 c15 d07 d15
+    vshufi32x4          m29, m9, q3232       ; c23 c31 d23 d31
+    mov                  r4, rsp
+    vshufi32x4           m0, m22, m19, q2020 ;  1
+    vshufi32x4           m1, m17, m29, q3131 ; 31
+    vshufi32x4           m2, m14, m26, q2020 ; 17
+    vshufi32x4           m3, m25, m18, q3131 ; 15
+    call .main_part1
+    vshufi32x4           m0, m25, m18, q2020 ;  7
+    vshufi32x4           m1, m14, m26, q3131 ; 25
+    vshufi32x4           m2, m17, m29, q2020 ; 23
+    vshufi32x4           m3, m22, m19, q3131 ;  9
+    call .main_part1
+    vshufi32x4           m0, m24, m21, q2020 ;  5
+    vshufi32x4           m1, m15, m27, q3131 ; 27
+    vshufi32x4           m2, m16, m28, q2020 ; 21
+    vshufi32x4           m3, m23, m20, q3131 ; 11
+    call .main_part1
+    vshufi32x4           m0, m23, m20, q2020 ;  3
+    vshufi32x4           m1, m16, m28, q3131 ; 29
+    vshufi32x4           m2, m15, m27, q2020 ; 19
+    vshufi32x4           m3, m24, m21, q3131 ; 13
+    call .main_part1
+    call .main_part2
+    mova                 m0, [cq+64* 1] ; a0
+    mova                m15, [cq+64* 0] ; b0
+    mova                 m3, [cq+64* 2] ; c0
+    mova                m16, [cq+64* 3] ; d0
+    mova                m14, [cq+64* 5] ; a4
+    mova                 m8, [cq+64* 4] ; b4
+    mova                m17, [cq+64* 6] ; c4
+    mova                 m1, [cq+64* 7] ; d4
+    vshufi32x4           m2, m0, m15, q3232  ; a16 a24 b16 b24
+    vinserti32x8         m0, ym15, 1         ; a00 a08 b00 b08
+    vshufi32x4          m15, m3, m16, q3232  ; c16 c24 d16 d24
+    vinserti32x8         m3, ym16, 1         ; c00 c08 d00 d08
+    vshufi32x4          m16, m14, m8, q3232  ; a20 a28 b20 b28
+    vinserti32x8        m14, ym8, 1          ; a04 a12 b04 b12
+    vshufi32x4           m8, m17, m1, q3232  ; c20 c28 d20 d28
+    vinserti32x8        m17, ym1, 1          ; c04 c12 d04 d12
+    vshufi32x4           m1, m0, m3, q3131   ;  8
+    vshufi32x4           m0, m3, q2020       ;  0
+    vshufi32x4           m3, m2, m15, q3131  ; 24
+    vshufi32x4           m2, m15, q2020      ; 16
+    vshufi32x4          m15, m14, m17, q3131 ; 12
+    vshufi32x4          m14, m17, q2020      ;  4
+    vshufi32x4          m17, m16, m8, q3131  ; 28
+    vshufi32x4          m16, m8, q2020       ; 20
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+    mova                 m8, [cq+64* 8]
+    mova                 m9, [cq+64*12]
+    mova                m11, [cq+64*10]
+    mova                m12, [cq+64*14]
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 2], m15
+    mova         [cq+64* 4], m16
+    mova         [cq+64* 6], m17
+    mova         [cq+64* 8], m18
+    mova         [cq+64*10], m19
+    mova         [cq+64*12], m20
+    mova         [cq+64*14], m21
+    mova                m22, [cq+64* 9]
+    mova                m27, [cq+64*13]
+    mova                m23, [cq+64*11]
+    mova                m24, [cq+64*15]
+    vshufi32x4          m26, m22, m8, q3232  ; a18 a26 b18 b26
+    vinserti32x8        m22, ym8, 1          ; a02 a10 b02 b10
+    vshufi32x4           m8, m9, m27, q3232  ; c18 c26 d18 d26
+    vinserti32x8         m9, ym27, 1         ; c02 c10 d02 d10
+    vshufi32x4          m27, m23, m11, q3232 ; a22 a30 b22 b30
+    vinserti32x8        m23, ym11, 1         ; a06 a14 b06 b14
+    vshufi32x4          m11, m12, m24, q3232 ; c22 c30 d22 d30
+    vinserti32x8        m12, ym24, 1         ; c06 c14 d06 d14
+    vshufi32x4          m28, m26, m8, q3131  ; 26
+    vshufi32x4          m26, m8, q2020       ; 18
+    vshufi32x4          m24, m22, m9, q3131  ; 10
+    vshufi32x4          m22, m9, q2020       ;  2
+    vshufi32x4          m29, m27, m11, q3131 ; 30
+    vshufi32x4          m27, m11, q2020      ; 22
+    vshufi32x4          m25, m23, m12, q3131 ; 14
+    vshufi32x4          m23, m12, q2020      ;  6
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast
+    jmp .end
+.fast: ; bottom/right halves are zero
+    pmulhrsw            ym9, ym23, [cq+64* 0]
+    pmulhrsw            ym6, ym23, [cq+64* 8]
+    mova                m14, [o(dup16_perm)]
+    pmulhrsw            ym8, ym23, [cq+64* 2]
+    pmulhrsw            xm0, xm23, [cq+64*14]
+    pmulhrsw            xm5, xm23, [cq+64*10]
+    pmulhrsw            ym1, ym23, [cq+64* 6]
+    pmulhrsw            ym7, ym23, [cq+64* 4]
+    pmulhrsw            xm3, xm23, [cq+64*12]
+    pmovzxwd             m9, ym9
+    pmovzxwd             m6, ym6
+    vpermb               m8, m14, m8
+    punpcklwd           xm0, xm0
+    vpermb              ym5, ym14, ym5
+    vpermb               m1, m14, m1
+    vpermb               m7, m14, m7
+    punpcklwd           xm3, xm3
+    pslld                m9, 16
+    pslld                m6, 16
+    call m(idct_16x16_internal_8bpc).main_fast
+          vpmulhrsw    ym21, ym23, [cq+64* 1]
+    {evex}vpmulhrsw    xm17, xm23, [cq+64*15] ; force EVEX encoding, which
+    {evex}vpmulhrsw    xm20, xm23, [cq+64* 9] ; reduces code size due to
+    {evex}vpmulhrsw    ym15, ym23, [cq+64* 7] ; compressed displacements
+    {evex}vpmulhrsw    ym18, ym23, [cq+64* 5]
+    {evex}vpmulhrsw    xm16, xm23, [cq+64*11]
+    {evex}vpmulhrsw    xm19, xm23, [cq+64*13]
+    {evex}vpmulhrsw    ym23,       [cq+64* 3]
+    vpermb              m21, m14, m21
+    punpcklwd          xm17, xm17
+    vpermb             ym20, ym14, ym20
+    vpermb              m15, m14, m15
+    vpermb              m18, m14, m18
+    vpermb             ym16, ym14, ym16
+    punpcklwd          xm19, xm19
+    vpermb              m14, m14, m23
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast
+    vpbroadcastd         m9, [o(pw_16384)]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).transpose_round
+    vshufi32x4          m16, m0, m3, q2020  ;  0
+    vshufi32x4          m26, m0, m3, q3131  ;  4
+    vshufi32x4           m0, m14, m2, q2020 ;  1
+    vshufi32x4          m14, m2, q3131      ;  5
+    vshufi32x4           m3, m19, m7, q3131 ; 15
+    vshufi32x4          m19, m7, q2020      ; 11
+    vshufi32x4          m27, m17, m9, q2020 ;  3
+    vshufi32x4          m17, m9, q3131      ;  7
+    vshufi32x4          m28, m20, m6, q2020 ;  9
+    vshufi32x4          m20, m6, q3131      ; 13
+    vshufi32x4          m22, m1, m18, q2020 ;  2
+    vshufi32x4          m23, m1, m18, q3131 ;  6
+    vshufi32x4          m24, m5, m15, q2020 ; 10
+    vshufi32x4          m25, m5, m15, q3131 ; 14
+    vshufi32x4          m15, m21, m4, q3131 ; 12
+    vshufi32x4          m21, m21, m4, q2020 ;  8
+    mov                  r4, rsp
+    call .main_part1_fast
+    mova                 m0, m17
+    mova                 m3, m28
+    call .main_part1_fast
+    mova                 m0, m14
+    mova                 m3, m19
+    call .main_part1_fast
+    mova                 m0, m27
+    mova                 m3, m20
+    call .main_part1_fast
+    call .main_part2
+    mova                 m0, m16
+    mova                 m1, m21
+    mova                m14, m26
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast2
+    mova         [cq+64*14], m21
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 6], m17
+    mova         [cq+64* 8], m18
+    mova         [cq+64*10], m19
+    mova         [cq+64* 4], m16
+    mova         [cq+64* 2], m15
+    mova         [cq+64*12], m20
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast2
+.end:
+    lea                  r4, [strideq*3]
+    vpbroadcastd        m12, [o(pw_2048)]
+    movshdup            m13, [o(permD)]
+    lea                  r5, [r4+strideq]   ; stride*4
+    lea                  r3, [dstq+r4*8]
+    lea                  r6, [strideq+r5*8] ; stride*33
+    lea                  r8, [r4+r5*8]      ; stride*35
+    add                  r3, r5             ; dst+stride*28
+    lea                  r7, [r6+strideq]   ; stride*34
+%macro IDCT_32x64_END 6 ; src, mem, stride[1-4]
+%if %2 < 8
+    paddsw              m10, m%2, m%1
+    psubsw              m11, m%2, m%1
+%else
+    mova                m11, [cq+64*(%2*2-16)]
+    paddsw              m10, m11, m%1
+    psubsw              m11, m%1
+%endif
+    mova                 m9, [rsp+64*(31-%2)]
+    mova                m%1, [rsp+64*%2]
+    paddsw               m8, m10, m9
+    psubsw              m10, m9
+    paddsw               m9, m11, m%1
+    pmovzxbw             m0, [dstq+%3]
+    psubsw              m11, m%1
+    pmovzxbw            m%1, [r3  +%4]
+    REPX  {pmulhrsw x, m12}, m8, m10, m9, m11
+    paddw                m8, m0
+    pmovzxbw             m0, [r3  +%5]
+    paddw               m10, m%1
+    pmovzxbw            m%1, [dstq+%6]
+    paddw                m9, m0
+    paddw               m11, m%1
+%if %2 >= 8
+%if %2 == 8
+    pxor                 m1, m1
+%endif
+    mova  [cq+64*(%2*2-16)], m1
+    mova  [cq+64*(%2*2-15)], m1
+%endif
+    packuswb             m8, m10
+    packuswb             m9, m11
+    vpermq               m8, m13, m8
+    vpermq               m9, m13, m9
+    mova          [dstq+%3], ym8
+    vextracti32x8 [r3  +%4], m8, 1
+    mova          [r3  +%5], ym9
+    vextracti32x8 [dstq+%6], m9, 1
+%if %2 == 3 || %2 == 7 || %2 == 11
+    add                dstq, r5
+    sub                  r3, r5
+%endif
+%endmacro
+    IDCT_32x64_END       29,  0, strideq*0, r8,   r4       , r5*8
+    IDCT_32x64_END       28,  1, strideq*1, r7,   strideq*2, r6
+    IDCT_32x64_END       27,  2, strideq*2, r6,   strideq*1, r7
+    IDCT_32x64_END       26,  3, r4       , r5*8, strideq*0, r8
+    IDCT_32x64_END       25,  4, strideq*0, r8,   r4       , r5*8
+    IDCT_32x64_END       24,  5, strideq*1, r7,   strideq*2, r6
+    IDCT_32x64_END       23,  6, strideq*2, r6,   strideq*1, r7
+    IDCT_32x64_END       22,  7, r4       , r5*8, strideq*0, r8
+    IDCT_32x64_END       21,  8, strideq*0, r8,   r4       , r5*8
+    IDCT_32x64_END       20,  9, strideq*1, r7,   strideq*2, r6
+    IDCT_32x64_END       19, 10, strideq*2, r6,   strideq*1, r7
+    IDCT_32x64_END       18, 11, r4       , r5*8, strideq*0, r8
+    IDCT_32x64_END       17, 12, strideq*0, r8,   r4       , r5*8
+    IDCT_32x64_END       16, 13, strideq*1, r7,   strideq*2, r6
+    IDCT_32x64_END       15, 14, strideq*2, r6,   strideq*1, r7
+    IDCT_32x64_END       14, 15, r4       , r5*8, strideq*0, r8
+    RET
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 64
+    imul                r6d, 181
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 128+256
+    sar                 r6d, 8+1
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).dconly3
+ALIGN function_align ; bottom three-quarters are zero
+cglobal_label .main_part1_fast2
+    vpbroadcastd         m7, [o(idct64_mul+4*0)]
+    vpbroadcastd         m8, [o(idct64_mul+4*1)]
+    pmulhrsw             m7, m0     ; t63a
+    pmulhrsw             m0, m8     ; t32a
+
+    punpcklwd            m4, m0, m7
+    punpckhwd            m6, m0, m7
+    mova                 m1, m10
+    vpdpwssd             m1, m4, [o(idct64_mul+4*9)] {bcstd}
+    mova                 m9, m10
+    vpdpwssd             m9, m6, [o(idct64_mul+4*9)] {bcstd}
+    REPX      {psrad x, 12}, m1, m9
+    packssdw             m1, m9
+    mova                 m9, m10
+    vpdpwssd             m9, m6, [o(idct64_mul+4*8)] {bcstd}
+    mova                 m6, m10
+    vpdpwssd             m6, m4, [o(idct64_mul+4*8)] {bcstd}
+    REPX      {psrad x, 12}, m9, m6
+    packssdw             m6, m9
+
+    mova                 m4, m0
+    mova                 m3, m7
+    mova                 m5, m1
+    mova                 m2, m6
+    jmp .main_part1c
+cglobal_label .main_part1_fast
+    vpbroadcastd         m1, [o(idct64_mul+4*0)]
+    vpbroadcastd         m8, [o(idct64_mul+4*1)]
+    vpbroadcastd         m2, [o(idct64_mul+4*6)]
+    vpbroadcastd         m9, [o(idct64_mul+4*7)]
+    pmulhrsw             m1, m0     ; t63a
+    pmulhrsw             m0, m8     ; t32a
+    pmulhrsw             m2, m3     ; t60a
+    pmulhrsw             m3, m9     ; t35a
+    mova                 m8, m0
+    mova                 m7, m1
+    mova                 m6, m3
+    mova                 m5, m2
+    jmp .main_part1b
+cglobal_label .main_part1
+    ; idct64 steps 1-5:
+    ; in1/31/17/15 -> t32a/33/34a/35/60/61a/62/63a
+    ; in7/25/23/ 9 -> t56a/57/58a/59/36/37a/38/39a
+    ; in5/27/21/11 -> t40a/41/42a/43/52/53a/54/55a
+    ; in3/29/19/13 -> t48a/49/50a/51/44/45a/46/47a
+    vpbroadcastd         m7, [o(idct64_mul+4*0)]
+    vpbroadcastd         m8, [o(idct64_mul+4*1)]
+    vpbroadcastd         m6, [o(idct64_mul+4*2)]
+    vpbroadcastd         m9, [o(idct64_mul+4*3)]
+    pmulhrsw             m7, m0     ; t63a
+    vpbroadcastd         m5, [o(idct64_mul+4*4)]
+    pmulhrsw             m0, m8     ; t32a
+    vpbroadcastd         m8, [o(idct64_mul+4*5)]
+    pmulhrsw             m6, m1     ; t62a
+    vpbroadcastd         m4, [o(idct64_mul+4*6)]
+    pmulhrsw             m1, m9     ; t33a
+    vpbroadcastd         m9, [o(idct64_mul+4*7)]
+    pmulhrsw             m5, m2     ; t61a
+    pmulhrsw             m2, m8     ; t34a
+    pmulhrsw             m4, m3     ; t60a
+    pmulhrsw             m3, m9     ; t35a
+    psubsw               m8, m0, m1 ; t33
+    paddsw               m0, m1     ; t32
+    psubsw               m1, m7, m6 ; t62
+    paddsw               m7, m6     ; t63
+    psubsw               m6, m3, m2 ; t34
+    paddsw               m3, m2     ; t35
+    psubsw               m2, m4, m5 ; t61
+    paddsw               m5, m4     ; t60
+.main_part1b:
+    vpbroadcastd        m11, [o(idct64_mul+4*8)]
+    vpbroadcastd        m12, [o(idct64_mul+4*9)]
+    ITX_MULSUB_2W         1, 8, 4, 9, 10, 11, 12 ; t33a, t62a
+    vpbroadcastd        m11, [o(idct64_mul+4*10)]
+    ITX_MULSUB_2W         2, 6, 4, 9, 10, 12, 11 ; t34a, t61a
+    psubsw               m4, m0, m3 ; t35a
+    paddsw               m0, m3     ; t32a
+    psubsw               m3, m7, m5 ; t60a
+    paddsw               m7, m5     ; t63a
+    psubsw               m5, m1, m2 ; t34
+    paddsw               m1, m2     ; t33
+    psubsw               m2, m8, m6 ; t61
+    paddsw               m6, m8     ; t62
+.main_part1c:
+    vpbroadcastd        m11, [o(idct64_mul+4*11)]
+    vpbroadcastd        m12, [o(idct64_mul+4*12)]
+    add                  r5, 4*13
+    ITX_MULSUB_2W         3, 4, 8, 9, 10, 11, 12 ; t35,  t60
+    ITX_MULSUB_2W         2, 5, 8, 9, 10, 11, 12 ; t34a, t61a
+    mova          [r4+64*0], m0
+    mova          [r4+64*7], m7
+    mova          [r4+64*1], m1
+    mova          [r4+64*6], m6
+    mova          [r4+64*3], m3
+    mova          [r4+64*4], m4
+    mova          [r4+64*2], m2
+    mova          [r4+64*5], m5
+    add                  r4, 64*8
+    ret
+cglobal_label .main_part2
+    vpbroadcastd        m11, [o(pw_1567_3784  -16*13)]
+    vpbroadcastd        m12, [o(pw_m3784_1567 -16*13)]
+    lea                  r6, [r4+64*7]
+    vpbroadcastd        m17, [o(pw_m1567_m3784-16*13)]
+    vpbroadcastd        m18, [o(pw_2896_2896  -16*13)]
+    vpbroadcastd        m19, [o(pw_m2896_2896 -16*13)]
+    sub                  r5, 16*13
+.main_part2_loop:
+    mova                 m0, [r4-64*32] ; t32a
+    mova                 m1, [r6-64*24] ; t39a
+    mova                 m2, [r6-64*32] ; t63a
+    mova                 m3, [r4-64*24] ; t56a
+    mova                 m4, [r4-64*16] ; t40a
+    mova                 m5, [r6-64* 8] ; t47a
+    mova                 m6, [r6-64*16] ; t55a
+    mova                 m7, [r4-64* 8] ; t48a
+    psubsw               m8, m0, m1 ; t39
+    paddsw               m0, m1     ; t32
+    psubsw               m1, m2, m3 ; t56
+    paddsw               m2, m3     ; t63
+    psubsw               m3, m5, m4 ; t40
+    paddsw               m5, m4     ; t47
+    psubsw               m4, m7, m6 ; t55
+    paddsw               m7, m6     ; t48
+    ITX_MULSUB_2W         1, 8, 6, 9, 10, 11, 12 ; t39a, t56a
+    ITX_MULSUB_2W         4, 3, 6, 9, 10, 12, 17 ; t40a, t55a
+    psubsw               m6, m2, m7 ; t48a
+    paddsw               m2, m7     ; t63a
+    psubsw               m7, m0, m5 ; t47a
+    paddsw               m0, m5     ; t32a
+    psubsw               m5, m8, m3 ; t55
+    paddsw               m8, m3     ; t56
+    psubsw               m3, m1, m4 ; t40
+    paddsw               m1, m4     ; t39
+    ITX_MULSUB_2W         6, 7, 4, 9, 10, 18, 19 ; t47,  t48
+    ITX_MULSUB_2W         5, 3, 4, 9, 10, 18, 19 ; t40a, t55a
+    mova         [r6-64* 8], m2
+    mova         [r4-64*32], m0
+    mova         [r4-64* 8], m8
+    mova         [r6-64*32], m1
+    mova         [r6-64*24], m6
+    mova         [r4-64*16], m7
+    mova         [r4-64*24], m5
+    mova         [r6-64*16], m3
+    add                  r4, 64
+    sub                  r6, 64
+    cmp                  r4, r6
+    jb .main_part2_loop
+    ret
+
+cglobal inv_txfm_add_dct_dct_64x32_8bpc, 4, 7, 0, dst, stride, c, eob
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 7, 30, 64*32, dst, stride, c, eob
+    vpbroadcastd        m23, [o(pw_2896x8)]
+%undef cmp
+    cmp                eobd, 136
+    jb .fast
+    pmulhrsw             m0, m23, [cq+64* 1]
+    pmulhrsw             m1, m23, [cq+64*31]
+    pmulhrsw             m2, m23, [cq+64*17]
+    pmulhrsw             m3, m23, [cq+64*15]
+    vpbroadcastd        m10, [o(pd_2048)]
+    mov                  r4, rsp
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    pmulhrsw             m0, m23, [cq+64* 7]
+    pmulhrsw             m1, m23, [cq+64*25]
+    pmulhrsw             m2, m23, [cq+64*23]
+    pmulhrsw             m3, m23, [cq+64* 9]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    pmulhrsw             m0, m23, [cq+64* 5]
+    pmulhrsw             m1, m23, [cq+64*27]
+    pmulhrsw             m2, m23, [cq+64*21]
+    pmulhrsw             m3, m23, [cq+64*11]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    pmulhrsw             m0, m23, [cq+64* 3]
+    pmulhrsw             m1, m23, [cq+64*29]
+    pmulhrsw             m2, m23, [cq+64*19]
+    pmulhrsw             m3, m23, [cq+64*13]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part2
+    pmulhrsw             m3, m23, [cq+64*24]
+    pmulhrsw             m1, m23, [cq+64* 8]
+    pmulhrsw             m2, m23, [cq+64*16]
+    pmulhrsw             m0, m23, [cq+64* 0]
+    pmulhrsw            m14, m23, [cq+64* 4]
+    pmulhrsw            m17, m23, [cq+64*28]
+    pmulhrsw            m16, m23, [cq+64*20]
+    pmulhrsw            m15, m23, [cq+64*12]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+    pmulhrsw            m22, m23, [cq+64* 2]
+    pmulhrsw            m29, m23, [cq+64*30]
+    pmulhrsw            m26, m23, [cq+64*18]
+    pmulhrsw            m25, m23, [cq+64*14]
+    pmulhrsw            m24, m23, [cq+64*10]
+    pmulhrsw            m27, m23, [cq+64*22]
+    pmulhrsw            m28, m23, [cq+64*26]
+    pmulhrsw            m23,      [cq+64* 6]
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 1], m15
+    mova         [cq+64* 2], m16
+    mova         [cq+64* 3], m17
+    mova         [cq+64* 4], m18
+    mova         [cq+64* 5], m19
+    mova         [cq+64* 6], m20
+    mova         [cq+64* 7], m21
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast
+    vpbroadcastd        m13, [o(pw_16384)]
+    call .pass1_end_part1
+    mova         [cq+64*16], m1
+    mova         [cq+64*17], m3
+    mova         [cq+64*18], m5
+    mova         [cq+64*19], m7
+    mova         [cq+64*24], m23
+    mova         [cq+64*25], m25
+    mova         [cq+64*26], m27
+    mova         [cq+64*27], m29
+    pmulhrsw            m23, m13, m0 ; a0
+    pmulhrsw            m25, m13, m2 ; a2
+    pmulhrsw            m27, m13, m4 ; a4
+    pmulhrsw            m29, m13, m6 ; a6
+    REPX {pmulhrsw x, m13}, m22, m24, m26, m28 ; e0 e2 e4 e6
+    call .pass1_end_part2
+    mova         [cq+64*20], m15
+    mova         [cq+64*21], m17
+    mova         [cq+64*22], m19
+    mova         [cq+64*23], m21
+    mova         [cq+64*28], m1
+    mova         [cq+64*29], m3
+    mova         [cq+64*30], m5
+    mova         [cq+64*31], m7
+    REPX {pmulhrsw x, m13}, m14, m16, m18, m20 ; c0 c2 c4 c6
+    REPX {pmulhrsw x, m13}, m0, m2, m4, m6     ; g0 g2 g4 g6
+    vinserti32x8        m3, m23, ym14, 1 ; a00 a01 c00 c01
+    vshufi32x4         m23, m14, q3232   ; a02 a03 c02 c03
+    vinserti32x8       m15, m22, ym0, 1  ; e00 e01 g00 g01
+    vshufi32x4         m22, m0, q3232    ; e02 e03 g02 g03
+    vinserti32x8        m1, m27, ym18, 1 ; a40 a41 c40 c41
+    vshufi32x4         m27, m18, q3232   ; a42 a43 c42 c43
+    vinserti32x8       m18, m26, ym4, 1  ; e40 e41 g40 g41
+    vshufi32x4         m26, m4, q3232    ; e42 e43 g42 g43
+    vinserti32x8       m14, m25, ym16, 1 ; a20 a21 c20 c21
+    vshufi32x4         m25, m16, q3232   ; a22 a23 c22 c23
+    vinserti32x8       m17, m24, ym2, 1  ; e20 e21 g20 g21
+    vshufi32x4         m24, m2, q3232    ; e22 e23 g22 g23
+    vinserti32x8       m19, m29, ym20, 1 ; a60 a61 c60 c61
+    vshufi32x4         m29, m20, q3232   ; a62 a63 c62 c63
+    vinserti32x8       m20, m28, ym6, 1  ; e60 e61 g60 g61
+    vshufi32x4         m28, m6, q3232    ; e62 e63 g62 g63
+    vshufi32x4          m2, m3, m15, q3131  ;  8
+    vshufi32x4          m0, m3, m15, q2020  ;  0
+    vshufi32x4          m6, m23, m22, q3131 ; 24
+    vshufi32x4          m4, m23, m22, q2020 ; 16
+    vshufi32x4          m3, m1, m18, q3131  ; 12
+    vshufi32x4          m1, m18, q2020      ;  4
+    vshufi32x4          m7, m27, m26, q3131 ; 28
+    vshufi32x4          m5, m27, m26, q2020 ; 20
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    vshufi32x4         m16, m14, m17, q3131 ; 10
+    vshufi32x4         m14, m17, q2020      ;  2
+    vshufi32x4         m17, m19, m20, q3131 ; 14
+    vshufi32x4         m15, m19, m20, q2020 ;  6
+    vshufi32x4         m20, m25, m24, q3131 ; 26
+    vshufi32x4         m18, m25, m24, q2020 ; 18
+    vshufi32x4         m21, m29, m28, q3131 ; 30
+    vshufi32x4         m19, m29, m28, q2020 ; 22
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    pmulhrsw           m22, m13, [cq+64*16] ; a1
+    pmulhrsw           m23, m13, [cq+64*20] ; c1
+    pmulhrsw           m24, m13, [cq+64*24] ; e1
+    pmulhrsw           m25, m13, [cq+64*28] ; g1
+    pmulhrsw           m26, m13, [cq+64*17] ; a3
+    pmulhrsw           m27, m13, [cq+64*21] ; c3
+    pmulhrsw           m28, m13, [cq+64*25] ; e3
+    pmulhrsw           m29, m13, [cq+64*29] ; g3
+    mova        [cq+64* 8], m14
+    mova        [cq+64* 9], m15
+    mova        [cq+64*10], m16
+    mova        [cq+64*11], m17
+    mova        [cq+64*12], m18
+    mova        [cq+64*13], m19
+    mova        [cq+64*14], m20
+    mova        [cq+64*15], m21
+    pmulhrsw           m14, m13, [cq+64*18] ; a5
+    pmulhrsw           m15, m13, [cq+64*22] ; c5
+    pmulhrsw           m16, m13, [cq+64*26] ; e5
+    pmulhrsw           m17, m13, [cq+64*30] ; g5
+    pmulhrsw           m18, m13, [cq+64*19] ; a7
+    pmulhrsw           m19, m13, [cq+64*23] ; c7
+    pmulhrsw           m20, m13, [cq+64*27] ; e7
+    pmulhrsw           m21, m13, [cq+64*31] ; g7
+    vinserti32x8        m8, m22, ym23, 1 ; a10 a11 c10 c11
+    vshufi32x4         m22, m23, q3232   ; a12 a13 c12 c13
+    vinserti32x8        m9, m24, ym25, 1 ; e10 e11 g10 g11
+    vshufi32x4         m24, m25, q3232   ; e12 e13 g12 g13
+    vinserti32x8       m23, m26, ym27, 1 ; a30 a31 c30 c31
+    vshufi32x4         m26, m27, q3232   ; a32 a33 c32 c33
+    vinserti32x8       m11, m28, ym29, 1 ; e30 e31 g30 g31
+    vshufi32x4         m28, m29, q3232   ; e32 e33 g32 g33
+    mova        [cq+64* 0], m0
+    mova        [cq+64* 1], m1
+    mova        [cq+64* 2], m2
+    mova        [cq+64* 3], m3
+    mova        [cq+64* 4], m4
+    mova        [cq+64* 5], m5
+    mova        [cq+64* 6], m6
+    mova        [cq+64* 7], m7
+    vinserti32x8       m12, m14, ym15, 1 ; a50 a51 c50 c51
+    vshufi32x4         m14, m15, q3232   ; a52 a53 c52 c53
+    vinserti32x8       m13, m16, ym17, 1 ; e50 e51 g50 g51
+    vshufi32x4         m16, m17, q3232   ; e52 e53 g52 g53
+    vinserti32x8       m25, m18, ym19, 1 ; a70 a71 c70 c71
+    vshufi32x4         m18, m19, q3232   ; a72 a73 c72 c73
+    vinserti32x8       m17, m20, ym21, 1 ; e70 e71 g70 g71
+    vshufi32x4         m20, m21, q3232   ; e72 e73 g72 g73
+    vshufi32x4         m27, m23, m11, q3131 ; 11 m27
+    vshufi32x4         m23, m11, q2020      ;  3 m23
+    vshufi32x4         m19, m26, m28, q3131 ; 27 m19
+    vshufi32x4         m15, m26, m28, q2020 ; 19 m15
+    vshufi32x4         m29, m25, m17, q3131 ; 15 m29
+    vshufi32x4         m25, m17, q2020      ;  7 m25
+    vshufi32x4         m21, m18, m20, q3131 ; 31 m21
+    vshufi32x4         m17, m18, m20, q2020 ; 23 m17
+    vshufi32x4         m20, m14, m16, q3131 ; 29 m20
+    vshufi32x4         m16, m14, m16, q2020 ; 21 m16
+    vshufi32x4         m18, m22, m24, q3131 ; 25 m18
+    vshufi32x4         m14, m22, m24, q2020 ; 17 m14
+    vshufi32x4         m26, m8, m9, q3131   ;  9 m26
+    vshufi32x4         m22, m8, m9, q2020   ;  1 m22
+    vshufi32x4         m28, m12, m13, q3131 ; 13 m28
+    vshufi32x4         m24, m12, m13, q2020 ;  5 m24
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf
+    vpbroadcastd       m13, [o(pw_16384)]
+    pmulhrsw            m0, m13, [r4-64*21]
+    pmulhrsw            m1, m13, [r4-64*22]
+    pmulhrsw            m2, m13, [r4-64*23]
+    pmulhrsw            m3, m13, [r4-64*24]
+    pmulhrsw            m4, m13, [r4-64*25]
+    pmulhrsw            m5, m13, [r4-64*26]
+    pmulhrsw            m6, m13, [r4-64*27]
+    pmulhrsw            m7, m13, [r4-64*28]
+    mova        [cq+64*16], m14
+    mova        [cq+64*17], m15
+    mova        [cq+64*18], m16
+    mova        [cq+64*19], m17
+    mova        [cq+64*20], m18
+    mova        [cq+64*21], m19
+    mova        [cq+64*22], m20
+    mova        [cq+64*23], m21
+    pmulhrsw           m14, m13, [r4-64*12]
+    pmulhrsw           m15, m13, [r4-64*11]
+    pmulhrsw           m16, m13, [r4-64*10]
+    pmulhrsw           m17, m13, [r4-64* 9]
+    pmulhrsw           m18, m13, [r4-64* 8]
+    pmulhrsw           m19, m13, [r4-64* 7]
+    pmulhrsw           m20, m13, [r4-64* 6]
+    pmulhrsw           m21, m13, [r4-64* 5]
+    mova        [cq+64*24], m22
+    mova        [cq+64*25], m23
+    mova        [cq+64*26], m24
+    mova        [cq+64*27], m25
+    mova        [cq+64*28], m26
+    mova        [cq+64*29], m27
+    mova        [cq+64*30], m28
+    mova        [cq+64*31], m29
+    call .transpose_2x8x8_lo
+    mova        [r4-64*12], m1
+    mova        [r4-64*11], m3
+    mova        [r4-64*10], m5
+    mova        [r4-64* 9], m7
+    mova        [r4-64* 8], m15
+    mova        [r4-64* 7], m17
+    mova        [r4-64* 6], m19
+    mova        [r4-64* 5], m21
+    vinserti32x8       m22, m0, ym14, 1     ; f00 f01 h00 h01
+    vshufi32x4         m23, m0, m14, q3232  ; f02 f03 h02 h03
+    vinserti32x8       m24, m2, ym16, 1     ; f20 f21 h20 h21
+    vshufi32x4         m25, m2, m16, q3232  ; f22 f23 h22 h23
+    vinserti32x8       m26, m4, ym18, 1     ; f40 f41 h40 h41
+    vshufi32x4         m27, m4, m18, q3232  ; f42 f43 h42 h43
+    vinserti32x8       m28, m6, ym20, 1     ; f60 f61 h60 h61
+    vshufi32x4         m29, m6, m20, q3232  ; f62 f63 h62 h63
+    pmulhrsw            m0, m13, [r4-64*20]
+    pmulhrsw            m1, m13, [r4-64*19]
+    pmulhrsw            m2, m13, [r4-64*18]
+    pmulhrsw            m3, m13, [r4-64*17]
+    pmulhrsw            m4, m13, [r4-64*16]
+    pmulhrsw            m5, m13, [r4-64*15]
+    pmulhrsw            m6, m13, [r4-64*14]
+    pmulhrsw            m7, m13, [r4-64*13]
+    pmulhrsw           m14, m13, [r4-64*29]
+    pmulhrsw           m15, m13, [r4-64*30]
+    pmulhrsw           m16, m13, [r4-64*31]
+    pmulhrsw           m17, m13, [r4-64*32]
+    pmulhrsw           m18, m13, [r4-64*33]
+    pmulhrsw           m19, m13, [r4-64*34]
+    pmulhrsw           m20, m13, [r4-64*35]
+    pmulhrsw           m21, m13, [r4-64*36]
+    call .transpose_2x8x8_lo
+    mova       [r4-64*20], m1
+    mova       [r4-64*19], m3
+    mova       [r4-64*18], m5
+    mova       [r4-64*17], m7
+    mova       [r4-64*16], m15
+    mova       [r4-64*15], m17
+    mova       [r4-64*14], m19
+    mova       [r4-64*13], m21
+    vinserti32x8        m1, m4, ym18, 1     ; b40 b41 d40 d41
+    vshufi32x4          m5, m4, m18, q3232  ; b42 b43 d42 d43
+    vshufi32x4          m4, m0, m14, q3232  ; b02 b03 d02 d03
+    vinserti32x8        m0, ym14, 1         ; b00 b01 d00 d01
+    vinserti32x8       m14, m2, ym16, 1     ; b20 b21 d20 d21
+    vshufi32x4         m18, m2, m16, q3232  ; b22 b23 d22 d23
+    vinserti32x8       m15, m6, ym20, 1     ; b60 b61 d60 d61
+    vshufi32x4         m19, m6, m20, q3232  ; b62 b63 d62 d63
+    vshufi32x4          m2, m0, m22, q3131  ;  8
+    vshufi32x4          m0, m22, q2020      ;  0
+    vshufi32x4          m3, m1, m26, q3131  ; 12
+    vshufi32x4          m1, m26, q2020      ;  4
+    vshufi32x4          m6, m4, m23, q3131  ; 24
+    vshufi32x4          m4, m23, q2020      ; 16
+    vshufi32x4          m7, m5, m27, q3131  ; 28
+    vshufi32x4          m5, m27, q2020      ; 20
+    call m(inv_txfm_add_dct_dct_32x8_8bpc).main
+    vshufi32x4         m16, m14, m24, q3131 ; 10
+    vshufi32x4         m14, m24, q2020      ;  2
+    vshufi32x4         m17, m15, m28, q3131 ; 14
+    vshufi32x4         m15, m28, q2020      ;  6
+    vshufi32x4         m20, m18, m25, q3131 ; 26
+    vshufi32x4         m18, m25, q2020      ; 18
+    vshufi32x4         m21, m19, m29, q3131 ; 30
+    vshufi32x4         m19, m29, q2020      ; 22
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf
+    mova               m22, [r4-64*20]
+    mova               m26, [r4-64*16]
+    mova               m23, [r4-64*19]
+    mova               m27, [r4-64*15]
+    mova               m24, [r4-64*18]
+    mova               m28, [r4-64*14]
+    mova               m25, [r4-64*17]
+    mova               m29, [r4-64*13]
+    mova        [r4-64*20], m14
+    mova        [r4-64*19], m15
+    mova        [r4-64*18], m16
+    mova        [r4-64*17], m17
+    mova        [r4-64*16], m18
+    mova        [r4-64*15], m19
+    mova        [r4-64*14], m20
+    mova        [r4-64*13], m21
+    mova               m19, [r4-64*12]
+    mova               m11, [r4-64* 8]
+    mova               m20, [r4-64*11]
+    mova               m12, [r4-64* 7]
+    mova               m21, [r4-64*10]
+    mova                m8, [r4-64* 6]
+    mova                m9, [r4-64* 9]
+    mova               m18, [r4-64* 5]
+    vshufi32x4         m14, m22, m26, q3232 ; b12 b13 d12 d13
+    vinserti32x8       m22, ym26, 1         ; b10 b11 d10 d11
+    vshufi32x4         m15, m23, m27, q3232 ; b32 b33 d32 d33
+    vinserti32x8       m23, ym27, 1         ; b30 b31 d30 d31
+    vshufi32x4         m16, m24, m28, q3232 ; b52 b53 d52 d53
+    vinserti32x8       m24, ym28, 1         ; b50 b51 d50 d51
+    vshufi32x4         m17, m25, m29, q3232 ; b72 b73 d72 d73
+    vinserti32x8       m25, ym29, 1         ; b70 b71 d70 d71
+    vinserti32x8       m27, m19, ym11, 1    ; f10 f11 h10 h11
+    vshufi32x4         m19, m11, q3232      ; f12 f13 h12 h13
+    vinserti32x8       m28, m20, ym12, 1    ; f30 f31 h30 h31
+    vshufi32x4         m20, m12, q3232      ; f32 f33 h32 h33
+    vinserti32x8       m29, m21, ym8, 1     ; f50 f51 h50 h51
+    vshufi32x4         m21, m8, q3232       ; f52 f53 h52 h53
+    vinserti32x8        m8, m9, ym18, 1     ; f70 f71 h70 h71
+    vshufi32x4          m9, m18, q3232      ; f72 f73 h72 h73
+    vshufi32x4         m26, m22, m27, q3131 ;  9
+    vshufi32x4         m22, m27, q2020      ;  1
+    vshufi32x4         m27, m23, m28, q3131 ; 11
+    vshufi32x4         m23, m28, q2020      ;  3
+    vshufi32x4         m28, m24, m29, q3131 ; 13
+    vshufi32x4         m24, m29, q2020      ;  5
+    vshufi32x4         m29, m25, m8, q3131  ; 15
+    vshufi32x4         m25, m8, q2020       ;  7
+    vshufi32x4         m18, m14, m19, q3131 ; 25
+    vshufi32x4         m14, m19, q2020      ; 17
+    vshufi32x4         m19, m15, m20, q3131 ; 27
+    vshufi32x4         m15, m20, q2020      ; 19
+    vshufi32x4         m20, m16, m21, q3131 ; 29
+    vshufi32x4         m16, m21, q2020      ; 21
+    vshufi32x4         m21, m17, m9, q3131  ; 31
+    vshufi32x4         m17, m9, q2020       ; 23
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf
+    jmp .end
+.fast: ; bottom/right halves are zero
+    {evex}vpmulhrsw     ym8, ym23, [cq+64* 4]
+    {evex}vpmulhrsw     xm1, xm23, [cq+64*12]
+    mova                m28, [o(dup16_perm)]
+    {evex}vpmulhrsw     ym7, ym23, [cq+64* 8]
+          vpmulhrsw    ym22, ym23, [cq+64* 0]
+    vpermb               m8, m28, m8
+    vpermb              ym1, ym28, ym1
+    vpermb               m7, m28, m7
+    pmovzxwd             m9, ym22
+    pslld                m9, 16
+    call m(idct_16x16_internal_8bpc).main_fast2
+    {evex}vpmulhrsw    ym21, ym23, [cq+64* 2]
+    {evex}vpmulhrsw    xm15, xm23, [cq+64*14]
+    {evex}vpmulhrsw    xm18, xm23, [cq+64*10]
+    {evex}vpmulhrsw    ym14, ym23, [cq+64* 6]
+    vpermb              m21, m28, m21
+    punpcklwd          xm15, xm15
+    vpermb             ym18, ym28, ym18
+    vpermb              m14, m28, m14
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast2
+          vpmulhrsw    ym22, ym23, [cq+64* 1]
+    {evex}vpmulhrsw    xm29, xm23, [cq+64*15]
+    {evex}vpmulhrsw    xm26, xm23, [cq+64* 9]
+    {evex}vpmulhrsw    ym25, ym23, [cq+64* 7]
+    {evex}vpmulhrsw    ym24, ym23, [cq+64* 5]
+    {evex}vpmulhrsw    xm27, xm23, [cq+64*11]
+    {evex}vpmulhrsw     xm8, xm23, [cq+64*13]
+    {evex}vpmulhrsw    ym23,       [cq+64* 3]
+    vpermb              m22, m28, m22
+    punpcklwd          xm29, xm29
+    vpermb             ym26, ym28, ym26
+    vpermb              m25, m28, m25
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 1], m15
+    mova         [cq+64* 2], m16
+    mova         [cq+64* 3], m17
+    REPX {vpermb x, m28, x}, m24, m27, m23
+    punpcklwd          xm28, xm8, xm8
+    mova         [cq+64* 4], m18
+    mova         [cq+64* 5], m19
+    mova         [cq+64* 6], m20
+    mova         [cq+64* 7], m21
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_oddhalf_fast
+    mov                  r4, rsp
+    vpbroadcastd        m13, [o(pw_16384)]
+    mova         [r4+64*16], m4
+    mova         [r4+64*17], m5
+    mova         [r4+64*18], m6
+    mova         [r4+64*19], m7
+    mova         [r4+64*28], m26
+    mova         [r4+64*29], m27
+    mova         [r4+64*30], m28
+    mova         [r4+64*31], m29
+    call m(inv_txfm_add_dct_dct_64x16_8bpc).pass1_end
+    mova         [r4+64*20], m22
+    mova         [r4+64*21], m23
+    mova         [r4+64*22], m24
+    mova         [r4+64*23], m25
+    mova         [r4+64*24], m26
+    mova         [r4+64*25], m27
+    mova         [r4+64*26], m28
+    mova         [r4+64*27], m29
+    call .pass2_fast
+    mova         [cq+64* 8], m14
+    mova         [cq+64* 9], m15
+    mova         [cq+64*10], m16
+    mova         [cq+64*11], m17
+    mova         [cq+64*12], m18
+    mova         [cq+64*13], m19
+    mova         [cq+64*14], m20
+    mova         [cq+64*15], m21
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast
+    mova         [cq+64* 0], m0
+    mova         [cq+64* 1], m1
+    mova         [cq+64* 2], m2
+    mova         [cq+64* 3], m3
+    mova         [cq+64* 4], m4
+    mova         [cq+64* 5], m5
+    mova         [cq+64* 6], m6
+    mova         [cq+64* 7], m7
+    pmulhrsw             m0, m13, [r4+64*16]
+    pmulhrsw             m1, m13, [r4+64*17]
+    pmulhrsw             m2, m13, [r4+64*18]
+    pmulhrsw             m3, m13, [r4+64*19]
+    pmulhrsw             m4, m13, [r4+64*20]
+    pmulhrsw             m5, m13, [r4+64*21]
+    pmulhrsw             m6, m13, [r4+64*22]
+    pmulhrsw             m7, m13, [r4+64*23]
+    mova         [cq+64*16], m14
+    mova         [cq+64*17], m15
+    mova         [cq+64*18], m16
+    mova         [cq+64*19], m17
+    mova         [cq+64*20], m18
+    mova         [cq+64*21], m19
+    mova         [cq+64*22], m20
+    mova         [cq+64*23], m21
+    pmulhrsw            m14, m13, [r4+64*24]
+    pmulhrsw            m15, m13, [r4+64*25]
+    pmulhrsw            m16, m13, [r4+64*26]
+    pmulhrsw            m17, m13, [r4+64*27]
+    pmulhrsw            m18, m13, [r4+64*28]
+    pmulhrsw            m19, m13, [r4+64*29]
+    pmulhrsw            m20, m13, [r4+64*30]
+    pmulhrsw            m21, m13, [r4+64*31]
+    mova         [cq+64*24], m22
+    mova         [cq+64*25], m23
+    mova         [cq+64*26], m24
+    mova         [cq+64*27], m25
+    mova         [cq+64*28], m26
+    mova         [cq+64*29], m27
+    mova         [cq+64*30], m28
+    mova         [cq+64*31], m29
+    call m(inv_txfm_add_dct_dct_64x16_8bpc).transpose_round
+    call .pass2_fast
+    mova         [r4+64*16], m14
+    mova         [r4+64*17], m15
+    mova         [r4+64*18], m16
+    mova         [r4+64*19], m17
+    mova         [r4+64*20], m18
+    mova         [r4+64*21], m19
+    mova         [r4+64*22], m20
+    mova         [r4+64*23], m21
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast
+.end:
+    vpbroadcastd        m13, [o(pw_2048)]
+    lea                  r5, [strideq*3]
+    pxor                m12, m12
+    lea                  r3, [dstq+r5*8]
+    lea                  r6, [strideq+r5] ; stride*4
+    add                  r3, r6           ; dst+stride*28
+%macro IDCT_64x32_END 5 ; src16, src32, mem, off_lo, off_hi
+    mova                m11, [cq+64*(   %3)] ;  0
+    mova                 m9, [cq+64*(31-%3)] ; 31
+%if %3 >= 8
+    mova                m%1, [rsp+64*(%1+16)]
+%endif
+    mova                m10, [dstq+%4]
+    paddsw               m8, m11, m9
+    psubsw              m11, m9
+    paddsw               m9, m%1, m%2
+    psubsw              m%1, m%2
+    punpcklbw           m%2, m10, m12
+    punpckhbw           m10, m12
+    pmulhrsw             m8, m13
+    pmulhrsw             m9, m13
+    paddw                m8, m%2
+    paddw                m9, m10
+    mova                m10, [r3+%5]
+    pmulhrsw            m11, m13
+    pmulhrsw            m%1, m13
+    mova    [cq+64*(   %3)], m12
+    mova    [cq+64*(31-%3)], m12
+    punpcklbw           m%2, m10, m12
+    punpckhbw           m10, m12
+    packuswb             m8, m9
+    paddw               m11, m%2
+    paddw               m%1, m10
+    packuswb            m11, m%1
+    mova          [dstq+%4], m8
+    mova          [r3  +%5], m11
+%if %3 == 3 || %3 == 7 || %3 == 11
+    add                dstq, r6
+    sub                  r3, r6
+%endif
+%endmacro
+    IDCT_64x32_END        0, 29,  0, strideq*0, r5
+    IDCT_64x32_END        1, 28,  1, strideq*1, strideq*2
+    IDCT_64x32_END        2, 27,  2, strideq*2, strideq*1
+    IDCT_64x32_END        3, 26,  3, r5       , strideq*0
+    IDCT_64x32_END        4, 25,  4, strideq*0, r5
+    IDCT_64x32_END        5, 24,  5, strideq*1, strideq*2
+    IDCT_64x32_END        6, 23,  6, strideq*2, strideq*1
+    IDCT_64x32_END        7, 22,  7, r5       , strideq*0
+    IDCT_64x32_END        0, 21,  8, strideq*0, r5
+    IDCT_64x32_END        1, 20,  9, strideq*1, strideq*2
+    IDCT_64x32_END        2, 19, 10, strideq*2, strideq*1
+    IDCT_64x32_END        3, 18, 11, r5       , strideq*0
+    IDCT_64x32_END        4, 17, 12, strideq*0, r5
+    IDCT_64x32_END        5, 16, 13, strideq*1, strideq*2
+    IDCT_64x32_END        6, 15, 14, strideq*2, strideq*1
+    IDCT_64x32_END        7, 14, 15, r5       , strideq*0
+    RET
+ALIGN function_align
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 32
+    imul                r6d, 181
+    add                 r6d, 128
+    sar                 r6d, 8
+    imul                r6d, 181
+    add                 r6d, 128+256
+    sar                 r6d, 8+1
+    jmp m(inv_txfm_add_dct_dct_64x16_8bpc).dconly2
+ALIGN function_align
+.pass1_end_part1:
+%macro IDCT_64x32_PASS1_END 3 ; src16, src32, src64
+%if %1 != %3
+    mova                m%1, [cq+64*%1]
+%endif
+    mova                 m9, [r4+64*(%3-36)] ; idct64 32+n
+    mova                m11, [r4+64*(-5-%3)] ; idct64 63-n
+    psubsw               m8, m%1, m%2        ; idct32 31-n
+    paddsw              m%1, m%2             ; idct32  0+n
+%if %1 == %3
+    psubsw              m%2, m8, m9   ; out 32+n e
+    paddsw               m8, m9       ; out 31-n d
+    psubsw               m9, m%1, m11 ; out 63-n h
+    paddsw              m%1, m11      ; out  0+n a
+%else
+    paddsw              m%2, m8, m9   ; out 23-n c
+    psubsw               m8, m9       ; out 40+n f
+    paddsw               m9, m%1, m11 ; out  8+n b
+    psubsw              m%1, m11      ; out 55-n g
+%endif
+    mova   [r4+64*(%3-36)], m8
+    mova   [r4+64*(-5-%3)], m9
+%endmacro
+    IDCT_64x32_PASS1_END  0, 29,  0
+    IDCT_64x32_PASS1_END  1, 28,  1
+    IDCT_64x32_PASS1_END  2, 27,  2
+    IDCT_64x32_PASS1_END  3, 26,  3
+    IDCT_64x32_PASS1_END  4, 25,  4
+    IDCT_64x32_PASS1_END  5, 24,  5
+    IDCT_64x32_PASS1_END  6, 23,  6
+    IDCT_64x32_PASS1_END  7, 22,  7
+.transpose_2x8x8_hi: ; m0-m7 + m22-m29 (inverted)
+    punpcklwd            m8, m25, m24 ; e0 f0 e1 f1 e2 f2 e3 f3
+    punpckhwd           m25, m24      ; e4 f4 e5 f5 e6 f6 e7 f7
+    punpcklwd           m24, m23, m22 ; g0 h0 g1 h1 g2 h2 g3 h3
+    punpckhwd           m23, m22      ; g4 h4 g5 h5 g6 h6 g7 h7
+    punpcklwd           m22, m29, m28 ; a0 b0 a1 b1 a2 b2 a3 b3
+    punpckhwd           m29, m28      ; a4 b4 a5 b5 a6 b6 a7 b7
+    punpcklwd           m28, m27, m26 ; c0 d0 c1 d1 c2 d2 c3 d3
+    punpckhwd           m27, m26      ; c4 d4 c5 d5 c6 d6 c7 d7
+    punpckldq           m26, m29, m27 ; a4 b4 c4 d4 a5 b5 c5 d5
+    punpckhdq           m29, m27      ; a6 b6 c6 d6 a7 b7 c7 d7
+    punpckldq           m27, m8, m24  ; e0 f0 g0 h0 e1 f1 g1 h1
+    punpckhdq            m8, m24      ; e2 f2 g2 h2 e3 f3 g3 h3
+    punpckhdq           m24, m22, m28 ; a2 b2 c2 d2 a3 b3 c3 d3
+    punpckldq           m22, m28      ; a0 b0 c0 d0 a1 b1 c1 d1
+    punpckldq           m28, m25, m23 ; e4 f4 g4 h4 e5 f5 g5 h5
+    punpckhdq           m25, m23      ; e6 f6 g6 h6 e7 f7 g7 h7
+    punpckhqdq          m23, m22, m27 ;  1 23
+    punpcklqdq          m22, m27      ;  0 22
+    punpckhqdq          m27, m26, m28 ;  5 27
+    punpcklqdq          m26, m28      ;  4 26
+    punpcklqdq          m28, m29, m25 ;  6 28
+    punpckhqdq          m29, m25      ;  7 29
+    punpckhqdq          m25, m24, m8  ;  3 25
+    punpcklqdq          m24, m8       ;  2 24
+.transpose_8x8:
+    punpckhwd            m8, m4, m5
+    punpcklwd            m4, m5
+    punpckhwd            m5, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m6, m7
+    punpcklwd            m6, m7
+    punpckhwd            m7, m2, m3
+    punpcklwd            m2, m3
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckldq            m2, m4, m6
+    punpckhdq            m4, m6
+    punpckhdq            m6, m5, m7
+    punpckldq            m5, m7
+    punpckldq            m7, m8, m1
+    punpckhdq            m8, m1
+    punpckhqdq           m1, m0, m2
+    punpcklqdq           m0, m2
+    punpcklqdq           m2, m3, m4
+    punpckhqdq           m3, m4
+    punpcklqdq           m4, m5, m7
+    punpckhqdq           m5, m7
+    punpckhqdq           m7, m6, m8
+    punpcklqdq           m6, m8
+    ret
+.pass1_end_part2:
+    IDCT_64x32_PASS1_END  0, 21,  8
+    IDCT_64x32_PASS1_END  1, 20,  9
+    IDCT_64x32_PASS1_END  2, 19, 10
+    IDCT_64x32_PASS1_END  3, 18, 11
+    IDCT_64x32_PASS1_END  4, 17, 12
+    IDCT_64x32_PASS1_END  5, 16, 13
+    IDCT_64x32_PASS1_END  6, 15, 14
+    IDCT_64x32_PASS1_END  7, 14, 15
+.transpose_2x8x8_lo: ; m0-m7 (inverted) + m14-m21
+    punpcklwd            m8, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m2, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m7, m6
+    punpckhwd            m7, m6
+    punpcklwd            m6, m5, m4
+    punpckhwd            m5, m4
+    punpckldq            m4, m7, m5
+    punpckhdq            m7, m5
+    punpckldq            m5, m8, m2
+    punpckhdq            m8, m2
+    punpckhdq            m2, m0, m6
+    punpckldq            m0, m6
+    punpckldq            m6, m3, m1
+    punpckhdq            m3, m1
+    punpckhqdq           m1, m0, m5
+    punpcklqdq           m0, m5
+    punpckhqdq           m5, m4, m6
+    punpcklqdq           m4, m6
+    punpcklqdq           m6, m7, m3
+    punpckhqdq           m7, m3
+    punpckhqdq           m3, m2, m8
+    punpcklqdq           m2, m8
+    punpckhwd            m8, m18, m19
+    punpcklwd           m18, m19
+    punpckhwd           m19, m14, m15
+    punpcklwd           m14, m15
+    punpckhwd           m15, m20, m21
+    punpcklwd           m20, m21
+    punpckhwd           m21, m16, m17
+    punpcklwd           m16, m17
+    punpckhdq           m17, m14, m16
+    punpckldq           m14, m16
+    punpckldq           m16, m18, m20
+    punpckhdq           m18, m20
+    punpckhdq           m20, m19, m21
+    punpckldq           m19, m21
+    punpckldq           m21, m8, m15
+    punpckhdq            m8, m15
+    punpckhqdq          m15, m14, m16
+    punpcklqdq          m14, m16
+    punpcklqdq          m16, m17, m18
+    punpckhqdq          m17, m18
+    punpcklqdq          m18, m19, m21
+    punpckhqdq          m19, m21
+    punpckhqdq          m21, m20, m8
+    punpcklqdq          m20, m8
+    ret
+.pass2_fast:
+    vshufi32x4          m24, m9, m15, q3131  ;  5
+    vshufi32x4          m22, m9, m15, q2020  ;  1
+    vshufi32x4          m15, m1, m16, q3131  ;  6
+    vshufi32x4          m14, m1, m16, q2020  ;  2
+    vshufi32x4           m1, m0, m3, q3131   ;  4
+    vshufi32x4           m0, m3, q2020       ;  0
+    vshufi32x4           m3, m8, m2, q3131   ; 12
+    vshufi32x4           m2, m8, m2, q2020   ;  8
+    vshufi32x4          m25, m11, m17, q3131 ;  7
+    vshufi32x4          m23, m11, m17, q2020 ;  3
+    vshufi32x4          m17, m5, m19, q3131  ; 14
+    vshufi32x4          m16, m5, m19, q2020  ; 10
+    vshufi32x4          m29, m6, m20, q3131  ; 15
+    vshufi32x4          m27, m6, m20, q2020  ; 11
+    vshufi32x4          m28, m4, m18, q3131  ; 13
+    vshufi32x4          m26, m4, m18, q2020  ;  9
+    jmp m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+
+cglobal inv_txfm_add_dct_dct_64x64_8bpc, 4, 7, 0, dst, stride, c, eob
+    lea                  r5, [o_base]
+    test               eobd, eobd
+    jz .dconly
+    PROLOGUE              0, 7, 30, 64*96, dst, stride, c, eob
+%undef cmp
+    cmp                eobd, 136
+    jb .fast
+    mova                 m0, [cq+64* 1]
+    mova                 m1, [cq+64*31]
+    mova                 m2, [cq+64*17]
+    mova                 m3, [cq+64*15]
+    vpbroadcastd        m10, [o(pd_2048)]
+    mov                  r4, rsp
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    mova                 m0, [cq+64* 7]
+    mova                 m1, [cq+64*25]
+    mova                 m2, [cq+64*23]
+    mova                 m3, [cq+64* 9]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    mova                 m0, [cq+64* 5]
+    mova                 m1, [cq+64*27]
+    mova                 m2, [cq+64*21]
+    mova                 m3, [cq+64*11]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    mova                 m0, [cq+64* 3]
+    mova                 m1, [cq+64*29]
+    mova                 m2, [cq+64*19]
+    mova                 m3, [cq+64*13]
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part2
+    mova                 m0, [cq+64* 0]
+    mova                 m1, [cq+64* 8]
+    mova                 m2, [cq+64*16]
+    mova                 m3, [cq+64*24]
+    mova                m14, [cq+64* 4]
+    mova                m15, [cq+64*12]
+    mova                m16, [cq+64*20]
+    mova                m17, [cq+64*28]
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+    mova                m22, [cq+64* 2]
+    mova                m29, [cq+64*30]
+    mova                m26, [cq+64*18]
+    mova                m25, [cq+64*14]
+    mova                m24, [cq+64*10]
+    mova                m27, [cq+64*22]
+    mova                m28, [cq+64*26]
+    mova                m23, [cq+64* 6]
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 1], m15
+    mova         [cq+64* 2], m16
+    mova         [cq+64* 3], m17
+    mova         [cq+64* 4], m18
+    mova         [cq+64* 5], m19
+    mova         [cq+64* 6], m20
+    mova         [cq+64* 7], m21
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast
+    vpbroadcastd        m13, [o(pw_8192)]
+    call m(inv_txfm_add_dct_dct_64x32_8bpc).pass1_end_part1
+    mova         [r4+64*36], m1
+    mova         [r4+64*37], m3
+    mova         [r4+64*38], m5
+    mova         [r4+64*39], m7
+    mova         [r4+64*44], m23
+    mova         [r4+64*45], m25
+    mova         [r4+64*46], m27
+    mova         [r4+64*47], m29
+    pmulhrsw            m23, m13, m0 ; a0
+    pmulhrsw            m25, m13, m2 ; a2
+    pmulhrsw            m27, m13, m4 ; a4
+    pmulhrsw            m29, m13, m6 ; a6
+    call m(inv_txfm_add_dct_dct_64x32_8bpc).pass1_end_part2
+    lea                  r6, [r4-64*4]
+    add                  r4, 64*28
+    call .pass2_end
+    mov                  r4, rsp
+    mova                 m0, [r4+64*23]
+    mova                 m1, [r4+64*22]
+    mova                 m2, [r4+64*21]
+    mova                 m3, [r4+64*20]
+    mova                 m4, [r4+64*19]
+    mova                 m5, [r4+64*18]
+    mova                 m6, [r4+64*17]
+    mova                 m7, [r4+64*16]
+    mova                m22, [r4+64*15]
+    mova                m23, [r4+64*14]
+    mova                m24, [r4+64*13]
+    mova                m25, [r4+64*12]
+    mova                m26, [r4+64*11]
+    mova                m27, [r4+64*10]
+    mova                m28, [r4+64* 9]
+    mova                m29, [r4+64* 8]
+    call m(inv_txfm_add_dct_dct_64x32_8bpc).transpose_2x8x8_hi
+    vpbroadcastd        m13, [o(pw_8192)]
+    mova         [r4+64* 8], m1
+    mova         [r4+64* 9], m3
+    mova         [r4+64*10], m5
+    mova         [r4+64*11], m7
+    mova         [r4+64*16], m23
+    mova         [r4+64*17], m25
+    mova         [r4+64*18], m27
+    mova         [r4+64*19], m29
+    pmulhrsw            m23, m13, m0 ; b0
+    pmulhrsw            m25, m13, m2 ; b2
+    pmulhrsw            m27, m13, m4 ; b4
+    pmulhrsw            m29, m13, m6 ; b6
+    mova                 m0, [r4+64*31]
+    mova                 m1, [r4+64*30]
+    mova                 m2, [r4+64*29]
+    mova                 m3, [r4+64*28]
+    mova                 m4, [r4+64*27]
+    mova                 m5, [r4+64*26]
+    mova                 m6, [r4+64*25]
+    mova                 m7, [r4+64*24]
+    mova                m14, [r4+64* 7]
+    mova                m15, [r4+64* 6]
+    mova                m16, [r4+64* 5]
+    mova                m17, [r4+64* 4]
+    mova                m18, [r4+64* 3]
+    mova                m19, [r4+64* 2]
+    mova                m20, [r4+64* 1]
+    mova                m21, [r4+64* 0]
+    call m(inv_txfm_add_dct_dct_64x32_8bpc).transpose_2x8x8_lo
+    mov                  r6, cq
+    call .pass2_end
+    jmp .end
+.fast: ; bottom/right halves are zero
+    mova                m28, [o(dup16_perm)]
+    pmovzxwd             m9,       [cq+64* 0]
+    vpermb               m8, m28,  [cq+64* 4]
+    vpermb              ym1, ym28, [cq+64*12]
+    vpermb               m7, m28,  [cq+64* 8]
+    pslld                m9, 16
+    call m(idct_16x16_internal_8bpc).main_fast2
+    vpermb              m21, m28,  [cq+64* 2]
+    vpermb             ym15, ym28, [cq+64*14]
+    vpermb             ym18, ym28, [cq+64*10]
+    vpermb              m14, m28,  [cq+64* 6]
+    call m(inv_txfm_add_dct_dct_16x32_8bpc).main_oddhalf_fast2
+    vpermb              m22, m28,  [cq+64* 1]
+    vpermb             ym29, ym28, [cq+64*15]
+    vpermb             ym26, ym28, [cq+64* 9]
+    vpermb              m25, m28,  [cq+64* 7]
+    vpermb              m24, m28,  [cq+64* 5]
+    vpermb             ym27, ym28, [cq+64*11]
+    vpermb              m23, m28,  [cq+64* 3]
+    vpermb             ym28, ym28, [cq+64*13]
+    mova         [cq+64* 0], m14
+    mova         [cq+64* 1], m15
+    mova         [cq+64* 2], m16
+    mova         [cq+64* 3], m17
+    mova         [cq+64* 4], m18
+    mova         [cq+64* 5], m19
+    mova         [cq+64* 6], m20
+    mova         [cq+64* 7], m21
+    call m(inv_txfm_add_dct_dct_16x64_8bpc).main_oddhalf_fast
+    vpbroadcastd        m13, [o(pw_8192)]
+    mova         [cq+64*16], m4
+    mova         [cq+64*17], m5
+    mova         [cq+64*18], m6
+    mova         [cq+64*19], m7
+    mova         [cq+64*28], m26
+    mova         [cq+64*29], m27
+    mova         [cq+64*30], m28
+    mova         [cq+64*31], m29
+    call m(inv_txfm_add_dct_dct_64x16_8bpc).pass1_end
+    mova         [cq+64*20], m22
+    mova         [cq+64*21], m23
+    mova         [cq+64*22], m24
+    mova         [cq+64*23], m25
+    mova         [cq+64*24], m26
+    mova         [cq+64*25], m27
+    mova         [cq+64*26], m28
+    mova         [cq+64*27], m29
+    lea                  r4, [rsp+64*64]
+    lea                  r3, [rsp+64*32]
+    call .pass2_fast
+    pmulhrsw             m0, m13, [cq+64*16]
+    pmulhrsw             m1, m13, [cq+64*17]
+    pmulhrsw             m2, m13, [cq+64*18]
+    pmulhrsw             m3, m13, [cq+64*19]
+    pmulhrsw             m4, m13, [cq+64*20]
+    pmulhrsw             m5, m13, [cq+64*21]
+    pmulhrsw             m6, m13, [cq+64*22]
+    pmulhrsw             m7, m13, [cq+64*23]
+    pmulhrsw            m14, m13, [cq+64*24]
+    pmulhrsw            m15, m13, [cq+64*25]
+    pmulhrsw            m16, m13, [cq+64*26]
+    pmulhrsw            m17, m13, [cq+64*27]
+    pmulhrsw            m18, m13, [cq+64*28]
+    pmulhrsw            m19, m13, [cq+64*29]
+    pmulhrsw            m20, m13, [cq+64*30]
+    pmulhrsw            m21, m13, [cq+64*31]
+    call m(inv_txfm_add_dct_dct_64x16_8bpc).transpose_round
+    mov                  r4, rsp
+    mov                  r3, cq
+    call .pass2_fast
+.end:
+    vpbroadcastd        m17, [o(pw_2048)]
+    lea                  r5, [strideq*8]
+    mov                  r3, dstq
+    pxor                m16, m16
+    sub                  r4, 64*5 ; rsp+64*31
+    mov                  r6, rsp
+.end_loop:
+    mova                 m2, [r6+64*32] ; idct16 0+n  lo
+    mova                 m7, [r6+64*48] ; idct32 31-n lo
+    mova                 m6, [cq+64* 0] ; idct16 0+n  hi
+    mova                 m0, [cq+64*16] ; idct32 31-n hi
+    mova                 m4, [r4+64*64] ; idct64 63-n lo
+    mova                 m1, [r4+64* 0] ; idct64 63-n hi
+    mova                 m5, [r6+64*64] ; idct64 32+n lo
+    mova                 m8, [r6+64* 0] ; idct64 32+n hi
+    sub                  r3, strideq
+    paddsw               m3, m2, m7     ; idct32  0+n lo
+    mova                m12, [dstq+r5*0]
+    psubsw               m2, m7         ; idct32 31-n lo
+    mova                m15, [r3  +r5*8]
+    paddsw               m7, m6, m0     ; idct32  0+n hi
+    mova                m13, [r3  +r5*4]
+    psubsw               m6, m0         ; idct32 31-n hi
+    mova                m14, [dstq+r5*4]
+    paddsw               m0, m3, m4     ; out  0+n lo
+    add                  r6, 64
+    psubsw               m3, m4         ; out 63-n lo
+    sub                  r4, 64
+    paddsw               m4, m7, m1     ; out  0+n hi
+    mova         [cq+64* 0], m16
+    psubsw               m7, m1         ; out 63-n hi
+    mova         [cq+64*16], m16
+    paddsw               m1, m2, m5     ; out 31-n lo
+    add                  cq, 64
+    psubsw               m2, m5         ; out 32+n lo
+    paddsw               m5, m6, m8     ; out 31-n hi
+    psubsw               m6, m8         ; out 32+n hi
+    pmulhrsw             m0, m17
+    punpcklbw            m8, m12, m16
+    pmulhrsw             m4, m17
+    punpckhbw           m12, m16
+    pmulhrsw             m3, m17
+    punpcklbw           m11, m15, m16
+    pmulhrsw             m7, m17
+    punpckhbw           m15, m16
+    pmulhrsw             m1, m17
+    punpcklbw            m9, m13, m16
+    pmulhrsw             m5, m17
+    punpckhbw           m13, m16
+    pmulhrsw             m2, m17
+    punpcklbw           m10, m14, m16
+    pmulhrsw             m6, m17
+    punpckhbw           m14, m16
+    paddw                m0, m8
+    paddw                m4, m12
+    packuswb             m0, m4
+    paddw                m3, m11
+    paddw                m7, m15
+    packuswb             m3, m7
+    paddw                m1, m9
+    paddw                m5, m13
+    packuswb             m1, m5
+    paddw                m2, m10
+    paddw                m6, m14
+    packuswb             m2, m6
+    mova        [dstq+r5*0], m0
+    mova        [r3  +r5*8], m3
+    mova        [r3  +r5*4], m1
+    mova        [dstq+r5*4], m2
+    add                dstq, strideq
+    cmp                  r6, r4
+    jb .end_loop
+    RET
+.dconly:
+    movsx               r6d, word [cq]
+    mov                [cq], eobd
+    or                  r3d, 64
+    jmp m(inv_txfm_add_dct_dct_64x16_8bpc).dconly
+ALIGN function_align
+.pass2_end:
+    REPX  {pmulhrsw x, m13}, m22, m24, m26, m28, m14, m16, m18, m20, m0, m2, m4, m6
+    mova         [r4+64*20], m1
+    mova         [r4+64*21], m3
+    mova         [r4+64*22], m5
+    mova         [r4+64*23], m7
+    vinserti32x8         m1, m23, ym14, 1    ; a00 a01 c00 c01
+    vshufi32x4           m3, m23, m14, q3232 ; a02 a03 c02 c03
+    vinserti32x8         m5, m22, ym0, 1     ; e00 e01 g00 g01
+    vshufi32x4          m14, m22, m0, q3232  ; e02 e03 g02 g03
+    mova         [r4+64*12], m15
+    mova         [r4+64*13], m17
+    mova         [r4+64*14], m19
+    mova         [r4+64*15], m21
+    vinserti32x8        m15, m27, ym18, 1    ; a40 a41 c40 c41
+    vshufi32x4          m17, m27, m18, q3232 ; a42 a43 c42 c43
+    vinserti32x8        m18, m26, ym4, 1     ; e40 e41 g40 g41
+    vshufi32x4          m19, m26, m4, q3232  ; e42 e43 g42 g43
+    vinserti32x8        m22, m25, ym16, 1    ; a20 a21 c20 c21
+    vshufi32x4          m26, m25, m16, q3232 ; a22 a23 c22 c23
+    vinserti32x8        m25, m24, ym2, 1     ; e20 e21 g20 g21
+    vshufi32x4          m27, m24, m2, q3232  ; e22 e23 g22 g23
+    vinserti32x8        m23, m29, ym20, 1    ; a60 a61 c60 c61
+    vshufi32x4          m29, m20, q3232      ; a62 a63 c62 c63
+    vshufi32x4          m13, m28, m6, q3232  ; e62 e63 g62 g63
+    vinserti32x8        m28, ym6, 1          ; e60 e61 g60 g61
+    vshufi32x4           m0, m1, m5, q2020   ;  0
+    vshufi32x4           m1, m5, q3131       ;  8
+    vshufi32x4           m2, m3, m14, q2020  ; 16
+    vshufi32x4           m3, m14, q3131      ; 24
+    vshufi32x4          m14, m15, m18, q2020 ;  4
+    vshufi32x4          m15, m18, q3131      ; 12
+    vshufi32x4          m16, m17, m19, q2020 ; 20
+    vshufi32x4          m17, m19, q3131      ; 28
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast
+    vshufi32x4          m24, m22, m25, q3131 ; 10
+    vshufi32x4          m22, m25, q2020      ;  2
+    vshufi32x4          m25, m23, m28, q3131 ; 14
+    vshufi32x4          m23, m28, q2020      ;  6
+    vshufi32x4          m28, m26, m27, q3131 ; 26
+    vshufi32x4          m26, m27, q2020      ; 18
+    vshufi32x4          m27, m29, m13, q2020 ; 22
+    vshufi32x4          m29, m13, q3131      ; 30
+    mova         [r6+64* 0], m0
+    mova         [r6+64* 1], m1
+    mova         [r6+64* 2], m2
+    mova         [r6+64* 3], m3
+    mova         [r6+64* 4], m4
+    mova         [r6+64* 5], m5
+    mova         [r6+64* 6], m6
+    mova         [r6+64* 7], m7
+    mova         [r6+64* 8], m14
+    mova         [r6+64* 9], m15
+    mova         [r6+64*10], m16
+    mova         [r6+64*11], m17
+    mova         [r6+64*12], m18
+    mova         [r6+64*13], m19
+    mova         [r6+64*14], m20
+    mova         [r6+64*15], m21
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast
+    vpbroadcastd        m13, [o(pw_8192)]
+    mova         [r6+64*16], m29
+    mova         [r6+64*17], m28
+    mova         [r6+64*18], m27
+    mova         [r6+64*19], m26
+    mova         [r6+64*20], m25
+    mova         [r6+64*21], m24
+    mova         [r6+64*22], m23
+    mova         [r6+64*23], m22
+    mova         [r6+64*24], m21
+    mova         [r6+64*25], m20
+    mova         [r6+64*26], m19
+    mova         [r6+64*27], m18
+    mova         [r6+64*28], m17
+    mova         [r6+64*29], m16
+    mova         [r6+64*30], m15
+    mova         [r6+64*31], m14
+    pmulhrsw            m15, m13, [r4+64* 8] ;  1  9 17 25
+    pmulhrsw            m16, m13, [r4+64*12]
+    pmulhrsw            m17, m13, [r4+64*16]
+    pmulhrsw            m18, m13, [r4+64*20]
+    pmulhrsw            m19, m13, [r4+64*11] ;  7 15 23 31
+    pmulhrsw            m20, m13, [r4+64*15]
+    pmulhrsw            m21, m13, [r4+64*19]
+    pmulhrsw            m22, m13, [r4+64*23]
+    vinserti32x8        m14, m15, ym16, 1 ; a1  a9  c1  c9
+    vshufi32x4          m15, m16, q3232   ; a17 a25 c17 c25
+    vinserti32x8        m16, m17, ym18, 1 ; e1  e9  g1  g9
+    vshufi32x4          m17, m18, q3232   ; e17 e25 g17 g25
+    pmulhrsw            m23, m13, [r4+64*10] ;  5 13 21 29
+    pmulhrsw            m24, m13, [r4+64*14]
+    pmulhrsw            m25, m13, [r4+64*18]
+    pmulhrsw            m26, m13, [r4+64*22]
+    vinserti32x8        m18, m19, ym20, 1 ; a7  a15 c7  c15
+    vshufi32x4          m19, m20, q3232   ; a23 a31 c23 c31
+    vinserti32x8        m20, m21, ym22, 1 ; e7  e15 g7  g15
+    vshufi32x4          m21, m22, q3232   ; e23 e31 g23 g31
+    pmulhrsw            m27, m13, [r4+64* 9] ;  3 11 19 27
+    pmulhrsw            m28, m13, [r4+64*13]
+    pmulhrsw            m29, m13, [r4+64*17]
+    pmulhrsw            m13,      [r4+64*21]
+    vshufi32x4           m0, m14, m16, q2020 ;  1
+    vshufi32x4           m1, m19, m21, q3131 ; 31
+    vshufi32x4           m2, m15, m17, q2020 ; 17
+    vshufi32x4           m3, m18, m20, q3131 ; 15
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    vshufi32x4           m0, m18, m20, q2020 ;  7
+    vshufi32x4           m1, m15, m17, q3131 ; 25
+    vshufi32x4           m2, m19, m21, q2020 ; 23
+    vshufi32x4           m3, m14, m16, q3131 ;  9
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    vinserti32x8        m22, m23, ym24, 1 ; a5  a13 c5  c13
+    vshufi32x4          m23, m24, q3232   ; a21 a29 c21 c29
+    vinserti32x8        m24, m25, ym26, 1 ; e5  e13 g5  g13
+    vshufi32x4          m25, m26, q3232   ; e21 e29 g21 g29
+    vinserti32x8        m26, m27, ym28, 1 ; a3  a11 c3  c11
+    vshufi32x4          m27, m28, q3232   ; a19 a27 c19 c27
+    vinserti32x8        m28, m29, ym13, 1 ; e3  e11 g3  g11
+    vshufi32x4          m29, m13, q3232   ; e19 e17 g19 g27
+    vshufi32x4           m0, m22, m24, q2020 ;  5
+    vshufi32x4           m1, m27, m29, q3131 ; 27
+    vshufi32x4           m2, m23, m25, q2020 ; 21
+    vshufi32x4           m3, m26, m28, q3131 ; 11
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    vshufi32x4           m0, m26, m28, q2020 ;  3
+    vshufi32x4           m1, m23, m25, q3131 ; 29
+    vshufi32x4           m2, m27, m29, q2020 ; 19
+    vshufi32x4           m3, m22, m24, q3131 ; 13
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1
+    jmp m(inv_txfm_add_dct_dct_32x64_8bpc).main_part2
+ALIGN function_align
+.pass2_fast:
+    vshufi32x4          m23, m1, m16, q3131  ;  6
+    vshufi32x4          m22, m1, m16, q2020  ;  2
+    vshufi32x4          m14, m0, m3, q3131   ;  4
+    vshufi32x4          m26, m0, m3, q2020   ;  0
+    vshufi32x4          m28, m9, m15, q3131  ;  5
+    vshufi32x4           m0, m9, m15, q2020  ;  1
+    vshufi32x4          m16, m11, m17, q3131 ;  7
+    vshufi32x4          m29, m11, m17, q2020 ;  3
+    vshufi32x4          m15, m8, m2, q3131   ; 12
+    vshufi32x4          m27, m8, m2, q2020   ;  8
+    vshufi32x4          m25, m5, m19, q3131  ; 14
+    vshufi32x4          m24, m5, m19, q2020  ; 10
+    vshufi32x4           m3, m6, m20, q3131  ; 15
+    vshufi32x4          m19, m6, m20, q2020  ; 11
+    vshufi32x4          m17, m4, m18, q3131  ; 13
+    vshufi32x4          m18, m4, m18, q2020  ;  9
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast
+    mova                 m0, m16
+    mova                 m3, m18
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast
+    mova                 m0, m28
+    mova                 m3, m19
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast
+    mova                 m0, m29
+    mova                 m3, m17
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part1_fast
+    call m(inv_txfm_add_dct_dct_32x64_8bpc).main_part2
+    mova                 m0, m26
+    mova                 m1, m27
+    call m(inv_txfm_add_dct_dct_32x16_8bpc).main_oddhalf_fast2
+    mova         [r3+64* 0], m0
+    mova         [r3+64* 1], m1
+    mova         [r3+64* 2], m2
+    mova         [r3+64* 3], m3
+    mova         [r3+64* 4], m4
+    mova         [r3+64* 5], m5
+    mova         [r3+64* 6], m6
+    mova         [r3+64* 7], m7
+    mova         [r3+64* 8], m14
+    mova         [r3+64* 9], m15
+    mova         [r3+64*10], m16
+    mova         [r3+64*11], m17
+    mova         [r3+64*12], m18
+    mova         [r3+64*13], m19
+    mova         [r3+64*14], m20
+    mova         [r3+64*15], m21
+    call m(inv_txfm_add_dct_dct_32x32_8bpc).main_oddhalf_fast2
+    mova         [r3+64*16], m29
+    mova         [r3+64*17], m28
+    mova         [r3+64*18], m27
+    mova         [r3+64*19], m26
+    mova         [r3+64*20], m25
+    mova         [r3+64*21], m24
+    mova         [r3+64*22], m23
+    mova         [r3+64*23], m22
+    mova         [r3+64*24], m21
+    mova         [r3+64*25], m20
+    mova         [r3+64*26], m19
+    mova         [r3+64*27], m18
+    mova         [r3+64*28], m17
+    mova         [r3+64*29], m16
+    mova         [r3+64*30], m15
+    mova         [r3+64*31], m14
+    ret
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/itx_sse.asm b/media/libdav1d/src/src/x86/itx_sse.asm
new file mode 100644
index 0000000000..ec7e3a52f4
--- /dev/null
+++ b/media/libdav1d/src/src/x86/itx_sse.asm
@@ -0,0 +1,6533 @@
+; Copyright © 2018-2021, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+
+SECTION_RODATA 16
+
+deint_shuf:  db  0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+
+deint_shuf1: db  0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+deint_shuf2: db  8,  9,  0,  1, 10, 11,  2,  3, 12, 13,  4,  5, 14, 15,  6,  7
+
+%macro COEF_PAIR 2-3 0 ; !0 = m%1_m%2, 2 = no %2_%1
+pw_%1_m%2:  times 4 dw  %1, -%2
+%if %3 != 2
+pw_%2_%1:   times 4 dw  %2,  %1
+%endif
+%if %3
+pw_m%1_m%2: times 4 dw -%1, -%2
+%endif
+%endmacro
+
+;adst4
+pw_1321_3803:   times 4 dw  1321,  3803
+pw_2482_m1321:  times 4 dw  2482, -1321
+pw_3344_2482:   times 4 dw  3344,  2482
+pw_3344_m3803:  times 4 dw  3344, -3803
+pw_3344_m3344:  times 4 dw  3344, -3344
+pw_0_3344       times 4 dw     0,  3344
+pw_m6688_m3803: times 4 dw -6688, -3803
+
+COEF_PAIR 2896, 2896
+COEF_PAIR 1567, 3784
+COEF_PAIR  799, 4017
+COEF_PAIR 3406, 2276
+COEF_PAIR  401, 4076
+COEF_PAIR 1931, 3612
+COEF_PAIR 3166, 2598
+COEF_PAIR 3920, 1189
+COEF_PAIR 3784, 1567, 1
+COEF_PAIR  995, 3973
+COEF_PAIR 1751, 3703
+COEF_PAIR 3513, 2106
+COEF_PAIR 3857, 1380
+COEF_PAIR 4017,  799, 1
+COEF_PAIR  201, 4091
+COEF_PAIR 2440, 3290
+COEF_PAIR 3035, 2751
+COEF_PAIR 4052,  601
+COEF_PAIR 2276, 3406, 1
+COEF_PAIR 4076,  401, 2
+COEF_PAIR 2598, 3166, 2
+COEF_PAIR 3612, 1931, 2
+COEF_PAIR 1189, 3920, 2
+
+pd_2048:        times 4 dd  2048
+pw_2048:        times 8 dw  2048
+pw_m2048:       times 8 dw -2048
+pw_4096:        times 8 dw  4096
+pw_16384:       times 8 dw  16384
+pw_m16384:      times 8 dw  -16384
+pw_1697x16:     times 8 dw  1697*16
+pw_1697x8:      times 8 dw  1697*8
+pw_2896x8:      times 8 dw  2896*8
+pw_3344x8:      times 8 dw  3344*8
+pw_8192:        times 8 dw  8192
+pw_m8192:       times 8 dw -8192
+pw_5:           times 8 dw  5
+pw_201x8:       times 8 dw   201*8
+pw_4091x8:      times 8 dw  4091*8
+pw_m2751x8:     times 8 dw -2751*8
+pw_3035x8:      times 8 dw  3035*8
+pw_1751x8:      times 8 dw  1751*8
+pw_3703x8:      times 8 dw  3703*8
+pw_m1380x8:     times 8 dw -1380*8
+pw_3857x8:      times 8 dw  3857*8
+pw_995x8:       times 8 dw   995*8
+pw_3973x8:      times 8 dw  3973*8
+pw_m2106x8:     times 8 dw -2106*8
+pw_3513x8:      times 8 dw  3513*8
+pw_2440x8:      times 8 dw  2440*8
+pw_3290x8:      times 8 dw  3290*8
+pw_m601x8:      times 8 dw  -601*8
+pw_4052x8:      times 8 dw  4052*8
+
+pw_4095x8:      times 8 dw  4095*8
+pw_101x8:       times 8 dw   101*8
+pw_2967x8:      times 8 dw  2967*8
+pw_m2824x8:     times 8 dw -2824*8
+pw_3745x8:      times 8 dw  3745*8
+pw_1660x8:      times 8 dw  1660*8
+pw_3822x8:      times 8 dw  3822*8
+pw_m1474x8:     times 8 dw -1474*8
+pw_3996x8:      times 8 dw  3996*8
+pw_897x8:       times 8 dw   897*8
+pw_3461x8:      times 8 dw  3461*8
+pw_m2191x8:     times 8 dw -2191*8
+pw_3349x8:      times 8 dw  3349*8
+pw_2359x8:      times 8 dw  2359*8
+pw_4036x8:      times 8 dw  4036*8
+pw_m700x8:      times 8 dw  -700*8
+pw_4065x8:      times 8 dw  4065*8
+pw_501x8:       times 8 dw   501*8
+pw_3229x8:      times 8 dw  3229*8
+pw_m2520x8:     times 8 dw -2520*8
+pw_3564x8:      times 8 dw  3564*8
+pw_2019x8:      times 8 dw  2019*8
+pw_3948x8:      times 8 dw  3948*8
+pw_m1092x8:     times 8 dw -1092*8
+pw_3889x8:      times 8 dw  3889*8
+pw_1285x8:      times 8 dw  1285*8
+pw_3659x8:      times 8 dw  3659*8
+pw_m1842x8:     times 8 dw -1842*8
+pw_3102x8:      times 8 dw  3102*8
+pw_2675x8:      times 8 dw  2675*8
+pw_4085x8:      times 8 dw  4085*8
+pw_m301x8:      times 8 dw  -301*8
+
+SECTION .text
+
+%define m(x) mangle(private_prefix %+ _ %+ x %+ SUFFIX)
+
+%if ARCH_X86_64
+%define o(x) x
+%else
+%define o(x) r5-$$+x ; PIC
+%endif
+
+%macro WRITE_4X4 9  ;src[1-2], tmp[1-3], row[1-4]
+    lea                  r2, [dstq+strideq*2]
+%assign %%i 1
+%rotate 5
+%rep 4
+    %if %1 & 2
+        CAT_XDEFINE %%row_adr, %%i, r2   + strideq*(%1&1)
+    %else
+        CAT_XDEFINE %%row_adr, %%i, dstq + strideq*(%1&1)
+    %endif
+    %assign %%i %%i + 1
+    %rotate 1
+%endrep
+
+    movd                 m%3, [%%row_adr1]        ;dst0
+    movd                 m%5, [%%row_adr2]        ;dst1
+    punpckldq            m%3, m%5                 ;high: dst1 :low: dst0
+    movd                 m%4, [%%row_adr3]        ;dst2
+    movd                 m%5, [%%row_adr4]        ;dst3
+    punpckldq            m%4, m%5                 ;high: dst3 :low: dst2
+
+    pxor                 m%5, m%5
+    punpcklbw            m%3, m%5                 ;extend byte to word
+    punpcklbw            m%4, m%5                 ;extend byte to word
+
+    paddw                m%3, m%1                 ;high: dst1 + out1 ;low: dst0 + out0
+    paddw                m%4, m%2                 ;high: dst3 + out3 ;low: dst2 + out2
+
+    packuswb             m%3, m%4                 ;high->low: dst3 + out3, dst2 + out2, dst1 + out1, dst0 + out0
+
+    movd        [%%row_adr1], m%3                  ;store dst0 + out0
+    pshuflw              m%4, m%3, q1032
+    movd        [%%row_adr2], m%4                  ;store dst1 + out1
+    punpckhqdq           m%3, m%3
+    movd        [%%row_adr3], m%3                  ;store dst2 + out2
+    psrlq                m%3, 32
+    movd        [%%row_adr4], m%3                  ;store dst3 + out3
+%endmacro
+
+%macro ITX4_END 4-5 2048 ; row[1-4], rnd
+%if %5
+    mova                 m2, [o(pw_%5)]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+%endif
+
+    WRITE_4X4            0, 1, 2, 3, 4, %1, %2, %3, %4
+    ret
+%endmacro
+
+; flags: 1 = swap, 2: coef_regs, 4: no_pack
+%macro ITX_MUL2X_PACK 5-6 0 ; dst/src, tmp[1], rnd, coef[1-2], flags
+%if %6 & 2
+    pmaddwd              m%2, m%4, m%1
+    pmaddwd              m%1, m%5
+%elif %6 & 1
+    pmaddwd              m%2, m%1, [o(pw_%5_%4)]
+    pmaddwd              m%1, [o(pw_%4_m%5)]
+%else
+    pmaddwd              m%2, m%1, [o(pw_%4_m%5)]
+    pmaddwd              m%1, [o(pw_%5_%4)]
+%endif
+    paddd                m%2, m%3
+    paddd                m%1, m%3
+    psrad                m%2, 12
+    psrad                m%1, 12
+%if %6 & 4 == 0
+    packssdw             m%1, m%2
+%endif
+%endmacro
+
+%macro IDCT4_1D_PACKED 0-1   ;pw_2896x8
+    mova                 m3, [o(pd_2048)]
+    punpckhwd            m2, m0, m1            ;unpacked in1 in3
+    punpcklwd            m0, m1                ;unpacked in0 in2
+    ITX_MUL2X_PACK        2, 1, 3, 1567, 3784
+    ITX_MUL2X_PACK        0, 1, 3, 2896, 2896
+    psubsw               m1, m0, m2            ;high: out2 ;low: out3
+    paddsw               m0, m2                ;high: out1 ;low: out0
+%endmacro
+
+%macro INV_TXFM_FN 4+ ; type1, type2, size, xmm/stack
+cglobal inv_txfm_add_%1_%2_%3_8bpc, 4, 6, %4, dst, stride, coeff, eob, tx2
+    %define %%p1 m(i%1_%3_internal_8bpc)
+%if ARCH_X86_32
+    LEA                    r5, $$
+%endif
+%if has_epilogue
+%ifidn %1_%2, dct_dct
+    test                 eobd, eobd
+    jz %%end
+%endif
+    lea                  tx2q, [o(m(i%2_%3_internal_8bpc).pass2)]
+    call %%p1
+    RET
+%%end:
+%else
+    lea                  tx2q, [o(m(i%2_%3_internal_8bpc).pass2)]
+%ifidn %1_%2, dct_dct
+    test                 eobd, eobd
+    jnz %%p1
+%else
+    times ((%%end - %%p1) >> 31) & 1 jmp %%p1
+ALIGN function_align
+%%end:
+%endif
+%endif
+%endmacro
+
+%macro INV_TXFM_4X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x4, 6
+%ifidn %1_%2, dct_dct
+    pshuflw              m0, [coeffq], q0000
+    punpcklqdq           m0, m0
+    mova                 m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1
+    mov            [coeffq], eobd                ;0
+    pmulhrsw             m0, m1
+    mova                 m1, m0
+    TAIL_CALL m(iadst_4x4_internal_8bpc).end2
+%endif
+%endmacro
+
+INIT_XMM ssse3
+; itx16 relies on dct_dct being the first function. If you change the order, adjust `itx8_start` in itx16.
+
+INV_TXFM_4X4_FN dct, dct
+INV_TXFM_4X4_FN dct, adst
+INV_TXFM_4X4_FN dct, flipadst
+INV_TXFM_4X4_FN dct, identity
+
+cglobal idct_4x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m0, [coeffq+16*0]      ;high: in1 ;low: in0
+    mova                 m1, [coeffq+16*1]      ;high: in3 ;low in2
+
+    IDCT4_1D_PACKED
+
+    mova                 m2, [o(deint_shuf)]
+    shufps               m3, m0, m1, q1331
+    shufps               m0, m1, q0220
+    pshufb               m0, m2                 ;high: in1 ;low: in0
+    pshufb               m1, m3, m2             ;high: in3 ;low :in2
+    jmp                tx2q
+
+.pass2:
+    IDCT4_1D_PACKED
+
+    pxor                 m2, m2
+    mova      [coeffq+16*0], m2
+    mova      [coeffq+16*1], m2                 ;memset(coeff, 0, sizeof(*coeff) * sh * sw);
+
+    ITX4_END     0, 1, 3, 2
+
+INV_TXFM_4X4_FN adst, dct
+INV_TXFM_4X4_FN adst, adst
+INV_TXFM_4X4_FN adst, flipadst
+INV_TXFM_4X4_FN adst, identity
+
+cglobal iadst_4x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m0, [coeffq+16*0]
+    mova                 m1, [coeffq+16*1]
+    call .main
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2       ;high: in3 ;low :in2
+    punpcklwd            m0, m2           ;high: in1 ;low: in0
+    jmp                tx2q
+
+.pass2:
+    call .main
+
+.end:
+    pxor                 m2, m2
+    mova      [coeffq+16*0], m2
+    mova      [coeffq+16*1], m2
+
+.end2:
+    ITX4_END              0, 1, 2, 3
+
+ALIGN function_align
+cglobal_label .main
+    punpcklwd            m2, m0, m1                ;unpacked in0 in2
+    punpckhwd            m0, m1                    ;unpacked in1 in3
+    mova                 m3, m0
+    pmaddwd              m1, m2, [o(pw_3344_m3344)];3344 * in0 - 3344 * in2
+    pmaddwd              m0, [o(pw_0_3344)]        ;3344 * in3
+    paddd                m1, m0                    ;t2
+    pmaddwd              m0, m2, [o(pw_1321_3803)] ;1321 * in0 + 3803 * in2
+    pmaddwd              m2, [o(pw_2482_m1321)]    ;2482 * in0 - 1321 * in2
+    pmaddwd              m4, m3, [o(pw_3344_2482)] ;3344 * in1 + 2482 * in3
+    pmaddwd              m5, m3, [o(pw_3344_m3803)];3344 * in1 - 3803 * in3
+    paddd                m4, m0                    ;t0 + t3
+    pmaddwd              m3, [o(pw_m6688_m3803)]   ;-2 * 3344 * in1 - 3803 * in3
+    mova                 m0, [o(pd_2048)]
+    paddd                m1, m0                    ;t2 + 2048
+    paddd                m2, m0
+    paddd                m0, m4                    ;t0 + t3 + 2048
+    paddd                m5, m2                    ;t1 + t3 + 2048
+    paddd                m2, m4
+    paddd                m2, m3                    ;t0 + t1 - t3 + 2048
+    REPX      {psrad x, 12}, m1, m0, m5, m2
+    packssdw             m0, m5                    ;high: out1 ;low: out0
+    packssdw             m1, m2                    ;high: out3 ;low: out3
+    ret
+
+INV_TXFM_4X4_FN flipadst, dct
+INV_TXFM_4X4_FN flipadst, adst
+INV_TXFM_4X4_FN flipadst, flipadst
+INV_TXFM_4X4_FN flipadst, identity
+
+cglobal iflipadst_4x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m0, [coeffq+16*0]
+    mova                 m1, [coeffq+16*1]
+    call m(iadst_4x4_internal_8bpc).main
+    punpcklwd            m2, m1, m0
+    punpckhwd            m1, m0
+    punpcklwd            m0, m1, m2            ;high: in3 ;low :in2
+    punpckhwd            m1, m2                ;high: in1 ;low: in0
+    jmp                tx2q
+
+.pass2:
+    call m(iadst_4x4_internal_8bpc).main
+
+.end:
+    pxor                 m2, m2
+    mova      [coeffq+16*0], m2
+    mova      [coeffq+16*1], m2
+
+.end2:
+    ITX4_END              3, 2, 1, 0
+
+INV_TXFM_4X4_FN identity, dct
+INV_TXFM_4X4_FN identity, adst
+INV_TXFM_4X4_FN identity, flipadst
+INV_TXFM_4X4_FN identity, identity
+
+cglobal iidentity_4x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m0, [coeffq+16*0]
+    mova                 m1, [coeffq+16*1]
+    mova                 m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m0, m3
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    punpckhwd            m2, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m0, m2            ;high: in3 ;low :in2
+    punpcklwd            m0, m2                ;high: in1 ;low: in0
+    jmp                tx2q
+
+.pass2:
+    mova                 m3, [o(pw_1697x8)]
+    pmulhrsw             m2, m3, m0
+    pmulhrsw             m3, m1
+    paddsw               m0, m2
+    paddsw               m1, m3
+    jmp m(iadst_4x4_internal_8bpc).end
+
+%macro IWHT4_1D_PACKED 0
+    punpckhqdq           m3, m0, m1            ;low: in1 high: in3
+    punpcklqdq           m0, m1                ;low: in0 high: in2
+    psubw                m2, m0, m3            ;low: in0 - in1 high: in2 - in3
+    paddw                m0, m3                ;low: in0 + in1 high: in2 + in3
+    punpckhqdq           m2, m2                ;t2 t2
+    punpcklqdq           m0, m0                ;t0 t0
+    psubw                m1, m0, m2
+    psraw                m1, 1                 ;t4 t4
+    psubw                m1, m3                ;low: t1/out2 high: t3/out1
+    psubw                m0, m1                ;high: out0
+    paddw                m2, m1                ;low: out3
+%endmacro
+
+INIT_XMM sse2
+cglobal inv_txfm_add_wht_wht_4x4_8bpc, 3, 3, 4, dst, stride, coeff
+    mova                 m0, [coeffq+16*0]
+    mova                 m1, [coeffq+16*1]
+    pxor                 m2, m2
+    mova      [coeffq+16*0], m2
+    mova      [coeffq+16*1], m2
+    psraw                m0, 2
+    psraw                m1, 2
+    IWHT4_1D_PACKED
+    punpckhwd            m0, m1
+    punpcklwd            m3, m1, m2
+    punpckhdq            m1, m0, m3
+    punpckldq            m0, m3
+    IWHT4_1D_PACKED
+    shufpd               m0, m2, 0x01
+    ITX4_END              0, 3, 2, 1, 0
+
+%macro IDCT8_1D_PACKED 0
+    mova                 m6, [o(pd_2048)]
+    punpckhwd            m4, m0, m3                 ;unpacked in1 in7
+    punpcklwd            m0, m2                     ;unpacked in0 in4
+    punpckhwd            m2, m1                     ;unpacked in5 in3
+    punpcklwd            m1, m3                     ;unpacked in2 in6
+    ITX_MUL2X_PACK        4, 3, 6,  799, 4017       ;low: t7a high: t4a
+    ITX_MUL2X_PACK        2, 3, 6, 3406, 2276       ;low: t6a high: t5a
+    ITX_MUL2X_PACK        1, 3, 6, 1567, 3784       ;low: t3  high: t2
+    psubsw               m3, m4, m2                 ;low: t6a high: t5a
+    paddsw               m4, m2                     ;low: t7  high: t4
+    pshufb               m3, [o(deint_shuf1)]
+    ITX_MUL2X_PACK        0, 2, 6, 2896, 2896       ;low: t0  high: t1
+    ITX_MUL2X_PACK        3, 2, 6, 2896, 2896       ;low: t6  high: t5
+    psubsw               m2, m0, m1                 ;low: tmp3 high: tmp2
+    paddsw               m0, m1                     ;low: tmp0 high: tmp1
+    punpcklqdq           m1, m4, m3                 ;low: t7   high: t6
+    punpckhqdq           m4, m3                     ;low: t4   high: t5
+    psubsw               m3, m0, m1                 ;low: out7 high: out6
+    paddsw               m0, m1                     ;low: out0 high: out1
+    paddsw               m1, m2, m4                 ;low: out3 high: out2
+    psubsw               m2, m4                     ;low: out4 high: out5
+%endmacro
+
+;dst1 = (src1 * coef1 - src2 * coef2 + rnd) >> 12
+;dst2 = (src1 * coef2 + src2 * coef1 + rnd) >> 12
+%macro ITX_MULSUB_2W 7-8 0 ; dst/src[1-2], tmp[1-2], rnd, coef[1-2], dst2_in_tmp1
+    punpckhwd           m%4, m%1, m%2
+    punpcklwd           m%1, m%2
+%if %7 < 8
+    pmaddwd             m%2, m%7, m%1
+    pmaddwd             m%3, m%7, m%4
+%else
+    mova                m%2, [o(pw_%7_%6)]
+%if %8
+    pmaddwd             m%3, m%1, m%2
+    pmaddwd             m%2, m%4
+%else
+    pmaddwd             m%3, m%4, m%2
+    pmaddwd             m%2, m%1
+%endif
+%endif
+    paddd               m%3, m%5
+    paddd               m%2, m%5
+    psrad               m%3, 12
+    psrad               m%2, 12
+%if %8
+    packssdw            m%3, m%2
+%else
+    packssdw            m%2, m%3                 ;dst2
+%endif
+%if %7 < 8
+    pmaddwd             m%4, m%6
+    pmaddwd             m%1, m%6
+%elif %8
+    mova                m%2, [o(pw_%6_m%7)]
+    pmaddwd             m%4, m%2
+    pmaddwd             m%1, m%2
+%else
+    mova                m%3, [o(pw_%6_m%7)]
+    pmaddwd             m%4, m%3
+    pmaddwd             m%1, m%3
+%endif
+    paddd               m%4, m%5
+    paddd               m%1, m%5
+    psrad               m%4, 12
+    psrad               m%1, 12
+    packssdw            m%1, m%4                 ;dst1
+%endmacro
+
+%macro IDCT4_1D 7 ; src[1-4], tmp[1-2], pd_2048
+    ITX_MULSUB_2W        %2, %4, %5, %6, %7, 1567, 3784, 1 ;t2, t3
+    ITX_MULSUB_2W        %1, %3, %4, %6, %7, 2896, 2896, 1 ;t1, t0
+    psubsw              m%3, m%1, m%2                      ;out2
+    paddsw              m%2, m%1                           ;out1
+    paddsw              m%1, m%5, m%4                      ;out0
+    psubsw              m%4, m%5                           ;out3
+%endmacro
+
+%macro WRITE_4X8 4 ;row[1-4]
+    WRITE_4X4             0, 1, 4, 5, 6, %1, %2, %3, %4
+    lea                dstq, [dstq+strideq*4]
+    WRITE_4X4             2, 3, 4, 5, 6, %1, %2, %3, %4
+%endmacro
+
+%macro INV_4X8 0
+    punpckhwd            m4, m2, m3
+    punpcklwd            m2, m3
+    punpckhwd            m3, m0, m1
+    punpcklwd            m0, m1
+    punpckhdq            m1, m0, m2                  ;low: in2 high: in3
+    punpckldq            m0, m2                      ;low: in0 high: in1
+    punpckldq            m2, m3, m4                  ;low: in4 high: in5
+    punpckhdq            m3, m4                      ;low: in6 high: in7
+%endmacro
+
+%macro INV_TXFM_4X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x8, 8
+%ifidn %1_%2, dct_dct
+    pshuflw              m0, [coeffq], q0000
+    punpcklqdq           m0, m0
+    mova                 m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1
+    mov           [coeffq], eobd
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, [o(pw_2048)]
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+    TAIL_CALL m(iadst_4x8_internal_8bpc).end3
+%endif
+%endmacro
+
+INIT_XMM ssse3
+INV_TXFM_4X8_FN dct, dct
+INV_TXFM_4X8_FN dct, adst
+INV_TXFM_4X8_FN dct, flipadst
+INV_TXFM_4X8_FN dct, identity
+
+cglobal idct_4x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [coeffq+16*0]
+    pmulhrsw             m1, m3, [coeffq+16*1]
+    pmulhrsw             m2, m3, [coeffq+16*2]
+    pmulhrsw             m3,     [coeffq+16*3]
+
+.pass1:
+    call m(idct_8x4_internal_8bpc).main
+    jmp m(iadst_4x8_internal_8bpc).pass1_end
+
+.pass2:
+    call .main
+    shufps               m1, m1, q1032
+    shufps               m3, m3, q1032
+    mova                 m4, [o(pw_2048)]
+    jmp m(iadst_4x8_internal_8bpc).end2
+
+ALIGN function_align
+cglobal_label .main
+    IDCT8_1D_PACKED
+    ret
+
+
+INV_TXFM_4X8_FN adst, dct
+INV_TXFM_4X8_FN adst, adst
+INV_TXFM_4X8_FN adst, flipadst
+INV_TXFM_4X8_FN adst, identity
+
+cglobal iadst_4x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [coeffq+16*0]
+    pmulhrsw             m1, m3, [coeffq+16*1]
+    pmulhrsw             m2, m3, [coeffq+16*2]
+    pmulhrsw             m3,     [coeffq+16*3]
+
+.pass1:
+    call m(iadst_8x4_internal_8bpc).main
+
+.pass1_end:
+    INV_4X8
+    jmp                tx2q
+
+.pass2:
+    shufps               m0, m0, q1032
+    shufps               m1, m1, q1032
+    call .main
+    mova                 m4, [o(pw_2048)]
+    pxor                 m5, m5
+    psubw                m5, m4
+
+.end:
+    punpcklqdq           m4, m5
+
+.end2:
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    pxor                 m5, m5
+    mova      [coeffq+16*0], m5
+    mova      [coeffq+16*1], m5
+    mova      [coeffq+16*2], m5
+    mova      [coeffq+16*3], m5
+
+.end3:
+    WRITE_4X8             0, 1, 2, 3
+    RET
+
+ALIGN function_align
+cglobal_label .main
+    mova                 m6, [o(pd_2048)]
+    punpckhwd            m4, m3, m0                ;unpacked in7 in0
+    punpckhwd            m5, m2, m1                ;unpacked in5 in2
+    punpcklwd            m1, m2                    ;unpacked in3 in4
+    punpcklwd            m0, m3                    ;unpacked in1 in6
+    ITX_MUL2X_PACK        4, 2, 6,  401, 4076      ;low:  t0a   high:  t1a
+    ITX_MUL2X_PACK        5, 2, 6, 1931, 3612      ;low:  t2a   high:  t3a
+    ITX_MUL2X_PACK        1, 2, 6, 3166, 2598      ;low:  t4a   high:  t5a
+    ITX_MUL2X_PACK        0, 2, 6, 3920, 1189      ;low:  t6a   high:  t7a
+
+    psubsw               m3, m4, m1                ;low:  t4    high:  t5
+    paddsw               m4, m1                    ;low:  t0    high:  t1
+    psubsw               m2, m5, m0                ;low:  t6    high:  t7
+    paddsw               m5, m0                    ;low:  t2    high:  t3
+
+    shufps               m1, m3, m2, q1032
+    punpckhwd            m2, m1
+    punpcklwd            m3, m1
+    ITX_MUL2X_PACK        3, 0, 6, 1567, 3784, 1   ;low:  t5a   high:  t4a
+    ITX_MUL2X_PACK        2, 0, 6, 3784, 1567      ;low:  t7a   high:  t6a
+
+    psubsw               m1, m4, m5                ;low:  t2    high:  t3
+    paddsw               m4, m5                    ;low:  out0  high: -out7
+    psubsw               m5, m3, m2                ;low:  t7    high:  t6
+    paddsw               m3, m2                    ;low:  out6  high: -out1
+    shufps               m0, m4, m3, q3210         ;low:  out0  high: -out1
+    shufps               m3, m4, q3210             ;low:  out6  high: -out7
+
+    mova                 m2, [o(pw_2896_m2896)]
+    mova                 m7, [o(pw_2896_2896)]
+    shufps               m4, m1, m5, q1032         ;low:  t3    high:  t7
+    shufps               m1, m5, q3210             ;low:  t2    high:  t6
+    punpcklwd            m5, m1, m4
+    punpckhwd            m1, m4
+    pmaddwd              m4, m2, m1                ;-out5
+    pmaddwd              m2, m5                    ; out4
+    pmaddwd              m1, m7                    ; out2
+    pmaddwd              m5, m7                    ;-out3
+    REPX      {paddd x, m6}, m4, m2, m1, m5
+    REPX      {psrad x, 12}, m4, m2, m1, m5
+    packssdw             m1, m5                    ;low:  out2  high: -out3
+    packssdw             m2, m4                    ;low:  out4  high: -out5
+    ret
+
+INV_TXFM_4X8_FN flipadst, dct
+INV_TXFM_4X8_FN flipadst, adst
+INV_TXFM_4X8_FN flipadst, flipadst
+INV_TXFM_4X8_FN flipadst, identity
+
+cglobal iflipadst_4x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [coeffq+16*0]
+    pmulhrsw             m1, m3, [coeffq+16*1]
+    pmulhrsw             m2, m3, [coeffq+16*2]
+    pmulhrsw             m3,     [coeffq+16*3]
+
+.pass1:
+    call m(iadst_8x4_internal_8bpc).main
+
+    punpcklwd            m4, m3, m2
+    punpckhwd            m3, m2
+    punpcklwd            m5, m1, m0
+    punpckhwd            m1, m0
+    punpckldq            m2, m3, m1                  ;low: in4 high: in5
+    punpckhdq            m3, m1                      ;low: in6 high: in7
+    punpckldq            m0, m4, m5                  ;low: in0 high: in1
+    punpckhdq            m1, m4, m5                  ;low: in2 high: in3
+    jmp                tx2q
+
+.pass2:
+    shufps               m0, m0, q1032
+    shufps               m1, m1, q1032
+    call m(iadst_4x8_internal_8bpc).main
+
+    mova                 m4, m0
+    mova                 m5, m1
+    pshufd               m0, m3, q1032
+    pshufd               m1, m2, q1032
+    pshufd               m2, m5, q1032
+    pshufd               m3, m4, q1032
+    mova                 m5, [o(pw_2048)]
+    pxor                 m4, m4
+    psubw                m4, m5
+    jmp m(iadst_4x8_internal_8bpc).end
+
+INV_TXFM_4X8_FN identity, dct
+INV_TXFM_4X8_FN identity, adst
+INV_TXFM_4X8_FN identity, flipadst
+INV_TXFM_4X8_FN identity, identity
+
+cglobal iidentity_4x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [coeffq+16*0]
+    pmulhrsw             m1, m3, [coeffq+16*1]
+    pmulhrsw             m2, m3, [coeffq+16*2]
+    pmulhrsw             m3,     [coeffq+16*3]
+
+.pass1:
+    mova                 m7, [o(pw_1697x8)]
+    pmulhrsw             m4, m7, m0
+    pmulhrsw             m5, m7, m1
+    pmulhrsw             m6, m7, m2
+    pmulhrsw             m7, m3
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    jmp m(iadst_4x8_internal_8bpc).pass1_end
+
+.pass2:
+    mova                 m4, [o(pw_4096)]
+    jmp m(iadst_4x8_internal_8bpc).end2
+
+
+%macro WRITE_8X2 5       ;coefs[1-2], tmp[1-3]
+    movq                 m%3, [dstq        ]
+    movq                 m%4, [dstq+strideq]
+    pxor                 m%5, m%5
+    punpcklbw            m%3, m%5                 ;extend byte to word
+    punpcklbw            m%4, m%5                 ;extend byte to word
+%ifnum %1
+    paddw                m%3, m%1
+%else
+    paddw                m%3, %1
+%endif
+%ifnum %2
+    paddw                m%4, m%2
+%else
+    paddw                m%4, %2
+%endif
+    packuswb             m%3, m%4
+    movq      [dstq        ], m%3
+    punpckhqdq           m%3, m%3
+    movq      [dstq+strideq], m%3
+%endmacro
+
+%macro WRITE_8X4 7      ;coefs[1-4], tmp[1-3]
+    WRITE_8X2             %1, %2, %5, %6, %7
+    lea                dstq, [dstq+strideq*2]
+    WRITE_8X2             %3, %4, %5, %6, %7
+%endmacro
+
+%macro INV_TXFM_8X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x4, 8
+%ifidn %1_%2, dct_dct
+    pshuflw              m0, [coeffq], q0000
+    punpcklqdq           m0, m0
+    mova                 m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, m1
+    mova                 m2, [o(pw_2048)]
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, m2
+    mova                 m1, m0
+    mova                 m2, m0
+    mova                 m3, m0
+    TAIL_CALL m(iadst_8x4_internal_8bpc).end2
+%endif
+%endmacro
+
+INV_TXFM_8X4_FN dct, dct
+INV_TXFM_8X4_FN dct, adst
+INV_TXFM_8X4_FN dct, flipadst
+INV_TXFM_8X4_FN dct, identity
+
+cglobal idct_8x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [coeffq+16*0]
+    pmulhrsw             m1, m3, [coeffq+16*1]
+    pmulhrsw             m2, m3, [coeffq+16*2]
+    pmulhrsw             m3,     [coeffq+16*3]
+
+    call m(idct_4x8_internal_8bpc).main
+
+    mova                 m4, [o(deint_shuf1)]
+    mova                 m5, [o(deint_shuf2)]
+    pshufb               m0, m4
+    pshufb               m1, m5
+    pshufb               m2, m4
+    pshufb               m3, m5
+    punpckhdq            m4, m0, m1
+    punpckldq            m0, m1
+    punpckhdq            m5, m2, m3
+    punpckldq            m2, m3
+    punpckhqdq           m1, m0, m2                      ;in1
+    punpcklqdq           m0, m2                          ;in0
+    punpckhqdq           m3, m4, m5                      ;in3
+    punpcklqdq           m2 ,m4, m5                      ;in2
+    jmp                tx2q
+
+.pass2:
+    call .main
+    jmp m(iadst_8x4_internal_8bpc).end
+
+ALIGN function_align
+cglobal_label .main
+    mova                 m6, [o(pd_2048)]
+    IDCT4_1D             0, 1, 2, 3, 4, 5, 6
+    ret
+
+INV_TXFM_8X4_FN adst, dct
+INV_TXFM_8X4_FN adst, adst
+INV_TXFM_8X4_FN adst, flipadst
+INV_TXFM_8X4_FN adst, identity
+
+cglobal iadst_8x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [coeffq+16*0]
+    pmulhrsw             m1, m3, [coeffq+16*1]
+    pmulhrsw             m2, m3, [coeffq+16*2]
+    pmulhrsw             m3,     [coeffq+16*3]
+
+    shufps               m0, m0, q1032
+    shufps               m1, m1, q1032
+    call m(iadst_4x8_internal_8bpc).main
+
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    pxor                 m5, m5
+    psubsw               m3, m5, m1
+    psubsw               m5, m4
+    punpckhdq            m4, m5, m3
+    punpckldq            m5, m3
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckhwd            m1, m0, m5      ;in1
+    punpcklwd            m0, m5          ;in0
+    punpcklwd            m2, m3, m4      ;in2
+    punpckhwd            m3, m4          ;in3
+    jmp              tx2q
+
+.pass2:
+    call .main
+
+.end:
+    mova                 m4, [o(pw_2048)]
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+
+.end2:
+    pxor                 m6, m6
+    mova      [coeffq+16*0], m6
+    mova      [coeffq+16*1], m6
+    mova      [coeffq+16*2], m6
+    mova      [coeffq+16*3], m6
+.end3:
+    WRITE_8X4             0, 1, 2, 3, 4, 5, 6
+    RET
+
+ALIGN function_align
+cglobal_label .main
+    punpckhwd            m6, m0, m2                    ;unpacked in0 in2
+    punpcklwd            m0, m2                        ;unpacked in0 in2
+    punpckhwd            m7, m1, m3                    ;unpacked in1 in3
+    punpcklwd            m1, m3                        ;unpacked in1 in3
+
+    mova                 m2, [o(pw_3344_m3344)]
+    mova                 m4, [o(pw_0_3344)]
+    pmaddwd              m3, m2, m6                    ;3344 * in0 - 3344 * in2
+    pmaddwd              m5, m4, m7                    ;3344 * in3
+    pmaddwd              m2, m0
+    pmaddwd              m4, m1
+    paddd                m3, m5
+    paddd                m2, m4
+    mova                 m4, [o(pd_2048)]
+    paddd                m3, m4                        ;t2 + 2048
+    paddd                m2, m4
+    psrad                m3, 12
+    psrad                m2, 12
+    packssdw             m2, m3                        ;out2
+
+    pmaddwd              m4, m0, [o(pw_1321_3803)]     ;1321 * in0 + 3803 * in2
+    pmaddwd              m0, [o(pw_2482_m1321)]        ;2482 * in0 - 1321 * in2
+    pmaddwd              m3, m1, [o(pw_3344_2482)]     ;3344 * in1 + 2482 * in3
+    pmaddwd              m5, m1, [o(pw_3344_m3803)]    ;3344 * in1 - 3803 * in3
+    paddd                m3, m4                        ;t0 + t3
+
+    pmaddwd              m1, [o(pw_m6688_m3803)]       ;-2 * 3344 * in1 - 3803 * in3
+    mova                 m4, [o(pd_2048)]
+    paddd                m0, m4
+    paddd                m4, m3                        ;t0 + t3 + 2048
+    paddd                m5, m0                        ;t1 + t3 + 2048
+    paddd                m3, m0
+    paddd                m3, m1                        ;t0 + t1 - t3 + 2048
+
+    psrad                m4, 12                        ;out0
+    psrad                m5, 12                        ;out1
+    psrad                m3, 12                        ;out3
+    packssdw             m0, m4, m5                    ;low: out0  high: out1
+
+    pmaddwd              m4, m6, [o(pw_1321_3803)]     ;1321 * in0 + 3803 * in2
+    pmaddwd              m6, [o(pw_2482_m1321)]        ;2482 * in0 - 1321 * in2
+    pmaddwd              m1, m7, [o(pw_3344_2482)]     ;3344 * in1 + 2482 * in3
+    pmaddwd              m5, m7, [o(pw_3344_m3803)]    ;3344 * in1 - 3803 * in3
+    paddd                m1, m4                        ;t0 + t3
+    pmaddwd              m7, [o(pw_m6688_m3803)]       ;-2 * 3344 * in1 - 3803 * in3
+
+    mova                 m4, [o(pd_2048)]
+    paddd                m6, m4
+    paddd                m4, m1                        ;t0 + t3 + 2048
+    paddd                m5, m6                        ;t1 + t3 + 2048
+    paddd                m1, m6
+    paddd                m1, m7                        ;t0 + t1 - t3 + 2048
+
+    psrad                m4, 12                        ;out0
+    psrad                m5, 12                        ;out1
+    psrad                m1, 12                        ;out3
+    packssdw             m3, m1                        ;out3
+    packssdw             m4, m5                        ;low: out0  high: out1
+
+    punpckhqdq           m1, m0, m4                    ;out1
+    punpcklqdq           m0, m4                        ;out0
+    ret
+
+INV_TXFM_8X4_FN flipadst, dct
+INV_TXFM_8X4_FN flipadst, adst
+INV_TXFM_8X4_FN flipadst, flipadst
+INV_TXFM_8X4_FN flipadst, identity
+
+cglobal iflipadst_8x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [coeffq+16*0]
+    pmulhrsw             m1, m3, [coeffq+16*1]
+    pmulhrsw             m2, m3, [coeffq+16*2]
+    pmulhrsw             m3,     [coeffq+16*3]
+
+    shufps               m0, m0, q1032
+    shufps               m1, m1, q1032
+    call m(iadst_4x8_internal_8bpc).main
+
+    punpckhwd            m5, m3, m2
+    punpcklwd            m3, m2
+    punpckhwd            m2, m1, m0
+    punpcklwd            m1, m0
+
+    pxor                 m0, m0
+    psubsw               m4, m0, m2
+    psubsw               m0, m5
+    punpckhdq            m2, m0, m4
+    punpckldq            m0, m4
+    punpckhdq            m4, m3, m1
+    punpckldq            m3, m1
+    punpckhwd            m1, m0, m3      ;in1
+    punpcklwd            m0, m3          ;in0
+    punpckhwd            m3, m2, m4      ;in3
+    punpcklwd            m2, m4          ;in2
+    jmp                  tx2q
+
+.pass2:
+    call m(iadst_8x4_internal_8bpc).main
+    mova                 m4, m0
+    mova                 m5, m1
+    mova                 m0, m3
+    mova                 m1, m2
+    mova                 m2, m5
+    mova                 m3, m4
+    jmp m(iadst_8x4_internal_8bpc).end
+
+INV_TXFM_8X4_FN identity, dct
+INV_TXFM_8X4_FN identity, adst
+INV_TXFM_8X4_FN identity, flipadst
+INV_TXFM_8X4_FN identity, identity
+
+cglobal iidentity_8x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [coeffq+16*0]
+    pmulhrsw             m1, m3, [coeffq+16*1]
+    pmulhrsw             m2, m3, [coeffq+16*2]
+    pmulhrsw             m3,     [coeffq+16*3]
+    paddsw               m0, m0
+    paddsw               m1, m1
+    paddsw               m2, m2
+    paddsw               m3, m3
+
+    punpckhwd            m4, m0, m1
+    punpcklwd            m0, m1
+    punpckhwd            m1, m2, m3
+    punpcklwd            m2, m3
+    punpckhdq            m5, m4, m1
+    punpckldq            m4, m1
+    punpckhdq            m3, m0, m2
+    punpckldq            m0, m2
+    punpckhwd            m1, m0, m4      ;in1
+    punpcklwd            m0, m4          ;in0
+    punpcklwd            m2, m3, m5      ;in2
+    punpckhwd            m3, m5          ;in3
+    jmp                tx2q
+
+.pass2:
+    mova                 m7, [o(pw_1697x8)]
+    pmulhrsw             m4, m7, m0
+    pmulhrsw             m5, m7, m1
+    pmulhrsw             m6, m7, m2
+    pmulhrsw             m7, m3
+    paddsw               m0, m4
+    paddsw               m1, m5
+    paddsw               m2, m6
+    paddsw               m3, m7
+    jmp m(iadst_8x4_internal_8bpc).end
+
+%macro INV_TXFM_8X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x8, 8, 16*4
+%ifidn %1_%2, dct_dct
+    pshuflw              m0, [coeffq], q0000
+    punpcklwd            m0, m0
+    mova                 m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1
+    mova                 m2, [o(pw_16384)]
+    mov            [coeffq], eobd
+    pmulhrsw             m0, m2
+    psrlw                m2, 3
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, m2
+.end:
+    mov                 r3d, 2
+    lea                tx2q, [o(m(inv_txfm_add_dct_dct_8x8_8bpc).end3)]
+.loop:
+    WRITE_8X4             0, 0, 0, 0, 1, 2, 3
+    lea                dstq, [dstq+strideq*2]
+    dec                 r3d
+    jg .loop
+    jmp                tx2q
+.end3:
+    RET
+%endif
+%endmacro
+
+%macro LOAD_8ROWS 2-3 0 ; src, stride, is_rect2
+%if %3
+    mova                 m7, [o(pw_2896x8)]
+    pmulhrsw             m0, m7, [%1+%2*0]
+    pmulhrsw             m1, m7, [%1+%2*1]
+    pmulhrsw             m2, m7, [%1+%2*2]
+    pmulhrsw             m3, m7, [%1+%2*3]
+    pmulhrsw             m4, m7, [%1+%2*4]
+    pmulhrsw             m5, m7, [%1+%2*5]
+    pmulhrsw             m6, m7, [%1+%2*6]
+    pmulhrsw             m7, [%1+%2*7]
+%else
+    mova                 m0, [%1+%2*0]
+    mova                 m1, [%1+%2*1]
+    mova                 m2, [%1+%2*2]
+    mova                 m3, [%1+%2*3]
+    mova                 m4, [%1+%2*4]
+    mova                 m5, [%1+%2*5]
+    mova                 m6, [%1+%2*6]
+    mova                 m7, [%1+%2*7]
+%endif
+%endmacro
+
+%macro IDCT8_1D_ODDHALF 7 ; src[1-4], tmp[1-2], pd_2048
+    ITX_MULSUB_2W         %1, %4, %5, %6, %7,  799, 4017    ;t4a, t7a
+    ITX_MULSUB_2W         %3, %2, %5, %6, %7, 3406, 2276, 1 ;t5a, t6a
+    psubsw               m%2, m%4, m%5                      ;t6a
+    paddsw               m%4, m%5                           ;t7
+    psubsw               m%5, m%1, m%3                      ;t5a
+    paddsw               m%1, m%3                           ;t4
+    ITX_MULSUB_2W         %2, %5, %3, %6, %7, 2896, 2896, 1 ;t5, t6
+%endmacro
+
+INV_TXFM_8X8_FN dct, dct
+INV_TXFM_8X8_FN dct, adst
+INV_TXFM_8X8_FN dct, flipadst
+INV_TXFM_8X8_FN dct, identity
+
+cglobal idct_8x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS          coeffq, 16
+
+.pass1:
+    call .main
+
+.pass1_end:
+    mova                    m7, [o(pw_16384)]
+
+.pass1_end1:
+    REPX      {pmulhrsw x, m7}, m0, m2, m4, m6
+    mova    [rsp+gprsize+16*1], m6
+
+.pass1_end2:
+    REPX      {pmulhrsw x, m7}, m1, m3, m5
+    pmulhrsw                m7, [rsp+gprsize+16*0]
+
+cglobal_label .pass1_end3
+    punpcklwd               m6, m1, m5             ;10 50 11 51 12 52 13 53
+    punpckhwd               m1, m5                 ;14 54 15 55 16 56 17 57
+    punpckhwd               m5, m0, m4             ;04 44 05 45 06 46 07 47
+    punpcklwd               m0, m4                 ;00 40 01 41 02 42 03 43
+    punpckhwd               m4, m3, m7             ;34 74 35 75 36 76 37 77
+    punpcklwd               m3, m7                 ;30 70 31 71 32 72 33 73
+    punpckhwd               m7, m1, m4             ;16 36 56 76 17 37 57 77
+    punpcklwd               m1, m4                 ;14 34 54 74 15 35 55 75
+    punpckhwd               m4, m6, m3             ;12 32 52 72 13 33 53 73
+    punpcklwd               m6, m3                 ;10 30 50 70 11 31 51 71
+    mova    [rsp+gprsize+16*2], m6
+    mova                    m6, [rsp+gprsize+16*1]
+    punpckhwd               m3, m2, m6             ;24 64 25 65 26 66 27 67
+    punpcklwd               m2, m6                 ;20 60 21 61 22 62 23 63
+    punpckhwd               m6, m5, m3             ;06 26 46 66 07 27 47 67
+    punpcklwd               m5, m3                 ;04 24 44 64 05 25 45 65
+    punpckhwd               m3, m0, m2             ;02 22 42 62 03 23 43 63
+    punpcklwd               m0, m2                 ;00 20 40 60 01 21 41 61
+
+    punpckhwd               m2, m6, m7             ;07 17 27 37 47 57 67 77
+    punpcklwd               m6, m7                 ;06 16 26 36 46 56 66 76
+    mova    [rsp+gprsize+16*0], m2
+    punpcklwd               m2, m3, m4             ;02 12 22 32 42 52 62 72
+    punpckhwd               m3, m4                 ;03 13 23 33 43 53 63 73
+    punpcklwd               m4, m5, m1             ;04 14 24 34 44 54 64 74
+    punpckhwd               m5, m1                 ;05 15 25 35 45 55 65 75
+    mova                    m7, [rsp+gprsize+16*2]
+    punpckhwd               m1, m0, m7             ;01 11 21 31 41 51 61 71
+    punpcklwd               m0, m7                 ;00 10 20 30 40 50 60 70
+    mova                    m7, [rsp+gprsize+16*0]
+    jmp                   tx2q
+
+.pass2:
+    lea                   tx2q, [o(m(idct_8x8_internal_8bpc).end4)]
+
+.pass2_main:
+    call .main
+
+.end:
+    mova                    m7, [o(pw_2048)]
+    REPX      {pmulhrsw x, m7}, m0, m2, m4, m6
+    mova    [rsp+gprsize+16*1], m6
+
+.end2:
+    REPX      {pmulhrsw x, m7}, m1, m3, m5
+    pmulhrsw                m7, [rsp+gprsize+16*0]
+    mova    [rsp+gprsize+16*2], m5
+    mova    [rsp+gprsize+16*0], m7
+
+.end3:
+    WRITE_8X4                0, 1, 2, 3, 5, 6, 7
+    lea                   dstq, [dstq+strideq*2]
+    WRITE_8X4                4, [rsp+gprsize+16*2], [rsp+gprsize+16*1], [rsp+gprsize+16*0], 5, 6, 7
+    jmp                   tx2q
+
+.end4:
+    pxor                    m7, m7
+    REPX   {mova [coeffq+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7
+    ret
+
+ALIGN function_align
+cglobal_label .main
+    mova  [rsp+gprsize*2+16*0], m7
+    mova  [rsp+gprsize*2+16*1], m3
+    mova  [rsp+gprsize*2+16*2], m1
+    mova                    m7, [o(pd_2048)]
+    IDCT4_1D                 0, 2, 4, 6, 1, 3, 7
+    mova                    m3, [rsp+gprsize*2+16*2]
+    mova  [rsp+gprsize*2+16*2], m2
+    mova                    m2, [rsp+gprsize*2+16*1]
+    mova  [rsp+gprsize*2+16*1], m4
+    mova                    m4, [rsp+gprsize*2+16*0]
+    mova  [rsp+gprsize*2+16*0], m6
+    IDCT8_1D_ODDHALF         3, 2, 5, 4, 1, 6, 7
+    mova                    m6, [rsp+gprsize*2+16*0]
+    psubsw                  m7, m0, m4                    ;out7
+    paddsw                  m0, m4                        ;out0
+    mova  [rsp+gprsize*2+16*0], m7
+    mova                    m1, [rsp+gprsize*2+16*2]
+    psubsw                  m4, m6, m3                    ;out4
+    paddsw                  m3, m6                        ;out3
+    mova                    m7, [rsp+gprsize*2+16*1]
+    psubsw                  m6, m1, m5                    ;out6
+    paddsw                  m1, m5                        ;out1
+    psubsw                  m5, m7, m2                    ;out5
+    paddsw                  m2, m7                        ;out2
+    ret
+
+
+INV_TXFM_8X8_FN adst, dct
+INV_TXFM_8X8_FN adst, adst
+INV_TXFM_8X8_FN adst, flipadst
+INV_TXFM_8X8_FN adst, identity
+
+cglobal iadst_8x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS          coeffq, 16
+
+.pass1:
+    call .main
+    call .main_pass1_end
+
+.pass1_end:
+    mova                    m7, [o(pw_16384)]
+
+.pass1_end1:
+    REPX      {pmulhrsw x, m7}, m0, m2, m4, m6
+    mova    [rsp+gprsize+16*1], m6
+    pxor                    m6, m6
+    psubw                   m6, m7
+    mova                    m7, m6
+    jmp m(idct_8x8_internal_8bpc).pass1_end2
+
+ALIGN function_align
+.pass2:
+    lea                   tx2q, [o(m(idct_8x8_internal_8bpc).end4)]
+
+.pass2_main:
+    call .main
+    call .main_pass2_end
+
+.end:
+    mova                    m7, [o(pw_2048)]
+    REPX      {pmulhrsw x, m7}, m0, m2, m4, m6
+    mova    [rsp+gprsize+16*1], m6
+    pxor                    m6, m6
+    psubw                   m6, m7
+    mova                    m7, m6
+    jmp m(idct_8x8_internal_8bpc).end2
+
+ALIGN function_align
+cglobal_label .main
+    mova  [rsp+gprsize*2+16*0], m7
+    mova  [rsp+gprsize*2+16*1], m3
+    mova  [rsp+gprsize*2+16*2], m4
+    mova                    m7, [o(pd_2048)]
+    ITX_MULSUB_2W            5, 2, 3, 4, 7, 1931, 3612    ;t3a, t2a
+    ITX_MULSUB_2W            1, 6, 3, 4, 7, 3920, 1189    ;t7a, t6a
+    paddsw                  m3, m2, m6                    ;t2
+    psubsw                  m2, m6                        ;t6
+    paddsw                  m4, m5, m1                    ;t3
+    psubsw                  m5, m1                        ;t7
+    ITX_MULSUB_2W            5, 2, 1, 6, 7, 3784, 1567    ;t6a, t7a
+
+    mova                    m6, [rsp+gprsize*2+16*2]
+    mova  [rsp+gprsize*2+16*2], m5
+    mova                    m1, [rsp+gprsize*2+16*1]
+    mova  [rsp+gprsize*2+16*1], m2
+    mova                    m5, [rsp+gprsize*2+16*0]
+    mova  [rsp+gprsize*2+16*0], m3
+    ITX_MULSUB_2W            5, 0, 2, 3, 7,  401, 4076    ;t1a, t0a
+    ITX_MULSUB_2W            1, 6, 2, 3, 7, 3166, 2598    ;t5a, t4a
+    psubsw                  m2, m0, m6                    ;t4
+    paddsw                  m0, m6                        ;t0
+    paddsw                  m3, m5, m1                    ;t1
+    psubsw                  m5, m1                        ;t5
+    ITX_MULSUB_2W            2, 5, 1, 6, 7, 1567, 3784    ;t5a, t4a
+
+    mova                    m7, [rsp+gprsize*2+16*0]
+    paddsw                  m1, m3, m4                    ;-out7
+    psubsw                  m3, m4                        ;t3
+    mova  [rsp+gprsize*2+16*0], m1
+    psubsw                  m4, m0, m7                    ;t2
+    paddsw                  m0, m7                        ;out0
+    mova                    m6, [rsp+gprsize*2+16*2]
+    mova                    m7, [rsp+gprsize*2+16*1]
+    paddsw                  m1, m5, m6                    ;-out1
+    psubsw                  m5, m6                        ;t6
+    paddsw                  m6, m2, m7                    ;out6
+    psubsw                  m2, m7                        ;t7
+    ret
+ALIGN function_align
+.main_pass1_end:
+    mova  [rsp+gprsize*2+16*1], m1
+    mova  [rsp+gprsize*2+16*2], m6
+    punpckhwd               m1, m4, m3
+    punpcklwd               m4, m3
+    punpckhwd               m7, m5, m2
+    punpcklwd               m5, m2
+    mova                    m2, [o(pw_2896_2896)]
+    mova                    m6, [o(pd_2048)]
+    pmaddwd                 m3, m2, m7
+    pmaddwd                 m2, m5
+    paddd                   m3, m6
+    paddd                   m2, m6
+    psrad                   m3, 12
+    psrad                   m2, 12
+    packssdw                m2, m3                        ;out2
+    mova                    m3, [o(pw_2896_m2896)]
+    pmaddwd                 m7, m3
+    pmaddwd                 m5, m3
+    paddd                   m7, m6
+    paddd                   m5, m6
+    psrad                   m7, 12
+    psrad                   m5, 12
+    packssdw                m5, m7                        ;-out5
+    mova                    m3, [o(pw_2896_2896)]
+    pmaddwd                 m7, m3, m1
+    pmaddwd                 m3, m4
+    paddd                   m7, m6
+    paddd                   m3, m6
+    psrad                   m7, 12
+    psrad                   m3, 12
+    packssdw                m3, m7                        ;-out3
+    mova                    m7, [o(pw_2896_m2896)]
+    pmaddwd                 m1, m7
+    pmaddwd                 m4, m7
+    paddd                   m1, m6
+    paddd                   m4, m6
+    psrad                   m1, 12
+    psrad                   m4, 12
+    packssdw                m4, m1                        ;-out5
+    mova                    m1, [rsp+gprsize*2+16*1]
+    mova                    m6, [rsp+gprsize*2+16*2]
+    ret
+ALIGN function_align
+cglobal_label .main_pass2_end
+    paddsw                  m7, m4, m3                    ;t2 + t3
+    psubsw                  m4, m3                        ;t2 - t3
+    paddsw                  m3, m5, m2                    ;t6 + t7
+    psubsw                  m5, m2                        ;t6 - t7
+    mova                    m2, [o(pw_2896x8)]
+    pmulhrsw                m4, m2                        ;out4
+    pmulhrsw                m5, m2                        ;-out5
+    pmulhrsw                m7, m2                        ;-out3
+    pmulhrsw                m2, m3                        ;out2
+    mova                    m3, m7
+    ret
+
+INV_TXFM_8X8_FN flipadst, dct
+INV_TXFM_8X8_FN flipadst, adst
+INV_TXFM_8X8_FN flipadst, flipadst
+INV_TXFM_8X8_FN flipadst, identity
+
+cglobal iflipadst_8x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS          coeffq, 16
+
+.pass1:
+    call m(iadst_8x8_internal_8bpc).main
+    call m(iadst_8x8_internal_8bpc).main_pass1_end
+
+.pass1_end:
+    mova                    m7, [o(pw_m16384)]
+
+.pass1_end1:
+    pmulhrsw                m1, m7
+    mova    [rsp+gprsize+16*1], m1
+    mova                    m1, m6
+    mova                    m6, m2
+    pmulhrsw                m2, m5, m7
+    mova                    m5, m6
+    mova                    m6, m4
+    pmulhrsw                m4, m3, m7
+    mova                    m3, m6
+    mova                    m6, m0
+    mova                    m0, m7
+    pxor                    m7, m7
+    psubw                   m7, m0
+    pmulhrsw                m0, [rsp+gprsize+16*0]
+    REPX      {pmulhrsw x, m7}, m1, m3, m5
+    pmulhrsw                m7, m6
+    jmp m(idct_8x8_internal_8bpc).pass1_end3
+
+ALIGN function_align
+.pass2:
+    lea                   tx2q, [o(m(idct_8x8_internal_8bpc).end4)]
+
+.pass2_main:
+    call m(iadst_8x8_internal_8bpc).main
+    call m(iadst_8x8_internal_8bpc).main_pass2_end
+
+.end:
+    mova                    m7, [o(pw_2048)]
+    REPX      {pmulhrsw x, m7}, m0, m2, m4, m6
+    mova    [rsp+gprsize+16*2], m2
+    mova                    m2, m0
+    pxor                    m0, m0
+    psubw                   m0, m7
+    mova                    m7, m2
+    pmulhrsw                m1, m0
+    pmulhrsw                m2, m5, m0
+    mova    [rsp+gprsize+16*1], m1
+    mova                    m5, m4
+    mova                    m1, m6
+    pmulhrsw                m4, m3, m0
+    pmulhrsw                m0, [rsp+gprsize+16*0]
+    mova                    m3, m5
+    mova    [rsp+gprsize+16*0], m7
+    jmp m(idct_8x8_internal_8bpc).end3
+
+INV_TXFM_8X8_FN identity, dct
+INV_TXFM_8X8_FN identity, adst
+INV_TXFM_8X8_FN identity, flipadst
+INV_TXFM_8X8_FN identity, identity
+
+cglobal iidentity_8x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS          coeffq, 16
+    mova    [rsp+gprsize+16*1], m6
+    jmp   m(idct_8x8_internal_8bpc).pass1_end3
+
+ALIGN function_align
+.pass2:
+    lea                   tx2q, [o(m(idct_8x8_internal_8bpc).end4)]
+
+.end:
+    pmulhrsw                m7, [o(pw_4096)]
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_4096)]
+    REPX      {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    mova    [rsp+gprsize+16*2], m5
+    mova    [rsp+gprsize+16*1], m6
+    jmp m(idct_8x8_internal_8bpc).end3
+
+
+%macro INV_TXFM_4X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 4x16, 8
+%ifidn %1_%2, dct_dct
+    pshuflw               m0, [coeffq], q0000
+    punpcklwd             m0, m0
+    mova                  m1, [o(pw_2896x8)]
+    pmulhrsw              m0, m1
+    mov             [coeffq], eobd
+    pmulhrsw              m0, [o(pw_16384)]
+    pmulhrsw              m0, m1
+    pmulhrsw              m0, [o(pw_2048)]
+.end:
+    WRITE_4X4             0, 0, 1, 2, 3, 0, 1, 2, 3
+    lea                dstq, [dstq+strideq*4]
+    WRITE_4X4             0, 0, 1, 2, 3, 0, 1, 2, 3
+    lea                dstq, [dstq+strideq*4]
+    WRITE_4X4             0, 0, 1, 2, 3, 0, 1, 2, 3
+    lea                dstq, [dstq+strideq*4]
+    WRITE_4X4             0, 0, 1, 2, 3, 0, 1, 2, 3
+    RET
+%endif
+%endmacro
+
+INV_TXFM_4X16_FN dct, dct
+INV_TXFM_4X16_FN dct, adst
+INV_TXFM_4X16_FN dct, flipadst
+INV_TXFM_4X16_FN dct, identity
+
+cglobal idct_4x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    lea                  r3, [o(m(idct_4x8_internal_8bpc).pass1)]
+
+.pass1:
+    mova                 m0, [coeffq+16*1]
+    mova                 m1, [coeffq+16*3]
+    mova                 m2, [coeffq+16*5]
+    mova                 m3, [coeffq+16*7]
+    push               tx2q
+    lea                tx2q, [o(m(idct_4x16_internal_8bpc).pass1_2)]
+    jmp                  r3
+
+.pass1_2:
+    mova      [coeffq+16*1], m0
+    mova      [coeffq+16*3], m1
+    mova      [coeffq+16*5], m2
+    mova      [coeffq+16*7], m3
+    mova                 m0, [coeffq+16*0]
+    mova                 m1, [coeffq+16*2]
+    mova                 m2, [coeffq+16*4]
+    mova                 m3, [coeffq+16*6]
+    lea                tx2q, [o(m(idct_4x16_internal_8bpc).pass1_end)]
+    jmp                  r3
+
+.pass1_end:
+    pop                tx2q
+
+    mova                 m4, [coeffq+16*1]
+    mova                 m5, [coeffq+16*3]
+    mova                 m6, [coeffq+16*5]
+    mova                 m7, [o(pw_16384)]
+    REPX   {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+
+    pmulhrsw             m7, [coeffq+16*7]
+    mova       [coeffq+16*7], m7
+    jmp                tx2q
+
+.pass2:
+    call m(idct_16x4_internal_8bpc).main
+
+.end:
+    mova                  m7, [o(pw_2048)]
+    REPX    {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulhrsw              m7, [coeffq+16*7]
+    mova       [coeffq+16*4], m4
+
+.end1:
+    mova       [coeffq+16*5], m5
+    mova       [coeffq+16*6], m6
+    mov                   r3, coeffq
+    WRITE_4X8              0, 1, 3, 2
+
+    mova                  m0, [r3+16*4]
+    mova                  m1, [r3+16*5]
+    mova                  m2, [r3+16*6]
+    mova                  m3, m7
+    lea                 dstq, [dstq+strideq*4]
+    WRITE_4X8              0, 1, 3, 2
+
+.end2:
+    pxor                  m7, m7
+    REPX     {mova [r3+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7
+    ret
+
+INV_TXFM_4X16_FN adst, dct
+INV_TXFM_4X16_FN adst, adst
+INV_TXFM_4X16_FN adst, flipadst
+INV_TXFM_4X16_FN adst, identity
+
+cglobal iadst_4x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    lea                   r3, [o(m(iadst_4x8_internal_8bpc).pass1)]
+    jmp   m(idct_4x16_internal_8bpc).pass1
+
+.pass2:
+    call m(iadst_16x4_internal_8bpc).main
+    call m(iadst_16x4_internal_8bpc).main_pass2_end
+
+    punpcklqdq            m6, m5, m4                ;low: -out5  high: -out7
+    punpckhqdq            m4, m5                    ;low:  out8  high:  out10
+    punpcklqdq            m5, m7, m2                ;low:  out4  high:  out6
+    punpckhqdq            m2, m7                    ;low: -out9  high: -out11
+    mova       [coeffq+16*4], m2
+    mova       [coeffq+16*5], m6
+    mova                  m2, [coeffq+16*6]
+    mova                  m6, [coeffq+16*7]
+    punpckhqdq            m1, m6, m0                ;low: -out13 high: -out15
+    punpcklqdq            m0, m6                    ;low:  out0  high:  out2
+    punpckhqdq            m6, m3, m2                ;low:  out12 high:  out14
+    punpcklqdq            m2, m3                    ;low: -out1  high: -out3
+
+    mova                  m7, [o(pw_2048)]
+
+.end1:
+    REPX    {pmulhrsw x, m7}, m0, m5, m4, m6
+    pxor                  m3, m3
+    psubw                 m3, m7
+    mova                  m7, [coeffq+16*4]
+    REPX    {pmulhrsw x, m3}, m2, m7, m1
+    pmulhrsw              m3, [coeffq+16*5]
+    mova       [coeffq+16*7], m5
+
+    punpckhqdq            m5, m4, m7                ;low:  out10 high:  out11
+    punpcklqdq            m4, m7                    ;low:  out8  high:  out9
+    punpckhqdq            m7, m6, m1                ;low:  out14 high:  out15
+    punpcklqdq            m6, m1                    ;low:  out12 high:  out13
+    punpckhqdq            m1, m0, m2                ;low:  out2  high:  out3
+    punpcklqdq            m0, m2                    ;low:  out0  high:  out1
+    mova       [coeffq+16*4], m4
+    mova                  m4, [coeffq+16*7]
+    punpcklqdq            m2, m4, m3                ;low:  out4  high:  out5
+    punpckhqdq            m4, m3                    ;low:  out6  high:  out7
+    mova                  m3, m4
+
+.end2:
+    mova       [coeffq+16*5], m5
+    mova       [coeffq+16*6], m6
+    mov                   r3, coeffq
+    WRITE_4X8              0, 1, 2, 3
+
+    mova                  m0, [r3+16*4]
+    mova                  m1, [r3+16*5]
+    mova                  m2, [r3+16*6]
+    mova                  m3, m7
+    lea                 dstq, [dstq+strideq*4]
+    WRITE_4X8              0, 1, 2, 3
+
+.end3:
+    pxor                  m7, m7
+    REPX     {mova [r3+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7
+    ret
+
+
+INV_TXFM_4X16_FN flipadst, dct
+INV_TXFM_4X16_FN flipadst, adst
+INV_TXFM_4X16_FN flipadst, flipadst
+INV_TXFM_4X16_FN flipadst, identity
+
+cglobal iflipadst_4x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    lea                   r3, [o(m(iflipadst_4x8_internal_8bpc).pass1)]
+    jmp   m(idct_4x16_internal_8bpc).pass1
+
+.pass2:
+    call m(iadst_16x4_internal_8bpc).main
+    call m(iadst_16x4_internal_8bpc).main_pass2_end
+
+    punpckhqdq            m6, m5, m4                ;low:  out5  high:  out7
+    punpcklqdq            m4, m5                    ;low: -out8  high: -out10
+    punpckhqdq            m5, m7, m2                ;low: -out4  high: -out6
+    punpcklqdq            m2, m7                    ;low:  out9  high:  out11
+    mova       [coeffq+16*4], m2
+    mova       [coeffq+16*5], m6
+    mova                  m2, [coeffq+16*6]
+    mova                  m6, [coeffq+16*7]
+    punpcklqdq            m1, m6, m0                ;low:  out13 high:  out15
+    punpckhqdq            m0, m6                    ;low: -out0  high: -out2
+    punpcklqdq            m6, m3, m2                ;low: -out12 high: -out14
+    punpckhqdq            m2, m3                    ;low:  out1  high:  out3
+
+    mova                  m7, [o(pw_m2048)]
+    jmp   m(iadst_4x16_internal_8bpc).end1
+
+
+INV_TXFM_4X16_FN identity, dct
+INV_TXFM_4X16_FN identity, adst
+INV_TXFM_4X16_FN identity, flipadst
+INV_TXFM_4X16_FN identity, identity
+
+%macro IDTX16 3-4 ; src/dst, tmp, pw_1697x16, [pw_16394]
+    pmulhrsw            m%2, m%3, m%1
+%if %0 == 4 ; if downshifting by 1
+    pmulhrsw            m%2, m%4
+%else
+    paddsw              m%1, m%1
+%endif
+    paddsw              m%1, m%2
+%endmacro
+
+cglobal iidentity_4x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                  m0, [coeffq+16*1]
+    mova                  m6, [o(pw_1697x8)]
+    mova                  m1, [coeffq+16*3]
+    mova                  m2, [coeffq+16*5]
+    mova                  m3, [coeffq+16*7]
+    pcmpeqw               m7, m7
+    mov                   r3, tx2q
+    lea                 tx2q, [o(.pass1_2)]
+.pass1:
+    pmulhrsw              m4, m6, m0
+    pmulhrsw              m5, m6, m1
+    pavgw                 m4, m0
+    pcmpeqw               m0, m7
+    pavgw                 m5, m1
+    pcmpeqw               m1, m7
+    pandn                 m0, m4
+    pmulhrsw              m4, m6, m2
+    pandn                 m1, m5
+    pmulhrsw              m5, m6, m3
+    pavgw                 m4, m2
+    pcmpeqw               m2, m7
+    pavgw                 m5, m3
+    pcmpeqw               m3, m7
+    pandn                 m2, m4
+    pandn                 m3, m5
+    jmp m(iadst_4x8_internal_8bpc).pass1_end
+.pass1_2:
+    mova       [coeffq+16*1], m0
+    mova       [coeffq+16*3], m1
+    mova       [coeffq+16*5], m2
+    mova       [coeffq+16*7], m3
+    mova                  m0, [coeffq+16*0]
+    mova                  m1, [coeffq+16*2]
+    mova                  m2, [coeffq+16*4]
+    mova                  m3, [coeffq+16*6]
+    lea                 tx2q, [o(.pass1_end)]
+    jmp .pass1
+.pass1_end:
+    mova                  m4, [coeffq+16*1]
+    mova                  m5, [coeffq+16*3]
+    mova                  m6, [coeffq+16*5]
+    jmp                   r3
+.pass2:
+    mova                  m7, [o(pw_1697x16)]
+    mova       [coeffq+16*6], m6
+    REPX    {IDTX16 x, 6, 7}, 0, 1, 2, 3, 4, 5
+    mova                  m6, [coeffq+16*7]
+    IDTX16                 6, 7, 7
+    mova       [coeffq+16*7], m6
+    mova                  m6, [coeffq+16*6]
+    pmulhrsw              m7, m6, [o(pw_1697x16)]
+    paddsw                m6, m6
+    paddsw                m6, m7
+    mova                  m7, [o(pw_2048)]
+    REPX    {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulhrsw              m7, [coeffq+16*7]
+    mova       [coeffq+16*4], m4
+    jmp m(iadst_4x16_internal_8bpc).end2
+
+
+%macro INV_TXFM_16X4_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x4, 8
+%ifidn %1_%2, dct_dct
+    movd                 m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1, [coeffq]
+    movd                 m2, [o(pw_16384)]
+    mov            [coeffq], eobd
+    mov                 r2d, 2
+    lea                tx2q, [o(m(inv_txfm_add_dct_dct_16x4_8bpc).end)]
+.dconly:
+    pmulhrsw             m0, m2
+    movd                 m2, [o(pw_2048)]              ;intentionally rip-relative
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, m2
+    pshuflw              m0, m0, q0000
+    punpcklwd            m0, m0
+    pxor                 m5, m5
+.dconly_loop:
+    mova                 m1, [dstq]
+    mova                 m3, [dstq+strideq]
+    punpckhbw            m2, m1, m5
+    punpcklbw            m1, m5
+    punpckhbw            m4, m3, m5
+    punpcklbw            m3, m5
+    paddw                m2, m0
+    paddw                m1, m0
+    paddw                m4, m0
+    paddw                m3, m0
+    packuswb             m1, m2
+    packuswb             m3, m4
+    mova             [dstq], m1
+    mova     [dstq+strideq], m3
+    lea                dstq, [dstq+strideq*2]
+    dec                 r2d
+    jg .dconly_loop
+    jmp                tx2q
+.end:
+    RET
+%endif
+%endmacro
+
+%macro LOAD_7ROWS 2 ;src, stride
+    mova                 m0, [%1+%2*0]
+    mova                 m1, [%1+%2*1]
+    mova                 m2, [%1+%2*2]
+    mova                 m3, [%1+%2*3]
+    mova                 m4, [%1+%2*4]
+    mova                 m5, [%1+%2*5]
+    mova                 m6, [%1+%2*6]
+%endmacro
+
+%macro SAVE_7ROWS 2 ;src, stride
+    mova          [%1+%2*0], m0
+    mova          [%1+%2*1], m1
+    mova          [%1+%2*2], m2
+    mova          [%1+%2*3], m3
+    mova          [%1+%2*4], m4
+    mova          [%1+%2*5], m5
+    mova          [%1+%2*6], m6
+%endmacro
+
+%macro IDCT16_1D_PACKED_ODDHALF 7  ;src[1-4], tmp[1-3]
+    punpckhwd            m%5, m%4, m%1                ;packed in13 in3
+    punpcklwd            m%1, m%4                     ;packed in1  in15
+    punpcklwd            m%4, m%3, m%2                ;packed in9  in7
+    punpckhwd            m%2, m%3                     ;packed in5  in11
+    mova                 m%7, [o(pd_2048)]
+    ITX_MUL2X_PACK        %1, %6, %7,  401, 4076, 1    ;low: t8a   high: t15a
+    ITX_MUL2X_PACK        %4, %6, %7, 3166, 2598, 1    ;low: t9a   high: t14a
+    ITX_MUL2X_PACK        %2, %6, %7, 1931, 3612, 1    ;low: t10a  high: t13a
+    ITX_MUL2X_PACK        %5, %6, %7, 3920, 1189, 1    ;low: t11a  high: t12a
+    psubsw               m%6, m%1, m%4                 ;low: t9    high: t14
+    paddsw               m%1, m%4                      ;low: t8    high: t15
+    psubsw               m%4, m%5, m%2                 ;low: t10   high: t13
+    paddsw               m%5, m%2                      ;low: t11   high: t12
+    mova                 m%2, [o(deint_shuf2)]
+    pshufb               m%6, m%2
+    pshufb               m%4, m%2
+    ITX_MUL2X_PACK        %6, %3, %7, 1567, 3784, 1    ;low: t9a   high: t14a
+    ITX_MUL2X_PACK        %4, %3, %7, m3784, 1567, 1   ;low: t10a  high: t13a
+    psubsw               m%3, m%1, m%5                 ;low: t11a  high: t12a
+    paddsw               m%1, m%5                      ;low: t8a   high: t15a
+    psubsw               m%5, m%6, m%4                 ;low: t10   high: t13
+    paddsw               m%6, m%4                      ;low: t9    high: t14
+    pshufb               m%3, m%2
+    pshufb               m%5, m%2
+    ITX_MUL2X_PACK        %3, %2, %7, 2896, 2896, 4    ;t12,  t11
+    ITX_MUL2X_PACK        %5, %4, %7, 2896, 2896, 4    ;t13a, t10a
+    packssdw             m%2, m%4                      ;low: t11   high: t10a
+    packssdw             m%3, m%5                      ;low: t12   high: t13a
+    punpckhqdq           m%4, m%1, m%6                 ;low: t15a  high: t14
+    punpcklqdq           m%1, m%6                      ;low: t8a   high: t9
+%endmacro
+
+INV_TXFM_16X4_FN dct, dct
+INV_TXFM_16X4_FN dct, adst
+INV_TXFM_16X4_FN dct, flipadst
+INV_TXFM_16X4_FN dct, identity
+
+cglobal idct_16x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_7ROWS        coeffq, 16
+    call .main
+
+.pass1_end:
+    punpckhwd             m7, m0, m2                 ;packed out1,  out5
+    punpcklwd             m0, m2                     ;packed out0,  out4
+    punpcklwd             m2, m1, m3                 ;packed out3,  out7
+    punpckhwd             m1, m3                     ;packed out2,  out6
+    mova       [coeffq+16*6], m7
+    mova                  m7, [coeffq+16*7]
+    punpckhwd             m3, m4, m6                 ;packed out9,  out13
+    punpcklwd             m4, m6                     ;packed out8,  out12
+    punpcklwd             m6, m5, m7                 ;packed out11, out15
+    punpckhwd             m5, m7                     ;packed out10, out14
+
+.pass1_end2:
+    mova                  m7, [o(pw_16384)]
+    REPX    {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulhrsw              m7, [coeffq+16*6]
+    mova       [coeffq+16*6], m7
+
+.pass1_end3:
+    punpckhwd             m7, m3, m6                 ;packed 9, 11, 13, 15 high
+    punpcklwd             m3, m6                     ;packed 9, 10, 13, 15 low
+    punpckhwd             m6, m4, m5                 ;packed 8, 10, 12, 14 high
+    punpcklwd             m4, m5                     ;packed 8, 10, 12, 14 low
+    punpckhwd             m5, m4, m3                 ;8, 9, 10, 11, 12, 13, 14, 15(1)
+    punpcklwd             m4, m3                     ;8, 9, 10, 11, 12, 13, 14, 15(0)
+    punpckhwd             m3, m6, m7                 ;8, 9, 10, 11, 12, 13, 14, 15(3)
+    punpcklwd             m6, m7                     ;8, 9, 10, 11, 12, 13, 14, 15(2)
+    mova       [coeffq+16*7], m3
+    mova                  m3, [coeffq+16*6]
+    punpckhwd             m7, m3, m2                 ;packed 1, 3, 5, 7 high
+    punpcklwd             m3, m2                     ;packed 1, 3, 5, 7 low
+    punpckhwd             m2, m0, m1                 ;packed 0, 2, 4, 6 high
+    punpcklwd             m0, m1                     ;packed 0, 2, 4, 6 low
+    punpckhwd             m1, m0, m3                 ;0, 1, 2, 3, 4, 5, 6, 7(1)
+    punpcklwd             m0, m3                     ;0, 1, 2, 3, 4, 5, 6, 7(0)
+    punpckhwd             m3, m2, m7                 ;0, 1, 2, 3, 4, 5, 6, 7(3)
+    punpcklwd             m2, m7                     ;0, 1, 2, 3, 4, 5, 6, 7(2)
+    jmp                 tx2q
+
+.pass2:
+    lea                 tx2q, [o(m(idct_8x4_internal_8bpc).pass2)]
+
+.pass2_end:
+    mova       [coeffq+16*4], m4
+    mova       [coeffq+16*5], m5
+    mova       [coeffq+16*6], m6
+    lea                   r3, [dstq+8]
+    call                tx2q
+
+    add               coeffq, 16*4
+    mova                  m0, [coeffq+16*0]
+    mova                  m1, [coeffq+16*1]
+    mova                  m2, [coeffq+16*2]
+    mova                  m3, [coeffq+16*3]
+    mov                 dstq, r3
+    jmp                 tx2q
+
+ALIGN function_align
+cglobal_label .main
+    punpckhqdq            m7, m0, m1                 ;low:in1  high:in3
+    punpcklqdq            m0, m1
+    punpcklqdq            m1, m2, m3
+    punpckhqdq            m3, m2                     ;low:in7  high:in5
+    mova       [coeffq+16*4], m7
+    mova       [coeffq+16*5], m3
+    mova                  m7, [coeffq+16*7]
+    punpcklqdq            m2, m4, m5
+    punpckhqdq            m4, m5                     ;low:in9  high:in11
+    punpcklqdq            m3, m6, m7
+    punpckhqdq            m7, m6                     ;low:in15 high:in13
+    mova       [coeffq+16*6], m4
+    IDCT8_1D_PACKED
+    mova                  m6, [coeffq+16*4]
+    mova                  m4, [coeffq+16*5]
+    mova                  m5, [coeffq+16*6]
+    mova       [coeffq+16*4], m1
+    mova       [coeffq+16*5], m2
+    mova       [coeffq+16*6], m3
+
+    IDCT16_1D_PACKED_ODDHALF 6, 4, 5, 7, 1, 2, 3
+
+    mova                  m1, [coeffq+16*4]
+    psubsw                m3, m0, m7                 ;low:out15 high:out14
+    paddsw                m0, m7                     ;low:out0  high:out1
+    psubsw                m7, m1, m5                 ;low:out12 high:out13
+    paddsw                m1, m5                     ;low:out3  high:out2
+    mova       [coeffq+16*7], m3
+    mova                  m2, [coeffq+16*5]
+    mova                  m3, [coeffq+16*6]
+    psubsw                m5, m2, m4                 ;low:out11 high:out10
+    paddsw                m2, m4                     ;low:out4  high:out5
+    psubsw                m4, m3, m6                 ;low:out8  high:out9
+    paddsw                m3, m6                     ;low:out7  high:out6
+    mova                  m6, m7
+    ret
+
+INV_TXFM_16X4_FN adst, dct
+INV_TXFM_16X4_FN adst, adst
+INV_TXFM_16X4_FN adst, flipadst
+INV_TXFM_16X4_FN adst, identity
+
+cglobal iadst_16x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_7ROWS        coeffq, 16
+    call .main
+    call .main_pass1_end
+
+    punpckhwd             m6, m7, m0                 ;packed -out11, -out15
+    punpcklwd             m0, m7                     ;packed   out0,   out4
+    punpcklwd             m7, m3, m4                 ;packed  -out3,  -out7
+    punpckhwd             m4, m3                     ;packed   out8,  out12
+    mova                  m1, [coeffq+16*6]
+    punpcklwd             m3, m1, m5                 ;packed  -out1,  -out5
+    punpckhwd             m5, m1                     ;packed  out10,  out14
+    mova                  m1, [coeffq+16*7]
+    mova       [coeffq+16*6], m3
+    mova       [coeffq+16*7], m7
+    punpckhwd             m3, m2, m1                 ;packed  -out9,  -out13
+    punpcklwd             m1, m2                     ;packed   out2,   out6
+
+    mova                  m7, [o(pw_16384)]
+
+.pass1_end:
+    REPX    {pmulhrsw x, m7}, m0, m1, m4, m5
+    pxor                  m2, m2
+    psubw                 m2, m7
+    mova                  m7, [coeffq+16*6]
+    REPX    {pmulhrsw x, m2}, m7, m3, m6
+    pmulhrsw              m2, [coeffq+16*7]
+    mova       [coeffq+16*6], m7
+    jmp   m(idct_16x4_internal_8bpc).pass1_end3
+
+.pass2:
+    lea                 tx2q, [o(m(iadst_8x4_internal_8bpc).pass2)]
+    jmp   m(idct_16x4_internal_8bpc).pass2_end
+
+ALIGN function_align
+cglobal_label .main
+    mova       [coeffq+16*6], m0
+    pshufd                m0, m1, q1032
+    pshufd                m2, m2, q1032
+    punpckhwd             m1, m6, m0                 ;packed in13,  in2
+    punpcklwd             m0, m6                     ;packed  in3, in12
+    punpckhwd             m7, m5, m2                 ;packed in11,  in4
+    punpcklwd             m2, m5                     ;packed  in5, in10
+    mova                  m6, [o(pd_2048)]
+    ITX_MUL2X_PACK         1, 5, 6,  995, 3973       ;low:t2   high:t3
+    ITX_MUL2X_PACK         7, 5, 6, 1751, 3703       ;low:t4   high:t5
+    ITX_MUL2X_PACK         2, 5, 6, 3513, 2106       ;low:t10  high:t11
+    ITX_MUL2X_PACK         0, 5, 6, 3857, 1380       ;low:t12  high:t13
+    psubsw                m5, m1, m2                 ;low:t10a high:t11a
+    paddsw                m1, m2                     ;low:t2a  high:t3a
+    psubsw                m2, m7, m0                 ;low:t12a high:t13a
+    paddsw                m7, m0                     ;low:t4a  high:t5a
+    punpcklqdq            m0, m5
+    punpckhwd             m0, m5                     ;packed t10a, t11a
+    punpcklqdq            m5, m2
+    punpckhwd             m2, m5                     ;packed t13a, t12a
+    ITX_MUL2X_PACK         0, 5, 6, 3406, 2276       ;low:t10  high:t11
+    ITX_MUL2X_PACK         2, 5, 6, 4017,  799, 1    ;low:t12  high:t13
+    mova       [coeffq+16*4], m1
+    mova       [coeffq+16*5], m7
+    mova                  m1, [coeffq+16*6]
+    mova                  m7, [coeffq+16*7]
+    pshufd                m1, m1, q1032
+    pshufd                m3, m3, q1032
+    punpckhwd             m5, m7, m1                 ;packed in15,  in0
+    punpcklwd             m1, m7                     ;packed  in1, in14
+    punpckhwd             m7, m4, m3                 ;packed  in9,  in6
+    punpcklwd             m3, m4                     ;packed  in7,  in8
+    ITX_MUL2X_PACK         5, 4, 6,  201, 4091       ;low:t0    high:t1
+    ITX_MUL2X_PACK         7, 4, 6, 2440, 3290       ;low:t6    high:t7
+    ITX_MUL2X_PACK         3, 4, 6, 3035, 2751       ;low:t8    high:t9
+    ITX_MUL2X_PACK         1, 4, 6, 4052,  601       ;low:t14   high:t15
+    psubsw                m4, m5, m3                 ;low:t8a   high:t9a
+    paddsw                m5, m3                     ;low:t0a   high:t1a
+    psubsw                m3, m7, m1                 ;low:t14a  high:t15a
+    paddsw                m7, m1                     ;low:t6a   high:t7a
+    punpcklqdq            m1, m4
+    punpckhwd             m1, m4                     ;packed  t8a,  t9a
+    punpcklqdq            m4, m3
+    punpckhwd             m3, m4                     ;packed t15a, t14a
+    ITX_MUL2X_PACK         1, 4, 6,  799, 4017       ;low:t8    high:t9
+    ITX_MUL2X_PACK         3, 4, 6, 2276, 3406, 1    ;low:t14   high:t15
+    paddsw                m4, m1, m2                 ;low:t12a  high:t13a
+    psubsw                m1, m2                     ;low:t8a   high:t9a
+    psubsw                m2, m0, m3                 ;low:t14a  high:t15a
+    paddsw                m0, m3                     ;low:t10a  high:t11a
+    punpcklqdq            m3, m1
+    punpckhwd             m3, m1                     ;packed t12a, t13a
+    punpcklqdq            m1, m2
+    punpckhwd             m2, m1                     ;packed t15a, t14a
+    ITX_MUL2X_PACK         3, 1, 6, 1567, 3784       ;low:t12   high:t13
+    ITX_MUL2X_PACK         2, 1, 6, 3784, 1567, 1    ;low:t14   high:t15
+    psubsw                m1, m3, m2                 ;low:t14a  high:t15a
+    paddsw                m3, m2                     ;low:out2  high:-out13
+    psubsw                m2, m4, m0                 ;low:t10   high:t11
+    paddsw                m0, m4                     ;low:-out1 high:out14
+    mova       [coeffq+16*6], m0
+    mova       [coeffq+16*7], m3
+    mova                  m0, [coeffq+16*4]
+    mova                  m3, [coeffq+16*5]
+    psubsw                m4, m5, m3                 ;low:t4    high:t5
+    paddsw                m5, m3                     ;low:t0    high:t1
+    psubsw                m3, m0, m7                 ;low:t6    high:t7
+    paddsw                m0, m7                     ;low:t2    high:t3
+    punpcklqdq            m7, m4
+    punpckhwd             m7, m4                     ;packed t4, t5
+    punpcklqdq            m4, m3
+    punpckhwd             m3, m4                     ;packed t7, t6
+    ITX_MUL2X_PACK         7, 4, 6, 1567, 3784       ;low:t4a   high:t5a
+    ITX_MUL2X_PACK         3, 4, 6, 3784, 1567, 1    ;low:t6a   high:t7a
+    psubsw                m4, m5, m0                 ;low:t2a   high:t3a
+    paddsw                m0, m5                     ;low:out0  high:-out15
+    psubsw                m5, m7, m3                 ;low:t6    high:t7
+    paddsw                m3, m7                     ;low:-out3 high:out12
+    ret
+ALIGN function_align
+.main_pass1_end:
+    mova                  m7, [o(deint_shuf1)]
+    mova       [coeffq+16*4], m0
+    mova       [coeffq+16*5], m3
+    mova                  m0, [o(pw_2896_m2896)]
+    mova                  m3, [o(pw_2896_2896)]
+    pshufb                m1, m7                     ;t14a t15a
+    pshufb                m2, m7                     ;t10  t11
+    pshufb                m4, m7                     ;t2a  t3a
+    pshufb                m5, m7                     ;t6   t7
+    pmaddwd               m7, m0, m2
+    pmaddwd               m2, m3
+    paddd                 m7, m6
+    paddd                 m2, m6
+    psrad                 m7, 12
+    psrad                 m2, 12
+    packssdw              m2, m7                     ;low:out6  high:-out9
+    pmaddwd               m7, m0, m4
+    pmaddwd               m4, m3
+    paddd                 m7, m6
+    paddd                 m4, m6
+    psrad                 m7, 12
+    psrad                 m4, 12
+    packssdw              m4, m7                     ;low:-out7 high:out8
+    pmaddwd               m7, m3, m5
+    pmaddwd               m5, m0
+    paddd                 m7, m6
+    paddd                 m5, m6
+    psrad                 m7, 12
+    psrad                 m5, 12
+    packssdw              m7, m5                     ;low:out4  high:-out11
+    pmaddwd               m5, m3, m1
+    pmaddwd               m1, m0
+    paddd                 m5, m6
+    paddd                 m1, m6
+    psrad                 m5, 12
+    psrad                 m1, 12
+    packssdw              m5, m1                     ;low:-out5 high:out10
+    mova                  m0, [coeffq+16*4]
+    mova                  m3, [coeffq+16*5]
+    ret
+ALIGN function_align
+cglobal_label .main_pass2_end
+    mova                  m7, [o(pw_2896x8)]
+    punpckhqdq            m6, m2, m1                 ;low:t11   high:t15a
+    punpcklqdq            m2, m1                     ;low:t10   high:t14a
+    psubsw                m1, m2, m6
+    paddsw                m2, m6
+    punpckhqdq            m6, m4, m5                 ;low:t3a   high:t7
+    punpcklqdq            m4, m5                     ;low:t2a   high:t6
+    psubsw                m5, m4, m6
+    paddsw                m4, m6
+    pmulhrsw              m1, m7                     ;low:-out9 high:out10
+    pmulhrsw              m2, m7                     ;low:out6  high:-out5
+    pmulhrsw              m5, m7                     ;low:out8  high:-out11
+    pmulhrsw              m4, m7                     ;low:-out7 high:out4
+    punpckhqdq            m7, m4, m5                 ;low:out4  high:-out11
+    punpcklqdq            m4, m5                     ;low:-out7 high:out8
+    punpckhqdq            m5, m2, m1                 ;low:-out5 high:out10
+    punpcklqdq            m2, m1                     ;low:out6  high:-out9
+    ret
+
+
+INV_TXFM_16X4_FN flipadst, dct
+INV_TXFM_16X4_FN flipadst, adst
+INV_TXFM_16X4_FN flipadst, flipadst
+INV_TXFM_16X4_FN flipadst, identity
+
+cglobal iflipadst_16x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_7ROWS        coeffq, 16
+    call m(iadst_16x4_internal_8bpc).main
+    call m(iadst_16x4_internal_8bpc).main_pass1_end
+
+    punpcklwd             m6, m7, m0                 ;packed  out11,  out15
+    punpckhwd             m0, m7                     ;packed  -out0,  -out4
+    punpckhwd             m7, m3, m4                 ;packed   out3,   out7
+    punpcklwd             m4, m3                     ;packed  -out8, -out12
+    mova                  m1, [coeffq+16*6]
+    punpckhwd             m3, m1, m5                 ;packed   out1,   out5
+    punpcklwd             m5, m1                     ;packed -out10, -out14
+    mova                  m1, [coeffq+16*7]
+    mova       [coeffq+16*6], m3
+    mova       [coeffq+16*7], m7
+    punpcklwd             m3, m2, m1                 ;packed   out9,  out13
+    punpckhwd             m1, m2                     ;packed  -out2,  -out6
+
+    mova                  m7, [o(pw_m16384)]
+    jmp   m(iadst_16x4_internal_8bpc).pass1_end
+
+.pass2:
+    lea                 tx2q, [o(m(iflipadst_8x4_internal_8bpc).pass2)]
+    jmp   m(idct_16x4_internal_8bpc).pass2_end
+
+
+INV_TXFM_16X4_FN identity, dct
+INV_TXFM_16X4_FN identity, adst
+INV_TXFM_16X4_FN identity, flipadst
+INV_TXFM_16X4_FN identity, identity
+
+cglobal iidentity_16x4_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                  m1, [coeffq+16*6]
+    mova                  m0, [coeffq+16*5]
+    mova                  m2, [coeffq+16*7]
+    mova                  m6, [o(pw_1697x16)]
+    mova                  m7, [o(pw_16384)]
+    pmulhrsw              m4, m6, m1
+    pmulhrsw              m3, m6, m0
+    pmulhrsw              m5, m6, m2
+    pmulhrsw              m4, m7
+    pmulhrsw              m3, m7
+    pmulhrsw              m5, m7
+    paddsw                m1, m4
+    paddsw                m0, m3
+    paddsw                m5, m2
+    mova                  m2, [coeffq+16*2]
+    mova                  m3, [coeffq+16*3]
+    mova                  m4, [coeffq+16*4]
+    mova       [coeffq+16*6], m1
+    mova       [coeffq+16*5], m0
+    mova       [coeffq+16*7], m5
+    pmulhrsw              m0, m6, m2
+    pmulhrsw              m1, m6, m3
+    pmulhrsw              m5, m6, m4
+    pmulhrsw              m0, m7
+    pmulhrsw              m1, m7
+    pmulhrsw              m5, m7
+    paddsw                m2, m0
+    paddsw                m3, m1
+    paddsw                m4, m5
+    mova                  m0, [coeffq+16*0]
+    mova                  m1, [coeffq+16*1]
+    pmulhrsw              m5, m6, m0
+    pmulhrsw              m6, m1
+    pmulhrsw              m5, m7
+    pmulhrsw              m6, m7
+    paddsw                m0, m5
+    paddsw                m1, m6
+    mova                  m6, [coeffq+16*6]
+    mova                  m5, [coeffq+16*5]
+    punpckhwd             m7, m0, m2                 ;packed out1,  out5
+    punpcklwd             m0, m2                     ;packed out0,  out4
+    punpckhwd             m2, m1, m3                 ;packed out3,  out7
+    punpcklwd             m1, m3                     ;packed out2,  out6
+    mova       [coeffq+16*6], m7
+    mova                  m7, [coeffq+16*7]
+    punpckhwd             m3, m4, m6                 ;packed out9,  out13
+    punpcklwd             m4, m6                     ;packed out8,  out12
+    punpckhwd             m6, m5, m7                 ;packed out11, out15
+    punpcklwd             m5, m7                     ;packed out10, out14
+    jmp   m(idct_16x4_internal_8bpc).pass1_end3
+
+.pass2:
+    lea                 tx2q, [o(m(iidentity_8x4_internal_8bpc).pass2)]
+    jmp   m(idct_16x4_internal_8bpc).pass2_end
+
+
+%macro SAVE_8ROWS 2  ;src, stride
+    mova                 [%1+%2*0], m0
+    mova                 [%1+%2*1], m1
+    mova                 [%1+%2*2], m2
+    mova                 [%1+%2*3], m3
+    mova                 [%1+%2*4], m4
+    mova                 [%1+%2*5], m5
+    mova                 [%1+%2*6], m6
+    mova                 [%1+%2*7], m7
+%endmacro
+
+%macro INV_TXFM_8X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 8x16, 8, 16*16
+%ifidn %1_%2, dct_dct
+    pshuflw              m0, [coeffq], q0000
+    punpcklwd            m0, m0
+    mova                 m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1
+    mova                 m2, [o(pw_16384)]
+    mov            [coeffq], eobd
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, m2
+    psrlw                m2, 3              ; pw_2048
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, m2
+    mov                 r3d, 4
+    lea                tx2q, [o(m(inv_txfm_add_dct_dct_8x16_8bpc).end)]
+    jmp m(inv_txfm_add_dct_dct_8x8_8bpc).loop
+.end:
+    RET
+%endif
+%endmacro
+
+INV_TXFM_8X16_FN dct, dct
+INV_TXFM_8X16_FN dct, adst
+INV_TXFM_8X16_FN dct, flipadst
+INV_TXFM_8X16_FN dct, identity
+
+cglobal idct_8x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    lea                    r3, [o(m(idct_8x8_internal_8bpc).pass1)]
+
+.pass1:
+    LOAD_8ROWS    coeffq+16*1, 32, 1
+    mov   [rsp+gprsize+16*11], tx2q
+    lea                  tx2q, [o(m(idct_8x16_internal_8bpc).pass1_end)]
+    jmp                    r3
+
+.pass1_end:
+    SAVE_8ROWS    coeffq+16*1, 32
+    LOAD_8ROWS    coeffq+16*0, 32, 1
+    mov                  tx2q, [rsp+gprsize+16*11]
+    jmp                    r3
+
+.pass2:
+    lea                  tx2q, [o(m(idct_8x16_internal_8bpc).end)]
+
+.pass2_pre:
+    mova       [coeffq+16*2 ], m1
+    mova       [coeffq+16*6 ], m3
+    mova       [coeffq+16*10], m5
+    mova       [coeffq+16*14], m7
+    mova                   m1, m2
+    mova                   m2, m4
+    mova                   m3, m6
+    mova                   m4, [coeffq+16*1 ]
+    mova                   m5, [coeffq+16*5 ]
+    mova                   m6, [coeffq+16*9 ]
+    mova                   m7, [coeffq+16*13]
+
+.pass2_main:
+    call m(idct_8x8_internal_8bpc).main
+
+    SAVE_7ROWS   rsp+gprsize+16*3, 16
+    mova                   m0, [coeffq+16*2 ]
+    mova                   m1, [coeffq+16*6 ]
+    mova                   m2, [coeffq+16*10]
+    mova                   m3, [coeffq+16*14]
+    mova                   m4, [coeffq+16*3 ]
+    mova                   m5, [coeffq+16*7 ]
+    mova                   m6, [coeffq+16*11]
+    mova                   m7, [coeffq+16*15]
+    call m(idct_16x8_internal_8bpc).main
+
+    mov                    r3, dstq
+    lea                  dstq, [dstq+strideq*8]
+    jmp  m(idct_8x8_internal_8bpc).end
+
+.end:
+    LOAD_8ROWS   rsp+gprsize+16*3, 16
+    mova   [rsp+gprsize+16*0], m7
+    lea                  tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    mov                  dstq, r3
+    jmp  m(idct_8x8_internal_8bpc).end
+
+.end1:
+    pxor                   m7, m7
+    REPX  {mova [coeffq+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15
+    ret
+
+INV_TXFM_8X16_FN adst, dct
+INV_TXFM_8X16_FN adst, adst
+INV_TXFM_8X16_FN adst, flipadst
+INV_TXFM_8X16_FN adst, identity
+
+cglobal iadst_8x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    lea                    r3, [o(m(iadst_8x8_internal_8bpc).pass1)]
+    jmp  m(idct_8x16_internal_8bpc).pass1
+
+.pass2:
+    lea                  tx2q, [o(m(iadst_8x16_internal_8bpc).end)]
+
+.pass2_pre:
+    mova    [rsp+gprsize+16*7], m0
+    mova    [rsp+gprsize+16*8], m1
+    mova    [rsp+gprsize+16*5], m6
+    mova    [rsp+gprsize+16*6], m7
+    mova                    m0, m2
+    mova                    m1, m3
+    mova                    m2, m4
+    mova                    m3, m5
+
+.pass2_main:
+    mova                    m4, [coeffq+16*1 ]
+    mova                    m5, [coeffq+16*3 ]
+    mova                    m6, [coeffq+16*13]
+    mova                    m7, [coeffq+16*15]
+    mova    [rsp+gprsize+16*3], m4
+    mova    [rsp+gprsize+16*4], m5
+    mova    [rsp+gprsize+16*9], m6
+    mova    [rsp+gprsize+32*5], m7
+    mova                    m4, [coeffq+16*5 ]
+    mova                    m5, [coeffq+16*7 ]
+    mova                    m6, [coeffq+16*9 ]
+    mova                    m7, [coeffq+16*11]
+
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass2_end
+
+    mov                    r3, dstq
+    lea                  dstq, [dstq+strideq*8]
+    jmp m(iadst_8x8_internal_8bpc).end
+
+.end:
+    LOAD_8ROWS   rsp+gprsize+16*3, 16
+    mova   [rsp+gprsize+16*0], m7
+    lea                  tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    mov                  dstq, r3
+    jmp  m(iadst_8x8_internal_8bpc).end
+
+
+INV_TXFM_8X16_FN flipadst, dct
+INV_TXFM_8X16_FN flipadst, adst
+INV_TXFM_8X16_FN flipadst, flipadst
+INV_TXFM_8X16_FN flipadst, identity
+
+cglobal iflipadst_8x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    lea                    r3, [o(m(iflipadst_8x8_internal_8bpc).pass1)]
+    jmp  m(idct_8x16_internal_8bpc).pass1
+
+.pass2:
+    lea                   tx2q, [o(m(iflipadst_8x16_internal_8bpc).end)]
+    lea                     r3, [dstq+strideq*8]
+
+.pass2_pre:
+    mova    [rsp+gprsize+16*7], m0
+    mova    [rsp+gprsize+16*8], m1
+    mova    [rsp+gprsize+16*5], m6
+    mova    [rsp+gprsize+16*6], m7
+    mova                    m0, m2
+    mova                    m1, m3
+    mova                    m2, m4
+    mova                    m3, m5
+
+.pass2_main:
+    mova                    m4, [coeffq+16*1 ]
+    mova                    m5, [coeffq+16*3 ]
+    mova                    m6, [coeffq+16*13]
+    mova                    m7, [coeffq+16*15]
+    mova    [rsp+gprsize+16*3], m4
+    mova    [rsp+gprsize+16*4], m5
+    mova    [rsp+gprsize+16*9], m6
+    mova    [rsp+gprsize+32*5], m7
+    mova                    m4, [coeffq+16*5 ]
+    mova                    m5, [coeffq+16*7 ]
+    mova                    m6, [coeffq+16*9 ]
+    mova                    m7, [coeffq+16*11]
+
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass2_end
+    jmp  m(iflipadst_8x8_internal_8bpc).end
+
+.end:
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    mov                   dstq, r3
+    jmp  m(iflipadst_8x8_internal_8bpc).end
+
+
+INV_TXFM_8X16_FN identity, dct
+INV_TXFM_8X16_FN identity, adst
+INV_TXFM_8X16_FN identity, flipadst
+INV_TXFM_8X16_FN identity, identity
+
+cglobal iidentity_8x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS    coeffq+16*1, 32, 1
+    mov                    r3, tx2q
+    lea                  tx2q, [o(.pass1_end)]
+    mova   [rsp+gprsize+16*1], m6
+    jmp  m(idct_8x8_internal_8bpc).pass1_end3
+
+.pass1_end:
+    SAVE_8ROWS    coeffq+16*1, 32
+    LOAD_8ROWS    coeffq+16*0, 32, 1
+    mov                  tx2q, r3
+    mova   [rsp+gprsize+16*1], m6
+    jmp  m(idct_8x8_internal_8bpc).pass1_end3
+
+.pass2:
+    lea                  tx2q, [o(.end1)]
+
+.end:
+    mova   [rsp+gprsize+16*0], m7
+    mova   [rsp+gprsize+16*1], m6
+    mova                   m7, [o(pw_1697x16)]
+    REPX     {IDTX16 x, 6, 7}, 0, 1, 2, 3, 4, 5
+    mova                   m6, [rsp+gprsize+16*1]
+    mova   [rsp+gprsize+16*2], m5
+    IDTX16                  6, 5, 7
+    mova                   m5, [rsp+gprsize+16*0]
+    IDTX16                  5, 7, 7
+    mova                   m7, [o(pw_2048)]
+    REPX     {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulhrsw               m7, [rsp+gprsize+16*2]
+    mova   [rsp+gprsize+16*0], m5
+    mova   [rsp+gprsize+16*1], m6
+    mova   [rsp+gprsize+16*2], m7
+    jmp  m(idct_8x8_internal_8bpc).end3
+
+.end1:
+    LOAD_8ROWS    coeffq+16*1, 32
+    lea                  tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    lea                  dstq, [dstq+strideq*2]
+    jmp .end
+
+
+%macro INV_TXFM_16X8_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x8, 8, 16*16
+%ifidn %1_%2, dct_dct
+    movd                 m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1, [coeffq]
+    movd                 m2, [o(pw_16384)]
+    mov            [coeffq], eobd
+    pmulhrsw             m0, m1
+    mov                 r2d, 4
+    lea                tx2q, [o(m(inv_txfm_add_dct_dct_16x8_8bpc).end)]
+    jmp m(inv_txfm_add_dct_dct_16x4_8bpc).dconly
+.end:
+    RET
+%endif
+%endmacro
+
+INV_TXFM_16X8_FN dct, dct
+INV_TXFM_16X8_FN dct, adst
+INV_TXFM_16X8_FN dct, flipadst
+INV_TXFM_16X8_FN dct, identity
+
+cglobal idct_16x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS    coeffq+16*0, 32, 1
+    call m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS   rsp+gprsize+16*3, 16
+
+    LOAD_8ROWS    coeffq+16*1, 32, 1
+    call  .main
+    mov                    r3, tx2q
+    lea                  tx2q, [o(.pass1_end)]
+    jmp  m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end:
+    SAVE_8ROWS    coeffq+16*1, 32
+    LOAD_8ROWS   rsp+gprsize+16*3, 16
+    mova   [rsp+gprsize+16*0], m7
+    mov                  tx2q, r3
+    jmp  m(idct_8x8_internal_8bpc).pass1_end
+
+.pass2:
+    lea                  tx2q, [o(.end)]
+    lea                    r3, [dstq+8]
+    jmp  m(idct_8x8_internal_8bpc).pass2_main
+
+.end:
+    LOAD_8ROWS    coeffq+16*1, 32
+    lea                  tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    mov                  dstq, r3
+    jmp  m(idct_8x8_internal_8bpc).pass2_main
+
+
+ALIGN function_align
+cglobal_label .main
+    mova [rsp+gprsize*2+16*1], m2
+    mova [rsp+gprsize*2+16*2], m6
+    mova [rsp+gprsize*2+32*5], m5
+
+    mova                   m6, [o(pd_2048)]
+    ITX_MULSUB_2W           0, 7, 2, 5, 6,  401, 4076   ;t8a, t15a
+    ITX_MULSUB_2W           4, 3, 2, 5, 6, 3166, 2598   ;t9a, t14a
+    psubsw                 m2, m0, m4                   ;t9
+    paddsw                 m0, m4                       ;t8
+    psubsw                 m4, m7, m3                   ;t14
+    paddsw                 m7, m3                       ;t15
+    ITX_MULSUB_2W           4, 2, 3, 5, 6, 1567, 3784   ;t9a, t14a
+    mova                   m3, [rsp+gprsize*2+16*1]
+    mova                   m5, [rsp+gprsize*2+32*5]
+    mova [rsp+gprsize*2+16*1], m2
+    mova [rsp+gprsize*2+32*5], m4
+    mova                   m2, [rsp+gprsize*2+16*2]
+    mova [rsp+gprsize*2+16*2], m7
+    ITX_MULSUB_2W           3, 5, 7, 4, 6, 1931, 3612   ;t10a, t13a
+    ITX_MULSUB_2W           2, 1, 7, 4, 6, 3920, 1189   ;t11a, t12a
+    psubsw                 m4, m2, m3                   ;t10
+    paddsw                 m2, m3                       ;t11
+    psubsw                 m3, m1, m5                   ;t13
+    paddsw                 m1, m5                       ;t12
+    ITX_MULSUB_2W           3, 4, 7, 5, 6, m3784, 1567  ;t10a, t13a
+    mova                   m7, [rsp+gprsize*2+32*5]
+    psubsw                 m6, m0, m2                   ;t11a
+    paddsw                 m0, m2                       ;t8a
+    paddsw                 m2, m7, m3                   ;t9
+    psubsw                 m7, m3                       ;t10
+    mova                   m5, [rsp+gprsize*2+16*0]
+    psubsw                 m3, m5, m0                   ;out8
+    paddsw                 m0, m5                       ;out7
+    mova [rsp+gprsize*2+32*5], m0
+    mova                   m5, [rsp+gprsize*2+16*9]
+    psubsw                 m0, m5, m2                   ;out9
+    paddsw                 m2, m5                       ;out6
+    mova [rsp+gprsize*2+16*0], m0
+    mova [rsp+gprsize*2+16*9], m2
+    mova                   m0, [rsp+gprsize*2+16*1]
+    mova                   m2, [rsp+gprsize*2+16*2]
+    mova [rsp+gprsize*2+16*1], m3
+    psubsw                 m5, m0, m4                   ;t13
+    paddsw                 m0, m4                       ;t14
+    mova                   m3, [o(pd_2048)]
+    psubsw                 m4, m2, m1                   ;t12a
+    paddsw                 m1, m2                       ;t15a
+    mova [rsp+gprsize*2+16*2], m1
+    ITX_MULSUB_2W           5, 7, 1, 2, 3, 2896, 2896   ;t10a, t13a
+    ITX_MULSUB_2W           4, 6, 1, 2, 3, 2896, 2896   ;t11,  t12
+    mova                   m3, [rsp+gprsize*2+16*8]
+    psubsw                 m2, m3, m5                   ;out10
+    paddsw                 m3, m5                       ;out5
+    mova                   m5, [rsp+gprsize*2+16*7]
+    mova [rsp+gprsize*2+16*8], m3
+    psubsw                 m3, m5, m4                   ;out11
+    paddsw                 m5, m4                       ;out4
+    mova                   m4, [rsp+gprsize*2+16*6]
+    mova [rsp+gprsize*2+16*7], m5
+    paddsw                 m5, m4, m6                   ;out3
+    psubsw                 m4, m6                       ;out12
+    mova                   m6, [rsp+gprsize*2+16*5]
+    mova [rsp+gprsize*2+16*6], m5
+    psubsw                 m5, m6, m7                   ;out13
+    paddsw                 m6, m7                       ;out2
+    mova                   m7, [rsp+gprsize*2+16*4]
+    mova [rsp+gprsize*2+16*5], m6
+    psubsw                 m6, m7, m0                   ;out14
+    paddsw                 m7, m0                       ;out1
+    mova                   m1, [rsp+gprsize*2+16*2]
+    mova                   m0, [rsp+gprsize*2+16*3]
+    mova [rsp+gprsize*2+16*4], m7
+    psubsw                 m7, m0, m1                   ;out15
+    paddsw                 m0, m1                       ;out0
+    mova [rsp+gprsize*2+16*3], m0
+    mova                   m1, [rsp+gprsize*2+16*0]
+    mova                   m0, [rsp+gprsize*2+16*1]
+    mova [rsp+gprsize*2+16*0], m7
+    ret
+
+INV_TXFM_16X8_FN adst, dct
+INV_TXFM_16X8_FN adst, adst
+INV_TXFM_16X8_FN adst, flipadst
+INV_TXFM_16X8_FN adst, identity
+
+cglobal iadst_16x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                    m7, [o(pw_2896x8)]
+    pmulhrsw                m0, m7, [coeffq+16*0 ]
+    pmulhrsw                m1, m7, [coeffq+16*1 ]
+    pmulhrsw                m2, m7, [coeffq+16*14]
+    pmulhrsw                m3, m7, [coeffq+16*15]
+    mova    [rsp+gprsize+16*7], m0
+    mova    [rsp+gprsize+16*8], m1
+    mova    [rsp+gprsize+16*9], m2
+    mova    [rsp+gprsize+32*5], m3
+    pmulhrsw                m0, m7, [coeffq+16*6 ]
+    pmulhrsw                m1, m7, [coeffq+16*7 ]
+    pmulhrsw                m2, m7, [coeffq+16*8 ]
+    pmulhrsw                m3, m7, [coeffq+16*9 ]
+    mova    [rsp+gprsize+16*3], m2
+    mova    [rsp+gprsize+16*4], m3
+    mova    [rsp+gprsize+16*5], m0
+    mova    [rsp+gprsize+16*6], m1
+    pmulhrsw                m0, m7, [coeffq+16*2 ]
+    pmulhrsw                m1, m7, [coeffq+16*3 ]
+    pmulhrsw                m2, m7, [coeffq+16*4 ]
+    pmulhrsw                m3, m7, [coeffq+16*5 ]
+    pmulhrsw                m4, m7, [coeffq+16*10]
+    pmulhrsw                m5, m7, [coeffq+16*11]
+    pmulhrsw                m6, m7, [coeffq+16*12]
+    pmulhrsw                m7,     [coeffq+16*13]
+
+    call .main
+    call .main_pass1_end
+    mov                    r3, tx2q
+    lea                  tx2q, [o(.pass1_end)]
+    jmp m(iadst_8x8_internal_8bpc).pass1_end
+
+.pass1_end:
+    SAVE_8ROWS    coeffq+16*1, 32
+    LOAD_8ROWS   rsp+gprsize+16*3, 16
+    mova   [rsp+gprsize+16*0], m7
+    mov                  tx2q, r3
+    jmp m(iadst_8x8_internal_8bpc).pass1_end
+
+.pass2:
+    lea                  tx2q, [o(.end)]
+    lea                    r3, [dstq+8]
+    jmp m(iadst_8x8_internal_8bpc).pass2_main
+
+.end:
+    LOAD_8ROWS    coeffq+16*1, 32
+    lea                  tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    mov                  dstq, r3
+    jmp m(iadst_8x8_internal_8bpc).pass2_main
+
+ALIGN function_align
+cglobal_label .main
+    mova  [rsp+gprsize*2+16*0], m1
+    mova  [rsp+gprsize*2+16*1], m2
+    mova  [rsp+gprsize*2+16*2], m6
+
+    mova                    m6, [o(pd_2048)]
+    ITX_MULSUB_2W            7, 0, 1, 2, 6,  995, 3973   ;t3,  t2
+    ITX_MULSUB_2W            3, 4, 1, 2, 6, 3513, 2106   ;t11, t10
+    psubsw                  m1, m0, m4                   ;t10a
+    paddsw                  m0, m4                       ;t2a
+    psubsw                  m4, m7, m3                   ;t11a
+    paddsw                  m3, m7                       ;t3a
+    ITX_MULSUB_2W            1, 4, 7, 2, 6, 3406, 2276   ;t11, t10
+    mova                    m2, [rsp+gprsize*2+16*0]     ;in3
+    mova                    m7, [rsp+gprsize*2+16*1]     ;in4
+    mova  [rsp+gprsize*2+16*0], m1                       ;t11
+    mova  [rsp+gprsize*2+16*1], m4                       ;t10
+    mova                    m1, [rsp+gprsize*2+16*2]     ;in12
+    mova  [rsp+gprsize*2+16*2], m0                       ;t2a
+    ITX_MULSUB_2W            5, 7, 0, 4, 6, 1751, 3703   ;t5,  t4
+    ITX_MULSUB_2W            2, 1, 0, 4, 6, 3857, 1380   ;t13, t12
+    psubsw                  m0, m7, m1                   ;t12a
+    paddsw                  m1, m7                       ;t4a
+    psubsw                  m4, m5, m2                   ;t13a
+    paddsw                  m5, m2                       ;t5a
+    ITX_MULSUB_2W            4, 0, 7, 2, 6, 4017,  799   ;t12, t13
+    mova                    m2, [rsp+gprsize*2+16*8]     ;in1
+    mova                    m7, [rsp+gprsize*2+16*9]     ;in14
+    mova  [rsp+gprsize*2+16*8], m4                       ;t12
+    mova  [rsp+gprsize*2+16*9], m0                       ;t13
+    mova                    m4, [rsp+gprsize*2+16*4]     ;in9
+    mova                    m0, [rsp+gprsize*2+16*5]     ;in6
+    mova  [rsp+gprsize*2+16*4], m1                       ;t4a
+    mova  [rsp+gprsize*2+16*5], m5                       ;t5a
+    ITX_MULSUB_2W            2, 7, 1, 5, 6, 4052,  601   ;t15, t14
+    ITX_MULSUB_2W            4, 0, 1, 5, 6, 2440, 3290   ;t7,  t6
+    psubsw                  m1, m0, m7                   ;t14a
+    paddsw                  m0, m7                       ;t6a
+    psubsw                  m5, m4, m2                   ;t15a
+    paddsw                  m4, m2                       ;t7a
+    ITX_MULSUB_2W            5, 1, 7, 2, 6, 2276, 3406   ;t14, t15
+    mova                    m2, [rsp+gprsize*2+16*2]     ;t2a
+    mova  [rsp+gprsize*2+16*2], m5                       ;t14
+    psubsw                  m7, m2, m0                   ;t6
+    paddsw                  m2, m0                       ;t2
+    psubsw                  m0, m3, m4                   ;t7
+    paddsw                  m3, m4                       ;t3
+    ITX_MULSUB_2W            0, 7, 4, 5, 6, 3784, 1567   ;t6a, t7a
+    mova                    m4, [rsp+gprsize*2+16*7]     ;in0
+    mova                    m5, [rsp+gprsize*2+32*5]     ;in15
+    mova  [rsp+gprsize*2+16*7], m3                       ;t3
+    mova  [rsp+gprsize*2+32*5], m1                       ;t15
+    mova                    m1, [rsp+gprsize*2+16*6]     ;in7
+    mova                    m3, [rsp+gprsize*2+16*3]     ;in8
+    mova  [rsp+gprsize*2+16*6], m7                       ;t7a
+    mova  [rsp+gprsize*2+16*3], m0                       ;t6a
+    ITX_MULSUB_2W            5, 4, 0, 7, 6,  201, 4091   ;t1,  t0
+    ITX_MULSUB_2W            1, 3, 0, 7, 6, 3035, 2751   ;t9,  t8
+    psubsw                  m0, m4, m3                   ;t8a
+    paddsw                  m4, m3                       ;t0a
+    psubsw                  m3, m5, m1                   ;t9a
+    paddsw                  m5, m1                       ;t1a
+    ITX_MULSUB_2W            0, 3, 1, 7, 6,  799, 4017   ;t9,  t8
+    mova                    m1, [rsp+gprsize*2+16*4]     ;t4a
+    mova                    m7, [rsp+gprsize*2+16*5]     ;t5a
+    mova  [rsp+gprsize*2+16*4], m3                       ;t8
+    mova  [rsp+gprsize*2+16*5], m0                       ;t9
+    psubsw                  m0, m4, m1                   ;t4
+    paddsw                  m4, m1                       ;t0
+    psubsw                  m3, m5, m7                   ;t5
+    paddsw                  m5, m7                       ;t1
+    ITX_MULSUB_2W            0, 3, 1, 7, 6, 1567, 3784   ;t5a, t4a
+    mova                    m7, [rsp+gprsize*2+16*3]     ;t6a
+    psubsw                  m1, m4, m2                   ;t2a
+    paddsw                  m4, m2                       ;out0
+    mova  [rsp+gprsize*2+16*3], m4                       ;out0
+    mova                    m4, [rsp+gprsize*2+16*6]     ;t7a
+    psubsw                  m2, m3, m7                   ;t6
+    paddsw                  m3, m7                       ;-out3
+    mova  [rsp+gprsize*2+16*6], m3                       ;-out3
+    psubsw                  m3, m0, m4                   ;t7
+    paddsw                  m0, m4                       ;out12
+    mova [rsp+gprsize*2+16*12], m3
+    mova                    m3, [rsp+gprsize*2+16*7]     ;t3
+    mova [rsp+gprsize*2+16* 7], m2                       ;out4
+    psubsw                  m2, m5, m3                   ;t3a
+    paddsw                  m5, m3                       ;-out15
+    mova [rsp+gprsize*2+16*11], m2
+    mova                    m2, [rsp+gprsize*2+32*5]     ;t15
+    mova [rsp+gprsize*2+16*10], m1                       ;-out7
+    mova                    m1, [rsp+gprsize*2+16*0]     ;t11
+    mova [rsp+gprsize*2+16*0 ], m5                       ;-out15
+    mova                    m3, [rsp+gprsize*2+16*1]     ;t10
+    mova [rsp+gprsize*2+16*1 ], m4                       ;-out11
+    mova                    m4, [rsp+gprsize*2+16*2]     ;t14
+    mova [rsp+gprsize*2+16*2 ], m0                       ;out12
+    psubsw                  m0, m3, m4                   ;t14a
+    paddsw                  m3, m4                       ;t10a
+    psubsw                  m5, m1, m2                   ;t15a
+    paddsw                  m1, m2                       ;t11a
+    ITX_MULSUB_2W            5, 0, 2, 4, 6, 3784, 1567   ;t14, t15
+    mova                    m2, [rsp+gprsize*2+16*4]     ;t8
+    mova                    m4, [rsp+gprsize*2+16*5]     ;t9
+    mova  [rsp+gprsize*2+16*4], m3                       ;t10a
+    mova  [rsp+gprsize*2+16*5], m1                       ;t11a
+    mova                    m3, [rsp+gprsize*2+16*8]     ;t12
+    mova                    m1, [rsp+gprsize*2+16*9]     ;t13
+    mova  [rsp+gprsize*2+16*8], m5                       ;t14
+    mova  [rsp+gprsize*2+16*9], m0                       ;t15
+    psubsw                  m5, m2, m3                   ;t12a
+    paddsw                  m2, m3                       ;t8a
+    psubsw                  m0, m4, m1                   ;t13a
+    paddsw                  m4, m1                       ;t9a
+    ITX_MULSUB_2W            5, 0, 1, 3, 6, 1567, 3784   ;t13, t12
+    mova                    m6, [rsp+gprsize*2+16*4]     ;t10a
+    mova                    m1, [rsp+gprsize*2+16*5]     ;t11a
+    psubsw                  m3, m2, m6                   ;t10
+    paddsw                  m2, m6                       ;-out1
+    paddsw                  m6, m4, m1                   ;out14
+    psubsw                  m4, m1                       ;t11
+    mova [rsp+gprsize*2+16*14], m4
+    mova [rsp+gprsize*2+16* 4], m2                       ;-out1
+    mova                    m4, [rsp+gprsize*2+16*8]     ;t14
+    mova                    m2, [rsp+gprsize*2+16*9]     ;t15
+    mova [rsp+gprsize*2+16* 9], m3                       ;out6
+    psubsw                  m3, m0, m4                   ;t14a
+    paddsw                  m0, m4                       ;out2
+    psubsw                  m4, m5, m2                   ;t15a
+    paddsw                  m5, m2                       ;-out13
+    mova [rsp+gprsize*2+16* 5], m0                       ;out2
+    ret
+ALIGN function_align
+.main_pass1_end:
+    mova                    m0, [rsp+gprsize*2+16*14]
+    mova [rsp+gprsize*2+16*14], m5
+    mova [rsp+gprsize*2+16*15], m6
+    mova                    m5, [o(pw_2896_2896)]
+    mova                    m6, [o(pw_2896_m2896)]
+    mova                    m7, [o(pd_2048)]
+    punpcklwd               m2, m3, m4
+    punpckhwd               m3, m4
+    pmaddwd                 m4, m5, m2
+    pmaddwd                 m2, m6
+    pmaddwd                 m1, m5, m3
+    pmaddwd                 m3, m6
+    REPX         {paddd x, m7}, m4, m2, m1, m3
+    REPX         {psrad x, 12}, m4, m1, m2, m3
+    packssdw                m4, m1                       ;-out5
+    packssdw                m2, m3                       ;out10
+    mova [rsp+gprsize*2+16* 8], m4
+    mova                    m3, [rsp+gprsize*2+16* 9]
+    punpcklwd               m1, m3, m0
+    punpckhwd               m3, m0
+    pmaddwd                 m0, m5, m1
+    pmaddwd                 m1, m6
+    pmaddwd                 m4, m5, m3
+    pmaddwd                 m3, m6
+    REPX         {paddd x, m7}, m0, m1, m4, m3
+    REPX         {psrad x, 12}, m0, m4, m1, m3
+    packssdw                m0, m4                       ;out6
+    packssdw                m1, m3                       ;-out9
+    mova [rsp+gprsize*2+16* 9], m0
+    mova                    m0, [rsp+gprsize*2+16* 7]
+    mova                    m4, [rsp+gprsize*2+16*12]
+    punpcklwd               m3, m0, m4
+    punpckhwd               m0, m4
+    pmaddwd                 m4, m5, m3
+    pmaddwd                 m3, m6
+    pmaddwd                 m5, m0
+    pmaddwd                 m0, m6
+    REPX         {paddd x, m7}, m4, m3, m5, m0
+    REPX         {psrad x, 12}, m4, m5, m3, m0
+    packssdw                m4, m5                       ;out4
+    packssdw                m3, m0                       ;-out11
+    mova [rsp+gprsize*2+16* 7], m4
+    mova                    m4, [rsp+gprsize*2+16*10]
+    mova                    m5, [rsp+gprsize*2+16*11]
+    punpcklwd               m0, m4, m5
+    punpckhwd               m4, m5
+    pmaddwd                 m5, m0, [o(pw_2896_2896)]
+    pmaddwd                 m0, m6
+    pmaddwd                 m6, m4
+    pmaddwd                 m4, [o(pw_2896_2896)]
+    REPX         {paddd x, m7}, m5, m0, m6, m4
+    REPX         {psrad x, 12}, m0, m6, m5, m4
+    packssdw                m0, m6                       ;out8
+    packssdw                m5, m4                       ;-out7
+    mova [rsp+gprsize*2+16*10], m5
+    mova                    m4, [rsp+gprsize*2+16* 2]    ;out12
+    mova                    m5, [rsp+gprsize*2+16*14]    ;-out13
+    mova                    m6, [rsp+gprsize*2+16*15]    ;out14
+    ret
+ALIGN function_align
+cglobal_label .main_pass2_end
+    mova                    m7, [o(pw_2896x8)]
+    mova                    m1, [rsp+gprsize*2+16* 9]
+    mova                    m2, [rsp+gprsize*2+16*14]
+    paddsw                  m0, m1, m2
+    psubsw                  m1, m2
+    pmulhrsw                m0, m7                       ;out6
+    pmulhrsw                m1, m7                       ;-out9
+    mova [rsp+gprsize*2+16* 9], m0
+    psubsw                  m2, m3, m4
+    paddsw                  m3, m4
+    pmulhrsw                m2, m7                       ;out10
+    pmulhrsw                m3, m7                       ;-out5
+    mova [rsp+gprsize*2+16* 8], m3
+    mova                    m3, [rsp+gprsize*2+16* 7]
+    mova                    m4, [rsp+gprsize*2+16*12]
+    paddsw                  m0, m3, m4
+    psubsw                  m3, m4
+    pmulhrsw                m0, m7                       ;out4
+    pmulhrsw                m3, m7                       ;-out11
+    mova [rsp+gprsize*2+16* 7], m0
+    mova                    m0, [rsp+gprsize*2+16*10]
+    paddsw                  m4, m0, [rsp+gprsize*2+16*11]
+    psubsw                  m0, [rsp+gprsize*2+16*11]
+    pmulhrsw                m4, m7                       ;-out7
+    pmulhrsw                m0, m7                       ;out8
+    mova [rsp+gprsize*2+16*10], m4
+    mova                    m4, [rsp+gprsize*2+16*2 ]    ;out12
+    ret
+
+INV_TXFM_16X8_FN flipadst, dct
+INV_TXFM_16X8_FN flipadst, adst
+INV_TXFM_16X8_FN flipadst, flipadst
+INV_TXFM_16X8_FN flipadst, identity
+
+cglobal iflipadst_16x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mova                    m7, [o(pw_2896x8)]
+    pmulhrsw                m0, m7, [coeffq+16*0 ]
+    pmulhrsw                m1, m7, [coeffq+16*1 ]
+    pmulhrsw                m2, m7, [coeffq+16*14]
+    pmulhrsw                m3, m7, [coeffq+16*15]
+    mova    [rsp+gprsize+16*7], m0
+    mova    [rsp+gprsize+16*8], m1
+    mova    [rsp+gprsize+16*9], m2
+    mova    [rsp+gprsize+32*5], m3
+    pmulhrsw                m0, m7, [coeffq+16*6 ]
+    pmulhrsw                m1, m7, [coeffq+16*7 ]
+    pmulhrsw                m2, m7, [coeffq+16*8 ]
+    pmulhrsw                m3, m7, [coeffq+16*9 ]
+    mova    [rsp+gprsize+16*3], m2
+    mova    [rsp+gprsize+16*4], m3
+    mova    [rsp+gprsize+16*5], m0
+    mova    [rsp+gprsize+16*6], m1
+    pmulhrsw                m0, m7, [coeffq+16*2 ]
+    pmulhrsw                m1, m7, [coeffq+16*3 ]
+    pmulhrsw                m2, m7, [coeffq+16*4 ]
+    pmulhrsw                m3, m7, [coeffq+16*5 ]
+    pmulhrsw                m4, m7, [coeffq+16*10]
+    pmulhrsw                m5, m7, [coeffq+16*11]
+    pmulhrsw                m6, m7, [coeffq+16*12]
+    pmulhrsw                m7,     [coeffq+16*13]
+
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass1_end
+
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS     coeffq+16*0, 32
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    mov                     r3, tx2q
+    lea                   tx2q, [o(.pass1_end)]
+    jmp m(iflipadst_8x8_internal_8bpc).pass1_end
+
+.pass1_end:
+    SAVE_8ROWS     coeffq+16*1, 32
+    LOAD_8ROWS     coeffq+16*0, 32
+    mova    [rsp+gprsize+16*0], m7
+    mov                   tx2q, r3
+    jmp m(iflipadst_8x8_internal_8bpc).pass1_end
+
+.pass2:
+    lea                   tx2q, [o(.end)]
+    lea                     r3, [dstq+8]
+    jmp m(iflipadst_8x8_internal_8bpc).pass2_main
+
+.end:
+    LOAD_8ROWS     coeffq+16*1, 32
+    lea                   tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    mov                   dstq, r3
+    jmp m(iflipadst_8x8_internal_8bpc).pass2_main
+
+
+INV_TXFM_16X8_FN identity, dct
+INV_TXFM_16X8_FN identity, adst
+INV_TXFM_16X8_FN identity, flipadst
+INV_TXFM_16X8_FN identity, identity
+
+cglobal iidentity_16x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    add                coeffq, 16*16
+    mova                   m4, [coeffq-16*7]
+    mova                   m5, [coeffq-16*5]
+    mova                   m6, [coeffq-16*3]
+    mova                   m7, [coeffq-16*1]
+    mov                    r3, tx2q
+    lea                  tx2q, [o(.pass1_end)]
+
+.pass1:
+    mova                   m0, [o(pw_2896x8)]
+    mova                   m2, [o(pw_1697x16)]
+    mova                   m3, [o(pw_16384)]
+    sub                coeffq, 8*16
+    REPX     {pmulhrsw x, m0}, m4, m5, m6, m7
+    pmulhrsw               m1, m2, m4
+    pmulhrsw               m1, m3
+    paddsw                 m1, m4 ; 1
+    pmulhrsw               m4, m2, m5
+    pmulhrsw               m4, m3
+    paddsw                 m4, m5 ; 3
+    pmulhrsw               m5, m2, m6
+    pmulhrsw               m5, m3
+    paddsw                 m5, m6 ; 5
+    pmulhrsw               m6, m2, m7
+    pmulhrsw               m6, m3
+    paddsw                 m7, m6 ; 7
+    pmulhrsw               m6, m0, [coeffq+16*6]
+    mova   [rsp+gprsize+16*0], m4
+    pmulhrsw               m4, m2, m6
+    pmulhrsw               m4, m3
+    paddsw                 m6, m4 ; 6
+    pmulhrsw               m4, m0, [coeffq+16*4]
+    mova   [rsp+gprsize+16*1], m6
+    pmulhrsw               m6, m2, m4
+    pmulhrsw               m6, m3
+    paddsw                 m4, m6 ; 4
+    pmulhrsw               m6, m0, [coeffq+16*2]
+    pmulhrsw               m0,     [coeffq+16*0]
+    pmulhrsw               m2, m6
+    pmulhrsw               m2, m3
+    paddsw                 m2, m6 ; 2
+    pmulhrsw               m6, m0, [o(pw_1697x16)]
+    pmulhrsw               m6, m3
+    mova                   m3, [rsp+gprsize+16*0]
+    paddsw                 m0, m6
+    jmp   m(idct_8x8_internal_8bpc).pass1_end3
+
+.pass1_end:
+    mova        [coeffq+16*1], m4
+    mova        [coeffq+16*3], m5
+    mova        [coeffq+16*5], m6
+    mova        [coeffq+16*7], m7
+    mova                   m4, [coeffq-16*7]
+    mova                   m5, [coeffq-16*5]
+    mova                   m6, [coeffq-16*3]
+    mova                   m7, [coeffq-16*1]
+    mova        [coeffq-16*7], m0
+    mova        [coeffq-16*5], m1
+    mova        [coeffq-16*3], m2
+    mova        [coeffq-16*1], m3
+    mov                  tx2q, r3
+    jmp .pass1
+
+.pass2:
+    lea                  tx2q, [o(.end)]
+    lea                    r3, [dstq+8]
+    jmp  m(iidentity_8x8_internal_8bpc).end
+
+.end:
+    LOAD_8ROWS    coeffq+16*1, 32
+    lea                  tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    mov                  dstq, r3
+    jmp  m(iidentity_8x8_internal_8bpc).end
+
+
+%macro INV_TXFM_16X16_FN 2 ; type1, type2
+    INV_TXFM_FN          %1, %2, 16x16, 8, 16*16
+%ifidn %1_%2, dct_dct
+    movd                   m1, [o(pw_2896x8)]
+    pmulhrsw               m0, m1, [coeffq]
+    movd                   m2, [o(pw_8192)]
+    mov              [coeffq], eobd
+    mov                   r2d, 8
+    lea                  tx2q, [o(m(inv_txfm_add_dct_dct_16x16_8bpc).end)]
+    jmp m(inv_txfm_add_dct_dct_16x4_8bpc).dconly
+.end:
+    RET
+%endif
+%endmacro
+
+INV_TXFM_16X16_FN dct, dct
+INV_TXFM_16X16_FN dct, adst
+INV_TXFM_16X16_FN dct, flipadst
+INV_TXFM_16X16_FN dct, identity
+
+cglobal idct_16x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS     coeffq+16*1, 64
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+16*3, 64
+    call m(idct_16x8_internal_8bpc).main
+    mov                     r3, tx2q
+    lea                   tx2q, [o(.pass1_end)]
+    mova                    m7, [o(pw_8192)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end:
+    SAVE_8ROWS    coeffq+16*17, 32
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end1)]
+    mova                    m7, [o(pw_8192)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+16*1, 32
+    LOAD_8ROWS     coeffq+16*0, 64
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+16*2, 64
+    call m(idct_16x8_internal_8bpc).main
+    lea                   tx2q, [o(.pass1_end2)]
+    mova                    m7, [o(pw_8192)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end2:
+    SAVE_8ROWS    coeffq+16*16, 32
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    mov                   tx2q, r3
+    mova                    m7, [o(pw_8192)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass2:
+    lea                   tx2q, [o(.end)]
+    jmp  m(idct_8x16_internal_8bpc).pass2_pre
+
+.end:
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.end1)]
+    mov                   dstq, r3
+    lea                     r3, [dstq+8]
+    jmp   m(idct_8x8_internal_8bpc).end
+
+.end1:
+    pxor                    m7, m7
+    REPX   {mova [coeffq+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15
+
+    add                 coeffq, 32*8
+    mov                   dstq, r3
+
+    mova                    m0, [coeffq+16*0 ]
+    mova                    m1, [coeffq+16*4 ]
+    mova                    m2, [coeffq+16*8 ]
+    mova                    m3, [coeffq+16*12]
+    mova                    m4, [coeffq+16*1 ]
+    mova                    m5, [coeffq+16*5 ]
+    mova                    m6, [coeffq+16*9 ]
+    mova                    m7, [coeffq+16*13]
+    lea                   tx2q, [o(m(idct_8x16_internal_8bpc).end)]
+    jmp  m(idct_8x16_internal_8bpc).pass2_main
+
+
+%macro ITX_16X16_ADST_LOAD_ODD_COEFS 0
+    mova                    m0, [coeffq+16*1 ]
+    mova                    m1, [coeffq+16*3 ]
+    mova                    m2, [coeffq+16*29]
+    mova                    m3, [coeffq+16*31]
+    mova    [rsp+gprsize+16*7], m0
+    mova    [rsp+gprsize+16*8], m1
+    mova    [rsp+gprsize+16*9], m2
+    mova    [rsp+gprsize+32*5], m3
+    mova                    m0, [coeffq+16*13]
+    mova                    m1, [coeffq+16*15]
+    mova                    m2, [coeffq+16*17]
+    mova                    m3, [coeffq+16*19]
+    mova    [rsp+gprsize+16*3], m2
+    mova    [rsp+gprsize+16*4], m3
+    mova    [rsp+gprsize+16*5], m0
+    mova    [rsp+gprsize+16*6], m1
+    mova                    m0, [coeffq+16*5 ]
+    mova                    m1, [coeffq+16*7 ]
+    mova                    m2, [coeffq+16*9 ]
+    mova                    m3, [coeffq+16*11]
+    mova                    m4, [coeffq+16*21]
+    mova                    m5, [coeffq+16*23]
+    mova                    m6, [coeffq+16*25]
+    mova                    m7, [coeffq+16*27]
+%endmacro
+
+%macro ITX_16X16_ADST_LOAD_EVEN_COEFS 0
+    mova                    m0, [coeffq+16*0 ]
+    mova                    m1, [coeffq+16*2 ]
+    mova                    m2, [coeffq+16*28]
+    mova                    m3, [coeffq+16*30]
+    mova    [rsp+gprsize+16*7], m0
+    mova    [rsp+gprsize+16*8], m1
+    mova    [rsp+gprsize+16*9], m2
+    mova    [rsp+gprsize+32*5], m3
+    mova                    m0, [coeffq+16*12]
+    mova                    m1, [coeffq+16*14]
+    mova                    m2, [coeffq+16*16]
+    mova                    m3, [coeffq+16*18]
+    mova    [rsp+gprsize+16*3], m2
+    mova    [rsp+gprsize+16*4], m3
+    mova    [rsp+gprsize+16*5], m0
+    mova    [rsp+gprsize+16*6], m1
+    mova                    m0, [coeffq+16*4 ]
+    mova                    m1, [coeffq+16*6 ]
+    mova                    m2, [coeffq+16*8 ]
+    mova                    m3, [coeffq+16*10]
+    mova                    m4, [coeffq+16*20]
+    mova                    m5, [coeffq+16*22]
+    mova                    m6, [coeffq+16*24]
+    mova                    m7, [coeffq+16*26]
+%endmacro
+
+INV_TXFM_16X16_FN adst, dct
+INV_TXFM_16X16_FN adst, adst
+INV_TXFM_16X16_FN adst, flipadst
+
+cglobal iadst_16x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    ITX_16X16_ADST_LOAD_ODD_COEFS
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass1_end
+
+    mov                     r3, tx2q
+    lea                   tx2q, [o(.pass1_end)]
+    mova                    m7, [o(pw_8192)]
+    jmp  m(iadst_8x8_internal_8bpc).pass1_end1
+
+.pass1_end:
+    SAVE_8ROWS    coeffq+16*17, 32
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end1)]
+    mova                    m7, [o(pw_8192)]
+    jmp  m(iadst_8x8_internal_8bpc).pass1_end1
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+16*1, 32
+    ITX_16X16_ADST_LOAD_EVEN_COEFS
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass1_end
+
+    lea                   tx2q, [o(.pass1_end2)]
+    mova                    m7, [o(pw_8192)]
+    jmp  m(iadst_8x8_internal_8bpc).pass1_end1
+
+.pass1_end2:
+    SAVE_8ROWS    coeffq+16*16, 32
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    mov                   tx2q, r3
+    mova                    m7, [o(pw_8192)]
+    jmp  m(iadst_8x8_internal_8bpc).pass1_end1
+
+.pass2:
+    lea                   tx2q, [o(.end)]
+    jmp m(iadst_8x16_internal_8bpc).pass2_pre
+
+.end:
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.end1)]
+    mov                   dstq, r3
+    lea                     r3, [dstq+8]
+    jmp  m(iadst_8x8_internal_8bpc).end
+
+.end1:
+    pxor                    m7, m7
+    REPX   {mova [coeffq+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15
+
+    add                 coeffq, 32*8
+    mov                   dstq, r3
+
+    mova                    m4, [coeffq+16*0 ]
+    mova                    m5, [coeffq+16*2 ]
+    mova                    m0, [coeffq+16*4 ]
+    mova                    m1, [coeffq+16*6 ]
+    mova                    m2, [coeffq+16*8 ]
+    mova                    m3, [coeffq+16*10]
+    mova                    m6, [coeffq+16*12]
+    mova                    m7, [coeffq+16*14]
+    mova    [rsp+gprsize+16*7], m4
+    mova    [rsp+gprsize+16*8], m5
+    mova    [rsp+gprsize+16*5], m6
+    mova    [rsp+gprsize+16*6], m7
+    lea                   tx2q, [o(m(iadst_8x16_internal_8bpc).end)]
+    jmp m(iadst_8x16_internal_8bpc).pass2_main
+
+
+INV_TXFM_16X16_FN flipadst, dct
+INV_TXFM_16X16_FN flipadst, adst
+INV_TXFM_16X16_FN flipadst, flipadst
+
+cglobal iflipadst_16x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    ITX_16X16_ADST_LOAD_ODD_COEFS
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass1_end
+
+    mov                     r3, tx2q
+    lea                   tx2q, [o(.pass1_end)]
+    mova                    m7, [o(pw_m8192)]
+    jmp  m(iflipadst_8x8_internal_8bpc).pass1_end1
+
+.pass1_end:
+    SAVE_8ROWS     coeffq+16*1, 32
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end1)]
+    mova                    m7, [o(pw_m8192)]
+    jmp  m(iflipadst_8x8_internal_8bpc).pass1_end1
+
+.pass1_end1:
+    SAVE_8ROWS    coeffq+16*17, 32
+    ITX_16X16_ADST_LOAD_EVEN_COEFS
+    call m(iadst_16x8_internal_8bpc).main
+    call m(iadst_16x8_internal_8bpc).main_pass1_end
+
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS     coeffq+16*0, 32
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end2)]
+    mova                    m7, [o(pw_m8192)]
+    jmp  m(iflipadst_8x8_internal_8bpc).pass1_end1
+
+.pass1_end2:
+    SAVE_8ROWS    coeffq+16*16, 32
+    LOAD_8ROWS    coeffq+16* 0, 32
+    mova    [rsp+gprsize+16*0], m7
+    mov                   tx2q, r3
+    mova                    m7, [o(pw_m8192)]
+    jmp m(iflipadst_8x8_internal_8bpc).pass1_end1
+
+.pass2:
+    lea                   tx2q, [o(.end)]
+    lea                     r3, [dstq+8]
+    jmp m(iflipadst_8x16_internal_8bpc).pass2_pre
+
+.end:
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.end1)]
+    lea                   dstq, [dstq+strideq*2]
+    jmp  m(iflipadst_8x8_internal_8bpc).end
+
+.end1:
+    pxor                    m7, m7
+    REPX   {mova [coeffq+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15
+
+    add                 coeffq, 32*8
+
+    mova                    m4, [coeffq+16*0 ]
+    mova                    m5, [coeffq+16*2 ]
+    mova                    m0, [coeffq+16*4 ]
+    mova                    m1, [coeffq+16*6 ]
+    mova                    m2, [coeffq+16*8 ]
+    mova                    m3, [coeffq+16*10]
+    mova                    m6, [coeffq+16*12]
+    mova                    m7, [coeffq+16*14]
+    mova    [rsp+gprsize+16*7], m4
+    mova    [rsp+gprsize+16*8], m5
+    mova    [rsp+gprsize+16*5], m6
+    mova    [rsp+gprsize+16*6], m7
+
+    lea                   tx2q, [o(.end2)]
+    mov                   dstq, r3
+    jmp m(iflipadst_8x16_internal_8bpc).pass2_main
+
+.end2:
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    lea                   dstq, [dstq+strideq*2]
+    jmp  m(iflipadst_8x8_internal_8bpc).end
+
+
+%macro IDTX16B 3 ; src/dst, tmp, pw_1697x16
+    pmulhrsw            m%2, m%3, m%1
+    psraw               m%2, 1
+    pavgw               m%1, m%2
+%endmacro
+
+INV_TXFM_16X16_FN identity, dct
+INV_TXFM_16X16_FN identity, identity
+
+cglobal iidentity_16x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    add                 coeffq, 16*17
+    mov                     r3, tx2q
+    lea                   tx2q, [o(.pass1_end)]
+
+.pass1:
+    mova                    m6, [o(pw_1697x16)]
+    mova                    m7, [coeffq+32*6]
+    mova                    m0, [coeffq+32*0]
+    mova                    m1, [coeffq+32*1]
+    mova                    m2, [coeffq+32*2]
+    mova                    m3, [coeffq+32*3]
+    mova                    m4, [coeffq+32*4]
+    REPX     {IDTX16B x, 5, 6}, 7, 0, 1, 2, 3, 4
+    mova                    m5, [coeffq+32*5]
+    mova    [rsp+gprsize+16*1], m7
+    IDTX16B                  5, 7, 6
+    mova                    m7, [coeffq+32*7]
+    IDTX16B                  7, 6, 6
+    jmp   m(idct_8x8_internal_8bpc).pass1_end3
+
+.pass1_end:
+    SAVE_8ROWS          coeffq, 32
+    sub                 coeffq, 16
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp .pass1
+
+.pass1_end1:
+    SAVE_8ROWS          coeffq, 32
+    sub                 coeffq, 15*16
+    lea                   tx2q, [o(.pass1_end2)]
+    jmp .pass1
+
+.pass1_end2:
+    SAVE_8ROWS          coeffq, 32
+    sub                 coeffq, 16
+    mov                   tx2q, r3
+    jmp .pass1
+
+.pass2:
+    lea                     r3, [dstq+8]
+    lea                   tx2q, [o(.end1)]
+
+.end:
+    mova    [rsp+gprsize+16*0], m7
+    mova    [rsp+gprsize+16*1], m4
+    mova                    m7, [o(pw_1697x16)]
+    REPX      {IDTX16 x, 4, 7}, 5, 6, 0, 1, 2, 3
+    mova                    m4, [o(pw_2048)]
+    pmulhrsw                m5, m4
+    pmulhrsw                m6, m4
+    mova    [rsp+gprsize+16*2], m5
+    mova                    m5, [rsp+gprsize+16*1]
+    mova    [rsp+gprsize+16*1], m6
+    IDTX16                   5, 6, 7
+    mova                    m6, [rsp+gprsize+16*0]
+    IDTX16                   6, 7, 7
+    REPX      {pmulhrsw x, m4}, m0, m1, m2, m3, m6
+    pmulhrsw                m4, m5
+    mova    [rsp+gprsize+16*0], m6
+    jmp   m(idct_8x8_internal_8bpc).end3
+
+.end1:
+    LOAD_8ROWS     coeffq+16*1, 32
+    lea                   tx2q, [o(.end2)]
+    lea                   dstq, [dstq+strideq*2]
+    jmp .end
+
+.end2:
+    pxor                    m7, m7
+    REPX   {mova [coeffq+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15
+
+    add                 coeffq, 32*8
+    LOAD_8ROWS          coeffq, 32
+    lea                   tx2q, [o(.end3)]
+    mov                   dstq, r3
+    jmp .end
+
+.end3:
+    LOAD_8ROWS     coeffq+16*1, 32
+    lea                   tx2q, [o(m(idct_8x16_internal_8bpc).end1)]
+    lea                   dstq, [dstq+strideq*2]
+    jmp .end
+
+
+cglobal inv_txfm_add_dct_dct_8x32_8bpc, 4, 6, 8, 16*36, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+    call  m(idct_8x32_internal_8bpc)
+    RET
+
+.dconly:
+    movd                 m1, [o(pw_2896x8)]
+    pmulhrsw             m0, m1, [coeffq]
+    movd                 m2, [o(pw_8192)]
+    mov            [coeffq], eobd
+    pmulhrsw             m0, m2
+    psrlw                m2, 2            ;pw_2048
+    pmulhrsw             m0, m1
+    pmulhrsw             m0, m2
+    pshuflw              m0, m0, q0000
+    punpcklwd            m0, m0
+    mov                 r3d, 8
+    lea                tx2q, [o(.end)]
+    jmp m(inv_txfm_add_dct_dct_8x8_8bpc).loop
+
+.end:
+    RET
+
+
+
+cglobal idct_8x32_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    cmp                   eobd, 106
+    jle .fast
+
+    LOAD_8ROWS     coeffq+16*3, 64
+    call  m(idct_8x8_internal_8bpc).main
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1:
+    mova   [rsp+gprsize+16*9 ], m0                        ;in24
+    mova   [rsp+gprsize+16*10], m4                        ;in28
+    mova   [rsp+gprsize+16*17], m2                        ;in26
+    mova   [rsp+gprsize+16*18], m6                        ;in30
+    mova   [rsp+gprsize+16*31], m1                        ;in25
+    mova   [rsp+gprsize+16*30], m3                        ;in27
+    mova   [rsp+gprsize+16*27], m5                        ;in29
+    mova   [rsp+gprsize+16*34], m7                        ;in31
+    LOAD_8ROWS     coeffq+16*2, 64
+    call  m(idct_8x8_internal_8bpc).main
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_1:
+    mova   [rsp+gprsize+16*7 ], m0                        ;in16
+    mova   [rsp+gprsize+16*8 ], m4                        ;in20
+    mova   [rsp+gprsize+16*15], m2                        ;in18
+    mova   [rsp+gprsize+16*16], m6                        ;in22
+    mova   [rsp+gprsize+16*33], m1                        ;in17
+    mova   [rsp+gprsize+16*28], m3                        ;in19
+    mova   [rsp+gprsize+16*29], m5                        ;in21
+    mova   [rsp+gprsize+16*32], m7                        ;in23
+
+.fast:
+    LOAD_8ROWS     coeffq+16*1, 64
+    call  m(idct_8x8_internal_8bpc).main
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end:
+    mova   [rsp+gprsize+16*5 ], m0                        ;in8
+    mova   [rsp+gprsize+16*6 ], m4                        ;in12
+    mova   [rsp+gprsize+16*13], m2                        ;in10
+    mova   [rsp+gprsize+16*14], m6                        ;in14
+    mova   [rsp+gprsize+16*21], m1                        ;in9
+    mova   [rsp+gprsize+16*24], m3                        ;in11
+    mova   [rsp+gprsize+16*25], m5                        ;in13
+    mova   [rsp+gprsize+16*20], m7                        ;in15
+    LOAD_8ROWS     coeffq+16*0, 64
+    call  m(idct_8x8_internal_8bpc).main
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end1:
+    mova   [rsp+gprsize+16*11], m2                        ;in2
+    mova   [rsp+gprsize+16*12], m6                        ;in6
+    mova   [rsp+gprsize+16*19], m1                        ;in1
+    mova   [rsp+gprsize+16*26], m3                        ;in3
+    mova   [rsp+gprsize+16*23], m5                        ;in5
+    mova   [rsp+gprsize+16*22], m7                        ;in7
+    mova                    m1, m4                        ;in4
+    mova                    m2, [rsp+gprsize+16*5 ]       ;in8
+    mova                    m3, [rsp+gprsize+16*6 ]       ;in12
+
+    cmp                   eobd, 106
+    jg .full
+
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS   rsp+gprsize+16*3 , 16
+    mova                    m0, [rsp+gprsize+16*11]
+    mova                    m1, [rsp+gprsize+16*12]
+    mova                    m2, [rsp+gprsize+16*13]
+    mova                    m3, [rsp+gprsize+16*14]
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    call .main_fast
+    jmp  .pass2
+
+.full:
+    mova                    m4, [rsp+gprsize+16*7 ]       ;in16
+    mova                    m5, [rsp+gprsize+16*8 ]       ;in20
+    mova                    m6, [rsp+gprsize+16*9 ]       ;in24
+    mova                    m7, [rsp+gprsize+16*10]       ;in28
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS   rsp+gprsize+16*3 , 16
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+    call .main
+
+.pass2:
+    lea                     r3, [o(.end6)]
+
+.end:
+    mova   [rsp+gprsize+16*0 ], m7
+    lea                   tx2q, [o(.end2)]
+
+.end1:
+    pxor                    m7, m7
+    REPX   {mova [coeffq+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7,  \
+                                     8,  9,  10, 11, 12, 13, 14, 15, \
+                                     16, 17, 18, 19, 20, 21, 22, 23, \
+                                     24, 25, 26, 27, 28, 29, 30, 31
+
+    jmp                   tx2q
+
+.end2:
+    lea                   tx2q, [o(.end3)]
+    jmp   m(idct_8x8_internal_8bpc).end
+
+.end3:
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    lea                   dstq, [dstq+strideq*2]
+    lea                   tx2q, [o(.end4)]
+    jmp   m(idct_8x8_internal_8bpc).end
+
+.end4:
+    LOAD_8ROWS   rsp+gprsize+16*19, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    lea                   dstq, [dstq+strideq*2]
+    lea                   tx2q, [o(.end5)]
+    jmp   m(idct_8x8_internal_8bpc).end
+
+.end5:
+    LOAD_8ROWS   rsp+gprsize+16*27, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    lea                   dstq, [dstq+strideq*2]
+    mov                   tx2q, r3
+    jmp   m(idct_8x8_internal_8bpc).end
+
+.end6:
+    ret
+
+ALIGN function_align
+cglobal_label .main_veryfast
+    mova                    m0, [rsp+gprsize*2+16*19]     ;in1
+    pmulhrsw                m3, m0, [o(pw_4091x8)]        ;t30,t31
+    pmulhrsw                m0, [o(pw_201x8)]             ;t16,t17
+    mova                    m7, [o(pd_2048)]
+    mova [rsp+gprsize*2+16*19], m0                        ;t16
+    mova [rsp+gprsize*2+16*34], m3                        ;t31
+    ITX_MULSUB_2W            3, 0, 1, 2, 7,  799, 4017    ;t17a, t30a
+    mova [rsp+gprsize*2+16*20], m3                        ;t17a
+    mova [rsp+gprsize*2+16*33], m0                        ;t30a
+    mova                    m1, [rsp+gprsize*2+16*22]     ;in7
+    pmulhrsw                m2, m1, [o(pw_3857x8)]        ;t28,t29
+    pmulhrsw                m1, [o(pw_m1380x8)]           ;t18,t19
+    mova [rsp+gprsize*2+16*22], m1                        ;t19
+    mova [rsp+gprsize*2+16*31], m2                        ;t28
+    ITX_MULSUB_2W            2, 1, 0, 3, 7, m4017, 799    ;t18a, t29a
+    mova [rsp+gprsize*2+16*21], m2                        ;t18a
+    mova [rsp+gprsize*2+16*32], m1                        ;t29a
+    mova                    m0, [rsp+gprsize*2+16*23]     ;in5
+    pmulhrsw                m3, m0, [o(pw_3973x8)]        ;t26, t27
+    pmulhrsw                m0, [o(pw_995x8)]             ;t20, t21
+    mova [rsp+gprsize*2+16*23], m0                        ;t20
+    mova [rsp+gprsize*2+16*30], m3                        ;t27
+    ITX_MULSUB_2W            3, 0, 1, 2, 7, 3406, 2276    ;t21a, t26a
+    mova [rsp+gprsize*2+16*24], m3                        ;t21a
+    mova [rsp+gprsize*2+16*29], m0                        ;t26a
+    mova                    m2, [rsp+gprsize*2+16*26]     ;in3
+    pxor                    m0, m0
+    mova                    m3, m0
+    pmulhrsw                m1, m2, [o(pw_4052x8)]
+    pmulhrsw                m2, [o(pw_m601x8)]
+    jmp .main2
+
+ALIGN function_align
+cglobal_label .main_fast ;bottom half is zero
+    mova                    m0, [rsp+gprsize*2+16*19]     ;in1
+    mova                    m1, [rsp+gprsize*2+16*20]     ;in15
+    pmulhrsw                m3, m0, [o(pw_4091x8)]        ;t31a
+    pmulhrsw                m0, [o(pw_201x8)]             ;t16a
+    pmulhrsw                m2, m1, [o(pw_3035x8)]        ;t30a
+    pmulhrsw                m1, [o(pw_m2751x8)]           ;t17a
+    mova                    m7, [o(pd_2048)]
+    psubsw                  m4, m0, m1                    ;t17
+    paddsw                  m0, m1                        ;t16
+    psubsw                  m5, m3, m2                    ;t30
+    paddsw                  m3, m2                        ;t31
+    ITX_MULSUB_2W            5, 4, 1, 2, 7,  799, 4017    ;t17a, t30a
+    mova [rsp+gprsize*2+16*19], m0                        ;t16
+    mova [rsp+gprsize*2+16*20], m5                        ;t17a
+    mova [rsp+gprsize*2+16*33], m4                        ;t30a
+    mova [rsp+gprsize*2+16*34], m3                        ;t31
+    mova                    m0, [rsp+gprsize*2+16*21]     ;in9
+    mova                    m1, [rsp+gprsize*2+16*22]     ;in7
+    pmulhrsw                m3, m0, [o(pw_3703x8)]
+    pmulhrsw                m0, [o(pw_1751x8)]
+    pmulhrsw                m2, m1, [o(pw_3857x8)]
+    pmulhrsw                m1, [o(pw_m1380x8)]
+    psubsw                  m4, m1, m0                    ;t18
+    paddsw                  m0, m1                        ;t19
+    psubsw                  m5, m2, m3                    ;t29
+    paddsw                  m3, m2                        ;t28
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, m4017, 799    ;t18a, t29a
+    mova [rsp+gprsize*2+16*21], m5                        ;t18a
+    mova [rsp+gprsize*2+16*22], m0                        ;t19
+    mova [rsp+gprsize*2+16*31], m3                        ;t28
+    mova [rsp+gprsize*2+16*32], m4                        ;t29a
+    mova                    m0, [rsp+gprsize*2+16*23]     ;in5
+    mova                    m1, [rsp+gprsize*2+16*24]     ;in11
+    pmulhrsw                m3, m0, [o(pw_3973x8)]
+    pmulhrsw                m0, [o(pw_995x8)]
+    pmulhrsw                m2, m1, [o(pw_3513x8)]
+    pmulhrsw                m1, [o(pw_m2106x8)]
+    psubsw                  m4, m0, m1                    ;t21
+    paddsw                  m0, m1                        ;t20
+    psubsw                  m5, m3, m2                    ;t26
+    paddsw                  m3, m2                        ;t27
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, 3406, 2276    ;t21a, t26a
+    mova [rsp+gprsize*2+16*23], m0                        ;t20
+    mova [rsp+gprsize*2+16*24], m5                        ;t21a
+    mova [rsp+gprsize*2+16*29], m4                        ;t26a
+    mova [rsp+gprsize*2+16*30], m3                        ;t27
+    mova                    m0, [rsp+gprsize*2+16*25]     ;in13
+    mova                    m2, [rsp+gprsize*2+16*26]     ;in3
+    pmulhrsw                m3, m0, [o(pw_3290x8)]
+    pmulhrsw                m0, [o(pw_2440x8)]
+    pmulhrsw                m1, m2, [o(pw_4052x8)]
+    pmulhrsw                m2, [o(pw_m601x8)]
+    jmp .main2
+
+ALIGN function_align
+cglobal_label .main
+    mova                    m7, [o(pd_2048)]
+    mova                    m0, [rsp+gprsize*2+16*19]     ;in1
+    mova                    m1, [rsp+gprsize*2+16*20]     ;in15
+    mova                    m2, [rsp+gprsize*2+16*33]     ;in17
+    mova                    m3, [rsp+gprsize*2+16*34]     ;in31
+    ITX_MULSUB_2W            0, 3, 4, 5, 7,  201, 4091    ;t16a, t31a
+    ITX_MULSUB_2W            2, 1, 4, 5, 7, 3035, 2751    ;t17a, t30a
+    psubsw                  m4, m0, m2                    ;t17
+    paddsw                  m0, m2                        ;t16
+    psubsw                  m5, m3, m1                    ;t30
+    paddsw                  m3, m1                        ;t31
+    ITX_MULSUB_2W            5, 4, 1, 2, 7,  799, 4017    ;t17a, t30a
+    mova [rsp+gprsize*2+16*19], m0                        ;t16
+    mova [rsp+gprsize*2+16*20], m5                        ;t17a
+    mova [rsp+gprsize*2+16*33], m4                        ;t30a
+    mova [rsp+gprsize*2+16*34], m3                        ;t31
+    mova                    m0, [rsp+gprsize*2+16*21]     ;in9
+    mova                    m1, [rsp+gprsize*2+16*22]     ;in7
+    mova                    m2, [rsp+gprsize*2+16*31]     ;in25
+    mova                    m3, [rsp+gprsize*2+16*32]     ;in23
+    ITX_MULSUB_2W            0, 3, 4, 5, 7, 1751, 3703    ;t18a, t29a
+    ITX_MULSUB_2W            2, 1, 4, 5, 7, 3857, 1380    ;t19a, t28a
+    psubsw                  m4, m2, m0                    ;t18
+    paddsw                  m0, m2                        ;t19
+    psubsw                  m5, m1, m3                    ;t29
+    paddsw                  m3, m1                        ;t28
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, m4017, 799    ;t18a, t29a
+    mova [rsp+gprsize*2+16*21], m5                        ;t18a
+    mova [rsp+gprsize*2+16*22], m0                        ;t19
+    mova [rsp+gprsize*2+16*31], m3                        ;t28
+    mova [rsp+gprsize*2+16*32], m4                        ;t29a
+    mova                    m0, [rsp+gprsize*2+16*23]     ;in5
+    mova                    m1, [rsp+gprsize*2+16*24]     ;in11
+    mova                    m2, [rsp+gprsize*2+16*29]     ;in21
+    mova                    m3, [rsp+gprsize*2+16*30]     ;in27
+    ITX_MULSUB_2W            0, 3, 4, 5, 7,  995, 3973    ;t20a, t27a
+    ITX_MULSUB_2W            2, 1, 4, 5, 7, 3513, 2106    ;t21a, t26a
+    psubsw                  m4, m0, m2                    ;t21
+    paddsw                  m0, m2                        ;t20
+    psubsw                  m5, m3, m1                    ;t26
+    paddsw                  m3, m1                        ;t27
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, 3406, 2276    ;t21a, t26a
+    mova [rsp+gprsize*2+16*23], m0                        ;t20
+    mova [rsp+gprsize*2+16*24], m5                        ;t21a
+    mova [rsp+gprsize*2+16*29], m4                        ;t26a
+    mova [rsp+gprsize*2+16*30], m3                        ;t27
+    mova                    m0, [rsp+gprsize*2+16*25]     ;in13
+    mova                    m1, [rsp+gprsize*2+16*26]     ;in3
+    mova                    m2, [rsp+gprsize*2+16*27]     ;in29
+    mova                    m3, [rsp+gprsize*2+16*28]     ;in19
+    ITX_MULSUB_2W            0, 3, 4, 5, 7, 2440, 3290    ;t22a, t25a
+    ITX_MULSUB_2W            2, 1, 4, 5, 7, 4052,  601    ;t23a, t24a
+
+.main2:
+    psubsw                  m4, m2, m0                    ;t22
+    paddsw                  m0, m2                        ;t23
+    psubsw                  m5, m1, m3                    ;t25
+    paddsw                  m3, m1                        ;t24
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, m2276, 3406   ;t22a, t25a
+    mova                    m2, [rsp+gprsize*2+16*24]     ;t21a
+    psubsw                  m1, m5, m2                    ;t21
+    paddsw                  m5, m2                        ;t22
+    mova [rsp+gprsize*2+16*25], m5                        ;t22
+    mova                    m2, [rsp+gprsize*2+16*29]     ;t26a
+    psubsw                  m5, m4, m2                    ;t26
+    paddsw                  m4, m2                        ;t25
+    mova [rsp+gprsize*2+16*28], m4                        ;t25
+    ITX_MULSUB_2W            5, 1, 2, 4, 7, m3784, 1567   ;t21a, t26a
+    mova [rsp+gprsize*2+16*24], m5                        ;t21a
+    mova [rsp+gprsize*2+16*29], m1                        ;t26a
+
+    mova                    m1, [rsp+gprsize*2+16*23]     ;t20
+    mova                    m5, [rsp+gprsize*2+16*30]     ;t27
+    psubsw                  m2, m0, m1                    ;t20a
+    paddsw                  m0, m1                        ;t23a
+    psubsw                  m6, m3, m5                    ;t27a
+    paddsw                  m3, m5                        ;t24a
+    ITX_MULSUB_2W            6, 2, 1, 5, 7, m3784, 1567   ;t20, t27
+    mova [rsp+gprsize*2+16*26], m0                        ;t23a
+    mova [rsp+gprsize*2+16*27], m3                        ;t24a
+    mova [rsp+gprsize*2+16*30], m2                        ;t27
+
+    mova                    m0, [rsp+gprsize*2+16*20]     ;t17a
+    mova                    m1, [rsp+gprsize*2+16*21]     ;t18a
+    mova                    m2, [rsp+gprsize*2+16*32]     ;t29a
+    mova                    m3, [rsp+gprsize*2+16*33]     ;t30a
+    psubsw                  m4, m0, m1                    ;t18
+    paddsw                  m0, m1                        ;t17
+    psubsw                  m5, m3, m2                    ;t29
+    paddsw                  m3, m2                        ;t30
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, 1567, 3784    ;t18a, t29a
+    mova [rsp+gprsize*2+16*20], m0                        ;t17
+    mova [rsp+gprsize*2+16*21], m5                        ;t18a
+    mova [rsp+gprsize*2+16*32], m4                        ;t29a
+    mova [rsp+gprsize*2+16*33], m3                        ;t30
+    mova                    m0, [rsp+gprsize*2+16*19]     ;t16
+    mova                    m1, [rsp+gprsize*2+16*22]     ;t19
+    mova                    m2, [rsp+gprsize*2+16*31]     ;t28
+    mova                    m3, [rsp+gprsize*2+16*34]     ;t31
+    psubsw                  m4, m0, m1                    ;t19a
+    paddsw                  m0, m1                        ;t16a
+    psubsw                  m5, m3, m2                    ;t28a
+    paddsw                  m3, m2                        ;t31a
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, 1567, 3784    ;t19, t28
+    mova                    m2, [rsp+gprsize*2+16*15]     ;tmp12
+    psubsw                  m1, m5, m6                    ;t20a
+    paddsw                  m5, m6                        ;t19a
+    psubsw                  m6, m2, m5                    ;out19
+    paddsw                  m2, m5                        ;out12
+    mova                    m5, [rsp+gprsize*2+16*30]     ;t27
+    mova [rsp+gprsize*2+16*22], m6                        ;out19
+    mova [rsp+gprsize*2+16*15], m2                        ;out12
+    psubsw                  m6, m4, m5                    ;t27a
+    paddsw                  m4, m5                        ;t28a
+    ITX_MULSUB_2W            6, 1, 2, 5, 7, 2896, 2896    ;t20, t27
+    mova                    m2, [rsp+gprsize*2+16*6 ]     ;tmp3
+    psubsw                  m5, m2, m4                    ;out28
+    paddsw                  m2, m4                        ;out3
+    mova                    m4, [rsp+gprsize*2+16*14]     ;tmp11
+    mova [rsp+gprsize*2+16*31], m5                        ;out28
+    mova [rsp+gprsize*2+16*6 ], m2                        ;out3
+    psubsw                  m5, m4, m6                    ;out20
+    paddsw                  m4, m6                        ;out11
+    mova                    m2, [rsp+gprsize*2+16*7 ]     ;tmp4
+    mova [rsp+gprsize*2+16*23], m5                        ;out20
+    mova [rsp+gprsize*2+16*14], m4                        ;out11
+    psubsw                  m5, m2, m1                    ;out27
+    paddsw                  m2, m1                        ;out4
+    mova                    m1, [rsp+gprsize*2+16*26]     ;t23a
+    mova                    m4, [rsp+gprsize*2+16*27]     ;t24a
+    mova [rsp+gprsize*2+16*30], m5                        ;out27
+    mova [rsp+gprsize*2+16*7 ], m2                        ;out4
+    psubsw                  m5, m0, m1                    ;t23
+    paddsw                  m0, m1                        ;t16
+    psubsw                  m2, m3, m4                    ;t24
+    paddsw                  m3, m4                        ;t31
+    ITX_MULSUB_2W            2, 5, 4, 6, 7, 2896, 2896    ;t23a, t24a
+    mova                    m6, [rsp+gprsize*2+16*18]     ;tmp15
+    psubsw                  m4, m6, m0                    ;out16
+    paddsw                  m6, m0                        ;out15
+    mova                    m0, [rsp+gprsize*2+16*3 ]     ;tmp0
+    mova                    m1, [rsp+gprsize*2+16*11]     ;tmp8
+    mova [rsp+gprsize*2+16*18], m6                        ;out15
+    mova [rsp+gprsize*2+16*19], m4                        ;out16
+    psubsw                  m6, m0, m3                    ;out31
+    paddsw                  m0, m3                        ;out0
+    psubsw                  m4, m1, m2                    ;out23
+    paddsw                  m1, m2                        ;out8
+    mova                    m3, [rsp+gprsize*2+16*10]     ;tmp7
+    mova [rsp+gprsize*2+16*34], m6                        ;out31
+    mova [rsp+gprsize*2+16*11], m1                        ;out8
+    mova [rsp+gprsize*2+16*26], m4                        ;out23
+    paddsw                  m6, m3, m5                    ;out7
+    psubsw                  m3, m5                        ;out24
+    mova                    m1, [rsp+gprsize*2+16*20]     ;t17
+    mova                    m5, [rsp+gprsize*2+16*25]     ;t22
+    mova                    m2, [rsp+gprsize*2+16*17]     ;tmp14
+    mova [rsp+gprsize*2+16*27], m3                        ;out24
+    psubsw                  m4, m1, m5                    ;t22a
+    paddsw                  m1, m5                        ;t17a
+    psubsw                  m3, m2, m1                    ;out17
+    paddsw                  m2, m1                        ;out14
+    mova                    m5, [rsp+gprsize*2+16*28]     ;t25
+    mova                    m1, [rsp+gprsize*2+16*33]     ;t30
+    mova [rsp+gprsize*2+16*17], m2                        ;out14
+    mova [rsp+gprsize*2+16*20], m3                        ;out17
+    psubsw                  m2, m1, m5                    ;t25a
+    paddsw                  m1, m5                        ;t30a
+    ITX_MULSUB_2W            2, 4, 3, 5, 7, 2896, 2896    ;t22, t25
+    mova                    m5, [rsp+gprsize*2+16*4 ]     ;tmp1
+    psubsw                  m3, m5, m1                    ;out30
+    paddsw                  m5, m1                        ;out1
+    mova                    m1, [rsp+gprsize*2+16*12]     ;tmp9
+    mova [rsp+gprsize*2+16*33], m3                        ;out30
+    mova [rsp+gprsize*2+16*4 ], m5                        ;out1
+    psubsw                  m3, m1, m2                    ;out22
+    paddsw                  m1, m2                        ;out9
+    mova                    m5, [rsp+gprsize*2+16*9 ]     ;tmp6
+    mova [rsp+gprsize*2+16*25], m3                        ;out22
+    mova [rsp+gprsize*2+16*12], m1                        ;out9
+    psubsw                  m3, m5, m4                    ;out25
+    paddsw                  m5, m4                        ;out6
+    mova                    m4, [rsp+gprsize*2+16*21]     ;t18a
+    mova                    m1, [rsp+gprsize*2+16*24]     ;t21a
+    mova                    m2, [rsp+gprsize*2+16*16]     ;tmp13
+    mova [rsp+gprsize*2+16*28], m3                        ;out25
+    mova [rsp+gprsize*2+16*9 ], m5                        ;out6
+    paddsw                  m3, m4, m1                    ;t18
+    psubsw                  m4, m1                        ;t21
+    psubsw                  m5, m2, m3                    ;out18
+    paddsw                  m2, m3                        ;out13
+    mova                    m1, [rsp+gprsize*2+16*29]     ;t26a
+    mova                    m3, [rsp+gprsize*2+16*32]     ;t29a
+    mova [rsp+gprsize*2+16*21], m5                        ;out18
+    mova [rsp+gprsize*2+16*16], m2                        ;out13
+    psubsw                  m5, m3, m1                    ;t26
+    paddsw                  m3, m1                        ;t29
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, 2896, 2896    ;t21a, t26a
+    mova                    m2, [rsp+gprsize*2+16*5 ]     ;tmp2
+    psubsw                  m1, m2, m3                    ;out29
+    paddsw                  m2, m3                        ;out2
+    mova                    m3, [rsp+gprsize*2+16*13]     ;tmp10
+    mova [rsp+gprsize*2+16*32], m1                        ;out29
+    psubsw                  m7, m3, m5                    ;out21
+    paddsw                  m3, m5                        ;out10
+    mova                    m5, [rsp+gprsize*2+16*8 ]     ;tmp5
+    mova [rsp+gprsize*2+16*24], m7                        ;out21
+    mova [rsp+gprsize*2+16*13], m3                        ;out10
+    psubsw                  m1, m5, m4                    ;out26
+    paddsw                  m5, m4                        ;out5
+    mova                    m7, m6                        ;out7
+    mova                    m3, [rsp+gprsize*2+16*6 ]     ;out3
+    mova                    m4, [rsp+gprsize*2+16*7 ]     ;out4
+    mova [rsp+gprsize*2+16*29], m1                        ;out26
+    mova                    m6, [rsp+gprsize*2+16*9 ]     ;out6
+    mova                    m1, [rsp+gprsize*2+16*4 ]     ;out1
+    ret
+
+
+cglobal inv_txfm_add_dct_dct_32x8_8bpc, 4, 6, 8, 16*36, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+    call  m(idct_32x8_internal_8bpc)
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_8192)]
+    mov               [coeffq], eobd
+    mov                    r3d, 8
+    lea                   tx2q, [o(.end)]
+
+.body:
+    pmulhrsw                m0, m2
+    movd                    m2, [o(pw_2048)]  ;intentionally rip-relative
+    pmulhrsw                m0, m1
+    pmulhrsw                m0, m2
+    pshuflw                 m0, m0, q0000
+    punpcklwd               m0, m0
+    pxor                    m5, m5
+
+.loop:
+    mova                    m1, [dstq+16*0]
+    mova                    m3, [dstq+16*1]
+    punpckhbw               m2, m1, m5
+    punpcklbw               m1, m5
+    punpckhbw               m4, m3, m5
+    punpcklbw               m3, m5
+    paddw                   m2, m0
+    paddw                   m1, m0
+    paddw                   m4, m0
+    paddw                   m3, m0
+    packuswb                m1, m2
+    packuswb                m3, m4
+    mova           [dstq+16*0], m1
+    mova           [dstq+16*1], m3
+    add                   dstq, strideq
+    dec                    r3d
+    jg .loop
+    jmp                   tx2q
+
+.end:
+    RET
+
+
+cglobal idct_32x8_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS     coeffq+16*0, 64
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    LOAD_8ROWS     coeffq+16*2, 64
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    LOAD_8ROWS     coeffq+16*1, 32
+    mova   [rsp+gprsize+16*19], m0                        ;in1
+    mova   [rsp+gprsize+16*26], m1                        ;in3
+    mova   [rsp+gprsize+16*23], m2                        ;in5
+    mova   [rsp+gprsize+16*22], m3                        ;in7
+    mova   [rsp+gprsize+16*21], m4                        ;in9
+    mova   [rsp+gprsize+16*24], m5                        ;in11
+    mova   [rsp+gprsize+16*25], m6                        ;in13
+    mova   [rsp+gprsize+16*20], m7                        ;in15
+
+    cmp                   eobd, 106
+    jg  .full
+    call m(idct_8x32_internal_8bpc).main_fast
+    jmp .pass2
+
+.full:
+    LOAD_8ROWS    coeffq+16*17, 32
+    mova   [rsp+gprsize+16*33], m0                        ;in17
+    mova   [rsp+gprsize+16*28], m1                        ;in19
+    mova   [rsp+gprsize+16*29], m2                        ;in21
+    mova   [rsp+gprsize+16*32], m3                        ;in23
+    mova   [rsp+gprsize+16*31], m4                        ;in25
+    mova   [rsp+gprsize+16*30], m5                        ;in27
+    mova   [rsp+gprsize+16*27], m6                        ;in29
+    mova   [rsp+gprsize+16*34], m7                        ;in31
+    call m(idct_8x32_internal_8bpc).main
+
+.pass2:
+    mova   [rsp+gprsize+16*0 ], m7
+    lea                   tx2q, [o(.end)]
+    jmp  m(idct_8x32_internal_8bpc).end1
+
+.end:
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.end1:
+    lea                     r3, [dstq+8]
+    lea                   tx2q, [o(.end2)]
+    jmp   m(idct_8x8_internal_8bpc).pass2_main
+
+.end2:
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.end3)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.end3:
+    mov                   dstq, r3
+    add                     r3, 8
+    lea                   tx2q, [o(.end4)]
+    jmp   m(idct_8x8_internal_8bpc).pass2_main
+
+.end4:
+    LOAD_8ROWS   rsp+gprsize+16*19, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.end5)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.end5:
+    mov                   dstq, r3
+    add                     r3, 8
+    lea                   tx2q, [o(.end6)]
+    jmp   m(idct_8x8_internal_8bpc).pass2_main
+
+.end6:
+    LOAD_8ROWS   rsp+gprsize+16*27, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.end7)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.end7:
+    mov                   dstq, r3
+    lea                   tx2q, [o(.end8)]
+    jmp   m(idct_8x8_internal_8bpc).pass2_main
+
+.end8:
+    ret
+
+
+cglobal inv_txfm_add_identity_identity_8x32_8bpc, 4, 6, 8, 16*4, dst, stride, coeff, eob, tx2
+    mov                    r5d, 4
+    mov                   tx2d, 2
+    cmp                   eobd, 107
+    cmovns                tx2d, r5d
+    mov                    r3d, tx2d
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    lea                   tx2q, [o(m(idct_32x8_internal_8bpc).end8)]
+.loop:
+    LOAD_8ROWS     coeffq+16*0, 64
+    paddsw                  m6, [o(pw_5)]
+    mova            [rsp+16*1], m6
+    mova                    m6, [o(pw_5)]
+    REPX        {paddsw x, m6}, m0, m1, m2, m3, m4, m5, m7
+    call  m(idct_8x8_internal_8bpc).pass1_end3
+    REPX        {psraw  x, 3 }, m0, m1, m2, m3, m4, m5, m6, m7
+    mova            [rsp+16*2], m5
+    mova            [rsp+16*1], m6
+    mova            [rsp+16*0], m7
+    call  m(idct_8x8_internal_8bpc).end3
+    lea                   dstq, [dstq+strideq*2]
+    pxor                    m7, m7
+    REPX   {mova [coeffq+64*x], m7}, 0, 1, 2, 3, 4, 5, 6, 7
+    add                 coeffq, 16
+    dec                    r3d
+    jg .loop
+    RET
+
+cglobal inv_txfm_add_identity_identity_32x8_8bpc, 4, 6, 8, 16*4, dst, stride, coeff, eob, tx2
+    mov                    r5d, 4
+    mov                   tx2d, 2
+    cmp                   eobd, 107
+    cmovns                tx2d, r5d
+    mov                    r3d, tx2d
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+
+.loop:
+    LOAD_8ROWS     coeffq+16*0, 16
+    pmulhrsw                m6, [o(pw_4096)]
+    mova            [rsp+16*1], m6
+    mova                    m6, [o(pw_4096)]
+    REPX      {pmulhrsw x, m6}, m0, m1, m2, m3, m4, m5, m7
+    lea                   tx2q, [o(m(idct_32x8_internal_8bpc).end8)]
+    call  m(idct_8x8_internal_8bpc).pass1_end3
+
+    mov             [rsp+16*3], dstq
+    mova            [rsp+16*2], m5
+    mova            [rsp+16*1], m6
+    mova            [rsp+16*0], m7
+    lea                   tx2q, [o(m(idct_8x8_internal_8bpc).end4)]
+    call  m(idct_8x8_internal_8bpc).end3
+
+    add                 coeffq, 16*8
+    mov                   dstq, [rsp+16*3]
+    lea                   dstq, [dstq+8]
+    dec                    r3d
+    jg .loop
+    jnc .loop
+    RET
+
+
+cglobal inv_txfm_add_dct_dct_16x32_8bpc, 4, 6, 8, 16*36, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+    call  m(idct_16x32_internal_8bpc)
+.end:
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_16384)]
+    mov               [coeffq], eobd
+    pmulhrsw                m0, m1
+    mov                    r2d, 16
+    lea                   tx2q, [o(.end)]
+    jmp m(inv_txfm_add_dct_dct_16x4_8bpc).dconly
+
+
+cglobal idct_16x32_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    LOAD_8ROWS     coeffq+16*1, 128, 1
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+16*5, 128, 1
+    call m(idct_16x8_internal_8bpc).main
+    lea                   tx2q, [o(.pass1_end)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end:
+    SAVE_8ROWS    coeffq+16*33, 64               ;in8~in15
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end1:
+    mova        [coeffq+16*1 ], m0                        ;in8
+    mova        [coeffq+16*5 ], m4                        ;in12
+    mova   [rsp+gprsize+16*13], m2                        ;in10
+    mova   [rsp+gprsize+16*14], m6                        ;in14
+    mova   [rsp+gprsize+16*21], m1                        ;in9
+    mova   [rsp+gprsize+16*24], m3                        ;in11
+    mova   [rsp+gprsize+16*25], m5                        ;in13
+    mova   [rsp+gprsize+16*20], m7                        ;in15
+    LOAD_8ROWS     coeffq+16*0, 128, 1
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+16*4, 128, 1
+    call m(idct_16x8_internal_8bpc).main
+    lea                   tx2q, [o(.pass1_end2)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end2:
+    SAVE_8ROWS    coeffq+16*32, 64               ;in0~in7
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end3)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end3:
+    mova   [rsp+gprsize+16*11], m2                        ;in2
+    mova   [rsp+gprsize+16*12], m6                        ;in6
+    mova   [rsp+gprsize+16*19], m1                        ;in1
+    mova   [rsp+gprsize+16*26], m3                        ;in3
+    mova   [rsp+gprsize+16*23], m5                        ;in5
+    mova   [rsp+gprsize+16*22], m7                        ;in7
+
+    cmp                   eobd, 150
+    jg .full
+
+    mova                    m1, m4                        ;in4
+    mova                    m2, [coeffq+16*1 ]            ;in8
+    mova                    m3, [coeffq+16*5 ]            ;in12
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    mova                    m0, [rsp+gprsize+16*11]       ;in2
+    mova                    m1, [rsp+gprsize+16*12]       ;in6
+    mova                    m2, [rsp+gprsize+16*13]       ;in10
+    mova                    m3, [rsp+gprsize+16*14]       ;in14
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    call m(idct_8x32_internal_8bpc).main_fast
+    jmp  .pass2
+
+.full:
+    mova        [coeffq+16*0 ], m0                        ;in0
+    mova        [coeffq+16*4 ], m4                        ;in4
+
+    LOAD_8ROWS     coeffq+16*2, 128, 1
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+16*6, 128, 1
+    call m(idct_16x8_internal_8bpc).main
+    lea                   tx2q, [o(.pass1_end4)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end4:
+    SAVE_8ROWS    coeffq+16*34, 64               ;in16~in23
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end5)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end5:
+    mova        [coeffq+16*2 ], m0                        ;in16
+    mova        [coeffq+16*6 ], m4                        ;in20
+    mova   [rsp+gprsize+16*15], m2                        ;in18
+    mova   [rsp+gprsize+16*16], m6                        ;in22
+    mova   [rsp+gprsize+16*33], m1                        ;in17
+    mova   [rsp+gprsize+16*28], m3                        ;in19
+    mova   [rsp+gprsize+16*29], m5                        ;in21
+    mova   [rsp+gprsize+16*32], m7                        ;in23
+
+    LOAD_8ROWS     coeffq+16*3, 128, 1
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+16*7, 128, 1
+    call m(idct_16x8_internal_8bpc).main
+    lea                   tx2q, [o(.pass1_end6)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end6:
+    SAVE_8ROWS    coeffq+16*35, 64                        ;in24~in31
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end7)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end7:
+    mova   [rsp+gprsize+16*17], m2                        ;in26
+    mova   [rsp+gprsize+16*18], m6                        ;in30
+    mova   [rsp+gprsize+16*31], m1                        ;in25
+    mova   [rsp+gprsize+16*30], m3                        ;in27
+    mova   [rsp+gprsize+16*27], m5                        ;in29
+    mova   [rsp+gprsize+16*34], m7                        ;in31
+
+    mova                    m6, m0                        ;in24
+    mova                    m7, m4                        ;in28
+    mova                    m0, [coeffq+16*0 ]            ;in0
+    mova                    m1, [coeffq+16*4 ]            ;in4
+    mova                    m2, [coeffq+16*1 ]            ;in8
+    mova                    m3, [coeffq+16*5 ]            ;in12
+    mova                    m4, [coeffq+16*2 ]            ;in16
+    mova                    m5, [coeffq+16*6 ]            ;in20
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS   rsp+gprsize+16*3 , 16
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    call m(idct_8x32_internal_8bpc).main
+
+.pass2:
+    mov  [rsp+gprsize*1+16*35], eobd
+    lea                     r3, [dstq+8]
+    mov  [rsp+gprsize*2+16*35], r3
+    lea                     r3, [o(.end)]
+    jmp  m(idct_8x32_internal_8bpc).end
+
+.end:
+    mov                   dstq, [rsp+gprsize*2+16*35]
+    mov                   eobd, [rsp+gprsize*1+16*35]
+    add                 coeffq, 16*32
+
+    mova                    m0, [coeffq+16*4 ]            ;in1
+    mova                    m1, [coeffq+16*12]            ;in3
+    mova                    m2, [coeffq+16*20]            ;in5
+    mova                    m3, [coeffq+16*28]            ;in7
+    mova                    m4, [coeffq+16*5 ]            ;in9
+    mova                    m5, [coeffq+16*13]            ;in11
+    mova                    m6, [coeffq+16*21]            ;in13
+    mova                    m7, [coeffq+16*29]            ;in15
+
+    mova   [rsp+gprsize+16*19], m0                        ;in1
+    mova   [rsp+gprsize+16*26], m1                        ;in3
+    mova   [rsp+gprsize+16*23], m2                        ;in5
+    mova   [rsp+gprsize+16*22], m3                        ;in7
+    mova   [rsp+gprsize+16*21], m4                        ;in9
+    mova   [rsp+gprsize+16*24], m5                        ;in11
+    mova   [rsp+gprsize+16*25], m6                        ;in13
+    mova   [rsp+gprsize+16*20], m7                        ;in15
+
+    mova                    m0, [coeffq+16*0 ]            ;in0
+    mova                    m1, [coeffq+16*16]            ;in4
+    mova                    m2, [coeffq+16*1 ]            ;in8
+    mova                    m3, [coeffq+16*17]            ;in12
+
+    cmp                   eobd, 150
+    jg .full1
+
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    mova                    m0, [coeffq+16*8 ]            ;in2
+    mova                    m1, [coeffq+16*24]            ;in6
+    mova                    m2, [coeffq+16*9 ]            ;in10
+    mova                    m3, [coeffq+16*25]            ;in14
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    call m(idct_8x32_internal_8bpc).main_fast
+    jmp m(idct_8x32_internal_8bpc).pass2
+
+.full1:
+    mova                    m4, [coeffq+16*2 ]            ;in16
+    mova                    m5, [coeffq+16*18]            ;in20
+    mova                    m6, [coeffq+16*3 ]            ;in24
+    mova                    m7, [coeffq+16*19]            ;in26
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    mova                    m0, [coeffq+16*8 ]            ;in2
+    mova                    m1, [coeffq+16*24]            ;in6
+    mova                    m2, [coeffq+16*9 ]            ;in10
+    mova                    m3, [coeffq+16*25]            ;in14
+    mova                    m4, [coeffq+16*10]            ;in18
+    mova                    m5, [coeffq+16*26]            ;in22
+    mova                    m6, [coeffq+16*11]            ;in26
+    mova                    m7, [coeffq+16*27]            ;in30
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    mova                    m0, [coeffq+16*6 ]            ;in17
+    mova                    m1, [coeffq+16*14]            ;in19
+    mova                    m2, [coeffq+16*22]            ;in21
+    mova                    m3, [coeffq+16*30]            ;in23
+    mova                    m4, [coeffq+16*7 ]            ;in25
+    mova                    m5, [coeffq+16*15]            ;in27
+    mova                    m6, [coeffq+16*23]            ;in29
+    mova                    m7, [coeffq+16*31]            ;in31
+
+    mova   [rsp+gprsize+16*33], m0                        ;in17
+    mova   [rsp+gprsize+16*28], m1                        ;in19
+    mova   [rsp+gprsize+16*29], m2                        ;in21
+    mova   [rsp+gprsize+16*32], m3                        ;in23
+    mova   [rsp+gprsize+16*31], m4                        ;in25
+    mova   [rsp+gprsize+16*30], m5                        ;in27
+    mova   [rsp+gprsize+16*27], m6                        ;in29
+    mova   [rsp+gprsize+16*34], m7                        ;in31
+
+    call m(idct_8x32_internal_8bpc).main
+    jmp m(idct_8x32_internal_8bpc).pass2
+
+
+cglobal inv_txfm_add_dct_dct_32x16_8bpc, 4, 6, 8, 16*36, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+
+    call m(idct_32x16_internal_8bpc)
+    call m(idct_8x16_internal_8bpc).pass2
+
+    add                 coeffq, 16*16
+    lea                   dstq, [r3+8]
+    LOAD_8ROWS       rsp+16*11, 16
+    mova            [rsp+16*0], m7
+    lea                   tx2q, [o(m(idct_32x16_internal_8bpc).end)]
+    call  m(idct_8x8_internal_8bpc).pass1_end
+    call m(idct_8x16_internal_8bpc).pass2
+
+    add                 coeffq, 16*16
+    lea                   dstq, [r3+8]
+    LOAD_8ROWS       rsp+16*19, 16
+    mova            [rsp+16*0], m7
+    lea                   tx2q, [o(m(idct_32x16_internal_8bpc).end)]
+    call  m(idct_8x8_internal_8bpc).pass1_end
+    call m(idct_8x16_internal_8bpc).pass2
+
+    add                 coeffq, 16*16
+    lea                   dstq, [r3+8]
+    LOAD_8ROWS       rsp+16*27, 16
+    mova            [rsp+16*0], m7
+    lea                   tx2q, [o(m(idct_32x16_internal_8bpc).end)]
+    call  m(idct_8x8_internal_8bpc).pass1_end
+    call m(idct_8x16_internal_8bpc).pass2
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_16384)]
+    mov               [coeffq], eobd
+    pmulhrsw                m0, m1
+    mov                    r3d, 16
+    lea                   tx2q, [o(m(inv_txfm_add_dct_dct_32x8_8bpc).end)]
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).body
+
+
+cglobal idct_32x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    add                 coeffq, 16
+    lea                     r3, [o(.pass1_end1)]
+.pass1:
+    LOAD_8ROWS     coeffq+16*0, 128, 1
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    LOAD_8ROWS     coeffq+16*4, 128, 1
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    LOAD_8ROWS     coeffq+16*2, 64, 1
+    mova   [rsp+gprsize+16*19], m0                        ;in1
+    mova   [rsp+gprsize+16*26], m1                        ;in3
+    mova   [rsp+gprsize+16*23], m2                        ;in5
+    mova   [rsp+gprsize+16*22], m3                        ;in7
+    mova   [rsp+gprsize+16*21], m4                        ;in9
+    mova   [rsp+gprsize+16*24], m5                        ;in11
+    mova   [rsp+gprsize+16*25], m6                        ;in13
+    mova   [rsp+gprsize+16*20], m7                        ;in15
+
+    LOAD_8ROWS    coeffq+16*34, 64, 1
+    mova   [rsp+gprsize+16*33], m0                        ;in17
+    mova   [rsp+gprsize+16*28], m1                        ;in19
+    mova   [rsp+gprsize+16*29], m2                        ;in21
+    mova   [rsp+gprsize+16*32], m3                        ;in23
+    mova   [rsp+gprsize+16*31], m4                        ;in25
+    mova   [rsp+gprsize+16*30], m5                        ;in27
+    mova   [rsp+gprsize+16*27], m6                        ;in29
+    mova   [rsp+gprsize+16*34], m7                        ;in31
+    call m(idct_8x32_internal_8bpc).main
+
+.pass1_end:
+    mova   [rsp+gprsize+16*0 ], m7
+    mov                   tx2q, r3
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+16*0, 32
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    lea                   tx2q, [o(.pass1_end2)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end2:
+    SAVE_8ROWS    coeffq+16*16, 32
+    LOAD_8ROWS   rsp+gprsize+16*19, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    lea                   tx2q, [o(.pass1_end3)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end3:
+    SAVE_8ROWS    coeffq+16*32, 32
+    LOAD_8ROWS   rsp+gprsize+16*27, 16
+    mova   [rsp+gprsize+16*0 ], m7
+    lea                   tx2q, [o(.pass1_end4)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end4:
+    SAVE_8ROWS    coeffq+16*48, 32
+
+    sub                 coeffq, 16
+    lea                     r3, [o(.end)]
+    jmp .pass1
+
+.end:
+    ret
+
+
+cglobal inv_txfm_add_identity_identity_16x32_8bpc, 4, 6, 8, 16*4, dst, stride, coeff, eob, tx2
+    mov                    r4d, eobd
+    cmp                   eobd, 43                ;if (eob > 43)
+    sbb                    r3d, r3d               ;  iteration_count++
+    cmp                    r4d, 150               ;if (eob > 150)
+    sbb                    r3d, 0                 ;  iteration_count++
+    cmp                    r4d, 278               ;if (eob > 278)
+    sbb                    r3d, -4                ;  iteration_count++
+
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    lea                     r4, [dstq+8]
+    mov             [rsp+16*3], r4
+    mov     [rsp+gprsize+16*3], r3d
+    mov   [rsp+gprsize*2+16*3], coeffq
+
+.loop:
+    LOAD_8ROWS          coeffq, 64, 1
+    mova            [rsp+16*1], m6
+    pxor                    m6, m6
+    REPX   {mova [coeffq+64*x], m6}, 0,  1,  2,  3,  4,  5,  6,  7
+    lea                   tx2q, [o(m(idct_32x16_internal_8bpc).end)]
+    call  m(idct_8x8_internal_8bpc).pass1_end3
+    mova            [rsp+16*0], m2
+    mova            [rsp+16*1], m3
+    mova            [rsp+16*2], m4
+    mova                    m3, [o(pw_1697x16)]
+    mova                    m4, [o(pw_16384)]
+    REPX   {IDTX16 x, 2, 3, 4}, 5, 6, 7, 0, 1
+    mova                    m2, [o(pw_8192)]
+    REPX      {pmulhrsw x, m2}, m5, m6, m7, m0, m1
+    mova                    m2, [rsp+16*0]
+    mova            [rsp+16*0], m7
+    IDTX16                   2, 7, 3, 4
+    mova                    m7, [rsp+16*2]
+    mova            [rsp+16*2], m5
+    IDTX16                   7, 5, 3, 4
+    mova                    m5, [rsp+16*1]
+    mova            [rsp+16*1], m6
+    pmulhrsw                m3, m5
+    pmulhrsw                m3, m4
+    psrlw                   m4, 1 ; pw_8192
+    paddsw                  m3, m5
+    pmulhrsw                m2, m4
+    pmulhrsw                m3, m4
+    pmulhrsw                m4, m7
+    call  m(idct_8x8_internal_8bpc).end3
+    lea                   dstq, [dstq+strideq*2]
+    add                 coeffq, 16
+    dec                    r3d
+    jg .loop
+    mov                 coeffq, [rsp+gprsize*2+16*3]
+    add                 coeffq, 64*8
+    mov                    r3d, [rsp+gprsize+16*3]
+    xor                   dstq, dstq
+    mov     [rsp+gprsize+16*3], dstq
+    mov                   dstq, [rsp+16*3]
+    test                   r3d, r3d
+    jnz .loop
+    RET
+
+
+cglobal inv_txfm_add_identity_identity_32x16_8bpc, 4, 6, 8, 16*4, dst, stride, coeff, eob, tx2
+    mov                    r4d, 12                ;0100b
+    mov                    r5d, 136               ;1000 1000b
+    cmp                   eobd, 44                ;if (eob > 43)
+    cmovns                 r4d, r5d               ;  iteration_count+2
+    cmp                   eobd, 151               ;if (eob > 150)
+    mov                    r3d, 34952             ;1000 1000 1000 1000b
+    cmovs                  r3d, r4d               ;  iteration_count += 4
+
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    lea                     r4, [dstq+8]
+    mov             [rsp+16*3], r4
+
+.loop:
+    LOAD_8ROWS          coeffq, 32, 1
+    REPX         {paddsw x, x}, m0, m1, m2, m3, m4, m5, m6, m7
+    mova            [rsp+16*1], m6
+    lea                   tx2q, [o(m(idct_32x16_internal_8bpc).end)]
+    call  m(idct_8x8_internal_8bpc).pass1_end3
+    mova            [rsp+16*1], m5
+    mova            [rsp+16*2], m6
+    mova                    m6, [o(pw_1697x16)]
+    REPX      {IDTX16 x, 5, 6}, 7, 0, 1, 2, 3, 4
+    pmulhrsw                m7, [o(pw_2048)]
+    mova                    m5, [rsp+16*1]
+    mova            [rsp+16*0], m7
+    IDTX16                   5, 7, 6
+    mova                    m7, [rsp+16*2]
+    IDTX16                   7, 6, 6
+    mova                    m6, [o(pw_2048)]
+    REPX      {pmulhrsw x, m6}, m0, m1, m2, m3, m4, m5, m7
+    mova            [rsp+16*2], m5
+    mova            [rsp+16*1], m7
+    call  m(idct_8x8_internal_8bpc).end3
+    lea                   dstq, [dstq+strideq*2]
+    pxor                    m7, m7
+    REPX {mova [coeffq+32*x], m7}, 0, 1, 2, 3, 4, 5, 6, 7
+
+.loop_end:
+    add                 coeffq, 16
+    shr                    r3d, 2
+    jz .ret
+    test                   r3d, 2
+    jnz .loop
+    mov                    r4d, r3d
+    and                    r4d, 1
+    lea                 coeffq, [coeffq+r4*8+32*7]
+    mov                   dstq, [rsp+16*3]
+    lea                     r4, [dstq+8]
+    mov             [rsp+16*3], r4
+    jmp .loop
+
+.ret:
+    RET
+
+
+cglobal inv_txfm_add_dct_dct_32x32_8bpc, 4, 6, 8, 16*36, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+
+    call m(idct_32x32_internal_8bpc)
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_8192)]
+    mov               [coeffq], eobd
+    mov                    r3d, 32
+    lea                   tx2q, [o(m(inv_txfm_add_dct_dct_32x8_8bpc).end)]
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).body
+
+
+cglobal idct_32x32_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mov                    r4d, 2
+    sub                   eobd, 136
+    mov  [rsp+gprsize*1+16*35], eobd
+    mov                    r3d, 4
+    cmovs                  r3d, r4d
+
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+
+    mov  [rsp+gprsize*2+16*35], coeffq
+
+.pass1_loop:
+    LOAD_8ROWS     coeffq+64*1, 64*2
+    mova   [rsp+gprsize+16*19], m0                        ;in1
+    mova   [rsp+gprsize+16*26], m1                        ;in3
+    mova   [rsp+gprsize+16*23], m2                        ;in5
+    mova   [rsp+gprsize+16*22], m3                        ;in7
+    mova   [rsp+gprsize+16*21], m4                        ;in9
+    mova   [rsp+gprsize+16*24], m5                        ;in11
+    mova   [rsp+gprsize+16*25], m6                        ;in13
+    mova   [rsp+gprsize+16*20], m7                        ;in15
+
+    mov                   tx2d, [rsp+gprsize*1+16*35]
+    test                  tx2d, tx2d
+    jl .fast
+
+.full:
+    LOAD_8ROWS     coeffq+64*0, 64*4
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+64*2, 64*4
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    LOAD_8ROWS    coeffq+64*17, 64*2
+    mova   [rsp+gprsize+16*33], m0                        ;in17
+    mova   [rsp+gprsize+16*28], m1                        ;in19
+    mova   [rsp+gprsize+16*29], m2                        ;in21
+    mova   [rsp+gprsize+16*32], m3                        ;in23
+    mova   [rsp+gprsize+16*31], m4                        ;in25
+    mova   [rsp+gprsize+16*30], m5                        ;in27
+    mova   [rsp+gprsize+16*27], m6                        ;in29
+    mova   [rsp+gprsize+16*34], m7                        ;in31
+
+    call m(idct_8x32_internal_8bpc).main
+    jmp .pass1_end
+
+.fast:
+    mova                    m0, [coeffq+256*0]
+    mova                    m1, [coeffq+256*1]
+    mova                    m2, [coeffq+256*2]
+    mova                    m3, [coeffq+256*3]
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    mova                    m0, [coeffq+128*1]
+    mova                    m1, [coeffq+128*3]
+    mova                    m2, [coeffq+128*5]
+    mova                    m3, [coeffq+128*7]
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    call m(idct_8x32_internal_8bpc).main_fast
+
+.pass1_end:
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+64*0, 64
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end2)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end2:
+    SAVE_8ROWS     coeffq+64*8, 64
+    LOAD_8ROWS   rsp+gprsize+16*19, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end3)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end3:
+    SAVE_8ROWS    coeffq+64*16, 64
+    LOAD_8ROWS   rsp+gprsize+16*27, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end4)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end4:
+    SAVE_8ROWS    coeffq+64*24, 64
+
+    add                 coeffq, 16
+    dec                    r3d
+    jg .pass1_loop
+
+
+.pass2:
+    mov                 coeffq, [rsp+gprsize*2+16*35]
+    mov                    r3d, 4
+    lea                   tx2q, [o(.pass2_end)]
+
+.pass2_loop:
+    mov  [rsp+gprsize*3+16*35], r3d
+    lea                     r3, [dstq+8]
+    mov  [rsp+gprsize*2+16*35], r3
+
+    mova                    m0, [coeffq+16*4 ]
+    mova                    m1, [coeffq+16*12]
+    mova                    m2, [coeffq+16*20]
+    mova                    m3, [coeffq+16*28]
+    mova                    m4, [coeffq+16*5 ]
+    mova                    m5, [coeffq+16*13]
+    mova                    m6, [coeffq+16*21]
+    mova                    m7, [coeffq+16*29]
+    mova   [rsp+gprsize+16*19], m0                        ;in1
+    mova   [rsp+gprsize+16*26], m1                        ;in3
+    mova   [rsp+gprsize+16*23], m2                        ;in5
+    mova   [rsp+gprsize+16*22], m3                        ;in7
+    mova   [rsp+gprsize+16*21], m4                        ;in9
+    mova   [rsp+gprsize+16*24], m5                        ;in11
+    mova   [rsp+gprsize+16*25], m6                        ;in13
+    mova   [rsp+gprsize+16*20], m7                        ;in15
+
+    mov                   eobd, [rsp+gprsize*1+16*35]
+    test                  eobd, eobd
+    jl .fast1
+
+.full1:
+    mova                    m0, [coeffq+16*0 ]
+    mova                    m1, [coeffq+16*16]
+    mova                    m2, [coeffq+16*1 ]
+    mova                    m3, [coeffq+16*17]
+    mova                    m4, [coeffq+16*2 ]
+    mova                    m5, [coeffq+16*18]
+    mova                    m6, [coeffq+16*3 ]
+    mova                    m7, [coeffq+16*19]
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    mova                    m0, [coeffq+16*8 ]
+    mova                    m1, [coeffq+16*24]
+    mova                    m2, [coeffq+16*9 ]
+    mova                    m3, [coeffq+16*25]
+    mova                    m4, [coeffq+16*10]
+    mova                    m5, [coeffq+16*26]
+    mova                    m6, [coeffq+16*11]
+    mova                    m7, [coeffq+16*27]
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    mova                    m0, [coeffq+16*6 ]
+    mova                    m1, [coeffq+16*14]
+    mova                    m2, [coeffq+16*22]
+    mova                    m3, [coeffq+16*30]
+    mova                    m4, [coeffq+16*7 ]
+    mova                    m5, [coeffq+16*15]
+    mova                    m6, [coeffq+16*23]
+    mova                    m7, [coeffq+16*31]
+    mova   [rsp+gprsize+16*33], m0                        ;in17
+    mova   [rsp+gprsize+16*28], m1                        ;in19
+    mova   [rsp+gprsize+16*29], m2                        ;in21
+    mova   [rsp+gprsize+16*32], m3                        ;in23
+    mova   [rsp+gprsize+16*31], m4                        ;in25
+    mova   [rsp+gprsize+16*30], m5                        ;in27
+    mova   [rsp+gprsize+16*27], m6                        ;in29
+    mova   [rsp+gprsize+16*34], m7                        ;in31
+
+    call m(idct_8x32_internal_8bpc).main
+    jmp                   tx2q
+
+.fast1:
+    mova                    m0, [coeffq+16*0 ]
+    mova                    m1, [coeffq+16*16]
+    mova                    m2, [coeffq+16*1 ]
+    mova                    m3, [coeffq+16*17]
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    mova                    m0, [coeffq+16*8 ]
+    mova                    m1, [coeffq+16*24]
+    mova                    m2, [coeffq+16*9 ]
+    mova                    m3, [coeffq+16*25]
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    call m(idct_8x32_internal_8bpc).main_fast
+    jmp                   tx2q
+
+.pass2_end:
+    lea                     r3, [o(.pass2_end1)]
+    jmp  m(idct_8x32_internal_8bpc).end
+
+.pass2_end1:
+    lea                   tx2q, [o(.pass2_end)]
+    add                 coeffq, 16*32
+    mov                   dstq, [rsp+gprsize*2+16*35]
+    mov                    r3d, [rsp+gprsize*3+16*35]
+    dec                    r3d
+    jg .pass2_loop
+
+    ret
+
+
+cglobal inv_txfm_add_identity_identity_32x32_8bpc, 4, 6, 8, 16*5, dst, stride, coeff, eob, tx2
+    mov                    r4d, 2
+    cmp                   eobd, 136
+    mov                    r3d, 4
+    cmovs                  r3d, r4d
+
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+
+    lea                     r4, [dstq+8]
+    mov   [rsp+gprsize*0+16*3], r4
+    mov   [rsp+gprsize*1+16*3], r3d
+    mov   [rsp+gprsize*2+16*3], r3d
+    mov   [rsp+gprsize*3+16*3], coeffq
+
+.loop:
+    LOAD_8ROWS          coeffq, 64
+    mova            [rsp+16*1], m6
+    lea                   tx2q, [o(m(idct_32x16_internal_8bpc).end)]
+    call  m(idct_8x8_internal_8bpc).pass1_end3
+    pmulhrsw                m7, [o(pw_8192)]
+    mova            [rsp+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    REPX      {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    mova            [rsp+16*1], m6
+    mova            [rsp+16*2], m5
+    call  m(idct_8x8_internal_8bpc).end3
+    lea                   dstq, [dstq+strideq*2]
+
+    pxor                    m7, m7
+    REPX   {mova [coeffq+64*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7
+
+    add                 coeffq, 16
+    dec                    r3d
+    jg .loop
+
+    mov                    r4d, [rsp+gprsize*2+16*3]
+    dec                    r4d
+    jle .ret
+
+    mov                   dstq, [rsp+gprsize*0+16*3]
+    mov                 coeffq, [rsp+gprsize*3+16*3]
+    mov   [rsp+gprsize*2+16*3], r4
+    lea                     r3, [dstq+8]
+    add                 coeffq, 64*8
+    mov   [rsp+gprsize*0+16*3], r3
+    mov                    r3d, [rsp+gprsize*1+16*3]
+    mov   [rsp+gprsize*3+16*3], coeffq
+    jmp .loop
+
+.ret:
+    RET
+
+
+cglobal inv_txfm_add_dct_dct_16x64_8bpc, 4, 6, 8, 16*68, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+    call m(idct_16x64_internal_8bpc)
+.end:
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_8192)]
+    mov               [coeffq], eobd
+    mov                    r2d, 32
+    lea                   tx2q, [o(.end)]
+    jmp m(inv_txfm_add_dct_dct_16x4_8bpc).dconly
+
+
+cglobal idct_16x64_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mov                    r4d, 2
+    sub                   eobd, 151
+    mov  [rsp+gprsize*1+16*67], eobd
+    mov                    r3d, 4
+    cmovs                  r3d, r4d
+
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+
+    mov  [rsp+gprsize*2+16*67], coeffq
+
+.pass1_loop:
+    LOAD_8ROWS     coeffq+64*0, 64*2
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+64*1, 64*2
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end:
+    SAVE_8ROWS     coeffq+64*8, 64
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+64*0, 64
+
+    add                 coeffq, 16
+    dec                    r3d
+    jg .pass1_loop
+
+    mov                 coeffq, [rsp+gprsize*2+16*67]
+    mov                    r3d, 2
+    lea                     r4, [dstq+8]
+    mov  [rsp+gprsize*2+16*67], r4
+    lea                     r4, [o(.end1)]
+
+.pass2_loop:
+    mov  [rsp+gprsize*3+16*67], r3d
+    mov                   eobd, [rsp+gprsize*1+16*67]
+
+    mova                    m0, [coeffq+16*4 ]            ;in1
+    mova                    m1, [coeffq+16*12]            ;in3
+    mova                    m2, [coeffq+16*20]            ;in5
+    mova                    m3, [coeffq+16*28]            ;in7
+    mova                    m4, [coeffq+16*5 ]            ;in9
+    mova                    m5, [coeffq+16*13]            ;in11
+    mova                    m6, [coeffq+16*21]            ;in13
+    mova                    m7, [coeffq+16*29]            ;in15
+    mova   [rsp+gprsize+16*35], m0                        ;in1
+    mova   [rsp+gprsize+16*49], m1                        ;in3
+    mova   [rsp+gprsize+16*43], m2                        ;in5
+    mova   [rsp+gprsize+16*41], m3                        ;in7
+    mova   [rsp+gprsize+16*39], m4                        ;in9
+    mova   [rsp+gprsize+16*45], m5                        ;in11
+    mova   [rsp+gprsize+16*47], m6                        ;in13
+    mova   [rsp+gprsize+16*37], m7                        ;in15
+
+    pxor                    m4, m4
+    mova                    m0, [coeffq+16*0]
+    mova                    m1, [coeffq+16*1]
+
+    test                  eobd, eobd
+    jl .fast
+
+.full:
+    mova                    m2, [coeffq+16*2]
+    mova                    m3, [coeffq+16*3]
+
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    pxor                    m4, m4
+    mova                    m0, [coeffq+16*16]
+    mova                    m1, [coeffq+16*17]
+    mova                    m2, [coeffq+16*18]
+    mova                    m3, [coeffq+16*19]
+
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    mova                    m0, [coeffq+16*8 ]
+    mova                    m1, [coeffq+16*24]
+    mova                    m2, [coeffq+16*9 ]
+    mova                    m3, [coeffq+16*25]
+    mova                    m4, [coeffq+16*10]
+    mova                    m5, [coeffq+16*26]
+    mova                    m6, [coeffq+16*11]
+    mova                    m7, [coeffq+16*27]
+    mova   [rsp+gprsize+16*19], m0
+    mova   [rsp+gprsize+16*26], m1
+    mova   [rsp+gprsize+16*23], m2
+    mova   [rsp+gprsize+16*22], m3
+    mova   [rsp+gprsize+16*21], m4
+    mova   [rsp+gprsize+16*24], m5
+    mova   [rsp+gprsize+16*25], m6
+    mova   [rsp+gprsize+16*20], m7
+
+    call m(idct_8x32_internal_8bpc).main_fast
+    SAVE_8ROWS    rsp+gprsize+16*3, 16
+
+    mova                    m0, [coeffq+16*6 ]            ;in17
+    mova                    m1, [coeffq+16*14]            ;in19
+    mova                    m2, [coeffq+16*22]            ;in21
+    mova                    m3, [coeffq+16*30]            ;in23
+    mova                    m4, [coeffq+16*7 ]            ;in25
+    mova                    m5, [coeffq+16*15]            ;in27
+    mova                    m6, [coeffq+16*23]            ;in29
+    mova                    m7, [coeffq+16*31]            ;in31
+    mova   [rsp+gprsize+16*63], m0                        ;in17
+    mova   [rsp+gprsize+16*53], m1                        ;in19
+    mova   [rsp+gprsize+16*55], m2                        ;in21
+    mova   [rsp+gprsize+16*61], m3                        ;in23
+    mova   [rsp+gprsize+16*59], m4                        ;in25
+    mova   [rsp+gprsize+16*57], m5                        ;in27
+    mova   [rsp+gprsize+16*51], m6                        ;in29
+    mova   [rsp+gprsize+16*65], m7                        ;in31
+
+    call .main
+    jmp  .end
+
+.fast:
+    REPX          {mova x, m4}, m2, m3, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    pxor                    m4, m4
+    mova                    m0, [coeffq+16*16]
+    mova                    m1, [coeffq+16*17]
+
+    REPX          {mova x, m4}, m2, m3, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    mova                    m0, [coeffq+16*8 ]
+    mova                    m1, [coeffq+16*24]
+    mova                    m2, [coeffq+16*9 ]
+    mova                    m3, [coeffq+16*25]
+    mova   [rsp+gprsize+16*19], m0                        ;in1
+    mova   [rsp+gprsize+16*26], m1                        ;in3
+    mova   [rsp+gprsize+16*23], m2                        ;in5
+    mova   [rsp+gprsize+16*22], m3                        ;in7
+
+    call m(idct_8x32_internal_8bpc).main_veryfast
+    SAVE_8ROWS    rsp+gprsize+16*3, 16
+
+    call .main_fast
+
+.end:
+    LOAD_8ROWS   rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    mov                     r3, r4
+    jmp  m(idct_8x32_internal_8bpc).end2
+
+.end1:
+    LOAD_8ROWS   rsp+gprsize+16*35, 16
+    lea                   dstq, [dstq+strideq*2]
+    lea                     r3, [rsp+16*32+gprsize]
+    call .write
+    mov                   dstq, [rsp+gprsize*2+16*67]
+    mov                    r3d, [rsp+gprsize*3+16*67]
+    lea                     r4, [dstq+8]
+    mov  [rsp+gprsize*2+16*67], r4
+    lea                     r4, [o(.end1)]
+
+    dec                    r3d
+    jg .pass2_loop
+    ret
+.write:
+    mova             [r3+16*0], m7
+    mov                     r4, -16*32
+    pxor                    m7, m7
+    sub                 coeffq, r4
+.zero_loop:
+    mova      [coeffq+r4+16*0], m7
+    mova      [coeffq+r4+16*1], m7
+    add                     r4, 16*2
+    jl .zero_loop
+    call .write_main2
+    LOAD_8ROWS        r3+16*11, 16
+    call .write_main
+    LOAD_8ROWS        r3+16*19, 16
+    call .write_main
+    LOAD_8ROWS        r3+16*27, 16
+.write_main:
+    mova             [r3+16*0], m7
+.write_main2:
+    mova                    m7, [o(pw_2048)]
+    REPX      {pmulhrsw x, m7}, m0, m1, m2, m3, m4, m5, m6
+    pmulhrsw                m7, [r3+16*0]
+    mova             [r3+16*2], m5
+    mova             [r3+16*1], m6
+    mova             [r3+16*0], m7
+    WRITE_8X4                0, 1, 2, 3, 5, 6, 7
+    lea                   dstq, [dstq+strideq*2]
+    WRITE_8X4                4, [r3+16*2], [r3+16*1], [r3+16*0], 5, 6, 7
+    lea                   dstq, [dstq+strideq*2]
+    ret
+
+
+ALIGN function_align
+cglobal_label .main_fast
+    mova                    m0, [rsp+gprsize*2+16*35]     ;in1
+    pmulhrsw                m3, m0, [o(pw_4095x8)]        ;t62,t63
+    pmulhrsw                m0, [o(pw_101x8)]             ;t32,t33
+    mova                    m7, [o(pd_2048)]
+    mova [rsp+gprsize*2+16*35], m0                        ;t32
+    mova [rsp+gprsize*2+16*66], m3                        ;t63
+    ITX_MULSUB_2W            3, 0, 1, 2, 7,  401, 4076    ;t33a, t62a
+    mova [rsp+gprsize*2+16*36], m3                        ;t33a
+    mova [rsp+gprsize*2+16*65], m0                        ;t62a
+
+    mova                    m1, [rsp+gprsize*2+16*37]     ;in15
+    pmulhrsw                m2, m1, [o(pw_3822x8)]        ;t60,t61
+    pmulhrsw                m1, [o(pw_m1474x8)]           ;t34,t35
+    mova [rsp+gprsize*2+16*38], m1                        ;t35
+    mova [rsp+gprsize*2+16*63], m2                        ;t60
+    ITX_MULSUB_2W            2, 1, 0, 3, 7, m4076, 401    ;t34a, t61a
+    mova [rsp+gprsize*2+16*37], m2                        ;t34a
+    mova [rsp+gprsize*2+16*64], m1                        ;t61a
+
+    mova                    m0, [rsp+gprsize*2+16*39]     ;in9
+    pmulhrsw                m3, m0, [o(pw_3996x8)]        ;t58,t59
+    pmulhrsw                m0, [o(pw_897x8)]             ;t36,t37
+    mova [rsp+gprsize*2+16*39], m0                        ;t36
+    mova [rsp+gprsize*2+16*62], m3                        ;t59
+    ITX_MULSUB_2W            3, 0, 1, 2, 7, 3166, 2598    ;t37a, t58a
+    mova [rsp+gprsize*2+16*40], m3                        ;t37a
+    mova [rsp+gprsize*2+16*61], m0                        ;t58a
+
+    mova                    m1, [rsp+gprsize*2+16*41]     ;in7
+    pmulhrsw                m2, m1, [o(pw_4036x8)]        ;t56,t57
+    pmulhrsw                m1, [o(pw_m700x8)]            ;t38,t39
+    mova [rsp+gprsize*2+16*42], m1                        ;t39
+    mova [rsp+gprsize*2+16*59], m2                        ;t56
+    ITX_MULSUB_2W            2, 1, 0, 3, 7, m2598, 3166   ;t38a, t57a
+    mova [rsp+gprsize*2+16*41], m2                        ;t38a
+    mova [rsp+gprsize*2+16*60], m1                        ;t57a
+
+    mova                    m0, [rsp+gprsize*2+16*43]     ;in5
+    pmulhrsw                m3, m0, [o(pw_4065x8)]        ;t54,t55
+    pmulhrsw                m0, [o(pw_501x8)]             ;t40,t41
+    mova [rsp+gprsize*2+16*43], m0                        ;t40
+    mova [rsp+gprsize*2+16*58], m3                        ;t55
+    ITX_MULSUB_2W            3, 0, 1, 2, 7, 1931, 3612    ;t41a, t54a
+    mova [rsp+gprsize*2+16*44], m3                        ;t41a
+    mova [rsp+gprsize*2+16*57], m0                        ;t54a
+
+    mova                    m1, [rsp+gprsize*2+16*45]     ;in11
+    pmulhrsw                m2, m1, [o(pw_3948x8)]        ;t52,t53
+    pmulhrsw                m1, [o(pw_m1092x8)]           ;t42,t43
+    mova [rsp+gprsize*2+16*46], m1                        ;t43
+    mova [rsp+gprsize*2+16*55], m2                        ;t52
+    ITX_MULSUB_2W            2, 1, 0, 3, 7, m3612, 1931   ;t42a, t53a
+    mova [rsp+gprsize*2+16*45], m2                        ;t42a
+    mova [rsp+gprsize*2+16*56], m1                        ;t53a
+
+    mova                    m0, [rsp+gprsize*2+16*47]     ;in13
+    pmulhrsw                m3, m0, [o(pw_3889x8)]        ;t50,t51
+    pmulhrsw                m0, [o(pw_1285x8)]            ;t44,t45
+    mova                    m6, m0
+    mova [rsp+gprsize*2+16*54], m3                        ;t51
+    ITX_MULSUB_2W            3, 0, 1, 2, 7, 3920, 1189    ;t45a, t50a
+    mova [rsp+gprsize*2+16*48], m3                        ;t45a
+    mova [rsp+gprsize*2+16*53], m0                        ;t50a
+
+    mova                    m0, [rsp+gprsize*2+16*49]     ;in3
+    pmulhrsw                m3, m0, [o(pw_4085x8)]        ;t48,t49
+    pmulhrsw                m0, [o(pw_m301x8)]            ;t46,t47
+    mova                    m4, m3
+    mova                    m5, m0
+
+    jmp .main2
+
+ALIGN function_align
+cglobal_label .main
+    mova                    m0, [rsp+gprsize*2+16*35]     ;in1
+    mova                    m1, [rsp+gprsize*2+16*65]     ;in31
+    pmulhrsw                m3, m0, [o(pw_4095x8)]        ;t63a
+    pmulhrsw                m0, [o(pw_101x8)]             ;t32a
+    pmulhrsw                m2, m1, [o(pw_2967x8)]        ;t62a
+    pmulhrsw                m1, [o(pw_m2824x8)]           ;t33a
+    mova                    m7, [o(pd_2048)]
+    psubsw                  m4, m0, m1                    ;t33
+    paddsw                  m0, m1                        ;t32
+    psubsw                  m5, m3, m2                    ;t62
+    paddsw                  m3, m2                        ;t63
+    ITX_MULSUB_2W            5, 4, 1, 2, 7,  401, 4076    ;t33a, t62a
+    mova [rsp+gprsize*2+16*35], m0                        ;t32
+    mova [rsp+gprsize*2+16*36], m5                        ;t33a
+    mova [rsp+gprsize*2+16*65], m4                        ;t62a
+    mova [rsp+gprsize*2+16*66], m3                        ;t63
+
+    mova                    m0, [rsp+gprsize*2+16*63]     ;in17
+    mova                    m1, [rsp+gprsize*2+16*37]     ;in15
+    pmulhrsw                m3, m0, [o(pw_3745x8)]        ;t61a
+    pmulhrsw                m0, [o(pw_1660x8)]            ;t34a
+    pmulhrsw                m2, m1, [o(pw_3822x8)]        ;t60a
+    pmulhrsw                m1, [o(pw_m1474x8)]           ;t35a
+    psubsw                  m4, m1, m0                    ;t34
+    paddsw                  m0, m1                        ;t35
+    psubsw                  m5, m2, m3                    ;t61
+    paddsw                  m3, m2                        ;t60
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, m4076, 401    ;t34a, t61a
+    mova [rsp+gprsize*2+16*37], m5                        ;t34a
+    mova [rsp+gprsize*2+16*38], m0                        ;t35
+    mova [rsp+gprsize*2+16*63], m3                        ;t60
+    mova [rsp+gprsize*2+16*64], m4                        ;t61a
+
+    mova                    m0, [rsp+gprsize*2+16*39]     ;in9
+    mova                    m1, [rsp+gprsize*2+16*61]     ;in23
+    pmulhrsw                m3, m0, [o(pw_3996x8)]        ;t59a
+    pmulhrsw                m0, [o(pw_897x8)]             ;t36a
+    pmulhrsw                m2, m1, [o(pw_3461x8)]        ;t58a
+    pmulhrsw                m1, [o(pw_m2191x8)]           ;t37a
+    psubsw                  m4, m0, m1                    ;t37
+    paddsw                  m0, m1                        ;t36
+    psubsw                  m5, m3, m2                    ;t58
+    paddsw                  m3, m2                        ;t59
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, 3166, 2598    ;t37a, t58a
+    mova [rsp+gprsize*2+16*39], m0                        ;t36
+    mova [rsp+gprsize*2+16*40], m5                        ;t37a
+    mova [rsp+gprsize*2+16*61], m4                        ;t58a
+    mova [rsp+gprsize*2+16*62], m3                        ;t59
+
+    mova                    m0, [rsp+gprsize*2+16*59]     ;in25
+    mova                    m1, [rsp+gprsize*2+16*41]     ;in7
+    pmulhrsw                m3, m0, [o(pw_3349x8)]        ;t57a
+    pmulhrsw                m0, [o(pw_2359x8)]            ;t38a
+    pmulhrsw                m2, m1, [o(pw_4036x8)]        ;t56a
+    pmulhrsw                m1, [o(pw_m700x8)]            ;t39a
+    psubsw                  m4, m1, m0                    ;t38
+    paddsw                  m0, m1                        ;t39
+    psubsw                  m5, m2, m3                    ;t57
+    paddsw                  m3, m2                        ;t56
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, m2598, 3166   ;t38a, t57a
+    mova [rsp+gprsize*2+16*41], m5                        ;t38a
+    mova [rsp+gprsize*2+16*42], m0                        ;t39
+    mova [rsp+gprsize*2+16*59], m3                        ;t56
+    mova [rsp+gprsize*2+16*60], m4                        ;t57a
+
+    mova                    m0, [rsp+gprsize*2+16*43]     ;in5
+    mova                    m1, [rsp+gprsize*2+16*57]     ;in27
+    pmulhrsw                m3, m0, [o(pw_4065x8)]        ;t55a
+    pmulhrsw                m0, [o(pw_501x8)]             ;t40a
+    pmulhrsw                m2, m1, [o(pw_3229x8)]        ;t54a
+    pmulhrsw                m1, [o(pw_m2520x8)]           ;t41a
+    psubsw                  m4, m0, m1                    ;t41
+    paddsw                  m0, m1                        ;t40
+    psubsw                  m5, m3, m2                    ;t54
+    paddsw                  m3, m2                        ;t55
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, 1931, 3612    ;t41a, t54a
+    mova [rsp+gprsize*2+16*43], m0                        ;t40
+    mova [rsp+gprsize*2+16*44], m5                        ;t41a
+    mova [rsp+gprsize*2+16*57], m4                        ;t54a
+    mova [rsp+gprsize*2+16*58], m3                        ;t55
+
+    mova                    m0, [rsp+gprsize*2+16*55]     ;in21
+    mova                    m1, [rsp+gprsize*2+16*45]     ;in11
+    pmulhrsw                m3, m0, [o(pw_3564x8)]        ;t53a
+    pmulhrsw                m0, [o(pw_2019x8)]            ;t42a
+    pmulhrsw                m2, m1, [o(pw_3948x8)]        ;t52a
+    pmulhrsw                m1, [o(pw_m1092x8)]           ;t43a
+    psubsw                  m4, m1, m0                    ;t42
+    paddsw                  m0, m1                        ;t43
+    psubsw                  m5, m2, m3                    ;t53
+    paddsw                  m3, m2                        ;t52
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, m3612, 1931   ;t42a, t53a
+    mova [rsp+gprsize*2+16*45], m5                        ;t42a
+    mova [rsp+gprsize*2+16*46], m0                        ;t43
+    mova [rsp+gprsize*2+16*55], m3                        ;t52
+    mova [rsp+gprsize*2+16*56], m4                        ;t53a
+
+    mova                    m0, [rsp+gprsize*2+16*47]     ;in13
+    mova                    m1, [rsp+gprsize*2+16*53]     ;in19
+    pmulhrsw                m3, m0, [o(pw_3889x8)]        ;t51a
+    pmulhrsw                m0, [o(pw_1285x8)]            ;t44a
+    pmulhrsw                m2, m1, [o(pw_3659x8)]        ;t50a
+    pmulhrsw                m1, [o(pw_m1842x8)]           ;t45a
+    psubsw                  m4, m0, m1                    ;t45
+    paddsw                  m0, m1                        ;t44
+    psubsw                  m5, m3, m2                    ;t50
+    paddsw                  m3, m2                        ;t51
+    ITX_MULSUB_2W            5, 4, 1, 2, 7, 3920, 1189    ;t45a, t50a
+    mova                    m6, m0
+    mova [rsp+gprsize*2+16*48], m5                        ;t45a
+    mova [rsp+gprsize*2+16*53], m4                        ;t50a
+    mova [rsp+gprsize*2+16*54], m3                        ;t51
+
+    mova                    m0, [rsp+gprsize*2+16*51]     ;in29
+    mova                    m1, [rsp+gprsize*2+16*49]     ;in3
+    pmulhrsw                m3, m0, [o(pw_3102x8)]        ;t49a
+    pmulhrsw                m0, [o(pw_2675x8)]            ;t46a
+    pmulhrsw                m2, m1, [o(pw_4085x8)]        ;t48a
+    pmulhrsw                m1, [o(pw_m301x8)]            ;t47a
+    psubsw                  m5, m1, m0                    ;t46
+    paddsw                  m0, m1                        ;t47
+    psubsw                  m4, m2, m3                    ;t49
+    paddsw                  m3, m2                        ;t48
+
+ALIGN function_align
+.main2:
+    ITX_MULSUB_2W            4, 5, 1, 2, 7, m1189, 3920   ;t46a, t49a
+    mova                    m1, [rsp+gprsize*2+16*54]     ;t51
+    psubsw                  m2, m0, m6                    ;t44a
+    paddsw                  m0, m6                        ;t47a
+    psubsw                  m6, m3, m1                    ;t51a
+    paddsw                  m3, m1                        ;t48a
+    mova [rsp+gprsize*2+16*50], m0                        ;t47a
+    mova [rsp+gprsize*2+16*51], m3                        ;t48a
+    ITX_MULSUB_2W            6, 2, 0, 3, 7, m2276, 3406   ;t44, t51
+    mova [rsp+gprsize*2+16*47], m6                        ;t44
+    mova [rsp+gprsize*2+16*54], m2                        ;t51
+
+    mova                    m0, [rsp+gprsize*2+16*48]     ;t45a
+    mova                    m3, [rsp+gprsize*2+16*53]     ;t50a
+    psubsw                  m2, m4, m0                    ;t45
+    paddsw                  m4, m0                        ;t46
+    psubsw                  m6, m5, m3                    ;t50
+    paddsw                  m5, m3                        ;t49
+    ITX_MULSUB_2W            6, 2, 0, 3, 7, m2276, 3406   ;t45a, t50a
+    mova [rsp+gprsize*2+16*48], m6                        ;t45a
+    mova [rsp+gprsize*2+16*49], m4                        ;t46
+    mova [rsp+gprsize*2+16*52], m5                        ;t49
+    mova [rsp+gprsize*2+16*53], m2                        ;t50a
+
+    mova                    m0, [rsp+gprsize*2+16*43]     ;t40
+    mova                    m2, [rsp+gprsize*2+16*46]     ;t43
+    mova                    m3, [rsp+gprsize*2+16*55]     ;t52
+    mova                    m1, [rsp+gprsize*2+16*58]     ;t55
+    psubsw                  m4, m0, m2                    ;t43a
+    paddsw                  m0, m2                        ;t40a
+    psubsw                  m5, m1, m3                    ;t52a
+    paddsw                  m1, m3                        ;t55a
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, 3406, 2276    ;t43, t52
+    mova [rsp+gprsize*2+16*43], m0                        ;t40a
+    mova [rsp+gprsize*2+16*46], m5                        ;t43
+    mova [rsp+gprsize*2+16*55], m4                        ;t52
+    mova [rsp+gprsize*2+16*58], m1                        ;t55a
+
+    mova                    m0, [rsp+gprsize*2+16*44]     ;t41a
+    mova                    m2, [rsp+gprsize*2+16*45]     ;t42a
+    mova                    m3, [rsp+gprsize*2+16*56]     ;t53a
+    mova                    m1, [rsp+gprsize*2+16*57]     ;t54a
+    psubsw                  m4, m0, m2                    ;t42
+    paddsw                  m0, m2                        ;t41
+    psubsw                  m5, m1, m3                    ;t53
+    paddsw                  m1, m3                        ;t54
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, 3406, 2276    ;t42a, t53a
+    mova [rsp+gprsize*2+16*44], m0                        ;t41
+    mova [rsp+gprsize*2+16*45], m5                        ;t42a
+    mova [rsp+gprsize*2+16*56], m4                        ;t53a
+    mova [rsp+gprsize*2+16*57], m1                        ;t54
+
+    mova                    m0, [rsp+gprsize*2+16*41]     ;t38a
+    mova                    m2, [rsp+gprsize*2+16*40]     ;t37a
+    mova                    m3, [rsp+gprsize*2+16*61]     ;t58a
+    mova                    m1, [rsp+gprsize*2+16*60]     ;t57a
+    psubsw                  m4, m0, m2                    ;t37
+    paddsw                  m0, m2                        ;t38
+    psubsw                  m5, m1, m3                    ;t58
+    paddsw                  m1, m3                        ;t57
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, m4017, 799    ;t37a, t58a
+    mova [rsp+gprsize*2+16*41], m0                        ;t38
+    mova [rsp+gprsize*2+16*40], m5                        ;t37a
+    mova [rsp+gprsize*2+16*61], m4                        ;t58a
+    mova [rsp+gprsize*2+16*60], m1                        ;t57
+
+    mova                    m0, [rsp+gprsize*2+16*42]     ;t39
+    mova                    m2, [rsp+gprsize*2+16*39]     ;t36
+    mova                    m3, [rsp+gprsize*2+16*62]     ;t59
+    mova                    m1, [rsp+gprsize*2+16*59]     ;t56
+    psubsw                  m4, m0, m2                    ;t36a
+    paddsw                  m0, m2                        ;t39a
+    psubsw                  m5, m1, m3                    ;t59a
+    paddsw                  m1, m3                        ;t56a
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, m4017, 799    ;t36, t59
+    mova [rsp+gprsize*2+16*42], m0                        ;t39a
+    mova [rsp+gprsize*2+16*39], m5                        ;t36
+    mova [rsp+gprsize*2+16*62], m4                        ;t59
+    mova [rsp+gprsize*2+16*59], m1                        ;t56a
+
+    mova                    m0, [rsp+gprsize*2+16*35]     ;t32
+    mova                    m2, [rsp+gprsize*2+16*38]     ;t35
+    mova                    m3, [rsp+gprsize*2+16*63]     ;t60
+    mova                    m1, [rsp+gprsize*2+16*66]     ;t63
+    psubsw                  m4, m0, m2                    ;t35a
+    paddsw                  m0, m2                        ;t32a
+    psubsw                  m5, m1, m3                    ;t60a
+    paddsw                  m1, m3                        ;t63a
+    ITX_MULSUB_2W            5, 4, 2, 3, 7,  799, 4017    ;t35, t60
+    mova [rsp+gprsize*2+16*35], m0                        ;t32a
+    mova [rsp+gprsize*2+16*38], m5                        ;t35
+    mova [rsp+gprsize*2+16*63], m4                        ;t60
+    mova [rsp+gprsize*2+16*66], m1                        ;t63a
+
+    mova                    m0, [rsp+gprsize*2+16*36]     ;t33a
+    mova                    m2, [rsp+gprsize*2+16*37]     ;t34a
+    mova                    m3, [rsp+gprsize*2+16*64]     ;t61a
+    mova                    m1, [rsp+gprsize*2+16*65]     ;t62a
+    psubsw                  m4, m0, m2                    ;t34
+    paddsw                  m0, m2                        ;t33
+    psubsw                  m5, m1, m3                    ;t61
+    paddsw                  m1, m3                        ;t62
+    ITX_MULSUB_2W            5, 4, 2, 3, 7,  799, 4017    ;t34a, t61a
+
+    mova                    m2, [rsp+gprsize*2+16*41]     ;t38
+    mova                    m3, [rsp+gprsize*2+16*60]     ;t57
+    psubsw                  m6, m0, m2                    ;t38a
+    paddsw                  m0, m2                        ;t33a
+    psubsw                  m2, m1, m3                    ;t57a
+    paddsw                  m1, m3                        ;t62a
+    mova [rsp+gprsize*2+16*36], m0                        ;t33a
+    mova [rsp+gprsize*2+16*65], m1                        ;t62a
+    ITX_MULSUB_2W            2, 6, 0, 3, 7, 1567, 3784    ;t38, t57
+    mova [rsp+gprsize*2+16*41], m2                        ;t38
+    mova [rsp+gprsize*2+16*60], m6                        ;t57
+
+    mova                    m2, [rsp+gprsize*2+16*40]     ;t37
+    mova                    m3, [rsp+gprsize*2+16*61]     ;t58
+    psubsw                  m0, m5, m2                    ;t37
+    paddsw                  m5, m2                        ;t34
+    psubsw                  m1, m4, m3                    ;t58
+    paddsw                  m4, m3                        ;t61
+    ITX_MULSUB_2W            1, 0, 2, 3, 7, 1567, 3784    ;t37a, t58a
+    mova [rsp+gprsize*2+16*37], m5                        ;t34
+    mova [rsp+gprsize*2+16*64], m4                        ;t61
+    mova [rsp+gprsize*2+16*40], m1                        ;t37a
+    mova [rsp+gprsize*2+16*61], m0                        ;t58a
+
+    mova                    m0, [rsp+gprsize*2+16*38]     ;t35
+    mova                    m2, [rsp+gprsize*2+16*39]     ;t36
+    mova                    m3, [rsp+gprsize*2+16*62]     ;t59
+    mova                    m1, [rsp+gprsize*2+16*63]     ;t60
+    psubsw                  m4, m0, m2                    ;t36a
+    paddsw                  m0, m2                        ;t35a
+    psubsw                  m5, m1, m3                    ;t59a
+    paddsw                  m1, m3                        ;t60a
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, 1567, 3784    ;t36, t59
+    mova [rsp+gprsize*2+16*38], m0                        ;t35a
+    mova [rsp+gprsize*2+16*39], m5                        ;t36
+    mova [rsp+gprsize*2+16*62], m4                        ;t59
+    mova [rsp+gprsize*2+16*63], m1                        ;t60a
+
+    mova                    m0, [rsp+gprsize*2+16*35]     ;t32a
+    mova                    m2, [rsp+gprsize*2+16*42]     ;t39a
+    mova                    m3, [rsp+gprsize*2+16*59]     ;t56a
+    mova                    m1, [rsp+gprsize*2+16*66]     ;t63a
+    psubsw                  m4, m0, m2                    ;t39
+    paddsw                  m0, m2                        ;t32
+    psubsw                  m5, m1, m3                    ;t56
+    paddsw                  m1, m3                        ;t63
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, 1567, 3784    ;t39a, t56a
+    mova [rsp+gprsize*2+16*35], m0                        ;t32
+    mova [rsp+gprsize*2+16*42], m5                        ;t39a
+    mova [rsp+gprsize*2+16*59], m4                        ;t56a
+    mova [rsp+gprsize*2+16*66], m1                        ;t63
+
+    mova                    m0, [rsp+gprsize*2+16*50]     ;t47a
+    mova                    m2, [rsp+gprsize*2+16*43]     ;t40a
+    mova                    m3, [rsp+gprsize*2+16*58]     ;t55a
+    mova                    m1, [rsp+gprsize*2+16*51]     ;t48a
+    psubsw                  m4, m0, m2                    ;t40
+    paddsw                  m0, m2                        ;t47
+    psubsw                  m5, m1, m3                    ;t55
+    paddsw                  m1, m3                        ;t48
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, m3784, 1567   ;t40a, t55a
+    mova [rsp+gprsize*2+16*50], m0                        ;t47
+    mova [rsp+gprsize*2+16*43], m5                        ;t40a
+    mova [rsp+gprsize*2+16*58], m4                        ;t55a
+    mova [rsp+gprsize*2+16*51], m1                        ;t48
+
+    mova                    m0, [rsp+gprsize*2+16*49]     ;t46
+    mova                    m2, [rsp+gprsize*2+16*44]     ;t41
+    mova                    m3, [rsp+gprsize*2+16*57]     ;t54
+    mova                    m1, [rsp+gprsize*2+16*52]     ;t49
+    psubsw                  m4, m0, m2                    ;t41a
+    paddsw                  m0, m2                        ;t46a
+    psubsw                  m5, m1, m3                    ;t54a
+    paddsw                  m1, m3                        ;t49a
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, m3784, 1567   ;t41, t54
+    mova [rsp+gprsize*2+16*49], m0                        ;t46a
+    mova [rsp+gprsize*2+16*44], m5                        ;t41
+    mova [rsp+gprsize*2+16*57], m4                        ;t54
+    mova [rsp+gprsize*2+16*52], m1                        ;t49a
+
+    mova                    m0, [rsp+gprsize*2+16*48]     ;t45a
+    mova                    m2, [rsp+gprsize*2+16*45]     ;t42a
+    mova                    m3, [rsp+gprsize*2+16*56]     ;t53a
+    mova                    m1, [rsp+gprsize*2+16*53]     ;t50a
+    psubsw                  m4, m0, m2                    ;t42
+    paddsw                  m0, m2                        ;t45
+    psubsw                  m5, m1, m3                    ;t53
+    paddsw                  m1, m3                        ;t50
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, m3784, 1567   ;t42a, t53a
+    mova [rsp+gprsize*2+16*48], m0                        ;t45
+    mova [rsp+gprsize*2+16*45], m5                        ;t42a
+    mova [rsp+gprsize*2+16*56], m4                        ;t53a
+    mova [rsp+gprsize*2+16*53], m1                        ;t50
+
+    mova                    m0, [rsp+gprsize*2+16*47]     ;t44
+    mova                    m2, [rsp+gprsize*2+16*46]     ;t43
+    mova                    m3, [rsp+gprsize*2+16*55]     ;t52
+    mova                    m1, [rsp+gprsize*2+16*54]     ;t51
+    psubsw                  m4, m0, m2                    ;t43a
+    paddsw                  m0, m2                        ;t44a
+    psubsw                  m5, m1, m3                    ;t52a
+    paddsw                  m1, m3                        ;t51a
+    ITX_MULSUB_2W            5, 4, 2, 3, 7, m3784, 1567   ;t43, t52
+
+    mova                    m2, [rsp+gprsize*2+16*38]     ;t35a
+    mova                    m3, [rsp+gprsize*2+16*31]     ;tmp[28]
+    psubsw                  m6, m2, m0                    ;t44
+    paddsw                  m2, m0                        ;t35
+    psubsw                  m0, m3, m2                    ;out35
+    paddsw                  m2, m3                        ;out28
+    mova                    m3, [rsp+gprsize*2+16*63]     ;t60a
+    mova [rsp+gprsize*2+16*38], m0                        ;out35
+    mova [rsp+gprsize*2+16*31], m2                        ;out28
+    psubsw                  m0, m3, m1                    ;t51
+    paddsw                  m3, m1                        ;t60
+    ITX_MULSUB_2W            0, 6, 1, 2, 7, 2896, 2896    ;t44a, t51a
+    mova                    m2, [rsp+gprsize*2+16*6 ]     ;tmp[3]
+    psubsw                  m1, m2, m3                    ;out60
+    paddsw                  m2, m3                        ;out3
+    mova                    m3, [rsp+gprsize*2+16*22]     ;tmp[19]
+    mova [rsp+gprsize*2+16*63], m1                        ;out60
+    mova [rsp+gprsize*2+16*6 ], m2                        ;out3
+    psubsw                  m1, m3, m0                    ;out44
+    paddsw                  m3, m0                        ;out19
+    mova                    m2, [rsp+gprsize*2+16*15]     ;tmp[12]
+
+    mova                    m0, [rsp+gprsize*2+16*39]     ;t36
+    mova [rsp+gprsize*2+16*47], m1                        ;out44
+    mova [rsp+gprsize*2+16*22], m3                        ;out19
+    mova                    m1, [rsp+gprsize*2+16*62]     ;t59
+    psubsw                  m3, m2, m6                    ;out51
+    paddsw                  m2, m6                        ;out12
+    mova [rsp+gprsize*2+16*54], m3                        ;out51
+    mova [rsp+gprsize*2+16*15], m2                        ;out12
+    psubsw                  m2, m0, m5                    ;t43a
+    paddsw                  m0, m5                        ;t36a
+    mova                    m5, [rsp+gprsize*2+16*30]     ;tmp[27]
+    psubsw                  m3, m1, m4                    ;t52a
+    paddsw                  m1, m4                        ;t59a
+    ITX_MULSUB_2W            3, 2, 4, 6, 7, 2896, 2896    ;t43, t52
+    mova                    m4, [rsp+gprsize*2+16*7 ]     ;tmp[4 ]
+    psubsw                  m6, m5, m0                    ;out36
+    paddsw                  m5, m0                        ;out27
+    psubsw                  m0, m4, m1                    ;out59
+    paddsw                  m4, m1                        ;out4
+    mova [rsp+gprsize*2+16*39], m6                        ;out36
+    mova [rsp+gprsize*2+16*30], m5                        ;out27
+    mova [rsp+gprsize*2+16*62], m0                        ;out59
+    mova [rsp+gprsize*2+16*7 ], m4                        ;out4
+    mova                    m0, [rsp+gprsize*2+16*23]     ;tmp[20]
+    mova                    m5, [rsp+gprsize*2+16*14]     ;tmp[11]
+    psubsw                  m4, m0, m3                    ;out43
+    paddsw                  m0, m3                        ;out20
+    psubsw                  m6, m5, m2                    ;out52
+    paddsw                  m5, m2                        ;out11
+    mova [rsp+gprsize*2+16*46], m4                        ;out43
+    mova [rsp+gprsize*2+16*23], m0                        ;out20
+    mova [rsp+gprsize*2+16*55], m6                        ;out52
+    mova [rsp+gprsize*2+16*14], m5                        ;out11
+
+    mova                    m0, [rsp+gprsize*2+16*40]     ;t37a
+    mova                    m5, [rsp+gprsize*2+16*45]     ;t42a
+    mova                    m3, [rsp+gprsize*2+16*56]     ;t53a
+    mova                    m1, [rsp+gprsize*2+16*61]     ;t58a
+    mova                    m2, [rsp+gprsize*2+16*29]     ;tmp[26]
+    psubsw                  m4, m0, m5                    ;t42
+    paddsw                  m0, m5                        ;t37
+    psubsw                  m5, m1, m3                    ;t53
+    paddsw                  m1, m3                        ;t58
+    ITX_MULSUB_2W            5, 4, 3, 6, 7, 2896, 2896    ;t43, t52
+    mova                    m3, [rsp+gprsize*2+16*8 ]     ;tmp[5 ]
+    psubsw                  m6, m2, m0                    ;out37
+    paddsw                  m2, m0                        ;out26
+    psubsw                  m0, m3, m1                    ;out58
+    paddsw                  m3, m1                        ;out5
+    mova [rsp+gprsize*2+16*40], m6                        ;out37
+    mova [rsp+gprsize*2+16*29], m2                        ;out26
+    mova [rsp+gprsize*2+16*61], m0                        ;out58
+    mova [rsp+gprsize*2+16*8 ], m3                        ;out5
+    mova                    m0, [rsp+gprsize*2+16*24]     ;tmp[21]
+    mova                    m1, [rsp+gprsize*2+16*13]     ;tmp[10]
+    psubsw                  m2, m0, m5                    ;out42
+    paddsw                  m0, m5                        ;out21
+    psubsw                  m3, m1, m4                    ;out53
+    paddsw                  m1, m4                        ;out10
+    mova [rsp+gprsize*2+16*45], m2                        ;out42
+    mova [rsp+gprsize*2+16*24], m0                        ;out21
+    mova [rsp+gprsize*2+16*56], m3                        ;out53
+    mova [rsp+gprsize*2+16*13], m1                        ;out10
+
+    mova                    m0, [rsp+gprsize*2+16*41]     ;t38
+    mova                    m5, [rsp+gprsize*2+16*44]     ;t41
+    mova                    m3, [rsp+gprsize*2+16*57]     ;t54
+    mova                    m1, [rsp+gprsize*2+16*60]     ;t57
+    mova                    m2, [rsp+gprsize*2+16*28]     ;tmp[25]
+    psubsw                  m4, m0, m5                    ;t41a
+    paddsw                  m0, m5                        ;t38a
+    psubsw                  m5, m1, m3                    ;t54a
+    paddsw                  m1, m3                        ;t57a
+    ITX_MULSUB_2W            5, 4, 3, 6, 7, 2896, 2896    ;t41a, t54a
+    mova                    m3, [rsp+gprsize*2+16*9 ]     ;tmp[6 ]
+    psubsw                  m6, m2, m0                    ;out38
+    paddsw                  m2, m0                        ;out25
+    psubsw                  m0, m3, m1                    ;out57
+    paddsw                  m3, m1                        ;out6
+    mova [rsp+gprsize*2+16*41], m6                        ;out38
+    mova [rsp+gprsize*2+16*28], m2                        ;out25
+    mova [rsp+gprsize*2+16*60], m0                        ;out57
+    mova [rsp+gprsize*2+16*9 ], m3                        ;out6
+    mova                    m0, [rsp+gprsize*2+16*25]     ;tmp[22]
+    mova                    m1, [rsp+gprsize*2+16*12]     ;tmp[9 ]
+    psubsw                  m2, m0, m5                    ;out41
+    paddsw                  m0, m5                        ;out22
+    psubsw                  m3, m1, m4                    ;out54
+    paddsw                  m1, m4                        ;out9
+    mova [rsp+gprsize*2+16*44], m2                        ;out41
+    mova [rsp+gprsize*2+16*25], m0                        ;out22
+    mova [rsp+gprsize*2+16*57], m3                        ;out54
+    mova [rsp+gprsize*2+16*12], m1                        ;out9
+
+    mova                    m0, [rsp+gprsize*2+16*42]     ;t39a
+    mova                    m5, [rsp+gprsize*2+16*43]     ;t40a
+    mova                    m3, [rsp+gprsize*2+16*58]     ;t55a
+    mova                    m1, [rsp+gprsize*2+16*59]     ;t56a
+    mova                    m2, [rsp+gprsize*2+16*27]     ;tmp[24]
+    psubsw                  m4, m0, m5                    ;t40
+    paddsw                  m0, m5                        ;t39
+    psubsw                  m5, m1, m3                    ;t55
+    paddsw                  m1, m3                        ;t56
+    ITX_MULSUB_2W            5, 4, 3, 6, 7, 2896, 2896    ;t40a, t55a
+    mova                    m3, [rsp+gprsize*2+16*10]     ;tmp[7 ]
+    psubsw                  m6, m2, m0                    ;out39
+    paddsw                  m2, m0                        ;out24
+    psubsw                  m0, m3, m1                    ;out56
+    paddsw                  m3, m1                        ;out7
+    mova [rsp+gprsize*2+16*42], m6                        ;out39
+    mova [rsp+gprsize*2+16*27], m2                        ;out24
+    mova [rsp+gprsize*2+16*59], m0                        ;out56
+    mova [rsp+gprsize*2+16*10], m3                        ;out7
+    mova                    m0, [rsp+gprsize*2+16*26]     ;tmp[23]
+    mova                    m1, [rsp+gprsize*2+16*11]     ;tmp[8 ]
+    psubsw                  m2, m0, m5                    ;out40
+    paddsw                  m0, m5                        ;out23
+    psubsw                  m3, m1, m4                    ;out55
+    paddsw                  m1, m4                        ;out8
+    mova [rsp+gprsize*2+16*43], m2                        ;out40
+    mova [rsp+gprsize*2+16*26], m0                        ;out23
+    mova [rsp+gprsize*2+16*58], m3                        ;out55
+    mova [rsp+gprsize*2+16*11], m1                        ;out8
+
+    mova                    m0, [rsp+gprsize*2+16*37]     ;t34
+    mova                    m5, [rsp+gprsize*2+16*48]     ;t45
+    mova                    m3, [rsp+gprsize*2+16*53]     ;t50
+    mova                    m1, [rsp+gprsize*2+16*64]     ;t61
+    mova                    m2, [rsp+gprsize*2+16*32]     ;tmp[29]
+    psubsw                  m4, m0, m5                    ;t45a
+    paddsw                  m0, m5                        ;t34a
+    psubsw                  m5, m1, m3                    ;t50a
+    paddsw                  m1, m3                        ;t61a
+    ITX_MULSUB_2W            5, 4, 3, 6, 7, 2896, 2896    ;t45, t50
+    mova                    m3, [rsp+gprsize*2+16*5 ]     ;tmp[2 ]
+    psubsw                  m6, m2, m0                    ;out34
+    paddsw                  m2, m0                        ;out29
+    psubsw                  m0, m3, m1                    ;out61
+    paddsw                  m3, m1                        ;out2
+    mova [rsp+gprsize*2+16*37], m6                        ;out34
+    mova [rsp+gprsize*2+16*32], m2                        ;out29
+    mova [rsp+gprsize*2+16*64], m0                        ;out61
+    mova [rsp+gprsize*2+16*5 ], m3                        ;out2
+    mova                    m0, [rsp+gprsize*2+16*21]     ;tmp[18]
+    mova                    m1, [rsp+gprsize*2+16*16]     ;tmp[13]
+    psubsw                  m2, m0, m5                    ;out45
+    paddsw                  m0, m5                        ;out18
+    psubsw                  m3, m1, m4                    ;out50
+    paddsw                  m1, m4                        ;out13
+    mova [rsp+gprsize*2+16*48], m2                        ;out45
+    mova [rsp+gprsize*2+16*21], m0                        ;out18
+    mova [rsp+gprsize*2+16*53], m3                        ;out50
+    mova [rsp+gprsize*2+16*16], m1                        ;out13
+
+    mova                    m0, [rsp+gprsize*2+16*36]     ;t33a
+    mova                    m5, [rsp+gprsize*2+16*49]     ;t46a
+    mova                    m3, [rsp+gprsize*2+16*52]     ;t49a
+    mova                    m1, [rsp+gprsize*2+16*65]     ;t62a
+    mova                    m2, [rsp+gprsize*2+16*33]     ;tmp[30]
+    psubsw                  m4, m0, m5                    ;t46
+    paddsw                  m0, m5                        ;t33
+    psubsw                  m5, m1, m3                    ;t49
+    paddsw                  m1, m3                        ;t62
+    ITX_MULSUB_2W            5, 4, 3, 6, 7, 2896, 2896    ;t45, t50
+    mova                    m3, [rsp+gprsize*2+16*4 ]     ;tmp[1 ]
+    psubsw                  m6, m2, m0                    ;out33
+    paddsw                  m2, m0                        ;out30
+    psubsw                  m0, m3, m1                    ;out62
+    paddsw                  m3, m1                        ;out1
+    mova [rsp+gprsize*2+16*36], m6                        ;out33
+    mova [rsp+gprsize*2+16*33], m2                        ;out30
+    mova [rsp+gprsize*2+16*65], m0                        ;out62
+    mova [rsp+gprsize*2+16*4 ], m3                        ;out1
+    mova                    m0, [rsp+gprsize*2+16*20]     ;tmp[17]
+    mova                    m1, [rsp+gprsize*2+16*17]     ;tmp[14]
+    psubsw                  m2, m0, m5                    ;out46
+    paddsw                  m0, m5                        ;out17
+    psubsw                  m3, m1, m4                    ;out49
+    paddsw                  m1, m4                        ;out14
+    mova [rsp+gprsize*2+16*49], m2                        ;out46
+    mova [rsp+gprsize*2+16*20], m0                        ;out17
+    mova [rsp+gprsize*2+16*52], m3                        ;out49
+    mova [rsp+gprsize*2+16*17], m1                        ;out14
+
+    mova                    m0, [rsp+gprsize*2+16*35]     ;t32
+    mova                    m5, [rsp+gprsize*2+16*50]     ;t47
+    mova                    m3, [rsp+gprsize*2+16*51]     ;t48
+    mova                    m1, [rsp+gprsize*2+16*66]     ;t63
+    mova                    m2, [rsp+gprsize*2+16*34]     ;tmp[31]
+    psubsw                  m4, m0, m5                    ;t47a
+    paddsw                  m0, m5                        ;t32a
+    psubsw                  m5, m1, m3                    ;t48a
+    paddsw                  m1, m3                        ;t63a
+    ITX_MULSUB_2W            5, 4, 3, 6, 7, 2896, 2896    ;t47, t48
+    mova                    m3, [rsp+gprsize*2+16*3 ]     ;tmp[0 ]
+    psubsw                  m6, m2, m0                    ;out32
+    paddsw                  m2, m0                        ;out31
+    psubsw                  m0, m3, m1                    ;out63
+    paddsw                  m3, m1                        ;out0
+    mova [rsp+gprsize*2+16*35], m6                        ;out32
+    mova [rsp+gprsize*2+16*34], m2                        ;out31
+    mova [rsp+gprsize*2+16*66], m0                        ;out63
+    mova [rsp+gprsize*2+16*3 ], m3                        ;out0
+    mova                    m0, [rsp+gprsize*2+16*19]     ;tmp[16]
+    mova                    m1, [rsp+gprsize*2+16*18]     ;tmp[15]
+    psubsw                  m2, m0, m5                    ;out47
+    paddsw                  m0, m5                        ;out16
+    psubsw                  m3, m1, m4                    ;out48
+    paddsw                  m1, m4                        ;out15
+    mova [rsp+gprsize*2+16*50], m2                        ;out47
+    mova [rsp+gprsize*2+16*19], m0                        ;out16
+    mova [rsp+gprsize*2+16*51], m3                        ;out48
+    mova [rsp+gprsize*2+16*18], m1                        ;out15
+    ret
+
+
+cglobal inv_txfm_add_dct_dct_64x16_8bpc, 4, 6, 8, 16*132, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+
+    call m(idct_64x16_internal_8bpc)
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_8192)]
+    mov               [coeffq], eobd
+    mov                    r3d, 16
+    lea                   tx2q, [o(.end)]
+
+.body:
+    pmulhrsw                m0, m2
+    movd                    m2, [o(pw_2048)]  ;intentionally rip-relative
+    pmulhrsw                m0, m1
+    pmulhrsw                m0, m2
+    pshuflw                 m0, m0, q0000
+    punpcklwd               m0, m0
+    pxor                    m7, m7
+
+.loop:
+    mova                    m1, [dstq+16*0]
+    mova                    m3, [dstq+16*1]
+    mova                    m5, [dstq+16*2]
+    mova                    m6, [dstq+16*3]
+    punpckhbw               m2, m1, m7
+    punpcklbw               m1, m7
+    punpckhbw               m4, m3, m7
+    punpcklbw               m3, m7
+    paddw                   m2, m0
+    paddw                   m1, m0
+    paddw                   m4, m0
+    paddw                   m3, m0
+    packuswb                m1, m2
+    packuswb                m3, m4
+    punpckhbw               m2, m5, m7
+    punpcklbw               m5, m7
+    punpckhbw               m4, m6, m7
+    punpcklbw               m6, m7
+    paddw                   m2, m0
+    paddw                   m5, m0
+    paddw                   m4, m0
+    paddw                   m6, m0
+    packuswb                m5, m2
+    packuswb                m6, m4
+    mova           [dstq+16*0], m1
+    mova           [dstq+16*1], m3
+    mova           [dstq+16*2], m5
+    mova           [dstq+16*3], m6
+    add                   dstq, strideq
+    dec                    r3d
+    jg .loop
+    jmp                   tx2q
+
+.end:
+    RET
+
+
+%macro LOAD_4ROWS 2-3 0 ;src, stride, is_rect2
+
+%if %3
+    mova                 m3, [o(pw_2896x8)]
+    pmulhrsw             m0, m3, [%1+%2*0]
+    pmulhrsw             m1, m3, [%1+%2*1]
+    pmulhrsw             m2, m3, [%1+%2*2]
+    pmulhrsw             m3, [%1+%2*3]
+%else
+    mova                 m0, [%1+%2*0]
+    mova                 m1, [%1+%2*1]
+    mova                 m2, [%1+%2*2]
+    mova                 m3, [%1+%2*3]
+%endif
+%endmacro
+
+%macro LOAD_4ROWS_H 2 ;src, stride
+    mova                 m4, [%1+%2*0]
+    mova                 m5, [%1+%2*1]
+    mova                 m6, [%1+%2*2]
+    mova                 m7, [%1+%2*3]
+%endmacro
+
+cglobal idct_64x16_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mov                    r3d, 2
+    mov  [rsp+gprsize*2+16*67], dstq
+    lea                   dstq, [rsp+gprsize+16*68]
+
+.pass1_loop:
+    LOAD_4ROWS     coeffq+32*0, 32*8
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    pxor                    m4, m4
+    LOAD_4ROWS     coeffq+32*4, 32*8
+
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    LOAD_8ROWS     coeffq+32*2, 32*4
+    mova   [rsp+gprsize+16*19], m0
+    mova   [rsp+gprsize+16*26], m1
+    mova   [rsp+gprsize+16*23], m2
+    mova   [rsp+gprsize+16*22], m3
+    mova   [rsp+gprsize+16*21], m4
+    mova   [rsp+gprsize+16*24], m5
+    mova   [rsp+gprsize+16*25], m6
+    mova   [rsp+gprsize+16*20], m7
+
+    call m(idct_8x32_internal_8bpc).main_fast
+    SAVE_8ROWS    rsp+gprsize+16*3, 16
+
+    LOAD_8ROWS     coeffq+32*1, 32*2
+    mova   [rsp+gprsize+16*35], m0                        ;in1
+    mova   [rsp+gprsize+16*49], m1                        ;in3
+    mova   [rsp+gprsize+16*43], m2                        ;in5
+    mova   [rsp+gprsize+16*41], m3                        ;in7
+    mova   [rsp+gprsize+16*39], m4                        ;in9
+    mova   [rsp+gprsize+16*45], m5                        ;in11
+    mova   [rsp+gprsize+16*47], m6                        ;in13
+    mova   [rsp+gprsize+16*37], m7                        ;in15
+
+    LOAD_8ROWS    coeffq+32*17, 32*2
+    mova   [rsp+gprsize+16*63], m0                        ;in17
+    mova   [rsp+gprsize+16*53], m1                        ;in19
+    mova   [rsp+gprsize+16*55], m2                        ;in21
+    mova   [rsp+gprsize+16*61], m3                        ;in23
+    mova   [rsp+gprsize+16*59], m4                        ;in25
+    mova   [rsp+gprsize+16*57], m5                        ;in27
+    mova   [rsp+gprsize+16*51], m6                        ;in29
+    mova   [rsp+gprsize+16*65], m7                        ;in31
+
+    call m(idct_16x64_internal_8bpc).main
+
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end:
+    SAVE_8ROWS     coeffq+32*0, 32
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+32*8, 32
+    LOAD_8ROWS   rsp+gprsize+16*19, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end2)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end2:
+    SAVE_8ROWS    coeffq+32*16, 32
+    LOAD_8ROWS   rsp+gprsize+16*27, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end3)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end3:
+    SAVE_8ROWS    coeffq+32*24, 32
+    LOAD_8ROWS   rsp+gprsize+16*35, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end4)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end4:
+    SAVE_8ROWS       dstq+32*0, 32
+    LOAD_8ROWS   rsp+gprsize+16*43, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end5)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end5:
+    SAVE_8ROWS       dstq+32*8, 32
+    LOAD_8ROWS   rsp+gprsize+16*51, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end6)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end6:
+    SAVE_8ROWS      dstq+32*16, 32
+    LOAD_8ROWS   rsp+gprsize+16*59, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end7)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end7:
+    SAVE_8ROWS      dstq+32*24, 32
+
+    add                 coeffq, 16
+    add                   dstq, 16
+    dec                    r3d
+    jg .pass1_loop
+
+.pass2:
+    mov                   dstq, [rsp+gprsize*2+16*67]
+    sub                 coeffq, 32
+    mov                    r3d, 4
+
+.pass2_loop:
+    mov  [rsp+gprsize*1+16*67], r3d
+
+    LOAD_4ROWS     coeffq+16*0, 32*2
+    LOAD_4ROWS_H   coeffq+16*1, 32*2
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_4ROWS     coeffq+16*2, 32*2
+    LOAD_4ROWS_H   coeffq+16*3, 32*2
+    call m(idct_16x8_internal_8bpc).main
+
+    mov                    r3, dstq
+    lea                  tx2q, [o(.end)]
+    lea                  dstq, [dstq+strideq*8]
+    jmp  m(idct_8x8_internal_8bpc).end
+
+.end:
+    LOAD_8ROWS   rsp+gprsize+16*3, 16
+    mova   [rsp+gprsize+16*0], m7
+    lea                  tx2q, [o(.end1)]
+    mov                  dstq, r3
+    jmp  m(idct_8x8_internal_8bpc).end
+
+.end1:
+    pxor                   m7, m7
+    REPX  {mova [coeffq+16*x], m7}, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15
+
+    add                 coeffq, 16*16
+    mov                    r3d, [rsp+gprsize*1+16*67]
+    mov                   dstq, [rsp+gprsize*2+16*67]
+    add                   dstq, 8
+    mov  [rsp+gprsize*2+16*67], dstq
+    dec                    r3d
+    jg .pass2_loop
+
+    mov                    r3d, 4
+    lea                 coeffq, [rsp+gprsize+16*68]
+.pass2_loop2:
+    mov  [rsp+gprsize*1+16*67], r3d
+
+    LOAD_4ROWS     coeffq+16*0, 32*2
+    LOAD_4ROWS_H   coeffq+16*1, 32*2
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_4ROWS     coeffq+16*2, 32*2
+    LOAD_4ROWS_H   coeffq+16*3, 32*2
+    call m(idct_16x8_internal_8bpc).main
+
+    mov                    r3, dstq
+    lea                  tx2q, [o(.end2)]
+    lea                  dstq, [dstq+strideq*8]
+    jmp  m(idct_8x8_internal_8bpc).end
+
+.end2:
+    LOAD_8ROWS   rsp+gprsize+16*3, 16
+    mova   [rsp+gprsize+16*0], m7
+    lea                  tx2q, [o(.end3)]
+    mov                  dstq, r3
+    jmp  m(idct_8x8_internal_8bpc).end
+
+.end3:
+
+    add                 coeffq, 16*16
+    mov                    r3d, [rsp+gprsize*1+16*67]
+    mov                   dstq, [rsp+gprsize*2+16*67]
+    add                   dstq, 8
+    mov  [rsp+gprsize*2+16*67], dstq
+    dec                    r3d
+    jg .pass2_loop2
+    ret
+
+
+cglobal inv_txfm_add_dct_dct_32x64_8bpc, 4, 6, 8, 16*68, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+    call m(idct_32x64_internal_8bpc)
+.end:
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_16384)]
+    mov               [coeffq], eobd
+    pmulhrsw                m0, m1
+    mov                    r3d, 64
+    lea                   tx2q, [o(.end)]
+    jmp m(inv_txfm_add_dct_dct_32x8_8bpc).body
+
+
+cglobal idct_32x64_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mov                    r4d, 2
+    sub                   eobd, 136
+    mov  [rsp+gprsize*1+16*67], eobd
+    mov                    r3d, 4
+    cmovs                  r3d, r4d
+
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+
+    mov  [rsp+gprsize*2+16*67], coeffq
+
+.pass1_loop:
+    LOAD_8ROWS     coeffq+64*1, 64*2, 1
+    mova   [rsp+gprsize+16*19], m0                        ;in1
+    mova   [rsp+gprsize+16*26], m1                        ;in3
+    mova   [rsp+gprsize+16*23], m2                        ;in5
+    mova   [rsp+gprsize+16*22], m3                        ;in7
+    mova   [rsp+gprsize+16*21], m4                        ;in9
+    mova   [rsp+gprsize+16*24], m5                        ;in11
+    mova   [rsp+gprsize+16*25], m6                        ;in13
+    mova   [rsp+gprsize+16*20], m7                        ;in15
+
+    mov                   tx2d, [rsp+gprsize*1+16*67]
+    test                  tx2d, tx2d
+    jl .fast
+
+.full:
+    LOAD_8ROWS     coeffq+64*0, 64*4, 1
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_8ROWS     coeffq+64*2, 64*4, 1
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    LOAD_8ROWS    coeffq+64*17, 64*2, 1
+    mova   [rsp+gprsize+16*33], m0                        ;in17
+    mova   [rsp+gprsize+16*28], m1                        ;in19
+    mova   [rsp+gprsize+16*29], m2                        ;in21
+    mova   [rsp+gprsize+16*32], m3                        ;in23
+    mova   [rsp+gprsize+16*31], m4                        ;in25
+    mova   [rsp+gprsize+16*30], m5                        ;in27
+    mova   [rsp+gprsize+16*27], m6                        ;in29
+    mova   [rsp+gprsize+16*34], m7                        ;in31
+
+    call m(idct_8x32_internal_8bpc).main
+    jmp .pass1_end
+
+.fast:
+    LOAD_4ROWS          coeffq, 256, 1
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+    LOAD_4ROWS    coeffq+128*1, 256, 1
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    call m(idct_8x32_internal_8bpc).main_fast
+
+.pass1_end:
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+64*0, 64
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end2)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end2:
+    SAVE_8ROWS     coeffq+64*8, 64
+    LOAD_8ROWS   rsp+gprsize+16*19, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end3)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end3:
+    SAVE_8ROWS    coeffq+64*16, 64
+    LOAD_8ROWS   rsp+gprsize+16*27, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end4)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end4:
+    SAVE_8ROWS    coeffq+64*24, 64
+
+    add                 coeffq, 16
+    dec                    r3d
+    jg .pass1_loop
+
+.pass2:
+    mov                 coeffq, [rsp+gprsize*2+16*67]
+    mov                    r3d, 4
+    lea                     r4, [dstq+8]
+    mov  [rsp+gprsize*2+16*67], r4
+    lea                     r4, [o(m(idct_16x64_internal_8bpc).end1)]
+    jmp m(idct_16x64_internal_8bpc).pass2_loop
+
+
+cglobal inv_txfm_add_dct_dct_64x32_8bpc, 4, 6, 8, 16*197, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+    call m(idct_64x32_internal_8bpc)
+.end:
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_16384)]
+    pmulhrsw                m0, m1
+    mov               [coeffq], eobd
+    mov                    r3d, 32
+    lea                   tx2q, [o(.end)]
+    jmp m(inv_txfm_add_dct_dct_64x16_8bpc).body
+
+
+cglobal idct_64x32_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mov                    r4d, 2
+    sub                   eobd, 136
+    mov  [rsp+gprsize*1+16*67], eobd
+    mov                    r3d, 4
+    cmovs                  r3d, r4d
+
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+
+    mov  [rsp+gprsize*2+16*67], coeffq
+    mov  [rsp+gprsize*3+16*67], dstq
+    lea                   dstq, [rsp+gprsize+16*69]
+    mov  [rsp+gprsize*4+16*67], dstq
+
+.pass1_loop:
+    LOAD_4ROWS     coeffq+64*0, 64*8, 1
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    pxor                    m4, m4
+    LOAD_4ROWS     coeffq+64*4, 64*8, 1
+
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    LOAD_8ROWS     coeffq+64*2, 64*4, 1
+    mova   [rsp+gprsize+16*19], m0
+    mova   [rsp+gprsize+16*26], m1
+    mova   [rsp+gprsize+16*23], m2
+    mova   [rsp+gprsize+16*22], m3
+    mova   [rsp+gprsize+16*21], m4
+    mova   [rsp+gprsize+16*24], m5
+    mova   [rsp+gprsize+16*25], m6
+    mova   [rsp+gprsize+16*20], m7
+
+    call m(idct_8x32_internal_8bpc).main_fast
+    SAVE_8ROWS    rsp+gprsize+16*3, 16
+
+    LOAD_8ROWS     coeffq+64*1, 64*2, 1
+    mova   [rsp+gprsize+16*35], m0                        ;in1
+    mova   [rsp+gprsize+16*49], m1                        ;in3
+    mova   [rsp+gprsize+16*43], m2                        ;in5
+    mova   [rsp+gprsize+16*41], m3                        ;in7
+    mova   [rsp+gprsize+16*39], m4                        ;in9
+    mova   [rsp+gprsize+16*45], m5                        ;in11
+    mova   [rsp+gprsize+16*47], m6                        ;in13
+    mova   [rsp+gprsize+16*37], m7                        ;in15
+
+    LOAD_8ROWS    coeffq+64*17, 64*2, 1
+    mova   [rsp+gprsize+16*63], m0                        ;in17
+    mova   [rsp+gprsize+16*53], m1                        ;in19
+    mova   [rsp+gprsize+16*55], m2                        ;in21
+    mova   [rsp+gprsize+16*61], m3                        ;in23
+    mova   [rsp+gprsize+16*59], m4                        ;in25
+    mova   [rsp+gprsize+16*57], m5                        ;in27
+    mova   [rsp+gprsize+16*51], m6                        ;in29
+    mova   [rsp+gprsize+16*65], m7                        ;in31
+
+    call m(idct_16x64_internal_8bpc).main
+
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end:
+    SAVE_8ROWS     coeffq+64*0, 64
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+64*8, 64
+    LOAD_8ROWS   rsp+gprsize+16*19, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end2)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end2:
+    SAVE_8ROWS    coeffq+64*16, 64
+    LOAD_8ROWS   rsp+gprsize+16*27, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end3)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end3:
+    SAVE_8ROWS    coeffq+64*24, 64
+    LOAD_8ROWS   rsp+gprsize+16*35, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end4)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end4:
+    SAVE_8ROWS       dstq+64*0, 64
+    LOAD_8ROWS   rsp+gprsize+16*43, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end5)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end5:
+    SAVE_8ROWS       dstq+64*8, 64
+    LOAD_8ROWS   rsp+gprsize+16*51, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end6)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end6:
+    SAVE_8ROWS      dstq+64*16, 64
+    LOAD_8ROWS   rsp+gprsize+16*59, 16
+    mova    [rsp+gprsize+16*0], m7
+    lea                   tx2q, [o(.pass1_end7)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end
+
+.pass1_end7:
+    SAVE_8ROWS      dstq+64*24, 64
+
+    add                 coeffq, 16
+    add                   dstq, 16
+    dec                    r3d
+    jg .pass1_loop
+
+.pass2:
+    mov                 coeffq, [rsp+gprsize*4+16*67]
+    mov                   dstq, [rsp+gprsize*3+16*67]
+    mov                   eobd, [rsp+gprsize*1+16*67]
+    lea                   dstq, [dstq+32]
+    mov  [rsp+gprsize*1+16*35], eobd
+    lea                   tx2q, [o(.pass2_end)]
+    mov                    r3d, 4
+    jmp m(idct_32x32_internal_8bpc).pass2_loop
+
+.pass2_end:
+    mova    [rsp+gprsize+16*0], m7
+    lea                     r3, [o(.pass2_end1)]
+    jmp  m(idct_8x32_internal_8bpc).end2
+
+.pass2_end1:
+    lea                   tx2q, [o(.pass2_end)]
+    add                 coeffq, 16*32
+    mov                   dstq, [rsp+gprsize*2+16*35]
+    mov                    r3d, [rsp+gprsize*3+16*35]
+    dec                    r3d
+    jg m(idct_32x32_internal_8bpc).pass2_loop
+
+.pass2_end2:
+    mov                   dstq, [rsp+gprsize*3+16*67]
+    mov                 coeffq, [rsp+gprsize*2+16*67]
+    lea                   tx2q, [o(m(idct_32x32_internal_8bpc).pass2_end)]
+    mov                    r3d, 4
+    jmp m(idct_32x32_internal_8bpc).pass2_loop
+
+
+cglobal inv_txfm_add_dct_dct_64x64_8bpc, 4, 6, 8, 16*197, dst, stride, coeff, eob, tx2
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+    test                  eobd, eobd
+    jz .dconly
+
+    call m(idct_64x64_internal_8bpc)
+    RET
+
+.dconly:
+    movd                    m1, [o(pw_2896x8)]
+    pmulhrsw                m0, m1, [coeffq]
+    movd                    m2, [o(pw_8192)]
+    mov               [coeffq], eobd
+    mov                    r3d, 64
+    lea                   tx2q, [o(m(inv_txfm_add_dct_dct_64x32_8bpc).end)]
+    jmp m(inv_txfm_add_dct_dct_64x16_8bpc).body
+
+cglobal idct_64x64_internal_8bpc, 0, 0, 0, dst, stride, coeff, eob, tx2
+    mov                    r5d, 4
+    mov                    r4d, 2
+    sub                   eobd, 136
+    cmovns                 r4d, r5d
+
+%if ARCH_X86_32
+    LEA                     r5, $$
+%endif
+
+    mov  [rsp+gprsize*1+16*67], eobd
+    mov                    r3d, r4d
+    mov  [rsp+gprsize*4+16*67], coeffq
+    mov  [rsp+gprsize*3+16*67], dstq
+    lea                   dstq, [rsp+gprsize+16*69]
+    mov  [rsp+gprsize*2+16*67], dstq
+
+.pass1_loop:
+    LOAD_4ROWS     coeffq+64*0, 64*8
+    pxor                    m4, m4
+    REPX          {mova x, m4}, m5, m6, m7
+    call  m(idct_8x8_internal_8bpc).main
+    SAVE_7ROWS    rsp+gprsize+16*3, 16
+
+    pxor                    m4, m4
+    LOAD_4ROWS     coeffq+64*4, 64*8
+
+    REPX          {mova x, m4}, m5, m6, m7
+    call m(idct_16x8_internal_8bpc).main
+    mova                    m7, [rsp+gprsize+16*0]
+    SAVE_8ROWS   rsp+gprsize+16*11, 16
+
+    LOAD_8ROWS     coeffq+64*2, 64*4
+    mova   [rsp+gprsize+16*19], m0
+    mova   [rsp+gprsize+16*26], m1
+    mova   [rsp+gprsize+16*23], m2
+    mova   [rsp+gprsize+16*22], m3
+    mova   [rsp+gprsize+16*21], m4
+    mova   [rsp+gprsize+16*24], m5
+    mova   [rsp+gprsize+16*25], m6
+    mova   [rsp+gprsize+16*20], m7
+
+    call m(idct_8x32_internal_8bpc).main_fast
+    SAVE_8ROWS    rsp+gprsize+16*3, 16
+
+    LOAD_8ROWS     coeffq+64*1, 64*2
+    mova   [rsp+gprsize+16*35], m0                        ;in1
+    mova   [rsp+gprsize+16*49], m1                        ;in3
+    mova   [rsp+gprsize+16*43], m2                        ;in5
+    mova   [rsp+gprsize+16*41], m3                        ;in7
+    mova   [rsp+gprsize+16*39], m4                        ;in9
+    mova   [rsp+gprsize+16*45], m5                        ;in11
+    mova   [rsp+gprsize+16*47], m6                        ;in13
+    mova   [rsp+gprsize+16*37], m7                        ;in15
+
+    LOAD_8ROWS    coeffq+64*17, 64*2
+    mova   [rsp+gprsize+16*63], m0                        ;in17
+    mova   [rsp+gprsize+16*53], m1                        ;in19
+    mova   [rsp+gprsize+16*55], m2                        ;in21
+    mova   [rsp+gprsize+16*61], m3                        ;in23
+    mova   [rsp+gprsize+16*59], m4                        ;in25
+    mova   [rsp+gprsize+16*57], m5                        ;in27
+    mova   [rsp+gprsize+16*51], m6                        ;in29
+    mova   [rsp+gprsize+16*65], m7                        ;in31
+
+    call m(idct_16x64_internal_8bpc).main
+
+    LOAD_8ROWS    rsp+gprsize+16*3, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end:
+    SAVE_8ROWS     coeffq+64*0, 64
+    LOAD_8ROWS   rsp+gprsize+16*11, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end1)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end1:
+    SAVE_8ROWS     coeffq+64*8, 64
+    LOAD_8ROWS   rsp+gprsize+16*19, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end2)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end2:
+    SAVE_8ROWS    coeffq+64*16, 64
+    LOAD_8ROWS   rsp+gprsize+16*27, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end3)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end3:
+    SAVE_8ROWS    coeffq+64*24, 64
+    LOAD_8ROWS   rsp+gprsize+16*35, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end4)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end4:
+    SAVE_8ROWS       dstq+64*0, 64
+    LOAD_8ROWS   rsp+gprsize+16*43, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end5)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end5:
+    SAVE_8ROWS       dstq+64*8, 64
+    LOAD_8ROWS   rsp+gprsize+16*51, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end6)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end6:
+    SAVE_8ROWS      dstq+64*16, 64
+    LOAD_8ROWS   rsp+gprsize+16*59, 16
+    mova    [rsp+gprsize+16*0], m7
+    mova                    m7, [o(pw_8192)]
+    lea                   tx2q, [o(.pass1_end7)]
+    jmp   m(idct_8x8_internal_8bpc).pass1_end1
+
+.pass1_end7:
+    SAVE_8ROWS      dstq+64*24, 64
+
+    add                 coeffq, 16
+    add                   dstq, 16
+    dec                    r3d
+    jg .pass1_loop
+
+.pass2:
+    mov                   dstq, [rsp+gprsize*3+16*67]
+    mov                 coeffq, [rsp+gprsize*2+16*67]
+    lea                   dstq, [dstq+32]
+    mov                    r3d, 4
+    lea                     r4, [dstq+8]
+    mov  [rsp+gprsize*2+16*67], r4
+    lea                     r4, [o(.pass2_end)]
+    jmp m(idct_16x64_internal_8bpc).pass2_loop
+
+.pass2_end:
+    LOAD_8ROWS   rsp+gprsize+16*35, 16
+    lea                   dstq, [dstq+strideq*2]
+    lea                     r3, [rsp+16*32+gprsize]
+    mova    [rsp+gprsize+16*0], m7
+    call m(idct_16x64_internal_8bpc).write
+    mov                   dstq, [rsp+gprsize*2+16*67]
+    mov                    r3d, [rsp+gprsize*3+16*67]
+    lea                     r4, [dstq+8]
+    mov  [rsp+gprsize*2+16*67], r4
+    lea                     r4, [o(.pass2_end)]
+
+    dec                    r3d
+    jg  m(idct_16x64_internal_8bpc).pass2_loop
+
+.pass2_end2:
+    mov                 coeffq, [rsp+gprsize*4+16*67]
+    mov                   dstq, [rsp+gprsize*2+16*67]
+    mov                    r3d, 4
+    sub                   dstq, 72
+    lea                     r4, [dstq+8]
+    mov  [rsp+gprsize*2+16*67], r4
+    lea                     r4, [o(m(idct_16x64_internal_8bpc).end1)]
+    jmp m(idct_16x64_internal_8bpc).pass2_loop
diff --git a/media/libdav1d/src/src/x86/loopfilter.h b/media/libdav1d/src/src/x86/loopfilter.h
new file mode 100644
index 0000000000..9535c753fb
--- /dev/null
+++ b/media/libdav1d/src/src/x86/loopfilter.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/loopfilter.h"
+
+#define decl_loopfilter_sb_fns(ext) \
+decl_loopfilter_sb_fn(BF(dav1d_lpf_h_sb_y, ext)); \
+decl_loopfilter_sb_fn(BF(dav1d_lpf_v_sb_y, ext)); \
+decl_loopfilter_sb_fn(BF(dav1d_lpf_h_sb_uv, ext)); \
+decl_loopfilter_sb_fn(BF(dav1d_lpf_v_sb_uv, ext))
+
+decl_loopfilter_sb_fns(ssse3);
+decl_loopfilter_sb_fns(avx2);
+decl_loopfilter_sb_fns(avx512icl);
+
+static ALWAYS_INLINE void loop_filter_dsp_init_x86(Dav1dLoopFilterDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSSE3)) return;
+
+    c->loop_filter_sb[0][0] = BF(dav1d_lpf_h_sb_y, ssse3);
+    c->loop_filter_sb[0][1] = BF(dav1d_lpf_v_sb_y, ssse3);
+    c->loop_filter_sb[1][0] = BF(dav1d_lpf_h_sb_uv, ssse3);
+    c->loop_filter_sb[1][1] = BF(dav1d_lpf_v_sb_uv, ssse3);
+
+#if ARCH_X86_64
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2)) return;
+
+    c->loop_filter_sb[0][0] = BF(dav1d_lpf_h_sb_y, avx2);
+    c->loop_filter_sb[0][1] = BF(dav1d_lpf_v_sb_y, avx2);
+    c->loop_filter_sb[1][0] = BF(dav1d_lpf_h_sb_uv, avx2);
+    c->loop_filter_sb[1][1] = BF(dav1d_lpf_v_sb_uv, avx2);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL)) return;
+
+    c->loop_filter_sb[0][1] = BF(dav1d_lpf_v_sb_y, avx512icl);
+    c->loop_filter_sb[1][1] = BF(dav1d_lpf_v_sb_uv, avx512icl);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SLOW_GATHER)) {
+        c->loop_filter_sb[0][0] = BF(dav1d_lpf_h_sb_y, avx512icl);
+        c->loop_filter_sb[1][0] = BF(dav1d_lpf_h_sb_uv, avx512icl);
+    }
+#endif
+}
diff --git a/media/libdav1d/src/src/x86/loopfilter16_avx2.asm b/media/libdav1d/src/src/x86/loopfilter16_avx2.asm
new file mode 100644
index 0000000000..ed83000ac2
--- /dev/null
+++ b/media/libdav1d/src/src/x86/loopfilter16_avx2.asm
@@ -0,0 +1,1161 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 32
+
+pb_mask: dd 1, 1, 2, 2, 4, 4, 8, 8
+pb_4x1_4x5_4x9_4x13: times 4 db 0, 1
+                     times 4 db 8, 9
+                     times 4 db 0, 1
+                     times 4 db 8, 9
+
+pw_1:     times 16 dw 1
+pw_2:     times 16 dw 2
+pw_3:     times 16 dw 3
+pw_4096:  times 2 dw 4096
+
+; 10bpc/12bpc:
+pw_4:     times 2 dw 4
+          times 2 dw 16
+clip_max: times 2 dw 511
+          times 2 dw 2047
+clip_min: times 2 dw -512
+          times 2 dw -2048
+
+SECTION .text
+
+;        in:            out:
+; mm%1   a b c d        a e i m
+; mm%2   e f g h        b f j n
+; mm%3   i j k l   ->   c g k o
+; mm%4   m n o p        d h l p
+%macro TRANSPOSE4X4W 5
+    punpcklwd        m%5, m%1, m%2
+    punpckhwd        m%1, m%2
+    punpcklwd        m%2, m%3, m%4
+    punpckhwd        m%3, m%4
+    punpckldq        m%4, m%5, m%2
+    punpckhdq        m%5, m%2
+    punpckldq        m%2, m%1, m%3
+    punpckhdq        m%1, m%3
+
+    SWAP              %1, %4
+    SWAP              %2, %5, %3
+%endmacro
+
+;         in:                  out:
+; xmm%1   a b c d e f g h      a i q y 6 E M U
+; xmm%2   i j k l m n o p      b j r z 7 F N V
+; xmm%3   q r s t u v w x      c k s 0 8 G O W
+; xmm%4   y z 0 1 2 3 4 5      d l t 1 9 H P X
+; xmm%5   6 7 8 9 A B C D  ->  e m u 2 A I Q Y
+; xmm%6   E F G H I J K L      f n v 3 B J R Z
+; xmm%7   M N O P Q R S T      g o w 4 C K S +
+; xmm%8   U V W X Y Z + =      h p x 5 D L T =
+%macro TRANSPOSE8X8W 9
+    ; xmm%1   a b c d e f g h      a i q y b j r z
+    ; xmm%2   i j k l m n o p      c k s 0 d l t 1
+    ; xmm%3   q r s t u v w x  ->  e m u 2 f n v 3
+    ; xmm%4   y z 0 1 2 3 4 5      g o w 4 h p x 5
+    TRANSPOSE4X4W     %1, %2, %3, %4, %9
+
+    ; xmm%5   6 7 8 9 A B C D      6 E M U 7 F N V
+    ; xmm%6   E F G H I J K L      8 G O W 9 H P X
+    ; xmm%7   M N O P Q R S T  ->  A I Q Y B J R Z
+    ; xmm%8   U V W X Y Z + =      C K S + D L T =
+    TRANSPOSE4X4W     %5, %6, %7, %8, %9
+
+    ; xmm%1   a i q y b j r z      a i q y 6 E M U
+    ; xmm%2   c k s 0 d l t 1      b j r z 7 F N V
+    ; xmm%3   e m u 2 f n v 3      c k s 0 8 G O W
+    ; xmm%4   g o w 4 h p x 5      d l t 1 9 H P X
+    ; xmm%5   6 E M U 7 F N V  ->  e m u 2 A I Q Y
+    ; xmm%6   8 G O W 9 H P X      f n v 3 B J R Z
+    ; xmm%7   A I Q Y B J R Z      g o w 4 C K S +
+    ; xmm%8   C K S + D L T =      h p x 5 D L T =
+    punpckhqdq       m%9, m%1, m%5
+    punpcklqdq       m%1, m%5
+    punpckhqdq       m%5, m%2, m%6
+    punpcklqdq       m%2, m%6
+    punpckhqdq       m%6, m%3, m%7
+    punpcklqdq       m%3, m%7
+    punpckhqdq       m%7, m%4, m%8
+    punpcklqdq       m%4, m%8
+
+    SWAP %8, %7, %4, %5, %3, %2, %9
+%endmacro
+
+; transpose and write m3-6, everything else is scratch
+%macro TRANSPOSE_8x4_AND_WRITE_4x16 0
+    ; transpose 8x4
+    punpcklwd     m0, m3, m4
+    punpckhwd     m3, m4
+    punpcklwd     m4, m5, m6
+    punpckhwd     m5, m6
+    punpckldq     m6, m0, m4
+    punpckhdq     m0, m4
+    punpckldq     m4, m3, m5
+    punpckhdq     m3, m5
+
+    ; write out
+    movq   [dstq+strideq*0-4], xm6
+    movhps [dstq+strideq*1-4], xm6
+    movq   [dstq+strideq*2-4], xm0
+    movhps [dstq+stride3q -4], xm0
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm4
+    movhps [dstq+strideq*1-4], xm4
+    movq   [dstq+strideq*2-4], xm3
+    movhps [dstq+stride3q -4], xm3
+    lea         dstq, [dstq+strideq*4]
+
+    vextracti128 xm6, m6, 1
+    vextracti128 xm0, m0, 1
+    vextracti128 xm4, m4, 1
+    vextracti128 xm3, m3, 1
+
+    movq   [dstq+strideq*0-4], xm6
+    movhps [dstq+strideq*1-4], xm6
+    movq   [dstq+strideq*2-4], xm0
+    movhps [dstq+stride3q -4], xm0
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm4
+    movhps [dstq+strideq*1-4], xm4
+    movq   [dstq+strideq*2-4], xm3
+    movhps [dstq+stride3q -4], xm3
+    lea         dstq, [dstq+strideq*4]
+%endmacro
+
+%macro FILTER 2 ; width [4/6/8/16], dir [h/v]
+    ; load data
+%ifidn %2, v
+%if %1 == 4
+    lea         tmpq, [dstq+mstrideq*2]
+    mova          m3, [tmpq+strideq*0]          ; p1
+    mova          m4, [tmpq+strideq*1]          ; p0
+    mova          m5, [tmpq+strideq*2]          ; q0
+    mova          m6, [tmpq+stride3q]           ; q1
+%else
+    ; load 6-8 pixels, remainder (for wd=16) will be read inline
+    lea         tmpq, [dstq+mstrideq*4]
+    ; we load p3 later
+    mova         m13, [tmpq+strideq*1]
+    mova          m3, [tmpq+strideq*2]
+    mova          m4, [tmpq+stride3q]
+    mova          m5, [dstq+strideq*0]
+    mova          m6, [dstq+strideq*1]
+    mova         m14, [dstq+strideq*2]
+%if %1 != 6
+    mova         m15, [dstq+stride3q]
+%endif
+%endif
+%else
+    ; load lines
+%if %1 == 4
+    movq         xm3, [dstq+strideq*0-4]
+    movq         xm4, [dstq+strideq*1-4]
+    movq         xm5, [dstq+strideq*2-4]
+    movq         xm6, [dstq+stride3q -4]
+    lea         tmpq, [dstq+strideq*4]
+    movq        xm11, [tmpq+strideq*0-4]
+    movq        xm13, [tmpq+strideq*1-4]
+    movq        xm14, [tmpq+strideq*2-4]
+    movq        xm15, [tmpq+stride3q -4]
+    lea         tmpq, [tmpq+strideq*4]
+    ; this overreads by 8 bytes but the buffers are padded
+    ; so that should be ok
+    vinserti128   m3, [tmpq+strideq*0-4], 1
+    vinserti128   m4, [tmpq+strideq*1-4], 1
+    vinserti128   m5, [tmpq+strideq*2-4], 1
+    vinserti128   m6, [tmpq+stride3q -4], 1
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128  m11, [tmpq+strideq*0-4], 1
+    vinserti128  m13, [tmpq+strideq*1-4], 1
+    vinserti128  m14, [tmpq+strideq*2-4], 1
+    vinserti128  m15, [tmpq+stride3q -4], 1
+
+    ; transpose 4x8
+    ; xm3: A-D0,A-D4
+    ; xm4: A-D1,A-D5
+    ; xm5: A-D2,A-D6
+    ; xm6: A-D3,A-D7
+    punpcklwd     m7, m3, m4
+    punpcklwd     m3, m11, m13
+    punpcklwd     m4, m5, m6
+    punpcklwd     m5, m14, m15
+    ; xm7: A0-1,B0-1,C0-1,D0-1
+    ; xm3: A4-5,B4-5,C4-5,D4-5
+    ; xm4: A2-3,B2-3,C2-3,D2-3
+    ; xm5: A6-7,B6-7,C6-7,D6-7
+    punpckldq     m6, m7, m4
+    punpckhdq     m7, m4
+    punpckldq     m8, m3, m5
+    punpckhdq     m5, m3, m5
+    ; xm6: A0-3,B0-3
+    ; xm7: C0-3,D0-3
+    ; xm8: A4-7,B4-7
+    ; xm5: C4-7,D4-7
+    punpcklqdq    m3, m6, m8
+    punpckhqdq    m4, m6, m8
+    punpckhqdq    m6, m7, m5
+    punpcklqdq    m5, m7, m5
+    ; xm3: A0-7
+    ; xm4: B0-7
+    ; xm5: C0-7
+    ; xm6: D0-7
+%elif %1 == 6 || %1 == 8
+    movu         xm3, [dstq+strideq*0-8]
+    movu         xm4, [dstq+strideq*1-8]
+    movu         xm5, [dstq+strideq*2-8]
+    movu         xm6, [dstq+stride3q -8]
+    lea         tmpq, [dstq+strideq*4]
+    movu        xm11, [tmpq+strideq*0-8]
+    movu        xm13, [tmpq+strideq*1-8]
+    movu        xm14, [tmpq+strideq*2-8]
+    movu        xm15, [tmpq+stride3q -8]
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128   m3, [tmpq+strideq*0-8], 1
+    vinserti128   m4, [tmpq+strideq*1-8], 1
+    vinserti128   m5, [tmpq+strideq*2-8], 1
+    vinserti128   m6, [tmpq+stride3q -8], 1
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128  m11, [tmpq+strideq*0-8], 1
+    vinserti128  m13, [tmpq+strideq*1-8], 1
+    vinserti128  m14, [tmpq+strideq*2-8], 1
+    vinserti128  m15, [tmpq+stride3q -8], 1
+
+    ; transpose 8x16
+    ; xm3: A-H0,A-H8
+    ; xm4: A-H1,A-H9
+    ; xm5: A-H2,A-H10
+    ; xm6: A-H3,A-H11
+    ; xm11: A-H4,A-H12
+    ; xm13: A-H5,A-H13
+    ; xm14: A-H6,A-H14
+    ; xm15: A-H7,A-H15
+    punpcklwd    m7, m3, m4
+    punpckhwd    m3, m4
+    punpcklwd    m4, m5, m6
+    punpckhwd    m5, m6
+    punpcklwd    m6, m11, m13
+    punpckhwd   m11, m13
+    punpcklwd   m13, m14, m15
+    punpckhwd   m14, m15
+    ; xm7: A0-1,B0-1,C0-1,D0-1
+    ; xm3: E0-1,F0-1,G0-1,H0-1
+    ; xm4: A2-3,B2-3,C2-3,D2-3
+    ; xm5: E2-3,F2-3,G2-3,H2-3
+    ; xm6: A4-5,B4-5,C4-5,D4-5
+    ; xm11: E4-5,F4-5,G4-5,H4-5
+    ; xm13: A6-7,B6-7,C6-7,D6-7
+    ; xm14: E6-7,F6-7,G6-7,H6-7
+    punpckldq   m15, m7, m4
+    punpckhdq    m7, m4
+    punpckldq    m9, m3, m5
+    punpckhdq    m8, m3, m5
+    punpckldq    m3, m6, m13
+    punpckhdq    m6, m13
+    punpckldq   m10, m11, m14
+    punpckhdq   m11, m14
+    ; xm15: A0-3,B0-3
+    ; xm7: C0-3,D0-3
+    ; xm9: E0-3,F0-3
+    ; xm8: G0-3,H0-3
+    ; xm3: A4-7,B4-7
+    ; xm6: C4-7,D4-7
+    ; xm10: E4-7,F4-7
+    ; xm11: G4-7,H4-7
+%if %1 != 6
+    punpcklqdq   m0, m15, m3
+%endif
+    punpckhqdq  m13, m15, m3
+    punpcklqdq   m3, m7, m6
+    punpckhqdq   m4, m7, m6
+    punpcklqdq   m5, m9, m10
+    punpckhqdq   m6, m9, m10
+    punpcklqdq  m14, m8, m11
+%if %1 != 6
+    punpckhqdq  m15, m8, m11
+    mova [rsp+5*32], m0
+%endif
+%else
+    ; We only use 14 pixels but we'll need the remainder at the end for
+    ; the second transpose
+    mova         xm0, [dstq+strideq*0-16]
+    mova         xm1, [dstq+strideq*1-16]
+    mova         xm2, [dstq+strideq*2-16]
+    mova         xm3, [dstq+stride3q -16]
+    lea         tmpq, [dstq+strideq*4]
+    mova         xm4, [tmpq+strideq*0-16]
+    mova         xm5, [tmpq+strideq*1-16]
+    mova         xm6, [tmpq+strideq*2-16]
+    mova         xm7, [tmpq+stride3q -16]
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128   m0, m0, [tmpq+strideq*0-16], 1
+    vinserti128   m1, m1, [tmpq+strideq*1-16], 1
+    vinserti128   m2, m2, [tmpq+strideq*2-16], 1
+    vinserti128   m3, m3, [tmpq+stride3q -16], 1
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128   m4, m4, [tmpq+strideq*0-16], 1
+    vinserti128   m5, m5, [tmpq+strideq*1-16], 1
+    vinserti128   m6, m6, [tmpq+strideq*2-16], 1
+    vinserti128   m7, m7, [tmpq+stride3q -16], 1
+
+    TRANSPOSE8X8W 0, 1, 2, 3, 4, 5, 6, 7, 8
+
+    mova    [rsp+6*32], m0
+    mova    [rsp+7*32], m1
+    mova    [rsp+8*32], m2
+    mova    [rsp+9*32], m3
+    mova    [rsp+5*32], m4
+
+    mova         xm0, [dstq+strideq*0]
+    mova         xm1, [dstq+strideq*1]
+    mova         xm2, [dstq+strideq*2]
+    mova         xm3, [dstq+stride3q ]
+    lea         tmpq, [dstq+strideq*4]
+    mova         xm8, [tmpq+strideq*0]
+    mova         xm9, [tmpq+strideq*1]
+    mova        xm10, [tmpq+strideq*2]
+    mova        xm11, [tmpq+stride3q ]
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128   m0, m0, [tmpq+strideq*0], 1
+    vinserti128   m1, m1, [tmpq+strideq*1], 1
+    vinserti128   m2, m2, [tmpq+strideq*2], 1
+    vinserti128   m3, m3, [tmpq+stride3q ], 1
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128   m8, m8, [tmpq+strideq*0], 1
+    vinserti128   m9, m9, [tmpq+strideq*1], 1
+    vinserti128  m10, m10, [tmpq+strideq*2], 1
+    vinserti128  m11, m11, [tmpq+stride3q ], 1
+
+    TRANSPOSE8X8W 0, 1, 2, 3, 8, 9, 10, 11, 4
+
+    mova   [rsp+10*32], m8
+    mova   [rsp+11*32], m9
+    mova   [rsp+12*32], m10
+    mova   [rsp+13*32], m11
+
+    ; 5,6,7,0,1,2,3 -> 13,3,4,5,6,14,15
+    SWAP         13, 5, 0
+    SWAP          3, 6, 1, 15
+    SWAP          4, 7
+    SWAP          2, 14
+%endif
+%endif
+
+    ; load L/E/I/H
+%ifidn %2, v
+    pmovzxbw      m1, [lq]
+    pmovzxbw      m0, [lq+l_strideq]
+    pxor          m2, m2
+%else
+    vpbroadcastq  m0, [lq]                      ; l0, l1
+    vpbroadcastq  m1, [lq+l_strideq]            ; l2, l3
+    vpbroadcastq  m2, [lq+l_strideq*2]          ; l4, l5
+    vpbroadcastq m10, [lq+l_stride3q]           ; l6, l7
+    punpckldq     m0, m1                        ; l0, l2, l1, l3 [2x]
+    punpckldq     m2, m10                       ; l4, l6, l5, l7 [2x]
+    vpblendd      m0, m0, m2, 11110000b         ; l0, l2, l1, l3, l4, l6, l5, l7
+    pxor          m2, m2
+    punpcklbw     m1, m0, m2                    ; l0, l2, l4, l6
+    punpckhbw     m0, m2                        ; l1, l3, l5, l7
+%endif
+    pcmpeqw      m10, m2, m0
+    pand          m1, m10
+    por           m0, m1                        ; l[x][] ? l[x][] : l[x-stride][]
+    pshufb        m0, [pb_4x1_4x5_4x9_4x13]     ; l[x][1]
+    pcmpeqw      m10, m2, m0                    ; !L
+    psrlw        m10, 1
+    psrlw         m2, m0, [lutq+128]
+    vpbroadcastw  m1, [lutq+136]
+    pminuw        m2, m1
+    pmaxuw        m2, [pw_1]                    ; I
+    psrlw         m1, m0, 4                     ; H
+    paddw         m0, [pw_2]
+    vpbroadcastd  m8, [r11]
+    paddw         m0, m0
+    paddw         m0, m2                        ; E
+    REPX {pmullw x, m8}, m0, m1, m2
+
+    psubw         m8, m3, m4                    ; p1-p0
+    psubw         m9, m5, m6                    ; q1-q0
+    REPX {pabsw x, x}, m8, m9
+    pmaxuw        m8, m10
+    pmaxuw        m8, m9
+    pcmpgtw       m7, m8, m1                    ; hev
+%if %1 != 4
+    psubw         m9, m13, m4                   ; p2-p0
+    pabsw         m9, m9
+    pmaxuw        m9, m8
+%if %1 != 6
+%ifidn %2, v
+    mova         m11, [tmpq+strideq*0]          ; p3
+%else
+    mova         m11, [rsp+5*32]                ; p3
+%endif
+    psubw        m10, m11, m4                   ; p3-p0
+    pabsw        m10, m10
+    pmaxuw        m9, m10
+%endif
+    psubw        m10, m5, m14                   ; q2-q0
+    pabsw        m10, m10
+    pmaxuw        m9, m10
+%if %1 != 6
+    psubw        m10, m5, m15                   ; q3-q0
+    pabsw        m10, m10
+    pmaxuw        m9, m10
+%endif
+    vpbroadcastd m10, [r11]
+    pcmpgtw       m9, m10                       ; !flat8in
+
+    psubw        m10, m13, m3                   ; p2-p1
+    pabsw        m10, m10
+%if %1 != 6
+    psubw        m11, m13                       ; p3-p2
+    pabsw        m11, m11
+    pmaxuw       m10, m11
+    psubw        m11, m14, m15                  ; q3-q2
+    pabsw        m11, m11
+    pmaxuw       m10, m11
+%endif
+    psubw        m11, m14, m6                   ; q2-q1
+    pabsw        m11, m11
+    pmaxuw       m10, m11
+
+%if %1 == 16
+    vpbroadcastd m11, [maskq+8]
+    vpbroadcastd  m1, [maskq+4]
+    por          m11, m1
+    pand         m11, m12
+    pcmpeqd      m11, m12
+    pand         m10, m11
+%else
+    vpbroadcastd m11, [maskq+4]
+    pand         m11, m12
+    pcmpeqd      m11, m12
+    pand         m10, m11                       ; only apply fm-wide to wd>4 blocks
+%endif
+    pmaxuw        m8, m10
+%endif
+    pcmpgtw       m8, m2
+
+    psubw        m10, m3, m6                    ; p1-q1
+    psubw        m11, m4, m5                    ; p0-q0
+    REPX {pabsw x, x}, m10, m11
+    paddw        m11, m11
+    psrlw        m10, 1
+    paddw        m10, m11                       ; abs(p0-q0)*2+(abs(p1-q1)>>1)
+    pcmpgtw      m10, m0                        ; abs(p0-q0)*2+(abs(p1-q1)>>1) > E
+    por           m8, m10
+
+%if %1 == 16
+
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*8]
+    mova          m0, [tmpq+strideq*1]
+    mova          m1, [tmpq+strideq*2]
+    mova          m2, [tmpq+stride3q]
+%else
+    mova          m0, [rsp+7*32]
+    mova          m1, [rsp+8*32]
+    mova          m2, [rsp+9*32]
+%endif
+    REPX {psubw x, m4}, m0, m1, m2
+    REPX {pabsw x, x}, m0, m1, m2
+    pmaxuw        m1, m0
+    pmaxuw        m1, m2
+%ifidn %2, v
+    lea         tmpq, [dstq+strideq*4]
+    mova          m0, [tmpq+strideq*0]
+    mova          m2, [tmpq+strideq*1]
+    mova         m10, [tmpq+strideq*2]
+%else
+    mova          m0, [rsp+10*32]
+    mova          m2, [rsp+11*32]
+    mova         m10, [rsp+12*32]
+%endif
+    REPX {psubw x, m5}, m0, m2, m10
+    REPX {pabsw x, x}, m0, m2, m10
+    pmaxuw        m0, m2
+    pmaxuw        m1, m10
+    pmaxuw        m1, m0
+    vpbroadcastd  m0, [r11]
+    pcmpgtw       m1, m0                        ; !flat8out
+    por           m1, m9                        ; !flat8in | !flat8out
+    vpbroadcastd  m2, [maskq+8]
+    pand         m10, m2, m12
+    pcmpeqd      m10, m12
+    pandn         m1, m10                       ; flat16
+    pandn         m1, m8, m1                    ; flat16 & fm
+
+    vpbroadcastd m10, [maskq+4]
+    por          m10, m2
+    pand          m2, m10, m12
+    pcmpeqd       m2, m12
+    pandn         m9, m2                        ; flat8in
+    pandn         m9, m8, m9
+    vpbroadcastd  m2, [maskq+0]
+    por           m2, m10
+    pand          m2, m12
+    pcmpeqd       m2, m12
+    pandn         m8, m2
+    pandn         m8, m9, m8                    ; fm & !flat8 & !flat16
+    pandn         m9, m1, m9                    ; flat8 & !flat16
+%elif %1 != 4
+    vpbroadcastd  m0, [maskq+4]
+    pand          m2, m0, m12
+    pcmpeqd       m2, m12
+    pandn         m9, m2
+    pandn         m9, m8, m9                    ; flat8 & fm
+    vpbroadcastd  m2, [maskq+0]
+    por           m0, m2
+    pand          m0, m12
+    pcmpeqd       m0, m12
+    pandn         m8, m0
+    pandn         m8, m9, m8                    ; fm & !flat8
+%else
+    vpbroadcastd  m0, [maskq+0]
+    pand          m0, m12
+    pcmpeqd       m0, m12
+    pandn         m8, m0                        ; fm
+%endif
+
+    ; short filter
+    vpbroadcastd  m0, [r11+8*1]                 ; 511 or 2047
+    vpbroadcastd  m2, [r11+8*2]                 ; -512 or -2048
+    psubw        m10, m5, m4
+    paddw        m11, m10, m10
+    paddw        m11, m10
+    psubw        m10, m3, m6                    ; iclip_diff(p1-q1)
+    pminsw       m10, m0
+    pmaxsw       m10, m2
+    pand         m10, m7                        ; f=iclip_diff(p1-q1)&hev
+    paddw        m10, m11                       ; f=iclip_diff(3*(q0-p0)+f)
+    pminsw       m10, m0
+    pmaxsw       m10, m2
+    pand          m8, m10                       ; f&=fm
+    vpbroadcastd m10, [pw_4]
+    paddw        m10, m8
+    paddw         m8, [pw_3]
+    REPX {pminsw x, m0}, m10, m8
+    psraw        m10, 3                         ; f2
+    psraw         m8, 3                         ; f1
+    psubw         m5, m10
+    paddw         m4, m8
+
+    paddw        m10, [pw_1]
+    psraw        m10, 1                         ; f=(f1+1)>>1
+    pandn         m8, m7, m10                   ; f&=!hev
+    paddw         m3, m8
+    psubw         m6, m8
+    pxor          m8, m8
+    psubw         m0, m2                        ; 1023 or 4095
+    REPX {pminsw x, m0}, m3, m4, m5, m6
+    REPX {pmaxsw x, m8}, m3, m4, m5, m6
+
+%if %1 == 16
+
+; m3-6 = p1/p0/q0/q1, m9=flat8, m1=flat16
+; m12=filter bits mask
+; m13-15=p2/q2/q3
+; m0,2,7-8,10-11 = free
+
+    ; flat16 filter
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*8]
+    mova          m0, [tmpq+strideq*1]          ; p6
+    mova          m2, [tmpq+strideq*2]          ; p5
+    mova          m7, [tmpq+stride3q]           ; p4
+    mova         m11, [tmpq+strideq*4]          ; p3
+%else
+    mova          m0, [rsp+7*32]
+    mova          m2, [rsp+8*32]
+    mova          m7, [rsp+9*32]
+    mova         m11, [rsp+5*32]
+%endif
+
+    mova [rsp+ 0*32], m9
+
+    ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0
+    paddw         m8, m0, [pw_1]
+    psllw         m8, 3                         ; p6*8+8
+    paddw        m10, m2, m7                    ; p5+p4
+    psubw         m8, m0
+    paddw        m10, m10                       ; (p5+p4)*2
+    paddw         m8, m11                       ; p6*7+p3
+    paddw        m10, m13                       ; (p5+p4)*2+p2
+    paddw         m8, m3                        ; p6*7+p3+p1
+    paddw        m10, m4                        ; (p5+p4)*2+p2+p0
+    paddw         m8, m5                        ; p6*7+p3+p1+q0
+    paddw         m8, m10                       ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0
+    psrlw        m10, m8, 4
+    vpblendvb    m10, m2, m10, m1
+%ifidn %2, v
+    mova [tmpq+strideq*2], m10                  ; p5
+%else
+    mova [rsp+8*32], m10
+%endif
+
+    ; sub p6*2, add p3/q1
+    paddw         m8, m11
+    paddw        m10, m0, m0
+    paddw         m8, m6
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb    m10, m7, m10, m1
+%ifidn %2, v
+    mova [tmpq+stride3q], m10                   ; p4
+%else
+    mova [rsp+9*32], m10
+%endif
+
+    ; sub p6/p5, add p2/q2
+    psubw         m8, m0
+    paddw        m10, m13, m14
+    psubw         m8, m2
+    paddw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb    m10, m11, m10, m1
+%ifidn %2, v
+    mova [tmpq+strideq*4], m10                  ; p3
+    lea         tmpq, [dstq+strideq*4]
+%else
+    mova [rsp+5*32], m10
+%endif
+
+    ; sub p6/p4, add p1/q3
+    paddw         m8, m3
+    paddw        m10, m0, m7
+    paddw         m8, m15
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb    m10, m13, m10, m1
+    mova  [rsp+1*32], m10                       ; don't clobber p2/m13
+
+    ; sub p6/p3, add p0/q4
+    paddw         m8, m4
+    paddw        m10, m0, m11
+%ifidn %2, v
+    paddw         m8, [tmpq+strideq*0]
+%else
+    paddw         m8, [rsp+10*32]
+%endif
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb    m10, m3, m10, m1
+    mova  [rsp+2*32], m10                       ; don't clobber p1/m3
+
+    ; sub p6/p2, add q0/q5
+    paddw         m8, m5
+    paddw        m10, m0, m13
+%ifidn %2, v
+    paddw         m8, [tmpq+strideq*1]
+%else
+    paddw         m8, [rsp+11*32]
+%endif
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb    m10, m4, m10, m1
+    mova  [rsp+3*32], m10                       ; don't clobber p0/m4
+
+    ; sub p6/p1, add q1/q6
+    paddw         m8, m6
+    paddw        m10, m0, m3
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*2]          ; q6
+%else
+    mova          m0, [rsp+12*32]               ; q6
+%endif
+    paddw         m8, m0
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb    m10, m5, m10, m1
+    mova  [rsp+4*32], m10                       ; don't clobber q0/m5
+
+    ; sub p5/p0, add q2/q6
+    paddw         m8, m14
+    paddw        m10, m2, m4
+    paddw         m8, m0
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb     m2, m6, m10, m1               ; don't clobber q1/m6
+
+    ; sub p4/q0, add q3/q6
+    paddw         m8, m15
+    paddw        m10, m7, m5
+    paddw         m8, m0
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb     m7, m14, m10, m1              ; don't clobber q2/m14
+
+    ; sub p3/q1, add q4/q6
+%ifidn %2, v
+    paddw         m8, [tmpq+strideq*0]
+%else
+    paddw         m8, [rsp+10*32]
+%endif
+    paddw        m10, m11, m6
+    paddw         m8, m0
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+    vpblendvb    m10, m15, m10, m1
+%ifidn %2, v
+    mova [tmpq+mstrideq], m10                   ; q3
+%else
+    mova [rsp+14*32], m10
+%endif
+
+    ; sub p2/q2, add q5/q6
+%ifidn %2, v
+    paddw         m8, [tmpq+strideq*1]
+%else
+    paddw         m8, [rsp+11*32]
+%endif
+    paddw        m10, m13, m14
+    paddw         m8, m0
+    psubw         m8, m10
+    psrlw        m10, m8, 4
+%ifidn %2, v
+    mova          m9, [tmpq+strideq*0]
+%else
+    mova          m9, [rsp+10*32]
+%endif
+    vpblendvb    m10, m9, m10, m1
+%ifidn %2, v
+    mova [tmpq+strideq*0], m10                   ; q4
+%else
+    mova [rsp+10*32], m10
+%endif
+
+    ; sub p1/q3, add q6*2
+    psubw         m8, m3
+    paddw         m0, m0
+    psubw         m8, m15
+    paddw         m8, m0
+    psrlw        m10, m8, 4
+%ifidn %2, v
+    mova          m9, [tmpq+strideq*1]
+%else
+    mova          m9, [rsp+11*32]
+%endif
+    vpblendvb    m10, m9, m10, m1
+%ifidn %2, v
+    mova [tmpq+strideq*1], m10                  ; q5
+%else
+    mova [rsp+11*32], m10
+%endif
+
+    mova          m9, [rsp+0*32]
+    mova         m13, [rsp+1*32]
+    mova          m3, [rsp+2*32]
+    mova          m4, [rsp+3*32]
+    mova          m5, [rsp+4*32]
+    SWAP           2, 6
+    SWAP           7, 14
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*4]
+%else
+    mova         m15, [rsp+14*32]
+%endif
+%endif
+
+%if %1 >= 8
+    ; flat8 filter
+    vpbroadcastd  m7, [pw_4096]
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*0]          ; p3
+%else
+    mova          m0, [rsp+5*32]                ; p3
+%endif
+    paddw         m1, m0, m13                   ; p3+p2
+    paddw         m2, m3, m4                    ; p1+p0
+    paddw         m8, m1, m1                    ; 2*(p3+p2)
+    paddw         m2, m0                        ; p1+p0+p3
+    paddw         m8, m5                        ; 2*(p3+p2)+q0
+    paddw         m2, m8                        ; 3*p3+2*p2+p1+p0+q0
+    pmulhrsw     m10, m2, m7
+
+    paddw         m8, m3, m6
+    psubw         m2, m1
+    paddw         m2, m8
+    pmulhrsw      m8, m2, m7
+
+    paddw        m11, m0, m3
+    paddw         m1, m4, m14
+    psubw         m2, m11
+    paddw         m2, m1
+    pmulhrsw      m1, m2, m7
+
+    paddw        m11, m0, m4
+    pblendvb      m4, m1, m9
+    paddw         m1, m5, m15
+    psubw         m2, m11
+    paddw         m2, m1
+    pmulhrsw     m11, m2, m7
+
+    paddw         m2, m6
+    paddw         m2, m15
+    paddw         m1, m13, m5
+    pblendvb      m5, m11, m9
+    pblendvb     m13, m10, m9
+    psubw         m2, m1
+    pmulhrsw      m1, m2, m7
+
+    psubw         m2, m3
+    pblendvb      m3, m8, m9
+    psubw         m2, m6
+    pblendvb      m6, m1, m9
+    paddw         m1, m15, m14
+    paddw         m2, m1
+    pmulhrsw      m2, m7
+
+    pblendvb     m14, m2, m9
+
+%ifidn %2, v
+    mova [tmpq+strideq*1], m13                  ; p2
+    mova [tmpq+strideq*2], m3                   ; p1
+    mova [tmpq+stride3q ], m4                   ; p0
+    mova [dstq+strideq*0], m5                   ; q0
+    mova [dstq+strideq*1], m6                   ; q1
+    mova [dstq+strideq*2], m14                  ; q2
+%elif %1 == 8
+    TRANSPOSE8X8W  0, 13, 3, 4, 5, 6, 14, 15, 1
+
+    ; write 8x16
+    movu   [dstq+strideq*0-8], xm0
+    movu   [dstq+strideq*1-8], xm13
+    movu   [dstq+strideq*2-8], xm3
+    movu   [dstq+stride3q -8], xm4
+    lea         dstq, [dstq+strideq*4]
+    movu   [dstq+strideq*0-8], xm5
+    movu   [dstq+strideq*1-8], xm6
+    movu   [dstq+strideq*2-8], xm14
+    movu   [dstq+stride3q -8], xm15
+    lea         dstq, [dstq+strideq*4]
+    vextracti128 [dstq+strideq*0-8], m0, 1
+    vextracti128 [dstq+strideq*1-8], m13, 1
+    vextracti128 [dstq+strideq*2-8], m3, 1
+    vextracti128 [dstq+stride3q -8], m4, 1
+    lea         dstq, [dstq+strideq*4]
+    vextracti128 [dstq+strideq*0-8], m5, 1
+    vextracti128 [dstq+strideq*1-8], m6, 1
+    vextracti128 [dstq+strideq*2-8], m14, 1
+    vextracti128 [dstq+stride3q -8], m15, 1
+    lea         dstq, [dstq+strideq*4]
+%else
+    mova          m8, [rsp+6*32]
+    mova          m1, [rsp+7*32]
+    mova          m2, [rsp+8*32]
+    mova          m7, [rsp+9*32]
+    TRANSPOSE8X8W  8, 1, 2, 7, 0, 13, 3, 4, 9
+
+    mova [dstq+strideq*0-16], xm8
+    mova [dstq+strideq*1-16], xm1
+    mova [dstq+strideq*2-16], xm2
+    mova [dstq+stride3q -16], xm7
+    lea         tmpq, [dstq+strideq*4]
+    mova [tmpq+strideq*0-16], xm0
+    mova [tmpq+strideq*1-16], xm13
+    mova [tmpq+strideq*2-16], xm3
+    mova [tmpq+stride3q -16], xm4
+    lea         tmpq, [tmpq+strideq*4]
+    vextracti128 [tmpq+strideq*0-16], m8, 1
+    vextracti128 [tmpq+strideq*1-16], m1, 1
+    vextracti128 [tmpq+strideq*2-16], m2, 1
+    vextracti128 [tmpq+stride3q -16], m7, 1
+    lea         tmpq, [tmpq+strideq*4]
+    vextracti128 [tmpq+strideq*0-16], m0, 1
+    vextracti128 [tmpq+strideq*1-16], m13, 1
+    vextracti128 [tmpq+strideq*2-16], m3, 1
+    vextracti128 [tmpq+stride3q -16], m4, 1
+
+    mova          m0, [rsp+10*32]
+    mova          m1, [rsp+11*32]
+    mova          m2, [rsp+12*32]
+    mova          m3, [rsp+13*32]
+    TRANSPOSE8X8W  5, 6, 14, 15, 0, 1, 2, 3, 4
+    mova [dstq+strideq*0], xm5
+    mova [dstq+strideq*1], xm6
+    mova [dstq+strideq*2], xm14
+    mova [dstq+stride3q ], xm15
+    lea         dstq, [dstq+strideq*4]
+    mova [dstq+strideq*0], xm0
+    mova [dstq+strideq*1], xm1
+    mova [dstq+strideq*2], xm2
+    mova [dstq+stride3q ], xm3
+    lea         dstq, [dstq+strideq*4]
+    vextracti128 [dstq+strideq*0], m5, 1
+    vextracti128 [dstq+strideq*1], m6, 1
+    vextracti128 [dstq+strideq*2], m14, 1
+    vextracti128 [dstq+stride3q ], m15, 1
+    lea         dstq, [dstq+strideq*4]
+    vextracti128 [dstq+strideq*0], m0, 1
+    vextracti128 [dstq+strideq*1], m1, 1
+    vextracti128 [dstq+strideq*2], m2, 1
+    vextracti128 [dstq+stride3q ], m3, 1
+    lea         dstq, [dstq+strideq*4]
+%endif
+%elif %1 == 6
+    ; flat6 filter
+    vpbroadcastd  m7, [pw_4096]
+    paddw         m8, m3, m4
+    paddw         m8, m13                       ; p2+p1+p0
+    paddw        m11, m13, m5
+    paddw         m8, m8
+    paddw         m8, m11                       ; p2+2*(p2+p1+p0)+q0
+    pmulhrsw      m2, m8, m7
+
+    paddw         m8, m5
+    paddw        m11, m13, m13
+    paddw         m8, m6
+    psubw         m8, m11
+    pmulhrsw     m10, m8, m7
+
+    paddw         m8, m6
+    paddw        m11, m13, m3
+    paddw         m8, m14
+    psubw         m8, m11
+    pmulhrsw     m11, m8, m7
+
+    psubw         m8, m3
+    paddw        m14, m14
+    psubw         m8, m4
+    paddw         m8, m14
+    pmulhrsw      m8, m7
+
+    pblendvb      m3, m2, m9
+    pblendvb      m4, m10, m9
+    pblendvb      m5, m11, m9
+    pblendvb      m6, m8, m9
+
+%ifidn %2, v
+    mova [tmpq+strideq*2], m3                   ; p1
+    mova [tmpq+stride3q ], m4                   ; p0
+    mova [dstq+strideq*0], m5                   ; q0
+    mova [dstq+strideq*1], m6                   ; q1
+%else
+    TRANSPOSE_8x4_AND_WRITE_4x16
+%endif
+%else
+%ifidn %2, v
+    mova [tmpq+strideq*0], m3                   ; p1
+    mova [tmpq+strideq*1], m4                   ; p0
+    mova [tmpq+strideq*2], m5                   ; q0
+    mova [tmpq+stride3q ], m6                   ; q1
+%else
+    TRANSPOSE_8x4_AND_WRITE_4x16
+%endif
+%endif
+%endmacro
+
+INIT_YMM avx2
+cglobal lpf_v_sb_y_16bpc, 6, 12, 16, 32 * 5, \
+                          dst, stride, mask, l, l_stride, lut, \
+                          w, stride3, mstride, tmp, mask_bits
+    mov          r6d, r7m
+    lea          r11, [pw_4]
+    shr          r6d, 11                      ; is_12bpc
+    lea          r11, [r11+r6*4]
+    mov           wd, wm
+    shl    l_strideq, 2
+    sub           lq, l_strideq
+    mov     mstrideq, strideq
+    neg     mstrideq
+    lea     stride3q, [strideq*3]
+    mov   mask_bitsd, 0xf
+    mova         m12, [pb_mask]
+
+.loop:
+    test   [maskq+8], mask_bitsd              ; vmask[2]
+    jz .no_flat16
+
+    FILTER        16, v
+    jmp .end
+
+.no_flat16:
+    test   [maskq+4], mask_bitsd              ; vmask[1]
+    jz .no_flat
+
+    FILTER         8, v
+    jmp .end
+
+.no_flat:
+    test   [maskq+0], mask_bitsd              ; vmask[0]
+    jz .end
+
+    call .v4
+
+.end:
+    pslld        m12, 4
+    add           lq, 16
+    add         dstq, 32
+    shl   mask_bitsd, 4
+    sub           wd, 4
+    jg .loop
+    RET
+ALIGN function_align
+.v4:
+    FILTER         4, v
+    ret
+
+INIT_YMM avx2
+cglobal lpf_h_sb_y_16bpc, 6, 12, 16, 32 * 15, \
+                          dst, stride, mask, l, l_stride, lut, \
+                          h, stride3, l_stride3, tmp, mask_bits
+    mov          r6d, r7m
+    lea          r11, [pw_4]
+    shr          r6d, 11                      ; is_12bpc
+    lea          r11, [r11+r6*4]
+    mov           hd, hm
+    shl    l_strideq, 2
+    sub           lq, 4
+    lea     stride3q, [strideq*3]
+    lea   l_stride3q, [l_strideq*3]
+    mov   mask_bitsd, 0xf
+    mova         m12, [pb_mask]
+
+.loop:
+    test   [maskq+8], mask_bitsd            ; vmask[2]
+    jz .no_flat16
+
+    FILTER        16, h
+    jmp .end
+
+.no_flat16:
+    test   [maskq+4], mask_bitsd            ; vmask[1]
+    jz .no_flat
+
+    FILTER         8, h
+    jmp .end
+
+.no_flat:
+    test   [maskq+0], mask_bitsd            ; vmask[0]
+    jz .no_filter
+
+    call .h4
+    jmp .end
+
+.no_filter:
+    lea         dstq, [dstq+strideq*8]
+    lea         dstq, [dstq+strideq*8]
+.end:
+    pslld        m12, 4
+    lea           lq, [lq+l_strideq*4]
+    shl   mask_bitsd, 4
+    sub           hd, 4
+    jg .loop
+    RET
+ALIGN function_align
+.h4:
+    FILTER         4, h
+    ret
+
+INIT_YMM avx2
+cglobal lpf_v_sb_uv_16bpc, 6, 12, 16, \
+                           dst, stride, mask, l, l_stride, lut, \
+                           w, stride3, mstride, tmp, mask_bits
+    mov          r6d, r7m
+    lea          r11, [pw_4]
+    shr          r6d, 11                      ; is_12bpc
+    lea          r11, [r11+r6*4]
+    mov           wd, wm
+    shl    l_strideq, 2
+    sub           lq, l_strideq
+    mov     mstrideq, strideq
+    neg     mstrideq
+    lea     stride3q, [strideq*3]
+    mov   mask_bitsd, 0xf
+    mova         m12, [pb_mask]
+
+.loop:
+    test   [maskq+4], mask_bitsd            ; vmask[1]
+    jz .no_flat
+
+    FILTER         6, v
+    jmp .end
+
+.no_flat:
+    test   [maskq+0], mask_bitsd            ; vmask[0]
+    jz .end
+
+    call mangle(private_prefix %+ _lpf_v_sb_y_16bpc_avx2).v4
+
+.end:
+    pslld        m12, 4
+    add           lq, 16
+    add         dstq, 32
+    shl   mask_bitsd, 4
+    sub           wd, 4
+    jg .loop
+    RET
+
+INIT_YMM avx2
+cglobal lpf_h_sb_uv_16bpc, 6, 12, 16, \
+                           dst, stride, mask, l, l_stride, lut, \
+                           h, stride3, l_stride3, tmp, mask_bits
+    mov          r6d, r7m
+    lea          r11, [pw_4]
+    shr          r6d, 11                      ; is_12bpc
+    lea          r11, [r11+r6*4]
+    mov           hd, hm
+    shl    l_strideq, 2
+    sub           lq, 4
+    lea     stride3q, [strideq*3]
+    lea   l_stride3q, [l_strideq*3]
+    mov   mask_bitsd, 0xf
+    mova         m12, [pb_mask]
+
+.loop:
+    test   [maskq+4], mask_bitsd            ; vmask[1]
+    jz .no_flat
+
+    FILTER         6, h
+    jmp .end
+
+.no_flat:
+    test   [maskq+0], mask_bitsd            ; vmask[0]
+    jz .no_filter
+
+    call mangle(private_prefix %+ _lpf_h_sb_y_16bpc_avx2).h4
+    jmp .end
+
+.no_filter:
+    lea         dstq, [dstq+strideq*8]
+    lea         dstq, [dstq+strideq*8]
+.end:
+    pslld        m12, 4
+    lea           lq, [lq+l_strideq*4]
+    shl   mask_bitsd, 4
+    sub           hd, 4
+    jg .loop
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/loopfilter16_avx512.asm b/media/libdav1d/src/src/x86/loopfilter16_avx512.asm
new file mode 100644
index 0000000000..b7bc3aa106
--- /dev/null
+++ b/media/libdav1d/src/src/x86/loopfilter16_avx512.asm
@@ -0,0 +1,912 @@
+; Copyright © 2022, VideoLAN and dav1d authors
+; Copyright © 2022, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+l_shuf_v:      times 2 db  0, 32
+pw_1:          times 2 dw  1
+               times 2 db  4, 36
+pw_3:          times 2 dw  3
+               times 2 db  8, 40
+pw_4:          times 2 dw  4
+               times 2 db 12, 44
+pw_16:         times 2 dw 16
+               times 2 db 16, 48
+pw_4096:       times 2 dw 4096
+               times 2 db 20, 52
+pw_16384:      times 2 dw 16384
+               times 2 db 24, 56
+pw_32767:      times 2 dw 32767
+               times 2 db 28, 60
+               times 2 dw  0
+filter_mask:   dd  1,  2,  4,  8, 16, 32, 64,128
+stride_mul:    dd  0,  1,  8,  9, 16, 17, 24, 25
+l_shuf_h:      db  4, -1,  4, -1,  4, -1,  4, -1, 12, -1, 12, -1, 12, -1, 12, -1
+clip_max: dw  511,  511,  2047,  2047
+clip_min: dw -512, -512, -2048, -2048
+
+SECTION .text
+
+%macro TRANSPOSE8X8W 9 ; src/dst[1-8], tmp
+    punpckhwd        m%9, m%5, m%6
+    punpcklwd        m%5, m%6
+    punpckhwd        m%6, m%1, m%2
+    punpcklwd        m%1, m%2
+    punpckhwd        m%2, m%7, m%8
+    punpcklwd        m%7, m%8
+    punpckhwd        m%8, m%3, m%4
+    punpcklwd        m%3, m%4
+    punpckhdq        m%4, m%1, m%3
+    punpckldq        m%1, m%3
+    punpckldq        m%3, m%5, m%7
+    punpckhdq        m%5, m%7
+    punpckhdq        m%7, m%6, m%8
+    punpckldq        m%6, m%8
+    punpckldq        m%8, m%9, m%2
+    punpckhdq        m%9, m%2
+    punpckhqdq       m%2, m%1, m%3
+    punpcklqdq       m%1, m%3
+    punpcklqdq       m%3, m%4, m%5
+    punpckhqdq       m%4, m%5
+    punpcklqdq       m%5, m%6, m%8
+    punpckhqdq       m%6, m%8
+    punpckhqdq       m%8, m%7, m%9
+    punpcklqdq       m%7, m%9
+%endmacro
+
+%macro FILTER 2 ; width [4/6/8/16], dir [h/v]
+%ifidn %2, v
+%if %1 == 16
+    lea             tmpq, [dstq+mstrideq*8]
+    mova              m0, [tmpq+strideq*1 ]
+    mova              m1, [tmpq+strideq*2 ] ; p5
+    mova              m2, [tmpq+stride3q  ] ; p4
+    mova              m3, [tmpq+strideq*4 ] ; p3
+    mova              m4, [tmpq+stride5q  ] ; p2
+%elif %1 == 6 || %1 == 8
+    lea             tmpq, [dstq+mstrideq*4]
+%if %1 == 8
+    mova              m3, [tmpq+strideq*0 ]
+%endif
+    mova              m4, [tmpq+strideq*1 ]
+%endif
+    mova              m5, [dstq+mstrideq*2] ; p1
+    mova              m6, [dstq+mstrideq*1] ; p0
+    mova              m7, [dstq+strideq*0 ] ; q0
+    mova              m8, [dstq+strideq*1 ] ; q1
+%if %1 != 4
+    mova              m9, [dstq+strideq*2 ] ; q2
+%endif
+%if %1 == 8 || %1 == 16
+    mova             m10, [dstq+stride3q  ] ; q3
+%endif
+%if %1 == 16
+    mova             m11, [dstq+strideq*4 ] ; q4
+    mova             m22, [dstq+stride5q  ] ; q5
+    mova             m23, [dstq+stride3q*2]
+%endif
+%else ; h
+%if %1 == 16
+    movu            ym16, [dstq+strideq*0 -16]
+    movu            ym17, [dstq+strideq*1 -16]
+    movu            ym18, [dstq+strideq*2 -16]
+    movu            ym19, [dstq+stride3q  -16]
+    movu            ym20, [dstq+strideq*4 -16]
+    movu            ym22, [dstq+stride5q  -16]
+    movu            ym23, [dstq+stride3q*2-16]
+    movu            ym28, [dstq+stride7q  -16]
+    lea             tmpq, [dstq+strideq*8 -16]
+    vinserti32x8      m7, m16, [tmpq+strideq*0 ], 1
+    vinserti32x8      m8, m17, [tmpq+strideq*1 ], 1
+    vinserti32x8      m9, m18, [tmpq+strideq*2 ], 1
+    vinserti32x8     m10, m19, [tmpq+stride3q  ], 1
+    vinserti32x8     m11, m20, [tmpq+strideq*4 ], 1
+    vinserti32x8     m22, m22, [tmpq+stride5q  ], 1
+    vinserti32x8     m23, m23, [tmpq+stride3q*2], 1
+    vinserti32x8     m28, m28, [tmpq+stride7q  ], 1
+    lea             tmpq, [tmpq+strideq*8]
+    TRANSPOSE8X8W      7,  8,  9, 10, 11, 22, 23, 28, 27
+    movu            ym16, [tmpq+strideq*0 ]
+    movu            ym17, [tmpq+strideq*1 ]
+    movu            ym18, [tmpq+strideq*2 ]
+    movu            ym19, [tmpq+stride3q  ]
+    movu            ym24, [tmpq+strideq*4 ]
+    movu            ym25, [tmpq+stride5q  ]
+    movu            ym26, [tmpq+stride3q*2]
+    movu            ym20, [tmpq+stride7q  ]
+    lea             tmpq, [tmpq+strideq*8]
+    vinserti32x8      m0, m16, [tmpq+strideq*0 ], 1
+    vinserti32x8      m1, m17, [tmpq+strideq*1 ], 1
+    vinserti32x8      m2, m18, [tmpq+strideq*2 ], 1
+    vinserti32x8      m3, m19, [tmpq+stride3q  ], 1
+    vinserti32x8      m4, m24, [tmpq+strideq*4 ], 1
+    vinserti32x8      m5, m25, [tmpq+stride5q  ], 1
+    vinserti32x8      m6, m26, [tmpq+stride3q*2], 1
+    vinserti32x8     m20, m20, [tmpq+stride7q  ], 1
+    TRANSPOSE8X8W      0,  1,  2,  3,  4,  5,  6, 20, 27
+    vshufi32x4       m27, m7, m0, q2020
+    vshufi32x4        m7, m0, q3131
+    vshufi32x4        m0, m8, m1, q2020
+    vshufi32x4        m8, m1, q3131
+    vshufi32x4        m1, m9, m2, q2020
+    vshufi32x4        m9, m2, q3131
+    vshufi32x4        m2, m10, m3, q2020
+    vshufi32x4       m10, m3, q3131
+    vshufi32x4        m3, m11, m4, q2020
+    vshufi32x4       m11, m4, q3131
+    vshufi32x4        m4, m22, m5, q2020
+    vshufi32x4       m22, m5, q3131
+    vshufi32x4        m5, m23, m6, q2020
+    vshufi32x4       m23, m6, q3131
+    vshufi32x4        m6, m28, m20, q2020
+    vshufi32x4       m28, m20, q3131
+%elif %1 == 6 || %1 == 8
+%if %1 == 8
+    sub             dstq, 8
+    movu            xm16, [dstq+strideq*0 ]
+    movu            xm17, [dstq+strideq*1 ]
+    movu            xm18, [dstq+strideq*2 ]
+    movu            xm19, [dstq+stride3q  ]
+    movu            xm24, [dstq+strideq*4 ]
+    movu            xm25, [dstq+stride5q  ]
+    movu            xm26, [dstq+stride3q*2]
+    movu            xm27, [dstq+stride7q  ]
+    lea             tmpq, [dstq+strideq*8 ]
+    vinserti128     ym16, [tmpq+strideq*0 ], 1
+    vinserti128     ym17, [tmpq+strideq*1 ], 1
+    vinserti128     ym18, [tmpq+strideq*2 ], 1
+    vinserti128     ym19, [tmpq+stride3q  ], 1
+    vinserti128     ym24, [tmpq+strideq*4 ], 1
+    vinserti128     ym25, [tmpq+stride5q  ], 1
+    vinserti128     ym26, [tmpq+stride3q*2], 1
+    vinserti128     ym27, [tmpq+stride7q  ], 1
+    lea             tmpq, [tmpq+strideq*8 ]
+    vinserti32x4     m10, m16, [tmpq+strideq*0 ], 2
+    vinserti32x4      m8, m17, [tmpq+strideq*1 ], 2
+    vinserti32x4      m5, m18, [tmpq+strideq*2 ], 2
+    vinserti32x4      m7, m19, [tmpq+stride3q  ], 2
+    vinserti32x4      m2, m24, [tmpq+strideq*4 ], 2
+    vinserti32x4      m9, m25, [tmpq+stride5q  ], 2
+    vinserti32x4      m3, m26, [tmpq+stride3q*2], 2
+    vinserti32x4      m4, m27, [tmpq+stride7q  ], 2
+    lea             tmpq, [tmpq+strideq*8 ]
+    vinserti32x4     m10, [tmpq+strideq*0 ], 3
+    vinserti32x4      m8, [tmpq+strideq*1 ], 3
+    vinserti32x4      m5, [tmpq+strideq*2 ], 3
+    vinserti32x4      m7, [tmpq+stride3q  ], 3
+    vinserti32x4      m2, [tmpq+strideq*4 ], 3
+    vinserti32x4      m9, [tmpq+stride5q  ], 3
+    vinserti32x4      m3, [tmpq+stride3q*2], 3
+    vinserti32x4      m4, [tmpq+stride7q  ], 3
+%else ; %1 == 6
+    movu            xm16, [dstq+strideq*0-8]
+    movu            xm17, [dstq+strideq*1-8]
+    movu            xm18, [dstq+strideq*2-8]
+    movu            xm19, [dstq+stride3q -8]
+    lea             tmpq, [dstq+strideq*4-8]
+    movu             xm2, [tmpq+strideq*0]
+    movu             xm9, [tmpq+strideq*1]
+    movu             xm3, [tmpq+strideq*2]
+    movu             xm4, [tmpq+stride3q ]
+    lea             tmpq, [tmpq+strideq*4]
+    vinserti128     ym16, [tmpq+strideq*0], 1
+    vinserti128     ym17, [tmpq+strideq*1], 1
+    vinserti128     ym18, [tmpq+strideq*2], 1
+    vinserti128     ym19, [tmpq+stride3q ], 1
+    lea             tmpq, [tmpq+strideq*4]
+    vinserti128      ym2, [tmpq+strideq*0], 1
+    vinserti128      ym9, [tmpq+strideq*1], 1
+    vinserti128      ym3, [tmpq+strideq*2], 1
+    vinserti128      ym4, [tmpq+stride3q ], 1
+    lea             tmpq, [tmpq+strideq*4]
+    vinserti32x4     m10, m16, [tmpq+strideq*0], 2
+    vinserti32x4      m8, m17, [tmpq+strideq*1], 2
+    vinserti32x4      m5, m18, [tmpq+strideq*2], 2
+    vinserti32x4      m7, m19, [tmpq+stride3q ], 2
+    lea             tmpq, [tmpq+strideq*4]
+    vinserti32x4      m2, [tmpq+strideq*0], 2
+    vinserti32x4      m9, [tmpq+strideq*1], 2
+    vinserti32x4      m3, [tmpq+strideq*2], 2
+    vinserti32x4      m4, [tmpq+stride3q ], 2
+    lea             tmpq, [tmpq+strideq*4]
+    vinserti32x4     m10, [tmpq+strideq*0], 3
+    vinserti32x4      m8, [tmpq+strideq*1], 3
+    vinserti32x4      m5, [tmpq+strideq*2], 3
+    vinserti32x4      m7, [tmpq+stride3q ], 3
+    lea             tmpq, [tmpq+strideq*4]
+    vinserti32x4      m2, [tmpq+strideq*0], 3
+    vinserti32x4      m9, [tmpq+strideq*1], 3
+    vinserti32x4      m3, [tmpq+strideq*2], 3
+    vinserti32x4      m4, [tmpq+stride3q ], 3
+%endif
+    punpcklwd         m6, m10, m8
+    punpckhwd        m10, m8
+    punpcklwd         m8, m5, m7
+    punpckhwd         m5, m7
+    punpcklwd         m7, m2, m9
+    punpckhwd         m2, m9
+    punpcklwd         m9, m3, m4
+    punpckhwd         m3, m4
+    punpckldq         m4, m6, m8
+    punpckhdq         m6, m8
+    punpckldq         m8, m10, m5
+    punpckhdq        m10, m5
+    punpckldq         m5, m7, m9
+    punpckhdq         m7, m9
+    punpckldq         m9, m2, m3
+    punpckhdq         m2, m3
+%if %1 == 8
+    punpcklqdq        m3, m4, m5
+%endif
+    punpckhqdq        m4, m5
+    punpcklqdq        m5, m6, m7
+    punpckhqdq        m6, m7
+    punpcklqdq        m7, m8, m9
+    punpckhqdq        m8, m9
+    punpcklqdq        m9, m10, m2
+%if %1 == 8
+    punpckhqdq       m10, m2
+%endif
+%else ; %1 == 4
+    kxnorb            k1, k1, k1
+    kmovb             k2, k1
+    vpgatherdq    m7{k1}, [dstq+ym12-4]
+    lea             tmpq, [dstq+strideq*2-4]
+    kmovb             k1, k2
+    vpgatherdq    m4{k2}, [tmpq+ym12]
+    lea             tmpq, [tmpq+strideq*2]
+    kmovb             k2, k1
+    vpgatherdq    m5{k1}, [tmpq+ym12]
+    lea             tmpq, [tmpq+strideq*2]
+    vpgatherdq    m6{k2}, [tmpq+ym12]
+    punpcklwd         m8, m7, m4
+    punpckhwd         m7, m4
+    punpcklwd         m4, m5, m6
+    punpckhwd         m5, m6
+    punpcklwd         m6, m8, m7
+    punpckhwd         m8, m7
+    punpcklwd         m7, m4, m5
+    punpckhwd         m4, m5
+    punpcklqdq        m5, m6, m7
+    punpckhqdq        m6, m7
+    punpcklqdq        m7, m8, m4
+    punpckhqdq        m8, m4
+%endif
+%endif
+
+    ; load L/E/I/H
+%ifidn %2, v
+    movu            ym16, [lq+l_strideq*1]
+    movsldup         m17, [l_shuf_v]
+    vptestnmb         k1, ym16, ym16
+    vmovdqu8    ym16{k1}, [lq+l_strideq*0]  ; l[x][] ? l[x][] : l[x-stride][]
+    vpermb           m16, m17, m16          ; l[x][1]
+%else
+    movq            xm16, [lq+l_strideq*0]
+    movq            xm17, [lq+l_strideq*1]
+    vinserti128     ym16, [lq+l_strideq*2], 1
+    vinserti128     ym17, [lq+l_stride3q ], 1
+    lea             tmpq, [lq+l_strideq*4]
+    vinserti32x4     m16, [tmpq+l_strideq*0], 2
+    vinserti32x4     m17, [tmpq+l_strideq*1], 2
+    vinserti32x4     m16, [tmpq+l_strideq*2], 3
+    vinserti32x4     m17, [tmpq+l_stride3q ], 3
+    punpcklqdq       m16, m17
+    vbroadcasti32x4  m17, [l_shuf_h]
+    vptestnmb         k1, m16, m16
+    vpalignr     m16{k1}, m16, 12
+    pshufb           m16, m17               ; l[x][1]
+%endif
+    vpbroadcastd     m20, [pw_32767]
+    psubw            m17, m5, m6            ; p1-p0
+    psubw            m18, m7, m8            ; q1-q0
+    vptestmw          k1, m16, m16          ; L
+    pabsw            m17, m17
+    pabsw            m18, m18
+    vpmaxuw      m20{k1}, m17, m18
+    vpbroadcastw     m17, [lutq+136]
+    psrlw            m18, m16, [lutq+128]
+    vpbroadcastd     m19, [pw_1]
+    pminuw           m18, m17
+    psrlw            m17, m16, 4            ; H
+    paddw            m16, m16
+    pmaxuw           m18, m19               ; I
+    vpaddd           m16, [pw_4] {1to16}
+    paddw            m16, m18               ; E
+    REPX {pmullw x, m13}, m17, m18, m16
+    vpcmpw            k4, m20, m17, 6       ; hev
+%if %1 != 4
+    psubw            m19, m4, m5            ; p2-p1
+    pabsw            m19, m19
+%if %1 == 8 || %1 == 16
+    psubw            m17, m3, m4            ; p3-p2
+    pabsw            m17, m17
+    pmaxuw           m19, m17
+    psubw            m17, m9, m10           ; q3-q2
+    pabsw            m17, m17
+    pmaxuw           m19, m17
+%endif
+    psubw            m17, m9, m8            ; q2-q1
+    pabsw            m17, m17
+    pmaxuw           m19, m17
+%if %1 == 16
+    vpbroadcastd    ym17, [maskq+4]
+    vpord           ym17, [maskq+8] {1to8}
+    vptestmd          k1, ym17, ym21
+%else
+    vptestmd          k1, ym21, [maskq+4] {1to8}
+%endif
+    pmaxuw           m19, m20
+    psubw            m17, m4, m6            ; p2-p0
+    pabsw            m17, m17
+    pmaxuw           m17, m20
+    vmovdqa64    m20{k1}, m19               ; only apply fm-wide to wd>4 blocks
+%if %1 == 8 || %1 == 16
+    psubw            m19, m3, m6            ; p3-p0
+    pabsw            m19, m19
+    pmaxuw           m17, m19
+    psubw            m19, m7, m10           ; q3-q0
+    pabsw            m19, m19
+    pmaxuw           m17, m19
+%endif
+    psubw            m19, m7, m9            ; q2-q0
+    pabsw            m19, m19
+    pmaxuw           m17, m19
+%endif
+    vpcmpw            k1, m20, m18, 2
+    psubw            m18, m5, m8            ; p1-q1
+    psubw            m19, m6, m7            ; p0-q0
+    pabsw            m18, m18
+    pabsw            m19, m19
+    psrlw            m18, 1
+    paddw            m19, m19
+    paddw            m18, m19               ; abs(p0-q0)*2+(abs(p1-q1)>>1)
+    vpcmpw        k1{k1}, m18, m16, 2       ; abs(p0-q0)*2+(abs(p1-q1)>>1) <= E
+%if %1 != 4
+    vpcmpw        k2{k1}, m17, m13, 2       ; flat8in
+%endif
+%if %1 == 16
+    psubw            m20, m0, m6
+    psubw            m16, m1, m6
+    pabsw            m20, m20
+    psubw            m17, m2, m6
+    pabsw            m16, m16
+    psubw            m18, m11, m7
+    pabsw            m17, m17
+    psubw            m19, m22, m7
+    pabsw            m18, m18
+    pmaxuw           m20, m16
+    psubw            m16, m23, m7
+    pabsw            m19, m19
+    pmaxuw           m17, m18
+    pabsw            m16, m16
+    vpandd          ym18, ym21, [maskq+8] {1to8}
+    pmaxuw           m20, m17
+    pmaxuw           m19, m16
+    pcmpeqd         ym16, ym21, ym18
+    vpternlogd      ym18, ym21, [maskq+4] {1to8}, 0xc8
+    pmaxuw           m20, m19
+    pcmpeqd         ym17, ym21, ym18
+    vpternlogd      ym18, ym21, [maskq+0] {1to8}, 0xc8
+    vpcmpw        k3{k2}, m20, m13, 2       ; flat8in & flat8out
+    pcmpeqd         ym18, ym21
+    vptestmb      k3{k3}, ym16, ym16        ; flat8 & fm
+    vptestmb      k2{k2}, ym17, ym17        ; flat8in
+    vptestmb      k1{k1}, ym18, ym18
+    kandnd            k1, k2, k1            ; fm & !flat8 & !flat16
+    kandnd            k2, k3, k2            ; flat8 & !flat16
+%elif %1 == 6 || %1 == 8
+    vpandd          ym17, ym21, [maskq+4] {1to8}
+    pcmpeqd         ym16, ym21, ym17
+    vpternlogd      ym17, ym21, [maskq+0] {1to8}, 0xc8
+    pcmpeqd         ym17, ym21
+    vptestmb      k2{k2}, ym16, ym16        ; flat8 & fm
+    vptestmb      k1{k1}, ym17, ym17
+    kandnd            k1, k2, k1            ; fm & !flat8
+%else ; %1 == 4
+    vpandd          ym16, ym21, [maskq+0] {1to8}
+    pcmpeqd         ym16, ym21
+    vptestmb      k1{k1}, ym16, ym16
+%endif
+
+    ; short filter
+    psubw            m16, m7, m6
+    vpbroadcastd     m17, [pw_3]
+    paddw            m18, m16, m16
+    paddw            m18, m16
+    psubw            m16, m5, m8            ; iclip_diff(p1-q1)
+    pminsw           m16, m14
+    vpmaxsw   m16{k4}{z}, m15               ; f=iclip_diff(p1-q1)&hev
+    knotd             k4, k4                ; !hev
+    paddw            m16, m18               ; f=iclip_diff(3*(q0-p0)+f)
+    vpbroadcastd     m18, [pw_4]
+    pminsw           m16, m14
+    vpmaxsw   m16{k1}{z}, m15               ; f&=fm
+    paddw            m17, m16
+    paddw            m16, m18
+    vpbroadcastd     m18, [pw_16384]
+    pminsw           m17, m14
+    pminsw           m16, m14
+    psraw            m17, 3                 ; f2
+    psraw            m16, 3                 ; f1
+    paddw             m6, m17
+    psubw             m7, m16
+    vpmulhrsw m16{k4}{z}, m18               ; (f=(f1+1)>>1) & !hev
+    psubw            m17, m14, m15          ; 1023 or 4095
+    pxor             m18, m18
+    paddw             m5, m16
+    psubw             m8, m16
+    REPX {pminsw x, m17}, m6, m7, m5, m8
+    REPX {pmaxsw x, m18}, m6, m7, m5, m8
+
+%if %1 == 16 ; flat16 filter
+    vpaddd           m19, m0, [pw_1] {1to16}
+    paddw            m16, m1, m2            ; p5+p4
+    paddw            m26, m1, m6            ; p5+p0
+    paddw            m24, m2, m7            ; p4+q0
+    paddw            m16, m4                ; p5+p4+p3
+    paddw            m17, m3, m5            ; p2+p1
+    psllw            m19, 3
+    paddw            m16, m26               ; p5*2+p4+p3+p0
+    paddw            m17, m24               ; p4+p2+p1+q0
+    psubw            m19, m0                ; p6*7+8
+    paddw            m16, m17               ; p5*2+p4*2+p3+p2+p1+q0
+    paddw            m18, m3, m8
+    paddw            m19, m16               ; p6*7+p5+p4*2+p3+p2+p1+p0+q0
+    paddw            m25, m1, m0
+    paddw            m16, m0, m0
+    psrlw         m1{k3}, m19, 4
+    paddw            m19, m18
+    psubw            m19, m16               ; +p3+q1-p6*2
+    paddw            m16, m2, m0
+    psrlw         m2{k3}, m19, 4
+    psubw            m19, m25
+    paddw            m25, m4, m9
+    paddw            m20, m10, m5
+    paddw            m19, m25               ; +p2+q2-p6-p5
+    paddw            m17, m0, m3
+    psubw            m16, m20, m16
+    psrlw         m3{k3}, m19, 4
+    paddw            m19, m16               ; +p1+q3-p6-p4
+    paddw            m16, m11, m6
+    psubw            m16, m17
+    paddw            m17, m0, m4
+    psrlw         m4{k3}, m19, 4
+    paddw            m19, m16               ; +p0+q4-p6-p3
+    paddw            m16, m22, m7
+    psubw            m16, m17
+    paddw            m17, m0, m5
+    psrlw         m5{k3}, m19, 4
+    paddw            m19, m16               ; +q0+q5-p6-p2
+    paddw            m16, m23, m8
+    psrlw         m6{k3}, m19, 4
+    psubw            m16, m17
+    paddw            m19, m16               ; +q1+q6-p6-p1
+    paddw            m16, m23, m9
+    psrlw         m7{k3}, m19, 4
+    psubw            m16, m26
+    paddw            m19, m16               ; +q2+q6-p5-p0
+    paddw            m16, m23, m10
+    psrlw         m8{k3}, m19, 4
+    psubw            m16, m24
+    paddw            m19, m16               ; +q3+q6-p4-p0
+    paddw            m16, m23, m11
+    psrlw         m9{k3}, m19, 4
+    psubw            m16, m18
+    paddw            m19, m16               ; +q4+q6-p3-q1
+    paddw            m16, m23, m22
+    psrlw        m10{k3}, m19, 4
+    psubw            m16, m25
+    paddw            m19, m16               ; +q5+q6-p2-q2
+    paddw            m16, m23, m23
+    psrlw        m11{k3}, m19, 4
+    psubw            m16, m20
+    paddw            m19, m16               ; +q6*2-p1-q3
+    psrlw        m22{k3}, m19, 4
+%endif
+%if %1 == 8 || %1 == 16 ; flat8 filter
+    vpbroadcastd     m20, [pw_4096]
+    paddw            m16, m3, m4            ; p3+p2
+    paddw            m19, m5, m6            ; p1+p0
+    paddw            m17, m16, m16          ; 2*(p3+p2)
+    paddw            m19, m3                ; p1+p0+p3
+    paddw            m17, m7                ; 2*(p3+p2)+q0
+    paddw            m19, m17               ; 3*p3+2*p2+p1+p0+q0
+    paddw            m18, m4, m7
+    pmulhrsw      m4{k2}, m19, m20
+    psubw            m19, m16
+    paddw            m17, m5, m8
+    paddw            m16, m3, m5
+    paddw            m19, m17
+    pmulhrsw      m5{k2}, m19, m20
+    psubw            m19, m16
+    paddw            m16, m6, m9
+    paddw            m19, m16
+    paddw            m16, m3, m6
+    pmulhrsw      m6{k2}, m19, m20
+    paddw            m19, m10
+    psubw            m16, m7, m16
+    paddw            m19, m16
+    psubw            m16, m10, m18
+    pmulhrsw      m7{k2}, m19, m20
+    paddw            m16, m8
+    paddw            m19, m16
+    psubw            m16, m10, m17
+    pmulhrsw      m8{k2}, m19, m20
+    paddw            m16, m9
+    paddw            m19, m16
+    pmulhrsw      m9{k2}, m19, m20
+%elif %1 == 6 ; flat6 filter
+    vpbroadcastd     m10, [pw_4096]
+    paddw             m2, m5, m6
+    paddw             m0, m4, m7
+    paddw             m1, m2, m4            ; p2+p1+p0
+    paddw             m3, m4, m4
+    paddw             m1, m1
+    paddw             m4, m5
+    paddw             m1, m0                ; p2+2*(p2+p1+p0)+q0
+    psubw             m3, m7, m3
+    pmulhrsw      m5{k2}, m1, m10
+    paddw             m3, m8
+    psubw             m4, m8, m4
+    paddw             m1, m3
+    pmulhrsw      m6{k2}, m1, m10
+    paddw             m4, m9
+    paddw             m9, m9
+    paddw             m1, m4
+    pmulhrsw      m7{k2}, m1, m10
+    psubw             m9, m2
+    paddw             m1, m9
+    pmulhrsw      m8{k2}, m1, m10
+%endif
+
+%ifidn %2, v
+%if %1 == 16
+    mova [tmpq+strideq*2 ], m1              ; p5
+    mova [tmpq+stride3q  ], m2              ; p4
+    mova [tmpq+strideq*4 ], m3              ; p3
+    mova [tmpq+stride5q  ], m4              ; p2
+%elif %1 == 8
+    mova [tmpq+strideq*1 ], m4              ; p2
+%endif
+    mova [dstq+mstrideq*2], m5              ; p1
+    mova [dstq+mstrideq  ], m6              ; p0
+    mova [dstq+strideq*0 ], m7              ; q0
+    mova [dstq+strideq*1 ], m8              ; q1
+%if %1 == 8 || %1 == 16
+    mova [dstq+strideq*2 ], m9              ; q2
+%endif
+%if %1 == 16
+    mova [dstq+stride3q  ], m10             ; q3
+    mova [dstq+strideq*4 ], m11             ; q4
+    mova [dstq+stride5q  ], m22             ; q5
+%endif
+%else
+%if %1 == 16
+    TRANSPOSE8X8W     27,  0,  1,  2,  3,  4,  5,  6, 20
+    TRANSPOSE8X8W      7,  8,  9, 10, 11, 22, 23, 28, 20
+    mova          [dstq+strideq*0 -16], xm27
+    mova          [dstq+strideq*0    ], xm7
+    mova          [dstq+strideq*1 -16], xm0
+    mova          [dstq+strideq*1    ], xm8
+    mova          [dstq+strideq*2 -16], xm1
+    mova          [dstq+strideq*2    ], xm9
+    mova          [dstq+stride3q  -16], xm2
+    mova          [dstq+stride3q     ], xm10
+    mova          [dstq+strideq*4 -16], xm3
+    mova          [dstq+strideq*4    ], xm11
+    mova          [dstq+stride5q  -16], xm4
+    mova          [dstq+stride5q     ], xm22
+    mova          [dstq+stride3q*2-16], xm5
+    mova          [dstq+stride3q*2   ], xm23
+    mova          [dstq+stride7q  -16], xm6
+    mova          [dstq+stride7q     ], xm28
+    lea             dstq, [dstq+strideq*8]
+    vextracti128  [dstq+strideq*0 -16], ym27, 1
+    vextracti128  [dstq+strideq*0    ], ym7, 1
+    vextracti128  [dstq+strideq*1 -16], ym0, 1
+    vextracti128  [dstq+strideq*1    ], ym8, 1
+    vextracti128  [dstq+strideq*2 -16], ym1, 1
+    vextracti128  [dstq+strideq*2    ], ym9, 1
+    vextracti128  [dstq+stride3q  -16], ym2, 1
+    vextracti128  [dstq+stride3q     ], ym10, 1
+    vextracti128  [dstq+strideq*4 -16], ym3, 1
+    vextracti128  [dstq+strideq*4    ], ym11, 1
+    vextracti128  [dstq+stride5q  -16], ym4, 1
+    vextracti128  [dstq+stride5q     ], ym22, 1
+    vextracti128  [dstq+stride3q*2-16], ym5, 1
+    vextracti128  [dstq+stride3q*2   ], ym23, 1
+    vextracti128  [dstq+stride7q  -16], ym6, 1
+    vextracti128  [dstq+stride7q     ], ym28, 1
+    lea             dstq, [dstq+strideq*8]
+    vextracti32x4 [dstq+strideq*0 -16], m27, 2
+    vextracti32x4 [dstq+strideq*0    ], m7, 2
+    vextracti32x4 [dstq+strideq*1 -16], m0, 2
+    vextracti32x4 [dstq+strideq*1    ], m8, 2
+    vextracti32x4 [dstq+strideq*2 -16], m1, 2
+    vextracti32x4 [dstq+strideq*2    ], m9, 2
+    vextracti32x4 [dstq+stride3q  -16], m2, 2
+    vextracti32x4 [dstq+stride3q     ], m10, 2
+    vextracti32x4 [dstq+strideq*4 -16], m3, 2
+    vextracti32x4 [dstq+strideq*4    ], m11, 2
+    vextracti32x4 [dstq+stride5q  -16], m4, 2
+    vextracti32x4 [dstq+stride5q     ], m22, 2
+    vextracti32x4 [dstq+stride3q*2-16], m5, 2
+    vextracti32x4 [dstq+stride3q*2   ], m23, 2
+    vextracti32x4 [dstq+stride7q  -16], m6, 2
+    vextracti32x4 [dstq+stride7q     ], m28, 2
+    lea             dstq, [dstq+strideq*8]
+    vextracti32x4 [dstq+strideq*0 -16], m27, 3
+    vextracti32x4 [dstq+strideq*0    ], m7, 3
+    vextracti32x4 [dstq+strideq*1 -16], m0, 3
+    vextracti32x4 [dstq+strideq*1    ], m8, 3
+    vextracti32x4 [dstq+strideq*2 -16], m1, 3
+    vextracti32x4 [dstq+strideq*2    ], m9, 3
+    vextracti32x4 [dstq+stride3q  -16], m2, 3
+    vextracti32x4 [dstq+stride3q     ], m10, 3
+    vextracti32x4 [dstq+strideq*4 -16], m3, 3
+    vextracti32x4 [dstq+strideq*4    ], m11, 3
+    vextracti32x4 [dstq+stride5q  -16], m4, 3
+    vextracti32x4 [dstq+stride5q     ], m22, 3
+    vextracti32x4 [dstq+stride3q*2-16], m5, 3
+    vextracti32x4 [dstq+stride3q*2   ], m23, 3
+    vextracti32x4 [dstq+stride7q  -16], m6, 3
+    vextracti32x4 [dstq+stride7q     ], m28, 3
+%elif %1 == 8
+    TRANSPOSE8X8W      3,  4,  5,  6,  7,  8,  9, 10,  2
+    movu   [dstq+strideq*0 ], xm3
+    movu   [dstq+strideq*1 ], xm4
+    movu   [dstq+strideq*2 ], xm5
+    movu   [dstq+stride3q  ], xm6
+    movu   [dstq+strideq*4 ], xm7
+    movu   [dstq+stride5q  ], xm8
+    movu   [dstq+stride3q*2], xm9
+    movu   [dstq+stride7q  ], xm10
+    lea             dstq, [dstq+strideq*8]
+    vextracti128  [dstq+strideq*0 ], ym3, 1
+    vextracti128  [dstq+strideq*1 ], ym4, 1
+    vextracti128  [dstq+strideq*2 ], ym5, 1
+    vextracti128  [dstq+stride3q  ], ym6, 1
+    vextracti128  [dstq+strideq*4 ], ym7, 1
+    vextracti128  [dstq+stride5q  ], ym8, 1
+    vextracti128  [dstq+stride3q*2], ym9, 1
+    vextracti128  [dstq+stride7q  ], ym10, 1
+    lea             dstq, [dstq+strideq*8]
+    vextracti32x4 [dstq+strideq*0 ], m3, 2
+    vextracti32x4 [dstq+strideq*1 ], m4, 2
+    vextracti32x4 [dstq+strideq*2 ], m5, 2
+    vextracti32x4 [dstq+stride3q  ], m6, 2
+    vextracti32x4 [dstq+strideq*4 ], m7, 2
+    vextracti32x4 [dstq+stride5q  ], m8, 2
+    vextracti32x4 [dstq+stride3q*2], m9, 2
+    vextracti32x4 [dstq+stride7q  ], m10, 2
+    lea             dstq, [dstq+strideq*8]
+    vextracti32x4 [dstq+strideq*0 ], m3, 3
+    vextracti32x4 [dstq+strideq*1 ], m4, 3
+    vextracti32x4 [dstq+strideq*2 ], m5, 3
+    vextracti32x4 [dstq+stride3q  ], m6, 3
+    vextracti32x4 [dstq+strideq*4 ], m7, 3
+    vextracti32x4 [dstq+stride5q  ], m8, 3
+    vextracti32x4 [dstq+stride3q*2], m9, 3
+    vextracti32x4 [dstq+stride7q  ], m10, 3
+    lea             dstq, [dstq+strideq*8+8]
+%else ; %1 == 4 || %1 == 6
+    punpcklwd         m9, m5, m6
+    punpckhwd         m5, m6
+    kxnorb            k1, k1, k1
+    punpcklwd         m6, m7, m8
+    punpckhwd         m7, m8
+    kmovb             k2, k1
+    punpckldq         m8, m9, m6
+    vpscatterdq [dstq+ym12-4]{k1}, m8
+    punpckhdq         m9, m6
+    lea             tmpq, [dstq+strideq*2-4]
+    kmovb             k1, k2
+    vpscatterdq [tmpq+ym12]{k2}, m9
+    punpckldq         m6, m5, m7
+    lea             tmpq, [tmpq+strideq*2]
+    kmovb             k2, k1
+    vpscatterdq [tmpq+ym12]{k1}, m6
+    punpckhdq         m5, m7
+    lea             tmpq, [tmpq+strideq*2]
+    vpscatterdq [tmpq+ym12]{k2}, m5
+%endif
+%endif
+%endmacro
+
+INIT_ZMM avx512icl
+cglobal lpf_v_sb_y_16bpc, 6, 12, 26, dst, stride, mask, l, l_stride, \
+                                     lut, w, stride3, mstride, tmp, \
+                                     mask_bits, stride5
+%define base tmpq-filter_mask
+    SWAP              12, 26                ; avoids clobbering xmm10 on WIN64
+    lea             tmpq, [filter_mask]
+    mov              r6d, r7m               ; bitdepth_max
+    lea         stride3q, [strideq*3]
+    shl        l_strideq, 2
+    lea         stride5q, [strideq*5]
+    shr              r6d, 11                ; is_12bpc
+    mova            ym21, [base+filter_mask]
+    mov         mstrideq, strideq
+    vpbroadcastd     m13, [base+pw_4+r6*8]
+    mov       mask_bitsd, 0xff
+    vpbroadcastd     m14, [base+clip_max+r6*4]
+    sub               lq, l_strideq
+    vpbroadcastd     m15, [base+clip_min+r6*4]
+    neg         mstrideq
+    mov               wd, wm
+.loop:
+    test       [maskq+8], mask_bitsd        ; vmask[2]
+    jz .no_flat16
+    FILTER            16, v
+    jmp .end
+.no_flat16:
+    test       [maskq+4], mask_bitsd        ; vmask[1]
+    jz .no_flat
+    FILTER             8, v
+    jmp .end
+.no_flat:
+    test       [maskq+0], mask_bitsd        ; vmask[0]
+    jz .end
+    call .v4
+.end:
+    shl       mask_bitsd, 8
+    add             dstq, 64
+    pslld           ym21, 8
+    add               lq, 32
+    sub               wd, 8
+    jg .loop
+    RET
+ALIGN function_align
+.v4: ; called by both luma and chroma
+    FILTER             4, v
+    ret
+
+cglobal lpf_h_sb_y_16bpc, 6, 13, 29, dst, stride, mask, l, l_stride, \
+                                     lut, h, stride3, l_stride3, tmp, \
+                                     mask_bits, stride5, stride7
+    lea             tmpq, [filter_mask]
+    mov              r6d, r7m               ; bitdepth_max
+    lea         stride3q, [strideq*3]
+    vpbroadcastd    ym12, strided
+    shl        l_strideq, 2
+    lea         stride5q, [strideq*5]
+    shr              r6d, 11                ; is_12bpc
+    pmulld          ym12, [base+stride_mul]
+    lea         stride7q, [strideq+stride3q*2]
+    mova            ym21, [base+filter_mask]
+    mov       mask_bitsd, 0xff
+    vpbroadcastd     m13, [base+pw_4+r6*8]
+    sub               lq, 4
+    vpbroadcastd     m14, [base+clip_max+r6*4]
+    lea       l_stride3q, [l_strideq*3]
+    vpbroadcastd     m15, [base+clip_min+r6*4]
+    mov               hd, hm
+.loop:
+    test       [maskq+8], mask_bitsd        ; vmask[2]
+    jz .no_flat16
+    FILTER            16, h
+    jmp .end
+.no_flat16:
+    test       [maskq+4], mask_bitsd        ; vmask[1]
+    jz .no_flat
+    FILTER             8, h
+    jmp .end2
+.no_flat:
+    test       [maskq+0], mask_bitsd        ; vmask[0]
+    jz .no_filter
+    call .h4
+.no_filter:
+    lea             dstq, [dstq+stride3q*8]
+.end:
+    lea             dstq, [dstq+strideq*8]
+.end2:
+    shl       mask_bitsd, 8
+    pslld           ym21, 8
+    lea               lq, [lq+l_strideq*8]
+    sub               hd, 8
+    jg .loop
+    RET
+ALIGN function_align
+.h4: ; called by both luma and chroma
+    FILTER         4, h
+    ret
+
+cglobal lpf_v_sb_uv_16bpc, 6, 11, 22, dst, stride, mask, l, l_stride, lut, \
+                                      w, stride3, mstride, tmp, mask_bits
+    lea             tmpq, [filter_mask]
+    mov              r6d, r7m               ; bitdepth_max
+    shl        l_strideq, 2
+    lea         stride3q, [strideq*3]
+    shr              r6d, 11                ; is_12bpc
+    mova            ym21, [base+filter_mask]
+    mov        mstrideq, strideq
+    vpbroadcastd     m13, [base+pw_4+r6*8]
+    mov       mask_bitsd, 0xff
+    vpbroadcastd     m14, [base+clip_max+r6*4]
+    sub               lq, l_strideq
+    vpbroadcastd     m15, [base+clip_min+r6*4]
+    neg         mstrideq
+    mov               wd, wm
+.loop:
+    test       [maskq+4], mask_bitsd        ; vmask[1]
+    jz .no_flat
+    FILTER             6, v
+    jmp .end
+.no_flat:
+    test       [maskq+0], mask_bitsd        ; vmask[0]
+    jz .end
+    call mangle(private_prefix %+ _lpf_v_sb_y_16bpc_avx512icl).v4
+.end:
+    shl       mask_bitsd, 8
+    add             dstq, 64
+    pslld           ym21, 8
+    add               lq, 32
+    sub               wd, 8
+    jg .loop
+    RET
+
+cglobal lpf_h_sb_uv_16bpc, 6, 11, 22, dst, stride, mask, l, l_stride, lut, \
+                                      h, stride3, l_stride3, tmp, mask_bits
+    lea             tmpq, [filter_mask]
+    mov              r6d, r7m               ; bitdepth_max
+    vpbroadcastd    ym12, strided
+    shl        l_strideq, 2
+    shr              r6d, 11                ; is_12bpc
+    pmulld          ym12, [base+stride_mul]
+    lea         stride3q, [strideq*3]
+    mova            ym21, [base+filter_mask]
+    mov       mask_bitsd, 0xff
+    vpbroadcastd     m13, [base+pw_4+r6*8]
+    sub               lq, 4
+    vpbroadcastd     m14, [base+clip_max+r6*4]
+    lea       l_stride3q, [l_strideq*3]
+    vpbroadcastd     m15, [base+clip_min+r6*4]
+    mov               hd, hm
+.loop:
+    test       [maskq+4], mask_bitsd        ; vmask[1]
+    jz .no_flat
+    FILTER             6, h
+    jmp .end
+.no_flat:
+    test       [maskq+0], mask_bitsd        ; vmask[0]
+    jz .end
+    call mangle(private_prefix %+ _lpf_h_sb_y_16bpc_avx512icl).h4
+.end:
+    lea             tmpq, [strideq+stride3q]
+    shl       mask_bitsd, 8
+    pslld           ym21, 8
+    lea             dstq, [dstq+tmpq*8]
+    lea               lq, [lq+l_strideq*8]
+    sub               hd, 8
+    jg .loop
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/loopfilter16_sse.asm b/media/libdav1d/src/src/x86/loopfilter16_sse.asm
new file mode 100644
index 0000000000..c486b57a21
--- /dev/null
+++ b/media/libdav1d/src/src/x86/loopfilter16_sse.asm
@@ -0,0 +1,1793 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 16
+
+%if ARCH_X86_64
+%define PIC_sym(a) a
+%else
+%define PIC_base $$
+%define PIC_sym(a) pic_regq+a-PIC_base
+%endif
+
+pb_4x1_4x5_4x9_4x13: times 4 db 0, 1
+                     times 4 db 8, 9
+
+pw_1: times 8 dw 1
+pw_2: times 8 dw 2
+pw_3: times 8 dw 3
+; 4 and 16 need to be next to each other since they are used as alternates
+; depending on whether bitdepth is 10 or 12
+pw_4: times 8 dw 4
+pw_16: times 8 dw 16
+pw_8: times 8 dw 8
+pw_4096: times 8 dw 4096
+
+pb_mask: dd 1, 1, 2, 2
+
+SECTION .text
+
+%if ARCH_X86_32
+%if STACK_ALIGNMENT < 16
+%define extra_stack 2
+%else
+%define extra_stack 0
+%endif
+%endif
+
+%macro RELOC_ARGS 2 ; h/v, off
+ASSERT ARCH_X86_32
+%if STACK_ALIGNMENT < 16
+    mov          r5d, [rstk + stack_offset + 4*4 + 4]
+%define lstridem [esp+%2+0*gprsize]
+    mov     lstridem, r5d
+    mov          r5d, [rstk + stack_offset + 4*5 + 4]
+%define lutm [esp+%2+1*gprsize]
+    mov         lutm, r5d
+    mov          r5d, [rstk + stack_offset + 4*6 + 4]
+%ifidn %1, v
+%define wm [esp+%2+2*gprsize]
+    mov           wm, r5d
+    mov          r5d, [rstk + stack_offset + 4*3 + 4]
+%define lm [esp+%2+3*gprsize]
+    mov           lm, r5d
+%else ; %1 == h
+%define hm [esp+%2+2*gprsize]
+    mov           hm, r5d
+%endif ; %1==v
+   mov           r5d, r7m
+%define bdmulm [esp+%2+4*gprsize]
+    mov       bdmulm, r5d
+%else
+%define lstridem r4m
+%define lutm r5m
+%ifidn %1, v
+%define wm r6m
+%define lm r3m
+%else
+%define hm r6m
+%endif
+%define bdmulm r7m
+%endif ; STACK_ALIGNMENT
+%endmacro
+
+%macro UNRELOC_ARGS 0
+%if ARCH_X86_32
+%undef lm
+%undef lstridem
+%undef wm
+%undef hm
+%undef lutm
+%endif
+%endmacro
+
+%macro SPLATD 2
+    movd %1, %2
+    pshufd %1, %1, q0000
+%endmacro
+
+%macro SPLATW 2
+    movd %1, %2
+    pshuflw %1, %1, q0000
+    punpcklqdq %1, %1
+%endmacro
+
+;        in:            out:
+; mm%1   a b c d        a e i m
+; mm%2   e f g h        b f j n
+; mm%3   i j k l   ->   c g k o
+; mm%4   m n o p        d h l p
+%macro TRANSPOSE4X4W 5
+    punpcklwd        m%5, m%1, m%2
+    punpckhwd        m%1, m%2
+    punpcklwd        m%2, m%3, m%4
+    punpckhwd        m%3, m%4
+    punpckldq        m%4, m%5, m%2
+    punpckhdq        m%5, m%2
+    punpckldq        m%2, m%1, m%3
+    punpckhdq        m%1, m%3
+
+    SWAP              %1, %4
+    SWAP              %2, %5, %3
+%endmacro
+
+;         in:                  out:
+; m%1   a b c d e f g h      a i q y 6 E M U
+; m%2   i j k l m n o p      b j r z 7 F N V
+; m%3   q r s t u v w x      c k s 0 8 G O W
+; m%4   y z 0 1 2 3 4 5      d l t 1 9 H P X
+; m%5   6 7 8 9 A B C D  ->  e m u 2 A I Q Y
+; m%6   E F G H I J K L      f n v 3 B J R Z
+; m%7   M N O P Q R S T      g o w 4 C K S +
+; m%8   U V W X Y Z + =      h p x 5 D L T =
+%if ARCH_X86_64
+%macro TRANSPOSE8X8W 9
+    ; m%1   a b c d e f g h      a i q y b j r z
+    ; m%2   i j k l m n o p      c k s 0 d l t 1
+    ; m%3   q r s t u v w x  ->  e m u 2 f n v 3
+    ; m%4   y z 0 1 2 3 4 5      g o w 4 h p x 5
+    TRANSPOSE4X4W     %1, %2, %3, %4, %9
+
+    ; m%5   6 7 8 9 A B C D      6 E M U 7 F N V
+    ; m%6   E F G H I J K L      8 G O W 9 H P X
+    ; m%7   M N O P Q R S T  ->  A I Q Y B J R Z
+    ; m%8   U V W X Y Z + =      C K S + D L T =
+    TRANSPOSE4X4W     %5, %6, %7, %8, %9
+
+    ; m%1   a i q y b j r z      a i q y 6 E M U
+    ; m%2   c k s 0 d l t 1      b j r z 7 F N V
+    ; m%3   e m u 2 f n v 3      c k s 0 8 G O W
+    ; m%4   g o w 4 h p x 5      d l t 1 9 H P X
+    ; m%5   6 E M U 7 F N V  ->  e m u 2 A I Q Y
+    ; m%6   8 G O W 9 H P X      f n v 3 B J R Z
+    ; m%7   A I Q Y B J R Z      g o w 4 C K S +
+    ; m%8   C K S + D L T =      h p x 5 D L T =
+    punpckhqdq       m%9, m%1, m%5
+    punpcklqdq       m%1, m%5
+    punpckhqdq       m%5, m%2, m%6
+    punpcklqdq       m%2, m%6
+    punpckhqdq       m%6, m%3, m%7
+    punpcklqdq       m%3, m%7
+    punpckhqdq       m%7, m%4, m%8
+    punpcklqdq       m%4, m%8
+
+    SWAP %8, %7, %4, %5, %3, %2, %9
+%endmacro
+%else ; x86-32
+; input: 1-7 in registers, 8 in first memory [read-only]
+; second memory is scratch, and may overlap with first or third memory
+; output: 1-5,7-8 in registers, 6 in third memory [write-only]
+%macro TRANSPOSE8X8W 13 ; regs [8x], mem [3x], a/u [in/out alignment [2x]
+    TRANSPOSE4X4W     %1, %2, %3, %4, %8
+%ifnidn %9, ""
+    mov%12           m%8, %9
+%else
+    mova             m%8, %10
+%endif
+    mova             %10, m%4
+    TRANSPOSE4X4W     %5, %6, %7, %8, %4
+    punpckhqdq       m%4, m%1, m%5
+    punpcklqdq       m%1, m%5
+    punpckhqdq       m%5, m%2, m%6
+    punpcklqdq       m%2, m%6
+    punpckhqdq       m%6, m%3, m%7
+    punpcklqdq       m%3, m%7
+    mova             m%7, %10
+%ifnidn %11, ""
+    mov%13           %11, m%6
+%else
+    mova             %10, m%6
+%endif
+    punpckhqdq       m%6, m%7, m%8
+    punpcklqdq       m%7, m%8
+
+    ; 1,4,2,5,3,8,7,6 -> 1,2,3,4,5,6,7,8
+    SWAP              %2, %4, %5, %3
+    SWAP              %6, %8
+%endmacro
+%endif ; x86-32/64
+
+; transpose and write m8-11, everything else is scratch
+%macro TRANSPOSE_8x4_AND_WRITE_4x8 5 ; p1, p0, q0, q1, tmp
+    ; transpose 8x4
+    punpcklwd     %5, %1, %2
+    punpckhwd     %1, %2
+    punpcklwd     %2, %3, %4
+    punpckhwd     %3, %4
+    punpckldq     %4, %5, %2
+    punpckhdq     %5, %2
+    punpckldq     %2, %1, %3
+    punpckhdq     %1, %3
+
+    ; write out
+    movq   [dstq+strideq*0-4], %4
+    movhps [dstq+strideq*1-4], %4
+    movq   [dstq+strideq*2-4], %5
+    movhps [dstq+stride3q -4], %5
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], %2
+    movhps [dstq+strideq*1-4], %2
+    movq   [dstq+strideq*2-4], %1
+    movhps [dstq+stride3q -4], %1
+    lea         dstq, [dstq+strideq*4]
+%endmacro
+
+%macro FILTER 2 ; width [4/6/8/16], dir [h/v]
+    ; load data
+%ifidn %2, v
+%if %1 == 4
+%if ARCH_X86_64
+%define P1 m8
+%define P0 m9
+%define Q0 m10
+%define Q1 m11
+    mova          P1, [dstq+mstrideq*2]         ; p1
+    mova          P0, [dstq+mstrideq*1]         ; p0
+    mova          Q0, [dstq+strideq*0]          ; q0
+    mova          Q1, [dstq+strideq*1]          ; q1
+%else ; x86-32
+%define P1 [dstq+mstrideq*2]
+%define P0 [dstq+mstrideq*1]
+%define Q0 [dstq+strideq*0]
+%define Q1 [dstq+strideq*1]
+%endif ; x86-32/64
+%else ; %1 != 4
+    ; load 6-8 pixels, remainder (for wd=16) will be read inline
+    lea         tmpq, [dstq+mstrideq*4]
+%if ARCH_X86_64
+    ; we load p3 later
+%define P2 m13
+%define P1 m8
+%define P0 m9
+%define Q0 m10
+%define Q1 m11
+%define Q2 m14
+    mova          P2, [tmpq+strideq*1]
+    mova          P1, [tmpq+strideq*2]
+    mova          P0, [tmpq+stride3q]
+    mova          Q0, [dstq+strideq*0]
+    mova          Q1, [dstq+strideq*1]
+    mova          Q2, [dstq+strideq*2]
+%if %1 != 6
+%define P3 [tmpq+strideq*0]
+%define Q3 m15
+    mova          Q3, [dstq+stride3q]
+%endif ; %1 != 6
+%else ; x86-32
+%define P2 [tmpq+strideq*1]
+%define P1 [dstq+mstrideq*2]
+%define P0 [dstq+mstrideq*1]
+%define Q0 [dstq+strideq*0]
+%define Q1 [dstq+strideq*1]
+%define Q2 [dstq+strideq*2]
+%if %1 != 6
+%define P3 [dstq+mstrideq*4]
+%define Q3 [dstq+stride3q]
+%endif ; %1 != 6
+%endif ; x86-32/64
+%endif ; %1 ==/!= 4
+%else ; %2 != v
+    ; load lines
+%if %1 == 4
+    movq          m0, [dstq+strideq*0-4]
+    movq          m2, [dstq+strideq*1-4]
+    movq          m4, [dstq+strideq*2-4]
+    movq          m5, [dstq+stride3q -4]
+    lea         tmpq, [dstq+strideq*4]
+    movq          m3, [tmpq+strideq*0-4]
+    movq          m6, [tmpq+strideq*1-4]
+    movq          m1, [tmpq+strideq*2-4]
+    movq          m7, [tmpq+stride3q -4]
+
+    ; transpose 4x8
+    ; m0: A-D0
+    ; m2: A-D1
+    ; m4: A-D2
+    ; m5: A-D3
+    ; m3: A-D4
+    ; m6: A-D5
+    ; m1: A-D6
+    ; m7: A-D7
+    punpcklwd     m0, m2
+    punpcklwd     m4, m5
+    punpcklwd     m3, m6
+    punpcklwd     m1, m7
+    ; m0: A0-1,B0-1,C0-1,D0-1
+    ; m4: A2-3,B2-3,C2-3,D2-3
+    ; m3: A4-5,B4-5,C4-5,D4-5
+    ; m1: A6-7,B6-7,C6-7,D6-7
+    punpckhdq     m2, m0, m4
+    punpckldq     m0, m4
+    punpckhdq     m4, m3, m1
+    punpckldq     m3, m1
+    ; m0: A0-3,B0-3
+    ; m2: C0-3,D0-3
+    ; m3: A4-7,B4-7
+    ; m4: C4-7,D4-7
+    punpckhqdq    m1, m0, m3
+    punpcklqdq    m0, m3
+    punpckhqdq    m3, m2, m4
+    punpcklqdq    m2, m4
+    ; m0: A0-7
+    ; m1: B0-7
+    ; m2: C0-7
+    ; m3: D0-7
+%if ARCH_X86_64
+    SWAP           0, 8
+    SWAP           1, 9
+    SWAP           2, 10
+    SWAP           3, 11
+%define P1 m8
+%define P0 m9
+%define Q0 m10
+%define Q1 m11
+%else
+%define P1 [esp+3*mmsize]
+%define P0 [esp+4*mmsize]
+%define Q0 [esp+5*mmsize]
+%define Q1 [esp+6*mmsize]
+    mova          P1, m0
+    mova          P0, m1
+    mova          Q0, m2
+    mova          Q1, m3
+%endif
+%elif %1 == 6 || %1 == 8
+    movu          m0, [dstq+strideq*0-8]
+    movu          m1, [dstq+strideq*1-8]
+    movu          m2, [dstq+strideq*2-8]
+    movu          m3, [dstq+stride3q -8]
+    lea         tmpq, [dstq+strideq*4]
+    movu          m4, [tmpq+strideq*0-8]
+    movu          m5, [tmpq+strideq*1-8]
+    movu          m6, [tmpq+strideq*2-8]
+%if ARCH_X86_64
+    movu          m7, [tmpq+stride3q -8]
+%endif
+
+    ; transpose 8x16
+    ; m0: A-H0,A-H8
+    ; m1: A-H1,A-H9
+    ; m2: A-H2,A-H10
+    ; m3: A-H3,A-H11
+    ; m4: A-H4,A-H12
+    ; m5: A-H5,A-H13
+    ; m6: A-H6,A-H14
+    ; m7: A-H7,A-H15
+%if ARCH_X86_64
+    punpcklwd     m8, m0, m1
+%else
+    punpcklwd     m7, m0, m1
+%endif
+    punpckhwd     m0, m1
+    punpcklwd     m1, m2, m3
+    punpckhwd     m2, m3
+    punpcklwd     m3, m4, m5
+    punpckhwd     m4, m5
+%if ARCH_X86_64
+    punpcklwd     m5, m6, m7
+    punpckhwd     m6, m7
+%else
+    mova  [rsp+3*16], m4
+    movu          m4, [tmpq+stride3q -8]
+    punpcklwd     m5, m6, m4
+    punpckhwd     m6, m4
+%endif
+    ; m8: A0-1,B0-1,C0-1,D0-1 [m7 on x86-32]
+    ; m0: E0-1,F0-1,G0-1,H0-1
+    ; m1: A2-3,B2-3,C2-3,D2-3
+    ; m2: E2-3,F2-3,G2-3,H2-3
+    ; m3: A4-5,B4-5,C4-5,D4-5
+    ; m4: E4-5,F4-5,G4-5,H4-5 [r3 on x86-32]
+    ; m5: A6-7,B6-7,C6-7,D6-7
+    ; m6: E6-7,F6-7,G6-7,H6-7
+%if ARCH_X86_64
+    punpckldq     m7, m8, m1
+    punpckhdq     m8, m1
+%else
+    punpckldq     m4, m7, m1
+    punpckhdq     m7, m1
+%endif
+    punpckldq     m1, m0, m2
+    punpckhdq     m0, m2
+    punpckldq     m2, m3, m5
+    punpckhdq     m3, m5
+%if ARCH_X86_64
+    punpckldq     m5, m4, m6
+    punpckhdq     m4, m6
+%else
+    mova  [rsp+4*16], m3
+    mova          m3, [rsp+3*16]
+    punpckldq     m5, m3, m6
+    punpckhdq     m3, m6
+%endif
+    ; m7: A0-3,B0-3 [m4 on x86-32]
+    ; m8: C0-3,D0-3 [m7 on x86-32]
+    ; m1: E0-3,F0-3
+    ; m0: G0-3,H0-3
+    ; m2: A4-7,B4-7
+    ; m3: C4-7,D4-7 [r4 on x86-32]
+    ; m5: E4-7,F4-7
+    ; m4: G4-7,H4-7 [m3 on x86-32]
+%if ARCH_X86_64
+%if %1 != 6
+    punpcklqdq    m6, m7, m2
+%endif
+    punpckhqdq    m7, m2
+    punpcklqdq    m2, m8, m3
+    punpckhqdq    m8, m3
+    punpcklqdq    m3, m1, m5
+    punpckhqdq    m1, m5
+%if %1 != 6
+    punpckhqdq    m5, m0, m4
+%endif
+    punpcklqdq    m0, m4
+%if %1 == 8
+    mova  [rsp+1*16], m6
+%define P3 [rsp+1*16]
+%endif
+    ; 7,2,8,3,1,0,5 -> 13,8,9,10,11,14,15
+    SWAP           7, 13
+    SWAP           8, 2, 9
+    SWAP           3, 10
+    SWAP           1, 11
+    SWAP           0, 14
+    SWAP           5, 15
+%define P2 m13
+%define P1 m8
+%define P0 m9
+%define Q0 m10
+%define Q1 m11
+%define Q2 m14
+%if %1 == 8
+%define Q3 m15
+%endif
+%else ; x86-32
+%if %1 == 8
+%define P3 [rsp+ 6*16]
+    punpcklqdq    m6, m4, m2
+    mova          P3, m6
+%endif
+    mova          m6, [rsp+4*16]
+    punpckhqdq    m4, m2
+    punpcklqdq    m2, m7, m6
+    punpckhqdq    m7, m6
+    punpcklqdq    m6, m1, m5
+    punpckhqdq    m1, m5
+%if %1 == 8
+%define Q3 [rsp+24*16]
+    punpckhqdq    m5, m0, m3
+    mova          Q3, m5
+%endif
+    punpcklqdq    m0, m3
+%if %1 == 8
+%define P2 [rsp+18*16]
+%define P1 [rsp+19*16]
+%define P0 [rsp+20*16]
+%define Q0 [rsp+21*16]
+%define Q1 [rsp+22*16]
+%define Q2 [rsp+23*16]
+%else
+%define P2 [rsp+3*16]
+%define P1 [rsp+4*16]
+%define P0 [rsp+5*16]
+%define Q0 [rsp+6*16]
+%define Q1 [rsp+7*16]
+%define Q2 [rsp+8*16]
+%endif
+    mova          P2, m4
+    mova          P1, m2
+    mova          P0, m7
+    mova          Q0, m6
+    mova          Q1, m1
+    mova          Q2, m0
+%endif ; x86-32/64
+%else ; %1 == 16
+    ; We only use 14 pixels but we'll need the remainder at the end for
+    ; the second transpose
+    mova          m0, [dstq+strideq*0-16]
+    mova          m1, [dstq+strideq*1-16]
+    mova          m2, [dstq+strideq*2-16]
+    mova          m3, [dstq+stride3q -16]
+    lea         tmpq, [dstq+strideq*4]
+    mova          m4, [tmpq+strideq*0-16]
+    mova          m5, [tmpq+strideq*1-16]
+    mova          m6, [tmpq+strideq*2-16]
+%if ARCH_X86_64
+    mova          m7, [tmpq+stride3q -16]
+
+    TRANSPOSE8X8W 0, 1, 2, 3, 4, 5, 6, 7, 8
+    SWAP           5, 13
+    SWAP           6, 8
+    SWAP           7, 9
+%define P2 m13
+%define P1 m8
+%define P0 m9
+%else ; x86-32
+%define P2 [esp+18*16]
+%define P1 [esp+19*16]
+%define P0 [esp+20*16]
+    TRANSPOSE8X8W 0, 1, 2, 3, 4, 5, 6, 7, \
+                     [tmpq+stride3q -16], P2, "", a, a
+    mova          P1, m6
+    mova          P0, m7
+%endif ; x86-32/64
+    mova [rsp+ 7*16], m0
+    mova [rsp+ 8*16], m1
+    mova [rsp+ 9*16], m2
+    mova [rsp+10*16], m3
+%define P3 [rsp+6*16]
+    mova          P3, m4
+
+    mova          m0, [dstq+strideq*0]
+    mova          m1, [dstq+strideq*1]
+    mova          m2, [dstq+strideq*2]
+    mova          m3, [dstq+stride3q ]
+    lea         tmpq, [dstq+strideq*4]
+    mova          m4, [tmpq+strideq*0]
+    mova          m5, [tmpq+strideq*1]
+    mova          m6, [tmpq+strideq*2]
+%if ARCH_X86_64
+    mova          m7, [tmpq+stride3q ]
+
+    TRANSPOSE8X8W 0, 1, 2, 3, 4, 5, 6, 7, 10
+    SWAP          0, 10
+    SWAP          1, 11
+    SWAP          2, 14
+    SWAP          3, 15
+%define Q0 m10
+%define Q1 m11
+%define Q2 m14
+%define Q3 m15
+%else ; x86-32
+    TRANSPOSE8X8W 0, 1, 2, 3, 4, 5, 6, 7, \
+                     [tmpq+stride3q ], [rsp+12*16], "", a, a
+%define Q0 [esp+21*16]
+%define Q1 [esp+22*16]
+%define Q2 [esp+23*16]
+%define Q3 [esp+24*16]
+    mova         Q0, m0
+    mova         Q1, m1
+    mova         Q2, m2
+    mova         Q3, m3
+%endif ; x86-32/64
+
+    mova [rsp+11*16], m4
+%if ARCH_X86_64
+    mova [rsp+12*16], m5
+%endif
+    mova [rsp+13*16], m6
+    mova [rsp+14*16], m7
+%endif ; %1 == 4/6/8/16
+%endif ; %2 ==/!= v
+
+    ; load L/E/I/H
+%if ARCH_X86_32
+%define l_strideq r5
+    mov    l_strideq, dword lstridem
+%ifidn %2, v
+%define lq r3
+    mov           lq, dword lm
+%endif
+%endif
+%ifidn %2, v
+%if cpuflag(sse4)
+    pmovzxbw      m1, [lq]
+    pmovzxbw      m0, [lq+l_strideq]
+    pxor          m2, m2
+%else ; ssse3
+    movq          m1, [lq]
+    movq          m0, [lq+l_strideq]
+    pxor          m2, m2
+    REPX {punpcklbw x, m2}, m1, m0
+%endif ; ssse3/sse4
+%else ; %2 != v
+    movq          m0, [lq]                      ; l0, l1
+    movq          m1, [lq+l_strideq]            ; l2, l3
+    punpckldq     m0, m1                        ; l0, l2, l1, l3
+    pxor          m2, m2
+    punpcklbw     m1, m0, m2                    ; l0, l2
+    punpckhbw     m0, m2                        ; l1, l3
+%endif ; %2==/!=v
+%if ARCH_X86_32
+%ifidn %2, v
+%undef lq
+    mov     mstrideq, mstridem
+%endif
+%endif
+    pcmpeqw       m5, m2, m0
+    pand          m1, m5
+    por           m0, m1                        ; l[x][] ? l[x][] : l[x-stride][]
+    pshufb        m0, [PIC_sym(pb_4x1_4x5_4x9_4x13)] ; l[x][1]
+    pcmpeqw       m5, m2, m0                    ; !L
+    psrlw         m5, 1
+%if ARCH_X86_64
+    psrlw         m2, m0, [lutq+128]
+    SPLATW        m1, [lutq+136]
+%else ; x86-32
+    mov           r5, lutm
+    psrlw         m2, m0, [r5+128]
+    SPLATW        m1, [r5+136]
+%endif ; x86-32/64
+    pminsw        m2, m1
+    pmaxsw        m2, [PIC_sym(pw_1)]           ; I
+    psrlw         m1, m0, 4                     ; H
+    paddw         m0, [PIC_sym(pw_2)]
+    paddw         m0, m0
+    paddw         m0, m2                        ; E
+    REPX {pmullw x, [bdmulq]}, m0, m1, m2
+%if ARCH_X86_32
+%undef l_strideq
+    lea    stride3q, [strideq*3]
+%endif
+
+    psubw         m3, P1, P0                    ; p1-p0
+    psubw         m4, Q0, Q1                    ; q0-q1
+    REPX {pabsw x, x}, m3, m4
+    pmaxsw        m3, m5
+    pmaxsw        m3, m4
+    pcmpgtw       m7, m3, m1                    ; hev
+%if %1 != 4
+    psubw         m4, P2, P0                    ; p2-p0
+    pabsw         m4, m4
+    pmaxsw        m4, m3
+%if %1 != 6
+    mova          m6, P3                        ; p3
+    psubw         m5, m6, P0                    ; p3-p0
+    pabsw         m5, m5
+    pmaxsw        m4, m5
+%endif ; %1 != 6
+    psubw         m5, Q0, Q2                    ; q0-q2
+    pabsw         m5, m5
+    pmaxsw        m4, m5
+%if %1 != 6
+    psubw         m5, Q0, Q3                    ; q0-q3
+    pabsw         m5, m5
+    pmaxsw        m4, m5
+%endif ; %1 != 6
+    pcmpgtw       m4, [bdmulq]                     ; !flat8in
+
+    psubw         m5, P2, P1                    ; p2-p1
+    pabsw         m5, m5
+%if %1 != 6
+    psubw         m6, P2                        ; p3-p2
+    pabsw         m6, m6
+    pmaxsw        m5, m6
+    psubw         m6, Q2, Q3                    ; q2-q3
+    pabsw         m6, m6
+    pmaxsw        m5, m6
+%endif ; %1 != 6
+    psubw         m6, Q2, Q1                    ; q2-q1
+    pabsw         m6, m6
+    pmaxsw        m5, m6
+
+%if %1 == 16
+    SPLATD        m6, [maskq+8]
+    SPLATD        m1, [maskq+4]
+    por           m6, m1
+    pand          m6, m12
+    pcmpeqd       m6, m12
+    pand          m5, m6
+%else ; %1 != 16
+    SPLATD        m6, [maskq+4]
+    pand          m6, m12
+    pcmpeqd       m6, m12
+    pand          m5, m6                        ; only apply fm-wide to wd>4 blocks
+%endif ; %1==/!=16
+    pmaxsw        m3, m5
+%endif ; %1 != 4
+    pcmpgtw       m3, m2
+
+    psubw         m5, P1, Q1                    ; p1-q1
+    psubw         m6, P0, Q0                    ; p0-q0
+    REPX {pabsw x, x}, m5, m6
+    paddw         m6, m6
+    psrlw         m5, 1
+    paddw         m5, m6                        ; abs(p0-q0)*2+(abs(p1-q1)>>1)
+    pcmpgtw       m5, m0                        ; abs(p0-q0)*2+(abs(p1-q1)>>1) > E
+    por           m3, m5
+
+%if %1 == 16
+
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*8]
+    mova          m0, [tmpq+strideq*1]
+    mova          m1, [tmpq+strideq*2]
+    mova          m2, [tmpq+stride3q]
+%else ; %2 != v
+    mova          m0, [rsp+ 8*16]
+    mova          m1, [rsp+ 9*16]
+    mova          m2, [rsp+10*16]
+%endif ; %2==/!=v
+    REPX {psubw x, P0}, m0, m1, m2
+    REPX {pabsw x, x}, m0, m1, m2
+    pmaxsw        m1, m0
+    pmaxsw        m1, m2
+%ifidn %2, v
+    lea         tmpq, [dstq+strideq*4]
+    mova          m0, [tmpq+strideq*0]
+    mova          m2, [tmpq+strideq*1]
+    mova          m5, [tmpq+strideq*2]
+%else ; %2 != v
+    mova          m0, [rsp+11*16]
+    mova          m2, [rsp+12*16]
+    mova          m5, [rsp+13*16]
+%endif ; %2==/!=v
+    REPX {psubw x, Q0}, m0, m2, m5
+    REPX {pabsw x, x}, m0, m2, m5
+    pmaxsw        m0, m2
+    pmaxsw        m1, m5
+    pmaxsw        m1, m0
+    pcmpgtw       m1, [bdmulq]                  ; !flat8out
+    por           m1, m4                        ; !flat8in | !flat8out
+    SPLATD        m2, [maskq+8]
+    pand          m5, m2, m12
+    pcmpeqd       m5, m12
+    pandn         m1, m5                        ; flat16
+    pandn         m5, m3, m1                    ; flat16 & fm
+    SWAP           1, 5
+
+    SPLATD        m5, [maskq+4]
+    por           m5, m2
+    pand          m2, m5, m12
+    pcmpeqd       m2, m12
+    pandn         m4, m2                        ; flat8in
+    pandn         m2, m3, m4
+    SWAP           2, 4
+    SPLATD        m2, [maskq+0]
+    por           m2, m5
+    pand          m2, m12
+    pcmpeqd       m2, m12
+    pandn         m3, m2
+    pandn         m0, m4, m3                    ; fm & !flat8 & !flat16
+    SWAP           0, 3
+    pandn         m0, m1, m4                    ; flat8 & !flat16
+    SWAP           0, 4
+%elif %1 != 4
+    SPLATD        m0, [maskq+4]
+    pand          m2, m0, m12
+    pcmpeqd       m2, m12
+    pandn         m4, m2
+    pandn         m2, m3, m4                    ; flat8 & fm
+    SWAP           2, 4
+    SPLATD        m2, [maskq+0]
+    por           m0, m2
+    pand          m0, m12
+    pcmpeqd       m0, m12
+    pandn         m3, m0
+    pandn         m0, m4, m3                    ; fm & !flat8
+    SWAP           0, 3
+%else ; %1 == 4
+    SPLATD        m0, [maskq+0]
+    pand          m0, m12
+    pcmpeqd       m0, m12
+    pandn         m3, m0                        ; fm
+%endif ; %1==/!=4
+
+    ; short filter
+%if ARCH_X86_64
+    SPLATW        m0, r7m
+%else
+    SPLATW        m0, bdmulm
+%endif
+    pcmpeqw       m2, m2
+    psrlw         m0, 1                         ; 511 or 2047
+    pxor          m2, m0                        ; -512 or -2048
+
+    psubw         m5, Q0, P0                    ; q0-p0
+    paddw         m6, m5, m5
+    paddw         m6, m5                        ; 3*(q0-p0)
+    psubw         m5, P1, Q1                    ; iclip_diff(p1-q1)
+    pminsw        m5, m0
+    pmaxsw        m5, m2
+    pand          m5, m7                        ; f=iclip_diff(p1-q1)&hev
+    paddw         m5, m6                        ; f=iclip_diff(3*(q0-p0)+f)
+    pminsw        m5, m0
+    pmaxsw        m5, m2
+    pand          m3, m5                        ; f&=fm
+    paddw         m5, m3, [PIC_sym(pw_3)]
+    paddw         m3, [PIC_sym(pw_4)]
+    REPX {pminsw x, m0}, m5, m3
+    psraw         m5, 3                         ; f2
+    psraw         m3, 3                         ; f1
+    psubw         m0, m2                        ; 1023 or 4095
+    pxor          m2, m2
+%if ARCH_X86_64
+    paddw         P0, m5
+    psubw         Q0, m3
+%else
+    paddw          m5, P0
+    psubw          m6, Q0, m3
+    REPX {pminsw x, m0}, m5, m6
+    REPX {pmaxsw x, m2}, m5, m6
+%endif
+
+    paddw         m3, [PIC_sym(pw_1)]
+    psraw         m3, 1                         ; f=(f1+1)>>1
+    pandn         m7, m3                        ; f&=!hev
+    SWAP           7, 3
+%if ARCH_X86_64
+    paddw         P1, m3
+    psubw         Q1, m3
+    REPX {pminsw x, m0}, P1, P0, Q0, Q1
+    REPX {pmaxsw x, m2}, P1, P0, Q0, Q1
+%else
+    psubw         m7, Q1, m3
+    paddw         m3, P1
+    REPX {pminsw x, m0}, m7, m3
+    REPX {pmaxsw x, m2}, m7, m3
+%if %1 > 4
+    mova          P1, m3
+    mova          P0, m5
+    mova          Q0, m6
+    mova          Q1, m7
+%endif
+%endif
+
+%if %1 == 16
+
+; m8-11 = p1/p0/q0/q1, m4=flat8, m1=flat16
+; m12=filter bits mask
+; m13-15=p2/q2/q3
+; m0,2-3,5-7 = free
+
+    ; flat16 filter
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*8]
+    mova          m0, [tmpq+strideq*1]          ; p6
+    mova          m2, [tmpq+strideq*2]          ; p5
+    mova          m7, [tmpq+stride3q]           ; p4
+    mova          m6, [tmpq+strideq*4]          ; p3
+    lea         tmpq, [dstq+mstrideq*4]
+%else ; %2 != v
+    mova          m0, [rsp+ 8*16]
+    mova          m2, [rsp+ 9*16]
+    mova          m7, [rsp+10*16]
+    mova          m6, [rsp+ 6*16]
+%endif ; %2==/!=v
+
+    mova [rsp+ 0*16], m4
+
+    ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0
+    psllw         m3, m0, 3                     ; p6*8
+    paddw         m3, [PIC_sym(pw_8)]
+    paddw         m5, m2, m7                    ; p5+p4
+    psubw         m3, m0
+    paddw         m5, m5                        ; (p5+p4)*2
+    paddw         m3, m6                        ; p6*7+p3
+    paddw         m5, P2                        ; (p5+p4)*2+p2
+    paddw         m3, P1                        ; p6*7+p3+p1
+    paddw         m5, P0                        ; (p5+p4)*2+p2+p0
+    paddw         m3, Q0                        ; p6*7+p3+p1+q0
+    paddw         m3, m5                        ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0
+    psrlw         m5, m3, 4
+    pand          m5, m1
+    pandn         m4, m1, m2
+    por           m5, m4
+%ifidn %2, v
+    mova [tmpq+mstrideq*2], m5                   ; p5
+%else ; %2 != v
+    mova  [rsp+9*16], m5
+%endif ; %2==/!=v
+
+    ; sub p6*2, add p3/q1
+    paddw         m3, m6
+    paddw         m5, m0, m0
+    paddw         m3, Q1
+    psubw         m3, m5
+    psrlw         m5, m3, 4
+    pand          m5, m1
+    pandn         m4, m1, m7
+    por           m5, m4
+%ifidn %2, v
+    mova [tmpq+mstrideq*1], m5                   ; p4
+%else ; %2 != v
+    mova [rsp+10*16], m5
+%endif ; %2==/!=v
+
+    ; sub p6/p5, add p2/q2
+    psubw         m3, m0
+    paddw         m5, P2, Q2
+    psubw         m3, m2
+    paddw         m3, m5
+    psrlw         m5, m3, 4
+    pand          m5, m1
+    pandn         m4, m1, m6
+    por           m5, m4
+%ifidn %2, v
+    mova [tmpq+strideq*0], m5                  ; p3
+%else ; %2 != v
+    mova  [rsp+6*16], m5
+%endif ; %2==/!=v
+
+%define WRITE_IN_PLACE 0
+%ifidn %2, v
+%if ARCH_X86_64
+%define WRITE_IN_PLACE 1
+%endif
+%endif
+
+    ; sub p6/p4, add p1/q3
+    paddw         m3, P1
+    paddw         m5, m0, m7
+    paddw         m3, Q3
+    psubw         m3, m5
+    psrlw         m5, m3, 4
+    pand          m5, m1
+    pandn         m4, m1, P2
+    por           m5, m4
+%if WRITE_IN_PLACE
+    mova [tmpq+strideq*1], m5
+%else
+    mova  [rsp+1*16], m5                        ; don't clobber p2/m13
+%endif
+
+    ; sub p6/p3, add p0/q4
+    paddw         m3, P0
+    paddw         m5, m0, m6
+%ifidn %2, v
+    paddw         m3, [dstq+strideq*4]
+%else ; %2 != v
+    paddw         m3, [rsp+11*16]
+%endif ; %2==/!=v
+    psubw         m3, m5
+    psrlw         m5, m3, 4
+    pand          m5, m1
+    pandn         m4, m1, P1
+    por           m5, m4
+%if WRITE_IN_PLACE
+    mova [dstq+mstrideq*2], m5
+%else
+    mova  [rsp+2*16], m5                        ; don't clobber p1/m3
+%endif
+
+    ; sub p6/p2, add q0/q5
+    paddw         m3, Q0
+    paddw         m5, m0, P2
+%ifidn %2, v
+%if ARCH_X86_32
+    lea           r4, P2
+%endif
+    lea         tmpq, [dstq+strideq*4]
+    paddw         m3, [tmpq+strideq*1]
+%else ; %2 != v
+    paddw         m3, [rsp+12*16]
+%endif ; %2==/!=v
+    psubw         m3, m5
+    psrlw         m5, m3, 4
+    pand          m5, m1
+    pandn         m4, m1, P0
+    por           m5, m4
+%if WRITE_IN_PLACE
+    mova [dstq+mstrideq*1], m5
+%else
+    mova  [rsp+3*16], m5                        ; don't clobber p0/m4
+%endif
+
+    ; sub p6/p1, add q1/q6
+    paddw         m3, Q1
+    paddw         m5, m0, P1
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*2]          ; q6
+%else ; %2 != v
+    mova          m0, [rsp+13*16]               ; q6
+%endif ; %2==/!=v
+    paddw         m3, m0
+    psubw         m3, m5
+    psrlw         m5, m3, 4
+    pand          m5, m1
+    pandn         m4, m1, Q0
+    por           m5, m4
+%if WRITE_IN_PLACE
+    mova      [dstq], m5
+%else
+    mova  [rsp+4*16], m5                        ; don't clobber q0/m5
+%endif
+
+    ; sub p5/p0, add q2/q6
+    paddw         m3, Q2
+    paddw         m5, m2, P0
+    paddw         m3, m0
+    psubw         m3, m5
+    psrlw         m5, m3, 4
+    pand          m5, m1
+    pandn         m4, m1, Q1
+    por           m2, m5, m4                    ; don't clobber q1/m6
+
+    ; sub p4/q0, add q3/q6
+    paddw         m3, Q3
+    paddw         m7, Q0
+    paddw         m3, m0
+    psubw         m3, m7
+    psrlw         m7, m3, 4
+    pand          m7, m1
+    pandn         m4, m1, Q2
+    por           m7, m4                        ; don't clobber q2/m14
+
+    ; sub p3/q1, add q4/q6
+%ifidn %2, v
+    paddw         m3, [tmpq+strideq*0]
+%else ; %2 != v
+    paddw         m3, [rsp+11*16]
+%endif ; %2==/!=v
+    paddw         m6, Q1
+    paddw         m3, m0
+    psubw         m3, m6
+    psrlw         m6, m3, 4
+    pand          m6, m1
+    pandn         m4, m1, Q3
+    por           m6, m4
+%if WRITE_IN_PLACE
+    mova [tmpq+mstrideq], m6                    ; q3
+%else ; %2 != v
+    mova  [rsp+5*16], m6
+%endif ; %2==/!=v
+
+    ; sub p2/q2, add q5/q6
+%ifidn %2, v
+    paddw         m3, [tmpq+strideq*1]
+%if ARCH_X86_64
+    paddw         m5, P2, Q2
+%else
+    ; because tmpq is clobbered, so we use a backup pointer for P2 instead
+    paddw         m5, [r4], Q2
+    mov     pic_regq, pic_regm
+%endif
+%else ; %2 != v
+    paddw         m3, [rsp+12*16]
+    paddw         m5, P2, Q2
+%endif ; %2==/!=v
+    paddw         m3, m0
+    psubw         m3, m5
+    psrlw         m5, m3, 4
+    pand          m5, m1
+%ifidn %2, v
+    pandn         m4, m1, [tmpq+strideq*0]
+%else ; %2 != v
+    pandn         m4, m1, [rsp+11*16]
+%endif ; %2==/!=v
+    por           m5, m4
+%ifidn %2, v
+    mova [tmpq+strideq*0], m5                   ; q4
+%else ; %2 != v
+    mova [rsp+11*16], m5
+%endif ; %2==/!=v
+
+    ; sub p1/q3, add q6*2
+    psubw         m3, P1
+    paddw         m0, m0
+    psubw         m3, Q3
+    paddw         m3, m0
+    psrlw         m5, m3, 4
+    pand          m5, m1
+%ifidn %2, v
+    pandn         m4, m1, [tmpq+strideq*1]
+%else ; %2 != v
+    pandn         m4, m1, [rsp+12*16]
+%endif ; %2==/!=v
+    por           m5, m4
+%ifidn %2, v
+    mova [tmpq+strideq*1], m5                   ; q5
+%else ; %2 != v
+    mova [rsp+12*16], m5
+%endif ; %2==/!=v
+
+    mova          m4, [rsp+0*16]
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*4]
+%endif
+%if ARCH_X86_64
+    SWAP           2, 11
+    SWAP           7, 14
+    SWAP           6, 15
+%else ; x86-32
+    mova          Q1, m2
+    mova          Q2, m7
+%endif ; x86-32/64
+%if WRITE_IN_PLACE
+    mova          P2, [tmpq+strideq*1]
+    mova          P1, [tmpq+strideq*2]
+    mova          P0, [tmpq+stride3q]
+    mova          Q0, [dstq]
+%elif ARCH_X86_64
+    mova          P2, [rsp+1*16]
+    mova          P1, [rsp+2*16]
+    mova          P0, [rsp+3*16]
+    mova          Q0, [rsp+4*16]
+%else ; !WRITE_IN_PLACE & x86-32
+    mova          m0, [rsp+1*16]
+    mova          m1, [rsp+2*16]
+    mova          m2, [rsp+3*16]
+    mova          m3, [rsp+4*16]
+    mova          m7, [rsp+5*16]
+    mova          P2, m0
+    mova          P1, m1
+    mova          P0, m2
+    mova          Q0, m3
+    mova          Q3, m7
+%endif ; WRITE_IN_PLACE / x86-32/64
+%undef WRITE_IN_PLACE
+%endif ; %1 == 16
+
+%if %1 >= 8
+
+    ; flat8 filter
+    mova          m0, P3                        ; p3
+    paddw         m1, m0, P2                    ; p3+p2
+    paddw         m2, P1, P0                    ; p1+p0
+    paddw         m3, m1, m1                    ; 2*(p3+p2)
+    paddw         m2, m0                        ; p1+p0+p3
+    paddw         m3, Q0                        ; 2*(p3+p2)+q0
+    paddw         m2, m3                        ; 3*p3+2*p2+p1+p0+q0
+    pmulhrsw      m7, m2, [PIC_sym(pw_4096)]
+    psubw         m7, P2
+    pand          m7, m4
+
+    paddw         m3, P1, Q1                    ; p1+q1
+    psubw         m2, m1                        ; 2*p3+p2+p1+p0+q0
+    paddw         m2, m3                        ; 2*p3+p2+2*p1+p0+q0+q1
+    pmulhrsw      m3, m2, [PIC_sym(pw_4096)]
+    psubw         m3, P1
+    pand          m3, m4
+
+    paddw         m5, m0, P1                    ; p3+p1
+    paddw         m6, P0, Q2                    ; p0+q2
+    psubw         m2, m5                        ; p3+p2+p1+p0+q0+q1
+    paddw         m2, m6                        ; p3+p2+p1+2*p0+q0+q1+q2
+    pmulhrsw      m5, m2, [PIC_sym(pw_4096)]
+    psubw         m5, P0
+    pand          m5, m4
+
+    paddw         m6, m0, P0                    ; p3+p0
+    paddw         m1, Q0, Q3                    ; q0+q3
+    psubw         m2, m6                        ; p2+p1+p0+q0+q1+q2
+    paddw         m2, m1                        ; p2+p1+p0+2*q0+q1+q2+q3
+    pmulhrsw      m6, m2, [PIC_sym(pw_4096)]
+    psubw         m6, Q0
+    pand          m6, m4
+
+    paddw         m2, Q1                        ; p2+p1+p0+2*q0+2*q1+q2+q3
+    paddw         m2, Q3                        ; p2+p1+p0+2*q0+2*q1+q2+2*q3
+    paddw         m1, P2, Q0                    ; p2+q0
+    psubw         m2, m1                        ; p1+p0+q0+2*q1+q2+2*q3
+    pmulhrsw      m1, m2, [PIC_sym(pw_4096)]
+    psubw         m1, Q1
+    pand          m1, m4
+
+    psubw         m2, P1                        ; p0+q0+2*q1+q2+2*q3
+    psubw         m2, Q1                        ; p0+q0+q1+q2+2*q3
+    paddw         m0, Q3, Q2                    ; q3+q2
+    paddw         m2, m0                        ; p0+q0+q1+2*q2+3*q3
+    pmulhrsw      m2, [PIC_sym(pw_4096)]
+    psubw         m2, Q2
+    pand          m2, m4
+
+    paddw         m7, P2
+    paddw         m3, P1
+    paddw         m5, P0
+    paddw         m6, Q0
+    paddw         m1, Q1
+    paddw         m2, Q2
+
+%ifidn %2, v
+    mova [tmpq+strideq*1], m7                   ; p2
+    mova [tmpq+strideq*2], m3                   ; p1
+    mova [tmpq+stride3q ], m5                   ; p0
+    mova [dstq+strideq*0], m6                   ; q0
+    mova [dstq+strideq*1], m1                   ; q1
+    mova [dstq+strideq*2], m2                   ; q2
+%else ; %2 != v
+    mova          m0, P3
+
+%if %1 == 8
+    lea         tmpq, [dstq+strideq*4]
+%if ARCH_X86_64
+    SWAP           4, 15
+    TRANSPOSE8X8W  0, 7, 3, 5, 6, 1, 2, 4, 8
+%else
+    TRANSPOSE8X8W  0, 7, 3, 5, 6, 1, 2, 4, "", \
+                      Q3, [tmpq+strideq*1-8], a, u
+%endif
+
+    ; write 8x8
+    movu   [dstq+strideq*0-8], m0
+    movu   [dstq+strideq*1-8], m7
+    movu   [dstq+strideq*2-8], m3
+    movu   [dstq+stride3q -8], m5
+    movu   [tmpq+strideq*0-8], m6
+%if ARCH_X86_64
+    movu   [tmpq+strideq*1-8], m1
+%endif
+    movu   [tmpq+strideq*2-8], m2
+    movu   [tmpq+stride3q -8], m4
+    lea         dstq, [dstq+strideq*8]
+%else ; %1 != 8
+%if ARCH_X86_64
+    SWAP           6, 8
+    SWAP           1, 9
+    SWAP           2, 10
+%else
+    mova  [rsp+1*16], m6
+    mova  [rsp+2*16], m1
+    mova  [rsp+3*16], m2
+%endif
+
+    mova          m1, [rsp+ 7*16]
+    mova          m2, [rsp+ 8*16]
+    mova          m4, [rsp+ 9*16]
+    mova          m6, [rsp+10*16]
+    lea         tmpq, [dstq+strideq*4]
+%if ARCH_X86_64
+    TRANSPOSE8X8W  1, 2, 4, 6, 0, 7, 3, 5, 11
+%else
+    mova  [rsp+7*16],  m5
+    TRANSPOSE8X8W  1, 2, 4, 6, 0, 7, 3, 5, "", \
+                      [rsp+7*16], [tmpq+strideq*1-16], a, a
+%endif
+
+    mova [dstq+strideq*0-16], m1
+    mova [dstq+strideq*1-16], m2
+    mova [dstq+strideq*2-16], m4
+    mova [dstq+stride3q -16], m6
+    mova [tmpq+strideq*0-16], m0
+%if ARCH_X86_64
+    mova [tmpq+strideq*1-16], m7
+%endif
+    mova [tmpq+strideq*2-16], m3
+    mova [tmpq+stride3q -16], m5
+
+%if ARCH_X86_64
+    SWAP           6, 8
+    SWAP           1, 9
+    SWAP           2, 10
+    SWAP           4, 15
+%else
+    mova          m6, [rsp+1*16]
+    mova          m1, [rsp+2*16]
+    mova          m2, [rsp+3*16]
+    mova          m4, Q3
+%endif
+    mova          m0, [rsp+11*16]
+    mova          m3, [rsp+12*16]
+    mova          m5, [rsp+13*16]
+%if ARCH_X86_64
+    mova          m7, [rsp+14*16]
+    TRANSPOSE8X8W  6, 1, 2, 4, 0, 3, 5, 7, 8
+%else
+    TRANSPOSE8X8W  6, 1, 2, 4, 0, 3, 5, 7, "", \
+                      [rsp+14*16], [tmpq+strideq*1], a, a
+%endif
+    mova [dstq+strideq*0], m6
+    mova [dstq+strideq*1], m1
+    mova [dstq+strideq*2], m2
+    mova [dstq+stride3q ], m4
+    mova [tmpq+strideq*0], m0
+%if ARCH_X86_64
+    mova [tmpq+strideq*1], m3
+%endif
+    mova [tmpq+strideq*2], m5
+    mova [tmpq+stride3q ], m7
+    lea         dstq, [dstq+strideq*8]
+%endif ; %1==/!=8
+%endif ; %2==/!=v
+%elif %1 == 6
+    ; flat6 filter
+    paddw         m3, P1, P0                    ; p1+p0
+    paddw         m3, P2                        ; p2+p1+p0
+    paddw         m6, P2, Q0                    ; p2+q0
+    paddw         m3, m3                        ; 2*(p2+p1+p0)
+    paddw         m3, m6                        ; p2+2*(p2+p1+p0)+q0
+    pmulhrsw      m2, m3, [PIC_sym(pw_4096)]
+    psubw         m2, P1
+    pand          m2, m4
+
+    paddw         m3, Q0                        ; p2+2*(p2+p1+p0+q0)
+    paddw         m6, P2, P2                    ; 2*p2
+    paddw         m3, Q1                        ; p2+2*(p2+p1+p0+q0)+q1
+    psubw         m3, m6                        ; p2+2*(p1+p0+q0)+q1
+    pmulhrsw      m5, m3, [PIC_sym(pw_4096)]
+    psubw         m5, P0
+    pand          m5, m4
+
+    paddw         m3, Q1                        ; p2+2*(p1+p0+q0+q1)
+    paddw         m6, P2, P1                    ; p2+p1
+    paddw         m3, Q2                        ; p2+2*(p1+p0+q0+q1)+q2
+    psubw         m3, m6                        ; p1+2*(p0+q0+q1)+q2
+    pmulhrsw      m6, m3, [PIC_sym(pw_4096)]
+    psubw         m6, Q0
+    pand          m6, m4
+
+    psubw         m3, P1                        ; 2*(p0+q0+q1)+q2
+%if ARCH_X86_64
+    paddw         Q2, Q2                        ; q2*2
+%else
+    mova          m0, Q2
+    paddw         m0, m0
+%endif
+    psubw         m3, P0                        ; p0+2*(q0+q1)+q2
+%if ARCH_X86_64
+    paddw         m3, Q2                        ; p0+q*(q0+q1+q2)+q2
+%else
+    paddw         m3, m0
+%endif
+    pmulhrsw      m3, [PIC_sym(pw_4096)]
+    psubw         m3, Q1
+    pand          m3, m4
+
+    paddw         m2, P1
+    paddw         m5, P0
+    paddw         m6, Q0
+    paddw         m3, Q1
+
+%ifidn %2, v
+    mova [dstq+mstrideq*2], m2                   ; p1
+    mova [dstq+mstrideq*1], m5                   ; p0
+    mova [dstq+strideq*0], m6                   ; q0
+    mova [dstq+strideq*1], m3                   ; q1
+%else ; %2 != v
+    TRANSPOSE_8x4_AND_WRITE_4x8 m2, m5, m6, m3, m0
+%endif ; %2==/!=v
+%else ; %1 == 4
+%if ARCH_X86_64
+%ifidn %2, v
+    mova [dstq+mstrideq*2], P1                   ; p1
+    mova [dstq+mstrideq*1], P0                   ; p0
+    mova [dstq+strideq*0], Q0                   ; q0
+    mova [dstq+strideq*1], Q1                   ; q1
+%else ; %2 != v
+    TRANSPOSE_8x4_AND_WRITE_4x8 P1, P0, Q0, Q1, m0
+%endif ; %2==/!=v
+%else ; x86-32
+%ifidn %2, v
+    mova [dstq+mstrideq*2], m3
+    mova [dstq+mstrideq*1], m5
+    mova [dstq+strideq*0], m6
+    mova [dstq+strideq*1], m7
+%else ; %2 != v
+    TRANSPOSE_8x4_AND_WRITE_4x8 m3, m5, m6, m7, m0
+%endif ; %2==/!=v
+%endif ; x86-32/64
+%endif ; %1
+%undef P3
+%undef P2
+%undef P1
+%undef P0
+%undef Q0
+%undef Q1
+%undef Q2
+%undef Q3
+%endmacro
+
+INIT_XMM ssse3
+; stack layout:
+; r0 - flat8 backup inside flat16 code
+%if ARCH_X86_64
+cglobal lpf_v_sb_y_16bpc, 6, 12, 16, -16 * 1, \
+                          dst, stride, mask, l, l_stride, lut, \
+                          w, stride3, mstride, tmp, mask_bits, bdmul
+    mov          r6d, r7m
+    sar          r6d, 7
+    and          r6d, 16                      ; 0 for 10bpc, 16 for 12bpc
+    lea       bdmulq, [pw_4]
+    add       bdmulq, r6
+    mov           wd, wm
+    shl    l_strideq, 2
+    sub           lq, l_strideq
+%else
+; stack layout [32bit only]:
+; r1-4 - p2-q0 post-filter16
+; r5 - p3
+; r6 - q3 post-filter16
+; r7 - GPRs [mask_bitsm, mstridem]
+; r8 - m12/pb_mask
+; r9 - bdmulq
+cglobal lpf_v_sb_y_16bpc, 4, 7, 8, -16 * (10 + extra_stack), \
+                          dst, stride, mask, mstride, pic_reg, stride3, tmp
+    RELOC_ARGS     v, 10*16
+%if STACK_ALIGNMENT >= 16
+    mov          r5d, r7m
+%endif
+    sar          r5d, 7
+    and          r5d, 16                      ; 0 for 10bpc, 16 for 12bpc
+    LEA     pic_regq, PIC_base
+%define pic_regm dword [esp+7*16+2*gprsize]
+    mov     pic_regm, pic_regq
+    mova          m0, [PIC_sym(pw_4)+r5]
+%define bdmulq esp+9*16
+    mova    [bdmulq], m0
+    shl dword lstridem, 2
+    sub           r3, dword lstridem
+    mov     dword lm, r3
+%endif
+    mov     mstrideq, strideq
+    neg     mstrideq
+    lea     stride3q, [strideq*3]
+%if ARCH_X86_64
+    mov   mask_bitsd, 0x3
+    mova         m12, [pb_mask]
+%else
+%define mstridem dword [esp+7*16+1*gprsize]
+    mov     mstridem, mstrideq
+%define mask_bitsm dword [esp+7*16+0*gprsize]
+    mov   mask_bitsm, 0x3
+    mova          m0, [PIC_sym(pb_mask)]
+%define m12 [esp+8*16]
+    mova         m12, m0
+%endif
+
+.loop:
+%if ARCH_X86_64
+    test   [maskq+8], mask_bitsd              ; vmask[2]
+%else
+    mov          r6d, mask_bitsm
+    test   [maskq+8], r6d
+%endif
+    jz .no_flat16
+
+    FILTER        16, v
+    jmp .end
+
+.no_flat16:
+%if ARCH_X86_64
+    test   [maskq+4], mask_bitsd              ; vmask[1]
+%else
+    test   [maskq+4], r6d
+%endif
+    jz .no_flat
+
+    FILTER         8, v
+    jmp .end
+
+.no_flat:
+%if ARCH_X86_64
+    test   [maskq+0], mask_bitsd              ; vmask[0]
+%else
+    test   [maskq+0], r6d
+%endif
+    jz .end
+
+    FILTER         4, v
+
+.end:
+%if ARCH_X86_64
+    pslld        m12, 2
+    add           lq, 8
+%else
+    mova          m0, m12
+    pslld         m0, 2
+    mova         m12, m0
+    add     dword lm, 8
+%endif
+    add         dstq, 16
+%if ARCH_X86_64
+    shl   mask_bitsd, 2
+    sub           wd, 2
+%else
+    shl   mask_bitsm, 2
+    sub     dword wm, 2
+%endif
+    jg .loop
+%undef mask_bitsm
+%undef bdmulq
+    UNRELOC_ARGS
+    RET
+
+INIT_XMM ssse3
+; stack layout:
+; r0 - flat8 backup inside flat16
+; r1-4 - p2-q0 post-filter16 backup
+; r5 - q3 post-filter16 backup
+; r6 - p3
+; r7-10 - p7-4
+; r11-14 - q4-7
+%if ARCH_X86_64
+cglobal lpf_h_sb_y_16bpc, 6, 11, 16, -16 * 15, \
+                          dst, stride, mask, l, l_stride, lut, \
+                          h, stride3, tmp, mask_bits, bdmul
+    mov          r6d, r7m
+    sar          r6d, 7
+    and          r6d, 16                      ; 0 for 10bpc, 16 for 12bpc
+    lea       bdmulq, [pw_4]
+    add       bdmulq, r6
+    mov           hd, hm
+    shl    l_strideq, 2
+%else
+; stack layout [32bit only]:
+; r15 - GPRs [mask_bitsm]
+; r16 - m12/pb_mask
+; r17 - bdmulq
+; r18-24 - p2-q3
+cglobal lpf_h_sb_y_16bpc, 4, 7, 8, -16 * (25 + extra_stack), \
+                          dst, stride, mask, l, pic_reg, stride3, tmp
+    RELOC_ARGS     h, 25*16
+%if STACK_ALIGNMENT >= 16
+    mov          r5d, r7m
+%endif
+    sar          r5d, 7
+    and          r5d, 16                      ; 0 for 10bpc, 16 for 12bpc
+    LEA     pic_regq, PIC_base
+    mova          m0, [PIC_sym(pw_4)+r5]
+%define bdmulq esp+17*16
+    mova    [bdmulq], m0
+    shl dword lstridem, 2
+%endif
+    sub           lq, 4
+    lea     stride3q, [strideq*3]
+%if ARCH_X86_64
+    mov   mask_bitsd, 0x3
+    mova         m12, [pb_mask]
+%else
+%define mask_bitsm dword [esp+15*16+0*gprsize]
+    mov   mask_bitsm, 0x3
+    mova          m0, [PIC_sym(pb_mask)]
+%define m12 [esp+16*16]
+    mova         m12, m0
+%endif
+
+.loop:
+%if ARCH_X86_64
+    test   [maskq+8], mask_bitsd            ; vmask[2]
+%else
+    mov         r6d, mask_bitsm
+    test   [maskq+8], r6d
+%endif
+    jz .no_flat16
+
+    FILTER        16, h
+    jmp .end
+
+.no_flat16:
+%if ARCH_X86_64
+    test   [maskq+4], mask_bitsd            ; vmask[1]
+%else
+    test   [maskq+4], r6d
+%endif
+    jz .no_flat
+
+    FILTER         8, h
+    jmp .end
+
+.no_flat:
+%if ARCH_X86_64
+    test   [maskq+0], mask_bitsd            ; vmask[0]
+%else
+    test   [maskq+0], r6d
+%endif
+    jz .no_filter
+
+    FILTER         4, h
+    jmp .end
+
+.no_filter:
+    lea         dstq, [dstq+strideq*8]
+.end:
+%if ARCH_X86_64
+    pslld        m12, 2
+    lea           lq, [lq+l_strideq*2]
+    shl   mask_bitsd, 2
+    sub           hd, 2
+%else
+    mova          m0, m12
+    pslld         m0, 2
+    mova         m12, m0
+    add           lq, dword lstridem
+    add           lq, dword lstridem
+    shl   mask_bitsm, 2
+    sub     dword hm, 2
+%endif
+    jg .loop
+%undef mask_bitsm
+%undef bdmulq
+    UNRELOC_ARGS
+    RET
+
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal lpf_v_sb_uv_16bpc, 6, 12, 16, \
+                           dst, stride, mask, l, l_stride, lut, \
+                           w, stride3, mstride, tmp, mask_bits, bdmul
+    mov          r6d, r7m
+    sar          r6d, 7
+    and          r6d, 16                      ; 0 for 10bpc, 16 for 12bpc
+    lea       bdmulq, [pw_4]
+    add       bdmulq, r6
+    mov           wd, wm
+    shl    l_strideq, 2
+    sub           lq, l_strideq
+%else
+; stack layout [32bit only]:
+; r0 - GPRs [mask_bitsm, mstridem]
+; r1 - m12/pb_mask
+; r2 - bdmulq
+cglobal lpf_v_sb_uv_16bpc, 4, 7, 8, -16 * (3 + extra_stack), \
+                           dst, stride, mask, mstride, pic_reg, stride3, tmp
+    RELOC_ARGS     v, 3*16
+%if STACK_ALIGNMENT >= 16
+    mov          r5d, r7m
+%endif
+    sar          r5d, 7
+    and          r5d, 16                      ; 0 for 10bpc, 16 for 12bpc
+    LEA     pic_regq, PIC_base
+    mova          m0, [PIC_sym(pw_4)+r5]
+%define bdmulq esp+2*16
+    mova    [bdmulq], m0
+    shl dword lstridem, 2
+    sub           r3, dword lstridem
+    mov     dword lm, r3
+%endif
+    mov     mstrideq, strideq
+    neg     mstrideq
+    lea     stride3q, [strideq*3]
+%if ARCH_X86_64
+    mov   mask_bitsd, 0x3
+    mova         m12, [pb_mask]
+%else
+%define mask_bitsm dword [esp+0*gprsize]
+%define mstridem dword [esp+1*gprsize]
+    mov   mask_bitsm, 0x3
+    mov     mstridem, mstrideq
+    mova          m0, [PIC_sym(pb_mask)]
+%define m12 [esp+1*16]
+    mova         m12, m0
+%endif
+
+.loop:
+%if ARCH_X86_64
+    test   [maskq+4], mask_bitsd            ; vmask[1]
+%else
+    mov          r6d, mask_bitsm
+    test   [maskq+4], r6d
+%endif
+    jz .no_flat
+
+    FILTER         6, v
+    jmp .end
+
+.no_flat:
+%if ARCH_X86_64
+    test   [maskq+0], mask_bitsd            ; vmask[0]
+%else
+    test   [maskq+0], r6d
+%endif
+    jz .end
+
+    FILTER         4, v
+
+.end:
+%if ARCH_X86_64
+    pslld        m12, 2
+    add           lq, 8
+%else
+    mova          m0, m12
+    pslld         m0, 2
+    mova         m12, m0
+    add     dword lm, 8
+%endif
+    add         dstq, 16
+%if ARCH_X86_64
+    shl   mask_bitsd, 2
+    sub           wd, 2
+%else
+    shl   mask_bitsm, 2
+    sub     dword wm, 2
+%endif
+    jg .loop
+%undef mask_bitsm
+%undef bdmulq
+    UNRELOC_ARGS
+    RET
+
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal lpf_h_sb_uv_16bpc, 6, 11, 16, \
+                           dst, stride, mask, l, l_stride, lut, \
+                           h, stride3, tmp, mask_bits, bdmul
+    mov          r6d, r7m
+    sar          r6d, 7
+    and          r6d, 16                      ; 0 for 10bpc, 16 for 12bpc
+    lea       bdmulq, [pw_4]
+    add       bdmulq, r6
+    mov           hd, hm
+    shl    l_strideq, 2
+%else
+; stack layout [32bit only]:
+; r0 - GPRs [mask_bitsm]
+; r1 - m12/pb_mask
+; r2 - bdmulq
+; r3-8 - p2-q2
+cglobal lpf_h_sb_uv_16bpc, 4, 7, 8, -16 * (9 + extra_stack), \
+                           dst, stride, mask, l, pic_reg, stride3, tmp
+    RELOC_ARGS     h, 9*16
+%if STACK_ALIGNMENT >= 16
+    mov          r5d, r7m
+%endif
+    sar          r5d, 7
+    and          r5d, 16                      ; 0 for 10bpc, 16 for 12bpc
+    LEA     pic_regq, PIC_base
+    mova          m0, [PIC_sym(pw_4)+r5]
+%define bdmulq esp+2*16
+    mova    [bdmulq], m0
+    shl dword lstridem, 2
+%endif
+    sub           lq, 4
+    lea     stride3q, [strideq*3]
+%if ARCH_X86_64
+    mov   mask_bitsd, 0x3
+    mova         m12, [pb_mask]
+%else
+%define mask_bitsm dword [esp+0*gprsize]
+    mov   mask_bitsm, 0x3
+    mova          m0, [PIC_sym(pb_mask)]
+%define m12 [esp+1*16]
+    mova         m12, m0
+%endif
+
+.loop:
+%if ARCH_X86_64
+    test   [maskq+4], mask_bitsd            ; vmask[1]
+%else
+    mov          r6d, mask_bitsm
+    test   [maskq+4], r6d
+%endif
+    jz .no_flat
+
+    FILTER         6, h
+    jmp .end
+
+.no_flat:
+%if ARCH_X86_64
+    test   [maskq+0], mask_bitsd            ; vmask[0]
+%else
+    test   [maskq+0], r6d
+%endif
+    jz .no_filter
+
+    FILTER         4, h
+    jmp .end
+
+.no_filter:
+    lea         dstq, [dstq+strideq*8]
+.end:
+%if ARCH_X86_64
+    pslld        m12, 2
+    lea           lq, [lq+l_strideq*2]
+    shl   mask_bitsd, 2
+    sub           hd, 2
+%else
+    mova          m0, m12
+    pslld         m0, 2
+    mova         m12, m0
+    add           lq, dword lstridem
+    add           lq, dword lstridem
+    shl   mask_bitsm, 2
+    sub     dword hm, 2
+%endif
+    jg .loop
+%undef mask_bitsm
+%undef bdmulq
+    UNRELOC_ARGS
+    RET
diff --git a/media/libdav1d/src/src/x86/loopfilter_avx2.asm b/media/libdav1d/src/src/x86/loopfilter_avx2.asm
new file mode 100644
index 0000000000..84696c758a
--- /dev/null
+++ b/media/libdav1d/src/src/x86/loopfilter_avx2.asm
@@ -0,0 +1,1569 @@
+; Copyright © 2018-2021, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 32
+
+pb_4x1_4x5_4x9_4x13: times 2 db 0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12
+pb_7_1: times 16 db 7, 1
+pb_3_1: times 16 db 3, 1
+pb_2_1: times 16 db 2, 1
+pb_m1_0: times 16 db -1, 0
+pb_m1_1: times 16 db -1, 1
+pb_m1_2: times 16 db -1, 2
+pb_1: times 32 db 1
+pb_2: times 32 db 2
+pb_3: times 32 db 3
+pb_4: times 32 db 4
+pb_16: times 32 db 16
+pb_63: times 32 db 63
+pb_64: times 32 db 64
+pb_128: times 32 db 0x80
+pb_129: times 32 db 0x81
+pb_240: times 32 db 0xf0
+pb_248: times 32 db 0xf8
+pb_254: times 32 db 0xfe
+
+pw_2048: times 16 dw 2048
+pw_4096: times 16 dw 4096
+
+pb_mask: dd 1, 2, 4, 8, 16, 32, 64, 128
+
+SECTION .text
+
+%macro ABSSUB 4 ; dst, a, b, tmp
+    psubusb       %1, %2, %3
+    psubusb       %4, %3, %2
+    por           %1, %4
+%endmacro
+
+%macro TRANSPOSE_16x4_AND_WRITE_4x32 5
+    ; transpose 16x4
+    punpcklbw    m%5, m%1, m%2
+    punpckhbw    m%1, m%2
+    punpcklbw    m%2, m%3, m%4
+    punpckhbw    m%3, m%4
+    punpcklwd    m%4, m%5, m%2
+    punpckhwd    m%5, m%2
+    punpcklwd    m%2, m%1, m%3
+    punpckhwd    m%1, m%3
+
+    ; write out
+    movd [dstq+strideq*0-2], xm%4
+    pextrd [dstq+strideq*1-2], xm%4, 1
+    pextrd [dstq+strideq*2-2], xm%4, 2
+    pextrd [dstq+stride3q-2], xm%4, 3
+    lea         dstq, [dstq+strideq*4]
+    movd [dstq+strideq*0-2], xm%5
+    pextrd [dstq+strideq*1-2], xm%5, 1
+    pextrd [dstq+strideq*2-2], xm%5, 2
+    pextrd [dstq+stride3q-2], xm%5, 3
+    lea         dstq, [dstq+strideq*4]
+    movd [dstq+strideq*0-2], xm%2
+    pextrd [dstq+strideq*1-2], xm%2, 1
+    pextrd [dstq+strideq*2-2], xm%2, 2
+    pextrd [dstq+stride3q-2], xm%2, 3
+    lea         dstq, [dstq+strideq*4]
+    movd [dstq+strideq*0-2], xm%1
+    pextrd [dstq+strideq*1-2], xm%1, 1
+    pextrd [dstq+strideq*2-2], xm%1, 2
+    pextrd [dstq+stride3q-2], xm%1, 3
+    lea         dstq, [dstq+strideq*4]
+
+    vextracti128 xm%4, m%4, 1
+    vextracti128 xm%5, m%5, 1
+    vextracti128 xm%2, m%2, 1
+    vextracti128 xm%1, m%1, 1
+
+    movd [dstq+strideq*0-2], xm%4
+    pextrd [dstq+strideq*1-2], xm%4, 1
+    pextrd [dstq+strideq*2-2], xm%4, 2
+    pextrd [dstq+stride3q-2], xm%4, 3
+    lea         dstq, [dstq+strideq*4]
+    movd [dstq+strideq*0-2], xm%5
+    pextrd [dstq+strideq*1-2], xm%5, 1
+    pextrd [dstq+strideq*2-2], xm%5, 2
+    pextrd [dstq+stride3q-2], xm%5, 3
+    lea         dstq, [dstq+strideq*4]
+    movd [dstq+strideq*0-2], xm%2
+    pextrd [dstq+strideq*1-2], xm%2, 1
+    pextrd [dstq+strideq*2-2], xm%2, 2
+    pextrd [dstq+stride3q-2], xm%2, 3
+    lea         dstq, [dstq+strideq*4]
+    movd [dstq+strideq*0-2], xm%1
+    pextrd [dstq+strideq*1-2], xm%1, 1
+    pextrd [dstq+strideq*2-2], xm%1, 2
+    pextrd [dstq+stride3q-2], xm%1, 3
+    lea         dstq, [dstq+strideq*4]
+%endmacro
+
+%macro TRANSPOSE_16X16B 3 ; in_load_15_from_mem, out_store_0_in_mem, mem
+%if %1 == 0
+    mova          %3, m15
+%endif
+
+    ; input in m0-15
+    punpcklbw    m15, m0, m1
+    punpckhbw     m0, m1
+    punpcklbw     m1, m2, m3
+    punpckhbw     m2, m3
+    punpcklbw     m3, m4, m5
+    punpckhbw     m4, m5
+    punpcklbw     m5, m6, m7
+    punpckhbw     m6, m7
+    punpcklbw     m7, m8, m9
+    punpckhbw     m8, m9
+    punpcklbw     m9, m10, m11
+    punpckhbw    m10, m11
+    punpcklbw    m11, m12, m13
+    punpckhbw    m12, m13
+    mova         m13, %3
+    mova          %3, m12
+    punpcklbw    m12, m14, m13
+    punpckhbw    m13, m14, m13
+
+    ; interleaved in m15,0,1,2,3,4,5,6,7,8,9,10,11,rsp%3,12,13
+    punpcklwd    m14, m15, m1
+    punpckhwd    m15, m1
+    punpcklwd     m1, m0, m2
+    punpckhwd     m0, m2
+    punpcklwd     m2, m3, m5
+    punpckhwd     m3, m5
+    punpcklwd     m5, m4, m6
+    punpckhwd     m4, m6
+    punpcklwd     m6, m7, m9
+    punpckhwd     m7, m9
+    punpcklwd     m9, m8, m10
+    punpckhwd     m8, m10
+    punpcklwd    m10, m11, m12
+    punpckhwd    m11, m12
+    mova         m12, %3
+    mova          %3, m11
+    punpcklwd    m11, m12, m13
+    punpckhwd    m12, m13
+
+    ; interleaved in m14,15,1,0,2,3,5,4,6,7,9,8,10,rsp%3,11,12
+    punpckldq    m13, m14, m2
+    punpckhdq    m14, m2
+    punpckldq     m2, m15, m3
+    punpckhdq    m15, m3
+    punpckldq     m3, m1, m5
+    punpckhdq     m1, m5
+    punpckldq     m5, m0, m4
+    punpckhdq     m0, m4
+    punpckldq     m4, m6, m10
+    punpckhdq     m6, m10
+    punpckldq    m10, m9, m11
+    punpckhdq     m9, m11
+    punpckldq    m11, m8, m12
+    punpckhdq     m8, m12
+    mova         m12, %3
+    mova          %3, m8
+    punpckldq     m8, m7, m12
+    punpckhdq     m7, m12
+
+    ; interleaved in m13,14,2,15,3,1,5,0,4,6,8,7,10,9,11,rsp%3
+    punpcklqdq   m12, m13, m4
+    punpckhqdq   m13, m4
+    punpcklqdq    m4, m14, m6
+    punpckhqdq   m14, m6
+    punpcklqdq    m6, m2, m8
+    punpckhqdq    m2, m8
+    punpcklqdq    m8, m15, m7
+    punpckhqdq   m15, m7
+    punpcklqdq    m7, m3, m10
+    punpckhqdq    m3, m10
+    punpcklqdq   m10, m1, m9
+    punpckhqdq    m1, m9
+    punpcklqdq    m9, m5, m11
+    punpckhqdq    m5, m11
+    mova         m11, %3
+    mova          %3, m12
+    punpcklqdq   m12, m0, m11
+    punpckhqdq    m0, m11
+%if %2 == 0
+    mova         m11, %3
+%endif
+
+    ; interleaved m11,13,4,14,6,2,8,15,7,3,10,1,9,5,12,0
+    SWAP          0, 11, 1, 13, 5, 2, 4, 6, 8, 7, 15
+    SWAP          3, 14, 12, 9
+%endmacro
+
+%macro FILTER 2 ; width [4/6/8/16], dir [h/v]
+    ; load data
+%ifidn %2, v
+%if %1 == 4
+    lea         tmpq, [dstq+mstrideq*2]
+    mova          m3, [tmpq+strideq*0]          ; p1
+    mova          m4, [tmpq+strideq*1]          ; p0
+    mova          m5, [tmpq+strideq*2]          ; q0
+    mova          m6, [tmpq+stride3q]           ; q1
+%else
+    ; load 6-8 pixels, remainder (for wd=16) will be read inline
+    lea         tmpq, [dstq+mstrideq*4]
+%if %1 != 6
+    mova         m12, [tmpq+strideq*0]
+%endif
+    mova         m13, [tmpq+strideq*1]
+    mova          m3, [tmpq+strideq*2]
+    mova          m4, [tmpq+stride3q]
+    mova          m5, [dstq+strideq*0]
+    mova          m6, [dstq+strideq*1]
+    mova         m14, [dstq+strideq*2]
+%if %1 != 6
+    mova         m15, [dstq+stride3q]
+%endif
+%endif
+%else
+    ; load lines
+%if %1 == 4
+    movd         xm3, [dstq+strideq*0-2]
+    movd         xm4, [dstq+strideq*1-2]
+    movd         xm5, [dstq+strideq*2-2]
+    movd         xm6, [dstq+stride3q -2]
+    lea         tmpq, [dstq+strideq*4]
+    pinsrd       xm3, [tmpq+strideq*0-2], 2
+    pinsrd       xm4, [tmpq+strideq*1-2], 2
+    pinsrd       xm5, [tmpq+strideq*2-2], 2
+    pinsrd       xm6, [tmpq+stride3q -2], 2
+    lea         tmpq, [tmpq+strideq*4]
+    pinsrd       xm3, [tmpq+strideq*0-2], 1
+    pinsrd       xm4, [tmpq+strideq*1-2], 1
+    pinsrd       xm5, [tmpq+strideq*2-2], 1
+    pinsrd       xm6, [tmpq+stride3q -2], 1
+    lea         tmpq, [tmpq+strideq*4]
+    pinsrd       xm3, [tmpq+strideq*0-2], 3
+    pinsrd       xm4, [tmpq+strideq*1-2], 3
+    pinsrd       xm5, [tmpq+strideq*2-2], 3
+    pinsrd       xm6, [tmpq+stride3q -2], 3
+    lea         tmpq, [tmpq+strideq*4]
+    movd        xm12, [tmpq+strideq*0-2]
+    movd        xm13, [tmpq+strideq*1-2]
+    movd        xm14, [tmpq+strideq*2-2]
+    movd        xm15, [tmpq+stride3q -2]
+    lea         tmpq, [tmpq+strideq*4]
+    pinsrd      xm12, [tmpq+strideq*0-2], 2
+    pinsrd      xm13, [tmpq+strideq*1-2], 2
+    pinsrd      xm14, [tmpq+strideq*2-2], 2
+    pinsrd      xm15, [tmpq+stride3q -2], 2
+    lea         tmpq, [tmpq+strideq*4]
+    pinsrd      xm12, [tmpq+strideq*0-2], 1
+    pinsrd      xm13, [tmpq+strideq*1-2], 1
+    pinsrd      xm14, [tmpq+strideq*2-2], 1
+    pinsrd      xm15, [tmpq+stride3q -2], 1
+    lea         tmpq, [tmpq+strideq*4]
+    pinsrd      xm12, [tmpq+strideq*0-2], 3
+    pinsrd      xm13, [tmpq+strideq*1-2], 3
+    pinsrd      xm14, [tmpq+strideq*2-2], 3
+    pinsrd      xm15, [tmpq+stride3q -2], 3
+    vinserti128   m3, xm12, 1
+    vinserti128   m4, xm13, 1
+    vinserti128   m5, xm14, 1
+    vinserti128   m6, xm15, 1
+
+    ; transpose 4x16
+    ; xm3: A-D0,A-D8,A-D4,A-D12
+    ; xm4: A-D1,A-D9,A-D5,A-D13
+    ; xm5: A-D2,A-D10,A-D6,A-D14
+    ; xm6: A-D3,A-D11,A-D7,A-D15
+    punpcklbw     m7, m3, m4
+    punpckhbw     m3, m4
+    punpcklbw     m4, m5, m6
+    punpckhbw     m5, m6
+    ; xm7: A0-1,B0-1,C0-1,D0-1,A8-9,B8-9,C8-9,D8-9
+    ; xm3: A4-5,B4-5,C4-5,D4-5,A12-13,B12-13,C12-13,D12-13
+    ; xm4: A2-3,B2-3,C2-3,D2-3,A10-11,B10-11,C10-11,D10-11
+    ; xm5: A6-7,B6-7,C6-7,D6-7,A14-15,B14-15,C14-15,D14-15
+    punpcklwd     m6, m7, m4
+    punpckhwd     m7, m4
+    punpcklwd     m4, m3, m5
+    punpckhwd     m3, m5
+    ; xm6: A0-3,B0-3,C0-3,D0-3
+    ; xm7: A8-11,B8-11,C8-11,D8-11
+    ; xm4: A4-7,B4-7,C4-7,D4-7
+    ; xm3: A12-15,B12-15,C12-15,D12-15
+    punpckldq     m5, m6, m4
+    punpckhdq     m6, m4
+    punpckldq     m4, m7, m3
+    punpckhdq     m7, m3
+    ; xm5: A0-7,B0-7
+    ; xm6: C0-7,D0-7
+    ; xm4: A8-15,B8-15
+    ; xm7: C8-15,D8-15
+    punpcklqdq    m3, m5, m4
+    punpckhqdq    m4, m5, m4
+    punpcklqdq    m5, m6, m7
+    punpckhqdq    m6, m7
+    ; xm3: A0-15
+    ; xm5: B0-15
+    ; xm4: C0-15
+    ; xm6: D0-15
+%elif %1 == 6 || %1 == 8
+    movq         xm3, [dstq+strideq*0-%1/2]
+    movq         xm4, [dstq+strideq*1-%1/2]
+    movq         xm5, [dstq+strideq*2-%1/2]
+    movq         xm6, [dstq+stride3q -%1/2]
+    lea         tmpq, [dstq+strideq*8]
+    movhps       xm3, [tmpq+strideq*0-%1/2]
+    movhps       xm4, [tmpq+strideq*1-%1/2]
+    movhps       xm5, [tmpq+strideq*2-%1/2]
+    movhps       xm6, [tmpq+stride3q -%1/2]
+    lea         tmpq, [tmpq+strideq*8]
+    movq         xm7, [tmpq+strideq*0-%1/2]
+    movq         xm8, [tmpq+strideq*1-%1/2]
+    movq         xm9, [tmpq+strideq*2-%1/2]
+    movq        xm11, [tmpq+stride3q -%1/2]
+    lea         tmpq, [tmpq+strideq*8]
+    movhps       xm7, [tmpq+strideq*0-%1/2]
+    movhps       xm8, [tmpq+strideq*1-%1/2]
+    movhps       xm9, [tmpq+strideq*2-%1/2]
+    movhps      xm11, [tmpq+stride3q -%1/2]
+    vinserti128   m3, xm7, 1
+    vinserti128   m4, xm8, 1
+    vinserti128   m5, xm9, 1
+    vinserti128   m6, xm11, 1
+    lea         tmpq, [dstq+strideq*4]
+    movq        xm12, [tmpq+strideq*0-%1/2]
+    movq        xm13, [tmpq+strideq*1-%1/2]
+    movq        xm14, [tmpq+strideq*2-%1/2]
+    movq        xm15, [tmpq+stride3q -%1/2]
+    lea         tmpq, [tmpq+strideq*8]
+    movhps      xm12, [tmpq+strideq*0-%1/2]
+    movhps      xm13, [tmpq+strideq*1-%1/2]
+    movhps      xm14, [tmpq+strideq*2-%1/2]
+    movhps      xm15, [tmpq+stride3q -%1/2]
+    lea         tmpq, [tmpq+strideq*8]
+    movq         xm7, [tmpq+strideq*0-%1/2]
+    movq         xm8, [tmpq+strideq*1-%1/2]
+    movq         xm9, [tmpq+strideq*2-%1/2]
+    movq        xm11, [tmpq+stride3q -%1/2]
+    lea         tmpq, [tmpq+strideq*8]
+    movhps       xm7, [tmpq+strideq*0-%1/2]
+    movhps       xm8, [tmpq+strideq*1-%1/2]
+    movhps       xm9, [tmpq+strideq*2-%1/2]
+    movhps      xm11, [tmpq+stride3q -%1/2]
+    vinserti128  m12, xm7, 1
+    vinserti128  m13, xm8, 1
+    vinserti128  m14, xm9, 1
+    vinserti128  m15, xm11, 1
+
+    ; transpose 8x16
+    ; xm3: A-H0,A-H8
+    ; xm4: A-H1,A-H9
+    ; xm5: A-H2,A-H10
+    ; xm6: A-H3,A-H11
+    ; xm12: A-H4,A-H12
+    ; xm13: A-H5,A-H13
+    ; xm14: A-H6,A-H14
+    ; xm15: A-H7,A-H15
+    punpcklbw    m7, m3, m4
+    punpckhbw    m3, m4
+    punpcklbw    m4, m5, m6
+    punpckhbw    m5, m6
+    punpcklbw    m6, m12, m13
+    punpckhbw   m12, m13
+    punpcklbw   m13, m14, m15
+    punpckhbw   m14, m15
+    ; xm7: A0-1,B0-1,C0-1,D0-1,E0-1,F0-1,G0-1,H0-1
+    ; xm3: A8-9,B8-9,C8-9,D8-9,E8-9,F8-9,G8-9,H8-9
+    ; xm4: A2-3,B2-3,C2-3,D2-3,E2-3,F2-3,G2-3,H2-3
+    ; xm5: A10-11,B10-11,C10-11,D10-11,E10-11,F10-11,G10-11,H10-11
+    ; xm6: A4-5,B4-5,C4-5,D4-5,E4-5,F4-5,G4-5,H4-5
+    ; xm12: A12-13,B12-13,C12-13,D12-13,E12-13,F12-13,G12-13,H12-13
+    ; xm13: A6-7,B6-7,C6-7,D6-7,E6-7,F6-7,G6-7,H6-7
+    ; xm14: A14-15,B14-15,C14-15,D14-15,E14-15,F14-15,G14-15,H14-15
+    punpcklwd   m15, m7, m4
+    punpckhwd    m7, m4
+    punpcklwd    m4, m3, m5
+    punpckhwd    m3, m5
+    punpcklwd    m5, m6, m13
+    punpckhwd    m6, m13
+    punpcklwd   m13, m12, m14
+    punpckhwd   m12, m14
+    ; xm15: A0-3,B0-3,C0-3,D0-3
+    ; xm7: E0-3,F0-3,G0-3,H0-3
+    ; xm4: A8-11,B8-11,C8-11,D8-11
+    ; xm3: E8-11,F8-11,G8-11,H8-11
+    ; xm5: A4-7,B4-7,C4-7,D4-7
+    ; xm6: E4-7,F4-7,G4-7,H4-7
+    ; xm13: A12-15,B12-15,C12-15,D12-15
+    ; xm12: E12-15,F12-15,G12-15,H12-15
+    punpckldq   m14, m15, m5
+    punpckhdq   m15, m5
+    punpckldq    m5, m7, m6
+%if %1 != 6
+    punpckhdq    m7, m6
+%endif
+    punpckldq    m6, m4, m13
+    punpckhdq    m4, m13
+    punpckldq   m13, m3, m12
+%if %1 != 6
+    punpckhdq   m12, m3, m12
+%endif
+    ; xm14: A0-7,B0-7
+    ; xm15: C0-7,D0-7
+    ; xm5: E0-7,F0-7
+    ; xm7: G0-7,H0-7
+    ; xm6: A8-15,B8-15
+    ; xm4: C8-15,D8-15
+    ; xm13: E8-15,F8-15
+    ; xm12: G8-15,H8-15
+    punpcklqdq   m3, m14, m6
+    punpckhqdq  m14, m6
+    punpckhqdq   m6, m15, m4
+    punpcklqdq  m15, m4
+    punpcklqdq   m4, m5, m13
+    punpckhqdq  m13, m5, m13
+%if %1 == 8
+    punpcklqdq   m5, m7, m12
+    punpckhqdq  m12, m7, m12
+    ; xm3: A0-15
+    ; xm14: B0-15
+    ; xm15: C0-15
+    ; xm6: D0-15
+    ; xm4: E0-15
+    ; xm13: F0-15
+    ; xm5: G0-15
+    ; xm12: H0-15
+    SWAP         12, 3, 15
+    SWAP         13, 14, 5, 4, 6
+    ; 3,14,15,6,4,13,5,12 -> 12,13,3,4,5,6,14,15
+%else
+    SWAP         13, 3, 14
+    SWAP          6, 4, 15, 5
+    ; 3,14,15,6,4,13 -> 13,3,4,5,6,14
+%endif
+%else
+    ; load and 16x16 transpose. We only use 14 pixels but we'll need the
+    ; remainder at the end for the second transpose
+    movu         xm0, [dstq+strideq*0-8]
+    movu         xm1, [dstq+strideq*1-8]
+    movu         xm2, [dstq+strideq*2-8]
+    movu         xm3, [dstq+stride3q -8]
+    lea         tmpq, [dstq+strideq*4]
+    movu         xm4, [tmpq+strideq*0-8]
+    movu         xm5, [tmpq+strideq*1-8]
+    movu         xm6, [tmpq+strideq*2-8]
+    movu         xm7, [tmpq+stride3q -8]
+    lea         tmpq, [tmpq+strideq*4]
+    movu         xm8, [tmpq+strideq*0-8]
+    movu         xm9, [tmpq+strideq*1-8]
+    movu        xm10, [tmpq+strideq*2-8]
+    movu        xm11, [tmpq+stride3q -8]
+    lea         tmpq, [tmpq+strideq*4]
+    movu        xm12, [tmpq+strideq*0-8]
+    movu        xm13, [tmpq+strideq*1-8]
+    movu        xm14, [tmpq+strideq*2-8]
+    movu        xm15, [tmpq+stride3q -8]
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128   m0, [tmpq+strideq*0-8], 1
+    vinserti128   m1, [tmpq+strideq*1-8], 1
+    vinserti128   m2, [tmpq+strideq*2-8], 1
+    vinserti128   m3, [tmpq+stride3q -8], 1
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128   m4, [tmpq+strideq*0-8], 1
+    vinserti128   m5, [tmpq+strideq*1-8], 1
+    vinserti128   m6, [tmpq+strideq*2-8], 1
+    vinserti128   m7, [tmpq+stride3q -8], 1
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128   m8, [tmpq+strideq*0-8], 1
+    vinserti128   m9, [tmpq+strideq*1-8], 1
+    vinserti128  m10, [tmpq+strideq*2-8], 1
+    vinserti128  m11, [tmpq+stride3q -8], 1
+    lea         tmpq, [tmpq+strideq*4]
+    vinserti128  m12, [tmpq+strideq*0-8], 1
+    vinserti128  m13, [tmpq+strideq*1-8], 1
+    vinserti128  m14, [tmpq+strideq*2-8], 1
+    vinserti128  m15, [tmpq+stride3q -8], 1
+
+    TRANSPOSE_16X16B 0, 1, [rsp+11*32]
+    mova  [rsp+12*32], m1
+    mova  [rsp+13*32], m2
+    mova  [rsp+14*32], m3
+    mova  [rsp+15*32], m12
+    mova  [rsp+16*32], m13
+    mova  [rsp+17*32], m14
+    mova  [rsp+18*32], m15
+    ; 4,5,6,7,8,9,10,11 -> 12,13,3,4,5,6,14,15
+    SWAP           12, 4, 7
+    SWAP           13, 5, 8
+    SWAP            3, 6, 9
+    SWAP           10, 14
+    SWAP           11, 15
+%endif
+%endif
+
+    ; load L/E/I/H
+%ifidn %2, v
+    movu          m1, [lq]
+    movu          m0, [lq+l_strideq]
+%else
+    movq         xm1, [lq]
+    movq         xm2, [lq+l_strideq*2]
+    movhps       xm1, [lq+l_strideq]
+    movhps       xm2, [lq+l_stride3q]
+    lea           lq, [lq+l_strideq*4]
+    movq        xm10, [lq]
+    movq         xm0, [lq+l_strideq*2]
+    movhps      xm10, [lq+l_strideq]
+    movhps       xm0, [lq+l_stride3q]
+    lea           lq, [lq+l_strideq*4]
+    vinserti128   m1, xm10, 1
+    vinserti128   m2, xm0, 1
+    shufps        m0, m1, m2, q3131
+    shufps        m1, m2, q2020
+%endif
+    pxor          m2, m2
+    pcmpeqb      m10, m2, m0
+    pand          m1, m10
+    por           m0, m1                        ; l[x][] ? l[x][] : l[x-stride][]
+    pshufb        m0, [pb_4x1_4x5_4x9_4x13]     ; l[x][1]
+    pcmpeqb      m10, m2, m0                    ; !L
+    psrlq         m2, m0, [lutq+128]
+    pand          m2, [pb_63]
+    vpbroadcastb  m1, [lutq+136]
+    pminub        m2, m1
+    pmaxub        m2, [pb_1]                    ; I
+    pand          m1, m0, [pb_240]
+    psrlq         m1, 4                         ; H
+    paddb         m0, [pb_2]
+    paddb         m0, m0
+    paddb         m0, m2                        ; E
+    pxor          m1, [pb_128]
+    pxor          m2, [pb_128]
+    pxor          m0, [pb_128]
+
+    ABSSUB        m8, m3, m4, m9                ; abs(p1-p0)
+    pmaxub        m8, m10
+    ABSSUB        m9, m5, m6, m10               ; abs(q1-q0)
+    pmaxub        m8, m9
+%if %1 == 4
+    pxor          m8, [pb_128]
+    pcmpgtb       m7, m8, m1                    ; hev
+%else
+    pxor          m7, m8, [pb_128]
+    pcmpgtb       m7, m1                        ; hev
+
+%if %1 == 6
+    ABSSUB        m9, m13, m4, m10              ; abs(p2-p0)
+    pmaxub        m9, m8
+%else
+    ABSSUB        m9, m12, m4, m10              ; abs(p3-p0)
+    pmaxub        m9, m8
+    ABSSUB       m10, m13, m4, m11              ; abs(p2-p0)
+    pmaxub        m9, m10
+%endif
+    ABSSUB       m10, m5,  m14, m11             ; abs(q2-q0)
+    pmaxub        m9, m10
+%if %1 != 6
+    ABSSUB       m10, m5,  m15, m11             ; abs(q3-q0)
+    pmaxub        m9, m10
+%endif
+    pxor          m9, [pb_128]
+    pcmpgtb       m9, [pb_129]                  ; !flat8in
+
+%if %1 == 6
+    ABSSUB       m10, m13, m3,  m1              ; abs(p2-p1)
+%else
+    ABSSUB       m10, m12, m13, m11             ; abs(p3-p2)
+    ABSSUB       m11, m13, m3,  m1              ; abs(p2-p1)
+    pmaxub       m10, m11
+    ABSSUB       m11, m14, m15, m1              ; abs(q3-q2)
+    pmaxub       m10, m11
+%endif
+    ABSSUB       m11, m14, m6,  m1              ; abs(q2-q1)
+    pmaxub       m10, m11
+%if %1 == 16
+    vpbroadcastd m11, [maskq+8]
+    vpbroadcastd  m1, [maskq+4]
+    por          m11, m1
+    pand         m11, [pb_mask]
+    pcmpeqd      m11, [pb_mask]
+    pand         m10, m11
+%else
+    vpbroadcastd m11, [maskq+4]
+    pand         m11, [pb_mask]
+    pcmpeqd      m11, [pb_mask]
+    pand         m10, m11                       ; only apply fm-wide to wd>4 blocks
+%endif
+    pmaxub        m8, m10
+
+    pxor          m8, [pb_128]
+%endif
+    pcmpgtb       m8, m2
+
+    ABSSUB       m10, m3, m6, m11               ; abs(p1-q1)
+    ABSSUB       m11, m4, m5, m2                ; abs(p0-q0)
+    paddusb      m11, m11
+    pand         m10, [pb_254]
+    psrlq        m10, 1
+    paddusb      m10, m11                       ; abs(p0-q0)*2+(abs(p1-q1)>>1)
+    pxor         m10, [pb_128]
+    pcmpgtb      m10, m0                        ; abs(p0-q0)*2+(abs(p1-q1)>>1) > E
+    por           m8, m10
+
+%if %1 == 16
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*8]
+    mova          m0, [tmpq+strideq*1]
+%else
+    mova          m0, [rsp+12*32]
+%endif
+    ABSSUB        m1, m0, m4, m2
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*2]
+%else
+    mova          m0, [rsp+13*32]
+%endif
+    ABSSUB        m2, m0, m4, m10
+    pmaxub        m1, m2
+%ifidn %2, v
+    mova          m0, [tmpq+stride3q]
+%else
+    mova          m0, [rsp+14*32]
+%endif
+    ABSSUB        m2, m0, m4, m10
+    pmaxub        m1, m2
+%ifidn %2, v
+    lea         tmpq, [dstq+strideq*4]
+    mova          m0, [tmpq+strideq*0]
+%else
+    mova          m0, [rsp+15*32]
+%endif
+    ABSSUB        m2, m0, m5, m10
+    pmaxub        m1, m2
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*1]
+%else
+    mova          m0, [rsp+16*32]
+%endif
+    ABSSUB        m2, m0, m5, m10
+    pmaxub        m1, m2
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*2]
+%else
+    mova          m0, [rsp+17*32]
+%endif
+    ABSSUB        m2, m0, m5, m10
+    pmaxub        m1, m2
+    pxor          m1, [pb_128]
+    pcmpgtb       m1, [pb_129]                  ; !flat8out
+    por           m1, m9                        ; !flat8in | !flat8out
+    vpbroadcastd  m2, [maskq+8]
+    pand         m10, m2, [pb_mask]
+    pcmpeqd      m10, [pb_mask]
+    pandn         m1, m10                       ; flat16
+    pandn         m1, m8, m1                    ; flat16 & fm
+
+    vpbroadcastd m10, [maskq+4]
+    por          m10, m2
+    pand          m2, m10, [pb_mask]
+    pcmpeqd       m2, [pb_mask]
+    pandn         m9, m2                        ; flat8in
+    pandn         m9, m8, m9
+    vpbroadcastd  m2, [maskq+0]
+    por           m2, m10
+    pand          m2, [pb_mask]
+    pcmpeqd       m2, [pb_mask]
+    pandn         m8, m2
+    pandn         m8, m9, m8                    ; fm & !flat8 & !flat16
+    pandn         m9, m1, m9                    ; flat8 & !flat16
+%elif %1 != 4
+    vpbroadcastd  m0, [maskq+4]
+    pand          m2, m0, [pb_mask]
+    pcmpeqd       m2, [pb_mask]
+    pandn         m9, m2
+    pandn         m9, m8, m9                    ; flat8 & fm
+    vpbroadcastd  m2, [maskq+0]
+    por           m0, m2
+    pand          m0, [pb_mask]
+    pcmpeqd       m0, [pb_mask]
+    pandn         m8, m0
+    pandn         m8, m9, m8                    ; fm & !flat8
+%else
+    vpbroadcastd  m0, [maskq+0]
+    pand          m0, [pb_mask]
+    pcmpeqd       m0, [pb_mask]
+    pandn         m8, m0                        ; fm
+%endif
+
+    ; short filter
+
+    pxor          m3, [pb_128]
+    pxor          m6, [pb_128]
+    psubsb       m10, m3, m6                    ; iclip_diff(p1-q1)
+    pand         m10, m7                        ; f=iclip_diff(p1-q1)&hev
+    pxor          m4, [pb_128]
+    pxor          m5, [pb_128]
+    psubsb       m11, m5, m4
+    paddsb       m10, m11
+    paddsb       m10, m11
+    paddsb       m10, m11                       ; f=iclip_diff(3*(q0-p0)+f)
+    pand          m8, m10                       ; f&=fm
+    paddsb       m10, m8, [pb_3]
+    paddsb        m8, [pb_4]
+    pand         m10, [pb_248]
+    pand          m8, [pb_248]
+    psrlq        m10, 3
+    psrlq         m8, 3
+    pxor         m10, [pb_16]
+    pxor          m8, [pb_16]
+    psubb        m10, [pb_16]                   ; f2
+    psubb         m8, [pb_16]                   ; f1
+    paddsb        m4, m10
+    psubsb        m5, m8
+    pxor          m4, [pb_128]
+    pxor          m5, [pb_128]
+
+    pxor          m8, [pb_128]
+    pxor         m10, m10
+    pavgb         m8, m10                       ; f=(f1+1)>>1
+    psubb         m8, [pb_64]
+    pandn         m8, m7, m8                    ; f&=!hev
+    paddsb        m3, m8
+    psubsb        m6, m8
+    pxor          m3, [pb_128]
+    pxor          m6, [pb_128]
+
+%if %1 == 16
+    ; flat16 filter
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*8]
+    mova          m0, [tmpq+strideq*1]          ; p6
+    mova          m2, [tmpq+strideq*2]          ; p5
+    mova          m7, [tmpq+stride3q]           ; p4
+%else
+    mova          m0, [rsp+12*32]
+    mova          m2, [rsp+13*32]
+    mova          m7, [rsp+14*32]
+%endif
+
+    mova  [rsp+0*32], m9
+    mova  [rsp+1*32], m14
+    mova  [rsp+2*32], m15
+
+    ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0 [p5/p4/p2/p1/p0/q0][p6/p3] A
+    ; write -6
+    punpcklbw    m14, m0, m12
+    punpckhbw    m15, m0, m12
+    pmaddubsw    m10, m14, [pb_7_1]
+    pmaddubsw    m11, m15, [pb_7_1]             ; p6*7+p3
+    punpcklbw     m8, m2, m7
+    punpckhbw     m9, m2, m7
+    pmaddubsw     m8, [pb_2]
+    pmaddubsw     m9, [pb_2]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p6*7+p5*2+p4*2+p3
+    punpcklbw     m8, m13, m3
+    punpckhbw     m9, m13, m3
+    pmaddubsw     m8, [pb_1]
+    pmaddubsw     m9, [pb_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p6*7+p5*2+p4*2+p3+p2+p1
+    punpcklbw     m8, m4, m5
+    punpckhbw     m9, m4, m5
+    pmaddubsw     m8, [pb_1]
+    pmaddubsw     m9, [pb_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0
+    pmulhrsw      m8, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m8, m9
+    pand          m8, m1
+    pandn         m9, m1, m2
+    por           m8, m9
+%ifidn %2, v
+    mova [tmpq+strideq*2], m8                   ; p5
+%else
+    mova [rsp+13*32], m8
+%endif
+
+    ; sub p6*2, add p3/q1 [reuse p6/p3 from A][-p6,+q1|save] B
+    ; write -5
+    pmaddubsw    m14, [pb_m1_1]
+    pmaddubsw    m15, [pb_m1_1]
+    paddw        m10, m14
+    paddw        m11, m15                       ; p6*6+p5*2+p4*2+p3*2+p2+p1+p0+q0
+    punpcklbw     m8, m0, m6
+    punpckhbw     m9, m0, m6
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    mova  [rsp+3*32], m8
+    mova  [rsp+4*32], m9
+    paddw        m10, m8
+    paddw        m11, m9                        ; p6*5+p5*2+p4*2+p3*2+p2+p1+p0+q0+q1
+    pmulhrsw      m8, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m8, m9
+    vpblendvb     m8, m7, m8, m1
+%ifidn %2, v
+    mova [tmpq+stride3q], m8                    ; p4
+%else
+    mova [rsp+14*32], m8
+%endif
+
+    ; sub p6/p5, add p2/q2 [-p6,+p2][-p5,+q2|save] C
+    ; write -4
+    mova         m14, [rsp+1*32]
+    punpcklbw     m8, m0, m13
+    punpckhbw     m9, m0, m13
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p6*4+p5*2+p4*2+p3*2+p2*2+p1+p0+q0+q1
+    punpcklbw     m8, m2, m14
+    punpckhbw     m2, m14
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m2, [pb_m1_1]
+    mova  [rsp+1*32], m8
+    paddw        m10, m8
+    paddw        m11, m2                        ; p6*4+p5+p4*2+p3*2+p2*2+p1+p0+q0+q1+q2
+    pmulhrsw      m8, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m8, m9
+    vpblendvb     m8, m12, m8, m1
+%ifidn %2, v
+    mova [tmpq+strideq*4], m8                   ; p3
+%else
+    mova [rsp+19*32], m8
+%endif
+
+    ; sub p6/p4, add p1/q3 [-p6,+p1][-p4,+q3|save] D
+    ; write -3
+    mova         m15, [rsp+2*32]
+    punpcklbw     m8, m0, m3
+    punpckhbw     m9, m0, m3
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p6*3+p5+p4*2+p3*2+p2*2+p1*2+p0+q0+q1+q2
+    punpcklbw     m8, m7, m15
+    punpckhbw     m7, m15
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m7, [pb_m1_1]
+    mova  [rsp+2*32], m8
+    paddw        m10, m8
+    paddw        m11, m7                        ; p6*3+p5+p4+p3*2+p2*2+p1*2+p0+q0+q1+q2+q3
+    pmulhrsw      m8, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m8, m9
+    vpblendvb     m8, m13, m8, m1
+    mova  [rsp+6*32], m8                        ; don't clobber p2/m13 since we need it in F
+
+    ; sub p6/p3, add p0/q4 [-p6,+p0][-p3,+q4|save] E
+    ; write -2
+%ifidn %2, v
+    lea         tmpq, [dstq+strideq*4]
+%endif
+    punpcklbw     m8, m0, m4
+    punpckhbw     m9, m0, m4
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p6*2+p5+p4+p3*2+p2*2+p1*2+p0*2+q0+q1+q2+q3
+%ifidn %2, v
+    mova          m9, [tmpq+strideq*0]          ; q4
+%else
+    mova          m9, [rsp+15*32]
+%endif
+    punpcklbw     m8, m12, m9
+    punpckhbw     m9, m12, m9
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    mova  [rsp+7*32], m8
+    mova  [rsp+5*32], m9
+    paddw        m10, m8
+    paddw        m11, m9                        ; p6*2+p5+p4+p3+p2*2+p1*2+p0*2+q0+q1+q2+q3+q4
+    pmulhrsw      m8, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m8, m9
+    vpblendvb     m8, m3, m8, m1
+    mova  [rsp+8*32], m8                        ; don't clobber p1/m3 since we need it in G
+
+    ; sub p6/p2, add q0/q5 [-p6,+q0][-p2,+q5|save] F
+    ; write -1
+%ifidn %2, v
+    mova          m9, [tmpq+strideq*1]          ; q5
+%else
+    mova          m9, [rsp+16*32]
+%endif
+    punpcklbw     m8, m0, m5
+    punpckhbw     m0, m5
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m0, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m0                        ; p6+p5+p4+p3+p2*2+p1*2+p0*2+q0*2+q1+q2+q3+q4
+    punpcklbw     m0, m13, m9
+    punpckhbw     m9, m13, m9
+    mova         m13, [rsp+6*32]
+    pmaddubsw     m0, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    mova [rsp+ 9*32], m0
+    mova [rsp+10*32], m9
+    paddw        m10, m0
+    paddw        m11, m9                        ; p6+p5+p4+p3+p2+p1*2+p0*2+q0*2+q1+q2+q3+q4+q5
+    pmulhrsw      m0, m10, [pw_2048]
+    pmulhrsw      m8, m11, [pw_2048]
+    packuswb      m0, m8
+    vpblendvb     m0, m4, m0, m1
+    mova  [rsp+6*32], m0                        ; don't clobber p0/m4 since we need it in H
+
+    ; sub p6/p1, add q1/q6 [reuse -p6,+q1 from B][-p1,+q6|save] G
+    ; write +0
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*2]          ; q6
+%else
+    mova          m0, [rsp+17*32]
+%endif
+    paddw        m10, [rsp+3*32]
+    paddw        m11, [rsp+4*32]                ; p5+p4+p3+p2+p1*2+p0*2+q0*2+q1*2+q2+q3+q4+q5
+    punpcklbw     m8, m3, m0
+    punpckhbw     m9, m3, m0
+    mova          m3, [rsp+8*32]
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    mova  [rsp+3*32], m8
+    mova  [rsp+4*32], m9
+    paddw        m10, m8
+    paddw        m11, m9                        ; p5+p4+p3+p2+p1+p0*2+q0*2+q1*2+q2+q3+q4+q5+q6
+    pmulhrsw      m8, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m8, m9
+    vpblendvb     m8, m5, m8, m1
+    mova  [rsp+8*32], m8                        ; don't clobber q0/m5 since we need it in I
+
+    ; sub p5/p0, add q2/q6 [reuse -p5,+q2 from C][-p0,+q6] H
+    ; write +1
+    paddw        m10, [rsp+1*32]
+    paddw        m11, m2                        ; p4+p3+p2+p1+p0*2+q0*2+q1*2+q2*2+q3+q4+q5+q6
+    punpcklbw     m8, m4, m0
+    punpckhbw     m2, m4, m0
+    mova          m4, [rsp+6*32]
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m2, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m2                        ; p4+p3+p2+p1+p0+q0*2+q1*2+q2*2+q3+q4+q5+q6*2
+    pmulhrsw      m2, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m2, m9
+    vpblendvb     m2, m6, m2, m1                ; don't clobber q1/m6 since we need it in K
+
+    ; sub p4/q0, add q3/q6 [reuse -p4,+q3 from D][-q0,+q6] I
+    ; write +2
+    paddw        m10, [rsp+2*32]
+    paddw        m11, m7                        ; p3+p2+p1+p0+q0*2+q1*2+q2*2+q3*2+q4+q5+q6*2
+    punpcklbw     m8, m5, m0
+    punpckhbw     m9, m5, m0
+    mova          m5, [rsp+8*32]
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p3+p2+p1+p0+q0+q1*2+q2*2+q3*2+q4+q5+q6*3
+    pmulhrsw      m7, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m7, m9
+    vpblendvb     m7, m14, m7, m1               ; don't clobber q2/m14 since we need it in K
+
+    ; sub p3/q1, add q4/q6 [reuse -p3,+q4 from E][-q1,+q6] J
+    ; write +3
+    paddw        m10, [rsp+7*32]
+    paddw        m11, [rsp+5*32]                ; p2+p1+p0+q0+q1*2+q2*2+q3*2+q4*2+q5+q6*3
+    punpcklbw     m8, m6, m0
+    punpckhbw     m9, m6, m0
+    SWAP           2, 6
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p2+p1+p0+q0+q1+q2*2+q3*2+q4*2+q5+q6*4
+    pmulhrsw      m8, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m8, m9
+    vpblendvb     m8, m15, m8, m1
+%ifidn %2, v
+    mova [tmpq+mstrideq], m8                    ; q3
+%else
+    mova [rsp+20*32], m8
+%endif
+
+    ; sub p2/q2, add q5/q6 [reuse -p2,+q5 from F][-q2,+q6] K
+    ; write +4
+    paddw        m10, [rsp+ 9*32]
+    paddw        m11, [rsp+10*32]               ; p1+p0+q0+q1+q2*2+q3*2+q4*2+q5*2+q6*4
+    punpcklbw     m8, m14, m0
+    punpckhbw     m9, m14, m0
+    SWAP          14, 7
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p1+p0+q0+q1+q2+q3*2+q4*2+q5*2+q6*5
+    pmulhrsw      m8, m10, [pw_2048]
+    pmulhrsw      m9, m11, [pw_2048]
+    packuswb      m8, m9
+%ifidn %2, v
+    mova          m9, [tmpq+strideq*0]
+%else
+    mova          m9, [rsp+15*32]
+%endif
+    vpblendvb     m8, m9, m8, m1
+%ifidn %2, v
+    mova [tmpq+strideq*0], m8                    ; q4
+%else
+    mova [rsp+15*32], m8
+%endif
+
+    ; sub p1/q3, add q6*2 [reuse -p1,+q6 from G][-q3,+q6] L
+    ; write +5
+    paddw        m10, [rsp+3*32]
+    paddw        m11, [rsp+4*32]                ; p1+p0+q0+q1+q2*2+q3*2+q4*2+q5*2+q6*4
+    punpcklbw     m8, m15, m0
+    punpckhbw     m9, m15, m0
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw     m9, [pb_m1_1]
+    paddw        m10, m8
+    paddw        m11, m9                        ; p1+p0+q0+q1+q2+q3*2+q4*2+q5*2+q6*5
+    pmulhrsw     m10, [pw_2048]
+    pmulhrsw     m11, [pw_2048]
+    packuswb     m10, m11
+%ifidn %2, v
+    mova         m11, [tmpq+strideq*1]
+%else
+    mova         m11, [rsp+16*32]
+%endif
+    vpblendvb    m10, m11, m10, m1
+%ifidn %2, v
+    mova [tmpq+strideq*1], m10                  ; q5
+%else
+    mova [rsp+16*32], m10
+%endif
+
+    mova          m9, [rsp+0*32]
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*4]
+%endif
+%endif
+%if %1 >= 8
+    ; flat8 filter
+    punpcklbw     m0, m12, m3
+    punpckhbw     m1, m12, m3
+    pmaddubsw     m2, m0, [pb_3_1]
+    pmaddubsw     m7, m1, [pb_3_1]              ; 3 * p3 + p1
+    punpcklbw     m8, m13, m4
+    punpckhbw    m11, m13, m4
+    pmaddubsw     m8, [pb_2_1]
+    pmaddubsw    m11, [pb_2_1]
+    paddw         m2, m8
+    paddw         m7, m11                       ; 3 * p3 + 2 * p2 + p1 + p0
+    punpcklbw     m8, m5, [pb_4]
+    punpckhbw    m11, m5, [pb_4]
+    pmaddubsw     m8, [pb_1]
+    pmaddubsw    m11, [pb_1]
+    paddw         m2, m8
+    paddw         m7, m11                       ; 3 * p3 + 2 * p2 + p1 + p0 + q0 + 4
+    psrlw         m8, m2, 3
+    psrlw        m11, m7, 3
+    packuswb      m8, m11
+    vpblendvb    m10, m13, m8, m9              ; p2
+%ifidn %2, v
+    mova [tmpq+strideq*1], m10                 ; p2
+%endif
+
+    pmaddubsw     m8, m0, [pb_m1_1]
+    pmaddubsw    m11, m1, [pb_m1_1]
+    paddw         m2, m8
+    paddw         m7, m11
+    punpcklbw     m8, m13, m6
+    punpckhbw    m11, m13, m6
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw    m11, [pb_m1_1]
+    paddw         m2, m8
+    paddw         m7, m11                       ; 2 * p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4
+    psrlw         m8, m2, 3
+    psrlw        m11, m7, 3
+    packuswb      m8, m11
+    vpblendvb     m8, m3, m8, m9                ; p1
+%ifidn %2, v
+    mova [tmpq+strideq*2], m8                   ; p1
+%else
+    mova  [rsp+0*32], m8
+%endif
+
+    pmaddubsw     m0, [pb_1]
+    pmaddubsw     m1, [pb_1]
+    psubw         m2, m0
+    psubw         m7, m1
+    punpcklbw     m8, m4, m14
+    punpckhbw    m11, m4, m14
+    pmaddubsw     m8, [pb_1]
+    pmaddubsw    m11, [pb_1]
+    paddw         m2, m8
+    paddw         m7, m11                       ; p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4
+    psrlw         m8, m2, 3
+    psrlw        m11, m7, 3
+    packuswb      m8, m11
+    vpblendvb     m8, m4, m8, m9                ; p0
+%ifidn %2, v
+    mova [tmpq+stride3q ], m8                   ; p0
+%else
+    mova  [rsp+1*32], m8
+%endif
+
+    punpcklbw     m0, m5, m15
+    punpckhbw     m1, m5, m15
+    pmaddubsw     m8, m0, [pb_1]
+    pmaddubsw    m11, m1, [pb_1]
+    paddw         m2, m8
+    paddw         m7, m11
+    punpcklbw     m8, m4, m12
+    punpckhbw    m11, m4, m12
+    pmaddubsw     m8, [pb_1]
+    pmaddubsw    m11, [pb_1]
+    psubw         m2, m8
+    psubw         m7, m11                       ; p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4
+    psrlw         m8, m2, 3
+    psrlw        m11, m7, 3
+    packuswb      m8, m11
+    vpblendvb    m11, m5, m8, m9                ; q0
+%ifidn %2, v
+    mova [dstq+strideq*0], m11                  ; q0
+%endif
+
+    pmaddubsw     m0, [pb_m1_1]
+    pmaddubsw     m1, [pb_m1_1]
+    paddw         m2, m0
+    paddw         m7, m1
+    punpcklbw     m8, m13, m6
+    punpckhbw    m13, m6
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw    m13, [pb_m1_1]
+    paddw         m2, m8
+    paddw         m7, m13                       ; p1 + p0 + q0 + 2 * q1 + q2 + 2 * q3 + 4
+    psrlw         m8, m2, 3
+    psrlw        m13, m7, 3
+    packuswb      m8, m13
+    vpblendvb    m13, m6, m8, m9                ; q1
+%ifidn %2, v
+    mova [dstq+strideq*1], m13                  ; q1
+%endif
+
+    punpcklbw     m0, m3, m6
+    punpckhbw     m1, m3, m6
+    pmaddubsw     m0, [pb_1]
+    pmaddubsw     m1, [pb_1]
+    psubw         m2, m0
+    psubw         m7, m1
+    punpcklbw     m0, m14, m15
+    punpckhbw     m1, m14, m15
+    pmaddubsw     m0, [pb_1]
+    pmaddubsw     m1, [pb_1]
+    paddw         m2, m0
+    paddw         m7, m1                        ; p0 + q0 + q1 + q2 + 2 * q2 + 3 * q3 + 4
+    psrlw         m2, 3
+    psrlw         m7, 3
+    packuswb      m2, m7
+    vpblendvb     m2, m14, m2, m9               ; q2
+%ifidn %2, v
+    mova [dstq+strideq*2], m2                   ; q2
+%else
+    mova          m0, [rsp+0*32]
+    mova          m1, [rsp+1*32]
+%if %1 == 8
+    ; 16x8 transpose
+    punpcklbw     m3, m12, m10
+    punpckhbw    m12, m10
+    punpcklbw    m10, m0, m1
+    punpckhbw     m0, m1
+    punpcklbw     m1, m11, m13
+    punpckhbw    m11, m13
+    punpcklbw    m13, m2, m15
+    punpckhbw     m2, m15
+
+    punpcklwd    m15, m3, m10
+    punpckhwd     m3, m10
+    punpcklwd    m10, m12, m0
+    punpckhwd    m12, m0
+    punpcklwd     m0, m1, m13
+    punpckhwd     m1, m13
+    punpcklwd    m13, m11, m2
+    punpckhwd    m11, m2
+
+    punpckldq     m2, m15, m0
+    punpckhdq    m15, m0
+    punpckldq     m0, m3, m1
+    punpckhdq     m3, m1
+    punpckldq     m1, m10, m13
+    punpckhdq    m10, m13
+    punpckldq    m13, m12, m11
+    punpckhdq    m12, m11
+
+    ; write 8x32
+    movq   [dstq+strideq*0-4], xm2
+    movhps [dstq+strideq*1-4], xm2
+    movq   [dstq+strideq*2-4], xm15
+    movhps [dstq+stride3q -4], xm15
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm0
+    movhps [dstq+strideq*1-4], xm0
+    movq   [dstq+strideq*2-4], xm3
+    movhps [dstq+stride3q -4], xm3
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm1
+    movhps [dstq+strideq*1-4], xm1
+    movq   [dstq+strideq*2-4], xm10
+    movhps [dstq+stride3q -4], xm10
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm13
+    movhps [dstq+strideq*1-4], xm13
+    movq   [dstq+strideq*2-4], xm12
+    movhps [dstq+stride3q -4], xm12
+    lea         dstq, [dstq+strideq*4]
+
+    vextracti128  xm2,  m2, 1
+    vextracti128 xm15, m15, 1
+    vextracti128  xm0,  m0, 1
+    vextracti128  xm3,  m3, 1
+    vextracti128  xm1,  m1, 1
+    vextracti128 xm10, m10, 1
+    vextracti128 xm13, m13, 1
+    vextracti128 xm12, m12, 1
+
+    movq   [dstq+strideq*0-4], xm2
+    movhps [dstq+strideq*1-4], xm2
+    movq   [dstq+strideq*2-4], xm15
+    movhps [dstq+stride3q -4], xm15
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm0
+    movhps [dstq+strideq*1-4], xm0
+    movq   [dstq+strideq*2-4], xm3
+    movhps [dstq+stride3q -4], xm3
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm1
+    movhps [dstq+strideq*1-4], xm1
+    movq   [dstq+strideq*2-4], xm10
+    movhps [dstq+stride3q -4], xm10
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm13
+    movhps [dstq+strideq*1-4], xm13
+    movq   [dstq+strideq*2-4], xm12
+    movhps [dstq+stride3q -4], xm12
+    lea         dstq, [dstq+strideq*4]
+%else
+    ; 16x16 transpose and store
+    SWAP           5, 10, 2
+    SWAP           6, 0
+    SWAP           7, 1
+    SWAP           8, 11
+    SWAP           9, 13
+    mova          m0, [rsp+11*32]
+    mova          m1, [rsp+12*32]
+    mova          m2, [rsp+13*32]
+    mova          m3, [rsp+14*32]
+    mova          m4, [rsp+19*32]
+    mova         m11, [rsp+20*32]
+    mova         m12, [rsp+15*32]
+    mova         m13, [rsp+16*32]
+    mova         m14, [rsp+17*32]
+    TRANSPOSE_16X16B 1, 0, [rsp+18*32]
+    movu [dstq+strideq*0-8], xm0
+    movu [dstq+strideq*1-8], xm1
+    movu [dstq+strideq*2-8], xm2
+    movu [dstq+stride3q -8], xm3
+    lea         dstq, [dstq+strideq*4]
+    movu [dstq+strideq*0-8], xm4
+    movu [dstq+strideq*1-8], xm5
+    movu [dstq+strideq*2-8], xm6
+    movu [dstq+stride3q -8], xm7
+    lea         dstq, [dstq+strideq*4]
+    movu [dstq+strideq*0-8], xm8
+    movu [dstq+strideq*1-8], xm9
+    movu [dstq+strideq*2-8], xm10
+    movu [dstq+stride3q -8], xm11
+    lea         dstq, [dstq+strideq*4]
+    movu [dstq+strideq*0-8], xm12
+    movu [dstq+strideq*1-8], xm13
+    movu [dstq+strideq*2-8], xm14
+    movu [dstq+stride3q -8], xm15
+    lea         dstq, [dstq+strideq*4]
+    vextracti128 [dstq+strideq*0-8], m0, 1
+    vextracti128 [dstq+strideq*1-8], m1, 1
+    vextracti128 [dstq+strideq*2-8], m2, 1
+    vextracti128 [dstq+stride3q -8], m3, 1
+    lea         dstq, [dstq+strideq*4]
+    vextracti128 [dstq+strideq*0-8], m4, 1
+    vextracti128 [dstq+strideq*1-8], m5, 1
+    vextracti128 [dstq+strideq*2-8], m6, 1
+    vextracti128 [dstq+stride3q -8], m7, 1
+    lea         dstq, [dstq+strideq*4]
+    vextracti128 [dstq+strideq*0-8], m8, 1
+    vextracti128 [dstq+strideq*1-8], m9, 1
+    vextracti128 [dstq+strideq*2-8], m10, 1
+    vextracti128 [dstq+stride3q -8], m11, 1
+    lea         dstq, [dstq+strideq*4]
+    vextracti128 [dstq+strideq*0-8], m12, 1
+    vextracti128 [dstq+strideq*1-8], m13, 1
+    vextracti128 [dstq+strideq*2-8], m14, 1
+    vextracti128 [dstq+stride3q -8], m15, 1
+    lea         dstq, [dstq+strideq*4]
+%endif
+%endif
+%elif %1 == 6
+    ; flat6 filter
+
+    punpcklbw     m8, m13, m5
+    punpckhbw    m11, m13, m5
+    pmaddubsw     m0, m8, [pb_3_1]
+    pmaddubsw     m1, m11, [pb_3_1]
+    punpcklbw     m7, m4, m3
+    punpckhbw    m10, m4, m3
+    pmaddubsw     m2, m7, [pb_2]
+    pmaddubsw    m12, m10, [pb_2]
+    paddw         m0, m2
+    paddw         m1, m12
+    pmulhrsw      m2, m0, [pw_4096]
+    pmulhrsw     m12, m1, [pw_4096]
+    packuswb      m2, m12
+    vpblendvb     m2, m3, m2, m9
+%ifidn %2, v
+    mova [tmpq+strideq*2], m2                   ; p1
+%endif
+
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw    m11, [pb_m1_1]
+    paddw         m0, m8
+    paddw         m1, m11
+    punpcklbw     m8, m13, m6
+    punpckhbw    m11, m13, m6
+    pmaddubsw     m8, [pb_m1_1]
+    pmaddubsw    m11, [pb_m1_1]
+    paddw         m0, m8
+    paddw         m1, m11
+    pmulhrsw     m12, m0, [pw_4096]
+    pmulhrsw     m13, m1, [pw_4096]
+    packuswb     m12, m13
+    vpblendvb    m12, m4, m12, m9
+%ifidn %2, v
+    mova [tmpq+stride3q], m12                   ; p0
+%endif
+
+    paddw         m0, m8
+    paddw         m1, m11
+    punpcklbw     m8, m3, m14
+    punpckhbw    m11, m3, m14
+    pmaddubsw    m14, m8, [pb_m1_1]
+    pmaddubsw    m13, m11, [pb_m1_1]
+    paddw         m0, m14
+    paddw         m1, m13
+    pmulhrsw     m14, m0, [pw_4096]
+    pmulhrsw     m13, m1, [pw_4096]
+    packuswb     m14, m13
+    vpblendvb    m14, m5, m14, m9
+%ifidn %2, v
+    mova [dstq+strideq*0], m14                  ; q0
+%endif
+
+    pmaddubsw     m8, [pb_m1_2]
+    pmaddubsw    m11, [pb_m1_2]
+    paddw         m0, m8
+    paddw         m1, m11
+    pmaddubsw     m7, [pb_m1_0]
+    pmaddubsw    m10, [pb_m1_0]
+    paddw         m0, m7
+    paddw         m1, m10
+    pmulhrsw      m0, [pw_4096]
+    pmulhrsw      m1, [pw_4096]
+    packuswb      m0, m1
+    vpblendvb     m0, m6, m0, m9
+%ifidn %2, v
+    mova [dstq+strideq*1], m0                   ; q1
+%else
+    TRANSPOSE_16x4_AND_WRITE_4x32 2, 12, 14, 0, 1
+%endif
+%else
+%ifidn %2, v
+    mova [tmpq+strideq*0], m3                   ; p1
+    mova [tmpq+strideq*1], m4                   ; p0
+    mova [tmpq+strideq*2], m5                   ; q0
+    mova [tmpq+stride3q ], m6                   ; q1
+%else
+    TRANSPOSE_16x4_AND_WRITE_4x32 3, 4, 5, 6, 7
+%endif
+%endif
+%endmacro
+
+INIT_YMM avx2
+cglobal lpf_v_sb_y_8bpc, 7, 10, 16, 32 * 11, \
+                    dst, stride, mask, l, l_stride, lut, \
+                    w, stride3, mstride, tmp
+    shl    l_strideq, 2
+    sub           lq, l_strideq
+    mov     mstrideq, strideq
+    neg     mstrideq
+    lea     stride3q, [strideq*3]
+
+.loop:
+    cmp byte [maskq+8], 0                       ; vmask[2]
+    je .no_flat16
+
+    FILTER        16, v
+    jmp .end
+
+.no_flat16:
+    cmp byte [maskq+4], 0                       ; vmask[1]
+    je .no_flat
+
+    FILTER         8, v
+    jmp .end
+
+.no_flat:
+    cmp byte [maskq+0], 0                       ; vmask[0]
+    je .end
+
+    call .v4
+
+.end:
+    add           lq, 32
+    add         dstq, 32
+    add        maskq, 1
+    sub           wd, 8
+    jg .loop
+    RET
+ALIGN function_align
+.v4:
+    FILTER         4, v
+    ret
+
+INIT_YMM avx2
+cglobal lpf_h_sb_y_8bpc, 7, 10, 16, 32 * 21, \
+                    dst, stride, mask, l, l_stride, lut, \
+                    h, stride3, l_stride3, tmp
+    shl    l_strideq, 2
+    sub           lq, 4
+    lea     stride3q, [strideq*3]
+    lea   l_stride3q, [l_strideq*3]
+
+.loop:
+    cmp byte [maskq+8], 0                       ; vmask[2]
+    je .no_flat16
+
+    FILTER        16, h
+    jmp .end
+
+.no_flat16:
+    cmp byte [maskq+4], 0                       ; vmask[1]
+    je .no_flat
+
+    FILTER         8, h
+    jmp .end
+
+.no_flat:
+    cmp byte [maskq+0], 0                       ; vmask[0]
+    je .no_filter
+
+    call .h4
+    jmp .end
+
+.no_filter:
+    lea         dstq, [dstq+stride3q*8]
+    lea           lq, [lq+l_strideq*8]
+    lea         dstq, [dstq+strideq*8]
+.end:
+    add        maskq, 1
+    sub           hd, 8
+    jg .loop
+    RET
+ALIGN function_align
+.h4:
+    FILTER         4, h
+    ret
+
+INIT_YMM avx2
+cglobal lpf_v_sb_uv_8bpc, 7, 10, 16, \
+                     dst, stride, mask, l, l_stride, lut, \
+                     w, stride3, mstride, tmp
+    shl    l_strideq, 2
+    sub           lq, l_strideq
+    mov     mstrideq, strideq
+    neg     mstrideq
+    lea     stride3q, [strideq*3]
+
+.loop:
+    cmp byte [maskq+4], 0                       ; vmask[1]
+    je .no_flat
+
+    FILTER         6, v
+    jmp .end
+
+.no_flat:
+    cmp byte [maskq+0], 0                       ; vmask[0]
+    je .end
+
+    call mangle(private_prefix %+ _lpf_v_sb_y_8bpc_avx2).v4
+
+.end:
+    add           lq, 32
+    add         dstq, 32
+    add        maskq, 1
+    sub           wd, 8
+    jg .loop
+    RET
+
+INIT_YMM avx2
+cglobal lpf_h_sb_uv_8bpc, 7, 10, 16, \
+                     dst, stride, mask, l, l_stride, lut, \
+                     h, stride3, l_stride3, tmp
+    shl    l_strideq, 2
+    sub           lq, 4
+    lea     stride3q, [strideq*3]
+    lea   l_stride3q, [l_strideq*3]
+
+.loop:
+    cmp byte [maskq+4], 0                       ; vmask[1]
+    je .no_flat
+
+    FILTER         6, h
+    jmp .end
+
+.no_flat:
+    cmp byte [maskq+0], 0                       ; vmask[0]
+    je .no_filter
+
+    call mangle(private_prefix %+ _lpf_h_sb_y_8bpc_avx2).h4
+    jmp .end
+
+.no_filter:
+    lea         dstq, [dstq+stride3q*8]
+    lea           lq, [lq+l_strideq*8]
+    lea         dstq, [dstq+strideq*8]
+.end:
+    add        maskq, 1
+    sub           hd, 8
+    jg .loop
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/loopfilter_avx512.asm b/media/libdav1d/src/src/x86/loopfilter_avx512.asm
new file mode 100644
index 0000000000..202a612aac
--- /dev/null
+++ b/media/libdav1d/src/src/x86/loopfilter_avx512.asm
@@ -0,0 +1,1529 @@
+; Copyright © 2018, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+pb_4x0_4x4_4x8_4x12: times 4 db 0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12
+
+pb_mask: dd 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080
+         dd 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
+
+hmulA: dd  0,  8, 16, 24, 32, 40, 48, 56,  4, 12, 20, 28, 36, 44, 52, 60
+hmulB: dd  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+hmulC: dd  0,  1,  2,  3, 16, 17, 18, 19, 32, 33, 34, 35, 48, 49, 50, 51
+hmulD: dd  0,  1, 16, 17, 32, 33, 48, 49
+hshuf4:db  0,  4,  8, 12,  1,  5,  9, 13,  2,  6, 10, 14,  3,  7, 11, 15
+
+shift1: dq 0x0204081020408000
+shift3: dq 0x0810204080000000
+shift4: dq 0x1020408000000000
+
+pb_1:    times 4 db 1
+pb_2:    times 4 db 2
+pb_3:    times 4 db 3
+pb_4:    times 4 db 4
+pb_16:   times 4 db 16
+pb_63:   times 4 db 63
+pb_64:   times 4 db 64
+pb_128:  times 4 db 0x80
+pb_2_1:  times 2 db 2, 1
+pb_3_1:  times 2 db 3, 1
+pb_7_1:  times 2 db 7, 1
+pb_m1_0: times 2 db -1, 0
+pb_m1_1: times 2 db -1, 1
+pb_m1_2: times 2 db -1, 2
+pw_2048: times 2 dw 2048
+pw_4096: times 2 dw 4096
+
+SECTION .text
+
+%macro ABSSUB 4 ; dst, a, b, tmp
+    psubusb           %1, %2, %3
+    psubusb           %4, %3, %2
+    por               %1, %4
+%endmacro
+
+%macro TRANSPOSE_16x4_AND_WRITE_4x32 5
+    punpcklbw        m%5, m%1, m%2
+    punpckhbw        m%1, m%2
+    punpcklbw        m%2, m%3, m%4
+    punpckhbw        m%3, m%4
+    punpcklwd        m%4, m%5, m%2
+    punpckhwd        m%5, m%2
+    punpcklwd        m%2, m%1, m%3
+    punpckhwd        m%1, m%3
+    kmovw             k1, k6
+    lea               t0, [dstq+strideq*4]
+    vpscatterdd [dstq+m19-2]{k1}, m%4
+    kmovw             k1, k6
+    lea               t1, [dstq+strideq*8]
+    vpscatterdd [t0  +m19-2]{k1}, m%5
+    kmovw             k1, k6
+    lea               t2, [t0  +strideq*8]
+    vpscatterdd [t1  +m19-2]{k1}, m%2
+    kmovw             k1, k6
+    vpscatterdd [t2  +m19-2]{k1}, m%1
+%endmacro
+
+%macro TRANSPOSE_16X16B 3 ; in_load_15_from_mem, out_store_0_in_mem, mem
+%if %1 == 0
+    SWAP             m16, m22
+%endif
+    punpcklbw        m22, m24, m26
+    punpckhbw        m24, m26
+    punpcklbw        m26, m2, m3
+    punpckhbw         m2, m3
+    punpcklbw         m3, m4, m5
+    punpckhbw         m4, m5
+    punpcklbw         m5, m6, m7
+    punpckhbw         m6, m7
+    punpcklbw         m7, m8, m9
+    punpckhbw         m8, m9
+    punpcklbw         m9, m10, m11
+    punpckhbw        m10, m11
+    punpcklbw        m11, m25, m13
+    punpckhbw        m25, m13
+%if %1 == 0
+    SWAP             m13, m16
+%else
+    mova             m13, %3
+%endif
+    SWAP             m16, m25
+    punpcklbw        m25, m14, m13
+    punpckhbw        m13, m14, m13
+    ; interleaved in m22,24,26,2,3,4,5,6,7,8,9,10,11,rsp%3,25,13
+    punpcklwd        m14, m22, m26
+    punpckhwd        m22, m26
+    punpcklwd        m26, m24, m2
+    punpckhwd        m24, m2
+    punpcklwd         m2, m3, m5
+    punpckhwd         m3, m5
+    punpcklwd         m5, m4, m6
+    punpckhwd         m4, m6
+    punpcklwd         m6, m7, m9
+    punpckhwd         m7, m9
+    punpcklwd         m9, m8, m10
+    punpckhwd         m8, m10
+    punpcklwd        m10, m11, m25
+    punpckhwd        m11, m25
+    SWAP             m25, m16, m11
+    punpcklwd        m11, m25, m13
+    punpckhwd        m25, m13
+    ; interleaved in m14,15,26,24,2,3,5,4,6,7,9,8,10,rsp%3,11,25
+    punpckldq        m13, m14, m2
+    punpckhdq        m14, m2
+    punpckldq         m2, m22, m3
+    punpckhdq        m22, m3
+    punpckldq         m3, m26, m5
+    punpckhdq        m26, m5
+    punpckldq         m5, m24, m4
+    punpckhdq        m24, m4
+    punpckldq         m4, m6, m10
+    punpckhdq         m6, m10
+    punpckldq        m10, m9, m11
+    punpckhdq         m9, m11
+    punpckldq        m11, m8, m25
+    punpckhdq         m8, m25
+    SWAP             m25, m16, m8
+    punpckldq         m8, m7, m25
+    punpckhdq         m7, m25
+    ; interleaved in m13,14,2,15,3,26,5,24,4,6,8,7,10,9,11,rsp%3
+    punpcklqdq       m25, m13, m4
+    punpckhqdq       m13, m4
+    punpcklqdq        m4, m14, m6
+    punpckhqdq       m14, m6
+    punpcklqdq        m6, m2, m8
+    punpckhqdq        m2, m8
+    punpcklqdq        m8, m22, m7
+    punpckhqdq       m22, m7
+    punpcklqdq        m7, m3, m10
+    punpckhqdq        m3, m10
+    punpcklqdq       m10, m26, m9
+    punpckhqdq       m26, m9
+    punpcklqdq        m9, m5, m11
+    punpckhqdq        m5, m11
+    SWAP             m11, m16
+%if %2 == 0
+    SWAP             m16, m25
+%else
+    mova              %3, m25
+%endif
+    punpcklqdq       m25, m24, m11
+    punpckhqdq       m24, m11
+%if %2 == 0
+    SWAP             m11, m16
+%endif
+    ; interleaved m11,13,4,14,6,2,8,15,7,3,10,26,9,5,25,24
+    SWAP              24, 11, 26, 13, 5, 2, 4, 6, 8, 7, 22
+    SWAP               3, 14, 25, 9
+%endmacro
+
+%macro FILTER 2 ; width [4/6/8/16], dir [h/v]
+    ; load data
+%ifidn %2, v
+%define is_h 0
+%if %1 == 4
+    lea               t0, [dstq+mstrideq*2]
+    mova              m3, [t0  +strideq*0]    ; p1
+    mova              m4, [t0  +strideq*1]    ; p0
+    mova              m5, [t0  +strideq*2]    ; q0
+    mova              m6, [t0  +stride3q ]    ; q1
+%else
+    ; load 6-8 pixels, remainder (for wd=16) will be read inline
+%if %1 == 16
+    lea               t0, [dstq+mstrideq*8]
+    mova             m16, [t0  +strideq*1]
+    mova             m17, [t0  +strideq*2]
+    mova             m18, [t0  +stride3q ]
+%endif
+    lea               t0, [dstq+mstrideq*4]
+%if %1 != 6
+    mova             m25, [t0  +strideq*0]
+%endif
+    mova             m13, [t0  +strideq*1]
+    mova              m3, [t0  +strideq*2]
+    mova              m4, [t0  +stride3q ]
+    mova              m5, [dstq+strideq*0]
+    mova              m6, [dstq+strideq*1]
+    mova             m14, [dstq+strideq*2]
+%if %1 != 6
+    mova             m22, [dstq+stride3q ]
+%endif
+%if %1 == 16
+    lea               t0, [dstq+strideq*4]
+    mova             m29, [t0  +strideq*0]
+    mova             m30, [t0  +strideq*1]
+    mova             m31, [t0  +strideq*2]
+%endif
+%endif
+%else ; h
+%define is_h 1
+    ; load lines
+%if %1 == 4
+    vbroadcasti32x4   m0, [hshuf4]
+    kmovw             k1, k6
+    lea               t0, [dstq+strideq*4]
+    vpgatherdd    m3{k1}, [dstq+m19-2]
+    kmovw             k1, k6
+    lea               t1, [dstq+strideq*8]
+    vpgatherdd    m4{k1}, [t0  +m19-2]
+    kmovw             k1, k6
+    lea               t2, [t0  +strideq*8]
+    vpgatherdd    m5{k1}, [t1  +m19-2]
+    kmovw             k1, k6
+    vpgatherdd    m6{k1}, [t2  +m19-2]
+    pshufb            m3, m0
+    pshufb            m4, m0
+    pshufb            m5, m0
+    pshufb            m6, m0
+    punpckldq         m7, m3, m4
+    punpckhdq         m3, m4
+    punpckldq         m4, m5, m6
+    punpckhdq         m5, m6
+    punpcklqdq        m6, m7, m4
+    punpckhqdq        m7, m4
+    punpcklqdq        m4, m3, m5
+    punpckhqdq        m3, m5
+    SWAP               3, 6
+    SWAP               5, 4, 7
+    ; 6,7,4,3 -> 3,4,5,6
+%elif %1 == 6 || %1 == 8
+    kmovb             k1, k7
+    lea               t0, [dstq+strideq*1]
+    vpgatherdq    m3{k1}, [dstq+ym21-%1/2]
+    kmovb             k1, k7
+    lea               t1, [dstq+strideq*2]
+    vpgatherdq    m4{k1}, [t0  +ym21-%1/2]
+    kmovb             k1, k7
+    lea               t2, [dstq+stride3q ]
+    vpgatherdq    m5{k1}, [t1  +ym21-%1/2]
+    kmovb             k1, k7
+    vextracti32x8    ym0, m21, 1
+    vpgatherdq    m6{k1}, [t2  +ym21-%1/2]
+    kmovb             k1, k7
+    vpgatherdq   m12{k1}, [dstq+ym0 -%1/2]
+    kmovb             k1, k7
+    vpgatherdq   m13{k1}, [t0  +ym0 -%1/2]
+    kmovb             k1, k7
+    vpgatherdq   m14{k1}, [t1  +ym0 -%1/2]
+    kmovb             k1, k7
+    vpgatherdq   m15{k1}, [t2  +ym0 -%1/2]
+    ; transpose 8x16
+    ; xm3: A-H0,A-H8
+    ; xm4: A-H1,A-H9
+    ; xm5: A-H2,A-H10
+    ; xm6: A-H3,A-H11
+    ; xm12: A-H4,A-H12
+    ; xm13: A-H5,A-H13
+    ; xm14: A-H6,A-H14
+    ; xm15: A-H7,A-H15
+    punpcklbw         m7, m3, m4
+    punpckhbw         m3, m4
+    punpcklbw         m4, m5, m6
+    punpckhbw         m5, m6
+    punpcklbw         m6, m12, m13
+    punpckhbw        m12, m13
+    punpcklbw        m13, m14, m15
+    punpckhbw        m14, m15
+    ; xm7: A0-1,B0-1,C0-1,D0-1,E0-1,F0-1,G0-1,H0-1
+    ; xm3: A8-9,B8-9,C8-9,D8-9,E8-9,F8-9,G8-9,H8-9
+    ; xm4: A2-3,B2-3,C2-3,D2-3,E2-3,F2-3,G2-3,H2-3
+    ; xm5: A10-11,B10-11,C10-11,D10-11,E10-11,F10-11,G10-11,H10-11
+    ; xm6: A4-5,B4-5,C4-5,D4-5,E4-5,F4-5,G4-5,H4-5
+    ; xm12: A12-13,B12-13,C12-13,D12-13,E12-13,F12-13,G12-13,H12-13
+    ; xm13: A6-7,B6-7,C6-7,D6-7,E6-7,F6-7,G6-7,H6-7
+    ; xm14: A14-15,B14-15,C14-15,D14-15,E14-15,F14-15,G14-15,H14-15
+    punpcklwd        m15, m7, m4
+    punpckhwd         m7, m4
+    punpcklwd         m4, m3, m5
+    punpckhwd         m3, m5
+    punpcklwd         m5, m6, m13
+    punpckhwd         m6, m13
+    punpcklwd        m13, m12, m14
+    punpckhwd        m12, m14
+    ; xm15: A0-3,B0-3,C0-3,D0-3
+    ; xm7: E0-3,F0-3,G0-3,H0-3
+    ; xm4: A8-11,B8-11,C8-11,D8-11
+    ; xm3: E8-11,F8-11,G8-11,H8-11
+    ; xm5: A4-7,B4-7,C4-7,D4-7
+    ; xm6: E4-7,F4-7,G4-7,H4-7
+    ; xm13: A12-15,B12-15,C12-15,D12-15
+    ; xm12: E12-15,F12-15,G12-15,H12-15
+    punpckldq        m14, m15, m5
+    punpckhdq        m15, m5
+    punpckldq         m5, m7, m6
+ %if %1 != 6
+    punpckhdq         m7, m6
+ %endif
+    punpckldq         m6, m4, m13
+    punpckhdq         m4, m13
+    punpckldq        m13, m3, m12
+ %if %1 != 6
+    punpckhdq        m12, m3, m12
+ %endif
+    ; xm14: A0-7,B0-7
+    ; xm15: C0-7,D0-7
+    ; xm5: E0-7,F0-7
+    ; xm7: G0-7,H0-7
+    ; xm6: A8-15,B8-15
+    ; xm4: C8-15,D8-15
+    ; xm13: E8-15,F8-15
+    ; xm12: G8-15,H8-15
+    punpcklqdq        m3, m14, m6
+    punpckhqdq       m14, m6
+    punpckhqdq        m6, m15, m4
+    punpcklqdq       m15, m4
+    punpcklqdq        m4, m5, m13
+    punpckhqdq       m13, m5, m13
+ %if %1 == 8
+    punpcklqdq        m5, m7, m12
+    punpckhqdq       m25, m7, m12
+    ; xm3: A0-15
+    ; xm14: B0-15
+    ; xm15: C0-15
+    ; xm6: D0-15
+    ; xm4: E0-15
+    ; xm13: F0-15
+    ; xm5: G0-15
+    ; xm25: H0-15
+    SWAP              25, 3, 15
+    SWAP              13, 14, 5, 4, 6
+    SWAP              15, 22
+    ; 3,14,15,6,4,13,5,12 -> 12,13,3,4,5,6,14,22
+ %else
+    SWAP              13, 3, 14
+    SWAP               6, 4, 15, 5
+    ; 3,14,15,6,4,13 -> 13,3,4,5,6,14
+ %endif
+%else ; 16, h
+    ; load and 16x16 transpose. We only use 14 pixels but we'll need the
+    ; remainder at the end for the second transpose
+    movu            xm24, [dstq+strideq*0-8]
+    movu            xm26, [dstq+strideq*1-8]
+    movu             xm2, [dstq+strideq*2-8]
+    movu             xm3, [dstq+stride3q -8]
+    lea               t0, [dstq+strideq*4]
+    movu             xm4, [t0  +strideq*0-8]
+    movu             xm5, [t0  +strideq*1-8]
+    movu             xm6, [t0  +strideq*2-8]
+    movu             xm7, [t0  +stride3q -8]
+    lea               t0, [t0  +strideq*4]
+    movu             xm8, [t0  +strideq*0-8]
+    movu             xm9, [t0  +strideq*1-8]
+    movu            xm10, [t0  +strideq*2-8]
+    movu            xm11, [t0  +stride3q -8]
+    lea               t0, [t0  +strideq*4]
+    movu            xm25, [t0  +strideq*0-8]
+    movu            xm13, [t0  +strideq*1-8]
+    movu            xm14, [t0  +strideq*2-8]
+    movu            xm22, [t0  +stride3q -8]
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4    ym24, [t0  +strideq*0-8], 1
+    vinserti32x4    ym26, [t0  +strideq*1-8], 1
+    vinserti32x4     ym2, [t0  +strideq*2-8], 1
+    vinserti32x4     ym3, [t0  +stride3q -8], 1
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4     ym4, [t0  +strideq*0-8], 1
+    vinserti32x4     ym5, [t0  +strideq*1-8], 1
+    vinserti32x4     ym6, [t0  +strideq*2-8], 1
+    vinserti32x4     ym7, [t0  +stride3q -8], 1
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4     ym8, [t0  +strideq*0-8], 1
+    vinserti32x4     ym9, [t0  +strideq*1-8], 1
+    vinserti32x4    ym10, [t0  +strideq*2-8], 1
+    vinserti32x4    ym11, [t0  +stride3q -8], 1
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4    ym25, [t0  +strideq*0-8], 1
+    vinserti32x4    ym13, [t0  +strideq*1-8], 1
+    vinserti32x4    ym14, [t0  +strideq*2-8], 1
+    vinserti32x4    ym22, [t0  +stride3q -8], 1
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4     m24, [t0  +strideq*0-8], 2
+    vinserti32x4     m26, [t0  +strideq*1-8], 2
+    vinserti32x4      m2, [t0  +strideq*2-8], 2
+    vinserti32x4      m3, [t0  +stride3q -8], 2
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4      m4, [t0  +strideq*0-8], 2
+    vinserti32x4      m5, [t0  +strideq*1-8], 2
+    vinserti32x4      m6, [t0  +strideq*2-8], 2
+    vinserti32x4      m7, [t0  +stride3q -8], 2
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4      m8, [t0  +strideq*0-8], 2
+    vinserti32x4      m9, [t0  +strideq*1-8], 2
+    vinserti32x4     m10, [t0  +strideq*2-8], 2
+    vinserti32x4     m11, [t0  +stride3q -8], 2
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4     m25, [t0  +strideq*0-8], 2
+    vinserti32x4     m13, [t0  +strideq*1-8], 2
+    vinserti32x4     m14, [t0  +strideq*2-8], 2
+    vinserti32x4     m22, [t0  +stride3q -8], 2
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4     m24, [t0  +strideq*0-8], 3
+    vinserti32x4     m26, [t0  +strideq*1-8], 3
+    vinserti32x4      m2, [t0  +strideq*2-8], 3
+    vinserti32x4      m3, [t0  +stride3q -8], 3
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4      m4, [t0  +strideq*0-8], 3
+    vinserti32x4      m5, [t0  +strideq*1-8], 3
+    vinserti32x4      m6, [t0  +strideq*2-8], 3
+    vinserti32x4      m7, [t0  +stride3q -8], 3
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4      m8, [t0  +strideq*0-8], 3
+    vinserti32x4      m9, [t0  +strideq*1-8], 3
+    vinserti32x4     m10, [t0  +strideq*2-8], 3
+    vinserti32x4     m11, [t0  +stride3q -8], 3
+    lea               t0, [t0  +strideq*4]
+    vinserti32x4     m25, [t0  +strideq*0-8], 3
+    vinserti32x4     m13, [t0  +strideq*1-8], 3
+    vinserti32x4     m14, [t0  +strideq*2-8], 3
+    vinserti32x4     m22, [t0  +stride3q -8], 3
+    ;
+    TRANSPOSE_16X16B 0, 1, [rsp+0*64]
+    SWAP             m16, m26
+    SWAP             m17, m2
+    SWAP             m18, m3
+    SWAP             m29, m25
+    SWAP             m30, m13
+    SWAP             m31, m14
+    mova      [rsp+4*64], m22
+    ; 4,5,6,7,8,9,10,11 -> 25,13,3,4,5,6,14,22
+    SWAP              25, 4, 7
+    SWAP              13, 5, 8
+    SWAP               3, 6, 9
+    SWAP              10, 14
+    SWAP              11, 22
+%endif
+%endif
+
+    ; load L/E/I/H
+    vpbroadcastd     m15, [pb_1]
+%ifidn %2, v
+    movu              m1, [lq]
+    movu              m0, [lq+l_strideq]
+%else
+    kmovw             k1, k6
+    vpgatherdd    m0{k1}, [lq+m20+4]
+    kmovw             k1, k6
+    vpgatherdd    m1{k1}, [lq+m20+0]
+%endif
+    pxor              m2, m2
+    pcmpeqb           k1, m0, m2
+    vmovdqu8      m0{k1}, m1                ; l[x][] ? l[x][] : l[x-stride][]
+    pshufb            m0, pbshuf            ; l[x][0]
+    vpcmpub           k3, m0, m2, 4 ; neq   ; L
+    psrlq             m2, m0, [lutq+128]
+    pand              m2, [pb_63]{bcstd}
+    vpbroadcastb      m1, [lutq+136]
+    pminub            m2, m1
+    pmaxub            m2, m15               ; I
+    gf2p8affineqb     m1, m0, [shift4]{bcstq}, 0 ; H
+    paddd             m0, [pb_2]{bcstd}
+    paddb             m0, m0
+    paddb             m0, m2                ; E
+
+    ABSSUB            m8, m3, m4, m9        ; abs(p1-p0)
+    ABSSUB            m9, m5, m6, m10       ; abs(q1-q0)
+    pmaxub            m8, m9
+    vpcmpub           k1, m8, m1, 6 ; gt    ; hev
+%if %1 != 4
+ %if %1 == 6
+    ABSSUB            m9, m13, m4, m10      ; abs(p2-p0)
+    pmaxub            m9, m8
+ %else
+    ABSSUB            m9, m25, m4, m10      ; abs(p3-p0)
+    pmaxub            m9, m8
+    ABSSUB           m10, m13, m4, m11      ; abs(p2-p0)
+    pmaxub            m9, m10
+ %endif
+    ABSSUB           m10, m5,  m14, m11     ; abs(q2-q0)
+    pmaxub            m9, m10
+ %if %1 != 6
+    ABSSUB           m10, m5,  m22, m11     ; abs(q3-q0)
+    pmaxub            m9, m10
+ %endif
+    vpcmpub       k2{k3}, m9, m15, 2 ; le   ; flat8in
+ %if %1 == 6
+    ABSSUB           m10, m13, m3,  m1      ; abs(p2-p1)
+ %else
+    ABSSUB           m10, m25, m13, m11     ; abs(p3-p2)
+    ABSSUB           m11, m13, m3,  m1      ; abs(p2-p1)
+    pmaxub           m10, m11
+    ABSSUB           m11, m14, m22, m1      ; abs(q3-q2)
+    pmaxub           m10, m11
+ %endif
+    ABSSUB           m11, m14, m6,  m1      ; abs(q2-q1)
+    pmaxub           m10, m11
+ %if %1 == 16
+    vpbroadcastd     m11, [maskq+8]
+    por              m11, [maskq+4]{bcstd}
+ %else
+    vpbroadcastd     m11, [maskq+4]
+ %endif
+    vptestmd          k4, m11, pbmask
+    vmovdqa32 m10{k4}{z}, m10               ; only apply fm-wide to wd>4 blocks
+    pmaxub            m8, m10
+%endif
+    vpcmpub       k3{k3}, m8, m2, 2 ; le
+    ABSSUB           m10, m3, m6, m11       ; abs(p1-q1)
+    ABSSUB           m11, m4, m5, m2        ; abs(p0-q0)
+    paddusb          m11, m11
+    gf2p8affineqb    m10, m10, [shift1]{bcstq}, 0
+    paddusb          m10, m11               ; abs(p0-q0)*2+(abs(p1-q1)>>1)
+    vpcmpub       k3{k3}, m10, m0, 2        ; abs(p0-q0)*2+(abs(p1-q1)>>1) <= E
+
+%if %1 == 16
+    ABSSUB            m1, m16, m4, m2
+    ABSSUB            m2, m17, m4, m10
+    pmaxub            m1, m2
+    ABSSUB            m2, m18, m4, m10
+    pmaxub            m1, m2
+    ABSSUB            m2, m29, m5, m10
+    pmaxub            m1, m2
+    ABSSUB            m2, m30, m5, m10
+    pmaxub            m1, m2
+    ABSSUB            m2, m31, m5, m10
+    pmaxub            m1, m2
+    kandq             k2, k2, k3
+    vpcmpub       k4{k2}, m1, m15, 2        ; flat8in & flat8out
+    vpbroadcastd      m2, [maskq+8]
+    vptestmd          k5, m2, pbmask
+    vpmovm2d          m7, k5
+    vptestmb      k4{k4}, m7, m7            ; flat16 & fm
+    por              m10, m2, [maskq+4]{bcstd}
+    vptestmd          k5, m10, pbmask
+    vpmovm2d          m7, k5
+    vptestmb      k2{k2}, m7, m7            ; flat8in
+    por               m2, m10, [maskq+0]{bcstd}
+    vptestmd          k5, m2, pbmask
+    vpmovm2d          m7, k5
+    vptestmb      k3{k3}, m7, m7
+    kandnq            k3, k2, k3            ; fm & !flat8 & !flat16
+    kandnq            k2, k4, k2            ; flat8 & !flat16
+%elif %1 != 4
+    vpbroadcastd      m0, [maskq+4]
+    vptestmd          k4, m0, pbmask
+    vpmovm2d          m7, k4
+    vptestmb      k2{k2}, m7, m7
+    kandq             k2, k2, k3            ; flat8 & fm
+    por               m0, [maskq+0]{bcstd}
+    vptestmd          k4, m0, pbmask
+    vpmovm2d          m7, k4
+    vptestmb      k3{k3}, m7, m7
+    kandnq            k3, k2, k3            ; fm & !flat8
+%else
+ %ifidn %2, v
+    vptestmd          k4, pbmask, [maskq+0]{bcstd}
+ %else
+    vpbroadcastd      m0, [maskq+0]
+    vptestmd          k4, m0, pbmask
+ %endif
+    vpmovm2d          m7, k4
+    vptestmb      k3{k3}, m7, m7            ; fm
+%endif
+
+    ; short filter
+%if %1 >= 8
+    SWAP             m23, m15
+%endif
+    vpbroadcastd     m15, [pb_3]
+    vpbroadcastd      m0, [pb_4]
+    vpbroadcastd     m12, [pb_16]
+    vpbroadcastd      m1, [pb_64]
+    pxor              m3, pb128
+    pxor              m6, pb128
+    psubsb    m10{k1}{z}, m3, m6            ; f=iclip_diff(p1-q1)&hev
+    pxor              m4, pb128
+    pxor              m5, pb128
+    psubsb           m11, m5, m4
+    paddsb           m10, m11
+    paddsb           m10, m11
+    paddsb    m10{k3}{z}, m10, m11          ; f=iclip_diff(3*(q0-p0)+f)&fm
+    paddsb            m8, m10, m15
+    paddsb           m10, m0
+    gf2p8affineqb     m8, m8, [shift3]{bcstq}, 16
+    gf2p8affineqb    m10, m10, [shift3]{bcstq}, 16
+    psubb             m8, m12               ; f2
+    psubb            m10, m12               ; f1
+    paddsb            m4, m8
+    psubsb            m5, m10
+    pxor              m4, pb128
+    pxor              m5, pb128
+    ;
+    pxor             m10, pb128
+    pxor              m8, m8
+    pavgb             m8, m10               ; f=(f1+1)>>1
+    psubb             m8, m1
+    knotq             k1, k1
+    paddsb        m3{k1}, m3, m8
+    psubsb        m6{k1}, m6, m8
+    pxor              m3, pb128
+    pxor              m6, pb128
+
+%if %1 == 16
+    ; flat16 filter
+%ifidn %2, v
+    lea               t0, [dstq+mstrideq*8]
+%endif
+    SWAP             m24, m16, m14
+    SWAP              m2, m17, m22
+    SWAP              m7, m18
+
+    ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0 [p5/p4/p2/p1/p0/q0][p6/p3] A
+    ; write -6
+    vpbroadcastd      m1, [pb_7_1]
+    vpbroadcastd     m12, [pb_2]
+    punpcklbw        m14, m24, m25
+    punpckhbw        m22, m24, m25
+    pmaddubsw        m10, m14, m1
+    pmaddubsw        m11, m22, m1          ; p6*7+p3
+    punpcklbw         m8, m2, m7
+    punpckhbw         m9, m2, m7
+    pmaddubsw         m8, m12
+    pmaddubsw         m9, m12
+    paddw            m10, m8
+    paddw            m11, m9                ; p6*7+p5*2+p4*2+p3
+%ifidn %2, h
+    vpbroadcastd     m27, [pw_2048]
+    vpbroadcastd      m1, [pb_m1_1]
+ %define pw2048 m27
+ %define pbm1_1 m1
+%endif
+    punpcklbw         m8, m13, m3
+    punpckhbw         m9, m13, m3
+    pmaddubsw         m8, m23
+    pmaddubsw         m9, m23
+    paddw            m10, m8
+    paddw            m11, m9                ; p6*7+p5*2+p4*2+p3+p2+p1
+    punpcklbw         m8, m4, m5
+    punpckhbw         m9, m4, m5
+    pmaddubsw         m8, m23
+    pmaddubsw         m9, m23
+    paddw            m10, m8
+    paddw            m11, m9                ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0
+    pmulhrsw          m8, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m8, m9
+%ifidn %2, v
+    vmovdqu8 [t0+strideq*2]{k4}, m8         ; p5
+%else
+    vpblendmb     m8{k4}, m2, m8
+    mova      [rsp+1*64], m8
+%endif
+
+    ; sub p6*2, add p3/q1 [reuse p6/p3 from A][-p6,+q1|save] B
+    ; write -5
+    pmaddubsw        m14, pbm1_1
+    pmaddubsw        m22, pbm1_1
+    paddw            m10, m14
+    paddw            m11, m22               ; p6*6+p5*2+p4*2+p3*2+p2+p1+p0+q0
+    punpcklbw         m8, m24, m6
+    punpckhbw         m9, m24, m6
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p6*5+p5*2+p4*2+p3*2+p2+p1+p0+q0+q1
+    SWAP             m18, m8
+    SWAP             m23, m9
+    pmulhrsw          m8, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m8, m9
+%ifidn %2, v
+    vmovdqu8 [t0+stride3q]{k4}, m8          ; p4
+%else
+    vpblendmb     m8{k4}, m7, m8
+    mova      [rsp+2*64], m8
+%endif
+
+    ; sub p6/p5, add p2/q2 [-p6,+p2][-p5,+q2|save] C
+    ; write -4
+    SWAP             m14, m16
+    punpcklbw         m8, m24, m13
+    punpckhbw         m9, m24, m13
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p6*4+p5*2+p4*2+p3*2+p2*2+p1+p0+q0+q1
+    punpcklbw         m8, m2, m14
+    punpckhbw         m2, m14
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m2, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m2                ; p6*4+p5+p4*2+p3*2+p2*2+p1+p0+q0+q1+q2
+    SWAP             m16, m8
+    pmulhrsw          m8, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m8, m9
+%ifidn %2, v
+    vmovdqu8 [t0+strideq*4]{k4}, m8         ; p3
+%else
+    vpblendmb     m8{k4}, m25, m8
+    mova      [rsp+3*64], m8
+%endif
+
+    ; sub p6/p4, add p1/q3 [-p6,+p1][-p4,+q3|save] D
+    ; write -3
+    SWAP             m22, m17
+    punpcklbw         m8, m24, m3
+    punpckhbw         m9, m24, m3
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p6*3+p5+p4*2+p3*2+p2*2+p1*2+p0+q0+q1+q2
+    punpcklbw         m8, m7, m22
+    punpckhbw         m7, m22
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m7, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m7                ; p6*3+p5+p4+p3*2+p2*2+p1*2+p0+q0+q1+q2+q3
+    SWAP             m17, m8
+    pmulhrsw          m8, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m8, m9
+    vpblendmb    m15{k4}, m13, m8           ; don't clobber p2/m13 since we need it in F
+
+    ; sub p6/p3, add p0/q4 [-p6,+p0][-p3,+q4|save] E
+    ; write -2
+%ifidn %2, v
+    lea               t0, [dstq+strideq*4]
+%endif
+    punpcklbw         m8, m24, m4
+    punpckhbw         m9, m24, m4
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p6*2+p5+p4+p3*2+p2*2+p1*2+p0*2+q0+q1+q2+q3
+    punpcklbw         m8, m25, m29
+    punpckhbw         m9, m25, m29
+    SWAP             m26, m29
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p6*2+p5+p4+p3+p2*2+p1*2+p0*2+q0+q1+q2+q3+q4
+    SWAP             m29, m8
+    SWAP              m0, m9
+    pmulhrsw          m8, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m8, m9
+    vpblendmb    m12{k4}, m3, m8            ; don't clobber p1/m3 since we need it in G
+
+    ; sub p6/p2, add q0/q5 [-p6,+q0][-p2,+q5|save] F
+    ; write -1
+%ifidn %2, h
+    SWAP             m28, m24
+    punpcklbw         m8, m28, m5
+    punpckhbw        m24, m28, m5
+%else
+    punpcklbw         m8, m24, m5
+    punpckhbw        m24, m5
+%endif
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw        m24, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m24               ; p6+p5+p4+p3+p2*2+p1*2+p0*2+q0*2+q1+q2+q3+q4
+    punpcklbw        m24, m13, m30
+    punpckhbw         m9, m13, m30
+%ifidn %2, h
+    SWAP             m27, m30
+%endif
+    SWAP             m13, m15
+    pmaddubsw        m24, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m24
+    paddw            m11, m9                ; p6+p5+p4+p3+p2+p1*2+p0*2+q0*2+q1+q2+q3+q4+q5
+    SWAP             m30, m24
+    SWAP             m15, m9
+%ifidn %2, h
+    SWAP              m9, m24
+ %define pw2048 m9
+%endif
+    pmulhrsw         m24, m10, pw2048
+    pmulhrsw          m8, m11, pw2048
+    paddw            m10, m18               ; p5+p4+p3+p2+p1*2+p0*2+q0*2+q1*2+q2+q3+q4+q5
+    paddw            m11, m23
+    packuswb         m24, m8
+    punpcklbw         m8, m3, m31
+    pmaddubsw         m8, pbm1_1
+    paddw            m10, m8                ; p5+p4+p3+p2+p1+p0*2+q0*2+q1*2+q2+q3+q4+q5+q6
+    SWAP             m18, m8
+    pmulhrsw          m8, m10, pw2048
+    paddw            m10, m16               ; p4+p3+p2+p1+p0*2+q0*2+q1*2+q2*2+q3+q4+q5+q6
+%ifidn %2, h
+    SWAP             m16, m9
+ %define pw2048 m16
+%endif
+    punpckhbw         m9, m3, m31
+    SWAP              m3, m12
+    pmaddubsw         m9, pbm1_1
+    paddw            m11, m9                ; p5+p4+p3+p2+p1+p0*2+q0*2+q1*2+q2+q3+q4+q5+q6
+    SWAP             m23, m9
+    pmulhrsw          m9, m11, pw2048
+    paddw            m11, m2                ; p4+p3+p2+p1+p0*2+q0*2+q1*2+q2*2+q3+q4+q5+q6
+%ifidn %2, h
+    SWAP              m2, m1
+ %define pbm1_1 m2
+%endif
+    vpblendmb     m1{k4}, m4, m24           ; don't clobber p0/m4 since we need it in H
+
+    ; sub p6/p1, add q1/q6 [reuse -p6,+q1 from B][-p1,+q6|save] G
+    ; write +0
+    SWAP             m24, m31               ; q6
+    packuswb          m8, m9
+%ifidn %2, h
+    SWAP             m31, m2
+ %define pbm1_1 m31
+%endif
+    vpblendmb    m12{k4}, m5, m8            ; don't clobber q0/m5 since we need it in I
+
+    ; sub p5/p0, add q2/q6 [reuse -p5,+q2 from C][-p0,+q6] H
+    ; write +1
+    punpcklbw         m8, m4, m24
+    punpckhbw         m2, m4, m24
+    SWAP              m4, m1
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m2, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m2                ; p4+p3+p2+p1+p0+q0*2+q1*2+q2*2+q3+q4+q5+q6*2
+    pmulhrsw          m2, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m2, m9
+    vpblendmb     m2{k4}, m6, m2            ; don't clobber q1/m6 since we need it in K
+
+    ; sub p4/q0, add q3/q6 [reuse -p4,+q3 from D][-q0,+q6] I
+    ; write +2
+    paddw            m10, m17               ; p3+p2+p1+p0+q0*2+q1*2+q2*2+q3*2+q4+q5+q6*2
+    paddw            m11, m7
+    punpcklbw         m8, m5, m24
+    punpckhbw         m9, m5, m24
+    SWAP              m5, m12
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p3+p2+p1+p0+q0+q1*2+q2*2+q3*2+q4+q5+q6*3
+    pmulhrsw          m7, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m7, m9
+    vpblendmb     m7{k4}, m14, m7           ; don't clobber q2/m14 since we need it in K
+
+    ; sub p3/q1, add q4/q6 [reuse -p3,+q4 from E][-q1,+q6] J
+    ; write +3
+    paddw            m10, m29               ; p2+p1+p0+q0+q1*2+q2*2+q3*2+q4*2+q5+q6*3
+    paddw            m11, m0
+    punpcklbw         m8, m6, m24
+    punpckhbw         m9, m6, m24
+    SWAP               2, 6
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p2+p1+p0+q0+q1+q2*2+q3*2+q4*2+q5+q6*4
+    pmulhrsw          m8, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m8, m9
+%ifidn %2, v
+    vmovdqu8 [t0+mstrideq]{k4}, m8
+%else
+    SWAP             m29, m16
+ %define pw2048 m29
+    vpblendmb    m16{k4}, m22, m8
+%endif
+
+    ; sub p2/q2, add q5/q6 [reuse -p2,+q5 from F][-q2,+q6] K
+    ; write +4
+    paddw            m10, m30               ; p1+p0+q0+q1+q2*2+q3*2+q4*2+q5*2+q6*4
+    paddw            m11, m15
+%ifidn %2, h
+    SWAP             m15, m8
+%endif
+    punpcklbw         m8, m14, m24
+    punpckhbw         m9, m14, m24
+    SWAP              14, 7
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p1+p0+q0+q1+q2+q3*2+q4*2+q5*2+q6*5
+    pmulhrsw          m8, m10, pw2048
+    pmulhrsw          m9, m11, pw2048
+    packuswb          m8, m9
+%ifidn %2, v
+    vmovdqu8 [t0+strideq*0]{k4}, m8         ; q4
+%else
+    vpblendmb    m17{k4}, m26, m8
+%endif
+
+    ; sub p1/q3, add q6*2 [reuse -p1,+q6 from G][-q3,+q6] L
+    ; write +5
+    paddw            m10, m18               ; p1+p0+q0+q1+q2*2+q3*2+q4*2+q5*2+q6*4
+    paddw            m11, m23
+    punpcklbw         m8, m22, m24
+    punpckhbw         m9, m22, m24
+    SWAP             m30, m24
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw         m9, pbm1_1
+    paddw            m10, m8
+    paddw            m11, m9                ; p1+p0+q0+q1+q2+q3*2+q4*2+q5*2+q6*5
+    pmulhrsw         m10, pw2048
+    pmulhrsw         m11, pw2048
+    packuswb         m10, m11
+%ifidn %2, v
+    vmovdqu8 [t0+strideq*1]{k4}, m10        ; q5
+%else
+    vmovdqu8     m27{k4}, m10
+%endif
+
+%ifidn %2, v
+    lea               t0, [dstq+mstrideq*4]
+%endif
+%endif
+
+%if %1 >= 8
+    ; flat8 filter
+    vpbroadcastd      m9, [pb_3_1]
+    vpbroadcastd     m10, [pb_2_1]
+%if %1 == 16
+    vpbroadcastd     m23, [pb_1]
+    vpbroadcastd      m0, [pb_4]
+%elifidn %2, h
+    vpbroadcastd     m31, [pb_m1_1]
+ %define pbm1_1 m31
+%endif
+    punpcklbw        m24, m25, m3
+    punpckhbw        m26, m25, m3
+    pmaddubsw         m2, m24, m9
+    pmaddubsw         m7, m26, m9           ; 3 * p3 + p1
+    punpcklbw         m8, m13, m4
+    punpckhbw        m11, m13, m4
+    pmaddubsw         m8, m10
+    pmaddubsw        m11, m10
+    paddw             m2, m8
+    paddw             m7, m11               ; 3 * p3 + 2 * p2 + p1 + p0
+    punpcklbw         m8, m5, m0
+    punpckhbw        m11, m5, m0
+    pmaddubsw         m8, m23
+    pmaddubsw        m11, m23
+    paddw             m2, m8
+    paddw             m7, m11               ; 3 * p3 + 2 * p2 + p1 + p0 + q0 + 4
+    psrlw             m8, m2, 3
+    psrlw            m11, m7, 3
+    packuswb          m8, m11
+%if is_h || %1 == 16
+    vpblendmb    m10{k2}, m13, m8           ; p2
+%endif
+%ifidn %2, v
+ %if %1 == 8
+    vmovdqu8 [t0+strideq*1]{k2}, m8
+ %else
+    mova  [t0+strideq*1], m10
+ %endif
+%endif
+
+    pmaddubsw         m8, m24, pbm1_1
+    pmaddubsw        m11, m26, pbm1_1
+    paddw             m2, m8
+    paddw             m7, m11
+    punpcklbw         m8, m13, m6
+    punpckhbw        m11, m13, m6
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw        m11, pbm1_1
+    paddw             m2, m8
+    paddw             m7, m11               ; 2 * p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4
+    psrlw             m8, m2, 3
+    psrlw            m11, m7, 3
+    packuswb          m8, m11
+    vpblendmb     m8{k2}, m3, m8            ; p1
+%ifidn %2, v
+    mova  [t0+strideq*2], m8
+%else
+    SWAP             m18, m8
+%endif
+
+    pmaddubsw        m24, m23
+    pmaddubsw        m26, m23
+    psubw             m2, m24
+    psubw             m7, m26
+    punpcklbw         m8, m4, m14
+    punpckhbw        m11, m4, m14
+    pmaddubsw         m8, m23
+    pmaddubsw        m11, m23
+    paddw             m2, m8
+    paddw             m7, m11               ; p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4
+    psrlw             m8, m2, 3
+    psrlw            m11, m7, 3
+    packuswb          m8, m11
+    vpblendmb     m8{k2}, m4, m8            ; p0
+%ifidn %2, v
+    mova   [t0+stride3q], m8
+%else
+    SWAP             m29, m8
+%endif
+
+    punpcklbw        m24, m5, m22
+    punpckhbw        m26, m5, m22
+    pmaddubsw         m8, m24, m23
+    pmaddubsw        m11, m26, m23
+    paddw             m2, m8
+    paddw             m7, m11
+    punpcklbw         m8, m4, m25
+    punpckhbw        m11, m4, m25
+    pmaddubsw         m8, m23
+    pmaddubsw        m11, m23
+    psubw             m2, m8
+    psubw             m7, m11               ; p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4
+    psrlw             m8, m2, 3
+    psrlw            m11, m7, 3
+    packuswb          m8, m11
+    vpblendmb    m11{k2}, m5, m8            ; q0
+%ifidn %2, v
+    mova [dstq+strideq*0], m11
+%endif
+
+    pmaddubsw        m24, pbm1_1
+    pmaddubsw        m26, pbm1_1
+    paddw             m2, m24
+    paddw             m7, m26
+    punpcklbw         m8, m13, m6
+    punpckhbw        m13, m6
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw        m13, pbm1_1
+    paddw             m2, m8
+    paddw             m7, m13               ; p1 + p0 + q0 + 2 * q1 + q2 + 2 * q3 + 4
+    psrlw             m8, m2, 3
+    psrlw            m13, m7, 3
+    packuswb          m8, m13
+    vpblendmb    m13{k2}, m6, m8            ; q1
+%ifidn %2, v
+    mova [dstq+strideq*1], m13
+%endif
+
+    punpcklbw        m24, m3, m6
+    punpckhbw        m26, m3, m6
+    pmaddubsw        m24, m23
+    pmaddubsw        m26, m23
+    psubw             m2, m24
+    psubw             m7, m26
+    punpcklbw        m24, m14, m22
+    punpckhbw        m26, m14, m22
+    pmaddubsw        m24, m23
+    pmaddubsw        m26, m23
+    paddw             m2, m24
+    paddw             m7, m26               ; p0 + q0 + q1 + q2 + 2 * q2 + 3 * q3 + 4
+    psrlw             m2, 3
+    psrlw             m7, 3
+    packuswb          m2, m7
+%if is_h || %1 == 16
+    vpblendmb     m2{k2}, m14, m2           ; q2
+%endif
+%ifidn %2, v
+ %if %1 == 8
+    vmovdqu8 [dstq+strideq*2]{k2}, m2
+ %else
+    mova [dstq+strideq*2], m2
+ %endif
+%endif
+
+%ifidn %2, h
+    SWAP             m24, m18
+    SWAP             m26, m29
+%if %1 == 8
+    ; 16x8 transpose
+    punpcklbw         m3, m25, m10
+    punpckhbw        m25, m10
+    punpcklbw        m10, m24, m26
+    punpckhbw        m24, m26
+    punpcklbw        m26, m11, m13
+    punpckhbw        m11, m13
+    punpcklbw        m13, m2, m22
+    punpckhbw         m2, m22
+    ;
+    punpcklwd        m22, m3, m10
+    punpckhwd         m3, m10
+    punpcklwd        m10, m25, m24
+    punpckhwd        m25, m24
+    punpcklwd        m24, m26, m13
+    punpckhwd        m26, m13
+    punpcklwd        m13, m11, m2
+    punpckhwd        m11, m2
+    ;
+    punpckldq         m2, m22, m24
+    punpckhdq        m22, m24
+    punpckldq        m24, m3, m26
+    punpckhdq         m3, m26
+    punpckldq        m26, m10, m13
+    punpckhdq        m10, m13
+    punpckldq        m13, m25, m11
+    punpckhdq        m25, m11
+    ; write 8x32
+    vpbroadcastd    ym16, strided
+    pmulld          ym16, [hmulD]
+    lea               t1, [dstq+strideq*2]
+    lea               t2, [dstq+strideq*4]
+    lea               t3, [t1  +strideq*4]
+    lea               t0, [dstq+strideq*8]
+    kmovb             k1, k6
+    kmovb             k2, k6
+    kmovb             k3, k6
+    kmovb             k4, k6
+    vpscatterdq [dstq+ym16-4]{k1}, m2
+    vpscatterdq [t1  +ym16-4]{k2}, m22
+    vpscatterdq [t2  +ym16-4]{k3}, m24
+    vpscatterdq [t3  +ym16-4]{k4}, m3
+    lea               t1, [t0+strideq*2]
+    lea               t2, [t0+strideq*4]
+    lea               t3, [t1+strideq*4]
+    kmovb             k1, k6
+    kmovb             k2, k6
+    kmovb             k3, k6
+    kmovb             k4, k6
+    vpscatterdq [t0+ym16-4]{k1}, m26
+    vpscatterdq [t1+ym16-4]{k2}, m10
+    vpscatterdq [t2+ym16-4]{k3}, m13
+    vpscatterdq [t3+ym16-4]{k4}, m25
+%else
+    ; 16x16 transpose and store
+    SWAP               5, 10, 2
+    SWAP               6, 24
+    SWAP               7, 26
+    SWAP               8, 11
+    SWAP               9, 13
+    mova             m24, [rsp+0*64]
+    SWAP             m26, m28
+    mova              m2, [rsp+1*64]
+    mova              m3, [rsp+2*64]
+    mova              m4, [rsp+3*64]
+    SWAP             m11, m16
+    SWAP             m25, m17
+    SWAP             m13, m27
+    SWAP             m14, m30
+    TRANSPOSE_16X16B 1, 0, [rsp+4*64]
+    movu [dstq+strideq*0-8], xm24
+    movu [dstq+strideq*1-8], xm26
+    movu [dstq+strideq*2-8], xm2
+    movu [dstq+stride3q -8], xm3
+    lea               t0, [dstq+strideq*4]
+    movu [t0+strideq*0-8], xm4
+    movu [t0+strideq*1-8], xm5
+    movu [t0+strideq*2-8], xm6
+    movu [t0+stride3q -8], xm7
+    lea               t0, [t0+strideq*4]
+    movu [t0+strideq*0-8], xm8
+    movu [t0+strideq*1-8], xm9
+    movu [t0+strideq*2-8], xm10
+    movu [t0+stride3q -8], xm11
+    lea               t0, [t0+strideq*4]
+    movu [t0+strideq*0-8], xm25
+    movu [t0+strideq*1-8], xm13
+    movu [t0+strideq*2-8], xm14
+    movu [t0+stride3q -8], xm22
+    lea               t0, [t0+strideq*4]
+    vextracti128 [t0+strideq*0-8], ym24, 1
+    vextracti128 [t0+strideq*1-8], ym26, 1
+    vextracti128 [t0+strideq*2-8], ym2, 1
+    vextracti128 [t0+stride3q -8], ym3, 1
+    lea               t0, [t0+strideq*4]
+    vextracti128 [t0+strideq*0-8], ym4, 1
+    vextracti128 [t0+strideq*1-8], ym5, 1
+    vextracti128 [t0+strideq*2-8], ym6, 1
+    vextracti128 [t0+stride3q -8], ym7, 1
+    lea               t0, [t0+strideq*4]
+    vextracti128 [t0+strideq*0-8], ym8, 1
+    vextracti128 [t0+strideq*1-8], ym9, 1
+    vextracti128 [t0+strideq*2-8], ym10, 1
+    vextracti128 [t0+stride3q -8], ym11, 1
+    lea               t0, [t0+strideq*4]
+    vextracti128 [t0+strideq*0-8], ym25, 1
+    vextracti128 [t0+strideq*1-8], ym13, 1
+    vextracti128 [t0+strideq*2-8], ym14, 1
+    vextracti128 [t0+stride3q -8], ym22, 1
+    lea               t0, [t0+strideq*4]
+    vextracti32x4 [t0+strideq*0-8], m24, 2
+    vextracti32x4 [t0+strideq*1-8], m26, 2
+    vextracti32x4 [t0+strideq*2-8], m2, 2
+    vextracti32x4 [t0+stride3q -8], m3, 2
+    lea               t0, [t0+strideq*4]
+    vextracti32x4 [t0+strideq*0-8], m4, 2
+    vextracti32x4 [t0+strideq*1-8], m5, 2
+    vextracti32x4 [t0+strideq*2-8], m6, 2
+    vextracti32x4 [t0+stride3q -8], m7, 2
+    lea               t0, [t0+strideq*4]
+    vextracti32x4 [t0+strideq*0-8], m8, 2
+    vextracti32x4 [t0+strideq*1-8], m9, 2
+    vextracti32x4 [t0+strideq*2-8], m10, 2
+    vextracti32x4 [t0+stride3q -8], m11, 2
+    lea               t0, [t0+strideq*4]
+    vextracti32x4 [t0+strideq*0-8], m25, 2
+    vextracti32x4 [t0+strideq*1-8], m13, 2
+    vextracti32x4 [t0+strideq*2-8], m14, 2
+    vextracti32x4 [t0+stride3q -8], m22, 2
+    lea               t0, [t0+strideq*4]
+    vextracti32x4 [t0+strideq*0-8], m24, 3
+    vextracti32x4 [t0+strideq*1-8], m26, 3
+    vextracti32x4 [t0+strideq*2-8], m2, 3
+    vextracti32x4 [t0+stride3q -8], m3, 3
+    lea               t0, [t0+strideq*4]
+    vextracti32x4 [t0+strideq*0-8], m4, 3
+    vextracti32x4 [t0+strideq*1-8], m5, 3
+    vextracti32x4 [t0+strideq*2-8], m6, 3
+    vextracti32x4 [t0+stride3q -8], m7, 3
+    lea               t0, [t0+strideq*4]
+    vextracti32x4 [t0+strideq*0-8], m8, 3
+    vextracti32x4 [t0+strideq*1-8], m9, 3
+    vextracti32x4 [t0+strideq*2-8], m10, 3
+    vextracti32x4 [t0+stride3q -8], m11, 3
+    lea               t0, [t0+strideq*4]
+    vextracti32x4 [t0+strideq*0-8], m25, 3
+    vextracti32x4 [t0+strideq*1-8], m13, 3
+    vextracti32x4 [t0+strideq*2-8], m14, 3
+    vextracti32x4 [t0+stride3q -8], m22, 3
+%endif
+%endif
+
+%elif %1 == 6
+    ; flat6 filter
+    vpbroadcastd     m15, [pb_3_1]
+    vpbroadcastd     m12, [pb_2]
+    punpcklbw         m8, m13, m5
+    punpckhbw        m11, m13, m5
+    pmaddubsw         m0, m8, m15
+    pmaddubsw         m1, m11, m15
+    punpcklbw         m7, m4, m3
+    punpckhbw        m10, m4, m3
+    pmaddubsw         m2, m7, m12
+    pmaddubsw        m12, m10, m12
+%ifidn %2, h
+    vpbroadcastd     m15, [pb_m1_1]
+ %define pbm1_1 m15
+%endif
+    paddw             m0, m2
+    paddw             m1, m12
+    pmulhrsw          m2, m0, m16
+    pmulhrsw         m12, m1, m16
+    packuswb          m2, m12
+    vpblendmb     m2{k2}, m3, m2            ; p1
+%ifidn %2, v
+    mova  [t0+strideq*2], m2
+%endif
+
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw        m11, pbm1_1
+    paddw             m0, m8
+    paddw             m1, m11
+    punpcklbw         m8, m13, m6
+    punpckhbw        m11, m13, m6
+    pmaddubsw         m8, pbm1_1
+    pmaddubsw        m11, pbm1_1
+    paddw             m0, m8
+    paddw             m1, m11
+    pmulhrsw         m12, m0, m16
+    pmulhrsw         m13, m1, m16
+    packuswb         m12, m13
+    vpblendmb    m12{k2}, m4, m12           ; p0
+%ifidn %2, v
+    mova   [t0+stride3q], m12
+%endif
+
+    vpbroadcastd      m9, [pb_m1_2]
+    vpbroadcastd      m4, [pb_m1_0]
+    paddw             m0, m8
+    paddw             m1, m11
+    punpcklbw         m8, m3, m14
+    punpckhbw        m11, m3, m14
+    pmaddubsw        m14, m8, pbm1_1
+    pmaddubsw        m13, m11, pbm1_1
+    paddw             m0, m14
+    paddw             m1, m13
+    pmulhrsw         m14, m0, m16
+    pmulhrsw         m13, m1, m16
+    packuswb         m14, m13
+    vpblendmb    m14{k2}, m5, m14           ; q0
+%ifidn %2, v
+    mova [dstq+strideq*0], m14
+%endif
+
+    pmaddubsw         m8, m9
+    pmaddubsw        m11, m9
+    paddw             m0, m8
+    paddw             m1, m11
+    pmaddubsw         m7, m4
+    pmaddubsw        m10, m4
+    paddw             m0, m7
+    paddw             m1, m10
+    pmulhrsw          m0, m16
+    pmulhrsw          m1, m16
+    packuswb          m0, m1
+    vpblendmb     m0{k2}, m6, m0            ; q1
+%ifidn %2, v
+    mova [dstq+strideq*1], m0
+%else
+    TRANSPOSE_16x4_AND_WRITE_4x32 2, 12, 14, 0, 1
+%endif
+%else ; %1 == 4
+%ifidn %2, v
+    mova  [t0+strideq*0], m3                ; p1
+    mova  [t0+strideq*1], m4                ; p0
+    mova  [t0+strideq*2], m5                ; q0
+    mova  [t0+stride3q ], m6                ; q1
+%else
+    TRANSPOSE_16x4_AND_WRITE_4x32 3, 4, 5, 6, 7
+%endif
+%endif
+%endmacro
+
+%define k7 k6
+
+INIT_ZMM avx512icl
+cglobal lpf_v_sb_y_8bpc, 7, 10, 32, dst, stride, mask, l, l_stride, \
+                                    lut, w, stride3, mstride
+ DECLARE_REG_TMP 9
+    shl        l_strideq, 2
+    sub               lq, l_strideq
+    mov         mstrideq, strideq
+    neg         mstrideq
+    lea         stride3q, [strideq*3]
+    mova             m21, [pb_4x0_4x4_4x8_4x12]
+    mova             m20, [pb_mask]
+    vpbroadcastd     m19, [pb_128]
+    vpbroadcastd     m28, [pb_m1_1]
+    vpbroadcastd     m27, [pw_2048]
+ %define pbshuf m21
+ %define pbmask m20
+ %define pb128  m19
+ %define pbm1_1 m28
+ %define pw2048 m27
+
+.loop:
+    cmp   word [maskq+8], 0                 ; vmask[2]
+    je .no_flat16
+
+    FILTER            16, v
+    jmp .end
+
+.no_flat16:
+    cmp   word [maskq+4], 0                 ; vmask[1]
+    je .no_flat
+
+    FILTER             8, v
+    jmp .end
+
+.no_flat:
+    cmp   word [maskq+0], 0                 ; vmask[0]
+    je .end
+
+    call .v4
+
+.end:
+    add               lq, 64
+    add             dstq, 64
+    add            maskq, 2
+    sub               wd, 16
+    jg .loop
+    RET
+ALIGN function_align
+RESET_MM_PERMUTATION
+.v4:
+    FILTER             4, v
+    ret
+
+cglobal lpf_h_sb_y_8bpc, 7, 13, 32, 5*64, dst, stride, mask, l, l_stride, \
+                                          lut, h, stride3, stride8
+ DECLARE_REG_TMP 9, 10, 11, 12
+    shl        l_strideq, 2
+    sub               lq, 4
+    lea         stride3q, [strideq*3]
+    lea         stride8q, [strideq*8]
+    kxnorw            k6, k6, k6
+    vpbroadcastd     m19, strided
+    vpbroadcastd     m20, l_strided
+    pmulld           m21, m19, [hmulA]
+    pmulld           m20, [hmulB]
+    pmulld           m19, [hmulC]
+ %define pbshuf [pb_4x0_4x4_4x8_4x12]
+ %define pbmask [pb_mask]
+ %define pb128  [pb_128]{bcstd}
+    shl        l_strideq, 1
+
+.loop:
+    cmp   word [maskq+8], 0                 ; vmask[2]
+    je .no_flat16
+
+    FILTER            16, h
+    jmp .end
+
+.no_flat16:
+    cmp   word [maskq+4], 0                 ; vmask[1]
+    je .no_flat
+
+    FILTER             8, h
+    jmp .end
+
+.no_flat:
+    cmp   word [maskq+0], 0                 ; vmask[0]
+    je .end
+
+    call .h4
+
+.end:
+    lea               lq, [lq+l_strideq*8]
+    lea             dstq, [dstq+stride8q*8]
+    add            maskq, 2
+    sub               hd, 16
+    jg .loop
+    RET
+ALIGN function_align
+RESET_MM_PERMUTATION
+.h4:
+    FILTER             4, h
+    ret
+
+cglobal lpf_v_sb_uv_8bpc, 7, 10, 22, dst, stride, mask, l, l_stride, \
+                                     lut, w, stride3, mstride
+ DECLARE_REG_TMP 9
+    shl        l_strideq, 2
+    sub               lq, l_strideq
+    mov         mstrideq, strideq
+    neg         mstrideq
+    lea         stride3q, [strideq*3]
+    mova             m21, [pb_4x0_4x4_4x8_4x12]
+    mova             m20, [pb_mask]
+    vpbroadcastd     m19, [pb_128]
+    vpbroadcastd     m17, [pb_m1_1]
+    vpbroadcastd     m16, [pw_4096]
+ %define pbshuf m21
+ %define pbmask m20
+ %define pb128  m19
+ %define pbm1_1 m17
+
+.loop:
+    cmp   word [maskq+4], 0                 ; vmask[1]
+    je .no_flat
+
+    FILTER             6, v
+    jmp .end
+
+.no_flat:
+    cmp   word [maskq+0], 0                 ; vmask[0]
+    je .end
+
+    call mangle(private_prefix %+ _lpf_v_sb_y_8bpc_avx512icl).v4
+
+.end:
+    add               lq, 64
+    add             dstq, 64
+    add            maskq, 2
+    sub               wd, 16
+    jg .loop
+    RET
+
+%undef k7
+cglobal lpf_h_sb_uv_8bpc, 7, 12, 22, dst, stride, mask, l, l_stride, \
+                                     lut, h, stride3, stride8
+ DECLARE_REG_TMP 9, 10, 11
+    mov              r7d, 0xffff
+    movzx            r8d, r7b
+    cmp               hd, 9
+    cmovb            r7d, r8d
+    kmovw             k6, r7d   ; h > 8 ? 0xffff : 0x00ff
+    shl        l_strideq, 2
+    sub               lq, 4
+    kshiftrw          k7, k6, 4 ; h > 8 ? 0xff   : 0xf0
+    lea         stride3q, [strideq*3]
+    lea         stride8q, [strideq*8]
+    vpbroadcastd     m19, strided
+    vpbroadcastd     m20, l_strided
+    pmulld           m21, m19, [hmulA]
+    pmulld           m20, [hmulB]
+    pmulld           m19, [hmulC]
+    mova             m18, [pb_mask]
+    vpbroadcastd     m17, [pb_128]
+    vpbroadcastd     m16, [pw_4096]
+ %define pbshuf [pb_4x0_4x4_4x8_4x12]
+ %define pbmask m18
+ %define pb128  m17
+    add        l_strideq, l_strideq
+
+.loop:
+    cmp   word [maskq+4], 0                 ; vmask[1]
+    je .no_flat
+
+    FILTER             6, h
+    jmp .end
+
+.no_flat:
+    cmp   word [maskq+0], 0                 ; vmask[0]
+    je .end
+
+    call mangle(private_prefix %+ _lpf_h_sb_y_8bpc_avx512icl).h4
+
+.end:
+    lea               lq, [lq+l_strideq*8]
+    lea             dstq, [dstq+stride8q*8]
+    add            maskq, 2
+    sub               hd, 16
+    jg .loop
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/loopfilter_sse.asm b/media/libdav1d/src/src/x86/loopfilter_sse.asm
new file mode 100644
index 0000000000..cd0eb54702
--- /dev/null
+++ b/media/libdav1d/src/src/x86/loopfilter_sse.asm
@@ -0,0 +1,2348 @@
+; Copyright © 2018-2021, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 16
+
+pb_4x0_4x4_4x8_4x12: db 0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12
+pb_7_1: times 8 db 7, 1
+pb_3_1: times 8 db 3, 1
+pb_2_1: times 8 db 2, 1
+pb_m1_0: times 8 db -1, 0
+pb_m1_1: times 8 db -1, 1
+pb_m1_2: times 8 db -1, 2
+pb_1: times 16 db 1
+pb_2: times 16 db 2
+pb_3: times 16 db 3
+pb_4: times 16 db 4
+pb_16: times 16 db 16
+pb_63: times 16 db 63
+pb_64: times 16 db 64
+pb_128: times 16 db 0x80
+pb_129: times 16 db 0x81
+pb_240: times 16 db 0xf0
+pb_248: times 16 db 0xf8
+pb_254: times 16 db 0xfe
+
+pw_2048: times 8 dw 2048
+pw_4096: times 8 dw 4096
+
+pd_mask: dd 1, 2, 4, 8
+
+SECTION .text
+
+%macro ABSSUB 4 ; dst, a, b, tmp
+    psubusb       %1, %2, %3
+    psubusb       %4, %3, %2
+    por           %1, %4
+%endmacro
+
+%macro TRANSPOSE_16x4_AND_WRITE_4x16 5
+    ; transpose 16x4
+    punpcklbw    m%5, m%1, m%2
+    punpckhbw    m%1, m%2
+    punpcklbw    m%2, m%3, m%4
+    punpckhbw    m%3, m%4
+    punpcklwd    m%4, m%5, m%2
+    punpckhwd    m%5, m%2
+    punpcklwd    m%2, m%1, m%3
+    punpckhwd    m%1, m%3
+
+    ; write out
+%assign %%n 0
+%rep 4
+    movd [dstq+strideq *0-2], xm%4
+    movd [dstq+strideq *4-2], xm%5
+    movd [dstq+strideq *8-2], xm%2
+    movd [dstq+stride3q*4-2], xm%1
+    add         dstq, strideq
+%if %%n < 3
+    psrldq      xm%4, 4
+    psrldq      xm%5, 4
+    psrldq      xm%2, 4
+    psrldq      xm%1, 4
+%endif
+%assign %%n (%%n+1)
+%endrep
+    lea         dstq, [dstq+stride3q*4]
+%endmacro
+
+%macro TRANSPOSE_16X16B 2 ; output_transpose, mem
+%if %1 == 0
+    mova          %2, m15 ; m7 in 32-bit
+%endif
+
+    ; input in m0-7
+    punpcklbw    m15, m0, m1
+    punpckhbw     m0, m1
+    punpcklbw     m1, m2, m3
+    punpckhbw     m2, m3
+    punpcklbw     m3, m4, m5
+    punpckhbw     m4, m5
+%if ARCH_X86_64
+    SWAP           4, 5, 7
+%else
+ %if %1 == 0
+    mova          m5, %2
+ %else
+    mova          m5, [esp+1*16]
+ %endif
+    mova          %2, m4
+%endif
+    punpcklbw     m4, m6, m5
+    punpckhbw     m6, m5
+
+    ; interleaved in m15,0,1,2,3,7,4,6
+    punpcklwd     m5, m15, m1
+    punpckhwd    m15, m1
+    punpcklwd     m1, m0, m2
+    punpckhwd     m0, m2
+    punpcklwd     m2, m3, m4
+    punpckhwd     m3, m4
+%if ARCH_X86_64
+    SWAP           3, 4, 7
+%else
+    mova          m4, %2
+    mova          %2, m3
+%endif
+    punpcklwd     m3, m4, m6
+    punpckhwd     m4, m6
+
+    ; interleaved in m5,15,1,0,2,7,3,4
+    punpckldq     m6, m5, m2
+    punpckhdq     m5, m2
+%if ARCH_X86_64
+    SWAP           2, 7, 5
+%else
+    mova          m2, %2
+    mova  [esp+1*16], m5
+%endif
+    punpckldq     m5, m15, m2
+    punpckhdq    m15, m2
+    punpckldq     m2, m1, m3
+    punpckhdq     m1, m3
+    punpckldq     m3, m0, m4
+    punpckhdq     m0, m4
+
+%if ARCH_X86_32
+    mova  [esp+0*16], m6
+    mova  [esp+2*16], m5
+    mova  [esp+3*16], m15
+    mova  [esp+4*16], m2
+    mova  [esp+5*16], m1
+    mova  [esp+6*16], m3
+    mova  [esp+7*16], m0
+    mova          m8, [esp+ 8*16]
+    mova          m9, [esp+ 9*16]
+    mova         m10, [esp+10*16]
+ %if %1 == 0
+    mova         m11, [esp+11*16]
+    mova         m12, [esp+12*16]
+    mova         m13, [esp+13*16]
+    mova         m14, [esp+14*16]
+ %else
+    mova         m11, [esp+20*16]
+    mova         m12, [esp+15*16]
+    mova         m13, [esp+16*16]
+    mova         m14, [esp+17*16]
+ %endif
+%endif
+
+    ; input in m8-m15
+%if ARCH_X86_64
+    SWAP           7, 4
+%endif
+    punpcklbw     m7, m8, m9
+    punpckhbw     m8, m9
+    punpcklbw     m9, m10, m11
+    punpckhbw    m10, m11
+    punpcklbw    m11, m12, m13
+    punpckhbw    m12, m13
+%if ARCH_X86_64
+    mova         m13, %2
+%else
+ %if %1 == 0
+    mova         m13, [esp+15*16]
+ %else
+    mova         m13, [esp+18*16]
+ %endif
+%endif
+    mova          %2, m12
+    punpcklbw    m12, m14, m13
+    punpckhbw    m14, m14, m13
+
+    ; interleaved in m7,8,9,10,11,rsp%2,12,14
+    punpcklwd    m13, m7, m9
+    punpckhwd     m7, m9
+    punpcklwd     m9, m8, m10
+    punpckhwd     m8, m10
+    punpcklwd    m10, m11, m12
+    punpckhwd    m11, m12
+    mova         m12, %2
+    mova          %2, m11
+    punpcklwd    m11, m12, m14
+    punpckhwd    m12, m14
+
+    ; interleaved in m13,7,9,8,10,rsp%2,11,12
+    punpckldq    m14, m13, m10
+    punpckhdq    m13, m10
+    punpckldq    m10, m9, m11
+    punpckhdq     m9, m11
+    punpckldq    m11, m8, m12
+    punpckhdq     m8, m12
+    mova         m12, %2
+    mova          %2, m8
+    punpckldq     m8, m7, m12
+    punpckhdq     m7, m12
+
+%if ARCH_X86_32
+    mova [esp+ 8*16], m10
+    mova [esp+ 9*16], m9
+    mova [esp+10*16], m11
+    SWAP           6, 1
+    SWAP           4, 2
+    SWAP           5, 3
+    mova          m6, [esp+0*16]
+    mova          m4, [esp+1*16]
+    mova          m5, [esp+2*16]
+%endif
+
+    ; interleaved in m6,7,5,15,2,1,3,0,14,13,10,9,11,rsp%2,8,7
+    punpcklqdq   m12, m6, m14
+    punpckhqdq    m6, m14
+    punpcklqdq   m14, m4, m13
+    punpckhqdq    m4, m13
+    punpcklqdq   m13, m5, m8
+    punpckhqdq    m5, m8
+%if ARCH_X86_64
+    SWAP           8, 5
+%else
+    mova          m8, [esp+3*16]
+    mova [esp+27*16], m5
+ %define m15 m8
+%endif
+    punpcklqdq    m5, m15, m7
+    punpckhqdq   m15, m7
+
+%if ARCH_X86_32
+    mova [esp+11*16], m12
+    mova [esp+12*16], m6
+    mova [esp+13*16], m14
+    mova [esp+14*16], m4
+    mova [esp+26*16], m13
+    mova [esp+ 0*16], m5
+    mova [esp+ 1*16], m15
+    mova          m2, [esp+ 4*16]
+    mova         m10, [esp+ 8*16]
+    mova          m1, [esp+ 5*16]
+    mova          m9, [esp+ 9*16]
+    mova          m3, [esp+ 6*16]
+    mova         m11, [esp+10*16]
+    mova          m0, [esp+ 7*16]
+%endif
+
+    punpcklqdq    m7, m2, m10
+    punpckhqdq    m2, m10
+    punpcklqdq   m10, m1, m9
+    punpckhqdq    m1, m9
+    punpcklqdq    m9, m3, m11
+    punpckhqdq    m3, m11
+    mova         m11, %2
+%if ARCH_X86_32
+ %define m12 m3
+%endif
+    mova          %2, m12
+    punpcklqdq   m12, m0, m11
+    punpckhqdq    m0, m11
+%if %1 == 1
+    mova         m11, %2
+%endif
+
+%if ARCH_X86_64
+    ; interleaved m11,6,14,4,13,8,5,15,7,2,10,1,9,3,12,0
+    SWAP           0, 11, 1, 6, 5, 8, 7, 15
+    SWAP           2, 14, 12, 9
+    SWAP           3, 4, 13
+%else
+ %if %1 == 0
+    mova [esp+15*16], m9
+    mova [esp+17*16], m12
+    mova [esp+18*16], m0
+    mova [esp+28*16], m10
+    mova [esp+29*16], m1
+    mova          m3, [esp+0*16]
+    mova          m4, [esp+1*16]
+    SWAP          m5, m7
+    SWAP          m6, m2
+ %else
+    SWAP           0, 7
+    SWAP           3, 1, 2, 4, 6
+ %endif
+%endif
+%endmacro
+
+%macro FILTER 2 ; width [4/6/8/16], dir [h/v]
+%if ARCH_X86_64
+ %define %%flat8mem [rsp+0*16]
+ %define %%q2mem    [rsp+1*16]
+ %define %%q3mem    [rsp+2*16]
+%else
+ %if %1 == 4 || %1 == 6
+  %define %%p2mem      [esp+ 8*16]
+  %define %%q2mem      [esp+ 9*16]
+  %define %%flat8mem   [esp+10*16]
+ %else
+  %ifidn %2, v
+   %define %%p2mem      [esp+16*16]
+   %define %%q2mem      [esp+ 1*16]
+   %define %%q3mem      [esp+18*16]
+   %define %%flat8mem   [esp+ 0*16]
+   %define %%flat16mem  [esp+20*16]
+  %else
+   %define %%p2mem     [esp+27*16]
+   %define %%q2mem     [esp+28*16]
+   %define %%q3mem     [esp+29*16]
+   %define %%flat8mem  [esp+21*16]
+   %define %%flat16mem [esp+30*16]
+  %endif
+ %endif
+ %xdefine m12reg m12
+%endif
+
+%if ARCH_X86_32
+    lea     stride3q, [strideq*3]
+%endif
+    ; load data
+%ifidn %2, v
+%if ARCH_X86_32
+    mov     mstrideq, strideq
+    neg     mstrideq
+%endif
+%if %1 == 4
+    lea         tmpq, [dstq+mstrideq*2]
+    mova          m3, [tmpq+strideq*0]          ; p1
+    mova          m4, [tmpq+strideq*1]          ; p0
+    mova          m5, [tmpq+strideq*2]          ; q0
+    mova          m6, [tmpq+stride3q]           ; q1
+%else
+    ; load 6-8 pixels, remainder (for wd=16) will be read inline
+    lea         tmpq, [dstq+mstrideq*4]
+    ; we load p3 later
+%define %%p3mem [dstq+mstrideq*4]
+ %if ARCH_X86_32
+  %define m13 m0
+  %define m14 m1
+  %define m15 m2
+ %endif
+    mova         m13, [tmpq+strideq*1]
+    mova          m3, [tmpq+strideq*2]
+    mova          m4, [tmpq+stride3q]
+    mova          m5, [dstq+strideq*0]
+    mova          m6, [dstq+strideq*1]
+    mova         m14, [dstq+strideq*2]
+%if %1 != 6
+    mova         m15, [dstq+stride3q]
+%endif
+ %if ARCH_X86_32
+    mova     %%p2mem, m13
+    mova     %%q2mem, m14
+  %define m13 %%p2mem
+  %define m14 %%q2mem
+  %if %1 != 6
+    mova     %%q3mem, m15
+   %define m15 %%q3mem
+  %endif
+ %endif
+%endif
+%else ; %2 == h
+    ; load lines
+%if %1 == 4
+    ; transpose 4x16
+    movd          m7, [dstq+strideq*0-2]
+    movd          m3, [dstq+strideq*1-2]
+    movd          m4, [dstq+strideq*2-2]
+    movd          m5, [dstq+stride3q -2]
+    lea         tmpq, [dstq+strideq*4]
+    punpcklbw     m7, m3
+    punpcklbw     m4, m5
+    movd          m3, [tmpq+strideq*0-2]
+    movd          m1, [tmpq+strideq*1-2]
+    movd          m5, [tmpq+strideq*2-2]
+    movd          m6, [tmpq+stride3q -2]
+    lea         tmpq, [tmpq+strideq*4]
+    punpcklbw     m3, m1
+    punpcklbw     m5, m6
+    movd          m0, [tmpq+strideq*0-2]
+    movd          m1, [tmpq+strideq*1-2]
+    punpcklbw     m0, m1
+    movd          m1, [tmpq+strideq*2-2]
+    movd          m2, [tmpq+stride3q -2]
+    punpcklbw     m1, m2
+    punpcklqdq    m7, m0
+    punpcklqdq    m4, m1
+    lea         tmpq, [tmpq+strideq*4]
+    movd          m0, [tmpq+strideq*0-2]
+    movd          m1, [tmpq+strideq*1-2]
+    punpcklbw     m0, m1
+    movd          m1, [tmpq+strideq*2-2]
+    movd          m2, [tmpq+stride3q -2]
+    punpcklbw     m1, m2
+    punpcklqdq    m3, m0
+    punpcklqdq    m5, m1
+    ; xm7: A0-1,B0-1,C0-1,D0-1,A8-9,B8-9,C8-9,D8-9
+    ; xm3: A4-5,B4-5,C4-5,D4-5,A12-13,B12-13,C12-13,D12-13
+    ; xm4: A2-3,B2-3,C2-3,D2-3,A10-11,B10-11,C10-11,D10-11
+    ; xm5: A6-7,B6-7,C6-7,D6-7,A14-15,B14-15,C14-15,D14-15
+    punpcklwd     m6, m7, m4
+    punpckhwd     m7, m4
+    punpcklwd     m4, m3, m5
+    punpckhwd     m3, m5
+    ; xm6: A0-3,B0-3,C0-3,D0-3
+    ; xm7: A8-11,B8-11,C8-11,D8-11
+    ; xm4: A4-7,B4-7,C4-7,D4-7
+    ; xm3: A12-15,B12-15,C12-15,D12-15
+    punpckldq     m5, m6, m4
+    punpckhdq     m6, m4
+    punpckldq     m4, m7, m3
+    punpckhdq     m7, m3
+    ; xm5: A0-7,B0-7
+    ; xm6: C0-7,D0-7
+    ; xm4: A8-15,B8-15
+    ; xm7: C8-15,D8-15
+    punpcklqdq    m3, m5, m4
+    punpckhqdq    m5, m5, m4
+    punpcklqdq    m4, m6, m7
+    punpckhqdq    m6, m7
+    ; xm3: A0-15
+    ; xm5: B0-15
+    ; xm4: C0-15
+    ; xm6: D0-15
+    SWAP           4, 5
+%elif %1 == 6 || %1 == 8
+    ; transpose 8x16
+    movq          m7, [dstq+strideq*0-%1/2]
+    movq          m3, [dstq+strideq*1-%1/2]
+    movq          m4, [dstq+strideq*2-%1/2]
+    movq          m5, [dstq+stride3q -%1/2]
+    lea         tmpq, [dstq+strideq*8]
+    punpcklbw     m7, m3
+    punpcklbw     m4, m5
+    movq          m3, [tmpq+strideq*0-%1/2]
+    movq          m1, [tmpq+strideq*1-%1/2]
+    movq          m5, [tmpq+strideq*2-%1/2]
+    movq          m6, [tmpq+stride3q -%1/2]
+    lea         tmpq, [dstq+strideq*4]
+    punpcklbw     m3, m1
+    punpcklbw     m5, m6
+    movq          m6, [tmpq+strideq*0-%1/2]
+    movq          m0, [tmpq+strideq*1-%1/2]
+    movq          m1, [tmpq+strideq*2-%1/2]
+    movq          m2, [tmpq+stride3q -%1/2]
+    lea         tmpq, [tmpq+strideq*8]
+    punpcklbw     m6, m0
+    punpcklbw     m1, m2
+    movq          m2, [tmpq+strideq*2-%1/2]
+    movq          m0, [tmpq+stride3q -%1/2]
+    punpcklbw     m2, m0
+%if ARCH_X86_64
+    SWAP         m15, m2
+%else
+ %define m15 [esp+3*16]
+    mova         m15, m2
+%endif
+    movq          m0, [tmpq+strideq*0-%1/2]
+    movq          m2, [tmpq+strideq*1-%1/2]
+    punpcklbw     m0, m2
+    ; xm7: A0-1,B0-1,C0-1,D0-1,E0-1,F0-1,G0-1,H0-1
+    ; xm3: A8-9,B8-9,C8-9,D8-9,E8-9,F8-9,G8-9,H8-9
+    ; xm4: A2-3,B2-3,C2-3,D2-3,E2-3,F2-3,G2-3,H2-3
+    ; xm5: A10-11,B10-11,C10-11,D10-11,E10-11,F10-11,G10-11,H10-11
+    ; xm6: A4-5,B4-5,C4-5,D4-5,E4-5,F4-5,G4-5,H4-5
+    ; xm0: A12-13,B12-13,C12-13,D12-13,E12-13,F12-13,G12-13,H12-13
+    ; xm1: A6-7,B6-7,C6-7,D6-7,E6-7,F6-7,G6-7,H6-7
+    ; xm2: A14-15,B14-15,C14-15,D14-15,E14-15,F14-15,G14-15,H14-15
+    punpcklwd     m2, m7, m4
+    punpckhwd     m7, m4
+    punpcklwd     m4, m3, m5
+    punpckhwd     m3, m5
+    punpcklwd     m5, m6, m1
+    punpckhwd     m6, m1
+    punpcklwd     m1, m0, m15
+    punpckhwd     m0, m15
+%if ARCH_X86_64
+    SWAP         m15, m0
+%else
+    mova         m15, m0
+%endif
+    ; xm2: A0-3,B0-3,C0-3,D0-3
+    ; xm7: E0-3,F0-3,G0-3,H0-3
+    ; xm4: A8-11,B8-11,C8-11,D8-11
+    ; xm3: E8-11,F8-11,G8-11,H8-11
+    ; xm5: A4-7,B4-7,C4-7,D4-7
+    ; xm6: E4-7,F4-7,G4-7,H4-7
+    ; xm1: A12-15,B12-15,C12-15,D12-15
+    ; xm0: E12-15,F12-15,G12-15,H12-15
+    punpckldq     m0, m2, m5
+    punpckhdq     m2, m5
+    punpckldq     m5, m7, m6
+%if %1 != 6
+    punpckhdq     m7, m6
+%endif
+    punpckldq     m6, m4, m1
+    punpckhdq     m4, m1
+    punpckldq     m1, m3, m15
+%if %1 != 6
+    punpckhdq     m3, m15
+ %if ARCH_X86_64
+    SWAP         m15, m3
+ %else
+    mova         m15, m3
+ %endif
+%endif
+    ; xm0: A0-7,B0-7
+    ; xm2: C0-7,D0-7
+    ; xm5: E0-7,F0-7
+    ; xm7: G0-7,H0-7
+    ; xm6: A8-15,B8-15
+    ; xm4: C8-15,D8-15
+    ; xm1: E8-15,F8-15
+    ; xm3: G8-15,H8-15
+    punpcklqdq    m3, m0, m6
+    punpckhqdq    m0, m6
+    punpckhqdq    m6, m2, m4
+    punpcklqdq    m2, m4
+    punpcklqdq    m4, m5, m1
+    punpckhqdq    m5, m1
+%if %1 == 8
+    punpcklqdq    m1, m7, m15
+    punpckhqdq    m7, m15
+    ; xm3: A0-15
+    ; xm0: B0-15
+    ; xm2: C0-15
+    ; xm6: D0-15
+    ; xm4: E0-15
+    ; xm5: F0-15
+    ; xm1: G0-15
+    ; xm7: H0-15
+%if ARCH_X86_64
+    SWAP          11, 3, 2
+    SWAP          13, 0
+    SWAP           6, 5, 4
+    SWAP          14, 1
+    SWAP          15, 7
+    ; 3,0,2,6,4,5,1,7 -> 11,13,3,4,5,6,14,15
+    mova [rsp+21*16], m11
+ %define %%p3mem [rsp+21*16]
+%else
+ %define m11 [esp+26*16]
+ %define m13 [esp+27*16]
+ %define m14 [esp+28*16]
+ %define m15 [esp+29*16]
+    mova         m11, m3
+    mova         m13, m0
+    SWAP           3, 2
+    SWAP           6, 5, 4
+    mova         m14, m1
+    mova         m15, m7
+ %define %%p3mem [esp+26*16]
+%endif
+%else
+ %if ARCH_X86_64
+    SWAP          13, 3, 0
+    SWAP          14, 5, 6, 4, 2
+    ; 3,0,2,6,4,5 -> 13,3,4,5,6,14
+ %else
+  %define m13 %%p2mem
+  %define m14 %%q2mem
+    mova         m13, m3
+    mova         m14, m5
+    SWAP           3, 0
+    SWAP           5, 6, 4, 2
+    ; 0,2,6,4 -> 3,4,5,6
+ %endif
+%endif
+%else
+%if ARCH_X86_64
+    mova [rsp+20*16], m12
+%endif
+    ; load and 16x16 transpose. We only use 14 pixels but we'll need the
+    ; remainder at the end for the second transpose
+%if ARCH_X86_32
+ %xdefine m8  m0
+ %xdefine m9  m1
+ %xdefine m10 m2
+ %xdefine m11 m3
+ %xdefine m12 m4
+ %xdefine m13 m5
+ %xdefine m14 m6
+ %xdefine m15 m7
+    lea         tmpq, [dstq+strideq*8]
+    movu          m8, [tmpq+strideq*0-8]
+    movu          m9, [tmpq+strideq*1-8]
+    movu         m10, [tmpq+strideq*2-8]
+    movu         m11, [tmpq+stride3q -8]
+    lea         tmpq, [tmpq+strideq*4]
+    movu         m12, [tmpq+strideq*0-8]
+    movu         m13, [tmpq+strideq*1-8]
+    movu         m14, [tmpq+strideq*2-8]
+    movu         m15, [tmpq+stride3q -8]
+    mova [esp+ 8*16], m8
+    mova [esp+ 9*16], m9
+    mova [esp+10*16], m10
+    mova [esp+11*16], m11
+    mova [esp+12*16], m12
+    mova [esp+13*16], m13
+    mova [esp+14*16], m14
+    mova [esp+15*16], m15
+%endif
+    movu          m0, [dstq+strideq*0-8]
+    movu          m1, [dstq+strideq*1-8]
+    movu          m2, [dstq+strideq*2-8]
+    movu          m3, [dstq+stride3q -8]
+    lea         tmpq, [dstq+strideq*4]
+    movu          m4, [tmpq+strideq*0-8]
+    movu          m5, [tmpq+strideq*1-8]
+    movu          m6, [tmpq+strideq*2-8]
+    movu          m7, [tmpq+stride3q -8]
+    lea         tmpq, [tmpq+strideq*4]
+%if ARCH_X86_64
+    movu          m8, [tmpq+strideq*0-8]
+    movu          m9, [tmpq+strideq*1-8]
+    movu         m10, [tmpq+strideq*2-8]
+    movu         m11, [tmpq+stride3q -8]
+    lea         tmpq, [tmpq+strideq*4]
+    movu         m12, [tmpq+strideq*0-8]
+    movu         m13, [tmpq+strideq*1-8]
+    movu         m14, [tmpq+strideq*2-8]
+    movu         m15, [tmpq+stride3q -8]
+%endif
+
+%if ARCH_X86_64
+    TRANSPOSE_16X16B 0, [rsp+11*16]
+    mova [rsp+12*16], m1
+    mova [rsp+13*16], m2
+    mova [rsp+14*16], m3
+    mova [rsp+15*16], m12
+    mova [rsp+16*16], m13
+    mova [rsp+17*16], m14
+    mova [rsp+18*16], m15
+    ; 4,5,6,7,8,9,10,11 -> 12,13,3,4,5,6,14,15
+    SWAP          12, 4, 7
+    SWAP          13, 5, 8
+    SWAP           3, 6, 9
+    SWAP          10, 14
+    SWAP          11, 15
+    mova [rsp+21*16], m12
+ %define %%p3mem [rsp+21*16]
+    mova         m12, [rsp+20*16]
+%else
+    TRANSPOSE_16X16B 0, [esp+16*16]
+ %define %%p3mem [esp+26*16]
+ %define m11 %%p3mem
+ %define m13 %%p2mem
+ %define m14 %%q2mem
+ %define m15 %%q3mem
+%endif
+%endif ; if 4 elif 6 or 8 else 16
+%endif ; if v else h
+
+    ; load L/E/I/H
+%if ARCH_X86_32
+    mov    l_strideq, l_stridem
+%endif
+%ifidn %2, v
+    movu          m1, [lq]
+    movu          m0, [lq+l_strideq]
+%else
+ %if ARCH_X86_32
+    lea   l_stride3q, [l_strideq*3]
+ %endif
+    movq         xm1, [lq]
+    movq         xm2, [lq+l_strideq*2]
+    movhps       xm1, [lq+l_strideq]
+    movhps       xm2, [lq+l_stride3q]
+    shufps        m0, m1, m2, q3131
+    shufps        m1, m2, q2020
+ %if ARCH_X86_32
+    lea     stride3q, [strideq*3]
+ %endif
+%endif
+
+%if ARCH_X86_32
+ %ifidn %2, v
+    mov         lutd, lutm
+ %endif
+%endif
+    pxor          m2, m2
+    pcmpeqb       m7, m2, m0
+    pand          m1, m7
+    por           m0, m1                        ; l[x][] ? l[x][] : l[x-stride][]
+    pshufb        m0, [PIC_sym(pb_4x0_4x4_4x8_4x12)] ; l[x][1]
+    pcmpeqb       m2, m0                        ; !L
+    psrlq         m7, m0, [lutq+128]
+    pand          m7, [PIC_sym(pb_63)]
+    pminub        m7, minlvl
+    pmaxub        m7, [PIC_sym(pb_1)]           ; I
+    pand          m1, m0, [PIC_sym(pb_240)]
+    psrlq         m1, 4                         ; H
+    paddb         m0, [PIC_sym(pb_2)]
+    paddb         m0, m0
+    paddb         m0, m7                        ; E
+    pxor          m1, [PIC_sym(pb_128)]
+    pxor          m7, [PIC_sym(pb_128)]
+    pxor          m0, [PIC_sym(pb_128)]
+    SWAP           2, 7
+
+%if ARCH_X86_64
+    SWAP           0, 8
+    SWAP           2, 10
+%else
+ %ifidn %2, v
+    mov     mstrideq, strideq
+    neg     mstrideq
+  %if %1 == 4
+    lea         tmpq, [dstq+mstrideq*2]
+  %elif %1 == 6 || %1 == 8
+    lea         tmpq, [dstq+mstrideq*4]
+  %endif
+ %endif
+    mova  [esp+3*16], m0
+    mova  [esp+4*16], m2
+%endif
+
+    ABSSUB        m0, m3, m4, m2                ; abs(p1-p0)
+    pmaxub        m0, m7
+    ABSSUB        m2, m5, m6, m7                ; abs(q1-q0)
+    pmaxub        m0, m2
+%if %1 == 4
+    pxor          m0, [PIC_sym(pb_128)]
+    pcmpgtb       m7, m0, m1                    ; hev
+ %if ARCH_X86_64
+    SWAP           7, 11
+ %else
+    mova  [esp+5*16], m7
+ %endif
+%else
+    pxor          m7, m0, [PIC_sym(pb_128)]
+    pcmpgtb       m7, m1                        ; hev
+%if ARCH_X86_64
+    SWAP           7, 11
+%else
+    mova  [esp+5*16], m7
+%endif
+
+%if %1 == 6
+    ABSSUB        m1, m13, m4, m7               ; abs(p2-p0)
+    pmaxub        m1, m0
+%else
+    mova          m2, %%p3mem
+    ABSSUB        m1, m2, m4, m7                ; abs(p3-p0)
+    pmaxub        m1, m0
+    ABSSUB        m7, m13, m4, m2               ; abs(p2-p0)
+    pmaxub        m1, m7
+%endif
+    ABSSUB        m7, m5, m14, m2               ; abs(p2-p0)
+    pmaxub        m1, m7
+%if %1 != 6
+    ABSSUB        m7, m5, m15, m2               ; abs(q3-q0)
+    pmaxub        m1, m7
+%endif
+    pxor          m1, [PIC_sym(pb_128)]
+    pcmpgtb       m1, [PIC_sym(pb_129)]         ; !flat8in
+%if ARCH_X86_64
+    SWAP           1, 9
+%else
+    mova  [esp+6*16], m1
+%endif
+
+%if %1 == 6
+    ABSSUB        m7, m13, m3, m1               ; abs(p2-p1)
+%else
+    mova          m2, %%p3mem
+    ABSSUB        m7, m2, m13, m1               ; abs(p3-p2)
+    ABSSUB        m2, m13, m3, m1               ; abs(p2-p1)
+    pmaxub        m7, m2
+    ABSSUB        m2, m14, m15, m1              ; abs(q3-q2)
+    pmaxub        m7, m2
+%endif
+    ABSSUB        m2, m14, m6,  m1              ; abs(q2-q1)
+    pmaxub        m7, m2
+%if ARCH_X86_32
+ %define m12 m1
+    mova         m12, maskmem
+%endif
+    pand          m2, m12, mask1
+    pcmpeqd       m2, m12
+    pand          m7, m2                        ; only apply fm-wide to wd>4 blocks
+    pmaxub        m0, m7
+
+    pxor          m0, [PIC_sym(pb_128)]
+%endif ; %if %1 == 4 else
+%if ARCH_X86_64
+    SWAP           2, 10
+    pcmpgtb       m0, m2
+%else
+    pcmpgtb       m0, [esp+4*16]
+%endif
+
+    ABSSUB        m1, m3, m6, m7                ; abs(p1-q1)
+    ABSSUB        m7, m4, m5, m2                ; abs(p0-q0)
+    paddusb       m7, m7
+    pand          m1, [PIC_sym(pb_254)]
+    psrlq         m1, 1
+    paddusb       m1, m7                        ; abs(p0-q0)*2+(abs(p1-q1)>>1)
+    pxor          m1, [PIC_sym(pb_128)]
+%if ARCH_X86_64
+    pcmpgtb       m1, m8                        ; abs(p0-q0)*2+(abs(p1-q1)>>1) > E
+%else
+    pcmpgtb       m1, [esp+3*16]
+%endif
+    por           m0, m1
+
+%if %1 == 16
+%if ARCH_X86_64
+    SWAP           0, 8
+%else
+    mova  [esp+3*16], m0
+%endif
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*8]
+    mova          m0, [tmpq+strideq*1]
+%else
+    mova          m0, [rsp+12*16]
+%endif
+    ABSSUB        m1, m0, m4, m2
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*2]
+%else
+    mova          m0, [rsp+13*16]
+%endif
+    ABSSUB        m2, m0, m4, m7
+    pmaxub        m1, m2
+%ifidn %2, v
+    mova          m0, [tmpq+stride3q]
+%else
+    mova          m0, [rsp+14*16]
+%endif
+    ABSSUB        m2, m0, m4, m7
+    pmaxub        m1, m2
+%ifidn %2, v
+    lea         tmpq, [dstq+strideq*4]
+    mova          m0, [tmpq+strideq*0]
+%else
+    mova          m0, [rsp+15*16]
+%endif
+    ABSSUB        m2, m0, m5, m7
+    pmaxub        m1, m2
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*1]
+%else
+    mova          m0, [rsp+16*16]
+%endif
+    ABSSUB        m2, m0, m5, m7
+    pmaxub        m1, m2
+%ifidn %2, v
+    mova          m0, [tmpq+strideq*2]
+%else
+    mova          m0, [rsp+17*16]
+%endif
+    ABSSUB        m2, m0, m5, m7
+    pmaxub        m1, m2
+    pxor          m1, [PIC_sym(pb_128)]
+    pcmpgtb       m1, [PIC_sym(pb_129)]         ; !flat8out
+%if ARCH_X86_64
+    por           m1, m9                        ; !flat8in | !flat8out
+%else
+    por           m1, [esp+6*16]
+ %define m12 m7
+    mova         m12, maskmem
+%endif
+    pand          m2, m12, mask2
+    pcmpeqd       m2, m12
+    pandn         m1, m2                        ; flat16
+%if ARCH_X86_64
+    pandn         m2, m8, m1                    ; flat16 & fm
+%else
+    pandn         m2, [esp+3*16], m1            ; flat16 & fm
+    mova %%flat16mem, m2
+%endif
+    SWAP           1, 2
+
+    pand          m2, m12, mask1
+    pcmpeqd       m2, m12
+%if ARCH_X86_64
+    pandn         m9, m2                    ; flat8in
+    pandn         m2, m8, m9
+    SWAP           2, 9
+%else
+    pandn         m0, [esp+6*16], m2
+    pandn         m2, [esp+3*16], m0
+    mova  [esp+6*16], m2
+%endif
+    pand          m2, m12, mask0
+    pcmpeqd       m2, m12
+%if ARCH_X86_64
+    pandn         m8, m2
+    pandn         m2, m9, m8                    ; fm & !flat8 & !flat16
+    SWAP           2, 8
+    pandn         m2, m1, m9                    ; flat8 & !flat16
+    SWAP           2, 9
+    SWAP           0, 8
+    SWAP           1, 10
+%else
+    pandn         m0, [esp+3*16], m2
+    pandn         m2, [esp+6*16], m0
+    SWAP           2, 0
+    pandn         m2, m1, [esp+6*16]
+    mova  %%flat8mem, m2
+%endif
+%elif %1 != 4
+ %if ARCH_X86_64
+    SWAP           1, 9
+ %else
+  %define m12 m7
+    mova         m12, maskmem
+    mova          m1, [esp+6*16]
+ %endif
+    pand          m2, m12, mask1
+    pcmpeqd       m2, m12
+    pandn         m1, m2
+    pandn         m2, m0, m1                    ; flat8 & fm
+    pand          m1, m12, mask0
+    pcmpeqd       m1, m12
+    pandn         m0, m1
+    pandn         m1, m2, m0                    ; fm & !flat8
+    SWAP           1, 2, 0
+ %if ARCH_X86_64
+    SWAP           1, 9
+ %else
+    mova  %%flat8mem, m1
+ %endif
+%else
+%if ARCH_X86_32
+ %define m12 m1
+    mova         m12, maskmem
+%endif
+    pand          m2, m12, mask0
+    pcmpeqd       m2, m12
+    pandn         m0, m2                        ; fm
+%endif
+
+    ; short filter
+
+    mova          m1, [PIC_sym(pb_128)]
+%if ARCH_X86_64
+    SWAP           7, 11
+%else
+    mova          m7, [esp+5*16]
+%endif
+    pxor          m3, m1
+    pxor          m6, m1
+    pxor          m4, m1
+    pxor          m5, m1
+    psubsb        m1, m3, m6                    ; iclip_diff(p1-q1)
+    pand          m1, m7                        ; f=iclip_diff(p1-q1)&hev
+    psubsb        m2, m5, m4
+    paddsb        m1, m2
+    paddsb        m1, m2
+    paddsb        m1, m2                        ; f=iclip_diff(3*(q0-p0)+f)
+    mova          m2, [PIC_sym(pb_16)]
+    pand          m0, m1                        ; f&=fm
+    paddsb        m1, m0, [PIC_sym(pb_3)]
+    paddsb        m0, [PIC_sym(pb_4)]
+    pand          m1, [PIC_sym(pb_248)]
+    pand          m0, [PIC_sym(pb_248)]
+    psrlq         m1, 3
+    psrlq         m0, 3
+    pxor          m1, m2
+    pxor          m0, m2
+    psubb         m1, m2                        ; f2
+    psubb         m0, m2                        ; f1
+    mova          m2, [PIC_sym(pb_128)]
+    paddsb        m4, m1
+    psubsb        m5, m0
+    pxor          m4, m2
+    pxor          m5, m2
+
+    pxor          m0, m2
+    pxor          m1, m1
+    pavgb         m0, m1                        ; f=(f1+1)>>1
+    psubb         m0, [PIC_sym(pb_64)]
+    pandn         m7, m0                        ; f&=!hev
+    paddsb        m3, m7
+    psubsb        m6, m7
+    pxor          m3, m2
+    pxor          m6, m2
+
+%if %1 == 16
+    ; flat16 filter
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*8]
+    mova          m0, [tmpq+strideq*1]          ; p6
+    mova          m2, [tmpq+strideq*2]          ; p5
+    mova          m7, [tmpq+stride3q]           ; p4
+%else
+    mova          m0, [rsp+12*16]
+    mova          m2, [rsp+13*16]
+    mova          m7, [rsp+14*16]
+%endif
+
+%if ARCH_X86_64
+    SWAP           1, 10
+    mova  %%flat8mem, m9
+    mova     %%q2mem, m14
+    mova     %%q3mem, m15
+    SWAP           0, 8
+    SWAP           1, 9
+%else
+ %ifidn %2, v
+    mova [esp+17*16], m0
+    mova [esp+19*16], m3
+    mova [esp+21*16], m4
+    mova [esp+22*16], m5
+    mova [esp+23*16], m6
+  %xdefine m11 m3
+  %xdefine m14 m4
+  %xdefine m15 m5
+  %xdefine m10 m6
+  %define m13 %%p2mem
+  %define m8  [esp+17*16]
+  %define m9  %%flat16mem
+  %define m3  [esp+19*16]
+  %define m4  [esp+21*16]
+  %define m5  [esp+22*16]
+  %define m6  [esp+23*16]
+ %else
+    mova [esp+31*16], m0
+    mova [esp+32*16], m3
+    mova [esp+33*16], m4
+    mova [esp+34*16], m5
+    mova [esp+35*16], m6
+  %xdefine m11 m3
+  %xdefine m14 m4
+  %xdefine m15 m5
+  %xdefine m10 m6
+  %define m13 %%p2mem
+  %define m8  [esp+31*16]
+  %define m9  %%flat16mem
+  %define m3  [esp+32*16]
+  %define m4  [esp+33*16]
+  %define m5  [esp+34*16]
+  %define m6  [esp+35*16]
+ %endif
+%endif
+
+    ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0 [p5/p4/p2/p1/p0/q0][p6/p3] A
+    ; write -6
+    mova         m11, %%p3mem
+%if ARCH_X86_64
+    punpcklbw    m14, m8, m11
+    punpckhbw    m15, m8, m11
+%else
+    punpcklbw    m14, m0, m11
+    punpckhbw    m15, m0, m11
+%endif
+%ifidn %2, v
+    mova  [rsp+5*16], m11
+%endif
+    pmaddubsw    m10, m14, [PIC_sym(pb_7_1)]
+    pmaddubsw    m11, m15, [PIC_sym(pb_7_1)]    ; p6*7+p3
+    punpcklbw     m0, m2, m7
+    punpckhbw     m1, m2, m7
+    pmaddubsw     m0, [PIC_sym(pb_2)]
+    pmaddubsw     m1, [PIC_sym(pb_2)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p6*7+p5*2+p4*2+p3
+    punpcklbw     m0, m13, m3
+    punpckhbw     m1, m13, m3
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    pmaddubsw     m1, [PIC_sym(pb_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p6*7+p5*2+p4*2+p3+p2+p1
+    punpcklbw     m0, m4, m5
+    punpckhbw     m1, m4, m5
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    pmaddubsw     m1, [PIC_sym(pb_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p6*7+p5*2+p4*2+p3+p2+p1+p0+q0
+    pmulhrsw      m0, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m2
+    por           m0, m1
+%ifidn %2, v
+    mova [tmpq+strideq*2], m0                   ; p5
+%else
+    mova [rsp+13*16], m0
+%endif
+
+    ; sub p6*2, add p3/q1 [reuse p6/p3 from A][-p6,+q1|save] B
+    ; write -5
+    pmaddubsw    m14, [PIC_sym(pb_m1_1)]
+    pmaddubsw    m15, [PIC_sym(pb_m1_1)]
+    paddw        m10, m14
+    paddw        m11, m15                       ; p6*6+p5*2+p4*2+p3*2+p2+p1+p0+q0
+    punpcklbw     m0, m8, m6
+    punpckhbw     m1, m8, m6
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    mova  [rsp+3*16], m0
+    mova  [rsp+4*16], m1
+    paddw        m10, m0
+    paddw        m11, m1                        ; p6*5+p5*2+p4*2+p3*2+p2+p1+p0+q0+q1
+    pmulhrsw      m0, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m7
+    por           m0, m1
+%ifidn %2, v
+    mova [tmpq+stride3q], m0                    ; p4
+%else
+    mova [rsp+14*16], m0
+%endif
+
+    ; sub p6/p5, add p2/q2 [-p6,+p2][-p5,+q2|save] C
+    ; write -4
+    mova         m14, %%q2mem
+    punpcklbw     m0, m8, m13
+    punpckhbw     m1, m8, m13
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p6*4+p5*2+p4*2+p3*2+p2*2+p1+p0+q0+q1
+    punpcklbw     m0, m2, m14
+    punpckhbw     m2, m14
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m2, [PIC_sym(pb_m1_1)]
+    mova  [rsp+1*16], m0
+    paddw        m10, m0
+    paddw        m11, m2                        ; p6*4+p5+p4*2+p3*2+p2*2+p1+p0+q0+q1+q2
+    pmulhrsw      m0, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, %%p3mem
+    por           m0, m1
+%ifidn %2, v
+    mova [tmpq+strideq*4], m0                   ; p3
+%else
+    mova [rsp+19*16], m0
+%endif
+
+    ; sub p6/p4, add p1/q3 [-p6,+p1][-p4,+q3|save] D
+    ; write -3
+    mova         m15, %%q3mem
+    punpcklbw     m0, m8, m3
+    punpckhbw     m1, m8, m3
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p6*3+p5+p4*2+p3*2+p2*2+p1*2+p0+q0+q1+q2
+    punpcklbw     m0, m7, m15
+    punpckhbw     m7, m15
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m7, [PIC_sym(pb_m1_1)]
+    mova  [rsp+2*16], m0
+%if ARCH_X86_32
+ %ifidn %2, v
+    mova [esp+24*16], m7
+ %else
+    mova [esp+36*16], m7
+ %endif
+%endif
+    paddw        m10, m0
+    paddw        m11, m7                        ; p6*3+p5+p4+p3*2+p2*2+p1*2+p0+q0+q1+q2+q3
+    pmulhrsw      m0, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m13
+    por           m0, m1
+    mova  [rsp+6*16], m0                        ; don't clobber p2/m13 since we need it in F
+
+    ; sub p6/p3, add p0/q4 [-p6,+p0][-p3,+q4|save] E
+    ; write -2
+    punpcklbw     m0, m8, m4
+    punpckhbw     m1, m8, m4
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p6*2+p5+p4+p3*2+p2*2+p1*2+p0*2+q0+q1+q2+q3
+%if ARCH_X86_64
+    SWAP           7, 8
+%endif
+%ifidn %2, v
+    mova          m1, [dstq+strideq*4]          ; q4
+    mova          m7, [rsp+5*16]                ; (pre-filter) p3
+%else
+    mova          m1, [rsp+15*16]
+    mova          m7, %%p3mem                   ; (pre-filter) p3
+%endif
+    punpcklbw     m0, m1, m7
+    punpckhbw     m1, m1, m7
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    mova  [rsp+7*16], m0
+    mova  [rsp+5*16], m1
+    psubw        m10, m0
+    psubw        m11, m1                        ; p6*2+p5+p4+p3+p2*2+p1*2+p0*2+q0+q1+q2+q3+q4
+    pmulhrsw      m0, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m3
+    por           m0, m1
+    mova  [rsp+8*16], m0                        ; don't clobber p1/m3 since we need it in G
+
+    ; sub p6/p2, add q0/q5 [-p6,+q0][-p2,+q5|save] F
+    ; write -1
+%ifidn %2, v
+    mova          m7, [tmpq+strideq*1]          ; p6
+    lea         tmpq, [dstq+strideq*4]
+    mova          m1, [tmpq+strideq*1]          ; q5
+%else
+    mova          m7, [rsp+12*16]               ; p6
+    mova          m1, [rsp+16*16]
+%endif
+    punpcklbw     m0, m7, m5
+    punpckhbw     m7, m5
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m7, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m7                        ; p6+p5+p4+p3+p2*2+p1*2+p0*2+q0*2+q1+q2+q3+q4
+    punpcklbw     m7, m13, m1
+    pmaddubsw     m7, [PIC_sym(pb_m1_1)]
+    mova  [rsp+9*16], m7
+    paddw        m10, m7
+%if ARCH_X86_64
+    punpckhbw    m13, m1
+    mova          m1, [rsp+6*16]
+    SWAP           1, 13
+%else
+    punpckhbw     m7, m13, m1
+    mova          m1, [esp+6*16]
+    mova         m13, m1
+    SWAP           1, 7
+%endif
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    mova [rsp+10*16], m1
+    paddw        m11, m1                        ; p6+p5+p4+p3+p2+p1*2+p0*2+q0*2+q1+q2+q3+q4+q5
+    pmulhrsw      m7, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m0, m11, [PIC_sym(pw_2048)]
+    packuswb      m7, m0
+    pand          m7, m9
+    pandn         m0, m9, m4
+    por           m7, m0
+    mova  [rsp+6*16], m7                        ; don't clobber p0/m4 since we need it in H
+
+    ; sub p6/p1, add q1/q6 [reuse -p6,+q1 from B][-p1,+q6|save] G
+    ; write +0
+%ifidn %2, v
+    mova          m7, [tmpq+strideq*2]          ; q6
+%else
+    mova          m7, [rsp+17*16]
+%endif
+    paddw        m10, [rsp+3*16]
+    paddw        m11, [rsp+4*16]                ; p5+p4+p3+p2+p1*2+p0*2+q0*2+q1*2+q2+q3+q4+q5
+    punpcklbw     m0, m3, m7
+    punpckhbw     m1, m3, m7
+%if ARCH_X86_64
+    mova          m3, [rsp+8*16]
+%endif
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    mova  [rsp+3*16], m0
+    mova  [rsp+4*16], m1
+    paddw        m10, m0
+    paddw        m11, m1                        ; p5+p4+p3+p2+p1+p0*2+q0*2+q1*2+q2+q3+q4+q5+q6
+    pmulhrsw      m0, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m5
+    por           m0, m1
+%if ARCH_X86_32
+    mova          m1, [esp+8*16]
+    mova          m3, m1
+%endif
+    mova  [rsp+8*16], m0                        ; don't clobber q0/m5 since we need it in I
+
+    ; sub p5/p0, add q2/q6 [reuse -p5,+q2 from C][-p0,+q6] H
+    ; write +1
+    paddw        m10, [rsp+1*16]
+    paddw        m11, m2                        ; p4+p3+p2+p1+p0*2+q0*2+q1*2+q2*2+q3+q4+q5+q6
+    punpcklbw     m0, m4, m7
+    punpckhbw     m2, m4, m7
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m2, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m2                        ; p4+p3+p2+p1+p0+q0*2+q1*2+q2*2+q3+q4+q5+q6*2
+%if ARCH_X86_64
+    mova          m4, [rsp+6*16]
+%else
+ %define m4 [esp+6*16]
+%endif
+    pmulhrsw      m2, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m2, m1
+    pand          m2, m9
+    pandn         m1, m9, m6
+    por           m2, m1                        ; don't clobber q1/m6 since we need it in K
+
+    ; sub p4/q0, add q3/q6 [reuse -p4,+q3 from D][-q0,+q6] I
+    ; write +2
+    paddw        m10, [rsp+2*16]
+%if ARCH_X86_64
+    SWAP           7, 8
+    paddw        m11, m7
+%else
+    mova          m8, m7
+ %ifidn %2, v
+    paddw        m11, [esp+24*16]               ; p3+p2+p1+p0+q0*2+q1*2+q2*2+q3*2+q4+q5+q6*2
+ %else
+    paddw        m11, [esp+36*16]               ; p3+p2+p1+p0+q0*2+q1*2+q2*2+q3*2+q4+q5+q6*2
+ %endif
+%endif
+    punpcklbw     m0, m5, m8
+    punpckhbw     m1, m5, m8
+%if ARCH_X86_64
+    mova          m5, [rsp+8*16]
+%else
+ %define m5 [esp+8*16]
+%endif
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p3+p2+p1+p0+q0+q1*2+q2*2+q3*2+q4+q5+q6*3
+    pmulhrsw      m7, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m7, m1
+    pand          m7, m9
+    pandn         m1, m9, m14
+    por           m7, m1                        ; don't clobber q2/m14 since we need it in K
+
+    ; sub p3/q1, add q4/q6 [reuse -p3,+q4 from E][-q1,+q6] J
+    ; write +3
+    psubw        m10, [rsp+7*16]
+    psubw        m11, [rsp+5*16]                ; p2+p1+p0+q0+q1*2+q2*2+q3*2+q4*2+q5+q6*3
+    punpcklbw     m0, m6, m8
+    punpckhbw     m1, m6, m8
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p2+p1+p0+q0+q1+q2*2+q3*2+q4*2+q5+q6*4
+    pmulhrsw      m0, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m15
+    por           m0, m1
+%ifidn %2, v
+    mova [tmpq+mstrideq], m0                    ; q3
+%else
+    mova [rsp+20*16], m0
+%endif
+
+    ; sub p2/q2, add q5/q6 [reuse -p2,+q5 from F][-q2,+q6] K
+    ; write +4
+    paddw        m10, [rsp+ 9*16]
+    paddw        m11, [rsp+10*16]               ; p1+p0+q0+q1+q2*2+q3*2+q4*2+q5*2+q6*4
+    punpcklbw     m0, m14, m8
+    punpckhbw     m1, m14, m8
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p1+p0+q0+q1+q2+q3*2+q4*2+q5*2+q6*5
+    pmulhrsw      m0, m10, [PIC_sym(pw_2048)]
+    pmulhrsw      m1, m11, [PIC_sym(pw_2048)]
+    packuswb      m0, m1
+    pand          m0, m9
+%ifidn %2, v
+    pandn         m1, m9, [tmpq+strideq*0]
+%else
+    pandn         m1, m9, [rsp+15*16]
+%endif
+    por           m0, m1
+%ifidn %2, v
+    mova [tmpq+strideq*0], m0                    ; q4
+%else
+    mova [rsp+15*16], m0
+%endif
+
+    ; sub p1/q3, add q6*2 [reuse -p1,+q6 from G][-q3,+q6] L
+    ; write +5
+    paddw        m10, [rsp+3*16]
+    paddw        m11, [rsp+4*16]                ; p1+p0+q0+q1+q2*2+q3*2+q4*2+q5*2+q6*4
+    punpcklbw     m0, m15, m8
+    punpckhbw     m1, m15, m8
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw        m10, m0
+    paddw        m11, m1                        ; p1+p0+q0+q1+q2+q3*2+q4*2+q5*2+q6*5
+    pmulhrsw     m10, [PIC_sym(pw_2048)]
+    pmulhrsw     m11, [PIC_sym(pw_2048)]
+    packuswb     m10, m11
+    pand         m10, m9
+%ifidn %2, v
+    pandn        m11, m9, [tmpq+strideq*1]
+%else
+    pandn        m11, m9, [rsp+16*16]
+%endif
+    por          m10, m11
+%ifidn %2, v
+    mova [tmpq+strideq*1], m10                  ; q5
+%else
+    mova [rsp+16*16], m10
+%endif
+
+%if ARCH_X86_64
+    SWAP           0, 8
+    SWAP           1, 9
+    SWAP          14, 7
+%else
+ %xdefine m3 m11
+ %xdefine m4 m14
+ %xdefine m5 m15
+ %xdefine m6 m10
+    mova     %%q2mem, m7
+ %ifidn %2, v
+    mova          m3, [esp+19*16]
+ %else
+    mova          m3, [esp+32*16]
+ %endif
+    mova          m4, [esp+ 6*16]
+    mova          m5, [esp+ 8*16]
+%endif
+    SWAP          m6, m2
+
+%if ARCH_X86_64
+    mova          m9, %%flat8mem
+%endif
+%ifidn %2, v
+    lea         tmpq, [dstq+mstrideq*4]
+%endif
+%endif ; if %1 == 16
+%if %1 >= 8
+    ; flat8 filter
+%if ARCH_X86_32
+ %define m9  %%flat8mem
+ %define m11 m1
+ %define m13 %%p2mem
+ %define m14 %%q2mem
+ %define m15 %%q3mem
+%endif
+    mova         m11, %%p3mem
+    punpcklbw     m0, m11, m3
+    punpcklbw     m7, m13, m4
+    pmaddubsw     m2, m0, [PIC_sym(pb_3_1)] ; 3 * p3 + p1
+    pmaddubsw     m7, [PIC_sym(pb_2_1)]
+    paddw         m2, m7                    ; 3 * p3 + 2 * p2 + p1 + p0
+    punpcklbw     m7, m5, [PIC_sym(pb_4)]
+    pmaddubsw     m7, [PIC_sym(pb_1)]
+    paddw         m2, m7                    ; 3 * p3 + 2 * p2 + p1 + p0 + q0 + 4
+    punpckhbw     m1, m11, m3
+    pmaddubsw     m7, m1, [PIC_sym(pb_3_1)] ; 3 * p3 + p1
+    punpckhbw     m0, m13, m4
+    pmaddubsw     m0, [PIC_sym(pb_2_1)]
+    paddw         m7, m0                    ; 3 * p3 + 2 * p2 + p1 + p0
+    punpckhbw     m0, m5, [PIC_sym(pb_4)]
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    paddw         m7, m0                    ; 3 * p3 + 2 * p2 + p1 + p0 + q0 + 4
+    psrlw         m0, m2, 3
+    psrlw         m1, m7, 3
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m13
+    por           m0, m1                    ; p2
+%ifidn %2, v
+    mova [tmpq+strideq*1], m0
+%else
+ %if ARCH_X86_64
+    SWAP           0, 10
+ %else
+    mova  [esp+2*16], m0
+ %endif
+%endif
+
+%if ARCH_X86_32
+    mova         m11, %%p3mem
+%endif
+    punpcklbw     m0, m11, m3
+    punpckhbw     m1, m11, m3
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw         m2, m0
+    paddw         m7, m1
+    punpcklbw     m0, m13, m6
+    punpckhbw     m1, m13, m6
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw         m2, m0
+    paddw         m7, m1            ; 2 * p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4
+    psrlw         m0, m2, 3
+    psrlw         m1, m7, 3
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m3
+    por           m0, m1            ; p1
+%ifidn %2, v
+    mova [tmpq+strideq*2], m0
+%else
+    mova  [rsp+0*16], m0
+%endif
+
+%if ARCH_X86_32
+    mova         m11, %%p3mem
+%endif
+    punpcklbw     m0, m11, m3
+    punpckhbw     m1, m11, m3
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    pmaddubsw     m1, [PIC_sym(pb_1)]
+    psubw         m2, m0
+    psubw         m7, m1
+    punpcklbw     m0, m4, m14
+    punpckhbw     m1, m4, m14
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    pmaddubsw     m1, [PIC_sym(pb_1)]
+    paddw         m2, m0
+    paddw         m7, m1            ; p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4
+    psrlw         m0, m2, 3
+    psrlw         m1, m7, 3
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m4
+    por           m0, m1            ; p0
+%ifidn %2, v
+    mova [tmpq+stride3q], m0
+%else
+    mova  [rsp+1*16], m0
+%endif
+
+    punpcklbw     m0, m5, m15
+    punpckhbw     m1, m5, m15
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    pmaddubsw     m1, [PIC_sym(pb_1)]
+    paddw         m2, m0
+    paddw         m7, m1
+%if ARCH_X86_32
+    mova         m11, %%p3mem
+%endif
+    punpcklbw     m0, m11, m4
+    punpckhbw    m11, m11, m4
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    pmaddubsw    m11, [PIC_sym(pb_1)]
+    psubw         m2, m0
+    psubw         m7, m11           ; p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4
+    psrlw         m0, m2, 3
+    psrlw        m11, m7, 3
+    packuswb      m0, m11
+    pand          m0, m9
+    pandn        m11, m9, m5
+    por          m11, m0            ; q0
+%ifidn %2, v
+    mova [dstq+strideq*0], m11
+%elif ARCH_X86_32
+    mova  [esp+8*16], m11
+%endif
+
+    punpcklbw     m0, m5, m15
+    punpckhbw     m1, m5, m15
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw         m2, m0
+    paddw         m7, m1
+    punpcklbw     m0, m13, m6
+    punpckhbw     m1, m13, m6
+    pmaddubsw     m0, [PIC_sym(pb_m1_1)]
+    pmaddubsw     m1, [PIC_sym(pb_m1_1)]
+    paddw         m2, m0
+    paddw         m7, m1            ; p1 + p0 + q0 + 2 * q1 + q2 + 2 * q3 + 4
+    psrlw         m0, m2, 3
+    psrlw         m1, m7, 3
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m6
+    por           m0, m1            ; q1
+%ifidn %2, v
+    mova [dstq+strideq*1], m0
+%else
+ %if ARCH_X86_64
+    SWAP           0, 13
+ %else
+    mova  [esp+9*16], m0
+ %endif
+%endif
+
+    punpcklbw     m0, m3, m6
+    punpckhbw     m1, m3, m6
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    pmaddubsw     m1, [PIC_sym(pb_1)]
+    psubw         m2, m0
+    psubw         m7, m1
+    punpcklbw     m0, m14, m15
+    punpckhbw     m1, m14, m15
+    pmaddubsw     m0, [PIC_sym(pb_1)]
+    pmaddubsw     m1, [PIC_sym(pb_1)]
+    paddw         m2, m0
+    paddw         m7, m1            ; p0 + q0 + q1 + q2 + 2 * q2 + 3 * q3 + 4
+    psrlw         m2, 3
+    psrlw         m7, 3
+    packuswb      m2, m7
+    pand          m2, m9
+    pandn         m7, m9, m14
+    por           m2, m7            ; q2
+%ifidn %2, v
+    mova [dstq+strideq*2], m2
+%else
+    mova          m0, [rsp+0*16]
+%if %1 == 8
+    mova          m1, [rsp+1*16]
+    mova          m4, %%p3mem
+
+%if ARCH_X86_32
+ %define m10 [esp+2*16]
+ %define m11 [esp+8*16]
+ %define m13 [esp+9*16]
+%endif
+
+    ; 16x8 transpose
+    punpcklbw     m3, m4, m10
+    punpckhbw     m4, m10
+    punpcklbw     m5, m0, m1
+    punpckhbw     m0, m1
+    punpcklbw     m1, m11, m13
+    punpckhbw     m6, m11, m13
+    punpcklbw     m7, m2, m15
+    punpckhbw     m2, m15
+%if ARCH_X86_64
+    SWAP           2, 15
+%else
+    mova         m15, m2
+%endif
+
+    punpcklwd     m2, m3, m5
+    punpckhwd     m3, m5
+    punpcklwd     m5, m4, m0
+    punpckhwd     m4, m0
+    punpcklwd     m0, m1, m7
+    punpckhwd     m1, m7
+    punpcklwd     m7, m6, m15
+    punpckhwd     m6, m15
+%if ARCH_X86_64
+    SWAP           6, 15
+%else
+    mova         m15, m6
+%endif
+
+    punpckldq     m6, m2, m0
+    punpckhdq     m2, m0
+    punpckldq     m0, m3, m1
+    punpckhdq     m3, m1
+    punpckldq     m1, m5, m7
+    punpckhdq     m5, m7
+    punpckldq     m7, m4, m15
+    punpckhdq     m4, m15
+
+    ; write 8x16
+    movq   [dstq+strideq*0-4], xm6
+    movhps [dstq+strideq*1-4], xm6
+    movq   [dstq+strideq*2-4], xm2
+    movhps [dstq+stride3q -4], xm2
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm0
+    movhps [dstq+strideq*1-4], xm0
+    movq   [dstq+strideq*2-4], xm3
+    movhps [dstq+stride3q -4], xm3
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm1
+    movhps [dstq+strideq*1-4], xm1
+    movq   [dstq+strideq*2-4], xm5
+    movhps [dstq+stride3q -4], xm5
+    lea         dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0-4], xm7
+    movhps [dstq+strideq*1-4], xm7
+    movq   [dstq+strideq*2-4], xm4
+    movhps [dstq+stride3q -4], xm4
+    lea         dstq, [dstq+strideq*4]
+%else
+    ; 16x16 transpose and store
+    SWAP           6, 0
+    SWAP           7, 1
+ %if ARCH_X86_64
+    SWAP           5, 10, 2
+    SWAP           8, 11
+    SWAP           9, 13
+    mova [rsp+21*16], m12
+ %else
+    mova [esp+10*16], m2
+  %xdefine m8  m0
+  %xdefine m9  m1
+  %xdefine m10 m2
+  %xdefine m11 m3
+  %xdefine m12 m4
+  %xdefine m13 m5
+  %xdefine m14 m6
+  %xdefine m15 m7
+ %endif
+    mova          m0, [rsp+11*16]
+    mova          m1, [rsp+12*16]
+    mova          m2, [rsp+13*16]
+    mova          m3, [rsp+14*16]
+    mova          m4, [rsp+19*16]
+%if ARCH_X86_64
+    mova          m7, [rsp+ 1*16]
+    mova         m11, [rsp+20*16]
+    mova         m12, [rsp+15*16]
+    mova         m13, [rsp+16*16]
+    mova         m14, [rsp+17*16]
+    TRANSPOSE_16X16B 1, [rsp+18*16]
+%else
+    mova          m5, [esp+ 2*16]
+    TRANSPOSE_16X16B 1, [esp+32*16]
+    mov         tmpq, dstq
+    lea         dstq, [dstq+strideq*8]
+%endif
+    movu [dstq+strideq*0-8], xm0
+    movu [dstq+strideq*1-8], xm1
+    movu [dstq+strideq*2-8], xm2
+    movu [dstq+stride3q -8], xm3
+    lea         dstq, [dstq+strideq*4]
+    movu [dstq+strideq*0-8], xm4
+    movu [dstq+strideq*1-8], xm5
+    movu [dstq+strideq*2-8], xm6
+    movu [dstq+stride3q -8], xm7
+%if ARCH_X86_64
+    lea         dstq, [dstq+strideq*4]
+%else
+  %xdefine m8  m0
+  %xdefine m9  m1
+  %xdefine m10 m2
+  %xdefine m11 m3
+  %xdefine m12 m4
+  %xdefine m13 m5
+  %xdefine m14 m6
+  %xdefine m15 m7
+    mova          m8, [esp+11*16]
+    mova          m9, [esp+12*16]
+    mova         m10, [esp+13*16]
+    mova         m11, [esp+14*16]
+    mova         m12, [esp+26*16]
+    mova         m13, [esp+27*16]
+    mova         m14, [esp+ 0*16]
+    mova         m15, [esp+ 1*16]
+    mov         dstq, tmpq
+%endif
+    movu [dstq+strideq*0-8], xm8
+    movu [dstq+strideq*1-8], xm9
+    movu [dstq+strideq*2-8], xm10
+    movu [dstq+stride3q -8], xm11
+    lea         dstq, [dstq+strideq*4]
+    movu [dstq+strideq*0-8], xm12
+    movu [dstq+strideq*1-8], xm13
+    movu [dstq+strideq*2-8], xm14
+    movu [dstq+stride3q -8], xm15
+    lea         dstq, [dstq+strideq*4]
+%if ARCH_X86_32
+    lea         dstq, [dstq+strideq*8]
+%else
+    mova         m12, [rsp+21*16]
+%endif
+
+%endif ; if %1 == 8
+%endif ; ifidn %2, v
+%elif %1 == 6
+    ; flat6 filter
+%if ARCH_X86_32
+    mova  [esp+3*16], m3
+    mova  [esp+4*16], m4
+    mova  [esp+5*16], m5
+    mova  [esp+6*16], m6
+ %xdefine m8  m3
+ %xdefine m10 m4
+ %xdefine m11 m5
+ %xdefine m15 m6
+ %define m3  [esp+3*16]
+ %define m4  [esp+4*16]
+ %define m5  [esp+5*16]
+ %define m6  [esp+6*16]
+ %define m9  %%flat8mem
+ %define m13 %%p2mem
+ %define m14 %%q2mem
+%endif
+
+    punpcklbw     m8, m13, m5
+    punpckhbw    m11, m13, m5
+    pmaddubsw     m0, m8, [PIC_sym(pb_3_1)]
+    pmaddubsw     m1, m11, [PIC_sym(pb_3_1)]
+    punpcklbw     m7, m4, m3
+    punpckhbw    m10, m4, m3
+    pmaddubsw     m2, m7, [PIC_sym(pb_2)]
+    pmaddubsw    m15, m10, [PIC_sym(pb_2)]
+    paddw         m0, m2
+    paddw         m1, m15
+    pmulhrsw      m2, m0, [PIC_sym(pw_4096)]
+    pmulhrsw     m15, m1, [PIC_sym(pw_4096)]
+    packuswb      m2, m15
+    pand          m2, m9
+    pandn        m15, m9, m3
+    por           m2, m15
+%ifidn %2, v
+    mova [tmpq+strideq*2], m2                   ; p1
+%elif ARCH_X86_32
+    mova [esp+11*16], m2
+%endif
+
+    pmaddubsw     m8, [PIC_sym(pb_m1_1)]
+    pmaddubsw    m11, [PIC_sym(pb_m1_1)]
+    paddw         m0, m8
+    paddw         m1, m11
+    punpcklbw     m8, m13, m6
+    punpckhbw    m11, m13, m6
+%if ARCH_X86_64
+    SWAP           2, 13
+%endif
+    pmaddubsw     m8, [PIC_sym(pb_m1_1)]
+    pmaddubsw    m11, [PIC_sym(pb_m1_1)]
+    paddw         m0, m8
+    paddw         m1, m11
+    pmulhrsw      m2, m0, [PIC_sym(pw_4096)]
+    pmulhrsw     m15, m1, [PIC_sym(pw_4096)]
+    packuswb      m2, m15
+    pand          m2, m9
+    pandn        m15, m9, m4
+    por           m2, m15
+%ifidn %2, v
+    mova [tmpq+stride3q], m2                    ; p0
+%elif ARCH_X86_32
+    mova  [esp+8*16], m2
+%endif
+
+    paddw         m0, m8
+    paddw         m1, m11
+    punpcklbw     m8, m3, m14
+    punpckhbw    m11, m3, m14
+%if ARCH_X86_64
+    SWAP           2, 14
+%endif
+    pmaddubsw     m2, m8, [PIC_sym(pb_m1_1)]
+    pmaddubsw    m15, m11, [PIC_sym(pb_m1_1)]
+    paddw         m0, m2
+    paddw         m1, m15
+    pmulhrsw      m2, m0, [PIC_sym(pw_4096)]
+    pmulhrsw     m15, m1, [PIC_sym(pw_4096)]
+    packuswb      m2, m15
+    pand          m2, m9
+    pandn        m15, m9, m5
+    por           m2, m15
+%ifidn %2, v
+    mova [dstq+strideq*0], m2                   ; q0
+%endif
+
+    pmaddubsw     m8, [PIC_sym(pb_m1_2)]
+    pmaddubsw    m11, [PIC_sym(pb_m1_2)]
+    paddw         m0, m8
+    paddw         m1, m11
+    pmaddubsw     m7, [PIC_sym(pb_m1_0)]
+    pmaddubsw    m10, [PIC_sym(pb_m1_0)]
+    paddw         m0, m7
+    paddw         m1, m10
+    pmulhrsw      m0, [PIC_sym(pw_4096)]
+    pmulhrsw      m1, [PIC_sym(pw_4096)]
+    packuswb      m0, m1
+    pand          m0, m9
+    pandn         m1, m9, m6
+    por           m0, m1
+%if ARCH_X86_32
+ %xdefine m3 m8
+ %xdefine m4 m10
+ %xdefine m5 m11
+ %xdefine m6 m15
+%endif
+%ifidn %2, v
+    mova [dstq+strideq*1], m0                   ; q1
+%else
+ %if ARCH_X86_64
+    SWAP           3, 13
+    SWAP           4, 14
+ %else
+    mova          m3, [esp+11*16]
+    mova          m4, [esp+ 8*16]
+ %endif
+    SWAP           5, 2
+    SWAP           6, 0
+    TRANSPOSE_16x4_AND_WRITE_4x16 3, 4, 5, 6, 7
+%endif
+%else ; if %1 == 4
+%ifidn %2, v
+    mova [tmpq+strideq*0], m3                   ; p1
+    mova [tmpq+strideq*1], m4                   ; p0
+    mova [tmpq+strideq*2], m5                   ; q0
+    mova [tmpq+stride3q ], m6                   ; q1
+%else
+    TRANSPOSE_16x4_AND_WRITE_4x16 3, 4, 5, 6, 7
+%endif
+%endif
+%if ARCH_X86_32
+ %define m12 m12reg
+%endif
+%endmacro
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;          32-bit PIC helpers          ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%if ARCH_X86_32
+ %define PIC_base_offset $$
+
+ %macro SETUP_PIC 0 ; PIC_reg
+  %define PIC_reg r2
+  %assign PIC_reg_stk_offset stack_size-gprsize*(1+copy_args*4)
+    LEA      PIC_reg, $$
+ %endmacro
+
+ %macro XCHG_PIC_REG 1 ; 0=mask 1=PIC_base
+  %if %1 == 0
+    mov [esp+PIC_reg_stk_offset], PIC_reg
+    mov      PIC_reg, maskm
+  %else
+    mov      PIC_reg, [esp+PIC_reg_stk_offset]
+  %endif
+ %endmacro
+
+ %define PIC_sym(sym) (PIC_reg+(sym)-PIC_base_offset)
+
+%else
+ %macro XCHG_PIC_REG 1
+ %endmacro
+ %define PIC_sym(sym) (sym)
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%if ARCH_X86_32
+ %if STACK_ALIGNMENT < required_stack_alignment
+  %assign copy_args 1
+ %else
+  %assign copy_args 0
+ %endif
+%endif
+
+%macro RELOC_ARGS 1
+ %if copy_args
+  %define maskm     [esp+stack_size-gprsize*1]
+  %define l_stridem [esp+stack_size-gprsize*2]
+  %define lutm      [esp+stack_size-gprsize*3]
+  %define %1m       [esp+stack_size-gprsize*4]
+    mov          r6d, r6m
+    mov        maskm, maskd
+    mov         lutm, lutd
+    mov          %1m, r6d
+ %else
+  %define %1m       r6m
+ %endif
+%endmacro
+
+%if ARCH_X86_32
+ %define tmpq       r4
+ %define mstrideq   r5
+ %define stride3q   r6
+ %define l_stride3q r6
+%endif
+
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal lpf_v_sb_y_8bpc, 7, 11, 16, 16 * 15, \
+                    dst, stride, mask, l, l_stride, lut, \
+                    w, stride3, mstride, tmp, mask_bits
+%else
+cglobal lpf_v_sb_y_8bpc, 6, 7, 8, -16 * (26 + copy_args), \
+                    dst, stride, mask, l, l_stride, lut, mask_bits
+    RELOC_ARGS w
+    SETUP_PIC
+ %define m12 m5
+%endif
+    shl    l_strideq, 2
+    sub           lq, l_strideq
+%if ARCH_X86_64
+    mov     mstrideq, strideq
+    neg     mstrideq
+    lea     stride3q, [strideq*3]
+%else
+    mov    l_stridem, l_strided
+%endif
+    mov   mask_bitsd, 0xf
+    mova         m12, [PIC_sym(pd_mask)]
+    XCHG_PIC_REG   0
+    movu          m0, [maskq]
+    pxor          m4, m4
+    movd          m3, [lutq+136]
+    pshufb        m3, m4
+    pshufd        m2, m0, q2222
+    pshufd        m1, m0, q1111
+    pshufd        m0, m0, q0000
+    por           m1, m2
+    por           m0, m1
+    mova [rsp+11*16], m0
+    mova [rsp+12*16], m1
+    mova [rsp+13*16], m2
+    mova [rsp+14*16], m3
+
+%define maskmem [esp+15*16]
+%define mask0   [rsp+11*16]
+%define mask1   [rsp+12*16]
+%define mask2   [rsp+13*16]
+%define minlvl  [rsp+14*16]
+
+.loop:
+    test   [maskq+8], mask_bitsd                ; vmask[2]
+    je .no_flat16
+
+%if ARCH_X86_32
+    XCHG_PIC_REG   1
+    mov  [esp+25*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER        16, v
+    jmp .end
+
+.no_flat16:
+    test   [maskq+4], mask_bitsd                ; vmask[1]
+    je .no_flat
+
+%if ARCH_X86_32
+    XCHG_PIC_REG   1
+    mov  [esp+25*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER         8, v
+    jmp .end
+
+.no_flat:
+    test   [maskq+0], mask_bitsd                ; vmask[0]
+    XCHG_PIC_REG   1
+    je .no_filter
+
+%if ARCH_X86_32
+    mov  [esp+25*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER         4, v
+
+.end:
+%if ARCH_X86_32
+    mova         m12, maskmem
+    mov   mask_bitsd, [esp+25*16]
+%endif
+.no_filter:
+    pslld        m12, 4
+    shl   mask_bitsd, 4
+    add           lq, 16
+    add         dstq, 16
+%if ARCH_X86_64
+    sub           wd, 4
+%else
+    sub     dword wm, 4
+%endif
+    XCHG_PIC_REG   0
+    jg .loop
+    RET
+
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal lpf_h_sb_y_8bpc, 7, 11, 16, 16 * 26, \
+                    dst, stride, mask, l, l_stride, lut, \
+                    h, stride3, l_stride3, tmp, mask_bits
+%else
+cglobal lpf_h_sb_y_8bpc, 6, 7, 8, -16 * (39 + copy_args), \
+                    dst, stride, mask, l, l_stride, lut, mask_bits
+    RELOC_ARGS h
+    SETUP_PIC
+ %define m12 m5
+%endif
+    sub           lq, 4
+    shl    l_strideq, 2
+%if ARCH_X86_64
+    lea     stride3q, [strideq*3]
+    lea   l_stride3q, [l_strideq*3]
+%else
+    mov    l_stridem, l_strided
+%endif
+    mov   mask_bitsd, 0xf
+    mova         m12, [PIC_sym(pd_mask)]
+    XCHG_PIC_REG   0
+    movu          m0, [maskq]
+    pxor          m4, m4
+    movd          m3, [lutq+136]
+    pshufb        m3, m4
+    pshufd        m2, m0, q2222
+    pshufd        m1, m0, q1111
+    pshufd        m0, m0, q0000
+    por           m1, m2
+    por           m0, m1
+    mova [rsp+22*16], m0
+    mova [rsp+23*16], m1
+    mova [rsp+24*16], m2
+    mova [rsp+25*16], m3
+
+%define maskmem [esp+37*16]
+%define mask0   [rsp+22*16]
+%define mask1   [rsp+23*16]
+%define mask2   [rsp+24*16]
+%define minlvl  [rsp+25*16]
+
+.loop:
+    test   [maskq+8], mask_bitsd                ; vmask[2]
+    je .no_flat16
+
+%if ARCH_X86_32
+    XCHG_PIC_REG   1
+    mov  [esp+38*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER        16, h
+    jmp .end
+
+.no_flat16:
+    test   [maskq+4], mask_bitsd                ; vmask[1]
+    je .no_flat
+
+%if ARCH_X86_32
+    XCHG_PIC_REG   1
+    mov  [esp+38*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER         8, h
+    jmp .end
+
+.no_flat:
+    test   [maskq+0], mask_bitsd                ; vmask[0]
+    XCHG_PIC_REG   1
+    je .no_filter
+
+%if ARCH_X86_32
+    mov  [esp+38*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER         4, h
+    jmp .end
+
+.no_filter:
+    lea         dstq, [dstq+strideq*8]
+    lea         dstq, [dstq+strideq*8]
+%if ARCH_X86_32
+    jmp .end_noload
+.end:
+    mova         m12, maskmem
+    mov    l_strideq, l_stridem
+    mov   mask_bitsd, [esp+38*16]
+.end_noload:
+%else
+.end:
+%endif
+    lea           lq, [lq+l_strideq*4]
+    pslld        m12, 4
+    shl   mask_bitsd, 4
+%if ARCH_X86_64
+    sub           hd, 4
+%else
+    sub     dword hm, 4
+%endif
+    XCHG_PIC_REG   0
+    jg .loop
+    RET
+
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal lpf_v_sb_uv_8bpc, 7, 11, 16, 3 * 16, \
+                     dst, stride, mask, l, l_stride, lut, \
+                     w, stride3, mstride, tmp, mask_bits
+%else
+cglobal lpf_v_sb_uv_8bpc, 6, 7, 8, -16 * (12 + copy_args), \
+                     dst, stride, mask, l, l_stride, lut, mask_bits
+    RELOC_ARGS w
+    SETUP_PIC
+ %define m12 m4
+%endif
+    shl    l_strideq, 2
+    sub           lq, l_strideq
+%if ARCH_X86_64
+    mov     mstrideq, strideq
+    neg     mstrideq
+    lea     stride3q, [strideq*3]
+%else
+    mov    l_stridem, l_strided
+%endif
+    mov   mask_bitsd, 0xf
+    mova         m12, [PIC_sym(pd_mask)]
+    XCHG_PIC_REG   0
+    movq          m0, [maskq]
+    pxor          m3, m3
+    movd          m2, [lutq+136]
+    pshufb        m2, m3
+    pshufd        m1, m0, q1111
+    pshufd        m0, m0, q0000
+    por           m0, m1
+    mova  [rsp+0*16], m0
+    mova  [rsp+1*16], m1
+    mova  [rsp+2*16], m2
+
+%define maskmem [esp+7*16]
+%define mask0   [rsp+0*16]
+%define mask1   [rsp+1*16]
+%define minlvl  [rsp+2*16]
+
+.loop:
+    test   [maskq+4], mask_bitsd                ; vmask[1]
+    je .no_flat
+
+%if ARCH_X86_32
+    XCHG_PIC_REG   1
+    mov  [esp+11*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER         6, v
+    jmp .end
+
+.no_flat:
+    test   [maskq+0], mask_bitsd                ; vmask[1]
+    XCHG_PIC_REG   1
+    je .no_filter
+
+%if ARCH_X86_32
+    mov  [esp+11*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER         4, v
+
+.end:
+%if ARCH_X86_32
+    mova         m12, maskmem
+    mov   mask_bitsd, [esp+11*16]
+%endif
+.no_filter:
+    pslld        m12, 4
+    shl   mask_bitsd, 4
+    add           lq, 16
+    add         dstq, 16
+%if ARCH_X86_64
+    sub           wd, 4
+%else
+    sub     dword wm, 4
+%endif
+    XCHG_PIC_REG   0
+    jg .loop
+    RET
+
+INIT_XMM ssse3
+%if ARCH_X86_64
+cglobal lpf_h_sb_uv_8bpc, 7, 11, 16, 16 * 3, \
+                     dst, stride, mask, l, l_stride, lut, \
+                     h, stride3, l_stride3, tmp, mask_bits
+%else
+cglobal lpf_h_sb_uv_8bpc, 6, 7, 8, -16 * (13 + copy_args), \
+                     dst, stride, mask, l, l_stride, lut, mask_bits
+    RELOC_ARGS h
+    SETUP_PIC
+ %define m12 m4
+%endif
+    sub           lq, 4
+    shl    l_strideq, 2
+%if ARCH_X86_64
+    lea     stride3q, [strideq*3]
+    lea   l_stride3q, [l_strideq*3]
+%else
+    mov    l_stridem, l_strided
+%endif
+    mov   mask_bitsd, 0xf
+    mova         m12, [PIC_sym(pd_mask)]
+    XCHG_PIC_REG   0
+    movq          m0, [maskq]
+    pxor          m3, m3
+    movd          m2, [lutq+136]
+    pshufb        m2, m3
+    pshufd        m1, m0, q1111
+    pshufd        m0, m0, q0000
+    por           m0, m1
+    mova  [rsp+0*16], m0
+    mova  [rsp+1*16], m1
+    mova  [rsp+2*16], m2
+
+%define maskmem [esp+7*16]
+%define mask0   [rsp+0*16]
+%define mask1   [rsp+1*16]
+%define minlvl  [rsp+2*16]
+
+.loop:
+    test   [maskq+4], mask_bitsd                ; vmask[1]
+    je .no_flat
+
+%if ARCH_X86_32
+    XCHG_PIC_REG   1
+    mov  [esp+12*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER         6, h
+    jmp .end
+
+.no_flat:
+    test   [maskq+0], mask_bitsd                ; vmask[1]
+    XCHG_PIC_REG   1
+    je .no_filter
+
+%if ARCH_X86_32
+    mov  [esp+12*16], mask_bitsd
+    mova     maskmem, m12
+%endif
+    FILTER         4, h
+    jmp .end
+
+.no_filter:
+    lea         dstq, [dstq+strideq*8]
+    lea         dstq, [dstq+strideq*8]
+%if ARCH_X86_32
+    jmp .end_noload
+.end:
+    mova         m12, maskmem
+    mov    l_strided, l_stridem
+    mov   mask_bitsd, [esp+12*16]
+.end_noload:
+%else
+.end:
+%endif
+    lea           lq, [lq+l_strideq*4]
+    pslld        m12, 4
+    shl   mask_bitsd, 4
+%if ARCH_X86_64
+    sub           hd, 4
+%else
+    sub     dword hm, 4
+%endif
+    XCHG_PIC_REG   0
+    jg .loop
+    RET
diff --git a/media/libdav1d/src/src/x86/looprestoration.h b/media/libdav1d/src/src/x86/looprestoration.h
new file mode 100644
index 0000000000..de23be8866
--- /dev/null
+++ b/media/libdav1d/src/src/x86/looprestoration.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/looprestoration.h"
+
+#include "common/intops.h"
+
+#define decl_wiener_filter_fns(ext) \
+decl_lr_filter_fn(BF(dav1d_wiener_filter7, ext)); \
+decl_lr_filter_fn(BF(dav1d_wiener_filter5, ext))
+
+#define decl_sgr_filter_fns(ext) \
+decl_lr_filter_fn(BF(dav1d_sgr_filter_5x5, ext)); \
+decl_lr_filter_fn(BF(dav1d_sgr_filter_3x3, ext)); \
+decl_lr_filter_fn(BF(dav1d_sgr_filter_mix, ext))
+
+decl_wiener_filter_fns(sse2);
+decl_wiener_filter_fns(ssse3);
+decl_wiener_filter_fns(avx2);
+decl_wiener_filter_fns(avx512icl);
+decl_sgr_filter_fns(ssse3);
+decl_sgr_filter_fns(avx2);
+decl_sgr_filter_fns(avx512icl);
+
+static ALWAYS_INLINE void loop_restoration_dsp_init_x86(Dav1dLoopRestorationDSPContext *const c, const int bpc) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSE2)) return;
+#if BITDEPTH == 8
+    c->wiener[0] = BF(dav1d_wiener_filter7, sse2);
+    c->wiener[1] = BF(dav1d_wiener_filter5, sse2);
+#endif
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSSE3)) return;
+    c->wiener[0] = BF(dav1d_wiener_filter7, ssse3);
+    c->wiener[1] = BF(dav1d_wiener_filter5, ssse3);
+    if (BITDEPTH == 8 || bpc == 10) {
+        c->sgr[0] = BF(dav1d_sgr_filter_5x5, ssse3);
+        c->sgr[1] = BF(dav1d_sgr_filter_3x3, ssse3);
+        c->sgr[2] = BF(dav1d_sgr_filter_mix, ssse3);
+    }
+
+#if ARCH_X86_64
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2)) return;
+
+    c->wiener[0] = BF(dav1d_wiener_filter7, avx2);
+    c->wiener[1] = BF(dav1d_wiener_filter5, avx2);
+    if (BITDEPTH == 8 || bpc == 10) {
+        c->sgr[0] = BF(dav1d_sgr_filter_5x5, avx2);
+        c->sgr[1] = BF(dav1d_sgr_filter_3x3, avx2);
+        c->sgr[2] = BF(dav1d_sgr_filter_mix, avx2);
+    }
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL)) return;
+
+    c->wiener[0] = BF(dav1d_wiener_filter7, avx512icl);
+#if BITDEPTH == 8
+    /* With VNNI we don't need a 5-tap version. */
+    c->wiener[1] = c->wiener[0];
+#else
+    c->wiener[1] = BF(dav1d_wiener_filter5, avx512icl);
+#endif
+    if (BITDEPTH == 8 || bpc == 10) {
+        c->sgr[0] = BF(dav1d_sgr_filter_5x5, avx512icl);
+        c->sgr[1] = BF(dav1d_sgr_filter_3x3, avx512icl);
+        c->sgr[2] = BF(dav1d_sgr_filter_mix, avx512icl);
+    }
+#endif
+}
diff --git a/media/libdav1d/src/src/x86/looprestoration16_avx2.asm b/media/libdav1d/src/src/x86/looprestoration16_avx2.asm
new file mode 100644
index 0000000000..4b18f7761e
--- /dev/null
+++ b/media/libdav1d/src/src/x86/looprestoration16_avx2.asm
@@ -0,0 +1,2689 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 32
+
+sgr_lshuf3:    db  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11
+sgr_lshuf5:    db  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9
+wiener_lshuf5: db  4,  5,  4,  5,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+               db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+wiener_lshuf7: db  8,  9,  8,  9,  8,  9,  8,  9,  8,  9, 10, 11, 12, 13, 14, 15
+               db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+wiener_shufA:  db  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11
+wiener_shufB:  db  6,  7,  4,  5,  8,  9,  6,  7, 10, 11,  8,  9, 12, 13, 10, 11
+wiener_shufC:  db  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15
+wiener_shufD:  db  2,  3, -1, -1,  4,  5, -1, -1,  6,  7, -1, -1,  8,  9, -1, -1
+wiener_shufE:  db  0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+
+wiener_hshift: dw 4, 4, 1, 1
+wiener_vshift: dw 1024, 1024, 4096, 4096
+wiener_round:  dd 1049600, 1048832
+
+pb_m10_m9:     times 2 db -10, -9
+pb_m6_m5:      times 2 db  -6, -5
+pb_m2_m1:      times 2 db  -2, -1
+pb_2_3:        times 2 db   2,  3
+pb_6_7:        times 2 db   6,  7
+pw_1023:       times 2 dw 1023
+pw_164_24:     dw 164, 24
+pw_455_24:     dw 455, 24
+pd_8:          dd 8
+pd_25:         dd 25
+pd_4096:       dd 4096
+pd_34816:      dd 34816
+pd_m262128:    dd -262128
+pf_256:        dd 256.0
+
+%define pw_256 sgr_lshuf5
+
+cextern pb_0to63
+
+SECTION .text
+
+DECLARE_REG_TMP 8, 7, 9, 11, 12, 13, 14 ; wiener ring buffer pointers
+
+INIT_YMM avx2
+cglobal wiener_filter7_16bpc, 4, 15, 16, -384*12-16, dst, stride, left, lpf, \
+                                                     w, h, edge, flt
+%define base t4-wiener_hshift
+    mov           fltq, r6mp
+    movifnidn       wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mov            t3d, r8m ; pixel_max
+    vbroadcasti128  m6, [wiener_shufA]
+    vpbroadcastd   m12, [fltq+ 0] ; x0 x1
+    lea             t4, [wiener_hshift]
+    vbroadcasti128  m7, [wiener_shufB]
+    add             wd, wd
+    vpbroadcastd   m13, [fltq+ 4] ; x2 x3
+    shr            t3d, 11
+    vpbroadcastd   m14, [fltq+16] ; y0 y1
+    add           lpfq, wq
+    vpbroadcastd   m15, [fltq+20] ; y2 y3
+    add           dstq, wq
+    vbroadcasti128  m8, [wiener_shufC]
+    lea             t1, [rsp+wq+16]
+    vbroadcasti128  m9, [wiener_shufD]
+    neg             wq
+    vpbroadcastd    m0, [base+wiener_hshift+t3*4]
+    vpbroadcastd   m10, [base+wiener_round+t3*4]
+    vpbroadcastd   m11, [base+wiener_vshift+t3*4]
+    pmullw         m12, m0 ; upshift filter coefs to make the
+    pmullw         m13, m0 ; horizontal downshift constant
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t6, t1
+    mov             t5, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t4, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .h
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+.main:
+    lea             t0, [t1+384*2]
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v3
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.v1:
+    call .v
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    mov             t6, t1
+    mov             t5, t1
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v3
+    add             t0, 384*8
+    call .hv
+    dec             hd
+    jnz .main
+.v3:
+    call .v
+.v2:
+    call .v
+    jmp .v1
+.extend_right:
+    movd           xm1, r10d
+    vpbroadcastd    m0, [pb_6_7]
+    mova            m2, [pb_0to63]
+    vpbroadcastb    m1, xm1
+    psubb           m0, m1
+    pminub          m0, m2
+    pshufb          m3, m0
+    vpbroadcastd    m0, [pb_m2_m1]
+    psubb           m0, m1
+    pminub          m0, m2
+    pshufb          m4, m0
+    vpbroadcastd    m0, [pb_m10_m9]
+    psubb           m0, m1
+    pminub          m0, m2
+    pshufb          m5, m0
+    ret
+.h:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movq           xm3, [leftq]
+    vpblendd        m3, [lpfq+r10-8], 0xfc
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    vbroadcasti128  m3, [lpfq+r10] ; avoid accessing memory located
+    mova            m4, [lpfq+r10] ; before the start of the buffer
+    shufpd          m3, m4, 0x05
+    pshufb          m3, [wiener_lshuf7]
+    jmp .h_main2
+.h_top:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m3, [lpfq+r10-8]
+.h_main:
+    mova            m4, [lpfq+r10+0]
+.h_main2:
+    movu            m5, [lpfq+r10+8]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -36
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    pshufb          m0, m3, m6
+    pshufb          m1, m4, m7
+    paddw           m0, m1
+    pshufb          m3, m8
+    pmaddwd         m0, m12
+    pshufb          m1, m4, m9
+    paddw           m3, m1
+    pshufb          m1, m4, m6
+    pmaddwd         m3, m13
+    pshufb          m2, m5, m7
+    paddw           m1, m2
+    vpbroadcastd    m2, [pd_m262128] ; (1 << 4) - (1 << 18)
+    pshufb          m4, m8
+    pmaddwd         m1, m12
+    pshufb          m5, m9
+    paddw           m4, m5
+    pmaddwd         m4, m13
+    paddd           m0, m2
+    paddd           m1, m2
+    paddd           m0, m3
+    paddd           m1, m4
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    psraw           m0, 1
+    mova      [t1+r10], m0
+    add            r10, 32
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movq           xm3, [leftq]
+    vpblendd        m3, [lpfq+r10-8], 0xfc
+    add          leftq, 8
+    jmp .hv_main
+.hv_extend_left:
+    movu            m3, [lpfq+r10-8]
+    pshufb          m3, [wiener_lshuf7]
+    jmp .hv_main
+.hv_bottom:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m3, [lpfq+r10-8]
+.hv_main:
+    mova            m4, [lpfq+r10+0]
+    movu            m5, [lpfq+r10+8]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -36
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    pshufb          m0, m3, m6
+    pshufb          m1, m4, m7
+    paddw           m0, m1
+    pshufb          m3, m8
+    pmaddwd         m0, m12
+    pshufb          m1, m4, m9
+    paddw           m3, m1
+    pshufb          m1, m4, m6
+    pmaddwd         m3, m13
+    pshufb          m2, m5, m7
+    paddw           m1, m2
+    vpbroadcastd    m2, [pd_m262128]
+    pshufb          m4, m8
+    pmaddwd         m1, m12
+    pshufb          m5, m9
+    paddw           m4, m5
+    pmaddwd         m4, m13
+    paddd           m0, m2
+    paddd           m1, m2
+    mova            m2, [t4+r10]
+    paddw           m2, [t2+r10]
+    mova            m5, [t3+r10]
+    paddd           m0, m3
+    paddd           m1, m4
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    mova            m4, [t5+r10]
+    paddw           m4, [t1+r10]
+    psraw           m0, 1
+    paddw           m3, m0, [t6+r10]
+    mova      [t0+r10], m0
+    punpcklwd       m0, m2, m5
+    pmaddwd         m0, m15
+    punpckhwd       m2, m5
+    pmaddwd         m2, m15
+    punpcklwd       m1, m3, m4
+    pmaddwd         m1, m14
+    punpckhwd       m3, m4
+    pmaddwd         m3, m14
+    paddd           m0, m10
+    paddd           m2, m10
+    paddd           m0, m1
+    paddd           m2, m3
+    psrad           m0, 5
+    psrad           m2, 5
+    packusdw        m0, m2
+    pmulhuw         m0, m11
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .hv_loop
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t6
+    add           dstq, strideq
+    ret
+.v:
+    mov            r10, wq
+.v_loop:
+    mova            m1, [t4+r10]
+    paddw           m1, [t2+r10]
+    mova            m2, [t3+r10]
+    mova            m4, [t1+r10]
+    paddw           m3, m4, [t6+r10]
+    paddw           m4, [t5+r10]
+    punpcklwd       m0, m1, m2
+    pmaddwd         m0, m15
+    punpckhwd       m1, m2
+    pmaddwd         m1, m15
+    punpcklwd       m2, m3, m4
+    pmaddwd         m2, m14
+    punpckhwd       m3, m4
+    pmaddwd         m3, m14
+    paddd           m0, m10
+    paddd           m1, m10
+    paddd           m0, m2
+    paddd           m1, m3
+    psrad           m0, 5
+    psrad           m1, 5
+    packusdw        m0, m1
+    pmulhuw         m0, m11
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .v_loop
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    add           dstq, strideq
+    ret
+
+cglobal wiener_filter5_16bpc, 4, 13, 16, 384*8+16, dst, stride, left, lpf, \
+                                                   w, h, edge, flt
+%define base t4-wiener_hshift
+    mov           fltq, r6mp
+    movifnidn       wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mov            t3d, r8m ; pixel_max
+    vbroadcasti128  m5, [wiener_shufE]
+    vpbroadcastw   m11, [fltq+ 2] ; x1
+    vbroadcasti128  m6, [wiener_shufB]
+    lea             t4, [wiener_hshift]
+    vbroadcasti128  m7, [wiener_shufD]
+    add             wd, wd
+    vpbroadcastd   m12, [fltq+ 4] ; x2 x3
+    shr            t3d, 11
+    vpbroadcastd    m8, [pd_m262128] ; (1 << 4) - (1 << 18)
+    add           lpfq, wq
+    vpbroadcastw   m13, [fltq+18] ; y1
+    add           dstq, wq
+    vpbroadcastd   m14, [fltq+20] ; y2 y3
+    lea             t1, [rsp+wq+16]
+    neg             wq
+    vpbroadcastd    m0, [base+wiener_hshift+t3*4]
+    vpbroadcastd    m9, [base+wiener_round+t3*4]
+    vpbroadcastd   m10, [base+wiener_vshift+t3*4]
+    mova           m15, [wiener_lshuf5]
+    pmullw         m11, m0
+    pmullw         m12, m0
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t4, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t3, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+.main:
+    mov             t0, t4
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v2
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v2
+    add             t0, 384*6
+    call .hv
+    dec             hd
+    jnz .main
+.v2:
+    call .v
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    add           dstq, strideq
+.v1:
+    call .v
+    jmp .end
+.extend_right:
+    movd           xm2, r10d
+    vpbroadcastd    m0, [pb_2_3]
+    vpbroadcastd    m1, [pb_m6_m5]
+    vpbroadcastb    m2, xm2
+    psubb           m0, m2
+    psubb           m1, m2
+    mova            m2, [pb_0to63]
+    pminub          m0, m2
+    pminub          m1, m2
+    pshufb          m3, m0
+    pshufb          m4, m1
+    ret
+.h:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd           xm3, [leftq+4]
+    vpblendd        m3, [lpfq+r10-4], 0xfe
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    vbroadcasti128  m4, [lpfq+r10] ; avoid accessing memory located
+    mova            m3, [lpfq+r10] ; before the start of the buffer
+    palignr         m3, m4, 12
+    pshufb          m3, m15
+    jmp .h_main
+.h_top:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m3, [lpfq+r10-4]
+.h_main:
+    movu            m4, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -34
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    pshufb          m0, m3, m5
+    pmaddwd         m0, m11
+    pshufb          m1, m4, m5
+    pmaddwd         m1, m11
+    pshufb          m2, m3, m6
+    pshufb          m3, m7
+    paddw           m2, m3
+    pshufb          m3, m4, m6
+    pmaddwd         m2, m12
+    pshufb          m4, m7
+    paddw           m3, m4
+    pmaddwd         m3, m12
+    paddd           m0, m8
+    paddd           m1, m8
+    paddd           m0, m2
+    paddd           m1, m3
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    psraw           m0, 1
+    mova      [t1+r10], m0
+    add            r10, 32
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movd           xm3, [leftq+4]
+    vpblendd        m3, [lpfq+r10-4], 0xfe
+    add          leftq, 8
+    jmp .hv_main
+.hv_extend_left:
+    movu            m3, [lpfq+r10-4]
+    pshufb          m3, m15
+    jmp .hv_main
+.hv_bottom:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m3, [lpfq+r10-4]
+.hv_main:
+    movu            m4, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -34
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    pshufb          m0, m3, m5
+    pmaddwd         m0, m11
+    pshufb          m1, m4, m5
+    pmaddwd         m1, m11
+    pshufb          m2, m3, m6
+    pshufb          m3, m7
+    paddw           m2, m3
+    pshufb          m3, m4, m6
+    pmaddwd         m2, m12
+    pshufb          m4, m7
+    paddw           m3, m4
+    pmaddwd         m3, m12
+    paddd           m0, m8
+    paddd           m1, m8
+    paddd           m0, m2
+    mova            m2, [t3+r10]
+    paddw           m2, [t1+r10]
+    paddd           m1, m3
+    mova            m4, [t2+r10]
+    punpckhwd       m3, m2, m4
+    pmaddwd         m3, m14
+    punpcklwd       m2, m4
+    mova            m4, [t4+r10]
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    pmaddwd         m2, m14
+    psraw           m0, 1
+    mova      [t0+r10], m0
+    punpckhwd       m1, m0, m4
+    pmaddwd         m1, m13
+    punpcklwd       m0, m4
+    pmaddwd         m0, m13
+    paddd           m3, m9
+    paddd           m2, m9
+    paddd           m1, m3
+    paddd           m0, m2
+    psrad           m1, 5
+    psrad           m0, 5
+    packusdw        m0, m1
+    pmulhuw         m0, m10
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .hv_loop
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t4
+    add           dstq, strideq
+    ret
+.v:
+    mov            r10, wq
+.v_loop:
+    mova            m0, [t1+r10]
+    paddw           m2, m0, [t3+r10]
+    mova            m1, [t2+r10]
+    mova            m4, [t4+r10]
+    punpckhwd       m3, m2, m1
+    pmaddwd         m3, m14
+    punpcklwd       m2, m1
+    pmaddwd         m2, m14
+    punpckhwd       m1, m0, m4
+    pmaddwd         m1, m13
+    punpcklwd       m0, m4
+    pmaddwd         m0, m13
+    paddd           m3, m9
+    paddd           m2, m9
+    paddd           m1, m3
+    paddd           m0, m2
+    psrad           m1, 5
+    psrad           m0, 5
+    packusdw        m0, m1
+    pmulhuw         m0, m10
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .v_loop
+    ret
+
+cglobal sgr_filter_5x5_16bpc, 4, 14, 16, 400*24+16, dst, stride, left, lpf, \
+                                                    w, h, edge, params
+%define base r13-pb_m10_m9
+    movifnidn       wd, wm
+    mov        paramsq, r6mp
+    lea            r13, [pb_m10_m9]
+    movifnidn       hd, hm
+    mov          edged, r7m
+    vpbroadcastw    m7, [paramsq+8] ; w0
+    add             wd, wd
+    vpbroadcastd    m8, [base+pd_8]
+    add           lpfq, wq
+    vpbroadcastd    m9, [base+pd_25]
+    add           dstq, wq
+    mova          xm10, [base+sgr_lshuf5]
+    lea             t3, [rsp+wq*2+400*12+16]
+    vpbroadcastd   m11, [paramsq+0] ; s0
+    lea             t4, [rsp+wq+400*20+16]
+    vpbroadcastd   m12, [base+pw_164_24]
+    lea             t1, [rsp+wq+20]
+    vbroadcastss   m13, [base+pf_256]
+    neg             wq
+    vpbroadcastd   m14, [base+pd_34816] ; (1 << 11) + (1 << 15)
+    pxor            m6, m6
+    vpbroadcastd   m15, [base+pw_1023]
+    psllw           m7, 4
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    call .top_fixup
+    add             t1, 400*6
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    mov             t0, t2
+    dec             hd
+    jz .height1
+    or           edged, 16
+    call .h
+.main:
+    add           lpfq, strideq
+    call .hv
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    test            hd, hd
+    jz .odd_height
+    call .h
+    add           lpfq, strideq
+    call .hv
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .h_top
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .hv
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .hv
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea             t2, [t1+400*6]
+    call .top_fixup
+    dec             hd
+    jz .no_top_height1
+    or           edged, 16
+    mov             t0, t1
+    mov             t1, t2
+    jmp .main
+.no_top_height1:
+    call .v
+    call .prep_n
+    jmp .odd_height_end
+.extend_right:
+    vpbroadcastw    m0, [lpfq-2]
+    movu            m1, [r13+r10+ 0]
+    movu            m2, [r13+r10+16]
+    vpblendvb       m4, m0, m1
+    vpblendvb       m5, m0, m2
+    ret
+.h: ; horizontal boxsum
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    vpbroadcastq   xm5, [leftq]
+    vinserti128     m5, [lpfq+wq], 1
+    mova            m4, [lpfq+wq]
+    add          leftq, 8
+    palignr         m4, m5, 10
+    jmp .h_main
+.h_extend_left:
+    mova           xm4, [lpfq+wq]
+    pshufb         xm4, xm10
+    vinserti128     m4, [lpfq+wq+10], 1
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m4, [lpfq+r10- 2]
+.h_main:
+    movu            m5, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -36
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    palignr         m2, m5, m4, 2
+    paddw           m0, m4, m2
+    palignr         m3, m5, m4, 6
+    paddw           m0, m3
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m1
+    punpckhwd       m2, m3
+    pmaddwd         m2, m2
+    shufpd          m5, m4, m5, 0x05
+    paddw           m0, m5
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m3
+    paddd           m1, m3
+    punpckhwd       m3, m4, m5
+    pmaddwd         m3, m3
+    shufps          m4, m5, q2121
+    paddw           m0, m4             ; sum
+    punpcklwd       m5, m4, m6
+    pmaddwd         m5, m5
+    punpckhwd       m4, m6
+    pmaddwd         m4, m4
+    paddd           m2, m3
+    test         edgeb, 16             ; y > 0
+    jz .h_loop_end
+    paddw           m0, [t1+r10+400*0]
+    paddd           m1, [t1+r10+400*2]
+    paddd           m2, [t1+r10+400*4]
+.h_loop_end:
+    paddd           m1, m5             ; sumsq
+    paddd           m2, m4
+    mova [t1+r10+400*0], m0
+    mova [t1+r10+400*2], m1
+    mova [t1+r10+400*4], m2
+    add            r10, 32
+    jl .h_loop
+    ret
+.top_fixup:
+    lea            r10, [wq-4]
+.top_fixup_loop: ; the sums of the first row needs to be doubled
+    mova            m0, [t1+r10+400*0]
+    mova            m1, [t1+r10+400*2]
+    mova            m2, [t1+r10+400*4]
+    paddw           m0, m0
+    paddd           m1, m1
+    paddd           m2, m2
+    mova [t2+r10+400*0], m0
+    mova [t2+r10+400*2], m1
+    mova [t2+r10+400*4], m2
+    add            r10, 32
+    jl .top_fixup_loop
+    ret
+ALIGN function_align
+.hv: ; horizontal boxsum + vertical boxsum + ab
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    vpbroadcastq   xm5, [leftq]
+    vinserti128     m5, [lpfq+wq], 1
+    mova            m4, [lpfq+wq]
+    add          leftq, 8
+    palignr         m4, m5, 10
+    jmp .hv_main
+.hv_extend_left:
+    mova           xm4, [lpfq+wq]
+    pshufb         xm4, xm10
+    vinserti128     m4, [lpfq+wq+10], 1
+    jmp .hv_main
+.hv_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m4, [lpfq+r10- 2]
+.hv_main:
+    movu            m5, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -36
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    palignr         m3, m5, m4, 2
+    paddw           m0, m4, m3
+    palignr         m1, m5, m4, 6
+    paddw           m0, m1
+    punpcklwd       m2, m3, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m1
+    pmaddwd         m3, m3
+    shufpd          m5, m4, m5, 0x05
+    paddw           m0, m5
+    punpcklwd       m1, m4, m5
+    pmaddwd         m1, m1
+    paddd           m2, m1
+    punpckhwd       m1, m4, m5
+    pmaddwd         m1, m1
+    shufps          m4, m5, q2121
+    paddw           m0, m4            ; h sum
+    punpcklwd       m5, m4, m6
+    pmaddwd         m5, m5
+    punpckhwd       m4, m6
+    pmaddwd         m4, m4
+    paddd           m3, m1
+    paddd           m2, m5            ; h sumsq
+    paddd           m3, m4
+    paddw           m1, m0, [t1+r10+400*0]
+    paddd           m4, m2, [t1+r10+400*2]
+    paddd           m5, m3, [t1+r10+400*4]
+    test            hd, hd
+    jz .hv_last_row
+.hv_main2:
+    paddw           m1, [t2+r10+400*0] ; hv sum
+    paddd           m4, [t2+r10+400*2] ; hv sumsq
+    paddd           m5, [t2+r10+400*4]
+    mova [t0+r10+400*0], m0
+    mova [t0+r10+400*2], m2
+    mova [t0+r10+400*4], m3
+    psrlw           m3, m1, 1
+    paddd           m4, m8
+    pavgw           m3, m6             ; (b + 2) >> 2
+    paddd           m5, m8
+    psrld           m4, 4              ; (a + 8) >> 4
+    punpcklwd       m2, m3, m6
+    psrld           m5, 4
+    punpckhwd       m3, m6
+    pmulld          m4, m9             ; a * 25
+    pmulld          m5, m9
+    pmaddwd         m2, m2             ; b * b
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    pmaxud          m4, m2
+    pmaxud          m5, m3
+    psubd           m4, m2             ; p
+    psubd           m5, m3
+    pmulld          m4, m11            ; p * s
+    pmulld          m5, m11
+    pmaddwd         m0, m12            ; b * 164
+    pmaddwd         m1, m12
+    paddw           m4, m12
+    paddw           m5, m12
+    psrld           m4, 20             ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m13, m4
+    pcmpgtd         m5, m13, m5
+    mulps           m2, m13            ; 256 / (z + 1)
+    mulps           m3, m13
+    psrld           m4, 24             ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m14            ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m14
+    mova    [t4+r10+4], m2
+    psrld           m0, 12             ; b
+    psrld           m1, 12
+    mova         [t3+r10*2+ 8], xm0
+    vextracti128 [t3+r10*2+40], m0, 1
+    mova         [t3+r10*2+24], xm1
+    vextracti128 [t3+r10*2+56], m1, 1
+    add            r10, 32
+    jl .hv_loop
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t2
+    ret
+.hv_last_row: ; esoteric edge case for odd heights
+    mova [t1+r10+400*0], m1
+    paddw            m1, m0
+    mova [t1+r10+400*2], m4
+    paddd            m4, m2
+    mova [t1+r10+400*4], m5
+    paddd            m5, m3
+    jmp .hv_main2
+.v: ; vertical boxsum + ab
+    lea            r10, [wq-4]
+.v_loop:
+    mova            m0, [t1+r10+400*0]
+    mova            m2, [t1+r10+400*2]
+    mova            m3, [t1+r10+400*4]
+    paddw           m1, m0, [t2+r10+400*0]
+    paddd           m4, m2, [t2+r10+400*2]
+    paddd           m5, m3, [t2+r10+400*4]
+    paddw           m0, m0
+    paddd           m2, m2
+    paddd           m3, m3
+    paddw           m1, m0             ; hv sum
+    paddd           m4, m2             ; hv sumsq
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    paddd           m4, m8
+    pavgw           m3, m6             ; (b + 2) >> 2
+    paddd           m5, m8
+    psrld           m4, 4              ; (a + 8) >> 4
+    punpcklwd       m2, m3, m6
+    psrld           m5, 4
+    punpckhwd       m3, m6
+    pmulld          m4, m9             ; a * 25
+    pmulld          m5, m9
+    pmaddwd         m2, m2             ; b * b
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    pmaxud          m4, m2
+    pmaxud          m5, m3
+    psubd           m4, m2             ; p
+    psubd           m5, m3
+    pmulld          m4, m11            ; p * s
+    pmulld          m5, m11
+    pmaddwd         m0, m12            ; b * 164
+    pmaddwd         m1, m12
+    paddw           m4, m12
+    paddw           m5, m12
+    psrld           m4, 20             ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m13, m4
+    pcmpgtd         m5, m13, m5
+    mulps           m2, m13            ; 256 / (z + 1)
+    mulps           m3, m13
+    psrld           m4, 24             ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m14            ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m14
+    mova    [t4+r10+4], m2
+    psrld           m0, 12             ; b
+    psrld           m1, 12
+    mova         [t3+r10*2+ 8], xm0
+    vextracti128 [t3+r10*2+40], m0, 1
+    mova         [t3+r10*2+24], xm1
+    vextracti128 [t3+r10*2+56], m1, 1
+    add            r10, 32
+    jl .v_loop
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    movu            m0, [t4+r10*1+ 2]
+    movu            m1, [t3+r10*2+ 4]
+    movu            m2, [t3+r10*2+36]
+    paddw           m3, m0, [t4+r10*1+ 0]
+    paddd           m4, m1, [t3+r10*2+ 0]
+    paddd           m5, m2, [t3+r10*2+32]
+    paddw           m3, [t4+r10*1+ 4]
+    paddd           m4, [t3+r10*2+ 8]
+    paddd           m5, [t3+r10*2+40]
+    paddw           m0, m3
+    psllw           m3, 2
+    paddd           m1, m4
+    pslld           m4, 2
+    paddd           m2, m5
+    pslld           m5, 2
+    paddw           m0, m3             ; a 565
+    paddd           m1, m4             ; b 565
+    paddd           m2, m5
+    mova [t4+r10*1+400*2+ 0], m0
+    mova [t3+r10*2+400*4+ 0], m1
+    mova [t3+r10*2+400*4+32], m2
+    add            r10, 32
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    movu            m0, [t4+r10*1+ 2]
+    movu            m1, [t3+r10*2+ 4]
+    movu            m2, [t3+r10*2+36]
+    paddw           m3, m0, [t4+r10*1+ 0]
+    paddd           m4, m1, [t3+r10*2+ 0]
+    paddd           m5, m2, [t3+r10*2+32]
+    paddw           m3, [t4+r10*1+ 4]
+    paddd           m4, [t3+r10*2+ 8]
+    paddd           m5, [t3+r10*2+40]
+    paddw           m0, m3
+    psllw           m3, 2
+    paddd           m1, m4
+    pslld           m4, 2
+    paddd           m2, m5
+    pslld           m5, 2
+    paddw           m0, m3             ; a 565
+    paddd           m1, m4             ; b 565
+    paddd           m2, m5
+    paddw           m3, m0, [t4+r10*1+400*2+ 0]
+    paddd           m4, m1, [t3+r10*2+400*4+ 0]
+    paddd           m5, m2, [t3+r10*2+400*4+32]
+    mova [t4+r10*1+400*2+ 0], m0
+    mova [t3+r10*2+400*4+ 0], m1
+    mova [t3+r10*2+400*4+32], m2
+    mova            m0, [dstq+r10]
+    punpcklwd       m1, m0, m6          ; src
+    punpcklwd       m2, m3, m6          ; a
+    pmaddwd         m2, m1              ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    vinserti128     m1, m4, xm5, 1
+    vperm2i128      m4, m5, 0x31
+    psubd           m1, m2              ; b - a * src + (1 << 8)
+    psubd           m4, m3
+    psrad           m1, 9
+    psrad           m4, 9
+    packssdw        m1, m4
+    pmulhrsw        m1, m7
+    paddw           m0, m1
+    pmaxsw          m0, m6
+    pminsw          m0, m15
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    mova            m0, [dstq+r10]
+    mova            m3, [t4+r10*1+400*2+ 0]
+    mova            m4, [t3+r10*2+400*4+ 0]
+    mova            m5, [t3+r10*2+400*4+32]
+    punpcklwd       m1, m0, m6          ; src
+    punpcklwd       m2, m3, m6          ; a
+    pmaddwd         m2, m1
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    vinserti128     m1, m4, xm5, 1
+    vperm2i128      m4, m5, 0x31
+    psubd           m1, m2              ; b - a * src + (1 << 7)
+    psubd           m4, m3
+    psrad           m1, 8
+    psrad           m4, 8
+    packssdw        m1, m4
+    pmulhrsw        m1, m7
+    paddw           m0, m1
+    pmaxsw          m0, m6
+    pminsw          m0, m15
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_3x3_16bpc, 4, 14, 15, 400*42+8, dst, stride, left, lpf, \
+                                                   w, h, edge, params
+    movifnidn       wd, wm
+    mov        paramsq, r6mp
+    lea            r13, [pb_m10_m9]
+    add             wd, wd
+    movifnidn       hd, hm
+    mov          edged, r7m
+    vpbroadcastw    m7, [paramsq+10] ; w1
+    add           lpfq, wq
+    vpbroadcastd    m8, [base+pd_8]
+    add           dstq, wq
+    vpbroadcastd    m9, [paramsq+ 4] ; s1
+    lea             t3, [rsp+wq*2+400*12+8]
+    mova          xm10, [base+sgr_lshuf3]
+    lea             t4, [rsp+wq+400*32+8]
+    vpbroadcastd   m11, [base+pw_455_24]
+    lea             t1, [rsp+wq+12]
+    vbroadcastss   m12, [base+pf_256]
+    neg             wq
+    vpbroadcastd   m13, [base+pd_34816]
+    pxor            m6, m6
+    vpbroadcastd   m14, [base+pw_1023]
+    psllw           m7, 4
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    add             t1, 400*6
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    add           lpfq, strideq
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    call .hv0
+    test            hd, hd
+    jz .odd_height
+    add           lpfq, strideq
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .hv0_bottom
+    add           lpfq, strideq
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea            r10, [wq-4]
+    lea             t2, [t1+400*6]
+.top_fixup_loop:
+    mova            m0, [t1+r10+400*0]
+    mova            m1, [t1+r10+400*2]
+    mova            m2, [t1+r10+400*4]
+    mova [t2+r10+400*0], m0
+    mova [t2+r10+400*2], m1
+    mova [t2+r10+400*4], m2
+    add            r10, 32
+    jl .top_fixup_loop
+    call .v0
+    jmp .main
+.extend_right:
+    vpbroadcastw    m0, [lpfq-2]
+    movu            m1, [r13+r10+ 2]
+    movu            m2, [r13+r10+18]
+    vpblendvb       m4, m0, m1
+    vpblendvb       m5, m0, m2
+    ret
+.h: ; horizontal boxsum
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    vpbroadcastq   xm5, [leftq]
+    vinserti128     m5, [lpfq+wq], 1
+    mova            m4, [lpfq+wq]
+    add          leftq, 8
+    palignr         m4, m5, 12
+    jmp .h_main
+.h_extend_left:
+    mova           xm4, [lpfq+wq]
+    pshufb         xm4, xm10
+    vinserti128     m4, [lpfq+wq+12], 1
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m4, [lpfq+r10+ 0]
+.h_main:
+    movu            m5, [lpfq+r10+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -34
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    palignr         m0, m5, m4, 2
+    paddw           m1, m4, m0
+    punpcklwd       m2, m4, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m0
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m1, m5             ; sum
+    punpcklwd       m4, m5, m6
+    pmaddwd         m4, m4
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m4             ; sumsq
+    paddd           m3, m5
+    mova [t1+r10+400*0], m1
+    mova [t1+r10+400*2], m2
+    mova [t1+r10+400*4], m3
+    add            r10, 32
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsum + vertical boxsum + ab (even rows)
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    vpbroadcastq   xm5, [leftq]
+    vinserti128     m5, [lpfq+wq], 1
+    mova            m4, [lpfq+wq]
+    add          leftq, 8
+    palignr         m4, m5, 12
+    jmp .hv0_main
+.hv0_extend_left:
+    mova           xm4, [lpfq+wq]
+    pshufb         xm4, xm10
+    vinserti128     m4, [lpfq+wq+12], 1
+    jmp .hv0_main
+.hv0_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+.hv0_loop:
+    movu            m4, [lpfq+r10+ 0]
+.hv0_main:
+    movu            m5, [lpfq+r10+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp           r10d, -34
+    jl .hv0_have_right
+    call .extend_right
+.hv0_have_right:
+    palignr         m0, m5, m4, 2
+    paddw           m1, m4, m0
+    punpcklwd       m2, m4, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m0
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m1, m5             ; sum
+    punpcklwd       m4, m5, m6
+    pmaddwd         m4, m4
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m4             ; sumsq
+    paddd           m3, m5
+    paddw           m0, m1, [t1+r10+400*0]
+    paddd           m4, m2, [t1+r10+400*2]
+    paddd           m5, m3, [t1+r10+400*4]
+    mova [t1+r10+400*0], m1
+    mova [t1+r10+400*2], m2
+    mova [t1+r10+400*4], m3
+    paddw           m1, m0, [t2+r10+400*0]
+    paddd           m2, m4, [t2+r10+400*2]
+    paddd           m3, m5, [t2+r10+400*4]
+    mova [t2+r10+400*0], m0
+    mova [t2+r10+400*2], m4
+    mova [t2+r10+400*4], m5
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m2
+    punpckhwd       m3, m6
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    pmaxud          m4, m2
+    psubd           m4, m2             ; p
+    pmaxud          m5, m3
+    psubd           m5, m3
+    pmulld          m4, m9             ; p * s
+    pmulld          m5, m9
+    pmaddwd         m0, m11            ; b * 455
+    pmaddwd         m1, m11
+    paddw           m4, m11
+    paddw           m5, m11
+    psrld           m4, 20             ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m12, m4
+    pcmpgtd         m5, m12, m5
+    mulps           m2, m12            ; 256 / (z + 1)
+    mulps           m3, m12
+    psrld           m4, 24             ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m13            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m13
+    psrld           m0, 12
+    psrld           m1, 12
+    mova         [t4+r10*1+400*0+ 4], m2
+    mova         [t3+r10*2+400*0+ 8], xm0
+    vextracti128 [t3+r10*2+400*0+40], m0, 1
+    mova         [t3+r10*2+400*0+24], xm1
+    vextracti128 [t3+r10*2+400*0+56], m1, 1
+    add            r10, 32
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    vpbroadcastq   xm5, [leftq]
+    vinserti128     m5, [lpfq+wq], 1
+    mova            m4, [lpfq+wq]
+    add          leftq, 8
+    palignr         m4, m5, 12
+    jmp .hv1_main
+.hv1_extend_left:
+    mova           xm4, [lpfq+wq]
+    pshufb         xm4, xm10
+    vinserti128     m4, [lpfq+wq+12], 1
+    jmp .hv1_main
+.hv1_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+.hv1_loop:
+    movu            m4, [lpfq+r10+ 0]
+.hv1_main:
+    movu            m5, [lpfq+r10+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp           r10d, -34
+    jl .hv1_have_right
+    call .extend_right
+.hv1_have_right:
+    palignr         m1, m5, m4, 2
+    paddw           m0, m4, m1
+    punpcklwd       m2, m4, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m1
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m0, m5             ; h sum
+    punpcklwd       m1, m5, m6
+    pmaddwd         m1, m1
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m1             ; h sumsq
+    paddd           m3, m5
+    paddw           m1, m0, [t2+r10+400*0]
+    paddd           m4, m2, [t2+r10+400*2]
+    paddd           m5, m3, [t2+r10+400*4]
+    mova [t2+r10+400*0], m0
+    mova [t2+r10+400*2], m2
+    mova [t2+r10+400*4], m3
+    paddd           m4, m8
+    paddd           m5, m8
+    psrld           m4, 4              ; (a + 8) >> 4
+    psrld           m5, 4
+    pslld           m2, m4, 3
+    pslld           m3, m5, 3
+    paddd           m4, m2             ; ((a + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m2
+    punpckhwd       m3, m6
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    pmaxud          m4, m2
+    psubd           m4, m2             ; p
+    pmaxud          m5, m3
+    psubd           m5, m3
+    pmulld          m4, m9             ; p * s
+    pmulld          m5, m9
+    pmaddwd         m0, m11            ; b * 455
+    pmaddwd         m1, m11
+    paddw           m4, m11
+    paddw           m5, m11
+    psrld           m4, 20             ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m12, m4
+    pcmpgtd         m5, m12, m5
+    mulps           m2, m12            ; 256 / (z + 1)
+    mulps           m3, m12
+    psrld           m4, 24             ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m13            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m13
+    psrld           m0, 12
+    psrld           m1, 12
+    mova         [t4+r10*1+400*2 +4], m2
+    mova         [t3+r10*2+400*4+ 8], xm0
+    vextracti128 [t3+r10*2+400*4+40], m0, 1
+    mova         [t3+r10*2+400*4+24], xm1
+    vextracti128 [t3+r10*2+400*4+56], m1, 1
+    add            r10, 32
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab (even rows)
+    lea            r10, [wq-4]
+.v0_loop:
+    mova            m0, [t1+r10+400*0]
+    mova            m4, [t1+r10+400*2]
+    mova            m5, [t1+r10+400*4]
+    paddw           m0, m0
+    paddd           m4, m4
+    paddd           m5, m5
+    paddw           m1, m0, [t2+r10+400*0]
+    paddd           m2, m4, [t2+r10+400*2]
+    paddd           m3, m5, [t2+r10+400*4]
+    mova [t2+r10+400*0], m0
+    mova [t2+r10+400*2], m4
+    mova [t2+r10+400*4], m5
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m2
+    punpckhwd       m3, m6
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    pmaxud          m4, m2
+    psubd           m4, m2             ; p
+    pmaxud          m5, m3
+    psubd           m5, m3
+    pmulld          m4, m9             ; p * s
+    pmulld          m5, m9
+    pmaddwd         m0, m11            ; b * 455
+    pmaddwd         m1, m11
+    paddw           m4, m11
+    paddw           m5, m11
+    psrld           m4, 20             ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m12, m4
+    pcmpgtd         m5, m12, m5
+    mulps           m2, m12            ; 256 / (z + 1)
+    mulps           m3, m12
+    psrld           m4, 24             ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m13            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m13
+    psrld           m0, 12
+    psrld           m1, 12
+    mova         [t4+r10*1+400*0+ 4], m2
+    mova         [t3+r10*2+400*0+ 8], xm0
+    vextracti128 [t3+r10*2+400*0+40], m0, 1
+    mova         [t3+r10*2+400*0+24], xm1
+    vextracti128 [t3+r10*2+400*0+56], m1, 1
+    add            r10, 32
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+    lea            r10, [wq-4]
+.v1_loop:
+    mova            m0, [t1+r10+400*0]
+    mova            m4, [t1+r10+400*2]
+    mova            m5, [t1+r10+400*4]
+    paddw           m1, m0, [t2+r10+400*0]
+    paddd           m2, m4, [t2+r10+400*2]
+    paddd           m3, m5, [t2+r10+400*4]
+    mova [t2+r10+400*0], m0
+    mova [t2+r10+400*2], m4
+    mova [t2+r10+400*4], m5
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m2
+    punpckhwd       m3, m6
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    pmaxud          m4, m2
+    psubd           m4, m2             ; p
+    pmaxud          m5, m3
+    psubd           m5, m3
+    pmulld          m4, m9             ; p * s
+    pmulld          m5, m9
+    pmaddwd         m0, m11            ; b * 455
+    pmaddwd         m1, m11
+    paddw           m4, m11
+    paddw           m5, m11
+    psrld           m4, 20             ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m12, m4
+    pcmpgtd         m5, m12, m5
+    mulps           m2, m12            ; 256 / (z + 1)
+    mulps           m3, m12
+    psrld           m4, 24             ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m13            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m13
+    psrld           m0, 12
+    psrld           m1, 12
+    mova         [t4+r10*1+400*2+ 4], m2
+    mova         [t3+r10*2+400*4+ 8], xm0
+    vextracti128 [t3+r10*2+400*4+40], m0, 1
+    mova         [t3+r10*2+400*4+24], xm1
+    vextracti128 [t3+r10*2+400*4+56], m1, 1
+    add            r10, 32
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    mova           xm0, [t4+r10*1+400*0+0]
+    paddw          xm0, [t4+r10*1+400*0+4]
+    paddw          xm2, xm0, [t4+r10*1+400*0+2]
+    mova            m1, [t3+r10*2+400*0+0]
+    paddd           m1, [t3+r10*2+400*0+8]
+    paddd           m3, m1, [t3+r10*2+400*0+4]
+    psllw          xm2, 2                ; a[-1] 444
+    pslld           m3, 2                ; b[-1] 444
+    psubw          xm2, xm0              ; a[-1] 343
+    psubd           m3, m1               ; b[-1] 343
+    mova [t4+r10*1+400* 4], xm2
+    mova [t3+r10*2+400* 8], m3
+    mova           xm0, [t4+r10*1+400*2+0]
+    paddw          xm0, [t4+r10*1+400*2+4]
+    paddw          xm2, xm0, [t4+r10*1+400*2+2]
+    mova            m1, [t3+r10*2+400*4+0]
+    paddd           m1, [t3+r10*2+400*4+8]
+    paddd           m3, m1, [t3+r10*2+400*4+4]
+    psllw          xm2, 2                 ; a[ 0] 444
+    pslld           m3, 2                 ; b[ 0] 444
+    mova [t4+r10*1+400* 6], xm2
+    mova [t3+r10*2+400*12], m3
+    psubw          xm2, xm0               ; a[ 0] 343
+    psubd           m3, m1                ; b[ 0] 343
+    mova [t4+r10*1+400* 8], xm2
+    mova [t3+r10*2+400*16], m3
+    add            r10, 16
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    mova            m3, [t4+r10*1+400*0+0]
+    paddw           m3, [t4+r10*1+400*0+4]
+    paddw           m1, m3, [t4+r10*1+400*0+2]
+    psllw           m1, 2                ; a[ 1] 444
+    psubw           m2, m1, m3           ; a[ 1] 343
+    paddw           m3, m2, [t4+r10*1+400*4]
+    paddw           m3, [t4+r10*1+400*6]
+    mova [t4+r10*1+400*4], m2
+    mova [t4+r10*1+400*6], m1
+    mova            m4, [t3+r10*2+400*0+0]
+    paddd           m4, [t3+r10*2+400*0+8]
+    paddd           m1, m4, [t3+r10*2+400*0+4]
+    pslld           m1, 2                ; b[ 1] 444
+    psubd           m2, m1, m4           ; b[ 1] 343
+    paddd           m4, m2, [t3+r10*2+400* 8+ 0]
+    paddd           m4, [t3+r10*2+400*12+ 0]
+    mova [t3+r10*2+400* 8+ 0], m2
+    mova [t3+r10*2+400*12+ 0], m1
+    mova            m5, [t3+r10*2+400*0+32]
+    paddd           m5, [t3+r10*2+400*0+40]
+    paddd           m1, m5, [t3+r10*2+400*0+36]
+    pslld           m1, 2
+    psubd           m2, m1, m5
+    paddd           m5, m2, [t3+r10*2+400* 8+32]
+    paddd           m5, [t3+r10*2+400*12+32]
+    mova [t3+r10*2+400* 8+32], m2
+    mova [t3+r10*2+400*12+32], m1
+    mova            m0, [dstq+r10]
+    punpcklwd       m1, m0, m6
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m1               ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    vinserti128     m1, m4, xm5, 1
+    vperm2i128      m4, m5, 0x31
+    psubd           m1, m2               ; b - a * src + (1 << 8)
+    psubd           m4, m3
+    psrad           m1, 9
+    psrad           m4, 9
+    packssdw        m1, m4
+    pmulhrsw        m1, m7
+    paddw           m0, m1
+    pmaxsw          m0, m6
+    pminsw          m0, m14
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    mova            m3, [t4+r10*1+400*2+0]
+    paddw           m3, [t4+r10*1+400*2+4]
+    paddw           m1, m3, [t4+r10*1+400*2+2]
+    psllw           m1, 2                ; a[ 1] 444
+    psubw           m2, m1, m3           ; a[ 1] 343
+    paddw           m3, m2, [t4+r10*1+400*6]
+    paddw           m3, [t4+r10*1+400*8]
+    mova [t4+r10*1+400*6], m1
+    mova [t4+r10*1+400*8], m2
+    mova            m4, [t3+r10*2+400*4+0]
+    paddd           m4, [t3+r10*2+400*4+8]
+    paddd           m1, m4, [t3+r10*2+400*4+4]
+    pslld           m1, 2                ; b[ 1] 444
+    psubd           m2, m1, m4           ; b[ 1] 343
+    paddd           m4, m2, [t3+r10*2+400*12+ 0]
+    paddd           m4, [t3+r10*2+400*16+ 0]
+    mova [t3+r10*2+400*12+ 0], m1
+    mova [t3+r10*2+400*16+ 0], m2
+    mova            m5, [t3+r10*2+400*4+32]
+    paddd           m5, [t3+r10*2+400*4+40]
+    paddd           m1, m5, [t3+r10*2+400*4+36]
+    pslld           m1, 2
+    psubd           m2, m1, m5
+    paddd           m5, m2, [t3+r10*2+400*12+32]
+    paddd           m5, [t3+r10*2+400*16+32]
+    mova [t3+r10*2+400*12+32], m1
+    mova [t3+r10*2+400*16+32], m2
+    mova            m0, [dstq+r10]
+    punpcklwd       m1, m0, m6
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m1               ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    vinserti128     m1, m4, xm5, 1
+    vperm2i128      m4, m5, 0x31
+    psubd           m1, m2               ; b - a * src + (1 << 8)
+    psubd           m4, m3
+    psrad           m1, 9
+    psrad           m4, 9
+    packssdw        m1, m4
+    pmulhrsw        m1, m7
+    paddw           m0, m1
+    pmaxsw          m0, m6
+    pminsw          m0, m14
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_mix_16bpc, 4, 14, 16, 400*66+8, dst, stride, left, lpf, \
+                                                   w, h, edge, params
+    movifnidn       wd, wm
+    mov        paramsq, r6mp
+    lea            r13, [pb_m10_m9]
+    add             wd, wd
+    movifnidn       hd, hm
+    mov          edged, r7m
+    add           lpfq, wq
+    vpbroadcastd   m15, [paramsq+8] ; w0 w1
+    add           dstq, wq
+    vpbroadcastd   m13, [paramsq+0] ; s0
+    lea             t3, [rsp+wq*2+400*24+8]
+    vpbroadcastd   m14, [paramsq+4] ; s1
+    lea             t4, [rsp+wq+400*52+8]
+    vpbroadcastd    m9, [base+pd_8]
+    lea             t1, [rsp+wq+12]
+    vpbroadcastd   m10, [base+pd_34816]
+    neg             wq
+    vbroadcastss   m11, [base+pf_256]
+    pxor            m7, m7
+    vpbroadcastd   m12, [base+pw_455_24]
+    psllw          m15, 2
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_avx2).top_fixup
+    add             t1, 400*12
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    add           lpfq, strideq
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    call .hv0
+    test            hd, hd
+    jz .odd_height
+    add           lpfq, strideq
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .hv0_bottom
+    add           lpfq, strideq
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea            r10, [wq-4]
+    lea             t2, [t1+400*12]
+.top_fixup_loop:
+    mova            m0, [t1+r10+400* 0]
+    mova            m1, [t1+r10+400* 2]
+    mova            m2, [t1+r10+400* 4]
+    paddw           m0, m0
+    mova            m3, [t1+r10+400* 6]
+    paddd           m1, m1
+    mova            m4, [t1+r10+400* 8]
+    paddd           m2, m2
+    mova            m5, [t1+r10+400*10]
+    mova [t2+r10+400* 0], m0
+    mova [t2+r10+400* 2], m1
+    mova [t2+r10+400* 4], m2
+    mova [t2+r10+400* 6], m3
+    mova [t2+r10+400* 8], m4
+    mova [t2+r10+400*10], m5
+    add            r10, 32
+    jl .top_fixup_loop
+    call .v0
+    jmp .main
+.h: ; horizontal boxsum
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    vpbroadcastq   xm5, [leftq]
+    vinserti128     m5, [lpfq+wq], 1
+    mova            m4, [lpfq+wq]
+    add          leftq, 8
+    palignr         m4, m5, 10
+    jmp .h_main
+.h_extend_left:
+    mova           xm4, [lpfq+wq]
+    pshufb         xm4, [base+sgr_lshuf5]
+    vinserti128     m4, [lpfq+wq+10], 1
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m4, [lpfq+r10- 2]
+.h_main:
+    movu            m5, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -36
+    jl .h_have_right
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_avx2).extend_right
+.h_have_right:
+    palignr         m3, m5, m4, 2
+    palignr         m0, m5, m4, 4
+    paddw           m1, m3, m0
+    punpcklwd       m2, m3, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m0
+    pmaddwd         m3, m3
+    palignr         m0, m5, m4, 6
+    paddw           m1, m0             ; sum3
+    punpcklwd       m6, m0, m7
+    pmaddwd         m6, m6
+    punpckhwd       m0, m7
+    pmaddwd         m0, m0
+    paddd           m2, m6             ; sumsq3
+    shufpd          m6, m4, m5, 0x05
+    punpcklwd       m5, m6, m4
+    paddw           m8, m4, m6
+    pmaddwd         m5, m5
+    punpckhwd       m6, m4
+    pmaddwd         m6, m6
+    paddd           m3, m0
+    mova [t1+r10+400* 6], m1
+    mova [t1+r10+400* 8], m2
+    mova [t1+r10+400*10], m3
+    paddw           m8, m1             ; sum5
+    paddd           m5, m2             ; sumsq5
+    paddd           m6, m3
+    mova [t1+r10+400* 0], m8
+    mova [t1+r10+400* 2], m5
+    mova [t1+r10+400* 4], m6
+    add            r10, 32
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsum + vertical boxsum + ab3 (even rows)
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    vpbroadcastq   xm5, [leftq]
+    vinserti128     m5, [lpfq+wq], 1
+    mova            m4, [lpfq+wq]
+    add          leftq, 8
+    palignr         m4, m5, 10
+    jmp .hv0_main
+.hv0_extend_left:
+    mova           xm4, [lpfq+wq]
+    pshufb         xm4, [base+sgr_lshuf5]
+    vinserti128     m4, [lpfq+wq+10], 1
+    jmp .hv0_main
+.hv0_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+.hv0_loop:
+    movu            m4, [lpfq+r10- 2]
+.hv0_main:
+    movu            m5, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp           r10d, -36
+    jl .hv0_have_right
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_avx2).extend_right
+.hv0_have_right:
+    palignr         m3, m5, m4, 2
+    palignr         m0, m5, m4, 4
+    paddw           m1, m3, m0
+    punpcklwd       m2, m3, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m0
+    pmaddwd         m3, m3
+    palignr         m0, m5, m4, 6
+    paddw           m1, m0             ; h sum3
+    punpcklwd       m6, m0, m7
+    pmaddwd         m6, m6
+    punpckhwd       m0, m7
+    pmaddwd         m0, m0
+    paddd           m2, m6             ; h sumsq3
+    shufpd          m6, m4, m5, 0x05
+    punpcklwd       m5, m6, m4
+    paddw           m8, m4, m6
+    pmaddwd         m5, m5
+    punpckhwd       m6, m4
+    pmaddwd         m6, m6
+    paddd           m3, m0
+    paddw           m8, m1             ; h sum5
+    paddd           m5, m2             ; h sumsq5
+    paddd           m6, m3
+    mova [t3+r10*2+400*8+ 8], m8 ; we need a clean copy of the last row TODO: t4?
+    mova [t3+r10*2+400*0+ 8], m5 ; in case height is odd
+    mova [t3+r10*2+400*0+40], m6
+    paddw           m8, [t1+r10+400* 0]
+    paddd           m5, [t1+r10+400* 2]
+    paddd           m6, [t1+r10+400* 4]
+    mova [t1+r10+400* 0], m8
+    mova [t1+r10+400* 2], m5
+    mova [t1+r10+400* 4], m6
+    paddw           m0, m1, [t1+r10+400* 6]
+    paddd           m4, m2, [t1+r10+400* 8]
+    paddd           m5, m3, [t1+r10+400*10]
+    mova [t1+r10+400* 6], m1
+    mova [t1+r10+400* 8], m2
+    mova [t1+r10+400*10], m3
+    paddw           m1, m0, [t2+r10+400* 6]
+    paddd           m2, m4, [t2+r10+400* 8]
+    paddd           m3, m5, [t2+r10+400*10]
+    mova [t2+r10+400* 6], m0
+    mova [t2+r10+400* 8], m4
+    mova [t2+r10+400*10], m5
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a3 + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m7             ; (b3 + 2) >> 2
+    punpcklwd       m2, m3, m7
+    pmaddwd         m2, m2
+    punpckhwd       m3, m7
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m7         ; b3
+    punpckhwd       m1, m7
+    pmaxud          m4, m2
+    psubd           m4, m2             ; p3
+    pmaxud          m5, m3
+    psubd           m5, m3
+    pmulld          m4, m14            ; p3 * s1
+    pmulld          m5, m14
+    pmaddwd         m0, m12            ; b3 * 455
+    pmaddwd         m1, m12
+    paddw           m4, m12
+    paddw           m5, m12
+    psrld           m4, 20             ; z3 + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z3 + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m11, m4
+    pcmpgtd         m5, m11, m5
+    mulps           m2, m11            ; 256 / (z3 + 1)
+    mulps           m3, m11
+    psrld           m4, 24             ; z3 < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x3
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova         [t4+r10*1+400*2+ 4], m2
+    mova         [t3+r10*2+400*4+ 8], xm0
+    vextracti128 [t3+r10*2+400*4+40], m0, 1
+    mova         [t3+r10*2+400*4+24], xm1
+    vextracti128 [t3+r10*2+400*4+56], m1, 1
+    add            r10, 32
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    vpbroadcastq   xm5, [leftq]
+    vinserti128     m5, [lpfq+wq], 1
+    mova            m4, [lpfq+wq]
+    add          leftq, 8
+    palignr         m4, m5, 10
+    jmp .hv1_main
+.hv1_extend_left:
+    mova           xm4, [lpfq+wq]
+    pshufb         xm4, [base+sgr_lshuf5]
+    vinserti128     m4, [lpfq+wq+10], 1
+    jmp .hv1_main
+.hv1_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+.hv1_loop:
+    movu            m4, [lpfq+r10- 2]
+.hv1_main:
+    movu            m5, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp           r10d, -36
+    jl .hv1_have_right
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_avx2).extend_right
+.hv1_have_right:
+    palignr         m6, m5, m4, 2
+    palignr         m3, m5, m4, 4
+    paddw           m2, m6, m3
+    punpcklwd       m0, m6, m3
+    pmaddwd         m0, m0
+    punpckhwd       m6, m3
+    pmaddwd         m6, m6
+    palignr         m3, m5, m4, 6
+    paddw           m2, m3             ; h sum3
+    punpcklwd       m1, m3, m7
+    pmaddwd         m1, m1
+    punpckhwd       m3, m7
+    pmaddwd         m3, m3
+    paddd           m0, m1             ; h sumsq3
+    shufpd          m1, m4, m5, 0x05
+    punpckhwd       m5, m4, m1
+    paddw           m8, m4, m1
+    pmaddwd         m5, m5
+    punpcklwd       m4, m1
+    pmaddwd         m4, m4
+    paddd           m6, m3
+    paddw           m1, m2, [t2+r10+400* 6]
+    mova [t2+r10+400* 6], m2
+    paddw           m8, m2             ; h sum5
+    paddd           m2, m0, [t2+r10+400* 8]
+    paddd           m3, m6, [t2+r10+400*10]
+    mova [t2+r10+400* 8], m0
+    mova [t2+r10+400*10], m6
+    paddd           m4, m0             ; h sumsq5
+    paddd           m5, m6
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pslld           m0, m2, 3
+    pslld           m6, m3, 3
+    paddd           m2, m0             ; ((a3 + 8) >> 4) * 9
+    paddd           m3, m6
+    psrlw           m6, m1, 1
+    pavgw           m6, m7             ; (b3 + 2) >> 2
+    punpcklwd       m0, m6, m7
+    pmaddwd         m0, m0
+    punpckhwd       m6, m7
+    pmaddwd         m6, m6
+    pmaxud          m2, m0
+    psubd           m2, m0             ; p3
+    pmaxud          m3, m6
+    psubd           m3, m6
+    punpcklwd       m0, m1, m7         ; b3
+    punpckhwd       m1, m7
+    pmulld          m2, m14            ; p3 * s1
+    pmulld          m3, m14
+    pmaddwd         m0, m12            ; b3 * 455
+    pmaddwd         m1, m12
+    paddw           m2, m12
+    paddw           m3, m12
+    psrld           m2, 20             ; z + 1
+    psrld           m3, 20
+    cvtdq2ps        m2, m2
+    cvtdq2ps        m3, m3
+    rcpps           m6, m2             ; 1 / (z + 1)
+    rcpps           m7, m3
+    pcmpgtd         m2, m11, m2
+    pcmpgtd         m3, m11, m3
+    mulps           m6, m11            ; 256 / (z + 1)
+    mulps           m7, m11
+    psrld           m2, 24             ; z < 255 ? 255 : 0
+    psrld           m3, 24
+    cvtps2dq        m6, m6
+    cvtps2dq        m7, m7
+    pminsw          m6, m2             ; x
+    pminsw          m7, m3
+    pmulld          m0, m6
+    packssdw        m6, m7
+    pmulld          m7, m1
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m7, m10
+    psrld           m0, 12
+    psrld           m7, 12
+    paddw           m1, m8, [t2+r10+400*0]
+    paddd           m2, m4, [t2+r10+400*2]
+    paddd           m3, m5, [t2+r10+400*4]
+    paddw           m1, [t1+r10+400*0]
+    paddd           m2, [t1+r10+400*2]
+    paddd           m3, [t1+r10+400*4]
+    mova [t2+r10+400*0], m8
+    mova [t2+r10+400*2], m4
+    mova [t2+r10+400*4], m5
+    mova         [t4+r10*1+400*4 +4], m6
+    mova         [t3+r10*2+400*8+ 8], xm0
+    vextracti128 [t3+r10*2+400*8+40], m0, 1
+    mova         [t3+r10*2+400*8+24], xm7
+    vextracti128 [t3+r10*2+400*8+56], m7, 1
+    vpbroadcastd    m4, [base+pd_25]
+    vpbroadcastd    m6, [base+pw_164_24]
+    pxor            m7, m7
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a5 + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m4             ; ((a5 + 8) >> 4) * 25
+    pmulld          m3, m4
+    psrlw           m5, m1, 1
+    pavgw           m5, m7             ; (b5 + 2) >> 2
+    punpcklwd       m4, m5, m7
+    pmaddwd         m4, m4
+    punpckhwd       m5, m7
+    pmaddwd         m5, m5
+    punpcklwd       m0, m1, m7         ; b5
+    punpckhwd       m1, m7
+    pmaxud          m2, m4
+    psubd           m2, m4             ; p5
+    pmaxud          m3, m5
+    psubd           m3, m5
+    pmulld          m2, m13            ; p5 * s0
+    pmulld          m3, m13
+    pmaddwd         m0, m6             ; b5 * 164
+    pmaddwd         m1, m6
+    paddw           m2, m6
+    paddw           m3, m6
+    psrld           m2, 20             ; z5 + 1
+    psrld           m3, 20
+    cvtdq2ps        m2, m2
+    cvtdq2ps        m3, m3
+    rcpps           m4, m2             ; 1 / (z5 + 1)
+    rcpps           m5, m3
+    pcmpgtd         m2, m11, m2
+    pcmpgtd         m3, m11, m3
+    mulps           m4, m11            ; 256 / (z5 + 1)
+    mulps           m5, m11
+    psrld           m2, 24             ; z5 < 255 ? 255 : 0
+    psrld           m3, 24
+    cvtps2dq        m4, m4
+    cvtps2dq        m5, m5
+    pminsw          m4, m2             ; x5
+    pminsw          m5, m3
+    pmulld          m0, m4
+    pmulld          m1, m5
+    packssdw        m4, m5
+    paddd           m0, m10            ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova         [t4+r10*1+400*0+ 4], m4
+    mova         [t3+r10*2+400*0+ 8], xm0
+    vextracti128 [t3+r10*2+400*0+40], m0, 1
+    mova         [t3+r10*2+400*0+24], xm1
+    vextracti128 [t3+r10*2+400*0+56], m1, 1
+    add            r10, 32
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab3 (even rows)
+    lea            r10, [wq-4]
+.v0_loop:
+    mova            m0, [t1+r10+400* 6]
+    mova            m4, [t1+r10+400* 8]
+    mova            m5, [t1+r10+400*10]
+    paddw           m0, m0
+    paddd           m4, m4
+    paddd           m5, m5
+    paddw           m1, m0, [t2+r10+400* 6]
+    paddd           m2, m4, [t2+r10+400* 8]
+    paddd           m3, m5, [t2+r10+400*10]
+    mova [t2+r10+400* 6], m0
+    mova [t2+r10+400* 8], m4
+    mova [t2+r10+400*10], m5
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a3 + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m7             ; (b3 + 2) >> 2
+    punpcklwd       m2, m3, m7
+    pmaddwd         m2, m2
+    punpckhwd       m3, m7
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m7         ; b3
+    punpckhwd       m1, m7
+    pmaxud          m4, m2
+    psubd           m4, m2             ; p3
+    pmaxud          m5, m3
+    psubd           m5, m3
+    pmulld          m4, m14            ; p3 * s1
+    pmulld          m5, m14
+    pmaddwd         m0, m12            ; b3 * 455
+    pmaddwd         m1, m12
+    paddw           m4, m12
+    paddw           m5, m12
+    psrld           m4, 20             ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m11, m4
+    pcmpgtd         m5, m11, m5
+    mulps           m2, m11            ; 256 / (z + 1)
+    mulps           m3, m11
+    psrld           m4, 24             ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova            m3, [t1+r10+400*0]
+    mova            m4, [t1+r10+400*2]
+    mova            m5, [t1+r10+400*4]
+    mova [t3+r10*2+400*8+ 8], m3
+    mova [t3+r10*2+400*0+ 8], m4
+    mova [t3+r10*2+400*0+40], m5
+    paddw           m3, m3 ; cc5
+    paddd           m4, m4
+    paddd           m5, m5
+    mova [t1+r10+400*0], m3
+    mova [t1+r10+400*2], m4
+    mova [t1+r10+400*4], m5
+    mova         [t4+r10*1+400*2+ 4], m2
+    mova         [t3+r10*2+400*4+ 8], xm0
+    vextracti128 [t3+r10*2+400*4+40], m0, 1
+    mova         [t3+r10*2+400*4+24], xm1
+    vextracti128 [t3+r10*2+400*4+56], m1, 1
+    add            r10, 32
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+    lea            r10, [wq-4]
+.v1_loop:
+    mova            m4, [t1+r10+400* 6]
+    mova            m5, [t1+r10+400* 8]
+    mova            m6, [t1+r10+400*10]
+    paddw           m1, m4, [t2+r10+400* 6]
+    paddd           m2, m5, [t2+r10+400* 8]
+    paddd           m3, m6, [t2+r10+400*10]
+    mova [t2+r10+400* 6], m4
+    mova [t2+r10+400* 8], m5
+    mova [t2+r10+400*10], m6
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a3 + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m7             ; (b3 + 2) >> 2
+    punpcklwd       m2, m3, m7
+    pmaddwd         m2, m2
+    punpckhwd       m3, m7
+    pmaddwd         m3, m3
+    punpcklwd       m0, m1, m7         ; b3
+    punpckhwd       m1, m7
+    pmaxud          m4, m2
+    psubd           m4, m2             ; p3
+    pmaxud          m5, m3
+    psubd           m5, m3
+    pmulld          m4, m14            ; p3 * s1
+    pmulld          m5, m14
+    pmaddwd         m0, m12            ; b3 * 455
+    pmaddwd         m1, m12
+    paddw           m4, m12
+    paddw           m5, m12
+    psrld           m4, 20             ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4             ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m11, m4
+    pcmpgtd         m5, m11, m5
+    mulps           m2, m11            ; 256 / (z + 1)
+    mulps           m3, m11
+    psrld           m4, 24             ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4             ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    packssdw        m2, m3
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m8, m1, 12
+    mova [t4+r10*1+400*4+4], m2
+    mova            m4, [t3+r10*2+400*8+ 8]
+    mova            m5, [t3+r10*2+400*0+ 8]
+    mova            m6, [t3+r10*2+400*0+40]
+    paddw           m1, m4, [t2+r10+400*0]
+    paddd           m2, m5, [t2+r10+400*2]
+    paddd           m3, m6, [t2+r10+400*4]
+    paddw           m1, [t1+r10+400*0]
+    paddd           m2, [t1+r10+400*2]
+    paddd           m3, [t1+r10+400*4]
+    mova [t2+r10+400*0], m4
+    mova [t2+r10+400*2], m5
+    mova [t2+r10+400*4], m6
+    mova         [t3+r10*2+400*8+ 8], xm0
+    vextracti128 [t3+r10*2+400*8+40], m0, 1
+    mova         [t3+r10*2+400*8+24], xm8
+    vextracti128 [t3+r10*2+400*8+56], m8, 1
+    vpbroadcastd    m4, [base+pd_25]
+    vpbroadcastd    m6, [base+pw_164_24]
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a5 + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m4             ; ((a5 + 8) >> 4) * 25
+    pmulld          m3, m4
+    psrlw           m5, m1, 1
+    pavgw           m5, m7             ; (b5 + 2) >> 2
+    punpcklwd       m4, m5, m7
+    pmaddwd         m4, m4
+    punpckhwd       m5, m7
+    pmaddwd         m5, m5
+    punpcklwd       m0, m1, m7         ; b5
+    punpckhwd       m1, m7
+    pmaxud          m2, m4
+    psubd           m2, m4             ; p5
+    pmaxud          m3, m5
+    psubd           m3, m5
+    pmulld          m2, m13            ; p5 * s0
+    pmulld          m3, m13
+    pmaddwd         m0, m6             ; b5 * 164
+    pmaddwd         m1, m6
+    paddw           m2, m6
+    paddw           m3, m6
+    psrld           m2, 20             ; z5 + 1
+    psrld           m3, 20
+    cvtdq2ps        m2, m2
+    cvtdq2ps        m3, m3
+    rcpps           m4, m2             ; 1 / (z5 + 1)
+    rcpps           m5, m3
+    pcmpgtd         m2, m11, m2
+    pcmpgtd         m3, m11, m3
+    mulps           m4, m11            ; 256 / (z5 + 1)
+    mulps           m5, m11
+    psrld           m2, 24             ; z5 < 255 ? 255 : 0
+    psrld           m3, 24
+    cvtps2dq        m4, m4
+    cvtps2dq        m5, m5
+    pminsw          m4, m2             ; x5
+    pminsw          m5, m3
+    pmulld          m0, m4
+    pmulld          m1, m5
+    packssdw        m4, m5
+    paddd           m0, m10            ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova         [t4+r10*1+400*0+ 4], m4
+    mova         [t3+r10*2+400*0+ 8], xm0
+    vextracti128 [t3+r10*2+400*0+40], m0, 1
+    mova         [t3+r10*2+400*0+24], xm1
+    vextracti128 [t3+r10*2+400*0+56], m1, 1
+    add            r10, 32
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    movu           xm0, [t4+r10*1+400*0+2]
+    paddw          xm2, xm0, [t4+r10*1+400*0+0]
+    paddw          xm2, [t4+r10*1+400*0+4]
+    movu            m1, [t3+r10*2+400*0+4]
+    paddd           m3, m1, [t3+r10*2+400*0+0]
+    paddd           m3, [t3+r10*2+400*0+8]
+    paddw          xm0, xm2
+    paddd           m1, m3
+    psllw          xm2, 2
+    pslld           m3, 2
+    paddw          xm0, xm2              ; a5 565
+    paddd           m1, m3               ; b5 565
+    mova [t4+r10*1+400* 6], xm0
+    mova [t3+r10*2+400*12], m1
+    mova           xm0, [t4+r10*1+400*2+0]
+    paddw          xm0, [t4+r10*1+400*2+4]
+    paddw          xm2, xm0, [t4+r10*1+400*2+2]
+    mova            m1, [t3+r10*2+400*4+0]
+    paddd           m1, [t3+r10*2+400*4+8]
+    paddd           m3, m1, [t3+r10*2+400*4+4]
+    psllw          xm2, 2                ; a3[-1] 444
+    pslld           m3, 2                ; b3[-1] 444
+    psubw          xm2, xm0              ; a3[-1] 343
+    psubd           m3, m1               ; b3[-1] 343
+    mova [t4+r10*1+400* 8], xm2
+    mova [t3+r10*2+400*16], m3
+    mova           xm0, [t4+r10*1+400*4+0]
+    paddw          xm0, [t4+r10*1+400*4+4]
+    paddw          xm2, xm0, [t4+r10*1+400*4+2]
+    mova            m1, [t3+r10*2+400*8+0]
+    paddd           m1, [t3+r10*2+400*8+8]
+    paddd           m3, m1, [t3+r10*2+400*8+4]
+    psllw          xm2, 2                 ; a3[ 0] 444
+    pslld           m3, 2                 ; b3[ 0] 444
+    mova [t4+r10*1+400*10], xm2
+    mova [t3+r10*2+400*20], m3
+    psubw          xm2, xm0               ; a3[ 0] 343
+    psubd           m3, m1                ; b3[ 0] 343
+    mova [t4+r10*1+400*12], xm2
+    mova [t3+r10*2+400*24], m3
+    add            r10, 16
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+    vpbroadcastd    m6, [base+pd_4096]
+.n0_loop:
+    movu           xm2, [t4+r10*1+2]
+    paddw          xm0, xm2, [t4+r10*1+0]
+    paddw          xm0, [t4+r10*1+4]
+    paddw          xm2, xm0
+    psllw          xm0, 2
+    paddw          xm0, xm2              ; a5
+    movu            m1, [t3+r10*2+4]
+    paddd           m4, m1, [t3+r10*2+0]
+    paddd           m4, [t3+r10*2+8]
+    paddd           m1, m4
+    pslld           m4, 2
+    paddd           m4, m1               ; b5
+    paddw          xm2, xm0, [t4+r10*1+400* 6]
+    mova [t4+r10*1+400* 6], xm0
+    paddd           m0, m4, [t3+r10*2+400*12]
+    mova [t3+r10*2+400*12], m4
+    mova           xm3, [t4+r10*1+400*2+0]
+    paddw          xm3, [t4+r10*1+400*2+4]
+    paddw          xm5, xm3, [t4+r10*1+400*2+2]
+    psllw          xm5, 2                ; a3[ 1] 444
+    psubw          xm4, xm5, xm3         ; a3[ 1] 343
+    paddw          xm3, xm4, [t4+r10*1+400* 8]
+    paddw          xm3, [t4+r10*1+400*10]
+    mova [t4+r10*1+400* 8], xm4
+    mova [t4+r10*1+400*10], xm5
+    mova            m1, [t3+r10*2+400*4+0]
+    paddd           m1, [t3+r10*2+400*4+8]
+    paddd           m5, m1, [t3+r10*2+400*4+4]
+    pslld           m5, 2                ; b3[ 1] 444
+    psubd           m4, m5, m1           ; b3[ 1] 343
+    paddd           m1, m4, [t3+r10*2+400*16]
+    paddd           m1, [t3+r10*2+400*20]
+    mova [t3+r10*2+400*16], m4
+    mova [t3+r10*2+400*20], m5
+    pmovzxwd        m4, [dstq+r10]
+    pmovzxwd        m2, xm2              ; a5
+    pmovzxwd        m3, xm3              ; a3
+    pmaddwd         m2, m4               ; a5 * src
+    pmaddwd         m3, m4               ; a3 * src
+    pslld           m4, 13
+    psubd           m0, m2               ; b5 - a5 * src + (1 << 8)
+    psubd           m1, m3               ; b3 - a3 * src + (1 << 8)
+    psrld           m0, 9
+    pslld           m1, 7
+    pblendw         m0, m1, 0xaa
+    pmaddwd         m0, m15
+    paddd           m4, m6
+    paddd           m0, m4
+    psrad           m0, 7
+    vextracti128   xm1, m0, 1
+    packusdw       xm0, xm1              ; clip
+    psrlw          xm0, 6
+    mova    [dstq+r10], xm0
+    add            r10, 16
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+    vpbroadcastd    m6, [base+pd_4096]
+.n1_loop:
+    mova           xm3, [t4+r10*1+400*4+0]
+    paddw          xm3, [t4+r10*1+400*4+4]
+    paddw          xm5, xm3, [t4+r10*1+400*4+2]
+    psllw          xm5, 2                ; a3[ 1] 444
+    psubw          xm4, xm5, xm3         ; a3[ 1] 343
+    paddw          xm3, xm4, [t4+r10*1+400*12]
+    paddw          xm3, [t4+r10*1+400*10]
+    mova [t4+r10*1+400*10], xm5
+    mova [t4+r10*1+400*12], xm4
+    mova            m1, [t3+r10*2+400*8+0]
+    paddd           m1, [t3+r10*2+400*8+8]
+    paddd           m5, m1, [t3+r10*2+400*8+4]
+    pslld           m5, 2                ; b3[ 1] 444
+    psubd           m4, m5, m1           ; b3[ 1] 343
+    paddd           m1, m4, [t3+r10*2+400*24]
+    paddd           m1, [t3+r10*2+400*20]
+    mova [t3+r10*2+400*20], m5
+    mova [t3+r10*2+400*24], m4
+    pmovzxwd        m4, [dstq+r10]
+    pmovzxwd        m2, [t4+r10*1+400* 6]
+    pmovzxwd        m3, xm3
+    mova            m0, [t3+r10*2+400*12]
+    pmaddwd         m2, m4               ; a5 * src
+    pmaddwd         m3, m4               ; a3 * src
+    pslld           m4, 13
+    psubd           m0, m2               ; b5 - a5 * src + (1 << 8)
+    psubd           m1, m3               ; b3 - a3 * src + (1 << 8)
+    psrld           m0, 8
+    pslld           m1, 7
+    pblendw         m0, m1, 0xaa
+    pmaddwd         m0, m15
+    paddd           m4, m6
+    paddd           m0, m4
+    psrad           m0, 7
+    vextracti128   xm1, m0, 1
+    packusdw       xm0, xm1              ; clip
+    psrlw          xm0, 6
+    mova    [dstq+r10], xm0
+    add            r10, 16
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/looprestoration16_avx512.asm b/media/libdav1d/src/src/x86/looprestoration16_avx512.asm
new file mode 100644
index 0000000000..e560c54a40
--- /dev/null
+++ b/media/libdav1d/src/src/x86/looprestoration16_avx512.asm
@@ -0,0 +1,2524 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 16
+
+wiener_shufA:  db  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11
+wiener_shufB:  db  6,  7,  4,  5,  8,  9,  6,  7, 10, 11,  8,  9, 12, 13, 10, 11
+wiener_shufC:  db  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15
+wiener_shufD:  db  2,  3, -1, -1,  4,  5, -1, -1,  6,  7, -1, -1,  8,  9, -1, -1
+wiener_shufE:  db  0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+r_ext_mask:    times 72 db -1
+               times  8 db  0
+wiener_hshift: dw 4, 4, 1, 1
+wiener_vshift: dw 1024, 1024, 4096, 4096
+wiener_round:  dd 1049600, 1048832
+
+pw_164_455:    dw 164, 455
+pw_1023:       times 2 dw 1023
+pw_61448:      times 2 dw 61448
+pd_m262128:    dd -262128
+pd_m34816:     dd -34816
+pd_m25:        dd -25
+pd_m9:         dd -9
+pd_8:          dd 8
+pd_2147483648: dd 2147483648
+
+cextern sgr_x_by_x
+
+SECTION .text
+
+DECLARE_REG_TMP 8, 7, 9, 11, 12, 13, 14 ; ring buffer pointers
+
+INIT_ZMM avx512icl
+cglobal wiener_filter7_16bpc, 4, 15, 17, -384*12-16, dst, stride, left, lpf, \
+                                                     w, h, edge, flt
+%define base t4-wiener_hshift
+    mov           fltq, r6mp
+    movifnidn       wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mov            t3d, r8m ; pixel_max
+    vbroadcasti128  m6, [wiener_shufA]
+    vpbroadcastd   m12, [fltq+ 0] ; x0 x1
+    lea             t4, [wiener_hshift]
+    vbroadcasti128  m7, [wiener_shufB]
+    add             wd, wd
+    vpbroadcastd   m13, [fltq+ 4] ; x2 x3
+    shr            t3d, 11
+    vpbroadcastd   m14, [fltq+16] ; y0 y1
+    add           lpfq, wq
+    vpbroadcastd   m15, [fltq+20] ; y2 y3
+    add           dstq, wq
+    vbroadcasti128  m8, [wiener_shufC]
+    lea             t1, [rsp+wq+16]
+    vbroadcasti128  m9, [wiener_shufD]
+    neg             wq
+    vpbroadcastd    m0, [base+wiener_hshift+t3*4]
+    mov           r10d, 0xfe
+    vpbroadcastd   m10, [base+wiener_round+t3*4]
+    kmovb           k1, r10d
+    vpbroadcastd   m11, [base+wiener_vshift+t3*4]
+    pmullw         m12, m0 ; upshift filter coefs to make the
+    vpbroadcastd   m16, [pd_m262128]
+    pmullw         m13, m0 ; horizontal downshift constant
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t6, t1
+    mov             t5, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t4, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .h
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+.main:
+    lea             t0, [t1+384*2]
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v3
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.v1:
+    call .v
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    mov             t6, t1
+    mov             t5, t1
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v3
+    add             t0, 384*8
+    call .hv
+    dec             hd
+    jnz .main
+.v3:
+    call .v
+.v2:
+    call .v
+    jmp .v1
+.h:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movq           xm3, [leftq]
+    vmovdqu64   m3{k1}, [lpfq+r10-8]
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    mova            m4, [lpfq+r10+0]
+    vpbroadcastw   xm3, xm4
+    vmovdqu64   m3{k1}, [lpfq+r10-8]
+    jmp .h_main2
+.h_top:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m3, [lpfq+r10-8]
+.h_main:
+    mova            m4, [lpfq+r10+0]
+.h_main2:
+    movu            m5, [lpfq+r10+8]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -68
+    jl .h_have_right
+    push            r0
+    lea             r0, [r_ext_mask+66]
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd      m3, m0, [r0+r10+ 0], 0xe4 ; c ? a : b
+    vpternlogd      m4, m0, [r0+r10+ 8], 0xe4
+    vpternlogd      m5, m0, [r0+r10+16], 0xe4
+    pop             r0
+.h_have_right:
+    pshufb          m2, m3, m6
+    pshufb          m1, m4, m7
+    paddw           m2, m1
+    pshufb          m3, m8
+    mova            m0, m16
+    vpdpwssd        m0, m2, m12
+    pshufb          m1, m4, m9
+    paddw           m3, m1
+    pshufb          m1, m4, m6
+    vpdpwssd        m0, m3, m13
+    pshufb          m2, m5, m7
+    paddw           m2, m1
+    mova            m1, m16
+    pshufb          m4, m8
+    vpdpwssd        m1, m2, m12
+    pshufb          m5, m9
+    paddw           m4, m5
+    vpdpwssd        m1, m4, m13
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    psraw           m0, 1
+    mova      [t1+r10], m0
+    add            r10, 64
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movq           xm3, [leftq]
+    vmovdqu64   m3{k1}, [lpfq+r10-8]
+    add          leftq, 8
+    jmp .hv_main
+.hv_extend_left:
+    mova            m4, [lpfq+r10+0]
+    vpbroadcastw   xm3, xm4
+    vmovdqu64   m3{k1}, [lpfq+r10-8]
+    jmp .hv_main2
+.hv_bottom:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m3, [lpfq+r10-8]
+.hv_main:
+    mova            m4, [lpfq+r10+0]
+.hv_main2:
+    movu            m5, [lpfq+r10+8]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -68
+    jl .hv_have_right
+    push            r0
+    lea             r0, [r_ext_mask+66]
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd      m3, m0, [r0+r10+ 0], 0xe4
+    vpternlogd      m4, m0, [r0+r10+ 8], 0xe4
+    vpternlogd      m5, m0, [r0+r10+16], 0xe4
+    pop             r0
+.hv_have_right:
+    pshufb          m2, m3, m6
+    pshufb          m1, m4, m7
+    paddw           m2, m1
+    pshufb          m3, m8
+    mova            m0, m16
+    vpdpwssd        m0, m2, m12
+    pshufb          m1, m4, m9
+    paddw           m3, m1
+    pshufb          m1, m4, m6
+    vpdpwssd        m0, m3, m13
+    pshufb          m2, m5, m7
+    paddw           m2, m1
+    pshufb          m4, m8
+    mova            m1, m16
+    vpdpwssd        m1, m2, m12
+    pshufb          m5, m9
+    paddw           m4, m5
+    vpdpwssd        m1, m4, m13
+    mova            m2, [t4+r10]
+    paddw           m2, [t2+r10]
+    mova            m5, [t3+r10]
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    mova            m4, [t5+r10]
+    paddw           m4, [t1+r10]
+    psraw           m0, 1
+    paddw           m3, m0, [t6+r10]
+    mova      [t0+r10], m0
+    punpcklwd       m1, m2, m5
+    mova            m0, m10
+    vpdpwssd        m0, m1, m15
+    punpckhwd       m2, m5
+    mova            m1, m10
+    vpdpwssd        m1, m2, m15
+    punpcklwd       m2, m3, m4
+    vpdpwssd        m0, m2, m14
+    punpckhwd       m3, m4
+    vpdpwssd        m1, m3, m14
+    psrad           m0, 5
+    psrad           m1, 5
+    packusdw        m0, m1
+    pmulhuw         m0, m11
+    mova    [dstq+r10], m0
+    add            r10, 64
+    jl .hv_loop
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t6
+    add           dstq, strideq
+    ret
+.v:
+    mov            r10, wq
+.v_loop:
+    mova            m2, [t4+r10]
+    paddw           m2, [t2+r10]
+    mova            m3, [t3+r10]
+    punpcklwd       m1, m2, m3
+    mova            m0, m10
+    vpdpwssd        m0, m1, m15
+    punpckhwd       m2, m3
+    mova            m1, m10
+    vpdpwssd        m1, m2, m15
+    mova            m4, [t1+r10]
+    paddw           m3, m4, [t6+r10]
+    paddw           m4, [t5+r10]
+    punpcklwd       m2, m3, m4
+    vpdpwssd        m0, m2, m14
+    punpckhwd       m3, m4
+    vpdpwssd        m1, m3, m14
+    psrad           m0, 5
+    psrad           m1, 5
+    packusdw        m0, m1
+    pmulhuw         m0, m11
+    mova    [dstq+r10], m0
+    add            r10, 64
+    jl .v_loop
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    add           dstq, strideq
+    ret
+
+cglobal wiener_filter5_16bpc, 4, 14, 15, 384*8+16, dst, stride, left, lpf, \
+                                                   w, h, edge, flt
+%define base r13-r_ext_mask-70
+    mov           fltq, r6mp
+    movifnidn       wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mov            t3d, r8m ; pixel_max
+    vbroadcasti128  m5, [wiener_shufE]
+    vpbroadcastw   m11, [fltq+ 2] ; x1
+    vbroadcasti128  m6, [wiener_shufB]
+    lea            r13, [r_ext_mask+70]
+    vbroadcasti128  m7, [wiener_shufD]
+    add             wd, wd
+    vpbroadcastd   m12, [fltq+ 4] ; x2 x3
+    shr            t3d, 11
+    vpbroadcastd    m8, [pd_m262128] ; (1 << 4) - (1 << 18)
+    add           lpfq, wq
+    vpbroadcastw   m13, [fltq+18] ; y1
+    add           dstq, wq
+    vpbroadcastd   m14, [fltq+20] ; y2 y3
+    lea             t1, [rsp+wq+16]
+    vpbroadcastd    m0, [base+wiener_hshift+t3*4]
+    neg             wq
+    vpbroadcastd    m9, [base+wiener_round+t3*4]
+    mov           r10d, 0xfffe
+    vpbroadcastd   m10, [base+wiener_vshift+t3*4]
+    kmovw           k1, r10d
+    pmullw         m11, m0
+    pmullw         m12, m0
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t4, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t3, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+.main:
+    mov             t0, t4
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v2
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v2
+    add             t0, 384*6
+    call .hv
+    dec             hd
+    jnz .main
+.v2:
+    call .v
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    add           dstq, strideq
+.v1:
+    call .v
+    jmp .end
+.h:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd           xm3, [leftq+4]
+    vmovdqu32   m3{k1}, [lpfq+r10-4]
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    vpbroadcastw   xm3, [lpfq+r10]
+    vmovdqu32   m3{k1}, [lpfq+r10-4]
+    jmp .h_main
+.h_top:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m3, [lpfq+r10-4]
+.h_main:
+    movu            m4, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -66
+    jl .h_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd      m3, m0, [r13+r10+0], 0xe4 ; c ? a : b
+    vpternlogd      m4, m0, [r13+r10+8], 0xe4
+.h_have_right:
+    pshufb          m1, m3, m5
+    mova            m0, m8
+    vpdpwssd        m0, m1, m11
+    pshufb          m2, m4, m5
+    mova            m1, m8
+    vpdpwssd        m1, m2, m11
+    pshufb          m2, m3, m6
+    pshufb          m3, m7
+    paddw           m2, m3
+    pshufb          m3, m4, m6
+    vpdpwssd        m0, m2, m12
+    pshufb          m4, m7
+    paddw           m3, m4
+    vpdpwssd        m1, m3, m12
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    psraw           m0, 1
+    mova      [t1+r10], m0
+    add            r10, 64
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movd           xm3, [leftq+4]
+    vmovdqu32   m3{k1}, [lpfq+r10-4]
+    add          leftq, 8
+    jmp .hv_main
+.hv_extend_left:
+    vpbroadcastw   xm3, [lpfq+r10]
+    vmovdqu32   m3{k1}, [lpfq+r10-4]
+    jmp .hv_main
+.hv_bottom:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m3, [lpfq+r10-4]
+.hv_main:
+    movu            m4, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -66
+    jl .hv_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd      m3, m0, [r13+r10+0], 0xe4
+    vpternlogd      m4, m0, [r13+r10+8], 0xe4
+.hv_have_right:
+    pshufb          m1, m3, m5
+    mova            m0, m8
+    vpdpwssd        m0, m1, m11
+    pshufb          m2, m4, m5
+    mova            m1, m8
+    vpdpwssd        m1, m2, m11
+    pshufb          m2, m3, m6
+    pshufb          m3, m7
+    paddw           m2, m3
+    pshufb          m3, m4, m6
+    vpdpwssd        m0, m2, m12
+    pshufb          m4, m7
+    paddw           m4, m3
+    vpdpwssd        m1, m4, m12
+    mova            m2, [t3+r10]
+    paddw           m2, [t1+r10]
+    mova            m3, [t2+r10]
+    punpcklwd       m4, m2, m3
+    punpckhwd       m2, m3
+    mova            m3, m9
+    vpdpwssd        m3, m2, m14
+    mova            m2, m9
+    vpdpwssd        m2, m4, m14
+    mova            m4, [t4+r10]
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    psraw           m0, 1
+    mova      [t0+r10], m0
+    punpcklwd       m1, m0, m4
+    vpdpwssd        m2, m1, m13
+    punpckhwd       m0, m4
+    vpdpwssd        m3, m0, m13
+    psrad           m2, 5
+    psrad           m3, 5
+    packusdw        m2, m3
+    pmulhuw         m2, m10
+    mova    [dstq+r10], m2
+    add            r10, 64
+    jl .hv_loop
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t4
+    add           dstq, strideq
+    ret
+.v:
+    mov            r10, wq
+.v_loop:
+    mova            m0, [t1+r10]
+    paddw           m2, m0, [t3+r10]
+    mova            m1, [t2+r10]
+    mova            m4, [t4+r10]
+    punpckhwd       m3, m2, m1
+    pmaddwd         m3, m14
+    punpcklwd       m2, m1
+    pmaddwd         m2, m14
+    punpckhwd       m1, m0, m4
+    pmaddwd         m1, m13
+    punpcklwd       m0, m4
+    pmaddwd         m0, m13
+    paddd           m3, m9
+    paddd           m2, m9
+    paddd           m1, m3
+    paddd           m0, m2
+    psrad           m1, 5
+    psrad           m0, 5
+    packusdw        m0, m1
+    pmulhuw         m0, m10
+    mova    [dstq+r10], m0
+    add            r10, 64
+    jl .v_loop
+    ret
+
+cglobal sgr_filter_5x5_16bpc, 4, 14, 22, 416*24+8, dst, stride, left, lpf, \
+                                                   w, h, edge, params
+%define base r13-r_ext_mask-72
+    movifnidn       wd, wm
+    mov        paramsq, r6mp
+    lea            r13, [r_ext_mask+72]
+    mov          edged, r7m
+    movifnidn       hd, hm
+    pxor            m6, m6
+    vpbroadcastw    m7, [paramsq+8] ; w0
+    add             wd, wd
+    vpbroadcastd    m8, [base+pd_8]
+    add           lpfq, wq
+    vpbroadcastd    m9, [base+pd_m25]
+    add           dstq, wq
+    vpsubd         m10, m6, [paramsq+0] {1to16} ; -s0
+    lea             t3, [rsp+wq*2+416*12+8]
+    vpbroadcastd   m11, [base+pw_164_455]
+    lea             t4, [rsp+wq+416*20+8]
+    vpbroadcastd   m12, [base+pw_61448]  ; (15 << 12) + (1 << 3)
+    lea             t1, [rsp+wq+12]
+    vpbroadcastd   m13, [base+pd_m34816] ; -((1 << 11) + (1 << 15))
+    neg             wq
+    vpbroadcastd   m14, [base+pw_1023]
+    psllw           m7, 4
+    mova           m18, [sgr_x_by_x+64*0]
+    mov           r10d, 0xfffffff8
+    mova           m19, [sgr_x_by_x+64*1]
+    kmovd           k1, r10d
+    mova           m20, [sgr_x_by_x+64*2]
+    mov            r10, 0x3333333333333333
+    mova           m21, [sgr_x_by_x+64*3]
+    kmovq           k2, r10
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    call .top_fixup
+    add             t1, 416*6
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    mov             t0, t2
+    dec             hd
+    jz .height1
+    or           edged, 16
+    call .h
+.main:
+    add           lpfq, strideq
+    call .hv
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    test            hd, hd
+    jz .odd_height
+    call .h
+    add           lpfq, strideq
+    call .hv
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .h_top
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .hv
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .hv
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea             t2, [t1+416*6]
+    call .top_fixup
+    dec             hd
+    jz .no_top_height1
+    or           edged, 16
+    mov             t0, t1
+    mov             t1, t2
+    jmp .main
+.no_top_height1:
+    call .v
+    call .prep_n
+    jmp .odd_height_end
+.h: ; horizontal boxsum
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movq          xm16, [leftq+2]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    vpbroadcastw  xm16, [lpfq+wq]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu           m16, [lpfq+r10- 2]
+.h_main:
+    movu           m17, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -68
+    jl .h_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd     m16, m0, [r13+r10+ 0], 0xe4 ; c ? a : b
+    vpternlogd     m17, m0, [r13+r10+16], 0xe4
+.h_have_right:
+    palignr         m2, m17, m16, 2
+    paddw           m0, m16, m2
+    palignr         m3, m17, m16, 6
+    paddw           m0, m3
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m1
+    punpckhwd       m2, m3
+    pmaddwd         m2, m2
+    shufpd         m17, m16, m17, 0x55
+    paddw           m0, m17
+    punpcklwd       m3, m16, m17
+    vpdpwssd        m1, m3, m3
+    punpckhwd       m3, m16, m17
+    vpdpwssd        m2, m3, m3
+    shufps         m16, m17, q2121
+    paddw           m0, m16            ; sum
+    test         edgeb, 16             ; y > 0
+    jz .h_loop_end
+    paddw           m0, [t1+r10+416*0]
+    paddd           m1, [t1+r10+416*2]
+    paddd           m2, [t1+r10+416*4]
+.h_loop_end:
+    punpcklwd      m17, m16, m6
+    vpdpwssd        m1, m17, m17       ; sumsq
+    punpckhwd      m16, m6
+    vpdpwssd        m2, m16, m16
+    mova [t1+r10+416*0], m0
+    mova [t1+r10+416*2], m1
+    mova [t1+r10+416*4], m2
+    add            r10, 64
+    jl .h_loop
+    ret
+.top_fixup:
+    lea            r10, [wq-4]
+.top_fixup_loop: ; the sums of the first row needs to be doubled
+    mova            m0, [t1+r10+416*0]
+    mova            m1, [t1+r10+416*2]
+    mova            m2, [t1+r10+416*4]
+    paddw           m0, m0
+    paddd           m1, m1
+    paddd           m2, m2
+    mova [t2+r10+416*0], m0
+    mova [t2+r10+416*2], m1
+    mova [t2+r10+416*4], m2
+    add            r10, 64
+    jl .top_fixup_loop
+    ret
+ALIGN function_align
+.hv: ; horizontal boxsum + vertical boxsum + ab
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movq          xm16, [leftq+2]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    add          leftq, 8
+    jmp .hv_main
+.hv_extend_left:
+    vpbroadcastw  xm16, [lpfq+wq]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    jmp .hv_main
+.hv_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu           m16, [lpfq+r10- 2]
+.hv_main:
+    movu           m17, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -68
+    jl .hv_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd     m16, m0, [r13+r10+ 0], 0xe4
+    vpternlogd     m17, m0, [r13+r10+16], 0xe4
+.hv_have_right:
+    palignr         m3, m17, m16, 2
+    paddw           m0, m16, m3
+    palignr         m1, m17, m16, 6
+    paddw           m0, m1
+    punpcklwd       m2, m3, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m1
+    pmaddwd         m3, m3
+    shufpd         m17, m16, m17, 0x55
+    paddw           m0, m17
+    punpcklwd       m1, m16, m17
+    vpdpwssd        m2, m1, m1
+    punpckhwd       m1, m16, m17
+    vpdpwssd        m3, m1, m1
+    shufps         m16, m17, q2121
+    paddw           m0, m16           ; h sum
+    punpcklwd      m17, m16, m6
+    vpdpwssd        m2, m17, m17      ; h sumsq
+    punpckhwd      m16, m6
+    vpdpwssd        m3, m16, m16
+    paddw           m1, m0, [t1+r10+416*0]
+    paddd          m16, m2, [t1+r10+416*2]
+    paddd          m17, m3, [t1+r10+416*4]
+    test            hd, hd
+    jz .hv_last_row
+.hv_main2:
+    paddw           m1, [t2+r10+416*0] ; hv sum
+    paddd          m16, [t2+r10+416*2] ; hv sumsq
+    paddd          m17, [t2+r10+416*4]
+    mova [t0+r10+416*0], m0
+    mova [t0+r10+416*2], m2
+    mova [t0+r10+416*4], m3
+    psrlw           m3, m1, 1
+    paddd          m16, m8
+    pavgw           m3, m6             ; (b + 2) >> 2
+    paddd          m17, m8
+    psrld          m16, 4              ; (a + 8) >> 4
+    psrld          m17, 4
+    pmulld         m16, m9             ; -a * 25
+    pmulld         m17, m9
+    punpcklwd       m2, m3, m6
+    vpdpwssd       m16, m2, m2         ; -p
+    punpckhwd       m3, m6
+    vpdpwssd       m17, m3, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    pmulld         m16, m10            ; p * s
+    pmulld         m17, m10
+    pmaddwd         m0, m11            ; b * 164
+    pmaddwd         m1, m11
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m20
+    pmaxsw         m17, m6
+    paddusw        m17, m12
+    psraw          m17, 4              ; min(z, 255) - 256
+    vpermt2b       m16, m17, m21       ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16            ; x
+    pandn          m16, m13, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    packssdw       m16, m17
+    psubd           m0, m13            ; x * b * 164 + (1 << 11) + (1 << 15)
+    psubd           m1, m13
+    mova    [t4+r10+4], m16
+    psrld          m16, m0, 12         ; b
+    psrld          m17, m1, 12
+    mova          [t3+r10*2+  8], xm16
+    mova          [t3+r10*2+ 24], xm17
+    vextracti128  [t3+r10*2+ 40], ym16, 1
+    vextracti128  [t3+r10*2+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+104], m16, 3
+    vextracti32x4 [t3+r10*2+120], m17, 3
+    add            r10, 64
+    jl .hv_loop
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t2
+    ret
+.hv_last_row: ; esoteric edge case for odd heights
+    mova [t1+r10+416*0], m1
+    paddw            m1, m0
+    mova [t1+r10+416*2], m16
+    paddd           m16, m2
+    mova [t1+r10+416*4], m17
+    paddd           m17, m3
+    jmp .hv_main2
+.v: ; vertical boxsum + ab
+    lea            r10, [wq-4]
+.v_loop:
+    mova            m2, [t1+r10+416*2]
+    mova            m3, [t1+r10+416*4]
+    mova            m0, [t1+r10+416*0]
+    paddd          m16, m2, [t2+r10+416*2]
+    paddd          m17, m3, [t2+r10+416*4]
+    paddw           m1, m0, [t2+r10+416*0]
+    paddd           m2, m2
+    paddd           m3, m3
+    paddd          m16, m2             ; hv sumsq
+    paddd          m17, m3
+    paddd          m16, m8
+    paddd          m17, m8
+    psrld          m16, 4              ; (a + 8) >> 4
+    psrld          m17, 4
+    pmulld         m16, m9             ; -a * 25
+    pmulld         m17, m9
+    paddw           m0, m0
+    paddw           m1, m0             ; hv sum
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    punpcklwd       m2, m3, m6
+    vpdpwssd       m16, m2, m2         ; -p
+    punpckhwd       m3, m6
+    vpdpwssd       m17, m3, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    pmulld         m16, m10            ; p * s
+    pmulld         m17, m10
+    pmaddwd         m0, m11            ; b * 164
+    pmaddwd         m1, m11
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m20
+    pmaxsw         m17, m6
+    paddusw        m17, m12
+    psraw          m17, 4              ; min(z, 255) - 256
+    vpermt2b       m16, m17, m21       ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16            ; x
+    pandn          m16, m13, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    packssdw       m16, m17
+    psubd           m0, m13            ; x * b * 164 + (1 << 11) + (1 << 15)
+    psubd           m1, m13
+    mova    [t4+r10+4], m16
+    psrld          m16, m0, 12         ; b
+    psrld          m17, m1, 12
+    mova          [t3+r10*2+  8], xm16
+    mova          [t3+r10*2+ 24], xm17
+    vextracti128  [t3+r10*2+ 40], ym16, 1
+    vextracti128  [t3+r10*2+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+104], m16, 3
+    vextracti32x4 [t3+r10*2+120], m17, 3
+    add            r10, 64
+    jl .v_loop
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    movu            m0, [t4+r10*1+ 2]
+    movu            m1, [t3+r10*2+ 4]
+    movu            m2, [t3+r10*2+68]
+    paddw           m3, m0, [t4+r10*1+ 0]
+    paddd          m16, m1, [t3+r10*2+ 0]
+    paddd          m17, m2, [t3+r10*2+64]
+    paddw           m3, [t4+r10*1+ 4]
+    paddd          m16, [t3+r10*2+ 8]
+    paddd          m17, [t3+r10*2+72]
+    paddw           m0, m3
+    psllw           m3, 2
+    paddd           m1, m16
+    pslld          m16, 2
+    paddd           m2, m17
+    pslld          m17, 2
+    paddw           m0, m3             ; a 565
+    paddd           m1, m16            ; b 565
+    paddd           m2, m17
+    mova [t4+r10*1+416*2+ 0], m0
+    mova [t3+r10*2+416*4+ 0], m1
+    mova [t3+r10*2+416*4+64], m2
+    add            r10, 64
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    movu            m0, [t4+r10*1+ 2]
+    movu            m1, [t3+r10*2+ 4]
+    movu            m2, [t3+r10*2+68]
+    paddw           m3, m0, [t4+r10*1+ 0]
+    paddd          m16, m1, [t3+r10*2+ 0]
+    paddd          m17, m2, [t3+r10*2+64]
+    paddw           m3, [t4+r10*1+ 4]
+    paddd          m16, [t3+r10*2+ 8]
+    paddd          m17, [t3+r10*2+72]
+    paddw           m0, m3
+    psllw           m3, 2
+    paddd           m1, m16
+    pslld          m16, 2
+    paddd           m2, m17
+    pslld          m17, 2
+    paddw           m0, m3             ; a 565
+    paddd           m1, m16            ; b 565
+    paddd           m2, m17
+    paddw           m3, m0, [t4+r10*1+416*2+ 0]
+    paddd          m16, m1, [t3+r10*2+416*4+ 0]
+    paddd          m17, m2, [t3+r10*2+416*4+64]
+    mova [t4+r10*1+416*2+ 0], m0
+    mova [t3+r10*2+416*4+ 0], m1
+    mova [t3+r10*2+416*4+64], m2
+    mova            m0, [dstq+r10]
+    punpcklwd       m1, m0, m6          ; src
+    punpcklwd       m2, m3, m6          ; a
+    pmaddwd         m2, m1              ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    vshufi32x4      m1, m16, m17, q2020
+    vshufi32x4     m16, m17, q3131
+    psubd           m1, m2              ; b - a * src + (1 << 8)
+    psubd          m16, m3
+    psrad           m1, 9
+    psrad          m16, 9
+    packssdw        m1, m16
+    pmulhrsw        m1, m7
+    paddw           m0, m1
+    pmaxsw          m0, m6
+    pminsw          m0, m14
+    mova    [dstq+r10], m0
+    add            r10, 64
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    mova            m0, [dstq+r10]
+    mova            m3, [t4+r10*1+416*2+ 0]
+    mova           m16, [t3+r10*2+416*4+ 0]
+    mova           m17, [t3+r10*2+416*4+64]
+    punpcklwd       m1, m0, m6          ; src
+    punpcklwd       m2, m3, m6          ; a
+    pmaddwd         m2, m1
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    vshufi32x4      m1, m16, m17, q2020
+    vshufi32x4     m16, m17, q3131
+    psubd           m1, m2              ; b - a * src + (1 << 7)
+    psubd          m16, m3
+    psrad           m1, 8
+    psrad          m16, 8
+    packssdw        m1, m16
+    pmulhrsw        m1, m7
+    paddw           m0, m1
+    pmaxsw          m0, m6
+    pminsw          m0, m14
+    mova    [dstq+r10], m0
+    add            r10, 64
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_3x3_16bpc, 4, 14, 22, 416*42+8, dst, stride, left, lpf, \
+                                                   w, h, edge, params
+    movifnidn       wd, wm
+    mov        paramsq, r6mp
+    lea            r13, [r_ext_mask+72]
+    mov          edged, r7m
+    movifnidn       hd, hm
+    pxor            m6, m6
+    vpbroadcastw    m7, [paramsq+10] ; w1
+    add             wd, wd
+    vpbroadcastd    m8, [base+pd_8]
+    add           lpfq, wq
+    vpbroadcastd    m9, [base+pd_m9]
+    add           dstq, wq
+    vpsubd         m10, m6, [paramsq+4] {1to16} ; -s1
+    lea             t3, [rsp+wq*2+416*12+8]
+    vpbroadcastd   m11, [base+pw_164_455]
+    lea             t4, [rsp+wq+416*32+8]
+    vpbroadcastd   m12, [base+pw_61448]
+    lea             t1, [rsp+wq+12]
+    vpbroadcastd   m13, [base+pd_m34816]
+    neg             wq
+    vpbroadcastd   m14, [base+pw_1023]
+    psllw           m7, 4
+    mova           m18, [sgr_x_by_x+64*0]
+    mov           r10d, 0xfffffffc
+    mova           m19, [sgr_x_by_x+64*1]
+    kmovd           k1, r10d
+    mova           m20, [sgr_x_by_x+64*2]
+    mov            r10, 0x3333333333333333
+    mova           m21, [sgr_x_by_x+64*3]
+    kmovq           k2, r10
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    add             t1, 416*6
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    add           lpfq, strideq
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    call .hv0
+    test            hd, hd
+    jz .odd_height
+    add           lpfq, strideq
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .hv0_bottom
+    add           lpfq, strideq
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea            r10, [wq-4]
+    lea             t2, [t1+416*6]
+.top_fixup_loop:
+    mova            m0, [t1+r10+416*0]
+    mova            m1, [t1+r10+416*2]
+    mova            m2, [t1+r10+416*4]
+    mova [t2+r10+416*0], m0
+    mova [t2+r10+416*2], m1
+    mova [t2+r10+416*4], m2
+    add            r10, 64
+    jl .top_fixup_loop
+    call .v0
+    jmp .main
+.h: ; horizontal boxsum
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd          xm16, [leftq+4]
+    vmovdqu16  m16{k1}, [lpfq+wq-4]
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    vpbroadcastw  xm16, [lpfq+wq]
+    vmovdqu16  m16{k1}, [lpfq+wq-4]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu           m16, [lpfq+r10+ 0]
+.h_main:
+    movu           m17, [lpfq+r10+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -66
+    jl .h_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd     m16, m0, [r13+r10+ 0], 0xe4
+    vpternlogd     m17, m0, [r13+r10+16], 0xe4
+.h_have_right:
+    palignr         m0, m17, m16, 2
+    paddw           m1, m16, m0
+    punpcklwd       m2, m16, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m16, m0
+    pmaddwd         m3, m3
+    palignr        m17, m16, 4
+    paddw           m1, m17            ; sum
+    punpcklwd      m16, m17, m6
+    vpdpwssd        m2, m16, m16       ; sumsq
+    punpckhwd      m17, m6
+    vpdpwssd        m3, m17, m17
+    mova [t1+r10+416*0], m1
+    mova [t1+r10+416*2], m2
+    mova [t1+r10+416*4], m3
+    add            r10, 64
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsum + vertical boxsum + ab (even rows)
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movd          xm16, [leftq+4]
+    vmovdqu16  m16{k1}, [lpfq+wq-4]
+    add          leftq, 8
+    jmp .hv0_main
+.hv0_extend_left:
+    vpbroadcastw  xm16, [lpfq+wq]
+    vmovdqu16  m16{k1}, [lpfq+wq-4]
+    jmp .hv0_main
+.hv0_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+.hv0_loop:
+    movu           m16, [lpfq+r10+ 0]
+.hv0_main:
+    movu           m17, [lpfq+r10+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp           r10d, -66
+    jl .hv0_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd     m16, m0, [r13+r10+ 0], 0xe4
+    vpternlogd     m17, m0, [r13+r10+16], 0xe4
+.hv0_have_right:
+    palignr         m0, m17, m16, 2
+    paddw           m1, m16, m0
+    punpcklwd       m2, m16, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m16, m0
+    pmaddwd         m3, m3
+    palignr        m17, m16, 4
+    paddw           m1, m17            ; sum
+    punpcklwd      m16, m17, m6
+    vpdpwssd        m2, m16, m16       ; sumsq
+    punpckhwd      m17, m6
+    vpdpwssd        m3, m17, m17
+    paddw           m0, m1, [t1+r10+416*0]
+    paddd          m16, m2, [t1+r10+416*2]
+    paddd          m17, m3, [t1+r10+416*4]
+    mova [t1+r10+416*0], m1
+    mova [t1+r10+416*2], m2
+    mova [t1+r10+416*4], m3
+    paddw           m1, m0, [t2+r10+416*0]
+    paddd           m2, m16, [t2+r10+416*2]
+    paddd           m3, m17, [t2+r10+416*4]
+    mova [t2+r10+416*0], m0
+    mova [t2+r10+416*2], m16
+    mova [t2+r10+416*4], m17
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m9             ; -((a + 8) >> 4) * 9
+    pmulld          m3, m9
+    psrlw          m17, m1, 1
+    pavgw          m17, m6             ; (b + 2) >> 2
+    punpcklwd      m16, m17, m6
+    vpdpwssd        m2, m16, m16       ; -p
+    punpckhwd      m17, m6
+    vpdpwssd        m3, m17, m17
+    punpcklwd      m16, m6, m1         ; b
+    punpckhwd      m17, m6, m1
+    pminsd          m2, m6
+    pminsd          m3, m6
+    pmulld          m2, m10            ; p * s
+    pmulld          m3, m10
+    pmaddwd        m16, m11            ; b * 455
+    pmaddwd        m17, m11
+    vpalignr    m3{k2}, m2, m2, 2
+    mova            m2, m20
+    paddusw         m3, m12
+    psraw           m3, 4              ; min(z, 255) - 256
+    vpermt2b        m2, m3, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m3
+    vpermi2b        m3, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m3{k3}, m2             ; x
+    pandn           m2, m13, m3
+    psrld           m3, 16
+    pmulld         m16, m2
+    pmulld         m17, m3
+    packssdw        m2, m3
+    psubd          m16, m13            ; x * b * 455 + (1 << 11) + (1 << 15)
+    psubd          m17, m13
+    mova [t4+r10*1+416*0+4], m2
+    psrld          m16, 12
+    psrld          m17, 12
+    mova          [t3+r10*2+416*0+  8], xm16
+    mova          [t3+r10*2+416*0+ 24], xm17
+    vextracti128  [t3+r10*2+416*0+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*0+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*0+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*0+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*0+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*0+120], m17, 3
+    add            r10, 64
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movd          xm16, [leftq+4]
+    vmovdqu16  m16{k1}, [lpfq+wq-4]
+    add          leftq, 8
+    jmp .hv1_main
+.hv1_extend_left:
+    vpbroadcastw  xm16, [lpfq+wq]
+    vmovdqu16  m16{k1}, [lpfq+wq-4]
+    jmp .hv1_main
+.hv1_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+.hv1_loop:
+    movu           m16, [lpfq+r10+ 0]
+.hv1_main:
+    movu           m17, [lpfq+r10+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp           r10d, -66
+    jl .hv1_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd     m16, m0, [r13+r10+ 0], 0xe4
+    vpternlogd     m17, m0, [r13+r10+16], 0xe4
+.hv1_have_right:
+    palignr         m1, m17, m16, 2
+    paddw           m0, m16, m1
+    punpcklwd       m2, m16, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m16, m1
+    pmaddwd         m3, m3
+    palignr        m17, m16, 4
+    paddw           m0, m17            ; h sum
+    punpcklwd       m1, m17, m6
+    vpdpwssd        m2, m1, m1         ; h sumsq
+    punpckhwd      m17, m6
+    vpdpwssd        m3, m17, m17
+    paddw           m1, m0, [t2+r10+416*0]
+    paddd          m16, m2, [t2+r10+416*2]
+    paddd          m17, m3, [t2+r10+416*4]
+    mova [t2+r10+416*0], m0
+    mova [t2+r10+416*2], m2
+    mova [t2+r10+416*4], m3
+    paddd          m16, m8
+    paddd          m17, m8
+    psrld          m16, 4              ; (a + 8) >> 4
+    psrld          m17, 4
+    pmulld         m16, m9             ; -((a + 8) >> 4) * 9
+    pmulld         m17, m9
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    punpcklwd       m2, m3, m6
+    vpdpwssd       m16, m2, m2         ; -p
+    punpckhwd       m3, m6
+    vpdpwssd       m17, m3, m3
+    punpcklwd       m0, m6, m1         ; b
+    punpckhwd       m1, m6, m1
+    pminsd         m16, m6
+    pminsd         m17, m6
+    pmulld         m16, m10            ; p * s
+    pmulld         m17, m10
+    pmaddwd         m0, m11            ; b * 455
+    pmaddwd         m1, m11
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m20
+    paddusw        m17, m12
+    psraw          m17, 4              ; min(z, 255) - 256
+    vpermt2b       m16, m17, m21       ; sgr_x_by_x[128..255]
+    vpmovb2m       k3, m17
+    vpermi2b       m17, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16            ; x
+    pandn          m16, m13, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    packssdw       m16, m17
+    psubd           m0, m13            ; x * b * 455 + (1 << 11) + (1 << 15)
+    psubd           m1, m13
+    mova [t4+r10*1+416*2+4], m16
+    psrld          m16, m0, 12
+    psrld          m17, m1, 12
+    mova          [t3+r10*2+416*4+  8], xm16
+    mova          [t3+r10*2+416*4+ 24], xm17
+    vextracti128  [t3+r10*2+416*4+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*4+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*4+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*4+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*4+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*4+120], m17, 3
+    add            r10, 64
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab (even rows)
+    lea            r10, [wq-4]
+.v0_loop:
+    mova            m0, [t1+r10+416*0]
+    mova           m16, [t1+r10+416*2]
+    mova           m17, [t1+r10+416*4]
+    paddw           m0, m0
+    paddd          m16, m16
+    paddd          m17, m17
+    paddw           m1, m0, [t2+r10+416*0]
+    paddd           m2, m16, [t2+r10+416*2]
+    paddd           m3, m17, [t2+r10+416*4]
+    mova [t2+r10+416*0], m0
+    mova [t2+r10+416*2], m16
+    mova [t2+r10+416*4], m17
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m9             ; -((a + 8) >> 4) * 9
+    pmulld          m3, m9
+    psrlw          m17, m1, 1
+    pavgw          m17, m6             ; (b + 2) >> 2
+    punpcklwd      m16, m17, m6
+    vpdpwssd        m2, m16, m16       ; -p
+    punpckhwd      m17, m6
+    vpdpwssd        m3, m17, m17
+    punpcklwd      m16, m6, m1         ; b
+    punpckhwd      m17, m6, m1
+    pminsd          m2, m6
+    pminsd          m3, m6
+    pmulld          m2, m10            ; p * s
+    pmulld          m3, m10
+    pmaddwd        m16, m11            ; b * 455
+    pmaddwd        m17, m11
+    vpalignr    m3{k2}, m2, m2, 2
+    mova            m2, m20
+    paddusw         m3, m12
+    psraw           m3, 4              ; min(z, 255) - 256
+    vpermt2b        m2, m3, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m3
+    vpermi2b        m3, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m3{k3}, m2             ; x
+    pandn           m2, m13, m3
+    psrld           m3, 16
+    pmulld         m16, m2
+    pmulld         m17, m3
+    packssdw        m2, m3
+    psubd          m16, m13            ; x * b * 455 + (1 << 11) + (1 << 15)
+    psubd          m17, m13
+    mova [t4+r10*1+416*0+4], m2
+    psrld          m16, 12
+    psrld          m17, 12
+    mova          [t3+r10*2+416*0+  8], xm16
+    mova          [t3+r10*2+416*0+ 24], xm17
+    vextracti128  [t3+r10*2+416*0+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*0+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*0+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*0+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*0+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*0+120], m17, 3
+    add            r10, 64
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+    lea            r10, [wq-4]
+.v1_loop:
+    mova            m0, [t1+r10+416*0]
+    mova           m16, [t1+r10+416*2]
+    mova           m17, [t1+r10+416*4]
+    paddw           m1, m0, [t2+r10+416*0]
+    paddd           m2, m16, [t2+r10+416*2]
+    paddd           m3, m17, [t2+r10+416*4]
+    mova [t2+r10+416*0], m0
+    mova [t2+r10+416*2], m16
+    mova [t2+r10+416*4], m17
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m9             ; -((a + 8) >> 4) * 9
+    pmulld          m3, m9
+    psrlw          m17, m1, 1
+    pavgw          m17, m6             ; (b + 2) >> 2
+    punpcklwd      m16, m17, m6
+    vpdpwssd        m2, m16, m16       ; -p
+    punpckhwd      m17, m6
+    vpdpwssd        m3, m17, m17
+    punpcklwd      m16, m6, m1         ; b
+    punpckhwd      m17, m6, m1
+    pminsd          m2, m6
+    pminsd          m3, m6
+    pmulld          m2, m10            ; p * s
+    pmulld          m3, m10
+    pmaddwd        m16, m11            ; b * 455
+    pmaddwd        m17, m11
+    vpalignr    m3{k2}, m2, m2, 2
+    mova            m2, m20
+    paddusw         m3, m12
+    psraw           m3, 4              ; min(z, 255) - 256
+    vpermt2b        m2, m3, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m3
+    vpermi2b        m3, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m3{k3}, m2             ; x
+    pandn           m2, m13, m3
+    psrld           m3, 16
+    pmulld         m16, m2
+    pmulld         m17, m3
+    packssdw        m2, m3
+    psubd          m16, m13            ; x * b * 455 + (1 << 11) + (1 << 15)
+    psubd          m17, m13
+    mova [t4+r10*1+416*2+4], m2
+    psrld          m16, 12
+    psrld          m17, 12
+    mova          [t3+r10*2+416*4+  8], xm16
+    mova          [t3+r10*2+416*4+ 24], xm17
+    vextracti128  [t3+r10*2+416*4+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*4+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*4+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*4+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*4+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*4+120], m17, 3
+    add            r10, 64
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    mova          ym16, [t4+r10*1+416*0+0]
+    paddw         ym16, [t4+r10*1+416*0+4]
+    paddw         ym17, ym16, [t4+r10*1+416*0+2]
+    mova            m0, [t3+r10*2+416*0+0]
+    paddd           m0, [t3+r10*2+416*0+8]
+    paddd           m1, m0, [t3+r10*2+416*0+4]
+    psllw         ym17, 2                ; a[-1] 444
+    pslld           m1, 2                ; b[-1] 444
+    psubw         ym17, ym16             ; a[-1] 343
+    psubd           m1, m0               ; b[-1] 343
+    vmovdqa32 [t4+r10*1+416* 4], ym17
+    vmovdqa32 [t3+r10*2+416* 8], m1
+    mova          ym16, [t4+r10*1+416*2+0]
+    paddw         ym16, [t4+r10*1+416*2+4]
+    paddw         ym17, ym16, [t4+r10*1+416*2+2]
+    mova            m0, [t3+r10*2+416*4+0]
+    paddd           m0, [t3+r10*2+416*4+8]
+    paddd           m1, m0, [t3+r10*2+416*4+4]
+    psllw         ym17, 2                 ; a[ 0] 444
+    pslld           m1, 2                 ; b[ 0] 444
+    vmovdqa32 [t4+r10*1+416* 6], ym17
+    vmovdqa32 [t3+r10*2+416*12], m1
+    psubw         ym17, ym16              ; a[ 0] 343
+    psubd           m1, m0                ; b[ 0] 343
+    vmovdqa32 [t4+r10*1+416* 8], ym17
+    vmovdqa32 [t3+r10*2+416*16], m1
+    add            r10, 32
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    mova            m3, [t4+r10*1+416*0+0]
+    paddw           m3, [t4+r10*1+416*0+4]
+    paddw           m1, m3, [t4+r10*1+416*0+2]
+    psllw           m1, 2                ; a[ 1] 444
+    psubw           m2, m1, m3           ; a[ 1] 343
+    paddw           m3, m2, [t4+r10*1+416*4]
+    paddw           m3, [t4+r10*1+416*6]
+    mova [t4+r10*1+416*4], m2
+    mova [t4+r10*1+416*6], m1
+    mova           m16, [t3+r10*2+416*0+0]
+    paddd          m16, [t3+r10*2+416*0+8]
+    paddd           m1, m16, [t3+r10*2+416*0+4]
+    pslld           m1, 2                ; b[ 1] 444
+    psubd           m2, m1, m16          ; b[ 1] 343
+    paddd          m16, m2, [t3+r10*2+416* 8+ 0]
+    paddd          m16, [t3+r10*2+416*12+ 0]
+    mova [t3+r10*2+416* 8+ 0], m2
+    mova [t3+r10*2+416*12+ 0], m1
+    mova           m17, [t3+r10*2+416*0+64]
+    paddd          m17, [t3+r10*2+416*0+72]
+    paddd           m1, m17, [t3+r10*2+416*0+68]
+    pslld           m1, 2
+    psubd           m2, m1, m17
+    paddd          m17, m2, [t3+r10*2+416* 8+64]
+    paddd          m17, [t3+r10*2+416*12+64]
+    mova [t3+r10*2+416* 8+64], m2
+    mova [t3+r10*2+416*12+64], m1
+    mova            m0, [dstq+r10]
+    punpcklwd       m1, m0, m6
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m1               ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    vshufi32x4      m1, m16, m17, q2020
+    vshufi32x4     m16, m17, q3131
+    psubd           m1, m2               ; b - a * src + (1 << 8)
+    psubd          m16, m3
+    psrad           m1, 9
+    psrad          m16, 9
+    packssdw        m1, m16
+    pmulhrsw        m1, m7
+    paddw           m0, m1
+    pmaxsw          m0, m6
+    pminsw          m0, m14
+    mova    [dstq+r10], m0
+    add            r10, 64
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    mova            m3, [t4+r10*1+416*2+0]
+    paddw           m3, [t4+r10*1+416*2+4]
+    paddw           m1, m3, [t4+r10*1+416*2+2]
+    psllw           m1, 2                ; a[ 1] 444
+    psubw           m2, m1, m3           ; a[ 1] 343
+    paddw           m3, m2, [t4+r10*1+416*6]
+    paddw           m3, [t4+r10*1+416*8]
+    mova [t4+r10*1+416*6], m1
+    mova [t4+r10*1+416*8], m2
+    mova           m16, [t3+r10*2+416*4+0]
+    paddd          m16, [t3+r10*2+416*4+8]
+    paddd           m1, m16, [t3+r10*2+416*4+4]
+    pslld           m1, 2                ; b[ 1] 444
+    psubd           m2, m1, m16          ; b[ 1] 343
+    paddd          m16, m2, [t3+r10*2+416*12+ 0]
+    paddd          m16, [t3+r10*2+416*16+ 0]
+    mova [t3+r10*2+416*12+ 0], m1
+    mova [t3+r10*2+416*16+ 0], m2
+    mova           m17, [t3+r10*2+416*4+64]
+    paddd          m17, [t3+r10*2+416*4+72]
+    paddd           m1, m17, [t3+r10*2+416*4+68]
+    pslld           m1, 2
+    psubd           m2, m1, m17
+    paddd          m17, m2, [t3+r10*2+416*12+64]
+    paddd          m17, [t3+r10*2+416*16+64]
+    mova [t3+r10*2+416*12+64], m1
+    mova [t3+r10*2+416*16+64], m2
+    mova            m0, [dstq+r10]
+    punpcklwd       m1, m0, m6
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m1               ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    vshufi32x4      m1, m16, m17, q2020
+    vshufi32x4     m16, m17, q3131
+    psubd           m1, m2               ; b - a * src + (1 << 8)
+    psubd          m16, m3
+    psrad           m1, 9
+    psrad          m16, 9
+    packssdw        m1, m16
+    pmulhrsw        m1, m7
+    paddw           m0, m1
+    pmaxsw          m0, m6
+    pminsw          m0, m14
+    mova    [dstq+r10], m0
+    add            r10, 64
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_mix_16bpc, 4, 14, 23, 416*66+8, dst, stride, left, lpf, \
+                                                   w, h, edge, params
+    movifnidn       wd, wm
+    mov        paramsq, r6mp
+    lea            r13, [r_ext_mask+72]
+    mov          edged, r7m
+    movifnidn       hd, hm
+    vpbroadcastd    m7, [paramsq+8] ; w0 w1
+    pxor            m6, m6
+    vpbroadcastd    m8, [base+pd_8]
+    add             wd, wd
+    vpbroadcastd    m9, [base+pd_m9]
+    add           lpfq, wq
+    vpbroadcastd   m10, [base+pd_m25]
+    add           dstq, wq
+    vpsubd         m11, m6, [paramsq+0] {1to16} ; -s0
+    lea             t3, [rsp+wq*2+416*24+8]
+    vpsubd         m12, m6, [paramsq+4] {1to16} ; -s1
+    lea             t4, [rsp+wq+416*52+8]
+    vpbroadcastd   m13, [base+pw_164_455]
+    lea             t1, [rsp+wq+12]
+    vpbroadcastd   m14, [base+pw_61448]
+    neg             wq
+    vpbroadcastd   m15, [base+pd_m34816]
+    psllw           m7, 2
+    vpbroadcastd   m22, [base+pd_2147483648]
+    mov           r10d, 0xfffffff8
+    mova           m18, [sgr_x_by_x+64*0]
+    kmovd           k1, r10d
+    mova           m19, [sgr_x_by_x+64*1]
+    mov            r10, 0x3333333333333333
+    mova           m20, [sgr_x_by_x+64*2]
+    kmovq           k2, r10
+    mova           m21, [sgr_x_by_x+64*3]
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_avx512icl).top_fixup
+    add             t1, 416*12
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    add           lpfq, strideq
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    call .hv0
+    test            hd, hd
+    jz .odd_height
+    add           lpfq, strideq
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .hv0_bottom
+    add           lpfq, strideq
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea            r10, [wq-4]
+    lea             t2, [t1+416*12]
+.top_fixup_loop:
+    mova            m0, [t1+r10+416* 0]
+    mova            m1, [t1+r10+416* 2]
+    mova            m2, [t1+r10+416* 4]
+    paddw           m0, m0
+    mova            m3, [t1+r10+416* 6]
+    paddd           m1, m1
+    mova            m4, [t1+r10+416* 8]
+    paddd           m2, m2
+    mova            m5, [t1+r10+416*10]
+    mova [t2+r10+416* 0], m0
+    mova [t2+r10+416* 2], m1
+    mova [t2+r10+416* 4], m2
+    mova [t2+r10+416* 6], m3
+    mova [t2+r10+416* 8], m4
+    mova [t2+r10+416*10], m5
+    add            r10, 64
+    jl .top_fixup_loop
+    call .v0
+    jmp .main
+.h: ; horizontal boxsum
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movq          xm16, [leftq+2]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    vpbroadcastw  xm16, [lpfq+wq]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu           m16, [lpfq+r10- 2]
+.h_main:
+    movu           m17, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -68
+    jl .h_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd     m16, m0, [r13+r10+ 0], 0xe4
+    vpternlogd     m17, m0, [r13+r10+16], 0xe4
+.h_have_right:
+    palignr         m3, m17, m16, 2
+    palignr         m0, m17, m16, 4
+    paddw           m1, m3, m0
+    punpcklwd       m2, m3, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m0
+    pmaddwd         m3, m3
+    palignr         m0, m17, m16, 6
+    paddw           m1, m0             ; sum3
+    punpcklwd       m4, m0, m6
+    vpdpwssd        m2, m4, m4         ; sumsq3
+    punpckhwd       m0, m6
+    vpdpwssd        m3, m0, m0
+    shufpd          m4, m16, m17, 0x55
+    punpcklwd      m17, m4, m16
+    paddw           m0, m16, m4
+    punpckhwd       m4, m16
+    mova [t1+r10+416* 6], m1
+    mova [t1+r10+416* 8], m2
+    mova [t1+r10+416*10], m3
+    paddw           m1, m0             ; sum5
+    vpdpwssd        m2, m17, m17       ; sumsq5
+    vpdpwssd        m3, m4, m4
+    mova [t1+r10+416* 0], m1
+    mova [t1+r10+416* 2], m2
+    mova [t1+r10+416* 4], m3
+    add            r10, 64
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsum + vertical boxsum + ab3 (even rows)
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movq          xm16, [leftq+2]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    add          leftq, 8
+    jmp .hv0_main
+.hv0_extend_left:
+    vpbroadcastw  xm16, [lpfq+wq]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    jmp .hv0_main
+.hv0_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+.hv0_loop:
+    movu           m16, [lpfq+r10- 2]
+.hv0_main:
+    movu           m17, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp           r10d, -68
+    jl .hv0_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd     m16, m0, [r13+r10+ 0], 0xe4
+    vpternlogd     m17, m0, [r13+r10+16], 0xe4
+.hv0_have_right:
+    palignr         m3, m17, m16, 2
+    palignr         m0, m17, m16, 4
+    paddw           m1, m3, m0
+    punpcklwd       m2, m3, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m0
+    pmaddwd         m3, m3
+    palignr         m0, m17, m16, 6
+    paddw           m1, m0             ; h sum3
+    punpcklwd       m4, m0, m6
+    vpdpwssd        m2, m4, m4         ; h sumsq3
+    punpckhwd       m0, m6
+    vpdpwssd        m3, m0, m0
+    shufpd         m17, m16, m17, 0x55
+    paddw           m4, m1, [t1+r10+416* 6]
+    paddd           m5, m2, [t1+r10+416* 8]
+    mova [t1+r10+416* 6], m1
+    mova [t1+r10+416* 8], m2
+    paddw           m1, m16
+    paddw           m1, m17            ; h sum5
+    punpcklwd       m0, m17, m16
+    vpdpwssd        m2, m0, m0         ; h sumsq5
+    paddd           m0, m3, [t1+r10+416*10]
+    mova [t1+r10+416*10], m3
+    punpckhwd      m17, m16
+    vpdpwssd        m3, m17, m17
+    mova [t3+r10*2+416*8+ 8], m1       ; we need a clean copy of the last row
+    mova [t3+r10*2+416*0+ 8], m2       ; in case height is odd
+    mova [t3+r10*2+416*0+72], m3
+    paddw           m1, [t1+r10+416* 0]
+    paddd           m2, [t1+r10+416* 2]
+    paddd           m3, [t1+r10+416* 4]
+    mova [t1+r10+416* 0], m1
+    mova [t1+r10+416* 2], m2
+    mova [t1+r10+416* 4], m3
+    paddw          m17, m4, [t2+r10+416* 6]
+    paddd           m2, m5, [t2+r10+416* 8]
+    paddd           m3, m0, [t2+r10+416*10]
+    mova [t2+r10+416* 6], m4
+    mova [t2+r10+416* 8], m5
+    mova [t2+r10+416*10], m0
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m9             ; -((a3 + 8) >> 4) * 9
+    pmulld          m3, m9
+    psrlw           m5, m17, 1
+    pavgw           m5, m6             ; (b3 + 2) >> 2
+    punpcklwd       m4, m5, m6
+    vpdpwssd        m2, m4, m4         ; -p3
+    punpckhwd       m5, m6
+    vpdpwssd        m3, m5, m5
+    punpcklwd      m16, m6, m17        ; b3
+    punpckhwd      m17, m6, m17
+    pminsd          m2, m6
+    pminsd          m3, m6
+    pmulld          m2, m12            ; p3 * s1
+    pmulld          m3, m12
+    pmaddwd        m16, m13            ; b3 * 455
+    pmaddwd        m17, m13
+    vpalignr    m3{k2}, m2, m2, 2
+    mova            m2, m20
+    paddusw         m3, m14
+    psraw           m3, 4              ; min(z3, 255) - 256
+    vpermt2b        m2, m3, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m3
+    vpermi2b        m3, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m3{k3}, m2             ; x3
+    pandn           m2, m15, m3
+    psrld           m3, 16
+    pmulld         m16, m2
+    pmulld         m17, m3
+    packssdw        m2, m3
+    mova [t4+r10*1+416*2+4], m2
+    psubd          m16, m15            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    psubd          m17, m15
+    psrld          m16, 12
+    psrld          m17, 12
+    mova          [t3+r10*2+416*4+  8], xm16
+    mova          [t3+r10*2+416*4+ 24], xm17
+    vextracti128  [t3+r10*2+416*4+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*4+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*4+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*4+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*4+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*4+120], m17, 3
+    add            r10, 64
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movq          xm16, [leftq+2]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    add          leftq, 8
+    jmp .hv1_main
+.hv1_extend_left:
+    vpbroadcastw  xm16, [lpfq+wq]
+    vmovdqu16  m16{k1}, [lpfq+wq-6]
+    jmp .hv1_main
+.hv1_bottom:
+    lea            r10, [wq-4]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+.hv1_loop:
+    movu           m16, [lpfq+r10- 2]
+.hv1_main:
+    movu           m17, [lpfq+r10+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp           r10d, -68
+    jl .hv1_have_right
+    vpbroadcastw    m0, [lpfq-2]
+    vpternlogd     m16, m0, [r13+r10+ 0], 0xe4
+    vpternlogd     m17, m0, [r13+r10+16], 0xe4
+.hv1_have_right:
+    palignr         m1, m17, m16, 2
+    palignr         m3, m17, m16, 4
+    paddw           m2, m1, m3
+    punpcklwd       m0, m1, m3
+    pmaddwd         m0, m0
+    punpckhwd       m1, m3
+    pmaddwd         m1, m1
+    palignr         m3, m17, m16, 6
+    paddw           m2, m3             ; h sum3
+    punpcklwd       m5, m3, m6
+    vpdpwssd        m0, m5, m5         ; h sumsq3
+    punpckhwd       m3, m6
+    vpdpwssd        m1, m3, m3
+    shufpd          m3, m16, m17, 0x55
+    punpcklwd       m5, m16, m3
+    paddw           m4, m16, m3
+    punpckhwd      m16, m3
+    paddw          m17, m2, [t2+r10+416* 6]
+    mova [t2+r10+416* 6], m2
+    paddw           m4, m2             ; h sum5
+    paddd           m2, m0, [t2+r10+416* 8]
+    paddd           m3, m1, [t2+r10+416*10]
+    mova [t2+r10+416* 8], m0
+    mova [t2+r10+416*10], m1
+    vpdpwssd        m0, m5, m5         ; h sumsq5
+    vpdpwssd        m1, m16, m16
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m9             ; -((a3 + 8) >> 4) * 9
+    pmulld          m3, m9
+    psrlw          m16, m17, 1
+    pavgw          m16, m6             ; (b3 + 2) >> 2
+    punpcklwd       m5, m16, m6
+    vpdpwssd        m2, m5, m5         ; -p3
+    punpckhwd      m16, m6
+    vpdpwssd        m3, m16, m16
+    punpcklwd      m16, m6, m17        ; b3
+    punpckhwd      m17, m6, m17
+    pminsd          m2, m6
+    pminsd          m3, m6
+    pmulld          m2, m12            ; p3 * s1
+    pmulld          m3, m12
+    pmaddwd        m16, m13            ; b3 * 455
+    pmaddwd        m17, m13
+    vpalignr    m3{k2}, m2, m2, 2
+    mova            m2, m20
+    paddusw         m3, m14
+    psraw           m3, 4              ; min(z3, 255) - 256
+    vpermt2b        m2, m3, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m3
+    vpermi2b        m3, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m3{k3}, m2             ; x3
+    pandn           m2, m15, m3
+    psrld           m3, 16
+    pmulld         m16, m2
+    pmulld         m17, m3
+    packssdw        m2, m3
+    mova [t4+r10*1+416*4+4], m2
+    psubd          m16, m15            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    psubd          m17, m15
+    psrld          m16, 12
+    psrld          m17, 12
+    paddw           m5, m4, [t2+r10+416*0]
+    paddd           m2, m0, [t2+r10+416*2]
+    paddd           m3, m1, [t2+r10+416*4]
+    paddw           m5, [t1+r10+416*0]
+    paddd           m2, [t1+r10+416*2]
+    paddd           m3, [t1+r10+416*4]
+    mova [t2+r10+416*0], m4
+    mova [t2+r10+416*2], m0
+    mova [t2+r10+416*4], m1
+    mova          [t3+r10*2+416*8+  8], xm16
+    mova          [t3+r10*2+416*8+ 24], xm17
+    vextracti128  [t3+r10*2+416*8+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*8+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*8+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*8+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*8+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*8+120], m17, 3
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a5 + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m10            ; -((a5 + 8) >> 4) * 25
+    pmulld          m3, m10
+    psrlw          m17, m5, 1
+    pavgw          m17, m6             ; (b5 + 2) >> 2
+    punpcklwd      m16, m17, m6
+    vpdpwssd        m2, m16, m16       ; -p5
+    punpckhwd      m17, m6
+    vpdpwssd        m3, m17, m17
+    punpcklwd      m16, m5, m6         ; b5
+    punpckhwd      m17, m5, m6
+    pmulld          m2, m11            ; p5 * s0
+    pmulld          m3, m11
+    pmaddwd        m16, m13            ; b5 * 164
+    pmaddwd        m17, m13
+    vpalignr    m3{k2}, m2, m2, 2
+    mova            m2, m20
+    pmaxsw          m3, m6
+    paddusw         m3, m14
+    psraw           m3, 4              ; min(z5, 255) - 256
+    vpermt2b        m2, m3, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m3
+    vpermi2b        m3, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m3{k3}, m2             ; x5
+    pandn           m2, m15, m3
+    psrld           m3, 16
+    pmulld         m16, m2
+    pmulld         m17, m3
+    packssdw        m2, m3
+    mova [t4+r10*1+416*0+4], m2
+    psubd          m16, m15            ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    psubd          m17, m15
+    psrld          m16, 12
+    psrld          m17, 12
+    mova          [t3+r10*2+416*0+  8], xm16
+    mova          [t3+r10*2+416*0+ 24], xm17
+    vextracti128  [t3+r10*2+416*0+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*0+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*0+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*0+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*0+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*0+120], m17, 3
+    add            r10, 64
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab3 (even rows)
+    lea            r10, [wq-4]
+.v0_loop:
+    mova           m16, [t1+r10+416* 6]
+    mova            m2, [t1+r10+416* 8]
+    mova            m3, [t1+r10+416*10]
+    paddw          m16, m16
+    paddd           m2, m2
+    paddd           m3, m3
+    paddw          m17, m16, [t2+r10+416* 6]
+    paddd           m4, m2, [t2+r10+416* 8]
+    paddd           m5, m3, [t2+r10+416*10]
+    mova [t2+r10+416* 6], m16
+    mova [t2+r10+416* 8], m2
+    mova [t2+r10+416*10], m3
+    paddd           m4, m8
+    paddd           m5, m8
+    psrld           m4, 4              ; (a3 + 8) >> 4
+    psrld           m5, 4
+    pmulld          m4, m9             ; -((a3 + 8) >> 4) * 9
+    pmulld          m5, m9
+    psrlw           m3, m17, 1
+    pavgw           m3, m6             ; (b3 + 2) >> 2
+    punpcklwd       m2, m3, m6
+    vpdpwssd        m4, m2, m2         ; -p3
+    punpckhwd       m3, m6
+    vpdpwssd        m5, m3, m3
+    punpcklwd      m16, m6, m17        ; b3
+    punpckhwd      m17, m6, m17
+    pminsd          m4, m6
+    pminsd          m5, m6
+    pmulld          m4, m12            ; p3 * s1
+    pmulld          m5, m12
+    pmaddwd        m16, m13            ; b3 * 455
+    pmaddwd        m17, m13
+    vpalignr    m5{k2}, m4, m4, 2
+    mova            m4, m20
+    paddusw         m5, m14
+    psraw           m5, 4              ; min(z3, 255) - 256
+    vpermt2b        m4, m5, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m5
+    vpermi2b        m5, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m5{k3}, m4             ; x3
+    pandn           m4, m15, m5
+    psrld           m5, 16
+    pmulld         m16, m4
+    pmulld         m17, m5
+    packssdw        m4, m5
+    mova [t4+r10*1+416*2+4], m4
+    psubd          m16, m15            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    psubd          m17, m15
+    psrld          m16, 12
+    psrld          m17, 12
+    mova            m3, [t1+r10+416*0]
+    mova            m4, [t1+r10+416*2]
+    mova            m5, [t1+r10+416*4]
+    mova [t3+r10*2+416*8+ 8], m3
+    mova [t3+r10*2+416*0+ 8], m4
+    mova [t3+r10*2+416*0+72], m5
+    paddw           m3, m3              ; cc5
+    paddd           m4, m4
+    paddd           m5, m5
+    mova [t1+r10+416*0], m3
+    mova [t1+r10+416*2], m4
+    mova [t1+r10+416*4], m5
+    mova          [t3+r10*2+416*4+  8], xm16
+    mova          [t3+r10*2+416*4+ 24], xm17
+    vextracti128  [t3+r10*2+416*4+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*4+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*4+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*4+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*4+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*4+120], m17, 3
+    add            r10, 64
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+    lea            r10, [wq-4]
+.v1_loop:
+    mova           m16, [t1+r10+416* 6]
+    mova            m2, [t1+r10+416* 8]
+    mova            m3, [t1+r10+416*10]
+    paddw          m17, m16, [t2+r10+416* 6]
+    paddd           m4, m2, [t2+r10+416* 8]
+    paddd           m5, m3, [t2+r10+416*10]
+    mova [t2+r10+416* 6], m16
+    mova [t2+r10+416* 8], m2
+    mova [t2+r10+416*10], m3
+    paddd           m4, m8
+    paddd           m5, m8
+    psrld           m4, 4              ; (a3 + 8) >> 4
+    psrld           m5, 4
+    pmulld          m4, m9              ; -((a3 + 8) >> 4) * 9
+    pmulld          m5, m9
+    psrlw           m3, m17, 1
+    pavgw           m3, m6             ; (b3 + 2) >> 2
+    punpcklwd       m2, m3, m6
+    vpdpwssd        m4, m2, m2         ; -p3
+    punpckhwd       m3, m6
+    vpdpwssd        m5, m3, m3
+    punpcklwd      m16, m6, m17        ; b3
+    punpckhwd      m17, m6, m17
+    pminsd          m4, m6
+    pminsd          m5, m6
+    pmulld          m4, m12            ; p3 * s1
+    pmulld          m5, m12
+    pmaddwd        m16, m13            ; b3 * 455
+    pmaddwd        m17, m13
+    vpalignr    m5{k2}, m4, m4, 2
+    mova            m4, m20
+    paddusw         m5, m14
+    psraw           m5, 4              ; min(z3, 255) - 256
+    vpermt2b        m4, m5, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m5
+    vpermi2b        m5, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m5{k3}, m4             ; x3
+    pandn           m4, m15, m5
+    psrld           m5, 16
+    pmulld         m16, m4
+    pmulld         m17, m5
+    packssdw        m4, m5
+    mova [t4+r10*1+416*4+4], m4
+    psubd          m16, m15            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    psubd          m17, m15
+    psrld          m16, 12
+    psrld          m17, 12
+    mova            m0, [t3+r10*2+416*8+ 8]
+    mova            m4, [t3+r10*2+416*0+ 8]
+    mova            m5, [t3+r10*2+416*0+72]
+    paddw           m1, m0, [t2+r10+416*0]
+    paddd           m2, m4, [t2+r10+416*2]
+    paddd           m3, m5, [t2+r10+416*4]
+    paddw           m1, [t1+r10+416*0]
+    paddd           m2, [t1+r10+416*2]
+    paddd           m3, [t1+r10+416*4]
+    mova [t2+r10+416*0], m0
+    mova [t2+r10+416*2], m4
+    mova [t2+r10+416*4], m5
+    mova          [t3+r10*2+416*8+  8], xm16
+    mova          [t3+r10*2+416*8+ 24], xm17
+    vextracti128  [t3+r10*2+416*8+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*8+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*8+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*8+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*8+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*8+120], m17, 3
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a5 + 8) >> 4
+    psrld           m3, 4
+    pmulld          m2, m10            ; -((a5 + 8) >> 4) * 25
+    pmulld          m3, m10
+    psrlw           m5, m1, 1
+    pavgw           m5, m6             ; (b5 + 2) >> 2
+    punpcklwd       m4, m5, m6
+    vpdpwssd        m2, m4, m4         ; -p5
+    punpckhwd       m5, m6
+    vpdpwssd        m3, m5, m5
+    punpcklwd      m16, m1, m6         ; b5
+    punpckhwd      m17, m1, m6
+    pmulld          m2, m11            ; p5 * s0
+    pmulld          m3, m11
+    pmaddwd        m16, m13            ; b5 * 164
+    pmaddwd        m17, m13
+    vpalignr    m3{k2}, m2, m2, 2
+    mova            m2, m20
+    pmaxsw          m3, m6
+    paddusw         m3, m14
+    psraw           m3, 4              ; min(z5, 255) - 256
+    vpermt2b        m2, m3, m21        ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m3
+    vpermi2b        m3, m18, m19       ; sgr_x_by_x[  0..127]
+    vmovdqu8    m3{k3}, m2             ; x5
+    pandn           m2, m15, m3
+    psrld           m3, 16
+    pmulld         m16, m2
+    pmulld         m17, m3
+    packssdw        m2, m3
+    mova [t4+r10*1+416*0+4], m2
+    psubd          m16, m15            ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    psubd          m17, m15
+    psrld          m16, 12
+    psrld          m17, 12
+    mova          [t3+r10*2+416*0+  8], xm16
+    mova          [t3+r10*2+416*0+ 24], xm17
+    vextracti128  [t3+r10*2+416*0+ 40], ym16, 1
+    vextracti128  [t3+r10*2+416*0+ 56], ym17, 1
+    vextracti32x4 [t3+r10*2+416*0+ 72], m16, 2
+    vextracti32x4 [t3+r10*2+416*0+ 88], m17, 2
+    vextracti32x4 [t3+r10*2+416*0+104], m16, 3
+    vextracti32x4 [t3+r10*2+416*0+120], m17, 3
+    add            r10, 64
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    movu           ym0, [t4+r10*1+416*0+2]
+    paddw          ym2, ym0, [t4+r10*1+416*0+0]
+    paddw          ym2, [t4+r10*1+416*0+4]
+    movu            m1, [t3+r10*2+416*0+4]
+    paddd           m3, m1, [t3+r10*2+416*0+0]
+    paddd           m3, [t3+r10*2+416*0+8]
+    paddw          ym0, ym2
+    paddd           m1, m3
+    psllw          ym2, 2
+    pslld           m3, 2
+    paddw          ym0, ym2              ; a5 565
+    paddd           m1, m3               ; b5 565
+    mova [t4+r10*1+416* 6], ym0
+    mova [t3+r10*2+416*12], m1
+    mova           ym0, [t4+r10*1+416*2+0]
+    paddw          ym0, [t4+r10*1+416*2+4]
+    paddw          ym2, ym0, [t4+r10*1+416*2+2]
+    mova            m1, [t3+r10*2+416*4+0]
+    paddd           m1, [t3+r10*2+416*4+8]
+    paddd           m3, m1, [t3+r10*2+416*4+4]
+    psllw          ym2, 2                ; a3[-1] 444
+    pslld           m3, 2                ; b3[-1] 444
+    psubw          ym2, ym0              ; a3[-1] 343
+    psubd           m3, m1               ; b3[-1] 343
+    mova [t4+r10*1+416* 8], ym2
+    mova [t3+r10*2+416*16], m3
+    mova           ym0, [t4+r10*1+416*4+0]
+    paddw          ym0, [t4+r10*1+416*4+4]
+    paddw          ym2, ym0, [t4+r10*1+416*4+2]
+    mova            m1, [t3+r10*2+416*8+0]
+    paddd           m1, [t3+r10*2+416*8+8]
+    paddd           m3, m1, [t3+r10*2+416*8+4]
+    psllw          ym2, 2                 ; a3[ 0] 444
+    pslld           m3, 2                 ; b3[ 0] 444
+    mova [t4+r10*1+416*10], ym2
+    mova [t3+r10*2+416*20], m3
+    psubw          ym2, ym0               ; a3[ 0] 343
+    psubd           m3, m1                ; b3[ 0] 343
+    mova [t4+r10*1+416*12], ym2
+    mova [t3+r10*2+416*24], m3
+    add            r10, 32
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    movu           ym2, [t4+r10*1+2]
+    paddw          ym0, ym2, [t4+r10*1+0]
+    paddw          ym0, [t4+r10*1+4]
+    paddw          ym2, ym0
+    psllw          ym0, 2
+    paddw          ym0, ym2              ; a5
+    movu            m1, [t3+r10*2+4]
+    paddd           m4, m1, [t3+r10*2+0]
+    paddd           m4, [t3+r10*2+8]
+    paddd           m1, m4
+    pslld           m4, 2
+    paddd           m4, m1               ; b5
+    paddw          ym2, ym0, [t4+r10*1+416* 6]
+    mova [t4+r10*1+416* 6], ym0
+    paddd           m0, m4, [t3+r10*2+416*12]
+    mova [t3+r10*2+416*12], m4
+    mova           ym3, [t4+r10*1+416*2+0]
+    paddw          ym3, [t4+r10*1+416*2+4]
+    paddw          ym5, ym3, [t4+r10*1+416*2+2]
+    psllw          ym5, 2                ; a3[ 1] 444
+    psubw          ym4, ym5, ym3         ; a3[ 1] 343
+    paddw          ym3, ym4, [t4+r10*1+416* 8]
+    paddw          ym3, [t4+r10*1+416*10]
+    mova [t4+r10*1+416* 8], ym4
+    mova [t4+r10*1+416*10], ym5
+    mova            m1, [t3+r10*2+416*4+0]
+    paddd           m1, [t3+r10*2+416*4+8]
+    paddd           m5, m1, [t3+r10*2+416*4+4]
+    pslld           m5, 2                ; b3[ 1] 444
+    psubd           m4, m5, m1           ; b3[ 1] 343
+    paddd           m1, m4, [t3+r10*2+416*16]
+    paddd           m1, [t3+r10*2+416*20]
+    mova [t3+r10*2+416*16], m4
+    mova [t3+r10*2+416*20], m5
+    pmovzxwd        m4, [dstq+r10]
+    pmovzxwd        m2, ym2              ; a5
+    pmovzxwd        m3, ym3              ; a3
+    pmaddwd         m2, m4               ; a5 * src
+    pmaddwd         m3, m4               ; a3 * src
+    vpshldd         m4, m22, 13
+    psubd           m0, m2               ; b5 - a5 * src + (1 << 8)
+    psubd           m1, m3               ; b3 - a3 * src + (1 << 8)
+    psrld           m0, 9
+    pslld           m1, 7
+    vpblendmb   m0{k2}, m1, m0
+    vpdpwssd        m4, m0, m7
+    psrad           m4, 7
+    pmaxsd          m4, m6
+    vpmovusdw     ym16, m4               ; clip
+    psrlw         ym16, 6
+    mova    [dstq+r10], ym16
+    add            r10, 32
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    mova           ym3, [t4+r10*1+416*4+0]
+    paddw          ym3, [t4+r10*1+416*4+4]
+    paddw          ym5, ym3, [t4+r10*1+416*4+2]
+    psllw          ym5, 2                ; a3[ 1] 444
+    psubw          ym4, ym5, ym3         ; a3[ 1] 343
+    paddw          ym3, ym4, [t4+r10*1+416*12]
+    paddw          ym3, [t4+r10*1+416*10]
+    mova [t4+r10*1+416*10], ym5
+    mova [t4+r10*1+416*12], ym4
+    mova            m0, [t3+r10*2+416*8+0]
+    paddd           m0, [t3+r10*2+416*8+8]
+    paddd           m5, m0, [t3+r10*2+416*8+4]
+    pslld           m5, 2                ; b3[ 1] 444
+    psubd           m4, m5, m0           ; b3[ 1] 343
+    paddd           m0, m4, [t3+r10*2+416*24]
+    paddd           m0, [t3+r10*2+416*20]
+    mova [t3+r10*2+416*20], m5
+    mova [t3+r10*2+416*24], m4
+    pmovzxwd        m4, [dstq+r10]
+    pmovzxwd        m2, [t4+r10*1+416* 6]
+    pmovzxwd        m3, ym3
+    mova            m1, [t3+r10*2+416*12]
+    pmaddwd         m2, m4               ; a5 * src
+    pmaddwd         m3, m4               ; a3 * src
+    vpshldd         m4, m22, 13
+    psubd           m1, m2               ; b5 - a5 * src + (1 << 8)
+    psubd           m0, m3               ; b3 - a3 * src + (1 << 8)
+    pslld           m0, 7
+    vpalignr    m0{k2}, m1, m1, 1
+    vpdpwssd        m4, m0, m7
+    psrad           m4, 7
+    pmaxsd          m4, m6
+    vpmovusdw     ym16, m4               ; clip
+    psrlw         ym16, 6
+    mova    [dstq+r10], ym16
+    add            r10, 32
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/looprestoration16_sse.asm b/media/libdav1d/src/src/x86/looprestoration16_sse.asm
new file mode 100644
index 0000000000..4a01e9bd45
--- /dev/null
+++ b/media/libdav1d/src/src/x86/looprestoration16_sse.asm
@@ -0,0 +1,3467 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA
+
+wiener_shufA:  db  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11
+wiener_shufB:  db  6,  7,  4,  5,  8,  9,  6,  7, 10, 11,  8,  9, 12, 13, 10, 11
+wiener_shufC:  db  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15
+wiener_shufD:  db  2,  3, -1, -1,  4,  5, -1, -1,  6,  7, -1, -1,  8,  9, -1, -1
+wiener_shufE:  db  0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+wiener_lshuf5: db  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11
+wiener_lshuf7: db  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7
+sgr_lshuf3:    db  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11
+sgr_lshuf5:    db  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9
+pb_0to15:      db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+
+pb_m14_m13:    times 8 db -14,-13
+pb_m10_m9:     times 8 db -10, -9
+pb_m6_m5:      times 8 db  -6, -5
+pb_m2_m1:      times 8 db  -2, -1
+pb_2_3:        times 8 db   2,  3
+pb_6_7:        times 8 db   6,  7
+pw_256:        times 8 dw 256
+pw_1023:       times 8 dw 1023
+pw_164_24:     times 4 dw 164, 24
+pw_455_24:     times 4 dw 455, 24
+pd_8:          times 4 dd 8
+pd_4096:       times 4 dd 4096
+pd_34816:      times 4 dd 34816
+pd_m262128:    times 4 dd -262128
+pd_0xffff:     times 4 dd 0xffff
+pd_0xfffffff0: times 4 dd 0xfffffff0
+pf_256:        times 4 dd 256.0
+
+wiener_shifts: dw 4, 4, 2048, 2048, 1, 1, 8192, 8192
+wiener_round:  dd 1049600, 1048832
+
+SECTION .text
+
+%macro movif64 2 ; dst, src
+ %if ARCH_X86_64
+    mov             %1, %2
+ %endif
+%endmacro
+
+%macro movif32 2 ; dst, src
+ %if ARCH_X86_32
+    mov             %1, %2
+ %endif
+%endmacro
+
+INIT_XMM ssse3
+%if ARCH_X86_32
+DECLARE_REG_TMP 5, 6
+ %if STACK_ALIGNMENT < 16
+  %assign extra_stack 13*16
+ %else
+  %assign extra_stack 12*16
+ %endif
+cglobal wiener_filter7_16bpc, 4, 7, 8, -384*12-16-extra_stack, \
+                              dst, stride, left, lpf, w, flt
+ %if STACK_ALIGNMENT < 16
+  %define lpfm        dword [esp+calloff+16*12+ 0]
+  %define wm          dword [esp+calloff+16*12+ 4]
+  %define hd          dword [esp+calloff+16*12+ 8]
+  %define edgeb        byte [esp+calloff+16*12+12]
+  %define edged       dword [esp+calloff+16*12+12]
+ %else
+  %define hd dword r5m
+  %define edgeb byte r7m
+ %endif
+ %define PICmem dword [esp+calloff+4*0]
+ %define t0m    dword [esp+calloff+4*1] ; wiener ring buffer pointers
+ %define t1m    dword [esp+calloff+4*2]
+ %define t2m    dword [esp+calloff+4*3]
+ %define t3m    dword [esp+calloff+4*4]
+ %define t4m    dword [esp+calloff+4*5]
+ %define t5m    dword [esp+calloff+4*6]
+ %define t6m    dword [esp+calloff+4*7]
+ %define t2 t2m
+ %define t3 t3m
+ %define t4 t4m
+ %define t5 t5m
+ %define t6 t6m
+ %define  m8 [esp+calloff+16*2]
+ %define  m9 [esp+calloff+16*3]
+ %define m10 [esp+calloff+16*4]
+ %define m11 [esp+calloff+16*5]
+ %define m12 [esp+calloff+16*6]
+ %define m13 [esp+calloff+16*7]
+ %define m14 [esp+calloff+16*8]
+ %define m15 [esp+calloff+16*9]
+ %define r10 r4
+ %define base t0-wiener_shifts
+ %assign calloff 0
+ %if STACK_ALIGNMENT < 16
+    mov             wd, [rstk+stack_offset+20]
+    mov             wm, wd
+    mov             r5, [rstk+stack_offset+24]
+    mov             hd, r5
+    mov             r5, [rstk+stack_offset+32]
+    mov          edged, r5 ; edge
+ %endif
+%else
+DECLARE_REG_TMP 8, 7, 9, 11, 12, 13, 14 ; wiener ring buffer pointers
+cglobal wiener_filter7_16bpc, 4, 15, 16, -384*12-16, dst, stride, left, lpf, \
+                                                     w, h, edge, flt
+ %define base
+%endif
+%if ARCH_X86_64 || STACK_ALIGNMENT >= 16
+    movifnidn       wd, wm
+%endif
+%if ARCH_X86_64
+    mov           fltq, r6mp
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mov            t3d, r8m ; pixel_max
+    movq           m13, [fltq]
+    movq           m15, [fltq+16]
+%else
+ %if STACK_ALIGNMENT < 16
+    mov             t0, [rstk+stack_offset+28]
+    mov             t1, [rstk+stack_offset+36] ; pixel_max
+    movq            m1, [t0]    ; fx
+    movq            m3, [t0+16] ; fy
+    LEA             t0, wiener_shifts
+ %else
+    mov           fltq, r6m
+    movq            m1, [fltq]
+    movq            m3, [fltq+16]
+    LEA             t0, wiener_shifts
+    mov             t1, r8m ; pixel_max
+ %endif
+    mov         PICmem, t0
+%endif
+    mova            m6, [base+wiener_shufA]
+    mova            m7, [base+wiener_shufB]
+%if ARCH_X86_64
+    lea             t4, [wiener_shifts]
+    add             wd, wd
+    pshufd         m12, m13, q0000 ; x0 x1
+    pshufd         m13, m13, q1111 ; x2 x3
+    pshufd         m14, m15, q0000 ; y0 y1
+    pshufd         m15, m15, q1111 ; y2 y3
+    mova            m8, [wiener_shufC]
+    mova            m9, [wiener_shufD]
+    add           lpfq, wq
+    lea             t1, [rsp+wq+16]
+    add           dstq, wq
+    neg             wq
+    shr            t3d, 11
+ %define base t4-wiener_shifts
+    movd           m10, [base+wiener_round+t3*4]
+    movq           m11, [base+wiener_shifts+t3*8]
+    pshufd         m10, m10, q0000
+    pshufd          m0, m11, q0000
+    pshufd         m11, m11, q1111
+    pmullw         m12, m0 ; upshift filter coefs to make the
+    pmullw         m13, m0 ; horizontal downshift constant
+ DEFINE_ARGS dst, stride, left, lpf, _, h, edge, _, _, _, w
+ %define lpfm [rsp]
+ %define base
+ %define wiener_lshuf7_mem [wiener_lshuf7]
+ %define pd_m262128_mem [pd_m262128]
+%else
+    add             wd, wd
+    mova            m4, [base+wiener_shufC]
+    mova            m5, [base+wiener_shufD]
+    pshufd          m0, m1, q0000
+    pshufd          m1, m1, q1111
+    pshufd          m2, m3, q0000
+    pshufd          m3, m3, q1111
+    mova            m8, m4
+    mova            m9, m5
+    mova           m14, m2
+    mova           m15, m3
+    shr             t1, 11
+    add           lpfq, wq
+    mova            m3, [base+pd_m262128]
+    movd            m4, [base+wiener_round+t1*4]
+    movq            m5, [base+wiener_shifts+t1*8]
+    lea             t1, [esp+extra_stack+wq+16]
+    add           dstq, wq
+    neg             wq
+    pshufd          m4, m4, q0000
+    pshufd          m2, m5, q0000
+    pshufd          m5, m5, q1111
+    mov             wm, wq
+    pmullw          m0, m2
+    pmullw          m1, m2
+    mova            m2, [base+wiener_lshuf7]
+ %define pd_m262128_mem [esp+calloff+16*10]
+    mova pd_m262128_mem, m3
+    mova           m10, m4
+    mova           m11, m5
+    mova           m12, m0
+    mova           m13, m1
+ %define wiener_lshuf7_mem [esp+calloff+16*11]
+    mova wiener_lshuf7_mem, m2
+%endif
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t6, t1
+    mov             t5, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t4, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov           lpfm, r10 ; below
+    call .h
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+.main:
+    lea             t0, [t1+384*2]
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v3
+    mov           lpfq, lpfm
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.v1:
+    call .v
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov           lpfm, r10
+    call .h
+    mov             t6, t1
+    mov             t5, t1
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v3
+    add             t0, 384*8
+    call .hv
+    dec             hd
+    jnz .main
+.v3:
+    call .v
+    movif32         wq, wm
+.v2:
+    call .v
+    movif32         wq, wm
+    jmp .v1
+.extend_right:
+%assign stack_offset stack_offset+8
+%assign calloff 8
+    movif32         t0, PICmem
+    pxor            m0, m0
+    movd            m1, wd
+    mova            m2, [base+pb_0to15]
+    pshufb          m1, m0
+    mova            m0, [base+pb_6_7]
+    psubb           m0, m1
+    pminub          m0, m2
+    pshufb          m3, m0
+    mova            m0, [base+pb_m2_m1]
+    psubb           m0, m1
+    pminub          m0, m2
+    pshufb          m4, m0
+    mova            m0, [base+pb_m10_m9]
+    psubb           m0, m1
+    pminub          m0, m2
+    pshufb          m5, m0
+    movif32         t0, t0m
+    ret
+%assign stack_offset stack_offset-4
+%assign calloff 4
+.h:
+    movif64         wq, r4
+    movif32         wq, wm
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movq            m3, [leftq]
+    movhps          m3, [lpfq+wq]
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    mova            m3, [lpfq+wq]         ; avoid accessing memory located
+    pshufb          m3, wiener_lshuf7_mem ; before the start of the buffer
+    jmp .h_main
+.h_top:
+    movif64         wq, r4
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m3, [lpfq+wq-8]
+.h_main:
+    mova            m4, [lpfq+wq+0]
+    movu            m5, [lpfq+wq+8]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             wd, -20
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    pshufb          m0, m3, m6
+    pshufb          m1, m4, m7
+    paddw           m0, m1
+    pshufb          m3, m8
+    pmaddwd         m0, m12
+    pshufb          m1, m4, m9
+    paddw           m3, m1
+    pshufb          m1, m4, m6
+    pmaddwd         m3, m13
+    pshufb          m2, m5, m7
+    paddw           m1, m2
+    mova            m2, pd_m262128_mem ; (1 << 4) - (1 << 18)
+    pshufb          m4, m8
+    pmaddwd         m1, m12
+    pshufb          m5, m9
+    paddw           m4, m5
+    pmaddwd         m4, m13
+    paddd           m0, m2
+    paddd           m1, m2
+    paddd           m0, m3
+    paddd           m1, m4
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    psraw           m0, 1
+    mova       [t1+wq], m0
+    add             wq, 16
+    jl .h_loop
+    movif32         wq, wm
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    movif64         wq, r4
+    movif32        t0m, t0
+    movif32        t1m, t1
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movq            m3, [leftq]
+    movhps          m3, [lpfq+wq]
+    add          leftq, 8
+    jmp .hv_main
+.hv_extend_left:
+    mova            m3, [lpfq+wq]
+    pshufb          m3, wiener_lshuf7_mem
+    jmp .hv_main
+.hv_bottom:
+    movif64         wq, r4
+    movif32        t0m, t0
+    movif32        t1m, t1
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m3, [lpfq+wq-8]
+.hv_main:
+    mova            m4, [lpfq+wq+0]
+    movu            m5, [lpfq+wq+8]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp             wd, -20
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    movif32         t1, t4m
+    movif32         t0, t2m
+    pshufb          m0, m3, m6
+    pshufb          m1, m4, m7
+    paddw           m0, m1
+    pshufb          m3, m8
+    pmaddwd         m0, m12
+    pshufb          m1, m4, m9
+    paddw           m3, m1
+    pshufb          m1, m4, m6
+    pmaddwd         m3, m13
+    pshufb          m2, m5, m7
+    paddw           m1, m2
+    mova            m2, pd_m262128_mem
+    pshufb          m4, m8
+    pmaddwd         m1, m12
+    pshufb          m5, m9
+    paddw           m4, m5
+    pmaddwd         m4, m13
+    paddd           m0, m2
+    paddd           m1, m2
+%if ARCH_X86_64
+    mova            m2, [t4+wq]
+    paddw           m2, [t2+wq]
+    mova            m5, [t3+wq]
+%else
+    mova            m2, [t1+wq]
+    paddw           m2, [t0+wq]
+    mov             t1, t3m
+    mov             t0, t5m
+    mova            m5, [t1+wq]
+    mov             t1, t1m
+%endif
+    paddd           m0, m3
+    paddd           m1, m4
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+%if ARCH_X86_64
+    mova            m4, [t5+wq]
+    paddw           m4, [t1+wq]
+    psraw           m0, 1
+    paddw           m3, m0, [t6+wq]
+%else
+    mova            m4, [t0+wq]
+    paddw           m4, [t1+wq]
+    mov             t0, t0m
+    mov             t1, t6m
+    psraw           m0, 1
+    paddw           m3, m0, [t1+wq]
+%endif
+    mova       [t0+wq], m0
+    punpcklwd       m0, m2, m5
+    pmaddwd         m0, m15
+    punpckhwd       m2, m5
+    pmaddwd         m2, m15
+    punpcklwd       m1, m3, m4
+    pmaddwd         m1, m14
+    punpckhwd       m3, m4
+    pmaddwd         m3, m14
+    paddd           m0, m10
+    paddd           m2, m10
+    paddd           m0, m1
+    paddd           m2, m3
+    psrad           m0, 6
+    psrad           m2, 6
+    packssdw        m0, m2
+    pmulhw          m0, m11
+    pxor            m1, m1
+    pmaxsw          m0, m1
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .hv_loop
+%if ARCH_X86_64
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t6
+%else
+    mov             r4, t5m
+    mov             t1, t4m
+    mov            t6m, r4
+    mov            t5m, t1
+    mov             r4, t3m
+    mov             t1, t2m
+    mov            t4m, r4
+    mov            t3m, t1
+    mov             r4, t1m
+    mov             t1, t0
+    mov            t2m, r4
+    mov             t0, t6m
+    mov             wq, wm
+%endif
+    add           dstq, strideq
+    ret
+.v:
+    movif64         wq, r4
+    movif32        t0m, t0
+    movif32        t1m, t1
+.v_loop:
+%if ARCH_X86_64
+    mova            m1, [t4+wq]
+    paddw           m1, [t2+wq]
+    mova            m2, [t3+wq]
+    mova            m4, [t1+wq]
+    paddw           m3, m4, [t6+wq]
+    paddw           m4, [t5+wq]
+%else
+    mov             t0, t4m
+    mov             t1, t2m
+    mova            m1, [t0+wq]
+    paddw           m1, [t1+wq]
+    mov             t0, t3m
+    mov             t1, t1m
+    mova            m2, [t0+wq]
+    mova            m4, [t1+wq]
+    mov             t0, t6m
+    mov             t1, t5m
+    paddw           m3, m4, [t0+wq]
+    paddw           m4, [t1+wq]
+%endif
+    punpcklwd       m0, m1, m2
+    pmaddwd         m0, m15
+    punpckhwd       m1, m2
+    pmaddwd         m1, m15
+    punpcklwd       m2, m3, m4
+    pmaddwd         m2, m14
+    punpckhwd       m3, m4
+    pmaddwd         m3, m14
+    paddd           m0, m10
+    paddd           m1, m10
+    paddd           m0, m2
+    paddd           m1, m3
+    psrad           m0, 6
+    psrad           m1, 6
+    packssdw        m0, m1
+    pmulhw          m0, m11
+    pxor            m1, m1
+    pmaxsw          m0, m1
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .v_loop
+%if ARCH_X86_64
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+%else
+    mov             t0, t5m
+    mov             t1, t4m
+    mov             r4, t3m
+    mov            t6m, t0
+    mov            t5m, t1
+    mov            t4m, r4
+    mov             r4, t2m
+    mov             t1, t1m
+    mov             t0, t0m
+    mov            t3m, r4
+    mov            t2m, t1
+%endif
+    add           dstq, strideq
+    ret
+
+%if ARCH_X86_32
+ %if STACK_ALIGNMENT < 16
+  %assign stack_size 12*16+384*8
+ %else
+  %assign stack_size 11*16+384*8
+ %endif
+cglobal wiener_filter5_16bpc, 4, 7, 8, -stack_size, dst, stride, left, \
+                                                    lpf, w, flt
+ %if STACK_ALIGNMENT < 16
+  %define lpfm        dword [esp+calloff+4*6]
+  %define wm          dword [esp+calloff+4*7]
+  %define hd          dword [esp+calloff+16*10+0]
+  %define edgeb        byte [esp+calloff+16*10+4]
+  %define edged       dword [esp+calloff+16*10+4]
+ %else
+  %define hd dword r5m
+  %define edgeb byte r7m
+ %endif
+ %define PICmem dword [esp+calloff+4*0]
+ %define t0m    dword [esp+calloff+4*1] ; wiener ring buffer pointers
+ %define t1m    dword [esp+calloff+4*2]
+ %define t2m    dword [esp+calloff+4*3]
+ %define t3m    dword [esp+calloff+4*4]
+ %define t4m    dword [esp+calloff+4*5]
+ %define t2 t2m
+ %define t3 t3m
+ %define t4 t4m
+ %define  m8 [esp+calloff+16*2]
+ %define  m9 [esp+calloff+16*3]
+ %define m10 [esp+calloff+16*4]
+ %define m11 [esp+calloff+16*5]
+ %define m12 [esp+calloff+16*6]
+ %define m13 [esp+calloff+16*7]
+ %define m14 [esp+calloff+16*8]
+ %define m15 [esp+calloff+16*9]
+ %define base t0-wiener_shifts
+ %assign calloff 0
+ %if STACK_ALIGNMENT < 16
+    mov             wd, [rstk+stack_offset+20]
+    mov             wm, wd
+    mov             r5, [rstk+stack_offset+24]
+    mov             hd, r5
+    mov             r5, [rstk+stack_offset+32]
+    mov          edged, r5 ; edge
+ %endif
+%else
+cglobal wiener_filter5_16bpc, 4, 14, 16, 384*8+16, dst, stride, left, lpf, \
+                                                   w, h, edge, flt
+ %define base
+%endif
+%if ARCH_X86_64 || STACK_ALIGNMENT >= 16
+    movifnidn       wd, wm
+%endif
+%if ARCH_X86_64
+    mov           fltq, r6mp
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mov            t3d, r8m ; pixel_max
+    movq           m12, [fltq]
+    movq           m14, [fltq+16]
+%else
+ %if STACK_ALIGNMENT < 16
+    mov             t0, [rstk+stack_offset+28]
+    mov             t1, [rstk+stack_offset+36] ; pixel_max
+    movq            m1, [t0]    ; fx
+    movq            m3, [t0+16] ; fy
+    LEA             t0, wiener_shifts
+ %else
+    mov           fltq, r6m
+    movq            m1, [fltq]
+    movq            m3, [fltq+16]
+    LEA             t0, wiener_shifts
+    mov             t1, r8m ; pixel_max
+ %endif
+    mov         PICmem, t0
+%endif
+    mova            m5, [base+wiener_shufE]
+    mova            m6, [base+wiener_shufB]
+    mova            m7, [base+wiener_shufD]
+%if ARCH_X86_64
+    lea             t4, [wiener_shifts]
+    add             wd, wd
+    punpcklwd      m11, m12, m12
+    pshufd         m11, m11, q1111 ; x1
+    pshufd         m12, m12, q1111 ; x2 x3
+    punpcklwd      m13, m14, m14
+    pshufd         m13, m13, q1111 ; y1
+    pshufd         m14, m14, q1111 ; y2 y3
+    shr            t3d, 11
+    mova            m8, [pd_m262128] ; (1 << 4) - (1 << 18)
+    add           lpfq, wq
+    lea             t1, [rsp+wq+16]
+    add           dstq, wq
+    neg             wq
+ %define base t4-wiener_shifts
+    movd            m9, [base+wiener_round+t3*4]
+    movq           m10, [base+wiener_shifts+t3*8]
+    pshufd          m9, m9, q0000
+    pshufd          m0, m10, q0000
+    pshufd         m10, m10, q1111
+    mova           m15, [wiener_lshuf5]
+    pmullw         m11, m0
+    pmullw         m12, m0
+ DEFINE_ARGS dst, stride, left, lpf, _, h, edge, _, _, _, w
+ %define lpfm [rsp]
+ %define base
+%else
+    add             wd, wd
+    punpcklwd       m0, m1, m1
+    pshufd          m0, m0, q1111 ; x1
+    pshufd          m1, m1, q1111 ; x2 x3
+    punpcklwd       m2, m3, m3
+    pshufd          m2, m2, q1111 ; y1
+    pshufd          m3, m3, q1111 ; y2 y3
+    mova            m4, [base+pd_m262128] ; (1 << 4) - (1 << 18)
+    mova           m13, m2
+    mova           m14, m3
+    mova            m8, m4
+    shr             t1, 11
+    add           lpfq, wq
+    movd            m2, [base+wiener_round+t1*4]
+    movq            m3, [base+wiener_shifts+t1*8]
+ %if STACK_ALIGNMENT < 16
+    lea             t1, [esp+16*11+wq+16]
+ %else
+    lea             t1, [esp+16*10+wq+16]
+ %endif
+    add           dstq, wq
+    neg             wq
+    pshufd          m2, m2, q0000
+    pshufd          m4, m3, q0000
+    pshufd          m3, m3, q1111
+    mov             wm, wq
+    pmullw          m0, m4
+    pmullw          m1, m4
+    mova            m4, [base+wiener_lshuf5]
+    mova            m9, m2
+    mova           m10, m3
+    mova           m11, m0
+    mova           m12, m1
+    mova           m15, m4
+%endif
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t4, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t3, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov           lpfm, r10 ; below
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+.main:
+    mov             t0, t4
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v2
+    mov           lpfq, lpfm
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov           lpfm, r10
+    call .h
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v2
+    add             t0, 384*6
+    call .hv
+    dec             hd
+    jnz .main
+.v2:
+    call .v
+%if ARCH_X86_64
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+%else
+    mov             t0, t3m
+    mov             r4, t2m
+    mov             t1, t1m
+    mov            t4m, t0
+    mov            t3m, r4
+    mov            t2m, t1
+    mov             wq, wm
+%endif
+    add           dstq, strideq
+.v1:
+    call .v
+    jmp .end
+.extend_right:
+%assign stack_offset stack_offset+8
+%assign calloff 8
+    movif32         t0, PICmem
+    pxor            m1, m1
+    movd            m2, wd
+    mova            m0, [base+pb_2_3]
+    pshufb          m2, m1
+    mova            m1, [base+pb_m6_m5]
+    psubb           m0, m2
+    psubb           m1, m2
+    mova            m2, [base+pb_0to15]
+    pminub          m0, m2
+    pminub          m1, m2
+    pshufb          m3, m0
+    pshufb          m4, m1
+    ret
+%assign stack_offset stack_offset-4
+%assign calloff 4
+.h:
+    movif64         wq, r4
+    movif32         wq, wm
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    mova            m4, [lpfq+wq]
+    movd            m3, [leftq+4]
+    pslldq          m4, 4
+    por             m3, m4
+    add          leftq, 8
+    jmp .h_main
+.h_extend_left:
+    mova            m3, [lpfq+wq] ; avoid accessing memory located
+    pshufb          m3, m15       ; before the start of the buffer
+    jmp .h_main
+.h_top:
+    movif64         wq, r4
+    movif32         wq, wm
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m3, [lpfq+wq-4]
+.h_main:
+    movu            m4, [lpfq+wq+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             wd, -18
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    pshufb          m0, m3, m5
+    pmaddwd         m0, m11
+    pshufb          m1, m4, m5
+    pmaddwd         m1, m11
+    pshufb          m2, m3, m6
+    pshufb          m3, m7
+    paddw           m2, m3
+    pshufb          m3, m4, m6
+    pmaddwd         m2, m12
+    pshufb          m4, m7
+    paddw           m3, m4
+    pmaddwd         m3, m12
+    paddd           m0, m8
+    paddd           m1, m8
+    paddd           m0, m2
+    paddd           m1, m3
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    psraw           m0, 1
+    mova       [t1+wq], m0
+    add             wq, 16
+    jl .h_loop
+    movif32         wq, wm
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    movif64         wq, r4
+    movif32        t0m, t0
+    movif32        t1m, t1
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    mova            m4, [lpfq+wq]
+    movd            m3, [leftq+4]
+    pslldq          m4, 4
+    por             m3, m4
+    add          leftq, 8
+    jmp .hv_main
+.hv_extend_left:
+    mova            m3, [lpfq+wq]
+    pshufb          m3, m15
+    jmp .hv_main
+.hv_bottom:
+    movif64         wq, r4
+    movif32        t0m, t0
+    movif32        t1m, t1
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m3, [lpfq+wq-4]
+.hv_main:
+    movu            m4, [lpfq+wq+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp             wd, -18
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    movif32         t1, t1m
+    movif32         t0, t3m
+    pshufb          m0, m3, m5
+    pmaddwd         m0, m11
+    pshufb          m1, m4, m5
+    pmaddwd         m1, m11
+    pshufb          m2, m3, m6
+    pshufb          m3, m7
+    paddw           m2, m3
+    pshufb          m3, m4, m6
+    pmaddwd         m2, m12
+    pshufb          m4, m7
+    paddw           m3, m4
+    pmaddwd         m3, m12
+    paddd           m0, m8
+    paddd           m1, m8
+    paddd           m0, m2
+%if ARCH_X86_64
+    mova            m2, [t3+wq]
+    paddw           m2, [t1+wq]
+    paddd           m1, m3
+    mova            m4, [t2+wq]
+%else
+    mova            m2, [t0+wq]
+    mov             t0, t2m
+    paddw           m2, [t1+wq]
+    mov             t1, t4m
+    paddd           m1, m3
+    mova            m4, [t0+wq]
+    mov             t0, t0m
+%endif
+    punpckhwd       m3, m2, m4
+    pmaddwd         m3, m14
+    punpcklwd       m2, m4
+%if ARCH_X86_64
+    mova            m4, [t4+wq]
+%else
+    mova            m4, [t1+wq]
+%endif
+    psrad           m0, 4
+    psrad           m1, 4
+    packssdw        m0, m1
+    pmaddwd         m2, m14
+    psraw           m0, 1
+    mova       [t0+wq], m0
+    punpckhwd       m1, m0, m4
+    pmaddwd         m1, m13
+    punpcklwd       m0, m4
+    pmaddwd         m0, m13
+    paddd           m3, m9
+    paddd           m2, m9
+    paddd           m1, m3
+    paddd           m0, m2
+    psrad           m1, 6
+    psrad           m0, 6
+    packssdw        m0, m1
+    pmulhw          m0, m10
+    pxor            m1, m1
+    pmaxsw          m0, m1
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .hv_loop
+%if ARCH_X86_64
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t4
+%else
+    mov             r4, t3m
+    mov             t1, t2m
+    mov            t4m, r4
+    mov            t3m, t1
+    mov             r4, t1m
+    mov             t1, t0
+    mov            t2m, r4
+    mov             t0, t4m
+    mov             wq, wm
+%endif
+    add           dstq, strideq
+    ret
+.v:
+    movif64         wq, r4
+    movif32        t1m, t1
+.v_loop:
+%if ARCH_X86_64
+    mova            m0, [t1+wq]
+    paddw           m2, m0, [t3+wq]
+    mova            m1, [t2+wq]
+    mova            m4, [t4+wq]
+%else
+    mov             t0, t3m
+    mova            m0, [t1+wq]
+    mov             t1, t2m
+    paddw           m2, m0, [t0+wq]
+    mov             t0, t4m
+    mova            m1, [t1+wq]
+    mova            m4, [t0+wq]
+%endif
+    punpckhwd       m3, m2, m1
+    pmaddwd         m3, m14
+    punpcklwd       m2, m1
+    pmaddwd         m2, m14
+    punpckhwd       m1, m0, m4
+    pmaddwd         m1, m13
+    punpcklwd       m0, m4
+    pmaddwd         m0, m13
+    paddd           m3, m9
+    paddd           m2, m9
+    paddd           m1, m3
+    paddd           m0, m2
+    psrad           m1, 6
+    psrad           m0, 6
+    packssdw        m0, m1
+    pmulhw          m0, m10
+    pxor            m1, m1
+    pmaxsw          m0, m1
+    mova     [dstq+wq], m0
+    add             wq, 16
+%if ARCH_X86_64
+    jl .v_loop
+%else
+    jge .v_end
+    mov             t1, t1m
+    jmp .v_loop
+.v_end:
+%endif
+    ret
+
+%macro MUL_32X16X2 6 ; dst[1-2], src[1-2], tmp[1-2]
+    pmulhuw         %5, %1, %3
+    pmulhuw         %6, %2, %4
+    pmullw          %1, %3
+    pmullw          %2, %4
+    pslld           %5, 16
+    pslld           %6, 16
+    paddd           %1, %5
+    paddd           %2, %6
+%endmacro
+
+%macro SGR_CALC_X 10 ; BB_dst, BB_src, b, tmp, an[1-2], zero, s, b_mul, pf_256
+    punpcklwd       %4, %3, %7
+    punpckhwd       %3, %7
+    pmaddwd         %4, %4                 ; b * b
+    pmaddwd         %3, %3
+    punpcklwd       %1, %2, %7             ; BB
+    punpckhwd       %2, %7
+    psubd           %5, %4                 ; a * n - b * b
+    psubd           %6, %3
+    pcmpgtd         %4, %5, %7
+    pcmpgtd         %3, %6, %7
+    pand            %5, %4                 ; p
+    pand            %6, %3
+    MUL_32X16X2     %5, %6, %8, %8, %4, %3 ; p * s
+    paddw           %5, %9
+    paddw           %6, %9
+    psrld           %5, 20                 ; z + 1
+    psrld           %6, 20
+    cvtdq2ps        %5, %5
+    cvtdq2ps        %6, %6
+    pmaddwd         %1, %9                 ; BB * 164
+    pmaddwd         %2, %9
+    rcpps           %3, %5                 ; 1 / (z + 1)
+    rcpps           %4, %6
+    cmpltps         %5, %10
+    cmpltps         %6, %10
+    mulps           %3, %10                ; 256 / (z + 1)
+    mulps           %4, %10
+    packssdw        %5, %6
+    cvtps2dq        %3, %3
+    cvtps2dq        %4, %4
+    psrlw           %5, 8                  ; z < 255 ? 255 : 0
+    packssdw        %3, %4
+    pminsw          %3, %5                 ; x
+%endmacro
+
+%if ARCH_X86_32
+DECLARE_REG_TMP 0, 1, 2, 3, 5
+ %if STACK_ALIGNMENT < 16
+  %assign extra_stack 5*16
+ %else
+  %assign extra_stack 3*16
+ %endif
+cglobal sgr_filter_5x5_16bpc, 1, 7, 8, -400*24-16-extra_stack, \
+                              dst, stride, left, lpf, w
+ %if STACK_ALIGNMENT < 16
+  %define dstm         dword [esp+calloff+16*0+4*6]
+  %define stridemp     dword [esp+calloff+16*0+4*7]
+  %define leftm        dword [esp+calloff+16*3+4*0]
+  %define lpfm         dword [esp+calloff+16*3+4*1]
+  %define w0m          dword [esp+calloff+16*3+4*2]
+  %define hd           dword [esp+calloff+16*3+4*3]
+  %define edgeb         byte [esp+calloff+16*3+4*4]
+  %define edged        dword [esp+calloff+16*3+4*4]
+  %define leftmp leftm
+ %else
+  %define w0m wm
+  %define hd dword r5m
+  %define edgeb  byte r7m
+  %define edged dword r7m
+ %endif
+ %define hvsrcm dword [esp+calloff+4*0]
+ %define w1m    dword [esp+calloff+4*1]
+ %define t0m    dword [esp+calloff+4*2]
+ %define t2m    dword [esp+calloff+4*3]
+ %define t3m    dword [esp+calloff+4*4]
+ %define t4m    dword [esp+calloff+4*5]
+ %define  m8 [base+pd_8]
+ %define  m9 [base+pd_0xfffffff0]
+ %define m10 [esp+calloff+16*2]
+ %define m11 [base+pw_164_24]
+ %define m12 [base+sgr_lshuf5]
+ %define m13 [base+pd_34816]
+ %define m14 [base+pw_1023]
+ %define m15 [base+pf_256]
+ %define r10 r4
+ %define base r6-pw_455_24
+ %assign calloff 0
+ %if STACK_ALIGNMENT < 16
+    mov        strideq, [rstk+stack_offset+ 8]
+    mov          leftq, [rstk+stack_offset+12]
+    mov           lpfq, [rstk+stack_offset+16]
+    mov             wd, [rstk+stack_offset+20]
+    mov           dstm, dstq
+    mov       stridemp, strideq
+    mov          leftm, leftq
+    mov             r1, [rstk+stack_offset+24]
+    mov             r2, [rstk+stack_offset+32]
+    mov           lpfm, lpfq
+    mov             hd, r1
+    mov          edged, r2
+ %endif
+%else
+cglobal sgr_filter_5x5_16bpc, 4, 13, 16, -400*24-16, dst, stride, left, lpf, \
+                                                     w, h, edge, params
+%endif
+%if ARCH_X86_64 || STACK_ALIGNMENT >= 16
+    movifnidn       wd, wm
+%endif
+%if ARCH_X86_64
+    mov        paramsq, r6mp
+    movifnidn       hd, hm
+    add             wd, wd
+    mov          edged, r7m
+    movu           m10, [paramsq]
+    mova           m12, [sgr_lshuf5]
+    add           lpfq, wq
+    mova            m8, [pd_8]
+    lea             t1, [rsp+wq+20]
+    mova            m9, [pd_0xfffffff0]
+    add           dstq, wq
+    lea             t3, [rsp+wq*2+400*12+16]
+    mova           m11, [pw_164_24]
+    lea             t4, [rsp+wq+400*20+16]
+    pshufhw         m7, m10, q0000
+    pshufb         m10, [pw_256]  ; s0
+    punpckhqdq      m7, m7        ; w0
+    neg             wq
+    mova           m13, [pd_34816]  ; (1 << 11) + (1 << 15)
+    pxor            m6, m6
+    mova           m14, [pw_1023]
+    psllw           m7, 4
+    movaps         m15, [pf_256]
+ DEFINE_ARGS dst, stride, left, lpf, _, h, edge, _, _, _, w
+ %define lpfm        [rsp]
+%else
+    mov             r1, [rstk+stack_offset+28] ; params
+    LEA             r6, pw_455_24
+    add             wd, wd
+    movu            m1, [r1]
+    add           lpfm, wq
+    lea             t1, [rsp+extra_stack+wq+20]
+    add           dstq, wq
+    lea             t3, [rsp+extra_stack+wq*2+400*12+16]
+    mov           dstm, dstq
+    lea             t4, [rsp+extra_stack+wq+400*20+16]
+    mov            t3m, t3
+    pshufhw         m7, m1, q0000
+    mov            t4m, t4
+    pshufb          m1, [base+pw_256] ; s0
+    punpckhqdq      m7, m7            ; w0
+    psllw           m7, 4
+    neg             wq
+    mova           m10, m1
+    pxor            m6, m6
+    mov            w1m, wd
+    sub             wd, 4
+    mov           lpfq, lpfm
+    mov            w0m, wd
+ %define strideq r5
+%endif
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, stridemp
+    mov             t2, t1
+    call .top_fixup
+    add             t1, 400*6
+    call .h_top
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov           lpfm, r10 ; below
+    movif32        t0m, t2
+    mov             t0, t2
+    dec             hd
+    jz .height1
+    or           edged, 16
+    call .h
+.main:
+    add           lpfq, stridemp
+    movif32         t4, t4m
+    call .hv
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+%if ARCH_X86_64
+    test            hb, hb
+%else
+    mov             r4, hd
+    test            r4, r4
+%endif
+    jz .odd_height
+    call .h
+    add           lpfq, stridemp
+    call .hv
+    movif32       dstq, dstm
+    call .n0
+    call .n1
+    sub             hd, 2
+    movif32         t0, t0m
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, lpfm
+    call .h_top
+    add           lpfq, stridemp
+    call .hv_bottom
+.end:
+    movif32       dstq, dstm
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    movif32         t4, t4m
+    call .hv
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .hv
+    movif32       dstq, dstm
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v
+    movif32       dstq, dstm
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v
+    jmp .end
+.no_top:
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov           lpfm, r10
+    call .h
+    lea             t2, [t1+400*6]
+    call .top_fixup
+    dec             hd
+    jz .no_top_height1
+    or           edged, 16
+    mov             t0, t1
+    mov             t1, t2
+    movif32        t0m, t0
+    jmp .main
+.no_top_height1:
+    movif32         t3, t3m
+    movif32         t4, t4m
+    call .v
+    call .prep_n
+    jmp .odd_height_end
+.extend_right:
+    movd            m0, wd
+    movd            m1, [lpfq-2]
+    mova            m2, [base+pw_256]
+    mova            m3, [base+pb_m14_m13]
+    pshufb          m0, m6
+    pshufb          m1, m2
+    psubb           m2, m0
+    psubb           m3, m0
+    mova            m0, [base+pb_0to15]
+    pcmpgtb         m2, m0
+    pcmpgtb         m3, m0
+    pand            m4, m2
+    pand            m5, m3
+    pandn           m2, m1
+    pandn           m3, m1
+    por             m4, m2
+    por             m5, m3
+    ret
+%assign stack_offset stack_offset+4
+%assign calloff 4
+.h: ; horizontal boxsum
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+ %define leftq r4
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32      leftq, leftm
+    movddup         m5, [leftq]
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    add         leftmp, 8
+    palignr         m4, m5, 10
+    jmp .h_main
+.h_extend_left:
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    pshufb          m4, m12
+    jmp .h_main
+.h_top:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32         wq, w0m
+.h_loop:
+    movu            m4, [lpfq+wq- 2]
+.h_main:
+    movu            m5, [lpfq+wq+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             wd, -20
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    palignr         m2, m5, m4, 2
+    paddw           m0, m4, m2
+    palignr         m3, m5, m4, 6
+    paddw           m0, m3
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m1
+    punpckhwd       m2, m3
+    pmaddwd         m2, m2
+    palignr         m5, m4, 8
+    paddw           m0, m5
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m3
+    paddd           m1, m3
+    punpckhwd       m3, m4, m5
+    pmaddwd         m3, m3
+    shufps          m4, m5, q2121
+    paddw           m0, m4             ; sum
+    punpcklwd       m5, m4, m6
+    pmaddwd         m5, m5
+    punpckhwd       m4, m6
+    pmaddwd         m4, m4
+    paddd           m2, m3
+    test         edgeb, 16             ; y > 0
+    jz .h_loop_end
+    paddw           m0, [t1+wq+400*0]
+    paddd           m1, [t1+wq+400*2]
+    paddd           m2, [t1+wq+400*4]
+.h_loop_end:
+    paddd           m1, m5             ; sumsq
+    paddd           m2, m4
+    mova [t1+wq+400*0], m0
+    mova [t1+wq+400*2], m1
+    mova [t1+wq+400*4], m2
+    add             wq, 16
+    jl .h_loop
+    ret
+.top_fixup:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov             wd, w0m
+%endif
+.top_fixup_loop: ; the sums of the first row needs to be doubled
+    mova            m0, [t1+wq+400*0]
+    mova            m1, [t1+wq+400*2]
+    mova            m2, [t1+wq+400*4]
+    paddw           m0, m0
+    paddd           m1, m1
+    paddd           m2, m2
+    mova [t2+wq+400*0], m0
+    mova [t2+wq+400*2], m1
+    mova [t2+wq+400*4], m2
+    add             wq, 16
+    jl .top_fixup_loop
+    ret
+ALIGN function_align
+.hv: ; horizontal boxsum + vertical boxsum + ab
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movif32      leftq, leftm
+    movddup         m5, [leftq]
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    add         leftmp, 8
+    palignr         m4, m5, 10
+    jmp .hv_main
+.hv_extend_left:
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    pshufb          m4, m12
+    jmp .hv_main
+.hv_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv_loop_start
+%endif
+.hv_loop:
+    movif32       lpfq, hvsrcm
+.hv_loop_start:
+    movu            m4, [lpfq+wq- 2]
+.hv_main:
+    movu            m5, [lpfq+wq+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp             wd, -20
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    movif32         t3, hd
+    palignr         m3, m5, m4, 2
+    paddw           m0, m4, m3
+    palignr         m1, m5, m4, 6
+    paddw           m0, m1
+    punpcklwd       m2, m3, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m1
+    pmaddwd         m3, m3
+    palignr         m5, m4, 8
+    paddw           m0, m5
+    punpcklwd       m1, m4, m5
+    pmaddwd         m1, m1
+    paddd           m2, m1
+    punpckhwd       m1, m4, m5
+    pmaddwd         m1, m1
+    shufps          m4, m5, q2121
+    paddw           m0, m4            ; h sum
+    punpcklwd       m5, m4, m6
+    pmaddwd         m5, m5
+    punpckhwd       m4, m6
+    pmaddwd         m4, m4
+    paddd           m3, m1
+    paddd           m2, m5            ; h sumsq
+    paddd           m3, m4
+    paddw           m1, m0, [t1+wq+400*0]
+    paddd           m4, m2, [t1+wq+400*2]
+    paddd           m5, m3, [t1+wq+400*4]
+%if ARCH_X86_64
+    test            hd, hd
+%else
+    test            t3, t3
+%endif
+    jz .hv_last_row
+.hv_main2:
+    paddw           m1, [t2+wq+400*0] ; hv sum
+    paddd           m4, [t2+wq+400*2] ; hv sumsq
+    paddd           m5, [t2+wq+400*4]
+    mova [t0+wq+400*0], m0
+    mova [t0+wq+400*2], m2
+    mova [t0+wq+400*4], m3
+    psrlw           m3, m1, 1
+    paddd           m4, m8
+    pavgw           m3, m6             ; (b + 2) >> 2
+    paddd           m5, m8
+    pand            m4, m9             ; ((a + 8) >> 4) << 4
+    pand            m5, m9
+    psrld           m2, m4, 4
+    psrld           m0, m5, 4
+    paddd           m2, m4
+    psrld           m4, 1
+    paddd           m0, m5
+    psrld           m5, 1
+    paddd           m4, m2             ; a * 25
+    paddd           m5, m0
+    movif32         t3, t3m
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m10, m11, m15
+    punpcklwd       m2, m3, m3
+    mova     [t4+wq+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m13            ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m13
+    psrld           m0, 12             ; b
+    psrld           m1, 12
+    mova  [t3+wq*2+ 8], m0
+    mova  [t3+wq*2+24], m1
+    add             wq, 16
+    jl .hv_loop
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t2
+    movif32        t0m, t0
+    ret
+.hv_last_row: ; esoteric edge case for odd heights
+    mova [t1+wq+400*0], m1
+    paddw           m1, m0
+    mova [t1+wq+400*2], m4
+    paddd           m4, m2
+    mova [t1+wq+400*4], m5
+    paddd           m5, m3
+    jmp .hv_main2
+.v: ; vertical boxsum + ab
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov             wd, w0m
+%endif
+.v_loop:
+    mova            m0, [t1+wq+400*0]
+    mova            m2, [t1+wq+400*2]
+    mova            m3, [t1+wq+400*4]
+    paddw           m1, m0, [t2+wq+400*0]
+    paddd           m4, m2, [t2+wq+400*2]
+    paddd           m5, m3, [t2+wq+400*4]
+    paddw           m0, m0
+    paddd           m2, m2
+    paddd           m3, m3
+    paddw           m1, m0             ; hv sum
+    paddd           m4, m2             ; hv sumsq
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    paddd           m4, m8
+    pavgw           m3, m6             ; (b + 2) >> 2
+    paddd           m5, m8
+    pand            m4, m9             ; ((a + 8) >> 4) << 4
+    pand            m5, m9
+    psrld           m2, m4, 4
+    psrld           m0, m5, 4
+    paddd           m2, m4
+    psrld           m4, 1
+    paddd           m0, m5
+    psrld           m5, 1
+    paddd           m4, m2             ; a * 25
+    paddd           m5, m0
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m10, m11, m15
+    punpcklwd       m2, m3, m3
+    mova     [t4+wq+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m13            ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m13
+    psrld           m0, 12             ; b
+    psrld           m1, 12
+    mova  [t3+wq*2+ 8], m0
+    mova  [t3+wq*2+24], m1
+    add             wq, 16
+    jl .v_loop
+    ret
+.prep_n: ; initial neighbor setup
+    movif64         wq, r4
+    movif32         wd, w1m
+.prep_n_loop:
+    movu            m0, [t4+wq*1+ 2]
+    movu            m3, [t4+wq*1+ 4]
+    movu            m1, [t3+wq*2+ 4]
+    movu            m4, [t3+wq*2+ 8]
+    movu            m2, [t3+wq*2+20]
+    movu            m5, [t3+wq*2+24]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    paddw           m3, [t4+wq*1+ 0]
+    paddd           m4, [t3+wq*2+ 0]
+    paddd           m5, [t3+wq*2+16]
+    paddw           m0, m3
+    psllw           m3, 2
+    paddd           m1, m4
+    pslld           m4, 2
+    paddd           m2, m5
+    pslld           m5, 2
+    paddw           m0, m3             ; a 565
+    paddd           m1, m4             ; b 565
+    paddd           m2, m5
+    mova [t4+wq*1+400*2+ 0], m0
+    mova [t3+wq*2+400*4+ 0], m1
+    mova [t3+wq*2+400*4+16], m2
+    add             wq, 16
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n0_loop:
+    movu            m0, [t4+wq*1+ 2]
+    movu            m3, [t4+wq*1+ 4]
+    movu            m1, [t3+wq*2+ 4]
+    movu            m4, [t3+wq*2+ 8]
+    movu            m2, [t3+wq*2+20]
+    movu            m5, [t3+wq*2+24]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    paddw           m3, [t4+wq*1+ 0]
+    paddd           m4, [t3+wq*2+ 0]
+    paddd           m5, [t3+wq*2+16]
+    paddw           m0, m3
+    psllw           m3, 2
+    paddd           m1, m4
+    pslld           m4, 2
+    paddd           m2, m5
+    pslld           m5, 2
+    paddw           m0, m3             ; a 565
+    paddd           m1, m4             ; b 565
+    paddd           m2, m5
+    paddw           m3, m0, [t4+wq*1+400*2+ 0]
+    paddd           m4, m1, [t3+wq*2+400*4+ 0]
+    paddd           m5, m2, [t3+wq*2+400*4+16]
+    mova [t4+wq*1+400*2+ 0], m0
+    mova [t3+wq*2+400*4+ 0], m1
+    mova [t3+wq*2+400*4+16], m2
+    mova            m0, [dstq+wq]
+    punpcklwd       m1, m0, m6          ; src
+    punpcklwd       m2, m3, m6          ; a
+    pmaddwd         m2, m1              ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    psubd           m4, m2              ; b - a * src + (1 << 8)
+    psubd           m5, m3
+    psrad           m4, 9
+    psrad           m5, 9
+    packssdw        m4, m5
+    pmulhrsw        m4, m7
+    paddw           m0, m4
+    pmaxsw          m0, m6
+    pminsw          m0, m14
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .n0_loop
+    add           dstq, stridemp
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n1_loop:
+    mova            m0, [dstq+wq]
+    mova            m3, [t4+wq*1+400*2+ 0]
+    mova            m4, [t3+wq*2+400*4+ 0]
+    mova            m5, [t3+wq*2+400*4+16]
+    punpcklwd       m1, m0, m6          ; src
+    punpcklwd       m2, m3, m6          ; a
+    pmaddwd         m2, m1
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    psubd           m4, m2              ; b - a * src + (1 << 7)
+    psubd           m5, m3
+    psrad           m4, 8
+    psrad           m5, 8
+    packssdw        m4, m5
+    pmulhrsw        m4, m7
+    paddw           m0, m4
+    pmaxsw          m0, m6
+    pminsw          m0, m14
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .n1_loop
+    add           dstq, stridemp
+    movif32       dstm, dstq
+    ret
+
+%if ARCH_X86_32
+ %if STACK_ALIGNMENT < 16
+  %assign extra_stack 4*16
+ %else
+  %assign extra_stack 2*16
+ %endif
+cglobal sgr_filter_3x3_16bpc, 1, 7, 8, -400*42-16-extra_stack, \
+                              dst, stride, left, lpf, w
+ %if STACK_ALIGNMENT < 16
+  %define dstm         dword [esp+calloff+16*2+4*0]
+  %define stridemp     dword [esp+calloff+16*2+4*1]
+  %define leftm        dword [esp+calloff+16*2+4*2]
+  %define lpfm         dword [esp+calloff+16*2+4*3]
+  %define w0m          dword [esp+calloff+16*2+4*4]
+  %define hd           dword [esp+calloff+16*2+4*5]
+  %define edgeb         byte [esp+calloff+16*2+4*6]
+  %define edged        dword [esp+calloff+16*2+4*6]
+  %define leftmp leftm
+ %else
+  %define w0m wm
+  %define hd dword r5m
+  %define edgeb  byte r7m
+  %define edged dword r7m
+ %endif
+ %define hvsrcm dword [esp+calloff+4*0]
+ %define w1m    dword [esp+calloff+4*1]
+ %define t3m    dword [esp+calloff+4*2]
+ %define t4m    dword [esp+calloff+4*3]
+ %define  m8 [base+pd_8]
+ %define  m9 [esp+calloff+16*1]
+ %define m10 [base+pw_455_24]
+ %define m11 [base+pd_34816]
+ %define m12 [base+sgr_lshuf3]
+ %define m13 [base+pw_1023]
+ %define m14 [base+pf_256]
+ %define base r6-pw_455_24
+ %assign calloff 0
+ %if STACK_ALIGNMENT < 16
+    mov        strideq, [rstk+stack_offset+ 8]
+    mov          leftq, [rstk+stack_offset+12]
+    mov           lpfq, [rstk+stack_offset+16]
+    mov             wd, [rstk+stack_offset+20]
+    mov           dstm, dstq
+    mov       stridemp, strideq
+    mov          leftm, leftq
+    mov             r1, [rstk+stack_offset+24]
+    mov             r2, [rstk+stack_offset+32]
+    mov           lpfm, lpfq
+    mov             hd, r1
+    mov          edged, r2
+ %endif
+%else
+cglobal sgr_filter_3x3_16bpc, 4, 13, 15, -400*42-8, dst, stride, left, lpf, \
+                                                    w, h, edge, params
+%endif
+%if ARCH_X86_64 || STACK_ALIGNMENT >= 16
+    movifnidn       wd, wm
+%endif
+%if ARCH_X86_64
+    mov        paramsq, r6mp
+    movifnidn       hd, hm
+    add             wd, wd
+    mov          edged, r7m
+    movq            m9, [paramsq+4]
+    add           lpfq, wq
+    lea             t1, [rsp+wq+12]
+    mova            m8, [pd_8]
+    add           dstq, wq
+    lea             t3, [rsp+wq*2+400*12+8]
+    mova           m10, [pw_455_24]
+    lea             t4, [rsp+wq+400*32+8]
+    mova           m11, [pd_34816]
+    pshuflw         m7, m9, q3333
+    pshufb          m9, [pw_256]  ; s1
+    punpcklqdq      m7, m7        ; w1
+    neg             wq
+    pxor            m6, m6
+    mova           m13, [pw_1023]
+    psllw           m7, 4
+    mova           m12, [sgr_lshuf3]
+    movaps         m14, [pf_256]
+ DEFINE_ARGS dst, stride, left, lpf, _, h, edge, _, _, _, w
+ %define lpfm [rsp]
+%else
+    mov             r1, [rstk+stack_offset+28] ; params
+    LEA             r6, pw_455_24
+    add             wd, wd
+    movq            m1, [r1+4]
+    add           lpfm, wq
+    lea             t1, [rsp+extra_stack+wq+20]
+    add           dstq, wq
+    lea             t3, [rsp+extra_stack+wq*2+400*12+16]
+    mov           dstm, dstq
+    lea             t4, [rsp+extra_stack+wq+400*32+16]
+    mov            t3m, t3
+    pshuflw         m7, m1, q3333
+    mov            t4m, t4
+    pshufb          m1, [base+pw_256] ; s1
+    punpcklqdq      m7, m7            ; w1
+    psllw           m7, 4
+    neg             wq
+    mova            m9, m1
+    pxor            m6, m6
+    mov            w1m, wd
+    sub             wd, 4
+    mov           lpfq, lpfm
+    mov            w0m, wd
+ %define strideq r5
+%endif
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, stridemp
+    mov             t2, t1
+    add             t1, 400*6
+    call .h_top
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov           lpfm, r10 ; below
+    movif32         t4, t4m
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv0
+%if ARCH_X86_64
+    test            hb, hb
+%else
+    mov             r4, hd
+    test            r4, r4
+%endif
+    jz .odd_height
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, lpfm
+    call .hv0_bottom
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov           lpfm, r10
+    call .h
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov             wq, w0m
+    mov         hvsrcm, lpfq
+%endif
+    lea             t2, [t1+400*6]
+.top_fixup_loop:
+    mova            m0, [t1+wq+400*0]
+    mova            m1, [t1+wq+400*2]
+    mova            m2, [t1+wq+400*4]
+    mova [t2+wq+400*0], m0
+    mova [t2+wq+400*2], m1
+    mova [t2+wq+400*4], m2
+    add             wq, 16
+    jl .top_fixup_loop
+    movif32         t3, t3m
+    movif32         t4, t4m
+    call .v0
+    jmp .main
+.extend_right:
+    movd            m1, wd
+    movd            m5, [lpfq-2]
+    mova            m2, [base+pw_256]
+    mova            m3, [base+pb_0to15]
+    pshufb          m1, m6
+    pshufb          m5, m2
+    psubb           m2, m1
+    pcmpgtb         m2, m3
+    pand            m4, m2
+    pandn           m2, m5
+    por             m4, m2
+    ret
+%assign stack_offset stack_offset+4
+%assign calloff 4
+.h: ; horizontal boxsum
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+ %define leftq r4
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32      leftq, leftm
+    movddup         m5, [leftq]
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    add         leftmp, 8
+    palignr         m4, m5, 12
+    jmp .h_main
+.h_extend_left:
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    pshufb          m4, m12
+    jmp .h_main
+.h_top:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32         wq, w0m
+.h_loop:
+    movu            m4, [lpfq+wq+ 0]
+.h_main:
+    movu            m5, [lpfq+wq+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             wd, -18
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    palignr         m0, m5, m4, 2
+    paddw           m1, m4, m0
+    punpcklwd       m2, m4, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m0
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m1, m5             ; sum
+    punpcklwd       m4, m5, m6
+    pmaddwd         m4, m4
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m4             ; sumsq
+    paddd           m3, m5
+    mova [t1+wq+400*0], m1
+    mova [t1+wq+400*2], m2
+    mova [t1+wq+400*4], m3
+    add             wq, 16
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsum + vertical boxsum + ab (even rows)
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movif32      leftq, leftm
+    movddup         m5, [leftq]
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    add         leftmp, 8
+    palignr         m4, m5, 12
+    jmp .hv0_main
+.hv0_extend_left:
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    pshufb          m4, m12
+    jmp .hv0_main
+.hv0_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv0_loop_start
+%endif
+.hv0_loop:
+    movif32       lpfq, hvsrcm
+.hv0_loop_start:
+    movu            m4, [lpfq+wq+ 0]
+.hv0_main:
+    movu            m5, [lpfq+wq+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp             wd, -18
+    jl .hv0_have_right
+    call .extend_right
+.hv0_have_right:
+    palignr         m0, m5, m4, 2
+    paddw           m1, m4, m0
+    punpcklwd       m2, m4, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m0
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m1, m5             ; sum
+    punpcklwd       m4, m5, m6
+    pmaddwd         m4, m4
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m4             ; sumsq
+    paddd           m3, m5
+    paddw           m0, m1, [t1+wq+400*0]
+    paddd           m4, m2, [t1+wq+400*2]
+    paddd           m5, m3, [t1+wq+400*4]
+    mova [t1+wq+400*0], m1
+    mova [t1+wq+400*2], m2
+    mova [t1+wq+400*4], m3
+    paddw           m1, m0, [t2+wq+400*0]
+    paddd           m2, m4, [t2+wq+400*2]
+    paddd           m3, m5, [t2+wq+400*4]
+    mova [t2+wq+400*0], m0
+    mova [t2+wq+400*2], m4
+    mova [t2+wq+400*4], m5
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    movif32         t3, t3m
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m9, m10, m14
+    punpcklwd       m2, m3, m3
+    mova     [t4+wq+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m11            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m11
+    psrld           m0, 12
+    psrld           m1, 12
+    mova  [t3+wq*2+ 8], m0
+    mova  [t3+wq*2+24], m1
+    add             wq, 16
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movif32      leftq, leftm
+    movddup         m5, [leftq]
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    add         leftmp, 8
+    palignr         m4, m5, 12
+    jmp .hv1_main
+.hv1_extend_left:
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    pshufb          m4, m12
+    jmp .hv1_main
+.hv1_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv1_loop_start
+%endif
+.hv1_loop:
+    movif32       lpfq, hvsrcm
+.hv1_loop_start:
+    movu            m4, [lpfq+wq+ 0]
+.hv1_main:
+    movu            m5, [lpfq+wq+16]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp             wd, -18
+    jl .hv1_have_right
+    call .extend_right
+.hv1_have_right:
+    palignr         m1, m5, m4, 2
+    paddw           m0, m4, m1
+    punpcklwd       m2, m4, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m1
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m0, m5             ; h sum
+    punpcklwd       m1, m5, m6
+    pmaddwd         m1, m1
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m1             ; h sumsq
+    paddd           m3, m5
+    paddw           m1, m0, [t2+wq+400*0]
+    paddd           m4, m2, [t2+wq+400*2]
+    paddd           m5, m3, [t2+wq+400*4]
+    mova [t2+wq+400*0], m0
+    mova [t2+wq+400*2], m2
+    mova [t2+wq+400*4], m3
+    paddd           m4, m8
+    paddd           m5, m8
+    psrld           m4, 4              ; (a + 8) >> 4
+    psrld           m5, 4
+    pslld           m2, m4, 3
+    pslld           m3, m5, 3
+    paddd           m4, m2             ; ((a + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    movif32         t3, t3m
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m9, m10, m14
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*1+400*2 +4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m11            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m11
+    psrld           m0, 12
+    psrld           m1, 12
+    mova [t3+wq*2+400*4+ 8], m0
+    mova [t3+wq*2+400*4+24], m1
+    add             wq, 16
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab (even rows)
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov             wd, w0m
+%endif
+.v0_loop:
+    mova            m0, [t1+wq+400*0]
+    mova            m4, [t1+wq+400*2]
+    mova            m5, [t1+wq+400*4]
+    paddw           m0, m0
+    paddd           m4, m4
+    paddd           m5, m5
+    paddw           m1, m0, [t2+wq+400*0]
+    paddd           m2, m4, [t2+wq+400*2]
+    paddd           m3, m5, [t2+wq+400*4]
+    mova [t2+wq+400*0], m0
+    mova [t2+wq+400*2], m4
+    mova [t2+wq+400*4], m5
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m9, m10, m14
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*1+400*0+ 4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m11            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m11
+    psrld           m0, 12
+    psrld           m1, 12
+    mova [t3+wq*2+400*0+ 8], m0
+    mova [t3+wq*2+400*0+24], m1
+    add             wq, 16
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov             wd, w0m
+%endif
+.v1_loop:
+    mova            m0, [t1+wq+400*0]
+    mova            m4, [t1+wq+400*2]
+    mova            m5, [t1+wq+400*4]
+    paddw           m1, m0, [t2+wq+400*0]
+    paddd           m2, m4, [t2+wq+400*2]
+    paddd           m3, m5, [t2+wq+400*4]
+    mova [t2+wq+400*0], m0
+    mova [t2+wq+400*2], m4
+    mova [t2+wq+400*4], m5
+    paddd           m2, m8
+    paddd           m3, m8
+    psrld           m2, 4              ; (a + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+    pavgw           m3, m6             ; (b + 2) >> 2
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m9, m10, m14
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*1+400*2+ 4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m11            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m11
+    psrld           m0, 12
+    psrld           m1, 12
+    mova [t3+wq*2+400*4+ 8], m0
+    mova [t3+wq*2+400*4+24], m1
+    add             wq, 16
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    movif64         wq, r4
+    movif32         wd, w1m
+.prep_n_loop:
+    movu            m0, [t4+wq*1+400*0+ 4]
+    movu            m1, [t3+wq*2+400*0+ 8]
+    movu            m2, [t3+wq*2+400*0+24]
+    movu            m3, [t4+wq*1+400*0+ 2]
+    movu            m4, [t3+wq*2+400*0+ 4]
+    movu            m5, [t3+wq*2+400*0+20]
+    paddw           m0, [t4+wq*1+400*0+ 0]
+    paddd           m1, [t3+wq*2+400*0+ 0]
+    paddd           m2, [t3+wq*2+400*0+16]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    psllw           m3, 2                ; a[-1] 444
+    pslld           m4, 2                ; b[-1] 444
+    pslld           m5, 2
+    psubw           m3, m0               ; a[-1] 343
+    psubd           m4, m1               ; b[-1] 343
+    psubd           m5, m2
+    mova [t4+wq*1+400*4], m3
+    mova [t3+wq*2+400*8+ 0], m4
+    mova [t3+wq*2+400*8+16], m5
+    movu            m0, [t4+wq*1+400*2+ 4]
+    movu            m1, [t3+wq*2+400*4+ 8]
+    movu            m2, [t3+wq*2+400*4+24]
+    movu            m3, [t4+wq*1+400*2+ 2]
+    movu            m4, [t3+wq*2+400*4+ 4]
+    movu            m5, [t3+wq*2+400*4+20]
+    paddw           m0, [t4+wq*1+400*2+ 0]
+    paddd           m1, [t3+wq*2+400*4+ 0]
+    paddd           m2, [t3+wq*2+400*4+16]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    psllw           m3, 2                 ; a[ 0] 444
+    pslld           m4, 2                 ; b[ 0] 444
+    pslld           m5, 2
+    mova [t4+wq*1+400* 6], m3
+    mova [t3+wq*2+400*12+ 0], m4
+    mova [t3+wq*2+400*12+16], m5
+    psubw           m3, m0                ; a[ 0] 343
+    psubd           m4, m1                ; b[ 0] 343
+    psubd           m5, m2
+    mova [t4+wq*1+400* 8], m3
+    mova [t3+wq*2+400*16+ 0], m4
+    mova [t3+wq*2+400*16+16], m5
+    add             wq, 16
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n0_loop:
+    movu            m3, [t4+wq*1+400*0+4]
+    movu            m1, [t4+wq*1+400*0+2]
+    paddw           m3, [t4+wq*1+400*0+0]
+    paddw           m1, m3
+    psllw           m1, 2                ; a[ 1] 444
+    psubw           m2, m1, m3           ; a[ 1] 343
+    paddw           m3, m2, [t4+wq*1+400*4]
+    paddw           m3, [t4+wq*1+400*6]
+    mova [t4+wq*1+400*4], m2
+    mova [t4+wq*1+400*6], m1
+    movu            m4, [t3+wq*2+400*0+8]
+    movu            m1, [t3+wq*2+400*0+4]
+    paddd           m4, [t3+wq*2+400*0+0]
+    paddd           m1, m4
+    pslld           m1, 2                ; b[ 1] 444
+    psubd           m2, m1, m4           ; b[ 1] 343
+    paddd           m4, m2, [t3+wq*2+400* 8+ 0]
+    paddd           m4, [t3+wq*2+400*12+ 0]
+    mova [t3+wq*2+400* 8+ 0], m2
+    mova [t3+wq*2+400*12+ 0], m1
+    movu            m5, [t3+wq*2+400*0+24]
+    movu            m1, [t3+wq*2+400*0+20]
+    paddd           m5, [t3+wq*2+400*0+16]
+    paddd           m1, m5
+    pslld           m1, 2
+    psubd           m2, m1, m5
+    paddd           m5, m2, [t3+wq*2+400* 8+16]
+    paddd           m5, [t3+wq*2+400*12+16]
+    mova [t3+wq*2+400* 8+16], m2
+    mova [t3+wq*2+400*12+16], m1
+    mova            m0, [dstq+wq]
+    punpcklwd       m1, m0, m6
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m1               ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    psubd           m4, m2               ; b - a * src + (1 << 8)
+    psubd           m5, m3
+    psrad           m4, 9
+    psrad           m5, 9
+    packssdw        m4, m5
+    pmulhrsw        m4, m7
+    paddw           m0, m4
+    pmaxsw          m0, m6
+    pminsw          m0, m13
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .n0_loop
+    add           dstq, stridemp
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n1_loop:
+    movu            m3, [t4+wq*1+400*2+4]
+    movu            m1, [t4+wq*1+400*2+2]
+    paddw           m3, [t4+wq*1+400*2+0]
+    paddw           m1, m3
+    psllw           m1, 2                ; a[ 1] 444
+    psubw           m2, m1, m3           ; a[ 1] 343
+    paddw           m3, m2, [t4+wq*1+400*6]
+    paddw           m3, [t4+wq*1+400*8]
+    mova [t4+wq*1+400*6], m1
+    mova [t4+wq*1+400*8], m2
+    movu            m4, [t3+wq*2+400*4+8]
+    movu            m1, [t3+wq*2+400*4+4]
+    paddd           m4, [t3+wq*2+400*4+0]
+    paddd           m1, m4
+    pslld           m1, 2                ; b[ 1] 444
+    psubd           m2, m1, m4           ; b[ 1] 343
+    paddd           m4, m2, [t3+wq*2+400*12+ 0]
+    paddd           m4, [t3+wq*2+400*16+ 0]
+    mova [t3+wq*2+400*12+ 0], m1
+    mova [t3+wq*2+400*16+ 0], m2
+    movu            m5, [t3+wq*2+400*4+24]
+    movu            m1, [t3+wq*2+400*4+20]
+    paddd           m5, [t3+wq*2+400*4+16]
+    paddd           m1, m5
+    pslld           m1, 2
+    psubd           m2, m1, m5
+    paddd           m5, m2, [t3+wq*2+400*12+16]
+    paddd           m5, [t3+wq*2+400*16+16]
+    mova [t3+wq*2+400*12+16], m1
+    mova [t3+wq*2+400*16+16], m2
+    mova            m0, [dstq+wq]
+    punpcklwd       m1, m0, m6
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m1               ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    psubd           m4, m2               ; b - a * src + (1 << 8)
+    psubd           m5, m3
+    psrad           m4, 9
+    psrad           m5, 9
+    packssdw        m4, m5
+    pmulhrsw        m4, m7
+    paddw           m0, m4
+    pmaxsw          m0, m6
+    pminsw          m0, m13
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .n1_loop
+    add           dstq, stridemp
+    movif32       dstm, dstq
+    ret
+
+%if ARCH_X86_32
+ %if STACK_ALIGNMENT < 16
+  %assign extra_stack 10*16
+ %else
+  %assign extra_stack 8*16
+ %endif
+cglobal sgr_filter_mix_16bpc, 1, 7, 8, -400*66-48-extra_stack, \
+                              dst, stride, left, lpf, w
+ %if STACK_ALIGNMENT < 16
+  %define dstm         dword [esp+calloff+16*8+4*0]
+  %define stridemp     dword [esp+calloff+16*8+4*1]
+  %define leftm        dword [esp+calloff+16*8+4*2]
+  %define lpfm         dword [esp+calloff+16*8+4*3]
+  %define w0m          dword [esp+calloff+16*8+4*4]
+  %define hd           dword [esp+calloff+16*8+4*5]
+  %define edgeb         byte [esp+calloff+16*8+4*6]
+  %define edged        dword [esp+calloff+16*8+4*6]
+  %define leftmp leftm
+ %else
+  %define w0m wm
+  %define hd dword r5m
+  %define edgeb  byte r7m
+  %define edged dword r7m
+ %endif
+ %define hvsrcm dword [esp+calloff+4*0]
+ %define w1m    dword [esp+calloff+4*1]
+ %define t3m    dword [esp+calloff+4*2]
+ %define t4m    dword [esp+calloff+4*3]
+ %xdefine m8 m6
+ %define  m9 [base+pd_8]
+ %define m10 [base+pd_34816]
+ %define m11 [base+pw_455_24]
+ %define m12 [base+pw_164_24]
+ %define m13 [esp+calloff+16*4]
+ %define m14 [esp+calloff+16*5]
+ %define m15 [esp+calloff+16*6]
+ %define  m6 [esp+calloff+16*7]
+ %define base r6-pw_455_24
+ %assign calloff 0
+ %if STACK_ALIGNMENT < 16
+    mov        strideq, [rstk+stack_offset+ 8]
+    mov          leftq, [rstk+stack_offset+12]
+    mov           lpfq, [rstk+stack_offset+16]
+    mov             wd, [rstk+stack_offset+20]
+    mov           dstm, dstq
+    mov       stridemp, strideq
+    mov          leftm, leftq
+    mov             r1, [rstk+stack_offset+24]
+    mov             r2, [rstk+stack_offset+32]
+    mov           lpfm, lpfq
+    mov             hd, r1
+    mov          edged, r2
+ %endif
+%else
+cglobal sgr_filter_mix_16bpc, 4, 13, 16, -400*66-40, dst, stride, left, lpf, \
+                                                     w, h, edge, params
+%endif
+%if ARCH_X86_64 || STACK_ALIGNMENT >= 16
+    movifnidn       wd, wm
+%endif
+%if ARCH_X86_64
+    mov        paramsq, r6mp
+    movifnidn       hd, hm
+    add             wd, wd
+    mov          edged, r7m
+    mova           m14, [paramsq]
+    add           lpfq, wq
+    mova            m9, [pd_8]
+    lea             t1, [rsp+wq+44]
+    mova           m10, [pd_34816]
+    add           dstq, wq
+    mova           m11, [pw_455_24]
+    lea             t3, [rsp+wq*2+400*24+40]
+    mova           m12, [pw_164_24]
+    lea             t4, [rsp+wq+400*52+40]
+    neg             wq
+    pshufd         m15, m14, q2222 ; w0 w1
+    punpcklwd      m14, m14
+    pshufd         m13, m14, q0000 ; s0
+    pshufd         m14, m14, q2222 ; s1
+    pxor            m6, m6
+    psllw          m15, 2
+ DEFINE_ARGS dst, stride, left, lpf, _, h, edge, _, _, _, w
+ %define lpfm [rsp]
+%else
+    mov             r1, [rstk+stack_offset+28] ; params
+    LEA             r6, pw_455_24
+    add             wd, wd
+    mova            m2, [r1]
+    add           lpfm, wq
+    lea             t1, [rsp+extra_stack+wq+52]
+    add           dstq, wq
+    lea             t3, [rsp+extra_stack+wq*2+400*24+48]
+    mov           dstm, dstq
+    lea             t4, [rsp+extra_stack+wq+400*52+48]
+    mov            t3m, t3
+    mov            t4m, t4
+    neg             wq
+    pshuflw         m0, m2, q0000
+    pshuflw         m1, m2, q2222
+    pshufhw         m2, m2, q1010
+    punpcklqdq      m0, m0 ; s0
+    punpcklqdq      m1, m1 ; s1
+    punpckhqdq      m2, m2 ; w0 w1
+    mov            w1m, wd
+    pxor            m3, m3
+    psllw           m2, 2
+    mova           m13, m0
+    mova           m14, m1
+    sub             wd, 4
+    mova           m15, m2
+    mova            m6, m3
+    mov           lpfq, lpfm
+    mov            w0m, wd
+ %define strideq r5
+%endif
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, stridemp
+    mov             t2, t1
+%if ARCH_X86_64
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_ssse3).top_fixup
+%else
+    mov             wq, w0m
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_ssse3).top_fixup_loop
+%endif
+    add             t1, 400*12
+    call .h_top
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov           lpfm, r10 ; below
+    movif32         t4, t4m
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv0
+%if ARCH_X86_64
+    test            hd, hd
+%else
+    mov             r4, hd
+    test            r4, r4
+%endif
+    jz .odd_height
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, lpfm
+    call .hv0_bottom
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov           lpfm, r10
+    call .h
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov             wq, w0m
+    mov         hvsrcm, lpfq
+%endif
+    lea             t2, [t1+400*12]
+.top_fixup_loop:
+    mova            m0, [t1+wq+400* 0]
+    mova            m1, [t1+wq+400* 2]
+    mova            m2, [t1+wq+400* 4]
+    paddw           m0, m0
+    mova            m3, [t1+wq+400* 6]
+    paddd           m1, m1
+    mova            m4, [t1+wq+400* 8]
+    paddd           m2, m2
+    mova            m5, [t1+wq+400*10]
+    mova [t2+wq+400* 0], m0
+    mova [t2+wq+400* 2], m1
+    mova [t2+wq+400* 4], m2
+    mova [t2+wq+400* 6], m3
+    mova [t2+wq+400* 8], m4
+    mova [t2+wq+400*10], m5
+    add             wq, 16
+    jl .top_fixup_loop
+    movif32         t3, t3m
+    movif32         t4, t4m
+    call .v0
+    jmp .main
+.h: ; horizontal boxsum
+%assign stack_offset stack_offset+4
+%assign calloff 4
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+ %define leftq r4
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32      leftq, leftm
+    movddup         m5, [leftq]
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    add         leftmp, 8
+    palignr         m4, m5, 10
+    jmp .h_main
+.h_extend_left:
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    pshufb          m4, [base+sgr_lshuf5]
+    jmp .h_main
+.h_top:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32         wq, w0m
+.h_loop:
+    movu            m4, [lpfq+wq- 2]
+.h_main:
+    movu            m5, [lpfq+wq+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             wd, -20
+    jl .h_have_right
+%if ARCH_X86_32
+    pxor            m8, m8
+%endif
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_ssse3).extend_right
+.h_have_right:
+    palignr         m3, m5, m4, 2
+    palignr         m0, m5, m4, 4
+    paddw           m1, m3, m0
+    punpcklwd       m2, m3, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m0
+    pmaddwd         m3, m3
+    palignr         m0, m5, m4, 6
+    paddw           m1, m0             ; sum3
+    punpcklwd       m7, m0, m6
+    pmaddwd         m7, m7
+    punpckhwd       m0, m6
+    pmaddwd         m0, m0
+    paddd           m2, m7             ; sumsq3
+    palignr         m5, m4, 8
+    punpcklwd       m7, m5, m4
+    paddd           m3, m0
+    paddw           m0, m4, m5
+    pmaddwd         m7, m7
+    punpckhwd       m5, m4
+    pmaddwd         m5, m5
+    mova [t1+wq+400* 6], m1
+    mova [t1+wq+400* 8], m2
+    mova [t1+wq+400*10], m3
+    paddw           m0, m1             ; sum5
+    paddd           m7, m2             ; sumsq5
+    paddd           m5, m3
+    mova [t1+wq+400* 0], m0
+    mova [t1+wq+400* 2], m7
+    mova [t1+wq+400* 4], m5
+    add             wq, 16
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsum + vertical boxsum + ab3 (even rows)
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movif32      leftq, leftm
+    movddup         m5, [leftq]
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    add         leftmp, 8
+    palignr         m4, m5, 10
+    jmp .hv0_main
+.hv0_extend_left:
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    pshufb          m4, [base+sgr_lshuf5]
+    jmp .hv0_main
+.hv0_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv0_loop_start
+%endif
+.hv0_loop:
+    movif32       lpfq, hvsrcm
+.hv0_loop_start:
+    movu            m4, [lpfq+wq- 2]
+.hv0_main:
+    movu            m5, [lpfq+wq+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp             wd, -20
+    jl .hv0_have_right
+%if ARCH_X86_32
+    pxor            m8, m8
+%endif
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_ssse3).extend_right
+.hv0_have_right:
+    palignr         m3, m5, m4, 2
+    palignr         m0, m5, m4, 4
+    movif32         t3, t3m
+    paddw           m1, m3, m0
+    punpcklwd       m2, m3, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m0
+    pmaddwd         m3, m3
+    palignr         m0, m5, m4, 6
+    paddw           m1, m0             ; h sum3
+    punpcklwd       m7, m0, m6
+    pmaddwd         m7, m7
+    punpckhwd       m0, m6
+    pmaddwd         m0, m0
+    paddd           m2, m7             ; h sumsq3
+    palignr         m5, m4, 8
+    punpcklwd       m7, m5, m4
+    paddd           m3, m0
+    paddw           m0, m4, m5
+    pmaddwd         m7, m7
+    punpckhwd       m5, m4
+    pmaddwd         m5, m5
+    paddw           m0, m1             ; h sum5
+    paddd           m7, m2             ; h sumsq5
+    paddd           m5, m3
+    mova [t3+wq*2+400*8+ 8], m0
+    mova [t3+wq*2+400*0+ 8], m7
+    mova [t3+wq*2+400*0+24], m5
+    paddw           m0, [t1+wq+400* 0]
+    paddd           m7, [t1+wq+400* 2]
+    paddd           m5, [t1+wq+400* 4]
+    mova [t1+wq+400* 0], m0
+    mova [t1+wq+400* 2], m7
+    mova [t1+wq+400* 4], m5
+    paddw           m0, m1, [t1+wq+400* 6]
+    paddd           m4, m2, [t1+wq+400* 8]
+    paddd           m5, m3, [t1+wq+400*10]
+    mova [t1+wq+400* 6], m1
+    mova [t1+wq+400* 8], m2
+    mova [t1+wq+400*10], m3
+    paddw           m1, m0, [t2+wq+400* 6]
+    paddd           m2, m4, [t2+wq+400* 8]
+    paddd           m3, m5, [t2+wq+400*10]
+    mova [t2+wq+400* 6], m0
+    mova [t2+wq+400* 8], m4
+    mova [t2+wq+400*10], m5
+    paddd           m2, m9
+    paddd           m3, m9
+    movaps          m8, [base+pf_256]
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a3 + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+%if ARCH_X86_32
+    pxor            m7, m7
+    pavgw           m3, m7
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m7, m14, m11, m8
+%else
+    pavgw           m3, m6             ; (b3 + 2) >> 2
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m14, m11, m8
+%endif
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*1+400*2+ 4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova [t3+wq*2+400*4+ 8], m0
+    mova [t3+wq*2+400*4+24], m1
+    add             wq, 16
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movif32      leftq, leftm
+    movddup         m5, [leftq]
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    add         leftmp, 8
+    palignr         m4, m5, 10
+    jmp .hv1_main
+.hv1_extend_left:
+    movif32         wq, w0m
+    mova            m4, [lpfq+wq+4]
+    pshufb          m4, [base+sgr_lshuf5]
+    jmp .hv1_main
+.hv1_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv1_loop_start
+%endif
+.hv1_loop:
+    movif32       lpfq, hvsrcm
+.hv1_loop_start:
+    movu            m4, [lpfq+wq- 2]
+.hv1_main:
+    movu            m5, [lpfq+wq+14]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp             wd, -20
+    jl .hv1_have_right
+%if ARCH_X86_32
+    pxor            m8, m8
+%endif
+    call mangle(private_prefix %+ _sgr_filter_5x5_16bpc_ssse3).extend_right
+.hv1_have_right:
+    palignr         m7, m5, m4, 2
+    palignr         m3, m5, m4, 4
+    paddw           m2, m7, m3
+    punpcklwd       m0, m7, m3
+    pmaddwd         m0, m0
+    punpckhwd       m7, m3
+    pmaddwd         m7, m7
+    palignr         m3, m5, m4, 6
+    paddw           m2, m3             ; h sum3
+    punpcklwd       m1, m3, m6
+    pmaddwd         m1, m1
+    punpckhwd       m3, m6
+    pmaddwd         m3, m3
+    paddd           m0, m1             ; h sumsq3
+    palignr         m5, m4, 8
+    punpckhwd       m1, m4, m5
+    paddw           m8, m4, m5
+    pmaddwd         m1, m1
+    punpcklwd       m4, m5
+    pmaddwd         m4, m4
+    paddd           m7, m3
+    paddw           m5, m2, [t2+wq+400* 6]
+    mova [t2+wq+400* 6], m2
+    paddw           m8, m2             ; h sum5
+    paddd           m2, m0, [t2+wq+400* 8]
+    paddd           m3, m7, [t2+wq+400*10]
+    mova [t2+wq+400* 8], m0
+    mova [t2+wq+400*10], m7
+    paddd           m4, m0             ; h sumsq5
+    paddd           m1, m7
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pslld           m0, m2, 3
+    pslld           m7, m3, 3
+    paddd           m2, m0             ; ((a3 + 8) >> 4) * 9
+    paddd           m3, m7
+    psrlw           m7, m5, 1
+    pavgw           m7, m6             ; (b3 + 2) >> 2
+%if ARCH_X86_32
+    mova      [esp+20], m8
+    mov             t3, t3m
+    SGR_CALC_X      m0, m5, m7, m8, m2, m3, m6, m14, m11, [base+pf_256]
+%else
+    SGR_CALC_X      m0, m5, m7, m12, m2, m3, m6, m14, m11, [base+pf_256]
+%endif
+    punpcklwd       m2, m7, m7
+    mova [t4+wq*1+400*4+4], m7
+    punpckhwd       m7, m7
+%if ARCH_X86_32
+    MUL_32X16X2     m0, m5, m2, m7, m3, m8
+    mova            m8, [esp+20]
+%else
+    MUL_32X16X2     m0, m5, m2, m7, m3, m12
+    mova           m12, [pw_164_24]
+%endif
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m5, m10
+    psrld           m0, 12
+    psrld           m5, 12
+    mova [t3+wq*2+400*8+ 8], m0
+    mova [t3+wq*2+400*8+24], m5
+    paddw           m5, m8, [t2+wq+400*0]
+    paddd           m2, m4, [t2+wq+400*2]
+    paddd           m3, m1, [t2+wq+400*4]
+    paddw           m5, [t1+wq+400*0]
+    paddd           m2, [t1+wq+400*2]
+    paddd           m3, [t1+wq+400*4]
+    mova [t2+wq+400*0], m8
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a5 + 8) >> 4
+    psrld           m3, 4
+    mova [t2+wq+400*2], m4
+    pslld           m8, m2, 4
+    mova [t2+wq+400*4], m1
+    pslld           m4, m3, 4
+    paddd           m8, m2
+    pslld           m2, 3
+    paddd           m4, m3
+    pslld           m3, 3
+    paddd           m2, m8             ; ((a5 + 8) >> 4) * 25
+    paddd           m3, m4
+    psrlw           m1, m5, 1
+%if ARCH_X86_32
+    pxor            m7, m7
+    pavgw           m1, m7
+    SGR_CALC_X      m0, m5, m1, m4, m2, m3, m7, m13, m12, [base+pf_256]
+%else
+    movaps          m8, [base+pf_256]
+    pavgw           m1, m6             ; (b5 + 2) >> 2
+    SGR_CALC_X      m0, m5, m1, m4, m2, m3, m6, m13, m12, m8
+%endif
+    punpcklwd       m2, m1, m1
+    mova [t4+wq*1+400*0+ 4], m1
+    punpckhwd       m1, m1
+    MUL_32X16X2     m0, m5, m2, m1, m3, m4
+    paddd           m0, m10            ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m5, m10
+    psrld           m0, 12
+    psrld           m5, 12
+    mova [t3+wq*2+400*0+ 8], m0
+    mova [t3+wq*2+400*0+24], m5
+    add             wq, 16
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab3 (even rows)
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov             wd, w0m
+%endif
+    movaps          m8, [base+pf_256]
+.v0_loop:
+    mova            m0, [t1+wq+400* 6]
+    mova            m4, [t1+wq+400* 8]
+    mova            m5, [t1+wq+400*10]
+    paddw           m0, m0
+    paddd           m4, m4
+    paddd           m5, m5
+    paddw           m1, m0, [t2+wq+400* 6]
+    paddd           m2, m4, [t2+wq+400* 8]
+    paddd           m3, m5, [t2+wq+400*10]
+    mova [t2+wq+400* 6], m0
+    mova [t2+wq+400* 8], m4
+    mova [t2+wq+400*10], m5
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a3 + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+%if ARCH_X86_32
+    pxor            m7, m7
+    pavgw           m3, m7
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m7, m14, m11, m8
+%else
+    pavgw           m3, m6             ; (b3 + 2) >> 2
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m14, m11, m8
+%endif
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*1+400*2+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova            m3, [t1+wq+400*0]
+    mova            m4, [t1+wq+400*2]
+    mova            m5, [t1+wq+400*4]
+    mova [t3+wq*2+400*8+ 8], m3
+    mova [t3+wq*2+400*0+ 8], m4
+    mova [t3+wq*2+400*0+24], m5
+    paddw           m3, m3 ; cc5
+    paddd           m4, m4
+    paddd           m5, m5
+    mova [t1+wq+400*0], m3
+    mova [t1+wq+400*2], m4
+    mova [t1+wq+400*4], m5
+    mova [t3+wq*2+400*4+ 8], m0
+    mova [t3+wq*2+400*4+24], m1
+    add             wq, 16
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+%if ARCH_X86_64
+    lea             wq, [r4-4]
+%else
+    mov             wd, w0m
+%endif
+    movaps          m8, [base+pf_256]
+.v1_loop:
+    mova            m4, [t1+wq+400* 6]
+    mova            m5, [t1+wq+400* 8]
+    mova            m7, [t1+wq+400*10]
+    paddw           m1, m4, [t2+wq+400* 6]
+    paddd           m2, m5, [t2+wq+400* 8]
+    paddd           m3, m7, [t2+wq+400*10]
+    mova [t2+wq+400* 6], m4
+    mova [t2+wq+400* 8], m5
+    mova [t2+wq+400*10], m7
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a3 + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a3 + 8) >> 4) * 9
+    paddd           m5, m3
+    psrlw           m3, m1, 1
+%if ARCH_X86_32
+    pxor            m7, m7
+    pavgw           m3, m7
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m7, m14, m11, m8
+%else
+    pavgw           m3, m6             ; (b3 + 2) >> 2
+    SGR_CALC_X      m0, m1, m3, m2, m4, m5, m6, m14, m11, m8
+%endif
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*1+400*4+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova            m4, [t3+wq*2+400*8+ 8]
+    mova            m5, [t3+wq*2+400*0+ 8]
+    mova            m7, [t3+wq*2+400*0+24]
+    mova [t3+wq*2+400*8+ 8], m0
+    mova [t3+wq*2+400*8+24], m1
+    paddw           m1, m4, [t2+wq+400*0]
+    paddd           m2, m5, [t2+wq+400*2]
+    paddd           m3, m7, [t2+wq+400*4]
+    paddw           m1, [t1+wq+400*0]
+    paddd           m2, [t1+wq+400*2]
+    paddd           m3, [t1+wq+400*4]
+    mova [t2+wq+400*0], m4
+    mova [t2+wq+400*2], m5
+    mova [t2+wq+400*4], m7
+    paddd           m2, m9
+    paddd           m3, m9
+    psrld           m2, 4              ; (a5 + 8) >> 4
+    psrld           m3, 4
+    pslld           m4, m2, 4
+    pslld           m5, m3, 4
+    paddd           m4, m2
+    pslld           m2, 3
+    paddd           m5, m3
+    pslld           m3, 3
+    paddd           m2, m4
+    paddd           m3, m5
+    psrlw           m5, m1, 1
+%if ARCH_X86_32
+    pxor            m7, m7
+    pavgw           m5, m7
+    SGR_CALC_X      m0, m1, m5, m4, m2, m3, m7, m13, m12, m8
+%else
+    pavgw           m5, m6             ; (b5 + 2) >> 2
+    SGR_CALC_X      m0, m1, m5, m4, m2, m3, m6, m13, m12, m8
+%endif
+    punpcklwd       m4, m5, m5
+    mova [t4+wq*1+400*0+ 4], m5
+    punpckhwd       m5, m5
+    MUL_32X16X2     m0, m1, m4, m5, m2, m3
+    paddd           m0, m10            ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova [t3+wq*2+400*0+ 8], m0
+    mova [t3+wq*2+400*0+24], m1
+    add             wq, 16
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    movif64         wq, r4
+    movif32         wd, w1m
+.prep_n_loop:
+    movu            m0, [t4+wq*1+400*0+ 2]
+    movu            m1, [t3+wq*2+400*0+ 4]
+    movu            m2, [t3+wq*2+400*0+20]
+    movu            m3, [t4+wq*1+400*0+ 4]
+    movu            m4, [t3+wq*2+400*0+ 8]
+    paddw           m3, [t4+wq*1+400*0+ 0]
+    paddd           m4, [t3+wq*2+400*0+ 0]
+    paddd           m5, m2, [t3+wq*2+400*0+16]
+    movu            m7, [t3+wq*2+400*0+24]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m7
+    paddw           m0, m3
+    paddd           m1, m4
+    paddd           m2, m5
+    psllw           m3, 2
+    pslld           m4, 2
+    pslld           m5, 2
+    paddw           m0, m3               ; a5 565
+    paddd           m1, m4               ; b5 565
+    paddd           m2, m5
+    mova [t4+wq*1+400* 6+ 0], m0
+    mova [t3+wq*2+400*12+ 0], m1
+    mova [t3+wq*2+400*12+16], m2
+    movu            m0, [t4+wq*1+400*2+ 4]
+    movu            m1, [t3+wq*2+400*4+ 8]
+    movu            m2, [t3+wq*2+400*4+24]
+    movu            m3, [t4+wq*1+400*2+ 2]
+    movu            m4, [t3+wq*2+400*4+ 4]
+    movu            m5, [t3+wq*2+400*4+20]
+    paddw           m0, [t4+wq*1+400*2+ 0]
+    paddd           m1, [t3+wq*2+400*4+ 0]
+    paddd           m2, [t3+wq*2+400*4+16]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    psllw           m3, 2                ; a3[-1] 444
+    pslld           m4, 2                ; b3[-1] 444
+    pslld           m5, 2
+    psubw           m3, m0               ; a3[-1] 343
+    psubd           m4, m1               ; b3[-1] 343
+    psubd           m5, m2
+    mova [t4+wq*1+400* 8+ 0], m3
+    mova [t3+wq*2+400*16+ 0], m4
+    mova [t3+wq*2+400*16+16], m5
+    movu            m0, [t4+wq*1+400*4+ 4]
+    movu            m1, [t3+wq*2+400*8+ 8]
+    movu            m2, [t3+wq*2+400*8+24]
+    movu            m3, [t4+wq*1+400*4+ 2]
+    movu            m4, [t3+wq*2+400*8+ 4]
+    movu            m5, [t3+wq*2+400*8+20]
+    paddw           m0, [t4+wq*1+400*4+ 0]
+    paddd           m1, [t3+wq*2+400*8+ 0]
+    paddd           m2, [t3+wq*2+400*8+16]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    psllw           m3, 2                 ; a3[ 0] 444
+    pslld           m4, 2                 ; b3[ 0] 444
+    pslld           m5, 2
+    mova [t4+wq*1+400*10+ 0], m3
+    mova [t3+wq*2+400*20+ 0], m4
+    mova [t3+wq*2+400*20+16], m5
+    psubw           m3, m0                ; a3[ 0] 343
+    psubd           m4, m1                ; b3[ 0] 343
+    psubd           m5, m2
+    mova [t4+wq*1+400*12+ 0], m3
+    mova [t3+wq*2+400*24+ 0], m4
+    mova [t3+wq*2+400*24+16], m5
+    add             wq, 16
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n0_loop:
+    movu            m0, [t4+wq*1+ 4]
+    movu            m2, [t4+wq*1+ 2]
+    paddw           m0, [t4+wq*1+ 0]
+    paddw           m0, m2
+    paddw           m2, m0
+    psllw           m0, 2
+    paddw           m0, m2               ; a5
+    movu            m4, [t3+wq*2+ 8]
+    movu            m5, [t3+wq*2+24]
+    movu            m1, [t3+wq*2+ 4]
+    movu            m3, [t3+wq*2+20]
+    paddd           m4, [t3+wq*2+ 0]
+    paddd           m5, [t3+wq*2+16]
+    paddd           m4, m1
+    paddd           m5, m3
+    paddd           m1, m4
+    paddd           m3, m5
+    pslld           m4, 2
+    pslld           m5, 2
+    paddd           m4, m1               ; b5
+    paddd           m5, m3
+    movu            m2, [t4+wq*1+400* 6]
+    paddw           m2, m0
+    mova [t4+wq*1+400* 6], m0
+    paddd           m0, m4, [t3+wq*2+400*12+ 0]
+    paddd           m1, m5, [t3+wq*2+400*12+16]
+    mova [t3+wq*2+400*12+ 0], m4
+    mova [t3+wq*2+400*12+16], m5
+    mova [rsp+16+ARCH_X86_32*4], m1
+    movu            m3, [t4+wq*1+400*2+4]
+    movu            m5, [t4+wq*1+400*2+2]
+    paddw           m3, [t4+wq*1+400*2+0]
+    paddw           m5, m3
+    psllw           m5, 2                ; a3[ 1] 444
+    psubw           m4, m5, m3           ; a3[ 1] 343
+    movu            m3, [t4+wq*1+400* 8]
+    paddw           m3, [t4+wq*1+400*10]
+    paddw           m3, m4
+    mova [t4+wq*1+400* 8], m4
+    mova [t4+wq*1+400*10], m5
+    movu            m1, [t3+wq*2+400*4+ 8]
+    movu            m5, [t3+wq*2+400*4+ 4]
+    movu            m7, [t3+wq*2+400*4+24]
+    movu            m8, [t3+wq*2+400*4+20]
+    paddd           m1, [t3+wq*2+400*4+ 0]
+    paddd           m7, [t3+wq*2+400*4+16]
+    paddd           m5, m1
+    paddd           m8, m7
+    pslld           m5, 2                ; b3[ 1] 444
+    pslld           m8, 2
+    psubd           m4, m5, m1           ; b3[ 1] 343
+%if ARCH_X86_32
+    mova      [esp+52], m8
+    psubd           m8, m7
+%else
+    psubd           m6, m8, m7
+    SWAP            m8, m6
+%endif
+    paddd           m1, m4, [t3+wq*2+400*16+ 0]
+    paddd           m7, m8, [t3+wq*2+400*16+16]
+    paddd           m1, [t3+wq*2+400*20+ 0]
+    paddd           m7, [t3+wq*2+400*20+16]
+    mova [t3+wq*2+400*16+ 0], m4
+    mova [t3+wq*2+400*16+16], m8
+    mova [t3+wq*2+400*20+ 0], m5
+%if ARCH_X86_32
+    mova            m8, [esp+52]
+%else
+    SWAP            m8, m6
+    pxor            m6, m6
+%endif
+    mova [t3+wq*2+400*20+16], m8
+    mova [rsp+32+ARCH_X86_32*4], m7
+    movu            m5, [dstq+wq]
+    punpcklwd       m4, m5, m6
+    punpcklwd       m7, m2, m6
+    pmaddwd         m7, m4               ; a5 * src
+    punpcklwd       m8, m3, m6
+    pmaddwd         m8, m4               ; a3 * src
+    punpckhwd       m5, m6
+    punpckhwd       m2, m6
+    pmaddwd         m2, m5
+    punpckhwd       m3, m6
+    pmaddwd         m3, m5
+    pslld           m4, 13
+    pslld           m5, 13
+    psubd           m0, m7               ; b5 - a5 * src + (1 << 8)
+    psubd           m1, m8               ; b3 - a3 * src + (1 << 8)
+    mova            m7, [base+pd_0xffff]
+    psrld           m0, 9
+    pslld           m1, 7
+    pand            m0, m7
+    pandn           m8, m7, m1
+    por             m0, m8
+    mova            m1, [rsp+16+ARCH_X86_32*4]
+    mova            m8, [rsp+32+ARCH_X86_32*4]
+    psubd           m1, m2
+    psubd           m8, m3
+    mova            m2, [base+pd_4096]
+    psrld           m1, 9
+    pslld           m8, 7
+    pand            m1, m7
+    pandn           m7, m8
+    por             m1, m7
+    pmaddwd         m0, m15
+    pmaddwd         m1, m15
+%if ARCH_X86_32
+    pxor            m7, m7
+%else
+    SWAP            m7, m6
+%endif
+    paddd           m4, m2
+    paddd           m5, m2
+    paddd           m0, m4
+    paddd           m1, m5
+    psrad           m0, 8
+    psrad           m1, 8
+    packssdw        m0, m1               ; clip
+    pmaxsw          m0, m7
+    psrlw           m0, 5
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .n0_loop
+    add           dstq, stridemp
+    ret
+%if ARCH_X86_64
+    SWAP            m6, m7
+%endif
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n1_loop:
+    movu            m3, [t4+wq*1+400*4+4]
+    movu            m5, [t4+wq*1+400*4+2]
+    paddw           m3, [t4+wq*1+400*4+0]
+    paddw           m5, m3
+    psllw           m5, 2                ; a3[ 1] 444
+    psubw           m4, m5, m3           ; a3[ 1] 343
+    paddw           m3, m4, [t4+wq*1+400*12]
+    paddw           m3, [t4+wq*1+400*10]
+    mova [t4+wq*1+400*10], m5
+    mova [t4+wq*1+400*12], m4
+    movu            m1, [t3+wq*2+400*8+ 8]
+    movu            m5, [t3+wq*2+400*8+ 4]
+    movu            m7, [t3+wq*2+400*8+24]
+    movu            m8, [t3+wq*2+400*8+20]
+    paddd           m1, [t3+wq*2+400*8+ 0]
+    paddd           m7, [t3+wq*2+400*8+16]
+    paddd           m5, m1
+    paddd           m8, m7
+    pslld           m5, 2                ; b3[ 1] 444
+    pslld           m8, 2
+    psubd           m4, m5, m1           ; b3[ 1] 343
+    psubd           m0, m8, m7
+    paddd           m1, m4, [t3+wq*2+400*24+ 0]
+    paddd           m7, m0, [t3+wq*2+400*24+16]
+    paddd           m1, [t3+wq*2+400*20+ 0]
+    paddd           m7, [t3+wq*2+400*20+16]
+    mova [t3+wq*2+400*20+ 0], m5
+    mova [t3+wq*2+400*20+16], m8
+    mova [t3+wq*2+400*24+ 0], m4
+    mova [t3+wq*2+400*24+16], m0
+    mova            m5, [dstq+wq]
+    mova            m2, [t4+wq*1+400* 6]
+    punpcklwd       m4, m5, m6
+    punpcklwd       m8, m2, m6
+    pmaddwd         m8, m4               ; a5 * src
+    punpcklwd       m0, m3, m6
+    pmaddwd         m0, m4               ; a3 * src
+    punpckhwd       m5, m6
+    punpckhwd       m2, m6
+    pmaddwd         m2, m5
+    punpckhwd       m3, m6
+    pmaddwd         m3, m5
+    psubd           m1, m0               ; b3 - a3 * src + (1 << 8)
+    pslld           m4, 13
+    pslld           m5, 13
+    mova            m0, [t3+wq*2+400*12+ 0]
+    psubd           m0, m8               ; b5 - a5 * src + (1 << 8)
+    mova            m8, [t3+wq*2+400*12+16]
+    psubd           m8, m2
+    psubd           m7, m3
+    mova            m2, [base+pd_0xffff]
+    pslld           m1, 7
+    psrld           m0, 8
+    psrld           m8, 8
+    pslld           m7, 7
+    pand            m0, m2
+    pandn           m3, m2, m1
+    por             m0, m3
+    pand            m8, m2
+    pandn           m2, m7
+    por             m2, m8
+    mova            m1, [base+pd_4096]
+    pmaddwd         m0, m15
+    pmaddwd         m2, m15
+%if ARCH_X86_64
+    SWAP            m7, m6
+%endif
+    pxor            m7, m7
+    paddd           m4, m1
+    paddd           m5, m1
+    paddd           m0, m4
+    paddd           m2, m5
+    psrad           m0, 8
+    psrad           m2, 8
+    packssdw        m0, m2              ; clip
+    pmaxsw          m0, m7
+    psrlw           m0, 5
+    mova     [dstq+wq], m0
+    add             wq, 16
+    jl .n1_loop
+    add           dstq, stridemp
+    movif32       dstm, dstq
+    ret
diff --git a/media/libdav1d/src/src/x86/looprestoration_avx2.asm b/media/libdav1d/src/src/x86/looprestoration_avx2.asm
new file mode 100644
index 0000000000..59ebf074db
--- /dev/null
+++ b/media/libdav1d/src/src/x86/looprestoration_avx2.asm
@@ -0,0 +1,2339 @@
+; Copyright © 2018, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 32
+
+wiener_l_shuf: db  4,  4,  4,  4,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+               db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+wiener_shufA:  db  1,  7,  2,  8,  3,  9,  4, 10,  5, 11,  6, 12,  7, 13,  8, 14
+wiener_shufB:  db  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8,  8,  9,  9, 10
+wiener_shufC:  db  6,  5,  7,  6,  8,  7,  9,  8, 10,  9, 11, 10, 12, 11, 13, 12
+sgr_l_shuf:    db  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11
+sgr_r_ext:     times 16 db 1
+               times 16 db 9
+sgr_shuf:      db  1, -1,  2, -1,  3, -1,  4, -1,  5, -1,  6, -1,  7, -1,  8, -1
+               db  9, -1, 10, -1, 11, -1, 12, -1
+
+pb_m5:         times 4 db -5
+pb_3:          times 4 db 3
+pw_5_6:        dw 5, 6
+pw_164_24:     dw 164, 24
+pw_455_24:     dw 455, 24
+pw_256:        times 2 dw 256
+pw_2056:       times 2 dw 2056
+pw_m16380:     times 2 dw -16380
+pd_25:         dd 25
+pd_34816:      dd 34816
+pd_m4096:      dd -4096
+pf_256:        dd 256.0
+
+cextern pb_0to63
+
+SECTION .text
+
+DECLARE_REG_TMP 8, 7, 9, 11, 12, 13, 14 ; ring buffer pointers
+
+INIT_YMM avx2
+cglobal wiener_filter7_8bpc, 4, 15, 16, -384*12-16, dst, stride, left, lpf, \
+                                                    w, h, edge, flt
+    mov           fltq, r6mp
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mov             wd, wm
+    vbroadcasti128  m6, [wiener_shufA]
+    vpbroadcastb   m11, [fltq+ 0] ; x0 x0
+    vbroadcasti128  m7, [wiener_shufB]
+    vpbroadcastd   m12, [fltq+ 2]
+    vbroadcasti128  m8, [wiener_shufC]
+    packsswb       m12, m12       ; x1 x2
+    vpbroadcastw   m13, [fltq+ 6] ; x3
+    vbroadcasti128  m9, [sgr_shuf+6]
+    add           lpfq, wq
+    vpbroadcastd   m10, [pw_m16380]
+    vpbroadcastd   m14, [fltq+16] ; y0 y1
+    add           dstq, wq
+    vpbroadcastd   m15, [fltq+20] ; y2 y3
+    lea             t1, [rsp+wq*2+16]
+    psllw          m14, 5
+    neg             wq
+    psllw          m15, 5
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t6, t1
+    mov             t5, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t4, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .h
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+.main:
+    lea             t0, [t1+384*2]
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v3
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.v1:
+    call .v
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    mov             t6, t1
+    mov             t5, t1
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v3
+    add             t0, 384*8
+    call .hv
+    dec             hd
+    jnz .main
+.v3:
+    call .v
+.v2:
+    call .v
+    jmp .v1
+.extend_right:
+    movd           xm2, r10d
+    vpbroadcastd    m0, [pb_3]
+    vpbroadcastd    m1, [pb_m5]
+    vpbroadcastb    m2, xm2
+    mova            m3, [pb_0to63]
+    psubb           m0, m2
+    psubb           m1, m2
+    pminub          m0, m3
+    pminub          m1, m3
+    pshufb          m4, m0
+    pshufb          m5, m1
+    ret
+.h:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd           xm4, [leftq]
+    vpblendd        m4, [lpfq+r10-4], 0xfe
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    vbroadcasti128  m5, [lpfq+r10] ; avoid accessing memory located
+    mova            m4, [lpfq+r10] ; before the start of the buffer
+    palignr         m4, m5, 12
+    pshufb          m4, [wiener_l_shuf]
+    jmp .h_main
+.h_top:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m4, [lpfq+r10-4]
+.h_main:
+    movu            m5, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -34
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    pshufb          m0, m4, m6
+    pmaddubsw       m0, m11
+    pshufb          m1, m5, m6
+    pmaddubsw       m1, m11
+    pshufb          m2, m4, m7
+    pmaddubsw       m2, m12
+    pshufb          m3, m5, m7
+    pmaddubsw       m3, m12
+    paddw           m0, m2
+    pshufb          m2, m4, m8
+    pmaddubsw       m2, m12
+    paddw           m1, m3
+    pshufb          m3, m5, m8
+    pmaddubsw       m3, m12
+    pshufb          m4, m9
+    paddw           m0, m2
+    pmullw          m2, m4, m13
+    pshufb          m5, m9
+    paddw           m1, m3
+    pmullw          m3, m5, m13
+    psllw           m4, 7
+    psllw           m5, 7
+    paddw           m4, m10
+    paddw           m5, m10
+    paddw           m0, m2
+    vpbroadcastd    m2, [pw_2056]
+    paddw           m1, m3
+    paddsw          m0, m4
+    paddsw          m1, m5
+    psraw           m0, 3
+    psraw           m1, 3
+    paddw           m0, m2
+    paddw           m1, m2
+    mova [t1+r10*2+ 0], m0
+    mova [t1+r10*2+32], m1
+    add            r10, 32
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movd           xm4, [leftq]
+    vpblendd        m4, [lpfq+r10-4], 0xfe
+    add          leftq, 4
+    jmp .hv_main
+.hv_extend_left:
+    movu            m4, [lpfq+r10-4]
+    pshufb          m4, [wiener_l_shuf]
+    jmp .hv_main
+.hv_bottom:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m4, [lpfq+r10-4]
+.hv_main:
+    movu            m5, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -34
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    pshufb          m0, m4, m6
+    pmaddubsw       m0, m11
+    pshufb          m1, m5, m6
+    pmaddubsw       m1, m11
+    pshufb          m2, m4, m7
+    pmaddubsw       m2, m12
+    pshufb          m3, m5, m7
+    pmaddubsw       m3, m12
+    paddw           m0, m2
+    pshufb          m2, m4, m8
+    pmaddubsw       m2, m12
+    paddw           m1, m3
+    pshufb          m3, m5, m8
+    pmaddubsw       m3, m12
+    pshufb          m4, m9
+    paddw           m0, m2
+    pmullw          m2, m4, m13
+    pshufb          m5, m9
+    paddw           m1, m3
+    pmullw          m3, m5, m13
+    psllw           m4, 7
+    psllw           m5, 7
+    paddw           m4, m10
+    paddw           m5, m10
+    paddw           m0, m2
+    paddw           m1, m3
+    mova            m2, [t4+r10*2]
+    paddw           m2, [t2+r10*2]
+    mova            m3, [t3+r10*2]
+    paddsw          m0, m4
+    vpbroadcastd    m4, [pw_2056]
+    paddsw          m1, m5
+    mova            m5, [t5+r10*2]
+    paddw           m5, [t1+r10*2]
+    psraw           m0, 3
+    psraw           m1, 3
+    paddw           m0, m4
+    paddw           m1, m4
+    paddw           m4, m0, [t6+r10*2]
+    mova    [t0+r10*2], m0
+    punpcklwd       m0, m2, m3
+    pmaddwd         m0, m15
+    punpckhwd       m2, m3
+    pmaddwd         m2, m15
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m14
+    punpckhwd       m4, m5
+    pmaddwd         m4, m14
+    paddd           m0, m3
+    paddd           m4, m2
+    mova            m2, [t4+r10*2+32]
+    paddw           m2, [t2+r10*2+32]
+    mova            m3, [t3+r10*2+32]
+    mova            m5, [t5+r10*2+32]
+    paddw           m5, [t1+r10*2+32]
+    packuswb        m0, m4
+    paddw           m4, m1, [t6+r10*2+32]
+    mova [t0+r10*2+32], m1
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m15
+    punpckhwd       m2, m3
+    pmaddwd         m2, m15
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m14
+    punpckhwd       m4, m5
+    pmaddwd         m4, m14
+    paddd           m1, m3
+    paddd           m2, m4
+    packuswb        m1, m2
+    psrlw           m0, 8
+    psrlw           m1, 8
+    packuswb        m0, m1
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .hv_loop
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t6
+    add           dstq, strideq
+    ret
+.v:
+    mov            r10, wq
+.v_loop:
+    mova            m2, [t4+r10*2+ 0]
+    paddw           m2, [t2+r10*2+ 0]
+    mova            m4, [t3+r10*2+ 0]
+    mova            m6, [t1+r10*2+ 0]
+    paddw           m8, m6, [t6+r10*2+ 0]
+    paddw           m6, [t5+r10*2+ 0]
+    mova            m3, [t4+r10*2+32]
+    paddw           m3, [t2+r10*2+32]
+    mova            m5, [t3+r10*2+32]
+    mova            m7, [t1+r10*2+32]
+    paddw           m9, m7, [t6+r10*2+32]
+    paddw           m7, [t5+r10*2+32]
+    punpcklwd       m0, m2, m4
+    pmaddwd         m0, m15
+    punpckhwd       m2, m4
+    pmaddwd         m2, m15
+    punpcklwd       m4, m8, m6
+    pmaddwd         m4, m14
+    punpckhwd       m6, m8, m6
+    pmaddwd         m6, m14
+    punpcklwd       m1, m3, m5
+    pmaddwd         m1, m15
+    punpckhwd       m3, m5
+    pmaddwd         m3, m15
+    punpcklwd       m5, m9, m7
+    pmaddwd         m5, m14
+    punpckhwd       m7, m9, m7
+    pmaddwd         m7, m14
+    paddd           m0, m4
+    paddd           m2, m6
+    paddd           m1, m5
+    paddd           m3, m7
+    packuswb        m0, m2
+    packuswb        m1, m3
+    psrlw           m0, 8
+    psrlw           m1, 8
+    packuswb        m0, m1
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .v_loop
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    add           dstq, strideq
+    ret
+
+cglobal wiener_filter5_8bpc, 4, 13, 16, 384*8+16, dst, stride, left, lpf, \
+                                                  w, h, edge, flt
+    mov           fltq, r6mp
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mov             wd, wm
+    vbroadcasti128  m6, [wiener_shufB]
+    vpbroadcastd   m12, [fltq+ 2]
+    vbroadcasti128  m7, [wiener_shufC]
+    packsswb       m12, m12       ; x1 x2
+    vpbroadcastw   m13, [fltq+ 6] ; x3
+    vbroadcasti128  m8, [sgr_shuf+6]
+    add           lpfq, wq
+    vpbroadcastd    m9, [pw_m16380]
+    vpbroadcastd   m10, [pw_2056]
+    mova           m11, [wiener_l_shuf]
+    vpbroadcastd   m14, [fltq+16] ; __ y1
+    add           dstq, wq
+    vpbroadcastd   m15, [fltq+20] ; y2 y3
+    lea             t1, [rsp+wq*2+16]
+    psllw          m14, 5
+    neg             wq
+    psllw          m15, 5
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t4, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t3, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+.main:
+    mov             t0, t4
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v2
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v2
+    add             t0, 384*6
+    call .hv
+    dec             hd
+    jnz .main
+.v2:
+    call .v
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    add           dstq, strideq
+.v1:
+    call .v
+    jmp .end
+.h:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd           xm4, [leftq]
+    vpblendd        m4, [lpfq+r10-4], 0xfe
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    vbroadcasti128  m5, [lpfq+r10] ; avoid accessing memory located
+    mova            m4, [lpfq+r10] ; before the start of the buffer
+    palignr         m4, m5, 12
+    pshufb          m4, m11
+    jmp .h_main
+.h_top:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m4, [lpfq+r10-4]
+.h_main:
+    movu            m5, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -33
+    jl .h_have_right
+    call mangle(private_prefix %+ _wiener_filter7_8bpc_avx2).extend_right
+.h_have_right:
+    pshufb          m0, m4, m6
+    pmaddubsw       m0, m12
+    pshufb          m1, m5, m6
+    pmaddubsw       m1, m12
+    pshufb          m2, m4, m7
+    pmaddubsw       m2, m12
+    pshufb          m3, m5, m7
+    pmaddubsw       m3, m12
+    pshufb          m4, m8
+    paddw           m0, m2
+    pmullw          m2, m4, m13
+    pshufb          m5, m8
+    paddw           m1, m3
+    pmullw          m3, m5, m13
+    psllw           m4, 7
+    psllw           m5, 7
+    paddw           m4, m9
+    paddw           m5, m9
+    paddw           m0, m2
+    paddw           m1, m3
+    paddsw          m0, m4
+    paddsw          m1, m5
+    psraw           m0, 3
+    psraw           m1, 3
+    paddw           m0, m10
+    paddw           m1, m10
+    mova [t1+r10*2+ 0], m0
+    mova [t1+r10*2+32], m1
+    add            r10, 32
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movd           xm4, [leftq]
+    vpblendd        m4, [lpfq+r10-4], 0xfe
+    add          leftq, 4
+    jmp .hv_main
+.hv_extend_left:
+    movu            m4, [lpfq+r10-4]
+    pshufb          m4, m11
+    jmp .hv_main
+.hv_bottom:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m4, [lpfq+r10-4]
+.hv_main:
+    movu            m5, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -33
+    jl .hv_have_right
+    call mangle(private_prefix %+ _wiener_filter7_8bpc_avx2).extend_right
+.hv_have_right:
+    pshufb          m0, m4, m6
+    pmaddubsw       m0, m12
+    pshufb          m1, m5, m6
+    pmaddubsw       m1, m12
+    pshufb          m2, m4, m7
+    pmaddubsw       m2, m12
+    pshufb          m3, m5, m7
+    pmaddubsw       m3, m12
+    pshufb          m4, m8
+    paddw           m0, m2
+    pmullw          m2, m4, m13
+    pshufb          m5, m8
+    paddw           m1, m3
+    pmullw          m3, m5, m13
+    psllw           m4, 7
+    psllw           m5, 7
+    paddw           m4, m9
+    paddw           m5, m9
+    paddw           m0, m2
+    paddw           m1, m3
+    mova            m2, [t3+r10*2]
+    paddw           m2, [t1+r10*2]
+    mova            m3, [t2+r10*2]
+    paddsw          m0, m4
+    paddsw          m1, m5
+    psraw           m0, 3
+    psraw           m1, 3
+    paddw           m0, m10
+    paddw           m1, m10
+    paddw           m4, m0, [t4+r10*2]
+    mova    [t0+r10*2], m0
+    punpcklwd       m0, m2, m3
+    pmaddwd         m0, m15
+    punpckhwd       m2, m3
+    pmaddwd         m2, m15
+    punpcklwd       m3, m4, m4
+    pmaddwd         m3, m14
+    punpckhwd       m4, m4
+    pmaddwd         m4, m14
+    paddd           m0, m3
+    paddd           m4, m2
+    mova            m2, [t3+r10*2+32]
+    paddw           m2, [t1+r10*2+32]
+    mova            m3, [t2+r10*2+32]
+    packuswb        m0, m4
+    paddw           m4, m1, [t4+r10*2+32]
+    mova [t0+r10*2+32], m1
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m15
+    punpckhwd       m2, m3
+    pmaddwd         m2, m15
+    punpcklwd       m3, m4, m4
+    pmaddwd         m3, m14
+    punpckhwd       m4, m4
+    pmaddwd         m4, m14
+    paddd           m1, m3
+    paddd           m2, m4
+    packuswb        m1, m2
+    psrlw           m0, 8
+    psrlw           m1, 8
+    packuswb        m0, m1
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .hv_loop
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t4
+    add           dstq, strideq
+    ret
+.v:
+    mov            r10, wq
+    psrld          m13, m14, 16 ; y1 __
+.v_loop:
+    mova            m6, [t1+r10*2+ 0]
+    paddw           m2, m6, [t3+r10*2+ 0]
+    mova            m4, [t2+r10*2+ 0]
+    mova            m7, [t1+r10*2+32]
+    paddw           m3, m7, [t3+r10*2+32]
+    mova            m5, [t2+r10*2+32]
+    paddw           m6, [t4+r10*2+ 0]
+    paddw           m7, [t4+r10*2+32]
+    punpcklwd       m0, m2, m4
+    pmaddwd         m0, m15
+    punpckhwd       m2, m4
+    pmaddwd         m2, m15
+    punpcklwd       m1, m3, m5
+    pmaddwd         m1, m15
+    punpckhwd       m3, m5
+    pmaddwd         m3, m15
+    punpcklwd       m5, m7, m6
+    pmaddwd         m4, m5, m14
+    punpckhwd       m7, m6
+    pmaddwd         m6, m7, m14
+    pmaddwd         m5, m13
+    pmaddwd         m7, m13
+    paddd           m0, m4
+    paddd           m2, m6
+    paddd           m1, m5
+    paddd           m3, m7
+    packuswb        m0, m2
+    packuswb        m1, m3
+    psrlw           m0, 8
+    psrlw           m1, 8
+    packuswb        m0, m1
+    mova    [dstq+r10], m0
+    add            r10, 32
+    jl .v_loop
+    ret
+
+cglobal sgr_filter_5x5_8bpc, 4, 12, 16, 400*24+16, dst, stride, left, lpf, \
+                                                   w, h, edge, params
+    mov        paramsq, r6mp
+    mov             wd, wm
+    movifnidn       hd, hm
+    vbroadcasti128  m8, [sgr_shuf+0]
+    mov          edged, r7m
+    vbroadcasti128  m9, [sgr_shuf+8]
+    add           lpfq, wq
+    vbroadcasti128 m10, [sgr_shuf+2]
+    add           dstq, wq
+    vbroadcasti128 m11, [sgr_shuf+6]
+    lea             t3, [rsp+wq*4+16+400*12]
+    vpbroadcastw    m7, [paramsq+8] ; w0
+    pxor            m6, m6
+    vpbroadcastd   m12, [paramsq+0] ; s0
+    lea             t1, [rsp+wq*2+20]
+    vpbroadcastd   m13, [pw_164_24]
+    neg             wq
+    vbroadcastss   m14, [pf_256]
+    psllw           m7, 4
+    vpbroadcastd   m15, [pd_m4096]
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    call .top_fixup
+    add             t1, 400*6
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    mov             t0, t2
+    dec             hd
+    jz .height1
+    or           edged, 16
+    call .h
+.main:
+    add           lpfq, strideq
+    call .hv
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    test            hd, hd
+    jz .odd_height
+    call .h
+    add           lpfq, strideq
+    call .hv
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .h_top
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .hv
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .hv
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea             t2, [t1+400*6]
+    call .top_fixup
+    dec             hd
+    jz .no_top_height1
+    or           edged, 16
+    mov             t0, t1
+    mov             t1, t2
+    jmp .main
+.no_top_height1:
+    call .v
+    call .prep_n
+    jmp .odd_height_end
+.extend_right:
+    movd           xm2, r10d
+    mova            m0, [sgr_r_ext]
+    vpbroadcastb    m2, xm2
+    psubb           m0, m2
+    pminub          m0, [pb_0to63]
+    pshufb          m5, m0
+    ret
+.h: ; horizontal boxsum
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    vpbroadcastd   xm0, [leftq]
+    mova           xm5, [lpfq+wq]
+    palignr        xm5, xm0, 12
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    mova           xm5, [lpfq+wq]
+    pshufb         xm5, [sgr_l_shuf]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu           xm5, [lpfq+r10-2]
+.h_main:
+    vinserti128     m5, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -18
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    pshufb          m3, m5, m8
+    pmullw          m4, m3, m3
+    pshufb          m2, m5, m9
+    paddw           m0, m3, m2
+    shufps          m3, m2, q2121
+    paddw           m0, m3
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m1
+    punpckhwd       m2, m3
+    pmaddwd         m2, m2
+    punpcklwd       m3, m4, m6
+    paddd           m1, m3
+    punpckhwd       m4, m6
+    paddd           m2, m4
+    pshufb          m4, m5, m10
+    paddw           m0, m4
+    pshufb          m5, m11
+    paddw           m0, m5 ; sum
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m3
+    punpckhwd       m4, m5
+    pmaddwd         m4, m4
+    test         edgeb, 16 ; y > 0
+    jz .h_loop_end
+    paddw           m0, [t1+r10*2+400*0]
+    paddd           m1, [t1+r10*2+400*2]
+    paddd           m2, [t1+r10*2+400*4]
+.h_loop_end:
+    paddd           m1, m3 ; sumsq
+    paddd           m2, m4
+    mova [t1+r10*2+400*0], m0
+    mova [t1+r10*2+400*2], m1
+    mova [t1+r10*2+400*4], m2
+    add            r10, 16
+    jl .h_loop
+    ret
+.top_fixup:
+    lea            r10, [wq-2]
+.top_fixup_loop: ; the sums of the first row needs to be doubled
+    mova            m0, [t1+r10*2+400*0]
+    mova            m1, [t1+r10*2+400*2]
+    mova            m2, [t1+r10*2+400*4]
+    paddw           m0, m0
+    paddd           m1, m1
+    paddd           m2, m2
+    mova [t2+r10*2+400*0], m0
+    mova [t2+r10*2+400*2], m1
+    mova [t2+r10*2+400*4], m2
+    add            r10, 16
+    jl .top_fixup_loop
+    ret
+ALIGN function_align
+.hv: ; horizontal boxsum + vertical boxsum + ab
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    vpbroadcastd   xm0, [leftq]
+    mova           xm5, [lpfq+wq]
+    palignr        xm5, xm0, 12
+    add          leftq, 4
+    jmp .hv_main
+.hv_extend_left:
+    mova           xm5, [lpfq+wq]
+    pshufb         xm5, [sgr_l_shuf]
+    jmp .hv_main
+.hv_bottom:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu           xm5, [lpfq+r10-2]
+.hv_main:
+    vinserti128     m5, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -18
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    pshufb          m1, m5, m8
+    pmullw          m4, m1, m1
+    pshufb          m3, m5, m9
+    paddw           m0, m1, m3
+    shufps          m1, m3, q2121
+    paddw           m0, m1
+    punpcklwd       m2, m3, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m1
+    pmaddwd         m3, m3
+    punpcklwd       m1, m4, m6
+    paddd           m2, m1
+    punpckhwd       m4, m6
+    paddd           m3, m4
+    pshufb          m1, m5, m10
+    paddw           m0, m1
+    pshufb          m5, m11
+    paddw           m0, m5               ; h sum
+    punpcklwd       m4, m5, m1
+    pmaddwd         m4, m4
+    punpckhwd       m5, m1
+    pmaddwd         m5, m5
+    paddw           m1, m0, [t1+r10*2+400*0]
+    paddd           m2, m4               ; h sumsq
+    paddd           m3, m5
+    paddd           m4, m2, [t1+r10*2+400*2]
+    paddd           m5, m3, [t1+r10*2+400*4]
+    test            hd, hd
+    jz .hv_last_row
+.hv_main2:
+    paddw           m1, [t2+r10*2+400*0] ; hv sum
+    paddd           m4, [t2+r10*2+400*2] ; hv sumsq
+    paddd           m5, [t2+r10*2+400*4]
+    mova [t0+r10*2+400*0], m0
+    mova [t0+r10*2+400*2], m2
+    mova [t0+r10*2+400*4], m3
+    vpbroadcastd    m2, [pd_25]
+    punpcklwd       m0, m1, m6           ; b
+    punpckhwd       m1, m6
+    pmulld          m4, m2               ; a * 25
+    pmulld          m5, m2
+    pmaddwd         m2, m0, m0           ; b * b
+    pmaddwd         m3, m1, m1
+    psubd           m4, m2               ; p
+    psubd           m5, m3
+    pmulld          m4, m12              ; p * s
+    pmulld          m5, m12
+    pmaddwd         m0, m13              ; b * 164
+    pmaddwd         m1, m13
+    paddw           m4, m13
+    paddw           m5, m13
+    psrld           m4, 20               ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4               ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m14, m4
+    pcmpgtd         m5, m14, m5
+    mulps           m2, m14              ; 256 / (z + 1)
+    mulps           m3, m14
+    psrld           m4, 24               ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4               ; x
+    pminsw          m3, m5
+    vpbroadcastd    m4, [pd_34816]
+    pmulld          m0, m2
+    pmulld          m1, m3
+    paddd           m0, m4               ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m4
+    pand            m0, m15
+    pand            m1, m15
+    por             m0, m2               ; a | (b << 12)
+    por             m1, m3
+    mova         [t3+r10*4+ 8], xm0      ; The neighbor calculations requires
+    vextracti128 [t3+r10*4+40], m0, 1    ; 13 bits for a and 21 bits for b.
+    mova         [t3+r10*4+24], xm1      ; Packing them allows for 12+20, but
+    vextracti128 [t3+r10*4+56], m1, 1    ; that gets us most of the way.
+    add            r10, 16
+    jl .hv_loop
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t2
+    ret
+.hv_last_row: ; esoteric edge case for odd heights
+    mova [t1+r10*2+400*0], m1
+    paddw              m1, m0
+    mova [t1+r10*2+400*2], m4
+    paddd              m4, m2
+    mova [t1+r10*2+400*4], m5
+    paddd              m5, m3
+    jmp .hv_main2
+.v: ; vertical boxsum + ab
+    lea            r10, [wq-2]
+.v_loop:
+    mova            m0, [t1+r10*2+400*0]
+    mova            m2, [t1+r10*2+400*2]
+    mova            m3, [t1+r10*2+400*4]
+    paddw           m1, m0, [t2+r10*2+400*0]
+    paddd           m4, m2, [t2+r10*2+400*2]
+    paddd           m5, m3, [t2+r10*2+400*4]
+    paddw           m0, m0
+    paddd           m2, m2
+    paddd           m3, m3
+    paddw           m1, m0               ; hv sum
+    paddd           m4, m2               ; hv sumsq
+    paddd           m5, m3
+    vpbroadcastd    m2, [pd_25]
+    punpcklwd       m0, m1, m6           ; b
+    punpckhwd       m1, m6
+    pmulld          m4, m2               ; a * 25
+    pmulld          m5, m2
+    pmaddwd         m2, m0, m0           ; b * b
+    pmaddwd         m3, m1, m1
+    psubd           m4, m2               ; p
+    psubd           m5, m3
+    pmulld          m4, m12              ; p * s
+    pmulld          m5, m12
+    pmaddwd         m0, m13              ; b * 164
+    pmaddwd         m1, m13
+    paddw           m4, m13
+    paddw           m5, m13
+    psrld           m4, 20               ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4               ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m14, m4
+    pcmpgtd         m5, m14, m5
+    mulps           m2, m14              ; 256 / (z + 1)
+    mulps           m3, m14
+    psrld           m4, 24               ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4               ; x
+    pminsw          m3, m5
+    vpbroadcastd    m4, [pd_34816]
+    pmulld          m0, m2
+    pmulld          m1, m3
+    paddd           m0, m4               ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m4
+    pand            m0, m15
+    pand            m1, m15
+    por             m0, m2               ; a | (b << 12)
+    por             m1, m3
+    mova         [t3+r10*4+ 8], xm0
+    vextracti128 [t3+r10*4+40], m0, 1
+    mova         [t3+r10*4+24], xm1
+    vextracti128 [t3+r10*4+56], m1, 1
+    add            r10, 16
+    jl .v_loop
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    movu            m0, [t3+r10*4+ 4]
+    movu            m1, [t3+r10*4+36]
+    paddd           m2, m0, [t3+r10*4+ 0]
+    paddd           m3, m1, [t3+r10*4+32]
+    paddd           m2, [t3+r10*4+ 8]
+    paddd           m3, [t3+r10*4+40]
+    paddd           m0, m2
+    pslld           m2, 2
+    paddd           m1, m3
+    pslld           m3, 2
+    paddd           m2, m0                ; ab 565
+    paddd           m3, m1
+    pandn           m0, m15, m2           ; a
+    psrld           m2, 12                ; b
+    pandn           m1, m15, m3
+    psrld           m3, 12
+    mova [t3+r10*4+400*4+ 0], m0
+    mova [t3+r10*4+400*8+ 0], m2
+    mova [t3+r10*4+400*4+32], m1
+    mova [t3+r10*4+400*8+32], m3
+    add            r10, 16
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    movu            m0, [t3+r10*4+ 4]
+    movu            m1, [t3+r10*4+36]
+    paddd           m2, m0, [t3+r10*4+ 0]
+    paddd           m3, m1, [t3+r10*4+32]
+    paddd           m2, [t3+r10*4+ 8]
+    paddd           m3, [t3+r10*4+40]
+    paddd           m0, m2
+    pslld           m2, 2
+    paddd           m1, m3
+    pslld           m3, 2
+    paddd           m2, m0
+    paddd           m3, m1
+    pandn           m0, m15, m2
+    psrld           m2, 12
+    pandn           m1, m15, m3
+    psrld           m3, 12
+    paddd           m4, m0, [t3+r10*4+400*4+ 0] ; a
+    paddd           m5, m1, [t3+r10*4+400*4+32]
+    mova [t3+r10*4+400*4+ 0], m0
+    mova [t3+r10*4+400*4+32], m1
+    paddd           m0, m2, [t3+r10*4+400*8+ 0] ; b
+    paddd           m1, m3, [t3+r10*4+400*8+32]
+    mova [t3+r10*4+400*8+ 0], m2
+    mova [t3+r10*4+400*8+32], m3
+    pmovzxbd        m2, [dstq+r10+0]
+    pmovzxbd        m3, [dstq+r10+8]
+    pmaddwd         m4, m2 ; a * src
+    pmaddwd         m5, m3
+    packssdw        m2, m3
+    psubd           m0, m4 ; b - a * src + (1 << 8)
+    psubd           m1, m5
+    psrad           m0, 9
+    psrad           m1, 9
+    packssdw        m0, m1
+    pmulhrsw        m0, m7
+    paddw           m0, m2
+    vextracti128   xm1, m0, 1
+    packuswb       xm0, xm1
+    pshufd         xm0, xm0, q3120
+    mova    [dstq+r10], xm0
+    add            r10, 16
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    pmovzxbd        m2, [dstq+r10+0]
+    pmovzxbd        m3, [dstq+r10+8]
+    pmaddwd         m4, m2, [t3+r10*4+400*4+ 0] ; a * src
+    pmaddwd         m5, m3, [t3+r10*4+400*4+32]
+    mova            m0, [t3+r10*4+400*8+ 0]     ; b
+    mova            m1, [t3+r10*4+400*8+32]
+    packssdw        m2, m3
+    psubd           m0, m4                      ; b - a * src + (1 << 7)
+    psubd           m1, m5
+    psrad           m0, 8
+    psrad           m1, 8
+    packssdw        m0, m1
+    pmulhrsw        m0, m7
+    paddw           m0, m2
+    vextracti128   xm1, m0, 1
+    packuswb       xm0, xm1
+    pshufd         xm0, xm0, q3120
+    mova    [dstq+r10], xm0
+    add            r10, 16
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_3x3_8bpc, 4, 14, 16, -400*28-16, dst, stride, left, lpf, \
+                                                    w, h, edge, params
+    mov        paramsq, r6mp
+    mov             wd, wm
+    movifnidn       hd, hm
+    vbroadcasti128  m8, [sgr_shuf+2]
+    mov          edged, r7m
+    vbroadcasti128  m9, [sgr_shuf+4]
+    add           lpfq, wq
+    vbroadcasti128 m10, [sgr_shuf+6]
+    add           dstq, wq
+    vpbroadcastw    m7, [paramsq+10] ; w1
+    lea             t3, [rsp+wq*4+16+400*12]
+    vpbroadcastd   m11, [paramsq+ 4] ; s1
+    pxor            m6, m6
+    vpbroadcastd   m12, [pw_455_24]
+    lea             t1, [rsp+wq*2+20]
+    vbroadcastss   m13, [pf_256]
+    neg             wq
+    vpbroadcastd   m14, [pd_34816] ; (1 << 11) + (1 << 15)
+    psllw           m7, 4
+    vpbroadcastd   m15, [pd_m4096]
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    add             t1, 400*6
+    call .h_top
+    lea             t4, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add             t4, strideq
+    mov          [rsp], t4 ; below
+    mov             t0, t2
+    call .hv
+.main:
+    mov             t5, t3
+    add             t3, 400*4
+    dec             hd
+    jz .height1
+    add           lpfq, strideq
+    call .hv
+    call .prep_n
+    dec             hd
+    jz .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    call .hv
+    call .n
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    call .n
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    call .n
+    RET
+.height1:
+    call .v
+    call .prep_n
+    mov             t2, t1
+    call .v
+    jmp .end
+.extend_bottom:
+    call .v
+    call .n
+    mov             t2, t1
+    call .v
+    jmp .end
+.no_top:
+    lea             t4, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea             t4, [t4+strideq*2]
+    mov          [rsp], t4
+    call .h
+    lea             t0, [t1+400*6]
+    mov             t2, t1
+    call .v
+    jmp .main
+.h: ; horizontal boxsum
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    vpbroadcastd   xm0, [leftq]
+    mova           xm5, [lpfq+wq]
+    palignr        xm5, xm0, 12
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    mova           xm5, [lpfq+wq]
+    pshufb         xm5, [sgr_l_shuf]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu           xm5, [lpfq+r10-2]
+.h_main:
+    vinserti128     m5, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -17
+    jl .h_have_right
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_avx2).extend_right
+.h_have_right:
+    pshufb          m0, m5, m8
+    pmullw          m2, m0, m0
+    pshufb          m4, m5, m9
+    paddw           m0, m4
+    pshufb          m5, m10
+    paddw           m0, m5 ; sum
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m3
+    punpckhwd       m4, m5
+    pmaddwd         m4, m4
+    punpcklwd       m1, m2, m6
+    punpckhwd       m2, m6
+    mova [t1+r10*2+400*0], m0
+    paddd           m1, m3 ; sumsq
+    paddd           m2, m4
+    mova [t1+r10*2+400*2], m1
+    mova [t1+r10*2+400*4], m2
+    add            r10, 16
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv: ; horizontal boxsum + vertical boxsum + ab
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    vpbroadcastd   xm0, [leftq]
+    mova           xm5, [lpfq+wq]
+    palignr        xm5, xm0, 12
+    add          leftq, 4
+    jmp .hv_main
+.hv_extend_left:
+    mova           xm5, [lpfq+wq]
+    pshufb         xm5, [sgr_l_shuf]
+    jmp .hv_main
+.hv_bottom:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu           xm5, [lpfq+r10-2]
+.hv_main:
+    vinserti128     m5, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -17
+    jl .hv_have_right
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_avx2).extend_right
+.hv_have_right:
+    pshufb          m0, m5, m8
+    pmullw          m3, m0, m0
+    pshufb          m1, m5, m9
+    paddw           m0, m1
+    pshufb          m5, m10
+    paddw           m0, m5               ; h sum
+    punpcklwd       m4, m5, m1
+    pmaddwd         m4, m4
+    punpckhwd       m5, m1
+    pmaddwd         m5, m5
+    paddw           m1, m0, [t2+r10*2+400*0]
+    paddw           m1, [t1+r10*2+400*0] ; hv sum
+    punpcklwd       m2, m3, m6
+    punpckhwd       m3, m6
+    paddd           m4, m2               ; h sumsq
+    paddd           m5, m3
+    paddd           m2, m4, [t2+r10*2+400*2]
+    paddd           m3, m5, [t2+r10*2+400*4]
+    paddd           m2, [t1+r10*2+400*2] ; hv sumsq
+    paddd           m3, [t1+r10*2+400*4]
+    mova [t0+r10*2+400*0], m0
+    punpcklwd       m0, m1, m6           ; b
+    punpckhwd       m1, m6
+    mova [t0+r10*2+400*2], m4
+    pslld           m4, m2, 3
+    mova [t0+r10*2+400*4], m5
+    pslld           m5, m3, 3
+    paddd           m4, m2               ; a * 9
+    pmaddwd         m2, m0, m0           ; b * b
+    paddd           m5, m3
+    pmaddwd         m3, m1, m1
+    psubd           m4, m2               ; p
+    psubd           m5, m3
+    pmulld          m4, m11              ; p * s
+    pmulld          m5, m11
+    pmaddwd         m0, m12              ; b * 455
+    pmaddwd         m1, m12
+    paddw           m4, m12
+    paddw           m5, m12
+    psrld           m4, 20               ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4               ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m13, m4
+    pcmpgtd         m5, m13, m5
+    mulps           m2, m13              ; 256 / (z + 1)
+    mulps           m3, m13
+    psrld           m4, 24               ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4               ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    paddd           m0, m14              ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m14
+    pand            m0, m15
+    pand            m1, m15
+    por             m0, m2               ; a | (b << 12)
+    por             m1, m3
+    mova         [t3+r10*4+ 8], xm0
+    vextracti128 [t3+r10*4+40], m0, 1
+    mova         [t3+r10*4+24], xm1
+    vextracti128 [t3+r10*4+56], m1, 1
+    add            r10, 16
+    jl .hv_loop
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t2
+    ret
+.v: ; vertical boxsum + ab
+    lea            r10, [wq-2]
+.v_loop:
+    mova            m1, [t1+r10*2+400*0]
+    paddw           m1, m1
+    paddw           m1, [t2+r10*2+400*0] ; hv sum
+    mova            m2, [t1+r10*2+400*2]
+    mova            m3, [t1+r10*2+400*4]
+    paddd           m2, m2
+    paddd           m3, m3
+    paddd           m2, [t2+r10*2+400*2] ; hv sumsq
+    paddd           m3, [t2+r10*2+400*4]
+    punpcklwd       m0, m1, m6           ; b
+    punpckhwd       m1, m6
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2               ; a * 9
+    pmaddwd         m2, m0, m0           ; b * b
+    paddd           m5, m3
+    pmaddwd         m3, m1, m1
+    psubd           m4, m2               ; p
+    psubd           m5, m3
+    pmulld          m4, m11              ; p * s
+    pmulld          m5, m11
+    pmaddwd         m0, m12              ; b * 455
+    pmaddwd         m1, m12
+    paddw           m4, m12
+    paddw           m5, m12
+    psrld           m4, 20               ; z + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4               ; 1 / (z + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m13, m4
+    pcmpgtd         m5, m13, m5
+    mulps           m2, m13              ; 256 / (z + 1)
+    mulps           m3, m13
+    psrld           m4, 24               ; z < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4               ; x
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    paddd           m0, m14              ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m14
+    pand            m0, m15
+    pand            m1, m15
+    por             m0, m2               ; a | (b << 12)
+    por             m1, m3
+    mova         [t3+r10*4+ 8], xm0
+    vextracti128 [t3+r10*4+40], m0, 1
+    mova         [t3+r10*4+24], xm1
+    vextracti128 [t3+r10*4+56], m1, 1
+    add            r10, 16
+    jl .v_loop
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+    mov             t4, t3
+    add             t3, 400*4
+.prep_n_loop:
+    mova            m2, [t5+r10*4+0]
+    mova            m3, [t4+r10*4+0]
+    paddd           m2, [t5+r10*4+8]
+    paddd           m3, [t4+r10*4+8]
+    paddd           m0, m2, [t5+r10*4+4]
+    paddd           m1, m3, [t4+r10*4+4]
+    pslld           m0, 2
+    paddd           m1, m1                ; ab[ 0] 222
+    psubd           m0, m2                ; ab[-1] 343
+    mova [t3+r10*4+400*4], m1
+    paddd           m1, m1
+    mova    [t5+r10*4], m0
+    psubd           m1, m3                ; ab[ 0] 343
+    mova    [t4+r10*4], m1
+    add            r10, 8
+    jl .prep_n_loop
+    ret
+; a+b are packed together in a single dword, but we can't do the
+; full neighbor calculations before splitting them since we don't
+; have sufficient precision. The solution is to do the calculations
+; in two equal halves and split a and b before doing the final sum.
+ALIGN function_align
+.n: ; neighbor + output
+    mov            r10, wq
+.n_loop:
+    mova            m4, [t3+r10*4+ 0]
+    paddd           m4, [t3+r10*4+ 8]
+    paddd           m5, m4, [t3+r10*4+ 4]
+    paddd           m5, m5                ; ab[+1] 222
+    mova            m2, [t3+r10*4+400*4+ 0]
+    paddd           m0, m2, [t5+r10*4+ 0] ; ab[ 0] 222 + ab[-1] 343
+    mova            m3, [t3+r10*4+400*4+32]
+    paddd           m1, m3, [t5+r10*4+32]
+    mova [t3+r10*4+400*4+ 0], m5
+    paddd           m5, m5
+    psubd           m5, m4                ; ab[+1] 343
+    mova [t5+r10*4+ 0], m5
+    paddd           m2, m5                ; ab[ 0] 222 + ab[+1] 343
+    mova            m4, [t3+r10*4+32]
+    paddd           m4, [t3+r10*4+40]
+    paddd           m5, m4, [t3+r10*4+36]
+    paddd           m5, m5
+    mova [t3+r10*4+400*4+32], m5
+    paddd           m5, m5
+    psubd           m5, m4
+    mova [t5+r10*4+32], m5
+    pandn           m4, m15, m0
+    psrld           m0, 12
+    paddd           m3, m5
+    pandn           m5, m15, m2
+    psrld           m2, 12
+    paddd           m4, m5                ; a
+    pandn           m5, m15, m1
+    psrld           m1, 12
+    paddd           m0, m2                ; b + (1 << 8)
+    pandn           m2, m15, m3
+    psrld           m3, 12
+    paddd           m5, m2
+    pmovzxbd        m2, [dstq+r10+0]
+    paddd           m1, m3
+    pmovzxbd        m3, [dstq+r10+8]
+    pmaddwd         m4, m2                ; a * src
+    pmaddwd         m5, m3
+    packssdw        m2, m3
+    psubd           m0, m4                ; b - a * src + (1 << 8)
+    psubd           m1, m5
+    psrad           m0, 9
+    psrad           m1, 9
+    packssdw        m0, m1
+    pmulhrsw        m0, m7
+    paddw           m0, m2
+    vextracti128   xm1, m0, 1
+    packuswb       xm0, xm1
+    pshufd         xm0, xm0, q3120
+    mova    [dstq+r10], xm0
+    add            r10, 16
+    jl .n_loop
+    mov            r10, t5
+    mov             t5, t4
+    mov             t4, r10
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_mix_8bpc, 4, 12, 16, 400*56+8, dst, stride, left, lpf, \
+                                                  w, h, edge, params
+    mov        paramsq, r6mp
+    mov             wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    vbroadcasti128  m9, [sgr_shuf+0]
+    vbroadcasti128 m10, [sgr_shuf+8]
+    add           lpfq, wq
+    vbroadcasti128 m11, [sgr_shuf+2]
+    vbroadcasti128 m12, [sgr_shuf+6]
+    add           dstq, wq
+    vpbroadcastd   m15, [paramsq+8] ; w0 w1
+    lea             t3, [rsp+wq*4+400*24+8]
+    vpbroadcastd   m13, [paramsq+0] ; s0
+    pxor            m7, m7
+    vpbroadcastd   m14, [paramsq+4] ; s1
+    lea             t1, [rsp+wq*2+12]
+    neg             wq
+    psllw          m15, 2 ; to reuse existing pd_m4096 register for rounding
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_avx2).top_fixup
+    add             t1, 400*12
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    add           lpfq, strideq
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    call .hv0
+    test            hd, hd
+    jz .odd_height
+    add           lpfq, strideq
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .hv0_bottom
+    add           lpfq, strideq
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea             t2, [t1+400*12]
+    lea            r10, [wq-2]
+.top_fixup_loop:
+    mova            m0, [t1+r10*2+400* 0]
+    mova            m1, [t1+r10*2+400* 2]
+    mova            m2, [t1+r10*2+400* 4]
+    paddw           m0, m0
+    mova            m3, [t1+r10*2+400* 6]
+    paddd           m1, m1
+    mova            m4, [t1+r10*2+400* 8]
+    paddd           m2, m2
+    mova            m5, [t1+r10*2+400*10]
+    mova [t2+r10*2+400* 0], m0
+    mova [t2+r10*2+400* 2], m1
+    mova [t2+r10*2+400* 4], m2
+    mova [t2+r10*2+400* 6], m3
+    mova [t2+r10*2+400* 8], m4
+    mova [t2+r10*2+400*10], m5
+    add            r10, 16
+    jl .top_fixup_loop
+    call .v0
+    jmp .main
+.h: ; horizontal boxsums
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    vpbroadcastd   xm0, [leftq]
+    mova           xm5, [lpfq+wq]
+    palignr        xm5, xm0, 12
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    mova           xm5, [lpfq+wq]
+    pshufb         xm5, [sgr_l_shuf]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu           xm5, [lpfq+r10-2]
+.h_main:
+    vinserti128     m5, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -18
+    jl .h_have_right
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_avx2).extend_right
+.h_have_right:
+    pshufb          m6, m5, m9
+    pshufb          m4, m5, m10
+    paddw           m8, m6, m4
+    shufps          m0, m6, m4, q2121
+    pmullw          m3, m0, m0
+    pshufb          m2, m5, m11
+    paddw           m0, m2
+    pshufb          m5, m12
+    paddw           m0, m5 ; sum3
+    punpcklwd       m1, m2, m5
+    pmaddwd         m1, m1
+    punpckhwd       m2, m5
+    pmaddwd         m2, m2
+    punpcklwd       m5, m6, m4
+    pmaddwd         m5, m5
+    punpckhwd       m6, m4
+    pmaddwd         m6, m6
+    punpcklwd       m4, m3, m7
+    paddd           m1, m4 ; sumsq3
+    punpckhwd       m3, m7
+    paddd           m2, m3
+    mova [t1+r10*2+400* 6], m0
+    mova [t1+r10*2+400* 8], m1
+    mova [t1+r10*2+400*10], m2
+    paddw           m8, m0 ; sum5
+    paddd           m5, m1 ; sumsq5
+    paddd           m6, m2
+    mova [t1+r10*2+400* 0], m8
+    mova [t1+r10*2+400* 2], m5
+    mova [t1+r10*2+400* 4], m6
+    add            r10, 16
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsums + vertical boxsum3 + ab3 (even rows)
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    vpbroadcastd   xm0, [leftq]
+    mova           xm5, [lpfq+wq]
+    palignr        xm5, xm0, 12
+    add          leftq, 4
+    jmp .hv0_main
+.hv0_extend_left:
+    mova           xm5, [lpfq+wq]
+    pshufb         xm5, [sgr_l_shuf]
+    jmp .hv0_main
+.hv0_bottom:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+.hv0_loop:
+    movu           xm5, [lpfq+r10-2]
+.hv0_main:
+    vinserti128     m5, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp           r10d, -18
+    jl .hv0_have_right
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_avx2).extend_right
+.hv0_have_right:
+    pshufb          m6, m5, m9
+    pshufb          m4, m5, m10
+    paddw           m8, m6, m4
+    shufps          m1, m6, m4, q2121
+    pmullw          m0, m1, m1
+    pshufb          m3, m5, m11
+    paddw           m1, m3
+    pshufb          m5, m12
+    paddw           m1, m5 ; sum3
+    punpcklwd       m2, m3, m5
+    pmaddwd         m2, m2
+    punpckhwd       m3, m5
+    pmaddwd         m3, m3
+    punpcklwd       m5, m6, m4
+    pmaddwd         m5, m5
+    punpckhwd       m6, m4
+    pmaddwd         m6, m6
+    punpcklwd       m4, m0, m7
+    paddd           m2, m4 ; sumsq3
+    punpckhwd       m0, m7
+    paddd           m3, m0
+    paddw           m8, m1 ; sum5
+    paddd           m5, m2 ; sumsq5
+    paddd           m6, m3
+    mova [t3+r10*4+400*8+ 8], m8 ; we need a clean copy of the last row
+    mova [t3+r10*4+400*0+ 8], m5 ; in case height is odd
+    mova [t3+r10*4+400*0+40], m6
+    paddw           m8, [t1+r10*2+400* 0]
+    paddd           m5, [t1+r10*2+400* 2]
+    paddd           m6, [t1+r10*2+400* 4]
+    mova [t1+r10*2+400* 0], m8
+    mova [t1+r10*2+400* 2], m5
+    mova [t1+r10*2+400* 4], m6
+    paddw           m0, m1, [t1+r10*2+400* 6]
+    paddd           m4, m2, [t1+r10*2+400* 8]
+    paddd           m5, m3, [t1+r10*2+400*10]
+    mova [t1+r10*2+400* 6], m1
+    mova [t1+r10*2+400* 8], m2
+    mova [t1+r10*2+400*10], m3
+    paddw           m1, m0, [t2+r10*2+400* 6]
+    paddd           m2, m4, [t2+r10*2+400* 8]
+    paddd           m3, m5, [t2+r10*2+400*10]
+    mova [t2+r10*2+400* 6], m0
+    mova [t2+r10*2+400* 8], m4
+    mova [t2+r10*2+400*10], m5
+    vpbroadcastd    m8, [pw_455_24]
+    punpcklwd       m0, m1, m7           ; b3
+    vbroadcastss    m6, [pf_256]
+    punpckhwd       m1, m7
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2               ; a3 * 9
+    pmaddwd         m2, m0, m0           ; b3 * b
+    paddd           m5, m3
+    pmaddwd         m3, m1, m1
+    psubd           m4, m2               ; p3
+    psubd           m5, m3
+    pmulld          m4, m14              ; p3 * s1
+    pmulld          m5, m14
+    pmaddwd         m0, m8               ; b3 * 455
+    pmaddwd         m1, m8
+    paddw           m4, m8
+    paddw           m5, m8
+    vpbroadcastd    m8, [pd_34816]
+    psrld           m4, 20               ; z3 + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4               ; 1 / (z3 + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m6, m4
+    pcmpgtd         m5, m6, m5
+    mulps           m2, m6               ; 256 / (z3 + 1)
+    mulps           m3, m6
+    vpbroadcastd    m6, [pd_m4096]
+    psrld           m4, 24               ; z3 < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4               ; x3
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    paddd           m0, m8               ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m8
+    pand            m0, m6
+    pand            m1, m6
+    por             m0, m2               ; a3 | (b3 << 12)
+    por             m1, m3
+    mova         [t3+r10*4+400*4+ 8], xm0
+    vextracti128 [t3+r10*4+400*4+40], m0, 1
+    mova         [t3+r10*4+400*4+24], xm1
+    vextracti128 [t3+r10*4+400*4+56], m1, 1
+    add            r10, 16
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    vpbroadcastd   xm0, [leftq]
+    mova           xm5, [lpfq+wq]
+    palignr        xm5, xm0, 12
+    add          leftq, 4
+    jmp .hv1_main
+.hv1_extend_left:
+    mova           xm5, [lpfq+wq]
+    pshufb         xm5, [sgr_l_shuf]
+    jmp .hv1_main
+.hv1_bottom:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+.hv1_loop:
+    movu           xm5, [lpfq+r10-2]
+.hv1_main:
+    vinserti128     m5, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp           r10d, -18
+    jl .hv1_have_right
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_avx2).extend_right
+.hv1_have_right:
+    pshufb          m6, m5, m9
+    pshufb          m3, m5, m10
+    paddw           m8, m6, m3
+    shufps          m2, m6, m3, q2121
+    pmullw          m1, m2, m2
+    pshufb          m0, m5, m11
+    paddw           m2, m0
+    pshufb          m5, m12
+    paddw           m2, m5 ; sum3
+    punpcklwd       m4, m5, m0
+    pmaddwd         m4, m4
+    punpckhwd       m5, m0
+    pmaddwd         m5, m5
+    punpcklwd       m0, m6, m3
+    pmaddwd         m0, m0
+    punpckhwd       m6, m3
+    pmaddwd         m6, m6
+    punpcklwd       m3, m1, m7
+    paddd           m4, m3 ; sumsq3
+    punpckhwd       m1, m7
+    paddd           m5, m1
+    paddw           m1, m2, [t2+r10*2+400* 6]
+    mova [t2+r10*2+400* 6], m2
+    paddw           m8, m2 ; sum5
+    paddd           m2, m4, [t2+r10*2+400* 8]
+    paddd           m3, m5, [t2+r10*2+400*10]
+    mova [t2+r10*2+400* 8], m4
+    mova [t2+r10*2+400*10], m5
+    vpbroadcastd    m9, [pw_455_24]
+    paddd           m4, m0 ; sumsq5
+    paddd           m5, m6
+    punpcklwd       m0, m1, m7           ; b3
+    punpckhwd       m1, m7
+    pslld           m6, m2, 3
+    pslld           m7, m3, 3
+    paddd           m6, m2               ; a3 * 9
+    pmaddwd         m2, m0, m0           ; b3 * b3
+    paddd           m7, m3
+    pmaddwd         m3, m1, m1
+    psubd           m6, m2               ; p3
+    psubd           m7, m3
+    pmulld          m6, m14              ; p3 * s1
+    pmulld          m7, m14
+    pmaddwd         m0, m9               ; b3 * 455
+    pmaddwd         m1, m9
+    paddw           m6, m9
+    paddw           m7, m9
+    vbroadcastss    m9, [pf_256]
+    psrld           m6, 20               ; z3 + 1
+    psrld           m7, 20
+    cvtdq2ps        m6, m6
+    cvtdq2ps        m7, m7
+    rcpps           m2, m6               ; 1 / (z3 + 1)
+    rcpps           m3, m7
+    pcmpgtd         m6, m9, m6
+    pcmpgtd         m7, m9, m7
+    mulps           m2, m9               ; 256 / (z3 + 1)
+    mulps           m3, m9
+    vpbroadcastd    m9, [pd_34816]
+    psrld           m6, 24               ; z3 < 255 ? 255 : 0
+    psrld           m7, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m6               ; x3
+    vpbroadcastd    m6, [pd_m4096]
+    pminsw          m3, m7
+    pmulld          m0, m2
+    pmulld          m1, m3
+    paddd           m0, m9               ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m9
+    pand            m0, m6
+    pand            m7, m6, m1
+    por             m0, m2               ; a3 | (b3 << 12)
+    por             m7, m3
+    paddw           m1, m8, [t2+r10*2+400*0]
+    paddd           m2, m4, [t2+r10*2+400*2]
+    paddd           m3, m5, [t2+r10*2+400*4]
+    paddw           m1, [t1+r10*2+400*0]
+    paddd           m2, [t1+r10*2+400*2]
+    paddd           m3, [t1+r10*2+400*4]
+    mova [t2+r10*2+400*0], m8
+    mova [t2+r10*2+400*2], m4
+    mova [t2+r10*2+400*4], m5
+    mova         [t3+r10*4+400*8+ 8], xm0
+    vextracti128 [t3+r10*4+400*8+40], m0, 1
+    mova         [t3+r10*4+400*8+24], xm7
+    vextracti128 [t3+r10*4+400*8+56], m7, 1
+    vpbroadcastd    m4, [pd_25]
+    pxor            m7, m7
+    vpbroadcastd    m8, [pw_164_24]
+    punpcklwd       m0, m1, m7           ; b5
+    punpckhwd       m1, m7
+    pmulld          m2, m4               ; a5 * 25
+    pmulld          m3, m4
+    pmaddwd         m4, m0, m0           ; b5 * b5
+    pmaddwd         m5, m1, m1
+    psubd           m2, m4               ; p5
+    psubd           m3, m5
+    pmulld          m2, m13              ; p5 * s0
+    pmulld          m3, m13
+    pmaddwd         m0, m8               ; b5 * 164
+    pmaddwd         m1, m8
+    paddw           m2, m8
+    paddw           m3, m8
+    vbroadcastss    m8, [pf_256]
+    psrld           m2, 20               ; z5 + 1
+    psrld           m3, 20
+    cvtdq2ps        m2, m2
+    cvtdq2ps        m3, m3
+    rcpps           m4, m2               ; 1 / (z5 + 1)
+    rcpps           m5, m3
+    pcmpgtd         m2, m8, m2
+    pcmpgtd         m3, m8, m3
+    mulps           m4, m8               ; 256 / (z5 + 1)
+    mulps           m5, m8
+    psrld           m2, 24               ; z5 < 255 ? 255 : 0
+    psrld           m3, 24
+    cvtps2dq        m4, m4
+    cvtps2dq        m5, m5
+    pminsw          m4, m2               ; x5
+    pminsw          m5, m3
+    pmulld          m0, m4
+    pmulld          m1, m5
+    paddd           m0, m9               ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m9
+    vbroadcasti128  m9, [sgr_shuf]
+    pand            m0, m6
+    pand            m1, m6
+    por             m0, m4               ; a5 | (b5 << 12)
+    por             m1, m5
+    mova         [t3+r10*4+400*0+ 8], xm0
+    vextracti128 [t3+r10*4+400*0+40], m0, 1
+    mova         [t3+r10*4+400*0+24], xm1
+    vextracti128 [t3+r10*4+400*0+56], m1, 1
+    add            r10, 16
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab3 (even rows)
+    lea            r10, [wq-2]
+    vpbroadcastd    m6, [pd_34816]
+.v0_loop:
+    mova            m0, [t1+r10*2+400* 6]
+    mova            m4, [t1+r10*2+400* 8]
+    mova            m5, [t1+r10*2+400*10]
+    paddw           m0, m0
+    paddd           m4, m4
+    paddd           m5, m5
+    paddw           m1, m0, [t2+r10*2+400* 6]
+    paddd           m2, m4, [t2+r10*2+400* 8]
+    paddd           m3, m5, [t2+r10*2+400*10]
+    mova [t2+r10*2+400* 6], m0
+    mova [t2+r10*2+400* 8], m4
+    mova [t2+r10*2+400*10], m5
+    vpbroadcastd    m8, [pw_455_24]
+    punpcklwd       m0, m1, m7           ; b3
+    punpckhwd       m1, m7
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2               ; a3 * 9
+    pmaddwd         m2, m0, m0           ; b3 * b3
+    paddd           m5, m3
+    pmaddwd         m3, m1, m1
+    psubd           m4, m2               ; p3
+    psubd           m5, m3
+    pmulld          m4, m14              ; p3 * s1
+    pmulld          m5, m14
+    pmaddwd         m0, m8               ; b3 * 455
+    pmaddwd         m1, m8
+    paddw           m4, m8
+    paddw           m5, m8
+    vbroadcastss    m8, [pf_256]
+    psrld           m4, 20               ; z3 + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4               ; 1 / (z3 + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m8, m4
+    pcmpgtd         m5, m8, m5
+    mulps           m2, m8               ; 256 / (z3 + 1)
+    mulps           m3, m8
+    vpbroadcastd    m8, [pd_m4096]
+    psrld           m4, 24               ; z3 < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4               ; x3
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    paddd           m0, m6               ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m6
+    pand            m0, m8
+    pand            m1, m8
+    por             m0, m2               ; a3 | (b3 << 12)
+    por             m1, m3
+    mova            m2, [t1+r10*2+400*0]
+    mova            m3, [t1+r10*2+400*2]
+    mova            m4, [t1+r10*2+400*4]
+    mova [t3+r10*4+400*8+ 8], m2
+    mova [t3+r10*4+400*0+ 8], m3
+    mova [t3+r10*4+400*0+40], m4
+    paddw           m2, m2               ; cc5
+    paddd           m3, m3
+    paddd           m4, m4
+    mova [t1+r10*2+400*0], m2
+    mova [t1+r10*2+400*2], m3
+    mova [t1+r10*2+400*4], m4
+    mova         [t3+r10*4+400*4+ 8], xm0
+    vextracti128 [t3+r10*4+400*4+40], m0, 1
+    mova         [t3+r10*4+400*4+24], xm1
+    vextracti128 [t3+r10*4+400*4+56], m1, 1
+    add            r10, 16
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+    lea            r10, [wq-2]
+.v1_loop:
+    mova            m4, [t1+r10*2+400* 6]
+    mova            m5, [t1+r10*2+400* 8]
+    mova            m6, [t1+r10*2+400*10]
+    paddw           m1, m4, [t2+r10*2+400* 6]
+    paddd           m2, m5, [t2+r10*2+400* 8]
+    paddd           m3, m6, [t2+r10*2+400*10]
+    mova [t2+r10*2+400* 6], m4
+    mova [t2+r10*2+400* 8], m5
+    mova [t2+r10*2+400*10], m6
+    vpbroadcastd    m8, [pw_455_24]
+    punpcklwd       m0, m1, m7           ; b3
+    punpckhwd       m1, m7
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2               ; a3 * 9
+    pmaddwd         m2, m0, m0           ; b3 * b3
+    paddd           m5, m3
+    pmaddwd         m3, m1, m1
+    psubd           m4, m2               ; p3
+    psubd           m5, m3
+    pmulld          m4, m14              ; p3 * s1
+    pmulld          m5, m14
+    pmaddwd         m0, m8               ; b3 * 455
+    pmaddwd         m1, m8
+    paddw           m4, m8
+    paddw           m5, m8
+    vbroadcastss    m8, [pf_256]
+    psrld           m4, 20               ; z3 + 1
+    psrld           m5, 20
+    cvtdq2ps        m4, m4
+    cvtdq2ps        m5, m5
+    rcpps           m2, m4               ; 1 / (z3 + 1)
+    rcpps           m3, m5
+    pcmpgtd         m4, m8, m4
+    pcmpgtd         m5, m8, m5
+    mulps           m2, m8               ; 256 / (z3 + 1)
+    mulps           m3, m8
+    vpbroadcastd    m8, [pd_m4096]
+    psrld           m4, 24               ; z3 < 255 ? 255 : 0
+    psrld           m5, 24
+    cvtps2dq        m2, m2
+    cvtps2dq        m3, m3
+    pminsw          m2, m4               ; x3
+    vpbroadcastd    m4, [pd_34816]
+    pminsw          m3, m5
+    pmulld          m0, m2
+    pmulld          m1, m3
+    paddd           m0, m4               ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m4
+    pand            m0, m8
+    pand            m8, m1
+    por             m0, m2               ; a3 | (b3 << 12)
+    por             m8, m3
+    mova            m4, [t3+r10*4+400*8+ 8]
+    mova            m5, [t3+r10*4+400*0+ 8]
+    mova            m6, [t3+r10*4+400*0+40]
+    paddw           m1, m4, [t2+r10*2+400*0]
+    paddd           m2, m5, [t2+r10*2+400*2]
+    paddd           m3, m6, [t2+r10*2+400*4]
+    paddw           m1, [t1+r10*2+400*0]
+    paddd           m2, [t1+r10*2+400*2]
+    paddd           m3, [t1+r10*2+400*4]
+    mova [t2+r10*2+400*0], m4
+    mova [t2+r10*2+400*2], m5
+    mova [t2+r10*2+400*4], m6
+    vpbroadcastd    m4, [pd_25]
+    mova         [t3+r10*4+400*8+ 8], xm0
+    vextracti128 [t3+r10*4+400*8+40], m0, 1
+    mova         [t3+r10*4+400*8+24], xm8
+    vextracti128 [t3+r10*4+400*8+56], m8, 1
+    vpbroadcastd    m8, [pw_164_24]
+    punpcklwd       m0, m1, m7           ; b5
+    vbroadcastss    m6, [pf_256]
+    punpckhwd       m1, m7
+    pmulld          m2, m4               ; a5 * 25
+    pmulld          m3, m4
+    pmaddwd         m4, m0, m0           ; b5 * b5
+    pmaddwd         m5, m1, m1
+    psubd           m2, m4               ; p5
+    psubd           m3, m5
+    pmulld          m2, m13              ; p5 * s0
+    pmulld          m3, m13
+    pmaddwd         m0, m8               ; b5 * 164
+    pmaddwd         m1, m8
+    paddw           m2, m8
+    paddw           m3, m8
+    vpbroadcastd    m8, [pd_34816]
+    psrld           m2, 20               ; z5 + 1
+    psrld           m3, 20
+    cvtdq2ps        m2, m2
+    cvtdq2ps        m3, m3
+    rcpps           m4, m2               ; 1 / (z5 + 1)
+    rcpps           m5, m3
+    pcmpgtd         m2, m6, m2
+    pcmpgtd         m3, m6, m3
+    mulps           m4, m6               ; 256 / (z5 + 1)
+    mulps           m5, m6
+    vpbroadcastd    m6, [pd_m4096]
+    psrld           m2, 24               ; z5 < 255 ? 255 : 0
+    psrld           m3, 24
+    cvtps2dq        m4, m4
+    cvtps2dq        m5, m5
+    pminsw          m4, m2               ; x5
+    pminsw          m5, m3
+    pmulld          m0, m4
+    pmulld          m1, m5
+    paddd           m0, m8               ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m8
+    pand            m0, m6
+    pand            m1, m6
+    por             m0, m4               ; a5 | (b5 << 12)
+    por             m1, m5
+    mova         [t3+r10*4+400*0+ 8], xm0
+    vextracti128 [t3+r10*4+400*0+40], m0, 1
+    mova         [t3+r10*4+400*0+24], xm1
+    vextracti128 [t3+r10*4+400*0+56], m1, 1
+    add            r10, 16
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    movu            m0, [t3+r10*4+400*0+4]
+    paddd           m1, m0, [t3+r10*4+400*0+0]
+    mova            m4, [t3+r10*4+400*4+0]
+    paddd           m1, [t3+r10*4+400*0+8]
+    mova            m5, [t3+r10*4+400*8+0]
+    paddd           m4, [t3+r10*4+400*4+8]
+    paddd           m5, [t3+r10*4+400*8+8]
+    paddd           m2, m4, [t3+r10*4+400*4+4]
+    paddd           m3, m5, [t3+r10*4+400*8+4]
+    paddd           m0, m1
+    pslld           m1, 2
+    pslld           m2, 2
+    paddd           m1, m0                ; ab5 565
+    paddd           m3, m3                ; ab3[ 0] 222
+    psubd           m2, m4                ; ab3[-1] 343
+    mova [t3+r10*4+400*20], m3
+    pandn           m0, m6, m1            ; a5 565
+    mova [t3+r10*4+400*24], m2
+    psrld           m1, 12                ; b5 565
+    mova [t3+r10*4+400*12], m0
+    paddd           m3, m3
+    mova [t3+r10*4+400*16], m1
+    psubd           m3, m5                ; ab3[ 0] 343
+    mova [t3+r10*4+400*28], m3
+    add            r10, 8
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    movu            m0, [t3+r10*4+4]
+    paddd           m4, m0, [t3+r10*4+0]
+    paddd           m4, [t3+r10*4+8]
+    paddd           m0, m4
+    pslld           m4, 2
+    paddd           m4, m0
+    pandn           m0, m6, m4
+    psrld           m4, 12
+    paddd           m2, m0, [t3+r10*4+400*12] ; a5
+    mova [t3+r10*4+400*12], m0
+    paddd           m0, m4, [t3+r10*4+400*16] ; b5 + (1 << 8)
+    mova [t3+r10*4+400*16], m4
+    mova            m3, [t3+r10*4+400*4+0]
+    paddd           m3, [t3+r10*4+400*4+8]
+    paddd           m5, m3, [t3+r10*4+400*4+4]
+    paddd           m5, m5                    ; ab3[ 1] 222
+    mova            m4, [t3+r10*4+400*20]
+    paddd           m1, m4, [t3+r10*4+400*24] ; ab3[ 0] 222 + ab3[-1] 343
+    mova [t3+r10*4+400*20], m5
+    paddd           m5, m5
+    psubd           m5, m3                    ; ab3[ 1] 343
+    mova [t3+r10*4+400*24], m5
+    paddd           m4, m5                    ; ab3[ 0] 222 + ab3[ 1] 343
+    pandn           m3, m6, m1
+    psrld           m1, 12
+    pandn           m5, m6, m4
+    psrld           m4, 12
+    paddd           m3, m5                    ; a3
+    paddd           m1, m4                    ; b3 + (1 << 8)
+    pmovzxbd        m4, [dstq+r10]
+    pmaddwd         m2, m4                    ; a5 * src
+    pmaddwd         m3, m4                    ; a3 * src
+    psubd           m0, m2                    ; b5 - a5 * src + (1 << 8)
+    psubd           m1, m3                    ; b3 - a3 * src + (1 << 8)
+    psrld           m0, 9
+    pslld           m1, 7
+    pblendw         m0, m1, 0xaa
+    pmaddwd         m0, m15
+    psubd           m0, m6
+    psrad           m0, 13
+    paddd           m0, m4
+    vextracti128   xm1, m0, 1
+    packssdw       xm0, xm1
+    packuswb       xm0, xm0
+    movq    [dstq+r10], xm0
+    add            r10, 8
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    mova            m3, [t3+r10*4+400*8+0]
+    paddd           m3, [t3+r10*4+400*8+8]
+    paddd           m5, m3, [t3+r10*4+400*8+4]
+    paddd           m5, m5                    ; ab3[ 1] 222
+    mova            m4, [t3+r10*4+400*20]
+    paddd           m1, m4, [t3+r10*4+400*28] ; ab3[ 0] 222 + ab3[-1] 343
+    mova [t3+r10*4+400*20], m5
+    paddd           m5, m5
+    psubd           m5, m3                    ; ab3[ 1] 343
+    mova [t3+r10*4+400*28], m5
+    paddd           m4, m5                    ; ab3[ 0] 222 + ab3[ 1] 343
+    pandn           m3, m6, m1
+    psrld           m1, 12
+    pandn           m5, m6, m4
+    psrld           m4, 12
+    paddd           m3, m5                    ; -a3
+    paddd           m1, m4                    ;  b3 + (1 << 8)
+    pmovzxbd        m4, [dstq+r10]
+    pmaddwd         m2, m4, [t3+r10*4+400*12] ; -a5 * src
+    mova            m0, [t3+r10*4+400*16]     ;  b5 + (1 << 7)
+    pmaddwd         m3, m4                    ; -a3 * src
+    psubd           m0, m2                    ; a5 * src + b5 + (1 << 7)
+    psubd           m1, m3                    ; a3 * src + b3 + (1 << 8)
+    psrld           m0, 8
+    pslld           m1, 7
+    pblendw         m0, m1, 0xaa
+    pmaddwd         m0, m15
+    psubd           m0, m6
+    psrad           m0, 13
+    paddd           m0, m4
+    vextracti128   xm1, m0, 1
+    packssdw       xm0, xm1
+    packuswb       xm0, xm0
+    movq    [dstq+r10], xm0
+    add            r10, 8
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/looprestoration_avx512.asm b/media/libdav1d/src/src/x86/looprestoration_avx512.asm
new file mode 100644
index 0000000000..1e571774ca
--- /dev/null
+++ b/media/libdav1d/src/src/x86/looprestoration_avx512.asm
@@ -0,0 +1,2122 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 32
+
+wiener_shufA:  db  1,  2,  7,  6,  3,  4,  9,  8,  5,  6, 11, 10,  7,  8, 13, 12
+wiener_shufB:  db  2,  3,  8,  7,  4,  5, 10,  9,  6,  7, 12, 11,  8,  9, 14, 13
+wiener_shufC:  db  3,  4,  4,  5,  5,  6,  6,  7,  7,  8,  8,  9,  9, 10, 10, 11
+wiener_shufD:  db  4,  5,  5,  6,  6,  7,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12
+wiener_perm32: db  1,  9,  3, 11,  5, 13,  7, 15, 33, 41, 35, 43, 37, 45, 39, 47
+               db 17, 25, 19, 27, 21, 29, 23, 31, 49, 57, 51, 59, 53, 61, 55, 63
+sgr_shuf:      db 128, 1, -1,  2,132,  3, -1,  4,136,  5, -1,  6,140,  7, -1,  8
+               db 129, 9, -1, 10,133, 11, -1, 12,137, -1, -1, -1,141, -1,  0,128
+sgr_mix_perm:  db  1,  3,  5,  7, 17, 19, 21, 23, 33, 35, 37, 39, 49, 51, 53, 55
+r_ext_mask:    times 68 db -1
+               times  4 db  0
+wiener_x_shuf: db  0,  2, -1,  0
+wiener_x_add:  db  0,  1,127,  0
+
+pw_61448:      times 2 dw 61448
+pw_164_455:    dw 164, 455
+pd_m16380:     dd -16380
+pd_m4096:      dd -4096
+pd_m25         dd -25
+pd_m9:         dd -9
+pd_34816:      dd 34816
+pd_8421376:    dd 8421376
+
+cextern sgr_x_by_x
+
+SECTION .text
+
+DECLARE_REG_TMP 8, 7, 9, 11, 12, 13, 14 ; ring buffer pointers
+
+INIT_ZMM avx512icl
+cglobal wiener_filter7_8bpc, 4, 15, 20, -384*12-16, dst, stride, left, lpf, \
+                                                    w, h, edge, flt
+    mov           fltq, r6mp
+    mov             wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    vbroadcasti32x4 m6, [wiener_shufA]
+    vbroadcasti32x4 m7, [wiener_shufB]
+    mov           r10d, 0xfffe
+    vbroadcasti32x4 m8, [wiener_shufC]
+    vbroadcasti32x4 m9, [wiener_shufD]
+    kmovw           k1, r10d
+    vpbroadcastd    m0, [wiener_x_shuf]
+    vpbroadcastd    m1, [wiener_x_add]
+    mov            r10, 0xaaaaaaaaaaaaaaaa
+    vpbroadcastd   m11, [fltq+ 0]
+    vpbroadcastd   m12, [fltq+ 4]
+    kmovq           k2, r10
+    vpbroadcastd   m10, [pd_m16380]
+    packsswb       m11, m11 ; x0   x1   x0   x1
+    vpbroadcastd   m14, [fltq+16]
+    pshufb         m12, m0
+    vpbroadcastd   m15, [fltq+20]
+    paddb          m12, m1  ; x2   x3+1 x2   127
+    vpbroadcastd   m13, [pd_8421376]
+    psllw          m14, 5   ; y0 y1
+    psllw          m15, 5   ; y2 y3
+    cmp             wd, 32  ; the minimum lr unit size for chroma in 4:2:0 is 32
+    jle .w32                ; pixels, so we need a special case for small widths
+    lea             t1, [rsp+wq*2+16]
+    add           lpfq, wq
+    add           dstq, wq
+    neg             wq
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t6, t1
+    mov             t5, t1
+    add             t1, 384*2
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t4, t1
+    add             t1, 384*2
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .h
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+.main:
+    lea             t0, [t1+384*2]
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v3
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.v1:
+    call .v
+    RET
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    mov             t6, t1
+    mov             t5, t1
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v3
+    add             t0, 384*8
+    call .hv
+    dec             hd
+    jnz .main
+.v3:
+    call .v
+.v2:
+    call .v
+    jmp .v1
+.h:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd          xm16, [leftq]
+    vmovdqu32  m16{k1}, [lpfq+r10-4]
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    vpbroadcastb  xm16, [lpfq+r10]   ; the masked load ensures that no exception
+    vmovdqu32  m16{k1}, [lpfq+r10-4] ; gets raised from accessing invalid memory
+    jmp .h_main
+.h_top:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu           m16, [lpfq+r10-4]
+.h_main:
+    movu           m17, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -66
+    jl .h_have_right
+    push            r0
+    lea             r0, [r_ext_mask+65]
+    vpbroadcastb    m0, [lpfq-1]
+    vpternlogd     m16, m0, [r0+r10+0], 0xe4 ; c ? a : b
+    vpternlogd     m17, m0, [r0+r10+8], 0xe4
+    pop             r0
+.h_have_right:
+    pshufb          m4, m16, m6
+    mova            m0, m10
+    vpdpbusd        m0, m4, m11
+    pshufb          m4, m16, m7
+    mova            m2, m10
+    vpdpbusd        m2, m4, m11
+    pshufb          m4, m17, m6
+    mova            m1, m10
+    vpdpbusd        m1, m4, m11
+    pshufb          m4, m17, m7
+    mova            m3, m10
+    vpdpbusd        m3, m4, m11
+    pshufb          m4, m16, m8
+    vpdpbusd        m0, m4, m12
+    pshufb         m16, m9
+    vpdpbusd        m2, m16, m12
+    pshufb          m4, m17, m8
+    vpdpbusd        m1, m4, m12
+    pshufb         m17, m9
+    vpdpbusd        m3, m17, m12
+    packssdw        m0, m2
+    packssdw        m1, m3
+    psraw           m0, 3
+    psraw           m1, 3
+    mova [t1+r10*2+ 0], m0
+    mova [t1+r10*2+64], m1
+    add            r10, 64
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movd          xm16, [leftq]
+    vmovdqu32  m16{k1}, [lpfq+r10-4]
+    add          leftq, 4
+    jmp .hv_main
+.hv_extend_left:
+    vpbroadcastb  xm16, [lpfq+r10]
+    vmovdqu32  m16{k1}, [lpfq+r10-4]
+    jmp .hv_main
+.hv_bottom:
+    mov            r10, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu           m16, [lpfq+r10-4]
+.hv_main:
+    movu           m17, [lpfq+r10+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -66
+    jl .hv_have_right
+    push            r0
+    lea             r0, [r_ext_mask+65]
+    vpbroadcastb    m0, [lpfq-1]
+    vpternlogd     m16, m0, [r0+r10+0], 0xe4 ; c ? a : b
+    vpternlogd     m17, m0, [r0+r10+8], 0xe4
+    pop             r0
+.hv_have_right:
+    pshufb          m4, m16, m6
+    mova            m0, m10
+    vpdpbusd        m0, m4, m11
+    pshufb          m4, m16, m7
+    mova            m2, m10
+    vpdpbusd        m2, m4, m11
+    pshufb          m4, m17, m6
+    mova            m1, m10
+    vpdpbusd        m1, m4, m11
+    pshufb          m4, m17, m7
+    mova            m3, m10
+    vpdpbusd        m3, m4, m11
+    pshufb          m4, m16, m8
+    vpdpbusd        m0, m4, m12
+    pshufb         m16, m9
+    vpdpbusd        m2, m16, m12
+    pshufb          m4, m17, m8
+    vpdpbusd        m1, m4, m12
+    pshufb         m17, m9
+    vpdpbusd        m3, m17, m12
+    packssdw        m0, m2
+    packssdw        m1, m3
+    psraw           m0, 3
+    psraw           m1, 3
+    mova           m16, [t4+r10*2]
+    paddw          m16, [t2+r10*2]
+    mova            m3, [t3+r10*2]
+    mova           m17, [t4+r10*2+64]
+    paddw          m17, [t2+r10*2+64]
+    mova            m5, [t3+r10*2+64]
+    punpcklwd       m4, m16, m3
+    mova            m2, m13
+    vpdpwssd        m2, m4, m15
+    punpcklwd      m18, m17, m5
+    mova            m4, m13
+    vpdpwssd        m4, m18, m15
+    punpckhwd      m16, m3
+    mova            m3, m13
+    vpdpwssd        m3, m16, m15
+    punpckhwd      m17, m5
+    mova            m5, m13
+    vpdpwssd        m5, m17, m15
+    mova           m17, [t5+r10*2]
+    paddw          m17, [t1+r10*2]
+    paddw          m16, m0, [t6+r10*2]
+    mova           m19, [t5+r10*2+64]
+    paddw          m19, [t1+r10*2+64]
+    paddw          m18, m1, [t6+r10*2+64]
+    mova [t0+r10*2+ 0], m0
+    mova [t0+r10*2+64], m1
+    punpcklwd       m0, m16, m17
+    vpdpwssd        m2, m0, m14
+    punpcklwd       m1, m18, m19
+    vpdpwssd        m4, m1, m14
+    punpckhwd      m16, m17
+    vpdpwssd        m3, m16, m14
+    punpckhwd      m18, m19
+    vpdpwssd        m5, m18, m14
+    packuswb        m2, m4
+    psrlw           m2, 8
+    vpackuswb   m2{k2}, m3, m5
+    movu    [dstq+r10], m2 ; We don't have a separate 5-tap version so the 7-tap
+    add            r10, 64 ; function is used for chroma as well, and in some
+    jl .hv_loop            ; esoteric edge cases chroma dst pointers may only
+    mov             t6, t5 ; have a 32-byte alignment despite having a width
+    mov             t5, t4 ; larger than 32, so use an unaligned store here.
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t6
+    add           dstq, strideq
+    ret
+.v:
+    mov            r10, wq
+.v_loop:
+    mova            m4, [t4+r10*2+ 0]
+    paddw           m4, [t2+r10*2+ 0]
+    mova            m1, [t3+r10*2+ 0]
+    mova            m5, [t4+r10*2+64]
+    paddw           m5, [t2+r10*2+64]
+    mova            m3, [t3+r10*2+64]
+    punpcklwd       m6, m4, m1
+    mova            m0, m13
+    vpdpwssd        m0, m6, m15
+    punpcklwd       m6, m5, m3
+    mova            m2, m13
+    vpdpwssd        m2, m6, m15
+    punpckhwd       m4, m1
+    mova            m1, m13
+    vpdpwssd        m1, m4, m15
+    punpckhwd       m5, m3
+    mova            m3, m13
+    vpdpwssd        m3, m5, m15
+    mova            m5, [t1+r10*2+ 0]
+    paddw           m4, m5, [t6+r10*2+ 0]
+    paddw           m5, [t5+r10*2+ 0]
+    mova            m7, [t1+r10*2+64]
+    paddw           m6, m7, [t6+r10*2+64]
+    paddw           m7, [t5+r10*2+64]
+    punpcklwd       m8, m4, m5
+    vpdpwssd        m0, m8, m14
+    punpcklwd       m8, m6, m7
+    vpdpwssd        m2, m8, m14
+    punpckhwd       m4, m5
+    vpdpwssd        m1, m4, m14
+    punpckhwd       m6, m7
+    vpdpwssd        m3, m6, m14
+    packuswb        m0, m2
+    psrlw           m0, 8
+    vpackuswb   m0{k2}, m1, m3
+    movu    [dstq+r10], m0
+    add            r10, 64
+    jl .v_loop
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    add           dstq, strideq
+    ret
+.w32:
+    lea            r10, [r_ext_mask+73]
+    mova          ym18, [wiener_perm32]
+    lea             t1, [rsp+16]
+    sub            r10, wq
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .w32_no_top
+    call .w32_h_top
+    add           lpfq, strideq
+    mov             t6, t1
+    mov             t5, t1
+    add             t1, 32*2
+    call .w32_h_top
+    lea             r9, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    mov             t4, t1
+    add             t1, 32*2
+    add             r9, strideq
+    mov          [rsp], r9 ; below
+    call .w32_h
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .w32_v1
+    add           lpfq, strideq
+    add             t1, 32*2
+    call .w32_h
+    mov             t2, t1
+    dec             hd
+    jz .w32_v2
+    add           lpfq, strideq
+    add             t1, 32*2
+    call .w32_h
+    dec             hd
+    jz .w32_v3
+.w32_main:
+    lea             t0, [t1+32*2]
+.w32_main_loop:
+    call .w32_hv
+    dec             hd
+    jnz .w32_main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .w32_v3
+    mov           lpfq, [rsp]
+    call .w32_hv_bottom
+    add           lpfq, strideq
+    call .w32_hv_bottom
+.w32_v1:
+    call .w32_v
+    RET
+.w32_no_top:
+    lea             r9, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea             r9, [r9+strideq*2]
+    mov          [rsp], r9
+    call .w32_h
+    mov             t6, t1
+    mov             t5, t1
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .w32_v1
+    add           lpfq, strideq
+    add             t1, 32*2
+    call .w32_h
+    mov             t2, t1
+    dec             hd
+    jz .w32_v2
+    add           lpfq, strideq
+    add             t1, 32*2
+    call .w32_h
+    dec             hd
+    jz .w32_v3
+    lea             t0, [t1+32*2]
+    call .w32_hv
+    dec             hd
+    jz .w32_v3
+    add             t0, 32*8
+    call .w32_hv
+    dec             hd
+    jnz .w32_main
+.w32_v3:
+    call .w32_v
+.w32_v2:
+    call .w32_v
+    jmp .w32_v1
+.w32_h:
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .w32_h_extend_left
+    movd          xm16, [leftq]
+    vmovdqu32 ym16{k1}, [lpfq-4]
+    add          leftq, 4
+    jmp .w32_h_main
+.w32_h_extend_left:
+    vpbroadcastb  xm16, [lpfq]   ; the masked load ensures that no exception
+    vmovdqu32 ym16{k1}, [lpfq-4] ; gets raised from accessing invalid memory
+    jmp .w32_h_main
+.w32_h_top:
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .w32_h_extend_left
+    movu          ym16, [lpfq-4]
+.w32_h_main:
+    vinserti32x8   m16, [lpfq+4], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .w32_h_have_right
+    vpbroadcastb    m0, [lpfq+wq-1]
+    movu          ym17, [r10-8]
+    vinserti32x8   m17, [r10+0], 1
+    vpternlogd     m16, m0, m17, 0xe4 ; c ? a : b
+.w32_h_have_right:
+    pshufb          m2, m16, m6
+    mova            m0, m10
+    vpdpbusd        m0, m2, m11
+    pshufb          m2, m16, m7
+    mova            m1, m10
+    vpdpbusd        m1, m2, m11
+    pshufb          m2, m16, m8
+    vpdpbusd        m0, m2, m12
+    pshufb         m16, m9
+    vpdpbusd        m1, m16, m12
+    packssdw        m0, m1
+    psraw           m0, 3
+    mova          [t1], m0
+    ret
+.w32_hv:
+    add           lpfq, strideq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .w32_hv_extend_left
+    movd          xm16, [leftq]
+    vmovdqu32 ym16{k1}, [lpfq-4]
+    add          leftq, 4
+    jmp .w32_hv_main
+.w32_hv_extend_left:
+    vpbroadcastb  xm16, [lpfq]
+    vmovdqu32 ym16{k1}, [lpfq-4]
+    jmp .w32_hv_main
+.w32_hv_bottom:
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .w32_hv_extend_left
+    movu          ym16, [lpfq-4]
+.w32_hv_main:
+    vinserti32x8   m16, [lpfq+4], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .w32_hv_have_right
+    vpbroadcastb    m0, [lpfq+wq-1]
+    movu          ym17, [r10-8]
+    vinserti32x8   m17, [r10+0], 1
+    vpternlogd     m16, m0, m17, 0xe4
+.w32_hv_have_right:
+    mova            m3, [t4]
+    paddw           m3, [t2]
+    mova            m2, [t3]
+    pshufb          m4, m16, m6
+    mova            m0, m10
+    vpdpbusd        m0, m4, m11
+    pshufb          m4, m16, m7
+    mova            m5, m10
+    vpdpbusd        m5, m4, m11
+    punpcklwd       m4, m3, m2
+    mova            m1, m13
+    vpdpwssd        m1, m4, m15
+    punpckhwd       m3, m2
+    mova            m2, m13
+    vpdpwssd        m2, m3, m15
+    pshufb          m4, m16, m8
+    vpdpbusd        m0, m4, m12
+    pshufb         m16, m9
+    vpdpbusd        m5, m16, m12
+    packssdw        m0, m5
+    psraw           m0, 3
+    mova            m4, [t5]
+    paddw           m4, [t1]
+    paddw           m3, m0, [t6]
+    mova          [t0], m0
+    punpcklwd       m0, m3, m4
+    vpdpwssd        m1, m0, m14
+    punpckhwd       m3, m4
+    vpdpwssd        m2, m3, m14
+    packuswb        m1, m2
+    vpermb         m16, m18, m1
+    mova        [dstq], ym16
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t6
+    add           dstq, strideq
+    ret
+.w32_v:
+    mova            m2, [t4]
+    paddw           m2, [t2]
+    mova            m1, [t3]
+    mova            m4, [t1]
+    paddw           m3, m4, [t6]
+    paddw           m4, [t5]
+    punpcklwd       m5, m2, m1
+    mova            m0, m13
+    vpdpwssd        m0, m5, m15
+    punpckhwd       m2, m1
+    mova            m1, m13
+    vpdpwssd        m1, m2, m15
+    punpcklwd       m2, m3, m4
+    vpdpwssd        m0, m2, m14
+    punpckhwd       m3, m4
+    vpdpwssd        m1, m3, m14
+    packuswb        m0, m1
+    vpermb         m16, m18, m0
+    mova        [dstq], ym16
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_5x5_8bpc, 4, 13, 23, 416*24+16, dst, stride, left, lpf, \
+                                                   w, h, edge, params
+    mov        paramsq, r6mp
+    mov             wd, wm
+    mov             hd, hm
+    mov          edged, r7m
+    vbroadcasti32x4 m5, [sgr_shuf+1]
+    add           lpfq, wq
+    vbroadcasti32x4 m6, [sgr_shuf+9]
+    add           dstq, wq
+    vbroadcasti32x4 m7, [sgr_shuf+3]
+    lea             t3, [rsp+wq*4+16+416*12]
+    vbroadcasti32x4 m8, [sgr_shuf+7]
+    pxor            m4, m4
+    vpbroadcastd    m9, [pd_m25]
+    vpsubd         m11, m4, [paramsq+0] {1to16} ; -s0
+    vpbroadcastw   m15, [paramsq+8]             ; w0
+    lea             t1, [rsp+wq*2+20]
+    vpbroadcastd   m10, [pw_164_455]
+    neg             wq
+    vpbroadcastd   m12, [pw_61448]              ; (15 << 12) + (1 << 3)
+    mov           r10d, 0xfe
+    vpbroadcastd   m13, [pd_m4096]
+    kmovb           k1, r10d
+    vpbroadcastd   m14, [pd_34816]              ; (1 << 11) + (1 << 15)
+    mov            r10, 0x3333333333333333
+    mova           m18, [sgr_x_by_x+64*0]
+    kmovq           k2, r10
+    mova           m19, [sgr_x_by_x+64*1]
+    lea            r12, [r_ext_mask+75]
+    mova           m20, [sgr_x_by_x+64*2]
+    psllw          m15, 4
+    mova           m21, [sgr_x_by_x+64*3]
+    lea            r10, [lpfq+strideq*4]
+    mova          ym22, [sgr_shuf]
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    call .top_fixup
+    add             t1, 416*6
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    mov             t0, t2
+    dec             hd
+    jz .height1
+    or           edged, 16
+    call .h
+.main:
+    add           lpfq, strideq
+    call .hv
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    test            hd, hd
+    jz .odd_height
+    call .h
+    add           lpfq, strideq
+    call .hv
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .h_top
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .hv
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .hv
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea             t2, [t1+416*6]
+    call .top_fixup
+    dec             hd
+    jz .no_top_height1
+    or           edged, 16
+    mov             t0, t1
+    mov             t1, t2
+    jmp .main
+.no_top_height1:
+    call .v
+    call .prep_n
+    jmp .odd_height_end
+.h: ; horizontal boxsum
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd          xm17, [leftq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    vpbroadcastb  xm17, [lpfq+wq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu          ym17, [lpfq+r10-2]
+.h_main:
+    vinserti32x8   m17, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -34
+    jl .h_have_right
+    vpbroadcastb    m0, [lpfq-1]
+    movu          ym16, [r12+r10-8]
+    vinserti32x8   m16, [r12+r10+0], 1
+    vpternlogd     m17, m0, m16, 0xe4
+.h_have_right:
+    pshufb          m3, m17, m5
+    pmullw          m2, m3, m3
+    pshufb          m1, m17, m6
+    paddw           m0, m3, m1
+    shufps          m3, m1, q2121
+    paddw           m0, m3
+    punpcklwd      m16, m3, m1
+    punpckhwd       m3, m1
+    punpcklwd       m1, m2, m4
+    vpdpwssd        m1, m16, m16
+    punpckhwd       m2, m4
+    vpdpwssd        m2, m3, m3
+    pshufb         m16, m17, m7
+    paddw           m0, m16
+    pshufb         m17, m8
+    paddw           m0, m17              ; sum
+    punpcklwd       m3, m16, m17
+    vpdpwssd        m1, m3, m3           ; sumsq
+    punpckhwd      m16, m17
+    vpdpwssd        m2, m16, m16
+    test         edgeb, 16 ; y > 0
+    jz .h_loop_end
+    paddw           m0, [t1+r10*2+416*0]
+    paddd           m1, [t1+r10*2+416*2]
+    paddd           m2, [t1+r10*2+416*4]
+.h_loop_end:
+    mova [t1+r10*2+416*0], m0
+    mova [t1+r10*2+416*2], m1
+    mova [t1+r10*2+416*4], m2
+    add            r10, 32
+    jl .h_loop
+    ret
+.top_fixup:
+    lea            r10, [wq-2]
+.top_fixup_loop: ; the sums of the first row needs to be doubled
+    mova            m0, [t1+r10*2+416*0]
+    mova            m1, [t1+r10*2+416*2]
+    mova            m2, [t1+r10*2+416*4]
+    paddw           m0, m0
+    paddd           m1, m1
+    paddd           m2, m2
+    mova [t2+r10*2+416*0], m0
+    mova [t2+r10*2+416*2], m1
+    mova [t2+r10*2+416*4], m2
+    add            r10, 32
+    jl .top_fixup_loop
+    ret
+ALIGN function_align
+.hv: ; horizontal boxsum + vertical boxsum + ab
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movd          xm17, [leftq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    add          leftq, 4
+    jmp .hv_main
+.hv_extend_left:
+    vpbroadcastb  xm17, [lpfq+wq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    jmp .hv_main
+.hv_bottom:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu          ym17, [lpfq+r10-2]
+.hv_main:
+    vinserti32x8   m17, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -34
+    jl .hv_have_right
+    vpbroadcastb    m0, [lpfq-1]
+    movu          ym16, [r12+r10-8]
+    vinserti32x8   m16, [r12+r10+0], 1
+    vpternlogd     m17, m0, m16, 0xe4
+.hv_have_right:
+    pshufb          m1, m17, m5
+    pmullw          m3, m1, m1
+    pshufb          m2, m17, m6
+    paddw           m0, m1, m2
+    shufps          m1, m2, q2121
+    paddw           m0, m1
+    punpcklwd      m16, m1, m2
+    punpckhwd       m1, m2
+    punpcklwd       m2, m3, m4
+    vpdpwssd        m2, m16, m16
+    punpckhwd       m3, m4
+    vpdpwssd        m3, m1, m1
+    pshufb         m16, m17, m7
+    paddw           m0, m16
+    pshufb         m17, m8
+    paddw           m0, m17              ; h sum
+    punpcklwd       m1, m16, m17
+    vpdpwssd        m2, m1, m1           ; h sumsq
+    punpckhwd      m16, m17
+    vpdpwssd        m3, m16, m16
+    paddw           m1, m0, [t1+r10*2+416*0]
+    paddd          m16, m2, [t1+r10*2+416*2]
+    paddd          m17, m3, [t1+r10*2+416*4]
+    test            hd, hd
+    jz .hv_last_row
+.hv_main2:
+    paddd          m16, [t2+r10*2+416*2] ; hv sumsq
+    paddd          m17, [t2+r10*2+416*4]
+    paddw           m1, [t2+r10*2+416*0] ; hv sum
+    mova [t0+r10*2+416*2], m2
+    mova [t0+r10*2+416*4], m3
+    mova [t0+r10*2+416*0], m0
+    pmulld         m16, m9               ; -a * 25
+    pmulld         m17, m9
+    punpcklwd       m0, m1, m4           ; b
+    vpdpwssd       m16, m0, m0           ; -p
+    punpckhwd       m1, m4
+    vpdpwssd       m17, m1, m1
+    pmaddwd         m0, m10              ; b * 164
+    pmaddwd         m1, m10
+    pmulld         m16, m11              ; p * s
+    pmulld         m17, m11
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m20
+    paddusw        m17, m12
+    psraw          m17, 4                ; min(z, 255) - 256
+    vpermt2b       m16, m17, m21         ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m18, m19         ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16              ; x
+    pandn          m16, m13, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    paddd           m0, m14              ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m14
+    vpternlogd     m16, m0, m13, 0xd8    ; a | (b << 12)
+    vpternlogd     m17, m1, m13, 0xd8
+    mova          [t3+r10*4+  8], m16    ; The neighbor calculations requires
+    mova          [t3+r10*4+ 24], xm17   ; 13 bits for a and 21 bits for b.
+    vextracti32x4 [t3+r10*4+ 56], m17, 2 ; Packing them allows for 12+20, but
+    mova          [t3+r10*4+ 72], m17    ; that gets us most of the way.
+    vextracti128  [t3+r10*4+ 72], ym16, 1
+    vextracti32x4 [t3+r10*4+104], m16, 3
+    add            r10, 32
+    jl .hv_loop
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t2
+    ret
+.hv_last_row: ; esoteric edge case for odd heights
+    mova [t1+r10*2+416*0], m1
+    paddw              m1, m0
+    mova [t1+r10*2+416*2], m16
+    paddd             m16, m2
+    mova [t1+r10*2+416*4], m17
+    paddd             m17, m3
+    jmp .hv_main2
+.v: ; vertical boxsum + ab
+    lea            r10, [wq-2]
+.v_loop:
+    mova            m2, [t1+r10*2+416*2]
+    paddd          m16, m2, [t2+r10*2+416*2]
+    mova            m3, [t1+r10*2+416*4]
+    paddd          m17, m3, [t2+r10*2+416*4]
+    paddd           m2, m2
+    paddd           m3, m3
+    paddd          m16, m2               ; hv sumsq
+    paddd          m17, m3
+    pmulld         m16, m9               ; -a * 25
+    pmulld         m17, m9
+    mova            m0, [t1+r10*2+416*0]
+    paddw           m1, m0, [t2+r10*2+416*0]
+    paddw           m0, m0
+    paddw           m1, m0               ; hv sum
+    punpcklwd       m0, m1, m4           ; b
+    vpdpwssd       m16, m0, m0           ; -p
+    punpckhwd       m1, m4
+    vpdpwssd       m17, m1, m1
+    pmaddwd         m0, m10              ; b * 164
+    pmaddwd         m1, m10
+    pmulld         m16, m11              ; p * s
+    pmulld         m17, m11
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m20
+    paddusw        m17, m12
+    psraw          m17, 4                ; min(z, 255) - 256
+    vpermt2b       m16, m17, m21         ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m18, m19         ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16              ; x
+    pandn          m16, m13, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    paddd           m0, m14              ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m14
+    vpternlogd     m16, m0, m13, 0xd8    ; a | (b << 12)
+    vpternlogd     m17, m1, m13, 0xd8
+    mova          [t3+r10*4+  8], m16
+    mova          [t3+r10*4+ 24], xm17
+    vextracti32x4 [t3+r10*4+ 56], m17, 2
+    mova          [t3+r10*4+ 72], m17
+    vextracti128  [t3+r10*4+ 72], ym16, 1
+    vextracti32x4 [t3+r10*4+104], m16, 3
+    add            r10, 32
+    jl .v_loop
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    movu            m0, [t3+r10*4+ 4]
+    movu            m1, [t3+r10*4+68]
+    paddd           m2, m0, [t3+r10*4+ 0]
+    paddd           m3, m1, [t3+r10*4+64]
+    paddd           m2, [t3+r10*4+ 8]
+    paddd           m3, [t3+r10*4+72]
+    paddd           m0, m2
+    pslld           m2, 2
+    paddd           m1, m3
+    pslld           m3, 2
+    paddd           m2, m0                ; ab 565
+    paddd           m3, m1
+    pandn           m0, m13, m2           ; a
+    psrld           m2, 12                ; b
+    pandn           m1, m13, m3
+    psrld           m3, 12
+    mova [t3+r10*4+416*4+ 0], m0
+    mova [t3+r10*4+416*8+ 0], m2
+    mova [t3+r10*4+416*4+64], m1
+    mova [t3+r10*4+416*8+64], m3
+    add            r10, 32
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    movu           m16, [t3+r10*4+ 4]
+    movu           m17, [t3+r10*4+68]
+    paddd           m0, m16, [t3+r10*4+ 0]
+    paddd           m1, m17, [t3+r10*4+64]
+    paddd           m0, [t3+r10*4+ 8]
+    paddd           m1, [t3+r10*4+72]
+    paddd          m16, m0
+    pslld           m0, 2
+    paddd          m17, m1
+    pslld           m1, 2
+    paddd           m0, m16
+    paddd           m1, m17
+    pandn          m16, m13, m0
+    psrld           m0, 12
+    pandn          m17, m13, m1
+    psrld           m1, 12
+    paddd           m2, m16, [t3+r10*4+416*4+ 0] ; a
+    paddd           m3, m17, [t3+r10*4+416*4+64]
+    mova [t3+r10*4+416*4+ 0], m16
+    mova [t3+r10*4+416*4+64], m17
+    paddd          m16, m0, [t3+r10*4+416*8+ 0] ; b + (1 << 8)
+    paddd          m17, m1, [t3+r10*4+416*8+64]
+    mova [t3+r10*4+416*8+ 0], m0
+    mova [t3+r10*4+416*8+64], m1
+    pmovzxbd        m0, [dstq+r10+ 0]
+    pmovzxbd        m1, [dstq+r10+16]
+    pmaddwd         m2, m0                      ; a * src
+    pmaddwd         m3, m1
+    packssdw        m0, m1
+    psubd          m16, m2                      ; b - a * src + (1 << 8)
+    psubd          m17, m3
+    psrad          m16, 9
+    psrad          m17, 9
+    packssdw       m16, m17
+    pmulhrsw       m16, m15
+    paddw          m16, m0
+    packuswb       m16, m16
+    vpermd         m16, m22, m16
+    mova    [dstq+r10], ym16
+    add            r10, 32
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    pmovzxbd        m0, [dstq+r10+ 0]
+    pmovzxbd        m1, [dstq+r10+16]
+    pmaddwd         m2, m0, [t3+r10*4+416*4+ 0] ; a * src
+    pmaddwd         m3, m1, [t3+r10*4+416*4+64]
+    mova           m16, [t3+r10*4+416*8+ 0]     ; b + (1 << 7)
+    mova           m17, [t3+r10*4+416*8+64]
+    packssdw        m0, m1
+    psubd          m16, m2                      ; b - a * src + (1 << 7)
+    psubd          m17, m3
+    psrad          m16, 8
+    psrad          m17, 8
+    packssdw       m16, m17
+    pmulhrsw       m16, m15
+    paddw          m16, m0
+    packuswb       m16, m16
+    vpermd         m16, m22, m16
+    mova    [dstq+r10], ym16
+    add            r10, 32
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_3x3_8bpc, 4, 15, 22, -416*28-16, dst, stride, left, lpf, \
+                                                    w, h, edge, params
+    mov        paramsq, r6mp
+    mov             wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    vbroadcasti32x4 m5, [sgr_shuf+3]
+    add           lpfq, wq
+    vbroadcasti32x4 m6, [sgr_shuf+5]
+    add           dstq, wq
+    vbroadcasti32x4 m7, [sgr_shuf+7]
+    pxor            m4, m4
+    vpbroadcastd    m8, [pd_m9]
+    vpsubd         m11, m4, [paramsq+4] {1to16} ; -s1
+    vpbroadcastw   m15, [paramsq+10]            ; w1
+    lea             t1, [rsp+wq*2+20]
+    vpbroadcastd   m10, [pw_164_455]
+    lea             t3, [rsp+wq*4+16+416*12]
+    vpbroadcastd   m12, [pw_61448]              ; (15 << 12) + (1 << 3)
+    neg             wq
+    vpbroadcastd   m13, [pd_m4096]
+    mov           r10d, 0xfe
+    vpbroadcastd   m14, [pd_34816]              ; (1 << 11) + (1 << 15)
+    kmovb           k1, r10d
+    mova           m18, [sgr_x_by_x+64*0]
+    mov            r10, 0x3333333333333333
+    mova           m19, [sgr_x_by_x+64*1]
+    kmovq           k2, r10
+    mova           m20, [sgr_x_by_x+64*2]
+    psllw          m15, 4
+    mova           m21, [sgr_x_by_x+64*3]
+    lea            r14, [r_ext_mask+75]
+    mova           ym9, [sgr_shuf]
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    add             t1, 416*6
+    call .h_top
+    lea             t4, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add             t4, strideq
+    mov          [rsp], t4 ; below
+    mov             t0, t2
+    call .hv
+.main:
+    mov             t5, t3
+    add             t3, 416*4
+    dec             hd
+    jz .height1
+    add           lpfq, strideq
+    call .hv
+    call .prep_n
+    dec             hd
+    jz .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    call .hv
+    call .n
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    call .n
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    call .n
+    RET
+.height1:
+    call .v
+    call .prep_n
+    mov             t2, t1
+    call .v
+    jmp .end
+.extend_bottom:
+    call .v
+    call .n
+    mov             t2, t1
+    call .v
+    jmp .end
+.no_top:
+    lea             t4, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea             t4, [t4+strideq*2]
+    mov          [rsp], t4
+    call .h
+    lea             t0, [t1+416*6]
+    mov             t2, t1
+    call .v
+    jmp .main
+.h: ; horizontal boxsum
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd          xm17, [leftq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    vpbroadcastb  xm17, [lpfq+wq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu          ym17, [lpfq+r10-2]
+.h_main:
+    vinserti32x8   m17, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -33
+    jl .h_have_right
+    vpbroadcastb    m0, [lpfq-1]
+    movu          ym16, [r14+r10-8]
+    vinserti32x8   m16, [r14+r10+0], 1
+    vpternlogd     m17, m0, m16, 0xe4
+.h_have_right:
+    pshufb          m0, m17, m5
+    pmullw          m2, m0, m0
+    pshufb         m16, m17, m6
+    paddw           m0, m16
+    pshufb         m17, m7
+    paddw           m0, m17    ; sum
+    punpcklwd       m3, m16, m17
+    punpcklwd       m1, m2, m4
+    vpdpwssd        m1, m3, m3 ; sumsq
+    punpckhwd      m16, m17
+    punpckhwd       m2, m4
+    vpdpwssd        m2, m16, m16
+    mova [t1+r10*2+416*0], m0
+    mova [t1+r10*2+416*2], m1
+    mova [t1+r10*2+416*4], m2
+    add            r10, 32
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv: ; horizontal boxsum + vertical boxsum + ab
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movd          xm17, [leftq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    add          leftq, 4
+    jmp .hv_main
+.hv_extend_left:
+    vpbroadcastb  xm17, [lpfq+wq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    jmp .hv_main
+.hv_bottom:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu          ym17, [lpfq+r10-2]
+.hv_main:
+    vinserti32x8   m17, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp           r10d, -33
+    jl .hv_have_right
+    vpbroadcastb    m0, [lpfq-1]
+    movu          ym16, [r14+r10-8]
+    vinserti32x8   m16, [r14+r10+0], 1
+    vpternlogd     m17, m0, m16, 0xe4
+.hv_have_right:
+    pshufb          m0, m17, m5
+    pmullw          m3, m0, m0
+    pshufb          m1, m17, m6
+    paddw           m0, m1
+    pshufb         m17, m7
+    paddw           m0, m17              ; h sum
+    punpcklwd      m16, m17, m1
+    punpcklwd       m2, m3, m4
+    vpdpwssd        m2, m16, m16         ; h sumsq
+    punpckhwd      m17, m1
+    punpckhwd       m3, m4
+    vpdpwssd        m3, m17, m17
+    paddw           m1, m0, [t2+r10*2+416*0]
+    paddw           m1, [t1+r10*2+416*0] ; hv sum
+    paddd          m16, m2, [t2+r10*2+416*2]
+    paddd          m17, m3, [t2+r10*2+416*4]
+    paddd          m16, [t1+r10*2+416*2] ; hv sumsq
+    paddd          m17, [t1+r10*2+416*4]
+    mova [t0+r10*2+416*0], m0
+    mova [t0+r10*2+416*2], m2
+    mova [t0+r10*2+416*4], m3
+    pmulld         m16, m8               ; -a * 9
+    pmulld         m17, m8
+    punpcklwd       m0, m4, m1           ; b
+    vpdpwssd       m16, m0, m0           ; -p
+    punpckhwd       m1, m4, m1
+    vpdpwssd       m17, m1, m1
+    pmaddwd         m0, m10              ; b * 455
+    pmaddwd         m1, m10
+    pmulld         m16, m11              ; p * s
+    pmulld         m17, m11
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m20
+    paddusw        m17, m12
+    psraw          m17, 4                ; min(z, 255) - 256
+    vpermt2b       m16, m17, m21         ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m18, m19         ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16              ; x
+    pandn          m16, m13, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    paddd           m0, m14              ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m14
+    vpternlogd     m16, m0, m13, 0xd8    ; a | (b << 12)
+    vpternlogd     m17, m1, m13, 0xd8
+    mova          [t3+r10*4+  8], m16
+    mova          [t3+r10*4+ 24], xm17
+    vextracti32x4 [t3+r10*4+ 56], m17, 2
+    mova          [t3+r10*4+ 72], m17
+    vextracti128  [t3+r10*4+ 72], ym16, 1
+    vextracti32x4 [t3+r10*4+104], m16, 3
+    add            r10, 32
+    jl .hv_loop
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t2
+    ret
+.v: ; vertical boxsum + ab
+    lea            r10, [wq-2]
+.v_loop:
+    mova           m16, [t1+r10*2+416*2]
+    mova           m17, [t1+r10*2+416*4]
+    paddd          m16, m16
+    paddd          m17, m17
+    paddd          m16, [t2+r10*2+416*2] ; hv sumsq
+    paddd          m17, [t2+r10*2+416*4]
+    pmulld         m16, m8               ; -a * 9
+    pmulld         m17, m8
+    mova            m1, [t1+r10*2+416*0]
+    paddw           m1, m1
+    paddw           m1, [t2+r10*2+416*0] ; hv sum
+    punpcklwd       m0, m4, m1           ; b
+    vpdpwssd       m16, m0, m0           ; -p
+    punpckhwd       m1, m4, m1
+    vpdpwssd       m17, m1, m1
+    pmaddwd         m0, m10              ; b * 455
+    pmaddwd         m1, m10
+    pmulld         m16, m11              ; p * s
+    pmulld         m17, m11
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m20
+    paddusw        m17, m12
+    psraw          m17, 4                ; min(z, 255) - 256
+    vpermt2b       m16, m17, m21         ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m18, m19         ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16              ; x
+    pandn          m16, m13, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    paddd           m0, m14              ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m14
+    vpternlogd     m16, m0, m13, 0xd8    ; a | (b << 12)
+    vpternlogd     m17, m1, m13, 0xd8
+    mova          [t3+r10*4+  8], m16
+    mova          [t3+r10*4+ 24], xm17
+    vextracti32x4 [t3+r10*4+ 56], m17, 2
+    mova          [t3+r10*4+ 72], m17
+    vextracti128  [t3+r10*4+ 72], ym16, 1
+    vextracti32x4 [t3+r10*4+104], m16, 3
+    add            r10, 32
+    jl .v_loop
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+    mov             t4, t3
+    add             t3, 416*4
+.prep_n_loop:
+    mova            m2, [t5+r10*4+0]
+    mova            m3, [t4+r10*4+0]
+    paddd           m2, [t5+r10*4+8]
+    paddd           m3, [t4+r10*4+8]
+    paddd           m0, m2, [t5+r10*4+4]
+    paddd           m1, m3, [t4+r10*4+4]
+    pslld           m0, 2
+    paddd           m1, m1                ; ab[ 0] 222
+    psubd           m0, m2                ; ab[-1] 343
+    mova [t3+r10*4+416*4], m1
+    paddd           m1, m1
+    mova    [t5+r10*4], m0
+    psubd           m1, m3                ; ab[ 0] 343
+    mova    [t4+r10*4], m1
+    add            r10, 16
+    jl .prep_n_loop
+    ret
+; a+b are packed together in a single dword, but we can't do the
+; full neighbor calculations before splitting them since we don't
+; have sufficient precision. The solution is to do the calculations
+; in two equal halves and split a and b before doing the final sum.
+ALIGN function_align
+.n: ; neighbor + output
+    mov            r10, wq
+.n_loop:
+    mova           m16, [t3+r10*4+ 0]
+    paddd          m16, [t3+r10*4+ 8]
+    paddd          m17, m16, [t3+r10*4+ 4]
+    paddd          m17, m17               ; ab[+1] 222
+    mova            m2, [t3+r10*4+416*4+ 0]
+    paddd           m0, m2, [t5+r10*4+ 0] ; ab[ 0] 222 + ab[-1] 343
+    mova            m3, [t3+r10*4+416*4+64]
+    paddd           m1, m3, [t5+r10*4+64]
+    mova [t3+r10*4+416*4+ 0], m17
+    paddd          m17, m17
+    psubd          m17, m16               ; ab[+1] 343
+    mova [t5+r10*4+ 0], m17
+    paddd           m2, m17               ; ab[ 0] 222 + ab[+1] 343
+    mova           m16, [t3+r10*4+64]
+    paddd          m16, [t3+r10*4+72]
+    paddd          m17, m16, [t3+r10*4+68]
+    paddd          m17, m17
+    mova [t3+r10*4+416*4+64], m17
+    paddd          m17, m17
+    psubd          m17, m16
+    mova [t5+r10*4+64], m17
+    pandn          m16, m13, m0
+    psrld           m0, 12
+    paddd           m3, m17
+    pandn          m17, m13, m2
+    psrld           m2, 12
+    paddd          m16, m17               ; a
+    pandn          m17, m13, m1
+    psrld           m1, 12
+    paddd           m0, m2                ; b + (1 << 8)
+    pandn           m2, m13, m3
+    psrld           m3, 12
+    paddd          m17, m2
+    pmovzxbd        m2, [dstq+r10+ 0]
+    paddd           m1, m3
+    pmovzxbd        m3, [dstq+r10+16]
+    pmaddwd        m16, m2                ; a * src
+    pmaddwd        m17, m3
+    packssdw        m2, m3
+    psubd           m0, m16               ; b - a * src + (1 << 8)
+    psubd           m1, m17
+    psrad           m0, 9
+    psrad           m1, 9
+    packssdw        m0, m1
+    pmulhrsw        m0, m15
+    paddw           m0, m2
+    packuswb        m0, m0
+    vpermd         m16, m9, m0
+    mova    [dstq+r10], ym16
+    add            r10, 32
+    jl .n_loop
+    mov            r10, t5
+    mov             t5, t4
+    mov             t4, r10
+    add           dstq, strideq
+    ret
+
+cglobal sgr_filter_mix_8bpc, 4, 13, 28, 416*56+8, dst, stride, left, lpf, \
+                                                  w, h, edge, params
+    mov        paramsq, r6mp
+    mov             wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    vbroadcasti128  m5, [sgr_shuf+1]
+    add           lpfq, wq
+    vbroadcasti128  m6, [sgr_shuf+9]
+    add           dstq, wq
+    vbroadcasti128  m7, [sgr_shuf+3]
+    lea             t3, [rsp+wq*4+416*24+8]
+    vbroadcasti128  m8, [sgr_shuf+7]
+    pxor            m4, m4
+    vpbroadcastd    m9, [pd_m9]
+    vpsubd         m11, m4, [paramsq+0] {1to16} ; -s0
+    vpbroadcastd   m14, [pw_61448]
+    vpsubd         m12, m4, [paramsq+4] {1to16} ; -s1
+    vpbroadcastd   m26, [paramsq+8]             ; w0 w1
+    lea             t1, [rsp+wq*2+12]
+    vpbroadcastd   m10, [pd_m25]
+    neg             wq
+    vpbroadcastd   m13, [pw_164_455]
+    mov           r10d, 0xfe
+    vpbroadcastd   m15, [pd_34816]
+    kmovb           k1, r10d
+    mova           m20, [sgr_x_by_x+64*0]
+    mov            r10, 0x3333333333333333
+    mova           m21, [sgr_x_by_x+64*1]
+    kmovq           k2, r10
+    mova           m22, [sgr_x_by_x+64*2]
+    lea            r12, [r_ext_mask+75]
+    mova           m23, [sgr_x_by_x+64*3]
+    vpbroadcastd   m24, [pd_m4096]
+    vpbroadcastd   m25, [sgr_shuf+28]           ; 0x8000____
+    psllw          m26, 5
+    mova          xm27, [sgr_mix_perm]
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t2, t1
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_avx512icl).top_fixup
+    add             t1, 416*12
+    call .h_top
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov          [rsp], r10 ; below
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    add           lpfq, strideq
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    add           lpfq, strideq
+    call .hv0
+    test            hd, hd
+    jz .odd_height
+    add           lpfq, strideq
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, [rsp]
+    call .hv0_bottom
+    add           lpfq, strideq
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov          [rsp], r10
+    call .h
+    lea             t2, [t1+416*12]
+    lea            r10, [wq-2]
+.top_fixup_loop:
+    mova            m0, [t1+r10*2+416* 0]
+    mova            m1, [t1+r10*2+416* 2]
+    mova            m2, [t1+r10*2+416* 4]
+    paddw           m0, m0
+    mova            m3, [t1+r10*2+416* 6]
+    paddd           m1, m1
+    mova           m16, [t1+r10*2+416* 8]
+    paddd           m2, m2
+    mova           m17, [t1+r10*2+416*10]
+    mova [t2+r10*2+416* 0], m0
+    mova [t2+r10*2+416* 2], m1
+    mova [t2+r10*2+416* 4], m2
+    mova [t2+r10*2+416* 6], m3
+    mova [t2+r10*2+416* 8], m16
+    mova [t2+r10*2+416*10], m17
+    add            r10, 32
+    jl .top_fixup_loop
+    call .v0
+    jmp .main
+.h: ; horizontal boxsums
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movd          xm17, [leftq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    add          leftq, 4
+    jmp .h_main
+.h_extend_left:
+    vpbroadcastb  xm17, [lpfq+wq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    jmp .h_main
+.h_top:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu          ym17, [lpfq+r10-2]
+.h_main:
+    vinserti32x8   m17, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp           r10d, -34
+    jl .h_have_right
+    vpbroadcastb    m0, [lpfq-1]
+    movu          ym16, [r12+r10-8]
+    vinserti32x8   m16, [r12+r10+0], 1
+    vpternlogd     m17, m0, m16, 0xe4
+.h_have_right:
+    pshufb          m3, m17, m5
+    pshufb         m18, m17, m6
+    shufps          m0, m3, m18, q2121
+    pmullw          m2, m0, m0
+    pshufb         m19, m17, m7
+    paddw           m0, m19
+    pshufb         m17, m8
+    paddw           m0, m17           ; sum3
+    punpcklwd      m16, m19, m17
+    punpcklwd       m1, m2, m4
+    vpdpwssd        m1, m16, m16      ; sumsq3
+    punpckhwd      m19, m17
+    punpckhwd       m2, m4
+    vpdpwssd        m2, m19, m19
+    mova [t1+r10*2+416* 6], m0
+    mova [t1+r10*2+416* 8], m1
+    mova [t1+r10*2+416*10], m2
+    punpcklwd      m19, m3, m18
+    paddw           m0, m3
+    vpdpwssd        m1, m19, m19      ; sumsq5
+    punpckhwd       m3, m18
+    paddw           m0, m18           ; sum5
+    vpdpwssd        m2, m3, m3
+    mova [t1+r10*2+416* 0], m0
+    mova [t1+r10*2+416* 2], m1
+    mova [t1+r10*2+416* 4], m2
+    add            r10, 32
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsums + vertical boxsum3 + ab3 (even rows)
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movd          xm17, [leftq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    add          leftq, 4
+    jmp .hv0_main
+.hv0_extend_left:
+    vpbroadcastb  xm17, [lpfq+wq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    jmp .hv0_main
+.hv0_bottom:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+.hv0_loop:
+    movu          ym17, [lpfq+r10-2]
+.hv0_main:
+    vinserti32x8   m17, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp           r10d, -34
+    jl .hv0_have_right
+    vpbroadcastb    m0, [lpfq-1]
+    movu          ym16, [r12+r10-8]
+    vinserti32x8   m16, [r12+r10+0], 1
+    vpternlogd     m17, m0, m16, 0xe4
+.hv0_have_right:
+    pshufb         m18, m17, m5
+    pshufb         m19, m17, m6
+    shufps          m1, m18, m19, q2121
+    pmullw          m3, m1, m1
+    pshufb          m0, m17, m7
+    paddw           m1, m0
+    pshufb         m17, m8
+    paddw           m1, m17           ; sum3
+    punpcklwd      m16, m0, m17
+    punpcklwd       m2, m3, m4
+    vpdpwssd        m2, m16, m16      ; sumsq3
+    punpckhwd       m0, m17
+    punpckhwd       m3, m4
+    vpdpwssd        m3, m0, m0
+    paddw           m0, m1, [t1+r10*2+416* 6]
+    paddd          m16, m2, [t1+r10*2+416* 8]
+    paddd          m17, m3, [t1+r10*2+416*10]
+    mova [t1+r10*2+416* 6], m1
+    mova [t1+r10*2+416* 8], m2
+    mova [t1+r10*2+416*10], m3
+    paddw           m1, m18
+    paddw           m1, m19           ; sum5
+    mova [t3+r10*4+416*8+ 8], m1
+    paddw           m1, [t1+r10*2+416* 0]
+    mova [t1+r10*2+416* 0], m1
+    punpcklwd       m1, m18, m19
+    vpdpwssd        m2, m1, m1        ; sumsq5
+    punpckhwd      m18, m19
+    vpdpwssd        m3, m18, m18
+    mova [t3+r10*4+416*0+ 8], m2      ; we need a clean copy of the last row
+    mova [t3+r10*4+416*0+72], m3      ; in case height is odd
+    paddd           m2, [t1+r10*2+416* 2]
+    paddd           m3, [t1+r10*2+416* 4]
+    mova [t1+r10*2+416* 2], m2
+    mova [t1+r10*2+416* 4], m3
+    paddw           m1, m0, [t2+r10*2+416* 6]
+    paddd           m2, m16, [t2+r10*2+416* 8]
+    paddd           m3, m17, [t2+r10*2+416*10]
+    mova [t2+r10*2+416* 6], m0
+    mova [t2+r10*2+416* 8], m16
+    mova [t2+r10*2+416*10], m17
+    pmulld         m16, m2, m9        ; -a3 * 9
+    pmulld         m17, m3, m9
+    punpcklwd       m0, m4, m1        ; b3
+    vpdpwssd       m16, m0, m0        ; -p3
+    punpckhwd       m1, m4, m1
+    vpdpwssd       m17, m1, m1
+    pmulld         m16, m12           ; p3 * s1
+    pmulld         m17, m12
+    pmaddwd         m0, m13           ; b3 * 455
+    pmaddwd         m1, m13
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m22
+    paddusw        m17, m14
+    psraw          m17, 4             ; min(z3, 255) - 256
+    vpermt2b       m16, m17, m23      ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m20, m21      ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16           ; x3
+    pandn          m16, m24, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    paddd           m0, m15           ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m15
+    vpternlogd     m16, m0, m24, 0xd8 ; a3 | (b3 << 12)
+    vpternlogd     m17, m1, m24, 0xd8
+    mova          [t3+r10*4+416*4+  8], m16
+    mova          [t3+r10*4+416*4+ 24], xm17
+    vextracti32x4 [t3+r10*4+416*4+ 56], m17, 2
+    mova          [t3+r10*4+416*4+ 72], m17
+    vextracti128  [t3+r10*4+416*4+ 72], ym16, 1
+    vextracti32x4 [t3+r10*4+416*4+104], m16, 3
+    add            r10, 32
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movd          xm17, [leftq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    add          leftq, 4
+    jmp .hv1_main
+.hv1_extend_left:
+    vpbroadcastb  xm17, [lpfq+wq]
+    vmovdqu32 ym17{k1}, [lpfq+wq-4]
+    jmp .hv1_main
+.hv1_bottom:
+    lea            r10, [wq-2]
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+.hv1_loop:
+    movu          ym17, [lpfq+r10-2]
+.hv1_main:
+    vinserti32x8   m17, [lpfq+r10+6], 1
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp           r10d, -34
+    jl .hv1_have_right
+    vpbroadcastb    m0, [lpfq-1]
+    movu          ym16, [r12+r10-8]
+    vinserti32x8   m16, [r12+r10+0], 1
+    vpternlogd    m17, m0, m16, 0xe4
+.hv1_have_right:
+    pshufb          m3, m17, m5
+    pshufb         m19, m17, m6
+    shufps          m2, m3, m19, q2121
+    pmullw          m1, m2, m2
+    pshufb         m18, m17, m7
+    paddw           m2, m18
+    pshufb         m17, m8
+    paddw           m2, m17           ; sum3
+    punpcklwd      m16, m17, m18
+    punpcklwd       m0, m1, m4
+    vpdpwssd        m0, m16, m16      ; sumsq3
+    punpckhwd      m17, m18
+    punpckhwd       m1, m4
+    vpdpwssd        m1, m17, m17
+    paddd          m16, m0, [t2+r10*2+416* 8]
+    paddd          m17, m1, [t2+r10*2+416*10]
+    mova [t2+r10*2+416* 8], m0
+    mova [t2+r10*2+416*10], m1
+    punpcklwd      m18, m3, m19
+    vpdpwssd        m0, m18, m18      ; sumsq5
+    punpckhwd      m18, m3, m19
+    vpdpwssd        m1, m18, m18
+    paddw           m3, m19
+    pmulld         m16, m9            ; -a3 * 9
+    pmulld         m17, m9
+    paddd          m18, m0, [t2+r10*2+416*2]
+    paddd          m19, m1, [t2+r10*2+416*4]
+    paddd          m18, [t1+r10*2+416*2]
+    paddd          m19, [t1+r10*2+416*4]
+    mova [t2+r10*2+416*2], m0
+    mova [t2+r10*2+416*4], m1
+    pmulld         m18, m10           ; -a5 * 25
+    pmulld         m19, m10
+    paddw           m1, m2, [t2+r10*2+416* 6]
+    mova [t2+r10*2+416* 6], m2
+    paddw           m2, m3            ; sum5
+    paddw           m3, m2, [t2+r10*2+416*0]
+    paddw           m3, [t1+r10*2+416*0]
+    mova [t2+r10*2+416*0], m2
+    punpcklwd       m0, m4, m1        ; b3
+    vpdpwssd       m16, m0, m0        ; -p3
+    punpckhwd       m1, m4, m1
+    vpdpwssd       m17, m1, m1
+    punpcklwd       m2, m3, m4        ; b5
+    vpdpwssd       m18, m2, m2        ; -p5
+    punpckhwd       m3, m4
+    vpdpwssd       m19, m3, m3
+    pmulld         m16, m12           ; p3 * s1
+    pmulld         m17, m12
+    pmulld         m18, m11           ; p5 * s0
+    pmulld         m19, m11
+    pmaddwd         m0, m13           ; b3 * 455
+    pmaddwd         m1, m13
+    pmaddwd         m2, m13           ; b5 * 164
+    pmaddwd         m3, m13
+    vpalignr   m17{k2}, m16, m16, 2
+    vpalignr   m19{k2}, m18, m18, 2
+    paddusw        m17, m14
+    mova           m16, m22
+    psraw          m17, 4             ; min(z3, 255) - 256
+    vpermt2b       m16, m17, m23      ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m20, m21      ; sgr_x_by_x[  0..127]
+    paddusw        m19, m14
+    mova           m18, m22
+    psraw          m19, 4             ; min(z5, 255) - 256
+    vpermt2b       m18, m19, m23      ; sgr_x_by_x[128..255]
+    vpmovb2m        k4, m19
+    vpermi2b       m19, m20, m21      ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16           ; x3
+    vmovdqu8   m19{k4}, m18           ; x5
+    pandn          m16, m24, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    pandn          m18, m24, m19
+    psrld          m19, 16
+    pmulld          m2, m18
+    pmulld          m3, m19
+    paddd           m0, m15           ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m15
+    vpternlogd     m16, m0, m24, 0xd8 ; a3 | (b3 << 12)
+    vpternlogd     m17, m1, m24, 0xd8
+    mova          [t3+r10*4+416*8+  8], m16
+    mova          [t3+r10*4+416*8+ 24], xm17
+    vextracti32x4 [t3+r10*4+416*8+ 56], m17, 2
+    paddd           m2, m15           ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m3, m15
+    mova          [t3+r10*4+416*8+ 72], m17
+    vextracti128  [t3+r10*4+416*8+ 72], ym16, 1
+    vextracti32x4 [t3+r10*4+416*8+104], m16, 3
+    vpternlogd     m18, m2, m24, 0xd8 ; a5 | (b5 << 12)
+    vpternlogd     m19, m3, m24, 0xd8
+    mova          [t3+r10*4+416*0+  8], m18
+    mova          [t3+r10*4+416*0+ 24], xm19
+    vextracti32x4 [t3+r10*4+416*0+ 56], m19, 2
+    mova          [t3+r10*4+416*0+ 72], m19
+    vextracti128  [t3+r10*4+416*0+ 72], ym18, 1
+    vextracti32x4 [t3+r10*4+416*0+104], m18, 3
+    add            r10, 32
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab3 (even rows)
+    lea            r10, [wq-2]
+.v0_loop:
+    mova            m2, [t1+r10*2+416* 8]
+    mova            m3, [t1+r10*2+416*10]
+    paddd           m2, m2
+    paddd           m3, m3
+    paddd          m16, m2, [t2+r10*2+416* 8]
+    paddd          m17, m3, [t2+r10*2+416*10]
+    mova            m0, [t1+r10*2+416* 6]
+    paddw           m0, m0
+    paddw           m1, m0, [t2+r10*2+416* 6]
+    pmulld         m16, m9            ; -a3 * 9
+    pmulld         m17, m9
+    mova [t2+r10*2+416* 6], m0
+    mova [t2+r10*2+416* 8], m2
+    mova [t2+r10*2+416*10], m3
+    mova            m2, [t1+r10*2+416*0]
+    mova            m3, [t1+r10*2+416*2]
+    mova           m18, [t1+r10*2+416*4]
+    punpcklwd       m0, m4, m1        ; b3
+    vpdpwssd       m16, m0, m0        ; -p3
+    punpckhwd       m1, m4, m1
+    vpdpwssd       m17, m1, m1
+    pmulld         m16, m12           ; p3 * s1
+    pmulld         m17, m12
+    pmaddwd         m0, m13           ; b3 * 455
+    pmaddwd         m1, m13
+    mova [t3+r10*4+416*8+ 8], m2
+    mova [t3+r10*4+416*0+ 8], m3
+    mova [t3+r10*4+416*0+72], m18
+    vpalignr   m17{k2}, m16, m16, 2
+    mova           m16, m22
+    paddusw        m17, m14
+    psraw          m17, 4             ; min(z3, 255) - 256
+    vpermt2b       m16, m17, m23      ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m20, m21      ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16           ; x3
+    pandn          m16, m24, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    paddw           m2, m2            ; cc5
+    paddd           m3, m3
+    paddd          m18, m18
+    mova [t1+r10*2+416*0], m2
+    mova [t1+r10*2+416*2], m3
+    mova [t1+r10*2+416*4], m18
+    paddd           m0, m15           ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m15
+    vpternlogd     m16, m0, m24, 0xd8 ; a3 | (b3 << 12)
+    vpternlogd     m17, m1, m24, 0xd8
+    mova          [t3+r10*4+416*4+  8], m16
+    mova          [t3+r10*4+416*4+ 24], xm17
+    vextracti32x4 [t3+r10*4+416*4+ 56], m17, 2
+    mova          [t3+r10*4+416*4+ 72], m17
+    vextracti128  [t3+r10*4+416*4+ 72], ym16, 1
+    vextracti32x4 [t3+r10*4+416*4+104], m16, 3
+    add            r10, 32
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+    lea            r10, [wq-2]
+.v1_loop:
+    mova            m0, [t1+r10*2+416* 8]
+    paddd          m16, m0, [t2+r10*2+416* 8]
+    mova            m1, [t1+r10*2+416*10]
+    paddd          m17, m1, [t2+r10*2+416*10]
+    mova            m2, [t3+r10*4+416*0+ 8]
+    paddd          m18, m2, [t2+r10*2+416* 2]
+    mova            m3, [t3+r10*4+416*0+72]
+    paddd          m19, m3, [t2+r10*2+416* 4]
+    paddd          m18, [t1+r10*2+416* 2]
+    paddd          m19, [t1+r10*2+416* 4]
+    mova [t2+r10*2+416* 8], m0
+    mova [t2+r10*2+416*10], m1
+    mova [t2+r10*2+416* 2], m2
+    mova [t2+r10*2+416* 4], m3
+    pmulld         m16, m9            ; -a3 * 9
+    pmulld         m17, m9
+    pmulld         m18, m10           ; -a5 * 25
+    pmulld         m19, m10
+    mova            m0, [t1+r10*2+416* 6]
+    paddw           m1, m0, [t2+r10*2+416* 6]
+    mova            m2, [t3+r10*4+416*8+ 8]
+    paddw           m3, m2, [t2+r10*2+416*0]
+    paddw           m3, [t1+r10*2+416*0]
+    mova [t2+r10*2+416* 6], m0
+    mova [t2+r10*2+416*0], m2
+    punpcklwd       m0, m4, m1        ; b3
+    vpdpwssd       m16, m0, m0        ; -p3
+    punpckhwd       m1, m4, m1
+    vpdpwssd       m17, m1, m1
+    punpcklwd       m2, m3, m4        ; b5
+    vpdpwssd       m18, m2, m2        ; -p5
+    punpckhwd       m3, m4
+    vpdpwssd       m19, m3, m3
+    pmulld         m16, m12           ; p3 * s1
+    pmulld         m17, m12
+    pmulld         m18, m11           ; p5 * s0
+    pmulld         m19, m11
+    pmaddwd         m0, m13           ; b3 * 455
+    pmaddwd         m1, m13
+    pmaddwd         m2, m13           ; b5 * 164
+    pmaddwd         m3, m13
+    vpalignr   m17{k2}, m16, m16, 2
+    vpalignr   m19{k2}, m18, m18, 2
+    paddusw        m17, m14
+    mova           m16, m22
+    psraw          m17, 4             ; min(z3, 255) - 256
+    vpermt2b       m16, m17, m23      ; sgr_x_by_x[128..255]
+    vpmovb2m        k3, m17
+    vpermi2b       m17, m20, m21      ; sgr_x_by_x[  0..127]
+    paddusw        m19, m14
+    mova           m18, m22
+    psraw          m19, 4             ; min(z5, 255) - 256
+    vpermt2b       m18, m19, m23      ; sgr_x_by_x[128..255]
+    vpmovb2m        k4, m19
+    vpermi2b       m19, m20, m21      ; sgr_x_by_x[  0..127]
+    vmovdqu8   m17{k3}, m16           ; x3
+    vmovdqu8   m19{k4}, m18           ; x5
+    pandn          m16, m24, m17
+    psrld          m17, 16
+    pmulld          m0, m16
+    pmulld          m1, m17
+    pandn          m18, m24, m19
+    psrld          m19, m19, 16
+    pmulld          m2, m18
+    pmulld          m3, m19
+    paddd           m0, m15           ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m15
+    vpternlogd     m16, m0, m24, 0xd8 ; a3 | (b3 << 12)
+    vpternlogd     m17, m1, m24, 0xd8
+    mova          [t3+r10*4+416*8+  8], m16
+    mova          [t3+r10*4+416*8+ 24], xm17
+    vextracti32x4 [t3+r10*4+416*8+ 56], m17, 2
+    paddd           m2, m15           ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m3, m15
+    mova          [t3+r10*4+416*8+ 72], m17
+    vextracti128  [t3+r10*4+416*8+ 72], ym16, 1
+    vextracti32x4 [t3+r10*4+416*8+104], m16, 3
+    vpternlogd     m18, m2, m24, 0xd8 ; a5 | (b5 << 12)
+    vpternlogd     m19, m3, m24, 0xd8
+    mova          [t3+r10*4+416*0+  8], m18
+    mova          [t3+r10*4+416*0+ 24], xm19
+    vextracti32x4 [t3+r10*4+416*0+ 56], m19, 2
+    mova          [t3+r10*4+416*0+ 72], m19
+    vextracti128  [t3+r10*4+416*0+ 72], ym18, 1
+    vextracti32x4 [t3+r10*4+416*0+104], m18, 3
+    add            r10, 32
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    mov            r10, wq
+.prep_n_loop:
+    movu            m0, [t3+r10*4+416*0+4]
+    paddd           m1, m0, [t3+r10*4+416*0+0]
+    mova           m16, [t3+r10*4+416*4+0]
+    paddd           m1, [t3+r10*4+416*0+8]
+    mova           m17, [t3+r10*4+416*8+0]
+    paddd          m16, [t3+r10*4+416*4+8]
+    paddd          m17, [t3+r10*4+416*8+8]
+    paddd           m2, m16, [t3+r10*4+416*4+4]
+    paddd           m3, m17, [t3+r10*4+416*8+4]
+    paddd           m0, m1
+    pslld           m1, 2
+    pslld           m2, 2
+    paddd           m1, m0            ; ab5 565
+    paddd           m3, m3            ; ab3[ 0] 222
+    psubd           m2, m16           ; ab3[-1] 343
+    mova [t3+r10*4+416*20], m3
+    pandn           m0, m24, m1       ; a5 565
+    mova [t3+r10*4+416*24], m2
+    psrld           m1, 12            ; b5 565
+    mova [t3+r10*4+416*12], m0
+    paddd           m3, m3
+    mova [t3+r10*4+416*16], m1
+    psubd           m3, m17           ; ab3[ 0] 343
+    mova [t3+r10*4+416*28], m3
+    add            r10, 16
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    mov            r10, wq
+.n0_loop:
+    movu            m2, [t3+r10*4+4]
+    paddd           m3, m2, [t3+r10*4+0]
+    paddd           m3, [t3+r10*4+8]
+    mova            m1, [t3+r10*4+416*4+0]
+    paddd           m2, m3
+    pslld           m3, 2
+    paddd           m1, [t3+r10*4+416*4+8]
+    paddd           m3, m2
+    pandn           m2, m24, m3
+    psrld           m3, 12
+    paddd           m0, m2, [t3+r10*4+416*12] ; a5
+    paddd          m16, m3, [t3+r10*4+416*16] ; b5 + (1 << 8)
+    mova [t3+r10*4+416*12], m2
+    mova [t3+r10*4+416*16], m3
+    paddd           m2, m1, [t3+r10*4+416*4+4]
+    paddd           m2, m2                    ; ab3[ 1] 222
+    mova            m3, [t3+r10*4+416*20]
+    paddd          m17, m3, [t3+r10*4+416*24] ; ab3[ 0] 222 + ab3[-1] 343
+    mova [t3+r10*4+416*20], m2
+    paddd           m2, m2
+    psubd           m2, m1                    ; ab3[ 1] 343
+    mova [t3+r10*4+416*24], m2
+    paddd           m2, m3                    ; ab3[ 0] 222 + ab3[ 1] 343
+    pandn           m1, m24, m17
+    psrld          m17, 12
+    pandn           m3, m24, m2
+    psrld           m2, 12
+    paddd           m1, m3                    ; a3
+    pmovzxbd        m3, [dstq+r10]
+    paddd          m17, m2                    ; b3 + (1 << 8)
+    pmaddwd         m0, m3                    ; a5 * src
+    pmaddwd         m1, m3                    ; a3 * src
+    vpshldd         m3, m25, 16               ; (dst << 16) + (1 << 15)
+    psubd          m16, m0                    ; b5 - a5 * src + (1 << 8)
+    psubd          m17, m1                    ; b3 - a3 * src + (1 << 8)
+    psrld          m16, 9
+    pslld          m17, 7
+    vmovdqu8   m17{k2}, m16
+    vpdpwssd        m3, m17, m26
+    packuswb        m3, m2
+    vpermb         m16, m27, m3
+    mova    [dstq+r10], xm16
+    add            r10, 16
+    jl .n0_loop
+    add           dstq, strideq
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    mov            r10, wq
+.n1_loop:
+    mova            m1, [t3+r10*4+416*8+0]
+    paddd           m1, [t3+r10*4+416*8+8]
+    paddd           m2, m1, [t3+r10*4+416*8+4]
+    paddd           m2, m2                    ; ab3[ 1] 222
+    mova            m0, [t3+r10*4+416*20]
+    paddd          m17, m0, [t3+r10*4+416*28] ; ab3[ 0] 222 + ab3[-1] 343
+    pmovzxbd        m3, [dstq+r10]
+    mova [t3+r10*4+416*20], m2
+    paddd           m2, m2
+    psubd           m2, m1                    ; ab3[ 1] 343
+    mova [t3+r10*4+416*28], m2
+    paddd           m0, m2                    ; ab3[ 0] 222 + ab3[ 1] 343
+    pandn           m1, m24, m17
+    psrld          m17, 12
+    pandn           m2, m24, m0
+    psrld           m0, 12
+    paddd           m1, m2                    ; a3
+    paddd          m17, m0                    ; b3 + (1 << 8)
+    mova           m16, [t3+r10*4+416*16]     ; b5 + (1 << 7)
+    pmaddwd         m1, m3                    ; a3 * src
+    pmaddwd         m0, m3, [t3+r10*4+416*12] ; a5 * src
+    vpshldd         m3, m25, 16               ; (dst << 16) + (1 << 15)
+    psubd          m17, m1                    ; b3 - a3 * src + (1 << 8)
+    psubd          m16, m0                    ; b5 - a5 * src + (1 << 7)
+    pslld          m17, 7
+    palignr    m17{k2}, m16, m16, 1
+    vpdpwssd        m3, m17, m26
+    packuswb        m3, m3
+    vpermb         m16, m27, m3
+    mova    [dstq+r10], xm16
+    add            r10, 16
+    jl .n1_loop
+    add           dstq, strideq
+    ret
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/looprestoration_sse.asm b/media/libdav1d/src/src/x86/looprestoration_sse.asm
new file mode 100644
index 0000000000..d5c2f50238
--- /dev/null
+++ b/media/libdav1d/src/src/x86/looprestoration_sse.asm
@@ -0,0 +1,3502 @@
+; Copyright © 2018, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; Copyright © 2018, VideoLabs
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 16
+
+wiener_init:   db  6,  7,  6,  7,  6,  7,  6,  7,  0,  0,  0,  0,  2,  4,  2,  4
+wiener_shufA:  db  1,  7,  2,  8,  3,  9,  4, 10,  5, 11,  6, 12,  7, 13,  8, 14
+wiener_shufB:  db  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8,  8,  9,  9, 10
+wiener_shufC:  db  6,  5,  7,  6,  8,  7,  9,  8, 10,  9, 11, 10, 12, 11, 13, 12
+wiener_shufD:  db  4, -1,  5, -1,  6, -1,  7, -1,  8, -1,  9, -1, 10, -1, 11, -1
+wiener_l_shuf: db  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11
+sgr_lshuf3:    db  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13
+sgr_lshuf5:    db  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12
+pb_0to15:      db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+
+pb_right_ext_mask: times 24 db 0xff
+                   times 8 db 0
+pb_1:          times 16 db 1
+pw_256:        times 8 dw 256
+pw_2056:       times 8 dw 2056
+pw_m16380:     times 8 dw -16380
+pw_164_24:     times 4 dw 164, 24
+pw_455_24:     times 4 dw 455, 24
+pd_4096:       times 4 dd 4096
+pd_34816:      times 4 dd 34816
+pd_0xffff:     times 4 dd 0xffff
+pf_256:        times 4 dd 256.0
+
+SECTION .text
+
+%macro movif64 2 ; dst, src
+ %if ARCH_X86_64
+    mov             %1, %2
+ %endif
+%endmacro
+
+%macro movif32 2 ; dst, src
+ %if ARCH_X86_32
+    mov             %1, %2
+ %endif
+%endmacro
+
+%if ARCH_X86_32
+ %define PIC_base_offset $$
+
+ %macro SETUP_PIC 1-3 1,0 ; PIC_reg, save_PIC_reg, restore_PIC_reg
+  %assign pic_reg_stk_off 4
+  %xdefine PIC_reg %1
+  %if %2 == 1
+    mov        [esp], %1
+  %endif
+    LEA      PIC_reg, PIC_base_offset
+  %if %3 == 1
+    XCHG_PIC_REG
+  %endif
+ %endmacro
+
+ %macro XCHG_PIC_REG 0
+    mov [esp+pic_reg_stk_off], PIC_reg
+    %assign pic_reg_stk_off (pic_reg_stk_off+4) % 8
+    mov PIC_reg, [esp+pic_reg_stk_off]
+ %endmacro
+
+ %define PIC_sym(sym)   (PIC_reg+(sym)-PIC_base_offset)
+
+%else
+ %macro XCHG_PIC_REG 0
+ %endmacro
+
+ %define PIC_sym(sym)   (sym)
+%endif
+
+%macro WIENER 0
+%if ARCH_X86_64
+DECLARE_REG_TMP 9, 7, 10, 11, 12, 13, 14 ; ring buffer pointers
+cglobal wiener_filter7_8bpc, 4, 15, 16, -384*12-16, dst, stride, left, lpf, \
+                                                    w, h, edge, flt, x
+    %define tmpstrideq strideq
+    %define base 0
+    mov           fltq, r6mp
+    mov             wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    movq           m14, [fltq]
+    add           lpfq, wq
+    movq            m7, [fltq+16]
+    add           dstq, wq
+    lea             t1, [rsp+wq*2+16]
+    mova           m15, [pw_2056]
+    neg             wq
+%if cpuflag(ssse3)
+    pshufb         m14, [wiener_init]
+    mova            m8, [wiener_shufA]
+    pshufd         m12, m14, q2222  ; x0 x0
+    mova            m9, [wiener_shufB]
+    pshufd         m13, m14, q3333  ; x1 x2
+    mova           m10, [wiener_shufC]
+    punpcklqdq     m14, m14         ; x3
+    mova           m11, [wiener_shufD]
+%else
+    mova           m10, [pw_m16380]
+    punpcklwd      m14, m14
+    pshufd         m11, m14, q0000 ; x0
+    pshufd         m12, m14, q1111 ; x1
+    pshufd         m13, m14, q2222 ; x2
+    pshufd         m14, m14, q3333 ; x3
+%endif
+%else
+DECLARE_REG_TMP 4, 0, _, 5
+%if cpuflag(ssse3)
+    %define m10         [base+wiener_shufC]
+    %define m11         [base+wiener_shufD]
+    %define stk_off     96
+%else
+    %define m10         [base+pw_m16380]
+    %define m11         [stk+96]
+    %define stk_off     112
+%endif
+cglobal wiener_filter7_8bpc, 0, 7, 8, -384*12-stk_off, _, x, left, lpf, tmpstride
+    %define base        r6-pb_right_ext_mask-21
+    %define stk         esp
+    %define dstq        leftq
+    %define edgeb       byte edged
+    %define edged       [stk+ 8]
+    %define dstmp       [stk+12]
+    %define hd    dword [stk+16]
+    %define wq          [stk+20]
+    %define strideq     [stk+24]
+    %define leftmp      [stk+28]
+    %define t2          [stk+32]
+    %define t4          [stk+36]
+    %define t5          [stk+40]
+    %define t6          [stk+44]
+    %define m8          [base+wiener_shufA]
+    %define m9          [base+wiener_shufB]
+    %define m12         [stk+48]
+    %define m13         [stk+64]
+    %define m14         [stk+80]
+    %define m15         [base+pw_2056]
+    mov             r1, r6m ; flt
+    mov             r0, r0m ; dst
+    mov             r4, r4m ; w
+    mov           lpfq, lpfm
+    mov             r2, r7m ; edge
+    mov             r5, r5m ; h
+    movq            m3, [r1+ 0]
+    movq            m7, [r1+16]
+    add             r0, r4
+    mov             r1, r1m ; stride
+    add           lpfq, r4
+    mov          edged, r2
+    mov             r2, r2m ; left
+    mov          dstmp, r0
+    lea             t1, [rsp+r4*2+stk_off]
+    mov             hd, r5
+    neg             r4
+    LEA             r6, pb_right_ext_mask+21
+    mov             wq, r4
+    mov        strideq, r1
+    mov         leftmp, r2
+    mov             r4, r1
+%if cpuflag(ssse3)
+    pshufb          m3, [base+wiener_init]
+    pshufd          m1, m3, q2222
+    pshufd          m2, m3, q3333
+    punpcklqdq      m3, m3
+%else
+    punpcklwd       m3, m3
+    pshufd          m0, m3, q0000
+    pshufd          m1, m3, q1111
+    pshufd          m2, m3, q2222
+    pshufd          m3, m3, q3333
+    mova           m11, m0
+%endif
+    mova           m12, m1
+    mova           m13, m2
+    mova           m14, m3
+%endif
+    psllw           m7, 5
+    pshufd          m6, m7, q0000 ; y0 y1
+    pshufd          m7, m7, q1111 ; y2 y3
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t6, t1
+    mov             t5, t1
+    add             t1, 384*2
+    call .h_top
+    lea             t3, [lpfq+tmpstrideq*4]
+    mov           lpfq, dstmp
+    add             t3, tmpstrideq
+    mov          [rsp], t3 ; below
+    mov             t4, t1
+    add             t1, 384*2
+    call .h
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+.main:
+    lea             t0, [t1+384*2]
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v3
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.v1:
+    call mangle(private_prefix %+ _wiener_filter7_8bpc_ssse3).v
+    RET
+.no_top:
+    lea             t3, [lpfq+tmpstrideq*4]
+    mov           lpfq, dstmp
+    lea             t3, [t3+tmpstrideq*2]
+    mov          [rsp], t3
+    call .h
+    mov             t6, t1
+    mov             t5, t1
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v2
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v3
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v3
+    add             t0, 384*8
+    call .hv
+    dec             hd
+    jnz .main
+.v3:
+    call mangle(private_prefix %+ _wiener_filter7_8bpc_ssse3).v
+.v2:
+    call mangle(private_prefix %+ _wiener_filter7_8bpc_ssse3).v
+    jmp .v1
+.extend_right:
+    movd            m2, [lpfq-1]
+%if ARCH_X86_64
+    push            r0
+    lea             r0, [pb_right_ext_mask+21]
+    movu            m0, [r0+xq+0]
+    movu            m1, [r0+xq+8]
+    pop             r0
+%else
+    movu            m0, [r6+xq+0]
+    movu            m1, [r6+xq+8]
+%endif
+%if cpuflag(ssse3)
+    pxor            m3, m3
+    pshufb          m2, m3
+%else
+    punpcklbw       m2, m2
+    pshuflw         m2, m2, q0000
+    punpcklqdq      m2, m2
+%endif
+    pand            m4, m0
+    pand            m5, m1
+    pandn           m0, m2
+    pandn           m1, m2
+    por             m4, m0
+    por             m5, m1
+    ret
+.h:
+    %define stk esp+4 ; offset due to call
+    mov             xq, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movifnidn    leftq, leftmp
+    mova            m4, [lpfq+xq]
+    movd            m5, [leftq]
+    add          leftq, 4
+    pslldq          m4, 4
+    por             m4, m5
+    movifnidn   leftmp, leftq
+    jmp .h_main
+.h_extend_left:
+%if cpuflag(ssse3)
+    mova            m4, [lpfq+xq]
+    pshufb          m4, [base+wiener_l_shuf]
+%else
+    mova            m5, [lpfq+xq]
+    pshufd          m4, m5, q2103
+    punpcklbw       m5, m5
+    punpcklwd       m5, m5
+    movss           m4, m5
+%endif
+    jmp .h_main
+.h_top:
+    mov             xq, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m4, [lpfq+xq-4]
+.h_main:
+    movu            m5, [lpfq+xq+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             xd, -18
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+%macro %%h7 0
+%if cpuflag(ssse3)
+    pshufb          m0, m4, m8
+    pmaddubsw       m0, m12
+    pshufb          m1, m5, m8
+    pmaddubsw       m1, m12
+    pshufb          m2, m4, m9
+    pmaddubsw       m2, m13
+    pshufb          m3, m5, m9
+    pmaddubsw       m3, m13
+    paddw           m0, m2
+    pshufb          m2, m4, m10
+    pmaddubsw       m2, m13
+    paddw           m1, m3
+    pshufb          m3, m5, m10
+    pmaddubsw       m3, m13
+    pshufb          m4, m11
+    paddw           m0, m2
+    pmullw          m2, m14, m4
+    pshufb          m5, m11
+    paddw           m1, m3
+    pmullw          m3, m14, m5
+    psllw           m4, 7
+    psllw           m5, 7
+    paddw           m0, m2
+    mova            m2, [base+pw_m16380]
+    paddw           m1, m3
+    paddw           m4, m2
+    paddw           m5, m2
+    paddsw          m0, m4
+    paddsw          m1, m5
+%else
+    psrldq          m0, m4, 1
+    pslldq          m1, m4, 1
+    pxor            m3, m3
+    punpcklbw       m0, m3
+    punpckhbw       m1, m3
+    paddw           m0, m1
+    pmullw          m0, m11
+    psrldq          m1, m4, 2
+    pslldq          m2, m4, 2
+    punpcklbw       m1, m3
+    punpckhbw       m2, m3
+    paddw           m1, m2
+    pmullw          m1, m12
+    paddw           m0, m1
+    pshufd          m2, m4, q0321
+    punpcklbw       m2, m3
+    pmullw          m1, m14, m2
+    paddw           m0, m1
+    psrldq          m1, m4, 3
+    pslldq          m4, 3
+    punpcklbw       m1, m3
+    punpckhbw       m4, m3
+    paddw           m1, m4
+    pmullw          m1, m13
+    paddw           m0, m1
+    psllw           m2, 7
+    paddw           m2, m10
+    paddsw          m0, m2
+    psrldq          m1, m5, 1
+    pslldq          m2, m5, 1
+    punpcklbw       m1, m3
+    punpckhbw       m2, m3
+    paddw           m1, m2
+    pmullw          m1, m11
+    psrldq          m2, m5, 2
+    pslldq          m4, m5, 2
+    punpcklbw       m2, m3
+    punpckhbw       m4, m3
+    paddw           m2, m4
+    pmullw          m2, m12
+    paddw           m1, m2
+    pshufd          m4, m5, q0321
+    punpcklbw       m4, m3
+    pmullw          m2, m14, m4
+    paddw           m1, m2
+    psrldq          m2, m5, 3
+    pslldq          m5, 3
+    punpcklbw       m2, m3
+    punpckhbw       m5, m3
+    paddw           m2, m5
+    pmullw          m2, m13
+    paddw           m1, m2
+    psllw           m4, 7
+    paddw           m4, m10
+    paddsw          m1, m4
+%endif
+%endmacro
+    %%h7
+    psraw           m0, 3
+    psraw           m1, 3
+    paddw           m0, m15
+    paddw           m1, m15
+    mova  [t1+xq*2+ 0], m0
+    mova  [t1+xq*2+16], m1
+    add             xq, 16
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov             xq, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movifnidn    leftq, leftmp
+    mova            m4, [lpfq+xq]
+    movd            m5, [leftq]
+    add          leftq, 4
+    pslldq          m4, 4
+    por             m4, m5
+    movifnidn   leftmp, leftq
+    jmp .hv_main
+.hv_extend_left:
+%if cpuflag(ssse3)
+    mova            m4, [lpfq+xq]
+    pshufb          m4, [base+wiener_l_shuf]
+%else
+    mova            m5, [lpfq+xq]
+    pshufd          m4, m5, q2103
+    punpcklbw       m5, m5
+    punpcklwd       m5, m5
+    movss           m4, m5
+%endif
+    jmp .hv_main
+.hv_bottom:
+    mov             xq, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m4, [lpfq+xq-4]
+.hv_main:
+    movu            m5, [lpfq+xq+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp             xd, -18
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    %%h7
+%if ARCH_X86_64
+    mova            m2, [t4+xq*2]
+    paddw           m2, [t2+xq*2]
+%else
+    mov             r2, t4
+    mova            m2, [r2+xq*2]
+    mov             r2, t2
+    paddw           m2, [r2+xq*2]
+    mov             r2, t5
+%endif
+    mova            m3, [t3+xq*2]
+%if ARCH_X86_64
+    mova            m5, [t5+xq*2]
+%else
+    mova            m5, [r2+xq*2]
+    mov             r2, t6
+%endif
+    paddw           m5, [t1+xq*2]
+    psraw           m0, 3
+    psraw           m1, 3
+    paddw           m0, m15
+    paddw           m1, m15
+%if ARCH_X86_64
+    paddw           m4, m0, [t6+xq*2]
+%else
+    paddw           m4, m0, [r2+xq*2]
+    mov             r2, t4
+%endif
+    mova     [t0+xq*2], m0
+    punpcklwd       m0, m2, m3
+    pmaddwd         m0, m7
+    punpckhwd       m2, m3
+    pmaddwd         m2, m7
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m6
+    punpckhwd       m4, m5
+    pmaddwd         m4, m6
+    paddd           m0, m3
+    mova            m3, [t3+xq*2+16]
+    paddd           m4, m2
+%if ARCH_X86_64
+    mova            m2, [t4+xq*2+16]
+    paddw           m2, [t2+xq*2+16]
+    mova            m5, [t5+xq*2+16]
+%else
+    mova            m2, [r2+xq*2+16]
+    mov             r2, t2
+    paddw           m2, [r2+xq*2+16]
+    mov             r2, t5
+    mova            m5, [r2+xq*2+16]
+    mov             r2, t6
+%endif
+    paddw           m5, [t1+xq*2+16]
+    packuswb        m0, m4
+%if ARCH_X86_64
+    paddw           m4, m1, [t6+xq*2+16]
+%else
+    paddw           m4, m1, [r2+xq*2+16]
+    mov           dstq, dstmp
+%endif
+    mova  [t0+xq*2+16], m1
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m7
+    punpckhwd       m2, m3
+    pmaddwd         m2, m7
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m6
+    punpckhwd       m4, m5
+    pmaddwd         m4, m6
+    paddd           m1, m3
+    paddd           m2, m4
+    packuswb        m1, m2
+    psrlw           m0, 8
+    psrlw           m1, 8
+    packuswb        m0, m1
+    mova     [dstq+xq], m0
+    add             xq, 16
+    jl .hv_loop
+    add           dstq, strideq
+%if ARCH_X86_64
+    mov             t6, t5
+    mov             t5, t4
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t6
+%else
+    mov          dstmp, dstq
+    mov             r1, t5
+    mov             r2, t4
+    mov             t6, r1
+    mov             t5, r2
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, r1
+%endif
+    ret
+%if cpuflag(ssse3) ; identical in sse2 and ssse3, so share code
+.v:
+    mov             xq, wq
+.v_loop:
+%if ARCH_X86_64
+    mova            m1, [t4+xq*2]
+    paddw           m1, [t2+xq*2]
+%else
+    mov             r2, t4
+    mova            m1, [r2+xq*2]
+    mov             r2, t2
+    paddw           m1, [r2+xq*2]
+    mov             r2, t6
+%endif
+    mova            m2, [t3+xq*2]
+    mova            m4, [t1+xq*2]
+%if ARCH_X86_64
+    paddw           m3, m4, [t6+xq*2]
+    paddw           m4, [t5+xq*2]
+%else
+    paddw           m3, m4, [r2+xq*2]
+    mov             r2, t5
+    paddw           m4, [r2+xq*2]
+    mov             r2, t4
+%endif
+    punpcklwd       m0, m1, m2
+    pmaddwd         m0, m7
+    punpckhwd       m1, m2
+    pmaddwd         m1, m7
+    punpcklwd       m2, m3, m4
+    pmaddwd         m2, m6
+    punpckhwd       m3, m4
+    pmaddwd         m3, m6
+    paddd           m0, m2
+    paddd           m1, m3
+%if ARCH_X86_64
+    mova            m2, [t4+xq*2+16]
+    paddw           m2, [t2+xq*2+16]
+%else
+    mova            m2, [r2+xq*2+16]
+    mov             r2, t2
+    paddw           m2, [r2+xq*2+16]
+    mov             r2, t6
+%endif
+    mova            m3, [t3+xq*2+16]
+    mova            m5, [t1+xq*2+16]
+%if ARCH_X86_64
+    paddw           m4, m5, [t6+xq*2+16]
+    paddw           m5, [t5+xq*2+16]
+%else
+    paddw           m4, m5, [r2+xq*2+16]
+    mov             r2, t5
+    paddw           m5, [r2+xq*2+16]
+    movifnidn     dstq, dstmp
+%endif
+    packuswb        m0, m1
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m7
+    punpckhwd       m2, m3
+    pmaddwd         m2, m7
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m6
+    punpckhwd       m4, m5
+    pmaddwd         m4, m6
+    paddd           m1, m3
+    paddd           m2, m4
+    packuswb        m1, m2
+    psrlw           m0, 8
+    psrlw           m1, 8
+    packuswb        m0, m1
+    mova     [dstq+xq], m0
+    add             xq, 16
+    jl .v_loop
+    add           dstq, strideq
+%if ARCH_X86_64
+    mov             t6, t5
+    mov             t5, t4
+%else
+    mov          dstmp, dstq
+    mov             r1, t5
+    mov             r2, t4
+    mov             t6, r1
+    mov             t5, r2
+%endif
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    ret
+%endif
+
+%if ARCH_X86_64
+cglobal wiener_filter5_8bpc, 4, 13, 16, 384*8+16, dst, stride, left, lpf, \
+                                                  w, h, edge, flt, x
+    mov           fltq, r6mp
+    mov             wd, wm
+    movifnidn       hd, hm
+    mov          edged, r7m
+    movq           m14, [fltq]
+    add           lpfq, wq
+    movq            m7, [fltq+16]
+    add           dstq, wq
+    mova            m8, [pw_m16380]
+    lea             t1, [rsp+wq*2+16]
+    mova           m15, [pw_2056]
+    neg             wq
+%if cpuflag(ssse3)
+    pshufb         m14, [wiener_init]
+    mova            m9, [wiener_shufB]
+    pshufd         m13, m14, q3333  ; x1 x2
+    mova           m10, [wiener_shufC]
+    punpcklqdq     m14, m14         ; x3
+    mova           m11, [wiener_shufD]
+    mova           m12, [wiener_l_shuf]
+%else
+    punpcklwd      m14, m14
+    pshufd         m11, m14, q1111 ; x1
+    pshufd         m13, m14, q2222 ; x2
+    pshufd         m14, m14, q3333 ; x3
+%endif
+%else
+%if cpuflag(ssse3)
+    %define stk_off     80
+%else
+    %define m11         [stk+80]
+    %define stk_off     96
+%endif
+cglobal wiener_filter5_8bpc, 0, 7, 8, -384*8-stk_off, _, x, left, lpf, tmpstride
+    %define stk         esp
+    %define leftmp      [stk+28]
+    %define m8          [base+pw_m16380]
+    %define m12         [base+wiener_l_shuf]
+    %define m14         [stk+48]
+    mov             r1, r6m ; flt
+    mov             r0, r0m ; dst
+    mov             r4, r4m ; w
+    mov           lpfq, lpfm
+    mov             r2, r7m ; edge
+    mov             r5, r5m ; h
+    movq            m2, [r1+ 0]
+    movq            m7, [r1+16]
+    add             r0, r4
+    mov             r1, r1m ; stride
+    add           lpfq, r4
+    mov          edged, r2
+    mov             r2, r2m ; left
+    mov          dstmp, r0
+    lea             t1, [rsp+r4*2+stk_off]
+    mov             hd, r5
+    neg             r4
+    LEA             r6, pb_right_ext_mask+21
+    mov             wq, r4
+    mov        strideq, r1
+    mov         leftmp, r2
+    mov             r4, r1
+%if cpuflag(ssse3)
+    pshufb          m2, [base+wiener_init]
+    pshufd          m1, m2, q3333
+    punpcklqdq      m2, m2
+%else
+    punpcklwd       m2, m2
+    pshufd          m0, m2, q1111
+    pshufd          m1, m2, q2222
+    pshufd          m2, m2, q3333
+    mova           m11, m0
+%endif
+    mova           m13, m1
+    mova           m14, m2
+%endif
+    psllw           m7, 5
+    pshufd          m6, m7, q0000 ; __ y1
+    pshufd          m7, m7, q1111 ; y2 y3
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, strideq
+    mov             t4, t1
+    add             t1, 384*2
+    call .h_top
+    lea             xq, [lpfq+tmpstrideq*4]
+    mov           lpfq, dstmp
+    mov             t3, t1
+    add             t1, 384*2
+    add             xq, tmpstrideq
+    mov          [rsp], xq ; below
+    call .h
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+.main:
+    mov             t0, t4
+.main_loop:
+    call .hv
+    dec             hd
+    jnz .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .v2
+    mov           lpfq, [rsp]
+    call .hv_bottom
+    add           lpfq, strideq
+    call .hv_bottom
+.end:
+    RET
+.no_top:
+    lea             t3, [lpfq+tmpstrideq*4]
+    mov           lpfq, dstmp
+    lea             t3, [t3+tmpstrideq*2]
+    mov          [rsp], t3
+    call .h
+    mov             t4, t1
+    mov             t3, t1
+    mov             t2, t1
+    dec             hd
+    jz .v1
+    add           lpfq, strideq
+    add             t1, 384*2
+    call .h
+    dec             hd
+    jz .v2
+    lea             t0, [t1+384*2]
+    call .hv
+    dec             hd
+    jz .v2
+    add             t0, 384*6
+    call .hv
+    dec             hd
+    jnz .main
+.v2:
+    call mangle(private_prefix %+ _wiener_filter5_8bpc_ssse3).v
+    add           dstq, strideq
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    movifnidn    dstmp, dstq
+.v1:
+    call mangle(private_prefix %+ _wiener_filter5_8bpc_ssse3).v
+    jmp .end
+.h:
+    %define stk esp+4
+    mov             xq, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movifnidn    leftq, leftmp
+    mova            m4, [lpfq+xq]
+    movd            m5, [leftq]
+    add          leftq, 4
+    pslldq          m4, 4
+    por             m4, m5
+    movifnidn   leftmp, leftq
+    jmp .h_main
+.h_extend_left:
+%if cpuflag(ssse3)
+    mova            m4, [lpfq+xq]
+    pshufb          m4, m12
+%else
+    mova            m5, [lpfq+xq]
+    pshufd          m4, m5, q2103
+    punpcklbw       m5, m5
+    punpcklwd       m5, m5
+    movss           m4, m5
+%endif
+    jmp .h_main
+.h_top:
+    mov             xq, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+.h_loop:
+    movu            m4, [lpfq+xq-4]
+.h_main:
+    movu            m5, [lpfq+xq+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             xd, -17
+    jl .h_have_right
+    call mangle(private_prefix %+ _wiener_filter7_8bpc %+ SUFFIX).extend_right
+.h_have_right:
+%macro %%h5 0
+%if cpuflag(ssse3)
+    pshufb          m0, m4, m9
+    pmaddubsw       m0, m13
+    pshufb          m1, m5, m9
+    pmaddubsw       m1, m13
+    pshufb          m2, m4, m10
+    pmaddubsw       m2, m13
+    pshufb          m3, m5, m10
+    pmaddubsw       m3, m13
+    pshufb          m4, m11
+    paddw           m0, m2
+    pmullw          m2, m14, m4
+    pshufb          m5, m11
+    paddw           m1, m3
+    pmullw          m3, m14, m5
+    psllw           m4, 7
+    psllw           m5, 7
+    paddw           m4, m8
+    paddw           m5, m8
+    paddw           m0, m2
+    paddw           m1, m3
+    paddsw          m0, m4
+    paddsw          m1, m5
+%else
+    psrldq          m0, m4, 2
+    pslldq          m1, m4, 2
+    pxor            m3, m3
+    punpcklbw       m0, m3
+    punpckhbw       m1, m3
+    paddw           m0, m1
+    pmullw          m0, m11
+    pshufd          m2, m4, q0321
+    punpcklbw       m2, m3
+    pmullw          m1, m14, m2
+    paddw           m0, m1
+    psrldq          m1, m4, 3
+    pslldq          m4, 3
+    punpcklbw       m1, m3
+    punpckhbw       m4, m3
+    paddw           m1, m4
+    pmullw          m1, m13
+    paddw           m0, m1
+    psllw           m2, 7
+    paddw           m2, m8
+    paddsw          m0, m2
+    psrldq          m1, m5, 2
+    pslldq          m4, m5, 2
+    punpcklbw       m1, m3
+    punpckhbw       m4, m3
+    paddw           m1, m4
+    pmullw          m1, m11
+    pshufd          m4, m5, q0321
+    punpcklbw       m4, m3
+    pmullw          m2, m14, m4
+    paddw           m1, m2
+    psrldq          m2, m5, 3
+    pslldq          m5, 3
+    punpcklbw       m2, m3
+    punpckhbw       m5, m3
+    paddw           m2, m5
+    pmullw          m2, m13
+    paddw           m1, m2
+    psllw           m4, 7
+    paddw           m4, m8
+    paddsw          m1, m4
+%endif
+%endmacro
+    %%h5
+    psraw           m0, 3
+    psraw           m1, 3
+    paddw           m0, m15
+    paddw           m1, m15
+    mova  [t1+xq*2+ 0], m0
+    mova  [t1+xq*2+16], m1
+    add             xq, 16
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv:
+    add           lpfq, strideq
+    mov             xq, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movifnidn    leftq, leftmp
+    mova            m4, [lpfq+xq]
+    movd            m5, [leftq]
+    add          leftq, 4
+    pslldq          m4, 4
+    por             m4, m5
+    movifnidn   leftmp, leftq
+    jmp .hv_main
+.hv_extend_left:
+%if cpuflag(ssse3)
+    mova            m4, [lpfq+xq]
+    pshufb          m4, m12
+%else
+    mova            m5, [lpfq+xq]
+    pshufd          m4, m5, q2103
+    punpcklbw       m5, m5
+    punpcklwd       m5, m5
+    movss           m4, m5
+%endif
+    jmp .hv_main
+.hv_bottom:
+    mov             xq, wq
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+.hv_loop:
+    movu            m4, [lpfq+xq-4]
+.hv_main:
+    movu            m5, [lpfq+xq+4]
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp             xd, -17
+    jl .hv_have_right
+    call mangle(private_prefix %+ _wiener_filter7_8bpc %+ SUFFIX).extend_right
+.hv_have_right:
+    %%h5
+    mova            m2, [t3+xq*2]
+    paddw           m2, [t1+xq*2]
+    psraw           m0, 3
+    psraw           m1, 3
+    paddw           m0, m15
+    paddw           m1, m15
+%if ARCH_X86_64
+    mova            m3, [t2+xq*2]
+    paddw           m4, m0, [t4+xq*2]
+%else
+    mov             r2, t2
+    mova            m3, [r2+xq*2]
+    mov             r2, t4
+    paddw           m4, m0, [r2+xq*2]
+%endif
+    mova     [t0+xq*2], m0
+    punpcklwd       m0, m2, m3
+    pmaddwd         m0, m7
+    punpckhwd       m2, m3
+    pmaddwd         m2, m7
+    punpcklwd       m3, m4, m4
+    pmaddwd         m3, m6
+    punpckhwd       m4, m4
+    pmaddwd         m4, m6
+    paddd           m0, m3
+    paddd           m4, m2
+    mova            m2, [t3+xq*2+16]
+    paddw           m2, [t1+xq*2+16]
+    packuswb        m0, m4
+%if ARCH_X86_64
+    mova            m3, [t2+xq*2+16]
+    paddw           m4, m1, [t4+xq*2+16]
+%else
+    paddw           m4, m1, [r2+xq*2+16]
+    mov             r2, t2
+    mova            m3, [r2+xq*2+16]
+    mov           dstq, dstmp
+%endif
+    mova  [t0+xq*2+16], m1
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m7
+    punpckhwd       m2, m3
+    pmaddwd         m2, m7
+    punpcklwd       m3, m4, m4
+    pmaddwd         m3, m6
+    punpckhwd       m4, m4
+    pmaddwd         m4, m6
+    paddd           m1, m3
+    paddd           m2, m4
+    packuswb        m1, m2
+    psrlw           m0, 8
+    psrlw           m1, 8
+    packuswb        m0, m1
+    mova     [dstq+xq], m0
+    add             xq, 16
+    jl .hv_loop
+    add           dstq, strideq
+    mov             t4, t3
+    mov             t3, t2
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t4
+    movifnidn    dstmp, dstq
+    ret
+%if cpuflag(ssse3)
+.v:
+    mov             xq, wq
+.v_loop:
+    mova            m3, [t1+xq*2]
+    paddw           m1, m3, [t3+xq*2]
+%if ARCH_X86_64
+    mova            m2, [t2+xq*2]
+    paddw           m3, [t4+xq*2]
+%else
+    mov             r2, t2
+    mova            m2, [r2+xq*2]
+    mov             r2, t4
+    paddw           m3, [r2+xq*2]
+%endif
+    punpcklwd       m0, m1, m2
+    pmaddwd         m0, m7
+    punpckhwd       m1, m2
+    pmaddwd         m1, m7
+    punpcklwd       m2, m3
+    pmaddwd         m2, m6
+    punpckhwd       m3, m3
+    pmaddwd         m3, m6
+    paddd           m0, m2
+    paddd           m1, m3
+    mova            m4, [t1+xq*2+16]
+    paddw           m2, m4, [t3+xq*2+16]
+%if ARCH_X86_64
+    mova            m3, [t2+xq*2+16]
+    paddw           m4, [t4+xq*2+16]
+%else
+    paddw           m4, [r2+xq*2+16]
+    mov             r2, t2
+    mova            m3, [r2+xq*2+16]
+    mov           dstq, dstmp
+%endif
+    packuswb        m0, m1
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m7
+    punpckhwd       m2, m3
+    pmaddwd         m2, m7
+    punpcklwd       m3, m4
+    pmaddwd         m3, m6
+    punpckhwd       m4, m4
+    pmaddwd         m4, m6
+    paddd           m1, m3
+    paddd           m2, m4
+    packuswb        m1, m2
+    psrlw           m0, 8
+    psrlw           m1, 8
+    packuswb        m0, m1
+    mova     [dstq+xq], m0
+    add             xq, 16
+    jl .v_loop
+    ret
+%endif
+%endmacro
+
+INIT_XMM sse2
+WIENER
+
+INIT_XMM ssse3
+WIENER
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;      self-guided     ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%macro MUL_32X16X2 6 ; dst[1-2], src[1-2], tmp[1-2]
+    pmulhuw         %5, %1, %3
+    pmulhuw         %6, %2, %4
+    pmullw          %1, %3
+    pmullw          %2, %4
+    pslld           %5, 16
+    pslld           %6, 16
+    paddd           %1, %5
+    paddd           %2, %6
+%endmacro
+
+%macro SGR_CALC_X 9 ; dst, tmp, b[1-2], an[1-2], s, b_mul, pf_256
+    pmaddwd         %1, %3, %3             ; b * b
+    pmaddwd         %2, %4, %4
+    psubd           %5, %1                 ; p
+    psubd           %6, %2
+    MUL_32X16X2     %5, %6, %7, %7, %1, %2 ; p * s
+    pmaddwd         %3, %8                 ; b * b_mul
+    pmaddwd         %4, %8
+    paddw           %5, %8
+    paddw           %6, %8
+    psrld           %5, 20                 ; z + 1
+    psrld           %6, 20
+    cvtdq2ps        %5, %5
+    cvtdq2ps        %6, %6
+    rcpps           %1, %5                 ; 1 / (z + 1)
+    rcpps           %2, %6
+    cmpltps         %5, %9
+    cmpltps         %6, %9
+    mulps           %1, %9                 ; 256 / (z + 1)
+    mulps           %2, %9
+    packssdw        %5, %6
+    cvtps2dq        %1, %1
+    cvtps2dq        %2, %2
+    psrlw           %5, 8                  ; z < 255 ? 255 : 0
+    packssdw        %1, %2
+    pminsw          %1, %5                 ; x
+%endmacro
+
+%if ARCH_X86_32
+DECLARE_REG_TMP 0, 1, 2, 3, 5
+ %if STACK_ALIGNMENT < 16
+  %assign extra_stack 5*16
+ %else
+  %assign extra_stack 3*16
+ %endif
+cglobal sgr_filter_5x5_8bpc, 1, 7, 8, -400*24-16-extra_stack, \
+                             dst, stride, left, lpf, w
+ %if STACK_ALIGNMENT < 16
+  %define dstm         dword [esp+calloff+16*0+4*6]
+  %define stridemp     dword [esp+calloff+16*0+4*7]
+  %define leftm        dword [esp+calloff+16*3+4*0]
+  %define lpfm         dword [esp+calloff+16*3+4*1]
+  %define w0m          dword [esp+calloff+16*3+4*2]
+  %define hd           dword [esp+calloff+16*3+4*3]
+  %define edgeb         byte [esp+calloff+16*3+4*4]
+  %define edged        dword [esp+calloff+16*3+4*4]
+  %define leftmp leftm
+ %else
+  %define w0m wm
+  %define hd dword r5m
+  %define edgeb  byte r7m
+  %define edged dword r7m
+ %endif
+ %define hvsrcm dword [esp+calloff+4*0]
+ %define w1m    dword [esp+calloff+4*1]
+ %define t0m    dword [esp+calloff+4*2]
+ %define t2m    dword [esp+calloff+4*3]
+ %define t3m    dword [esp+calloff+4*4]
+ %define t4m    dword [esp+calloff+4*5]
+ %define  m8 [base+pb_1]
+ %define  m9 [esp+calloff+16*2]
+ %define m10 [base+pw_164_24]
+ %define m11 [base+sgr_lshuf5]
+ %define m12 [base+pd_34816]
+ %define m13 [base+pb_0to15]
+ %define m14 [base+pf_256]
+ %define r10 r4
+ %define base r6-pw_2056
+ %assign calloff 0
+ %if STACK_ALIGNMENT < 16
+    mov        strideq, [rstk+stack_offset+ 8]
+    mov          leftq, [rstk+stack_offset+12]
+    mov           lpfq, [rstk+stack_offset+16]
+    mov             wd, [rstk+stack_offset+20]
+    mov           dstm, dstq
+    mov       stridemp, strideq
+    mov          leftm, leftq
+    mov             r1, [rstk+stack_offset+24]
+    mov             r2, [rstk+stack_offset+32]
+    mov           lpfm, lpfq
+    mov             hd, r1
+    mov          edged, r2
+ %endif
+%else
+DECLARE_REG_TMP 8, 7, 9, 11, 12
+cglobal sgr_filter_5x5_8bpc, 4, 13, 15, -400*24-16, dst, stride, left, lpf, \
+                                                    w, h, edge, params
+%endif
+%if ARCH_X86_64 || STACK_ALIGNMENT >= 16
+    mov             wd, wm
+%endif
+%if ARCH_X86_64
+    mov        paramsq, r6mp
+    movifnidn       hd, hm
+    mov          edged, r7m
+    movu            m9, [paramsq]
+    add           lpfq, wq
+    mova            m8, [pb_1]
+    lea             t1, [rsp+wq*2+20]
+    mova           m10, [pw_164_24]
+    add           dstq, wq
+    lea             t3, [rsp+wq*4+400*12+16]
+    mova           m12, [pd_34816]  ; (1 << 11) + (1 << 15)
+    lea             t4, [rsp+wq*2+400*20+16]
+    pshufhw         m7, m9, q0000
+    pshufb          m9, [pw_256]  ; s0
+    punpckhqdq      m7, m7        ; w0
+    neg             wq
+    mova           m13, [pb_0to15]
+    pxor            m6, m6
+    mova           m11, [sgr_lshuf5]
+    psllw           m7, 4
+    movaps         m14, [pf_256]
+ DEFINE_ARGS dst, stride, left, lpf, _, h, edge, _, _, _, w
+ %define lpfm [rsp]
+%else
+    mov             r1, [rstk+stack_offset+28] ; params
+    LEA             r6, pw_2056
+    movu            m1, [r1]
+    add           lpfm, wq
+    lea             t1, [rsp+extra_stack+wq*2+20]
+    add           dstq, wq
+    lea             t3, [rsp+extra_stack+wq*4+400*12+16]
+    mov           dstm, dstq
+    lea             t4, [rsp+extra_stack+wq*2+400*20+16]
+    mov            t3m, t3
+    pshufhw         m7, m1, q0000
+    mov            t4m, t4
+    pshufb          m1, [base+pw_256] ; s0
+    punpckhqdq      m7, m7            ; w0
+    psllw           m7, 4
+    neg             wq
+    mova            m9, m1
+    pxor            m6, m6
+    mov            w1m, wd
+    sub             wd, 2
+    mov           lpfq, lpfm
+    mov            w0m, wd
+ %define strideq r5
+%endif
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, stridemp
+    mov             t2, t1
+    call .top_fixup
+    add             t1, 400*6
+    call .h_top
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov           lpfm, r10 ; below
+    movif32        t0m, t2
+    mov             t0, t2
+    dec             hd
+    jz .height1
+    or           edged, 16
+    call .h
+.main:
+    add           lpfq, stridemp
+    movif32         t4, t4m
+    call .hv
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+%if ARCH_X86_64
+    test            hb, hb
+%else
+    mov             r4, hd
+    test            r4, r4
+%endif
+    jz .odd_height
+    call .h
+    add           lpfq, stridemp
+    call .hv
+    movif32       dstq, dstm
+    call .n0
+    call .n1
+    sub             hd, 2
+    movif32         t0, t0m
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, lpfm
+    call .h_top
+    add           lpfq, stridemp
+    call .hv_bottom
+.end:
+    movif32       dstq, dstm
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    movif32         t4, t4m
+    call .hv
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .hv
+    movif32       dstq, dstm
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v
+    movif32       dstq, dstm
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v
+    jmp .end
+.no_top:
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov           lpfm, r10
+    call .h
+    lea             t2, [t1+400*6]
+    call .top_fixup
+    dec             hd
+    jz .no_top_height1
+    or           edged, 16
+    mov             t0, t1
+    mov             t1, t2
+    movif32        t0m, t0
+    jmp .main
+.no_top_height1:
+    movif32         t3, t3m
+    movif32         t4, t4m
+    call .v
+    call .prep_n
+    jmp .odd_height_end
+.extend_right:
+%assign stack_offset stack_offset+8
+%assign calloff 8
+    movd            m1, wd
+    movd            m3, [lpfq-1]
+    pshufb          m1, m6
+    pshufb          m3, m6
+    psubb           m2, m8, m1
+    pcmpgtb         m2, m13
+    pand            m5, m2
+    pandn           m2, m3
+    por             m5, m2
+    ret
+%assign stack_offset stack_offset-4
+%assign calloff 4
+.h: ; horizontal boxsum
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+ %define leftq r4
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32      leftq, leftm
+    movddup         m4, [leftq-4]
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    add         leftmp, 4
+    palignr         m5, m4, 13
+    jmp .h_main
+.h_extend_left:
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    pshufb          m5, m11
+    jmp .h_main
+.h_top:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32         wq, w0m
+.h_loop:
+    movu            m5, [lpfq+wq-1]
+.h_main:
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             wd, -10
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    punpcklbw       m4, m5, m6
+    punpckhbw       m5, m6
+    palignr         m2, m5, m4, 2
+    paddw           m0, m4, m2
+    palignr         m3, m5, m4, 6
+    paddw           m0, m3
+    punpcklwd       m1, m2, m3
+    pmaddwd         m1, m1
+    punpckhwd       m2, m3
+    pmaddwd         m2, m2
+    palignr         m5, m4, 8
+    paddw           m0, m5
+    punpcklwd       m3, m4, m5
+    pmaddwd         m3, m3
+    paddd           m1, m3
+    punpckhwd       m3, m4, m5
+    pmaddwd         m3, m3
+    shufps          m4, m5, q2121
+    paddw           m0, m4             ; sum
+    punpcklwd       m5, m4, m6
+    pmaddwd         m5, m5
+    punpckhwd       m4, m6
+    pmaddwd         m4, m4
+    paddd           m2, m3
+    test         edgeb, 16             ; y > 0
+    jz .h_loop_end
+    paddw           m0, [t1+wq*2+400*0]
+    paddd           m1, [t1+wq*2+400*2]
+    paddd           m2, [t1+wq*2+400*4]
+.h_loop_end:
+    paddd           m1, m5             ; sumsq
+    paddd           m2, m4
+    mova [t1+wq*2+400*0], m0
+    mova [t1+wq*2+400*2], m1
+    mova [t1+wq*2+400*4], m2
+    add             wq, 8
+    jl .h_loop
+    ret
+.top_fixup:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov             wd, w0m
+%endif
+.top_fixup_loop: ; the sums of the first row needs to be doubled
+    mova            m0, [t1+wq*2+400*0]
+    mova            m1, [t1+wq*2+400*2]
+    mova            m2, [t1+wq*2+400*4]
+    paddw           m0, m0
+    paddd           m1, m1
+    paddd           m2, m2
+    mova [t2+wq*2+400*0], m0
+    mova [t2+wq*2+400*2], m1
+    mova [t2+wq*2+400*4], m2
+    add             wq, 8
+    jl .top_fixup_loop
+    ret
+ALIGN function_align
+.hv: ; horizontal boxsum + vertical boxsum + ab
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movif32      leftq, leftm
+    movddup         m4, [leftq-4]
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    add         leftmp, 4
+    palignr         m5, m4, 13
+    jmp .hv_main
+.hv_extend_left:
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    pshufb          m5, m11
+    jmp .hv_main
+.hv_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv_loop_start
+%endif
+.hv_loop:
+    movif32       lpfq, hvsrcm
+.hv_loop_start:
+    movu            m5, [lpfq+wq-1]
+.hv_main:
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv_have_right
+    cmp             wd, -10
+    jl .hv_have_right
+    call .extend_right
+.hv_have_right:
+    movif32         t3, hd
+    punpcklbw       m4, m5, m6
+    punpckhbw       m5, m6
+    palignr         m3, m5, m4, 2
+    paddw           m0, m4, m3
+    palignr         m1, m5, m4, 6
+    paddw           m0, m1
+    punpcklwd       m2, m3, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m1
+    pmaddwd         m3, m3
+    palignr         m5, m4, 8
+    paddw           m0, m5
+    punpcklwd       m1, m4, m5
+    pmaddwd         m1, m1
+    paddd           m2, m1
+    punpckhwd       m1, m4, m5
+    pmaddwd         m1, m1
+    shufps          m4, m5, q2121
+    paddw           m0, m4            ; h sum
+    punpcklwd       m5, m4, m6
+    pmaddwd         m5, m5
+    punpckhwd       m4, m6
+    pmaddwd         m4, m4
+    paddd           m3, m1
+    paddd           m2, m5            ; h sumsq
+    paddd           m3, m4
+    paddw           m1, m0, [t1+wq*2+400*0]
+    paddd           m4, m2, [t1+wq*2+400*2]
+    paddd           m5, m3, [t1+wq*2+400*4]
+%if ARCH_X86_64
+    test            hd, hd
+%else
+    test            t3, t3
+%endif
+    jz .hv_last_row
+.hv_main2:
+    paddw           m1, [t2+wq*2+400*0] ; hv sum
+    paddd           m4, [t2+wq*2+400*2] ; hv sumsq
+    paddd           m5, [t2+wq*2+400*4]
+    mova [t0+wq*2+400*0], m0
+    pslld           m0, m4, 4
+    mova [t0+wq*2+400*2], m2
+    mova [t0+wq*2+400*4], m3
+    pslld           m2, m4, 3
+    paddd           m4, m0
+    pslld           m0, m5, 4
+    paddd           m4, m2             ; a * 25
+    pslld           m2, m5, 3
+    paddd           m5, m0
+    paddd           m5, m2
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    SGR_CALC_X      m3, m2, m0, m1, m4, m5, m9, m10, m14
+    movif32         t3, t3m
+    punpcklwd       m2, m3, m3
+    mova   [t4+wq*2+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m12            ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m12
+    psrld           m0, 12             ; b
+    psrld           m1, 12
+    mova  [t3+wq*4+ 8], m0
+    mova  [t3+wq*4+24], m1
+    add             wq, 8
+    jl .hv_loop
+    mov             t2, t1
+    mov             t1, t0
+    mov             t0, t2
+    movif32        t0m, t0
+    ret
+.hv_last_row: ; esoteric edge case for odd heights
+    mova [t1+wq*2+400*0], m1
+    paddw             m1, m0
+    mova [t1+wq*2+400*2], m4
+    paddd             m4, m2
+    mova [t1+wq*2+400*4], m5
+    paddd             m5, m3
+    jmp .hv_main2
+.v: ; vertical boxsum + ab
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov             wd, w0m
+%endif
+.v_loop:
+    mova            m0, [t1+wq*2+400*0]
+    mova            m2, [t1+wq*2+400*2]
+    mova            m3, [t1+wq*2+400*4]
+    paddw           m1, m0, [t2+wq*2+400*0]
+    paddd           m4, m2, [t2+wq*2+400*2]
+    paddd           m5, m3, [t2+wq*2+400*4]
+    paddw           m0, m0
+    paddd           m2, m2
+    paddd           m3, m3
+    paddw           m1, m0             ; hv sum
+    paddd           m4, m2             ; hv sumsq
+    pslld           m0, m4, 4
+    paddd           m5, m3
+    pslld           m2, m4, 3
+    paddd           m4, m0
+    pslld           m0, m5, 4
+    paddd           m4, m2             ; a * 25
+    pslld           m2, m5, 3
+    paddd           m5, m0
+    paddd           m5, m2
+    punpcklwd       m0, m1, m6
+    punpckhwd       m1, m6
+    SGR_CALC_X      m3, m2, m0, m1, m4, m5, m9, m10, m14
+    punpcklwd       m2, m3, m3
+    mova   [t4+wq*2+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m12            ; x * b * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m12
+    psrld           m0, 12             ; b
+    psrld           m1, 12
+    mova  [t3+wq*4+ 8], m0
+    mova  [t3+wq*4+24], m1
+    add             wq, 8
+    jl .v_loop
+    ret
+.prep_n: ; initial neighbor setup
+    movif64         wq, r4
+    movif32         wd, w1m
+.prep_n_loop:
+    movu            m0, [t4+wq*2+ 2]
+    movu            m3, [t4+wq*2+ 4]
+    movu            m1, [t3+wq*4+ 4]
+    movu            m4, [t3+wq*4+ 8]
+    movu            m2, [t3+wq*4+20]
+    movu            m5, [t3+wq*4+24]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    paddw           m3, [t4+wq*2+ 0]
+    paddd           m4, [t3+wq*4+ 0]
+    paddd           m5, [t3+wq*4+16]
+    paddw           m0, m3
+    psllw           m3, 2
+    paddd           m1, m4
+    pslld           m4, 2
+    paddd           m2, m5
+    pslld           m5, 2
+    paddw           m0, m3             ; a 565
+    paddd           m1, m4             ; b 565
+    paddd           m2, m5
+    mova [t4+wq*2+400*2+ 0], m0
+    mova [t3+wq*4+400*4+ 0], m1
+    mova [t3+wq*4+400*4+16], m2
+    add             wq, 8
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n0_loop:
+    movu            m0, [t4+wq*2+ 2]
+    movu            m3, [t4+wq*2+ 4]
+    movu            m1, [t3+wq*4+ 4]
+    movu            m4, [t3+wq*4+ 8]
+    movu            m2, [t3+wq*4+20]
+    movu            m5, [t3+wq*4+24]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    paddw           m3, [t4+wq*2+ 0]
+    paddd           m4, [t3+wq*4+ 0]
+    paddd           m5, [t3+wq*4+16]
+    paddw           m0, m3
+    psllw           m3, 2
+    paddd           m1, m4
+    pslld           m4, 2
+    paddd           m2, m5
+    pslld           m5, 2
+    paddw           m0, m3             ; a 565
+    paddd           m1, m4             ; b 565
+    paddd           m2, m5
+    paddw           m3, m0, [t4+wq*2+400*2+ 0]
+    paddd           m4, m1, [t3+wq*4+400*4+ 0]
+    paddd           m5, m2, [t3+wq*4+400*4+16]
+    mova [t4+wq*2+400*2+ 0], m0
+    mova [t3+wq*4+400*4+ 0], m1
+    mova [t3+wq*4+400*4+16], m2
+    movq            m0, [dstq+wq]
+    punpcklbw       m0, m6
+    punpcklwd       m1, m0, m6          ; src
+    punpcklwd       m2, m3, m6          ; a
+    pmaddwd         m2, m1              ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    psubd           m4, m2              ; b - a * src + (1 << 8)
+    psubd           m5, m3
+    psrad           m4, 9
+    psrad           m5, 9
+    packssdw        m4, m5
+    pmulhrsw        m4, m7
+    paddw           m0, m4
+    packuswb        m0, m0
+    movq     [dstq+wq], m0
+    add             wq, 8
+    jl .n0_loop
+    add           dstq, stridemp
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n1_loop:
+    movq            m0, [dstq+wq]
+    mova            m3, [t4+wq*2+400*2+ 0]
+    mova            m4, [t3+wq*4+400*4+ 0]
+    mova            m5, [t3+wq*4+400*4+16]
+    punpcklbw       m0, m6
+    punpcklwd       m1, m0, m6          ; src
+    punpcklwd       m2, m3, m6          ; a
+    pmaddwd         m2, m1              ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    psubd           m4, m2              ; b - a * src + (1 << 7)
+    psubd           m5, m3
+    psrad           m4, 8
+    psrad           m5, 8
+    packssdw        m4, m5
+    pmulhrsw        m4, m7
+    paddw           m0, m4
+    packuswb        m0, m0
+    movq     [dstq+wq], m0
+    add             wq, 8
+    jl .n1_loop
+    add           dstq, stridemp
+    movif32       dstm, dstq
+    ret
+
+%if ARCH_X86_32
+ %if STACK_ALIGNMENT < 16
+  %assign extra_stack 4*16
+ %else
+  %assign extra_stack 2*16
+ %endif
+cglobal sgr_filter_3x3_8bpc, 1, 7, 8, -400*42-16-extra_stack, \
+                             dst, stride, left, lpf, w
+ %if STACK_ALIGNMENT < 16
+  %define dstm         dword [esp+calloff+16*2+4*0]
+  %define stridemp     dword [esp+calloff+16*2+4*1]
+  %define leftm        dword [esp+calloff+16*2+4*2]
+  %define lpfm         dword [esp+calloff+16*2+4*3]
+  %define w0m          dword [esp+calloff+16*2+4*4]
+  %define hd           dword [esp+calloff+16*2+4*5]
+  %define edgeb         byte [esp+calloff+16*2+4*6]
+  %define edged        dword [esp+calloff+16*2+4*6]
+  %define leftmp leftm
+ %else
+  %define w0m wm
+  %define hd dword r5m
+  %define edgeb  byte r7m
+  %define edged dword r7m
+ %endif
+ %define hvsrcm dword [esp+calloff+4*0]
+ %define w1m    dword [esp+calloff+4*1]
+ %define t3m    dword [esp+calloff+4*2]
+ %define t4m    dword [esp+calloff+4*3]
+ %define  m8 [base+pb_0to15]
+ %define  m9 [esp+calloff+16*1]
+ %define m10 [base+pw_455_24]
+ %define m11 [base+pd_34816]
+ %define m12 m6
+ %define m13 [base+sgr_lshuf3]
+ %define m14 [base+pf_256]
+ %define base r6-pw_2056
+ %assign calloff 0
+ %if STACK_ALIGNMENT < 16
+    mov        strideq, [rstk+stack_offset+ 8]
+    mov          leftq, [rstk+stack_offset+12]
+    mov           lpfq, [rstk+stack_offset+16]
+    mov             wd, [rstk+stack_offset+20]
+    mov           dstm, dstq
+    mov       stridemp, strideq
+    mov          leftm, leftq
+    mov             r1, [rstk+stack_offset+24]
+    mov             r2, [rstk+stack_offset+32]
+    mov           lpfm, lpfq
+    mov             hd, r1
+    mov          edged, r2
+ %endif
+%else
+cglobal sgr_filter_3x3_8bpc, 4, 13, 15, -400*42-8, dst, stride, left, lpf, \
+                                                   w, h, edge, params
+%endif
+%if ARCH_X86_64 || STACK_ALIGNMENT >= 16
+    mov             wd, wm
+%endif
+%if ARCH_X86_64
+    mov        paramsq, r6mp
+    mov             hd, hm
+    mov          edged, r7m
+    movq            m9, [paramsq+4]
+    add           lpfq, wq
+    lea             t1, [rsp+wq*2+12]
+    mova            m8, [pb_0to15]
+    add           dstq, wq
+    lea             t3, [rsp+wq*4+400*12+8]
+    mova           m10, [pw_455_24]
+    lea             t4, [rsp+wq*2+400*32+8]
+    mova           m11, [pd_34816]
+    pshuflw         m7, m9, q3333
+    pshufb          m9, [pw_256]  ; s1
+    punpcklqdq      m7, m7        ; w1
+    neg             wq
+    pxor            m6, m6
+    mova           m13, [sgr_lshuf3]
+    psllw           m7, 4
+    movaps         m14, [pf_256]
+ DEFINE_ARGS dst, stride, left, lpf, _, h, edge, _, _, _, w
+ %define lpfm [rsp]
+%else
+    mov             r1, [rstk+stack_offset+28] ; params
+    LEA             r6, pw_2056
+    movq            m1, [r1+4]
+    add           lpfm, wq
+    lea             t1, [rsp+extra_stack+wq*2+20]
+    add           dstq, wq
+    lea             t3, [rsp+extra_stack+wq*4+400*12+16]
+    mov           dstm, dstq
+    lea             t4, [rsp+extra_stack+wq*2+400*32+16]
+    mov            t3m, t3
+    pshuflw         m7, m1, q3333
+    mov            t4m, t4
+    pshufb          m1, [base+pw_256] ; s1
+    punpcklqdq      m7, m7            ; w1
+    psllw           m7, 4
+    neg             wq
+    mova            m9, m1
+    pxor            m6, m6
+    mov            w1m, wd
+    sub             wd, 2
+    mov           lpfq, lpfm
+    mov            w0m, wd
+ %define strideq r5
+%endif
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, stridemp
+    mov             t2, t1
+    add             t1, 400*6
+    call .h_top
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov           lpfm, r10 ; below
+    movif32         t4, t4m
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv0
+%if ARCH_X86_64
+    test            hb, hb
+%else
+    mov             r4, hd
+    test            r4, r4
+%endif
+    jz .odd_height
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, lpfm
+    call .hv0_bottom
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov           lpfm, r10
+    call .h
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov             wq, w0m
+    mov         hvsrcm, lpfq
+%endif
+    lea             t2, [t1+400*6]
+.top_fixup_loop:
+    mova            m0, [t1+wq*2+400*0]
+    mova            m1, [t1+wq*2+400*2]
+    mova            m2, [t1+wq*2+400*4]
+    mova [t2+wq*2+400*0], m0
+    mova [t2+wq*2+400*2], m1
+    mova [t2+wq*2+400*4], m2
+    add             wq, 8
+    jl .top_fixup_loop
+    movif32         t3, t3m
+    movif32         t4, t4m
+    call .v0
+    jmp .main
+.extend_right:
+%assign stack_offset stack_offset+8
+%assign calloff 8
+    movd            m0, [lpfq-1]
+    movd            m1, wd
+    mova            m3, m8
+    pshufb          m0, m6
+    pshufb          m1, m6
+    mova            m2, m6
+    psubb           m2, m1
+    pcmpgtb         m2, m3
+    pand            m5, m2
+    pandn           m2, m0
+    por             m5, m2
+    ret
+%assign stack_offset stack_offset-4
+%assign calloff 4
+.h: ; horizontal boxsum
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+ %define leftq r4
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32      leftq, leftm
+    movddup         m4, [leftq-4]
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    add         leftmp, 4
+    palignr         m5, m4, 14
+    jmp .h_main
+.h_extend_left:
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    pshufb          m5, m13
+    jmp .h_main
+.h_top:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32         wq, w0m
+.h_loop:
+    movu            m5, [lpfq+wq]
+.h_main:
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .h_have_right
+    cmp             wd, -9
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    punpcklbw       m4, m5, m6
+    punpckhbw       m5, m6
+    palignr         m0, m5, m4, 2
+    paddw           m1, m4, m0
+    punpcklwd       m2, m4, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m0
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m1, m5             ; sum
+    punpcklwd       m4, m5, m6
+    pmaddwd         m4, m4
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m4             ; sumsq
+    paddd           m3, m5
+    mova [t1+wq*2+400*0], m1
+    mova [t1+wq*2+400*2], m2
+    mova [t1+wq*2+400*4], m3
+    add             wq, 8
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsum + vertical boxsum + ab (even rows)
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movif32      leftq, leftm
+    movddup         m4, [leftq-4]
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    add         leftmp, 4
+    palignr         m5, m4, 14
+    jmp .hv0_main
+.hv0_extend_left:
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    pshufb          m5, m13
+    jmp .hv0_main
+.hv0_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv0_loop_start
+%endif
+.hv0_loop:
+    movif32       lpfq, hvsrcm
+.hv0_loop_start:
+    movu            m5, [lpfq+wq]
+.hv0_main:
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv0_have_right
+    cmp             wd, -9
+    jl .hv0_have_right
+    call .extend_right
+.hv0_have_right:
+    punpcklbw       m4, m5, m6
+    punpckhbw       m5, m6
+    palignr         m0, m5, m4, 2
+    paddw           m1, m4, m0
+    punpcklwd       m2, m4, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m0
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m1, m5             ; sum
+    punpcklwd       m4, m5, m6
+    pmaddwd         m4, m4
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m4             ; sumsq
+    paddd           m3, m5
+    paddw           m0, m1, [t1+wq*2+400*0]
+    paddd           m4, m2, [t1+wq*2+400*2]
+    paddd           m5, m3, [t1+wq*2+400*4]
+    mova [t1+wq*2+400*0], m1
+    mova [t1+wq*2+400*2], m2
+    mova [t1+wq*2+400*4], m3
+    paddw           m1, m0, [t2+wq*2+400*0]
+    paddd           m2, m4, [t2+wq*2+400*2]
+    paddd           m3, m5, [t2+wq*2+400*4]
+    mova [t2+wq*2+400*0], m0
+    mova [t2+wq*2+400*2], m4
+    mova [t2+wq*2+400*4], m5
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; a * 9
+    paddd           m5, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    SGR_CALC_X      m3, m2, m0, m1, m4, m5, m9, m10, m14
+    movif32         t3, t3m
+    punpcklwd       m2, m3, m3
+    mova   [t4+wq*2+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m11            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m11
+    psrld           m0, 12
+    psrld           m1, 12
+    mova  [t3+wq*4+ 8], m0
+    mova  [t3+wq*4+24], m1
+    add             wq, 8
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movif32      leftq, leftm
+    movddup         m4, [leftq-4]
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    add         leftmp, 4
+    palignr         m5, m4, 14
+    jmp .hv1_main
+.hv1_extend_left:
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    pshufb          m5, m13
+    jmp .hv1_main
+.hv1_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv1_loop_start
+%endif
+.hv1_loop:
+    movif32       lpfq, hvsrcm
+.hv1_loop_start:
+    movu            m5, [lpfq+wq]
+.hv1_main:
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+    jnz .hv1_have_right
+    cmp             wd, -9
+    jl .hv1_have_right
+    call .extend_right
+.hv1_have_right:
+    punpcklbw       m4, m5, m6
+    punpckhbw       m5, m6
+    palignr         m1, m5, m4, 2
+    paddw           m0, m4, m1
+    punpcklwd       m2, m4, m1
+    pmaddwd         m2, m2
+    punpckhwd       m3, m4, m1
+    pmaddwd         m3, m3
+    palignr         m5, m4, 4
+    paddw           m0, m5             ; h sum
+    punpcklwd       m1, m5, m6
+    pmaddwd         m1, m1
+    punpckhwd       m5, m6
+    pmaddwd         m5, m5
+    paddd           m2, m1             ; h sumsq
+    paddd           m3, m5
+    paddw           m1, m0, [t2+wq*2+400*0]
+    paddd           m4, m2, [t2+wq*2+400*2]
+    paddd           m5, m3, [t2+wq*2+400*4]
+    mova [t2+wq*2+400*0], m0
+    mova [t2+wq*2+400*2], m2
+    mova [t2+wq*2+400*4], m3
+    pslld           m2, m4, 3
+    pslld           m3, m5, 3
+    paddd           m4, m2             ; a * 9
+    paddd           m5, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    SGR_CALC_X      m3, m2, m0, m1, m4, m5, m9, m10, m14
+    movif32         t3, t3m
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*2+400*2 +4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m11            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m11
+    psrld           m0, 12
+    psrld           m1, 12
+    mova [t3+wq*4+400*4+ 8], m0
+    mova [t3+wq*4+400*4+24], m1
+    add             wq, 8
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab (even rows)
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov             wd, w0m
+%endif
+.v0_loop:
+    mova            m0, [t1+wq*2+400*0]
+    mova            m4, [t1+wq*2+400*2]
+    mova            m5, [t1+wq*2+400*4]
+    paddw           m0, m0
+    paddd           m4, m4
+    paddd           m5, m5
+    paddw           m1, m0, [t2+wq*2+400*0]
+    paddd           m2, m4, [t2+wq*2+400*2]
+    paddd           m3, m5, [t2+wq*2+400*4]
+    mova [t2+wq*2+400*0], m0
+    mova [t2+wq*2+400*2], m4
+    mova [t2+wq*2+400*4], m5
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; a * 9
+    paddd           m5, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    SGR_CALC_X      m3, m2, m0, m1, m4, m5, m9, m10, m14
+    punpcklwd       m2, m3, m3
+    mova   [t4+wq*2+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m11            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m11
+    psrld           m0, 12
+    psrld           m1, 12
+    mova  [t3+wq*4+ 8], m0
+    mova  [t3+wq*4+24], m1
+    add             wq, 8
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov             wd, w0m
+%endif
+.v1_loop:
+    mova            m0, [t1+wq*2+400*0]
+    mova            m4, [t1+wq*2+400*2]
+    mova            m5, [t1+wq*2+400*4]
+    paddw           m1, m0, [t2+wq*2+400*0]
+    paddd           m2, m4, [t2+wq*2+400*2]
+    paddd           m3, m5, [t2+wq*2+400*4]
+    mova [t2+wq*2+400*0], m0
+    mova [t2+wq*2+400*2], m4
+    mova [t2+wq*2+400*4], m5
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; a * 9
+    paddd           m5, m3
+    punpcklwd       m0, m1, m6         ; b
+    punpckhwd       m1, m6
+    SGR_CALC_X      m3, m2, m0, m1, m4, m5, m9, m10, m14
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*2+400*2+ 4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m11            ; x * b * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m11
+    psrld           m0, 12
+    psrld           m1, 12
+    mova [t3+wq*4+400*4+ 8], m0
+    mova [t3+wq*4+400*4+24], m1
+    add             wq, 8
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    movif64         wq, r4
+    movif32         wd, w1m
+.prep_n_loop:
+    movu            m0, [t4+wq*2+400*0+ 4]
+    movu            m1, [t3+wq*4+400*0+ 8]
+    movu            m2, [t3+wq*4+400*0+24]
+    movu            m3, [t4+wq*2+400*0+ 2]
+    movu            m4, [t3+wq*4+400*0+ 4]
+    movu            m5, [t3+wq*4+400*0+20]
+    paddw           m0, [t4+wq*2+400*0+ 0]
+    paddd           m1, [t3+wq*4+400*0+ 0]
+    paddd           m2, [t3+wq*4+400*0+16]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    psllw           m3, 2                ; a[-1] 444
+    pslld           m4, 2                ; b[-1] 444
+    pslld           m5, 2
+    psubw           m3, m0               ; a[-1] 343
+    psubd           m4, m1               ; b[-1] 343
+    psubd           m5, m2
+    mova [t4+wq*2+400*4], m3
+    mova [t3+wq*4+400*8+ 0], m4
+    mova [t3+wq*4+400*8+16], m5
+    movu            m0, [t4+wq*2+400*2+ 4]
+    movu            m1, [t3+wq*4+400*4+ 8]
+    movu            m2, [t3+wq*4+400*4+24]
+    movu            m3, [t4+wq*2+400*2+ 2]
+    movu            m4, [t3+wq*4+400*4+ 4]
+    movu            m5, [t3+wq*4+400*4+20]
+    paddw           m0, [t4+wq*2+400*2+ 0]
+    paddd           m1, [t3+wq*4+400*4+ 0]
+    paddd           m2, [t3+wq*4+400*4+16]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    psllw           m3, 2                 ; a[ 0] 444
+    pslld           m4, 2                 ; b[ 0] 444
+    pslld           m5, 2
+    mova [t4+wq*2+400* 6], m3
+    mova [t3+wq*4+400*12+ 0], m4
+    mova [t3+wq*4+400*12+16], m5
+    psubw           m3, m0                ; a[ 0] 343
+    psubd           m4, m1                ; b[ 0] 343
+    psubd           m5, m2
+    mova [t4+wq*2+400* 8], m3
+    mova [t3+wq*4+400*16+ 0], m4
+    mova [t3+wq*4+400*16+16], m5
+    add             wq, 8
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n0_loop:
+    movu            m3, [t4+wq*2+400*0+4]
+    movu            m1, [t4+wq*2+400*0+2]
+    paddw           m3, [t4+wq*2+400*0+0]
+    paddw           m1, m3
+    psllw           m1, 2                ; a[ 1] 444
+    psubw           m2, m1, m3           ; a[ 1] 343
+    paddw           m3, m2, [t4+wq*2+400*4]
+    paddw           m3, [t4+wq*2+400*6]
+    mova [t4+wq*2+400*4], m2
+    mova [t4+wq*2+400*6], m1
+    movu            m4, [t3+wq*4+400*0+8]
+    movu            m1, [t3+wq*4+400*0+4]
+    paddd           m4, [t3+wq*4+400*0+0]
+    paddd           m1, m4
+    pslld           m1, 2                ; b[ 1] 444
+    psubd           m2, m1, m4           ; b[ 1] 343
+    paddd           m4, m2, [t3+wq*4+400* 8+ 0]
+    paddd           m4, [t3+wq*4+400*12+ 0]
+    mova [t3+wq*4+400* 8+ 0], m2
+    mova [t3+wq*4+400*12+ 0], m1
+    movu            m5, [t3+wq*4+400*0+24]
+    movu            m1, [t3+wq*4+400*0+20]
+    paddd           m5, [t3+wq*4+400*0+16]
+    paddd           m1, m5
+    pslld           m1, 2
+    psubd           m2, m1, m5
+    paddd           m5, m2, [t3+wq*4+400* 8+16]
+    paddd           m5, [t3+wq*4+400*12+16]
+    mova [t3+wq*4+400* 8+16], m2
+    mova [t3+wq*4+400*12+16], m1
+    movq            m0, [dstq+wq]
+    punpcklbw       m0, m6
+    punpcklwd       m1, m0, m6
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m1               ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    psubd           m4, m2               ; b - a * src + (1 << 8)
+    psubd           m5, m3
+    psrad           m4, 9
+    psrad           m5, 9
+    packssdw        m4, m5
+    pmulhrsw        m4, m7
+    paddw           m0, m4
+    packuswb        m0, m0
+    movq     [dstq+wq], m0
+    add             wq, 8
+    jl .n0_loop
+    add           dstq, stridemp
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n1_loop:
+    movu            m3, [t4+wq*2+400*2+4]
+    movu            m1, [t4+wq*2+400*2+2]
+    paddw           m3, [t4+wq*2+400*2+0]
+    paddw           m1, m3
+    psllw           m1, 2                ; a[ 1] 444
+    psubw           m2, m1, m3           ; a[ 1] 343
+    paddw           m3, m2, [t4+wq*2+400*6]
+    paddw           m3, [t4+wq*2+400*8]
+    mova [t4+wq*2+400*6], m1
+    mova [t4+wq*2+400*8], m2
+    movu            m4, [t3+wq*4+400*4+8]
+    movu            m1, [t3+wq*4+400*4+4]
+    paddd           m4, [t3+wq*4+400*4+0]
+    paddd           m1, m4
+    pslld           m1, 2                ; b[ 1] 444
+    psubd           m2, m1, m4           ; b[ 1] 343
+    paddd           m4, m2, [t3+wq*4+400*12+ 0]
+    paddd           m4, [t3+wq*4+400*16+ 0]
+    mova [t3+wq*4+400*12+ 0], m1
+    mova [t3+wq*4+400*16+ 0], m2
+    movu            m5, [t3+wq*4+400*4+24]
+    movu            m1, [t3+wq*4+400*4+20]
+    paddd           m5, [t3+wq*4+400*4+16]
+    paddd           m1, m5
+    pslld           m1, 2
+    psubd           m2, m1, m5
+    paddd           m5, m2, [t3+wq*4+400*12+16]
+    paddd           m5, [t3+wq*4+400*16+16]
+    mova [t3+wq*4+400*12+16], m1
+    mova [t3+wq*4+400*16+16], m2
+    movq            m0, [dstq+wq]
+    punpcklbw       m0, m6
+    punpcklwd       m1, m0, m6
+    punpcklwd       m2, m3, m6
+    pmaddwd         m2, m1               ; a * src
+    punpckhwd       m1, m0, m6
+    punpckhwd       m3, m6
+    pmaddwd         m3, m1
+    psubd           m4, m2               ; b - a * src + (1 << 8)
+    psubd           m5, m3
+    psrad           m4, 9
+    psrad           m5, 9
+    packssdw        m4, m5
+    pmulhrsw        m4, m7
+    paddw           m0, m4
+    packuswb        m0, m0
+    movq     [dstq+wq], m0
+    add             wq, 8
+    jl .n1_loop
+    add           dstq, stridemp
+    movif32       dstm, dstq
+    ret
+
+%if ARCH_X86_32
+ %if STACK_ALIGNMENT < 16
+  %assign extra_stack 10*16
+ %else
+  %assign extra_stack 8*16
+ %endif
+cglobal sgr_filter_mix_8bpc, 1, 7, 8, -400*66-48-extra_stack, \
+                             dst, stride, left, lpf, w
+ %if STACK_ALIGNMENT < 16
+  %define dstm         dword [esp+calloff+16*8+4*0]
+  %define stridemp     dword [esp+calloff+16*8+4*1]
+  %define leftm        dword [esp+calloff+16*8+4*2]
+  %define lpfm         dword [esp+calloff+16*8+4*3]
+  %define w0m          dword [esp+calloff+16*8+4*4]
+  %define hd           dword [esp+calloff+16*8+4*5]
+  %define edgeb         byte [esp+calloff+16*8+4*6]
+  %define edged        dword [esp+calloff+16*8+4*6]
+  %define leftmp leftm
+ %else
+  %define w0m wm
+  %define hd dword r5m
+  %define edgeb  byte r7m
+  %define edged dword r7m
+ %endif
+ %define hvsrcm dword [esp+calloff+4*0]
+ %define w1m    dword [esp+calloff+4*1]
+ %define t3m    dword [esp+calloff+4*2]
+ %define t4m    dword [esp+calloff+4*3]
+ %xdefine m8 m6
+ %define  m9 [base+pd_0xffff]
+ %define m10 [base+pd_34816]
+ %define m11 [base+pw_455_24]
+ %define m12 [base+pw_164_24]
+ %define m13 [esp+calloff+16*4]
+ %define m14 [esp+calloff+16*5]
+ %define m15 [esp+calloff+16*6]
+ %define  m6 [esp+calloff+16*7]
+ %define base r6-pw_2056
+ %assign calloff 0
+ %if STACK_ALIGNMENT < 16
+    mov        strideq, [rstk+stack_offset+ 8]
+    mov          leftq, [rstk+stack_offset+12]
+    mov           lpfq, [rstk+stack_offset+16]
+    mov             wd, [rstk+stack_offset+20]
+    mov           dstm, dstq
+    mov       stridemp, strideq
+    mov          leftm, leftq
+    mov             r1, [rstk+stack_offset+24]
+    mov             r2, [rstk+stack_offset+32]
+    mov           lpfm, lpfq
+    mov             hd, r1
+    mov          edged, r2
+ %endif
+%else
+cglobal sgr_filter_mix_8bpc, 4, 13, 16, -400*66-40, dst, stride, left, lpf, \
+                                                    w, h, edge, params
+%endif
+%if ARCH_X86_64 || STACK_ALIGNMENT >= 16
+    mov             wd, wm
+%endif
+%if ARCH_X86_64
+    mov        paramsq, r6mp
+    movifnidn       hd, hm
+    mov          edged, r7m
+    mova           m15, [paramsq]
+    add           lpfq, wq
+    mova            m9, [pd_0xffff]
+    lea             t1, [rsp+wq*2+44]
+    mova           m10, [pd_34816]
+    add           dstq, wq
+    lea             t3, [rsp+wq*4+400*24+40]
+    mova           m11, [pw_455_24]
+    lea             t4, [rsp+wq*2+400*52+40]
+    mova           m12, [pw_164_24]
+    neg             wq
+    pshuflw        m13, m15, q0000
+    pshuflw        m14, m15, q2222
+    pshufhw        m15, m15, q1010
+    punpcklqdq     m13, m13 ; s0
+    punpcklqdq     m14, m14 ; s1
+    punpckhqdq     m15, m15 ; w0 w1
+    pxor            m6, m6
+    psllw          m15, 2
+ DEFINE_ARGS dst, stride, left, lpf, _, h, edge, _, _, _, w
+ %define lpfm [rsp]
+%else
+    mov             r1, [rstk+stack_offset+28] ; params
+    LEA             r6, pw_2056
+    mova            m2, [r1]
+    add           lpfm, wq
+    lea             t1, [rsp+extra_stack+wq*2+52]
+    add           dstq, wq
+    lea             t3, [rsp+extra_stack+wq*4+400*24+48]
+    mov           dstm, dstq
+    lea             t4, [rsp+extra_stack+wq*2+400*52+48]
+    mov            t3m, t3
+    mov            t4m, t4
+    neg             wq
+    pshuflw         m0, m2, q0000
+    pshuflw         m1, m2, q2222
+    pshufhw         m2, m2, q1010
+    punpcklqdq      m0, m0 ; s0
+    punpcklqdq      m1, m1 ; s1
+    punpckhqdq      m2, m2 ; w0 w1
+    mov            w1m, wd
+    pxor            m3, m3
+    psllw           m2, 2
+    mova           m13, m0
+    mova           m14, m1
+    sub             wd, 2
+    mova           m15, m2
+    mova            m6, m3
+    mov           lpfq, lpfm
+    mov            w0m, wd
+ %define strideq r5
+%endif
+    test         edgeb, 4 ; LR_HAVE_TOP
+    jz .no_top
+    call .h_top
+    add           lpfq, stridemp
+    mov             t2, t1
+%if ARCH_X86_64
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_ssse3).top_fixup
+%else
+    mov             wq, w0m
+    call mangle(private_prefix %+ _sgr_filter_5x5_8bpc_ssse3).top_fixup_loop
+%endif
+    add             t1, 400*12
+    call .h_top
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    add            r10, strideq
+    mov           lpfm, r10 ; below
+    movif32         t4, t4m
+    call .hv0
+.main:
+    dec             hd
+    jz .height1
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1
+    call .prep_n
+    sub             hd, 2
+    jl .extend_bottom
+.main_loop:
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv0
+%if ARCH_X86_64
+    test            hd, hd
+%else
+    mov             r4, hd
+    test            r4, r4
+%endif
+    jz .odd_height
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1
+    call .n0
+    call .n1
+    sub             hd, 2
+    jge .main_loop
+    test         edgeb, 8 ; LR_HAVE_BOTTOM
+    jz .extend_bottom
+    mov           lpfq, lpfm
+    call .hv0_bottom
+    movif32       lpfq, hvsrcm
+    add           lpfq, stridemp
+    call .hv1_bottom
+.end:
+    call .n0
+    call .n1
+.end2:
+    RET
+.height1:
+    call .v1
+    call .prep_n
+    jmp .odd_height_end
+.odd_height:
+    call .v1
+    call .n0
+    call .n1
+.odd_height_end:
+    call .v0
+    call .v1
+    call .n0
+    jmp .end2
+.extend_bottom:
+    call .v0
+    call .v1
+    jmp .end
+.no_top:
+    movif32    strideq, stridemp
+    lea            r10, [lpfq+strideq*4]
+    mov           lpfq, dstq
+    lea            r10, [r10+strideq*2]
+    mov           lpfm, r10
+    call .h
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov             wq, w0m
+    mov         hvsrcm, lpfq
+%endif
+    lea             t2, [t1+400*12]
+.top_fixup_loop:
+    mova            m0, [t1+wq*2+400* 0]
+    mova            m1, [t1+wq*2+400* 2]
+    mova            m2, [t1+wq*2+400* 4]
+    paddw           m0, m0
+    mova            m3, [t1+wq*2+400* 6]
+    paddd           m1, m1
+    mova            m4, [t1+wq*2+400* 8]
+    paddd           m2, m2
+    mova            m5, [t1+wq*2+400*10]
+    mova [t2+wq*2+400* 0], m0
+    mova [t2+wq*2+400* 2], m1
+    mova [t2+wq*2+400* 4], m2
+    mova [t2+wq*2+400* 6], m3
+    mova [t2+wq*2+400* 8], m4
+    mova [t2+wq*2+400*10], m5
+    add             wq, 8
+    jl .top_fixup_loop
+    movif32         t3, t3m
+    movif32         t4, t4m
+    call .v0
+    jmp .main
+.extend_right:
+%assign stack_offset stack_offset+8
+%assign calloff 8
+%if ARCH_X86_64
+    SWAP            m8, m6
+%endif
+    movd            m1, wd
+    movd            m3, [lpfq-1]
+    pshufb          m1, m8
+    pshufb          m3, m8
+    psubb           m2, [base+pb_1], m1
+    pcmpgtb         m2, [base+pb_0to15]
+    pand            m5, m2
+    pandn           m2, m3
+    por             m5, m2
+%if ARCH_X86_64
+    SWAP            m6, m8
+%endif
+    ret
+%assign stack_offset stack_offset-4
+%assign calloff 4
+.h: ; horizontal boxsum
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+ %define leftq r4
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32      leftq, leftm
+    movddup         m4, [leftq-4]
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    add         leftmp, 4
+    palignr         m5, m4, 13
+    jmp .h_main
+.h_extend_left:
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    pshufb          m5, [base+sgr_lshuf5]
+    jmp .h_main
+.h_top:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .h_extend_left
+    movif32         wq, w0m
+.h_loop:
+    movu            m5, [lpfq+wq-1]
+.h_main:
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+%if ARCH_X86_32
+    pxor            m8, m8
+%else
+    SWAP            m8, m6
+%endif
+    jnz .h_have_right
+    cmp             wd, -10
+    jl .h_have_right
+    call .extend_right
+.h_have_right:
+    punpcklbw       m4, m5, m8
+    punpckhbw       m5, m8
+    palignr         m3, m5, m4, 2
+    palignr         m0, m5, m4, 4
+    paddw           m1, m3, m0
+    punpcklwd       m2, m3, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m0
+    pmaddwd         m3, m3
+    palignr         m0, m5, m4, 6
+    paddw           m1, m0             ; sum3
+    punpcklwd       m7, m0, m8
+    pmaddwd         m7, m7
+    punpckhwd       m0, m8
+    pmaddwd         m0, m0
+%if ARCH_X86_64
+    SWAP            m6, m8
+%endif
+    paddd           m2, m7             ; sumsq3
+    palignr         m5, m4, 8
+    punpcklwd       m7, m5, m4
+    paddw           m8, m4, m5
+    pmaddwd         m7, m7
+    punpckhwd       m5, m4
+    pmaddwd         m5, m5
+    paddd           m3, m0
+    mova [t1+wq*2+400* 6], m1
+    mova [t1+wq*2+400* 8], m2
+    mova [t1+wq*2+400*10], m3
+    paddw           m8, m1             ; sum5
+    paddd           m7, m2             ; sumsq5
+    paddd           m5, m3
+    mova [t1+wq*2+400* 0], m8
+    mova [t1+wq*2+400* 2], m7
+    mova [t1+wq*2+400* 4], m5
+    add             wq, 8
+    jl .h_loop
+    ret
+ALIGN function_align
+.hv0: ; horizontal boxsum + vertical boxsum + ab3 (even rows)
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movif32      leftq, leftm
+    movddup         m4, [leftq-4]
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    add         leftmp, 4
+    palignr         m5, m4, 13
+    jmp .hv0_main
+.hv0_extend_left:
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    pshufb          m5, [base+sgr_lshuf5]
+    jmp .hv0_main
+.hv0_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv0_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv0_loop_start
+%endif
+.hv0_loop:
+    movif32       lpfq, hvsrcm
+.hv0_loop_start:
+    movu            m5, [lpfq+wq-1]
+.hv0_main:
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+%if ARCH_X86_32
+    pxor            m8, m8
+%else
+    SWAP            m8, m6
+%endif
+    jnz .hv0_have_right
+    cmp             wd, -10
+    jl .hv0_have_right
+    call .extend_right
+.hv0_have_right:
+    punpcklbw       m4, m5, m8
+    punpckhbw       m5, m8
+    palignr         m3, m5, m4, 2
+    palignr         m0, m5, m4, 4
+    movif32         t3, t3m
+    paddw           m1, m3, m0
+    punpcklwd       m2, m3, m0
+    pmaddwd         m2, m2
+    punpckhwd       m3, m0
+    pmaddwd         m3, m3
+    palignr         m0, m5, m4, 6
+    paddw           m1, m0             ; h sum3
+    punpcklwd       m7, m0, m8
+    pmaddwd         m7, m7
+    punpckhwd       m0, m8
+%if ARCH_X86_64
+    SWAP            m6, m8
+%endif
+    pmaddwd         m0, m0
+    paddd           m2, m7             ; h sumsq3
+    palignr         m5, m4, 8
+    punpcklwd       m7, m5, m4
+    paddw           m8, m4, m5
+    pmaddwd         m7, m7
+    punpckhwd       m5, m4
+    pmaddwd         m5, m5
+    paddd           m3, m0
+    paddw           m8, m1             ; h sum5
+    paddd           m7, m2             ; h sumsq5
+    paddd           m5, m3
+    mova [t3+wq*4+400*8+ 8], m8
+    mova [t3+wq*4+400*0+ 8], m7
+    mova [t3+wq*4+400*0+24], m5
+    paddw           m8, [t1+wq*2+400* 0]
+    paddd           m7, [t1+wq*2+400* 2]
+    paddd           m5, [t1+wq*2+400* 4]
+    mova [t1+wq*2+400* 0], m8
+    mova [t1+wq*2+400* 2], m7
+    mova [t1+wq*2+400* 4], m5
+    paddw           m0, m1, [t1+wq*2+400* 6]
+    paddd           m4, m2, [t1+wq*2+400* 8]
+    paddd           m5, m3, [t1+wq*2+400*10]
+    mova [t1+wq*2+400* 6], m1
+    mova [t1+wq*2+400* 8], m2
+    mova [t1+wq*2+400*10], m3
+    paddw           m1, m0, [t2+wq*2+400* 6]
+    paddd           m2, m4, [t2+wq*2+400* 8]
+    paddd           m3, m5, [t2+wq*2+400*10]
+    mova [t2+wq*2+400* 6], m0
+    mova [t2+wq*2+400* 8], m4
+    mova [t2+wq*2+400*10], m5
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; a3 * 9
+    paddd           m5, m3
+    movaps          m7, [base+pf_256]
+%if ARCH_X86_32
+    pxor            m2, m2
+    punpcklwd       m0, m1, m2
+    punpckhwd       m1, m2
+%else
+    punpcklwd       m0, m1, m6         ; b3
+    punpckhwd       m1, m6
+%endif
+    SGR_CALC_X      m3, m2, m0, m1, m4, m5, m14, m11, m7
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*2+400*2+ 4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova [t3+wq*4+400*4+ 8], m0
+    mova [t3+wq*4+400*4+24], m1
+    add             wq, 8
+    jl .hv0_loop
+    ret
+ALIGN function_align
+.hv1: ; horizontal boxsums + vertical boxsums + ab (odd rows)
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movif32      leftq, leftm
+    movddup         m4, [leftq-4]
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    add         leftmp, 4
+    palignr         m5, m4, 13
+    jmp .hv1_main
+.hv1_extend_left:
+    movif32         wq, w0m
+    mova            m5, [lpfq+wq+2]
+    pshufb          m5, [base+sgr_lshuf5]
+    jmp .hv1_main
+.hv1_bottom:
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov         hvsrcm, lpfq
+%endif
+    test         edgeb, 1 ; LR_HAVE_LEFT
+    jz .hv1_extend_left
+    movif32         wq, w0m
+%if ARCH_X86_32
+    jmp .hv1_loop_start
+%endif
+.hv1_loop:
+    movif32       lpfq, hvsrcm
+.hv1_loop_start:
+    movu            m5, [lpfq+wq-1]
+.hv1_main:
+    test         edgeb, 2 ; LR_HAVE_RIGHT
+%if ARCH_X86_32
+    pxor            m8, m8
+%else
+    SWAP            m8, m6
+%endif
+    jnz .hv1_have_right
+    cmp             wd, -10
+    jl .hv1_have_right
+    call .extend_right
+.hv1_have_right:
+    punpcklbw       m4, m5, m8
+    punpckhbw       m5, m8
+    palignr         m7, m5, m4, 2
+    palignr         m3, m5, m4, 4
+    paddw           m2, m7, m3
+    punpcklwd       m0, m7, m3
+    pmaddwd         m0, m0
+    punpckhwd       m7, m3
+    pmaddwd         m7, m7
+    palignr         m3, m5, m4, 6
+    paddw           m2, m3             ; h sum3
+    punpcklwd       m1, m3, m8
+    pmaddwd         m1, m1
+    punpckhwd       m3, m8
+%if ARCH_X86_64
+    SWAP            m6, m8
+%endif
+    pmaddwd         m3, m3
+    paddd           m0, m1             ; h sumsq3
+    palignr         m5, m4, 8
+    punpckhwd       m1, m4, m5
+    paddw           m8, m4, m5
+    pmaddwd         m1, m1
+    punpcklwd       m4, m5
+    pmaddwd         m4, m4
+    paddd           m7, m3
+    paddw           m5, m2, [t2+wq*2+400* 6]
+    mova [t2+wq*2+400* 6], m2
+    paddw           m8, m2             ; h sum5
+    paddd           m2, m0, [t2+wq*2+400* 8]
+    paddd           m3, m7, [t2+wq*2+400*10]
+    mova [t2+wq*2+400* 8], m0
+    mova [t2+wq*2+400*10], m7
+    paddd           m4, m0             ; h sumsq5
+    paddd           m1, m7
+    pslld           m0, m2, 3
+    pslld           m7, m3, 3
+    paddd           m2, m0             ; a3 * 9
+    paddd           m3, m7
+%if ARCH_X86_32
+    mova      [esp+20], m8
+    pxor            m8, m8
+%else
+    SWAP            m8, m6
+%endif
+    punpcklwd       m0, m5, m8         ; b3
+    punpckhwd       m5, m8
+    SGR_CALC_X      m8, m7, m0, m5, m2, m3, m14, m11, [base+pf_256]
+    movif32         t3, t3m
+    punpcklwd       m2, m8, m8
+    mova [t4+wq*2+400*4+ 4], m8
+    punpckhwd       m8, m8
+    MUL_32X16X2     m0, m5, m2, m8, m3, m7
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m5, m10
+    psrld           m0, 12
+    psrld           m5, 12
+    mova [t3+wq*4+400*8+ 8], m0
+    mova [t3+wq*4+400*8+24], m5
+%if ARCH_X86_32
+    mova            m8, [esp+20]
+%else
+    SWAP            m6, m8
+    pxor            m6, m6
+%endif
+    paddw           m5, m8, [t2+wq*2+400*0]
+    paddd           m2, m4, [t2+wq*2+400*2]
+    paddd           m3, m1, [t2+wq*2+400*4]
+    paddw           m5, [t1+wq*2+400*0]
+    paddd           m2, [t1+wq*2+400*2]
+    paddd           m3, [t1+wq*2+400*4]
+    mova [t2+wq*2+400*0], m8
+    pslld           m0, m2, 4
+    mova [t2+wq*2+400*2], m4
+    pslld           m8, m3, 4
+    mova [t2+wq*2+400*4], m1
+    pslld           m4, m2, 3
+    paddd           m2, m0
+    pslld           m0, m3, 3
+    paddd           m3, m8
+    paddd           m2, m4             ; a5 * 25
+    paddd           m3, m0
+%if ARCH_X86_32
+    pxor            m7, m7
+    punpcklwd       m0, m5, m7
+    punpckhwd       m5, m7
+%else
+    punpcklwd       m0, m5, m6         ; b5
+    punpckhwd       m5, m6
+%endif
+    movaps          m8, [base+pf_256]
+    SGR_CALC_X      m1, m4, m0, m5, m2, m3, m13, m12, m8
+    punpcklwd       m2, m1, m1
+    mova   [t4+wq*2+4], m1
+    punpckhwd       m1, m1
+    MUL_32X16X2     m0, m5, m2, m1, m3, m4
+    paddd           m0, m10            ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m5, m10
+    psrld           m0, 12
+    psrld           m5, 12
+    mova  [t3+wq*4+ 8], m0
+    mova  [t3+wq*4+24], m5
+    add             wq, 8
+    jl .hv1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.v0: ; vertical boxsums + ab3 (even rows)
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov             wd, w0m
+%endif
+    movaps          m8, [base+pf_256]
+.v0_loop:
+    mova            m0, [t1+wq*2+400* 6]
+    mova            m4, [t1+wq*2+400* 8]
+    mova            m5, [t1+wq*2+400*10]
+    paddw           m0, m0
+    paddd           m4, m4
+    paddd           m5, m5
+    paddw           m1, m0, [t2+wq*2+400* 6]
+    paddd           m2, m4, [t2+wq*2+400* 8]
+    paddd           m3, m5, [t2+wq*2+400*10]
+    mova [t2+wq*2+400* 6], m0
+    mova [t2+wq*2+400* 8], m4
+    mova [t2+wq*2+400*10], m5
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; a3 * 9
+    paddd           m5, m3
+%if ARCH_X86_32
+    pxor            m7, m7
+    punpcklwd       m0, m1, m7
+    punpckhwd       m1, m7
+%else
+    punpcklwd       m0, m1, m6         ; b3
+    punpckhwd       m1, m6
+%endif
+    SGR_CALC_X      m3, m2, m0, m1, m4, m5, m14, m11, m8
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*2+400*2+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m1, m2, m3, m4, m5
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova            m3, [t1+wq*2+400*0]
+    mova            m4, [t1+wq*2+400*2]
+    mova            m5, [t1+wq*2+400*4]
+    mova [t3+wq*4+400*8+ 8], m3
+    mova [t3+wq*4+400*0+ 8], m4
+    mova [t3+wq*4+400*0+24], m5
+    paddw           m3, m3 ; cc5
+    paddd           m4, m4
+    paddd           m5, m5
+    mova [t1+wq*2+400*0], m3
+    mova [t1+wq*2+400*2], m4
+    mova [t1+wq*2+400*4], m5
+    mova [t3+wq*4+400*4+ 8], m0
+    mova [t3+wq*4+400*4+24], m1
+    add             wq, 8
+    jl .v0_loop
+    ret
+.v1: ; vertical boxsums + ab (odd rows)
+%if ARCH_X86_64
+    lea             wq, [r4-2]
+%else
+    mov             wd, w0m
+%endif
+.v1_loop:
+    mova            m4, [t1+wq*2+400* 6]
+    mova            m5, [t1+wq*2+400* 8]
+    mova            m7, [t1+wq*2+400*10]
+    paddw           m8, m4, [t2+wq*2+400* 6]
+    paddd           m2, m5, [t2+wq*2+400* 8]
+    paddd           m3, m7, [t2+wq*2+400*10]
+    mova [t2+wq*2+400* 6], m4
+    mova [t2+wq*2+400* 8], m5
+    mova [t2+wq*2+400*10], m7
+    pslld           m4, m2, 3
+    pslld           m5, m3, 3
+    paddd           m4, m2             ; ((a3 + 8) >> 4) * 9
+    paddd           m5, m3
+    movaps          m1, [base+pf_256]
+%if ARCH_X86_32
+    pxor            m7, m7
+    punpcklwd       m0, m8, m7
+    punpckhwd       m8, m7
+%else
+    punpcklwd       m0, m8, m6         ; b3
+    punpckhwd       m8, m6
+%endif
+    SGR_CALC_X      m3, m2, m0, m8, m4, m5, m14, m11, m1
+    punpcklwd       m2, m3, m3
+    mova [t4+wq*2+400*4+4], m3
+    punpckhwd       m3, m3
+    MUL_32X16X2     m0, m8, m2, m3, m4, m5
+    paddd           m0, m10            ; x3 * b3 * 455 + (1 << 11) + (1 << 15)
+    paddd           m8, m10
+    psrld           m0, 12
+    psrld           m8, 12
+    mova            m4, [t3+wq*4+400*8+ 8]
+    mova            m5, [t3+wq*4+400*0+ 8]
+    mova            m7, [t3+wq*4+400*0+24]
+    paddw           m1, m4, [t2+wq*2+400*0]
+    paddd           m2, m5, [t2+wq*2+400*2]
+    paddd           m3, m7, [t2+wq*2+400*4]
+    paddw           m1, [t1+wq*2+400*0]
+    paddd           m2, [t1+wq*2+400*2]
+    paddd           m3, [t1+wq*2+400*4]
+    mova [t2+wq*2+400*0], m4
+    mova [t2+wq*2+400*2], m5
+    mova [t2+wq*2+400*4], m7
+    pslld           m4, m2, 4
+    mova [t3+wq*4+400*8+ 8], m0
+    pslld           m5, m3, 4
+    mova [t3+wq*4+400*8+24], m8
+    pslld           m7, m2, 3
+    paddd           m2, m4
+    pslld           m4, m3, 3
+    paddd           m3, m5
+    paddd           m2, m7             ; a5 * 25
+    paddd           m3, m4
+    movaps          m8, [base+pf_256]
+%if ARCH_X86_32
+    pxor            m7, m7
+    punpcklwd       m0, m1, m7
+    punpckhwd       m1, m7
+%else
+    punpcklwd       m0, m1, m6         ; b5
+    punpckhwd       m1, m6
+%endif
+    SGR_CALC_X      m5, m4, m0, m1, m2, m3, m13, m12, m8
+    punpcklwd       m4, m5, m5
+    mova   [t4+wq*2+4], m5
+    punpckhwd       m5, m5
+    MUL_32X16X2     m0, m1, m4, m5, m2, m3
+    paddd           m0, m10            ; x5 * b5 * 164 + (1 << 11) + (1 << 15)
+    paddd           m1, m10
+    psrld           m0, 12
+    psrld           m1, 12
+    mova  [t3+wq*4+ 8], m0
+    mova  [t3+wq*4+24], m1
+    add             wq, 8
+    jl .v1_loop
+    mov            r10, t2
+    mov             t2, t1
+    mov             t1, r10
+    ret
+.prep_n: ; initial neighbor setup
+    movif64         wq, r4
+    movif32         wd, w1m
+.prep_n_loop:
+    movu            m0, [t4+wq*2+400*0+ 2]
+    movu            m1, [t3+wq*4+400*0+ 4]
+    movu            m2, [t3+wq*4+400*0+20]
+    movu            m7, [t4+wq*2+400*0+ 4]
+    movu            m8, [t3+wq*4+400*0+ 8]
+    paddw           m3, m0, [t4+wq*2+400*0+ 0]
+    paddd           m4, m1, [t3+wq*4+400*0+ 0]
+    paddd           m5, m2, [t3+wq*4+400*0+16]
+    paddw           m3, m7
+    paddd           m4, m8
+    movu            m7, [t3+wq*4+400*0+24]
+    paddw           m0, m3
+    paddd           m1, m4
+    psllw           m3, 2
+    pslld           m4, 2
+    paddd           m5, m7
+    paddd           m2, m5
+    pslld           m5, 2
+    paddw           m0, m3               ; a5 565
+    paddd           m1, m4               ; b5 565
+    paddd           m2, m5
+    mova [t4+wq*2+400* 6+ 0], m0
+    mova [t3+wq*4+400*12+ 0], m1
+    mova [t3+wq*4+400*12+16], m2
+    movu            m0, [t4+wq*2+400*2+ 4]
+    movu            m1, [t3+wq*4+400*4+ 8]
+    movu            m2, [t3+wq*4+400*4+24]
+    movu            m3, [t4+wq*2+400*2+ 2]
+    movu            m4, [t3+wq*4+400*4+ 4]
+    movu            m5, [t3+wq*4+400*4+20]
+    paddw           m0, [t4+wq*2+400*2+ 0]
+    paddd           m1, [t3+wq*4+400*4+ 0]
+    paddd           m2, [t3+wq*4+400*4+16]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    psllw           m3, 2                ; a3[-1] 444
+    pslld           m4, 2                ; b3[-1] 444
+    pslld           m5, 2
+    psubw           m3, m0               ; a3[-1] 343
+    psubd           m4, m1               ; b3[-1] 343
+    psubd           m5, m2
+    mova [t4+wq*2+400* 8+ 0], m3
+    mova [t3+wq*4+400*16+ 0], m4
+    mova [t3+wq*4+400*16+16], m5
+    movu            m0, [t4+wq*2+400*4+ 4]
+    movu            m1, [t3+wq*4+400*8+ 8]
+    movu            m2, [t3+wq*4+400*8+24]
+    movu            m3, [t4+wq*2+400*4+ 2]
+    movu            m4, [t3+wq*4+400*8+ 4]
+    movu            m5, [t3+wq*4+400*8+20]
+    paddw           m0, [t4+wq*2+400*4+ 0]
+    paddd           m1, [t3+wq*4+400*8+ 0]
+    paddd           m2, [t3+wq*4+400*8+16]
+    paddw           m3, m0
+    paddd           m4, m1
+    paddd           m5, m2
+    psllw           m3, 2                 ; a3[ 0] 444
+    pslld           m4, 2                 ; b3[ 0] 444
+    pslld           m5, 2
+    mova [t4+wq*2+400*10+ 0], m3
+    mova [t3+wq*4+400*20+ 0], m4
+    mova [t3+wq*4+400*20+16], m5
+    psubw           m3, m0                ; a3[ 0] 343
+    psubd           m4, m1                ; b3[ 0] 343
+    psubd           m5, m2
+    mova [t4+wq*2+400*12+ 0], m3
+    mova [t3+wq*4+400*24+ 0], m4
+    mova [t3+wq*4+400*24+16], m5
+    add             wq, 8
+    jl .prep_n_loop
+    ret
+ALIGN function_align
+.n0: ; neighbor + output (even rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n0_loop:
+    movu            m0, [t4+wq*2+ 4]
+    movu            m2, [t4+wq*2+ 2]
+    paddw           m0, [t4+wq*2+ 0]
+    paddw           m0, m2
+    paddw           m2, m0
+    psllw           m0, 2
+    paddw           m0, m2               ; a5
+    movu            m4, [t3+wq*4+ 8]
+    movu            m5, [t3+wq*4+24]
+    movu            m1, [t3+wq*4+ 4]
+    movu            m3, [t3+wq*4+20]
+    paddd           m4, [t3+wq*4+ 0]
+    paddd           m5, [t3+wq*4+16]
+    paddd           m4, m1
+    paddd           m5, m3
+    paddd           m1, m4
+    paddd           m3, m5
+    pslld           m4, 2
+    pslld           m5, 2
+    paddd           m4, m1               ; b5
+    paddd           m5, m3
+    movu            m2, [t4+wq*2+400* 6]
+    paddw           m2, m0
+    mova [t4+wq*2+400* 6], m0
+    paddd           m0, m4, [t3+wq*4+400*12+ 0]
+    paddd           m1, m5, [t3+wq*4+400*12+16]
+    mova [t3+wq*4+400*12+ 0], m4
+    mova [t3+wq*4+400*12+16], m5
+    mova [rsp+16+ARCH_X86_32*4], m1
+    movu            m3, [t4+wq*2+400*2+4]
+    movu            m5, [t4+wq*2+400*2+2]
+    paddw           m3, [t4+wq*2+400*2+0]
+    paddw           m5, m3
+    psllw           m5, 2                ; a3[ 1] 444
+    psubw           m4, m5, m3           ; a3[ 1] 343
+    movu            m3, [t4+wq*2+400* 8]
+    paddw           m3, [t4+wq*2+400*10]
+    paddw           m3, m4
+    mova [t4+wq*2+400* 8], m4
+    mova [t4+wq*2+400*10], m5
+    movu            m1, [t3+wq*4+400*4+ 8]
+    movu            m5, [t3+wq*4+400*4+ 4]
+    movu            m7, [t3+wq*4+400*4+24]
+    movu            m8, [t3+wq*4+400*4+20]
+    paddd           m1, [t3+wq*4+400*4+ 0]
+    paddd           m7, [t3+wq*4+400*4+16]
+    paddd           m5, m1
+    paddd           m8, m7
+    pslld           m5, 2                ; b3[ 1] 444
+    pslld           m8, 2
+    psubd           m4, m5, m1           ; b3[ 1] 343
+%if ARCH_X86_32
+    mova      [esp+52], m8
+    psubd           m8, m7
+%else
+    psubd           m6, m8, m7
+    SWAP            m8, m6
+%endif
+    paddd           m1, m4, [t3+wq*4+400*16+ 0]
+    paddd           m7, m8, [t3+wq*4+400*16+16]
+    paddd           m1, [t3+wq*4+400*20+ 0]
+    paddd           m7, [t3+wq*4+400*20+16]
+    mova [t3+wq*4+400*16+ 0], m4
+    mova [t3+wq*4+400*16+16], m8
+    mova [t3+wq*4+400*20+ 0], m5
+%if ARCH_X86_32
+    mova            m8, [esp+52]
+%else
+    SWAP            m8, m6
+    pxor            m6, m6
+%endif
+    mova [t3+wq*4+400*20+16], m8
+    mova [rsp+32+ARCH_X86_32*4], m7
+    movq            m4, [dstq+wq]
+    punpcklbw       m4, m6
+    punpcklwd       m5, m4, m6
+    punpcklwd       m7, m2, m6
+    pmaddwd         m7, m5               ; a5 * src
+    punpcklwd       m8, m3, m6
+    pmaddwd         m8, m5               ; a3 * src
+    punpckhwd       m5, m4, m6
+    punpckhwd       m2, m6
+    pmaddwd         m2, m5
+    punpckhwd       m3, m6
+    pmaddwd         m3, m5
+    psubd           m0, m7               ; b5 - a5 * src + (1 << 8) - (src << 13)
+    psubd           m1, m8               ; b3 - a3 * src + (1 << 8) - (src << 13)
+    psrld           m0, 9
+    pslld           m1, 7
+    pand            m0, m9
+    pandn           m8, m9, m1
+    por             m0, m8
+    mova            m1, [rsp+16+ARCH_X86_32*4]
+    psubd           m1, m2
+    mova            m2, [rsp+32+ARCH_X86_32*4]
+    psubd           m2, m3
+    mova            m3, [base+pd_4096]
+    psrld           m1, 9
+    pslld           m2, 7
+    pand            m1, m9
+    pandn           m5, m9, m2
+    por             m1, m5
+    pmaddwd         m0, m15
+    pmaddwd         m1, m15
+    paddd           m0, m3
+    paddd           m1, m3
+    psrad           m0, 13
+    psrad           m1, 13
+    packssdw        m0, m1
+    paddw           m0, m4
+    packuswb        m0, m0
+    movq     [dstq+wq], m0
+    add             wq, 8
+    jl .n0_loop
+    add           dstq, stridemp
+    ret
+ALIGN function_align
+.n1: ; neighbor + output (odd rows)
+    movif64         wq, r4
+    movif32         wd, w1m
+.n1_loop:
+    movu            m3, [t4+wq*2+400*4+4]
+    movu            m5, [t4+wq*2+400*4+2]
+    paddw           m3, [t4+wq*2+400*4+0]
+    paddw           m5, m3
+    psllw           m5, 2                ; a3[ 1] 444
+    psubw           m4, m5, m3           ; a3[ 1] 343
+    paddw           m3, m4, [t4+wq*2+400*12]
+    paddw           m3, [t4+wq*2+400*10]
+    mova [t4+wq*2+400*10], m5
+    mova [t4+wq*2+400*12], m4
+    movu            m1, [t3+wq*4+400*8+ 8]
+    movu            m5, [t3+wq*4+400*8+ 4]
+    movu            m7, [t3+wq*4+400*8+24]
+    movu            m8, [t3+wq*4+400*8+20]
+    paddd           m1, [t3+wq*4+400*8+ 0]
+    paddd           m7, [t3+wq*4+400*8+16]
+    paddd           m5, m1
+    paddd           m8, m7
+    pslld           m5, 2                ; b3[ 1] 444
+    pslld           m8, 2
+    psubd           m4, m5, m1           ; b3[ 1] 343
+    psubd           m0, m8, m7
+    paddd           m1, m4, [t3+wq*4+400*24+ 0]
+    paddd           m7, m0, [t3+wq*4+400*24+16]
+    paddd           m1, [t3+wq*4+400*20+ 0]
+    paddd           m7, [t3+wq*4+400*20+16]
+    mova [t3+wq*4+400*20+ 0], m5
+    mova [t3+wq*4+400*20+16], m8
+    mova [t3+wq*4+400*24+ 0], m4
+    mova [t3+wq*4+400*24+16], m0
+    movq            m5, [dstq+wq]
+    mova            m2, [t4+wq*2+400* 6]
+    punpcklbw       m5, m6
+    punpcklwd       m4, m5, m6
+    punpcklwd       m8, m2, m6
+    pmaddwd         m8, m4               ; a5 * src
+    punpcklwd       m0, m3, m6
+    pmaddwd         m0, m4               ; a3 * src
+    punpckhwd       m4, m5, m6
+    punpckhwd       m2, m6
+    pmaddwd         m2, m4
+    punpckhwd       m3, m6
+    pmaddwd         m3, m4
+    psubd           m1, m0               ; b3 - a3 * src + (1 << 8) - (src << 13)
+    mova            m0, [t3+wq*4+400*12+ 0]
+    psubd           m0, m8               ; b5 - a5 * src + (1 << 8) - (src << 13)
+    mova            m4, [t3+wq*4+400*12+16]
+    psubd           m4, m2
+    psubd           m7, m3
+    pslld           m1, 7
+    psrld           m0, 8
+    psrld           m4, 8
+    pslld           m7, 7
+    pandn           m3, m9, m1
+    pand            m0, m9
+    por             m0, m3
+    pand            m4, m9
+    pandn           m2, m9, m7
+    por             m2, m4
+    mova            m1, [base+pd_4096]
+    pmaddwd         m0, m15
+    pmaddwd         m2, m15
+    paddd           m0, m1
+    paddd           m2, m1
+    psrad           m0, 13
+    psrad           m2, 13
+    packssdw        m0, m2
+    paddw           m0, m5
+    packuswb        m0, m0
+    movq     [dstq+wq], m0
+    add             wq, 8
+    jl .n1_loop
+    add           dstq, stridemp
+    movif32       dstm, dstq
+    ret
diff --git a/media/libdav1d/src/src/x86/mc.h b/media/libdav1d/src/src/x86/mc.h
new file mode 100644
index 0000000000..45a8a2d8e9
--- /dev/null
+++ b/media/libdav1d/src/src/x86/mc.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018-2021, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/mc.h"
+
+#define decl_fn(type, name) \
+    decl_##type##_fn(BF(name, ssse3)); \
+    decl_##type##_fn(BF(name, avx2)); \
+    decl_##type##_fn(BF(name, avx512icl));
+#define init_mc_fn(type, name, suffix) \
+    c->mc[type] = BF(dav1d_put_##name, suffix)
+#define init_mct_fn(type, name, suffix) \
+    c->mct[type] = BF(dav1d_prep_##name, suffix)
+#define init_mc_scaled_fn(type, name, suffix) \
+    c->mc_scaled[type] = BF(dav1d_put_##name, suffix)
+#define init_mct_scaled_fn(type, name, suffix) \
+    c->mct_scaled[type] = BF(dav1d_prep_##name, suffix)
+
+decl_8tap_fns(ssse3);
+decl_8tap_fns(avx2);
+decl_8tap_fns(avx512icl);
+
+decl_fn(mc, dav1d_put_bilin);
+decl_fn(mct, dav1d_prep_bilin);
+
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_regular);
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_regular_smooth);
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_regular_sharp);
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_smooth);
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_smooth_regular);
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_smooth_sharp);
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_sharp);
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_sharp_regular);
+decl_fn(mc_scaled, dav1d_put_8tap_scaled_sharp_smooth);
+decl_fn(mc_scaled, dav1d_put_bilin_scaled);
+
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_regular);
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_regular_smooth);
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_regular_sharp);
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_smooth);
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_smooth_regular);
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_smooth_sharp);
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_sharp);
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_sharp_regular);
+decl_fn(mct_scaled, dav1d_prep_8tap_scaled_sharp_smooth);
+decl_fn(mct_scaled, dav1d_prep_bilin_scaled);
+
+decl_fn(avg, dav1d_avg);
+decl_fn(w_avg, dav1d_w_avg);
+decl_fn(mask, dav1d_mask);
+decl_fn(w_mask, dav1d_w_mask_420);
+decl_fn(w_mask, dav1d_w_mask_422);
+decl_fn(w_mask, dav1d_w_mask_444);
+decl_fn(blend, dav1d_blend);
+decl_fn(blend_dir, dav1d_blend_v);
+decl_fn(blend_dir, dav1d_blend_h);
+
+decl_fn(warp8x8, dav1d_warp_affine_8x8);
+decl_warp8x8_fn(BF(dav1d_warp_affine_8x8, sse4));
+decl_fn(warp8x8t, dav1d_warp_affine_8x8t);
+decl_warp8x8t_fn(BF(dav1d_warp_affine_8x8t, sse4));
+
+decl_fn(emu_edge, dav1d_emu_edge);
+
+decl_fn(resize, dav1d_resize);
+
+static ALWAYS_INLINE void mc_dsp_init_x86(Dav1dMCDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if(!(flags & DAV1D_X86_CPU_FLAG_SSSE3))
+        return;
+
+    init_8tap_fns(ssse3);
+
+    init_mc_fn(FILTER_2D_BILINEAR,             bilin,               ssse3);
+    init_mct_fn(FILTER_2D_BILINEAR,            bilin,               ssse3);
+
+    init_mc_scaled_fn(FILTER_2D_8TAP_REGULAR,        8tap_scaled_regular,        ssse3);
+    init_mc_scaled_fn(FILTER_2D_8TAP_REGULAR_SMOOTH, 8tap_scaled_regular_smooth, ssse3);
+    init_mc_scaled_fn(FILTER_2D_8TAP_REGULAR_SHARP,  8tap_scaled_regular_sharp,  ssse3);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SMOOTH_REGULAR, 8tap_scaled_smooth_regular, ssse3);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SMOOTH,         8tap_scaled_smooth,         ssse3);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SMOOTH_SHARP,   8tap_scaled_smooth_sharp,   ssse3);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SHARP_REGULAR,  8tap_scaled_sharp_regular,  ssse3);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SHARP_SMOOTH,   8tap_scaled_sharp_smooth,   ssse3);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SHARP,          8tap_scaled_sharp,          ssse3);
+    init_mc_scaled_fn(FILTER_2D_BILINEAR,            bilin_scaled,               ssse3);
+
+    init_mct_scaled_fn(FILTER_2D_8TAP_REGULAR,        8tap_scaled_regular,        ssse3);
+    init_mct_scaled_fn(FILTER_2D_8TAP_REGULAR_SMOOTH, 8tap_scaled_regular_smooth, ssse3);
+    init_mct_scaled_fn(FILTER_2D_8TAP_REGULAR_SHARP,  8tap_scaled_regular_sharp,  ssse3);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SMOOTH_REGULAR, 8tap_scaled_smooth_regular, ssse3);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SMOOTH,         8tap_scaled_smooth,         ssse3);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SMOOTH_SHARP,   8tap_scaled_smooth_sharp,   ssse3);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SHARP_REGULAR,  8tap_scaled_sharp_regular,  ssse3);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SHARP_SMOOTH,   8tap_scaled_sharp_smooth,   ssse3);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SHARP,          8tap_scaled_sharp,          ssse3);
+    init_mct_scaled_fn(FILTER_2D_BILINEAR,            bilin_scaled,               ssse3);
+
+    c->avg = BF(dav1d_avg, ssse3);
+    c->w_avg = BF(dav1d_w_avg, ssse3);
+    c->mask = BF(dav1d_mask, ssse3);
+    c->w_mask[0] = BF(dav1d_w_mask_444, ssse3);
+    c->w_mask[1] = BF(dav1d_w_mask_422, ssse3);
+    c->w_mask[2] = BF(dav1d_w_mask_420, ssse3);
+    c->blend = BF(dav1d_blend, ssse3);
+    c->blend_v = BF(dav1d_blend_v, ssse3);
+    c->blend_h = BF(dav1d_blend_h, ssse3);
+    c->warp8x8  = BF(dav1d_warp_affine_8x8, ssse3);
+    c->warp8x8t = BF(dav1d_warp_affine_8x8t, ssse3);
+    c->emu_edge = BF(dav1d_emu_edge, ssse3);
+    c->resize = BF(dav1d_resize, ssse3);
+
+    if(!(flags & DAV1D_X86_CPU_FLAG_SSE41))
+        return;
+
+#if BITDEPTH == 8
+    c->warp8x8  = BF(dav1d_warp_affine_8x8, sse4);
+    c->warp8x8t = BF(dav1d_warp_affine_8x8t, sse4);
+#endif
+
+#if ARCH_X86_64
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2))
+        return;
+
+    init_8tap_fns(avx2);
+
+    init_mc_fn(FILTER_2D_BILINEAR,            bilin,               avx2);
+    init_mct_fn(FILTER_2D_BILINEAR,           bilin,               avx2);
+
+    init_mc_scaled_fn(FILTER_2D_8TAP_REGULAR,        8tap_scaled_regular,        avx2);
+    init_mc_scaled_fn(FILTER_2D_8TAP_REGULAR_SMOOTH, 8tap_scaled_regular_smooth, avx2);
+    init_mc_scaled_fn(FILTER_2D_8TAP_REGULAR_SHARP,  8tap_scaled_regular_sharp,  avx2);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SMOOTH_REGULAR, 8tap_scaled_smooth_regular, avx2);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SMOOTH,         8tap_scaled_smooth,         avx2);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SMOOTH_SHARP,   8tap_scaled_smooth_sharp,   avx2);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SHARP_REGULAR,  8tap_scaled_sharp_regular,  avx2);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SHARP_SMOOTH,   8tap_scaled_sharp_smooth,   avx2);
+    init_mc_scaled_fn(FILTER_2D_8TAP_SHARP,          8tap_scaled_sharp,          avx2);
+    init_mc_scaled_fn(FILTER_2D_BILINEAR,            bilin_scaled,               avx2);
+
+    init_mct_scaled_fn(FILTER_2D_8TAP_REGULAR,        8tap_scaled_regular,        avx2);
+    init_mct_scaled_fn(FILTER_2D_8TAP_REGULAR_SMOOTH, 8tap_scaled_regular_smooth, avx2);
+    init_mct_scaled_fn(FILTER_2D_8TAP_REGULAR_SHARP,  8tap_scaled_regular_sharp,  avx2);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SMOOTH_REGULAR, 8tap_scaled_smooth_regular, avx2);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SMOOTH,         8tap_scaled_smooth,         avx2);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SMOOTH_SHARP,   8tap_scaled_smooth_sharp,   avx2);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SHARP_REGULAR,  8tap_scaled_sharp_regular,  avx2);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SHARP_SMOOTH,   8tap_scaled_sharp_smooth,   avx2);
+    init_mct_scaled_fn(FILTER_2D_8TAP_SHARP,          8tap_scaled_sharp,          avx2);
+    init_mct_scaled_fn(FILTER_2D_BILINEAR,            bilin_scaled,               avx2);
+
+    c->avg = BF(dav1d_avg, avx2);
+    c->w_avg = BF(dav1d_w_avg, avx2);
+    c->mask = BF(dav1d_mask, avx2);
+    c->w_mask[0] = BF(dav1d_w_mask_444, avx2);
+    c->w_mask[1] = BF(dav1d_w_mask_422, avx2);
+    c->w_mask[2] = BF(dav1d_w_mask_420, avx2);
+    c->blend = BF(dav1d_blend, avx2);
+    c->blend_v = BF(dav1d_blend_v, avx2);
+    c->blend_h = BF(dav1d_blend_h, avx2);
+    c->warp8x8  = BF(dav1d_warp_affine_8x8, avx2);
+    c->warp8x8t = BF(dav1d_warp_affine_8x8t, avx2);
+    c->emu_edge = BF(dav1d_emu_edge, avx2);
+    c->resize = BF(dav1d_resize, avx2);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL))
+        return;
+
+    init_8tap_fns(avx512icl);
+
+    init_mc_fn (FILTER_2D_BILINEAR,            bilin,               avx512icl);
+    init_mct_fn(FILTER_2D_BILINEAR,            bilin,               avx512icl);
+
+    c->avg = BF(dav1d_avg, avx512icl);
+    c->w_avg = BF(dav1d_w_avg, avx512icl);
+    c->mask = BF(dav1d_mask, avx512icl);
+    c->w_mask[0] = BF(dav1d_w_mask_444, avx512icl);
+    c->w_mask[1] = BF(dav1d_w_mask_422, avx512icl);
+    c->w_mask[2] = BF(dav1d_w_mask_420, avx512icl);
+    c->blend = BF(dav1d_blend, avx512icl);
+    c->blend_v = BF(dav1d_blend_v, avx512icl);
+    c->blend_h = BF(dav1d_blend_h, avx512icl);
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SLOW_GATHER)) {
+        c->resize = BF(dav1d_resize, avx512icl);
+        c->warp8x8  = BF(dav1d_warp_affine_8x8, avx512icl);
+        c->warp8x8t = BF(dav1d_warp_affine_8x8t, avx512icl);
+    }
+#endif
+}
diff --git a/media/libdav1d/src/src/x86/mc16_avx2.asm b/media/libdav1d/src/src/x86/mc16_avx2.asm
new file mode 100644
index 0000000000..6b4424946b
--- /dev/null
+++ b/media/libdav1d/src/src/x86/mc16_avx2.asm
@@ -0,0 +1,6793 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+; dav1d_obmc_masks[] * -512
+const obmc_masks_avx2
+            dw      0,      0,  -9728,      0, -12800,  -7168,  -2560,      0
+            dw -14336, -11264,  -8192,  -5632,  -3584,  -1536,      0,      0
+            dw -15360, -13824, -12288, -10752,  -9216,  -7680,  -6144,  -5120
+            dw  -4096,  -3072,  -2048,  -1536,      0,      0,      0,      0
+            dw -15872, -14848, -14336, -13312, -12288, -11776, -10752, -10240
+            dw  -9728,  -8704,  -8192,  -7168,  -6656,  -6144,  -5632,  -4608
+            dw  -4096,  -3584,  -3072,  -2560,  -2048,  -2048,  -1536,  -1024
+            dw      0,      0,      0,      0,      0,      0,      0,      0
+
+deint_shuf:     dd 0,  4,  1,  5,  2,  6,  3,  7
+subpel_h_shufA: db 0,  1,  2,  3,  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9
+subpel_h_shufB: db 4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13
+subpel_h_shuf2: db 0,  1,  2,  3,  4,  5,  6,  7,  2,  3,  4,  5,  6,  7,  8,  9
+subpel_s_shuf2: db 0,  1,  2,  3,  4,  5,  6,  7,  0,  1,  2,  3,  4,  5,  6,  7
+subpel_s_shuf8: db 0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+rescale_mul:    dd 0,  1,  2,  3,  4,  5,  6,  7
+rescale_mul2:   dd 0,  1,  4,  5,  2,  3,  6,  7
+resize_shuf:    db 0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7
+                db 8,  9, 10, 11, 12, 13, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15
+blend_shuf:     db 0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  2,  3,  2,  3,  2,  3
+wswap:          db 2,  3,  0,  1,  6,  7,  4,  5, 10, 11,  8,  9, 14, 15, 12, 13
+bdct_lb_q: times 8 db 0
+           times 8 db 4
+           times 8 db 8
+           times 8 db 12
+
+prep_mul:         dw 16, 16, 4, 4
+put_bilin_h_rnd:  dw 8, 8, 10, 10
+put_8tap_h_rnd:   dd 34, 40
+s_8tap_h_rnd:     dd 2, 8
+s_8tap_h_sh:      dd 2, 4
+put_s_8tap_v_rnd: dd 512, 128
+put_s_8tap_v_sh:  dd 10, 8
+prep_8tap_1d_rnd: dd     8 - (8192 <<  4)
+prep_8tap_2d_rnd: dd    32 - (8192 <<  5)
+warp8x8t_rnd:     dd 16384 - (8192 << 15)
+warp8x8_shift:    dd  5,  3
+warp8x8_rnd:      dw   4096,   4096,  16384,  16384
+bidir_rnd:        dw -16400, -16400, -16388, -16388
+bidir_mul:        dw   2048,   2048,   8192,   8192
+
+%define pw_16 prep_mul
+%define pd_512 put_s_8tap_v_rnd
+
+pw_2:          times 2 dw 2
+pw_64:         times 2 dw 64
+pw_2048:       times 2 dw 2048
+pw_8192:       times 2 dw 8192
+pw_27615:      times 2 dw 27615
+pw_32766:      times 2 dw 32766
+pw_m512:       times 2 dw -512
+pd_32:         dd 32
+pd_63:         dd 63
+pd_64:         dd 64
+pd_32768:      dd 32768
+pd_65538:      dd 65538
+pd_m524256:    dd -524256 ; -8192 << 6 + 32
+pd_0x3ff:      dd 0x3ff
+pq_0x40000000: dq 0x40000000
+               dd 0
+
+%macro BIDIR_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - 2*%3)
+    %xdefine %%base %1_%2_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1_16bpc_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%prefix %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+BIDIR_JMP_TABLE avg,        avx2,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_avg,      avx2,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE mask,       avx2,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_420, avx2,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_422, avx2,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_444, avx2,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE blend,      avx2,    4, 8, 16, 32
+BIDIR_JMP_TABLE blend_v,    avx2, 2, 4, 8, 16, 32
+BIDIR_JMP_TABLE blend_h,    avx2, 2, 4, 8, 16, 32, 64, 128
+
+%macro BASE_JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base %1_%2
+    %%table:
+    %rep %0 - 2
+        dw %%base %+ _w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%xdefine put_avx2 mangle(private_prefix %+ _put_bilin_16bpc_avx2.put)
+%xdefine prep_avx2 mangle(private_prefix %+ _prep_bilin_16bpc_avx2.prep)
+
+BASE_JMP_TABLE put,  avx2, 2, 4, 8, 16, 32, 64, 128
+BASE_JMP_TABLE prep, avx2,    4, 8, 16, 32, 64, 128
+
+%macro HV_JMP_TABLE 5-*
+    %xdefine %%prefix mangle(private_prefix %+ _%1_%2_16bpc_%3)
+    %xdefine %%base %1_%3
+    %assign %%types %4
+    %if %%types & 1
+        %xdefine %1_%2_h_%3_table  (%%h  - %5)
+        %%h:
+        %rep %0 - 4
+            dw %%prefix %+ .h_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 2
+        %xdefine %1_%2_v_%3_table  (%%v  - %5)
+        %%v:
+        %rep %0 - 4
+            dw %%prefix %+ .v_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 4
+        %xdefine %1_%2_hv_%3_table (%%hv - %5)
+        %%hv:
+        %rep %0 - 4
+            dw %%prefix %+ .hv_w%5 - %%base
+            %rotate 1
+        %endrep
+    %endif
+%endmacro
+
+HV_JMP_TABLE put,  bilin, avx2, 7, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE prep, bilin, avx2, 7,    4, 8, 16, 32, 64, 128
+
+%macro SCALED_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base mangle(private_prefix %+ _%1_16bpc_%2)
+%%table:
+    %rep %0 - 2
+        dw %%base %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+    %rotate 2
+ %%dy_1024:
+    %xdefine %1_%2_dy1_table (%%dy_1024 - %3)
+    %rep %0 - 2
+        dw %%base %+ .dy1_w%3 - %%base
+        %rotate 1
+    %endrep
+    %rotate 2
+ %%dy_2048:
+    %xdefine %1_%2_dy2_table (%%dy_2048 - %3)
+    %rep %0 - 2
+        dw %%base %+ .dy2_w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+SCALED_JMP_TABLE put_8tap_scaled, avx2, 2, 4, 8, 16, 32, 64, 128
+SCALED_JMP_TABLE prep_8tap_scaled, avx2,   4, 8, 16, 32, 64, 128
+
+%define table_offset(type, fn) type %+ fn %+ SUFFIX %+ _table - type %+ SUFFIX
+
+cextern mc_subpel_filters
+%define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8)
+
+cextern mc_warp_filter
+cextern resize_filter
+
+SECTION .text
+
+INIT_XMM avx2
+cglobal put_bilin_16bpc, 4, 8, 0, dst, ds, src, ss, w, h, mxy
+    mov                mxyd, r6m ; mx
+    lea                  r7, [put_avx2]
+%if UNIX64
+    DECLARE_REG_TMP 8
+    %define org_w r8d
+    mov                 r8d, wd
+%else
+    DECLARE_REG_TMP 7
+    %define org_w wm
+%endif
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r7m ; my
+    test               mxyd, mxyd
+    jnz .v
+.put:
+    movzx                wd, word [r7+wq*2+table_offset(put,)]
+    add                  wq, r7
+    jmp                  wq
+.put_w2:
+    mov                 r6d, [srcq+ssq*0]
+    mov                 r7d, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6d
+    mov        [dstq+dsq*1], r7d
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w2
+    RET
+.put_w4:
+    mov                  r6, [srcq+ssq*0]
+    mov                  r7, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6
+    mov        [dstq+dsq*1], r7
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w4
+    RET
+.put_w8:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w8
+    RET
+INIT_YMM avx2
+.put_w16:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w16
+    RET
+.put_w32:
+    movu                 m0, [srcq+ssq*0+32*0]
+    movu                 m1, [srcq+ssq*0+32*1]
+    movu                 m2, [srcq+ssq*1+32*0]
+    movu                 m3, [srcq+ssq*1+32*1]
+    lea                srcq, [srcq+ssq*2]
+    mova  [dstq+dsq*0+32*0], m0
+    mova  [dstq+dsq*0+32*1], m1
+    mova  [dstq+dsq*1+32*0], m2
+    mova  [dstq+dsq*1+32*1], m3
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w32
+    RET
+.put_w64:
+    movu                 m0, [srcq+32*0]
+    movu                 m1, [srcq+32*1]
+    movu                 m2, [srcq+32*2]
+    movu                 m3, [srcq+32*3]
+    add                srcq, ssq
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    mova        [dstq+32*2], m2
+    mova        [dstq+32*3], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w64
+    RET
+.put_w128:
+    movu                 m0, [srcq+32*0]
+    movu                 m1, [srcq+32*1]
+    movu                 m2, [srcq+32*2]
+    movu                 m3, [srcq+32*3]
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    mova        [dstq+32*2], m2
+    mova        [dstq+32*3], m3
+    movu                 m0, [srcq+32*4]
+    movu                 m1, [srcq+32*5]
+    movu                 m2, [srcq+32*6]
+    movu                 m3, [srcq+32*7]
+    add                srcq, ssq
+    mova        [dstq+32*4], m0
+    mova        [dstq+32*5], m1
+    mova        [dstq+32*6], m2
+    mova        [dstq+32*7], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w128
+    RET
+.h:
+    movd                xm5, mxyd
+    mov                mxyd, r7m ; my
+    vpbroadcastd         m4, [pw_16]
+    vpbroadcastw         m5, xm5
+    psubw                m4, m5
+    test               mxyd, mxyd
+    jnz .hv
+    ; 12-bit is rounded twice so we can't use the same pmulhrsw approach as .v
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_h)]
+    mov                 r6d, r8m ; bitdepth_max
+    add                  wq, r7
+    shr                 r6d, 11
+    vpbroadcastd         m3, [r7-put_avx2+put_bilin_h_rnd+r6*4]
+    jmp                  wq
+.h_w2:
+    movq                xm1, [srcq+ssq*0]
+    movhps              xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmullw              xm0, xm4, xm1
+    psrlq               xm1, 16
+    pmullw              xm1, xm5
+    paddw               xm0, xm3
+    paddw               xm0, xm1
+    psrlw               xm0, 4
+    movd       [dstq+dsq*0], xm0
+    pextrd     [dstq+dsq*1], xm0, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2
+    RET
+.h_w4:
+    movq                xm0, [srcq+ssq*0]
+    movhps              xm0, [srcq+ssq*1]
+    movq                xm1, [srcq+ssq*0+2]
+    movhps              xm1, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    pmullw              xm0, xm4
+    pmullw              xm1, xm5
+    paddw               xm0, xm3
+    paddw               xm0, xm1
+    psrlw               xm0, 4
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4
+    RET
+.h_w8:
+    movu                xm0, [srcq+ssq*0]
+    vinserti128          m0, [srcq+ssq*1], 1
+    movu                xm1, [srcq+ssq*0+2]
+    vinserti128          m1, [srcq+ssq*1+2], 1
+    lea                srcq, [srcq+ssq*2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    paddw                m0, m3
+    paddw                m0, m1
+    psrlw                m0, 4
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    pmullw               m0, m4, [srcq+ssq*0]
+    pmullw               m1, m5, [srcq+ssq*0+2]
+    paddw                m0, m3
+    paddw                m0, m1
+    pmullw               m1, m4, [srcq+ssq*1]
+    pmullw               m2, m5, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m0, 4
+    psrlw                m1, 4
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+    pmullw               m0, m4, [srcq+32*0]
+    pmullw               m1, m5, [srcq+32*0+2]
+    paddw                m0, m3
+    paddw                m0, m1
+    pmullw               m1, m4, [srcq+32*1]
+    pmullw               m2, m5, [srcq+32*1+2]
+    add                srcq, ssq
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m0, 4
+    psrlw                m1, 4
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w32
+    RET
+.h_w64:
+.h_w128:
+    movifnidn           t0d, org_w
+.h_w64_loop0:
+    mov                 r6d, t0d
+.h_w64_loop:
+    pmullw               m0, m4, [srcq+r6*2-32*1]
+    pmullw               m1, m5, [srcq+r6*2-32*1+2]
+    paddw                m0, m3
+    paddw                m0, m1
+    pmullw               m1, m4, [srcq+r6*2-32*2]
+    pmullw               m2, m5, [srcq+r6*2-32*2+2]
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m0, 4
+    psrlw                m1, 4
+    mova   [dstq+r6*2-32*1], m0
+    mova   [dstq+r6*2-32*2], m1
+    sub                 r6d, 32
+    jg .h_w64_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w64_loop0
+    RET
+.v:
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_v)]
+    shl                mxyd, 11
+    movd                xm5, mxyd
+    add                  wq, r7
+    vpbroadcastw         m5, xm5
+    jmp                  wq
+.v_w2:
+    movd                xm0, [srcq+ssq*0]
+.v_w2_loop:
+    movd                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpckldq           xm2, xm0, xm1
+    movd                xm0, [srcq+ssq*0]
+    punpckldq           xm1, xm0
+    psubw               xm1, xm2
+    pmulhrsw            xm1, xm5
+    paddw               xm1, xm2
+    movd       [dstq+dsq*0], xm1
+    pextrd     [dstq+dsq*1], xm1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movq                xm0, [srcq+ssq*0]
+.v_w4_loop:
+    movq                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklqdq          xm2, xm0, xm1
+    movq                xm0, [srcq+ssq*0]
+    punpcklqdq          xm1, xm0
+    psubw               xm1, xm2
+    pmulhrsw            xm1, xm5
+    paddw               xm1, xm2
+    movq       [dstq+dsq*0], xm1
+    movhps     [dstq+dsq*1], xm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movu                xm0, [srcq+ssq*0]
+.v_w8_loop:
+    vbroadcasti128       m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd             m2, m0, m1, 0xf0
+    vbroadcasti128       m0, [srcq+ssq*0]
+    vpblendd             m1, m0, 0xf0
+    psubw                m1, m2
+    pmulhrsw             m1, m5
+    paddw                m1, m2
+    mova         [dstq+dsq*0], xm1
+    vextracti128 [dstq+dsq*1], m1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w32:
+    movu                 m0, [srcq+ssq*0+32*0]
+    movu                 m1, [srcq+ssq*0+32*1]
+.v_w32_loop:
+    movu                 m2, [srcq+ssq*1+32*0]
+    movu                 m3, [srcq+ssq*1+32*1]
+    lea                srcq, [srcq+ssq*2]
+    psubw                m4, m2, m0
+    pmulhrsw             m4, m5
+    paddw                m4, m0
+    movu                 m0, [srcq+ssq*0+32*0]
+    mova  [dstq+dsq*0+32*0], m4
+    psubw                m4, m3, m1
+    pmulhrsw             m4, m5
+    paddw                m4, m1
+    movu                 m1, [srcq+ssq*0+32*1]
+    mova  [dstq+dsq*0+32*1], m4
+    psubw                m4, m0, m2
+    pmulhrsw             m4, m5
+    paddw                m4, m2
+    mova  [dstq+dsq*1+32*0], m4
+    psubw                m4, m1, m3
+    pmulhrsw             m4, m5
+    paddw                m4, m3
+    mova  [dstq+dsq*1+32*1], m4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w32_loop
+    RET
+.v_w16:
+.v_w64:
+.v_w128:
+    movifnidn           t0d, org_w
+    add                 t0d, t0d
+    mov                  r4, srcq
+    lea                 r6d, [hq+t0*8-256]
+    mov                  r7, dstq
+.v_w16_loop0:
+    movu                 m0, [srcq+ssq*0]
+.v_w16_loop:
+    movu                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    psubw                m1, m3, m0
+    pmulhrsw             m1, m5
+    paddw                m1, m0
+    movu                 m0, [srcq+ssq*0]
+    psubw                m2, m0, m3
+    pmulhrsw             m2, m5
+    paddw                m2, m3
+    mova       [dstq+dsq*0], m1
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    add                  r4, 32
+    add                  r7, 32
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+    sub                 r6d, 1<<8
+    jg .v_w16_loop0
+    RET
+.hv:
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_hv)]
+    WIN64_SPILL_XMM       8
+    shl                mxyd, 11
+    vpbroadcastd         m3, [pw_2]
+    movd                xm6, mxyd
+    vpbroadcastd         m7, [pw_8192]
+    add                  wq, r7
+    vpbroadcastw         m6, xm6
+    test          dword r8m, 0x800
+    jnz .hv_12bpc
+    psllw                m4, 2
+    psllw                m5, 2
+    vpbroadcastd         m7, [pw_2048]
+.hv_12bpc:
+    jmp                  wq
+.hv_w2:
+    vpbroadcastq        xm1, [srcq+ssq*0]
+    pmullw              xm0, xm4, xm1
+    psrlq               xm1, 16
+    pmullw              xm1, xm5
+    paddw               xm0, xm3
+    paddw               xm0, xm1
+    psrlw               xm0, 2
+.hv_w2_loop:
+    movq                xm2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps              xm2, [srcq+ssq*0]
+    pmullw              xm1, xm4, xm2
+    psrlq               xm2, 16
+    pmullw              xm2, xm5
+    paddw               xm1, xm3
+    paddw               xm1, xm2
+    psrlw               xm1, 2              ; 1 _ 2 _
+    shufpd              xm2, xm0, xm1, 0x01 ; 0 _ 1 _
+    mova                xm0, xm1
+    psubw               xm1, xm2
+    paddw               xm1, xm1
+    pmulhw              xm1, xm6
+    paddw               xm1, xm2
+    pmulhrsw            xm1, xm7
+    movd       [dstq+dsq*0], xm1
+    pextrd     [dstq+dsq*1], xm1, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    pmullw              xm0, xm4, [srcq+ssq*0-8]
+    pmullw              xm1, xm5, [srcq+ssq*0-6]
+    paddw               xm0, xm3
+    paddw               xm0, xm1
+    psrlw               xm0, 2
+.hv_w4_loop:
+    movq                xm1, [srcq+ssq*1]
+    movq                xm2, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    movhps              xm1, [srcq+ssq*0]
+    movhps              xm2, [srcq+ssq*0+2]
+    pmullw              xm1, xm4
+    pmullw              xm2, xm5
+    paddw               xm1, xm3
+    paddw               xm1, xm2
+    psrlw               xm1, 2              ; 1 2
+    shufpd              xm2, xm0, xm1, 0x01 ; 0 1
+    mova                xm0, xm1
+    psubw               xm1, xm2
+    paddw               xm1, xm1
+    pmulhw              xm1, xm6
+    paddw               xm1, xm2
+    pmulhrsw            xm1, xm7
+    movq       [dstq+dsq*0], xm1
+    movhps     [dstq+dsq*1], xm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    pmullw              xm0, xm4, [srcq+ssq*0]
+    pmullw              xm1, xm5, [srcq+ssq*0+2]
+    paddw               xm0, xm3
+    paddw               xm0, xm1
+    psrlw               xm0, 2
+    vinserti128          m0, xm0, 1
+.hv_w8_loop:
+    movu                xm1, [srcq+ssq*1]
+    movu                xm2, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    vinserti128          m1, [srcq+ssq*0], 1
+    vinserti128          m2, [srcq+ssq*0+2], 1
+    pmullw               m1, m4
+    pmullw               m2, m5
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m1, 2            ; 1 2
+    vperm2i128           m2, m0, m1, 0x21 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    paddw                m1, m1
+    pmulhw               m1, m6
+    paddw                m1, m2
+    pmulhrsw             m1, m7
+    mova         [dstq+dsq*0], xm1
+    vextracti128 [dstq+dsq*1], m1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+.hv_w32:
+.hv_w64:
+.hv_w128:
+%if UNIX64
+    lea                 r6d, [r8*2-32]
+%else
+    mov                 r6d, wm
+    lea                 r6d, [r6*2-32]
+%endif
+    mov                  r4, srcq
+    lea                 r6d, [hq+r6*8]
+    mov                  r7, dstq
+.hv_w16_loop0:
+    pmullw               m0, m4, [srcq+ssq*0]
+    pmullw               m1, m5, [srcq+ssq*0+2]
+    paddw                m0, m3
+    paddw                m0, m1
+    psrlw                m0, 2
+.hv_w16_loop:
+    pmullw               m1, m4, [srcq+ssq*1]
+    pmullw               m2, m5, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m1, 2
+    psubw                m2, m1, m0
+    paddw                m2, m2
+    pmulhw               m2, m6
+    paddw                m2, m0
+    pmulhrsw             m2, m7
+    mova       [dstq+dsq*0], m2
+    pmullw               m0, m4, [srcq+ssq*0]
+    pmullw               m2, m5, [srcq+ssq*0+2]
+    paddw                m0, m3
+    paddw                m0, m2
+    psrlw                m0, 2
+    psubw                m2, m0, m1
+    paddw                m2, m2
+    pmulhw               m2, m6
+    paddw                m2, m1
+    pmulhrsw             m2, m7
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    add                  r4, 32
+    add                  r7, 32
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+    sub                 r6d, 1<<8
+    jg .hv_w16_loop0
+    RET
+
+cglobal prep_bilin_16bpc, 3, 7, 0, tmp, src, stride, w, h, mxy, stride3
+    movifnidn          mxyd, r5m ; mx
+    lea                  r6, [prep_avx2]
+%if UNIX64
+    DECLARE_REG_TMP 7
+    %define org_w r7d
+%else
+    DECLARE_REG_TMP 6
+    %define org_w r5m
+%endif
+    mov               org_w, wd
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r6m ; my
+    test               mxyd, mxyd
+    jnz .v
+.prep:
+    movzx                wd, word [r6+wq*2+table_offset(prep,)]
+    mov                 r5d, r7m ; bitdepth_max
+    vpbroadcastd         m5, [r6-prep_avx2+pw_8192]
+    add                  wq, r6
+    shr                 r5d, 11
+    vpbroadcastd         m4, [r6-prep_avx2+prep_mul+r5*4]
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.prep_w4:
+    movq                xm0, [srcq+strideq*0]
+    movhps              xm0, [srcq+strideq*1]
+    vpbroadcastq         m1, [srcq+strideq*2]
+    vpbroadcastq         m2, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpblendd             m0, m1, 0x30
+    vpblendd             m0, m2, 0xc0
+    pmullw               m0, m4
+    psubw                m0, m5
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .prep_w4
+    RET
+.prep_w8:
+    movu                xm0, [srcq+strideq*0]
+    vinserti128          m0, [srcq+strideq*1], 1
+    movu                xm1, [srcq+strideq*2]
+    vinserti128          m1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    pmullw               m0, m4
+    pmullw               m1, m4
+    psubw                m0, m5
+    psubw                m1, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    add                tmpq, 32*2
+    sub                  hd, 4
+    jg .prep_w8
+    RET
+.prep_w16:
+    pmullw               m0, m4, [srcq+strideq*0]
+    pmullw               m1, m4, [srcq+strideq*1]
+    pmullw               m2, m4, [srcq+strideq*2]
+    pmullw               m3, m4, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    psubw                m0, m5
+    psubw                m1, m5
+    psubw                m2, m5
+    psubw                m3, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    sub                  hd, 4
+    jg .prep_w16
+    RET
+.prep_w32:
+    pmullw               m0, m4, [srcq+strideq*0+32*0]
+    pmullw               m1, m4, [srcq+strideq*0+32*1]
+    pmullw               m2, m4, [srcq+strideq*1+32*0]
+    pmullw               m3, m4, [srcq+strideq*1+32*1]
+    lea                srcq, [srcq+strideq*2]
+    psubw                m0, m5
+    psubw                m1, m5
+    psubw                m2, m5
+    psubw                m3, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    sub                  hd, 2
+    jg .prep_w32
+    RET
+.prep_w64:
+    pmullw               m0, m4, [srcq+32*0]
+    pmullw               m1, m4, [srcq+32*1]
+    pmullw               m2, m4, [srcq+32*2]
+    pmullw               m3, m4, [srcq+32*3]
+    add                srcq, strideq
+    psubw                m0, m5
+    psubw                m1, m5
+    psubw                m2, m5
+    psubw                m3, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    dec                  hd
+    jg .prep_w64
+    RET
+.prep_w128:
+    pmullw               m0, m4, [srcq+32*0]
+    pmullw               m1, m4, [srcq+32*1]
+    pmullw               m2, m4, [srcq+32*2]
+    pmullw               m3, m4, [srcq+32*3]
+    psubw                m0, m5
+    psubw                m1, m5
+    psubw                m2, m5
+    psubw                m3, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    pmullw               m0, m4, [srcq+32*4]
+    pmullw               m1, m4, [srcq+32*5]
+    pmullw               m2, m4, [srcq+32*6]
+    pmullw               m3, m4, [srcq+32*7]
+    add                tmpq, 32*8
+    add                srcq, strideq
+    psubw                m0, m5
+    psubw                m1, m5
+    psubw                m2, m5
+    psubw                m3, m5
+    mova        [tmpq-32*4], m0
+    mova        [tmpq-32*3], m1
+    mova        [tmpq-32*2], m2
+    mova        [tmpq-32*1], m3
+    dec                  hd
+    jg .prep_w128
+    RET
+.h:
+    movd                xm5, mxyd
+    mov                mxyd, r6m ; my
+    vpbroadcastd         m4, [pw_16]
+    vpbroadcastw         m5, xm5
+    vpbroadcastd         m3, [pw_32766]
+    psubw                m4, m5
+    test          dword r7m, 0x800
+    jnz .h_12bpc
+    psllw                m4, 2
+    psllw                m5, 2
+.h_12bpc:
+    test               mxyd, mxyd
+    jnz .hv
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_h)]
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.h_w4:
+    movu                xm1, [srcq+strideq*0]
+    vinserti128          m1, [srcq+strideq*2], 1
+    movu                xm2, [srcq+strideq*1]
+    vinserti128          m2, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    punpcklqdq           m0, m1, m2
+    psrldq               m1, 2
+    pslldq               m2, 6
+    pmullw               m0, m4
+    vpblendd             m1, m2, 0xcc
+    pmullw               m1, m5
+    psubw                m0, m3
+    paddw                m0, m1
+    psraw                m0, 2
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4
+    RET
+.h_w8:
+    movu                xm0, [srcq+strideq*0]
+    vinserti128          m0, [srcq+strideq*1], 1
+    movu                xm1, [srcq+strideq*0+2]
+    vinserti128          m1, [srcq+strideq*1+2], 1
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    psubw                m0, m3
+    paddw                m0, m1
+    psraw                m0, 2
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    pmullw               m0, m4, [srcq+strideq*0]
+    pmullw               m1, m5, [srcq+strideq*0+2]
+    psubw                m0, m3
+    paddw                m0, m1
+    pmullw               m1, m4, [srcq+strideq*1]
+    pmullw               m2, m5, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    psubw                m1, m3
+    paddw                m1, m2
+    psraw                m0, 2
+    psraw                m1, 2
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    add                tmpq, 32*2
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+.h_w64:
+.h_w128:
+    movifnidn           t0d, org_w
+.h_w32_loop0:
+    mov                 r3d, t0d
+.h_w32_loop:
+    pmullw               m0, m4, [srcq+r3*2-32*1]
+    pmullw               m1, m5, [srcq+r3*2-32*1+2]
+    psubw                m0, m3
+    paddw                m0, m1
+    pmullw               m1, m4, [srcq+r3*2-32*2]
+    pmullw               m2, m5, [srcq+r3*2-32*2+2]
+    psubw                m1, m3
+    paddw                m1, m2
+    psraw                m0, 2
+    psraw                m1, 2
+    mova   [tmpq+r3*2-32*1], m0
+    mova   [tmpq+r3*2-32*2], m1
+    sub                 r3d, 32
+    jg .h_w32_loop
+    add                srcq, strideq
+    lea                tmpq, [tmpq+t0*2]
+    dec                  hd
+    jg .h_w32_loop0
+    RET
+.v:
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_v)]
+    movd                xm5, mxyd
+    vpbroadcastd         m4, [pw_16]
+    vpbroadcastw         m5, xm5
+    vpbroadcastd         m3, [pw_32766]
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    psubw                m4, m5
+    test          dword r7m, 0x800
+    jnz .v_12bpc
+    psllw                m4, 2
+    psllw                m5, 2
+.v_12bpc:
+    jmp                  wq
+.v_w4:
+    movq                xm0, [srcq+strideq*0]
+.v_w4_loop:
+    vpbroadcastq         m2, [srcq+strideq*2]
+    vpbroadcastq        xm1, [srcq+strideq*1]
+    vpblendd             m2, m0, 0x03 ; 0 2 2 2
+    vpbroadcastq         m0, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpblendd             m1, m0, 0xf0 ; 1 1 3 3
+    vpbroadcastq         m0, [srcq+strideq*0]
+    vpblendd             m1, m2, 0x33 ; 0 1 2 3
+    vpblendd             m0, m2, 0x0c ; 4 2 4 4
+    punpckhqdq           m2, m1, m0   ; 1 2 3 4
+    pmullw               m1, m4
+    pmullw               m2, m5
+    psubw                m1, m3
+    paddw                m1, m2
+    psraw                m1, 2
+    mova             [tmpq], m1
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movu                xm0, [srcq+strideq*0]
+.v_w8_loop:
+    vbroadcasti128       m2, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    vpblendd             m1, m0, m2, 0xf0 ; 0 1
+    vbroadcasti128       m0, [srcq+strideq*0]
+    vpblendd             m2, m0, 0xf0     ; 1 2
+    pmullw               m1, m4
+    pmullw               m2, m5
+    psubw                m1, m3
+    paddw                m1, m2
+    psraw                m1, 2
+    mova             [tmpq], m1
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w16:
+    movu                 m0, [srcq+strideq*0]
+.v_w16_loop:
+    movu                 m2, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m0, m4
+    pmullw               m1, m5, m2
+    psubw                m0, m3
+    paddw                m1, m0
+    movu                 m0, [srcq+strideq*0]
+    psraw                m1, 2
+    pmullw               m2, m4
+    mova        [tmpq+32*0], m1
+    pmullw               m1, m5, m0
+    psubw                m2, m3
+    paddw                m1, m2
+    psraw                m1, 2
+    mova        [tmpq+32*1], m1
+    add                tmpq, 32*2
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+.v_w64:
+.v_w128:
+%if WIN64
+    PUSH                 r7
+%endif
+    movifnidn           r7d, org_w
+    add                 r7d, r7d
+    mov                  r3, srcq
+    lea                 r6d, [hq+r7*8-256]
+    mov                  r5, tmpq
+.v_w32_loop0:
+    movu                 m0, [srcq+strideq*0]
+.v_w32_loop:
+    movu                 m2, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m0, m4
+    pmullw               m1, m5, m2
+    psubw                m0, m3
+    paddw                m1, m0
+    movu                 m0, [srcq+strideq*0]
+    psraw                m1, 2
+    pmullw               m2, m4
+    mova        [tmpq+r7*0], m1
+    pmullw               m1, m5, m0
+    psubw                m2, m3
+    paddw                m1, m2
+    psraw                m1, 2
+    mova        [tmpq+r7*1], m1
+    lea                tmpq, [tmpq+r7*2]
+    sub                  hd, 2
+    jg .v_w32_loop
+    add                  r3, 32
+    add                  r5, 32
+    movzx                hd, r6b
+    mov                srcq, r3
+    mov                tmpq, r5
+    sub                 r6d, 1<<8
+    jg .v_w32_loop0
+%if WIN64
+    POP                  r7
+%endif
+    RET
+.hv:
+    WIN64_SPILL_XMM       7
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_hv)]
+    shl                mxyd, 11
+    movd                xm6, mxyd
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    vpbroadcastw         m6, xm6
+    jmp                  wq
+.hv_w4:
+    movu                xm1, [srcq+strideq*0]
+%if WIN64
+    movaps         [rsp+24], xmm7
+%endif
+    pmullw              xm0, xm4, xm1
+    psrldq              xm1, 2
+    pmullw              xm1, xm5
+    psubw               xm0, xm3
+    paddw               xm0, xm1
+    psraw               xm0, 2
+    vpbroadcastq         m0, xm0
+.hv_w4_loop:
+    movu                xm1, [srcq+strideq*1]
+    vinserti128          m1, [srcq+stride3q ], 1
+    movu                xm2, [srcq+strideq*2]
+    lea                srcq, [srcq+strideq*4]
+    vinserti128          m2, [srcq+strideq*0], 1
+    punpcklqdq           m7, m1, m2
+    psrldq               m1, 2
+    pslldq               m2, 6
+    pmullw               m7, m4
+    vpblendd             m1, m2, 0xcc
+    pmullw               m1, m5
+    psubw                m7, m3
+    paddw                m1, m7
+    psraw                m1, 2         ; 1 2 3 4
+    vpblendd             m0, m1, 0x3f
+    vpermq               m2, m0, q2103 ; 0 1 2 3
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhrsw             m1, m6
+    paddw                m1, m2
+    mova             [tmpq], m1
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+%if WIN64
+    movaps             xmm7, [rsp+24]
+%endif
+    RET
+.hv_w8:
+    pmullw              xm0, xm4, [srcq+strideq*0]
+    pmullw              xm1, xm5, [srcq+strideq*0+2]
+    psubw               xm0, xm3
+    paddw               xm0, xm1
+    psraw               xm0, 2
+    vinserti128          m0, xm0, 1
+.hv_w8_loop:
+    movu                xm1, [srcq+strideq*1]
+    movu                xm2, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    vinserti128          m1, [srcq+strideq*0], 1
+    vinserti128          m2, [srcq+strideq*0+2], 1
+    pmullw               m1, m4
+    pmullw               m2, m5
+    psubw                m1, m3
+    paddw                m1, m2
+    psraw                m1, 2            ; 1 2
+    vperm2i128           m2, m0, m1, 0x21 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhrsw             m1, m6
+    paddw                m1, m2
+    mova             [tmpq], m1
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+.hv_w32:
+.hv_w64:
+.hv_w128:
+%if WIN64
+    PUSH                 r7
+%endif
+    movifnidn           r7d, org_w
+    add                 r7d, r7d
+    mov                  r3, srcq
+    lea                 r6d, [hq+r7*8-256]
+    mov                  r5, tmpq
+.hv_w16_loop0:
+    pmullw               m0, m4, [srcq]
+    pmullw               m1, m5, [srcq+2]
+    psubw                m0, m3
+    paddw                m0, m1
+    psraw                m0, 2
+.hv_w16_loop:
+    pmullw               m1, m4, [srcq+strideq*1]
+    pmullw               m2, m5, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    psubw                m1, m3
+    paddw                m1, m2
+    psraw                m1, 2
+    psubw                m2, m1, m0
+    pmulhrsw             m2, m6
+    paddw                m2, m0
+    mova        [tmpq+r7*0], m2
+    pmullw               m0, m4, [srcq+strideq*0]
+    pmullw               m2, m5, [srcq+strideq*0+2]
+    psubw                m0, m3
+    paddw                m0, m2
+    psraw                m0, 2
+    psubw                m2, m0, m1
+    pmulhrsw             m2, m6
+    paddw                m2, m1
+    mova        [tmpq+r7*1], m2
+    lea                tmpq, [tmpq+r7*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    add                  r3, 32
+    add                  r5, 32
+    movzx                hd, r6b
+    mov                srcq, r3
+    mov                tmpq, r5
+    sub                 r6d, 1<<8
+    jg .hv_w16_loop0
+%if WIN64
+    POP                  r7
+%endif
+    RET
+
+; int8_t subpel_filters[5][15][8]
+%assign FILTER_REGULAR (0*15 << 16) | 3*15
+%assign FILTER_SMOOTH  (1*15 << 16) | 4*15
+%assign FILTER_SHARP   (2*15 << 16) | 3*15
+
+%macro FN 4-5 ; prefix, type, type_h, type_v, jmp_to
+cglobal %1_%2_16bpc
+    mov                 t0d, FILTER_%3
+%ifidn %3, %4
+    mov                 t1d, t0d
+%else
+    mov                 t1d, FILTER_%4
+%endif
+%if %0 == 5 ; skip the jump in the last filter
+    jmp mangle(private_prefix %+ _%5 %+ SUFFIX)
+%endif
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 4, 5
+%else
+DECLARE_REG_TMP 7, 8
+%endif
+
+%define PUT_8TAP_FN FN put_8tap,
+PUT_8TAP_FN smooth,         SMOOTH,  SMOOTH,  put_6tap_16bpc
+PUT_8TAP_FN smooth_regular, SMOOTH,  REGULAR, put_6tap_16bpc
+PUT_8TAP_FN regular_smooth, REGULAR, SMOOTH,  put_6tap_16bpc
+PUT_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal put_6tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my
+%define base r8-put_avx2
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    lea                  r8, [put_avx2]
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.put:
+    tzcnt                wd, wd
+    movzx                wd, word [r8+wq*2+table_offset(put,)]
+    add                  wq, r8
+%if WIN64
+    pop                  r8
+%endif
+    jmp                  wq
+.h_w2:
+    movzx               mxd, mxb
+    sub                srcq, 2
+    mova                xm2, [subpel_h_shuf2]
+    vpbroadcastd        xm3, [base+subpel_filters+mxq*8+2]
+    pmovsxbw            xm3, xm3
+.h_w2_loop:
+    movu                xm0, [srcq+ssq*0]
+    movu                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb              xm0, xm2
+    pshufb              xm1, xm2
+    pmaddwd             xm0, xm3
+    pmaddwd             xm1, xm3
+    phaddd              xm0, xm1
+    paddd               xm0, xm4
+    psrad               xm0, 6
+    packusdw            xm0, xm0
+    pminsw              xm0, xm5
+    movd       [dstq+dsq*0], xm0
+    pextrd     [dstq+dsq*1], xm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2_loop
+    RET
+.h_w4:
+    movzx               mxd, mxb
+    sub                srcq, 2
+    pmovsxbw            xm3, [base+subpel_filters+mxq*8]
+    WIN64_SPILL_XMM       8
+    vbroadcasti128       m6, [subpel_h_shufA]
+    vbroadcasti128       m7, [subpel_h_shufB]
+    pshufd              xm3, xm3, q2211
+    vpbroadcastq         m2, xm3
+    vpermq               m3, m3, q1111
+.h_w4_loop:
+    movu                xm1, [srcq+ssq*0]
+    vinserti128          m1, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m0, m1, m6 ; 0 1 1 2 2 3 3 4
+    pshufb               m1, m7     ; 2 3 3 4 4 5 5 6
+    pmaddwd              m0, m2
+    pmaddwd              m1, m3
+    paddd                m0, m4
+    paddd                m0, m1
+    psrad                m0, 6
+    vextracti128        xm1, m0, 1
+    packusdw            xm0, xm1
+    pminsw              xm0, xm5
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h:
+    test                myd, 0xf00
+    jnz .hv
+    mov                 r7d, r8m
+    vpbroadcastw         m5, r8m
+    shr                 r7d, 11
+    vpbroadcastd         m4, [base+put_8tap_h_rnd+r7*4]
+    cmp                  wd, 4
+    je .h_w4
+    jl .h_w2
+    WIN64_SPILL_XMM      11
+    shr                 mxd, 16
+    sub                srcq, 4
+    vpbroadcastq         m0, [base+subpel_filters+1+mxq*8]
+    vbroadcasti128       m6, [base+subpel_h_shufA]
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    pshufd               m7, m0, q0000
+    pshufd               m8, m0, q1111
+    pshufd               m9, m0, q2222
+    sub                  wd, 16
+    jge .h_w16
+.h_w8:
+%macro PUT_6TAP_H 5 ; dst/src+0, src+8, src+16, tmp[1-2]
+    pshufb              m%1, m6        ; 01 12 23 34
+    pshufb              m%2, m6        ; 45 56 67 78
+    pmaddwd             m%4, m7, m%1   ; a0
+    pshufb              m%3, m6        ; 89 9a ab bc
+    pmaddwd             m%5, m9, m%2   ; a2
+    shufpd              m%1, m%2, 0x05 ; 23 34 45 56
+    paddd               m%4, m%5       ; a0+a2
+    pmaddwd             m%5, m7, m%2   ; b0
+    shufpd              m%2, m%3, 0x05 ; 67 78 89 9a
+    pmaddwd             m%3, m9        ; b2
+    pmaddwd             m%1, m8        ; a1
+    pmaddwd             m%2, m8        ; b1
+    paddd               m%3, m%5       ; b0+b2
+    paddd               m%4, m4
+    paddd               m%3, m4
+    paddd               m%1, m%4
+    paddd               m%2, m%3
+    psrad               m%1, 6
+    psrad               m%2, 6
+    packusdw            m%1, m%2
+    pminsw              m%1, m5
+%endmacro
+    movu                xm0, [srcq+ssq*0+ 0]
+    vinserti128          m0, [srcq+ssq*1+ 0], 1
+    movu                xm2, [srcq+ssq*0+16]
+    vinserti128          m2, [srcq+ssq*1+16], 1
+    shufpd               m1, m0, m2, 0x05
+    lea                srcq, [srcq+ssq*2]
+    PUT_6TAP_H            0, 1, 2, 3, 10
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    mov                 r6d, wd
+.h_w16_loop:
+    movu                 m0, [srcq+r6*2+ 0]
+    movu                 m1, [srcq+r6*2+ 8]
+    movu                 m2, [srcq+r6*2+16]
+    PUT_6TAP_H            0, 1, 2, 3, 10
+    mova        [dstq+r6*2], m0
+    sub                 r6d, 16
+    jge .h_w16_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w16
+    RET
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m0, [base+subpel_filters+1+myq*8]
+    WIN64_SPILL_XMM      10, 12
+    vpbroadcastd         m5, [pd_32]
+    vpbroadcastw         m6, r8m
+    punpcklbw            m0, m0
+    mov                  r6, ssq
+    psraw                m0, 8 ; sign-extend
+    neg                  r6
+    pshufd               m7, m0, q0000
+    pshufd               m8, m0, q1111
+    pshufd               m9, m0, q2222
+    cmp                  wd, 4
+    jg .v_w8
+    je .v_w4
+.v_w2:
+    movd                xm2, [srcq+r6 *2]
+    pinsrd              xm2, [srcq+r6 *1], 1
+    pinsrd              xm2, [srcq+ssq*0], 2
+    pinsrd              xm2, [srcq+ssq*1], 3 ; 0 1 2 3
+    lea                srcq, [srcq+ssq*2]
+    movd                xm0, [srcq+ssq*0]
+    palignr             xm3, xm0, xm2, 4     ; 1 2 3 4
+    punpcklwd           xm1, xm2, xm3        ; 01 12
+    punpckhwd           xm2, xm3             ; 23 34
+.v_w2_loop:
+    movd                xm3, [srcq+ssq*1]
+    pmaddwd             xm4, xm7, xm1        ; a0 b0
+    mova                xm1, xm2
+    pmaddwd             xm2, xm8             ; a1 b1
+    lea                srcq, [srcq+ssq*2]
+    paddd               xm4, xm2
+    punpckldq           xm2, xm0, xm3        ; 4 5
+    movd                xm0, [srcq+ssq*0]
+    punpckldq           xm3, xm0             ; 5 6
+    punpcklwd           xm2, xm3             ; 45 56
+    pmaddwd             xm3, xm9, xm2        ; a2 b2
+    paddd               xm4, xm5
+    paddd               xm4, xm3
+    psrad               xm4, 6
+    packusdw            xm4, xm4
+    pminsw              xm4, xm6
+    movd       [dstq+dsq*0], xm4
+    pextrd     [dstq+dsq*1], xm4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movq                xm1, [srcq+r6 *2]
+    vpbroadcastq         m3, [srcq+r6 *1]
+    vpbroadcastq         m2, [srcq+ssq*0]
+    vpbroadcastq         m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m1, m3, 0x30
+    vpblendd             m3, m2, 0x30
+    punpcklwd            m1, m3     ; 01 12
+    vpblendd             m2, m4, 0x30
+    vpblendd             m4, m0, 0x30
+    punpcklwd            m2, m4     ; 23 34
+.v_w4_loop:
+    vpbroadcastq         m3, [srcq+ssq*1]
+    pmaddwd              m4, m7, m1 ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m8     ; a1 b1
+    lea                srcq, [srcq+ssq*2]
+    paddd                m4, m2
+    vpblendd             m2, m0, m3, 0x30
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m3, m0, 0x30
+    punpcklwd            m2, m3     ; 45 56
+    pmaddwd              m3, m9, m2 ; a2 b2
+    paddd                m4, m5
+    paddd                m4, m3
+    psrad                m4, 6
+    vextracti128        xm3, m4, 1
+    packusdw            xm4, xm3
+    pminsw              xm4, xm6
+    movq       [dstq+dsq*0], xm4
+    movhps     [dstq+dsq*1], xm4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    shl                  wd, 5
+    WIN64_PUSH_XMM       12
+    lea                  wd, [hq+wq-256]
+.v_w8_loop0:
+    vbroadcasti128       m3, [srcq+r6 *2]
+    vbroadcasti128       m4, [srcq+r6 *1]
+    lea                  r7, [srcq+ssq*2]
+    vbroadcasti128       m0, [srcq+ssq*0]
+    vbroadcasti128       m1, [srcq+ssq*1]
+    mov                  r8, dstq
+    vbroadcasti128       m2, [r7+ssq*0]
+    shufpd               m3, m0, 0x0c
+    shufpd               m4, m1, 0x0c
+    punpcklwd            m1, m3, m4 ; 01
+    punpckhwd            m3, m4     ; 23
+    shufpd               m0, m2, 0x0c
+    punpcklwd            m2, m4, m0 ; 12
+    punpckhwd            m4, m0     ; 34
+.v_w8_loop:
+    vbroadcasti128       m5, [r7+ssq*1]
+    pmaddwd             m10, m7, m1 ; a0
+    lea                  r7, [r7+ssq*2]
+    pmaddwd             m11, m7, m2 ; b0
+    mova                 m1, m3
+    pmaddwd              m3, m8     ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m8     ; b1
+    paddd               m10, m3
+    vbroadcasti128       m3, [r7+ssq*0]
+    paddd               m11, m4
+    shufpd               m4, m0, m5, 0x0d
+    shufpd               m0, m5, m3, 0x0c
+    punpcklwd            m3, m4, m0 ; 45
+    punpckhwd            m4, m0     ; 56
+    pmaddwd              m5, m9, m3 ; a2
+    paddd               m10, m5
+    pmaddwd              m5, m9, m4 ; b2
+    paddd                m5, m11
+    psrad               m10, 5
+    psrad                m5, 5
+    packusdw            m10, m5
+    pxor                 m5, m5
+    pavgw                m5, m10
+    pminsw               m5, m6
+    vpermq               m5, m5, q3120
+    mova         [r8+dsq*0], xm5
+    vextracti128 [r8+dsq*1], m5, 1
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .v_w8_loop0
+    RET
+.hv:
+    WIN64_SPILL_XMM      12, 16
+    vpbroadcastd        m10, [pd_512]
+    vpbroadcastw        m11, r8m
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    vpbroadcastd         m0, [base+subpel_filters+mxq*8+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m1, [base+subpel_filters+1+myq*8]
+    mov                  r6, ssq
+    sub                srcq, 2
+    neg                  r6
+    pxor                 m6, m6
+    punpcklbw            m6, m0
+    punpcklbw            m1, m1
+    psraw                m1, 8 ; sign-extend
+    test          dword r8m, 0x800
+    jz .hv_10bit
+    psraw                m6, 2
+    psllw                m1, 2
+.hv_10bit:
+    pshufd               m7, m1, q0000
+    pshufd               m8, m1, q1111
+    pshufd               m9, m1, q2222
+    cmp                  wd, 4
+    je .hv_w4
+    vbroadcasti128       m5, [subpel_h_shuf2]
+    vbroadcasti128       m0, [srcq+ssq*0]
+    vinserti128          m2, m0, [srcq+r6*2], 1 ; 2 0
+    movu                xm1, [srcq+ssq*1]
+    vinserti128          m1, [srcq+r6 *1], 1    ; 3 1
+    lea                srcq, [srcq+ssq*2]
+    vinserti128          m0, [srcq+ssq*0], 0    ; 4 2
+    REPX    {pshufb  x, m5}, m2, m1, m0
+    REPX    {pmaddwd x, m6}, m2, m1, m0
+    phaddd               m2, m1
+    phaddd               m1, m0
+    paddd                m2, m10
+    paddd                m1, m10
+    psrad                m2, 10
+    psrad                m1, 10
+    packssdw             m2, m1       ; 2 3 3 4   0 1 1 2
+    punpckhqdq           m0, m2, m2
+    punpcklwd            m2, m0       ; 23 34
+    vextracti128        xm1, m2, 1    ; 01 12
+.hv_w2_loop:
+    movu                xm3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movu                xm4, [srcq+ssq*0]
+    pshufb              xm3, xm5
+    pshufb              xm4, xm5
+    pmaddwd             xm3, xm6
+    pmaddwd             xm4, xm6
+    phaddd              xm3, xm4
+    pmaddwd             xm4, xm7, xm1 ; a0 b0
+    mova                xm1, xm2
+    pmaddwd             xm2, xm8      ; a1 b1
+    paddd               xm4, xm2
+    paddd               xm3, xm10
+    psrad               xm3, 10
+    packssdw            xm3, xm3
+    palignr             xm2, xm3, xm0, 12
+    mova                xm0, xm3
+    punpcklwd           xm2, xm0      ; 45 56
+    pmaddwd             xm3, xm9, xm2 ; a2 b2
+    paddd               xm4, xm10
+    paddd               xm4, xm3
+    psrad               xm4, 10
+    packusdw            xm4, xm4
+    pminsw              xm4, xm11
+    movd       [dstq+dsq*0], xm4
+    pextrd     [dstq+dsq*1], xm4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    WIN64_PUSH_XMM       14
+    vbroadcasti128      m12, [subpel_h_shufA]
+    pshufd               m5, m6, q0000
+    vbroadcasti128      m13, [subpel_h_shufB]
+    pshufd               m6, m6, q1111
+    movu                xm2, [srcq+r6 *2]
+    vinserti128          m2, [srcq+r6 *1], 1 ; 0 1
+    movu                xm0, [srcq+ssq*0]
+    vinserti128          m0, [srcq+ssq*1], 1 ; 2 3
+    lea                srcq, [srcq+ssq*2]
+    movu                xm3, [srcq+ssq*0]    ; 4
+    pshufb               m1, m2, m12
+    pmaddwd              m1, m5
+    pshufb               m2, m13
+    pmaddwd              m2, m6
+    pshufb               m4, m0, m12
+    pmaddwd              m4, m5
+    pshufb               m0, m13
+    pmaddwd              m0, m6
+    paddd                m2, m1
+    pshufb              xm1, xm3, xm12
+    pmaddwd             xm1, xm5
+    pshufb              xm3, xm13
+    pmaddwd             xm3, xm6
+    paddd                m0, m4
+    paddd                m2, m10
+    paddd               xm1, xm10
+    paddd                m0, m10
+    paddd               xm3, xm1
+    REPX      {psrad x, 10}, m2, m0, xm3
+    packssdw             m2, m0     ; 0 2   1 3
+    packssdw            xm0, xm3    ; 2 4
+    vperm2i128           m0, m2, 0x03
+    punpcklwd            m1, m2, m0 ; 01 12
+    punpckhwd            m2, m0     ; 23 34
+.hv_w4_loop:
+    movu                xm3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti128          m3, [srcq+ssq*0], 1
+    pmaddwd              m4, m7, m1 ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m8     ; a1 b1
+    paddd                m4, m2
+    pshufb               m2, m3, m12
+    pmaddwd              m2, m5
+    pshufb               m3, m13
+    pmaddwd              m3, m6
+    paddd                m2, m10
+    paddd                m3, m2
+    psrad                m3, 10
+    packssdw             m3, m3     ; 5 5   6 6
+    vperm2i128           m2, m0, m3, 0x21
+    mova                 m0, m3
+    punpckhwd            m2, m3     ; 45 56
+    pmaddwd              m3, m9, m2 ; a2 b2
+    paddd                m4, m10
+    paddd                m4, m3
+    psrad                m4, 10
+    vextracti128        xm3, m4, 1
+    packusdw            xm4, xm3
+    pminsw              xm4, xm11
+    movq       [dstq+dsq*0], xm4
+    movhps     [dstq+dsq*1], xm4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    WIN64_PUSH_XMM       16, 12
+    shr                 mxd, 16
+    vbroadcasti128      m12, [subpel_h_shufA]
+    vpbroadcastq         m2, [base+subpel_filters+1+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    pmovsxbw            xm1, [base+subpel_filters+1+myq*8]
+    shl                  wd, 5
+    mov                  r6, ssq
+    sub                srcq, 4
+    pxor                 m0, m0
+    neg                  r6
+    punpcklbw            m0, m2
+    lea                  wd, [hq+wq-256]
+    test          dword r8m, 0x800
+    jz .hv_w8_10bit
+    psraw                m0, 2
+    psllw               xm1, 2
+.hv_w8_10bit:
+    pshufd               m7, m0, q0000
+    pshufd               m8, m0, q1111
+%if WIN64
+    %define v_mul (rsp+stack_offset+40) ; r4m
+%else
+    %define v_mul (rsp+stack_offset+ 8) ; r6m
+%endif
+    mova            [v_mul], xm1
+    pshufd               m9, m0, q2222
+.hv_w8_loop0:
+    vbroadcasti128       m0, [srcq+ssq*0+ 0]
+    vinserti128          m3, m0, [srcq+r6*2+ 0], 0
+    lea                  r7, [srcq+ssq*2]
+    vbroadcasti128       m2, [srcq+ssq*0+16]
+    vinserti128          m1, m2, [srcq+r6*2+16], 0
+    mov                  r8, dstq
+    vinserti128          m0, [r7  +ssq*0+ 0], 1
+    vinserti128          m2, [r7  +ssq*0+16], 1
+    shufpd               m4, m3, m1, 0x05
+%macro PUT_6TAP_HV_H 5 ; dst/src+0, src+8, src+16, tmp[1-2]
+    pshufb              m%1, m12       ; 01 12 23 34
+    pshufb              m%2, m12       ; 45 56 67 78
+    pmaddwd             m%4, m7, m%1   ; a0
+    pshufb              m%3, m12       ; 89 9a ab bc
+    pmaddwd             m%5, m9, m%2   ; a2
+    shufpd              m%1, m%2, 0x05 ; 23 34 45 56
+    paddd               m%4, m%5       ; a0+a2
+    pmaddwd             m%5, m7, m%2   ; b0
+    shufpd              m%2, m%3, 0x05 ; 67 78 89 9a
+    pmaddwd             m%3, m9        ; b2
+    pmaddwd             m%1, m8        ; a1
+    pmaddwd             m%2, m8        ; b1
+    paddd               m%3, m%5       ; b0+b2
+    paddd               m%4, m10
+    paddd               m%3, m10
+    paddd               m%1, m%4
+    paddd               m%2, m%3
+    psrad               m%1, 10
+    psrad               m%2, 10
+    packssdw            m%1, m%2
+%endmacro
+    PUT_6TAP_HV_H         3, 4, 1, 5, 6  ; 0 2
+    movu                xm4, [srcq+r6 *1+ 0]
+    vinserti128          m4, [srcq+ssq*1+ 0], 1
+    shufpd               m1, m0, m2, 0x05
+    PUT_6TAP_HV_H         0, 1, 2, 5, 6  ; 2 4
+    movu                xm2, [srcq+r6 *1+16]
+    vinserti128          m2, [srcq+ssq*1+16], 1
+    shufpd               m1, m4, m2, 0x05
+    PUT_6TAP_HV_H         4, 1, 2, 5, 6  ; 1 3
+    vpermq               m3, m3, q3120
+    vpermq               m4, m4, q3120
+    vpermq               m0, m0, q3120
+    punpcklwd            m1, m3, m4      ; 01
+    punpckhwd            m3, m4          ; 23
+    punpcklwd            m2, m4, m0      ; 12
+    punpckhwd            m4, m0          ; 34
+.hv_w8_loop:
+    vpbroadcastd        m15, [v_mul+4*0]
+    vpbroadcastd        m13, [v_mul+4*1]
+    movu                xm5, [r7+ssq*1+ 0]
+    movu                xm6, [r7+ssq*1+16]
+    lea                  r7, [r7+ssq*2]
+    pmaddwd             m14, m15, m1     ; a0
+    pmaddwd             m15, m2          ; b0
+    vinserti128          m5, [r7+ssq*0+ 0], 1
+    vinserti128          m6, [r7+ssq*0+16], 1
+    mova                 m1, m3
+    pmaddwd              m3, m13         ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m13         ; b1
+    paddd               m14, m3
+    shufpd               m3, m5, m6, 0x05
+    paddd               m15, m4
+    PUT_6TAP_HV_H         5, 3, 6, 4, 13 ; 5 6
+    vpbroadcastd         m6, [v_mul+4*2]
+    vpermq               m5, m5, q3120
+    shufpd               m4, m0, m5, 0x05
+    mova                 m0, m5
+    punpcklwd            m3, m4, m5      ; 45
+    punpckhwd            m4, m5          ; 56
+    pmaddwd              m5, m6, m3      ; a2
+    pmaddwd              m6, m4          ; b2
+    paddd               m14, m10
+    paddd               m15, m10
+    paddd                m5, m14
+    paddd                m6, m15
+    psrad                m5, 10
+    psrad                m6, 10
+    packusdw             m5, m6
+    pminsw               m5, m11
+    vpermq               m5, m5, q3120
+    mova         [r8+dsq*0], xm5
+    vextracti128 [r8+dsq*1], m5, 1
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .hv_w8_loop0
+    RET
+
+PUT_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_16bpc
+PUT_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  put_8tap_16bpc
+PUT_8TAP_FN regular_sharp,  REGULAR, SHARP,   put_8tap_16bpc
+PUT_8TAP_FN sharp_regular,  SHARP,   REGULAR, put_8tap_16bpc
+PUT_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my
+%define base r8-put_avx2
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    lea                  r8, [put_avx2]
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _put_6tap_16bpc_avx2).put
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m0, [base+subpel_filters+myq*8]
+    WIN64_SPILL_XMM      12, 15
+    vpbroadcastd         m6, [pd_32]
+    vpbroadcastw         m7, r8m
+    lea                  r6, [ssq*3]
+    sub                srcq, r6
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    pshufd               m8, m0, q0000
+    pshufd               m9, m0, q1111
+    pshufd              m10, m0, q2222
+    pshufd              m11, m0, q3333
+    cmp                  wd, 4
+    jg .v_w8
+    je .v_w4
+.v_w2:
+    movd                xm2, [srcq+ssq*0]
+    pinsrd              xm2, [srcq+ssq*1], 1
+    pinsrd              xm2, [srcq+ssq*2], 2
+    pinsrd              xm2, [srcq+r6   ], 3 ; 0 1 2 3
+    lea                srcq, [srcq+ssq*4]
+    movd                xm3, [srcq+ssq*0]
+    vpbroadcastd        xm1, [srcq+ssq*1]
+    vpbroadcastd        xm0, [srcq+ssq*2]
+    add                srcq, r6
+    vpblendd            xm3, xm1, 0x02       ; 4 5
+    vpblendd            xm1, xm0, 0x02       ; 5 6
+    palignr             xm4, xm3, xm2, 4     ; 1 2 3 4
+    punpcklwd           xm3, xm1             ; 45 56
+    punpcklwd           xm1, xm2, xm4        ; 01 12
+    punpckhwd           xm2, xm4             ; 23 34
+.v_w2_loop:
+    vpbroadcastd        xm4, [srcq+ssq*0]
+    pmaddwd             xm5, xm8, xm1        ; a0 b0
+    mova                xm1, xm2
+    pmaddwd             xm2, xm9             ; a1 b1
+    paddd               xm5, xm6
+    paddd               xm5, xm2
+    mova                xm2, xm3
+    pmaddwd             xm3, xm10            ; a2 b2
+    paddd               xm5, xm3
+    vpblendd            xm3, xm0, xm4, 0x02  ; 6 7
+    vpbroadcastd        xm0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd            xm4, xm0, 0x02       ; 7 8
+    punpcklwd           xm3, xm4             ; 67 78
+    pmaddwd             xm4, xm11, xm3       ; a3 b3
+    paddd               xm5, xm4
+    psrad               xm5, 6
+    packusdw            xm5, xm5
+    pminsw              xm5, xm7
+    movd       [dstq+dsq*0], xm5
+    pextrd     [dstq+dsq*1], xm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movq                xm1, [srcq+ssq*0]
+    vpbroadcastq         m0, [srcq+ssq*1]
+    vpbroadcastq         m2, [srcq+ssq*2]
+    vpbroadcastq         m4, [srcq+r6   ]
+    lea                srcq, [srcq+ssq*4]
+    vpbroadcastq         m3, [srcq+ssq*0]
+    vpbroadcastq         m5, [srcq+ssq*1]
+    vpblendd             m1, m0, 0x30
+    vpblendd             m0, m2, 0x30
+    punpcklwd            m1, m0      ; 01 12
+    vpbroadcastq         m0, [srcq+ssq*2]
+    add                srcq, r6
+    vpblendd             m2, m4, 0x30
+    vpblendd             m4, m3, 0x30
+    punpcklwd            m2, m4      ; 23 34
+    vpblendd             m3, m5, 0x30
+    vpblendd             m5, m0, 0x30
+    punpcklwd            m3, m5      ; 45 56
+.v_w4_loop:
+    vpbroadcastq         m4, [srcq+ssq*0]
+    pmaddwd              m5, m8, m1  ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m9      ; a1 b1
+    paddd                m5, m6
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, m10     ; a2 b2
+    paddd                m5, m3
+    vpblendd             m3, m0, m4, 0x30
+    vpbroadcastq         m0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd             m4, m0, 0x30
+    punpcklwd            m3, m4      ; 67 78
+    pmaddwd              m4, m11, m3 ; a3 b3
+    paddd                m5, m4
+    psrad                m5, 6
+    vextracti128        xm4, m5, 1
+    packusdw            xm5, xm4
+    pminsw              xm5, xm7
+    movq       [dstq+dsq*0], xm5
+    movhps     [dstq+dsq*1], xm5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    shl                  wd, 5
+    WIN64_PUSH_XMM       15
+    lea                  wd, [hq+wq-256]
+.v_w8_loop0:
+    vbroadcasti128       m4, [srcq+ssq*0]
+    vbroadcasti128       m5, [srcq+ssq*1]
+    lea                  r7, [srcq+ssq*4]
+    vbroadcasti128       m0, [srcq+r6   ]
+    vbroadcasti128       m6, [srcq+ssq*2]
+    mov                  r8, dstq
+    vbroadcasti128       m1, [r7+ssq*0]
+    vbroadcasti128       m2, [r7+ssq*1]
+    vbroadcasti128       m3, [r7+ssq*2]
+    add                  r7, r6
+    shufpd               m4, m0, 0x0c
+    shufpd               m5, m1, 0x0c
+    punpcklwd            m1, m4, m5 ; 01
+    punpckhwd            m4, m5     ; 34
+    shufpd               m6, m2, 0x0c
+    punpcklwd            m2, m5, m6 ; 12
+    punpckhwd            m5, m6     ; 45
+    shufpd               m0, m3, 0x0c
+    punpcklwd            m3, m6, m0 ; 23
+    punpckhwd            m6, m0     ; 56
+.v_w8_loop:
+    vbroadcasti128      m14, [r7+ssq*0]
+    pmaddwd             m12, m8, m1  ; a0
+    pmaddwd             m13, m8, m2  ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddwd              m3, m9      ; a1
+    pmaddwd              m4, m9      ; b1
+    paddd               m12, m3
+    paddd               m13, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddwd              m5, m10     ; a2
+    pmaddwd              m6, m10     ; b2
+    paddd               m12, m5
+    vbroadcasti128       m5, [r7+ssq*1]
+    lea                  r7, [r7+ssq*2]
+    paddd               m13, m6
+    shufpd               m6, m0, m14, 0x0d
+    shufpd               m0, m14, m5, 0x0c
+    punpcklwd            m5, m6, m0  ; 67
+    punpckhwd            m6, m0      ; 78
+    pmaddwd             m14, m11, m5 ; a3
+    paddd               m12, m14
+    pmaddwd             m14, m11, m6 ; b3
+    paddd               m13, m14
+    psrad               m12, 5
+    psrad               m13, 5
+    packusdw            m12, m13
+    pxor                m13, m13
+    pavgw               m12, m13
+    pminsw              m12, m7
+    vpermq              m12, m12, q3120
+    mova         [r8+dsq*0], xm12
+    vextracti128 [r8+dsq*1], m12, 1
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .v_w8_loop0
+    RET
+.h:
+    RESET_STACK_STATE
+    test                myd, 0xf00
+    jnz .hv
+    mov                 r7d, r8m
+    vpbroadcastw         m5, r8m
+    shr                 r7d, 11
+    vpbroadcastd         m4, [base+put_8tap_h_rnd+r7*4]
+    cmp                  wd, 4
+    jl mangle(private_prefix %+ _put_6tap_16bpc_avx2).h_w2
+    je mangle(private_prefix %+ _put_6tap_16bpc_avx2).h_w4
+    WIN64_SPILL_XMM      13
+    shr                 mxd, 16
+    sub                srcq, 6
+    vpbroadcastq         m0, [base+subpel_filters+mxq*8]
+    vbroadcasti128       m6, [subpel_h_shufA]
+    vbroadcasti128       m7, [subpel_h_shufB]
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    pshufd               m8, m0, q0000
+    pshufd               m9, m0, q1111
+    pshufd              m10, m0, q2222
+    pshufd              m11, m0, q3333
+    sub                  wd, 16
+    jge .h_w16
+.h_w8:
+%macro PUT_8TAP_H 5 ; dst/src+0, src+8, src+16, tmp[1-2]
+    pshufb              m%4, m%1, m7   ; 2 3 3 4 4 5 5 6
+    pshufb              m%1, m6        ; 0 1 1 2 2 3 3 4
+    pmaddwd             m%5, m9, m%4   ; abcd1
+    pmaddwd             m%1, m8        ; abcd0
+    pshufb              m%2, m7        ; 6 7 7 8 8 9 9 a
+    shufpd              m%4, m%2, 0x05 ; 4 5 5 6 6 7 7 8
+    paddd               m%5, m4
+    paddd               m%1, m%5
+    pmaddwd             m%5, m11, m%2  ; abcd3
+    paddd               m%1, m%5
+    pmaddwd             m%5, m10, m%4  ; abcd2
+    pshufb              m%3, m7        ; a b b c c d d e
+    pmaddwd             m%4, m8        ; efgh0
+    paddd               m%1, m%5
+    pmaddwd             m%5, m9, m%2   ; efgh1
+    shufpd              m%2, m%3, 0x05 ; 8 9 9 a a b b c
+    pmaddwd             m%3, m11       ; efgh3
+    pmaddwd             m%2, m10       ; efgh2
+    paddd               m%4, m4
+    paddd               m%4, m%5
+    paddd               m%3, m%4
+    paddd               m%2, m%3
+    psrad               m%1, 6
+    psrad               m%2, 6
+    packusdw            m%1, m%2
+    pminsw              m%1, m5
+%endmacro
+    movu                xm0, [srcq+ssq*0+ 0]
+    vinserti128          m0, [srcq+ssq*1+ 0], 1
+    movu                xm2, [srcq+ssq*0+16]
+    vinserti128          m2, [srcq+ssq*1+16], 1
+    lea                srcq, [srcq+ssq*2]
+    shufpd               m1, m0, m2, 0x05
+    PUT_8TAP_H            0, 1, 2, 3, 12
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    mov                 r6d, wd
+.h_w16_loop:
+    movu                 m0, [srcq+r6*2+ 0]
+    movu                 m1, [srcq+r6*2+ 8]
+    movu                 m2, [srcq+r6*2+16]
+    PUT_8TAP_H            0, 1, 2, 3, 12
+    mova        [dstq+r6*2], m0
+    sub                 r6d, 16
+    jge .h_w16_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w16
+    RET
+.hv:
+    WIN64_SPILL_XMM      16
+    vpbroadcastw        m15, r8m
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    vpbroadcastd         m0, [base+subpel_filters+mxq*8+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m1, [base+subpel_filters+myq*8]
+    vpbroadcastd         m6, [pd_512]
+    lea                  r6, [ssq*3]
+    sub                srcq, 2
+    sub                srcq, r6
+    pxor                 m7, m7
+    punpcklbw            m7, m0
+    punpcklbw            m1, m1
+    psraw                m1, 8 ; sign-extend
+    test          dword r8m, 0x800
+    jz .hv_10bit
+    psraw                m7, 2
+    psllw                m1, 2
+.hv_10bit:
+    pshufd              m11, m1, q0000
+    pshufd              m12, m1, q1111
+    pshufd              m13, m1, q2222
+    pshufd              m14, m1, q3333
+    cmp                  wd, 4
+    je .hv_w4
+    vbroadcasti128       m9, [subpel_h_shuf2]
+    vbroadcasti128       m1, [srcq+r6   ]    ; 3 3
+    movu                xm3, [srcq+ssq*2]
+    movu                xm0, [srcq+ssq*0]
+    movu                xm2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*4]
+    vinserti128          m3, [srcq+ssq*0], 1 ; 2 4
+    vinserti128          m0, [srcq+ssq*1], 1 ; 0 5
+    vinserti128          m2, [srcq+ssq*2], 1 ; 1 6
+    add                srcq, r6
+    pshufb               m1, m9
+    pshufb               m3, m9
+    pshufb               m0, m9
+    pshufb               m2, m9
+    pmaddwd              m1, m7
+    pmaddwd              m3, m7
+    pmaddwd              m0, m7
+    pmaddwd              m2, m7
+    phaddd               m1, m3
+    phaddd               m0, m2
+    paddd                m1, m6
+    paddd                m0, m6
+    psrad                m1, 10
+    psrad                m0, 10
+    packssdw             m1, m0         ; 3 2 0 1
+    vextracti128        xm0, m1, 1      ; 3 4 5 6
+    pshufd              xm2, xm1, q1301 ; 2 3 1 2
+    pshufd              xm3, xm0, q2121 ; 4 5 4 5
+    punpckhwd           xm1, xm2        ; 01 12
+    punpcklwd           xm2, xm0        ; 23 34
+    punpckhwd           xm3, xm0        ; 45 56
+.hv_w2_loop:
+    movu                xm4, [srcq+ssq*0]
+    movu                xm5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb              xm4, xm9
+    pshufb              xm5, xm9
+    pmaddwd             xm4, xm7
+    pmaddwd             xm5, xm7
+    phaddd              xm4, xm5
+    pmaddwd             xm5, xm11, xm1 ; a0 b0
+    mova                xm1, xm2
+    pmaddwd             xm2, xm12      ; a1 b1
+    paddd               xm5, xm2
+    mova                xm2, xm3
+    pmaddwd             xm3, xm13      ; a2 b2
+    paddd               xm5, xm3
+    paddd               xm4, xm6
+    psrad               xm4, 10
+    packssdw            xm4, xm4
+    palignr             xm3, xm4, xm0, 12
+    mova                xm0, xm4
+    punpcklwd           xm3, xm0       ; 67 78
+    pmaddwd             xm4, xm14, xm3 ; a3 b3
+    paddd               xm5, xm6
+    paddd               xm5, xm4
+    psrad               xm5, 10
+    packusdw            xm5, xm5
+    pminsw              xm5, xm15
+    movd       [dstq+dsq*0], xm5
+    pextrd     [dstq+dsq*1], xm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    vbroadcasti128       m9, [subpel_h_shufA]
+    vbroadcasti128      m10, [subpel_h_shufB]
+    pshufd               m8, m7, q1111
+    pshufd               m7, m7, q0000
+    movu                xm1, [srcq+ssq*0]
+    vinserti128          m1, [srcq+ssq*1], 1     ; 0 1
+    vbroadcasti128       m0, [srcq+r6   ]
+    vinserti128          m2, m0, [srcq+ssq*2], 0 ; 2 3
+    lea                srcq, [srcq+ssq*4]
+    vinserti128          m0, [srcq+ssq*0], 1     ; 3 4
+    movu                xm3, [srcq+ssq*1]
+    vinserti128          m3, [srcq+ssq*2], 1     ; 5 6
+    add                srcq, r6
+    pshufb               m4, m1, m9
+    pshufb               m1, m10
+    pmaddwd              m4, m7
+    pmaddwd              m1, m8
+    pshufb               m5, m2, m9
+    pshufb               m2, m10
+    pmaddwd              m5, m7
+    pmaddwd              m2, m8
+    paddd                m4, m6
+    paddd                m1, m4
+    pshufb               m4, m0, m9
+    pshufb               m0, m10
+    pmaddwd              m4, m7
+    pmaddwd              m0, m8
+    paddd                m5, m6
+    paddd                m2, m5
+    pshufb               m5, m3, m9
+    pshufb               m3, m10
+    pmaddwd              m5, m7
+    pmaddwd              m3, m8
+    paddd                m4, m6
+    paddd                m4, m0
+    paddd                m5, m6
+    paddd                m5, m3
+    vperm2i128           m0, m1, m2, 0x21
+    psrld                m1, 10
+    psrld                m2, 10
+    vperm2i128           m3, m4, m5, 0x21
+    pslld                m4, 6
+    pslld                m5, 6
+    pblendw              m2, m4, 0xaa ; 23 34
+    pslld                m0, 6
+    pblendw              m1, m0, 0xaa ; 01 12
+    psrld                m3, 10
+    pblendw              m3, m5, 0xaa ; 45 56
+    psrad                m0, m5, 16
+.hv_w4_loop:
+    movu                xm4, [srcq+ssq*0]
+    vinserti128          m4, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m5, m11, m1   ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m12       ; a1 b1
+    paddd                m5, m6
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, m13       ; a2 b2
+    paddd                m5, m3
+    pshufb               m3, m4, m9
+    pshufb               m4, m10
+    pmaddwd              m3, m7
+    pmaddwd              m4, m8
+    paddd                m3, m6
+    paddd                m4, m3
+    psrad                m4, 10
+    packssdw             m0, m4        ; _ 7 6 8
+    vpermq               m3, m0, q1122 ; _ 6 _ 7
+    punpckhwd            m3, m0        ; 67 78
+    mova                 m0, m4
+    pmaddwd              m4, m14, m3   ; a3 b3
+    paddd                m4, m5
+    psrad                m4, 10
+    vextracti128        xm5, m4, 1
+    packusdw            xm4, xm5
+    pminsw              xm4, xm15
+    movq       [dstq+dsq*0], xm4
+    movhps     [dstq+dsq*1], xm4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    vpbroadcastq         m2, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    pmovsxbw            xm1, [base+subpel_filters+myq*8]
+    shl                  wd, 5
+    lea                  r6, [ssq*3]
+    sub                srcq, 6
+    pxor                 m0, m0
+    sub                srcq, r6
+    punpcklbw            m0, m2
+    lea                  wd, [hq+wq-256]
+    test          dword r8m, 0x800
+    jz .hv_w8_10bit
+    psraw                m0, 2
+    psllw               xm1, 2
+.hv_w8_10bit:
+    pshufd              m11, m0, q0000
+    pshufd              m12, m0, q1111
+    mova            [v_mul], xm1
+    pshufd              m13, m0, q2222
+    pshufd              m14, m0, q3333
+.hv_w8_loop0:
+%macro PUT_8TAP_HV_H 3 ; dst/src+0, src+8, src+16
+    pshufb               m2, m%1, m9   ; 2 3 3 4 4 5 5 6
+    pshufb              m%1, m8        ; 0 1 1 2 2 3 3 4
+    pmaddwd              m3, m12, m2
+    pmaddwd             m%1, m11
+    pshufb              m%2, m9        ; 6 7 7 8 8 9 9 a
+    shufpd               m2, m%2, 0x05 ; 4 5 5 6 6 7 7 8
+    paddd                m3, m10
+    paddd               m%1, m3
+    pmaddwd              m3, m14, m%2
+    paddd               m%1, m3
+    pmaddwd              m3, m13, m2
+    pshufb              m%3, m9        ; a b b c c d d e
+    pmaddwd              m2, m11
+    paddd               m%1, m3
+    pmaddwd              m3, m12, m%2
+    shufpd              m%2, m%3, 0x05 ; 8 9 9 a a b b c
+    pmaddwd             m%3, m14
+    pmaddwd             m%2, m13
+    paddd                m2, m10
+    paddd                m2, m3
+    paddd               m%3, m2
+    paddd               m%2, m%3
+    psrad               m%1, 10
+    psrad               m%2, 10
+    packssdw            m%1, m%2
+%endmacro
+    movu                xm4, [srcq+r6 *1+ 0]
+    vbroadcasti128       m8, [subpel_h_shufA]
+    lea                  r7, [srcq+ssq*4]
+    movu                xm6, [srcq+r6 *1+ 8]
+    vbroadcasti128       m9, [subpel_h_shufB]
+    mov                  r8, dstq
+    movu                xm0, [srcq+r6 *1+16]
+    vpbroadcastd        m10, [pd_512]
+    movu                xm5, [srcq+ssq*0+ 0]
+    vinserti128          m5, [r7  +ssq*0+ 0], 1
+    movu                xm1, [srcq+ssq*0+16]
+    vinserti128          m1, [r7  +ssq*0+16], 1
+    shufpd               m7, m5, m1, 0x05
+    INIT_XMM avx2
+    PUT_8TAP_HV_H         4, 6, 0    ; 3
+    INIT_YMM avx2
+    PUT_8TAP_HV_H         5, 7, 1    ; 0 4
+    movu                xm0, [srcq+ssq*2+ 0]
+    vinserti128          m0, [srcq+r6 *2+ 0], 1
+    movu                xm1, [srcq+ssq*2+16]
+    vinserti128          m1, [srcq+r6 *2+16], 1
+    shufpd               m7, m0, m1, 0x05
+    PUT_8TAP_HV_H         0, 7, 1    ; 2 6
+    movu                xm6, [srcq+ssq*1+ 0]
+    movu                xm1, [srcq+ssq*1+16]
+    vinserti128          m6, [r7  +ssq*1+ 0], 1
+    vinserti128          m1, [r7  +ssq*1+16], 1
+    add                  r7, r6
+    shufpd               m7, m6, m1, 0x05
+    PUT_8TAP_HV_H         6, 7, 1    ; 1 5
+    vpermq               m4, m4, q1100
+    vpermq               m5, m5, q3120
+    vpermq               m6, m6, q3120
+    vpermq               m7, m0, q3120
+    punpcklwd            m3, m7, m4  ; 23
+    punpckhwd            m4, m5      ; 34
+    punpcklwd            m1, m5, m6  ; 01
+    punpckhwd            m5, m6      ; 45
+    punpcklwd            m2, m6, m7  ; 12
+    punpckhwd            m6, m7      ; 56
+.hv_w8_loop:
+    vpbroadcastd         m9, [v_mul+4*0]
+    vpbroadcastd         m7, [v_mul+4*1]
+    vpbroadcastd        m10, [v_mul+4*2]
+    pmaddwd              m8, m9, m1  ; a0
+    pmaddwd              m9, m2      ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddwd              m3, m7      ; a1
+    pmaddwd              m4, m7      ; b1
+    paddd                m8, m3
+    paddd                m9, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddwd              m5, m10     ; a2
+    pmaddwd              m6, m10     ; b2
+    paddd                m8, m5
+    paddd                m9, m6
+    movu                xm5, [r7+ssq*0]
+    vinserti128          m5, [r7+ssq*1], 1
+    vbroadcasti128       m7, [subpel_h_shufA]
+    vbroadcasti128      m10, [subpel_h_shufB]
+    movu                xm6, [r7+ssq*0+16]
+    vinserti128          m6, [r7+ssq*1+16], 1
+    vextracti128       [r8], m0, 1
+    pshufb               m0, m5, m7  ; 01
+    pshufb               m5, m10     ; 23
+    pmaddwd              m0, m11
+    pmaddwd              m5, m12
+    paddd                m0, m5
+    pshufb               m5, m6, m7  ; 89
+    pshufb               m6, m10     ; ab
+    pmaddwd              m5, m13
+    pmaddwd              m6, m14
+    paddd                m6, m5
+    movu                xm5, [r7+ssq*0+8]
+    vinserti128          m5, [r7+ssq*1+8], 1
+    lea                  r7, [r7+ssq*2]
+    pshufb               m7, m5, m7
+    pshufb               m5, m10
+    pmaddwd             m10, m13, m7
+    pmaddwd              m7, m11
+    paddd                m0, m10
+    vpbroadcastd        m10, [pd_512]
+    paddd                m6, m7
+    pmaddwd              m7, m14, m5
+    pmaddwd              m5, m12
+    paddd                m0, m7
+    paddd                m5, m6
+    vbroadcasti128       m6, [r8]
+    paddd                m8, m10
+    paddd                m9, m10
+    paddd                m0, m10
+    paddd                m5, m10
+    vpbroadcastd        m10, [v_mul+4*3]
+    psrad                m0, 10
+    psrad                m5, 10
+    packssdw             m0, m5
+    vpermq               m7, m0, q3120 ; 7 8
+    shufpd               m6, m7, 0x04  ; 6 7
+    punpcklwd            m5, m6, m7    ; 67
+    punpckhwd            m6, m7        ; 78
+    pmaddwd              m7, m10, m5   ; a3
+    pmaddwd             m10, m6        ; b3
+    paddd                m7, m8
+    paddd                m9, m10
+    psrad                m7, 10
+    psrad                m9, 10
+    packusdw             m7, m9
+    pminsw               m7, m15
+    vpermq               m7, m7, q3120
+    mova         [r8+dsq*0], xm7
+    vextracti128 [r8+dsq*1], m7, 1
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .hv_w8_loop0
+    RET
+
+%if WIN64
+DECLARE_REG_TMP 6, 4
+%else
+DECLARE_REG_TMP 6, 7
+%endif
+
+%define PREP_8TAP_FN FN prep_8tap,
+PREP_8TAP_FN smooth,         SMOOTH,  SMOOTH,  prep_6tap_16bpc
+PREP_8TAP_FN smooth_regular, SMOOTH,  REGULAR, prep_6tap_16bpc
+PREP_8TAP_FN regular_smooth, REGULAR, SMOOTH,  prep_6tap_16bpc
+PREP_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal prep_6tap_16bpc, 4, 8, 0, tmp, src, ss, w, h, mx, my
+%define base r7-prep_avx2
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    lea                  r7, [prep_avx2]
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.prep:
+    tzcnt                wd, wd
+    mov                 r6d, r7m ; bitdepth_max
+    movzx                wd, word [r7+wq*2+table_offset(prep,)]
+    vpbroadcastd         m5, [r7-prep_avx2+pw_8192]
+    shr                 r6d, 11
+    add                  wq, r7
+    vpbroadcastd         m4, [base+prep_mul+r6*4]
+    lea                  r6, [ssq*3]
+%if WIN64
+    pop                  r7
+%endif
+    jmp                  wq
+.h_w4:
+    movzx               mxd, mxb
+    sub                srcq, 2
+    pmovsxbw            xm0, [base+subpel_filters+mxq*8]
+    vbroadcasti128       m3, [subpel_h_shufA]
+    lea                  r6, [ssq*3]
+    vbroadcasti128       m4, [subpel_h_shufB]
+    WIN64_SPILL_XMM       8
+    pshufd              xm0, xm0, q2211
+    test          dword r7m, 0x800
+    jnz .h_w4_12bpc
+    psllw               xm0, 2
+.h_w4_12bpc:
+    vpbroadcastq         m6, xm0
+    vpermq               m7, m0, q1111
+.h_w4_loop:
+    movu                xm1, [srcq+ssq*0]
+    vinserti128          m1, [srcq+ssq*2], 1
+    movu                xm2, [srcq+ssq*1]
+    vinserti128          m2, [srcq+r6 *1], 1
+    lea                srcq, [srcq+ssq*4]
+    pshufb               m0, m1, m3 ; 0 1 1 2 2 3 3 4
+    pshufb               m1, m4     ; 2 3 3 4 4 5 5 6
+    pmaddwd              m0, m6
+    pmaddwd              m1, m7
+    paddd                m0, m5
+    paddd                m0, m1
+    pshufb               m1, m2, m3
+    pshufb               m2, m4
+    pmaddwd              m1, m6
+    pmaddwd              m2, m7
+    paddd                m1, m5
+    paddd                m1, m2
+    psrad                m0, 4
+    psrad                m1, 4
+    packssdw             m0, m1
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4_loop
+    RET
+.h:
+    test                myd, 0xf00
+    jnz .hv
+    vpbroadcastd         m5, [prep_8tap_1d_rnd] ; 8 - (8192 << 4)
+    cmp                  wd, 4
+    je .h_w4
+    shr                 mxd, 16
+    sub                srcq, 4
+    vpbroadcastq         m0, [base+subpel_filters+1+mxq*8]
+    WIN64_SPILL_XMM      10
+    vbroadcasti128       m6, [subpel_h_shufA]
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    test          dword r7m, 0x800
+    jnz .h_12bpc
+    psllw                m0, 2
+.h_12bpc:
+    pshufd               m7, m0, q0000
+    pshufd               m8, m0, q1111
+    pshufd               m9, m0, q2222
+    cmp                  wd, 8
+    jg .h_w16
+.h_w8:
+    movu                xm0, [srcq+ssq*0+ 0]
+    vinserti128          m0, [srcq+ssq*1+ 0], 1
+    movu                xm2, [srcq+ssq*0+16]
+    vinserti128          m2, [srcq+ssq*1+16], 1
+    lea                srcq, [srcq+ssq*2]
+    shufpd               m1, m0, m2, 0x05
+%macro PREP_6TAP_H 5 ; dst/src+0, src+8, src+16, tmp[1-2]
+    pshufb              m%1, m6        ; 01 12 23 34
+    pshufb              m%2, m6        ; 45 56 67 78
+    pmaddwd             m%4, m7, m%1   ; a0
+    pshufb              m%3, m6        ; 89 9a ab bc
+    pmaddwd             m%5, m9, m%2   ; a2
+    shufpd              m%1, m%2, 0x05 ; 23 34 45 56
+    paddd               m%4, m%5       ; a0+a2
+    pmaddwd             m%5, m7, m%2   ; b0
+    shufpd              m%2, m%3, 0x05 ; 67 78 89 9a
+    pmaddwd             m%3, m9        ; b2
+    pmaddwd             m%1, m8        ; a1
+    pmaddwd             m%2, m8        ; b1
+    paddd               m%3, m%5       ; b0+b2
+    paddd               m%4, m5
+    paddd               m%3, m5
+    paddd               m%1, m%4
+    paddd               m%2, m%3
+    psrad               m%1, 4
+    psrad               m%2, 4
+    packssdw            m%1, m%2
+%endmacro
+    PREP_6TAP_H           0, 1, 2, 3, 4
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    add                  wd, wd
+.h_w16_loop0:
+    mov                 r6d, wd
+.h_w16_loop:
+    movu                 m0, [srcq+r6-32]
+    movu                 m1, [srcq+r6-24]
+    movu                 m2, [srcq+r6-16]
+    PREP_6TAP_H           0, 1, 2, 3, 4
+    mova       [tmpq+r6-32], m0
+    sub                 r6d, 32
+    jg .h_w16_loop
+    add                srcq, ssq
+    add                tmpq, wq
+    dec                  hd
+    jg .h_w16_loop0
+    RET
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m0, [base+subpel_filters+1+myq*8]
+    WIN64_SPILL_XMM       9, 12
+    vpbroadcastd         m5, [prep_8tap_1d_rnd]
+    mov                  r6, ssq
+    punpcklbw            m0, m0
+    neg                  r6
+    psraw                m0, 8 ; sign-extend
+    test          dword r7m, 0x800
+    jnz .v_12bpc
+    psllw                m0, 2
+.v_12bpc:
+    pshufd               m6, m0, q0000
+    pshufd               m7, m0, q1111
+    pshufd               m8, m0, q2222
+    cmp                  wd, 4
+    jg .v_w8
+.v_w4:
+    movq                xm1, [srcq+r6 *2]
+    vpbroadcastq         m3, [srcq+r6 *1]
+    vpbroadcastq         m2, [srcq+ssq*0]
+    vpbroadcastq         m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m1, m3, 0x30
+    vpblendd             m3, m2, 0x30
+    punpcklwd            m1, m3     ; 01 12
+    vpblendd             m2, m4, 0x30
+    vpblendd             m4, m0, 0x30
+    punpcklwd            m2, m4     ; 23 34
+.v_w4_loop:
+    vpbroadcastq         m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m4, m6, m1 ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m7     ; a1 b1
+    paddd                m4, m2
+    vpblendd             m2, m0, m3, 0x30
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m3, m0, 0x30
+    punpcklwd            m2, m3     ; 45 56
+    pmaddwd              m3, m8, m2 ; a2 b2
+    paddd                m4, m5
+    paddd                m4, m3
+    psrad                m4, 4
+    vextracti128        xm3, m4, 1
+    packssdw            xm4, xm3
+    mova             [tmpq], xm4
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    WIN64_PUSH_XMM       12
+%if WIN64
+    push                 r8
+%endif
+    mov                 r8d, wd
+    shl                  wd, 5
+    lea                  wd, [hq+wq-256]
+.v_w8_loop0:
+    vbroadcasti128       m3, [srcq+r6 *2]
+    vbroadcasti128       m4, [srcq+r6 *1]
+    lea                  r5, [srcq+ssq*2]
+    vbroadcasti128       m0, [srcq+ssq*0]
+    vbroadcasti128       m1, [srcq+ssq*1]
+    mov                  r7, tmpq
+    vbroadcasti128       m2, [r5+ssq*0]
+    shufpd               m3, m0, 0x0c
+    shufpd               m4, m1, 0x0c
+    punpcklwd            m1, m3, m4 ; 01
+    punpckhwd            m3, m4     ; 23
+    shufpd               m0, m2, 0x0c
+    punpcklwd            m2, m4, m0 ; 12
+    punpckhwd            m4, m0     ; 34
+.v_w8_loop:
+    vbroadcasti128       m9, [r5+ssq*1]
+    pmaddwd             m10, m6, m1 ; a0
+    lea                  r5, [r5+ssq*2]
+    pmaddwd             m11, m6, m2 ; b0
+    mova                 m1, m3
+    pmaddwd              m3, m7     ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m7     ; b1
+    paddd               m10, m5
+    paddd               m11, m5
+    paddd               m10, m3
+    vbroadcasti128       m3, [r5+ssq*0]
+    paddd               m11, m4
+    shufpd               m4, m0, m9, 0x0d
+    shufpd               m0, m9, m3, 0x0c
+    punpcklwd            m3, m4, m0 ; 45
+    punpckhwd            m4, m0     ; 56
+    pmaddwd              m9, m8, m3 ; a2
+    paddd               m10, m9
+    pmaddwd              m9, m8, m4 ; b2
+    paddd               m11, m9
+    psrad               m10, 4
+    psrad               m11, 4
+    packssdw            m10, m11
+    vpermq              m10, m10, q3120
+    mova          [r7+r8*0], xm10
+    vextracti128  [r7+r8*2], m10, 1
+    lea                  r7, [r7+r8*4]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 16
+    add                tmpq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .v_w8_loop0
+%if WIN64
+    pop                  r8
+%endif
+    RET
+.hv:
+    WIN64_SPILL_XMM      13, 15
+    vpbroadcastd         m7, [prep_8tap_2d_rnd]
+    vbroadcasti128       m8, [subpel_h_shufA]
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    vpbroadcastd         m0, [base+subpel_filters+mxq*8+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m1, [base+subpel_filters+1+myq*8]
+    mov                  r6, ssq
+    sub                srcq, 2
+    pxor                 m6, m6
+    neg                  r6
+    punpcklbw            m6, m0
+    punpcklbw            m1, m1
+    psraw                m6, 4
+    psraw                m1, 8
+    test          dword r7m, 0x800
+    jz .hv_w4_10bit
+    psraw                m6, 2
+.hv_w4_10bit:
+    pshufd              m10, m1, q0000
+    pshufd              m11, m1, q1111
+    pshufd              m12, m1, q2222
+.hv_w4:
+    movu                xm2, [srcq+r6 *2]
+    vinserti128          m2, [srcq+r6 *1], 1 ; 0 1
+    pshufd               m5, m6, q0000
+    vbroadcasti128       m9, [base+subpel_h_shufB]
+    movu                xm0, [srcq+ssq*0]
+    pshufd               m6, m6, q1111
+    vinserti128          m0, [srcq+ssq*1], 1 ; 2 3
+    lea                srcq, [srcq+ssq*2]
+    movu                xm3, [srcq+ssq*0]    ; 4
+    pshufb               m1, m2, m8
+    pmaddwd              m1, m5
+    pshufb               m2, m9
+    pmaddwd              m2, m6
+    pshufb               m4, m0, m8
+    pmaddwd              m4, m5
+    pshufb               m0, m9
+    pmaddwd              m0, m6
+    paddd                m2, m1
+    pshufb              xm1, xm3, xm8
+    pmaddwd             xm1, xm5
+    pshufb              xm3, xm9
+    pmaddwd             xm3, xm6
+    paddd                m0, m4
+    paddd                m2, m7
+    paddd               xm1, xm7
+    paddd                m0, m7
+    paddd               xm3, xm1
+    REPX       {psrad x, 6}, m2, m0, xm3
+    packssdw             m2, m0      ; 0 2   1 3
+    packssdw            xm0, xm3     ; 2 4
+    vperm2i128           m0, m2, 0x03
+    punpcklwd            m1, m2, m0  ; 01 12
+    punpckhwd            m2, m0      ; 23 34
+.hv_w4_loop:
+    movu                xm3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti128          m3, [srcq+ssq*0], 1
+    pmaddwd              m4, m10, m1 ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m11     ; a1 b1
+    paddd                m4, m2
+    pshufb               m2, m3, m8
+    pmaddwd              m2, m5
+    pshufb               m3, m9
+    pmaddwd              m3, m6
+    paddd                m2, m7
+    paddd                m3, m2
+    psrad                m3, 6
+    packssdw             m3, m3      ; 5 5   6 6
+    vperm2i128           m2, m0, m3, 0x21
+    mova                 m0, m3
+    punpckhwd            m2, m3      ; 45 56
+    pmaddwd              m3, m12, m2 ; a2 b2
+    paddd                m4, m7
+    paddd                m4, m3
+    psrad                m4, 6
+    vextracti128        xm3, m4, 1
+    packssdw            xm4, xm3
+    mova             [tmpq], xm4
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    vpbroadcastq         m2, [base+subpel_filters+1+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    pmovsxbw            xm1, [base+subpel_filters+1+myq*8]
+    WIN64_PUSH_XMM       15
+%if WIN64
+    PUSH                 r8
+%endif
+    mov                 r8d, wd
+    shl                  wd, 5
+    mov                  r6, ssq
+    sub                srcq, 4
+    neg                  r6
+    lea                  wd, [hq+wq-256]
+    pxor                 m0, m0
+    punpcklbw            m0, m2
+    psraw                m0, 4
+    test          dword r7m, 0x800
+    jz .hv_w8_10bit
+    psraw                m0, 2
+.hv_w8_10bit:
+    pshufd              m10, m0, q0000
+    pshufd              m11, m0, q1111
+    mova            [v_mul], xm1
+    pshufd              m12, m0, q2222
+.hv_w8_loop0:
+    vbroadcasti128       m0, [srcq+ssq*0+ 0]
+    vinserti128          m3, m0, [srcq+r6*2+ 0], 0
+    lea                  r5, [srcq+ssq*2]
+    vbroadcasti128       m2, [srcq+ssq*0+16]
+    vinserti128          m1, m2, [srcq+r6*2+16], 0
+    mov                  r7, tmpq
+    vinserti128          m0, [r5  +ssq*0+ 0], 1
+    vinserti128          m2, [r5  +ssq*0+16], 1
+    shufpd               m4, m3, m1, 0x05
+%macro PREP_6TAP_HV_H 5 ; dst/src+0, src+8, src+16, tmp[1-2]
+    pshufb              m%1, m8        ; 01 12 23 34
+    pshufb              m%2, m8        ; 45 56 67 78
+    pmaddwd             m%4, m10, m%1  ; a0
+    pshufb              m%3, m8        ; 89 9a ab bc
+    pmaddwd             m%5, m12, m%2  ; a2
+    shufpd              m%1, m%2, 0x05 ; 23 34 45 56
+    paddd               m%4, m%5       ; a0+a2
+    pmaddwd             m%5, m10, m%2  ; b0
+    shufpd              m%2, m%3, 0x05 ; 67 78 89 9a
+    pmaddwd             m%3, m12       ; b2
+    pmaddwd             m%1, m11       ; a1
+    pmaddwd             m%2, m11       ; b1
+    paddd               m%3, m%5       ; b0+b2
+    paddd               m%4, m7
+    paddd               m%3, m7
+    paddd               m%1, m%4
+    paddd               m%2, m%3
+    psrad               m%1, 6
+    psrad               m%2, 6
+    packssdw            m%1, m%2
+%endmacro
+    PREP_6TAP_HV_H        3, 4, 1, 5, 6  ; 0 2
+    movu                xm4, [srcq+r6 *1+ 0]
+    vinserti128          m4, [srcq+ssq*1+ 0], 1
+    shufpd               m1, m0, m2, 0x05
+    PREP_6TAP_HV_H        0, 1, 2, 5, 6  ; 2 4
+    movu                xm2, [srcq+r6 *1+16]
+    vinserti128          m2, [srcq+ssq*1+16], 1
+    shufpd               m1, m4, m2, 0x05
+    PREP_6TAP_HV_H        4, 1, 2, 5, 6  ; 1 3
+    vpermq               m3, m3, q3120
+    vpermq               m4, m4, q3120
+    vpermq               m0, m0, q3120
+    punpcklwd            m1, m3, m4     ; 01
+    punpckhwd            m3, m4         ; 23
+    punpcklwd            m2, m4, m0     ; 12
+    punpckhwd            m4, m0         ; 34
+.hv_w8_loop:
+    vpbroadcastd        m14, [v_mul+4*0]
+    vpbroadcastd         m9, [v_mul+4*1]
+    movu                xm5, [r5+ssq*1+ 0]
+    movu                xm6, [r5+ssq*1+16]
+    lea                  r5, [r5+ssq*2]
+    pmaddwd             m13, m14, m1    ; a0
+    pmaddwd             m14, m2         ; b0
+    vinserti128          m5, [r5+ssq*0+ 0], 1
+    vinserti128          m6, [r5+ssq*0+16], 1
+    mova                 m1, m3
+    pmaddwd              m3, m9         ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m9         ; b1
+    paddd               m13, m3
+    shufpd               m3, m5, m6, 0x05
+    paddd               m14, m4
+    PREP_6TAP_HV_H        5, 3, 6, 4, 9 ; 5 6
+    vpbroadcastd         m6, [v_mul+4*2]
+    vpermq               m5, m5, q3120
+    shufpd               m4, m0, m5, 0x05
+    mova                 m0, m5
+    punpcklwd            m3, m4, m5     ; 45
+    punpckhwd            m4, m5         ; 56
+    pmaddwd              m5, m6, m3     ; a2
+    pmaddwd              m6, m4         ; b2
+    paddd               m13, m7
+    paddd               m14, m7
+    paddd                m5, m13
+    paddd                m6, m14
+    psrad                m5, 6
+    psrad                m6, 6
+    packssdw             m5, m6
+    vpermq               m5, m5, q3120
+    mova          [r7+r8*0], xm5
+    vextracti128  [r7+r8*2], m5, 1
+    lea                  r7, [r7+r8*4]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 16
+    add                tmpq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .hv_w8_loop0
+%if WIN64
+    POP                  r8
+%endif
+    RET
+
+PREP_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_16bpc
+PREP_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_16bpc
+PREP_8TAP_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_16bpc
+PREP_8TAP_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_16bpc
+PREP_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal prep_8tap_16bpc, 4, 8, 0, tmp, src, stride, w, h, mx, my
+%define base r7-prep_avx2
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    lea                  r7, [prep_avx2]
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _prep_6tap_16bpc_avx2).prep
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m0, [base+subpel_filters+myq*8]
+    WIN64_SPILL_XMM      12, 15
+    vpbroadcastd         m7, [prep_8tap_1d_rnd]
+    lea                  r6, [strideq*3]
+    punpcklbw            m0, m0
+    sub                srcq, r6
+    psraw                m0, 8 ; sign-extend
+    test          dword r7m, 0x800
+    jnz .v_12bpc
+    psllw                m0, 2
+.v_12bpc:
+    pshufd               m8, m0, q0000
+    pshufd               m9, m0, q1111
+    pshufd              m10, m0, q2222
+    pshufd              m11, m0, q3333
+    cmp                  wd, 4
+    jg .v_w8
+.v_w4:
+    movq                xm1, [srcq+strideq*0]
+    vpbroadcastq         m0, [srcq+strideq*1]
+    vpbroadcastq         m2, [srcq+strideq*2]
+    vpbroadcastq         m4, [srcq+r6       ]
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastq         m3, [srcq+strideq*0]
+    vpbroadcastq         m5, [srcq+strideq*1]
+    vpblendd             m1, m0, 0x30
+    vpblendd             m0, m2, 0x30
+    punpcklwd            m1, m0      ; 01 12
+    vpbroadcastq         m0, [srcq+strideq*2]
+    add                srcq, r6
+    vpblendd             m2, m4, 0x30
+    vpblendd             m4, m3, 0x30
+    punpcklwd            m2, m4      ; 23 34
+    vpblendd             m3, m5, 0x30
+    vpblendd             m5, m0, 0x30
+    punpcklwd            m3, m5      ; 45 56
+.v_w4_loop:
+    vpbroadcastq         m4, [srcq+strideq*0]
+    pmaddwd              m5, m8, m1  ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m9      ; a1 b1
+    paddd                m5, m7
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, m10     ; a2 b2
+    paddd                m5, m3
+    vpblendd             m3, m0, m4, 0x30
+    vpbroadcastq         m0, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    vpblendd             m4, m0, 0x30
+    punpcklwd            m3, m4      ; 67 78
+    pmaddwd              m4, m11, m3 ; a3 b3
+    paddd                m5, m4
+    psrad                m5, 4
+    vextracti128        xm4, m5, 1
+    packssdw            xm5, xm4
+    mova             [tmpq], xm5
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+%if WIN64
+    WIN64_PUSH_XMM       15
+    push                 r8
+%endif
+    mov                 r8d, wd
+    shl                  wd, 5
+    lea                  wd, [hq+wq-256]
+.v_w8_loop0:
+    vbroadcasti128       m4, [srcq+strideq*0]
+    vbroadcasti128       m5, [srcq+strideq*1]
+    lea                  r5, [srcq+strideq*4]
+    vbroadcasti128       m0, [srcq+r6       ]
+    vbroadcasti128       m6, [srcq+strideq*2]
+    mov                  r7, tmpq
+    vbroadcasti128       m1, [r5+strideq*0]
+    vbroadcasti128       m2, [r5+strideq*1]
+    vbroadcasti128       m3, [r5+strideq*2]
+    add                  r5, r6
+    shufpd               m4, m0, 0x0c
+    shufpd               m5, m1, 0x0c
+    punpcklwd            m1, m4, m5 ; 01
+    punpckhwd            m4, m5     ; 34
+    shufpd               m6, m2, 0x0c
+    punpcklwd            m2, m5, m6 ; 12
+    punpckhwd            m5, m6     ; 45
+    shufpd               m0, m3, 0x0c
+    punpcklwd            m3, m6, m0 ; 23
+    punpckhwd            m6, m0     ; 56
+.v_w8_loop:
+    vbroadcasti128      m14, [r5+strideq*0]
+    pmaddwd             m12, m8, m1  ; a0
+    pmaddwd             m13, m8, m2  ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddwd              m3, m9      ; a1
+    pmaddwd              m4, m9      ; b1
+    paddd               m12, m7
+    paddd               m13, m7
+    paddd               m12, m3
+    paddd               m13, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddwd              m5, m10     ; a2
+    pmaddwd              m6, m10     ; b2
+    paddd               m12, m5
+    vbroadcasti128       m5, [r5+strideq*1]
+    lea                  r5, [r5+strideq*2]
+    paddd               m13, m6
+    shufpd               m6, m0, m14, 0x0d
+    shufpd               m0, m14, m5, 0x0c
+    punpcklwd            m5, m6, m0  ; 67
+    punpckhwd            m6, m0      ; 78
+    pmaddwd             m14, m11, m5 ; a3
+    paddd               m12, m14
+    pmaddwd             m14, m11, m6 ; b3
+    paddd               m13, m14
+    psrad               m12, 4
+    psrad               m13, 4
+    packssdw            m12, m13
+    vpermq              m12, m12, q3120
+    mova          [r7+r8*0], xm12
+    vextracti128  [r7+r8*2], m12, 1
+    lea                  r7, [r7+r8*4]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 16
+    add                tmpq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .v_w8_loop0
+%if WIN64
+    pop                  r8
+%endif
+    RET
+.h:
+    test                myd, 0xf00
+    jnz .hv
+    vpbroadcastd         m5, [prep_8tap_1d_rnd] ; 8 - (8192 << 4)
+    cmp                  wd, 4
+    je mangle(private_prefix %+ _prep_6tap_16bpc_avx2).h_w4
+    shr                 mxd, 16
+    sub                srcq, 6
+    vpbroadcastq         m0, [base+subpel_filters+mxq*8]
+    WIN64_SPILL_XMM      12
+    vbroadcasti128       m6, [subpel_h_shufA]
+    vbroadcasti128       m7, [subpel_h_shufB]
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    test          dword r7m, 0x800
+    jnz .h_12bpc
+    psllw                m0, 2
+.h_12bpc:
+    pshufd               m8, m0, q0000
+    pshufd               m9, m0, q1111
+    pshufd              m10, m0, q2222
+    pshufd              m11, m0, q3333
+    cmp                  wd, 8
+    jg .h_w16
+.h_w8:
+%macro PREP_8TAP_H 5 ; dst/src+0, src+8, src+16, tmp[1-2]
+    pshufb              m%4, m%1, m7   ; 2 3 3 4 4 5 5 6
+    pshufb              m%1, m6        ; 0 1 1 2 2 3 3 4
+    pmaddwd             m%5, m9, m%4   ; abcd1
+    pmaddwd             m%1, m8        ; abcd0
+    pshufb              m%2, m7        ; 6 7 7 8 8 9 9 a
+    shufpd              m%4, m%2, 0x05 ; 4 5 5 6 6 7 7 8
+    paddd               m%5, m5
+    paddd               m%1, m%5
+    pmaddwd             m%5, m11, m%2  ; abcd3
+    paddd               m%1, m%5
+    pmaddwd             m%5, m10, m%4  ; abcd2
+    pshufb              m%3, m7        ; a b b c c d d e
+    pmaddwd             m%4, m8        ; efgh0
+    paddd               m%1, m%5
+    pmaddwd             m%5, m9, m%2   ; efgh1
+    shufpd              m%2, m%3, 0x05 ; 8 9 9 a a b b c
+    pmaddwd             m%3, m11       ; efgh3
+    pmaddwd             m%2, m10       ; efgh2
+    paddd               m%4, m5
+    paddd               m%4, m%5
+    paddd               m%3, m%4
+    paddd               m%2, m%3
+    psrad               m%1, 4
+    psrad               m%2, 4
+    packssdw            m%1, m%2
+%endmacro
+    movu                xm0, [srcq+strideq*0+ 0]
+    vinserti128          m0, [srcq+strideq*1+ 0], 1
+    movu                xm2, [srcq+strideq*0+16]
+    vinserti128          m2, [srcq+strideq*1+16], 1
+    lea                srcq, [srcq+strideq*2]
+    shufpd               m1, m0, m2, 0x05
+    PREP_8TAP_H           0, 1, 2, 3, 4
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    add                  wd, wd
+.h_w16_loop0:
+    mov                 r6d, wd
+.h_w16_loop:
+    movu                 m0, [srcq+r6-32]
+    movu                 m1, [srcq+r6-24]
+    movu                 m2, [srcq+r6-16]
+    PREP_8TAP_H           0, 1, 2, 3, 4
+    mova       [tmpq+r6-32], m0
+    sub                 r6d, 32
+    jg .h_w16_loop
+    add                srcq, strideq
+    add                tmpq, wq
+    dec                  hd
+    jg .h_w16_loop0
+    RET
+.hv:
+    WIN64_SPILL_XMM      16
+    vpbroadcastd        m15, [prep_8tap_2d_rnd]
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    vpbroadcastd         m0, [base+subpel_filters+mxq*8+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m1, [base+subpel_filters+myq*8]
+    lea                  r6, [strideq*3]
+    sub                srcq, 2
+    pxor                 m7, m7
+    sub                srcq, r6
+    punpcklbw            m7, m0
+    punpcklbw            m1, m1
+    psraw                m7, 4
+    psraw                m1, 8
+    test          dword r7m, 0x800
+    jz .hv_w4_10bit
+    psraw                m7, 2
+.hv_w4_10bit:
+    pshufd              m11, m1, q0000
+    pshufd              m12, m1, q1111
+    pshufd              m13, m1, q2222
+    pshufd              m14, m1, q3333
+.hv_w4:
+    vbroadcasti128       m9, [subpel_h_shufA]
+    vbroadcasti128      m10, [subpel_h_shufB]
+    pshufd               m8, m7, q1111
+    pshufd               m7, m7, q0000
+    movu                xm1, [srcq+strideq*0]
+    vinserti128          m1, [srcq+strideq*1], 1     ; 0 1
+    vbroadcasti128       m0, [srcq+r6       ]
+    vinserti128          m2, m0, [srcq+strideq*2], 0 ; 2 3
+    lea                srcq, [srcq+strideq*4]
+    vinserti128          m0, [srcq+strideq*0], 1     ; 3 4
+    movu                xm3, [srcq+strideq*1]
+    vinserti128          m3, [srcq+strideq*2], 1     ; 5 6
+    add                srcq, r6
+    pshufb               m4, m1, m9
+    pshufb               m1, m10
+    pmaddwd              m4, m7
+    pmaddwd              m1, m8
+    pshufb               m5, m2, m9
+    pshufb               m2, m10
+    pmaddwd              m5, m7
+    pmaddwd              m2, m8
+    paddd                m4, m15
+    paddd                m1, m4
+    pshufb               m4, m0, m9
+    pshufb               m0, m10
+    pmaddwd              m4, m7
+    pmaddwd              m0, m8
+    paddd                m5, m15
+    paddd                m2, m5
+    pshufb               m5, m3, m9
+    pshufb               m3, m10
+    pmaddwd              m5, m7
+    pmaddwd              m3, m8
+    paddd                m4, m15
+    paddd                m4, m0
+    paddd                m5, m15
+    paddd                m5, m3
+    vperm2i128           m0, m1, m2, 0x21
+    psrld                m1, 6
+    psrld                m2, 6
+    vperm2i128           m3, m4, m5, 0x21
+    pslld                m4, 10
+    pslld                m5, 10
+    pblendw              m2, m4, 0xaa ; 23 34
+    pslld                m0, 10
+    pblendw              m1, m0, 0xaa ; 01 12
+    psrld                m3, 6
+    pblendw              m3, m5, 0xaa ; 45 56
+    psrad                m0, m5, 16
+.hv_w4_loop:
+    movu                xm4, [srcq+strideq*0]
+    vinserti128          m4, [srcq+strideq*1], 1
+    lea                srcq, [srcq+strideq*2]
+    pmaddwd              m5, m11, m1   ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m12       ; a1 b1
+    paddd                m5, m15
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, m13       ; a2 b2
+    paddd                m5, m3
+    pshufb               m3, m4, m9
+    pshufb               m4, m10
+    pmaddwd              m3, m7
+    pmaddwd              m4, m8
+    paddd                m3, m15
+    paddd                m4, m3
+    psrad                m4, 6
+    packssdw             m0, m4        ; _ 7 6 8
+    vpermq               m3, m0, q1122 ; _ 6 _ 7
+    punpckhwd            m3, m0        ; 67 78
+    mova                 m0, m4
+    pmaddwd              m4, m14, m3   ; a3 b3
+    paddd                m4, m5
+    psrad                m4, 6
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+    mova             [tmpq], xm4
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    vpbroadcastq         m2, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    pmovsxbw            xm1, [base+subpel_filters+myq*8]
+%if WIN64
+    PUSH                 r8
+%endif
+    mov                 r8d, wd
+    shl                  wd, 5
+    lea                  r6, [strideq*3]
+    sub                srcq, 6
+    sub                srcq, r6
+    lea                  wd, [hq+wq-256]
+    pxor                 m0, m0
+    punpcklbw            m0, m2
+    psraw                m0, 4
+    test          dword r7m, 0x800
+    jz .hv_w8_10bit
+    psraw                m0, 2
+.hv_w8_10bit:
+    pshufd              m11, m0, q0000
+    pshufd              m12, m0, q1111
+    mova            [v_mul], xm1
+    pshufd              m13, m0, q2222
+    pshufd              m14, m0, q3333
+.hv_w8_loop0:
+%macro PREP_8TAP_HV_H 3 ; dst/src+0, src+8, src+16
+    pshufb               m2, m%1, m9   ; 2 3 3 4 4 5 5 6
+    pshufb              m%1, m8        ; 0 1 1 2 2 3 3 4
+    pmaddwd              m3, m12, m2
+    pmaddwd             m%1, m11
+    pshufb              m%2, m9        ; 6 7 7 8 8 9 9 a
+    shufpd               m2, m%2, 0x05 ; 4 5 5 6 6 7 7 8
+    paddd                m3, m15
+    paddd               m%1, m3
+    pmaddwd              m3, m14, m%2
+    paddd               m%1, m3
+    pmaddwd              m3, m13, m2
+    pshufb              m%3, m9        ; a b b c c d d e
+    pmaddwd              m2, m11
+    paddd               m%1, m3
+    pmaddwd              m3, m12, m%2
+    shufpd              m%2, m%3, 0x05 ; 8 9 9 a a b b c
+    pmaddwd             m%3, m14
+    pmaddwd             m%2, m13
+    paddd                m2, m15
+    paddd                m2, m3
+    paddd                m2, m%3
+    paddd                m2, m%2
+    psrad               m%1, 6
+    psrad                m2, 6
+    packssdw            m%1, m2
+%endmacro
+    movu                xm4, [srcq+r6       + 0]
+    vbroadcasti128       m8, [subpel_h_shufA]
+    lea                  r5, [srcq+strideq*4]
+    movu                xm6, [srcq+r6       + 8]
+    vbroadcasti128       m9, [subpel_h_shufB]
+    mov                  r7, tmpq
+    movu                xm0, [srcq+r6       +16]
+    movu                xm5, [srcq+strideq*0+ 0]
+    vinserti128          m5, [r5  +strideq*0+ 0], 1
+    movu                xm1, [srcq+strideq*0+16]
+    vinserti128          m1, [r5  +strideq*0+16], 1
+    shufpd               m7, m5, m1, 0x05
+    INIT_XMM avx2
+    PREP_8TAP_HV_H        4, 6, 0    ; 3
+    INIT_YMM avx2
+    PREP_8TAP_HV_H        5, 7, 1    ; 0 4
+    movu                xm0, [srcq+strideq*2+ 0]
+    vinserti128          m0, [srcq+r6     *2+ 0], 1
+    movu                xm1, [srcq+strideq*2+16]
+    vinserti128          m1, [srcq+r6     *2+16], 1
+    shufpd               m7, m0, m1, 0x05
+    PREP_8TAP_HV_H        0, 7, 1    ; 2 6
+    movu                xm6, [srcq+strideq*1+ 0]
+    movu                xm1, [srcq+strideq*1+16]
+    vinserti128          m6, [r5  +strideq*1+ 0], 1
+    vinserti128          m1, [r5  +strideq*1+16], 1
+    add                  r5, r6
+    shufpd               m7, m6, m1, 0x05
+    PREP_8TAP_HV_H        6, 7, 1    ; 1 5
+    vpermq               m4, m4, q1100
+    vpermq               m5, m5, q3120
+    vpermq               m6, m6, q3120
+    vpermq               m7, m0, q3120
+    punpcklwd            m3, m7, m4  ; 23
+    punpckhwd            m4, m5      ; 34
+    punpcklwd            m1, m5, m6  ; 01
+    punpckhwd            m5, m6      ; 45
+    punpcklwd            m2, m6, m7  ; 12
+    punpckhwd            m6, m7      ; 56
+.hv_w8_loop:
+    vpbroadcastd         m9, [v_mul+4*0]
+    vpbroadcastd         m7, [v_mul+4*1]
+    vpbroadcastd        m10, [v_mul+4*2]
+    pmaddwd              m8, m9, m1  ; a0
+    pmaddwd              m9, m2      ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddwd              m3, m7      ; a1
+    pmaddwd              m4, m7      ; b1
+    paddd                m8, m15
+    paddd                m9, m15
+    paddd                m8, m3
+    paddd                m9, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddwd              m5, m10     ; a2
+    pmaddwd              m6, m10     ; b2
+    paddd                m8, m5
+    paddd                m9, m6
+    movu                xm5, [r5+strideq*0]
+    vinserti128          m5, [r5+strideq*1], 1
+    vbroadcasti128       m7, [subpel_h_shufA]
+    vbroadcasti128      m10, [subpel_h_shufB]
+    movu                xm6, [r5+strideq*0+16]
+    vinserti128          m6, [r5+strideq*1+16], 1
+    vextracti128       [r7], m0, 1
+    pshufb               m0, m5, m7  ; 01
+    pshufb               m5, m10     ; 23
+    pmaddwd              m0, m11
+    pmaddwd              m5, m12
+    paddd                m0, m15
+    paddd                m0, m5
+    pshufb               m5, m6, m7  ; 89
+    pshufb               m6, m10     ; ab
+    pmaddwd              m5, m13
+    pmaddwd              m6, m14
+    paddd                m5, m15
+    paddd                m6, m5
+    movu                xm5, [r5+strideq*0+8]
+    vinserti128          m5, [r5+strideq*1+8], 1
+    lea                  r5, [r5+strideq*2]
+    pshufb               m7, m5, m7
+    pshufb               m5, m10
+    pmaddwd             m10, m13, m7
+    pmaddwd              m7, m11
+    paddd                m0, m10
+    paddd                m6, m7
+    pmaddwd              m7, m14, m5
+    pmaddwd              m5, m12
+    paddd                m0, m7
+    paddd                m5, m6
+    vbroadcasti128       m6, [r7]
+    vpbroadcastd        m10, [v_mul+4*3]
+    psrad                m0, 6
+    psrad                m5, 6
+    packssdw             m0, m5
+    vpermq               m7, m0, q3120 ; 7 8
+    shufpd               m6, m7, 0x04  ; 6 7
+    punpcklwd            m5, m6, m7    ; 67
+    punpckhwd            m6, m7        ; 78
+    pmaddwd              m7, m10, m5   ; a3
+    pmaddwd             m10, m6        ; b3
+    paddd                m7, m8
+    paddd                m9, m10
+    psrad                m7, 6
+    psrad                m9, 6
+    packssdw             m7, m9
+    vpermq               m7, m7, q3120
+    mova          [r7+r8*0], xm7
+    vextracti128  [r7+r8*2], m7, 1
+    lea                  r7, [r7+r8*4]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 16
+    add                tmpq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .hv_w8_loop0
+%if WIN64
+    POP                  r8
+%endif
+    RET
+
+%macro movifprep 2
+ %if isprep
+    mov %1, %2
+ %endif
+%endmacro
+
+%macro REMAP_REG 2
+ %xdefine r%1  r%2
+ %xdefine r%1q r%2q
+ %xdefine r%1d r%2d
+%endmacro
+
+%macro MCT_8TAP_SCALED_REMAP_REGS_TO_PREV 0
+ %if isprep
+  %xdefine r14_save r14
+  %assign %%i 14
+  %rep 14
+   %assign %%j %%i-1
+   REMAP_REG %%i, %%j
+   %assign %%i %%i-1
+  %endrep
+ %endif
+%endmacro
+
+%macro MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT 0
+ %if isprep
+  %assign %%i 1
+  %rep 13
+   %assign %%j %%i+1
+   REMAP_REG %%i, %%j
+   %assign %%i %%i+1
+  %endrep
+  %xdefine r14 r14_save
+  %undef r14_save
+ %endif
+%endmacro
+
+%macro MC_8TAP_SCALED_RET 0-1 1 ; leave_mapping_unchanged
+    MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT
+    RET
+ %if %1
+    MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %endif
+%endmacro
+
+%macro MC_8TAP_SCALED_H 8-9 0 ; dst, tmp[0-6], load_hrnd
+    movu               xm%1, [srcq+ r4*2]
+    movu               xm%2, [srcq+ r6*2]
+    movu               xm%3, [srcq+ r7*2]
+    movu               xm%4, [srcq+ r9*2]
+    vinserti128         m%1, [srcq+r10*2], 1
+    vinserti128         m%2, [srcq+r11*2], 1
+    vinserti128         m%3, [srcq+r13*2], 1
+    vinserti128         m%4, [srcq+ rX*2], 1
+    add                srcq, ssq
+    movu               xm%5, [srcq+ r4*2]
+    movu               xm%6, [srcq+ r6*2]
+    movu               xm%7, [srcq+ r7*2]
+    movu               xm%8, [srcq+ r9*2]
+    vinserti128         m%5, [srcq+r10*2], 1
+    vinserti128         m%6, [srcq+r11*2], 1
+    vinserti128         m%7, [srcq+r13*2], 1
+    vinserti128         m%8, [srcq+ rX*2], 1
+    add                srcq, ssq
+    pmaddwd             m%1, m12
+    pmaddwd             m%2, m13
+    pmaddwd             m%3, m14
+    pmaddwd             m%4, m15
+    pmaddwd             m%5, m12
+    pmaddwd             m%6, m13
+    pmaddwd             m%7, m14
+    pmaddwd             m%8, m15
+    phaddd              m%1, m%2
+ %if %9
+    mova                m10, [rsp+0x00]
+ %endif
+    phaddd              m%3, m%4
+    phaddd              m%5, m%6
+    phaddd              m%7, m%8
+    phaddd              m%1, m%3
+    phaddd              m%5, m%7
+    paddd               m%1, m10
+    paddd               m%5, m10
+    psrad               m%1, xm11
+    psrad               m%5, xm11
+    packssdw            m%1, m%5
+%endmacro
+
+%macro MC_8TAP_SCALED 1
+%ifidn %1, put
+ %assign isput  1
+ %assign isprep 0
+cglobal put_8tap_scaled_16bpc, 4, 14, 16, 0xe0, dst, ds, src, ss, w, h, mx, my, dx, dy, pxmax
+ %xdefine base_reg r12
+    mov                 r7d, pxmaxm
+%else
+ %assign isput  0
+ %assign isprep 1
+cglobal prep_8tap_scaled_16bpc, 4, 14, 16, 0xe0, tmp, src, ss, w, h, mx, my, dx, dy, pxmax
+  %define tmp_stridem qword [rsp+0xd0]
+ %xdefine base_reg r11
+%endif
+    lea            base_reg, [%1_8tap_scaled_16bpc_avx2]
+%define base base_reg-%1_8tap_scaled_16bpc_avx2
+    tzcnt                wd, wm
+    vpbroadcastd         m8, dxm
+%if isprep && UNIX64
+    movd               xm10, mxd
+    vpbroadcastd        m10, xm10
+    mov                 r5d, t0d
+ DECLARE_REG_TMP 5, 7
+    mov                 r6d, pxmaxm
+%else
+    vpbroadcastd        m10, mxm
+ %if isput
+    vpbroadcastw        m11, pxmaxm
+ %else
+    mov                 r6d, pxmaxm
+ %endif
+%endif
+    mov                 dyd, dym
+%if isput
+ %if WIN64
+    mov                 r8d, hm
+  DEFINE_ARGS dst, ds, src, ss, w, _, _, my, h, dy, ss3
+  %define hm r5m
+  %define dxm r8m
+ %else
+  DEFINE_ARGS dst, ds, src, ss, w, h, _, my, dx, dy, ss3
+  %define hm r6m
+ %endif
+ %define dsm [rsp+0x98]
+ %define rX r1
+ %define rXd r1d
+%else ; prep
+ %if WIN64
+    mov                 r7d, hm
+  DEFINE_ARGS tmp, src, ss, w, _, _, my, h, dy, ss3
+  %define hm r4m
+  %define dxm r7m
+ %else
+  DEFINE_ARGS tmp, src, ss, w, h, _, my, dx, dy, ss3
+  %define hm [rsp+0x98]
+ %endif
+ MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %define rX r14
+ %define rXd r14d
+%endif
+    shr                 r7d, 11
+    vpbroadcastd         m6, [base+pd_0x3ff]
+    vpbroadcastd        m12, [base+s_8tap_h_rnd+r7*4]
+    movd                xm7, [base+s_8tap_h_sh+r7*4]
+%if isput
+    vpbroadcastd        m13, [base+put_s_8tap_v_rnd+r7*4]
+    pinsrd              xm7, [base+put_s_8tap_v_sh+r7*4], 2
+%else
+    vpbroadcastd        m13, [base+pd_m524256]
+%endif
+    pxor                 m9, m9
+    lea                ss3q, [ssq*3]
+    movzx               r7d, t1b
+    shr                 t1d, 16
+    cmp                  hd, 6
+    cmovs               t1d, r7d
+    sub                srcq, ss3q
+    cmp                 dyd, 1024
+    je .dy1
+    cmp                 dyd, 2048
+    je .dy2
+    movzx                wd, word [base+%1_8tap_scaled_avx2_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%if isput
+.w2:
+    mov                 myd, mym
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd               xm15, t0d
+    punpckldq            m8, m9, m8
+    paddd               m10, m8 ; mx+dx*[0,1]
+    vpbroadcastd       xm14, [base+pq_0x40000000+2]
+    vpbroadcastd       xm15, xm15
+    pand                xm8, xm10, xm6
+    psrld               xm8, 6
+    paddd              xm15, xm8
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    vbroadcasti128       m5, [base+bdct_lb_q]
+    vbroadcasti128       m6, [base+subpel_s_shuf2]
+    vpbroadcastd       xm15, [base+subpel_filters+r4*8+2]
+    vpbroadcastd        xm4, [base+subpel_filters+r6*8+2]
+    pcmpeqd             xm8, xm9
+    psrld               m10, 10
+    paddd               m10, m10
+    movu                xm0, [srcq+ssq*0]
+    movu                xm1, [srcq+ssq*1]
+    movu                xm2, [srcq+ssq*2]
+    movu                xm3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pshufb              m10, m5
+    paddb               m10, m6
+    vpblendd           xm15, xm4, 0xa
+    pblendvb           xm15, xm14, xm8
+    pmovsxbw            m15, xm15
+    vinserti128          m0, [srcq+ssq*0], 1 ; 0 4
+    vinserti128          m1, [srcq+ssq*1], 1 ; 1 5
+    vinserti128          m2, [srcq+ssq*2], 1 ; 2 6
+    vinserti128          m3, [srcq+ss3q ], 1 ; 3 7
+    lea                srcq, [srcq+ssq*4]
+    REPX    {pshufb x, m10}, m0, m1, m2, m3
+    REPX   {pmaddwd x, m15}, m0, m1, m2, m3
+    phaddd               m0, m1
+    phaddd               m2, m3
+    paddd                m0, m12
+    paddd                m2, m12
+    psrad                m0, xm7
+    psrad                m2, xm7
+    packssdw             m0, m2             ; 0 1 2 3  4 5 6 7
+    vextracti128        xm1, m0, 1
+    palignr             xm2, xm1, xm0, 4    ; 1 2 3 4
+    punpcklwd           xm3, xm0, xm2       ; 01 12
+    punpckhwd           xm0, xm2            ; 23 34
+    pshufd              xm4, xm1, q0321     ; 5 6 7 _
+    punpcklwd           xm2, xm1, xm4       ; 45 56
+    punpckhwd           xm4, xm1, xm4       ; 67 __
+.w2_loop:
+    and                 myd, 0x3ff
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq               xm14, r6q
+    pmovsxbw           xm14, xm14
+    pshufd              xm8, xm14, q0000
+    pshufd              xm9, xm14, q1111
+    pmaddwd             xm5, xm3, xm8
+    pmaddwd             xm6, xm0, xm9
+    pshufd              xm8, xm14, q2222
+    pshufd             xm14, xm14, q3333
+    paddd               xm5, xm6
+    pmaddwd             xm6, xm2, xm8
+    pmaddwd             xm8, xm4, xm14
+    psrldq              xm9, xm7, 8
+    paddd               xm5, xm6
+    paddd               xm5, xm13
+    paddd               xm5, xm8
+    psrad               xm5, xm9
+    packusdw            xm5, xm5
+    pminsw              xm5, xm11
+    movd             [dstq], xm5
+    add                dstq, dsq
+    dec                  hd
+    jz .ret
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .w2_loop
+    movu                xm5, [srcq]
+    test                myd, 0x400
+    jz .w2_skip_line
+    add                srcq, ssq
+    shufps              xm3, xm0, q1032     ; 01 12
+    shufps              xm0, xm2, q1032     ; 23 34
+    shufps              xm2, xm4, q1032     ; 45 56
+    pshufb              xm5, xm10
+    pmaddwd             xm5, xm15
+    phaddd              xm5, xm5
+    paddd               xm5, xm12
+    psrad               xm5, xm7
+    packssdw            xm5, xm5
+    palignr             xm1, xm5, xm1, 12
+    punpcklqdq          xm1, xm1            ; 6 7 6 7
+    punpcklwd           xm4, xm1, xm5       ; 67 __
+    jmp .w2_loop
+.w2_skip_line:
+    movu                xm6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova                xm3, xm0            ; 01 12
+    mova                xm0, xm2            ; 23 34
+    pshufb              xm5, xm10
+    pshufb              xm6, xm10
+    pmaddwd             xm5, xm15
+    pmaddwd             xm6, xm15
+    phaddd              xm5, xm6
+    paddd               xm5, xm12
+    psrad               xm5, xm7
+    packssdw            xm5, xm5            ; 6 7 6 7
+    palignr             xm1, xm5, xm1, 8    ; 4 5 6 7
+    pshufd              xm5, xm1, q0321     ; 5 6 7 _
+    punpcklwd           xm2, xm1, xm5       ; 45 56
+    punpckhwd           xm4, xm1, xm5       ; 67 __
+    jmp .w2_loop
+%endif
+.w4:
+    mov                 myd, mym
+    mova         [rsp+0x00], m12
+%if isput
+    mova         [rsp+0x20], xm13
+%else
+    SWAP                m11, m13
+%endif
+    mova         [rsp+0x30], xm7
+    vbroadcasti128       m7, [base+rescale_mul]
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd               xm15, t0d
+    pmaddwd              m8, m7
+    vpbroadcastq         m2, [base+pq_0x40000000+1]
+    vpbroadcastd       xm15, xm15
+    SWAP                m13, m10
+    paddd               m13, m8 ; mx+dx*[0-3]
+    pand                 m6, m13
+    psrld                m6, 6
+    paddd              xm15, xm6
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    pextrd             r11d, xm15, 2
+    pextrd             r13d, xm15, 3
+    vbroadcasti128       m5, [base+bdct_lb_q+ 0]
+    vbroadcasti128       m1, [base+bdct_lb_q+16]
+    vbroadcasti128       m0, [base+subpel_s_shuf2]
+    vpbroadcastd       xm14, [base+subpel_filters+r4*8+2]
+    vpbroadcastd        xm7, [base+subpel_filters+r6*8+2]
+    vpbroadcastd       xm15, [base+subpel_filters+r11*8+2]
+    vpbroadcastd        xm8, [base+subpel_filters+r13*8+2]
+    pcmpeqd              m6, m9
+    punpckldq           m10, m6, m6
+    punpckhdq            m6, m6
+    psrld               m13, 10
+    paddd               m13, m13
+    vpblendd           xm14, xm7, 0xa
+    vpblendd           xm15, xm8, 0xa
+    pmovsxbw            m14, xm14
+    pmovsxbw            m15, xm15
+    pblendvb            m14, m2, m10
+    pblendvb            m15, m2, m6
+    pextrd               r4, xm13, 2
+    pshufb              m12, m13, m5
+    pshufb              m13, m1
+    lea                  r6, [r4+ssq*1]
+    lea                 r11, [r4+ssq*2]
+    lea                 r13, [r4+ss3q ]
+    movu                xm7, [srcq+ssq*0]
+    movu                xm9, [srcq+ssq*1]
+    movu                xm8, [srcq+ssq*2]
+    movu               xm10, [srcq+ss3q ]
+    movu                xm1, [srcq+r4   ]
+    movu                xm3, [srcq+r6   ]
+    movu                xm2, [srcq+r11  ]
+    movu                xm4, [srcq+r13  ]
+    lea                srcq, [srcq+ssq*4]
+    vinserti128          m7, [srcq+ssq*0], 1
+    vinserti128          m9, [srcq+ssq*1], 1
+    vinserti128          m8, [srcq+ssq*2], 1
+    vinserti128         m10, [srcq+ss3q ], 1
+    vinserti128          m1, [srcq+r4   ], 1
+    vinserti128          m3, [srcq+r6   ], 1
+    vinserti128          m2, [srcq+r11  ], 1
+    vinserti128          m4, [srcq+r13  ], 1
+    lea                srcq, [srcq+ssq*4]
+    vpbroadcastb         m5, xm13
+    psubb               m13, m5
+    paddb               m12, m0
+    paddb               m13, m0
+    REPX    {pshufb x, m12}, m7, m9, m8, m10
+    REPX   {pmaddwd x, m14}, m7, m9, m8, m10
+    REPX    {pshufb x, m13}, m1, m2, m3, m4
+    REPX   {pmaddwd x, m15}, m1, m2, m3, m4
+    mova                 m5, [rsp+0x00]
+    movd                xm6, [rsp+0x30]
+    phaddd               m7, m1
+    phaddd               m9, m3
+    phaddd               m8, m2
+    phaddd              m10, m4
+    REPX      {paddd x, m5}, m7, m9, m8, m10
+    REPX     {psrad x, xm6}, m7, m9, m8, m10
+    packssdw             m7, m9                 ; 0 1  4 5
+    packssdw             m8, m10                ; 2 3  6 7
+    vextracti128        xm9, m7, 1              ; 4 5
+    vextracti128        xm3, m8, 1              ; 6 7
+    shufps              xm4, xm7, xm8, q1032    ; 1 2
+    shufps              xm5, xm8, xm9, q1032    ; 3 4
+    shufps              xm6, xm9, xm3, q1032    ; 5 6
+    psrldq             xm10, xm3, 8             ; 7 _
+    punpcklwd           xm0, xm7, xm4   ; 01
+    punpckhwd           xm7, xm4        ; 12
+    punpcklwd           xm1, xm8, xm5   ; 23
+    punpckhwd           xm8, xm5        ; 34
+    punpcklwd           xm2, xm9, xm6   ; 45
+    punpckhwd           xm9, xm6        ; 56
+    punpcklwd           xm3, xm10       ; 67
+    mova         [rsp+0x40], xm7
+    mova         [rsp+0x50], xm8
+    mova         [rsp+0x60], xm9
+.w4_loop:
+    and                 myd, 0x3ff
+    mov                r11d, 64 << 24
+    mov                r13d, myd
+    shr                r13d, 6
+    lea                r13d, [t1+r13]
+    cmovnz             r11q, [base+subpel_filters+r13*8]
+    movq                xm9, r11q
+    pmovsxbw            xm9, xm9
+    pshufd              xm7, xm9, q0000
+    pshufd              xm8, xm9, q1111
+    pmaddwd             xm4, xm0, xm7
+    pmaddwd             xm5, xm1, xm8
+    pshufd              xm7, xm9, q2222
+    pshufd              xm9, xm9, q3333
+    pmaddwd             xm6, xm2, xm7
+    pmaddwd             xm8, xm3, xm9
+%if isput
+    mova                xm7, [rsp+0x20]
+    movd                xm9, [rsp+0x38]
+%else
+    SWAP                 m7, m11
+%endif
+    paddd               xm4, xm5
+    paddd               xm6, xm8
+    paddd               xm4, xm6
+    paddd               xm4, xm7
+%if isput
+    psrad               xm4, xm9
+    packusdw            xm4, xm4
+    pminuw              xm4, xm11
+    movq             [dstq], xm4
+    add                dstq, dsq
+%else
+    SWAP                m11, m7
+    psrad               xm4, 6
+    packssdw            xm4, xm4
+    movq             [tmpq], xm4
+    add                tmpq, 8
+%endif
+    dec                  hd
+    jz .ret
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .w4_loop
+    mova                xm8, [rsp+0x00]
+    movd                xm9, [rsp+0x30]
+    movu                xm4, [srcq]
+    movu                xm5, [srcq+r4]
+    test                myd, 0x400
+    jz .w4_skip_line
+    mova                xm0, [rsp+0x40]
+    mova         [rsp+0x40], xm1
+    mova                xm1, [rsp+0x50]
+    mova         [rsp+0x50], xm2
+    mova                xm2, [rsp+0x60]
+    mova         [rsp+0x60], xm3
+    pshufb              xm4, xm12
+    pshufb              xm5, xm13
+    pmaddwd             xm4, xm14
+    pmaddwd             xm5, xm15
+    phaddd              xm4, xm5
+    paddd               xm4, xm8
+    psrad               xm4, xm9
+    packssdw            xm4, xm4
+    punpcklwd           xm3, xm10, xm4
+    mova               xm10, xm4
+    add                srcq, ssq
+    jmp .w4_loop
+.w4_skip_line:
+    movu                xm6, [srcq+ssq*1]
+    movu                xm7, [srcq+r6]
+    movu                 m0, [rsp+0x50]
+    pshufb              xm4, xm12
+    pshufb              xm6, xm12
+    pshufb              xm5, xm13
+    pshufb              xm7, xm13
+    pmaddwd             xm4, xm14
+    pmaddwd             xm6, xm14
+    pmaddwd             xm5, xm15
+    pmaddwd             xm7, xm15
+    mova         [rsp+0x40], m0
+    phaddd              xm4, xm5
+    phaddd              xm6, xm7
+    paddd               xm4, xm8
+    paddd               xm6, xm8
+    psrad               xm4, xm9
+    psrad               xm6, xm9
+    packssdw            xm4, xm6
+    punpcklwd           xm9, xm10, xm4
+    mova         [rsp+0x60], xm9
+    psrldq             xm10, xm4, 8
+    mova                xm0, xm1
+    mova                xm1, xm2
+    mova                xm2, xm3
+    punpcklwd           xm3, xm4, xm10
+    lea                srcq, [srcq+ssq*2]
+    jmp .w4_loop
+    SWAP                m10, m13
+%if isprep
+    SWAP                m13, m11
+%endif
+.w8:
+    mov    dword [rsp+0x80], 1
+    movifprep   tmp_stridem, 16
+    jmp .w_start
+.w16:
+    mov    dword [rsp+0x80], 2
+    movifprep   tmp_stridem, 32
+    jmp .w_start
+.w32:
+    mov    dword [rsp+0x80], 4
+    movifprep   tmp_stridem, 64
+    jmp .w_start
+.w64:
+    mov    dword [rsp+0x80], 8
+    movifprep   tmp_stridem, 128
+    jmp .w_start
+.w128:
+    mov    dword [rsp+0x80], 16
+    movifprep   tmp_stridem, 256
+.w_start:
+    SWAP                m10, m12, m1
+    SWAP                m11, m7
+    ; m1=mx, m7=pxmax, m10=h_rnd, m11=h_sh, m12=free
+%if isput
+    movifnidn           dsm, dsq
+    mova         [rsp+0xb0], xm7
+%endif
+    mova         [rsp+0x00], m10
+    mova         [rsp+0x20], m13
+    shr                 t0d, 16
+    sub                srcq, 6
+    pmaddwd              m8, [base+rescale_mul2]
+    movd               xm15, t0d
+    mov          [rsp+0x84], t0d
+    mov          [rsp+0x88], srcq
+    mov          [rsp+0x90], r0q ; dstq / tmpq
+%if UNIX64
+    mov                  hm, hd
+%endif
+    shl           dword dxm, 3 ; dx*8
+    vpbroadcastd        m15, xm15
+    paddd                m1, m8 ; mx+dx*[0-7]
+    jmp .hloop
+.hloop_prep:
+    dec    dword [rsp+0x80]
+    jz .ret
+    add    qword [rsp+0x90], 16
+    mov                  hd, hm
+    vpbroadcastd         m8, dxm
+    vpbroadcastd         m6, [base+pd_0x3ff]
+    paddd                m1, m8, [rsp+0x40]
+    vpbroadcastd        m15, [rsp+0x84]
+    pxor                 m9, m9
+    mov                srcq, [rsp+0x88]
+    mov                 r0q, [rsp+0x90] ; dstq / tmpq
+.hloop:
+    vpbroadcastq        xm2, [base+pq_0x40000000]
+    pand                 m5, m1, m6
+    psrld                m5, 6
+    paddd               m15, m5
+    pcmpeqd              m5, m9
+    vextracti128        xm7, m15, 1
+    movq                 r6, xm15
+    pextrq               r9, xm15, 1
+    movq                r11, xm7
+    pextrq               rX, xm7, 1
+    mov                 r4d, r6d
+    shr                  r6, 32
+    mov                 r7d, r9d
+    shr                  r9, 32
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    mova         [rsp+0x40], m1
+    movq               xm12, [base+subpel_filters+ r4*8]
+    movq               xm13, [base+subpel_filters+ r6*8]
+    movhps             xm12, [base+subpel_filters+ r7*8]
+    movhps             xm13, [base+subpel_filters+ r9*8]
+    movq               xm14, [base+subpel_filters+r10*8]
+    movq               xm15, [base+subpel_filters+r11*8]
+    movhps             xm14, [base+subpel_filters+r13*8]
+    movhps             xm15, [base+subpel_filters+ rX*8]
+    psrld                m1, 10
+    vextracti128        xm7, m1, 1
+    vextracti128        xm6, m5, 1
+    movq         [rsp+0xa0], xm1
+    movq         [rsp+0xa8], xm7
+    movq                 r6, xm1
+    pextrq              r11, xm1, 1
+    movq                 r9, xm7
+    pextrq               rX, xm7, 1
+    mov                 r4d, r6d
+    shr                  r6, 32
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                 r7d, r9d
+    shr                  r9, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    pshufd              xm4, xm5, q2200
+    pshufd              xm5, xm5, q3311
+    pshufd              xm7, xm6, q2200
+    pshufd              xm6, xm6, q3311
+    pblendvb           xm12, xm2, xm4
+    pblendvb           xm13, xm2, xm5
+    pblendvb           xm14, xm2, xm7
+    pblendvb           xm15, xm2, xm6
+    pmovsxbw            m12, xm12
+    pmovsxbw            m13, xm13
+    pmovsxbw            m14, xm14
+    pmovsxbw            m15, xm15
+    MC_8TAP_SCALED_H 0, 1, 2, 3, 4, 5, 6, 7 ; 0a 1a 0b 1b
+    mova        [rsp+0x60], m0
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 7, 8 ; 2a 3a 2b 3b
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 7, 8, 9 ; 4a 5a 4b 5b
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 7, 8, 9, 0 ; 6a 7a 6b 7b
+    mova                 m0, [rsp+0x60]
+    vbroadcasti128       m9, [base+subpel_s_shuf8]
+    mov                 myd, mym
+    mov                 dyd, dym
+    pshufb               m0, m9     ; 01a 01b
+    pshufb               m1, m9     ; 23a 23b
+    pshufb               m2, m9     ; 45a 45b
+    pshufb               m3, m9     ; 67a 67b
+.vloop:
+    and                 myd, 0x3ff
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq                xm9, r6q
+    punpcklqdq          xm9, xm9
+    pmovsxbw             m9, xm9
+    pshufd               m8, m9, q0000
+    pshufd               m7, m9, q1111
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m7
+    pshufd               m8, m9, q2222
+    pshufd               m9, m9, q3333
+    pmaddwd              m6, m2, m8
+    pmaddwd              m7, m3, m9
+%if isput
+    psrldq              xm8, xm11, 8
+%endif
+    paddd                m4, [rsp+0x20]
+    paddd                m6, m7
+    paddd                m4, m5
+    paddd                m4, m6
+%if isput
+    psrad                m4, xm8
+    vextracti128        xm5, m4, 1
+    packusdw            xm4, xm5
+    pminsw              xm4, [rsp+0xb0]
+    mova             [dstq], xm4
+    add                dstq, dsm
+%else
+    psrad                m4, 6
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+    mova             [tmpq], xm4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .hloop_prep
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .vloop
+    test                myd, 0x400
+    mov          [rsp+0x60], myd
+    mov                 r4d, [rsp+0xa0]
+    mov                 r6d, [rsp+0xa4]
+    mov                 r7d, [rsp+0xa8]
+    mov                 r9d, [rsp+0xac]
+    jz .skip_line
+    vbroadcasti128       m9, [base+wswap]
+    movu                xm4, [srcq+ r4*2]
+    movu                xm5, [srcq+ r6*2]
+    movu                xm6, [srcq+ r7*2]
+    movu                xm7, [srcq+ r9*2]
+    vinserti128          m4, [srcq+r10*2], 1
+    vinserti128          m5, [srcq+r11*2], 1
+    vinserti128          m6, [srcq+r13*2], 1
+    vinserti128          m7, [srcq+ rX*2], 1
+    add                srcq, ssq
+    mov                 myd, [rsp+0x60]
+    mov                 dyd, dym
+    pshufb               m0, m9
+    pshufb               m1, m9
+    pshufb               m2, m9
+    pshufb               m3, m9
+    pmaddwd              m4, m12
+    pmaddwd              m5, m13
+    pmaddwd              m6, m14
+    pmaddwd              m7, m15
+    phaddd               m4, m5
+    phaddd               m6, m7
+    phaddd               m4, m6
+    paddd                m4, m10
+    psrad                m4, xm11
+    pslld                m4, 16
+    pblendw              m0, m1, 0xaa
+    pblendw              m1, m2, 0xaa
+    pblendw              m2, m3, 0xaa
+    pblendw              m3, m4, 0xaa
+    jmp .vloop
+.skip_line:
+    mova                 m0, m1
+    mova                 m1, m2
+    mova                 m2, m3
+    MC_8TAP_SCALED_H      3, 10, 4, 5, 6, 7, 8, 9, 1
+    vbroadcasti128       m9, [base+subpel_s_shuf8]
+    mov                 myd, [rsp+0x60]
+    mov                 dyd, dym
+    pshufb               m3, m9
+    jmp .vloop
+    SWAP                 m1, m12, m10
+    SWAP                 m7, m11
+.dy1:
+    movzx                wd, word [base+%1_8tap_scaled_avx2_dy1_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%if isput
+.dy1_w2:
+    mov                 myd, mym
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd               xm15, t0d
+    punpckldq            m8, m9, m8
+    paddd               m10, m8 ; mx+dx*[0-1]
+    vpbroadcastd       xm14, [base+pq_0x40000000+2]
+    vpbroadcastd       xm15, xm15
+    pand                xm8, xm10, xm6
+    psrld               xm8, 6
+    paddd              xm15, xm8
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    vbroadcasti128       m5, [base+bdct_lb_q]
+    vbroadcasti128       m6, [base+subpel_s_shuf2]
+    vpbroadcastd        m15, [base+subpel_filters+r4*8+2]
+    vpbroadcastd         m4, [base+subpel_filters+r6*8+2]
+    pcmpeqd             xm8, xm9
+    psrld               m10, 10
+    paddd               m10, m10
+    movu                xm0, [srcq+ssq*0]
+    movu                xm1, [srcq+ssq*1]
+    movu                xm2, [srcq+ssq*2]
+    movu                xm3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pshufb              m10, m5
+    paddb               m10, m6
+    vpblendd           xm15, xm4, 0xa
+    pblendvb           xm15, xm14, xm8
+    pmovsxbw            m15, xm15
+    vinserti128          m0, [srcq+ssq*0], 1
+    vinserti128          m1, [srcq+ssq*1], 1
+    vinserti128          m2, [srcq+ssq*2], 1
+    add                srcq, ss3q
+    movq                xm6, r4q
+    pmovsxbw            xm6, xm6
+    pshufd              xm8, xm6, q0000
+    pshufd              xm9, xm6, q1111
+    pshufd             xm14, xm6, q2222
+    pshufd              xm6, xm6, q3333
+    REPX    {pshufb x, m10}, m0, m1, m2
+    pshufb              xm3, xm10
+    REPX   {pmaddwd x, m15}, m0, m1, m2
+    pmaddwd             xm3, xm15
+    phaddd               m0, m1
+    phaddd               m2, m3
+    paddd                m0, m12
+    paddd                m2, m12
+    psrad                m0, xm7
+    psrad                m2, xm7
+    packssdw             m0, m2
+    vextracti128        xm1, m0, 1
+    palignr             xm2, xm1, xm0, 4
+    pshufd              xm4, xm1, q2121
+    punpcklwd           xm3, xm0, xm2       ; 01 12
+    punpckhwd           xm0, xm2            ; 23 34
+    punpcklwd           xm2, xm1, xm4       ; 45 56
+.dy1_w2_loop:
+    movu                xm1, [srcq+ssq*0]
+    movu                xm5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb              xm1, xm10
+    pshufb              xm5, xm10
+    pmaddwd             xm1, xm15
+    pmaddwd             xm5, xm15
+    phaddd              xm1, xm5
+    pmaddwd             xm5, xm3, xm8
+    mova                xm3, xm0
+    pmaddwd             xm0, xm9
+    paddd               xm1, xm12
+    psrad               xm1, xm7
+    packssdw            xm1, xm1
+    paddd               xm5, xm0
+    mova                xm0, xm2
+    pmaddwd             xm2, xm14
+    paddd               xm5, xm2
+    palignr             xm2, xm1, xm4, 12
+    punpcklwd           xm2, xm1            ; 67 78
+    pmaddwd             xm4, xm2, xm6
+    paddd               xm5, xm13
+    paddd               xm5, xm4
+    mova                xm4, xm1
+    psrldq              xm1, xm7, 8
+    psrad               xm5, xm1
+    packusdw            xm5, xm5
+    pminsw              xm5, xm11
+    movd       [dstq+dsq*0], xm5
+    pextrd     [dstq+dsq*1], xm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .dy1_w2_loop
+    RET
+%endif
+.dy1_w4:
+    mov                 myd, mym
+%if isput
+    mova         [rsp+0x50], xm11
+%endif
+    mova         [rsp+0x00], m12
+    mova         [rsp+0x20], m13
+    mova         [rsp+0x40], xm7
+    vbroadcasti128       m7, [base+rescale_mul]
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd               xm15, t0d
+    pmaddwd              m8, m7
+    vpbroadcastq         m2, [base+pq_0x40000000+1]
+    vpbroadcastd       xm15, xm15
+    SWAP                m13, m10
+    paddd               m13, m8 ; mx+dx*[0-3]
+    pand                 m6, m13
+    psrld                m6, 6
+    paddd              xm15, xm6
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    pextrd             r11d, xm15, 2
+    pextrd             r13d, xm15, 3
+    vbroadcasti128       m5, [base+bdct_lb_q+ 0]
+    vbroadcasti128       m1, [base+bdct_lb_q+16]
+    vbroadcasti128       m4, [base+subpel_s_shuf2]
+    vpbroadcastd       xm14, [base+subpel_filters+r4*8+2]
+    vpbroadcastd        xm7, [base+subpel_filters+r6*8+2]
+    vpbroadcastd       xm15, [base+subpel_filters+r11*8+2]
+    vpbroadcastd        xm8, [base+subpel_filters+r13*8+2]
+    pcmpeqd              m6, m9
+    punpckldq           m10, m6, m6
+    punpckhdq            m6, m6
+    psrld               m13, 10
+    paddd               m13, m13
+    vpblendd           xm14, xm7, 0xa
+    vpblendd           xm15, xm8, 0xa
+    pmovsxbw            m14, xm14
+    pmovsxbw            m15, xm15
+    pblendvb            m14, m2, m10
+    pblendvb            m15, m2, m6
+    pextrd               r4, xm13, 2
+    pshufb              m12, m13, m5
+    pshufb              m13, m1
+    lea                  r6, [r4+ssq*2]
+    lea                 r11, [r4+ssq*1]
+    lea                 r13, [r4+ss3q ]
+    movu                xm0, [srcq+ssq*0]
+    movu                xm7, [srcq+r4   ]
+    movu                xm1, [srcq+ssq*2]
+    movu                xm8, [srcq+r6   ]
+    vinserti128          m0, [srcq+ssq*1], 1 ; 0 1
+    vinserti128          m7, [srcq+r11  ], 1
+    vinserti128          m1, [srcq+ss3q ], 1 ; 2 3
+    vinserti128          m8, [srcq+r13  ], 1
+    lea                srcq, [srcq+ssq*4]
+    movu                xm2, [srcq+ssq*0]
+    movu                xm9, [srcq+r4   ]
+    movu                xm3, [srcq+ssq*2]    ; 6 _
+    movu               xm10, [srcq+r6   ]
+    vinserti128          m2, [srcq+ssq*1], 1 ; 4 5
+    vinserti128          m9, [srcq+r11  ], 1
+    lea                srcq, [srcq+ss3q ]
+    vpbroadcastb         m5, xm13
+    psubb               m13, m5
+    paddb               m12, m4
+    paddb               m13, m4
+    mova                 m5, [rsp+0x00]
+    movd                xm6, [rsp+0x40]
+    pshufb               m0, m12
+    pshufb               m1, m12
+    pmaddwd              m0, m14
+    pmaddwd              m1, m14
+    pshufb               m7, m13
+    pshufb               m8, m13
+    pmaddwd              m7, m15
+    pmaddwd              m8, m15
+    pshufb               m2, m12
+    pshufb              xm3, xm12
+    pmaddwd              m2, m14
+    pmaddwd             xm3, xm14
+    pshufb               m9, m13
+    pshufb             xm10, xm13
+    pmaddwd              m9, m15
+    pmaddwd            xm10, xm15
+    phaddd               m0, m7
+    phaddd               m1, m8
+    phaddd               m2, m9
+    phaddd              xm3, xm10
+    paddd                m0, m5
+    paddd                m1, m5
+    paddd                m2, m5
+    paddd               xm3, xm5
+    psrad                m0, xm6
+    psrad                m1, xm6
+    psrad                m2, xm6
+    psrad               xm3, xm6
+    vperm2i128           m4, m0, m1, 0x21 ; 1 2
+    vperm2i128           m5, m1, m2, 0x21 ; 3 4
+    vperm2i128           m6, m2, m3, 0x21 ; 5 6
+    shr                 myd, 6
+    mov                r13d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz             r13q, [base+subpel_filters+myq*8]
+    pslld                m4, 16
+    pslld                m5, 16
+    pslld                m6, 16
+    pblendw              m0, m4, 0xaa ; 01 12
+    pblendw              m1, m5, 0xaa ; 23 34
+    pblendw              m2, m6, 0xaa ; 45 56
+    movq               xm10, r13q
+    punpcklqdq         xm10, xm10
+    pmovsxbw            m10, xm10
+    pshufd               m7, m10, q0000
+    pshufd               m8, m10, q1111
+    pshufd               m9, m10, q2222
+    pshufd              m10, m10, q3333
+.dy1_w4_loop:
+    movu               xm11, [srcq+ssq*0]
+    movu                xm6, [srcq+r4   ]
+    vinserti128         m11, [srcq+ssq*1], 1
+    vinserti128          m6, [srcq+r11  ], 1
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m4, m0, m7
+    pmaddwd              m5, m1, m8
+    pshufb              m11, m12
+    pshufb               m6, m13
+    pmaddwd             m11, m14
+    pmaddwd              m6, m15
+    paddd                m4, [rsp+0x20]
+    phaddd              m11, m6
+    pmaddwd              m6, m2, m9
+    paddd               m11, [rsp+0x00]
+    psrad               m11, [rsp+0x40]
+    mova                 m0, m1
+    mova                 m1, m2
+    paddd                m5, m6
+    paddd                m4, m5
+    vinserti128          m2, m3, xm11, 1
+    pslld                m3, m11, 16
+    pblendw              m2, m3, 0xaa   ; 67 78
+    pmaddwd              m5, m2, m10
+    vextracti128        xm3, m11, 1
+    paddd                m4, m5
+%if isput
+    psrad                m4, [rsp+0x48]
+    vextracti128        xm5, m4, 1
+    packusdw            xm4, xm5
+    pminsw              xm4, [rsp+0x50]
+    movq       [dstq+dsq*0], xm4
+    movhps     [dstq+dsq*1], xm4
+    lea                dstq, [dstq+dsq*2]
+%else
+    psrad                m4, 6
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+    mova             [tmpq], xm4
+    add                tmpq, 16
+%endif
+    sub                  hd, 2
+    jg .dy1_w4_loop
+    MC_8TAP_SCALED_RET
+    SWAP                 m10, m13
+.dy1_w8:
+    mov    dword [rsp+0xa0], 1
+    movifprep   tmp_stridem, 16
+    jmp .dy1_w_start
+.dy1_w16:
+    mov    dword [rsp+0xa0], 2
+    movifprep   tmp_stridem, 32
+    jmp .dy1_w_start
+.dy1_w32:
+    mov    dword [rsp+0xa0], 4
+    movifprep   tmp_stridem, 64
+    jmp .dy1_w_start
+.dy1_w64:
+    mov    dword [rsp+0xa0], 8
+    movifprep   tmp_stridem, 128
+    jmp .dy1_w_start
+.dy1_w128:
+    mov    dword [rsp+0xa0], 16
+    movifprep   tmp_stridem, 256
+.dy1_w_start:
+    SWAP                m10, m12, m1
+    SWAP                m11, m7
+    ; m1=mx, m7=pxmax, m10=h_rnd, m11=h_sh, m12=free
+    mov                 myd, mym
+%if isput
+ %define dsm [rsp+0xb8]
+    movifnidn           dsm, dsq
+    mova         [rsp+0xc0], xm7
+%else
+ %if UNIX64
+  %define hm [rsp+0xb8]
+ %endif
+%endif
+    mova         [rsp+0x00], m10
+    mova         [rsp+0x20], m13
+    mova         [rsp+0x40], xm11
+    shr                 t0d, 16
+    sub                srcq, 6
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pmaddwd              m8, [base+rescale_mul2]
+    movd               xm15, t0d
+    mov          [rsp+0xa4], t0d
+    mov          [rsp+0xa8], srcq
+    mov          [rsp+0xb0], r0q ; dstq / tmpq
+%if UNIX64
+    mov                  hm, hd
+%endif
+    shl           dword dxm, 3 ; dx*8
+    vpbroadcastd        m15, xm15
+    paddd                m1, m8 ; mx+dx*[0-7]
+    movq                xm0, r4q
+    pmovsxbw            xm0, xm0
+    mova         [rsp+0x50], xm0
+    jmp .dy1_hloop
+.dy1_hloop_prep:
+    dec    dword [rsp+0xa0]
+    jz .ret
+    add    qword [rsp+0xb0], 16
+    mov                  hd, hm
+    vpbroadcastd         m8, dxm
+    vpbroadcastd         m6, [base+pd_0x3ff]
+    paddd                m1, m8, [rsp+0x60]
+    vpbroadcastd        m15, [rsp+0xa4]
+    pxor                 m9, m9
+    mov                srcq, [rsp+0xa8]
+    mov                 r0q, [rsp+0xb0] ; dstq / tmpq
+    mova                m10, [rsp+0x00]
+    mova               xm11, [rsp+0x40]
+.dy1_hloop:
+    vpbroadcastq        xm2, [base+pq_0x40000000]
+    pand                 m5, m1, m6
+    psrld                m5, 6
+    paddd               m15, m5
+    pcmpeqd              m5, m9
+    vextracti128        xm7, m15, 1
+    movq                 r6, xm15
+    pextrq               r9, xm15, 1
+    movq                r11, xm7
+    pextrq               rX, xm7, 1
+    mov                 r4d, r6d
+    shr                  r6, 32
+    mov                 r7d, r9d
+    shr                  r9, 32
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    mova         [rsp+0x60], m1
+    movq               xm12, [base+subpel_filters+ r4*8]
+    movq               xm13, [base+subpel_filters+ r6*8]
+    movhps             xm12, [base+subpel_filters+ r7*8]
+    movhps             xm13, [base+subpel_filters+ r9*8]
+    movq               xm14, [base+subpel_filters+r10*8]
+    movq               xm15, [base+subpel_filters+r11*8]
+    movhps             xm14, [base+subpel_filters+r13*8]
+    movhps             xm15, [base+subpel_filters+ rX*8]
+    psrld                m1, 10
+    vextracti128        xm7, m1, 1
+    vextracti128        xm6, m5, 1
+    movq                 r6, xm1
+    pextrq              r11, xm1, 1
+    movq                 r9, xm7
+    pextrq               rX, xm7, 1
+    mov                 r4d, r6d
+    shr                  r6, 32
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                 r7d, r9d
+    shr                  r9, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    pshufd              xm4, xm5, q2200
+    pshufd              xm5, xm5, q3311
+    pshufd              xm7, xm6, q2200
+    pshufd              xm6, xm6, q3311
+    pblendvb           xm12, xm2, xm4
+    pblendvb           xm13, xm2, xm5
+    pblendvb           xm14, xm2, xm7
+    pblendvb           xm15, xm2, xm6
+    pmovsxbw            m12, xm12
+    pmovsxbw            m13, xm13
+    pmovsxbw            m14, xm14
+    pmovsxbw            m15, xm15
+    MC_8TAP_SCALED_H 0, 1, 2, 3, 4, 5, 6, 7 ; 0a 1a 0b 1b
+    mova         [rsp+0x80], m0
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 7, 8 ; 2a 3a 2b 3b
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 7, 8, 9 ; 4a 5a 4b 5b
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 7, 8, 9, 0 ; 6a 7a 6b 7b
+    mova                 m0, [rsp+0x80]
+    vbroadcasti128       m7, [base+subpel_s_shuf8]
+    vpbroadcastd         m8, [rsp+0x50]
+    vpbroadcastd         m9, [rsp+0x54]
+    vpbroadcastd        m10, [rsp+0x58]
+    vpbroadcastd        m11, [rsp+0x5c]
+    pshufb               m0, m7     ; 01a 01b
+    pshufb               m1, m7     ; 23a 23b
+    pshufb               m2, m7     ; 45a 45b
+    pshufb               m3, m7     ; 67a 67b
+.dy1_vloop:
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m9
+    pmaddwd              m6, m2, m10
+    pmaddwd              m7, m3, m11
+    paddd                m4, [rsp+0x20]
+    paddd                m6, m7
+    paddd                m4, m5
+    paddd                m4, m6
+%if isput
+    psrad                m4, [rsp+0x48]
+    vextracti128        xm5, m4, 1
+    packusdw            xm4, xm5
+    pminsw              xm4, [rsp+0xc0]
+    mova             [dstq], xm4
+    add                dstq, dsm
+%else
+    psrad                m4, 6
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+    mova             [tmpq], xm4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .dy1_hloop_prep
+    vbroadcasti128       m7, [base+wswap]
+    pshufb               m0, m7
+    pshufb               m1, m7
+    pshufb               m2, m7
+    pshufb               m3, m7
+    movu                xm4, [srcq+ r4*2]
+    movu                xm5, [srcq+ r6*2]
+    movu                xm6, [srcq+ r7*2]
+    movu                xm7, [srcq+ r9*2]
+    vinserti128          m4, [srcq+r10*2], 1
+    vinserti128          m5, [srcq+r11*2], 1
+    vinserti128          m6, [srcq+r13*2], 1
+    vinserti128          m7, [srcq+ rX*2], 1
+    add                srcq, ssq
+    pmaddwd              m4, m12
+    pmaddwd              m5, m13
+    pmaddwd              m6, m14
+    pmaddwd              m7, m15
+    phaddd               m4, m5
+    phaddd               m6, m7
+    phaddd               m4, m6
+    paddd                m4, [rsp+0x00]
+    psrad                m4, [rsp+0x40]
+    pslld                m4, 16
+    pblendw              m0, m1, 0xaa
+    pblendw              m1, m2, 0xaa
+    pblendw              m2, m3, 0xaa
+    pblendw              m3, m4, 0xaa
+    jmp .dy1_vloop
+    SWAP                 m1, m12, m10
+    SWAP                 m7, m11
+.dy2:
+    movzx                wd, word [base+%1_8tap_scaled_avx2_dy2_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%if isput
+.dy2_w2:
+    mov                 myd, mym
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd               xm15, t0d
+    punpckldq            m8, m9, m8
+    paddd               m10, m8 ; mx+dx*[0-1]
+    vpbroadcastd       xm14, [base+pq_0x40000000+2]
+    vpbroadcastd       xm15, xm15
+    pand                xm8, xm10, xm6
+    psrld               xm8, 6
+    paddd              xm15, xm8
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    vbroadcasti128       m5, [base+bdct_lb_q]
+    vbroadcasti128       m6, [base+subpel_s_shuf2]
+    vpbroadcastd       xm15, [base+subpel_filters+r4*8+2]
+    vpbroadcastd        xm4, [base+subpel_filters+r6*8+2]
+    pcmpeqd             xm8, xm9
+    psrld               m10, 10
+    paddd               m10, m10
+    movu                xm0, [srcq+ssq*0]
+    movu                xm1, [srcq+ssq*2]
+    movu                xm2, [srcq+ssq*4]
+    pshufb              m10, m5
+    paddb               m10, m6
+    vpblendd           xm15, xm4, 0xa
+    pblendvb           xm15, xm14, xm8
+    pmovsxbw            m15, xm15
+    vinserti128          m0, [srcq+ssq*1], 1 ; 0 1
+    vinserti128          m1, [srcq+ss3q ], 1 ; 2 3
+    lea                srcq, [srcq+ssq*4]
+    vinserti128          m2, [srcq+ssq*1], 1 ; 4 5
+    lea                srcq, [srcq+ssq*2]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pshufb               m0, m10
+    pshufb               m1, m10
+    pshufb               m2, m10
+    pmaddwd              m0, m15
+    pmaddwd              m1, m15
+    pmaddwd              m2, m15
+    movq                xm6, r4q
+    pmovsxbw            xm6, xm6
+    phaddd               m0, m1
+    phaddd               m1, m2
+    paddd                m0, m12
+    paddd                m1, m12
+    psrad                m0, xm7
+    psrad                m1, xm7
+    packssdw             m0, m1             ; 0 2 2 4  1 3 3 5
+    vextracti128        xm1, m0, 1
+    pshufd              xm8, xm6, q0000
+    pshufd              xm9, xm6, q1111
+    pshufd             xm14, xm6, q2222
+    pshufd              xm6, xm6, q3333
+    punpcklwd           xm2, xm0, xm1       ; 01 23
+    punpckhwd           xm1, xm0, xm1       ; 23 45
+.dy2_w2_loop:
+    movu                xm3, [srcq+ssq*0]
+    movu                xm5, [srcq+ssq*2]
+    vinserti128          m3, [srcq+ssq*1], 1 ; 6 7
+    vinserti128          m5, [srcq+ss3q ], 1 ; 8 9
+    lea                srcq, [srcq+ssq*4]
+    pmaddwd             xm4, xm2, xm8
+    pmaddwd             xm1, xm9
+    pshufb               m3, m10
+    pshufb               m5, m10
+    pmaddwd              m3, m15
+    pmaddwd              m5, m15
+    phaddd               m3, m5
+    paddd               xm4, xm1
+    paddd                m3, m12
+    psrad                m3, xm7
+    packssdw             m3, m3
+    pshufd               m3, m3, q2100
+    palignr              m0, m3, m0, 12     ; 4 6 6 8  5 7 7 9
+    vextracti128        xm1, m0, 1
+    punpcklwd           xm2, xm0, xm1       ; 45 67
+    punpckhwd           xm1, xm0, xm1       ; 67 89
+    pmaddwd             xm3, xm2, xm14
+    pmaddwd             xm5, xm1, xm6
+    paddd               xm4, xm13
+    paddd               xm4, xm3
+    psrldq              xm3, xm7, 8
+    paddd               xm4, xm5
+    psrad               xm4, xm3
+    packusdw            xm4, xm4
+    pminsw              xm4, xm11
+    movd       [dstq+dsq*0], xm4
+    pextrd     [dstq+dsq*1], xm4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .dy2_w2_loop
+    RET
+%endif
+.dy2_w4:
+    mov                 myd, mym
+%if isput
+    mova         [rsp+0x50], xm11
+%endif
+    mova         [rsp+0x00], m12
+    mova         [rsp+0x20], m13
+    mova         [rsp+0x40], xm7
+    vbroadcasti128       m7, [base+rescale_mul]
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd               xm15, t0d
+    pmaddwd              m8, m7
+    vpbroadcastq         m2, [base+pq_0x40000000+1]
+    vpbroadcastd       xm15, xm15
+    SWAP                m13, m10
+    paddd               m13, m8 ; mx+dx*[0-3]
+    pand                 m6, m13
+    psrld                m6, 6
+    paddd              xm15, xm6
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    pextrd             r11d, xm15, 2
+    pextrd             r13d, xm15, 3
+    vbroadcasti128       m5, [base+bdct_lb_q+ 0]
+    vbroadcasti128       m1, [base+bdct_lb_q+16]
+    vbroadcasti128       m4, [base+subpel_s_shuf2]
+    vpbroadcastd       xm14, [base+subpel_filters+r4*8+2]
+    vpbroadcastd        xm7, [base+subpel_filters+r6*8+2]
+    vpbroadcastd       xm15, [base+subpel_filters+r11*8+2]
+    vpbroadcastd        xm8, [base+subpel_filters+r13*8+2]
+    shr                 myd, 6
+    mov                r13d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz             r13q, [base+subpel_filters+myq*8]
+    pcmpeqd              m6, m9
+    punpckldq           m11, m6, m6
+    punpckhdq            m6, m6
+    psrld               m13, 10
+    paddd               m13, m13
+    vpblendd           xm14, xm7, 0xa
+    vpblendd           xm15, xm8, 0xa
+    pmovsxbw            m14, xm14
+    pmovsxbw            m15, xm15
+    movq               xm10, r13q
+    pblendvb            m14, m2, m11
+    pblendvb            m15, m2, m6
+    pextrd               r4, xm13, 2
+    pshufb              m12, m13, m5
+    pshufb              m13, m1
+    lea                  r6, [r4+ssq*1]
+    lea                 r11, [r4+ssq*2]
+    lea                 r13, [r4+ss3q ]
+    movu                xm0, [srcq+ssq*0]
+    movu                xm7, [srcq+r4   ]
+    movu                xm1, [srcq+ssq*1]
+    movu                xm8, [srcq+r6   ]
+    vinserti128          m0, [srcq+ssq*2], 1 ; 0 2
+    vinserti128          m7, [srcq+r11  ], 1
+    vinserti128          m1, [srcq+ss3q ], 1 ; 1 3
+    vinserti128          m8, [srcq+r13  ], 1
+    lea                srcq, [srcq+ssq*4]
+    movu                xm2, [srcq+ssq*0]
+    movu                xm9, [srcq+r4   ]
+    vinserti128          m2, [srcq+ssq*1], 1 ; 4 5
+    vinserti128          m9, [srcq+r6   ], 1
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastb         m5, xm13
+    psubb               m13, m5
+    paddb               m12, m4
+    paddb               m13, m4
+    mova                 m5, [rsp+0x00]
+    movd                xm6, [rsp+0x40]
+    pshufb               m0, m12
+    pshufb               m1, m12
+    pshufb               m2, m12
+    pmaddwd              m0, m14
+    pmaddwd              m1, m14
+    pmaddwd              m2, m14
+    pshufb               m7, m13
+    pshufb               m8, m13
+    pshufb               m9, m13
+    pmaddwd              m7, m15
+    pmaddwd              m8, m15
+    pmaddwd              m9, m15
+    punpcklqdq         xm10, xm10
+    pmovsxbw            m10, xm10
+    phaddd               m0, m7
+    phaddd               m1, m8
+    phaddd               m2, m9
+    paddd                m0, m5
+    paddd                m1, m5
+    paddd                m2, m5
+    psrad                m0, xm6
+    psrad                m1, xm6
+    psrad                m2, xm6
+    vperm2i128           m3, m0, m2, 0x21 ; 2 4
+    vperm2i128           m2, m1, 0x13     ; 3 5
+    pshufd               m7, m10, q0000
+    pshufd               m8, m10, q1111
+    pshufd               m9, m10, q2222
+    pshufd              m10, m10, q3333
+    packssdw             m0, m3 ; 0 2  2 4
+    packssdw             m1, m2 ; 1 3  3 5
+    punpckhwd            m2, m0, m1 ; 23 45
+    punpcklwd            m0, m1     ; 01 23
+.dy2_w4_loop:
+    movu                xm1, [srcq+ssq*0]
+    movu                xm6, [srcq+r4   ]
+    movu                xm3, [srcq+ssq*1]
+    movu               xm11, [srcq+r6   ]
+    vinserti128          m1, [srcq+ssq*2], 1 ; 6 8
+    vinserti128          m6, [srcq+r11  ], 1
+    vinserti128          m3, [srcq+ss3q ], 1 ; 7 9
+    vinserti128         m11, [srcq+r13  ], 1
+    lea                srcq, [srcq+ssq*4]
+    pmaddwd              m4, m0, m7
+    pmaddwd              m5, m2, m8
+    pshufb               m1, m12
+    pshufb               m3, m12
+    pmaddwd              m1, m14
+    pmaddwd              m3, m14
+    mova                 m0, [rsp+0x00]
+    pshufb               m6, m13
+    pshufb              m11, m13
+    pmaddwd              m6, m15
+    pmaddwd             m11, m15
+    paddd                m4, m5
+    movd                xm5, [rsp+0x40]
+    phaddd               m1, m6
+    phaddd               m3, m11
+    paddd                m1, m0
+    paddd                m3, m0
+    psrad                m1, xm5
+    psrad                m3, xm5
+    pslld                m3, 16
+    pblendw              m1, m3, 0xaa     ; 67 89
+    vperm2i128           m0, m2, m1, 0x21 ; 45 67
+    paddd                m4, [rsp+0x20]
+    mova                 m2, m1
+    pmaddwd              m5, m0, m9
+    pmaddwd              m6, m2, m10
+    paddd                m4, m5
+    paddd                m4, m6
+%if isput
+    psrad                m4, [rsp+0x48]
+    vextracti128        xm5, m4, 1
+    packusdw            xm4, xm5
+    pminsw              xm4, [rsp+0x50]
+    movq       [dstq+dsq*0], xm4
+    movhps     [dstq+dsq*1], xm4
+    lea                dstq, [dstq+dsq*2]
+%else
+    psrad                m4, 6
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+    mova             [tmpq], xm4
+    add                tmpq, 16
+%endif
+    sub                  hd, 2
+    jg .dy2_w4_loop
+    MC_8TAP_SCALED_RET
+    SWAP                m10, m13
+.dy2_w8:
+    mov    dword [rsp+0xa0], 1
+    movifprep   tmp_stridem, 16
+    jmp .dy2_w_start
+.dy2_w16:
+    mov    dword [rsp+0xa0], 2
+    movifprep   tmp_stridem, 32
+    jmp .dy2_w_start
+.dy2_w32:
+    mov    dword [rsp+0xa0], 4
+    movifprep   tmp_stridem, 64
+    jmp .dy2_w_start
+.dy2_w64:
+    mov    dword [rsp+0xa0], 8
+    movifprep   tmp_stridem, 128
+    jmp .dy2_w_start
+.dy2_w128:
+    mov    dword [rsp+0xa0], 16
+    movifprep   tmp_stridem, 256
+.dy2_w_start:
+    SWAP                m10, m12, m1
+    SWAP                m11, m7
+    ; m1=mx, m7=pxmax, m10=h_rnd, m11=h_sh, m12=free
+    mov                 myd, mym
+%if isput
+    movifnidn           dsm, dsq
+    mova         [rsp+0xc0], xm7
+%endif
+    mova         [rsp+0x00], m10
+    mova         [rsp+0x20], m13
+    mova         [rsp+0x40], xm11
+    shr                 t0d, 16
+    sub                srcq, 6
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pmaddwd              m8, [base+rescale_mul2]
+    movd               xm15, t0d
+    mov          [rsp+0xa4], t0d
+    mov          [rsp+0xa8], srcq
+    mov          [rsp+0xb0], r0q ; dstq / tmpq
+%if UNIX64
+    mov                  hm, hd
+%endif
+    shl           dword dxm, 3 ; dx*8
+    vpbroadcastd        m15, xm15
+    paddd                m1, m8 ; mx+dx*[0-7]
+    movq                xm0, r4q
+    pmovsxbw            xm0, xm0
+    mova         [rsp+0x50], xm0
+    jmp .dy2_hloop
+.dy2_hloop_prep:
+    dec    dword [rsp+0xa0]
+    jz .ret
+    add    qword [rsp+0xb0], 16
+    mov                  hd, hm
+    vpbroadcastd         m8, dxm
+    vpbroadcastd         m6, [base+pd_0x3ff]
+    paddd                m1, m8, [rsp+0x60]
+    vpbroadcastd        m15, [rsp+0xa4]
+    pxor                 m9, m9
+    mov                srcq, [rsp+0xa8]
+    mov                 r0q, [rsp+0xb0] ; dstq / tmpq
+    mova                m10, [rsp+0x00]
+    mova               xm11, [rsp+0x40]
+.dy2_hloop:
+    vpbroadcastq        xm2, [base+pq_0x40000000]
+    pand                 m5, m1, m6
+    psrld                m5, 6
+    paddd               m15, m5
+    pcmpeqd              m5, m9
+    vextracti128        xm7, m15, 1
+    movq                 r6, xm15
+    pextrq               r9, xm15, 1
+    movq                r11, xm7
+    pextrq               rX, xm7, 1
+    mov                 r4d, r6d
+    shr                  r6, 32
+    mov                 r7d, r9d
+    shr                  r9, 32
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    mova         [rsp+0x60], m1
+    movq               xm12, [base+subpel_filters+ r4*8]
+    movq               xm13, [base+subpel_filters+ r6*8]
+    movhps             xm12, [base+subpel_filters+ r7*8]
+    movhps             xm13, [base+subpel_filters+ r9*8]
+    movq               xm14, [base+subpel_filters+r10*8]
+    movq               xm15, [base+subpel_filters+r11*8]
+    movhps             xm14, [base+subpel_filters+r13*8]
+    movhps             xm15, [base+subpel_filters+ rX*8]
+    psrld                m1, 10
+    vextracti128        xm7, m1, 1
+    vextracti128        xm6, m5, 1
+    movq                 r6, xm1
+    pextrq              r11, xm1, 1
+    movq                 r9, xm7
+    pextrq               rX, xm7, 1
+    mov                 r4d, r6d
+    shr                  r6, 32
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                 r7d, r9d
+    shr                  r9, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    pshufd              xm4, xm5, q2200
+    pshufd              xm5, xm5, q3311
+    pshufd              xm7, xm6, q2200
+    pshufd              xm6, xm6, q3311
+    pblendvb           xm12, xm2, xm4
+    pblendvb           xm13, xm2, xm5
+    pblendvb           xm14, xm2, xm7
+    pblendvb           xm15, xm2, xm6
+    pmovsxbw            m12, xm12
+    pmovsxbw            m13, xm13
+    pmovsxbw            m14, xm14
+    pmovsxbw            m15, xm15
+    MC_8TAP_SCALED_H 0, 1, 2, 3, 4, 5, 6, 7 ; 0a 1a 0b 1b
+    mova         [rsp+0x80], m0
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 7, 8 ; 2a 3a 2b 3b
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 7, 8, 9 ; 4a 5a 4b 5b
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 7, 8, 9, 0 ; 6a 7a 6b 7b
+    mova                 m0, [rsp+0x80]
+    vbroadcasti128       m7, [base+subpel_s_shuf8]
+    vpbroadcastd         m8, [rsp+0x50]
+    vpbroadcastd         m9, [rsp+0x54]
+    vpbroadcastd        m10, [rsp+0x58]
+    vpbroadcastd        m11, [rsp+0x5c]
+    pshufb               m0, m7     ; 01a 01b
+    pshufb               m1, m7     ; 23a 23b
+    pshufb               m2, m7     ; 45a 45b
+    pshufb               m3, m7     ; 67a 67b
+.dy2_vloop:
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m9
+    pmaddwd              m6, m2, m10
+    pmaddwd              m7, m3, m11
+    paddd                m4, [rsp+0x20]
+    paddd                m6, m7
+    paddd                m4, m5
+    paddd                m4, m6
+%if isput
+    psrad                m4, [rsp+0x48]
+    vextracti128        xm5, m4, 1
+    packusdw            xm4, xm5
+    pminsw              xm4, [rsp+0xc0]
+    mova             [dstq], xm4
+    add                dstq, dsm
+%else
+    psrad                m4, 6
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+    mova             [tmpq], xm4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .dy2_hloop_prep
+    mova                 m0, m1
+    mova                 m1, m2
+    mova                 m2, m3
+    movu                xm3, [srcq+ r4*2]
+    movu                xm4, [srcq+ r6*2]
+    movu                xm5, [srcq+ r7*2]
+    movu                xm6, [srcq+ r9*2]
+    vinserti128          m3, [srcq+r10*2], 1
+    vinserti128          m4, [srcq+r11*2], 1
+    vinserti128          m5, [srcq+r13*2], 1
+    vinserti128          m6, [srcq+ rX*2], 1
+    add                srcq, ssq
+    pmaddwd              m3, m12
+    pmaddwd              m4, m13
+    pmaddwd              m5, m14
+    pmaddwd              m6, m15
+    phaddd               m3, m4
+    phaddd               m5, m6
+    phaddd               m3, m5
+    movu                xm4, [srcq+ r4*2]
+    movu                xm5, [srcq+ r6*2]
+    movu                xm6, [srcq+ r7*2]
+    movu                xm7, [srcq+ r9*2]
+    vinserti128          m4, [srcq+r10*2], 1
+    vinserti128          m5, [srcq+r11*2], 1
+    vinserti128          m6, [srcq+r13*2], 1
+    vinserti128          m7, [srcq+ rX*2], 1
+    add                srcq, ssq
+    pmaddwd              m4, m12
+    pmaddwd              m5, m13
+    pmaddwd              m6, m14
+    pmaddwd              m7, m15
+    phaddd               m4, m5
+    phaddd               m6, m7
+    mova                 m5, [rsp+0x00]
+    movd                xm7, [rsp+0x40]
+    phaddd               m4, m6
+    paddd                m3, m5
+    paddd                m4, m5
+    psrad                m3, xm7
+    psrad                m4, xm7
+    pslld                m4, 16
+    pblendw              m3, m4, 0xaa
+    jmp .dy2_vloop
+.ret:
+    MC_8TAP_SCALED_RET 0
+%undef isput
+%undef isprep
+%endmacro
+
+%macro BILIN_SCALED_FN 1
+cglobal %1_bilin_scaled_16bpc
+    mov                 t0d, (5*15 << 16) | 5*15
+    mov                 t1d, t0d
+    jmp mangle(private_prefix %+ _%1_8tap_scaled_16bpc %+ SUFFIX)
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 6, 5
+%else
+DECLARE_REG_TMP 6, 8
+%endif
+
+%define PUT_8TAP_SCALED_FN FN put_8tap_scaled,
+BILIN_SCALED_FN put
+PUT_8TAP_SCALED_FN sharp,          SHARP,   SHARP,   put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN sharp_smooth,   SHARP,   SMOOTH,  put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN smooth,         SMOOTH,  SMOOTH,  put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN sharp_regular,  SHARP,   REGULAR, put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN regular_sharp,  REGULAR, SHARP,   put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN smooth_regular, SMOOTH,  REGULAR, put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN regular_smooth, REGULAR, SMOOTH,  put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN regular,        REGULAR, REGULAR
+MC_8TAP_SCALED put
+
+%if WIN64
+DECLARE_REG_TMP 5, 4
+%else
+DECLARE_REG_TMP 6, 7
+%endif
+
+%define PREP_8TAP_SCALED_FN FN prep_8tap_scaled,
+BILIN_SCALED_FN prep
+PREP_8TAP_SCALED_FN sharp,          SHARP,   SHARP,   prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN smooth,         SMOOTH,  SMOOTH,  prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN smooth_regular, SMOOTH,  REGULAR, prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN regular_smooth, REGULAR, SMOOTH,  prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN regular,        REGULAR, REGULAR
+MC_8TAP_SCALED prep
+
+%macro WARP_V 5 ; dst, 01, 23, 45, 67
+    lea               tmp1d, [myq+deltaq*4]
+    lea               tmp2d, [myq+deltaq*1]
+    shr                 myd, 10
+    shr               tmp1d, 10
+    movq                xm8, [filterq+myq  *8]
+    vinserti128          m8, [filterq+tmp1q*8], 1 ; a e
+    lea               tmp1d, [tmp2q+deltaq*4]
+    lea                 myd, [tmp2q+deltaq*1]
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    movq                xm0, [filterq+tmp2q*8]
+    vinserti128          m0, [filterq+tmp1q*8], 1 ; b f
+    lea               tmp1d, [myq+deltaq*4]
+    lea               tmp2d, [myq+deltaq*1]
+    shr                 myd, 10
+    shr               tmp1d, 10
+    movq                xm9, [filterq+myq  *8]
+    vinserti128          m9, [filterq+tmp1q*8], 1 ; c g
+    lea               tmp1d, [tmp2q+deltaq*4]
+    lea                 myd, [tmp2q+gammaq]       ; my += gamma
+    punpcklwd            m8, m0
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    movq                xm0, [filterq+tmp2q*8]
+    vinserti128          m0, [filterq+tmp1q*8], 1 ; d h
+    punpcklwd            m0, m9, m0
+    punpckldq            m9, m8, m0
+    punpckhdq            m0, m8, m0
+    punpcklbw            m8, m11, m9 ; a0 a1 b0 b1 c0 c1 d0 d1 << 8
+    punpckhbw            m9, m11, m9 ; a2 a3 b2 b3 c2 c3 d2 d3 << 8
+    pmaddwd             m%2, m8
+    pmaddwd              m9, m%3
+    punpcklbw            m8, m11, m0 ; a4 a5 b4 b5 c4 c5 d4 d5 << 8
+    punpckhbw            m0, m11, m0 ; a6 a7 b6 b7 c6 c7 d6 d7 << 8
+    pmaddwd              m8, m%4
+    pmaddwd              m0, m%5
+    paddd                m9, m%2
+    mova                m%2, m%3
+    paddd                m0, m8
+    mova                m%3, m%4
+    mova                m%4, m%5
+    paddd               m%1, m0, m9
+%endmacro
+
+cglobal warp_affine_8x8t_16bpc, 4, 14, 16, tmp, ts
+    mov                 r6d, r7m
+    lea                  r9, [$$]
+    shr                 r6d, 11
+    vpbroadcastd        m13, [r9-$$+warp8x8_shift+r6*4]
+    vpbroadcastd        m14, [warp8x8t_rnd]
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_avx2).main
+    jmp .start
+.loop:
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_avx2).main2
+    lea                tmpq, [tmpq+tsq*4]
+.start:
+    paddd                m7, m14
+    paddd                m0, m14
+    psrad                m7, 15
+    psrad                m0, 15
+    packssdw             m7, m0
+    vpermq               m7, m7, q3120
+    mova         [tmpq+tsq*0], xm7
+    vextracti128 [tmpq+tsq*2], m7, 1
+    dec                 r4d
+    jg .loop
+.end:
+    RET
+
+cglobal warp_affine_8x8_16bpc, 4, 14, 16, dst, ds, src, ss, abcd, mx, tmp2, \
+                                          alpha, beta, filter, tmp1, delta, \
+                                          my, gamma
+    mov                 r6d, r7m
+    lea             filterq, [$$]
+    shr                 r6d, 11
+    vpbroadcastd        m13, [filterq-$$+warp8x8_shift+r6*4]
+    vpbroadcastd        m14, [filterq-$$+warp8x8_rnd  +r6*4]
+    vpbroadcastw        m15, r7m ; pixel_max
+    call .main
+    jmp .start
+.loop:
+    call .main2
+    lea                dstq, [dstq+dsq*2]
+.start:
+    psrad                m7, 16
+    psrad                m0, 16
+    packusdw             m7, m0
+    pmulhrsw             m7, m14
+    pminsw               m7, m15
+    vpermq               m7, m7, q3120
+    mova         [dstq+dsq*0], xm7
+    vextracti128 [dstq+dsq*1], m7, 1
+    dec                 r4d
+    jg .loop
+.end:
+    RET
+ALIGN function_align
+.main:
+    ; Stack args offset by one (r4m -> r5m etc.) due to call
+%if WIN64
+    mov               abcdq, r5m
+    mov                 mxd, r6m
+%endif
+    movsx            alphad, word [abcdq+2*0]
+    movsx             betad, word [abcdq+2*1]
+    vpbroadcastd        m12, [pd_32768]
+    pxor                m11, m11
+    add             filterq, mc_warp_filter-$$
+    lea               tmp1q, [ssq*3]
+    add                 mxd, 512+(64<<10)
+    lea               tmp2d, [alphaq*3]
+    sub                srcq, tmp1q    ; src -= src_stride*3
+    sub               betad, tmp2d    ; beta -= alpha*3
+    mov                 myd, r7m
+    call .h
+    psrld                m1, m0, 16
+    call .h
+    pblendw              m1, m0, 0xaa ; 01
+    psrld                m2, m0, 16
+    call .h
+    pblendw              m2, m0, 0xaa ; 12
+    psrld                m3, m0, 16
+    call .h
+    pblendw              m3, m0, 0xaa ; 23
+    psrld                m4, m0, 16
+    call .h
+    pblendw              m4, m0, 0xaa ; 34
+    psrld                m5, m0, 16
+    call .h
+    pblendw              m5, m0, 0xaa ; 45
+    psrld                m6, m0, 16
+    call .h
+    pblendw              m6, m0, 0xaa ; 56
+    movsx            deltad, word [abcdq+2*2]
+    movsx            gammad, word [abcdq+2*3]
+    add                 myd, 512+(64<<10)
+    mov                 r4d, 4
+    lea               tmp1d, [deltaq*3]
+    sub              gammad, tmp1d    ; gamma -= delta*3
+.main2:
+    call .h
+    psrld                m7, m6, 16
+    pblendw              m7, m0, 0xaa ; 67
+    WARP_V                7, 1, 3, 5, 7
+    call .h
+    psrld               m10, m5, 16
+    pblendw             m10, m0, 0xaa ; 78
+    WARP_V                0, 2, 4, 6, 10
+    ret
+ALIGN function_align
+.h:
+    lea               tmp1d, [mxq+alphaq*4]
+    lea               tmp2d, [mxq+alphaq*1]
+    movu               xm10, [srcq-6]
+    vinserti128         m10, [srcq+2], 1
+    shr                 mxd, 10 ; 0
+    shr               tmp1d, 10 ; 4
+    movq                xm0, [filterq+mxq  *8]
+    vinserti128          m0, [filterq+tmp1q*8], 1
+    lea               tmp1d, [tmp2q+alphaq*4]
+    lea                 mxd, [tmp2q+alphaq*1]
+    movu                xm8, [srcq-4]
+    vinserti128          m8, [srcq+4], 1
+    shr               tmp2d, 10 ; 1
+    shr               tmp1d, 10 ; 5
+    movq                xm9, [filterq+tmp2q*8]
+    vinserti128          m9, [filterq+tmp1q*8], 1
+    lea               tmp1d, [mxq+alphaq*4]
+    lea               tmp2d, [mxq+alphaq*1]
+    shr                 mxd, 10 ; 2
+    shr               tmp1d, 10 ; 6
+    punpcklbw            m0, m11, m0
+    pmaddwd              m0, m10
+    movu               xm10, [srcq-2]
+    vinserti128         m10, [srcq+6], 1
+    punpcklbw            m9, m11, m9
+    pmaddwd              m9, m8
+    movq                xm8, [filterq+mxq  *8]
+    vinserti128          m8, [filterq+tmp1q*8], 1
+    lea               tmp1d, [tmp2q+alphaq*4]
+    lea                 mxd, [tmp2q+betaq] ; mx += beta
+    phaddd               m0, m9 ; 0 1   4 5
+    movu                xm9, [srcq+0]
+    vinserti128          m9, [srcq+8], 1
+    shr               tmp2d, 10 ; 3
+    shr               tmp1d, 10 ; 7
+    punpcklbw            m8, m11, m8
+    pmaddwd              m8, m10
+    movq               xm10, [filterq+tmp2q*8]
+    vinserti128         m10, [filterq+tmp1q*8], 1
+    punpcklbw           m10, m11, m10
+    pmaddwd              m9, m10
+    add                srcq, ssq
+    phaddd               m8, m9 ; 2 3   6 7
+    phaddd               m0, m8 ; 0 1 2 3   4 5 6 7
+    vpsllvd              m0, m13
+    paddd                m0, m12 ; rounded 14-bit result in upper 16 bits of dword
+    ret
+
+%macro BIDIR_FN 0
+    call .main
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    movq   [dstq          ], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti128        xm0, m0, 1
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    cmp                  hd, 4
+    je .ret
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq          ], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti128        xm1, m1, 1
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+    cmp                  hd, 8
+    je .ret
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq          ], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti128        xm2, m2, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq          ], xm3
+    movhps [dstq+strideq*1], xm3
+    vextracti128        xm3, m3, 1
+    movq   [dstq+strideq*2], xm3
+    movhps [dstq+stride3q ], xm3
+.ret:
+    RET
+.w8:
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova         [dstq+strideq*2], xm1
+    vextracti128 [dstq+stride3q ], m1, 1
+    cmp                  hd, 4
+    jne .w8_loop_start
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova         [dstq+strideq*2], xm1
+    vextracti128 [dstq+stride3q ], m1, 1
+.w8_loop_start:
+    lea                dstq, [dstq+strideq*4]
+    mova         [dstq+strideq*0], xm2
+    vextracti128 [dstq+strideq*1], m2, 1
+    mova         [dstq+strideq*2], xm3
+    vextracti128 [dstq+stride3q ], m3, 1
+    sub                  hd, 8
+    jg .w8_loop
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+stride3q ], m3
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w32:
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*1+32*0], m2
+    mova [dstq+strideq*1+32*1], m3
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    mova        [dstq+32*2], m2
+    mova        [dstq+32*3], m3
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    mova        [dstq+32*2], m2
+    mova        [dstq+32*3], m3
+    call .main
+    mova        [dstq+32*4], m0
+    mova        [dstq+32*5], m1
+    mova        [dstq+32*6], m2
+    mova        [dstq+32*7], m3
+    dec                  hd
+    jg .w128_loop
+    RET
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 5
+%else
+DECLARE_REG_TMP 7
+%endif
+
+cglobal avg_16bpc, 4, 7, 6, dst, stride, tmp1, tmp2, w, h, stride3
+%define base r6-avg_avx2_table
+    lea                  r6, [avg_avx2_table]
+    tzcnt                wd, wm
+    mov                 t0d, r6m ; pixel_max
+    movsxd               wq, [r6+wq*4]
+    shr                 t0d, 11
+    vpbroadcastd         m4, [base+bidir_rnd+t0*4]
+    vpbroadcastd         m5, [base+bidir_mul+t0*4]
+    movifnidn            hd, hm
+    add                  wq, r6
+    BIDIR_FN
+ALIGN function_align
+.main:
+    mova                 m0, [tmp1q+32*0]
+    paddsw               m0, [tmp2q+32*0]
+    mova                 m1, [tmp1q+32*1]
+    paddsw               m1, [tmp2q+32*1]
+    mova                 m2, [tmp1q+32*2]
+    paddsw               m2, [tmp2q+32*2]
+    mova                 m3, [tmp1q+32*3]
+    paddsw               m3, [tmp2q+32*3]
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    pmaxsw               m0, m4
+    pmaxsw               m1, m4
+    pmaxsw               m2, m4
+    pmaxsw               m3, m4
+    psubsw               m0, m4
+    psubsw               m1, m4
+    psubsw               m2, m4
+    psubsw               m3, m4
+    pmulhw               m0, m5
+    pmulhw               m1, m5
+    pmulhw               m2, m5
+    pmulhw               m3, m5
+    ret
+
+cglobal w_avg_16bpc, 4, 7, 9, dst, stride, tmp1, tmp2, w, h, stride3
+    lea                  r6, [w_avg_avx2_table]
+    tzcnt                wd, wm
+    mov                 t0d, r6m ; weight
+    vpbroadcastw         m8, r7m ; pixel_max
+    vpbroadcastd         m7, [r6-w_avg_avx2_table+pd_65538]
+    movsxd               wq, [r6+wq*4]
+    paddw                m7, m8
+    add                  wq, r6
+    lea                 r6d, [t0-16]
+    shl                 t0d, 16
+    sub                 t0d, r6d ; 16-weight, weight
+    pslld                m7, 7
+    rorx                r6d, t0d, 30 ; << 2
+    test          dword r7m, 0x800
+    cmovz               r6d, t0d
+    movifnidn            hd, hm
+    movd                xm6, r6d
+    vpbroadcastd         m6, xm6
+    BIDIR_FN
+ALIGN function_align
+.main:
+    mova                 m4, [tmp1q+32*0]
+    mova                 m0, [tmp2q+32*0]
+    punpckhwd            m5, m0, m4
+    punpcklwd            m0, m4
+    mova                 m4, [tmp1q+32*1]
+    mova                 m1, [tmp2q+32*1]
+    pmaddwd              m5, m6
+    pmaddwd              m0, m6
+    paddd                m5, m7
+    paddd                m0, m7
+    psrad                m5, 8
+    psrad                m0, 8
+    packusdw             m0, m5
+    punpckhwd            m5, m1, m4
+    punpcklwd            m1, m4
+    mova                 m4, [tmp1q+32*2]
+    mova                 m2, [tmp2q+32*2]
+    pmaddwd              m5, m6
+    pmaddwd              m1, m6
+    paddd                m5, m7
+    paddd                m1, m7
+    psrad                m5, 8
+    psrad                m1, 8
+    packusdw             m1, m5
+    punpckhwd            m5, m2, m4
+    punpcklwd            m2, m4
+    mova                 m4, [tmp1q+32*3]
+    mova                 m3, [tmp2q+32*3]
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    pmaddwd              m5, m6
+    pmaddwd              m2, m6
+    paddd                m5, m7
+    paddd                m2, m7
+    psrad                m5, 8
+    psrad                m2, 8
+    packusdw             m2, m5
+    punpckhwd            m5, m3, m4
+    punpcklwd            m3, m4
+    pmaddwd              m5, m6
+    pmaddwd              m3, m6
+    paddd                m5, m7
+    paddd                m3, m7
+    psrad                m5, 8
+    psrad                m3, 8
+    packusdw             m3, m5
+    pminsw               m0, m8
+    pminsw               m1, m8
+    pminsw               m2, m8
+    pminsw               m3, m8
+    ret
+
+cglobal mask_16bpc, 4, 8, 11, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-mask_avx2_table
+    lea                  r7, [mask_avx2_table]
+    tzcnt                wd, wm
+    mov                 r6d, r7m ; pixel_max
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd         m8, [base+pw_64]
+    vpbroadcastd         m9, [base+bidir_rnd+r6*4]
+    vpbroadcastd        m10, [base+bidir_mul+r6*4]
+    mov               maskq, maskmp
+    add                  wq, r7
+    BIDIR_FN
+ALIGN function_align
+.main:
+%macro MASK 1
+    pmovzxbw             m5, [maskq+16*%1]
+    mova                m%1, [tmp1q+32*%1]
+    mova                 m6, [tmp2q+32*%1]
+    punpckhwd            m4, m%1, m6
+    punpcklwd           m%1, m6
+    psubw                m7, m8, m5
+    punpckhwd            m6, m5, m7 ; m, 64-m
+    punpcklwd            m5, m7
+    pmaddwd              m4, m6     ; tmp1 * m + tmp2 * (64-m)
+    pmaddwd             m%1, m5
+    psrad                m4, 5
+    psrad               m%1, 5
+    packssdw            m%1, m4
+    pmaxsw              m%1, m9
+    psubsw              m%1, m9
+    pmulhw              m%1, m10
+%endmacro
+    MASK                  0
+    MASK                  1
+    MASK                  2
+    MASK                  3
+    add               maskq, 16*4
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    ret
+
+cglobal w_mask_420_16bpc, 4, 8, 16, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_420_avx2_table
+    lea                  r7, [w_mask_420_avx2_table]
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    movd                xm0, r7m ; sign
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd        m10, [base+pw_27615] ; ((64 - 38) << 10) + 1023 - 32
+    vpbroadcastd        m11, [base+pw_64]
+    vpbroadcastd        m12, [base+bidir_rnd+r6*4]
+    vpbroadcastd        m13, [base+bidir_mul+r6*4]
+    movd               xm14, [base+pw_2]
+    mov               maskq, maskmp
+    psubw              xm14, xm0
+    vpbroadcastw        m14, xm14
+    add                  wq, r7
+    call .main
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    phaddd               m4, m5
+    paddw                m4, m14
+    psrlw                m4, 2
+    packuswb             m4, m4
+    vextracti128        xm5, m4, 1
+    punpcklwd           xm4, xm5
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti128        xm0, m0, 1
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    mova            [maskq], xm4
+    cmp                  hd, 8
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti128        xm1, m1, 1
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+    je .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti128        xm2, m2, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm3
+    movhps [dstq+strideq*1], xm3
+    vextracti128        xm3, m3, 1
+    movq   [dstq+strideq*2], xm3
+    movhps [dstq+stride3q ], xm3
+.w4_end:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 16
+.w8:
+    vperm2i128           m6, m4, m5, 0x21
+    vpblendd             m4, m5, 0xf0
+    paddw                m4, m14
+    paddw                m4, m6
+    psrlw                m4, 2
+    vextracti128        xm5, m4, 1
+    packuswb            xm4, xm5
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova         [dstq+strideq*2], xm1
+    vextracti128 [dstq+stride3q ], m1, 1
+    mova            [maskq], xm4
+    sub                  hd, 8
+    jl .w8_end
+    lea                dstq, [dstq+strideq*4]
+    mova         [dstq+strideq*0], xm2
+    vextracti128 [dstq+strideq*1], m2, 1
+    mova         [dstq+strideq*2], xm3
+    vextracti128 [dstq+stride3q ], m3, 1
+    jg .w8_loop
+.w8_end:
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 16
+.w16:
+    punpcklqdq           m6, m4, m5
+    punpckhqdq           m4, m5
+    paddw                m6, m14
+    paddw                m4, m6
+    psrlw                m4, 2
+    vextracti128        xm5, m4, 1
+    packuswb            xm4, xm5
+    pshufd              xm4, xm4, q3120
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+stride3q ], m3
+    mova            [maskq], xm4
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 32
+.w32:
+    paddw                m4, m14
+    paddw                m4, m5
+    psrlw               m15, m4, 2
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*1+32*0], m2
+    mova [dstq+strideq*1+32*1], m3
+    call .main
+    mova                 m6, [deint_shuf]
+    paddw                m4, m14
+    paddw                m4, m5
+    psrlw                m4, 2
+    packuswb            m15, m4
+    vpermd               m4, m6, m15
+    mova [dstq+strideq*2+32*0], m0
+    mova [dstq+strideq*2+32*1], m1
+    mova [dstq+stride3q +32*0], m2
+    mova [dstq+stride3q +32*1], m3
+    mova            [maskq], m4
+    sub                  hd, 4
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 32
+.w64:
+    paddw                m4, m14
+    paddw               m15, m14, m5
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*0+32*2], m2
+    mova [dstq+strideq*0+32*3], m3
+    mova            [maskq], m4 ; no available registers
+    call .main
+    paddw                m4, [maskq]
+    mova                 m6, [deint_shuf]
+    paddw                m5, m15
+    psrlw                m4, 2
+    psrlw                m5, 2
+    packuswb             m4, m5 ; 0 2 4 6   1 3 5 7
+    vpermd               m4, m6, m4
+    mova [dstq+strideq*1+32*0], m0
+    mova [dstq+strideq*1+32*1], m1
+    mova [dstq+strideq*1+32*2], m2
+    mova [dstq+strideq*1+32*3], m3
+    mova            [maskq], m4
+    sub                  hd, 2
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 64
+.w128:
+    paddw                m4, m14
+    paddw                m5, m14
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*0+32*2], m2
+    mova [dstq+strideq*0+32*3], m3
+    mova       [maskq+32*0], m4
+    mova     [dstq+strideq], m5
+    call .main
+    paddw                m4, m14
+    paddw               m15, m14, m5
+    mova [dstq+strideq*0+32*4], m0
+    mova [dstq+strideq*0+32*5], m1
+    mova [dstq+strideq*0+32*6], m2
+    mova [dstq+strideq*0+32*7], m3
+    mova       [maskq+32*1], m4
+    call .main
+    paddw                m4, [maskq+32*0]
+    paddw                m5, [dstq+strideq]
+    mova                 m6, [deint_shuf]
+    psrlw                m4, 2
+    psrlw                m5, 2
+    packuswb             m4, m5
+    vpermd               m4, m6, m4
+    mova [dstq+strideq*1+32*0], m0
+    mova [dstq+strideq*1+32*1], m1
+    mova [dstq+strideq*1+32*2], m2
+    mova [dstq+strideq*1+32*3], m3
+    mova       [maskq+32*0], m4
+    call .main
+    paddw                m4, [maskq+32*1]
+    mova                 m6, [deint_shuf]
+    paddw                m5, m15
+    psrlw                m4, 2
+    psrlw                m5, 2
+    packuswb             m4, m5
+    vpermd               m4, m6, m4
+    mova [dstq+strideq*1+32*4], m0
+    mova [dstq+strideq*1+32*5], m1
+    mova [dstq+strideq*1+32*6], m2
+    mova [dstq+strideq*1+32*7], m3
+    mova       [maskq+32*1], m4
+    sub                  hd, 2
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+%macro W_MASK 2-6 11, 12, 13 ; dst/src1, mask/src2, pw_64, rnd, mul
+    mova                m%1, [tmp1q+32*%1]
+    mova                m%2, [tmp2q+32*%1]
+    punpcklwd            m8, m%2, m%1
+    punpckhwd            m9, m%2, m%1
+    psubsw              m%1, m%2
+    pabsw               m%1, m%1
+    psubusw              m7, m10, m%1
+    psrlw                m7, 10       ; 64-m
+    psubw               m%2, m%3, m7  ; m
+    punpcklwd           m%1, m7, m%2
+    punpckhwd            m7, m%2
+    pmaddwd             m%1, m8
+    pmaddwd              m7, m9
+    psrad               m%1, 5
+    psrad                m7, 5
+    packssdw            m%1, m7
+    pmaxsw              m%1, m%4
+    psubsw              m%1, m%4
+    pmulhw              m%1, m%5
+%endmacro
+    W_MASK                0, 4
+    W_MASK                1, 5
+    phaddw               m4, m5
+    W_MASK                2, 5
+    W_MASK                3, 6
+    phaddw               m5, m6
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    ret
+
+cglobal w_mask_422_16bpc, 4, 8, 16, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_422_avx2_table
+    lea                  r7, [w_mask_422_avx2_table]
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    vpbroadcastb        m14, r7m ; sign
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd        m10, [base+pw_27615]
+    vpbroadcastd        m11, [base+pw_64]
+    vpbroadcastd        m12, [base+bidir_rnd+r6*4]
+    vpbroadcastd        m13, [base+bidir_mul+r6*4]
+    mova                m15, [base+deint_shuf]
+    mov               maskq, maskmp
+    add                  wq, r7
+    call .main
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti128        xm0, m0, 1
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    cmp                  hd, 8
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti128        xm1, m1, 1
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+    je .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti128        xm2, m2, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm3
+    movhps [dstq+strideq*1], xm3
+    vextracti128        xm3, m3, 1
+    movq   [dstq+strideq*2], xm3
+    movhps [dstq+stride3q ], xm3
+.w4_end:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w8:
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova         [dstq+strideq*2], xm1
+    vextracti128 [dstq+stride3q ], m1, 1
+    sub                  hd, 8
+    jl .w8_end
+    lea                dstq, [dstq+strideq*4]
+    mova         [dstq+strideq*0], xm2
+    vextracti128 [dstq+strideq*1], m2, 1
+    mova         [dstq+strideq*2], xm3
+    vextracti128 [dstq+stride3q ], m3, 1
+    jg .w8_loop
+.w8_end:
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    mova   [dstq+strideq*2], m2
+    mova   [dstq+stride3q ], m3
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w32:
+    mova [dstq+strideq*0+32*0], m0
+    mova [dstq+strideq*0+32*1], m1
+    mova [dstq+strideq*1+32*0], m2
+    mova [dstq+strideq*1+32*1], m3
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    mova        [dstq+32*2], m2
+    mova        [dstq+32*3], m3
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    mova        [dstq+32*2], m2
+    mova        [dstq+32*3], m3
+    call .main
+    mova        [dstq+32*4], m0
+    mova        [dstq+32*5], m1
+    mova        [dstq+32*6], m2
+    mova        [dstq+32*7], m3
+    dec                  hd
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+    W_MASK                0, 4
+    W_MASK                1, 5
+    phaddw               m4, m5
+    W_MASK                2, 5
+    W_MASK                3, 6
+    phaddw               m5, m6
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    packuswb             m4, m5
+    pxor                 m5, m5
+    psubb                m4, m14
+    pavgb                m4, m5
+    vpermd               m4, m15, m4
+    mova            [maskq], m4
+    add               maskq, 32
+    ret
+
+cglobal w_mask_444_16bpc, 4, 8, 11, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_444_avx2_table
+    lea                  r7, [w_mask_444_avx2_table]
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd        m10, [base+pw_27615]
+    vpbroadcastd         m4, [base+pw_64]
+    vpbroadcastd         m5, [base+bidir_rnd+r6*4]
+    vpbroadcastd         m6, [base+bidir_mul+r6*4]
+    mov               maskq, maskmp
+    add                  wq, r7
+    call .main
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti128        xm0, m0, 1
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    cmp                  hd, 8
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti128        xm1, m1, 1
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+    je .w4_end
+    call .main
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti128        xm0, m0, 1
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti128        xm1, m1, 1
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+.w4_end:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w8:
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova         [dstq+strideq*2], xm1
+    vextracti128 [dstq+stride3q ], m1, 1
+    sub                  hd, 4
+    jg .w8_loop
+.w8_end:
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w16:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    add                dstq, strideq
+.w32:
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    dec                  hd
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    call .main
+    mova        [dstq+32*2], m0
+    mova        [dstq+32*3], m1
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    call .main
+    mova        [dstq+32*2], m0
+    mova        [dstq+32*3], m1
+    call .main
+    mova        [dstq+32*4], m0
+    mova        [dstq+32*5], m1
+    call .main
+    mova        [dstq+32*6], m0
+    mova        [dstq+32*7], m1
+    dec                  hd
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+    W_MASK                0, 2, 4, 5, 6
+    W_MASK                1, 3, 4, 5, 6
+    packuswb             m2, m3
+    vpermq               m2, m2, q3120
+    add               tmp1q, 32*2
+    add               tmp2q, 32*2
+    mova            [maskq], m2
+    add               maskq, 32
+    ret
+
+; (a * (64 - m) + b * m + 32) >> 6
+; = (((b - a) * m + 32) >> 6) + a
+; = (((b - a) * (m << 9) + 16384) >> 15) + a
+;   except m << 9 overflows int16_t when m == 64 (which is possible),
+;   but if we negate m it works out (-64 << 9 == -32768).
+; = (((a - b) * (m * -512) + 16384) >> 15) + a
+cglobal blend_16bpc, 3, 7, 7, dst, ds, tmp, w, h, mask
+%define base r6-blend_avx2_table
+    lea                  r6, [blend_avx2_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r6+wq*4]
+    movifnidn         maskq, maskmp
+    vpbroadcastd         m6, [base+pw_m512]
+    add                  wq, r6
+    lea                  r6, [dsq*3]
+    jmp                  wq
+.w4:
+    pmovzxbw             m3, [maskq]
+    movq                xm0, [dstq+dsq*0]
+    movhps              xm0, [dstq+dsq*1]
+    vpbroadcastq         m1, [dstq+dsq*2]
+    vpbroadcastq         m2, [dstq+r6   ]
+    vpblendd             m0, m1, 0x30
+    vpblendd             m0, m2, 0xc0
+    psubw                m1, m0, [tmpq]
+    add               maskq, 16
+    add                tmpq, 32
+    pmullw               m3, m6
+    pmulhrsw             m1, m3
+    paddw                m0, m1
+    vextracti128        xm1, m0, 1
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    movq       [dstq+dsq*2], xm1
+    movhps     [dstq+r6   ], xm1
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    pmovzxbw             m4, [maskq+16*0]
+    pmovzxbw             m5, [maskq+16*1]
+    mova                xm0, [dstq+dsq*0]
+    vinserti128          m0, [dstq+dsq*1], 1
+    mova                xm1, [dstq+dsq*2]
+    vinserti128          m1, [dstq+r6   ], 1
+    psubw                m2, m0, [tmpq+32*0]
+    psubw                m3, m1, [tmpq+32*1]
+    add               maskq, 16*2
+    add                tmpq, 32*2
+    pmullw               m4, m6
+    pmullw               m5, m6
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    mova         [dstq+dsq*2], xm1
+    vextracti128 [dstq+r6   ], m1, 1
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    pmovzxbw             m4, [maskq+16*0]
+    pmovzxbw             m5, [maskq+16*1]
+    mova                 m0,     [dstq+dsq*0]
+    psubw                m2, m0, [tmpq+ 32*0]
+    mova                 m1,     [dstq+dsq*1]
+    psubw                m3, m1, [tmpq+ 32*1]
+    add               maskq, 16*2
+    add                tmpq, 32*2
+    pmullw               m4, m6
+    pmullw               m5, m6
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w16
+    RET
+.w32:
+    pmovzxbw             m4, [maskq+16*0]
+    pmovzxbw             m5, [maskq+16*1]
+    mova                 m0,     [dstq+32*0]
+    psubw                m2, m0, [tmpq+32*0]
+    mova                 m1,     [dstq+32*1]
+    psubw                m3, m1, [tmpq+32*1]
+    add               maskq, 16*2
+    add                tmpq, 32*2
+    pmullw               m4, m6
+    pmullw               m5, m6
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    add                dstq, dsq
+    dec                  hd
+    jg .w32
+    RET
+
+INIT_XMM avx2
+cglobal blend_v_16bpc, 3, 6, 6, dst, ds, tmp, w, h
+%define base r5-blend_v_avx2_table
+    lea                  r5, [blend_v_avx2_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  wq
+.w2:
+    vpbroadcastd         m2, [base+obmc_masks_avx2+2*2]
+.w2_loop:
+    movd                 m0, [dstq+dsq*0]
+    pinsrd               m0, [dstq+dsq*1], 1
+    movq                 m1, [tmpq]
+    add                tmpq, 4*2
+    psubw                m1, m0, m1
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    movd       [dstq+dsq*0], m0
+    pextrd     [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w2_loop
+    RET
+.w4:
+    vpbroadcastq         m2, [base+obmc_masks_avx2+4*2]
+.w4_loop:
+    movq                 m0, [dstq+dsq*0]
+    movhps               m0, [dstq+dsq*1]
+    psubw                m1, m0, [tmpq]
+    add                tmpq, 8*2
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+INIT_YMM avx2
+.w8:
+    vbroadcasti128       m2, [base+obmc_masks_avx2+8*2]
+.w8_loop:
+    mova                xm0, [dstq+dsq*0]
+    vinserti128          m0, [dstq+dsq*1], 1
+    psubw                m1, m0, [tmpq]
+    add                tmpq, 16*2
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16:
+    mova                 m4, [base+obmc_masks_avx2+16*2]
+.w16_loop:
+    mova                 m0,     [dstq+dsq*0]
+    psubw                m2, m0, [tmpq+ 32*0]
+    mova                 m1,     [dstq+dsq*1]
+    psubw                m3, m1, [tmpq+ 32*1]
+    add                tmpq, 32*2
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32:
+%if WIN64
+    movaps         [rsp+ 8], xmm6
+    movaps         [rsp+24], xmm7
+%endif
+    mova                 m6, [base+obmc_masks_avx2+32*2]
+    vbroadcasti128       m7, [base+obmc_masks_avx2+32*3]
+.w32_loop:
+    mova                 m0,     [dstq+dsq*0+32*0]
+    psubw                m3, m0, [tmpq      +32*0]
+    mova                xm2,     [dstq+dsq*0+32*1]
+    mova                xm5,     [tmpq      +32*1]
+    mova                 m1,     [dstq+dsq*1+32*0]
+    psubw                m4, m1, [tmpq      +32*2]
+    vinserti128          m2,     [dstq+dsq*1+32*1], 1
+    vinserti128          m5,     [tmpq      +32*3], 1
+    add                tmpq, 32*4
+    psubw                m5, m2, m5
+    pmulhrsw             m3, m6
+    pmulhrsw             m4, m6
+    pmulhrsw             m5, m7
+    paddw                m0, m3
+    paddw                m1, m4
+    paddw                m2, m5
+    mova         [dstq+dsq*0+32*0], m0
+    mova         [dstq+dsq*1+32*0], m1
+    mova         [dstq+dsq*0+32*1], xm2
+    vextracti128 [dstq+dsq*1+32*1], m2, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w32_loop
+%if WIN64
+    movaps             xmm6, [rsp+ 8]
+    movaps             xmm7, [rsp+24]
+%endif
+    RET
+
+%macro BLEND_H_ROW 2-3 0; dst_off, tmp_off, inc_tmp
+    mova                 m0,     [dstq+32*(%1+0)]
+    psubw                m2, m0, [tmpq+32*(%2+0)]
+    mova                 m1,     [dstq+32*(%1+1)]
+    psubw                m3, m1, [tmpq+32*(%2+1)]
+%if %3
+    add                tmpq, 32*%3
+%endif
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    mova   [dstq+32*(%1+0)], m0
+    mova   [dstq+32*(%1+1)], m1
+%endmacro
+
+INIT_XMM avx2
+cglobal blend_h_16bpc, 3, 6, 6, dst, ds, tmp, w, h, mask
+%define base r5-blend_h_avx2_table
+    lea                  r5, [blend_h_avx2_table]
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    lea               maskq, [base+obmc_masks_avx2+hq*2]
+    lea                  hd, [hq*3]
+    shr                  hd, 2 ; h * 3/4
+    lea               maskq, [maskq+hq*2]
+    neg                  hq
+    jmp                  wq
+.w2:
+    movd                 m0, [dstq+dsq*0]
+    pinsrd               m0, [dstq+dsq*1], 1
+    movd                 m2, [maskq+hq*2]
+    movq                 m1, [tmpq]
+    add                tmpq, 4*2
+    punpcklwd            m2, m2
+    psubw                m1, m0, m1
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    movd       [dstq+dsq*0], m0
+    pextrd     [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w2
+    RET
+.w4:
+    mova                 m3, [blend_shuf]
+.w4_loop:
+    movq                 m0, [dstq+dsq*0]
+    movhps               m0, [dstq+dsq*1]
+    movd                 m2, [maskq+hq*2]
+    psubw                m1, m0, [tmpq]
+    add                tmpq, 8*2
+    pshufb               m2, m3
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w4_loop
+    RET
+INIT_YMM avx2
+.w8:
+    vbroadcasti128       m3, [blend_shuf]
+    shufpd               m3, m3, 0x0c
+.w8_loop:
+    mova                xm0, [dstq+dsq*0]
+    vinserti128          m0, [dstq+dsq*1], 1
+    vpbroadcastd         m2, [maskq+hq*2]
+    psubw                m1, m0, [tmpq]
+    add                tmpq, 16*2
+    pshufb               m2, m3
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w8_loop
+    RET
+.w16:
+    vpbroadcastw         m4, [maskq+hq*2]
+    vpbroadcastw         m5, [maskq+hq*2+2]
+    mova                 m0,     [dstq+dsq*0]
+    psubw                m2, m0, [tmpq+ 32*0]
+    mova                 m1,     [dstq+dsq*1]
+    psubw                m3, m1, [tmpq+ 32*1]
+    add                tmpq, 32*2
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w16
+    RET
+.w32:
+    vpbroadcastw         m4, [maskq+hq*2]
+    BLEND_H_ROW           0, 0, 2
+    add                dstq, dsq
+    inc                  hq
+    jl .w32
+    RET
+.w64:
+    vpbroadcastw         m4, [maskq+hq*2]
+    BLEND_H_ROW           0, 0
+    BLEND_H_ROW           2, 2, 4
+    add                dstq, dsq
+    inc                  hq
+    jl .w64
+    RET
+.w128:
+    vpbroadcastw         m4, [maskq+hq*2]
+    BLEND_H_ROW           0,  0
+    BLEND_H_ROW           2,  2, 8
+    BLEND_H_ROW           4, -4
+    BLEND_H_ROW           6, -2
+    add                dstq, dsq
+    inc                  hq
+    jl .w128
+    RET
+
+cglobal emu_edge_16bpc, 10, 13, 1, bw, bh, iw, ih, x, y, dst, dstride, src, sstride, \
+                                   bottomext, rightext
+    ; we assume that the buffer (stride) is larger than width, so we can
+    ; safely overwrite by a few bytes
+
+    ; ref += iclip(y, 0, ih - 1) * PXSTRIDE(ref_stride)
+    xor                r12d, r12d
+    lea                 r10, [ihq-1]
+    cmp                  yq, ihq
+    cmovs               r10, yq
+    test                 yq, yq
+    cmovs               r10, r12
+    imul                r10, sstrideq
+    add                srcq, r10
+
+    ; ref += iclip(x, 0, iw - 1)
+    lea                 r10, [iwq-1]
+    cmp                  xq, iwq
+    cmovs               r10, xq
+    test                 xq, xq
+    cmovs               r10, r12
+    lea                srcq, [srcq+r10*2]
+
+    ; bottom_ext = iclip(y + bh - ih, 0, bh - 1)
+    lea          bottomextq, [yq+bhq]
+    sub          bottomextq, ihq
+    lea                  r3, [bhq-1]
+    cmovs        bottomextq, r12
+
+    DEFINE_ARGS bw, bh, iw, ih, x, topext, dst, dstride, src, sstride, \
+                bottomext, rightext
+
+    ; top_ext = iclip(-y, 0, bh - 1)
+    neg             topextq
+    cmovs           topextq, r12
+    cmp          bottomextq, bhq
+    cmovns       bottomextq, r3
+    cmp             topextq, bhq
+    cmovg           topextq, r3
+
+    ; right_ext = iclip(x + bw - iw, 0, bw - 1)
+    lea           rightextq, [xq+bwq]
+    sub           rightextq, iwq
+    lea                  r2, [bwq-1]
+    cmovs         rightextq, r12
+
+    DEFINE_ARGS bw, bh, iw, ih, leftext, topext, dst, dstride, src, sstride, \
+                bottomext, rightext
+
+    ; left_ext = iclip(-x, 0, bw - 1)
+    neg            leftextq
+    cmovs          leftextq, r12
+    cmp           rightextq, bwq
+    cmovns        rightextq, r2
+    cmp            leftextq, bwq
+    cmovns         leftextq, r2
+
+    DEFINE_ARGS bw, centerh, centerw, dummy, leftext, topext, \
+                dst, dstride, src, sstride, bottomext, rightext
+
+    ; center_h = bh - top_ext - bottom_ext
+    lea                  r3, [bottomextq+topextq]
+    sub            centerhq, r3
+
+    ; blk += top_ext * PXSTRIDE(dst_stride)
+    mov                  r2, topextq
+    imul                 r2, dstrideq
+    add                dstq, r2
+    mov                 r9m, dstq
+
+    ; center_w = bw - left_ext - right_ext
+    mov            centerwq, bwq
+    lea                  r3, [rightextq+leftextq]
+    sub            centerwq, r3
+
+%macro v_loop 3 ; need_left_ext, need_right_ext, suffix
+.v_loop_%3:
+%if %1
+    ; left extension
+    xor                  r3, r3
+    vpbroadcastw         m0, [srcq]
+.left_loop_%3:
+    mova        [dstq+r3*2], m0
+    add                  r3, 16
+    cmp                  r3, leftextq
+    jl .left_loop_%3
+
+    ; body
+    lea                 r12, [dstq+leftextq*2]
+%endif
+    xor                  r3, r3
+.body_loop_%3:
+    movu                 m0, [srcq+r3*2]
+%if %1
+    movu         [r12+r3*2], m0
+%else
+    movu        [dstq+r3*2], m0
+%endif
+    add                  r3, 16
+    cmp                  r3, centerwq
+    jl .body_loop_%3
+
+%if %2
+    ; right extension
+%if %1
+    lea                 r12, [r12+centerwq*2]
+%else
+    lea                 r12, [dstq+centerwq*2]
+%endif
+    xor                  r3, r3
+    vpbroadcastw         m0, [srcq+centerwq*2-2]
+.right_loop_%3:
+    movu         [r12+r3*2], m0
+    add                  r3, 16
+    cmp                  r3, rightextq
+    jl .right_loop_%3
+
+%endif
+    add                dstq, dstrideq
+    add                srcq, sstrideq
+    dec            centerhq
+    jg .v_loop_%3
+%endmacro
+
+    test           leftextq, leftextq
+    jnz .need_left_ext
+    test          rightextq, rightextq
+    jnz .need_right_ext
+    v_loop                0, 0, 0
+    jmp .body_done
+
+.need_left_ext:
+    test          rightextq, rightextq
+    jnz .need_left_right_ext
+    v_loop                1, 0, 1
+    jmp .body_done
+
+.need_left_right_ext:
+    v_loop                1, 1, 2
+    jmp .body_done
+
+.need_right_ext:
+    v_loop                0, 1, 3
+
+.body_done:
+    ; bottom edge extension
+    test         bottomextq, bottomextq
+    jz .top
+    mov                srcq, dstq
+    sub                srcq, dstrideq
+    xor                  r1, r1
+.bottom_x_loop:
+    mova                 m0, [srcq+r1*2]
+    lea                  r3, [dstq+r1*2]
+    mov                  r4, bottomextq
+.bottom_y_loop:
+    mova               [r3], m0
+    add                  r3, dstrideq
+    dec                  r4
+    jg .bottom_y_loop
+    add                  r1, 16
+    cmp                  r1, bwq
+    jl .bottom_x_loop
+
+.top:
+    ; top edge extension
+    test            topextq, topextq
+    jz .end
+    mov                srcq, r9m
+    mov                dstq, dstm
+    xor                  r1, r1
+.top_x_loop:
+    mova                 m0, [srcq+r1*2]
+    lea                  r3, [dstq+r1*2]
+    mov                  r4, topextq
+.top_y_loop:
+    mova               [r3], m0
+    add                  r3, dstrideq
+    dec                  r4
+    jg .top_y_loop
+    add                  r1, 16
+    cmp                  r1, bwq
+    jl .top_x_loop
+
+.end:
+    RET
+
+cglobal resize_16bpc, 6, 12, 16, dst, dst_stride, src, src_stride, \
+                                 dst_w, h, src_w, dx, mx0, pxmax
+    sub          dword mx0m, 4<<14
+    sub        dword src_wm, 8
+    vpbroadcastd         m5, dxm
+    vpbroadcastd         m8, mx0m
+    vpbroadcastd         m6, src_wm
+ DEFINE_ARGS dst, dst_stride, src, src_stride, dst_w, h, x, _, _, pxmax
+    LEA                  r7, $$
+%define base r7-$$
+    vpbroadcastd         m3, [base+pd_64]
+    vpbroadcastw        xm7, pxmaxm
+    pmaddwd              m2, m5, [base+rescale_mul] ; dx*[0,1,2,3,4,5,6,7]
+    pslld                m5, 3                      ; dx*8
+    pslld                m6, 14
+    paddd                m8, m2                     ; mx+[0..7]*dx
+.loop_y:
+    xor                  xd, xd
+    mova                 m4, m8             ; per-line working version of mx
+.loop_x:
+    vpbroadcastd        m10, [base+pd_63]
+    pxor                 m2, m2
+    pmaxsd               m0, m4, m2
+    psrad                m9, m4, 8          ; filter offset (unmasked)
+    pminsd               m0, m6             ; iclip(mx, 0, src_w-8)
+    psubd                m1, m4, m0         ; pshufb offset
+    psrad                m0, 14             ; clipped src_x offset
+    psrad                m1, 14             ; pshufb edge_emu offset
+    pand                 m9, m10            ; filter offset (masked)
+    ; load source pixels
+    movd                r8d, xm0
+    pextrd              r9d, xm0, 1
+    pextrd             r10d, xm0, 2
+    pextrd             r11d, xm0, 3
+    vextracti128        xm0, m0, 1
+    movu               xm10, [srcq+r8*2]
+    movu               xm11, [srcq+r9*2]
+    movu               xm12, [srcq+r10*2]
+    movu               xm13, [srcq+r11*2]
+    movd                r8d, xm0
+    pextrd              r9d, xm0, 1
+    pextrd             r10d, xm0, 2
+    pextrd             r11d, xm0, 3
+    vinserti128         m10, [srcq+r8*2], 1
+    vinserti128         m11, [srcq+r9*2], 1
+    vinserti128         m12, [srcq+r10*2], 1
+    vinserti128         m13, [srcq+r11*2], 1
+    ptest                m1, m1
+    jz .filter
+    movq                 r9, xm1
+    pextrq              r11, xm1, 1
+    movsxd               r8, r9d
+    sar                  r9, 32
+    movsxd              r10, r11d
+    sar                 r11, 32
+    vextracti128        xm1, m1, 1
+    movu               xm14, [base+resize_shuf+8+r8*2]
+    movu               xm15, [base+resize_shuf+8+r9*2]
+    movu                xm0, [base+resize_shuf+8+r10*2]
+    movu                xm2, [base+resize_shuf+8+r11*2]
+    movq                 r9, xm1
+    pextrq              r11, xm1, 1
+    movsxd               r8, r9d
+    sar                  r9, 32
+    movsxd              r10, r11d
+    sar                 r11, 32
+    vinserti128         m14, [base+resize_shuf+8+r8*2], 1
+    vinserti128         m15, [base+resize_shuf+8+r9*2], 1
+    vinserti128          m0, [base+resize_shuf+8+r10*2], 1
+    vinserti128          m2, [base+resize_shuf+8+r11*2], 1
+    pshufb              m10, m14
+    pshufb              m11, m15
+    pshufb              m12, m0
+    pshufb              m13, m2
+.filter:
+    movd                r8d, xm9
+    pextrd              r9d, xm9, 1
+    pextrd             r10d, xm9, 2
+    pextrd             r11d, xm9, 3
+    vextracti128        xm9, m9, 1
+    movq               xm14, [base+resize_filter+r8*8]
+    movq               xm15, [base+resize_filter+r9*8]
+    movq                xm0, [base+resize_filter+r10*8]
+    movq                xm2, [base+resize_filter+r11*8]
+    movd                r8d, xm9
+    pextrd              r9d, xm9, 1
+    pextrd             r10d, xm9, 2
+    pextrd             r11d, xm9, 3
+    movhps             xm14, [base+resize_filter+r8*8]
+    movhps             xm15, [base+resize_filter+r9*8]
+    movhps              xm0, [base+resize_filter+r10*8]
+    movhps              xm2, [base+resize_filter+r11*8]
+    pmovsxbw            m14, xm14
+    pmovsxbw            m15, xm15
+    pmovsxbw             m0, xm0
+    pmovsxbw             m2, xm2
+    pmaddwd             m10, m14
+    pmaddwd             m11, m15
+    pmaddwd             m12, m0
+    pmaddwd             m13, m2
+    phaddd              m10, m11
+    phaddd              m12, m13
+    phaddd              m10, m12
+    psubd               m10, m3, m10
+    psrad               m10, 7
+    vextracti128        xm0, m10, 1
+    packusdw           xm10, xm0
+    pminsw             xm10, xm7
+    mova        [dstq+xq*2], xm10
+    paddd                m4, m5
+    add                  xd, 8
+    cmp                  xd, dst_wd
+    jl .loop_x
+    add                dstq, dst_strideq
+    add                srcq, src_strideq
+    dec                  hd
+    jg .loop_y
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/mc16_avx512.asm b/media/libdav1d/src/src/x86/mc16_avx512.asm
new file mode 100644
index 0000000000..3e352c5b37
--- /dev/null
+++ b/media/libdav1d/src/src/x86/mc16_avx512.asm
@@ -0,0 +1,6119 @@
+; Copyright © 2020, VideoLAN and dav1d authors
+; Copyright © 2020, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+spel_h_shufA:  db  0,  1,  2,  3,  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9
+               db 32, 33, 34, 35, 34, 35, 36, 37, 36, 37, 38, 39, 38, 39, 40, 41
+spel_h_shufC:  db  8,  9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15, 14, 15, 16, 17
+               db 40, 41, 42, 43, 42, 43, 44, 45, 44, 45, 46, 47, 46, 47, 48, 49
+               db 16, 17, 18, 19, 18, 19, 20, 21, 20, 21, 22, 23, 22, 23, 24, 25
+               db 48, 49, 50, 51, 50, 51, 52, 53, 52, 53, 54, 55, 54, 55, 56, 57
+spel_h_shufB:  db  4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13
+               db 36, 37, 38, 39, 38, 39, 40, 41, 40, 41, 42, 43, 42, 43, 44, 45
+spel_h_shufD:  db 12, 13, 14, 15, 14, 15, 16, 17, 16, 17, 18, 19, 18, 19, 20, 21
+               db 44, 45, 46, 47, 46, 47, 48, 49, 48, 49, 50, 51, 50, 51, 52, 53
+               db 20, 21, 22, 23, 22, 23, 24, 25, 24, 25, 26, 27, 26, 27, 28, 29
+               db 52, 53, 54, 55, 54, 55, 56, 57, 56, 57, 58, 59, 58, 59, 60, 61
+spel_v_shuf8:  db  0,  1, 16, 17,  2,  3, 18, 19,  4,  5, 20, 21,  6,  7, 22, 23
+               db 16, 17, 32, 33, 18, 19, 34, 35, 20, 21, 36, 37, 22, 23, 38, 39
+               db  8,  9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31
+               db 24, 25, 40, 41, 26, 27, 42, 43, 28, 29, 44, 45, 30, 31, 46, 47
+spel_v_shuf16: db  0,  1, 32, 33,  2,  3, 34, 35,  4,  5, 36, 37,  6,  7, 38, 39
+               db  8,  9, 40, 41, 10, 11, 42, 43, 12, 13, 44, 45, 14, 15, 46, 47
+               db 16, 17, 48, 49, 18, 19, 50, 51, 20, 21, 52, 53, 22, 23, 54, 55
+               db 24, 25, 56, 57, 26, 27, 58, 59, 28, 29, 60, 61, 30, 31, 62, 63
+prep_endA:     db  1,  2,  5,  6,  9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30
+               db 33, 34, 37, 38, 41, 42, 45, 46, 49, 50, 53, 54, 57, 58, 61, 62
+               db 65, 66, 69, 70, 73, 74, 77, 78, 81, 82, 85, 86, 89, 90, 93, 94
+               db 97, 98,101,102,105,106,109,110,113,114,117,118,121,122,125,126
+prep_endB:     db  1,  2,  5,  6,  9, 10, 13, 14, 33, 34, 37, 38, 41, 42, 45, 46
+               db 17, 18, 21, 22, 25, 26, 29, 30, 49, 50, 53, 54, 57, 58, 61, 62
+               db 65, 66, 69, 70, 73, 74, 77, 78, 97, 98,101,102,105,106,109,110
+               db 81, 82, 85, 86, 89, 90, 93, 94,113,114,117,118,121,122,125,126
+prep_endC:     db  1,  2,  5,  6,  9, 10, 13, 14, 65, 66, 69, 70, 73, 74, 77, 78
+               db 17, 18, 21, 22, 25, 26, 29, 30, 81, 82, 85, 86, 89, 90, 93, 94
+               db 33, 34, 37, 38, 41, 42, 45, 46, 97, 98,101,102,105,106,109,110
+               db 49, 50, 53, 54, 57, 58, 61, 62,113,114,117,118,121,122,125,126
+spel_shuf4a:   db  1,  2, 17, 18,  5,  6, 21, 22,  9, 10, 25, 26, 13, 14, 29, 30
+               db 17, 18, 33, 34, 21, 22, 37, 38, 25, 26, 41, 42, 29, 30, 45, 46
+               db 33, 34, 49, 50, 37, 38, 53, 54, 41, 42, 57, 58, 45, 46, 61, 62
+               db 49, 50, 65, 66, 53, 54, 69, 70, 57, 58, 73, 74, 61, 62, 77, 78
+spel_shuf4b:   db 50, 51, 65, 66, 54, 55, 69, 70, 58, 59, 73, 74, 62, 63, 77, 78
+               db 65, 66, 81, 82, 69, 70, 85, 86, 73, 74, 89, 90, 77, 78, 93, 94
+               db 81, 82, 97, 98, 85, 86,101,102, 89, 90,105,106, 93, 94,109,110
+               db 97, 98,113,114,101,102,117,118,105,106,121,122,109,110,125,126
+spel_shuf8a:   db  1,  2, 17, 18,  5,  6, 21, 22,  9, 10, 25, 26, 13, 14, 29, 30
+               db 17, 18, 65, 66, 21, 22, 69, 70, 25, 26, 73, 74, 29, 30, 77, 78
+               db 33, 34, 49, 50, 37, 38, 53, 54, 41, 42, 57, 58, 45, 46, 61, 62
+               db 49, 50, 97, 98, 53, 54,101,102, 57, 58,105,106, 61, 62,109,110
+spel_shuf8b:   db 18, 19, 65, 66, 22, 23, 69, 70, 26, 27, 73, 74, 30, 31, 77, 78
+               db 65, 66, 81, 82, 69, 70, 85, 86, 73, 74, 89, 90, 77, 78, 93, 94
+               db 50, 51, 97, 98, 54, 55,101,102, 58, 59,105,106, 62, 63,109,110
+               db 97, 98,113,114,101,102,117,118,105,106,121,122,109,110,125,126
+spel_shuf16:   db  1,  2, 33, 34,  5,  6, 37, 38,  9, 10, 41, 42, 13, 14, 45, 46
+               db 17, 18, 49, 50, 21, 22, 53, 54, 25, 26, 57, 58, 29, 30, 61, 62
+               db 65, 66, 97, 98, 69, 70,101,102, 73, 74,105,106, 77, 78,109,110
+               db 81, 82,113,114, 85, 86,117,118, 89, 90,121,122, 93, 94,125,126
+spel_shuf32:   db  1,  2, 65, 66,  5,  6, 69, 70,  9, 10, 73, 74, 13, 14, 77, 78
+               db 17, 18, 81, 82, 21, 22, 85, 86, 25, 26, 89, 90, 29, 30, 93, 94
+               db 33, 34, 97, 98, 37, 38,101,102, 41, 42,105,106, 45, 46,109,110
+               db 49, 50,113,114, 53, 54,117,118, 57, 58,121,122, 61, 62,125,126
+spel_h_shuf2b: db  1,  2, 17, 18,  5,  6, 21, 22, 17, 18, 33, 34, 21, 22, 37, 38
+               db 33, 34, 49, 50, 37, 38, 53, 54, 49, 50,  9, 10, 53, 54, 13, 14
+               db  9, 10, 25, 26, 13, 14, 29, 30, 25, 26, 41, 42, 29, 30, 45, 46
+spel_shuf2:    db 10, 11, 17, 18, 14, 15, 21, 22, 17, 18, 25, 26, 21, 22, 29, 30
+spel_h_shuf2a: db  0,  1,  2,  3,  2,  3,  4,  5, 16, 17, 18, 19, 18, 19, 20, 21
+               db  4,  5,  6,  7,  6,  7,  8,  9, 20, 21, 22, 23, 22, 23, 24, 25
+w_mask_end42x: db  1,  5,  9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61
+               db 65, 69, 73, 77, 81, 85, 89, 93, 97,101,105,109,113,117,121,125
+w_mask_end444: db  0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+               db 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62
+               db 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94
+               db 96, 98,100,102,104,106,108,110,112,114,116,118,120,122,124,126
+w_mask_shuf4:  db  0,  2,  8, 10,  4,  6, 12, 14, 16, 18, 24, 26, 20, 22, 28, 30
+               db 32, 34, 40, 42, 36, 38, 44, 46, 48, 50, 56, 58, 52, 54, 60, 62
+               db 64, 66, 72, 74, 68, 70, 76, 78, 80, 82, 88, 90, 84, 86, 92, 94
+               db 96, 98,104,106,100,102,108,110,112,114,120,122,116,118,124,126
+w_mask_shuf8:  db  0,  2, 16, 18,  4,  6, 20, 22,  8, 10, 24, 26, 12, 14, 28, 30
+               db 32, 34, 48, 50, 36, 38, 52, 54, 40, 42, 56, 58, 44, 46, 60, 62
+               db 64, 66, 80, 82, 68, 70, 84, 86, 72, 74, 88, 90, 76, 78, 92, 94
+               db 96, 98,112,114,100,102,116,118,104,106,120,122,108,110,124,126
+w_mask_shuf16: db  0,  2, 32, 34,  4,  6, 36, 38,  8, 10, 40, 42, 12, 14, 44, 46
+               db 16, 18, 48, 50, 20, 22, 52, 54, 24, 26, 56, 58, 28, 30, 60, 62
+               db 64, 66, 96, 98, 68, 70,100,102, 72, 74,104,106, 76, 78,108,110
+               db 80, 82,112,114, 84, 86,116,118, 88, 90,120,122, 92, 94,124,126
+warp8x8_permA: db  0,  1,  2,  3, 32, 33, 34, 35,  2,  3,  4,  5, 34, 35, 36, 37
+               db  4,  5,  6,  7, 36, 37, 38, 39,  6,  7,  8,  9, 38, 39, 40, 41
+               db  8,  9, 10, 11, 40, 41, 42, 43, 10, 11, 12, 13, 42, 43, 44, 45
+               db 12, 13, 14, 15, 44, 45, 46, 47, 14, 15, 16, 17, 46, 47, 48, 49
+warp8x8_permB: db 12, 13, 14, 15, 44, 45, 46, 47, 14, 15, 16, 17, 46, 47, 48, 49
+               db 16, 17, 18, 19, 48, 49, 50, 51, 18, 19, 20, 21, 50, 51, 52, 53
+               db 20, 21, 22, 23, 52, 53, 54, 55, 22, 23, 24, 25, 54, 55, 56, 57
+               db 24, 25, 26, 27, 56, 57, 58, 59, 26, 27, 28, 29, 58, 59, 60, 61
+warp8x8_end:   db  0,  1,  4,  5, 16, 17, 20, 21, 32, 33, 36, 37, 48, 49, 52, 53
+               db  2,  3,  6,  7, 18, 19, 22, 23, 34, 35, 38, 39, 50, 51, 54, 55
+               db  8,  9, 12, 13, 24, 25, 28, 29, 40, 41, 44, 45, 56, 57, 60, 61
+               db 10, 11, 14, 15, 26, 27, 30, 31, 42, 43, 46, 47, 58, 59, 62, 63
+deint_q_shuf: ;dq  0,  2,  4,  6,  1,  3,  5,  7
+pd_0to7:       dd  0,  1,  2,  3,  4,  5,  6,  7
+               dd  1
+pw_2048:       times 2 dw 2048
+               dd  3
+pw_8192:       times 2 dw 8192
+avg_shift:     dw  5,  5,  3,  3
+pw_27615:      times 2 dw 27615
+pw_32766:      times 2 dw 32766
+warp8x8_permC: db -1,  0, -1,  1, -1,  8, -1,  9, -1,  4, -1,  5, -1, 12, -1, 13
+warp8x8_permD: db -1,  2, -1,  3, -1, 10, -1, 11, -1,  6, -1,  7, -1, 14, -1, 15
+warp_shift_h:  db 11, 19, 11, 19, 43, 51, 43, 51, 13, 21, 13, 21, 45, 53, 45, 53
+blend_shuf:    db  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  2,  3,  2,  3,  2,  3
+resize_permA:  dd  0,  4,  8, 12,  1,  5,  9, 13, 16, 20, 24, 28, 17, 21, 25, 29
+resize_permB:  dd  2,  6, 10, 14,  3,  7, 11, 15, 18, 22, 26, 30, 19, 23, 27, 31
+resize_permC:  dq  0,  1,  4,  5,  8,  9, 12, 13
+resize_permD:  dq  2,  3,  6,  7, 10, 11, 14, 15
+resize_permE:  dq  0,  2,  4,  6
+resize_shufA:  db -1,  0, -1,  1, -1,  4, -1,  5, -1,  8, -1,  9, -1, 12, -1, 13
+resize_shufB:  db -1,  2, -1,  3, -1,  6, -1,  7, -1, 10, -1, 11, -1, 14, -1, 15
+rescale_mul:   dd  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+resize_shuf:   db  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7
+               db  8,  9, 10, 11, 12, 13, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15
+
+prep_hv_shift:    dq  6,  4
+put_bilin_h_rnd:  dw  8,  8, 10, 10
+prep_mul:         dw 16, 16,  4,  4
+put_8tap_h_rnd:   dd 34, 40
+prep_8tap_rnd:    dd 128 - (8192 << 8)
+warp_8x8_rnd_h:   dd 512, 2048
+warp_8x8_rnd_v:   dd 262144, 65536
+warp_8x8t_rnd_v:  dd 16384 - (8192 << 15)
+avg_round:        dw -16400, -16400, -16388, -16388
+w_avg_round:      dd 128 + (8192 << 4),  32 + (8192 << 4)
+mask_round:       dd 512 + (8192 << 6), 128 + (8192 << 6)
+w_mask_round:     dd 128, 64
+bidir_shift:      dw  6,  6,  4,  4
+
+pb_64:    times 4 db 64
+pw_m512:  times 2 dw -512
+pw_2:     times 2 dw 2
+pw_64:    times 2 dw 64
+pd_32:    dd 32
+pd_63:    dd 63
+pd_128:   dd 128
+pd_640:   dd 640
+pd_2176:  dd 2176
+pd_16384: dd 16384
+pd_0_4:   dd 0, 4
+
+%define pw_16 prep_mul
+%define pd_512 warp_8x8_rnd_h
+
+%macro BASE_JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base %1_%2
+    %%table:
+    %rep %0 - 2
+        dw %%base %+ _w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro HV_JMP_TABLE 5-*
+    %xdefine %%prefix mangle(private_prefix %+ _%1_%2_16bpc_%3)
+    %xdefine %%base %1_%3
+    %assign %%types %4
+    %if %%types & 1
+        %xdefine %1_%2_h_%3_table  (%%h  - %5)
+        %%h:
+        %rep %0 - 4
+            dw %%prefix %+ .h_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 2
+        %xdefine %1_%2_v_%3_table  (%%v  - %5)
+        %%v:
+        %rep %0 - 4
+            dw %%prefix %+ .v_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 4
+        %xdefine %1_%2_hv_%3_table (%%hv - %5)
+        %%hv:
+        %rep %0 - 4
+            dw %%prefix %+ .hv_w%5 - %%base
+            %rotate 1
+        %endrep
+    %endif
+%endmacro
+
+%macro BIDIR_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - 2*%3)
+    %xdefine %%base %1_%2_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1_16bpc_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%prefix %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%xdefine put_avx512icl mangle(private_prefix %+ _put_bilin_16bpc_avx512icl.put)
+%xdefine prep_avx512icl mangle(private_prefix %+ _prep_bilin_16bpc_avx512icl.prep)
+
+BIDIR_JMP_TABLE avg,        avx512icl,       4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_avg,      avx512icl,       4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE mask,       avx512icl,       4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_420, avx512icl,       4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_422, avx512icl,       4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_444, avx512icl,       4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE blend,      avx512icl,       4, 8, 16, 32
+BIDIR_JMP_TABLE blend_v,    avx512icl,    2, 4, 8, 16, 32
+BIDIR_JMP_TABLE blend_h,    avx512icl,    2, 4, 8, 16, 32, 64, 128
+BASE_JMP_TABLE put,         avx512icl,    2, 4, 8, 16, 32, 64, 128
+BASE_JMP_TABLE prep,        avx512icl,       4, 8, 16, 32, 64, 128
+HV_JMP_TABLE   put,  bilin, avx512icl, 7, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE   prep, bilin, avx512icl, 7,    4, 8, 16, 32, 64, 128
+HV_JMP_TABLE   put,  6tap,  avx512icl, 2, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE   put,  8tap,  avx512icl, 2, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE   prep, 6tap,  avx512icl, 2,    4, 8, 16, 32, 64, 128
+HV_JMP_TABLE   prep, 8tap,  avx512icl, 2,    4, 8, 16, 32, 64, 128
+
+%define table_offset(type, fn) type %+ fn %+ SUFFIX %+ _table - type %+ SUFFIX
+
+cextern mc_subpel_filters
+%define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8)
+
+cextern mc_warp_filter
+cextern obmc_masks_avx2
+cextern resize_filter
+
+SECTION .text
+
+%if WIN64
+DECLARE_REG_TMP 4
+%else
+DECLARE_REG_TMP 8
+%endif
+
+INIT_ZMM avx512icl
+cglobal put_bilin_16bpc, 4, 8, 13, dst, ds, src, ss, w, h, mxy
+    mov                mxyd, r6m ; mx
+    lea                  r7, [put_avx512icl]
+    tzcnt               t0d, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r7m ; my
+    test               mxyd, mxyd
+    jnz .v
+.put:
+    movzx               t0d, word [r7+t0*2+table_offset(put,)]
+    add                  t0, r7
+    jmp                  t0
+.put_w2:
+    mov                 r6d, [srcq+ssq*0]
+    mov                 r7d, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6d
+    mov        [dstq+dsq*1], r7d
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w2
+    RET
+.put_w4:
+    mov                  r6, [srcq+ssq*0]
+    mov                  r7, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6
+    mov        [dstq+dsq*1], r7
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w4
+    RET
+.put_w8:
+    movu               xmm0, [srcq+ssq*0]
+    movu               xmm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], xmm0
+    mova       [dstq+dsq*1], xmm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w8
+    RET
+.put_w16:
+    movu                ym0, [srcq+ssq*0]
+    movu                ym1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], ym0
+    mova       [dstq+dsq*1], ym1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w16
+    RET
+.put_w32:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w32
+    RET
+.put_w64:
+    movu                 m0, [srcq+ssq*0+64*0]
+    movu                 m1, [srcq+ssq*0+64*1]
+    movu                 m2, [srcq+ssq*1+64*0]
+    movu                 m3, [srcq+ssq*1+64*1]
+    lea                srcq, [srcq+ssq*2]
+    mova  [dstq+dsq*0+64*0], m0
+    mova  [dstq+dsq*0+64*1], m1
+    mova  [dstq+dsq*1+64*0], m2
+    mova  [dstq+dsq*1+64*1], m3
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w64
+    RET
+.put_w128:
+    movu                 m0, [srcq+64*0]
+    movu                 m1, [srcq+64*1]
+    movu                 m2, [srcq+64*2]
+    movu                 m3, [srcq+64*3]
+    add                srcq, ssq
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    mova        [dstq+64*2], m2
+    mova        [dstq+64*3], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w128
+    RET
+.h:
+    vpbroadcastw         m5, mxyd
+    mov                mxyd, r7m ; my
+    vpbroadcastd         m4, [pw_16]
+    psubw                m4, m5
+    test               mxyd, mxyd
+    jnz .hv
+    ; 12-bit is rounded twice so we can't use the same pmulhrsw approach as .v
+    movzx               t0d, word [r7+t0*2+table_offset(put, _bilin_h)]
+    mov                 r6d, r8m ; bitdepth_max
+    add                  t0, r7
+    shr                 r6d, 11
+    vpbroadcastd         m6, [r7-put_avx512icl+put_bilin_h_rnd+r6*4]
+    jmp                  t0
+.h_w2:
+    movq               xmm1, [srcq+ssq*0]
+    movhps             xmm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmullw             xmm0, xmm1, xm4
+    psrlq              xmm1, 16
+    pmullw             xmm1, xm5
+    paddw              xmm0, xm6
+    paddw              xmm0, xmm1
+    psrlw              xmm0, 4
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2
+    RET
+.h_w4:
+    movq               xmm0, [srcq+ssq*0+0]
+    movhps             xmm0, [srcq+ssq*1+0]
+    movq               xmm1, [srcq+ssq*0+2]
+    movhps             xmm1, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    pmullw             xmm0, xm4
+    pmullw             xmm1, xm5
+    paddw              xmm0, xm6
+    paddw              xmm0, xmm1
+    psrlw              xmm0, 4
+    movq       [dstq+dsq*0], xmm0
+    movhps     [dstq+dsq*1], xmm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4
+    RET
+.h_w8:
+    movu                xm0, [srcq+ssq*0+0]
+    vinserti32x4        ym0, [srcq+ssq*1+0], 1
+    movu                xm1, [srcq+ssq*0+2]
+    vinserti32x4        ym1, [srcq+ssq*1+2], 1
+    lea                srcq, [srcq+ssq*2]
+    pmullw              ym0, ym4
+    pmullw              ym1, ym5
+    paddw               ym0, ym6
+    paddw               ym0, ym1
+    psrlw               ym0, 4
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], ym0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    movu                ym0, [srcq+ssq*0+0]
+    vinserti32x8         m0, [srcq+ssq*1+0], 1
+    movu                ym1, [srcq+ssq*0+2]
+    vinserti32x8         m1, [srcq+ssq*1+2], 1
+    lea                srcq, [srcq+ssq*2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    paddw                m0, m6
+    paddw                m0, m1
+    psrlw                m0, 4
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+    pmullw               m0, m4, [srcq+ssq*0+0]
+    pmullw               m2, m5, [srcq+ssq*0+2]
+    pmullw               m1, m4, [srcq+ssq*1+0]
+    pmullw               m3, m5, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    paddw                m0, m6
+    paddw                m1, m6
+    paddw                m0, m2
+    paddw                m1, m3
+    psrlw                m0, 4
+    psrlw                m1, 4
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w32
+    RET
+.h_w64:
+    pmullw               m0, m4, [srcq+64*0+0]
+    pmullw               m2, m5, [srcq+64*0+2]
+    pmullw               m1, m4, [srcq+64*1+0]
+    pmullw               m3, m5, [srcq+64*1+2]
+    add                srcq, ssq
+    paddw                m0, m6
+    paddw                m1, m6
+    paddw                m0, m2
+    paddw                m1, m3
+    psrlw                m0, 4
+    psrlw                m1, 4
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w64
+    RET
+.h_w128:
+    pmullw               m0, m4, [srcq+64*0+0]
+    pmullw               m7, m5, [srcq+64*0+2]
+    pmullw               m1, m4, [srcq+64*1+0]
+    pmullw               m8, m5, [srcq+64*1+2]
+    pmullw               m2, m4, [srcq+64*2+0]
+    pmullw               m9, m5, [srcq+64*2+2]
+    pmullw               m3, m4, [srcq+64*3+0]
+    pmullw              m10, m5, [srcq+64*3+2]
+    add                srcq, ssq
+    REPX      {paddw x, m6}, m0, m1, m2, m3
+    paddw                m0, m7
+    paddw                m1, m8
+    paddw                m2, m9
+    paddw                m3, m10
+    REPX       {psrlw x, 4}, m0, m1, m2, m3
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    mova        [dstq+64*2], m2
+    mova        [dstq+64*3], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w128
+    RET
+.v:
+    movzx               t0d, word [r7+t0*2+table_offset(put, _bilin_v)]
+    shl                mxyd, 11
+    vpbroadcastw         m8, mxyd
+    add                  t0, r7
+    jmp                  t0
+.v_w2:
+    movd               xmm0, [srcq+ssq*0]
+.v_w2_loop:
+    movd               xmm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpckldq          xmm2, xmm0, xmm1
+    movd               xmm0, [srcq+ssq*0]
+    punpckldq          xmm1, xmm0
+    psubw              xmm1, xmm2
+    pmulhrsw           xmm1, xm8
+    paddw              xmm1, xmm2
+    movd       [dstq+dsq*0], xmm1
+    pextrd     [dstq+dsq*1], xmm1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movq               xmm0, [srcq+ssq*0]
+.v_w4_loop:
+    movq               xmm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklqdq         xmm2, xmm0, xmm1
+    movq               xmm0, [srcq+ssq*0]
+    punpcklqdq         xmm1, xmm0
+    psubw              xmm1, xmm2
+    pmulhrsw           xmm1, xm8
+    paddw              xmm1, xmm2
+    movq       [dstq+dsq*0], xmm1
+    movhps     [dstq+dsq*1], xmm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movu               xmm0, [srcq+ssq*0]
+.v_w8_loop:
+    vbroadcasti128     ymm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd           ymm2, ymm0, ymm1, 0xf0
+    vbroadcasti128     ymm0, [srcq+ssq*0]
+    vpblendd           ymm1, ymm0, 0xf0
+    psubw              ymm1, ymm2
+    pmulhrsw           ymm1, ym8
+    paddw              ymm1, ymm2
+    mova         [dstq+dsq*0], xmm1
+    vextracti128 [dstq+dsq*1], ymm1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    vzeroupper
+    RET
+.v_w16:
+    movu                ym0, [srcq+ssq*0]
+.v_w16_loop:
+    movu                ym3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    psubw               ym1, ym3, ym0
+    pmulhrsw            ym1, ym8
+    paddw               ym1, ym0
+    movu                ym0, [srcq+ssq*0]
+    psubw               ym2, ym0, ym3
+    pmulhrsw            ym2, ym8
+    paddw               ym2, ym3
+    mova       [dstq+dsq*0], ym1
+    mova       [dstq+dsq*1], ym2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+    movu                 m0, [srcq+ssq*0]
+.v_w32_loop:
+    movu                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    psubw                m1, m3, m0
+    pmulhrsw             m1, m8
+    paddw                m1, m0
+    movu                 m0, [srcq+ssq*0]
+    psubw                m2, m0, m3
+    pmulhrsw             m2, m8
+    paddw                m2, m3
+    mova       [dstq+dsq*0], m1
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w32_loop
+    RET
+.v_w64:
+    movu                 m0, [srcq+ssq*0+64*0]
+    movu                 m1, [srcq+ssq*0+64*1]
+.v_w64_loop:
+    movu                 m2, [srcq+ssq*1+64*0]
+    movu                 m3, [srcq+ssq*1+64*1]
+    lea                srcq, [srcq+ssq*2]
+    psubw                m4, m2, m0
+    pmulhrsw             m4, m8
+    paddw                m4, m0
+    movu                 m0, [srcq+ssq*0+64*0]
+    psubw                m5, m3, m1
+    pmulhrsw             m5, m8
+    paddw                m5, m1
+    movu                 m1, [srcq+ssq*0+64*1]
+    psubw                m6, m0, m2
+    pmulhrsw             m6, m8
+    psubw                m7, m1, m3
+    pmulhrsw             m7, m8
+    mova  [dstq+dsq*0+64*0], m4
+    mova  [dstq+dsq*0+64*1], m5
+    paddw                m6, m2
+    paddw                m7, m3
+    mova  [dstq+dsq*1+64*0], m6
+    mova  [dstq+dsq*1+64*1], m7
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w64_loop
+    RET
+.v_w128:
+    movu                 m0, [srcq+ssq*0+64*0]
+    movu                 m1, [srcq+ssq*0+64*1]
+    movu                 m2, [srcq+ssq*0+64*2]
+    movu                 m3, [srcq+ssq*0+64*3]
+.v_w128_loop:
+    movu                 m4, [srcq+ssq*1+64*0]
+    movu                 m5, [srcq+ssq*1+64*1]
+    movu                 m6, [srcq+ssq*1+64*2]
+    movu                 m7, [srcq+ssq*1+64*3]
+    lea                srcq, [srcq+ssq*2]
+    psubw                m9, m4, m0
+    pmulhrsw             m9, m8
+    paddw                m9, m0
+    movu                 m0, [srcq+ssq*0+64*0]
+    psubw               m10, m5, m1
+    pmulhrsw            m10, m8
+    paddw               m10, m1
+    movu                 m1, [srcq+ssq*0+64*1]
+    psubw               m11, m6, m2
+    pmulhrsw            m11, m8
+    paddw               m11, m2
+    movu                 m2, [srcq+ssq*0+64*2]
+    psubw               m12, m7, m3
+    pmulhrsw            m12, m8
+    paddw               m12, m3
+    movu                 m3, [srcq+ssq*0+64*3]
+    mova  [dstq+dsq*0+64*0], m9
+    psubw                m9, m0, m4
+    pmulhrsw             m9, m8
+    mova  [dstq+dsq*0+64*1], m10
+    psubw               m10, m1, m5
+    pmulhrsw            m10, m8
+    mova  [dstq+dsq*0+64*2], m11
+    psubw               m11, m2, m6
+    pmulhrsw            m11, m8
+    mova  [dstq+dsq*0+64*3], m12
+    psubw               m12, m3, m7
+    pmulhrsw            m12, m8
+    paddw                m9, m4
+    paddw               m10, m5
+    mova  [dstq+dsq*1+64*0], m9
+    mova  [dstq+dsq*1+64*1], m10
+    paddw               m11, m6
+    paddw               m12, m7
+    mova  [dstq+dsq*1+64*2], m11
+    mova  [dstq+dsq*1+64*3], m12
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w128_loop
+    RET
+.hv:
+    movzx               t0d, word [r7+t0*2+table_offset(put, _bilin_hv)]
+    shl                mxyd, 11
+    vpbroadcastd         m6, [pw_2]
+    vpbroadcastw         m7, mxyd
+    vpbroadcastd         m8, [pw_8192]
+    add                  t0, r7
+    test          dword r8m, 0x800
+    jnz .hv_12bpc
+    psllw                m4, 2
+    psllw                m5, 2
+    vpbroadcastd         m8, [pw_2048]
+.hv_12bpc:
+    jmp                  t0
+.hv_w2:
+    vpbroadcastq       xmm1, [srcq+ssq*0]
+    pmullw             xmm0, xmm1, xm4
+    psrlq              xmm1, 16
+    pmullw             xmm1, xm5
+    paddw              xmm0, xm6
+    paddw              xmm0, xmm1
+    psrlw              xmm0, 2
+.hv_w2_loop:
+    movq               xmm2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps             xmm2, [srcq+ssq*0]
+    pmullw             xmm1, xmm2, xm4
+    psrlq              xmm2, 16
+    pmullw             xmm2, xm5
+    paddw              xmm1, xm6
+    paddw              xmm1, xmm2
+    psrlw              xmm1, 2                ; 1 _ 2 _
+    shufpd             xmm2, xmm0, xmm1, 0x01 ; 0 _ 1 _
+    mova               xmm0, xmm1
+    psubw              xmm1, xmm2
+    paddw              xmm1, xmm1
+    pmulhw             xmm1, xm7
+    paddw              xmm1, xmm2
+    pmulhrsw           xmm1, xm8
+    movd       [dstq+dsq*0], xmm1
+    pextrd     [dstq+dsq*1], xmm1, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    pmullw             xmm0, xm4, [srcq+ssq*0-8]
+    pmullw             xmm1, xm5, [srcq+ssq*0-6]
+    paddw              xmm0, xm6
+    paddw              xmm0, xmm1
+    psrlw              xmm0, 2
+.hv_w4_loop:
+    movq               xmm1, [srcq+ssq*1+0]
+    movq               xmm2, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    movhps             xmm1, [srcq+ssq*0+0]
+    movhps             xmm2, [srcq+ssq*0+2]
+    pmullw             xmm1, xm4
+    pmullw             xmm2, xm5
+    paddw              xmm1, xm6
+    paddw              xmm1, xmm2
+    psrlw              xmm1, 2                ; 1 2
+    shufpd             xmm2, xmm0, xmm1, 0x01 ; 0 1
+    mova               xmm0, xmm1
+    psubw              xmm1, xmm2
+    paddw              xmm1, xmm1
+    pmulhw             xmm1, xm7
+    paddw              xmm1, xmm2
+    pmulhrsw           xmm1, xm8
+    movq       [dstq+dsq*0], xmm1
+    movhps     [dstq+dsq*1], xmm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    pmullw             xmm0, xm4, [srcq+ssq*0+0]
+    pmullw             xmm1, xm5, [srcq+ssq*0+2]
+    paddw              xmm0, xm6
+    paddw              xmm0, xmm1
+    psrlw              xmm0, 2
+    vinserti32x4        ym0, xmm0, 1
+.hv_w8_loop:
+    movu                xm1, [srcq+ssq*1+0]
+    movu                xm2, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x4        ym1, [srcq+ssq*0+0], 1
+    vinserti32x4        ym2, [srcq+ssq*0+2], 1
+    pmullw              ym1, ym4
+    pmullw              ym2, ym5
+    paddw               ym1, ym6
+    paddw               ym1, ym2
+    psrlw               ym1, 2              ; 1 2
+    vshufi32x4          ym2, ym0, ym1, 0x01 ; 0 1
+    mova                ym0, ym1
+    psubw               ym1, ym2
+    paddw               ym1, ym1
+    pmulhw              ym1, ym7
+    paddw               ym1, ym2
+    pmulhrsw            ym1, ym8
+    mova          [dstq+dsq*0], xm1
+    vextracti32x4 [dstq+dsq*1], ym1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+    pmullw              ym0, ym4, [srcq+ssq*0+0]
+    pmullw              ym1, ym5, [srcq+ssq*0+2]
+    paddw               ym0, ym6
+    paddw               ym0, ym1
+    psrlw               ym0, 2
+    vinserti32x8         m0, ym0, 1
+.hv_w16_loop:
+    movu                ym1, [srcq+ssq*1+0]
+    movu                ym2, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8         m1, [srcq+ssq*0+0], 1
+    vinserti32x8         m2, [srcq+ssq*0+2], 1
+    pmullw               m1, m4
+    pmullw               m2, m5
+    paddw                m1, m6
+    paddw                m1, m2
+    psrlw                m1, 2             ; 1 2
+    vshufi32x4           m2, m0, m1, q1032 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    paddw                m1, m1
+    pmulhw               m1, m7
+    paddw                m1, m2
+    pmulhrsw             m1, m8
+    mova          [dstq+dsq*0], ym1
+    vextracti32x8 [dstq+dsq*1], m1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    RET
+.hv_w32:
+.hv_w64:
+.hv_w128:
+    movifnidn            wd, wm
+    lea                 r6d, [hq+wq*8-256]
+    mov                  r4, srcq
+    mov                  r7, dstq
+.hv_w32_loop0:
+    pmullw               m0, m4, [srcq+ssq*0+0]
+    pmullw               m1, m5, [srcq+ssq*0+2]
+    paddw                m0, m6
+    paddw                m0, m1
+    psrlw                m0, 2
+.hv_w32_loop:
+    pmullw               m3, m4, [srcq+ssq*1+0]
+    pmullw               m1, m5, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    paddw                m3, m6
+    paddw                m3, m1
+    psrlw                m3, 2
+    psubw                m1, m3, m0
+    paddw                m1, m1
+    pmulhw               m1, m7
+    paddw                m1, m0
+    pmullw               m0, m4, [srcq+ssq*0+0]
+    pmullw               m2, m5, [srcq+ssq*0+2]
+    paddw                m0, m6
+    paddw                m0, m2
+    psrlw                m0, 2
+    psubw                m2, m0, m3
+    paddw                m2, m2
+    pmulhw               m2, m7
+    paddw                m2, m3
+    pmulhrsw             m1, m8
+    pmulhrsw             m2, m8
+    mova       [dstq+dsq*0], m1
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w32_loop
+    add                  r4, 64
+    add                  r7, 64
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+    sub                 r6d, 1<<8
+    jg .hv_w32_loop0
+    RET
+
+cglobal prep_bilin_16bpc, 3, 7, 16, tmp, src, stride, w, h, mxy, stride3
+    movifnidn          mxyd, r5m ; mx
+    lea                  r6, [prep_avx512icl]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r6m ; my
+    test               mxyd, mxyd
+    jnz .v
+.prep:
+    movzx                wd, word [r6+wq*2+table_offset(prep,)]
+    mov                 r5d, r7m ; bitdepth_max
+    vpbroadcastd         m5, [r6-prep_avx512icl+pw_8192]
+    add                  wq, r6
+    shr                 r5d, 11
+    vpbroadcastd         m4, [r6-prep_avx512icl+prep_mul+r5*4]
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.prep_w4:
+    mov                 r3d, 0x0c
+    kmovb                k1, r3d
+.prep_w4_loop:
+    movq                xm0, [srcq+strideq*0]
+    movhps              xm0, [srcq+strideq*1]
+    vpbroadcastq        ym1, [srcq+strideq*2]
+    vpunpcklqdq     ym0{k1}, ym1, [srcq+stride3q] {1to4}
+    lea                srcq, [srcq+strideq*4]
+    pmullw              ym0, ym4
+    psubw               ym0, ym5
+    mova             [tmpq], ym0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .prep_w4_loop
+    RET
+.prep_w8:
+    movu                xm0, [srcq+strideq*0]
+    vinserti32x4        ym0, [srcq+strideq*1], 1
+    vinserti32x4         m0, [srcq+strideq*2], 2
+    vinserti32x4         m0, [srcq+stride3q ], 3
+    lea                srcq, [srcq+strideq*4]
+    pmullw               m0, m4
+    psubw                m0, m5
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .prep_w8
+    RET
+.prep_w16:
+    movu                ym0, [srcq+strideq*0]
+    vinserti32x8         m0, [srcq+strideq*1], 1
+    movu                ym1, [srcq+strideq*2]
+    vinserti32x8         m1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    pmullw               m0, m4
+    pmullw               m1, m4
+    psubw                m0, m5
+    psubw                m1, m5
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    add                tmpq, 64*2
+    sub                  hd, 4
+    jg .prep_w16
+    RET
+.prep_w32:
+    pmullw               m0, m4, [srcq+strideq*0]
+    pmullw               m1, m4, [srcq+strideq*1]
+    pmullw               m2, m4, [srcq+strideq*2]
+    pmullw               m3, m4, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    REPX      {psubw x, m5}, m0, m1, m2, m3
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    sub                  hd, 4
+    jg .prep_w32
+    RET
+.prep_w64:
+    pmullw               m0, m4, [srcq+strideq*0+64*0]
+    pmullw               m1, m4, [srcq+strideq*0+64*1]
+    pmullw               m2, m4, [srcq+strideq*1+64*0]
+    pmullw               m3, m4, [srcq+strideq*1+64*1]
+    lea                srcq, [srcq+strideq*2]
+    REPX      {psubw x, m5}, m0, m1, m2, m3
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    sub                  hd, 2
+    jg .prep_w64
+    RET
+.prep_w128:
+    pmullw               m0, m4, [srcq+64*0]
+    pmullw               m1, m4, [srcq+64*1]
+    pmullw               m2, m4, [srcq+64*2]
+    pmullw               m3, m4, [srcq+64*3]
+    add                srcq, strideq
+    REPX      {psubw x, m5}, m0, m1, m2, m3
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    dec                  hd
+    jg .prep_w128
+    RET
+.h:
+    vpbroadcastw         m5, mxyd
+    mov                mxyd, r6m ; my
+    vpbroadcastd         m4, [pw_16]
+    vpbroadcastd         m6, [pw_32766]
+    psubw                m4, m5
+    test          dword r7m, 0x800
+    jnz .h_12bpc
+    psllw                m4, 2
+    psllw                m5, 2
+.h_12bpc:
+    test               mxyd, mxyd
+    jnz .hv
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_h)]
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.h_w4:
+    movu                xm1, [srcq+strideq*0]
+    vinserti32x4        ym1, [srcq+strideq*2], 1
+    movu                xm2, [srcq+strideq*1]
+    vinserti32x4        ym2, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    punpcklqdq          ym0, ym1, ym2
+    psrldq              ym1, 2
+    psrldq              ym2, 2
+    pmullw              ym0, ym4
+    punpcklqdq          ym1, ym2
+    pmullw              ym1, ym5
+    psubw               ym0, ym6
+    paddw               ym0, ym1
+    psraw               ym0, 2
+    mova             [tmpq], ym0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4
+    RET
+.h_w8:
+    movu                xm0, [srcq+strideq*0+0]
+    movu                xm1, [srcq+strideq*0+2]
+    vinserti32x4        ym0, [srcq+strideq*1+0], 1
+    vinserti32x4        ym1, [srcq+strideq*1+2], 1
+    vinserti32x4         m0, [srcq+strideq*2+0], 2
+    vinserti32x4         m1, [srcq+strideq*2+2], 2
+    vinserti32x4         m0, [srcq+stride3q +0], 3
+    vinserti32x4         m1, [srcq+stride3q +2], 3
+    lea                srcq, [srcq+strideq*4]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    psubw                m0, m6
+    paddw                m0, m1
+    psraw                m0, 2
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .h_w8
+    RET
+.h_w16:
+    movu                ym0, [srcq+strideq*0+0]
+    vinserti32x8         m0, [srcq+strideq*1+0], 1
+    movu                ym1, [srcq+strideq*0+2]
+    vinserti32x8         m1, [srcq+strideq*1+2], 1
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    psubw                m0, m6
+    paddw                m0, m1
+    psraw                m0, 2
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+    pmullw               m0, m4, [srcq+strideq*0+0]
+    pmullw               m2, m5, [srcq+strideq*0+2]
+    pmullw               m1, m4, [srcq+strideq*1+0]
+    pmullw               m3, m5, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    psubw                m0, m6
+    psubw                m1, m6
+    paddw                m0, m2
+    paddw                m1, m3
+    psraw                m0, 2
+    psraw                m1, 2
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    add                tmpq, 64*2
+    sub                  hd, 2
+    jg .h_w32
+    RET
+.h_w64:
+    pmullw               m0, m4, [srcq+ 0]
+    pmullw               m2, m5, [srcq+ 2]
+    pmullw               m1, m4, [srcq+64]
+    pmullw               m3, m5, [srcq+66]
+    add                srcq, strideq
+    psubw                m0, m6
+    psubw                m1, m6
+    paddw                m0, m2
+    paddw                m1, m3
+    psraw                m0, 2
+    psraw                m1, 2
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    add                tmpq, 64*2
+    dec                  hd
+    jg .h_w64
+    RET
+.h_w128:
+    pmullw               m0, m4, [srcq+  0]
+    pmullw               m7, m5, [srcq+  2]
+    pmullw               m1, m4, [srcq+ 64]
+    pmullw               m8, m5, [srcq+ 66]
+    pmullw               m2, m4, [srcq+128]
+    pmullw               m9, m5, [srcq+130]
+    pmullw               m3, m4, [srcq+192]
+    pmullw              m10, m5, [srcq+194]
+    add                srcq, strideq
+    REPX      {psubw x, m6}, m0, m1, m2, m3
+    paddw                m0, m7
+    paddw                m1, m8
+    paddw                m2, m9
+    paddw                m3, m10
+    REPX       {psraw x, 2}, m0, m1, m2, m3
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    dec                  hd
+    jg .h_w128
+    RET
+.v:
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_v)]
+    vpbroadcastw         m9, mxyd
+    vpbroadcastd         m8, [pw_16]
+    vpbroadcastd        m10, [pw_32766]
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    psubw                m8, m9
+    test          dword r7m, 0x800
+    jnz .v_12bpc
+    psllw                m8, 2
+    psllw                m9, 2
+.v_12bpc:
+    jmp                  wq
+.v_w4:
+    movq               xmm0, [srcq+strideq*0]
+.v_w4_loop:
+    vpbroadcastq       xmm2, [srcq+strideq*1]
+    vpbroadcastq       ymm1, [srcq+strideq*2]
+    vpbroadcastq       ymm3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpblendd           ymm2, ymm1, 0x30
+    vpblendd           ymm2, ymm3, 0xc0
+    vpblendd           ymm1, ymm2, ymm0, 0x03 ; 0 1 2 3
+    movq               xmm0, [srcq+strideq*0]
+    valignq            ymm2, ymm0, ymm2, 1    ; 1 2 3 4
+    pmullw             ymm1, ym8
+    pmullw             ymm2, ym9
+    psubw              ymm1, ym10
+    paddw              ymm1, ymm2
+    psraw              ymm1, 2
+    mova             [tmpq], ymm1
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    vzeroupper
+    RET
+.v_w8:
+    movu                xm0, [srcq+strideq*0]
+.v_w8_loop:
+    vinserti32x4        ym1, ym0, [srcq+strideq*1], 1
+    vinserti32x4         m1, [srcq+strideq*2], 2
+    vinserti32x4         m1, [srcq+stride3q ], 3 ; 0 1 2 3
+    lea                srcq, [srcq+strideq*4]
+    movu                xm0, [srcq+strideq*0]
+    valignq              m2, m0, m1, 2           ; 1 2 3 4
+    pmullw               m1, m8
+    pmullw               m2, m9
+    psubw                m1, m10
+    paddw                m1, m2
+    psraw                m1, 2
+    mova             [tmpq], m1
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    movu                ym0, [srcq+strideq*0]
+.v_w16_loop:
+    vinserti32x8         m1, m0, [srcq+strideq*1], 1 ; 0 1
+    movu                ym3, [srcq+strideq*2]
+    vinserti32x8         m2, m3, [srcq+stride3q ], 1 ; 2 3
+    lea                srcq, [srcq+strideq*4]
+    movu                ym0, [srcq+strideq*0]
+    vshufi32x4           m3, m1, m3, q1032           ; 1 2
+    vshufi32x4           m4, m2, m0, q1032           ; 3 4
+    pmullw               m1, m8
+    pmullw               m2, m8
+    pmullw               m3, m9
+    pmullw               m4, m9
+    psubw                m1, m10
+    psubw                m2, m10
+    paddw                m1, m3
+    paddw                m2, m4
+    psraw                m1, 2
+    psraw                m2, 2
+    mova        [tmpq+64*0], m1
+    mova        [tmpq+64*1], m2
+    add                tmpq, 64*2
+    sub                  hd, 4
+    jg .v_w16_loop
+    RET
+.v_w32:
+    movu                 m0, [srcq+strideq*0]
+.v_w32_loop:
+    movu                 m3, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m1, m8, m0
+    movu                 m0, [srcq+strideq*0]
+    pmullw               m2, m8, m3
+    pmullw               m3, m9
+    pmullw               m4, m9, m0
+    psubw                m1, m10
+    psubw                m2, m10
+    paddw                m1, m3
+    paddw                m2, m4
+    psraw                m1, 2
+    psraw                m2, 2
+    mova        [tmpq+64*0], m1
+    mova        [tmpq+64*1], m2
+    add                tmpq, 64*2
+    sub                  hd, 2
+    jg .v_w32_loop
+    RET
+.v_w64:
+    movu                 m0, [srcq+64*0]
+    movu                 m1, [srcq+64*1]
+.v_w64_loop:
+    add                srcq, strideq
+    pmullw               m2, m8, m0
+    movu                 m0, [srcq+64*0]
+    pmullw               m3, m8, m1
+    movu                 m1, [srcq+64*1]
+    pmullw               m4, m9, m0
+    pmullw               m5, m9, m1
+    psubw                m2, m10
+    psubw                m3, m10
+    paddw                m2, m4
+    paddw                m3, m5
+    psraw                m2, 2
+    psraw                m3, 2
+    mova        [tmpq+64*0], m2
+    mova        [tmpq+64*1], m3
+    add                tmpq, 64*2
+    dec                  hd
+    jg .v_w64_loop
+    RET
+.v_w128:
+    movu                 m0, [srcq+64*0]
+    movu                 m1, [srcq+64*1]
+    movu                 m2, [srcq+64*2]
+    movu                 m3, [srcq+64*3]
+.v_w128_loop:
+    add                srcq, strideq
+    pmullw               m4, m8, m0
+    movu                 m0, [srcq+64*0]
+    pmullw               m5, m8, m1
+    movu                 m1, [srcq+64*1]
+    pmullw               m6, m8, m2
+    movu                 m2, [srcq+64*2]
+    pmullw               m7, m8, m3
+    movu                 m3, [srcq+64*3]
+    pmullw              m11, m9, m0
+    pmullw              m12, m9, m1
+    pmullw              m13, m9, m2
+    pmullw              m14, m9, m3
+    REPX     {psubw x, m10}, m4, m5, m6, m7
+    paddw                m4, m11
+    paddw                m5, m12
+    paddw                m6, m13
+    paddw                m7, m14
+    REPX       {psraw x, 2}, m4, m5, m6, m7
+    mova        [tmpq+64*0], m4
+    mova        [tmpq+64*1], m5
+    mova        [tmpq+64*2], m6
+    mova        [tmpq+64*3], m7
+    add                tmpq, 64*4
+    dec                  hd
+    jg .v_w128_loop
+    RET
+.hv:
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_hv)]
+    shl                mxyd, 11
+    vpbroadcastw         m7, mxyd
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.hv_w4:
+    movq               xmm0, [srcq+strideq*0+0]
+    movq               xmm1, [srcq+strideq*0+2]
+    pmullw             xmm0, xm4
+    pmullw             xmm1, xm5
+    psubw              xmm0, xm6
+    paddw              xmm0, xmm1
+    psraw              xmm0, 2
+    vpbroadcastq        ym0, xmm0
+.hv_w4_loop:
+    movu                xm1, [srcq+strideq*1]
+    vinserti128         ym1, [srcq+stride3q ], 1
+    movu                xm2, [srcq+strideq*2]
+    lea                srcq, [srcq+strideq*4]
+    vinserti128         ym2, [srcq+strideq*0], 1
+    punpcklqdq          ym3, ym1, ym2
+    psrldq              ym1, 2
+    psrldq              ym2, 2
+    pmullw              ym3, ym4
+    punpcklqdq          ym1, ym2
+    pmullw              ym1, ym5
+    psubw               ym3, ym6
+    paddw               ym1, ym3
+    psraw               ym1, 2           ; 1 2 3 4
+    valignq             ym2, ym1, ym0, 3 ; 0 1 2 3
+    mova                ym0, ym1
+    psubw               ym1, ym2
+    pmulhrsw            ym1, ym7
+    paddw               ym1, ym2
+    mova             [tmpq], ym1
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    pmullw              xm0, xm4, [srcq+strideq*0+0]
+    pmullw              xm1, xm5, [srcq+strideq*0+2]
+    psubw               xm0, xm6
+    paddw               xm0, xm1
+    psraw               xm0, 2
+    vinserti32x4         m0, xm0, 3
+.hv_w8_loop:
+    movu                xm1, [srcq+strideq*1+0]
+    movu                xm2, [srcq+strideq*1+2]
+    vinserti32x4        ym1, [srcq+strideq*2+0], 1
+    vinserti32x4        ym2, [srcq+strideq*2+2], 1
+    vinserti32x4         m1, [srcq+stride3q +0], 2
+    vinserti32x4         m2, [srcq+stride3q +2], 2
+    lea                srcq, [srcq+strideq*4]
+    vinserti32x4         m1, [srcq+strideq*0+0], 3
+    vinserti32x4         m2, [srcq+strideq*0+2], 3
+    pmullw               m1, m4
+    pmullw               m2, m5
+    psubw                m1, m6
+    paddw                m1, m2
+    psraw                m1, 2         ; 1 2 3 4
+    valignq              m2, m1, m0, 6 ; 0 1 2 3
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhrsw             m1, m7
+    paddw                m1, m2
+    mova             [tmpq], m1
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+    pmullw              ym0, ym4, [srcq+strideq*0+0]
+    pmullw              ym1, ym5, [srcq+strideq*0+2]
+    psubw               ym0, ym6
+    paddw               ym0, ym1
+    psraw               ym0, 2
+    vinserti32x8         m0, ym0, 1
+.hv_w16_loop:
+    movu                ym1, [srcq+strideq*1+0]
+    movu                ym2, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    vinserti32x8         m1, [srcq+strideq*0+0], 1
+    vinserti32x8         m2, [srcq+strideq*0+2], 1
+    pmullw               m1, m4
+    pmullw               m2, m5
+    psubw                m1, m6
+    paddw                m1, m2
+    psraw                m1, 2             ; 1 2
+    vshufi32x4           m2, m0, m1, q1032 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhrsw             m1, m7
+    paddw                m1, m2
+    mova             [tmpq], m1
+    add                tmpq, 64
+    sub                  hd, 2
+    jg .hv_w16_loop
+    RET
+.hv_w32:
+    pmullw               m0, m4, [srcq+strideq*0+0]
+    pmullw               m1, m5, [srcq+strideq*0+2]
+    psubw                m0, m6
+    paddw                m0, m1
+    psraw                m0, 2
+.hv_w32_loop:
+    pmullw               m3, m4, [srcq+strideq*1+0]
+    pmullw               m1, m5, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    psubw                m3, m6
+    paddw                m3, m1
+    psraw                m3, 2
+    psubw                m1, m3, m0
+    pmulhrsw             m1, m7
+    paddw                m1, m0
+    pmullw               m0, m4, [srcq+strideq*0+0]
+    pmullw               m2, m5, [srcq+strideq*0+2]
+    psubw                m0, m6
+    paddw                m0, m2
+    psraw                m0, 2
+    psubw                m2, m0, m3
+    pmulhrsw             m2, m7
+    paddw                m2, m3
+    mova        [tmpq+64*0], m1
+    mova        [tmpq+64*1], m2
+    add                tmpq, 64*2
+    sub                  hd, 2
+    jg .hv_w32_loop
+    RET
+.hv_w64:
+    pmullw               m0, m4, [srcq+ 0]
+    pmullw               m2, m5, [srcq+ 2]
+    pmullw               m1, m4, [srcq+64]
+    pmullw               m3, m5, [srcq+66]
+    psubw                m0, m6
+    psubw                m1, m6
+    paddw                m0, m2
+    paddw                m1, m3
+    psraw                m0, 2
+    psraw                m1, 2
+.hv_w64_loop:
+    add                srcq, strideq
+    pmullw               m2, m4, [srcq+ 0]
+    pmullw               m8, m5, [srcq+ 2]
+    pmullw               m3, m4, [srcq+64]
+    pmullw               m9, m5, [srcq+66]
+    psubw                m2, m6
+    psubw                m3, m6
+    paddw                m2, m8
+    paddw                m3, m9
+    psraw                m2, 2
+    psraw                m3, 2
+    psubw                m8, m2, m0
+    psubw                m9, m3, m1
+    pmulhrsw             m8, m7
+    pmulhrsw             m9, m7
+    paddw                m8, m0
+    mova                 m0, m2
+    paddw                m9, m1
+    mova                 m1, m3
+    mova        [tmpq+64*0], m8
+    mova        [tmpq+64*1], m9
+    add                tmpq, 64*2
+    dec                  hd
+    jg .hv_w64_loop
+    RET
+.hv_w128:
+    pmullw               m0, m4, [srcq+  0]
+    pmullw               m8, m5, [srcq+  2]
+    pmullw               m1, m4, [srcq+ 64]
+    pmullw               m9, m5, [srcq+ 66]
+    pmullw               m2, m4, [srcq+128]
+    pmullw              m10, m5, [srcq+130]
+    pmullw               m3, m4, [srcq+192]
+    pmullw              m11, m5, [srcq+194]
+    REPX      {psubw x, m6}, m0, m1, m2, m3
+    paddw                m0, m8
+    paddw                m1, m9
+    paddw                m2, m10
+    paddw                m3, m11
+    REPX       {psraw x, 2}, m0, m1, m2, m3
+.hv_w128_loop:
+    add                srcq, strideq
+    pmullw               m8, m4, [srcq+  0]
+    pmullw              m12, m5, [srcq+  2]
+    pmullw               m9, m4, [srcq+ 64]
+    pmullw              m13, m5, [srcq+ 66]
+    pmullw              m10, m4, [srcq+128]
+    pmullw              m14, m5, [srcq+130]
+    pmullw              m11, m4, [srcq+192]
+    pmullw              m15, m5, [srcq+194]
+    REPX      {psubw x, m6}, m8, m9, m10, m11
+    paddw                m8, m12
+    paddw                m9, m13
+    paddw               m10, m14
+    paddw               m11, m15
+    REPX       {psraw x, 2}, m8, m9, m10, m11
+    psubw               m12, m8, m0
+    psubw               m13, m9, m1
+    psubw               m14, m10, m2
+    psubw               m15, m11, m3
+    REPX   {pmulhrsw x, m7}, m12, m13, m14, m15
+    paddw               m12, m0
+    mova                 m0, m8
+    paddw               m13, m1
+    mova                 m1, m9
+    mova        [tmpq+64*0], m12
+    mova        [tmpq+64*1], m13
+    paddw               m14, m2
+    mova                 m2, m10
+    paddw               m15, m3
+    mova                 m3, m11
+    mova        [tmpq+64*2], m14
+    mova        [tmpq+64*3], m15
+    add                tmpq, 64*4
+    dec                  hd
+    jg .hv_w128_loop
+    RET
+
+; int8_t subpel_filters[5][15][8]
+%assign FILTER_REGULAR (0*15 << 16) | 3*15
+%assign FILTER_SMOOTH  (1*15 << 16) | 4*15
+%assign FILTER_SHARP   (2*15 << 16) | 3*15
+
+%macro FN 4-5 ; prefix, type, type_h, type_v, jmp_to
+cglobal %1_%2_16bpc
+    mov                 t0d, FILTER_%3
+%ifidn %3, %4
+    mov                 t1d, t0d
+%else
+    mov                 t1d, FILTER_%4
+%endif
+%if %0 == 5 ; skip the jump in the last filter
+    jmp mangle(private_prefix %+ _%5 %+ SUFFIX)
+%endif
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 4, 5
+%define buf rsp+stack_offset+8 ; shadow space
+%else
+DECLARE_REG_TMP 7, 8
+%define buf rsp-40 ; red zone
+%endif
+
+%define PUT_8TAP_FN FN put_8tap,
+PUT_8TAP_FN smooth,         SMOOTH,  SMOOTH,  put_6tap_16bpc
+PUT_8TAP_FN smooth_regular, SMOOTH,  REGULAR, put_6tap_16bpc
+PUT_8TAP_FN regular_smooth, REGULAR, SMOOTH,  put_6tap_16bpc
+PUT_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal put_6tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my
+%define base r8-put_avx512icl
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    lea                  r8, [put_avx512icl]
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.put:
+    tzcnt                wd, wd
+    movzx                wd, word [r8+wq*2+table_offset(put,)]
+    add                  wq, r8
+%if WIN64
+    pop                  r8
+%endif
+    jmp                  wq
+.h_w8:
+    mova                 m4, [spel_h_shufA]
+    movu                 m5, [spel_h_shufB]
+    movu                 m6, [spel_h_shufC]
+.h_w8_loop:
+    movu                ym2, [srcq+ssq*0]
+    vinserti32x8         m2, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    mova                 m0, m8
+    vpermb               m1, m4, m2
+    vpdpwssd             m0, m10, m1
+    vpermb               m1, m5, m2
+    vpdpwssd             m0, m11, m1
+    vpermb               m1, m6, m2
+    vpdpwssd             m0, m12, m1
+    psrad                m0, 6
+    vextracti32x8       ym1, m0, 1
+    packusdw            ym0, ym1
+    pminsw              ym0, ym15
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], ym0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8_loop
+    RET
+.h:
+    vpbroadcastw        m15, r8m
+    test                myd, 0xf00
+    jnz .hv
+    mov                 r7d, r8m
+    shr                 r7d, 11
+    vpbroadcastd         m8, [base+put_8tap_h_rnd+r7*4]
+    cmp                  wd, 4
+    jle mangle(private_prefix %+ _put_8tap_16bpc_avx512icl).h_w4
+    shr                 mxd, 16
+    sub                srcq, 4
+    pmovsxbw           xmm0, [base+subpel_filters+1+mxq*8]
+    mova              [buf], xmm0
+    vpbroadcastd        m10, xmm0
+    vpbroadcastd        m12, [buf+8]
+    vpbroadcastd        m11, [buf+4]
+    sub                  wd, 16
+    jl .h_w8
+    vbroadcasti32x4      m6, [spel_h_shufA]
+    vbroadcasti32x4      m7, [spel_h_shufB]
+    jg .h_w32
+.h_w16_loop:
+    movu                ym2, [srcq+ssq*0+ 0]
+    vinserti32x8         m2, [srcq+ssq*1+ 0], 1
+    movu                ym3, [srcq+ssq*0+12]
+    vinserti32x8         m3, [srcq+ssq*1+12], 1
+    lea                srcq, [srcq+ssq*2]
+    mova                 m0, m8
+    mova                 m1, m8
+    pshufb               m4, m2, m6
+    vpdpwssd             m0, m10, m4 ; a0  b0
+    pshufb               m4, m3, m7
+    vpdpwssd             m1, m12, m4 ; a2' b2'
+    pshufb               m2, m7
+    pshufb               m3, m6
+    vpdpwssd             m0, m11, m2 ; a1  b1
+    vpdpwssd             m1, m11, m3 ; a1' b1'
+    shufpd               m2, m3, 0x55
+    vpdpwssd             m0, m12, m2 ; a2  b2
+    vpdpwssd             m1, m10, m2 ; a0' b0'
+    psrad                m0, 6
+    psrad                m1, 6
+    packusdw             m0, m1
+    pminsw               m0, m15
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16_loop
+    RET
+.h_w32:
+    lea                srcq, [srcq+wq*2]
+    lea                dstq, [dstq+wq*2]
+    neg                  wq
+.h_w32_loop0:
+    mov                  r6, wq
+.h_w32_loop:
+    movu                 m2, [srcq+r6*2+ 0]
+    movu                 m3, [srcq+r6*2+12]
+    mova                 m0, m8
+    mova                 m1, m8
+    pshufb               m4, m2, m6
+    vpdpwssd             m0, m10, m4 ; a0
+    pshufb               m4, m3, m7
+    vpdpwssd             m1, m12, m4 ; b2
+    pshufb               m2, m7
+    pshufb               m3, m6
+    vpdpwssd             m0, m11, m2 ; a1
+    vpdpwssd             m1, m11, m3 ; b1
+    shufpd               m2, m3, 0x55
+    vpdpwssd             m0, m12, m2 ; a2
+    vpdpwssd             m1, m10, m2 ; b0
+    psrad                m0, 6
+    psrad                m1, 6
+    packusdw             m0, m1
+    pminsw               m0, m15
+    mova        [dstq+r6*2], m0
+    add                  r6, 32
+    jl .h_w32_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w32_loop0
+    RET
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastd        m11, [pd_32]
+    pmovsxbw           xmm0, [base+subpel_filters+1+myq*8]
+    tzcnt               r7d, wd
+    vpbroadcastw        m15, r8m
+    mov                  r6, ssq
+    movzx               r7d, word [r8+r7*2+table_offset(put, _6tap_v)]
+    neg                  r6
+    mova [rsp+stack_offset+8], xmm0
+    vpbroadcastd        m12, xmm0
+    add                  r7, r8
+    vpbroadcastd        m13, [rsp+stack_offset+12]
+    vpbroadcastd        m14, [rsp+stack_offset+16]
+    jmp                  r7
+.v_w2:
+    movd               xmm2, [srcq+r6 *2]
+    pinsrd             xmm2, [srcq+r6 *1], 1
+    pinsrd             xmm2, [srcq+ssq*0], 2
+    pinsrd             xmm2, [srcq+ssq*1], 3 ; 0 1 2 3
+    lea                srcq, [srcq+ssq*2]
+    movd               xmm0, [srcq+ssq*0]
+    palignr            xmm3, xmm0, xmm2, 4   ; 1 2 3 4
+    punpcklwd          xmm1, xmm2, xmm3      ; 01 12
+    punpckhwd          xmm2, xmm3            ; 23 34
+.v_w2_loop:
+    movd               xmm3, [srcq+ssq*1]
+    mova               xmm4, xm11
+    vpdpwssd           xmm4, xmm1, xm12      ; a0 b0
+    lea                srcq, [srcq+ssq*2]
+    mova               xmm1, xmm2
+    vpdpwssd           xmm4, xmm2, xm13      ; a1 b1
+    punpckldq          xmm2, xmm0, xmm3      ; 4 5
+    movd               xmm0, [srcq+ssq*0]
+    punpckldq          xmm3, xmm0            ; 5 6
+    punpcklwd          xmm2, xmm3            ; 45 56
+    vpdpwssd           xmm4, xmm2, xm14      ; a2 b2
+    psrad              xmm4, 6
+    packusdw           xmm4, xmm4
+    pminsw             xmm4, xm15
+    movd       [dstq+dsq*0], xmm4
+    pextrd     [dstq+dsq*1], xmm4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movq               xmm1, [srcq+r6 *2]
+    vpbroadcastq       ymm3, [srcq+r6 *1]
+    vpbroadcastq       ymm2, [srcq+ssq*0]
+    vpbroadcastq       ymm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastq       ymm0, [srcq+ssq*0]
+    vpblendd           ymm1, ymm3, 0x30
+    vpblendd           ymm3, ymm2, 0x30
+    punpcklwd          ymm1, ymm3       ; 01 12
+    vpblendd           ymm2, ymm4, 0x30
+    vpblendd           ymm4, ymm0, 0x30
+    punpcklwd          ymm2, ymm4       ; 23 34
+.v_w4_loop:
+    vpbroadcastq       ymm3, [srcq+ssq*1]
+    mova               ymm4, ym11
+    vpdpwssd           ymm4, ymm1, ym12 ; a0 b0
+    lea                srcq, [srcq+ssq*2]
+    mova               ymm1, ymm2
+    vpdpwssd           ymm4, ymm2, ym13 ; a1 b1
+    vpblendd           ymm2, ymm0, ymm3, 0x30
+    vpbroadcastq       ymm0, [srcq+ssq*0]
+    vpblendd           ymm3, ymm0, 0x30
+    punpcklwd          ymm2, ymm3       ; 45 56
+    vpdpwssd           ymm4, ymm2, ym14 ; a2 b2
+    psrad              ymm4, 6
+    vextracti128       xmm3, ymm4, 1
+    packusdw           xmm4, xmm3
+    pminsw             xmm4, xm15
+    movq       [dstq+dsq*0], xmm4
+    movhps     [dstq+dsq*1], xmm4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    vzeroupper
+    RET
+.v_w8:
+    vbroadcasti32x4      m0, [srcq+ssq*0]
+    vinserti32x4         m1, m0, [srcq+r6 *2], 0
+    vinserti32x4         m1, [srcq+r6 *1], 1 ; 0 1 2
+    vinserti32x4        ym0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    mova                 m5, [spel_v_shuf8]
+    vinserti32x4         m0, [srcq+ssq*0], 2 ; 2 3 4
+    vpermb               m1, m5, m1          ; 01 12
+    vpermb               m2, m5, m0          ; 23 34
+.v_w8_loop:
+    vinserti32x4         m0, [srcq+ssq*1], 3
+    lea                srcq, [srcq+ssq*2]
+    movu                xm3, [srcq+ssq*0]
+    mova                 m4, m11
+    vpdpwssd             m4, m12, m1         ; a0 b0
+    vshufi32x4           m0, m3, q1032       ; 4 5 6
+    mova                 m1, m2
+    vpdpwssd             m4, m13, m2         ; a1 b1
+    vpermb               m2, m5, m0          ; 45 56
+    vpdpwssd             m4, m14, m2         ; a2 b2
+    psrad                m4, 6
+    vextracti32x8       ym3, m4, 1
+    packusdw            ym4, ym3
+    pminsw              ym4, ym15
+    mova          [dstq+dsq*0], xm4
+    vextracti32x4 [dstq+dsq*1], ym4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w16:
+    vbroadcasti32x8      m0, [srcq+r6 *1]
+    vinserti32x8         m1, m0, [srcq+ssq*0], 1
+    vinserti32x8         m0, [srcq+r6*2], 0
+    mova                 m6, [spel_v_shuf16]
+    movu                ym3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8         m3, [srcq+ssq*0], 1
+    vpermb               m1, m6, m1     ; 12
+    vpermb               m0, m6, m0     ; 01
+    vpermb               m3, m6, m3     ; 34
+    mova                 m7, [deint_q_shuf]
+    vpshrdd              m2, m1, m3, 16 ; 23
+.v_w16_loop:
+    mova                 m5, m11
+    vpdpwssd             m5, m12, m1    ; b0
+    mova                 m4, m11
+    vpdpwssd             m4, m12, m0    ; a0
+    mova                 m1, m3
+    vpdpwssd             m5, m13, m3    ; b1
+    mova                 m0, m2
+    vpdpwssd             m4, m13, m2    ; a1
+    movu                ym3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8         m3, [srcq+ssq*0], 1
+    vpermb               m3, m6, m3     ; 56
+    vpshrdd              m2, m1, m3, 16 ; 45
+    vpdpwssd             m5, m14, m3    ; b2
+    vpdpwssd             m4, m14, m2    ; a2
+    psrad                m5, 6
+    psrad                m4, 6
+    packusdw             m4, m5
+    pminsw               m4, m15
+    vpermq               m4, m7, m4
+    mova          [dstq+dsq*0], ym4
+    vextracti32x8 [dstq+dsq*1], m4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+.v_w64:
+.v_w128:
+    lea                  wd, [hq+wq*8-256]
+.v_w32_loop0:
+    movu                m16, [srcq+r6 *2]
+    movu                m17, [srcq+r6 *1]
+    lea                  r7, [srcq+ssq*2]
+    movu                m18, [srcq+ssq*0]
+    movu                m19, [srcq+ssq*1]
+    mov                  r8, dstq
+    movu                m20, [r7  +ssq*0]
+    punpcklwd            m0, m16, m17 ; 01
+    punpckhwd           m16, m17
+    punpcklwd            m1, m17, m18 ; 12
+    punpckhwd           m17, m18
+    punpcklwd            m2, m18, m19 ; 23
+    punpckhwd           m18, m19
+    punpcklwd            m3, m19, m20 ; 34
+    punpckhwd           m19, m20
+.v_w32_loop:
+    mova                 m4, m11
+    vpdpwssd             m4, m12, m0  ; a0
+    mova                 m6, m11
+    vpdpwssd             m6, m12, m16
+    mova                 m5, m11
+    vpdpwssd             m5, m12, m1  ; b0
+    mova                 m7, m11
+    vpdpwssd             m7, m12, m17
+    mova                 m0, m2
+    vpdpwssd             m4, m13, m2  ; a1
+    mova                m16, m18
+    vpdpwssd             m6, m13, m18
+    mova                 m1, m3
+    vpdpwssd             m5, m13, m3  ; b1
+    mova                m17, m19
+    vpdpwssd             m7, m13, m19
+    movu                m19, [r7+ssq*1]
+    lea                  r7, [r7+ssq*2]
+    punpcklwd            m2, m20, m19 ; 45
+    punpckhwd           m18, m20, m19
+    movu                m20, [r7+ssq*0]
+    vpdpwssd             m4, m14, m2  ; a2
+    vpdpwssd             m6, m14, m18
+    punpcklwd            m3, m19, m20 ; 56
+    punpckhwd           m19, m20
+    vpdpwssd             m5, m14, m3  ; b2
+    vpdpwssd             m7, m14, m19
+    REPX       {psrad x, 6}, m4, m6, m5, m7
+    packusdw             m4, m6
+    packusdw             m5, m7
+    pminsw               m4, m15
+    pminsw               m5, m15
+    mova         [r8+dsq*0], m4
+    mova         [r8+dsq*1], m5
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .v_w32_loop
+    add                srcq, 64
+    add                dstq, 64
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .v_w32_loop0
+    vzeroupper
+    RET
+.hv:
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    pmovsxbw           xmm1, [base+subpel_filters+1+myq*8]
+    mov                  r6, ssq
+    sub                srcq, 2
+    neg                  r6
+    test          dword r8m, 0x800
+    jnz .hv_12bit
+    vpbroadcastd        m10, [pd_2176]
+    psllw              xmm0, 6
+    jmp .hv_main
+.hv_12bit:
+    vpbroadcastd        m10, [pd_640]
+    psllw              xmm0, 4
+    psllw              xmm1, 2
+.hv_main:
+    movu                xm4, [srcq+r6 *2]
+    vinserti32x4        ym4, [srcq+r6 *1], 1
+    vinserti32x4         m4, [srcq+ssq*0], 2
+    vbroadcasti32x4      m6, [spel_h_shufA]
+    vinserti32x4         m4, [srcq+ssq*1], 3 ; 0 1 2 3
+    lea                srcq, [srcq+ssq*2]
+    movu                xm5, [srcq+ssq*0]    ; 4
+    mova           [buf+ 0], xmm0
+    mova           [buf+16], xmm1
+    vpbroadcastd         m8, [buf+ 4]
+    vpbroadcastd         m9, [buf+ 8]
+    vpbroadcastd       ym12, xmm1
+    vpbroadcastd       ym13, [buf+20]
+    vpbroadcastd       ym14, [buf+24]
+    cmp                  wd, 4
+    je .hv_w4
+    vbroadcasti32x4      m2, [spel_h_shufA]
+    mova                 m3, [spel_h_shuf2b]
+    mova                 m1, m10
+    pshufb               m4, m6
+    pshufb              xm5, xm6
+    punpcklqdq           m2, m4, m5
+    vpdpwssd             m1, m8, m2    ; 04 1_ 2_ 3_
+    mova                ym6, [spel_h_shuf2a]
+    punpckhqdq           m4, m5
+    mova                xm5, [spel_shuf2]
+    vpdpwssd             m1, m9, m4
+    vpermb               m1, m3, m1    ; 01 12
+    vextracti32x4       xm2, ym1, 1    ; 23 34
+.hv_w2_loop:
+    movu                xm3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x4        ym3, [srcq+ssq*0], 1
+    vpermb              ym3, ym6, ym3
+    pmaddwd            xmm0, xm12, xm1 ; a0 b0
+    mova                xm4, xm10
+    vpdpwssd            xm4, xm8, xm3
+    vextracti32x4       xm3, ym3, 1
+    mova                xm1, xm2
+    vpdpwssd           xmm0, xm13, xm2 ; a1 b1
+    vpdpwssd            xm4, xm9, xm3  ; 5 6
+    vpermt2b            xm2, xm5, xm4  ; 45 56
+    vpdpwssd           xmm0, xm14, xm2 ; a2 b2
+    psrad              xmm0, 10
+    packusdw           xmm0, xmm0
+    pminsw             xmm0, xm15
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    vbroadcasti32x4      m7, [spel_h_shufB]
+    mova                ym0, [spel_shuf4a]
+    pshufb               m1, m4, m6
+    mova                 m2, m10
+    vpdpwssd             m2, m8, m1
+    pshufb              xm1, xm5, xm6
+    mova                xm3, xm10
+    vpdpwssd            xm3, xm8, xm1
+    pshufb               m4, m7
+    pshufb              xm5, xm7
+    vpdpwssd             m2, m9, m4    ; 0 1 2 3
+    vpdpwssd            xm3, xm9, xm5  ; 4
+    mova                ym5, [spel_shuf4b]
+    vpermb               m1, m0, m2    ; 01 12
+    vshufi32x4           m2, m3, q1032 ; 2 3 4
+    vpermb               m2, m0, m2    ; 23 34
+.hv_w4_loop:
+    movu                xm3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x4        ym3, [srcq+ssq*0], 1
+    pmaddwd             ym0, ym12, ym1 ; a0 b0
+    mova                ym1, ym2
+    pshufb              ym4, ym3, ym6
+    mova                ym2, ym10
+    vpdpwssd            ym2, ym8, ym4
+    pshufb              ym3, ym7
+    vpdpwssd            ym0, ym13, ym1 ; a1 b1
+    vpdpwssd            ym2, ym9, ym3  ; 5 6
+    vpermt2b            ym2, ym5, ym1  ; 45 56
+    vpdpwssd            ym0, ym14, ym2 ; a2 b2
+    psrad               ym0, 10
+    vextracti32x4       xm4, ym0, 1
+    packusdw            xm0, xm4
+    pminsw             xmm0, xm0, xm15
+    movq       [dstq+dsq*0], xmm0
+    movhps     [dstq+dsq*1], xmm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    pmovsxbw           xmm0, [base+subpel_filters+1+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    pmovsxbw           xmm1, [base+subpel_filters+1+myq*8]
+    mov                  r6, ssq
+    sub                srcq, 4
+    neg                  r6
+    test          dword r8m, 0x800
+    jnz .hv_w8_12bit
+    vpbroadcastd         m8, [pd_2176]
+    psllw              xmm0, 6
+    jmp .hv_w8_main
+.hv_w8_12bit:
+    vpbroadcastd         m8, [pd_640]
+    psllw              xmm0, 4
+    psllw              xmm1, 2
+.hv_w8_main:
+    mova           [buf+ 0], xmm0
+    mova           [buf+16], xmm1
+    vpbroadcastd         m9, xmm0
+    vpbroadcastd        m10, [buf+ 4]
+    vpbroadcastd        m11, [buf+ 8]
+    vpbroadcastd        m12, xmm1
+    vpbroadcastd        m13, [buf+20]
+    vpbroadcastd        m14, [buf+24]
+    cmp                  wd, 16
+    jge .hv_w16
+    mova                 m6, [spel_h_shufA]
+    movu               ym16, [srcq+r6 *2]
+    vinserti32x8        m16, [srcq+r6 *1], 1 ; 0 1
+    movu               ym17, [srcq+ssq*0]
+    vinserti32x8        m17, [srcq+ssq*1], 1 ; 2 3
+    lea                srcq, [srcq+ssq*2]
+    movu               ym18, [srcq+ssq*0]    ; 4
+    movu                 m7, [spel_h_shufC]
+    vpermb               m3, m6, m16
+    mova                 m1, m8
+    vpermb               m4, m6, m17
+    vpdpwssd             m1, m9, m3   ; a0 b0
+    mova                 m2, m8
+    vpermb               m5, m6, m18
+    vpdpwssd             m2, m9, m4   ; c0 d0
+    mova                 m0, m8
+    vpermb              m16, m7, m16
+    vpdpwssd             m0, m9, m5   ; e0
+    vpermb              m17, m7, m17
+    vpdpwssd             m1, m11, m16 ; a2 b2
+    vpermb              m18, m7, m18
+    vpdpwssd             m2, m11, m17 ; c2 d2
+    shufpd               m3, m16, 0x55
+    vpdpwssd             m0, m11, m18 ; e2
+    mova                m16, [spel_shuf8a]
+    shufpd               m4, m17, 0x55
+    vpdpwssd             m1, m10, m3  ; a1 b1
+    shufpd               m5, m18, 0x55
+    vpdpwssd             m2, m10, m4  ; c1 d1
+    vpdpwssd             m0, m10, m5  ; e1
+    mova                 m5, [spel_shuf8b]
+    vpermt2b             m1, m16, m2  ; 01 12
+    vpermt2b             m2, m16, m0  ; 23 34
+.hv_w8_loop:
+    movu               ym18, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8        m18, [srcq+ssq*0], 1
+    mova                 m0, m8
+    vpermb              m17, m6, m18
+    vpdpwssd             m0, m9, m17  ; f0 g0
+    vpermb              m18, m7, m18
+    pmaddwd             m16, m12, m1  ; A0 B0
+    vpdpwssd             m0, m11, m18 ; f2 g2
+    shufpd              m17, m18, 0x55
+    mova                 m1, m2
+    vpdpwssd            m16, m13, m2  ; A1 B1
+    vpdpwssd             m0, m10, m17 ; f1 g1
+    vpermt2b             m2, m5, m0   ; 45 56
+    vpdpwssd            m16, m14, m2  ; A2 B2
+    psrad               m16, 10
+    vextracti32x8      ym17, m16, 1
+    packusdw           ym16, ym17
+    pminsw             ym16, ym15
+    mova         [dstq+dsq*0], xm16
+    vextracti128 [dstq+dsq*1], ym16, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    vzeroupper
+    RET
+.hv_w16:
+    vbroadcasti32x4     m20, [spel_h_shufA]
+    vbroadcasti32x4     m21, [spel_h_shufB]
+    jg .hv_w32
+    vbroadcasti32x8      m6, [srcq+r6 *2+ 8]
+    vinserti32x8         m2, m6, [srcq+r6 *2+16], 1
+    vinserti32x8         m6, [srcq+r6 *2+ 0], 0 ; 0
+    movu               ym16, [srcq+r6 *1+ 0]
+    movu               ym17, [srcq+r6 *1+12]
+    vinserti32x8        m16, [srcq+ssq*0+ 0], 1
+    vinserti32x8        m17, [srcq+ssq*0+12], 1 ; 1 2
+    movu               ym18, [srcq+ssq*1+ 0]
+    movu               ym19, [srcq+ssq*1+12]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8        m18, [srcq+ssq*0+ 0], 1
+    vinserti32x8        m19, [srcq+ssq*0+12], 1 ; 3 4
+    pshufb               m2, m20
+    mova                 m1, m8
+    pshufb               m3, m16, m20
+    vpdpwssd             m1, m11, m2    ; a2
+    mova                 m2, m8
+    pshufb               m4, m17, m21
+    vpdpwssd             m2, m9, m3     ; b0  c0
+    mova                 m3, m8
+    pshufb               m5, m18, m20
+    vpdpwssd             m3, m11, m4    ; b2' c2'
+    mova                 m4, m8
+    pshufb               m7, m19, m21
+    vpdpwssd             m4, m9, m5     ; d0  e0
+    mova                 m5, m8
+    pshufb               m0, m6, m20
+    vpdpwssd             m5, m11, m7    ; d2' e2'
+    mova                 m7, [spel_shuf16]
+    pshufb              m16, m21
+    vpdpwssd             m1, m9, m0     ; a0
+    pshufb              m17, m20
+    vpdpwssd             m2, m10, m16   ; b1  c1
+    pshufb              m18, m21
+    vpdpwssd             m3, m10, m17   ; b1' c1'
+    pshufb              m19, m20
+    vpdpwssd             m4, m10, m18   ; d1  e1
+    pshufb               m6, m21
+    vpdpwssd             m5, m10, m19   ; d1' e1'
+    shufpd              m16, m17, 0x55
+    vpdpwssd             m1, m10, m6    ; a1
+    shufpd              m18, m19, 0x55
+    vpdpwssd             m2, m11, m16   ; b2  c2
+    vpdpwssd             m3, m9, m16    ; b0' c0'
+    vpdpwssd             m4, m11, m18   ; d2  e2
+    vpdpwssd             m5, m9, m18    ; d0' e0'
+    pslldq               m1, 1
+    vpermt2b             m2, m7, m3     ; 12
+    vpermt2b             m4, m7, m5     ; 34
+    vpshrdd              m1, m2, 16     ; 01
+    vpshrdd              m3, m2, m4, 16 ; 23
+.hv_w16_loop:
+    movu               ym18, [srcq+ssq*1+ 0]
+    movu               ym19, [srcq+ssq*1+12]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8        m18, [srcq+ssq*0+ 0], 1
+    vinserti32x8        m19, [srcq+ssq*0+12], 1
+    mova                 m5, m8
+    mova                 m6, m8
+    pshufb              m17, m18, m20
+    vpdpwssd             m5, m9, m17    ; f0  g0
+    pshufb              m16, m19, m21
+    vpdpwssd             m6, m11, m16   ; f2' g2'
+    pmaddwd             m17, m12, m2    ; B0
+    mova                 m2, m4
+    pmaddwd             m16, m12, m1    ; A0
+    mova                 m1, m3
+    pshufb              m18, m21
+    vpdpwssd             m5, m10, m18   ; f1  g1
+    pshufb              m19, m20
+    vpdpwssd             m6, m10, m19   ; f1' g1'
+    vpdpwssd            m17, m13, m4    ; B1
+    vpdpwssd            m16, m13, m3    ; A1
+    shufpd              m18, m19, 0x55
+    vpdpwssd             m5, m11, m18   ; f2  g2
+    vpdpwssd             m6, m9, m18    ; f0' g0'
+    mova                 m4, m7
+    vpermi2b             m4, m5, m6     ; 56
+    vpshrdd              m3, m2, m4, 16 ; 45
+    vpdpwssd            m17, m14, m4    ; B2
+    vpdpwssd            m16, m14, m3    ; A2
+    psrad               m16, 10
+    psrad               m17, 10
+    vshufi32x4          m18, m16, m17, q3232
+    vinserti32x8        m16, ym17, 1
+    packusdw            m16, m18
+    pminsw              m16, m15
+    mova          [dstq+dsq*0], ym16
+    vextracti32x8 [dstq+dsq*1], m16, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    vzeroupper
+    RET
+.hv_w32:
+    WIN64_SPILL_XMM      28
+    mova                m27, [spel_shuf32]
+    lea                  wd, [hq+wq*8-256]
+.hv_w32_loop0:
+    movu                m16, [srcq+r6 *2+ 0]
+    movu                 m7, [srcq+r6 *2+12]
+    movu                 m6, [srcq+r6 *1+ 0]
+    movu                m18, [srcq+r6 *1+12]
+    lea                  r7, [srcq+ssq*2]
+    movu                m17, [srcq+ssq*0+ 0]
+    movu                m19, [srcq+ssq*0+12]
+    movu                m22, [srcq+ssq*1+ 0]
+    movu                m24, [srcq+ssq*1+12]
+    mov                  r8, dstq
+    movu                m23, [r7  +ssq*0+ 0]
+    movu                m25, [r7  +ssq*0+12]
+    pshufb               m1, m16, m20
+    mova                 m0, m8
+    pshufb               m2, m7, m21
+    vpdpwssd             m0, m9, m1     ; a0
+    mova                 m1, m8
+    pshufb               m4, m6, m20
+    vpdpwssd             m1, m11, m2    ; a2'
+    mova                 m2, m8
+    pshufb               m3, m17, m20
+    vpdpwssd             m2, m9, m4     ; b0
+    mova                 m4, m8
+    pshufb               m5, m18, m21
+    vpdpwssd             m4, m9, m3     ; c0
+    mova                 m3, m8
+    pshufb              m26, m19, m21
+    vpdpwssd             m3, m11, m5    ; b2'
+    mova                 m5, m8
+    pshufb              m16, m21
+    vpdpwssd             m5, m11, m26   ; c2'
+    pshufb               m7, m20
+    vpdpwssd             m0, m10, m16   ; a1
+    pshufb               m6, m21
+    vpdpwssd             m1, m10, m7    ; a1'
+    pshufb              m17, m21
+    vpdpwssd             m2, m10, m6    ; b1
+    pshufb              m18, m20
+    vpdpwssd             m4, m10, m17   ; c1
+    pshufb              m19, m20
+    vpdpwssd             m3, m10, m18   ; b1'
+    shufpd              m16, m7, 0x55
+    vpdpwssd             m5, m10, m19   ; c1'
+    shufpd               m6, m18, 0x55
+    vpdpwssd             m0, m11, m16   ; a2
+    shufpd              m17, m19, 0x55
+    vpdpwssd             m1, m9, m16    ; a0'
+    pshufb              m16, m22, m20
+    vpdpwssd             m2, m11, m6    ; b2
+    pshufb               m7, m23, m20
+    vpdpwssd             m4, m11, m17   ; c2
+    vpdpwssd             m3, m9, m6     ; b0'
+    mova                 m6, m8
+    vpdpwssd             m5, m9, m17    ; c0'
+    pshufb              m17, m24, m21
+    vpdpwssd             m6, m9, m16    ; d0
+    mova                m16, m8
+    pshufb              m26, m25, m21
+    vpdpwssd            m16, m9, m7     ; e0
+    mova                 m7, m8
+    pshufb              m22, m21
+    vpdpwssd             m7, m11, m17   ; d2'
+    mova                m17, m8
+    pshufb              m23, m21
+    vpdpwssd            m17, m11, m26   ; e2'
+    pshufb              m24, m20
+    vpdpwssd             m6, m10, m22   ; d1
+    pshufb              m25, m20
+    vpdpwssd            m16, m10, m23   ; e1
+    shufpd              m22, m24, 0x55
+    vpdpwssd             m7, m10, m24   ; d1'
+    shufpd              m23, m25, 0x55
+    vpdpwssd            m17, m10, m25   ; e1'
+    pslldq               m0, 1
+    vpdpwssd             m6, m11, m22   ; d2
+    pslldq               m1, 1
+    vpdpwssd            m16, m11, m23   ; e2
+    vpermt2b             m2, m27, m4    ; 12
+    vpdpwssd             m7, m9, m22    ; d0'
+    vpermt2b             m3, m27, m5    ; 12'
+    vpdpwssd            m17, m9, m23    ; e0'
+    vpshrdd              m0, m2, 16     ; 01
+    vpermt2b             m6, m27, m16   ; 34
+    vpshrdd              m1, m3, 16     ; 01'
+    vpermt2b             m7, m27, m17   ; 34'
+    vpshrdd              m4, m2, m6, 16 ; 23
+    vpshrdd              m5, m3, m7, 16 ; 23'
+.hv_w32_loop:
+    movu                m22, [r7+ssq*1+ 0]
+    movu                m24, [r7+ssq*1+12]
+    lea                  r7, [r7+ssq*2]
+    movu                m23, [r7+ssq*0+ 0]
+    movu                m25, [r7+ssq*0+12]
+    pmaddwd             m17, m12, m2    ; B0
+    mova                 m2, m6
+    pmaddwd             m19, m12, m3    ; B0'
+    mova                 m3, m7
+    pmaddwd             m16, m12, m0    ; A0
+    mova                 m0, m4
+    pmaddwd             m18, m12, m1    ; A0'
+    mova                 m1, m5
+    vpdpwssd            m17, m13, m6    ; B1
+    vpdpwssd            m19, m13, m7    ; B1'
+    mova                 m6, m8
+    vpdpwssd            m16, m13, m4    ; A1
+    pshufb               m4, m22, m20
+    vpdpwssd            m18, m13, m5    ; A1'
+    pshufb               m7, m23, m20
+    vpdpwssd             m6, m9, m4     ; f0
+    mova                 m4, m8
+    pshufb               m5, m24, m21
+    vpdpwssd             m4, m9, m7     ; g0
+    mova                 m7, m8
+    pshufb              m26, m25, m21
+    vpdpwssd             m7, m11, m5    ; f2'
+    mova                 m5, m8
+    pshufb              m22, m21
+    vpdpwssd             m5, m11, m26   ; g2'
+    pshufb              m23, m21
+    vpdpwssd             m6, m10, m22   ; f1
+    pshufb              m24, m20
+    vpdpwssd             m4, m10, m23   ; g1
+    pshufb              m25, m20
+    vpdpwssd             m7, m10, m24   ; f1'
+    shufpd              m22, m24, 0x55
+    vpdpwssd             m5, m10, m25   ; g1'
+    shufpd              m23, m25, 0x55
+    vpdpwssd             m6, m11, m22   ; f2
+    vpdpwssd             m4, m11, m23   ; g2
+    vpdpwssd             m7, m9, m22    ; f0'
+    vpdpwssd             m5, m9, m23    ; g0'
+    vpermt2b             m6, m27, m4    ; 56
+    vpermt2b             m7, m27, m5    ; 56'
+    vpdpwssd            m17, m14, m6    ; B2
+    vpshrdd              m4, m2, m6, 16 ; 45
+    vpdpwssd            m19, m14, m7    ; B2'
+    vpshrdd              m5, m3, m7, 16 ; 45'
+    vpdpwssd            m16, m14, m4    ; A2
+    vpdpwssd            m18, m14, m5    ; A2'
+    REPX      {psrad x, 10}, m17, m19, m16, m18
+    packusdw            m17, m19
+    packusdw            m16, m18
+    pminsw              m17, m15
+    pminsw              m16, m15
+    mova         [r8+dsq*0], m16
+    mova         [r8+dsq*1], m17
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .hv_w32_loop
+    add                srcq, 64
+    add                dstq, 64
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .hv_w32_loop0
+    RET
+
+PUT_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_16bpc
+PUT_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  put_8tap_16bpc
+PUT_8TAP_FN regular_sharp,  REGULAR, SHARP,   put_8tap_16bpc
+PUT_8TAP_FN sharp_regular,  SHARP,   REGULAR, put_8tap_16bpc
+PUT_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    lea                  r8, [put_avx512icl]
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _put_6tap_16bpc_avx512icl).put
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastd        m10, [pd_32]
+    pmovsxbw           xmm0, [base+subpel_filters+myq*8]
+    tzcnt               r7d, wd
+    vpbroadcastw        m11, r8m
+    lea                  r6, [ssq*3]
+    movzx               r7d, word [r8+r7*2+table_offset(put, _8tap_v)]
+    sub                srcq, r6
+    mova [rsp+stack_offset+8], xmm0
+    vpbroadcastd        m12, xmm0
+    add                  r7, r8
+    vpbroadcastd        m13, [rsp+stack_offset+12]
+    vpbroadcastd        m14, [rsp+stack_offset+16]
+    vpbroadcastd        m15, [rsp+stack_offset+20]
+    jmp                  r7
+.v_w2:
+    movd               xmm2, [srcq+ssq*0]
+    pinsrd             xmm2, [srcq+ssq*1], 1
+    pinsrd             xmm2, [srcq+ssq*2], 2
+    add                srcq, r6
+    pinsrd             xmm2, [srcq+ssq*0], 3  ; 0 1 2 3
+    movd               xmm3, [srcq+ssq*1]
+    vpbroadcastd       xmm1, [srcq+ssq*2]
+    add                srcq, r6
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm3, xmm1, 0x02       ; 4 5
+    vpblendd           xmm1, xmm0, 0x02       ; 5 6
+    palignr            xmm4, xmm3, xmm2, 4    ; 1 2 3 4
+    punpcklwd          xmm3, xmm1             ; 45 56
+    punpcklwd          xmm1, xmm2, xmm4       ; 01 12
+    punpckhwd          xmm2, xmm4             ; 23 34
+.v_w2_loop:
+    vpbroadcastd       xmm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova               xmm5, xm10
+    vpdpwssd           xmm5, xm12, xmm1       ; a0 b0
+    mova               xmm1, xmm2
+    vpdpwssd           xmm5, xm13, xmm2       ; a1 b1
+    mova               xmm2, xmm3
+    vpdpwssd           xmm5, xm14, xmm3       ; a2 b2
+    vpblendd           xmm3, xmm0, xmm4, 0x02 ; 6 7
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm4, xmm0, 0x02       ; 7 8
+    punpcklwd          xmm3, xmm4             ; 67 78
+    vpdpwssd           xmm5, xm15, xmm3       ; a3 b3
+    psrad              xmm5, 6
+    packusdw           xmm5, xmm5
+    pminsw             xmm5, xm11
+    movd       [dstq+dsq*0], xmm5
+    pextrd     [dstq+dsq*1], xmm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movq               xmm1, [srcq+ssq*0]
+    vpbroadcastq       ymm0, [srcq+ssq*1]
+    vpbroadcastq       ymm2, [srcq+ssq*2]
+    add                srcq, r6
+    vpbroadcastq       ymm4, [srcq+ssq*0]
+    vpbroadcastq       ymm3, [srcq+ssq*1]
+    vpbroadcastq       ymm5, [srcq+ssq*2]
+    add                srcq, r6
+    vpblendd           ymm1, ymm0, 0x30
+    vpblendd           ymm0, ymm2, 0x30
+    punpcklwd          ymm1, ymm0       ; 01 12
+    vpbroadcastq       ymm0, [srcq+ssq*0]
+    vpblendd           ymm2, ymm4, 0x30
+    vpblendd           ymm4, ymm3, 0x30
+    punpcklwd          ymm2, ymm4       ; 23 34
+    vpblendd           ymm3, ymm5, 0x30
+    vpblendd           ymm5, ymm0, 0x30
+    punpcklwd          ymm3, ymm5       ; 45 56
+.v_w4_loop:
+    vpbroadcastq       ymm5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova               ymm4, ym10
+    vpdpwssd           ymm4, ym12, ymm1 ; a0 b0
+    mova               ymm1, ymm2
+    vpdpwssd           ymm4, ym13, ymm2 ; a1 b1
+    mova               ymm2, ymm3
+    vpdpwssd           ymm4, ym14, ymm3 ; a2 b2
+    vpblendd           ymm3, ymm0, ymm5, 0x30
+    vpbroadcastq       ymm0, [srcq+ssq*0]
+    vpblendd           ymm5, ymm0, 0x30
+    punpcklwd          ymm3, ymm5       ; 67 78
+    vpdpwssd           ymm4, ym15, ymm3 ; a3 b3
+    psrad              ymm4, 6
+    vextracti128       xmm5, ymm4, 1
+    packusdw           xmm4, xmm5
+    pminsw             xmm4, xm11
+    movq       [dstq+dsq*0], xmm4
+    movhps     [dstq+dsq*1], xmm4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    vzeroupper
+    RET
+.v_w8:
+    vbroadcasti32x4      m2, [srcq+ssq*2]
+    vinserti32x4         m1, m2, [srcq+ssq*0], 0
+    vinserti32x4         m1, [srcq+ssq*1], 1 ; 0 1 2
+    add                srcq, r6
+    vinserti32x4        ym2, [srcq+ssq*0], 1
+    vinserti32x4         m2, [srcq+ssq*1], 2 ; 2 3 4
+    mova                 m6, [spel_v_shuf8]
+    movu                xm0, [srcq+ssq*1]
+    vinserti32x4        ym0, [srcq+ssq*2], 1
+    add                srcq, r6
+    vinserti32x4         m0, [srcq+ssq*0], 2 ; 4 5 6
+    vpermb               m1, m6, m1          ; 01 12
+    vpermb               m2, m6, m2          ; 23 34
+    vpermb               m3, m6, m0          ; 45 56
+.v_w8_loop:
+    vinserti32x4         m0, [srcq+ssq*1], 3
+    lea                srcq, [srcq+ssq*2]
+    movu                xm5, [srcq+ssq*0]
+    mova                 m4, m10
+    vpdpwssd             m4, m12, m1         ; a0 b0
+    mova                 m1, m2
+    vshufi32x4           m0, m5, q1032       ; 6 7 8
+    vpdpwssd             m4, m13, m2         ; a1 b1
+    mova                 m2, m3
+    vpdpwssd             m4, m14, m3         ; a2 b2
+    vpermb               m3, m6, m0          ; 67 78
+    vpdpwssd             m4, m15, m3         ; a3 b3
+    psrad                m4, 6
+    vextracti32x8       ym5, m4, 1
+    packusdw            ym4, ym5
+    pminsw              ym4, ym11
+    mova          [dstq+dsq*0], xm4
+    vextracti32x4 [dstq+dsq*1], ym4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w16:
+    vbroadcasti32x8      m0, [srcq+ssq*1]
+    vinserti32x8         m1, m0, [srcq+ssq*2], 1
+    vinserti32x8         m0, [srcq+ssq*0], 0
+    mova                 m8, [spel_v_shuf16]
+    add                srcq, r6
+    movu                ym3, [srcq+ssq*0]
+    vinserti32x8         m3, [srcq+ssq*1], 1
+    movu                ym5, [srcq+ssq*2]
+    add                srcq, r6
+    vinserti32x8         m5, [srcq+ssq*0], 1
+    vpermb               m1, m8, m1     ; 12
+    vpermb               m0, m8, m0     ; 01
+    vpermb               m3, m8, m3     ; 34
+    vpermb               m5, m8, m5     ; 56
+    mova                 m9, [deint_q_shuf]
+    vpshrdd              m2, m1, m3, 16 ; 23
+    vpshrdd              m4, m3, m5, 16 ; 45
+.v_w16_loop:
+    mova                 m7, m10
+    vpdpwssd             m7, m12, m1    ; b0
+    mova                 m6, m10
+    vpdpwssd             m6, m12, m0    ; a0
+    mova                 m1, m3
+    vpdpwssd             m7, m13, m3    ; b1
+    mova                 m0, m2
+    vpdpwssd             m6, m13, m2    ; a1
+    mova                 m3, m5
+    vpdpwssd             m7, m14, m5    ; b2
+    mova                 m2, m4
+    vpdpwssd             m6, m14, m4    ; a2
+    movu                ym5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8         m5, [srcq+ssq*0], 1
+    vpermb               m5, m8, m5     ; 78
+    vpshrdd              m4, m3, m5, 16 ; 67
+    vpdpwssd             m7, m15, m5    ; b3
+    vpdpwssd             m6, m15, m4    ; a3
+    psrad                m7, 6
+    psrad                m6, 6
+    packusdw             m6, m7
+    pminsw               m6, m11
+    vpermq               m6, m9, m6
+    mova          [dstq+dsq*0], ym6
+    vextracti32x8 [dstq+dsq*1], m6, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+.v_w64:
+.v_w128:
+    WIN64_SPILL_XMM      23
+    lea                  wd, [hq+wq*8-256]
+.v_w32_loop0:
+    movu                m16, [srcq+ssq*0]
+    movu                m17, [srcq+ssq*1]
+    lea                  r7, [srcq+r6   ]
+    movu                m18, [srcq+ssq*2]
+    movu                m19, [r7  +ssq*0]
+    mov                  r8, dstq
+    movu                m20, [r7  +ssq*1]
+    movu                m21, [r7  +ssq*2]
+    add                  r7, r6
+    movu                m22, [r7  +ssq*0]
+    punpcklwd            m0, m16, m17 ; 01l
+    punpckhwd           m16, m17      ; 01h
+    punpcklwd            m1, m17, m18 ; 12l
+    punpckhwd           m17, m18      ; 12h
+    punpcklwd            m2, m18, m19 ; 23l
+    punpckhwd           m18, m19      ; 23h
+    punpcklwd            m3, m19, m20 ; 34l
+    punpckhwd           m19, m20      ; 34h
+    punpcklwd            m4, m20, m21 ; 45l
+    punpckhwd           m20, m21      ; 45h
+    punpcklwd            m5, m21, m22 ; 56l
+    punpckhwd           m21, m22      ; 56h
+.v_w32_loop:
+    mova                 m6, m10
+    vpdpwssd             m6, m12, m0  ; a0l
+    mova                 m8, m10
+    vpdpwssd             m8, m12, m16 ; a0h
+    mova                 m7, m10
+    vpdpwssd             m7, m12, m1  ; b0l
+    mova                 m9, m10
+    vpdpwssd             m9, m12, m17 ; b0h
+    mova                 m0, m2
+    vpdpwssd             m6, m13, m2  ; a1l
+    mova                m16, m18
+    vpdpwssd             m8, m13, m18 ; a1h
+    mova                 m1, m3
+    vpdpwssd             m7, m13, m3  ; b1l
+    mova                m17, m19
+    vpdpwssd             m9, m13, m19 ; b1h
+    mova                 m2, m4
+    vpdpwssd             m6, m14, m4  ; a2l
+    mova                m18, m20
+    vpdpwssd             m8, m14, m20 ; a2h
+    mova                 m3, m5
+    vpdpwssd             m7, m14, m5  ; b2l
+    mova                m19, m21
+    vpdpwssd             m9, m14, m21 ; b2h
+    movu                m21, [r7+ssq*1]
+    lea                  r7, [r7+ssq*2]
+    punpcklwd            m4, m22, m21 ; 67l
+    punpckhwd           m20, m22, m21 ; 67h
+    movu                m22, [r7+ssq*0]
+    vpdpwssd             m6, m15, m4  ; a3l
+    vpdpwssd             m8, m15, m20 ; a3h
+    punpcklwd            m5, m21, m22 ; 78l
+    punpckhwd           m21, m22      ; 78h
+    vpdpwssd             m7, m15, m5  ; b3l
+    vpdpwssd             m9, m15, m21 ; b3h
+    REPX       {psrad x, 6}, m6, m8, m7, m9
+    packusdw             m6, m8
+    packusdw             m7, m9
+    pminsw               m6, m11
+    pminsw               m7, m11
+    mova         [r8+dsq*0], m6
+    mova         [r8+dsq*1], m7
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .v_w32_loop
+    add                srcq, 64
+    add                dstq, 64
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .v_w32_loop0
+    RET
+.h_w2:
+    RESET_STACK_STATE
+    mova                ym2, [spel_h_shuf2a]
+    sub                srcq, 2
+    pshufd             xmm3, xmm0, q1111
+    pshufd             xmm4, xmm0, q2222
+.h_w2_loop:
+    movu                xm1, [srcq+ssq*0]
+    vinserti32x4        ym1, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    mova               xmm0, xm8
+    vpermb              ym1, ym2, ym1
+    vpdpwssd           xmm0, xmm3, xm1
+    vextracti32x4       xm1, ym1, 1
+    vpdpwssd           xmm0, xmm4, xm1
+    psrad              xmm0, 6
+    packusdw           xmm0, xmm0
+    pminsw             xmm0, xm15
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2_loop
+    RET
+.h_w4:
+    movzx               mxd, mxb
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    jl .h_w2
+    vbroadcasti32x4     ym4, [spel_h_shufA]
+    vbroadcasti32x4     ym5, [spel_h_shufB]
+    sub                srcq, 2
+    pshufd             xmm0, xmm0, q2211
+    vpbroadcastq        ym6, xmm0
+    vpermq              ym7, ymm0, q1111
+.h_w4_loop:
+    movu                xm2, [srcq+ssq*0]
+    vinserti32x4        ym2, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    mova                ym0, ym8
+    pshufb              ym1, ym2, ym4
+    vpdpwssd            ym0, ym6, ym1
+    pshufb              ym2, ym5
+    vpdpwssd            ym0, ym7, ym2
+    psrad               ym0, 6
+    vextracti32x4       xm1, ym0, 1
+    packusdw            xm0, xm1
+    pminsw             xmm0, xm0, xm15
+    movq       [dstq+dsq*0], xmm0
+    movhps     [dstq+dsq*1], xmm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h_w8:
+    mova                 m4, [spel_h_shufA]
+    movu                 m5, [spel_h_shufB]
+    movu                 m6, [spel_h_shufC]
+    mova                 m7, [spel_h_shufD]
+.h_w8_loop:
+    movu                ym2, [srcq+ssq*0]
+    vinserti32x8         m2, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    mova                 m0, m8
+    vpermb               m1, m4, m2
+    vpdpwssd             m0, m10, m1
+    vpermb               m1, m5, m2
+    vpdpwssd             m0, m11, m1
+    vpermb               m1, m6, m2
+    vpdpwssd             m0, m12, m1
+    vpermb               m1, m7, m2
+    vpdpwssd             m0, m13, m1
+    psrad                m0, 6
+    vextracti32x8       ym1, m0, 1
+    packusdw            ym0, ym1
+    pminsw              ym0, ym15
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], ym0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8_loop
+    RET
+.h:
+    vpbroadcastw        m15, r8m
+    test                myd, 0xf00
+    jnz .hv
+    mov                 r7d, r8m
+    shr                 r7d, 11
+    vpbroadcastd         m8, [base+put_8tap_h_rnd+r7*4]
+    cmp                  wd, 4
+    jle .h_w4
+    shr                 mxd, 16
+    sub                srcq, 6
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    mova              [buf], xmm0
+    vpbroadcastd        m10, xmm0
+    vpbroadcastd        m11, [buf+ 4]
+    vpbroadcastd        m12, [buf+ 8]
+    vpbroadcastd        m13, [buf+12]
+    sub                  wd, 16
+    jl .h_w8
+    vbroadcasti32x4      m6, [spel_h_shufA]
+    vbroadcasti32x4      m7, [spel_h_shufB]
+    jg .h_w32
+.h_w16_loop:
+    movu                ym2, [srcq+ssq*0+ 0]
+    vinserti32x8         m2, [srcq+ssq*1+ 0], 1
+    movu                ym3, [srcq+ssq*0+16]
+    vinserti32x8         m3, [srcq+ssq*1+16], 1
+    lea                srcq, [srcq+ssq*2]
+    mova                 m0, m8
+    mova                 m1, m8
+    pshufb               m4, m2, m6
+    vpdpwssd             m0, m10, m4 ; a0
+    pshufb               m4, m3, m6
+    vpdpwssd             m1, m12, m4 ; b2
+    pshufb               m4, m2, m7
+    vpdpwssd             m0, m11, m4 ; a1
+    pshufb               m4, m3, m7
+    vpdpwssd             m1, m13, m4 ; b3
+    shufpd               m2, m3, 0x55
+    pshufb               m4, m2, m6
+    vpdpwssd             m0, m12, m4 ; a2
+    vpdpwssd             m1, m10, m4 ; b0
+    pshufb               m2, m7
+    vpdpwssd             m0, m13, m2 ; a3
+    vpdpwssd             m1, m11, m2 ; b1
+    psrad                m0, 6
+    psrad                m1, 6
+    packusdw             m0, m1
+    pminsw               m0, m15
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16_loop
+    RET
+.h_w32:
+    lea                srcq, [srcq+wq*2]
+    lea                dstq, [dstq+wq*2]
+    neg                  wq
+.h_w32_loop0:
+    mov                  r6, wq
+.h_w32_loop:
+    movu                 m2, [srcq+r6*2+ 0]
+    movu                 m3, [srcq+r6*2+ 8]
+    mova                 m0, m8
+    mova                 m1, m8
+    pshufb               m4, m2, m6
+    vpdpwssd             m0, m10, m4 ; a0
+    pshufb               m4, m3, m6
+    vpdpwssd             m1, m10, m4 ; b0
+    vpdpwssd             m0, m12, m4 ; a2
+    movu                 m4, [srcq+r6*2+16]
+    pshufb               m3, m7
+    vpdpwssd             m1, m11, m3 ; b1
+    vpdpwssd             m0, m13, m3 ; a3
+    pshufb               m3, m4, m6
+    vpdpwssd             m1, m12, m3 ; b2
+    pshufb               m2, m7
+    vpdpwssd             m0, m11, m2 ; a1
+    pshufb               m4, m7
+    vpdpwssd             m1, m13, m4 ; b3
+    psrad                m0, 6
+    psrad                m1, 6
+    packusdw             m0, m1
+    pminsw               m0, m15
+    mova        [dstq+r6*2], m0
+    add                  r6, 32
+    jl .h_w32_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w32_loop0
+    RET
+.hv:
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    pmovsxbw           xmm1, [base+subpel_filters+myq*8]
+    lea                  r6, [ssq*3]
+    sub                srcq, 2
+    sub                srcq, r6
+    test          dword r8m, 0x800
+    jnz .hv_12bit
+    vpbroadcastd        m10, [pd_2176]
+    psllw              xmm0, 6
+    jmp .hv_main
+.hv_12bit:
+    vpbroadcastd        m10, [pd_640]
+    psllw              xmm0, 4
+    psllw              xmm1, 2
+.hv_main:
+    mova           [buf+ 0], xmm0
+    mova           [buf+16], xmm1
+    vpbroadcastd         m8, [buf+ 4]
+    vpbroadcastd         m9, [buf+ 8]
+    vpbroadcastd       ym11, xmm1
+    vpbroadcastd       ym12, [buf+20]
+    vpbroadcastd       ym13, [buf+24]
+    vpbroadcastd       ym14, [buf+28]
+    movu                xm4, [srcq+ssq*0]
+    vinserti32x4        ym4, [srcq+ssq*1], 1
+    vinserti32x4         m4, [srcq+ssq*2], 2
+    add                srcq, r6
+    vinserti32x4         m4, [srcq+ssq*0], 3 ; 0 1 2 3
+    movu                xm0, [srcq+ssq*1]
+    vinserti32x4        ym0, [srcq+ssq*2], 1
+    add                srcq, r6
+    vinserti32x4         m0, [srcq+ssq*0], 2 ; 4 5 6
+    cmp                  wd, 4
+    je .hv_w4
+    vbroadcasti32x4      m2, [spel_h_shufA]
+    mova                 m3, [spel_h_shuf2b]
+    mova                ym6, [spel_h_shuf2a]
+    mova                xm7, [spel_shuf2]
+    mova                 m1, m10
+    pshufb               m4, m2
+    pshufb               m0, m2
+    punpcklqdq           m2, m4, m0
+    vpdpwssd             m1, m8, m2    ; 04 15 26 3_
+    punpckhqdq           m4, m0
+    vpdpwssd             m1, m9, m4
+    vpermb               m1, m3, m1    ; 01 12
+    vextracti32x4       xm2, ym1, 1    ; 23 34
+    vextracti32x4       xm3, m1, 2     ; 45 56
+.hv_w2_loop:
+    movu                xm5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x4        ym5, [srcq+ssq*0], 1
+    mova                xm4, xm10
+    vpermb              ym5, ym6, ym5
+    pmaddwd            xmm0, xm11, xm1 ; a0 b0
+    vpdpwssd            xm4, xm8, xm5
+    vextracti32x4       xm5, ym5, 1
+    mova                xm1, xm2
+    vpdpwssd           xmm0, xm12, xm2 ; a1 b1
+    vpdpwssd            xm4, xm9, xm5  ; 7 8
+    mova                xm2, xm3
+    vpdpwssd           xmm0, xm13, xm3 ; a2 b2
+    vpermt2b            xm3, xm7, xm4  ; 67 78
+    vpdpwssd           xmm0, xm14, xm3 ; a3 b3
+    psrad              xmm0, 10
+    packusdw           xmm0, xmm0
+    pminsw             xmm0, xm15
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    vbroadcasti32x4     m19, [spel_h_shufA]
+    vbroadcasti32x4     m20, [spel_h_shufB]
+    mova                ym6, [spel_shuf4a]
+    mova                ym7, [spel_shuf4b]
+    mova                 m2, m10
+    mova                 m3, m10
+    pshufb               m1, m4, m19
+    vpdpwssd             m2, m8, m1
+    pshufb               m1, m0, m19
+    vpdpwssd             m3, m8, m1
+    pshufb               m4, m20
+    vpdpwssd             m2, m9, m4
+    pshufb               m0, m20
+    vpdpwssd             m3, m9, m0
+    vpermb               m1, m6, m2    ; 01 12
+    vshufi32x4           m2, m3, q1032
+    vpermb               m3, m6, m3    ; 45 56
+    vpermb               m2, m6, m2    ; 23 34
+.hv_w4_loop:
+    movu               xm18, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti128        ym18, [srcq+ssq*0], 1
+    pmaddwd            ym16, ym11, ym1 ; a0 b0
+    mova                ym1, ym2
+    mova                ym2, ym3
+    pshufb             ym17, ym18, ym19
+    mova                ym3, ym10
+    vpdpwssd            ym3, ym8, ym17
+    pshufb             ym18, ym20
+    vpdpwssd           ym16, ym12, ym1 ; a1 b1
+    vpdpwssd            ym3, ym9, ym18 ; 7 8
+    vpdpwssd           ym16, ym13, ym2 ; a2 b2
+    vpermt2b            ym3, ym7, ym2  ; 67 78
+    vpdpwssd           ym16, ym14, ym3 ; a3 b3
+    psrad              ym16, 10
+    vextracti128       xm17, ym16, 1
+    packusdw           xm16, xm17
+    pminsw             xm16, xm15
+    movq       [dstq+dsq*0], xm16
+    movhps     [dstq+dsq*1], xm16
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    vzeroupper
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    pmovsxbw           xmm1, [base+subpel_filters+myq*8]
+    lea                  r6, [ssq*3]
+    sub                srcq, 6
+    sub                srcq, r6
+    test          dword r8m, 0x800
+    jnz .hv_w8_12bit
+    vpbroadcastd        m10, [pd_2176]
+    psllw              xmm0, 6
+    jmp .hv_w8_main
+.hv_w8_12bit:
+    vpbroadcastd        m10, [pd_640]
+    psllw              xmm0, 4
+    psllw              xmm1, 2
+.hv_w8_main:
+    mova           [buf+ 0], xmm0
+    mova           [buf+16], xmm1
+    vpbroadcastd        m11, xmm0
+    vpbroadcastd        m12, [buf+ 4]
+    vpbroadcastd        m13, [buf+ 8]
+    vpbroadcastd        m14, [buf+12]
+    vpbroadcastd        m16, xmm1
+    vpbroadcastd        m17, [buf+20]
+    vpbroadcastd        m18, [buf+24]
+    vpbroadcastd        m19, [buf+28]
+    cmp                  wd, 8
+    jg .hv_w16
+    mova                 m5, [spel_h_shufA]
+    movu                ym0, [srcq+ssq*0]
+    vinserti32x8         m0, [srcq+ssq*1], 1 ; 0 1
+    movu                ym9, [srcq+ssq*2]
+    add                srcq, r6
+    vinserti32x8         m9, [srcq+ssq*0], 1 ; 2 3
+    movu               ym20, [srcq+ssq*1]
+    vinserti32x8        m20, [srcq+ssq*2], 1 ; 4 5
+    add srcq, r6
+    movu               ym21, [srcq+ssq*0]    ; 6
+    movu                 m6, [spel_h_shufB]
+    movu                 m7, [spel_h_shufC]
+    vpermb               m8, m5, m0
+    mova                 m1, m10
+    vpdpwssd             m1, m11, m8  ; a0 b0
+    vpermb               m8, m5, m9
+    mova                 m2, m10
+    vpdpwssd             m2, m11, m8  ; c0 d0
+    vpermb               m8, m5, m20
+    mova                 m3, m10
+    vpdpwssd             m3, m11, m8  ; e0 f0
+    vpermb               m8, m5, m21
+    mova                 m4, m10
+    vpdpwssd             m4, m11, m8  ; g0
+    vpermb               m8, m6, m0
+    vpdpwssd             m1, m12, m8  ; a1 b1
+    vpermb               m8, m6, m9
+    vpdpwssd             m2, m12, m8  ; c1 d1
+    vpermb               m8, m6, m20
+    vpdpwssd             m3, m12, m8  ; e1 f1
+    vpermb               m8, m6, m21
+    vpdpwssd             m4, m12, m8  ; g1
+    vpermb               m8, m7, m0
+    vpdpwssd             m1, m13, m8  ; a2 b2
+    vpermb               m8, m7, m9
+    vpdpwssd             m2, m13, m8  ; c2 d2
+    vpermb               m8, m7, m20
+    vpdpwssd             m3, m13, m8  ; e2 f2
+    vpermb               m8, m7, m21
+    vpdpwssd             m4, m13, m8  ; g2
+    mova                 m8, [spel_h_shufD]
+    vpermb               m0, m8, m0
+    vpdpwssd             m1, m14, m0  ; a3 b3
+    mova                 m0, [spel_shuf8a]
+    vpermb               m9, m8, m9
+    vpdpwssd             m2, m14, m9  ; c3 d3
+    mova                 m9, [spel_shuf8b]
+    vpermb              m20, m8, m20
+    vpdpwssd             m3, m14, m20 ; e3 f3
+    vpermb              m21, m8, m21
+    vpdpwssd             m4, m14, m21 ; g3
+    vpermt2b             m1, m0, m2   ; 01 12
+    vpermt2b             m2, m0, m3   ; 23 34
+    vpermt2b             m3, m0, m4   ; 45 56
+.hv_w8_loop:
+    movu                ym0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8         m0, [srcq+ssq*0], 1
+    mova                 m4, m10
+    vpermb              m21, m5, m0
+    vpdpwssd             m4, m11, m21 ; h0 i0
+    vpermb              m21, m6, m0
+    pmaddwd             m20, m16, m1  ; A0 B0
+    vpdpwssd             m4, m12, m21 ; h1 i1
+    vpermb              m21, m7, m0
+    mova                 m1, m2
+    vpdpwssd            m20, m17, m2  ; A1 B1
+    vpdpwssd             m4, m13, m21 ; h2 i2
+    vpermb              m21, m8, m0
+    mova                 m2, m3
+    vpdpwssd            m20, m18, m3  ; A2 B2
+    vpdpwssd             m4, m14, m21 ; h3 i3
+    vpermt2b             m3, m9, m4   ; 67 78
+    vpdpwssd            m20, m19, m3  ; A3 B3
+    psrad               m20, 10
+    vextracti32x8      ym21, m20, 1
+    packusdw           ym20, ym21
+    pminsw             ym20, ym15
+    mova         [dstq+dsq*0], xm20
+    vextracti128 [dstq+dsq*1], ym20, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    vzeroupper
+    RET
+.hv_w16:
+    WIN64_SPILL_XMM 26
+    vbroadcasti32x4     m20, [spel_h_shufA]
+    vbroadcasti32x4     m21, [spel_h_shufB]
+    add                  wd, wd
+    mova                 m9, [spel_shuf16]
+    lea                  wd, [hq+wq*8-256]
+.hv_w16_loop0:
+    vbroadcasti32x8      m5, [srcq+ssq*0+ 8]
+    vinserti32x8         m4, m5, [srcq+ssq*0+ 0], 0
+    vinserti32x8         m5, [srcq+ssq*0+16], 1 ; 0
+    movu                ym6, [srcq+ssq*1+ 0]
+    movu                ym7, [srcq+ssq*1+16]
+    lea                  r7, [srcq+r6]
+    vinserti32x8         m6, [srcq+ssq*2+ 0], 1
+    vinserti32x8         m7, [srcq+ssq*2+16], 1 ; 1 2
+    movu               ym22, [r7  +ssq*0+ 0]
+    movu               ym23, [r7  +ssq*0+16]
+    mov                  r8, dstq
+    vinserti32x8        m22, [r7  +ssq*1+ 0], 1
+    vinserti32x8        m23, [r7  +ssq*1+16], 1 ; 3 4
+    movu               ym24, [r7  +ssq*2+ 0]
+    movu               ym25, [r7  +ssq*2+16]
+    add                  r7, r6
+    vinserti32x8        m24, [r7  +ssq*0+ 0], 1
+    vinserti32x8        m25, [r7  +ssq*0+16], 1 ; 5 6
+    pshufb               m0, m4, m20
+    mova                 m1, m10
+    vpdpwssd             m1, m11, m0    ; a0
+    pshufb               m0, m6, m20
+    mova                 m2, m10
+    vpdpwssd             m2, m11, m0    ; b0
+    pshufb               m0, m7, m20
+    mova                 m3, m10
+    vpdpwssd             m3, m13, m0    ; c2
+    pshufb               m0, m4, m21
+    vpdpwssd             m1, m12, m0    ; a1
+    pshufb               m0, m6, m21
+    vpdpwssd             m2, m12, m0    ; b1
+    pshufb               m0, m7, m21
+    vpdpwssd             m3, m14, m0    ; c3
+    pshufb               m0, m5, m20
+    vpdpwssd             m1, m13, m0    ; a2
+    shufpd               m6, m7, 0x55
+    pshufb               m7, m6, m20
+    vpdpwssd             m2, m13, m7    ; b2
+    vpdpwssd             m3, m11, m7    ; c0
+    pshufb               m5, m21
+    vpdpwssd             m1, m14, m5    ; a3
+    pshufb               m6, m21
+    vpdpwssd             m2, m14, m6    ; b3
+    vpdpwssd             m3, m12, m6    ; c1
+    pshufb               m0, m22, m20
+    mova                 m4, m10
+    vpdpwssd             m4, m11, m0    ; d0
+    pshufb               m0, m23, m20
+    mova                 m5, m10
+    vpdpwssd             m5, m13, m0    ; e2
+    pshufb               m0, m24, m20
+    mova                 m6, m10
+    vpdpwssd             m6, m11, m0    ; f0
+    pshufb               m0, m25, m20
+    mova                 m7, m10
+    vpdpwssd             m7, m13, m0    ; g2
+    pshufb               m0, m22, m21
+    vpdpwssd             m4, m12, m0    ; d1
+    pshufb               m0, m23, m21
+    vpdpwssd             m5, m14, m0    ; e3
+    pshufb               m0, m24, m21
+    vpdpwssd             m6, m12, m0    ; f1
+    pshufb               m0, m25, m21
+    vpdpwssd             m7, m14, m0    ; g3
+    shufpd              m22, m23, 0x55
+    pshufb              m23, m22, m20
+    vpdpwssd             m4, m13, m23   ; d2
+    vpdpwssd             m5, m11, m23   ; e0
+    shufpd              m24, m25, 0x55
+    pshufb              m25, m24, m20
+    vpdpwssd             m6, m13, m25   ; f2
+    vpdpwssd             m7, m11, m25   ; g0
+    pshufb              m22, m21
+    vpdpwssd             m4, m14, m22   ; d3
+    vpdpwssd             m5, m12, m22   ; e1
+    pshufb              m24, m21
+    vpdpwssd             m6, m14, m24   ; f3
+    vpdpwssd             m7, m12, m24   ; g1
+    pslldq               m1, 1
+    vpermt2b             m2, m9, m3     ; 12
+    vpermt2b             m4, m9, m5     ; 34
+    vpermt2b             m6, m9, m7     ; 56
+    vpshrdd              m1, m2, 16     ; 01
+    vpshrdd              m3, m2, m4, 16 ; 23
+    vpshrdd              m5, m4, m6, 16 ; 45
+.hv_w16_loop:
+    movu               ym24, [r7+ssq*1+ 0]
+    movu               ym25, [r7+ssq*1+16]
+    lea                  r7, [r7+ssq*2]
+    vinserti32x8        m24, [r7+ssq*0+ 0], 1
+    vinserti32x8        m25, [r7+ssq*0+16], 1
+    mova                 m7, m10
+    mova                 m8, m10
+    pshufb               m0, m24, m20
+    vpdpwssd             m7, m11, m0    ; h0
+    pshufb               m0, m25, m20
+    vpdpwssd             m8, m13, m0    ; i2
+    pmaddwd             m22, m16, m1    ; A0
+    mova                 m1, m3
+    pmaddwd             m23, m16, m2    ; B0
+    mova                 m2, m4
+    pshufb               m0, m24, m21
+    vpdpwssd             m7, m12, m0    ; h1
+    pshufb               m0, m25, m21
+    vpdpwssd             m8, m14, m0    ; i3
+    vpdpwssd            m22, m17, m3    ; A1
+    mova                 m3, m5
+    vpdpwssd            m23, m17, m4    ; B1
+    mova                 m4, m6
+    shufpd              m24, m25, 0x55
+    pshufb              m25, m24, m20
+    vpdpwssd             m7, m13, m25   ; h2
+    vpdpwssd             m8, m11, m25   ; i0
+    vpdpwssd            m22, m18, m5    ; A2
+    vpdpwssd            m23, m18, m6    ; B2
+    pshufb              m24, m21
+    vpdpwssd             m7, m14, m24   ; h3
+    vpdpwssd             m8, m12, m24   ; i1
+    vpermt2b             m7, m9, m8     ; 78
+    vpshrdd              m5, m6, m7, 16 ; 67
+    vpdpwssd            m22, m19, m5    ; A3
+    vpdpwssd            m23, m19, m7    ; B3
+    mova                 m6, m7
+    psrad               m22, 10
+    psrad               m23, 10
+    vshufi32x4           m0, m22, m23, q3232
+    vinserti32x8        m22, ym23, 1
+    packusdw            m22, m0
+    pminsw              m22, m15
+    mova          [r8+dsq*0], ym22
+    vextracti32x8 [r8+dsq*1], m22, 1
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    add                srcq, 32
+    add                dstq, 32
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .hv_w16_loop0
+    RET
+
+%if WIN64
+DECLARE_REG_TMP 6, 4
+%else
+DECLARE_REG_TMP 6, 7
+%endif
+
+%define PREP_8TAP_FN FN prep_8tap,
+PREP_8TAP_FN smooth,         SMOOTH,  SMOOTH,  prep_6tap_16bpc
+PREP_8TAP_FN smooth_regular, SMOOTH,  REGULAR, prep_6tap_16bpc
+PREP_8TAP_FN regular_smooth, REGULAR, SMOOTH,  prep_6tap_16bpc
+PREP_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal prep_6tap_16bpc, 3, 8, 0, tmp, src, ss, w, h, mx, my
+%define base r7-prep_avx512icl
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    lea                  r7, [prep_avx512icl]
+    mov                  wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.prep:
+    tzcnt                wd, wd
+    mov                 r5d, r7m ; bitdepth_max
+    vpbroadcastd         m5, [pw_8192]
+    movzx                wd, word [r7+wq*2+table_offset(prep,)]
+    shr                 r5d, 11
+    vpbroadcastd         m4, [r7-prep_avx512icl+prep_mul+r5*4]
+    add                  wq, r7
+    lea                  r6, [ssq*3]
+%if WIN64
+    pop                  r7
+%endif
+    jmp                  wq
+.h_w8:
+    mova                 m6, [spel_h_shufA]
+    movu                 m7, [spel_h_shufC]
+    mova                 m8, [prep_endB]
+.h_w8_loop:
+    movu                ym4, [srcq+ssq*0]
+    vinserti32x8         m4, [srcq+ssq*1], 1
+    movu                ym5, [srcq+ssq*2]
+    vinserti32x8         m5, [srcq+r6   ], 1
+    lea                srcq, [srcq+ssq*4]
+    mova                 m0, m10
+    mova                 m1, m10
+    vpermb               m2, m6, m4
+    vpermb               m3, m6, m5
+    vpdpwssd             m0, m12, m2 ; a0 b0
+    vpdpwssd             m1, m12, m3 ; c0 d0
+    vpermb               m4, m7, m4
+    vpermb               m5, m7, m5
+    vpdpwssd             m0, m14, m4 ; a2 b2
+    vpdpwssd             m1, m14, m5 ; c2 d2
+    shufpd               m2, m4, 0x55
+    shufpd               m3, m5, 0x55
+    vpdpwssd             m0, m13, m2 ; a1 b1
+    vpdpwssd             m1, m13, m3 ; c1 d1
+    vpermt2b             m0, m8, m1
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .h_w8_loop
+    RET
+.h:
+    vpbroadcastd        m10, [prep_8tap_rnd]
+    test                myd, 0xf00
+    jnz .hv
+    lea                  r6, [ssq*3]
+    cmp                  wd, 4
+    je mangle(private_prefix %+ _prep_8tap_16bpc_avx512icl).h_w4
+    shr                 mxd, 16
+    pmovsxbw           xmm0, [base+subpel_filters+1+mxq*8]
+    mov                 r5d, r7m
+    sub                srcq, 4
+    shr                 r5d, 11
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    mova             [tmpq], xmm0
+    vpbroadcastd        m12, xmm0
+    vpbroadcastd        m13, [tmpq+ 4]
+    vpbroadcastd        m14, [tmpq+ 8]
+    cmp                  wd, 16
+    jl .h_w8
+    vbroadcasti32x4      m5, [spel_h_shufA]
+    vbroadcasti32x4      m6, [spel_h_shufB]
+    mova                 m7, [prep_endC]
+    jg .h_w32
+.h_w16_loop:
+    movu                ym2, [srcq+ssq*0+ 0]
+    vinserti32x8         m2, [srcq+ssq*1+ 0], 1
+    movu                ym3, [srcq+ssq*0+12]
+    vinserti32x8         m3, [srcq+ssq*1+12], 1
+    lea                srcq, [srcq+ssq*2]
+    mova                 m0, m10
+    mova                 m1, m10
+    pshufb               m4, m2, m5   ; 01
+    vpdpwssd             m0, m12, m4  ; a0  b0
+    pshufb               m4, m3, m6   ; 89
+    vpdpwssd             m1, m14, m4  ; a2' b2'
+    pshufb               m2, m6       ; 23
+    pshufb               m3, m5       ; 67
+    vpdpwssd             m0, m13, m2  ; a1  b1
+    vpdpwssd             m1, m13, m3  ; a1' b1'
+    shufpd               m2, m3, 0x55 ; 45
+    vpdpwssd             m0, m14, m2  ; a2  b2
+    vpdpwssd             m1, m12, m2  ; a0' b0'
+    vpermt2b             m0, m7, m1
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 2
+    jg .h_w16_loop
+    RET
+.h_w32:
+    lea                srcq, [srcq+wq*2]
+    neg                  wq
+.h_w32_loop0:
+    mov                  r6, wq
+.h_w32_loop:
+    movu                 m2, [srcq+r6*2+ 0]
+    movu                 m3, [srcq+r6*2+12]
+    mova                 m0, m10
+    mova                 m1, m10
+    pshufb               m4, m2, m5
+    vpdpwssd             m0, m12, m4
+    pshufb               m4, m3, m6
+    vpdpwssd             m1, m14, m4
+    pshufb               m2, m6
+    pshufb               m3, m5
+    vpdpwssd             m0, m13, m2
+    vpdpwssd             m1, m13, m3
+    shufpd               m2, m3, 0x55
+    vpdpwssd             m0, m14, m2
+    vpdpwssd             m1, m12, m2
+    vpermt2b             m0, m7, m1
+    mova             [tmpq], m0
+    add                tmpq, 64
+    add                  r6, 32
+    jl .h_w32_loop
+    add                srcq, ssq
+    dec                  hd
+    jg .h_w32_loop0
+    RET
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    mov                 r5d, r7m
+    vpbroadcastd        m10, [prep_8tap_rnd]
+    pmovsxbw           xmm0, [base+subpel_filters+1+myq*8]
+    tzcnt               r6d, wd
+    shr                 r5d, 11
+    movzx               r6d, word [r7+r6*2+table_offset(prep, _6tap_v)]
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    add                  r7, r6
+    mova             [tmpq], xmm0
+    vpbroadcastd        m12, xmm0
+    mov                  r6, ssq
+    vpbroadcastd        m13, [tmpq+ 4]
+    neg                  r6
+    vpbroadcastd        m14, [tmpq+ 8]
+    jmp                  r7
+.v_w4:
+    mov                 r3d, 0x330c
+    movq                xm1, [srcq+r6 *2]
+    kmovw                k1, r3d
+    vpbroadcastq    ym1{k1}, [srcq+r6 *1]
+    vpbroadcastq         m2, [srcq+ssq*0]
+    vinserti32x4     m1{k1}, m2, [srcq+ssq*1], 3
+    movq                xm0, [srcq+ssq*2]
+    mova                ym4, [prep_endA]
+    valignq              m0, m1, 2
+    punpcklwd            m1, m0        ; 01 12 23 34
+.v_w4_loop:
+    lea                srcq, [srcq+ssq*4]
+    movq                xm2, [srcq+r6 *1]
+    vpbroadcastq    ym2{k1}, [srcq+ssq*0]
+    vpbroadcastq         m3, [srcq+ssq*1]
+    vinserti32x4     m2{k1}, m3, [srcq+ssq*2], 3
+    mova                 m3, m10
+    vpdpwssd             m3, m12, m1   ; a0 b0 c0 d0
+    valignq              m0, m2, m0, 6 ; 4 5 6 7
+    punpcklwd            m0, m2        ; 45 56 67 78
+    vpdpwssd             m3, m14, m0   ; a2 b2 c2 d2
+    vshufi32x4           m1, m0, q1032 ; 23 34 45 56
+    vpdpwssd             m3, m13, m1   ; a1 b1 c1 d1
+    mova                 m1, m0
+    mova                 m0, m2
+    vpermb               m3, m4, m3
+    mova             [tmpq], ym3
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    RET
+.v_w8:
+    vbroadcasti32x4     ym1, [srcq+r6 *1]
+    mov                 r3d, 0x33
+    vbroadcasti32x4      m2, [srcq+ssq*0]
+    kmovb                k1, r3d
+    mova                 m6, [spel_v_shuf8]
+    vinserti64x2     m1{k1}, m2, [srcq+r6 *2], 0 ; 0 1 2
+    vbroadcasti32x4     ym0, [srcq+ssq*1]
+    vinserti64x2     m0{k1}, m2, [srcq+ssq*2], 2 ; 2 3 4
+    mova                 m7, [prep_endB]
+    vpermb               m1, m6, m1  ; 01 12
+    vpermb               m2, m6, m0  ; 23 34
+.v_w8_loop:
+    lea                srcq, [srcq+ssq*4]
+    vbroadcasti32x4     ym3, [srcq+r6 *1]
+    movu                xm4, [srcq+ssq*0]
+    vshufi64x2       m3{k1}, m0, m4, q1032       ; 4 5 6
+    vbroadcasti32x4     ym0, [srcq+ssq*1]
+    vinserti64x2     m0{k1}, m4, [srcq+ssq*2], 2 ; 6 7 8
+    mova                 m4, m10
+    vpdpwssd             m4, m12, m1 ; a0 b0
+    mova                 m5, m10
+    vpdpwssd             m5, m12, m2 ; c0 d0
+    vpermb               m1, m6, m3  ; 45 56
+    vpdpwssd             m4, m13, m2 ; a1 b1
+    vpermb               m2, m6, m0  ; 67 78
+    vpdpwssd             m5, m13, m1 ; c1 d1
+    vpdpwssd             m4, m14, m1 ; a2 b2
+    vpdpwssd             m5, m14, m2 ; c2 d2
+    vpermt2b             m4, m7, m5
+    mova             [tmpq], m4
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    vbroadcasti32x8      m0, [srcq+r6 *1]
+    vinserti32x8         m1, m0, [srcq+ssq*0], 1 ; 1 2
+    vinserti32x8         m0, [srcq+r6 *2], 0     ; 0 1
+    mova                 m6, [spel_v_shuf16]
+    movu                ym3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8         m3, [srcq+ssq*0], 1     ; 3 4
+    mova                 m7, [prep_endA]
+    vpermb               m1, m6, m1     ; 12
+    vpermb               m0, m6, m0     ; 01
+    vpermb               m3, m6, m3     ; 34
+    vpshrdd              m2, m1, m3, 16 ; 23
+.v_w16_loop:
+    mova                 m5, m10
+    vpdpwssd             m5, m12, m1    ; b0
+    mova                 m4, m10
+    vpdpwssd             m4, m12, m0    ; a0
+    mova                 m1, m3
+    vpdpwssd             m5, m13, m3    ; b1
+    movu                ym3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpdpwssd             m4, m13, m2    ; a1
+    vinserti32x8         m3, [srcq+ssq*0], 1
+    mova                 m0, m2
+    vpermb               m3, m6, m3     ; 56
+    vpshrdd              m2, m1, m3, 16 ; 45
+    vpdpwssd             m5, m14, m3    ; b2
+    vpdpwssd             m4, m14, m2    ; a2
+    vpermt2b             m4, m7, m5
+    mova             [tmpq], m4
+    add                tmpq, 64
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+.v_w64:
+.v_w128:
+%if WIN64
+    push                 r8
+%endif
+    mova                m11, [prep_endC]
+    lea                  r5, [hq+wq*8-256]
+.v_w32_loop0:
+    movu                 m4, [srcq+r6 *2]
+    movu                 m5, [srcq+r6 *1]
+    lea                  r7, [srcq+ssq*2]
+    movu                 m6, [srcq+ssq*0]
+    movu                 m7, [srcq+ssq*1]
+    mov                  r8, tmpq
+    movu                 m8, [r7  +ssq*0]
+    punpcklwd            m0, m4, m5  ; 01
+    punpckhwd            m4, m5
+    punpcklwd            m1, m5, m6  ; 12
+    punpckhwd            m5, m6
+    punpcklwd            m2, m6, m7  ; 23
+    punpckhwd            m6, m7
+    punpcklwd            m3, m7, m8  ; 34
+    punpckhwd            m7, m8
+.v_w32_loop:
+    mova                m16, m10
+    movu                 m9, [r7+ssq*1]
+    mova                m18, m10
+    vpdpwssd            m16, m12, m0 ; a0
+    mova                m17, m10
+    vpdpwssd            m18, m12, m4
+    mova                m19, m10
+    vpdpwssd            m17, m12, m1 ; b0
+    lea                  r7, [r7+ssq*2]
+    vpdpwssd            m19, m12, m5
+    mova                 m0, m2
+    vpdpwssd            m16, m13, m2 ; a1
+    punpcklwd            m2, m8, m9  ; 45
+    mova                 m4, m6
+    vpdpwssd            m18, m13, m6
+    punpckhwd            m6, m8, m9
+    movu                 m8, [r7+ssq*0]
+    vpdpwssd            m17, m13, m3 ; b1
+    mova                 m1, m3
+    vpdpwssd            m19, m13, m7
+    mova                 m5, m7
+    vpdpwssd            m16, m14, m2 ; a2
+    punpcklwd            m3, m9, m8  ; 56
+    vpdpwssd            m18, m14, m6
+    punpckhwd            m7, m9, m8
+    vpdpwssd            m17, m14, m3 ; b2
+    vpdpwssd            m19, m14, m7
+    vpermt2b            m16, m11, m18
+    vpermt2b            m17, m11, m19
+    mova          [r8+wq*0], m16
+    mova          [r8+wq*2], m17
+    lea                  r8, [r8+wq*4]
+    sub                  hd, 2
+    jg .v_w32_loop
+    add                srcq, 64
+    add                tmpq, 64
+    movzx                hd, r5b
+    sub                 r5d, 1<<8
+    jg .v_w32_loop0
+%if WIN64
+    pop                  r8
+%endif
+    vzeroupper
+    RET
+.hv_w4:
+    movzx               mxd, mxb
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    mov                 r5d, r7m
+    pmovsxbw           xmm1, [base+subpel_filters+1+myq*8]
+    mov                  r6, ssq
+    sub                srcq, 2
+    shr                 r5d, 11
+    neg                  r6
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    psllw              xmm1, 2
+    mova          [tmpq+ 0], xmm0
+    mova          [tmpq+16], xmm1
+    vpbroadcastd         m8, [tmpq+ 4]
+    mov                 r3d, 0xf0
+    vpbroadcastd         m9, [tmpq+ 8]
+    vpbroadcastd        m12, xmm1
+    movu                xm3, [srcq+r6 *2]
+    kmovb                k1, r3d
+    vinserti32x4        ym3, [srcq+r6 *1], 1
+    vbroadcasti32x4      m2, [srcq+ssq*0]
+    vinserti64x2     m3{k1}, m2, [srcq+ssq*1], 3
+    movu                xm4, [srcq+ssq*2]
+    vbroadcasti32x4      m5, [spel_h_shufA]
+    vbroadcasti32x4      m6, [spel_h_shufB]
+    mova                 m1, m11
+    mova                m15, [spel_shuf4a]
+    mova                xm2, xm11
+    pshufb               m0, m3, m5
+    vpdpwssd             m1, m8, m0
+    pshufb              xm0, xm4, xm5
+    vpdpwssd            xm2, xm8, xm0
+    vpbroadcastd        m13, [tmpq+20]
+    pshufb               m3, m6
+    vpbroadcastd        m14, [tmpq+24]
+    pshufb              xm4, xm6
+    mova                 m7, [spel_shuf4b]
+    vpdpwssd             m1, m9, m3    ; 0 1 2 3
+    vpdpwssd            xm2, xm9, xm4  ; 4
+    vpermt2b             m1, m15, m2   ; 01 12 23 34
+    mova               ym15, [prep_endA]
+.hv_w4_loop:
+    lea                srcq, [srcq+ssq*4]
+    movu                xm4, [srcq+r6 *1]
+    vinserti32x4        ym4, [srcq+ssq*0], 1
+    vbroadcasti32x4      m3, [srcq+ssq*1]
+    vinserti64x2     m4{k1}, m3, [srcq+ssq*2], 3
+    mova                 m2, m11
+    pshufb               m3, m4, m5
+    vpdpwssd             m2, m8, m3
+    mova                 m3, m10
+    vpdpwssd             m3, m12, m1   ; a0 b0 c0 d0
+    pshufb               m4, m6
+    vpdpwssd             m2, m9, m4    ; 5 6 7 8
+    mova                 m4, m1
+    vpermt2b             m1, m7, m2    ; 45 56 67 78
+    vpdpwssd             m3, m14, m1   ; a2 b2 c2 d2
+    vshufi32x4           m4, m1, q1032 ; 23 34 45 56
+    vpdpwssd             m3, m13, m4   ; a1 b1 c1 d1
+    vpermb               m3, m15, m3
+    mova             [tmpq], ym3
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    mova                 m8, [spel_h_shufA]
+    movu               ym18, [srcq+r6 *2]
+    vinserti32x8        m18, [srcq+r6 *1], 1 ; 0 1
+    movu               ym19, [srcq+ssq*0]
+    vinserti32x8        m19, [srcq+ssq*1], 1 ; 2 3
+    movu               ym20, [srcq+ssq*2]    ; 4
+    movu                 m9, [spel_h_shufC]
+    mova                m21, [spel_shuf8a]
+    mova                 m0, [spel_shuf8b]
+    vpermb               m4, m8, m18
+    mova                 m1, m10
+    vpermb               m5, m8, m19
+    vpdpwssd             m1, m12, m4  ; a0 b0
+    mova                 m2, m10
+    vpermb               m6, m8, m20
+    vpdpwssd             m2, m12, m5  ; c0 d0
+    mova                 m3, m10
+    vpermb              m18, m9, m18
+    vpdpwssd             m3, m12, m6  ; e0
+    mova                 m7, [prep_endB]
+    vpermb              m19, m9, m19
+    vpdpwssd             m1, m14, m18 ; a2 b2
+    vpermb              m20, m9, m20
+    vpdpwssd             m2, m14, m19 ; c2 d2
+    shufpd               m4, m18, 0x55
+    vpdpwssd             m3, m14, m20 ; e2
+    shufpd               m5, m19, 0x55
+    vpdpwssd             m1, m13, m4  ; a1 b1
+    shufpd               m6, m20, 0x55
+    vpdpwssd             m2, m13, m5  ; c1 d1
+    vpdpwssd             m3, m13, m6  ; e1
+    vpermt2b             m1, m21, m2  ; 01 12
+    vpermt2b             m2, m21, m3  ; 23 34
+.hv_w8_loop:
+    lea                srcq, [srcq+ssq*4]
+    movu               ym18, [srcq+r6 *1]
+    vinserti32x8        m18, [srcq+ssq*0], 1
+    movu               ym19, [srcq+ssq*1]
+    vinserti32x8        m19, [srcq+ssq*2], 1
+    mova                 m3, m10
+    vpermb               m5, m8, m18
+    mova                 m4, m10
+    vpermb               m6, m8, m19
+    vpdpwssd             m3, m12, m5  ; f0 g0
+    mova                m20, m11
+    vpdpwssd             m4, m12, m6  ; h0 i0
+    mova                m21, m11
+    vpdpwssd            m20, m15, m1  ; A0 B0
+    vpermb              m18, m9, m18
+    vpdpwssd            m21, m15, m2  ; C0 D0
+    vpermb              m19, m9, m19
+    vpdpwssd             m3, m14, m18 ; f2 g2
+    vpdpwssd             m4, m14, m19 ; h2 i2
+    shufpd               m5, m18, 0x55
+    vpdpwssd            m20, m16, m2  ; A1 B1
+    shufpd               m6, m19, 0x55
+    vpdpwssd             m3, m13, m5  ; f1 g1
+    vpdpwssd             m4, m13, m6  ; h1 i1
+    vpermt2b             m2, m0, m3   ; 45 56
+    vpdpwssd            m21, m16, m2  ; C1 D1
+    mova                 m1, m2
+    vpermt2b             m2, m0, m4   ; 67 78
+    vpdpwssd            m20, m17, m1  ; A2 B2
+    vpdpwssd            m21, m17, m2  ; A2 B2
+    vpermt2b            m20, m7, m21
+    mova             [tmpq], m20
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .hv_w8_loop
+    vzeroupper
+    RET
+.hv:
+    vpbroadcastd        m11, [pd_128]
+    cmp                  wd, 4
+    je .hv_w4
+    shr                 mxd, 16
+    pmovsxbw           xmm0, [base+subpel_filters+1+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    mov                 r5d, r7m
+    pmovsxbw           xmm1, [base+subpel_filters+1+myq*8]
+    mov                  r6, ssq
+    sub                srcq, 4
+    shr                 r5d, 11
+    neg                  r6
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    psllw              xmm1, 2
+    mova          [tmpq+ 0], xmm0
+    mova          [tmpq+16], xmm1
+    vpbroadcastd        m12, xmm0
+    vpbroadcastd        m13, [tmpq+ 4]
+    vpbroadcastd        m14, [tmpq+ 8]
+    vpbroadcastd        m15, xmm1
+    vpbroadcastd        m16, [tmpq+20]
+    vpbroadcastd        m17, [tmpq+24]
+    cmp                  wd, 16
+    jl .hv_w8
+    vbroadcasti32x4      m8, [spel_h_shufA]
+    vbroadcasti32x4      m9, [spel_h_shufB]
+    jg .hv_w32
+    vbroadcasti32x8      m6, [srcq+r6 *2+ 8]
+    vinserti32x8         m2, m6, [srcq+r6 *2+16], 1
+    vinserti32x8         m6, [srcq+r6 *2+ 0], 0 ; 0
+    movu               ym18, [srcq+r6 *1+ 0]
+    movu               ym19, [srcq+r6 *1+12]
+    vinserti32x8        m18, [srcq+ssq*0+ 0], 1
+    vinserti32x8        m19, [srcq+ssq*0+12], 1 ; 1 2
+    movu               ym20, [srcq+ssq*1+ 0]
+    movu               ym21, [srcq+ssq*1+12]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8        m20, [srcq+ssq*0+ 0], 1
+    vinserti32x8        m21, [srcq+ssq*0+12], 1 ; 3 4
+    pshufb               m2, m8
+    mova                 m1, m10
+    pshufb               m3, m18, m8
+    vpdpwssd             m1, m14, m2    ; a2
+    mova                 m2, m10
+    pshufb               m4, m19, m9
+    vpdpwssd             m2, m12, m3    ; b0  c0
+    mova                 m3, m10
+    pshufb               m5, m20, m8
+    vpdpwssd             m3, m14, m4    ; b2' c2'
+    mova                 m4, m10
+    pshufb               m7, m21, m9
+    vpdpwssd             m4, m12, m5    ; d0  e0
+    mova                 m5, m10
+    pshufb               m0, m6, m8
+    vpdpwssd             m5, m14, m7    ; d2' e2'
+    mova                 m7, [spel_shuf16]
+    pshufb              m18, m9
+    vpdpwssd             m1, m12, m0    ; a0
+    pshufb              m19, m8
+    vpdpwssd             m2, m13, m18   ; b1  c1
+    pshufb              m20, m9
+    vpdpwssd             m3, m13, m19   ; b1' c1'
+    pshufb              m21, m8
+    vpdpwssd             m4, m13, m20   ; d1  e1
+    pshufb               m6, m9
+    vpdpwssd             m5, m13, m21   ; d1' e1'
+    mova                 m0, [prep_endB]
+    shufpd              m18, m19, 0x55
+    vpdpwssd             m1, m13, m6    ; a1
+    shufpd              m20, m21, 0x55
+    vpdpwssd             m2, m14, m18   ; b2  c2
+    vpdpwssd             m3, m12, m18   ; b0' c0'
+    vpdpwssd             m4, m14, m20   ; d2  e2
+    vpdpwssd             m5, m12, m20   ; d0' e0'
+    pslldq               m1, 1
+    vpermt2b             m2, m7, m3     ; 12
+    vpermt2b             m4, m7, m5     ; 34
+    vpshrdd              m1, m2, 16     ; 01
+    vpshrdd              m3, m2, m4, 16 ; 23
+.hv_w16_loop:
+    movu               ym18, [srcq+ssq*1+ 0]
+    movu               ym19, [srcq+ssq*1+12]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8        m18, [srcq+ssq*0+ 0], 1
+    vinserti32x8        m19, [srcq+ssq*0+12], 1
+    mova                 m5, m10
+    mova                 m6, m10
+    pshufb              m21, m18, m8
+    vpdpwssd             m5, m12, m21   ; f0  g0
+    pshufb              m20, m19, m9
+    mova                m21, m11
+    vpdpwssd             m6, m14, m20   ; f2' g2'
+    mova                m20, m11
+    vpdpwssd            m21, m15, m2    ; B0
+    mova                 m2, m4
+    vpdpwssd            m20, m15, m1    ; A0
+    mova                 m1, m3
+    pshufb              m18, m9
+    vpdpwssd             m5, m13, m18   ; f1  g1
+    pshufb              m19, m8
+    vpdpwssd             m6, m13, m19   ; f1' g1'
+    vpdpwssd            m21, m16, m4    ; B1
+    vpdpwssd            m20, m16, m3    ; A1
+    shufpd              m18, m19, 0x55
+    vpdpwssd             m5, m14, m18   ; f2  g2
+    vpdpwssd             m6, m12, m18   ; f0' g0'
+    mova                 m4, m7
+    vpermi2b             m4, m5, m6     ; 56
+    vpshrdd              m3, m2, m4, 16 ; 45
+    vpdpwssd            m21, m17, m4    ; B2
+    vpdpwssd            m20, m17, m3    ; A2
+    vpermt2b            m20, m0, m21
+    mova             [tmpq], m20
+    add                tmpq, 64
+    sub                  hd, 2
+    jg .hv_w16_loop
+    vzeroupper
+    RET
+.hv_w32:
+    WIN64_SPILL_XMM      29
+%if WIN64
+    push                 r8
+%endif
+    mova                m27, [spel_shuf32]
+    lea                 r5d, [hq+wq*8-256]
+    mova                m28, [prep_endC]
+.hv_w32_loop0:
+    movu                m18, [srcq+r6 *2+ 0]
+    movu                 m7, [srcq+r6 *2+12]
+    movu                 m6, [srcq+r6 *1+ 0]
+    movu                m20, [srcq+r6 *1+12]
+    lea                  r7, [srcq+ssq*2]
+    movu                m19, [srcq+ssq*0+ 0]
+    movu                m21, [srcq+ssq*0+12]
+    movu                m22, [srcq+ssq*1+ 0]
+    movu                m24, [srcq+ssq*1+12]
+    mov                  r8, tmpq
+    movu                m23, [r7  +ssq*0+ 0]
+    movu                m25, [r7  +ssq*0+12]
+    pshufb               m1, m18, m8
+    mova                 m0, m10
+    pshufb               m2, m7, m9
+    vpdpwssd             m0, m12, m1    ; a0
+    mova                 m1, m10
+    pshufb               m4, m6, m8
+    vpdpwssd             m1, m14, m2    ; a2'
+    mova                 m2, m10
+    pshufb               m3, m19, m8
+    vpdpwssd             m2, m12, m4    ; b0
+    mova                 m4, m10
+    pshufb               m5, m20, m9
+    vpdpwssd             m4, m12, m3    ; c0
+    mova                 m3, m10
+    pshufb              m26, m21, m9
+    vpdpwssd             m3, m14, m5    ; b2'
+    mova                 m5, m10
+    pshufb              m18, m9
+    vpdpwssd             m5, m14, m26   ; c2'
+    pshufb               m7, m8
+    vpdpwssd             m0, m13, m18   ; a1
+    pshufb               m6, m9
+    vpdpwssd             m1, m13, m7    ; a1'
+    pshufb              m19, m9
+    vpdpwssd             m2, m13, m6    ; b1
+    pshufb              m20, m8
+    vpdpwssd             m4, m13, m19   ; c1
+    pshufb              m21, m8
+    vpdpwssd             m3, m13, m20   ; b1'
+    shufpd              m18, m7, 0x55
+    vpdpwssd             m5, m13, m21   ; c1'
+    shufpd               m6, m20, 0x55
+    vpdpwssd             m0, m14, m18   ; a2
+    shufpd              m19, m21, 0x55
+    vpdpwssd             m1, m12, m18   ; a0'
+    pshufb              m18, m22, m8
+    vpdpwssd             m2, m14, m6    ; b2
+    pshufb               m7, m23, m8
+    vpdpwssd             m4, m14, m19   ; c2
+    vpdpwssd             m3, m12, m6    ; b0'
+    mova                 m6, m10
+    vpdpwssd             m5, m12, m19   ; c0'
+    pshufb              m19, m24, m9
+    vpdpwssd             m6, m12, m18   ; d0
+    mova                m18, m10
+    pshufb              m26, m25, m9
+    vpdpwssd            m18, m12, m7    ; e0
+    mova                 m7, m10
+    pshufb              m22, m9
+    vpdpwssd             m7, m14, m19   ; d2'
+    mova                m19, m10
+    pshufb              m23, m9
+    vpdpwssd            m19, m14, m26   ; e2'
+    pshufb              m24, m8
+    vpdpwssd             m6, m13, m22   ; d1
+    pshufb              m25, m8
+    vpdpwssd            m18, m13, m23   ; e1
+    shufpd              m22, m24, 0x55
+    vpdpwssd             m7, m13, m24   ; d1'
+    shufpd              m23, m25, 0x55
+    vpdpwssd            m19, m13, m25   ; e1'
+    pslldq               m0, 1
+    vpdpwssd             m6, m14, m22   ; d2
+    pslldq               m1, 1
+    vpdpwssd            m18, m14, m23   ; e2
+    vpermt2b             m2, m27, m4    ; 12
+    vpdpwssd             m7, m12, m22   ; d0'
+    vpermt2b             m3, m27, m5    ; 12'
+    vpdpwssd            m19, m12, m23   ; e0'
+    vpshrdd              m0, m2, 16     ; 01
+    vpermt2b             m6, m27, m18   ; 34
+    vpshrdd              m1, m3, 16     ; 01'
+    vpermt2b             m7, m27, m19   ; 34'
+    vpshrdd              m4, m2, m6, 16 ; 23
+    vpshrdd              m5, m3, m7, 16 ; 23'
+.hv_w32_loop:
+    movu                m22, [r7+ssq*1+ 0]
+    movu                m24, [r7+ssq*1+12]
+    lea                  r7, [r7+ssq*2]
+    movu                m23, [r7+ssq*0+ 0]
+    movu                m25, [r7+ssq*0+12]
+    mova                m19, m11
+    vpdpwssd            m19, m15, m2    ; B0
+    mova                m21, m11
+    vpdpwssd            m21, m15, m3    ; B0'
+    mova                m18, m11
+    vpdpwssd            m18, m15, m0    ; A0
+    mova                m20, m11
+    vpdpwssd            m20, m15, m1    ; A0'
+    mova                 m2, m6
+    vpdpwssd            m19, m16, m6    ; B1
+    mova                 m3, m7
+    vpdpwssd            m21, m16, m7    ; B1'
+    mova                 m0, m4
+    vpdpwssd            m18, m16, m4    ; A1
+    mova                 m1, m5
+    pshufb               m4, m22, m8
+    vpdpwssd            m20, m16, m5    ; A1'
+    mova                 m6, m10
+    pshufb               m7, m23, m8
+    vpdpwssd             m6, m12, m4    ; f0
+    mova                 m4, m10
+    pshufb               m5, m24, m9
+    vpdpwssd             m4, m12, m7    ; g0
+    mova                 m7, m10
+    pshufb              m26, m25, m9
+    vpdpwssd             m7, m14, m5    ; f2'
+    mova                 m5, m10
+    pshufb              m22, m9
+    vpdpwssd             m5, m14, m26   ; g2'
+    pshufb              m23, m9
+    vpdpwssd             m6, m13, m22   ; f1
+    pshufb              m24, m8
+    vpdpwssd             m4, m13, m23   ; g1
+    pshufb              m25, m8
+    vpdpwssd             m7, m13, m24   ; f1'
+    shufpd              m22, m24, 0x55
+    vpdpwssd             m5, m13, m25   ; g1'
+    shufpd              m23, m25, 0x55
+    vpdpwssd             m6, m14, m22   ; f2
+    vpdpwssd             m4, m14, m23   ; g2
+    vpdpwssd             m7, m12, m22   ; f0'
+    vpdpwssd             m5, m12, m23   ; g0'
+    vpermt2b             m6, m27, m4    ; 56
+    vpermt2b             m7, m27, m5    ; 56'
+    vpdpwssd            m19, m17, m6    ; B2
+    vpshrdd              m4, m2, m6, 16 ; 45
+    vpdpwssd            m21, m17, m7    ; B2'
+    vpshrdd              m5, m3, m7, 16 ; 45'
+    vpdpwssd            m18, m17, m4    ; A2
+    vpdpwssd            m20, m17, m5    ; A2'
+    vpermt2b            m19, m28, m21
+    vpermt2b            m18, m28, m20
+    mova          [r8+wq*0], m18
+    mova          [r8+wq*2], m19
+    lea                  r8, [r8+wq*4]
+    sub                  hd, 2
+    jg .hv_w32_loop
+    add                srcq, 64
+    add                tmpq, 64
+    movzx                hd, r5b
+    sub                 r5d, 1<<8
+    jg .hv_w32_loop0
+%if WIN64
+    pop                  r8
+%endif
+    RET
+
+PREP_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_16bpc
+PREP_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_16bpc
+PREP_8TAP_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_16bpc
+PREP_8TAP_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_16bpc
+PREP_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal prep_8tap_16bpc, 3, 8, 0, tmp, src, stride, w, h, mx, my
+%define base r7-prep_avx512icl
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    lea                  r7, [prep_avx512icl]
+    mov                  wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _prep_6tap_16bpc_avx512icl).prep
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    mov                 r5d, r7m
+    vpbroadcastd        m10, [prep_8tap_rnd]
+    pmovsxbw           xmm0, [base+subpel_filters+myq*8]
+    tzcnt               r6d, wd
+    shr                 r5d, 11
+    movzx               r6d, word [r7+r6*2+table_offset(prep, _8tap_v)]
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    add                  r7, r6
+    lea                  r6, [strideq*3]
+    sub                srcq, r6
+    mova             [tmpq], xmm0
+    vpbroadcastd        m12, xmm0
+    vpbroadcastd        m13, [tmpq+ 4]
+    vpbroadcastd        m14, [tmpq+ 8]
+    vpbroadcastd        m15, [tmpq+12]
+    jmp                  r7
+.v_w4:
+    mov                 r3d, 0x330c
+    movq                xm1, [srcq+strideq*0]
+    kmovw                k1, r3d
+    vpbroadcastq    ym1{k1}, [srcq+strideq*1]
+    vpbroadcastq         m0, [srcq+r6       ]
+    vinserti32x4     m1{k1}, m0, [srcq+strideq*2], 2 ; 0 1 2 3
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastq    ym0{k1}, [srcq+strideq*0]
+    vpbroadcastq         m2, [srcq+strideq*1]
+    vinserti32x4     m0{k1}, m2, [srcq+strideq*2], 3 ; 3 4 5 6
+    mova                ym5, [prep_endA]
+    vshufi32x4           m3, m1, m0, q1021 ; 1 2 3 4
+    vshufi32x4           m2, m1, m0, q2132 ; 2 3 4 5
+    punpcklwd            m1, m3            ; 01 12 23 34
+    punpcklwd            m2, m0            ; 23 34 45 56
+.v_w4_loop:
+    movq                xm4, [srcq+r6       ]
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastq    ym4{k1}, [srcq+strideq*0]
+    vpbroadcastq         m3, [srcq+strideq*1]
+    vinserti32x4     m4{k1}, m3, [srcq+strideq*2], 3 ; 7 8 9 a
+    mova                 m3, m10
+    vpdpwssd             m3, m12, m1       ; a0 b0 c0 d0
+    valignq              m1, m4, m0, 6     ; 6 7 8 9
+    vpdpwssd             m3, m13, m2       ; a1 b1 c1 d1
+    mova                 m0, m4
+    punpcklwd            m4, m1, m4        ; 67 78 89 9a
+    vpdpwssd             m3, m15, m4       ; a3 b3 c3 d3
+    vshufi32x4           m1, m2, m4, q1032 ; 45 56 67 78
+    vpdpwssd             m3, m14, m1       ; a2 b2 c2 d2
+    mova                 m2, m4
+    vpermb               m3, m5, m3
+    mova             [tmpq], ym3
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movu                xm0, [srcq+strideq*0]
+    mov                 r3d, 0x33
+    vbroadcasti32x4     ym1, [srcq+strideq*1]
+    kmovb                k1, r3d
+    mova                 m7, [spel_v_shuf8]
+    vinserti64x2     m1{k1}, m0, [srcq+strideq*2], 2 ; 0 1 2
+    add                srcq, r6
+    vbroadcasti32x4     ym2, [srcq+strideq*0]
+    vbroadcasti32x4      m3, [srcq+strideq*1]
+    vbroadcasti32x4     ym0, [srcq+strideq*2]
+    vshufi64x2       m2{k1}, m1, m3, q1032    ; 2 3 4
+    vinserti64x2     m0{k1}, m3, [srcq+r6], 2 ; 4 5 6
+    mova                 m8, [prep_endB]
+    vpermb               m1, m7, m1  ; 01 12
+    vpermb               m2, m7, m2  ; 23 34
+    vpermb               m3, m7, m0  ; 45 56
+.v_w8_loop:
+    lea                srcq, [srcq+strideq*4]
+    vbroadcasti32x4     ym4, [srcq+strideq*0]
+    movu                xm5, [srcq+strideq*1]
+    vshufi64x2       m4{k1}, m0, m5, q1032    ; 6 7 8
+    vbroadcasti32x4     ym0, [srcq+strideq*2]
+    vinserti64x2     m0{k1}, m5, [srcq+r6], 2 ; 8 9 a
+    mova                 m5, m10
+    vpdpwssd             m5, m12, m1 ; a0 b0
+    mova                 m6, m10
+    vpdpwssd             m6, m12, m2 ; c0 d0
+    mova                 m1, m3
+    vpdpwssd             m5, m13, m2 ; c1 d1
+    vpdpwssd             m6, m13, m3 ; c1 d1
+    vpermb               m2, m7, m4  ; 67 78
+    vpdpwssd             m5, m14, m3 ; a2 b2
+    vpermb               m3, m7, m0  ; 89 9a
+    vpdpwssd             m6, m14, m2 ; c2 d2
+    vpdpwssd             m5, m15, m2 ; a3 b3
+    vpdpwssd             m6, m15, m3 ; c3 d3
+    vpermt2b             m5, m8, m6
+    mova             [tmpq], m5
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    vbroadcasti32x8      m0, [srcq+strideq*1]
+    vinserti32x8         m1, m0, [srcq+strideq*2], 1
+    vinserti32x8         m0, [srcq+strideq*0], 0
+    mova                 m8, [spel_v_shuf16]
+    add                srcq, r6
+    movu                ym3, [srcq+strideq*0]
+    vinserti32x8         m3, [srcq+strideq*1], 1
+    movu                ym5, [srcq+strideq*2]
+    add                srcq, r6
+    vinserti32x8         m5, [srcq+strideq*0], 1
+    mova                m11, [prep_endA]
+    vpermb               m1, m8, m1     ; 12
+    vpermb               m0, m8, m0     ; 01
+    vpermb               m3, m8, m3     ; 34
+    vpermb               m5, m8, m5     ; 56
+    vpshrdd              m2, m1, m3, 16 ; 23
+    vpshrdd              m4, m3, m5, 16 ; 45
+.v_w16_loop:
+    mova                 m7, m10
+    vpdpwssd             m7, m12, m1    ; b0
+    mova                 m6, m10
+    vpdpwssd             m6, m12, m0    ; a0
+    mova                 m1, m3
+    vpdpwssd             m7, m13, m3    ; b1
+    mova                 m0, m2
+    vpdpwssd             m6, m13, m2    ; a1
+    mova                 m3, m5
+    vpdpwssd             m7, m14, m5    ; b2
+    mova                 m2, m4
+    vpdpwssd             m6, m14, m4    ; a2
+    movu                ym5, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    vinserti32x8         m5, [srcq+strideq*0], 1
+    vpermb               m5, m8, m5     ; 78
+    vpshrdd              m4, m3, m5, 16 ; 67
+    vpdpwssd             m7, m15, m5    ; b3
+    vpdpwssd             m6, m15, m4    ; a3
+    vpermt2b             m6, m11, m7
+    mova             [tmpq], m6
+    add                tmpq, 64
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+.v_w64:
+.v_w128:
+    WIN64_PUSH_XMM       23
+%if WIN64
+    push                 r8
+%endif
+    mova                m11, [prep_endC]
+    lea                  r5, [hq+wq*8-256]
+.v_w32_loop0:
+    movu                m16, [srcq+strideq*0]
+    movu                m17, [srcq+strideq*1]
+    lea                  r7, [srcq+r6]
+    movu                m18, [srcq+strideq*2]
+    movu                m19, [r7  +strideq*0]
+    mov                  r8, tmpq
+    movu                m20, [r7  +strideq*1]
+    movu                m21, [r7  +strideq*2]
+    add                  r7, r6
+    movu                m22, [r7  +strideq*0]
+    punpcklwd            m0, m16, m17 ; 01l
+    punpckhwd           m16, m17      ; 01h
+    punpcklwd            m1, m17, m18 ; 12l
+    punpckhwd           m17, m18      ; 12h
+    punpcklwd            m2, m18, m19 ; 23l
+    punpckhwd           m18, m19      ; 23h
+    punpcklwd            m3, m19, m20 ; 34l
+    punpckhwd           m19, m20      ; 34h
+    punpcklwd            m4, m20, m21 ; 45l
+    punpckhwd           m20, m21      ; 45h
+    punpcklwd            m5, m21, m22 ; 56l
+    punpckhwd           m21, m22      ; 56h
+.v_w32_loop:
+    mova                 m6, m10
+    vpdpwssd             m6, m12, m0  ; a0l
+    mova                 m8, m10
+    vpdpwssd             m8, m12, m16 ; a0h
+    mova                 m7, m10
+    vpdpwssd             m7, m12, m1  ; b0l
+    mova                 m9, m10
+    vpdpwssd             m9, m12, m17 ; b0h
+    mova                 m0, m2
+    vpdpwssd             m6, m13, m2  ; a1l
+    mova                m16, m18
+    vpdpwssd             m8, m13, m18 ; a1h
+    mova                 m1, m3
+    vpdpwssd             m7, m13, m3  ; b1l
+    mova                m17, m19
+    vpdpwssd             m9, m13, m19 ; b1h
+    mova                 m2, m4
+    vpdpwssd             m6, m14, m4  ; a2l
+    mova                m18, m20
+    vpdpwssd             m8, m14, m20 ; a2h
+    mova                 m3, m5
+    vpdpwssd             m7, m14, m5  ; b2l
+    mova                m19, m21
+    vpdpwssd             m9, m14, m21 ; b2h
+    movu                m21, [r7+strideq*1]
+    lea                  r7, [r7+strideq*2]
+    punpcklwd            m4, m22, m21 ; 67l
+    punpckhwd           m20, m22, m21 ; 67h
+    movu                m22, [r7+strideq*0]
+    vpdpwssd             m6, m15, m4  ; a3l
+    vpdpwssd             m8, m15, m20 ; a3h
+    punpcklwd            m5, m21, m22 ; 78l
+    punpckhwd           m21, m22      ; 78h
+    vpdpwssd             m7, m15, m5  ; b3l
+    vpdpwssd             m9, m15, m21 ; b3h
+    vpermt2b             m6, m11, m8
+    vpermt2b             m7, m11, m9
+    mova          [r8+wq*0], m6
+    mova          [r8+wq*2], m7
+    lea                  r8, [r8+wq*4]
+    sub                  hd, 2
+    jg .v_w32_loop
+    add                srcq, 64
+    add                tmpq, 64
+    movzx                hd, r5b
+    sub                 r5d, 1<<8
+    jg .v_w32_loop0
+%if WIN64
+    pop                  r8
+%endif
+    RET
+.h_w4:
+    RESET_STACK_STATE
+    movzx               mxd, mxb
+    sub                srcq, 2
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    mov                 r5d, r7m
+    vbroadcasti32x4      m4, [spel_h_shufA]
+    vbroadcasti32x4      m5, [spel_h_shufB]
+    shr                 r5d, 11
+    mova                ym9, [prep_endA]
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    mova             [tmpq], xmm0
+    vpbroadcastd         m6, [tmpq+4]
+    vpbroadcastd         m7, [tmpq+8]
+.h_w4_loop:
+    movu                xm2, [srcq+strideq*0]
+    vinserti32x4        ym2, [srcq+strideq*1], 1
+    vinserti32x4         m2, [srcq+strideq*2], 2
+    vinserti32x4         m2, [srcq+r6       ], 3
+    lea                srcq, [srcq+strideq*4]
+    mova                 m0, m10
+    pshufb               m1, m2, m4
+    vpdpwssd             m0, m6, m1
+    pshufb               m2, m5
+    vpdpwssd             m0, m7, m2
+    vpermb               m0, m9, m0
+    mova             [tmpq], ym0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4_loop
+    RET
+.h_w8:
+    mova                 m6, [spel_h_shufA]
+    movu                 m7, [spel_h_shufB]
+    movu                 m8, [spel_h_shufC]
+    mova                 m9, [spel_h_shufD]
+    mova                m11, [prep_endB]
+.h_w8_loop:
+    movu                ym4, [srcq+strideq*0]
+    vinserti32x8         m4, [srcq+strideq*1], 1
+    movu                ym5, [srcq+strideq*2]
+    vinserti32x8         m5, [srcq+r6       ], 1
+    lea                srcq, [srcq+strideq*4]
+    mova                 m0, m10
+    mova                 m1, m10
+    vpermb               m2, m6, m4
+    vpermb               m3, m6, m5
+    vpdpwssd             m0, m12, m2
+    vpdpwssd             m1, m12, m3
+    vpermb               m2, m7, m4
+    vpermb               m3, m7, m5
+    vpdpwssd             m0, m13, m2
+    vpdpwssd             m1, m13, m3
+    vpermb               m2, m8, m4
+    vpermb               m3, m8, m5
+    vpdpwssd             m0, m14, m2
+    vpdpwssd             m1, m14, m3
+    vpermb               m2, m9, m4
+    vpermb               m3, m9, m5
+    vpdpwssd             m0, m15, m2
+    vpdpwssd             m1, m15, m3
+    vpermt2b             m0, m11, m1
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .h_w8_loop
+    RET
+.h:
+    vpbroadcastd        m10, [prep_8tap_rnd]
+    test                myd, 0xf00
+    jnz .hv
+    lea                  r6, [strideq*3]
+    cmp                  wd, 4
+    je .h_w4
+    shr                 mxd, 16
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    mov                 r5d, r7m
+    sub                srcq, 6
+    shr                 r5d, 11
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    mova             [tmpq], xmm0
+    vpbroadcastd        m12, xmm0
+    vpbroadcastd        m13, [tmpq+ 4]
+    vpbroadcastd        m14, [tmpq+ 8]
+    vpbroadcastd        m15, [tmpq+12]
+    cmp                  wd, 16
+    jl .h_w8
+    vbroadcasti32x4      m6, [spel_h_shufA]
+    vbroadcasti32x4      m7, [spel_h_shufB]
+    mova                m11, [prep_endC]
+    jg .h_w32
+.h_w16_loop:
+    movu                ym2, [srcq+strideq*0+ 0]
+    vinserti32x8         m2, [srcq+strideq*1+ 0], 1
+    movu                ym3, [srcq+strideq*0+16]
+    vinserti32x8         m3, [srcq+strideq*1+16], 1
+    lea                srcq, [srcq+strideq*2]
+    mova                 m0, m10
+    mova                 m1, m10
+    pshufb               m4, m2, m6
+    vpdpwssd             m0, m12, m4 ; a0
+    pshufb               m4, m3, m6
+    vpdpwssd             m1, m14, m4 ; b2
+    pshufb               m4, m2, m7
+    vpdpwssd             m0, m13, m4 ; a1
+    pshufb               m4, m3, m7
+    vpdpwssd             m1, m15, m4 ; b3
+    shufpd               m2, m3, 0x55
+    pshufb               m4, m2, m6
+    vpdpwssd             m0, m14, m4 ; a2
+    vpdpwssd             m1, m12, m4 ; b0
+    pshufb               m2, m7
+    vpdpwssd             m0, m15, m2 ; a3
+    vpdpwssd             m1, m13, m2 ; b1
+    vpermt2b             m0, m11, m1
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 2
+    jg .h_w16_loop
+    RET
+.h_w32:
+    lea                srcq, [srcq+wq*2]
+    neg                  wq
+.h_w32_loop0:
+    mov                  r6, wq
+.h_w32_loop:
+    movu                 m2, [srcq+r6*2+ 0]
+    movu                 m3, [srcq+r6*2+ 8]
+    mova                 m0, m10
+    mova                 m1, m10
+    pshufb               m4, m2, m6
+    vpdpwssd             m0, m12, m4 ; a0
+    pshufb               m4, m3, m6
+    vpdpwssd             m1, m12, m4 ; b0
+    vpdpwssd             m0, m14, m4 ; a2
+    movu                 m4, [srcq+r6*2+16]
+    pshufb               m3, m7
+    vpdpwssd             m1, m13, m3 ; b1
+    vpdpwssd             m0, m15, m3 ; a3
+    pshufb               m3, m4, m6
+    vpdpwssd             m1, m14, m3 ; b2
+    pshufb               m2, m7
+    vpdpwssd             m0, m13, m2 ; a1
+    pshufb               m4, m7
+    vpdpwssd             m1, m15, m4 ; b3
+    vpermt2b             m0, m11, m1
+    mova             [tmpq], m0
+    add                tmpq, 64
+    add                  r6, 32
+    jl .h_w32_loop
+    add                srcq, strideq
+    dec                  hd
+    jg .h_w32_loop0
+    RET
+.hv:
+    vpbroadcastd        m11, [pd_128]
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    mov                 r5d, r7m
+    pmovsxbw           xmm1, [base+subpel_filters+myq*8]
+    lea                  r6, [strideq*3]
+    sub                srcq, 2
+    shr                 r5d, 11
+    sub                srcq, r6
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    psllw              xmm1, 2
+    mova          [tmpq+ 0], xmm0
+    mova          [tmpq+16], xmm1
+    vpbroadcastd        m12, xmm1
+    movu               xm16, [srcq+strideq*0]
+    mov                 r3d, 0xff0
+    vinserti128        ym16, [srcq+strideq*1], 1
+    kmovw                k1, r3d
+    vbroadcasti32x4     m18, [srcq+strideq*2]
+    add                srcq, r6
+    vinserti64x2    m16{k1}, m18, [srcq+strideq*0], 3
+    movu               xm17, [srcq+strideq*1]
+    vbroadcasti32x4    ym18, [srcq+strideq*2]
+    add                srcq, r6
+    vinserti32x4    m17{k1}, m18, [srcq+strideq*0], 2
+    vbroadcasti32x4      m5, [spel_h_shufA]
+    vbroadcasti32x4      m6, [spel_h_shufB]
+    vpbroadcastd         m8, [tmpq+ 4]
+    vpbroadcastd         m9, [tmpq+ 8]
+    mova                 m1, m10
+    mova                m19, [spel_shuf4a]
+    mova                 m2, m10
+    pshufb               m0, m16, m5
+    vpdpwssd             m1, m8, m0
+    pshufb               m0, m17, m5
+    vpdpwssd             m2, m8, m0
+    vpbroadcastd        m13, [tmpq+20]
+    pshufb              m16, m6
+    vpbroadcastd        m14, [tmpq+24]
+    pshufb              m17, m6
+    vpbroadcastd        m15, [tmpq+28]
+    vpdpwssd             m1, m9, m16       ; 0 1 2 3
+    vpdpwssd             m2, m9, m17       ; 4 5 6
+    mova                 m7, [spel_shuf4b]
+    vpermt2b             m1, m19, m2       ; 01 12 23 34
+    vpermb               m2, m19, m2       ; 45 56
+    mova               ym19, [prep_endA]
+    vshufi32x4           m2, m1, m2, q1032 ; 23 34 45 56
+.hv_w4_loop:
+    movu               xm17, [srcq+strideq*1]
+    vinserti128        ym17, [srcq+strideq*2], 1
+    vbroadcasti32x4     m16, [srcq+r6       ]
+    lea                srcq, [srcq+strideq*4]
+    vinserti64x2    m17{k1}, m16, [srcq+strideq*0], 3
+    mova                m18, m10
+    pshufb              m16, m17, m5
+    vpdpwssd            m18, m8, m16
+    mova                m16, m11
+    vpdpwssd            m16, m12, m1       ; a0 b0 c0 d0
+    pshufb              m17, m6
+    vpdpwssd            m18, m9, m17       ; 7 8 9 a
+    mova                 m1, m2
+    vpdpwssd            m16, m13, m2       ; a1 b1 c1 d1
+    vpermt2b             m2, m7, m18       ; 67 78 89 9a
+    vpdpwssd            m16, m15, m2       ; a3 b3 c3 d3
+    vshufi32x4           m1, m2, q1032     ; 45 56 67 78
+    vpdpwssd            m16, m14, m1       ; a2 b2 c2 d2
+    vpermb              m16, m19, m16
+    mova             [tmpq], ym16
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    vzeroupper
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    pmovsxbw           xmm0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    mov                 r5d, r7m
+    pmovsxbw           xmm1, [base+subpel_filters+myq*8]
+    lea                  r6, [strideq*3]
+    sub                srcq, 6
+    shr                 r5d, 11
+    sub                srcq, r6
+    psllw              xmm0, [base+prep_hv_shift+r5*8]
+    psllw              xmm1, 2
+    mova          [tmpq+ 0], xmm0
+    mova          [tmpq+16], xmm1
+    vpbroadcastd        m12, xmm0
+    vpbroadcastd        m13, [tmpq+ 4]
+    vpbroadcastd        m14, [tmpq+ 8]
+    vpbroadcastd        m15, [tmpq+12]
+    vpbroadcastd        m16, xmm1
+    vpbroadcastd        m17, [tmpq+20]
+    vpbroadcastd        m18, [tmpq+24]
+    vpbroadcastd        m19, [tmpq+28]
+    cmp                  wd, 8
+    jg .hv_w16
+    WIN64_SPILL_XMM      23
+    mova                 m5, [spel_h_shufA]
+    movu                ym0, [srcq+strideq*0]
+    vinserti32x8         m0, [srcq+strideq*1], 1 ; 0 1
+    movu                ym9, [srcq+strideq*2]
+    add                srcq, r6
+    vinserti32x8         m9, [srcq+strideq*0], 1 ; 2 3
+    movu               ym20, [srcq+strideq*1]
+    vinserti32x8        m20, [srcq+strideq*2], 1 ; 4 5
+    add                srcq, r6
+    movu               ym21, [srcq+strideq*0]    ; 6
+    movu                 m6, [spel_h_shufB]
+    movu                 m7, [spel_h_shufC]
+    mova               ym22, [prep_endB]
+    vpermb               m8, m5, m0
+    mova                 m1, m10
+    vpdpwssd             m1, m12, m8  ; a0 b0
+    vpermb               m8, m5, m9
+    mova                 m2, m10
+    vpdpwssd             m2, m12, m8  ; c0 d0
+    vpermb               m8, m5, m20
+    mova                 m3, m10
+    vpdpwssd             m3, m12, m8  ; e0 f0
+    vpermb               m8, m5, m21
+    mova                 m4, m10
+    vpdpwssd             m4, m12, m8  ; g0
+    vpermb               m8, m6, m0
+    vpdpwssd             m1, m13, m8  ; a1 b1
+    vpermb               m8, m6, m9
+    vpdpwssd             m2, m13, m8  ; c1 d1
+    vpermb               m8, m6, m20
+    vpdpwssd             m3, m13, m8  ; e1 f1
+    vpermb               m8, m6, m21
+    vpdpwssd             m4, m13, m8  ; g1
+    vpermb               m8, m7, m0
+    vpdpwssd             m1, m14, m8  ; a2 b2
+    vpermb               m8, m7, m9
+    vpdpwssd             m2, m14, m8  ; c2 d2
+    vpermb               m8, m7, m20
+    vpdpwssd             m3, m14, m8  ; e2 f2
+    vpermb               m8, m7, m21
+    vpdpwssd             m4, m14, m8  ; g2
+    mova                 m8, [spel_h_shufD]
+    vpermb               m0, m8, m0
+    vpdpwssd             m1, m15, m0  ; a3 b3
+    mova                 m0, [spel_shuf8a]
+    vpermb               m9, m8, m9
+    vpdpwssd             m2, m15, m9  ; c3 d3
+    mova                 m9, [spel_shuf8b]
+    vpermb              m20, m8, m20
+    vpdpwssd             m3, m15, m20 ; e3 f3
+    vpermb              m21, m8, m21
+    vpdpwssd             m4, m15, m21 ; g3
+    vpermt2b             m1, m0, m2   ; 01 12
+    vpermt2b             m2, m0, m3   ; 23 34
+    vpermt2b             m3, m0, m4   ; 45 56
+.hv_w8_loop:
+    movu                ym0, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    vinserti32x8         m0, [srcq+strideq*0], 1
+    mova                 m4, m10
+    mova                m20, m11
+    vpermb              m21, m5, m0
+    vpdpwssd             m4, m12, m21 ; h0 i0
+    vpermb              m21, m6, m0
+    vpdpwssd            m20, m16, m1  ; A0 B0
+    vpdpwssd             m4, m13, m21 ; h1 i1
+    vpermb              m21, m7, m0
+    mova                 m1, m2
+    vpdpwssd            m20, m17, m2  ; A1 B1
+    vpdpwssd             m4, m14, m21 ; h2 i2
+    vpermb              m21, m8, m0
+    mova                 m2, m3
+    vpdpwssd            m20, m18, m3  ; A2 B2
+    vpdpwssd             m4, m15, m21 ; h3 i3
+    vpermt2b             m3, m9, m4   ; 67 78
+    vpdpwssd            m20, m19, m3  ; A3 B3
+    vpermb              m20, m22, m20
+    mova             [tmpq], ym20
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+    WIN64_SPILL_XMM      27
+%if WIN64
+    push                 r8
+%endif
+    vbroadcasti32x4     m20, [spel_h_shufA]
+    vbroadcasti32x4     m21, [spel_h_shufB]
+    add                  wd, wd
+    mova                 m9, [spel_shuf16]
+    mova                m26, [prep_endB]
+    lea                 r5d, [hq+wq*8-256]
+.hv_w16_loop0:
+    vbroadcasti32x8      m5, [srcq+strideq*0+ 8]
+    vinserti32x8         m4, m5, [srcq+strideq*0+ 0], 0
+    vinserti32x8         m5, [srcq+strideq*0+16], 1 ; 0
+    movu                ym6, [srcq+strideq*1+ 0]
+    movu                ym7, [srcq+strideq*1+16]
+    lea                  r7, [srcq+r6]
+    vinserti32x8         m6, [srcq+strideq*2+ 0], 1
+    vinserti32x8         m7, [srcq+strideq*2+16], 1 ; 1 2
+    movu               ym22, [r7  +strideq*0+ 0]
+    movu               ym23, [r7  +strideq*0+16]
+    mov                  r8, tmpq
+    vinserti32x8        m22, [r7  +strideq*1+ 0], 1
+    vinserti32x8        m23, [r7  +strideq*1+16], 1 ; 3 4
+    movu               ym24, [r7  +strideq*2+ 0]
+    movu               ym25, [r7  +strideq*2+16]
+    add                  r7, r6
+    vinserti32x8        m24, [r7  +strideq*0+ 0], 1
+    vinserti32x8        m25, [r7  +strideq*0+16], 1 ; 5 6
+    pshufb               m0, m4, m20
+    mova                 m1, m10
+    vpdpwssd             m1, m12, m0    ; a0
+    pshufb               m0, m6, m20
+    mova                 m2, m10
+    vpdpwssd             m2, m12, m0    ; b0
+    pshufb               m0, m7, m20
+    mova                 m3, m10
+    vpdpwssd             m3, m14, m0    ; c2
+    pshufb               m0, m4, m21
+    vpdpwssd             m1, m13, m0    ; a1
+    pshufb               m0, m6, m21
+    vpdpwssd             m2, m13, m0    ; b1
+    pshufb               m0, m7, m21
+    vpdpwssd             m3, m15, m0    ; c3
+    pshufb               m0, m5, m20
+    vpdpwssd             m1, m14, m0    ; a2
+    shufpd               m6, m7, 0x55
+    pshufb               m7, m6, m20
+    vpdpwssd             m2, m14, m7    ; b2
+    vpdpwssd             m3, m12, m7    ; c0
+    pshufb               m5, m21
+    vpdpwssd             m1, m15, m5    ; a3
+    pshufb               m6, m21
+    vpdpwssd             m2, m15, m6    ; b3
+    vpdpwssd             m3, m13, m6    ; c1
+    pshufb               m0, m22, m20
+    mova                 m4, m10
+    vpdpwssd             m4, m12, m0    ; d0
+    pshufb               m0, m23, m20
+    mova                 m5, m10
+    vpdpwssd             m5, m14, m0    ; e2
+    pshufb               m0, m24, m20
+    mova                 m6, m10
+    vpdpwssd             m6, m12, m0    ; f0
+    pshufb               m0, m25, m20
+    mova                 m7, m10
+    vpdpwssd             m7, m14, m0    ; g2
+    pshufb               m0, m22, m21
+    vpdpwssd             m4, m13, m0    ; d1
+    pshufb               m0, m23, m21
+    vpdpwssd             m5, m15, m0    ; e3
+    pshufb               m0, m24, m21
+    vpdpwssd             m6, m13, m0    ; f1
+    pshufb               m0, m25, m21
+    vpdpwssd             m7, m15, m0    ; g3
+    shufpd              m22, m23, 0x55
+    pshufb              m23, m22, m20
+    vpdpwssd             m4, m14, m23   ; d2
+    vpdpwssd             m5, m12, m23   ; e0
+    shufpd              m24, m25, 0x55
+    pshufb              m25, m24, m20
+    vpdpwssd             m6, m14, m25   ; f2
+    vpdpwssd             m7, m12, m25   ; g0
+    pshufb              m22, m21
+    vpdpwssd             m4, m15, m22   ; d3
+    vpdpwssd             m5, m13, m22   ; e1
+    pshufb              m24, m21
+    vpdpwssd             m6, m15, m24   ; f3
+    vpdpwssd             m7, m13, m24   ; g1
+    pslldq               m1, 1
+    vpermt2b             m2, m9, m3     ; 12
+    vpermt2b             m4, m9, m5     ; 34
+    vpermt2b             m6, m9, m7     ; 56
+    vpshrdd              m1, m2, 16     ; 01
+    vpshrdd              m3, m2, m4, 16 ; 23
+    vpshrdd              m5, m4, m6, 16 ; 45
+.hv_w16_loop:
+    movu               ym24, [r7+strideq*1+ 0]
+    movu               ym25, [r7+strideq*1+16]
+    lea                  r7, [r7+strideq*2]
+    vinserti32x8        m24, [r7+strideq*0+ 0], 1
+    vinserti32x8        m25, [r7+strideq*0+16], 1
+    mova                 m7, m10
+    mova                 m8, m10
+    pshufb               m0, m24, m20
+    vpdpwssd             m7, m12, m0    ; h0
+    mova                m22, m11
+    pshufb               m0, m25, m20
+    vpdpwssd             m8, m14, m0    ; i2
+    mova                m23, m11
+    vpdpwssd            m22, m16, m1    ; A0
+    mova                 m1, m3
+    vpdpwssd            m23, m16, m2    ; B0
+    mova                 m2, m4
+    pshufb               m0, m24, m21
+    vpdpwssd             m7, m13, m0    ; h1
+    pshufb               m0, m25, m21
+    vpdpwssd             m8, m15, m0    ; i3
+    vpdpwssd            m22, m17, m3    ; A1
+    mova                 m3, m5
+    vpdpwssd            m23, m17, m4    ; B1
+    mova                 m4, m6
+    shufpd              m24, m25, 0x55
+    pshufb              m25, m24, m20
+    vpdpwssd             m7, m14, m25   ; h2
+    vpdpwssd             m8, m12, m25   ; i0
+    vpdpwssd            m22, m18, m5    ; A2
+    vpdpwssd            m23, m18, m6    ; B2
+    pshufb              m24, m21
+    vpdpwssd             m7, m15, m24   ; h3
+    vpdpwssd             m8, m13, m24   ; i1
+    vpermt2b             m7, m9, m8     ; 78
+    vpshrdd              m5, m6, m7, 16 ; 67
+    vpdpwssd            m22, m19, m5    ; A3
+    vpdpwssd            m23, m19, m7    ; B3
+    mova                 m6, m7
+    vpermt2b            m22, m26, m23
+    mova          [r8+wq*0], ym22
+    vextracti32x8 [r8+wq*1], m22, 1
+    lea                  r8, [r8+wq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    add                srcq, 32
+    add                tmpq, 32
+    movzx                hd, r5b
+    sub                 r5d, 1<<8
+    jg .hv_w16_loop0
+%if WIN64
+    pop                  r8
+%endif
+    RET
+
+%if WIN64
+DECLARE_REG_TMP 5
+%else
+DECLARE_REG_TMP 7
+%endif
+
+cglobal warp_affine_8x8t_16bpc, 4, 7, 22, tmp, ts
+%define base r6-pd_0to7
+    mov                 t0d, r7m
+    lea                  r6, [pd_0to7]
+    shr                 t0d, 11
+    vpbroadcastd         m8, [base+warp_8x8t_rnd_v]
+    vpbroadcastd         m1, [base+warp_8x8_rnd_h+t0*4]
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_avx512icl).main
+    psrad               m14, m16, 15
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_avx512icl).main2
+    psrad               m16, 15
+    packssdw            m14, m16
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_avx512icl).main2
+    psrad               m15, m16, 15
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_avx512icl).main2
+    add                 tsq, tsq
+    psrad               m16, 15
+    packssdw            m15, m16
+    jmp mangle(private_prefix %+ _warp_affine_8x8_16bpc_avx512icl).end
+
+cglobal warp_affine_8x8_16bpc, 4, 7, 22, dst, ds, src, ss, abcd
+    mov                 t0d, r7m ; pixel_max
+    lea                  r6, [pd_0to7]
+    shr                 t0d, 11
+    vpbroadcastd         m1, [base+warp_8x8_rnd_h+t0*4]
+    vpbroadcastd         m8, [base+warp_8x8_rnd_v+t0*4]
+    call .main
+    psrad               m14, m16, 13
+    call .main2
+    psrad               m16, 13
+    packusdw            m14, m16
+    call .main2
+    psrad               m15, m16, 13
+    call .main2
+    vpbroadcastd         m0, [base+bidir_shift+t0*4]
+    vpsrlvw             m14, m0
+    psrad               m16, 13
+    packusdw            m15, m16
+    vpsrlvw             m15, m0
+.end:
+    mova                 m0, [base+warp8x8_end]
+    vpermb              m16, m0, m14
+    lea                  r2, [dsq*3]
+    mova          [dstq+dsq*0], xm16
+    vextracti128  [dstq+dsq*1], ym16, 1
+    vextracti32x4 [dstq+dsq*2], m16, 2
+    vextracti32x4 [dstq+r2   ], m16, 3
+    vpermb              m16, m0, m15
+    lea                dstq, [dstq+dsq*4]
+    mova          [dstq+dsq*0], xm16
+    vextracti128  [dstq+dsq*1], ym16, 1
+    vextracti32x4 [dstq+dsq*2], m16, 2
+    vextracti32x4 [dstq+r2   ], m16, 3
+    RET
+.main:
+    vpbroadcastd        ym3, [base+pd_512]
+%if WIN64
+    mov               abcdq, r5mp
+    vpaddd             ym18, ym3, r6m {1to8} ; mx
+%else
+    add                 r5d, 512
+    vpbroadcastd       ym18, r5d
+%endif
+    vpaddd             ym20, ym3, r7m {1to8} ; my
+    mova               ym16, [base+pd_0to7]
+    vpbroadcastd       ym19, [abcdq+4*0]     ; alpha
+    vpbroadcastd       ym21, [abcdq+4*1]     ; gamma
+    lea                  r4, [ssq*3+6]
+    vpdpwssd           ym18, ym19, ym16      ; tmx
+    vpdpwssd           ym20, ym21, ym16      ; tmy
+    sub                srcq, r4
+    mova                m10, [base+warp8x8_permA]
+    lea                  r4, [mc_warp_filter+64*8]
+    vbroadcasti32x4     m12, [base+warp8x8_permC]
+    kxnorb               k1, k1, k1
+    vbroadcasti32x4     m13, [base+warp8x8_permD]
+    movu                ym5, [srcq+0]
+    vinserti32x8         m5, [srcq+8], 1
+    psrad              ym17, ym18, 10
+    mova                m11, [base+warp8x8_permB]
+    kmovb                k2, k1
+    vpgatherdq       m3{k1}, [r4+ym17*8]    ; filter_x0
+    psrad              ym19, 16             ; beta
+    psrad              ym21, 16             ; delta
+    paddd              ym18, ym19
+    vpermb               m4, m10, m5
+    vpbroadcastq         m9, [base+warp_shift_h+t0*8]
+    pshufd               m3, m3, q3120
+    paddd                m7, m1, m1
+    pshufb               m2, m3, m12
+    vpdpwssd             m1, m4, m2
+    vpermb               m5, m11, m5
+    vshufi32x4           m4, m5, q1021
+    pshufb               m3, m13
+    vpdpwssd             m1, m4, m3
+    call .h
+    psllq                m2, m1, 32
+    paddd                m1, m2
+    vpmultishiftqb       m1, m9, m1
+    vpshrdq              m1, m0, 48          ; 01 12
+    call .h
+    vpshrdq              m2, m1, m0, 48      ; 23 34
+    call .h
+    vpshrdq              m3, m2, m0, 48      ; 45 56
+.main2:
+    call .h
+    psrad               ym6, ym20, 10
+    kmovb                k1, k2
+    paddd              ym17, ym20, ym21      ; my += delta
+    vpgatherdq      m20{k2}, [r4+ym6*8]      ; filter_y0
+    psrad              ym16, ym17, 10
+    kmovb                k2, k1
+    vpgatherdq       m6{k1}, [r4+ym16*8]     ; filter_y1
+    shufps               m5, m20, m6, q2020
+    mova                m16, m8
+    pshufb               m4, m5, m12
+    vpdpwssd            m16, m1, m4          ; a0 b0
+    pshufb               m5, m13
+    mova                 m1, m2
+    vpdpwssd            m16, m2, m5          ; a1 b1
+    shufps               m6, m20, m6, q3131
+    paddd              ym20, ym17, ym21
+    pshufb               m4, m6, m12
+    mova                 m2, m3
+    vpdpwssd            m16, m3, m4          ; a2 b2
+    vpshrdq              m3, m0, 48          ; 67 78
+    pshufb               m6, m13
+    vpdpwssd            m16, m3, m6          ; a3 b3
+    ret
+ALIGN function_align
+.h:
+    movu               ym16, [srcq+ssq*1]
+    psrad               ym6, ym18, 10
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8         m5, m16, [srcq+ssq*0], 1
+    kmovb                k1, k2
+    paddd              ym17, ym18, ym19      ; mx += beta
+    vpgatherdq      m18{k2}, [r4+ym6*8]      ; filter_x1
+    psrad              ym16, ym17, 10
+    kmovb                k2, k1
+    vpgatherdq       m6{k1}, [r4+ym16*8]     ; filter_x2
+    vpermb               m4, m10, m5
+    shufps              m16, m18, m6, q2020
+    shufps               m6, m18, m6, q3131
+    mova                 m0, m7
+    pshufb              m18, m16, m12
+    vpdpwssd             m0, m4, m18         ; a0 b0
+    vpermb               m5, m11, m5
+    pshufb              m18, m6, m13
+    vpdpwssd             m0, m5, m18         ; a3 b3
+    paddd              ym18, ym17, ym19
+    vshufi32x4          m17, m4, m5, q1021
+    pshufb              m16, m13
+    vpdpwssd             m0, m17, m16        ; a1 b1
+    vshufi32x4           m4, m5, q2132
+    pshufb               m6, m12
+    vpdpwssd             m0, m4, m6          ; a2 b2
+    vpmultishiftqb       m0, m9, m0          ; a a b b
+    ret
+
+%macro BIDIR_FN 0
+    call .main
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    movq   [dstq          ], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti32x4       xm2, ym0, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    cmp                  hd, 8
+    jl .w4_end
+    vextracti32x4       xm2, m0, 2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq          ], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti32x4       xm0, m0, 3
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    je .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq          ], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti32x4       xm0, ym1, 1
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    vextracti32x4       xm0, m1, 2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq          ], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti32x4       xm1, m1, 3
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+.w4_end:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w8:
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    sub                  hd, 8
+    jl .w8_end
+    lea                dstq, [dstq+strideq*4]
+    mova          [dstq+strideq*0], xm1
+    vextracti32x4 [dstq+strideq*1], ym1, 1
+    vextracti32x4 [dstq+strideq*2], m1, 2
+    vextracti32x4 [dstq+stride3q ], m1, 3
+    jg .w8_loop
+.w8_end:
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+stride3q ], m1, 1
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w32:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    call .main
+    mova        [dstq+64*2], m0
+    mova        [dstq+64*3], m1
+    dec                  hd
+    jg .w128_loop
+    RET
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 5
+%else
+DECLARE_REG_TMP 7
+%endif
+
+cglobal avg_16bpc, 4, 7, 4, dst, stride, tmp1, tmp2, w, h, stride3
+%define base r6-avg_avx512icl_table
+    lea                  r6, [avg_avx512icl_table]
+    tzcnt                wd, wm
+    mov                 t0d, r6m ; pixel_max
+    movsxd               wq, [r6+wq*4]
+    shr                 t0d, 11
+    vpbroadcastd         m2, [base+avg_round+t0*4]
+    vpbroadcastd         m3, [base+avg_shift+t0*4]
+    movifnidn            hd, hm
+    add                  wq, r6
+    BIDIR_FN
+ALIGN function_align
+.main:
+    mova                 m0, [tmp1q+64*0]
+    paddsw               m0, [tmp2q+64*0]
+    mova                 m1, [tmp1q+64*1]
+    paddsw               m1, [tmp2q+64*1]
+    add               tmp1q, 64*2
+    add               tmp2q, 64*2
+    pmaxsw               m0, m2
+    pmaxsw               m1, m2
+    psubsw               m0, m2
+    psubsw               m1, m2
+    vpsrlvw              m0, m3
+    vpsrlvw              m1, m3
+    ret
+
+cglobal w_avg_16bpc, 4, 7, 8, dst, stride, tmp1, tmp2, w, h, stride3
+%define base r6-w_avg_avx512icl_table
+    lea                  r6, [w_avg_avx512icl_table]
+    tzcnt                wd, wm
+    mov                 t0d, r7m ; pixel_max
+    shr                 t0d, 11
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastd         m5, [base+w_avg_round+t0*4]
+    vpbroadcastd         m7, [base+bidir_shift+t0*4]
+    add                  wq, r6
+    mov                 r6d, r6m ; weight
+    lea                 t0d, [r6-16]
+    shl                 r6d, 16
+    sub                 r6d, t0d ; 16-weight, weight
+    movifnidn            hd, hm
+    vpbroadcastd         m6, r6d
+    BIDIR_FN
+ALIGN function_align
+.main:
+    mova                 m3, [tmp1q+64*0]
+    mova                 m1, [tmp2q+64*0]
+    mova                 m0, [tmp1q+64*1]
+    mova                 m4, [tmp2q+64*1]
+    add               tmp1q, 64*2
+    add               tmp2q, 64*2
+    punpcklwd            m2, m1, m3
+    punpckhwd            m1, m3
+    punpcklwd            m3, m4, m0
+    punpckhwd            m4, m0
+    mova                 m0, m5
+    vpdpwssd             m0, m6, m2
+    mova                 m2, m5
+    vpdpwssd             m2, m6, m1
+    mova                 m1, m5
+    vpdpwssd             m1, m6, m3
+    mova                 m3, m5
+    vpdpwssd             m3, m6, m4
+    REPX       {psrad x, 2}, m0, m2, m1, m3
+    packusdw             m0, m2
+    packusdw             m1, m3
+    vpsrlvw              m0, m7
+    vpsrlvw              m1, m7
+    ret
+
+cglobal mask_16bpc, 4, 8, 11, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-mask_avx512icl_table
+    lea                  r7, [mask_avx512icl_table]
+    tzcnt                wd, wm
+    mov                 r6d, r7m ; pixel_max
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd         m8, [base+pw_64]
+    vpbroadcastd         m9, [base+mask_round+r6*4]
+    vpbroadcastd        m10, [base+bidir_shift+r6*4]
+    mov               maskq, maskmp
+    add                  wq, r7
+    BIDIR_FN
+ALIGN function_align
+.main:
+    pmovzxbw             m1, [maskq+32*0]
+    mova                 m4, [tmp1q+64*0]
+    mova                 m2, [tmp2q+64*0]
+    pmovzxbw             m6, [maskq+32*1]
+    mova                 m5, [tmp1q+64*1]
+    mova                 m3, [tmp2q+64*1]
+    add               maskq, 32*2
+    add               tmp1q, 64*2
+    add               tmp2q, 64*2
+    punpcklwd            m7, m4, m2
+    punpckhwd            m4, m2
+    psubw                m0, m8, m1
+    punpcklwd            m2, m1, m0 ; m, 64-m
+    punpckhwd            m1, m0
+    mova                 m0, m9
+    vpdpwssd             m0, m7, m2
+    mova                 m2, m9
+    vpdpwssd             m2, m4, m1 ; tmp1 * m + tmp2 * (64-m)
+    punpcklwd            m7, m5, m3
+    punpckhwd            m5, m3
+    psubw                m1, m8, m6
+    punpcklwd            m3, m6, m1
+    punpckhwd            m6, m1
+    mova                 m1, m9
+    vpdpwssd             m1, m7, m3
+    mova                 m3, m9
+    vpdpwssd             m3, m5, m6
+    REPX       {psrad x, 4}, m0, m2, m1, m3
+    packusdw             m0, m2
+    packusdw             m1, m3
+    vpsrlvw              m0, m10
+    vpsrlvw              m1, m10
+    ret
+
+cglobal w_mask_420_16bpc, 4, 8, 16, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_420_avx512icl_table
+    lea                  r7, [w_mask_420_avx512icl_table]
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd        m10, [base+pw_27615] ; ((64 - 38) << 10) + 1023 - 32
+    vpbroadcastd        m11, [base+pw_64]
+    vpbroadcastd        m12, [base+mask_round+r6*4]
+    vpbroadcastd        m13, [base+bidir_shift+r6*4]
+    mov                 r6d, r7m ; sign
+    vpbroadcastd        m14, [base+w_mask_round+r6*4]
+    mova               ym15, [w_mask_end42x]
+    mov               maskq, maskmp
+    add                  wq, r7
+    call .main
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    mova                 m4, [w_mask_shuf4]
+    vpermt2b             m2, m4, m3
+    mova                 m3, m14
+    vpdpbusd             m3, m2, [pb_64] {1to16}
+    vpermb               m3, m15, m3
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti32x4       xm2, ym0, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    mova            [maskq], xm3
+    cmp                  hd, 8
+    jl .w4_end
+    vextracti32x4       xm2, m0, 2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti32x4       xm0, m0, 3
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    je .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti32x4       xm2, ym1, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    vextracti32x4       xm2, m1, 2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti32x4       xm1, m1, 3
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+.w4_end:
+    RET
+.w8:
+    mova                 m8, [w_mask_shuf8]
+    vpbroadcastd         m9, [pb_64]
+    jmp .w8_start
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 16
+.w8_start:
+    vpermt2b             m2, m8, m3
+    mova                 m3, m14
+    vpdpbusd             m3, m2, m9
+    vpermb               m3, m15, m3
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    mova            [maskq], xm3
+    sub                  hd, 8
+    jl .w8_end
+    lea                dstq, [dstq+strideq*4]
+    mova          [dstq+strideq*0], xm1
+    vextracti32x4 [dstq+strideq*1], ym1, 1
+    vextracti32x4 [dstq+strideq*2], m1, 2
+    vextracti32x4 [dstq+stride3q ], m1, 3
+    jg .w8_loop
+.w8_end:
+    RET
+.w16:
+    mova                 m8, [w_mask_shuf16]
+    vpbroadcastd         m9, [pb_64]
+    jmp .w16_start
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 16
+.w16_start:
+    vpermt2b             m2, m8, m3
+    mova                 m3, m14
+    vpdpbusd             m3, m2, m9
+    vpermb               m3, m15, m3
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+stride3q ], m1, 1
+    mova            [maskq], xm3
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 32
+.w32:
+    paddw                m2, m3
+    mova                 m8, m14
+    vpdpwssd             m8, m11, m2
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    call .main
+    paddw                m2, m3
+    mova                 m3, m14
+    vpdpwssd             m3, m11, m2
+    vpermt2b             m8, m15, m3
+    mova   [dstq+strideq*2], m0
+    mova   [dstq+stride3q ], m1
+    mova            [maskq], ym8
+    sub                  hd, 4
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 32
+.w64:
+    mova                 m8, m2
+    mova                 m9, m3
+    mova [dstq+strideq*0+64*0], m0
+    mova [dstq+strideq*0+64*1], m1
+    call .main
+    paddw                m8, m2
+    paddw                m9, m3
+    mova                 m2, m14
+    vpdpwssd             m2, m11, m8
+    mova                 m3, m14
+    vpdpwssd             m3, m11, m9
+    vpermt2b             m2, m15, m3
+    mova [dstq+strideq*1+64*0], m0
+    mova [dstq+strideq*1+64*1], m1
+    mova            [maskq], ym2
+    sub                  hd, 2
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 64
+.w128:
+    mova               m16, m2
+    mova                m8, m3
+    mova [dstq+strideq*0+64*0], m0
+    mova [dstq+strideq*0+64*1], m1
+    call .main
+    mova                m17, m2
+    mova                 m9, m3
+    mova [dstq+strideq*0+64*2], m0
+    mova [dstq+strideq*0+64*3], m1
+    call .main
+    paddw                m2, m16
+    paddw                m3, m8
+    mova                m16, m14
+    vpdpwssd            m16, m11, m2
+    mova                 m8, m14
+    vpdpwssd             m8, m11, m3
+    mova [dstq+strideq*1+64*0], m0
+    mova [dstq+strideq*1+64*1], m1
+    call .main
+    paddw                m2, m17
+    paddw                m3, m9
+    mova                m17, m14
+    vpdpwssd            m17, m11, m2
+    mova                 m9, m14
+    vpdpwssd             m9, m11, m3
+    vpermt2b            m16, m15, m8
+    vpermt2b            m17, m15, m9
+    mova [dstq+strideq*1+64*2], m0
+    mova [dstq+strideq*1+64*3], m1
+    mova       [maskq+32*0], ym16
+    mova       [maskq+32*1], ym17
+    sub                  hd, 2
+    jg .w128_loop
+    vzeroupper
+    RET
+ALIGN function_align
+.main:
+    mova                 m1, [tmp1q+64*0]
+    mova                 m3, [tmp2q+64*0]
+    mova                 m4, [tmp1q+64*1]
+    mova                 m7, [tmp2q+64*1]
+    add               tmp1q, 64*2
+    add               tmp2q, 64*2
+    psubsw               m6, m1, m3
+    punpcklwd            m5, m3, m1
+    pabsw                m6, m6
+    punpckhwd            m3, m1
+    psubusw              m6, m10, m6
+    psrlw                m6, 10      ; 64-m
+    psubw                m2, m11, m6 ; m
+    punpcklwd            m1, m6, m2
+    punpckhwd            m6, m2
+    mova                 m0, m12
+    vpdpwssd             m0, m5, m1
+    mova                 m1, m12
+    vpdpwssd             m1, m3, m6
+    psubsw               m5, m4, m7
+    punpcklwd            m6, m7, m4
+    pabsw                m5, m5
+    punpckhwd            m7, m4
+    psubusw              m5, m10, m5
+    psrlw                m5, 10
+    psubw                m3, m11, m5
+    punpcklwd            m4, m5, m3
+    psrad                m0, 4
+    punpckhwd            m5, m3
+    psrad                m1, 4
+    packusdw             m0, m1
+    mova                 m1, m12
+    vpdpwssd             m1, m6, m4
+    mova                 m4, m12
+    vpdpwssd             m4, m7, m5
+    psrad                m1, 4
+    psrad                m4, 4
+    packusdw             m1, m4
+    vpsrlvw              m0, m13
+    vpsrlvw              m1, m13
+    ret
+
+cglobal w_mask_422_16bpc, 4, 8, 15, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_422_avx512icl_table
+    lea                  r7, [w_mask_422_avx512icl_table]
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd         m8, [base+pw_27615] ; ((64 - 38) << 10) + 1023 - 32
+    vpbroadcastd         m9, [base+pw_64]
+    vpbroadcastd        m10, [base+mask_round+r6*4]
+    vpbroadcastd        m11, [base+bidir_shift+r6*4]
+    mov                 r6d, r7m ; sign
+    vpbroadcastd        m12, [base+w_mask_round+r6*4]
+    mova               ym13, [w_mask_end42x]
+    mov               maskq, maskmp
+    add                  wq, r7
+    paddw               m14, m9, m9 ; pw_128
+    call .main
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti32x4       xm2, ym0, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    cmp                  hd, 8
+    jl .w4_end
+    vextracti32x4       xm2, m0, 2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti32x4       xm0, m0, 3
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    je .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti32x4       xm2, ym1, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    vextracti32x4       xm2, m1, 2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti32x4       xm1, m1, 3
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+.w4_end:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w8:
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    sub                  hd, 8
+    jl .w8_end
+    lea                dstq, [dstq+strideq*4]
+    mova          [dstq+strideq*0], xm1
+    vextracti32x4 [dstq+strideq*1], ym1, 1
+    vextracti32x4 [dstq+strideq*2], m1, 2
+    vextracti32x4 [dstq+stride3q ], m1, 3
+    jg .w8_loop
+.w8_end:
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+stride3q ], m1, 1
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w32:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    call .main
+    mova        [dstq+64*2], m0
+    mova        [dstq+64*3], m1
+    dec                  hd
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+    mova                 m1, [tmp1q+64*0]
+    mova                 m3, [tmp2q+64*0]
+    mova                 m4, [tmp1q+64*1]
+    mova                 m7, [tmp2q+64*1]
+    add               tmp1q, 64*2
+    add               tmp2q, 64*2
+    psubsw               m6, m1, m3
+    punpcklwd            m5, m3, m1
+    pabsw                m6, m6
+    punpckhwd            m3, m1
+    psubusw              m6, m8, m6
+    psrlw                m6, 10
+    psubw                m2, m9, m6
+    punpcklwd            m1, m6, m2
+    punpckhwd            m6, m2
+    mova                 m0, m10
+    vpdpwssd             m0, m5, m1
+    mova                 m1, m10
+    vpdpwssd             m1, m3, m6
+    psubsw               m5, m4, m7
+    punpcklwd            m6, m7, m4
+    pabsw                m5, m5
+    punpckhwd            m7, m4
+    psubusw              m5, m8, m5
+    psrlw                m5, 10
+    psubw                m3, m9, m5
+    punpcklwd            m4, m5, m3
+    psrad                m0, 4
+    punpckhwd            m5, m3
+    psrad                m1, 4
+    packusdw             m0, m1
+    mova                 m1, m10
+    vpdpwssd             m1, m6, m4
+    mova                 m4, m10
+    vpdpwssd             m4, m7, m5
+    mova                 m5, m12
+    vpdpwssd             m5, m14, m2
+    mova                 m2, m12
+    vpdpwssd             m2, m14, m3
+    psrad                m1, 4
+    psrad                m4, 4
+    packusdw             m1, m4
+    vpermt2b             m5, m13, m2
+    vpsrlvw              m0, m11
+    vpsrlvw              m1, m11
+    mova            [maskq], ym5
+    add               maskq, 32
+    ret
+
+cglobal w_mask_444_16bpc, 4, 8, 13, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_444_avx512icl_table
+    lea                  r7, [w_mask_444_avx512icl_table]
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    movifnidn            hd, hm
+    shr                 r6d, 11
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd         m8, [base+pw_27615] ; ((64 - 38) << 10) + 1023 - 32
+    vpbroadcastd         m9, [base+pw_64]
+    vpbroadcastd        m10, [base+mask_round+r6*4]
+    mova                m11, [w_mask_end444]
+    vpbroadcastd        m12, [base+bidir_shift+r6*4]
+    mov               maskq, maskmp
+    add                  wq, r7
+    call .main
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    movq   [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm0
+    vextracti32x4       xm2, ym0, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    cmp                  hd, 8
+    jl .w4_end
+    vextracti32x4       xm2, m0, 2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti32x4       xm0, m0, 3
+    movq   [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm0
+    je .w4_end
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm1
+    movhps [dstq+strideq*1], xm1
+    vextracti32x4       xm2, ym1, 1
+    movq   [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm2
+    vextracti32x4       xm2, m1, 2
+    lea                dstq, [dstq+strideq*4]
+    movq   [dstq+strideq*0], xm2
+    movhps [dstq+strideq*1], xm2
+    vextracti32x4       xm1, m1, 3
+    movq   [dstq+strideq*2], xm1
+    movhps [dstq+stride3q ], xm1
+.w4_end:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w8:
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], ym0, 1
+    vextracti32x4 [dstq+strideq*2], m0, 2
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    sub                  hd, 8
+    jl .w8_end
+    lea                dstq, [dstq+strideq*4]
+    mova          [dstq+strideq*0], xm1
+    vextracti32x4 [dstq+strideq*1], ym1, 1
+    vextracti32x4 [dstq+strideq*2], m1, 2
+    vextracti32x4 [dstq+stride3q ], m1, 3
+    jg .w8_loop
+.w8_end:
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    mova          [dstq+strideq*2], ym1
+    vextracti32x8 [dstq+stride3q ], m1, 1
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w32:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    call .main
+    mova        [dstq+64*2], m0
+    mova        [dstq+64*3], m1
+    dec                  hd
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+    mova                 m1, [tmp1q+64*0]
+    mova                 m3, [tmp2q+64*0]
+    mova                 m4, [tmp1q+64*1]
+    mova                 m7, [tmp2q+64*1]
+    add               tmp1q, 64*2
+    add               tmp2q, 64*2
+    psubsw               m6, m1, m3
+    punpcklwd            m5, m3, m1
+    pabsw                m6, m6
+    punpckhwd            m3, m1
+    psubusw              m6, m8, m6
+    psrlw                m6, 10
+    psubw                m2, m9, m6
+    punpcklwd            m1, m6, m2
+    punpckhwd            m6, m2
+    mova                 m0, m10
+    vpdpwssd             m0, m5, m1
+    mova                 m1, m10
+    vpdpwssd             m1, m3, m6
+    psubsw               m5, m4, m7
+    punpcklwd            m6, m7, m4
+    pabsw                m5, m5
+    punpckhwd            m7, m4
+    psubusw              m5, m8, m5
+    psrlw                m5, 10
+    psubw                m3, m9, m5
+    punpcklwd            m4, m5, m3
+    psrad                m0, 4
+    punpckhwd            m5, m3
+    psrad                m1, 4
+    packusdw             m0, m1
+    mova                 m1, m10
+    vpdpwssd             m1, m6, m4
+    mova                 m4, m10
+    vpdpwssd             m4, m7, m5
+    vpermt2b             m2, m11, m3
+    psrad                m1, 4
+    psrad                m4, 4
+    packusdw             m1, m4
+    vpsrlvw              m0, m12
+    vpsrlvw              m1, m12
+    mova            [maskq], m2
+    add               maskq, 64
+    ret
+
+cglobal blend_16bpc, 3, 7, 7, dst, ds, tmp, w, h, mask
+%define base r6-blend_avx512icl_table
+    lea                  r6, [blend_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r6+wq*4]
+    movifnidn         maskq, maskmp
+    vpbroadcastd         m6, [base+pw_m512]
+    add                  wq, r6
+    lea                  r6, [dsq*3]
+    jmp                  wq
+.w4:
+    pmovzxbw           ym19, [maskq]
+    movq               xm16, [dstq+dsq*0]
+    movhps             xm16, [dstq+dsq*1]
+    vpbroadcastq       ym17, [dstq+dsq*2]
+    vpbroadcastq       ym18, [dstq+r6   ]
+    pmullw             ym19, ym6
+    vpblendd           ym16, ym17, 0x30
+    vpblendd           ym16, ym18, 0xc0
+    psubw              ym17, ym16, [tmpq]
+    add               maskq, 16
+    add                tmpq, 32
+    pmulhrsw           ym17, ym19
+    paddw              ym16, ym17
+    vextracti128       xm17, ym16, 1
+    movq       [dstq+dsq*0], xm16
+    movhps     [dstq+dsq*1], xm16
+    movq       [dstq+dsq*2], xm17
+    movhps     [dstq+r6   ], xm17
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w4
+    vzeroupper
+    RET
+.w8:
+    pmovzxbw             m2, [maskq]
+    mova                xm0, [dstq+dsq*0]
+    vinserti32x4        ym0, [dstq+dsq*1], 1
+    vinserti32x4         m0, [dstq+dsq*2], 2
+    vinserti32x4         m0, [dstq+r6   ], 3
+    pmullw               m2, m6
+    psubw                m1, m0, [tmpq]
+    add               maskq, 32
+    add                tmpq, 64
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], ym0, 1
+    vextracti32x4 [dstq+dsq*2], m0, 2
+    vextracti32x4 [dstq+r6   ], m0, 3
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+.w16:
+    pmovzxbw             m4, [maskq+32*0]
+    pmovzxbw             m5, [maskq+32*1]
+    mova                ym0, [dstq+dsq*0]
+    vinserti32x8         m0, [dstq+dsq*1], 1
+    mova                ym1, [dstq+dsq*2]
+    vinserti32x8         m1, [dstq+r6   ], 1
+    pmullw               m4, m6
+    pmullw               m5, m6
+    psubw                m2, m0, [tmpq+64*0]
+    psubw                m3, m1, [tmpq+64*1]
+    add               maskq, 32*2
+    add                tmpq, 64*2
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    mova          [dstq+dsq*2], ym1
+    vextracti32x8 [dstq+r6   ], m1, 1
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w16
+    RET
+.w32:
+    pmovzxbw             m4, [maskq+32*0]
+    pmovzxbw             m5, [maskq+32*1]
+    mova                 m0, [dstq+dsq*0]
+    mova                 m1, [dstq+dsq*1]
+    pmullw               m4, m6
+    pmullw               m5, m6
+    psubw                m2, m0, [tmpq+ 64*0]
+    psubw                m3, m1, [tmpq+ 64*1]
+    add               maskq, 32*2
+    add                tmpq, 64*2
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w32
+    RET
+
+cglobal blend_v_16bpc, 3, 6, 5, dst, ds, tmp, w, h
+    lea                  r5, [blend_v_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  wq
+.w2:
+    vpbroadcastd       xmm2, [obmc_masks_avx2+2*2]
+.w2_loop:
+    movd               xmm0, [dstq+dsq*0]
+    pinsrd             xmm0, [dstq+dsq*1], 1
+    movq               xmm1, [tmpq]
+    add                tmpq, 4*2
+    psubw              xmm1, xmm0, xmm1
+    pmulhrsw           xmm1, xmm2
+    paddw              xmm0, xmm1
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w2_loop
+    RET
+.w4:
+    vpbroadcastq       xmm2, [obmc_masks_avx2+4*2]
+.w4_loop:
+    movq               xmm0, [dstq+dsq*0]
+    movhps             xmm0, [dstq+dsq*1]
+    psubw              xmm1, xmm0, [tmpq]
+    add                tmpq, 8*2
+    pmulhrsw           xmm1, xmm2
+    paddw              xmm0, xmm1
+    movq       [dstq+dsq*0], xmm0
+    movhps     [dstq+dsq*1], xmm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+.w8:
+    vbroadcasti32x4     ym2, [obmc_masks_avx2+8*2]
+.w8_loop:
+    mova                xm0, [dstq+dsq*0]
+    vinserti32x4        ym0, [dstq+dsq*1], 1
+    psubw               ym1, ym0, [tmpq]
+    add                tmpq, 16*2
+    pmulhrsw            ym1, ym2
+    paddw               ym0, ym1
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], ym0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16:
+    vbroadcasti32x8      m2, [obmc_masks_avx2+16*2]
+.w16_loop:
+    mova                ym0, [dstq+dsq*0]
+    vinserti32x8         m0, [dstq+dsq*1], 1
+    psubw                m1, m0, [tmpq]
+    add                tmpq, 32*2
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32:
+    mova                 m4, [obmc_masks_avx2+32*2]
+.w32_loop:
+    mova                 m0,     [dstq+dsq*0]
+    psubw                m2, m0, [tmpq+ 64*0]
+    mova                 m1,     [dstq+dsq*1]
+    psubw                m3, m1, [tmpq+ 64*1]
+    add                tmpq, 64*2
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+
+cglobal blend_h_16bpc, 3, 7, 9, dst, ds, tmp, w, h, mask
+%define base r6-$$
+    lea                  r6, [$$]
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [base+blend_h_avx512icl_table+wq*4]
+    lea               maskq, [base+obmc_masks_avx2+hq*2]
+    lea                  hd, [hq*3]
+    lea                  wq, [base+blend_h_avx512icl_table+wq]
+    shr                  hd, 2 ; h * 3/4
+    lea               maskq, [maskq+hq*2]
+    neg                  hq
+    jmp                  wq
+.w2:
+    movd               xmm0, [dstq+dsq*0]
+    pinsrd             xmm0, [dstq+dsq*1], 1
+    movd               xmm2, [maskq+hq*2]
+    movq               xmm1, [tmpq]
+    add                tmpq, 4*2
+    punpcklwd          xmm2, xmm2
+    psubw              xmm1, xmm0, xmm1
+    pmulhrsw           xmm1, xmm2
+    paddw              xmm0, xmm1
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w2
+    RET
+.w4:
+    mova               xmm3, [blend_shuf]
+.w4_loop:
+    movq               xmm0, [dstq+dsq*0]
+    movhps             xmm0, [dstq+dsq*1]
+    movd               xmm2, [maskq+hq*2]
+    psubw              xmm1, xmm0, [tmpq]
+    add                tmpq, 8*2
+    pshufb             xmm2, xmm3
+    pmulhrsw           xmm1, xmm2
+    paddw              xmm0, xmm1
+    movq       [dstq+dsq*0], xmm0
+    movhps     [dstq+dsq*1], xmm0
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w4_loop
+    RET
+.w8:
+    vbroadcasti32x4     ym3, [blend_shuf]
+    shufpd              ym3, ym3, 0x0c
+.w8_loop:
+    mova                xm0, [dstq+dsq*0]
+    vinserti32x4        ym0, [dstq+dsq*1], 1
+    vpbroadcastd        ym2, [maskq+hq*2]
+    psubw               ym1, ym0, [tmpq]
+    add                tmpq, 16*2
+    pshufb              ym2, ym3
+    pmulhrsw            ym1, ym2
+    paddw               ym0, ym1
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], ym0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w8_loop
+    RET
+.w16:
+    vbroadcasti32x4      m3, [blend_shuf]
+    shufpd               m3, m3, 0xf0
+.w16_loop:
+    mova                ym0, [dstq+dsq*0]
+    vinserti32x8         m0, [dstq+dsq*1], 1
+    vpbroadcastd         m2, [maskq+hq*2]
+    psubw                m1, m0, [tmpq]
+    add                tmpq, 32*2
+    pshufb               m2, m3
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w16_loop
+    RET
+.w32:
+    vpbroadcastw         m4, [maskq+hq*2]
+    vpbroadcastw         m5, [maskq+hq*2+2]
+    mova                 m0,     [dstq+dsq*0]
+    psubw                m2, m0, [tmpq+ 64*0]
+    mova                 m1,     [dstq+dsq*1]
+    psubw                m3, m1, [tmpq+ 64*1]
+    add                tmpq, 64*2
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w32
+    RET
+.w64:
+    vpbroadcastw         m4, [maskq+hq*2]
+    mova                 m0,     [dstq+64*0]
+    psubw                m2, m0, [tmpq+64*0]
+    mova                 m1,     [dstq+64*1]
+    psubw                m3, m1, [tmpq+64*1]
+    add                tmpq, 64*2
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    add                dstq, dsq
+    inc                  hq
+    jl .w64
+    RET
+.w128:
+    vpbroadcastw         m8, [maskq+hq*2]
+    mova                 m0,     [dstq+64*0]
+    psubw                m4, m0, [tmpq+64*0]
+    mova                 m1,     [dstq+64*1]
+    psubw                m5, m1, [tmpq+64*1]
+    mova                 m2,     [dstq+64*2]
+    psubw                m6, m2, [tmpq+64*2]
+    mova                 m3,     [dstq+64*3]
+    psubw                m7, m3, [tmpq+64*3]
+    add                tmpq, 64*4
+    REPX   {pmulhrsw x, m8}, m4, m5, m6, m7
+    paddw                m0, m4
+    paddw                m1, m5
+    paddw                m2, m6
+    paddw                m3, m7
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    mova        [dstq+64*2], m2
+    mova        [dstq+64*3], m3
+    add                dstq, dsq
+    inc                  hq
+    jl .w128
+    RET
+
+cglobal resize_16bpc, 6, 12, 32, dst, dst_stride, src, src_stride, \
+                                 dst_w, h, src_w, dx, mx0, pxmax
+    sub          dword mx0m, 4<<14
+    sub        dword src_wm, 8
+    mov                  r6, ~0
+    vpbroadcastd         m5, dxm
+    vpbroadcastd         m8, mx0m
+    vpbroadcastd         m6, src_wm
+    kmovq                k6, r6
+ DEFINE_ARGS dst, dst_stride, src, src_stride, dst_w, h, x, _, _, pxmax
+    LEA                  r7, $$
+%define base r7-$$
+    vpbroadcastd         m3, [base+pd_16384]
+    vpbroadcastd         m7, [base+pd_63]
+    mova                m24, [base+resize_permA]
+    mova                m25, [base+resize_permB]
+    mova                m26, [base+resize_permC]
+    mova                m27, [base+resize_permD]
+    vbroadcasti32x4     m28, [base+resize_shufA]
+    vbroadcasti32x4     m29, [base+resize_shufB]
+    mova                m30, [base+resize_permE]
+    vpbroadcastw       ym31, pxmaxm
+    vpdpwssd             m8, m5, [base+rescale_mul] ; mx+dx*[0-15]
+    pslld                m5, 4                      ; dx*16
+    pslld                m6, 14
+    pxor                 m2, m2
+.loop_y:
+    xor                  xd, xd
+    mova                 m4, m8     ; per-line working version of mx
+.loop_x:
+    pmaxsd               m0, m4, m2
+    psrad                m9, m4, 8  ; filter offset (unmasked)
+    pminsd               m0, m6     ; iclip(mx, 0, src_w-8)
+    psubd                m1, m4, m0 ; pshufb offset
+    psrad                m0, 14     ; clipped src_x offset
+    psrad                m1, 14     ; pshufb edge_emu offset
+    vptestmd             k5, m1, m1
+    pand                 m9, m7     ; filter offset (masked)
+    ktestw               k5, k5
+    jz .load
+    vpbroadcastq        m14, [base+pd_0_4]
+    vpermq              m10, m0, q1100
+    vpermq              m11, m0, q3322
+    vpermq              m20, m1, q1100
+    vpermq              m21, m1, q3322
+    punpckldq           m10, m10
+    punpckldq           m11, m11
+    punpckldq           m20, m20
+    punpckldq           m21, m21
+    paddd               m10, m14
+    paddd               m11, m14
+    paddd               m20, m14
+    paddd               m21, m14
+    vextracti32x8      ym12, m10, 1
+    vextracti32x8      ym13, m11, 1
+    vextracti32x8      ym22, m20, 1
+    vextracti32x8      ym23, m21, 1
+    kmovq                k1, k6
+    kmovq                k2, k6
+    kmovq                k3, k6
+    kmovq                k4, k6
+    vpgatherdq      m16{k1}, [srcq+ym10*2] ; 0 1 2 3
+    vpgatherdq      m17{k2}, [srcq+ym11*2] ; 4 5 6 7
+    vpgatherdq      m18{k3}, [srcq+ym12*2] ; 8 9 A B
+    vpgatherdq      m19{k4}, [srcq+ym13*2] ; C D E F
+    kmovq                k1, k6
+    kmovq                k2, k6
+    kmovq                k3, k6
+    kmovq                k4, k6
+    vpgatherdq       m0{k1}, [base+resize_shuf+8+ym20*2]
+    vpgatherdq       m1{k2}, [base+resize_shuf+8+ym21*2]
+    vpgatherdq      m14{k3}, [base+resize_shuf+8+ym22*2]
+    vpgatherdq      m15{k4}, [base+resize_shuf+8+ym23*2]
+    pshufb              m16, m0
+    pshufb              m17, m1
+    pshufb              m18, m14
+    pshufb              m19, m15
+    mova                m20, m24
+    mova                m22, m24
+    mova                m21, m25
+    mova                m23, m25
+    vpermi2d            m20, m16, m17 ; 0-3a 0-3b 4-7a 4-7b
+    vpermi2d            m21, m16, m17 ; 0-3c 0-3d 4-7c 4-7d
+    vpermi2d            m22, m18, m19 ; 8-Ba 8-Bb C-Fa C-Fb
+    vpermi2d            m23, m18, m19 ; 8-Bc 8-Bd C-Fc C-Fd
+    mova                m15, m26
+    mova                m17, m26
+    mova                m16, m27
+    mova                m18, m27
+    vpermi2q            m15, m20, m22 ; 0-3a 4-7a 8-Ba C-Fa
+    vpermi2q            m16, m20, m22 ; 0-3b 4-7b 8-Bb C-Fb
+    vpermi2q            m17, m21, m23 ; 0-3c 4-7c 8-Bc C-Fc
+    vpermi2q            m18, m21, m23 ; 0-3d 4-7d 8-Bd C-Fd
+    kmovq                k1, k6
+    kmovq                k2, k6
+    vpgatherdd      m11{k1}, [base+resize_filter+m9*8+0]
+    vpgatherdd      m13{k2}, [base+resize_filter+m9*8+4]
+    pshufb              m10, m11, m28
+    pshufb              m11, m11, m29
+    pshufb              m12, m13, m28
+    pshufb              m13, m13, m29
+    jmp .filter
+.load:
+    kmovq                k1, k6
+    kmovq                k2, k6
+    kmovq                k3, k6
+    kmovq                k4, k6
+    vpgatherdd      m11{k1}, [base+resize_filter+m9*8+0]
+    vpgatherdd      m13{k2}, [base+resize_filter+m9*8+4]
+    pshufb              m10, m11, m28
+    pshufb              m11, m11, m29
+    pshufb              m12, m13, m28
+    pshufb              m13, m13, m29
+    vpgatherdd      m15{k3}, [srcq+m0*2+ 0]
+    vpgatherdd      m16{k4}, [srcq+m0*2+ 4]
+    kmovq                k1, k6
+    kmovq                k2, k6
+    vpgatherdd      m17{k1}, [srcq+m0*2+ 8]
+    vpgatherdd      m18{k2}, [srcq+m0*2+12]
+.filter:
+    mova                m14, m2
+    vpdpwssd            m14, m15, m10
+    vpdpwssd            m14, m16, m11
+    vpdpwssd            m14, m17, m12
+    vpdpwssd            m14, m18, m13
+    psubd               m14, m3, m14
+    psrad               m14, 15
+    packusdw            m14, m14
+    vpermq              m14, m30, m14
+    pminsw             ym14, ym31
+    mova        [dstq+xq*2], ym14
+    paddd                m4, m5
+    add                  xd, 16
+    cmp                  xd, dst_wd
+    jl .loop_x
+    add                dstq, dst_strideq
+    add                srcq, src_strideq
+    dec                  hd
+    jg .loop_y
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/mc16_sse.asm b/media/libdav1d/src/src/x86/mc16_sse.asm
new file mode 100644
index 0000000000..319dd45544
--- /dev/null
+++ b/media/libdav1d/src/src/x86/mc16_sse.asm
@@ -0,0 +1,10109 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA
+
+; dav1d_obmc_masks[] << 9
+obmc_masks:     dw     0,     0,  9728,     0, 12800,  7168,  2560,     0
+                dw 14336, 11264,  8192,  5632,  3584,  1536,     0,     0
+                dw 15360, 13824, 12288, 10752,  9216,  7680,  6144,  5120
+                dw  4096,  3072,  2048,  1536,     0,     0,     0,     0
+                dw 15872, 14848, 14336, 13312, 12288, 11776, 10752, 10240
+                dw  9728,  8704,  8192,  7168,  6656,  6144,  5632,  4608
+                dw  4096,  3584,  3072,  2560,  2048,  2048,  1536,  1024
+
+blend_shuf:     db 0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  2,  3,  2,  3,  2,  3
+spel_h_shufA:   db 0,  1,  2,  3,  2,  3,  4,  5,  4,  5,  6,  7,  6,  7,  8,  9
+spel_h_shufB:   db 4,  5,  6,  7,  6,  7,  8,  9,  8,  9, 10, 11, 10, 11, 12, 13
+spel_h_shuf2:   db 0,  1,  2,  3,  4,  5,  6,  7,  2,  3,  4,  5,  6,  7,  8,  9
+spel_s_shuf2:   db 0,  1,  2,  3,  4,  5,  6,  7,  0,  1,  2,  3,  4,  5,  6,  7
+spel_s_shuf8:   db 0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+unpckw:         db 0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+rescale_mul:    dd 0,  1,  2,  3
+resize_shuf:    db 0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  4,  5,  6,  7
+                db 8,  9, 10, 11, 12, 13, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15
+bdct_lb_q: times 8 db 0
+           times 8 db 4
+           times 8 db 8
+           times 8 db 12
+
+pw_2:             times 8 dw 2
+pw_16:            times 4 dw 16
+prep_mul:         times 4 dw 16
+                  times 8 dw 4
+pw_64:            times 8 dw 64
+pw_256:           times 8 dw 256
+pw_2048:          times 4 dw 2048
+bidir_mul:        times 4 dw 2048
+pw_8192:          times 8 dw 8192
+pw_27615:         times 8 dw 27615
+pw_32766:         times 8 dw 32766
+pw_m512:          times 8 dw -512
+pd_63:            times 4 dd 63
+pd_64:            times 4 dd 64
+pd_512:           times 4 dd 512
+pd_2560:          times 2 dd 2560
+pd_8704:          times 2 dd 8704
+pd_m524256:       times 4 dd -524256 ; -8192 << 6 + 32
+pd_0x3ff:         times 4 dd 0x3ff
+pd_0x4000:        times 4 dd 0x4000
+pq_0x400000:      times 2 dq 0x400000
+pq_0x40000000:    times 2 dq 0x40000000
+pd_65538:         times 2 dd 65538
+
+put_bilin_h_rnd:  times 4 dw 8
+                  times 4 dw 10
+s_8tap_h_rnd:     times 2 dd 2
+                  times 2 dd 8
+put_s_8tap_v_rnd: times 2 dd 512
+                  times 2 dd 128
+s_8tap_h_sh:      dd 2, 4
+put_s_8tap_v_sh:  dd 10, 8
+bidir_rnd:        times 4 dw -16400
+                  times 4 dw -16388
+put_8tap_h_rnd:   dd 34, 34, 40, 40
+prep_8tap_1d_rnd: times 2 dd     8 - (8192 <<  4)
+prep_8tap_2d_rnd: times 4 dd    32 - (8192 <<  5)
+
+warp8x8_shift:    dd 11, 13
+warp8x8_rnd1:     dd 1024, 1024, 4096, 4096
+warp8x8_rnd2:     times 4 dw 4096
+                  times 4 dw 16384
+warp8x8t_rnd:     times 2 dd 16384 - (8192 << 15)
+
+%macro BIDIR_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - 2*%3)
+    %xdefine %%base %1_%2_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1_16bpc_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%prefix %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+BIDIR_JMP_TABLE avg,        ssse3,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_avg,      ssse3,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE mask,       ssse3,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_420, ssse3,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_422, ssse3,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_444, ssse3,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE blend,      ssse3,    4, 8, 16, 32
+BIDIR_JMP_TABLE blend_v,    ssse3, 2, 4, 8, 16, 32
+BIDIR_JMP_TABLE blend_h,    ssse3, 2, 4, 8, 16, 32, 64, 128
+
+%macro BASE_JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base %1_%2
+    %%table:
+    %rep %0 - 2
+        dw %%base %+ _w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%xdefine put_ssse3 mangle(private_prefix %+ _put_bilin_16bpc_ssse3.put)
+%xdefine prep_ssse3 mangle(private_prefix %+ _prep_bilin_16bpc_ssse3.prep)
+
+BASE_JMP_TABLE put,  ssse3, 2, 4, 8, 16, 32, 64, 128
+BASE_JMP_TABLE prep, ssse3,    4, 8, 16, 32, 64, 128
+
+%macro SCALED_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base mangle(private_prefix %+ _%1_16bpc_%2)
+%%table:
+    %rep %0 - 2
+        dw %%base %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+    %rotate 2
+%%dy_1024:
+    %xdefine %1_%2_dy1_table (%%dy_1024 - %3)
+    %rep %0 - 2
+        dw %%base %+ .dy1_w%3 - %%base
+        %rotate 1
+    %endrep
+    %rotate 2
+%%dy_2048:
+    %xdefine %1_%2_dy2_table (%%dy_2048 - %3)
+    %rep %0 - 2
+        dw %%base %+ .dy2_w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+SCALED_JMP_TABLE put_8tap_scaled, ssse3, 2, 4, 8, 16, 32, 64, 128
+SCALED_JMP_TABLE prep_8tap_scaled, ssse3,   4, 8, 16, 32, 64, 128
+
+cextern mc_subpel_filters
+%define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8)
+
+cextern mc_warp_filter
+cextern resize_filter
+
+SECTION .text
+
+%if UNIX64
+DECLARE_REG_TMP 7
+%else
+DECLARE_REG_TMP 5
+%endif
+
+INIT_XMM ssse3
+cglobal put_bilin_16bpc, 4, 7, 0, dst, ds, src, ss, w, h, mxy
+%define base t0-put_ssse3
+    mov                mxyd, r6m ; mx
+    LEA                  t0, put_ssse3
+    movifnidn            wd, wm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r7m ; my
+    test               mxyd, mxyd
+    jnz .v
+.put:
+    tzcnt                wd, wd
+    movzx                wd, word [base+put_ssse3_table+wq*2]
+    add                  wq, t0
+    movifnidn            hd, hm
+    jmp                  wq
+.put_w2:
+    mov                 r4d, [srcq+ssq*0]
+    mov                 r6d, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r4d
+    mov        [dstq+dsq*1], r6d
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w2
+    RET
+.put_w4:
+    movq                 m0, [srcq+ssq*0]
+    movq                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq       [dstq+dsq*0], m0
+    movq       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w4
+    RET
+.put_w8:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w8
+    RET
+.put_w16:
+    movu                 m0, [srcq+ssq*0+16*0]
+    movu                 m1, [srcq+ssq*0+16*1]
+    movu                 m2, [srcq+ssq*1+16*0]
+    movu                 m3, [srcq+ssq*1+16*1]
+    lea                srcq, [srcq+ssq*2]
+    mova  [dstq+dsq*0+16*0], m0
+    mova  [dstq+dsq*0+16*1], m1
+    mova  [dstq+dsq*1+16*0], m2
+    mova  [dstq+dsq*1+16*1], m3
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w16
+    RET
+.put_w32:
+    movu                 m0, [srcq+16*0]
+    movu                 m1, [srcq+16*1]
+    movu                 m2, [srcq+16*2]
+    movu                 m3, [srcq+16*3]
+    add                srcq, ssq
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    mova        [dstq+16*2], m2
+    mova        [dstq+16*3], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w32
+    RET
+.put_w64:
+    movu                 m0, [srcq+16*0]
+    movu                 m1, [srcq+16*1]
+    movu                 m2, [srcq+16*2]
+    movu                 m3, [srcq+16*3]
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    mova        [dstq+16*2], m2
+    mova        [dstq+16*3], m3
+    movu                 m0, [srcq+16*4]
+    movu                 m1, [srcq+16*5]
+    movu                 m2, [srcq+16*6]
+    movu                 m3, [srcq+16*7]
+    add                srcq, ssq
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m1
+    mova        [dstq+16*6], m2
+    mova        [dstq+16*7], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w64
+    RET
+.put_w128:
+    add                srcq, 16*8
+    add                dstq, 16*8
+.put_w128_loop:
+    movu                 m0, [srcq-16*8]
+    movu                 m1, [srcq-16*7]
+    movu                 m2, [srcq-16*6]
+    movu                 m3, [srcq-16*5]
+    mova        [dstq-16*8], m0
+    mova        [dstq-16*7], m1
+    mova        [dstq-16*6], m2
+    mova        [dstq-16*5], m3
+    movu                 m0, [srcq-16*4]
+    movu                 m1, [srcq-16*3]
+    movu                 m2, [srcq-16*2]
+    movu                 m3, [srcq-16*1]
+    mova        [dstq-16*4], m0
+    mova        [dstq-16*3], m1
+    mova        [dstq-16*2], m2
+    mova        [dstq-16*1], m3
+    movu                 m0, [srcq+16*0]
+    movu                 m1, [srcq+16*1]
+    movu                 m2, [srcq+16*2]
+    movu                 m3, [srcq+16*3]
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    mova        [dstq+16*2], m2
+    mova        [dstq+16*3], m3
+    movu                 m0, [srcq+16*4]
+    movu                 m1, [srcq+16*5]
+    movu                 m2, [srcq+16*6]
+    movu                 m3, [srcq+16*7]
+    add                srcq, ssq
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m1
+    mova        [dstq+16*6], m2
+    mova        [dstq+16*7], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w128_loop
+    RET
+.h:
+    movd                 m5, mxyd
+    mov                mxyd, r7m ; my
+    mova                 m4, [base+pw_16]
+    pshufb               m5, [base+pw_256]
+    psubw                m4, m5
+    test               mxyd, mxyd
+    jnz .hv
+    ; 12-bit is rounded twice so we can't use the same pmulhrsw approach as .v
+    mov                 r6d, r8m ; bitdepth_max
+    shr                 r6d, 11
+    movddup              m3, [base+put_bilin_h_rnd+r6*8]
+    movifnidn            hd, hm
+    sub                  wd, 8
+    jg .h_w16
+    je .h_w8
+    cmp                  wd, -4
+    je .h_w4
+.h_w2:
+    movq                 m1, [srcq+ssq*0]
+    movhps               m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmullw               m0, m4, m1
+    psrlq                m1, 16
+    pmullw               m1, m5
+    paddw                m0, m3
+    paddw                m0, m1
+    psrlw                m0, 4
+    movd       [dstq+dsq*0], m0
+    punpckhqdq           m0, m0
+    movd       [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2
+    RET
+.h_w4:
+    movq                 m0, [srcq+ssq*0]
+    movhps               m0, [srcq+ssq*1]
+    movq                 m1, [srcq+ssq*0+2]
+    movhps               m1, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    paddw                m0, m3
+    paddw                m0, m1
+    psrlw                m0, 4
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4
+    RET
+.h_w8:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*0+2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    paddw                m0, m3
+    paddw                m0, m1
+    movu                 m1, [srcq+ssq*1]
+    movu                 m2, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    pmullw               m1, m4
+    pmullw               m2, m5
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m0, 4
+    psrlw                m1, 4
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    lea                srcq, [srcq+wq*2]
+    lea                dstq, [dstq+wq*2]
+    neg                  wq
+.h_w16_loop0:
+    mov                  r6, wq
+.h_w16_loop:
+    movu                 m0, [srcq+r6*2+ 0]
+    movu                 m1, [srcq+r6*2+ 2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    paddw                m0, m3
+    paddw                m0, m1
+    movu                 m1, [srcq+r6*2+16]
+    movu                 m2, [srcq+r6*2+18]
+    pmullw               m1, m4
+    pmullw               m2, m5
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m0, 4
+    psrlw                m1, 4
+    mova   [dstq+r6*2+16*0], m0
+    mova   [dstq+r6*2+16*1], m1
+    add                  r6, 16
+    jl .h_w16_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w16_loop0
+    RET
+.v:
+    shl                mxyd, 11
+    movd                 m5, mxyd
+    pshufb               m5, [base+pw_256]
+    movifnidn            hd, hm
+    cmp                  wd, 4
+    jg .v_w8
+    je .v_w4
+.v_w2:
+    movd                 m0, [srcq+ssq*0]
+.v_w2_loop:
+    movd                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklqdq           m2, m0, m1
+    movd                 m0, [srcq+ssq*0]
+    punpcklqdq           m1, m0
+    psubw                m1, m2
+    pmulhrsw             m1, m5
+    paddw                m1, m2
+    movd       [dstq+dsq*0], m1
+    punpckhqdq           m1, m1
+    movd       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movq                 m0, [srcq+ssq*0]
+.v_w4_loop:
+    movq                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklqdq           m2, m0, m1
+    movq                 m0, [srcq+ssq*0]
+    punpcklqdq           m1, m0
+    psubw                m1, m2
+    pmulhrsw             m1, m5
+    paddw                m1, m2
+    movq       [dstq+dsq*0], m1
+    movhps     [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+%if ARCH_X86_64
+%if WIN64
+    push                 r7
+%endif
+    shl                  wd, 5
+    mov                  r7, srcq
+    lea                 r6d, [wq+hq-256]
+    mov                  r4, dstq
+%else
+    mov                  r6, srcq
+%endif
+.v_w8_loop0:
+    movu                 m0, [srcq+ssq*0]
+.v_w8_loop:
+    movu                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    psubw                m1, m3, m0
+    pmulhrsw             m1, m5
+    paddw                m1, m0
+    movu                 m0, [srcq+ssq*0]
+    psubw                m2, m0, m3
+    pmulhrsw             m2, m5
+    paddw                m2, m3
+    mova       [dstq+dsq*0], m1
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+%if ARCH_X86_64
+    add                  r7, 16
+    add                  r4, 16
+    movzx                hd, r6b
+    mov                srcq, r7
+    mov                dstq, r4
+    sub                 r6d, 1<<8
+%else
+    mov                dstq, dstmp
+    add                  r6, 16
+    mov                  hd, hm
+    add                dstq, 16
+    mov                srcq, r6
+    mov               dstmp, dstq
+    sub                  wd, 8
+%endif
+    jg .v_w8_loop0
+%if WIN64
+    pop                 r7
+%endif
+    RET
+.hv:
+    WIN64_SPILL_XMM       8
+    shl                mxyd, 11
+    mova                 m3, [base+pw_2]
+    movd                 m6, mxyd
+    mova                 m7, [base+pw_8192]
+    pshufb               m6, [base+pw_256]
+    test          dword r8m, 0x800
+    jnz .hv_12bpc
+    psllw                m4, 2
+    psllw                m5, 2
+    mova                 m7, [base+pw_2048]
+.hv_12bpc:
+    movifnidn            hd, hm
+    cmp                  wd, 4
+    jg .hv_w8
+    je .hv_w4
+.hv_w2:
+    movddup              m0, [srcq+ssq*0]
+    pshufhw              m1, m0, q0321
+    pmullw               m0, m4
+    pmullw               m1, m5
+    paddw                m0, m3
+    paddw                m0, m1
+    psrlw                m0, 2
+.hv_w2_loop:
+    movq                 m2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps               m2, [srcq+ssq*0]
+    pmullw               m1, m4, m2
+    psrlq                m2, 16
+    pmullw               m2, m5
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m1, 2            ; 1 _ 2 _
+    shufpd               m2, m0, m1, 0x01 ; 0 _ 1 _
+    mova                 m0, m1
+    psubw                m1, m2
+    paddw                m1, m1
+    pmulhw               m1, m6
+    paddw                m1, m2
+    pmulhrsw             m1, m7
+    movd       [dstq+dsq*0], m1
+    punpckhqdq           m1, m1
+    movd       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    movddup              m0, [srcq+ssq*0]
+    movddup              m1, [srcq+ssq*0+2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    paddw                m0, m3
+    paddw                m0, m1
+    psrlw                m0, 2
+.hv_w4_loop:
+    movq                 m1, [srcq+ssq*1]
+    movq                 m2, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    movhps               m1, [srcq+ssq*0]
+    movhps               m2, [srcq+ssq*0+2]
+    pmullw               m1, m4
+    pmullw               m2, m5
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m1, 2            ; 1 2
+    shufpd               m2, m0, m1, 0x01 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    paddw                m1, m1
+    pmulhw               m1, m6
+    paddw                m1, m2
+    pmulhrsw             m1, m7
+    movq       [dstq+dsq*0], m1
+    movhps     [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+%if ARCH_X86_64
+%if WIN64
+    push                 r7
+%endif
+    shl                  wd, 5
+    lea                 r6d, [wq+hq-256]
+    mov                  r4, srcq
+    mov                  r7, dstq
+%else
+    mov                  r6, srcq
+%endif
+.hv_w8_loop0:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*0+2]
+    pmullw               m0, m4
+    pmullw               m1, m5
+    paddw                m0, m3
+    paddw                m0, m1
+    psrlw                m0, 2
+.hv_w8_loop:
+    movu                 m1, [srcq+ssq*1]
+    movu                 m2, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    pmullw               m1, m4
+    pmullw               m2, m5
+    paddw                m1, m3
+    paddw                m1, m2
+    psrlw                m1, 2
+    psubw                m2, m1, m0
+    paddw                m2, m2
+    pmulhw               m2, m6
+    paddw                m2, m0
+    pmulhrsw             m2, m7
+    mova       [dstq+dsq*0], m2
+    movu                 m0, [srcq+ssq*0]
+    movu                 m2, [srcq+ssq*0+2]
+    pmullw               m0, m4
+    pmullw               m2, m5
+    paddw                m0, m3
+    paddw                m0, m2
+    psrlw                m0, 2
+    psubw                m2, m0, m1
+    paddw                m2, m2
+    pmulhw               m2, m6
+    paddw                m2, m1
+    pmulhrsw             m2, m7
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+%if ARCH_X86_64
+    add                  r4, 16
+    add                  r7, 16
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+    sub                 r6d, 1<<8
+%else
+    mov                dstq, dstmp
+    add                  r6, 16
+    mov                  hd, hm
+    add                dstq, 16
+    mov                srcq, r6
+    mov               dstmp, dstq
+    sub                  wd, 8
+%endif
+    jg .hv_w8_loop0
+%if WIN64
+    pop                  r7
+%endif
+    RET
+
+cglobal prep_bilin_16bpc, 4, 7, 0, tmp, src, stride, w, h, mxy, stride3
+%define base r6-prep_ssse3
+    movifnidn          mxyd, r5m ; mx
+    LEA                  r6, prep_ssse3
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r6m ; my
+    test               mxyd, mxyd
+    jnz .v
+.prep:
+    tzcnt                wd, wd
+    movzx                wd, word [base+prep_ssse3_table+wq*2]
+    mov                 r5d, r7m ; bitdepth_max
+    mova                 m5, [base+pw_8192]
+    add                  wq, r6
+    shr                 r5d, 11
+    movddup              m4, [base+prep_mul+r5*8]
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.prep_w4:
+    movq                 m0, [srcq+strideq*0]
+    movhps               m0, [srcq+strideq*1]
+    movq                 m1, [srcq+strideq*2]
+    movhps               m1, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    pmullw               m0, m4
+    pmullw               m1, m4
+    psubw                m0, m5
+    psubw                m1, m5
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    add                tmpq, 16*2
+    sub                  hd, 4
+    jg .prep_w4
+    RET
+.prep_w8:
+    movu                 m0, [srcq+strideq*0]
+    movu                 m1, [srcq+strideq*1]
+    movu                 m2, [srcq+strideq*2]
+    movu                 m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    sub                  hd, 4
+    jg .prep_w8
+    RET
+.prep_w16:
+    movu                 m0, [srcq+strideq*0+16*0]
+    movu                 m1, [srcq+strideq*0+16*1]
+    movu                 m2, [srcq+strideq*1+16*0]
+    movu                 m3, [srcq+strideq*1+16*1]
+    lea                srcq, [srcq+strideq*2]
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    sub                  hd, 2
+    jg .prep_w16
+    RET
+.prep_w32:
+    movu                 m0, [srcq+16*0]
+    movu                 m1, [srcq+16*1]
+    movu                 m2, [srcq+16*2]
+    movu                 m3, [srcq+16*3]
+    add                srcq, strideq
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    dec                  hd
+    jg .prep_w32
+    RET
+.prep_w64:
+    movu                 m0, [srcq+16*0]
+    movu                 m1, [srcq+16*1]
+    movu                 m2, [srcq+16*2]
+    movu                 m3, [srcq+16*3]
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    movu                 m0, [srcq+16*4]
+    movu                 m1, [srcq+16*5]
+    movu                 m2, [srcq+16*6]
+    movu                 m3, [srcq+16*7]
+    add                srcq, strideq
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*4], m0
+    mova        [tmpq+16*5], m1
+    mova        [tmpq+16*6], m2
+    mova        [tmpq+16*7], m3
+    add                tmpq, 16*8
+    dec                  hd
+    jg .prep_w64
+    RET
+.prep_w128:
+    movu                 m0, [srcq+16* 0]
+    movu                 m1, [srcq+16* 1]
+    movu                 m2, [srcq+16* 2]
+    movu                 m3, [srcq+16* 3]
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    movu                 m0, [srcq+16* 4]
+    movu                 m1, [srcq+16* 5]
+    movu                 m2, [srcq+16* 6]
+    movu                 m3, [srcq+16* 7]
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*4], m0
+    mova        [tmpq+16*5], m1
+    mova        [tmpq+16*6], m2
+    mova        [tmpq+16*7], m3
+    movu                 m0, [srcq+16* 8]
+    movu                 m1, [srcq+16* 9]
+    movu                 m2, [srcq+16*10]
+    movu                 m3, [srcq+16*11]
+    add                tmpq, 16*16
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq-16*8], m0
+    mova        [tmpq-16*7], m1
+    mova        [tmpq-16*6], m2
+    mova        [tmpq-16*5], m3
+    movu                 m0, [srcq+16*12]
+    movu                 m1, [srcq+16*13]
+    movu                 m2, [srcq+16*14]
+    movu                 m3, [srcq+16*15]
+    add                srcq, strideq
+    REPX     {pmullw x, m4}, m0, m1, m2, m3
+    REPX     {psubw  x, m5}, m0, m1, m2, m3
+    mova        [tmpq-16*4], m0
+    mova        [tmpq-16*3], m1
+    mova        [tmpq-16*2], m2
+    mova        [tmpq-16*1], m3
+    dec                  hd
+    jg .prep_w128
+    RET
+.h:
+    movd                 m4, mxyd
+    mov                mxyd, r6m ; my
+    mova                 m3, [base+pw_16]
+    pshufb               m4, [base+pw_256]
+    mova                 m5, [base+pw_32766]
+    psubw                m3, m4
+    test          dword r7m, 0x800
+    jnz .h_12bpc
+    psllw                m3, 2
+    psllw                m4, 2
+.h_12bpc:
+    test               mxyd, mxyd
+    jnz .hv
+    sub                  wd, 8
+    je .h_w8
+    jg .h_w16
+.h_w4:
+    movq                 m0, [srcq+strideq*0]
+    movhps               m0, [srcq+strideq*1]
+    movq                 m1, [srcq+strideq*0+2]
+    movhps               m1, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m0, m3
+    pmullw               m1, m4
+    psubw                m0, m5
+    paddw                m0, m1
+    psraw                m0, 2
+    mova             [tmpq], m0
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .h_w4
+    RET
+.h_w8:
+    movu                 m0, [srcq+strideq*0]
+    movu                 m1, [srcq+strideq*0+2]
+    pmullw               m0, m3
+    pmullw               m1, m4
+    psubw                m0, m5
+    paddw                m0, m1
+    movu                 m1, [srcq+strideq*1]
+    movu                 m2, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m1, m3
+    pmullw               m2, m4
+    psubw                m1, m5
+    paddw                m1, m2
+    psraw                m0, 2
+    psraw                m1, 2
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    add                tmpq, 16*2
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    lea                srcq, [srcq+wq*2]
+    neg                  wq
+.h_w16_loop0:
+    mov                  r6, wq
+.h_w16_loop:
+    movu                 m0, [srcq+r6*2+ 0]
+    movu                 m1, [srcq+r6*2+ 2]
+    pmullw               m0, m3
+    pmullw               m1, m4
+    psubw                m0, m5
+    paddw                m0, m1
+    movu                 m1, [srcq+r6*2+16]
+    movu                 m2, [srcq+r6*2+18]
+    pmullw               m1, m3
+    pmullw               m2, m4
+    psubw                m1, m5
+    paddw                m1, m2
+    psraw                m0, 2
+    psraw                m1, 2
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    add                tmpq, 16*2
+    add                  r6, 16
+    jl .h_w16_loop
+    add                srcq, strideq
+    dec                  hd
+    jg .h_w16_loop0
+    RET
+.v:
+    movd                 m4, mxyd
+    mova                 m3, [base+pw_16]
+    pshufb               m4, [base+pw_256]
+    mova                 m5, [base+pw_32766]
+    psubw                m3, m4
+    test          dword r7m, 0x800
+    jnz .v_12bpc
+    psllw                m3, 2
+    psllw                m4, 2
+.v_12bpc:
+    cmp                  wd, 8
+    je .v_w8
+    jg .v_w16
+.v_w4:
+    movq                 m0, [srcq+strideq*0]
+.v_w4_loop:
+    movq                 m2, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    punpcklqdq           m1, m0, m2 ; 0 1
+    movq                 m0, [srcq+strideq*0]
+    punpcklqdq           m2, m0     ; 1 2
+    pmullw               m1, m3
+    pmullw               m2, m4
+    psubw                m1, m5
+    paddw                m1, m2
+    psraw                m1, 2
+    mova             [tmpq], m1
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movu                 m0, [srcq+strideq*0]
+.v_w8_loop:
+    movu                 m2, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m0, m3
+    pmullw               m1, m4, m2
+    psubw                m0, m5
+    paddw                m1, m0
+    movu                 m0, [srcq+strideq*0]
+    psraw                m1, 2
+    pmullw               m2, m3
+    mova        [tmpq+16*0], m1
+    pmullw               m1, m4, m0
+    psubw                m2, m5
+    paddw                m1, m2
+    psraw                m1, 2
+    mova        [tmpq+16*1], m1
+    add                tmpq, 16*2
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w16:
+%if WIN64
+    push                 r7
+%endif
+    mov                  r5, srcq
+%if ARCH_X86_64
+    lea                 r6d, [wq*4-32]
+    mov                  wd, wd
+    lea                 r6d, [hq+r6*8]
+    mov                  r7, tmpq
+%else
+    mov                 r6d, wd
+%endif
+.v_w16_loop0:
+    movu                 m0, [srcq+strideq*0]
+.v_w16_loop:
+    movu                 m2, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m0, m3
+    pmullw               m1, m4, m2
+    psubw                m0, m5
+    paddw                m1, m0
+    movu                 m0, [srcq+strideq*0]
+    psraw                m1, 2
+    pmullw               m2, m3
+    mova        [tmpq+wq*0], m1
+    pmullw               m1, m4, m0
+    psubw                m2, m5
+    paddw                m1, m2
+    psraw                m1, 2
+    mova        [tmpq+wq*2], m1
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jg .v_w16_loop
+%if ARCH_X86_64
+    add                  r5, 16
+    add                  r7, 16
+    movzx                hd, r6b
+    mov                srcq, r5
+    mov                tmpq, r7
+    sub                 r6d, 1<<8
+%else
+    mov                tmpq, tmpmp
+    add                  r5, 16
+    mov                  hd, hm
+    add                tmpq, 16
+    mov                srcq, r5
+    mov               tmpmp, tmpq
+    sub                 r6d, 8
+%endif
+    jg .v_w16_loop0
+%if WIN64
+    pop                  r7
+%endif
+    RET
+.hv:
+    WIN64_SPILL_XMM       7
+    shl                mxyd, 11
+    movd                 m6, mxyd
+    pshufb               m6, [base+pw_256]
+    cmp                  wd, 8
+    je .hv_w8
+    jg .hv_w16
+.hv_w4:
+    movddup              m0, [srcq+strideq*0]
+    movddup              m1, [srcq+strideq*0+2]
+    pmullw               m0, m3
+    pmullw               m1, m4
+    psubw                m0, m5
+    paddw                m0, m1
+    psraw                m0, 2
+.hv_w4_loop:
+    movq                 m1, [srcq+strideq*1]
+    movq                 m2, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    movhps               m1, [srcq+strideq*0]
+    movhps               m2, [srcq+strideq*0+2]
+    pmullw               m1, m3
+    pmullw               m2, m4
+    psubw                m1, m5
+    paddw                m1, m2
+    psraw                m1, 2            ; 1 2
+    shufpd               m2, m0, m1, 0x01 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhrsw             m1, m6
+    paddw                m1, m2
+    mova             [tmpq], m1
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    movu                 m0, [srcq+strideq*0]
+    movu                 m1, [srcq+strideq*0+2]
+    pmullw               m0, m3
+    pmullw               m1, m4
+    psubw                m0, m5
+    paddw                m0, m1
+    psraw                m0, 2
+.hv_w8_loop:
+    movu                 m1, [srcq+strideq*1]
+    movu                 m2, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m1, m3
+    pmullw               m2, m4
+    psubw                m1, m5
+    paddw                m1, m2
+    psraw                m1, 2
+    psubw                m2, m1, m0
+    pmulhrsw             m2, m6
+    paddw                m2, m0
+    mova        [tmpq+16*0], m2
+    movu                 m0, [srcq+strideq*0]
+    movu                 m2, [srcq+strideq*0+2]
+    pmullw               m0, m3
+    pmullw               m2, m4
+    psubw                m0, m5
+    paddw                m0, m2
+    psraw                m0, 2
+    psubw                m2, m0, m1
+    pmulhrsw             m2, m6
+    paddw                m2, m1
+    mova        [tmpq+16*1], m2
+    add                tmpq, 16*2
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+%if WIN64
+    push                 r7
+%endif
+    mov                  r5, srcq
+%if ARCH_X86_64
+    lea                 r6d, [wq*4-32]
+    mov                  wd, wd
+    lea                 r6d, [hq+r6*8]
+    mov                  r7, tmpq
+%else
+    mov                 r6d, wd
+%endif
+.hv_w16_loop0:
+    movu                 m0, [srcq+strideq*0]
+    movu                 m1, [srcq+strideq*0+2]
+    pmullw               m0, m3
+    pmullw               m1, m4
+    psubw                m0, m5
+    paddw                m0, m1
+    psraw                m0, 2
+.hv_w16_loop:
+    movu                 m1, [srcq+strideq*1]
+    movu                 m2, [srcq+strideq*1+2]
+    lea                srcq, [srcq+strideq*2]
+    pmullw               m1, m3
+    pmullw               m2, m4
+    psubw                m1, m5
+    paddw                m1, m2
+    psraw                m1, 2
+    psubw                m2, m1, m0
+    pmulhrsw             m2, m6
+    paddw                m2, m0
+    mova        [tmpq+wq*0], m2
+    movu                 m0, [srcq+strideq*0]
+    movu                 m2, [srcq+strideq*0+2]
+    pmullw               m0, m3
+    pmullw               m2, m4
+    psubw                m0, m5
+    paddw                m0, m2
+    psraw                m0, 2
+    psubw                m2, m0, m1
+    pmulhrsw             m2, m6
+    paddw                m2, m1
+    mova        [tmpq+wq*2], m2
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jg .hv_w16_loop
+%if ARCH_X86_64
+    add                  r5, 16
+    add                  r7, 16
+    movzx                hd, r6b
+    mov                srcq, r5
+    mov                tmpq, r7
+    sub                 r6d, 1<<8
+%else
+    mov                tmpq, tmpmp
+    add                  r5, 16
+    mov                  hd, hm
+    add                tmpq, 16
+    mov                srcq, r5
+    mov               tmpmp, tmpq
+    sub                 r6d, 8
+%endif
+    jg .hv_w16_loop0
+%if WIN64
+    pop                  r7
+%endif
+    RET
+
+; int8_t subpel_filters[5][15][8]
+%assign FILTER_REGULAR (0*15 << 16) | 3*15
+%assign FILTER_SMOOTH  (1*15 << 16) | 4*15
+%assign FILTER_SHARP   (2*15 << 16) | 3*15
+
+%macro FN 4-5 ; prefix, type, type_h, type_v, jmp_to
+cglobal %1_%2_16bpc
+    mov                 t0d, FILTER_%3
+%ifidn %3, %4
+    mov                 t1d, t0d
+%else
+    mov                 t1d, FILTER_%4
+%endif
+%if %0 == 5 ; skip the jump in the last filter
+    jmp mangle(private_prefix %+ _%5 %+ SUFFIX)
+%endif
+%endmacro
+
+%if ARCH_X86_32
+DECLARE_REG_TMP 1, 2, 6
+%elif WIN64
+DECLARE_REG_TMP 4, 5, 8
+%else
+DECLARE_REG_TMP 7, 8, 8
+%endif
+
+%define PUT_8TAP_FN FN put_8tap,
+PUT_8TAP_FN smooth,         SMOOTH,  SMOOTH,  put_6tap_16bpc
+PUT_8TAP_FN smooth_regular, SMOOTH,  REGULAR, put_6tap_16bpc
+PUT_8TAP_FN regular_smooth, REGULAR, SMOOTH,  put_6tap_16bpc
+PUT_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal put_6tap_16bpc, 0, 9, 0, dst, ds, src, ss, w, h, mx, my
+    %define            base  t2-put_ssse3
+%if ARCH_X86_32
+    %define             mxb  r0b
+    %define             mxd  r0
+    %define             mxq  r0
+    %define             myb  r1b
+    %define             myd  r1
+    %define             myq  r1
+%endif
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    LEA                  t2, put_ssse3
+    movifnidn            wd, wm
+    movifnidn          srcq, srcmp
+    movifnidn           ssq, ssmp
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.put:
+    tzcnt                wd, wd
+    movzx                wd, word [base+put_ssse3_table+wq*2]
+    movifnidn          dstq, dstmp
+    movifnidn           dsq, dsmp
+    add                  wq, t2
+%if WIN64
+    pop                  r8
+    pop                  r7
+%endif
+    jmp                  wq
+.h_w2:
+    mova                 m2, [base+spel_h_shuf2]
+    pshufd               m3, m3, q2121
+.h_w2_loop:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m0, m2
+    pshufb               m1, m2
+    pmaddwd              m0, m3
+    pmaddwd              m1, m3
+    phaddd               m0, m1
+    paddd                m0, m4
+    psrad                m0, 6
+    packssdw             m0, m0
+    pxor                 m1, m1
+    pminsw               m0, m5
+    pmaxsw               m0, m1
+    movd       [dstq+dsq*0], m0
+    pshuflw              m0, m0, q3232
+    movd       [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2_loop
+    RET
+.h_w4:
+    movzx               mxd, mxb
+    lea                srcq, [srcq-2]
+    movq                 m3, [base+subpel_filters+mxq*8]
+    movifnidn          dstq, dstmp
+    punpcklbw            m3, m3
+    psraw                m3, 8 ; sign-extend
+    jl .h_w2
+    WIN64_SPILL_XMM       9
+    mova                 m7, [base+spel_h_shufA]
+%if ARCH_X86_32
+    %define              m8  [base+spel_h_shufB]
+%else
+    mova                 m8, [base+spel_h_shufB]
+%endif
+    pshufd               m2, m3, q1111
+    pshufd               m3, m3, q2222
+.h_w4_loop:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m6, m0, m7 ; 0 1 1 2 2 3 3 4
+    pmaddwd              m6, m2
+    pshufb               m0, m8     ; 2 3 3 4 4 5 5 6
+    pmaddwd              m0, m3
+    paddd                m0, m6
+    pshufb               m6, m1, m7
+    pmaddwd              m6, m2
+    pshufb               m1, m8
+    pmaddwd              m1, m3
+    paddd                m0, m4
+    paddd                m6, m4
+    paddd                m1, m6
+    psrad                m0, 6
+    psrad                m1, 6
+    packssdw             m0, m1
+    pxor                 m1, m1
+    pminsw               m0, m5
+    pmaxsw               m0, m1
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h:
+    RESET_STACK_STATE
+    test                myd, 0xf00
+    jnz .hv
+    mov                 myd, r8m
+    movd                 m5, r8m
+    shr                 myd, 11
+    movddup              m4, [base+put_8tap_h_rnd+myq*8]
+    movifnidn           dsq, dsmp
+    pshufb               m5, [base+pw_256]
+    sub                  wd, 4
+    jle .h_w4
+    WIN64_SPILL_XMM      11
+    shr                 mxd, 16
+    movq                 m2, [base+subpel_filters+1+mxq*8]
+    movifnidn          dstq, dstmp
+    mova                 m6, [base+spel_h_shufA]
+    mova                 m7, [base+spel_h_shufB]
+    lea                srcq, [srcq+wq*2]
+    punpcklbw            m2, m2
+    lea                dstq, [dstq+wq*2]
+    psraw                m2, 8
+    neg                  wq
+%if ARCH_X86_32
+    ALLOC_STACK       -16*3
+    %define              m8  [rsp+16*0]
+    %define              m9  [rsp+16*1]
+    %define             m10  [rsp+16*2]
+    pshufd               m0, m2, q0000
+    pshufd               m1, m2, q1111
+    pshufd               m2, m2, q2222
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+%else
+    pshufd               m8, m2, q0000
+    pshufd               m9, m2, q1111
+    pshufd              m10, m2, q2222
+%endif
+.h_w8_loop0:
+    mov                  r6, wq
+.h_w8_loop:
+    movu                 m3, [srcq+r6*2-4]
+    movu                 m2, [srcq+r6*2+8]
+    pshufb               m0, m3, m6   ; 01 12 23 34
+    pmaddwd              m0, m8       ; abcd0
+    pshufb               m3, m7       ; 23 34 45 56
+    pmaddwd              m1, m9, m3   ; abcd1
+    paddd                m0, m1
+    pshufb               m1, m2, m6   ; 67 78 89 9a
+    shufpd               m3, m1, 0x01 ; 45 56 67 78
+    pmaddwd              m1, m9       ; efgh1
+    pshufb               m2, m7       ; 89 9a ab bc
+    pmaddwd              m2, m10      ; efgh2
+    paddd                m1, m2
+    pmaddwd              m2, m10, m3  ; abcd2
+    pmaddwd              m3, m8       ; efgh0
+    paddd                m0, m4
+    paddd                m1, m4
+    paddd                m0, m2
+    paddd                m1, m3
+    psrad                m0, 6
+    psrad                m1, 6
+    packssdw             m0, m1
+    pxor                 m1, m1
+    pminsw               m0, m5
+    pmaxsw               m0, m1
+    mova        [dstq+r6*2], m0
+    add                  r6, 8
+    jl .h_w8_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w8_loop0
+    RET
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movq                 m2, [base+subpel_filters+1+myq*8]
+    WIN64_SPILL_XMM      11, 16
+    movd                 m5, r8m
+    movifnidn          dstq, dstmp
+    movifnidn           dsq, dsmp
+    punpcklbw            m2, m2
+    pshufb               m5, [base+pw_256]
+    psraw                m2, 8 ; sign-extend
+%if ARCH_X86_32
+    ALLOC_STACK       -16*4
+    pshufd               m0, m2, q0000
+    mov                  r6, ssq
+    pshufd               m1, m2, q1111
+    neg                  r6
+    pshufd               m2, m2, q2222
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+    cmp                  wd, 2
+    jne .v_w4
+%else
+    mov                  r6, ssq
+    pshufd               m8, m2, q0000
+    neg                  r6
+    cmp                  wd, 4
+    jg .v_w8
+    pshufd               m9, m2, q1111
+    pshufd              m10, m2, q2222
+    je .v_w4
+%endif
+.v_w2:
+    movd                 m1, [srcq+r6 *2]
+    movd                 m3, [srcq+r6 *1]
+    movd                 m2, [srcq+ssq*0]
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m1, m3      ; 0 1
+    punpckldq            m3, m2      ; 1 2
+    punpckldq            m2, m4      ; 2 3
+    punpckldq            m4, m0      ; 3 4
+    punpcklwd            m1, m3      ; 01 12
+    punpcklwd            m2, m4      ; 23 34
+    pxor                 m6, m6
+.v_w2_loop:
+    movd                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m4, m8, m1  ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m9      ; a1 b1
+    paddd                m4, m2
+    punpckldq            m2, m0, m3  ; 4 5
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m3, m0      ; 5 6
+    punpcklwd            m2, m3      ; 67 78
+    pmaddwd              m3, m10, m2 ; a2 b2
+    paddd                m4, m3
+    psrad                m4, 5
+    packssdw             m4, m4
+    pmaxsw               m4, m6
+    pavgw                m4, m6
+    pminsw               m4, m5
+    movd       [dstq+dsq*0], m4
+    pshuflw              m4, m4, q3232
+    movd       [dstq+dsq*1], m4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+%if ARCH_X86_32
+    shl                  wd, 14
+    lea                srcq, [srcq+r6*2]
+    lea                  wd, [wq+hq-(1<<16)]
+%if STACK_ALIGNMENT < 16
+    %define           dstmp  [esp+16*3]
+%endif
+.v_w4_loop0:
+    mov               dstmp, dstq
+    movq                 m1, [srcq+ssq*0]
+    movq                 m2, [srcq+ssq*1]
+    lea                  r6, [srcq+ssq*2]
+    movq                 m3, [r6  +ssq*0]
+    movq                 m4, [r6  +ssq*1]
+    lea                  r6, [r6  +ssq*2]
+%else
+    movq                 m1, [srcq+r6 *2]
+    movq                 m2, [srcq+r6 *1]
+    lea                  r6, [srcq+ssq*2]
+    movq                 m3, [srcq+ssq*0]
+    movq                 m4, [srcq+ssq*1]
+%endif
+    movq                 m0, [r6  +ssq*0]
+    punpcklwd            m1, m2      ; 01
+    punpcklwd            m2, m3      ; 12
+    punpcklwd            m3, m4      ; 23
+    punpcklwd            m4, m0      ; 34
+.v_w4_loop:
+    pmaddwd              m6, m8, m1  ; a0
+    pmaddwd              m7, m8, m2  ; b0
+    mova                 m1, m3
+    pmaddwd              m3, m9      ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m9      ; b1
+    paddd                m6, m3
+    movq                 m3, [r6+ssq*0]
+    paddd                m7, m4
+    movq                 m4, [r6+ssq*1]
+    lea                  r6, [r6+ssq*2]
+    movq                 m0, [r6+ssq*0]
+    punpcklwd            m3, m4      ; 45
+    punpcklwd            m4, m0      ; 56
+    pmaddwd              m0, m10, m3 ; a2
+    paddd                m6, m0
+    pmaddwd              m0, m10, m4 ; b2
+    paddd                m7, m0
+    psrad                m6, 5
+    psrad                m7, 5
+    packssdw             m6, m7
+    pxor                 m7, m7
+    pmaxsw               m6, m7
+    pavgw                m6, m7
+    pminsw               m6, m5
+    movq       [dstq+dsq*0], m6
+    movhps     [dstq+dsq*1], m6
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+%if ARCH_X86_32
+    mov                dstq, dstmp
+    add                srcq, 8
+    movzx                hd, ww
+    add                dstq, 8
+    sub                  wd, 1<<16
+    jg .v_w4_loop0
+    RET
+%else
+    RET
+.v_w8:
+    mova                r6m, m8
+    shl                  wd, 5
+    pshufd               m6, m2, q1111
+    lea                  wd, [wq+hq-(1<<8)]
+    pshufd               m7, m2, q2222
+    WIN64_PUSH_XMM       16
+.v_w8_loop0:
+    movu                 m9, [srcq+ r6*2]
+    movu                m11, [srcq+ r6*1]
+    lea                  r7, [srcq+ssq*2]
+    movu                m13, [srcq+ssq*0]
+    movu                m15, [srcq+ssq*1]
+    mov                  r8, dstq
+    movu                 m4, [r7  +ssq*0]
+    punpcklwd            m8, m9, m11  ; 01
+    punpckhwd            m9, m11
+    punpcklwd           m10, m11, m13 ; 12
+    punpckhwd           m11, m13
+    punpcklwd           m12, m13, m15 ; 23
+    punpckhwd           m13, m15
+    punpcklwd           m14, m15, m4  ; 34
+    punpckhwd           m15, m4
+.v_w8_loop:
+    mova                 m3, r6m
+    pmaddwd              m0, m8, m3   ; a0
+    pmaddwd              m2, m9, m3   ; a0'
+    pmaddwd              m1, m10, m3  ; b0
+    pmaddwd              m3, m11      ; b0'
+    mova                 m8, m12
+    pmaddwd             m12, m6       ; a1
+    mova                 m9, m13
+    pmaddwd             m13, m6       ; a1'
+    mova                m10, m14
+    pmaddwd             m14, m6       ; b1
+    mova                m11, m15
+    pmaddwd             m15, m6       ; b1'
+    paddd                m0, m12
+    paddd                m2, m13
+    movu                m13, [r7+ssq*0]
+    paddd                m1, m14
+    paddd                m3, m15
+    movu                m15, [r7+ssq*1]
+    lea                  r7, [r7+ssq*2]
+    movu                 m4, [r7+ssq*0]
+    punpcklwd           m12, m13, m15 ; 45
+    punpckhwd           m13, m15
+    punpcklwd           m14, m15, m4  ; 56
+    punpckhwd           m15, m4
+    pmaddwd              m4, m7, m12  ; a2
+    paddd                m0, m4
+    pmaddwd              m4, m7, m13  ; a2'
+    paddd                m2, m4
+    pmaddwd              m4, m7, m14  ; b2
+    paddd                m1, m4
+    pmaddwd              m4, m7, m15  ; b2'
+    paddd                m3, m4
+    REPX       {psrad x, 5}, m0, m2, m1, m3
+    packssdw             m0, m2
+    packssdw             m1, m3
+    pxor                 m2, m2
+    pmaxsw               m0, m2
+    pmaxsw               m1, m2
+    pavgw                m0, m2
+    pavgw                m1, m2
+    pminsw               m0, m5
+    pminsw               m1, m5
+    mova         [r8+dsq*0], m0
+    mova         [r8+dsq*1], m1
+    lea                  r8, [r8+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .v_w8_loop0
+    RET
+%endif
+.hv:
+    cmp                  wd, 4
+    jg .hv_w8
+    WIN64_SPILL_XMM      12, 16
+%if ARCH_X86_32
+    movd                 m3, r8m
+    pshufb               m3, [base+pw_256]
+%else
+    movd                m11, r8m
+    pshufb              m11, [base+pw_256]
+%endif
+    movzx               mxd, mxb
+    movq                 m0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movq                 m2, [base+subpel_filters+1+myq*8]
+    movddup              m7, [base+pd_8704]
+    sub                srcq, 2
+    pshuflw              m0, m0, q2121
+    pxor                 m6, m6
+    punpcklbw            m6, m0
+    punpcklbw            m2, m2
+    psraw                m2, 8 ; sign-extend
+    test          dword r8m, 0x800
+    jz .hv_w2_10bpc
+    movddup              m7, [base+pd_2560]
+    psraw                m6, 2
+    psllw                m2, 2
+.hv_w2_10bpc:
+%if ARCH_X86_32
+%assign regs_used 2
+    ALLOC_STACK       -16*7
+%assign regs_used 7
+    mov                dstq, r0mp
+    mov                 dsq, r1mp
+    %define             m11  [esp+16*4]
+    pshufd               m0, m2, q0000
+    pshufd               m1, m2, q1111
+    pshufd               m2, m2, q2222
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+    mova                m11, m3
+    neg                 ssq
+    movu                 m3, [srcq+ssq*2]
+    movu                 m4, [srcq+ssq*1]
+    neg                 ssq
+%else
+    pshufd               m8, m2, q0000
+    mov                  r6, ssq
+    pshufd               m9, m2, q1111
+    neg                  r6
+    pshufd              m10, m2, q2222
+    movu                 m3, [srcq+r6 *2]
+    movu                 m4, [srcq+r6 *1]
+%endif
+    movu                 m1, [srcq+ssq*0]
+    movu                 m0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movu                 m2, [srcq+ssq*0]
+    cmp                  wd, 4
+    je .hv_w4
+    mova                 m5, [base+spel_h_shuf2]
+    REPX    {pshufb  x, m5}, m3, m4, m0, m1, m2
+    REPX    {pmaddwd x, m6}, m3, m0, m4, m1, m2
+    phaddd               m3, m0        ; 0 3
+    phaddd               m4, m1        ; 1 2
+    phaddd               m0, m2        ; 3 4
+    REPX    {paddd   x, m7}, m3, m4, m0
+    REPX    {psrad   x, 10}, m3, m4, m0
+    packssdw             m3, m4        ; 0 3 1 2
+    packssdw             m4, m0        ; 1 2 3 4
+    pshufd               m2, m3, q1320 ; 0 1 2 3
+    punpcklwd            m1, m2, m4    ; 01 12
+    punpckhwd            m2, m4        ; 23 34
+.hv_w2_loop:
+    movu                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movu                 m4, [srcq+ssq*0]
+    pshufb               m3, m5
+    pshufb               m4, m5
+    pmaddwd              m3, m6
+    pmaddwd              m4, m6
+    phaddd               m3, m4
+    pmaddwd              m4, m8, m1    ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m9        ; a1 b1
+    paddd                m4, m2
+    paddd                m3, m7
+    psrad                m3, 10        ; 5 6
+    packssdw             m0, m3
+    pshufd               m2, m0, q2103
+    punpckhwd            m2, m0        ; 45 56
+    mova                 m0, m3
+    pmaddwd              m3, m10, m2   ; a2 b2
+    paddd                m4, m3
+    psrad                m4, 10
+    packssdw             m4, m4
+    pxor                 m3, m3
+    pminsw               m4, m11
+    pmaxsw               m4, m3
+    movd       [dstq+dsq*0], m4
+    pshuflw              m4, m4, q1032
+    movd       [dstq+dsq*1], m4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+%if ARCH_X86_32
+    %define             m12  [esp+16*5]
+    %define             m13  [esp+16*6]
+    %define             m14  [base+spel_h_shufA]
+    %define             m15  [base+spel_h_shufB]
+    pshufd               m5, m6, q0000
+    pshufd               m6, m6, q1111
+    mova                m12, m5
+    mova                m13, m6
+%else
+    WIN64_PUSH_XMM       16
+    mova                m14, [base+spel_h_shufA]
+    mova                m15, [base+spel_h_shufB]
+    pshufd              m12, m6, q0000
+    pshufd              m13, m6, q1111
+%endif
+%macro HV_H_W4_6TAP 3-4 m15 ; dst, src, tmp, shufB
+    pshufb               %3, %2, m14
+    pmaddwd              %3, m12
+    pshufb               %2, %4
+    pmaddwd              %2, m13
+    paddd                %3, m7
+    paddd                %1, %2, %3
+%endmacro
+    HV_H_W4_6TAP         m3, m3, m5
+    HV_H_W4_6TAP         m4, m4, m5
+    HV_H_W4_6TAP         m5, m1, m5
+    HV_H_W4_6TAP         m0, m0, m1
+    HV_H_W4_6TAP         m2, m2, m1
+    REPX      {psrad x, 10}, m3, m5, m4, m0, m2
+    packssdw             m3, m5      ; 0 2
+    packssdw             m4, m0      ; 1 3
+    packssdw             m5, m2      ; 2 4
+    punpcklwd            m1, m3, m4  ; 01
+    punpckhwd            m3, m4      ; 23
+    punpcklwd            m2, m4, m5  ; 12
+    punpckhwd            m4, m5      ; 34
+.hv_w4_loop:
+    movu                 m0, [srcq+ssq*1]
+    pmaddwd              m5, m8, m1  ; a0
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m6, m8, m2  ; b0
+    mova                 m1, m3
+    pmaddwd              m3, m9      ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m9      ; b1
+    paddd                m5, m3
+    movu                 m3, [srcq+ssq*0]
+    paddd                m6, m4
+    HV_H_W4_6TAP         m0, m0, m4
+    HV_H_W4_6TAP         m3, m3, m4
+    psrad                m4, m2, 16
+    psrad                m0, 10
+    psrad                m3, 10
+    packssdw             m4, m0      ; 4 5
+    packssdw             m0, m3      ; 5 6
+    punpcklwd            m3, m4, m0  ; 45
+    punpckhwd            m4, m0      ; 56
+    pmaddwd              m0, m10, m3 ; a2
+    paddd                m5, m0
+    pmaddwd              m0, m10, m4 ; b2
+    paddd                m6, m0
+    psrad                m5, 10
+    psrad                m6, 10
+    packssdw             m5, m6
+    pxor                 m6, m6
+    pminsw               m5, m11
+    pmaxsw               m5, m6
+    movq       [dstq+dsq*0], m5
+    movhps     [dstq+dsq*1], m5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    RESET_STACK_STATE
+    shr                 mxd, 16
+    movq                 m2, [base+subpel_filters+1+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movq                 m1, [base+subpel_filters+1+myq*8]
+    movd                 m3, r8m
+    movddup              m4, [base+pd_8704]
+    pshufb               m3, [base+pw_256]
+    pxor                 m0, m0
+    punpcklbw            m0, m2
+    punpcklbw            m1, m1
+    sub                srcq, 4
+    psraw                m1, 8 ; sign-extend
+    test          dword r8m, 0x800
+    jz .hv_w8_10bpc
+    movddup              m4, [base+pd_2560]
+    psraw                m0, 2
+    psllw                m1, 2
+.hv_w8_10bpc:
+%if ARCH_X86_32
+%assign regs_used 2
+    ALLOC_STACK       -16*9
+%assign regs_used 7
+    mov                dstq, r0mp
+    mov                 dsq, r1mp
+    mova         [rsp+16*7], m4
+%else
+    ALLOC_STACK        16*7, 16
+%endif
+    mova         [rsp+16*6], m3
+    pshufd               m2, m0, q0000
+    mova         [rsp+16*0], m2
+    pshufd               m2, m0, q1111
+    mova         [rsp+16*1], m2
+    pshufd               m0, m0, q2222
+    mova         [rsp+16*2], m0
+    pshufd               m2, m1, q0000
+    mova         [rsp+16*3], m2
+    pshufd               m2, m1, q1111
+    mova         [rsp+16*4], m2
+    pshufd               m1, m1, q2222
+    mova         [rsp+16*5], m1
+    mov                  r6, ssq
+    neg                  r6
+%if ARCH_X86_32
+    shl                  wd, 14
+    lea                 r4d, [wq+hq-(1<<16)]
+%if STACK_ALIGNMENT < 16
+    %define           srcmp  [esp+16*8+4*0]
+    %define           dstmp  [esp+16*8+4*1]
+%endif
+%macro HV_H_6TAP 3-6 [rsp+16*0], [rsp+16*1], [rsp+16*2] ; dst, src[1-2], mul[1-3]
+    punpcklwd            %1, %2, %3   ; 01 12 23 34
+    punpckhwd            %2, %3       ; 45 56 67 78
+    pmaddwd              %3, %4, %1   ; a0
+    shufpd               %1, %2, 0x01 ; 23 34 45 56
+    pmaddwd              %2, %6       ; a2
+    pmaddwd              %1, %5       ; a1
+    paddd                %2, %3
+    paddd                %1, %2
+%endmacro
+.hv_w8_loop0:
+    mov               srcmp, srcq
+    mov               dstmp, dstq
+    movu                 m5, [srcq+r6*2+0]
+    movu                 m6, [srcq+r6*2+2]
+    mova                 m7, [rsp+16*0]
+    mova                 m1, [rsp+16*1]
+    mova                 m0, [rsp+16*2]
+    HV_H_6TAP            m2, m5, m6, m7, m1, m0
+    movu                 m5, [srcq+r6*1+0]
+    movu                 m6, [srcq+r6*1+2]
+    HV_H_6TAP            m3, m5, m6, m7, m1, m0
+    movu                 m5, [srcq+ssq*0+0]
+    movu                 m6, [srcq+ssq*0+2]
+    HV_H_6TAP            m4, m5, m6, m7, m1, m0
+    movu                 m5, [srcq+ssq*1+0]
+    movu                 m6, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    HV_H_6TAP            m0, m5, m6, m7, m1
+    movu                 m5, [srcq+ssq*0+0]
+    movu                 m6, [srcq+ssq*0+2]
+    HV_H_6TAP            m1, m5, m6, m7
+    mova                 m5, [rsp+16*7]
+    REPX      {paddd x, m5}, m2, m3, m4, m0, m1
+    REPX      {psrad x, 10}, m2, m4, m3, m0, m1
+    packssdw             m2, m4     ; 0 2
+    packssdw             m3, m0     ; 1 3
+    packssdw             m4, m1     ; 2 4
+    punpcklwd            m0, m2, m3 ; 01
+    punpckhwd            m2, m3     ; 23
+    punpcklwd            m1, m3, m4 ; 12
+    punpckhwd            m3, m4     ; 34
+.hv_w8_loop:
+    mova                 m5, [rsp+16*3]
+    mova                 m6, [rsp+16*4]
+    pmaddwd              m4, m0, m5 ; a0
+    pmaddwd              m5, m1     ; b0
+    mova                 m0, m2
+    pmaddwd              m2, m6     ; a1
+    mova                 m1, m3
+    pmaddwd              m3, m6     ; b1
+    paddd                m4, m2
+    movu                 m2, [srcq+ssq*1+0]
+    paddd                m5, m3
+    movu                 m3, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    HV_H_6TAP            m6, m2, m3
+    movu                 m2, [srcq+ssq*0+0]
+    movu                 m3, [srcq+ssq*0+2]
+    HV_H_6TAP            m7, m2, m3
+    mova                 m2, [rsp+16*7]
+    psrad                m3, m1, 16
+    paddd                m6, m2
+    paddd                m7, m2
+    psrad                m6, 10
+    psrad                m7, 10
+    packssdw             m3, m6     ; 4 5
+    packssdw             m6, m7     ; 5 6
+    mova                 m7, [rsp+16*5]
+    punpcklwd            m2, m3, m6 ; 45
+    punpckhwd            m3, m6     ; 56
+    pmaddwd              m6, m2, m7 ; a2
+    pmaddwd              m7, m3     ; b2
+    paddd                m4, m6
+    paddd                m5, m7
+    psrad                m4, 10
+    psrad                m5, 10
+    packssdw             m4, m5
+    pxor                 m5, m5
+    pminsw               m4, [rsp+16*6]
+    pmaxsw               m4, m5
+    movq       [dstq+dsq*0], m4
+    movhps     [dstq+dsq*1], m4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    mov                srcq, srcmp
+    mov                dstq, dstmp
+    movzx                hd, r4w
+    add                srcq, 8
+    add                dstq, 8
+    sub                 r4d, 1<<16
+%else
+    shl                  wd, 5
+    lea                 r8d, [wq+hq-256]
+%macro HV_H_6TAP 5-9 [spel_h_shufA], [rsp+16*0], [rsp+16*1], [rsp+16*2] ; dst, src[1-3], shift, shuf, mul[1-3]
+%ifid %6
+    REPX     {pshufb x, %6}, %2, %3, %4
+%else
+    mova                 %1, %6
+    pshufb               %2, %1       ; 01 12 23 34
+    pshufb               %3, %1       ; 45 56 67 78
+    pshufb               %4, %1       ; 89 9a ab bc
+%endif
+    pmaddwd              %1, %7, %2
+    shufpd               %2, %3, 0x01 ; 23 34 45 56
+    pmaddwd              %2, %8
+    paddd                %1, %2
+    pmaddwd              %2, %9, %3
+    paddd                %1, %2
+    pmaddwd              %2, %7, %3
+    shufpd               %3, %4, 0x01 ; 67 78 89 9a
+    pmaddwd              %4, %9
+    pmaddwd              %3, %8
+    paddd                %1, m4
+    paddd                %2, m4
+    paddd                %3, %4
+    paddd                %2, %3
+    psrad                %1, %5
+    psrad                %2, %5
+    packssdw             %1, %2
+%endmacro
+.hv_w8_loop0:
+    mova                 m5, [spel_h_shufA]
+    movu                 m0, [srcq+r6*2+ 0]
+    mova                 m6, [rsp+16*0]
+    movu                 m1, [srcq+r6*2+ 8]
+    mova                 m7, [rsp+16*1]
+    movu                 m2, [srcq+r6*2+16]
+    mova                 m8, [rsp+16*2]
+    HV_H_6TAP            m9, m0, m1, m2, 10, m5, m6, m7, m8
+    movu                 m0, [srcq+r6*1+ 0]
+    movu                 m1, [srcq+r6*1+ 8]
+    movu                 m2, [srcq+r6*1+16]
+    lea                  r4, [srcq+ssq*2]
+    HV_H_6TAP           m11, m0, m1, m2, 10, m5, m6, m7, m8
+    movu                 m0, [srcq+ssq*0+ 0]
+    movu                 m1, [srcq+ssq*0+ 8]
+    movu                 m2, [srcq+ssq*0+16]
+    mov                  r7, dstq
+    HV_H_6TAP           m13, m0, m1, m2, 10, m5, m6, m7, m8
+    movu                 m0, [srcq+ssq*1+ 0]
+    movu                 m1, [srcq+ssq*1+ 8]
+    movu                 m2, [srcq+ssq*1+16]
+    HV_H_6TAP           m15, m0, m1, m2, 10, m5, m6, m7, m8
+    movu                 m0, [r4+ssq*0+ 0]
+    movu                 m1, [r4+ssq*0+ 8]
+    movu                 m2, [r4+ssq*0+16]
+    HV_H_6TAP            m5, m0, m1, m2, 10, m5, m6, m7, m8
+    punpcklwd            m8, m9, m11  ; 01
+    punpckhwd            m9, m11
+    punpcklwd           m10, m11, m13 ; 12
+    punpckhwd           m11, m13
+    punpcklwd           m12, m13, m15 ; 23
+    punpckhwd           m13, m15
+    punpcklwd           m14, m15, m5  ; 34
+    punpckhwd           m15, m5
+.hv_w8_loop:
+    mova                 m3, [rsp+16*3]
+    mova                 m7, [rsp+16*4]
+    pmaddwd              m0, m8, m3   ; a0
+    mova                 m8, m12
+    pmaddwd              m2, m9, m3   ; a0'
+    mova                 m9, m13
+    pmaddwd              m1, m10, m3  ; b0
+    mova                m10, m14
+    pmaddwd              m3, m11      ; b0'
+    mova                m11, m15
+    REPX    {pmaddwd x, m7}, m12, m13, m14, m15
+    movu                 m6, [r4+ssq*1+ 0]
+    paddd                m0, m12
+    movu                 m7, [r4+ssq*1+ 8]
+    paddd                m2, m13
+    movu                m12, [r4+ssq*1+16]
+    paddd                m1, m14
+    lea                  r4, [r4+ssq*2]
+    paddd                m3, m15
+    HV_H_6TAP           m15, m6, m7, m12, 10
+    movu                 m6, [r4+ssq*0+ 0]
+    movu                 m7, [r4+ssq*0+ 8]
+    movu                m14, [r4+ssq*0+16]
+    punpcklwd           m12, m5, m15 ; 45
+    punpckhwd           m13, m5, m15
+    HV_H_6TAP            m5, m6, m7, m14, 10
+    mova                 m7, [rsp+16*5]
+    punpcklwd           m14, m15, m5  ; 56
+    punpckhwd           m15, m5
+    pmaddwd              m6, m12, m7  ; a2
+    paddd                m0, m6
+    pmaddwd              m6, m13, m7  ; a2'
+    paddd                m2, m6
+    pmaddwd              m6, m14, m7  ; b2
+    pmaddwd              m7, m15      ; b2'
+    paddd                m1, m6
+    mova                 m6, [rsp+16*6]
+    paddd                m3, m7
+    REPX      {psrad x, 10}, m0, m2, m1, m3
+    packssdw             m0, m2
+    packssdw             m1, m3
+    pxor                 m2, m2
+    pminsw               m0, m6
+    pminsw               m1, m6
+    pmaxsw               m0, m2
+    pmaxsw               m1, m2
+    mova         [r7+dsq*0], m0
+    mova         [r7+dsq*1], m1
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, r8b
+    sub                 r8d, 1<<8
+%endif
+    jg .hv_w8_loop0
+    RET
+
+PUT_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_16bpc
+PUT_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  put_8tap_16bpc
+PUT_8TAP_FN regular_sharp,  REGULAR, SHARP,   put_8tap_16bpc
+PUT_8TAP_FN sharp_regular,  SHARP,   REGULAR, put_8tap_16bpc
+PUT_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal put_8tap_16bpc, 0, 9, 0, dst, ds, src, ss, w, h, mx, my
+%if ARCH_X86_32
+    %define             mxb  r0b
+    %define             mxd  r0
+    %define             mxq  r0
+    %define             myb  r1b
+    %define             myd  r1
+    %define             myq  r1
+    %define              m8  [esp+16*0]
+    %define              m9  [esp+16*1]
+    %define             m10  [esp+16*2]
+    %define             m11  [esp+16*3]
+    %define             m12  [esp+16*4]
+    %define             m13  [esp+16*5]
+    %define             m14  [esp+16*6]
+    %define             m15  [esp+16*7]
+%endif
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    LEA                  t2, put_ssse3
+    movifnidn            wd, wm
+    movifnidn          srcq, srcmp
+    movifnidn           ssq, ssmp
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _put_6tap_16bpc_ssse3).put
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movq                 m3, [base+subpel_filters+myq*8]
+    WIN64_SPILL_XMM      15
+    movd                 m7, r8m
+    movifnidn          dstq, dstmp
+    movifnidn           dsq, dsmp
+    punpcklbw            m3, m3
+    pshufb               m7, [base+pw_256]
+    psraw                m3, 8 ; sign-extend
+%if ARCH_X86_32
+    ALLOC_STACK       -16*7
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+    mova                m11, m3
+%else
+    pshufd               m8, m3, q0000
+    pshufd               m9, m3, q1111
+    pshufd              m10, m3, q2222
+    pshufd              m11, m3, q3333
+%endif
+    lea                  r6, [ssq*3]
+    sub                srcq, r6
+    cmp                  wd, 2
+    jne .v_w4
+.v_w2:
+    movd                 m1, [srcq+ssq*0]
+    movd                 m4, [srcq+ssq*1]
+    movd                 m2, [srcq+ssq*2]
+    add                srcq, r6
+    movd                 m5, [srcq+ssq*0]
+    movd                 m3, [srcq+ssq*1]
+    movd                 m6, [srcq+ssq*2]
+    add                srcq, r6
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m1, m4      ; 0 1
+    punpckldq            m4, m2      ; 1 2
+    punpckldq            m2, m5      ; 2 3
+    punpckldq            m5, m3      ; 3 4
+    punpckldq            m3, m6      ; 4 5
+    punpckldq            m6, m0      ; 5 6
+    punpcklwd            m1, m4      ; 01 12
+    punpcklwd            m2, m5      ; 23 34
+    punpcklwd            m3, m6      ; 45 56
+    pxor                 m6, m6
+.v_w2_loop:
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m5, m8, m1  ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m9      ; a1 b1
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, m10     ; a2 b2
+    paddd                m5, m3
+    punpckldq            m3, m0, m4  ; 6 7
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m4, m0      ; 7 8
+    punpcklwd            m3, m4      ; 67 78
+    pmaddwd              m4, m11, m3 ; a3 b3
+    paddd                m5, m4
+    psrad                m5, 5
+    packssdw             m5, m5
+    pmaxsw               m5, m6
+    pavgw                m5, m6
+    pminsw               m5, m7
+    movd       [dstq+dsq*0], m5
+    pshuflw              m5, m5, q3232
+    movd       [dstq+dsq*1], m5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+%if ARCH_X86_32
+    shl                  wd, 14
+%if STACK_ALIGNMENT < 16
+    mov          [esp+4*29], srcq
+    mov          [esp+4*30], dstq
+%else
+    mov               srcmp, srcq
+%endif
+    lea                  wd, [wq+hq-(1<<16)]
+%else
+    shl                  wd, 6
+    mov                  r7, srcq
+    mov                  r8, dstq
+    lea                  wd, [wq+hq-(1<<8)]
+%endif
+.v_w4_loop0:
+    movq                 m1, [srcq+ssq*0]
+    movq                 m2, [srcq+ssq*1]
+    movq                 m3, [srcq+ssq*2]
+    add                srcq, r6
+    movq                 m4, [srcq+ssq*0]
+    movq                 m5, [srcq+ssq*1]
+    movq                 m6, [srcq+ssq*2]
+    add                srcq, r6
+    movq                 m0, [srcq+ssq*0]
+    punpcklwd            m1, m2      ; 01
+    punpcklwd            m2, m3      ; 12
+    punpcklwd            m3, m4      ; 23
+    punpcklwd            m4, m5      ; 34
+    punpcklwd            m5, m6      ; 45
+    punpcklwd            m6, m0      ; 56
+%if ARCH_X86_32
+    jmp .v_w4_loop_start
+.v_w4_loop:
+    mova                 m1, m12
+    mova                 m2, m13
+    mova                 m3, m14
+.v_w4_loop_start:
+    pmaddwd              m1, m8      ; a0
+    pmaddwd              m2, m8      ; b0
+    mova                m12, m3
+    mova                m13, m4
+    pmaddwd              m3, m9      ; a1
+    pmaddwd              m4, m9      ; b1
+    paddd                m1, m3
+    paddd                m2, m4
+    mova                m14, m5
+    mova                 m4, m6
+    pmaddwd              m5, m10     ; a2
+    pmaddwd              m6, m10     ; b2
+    paddd                m1, m5
+    paddd                m2, m6
+    movq                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklwd            m5, m0, m6  ; 67
+    movq                 m0, [srcq+ssq*0]
+    pmaddwd              m3, m11, m5 ; a3
+    punpcklwd            m6, m0      ; 78
+    paddd                m1, m3
+    pmaddwd              m3, m11, m6 ; b3
+    paddd                m2, m3
+    psrad                m1, 5
+    psrad                m2, 5
+    packssdw             m1, m2
+    pxor                 m2, m2
+    pmaxsw               m1, m2
+    pavgw                m1, m2
+    pminsw               m1, m7
+    movq       [dstq+dsq*0], m1
+    movhps     [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+%if STACK_ALIGNMENT < 16
+    mov                srcq, [esp+4*29]
+    mov                dstq, [esp+4*30]
+    movzx                hd, ww
+    add                srcq, 8
+    add                dstq, 8
+    mov          [esp+4*29], srcq
+    mov          [esp+4*30], dstq
+%else
+    mov                srcq, srcmp
+    mov                dstq, dstmp
+    movzx                hd, ww
+    add                srcq, 8
+    add                dstq, 8
+    mov               srcmp, srcq
+    mov               dstmp, dstq
+%endif
+    sub                  wd, 1<<16
+%else
+.v_w4_loop:
+    pmaddwd             m12, m8, m1  ; a0
+    pmaddwd             m13, m8, m2  ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddwd              m3, m9      ; a1
+    pmaddwd              m4, m9      ; b1
+    paddd               m12, m3
+    paddd               m13, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddwd              m5, m10     ; a2
+    pmaddwd              m6, m10     ; b2
+    paddd               m12, m5
+    paddd               m13, m6
+    movq                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklwd            m5, m0, m6  ; 67
+    movq                 m0, [srcq+ssq*0]
+    pmaddwd             m14, m11, m5 ; a3
+    punpcklwd            m6, m0      ; 78
+    paddd               m12, m14
+    pmaddwd             m14, m11, m6 ; b3
+    paddd               m13, m14
+    psrad               m12, 5
+    psrad               m13, 5
+    packssdw            m12, m13
+    pxor                m13, m13
+    pmaxsw              m12, m13
+    pavgw               m12, m13
+    pminsw              m12, m7
+    movq       [dstq+dsq*0], m12
+    movhps     [dstq+dsq*1], m12
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    add                  r7, 8
+    add                  r8, 8
+    movzx                hd, wb
+    mov                srcq, r7
+    mov                dstq, r8
+    sub                  wd, 1<<8
+%endif
+    jg .v_w4_loop0
+    RET
+.h:
+    RESET_STACK_STATE
+    test                myd, 0xf00
+    jnz .hv
+    mov                 myd, r8m
+    movd                 m5, r8m
+    shr                 myd, 11
+    movddup              m4, [base+put_8tap_h_rnd+myq*8]
+    movifnidn           dsq, dsmp
+    pshufb               m5, [base+pw_256]
+    cmp                  wd, 4
+    jle mangle(private_prefix %+ _put_6tap_16bpc_ssse3).h_w4
+    WIN64_SPILL_XMM      12
+    shr                 mxd, 16
+    movq                 m3, [base+subpel_filters+mxq*8]
+    movifnidn          dstq, dstmp
+    mova                 m6, [base+spel_h_shufA]
+    mova                 m7, [base+spel_h_shufB]
+%if UNIX64
+    mov                  wd, wd
+%endif
+    lea                srcq, [srcq+wq*2]
+    punpcklbw            m3, m3
+    lea                dstq, [dstq+wq*2]
+    psraw                m3, 8
+    neg                  wq
+%if ARCH_X86_32
+    ALLOC_STACK       -16*4
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+    mova                m11, m3
+%else
+    pshufd               m8, m3, q0000
+    pshufd               m9, m3, q1111
+    pshufd              m10, m3, q2222
+    pshufd              m11, m3, q3333
+%endif
+.h_w8_loop0:
+    mov                  r6, wq
+.h_w8_loop:
+    movu                 m0, [srcq+r6*2- 6]
+    movu                 m1, [srcq+r6*2+ 2]
+    pshufb               m2, m0, m6   ; 0 1 1 2 2 3 3 4
+    pshufb               m0, m7       ; 2 3 3 4 4 5 5 6
+    pmaddwd              m2, m8       ; abcd0
+    pmaddwd              m0, m9       ; abcd1
+    pshufb               m3, m1, m6   ; 4 5 5 6 6 7 7 8
+    pshufb               m1, m7       ; 6 7 7 8 8 9 9 a
+    paddd                m2, m4
+    paddd                m0, m2
+    pmaddwd              m2, m10, m3  ; abcd2
+    pmaddwd              m3, m8       ; efgh0
+    paddd                m0, m2
+    pmaddwd              m2, m11, m1  ; abcd3
+    pmaddwd              m1, m9       ; efgh1
+    paddd                m0, m2
+    movu                 m2, [srcq+r6*2+10]
+    paddd                m3, m4
+    paddd                m1, m3
+    pshufb               m3, m2, m6   ; 8 9 9 a a b b c
+    pshufb               m2, m7       ; a b b c c d d e
+    pmaddwd              m3, m10      ; efgh2
+    pmaddwd              m2, m11      ; efgh3
+    paddd                m1, m3
+    paddd                m1, m2
+    psrad                m0, 6
+    psrad                m1, 6
+    packssdw             m0, m1
+    pxor                 m1, m1
+    pminsw               m0, m5
+    pmaxsw               m0, m1
+    mova        [dstq+r6*2], m0
+    add                  r6, 8
+    jl .h_w8_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w8_loop0
+    RET
+.hv:
+    RESET_STACK_STATE
+%if ARCH_X86_32
+    movd                 m4, r8m
+    pshufb               m4, [base+pw_256]
+%else
+%if WIN64
+    ALLOC_STACK        16*6, 16
+%endif
+    movd                m15, r8m
+    pshufb              m15, [base+pw_256]
+%endif
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    je .hv_w4
+    movq                 m0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movq                 m3, [base+subpel_filters+myq*8]
+    movddup              m6, [base+pd_8704]
+    pshuflw              m0, m0, q2121
+    pxor                 m7, m7
+    punpcklbw            m7, m0
+    punpcklbw            m3, m3
+    psraw                m3, 8 ; sign-extend
+    test          dword r8m, 0x800
+    jz .hv_w2_10bpc
+    movddup              m6, [base+pd_2560]
+    psraw                m7, 2
+    psllw                m3, 2
+.hv_w2_10bpc:
+%if ARCH_X86_32
+    mov                dstq, dstmp
+    mov                 dsq, dsmp
+    mova                 m5, [base+spel_h_shuf2]
+    ALLOC_STACK       -16*8
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    mova                 m9, m5
+    mova                m11, m0
+    mova                m12, m1
+    mova                m13, m2
+    mova                m14, m3
+    mova                m15, m4
+%else
+    mova                 m9, [base+spel_h_shuf2]
+    pshufd              m11, m3, q0000
+    pshufd              m12, m3, q1111
+    pshufd              m13, m3, q2222
+    pshufd              m14, m3, q3333
+%endif
+    lea                  r6, [ssq*3]
+    sub                srcq, 2
+    sub                srcq, r6
+    movu                 m2, [srcq+ssq*0]
+    movu                 m3, [srcq+ssq*1]
+    movu                 m1, [srcq+ssq*2]
+    add                srcq, r6
+    movu                 m4, [srcq+ssq*0]
+%if ARCH_X86_32
+    REPX    {pshufb  x, m5}, m2, m3, m1, m4
+%else
+    REPX    {pshufb  x, m9}, m2, m3, m1, m4
+%endif
+    REPX    {pmaddwd x, m7}, m2, m3, m1, m4
+    phaddd               m2, m3        ; 0 1
+    phaddd               m1, m4        ; 2 3
+    movu                 m3, [srcq+ssq*1]
+    movu                 m4, [srcq+ssq*2]
+    add                srcq, r6
+    movu                 m0, [srcq+ssq*0]
+%if ARCH_X86_32
+    REPX    {pshufb  x, m5}, m3, m4, m0
+%else
+    REPX    {pshufb  x, m9}, m3, m4, m0
+%endif
+    REPX    {pmaddwd x, m7}, m3, m4, m0
+    phaddd               m3, m4        ; 4 5
+    phaddd               m0, m0        ; 6 6
+    REPX    {paddd   x, m6}, m2, m1, m3, m0
+    REPX    {psrad   x, 10}, m2, m1, m3, m0
+    packssdw             m2, m1        ; 0 1 2 3
+    packssdw             m3, m0        ; 4 5 6 _
+    palignr              m4, m3, m2, 4 ; 1 2 3 4
+    pshufd               m5, m3, q0321 ; 5 6 _ _
+    punpcklwd            m1, m2, m4    ; 01 12
+    punpckhwd            m2, m4        ; 23 34
+    punpcklwd            m3, m5        ; 45 56
+.hv_w2_loop:
+    movu                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movu                 m5, [srcq+ssq*0]
+    pshufb               m4, m9
+    pshufb               m5, m9
+    pmaddwd              m4, m7
+    pmaddwd              m5, m7
+    phaddd               m4, m5
+    pmaddwd              m5, m11, m1   ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m12       ; a1 b1
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, m13       ; a2 b2
+    paddd                m5, m3
+    paddd                m4, m6
+    psrad                m4, 10        ; 7 8
+    packssdw             m0, m4
+    pshufd               m3, m0, q2103
+    punpckhwd            m3, m0        ; 67 78
+    mova                 m0, m4
+    pmaddwd              m4, m14, m3   ; a3 b3
+    paddd                m5, m4
+    psrad                m5, 10
+    packssdw             m5, m5
+    pxor                 m4, m4
+    pminsw               m5, m15
+    pmaxsw               m5, m4
+    movd       [dstq+dsq*0], m5
+    pshuflw              m5, m5, q3232
+    movd       [dstq+dsq*1], m5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+.hv_w4:
+    movq                 m2, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movq                 m3, [base+subpel_filters+myq*8]
+%if ARCH_X86_32
+    RESET_STACK_STATE
+    mov                dstq, dstmp
+    mov                 dsq, dsmp
+    mova                 m0, [base+spel_h_shufA]
+    mova                 m1, [base+spel_h_shufB]
+    mova                 m6, [base+pd_512]
+    ALLOC_STACK      -16*15
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m14, m6
+%else
+    mova                 m8, [base+spel_h_shufA]
+    mova                 m9, [base+spel_h_shufB]
+%endif
+    pxor                 m0, m0
+    punpcklbw            m0, m2
+    punpcklbw            m3, m3
+    psraw                m3, 8
+    test          dword r8m, 0x800
+    jz .hv_w4_10bpc
+    psraw                m0, 2
+    psllw                m3, 2
+.hv_w4_10bpc:
+    lea                  r6, [ssq*3]
+    sub                srcq, 6
+    sub                srcq, r6
+%if ARCH_X86_32
+    %define tmp esp+16*8
+    shl                  wd, 14
+%if STACK_ALIGNMENT < 16
+    mov          [esp+4*61], srcq
+    mov          [esp+4*62], dstq
+%else
+    mov               srcmp, srcq
+%endif
+    mova         [tmp+16*5], m4
+    lea                  wd, [wq+hq-(1<<16)]
+    pshufd               m1, m0, q0000
+    pshufd               m2, m0, q1111
+    pshufd               m5, m0, q2222
+    pshufd               m0, m0, q3333
+    mova                m10, m1
+    mova                m11, m2
+    mova                m12, m5
+    mova                m13, m0
+%else
+%if WIN64
+    %define tmp rsp
+%else
+    %define tmp rsp-104 ; red zone
+%endif
+    shl                  wd, 6
+    mov                  r7, srcq
+    mov                  r8, dstq
+    lea                  wd, [wq+hq-(1<<8)]
+    pshufd              m10, m0, q0000
+    pshufd              m11, m0, q1111
+    pshufd              m12, m0, q2222
+    pshufd              m13, m0, q3333
+    mova         [tmp+16*5], m15
+%endif
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    mova         [tmp+16*1], m0
+    mova         [tmp+16*2], m1
+    mova         [tmp+16*3], m2
+    mova         [tmp+16*4], m3
+%macro PUT_8TAP_HV_H 4-5 m14 ; dst/src+0, src+8, tmp, shift, [pd_512]
+    pshufb              m%3, m%1, m8 ; 0 1 1 2 2 3 3 4
+    pshufb              m%1, m9      ; 2 3 3 4 4 5 5 6
+    pmaddwd             m%3, m10
+    pmaddwd             m%1, m11
+    paddd               m%3, %5
+    paddd               m%1, m%3
+    pshufb              m%3, m%2, m8 ; 4 5 5 6 6 7 7 8
+    pshufb              m%2, m9      ; 6 7 7 8 8 9 9 a
+    pmaddwd             m%3, m12
+    pmaddwd             m%2, m13
+    paddd               m%1, m%3
+    paddd               m%1, m%2
+    psrad               m%1, %4
+%endmacro
+.hv_w4_loop0:
+%if ARCH_X86_64
+    mova                m14, [pd_512]
+%endif
+    movu                 m4, [srcq+ssq*0+0]
+    movu                 m1, [srcq+ssq*0+8]
+    movu                 m5, [srcq+ssq*1+0]
+    movu                 m2, [srcq+ssq*1+8]
+    movu                 m6, [srcq+ssq*2+0]
+    movu                 m3, [srcq+ssq*2+8]
+    add                srcq, r6
+    PUT_8TAP_HV_H         4, 1, 0, 10
+    PUT_8TAP_HV_H         5, 2, 0, 10
+    PUT_8TAP_HV_H         6, 3, 0, 10
+    movu                 m7, [srcq+ssq*0+0]
+    movu                 m2, [srcq+ssq*0+8]
+    movu                 m1, [srcq+ssq*1+0]
+    movu                 m3, [srcq+ssq*1+8]
+    PUT_8TAP_HV_H         7, 2, 0, 10
+    PUT_8TAP_HV_H         1, 3, 0, 10
+    movu                 m2, [srcq+ssq*2+0]
+    movu                 m3, [srcq+ssq*2+8]
+    add                srcq, r6
+    PUT_8TAP_HV_H         2, 3, 0, 10
+    packssdw             m4, m7      ; 0 3
+    packssdw             m5, m1      ; 1 4
+    movu                 m0, [srcq+ssq*0+0]
+    movu                 m1, [srcq+ssq*0+8]
+    PUT_8TAP_HV_H         0, 1, 3, 10
+    packssdw             m6, m2      ; 2 5
+    packssdw             m7, m0      ; 3 6
+    punpcklwd            m1, m4, m5  ; 01
+    punpckhwd            m4, m5      ; 34
+    punpcklwd            m2, m5, m6  ; 12
+    punpckhwd            m5, m6      ; 45
+    punpcklwd            m3, m6, m7  ; 23
+    punpckhwd            m6, m7      ; 56
+%if ARCH_X86_32
+    jmp .hv_w4_loop_start
+.hv_w4_loop:
+    mova                 m1, [tmp+16*6]
+    mova                 m2, m15
+.hv_w4_loop_start:
+    mova                 m7, [tmp+16*1]
+    pmaddwd              m1, m7      ; a0
+    pmaddwd              m2, m7      ; b0
+    mova                 m7, [tmp+16*2]
+    mova         [tmp+16*6], m3
+    pmaddwd              m3, m7      ; a1
+    mova                m15, m4
+    pmaddwd              m4, m7      ; b1
+    mova                 m7, [tmp+16*3]
+    paddd                m1, m3
+    paddd                m2, m4
+    mova                 m3, m5
+    pmaddwd              m5, m7      ; a2
+    mova                 m4, m6
+    pmaddwd              m6, m7      ; b2
+    paddd                m1, m5
+    paddd                m2, m6
+    movu                 m7, [srcq+ssq*1+0]
+    movu                 m5, [srcq+ssq*1+8]
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_HV_H         7, 5, 6, 10
+    packssdw             m0, m7      ; 6 7
+    mova         [tmp+16*0], m0
+    movu                 m0, [srcq+ssq*0+0]
+    movu                 m5, [srcq+ssq*0+8]
+    PUT_8TAP_HV_H         0, 5, 6, 10
+    mova                 m6, [tmp+16*0]
+    packssdw             m7, m0      ; 7 8
+    punpcklwd            m5, m6, m7  ; 67
+    punpckhwd            m6, m7      ; 78
+    pmaddwd              m7, m5, [tmp+16*4]
+    paddd                m1, m7      ; a3
+    pmaddwd              m7, m6, [tmp+16*4]
+    paddd                m2, m7      ; b3
+    psrad                m1, 9
+    psrad                m2, 9
+    packssdw             m1, m2
+    pxor                 m7, m7
+    pmaxsw               m1, m7
+    pavgw                m7, m1
+    pminsw               m7, [tmp+16*5]
+    movq       [dstq+dsq*0], m7
+    movhps     [dstq+dsq*1], m7
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+%if STACK_ALIGNMENT < 16
+    mov                srcq, [esp+4*61]
+    mov                dstq, [esp+4*62]
+    add                srcq, 8
+    add                dstq, 8
+    mov          [esp+4*61], srcq
+    mov          [esp+4*62], dstq
+%else
+    mov                srcq, srcmp
+    mov                dstq, dstmp
+    add                srcq, 8
+    add                dstq, 8
+    mov               srcmp, srcq
+    mov               dstmp, dstq
+%endif
+    movzx                hd, ww
+    sub                  wd, 1<<16
+%else
+.hv_w4_loop:
+    mova                m15, [tmp+16*1]
+    pmaddwd             m14, m15, m1 ; a0
+    pmaddwd             m15, m2      ; b0
+    mova                 m7, [tmp+16*2]
+    mova                 m1, m3
+    pmaddwd              m3, m7      ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m7      ; b1
+    mova                 m7, [tmp+16*3]
+    paddd               m14, m3
+    paddd               m15, m4
+    mova                 m3, m5
+    pmaddwd              m5, m7      ; a2
+    mova                 m4, m6
+    pmaddwd              m6, m7      ; b2
+    paddd               m14, m5
+    paddd               m15, m6
+    movu                 m7, [srcq+ssq*1+0]
+    movu                 m5, [srcq+ssq*1+8]
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_HV_H         7, 5, 6, 10, [pd_512]
+    packssdw             m0, m7      ; 6 7
+    mova         [tmp+16*0], m0
+    movu                 m0, [srcq+ssq*0+0]
+    movu                 m5, [srcq+ssq*0+8]
+    PUT_8TAP_HV_H         0, 5, 6, 10, [pd_512]
+    mova                 m6, [tmp+16*0]
+    packssdw             m7, m0      ; 7 8
+    punpcklwd            m5, m6, m7  ; 67
+    punpckhwd            m6, m7      ; 78
+    pmaddwd              m7, m5, [tmp+16*4]
+    paddd               m14, m7      ; a3
+    pmaddwd              m7, m6, [tmp+16*4]
+    paddd               m15, m7      ; b3
+    psrad               m14, 9
+    psrad               m15, 9
+    packssdw            m14, m15
+    pxor                 m7, m7
+    pmaxsw              m14, m7
+    pavgw                m7, m14
+    pminsw               m7, [tmp+16*5]
+    movq       [dstq+dsq*0], m7
+    movhps     [dstq+dsq*1], m7
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    add                  r7, 8
+    add                  r8, 8
+    movzx                hd, wb
+    mov                srcq, r7
+    mov                dstq, r8
+    sub                  wd, 1<<8
+%endif
+    jg .hv_w4_loop0
+    RET
+%undef tmp
+
+%if ARCH_X86_32
+DECLARE_REG_TMP 2, 1, 6, 4
+%elif WIN64
+DECLARE_REG_TMP 6, 4, 7, 4
+%else
+DECLARE_REG_TMP 6, 7, 7, 8
+%endif
+
+%define PREP_8TAP_FN FN prep_8tap,
+PREP_8TAP_FN smooth,         SMOOTH,  SMOOTH,  prep_6tap_16bpc
+PREP_8TAP_FN smooth_regular, SMOOTH,  REGULAR, prep_6tap_16bpc
+PREP_8TAP_FN regular_smooth, REGULAR, SMOOTH,  prep_6tap_16bpc
+PREP_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal prep_6tap_16bpc, 0, 8, 0, tmp, src, ss, w, h, mx, my
+    %define            base  t2-prep_ssse3
+%if ARCH_X86_32
+    %define             mxb  r0b
+    %define             mxd  r0
+    %define             mxq  r0
+    %define             myb  r2b
+    %define             myd  r2
+    %define             myq  r2
+%endif
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    LEA                  t2, prep_ssse3
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    movifnidn          srcq, srcmp
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.prep:
+    tzcnt                wd, wd
+    mov                 myd, r7m ; bitdepth_max
+    movzx                wd, word [base+prep_ssse3_table+wq*2]
+    mova                 m5, [base+pw_8192]
+    shr                 myd, 11
+    add                  wq, t2
+    movddup              m4, [base+prep_mul+myq*8]
+    movifnidn           ssq, ssmp
+    movifnidn          tmpq, tmpmp
+    lea                  r6, [ssq*3]
+%if WIN64
+    pop                  r7
+%endif
+    jmp                  wq
+.h:
+    RESET_STACK_STATE
+    test                myd, 0xf00
+    jnz .hv
+    movifnidn           ssq, r2mp
+    movddup              m5, [base+prep_8tap_1d_rnd]
+    cmp                  wd, 4
+    je mangle(private_prefix %+ _prep_8tap_16bpc_ssse3).h_w4
+    WIN64_SPILL_XMM      10
+    shr                 mxd, 16
+    movq                 m2, [base+subpel_filters+1+mxq*8]
+    movifnidn          tmpq, r0mp
+    mova                 m4, [base+spel_h_shufA]
+    add                  wd, wd
+    mova                 m6, [base+spel_h_shufB]
+    add                srcq, wq
+    punpcklbw            m2, m2
+    add                tmpq, wq
+    psraw                m2, 8
+    neg                  wq
+    test          dword r7m, 0x800
+    jnz .h_w8_12bpc
+    psllw                m2, 2
+.h_w8_12bpc:
+    pshufd               m7, m2, q0000
+%if ARCH_X86_32
+    ALLOC_STACK       -16*2
+    %define              m8  [rsp+16*0]
+    %define              m9  [rsp+16*1]
+    pshufd               m0, m2, q1111
+    pshufd               m1, m2, q2222
+    mova                 m8, m0
+    mova                 m9, m1
+%else
+    pshufd               m8, m2, q1111
+    pshufd               m9, m2, q2222
+%endif
+.h_w8_loop0:
+    mov                  r6, wq
+.h_w8_loop:
+    movu                 m3, [srcq+r6-4]
+    movu                 m2, [srcq+r6+8]
+    pshufb               m0, m3, m4  ; 01 12 23 34
+    pmaddwd              m0, m7      ; abcd0
+    pshufb               m3, m6      ; 23 34 45 56
+    pmaddwd              m1, m8, m3  ; abcd1
+    paddd                m0, m1
+    pshufb               m1, m2, m4  ; 67 78 89 9a
+    shufpd               m3, m1, 0x01; 45 56 67 78
+    pmaddwd              m1, m8      ; efgh1
+    pshufb               m2, m6      ; 89 9a ab bc
+    pmaddwd              m2, m9      ; efgh2
+    paddd                m1, m2
+    pmaddwd              m2, m9 , m3 ; abcd2
+    pmaddwd              m3, m7      ; efgh0
+    paddd                m0, m5
+    paddd                m1, m5
+    paddd                m0, m2
+    paddd                m1, m3
+    psrad                m0, 4
+    psrad                m1, 4
+    packssdw             m0, m1
+    mova          [tmpq+r6], m0
+    add                  r6, 16
+    jl .h_w8_loop
+    add                srcq, ssq
+    sub                tmpq, wq
+    dec                  hd
+    jg .h_w8_loop0
+    RET
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movddup              m5, [base+prep_8tap_1d_rnd]
+    movq                 m2, [base+subpel_filters+1+myq*8]
+    WIN64_SPILL_XMM      11, 16
+    movifnidn           ssq, r2mp
+    movifnidn          tmpq, r0mp
+    punpcklbw            m2, m2
+    sub                srcq, ssq
+    psraw                m2, 8 ; sign-extend
+    test          dword r7m, 0x800
+    jnz .v_12bpc
+    psllw                m2, 2
+.v_12bpc:
+    sub                srcq, ssq
+%if ARCH_X86_32
+    ALLOC_STACK       -16*4
+    pshufd               m0, m2, q0000
+    mov                 r6d, wd
+    pshufd               m1, m2, q1111
+    shl                 r6d, 14
+    pshufd               m2, m2, q2222
+    lea                 r6d, [r6+hq-(1<<16)]
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+%if STACK_ALIGNMENT < 16
+    %define           srcmp  [esp+16*3+4*0]
+    %define           tmpmp  [esp+16*3+4*1]
+%endif
+.v_w4_loop0:
+    mov               srcmp, srcq
+    mov               tmpmp, tmpq
+%else
+    pshufd               m8, m2, q0000
+    and                  wd, -8
+    jnz .v_w8
+    pshufd               m9, m2, q1111
+    pshufd              m10, m2, q2222
+%endif
+    movq                 m1, [srcq+ssq*0]
+    movq                 m2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m3, [srcq+ssq*0]
+    movq                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m0, [srcq+ssq*0]
+    punpcklwd            m1, m2      ; 01
+    punpcklwd            m2, m3      ; 12
+    punpcklwd            m3, m4      ; 23
+    punpcklwd            m4, m0      ; 34
+.v_w4_loop:
+    pmaddwd              m6, m8, m1  ; a0
+    pmaddwd              m7, m8, m2  ; b0
+    mova                 m1, m3
+    pmaddwd              m3, m9      ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m9      ; b1
+    paddd                m6, m3
+    movq                 m3, [srcq+ssq*0]
+    paddd                m7, m4
+    movq                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m0, [srcq+ssq*0]
+    punpcklwd            m3, m4      ; 45
+    punpcklwd            m4, m0      ; 56
+    pmaddwd              m0, m10, m3 ; a2
+    paddd                m6, m5
+    paddd                m6, m0
+    pmaddwd              m0, m10, m4 ; b2
+    paddd                m7, m5
+    paddd                m7, m0
+    psrad                m6, 4
+    psrad                m7, 4
+    packssdw             m6, m7
+%if ARCH_X86_32
+    movq        [tmpq+wq*0], m6
+    movhps      [tmpq+wq*2], m6
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jg .v_w4_loop
+    mov                srcq, srcmp
+    mov                tmpq, tmpmp
+    movzx                hd, r6w
+    add                srcq, 8
+    add                tmpq, 8
+    sub                 r6d, 1<<16
+    jg .v_w4_loop0
+    RET
+%else
+    mova             [tmpq], m6
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    mova                r6m, m8
+    lea                 r6d, [wq*4-(1<<5)]
+    pshufd               m6, m2, q1111
+    lea                 r6d, [hq+r6*8]
+    pshufd               m7, m2, q2222
+    WIN64_PUSH_XMM       16
+.v_w8_loop0:
+    movu                 m9, [srcq+ssq*0]
+    lea                  r5, [srcq+ssq*2]
+    movu                m11, [srcq+ssq*1]
+    mov                  r7, tmpq
+    movu                m13, [r5+ssq*0]
+    movu                m15, [r5+ssq*1]
+    lea                  r5, [r5+ssq*2]
+    movu                 m4, [r5+ssq*0]
+    punpcklwd            m8, m9, m11  ; 01
+    punpckhwd            m9, m11
+    punpcklwd           m10, m11, m13 ; 12
+    punpckhwd           m11, m13
+    punpcklwd           m12, m13, m15 ; 23
+    punpckhwd           m13, m15
+    punpcklwd           m14, m15, m4  ; 34
+    punpckhwd           m15, m4
+.v_w8_loop:
+    mova                 m3, r6m
+    pmaddwd              m0, m8, m3   ; a0
+    pmaddwd              m2, m9, m3   ; a0'
+    pmaddwd              m1, m10, m3  ; b0
+    pmaddwd              m3, m11      ; b0'
+    mova                 m8, m12
+    pmaddwd             m12, m6       ; a1
+    mova                 m9, m13
+    pmaddwd             m13, m6       ; a1'
+    mova                m10, m14
+    pmaddwd             m14, m6       ; b1
+    mova                m11, m15
+    pmaddwd             m15, m6       ; b1'
+    paddd                m0, m12
+    paddd                m2, m13
+    movu                m13, [r5+ssq*0]
+    paddd                m1, m14
+    paddd                m3, m15
+    movu                m15, [r5+ssq*1]
+    lea                  r5, [r5+ssq*2]
+    movu                 m4, [r5+ssq*0]
+    REPX      {paddd x, m5}, m0, m2, m1, m3
+    punpcklwd           m12, m13, m15 ; 45
+    punpckhwd           m13, m15
+    punpcklwd           m14, m15, m4  ; 56
+    punpckhwd           m15, m4
+    pmaddwd              m4, m7, m12  ; a2
+    paddd                m0, m4
+    pmaddwd              m4, m7, m13  ; a2'
+    paddd                m2, m4
+    pmaddwd              m4, m7, m14  ; b2
+    paddd                m1, m4
+    pmaddwd              m4, m7, m15  ; b2'
+    paddd                m3, m4
+    REPX       {psrad x, 4}, m0, m2, m1, m3
+    packssdw             m0, m2
+    packssdw             m1, m3
+    mova          [r7+wq*0], m0
+    mova          [r7+wq*2], m1
+    lea                  r7, [r7+wq*4]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 16
+    add                tmpq, 16
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_w8_loop0
+    RET
+%endif
+.hv:
+    and                  wd, -8
+    jnz .hv_w8
+    movzx               mxd, mxb
+    movq                 m0, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movq                 m2, [base+subpel_filters+1+myq*8]
+    WIN64_SPILL_XMM      15
+    movifnidn           ssq, r2mp
+    movifnidn          tmpq, r0mp
+    mova                 m7, [base+prep_8tap_2d_rnd]
+    sub                srcq, 2
+    pshuflw              m0, m0, q2121
+    pxor                 m6, m6
+    punpcklbw            m6, m0
+    punpcklbw            m2, m2
+    psraw                m6, 4
+    psraw                m2, 8
+    test          dword r7m, 0x800
+    jz .hv_w4_10bpc
+    psraw                m6, 2
+.hv_w4_10bpc:
+%if ARCH_X86_32
+%assign regs_used 4
+    ALLOC_STACK       -16*7
+%assign regs_used 7
+    %define             m10  [esp+16*3]
+    %define             m12  [esp+16*5]
+    %define             m13  [esp+16*6]
+    %define             m14  [base+spel_h_shufA]
+    %define             m11  [base+spel_h_shufB]
+    pshufd               m0, m2, q0000
+    pshufd               m1, m2, q1111
+    pshufd               m2, m2, q2222
+    pshufd               m5, m6, q0000
+    pshufd               m6, m6, q1111
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+    mova                m12, m5
+    mova                m13, m6
+    neg                 ssq
+    movu                 m3, [srcq+ssq*2]
+    movu                 m4, [srcq+ssq*1]
+    neg                 ssq
+%else
+    mov                  r6, ssq
+    pshufd               m8, m2, q0000
+    neg                  r6
+    pshufd               m9, m2, q1111
+    movu                 m3, [srcq+r6 *2]
+    pshufd              m10, m2, q2222
+    movu                 m4, [srcq+r6 *1]
+    pshufd              m12, m6, q0000
+    mova                m14, [base+spel_h_shufA]
+    pshufd              m13, m6, q1111
+    mova                m11, [base+spel_h_shufB]
+%endif
+    movu                 m1, [srcq+ssq*0]
+    movu                 m0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movu                 m2, [srcq+ssq*0]
+    HV_H_W4_6TAP         m3, m3, m5, m11
+    HV_H_W4_6TAP         m4, m4, m5, m11
+    HV_H_W4_6TAP         m5, m1, m5, m11
+    HV_H_W4_6TAP         m0, m0, m1, m11
+    HV_H_W4_6TAP         m2, m2, m1, m11
+    REPX       {psrad x, 6}, m3, m5, m4, m0, m2
+    packssdw             m3, m5      ; 0 2
+    packssdw             m4, m0      ; 1 3
+    packssdw             m5, m2      ; 2 4
+    punpcklwd            m1, m3, m4  ; 01
+    punpckhwd            m3, m4      ; 23
+    punpcklwd            m2, m4, m5  ; 12
+    punpckhwd            m4, m5      ; 34
+.hv_w4_loop:
+    movu                 m0, [srcq+ssq*1]
+    pmaddwd              m5, m8, m1  ; a0
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m6, m8, m2  ; b0
+    mova                 m1, m3
+    pmaddwd              m3, m9      ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m9      ; b1
+    paddd                m5, m3
+    movu                 m3, [srcq+ssq*0]
+    paddd                m6, m4
+    HV_H_W4_6TAP         m0, m0, m4, m11
+    HV_H_W4_6TAP         m3, m3, m4, m11
+    psrad                m4, m2, 16
+    psrad                m0, 6
+    psrad                m3, 6
+    packssdw             m4, m0      ; 4 5
+    packssdw             m0, m3      ; 5 6
+    punpcklwd            m3, m4, m0  ; 45
+    punpckhwd            m4, m0      ; 56
+    pmaddwd              m0, m10, m3 ; a2
+    paddd                m5, m7
+    paddd                m5, m0
+    pmaddwd              m0, m10, m4 ; b2
+    paddd                m6, m7
+    paddd                m6, m0
+    psrad                m5, 6
+    psrad                m6, 6
+    packssdw             m5, m6
+    mova             [tmpq], m5
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    RESET_STACK_STATE
+    shr                 mxd, 16
+    movq                 m2, [base+subpel_filters+1+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovb               myd, mxd
+    movq                 m1, [base+subpel_filters+1+myq*8]
+    movifnidn           ssq, r2mp
+    mova                 m4, [base+prep_8tap_2d_rnd]
+    pxor                 m0, m0
+    punpcklbw            m0, m2
+    punpcklbw            m1, m1
+    sub                srcq, 4
+    psraw                m0, 4
+    psraw                m1, 8
+    test          dword r7m, 0x800
+    jz .hv_w8_10bpc
+    psraw                m0, 2
+.hv_w8_10bpc:
+%if ARCH_X86_32
+%assign regs_used 1
+    ALLOC_STACK       -16*9
+%assign regs_used 7
+    mov                tmpq, r0mp
+    mova         [rsp+16*7], m4
+%else
+%if WIN64
+    PUSH                 r8
+%assign regs_used 9
+%endif
+    ALLOC_STACK        16*6, 16
+%endif
+    pshufd               m2, m0, q0000
+    mova         [rsp+16*0], m2
+    pshufd               m2, m0, q1111
+    mova         [rsp+16*1], m2
+    pshufd               m0, m0, q2222
+    mova         [rsp+16*2], m0
+    pshufd               m2, m1, q0000
+    mova         [rsp+16*3], m2
+    pshufd               m2, m1, q1111
+    mova         [rsp+16*4], m2
+    pshufd               m1, m1, q2222
+    mova         [rsp+16*5], m1
+    mov                  r6, ssq
+    neg                  r6
+%if ARCH_X86_32
+    mov                 r5d, wd
+    shl                 r5d, 14
+    lea                 r5d, [r5+hq-(1<<16)]
+%if STACK_ALIGNMENT < 16
+    %define           srcmp  [esp+16*8+4*0]
+    %define           tmpmp  [esp+16*8+4*1]
+%endif
+.hv_w8_loop0:
+    mov               srcmp, srcq
+    mov               tmpmp, tmpq
+    movu                 m5, [srcq+r6*2+0]
+    movu                 m6, [srcq+r6*2+2]
+    mova                 m7, [rsp+16*0]
+    mova                 m1, [rsp+16*1]
+    mova                 m0, [rsp+16*2]
+    HV_H_6TAP            m2, m5, m6, m7, m1, m0
+    movu                 m5, [srcq+r6*1+0]
+    movu                 m6, [srcq+r6*1+2]
+    HV_H_6TAP            m3, m5, m6, m7, m1, m0
+    movu                 m5, [srcq+ssq*0+0]
+    movu                 m6, [srcq+ssq*0+2]
+    HV_H_6TAP            m4, m5, m6, m7, m1, m0
+    movu                 m5, [srcq+ssq*1+0]
+    movu                 m6, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    HV_H_6TAP            m0, m5, m6, m7, m1
+    movu                 m5, [srcq+ssq*0+0]
+    movu                 m6, [srcq+ssq*0+2]
+    HV_H_6TAP            m1, m5, m6, m7
+    mova                 m5, [rsp+16*7]
+    REPX      {paddd x, m5}, m2, m3, m4, m0, m1
+    REPX      {psrad x, 6 }, m2, m4, m3, m0, m1
+    packssdw             m2, m4     ; 0 2
+    packssdw             m3, m0     ; 1 3
+    packssdw             m4, m1     ; 2 4
+    punpcklwd            m0, m2, m3 ; 01
+    punpckhwd            m2, m3     ; 23
+    punpcklwd            m1, m3, m4 ; 12
+    punpckhwd            m3, m4     ; 34
+.hv_w8_loop:
+    mova                 m5, [rsp+16*3]
+    mova                 m6, [rsp+16*4]
+    pmaddwd              m4, m0, m5 ; a0
+    pmaddwd              m5, m1     ; b0
+    mova                 m0, m2
+    pmaddwd              m2, m6     ; a1
+    mova                 m1, m3
+    pmaddwd              m3, m6     ; b1
+    paddd                m4, m2
+    movu                 m2, [srcq+ssq*1+0]
+    paddd                m5, m3
+    movu                 m3, [srcq+ssq*1+2]
+    lea                srcq, [srcq+ssq*2]
+    HV_H_6TAP            m6, m2, m3
+    movu                 m2, [srcq+ssq*0+0]
+    movu                 m3, [srcq+ssq*0+2]
+    HV_H_6TAP            m7, m2, m3
+    mova                 m2, [rsp+16*7]
+    psrad                m3, m1, 16
+    REPX      {paddd x, m2}, m6, m7, m4, m5
+    psrad                m6, 6
+    psrad                m7, 6
+    packssdw             m3, m6     ; 4 5
+    packssdw             m6, m7     ; 5 6
+    mova                 m7, [rsp+16*5]
+    punpcklwd            m2, m3, m6 ; 45
+    punpckhwd            m3, m6     ; 56
+    pmaddwd              m6, m2, m7 ; a2
+    pmaddwd              m7, m3     ; b2
+    paddd                m4, m6
+    paddd                m5, m7
+    psrad                m4, 6
+    psrad                m5, 6
+    packssdw             m4, m5
+    movq        [tmpq+wq*0], m4
+    movhps      [tmpq+wq*2], m4
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    mov                srcq, srcmp
+    mov                tmpq, tmpmp
+    movzx                hd, r5w
+    add                srcq, 8
+    add                tmpq, 8
+    sub                 r5d, 1<<16
+%else
+    lea                 r8d, [wq*4-(1<<5)]
+    lea                 r8d, [hq+r8*8]
+.hv_w8_loop0:
+    mova                 m5, [spel_h_shufA]
+    movu                 m0, [srcq+r6*2+ 0]
+    mova                 m6, [rsp+16*0]
+    movu                 m1, [srcq+r6*2+ 8]
+    mova                 m7, [rsp+16*1]
+    movu                 m2, [srcq+r6*2+16]
+    mova                 m8, [rsp+16*2]
+    HV_H_6TAP            m9, m0, m1, m2, 6, m5, m6, m7, m8
+    movu                 m0, [srcq+r6*1+ 0]
+    movu                 m1, [srcq+r6*1+ 8]
+    movu                 m2, [srcq+r6*1+16]
+    lea                  r5, [srcq+ssq*2]
+    HV_H_6TAP           m11, m0, m1, m2, 6, m5, m6, m7, m8
+    movu                 m0, [srcq+ssq*0+ 0]
+    movu                 m1, [srcq+ssq*0+ 8]
+    movu                 m2, [srcq+ssq*0+16]
+    mov                  r7, tmpq
+    HV_H_6TAP           m13, m0, m1, m2, 6, m5, m6, m7, m8
+    movu                 m0, [srcq+ssq*1+ 0]
+    movu                 m1, [srcq+ssq*1+ 8]
+    movu                 m2, [srcq+ssq*1+16]
+    HV_H_6TAP           m15, m0, m1, m2, 6, m5, m6, m7, m8
+    movu                 m0, [r5+ssq*0+ 0]
+    movu                 m1, [r5+ssq*0+ 8]
+    movu                 m2, [r5+ssq*0+16]
+    HV_H_6TAP            m5, m0, m1, m2, 6, m5, m6, m7, m8
+    punpcklwd            m8, m9, m11  ; 01
+    punpckhwd            m9, m11
+    punpcklwd           m10, m11, m13 ; 12
+    punpckhwd           m11, m13
+    punpcklwd           m12, m13, m15 ; 23
+    punpckhwd           m13, m15
+    punpcklwd           m14, m15, m5  ; 34
+    punpckhwd           m15, m5
+.hv_w8_loop:
+    mova                 m3, [rsp+16*3]
+    mova                 m7, [rsp+16*4]
+    pmaddwd              m0, m8, m3   ; a0
+    mova                 m8, m12
+    pmaddwd              m2, m9, m3   ; a0'
+    mova                 m9, m13
+    pmaddwd              m1, m10, m3  ; b0
+    mova                m10, m14
+    pmaddwd              m3, m11      ; b0'
+    mova                m11, m15
+    REPX    {pmaddwd x, m7}, m12, m13, m14, m15
+    movu                 m6, [r5+ssq*1+ 0]
+    paddd                m0, m12
+    movu                 m7, [r5+ssq*1+ 8]
+    paddd                m2, m13
+    movu                m12, [r5+ssq*1+16]
+    paddd                m1, m14
+    lea                  r5, [r5+ssq*2]
+    paddd                m3, m15
+    HV_H_6TAP           m15, m6, m7, m12, 6
+    movu                 m6, [r5+ssq*0+ 0]
+    movu                 m7, [r5+ssq*0+ 8]
+    movu                m14, [r5+ssq*0+16]
+    punpcklwd           m12, m5, m15 ; 45
+    punpckhwd           m13, m5, m15
+    HV_H_6TAP            m5, m6, m7, m14, 6
+    mova                 m7, [rsp+16*5]
+    REPX      {paddd x, m4}, m0, m2, m1, m3
+    punpcklwd           m14, m15, m5  ; 56
+    punpckhwd           m15, m5
+    pmaddwd              m6, m12, m7  ; a2
+    paddd                m0, m6
+    pmaddwd              m6, m13, m7  ; a2'
+    paddd                m2, m6
+    pmaddwd              m6, m14, m7  ; b2
+    pmaddwd              m7, m15      ; b2'
+    paddd                m1, m6
+    paddd                m3, m7
+    REPX       {psrad x, 6}, m0, m2, m1, m3
+    packssdw             m0, m2
+    packssdw             m1, m3
+    mova          [r7+wq*0], m0
+    mova          [r7+wq*2], m1
+    lea                  r7, [r7+wq*4]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 16
+    add                tmpq, 16
+    movzx                hd, r8b
+    sub                 r8d, 1<<8
+%endif
+    jg .hv_w8_loop0
+    RET
+
+PREP_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_16bpc
+PREP_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_16bpc
+PREP_8TAP_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_16bpc
+PREP_8TAP_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_16bpc
+PREP_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal prep_8tap_16bpc, 0, 8, 0, tmp, src, ss, w, h, mx, my
+%if ARCH_X86_32
+    %define             mxb  r0b
+    %define             mxd  r0
+    %define             mxq  r0
+    %define             myb  r2b
+    %define             myd  r2
+    %define             myq  r2
+    %define              m8  [esp+16*0]
+    %define              m9  [esp+16*1]
+    %define             m10  [esp+16*2]
+    %define             m11  [esp+16*3]
+    %define             m12  [esp+16*4]
+    %define             m13  [esp+16*5]
+    %define             m14  [esp+16*6]
+    %define             m15  [esp+16*7]
+%endif
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    LEA                  t2, prep_ssse3
+    movifnidn            wd, wm
+    movifnidn          srcq, srcmp
+    test                mxd, 0xf00
+    jnz .h
+    movifnidn            hd, hm
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _prep_6tap_16bpc_ssse3).prep
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    movq                 m3, [base+subpel_filters+myq*8]
+    WIN64_SPILL_XMM      15
+    movddup              m7, [base+prep_8tap_1d_rnd]
+    movifnidn           ssq, r2mp
+    movifnidn          tmpq, r0mp
+    punpcklbw            m3, m3
+    psraw                m3, 8 ; sign-extend
+    test          dword r7m, 0x800
+    jnz .v_12bpc
+    psllw                m3, 2
+.v_12bpc:
+%if ARCH_X86_32
+    ALLOC_STACK       -16*7
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+    mova                m11, m3
+%else
+    pshufd               m8, m3, q0000
+    pshufd               m9, m3, q1111
+    pshufd              m10, m3, q2222
+    pshufd              m11, m3, q3333
+%endif
+    lea                  r6, [ssq*3]
+    sub                srcq, r6
+    mov                 r6d, wd
+    shl                  wd, 6
+    mov                  r5, srcq
+%if ARCH_X86_64
+    mov                  r7, tmpq
+%elif STACK_ALIGNMENT < 16
+    mov          [esp+4*29], tmpq
+%endif
+    lea                  wd, [wq+hq-(1<<8)]
+.v_loop0:
+    movq                 m1, [srcq+ssq*0]
+    movq                 m2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m3, [srcq+ssq*0]
+    movq                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m5, [srcq+ssq*0]
+    movq                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m0, [srcq+ssq*0]
+    punpcklwd            m1, m2      ; 01
+    punpcklwd            m2, m3      ; 12
+    punpcklwd            m3, m4      ; 23
+    punpcklwd            m4, m5      ; 34
+    punpcklwd            m5, m6      ; 45
+    punpcklwd            m6, m0      ; 56
+%if ARCH_X86_32
+    jmp .v_loop_start
+.v_loop:
+    mova                 m1, m12
+    mova                 m2, m13
+    mova                 m3, m14
+.v_loop_start:
+    pmaddwd              m1, m8      ; a0
+    pmaddwd              m2, m8      ; b0
+    mova                m12, m3
+    mova                m13, m4
+    pmaddwd              m3, m9      ; a1
+    pmaddwd              m4, m9      ; b1
+    paddd                m1, m3
+    paddd                m2, m4
+    mova                m14, m5
+    mova                 m4, m6
+    pmaddwd              m5, m10     ; a2
+    pmaddwd              m6, m10     ; b2
+    paddd                m1, m5
+    paddd                m2, m6
+    movq                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklwd            m5, m0, m6  ; 67
+    movq                 m0, [srcq+ssq*0]
+    pmaddwd              m3, m11, m5 ; a3
+    punpcklwd            m6, m0      ; 78
+    paddd                m1, m7
+    paddd                m1, m3
+    pmaddwd              m3, m11, m6 ; b3
+    paddd                m2, m7
+    paddd                m2, m3
+    psrad                m1, 4
+    psrad                m2, 4
+    packssdw             m1, m2
+    movq        [tmpq+r6*0], m1
+    movhps      [tmpq+r6*2], m1
+    lea                tmpq, [tmpq+r6*4]
+    sub                  hd, 2
+    jg .v_loop
+%if STACK_ALIGNMENT < 16
+    mov                tmpq, [esp+4*29]
+    add                  r5, 8
+    add                tmpq, 8
+    mov                srcq, r5
+    mov          [esp+4*29], tmpq
+%else
+    mov                tmpq, tmpmp
+    add                  r5, 8
+    add                tmpq, 8
+    mov                srcq, r5
+    mov               tmpmp, tmpq
+%endif
+%else
+.v_loop:
+    pmaddwd             m12, m8, m1  ; a0
+    pmaddwd             m13, m8, m2  ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddwd              m3, m9      ; a1
+    pmaddwd              m4, m9      ; b1
+    paddd               m12, m3
+    paddd               m13, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddwd              m5, m10     ; a2
+    pmaddwd              m6, m10     ; b2
+    paddd               m12, m5
+    paddd               m13, m6
+    movq                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklwd            m5, m0, m6  ; 67
+    movq                 m0, [srcq+ssq*0]
+    pmaddwd             m14, m11, m5 ; a3
+    punpcklwd            m6, m0      ; 78
+    paddd               m12, m7
+    paddd               m12, m14
+    pmaddwd             m14, m11, m6 ; b3
+    paddd               m13, m7
+    paddd               m13, m14
+    psrad               m12, 4
+    psrad               m13, 4
+    packssdw            m12, m13
+    movq        [tmpq+r6*0], m12
+    movhps      [tmpq+r6*2], m12
+    lea                tmpq, [tmpq+r6*4]
+    sub                  hd, 2
+    jg .v_loop
+    add                  r5, 8
+    add                  r7, 8
+    mov                srcq, r5
+    mov                tmpq, r7
+%endif
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .v_loop0
+    RET
+.h:
+    RESET_STACK_STATE
+    test                myd, 0xf00
+    jnz .hv
+    movifnidn           ssq, r2mp
+    movifnidn            hd, r4m
+    movddup              m5, [base+prep_8tap_1d_rnd]
+    cmp                  wd, 4
+    jne .h_w8
+.h_w4:
+    movzx               mxd, mxb
+    movq                 m0, [base+subpel_filters+mxq*8]
+    mova                 m3, [base+spel_h_shufA]
+    mova                 m4, [base+spel_h_shufB]
+    movifnidn          tmpq, tmpmp
+    sub                srcq, 2
+    WIN64_SPILL_XMM       8
+    punpcklbw            m0, m0
+    psraw                m0, 8
+    test          dword r7m, 0x800
+    jnz .h_w4_12bpc
+    psllw                m0, 2
+.h_w4_12bpc:
+    pshufd               m6, m0, q1111
+    pshufd               m7, m0, q2222
+.h_w4_loop:
+    movu                 m1, [srcq+ssq*0]
+    movu                 m2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m0, m1, m3 ; 0 1 1 2 2 3 3 4
+    pshufb               m1, m4     ; 2 3 3 4 4 5 5 6
+    pmaddwd              m0, m6
+    pmaddwd              m1, m7
+    paddd                m0, m5
+    paddd                m0, m1
+    pshufb               m1, m2, m3
+    pshufb               m2, m4
+    pmaddwd              m1, m6
+    pmaddwd              m2, m7
+    paddd                m1, m5
+    paddd                m1, m2
+    psrad                m0, 4
+    psrad                m1, 4
+    packssdw             m0, m1
+    mova             [tmpq], m0
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h_w8:
+    WIN64_SPILL_XMM      11
+    shr                 mxd, 16
+    movq                 m2, [base+subpel_filters+mxq*8]
+    mova                 m4, [base+spel_h_shufA]
+    mova                 m6, [base+spel_h_shufB]
+    movifnidn          tmpq, r0mp
+    add                  wd, wd
+    punpcklbw            m2, m2
+    add                srcq, wq
+    psraw                m2, 8
+    add                tmpq, wq
+    neg                  wq
+    test          dword r7m, 0x800
+    jnz .h_w8_12bpc
+    psllw                m2, 2
+.h_w8_12bpc:
+    pshufd               m7, m2, q0000
+%if ARCH_X86_32
+    ALLOC_STACK       -16*3
+    pshufd               m0, m2, q1111
+    pshufd               m1, m2, q2222
+    pshufd               m2, m2, q3333
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m10, m2
+%else
+    pshufd               m8, m2, q1111
+    pshufd               m9, m2, q2222
+    pshufd              m10, m2, q3333
+%endif
+.h_w8_loop0:
+    mov                  r6, wq
+.h_w8_loop:
+    movu                 m0, [srcq+r6- 6]
+    movu                 m1, [srcq+r6+ 2]
+    pshufb               m2, m0, m4  ; 0 1 1 2 2 3 3 4
+    pshufb               m0, m6      ; 2 3 3 4 4 5 5 6
+    pmaddwd              m2, m7      ; abcd0
+    pmaddwd              m0, m8      ; abcd1
+    pshufb               m3, m1, m4  ; 4 5 5 6 6 7 7 8
+    pshufb               m1, m6      ; 6 7 7 8 8 9 9 a
+    paddd                m2, m5
+    paddd                m0, m2
+    pmaddwd              m2, m9, m3  ; abcd2
+    pmaddwd              m3, m7      ; efgh0
+    paddd                m0, m2
+    pmaddwd              m2, m10, m1 ; abcd3
+    pmaddwd              m1, m8      ; efgh1
+    paddd                m0, m2
+    movu                 m2, [srcq+r6+10]
+    paddd                m3, m5
+    paddd                m1, m3
+    pshufb               m3, m2, m4  ; a b b c c d d e
+    pshufb               m2, m6      ; 8 9 9 a a b b c
+    pmaddwd              m3, m9      ; efgh2
+    pmaddwd              m2, m10     ; efgh3
+    paddd                m1, m3
+    paddd                m1, m2
+    psrad                m0, 4
+    psrad                m1, 4
+    packssdw             m0, m1
+    mova          [tmpq+r6], m0
+    add                  r6, 16
+    jl .h_w8_loop
+    add                srcq, ssq
+    sub                tmpq, wq
+    dec                  hd
+    jg .h_w8_loop0
+    RET
+.hv:
+    RESET_STACK_STATE
+    movzx               t3d, mxb
+    shr                 mxd, 16
+    cmp                  wd, 4
+    cmove               mxd, t3d
+    movifnidn            hd, r4m
+    movq                 m2, [base+subpel_filters+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    movq                 m3, [base+subpel_filters+myq*8]
+%if ARCH_X86_32
+    mov                 ssq, r2mp
+    mov                tmpq, r0mp
+    mova                 m0, [base+spel_h_shufA]
+    mova                 m1, [base+spel_h_shufB]
+    mova                 m4, [base+prep_8tap_2d_rnd]
+    ALLOC_STACK      -16*14
+    mova                 m8, m0
+    mova                 m9, m1
+    mova                m14, m4
+%else
+%if WIN64
+    ALLOC_STACK        16*6, 16
+%endif
+    mova                 m8, [base+spel_h_shufA]
+    mova                 m9, [base+spel_h_shufB]
+%endif
+    pxor                 m0, m0
+    punpcklbw            m0, m2
+    punpcklbw            m3, m3
+    psraw                m0, 4
+    psraw                m3, 8
+    test          dword r7m, 0x800
+    jz .hv_10bpc
+    psraw                m0, 2
+.hv_10bpc:
+    lea                  r6, [ssq*3]
+    sub                srcq, 6
+    sub                srcq, r6
+    mov                 r6d, wd
+    shl                  wd, 6
+    mov                  r5, srcq
+%if ARCH_X86_32
+    %define             tmp  esp+16*8
+%if STACK_ALIGNMENT < 16
+    mov          [esp+4*61], tmpq
+%endif
+    pshufd               m1, m0, q0000
+    pshufd               m2, m0, q1111
+    pshufd               m5, m0, q2222
+    pshufd               m0, m0, q3333
+    mova                m10, m1
+    mova                m11, m2
+    mova                m12, m5
+    mova                m13, m0
+%else
+%if WIN64
+    %define             tmp  rsp
+%else
+    %define             tmp  rsp-88 ; red zone
+%endif
+    mov                  r7, tmpq
+    pshufd              m10, m0, q0000
+    pshufd              m11, m0, q1111
+    pshufd              m12, m0, q2222
+    pshufd              m13, m0, q3333
+%endif
+    lea                  wd, [wq+hq-(1<<8)]
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    mova         [tmp+16*1], m0
+    mova         [tmp+16*2], m1
+    mova         [tmp+16*3], m2
+    mova         [tmp+16*4], m3
+.hv_loop0:
+%if ARCH_X86_64
+    mova                m14, [prep_8tap_2d_rnd]
+%endif
+    movu                 m4, [srcq+ssq*0+0]
+    movu                 m1, [srcq+ssq*0+8]
+    movu                 m5, [srcq+ssq*1+0]
+    movu                 m2, [srcq+ssq*1+8]
+    lea                srcq, [srcq+ssq*2]
+    movu                 m6, [srcq+ssq*0+0]
+    movu                 m3, [srcq+ssq*0+8]
+    PUT_8TAP_HV_H         4, 1, 0, 6
+    PUT_8TAP_HV_H         5, 2, 0, 6
+    PUT_8TAP_HV_H         6, 3, 0, 6
+    movu                 m7, [srcq+ssq*1+0]
+    movu                 m2, [srcq+ssq*1+8]
+    lea                srcq, [srcq+ssq*2]
+    movu                 m1, [srcq+ssq*0+0]
+    movu                 m3, [srcq+ssq*0+8]
+    PUT_8TAP_HV_H         7, 2, 0, 6
+    PUT_8TAP_HV_H         1, 3, 0, 6
+    movu                 m2, [srcq+ssq*1+0]
+    movu                 m3, [srcq+ssq*1+8]
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_HV_H         2, 3, 0, 6
+    packssdw             m4, m7      ; 0 3
+    packssdw             m5, m1      ; 1 4
+    movu                 m0, [srcq+ssq*0+0]
+    movu                 m1, [srcq+ssq*0+8]
+    PUT_8TAP_HV_H         0, 1, 3, 6
+    packssdw             m6, m2      ; 2 5
+    packssdw             m7, m0      ; 3 6
+    punpcklwd            m1, m4, m5  ; 01
+    punpckhwd            m4, m5      ; 34
+    punpcklwd            m2, m5, m6  ; 12
+    punpckhwd            m5, m6      ; 45
+    punpcklwd            m3, m6, m7  ; 23
+    punpckhwd            m6, m7      ; 56
+%if ARCH_X86_32
+    jmp .hv_loop_start
+.hv_loop:
+    mova                 m1, [tmp+16*5]
+    mova                 m2, m15
+.hv_loop_start:
+    mova                 m7, [tmp+16*1]
+    pmaddwd              m1, m7      ; a0
+    pmaddwd              m2, m7      ; b0
+    mova                 m7, [tmp+16*2]
+    mova         [tmp+16*5], m3
+    pmaddwd              m3, m7      ; a1
+    mova                m15, m4
+    pmaddwd              m4, m7      ; b1
+    mova                 m7, [tmp+16*3]
+    paddd                m1, m14
+    paddd                m2, m14
+    paddd                m1, m3
+    paddd                m2, m4
+    mova                 m3, m5
+    pmaddwd              m5, m7      ; a2
+    mova                 m4, m6
+    pmaddwd              m6, m7      ; b2
+    paddd                m1, m5
+    paddd                m2, m6
+    movu                 m7, [srcq+ssq*1+0]
+    movu                 m5, [srcq+ssq*1+8]
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_HV_H         7, 5, 6, 6
+    packssdw             m0, m7      ; 6 7
+    mova         [tmp+16*0], m0
+    movu                 m0, [srcq+ssq*0+0]
+    movu                 m5, [srcq+ssq*0+8]
+    PUT_8TAP_HV_H         0, 5, 6, 6
+    mova                 m6, [tmp+16*0]
+    packssdw             m7, m0      ; 7 8
+    punpcklwd            m5, m6, m7  ; 67
+    punpckhwd            m6, m7      ; 78
+    pmaddwd              m7, m5, [tmp+16*4]
+    paddd                m1, m7      ; a3
+    pmaddwd              m7, m6, [tmp+16*4]
+    paddd                m2, m7      ; b3
+    psrad                m1, 6
+    psrad                m2, 6
+    packssdw             m1, m2
+    movq        [tmpq+r6*0], m1
+    movhps      [tmpq+r6*2], m1
+    lea                tmpq, [tmpq+r6*4]
+    sub                  hd, 2
+    jg .hv_loop
+%if STACK_ALIGNMENT < 16
+    mov                tmpq, [esp+4*61]
+    add                  r5, 8
+    add                tmpq, 8
+    mov                srcq, r5
+    mov          [esp+4*61], tmpq
+%else
+    mov                tmpq, tmpmp
+    add                  r5, 8
+    add                tmpq, 8
+    mov                srcq, r5
+    mov               tmpmp, tmpq
+%endif
+%else
+.hv_loop:
+    mova                m15, [tmp+16*1]
+    mova                 m7, [prep_8tap_2d_rnd]
+    pmaddwd             m14, m15, m1 ; a0
+    pmaddwd             m15, m2      ; b0
+    paddd               m14, m7
+    paddd               m15, m7
+    mova                 m7, [tmp+16*2]
+    mova                 m1, m3
+    pmaddwd              m3, m7      ; a1
+    mova                 m2, m4
+    pmaddwd              m4, m7      ; b1
+    mova                 m7, [tmp+16*3]
+    paddd               m14, m3
+    paddd               m15, m4
+    mova                 m3, m5
+    pmaddwd              m5, m7      ; a2
+    mova                 m4, m6
+    pmaddwd              m6, m7      ; b2
+    paddd               m14, m5
+    paddd               m15, m6
+    movu                 m7, [srcq+ssq*1+0]
+    movu                 m5, [srcq+ssq*1+8]
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_HV_H         7, 5, 6, 6, [prep_8tap_2d_rnd]
+    packssdw             m0, m7      ; 6 7
+    mova         [tmp+16*0], m0
+    movu                 m0, [srcq+ssq*0+0]
+    movu                 m5, [srcq+ssq*0+8]
+    PUT_8TAP_HV_H         0, 5, 6, 6, [prep_8tap_2d_rnd]
+    mova                 m6, [tmp+16*0]
+    packssdw             m7, m0      ; 7 8
+    punpcklwd            m5, m6, m7  ; 67
+    punpckhwd            m6, m7      ; 78
+    pmaddwd              m7, m5, [tmp+16*4]
+    paddd               m14, m7      ; a3
+    pmaddwd              m7, m6, [tmp+16*4]
+    paddd               m15, m7      ; b3
+    psrad               m14, 6
+    psrad               m15, 6
+    packssdw            m14, m15
+    movq        [tmpq+r6*0], m14
+    movhps      [tmpq+r6*2], m14
+    lea                tmpq, [tmpq+r6*4]
+    sub                  hd, 2
+    jg .hv_loop
+    add                  r5, 8
+    add                  r7, 8
+    mov                srcq, r5
+    mov                tmpq, r7
+%endif
+    movzx                hd, wb
+    sub                  wd, 1<<8
+    jg .hv_loop0
+    RET
+%undef tmp
+
+%macro movifprep 2
+ %if isprep
+    mov %1, %2
+ %endif
+%endmacro
+
+%macro SAVE_REG 1
+ %xdefine r%1_save  r%1
+ %xdefine r%1q_save r%1q
+ %xdefine r%1d_save r%1d
+ %if ARCH_X86_32
+  %define r%1m_save [rstk+stack_offset+(%1+1)*4]
+ %endif
+%endmacro
+
+%macro LOAD_REG 1
+ %xdefine r%1  r%1_save
+ %xdefine r%1q r%1q_save
+ %xdefine r%1d r%1d_save
+ %if ARCH_X86_32
+  %define r%1m r%1m_save
+ %endif
+ %undef r%1d_save
+ %undef r%1q_save
+ %undef r%1_save
+%endmacro
+
+%macro REMAP_REG 2-3
+ %xdefine r%1  r%2
+ %xdefine r%1q r%2q
+ %xdefine r%1d r%2d
+ %if ARCH_X86_32
+  %if %3 == 0
+   %xdefine r%1m r%2m
+  %else
+   %define r%1m [rstk+stack_offset+(%1+1)*4]
+  %endif
+ %endif
+%endmacro
+
+%macro MCT_8TAP_SCALED_REMAP_REGS_TO_PREV 0
+ %if isprep
+  %if ARCH_X86_64
+   SAVE_REG 14
+   %assign %%i 14
+   %rep 14
+    %assign %%j %%i-1
+    REMAP_REG %%i, %%j
+    %assign %%i %%i-1
+   %endrep
+  %else
+   SAVE_REG 5
+   %assign %%i 5
+   %rep 5
+    %assign %%j %%i-1
+    REMAP_REG %%i, %%j, 0
+    %assign %%i %%i-1
+   %endrep
+  %endif
+ %endif
+%endmacro
+
+%macro MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT 0
+ %if isprep
+  %assign %%i 1
+  %if ARCH_X86_64
+   %rep 13
+    %assign %%j %%i+1
+    REMAP_REG %%i, %%j
+    %assign %%i %%i+1
+   %endrep
+   LOAD_REG 14
+  %else
+   %rep 4
+    %assign %%j %%i+1
+    REMAP_REG %%i, %%j, 1
+    %assign %%i %%i+1
+   %endrep
+   LOAD_REG 5
+  %endif
+ %endif
+%endmacro
+
+%macro MC_8TAP_SCALED_RET 0-1 1 ; leave_mapping_unchanged
+    MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT
+    RET
+ %if %1
+    MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %endif
+%endmacro
+
+%if ARCH_X86_32
+ %macro MC_4TAP_SCALED_H 1 ; dst_mem
+    movu                 m7, [srcq+ssq*0]
+    movu                 m2, [srcq+ssq*1]
+    movu                 m5, [r4  +ssq*0]
+    movu                 m6, [r4  +ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    lea                  r4, [r4  +ssq*2]
+    REPX    {pshufb x, m12}, m7, m2
+    REPX   {pmaddwd x, m13}, m7, m2
+    REPX    {pshufb x, m14}, m5, m6
+    REPX   {pmaddwd x, m15}, m5, m6
+    phaddd               m7, m5
+    phaddd               m2, m6
+    mova                 m5, [esp+0x00]
+    movd                 m6, [esp+0x10]
+    paddd                m7, m5
+    paddd                m2, m5
+    psrad                m7, m6
+    psrad                m2, m6
+    packssdw             m7, m2
+    mova           [stk+%1], m7
+ %endmacro
+%endif
+
+%if ARCH_X86_64
+ %macro MC_8TAP_SCALED_H 8 ; dst, tmp[0-6]
+    movu                m%1, [srcq+ r4*2]
+    movu                m%2, [srcq+ r6*2]
+    movu                m%3, [srcq+ r7*2]
+    movu                m%4, [srcq+ r9*2]
+    movu                m%5, [srcq+r10*2]
+    movu                m%6, [srcq+r11*2]
+    movu                m%7, [srcq+r13*2]
+    movu                m%8, [srcq+ rX*2]
+    add                srcq, ssq
+    pmaddwd             m%1, [stk+0x10]
+    pmaddwd             m%2, [stk+0x20]
+    pmaddwd             m%3, [stk+0x30]
+    pmaddwd             m%4, [stk+0x40]
+    pmaddwd             m%5, [stk+0x50]
+    pmaddwd             m%6, [stk+0x60]
+    pmaddwd             m%7, [stk+0x70]
+    pmaddwd             m%8, [stk+0x80]
+    phaddd              m%1, m%2
+    phaddd              m%3, m%4
+    phaddd              m%5, m%6
+    phaddd              m%7, m%8
+    phaddd              m%1, m%3
+    phaddd              m%5, m%7
+    paddd               m%1, hround
+    paddd               m%5, hround
+    psrad               m%1, m12
+    psrad               m%5, m12
+    packssdw            m%1, m%5
+ %endmacro
+%else
+ %macro MC_8TAP_SCALED_H 2-3 1 ; weights_mem_start, h_mem, load_fh_offsets
+  %if %3 == 1
+    mov                  r0, [stk+ 0]
+    mov                  rX, [stk+ 4]
+    mov                  r4, [stk+ 8]
+    mov                  r5, [stk+12]
+  %endif
+    movu                 m0, [srcq+r0*2]
+    movu                 m1, [srcq+rX*2]
+    movu                 m2, [srcq+r4*2]
+    movu                 m3, [srcq+r5*2]
+    mov                  r0, [stk+16]
+    mov                  rX, [stk+20]
+    mov                  r4, [stk+24]
+    mov                  r5, [stk+28]
+    pmaddwd              m0, [stk+%1+0x00]
+    pmaddwd              m1, [stk+%1+0x10]
+    pmaddwd              m2, [stk+%1+0x20]
+    pmaddwd              m3, [stk+%1+0x30]
+    phaddd               m0, m1
+    phaddd               m2, m3
+    movu                 m4, [srcq+r0*2]
+    movu                 m5, [srcq+rX*2]
+    movu                 m6, [srcq+r4*2]
+    movu                 m7, [srcq+r5*2]
+    add                srcq, ssq
+    pmaddwd              m4, [stk+%1+0xa0]
+    pmaddwd              m5, [stk+%1+0xb0]
+    pmaddwd              m6, [stk+%1+0xc0]
+    pmaddwd              m7, [stk+%1+0xd0]
+    phaddd               m4, m5
+    phaddd               m6, m7
+    phaddd               m0, m2
+    phaddd               m4, m6
+    paddd                m0, hround
+    paddd                m4, hround
+    psrad                m0, m12
+    psrad                m4, m12
+    packssdw             m0, m4
+  %if %2 != 0
+    mova           [stk+%2], m0
+  %endif
+ %endmacro
+%endif
+
+%macro MC_8TAP_SCALED 1
+%ifidn %1, put
+ %assign isput  1
+ %assign isprep 0
+ %if ARCH_X86_64
+  %if required_stack_alignment <= STACK_ALIGNMENT
+cglobal put_8tap_scaled_16bpc, 2, 15, 16, 0x1c0, dst, ds, src, ss, w, h, mx, my, dx, dy, pxmax
+  %else
+cglobal put_8tap_scaled_16bpc, 2, 14, 16, 0x1c0, dst, ds, src, ss, w, h, mx, my, dx, dy, pxmax
+  %endif
+ %else ; ARCH_X86_32
+  %if required_stack_alignment <= STACK_ALIGNMENT
+cglobal put_8tap_scaled_16bpc, 0, 7, 8, 0x200, dst, ds, src, ss, w, h, mx, my, dx, dy, pxmax
+  %else
+cglobal put_8tap_scaled_16bpc, 0, 7, 8, -0x200-0x30, dst, ds, src, ss, w, h, mx, my, dx, dy, pxmax
+  %endif
+ %endif
+ %xdefine base_reg r12
+%else ; prep
+ %assign isput  0
+ %assign isprep 1
+ %if ARCH_X86_64
+  %if required_stack_alignment <= STACK_ALIGNMENT
+cglobal prep_8tap_scaled_16bpc, 2, 15, 16, 0x1c0, tmp, src, ss, w, h, mx, my, dx, dy, pxmax
+   %xdefine tmp_stridem r14q
+  %else
+cglobal prep_8tap_scaled_16bpc, 2, 14, 16, 0x1c0, tmp, src, ss, w, h, mx, my, dx, dy, pxmax
+   %define tmp_stridem qword [stk+0x138]
+  %endif
+  %xdefine base_reg r11
+ %else ; ARCH_X86_32
+  %if required_stack_alignment <= STACK_ALIGNMENT
+cglobal prep_8tap_scaled_16bpc, 0, 7, 8, 0x200, tmp, src, ss, w, h, mx, my, dx, dy, pxmax
+  %else
+cglobal prep_8tap_scaled_16bpc, 0, 6, 8, 0x200, tmp, src, ss, w, h, mx, my, dx, dy, pxmax
+  %endif
+  %define tmp_stridem dword [stk+0x138]
+ %endif
+%endif
+%if ARCH_X86_32
+    mov         [esp+0x1f0], t0d
+    mov         [esp+0x1f4], t1d
+ %if isput && required_stack_alignment > STACK_ALIGNMENT
+    mov                dstd, dstm
+    mov                 dsd, dsm
+    mov                srcd, srcm
+    mov                 ssd, ssm
+    mov                  hd, hm
+    mov                  r4, mxm
+  %define r0m  [esp+0x200]
+  %define dsm  [esp+0x204]
+  %define dsmp dsm
+  %define r1m  dsm
+  %define r2m  [esp+0x208]
+  %define ssm  [esp+0x20c]
+  %define r3m  ssm
+  %define hm   [esp+0x210]
+  %define mxm  [esp+0x214]
+    mov                 r0m, dstd
+    mov                 dsm, dsd
+    mov                 r2m, srcd
+    mov                 ssm, ssd
+    mov                  hm, hd
+    mov                  r0, mym
+    mov                  r1, dxm
+    mov                  r2, dym
+  %define mym    [esp+0x218]
+  %define dxm    [esp+0x21c]
+  %define dym    [esp+0x220]
+    mov                 mxm, r4
+    mov                 mym, r0
+    mov                 dxm, r1
+    mov                 dym, r2
+    tzcnt                wd, wm
+ %endif
+ %if isput
+    mov                  r3, pxmaxm
+  %define pxmaxm r3
+ %else
+    mov                  r2, pxmaxm
+ %endif
+ %if isprep && required_stack_alignment > STACK_ALIGNMENT
+  %xdefine base_reg r5
+ %else
+  %xdefine base_reg r6
+ %endif
+%endif
+    LEA            base_reg, %1_8tap_scaled_16bpc_ssse3
+%xdefine base base_reg-%1_8tap_scaled_16bpc_ssse3
+%if ARCH_X86_64 || isprep || required_stack_alignment <= STACK_ALIGNMENT
+    tzcnt                wd, wm
+%endif
+%if ARCH_X86_64
+ %if isput
+    mov                 r7d, pxmaxm
+ %endif
+%else
+ %define m8  m0
+ %define m9  m1
+ %define m14 m4
+ %define m15 m3
+%endif
+    movd                 m8, dxm
+    movd                m14, mxm
+%if isput
+    movd                m15, pxmaxm
+%endif
+    pshufd               m8, m8, q0000
+    pshufd              m14, m14, q0000
+%if isput
+    pshuflw             m15, m15, q0000
+    punpcklqdq          m15, m15
+%endif
+%if isprep
+ %if UNIX64
+    mov                 r5d, t0d
+  DECLARE_REG_TMP 5, 7
+ %endif
+ %if ARCH_X86_64
+    mov                 r6d, pxmaxm
+ %endif
+%endif
+%if ARCH_X86_64
+    mov                 dyd, dym
+%endif
+%if isput
+ %if WIN64
+    mov                 r8d, hm
+  DEFINE_ARGS dst, ds, src, ss, w, _, _, my, h, dy, ss3
+  %define hm r5m
+  %define dxm r8m
+ %elif ARCH_X86_64
+  DEFINE_ARGS dst, ds, src, ss, w, h, _, my, dx, dy, ss3
+  %define hm r6m
+ %else
+ %endif
+ %if ARCH_X86_64
+  %if required_stack_alignment > STACK_ALIGNMENT
+   %define dsm [rsp+0x138]
+   %define rX r1
+   %define rXd r1d
+  %else
+   %define dsm dsq
+   %define rX r14
+   %define rXd r14d
+  %endif
+ %else
+  %define rX r1
+ %endif
+%else ; prep
+ %if WIN64
+    mov                 r7d, hm
+  DEFINE_ARGS tmp, src, ss, w, _, _, my, h, dy, ss3
+  %define hm r4m
+  %define dxm r7m
+ %elif ARCH_X86_64
+  DEFINE_ARGS tmp, src, ss, w, h, _, my, dx, dy, ss3
+  %xdefine hm r7m
+ %endif
+ MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %if ARCH_X86_64
+  %define rX r14
+  %define rXd r14d
+ %else
+  %define rX r3
+ %endif
+%endif
+%if ARCH_X86_64
+    shr                 r7d, 11
+    mova                m10, [base+pd_0x3ff]
+    movddup             m11, [base+s_8tap_h_rnd+r7*8]
+    movd                m12, [base+s_8tap_h_sh+r7*4]
+ %if isput
+    movddup             m13, [base+put_s_8tap_v_rnd+r7*8]
+    movd                 m7, [base+put_s_8tap_v_sh+r7*4]
+  %define pxmaxm [rsp]
+    mova             pxmaxm, m15
+    punpcklqdq          m12, m7
+ %endif
+    lea                ss3q, [ssq*3]
+    movzx               r7d, t1b
+    shr                 t1d, 16
+    cmp                  hd, 6
+    cmovs               t1d, r7d
+    sub                srcq, ss3q
+%else
+ %define m10    [base+pd_0x3ff]
+ %define m11    [esp+0x00]
+ %define m12    [esp+0x10]
+    shr                  r3, 11
+    movddup              m1, [base+s_8tap_h_rnd+r3*8]
+    movd                 m2, [base+s_8tap_h_sh+r3*4]
+ %if isput
+  %define m13    [esp+0x20]
+  %define pxmaxm [esp+0x30]
+  %define stk esp+0x40
+    movddup              m5, [base+put_s_8tap_v_rnd+r3*8]
+    movd                 m6, [base+put_s_8tap_v_sh+r3*4]
+    mova             pxmaxm, m15
+    punpcklqdq           m2, m6
+    mova                m13, m5
+ %else
+  %define m13 [base+pd_m524256]
+ %endif
+    mov                 ssd, ssm
+    mova                m11, m1
+    mova                m12, m2
+ MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT
+    mov                  r1, [esp+0x1f4]
+    lea                  r0, [ssd*3]
+    movzx                r2, r1b
+    shr                  r1, 16
+    cmp            dword hm, 6
+    cmovs                r1, r2
+    mov         [esp+0x1f4], r1
+ %if isprep
+    mov                  r1, r1m
+ %endif
+    mov                  r2, r2m
+    sub                srcq, r0
+ MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %define ss3q r0
+ %define myd r4
+ %define dyd dword dym
+ %define hd  dword hm
+%endif
+    cmp                 dyd, 1024
+    je .dy1
+    cmp                 dyd, 2048
+    je .dy2
+    movzx                wd, word [base+%1_8tap_scaled_ssse3_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%if isput
+.w2:
+ %if ARCH_X86_64
+    mov                 myd, mym
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd                m15, t0d
+ %else
+    movzx                r4, byte [esp+0x1f0]
+    sub                srcq, 2
+    movd                m15, r4
+ %endif
+    pxor                 m9, m9
+    punpckldq            m9, m8
+    paddd               m14, m9 ; mx+dx*[0-1]
+ %if ARCH_X86_64
+    mova                 m9, [base+pd_0x4000]
+ %endif
+    pshufd              m15, m15, q0000
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd               m15, m8
+    movd                r4d, m15
+    pshufd              m15, m15, q0321
+ %if ARCH_X86_64
+    movd                r6d, m15
+ %else
+    movd                r3d, m15
+ %endif
+    mova                 m5, [base+bdct_lb_q]
+    mova                 m6, [base+spel_s_shuf2]
+    movd                m15, [base+subpel_filters+r4*8+2]
+ %if ARCH_X86_64
+    movd                 m7, [base+subpel_filters+r6*8+2]
+ %else
+    movd                 m7, [base+subpel_filters+r3*8+2]
+ %endif
+    pxor                 m2, m2
+    pcmpeqd              m8, m2
+    psrld               m14, 10
+    paddd               m14, m14
+ %if ARCH_X86_32
+    mov                  r3, r3m
+    pshufb              m14, m5
+    paddb               m14, m6
+    mova              [stk], m14
+    SWAP                 m5, m0
+    SWAP                 m6, m3
+  %define m15 m6
+ %endif
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    movu                 m2, [srcq+ssq*2]
+    movu                 m3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    punpckldq           m15, m7
+ %if ARCH_X86_64
+    pshufb              m14, m5
+    paddb               m14, m6
+    pand                 m9, m8
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m9
+    movu                 m4, [srcq+ssq*0]
+    movu                 m5, [srcq+ssq*1]
+    movu                 m6, [srcq+ssq*2]
+    movu                 m7, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+ %else
+    pand                 m7, m5, [base+pd_0x4000]
+    pandn                m5, m15
+    por                  m5, m7
+  %define m15 m5
+ %endif
+    punpcklbw           m15, m15
+    psraw               m15, 8
+    REPX    {pshufb x, m14}, m0, m1, m2, m3
+    REPX   {pmaddwd x, m15}, m0, m1, m2, m3
+ %if ARCH_X86_64
+    REPX    {pshufb x, m14}, m4, m5, m6, m7
+    REPX   {pmaddwd x, m15}, m4, m5, m6, m7
+    phaddd               m0, m1
+    phaddd               m2, m3
+    phaddd               m4, m5
+    phaddd               m6, m7
+    REPX     {paddd x, m11}, m0, m2, m4, m6
+    REPX     {psrad x, m12}, m0, m2, m4, m6
+    packssdw             m0, m2 ; 0 1 2 3
+    packssdw             m4, m6 ; 4 5 6 7
+    SWAP                 m1, m4
+ %else
+    mova         [stk+0x10], m15
+    phaddd               m0, m1
+    phaddd               m2, m3
+    movu                 m1, [srcq+ssq*0]
+    movu                 m7, [srcq+ssq*1]
+    movu                 m6, [srcq+ssq*2]
+    movu                 m3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    REPX    {pshufb x, m14}, m1, m7, m6, m3
+    REPX   {pmaddwd x, m15}, m1, m7, m6, m3
+    phaddd               m1, m7
+    phaddd               m6, m3
+    REPX     {paddd x, m11}, m0, m2, m1, m6
+    REPX     {psrad x, m12}, m0, m2, m1, m6
+    packssdw             m0, m2
+    packssdw             m1, m6
+  %define m14 [stk+0x00]
+  %define m15 [stk+0x10]
+ %endif
+    palignr              m2, m1, m0, 4 ; 1 2 3 4
+    punpcklwd            m3, m0, m2    ; 01 12
+    punpckhwd            m0, m2        ; 23 34
+    pshufd               m5, m1, q0321 ; 5 6 7 _
+    punpcklwd            m2, m1, m5    ; 45 56
+    punpckhwd            m4, m1, m5    ; 67 __
+ %if ARCH_X86_32
+    mov                 myd, mym
+    mov                  r0, r0m
+    mova         [stk+0x20], m3
+    mova         [stk+0x30], m0
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m4
+ %endif
+.w2_loop:
+    and                 myd, 0x3ff
+ %if ARCH_X86_64
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq                m10, r6q
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    pshufd               m7, m10, q0000
+    pshufd               m8, m10, q1111
+    pmaddwd              m5, m3, m7
+    pmaddwd              m6, m0, m8
+    pshufd               m9, m10, q2222
+    pshufd              m10, m10, q3333
+    pmaddwd              m7, m2, m9
+    pmaddwd              m8, m4, m10
+    paddd                m5, m6
+    paddd                m7, m8
+ %else
+    mov                  r1, [esp+0x1f4]
+    xor                  r3, r3
+    mov                  r5, myd
+    shr                  r5, 6
+    lea                  r1, [r1+r5]
+    mov                  r5, 64 << 24
+    cmovnz               r3, [base+subpel_filters+r1*8+4]
+    cmovnz               r5, [base+subpel_filters+r1*8+0]
+    movd                 m6, r3
+    movd                 m7, r5
+    punpckldq            m7, m6
+    punpcklbw            m7, m7
+    psraw                m7, 8
+    pshufd               m5, m7, q0000
+    pshufd               m6, m7, q1111
+    pmaddwd              m3, m5
+    pmaddwd              m0, m6
+    pshufd               m5, m7, q2222
+    pshufd               m7, m7, q3333
+    pmaddwd              m2, m5
+    pmaddwd              m4, m7
+    paddd                m3, m0
+    paddd                m2, m4
+    SWAP                 m5, m3
+    SWAP                 m7, m2
+  %define m8 m3
+ %endif
+    paddd                m5, m13
+    pshufd               m6, m12, q1032
+    pxor                 m8, m8
+    paddd                m5, m7
+    psrad                m5, m6
+    packssdw             m5, m5
+    pmaxsw               m5, m8
+    pminsw               m5, pxmaxm
+    movd             [dstq], m5
+    add                dstq, dsmp
+    dec                  hd
+    jz .ret
+ %if ARCH_X86_64
+    add                 myd, dyd
+ %else
+    add                 myd, dym
+ %endif
+    test                myd, ~0x3ff
+ %if ARCH_X86_32
+    SWAP                 m3, m5
+    SWAP                 m2, m7
+    mova                 m3, [stk+0x20]
+    mova                 m0, [stk+0x30]
+    mova                 m2, [stk+0x40]
+    mova                 m4, [stk+0x50]
+ %endif
+    jz .w2_loop
+ %if ARCH_X86_32
+    mov                  r3, r3m
+ %endif
+    movu                 m5, [srcq]
+    test                myd, 0x400
+    jz .w2_skip_line
+    add                srcq, ssq
+    shufps               m3, m0, q1032      ; 01 12
+    shufps               m0, m2, q1032      ; 23 34
+    shufps               m2, m4, q1032      ; 45 56
+    pshufb               m5, m14
+    pmaddwd              m5, m15
+    phaddd               m5, m5
+    paddd                m5, m11
+    psrad                m5, m12
+    packssdw             m5, m5
+    palignr              m4, m5, m1, 12
+    punpcklqdq           m1, m4, m4         ; 6 7 6 7
+    punpcklwd            m4, m1, m5         ; 67 __
+ %if ARCH_X86_32
+    mova         [stk+0x20], m3
+    mova         [stk+0x30], m0
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m4
+ %endif
+    jmp .w2_loop
+.w2_skip_line:
+    movu                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova                 m3, m0             ; 01 12
+    mova                 m0, m2             ; 23 34
+    pshufb               m5, m14
+    pshufb               m6, m14
+    pmaddwd              m5, m15
+    pmaddwd              m6, m15
+    phaddd               m5, m6
+    paddd                m5, m11
+    psrad                m5, m12
+    packssdw             m5, m5             ; 6 7 6 7
+    punpckhqdq           m1, m5             ; 4 5 6 7
+    pshufd               m5, m1, q0321      ; 5 6 7 _
+    punpcklwd            m2, m1, m5         ; 45 56
+    punpckhwd            m4, m1, m5         ; 67 __
+ %if ARCH_X86_32
+    mova         [stk+0x20], m3
+    mova         [stk+0x30], m0
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m4
+ %endif
+    jmp .w2_loop
+%endif
+INIT_XMM ssse3
+.w4:
+%if ARCH_X86_64
+    mov                 myd, mym
+    mova         [rsp+0x10], m11
+    mova         [rsp+0x20], m12
+ %if isput
+    mova         [rsp+0x30], m13
+ %endif
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd                m15, t0d
+%else
+ %define m8  m0
+ %xdefine m14 m4
+ %define m15 m3
+    movzx                r4, byte [esp+0x1f0]
+    sub                srcq, 2
+    movd                m15, r4
+%endif
+    pmaddwd              m8, [base+rescale_mul]
+%if ARCH_X86_64
+    mova                 m9, [base+pd_0x4000]
+%else
+ %define m9 [base+pd_0x4000]
+%endif
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m0, m14, m10
+    psrld                m0, 6
+    paddd               m15, m0
+    pshufd               m7, m15, q1032
+%if ARCH_X86_64
+    movd                r4d, m15
+    movd               r11d, m7
+    pshufd              m15, m15, q0321
+    pshufd               m7, m7, q0321
+    movd                r6d, m15
+    movd               r13d, m7
+    mova                m10, [base+bdct_lb_q+ 0]
+    mova                m11, [base+bdct_lb_q+16]
+    movd                m13, [base+subpel_filters+ r4*8+2]
+    movd                 m2, [base+subpel_filters+ r6*8+2]
+    movd                m15, [base+subpel_filters+r11*8+2]
+    movd                 m4, [base+subpel_filters+r13*8+2]
+%else
+    movd                 r0, m15
+    movd                 r4, m7
+    pshufd              m15, m15, q0321
+    pshufd               m7, m7, q0321
+    movd                 rX, m15
+    movd                 r5, m7
+    mova                 m5, [base+bdct_lb_q+ 0]
+    mova                 m6, [base+bdct_lb_q+16]
+    movd                 m1, [base+subpel_filters+r0*8+2]
+    movd                 m2, [base+subpel_filters+rX*8+2]
+    movd                 m3, [base+subpel_filters+r4*8+2]
+    movd                 m7, [base+subpel_filters+r5*8+2]
+    movifprep            r3, r3m
+    SWAP                 m4, m7
+ %define m10 m5
+ %define m11 m6
+ %define m12 m1
+ %define m13 m1
+%endif
+    psrld               m14, 10
+    paddd               m14, m14
+    punpckldq           m13, m2
+    punpckldq           m15, m4
+    punpcklqdq          m13, m15
+    pxor                 m2, m2
+    pcmpeqd              m0, m2
+%if ARCH_X86_64
+    pand                 m9, m0
+%else
+    pand                 m2, m9, m0
+ %define m9 m2
+    SWAP                 m7, m4
+%endif
+    pandn                m0, m13
+%if ARCH_X86_64
+    SWAP                m13, m0
+%else
+ %define m13 m0
+%endif
+    por                 m13, m9
+    punpckhbw           m15, m13, m13
+    punpcklbw           m13, m13
+    psraw               m15, 8
+    psraw               m13, 8
+    pshufb              m12, m14, m10
+    pshufb              m14, m11
+    mova                m10, [base+spel_s_shuf2]
+    movd                r4d, m14
+    shr                 r4d, 24
+%if ARCH_X86_32
+    mova         [stk+0x20], m13
+    mova         [stk+0x30], m15
+    pxor                 m2, m2
+%endif
+    pshufb               m7, m14, m2
+    psubb               m14, m7
+    paddb               m12, m10
+    paddb               m14, m10
+%if ARCH_X86_64
+    lea                  r6, [r4+ssq*1]
+    lea                 r11, [r4+ssq*2]
+    lea                 r13, [r4+ss3q ]
+    movu                 m7, [srcq+ssq*0]
+    movu                 m9, [srcq+ssq*1]
+    movu                 m8, [srcq+ssq*2]
+    movu                m10, [srcq+ss3q ]
+    movu                 m1, [srcq+r4   ]
+    movu                 m3, [srcq+r6   ]
+    movu                 m2, [srcq+r11  ]
+    movu                 m4, [srcq+r13  ]
+    lea                srcq, [srcq+ssq*4]
+    REPX    {pshufb x, m12}, m7, m9, m8, m10
+    REPX   {pmaddwd x, m13}, m7, m9, m8, m10
+    REPX    {pshufb x, m14}, m1, m2, m3, m4
+    REPX   {pmaddwd x, m15}, m1, m2, m3, m4
+    mova                 m5, [rsp+0x10]
+    movd                xm6, [rsp+0x20]
+    phaddd               m7, m1
+    phaddd               m9, m3
+    phaddd               m8, m2
+    phaddd              m10, m4
+    movu                 m1, [srcq+ssq*0]
+    movu                 m2, [srcq+ssq*1]
+    movu                 m3, [srcq+ssq*2]
+    movu                 m4, [srcq+ss3q ]
+    REPX      {paddd x, m5}, m7, m9, m8, m10
+    REPX     {psrad x, xm6}, m7, m9, m8, m10
+    packssdw             m7, m9  ; 0 1
+    packssdw             m8, m10 ; 2 3
+    movu                 m0, [srcq+r4   ]
+    movu                 m9, [srcq+r6   ]
+    movu                m10, [srcq+r11  ]
+    movu                m11, [srcq+r13  ]
+    lea                srcq, [srcq+ssq*4]
+    REPX    {pshufb x, m12}, m1, m2, m3, m4
+    REPX   {pmaddwd x, m13}, m1, m2, m3, m4
+    REPX    {pshufb x, m14}, m0, m9, m10, m11
+    REPX   {pmaddwd x, m15}, m0, m9, m10, m11
+    phaddd               m1, m0
+    phaddd               m2, m9
+    phaddd               m3, m10
+    phaddd               m4, m11
+    REPX      {paddd x, m5}, m1, m2, m3, m4
+    REPX     {psrad x, xm6}, m1, m2, m3, m4
+    packssdw             m1, m2 ; 4 5
+    packssdw             m3, m4 ; 6 7
+    SWAP                 m9, m1
+    shufps               m4, m7, m8, q1032  ; 1 2
+    shufps               m5, m8, m9, q1032  ; 3 4
+    shufps               m6, m9, m3, q1032  ; 5 6
+    pshufd              m10, m3, q1032      ; 7 _
+    punpcklwd            m0, m7, m4 ; 01
+    punpckhwd            m7, m4     ; 12
+    punpcklwd            m1, m8, m5 ; 23
+    punpckhwd            m8, m5     ; 34
+    punpcklwd            m2, m9, m6 ; 45
+    punpckhwd            m9, m6     ; 56
+    punpcklwd            m3, m10    ; 67
+    mova         [rsp+0x40], m7
+    mova         [rsp+0x50], m8
+    mova         [rsp+0x60], m9
+%else
+    mova         [stk+0x00], m12
+    mova         [stk+0x10], m14
+    add                  r4, srcq
+    MC_4TAP_SCALED_H   0x40 ; 0 1
+    MC_4TAP_SCALED_H   0x50 ; 2 3
+    MC_4TAP_SCALED_H   0x60 ; 4 5
+    MC_4TAP_SCALED_H   0x70 ; 6 7
+    mova                 m4, [stk+0x40]
+    mova                 m5, [stk+0x50]
+    mova                 m6, [stk+0x60]
+    mova                 m7, [stk+0x70]
+    mov          [stk+0xc0], r4
+    shufps               m1, m4, m5, q1032 ; 1 2
+    shufps               m2, m5, m6, q1032 ; 3 4
+    shufps               m3, m6, m7, q1032 ; 5 6
+    pshufd               m0, m7, q1032     ; 7 _
+    mova         [stk+0xb0], m0
+    punpcklwd            m0, m4, m1         ; 01
+    punpckhwd            m4, m1             ; 12
+    punpcklwd            m1, m5, m2         ; 23
+    punpckhwd            m5, m2             ; 34
+    punpcklwd            m2, m6, m3         ; 45
+    punpckhwd            m6, m3             ; 56
+    punpcklwd            m3, m7, [stk+0xb0] ; 67
+    mov                 myd, mym
+    mov                  r0, r0m
+    mova         [stk+0x40], m0 ; 01
+    mova         [stk+0x50], m1 ; 23
+    mova         [stk+0x60], m2 ; 45
+    mova         [stk+0x70], m3 ; 67
+    mova         [stk+0x80], m4 ; 12
+    mova         [stk+0x90], m5 ; 34
+    mova         [stk+0xa0], m6 ; 56
+ %define m12 [stk+0x00]
+ %define m14 [stk+0x10]
+ %define m13 [stk+0x20]
+ %define m15 [stk+0x30]
+ %define hrnd_mem [esp+0x00]
+ %define hsh_mem  [esp+0x10]
+ %if isput
+  %define vrnd_mem [esp+0x20]
+ %else
+  %define vrnd_mem [base+pd_m524256]
+ %endif
+%endif
+.w4_loop:
+    and                 myd, 0x3ff
+%if ARCH_X86_64
+    mov                r11d, 64 << 24
+    mov                r13d, myd
+    shr                r13d, 6
+    lea                r13d, [t1+r13]
+    cmovnz             r11q, [base+subpel_filters+r13*8]
+    movq                 m9, r11q
+    punpcklbw            m9, m9
+    psraw                m9, 8
+    pshufd               m7, m9, q0000
+    pshufd               m8, m9, q1111
+    pmaddwd              m4, m0, m7
+    pmaddwd              m5, m1, m8
+    pshufd               m7, m9, q2222
+    pshufd               m9, m9, q3333
+    pmaddwd              m6, m2, m7
+    pmaddwd              m8, m3, m9
+ %if isput
+    movd                 m9, [rsp+0x28]
+  %define vrnd_mem [rsp+0x30]
+ %else
+  %define vrnd_mem [base+pd_m524256]
+ %endif
+    paddd                m4, m5
+    paddd                m6, m8
+    paddd                m4, m6
+    paddd                m4, vrnd_mem
+%else
+    mov                 mym, myd
+    mov                  r5, [esp+0x1f4]
+    xor                  r3, r3
+    shr                  r4, 6
+    lea                  r5, [r5+r4]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r5*8+0]
+    cmovnz               r3, [base+subpel_filters+r5*8+4]
+    movd                 m7, r4
+    movd                 m6, r3
+    punpckldq            m7, m6
+    punpcklbw            m7, m7
+    psraw                m7, 8
+    pshufd               m4, m7, q0000
+    pshufd               m5, m7, q1111
+    pshufd               m6, m7, q2222
+    pshufd               m7, m7, q3333
+    pmaddwd              m0, m4
+    pmaddwd              m1, m5
+    pmaddwd              m2, m6
+    pmaddwd              m3, m7
+ %if isput
+    movd                 m4, [esp+0x18]
+ %endif
+    paddd                m0, m1
+    paddd                m2, m3
+    paddd                m0, vrnd_mem
+    paddd                m0, m2
+    SWAP                 m4, m0
+ %define m9 m0
+%endif
+%if isput
+    pxor                 m5, m5
+    psrad                m4, m9
+    packssdw             m4, m4
+    pmaxsw               m4, m5
+    pminsw               m4, pxmaxm
+    movq             [dstq], m4
+    add                dstq, dsmp
+%else
+    psrad                m4, 6
+    packssdw             m4, m4
+    movq             [tmpq], m4
+    add                tmpq, 8
+%endif
+    dec                  hd
+    jz .ret
+%if ARCH_X86_64
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .w4_loop
+    mova                 m8, [rsp+0x10]
+    movd                 m9, [rsp+0x20]
+    movu                 m4, [srcq]
+    movu                 m5, [srcq+r4]
+    test                myd, 0x400
+    jz .w4_skip_line
+    mova                 m0, [rsp+0x40]
+    mova         [rsp+0x40], m1
+    mova                 m1, [rsp+0x50]
+    mova         [rsp+0x50], m2
+    mova                 m2, [rsp+0x60]
+    mova         [rsp+0x60], m3
+    pshufb               m4, m12
+    pshufb               m5, m14
+    pmaddwd              m4, m13
+    pmaddwd              m5, m15
+    phaddd               m4, m5
+    paddd                m4, m8
+    psrad                m4, m9
+    packssdw             m4, m4
+    punpcklwd            m3, m10, m4
+    mova                m10, m4
+    add                srcq, ssq
+    jmp .w4_loop
+.w4_skip_line:
+    movu                 m6, [srcq+ssq*1]
+    movu                 m7, [srcq+r6]
+    mova                 m0, [rsp+0x50]
+    mova                m11, [rsp+0x60]
+    pshufb               m4, m12
+    pshufb               m6, m12
+    pshufb               m5, m14
+    pshufb               m7, m14
+    pmaddwd              m4, m13
+    pmaddwd              m6, m13
+    pmaddwd              m5, m15
+    pmaddwd              m7, m15
+    mova         [rsp+0x40], m0
+    mova         [rsp+0x50], m11
+    phaddd               m4, m5
+    phaddd               m6, m7
+    paddd                m4, m8
+    paddd                m6, m8
+    psrad                m4, m9
+    psrad                m6, m9
+    packssdw             m4, m6
+    punpcklwd            m9, m10, m4
+    mova         [rsp+0x60], m9
+    pshufd              m10, m4, q1032
+    mova                 m0, m1
+    mova                 m1, m2
+    mova                 m2, m3
+    punpcklwd            m3, m4, m10
+    lea                srcq, [srcq+ssq*2]
+    jmp .w4_loop
+%else
+    SWAP                 m0, m4
+    mov                 myd, mym
+    mov                  r3, r3m
+    add                 myd, dym
+    test                myd, ~0x3ff
+    jnz .w4_next_line
+    mova                 m0, [stk+0x40]
+    mova                 m1, [stk+0x50]
+    mova                 m2, [stk+0x60]
+    mova                 m3, [stk+0x70]
+    jmp .w4_loop
+.w4_next_line:
+    mov                  r5, [stk+0xc0]
+    movu                 m4, [srcq]
+    movu                 m5, [r5]
+    test                myd, 0x400
+    jz .w4_skip_line
+    add          [stk+0xc0], ssq
+    mova                 m0, [stk+0x80]
+    mova                 m3, [stk+0x50]
+    mova         [stk+0x40], m0
+    mova         [stk+0x80], m3
+    mova                 m1, [stk+0x90]
+    mova                 m6, [stk+0x60]
+    mova         [stk+0x50], m1
+    mova         [stk+0x90], m6
+    mova                 m2, [stk+0xa0]
+    mova                 m7, [stk+0x70]
+    mova         [stk+0x60], m2
+    mova         [stk+0xa0], m7
+    pshufb               m4, m12
+    pshufb               m5, m14
+    pmaddwd              m4, m13
+    pmaddwd              m5, m15
+    phaddd               m4, m5
+    paddd                m4, hrnd_mem
+    psrad                m4, hsh_mem
+    packssdw             m4, m4
+    punpcklwd            m3, [stk+0xb0], m4
+    mova         [stk+0xb0], m4
+    mova         [stk+0x70], m3
+    add                srcq, ssq
+    jmp .w4_loop
+.w4_skip_line:
+    movu                 m6, [srcq+ssq*1]
+    movu                 m7, [r5  +ssq*1]
+    lea                  r5, [r5  +ssq*2]
+    mov          [stk+0xc0], r5
+    mova                 m0, [stk+0x50]
+    mova                 m1, [stk+0x60]
+    mova                 m2, [stk+0x70]
+    mova                 m3, [stk+0x90]
+    pshufb               m4, m12
+    pshufb               m6, m12
+    pshufb               m5, m14
+    pshufb               m7, m14
+    pmaddwd              m4, m13
+    pmaddwd              m6, m13
+    pmaddwd              m5, m15
+    pmaddwd              m7, m15
+    mova         [stk+0x40], m0
+    mova         [stk+0x50], m1
+    mova         [stk+0x60], m2
+    mova         [stk+0x80], m3
+    phaddd               m4, m5
+    phaddd               m6, m7
+    mova                 m5, [stk+0xa0]
+    mova                 m7, [stk+0xb0]
+    paddd                m4, hrnd_mem
+    paddd                m6, hrnd_mem
+    psrad                m4, hsh_mem
+    psrad                m6, hsh_mem
+    packssdw             m4, m6
+    punpcklwd            m7, m4
+    pshufd               m6, m4, q1032
+    mova         [stk+0x90], m5
+    mova         [stk+0xa0], m7
+    mova         [stk+0xb0], m6
+    punpcklwd            m3, m4, m6
+    mova         [stk+0x70], m3
+    lea                srcq, [srcq+ssq*2]
+    jmp .w4_loop
+%endif
+INIT_XMM ssse3
+%if ARCH_X86_64
+ %define stk rsp+0x20
+%endif
+.w8:
+    mov    dword [stk+0xf0], 1
+    movifprep   tmp_stridem, 16
+    jmp .w_start
+.w16:
+    mov    dword [stk+0xf0], 2
+    movifprep   tmp_stridem, 32
+    jmp .w_start
+.w32:
+    mov    dword [stk+0xf0], 4
+    movifprep   tmp_stridem, 64
+    jmp .w_start
+.w64:
+    mov    dword [stk+0xf0], 8
+    movifprep   tmp_stridem, 128
+    jmp .w_start
+.w128:
+    mov    dword [stk+0xf0], 16
+    movifprep   tmp_stridem, 256
+.w_start:
+%if ARCH_X86_64
+ %ifidn %1, put
+    movifnidn           dsm, dsq
+ %endif
+    mova         [rsp+0x10], m11
+ %define hround m11
+    shr                 t0d, 16
+    movd                m15, t0d
+ %if isprep
+    mova                m13, [base+pd_m524256]
+ %endif
+%else
+ %define hround [esp+0x00]
+ %define m12    [esp+0x10]
+ %define m10    [base+pd_0x3ff]
+ %define m8  m0
+ %xdefine m14 m4
+ %define m15 m3
+ %if isprep
+  %define ssq ssm
+ %endif
+    mov                  r4, [esp+0x1f0]
+    shr                  r4, 16
+    movd                m15, r4
+    mov                  r0, r0m
+    mov                 myd, mym
+%endif
+    sub                srcq, 6
+    pslld                m7, m8, 2 ; dx*4
+    pmaddwd              m8, [base+rescale_mul] ; dx*[0-3]
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+    mova        [stk+0x100], m7
+    mova        [stk+0x120], m15
+    mov         [stk+0x0f8], srcq
+    mov         [stk+0x130], r0q ; dstq / tmpq
+%if ARCH_X86_64 && UNIX64
+    mov                  hm, hd
+%elif ARCH_X86_32
+    mov                  r5, hm
+    mov         [stk+0x0f4], myd
+    mov         [stk+0x134], r5
+%endif
+    jmp .hloop
+.hloop_prep:
+    dec   dword [stk+0x0f0]
+    jz .ret
+%if ARCH_X86_64
+    add   qword [stk+0x130], 16
+    mov                  hd, hm
+%else
+    add   dword [stk+0x130], 16
+    mov                 myd, [stk+0x0f4]
+    mov                  r5, [stk+0x134]
+    mov                  r0, [stk+0x130]
+%endif
+    mova                 m7, [stk+0x100]
+    mova                m14, [stk+0x110]
+%if ARCH_X86_64
+    mova                m10, [base+pd_0x3ff]
+    mova                m11, [rsp+0x10]
+%endif
+    mova                m15, [stk+0x120]
+    mov                srcq, [stk+0x0f8]
+%if ARCH_X86_64
+    mov                 r0q, [stk+0x130] ; dstq / tmpq
+%else
+    mov                 mym, myd
+    mov                  hm, r5
+    mov                 r0m, r0
+    mov                  r3, r3m
+%endif
+    paddd               m14, m7
+.hloop:
+%if ARCH_X86_64
+    mova                 m9, [base+pq_0x40000000]
+%else
+ %define m9 [base+pq_0x40000000]
+%endif
+    pxor                 m1, m1
+    psrld                m2, m14, 10
+    mova              [stk], m2
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd                m5, m15, m6
+    pcmpeqd              m6, m1
+    pshufd               m2, m5, q1032
+%if ARCH_X86_64
+    movd                r4d, m5
+    movd                r6d, m2
+    pshufd               m5, m5, q0321
+    pshufd               m2, m2, q0321
+    movd                r7d, m5
+    movd                r9d, m2
+    movq                 m0, [base+subpel_filters+r4*8]
+    movq                 m1, [base+subpel_filters+r6*8]
+    movhps               m0, [base+subpel_filters+r7*8]
+    movhps               m1, [base+subpel_filters+r9*8]
+%else
+    movd                 r0, m5
+    movd                 rX, m2
+    pshufd               m5, m5, q0321
+    pshufd               m2, m2, q0321
+    movd                 r4, m5
+    movd                 r5, m2
+    movq                 m0, [base+subpel_filters+r0*8]
+    movq                 m1, [base+subpel_filters+rX*8]
+    movhps               m0, [base+subpel_filters+r4*8]
+    movhps               m1, [base+subpel_filters+r5*8]
+%endif
+    paddd               m14, m7 ; mx+dx*[4-7]
+    pand                 m5, m14, m10
+    psrld                m5, 6
+    paddd               m15, m5
+    pxor                 m2, m2
+    pcmpeqd              m5, m2
+    mova        [stk+0x110], m14
+    pshufd               m4, m15, q1032
+%if ARCH_X86_64
+    movd               r10d, m15
+    movd               r11d, m4
+    pshufd              m15, m15, q0321
+    pshufd               m4, m4, q0321
+    movd               r13d, m15
+    movd                rXd, m4
+    movq                 m2, [base+subpel_filters+r10*8]
+    movq                 m3, [base+subpel_filters+r11*8]
+    movhps               m2, [base+subpel_filters+r13*8]
+    movhps               m3, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    movq                r11, m14
+    punpckhqdq          m14, m14
+    movq                 rX, m14
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    mov                 r4d, [stk+ 0]
+    mov                 r6d, [stk+ 4]
+    mov                 r7d, [stk+ 8]
+    mov                 r9d, [stk+12]
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd              m14, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m7, m9, m4
+    pand                 m8, m9, m6
+    pand                m15, m9, m14
+    pand                 m9, m9, m5
+    pandn                m4, m0
+    pandn                m6, m1
+    pandn               m14, m2
+    pandn                m5, m3
+    por                  m7, m4
+    por                  m8, m6
+    por                 m15, m14
+    por                  m9, m5
+    punpcklbw            m0, m7, m7
+    punpckhbw            m7, m7
+    punpcklbw            m1, m8, m8
+    punpckhbw            m8, m8
+    psraw                m0, 8
+    psraw                m7, 8
+    psraw                m1, 8
+    psraw                m8, 8
+    punpcklbw            m2, m15, m15
+    punpckhbw           m15, m15
+    punpcklbw            m3, m9, m9
+    punpckhbw            m9, m9
+    psraw                m2, 8
+    psraw               m15, 8
+    psraw                m3, 8
+    psraw                m9, 8
+    mova         [stk+0x10], m0
+    mova         [stk+0x20], m7
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m8
+    mova         [stk+0x50], m2
+    mova         [stk+0x60], m15
+    mova         [stk+0x70], m3
+    mova         [stk+0x80], m9
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 9, 10 ; 0
+    mova         [stk+0x90], m1
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 1, 9, 10 ; 1
+    mova         [stk+0xa0], m2
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 1, 2, 9, 10 ; 2
+    mova         [stk+0xb0], m3
+    MC_8TAP_SCALED_H 4, 5, 6, 1, 2, 3, 9, 10 ; 3
+    mova         [stk+0xc0], m4
+    MC_8TAP_SCALED_H 5, 6, 1, 2, 3, 4, 9, 10 ; 4
+    mova         [stk+0xd0], m5
+    MC_8TAP_SCALED_H 6, 1, 2, 3, 4, 5, 9, 10 ; 5
+    MC_8TAP_SCALED_H 7, 1, 2, 3, 4, 5, 9, 10 ; 6
+    MC_8TAP_SCALED_H 8, 1, 2, 3, 4, 5, 9, 10 ; 7
+    mova                 m5, [stk+0xd0]
+    mova                 m1, [stk+0x90]
+    mova                 m2, [stk+0xa0]
+    mova                 m3, [stk+0xb0]
+    mova                 m9, [stk+0xc0]
+    mov                 myd, mym
+    mov                 dyd, dym
+    punpcklwd            m4, m5, m6 ; 45a
+    punpckhwd            m5, m6     ; 45b
+    punpcklwd            m6, m7, m8 ; 67a
+    punpckhwd            m7, m8     ; 67b
+    punpcklwd            m0, m1, m2 ; 01a
+    punpckhwd            m1, m2     ; 01b
+    punpcklwd            m2, m3, m9 ; 23a
+    punpckhwd            m3, m9     ; 23b
+    mova         [stk+0x90], m4
+    mova         [stk+0xa0], m5
+    mova         [stk+0xb0], m6
+    mova         [stk+0xc0], m7
+ %define hround [rsp+0x10]
+.vloop:
+    and                 myd, 0x3ff
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq                m11, r6q
+    punpcklbw           m11, m11
+    psraw               m11, 8
+    pshufd               m5, m11, q0000
+    pshufd               m7, m11, q1111
+    pshufd              m10, m11, q2222
+    pshufd              m11, m11, q3333
+    pmaddwd              m4, m5, m0
+    pmaddwd              m5, m5, m1
+    pmaddwd              m6, m7, m2
+    pmaddwd              m7, m7, m3
+    paddd                m4, m13
+    paddd                m5, m13
+    paddd                m4, m6
+    paddd                m5, m7
+    pmaddwd              m6, [stk+0x90], m10
+    pmaddwd              m7, [stk+0xa0], m10
+    pmaddwd              m8, [stk+0xb0], m11
+    pmaddwd              m9, [stk+0xc0], m11
+    paddd                m4, m6
+    paddd                m5, m7
+ %if isput
+    pshufd               m6, m12, q1032
+ %endif
+    paddd                m4, m8
+    paddd                m5, m9
+%else
+    movd                 r0, m15
+    movd                 rX, m4
+    pshufd              m15, m15, q0321
+    pshufd               m4, m4, q0321
+    movd                 r4, m15
+    movd                 r5, m4
+    mova                m14, [stk+0x110]
+    movq                 m2, [base+subpel_filters+r0*8]
+    movq                 m3, [base+subpel_filters+rX*8]
+    movhps               m2, [base+subpel_filters+r4*8]
+    movhps               m3, [base+subpel_filters+r5*8]
+    psrld               m14, 10
+    mova           [stk+16], m14
+    mov                  r0, [stk+ 0]
+    mov                  rX, [stk+ 4]
+    mov                  r4, [stk+ 8]
+    mov                  r5, [stk+12]
+    mova         [stk+0x20], m0
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd               m7, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m0, m9, m4
+    pand                 m1, m9, m6
+    pand                 m2, m9, m7
+    pand                 m3, m9, m5
+    pandn                m4, [stk+0x20]
+    pandn                m6, [stk+0x30]
+    pandn                m7, [stk+0x40]
+    pandn                m5, [stk+0x50]
+    por                  m0, m4
+    por                  m1, m6
+    por                  m2, m7
+    por                  m3, m5
+    punpcklbw            m4, m0, m0
+    punpckhbw            m0, m0
+    punpcklbw            m5, m1, m1
+    punpckhbw            m1, m1
+    psraw                m4, 8
+    psraw                m0, 8
+    psraw                m5, 8
+    psraw                m1, 8
+    punpcklbw            m6, m2, m2
+    punpckhbw            m2, m2
+    punpcklbw            m7, m3, m3
+    punpckhbw            m3, m3
+    psraw                m6, 8
+    psraw                m2, 8
+    psraw                m7, 8
+    psraw                m3, 8
+    mova        [stk+0x0a0], m4
+    mova        [stk+0x0b0], m0
+    mova        [stk+0x0c0], m5
+    mova        [stk+0x0d0], m1
+    mova        [stk+0x140], m6
+    mova        [stk+0x150], m2
+    mova        [stk+0x160], m7
+    mova        [stk+0x170], m3
+    MC_8TAP_SCALED_H   0xa0, 0x20, 0 ; 0
+    MC_8TAP_SCALED_H   0xa0, 0x30    ; 1
+    MC_8TAP_SCALED_H   0xa0, 0x40    ; 2
+    MC_8TAP_SCALED_H   0xa0, 0x50    ; 3
+    MC_8TAP_SCALED_H   0xa0, 0x60    ; 4
+    MC_8TAP_SCALED_H   0xa0, 0x70    ; 5
+    MC_8TAP_SCALED_H   0xa0, 0x80    ; 6
+    MC_8TAP_SCALED_H   0xa0, 0x90    ; 7
+    mova                 m5, [stk+0x60]
+    mova                 m6, [stk+0x70]
+    mova                 m7, [stk+0x80]
+    mova                 m0, [stk+0x90]
+    mov                 myd, mym
+    punpcklwd            m4, m5, m6      ; 45a
+    punpckhwd            m5, m6          ; 45b
+    punpcklwd            m6, m7, m0      ; 67a
+    punpckhwd            m7, m0          ; 67b
+    mova         [stk+0x60], m4
+    mova         [stk+0x70], m5
+    mova         [stk+0x80], m6
+    mova         [stk+0x90], m7
+    mova                 m1, [stk+0x20]
+    mova                 m2, [stk+0x30]
+    mova                 m3, [stk+0x40]
+    mova                 m4, [stk+0x50]
+    punpcklwd            m0, m1, m2      ; 01a
+    punpckhwd            m1, m2          ; 01b
+    punpcklwd            m2, m3, m4      ; 23a
+    punpckhwd            m3, m4          ; 23b
+    mova         [stk+0x20], m0
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+.vloop:
+    mov                  r0, r0m
+    mov                  r5, [esp+0x1f4]
+    and                 myd, 0x3ff
+    mov                 mym, myd
+    xor                  r3, r3
+    shr                  r4, 6
+    lea                  r5, [r5+r4]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r5*8+0]
+    cmovnz               r3, [base+subpel_filters+r5*8+4]
+    movd                 m7, r4
+    movd                 m6, r3
+    punpckldq            m7, m6
+    punpcklbw            m7, m7
+    psraw                m7, 8
+    pshufd               m4, m7, q0000
+    pshufd               m5, m7, q1111
+    pmaddwd              m0, m4
+    pmaddwd              m1, m4
+    pmaddwd              m2, m5
+    pmaddwd              m3, m5
+    pshufd               m6, m7, q2222
+    pshufd               m7, m7, q3333
+    paddd                m0, m2
+    paddd                m1, m3
+    pmaddwd              m2, [stk+0x60], m6
+    pmaddwd              m3, [stk+0x70], m6
+    pmaddwd              m4, [stk+0x80], m7
+    pmaddwd              m5, [stk+0x90], m7
+ %if isput
+    movd                 m6, [esp+0x18]
+ %endif
+    paddd                m0, m2
+    paddd                m1, m3
+    paddd                m0, vrnd_mem
+    paddd                m1, vrnd_mem
+    paddd                m4, m0
+    paddd                m5, m1
+%endif
+%ifidn %1, put
+    psrad                m4, m6
+    psrad                m5, m6
+    packssdw             m4, m5
+    pxor                 m7, m7
+    pmaxsw               m4, m7
+    pminsw               m4, pxmaxm
+    mova             [dstq], m4
+    add                dstq, dsm
+%else
+    psrad                m4, 6
+    psrad                m5, 6
+    packssdw             m4, m5
+    mova             [tmpq], m4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .hloop_prep
+%if ARCH_X86_64
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .vloop
+    test                myd, 0x400
+    mov         [stk+0x140], myd
+    mov                 r4d, [stk+ 0]
+    mov                 r6d, [stk+ 4]
+    mov                 r7d, [stk+ 8]
+    mov                 r9d, [stk+12]
+    jz .skip_line
+    mova                m14, [base+unpckw]
+    movu                 m8, [srcq+r10*2]
+    movu                 m9, [srcq+r11*2]
+    movu                m10, [srcq+r13*2]
+    movu                m11, [srcq+ rX*2]
+    movu                 m4, [srcq+ r4*2]
+    movu                 m5, [srcq+ r6*2]
+    movu                 m6, [srcq+ r7*2]
+    movu                 m7, [srcq+ r9*2]
+    add                srcq, ssq
+    mov                 myd, [stk+0x140]
+    mov                 dyd, dym
+    pshufd              m15, m14, q1032
+    pshufb               m0, m14                ; 0a 1a
+    pshufb               m1, m14                ; 0b 1b
+    pshufb               m2, m15                ; 3a 2a
+    pshufb               m3, m15                ; 3b 2b
+    pmaddwd              m8, [stk+0x50]
+    pmaddwd              m9, [stk+0x60]
+    pmaddwd             m10, [stk+0x70]
+    pmaddwd             m11, [stk+0x80]
+    pmaddwd              m4, [stk+0x10]
+    pmaddwd              m5, [stk+0x20]
+    pmaddwd              m6, [stk+0x30]
+    pmaddwd              m7, [stk+0x40]
+    phaddd               m8, m9
+    phaddd              m10, m11
+    mova                m11, hround
+    phaddd               m4, m5
+    phaddd               m6, m7
+    phaddd               m8, m10
+    phaddd               m4, m6
+    paddd                m4, m11
+    paddd                m8, m11
+    psrad                m4, m12
+    psrad                m8, m12
+    packssdw             m4, m8
+    pshufb               m5, [stk+0x90], m14    ; 4a 5a
+    pshufb               m6, [stk+0xa0], m14    ; 4b 5b
+    pshufb               m7, [stk+0xb0], m15    ; 7a 6a
+    pshufb               m8, [stk+0xc0], m15    ; 7b 6b
+    punpckhwd            m0, m2 ; 12a
+    punpckhwd            m1, m3 ; 12b
+    punpcklwd            m2, m5 ; 34a
+    punpcklwd            m3, m6 ; 34b
+    punpckhwd            m5, m7 ; 56a
+    punpckhwd            m6, m8 ; 56b
+    punpcklwd            m7, m4 ; 78a
+    punpckhqdq           m4, m4
+    punpcklwd            m8, m4 ; 78b
+    mova         [stk+0x90], m5
+    mova         [stk+0xa0], m6
+    mova         [stk+0xb0], m7
+    mova         [stk+0xc0], m8
+    jmp .vloop
+.skip_line:
+    MC_8TAP_SCALED_H 4, 8, 5, 6, 7, 9, 10, 11
+    MC_8TAP_SCALED_H 8, 5, 6, 7, 9, 0, 10, 11
+    mov                 myd, [stk+0x140]
+    mov                 dyd, dym
+    mova                 m0, m2         ; 01a
+    mova                 m1, m3         ; 01b
+    mova                 m2, [stk+0x90] ; 23a
+    mova                 m3, [stk+0xa0] ; 23b
+    mova                 m5, [stk+0xb0] ; 45a
+    mova                 m6, [stk+0xc0] ; 45b
+    punpcklwd            m7, m4, m8     ; 67a
+    punpckhwd            m4, m8         ; 67b
+    mova         [stk+0x90], m5
+    mova         [stk+0xa0], m6
+    mova         [stk+0xb0], m7
+    mova         [stk+0xc0], m4
+%else
+    mov                 r0m, r0
+    mov                 myd, mym
+    mov                  r3, r3m
+    add                 myd, dym
+    test                myd, ~0x3ff
+    mov                 mym, myd
+    jnz .next_line
+    mova                 m0, [stk+0x20]
+    mova                 m1, [stk+0x30]
+    mova                 m2, [stk+0x40]
+    mova                 m3, [stk+0x50]
+    jmp .vloop
+.next_line:
+    test                myd, 0x400
+    mov                  r0, [stk+ 0]
+    mov                  rX, [stk+ 4]
+    mov                  r4, [stk+ 8]
+    mov                  r5, [stk+12]
+    jz .skip_line
+    MC_8TAP_SCALED_H 0xa0, 0xe0, 0 ; 8
+    mova                 m7, [base+unpckw]
+    pshufd               m4, m7, q1032
+    pshufb               m0, [stk+0x20], m7 ; 0a 1a
+    pshufb               m1, [stk+0x30], m7 ; 0b 1b
+    pshufb               m2, [stk+0x40], m4 ; 3a 2a
+    pshufb               m3, [stk+0x50], m4 ; 3b 2b
+    pshufb               m5, [stk+0x60], m7 ; 4a 5a
+    pshufb               m6, [stk+0x70], m7 ; 4b 5b
+    pshufb               m7, [stk+0x80], m4 ; 7a 6a
+    punpckhwd            m0, m2 ; 12a
+    punpckhwd            m1, m3 ; 12b
+    punpcklwd            m2, m5 ; 34a
+    punpcklwd            m3, m6 ; 34b
+    mova         [stk+0x20], m0
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+    punpckhwd            m5, m7 ; 56a
+    mova         [stk+0x60], m5
+    pshufb               m5, [stk+0x90], m4 ; 7b 6b
+    punpcklwd            m7, [stk+0xe0] ; 78a
+    punpckhwd            m6, m5 ; 56b
+    mova         [stk+0x70], m6
+    movq                 m6, [stk+0xe8]
+    mova         [stk+0x80], m7
+    punpcklwd            m5, m6
+    mov                 myd, mym
+    mova         [stk+0x90], m5
+    jmp .vloop
+.skip_line:
+    MC_8TAP_SCALED_H 0xa0, 0xe0, 0 ; 8
+    MC_8TAP_SCALED_H 0xa0, 0       ; 9
+    mova                 m7, [stk+0xe0]
+    mova                 m2, [stk+0x60] ; 23a
+    mova                 m3, [stk+0x70] ; 23b
+    mova                 m4, [stk+0x80] ; 45a
+    mova                 m5, [stk+0x90] ; 45b
+    punpcklwd            m6, m7, m0     ; 67a
+    punpckhwd            m7, m0         ; 67b
+    mova                 m0, [stk+0x40] ; 01a
+    mova                 m1, [stk+0x50] ; 01b
+    mov                 myd, mym
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+    mova         [stk+0x60], m4
+    mova         [stk+0x70], m5
+    mova         [stk+0x80], m6
+    mova         [stk+0x90], m7
+    mova         [stk+0x20], m0
+    mova         [stk+0x30], m1
+%endif
+    jmp .vloop
+INIT_XMM ssse3
+.dy1:
+    movzx                wd, word [base+%1_8tap_scaled_ssse3_dy1_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%if isput
+.dy1_w2:
+ %if ARCH_X86_64
+    mov                 myd, mym
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd                m15, t0d
+ %else
+  %define m8  m0
+  %define m9  m1
+  %define m14 m4
+  %define m15 m3
+  %define m11 [esp+0x00]
+  %define m12 [esp+0x10]
+  %define m13 [esp+0x20]
+    movzx                r5, byte [esp+0x1f0]
+    sub                srcq, 2
+    movd                m15, r5
+    mov                  r1, r1m
+ %endif
+    pxor                 m9, m9
+    punpckldq            m9, m8
+    paddd               m14, m9 ; mx+dx*[0-1]
+ %if ARCH_X86_64
+    mova                 m9, [base+pd_0x4000]
+ %endif
+    pshufd              m15, m15, q0000
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd               m15, m8
+    movd                r4d, m15
+    pshufd              m15, m15, q0321
+ %if ARCH_X86_64
+    movd                r6d, m15
+ %else
+    movd                r3d, m15
+ %endif
+    mova                 m5, [base+bdct_lb_q]
+    mova                 m6, [base+spel_s_shuf2]
+    movd                m15, [base+subpel_filters+r4*8+2]
+ %if ARCH_X86_64
+    movd                 m7, [base+subpel_filters+r6*8+2]
+ %else
+    movd                 m7, [base+subpel_filters+r3*8+2]
+ %endif
+    pxor                 m2, m2
+    pcmpeqd              m8, m2
+    psrld               m14, 10
+    paddd               m14, m14
+ %if ARCH_X86_32
+    mov                  r3, r3m
+    pshufb              m14, m5
+    paddb               m14, m6
+    mova              [stk], m14
+    SWAP                 m5, m0
+    SWAP                 m6, m3
+  %define m15 m6
+ %endif
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    movu                 m2, [srcq+ssq*2]
+    movu                 m3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    punpckldq           m15, m7
+ %if ARCH_X86_64
+    pshufb              m14, m5
+    paddb               m14, m6
+    pand                 m9, m8
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m9
+    movu                 m4, [srcq+ssq*0]
+    movu                 m5, [srcq+ssq*1]
+    movu                 m6, [srcq+ssq*2]
+    add                srcq, ss3q
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+ %else
+    pand                 m7, m5, [base+pd_0x4000]
+    pandn                m5, m15
+    por                  m5, m7
+  %define m15 m5
+    mov                 myd, mym
+    mov                  r5, [esp+0x1f4]
+    xor                  r3, r3
+    shr                 myd, 6
+    lea                  r5, [r5+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r5*8+0]
+    cmovnz               r3, [base+subpel_filters+r5*8+4]
+    mov          [stk+0x20], r3
+    mov                  r3, r3m
+ %endif
+    punpcklbw           m15, m15
+    psraw               m15, 8
+    REPX    {pshufb x, m14}, m0, m1, m2, m3
+    REPX   {pmaddwd x, m15}, m0, m1, m2, m3
+ %if ARCH_X86_64
+    REPX    {pshufb x, m14}, m4, m5, m6
+    REPX   {pmaddwd x, m15}, m4, m5, m6
+    phaddd               m0, m1
+    phaddd               m2, m3
+    phaddd               m4, m5
+    phaddd               m6, m6
+    REPX     {paddd x, m11}, m0, m2, m4, m6
+    REPX     {psrad x, m12}, m0, m2, m4, m6
+    packssdw             m0, m2 ; 0 1 2 3
+    packssdw             m4, m6 ; 4 5 6
+    SWAP                 m1, m4
+    movq                m10, r4
+ %else
+    mova         [stk+0x10], m15
+    phaddd               m0, m1
+    phaddd               m2, m3
+    movu                 m1, [srcq+ssq*0]
+    movu                 m7, [srcq+ssq*1]
+    movu                 m6, [srcq+ssq*2]
+    add                srcq, ss3q
+    REPX    {pshufb x, m14}, m1, m7, m6
+    REPX   {pmaddwd x, m15}, m1, m7, m6
+  %define m14 [stk+0x00]
+  %define m15 [stk+0x10]
+    phaddd               m1, m7
+    phaddd               m6, m6
+    REPX     {paddd x, m11}, m0, m2, m1, m6
+    REPX     {psrad x, m12}, m0, m2, m1, m6
+    packssdw             m0, m2
+    packssdw             m1, m6
+  %define m8  m6
+  %define m9  m4
+  %define m10 m5
+    movd                m10, r4
+    movd                 m9, [stk+0x20]
+    punpckldq           m10, m9
+ %endif
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    pshufd               m7, m10, q0000
+    pshufd               m8, m10, q1111
+    pshufd               m9, m10, q2222
+    pshufd              m10, m10, q3333
+ %if ARCH_X86_32
+    mova         [stk+0x50], m7
+    mova         [stk+0x60], m8
+    mova         [stk+0x70], m9
+    mova         [stk+0x80], m10
+  %define m7  [stk+0x50]
+  %define m8  [stk+0x60]
+  %define m9  [stk+0x70]
+  %define m10 [stk+0x80]
+ %endif
+    palignr              m2, m1, m0, 4 ; 1 2 3 4
+    punpcklwd            m3, m0, m2    ; 01 12
+    punpckhwd            m0, m2        ; 23 34
+    pshufd               m4, m1, q2121 ; 5 6 5 6
+    punpcklwd            m2, m1, m4    ; 45 56
+ %if ARCH_X86_32
+    mov                  r0, r0m
+ %endif
+.dy1_w2_loop:
+    movu                 m1, [srcq+ssq*0]
+    movu                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m5, m3, m7
+    mova                 m3, m0
+    pmaddwd              m0, m8
+    pshufb               m1, m14
+    pshufb               m6, m14
+    pmaddwd              m1, m15
+    pmaddwd              m6, m15
+    phaddd               m1, m6
+    paddd                m1, m11
+    psrad                m1, m12
+    packssdw             m1, m1
+    paddd                m5, m0
+    mova                 m0, m2
+    pmaddwd              m2, m9
+    paddd                m5, m2
+    palignr              m2, m1, m4, 12
+    punpcklwd            m2, m1        ; 67 78
+    pmaddwd              m4, m2, m10
+    paddd                m5, m13
+    paddd                m5, m4
+    pxor                 m6, m6
+    mova                 m4, m1
+    pshufd               m1, m12, q1032
+    psrad                m5, m1
+    packssdw             m5, m5
+    pmaxsw               m5, m6
+    pminsw               m5, pxmaxm
+    movd       [dstq+dsq*0], m5
+    pshuflw              m5, m5, q1032
+    movd       [dstq+dsq*1], m5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .dy1_w2_loop
+    RET
+%endif
+INIT_XMM ssse3
+.dy1_w4:
+%if ARCH_X86_64
+    mov                 myd, mym
+    mova         [rsp+0x10], m11
+    mova         [rsp+0x20], m12
+ %if isput
+    mova         [rsp+0x30], m13
+  %define vrnd_mem [rsp+0x30]
+  %define stk rsp+0x40
+ %else
+  %define vrnd_mem [base+pd_m524256]
+  %define stk rsp+0x30
+ %endif
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd                m15, t0d
+%else
+ %define m10 [base+pd_0x3ff]
+ %define m9  [base+pd_0x4000]
+ %define m8  m0
+ %xdefine m14 m4
+ %define m15 m3
+ %if isprep
+  %define ssq r3
+ %endif
+    movzx                r5, byte [esp+0x1f0]
+    sub                srcq, 2
+    movd                m15, r5
+%endif
+    pmaddwd              m8, [base+rescale_mul]
+%if ARCH_X86_64
+    mova                 m9, [base+pd_0x4000]
+%endif
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m0, m14, m10
+    psrld                m0, 6
+    paddd               m15, m0
+    pshufd               m7, m15, q1032
+%if ARCH_X86_64
+    movd                r4d, m15
+    movd               r11d, m7
+    pshufd              m15, m15, q0321
+    pshufd               m7, m7, q0321
+    movd                r6d, m15
+    movd               r13d, m7
+    mova                m10, [base+bdct_lb_q+ 0]
+    mova                m11, [base+bdct_lb_q+16]
+    movd                m13, [base+subpel_filters+ r4*8+2]
+    movd                 m2, [base+subpel_filters+ r6*8+2]
+    movd                m15, [base+subpel_filters+r11*8+2]
+    movd                 m4, [base+subpel_filters+r13*8+2]
+%else
+    movd                 r0, m15
+    movd                 r4, m7
+    pshufd              m15, m15, q0321
+    pshufd               m7, m7, q0321
+    movd                 rX, m15
+    movd                 r5, m7
+    mova                 m5, [base+bdct_lb_q+ 0]
+    mova                 m6, [base+bdct_lb_q+16]
+    movd                 m1, [base+subpel_filters+r0*8+2]
+    movd                 m2, [base+subpel_filters+rX*8+2]
+    movd                 m3, [base+subpel_filters+r4*8+2]
+    movd                 m7, [base+subpel_filters+r5*8+2]
+    SWAP                 m4, m7
+ %if isprep
+    mov                  r3, r3m
+ %endif
+ %define m10 m5
+ %define m11 m6
+ %define m12 m1
+ %define m13 m1
+%endif
+    psrld               m14, 10
+    paddd               m14, m14
+    punpckldq           m13, m2
+    punpckldq           m15, m4
+    punpcklqdq          m13, m15
+    pxor                 m2, m2
+    pcmpeqd              m0, m2
+%if ARCH_X86_64
+    pand                 m9, m0
+%else
+    pand                 m2, m9, m0
+ %define m9 m2
+    SWAP                 m7, m4
+%endif
+    pandn                m0, m13
+%if ARCH_X86_64
+    SWAP                m13, m0
+%else
+ %define m13 m0
+%endif
+    por                 m13, m9
+    punpckhbw           m15, m13, m13
+    punpcklbw           m13, m13
+    psraw               m15, 8
+    psraw               m13, 8
+    pshufb              m12, m14, m10
+    pshufb              m14, m11
+    mova                m10, [base+spel_s_shuf2]
+    movd                r4d, m14
+    shr                 r4d, 24
+%if ARCH_X86_32
+    mova         [stk+0x40], m13
+    mova         [stk+0x50], m15
+    pxor                 m2, m2
+%endif
+    pshufb               m7, m14, m2
+    psubb               m14, m7
+    paddb               m12, m10
+    paddb               m14, m10
+%if ARCH_X86_64
+    lea                  r6, [r4+ssq*1]
+    lea                 r11, [r4+ssq*2]
+    lea                 r13, [r4+ss3q ]
+    movu                 m7, [srcq+ssq*0]
+    movu                 m9, [srcq+ssq*1]
+    movu                 m8, [srcq+ssq*2]
+    movu                m10, [srcq+ss3q ]
+    movu                 m1, [srcq+r4   ]
+    movu                 m3, [srcq+r6   ]
+    movu                 m2, [srcq+r11  ]
+    movu                 m4, [srcq+r13  ]
+    lea                srcq, [srcq+ssq*4]
+    REPX    {pshufb x, m12}, m7, m9, m8, m10
+    REPX   {pmaddwd x, m13}, m7, m9, m8, m10
+    REPX    {pshufb x, m14}, m1, m3, m2, m4
+    REPX   {pmaddwd x, m15}, m1, m3, m2, m4
+    mova                 m5, [rsp+0x10]
+    movd                xm6, [rsp+0x20]
+    phaddd               m7, m1
+    phaddd               m9, m3
+    phaddd               m8, m2
+    phaddd              m10, m4
+    movu                 m1, [srcq+ssq*0]
+    movu                 m2, [srcq+ssq*1]
+    movu                 m3, [srcq+ssq*2]
+    REPX      {paddd x, m5}, m7, m9, m8, m10
+    REPX     {psrad x, xm6}, m7, m9, m8, m10
+    packssdw             m7, m9  ; 0 1
+    packssdw             m8, m10 ; 2 3
+    movu                 m0, [srcq+r4   ]
+    movu                 m9, [srcq+r6   ]
+    movu                m10, [srcq+r11  ]
+    add                srcq, ss3q
+    REPX    {pshufb x, m12}, m1, m2, m3
+    REPX   {pmaddwd x, m13}, m1, m2, m3
+    REPX    {pshufb x, m14}, m0, m9, m10
+    REPX   {pmaddwd x, m15}, m0, m9, m10
+    phaddd               m1, m0
+    phaddd               m2, m9
+    phaddd               m3, m10
+    shr                 myd, 6
+    mov                r13d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz             r13q, [base+subpel_filters+myq*8]
+    REPX      {paddd x, m5}, m1, m2, m3
+    REPX     {psrad x, xm6}, m1, m2, m3
+    packssdw             m1, m2 ; 4 5
+    packssdw             m3, m3 ; 6 6
+    SWAP                 m9, m1
+    shufps               m4, m7, m8, q1032  ; 1 2
+    shufps               m5, m8, m9, q1032  ; 3 4
+    shufps               m6, m9, m3, q1032  ; 5 6
+    punpcklwd            m0, m7, m4 ; 01
+    punpckhwd            m7, m4     ; 12
+    punpcklwd            m1, m8, m5 ; 23
+    punpckhwd            m8, m5     ; 34
+    punpcklwd            m2, m9, m6 ; 45
+    punpckhwd            m9, m6     ; 56
+    movq                m10, r13
+    mova         [stk+0x00], m1
+    mova         [stk+0x10], m8
+    mova         [stk+0x20], m2
+    mova         [stk+0x30], m9
+    mova         [stk+0x40], m3
+ %define hrnd_mem [rsp+0x10]
+ %define hsh_mem  [rsp+0x20]
+ %define vsh_mem  [rsp+0x28]
+ %if isput
+  %define vrnd_mem [rsp+0x30]
+ %else
+  %define vrnd_mem [base+pd_m524256]
+ %endif
+%else
+    mova         [stk+0x20], m12
+    mova         [stk+0x30], m14
+    add                  r4, srcq
+    MC_4TAP_SCALED_H   0x60 ; 0 1
+    MC_4TAP_SCALED_H   0x70 ; 2 3
+    MC_4TAP_SCALED_H   0x80 ; 4 5
+    movu                 m7, [srcq]
+    movu                 m2, [r4]
+    add                srcq, ssq
+    add                  r4, ssq
+    mov          [stk+0xb0], r4
+    pshufb               m7, m12
+    pshufb               m2, m14
+    pmaddwd              m7, m13
+    pmaddwd              m2, m15
+    phaddd               m7, m2
+    paddd                m7, [esp+0x00]
+    psrad                m7, [esp+0x10]
+    packssdw             m7, m7 ; 6 6
+    mova                 m4, [stk+0x60]
+    mova                 m5, [stk+0x70]
+    mova                 m6, [stk+0x80]
+    mov                 myd, mym
+    mov                  rX, [esp+0x1f4]
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  rX, [rX+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+rX*8+0]
+    cmovnz               r5, [base+subpel_filters+rX*8+4]
+    mov                  r3, r3m
+    shufps               m1, m4, m5, q1032 ; 1 2
+    shufps               m2, m5, m6, q1032 ; 3 4
+    shufps               m3, m6, m7, q1032 ; 5 6
+    mova         [stk+0xa0], m7
+    punpcklwd            m0, m4, m1         ; 01
+    punpckhwd            m4, m1             ; 12
+    punpcklwd            m1, m5, m2         ; 23
+    punpckhwd            m5, m2             ; 34
+    punpcklwd            m2, m6, m3         ; 45
+    punpckhwd            m6, m3             ; 56
+    movd                 m7, r4
+    movd                 m3, r5
+    mov                  r0, r0m
+ %if isput
+    mov                  r1, r1m
+ %endif
+    mov                  r4, [stk+0xb0]
+    mova         [stk+0xc0], m4 ; 12
+    mova         [stk+0x60], m1 ; 23
+    mova         [stk+0x70], m2 ; 45
+    mova         [stk+0x80], m5 ; 34
+    mova         [stk+0x90], m6 ; 56
+ %define m12 [stk+0x20]
+ %define m14 [stk+0x30]
+ %define m13 [stk+0x40]
+ %define m15 [stk+0x50]
+ %define hrnd_mem [esp+0x00]
+ %define hsh_mem  [esp+0x10]
+ %define vsh_mem  [esp+0x18]
+ %if isput
+  %define vrnd_mem [esp+0x20]
+ %else
+  %define vrnd_mem [base+pd_m524256]
+ %endif
+ %define m10 m7
+    punpckldq           m10, m3
+%endif
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    pshufd               m3, m10, q0000
+    pshufd               m4, m10, q1111
+    pshufd               m5, m10, q2222
+    pshufd              m10, m10, q3333
+%if ARCH_X86_32
+ %xdefine m8  m3
+ %xdefine m9  m6
+ %xdefine m11 m5
+ %xdefine m6  m4
+    mova         [stk+0x100], m3
+    mova         [stk+0x110], m4
+    mova         [stk+0x120], m5
+    mova         [stk+0x130], m10
+ %define m3  [stk+0x100]
+ %define m4  [stk+0x110]
+ %define m5  [stk+0x120]
+ %define m10 [stk+0x130]
+    mova                 m7, [stk+0xc0]
+    mova                 m8, [stk+0x80]
+%endif
+.dy1_w4_loop:
+    movu                m11, [srcq+ssq*0]
+    movu                 m6, [srcq+ssq*1]
+    pmaddwd              m0, m3
+    pmaddwd              m7, m3
+    pmaddwd              m1, m4
+    pmaddwd              m8, m4
+    pmaddwd              m2, m5
+    pmaddwd              m9, m5
+    paddd                m1, m0
+    paddd                m8, m7
+%if ARCH_X86_64
+    movu                 m0, [srcq+r4]
+    movu                 m7, [srcq+r6]
+%else
+    movu                 m0, [r4+ssq*0]
+    movu                 m7, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+%endif
+    lea                srcq, [srcq+ssq*2]
+    paddd                m1, m2
+    paddd                m8, m9
+    pshufb              m11, m12
+    pshufb               m6, m12
+    pmaddwd             m11, m13
+    pmaddwd              m6, m13
+    pshufb               m0, m14
+    pshufb               m7, m14
+    pmaddwd              m0, m15
+    pmaddwd              m7, m15
+    phaddd              m11, m0
+    phaddd               m6, m7
+    paddd               m11, hrnd_mem
+    paddd                m6, hrnd_mem
+    psrad               m11, hsh_mem
+    psrad                m6, hsh_mem
+    packssdw            m11, m6                     ; 7 8
+%if ARCH_X86_64
+    shufps               m9, [stk+0x40], m11, q1032 ; 6 7
+    mova                 m0, [stk+0x00]
+    mova         [stk+0x40], m11
+%else
+    shufps               m9, [stk+0xa0], m11, q1032 ; 6 7
+    mova                 m0, [stk+0x60]
+    mova         [stk+0xa0], m11
+%endif
+    punpcklwd            m2, m9, m11 ; 67
+    punpckhwd            m9, m11     ; 78
+    pmaddwd              m6, m2, m10
+    pmaddwd              m7, m9, m10
+%if isput
+    movd                m11, vsh_mem
+%endif
+    paddd                m1, vrnd_mem
+    paddd                m8, vrnd_mem
+    paddd                m1, m6
+    paddd                m8, m7
+%if ARCH_X86_64
+    mova                 m7, [stk+0x10]
+%else
+    mova                 m7, [stk+0x80]
+%endif
+%if isput
+    psrad                m1, m11
+    psrad                m8, m11
+%else
+    psrad                m1, 6
+    psrad                m8, 6
+%endif
+    packssdw             m1, m8
+%if ARCH_X86_64
+    mova                 m8, [stk+0x30]
+%else
+    mova                 m8, [stk+0x90]
+%endif
+%if isput
+    pxor                 m6, m6
+    pmaxsw               m1, m6
+    pminsw               m1, pxmaxm
+    movq       [dstq+dsq*0], m1
+    movhps     [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+%else
+    mova             [tmpq], m1
+    add                tmpq, 16
+%endif
+%if ARCH_X86_64
+    mova                 m1, [stk+0x20]
+    mova         [stk+0x10], m8
+    mova         [stk+0x00], m1
+    mova         [stk+0x20], m2
+    mova         [stk+0x30], m9
+%else
+    mova                 m1, [stk+0x70]
+    mova         [stk+0x80], m8
+    mova         [stk+0x60], m1
+    mova         [stk+0x70], m2
+    mova         [stk+0x90], m9
+%endif
+    sub                  hd, 2
+    jg .dy1_w4_loop
+    MC_8TAP_SCALED_RET ; why not jz .ret?
+INIT_XMM ssse3
+.dy1_w8:
+    mov    dword [stk+0xf0], 1
+    movifprep   tmp_stridem, 16
+    jmp .dy1_w_start
+.dy1_w16:
+    mov    dword [stk+0xf0], 2
+    movifprep   tmp_stridem, 32
+    jmp .dy1_w_start
+.dy1_w32:
+    mov    dword [stk+0xf0], 4
+    movifprep   tmp_stridem, 64
+    jmp .dy1_w_start
+.dy1_w64:
+    mov    dword [stk+0xf0], 8
+    movifprep   tmp_stridem, 128
+    jmp .dy1_w_start
+.dy1_w128:
+    mov    dword [stk+0xf0], 16
+    movifprep   tmp_stridem, 256
+.dy1_w_start:
+    mov                 myd, mym
+%if ARCH_X86_64
+ %ifidn %1, put
+    movifnidn           dsm, dsq
+ %endif
+    mova         [rsp+0x10], m11
+    mova         [rsp+0x20], m12
+ %define hround m11
+ %if isput
+    mova         [rsp+0x30], m13
+ %else
+    mova                m13, [base+pd_m524256]
+ %endif
+    shr                 t0d, 16
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    movd                m15, t0d
+%else
+ %define hround [esp+0x00]
+ %define m12    [esp+0x10]
+ %define m10    [base+pd_0x3ff]
+ %define m8  m0
+ %xdefine m14 m4
+ %xdefine m15 m3
+ %if isprep
+  %define ssq ssm
+ %endif
+    mov                  r5, [esp+0x1f0]
+    mov                  r3, [esp+0x1f4]
+    shr                  r5, 16
+    movd                m15, r5
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  r3, [r3+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r3*8+0]
+    cmovnz               r5, [base+subpel_filters+r3*8+4]
+    mov                  r0, r0m
+    mov                  r3, r3m
+%endif
+    sub                srcq, 6
+    pslld                m7, m8, 2 ; dx*4
+    pmaddwd              m8, [base+rescale_mul] ; dx*[0-3]
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+%if ARCH_X86_64
+    movq                 m3, r4q
+%else
+    movd                 m5, r4
+    movd                 m6, r5
+    punpckldq            m5, m6
+    SWAP                 m3, m5
+%endif
+    punpcklbw            m3, m3
+    psraw                m3, 8
+    mova        [stk+0x100], m7
+    mova        [stk+0x120], m15
+    mov         [stk+0x0f8], srcq
+    mov         [stk+0x130], r0q ; dstq / tmpq
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+%if ARCH_X86_64
+    mova        [stk+0x140], m0
+    mova        [stk+0x150], m1
+    mova        [stk+0x160], m2
+    mova        [stk+0x170], m3
+ %if UNIX64
+    mov                  hm, hd
+ %endif
+%else
+    mova        [stk+0x180], m0
+    mova        [stk+0x190], m1
+    mova        [stk+0x1a0], m2
+    mova        [stk+0x1b0], m3
+    SWAP                 m5, m3
+    mov                  r5, hm
+    mov         [stk+0x134], r5
+%endif
+    jmp .dy1_hloop
+.dy1_hloop_prep:
+    dec   dword [stk+0x0f0]
+    jz .ret
+%if ARCH_X86_64
+    add   qword [stk+0x130], 16
+    mov                  hd, hm
+%else
+    add   dword [stk+0x130], 16
+    mov                  r5, [stk+0x134]
+    mov                  r0, [stk+0x130]
+%endif
+    mova                 m7, [stk+0x100]
+    mova                m14, [stk+0x110]
+%if ARCH_X86_64
+    mova                m10, [base+pd_0x3ff]
+    mova                m11, [rsp+0x10]
+%endif
+    mova                m15, [stk+0x120]
+    mov                srcq, [stk+0x0f8]
+%if ARCH_X86_64
+    mov                 r0q, [stk+0x130] ; dstq / tmpq
+%else
+    mov                  hm, r5
+    mov                 r0m, r0
+    mov                  r3, r3m
+%endif
+    paddd               m14, m7
+.dy1_hloop:
+%if ARCH_X86_64
+    mova                 m9, [base+pq_0x40000000]
+%else
+ %define m9 [base+pq_0x40000000]
+%endif
+    pxor                 m1, m1
+    psrld                m2, m14, 10
+    mova              [stk], m2
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd                m5, m15, m6
+    pcmpeqd              m6, m1
+    pshufd               m2, m5, q1032
+%if ARCH_X86_64
+    movd                r4d, m5
+    movd                r6d, m2
+    pshufd               m5, m5, q0321
+    pshufd               m2, m2, q0321
+    movd                r7d, m5
+    movd                r9d, m2
+    movq                 m0, [base+subpel_filters+r4*8]
+    movq                 m1, [base+subpel_filters+r6*8]
+    movhps               m0, [base+subpel_filters+r7*8]
+    movhps               m1, [base+subpel_filters+r9*8]
+%else
+    movd                 r0, m5
+    movd                 rX, m2
+    pshufd               m5, m5, q0321
+    pshufd               m2, m2, q0321
+    movd                 r4, m5
+    movd                 r5, m2
+    movq                 m0, [base+subpel_filters+r0*8]
+    movq                 m1, [base+subpel_filters+rX*8]
+    movhps               m0, [base+subpel_filters+r4*8]
+    movhps               m1, [base+subpel_filters+r5*8]
+%endif
+    paddd               m14, m7 ; mx+dx*[4-7]
+    pand                 m5, m14, m10
+    psrld                m5, 6
+    paddd               m15, m5
+    pxor                 m2, m2
+    pcmpeqd              m5, m2
+    mova        [stk+0x110], m14
+    pshufd               m4, m15, q1032
+%if ARCH_X86_64
+    movd               r10d, m15
+    movd               r11d, m4
+    pshufd              m15, m15, q0321
+    pshufd               m4, m4, q0321
+    movd               r13d, m15
+    movd                rXd, m4
+    movq                 m2, [base+subpel_filters+r10*8]
+    movq                 m3, [base+subpel_filters+r11*8]
+    movhps               m2, [base+subpel_filters+r13*8]
+    movhps               m3, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    movq                r11, m14
+    punpckhqdq          m14, m14
+    movq                 rX, m14
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    mov                 r4d, [stk+ 0]
+    mov                 r6d, [stk+ 4]
+    mov                 r7d, [stk+ 8]
+    mov                 r9d, [stk+12]
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd              m14, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m7, m9, m4
+    pand                 m8, m9, m6
+    pand                m15, m9, m14
+    pand                 m9, m9, m5
+    pandn                m4, m0
+    pandn                m6, m1
+    pandn               m14, m2
+    pandn                m5, m3
+    por                  m7, m4
+    por                  m8, m6
+    por                 m15, m14
+    por                  m9, m5
+    punpcklbw            m0, m7, m7
+    punpckhbw            m7, m7
+    punpcklbw            m1, m8, m8
+    punpckhbw            m8, m8
+    psraw                m0, 8
+    psraw                m7, 8
+    psraw                m1, 8
+    psraw                m8, 8
+    punpcklbw            m2, m15, m15
+    punpckhbw           m15, m15
+    punpcklbw            m3, m9, m9
+    punpckhbw            m9, m9
+    psraw                m2, 8
+    psraw               m15, 8
+    psraw                m3, 8
+    psraw                m9, 8
+    mova         [stk+0x10], m0
+    mova         [stk+0x20], m7
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m8
+    mova         [stk+0x50], m2
+    mova         [stk+0x60], m15
+    mova         [stk+0x70], m3
+    mova         [stk+0x80], m9
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 9, 10 ; 0
+    mova         [stk+0x90], m1
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 1, 9, 10 ; 1
+    mova         [stk+0xa0], m2
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 1, 2, 9, 10 ; 2
+    mova         [stk+0xb0], m3
+    MC_8TAP_SCALED_H 4, 5, 6, 1, 2, 3, 9, 10 ; 3
+    mova         [stk+0xc0], m4
+    MC_8TAP_SCALED_H 5, 6, 1, 2, 3, 4, 9, 10 ; 4
+    mova         [stk+0xd0], m5
+    MC_8TAP_SCALED_H 6, 1, 2, 3, 4, 5, 9, 10 ; 5
+    MC_8TAP_SCALED_H 7, 1, 2, 3, 4, 5, 9, 10 ; 6
+    MC_8TAP_SCALED_H 8, 1, 2, 3, 4, 5, 9, 10 ; 7
+    mova                 m5, [stk+0xd0]
+    mova                 m1, [stk+0x90]
+    mova                 m2, [stk+0xa0]
+    mova                 m3, [stk+0xb0]
+    mova                 m9, [stk+0xc0]
+    punpcklwd            m4, m5, m6 ; 45a
+    punpckhwd            m5, m6     ; 45b
+    punpcklwd            m6, m7, m8 ; 67a
+    punpckhwd            m7, m8     ; 67b
+    punpcklwd            m0, m1, m2 ; 01a
+    punpckhwd            m1, m2     ; 01b
+    punpcklwd            m2, m3, m9 ; 23a
+    punpckhwd            m3, m9     ; 23b
+    mova                m10, [stk+0x140]
+    mova                m11, [stk+0x150]
+    mova                m14, [stk+0x160]
+    mova                m15, [stk+0x170]
+    mova         [stk+0x90], m4
+    mova         [stk+0xa0], m5
+    mova         [stk+0xb0], m6
+    mova         [stk+0xc0], m7
+ %define hround [rsp+0x10]
+ %define shift  [rsp+0x20]
+ %if isput
+  %define vround [rsp+0x30]
+ %else
+  %define vround [base+pd_m524256]
+ %endif
+.dy1_vloop:
+    pmaddwd              m4, m0, m10
+    pmaddwd              m5, m1, m10
+    pmaddwd              m6, m2, m11
+    pmaddwd              m7, m3, m11
+    paddd                m4, m13
+    paddd                m5, m13
+    paddd                m4, m6
+    paddd                m5, m7
+    pmaddwd              m6, [stk+0x90], m14
+    pmaddwd              m7, [stk+0xa0], m14
+    pmaddwd              m8, [stk+0xb0], m15
+    pmaddwd              m9, [stk+0xc0], m15
+    paddd                m4, m6
+    paddd                m5, m7
+ %if isput
+    pshufd               m6, m12, q1032
+ %endif
+    paddd                m4, m8
+    paddd                m5, m9
+%else
+    movd                 r0, m15
+    movd                 rX, m4
+    pshufd              m15, m15, q0321
+    pshufd               m4, m4, q0321
+    movd                 r4, m15
+    movd                 r5, m4
+    mova                m14, [stk+0x110]
+    movq                 m2, [base+subpel_filters+r0*8]
+    movq                 m3, [base+subpel_filters+rX*8]
+    movhps               m2, [base+subpel_filters+r4*8]
+    movhps               m3, [base+subpel_filters+r5*8]
+    psrld               m14, 10
+    mova           [stk+16], m14
+    mov                  r0, [stk+ 0]
+    mov                  rX, [stk+ 4]
+    mov                  r4, [stk+ 8]
+    mov                  r5, [stk+12]
+    mova         [stk+0x20], m0
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd               m7, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m0, m9, m4
+    pand                 m1, m9, m6
+    pand                 m2, m9, m7
+    pand                 m3, m9, m5
+    pandn                m4, [stk+0x20]
+    pandn                m6, [stk+0x30]
+    pandn                m7, [stk+0x40]
+    pandn                m5, [stk+0x50]
+    por                  m0, m4
+    por                  m1, m6
+    por                  m2, m7
+    por                  m3, m5
+    punpcklbw            m4, m0, m0
+    punpckhbw            m0, m0
+    punpcklbw            m5, m1, m1
+    punpckhbw            m1, m1
+    psraw                m4, 8
+    psraw                m0, 8
+    psraw                m5, 8
+    psraw                m1, 8
+    punpcklbw            m6, m2, m2
+    punpckhbw            m2, m2
+    punpcklbw            m7, m3, m3
+    punpckhbw            m3, m3
+    psraw                m6, 8
+    psraw                m2, 8
+    psraw                m7, 8
+    psraw                m3, 8
+    mova        [stk+0x0a0], m4
+    mova        [stk+0x0b0], m0
+    mova        [stk+0x0c0], m5
+    mova        [stk+0x0d0], m1
+    mova        [stk+0x140], m6
+    mova        [stk+0x150], m2
+    mova        [stk+0x160], m7
+    mova        [stk+0x170], m3
+    MC_8TAP_SCALED_H   0xa0, 0x20, 0 ; 0
+    MC_8TAP_SCALED_H   0xa0, 0x30    ; 1
+    MC_8TAP_SCALED_H   0xa0, 0x40    ; 2
+    MC_8TAP_SCALED_H   0xa0, 0x50    ; 3
+    MC_8TAP_SCALED_H   0xa0, 0x60    ; 4
+    MC_8TAP_SCALED_H   0xa0, 0x70    ; 5
+    MC_8TAP_SCALED_H   0xa0, 0x80    ; 6
+    MC_8TAP_SCALED_H   0xa0, 0x90    ; 7
+    mova                 m5, [stk+0x60]
+    mova                 m6, [stk+0x70]
+    mova                 m7, [stk+0x80]
+    mova                 m0, [stk+0x90]
+    mov                  r0, r0m
+    punpcklwd            m4, m5, m6      ; 45a
+    punpckhwd            m5, m6          ; 45b
+    punpcklwd            m6, m7, m0      ; 67a
+    punpckhwd            m7, m0          ; 67b
+    mova         [stk+0x60], m4
+    mova         [stk+0x70], m5
+    mova         [stk+0x80], m6
+    mova         [stk+0x90], m7
+    mova                 m1, [stk+0x20]
+    mova                 m2, [stk+0x30]
+    mova                 m3, [stk+0x40]
+    mova                 m4, [stk+0x50]
+    punpcklwd            m0, m1, m2      ; 01a
+    punpckhwd            m1, m2          ; 01b
+    punpcklwd            m2, m3, m4      ; 23a
+    punpckhwd            m3, m4          ; 23b
+    mova                 m4, [stk+0x180]
+    mova                 m5, [stk+0x190]
+    mova                 m6, [stk+0x1a0]
+    mova                 m7, [stk+0x1b0]
+    mova         [stk+0x20], m0
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+.dy1_vloop:
+    pmaddwd              m0, m4
+    pmaddwd              m1, m4
+    pmaddwd              m2, m5
+    pmaddwd              m3, m5
+    paddd                m0, m2
+    paddd                m1, m3
+    pmaddwd              m2, [stk+0x60], m6
+    pmaddwd              m3, [stk+0x70], m6
+    pmaddwd              m4, [stk+0x80], m7
+    pmaddwd              m5, [stk+0x90], m7
+ %if isput
+    movd                 m6, [esp+0x18]
+ %endif
+    paddd                m0, m2
+    paddd                m1, m3
+    paddd                m0, vrnd_mem
+    paddd                m1, vrnd_mem
+    paddd                m4, m0
+    paddd                m5, m1
+%endif
+%ifidn %1, put
+    psrad                m4, m6
+    psrad                m5, m6
+    packssdw             m4, m5
+    pxor                 m7, m7
+    pmaxsw               m4, m7
+    pminsw               m4, pxmaxm
+    mova             [dstq], m4
+    add                dstq, dsm
+%else
+    psrad                m4, 6
+    psrad                m5, 6
+    packssdw             m4, m5
+    mova             [tmpq], m4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .dy1_hloop_prep
+%if ARCH_X86_64
+    movu                 m8, [srcq+r10*2]
+    movu                 m9, [srcq+r11*2]
+    movu                m12, [srcq+r13*2]
+    movu                m13, [srcq+ rX*2]
+    movu                 m4, [srcq+ r4*2]
+    movu                 m5, [srcq+ r6*2]
+    movu                 m6, [srcq+ r7*2]
+    movu                 m7, [srcq+ r9*2]
+    add                srcq, ssq
+    pmaddwd              m8, [stk+0x50]
+    pmaddwd              m9, [stk+0x60]
+    pmaddwd             m12, [stk+0x70]
+    pmaddwd             m13, [stk+0x80]
+    pmaddwd              m4, [stk+0x10]
+    pmaddwd              m5, [stk+0x20]
+    pmaddwd              m6, [stk+0x30]
+    pmaddwd              m7, [stk+0x40]
+    phaddd               m8, m9
+    phaddd              m12, m13
+    mova                 m9, [base+unpckw]
+    mova                m13, hround
+    phaddd               m4, m5
+    phaddd               m6, m7
+    phaddd               m8, m12
+    phaddd               m4, m6
+    pshufd               m5, m9, q1032
+    pshufb               m0, m9             ; 0a 1a
+    pshufb               m1, m9             ; 0b 1b
+    pshufb               m2, m5             ; 3a 2a
+    pshufb               m3, m5             ; 3b 2b
+    mova                m12, shift
+    paddd                m4, m13
+    paddd                m8, m13
+    psrad                m4, m12
+    psrad                m8, m12
+    packssdw             m4, m8
+    pshufb               m6, [stk+0x90], m9 ; 4a 5a
+    pshufb               m7, [stk+0xa0], m9 ; 4b 5b
+    pshufb               m8, [stk+0xb0], m5 ; 7a 6a
+    pshufb              m13, [stk+0xc0], m5 ; 7b 6b
+    punpckhwd            m0, m2  ; 12a
+    punpckhwd            m1, m3  ; 12b
+    punpcklwd            m2, m6  ; 34a
+    punpcklwd            m3, m7  ; 34b
+    punpckhwd            m6, m8  ; 56a
+    punpckhwd            m7, m13 ; 56b
+    punpcklwd            m8, m4  ; 78a
+    punpckhqdq           m4, m4
+    punpcklwd           m13, m4  ; 78b
+    mova         [stk+0x90], m6
+    mova         [stk+0xa0], m7
+    mova         [stk+0xb0], m8
+    mova         [stk+0xc0], m13
+    mova                m13, vround
+%else
+    mov                 r0m, r0
+    mov                  r3, r3m
+    mov                  r0, [stk+ 0]
+    mov                  rX, [stk+ 4]
+    mov                  r4, [stk+ 8]
+    mov                  r5, [stk+12]
+    MC_8TAP_SCALED_H 0xa0, 0xe0, 0 ; 8
+    mova                 m7, [base+unpckw]
+    pshufd               m4, m7, q1032
+    pshufb               m0, [stk+0x20], m7 ; 0a 1a
+    pshufb               m1, [stk+0x30], m7 ; 0b 1b
+    pshufb               m2, [stk+0x40], m4 ; 3a 2a
+    pshufb               m3, [stk+0x50], m4 ; 3b 2b
+    pshufb               m5, [stk+0x60], m7 ; 4a 5a
+    pshufb               m6, [stk+0x70], m7 ; 4b 5b
+    pshufb               m7, [stk+0x80], m4 ; 7a 6a
+    punpckhwd            m0, m2 ; 12a
+    punpckhwd            m1, m3 ; 12b
+    punpcklwd            m2, m5 ; 34a
+    punpcklwd            m3, m6 ; 34b
+    mova         [stk+0x20], m0
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+    punpckhwd            m5, m7 ; 56a
+    mova         [stk+0x60], m5
+    pshufb               m5, [stk+0x90], m4 ; 7b 6b
+    punpcklwd            m7, [stk+0xe0] ; 78a
+    mova                 m4, [stk+0x180]
+    punpckhwd            m6, m5 ; 56b
+    mova         [stk+0x70], m6
+    movq                 m6, [stk+0xe8]
+    mova         [stk+0x80], m7
+    mova                 m7, [stk+0x1b0]
+    punpcklwd            m5, m6
+    mova                 m6, [stk+0x1a0]
+    mova         [stk+0x90], m5
+    mova                 m5, [stk+0x190]
+    mov                  r0, r0m
+%endif
+    jmp .dy1_vloop
+INIT_XMM ssse3
+%if ARCH_X86_64
+ %define stk rsp+0x20
+%endif
+.dy2:
+    movzx                wd, word [base+%1_8tap_scaled_ssse3_dy2_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%if isput
+.dy2_w2:
+ %if ARCH_X86_64
+    mov                 myd, mym
+    mova         [rsp+0x10], m13
+  %define vrnd_mem [rsp+0x10]
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd                m15, t0d
+ %else
+  %define m8  m0
+  %define m9  m1
+  %define m14 m4
+  %define m15 m3
+  %define m11 [esp+0x00]
+  %define m12 [esp+0x10]
+  %define vrnd_mem [esp+0x20]
+    mov                  r1, r1m
+    movzx                r5, byte [esp+0x1f0]
+    sub                srcq, 2
+    movd                m15, r5
+ %endif
+    pxor                 m9, m9
+    punpckldq            m9, m8
+    paddd               m14, m9 ; mx+dx*[0-1]
+ %if ARCH_X86_64
+    mova                 m9, [base+pd_0x4000]
+ %endif
+    pshufd              m15, m15, q0000
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd               m15, m8
+    movd                r4d, m15
+    pshufd              m15, m15, q0321
+ %if ARCH_X86_64
+    movd                r6d, m15
+ %else
+    movd                r3d, m15
+ %endif
+    mova                 m5, [base+bdct_lb_q]
+    mova                 m6, [base+spel_s_shuf2]
+    movd                m15, [base+subpel_filters+r4*8+2]
+ %if ARCH_X86_64
+    movd                 m7, [base+subpel_filters+r6*8+2]
+ %else
+    movd                 m7, [base+subpel_filters+r3*8+2]
+ %endif
+    pxor                 m2, m2
+    pcmpeqd              m8, m2
+    psrld               m14, 10
+    paddd               m14, m14
+ %if ARCH_X86_32
+    mov                  r3, r3m
+    pshufb              m14, m5
+    paddb               m14, m6
+    mova              [stk], m14
+    SWAP                 m5, m0
+    SWAP                 m6, m3
+  %define m15 m6
+ %endif
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*2]
+    movu                 m2, [srcq+ssq*4]
+    punpckldq           m15, m7
+ %if ARCH_X86_64
+    pshufb              m14, m5
+    paddb               m14, m6
+    pand                 m9, m8
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m9
+    movu                 m4, [srcq+ssq*1]
+    movu                 m5, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    movu                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+ %else
+    pand                 m7, m5, [base+pd_0x4000]
+    pandn                m5, m15
+    por                  m5, m7
+  %define m15 m5
+    mov                 myd, mym
+    mov                  r5, [esp+0x1f4]
+    xor                  r3, r3
+    shr                 myd, 6
+    lea                  r5, [r5+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r5*8+0]
+    cmovnz               r3, [base+subpel_filters+r5*8+4]
+    mov          [stk+0x20], r3
+    mov                  r3, r3m
+ %endif
+    punpcklbw           m15, m15
+    psraw               m15, 8
+    REPX    {pshufb x, m14}, m0, m1, m2
+    REPX   {pmaddwd x, m15}, m0, m1, m2
+ %if ARCH_X86_64
+    REPX    {pshufb x, m14}, m4, m5, m6
+    REPX   {pmaddwd x, m15}, m4, m5, m6
+    phaddd               m0, m1
+    phaddd               m1, m2
+    phaddd               m4, m5
+    phaddd               m5, m6
+    REPX     {paddd x, m11}, m0, m1, m4, m5
+    REPX     {psrad x, m12}, m0, m1, m4, m5
+    packssdw             m0, m1 ; 0 2 2 4
+    packssdw             m4, m5 ; 1 3 3 5
+    SWAP                 m2, m4
+    movq                m10, r4
+ %else
+    mova         [stk+0x10], m15
+    phaddd               m0, m1
+    phaddd               m1, m2
+    movu                 m2, [srcq+ssq*1]
+    movu                 m7, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    movu                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    REPX    {pshufb x, m14}, m2, m7, m6
+    REPX   {pmaddwd x, m15}, m2, m7, m6
+  %define m14 [stk+0x00]
+  %define m15 [stk+0x10]
+    phaddd               m2, m7
+    phaddd               m7, m6
+    REPX     {paddd x, m11}, m0, m1, m2, m7
+    REPX     {psrad x, m12}, m0, m1, m2, m7
+    packssdw             m0, m1
+    packssdw             m2, m7
+  %define m8  m6
+  %define m9  m4
+  %define m10 m5
+    movd                m10, r4
+    movd                 m9, [stk+0x20]
+    punpckldq           m10, m9
+ %endif
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    pshufd               m7, m10, q0000
+    pshufd               m8, m10, q1111
+    pshufd               m9, m10, q2222
+    pshufd              m10, m10, q3333
+ %if ARCH_X86_32
+    mova         [stk+0x50], m7
+    mova         [stk+0x60], m8
+    mova         [stk+0x70], m9
+    mova         [stk+0x80], m10
+  %xdefine m13 m7
+  %define m7  [stk+0x50]
+  %define m8  [stk+0x60]
+  %define m9  [stk+0x70]
+  %define m10 [stk+0x80]
+ %endif
+    punpcklwd            m1, m0, m2    ; 01 23
+    punpckhwd            m3, m0, m2    ; 23 45
+ %if ARCH_X86_32
+    mov                  r4, r0m
+  %define dstq r4
+    mova         [stk+0x20], m3
+    mova         [stk+0x30], m0
+ %endif
+.dy2_w2_loop:
+    movu                 m4, [srcq+ssq*0]
+    movu                 m5, [srcq+ssq*1]
+    movu                 m6, [srcq+ssq*2]
+    movu                m13, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pmaddwd              m3, m8
+    REPX    {pshufb x, m14}, m4, m5, m6, m13
+    REPX   {pmaddwd x, m15}, m4, m5, m6, m13
+    phaddd               m4, m5
+    phaddd               m6, m13
+    pmaddwd              m5, m1, m7
+    paddd                m4, m11
+    paddd                m6, m11
+    psrad                m4, m12
+    psrad                m6, m12
+    packssdw             m4, m6 ; 6 7 8 9
+    paddd                m5, m3
+    pshufd               m3, m4, q2200
+    pshufd               m4, m4, q3311
+    palignr              m3, m0, 12 ; 4 6 6 8
+    palignr              m4, m2, 12 ; 5 7 7 9
+    mova                 m0, m3
+    mova                 m2, m4
+    punpcklwd            m1, m3, m4
+    punpckhwd            m3, m4
+    pmaddwd              m6, m1, m9
+    pmaddwd              m4, m3, m10
+    paddd                m5, vrnd_mem
+    paddd                m6, m4
+    paddd                m5, m6
+    pshufd               m4, m12, q1032
+    pxor                 m6, m6
+    psrad                m5, m4
+    packssdw             m5, m5
+    pmaxsw               m5, m6
+    pminsw               m5, pxmaxm
+    movd       [dstq+dsq*0], m5
+    pshuflw              m5, m5, q1032
+    movd       [dstq+dsq*1], m5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .dy2_w2_loop
+    RET
+%endif
+INIT_XMM ssse3
+.dy2_w4:
+%if ARCH_X86_64
+    mov                 myd, mym
+    mova         [rsp+0x10], m11
+    mova         [rsp+0x20], m12
+ %if isput
+    mova         [rsp+0x30], m13
+  %define vrnd_mem [rsp+0x30]
+  %define stk rsp+0x40
+ %else
+  %define vrnd_mem [base+pd_m524256]
+  %define stk rsp+0x30
+ %endif
+    movzx               t0d, t0b
+    sub                srcq, 2
+    movd                m15, t0d
+%else
+ %define m10 [base+pd_0x3ff]
+ %define m9  [base+pd_0x4000]
+ %define m8  m0
+ %xdefine m14 m4
+ %define m15 m3
+ %if isprep
+  %define ssq r3
+ %endif
+    movzx                r5, byte [esp+0x1f0]
+    sub                srcq, 2
+    movd                m15, r5
+%endif
+    pmaddwd              m8, [base+rescale_mul]
+%if ARCH_X86_64
+    mova                 m9, [base+pd_0x4000]
+%endif
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m0, m14, m10
+    psrld                m0, 6
+    paddd               m15, m0
+    pshufd               m7, m15, q1032
+%if ARCH_X86_64
+    movd                r4d, m15
+    movd               r11d, m7
+    pshufd              m15, m15, q0321
+    pshufd               m7, m7, q0321
+    movd                r6d, m15
+    movd               r13d, m7
+    mova                m10, [base+bdct_lb_q+ 0]
+    mova                m11, [base+bdct_lb_q+16]
+    movd                m13, [base+subpel_filters+ r4*8+2]
+    movd                 m2, [base+subpel_filters+ r6*8+2]
+    movd                m15, [base+subpel_filters+r11*8+2]
+    movd                 m4, [base+subpel_filters+r13*8+2]
+%else
+    movd                 r1, m15
+    movd                 r4, m7
+    pshufd              m15, m15, q0321
+    pshufd               m7, m7, q0321
+    movd                 r3, m15
+    movd                 r5, m7
+    mova                 m5, [base+bdct_lb_q+ 0]
+    mova                 m6, [base+bdct_lb_q+16]
+    movd                 m1, [base+subpel_filters+r1*8+2]
+    movd                 m2, [base+subpel_filters+r3*8+2]
+    movd                 m3, [base+subpel_filters+r4*8+2]
+    movd                 m7, [base+subpel_filters+r5*8+2]
+    SWAP                 m4, m7
+    mov                  r3, r3m
+ %if isprep
+    lea                ss3q, [ssq*3]
+ %endif
+ %define m10 m5
+ %define m11 m6
+ %define m12 m1
+ %define m13 m1
+%endif
+    psrld               m14, 10
+    paddd               m14, m14
+    punpckldq           m13, m2
+    punpckldq           m15, m4
+    punpcklqdq          m13, m15
+    pxor                 m2, m2
+    pcmpeqd              m0, m2
+%if ARCH_X86_64
+    pand                 m9, m0
+%else
+    pand                 m2, m9, m0
+ %define m9 m2
+    SWAP                 m7, m4
+%endif
+    pandn                m0, m13
+%if ARCH_X86_64
+    SWAP                m13, m0
+%else
+ %define m13 m0
+%endif
+    por                 m13, m9
+    punpckhbw           m15, m13, m13
+    punpcklbw           m13, m13
+    psraw               m15, 8
+    psraw               m13, 8
+    pshufb              m12, m14, m10
+    pshufb              m14, m11
+    mova                m10, [base+spel_s_shuf2]
+    movd                r4d, m14
+    shr                 r4d, 24
+%if ARCH_X86_32
+    mova         [stk+0x40], m13
+    mova         [stk+0x50], m15
+    pxor                 m2, m2
+%endif
+    pshufb               m7, m14, m2
+    psubb               m14, m7
+    paddb               m12, m10
+    paddb               m14, m10
+%if ARCH_X86_64
+    lea                  r6, [r4+ssq*1]
+    lea                 r11, [r4+ssq*2]
+    lea                 r13, [r4+ss3q ]
+    movu                 m1, [srcq+ssq*0]
+    movu                 m8, [srcq+ssq*2]
+    movu                 m9, [srcq+ssq*1]
+    movu                m10, [srcq+ss3q ]
+    movu                 m7, [srcq+r4   ]
+    movu                 m2, [srcq+r11  ]
+    movu                 m3, [srcq+r6   ]
+    movu                 m4, [srcq+r13  ]
+    lea                srcq, [srcq+ssq*4]
+    REPX    {pshufb x, m12}, m1, m9, m8, m10
+    REPX   {pmaddwd x, m13}, m1, m9, m8, m10
+    REPX    {pshufb x, m14}, m7, m3, m2, m4
+    REPX   {pmaddwd x, m15}, m7, m3, m2, m4
+    mova                 m5, [rsp+0x10]
+    movd                xm6, [rsp+0x20]
+    phaddd               m1, m7
+    phaddd               m8, m2
+    phaddd               m9, m3
+    phaddd              m10, m4
+    movu                 m2, [srcq+ssq*0]
+    movu                 m3, [srcq+ssq*1]
+    REPX      {paddd x, m5}, m1, m9, m8, m10
+    REPX     {psrad x, xm6}, m1, m9, m8, m10
+    packssdw             m1, m8     ; 0 2
+    packssdw             m9, m10    ; 1 3
+    movu                 m0, [srcq+r4   ]
+    movu                 m8, [srcq+r6   ]
+    lea                srcq, [srcq+ssq*2]
+    REPX    {pshufb x, m12}, m2, m3
+    REPX   {pmaddwd x, m13}, m2, m3
+    REPX    {pshufb x, m14}, m0, m8
+    REPX   {pmaddwd x, m15}, m0, m8
+    phaddd               m2, m0
+    phaddd               m3, m8
+    shr                 myd, 6
+    mov                 r9d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r9q, [base+subpel_filters+myq*8]
+    REPX      {paddd x, m5}, m2, m3
+    REPX     {psrad x, xm6}, m2, m3
+    packssdw             m2, m3        ; 4 5
+    pshufd               m3, m2, q1032 ; 5 _
+    punpcklwd            m0, m1, m9    ; 01
+    punpckhwd            m1, m9        ; 23
+    punpcklwd            m2, m3        ; 45
+    movq                m10, r9
+ %define hrnd_mem [rsp+0x10]
+ %define hsh_mem  [rsp+0x20]
+ %define vsh_mem  [rsp+0x28]
+ %if isput
+  %define vrnd_mem [rsp+0x30]
+ %else
+  %define vrnd_mem [base+pd_m524256]
+ %endif
+%else
+    mova         [stk+0x20], m12
+    mova         [stk+0x30], m14
+    add                  r4, srcq
+    MC_4TAP_SCALED_H   0x60 ; 0 1
+    MC_4TAP_SCALED_H   0x70 ; 2 3
+    MC_4TAP_SCALED_H   0x80 ; 4 5
+    mov          [stk+0xe0], r4
+    mova                 m3, [base+spel_s_shuf8]
+    mova                 m0, [stk+0x60]
+    mova                 m1, [stk+0x70]
+    mova                 m2, [stk+0x80]
+    mov                 myd, mym
+    mov                  rX, [esp+0x1f4]
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  rX, [rX+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+rX*8+0]
+    cmovnz               r5, [base+subpel_filters+rX*8+4]
+    mov                  r3, r3m
+    pshufb               m0, m3 ; 01
+    pshufb               m1, m3 ; 23
+    pshufb               m2, m3 ; 45
+    movd                 m7, r4
+    movd                 m4, r5
+    mov                  r5, r0m
+ %if isput
+    mov                  r1, r1m
+ %endif
+    mov                  r4, [stk+0xe0]
+ %define dstq r5
+ %define tmpq r5
+ %define m12 [stk+0x20]
+ %define m14 [stk+0x30]
+ %define m13 [stk+0x40]
+ %define m15 [stk+0x50]
+ %define hrnd_mem [esp+0x00]
+ %define hsh_mem  [esp+0x10]
+ %define vsh_mem  [esp+0x18]
+ %if isput
+  %define vrnd_mem [esp+0x20]
+ %else
+  %define vrnd_mem [base+pd_m524256]
+ %endif
+ %define m10 m7
+    punpckldq           m10, m4
+%endif
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    pshufd               m3, m10, q0000
+    pshufd               m4, m10, q1111
+    pshufd               m5, m10, q2222
+    pshufd              m10, m10, q3333
+%if ARCH_X86_32
+ %xdefine m8  m3
+ %xdefine m9  m6
+ %xdefine m11 m5
+ %xdefine m6  m4
+    mova         [stk+0x100], m3
+    mova         [stk+0x110], m4
+    mova         [stk+0x120], m5
+    mova         [stk+0x130], m10
+ %define m3  [stk+0x100]
+ %define m4  [stk+0x110]
+ %define m5  [stk+0x120]
+ %define m10 [stk+0x130]
+%endif
+.dy2_w4_loop:
+    pmaddwd              m8, m0, m3
+    pmaddwd              m9, m1, m3
+    mova                 m0, m2
+    pmaddwd              m1, m4
+    pmaddwd             m11, m2, m4
+    paddd                m8, vrnd_mem
+    paddd                m9, vrnd_mem
+    pmaddwd              m2, m5
+    paddd                m8, m1
+    paddd                m9, m11
+    paddd                m8, m2
+    movu                 m6, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*2]
+%if ARCH_X86_64
+    movu                m11, [srcq+r4 ]
+    movu                 m2, [srcq+r11]
+%else
+    movu                m11, [r4+ssq*0]
+    movu                 m2, [r4+ssq*2]
+%endif
+    pshufb               m6, m12
+    pshufb               m1, m12
+    pmaddwd              m6, m13
+    pmaddwd              m1, m13
+    pshufb              m11, m14
+    pshufb               m2, m14
+    pmaddwd             m11, m15
+    pmaddwd              m2, m15
+    phaddd               m6, m11
+    phaddd               m1, m2
+    paddd                m6, hrnd_mem
+    paddd                m1, hrnd_mem
+    psrad                m6, hsh_mem
+    psrad                m1, hsh_mem
+    movu                 m7, [srcq+ssq*1]
+    movu                m11, [srcq+ss3q ]
+    packssdw             m6, m1 ; 6 8
+%if ARCH_X86_64
+    movu                 m2, [srcq+r6 ]
+    movu                 m1, [srcq+r13]
+%else
+    movu                 m2, [r4+ssq*1]
+    movu                 m1, [r4+ss3q ]
+%endif
+    pshufb               m7, m12
+    pshufb              m11, m12
+    pmaddwd              m7, m13
+    pmaddwd             m11, m13
+    pshufb               m2, m14
+    pshufb               m1, m14
+    pmaddwd              m2, m15
+    pmaddwd              m1, m15
+    phaddd               m7, m2
+    phaddd              m11, m1
+    paddd                m7, hrnd_mem
+    paddd               m11, hrnd_mem
+    psrad                m7, hsh_mem
+    psrad               m11, hsh_mem
+    packssdw             m7, m11 ; 7 9
+%if ARCH_X86_32
+    lea                  r4, [r4+ssq*4]
+%endif
+    lea                srcq, [srcq+ssq*4]
+    punpcklwd            m1, m6, m7 ; 67
+    punpckhwd            m6, m7     ; 89
+    mova                 m2, m6
+    pmaddwd             m11, m1, m5
+    pmaddwd              m7, m1, m10
+    pmaddwd              m6, m10
+    paddd                m9, m11
+%if isput
+    movd                m11, vsh_mem
+%endif
+    paddd                m8, m7
+    paddd                m9, m6
+%if isput
+    psrad                m8, m11
+    psrad                m9, m11
+    packssdw             m8, m9
+    pxor                 m7, m7
+    pmaxsw               m8, m7
+    pminsw               m8, pxmaxm
+    movq       [dstq+dsq*0], m8
+    movhps     [dstq+dsq*1], m8
+    lea                dstq, [dstq+dsq*2]
+%else
+    psrad                m8, 6
+    psrad                m9, 6
+    packssdw             m8, m9
+    mova             [tmpq], m8
+    add                tmpq, 16
+%endif
+    sub                  hd, 2
+    jg .dy2_w4_loop
+    MC_8TAP_SCALED_RET ; why not jz .ret?
+INIT_XMM ssse3
+.dy2_w8:
+    mov    dword [stk+0xf0], 1
+    movifprep   tmp_stridem, 16
+    jmp .dy2_w_start
+.dy2_w16:
+    mov    dword [stk+0xf0], 2
+    movifprep   tmp_stridem, 32
+    jmp .dy2_w_start
+.dy2_w32:
+    mov    dword [stk+0xf0], 4
+    movifprep   tmp_stridem, 64
+    jmp .dy2_w_start
+.dy2_w64:
+    mov    dword [stk+0xf0], 8
+    movifprep   tmp_stridem, 128
+    jmp .dy2_w_start
+.dy2_w128:
+    mov    dword [stk+0xf0], 16
+    movifprep   tmp_stridem, 256
+.dy2_w_start:
+    mov                 myd, mym
+%if ARCH_X86_64
+ %ifidn %1, put
+    movifnidn           dsm, dsq
+ %endif
+    mova         [rsp+0x10], m11
+    mova         [rsp+0x20], m12
+ %define hround m11
+ %if isput
+    mova         [rsp+0x30], m13
+ %else
+    mova                m13, [base+pd_m524256]
+ %endif
+    shr                 t0d, 16
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    movd                m15, t0d
+%else
+ %define hround [esp+0x00]
+ %define m12    [esp+0x10]
+ %define m10    [base+pd_0x3ff]
+ %define m8  m0
+ %xdefine m14 m4
+ %xdefine m15 m3
+ %if isput
+  %define dstq r0
+ %else
+  %define tmpq r0
+  %define ssq ssm
+ %endif
+    mov                  r5, [esp+0x1f0]
+    mov                  r3, [esp+0x1f4]
+    shr                  r5, 16
+    movd                m15, r5
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  r3, [r3+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r3*8+0]
+    cmovnz               r5, [base+subpel_filters+r3*8+4]
+    mov                  r0, r0m
+    mov                  r3, r3m
+%endif
+    sub                srcq, 6
+    pslld                m7, m8, 2 ; dx*4
+    pmaddwd              m8, [base+rescale_mul] ; dx*[0-3]
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+%if ARCH_X86_64
+    movq                 m3, r4q
+%else
+    movd                 m5, r4
+    movd                 m6, r5
+    punpckldq            m5, m6
+    SWAP                 m3, m5
+%endif
+    punpcklbw            m3, m3
+    psraw                m3, 8
+    mova        [stk+0x100], m7
+    mova        [stk+0x120], m15
+    mov         [stk+0x0f8], srcq
+    mov         [stk+0x130], r0q ; dstq / tmpq
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+%if ARCH_X86_64
+    mova        [stk+0x140], m0
+    mova        [stk+0x150], m1
+    mova        [stk+0x160], m2
+    mova        [stk+0x170], m3
+ %if UNIX64
+    mov                  hm, hd
+ %endif
+%else
+    mova        [stk+0x180], m0
+    mova        [stk+0x190], m1
+    mova        [stk+0x1a0], m2
+    mova        [stk+0x1b0], m3
+    SWAP                 m5, m3
+    mov                  r5, hm
+    mov         [stk+0x134], r5
+%endif
+    jmp .dy2_hloop
+.dy2_hloop_prep:
+    dec   dword [stk+0x0f0]
+    jz .ret
+%if ARCH_X86_64
+    add   qword [stk+0x130], 16
+    mov                  hd, hm
+%else
+    add   dword [stk+0x130], 16
+    mov                  r5, [stk+0x134]
+    mov                  r0, [stk+0x130]
+%endif
+    mova                 m7, [stk+0x100]
+    mova                m14, [stk+0x110]
+%if ARCH_X86_64
+    mova                m10, [base+pd_0x3ff]
+    mova                m11, [rsp+0x10]
+%endif
+    mova                m15, [stk+0x120]
+    mov                srcq, [stk+0x0f8]
+%if ARCH_X86_64
+    mov                 r0q, [stk+0x130] ; dstq / tmpq
+%else
+    mov                  hm, r5
+    mov                 r0m, r0
+    mov                  r3, r3m
+%endif
+    paddd               m14, m7
+.dy2_hloop:
+%if ARCH_X86_64
+    mova                 m9, [base+pq_0x40000000]
+%else
+ %define m9 [base+pq_0x40000000]
+%endif
+    pxor                 m1, m1
+    psrld                m2, m14, 10
+    mova              [stk], m2
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd                m5, m15, m6
+    pcmpeqd              m6, m1
+    pshufd               m2, m5, q1032
+%if ARCH_X86_64
+    movd                r4d, m5
+    movd                r6d, m2
+    pshufd               m5, m5, q0321
+    pshufd               m2, m2, q0321
+    movd                r7d, m5
+    movd                r9d, m2
+    movq                 m0, [base+subpel_filters+r4*8]
+    movq                 m1, [base+subpel_filters+r6*8]
+    movhps               m0, [base+subpel_filters+r7*8]
+    movhps               m1, [base+subpel_filters+r9*8]
+%else
+    movd                 r0, m5
+    movd                 rX, m2
+    pshufd               m5, m5, q0321
+    pshufd               m2, m2, q0321
+    movd                 r4, m5
+    movd                 r5, m2
+    movq                 m0, [base+subpel_filters+r0*8]
+    movq                 m1, [base+subpel_filters+rX*8]
+    movhps               m0, [base+subpel_filters+r4*8]
+    movhps               m1, [base+subpel_filters+r5*8]
+%endif
+    paddd               m14, m7 ; mx+dx*[4-7]
+    pand                 m5, m14, m10
+    psrld                m5, 6
+    paddd               m15, m5
+    pxor                 m2, m2
+    pcmpeqd              m5, m2
+    mova        [stk+0x110], m14
+    pshufd               m4, m15, q1032
+%if ARCH_X86_64
+    movd               r10d, m15
+    movd               r11d, m4
+    pshufd              m15, m15, q0321
+    pshufd               m4, m4, q0321
+    movd               r13d, m15
+    movd                rXd, m4
+    movq                 m2, [base+subpel_filters+r10*8]
+    movq                 m3, [base+subpel_filters+r11*8]
+    movhps               m2, [base+subpel_filters+r13*8]
+    movhps               m3, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    movq                r11, m14
+    punpckhqdq          m14, m14
+    movq                 rX, m14
+    mov                r10d, r11d
+    shr                 r11, 32
+    mov                r13d, rXd
+    shr                  rX, 32
+    mov                 r4d, [stk+ 0]
+    mov                 r6d, [stk+ 4]
+    mov                 r7d, [stk+ 8]
+    mov                 r9d, [stk+12]
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd              m14, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m7, m9, m4
+    pand                 m8, m9, m6
+    pand                m15, m9, m14
+    pand                 m9, m9, m5
+    pandn                m4, m0
+    pandn                m6, m1
+    pandn               m14, m2
+    pandn                m5, m3
+    por                  m7, m4
+    por                  m8, m6
+    por                 m15, m14
+    por                  m9, m5
+    punpcklbw            m0, m7, m7
+    punpckhbw            m7, m7
+    punpcklbw            m1, m8, m8
+    punpckhbw            m8, m8
+    psraw                m0, 8
+    psraw                m7, 8
+    psraw                m1, 8
+    psraw                m8, 8
+    punpcklbw            m2, m15, m15
+    punpckhbw           m15, m15
+    punpcklbw            m3, m9, m9
+    punpckhbw            m9, m9
+    psraw                m2, 8
+    psraw               m15, 8
+    psraw                m3, 8
+    psraw                m9, 8
+    mova         [stk+0x10], m0
+    mova         [stk+0x20], m7
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m8
+    mova         [stk+0x50], m2
+    mova         [stk+0x60], m15
+    mova         [stk+0x70], m3
+    mova         [stk+0x80], m9
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 9, 10 ; 0
+    mova         [stk+0x90], m1
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 1, 9, 10 ; 1
+    mova         [stk+0xa0], m2
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 1, 2, 9, 10 ; 2
+    mova         [stk+0xb0], m3
+    MC_8TAP_SCALED_H 4, 5, 6, 1, 2, 3, 9, 10 ; 3
+    mova         [stk+0xc0], m4
+    MC_8TAP_SCALED_H 5, 6, 1, 2, 3, 4, 9, 10 ; 4
+    mova         [stk+0xd0], m5
+    MC_8TAP_SCALED_H 6, 1, 2, 3, 4, 5, 9, 10 ; 5
+    MC_8TAP_SCALED_H 7, 1, 2, 3, 4, 5, 9, 10 ; 6
+    MC_8TAP_SCALED_H 8, 1, 2, 3, 4, 5, 9, 10 ; 7
+    mova                 m5, [stk+0xd0]
+    mova                 m1, [stk+0x90]
+    mova                 m2, [stk+0xa0]
+    mova                 m3, [stk+0xb0]
+    mova                 m9, [stk+0xc0]
+    punpcklwd            m4, m5, m6 ; 45a
+    punpckhwd            m5, m6     ; 45b
+    punpcklwd            m6, m7, m8 ; 67a
+    punpckhwd            m7, m8     ; 67b
+    punpcklwd            m0, m1, m2 ; 01a
+    punpckhwd            m1, m2     ; 01b
+    punpcklwd            m2, m3, m9 ; 23a
+    punpckhwd            m3, m9     ; 23b
+    mova                m10, [stk+0x140]
+    mova                m11, [stk+0x150]
+    mova                m14, [stk+0x160]
+    mova                m15, [stk+0x170]
+    mova         [stk+0x90], m4
+    mova         [stk+0xa0], m5
+    mova         [stk+0xb0], m6
+    mova         [stk+0xc0], m7
+ %define hround [rsp+0x10]
+ %define shift  [rsp+0x20]
+ %if isput
+  %define vround [rsp+0x30]
+ %else
+  %define vround [base+pd_m524256]
+ %endif
+.dy2_vloop:
+    pmaddwd              m4, m0, m10
+    pmaddwd              m5, m1, m10
+    pmaddwd              m6, m2, m11
+    pmaddwd              m7, m3, m11
+    paddd                m4, m13
+    paddd                m5, m13
+    paddd                m4, m6
+    paddd                m5, m7
+    pmaddwd              m6, [stk+0x90], m14
+    pmaddwd              m7, [stk+0xa0], m14
+    pmaddwd              m8, [stk+0xb0], m15
+    pmaddwd              m9, [stk+0xc0], m15
+    paddd                m4, m6
+    paddd                m5, m7
+ %if isput
+    pshufd               m6, m12, q1032
+ %endif
+    paddd                m4, m8
+    paddd                m5, m9
+%else
+    movd                 r0, m15
+    movd                 rX, m4
+    pshufd              m15, m15, q0321
+    pshufd               m4, m4, q0321
+    movd                 r4, m15
+    movd                 r5, m4
+    mova                m14, [stk+0x110]
+    movq                 m2, [base+subpel_filters+r0*8]
+    movq                 m3, [base+subpel_filters+rX*8]
+    movhps               m2, [base+subpel_filters+r4*8]
+    movhps               m3, [base+subpel_filters+r5*8]
+    psrld               m14, 10
+    mova           [stk+16], m14
+    mov                  r0, [stk+ 0]
+    mov                  rX, [stk+ 4]
+    mov                  r4, [stk+ 8]
+    mov                  r5, [stk+12]
+    mova         [stk+0x20], m0
+    mova         [stk+0x30], m1
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd               m7, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m0, m9, m4
+    pand                 m1, m9, m6
+    pand                 m2, m9, m7
+    pand                 m3, m9, m5
+    pandn                m4, [stk+0x20]
+    pandn                m6, [stk+0x30]
+    pandn                m7, [stk+0x40]
+    pandn                m5, [stk+0x50]
+    por                  m0, m4
+    por                  m1, m6
+    por                  m2, m7
+    por                  m3, m5
+    punpcklbw            m4, m0, m0
+    punpckhbw            m0, m0
+    punpcklbw            m5, m1, m1
+    punpckhbw            m1, m1
+    psraw                m4, 8
+    psraw                m0, 8
+    psraw                m5, 8
+    psraw                m1, 8
+    punpcklbw            m6, m2, m2
+    punpckhbw            m2, m2
+    punpcklbw            m7, m3, m3
+    punpckhbw            m3, m3
+    psraw                m6, 8
+    psraw                m2, 8
+    psraw                m7, 8
+    psraw                m3, 8
+    mova        [stk+0x0a0], m4
+    mova        [stk+0x0b0], m0
+    mova        [stk+0x0c0], m5
+    mova        [stk+0x0d0], m1
+    mova        [stk+0x140], m6
+    mova        [stk+0x150], m2
+    mova        [stk+0x160], m7
+    mova        [stk+0x170], m3
+    MC_8TAP_SCALED_H   0xa0, 0x20, 0 ; 0
+    MC_8TAP_SCALED_H   0xa0, 0x30    ; 1
+    MC_8TAP_SCALED_H   0xa0, 0x40    ; 2
+    MC_8TAP_SCALED_H   0xa0, 0x50    ; 3
+    MC_8TAP_SCALED_H   0xa0, 0x60    ; 4
+    MC_8TAP_SCALED_H   0xa0, 0x70    ; 5
+    MC_8TAP_SCALED_H   0xa0, 0x80    ; 6
+    MC_8TAP_SCALED_H   0xa0, 0x90    ; 7
+    mova                 m5, [stk+0x60]
+    mova                 m6, [stk+0x70]
+    mova                 m7, [stk+0x80]
+    mova                 m0, [stk+0x90]
+    mov                  r0, r0m
+    punpcklwd            m4, m5, m6      ; 45a
+    punpckhwd            m5, m6          ; 45b
+    punpcklwd            m6, m7, m0      ; 67a
+    punpckhwd            m7, m0          ; 67b
+    mova         [stk+0x60], m4
+    mova         [stk+0x70], m5
+    mova         [stk+0x80], m6
+    mova         [stk+0x90], m7
+    mova                 m1, [stk+0x20]
+    mova                 m2, [stk+0x30]
+    mova                 m3, [stk+0x40]
+    mova                 m4, [stk+0x50]
+    punpcklwd            m0, m1, m2      ; 01a
+    punpckhwd            m1, m2          ; 01b
+    punpcklwd            m2, m3, m4      ; 23a
+    punpckhwd            m3, m4          ; 23b
+    mova                 m4, [stk+0x180]
+    mova                 m5, [stk+0x190]
+    mova                 m6, [stk+0x1a0]
+    mova                 m7, [stk+0x1b0]
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+.dy2_vloop:
+    pmaddwd              m0, m4
+    pmaddwd              m1, m4
+    pmaddwd              m2, m5
+    pmaddwd              m3, m5
+    paddd                m0, m2
+    paddd                m1, m3
+    pmaddwd              m2, [stk+0x60], m6
+    pmaddwd              m3, [stk+0x70], m6
+    pmaddwd              m4, [stk+0x80], m7
+    pmaddwd              m5, [stk+0x90], m7
+ %if isput
+    movd                 m6, [esp+0x18]
+ %endif
+    paddd                m0, m2
+    paddd                m1, m3
+    paddd                m0, vrnd_mem
+    paddd                m1, vrnd_mem
+    paddd                m4, m0
+    paddd                m5, m1
+%endif
+%ifidn %1, put
+    psrad                m4, m6
+    psrad                m5, m6
+    packssdw             m4, m5
+    pxor                 m7, m7
+    pmaxsw               m4, m7
+    pminsw               m4, pxmaxm
+    mova             [dstq], m4
+    add                dstq, dsm
+%else
+    psrad                m4, 6
+    psrad                m5, 6
+    packssdw             m4, m5
+    mova             [tmpq], m4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .dy2_hloop_prep
+%if ARCH_X86_64
+    MC_8TAP_SCALED_H 4, 8, 5, 6, 7, 9, 0, 1
+    mova         [stk+0xd0], m4
+    MC_8TAP_SCALED_H 8, 5, 6, 7, 9, 4, 0, 1
+    mova                 m4, [stk+0xd0]
+    mova                 m0, m2         ; 01a
+    mova                 m1, m3         ; 01b
+    mova                 m2, [stk+0x90] ; 23a
+    mova                 m3, [stk+0xa0] ; 23b
+    mova                 m5, [stk+0xb0] ; 45a
+    mova                 m6, [stk+0xc0] ; 45b
+    punpcklwd            m7, m4, m8     ; 67a
+    punpckhwd            m4, m8         ; 67b
+    mova         [stk+0x90], m5
+    mova         [stk+0xa0], m6
+    mova         [stk+0xb0], m7
+    mova         [stk+0xc0], m4
+%else
+    mov                 r0m, r0
+    mov                  r3, r3m
+    MC_8TAP_SCALED_H 0xa0, 0xe0 ; 8
+    MC_8TAP_SCALED_H 0xa0, 0    ; 9
+    mova                 m7, [stk+0xe0]
+    mova                 m2, [stk+0x60] ; 23a
+    mova                 m3, [stk+0x70] ; 23b
+    mova                 m4, [stk+0x80] ; 45a
+    mova                 m5, [stk+0x90] ; 45b
+    punpcklwd            m6, m7, m0     ; 67a
+    punpckhwd            m7, m0         ; 67b
+    mova                 m0, [stk+0x40] ; 01a
+    mova                 m1, [stk+0x50] ; 01b
+    mova         [stk+0x40], m2
+    mova         [stk+0x50], m3
+    mova         [stk+0x60], m4
+    mova         [stk+0x70], m5
+    mova                 m4, [stk+0x180]
+    mova                 m5, [stk+0x190]
+    mova         [stk+0x80], m6
+    mova         [stk+0x90], m7
+    mova                 m6, [stk+0x1a0]
+    mova                 m7, [stk+0x1b0]
+    mov                  r0, r0m
+%endif
+    jmp .dy2_vloop
+INIT_XMM ssse3
+.ret:
+    MC_8TAP_SCALED_RET 0
+%if ARCH_X86_32 && !isprep && required_stack_alignment > STACK_ALIGNMENT
+ %define r0m [rstk+stack_offset+ 4]
+ %define r1m [rstk+stack_offset+ 8]
+ %define r2m [rstk+stack_offset+12]
+ %define r3m [rstk+stack_offset+16]
+%endif
+%undef isput
+%undef isprep
+%endmacro
+
+%macro BILIN_SCALED_FN 1
+cglobal %1_bilin_scaled_16bpc
+    mov                 t0d, (5*15 << 16) | 5*15
+    mov                 t1d, (5*15 << 16) | 5*15
+    jmp mangle(private_prefix %+ _%1_8tap_scaled_16bpc %+ SUFFIX)
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 6, 5
+%elif ARCH_X86_64
+DECLARE_REG_TMP 6, 8
+%else
+DECLARE_REG_TMP 1, 2
+%endif
+
+%define PUT_8TAP_SCALED_FN FN put_8tap_scaled,
+BILIN_SCALED_FN put
+PUT_8TAP_SCALED_FN sharp,          SHARP,   SHARP,   put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN sharp_smooth,   SHARP,   SMOOTH,  put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN smooth,         SMOOTH,  SMOOTH,  put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN sharp_regular,  SHARP,   REGULAR, put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN regular_sharp,  REGULAR, SHARP,   put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN smooth_regular, SMOOTH,  REGULAR, put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN regular_smooth, REGULAR, SMOOTH,  put_8tap_scaled_16bpc
+PUT_8TAP_SCALED_FN regular,        REGULAR, REGULAR
+MC_8TAP_SCALED put
+
+%if WIN64
+DECLARE_REG_TMP 5, 4
+%elif ARCH_X86_64
+DECLARE_REG_TMP 6, 7
+%else
+DECLARE_REG_TMP 1, 2
+%endif
+
+%define PREP_8TAP_SCALED_FN FN prep_8tap_scaled,
+BILIN_SCALED_FN prep
+PREP_8TAP_SCALED_FN sharp,          SHARP,   SHARP,   prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN smooth,         SMOOTH,  SMOOTH,  prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN smooth_regular, SMOOTH,  REGULAR, prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN regular_smooth, REGULAR, SMOOTH,  prep_8tap_scaled_16bpc
+PREP_8TAP_SCALED_FN regular,        REGULAR, REGULAR
+MC_8TAP_SCALED prep
+
+%if ARCH_X86_64
+DECLARE_REG_TMP 6
+%else
+DECLARE_REG_TMP 2
+%endif
+
+%if ARCH_X86_64
+; warp8x8t spills one less xmm register than warp8x8 on WIN64, compensate that
+; by allocating 16 bytes more stack space so that stack offsets match up.
+%if WIN64 && STACK_ALIGNMENT == 16
+%assign stksz 16*14
+%else
+%assign stksz 16*13
+%endif
+cglobal warp_affine_8x8t_16bpc, 4, 13, 9, stksz, dst, ds, src, ss, delta, \
+                                                 mx, tmp, alpha, beta, \
+                                                 filter, my, gamma, cnt
+%assign stack_size_padded_8x8t stack_size_padded
+%else
+cglobal warp_affine_8x8t_16bpc, 0, 7, 8, -16*17, alpha, gamma, src, tmp, \
+                                                 filter, mx, my
+%define m8   [esp+16*13]
+%define m9   [esp+16*14]
+%define cntd dword [esp+4*63]
+%define dstq tmpq
+%define dsq  0
+%if STACK_ALIGNMENT < 16
+%define dstm [esp+4*65]
+%define dsm  [esp+4*66]
+%else
+%define dstm r0m
+%define dsm  r1m
+%endif
+%endif
+%define base filterq-$$
+    mov                 t0d, r7m
+    LEA             filterq, $$
+    shr                 t0d, 11
+%if ARCH_X86_64
+    movddup              m8, [base+warp8x8t_rnd]
+%else
+    movddup              m1, [base+warp8x8t_rnd]
+    mov                  r1, r1m
+    add                  r1, r1
+    mova                 m8, m1
+    mov                 r1m, r1 ; ds *= 2
+%endif
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_ssse3).main
+    jmp .start
+.loop:
+%if ARCH_X86_64
+    lea                dstq, [dstq+dsq*4]
+%else
+    add                dstq, dsm
+    mov                dstm, dstq
+%endif
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_ssse3).main2
+.start:
+%if ARCH_X86_32
+    mov                dstq, dstm
+%endif
+    paddd                m1, m8
+    paddd                m2, m8
+    psrad                m1, 15
+    psrad                m2, 15
+    packssdw             m1, m2
+    mova       [dstq+dsq*0], m1
+    call mangle(private_prefix %+ _warp_affine_8x8_16bpc_ssse3).main3
+%if ARCH_X86_32
+    mov                dstq, dstm
+    add                dstq, dsm
+%endif
+    paddd                m1, m8
+    paddd                m2, m8
+    psrad                m1, 15
+    psrad                m2, 15
+    packssdw             m1, m2
+    mova       [dstq+dsq*2], m1
+    dec                cntd
+    jg .loop
+    RET
+
+%if ARCH_X86_64
+cglobal warp_affine_8x8_16bpc, 4, 13, 10, 16*13, dst, ds, src, ss, delta, \
+                                                 mx, tmp, alpha, beta, \
+                                                 filter, my, gamma, cnt
+ASSERT stack_size_padded == stack_size_padded_8x8t
+%else
+cglobal warp_affine_8x8_16bpc, 0, 7, 8, -16*17, alpha, gamma, src, tmp, \
+                                                filter, mx, my
+%endif
+    mov                 t0d, r7m
+    LEA             filterq, $$
+    shr                 t0d, 11
+%if ARCH_X86_64
+    movddup              m8, [base+warp8x8_rnd2+t0*8]
+    movd                 m9, r7m ; pixel_max
+    pshufb               m9, [base+pw_256]
+%else
+    movddup              m1, [base+warp8x8_rnd2+t0*8]
+    movd                 m2, r7m ; pixel_max
+    pshufb               m2, [base+pw_256]
+    mova                 m8, m1
+    mova                 m9, m2
+%endif
+    call .main
+    jmp .start
+.loop:
+%if ARCH_X86_64
+    lea                dstq, [dstq+dsq*2]
+%else
+    add                dstq, dsm
+    mov                dstm, dstq
+%endif
+    call .main2
+.start:
+%if ARCH_X86_32
+    mov                dstq, dstm
+%endif
+    psrad                m1, 16
+    psrad                m2, 16
+    packssdw             m1, m2
+    pmaxsw               m1, m6
+    pmulhrsw             m1, m8
+    pminsw               m1, m9
+    mova       [dstq+dsq*0], m1
+    call .main3
+%if ARCH_X86_32
+    mov                dstq, dstm
+    add                dstq, dsm
+%endif
+    psrad                m1, 16
+    psrad                m2, 16
+    packssdw             m1, m2
+    pmaxsw               m1, m6
+    pmulhrsw             m1, m8
+    pminsw               m1, m9
+    mova       [dstq+dsq*1], m1
+    dec                cntd
+    jg .loop
+    RET
+ALIGN function_align
+.main:
+    ; Stack args offset by one (r4m -> r5m etc.) due to call
+%if WIN64
+    mov              deltaq, r5m
+    mov                 mxd, r6m
+%endif
+    movd                 m0, [base+warp8x8_shift+t0*4]
+    movddup              m7, [base+warp8x8_rnd1+t0*8]
+    add             filterq, mc_warp_filter-$$
+%if ARCH_X86_64
+    movsx            alphad, word [deltaq+2*0]
+    movsx             betad, word [deltaq+2*1]
+    movsx            gammad, word [deltaq+2*2]
+    movsx            deltad, word [deltaq+2*3]
+    lea                tmpq, [ssq*3]
+    add                 mxd, 512+(64<<10)
+    sub                srcq, tmpq             ; src -= ss*3
+    imul               tmpd, alphad, -7
+    mov                 myd, r7m
+    add               betad, tmpd             ; beta -= alpha*7
+    imul               tmpd, gammad, -7
+    add                 myd, 512+(64<<10)
+    mov                cntd, 4
+    add              deltad, tmpd             ; delta -= gamma*7
+%else
+%if STACK_ALIGNMENT < 16
+    %assign stack_offset stack_offset - gprsize
+%endif
+    mov                 r3d, r5m              ; abcd
+%if STACK_ALIGNMENT < 16
+    mov                  r0, r1m              ; dst
+    mov                  r1, r2m              ; ds
+    mov  [esp+gprsize+4*65], r0
+    mov  [esp+gprsize+4*66], r1
+%endif
+    movsx            alphad, word [r3+2*0]
+    movsx               r2d, word [r3+2*1]
+    movsx            gammad, word [r3+2*2]
+    movsx               r3d, word [r3+2*3]
+    imul                r5d, alphad, -7
+    add                 r2d, r5d              ; beta -= alpha*7
+    imul                r5d, gammad, -7
+    mov  [esp+gprsize+4*60], r2d
+    add                 r3d, r5d              ; delta -= gamma*7
+    mov  [esp+gprsize+4*61], r3d
+    mov                 r3d, r4m              ; ss
+    mov                srcq, r3m
+    mov                 mxd, r6m
+    mov                 myd, r7m
+    mov dword [esp+gprsize+4*63], 4           ; cnt
+    mov  [esp+gprsize+4*62], r3
+    lea                  r3, [r3*3]
+    add                 mxd, 512+(64<<10)
+    add                 myd, 512+(64<<10)
+    sub                srcq, r3               ; src -= ss*3
+%if STACK_ALIGNMENT < 16
+    %assign stack_offset stack_offset + gprsize
+%endif
+%endif
+    mova      [rsp+gprsize], m0
+    pxor                 m6, m6
+    call .h
+    mova                 m5, m0
+    call .h
+    punpcklwd            m1, m5, m0           ; 01
+    punpckhwd            m5, m0
+    mova [rsp+gprsize+16* 1], m1
+    mova [rsp+gprsize+16* 4], m5
+    mova                 m5, m0
+    call .h
+    punpcklwd            m1, m5, m0           ; 12
+    punpckhwd            m5, m0
+    mova [rsp+gprsize+16* 7], m1
+    mova [rsp+gprsize+16*10], m5
+    mova                 m5, m0
+    call .h
+    punpcklwd            m1, m5, m0           ; 23
+    punpckhwd            m5, m0
+    mova [rsp+gprsize+16* 2], m1
+    mova [rsp+gprsize+16* 5], m5
+    mova                 m5, m0
+    call .h
+    punpcklwd            m1, m5, m0           ; 34
+    punpckhwd            m5, m0
+    mova [rsp+gprsize+16* 8], m1
+    mova [rsp+gprsize+16*11], m5
+    mova                 m5, m0
+    call .h
+    punpcklwd            m1, m5, m0           ; 45
+    punpckhwd            m5, m0
+    mova [rsp+gprsize+16* 3], m1
+    mova [rsp+gprsize+16* 6], m5
+    mova                 m5, m0
+    call .h
+    punpcklwd            m1, m5, m0           ; 56
+    punpckhwd            m5, m0
+    mova [rsp+gprsize+16* 9], m1
+    mova [rsp+gprsize+16*12], m5
+    mova                 m5, m0
+.main2:
+    call .h
+%macro WARP_V 6 ; 01l, 23l, 45l, 01h, 23h, 45h
+    lea                tmpd, [myq+gammaq]
+    shr                 myd, 10
+    movq                 m4, [filterq+myq*8]  ; a
+    lea                 myd, [tmpq+gammaq]
+    shr                tmpd, 10
+    movq                 m2, [filterq+tmpq*8] ; b
+    lea                tmpd, [myq+gammaq]
+    shr                 myd, 10
+    movq                 m3, [filterq+myq*8]  ; c
+    lea                 myd, [tmpq+gammaq]
+    shr                tmpd, 10
+    movq                 m1, [filterq+tmpq*8] ; d
+    lea                tmpd, [myq+gammaq]
+    shr                 myd, 10
+    punpcklwd            m4, m2
+    punpcklwd            m3, m1
+    punpckldq            m2, m4, m3
+    punpckhdq            m4, m3
+    punpcklbw            m1, m6, m2           ; a0 a1 b0 b1 c0 c1 d0 d1 << 8
+    pmaddwd              m1, [rsp+gprsize+16*%1]
+    punpckhbw            m3, m6, m2           ; a2 a3 b2 b3 c2 c3 d2 d3 << 8
+    mova                 m2, [rsp+gprsize+16*%2]
+    pmaddwd              m3, m2
+    mova [rsp+gprsize+16*%1], m2
+    paddd                m1, m3
+    punpcklbw            m3, m6, m4           ; a4 a5 b4 b5 c4 c5 d4 d5 << 8
+    mova                 m2, [rsp+gprsize+16*%3]
+    pmaddwd              m3, m2
+    mova [rsp+gprsize+16*%2], m2
+    paddd                m1, m3
+    punpcklwd            m3, m5, m0           ; 67
+    punpckhbw            m2, m6, m4           ; a6 a7 b6 b7 c6 c7 d6 d7 << 8
+    pmaddwd              m2, m3
+    mova [rsp+gprsize+16*%3], m3
+    paddd                m1, m2
+    movq                 m4, [filterq+myq*8]  ; e
+    lea                 myd, [tmpq+gammaq]
+    shr                tmpd, 10
+    movq                 m3, [filterq+tmpq*8] ; f
+    lea                tmpd, [myq+gammaq]
+    shr                 myd, 10
+    movq                 m2, [filterq+myq*8]  ; g
+%if ARCH_X86_64
+    lea                 myd, [tmpq+deltaq]    ; my += delta
+%else
+    mov                 myd, [esp+gprsize+4*61]
+    add                 myd, tmpd
+%endif
+    shr                tmpd, 10
+    punpcklwd            m4, m3
+    movq                 m3, [filterq+tmpq*8] ; h
+    punpcklwd            m2, m3
+    punpckldq            m3, m4, m2
+    punpckhdq            m4, m2
+    punpcklbw            m2, m6, m3           ; e0 e1 f0 f1 g0 g1 h0 h1 << 8
+    pmaddwd              m2, [rsp+gprsize+16*%4]
+    punpckhbw            m6, m3               ; e2 e3 f2 f3 g2 g3 h2 h3 << 8
+    mova                 m3, [rsp+gprsize+16*%5]
+    pmaddwd              m6, m3
+    mova [rsp+gprsize+16*%4], m3
+    pxor                 m3, m3
+    paddd                m2, m6
+    punpcklbw            m3, m4               ; e4 e5 f4 f5 g4 g5 h4 h5 << 8
+    mova                 m6, [rsp+gprsize+16*%6]
+    pmaddwd              m3, m6
+    mova [rsp+gprsize+16*%5], m6
+    punpckhwd            m5, m0
+    pxor                 m6, m6
+    paddd                m2, m3
+    punpckhbw            m3, m6, m4           ; e6 e7 f6 f7 g6 g7 h6 h7 << 8
+    pmaddwd              m3, m5
+    mova [rsp+gprsize+16*%6], m5
+    mova                 m5, m0
+    paddd                m2, m3
+%endmacro
+    WARP_V                1,  2,  3,  4,  5,  6
+    ret
+.main3:
+    call .h
+    WARP_V                7,  8,  9, 10, 11, 12
+    ret
+ALIGN function_align
+.h:
+    lea                tmpd, [mxq+alphaq]
+    shr                 mxd, 10
+    movq                 m3, [filterq+mxq*8]
+    punpcklbw            m0, m6, m3
+    movu                 m3, [srcq-6]
+    pmaddwd              m0, m3               ; 0
+    lea                 mxd, [tmpq+alphaq]
+    shr                tmpd, 10
+    movq                 m3, [filterq+tmpq*8]
+    punpcklbw            m2, m6, m3
+    movu                 m3, [srcq-4]
+    pmaddwd              m2, m3               ; 1
+    lea                tmpd, [mxq+alphaq]
+    shr                 mxd, 10
+    movq                 m3, [filterq+mxq*8]
+    phaddd               m0, m2               ; 0 1
+    punpcklbw            m2, m6, m3
+    movu                 m3, [srcq-2]
+    pmaddwd              m2, m3               ; 2
+    lea                 mxd, [tmpq+alphaq]
+    shr                tmpd, 10
+    movq                 m3, [filterq+tmpq*8]
+    punpcklbw            m1, m6, m3
+    movu                 m3, [srcq+0]
+    pmaddwd              m1, m3               ; 3
+    lea                tmpd, [mxq+alphaq]
+    shr                 mxd, 10
+    movq                 m3, [filterq+mxq*8]
+    phaddd               m2, m1               ; 2 3
+    punpcklbw            m1, m6, m3
+    movu                 m3, [srcq+2]
+    pmaddwd              m1, m3               ; 4
+    lea                 mxd, [tmpq+alphaq]
+    shr                tmpd, 10
+    movq                 m3, [filterq+tmpq*8]
+    phaddd               m0, m2               ; 0 1 2 3
+    punpcklbw            m2, m6, m3
+    movu                 m3, [srcq+4]
+    pmaddwd              m2, m3               ; 5
+    lea                tmpd, [mxq+alphaq]
+    shr                 mxd, 10
+    movq                 m3, [filterq+mxq*8]
+    phaddd               m1, m2               ; 4 5
+    punpcklbw            m2, m6, m3
+    movu                 m3, [srcq+6]
+    pmaddwd              m2, m3               ; 6
+%if ARCH_X86_64
+    lea                 mxd, [tmpq+betaq]     ; mx += beta
+%else
+    mov                 mxd, [esp+gprsize*2+4*60]
+    add                 mxd, tmpd
+%endif
+    shr                tmpd, 10
+    movq                 m3, [filterq+tmpq*8]
+    punpcklbw            m4, m6, m3
+    movu                 m3, [srcq+8]
+%if ARCH_X86_64
+    add                srcq, ssq
+%else
+    add                srcq, [esp+gprsize*2+4*62]
+%endif
+    pmaddwd              m3, m4               ; 7
+    phaddd               m2, m3               ; 6 7
+    phaddd               m1, m2               ; 4 5 6 7
+    paddd                m0, m7
+    paddd                m1, m7
+    psrad                m0, [rsp+gprsize*2]
+    psrad                m1, [rsp+gprsize*2]
+    packssdw             m0, m1
+    ret
+
+%macro BIDIR_FN 0
+    call .main
+    jmp                  wq
+.w4_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w4:
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    movq   [dstq+strideq*0], m1
+    movhps [dstq+strideq*1], m1
+    sub                  hd, 4
+    jg .w4_loop
+.ret:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w8:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    sub                  hd, 2
+    jne .w8_loop
+    RET
+.w16_loop:
+    call .main
+    add                dstq, strideq
+.w16:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    dec                  hd
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    add                dstq, strideq
+.w32:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    call .main
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    dec                  hd
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    call .main
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    call .main
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m1
+    call .main
+    mova        [dstq+16*6], m0
+    mova        [dstq+16*7], m1
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova       [dstq+16* 0], m0
+    mova       [dstq+16* 1], m1
+    call .main
+    mova       [dstq+16* 2], m0
+    mova       [dstq+16* 3], m1
+    call .main
+    mova       [dstq+16* 4], m0
+    mova       [dstq+16* 5], m1
+    call .main
+    mova       [dstq+16* 6], m0
+    mova       [dstq+16* 7], m1
+    call .main
+    mova       [dstq+16* 8], m0
+    mova       [dstq+16* 9], m1
+    call .main
+    mova       [dstq+16*10], m0
+    mova       [dstq+16*11], m1
+    call .main
+    mova       [dstq+16*12], m0
+    mova       [dstq+16*13], m1
+    call .main
+    mova       [dstq+16*14], m0
+    mova       [dstq+16*15], m1
+    dec                  hd
+    jg .w128_loop
+    RET
+%endmacro
+
+%if UNIX64
+DECLARE_REG_TMP 7
+%else
+DECLARE_REG_TMP 5
+%endif
+
+cglobal avg_16bpc, 4, 7, 4, dst, stride, tmp1, tmp2, w, h
+%define base r6-avg_ssse3_table
+    LEA                  r6, avg_ssse3_table
+    tzcnt                wd, wm
+    mov                 t0d, r6m ; pixel_max
+    movsxd               wq, [r6+wq*4]
+    shr                 t0d, 11
+    movddup              m2, [base+bidir_rnd+t0*8]
+    movddup              m3, [base+bidir_mul+t0*8]
+    movifnidn            hd, hm
+    add                  wq, r6
+    BIDIR_FN
+ALIGN function_align
+.main:
+    mova                 m0, [tmp1q+16*0]
+    paddsw               m0, [tmp2q+16*0]
+    mova                 m1, [tmp1q+16*1]
+    paddsw               m1, [tmp2q+16*1]
+    add               tmp1q, 16*2
+    add               tmp2q, 16*2
+    pmaxsw               m0, m2
+    pmaxsw               m1, m2
+    psubsw               m0, m2
+    psubsw               m1, m2
+    pmulhw               m0, m3
+    pmulhw               m1, m3
+    ret
+
+cglobal w_avg_16bpc, 4, 7, 8, dst, stride, tmp1, tmp2, w, h
+%define base r6-w_avg_ssse3_table
+    LEA                  r6, w_avg_ssse3_table
+    tzcnt                wd, wm
+    mov                 t0d, r6m ; weight
+    movd                 m6, r7m ; pixel_max
+    movddup              m5, [base+pd_65538]
+    movsxd               wq, [r6+wq*4]
+    pshufb               m6, [base+pw_256]
+    add                  wq, r6
+    lea                 r6d, [t0-16]
+    shl                 t0d, 16
+    sub                 t0d, r6d ; 16-weight, weight
+    paddw                m5, m6
+    mov                 r6d, t0d
+    shl                 t0d, 2
+    test          dword r7m, 0x800
+    cmovnz              r6d, t0d
+    movifnidn            hd, hm
+    movd                 m4, r6d
+    pslld                m5, 7
+    pxor                 m7, m7
+    pshufd               m4, m4, q0000
+    BIDIR_FN
+ALIGN function_align
+.main:
+    mova                 m2, [tmp1q+16*0]
+    mova                 m0, [tmp2q+16*0]
+    punpckhwd            m3, m0, m2
+    punpcklwd            m0, m2
+    mova                 m2, [tmp1q+16*1]
+    mova                 m1, [tmp2q+16*1]
+    add               tmp1q, 16*2
+    add               tmp2q, 16*2
+    pmaddwd              m3, m4
+    pmaddwd              m0, m4
+    paddd                m3, m5
+    paddd                m0, m5
+    psrad                m3, 8
+    psrad                m0, 8
+    packssdw             m0, m3
+    punpckhwd            m3, m1, m2
+    punpcklwd            m1, m2
+    pmaddwd              m3, m4
+    pmaddwd              m1, m4
+    paddd                m3, m5
+    paddd                m1, m5
+    psrad                m3, 8
+    psrad                m1, 8
+    packssdw             m1, m3
+    pminsw               m0, m6
+    pminsw               m1, m6
+    pmaxsw               m0, m7
+    pmaxsw               m1, m7
+    ret
+
+%if ARCH_X86_64
+cglobal mask_16bpc, 4, 7, 9, dst, stride, tmp1, tmp2, w, h, mask
+%else
+cglobal mask_16bpc, 4, 7, 8, dst, stride, tmp1, tmp2, w, mask
+%define hd dword r5m
+%define m8 [base+pw_64]
+%endif
+%define base r6-mask_ssse3_table
+    LEA                  r6, mask_ssse3_table
+    tzcnt                wd, wm
+    mov                 t0d, r7m ; pixel_max
+    shr                 t0d, 11
+    movsxd               wq, [r6+wq*4]
+    movddup              m6, [base+bidir_rnd+t0*8]
+    movddup              m7, [base+bidir_mul+t0*8]
+%if ARCH_X86_64
+    mova                 m8, [base+pw_64]
+    movifnidn            hd, hm
+%endif
+    add                  wq, r6
+    mov               maskq, r6mp
+    BIDIR_FN
+ALIGN function_align
+.main:
+    movq                 m3, [maskq+8*0]
+    mova                 m0, [tmp1q+16*0]
+    mova                 m4, [tmp2q+16*0]
+    pxor                 m5, m5
+    punpcklbw            m3, m5
+    punpckhwd            m2, m0, m4
+    punpcklwd            m0, m4
+    psubw                m1, m8, m3
+    punpckhwd            m4, m3, m1 ; m, 64-m
+    punpcklwd            m3, m1
+    pmaddwd              m2, m4     ; tmp1 * m + tmp2 * (64-m)
+    pmaddwd              m0, m3
+    movq                 m3, [maskq+8*1]
+    mova                 m1, [tmp1q+16*1]
+    mova                 m4, [tmp2q+16*1]
+    add               maskq, 8*2
+    add               tmp1q, 16*2
+    add               tmp2q, 16*2
+    psrad                m2, 5
+    psrad                m0, 5
+    packssdw             m0, m2
+    punpcklbw            m3, m5
+    punpckhwd            m2, m1, m4
+    punpcklwd            m1, m4
+    psubw                m5, m8, m3
+    punpckhwd            m4, m3, m5 ; m, 64-m
+    punpcklwd            m3, m5
+    pmaddwd              m2, m4     ; tmp1 * m + tmp2 * (64-m)
+    pmaddwd              m1, m3
+    psrad                m2, 5
+    psrad                m1, 5
+    packssdw             m1, m2
+    pmaxsw               m0, m6
+    pmaxsw               m1, m6
+    psubsw               m0, m6
+    psubsw               m1, m6
+    pmulhw               m0, m7
+    pmulhw               m1, m7
+    ret
+
+cglobal w_mask_420_16bpc, 4, 7, 12, dst, stride, tmp1, tmp2, w, h, mask
+%define base t0-w_mask_420_ssse3_table
+    LEA                  t0, w_mask_420_ssse3_table
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    movd                 m0, r7m ; sign
+    shr                 r6d, 11
+    movsxd               wq, [t0+wq*4]
+%if ARCH_X86_64
+    mova                 m8, [base+pw_27615] ; ((64 - 38) << 10) + 1023 - 32
+    mova                 m9, [base+pw_64]
+    movddup             m10, [base+bidir_rnd+r6*8]
+    movddup             m11, [base+bidir_mul+r6*8]
+%else
+    mova                 m1, [base+pw_27615] ; ((64 - 38) << 10) + 1023 - 32
+    mova                 m2, [base+pw_64]
+    movddup              m3, [base+bidir_rnd+r6*8]
+    movddup              m4, [base+bidir_mul+r6*8]
+    ALLOC_STACK       -16*4
+    mova         [rsp+16*0], m1
+    mova         [rsp+16*1], m2
+    mova         [rsp+16*2], m3
+    mova         [rsp+16*3], m4
+    %define              m8  [rsp+gprsize+16*0]
+    %define              m9  [rsp+gprsize+16*1]
+    %define             m10  [rsp+gprsize+16*2]
+    %define             m11  [rsp+gprsize+16*3]
+%endif
+    movd                 m7, [base+pw_2]
+    psubw                m7, m0
+    pshufb               m7, [base+pw_256]
+    add                  wq, t0
+    movifnidn            hd, r5m
+    mov               maskq, r6mp
+    call .main
+    jmp                  wq
+.w4_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 4
+.w4:
+    movq   [dstq+strideq*0], m0
+    phaddw               m2, m3
+    movhps [dstq+strideq*1], m0
+    phaddd               m2, m2
+    lea                dstq, [dstq+strideq*2]
+    paddw                m2, m7
+    movq   [dstq+strideq*0], m1
+    psrlw                m2, 2
+    movhps [dstq+strideq*1], m1
+    packuswb             m2, m2
+    movd            [maskq], m2
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 4
+.w8:
+    mova   [dstq+strideq*0], m0
+    paddw                m2, m3
+    phaddw               m2, m2
+    mova   [dstq+strideq*1], m1
+    paddw                m2, m7
+    psrlw                m2, 2
+    packuswb             m2, m2
+    movd            [maskq], m2
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 8
+.w16:
+    mova [dstq+strideq*1+16*0], m2
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*1+16*1], m3
+    mova [dstq+strideq*0+16*1], m1
+    call .main
+    paddw                m2, [dstq+strideq*1+16*0]
+    paddw                m3, [dstq+strideq*1+16*1]
+    mova [dstq+strideq*1+16*0], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*1], m1
+    paddw                m2, m7
+    psrlw                m2, 2
+    packuswb             m2, m2
+    movq            [maskq], m2
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 16
+.w32:
+    mova [dstq+strideq*1+16*0], m2
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*1+16*1], m3
+    mova [dstq+strideq*0+16*1], m1
+    call .main
+    mova [dstq+strideq*0+16*2], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*3], m2
+    mova [dstq+strideq*0+16*3], m1
+    call .main
+    paddw                m2, [dstq+strideq*1+16*0]
+    paddw                m3, [dstq+strideq*1+16*1]
+    mova [dstq+strideq*1+16*0], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*2], m2
+    mova [dstq+strideq*1+16*1], m1
+    call .main
+    phaddw               m2, m3
+    paddw                m3, m7, [dstq+strideq*1+16*2]
+    paddw                m2, [dstq+strideq*1+16*3]
+    mova [dstq+strideq*1+16*2], m0
+    paddw                m2, m7
+    psrlw                m3, 2
+    psrlw                m2, 2
+    mova [dstq+strideq*1+16*3], m1
+    packuswb             m3, m2
+    mova            [maskq], m3
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 16*2
+.w64:
+    mova [dstq+strideq*1+16*1], m2
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*1+16*2], m3
+    mova [dstq+strideq*0+16*1], m1
+    call .main
+    mova [dstq+strideq*1+16*3], m2
+    mova [dstq+strideq*0+16*2], m0
+    mova [dstq+strideq*1+16*4], m3
+    mova [dstq+strideq*0+16*3], m1
+    call .main
+    mova [dstq+strideq*1+16*5], m2
+    mova [dstq+strideq*0+16*4], m0
+    mova [dstq+strideq*1+16*6], m3
+    mova [dstq+strideq*0+16*5], m1
+    call .main
+    mova [dstq+strideq*0+16*6], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*7], m2
+    mova [dstq+strideq*0+16*7], m1
+    call .main
+    paddw                m2, [dstq+strideq*1+16*1]
+    paddw                m3, [dstq+strideq*1+16*2]
+    mova [dstq+strideq*1+16*0], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*2], m2
+    mova [dstq+strideq*1+16*1], m1
+    call .main
+    paddw                m2, [dstq+strideq*1+16*3]
+    paddw                m3, [dstq+strideq*1+16*4]
+    phaddw               m2, m3
+    paddw                m3, m7, [dstq+strideq*1+16*2]
+    mova [dstq+strideq*1+16*2], m0
+    paddw                m2, m7
+    psrlw                m3, 2
+    psrlw                m2, 2
+    mova [dstq+strideq*1+16*3], m1
+    packuswb             m3, m2
+    mova       [maskq+16*0], m3
+    call .main
+    paddw                m2, [dstq+strideq*1+16*5]
+    paddw                m3, [dstq+strideq*1+16*6]
+    mova [dstq+strideq*1+16*4], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*6], m2
+    mova [dstq+strideq*1+16*5], m1
+    call .main
+    phaddw               m2, m3
+    paddw                m3, m7, [dstq+strideq*1+16*6]
+    paddw                m2, [dstq+strideq*1+16*7]
+    mova [dstq+strideq*1+16*6], m0
+    paddw                m2, m7
+    psrlw                m3, 2
+    psrlw                m2, 2
+    mova [dstq+strideq*1+16*7], m1
+    packuswb             m3, m2
+    mova       [maskq+16*1], m3
+    sub                  hd, 2
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 16*4
+.w128:
+    mova [dstq+strideq*1+16* 1], m2
+    mova [dstq+strideq*0+16* 0], m0
+    mova [dstq+strideq*1+16* 2], m3
+    mova [dstq+strideq*0+16* 1], m1
+    call .main
+    mova [dstq+strideq*1+16* 3], m2
+    mova [dstq+strideq*0+16* 2], m0
+    mova [dstq+strideq*1+16* 4], m3
+    mova [dstq+strideq*0+16* 3], m1
+    call .main
+    mova [dstq+strideq*1+16* 5], m2
+    mova [dstq+strideq*0+16* 4], m0
+    mova [dstq+strideq*1+16* 6], m3
+    mova [dstq+strideq*0+16* 5], m1
+    call .main
+    mova [dstq+strideq*1+16* 7], m2
+    mova [dstq+strideq*0+16* 6], m0
+    mova [dstq+strideq*1+16* 8], m3
+    mova [dstq+strideq*0+16* 7], m1
+    call .main
+    mova [dstq+strideq*1+16* 9], m2
+    mova [dstq+strideq*0+16* 8], m0
+    mova [dstq+strideq*1+16*10], m3
+    mova [dstq+strideq*0+16* 9], m1
+    call .main
+    mova [dstq+strideq*1+16*11], m2
+    mova [dstq+strideq*0+16*10], m0
+    mova [dstq+strideq*1+16*12], m3
+    mova [dstq+strideq*0+16*11], m1
+    call .main
+    mova [dstq+strideq*1+16*13], m2
+    mova [dstq+strideq*0+16*12], m0
+    mova [dstq+strideq*1+16*14], m3
+    mova [dstq+strideq*0+16*13], m1
+    call .main
+    mova [dstq+strideq*0+16*14], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*15], m2
+    mova [dstq+strideq*0+16*15], m1
+    call .main
+    paddw                m2, [dstq+strideq*1+16* 1]
+    paddw                m3, [dstq+strideq*1+16* 2]
+    mova [dstq+strideq*1+16* 0], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16* 2], m2
+    mova [dstq+strideq*1+16* 1], m1
+    call .main
+    paddw                m2, [dstq+strideq*1+16* 3]
+    paddw                m3, [dstq+strideq*1+16* 4]
+    phaddw               m2, m3
+    paddw                m3, m7, [dstq+strideq*1+16* 2]
+    mova [dstq+strideq*1+16* 2], m0
+    paddw                m2, m7
+    psrlw                m3, 2
+    psrlw                m2, 2
+    mova [dstq+strideq*1+16* 3], m1
+    packuswb             m3, m2
+    mova       [maskq+16*0], m3
+    call .main
+    paddw                m2, [dstq+strideq*1+16* 5]
+    paddw                m3, [dstq+strideq*1+16* 6]
+    mova [dstq+strideq*1+16* 4], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16* 6], m2
+    mova [dstq+strideq*1+16* 5], m1
+    call .main
+    paddw                m2, [dstq+strideq*1+16* 7]
+    paddw                m3, [dstq+strideq*1+16* 8]
+    phaddw               m2, m3
+    paddw                m3, m7, [dstq+strideq*1+16* 6]
+    mova [dstq+strideq*1+16* 6], m0
+    paddw                m2, m7
+    psrlw                m3, 2
+    psrlw                m2, 2
+    mova [dstq+strideq*1+16* 7], m1
+    packuswb             m3, m2
+    mova       [maskq+16*1], m3
+    call .main
+    paddw                m2, [dstq+strideq*1+16* 9]
+    paddw                m3, [dstq+strideq*1+16*10]
+    mova [dstq+strideq*1+16* 8], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*10], m2
+    mova [dstq+strideq*1+16* 9], m1
+    call .main
+    paddw                m2, [dstq+strideq*1+16*11]
+    paddw                m3, [dstq+strideq*1+16*12]
+    phaddw               m2, m3
+    paddw                m3, m7, [dstq+strideq*1+16*10]
+    mova [dstq+strideq*1+16*10], m0
+    paddw                m2, m7
+    psrlw                m3, 2
+    psrlw                m2, 2
+    mova [dstq+strideq*1+16*11], m1
+    packuswb             m3, m2
+    mova       [maskq+16*2], m3
+    call .main
+    paddw                m2, [dstq+strideq*1+16*13]
+    paddw                m3, [dstq+strideq*1+16*14]
+    mova [dstq+strideq*1+16*12], m0
+    phaddw               m2, m3
+    mova [dstq+strideq*1+16*14], m2
+    mova [dstq+strideq*1+16*13], m1
+    call .main
+    phaddw               m2, m3
+    paddw                m3, m7, [dstq+strideq*1+16*14]
+    paddw                m2, [dstq+strideq*1+16*15]
+    mova [dstq+strideq*1+16*14], m0
+    paddw                m2, m7
+    psrlw                m3, 2
+    psrlw                m2, 2
+    mova [dstq+strideq*1+16*15], m1
+    packuswb             m3, m2
+    mova       [maskq+16*3], m3
+    sub                  hd, 2
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+%macro W_MASK 2 ; dst/tmp_offset, mask
+    mova                m%1, [tmp1q+16*%1]
+    mova                m%2, [tmp2q+16*%1]
+    punpcklwd            m4, m%2, m%1
+    punpckhwd            m5, m%2, m%1
+    psubsw              m%1, m%2
+    pabsw               m%1, m%1
+    psubusw              m6, m8, m%1
+    psrlw                m6, 10      ; 64-m
+    psubw               m%2, m9, m6  ; m
+    punpcklwd           m%1, m6, m%2
+    punpckhwd            m6, m%2
+    pmaddwd             m%1, m4
+    pmaddwd              m6, m5
+    psrad               m%1, 5
+    psrad                m6, 5
+    packssdw            m%1, m6
+    pmaxsw              m%1, m10
+    psubsw              m%1, m10
+    pmulhw              m%1, m11
+%endmacro
+    W_MASK                0, 2
+    W_MASK                1, 3
+    add               tmp1q, 16*2
+    add               tmp2q, 16*2
+    ret
+
+cglobal w_mask_422_16bpc, 4, 7, 12, dst, stride, tmp1, tmp2, w, h, mask
+%define base t0-w_mask_422_ssse3_table
+    LEA                  t0, w_mask_422_ssse3_table
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    movd                 m7, r7m ; sign
+    shr                 r6d, 11
+    movsxd               wq, [t0+wq*4]
+%if ARCH_X86_64
+    mova                 m8, [base+pw_27615]
+    mova                 m9, [base+pw_64]
+    movddup             m10, [base+bidir_rnd+r6*8]
+    movddup             m11, [base+bidir_mul+r6*8]
+%else
+    mova                 m1, [base+pw_27615]
+    mova                 m2, [base+pw_64]
+    movddup              m3, [base+bidir_rnd+r6*8]
+    movddup              m4, [base+bidir_mul+r6*8]
+    ALLOC_STACK       -16*4
+    mova         [rsp+16*0], m1
+    mova         [rsp+16*1], m2
+    mova         [rsp+16*2], m3
+    mova         [rsp+16*3], m4
+%endif
+    pxor                 m0, m0
+    add                  wq, t0
+    pshufb               m7, m0
+    movifnidn            hd, r5m
+    mov               maskq, r6mp
+    call .main
+    jmp                  wq
+.w4_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w4:
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    movq   [dstq+strideq*0], m1
+    movhps [dstq+strideq*1], m1
+    sub                  hd, 4
+    jg .w4_loop
+.end:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w8:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    sub                  hd, 2
+    jg .w8_loop
+.w8_end:
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w16:
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*0+16*1], m1
+    call .main
+    mova [dstq+strideq*1+16*0], m0
+    mova [dstq+strideq*1+16*1], m1
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    add                dstq, strideq
+.w32:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    call .main
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    dec                  hd
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    call .main
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    call .main
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m1
+    call .main
+    mova        [dstq+16*6], m0
+    mova        [dstq+16*7], m1
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova       [dstq+16* 0], m0
+    mova       [dstq+16* 1], m1
+    call .main
+    mova       [dstq+16* 2], m0
+    mova       [dstq+16* 3], m1
+    call .main
+    mova       [dstq+16* 4], m0
+    mova       [dstq+16* 5], m1
+    call .main
+    mova       [dstq+16* 6], m0
+    mova       [dstq+16* 7], m1
+    call .main
+    mova       [dstq+16* 8], m0
+    mova       [dstq+16* 9], m1
+    call .main
+    mova       [dstq+16*10], m0
+    mova       [dstq+16*11], m1
+    call .main
+    mova       [dstq+16*12], m0
+    mova       [dstq+16*13], m1
+    call .main
+    mova       [dstq+16*14], m0
+    mova       [dstq+16*15], m1
+    dec                  hd
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+    W_MASK                0, 2
+    W_MASK                1, 3
+    phaddw               m2, m3
+    add               tmp1q, 16*2
+    add               tmp2q, 16*2
+    packuswb             m2, m2
+    pxor                 m3, m3
+    psubb                m2, m7
+    pavgb                m2, m3
+    movq            [maskq], m2
+    add               maskq, 8
+    ret
+
+cglobal w_mask_444_16bpc, 4, 7, 12, dst, stride, tmp1, tmp2, w, h, mask
+%define base t0-w_mask_444_ssse3_table
+    LEA                  t0, w_mask_444_ssse3_table
+    tzcnt                wd, wm
+    mov                 r6d, r8m ; pixel_max
+    shr                 r6d, 11
+    movsxd               wq, [t0+wq*4]
+%if ARCH_X86_64
+    mova                 m8, [base+pw_27615]
+    mova                 m9, [base+pw_64]
+    movddup             m10, [base+bidir_rnd+r6*8]
+    movddup             m11, [base+bidir_mul+r6*8]
+%else
+    mova                 m1, [base+pw_27615]
+    mova                 m2, [base+pw_64]
+    movddup              m3, [base+bidir_rnd+r6*8]
+    movddup              m7, [base+bidir_mul+r6*8]
+    ALLOC_STACK       -16*3
+    mova         [rsp+16*0], m1
+    mova         [rsp+16*1], m2
+    mova         [rsp+16*2], m3
+    %define             m11  m7
+%endif
+    add                  wq, t0
+    movifnidn            hd, r5m
+    mov               maskq, r6mp
+    call .main
+    jmp                  wq
+.w4_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w4:
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    movq   [dstq+strideq*0], m1
+    movhps [dstq+strideq*1], m1
+    sub                  hd, 4
+    jg .w4_loop
+.end:
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w8:
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    sub                  hd, 2
+    jg .w8_loop
+.w8_end:
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w16:
+    mova [dstq+strideq*0+16*0], m0
+    mova [dstq+strideq*0+16*1], m1
+    call .main
+    mova [dstq+strideq*1+16*0], m0
+    mova [dstq+strideq*1+16*1], m1
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    add                dstq, strideq
+.w32:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    call .main
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    dec                  hd
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    call .main
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    call .main
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m1
+    call .main
+    mova        [dstq+16*6], m0
+    mova        [dstq+16*7], m1
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova       [dstq+16* 0], m0
+    mova       [dstq+16* 1], m1
+    call .main
+    mova       [dstq+16* 2], m0
+    mova       [dstq+16* 3], m1
+    call .main
+    mova       [dstq+16* 4], m0
+    mova       [dstq+16* 5], m1
+    call .main
+    mova       [dstq+16* 6], m0
+    mova       [dstq+16* 7], m1
+    call .main
+    mova       [dstq+16* 8], m0
+    mova       [dstq+16* 9], m1
+    call .main
+    mova       [dstq+16*10], m0
+    mova       [dstq+16*11], m1
+    call .main
+    mova       [dstq+16*12], m0
+    mova       [dstq+16*13], m1
+    call .main
+    mova       [dstq+16*14], m0
+    mova       [dstq+16*15], m1
+    dec                  hd
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+    W_MASK                0, 2
+    W_MASK                1, 3
+    packuswb             m2, m3
+    add               tmp1q, 16*2
+    add               tmp2q, 16*2
+    mova            [maskq], m2
+    add               maskq, 16
+    ret
+
+; (a * (64 - m) + b * m + 32) >> 6
+; = (((b - a) * m + 32) >> 6) + a
+; = (((b - a) * (m << 9) + 16384) >> 15) + a
+;   except m << 9 overflows int16_t when m == 64 (which is possible),
+;   but if we negate m it works out (-64 << 9 == -32768).
+; = (((a - b) * (m * -512) + 16384) >> 15) + a
+cglobal blend_16bpc, 3, 7, 8, dst, stride, tmp, w, h, mask, stride3
+%define base r6-blend_ssse3_table
+    LEA                  r6, blend_ssse3_table
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r6+wq*4]
+    movifnidn         maskq, maskmp
+    mova                 m7, [base+pw_m512]
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    pxor                 m6, m6
+    jmp                  wq
+.w4:
+    mova                 m5, [maskq]
+    movq                 m0, [dstq+strideq*0]
+    movhps               m0, [dstq+strideq*1]
+    movq                 m1, [dstq+strideq*2]
+    movhps               m1, [dstq+stride3q ]
+    psubw                m2, m0, [tmpq+16*0]
+    psubw                m3, m1, [tmpq+16*1]
+    add               maskq, 16
+    add                tmpq, 32
+    punpcklbw            m4, m5, m6
+    punpckhbw            m5, m6
+    pmullw               m4, m7
+    pmullw               m5, m7
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    movq   [dstq+strideq*2], m1
+    movhps [dstq+stride3q ], m1
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    mova                 m5, [maskq]
+    mova                 m0, [dstq+strideq*0]
+    mova                 m1, [dstq+strideq*1]
+    psubw                m2, m0, [tmpq+16*0]
+    psubw                m3, m1, [tmpq+16*1]
+    add               maskq, 16
+    add                tmpq, 32
+    punpcklbw            m4, m5, m6
+    punpckhbw            m5, m6
+    pmullw               m4, m7
+    pmullw               m5, m7
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8
+    RET
+.w16:
+    mova                 m5, [maskq]
+    mova                 m0, [dstq+16*0]
+    mova                 m1, [dstq+16*1]
+    psubw                m2, m0, [tmpq+16*0]
+    psubw                m3, m1, [tmpq+16*1]
+    add               maskq, 16
+    add                tmpq, 32
+    punpcklbw            m4, m5, m6
+    punpckhbw            m5, m6
+    pmullw               m4, m7
+    pmullw               m5, m7
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w16
+    RET
+.w32:
+    mova                 m5, [maskq+16*0]
+    mova                 m0, [dstq+16*0]
+    mova                 m1, [dstq+16*1]
+    psubw                m2, m0, [tmpq+16*0]
+    psubw                m3, m1, [tmpq+16*1]
+    punpcklbw            m4, m5, m6
+    punpckhbw            m5, m6
+    pmullw               m4, m7
+    pmullw               m5, m7
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    mova                 m5, [maskq+16*1]
+    mova                 m0, [dstq+16*2]
+    mova                 m1, [dstq+16*3]
+    psubw                m2, m0, [tmpq+16*2]
+    psubw                m3, m1, [tmpq+16*3]
+    add               maskq, 32
+    add                tmpq, 64
+    punpcklbw            m4, m5, m6
+    punpckhbw            m5, m6
+    pmullw               m4, m7
+    pmullw               m5, m7
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova        [dstq+16*2], m0
+    mova        [dstq+16*3], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w32
+    RET
+
+cglobal blend_v_16bpc, 3, 6, 6, dst, stride, tmp, w, h
+%define base r5-blend_v_ssse3_table
+    LEA                  r5, blend_v_ssse3_table
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    add                  wq, r5
+    jmp                  wq
+.w2:
+    movd                 m4, [base+obmc_masks+2*2]
+.w2_loop:
+    movd                 m0, [dstq+strideq*0]
+    movd                 m2, [tmpq+4*0]
+    movd                 m1, [dstq+strideq*1]
+    movd                 m3, [tmpq+4*1]
+    add                tmpq, 4*2
+    psubw                m2, m0
+    psubw                m3, m1
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    movd   [dstq+strideq*0], m0
+    movd   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w2_loop
+    RET
+.w4:
+    movddup              m2, [base+obmc_masks+4*2]
+.w4_loop:
+    movq                 m0, [dstq+strideq*0]
+    movhps               m0, [dstq+strideq*1]
+    mova                 m1, [tmpq]
+    add                tmpq, 8*2
+    psubw                m1, m0
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+.w8:
+    mova                 m4, [base+obmc_masks+8*2]
+.w8_loop:
+    mova                 m0, [dstq+strideq*0]
+    mova                 m2, [tmpq+16*0]
+    mova                 m1, [dstq+strideq*1]
+    mova                 m3, [tmpq+16*1]
+    add                tmpq, 16*2
+    psubw                m2, m0
+    psubw                m3, m1
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16:
+    mova                 m4, [base+obmc_masks+16*2]
+    movq                 m5, [base+obmc_masks+16*3]
+.w16_loop:
+    mova                 m0, [dstq+16*0]
+    mova                 m2, [tmpq+16*0]
+    mova                 m1, [dstq+16*1]
+    mova                 m3, [tmpq+16*1]
+    add                tmpq, 16*2
+    psubw                m2, m0
+    psubw                m3, m1
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w16_loop
+    RET
+.w32:
+%if WIN64
+    movaps          [rsp+8], m6
+%endif
+    mova                 m4, [base+obmc_masks+16*4]
+    mova                 m5, [base+obmc_masks+16*5]
+    mova                 m6, [base+obmc_masks+16*6]
+.w32_loop:
+    mova                 m0, [dstq+16*0]
+    mova                 m2, [tmpq+16*0]
+    mova                 m1, [dstq+16*1]
+    mova                 m3, [tmpq+16*1]
+    psubw                m2, m0
+    psubw                m3, m1
+    pmulhrsw             m2, m4
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    mova                 m2, [dstq+16*2]
+    paddw                m1, m3
+    mova                 m3, [tmpq+16*2]
+    add                tmpq, 16*4
+    psubw                m3, m2
+    pmulhrsw             m3, m6
+    paddw                m2, m3
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    mova        [dstq+16*2], m2
+    add                dstq, strideq
+    dec                  hd
+    jg .w32_loop
+%if WIN64
+    movaps               m6, [rsp+8]
+%endif
+    RET
+
+%macro BLEND_H_ROW 2-3 0; dst_off, tmp_off, inc_tmp
+    mova                 m0, [dstq+16*(%1+0)]
+    mova                 m2, [tmpq+16*(%2+0)]
+    mova                 m1, [dstq+16*(%1+1)]
+    mova                 m3, [tmpq+16*(%2+1)]
+%if %3
+    add                tmpq, 16*%3
+%endif
+    psubw                m2, m0
+    psubw                m3, m1
+    pmulhrsw             m2, m5
+    pmulhrsw             m3, m5
+    paddw                m0, m2
+    paddw                m1, m3
+    mova   [dstq+16*(%1+0)], m0
+    mova   [dstq+16*(%1+1)], m1
+%endmacro
+
+cglobal blend_h_16bpc, 3, 7, 6, dst, ds, tmp, w, h, mask
+%define base r6-blend_h_ssse3_table
+    LEA                  r6, blend_h_ssse3_table
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    movddup              m4, [base+blend_shuf]
+    lea               maskq, [base+obmc_masks+hq*2]
+    lea                  hd, [hq*3]
+    add                  wq, r6
+    shr                  hd, 2 ; h * 3/4
+    lea               maskq, [maskq+hq*2]
+    neg                  hq
+    jmp                  wq
+.w2:
+    movd                 m0, [dstq+dsq*0]
+    movd                 m2, [dstq+dsq*1]
+    movd                 m3, [maskq+hq*2]
+    movq                 m1, [tmpq]
+    add                tmpq, 4*2
+    punpckldq            m0, m2
+    punpcklwd            m3, m3
+    psubw                m1, m0
+    pmulhrsw             m1, m3
+    paddw                m0, m1
+    movd       [dstq+dsq*0], m0
+    psrlq                m0, 32
+    movd       [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w2
+    RET
+.w4:
+    mova                 m3, [base+blend_shuf]
+.w4_loop:
+    movq                 m0, [dstq+dsq*0]
+    movhps               m0, [dstq+dsq*1]
+    movd                 m2, [maskq+hq*2]
+    mova                 m1, [tmpq]
+    add                tmpq, 8*2
+    psubw                m1, m0
+    pshufb               m2, m3
+    pmulhrsw             m1, m2
+    paddw                m0, m1
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w4_loop
+    RET
+.w8:
+    movddup              m5, [base+blend_shuf+8]
+%if WIN64
+    movaps         [rsp+ 8], m6
+    movaps         [rsp+24], m7
+%endif
+.w8_loop:
+    movd                 m7, [maskq+hq*2]
+    mova                 m0, [dstq+dsq*0]
+    mova                 m2, [tmpq+16*0]
+    mova                 m1, [dstq+dsq*1]
+    mova                 m3, [tmpq+16*1]
+    add                tmpq, 16*2
+    pshufb               m6, m7, m4
+    psubw                m2, m0
+    pshufb               m7, m5
+    psubw                m3, m1
+    pmulhrsw             m2, m6
+    pmulhrsw             m3, m7
+    paddw                m0, m2
+    paddw                m1, m3
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w8_loop
+%if WIN64
+    movaps               m6, [rsp+ 8]
+    movaps               m7, [rsp+24]
+%endif
+    RET
+.w16:
+    movd                 m5, [maskq+hq*2]
+    pshufb               m5, m4
+    BLEND_H_ROW           0, 0, 2
+    add                dstq, dsq
+    inc                  hq
+    jl .w16
+    RET
+.w32:
+    movd                 m5, [maskq+hq*2]
+    pshufb               m5, m4
+    BLEND_H_ROW           0, 0
+    BLEND_H_ROW           2, 2, 4
+    add                dstq, dsq
+    inc                  hq
+    jl .w32
+    RET
+.w64:
+    movd                 m5, [maskq+hq*2]
+    pshufb               m5, m4
+    BLEND_H_ROW           0, 0
+    BLEND_H_ROW           2, 2
+    BLEND_H_ROW           4, 4
+    BLEND_H_ROW           6, 6, 8
+    add                dstq, dsq
+    inc                  hq
+    jl .w64
+    RET
+.w128:
+    movd                 m5, [maskq+hq*2]
+    pshufb               m5, m4
+    BLEND_H_ROW           0,  0
+    BLEND_H_ROW           2,  2
+    BLEND_H_ROW           4,  4
+    BLEND_H_ROW           6,  6, 16
+    BLEND_H_ROW           8, -8
+    BLEND_H_ROW          10, -6
+    BLEND_H_ROW          12, -4
+    BLEND_H_ROW          14, -2
+    add                dstq, dsq
+    inc                  hq
+    jl .w128
+    RET
+
+; emu_edge args:
+; const intptr_t bw, const intptr_t bh, const intptr_t iw, const intptr_t ih,
+; const intptr_t x, const intptr_t y, pixel *dst, const ptrdiff_t dst_stride,
+; const pixel *ref, const ptrdiff_t ref_stride
+;
+; bw, bh total filled size
+; iw, ih, copied block -> fill bottom, right
+; x, y, offset in bw/bh -> fill top, left
+cglobal emu_edge_16bpc, 10, 13, 1, bw, bh, iw, ih, x, \
+                             y, dst, dstride, src, sstride, \
+                             bottomext, rightext, blk
+    ; we assume that the buffer (stride) is larger than width, so we can
+    ; safely overwrite by a few bytes
+
+%if ARCH_X86_64
+ %define reg_zero       r12q
+ %define reg_tmp        r10
+ %define reg_src        srcq
+ %define reg_bottomext  bottomextq
+ %define reg_rightext   rightextq
+ %define reg_blkm       r9m
+%else
+ %define reg_zero       r6
+ %define reg_tmp        r0
+ %define reg_src        r1
+ %define reg_bottomext  r0
+ %define reg_rightext   r1
+ %define reg_blkm       r2m
+%endif
+    ;
+    ; ref += iclip(y, 0, ih - 1) * PXSTRIDE(ref_stride)
+    xor            reg_zero, reg_zero
+    lea             reg_tmp, [ihq-1]
+    cmp                  yq, ihq
+    cmovs           reg_tmp, yq
+    test                 yq, yq
+    cmovs           reg_tmp, reg_zero
+%if ARCH_X86_64
+    imul            reg_tmp, sstrideq
+    add                srcq, reg_tmp
+%else
+    imul            reg_tmp, sstridem
+    mov             reg_src, srcm
+    add             reg_src, reg_tmp
+%endif
+    ;
+    ; ref += iclip(x, 0, iw - 1)
+    lea             reg_tmp, [iwq-1]
+    cmp                  xq, iwq
+    cmovs           reg_tmp, xq
+    test                 xq, xq
+    cmovs           reg_tmp, reg_zero
+    lea             reg_src, [reg_src+reg_tmp*2]
+%if ARCH_X86_32
+    mov                srcm, reg_src
+%endif
+    ;
+    ; bottom_ext = iclip(y + bh - ih, 0, bh - 1)
+%if ARCH_X86_32
+    mov                  r1, r1m ; restore bh
+%endif
+    lea       reg_bottomext, [yq+bhq]
+    sub       reg_bottomext, ihq
+    lea                  r3, [bhq-1]
+    cmovs     reg_bottomext, reg_zero
+    ;
+
+    DEFINE_ARGS bw, bh, iw, ih, x, \
+                topext, dst, dstride, src, sstride, \
+                bottomext, rightext, blk
+
+    ; top_ext = iclip(-y, 0, bh - 1)
+    neg             topextq
+    cmovs           topextq, reg_zero
+    cmp       reg_bottomext, bhq
+    cmovns    reg_bottomext, r3
+    cmp             topextq, bhq
+    cmovg           topextq, r3
+ %if ARCH_X86_32
+    mov                 r4m, reg_bottomext
+    ;
+    ; right_ext = iclip(x + bw - iw, 0, bw - 1)
+    mov                  r0, r0m ; restore bw
+ %endif
+    lea        reg_rightext, [xq+bwq]
+    sub        reg_rightext, iwq
+    lea                  r2, [bwq-1]
+    cmovs      reg_rightext, reg_zero
+
+    DEFINE_ARGS bw, bh, iw, ih, leftext, \
+                topext, dst, dstride, src, sstride, \
+                bottomext, rightext, blk
+
+    ; left_ext = iclip(-x, 0, bw - 1)
+    neg            leftextq
+    cmovs          leftextq, reg_zero
+    cmp        reg_rightext, bwq
+    cmovns     reg_rightext, r2
+ %if ARCH_X86_32
+    mov                 r3m, r1
+ %endif
+    cmp            leftextq, bwq
+    cmovns         leftextq, r2
+
+%undef reg_zero
+%undef reg_tmp
+%undef reg_src
+%undef reg_bottomext
+%undef reg_rightext
+
+    DEFINE_ARGS bw, centerh, centerw, dummy, leftext, \
+                topext, dst, dstride, src, sstride, \
+                bottomext, rightext, blk
+
+    ; center_h = bh - top_ext - bottom_ext
+%if ARCH_X86_64
+    lea                  r3, [bottomextq+topextq]
+    sub            centerhq, r3
+%else
+    mov                   r1, centerhm ; restore r1
+    sub             centerhq, topextq
+    sub             centerhq, r4m
+    mov                  r1m, centerhq
+%endif
+    ;
+    ; blk += top_ext * PXSTRIDE(dst_stride)
+    mov                  r2, topextq
+%if ARCH_X86_64
+    imul                 r2, dstrideq
+%else
+    mov                  r6, r6m ; restore dstq
+    imul                 r2, dstridem
+%endif
+    add                dstq, r2
+    mov            reg_blkm, dstq ; save pointer for ext
+    ;
+    ; center_w = bw - left_ext - right_ext
+    mov            centerwq, bwq
+%if ARCH_X86_64
+    lea                  r3, [rightextq+leftextq]
+    sub            centerwq, r3
+%else
+    sub            centerwq, r3m
+    sub            centerwq, leftextq
+%endif
+
+; vloop Macro
+%macro v_loop 3 ; need_left_ext, need_right_ext, suffix
+  %if ARCH_X86_64
+    %define reg_tmp        r12
+  %else
+    %define reg_tmp        r0
+  %endif
+.v_loop_%3:
+  %if ARCH_X86_32
+    mov                  r0, r0m
+    mov                  r1, r1m
+  %endif
+%if %1
+    ; left extension
+  %if ARCH_X86_64
+    movd                 m0, [srcq]
+  %else
+    mov                  r3, srcm
+    movd                 m0, [r3]
+  %endif
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+    xor                  r3, r3
+.left_loop_%3:
+    mova        [dstq+r3*2], m0
+    add                  r3, mmsize/2
+    cmp                  r3, leftextq
+    jl .left_loop_%3
+    ; body
+    lea             reg_tmp, [dstq+leftextq*2]
+%endif
+    xor                  r3, r3
+.body_loop_%3:
+  %if ARCH_X86_64
+    movu                 m0, [srcq+r3*2]
+  %else
+    mov                  r1, srcm
+    movu                 m0, [r1+r3*2]
+  %endif
+%if %1
+    movu     [reg_tmp+r3*2], m0
+%else
+    movu        [dstq+r3*2], m0
+%endif
+    add                  r3, mmsize/2
+    cmp                  r3, centerwq
+    jl .body_loop_%3
+%if %2
+    ; right extension
+%if %1
+    lea             reg_tmp, [reg_tmp+centerwq*2]
+%else
+    lea             reg_tmp, [dstq+centerwq*2]
+%endif
+  %if ARCH_X86_64
+    movd                 m0, [srcq+centerwq*2-2]
+  %else
+    mov                  r3, srcm
+    movd                 m0, [r3+centerwq*2-2]
+  %endif
+    pshuflw              m0, m0, q0000
+    punpcklqdq           m0, m0
+    xor                  r3, r3
+.right_loop_%3:
+    movu     [reg_tmp+r3*2], m0
+    add                  r3, mmsize/2
+  %if ARCH_X86_64
+    cmp                  r3, rightextq
+  %else
+    cmp                  r3, r3m
+  %endif
+    jl .right_loop_%3
+%endif
+  %if ARCH_X86_64
+    add                dstq, dstrideq
+    add                srcq, sstrideq
+    dec            centerhq
+    jg .v_loop_%3
+  %else
+    add                dstq, dstridem
+    mov                  r0, sstridem
+    add                srcm, r0
+    sub       dword centerhm, 1
+    jg .v_loop_%3
+    mov                  r0, r0m ; restore r0
+  %endif
+%endmacro ; vloop MACRO
+
+    test           leftextq, leftextq
+    jnz .need_left_ext
+ %if ARCH_X86_64
+    test          rightextq, rightextq
+    jnz .need_right_ext
+ %else
+    cmp            leftextq, r3m ; leftextq == 0
+    jne .need_right_ext
+ %endif
+    v_loop                0, 0, 0
+    jmp .body_done
+
+    ;left right extensions
+.need_left_ext:
+ %if ARCH_X86_64
+    test          rightextq, rightextq
+ %else
+    mov                  r3, r3m
+    test                 r3, r3
+ %endif
+    jnz .need_left_right_ext
+    v_loop                1, 0, 1
+    jmp .body_done
+
+.need_left_right_ext:
+    v_loop                1, 1, 2
+    jmp .body_done
+
+.need_right_ext:
+    v_loop                0, 1, 3
+
+.body_done:
+; r0 ; bw
+; r1 ;; x loop
+; r4 ;; y loop
+; r5 ; topextq
+; r6 ;dstq
+; r7 ;dstrideq
+; r8 ; srcq
+%if ARCH_X86_64
+ %define reg_dstride    dstrideq
+%else
+ %define reg_dstride    r2
+%endif
+    ;
+    ; bottom edge extension
+ %if ARCH_X86_64
+    test         bottomextq, bottomextq
+    jz .top
+ %else
+    xor                  r1, r1
+    cmp                  r1, r4m
+    je .top
+ %endif
+    ;
+ %if ARCH_X86_64
+    mov                srcq, dstq
+    sub                srcq, dstrideq
+    xor                  r1, r1
+ %else
+    mov                  r3, dstq
+    mov         reg_dstride, dstridem
+    sub                  r3, reg_dstride
+    mov                srcm, r3
+ %endif
+    ;
+.bottom_x_loop:
+ %if ARCH_X86_64
+    mova                 m0, [srcq+r1*2]
+    lea                  r3, [dstq+r1*2]
+    mov                  r4, bottomextq
+ %else
+    mov                  r3, srcm
+    mova                 m0, [r3+r1*2]
+    lea                  r3, [dstq+r1*2]
+    mov                  r4, r4m
+ %endif
+    ;
+.bottom_y_loop:
+    mova               [r3], m0
+    add                  r3, reg_dstride
+    dec                  r4
+    jg .bottom_y_loop
+    add                  r1, mmsize/2
+    cmp                  r1, bwq
+    jl .bottom_x_loop
+
+.top:
+    ; top edge extension
+    test            topextq, topextq
+    jz .end
+%if ARCH_X86_64
+    mov                srcq, reg_blkm
+%else
+    mov                  r3, reg_blkm
+    mov         reg_dstride, dstridem
+%endif
+    mov                dstq, dstm
+    xor                  r1, r1
+    ;
+.top_x_loop:
+%if ARCH_X86_64
+    mova                 m0, [srcq+r1*2]
+%else
+    mov                  r3, reg_blkm
+    mova                 m0, [r3+r1*2]
+%endif
+    lea                  r3, [dstq+r1*2]
+    mov                  r4, topextq
+    ;
+.top_y_loop:
+    mova               [r3], m0
+    add                  r3, reg_dstride
+    dec                  r4
+    jg .top_y_loop
+    add                  r1, mmsize/2
+    cmp                  r1, bwq
+    jl .top_x_loop
+
+.end:
+    RET
+
+%undef reg_dstride
+%undef reg_blkm
+%undef reg_tmp
+
+%macro SCRATCH 3
+%if ARCH_X86_32
+    mova [rsp+%3*mmsize], m%1
+%define m%2 [rsp+%3*mmsize]
+%else
+    SWAP             %1, %2
+%endif
+%endmacro
+
+%if ARCH_X86_64
+cglobal resize_16bpc, 0, 12, 16, 1*16, dst, dst_stride, src, src_stride, \
+                                       dst_w, h, src_w, dx, mx0, pxmax
+%elif STACK_ALIGNMENT >= 16
+cglobal resize_16bpc, 0, 7, 8, 6*16, dst, dst_stride, src, src_stride, \
+                                     dst_w, h, src_w, dx, mx0, pxmax
+%else
+cglobal resize_16bpc, 0, 6, 8, 6*16, dst, dst_stride, src, src_stride, \
+                                     dst_w, h, src_w, dx, mx0, pxmax
+%endif
+    movifnidn         dstq, dstmp
+    movifnidn         srcq, srcmp
+%if STACK_ALIGNMENT >= 16
+    movifnidn       dst_wd, dst_wm
+%endif
+%if ARCH_X86_64
+    movifnidn           hd, hm
+%endif
+    sub         dword mx0m, 4<<14
+    sub       dword src_wm, 8
+    movd                m4, pxmaxm
+    movd                m7, dxm
+    movd                m6, mx0m
+    movd                m5, src_wm
+    punpcklwd           m4, m4
+    pshufd              m4, m4, q0000
+    pshufd              m7, m7, q0000
+    pshufd              m6, m6, q0000
+    pshufd              m5, m5, q0000
+    mova [rsp+16*3*ARCH_X86_32], m4
+%if ARCH_X86_64
+ DEFINE_ARGS dst, dst_stride, src, src_stride, dst_w, h, x
+    LEA                 r7, $$
+ %define base r7-$$
+%else
+ DEFINE_ARGS dst, dst_stride, src, src_stride, dst_w, x
+ %define hd dword r5m
+ %if STACK_ALIGNMENT >= 16
+    LEA                 r6, $$
+  %define base r6-$$
+ %else
+    LEA                 r4, $$
+  %define base r4-$$
+ %endif
+%endif
+%if ARCH_X86_64
+    mova               m12, [base+pd_64]
+    mova               m11, [base+pd_63]
+%else
+ %define m12 [base+pd_64]
+ %define m11 [base+pd_63]
+%endif
+    pmaddwd             m4, m7, [base+rescale_mul] ; dx*[0,1,2,3]
+    pslld               m7, 2                      ; dx*4
+    pslld               m5, 14
+    paddd               m6, m4                     ; mx+[0..3]*dx
+    SCRATCH              7, 15, 0
+    SCRATCH              6, 14, 1
+    SCRATCH              5, 13, 2
+    pxor                m1, m1
+.loop_y:
+    xor                 xd, xd
+    mova                m0, m14            ; per-line working version of mx
+.loop_x:
+    pcmpgtd             m1, m0
+    pandn               m1, m0
+    psrad               m2, m0, 8          ; filter offset (unmasked)
+    pcmpgtd             m3, m13, m1
+    pand                m1, m3
+    pandn               m3, m13
+    por                 m1, m3
+    psubd               m3, m0, m1         ; pshufb offset
+    psrad               m1, 14             ; clipped src_x offset
+    psrad               m3, 14             ; pshufb edge_emu offset
+    pand                m2, m11            ; filter offset (masked)
+    ; load source pixels
+%if ARCH_X86_64
+    movd               r8d, m1
+    pshuflw             m1, m1, q3232
+    movd               r9d, m1
+    punpckhqdq          m1, m1
+    movd              r10d, m1
+    psrlq               m1, 32
+    movd              r11d, m1
+    movu                m4, [srcq+r8*2]
+    movu                m5, [srcq+r9*2]
+    movu                m6, [srcq+r10*2]
+    movu                m7, [srcq+r11*2]
+    ; if no emulation is required, we don't need to shuffle or emulate edges
+    packssdw            m3, m3
+    movq               r11, m3
+    test               r11, r11
+    jz .filter
+    movsx               r8, r11w
+    sar                r11, 16
+    movsx               r9, r11w
+    sar                r11, 16
+    movsx              r10, r11w
+    sar                r11, 16
+    movu                m1, [base+resize_shuf+8+r8*2]
+    movu                m3, [base+resize_shuf+8+r9*2]
+    movu                m8, [base+resize_shuf+8+r10*2]
+    movu                m9, [base+resize_shuf+8+r11*2]
+    pshufb              m4, m1
+    pshufb              m5, m3
+    pshufb              m6, m8
+    pshufb              m7, m9
+.filter:
+    movd               r8d, m2
+    pshuflw             m2, m2, q3232
+    movd               r9d, m2
+    punpckhqdq          m2, m2
+    movd              r10d, m2
+    psrlq               m2, 32
+    movd              r11d, m2
+    movq                m8, [base+resize_filter+r8*8]
+    movq                m2, [base+resize_filter+r9*8]
+    pxor                m9, m9
+    punpcklbw           m1, m9, m8
+    punpcklbw           m3, m9, m2
+    psraw               m1, 8
+    psraw               m3, 8
+    movq               m10, [base+resize_filter+r10*8]
+    movq                m2, [base+resize_filter+r11*8]
+    punpcklbw           m8, m9, m10
+    punpcklbw           m9, m2
+    psraw               m8, 8
+    psraw               m9, 8
+    pmaddwd             m4, m1
+    pmaddwd             m5, m3
+    pmaddwd             m6, m8
+    pmaddwd             m7, m9
+    phaddd              m4, m5
+%else
+    movd                r3, m1
+    pshuflw             m1, m1, q3232
+    movd                r1, m1
+    punpckhqdq          m1, m1
+    movu                m4, [srcq+r3*2]
+    movu                m5, [srcq+r1*2]
+    movd                r3, m1
+    psrlq               m1, 32
+    movd                r1, m1
+    movu                m6, [srcq+r3*2]
+    movu                m7, [srcq+r1*2]
+    ; if no emulation is required, we don't need to shuffle or emulate edges
+    pxor                m1, m1
+    pcmpeqb             m1, m3
+    pmovmskb           r3d, m1
+    cmp                r3d, 0xffff
+    je .filter
+    movd                r3, m3
+    movu                m1, [base+resize_shuf+8+r3*2]
+    pshuflw             m3, m3, q3232
+    movd                r1, m3
+    pshufb              m4, m1
+    movu                m1, [base+resize_shuf+8+r1*2]
+    punpckhqdq          m3, m3
+    movd                r3, m3
+    pshufb              m5, m1
+    movu                m1, [base+resize_shuf+8+r3*2]
+    psrlq               m3, 32
+    movd                r1, m3
+    pshufb              m6, m1
+    movu                m1, [base+resize_shuf+8+r1*2]
+    pshufb              m7, m1
+.filter:
+    mova        [esp+4*16], m6
+    mova        [esp+5*16], m7
+    movd                r3, m2
+    pshuflw             m2, m2, q3232
+    movd                r1, m2
+    movq                m6, [base+resize_filter+r3*8]
+    movq                m7, [base+resize_filter+r1*8]
+    pxor                m3, m3
+    punpcklbw           m1, m3, m6
+    punpcklbw           m3, m7
+    psraw               m1, 8
+    psraw               m3, 8
+    pmaddwd             m4, m1
+    pmaddwd             m5, m3
+    punpckhqdq          m2, m2
+    movd                r3, m2
+    psrlq               m2, 32
+    movd                r1, m2
+    phaddd              m4, m5
+    movq                m2, [base+resize_filter+r3*8]
+    movq                m5, [base+resize_filter+r1*8]
+    mova                m6, [esp+4*16]
+    mova                m7, [esp+5*16]
+    pxor                m3, m3
+    punpcklbw           m1, m3, m2
+    punpcklbw           m3, m5
+    psraw               m1, 8
+    psraw               m3, 8
+    pmaddwd             m6, m1
+    pmaddwd             m7, m3
+%endif
+    phaddd              m6, m7
+    phaddd              m4, m6
+    pxor                m1, m1
+    psubd               m2, m12, m4
+    psrad               m2, 7
+    packssdw            m2, m2
+    pmaxsw              m2, m1
+    pminsw              m2, [rsp+16*3*ARCH_X86_32]
+    movq       [dstq+xq*2], m2
+    paddd               m0, m15
+    add                 xd, 4
+%if STACK_ALIGNMENT >= 16
+    cmp                 xd, dst_wd
+%else
+    cmp                 xd, dst_wm
+%endif
+    jl .loop_x
+    add               dstq, dst_stridemp
+    add               srcq, src_stridemp
+    dec                 hd
+    jg .loop_y
+    RET
diff --git a/media/libdav1d/src/src/x86/mc_avx2.asm b/media/libdav1d/src/src/x86/mc_avx2.asm
new file mode 100644
index 0000000000..df8bebb1cb
--- /dev/null
+++ b/media/libdav1d/src/src/x86/mc_avx2.asm
@@ -0,0 +1,6563 @@
+; Copyright © 2018-2021, VideoLAN and dav1d authors
+; Copyright © 2018-2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 32
+
+; dav1d_obmc_masks[] with 64-x interleaved
+obmc_masks:     db  0,  0,  0,  0
+                ; 2
+                db 45, 19, 64,  0
+                ; 4
+                db 39, 25, 50, 14, 59,  5, 64,  0
+                ; 8
+                db 36, 28, 42, 22, 48, 16, 53, 11, 57,  7, 61,  3, 64,  0, 64,  0
+                ; 16
+                db 34, 30, 37, 27, 40, 24, 43, 21, 46, 18, 49, 15, 52, 12, 54, 10
+                db 56,  8, 58,  6, 60,  4, 61,  3, 64,  0, 64,  0, 64,  0, 64,  0
+                ; 32
+                db 33, 31, 35, 29, 36, 28, 38, 26, 40, 24, 41, 23, 43, 21, 44, 20
+                db 45, 19, 47, 17, 48, 16, 50, 14, 51, 13, 52, 12, 53, 11, 55,  9
+                db 56,  8, 57,  7, 58,  6, 59,  5, 60,  4, 60,  4, 61,  3, 62,  2
+                db 64,  0, 64,  0, 64,  0, 64,  0, 64,  0, 64,  0, 64,  0, 64,  0
+
+warp_8x8_shufA: db  0,  2,  4,  6,  1,  3,  5,  7,  1,  3,  5,  7,  2,  4,  6,  8
+                db  4,  6,  8, 10,  5,  7,  9, 11,  5,  7,  9, 11,  6,  8, 10, 12
+warp_8x8_shufB: db  2,  4,  6,  8,  3,  5,  7,  9,  3,  5,  7,  9,  4,  6,  8, 10
+                db  6,  8, 10, 12,  7,  9, 11, 13,  7,  9, 11, 13,  8, 10, 12, 14
+subpel_h_shuf4: db  0,  1,  2,  3,  1,  2,  3,  4,  8,  9, 10, 11,  9, 10, 11, 12
+                db  2,  3,  4,  5,  3,  4,  5,  6, 10, 11, 12, 13, 11, 12, 13, 14
+subpel_h_shufA: db  0,  1,  2,  3,  1,  2,  3,  4,  2,  3,  4,  5,  3,  4,  5,  6
+subpel_h_shufB: db  4,  5,  6,  7,  5,  6,  7,  8,  6,  7,  8,  9,  7,  8,  9, 10
+subpel_h_shufC: db  8,  9, 10, 11,  9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14
+subpel_v_shuf4: db  0,  4,  8, 12,  1,  5,  9, 13,  2,  6, 10, 14,  3,  7, 11, 15
+subpel_s_shuf2: db  0,  1,  2,  3,  0,  1,  2,  3,  8,  9, 10, 11,  8,  9, 10, 11
+subpel_s_shuf8: db  0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+bilin_h_shuf4:  db  0,  1,  1,  2,  2,  3,  3,  4,  8,  9,  9, 10, 10, 11, 11, 12
+bilin_v_shuf4:  db  4,  0,  5,  1,  6,  2,  7,  3,  8,  4,  9,  5, 10,  6, 11,  7
+deint_shuf4:    db  0,  4,  1,  5,  2,  6,  3,  7,  4,  8,  5,  9,  6, 10,  7, 11
+blend_shuf:     db  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  2,  3,  2,  3,  2,  3
+pb_8x0_8x8:     db  0,  0,  0,  0,  0,  0,  0,  0,  8,  8,  8,  8,  8,  8,  8,  8
+bdct_lb_dw:     db  0,  0,  0,  0,  4,  4,  4,  4,  8,  8,  8,  8, 12, 12, 12, 12
+wswap:          db  2,  3,  0,  1,  6,  7,  4,  5, 10, 11,  8,  9, 14, 15, 12, 13
+resize_shuf:    db  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  7,  7,  7,  7
+rescale_mul:    dd  0,  1,  2,  3,  4,  5,  6,  7
+
+wm_420_sign:    dd 0x01020102, 0x01010101
+wm_422_sign:    dd 0x80808080, 0x7f7f7f7f
+
+pb_64:   times 4 db 64
+pw_m256: times 2 dw -256
+pw_15:   times 2 dw 15
+pw_32:   times 2 dw 32
+pw_34:   times 2 dw 34
+pw_258:  times 2 dw 258
+pw_512:  times 2 dw 512
+pw_1024: times 2 dw 1024
+pw_2048: times 2 dw 2048
+pw_6903: times 2 dw 6903
+pw_8192: times 2 dw 8192
+pd_32:           dd 32
+pd_63:           dd 63
+pd_512:          dd 512
+pd_32768:        dd 32768
+pd_0x3ff:        dd 0x3ff
+pd_0x4000:       dd 0x4000
+pq_0x40000000:   dq 0x40000000
+
+cextern mc_subpel_filters
+cextern mc_warp_filter2
+cextern resize_filter
+cextern z_filter_s
+
+%define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8)
+
+%macro BASE_JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base %1_%2
+    %%table:
+    %rep %0 - 2
+        dw %%base %+ _w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro HV_JMP_TABLE 5-*
+    %xdefine %%prefix mangle(private_prefix %+ _%1_%2_8bpc_%3)
+    %xdefine %%base %1_%3
+    %assign %%types %4
+    %if %%types & 1
+        %xdefine %1_%2_h_%3_table  (%%h  - %5)
+        %%h:
+        %rep %0 - 4
+            dw %%prefix %+ .h_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 2
+        %xdefine %1_%2_v_%3_table  (%%v  - %5)
+        %%v:
+        %rep %0 - 4
+            dw %%prefix %+ .v_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 4
+        %xdefine %1_%2_hv_%3_table (%%hv - %5)
+        %%hv:
+        %rep %0 - 4
+            dw %%prefix %+ .hv_w%5 - %%base
+            %rotate 1
+        %endrep
+    %endif
+%endmacro
+
+%macro BIDIR_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - 2*%3)
+    %xdefine %%base %1_%2_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1_8bpc_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%prefix %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro SCALED_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base mangle(private_prefix %+ _%1_8bpc_%2)
+%%table:
+    %rep %0 - 2
+        dw %%base %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+    %rotate 2
+%%dy_1024:
+    %xdefine %1_%2_dy1_table (%%dy_1024 - %3)
+    %rep %0 - 2
+        dw %%base %+ .dy1_w%3 - %%base
+        %rotate 1
+    %endrep
+    %rotate 2
+%%dy_2048:
+    %xdefine %1_%2_dy2_table (%%dy_2048 - %3)
+    %rep %0 - 2
+        dw %%base %+ .dy2_w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%xdefine put_avx2 mangle(private_prefix %+ _put_bilin_8bpc_avx2.put)
+%xdefine prep_avx2 mangle(private_prefix %+ _prep_bilin_8bpc_avx2.prep)
+
+%define table_offset(type, fn) type %+ fn %+ SUFFIX %+ _table - type %+ SUFFIX
+
+BASE_JMP_TABLE   put,  avx2,            2, 4, 8, 16, 32, 64, 128
+BASE_JMP_TABLE   prep, avx2,               4, 8, 16, 32, 64, 128
+HV_JMP_TABLE     put,  bilin, avx2,  7, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE     prep, bilin, avx2,  7,    4, 8, 16, 32, 64, 128
+HV_JMP_TABLE     put,  6tap,  avx2,  3, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE     put,  8tap,  avx2,  3, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE     prep, 6tap,  avx2,  1,    4, 8, 16, 32, 64, 128
+HV_JMP_TABLE     prep, 8tap,  avx2,  1,    4, 8, 16, 32, 64, 128
+SCALED_JMP_TABLE put_8tap_scaled, avx2, 2, 4, 8, 16, 32, 64, 128
+SCALED_JMP_TABLE prep_8tap_scaled, avx2,   4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE  avg, avx2,                4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE  w_avg, avx2,              4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE  mask, avx2,               4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE  w_mask_420, avx2,         4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE  w_mask_422, avx2,         4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE  w_mask_444, avx2,         4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE  blend, avx2,              4, 8, 16, 32
+BIDIR_JMP_TABLE  blend_v, avx2,         2, 4, 8, 16, 32
+BIDIR_JMP_TABLE  blend_h, avx2,         2, 4, 8, 16, 32, 32, 32
+
+SECTION .text
+
+INIT_XMM avx2
+cglobal put_bilin_8bpc, 4, 8, 0, dst, ds, src, ss, w, h, mxy
+    movifnidn          mxyd, r6m ; mx
+    lea                  r7, [put_avx2]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r7m ; my
+    test               mxyd, mxyd
+    jnz .v
+.put:
+    movzx                wd, word [r7+wq*2+table_offset(put,)]
+    add                  wq, r7
+    jmp                  wq
+.put_w2:
+    movzx               r6d, word [srcq+ssq*0]
+    movzx               r7d, word [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6w
+    mov        [dstq+dsq*1], r7w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w2
+    RET
+.put_w4:
+    mov                 r6d, [srcq+ssq*0]
+    mov                 r7d, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6d
+    mov        [dstq+dsq*1], r7d
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w4
+    RET
+.put_w8:
+    mov                  r6, [srcq+ssq*0]
+    mov                  r7, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6
+    mov        [dstq+dsq*1], r7
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w8
+    RET
+.put_w16:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w16
+    RET
+INIT_YMM avx2
+.put_w32:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w32
+    RET
+.put_w64:
+    movu                 m0, [srcq+ssq*0+32*0]
+    movu                 m1, [srcq+ssq*0+32*1]
+    movu                 m2, [srcq+ssq*1+32*0]
+    movu                 m3, [srcq+ssq*1+32*1]
+    lea                srcq, [srcq+ssq*2]
+    mova  [dstq+dsq*0+32*0], m0
+    mova  [dstq+dsq*0+32*1], m1
+    mova  [dstq+dsq*1+32*0], m2
+    mova  [dstq+dsq*1+32*1], m3
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w64
+    RET
+.put_w128:
+    movu                 m0, [srcq+32*0]
+    movu                 m1, [srcq+32*1]
+    movu                 m2, [srcq+32*2]
+    movu                 m3, [srcq+32*3]
+    add                srcq, ssq
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    mova        [dstq+32*2], m2
+    mova        [dstq+32*3], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w128
+    RET
+.h:
+    ; (16 * src[x] + (mx * (src[x + 1] - src[x])) + 8) >> 4
+    ; = ((16 - mx) * src[x] + mx * src[x + 1] + 8) >> 4
+    imul               mxyd, 255
+    vbroadcasti128       m4, [z_filter_s+2]
+    add                mxyd, 16
+    movd                xm5, mxyd
+    mov                mxyd, r7m ; my
+    vpbroadcastw         m5, xm5
+    test               mxyd, mxyd
+    jnz .hv
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_h)]
+    vpbroadcastd         m3, [pw_2048]
+    add                  wq, r7
+    jmp                  wq
+.h_w2:
+    movd                xm0, [srcq+ssq*0]
+    pinsrd              xm0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pshufb              xm0, xm4
+    pmaddubsw           xm0, xm5
+    pmulhrsw            xm0, xm3
+    packuswb            xm0, xm0
+    pextrw     [dstq+dsq*0], xm0, 0
+    pextrw     [dstq+dsq*1], xm0, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2
+    RET
+.h_w4:
+    mova                xm4, [bilin_h_shuf4]
+.h_w4_loop:
+    movq                xm0, [srcq+ssq*0]
+    movhps              xm0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb              xm0, xm4
+    pmaddubsw           xm0, xm5
+    pmulhrsw            xm0, xm3
+    packuswb            xm0, xm0
+    movd       [dstq+dsq*0], xm0
+    pextrd     [dstq+dsq*1], xm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h_w8:
+    movu                xm0, [srcq+ssq*0]
+    movu                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb              xm0, xm4
+    pshufb              xm1, xm4
+    pmaddubsw           xm0, xm5
+    pmaddubsw           xm1, xm5
+    pmulhrsw            xm0, xm3
+    pmulhrsw            xm1, xm3
+    packuswb            xm0, xm1
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    movu                xm0, [srcq+ssq*0+8*0]
+    vinserti128          m0, [srcq+ssq*1+8*0], 1
+    movu                xm1, [srcq+ssq*0+8*1]
+    vinserti128          m1, [srcq+ssq*1+8*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    add                srcq, ssq
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w32
+    RET
+.h_w64:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    movu                 m1, [srcq+8*4]
+    movu                 m2, [srcq+8*5]
+    add                srcq, ssq
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmulhrsw             m1, m3
+    pmulhrsw             m2, m3
+    packuswb             m1, m2
+    mova        [dstq+32*0], m0
+    mova        [dstq+32*1], m1
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w64
+    RET
+.h_w128:
+    mov                  r6, -32*3
+.h_w128_loop:
+    movu                 m0, [srcq+r6+32*3+8*0]
+    movu                 m1, [srcq+r6+32*3+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    mova     [dstq+r6+32*3], m0
+    add                  r6, 32
+    jle .h_w128_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w128
+    RET
+.v:
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_v)]
+    imul               mxyd, 255
+    vpbroadcastd         m5, [pw_2048]
+    add                mxyd, 16
+    add                  wq, r7
+    movd                xm4, mxyd
+    vpbroadcastw         m4, xm4
+    jmp                  wq
+.v_w2:
+    movd                xm0,      [srcq+ssq*0]
+.v_w2_loop:
+    pinsrw              xm1, xm0, [srcq+ssq*1], 1 ; 0 1
+    lea                srcq,      [srcq+ssq*2]
+    pinsrw              xm0, xm1, [srcq+ssq*0], 0 ; 2 1
+    pshuflw             xm1, xm1, q2301           ; 1 0
+    punpcklbw           xm1, xm0
+    pmaddubsw           xm1, xm4
+    pmulhrsw            xm1, xm5
+    packuswb            xm1, xm1
+    pextrw     [dstq+dsq*0], xm1, 1
+    pextrw     [dstq+dsq*1], xm1, 0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movd                xm0, [srcq+ssq*0]
+.v_w4_loop:
+    vpbroadcastd        xm2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd            xm1, xm2, xm0, 0x01 ; 0 1
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    vpblendd            xm2, xm0, 0x02      ; 1 2
+    punpcklbw           xm1, xm2
+    pmaddubsw           xm1, xm4
+    pmulhrsw            xm1, xm5
+    packuswb            xm1, xm1
+    movd       [dstq+dsq*0], xm1
+    pextrd     [dstq+dsq*1], xm1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq                xm0, [srcq+ssq*0]
+.v_w8_loop:
+    movq                xm2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklbw           xm1, xm0, xm2
+    movq                xm0, [srcq+ssq*0]
+    punpcklbw           xm2, xm0
+    pmaddubsw           xm1, xm4
+    pmaddubsw           xm2, xm4
+    pmulhrsw            xm1, xm5
+    pmulhrsw            xm2, xm5
+    packuswb            xm1, xm2
+    movq       [dstq+dsq*0], xm1
+    movhps     [dstq+dsq*1], xm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w16:
+    movu                xm0, [srcq+ssq*0]
+.v_w16_loop:
+    vbroadcasti128       m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd             m2, m3, m0, 0x0f ; 0 1
+    vbroadcasti128       m0, [srcq+ssq*0]
+    vpblendd             m3, m0, 0xf0     ; 1 2
+    punpcklbw            m1, m2, m3
+    punpckhbw            m2, m3
+    pmaddubsw            m1, m4
+    pmaddubsw            m2, m4
+    pmulhrsw             m1, m5
+    pmulhrsw             m2, m5
+    packuswb             m1, m2
+    mova         [dstq+dsq*0], xm1
+    vextracti128 [dstq+dsq*1], m1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+%macro PUT_BILIN_V_W32 0
+    movu                 m0, [srcq+ssq*0]
+%%loop:
+    movu                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklbw            m1, m0, m3
+    punpckhbw            m2, m0, m3
+    movu                 m0, [srcq+ssq*0]
+    pmaddubsw            m1, m4
+    pmaddubsw            m2, m4
+    pmulhrsw             m1, m5
+    pmulhrsw             m2, m5
+    packuswb             m1, m2
+    punpcklbw            m2, m3, m0
+    punpckhbw            m3, m0
+    pmaddubsw            m2, m4
+    pmaddubsw            m3, m4
+    pmulhrsw             m2, m5
+    pmulhrsw             m3, m5
+    packuswb             m2, m3
+    mova       [dstq+dsq*0], m1
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg %%loop
+%endmacro
+    PUT_BILIN_V_W32
+    RET
+.v_w64:
+    movu                 m0, [srcq+32*0]
+    movu                 m1, [srcq+32*1]
+.v_w64_loop:
+    add                srcq, ssq
+    movu                 m3, [srcq+32*0]
+    punpcklbw            m2, m0, m3
+    punpckhbw            m0, m3
+    pmaddubsw            m2, m4
+    pmaddubsw            m0, m4
+    pmulhrsw             m2, m5
+    pmulhrsw             m0, m5
+    packuswb             m2, m0
+    mova                 m0, m3
+    movu                 m3, [srcq+32*1]
+    mova        [dstq+32*0], m2
+    punpcklbw            m2, m1, m3
+    punpckhbw            m1, m3
+    pmaddubsw            m2, m4
+    pmaddubsw            m1, m4
+    pmulhrsw             m2, m5
+    pmulhrsw             m1, m5
+    packuswb             m2, m1
+    mova                 m1, m3
+    mova        [dstq+32*1], m2
+    add                dstq, dsq
+    dec                  hd
+    jg .v_w64_loop
+    RET
+.v_w128:
+    lea                 r6d, [hq+(3<<8)]
+    mov                  r4, srcq
+    mov                  r7, dstq
+.v_w128_loop:
+    PUT_BILIN_V_W32
+    add                  r4, 32
+    add                  r7, 32
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+    sub                 r6d, 1<<8
+    jg .v_w128_loop
+    RET
+.hv:
+    ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 128) >> 8
+    ; = (src[x] + ((my * (src[x + src_stride] - src[x])) >> 4) + 8) >> 4
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_hv)]
+    WIN64_SPILL_XMM       8
+    shl                mxyd, 11 ; can't shift by 12 due to signed overflow
+    vpbroadcastd         m7, [pw_15]
+    movd                xm6, mxyd
+    add                  wq, r7
+    paddb                m5, m5
+    vpbroadcastw         m6, xm6
+    jmp                  wq
+.hv_w2:
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    pshufb              xm0, xm4
+    pmaddubsw           xm0, xm5
+.hv_w2_loop:
+    movd                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pinsrd              xm1, [srcq+ssq*0], 1
+    pshufb              xm1, xm4
+    pmaddubsw           xm1, xm5             ; 1 _ 2 _
+    shufps              xm2, xm0, xm1, q1032 ; 0 _ 1 _
+    mova                xm0, xm1
+    psubw               xm1, xm2
+    pmulhw              xm1, xm6
+    pavgw               xm2, xm7
+    paddw               xm1, xm2
+    psrlw               xm1, 4
+    packuswb            xm1, xm1
+    pextrw     [dstq+dsq*0], xm1, 0
+    pextrw     [dstq+dsq*1], xm1, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    mova                xm4, [bilin_h_shuf4]
+    movddup             xm0, [srcq+ssq*0]
+    pshufb              xm0, xm4
+    pmaddubsw           xm0, xm5
+.hv_w4_loop:
+    movq                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps              xm1, [srcq+ssq*0]
+    pshufb              xm1, xm4
+    pmaddubsw           xm1, xm5             ; 1 2
+    shufps              xm2, xm0, xm1, q1032 ; 0 1
+    mova                xm0, xm1
+    psubw               xm1, xm2
+    pmulhw              xm1, xm6
+    pavgw               xm2, xm7
+    paddw               xm1, xm2
+    psrlw               xm1, 4
+    packuswb            xm1, xm1
+    movd       [dstq+dsq*0], xm1
+    pextrd     [dstq+dsq*1], xm1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    vbroadcasti128       m0, [srcq+ssq*0]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w8_loop:
+    movu                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti128          m1, [srcq+ssq*0], 1
+    pshufb               m1, m4
+    pmaddubsw            m1, m5           ; 1 2
+    vperm2i128           m2, m0, m1, 0x21 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhw               m1, m6
+    pavgw                m2, m7
+    paddw                m1, m2
+    psrlw                m1, 4
+    vextracti128        xm2, m1, 1
+    packuswb            xm1, xm2
+    movq       [dstq+dsq*0], xm1
+    movhps     [dstq+dsq*1], xm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+    movu                 m0, [srcq+ssq*0+8*0]
+    vinserti128          m0, [srcq+ssq*0+8*1], 1
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w16_loop:
+    movu                xm2, [srcq+ssq*1+8*0]
+    vinserti128          m2, [srcq+ssq*1+8*1], 1
+    lea                srcq, [srcq+ssq*2]
+    movu                xm3, [srcq+ssq*0+8*0]
+    vinserti128          m3, [srcq+ssq*0+8*1], 1
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m2, m5
+    psubw                m1, m2, m0
+    pmulhw               m1, m6
+    pavgw                m0, m7
+    paddw                m1, m0
+    pmaddubsw            m0, m3, m5
+    psubw                m3, m0, m2
+    pmulhw               m3, m6
+    pavgw                m2, m7
+    paddw                m3, m2
+    psrlw                m1, 4
+    psrlw                m3, 4
+    packuswb             m1, m3
+    vpermq               m1, m1, q3120
+    mova         [dstq+dsq*0], xm1
+    vextracti128 [dstq+dsq*1], m1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    RET
+.hv_w128:
+    lea                 r6d, [hq+(3<<16)]
+    jmp .hv_w32_start
+.hv_w64:
+    lea                 r6d, [hq+(1<<16)]
+.hv_w32_start:
+    mov                  r4, srcq
+    mov                  r7, dstq
+.hv_w32:
+%if WIN64
+    movaps              r4m, xmm8
+%endif
+.hv_w32_loop0:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+.hv_w32_loop:
+    add                srcq, ssq
+    movu                 m2, [srcq+8*0]
+    movu                 m3, [srcq+8*1]
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    psubw                m8, m2, m0
+    pmulhw               m8, m6
+    pavgw                m0, m7
+    paddw                m8, m0
+    mova                 m0, m2
+    psubw                m2, m3, m1
+    pmulhw               m2, m6
+    pavgw                m1, m7
+    paddw                m2, m1
+    mova                 m1, m3
+    psrlw                m8, 4
+    psrlw                m2, 4
+    packuswb             m8, m2
+    mova             [dstq], m8
+    add                dstq, dsq
+    dec                  hd
+    jg .hv_w32_loop
+    add                  r4, 32
+    add                  r7, 32
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+    sub                 r6d, 1<<16
+    jg .hv_w32_loop0
+%if WIN64
+    movaps             xmm8, r4m
+%endif
+    RET
+
+cglobal prep_bilin_8bpc, 3, 7, 0, tmp, src, stride, w, h, mxy, stride3
+    movifnidn          mxyd, r5m ; mx
+    lea                  r6, [prep%+SUFFIX]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r6m ; my
+    test               mxyd, mxyd
+    jnz .v
+.prep:
+    movzx                wd, word [r6+wq*2+table_offset(prep,)]
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.prep_w4:
+    movd                xm0, [srcq+strideq*0]
+    pinsrd              xm0, [srcq+strideq*1], 1
+    pinsrd              xm0, [srcq+strideq*2], 2
+    pinsrd              xm0, [srcq+stride3q ], 3
+    lea                srcq, [srcq+strideq*4]
+    pmovzxbw             m0, xm0
+    psllw                m0, 4
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .prep_w4
+    RET
+.prep_w8:
+    movq                xm0, [srcq+strideq*0]
+    movhps              xm0, [srcq+strideq*1]
+    movq                xm1, [srcq+strideq*2]
+    movhps              xm1, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    pmovzxbw             m0, xm0
+    pmovzxbw             m1, xm1
+    psllw                m0, 4
+    psllw                m1, 4
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    add                tmpq, 32*2
+    sub                  hd, 4
+    jg .prep_w8
+    RET
+.prep_w16:
+    pmovzxbw             m0, [srcq+strideq*0]
+    pmovzxbw             m1, [srcq+strideq*1]
+    pmovzxbw             m2, [srcq+strideq*2]
+    pmovzxbw             m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    psllw                m0, 4
+    psllw                m1, 4
+    psllw                m2, 4
+    psllw                m3, 4
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    sub                  hd, 4
+    jg .prep_w16
+    RET
+.prep_w32:
+    pmovzxbw             m0, [srcq+strideq*0+16*0]
+    pmovzxbw             m1, [srcq+strideq*0+16*1]
+    pmovzxbw             m2, [srcq+strideq*1+16*0]
+    pmovzxbw             m3, [srcq+strideq*1+16*1]
+    lea                srcq, [srcq+strideq*2]
+    psllw                m0, 4
+    psllw                m1, 4
+    psllw                m2, 4
+    psllw                m3, 4
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    sub                  hd, 2
+    jg .prep_w32
+    RET
+.prep_w64:
+    pmovzxbw             m0, [srcq+16*0]
+    pmovzxbw             m1, [srcq+16*1]
+    pmovzxbw             m2, [srcq+16*2]
+    pmovzxbw             m3, [srcq+16*3]
+    add                srcq, strideq
+    psllw                m0, 4
+    psllw                m1, 4
+    psllw                m2, 4
+    psllw                m3, 4
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    dec                  hd
+    jg .prep_w64
+    RET
+.prep_w128:
+    pmovzxbw             m0, [srcq+16*0]
+    pmovzxbw             m1, [srcq+16*1]
+    pmovzxbw             m2, [srcq+16*2]
+    pmovzxbw             m3, [srcq+16*3]
+    psllw                m0, 4
+    psllw                m1, 4
+    psllw                m2, 4
+    psllw                m3, 4
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    pmovzxbw             m0, [srcq+16*4]
+    pmovzxbw             m1, [srcq+16*5]
+    pmovzxbw             m2, [srcq+16*6]
+    pmovzxbw             m3, [srcq+16*7]
+    add                tmpq, 32*8
+    add                srcq, strideq
+    psllw                m0, 4
+    psllw                m1, 4
+    psllw                m2, 4
+    psllw                m3, 4
+    mova        [tmpq-32*4], m0
+    mova        [tmpq-32*3], m1
+    mova        [tmpq-32*2], m2
+    mova        [tmpq-32*1], m3
+    dec                  hd
+    jg .prep_w128
+    RET
+.h:
+    ; 16 * src[x] + (mx * (src[x + 1] - src[x]))
+    ; = (16 - mx) * src[x] + mx * src[x + 1]
+    imul               mxyd, 255
+    vbroadcasti128       m4, [z_filter_s+2]
+    add                mxyd, 16
+    movd                xm5, mxyd
+    mov                mxyd, r6m ; my
+    vpbroadcastw         m5, xm5
+    test               mxyd, mxyd
+    jnz .hv
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_h)]
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.h_w4:
+    vbroadcasti128       m4, [bilin_h_shuf4]
+.h_w4_loop:
+    movq                xm0, [srcq+strideq*0]
+    movhps              xm0, [srcq+strideq*1]
+    movq                xm1, [srcq+strideq*2]
+    movhps              xm1, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vinserti128          m0, xm1, 1
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4_loop
+    RET
+.h_w8:
+.h_w8_loop:
+    movu                xm0, [srcq+strideq*0]
+    vinserti128          m0, [srcq+strideq*1], 1
+    movu                xm1, [srcq+strideq*2]
+    vinserti128          m1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    add                tmpq, 32*2
+    sub                  hd, 4
+    jg .h_w8_loop
+    RET
+.h_w16:
+.h_w16_loop:
+    movu                xm0, [srcq+strideq*0+8*0]
+    vinserti128          m0, [srcq+strideq*0+8*1], 1
+    movu                xm1, [srcq+strideq*1+8*0]
+    vinserti128          m1, [srcq+strideq*1+8*1], 1
+    movu                xm2, [srcq+strideq*2+8*0]
+    vinserti128          m2, [srcq+strideq*2+8*1], 1
+    movu                xm3, [srcq+stride3q +8*0]
+    vinserti128          m3, [srcq+stride3q +8*1], 1
+    lea                srcq, [srcq+strideq*4]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    sub                  hd, 4
+    jg .h_w16_loop
+    RET
+.h_w32:
+.h_w32_loop:
+    movu                xm0, [srcq+strideq*0+8*0]
+    vinserti128          m0, [srcq+strideq*0+8*1], 1
+    movu                xm1, [srcq+strideq*0+8*2]
+    vinserti128          m1, [srcq+strideq*0+8*3], 1
+    movu                xm2, [srcq+strideq*1+8*0]
+    vinserti128          m2, [srcq+strideq*1+8*1], 1
+    movu                xm3, [srcq+strideq*1+8*2]
+    vinserti128          m3, [srcq+strideq*1+8*3], 1
+    lea                srcq, [srcq+strideq*2]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    sub                  hd, 2
+    jg .h_w32_loop
+    RET
+.h_w64:
+    movu                xm0, [srcq+8*0]
+    vinserti128          m0, [srcq+8*1], 1
+    movu                xm1, [srcq+8*2]
+    vinserti128          m1, [srcq+8*3], 1
+    movu                xm2, [srcq+8*4]
+    vinserti128          m2, [srcq+8*5], 1
+    movu                xm3, [srcq+8*6]
+    vinserti128          m3, [srcq+8*7], 1
+    add                srcq, strideq
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    add                tmpq, 32*4
+    dec                  hd
+    jg .h_w64
+    RET
+.h_w128:
+    movu                xm0, [srcq+8*0]
+    vinserti128          m0, [srcq+8*1], 1
+    movu                xm1, [srcq+8*2]
+    vinserti128          m1, [srcq+8*3], 1
+    movu                xm2, [srcq+8*4]
+    vinserti128          m2, [srcq+8*5], 1
+    movu                xm3, [srcq+8*6]
+    vinserti128          m3, [srcq+8*7], 1
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq+32*0], m0
+    mova        [tmpq+32*1], m1
+    mova        [tmpq+32*2], m2
+    mova        [tmpq+32*3], m3
+    movu                xm0, [srcq+8* 8]
+    vinserti128          m0, [srcq+8* 9], 1
+    movu                xm1, [srcq+8*10]
+    vinserti128          m1, [srcq+8*11], 1
+    movu                xm2, [srcq+8*12]
+    vinserti128          m2, [srcq+8*13], 1
+    movu                xm3, [srcq+8*14]
+    vinserti128          m3, [srcq+8*15], 1
+    add                tmpq, 32*8
+    add                srcq, strideq
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq-32*4], m0
+    mova        [tmpq-32*3], m1
+    mova        [tmpq-32*2], m2
+    mova        [tmpq-32*1], m3
+    dec                  hd
+    jg .h_w128
+    RET
+.v:
+    WIN64_SPILL_XMM       7
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_v)]
+    imul               mxyd, 255
+    add                mxyd, 16
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    movd                xm6, mxyd
+    vpbroadcastw         m6, xm6
+    jmp                  wq
+.v_w4:
+    movd                xm0, [srcq+strideq*0]
+.v_w4_loop:
+    vpbroadcastd         m1, [srcq+strideq*2]
+    vpbroadcastd        xm2, [srcq+strideq*1]
+    vpbroadcastd         m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpblendd             m1, m0, 0x05     ; 0 2 2 2
+    vpbroadcastd         m0, [srcq+strideq*0]
+    vpblendd             m3, m2, 0x0f     ; 1 1 3 3
+    vpblendd             m2, m1, m0, 0xa0 ; 0 2 2 4
+    vpblendd             m1, m3, 0xaa     ; 0 1 2 3
+    vpblendd             m2, m3, 0x55     ; 1 2 3 4
+    punpcklbw            m1, m2
+    pmaddubsw            m1, m6
+    mova             [tmpq], m1
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq                xm0, [srcq+strideq*0]
+.v_w8_loop:
+    vpbroadcastq         m1, [srcq+strideq*2]
+    vpbroadcastq         m2, [srcq+strideq*1]
+    vpbroadcastq         m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpblendd             m1, m0, 0x03     ; 0 2 2 2
+    vpbroadcastq         m0, [srcq+strideq*0]
+    vpblendd             m2, m3, 0xcc     ; 1 3 1 3
+    vpblendd             m3, m2, m1, 0xf0 ; 1 3 2 2
+    vpblendd             m2, m1, 0x0f     ; 0 2 1 3
+    vpblendd             m3, m0, 0xc0     ; 1 3 2 4
+    punpcklbw            m1, m2, m3
+    punpckhbw            m2, m3
+    pmaddubsw            m1, m6
+    pmaddubsw            m2, m6
+    mova        [tmpq+32*0], m1
+    mova        [tmpq+32*1], m2
+    add                tmpq, 32*2
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    vbroadcasti128       m0, [srcq+strideq*0]
+.v_w16_loop:
+    vbroadcasti128       m1, [srcq+strideq*1]
+    vbroadcasti128       m2, [srcq+strideq*2]
+    vbroadcasti128       m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    shufpd               m4, m0, m2, 0x0c ; 0 2
+    vbroadcasti128       m0, [srcq+strideq*0]
+    shufpd               m1, m3, 0x0c     ; 1 3
+    shufpd               m2, m0, 0x0c     ; 2 4
+    punpcklbw            m3, m4, m1
+    punpcklbw            m5, m1, m2
+    punpckhbw            m4, m1
+    punpckhbw            m1, m2
+    pmaddubsw            m3, m6
+    pmaddubsw            m5, m6
+    pmaddubsw            m4, m6
+    pmaddubsw            m1, m6
+    mova        [tmpq+32*0], m3
+    mova        [tmpq+32*1], m5
+    mova        [tmpq+32*2], m4
+    mova        [tmpq+32*3], m1
+    add                tmpq, 32*4
+    sub                  hd, 4
+    jg .v_w16_loop
+    RET
+.v_w32:
+    vpermq               m0, [srcq+strideq*0], q3120
+.v_w32_loop:
+    vpermq               m1, [srcq+strideq*1], q3120
+    vpermq               m2, [srcq+strideq*2], q3120
+    vpermq               m3, [srcq+stride3q ], q3120
+    lea                srcq, [srcq+strideq*4]
+    punpcklbw            m4, m0, m1
+    punpckhbw            m5, m0, m1
+    vpermq               m0, [srcq+strideq*0], q3120
+    pmaddubsw            m4, m6
+    pmaddubsw            m5, m6
+    mova        [tmpq+32*0], m4
+    mova        [tmpq+32*1], m5
+    punpcklbw            m4, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m4, m6
+    pmaddubsw            m1, m6
+    punpcklbw            m5, m2, m3
+    punpckhbw            m2, m3
+    pmaddubsw            m5, m6
+    pmaddubsw            m2, m6
+    mova        [tmpq+32*2], m4
+    mova        [tmpq+32*3], m1
+    add                tmpq, 32*8
+    punpcklbw            m1, m3, m0
+    punpckhbw            m3, m0
+    pmaddubsw            m1, m6
+    pmaddubsw            m3, m6
+    mova        [tmpq-32*4], m5
+    mova        [tmpq-32*3], m2
+    mova        [tmpq-32*2], m1
+    mova        [tmpq-32*1], m3
+    sub                  hd, 4
+    jg .v_w32_loop
+    RET
+.v_w64:
+    vpermq               m0, [srcq+strideq*0+32*0], q3120
+    vpermq               m1, [srcq+strideq*0+32*1], q3120
+.v_w64_loop:
+    vpermq               m2, [srcq+strideq*1+32*0], q3120
+    vpermq               m3, [srcq+strideq*1+32*1], q3120
+    lea                srcq, [srcq+strideq*2]
+    punpcklbw            m4, m0, m2
+    punpckhbw            m0, m2
+    pmaddubsw            m4, m6
+    pmaddubsw            m0, m6
+    mova        [tmpq+32*0], m4
+    mova        [tmpq+32*1], m0
+    punpcklbw            m4, m1, m3
+    punpckhbw            m5, m1, m3
+    vpermq               m0, [srcq+strideq*0+32*0], q3120
+    vpermq               m1, [srcq+strideq*0+32*1], q3120
+    pmaddubsw            m4, m6
+    pmaddubsw            m5, m6
+    mova        [tmpq+32*2], m4
+    mova        [tmpq+32*3], m5
+    add                tmpq, 32*8
+    punpcklbw            m4, m2, m0
+    punpckhbw            m2, m0
+    punpcklbw            m5, m3, m1
+    punpckhbw            m3, m1
+    pmaddubsw            m4, m6
+    pmaddubsw            m2, m6
+    pmaddubsw            m5, m6
+    pmaddubsw            m3, m6
+    mova        [tmpq-32*4], m4
+    mova        [tmpq-32*3], m2
+    mova        [tmpq-32*2], m5
+    mova        [tmpq-32*1], m3
+    sub                  hd, 2
+    jg .v_w64_loop
+    RET
+.v_w128:
+    lea                 r6d, [hq+(3<<8)]
+    mov                  r3, srcq
+    mov                  r5, tmpq
+.v_w128_loop0:
+    vpermq               m0, [srcq+strideq*0], q3120
+.v_w128_loop:
+    vpermq               m1, [srcq+strideq*1], q3120
+    lea                srcq, [srcq+strideq*2]
+    punpcklbw            m2, m0, m1
+    punpckhbw            m3, m0, m1
+    vpermq               m0, [srcq+strideq*0], q3120
+    pmaddubsw            m2, m6
+    pmaddubsw            m3, m6
+    punpcklbw            m4, m1, m0
+    punpckhbw            m1, m0
+    pmaddubsw            m4, m6
+    pmaddubsw            m1, m6
+    mova        [tmpq+32*0], m2
+    mova        [tmpq+32*1], m3
+    mova        [tmpq+32*8], m4
+    mova        [tmpq+32*9], m1
+    add                tmpq, 32*16
+    sub                  hd, 2
+    jg .v_w128_loop
+    add                  r3, 32
+    add                  r5, 64
+    movzx                hd, r6b
+    mov                srcq, r3
+    mov                tmpq, r5
+    sub                 r6d, 1<<8
+    jg .v_w128_loop0
+    RET
+.hv:
+    ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 8) >> 4
+    ; = src[x] + (((my * (src[x + src_stride] - src[x])) + 8) >> 4)
+    WIN64_SPILL_XMM       7
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_hv)]
+    shl                mxyd, 11
+    movd                xm6, mxyd
+    vpbroadcastw         m6, xm6
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.hv_w4:
+    vbroadcasti128       m4, [bilin_h_shuf4]
+    vpbroadcastq         m0, [srcq+strideq*0]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w4_loop:
+    movq                xm1, [srcq+strideq*1]
+    movhps              xm1, [srcq+strideq*2]
+    movq                xm2, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    movhps              xm2, [srcq+strideq*0]
+    vinserti128          m1, xm2, 1
+    pshufb               m1, m4
+    pmaddubsw            m1, m5        ; 1 2 3 4
+    vpblendd             m2, m1, m0, 0xc0
+    vpermq               m2, m2, q2103 ; 0 1 2 3
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhrsw             m1, m6
+    paddw                m1, m2
+    mova             [tmpq], m1
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    vbroadcasti128       m0, [srcq+strideq*0]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w8_loop:
+    movu                xm1, [srcq+strideq*1]
+    vinserti128          m1, [srcq+strideq*2], 1
+    movu                xm2, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vinserti128          m2, [srcq+strideq*0], 1
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pmaddubsw            m1, m5           ; 1 2
+    vperm2i128           m3, m0, m1, 0x21 ; 0 1
+    pmaddubsw            m0, m2, m5       ; 3 4
+    vperm2i128           m2, m1, m0, 0x21 ; 2 3
+    psubw                m1, m3
+    pmulhrsw             m1, m6
+    paddw                m1, m3
+    psubw                m3, m0, m2
+    pmulhrsw             m3, m6
+    paddw                m3, m2
+    mova        [tmpq+32*0], m1
+    mova        [tmpq+32*1], m3
+    add                tmpq, 32*2
+    sub                  hd, 4
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+    movu                xm0, [srcq+strideq*0+8*0]
+    vinserti128          m0, [srcq+strideq*0+8*1], 1
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w16_loop:
+    movu                xm1, [srcq+strideq*1+8*0]
+    vinserti128          m1, [srcq+strideq*1+8*1], 1
+    lea                srcq, [srcq+strideq*2]
+    movu                xm2, [srcq+strideq*0+8*0]
+    vinserti128          m2, [srcq+strideq*0+8*1], 1
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pmaddubsw            m1, m5
+    psubw                m3, m1, m0
+    pmulhrsw             m3, m6
+    paddw                m3, m0
+    pmaddubsw            m0, m2, m5
+    psubw                m2, m0, m1
+    pmulhrsw             m2, m6
+    paddw                m2, m1
+    mova        [tmpq+32*0], m3
+    mova        [tmpq+32*1], m2
+    add                tmpq, 32*2
+    sub                  hd, 2
+    jg .hv_w16_loop
+    RET
+.hv_w32:
+    movu                xm0, [srcq+8*0]
+    vinserti128          m0, [srcq+8*1], 1
+    movu                xm1, [srcq+8*2]
+    vinserti128          m1, [srcq+8*3], 1
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+.hv_w32_loop:
+    add                srcq, strideq
+    movu                xm2, [srcq+8*0]
+    vinserti128          m2, [srcq+8*1], 1
+    pshufb               m2, m4
+    pmaddubsw            m2, m5
+    psubw                m3, m2, m0
+    pmulhrsw             m3, m6
+    paddw                m3, m0
+    mova                 m0, m2
+    movu                xm2, [srcq+8*2]
+    vinserti128          m2, [srcq+8*3], 1
+    pshufb               m2, m4
+    pmaddubsw            m2, m5
+    mova        [tmpq+32*0], m3
+    psubw                m3, m2, m1
+    pmulhrsw             m3, m6
+    paddw                m3, m1
+    mova                 m1, m2
+    mova        [tmpq+32*1], m3
+    add                tmpq, 32*2
+    dec                  hd
+    jg .hv_w32_loop
+    RET
+.hv_w128:
+    lea                 r3d, [hq+(7<<8)]
+    mov                 r6d, 256
+    jmp .hv_w64_start
+.hv_w64:
+    lea                 r3d, [hq+(3<<8)]
+    mov                 r6d, 128
+.hv_w64_start:
+%if WIN64
+    PUSH                 r7
+%endif
+    mov                  r5, srcq
+    mov                  r7, tmpq
+.hv_w64_loop0:
+    movu                xm0, [srcq+strideq*0+8*0]
+    vinserti128          m0, [srcq+strideq*0+8*1], 1
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w64_loop:
+    movu                xm1, [srcq+strideq*1+8*0]
+    vinserti128          m1, [srcq+strideq*1+8*1], 1
+    lea                srcq, [srcq+strideq*2]
+    movu                xm2, [srcq+strideq*0+8*0]
+    vinserti128          m2, [srcq+strideq*0+8*1], 1
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pmaddubsw            m1, m5
+    psubw                m3, m1, m0
+    pmulhrsw             m3, m6
+    paddw                m3, m0
+    pmaddubsw            m0, m2, m5
+    psubw                m2, m0, m1
+    pmulhrsw             m2, m6
+    paddw                m2, m1
+    mova        [tmpq+r6*0], m3
+    mova        [tmpq+r6*1], m2
+    lea                tmpq, [tmpq+r6*2]
+    sub                  hd, 2
+    jg .hv_w64_loop
+    add                  r5, 16
+    add                  r7, 32
+    movzx                hd, r3b
+    mov                srcq, r5
+    mov                tmpq, r7
+    sub                 r3d, 1<<8
+    jg .hv_w64_loop0
+%if WIN64
+    POP                  r7
+%endif
+    RET
+
+; int8_t subpel_filters[5][15][8]
+%assign FILTER_REGULAR (0*15 << 16) | 3*15
+%assign FILTER_SMOOTH  (1*15 << 16) | 4*15
+%assign FILTER_SHARP   (2*15 << 16) | 3*15
+
+%macro FN 4-5 ; fn, type, type_h, type_v, jmp_to
+cglobal %1_%2_8bpc
+    mov                 t0d, FILTER_%3
+%ifidn %3, %4
+    mov                 t1d, t0d
+%else
+    mov                 t1d, FILTER_%4
+%endif
+%if %0 == 5 ; skip the jump in the last filter
+    jmp mangle(private_prefix %+ _%5 %+ SUFFIX)
+%endif
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 4, 5
+%else
+DECLARE_REG_TMP 7, 8
+%endif
+
+%define PUT_8TAP_FN FN put_8tap,
+PUT_8TAP_FN smooth,         SMOOTH,  SMOOTH,  put_6tap_8bpc
+PUT_8TAP_FN smooth_regular, SMOOTH,  REGULAR, put_6tap_8bpc
+PUT_8TAP_FN regular_smooth, REGULAR, SMOOTH,  put_6tap_8bpc
+PUT_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal put_6tap_8bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my, ns
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    lea                  r8, [put_avx2]
+    mov                  wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.put:
+    tzcnt                wd, wd
+    movzx                wd, word [r8+wq*2+table_offset(put,)]
+    add                  wq, r8
+    lea                  r6, [ssq*3]
+    lea                  r7, [dsq*3]
+%if WIN64
+    pop                  r8
+%endif
+    jmp                  wq
+.h_w2:
+    movzx               mxd, mxb
+    lea                srcq, [srcq-1]
+    vpbroadcastd        xm4, [r8+mxq*8+subpel_filters-put_avx2+2]
+    je .h_w4
+    mova                xm3, [subpel_h_shuf4]
+.h_w2_loop:
+    movq                xm0, [srcq+ssq*0]
+    movhps              xm0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb              xm0, xm3
+    pmaddubsw           xm0, xm4
+    phaddw              xm0, xm0
+    paddw               xm0, xm5
+    psraw               xm0, 6
+    packuswb            xm0, xm0
+    pextrw     [dstq+dsq*0], xm0, 0
+    pextrw     [dstq+dsq*1], xm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2_loop
+    RET
+.h_w4:
+    mova                xm3, [subpel_h_shufA]
+.h_w4_loop:
+    movq                xm0, [srcq+ssq*0]
+    movq                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb              xm0, xm3
+    pshufb              xm1, xm3
+    pmaddubsw           xm0, xm4
+    pmaddubsw           xm1, xm4
+    phaddw              xm0, xm1
+    paddw               xm0, xm5
+    psraw               xm0, 6
+    packuswb            xm0, xm0
+    movd       [dstq+dsq*0], xm0
+    pextrd     [dstq+dsq*1], xm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h:
+    test                myd, 0xf00
+    jnz .hv
+    vpbroadcastd         m5, [pw_34] ; 2 + (8 << 2)
+    cmp                  wd, 4
+    jle .h_w2
+    WIN64_SPILL_XMM      11
+    tzcnt                wd, wd
+    vbroadcasti128       m4, [z_filter_s+ 2] ; 01
+    shr                 mxd, 16
+    vbroadcasti128       m6, [z_filter_s+ 6] ; 23
+    sub                srcq, 2
+    vbroadcasti128       m7, [z_filter_s+10] ; 45
+    lea                 mxq, [r8+mxq*8+subpel_filters+1-put_avx2]
+    movzx                wd, word [r8+wq*2+table_offset(put, _6tap_h)]
+    vpbroadcastw         m8, [mxq+0]
+    vpbroadcastw         m9, [mxq+2]
+    add                  wq, r8
+    vpbroadcastw        m10, [mxq+4]
+    jmp                  wq
+.h_w8:
+%macro PUT_6TAP_H 3 ; dst/src, tmp[1-2]
+    pshufb              m%2, m%1, m4
+    pmaddubsw           m%2, m8
+    pshufb              m%3, m%1, m6
+    pmaddubsw           m%3, m9
+    pshufb              m%1, m7
+    pmaddubsw           m%1, m10
+    paddw               m%2, m5
+    paddw               m%1, m%3
+    paddw               m%1, m%2
+    psraw               m%1, 6
+%endmacro
+    movu                xm0, [srcq+ssq*0]
+    vinserti128          m0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    PUT_6TAP_H            0, 1, 2
+    vextracti128        xm1, m0, 1
+    packuswb            xm0, xm1
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    movu                xm0, [srcq+ssq*0+8*0]
+    vinserti128          m0, [srcq+ssq*1+8*0], 1
+    movu                xm1, [srcq+ssq*0+8*1]
+    vinserti128          m1, [srcq+ssq*1+8*1], 1
+    PUT_6TAP_H            0, 2, 3
+    lea                srcq, [srcq+ssq*2]
+    PUT_6TAP_H            1, 2, 3
+    packuswb             m0, m1
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+    xor                 r6d, r6d
+    jmp .h_start
+.h_w64:
+    mov                  r6, -32*1
+    jmp .h_start
+.h_w128:
+    mov                  r6, -32*3
+.h_start:
+    sub                srcq, r6
+    sub                dstq, r6
+    mov                  r4, r6
+.h_loop:
+    movu                 m0, [srcq+r6+8*0]
+    movu                 m1, [srcq+r6+8*1]
+    PUT_6TAP_H            0, 2, 3
+    PUT_6TAP_H            1, 2, 3
+    packuswb             m0, m1
+    mova          [dstq+r6], m0
+    add                  r6, 32
+    jle .h_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    mov                  r6, r4
+    dec                  hd
+    jg .h_loop
+    RET
+.v:
+    WIN64_SPILL_XMM       9, 12
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    tzcnt               r6d, wd
+    movzx               r6d, word [r8+r6*2+table_offset(put, _6tap_v)]
+    vpbroadcastd         m8, [pw_512]
+    lea                 myq, [r8+myq*8+subpel_filters+1-put_avx2]
+    vpbroadcastw         m5, [myq+0]
+    vpbroadcastw         m6, [myq+2]
+    vpbroadcastw         m7, [myq+4]
+    add                  r6, r8
+    mov                 nsq, ssq
+    neg                 nsq
+    jmp                  r6
+.v_w2:
+    movd                xm2, [srcq+nsq*2]
+    pinsrw              xm2, [srcq+nsq*1], 2
+    pinsrw              xm2, [srcq+ssq*0], 4
+    pinsrw              xm2, [srcq+ssq*1], 6 ; 0 1 2 3
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    palignr             xm3, xm0, xm2, 4     ; 1 2 3 4
+    punpcklbw           xm1, xm2, xm3        ; 01 12
+    punpckhbw           xm2, xm3             ; 23 34
+.v_w2_loop:
+    vpbroadcastd        xm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw           xm3, xm1, xm5        ; a0 b0
+    mova                xm1, xm2
+    pmaddubsw           xm2, xm6             ; a1 b1
+    paddw               xm3, xm2
+    vpblendd            xm2, xm0, xm4, 0x02  ; 4 5
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    vpblendd            xm4, xm0, 0x02       ; 5 6
+    punpcklbw           xm2, xm4             ; 67 78
+    pmaddubsw           xm4, xm2, xm7        ; a3 b3
+    paddw               xm3, xm4
+    pmulhrsw            xm3, xm8
+    packuswb            xm3, xm3
+    pextrw     [dstq+dsq*0], xm3, 0
+    pextrw     [dstq+dsq*1], xm3, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movd                xm2, [srcq+nsq*2]
+    pinsrd              xm2, [srcq+nsq*1], 1
+    pinsrd              xm2, [srcq+ssq*0], 2
+    pinsrd              xm2, [srcq+ssq*1], 3 ; 0 1 2 3
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    palignr             xm3, xm0, xm2, 4     ; 1 2 3 4
+    punpcklbw           xm1, xm2, xm3        ; 01 12
+    punpckhbw           xm2, xm3             ; 23 34
+.v_w4_loop:
+    vpbroadcastd        xm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw           xm3, xm1, xm5        ; a0 b0
+    mova                xm1, xm2
+    pmaddubsw           xm2, xm6             ; a1 b1
+    paddw               xm3, xm2
+    vpblendd            xm2, xm0, xm4, 0x02  ; 4 5
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    vpblendd            xm4, xm0, 0x02       ; 5 6
+    punpcklbw           xm2, xm4             ; 45 56
+    pmaddubsw           xm4, xm2, xm7        ; a2 b2
+    paddw               xm3, xm4
+    pmulhrsw            xm3, xm8
+    packuswb            xm3, xm3
+    movd       [dstq+dsq*0], xm3
+    pextrd     [dstq+dsq*1], xm3, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq                xm1, [srcq+nsq*2]
+    vpbroadcastq         m3, [srcq+nsq*1]
+    vpbroadcastq         m2, [srcq+ssq*0]
+    vpbroadcastq         m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m1, m3, 0x30
+    vpblendd             m3, m2, 0x30
+    punpcklbw            m1, m3      ; 01 12
+    vpblendd             m2, m4, 0x30
+    vpblendd             m4, m0, 0x30
+    punpcklbw            m2, m4      ; 23 34
+.v_w8_loop:
+    vpbroadcastq         m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw            m3, m1, m5  ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, m6      ; a1 b1
+    paddw                m3, m2
+    vpblendd             m2, m0, m4, 0x30
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m4, m0, 0x30
+    punpcklbw            m2, m4      ; 45 56
+    pmaddubsw            m4, m2, m7  ; a2 b2
+    paddw                m3, m4
+    pmulhrsw             m3, m8
+    vextracti128        xm4, m3, 1
+    packuswb            xm3, xm4
+    movq       [dstq+dsq*0], xm3
+    movhps     [dstq+dsq*1], xm3
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w16:
+.v_w32:
+.v_w64:
+.v_w128:
+    lea                 r6d, [wq*8-128]
+    WIN64_PUSH_XMM       12
+    lea                 r6d, [hq+r6*2]
+.v_w16_loop0:
+    vbroadcasti128       m3, [srcq+nsq*2]
+    vbroadcasti128       m4, [srcq+nsq*1]
+    lea                  r4, [srcq+ssq*2]
+    vbroadcasti128       m0, [srcq+ssq*0]
+    vbroadcasti128       m1, [srcq+ssq*1]
+    mov                  r7, dstq
+    vbroadcasti128       m2, [r4+ssq*0]
+    shufpd               m3, m0, 0x0c
+    shufpd               m4, m1, 0x0c
+    punpcklbw            m1, m3, m4 ; 01
+    punpckhbw            m3, m4     ; 23
+    shufpd               m0, m2, 0x0c
+    punpcklbw            m2, m4, m0 ; 12
+    punpckhbw            m4, m0     ; 34
+.v_w16_loop:
+    vbroadcasti128       m9, [r4+ssq*1]
+    pmaddubsw           m10, m1, m5  ; a0
+    lea                  r4, [r4+ssq*2]
+    pmaddubsw           m11, m2, m5  ; b0
+    mova                 m1, m3
+    pmaddubsw            m3, m6      ; a1
+    mova                 m2, m4
+    pmaddubsw            m4, m6      ; b1
+    paddw               m10, m3
+    vbroadcasti128       m3, [r4+ssq*0]
+    paddw               m11, m4
+    shufpd               m4, m0, m9, 0x0d
+    shufpd               m0, m9, m3, 0x0c
+    punpcklbw            m3, m4, m0  ; 45
+    punpckhbw            m4, m0      ; 56
+    pmaddubsw            m9, m3, m7  ; a2
+    paddw               m10, m9
+    pmaddubsw            m9, m4, m7  ; b2
+    paddw               m11, m9
+    pmulhrsw            m10, m8
+    pmulhrsw            m11, m8
+    packuswb            m10, m11
+    vpermq              m10, m10, q3120
+    mova         [r7+dsq*0], xm10
+    vextracti128 [r7+dsq*1], m10, 1
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_w16_loop0
+    RET
+.hv:
+    WIN64_SPILL_XMM      12, 16
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    dec                srcq
+    vpbroadcastd         m6, [r8+mxq*8+subpel_filters-put_avx2+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m0, [r8+myq*8+subpel_filters+1-put_avx2]
+    vpbroadcastd         m7, [pw_8192]
+    punpcklbw            m0, m0
+    vpbroadcastd         m8, [pd_512]
+    psraw                m0, 8 ; sign-extend
+    mov                 nsq, ssq
+    pshufd               m9, m0, q0000
+    neg                 nsq
+    pshufd              m10, m0, q1111
+    pshufd              m11, m0, q2222
+    cmp                  wd, 4
+    je .hv_w4
+    vbroadcasti128       m5, [subpel_h_shuf4]
+    movq                xm2, [srcq+nsq*2]
+    movhps              xm2, [srcq+nsq*1]
+    movq                xm0, [srcq+ssq*0]
+    movhps              xm0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastq         m1, [srcq+ssq*0]
+    vpblendd             m2, m1, 0x30
+    pshufb               m2, m5
+    pshufb              xm0, xm5
+    pmaddubsw            m2, m6
+    pmaddubsw           xm0, xm6
+    phaddw               m2, m0
+    pmulhrsw             m2, m7
+    vextracti128        xm0, m2, 1
+    palignr             xm0, xm2, 4
+    punpcklwd           xm1, xm2, xm0  ; 01 12
+    punpckhwd           xm2, xm0       ; 23 34
+.hv_w2_loop:
+    movq                xm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps              xm4, [srcq+ssq*0]
+    pshufb              xm4, xm5
+    pmaddubsw           xm4, xm6
+    pmaddwd             xm3, xm9, xm1  ; a0 b0
+    mova                xm1, xm2
+    pmaddwd             xm2, xm10      ; a1 b1
+    phaddw              xm4, xm4
+    paddd               xm3, xm2
+    pmulhrsw            xm4, xm7
+    palignr             xm2, xm4, xm0, 12
+    mova                xm0, xm4
+    punpcklwd           xm2, xm4       ; 45 56
+    pmaddwd             xm4, xm11, xm2 ; a2 b2
+    paddd               xm3, xm8
+    paddd               xm3, xm4
+    psrad               xm3, 10
+    packssdw            xm3, xm3
+    packuswb            xm3, xm3
+    pextrw     [dstq+dsq*0], xm3, 0
+    pextrw     [dstq+dsq*1], xm3, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    mova                 m5, [subpel_h_shuf4]
+    vpbroadcastq         m2, [srcq+nsq*2]
+    vpbroadcastq         m4, [srcq+nsq*1]
+    vpbroadcastq         m1, [srcq+ssq*0]
+    vpbroadcastq         m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m2, m4, 0xcc ; 0 1
+    vpblendd             m1, m3, 0xcc ; 2 3
+    pshufb               m2, m5
+    pshufb               m1, m5
+    pshufb               m0, m5
+    pmaddubsw            m2, m6
+    pmaddubsw            m1, m6
+    pmaddubsw            m0, m6
+    phaddw               m2, m1
+    phaddw               m0, m0
+    pmulhrsw             m2, m7
+    pmulhrsw             m0, m7
+    palignr              m3, m0, m2, 4
+    punpcklwd            m1, m2, m3   ; 01 12
+    punpckhwd            m2, m3       ; 23 34
+.hv_w4_loop:
+    vpbroadcastq         m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m3, m9, m1   ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m10      ; a1 b1
+    paddd                m3, m2
+    vpbroadcastq         m2, [srcq+ssq*0]
+    vpblendd             m4, m2, 0xcc ; 5 6
+    pshufb               m4, m5
+    pmaddubsw            m4, m6
+    phaddw               m4, m4
+    pmulhrsw             m4, m7
+    palignr              m2, m4, m0, 12
+    mova                 m0, m4
+    punpcklwd            m2, m4       ; 45 56
+    pmaddwd              m4, m11, m2  ; a2 b2
+    paddd                m3, m8
+    paddd                m3, m4
+    psrad                m3, 10
+    vextracti128        xm4, m3, 1
+    packssdw            xm3, xm4
+    packuswb            xm3, xm3
+    pshuflw             xm3, xm3, q3120
+    movd       [dstq+dsq*0], xm3
+    pextrd     [dstq+dsq*1], xm3, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    sub                srcq, 2
+    lea                 mxq, [r8+mxq*8+subpel_filters+1-put_avx2]
+    WIN64_PUSH_XMM       16
+    vpbroadcastw        m10, [mxq+0]
+    vpbroadcastw        m11, [mxq+2]
+    vpbroadcastw        m12, [mxq+4]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m0, [r8+myq*8+subpel_filters+1-put_avx2]
+    lea                 r6d, [wq*8-64]
+    vbroadcasti128       m8, [z_filter_s+ 6]
+    punpcklbw            m0, m0
+    vbroadcasti128       m9, [z_filter_s+10]
+    psraw                m0, 8 ; sign-extend
+    mov                 nsq, ssq
+    pshufd              m13, m0, q0000
+    neg                 nsq
+    pshufd              m14, m0, q1111
+    lea                 r6d, [hq+r6*4]
+    pshufd              m15, m0, q2222
+.hv_w8_loop0:
+    vbroadcasti128       m7, [z_filter_s+2]
+    movu                xm3, [srcq+nsq*2]
+    lea                  r4, [srcq+ssq*2]
+    movu                xm4, [srcq+nsq*1]
+    vbroadcasti128       m0, [srcq+ssq*0]
+    mov                  r7, dstq
+    vinserti128          m4, [srcq+ssq*1], 1 ; 1 3
+    vpblendd             m3, m0, 0xf0        ; 0 2
+    vinserti128          m0, [r4+ssq*0], 1   ; 2 4
+    vpbroadcastd         m5, [pw_8192]
+%macro HV_H_6TAP_W8 6 ; src/dst, tmp[1-2], shuf[1-3]
+    pshufb               %2, %1, %4
+    pmaddubsw            %2, m10
+    pshufb               %3, %1, %5
+    pmaddubsw            %3, m11
+    pshufb               %1, %6
+    pmaddubsw            %1, m12
+    paddw                %2, %3
+    paddw                %1, %2
+%endmacro
+    HV_H_6TAP_W8         m3, m1, m2, m7, m8, m9
+    HV_H_6TAP_W8         m4, m1, m2, m7, m8, m9
+    HV_H_6TAP_W8         m0, m1, m2, m7, m8, m9
+    vpermq               m3, m3, q3120
+    vpermq               m4, m4, q3120
+    vpermq               m0, m0, q3120
+    pmulhrsw             m3, m5
+    pmulhrsw             m4, m5
+    pmulhrsw             m0, m5
+    punpcklwd            m1, m3, m4  ; 01
+    punpckhwd            m3, m4      ; 23
+    punpcklwd            m2, m4, m0  ; 12
+    punpckhwd            m4, m0      ; 34
+.hv_w8_loop:
+    movu                xm7, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+    vinserti128          m7, [r4+ssq*0], 1 ; 5 6
+    pmaddwd              m5, m13, m1 ; a0
+    mova                 m1, m3
+    pmaddwd              m6, m13, m2 ; b0
+    mova                 m2, m4
+    pmaddwd              m3, m14     ; a1
+    pmaddwd              m4, m14     ; b1
+    paddd                m5, m3
+    vbroadcasti128       m3, [z_filter_s+2]
+    paddd                m6, m4
+    HV_H_6TAP_W8         m7, m3, m4, m3, m8, m9
+    vpbroadcastd         m3, [pw_8192]
+    vpbroadcastd         m4, [pd_512]
+    pmulhrsw             m7, m3
+    paddd                m5, m4
+    paddd                m6, m4
+    mova                 m4, m0
+    vpermq               m0, m7, q3120
+    shufpd               m4, m0, 0x05
+    punpcklwd            m3, m4, m0  ; 45
+    pmaddwd              m7, m15, m3 ; a2
+    punpckhwd            m4, m0      ; 67
+    paddd                m5, m7
+    pmaddwd              m7, m15, m4 ; b2
+    paddd                m6, m7
+    psrad                m5, 10
+    psrad                m6, 10
+    packssdw             m5, m6
+    vextracti128        xm6, m5, 1
+    packuswb            xm5, xm6
+    pshufd              xm5, xm5, q3120
+    movq         [r7+dsq*0], xm5
+    movhps       [r7+dsq*1], xm5
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 8
+    add                dstq, 8
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .hv_w8_loop0
+    RET
+
+PUT_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,  put_8tap_8bpc
+PUT_8TAP_FN sharp_smooth,   SHARP,   SMOOTH, put_8tap_8bpc
+PUT_8TAP_FN regular_sharp,  REGULAR, SHARP,  put_8tap_8bpc
+PUT_8TAP_FN sharp_regular,  SHARP,   REGULAR, put_8tap_8bpc
+PUT_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal put_8tap_8bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    lea                  r8, [put_avx2]
+    movsxd               wq, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _put_6tap_8bpc_avx2).put
+.v:
+    WIN64_SPILL_XMM      12, 15
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    tzcnt               r6d, wd
+    movzx               r6d, word [r8+r6*2+table_offset(put, _8tap_v)]
+    vpbroadcastd         m7, [pw_512]
+    lea                 myq, [r8+myq*8+subpel_filters-put_avx2]
+    vpbroadcastw         m8, [myq+0]
+    vpbroadcastw         m9, [myq+2]
+    vpbroadcastw        m10, [myq+4]
+    vpbroadcastw        m11, [myq+6]
+    add                  r6, r8
+    lea                ss3q, [ssq*3]
+    sub                srcq, ss3q
+    jmp                  r6
+.v_w2:
+    movd                xm2, [srcq+ssq*0]
+    pinsrw              xm2, [srcq+ssq*1], 2
+    pinsrw              xm2, [srcq+ssq*2], 4
+    add                srcq, ss3q
+    pinsrw              xm2, [srcq+ssq*0], 6 ; 0 1 2 3
+    movd                xm3, [srcq+ssq*1]
+    vpbroadcastd        xm1, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    vpblendd            xm3, xm1, 0x02       ; 4 5
+    vpblendd            xm1, xm0, 0x02       ; 5 6
+    palignr             xm4, xm3, xm2, 4     ; 1 2 3 4
+    punpcklbw           xm3, xm1             ; 45 56
+    punpcklbw           xm1, xm2, xm4        ; 01 12
+    punpckhbw           xm2, xm4             ; 23 34
+.v_w2_loop:
+    pmaddubsw           xm5, xm1, xm8        ; a0 b0
+    mova                xm1, xm2
+    pmaddubsw           xm2, xm9             ; a1 b1
+    paddw               xm5, xm2
+    mova                xm2, xm3
+    pmaddubsw           xm3, xm10            ; a2 b2
+    paddw               xm5, xm3
+    vpbroadcastd        xm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd            xm3, xm0, xm4, 0x02  ; 6 7
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    vpblendd            xm4, xm0, 0x02       ; 7 8
+    punpcklbw           xm3, xm4             ; 67 78
+    pmaddubsw           xm4, xm3, xm11       ; a3 b3
+    paddw               xm5, xm4
+    pmulhrsw            xm5, xm7
+    packuswb            xm5, xm5
+    pextrw     [dstq+dsq*0], xm5, 0
+    pextrw     [dstq+dsq*1], xm5, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movd                xm2, [srcq+ssq*0]
+    pinsrd              xm2, [srcq+ssq*1], 1
+    pinsrd              xm2, [srcq+ssq*2], 2
+    add                srcq, ss3q
+    pinsrd              xm2, [srcq+ssq*0], 3 ; 0 1 2 3
+    movd                xm3, [srcq+ssq*1]
+    vpbroadcastd        xm1, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    vpblendd            xm3, xm1, 0x02       ; 4 5
+    vpblendd            xm1, xm0, 0x02       ; 5 6
+    palignr             xm4, xm3, xm2, 4     ; 1 2 3 4
+    punpcklbw           xm3, xm1             ; 45 56
+    punpcklbw           xm1, xm2, xm4        ; 01 12
+    punpckhbw           xm2, xm4             ; 23 34
+.v_w4_loop:
+    pmaddubsw           xm5, xm1, xm8        ; a0 b0
+    mova                xm1, xm2
+    pmaddubsw           xm2, xm9             ; a1 b1
+    paddw               xm5, xm2
+    mova                xm2, xm3
+    pmaddubsw           xm3, xm10            ; a2 b2
+    paddw               xm5, xm3
+    vpbroadcastd        xm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd            xm3, xm0, xm4, 0x02  ; 6 7
+    vpbroadcastd        xm0, [srcq+ssq*0]
+    vpblendd            xm4, xm0, 0x02       ; 7 8
+    punpcklbw           xm3, xm4             ; 67 78
+    pmaddubsw           xm4, xm3, xm11       ; a3 b3
+    paddw               xm5, xm4
+    pmulhrsw            xm5, xm7
+    packuswb            xm5, xm5
+    movd       [dstq+dsq*0], xm5
+    pextrd     [dstq+dsq*1], xm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq                xm1, [srcq+ssq*0]
+    vpbroadcastq         m4, [srcq+ssq*1]
+    vpbroadcastq         m2, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastq         m5, [srcq+ssq*0]
+    vpbroadcastq         m3, [srcq+ssq*1]
+    vpbroadcastq         m6, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m1, m4, 0x30
+    vpblendd             m4, m2, 0x30
+    punpcklbw            m1, m4      ; 01 12
+    vpblendd             m2, m5, 0x30
+    vpblendd             m5, m3, 0x30
+    punpcklbw            m2, m5      ; 23 34
+    vpblendd             m3, m6, 0x30
+    vpblendd             m6, m0, 0x30
+    punpcklbw            m3, m6      ; 45 56
+.v_w8_loop:
+    vpbroadcastq         m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw            m5, m1, m8  ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, m9      ; a1 b1
+    paddw                m5, m2
+    mova                 m2, m3
+    pmaddubsw            m3, m10     ; a2 b2
+    paddw                m5, m3
+    vpblendd             m3, m0, m4, 0x30
+    vpbroadcastq         m0, [srcq+ssq*0]
+    vpblendd             m4, m0, 0x30
+    punpcklbw            m3, m4      ; 67 78
+    pmaddubsw            m4, m3, m11 ; a3 b3
+    paddw                m5, m4
+    pmulhrsw             m5, m7
+    vextracti128        xm4, m5, 1
+    packuswb            xm5, xm4
+    movq       [dstq+dsq*0], xm5
+    movhps     [dstq+dsq*1], xm5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w16:
+.v_w32:
+.v_w64:
+.v_w128:
+    lea                 r6d, [wq*8-128]
+    WIN64_PUSH_XMM       15
+    lea                 r6d, [hq+r6*2]
+.v_w16_loop0:
+    vbroadcasti128       m4, [srcq+ssq*0]
+    vbroadcasti128       m5, [srcq+ssq*1]
+    lea                  r4, [srcq+ss3q]
+    vbroadcasti128       m6, [srcq+ssq*2]
+    vbroadcasti128       m0, [r4+ssq*0]
+    mov                  r7, dstq
+    vbroadcasti128       m1, [r4+ssq*1]
+    vbroadcasti128       m2, [r4+ssq*2]
+    add                  r4, ss3q
+    vbroadcasti128       m3, [r4+ssq*0]
+    shufpd               m4, m0, 0x0c
+    shufpd               m5, m1, 0x0c
+    punpcklbw            m1, m4, m5 ; 01
+    punpckhbw            m4, m5     ; 34
+    shufpd               m6, m2, 0x0c
+    punpcklbw            m2, m5, m6 ; 12
+    punpckhbw            m5, m6     ; 45
+    shufpd               m0, m3, 0x0c
+    punpcklbw            m3, m6, m0 ; 23
+    punpckhbw            m6, m0     ; 56
+.v_w16_loop:
+    vbroadcasti128      m12, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+    pmaddubsw           m13, m1, m8  ; a0
+    pmaddubsw           m14, m2, m8  ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddubsw            m3, m9      ; a1
+    pmaddubsw            m4, m9      ; b1
+    paddw               m13, m3
+    paddw               m14, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddubsw            m5, m10     ; a2
+    pmaddubsw            m6, m10     ; b2
+    paddw               m13, m5
+    vbroadcasti128       m5, [r4+ssq*0]
+    paddw               m14, m6
+    shufpd               m6, m0, m12, 0x0d
+    shufpd               m0, m12, m5, 0x0c
+    punpcklbw            m5, m6, m0  ; 67
+    punpckhbw            m6, m0      ; 78
+    pmaddubsw           m12, m5, m11 ; a3
+    paddw               m13, m12
+    pmaddubsw           m12, m6, m11 ; b3
+    paddw               m14, m12
+    pmulhrsw            m13, m7
+    pmulhrsw            m14, m7
+    packuswb            m13, m14
+    vpermq              m13, m13, q3120
+    mova         [r7+dsq*0], xm13
+    vextracti128 [r7+dsq*1], m13, 1
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_w16_loop0
+    RET
+.h:
+.h_w2:
+.h_w4:
+    test                myd, 0xf00
+    jnz .hv
+    vpbroadcastd         m5, [pw_34] ; 2 + (8 << 2)
+    cmp                  wd, 4
+    jle mangle(private_prefix %+ _put_6tap_8bpc_avx2).h_w2
+    WIN64_SPILL_XMM      11
+    tzcnt                wd, wd
+    vbroadcasti128       m6, [subpel_h_shufA]
+    shr                 mxd, 16
+    vbroadcasti128       m7, [subpel_h_shufB]
+    sub                srcq, 3
+    vbroadcasti128       m8, [subpel_h_shufC]
+    movzx                wd, word [r8+wq*2+table_offset(put, _8tap_h)]
+    vpbroadcastd         m9, [r8+mxq*8+subpel_filters-put_avx2+0]
+    vpbroadcastd        m10, [r8+mxq*8+subpel_filters-put_avx2+4]
+    add                  wq, r8
+    jmp                  wq
+.h_w8:
+%macro PUT_8TAP_H 4 ; dst/src, tmp[1-3]
+    pshufb              m%2, m%1, m7
+    pshufb              m%3, m%1, m8
+    pshufb              m%1, m6
+    pmaddubsw           m%4, m%2, m9
+    pmaddubsw           m%2, m10
+    pmaddubsw           m%3, m10
+    pmaddubsw           m%1, m9
+    paddw               m%3, m%4
+    paddw               m%1, m%2
+    phaddw              m%1, m%3
+    paddw               m%1, m5
+    psraw               m%1, 6
+%endmacro
+    movu                xm0, [srcq+ssq*0]
+    vinserti128          m0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_H            0, 1, 2, 3
+    vextracti128        xm1, m0, 1
+    packuswb            xm0, xm1
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    movu                xm0, [srcq+ssq*0+8*0]
+    vinserti128          m0, [srcq+ssq*1+8*0], 1
+    movu                xm1, [srcq+ssq*0+8*1]
+    vinserti128          m1, [srcq+ssq*1+8*1], 1
+    PUT_8TAP_H            0, 2, 3, 4
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_H            1, 2, 3, 4
+    packuswb             m0, m1
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+    xor                 r6d, r6d
+    jmp .h_start
+.h_w64:
+    mov                  r6, -32*1
+    jmp .h_start
+.h_w128:
+    mov                  r6, -32*3
+.h_start:
+    sub                srcq, r6
+    sub                dstq, r6
+    mov                  r4, r6
+.h_loop:
+    movu                 m0, [srcq+r6+8*0]
+    movu                 m1, [srcq+r6+8*1]
+    PUT_8TAP_H            0, 2, 3, 4
+    PUT_8TAP_H            1, 2, 3, 4
+    packuswb             m0, m1
+    mova          [dstq+r6], m0
+    add                  r6, 32
+    jle .h_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    mov                  r6, r4
+    dec                  hd
+    jg .h_loop
+    RET
+.hv:
+    WIN64_SPILL_XMM      14, 16
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    dec                srcq
+    vpbroadcastd         m7, [r8+mxq*8+subpel_filters-put_avx2+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m0, [r8+myq*8+subpel_filters-put_avx2]
+    lea                ss3q, [ssq*3]
+    sub                srcq, ss3q
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    vpbroadcastd         m8, [pw_8192]
+    vpbroadcastd         m9, [pd_512]
+    pshufd              m10, m0, q0000
+    pshufd              m11, m0, q1111
+    pshufd              m12, m0, q2222
+    pshufd              m13, m0, q3333
+    cmp                  wd, 4
+    je .hv_w4
+    vbroadcasti128       m6, [subpel_h_shuf4]
+    movq                xm2, [srcq+ssq*0]
+    movhps              xm2, [srcq+ssq*1]
+    movq                xm0, [srcq+ssq*2]
+    add                srcq, ss3q
+    movhps              xm0, [srcq+ssq*0]
+    vpbroadcastq         m3, [srcq+ssq*1]
+    vpbroadcastq         m4, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastq         m1, [srcq+ssq*0]
+    vpblendd             m2, m3, 0x30
+    vpblendd             m0, m1, 0x30
+    vpblendd             m2, m4, 0xc0
+    pshufb               m2, m6
+    pshufb               m0, m6
+    pmaddubsw            m2, m7
+    pmaddubsw            m0, m7
+    phaddw               m2, m0
+    pmulhrsw             m2, m8
+    vextracti128        xm3, m2, 1
+    palignr             xm4, xm3, xm2, 4
+    punpcklwd           xm1, xm2, xm4  ; 01 12
+    punpckhwd           xm2, xm4       ; 23 34
+    pshufd              xm0, xm3, q2121
+    punpcklwd           xm3, xm0       ; 45 56
+.hv_w2_loop:
+    movq                xm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps              xm4, [srcq+ssq*0]
+    pshufb              xm4, xm6
+    pmaddubsw           xm4, xm7
+    pmaddwd             xm5, xm1, xm10 ; a0 b0
+    mova                xm1, xm2
+    pmaddwd             xm2, xm11      ; a1 b1
+    paddd               xm5, xm2
+    mova                xm2, xm3
+    pmaddwd             xm3, xm12      ; a2 b2
+    phaddw              xm4, xm4
+    pmulhrsw            xm4, xm8
+    paddd               xm5, xm3
+    palignr             xm3, xm4, xm0, 12
+    mova                xm0, xm4
+    punpcklwd           xm3, xm0       ; 67 78
+    pmaddwd             xm4, xm3, xm13 ; a3 b3
+    paddd               xm5, xm9
+    paddd               xm5, xm4
+    psrad               xm5, 10
+    packssdw            xm5, xm5
+    packuswb            xm5, xm5
+    pextrw     [dstq+dsq*0], xm5, 0
+    pextrw     [dstq+dsq*1], xm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    mova                 m6, [subpel_h_shuf4]
+    vpbroadcastq         m2, [srcq+ssq*0]
+    vpbroadcastq         m4, [srcq+ssq*1]
+    vpbroadcastq         m0, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastq         m5, [srcq+ssq*0]
+    vpbroadcastq         m3, [srcq+ssq*1]
+    vpblendd             m2, m4, 0xcc ; 0 1
+    vpbroadcastq         m4, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastq         m1, [srcq+ssq*0]
+    vpblendd             m0, m5, 0xcc ; 2 3
+    vpblendd             m3, m4, 0xcc ; 4 5
+    pshufb               m2, m6
+    pshufb               m0, m6
+    pshufb               m3, m6
+    pshufb               m1, m6
+    pmaddubsw            m2, m7
+    pmaddubsw            m0, m7
+    pmaddubsw            m3, m7
+    pmaddubsw            m1, m7
+    phaddw               m2, m0
+    phaddw               m3, m1
+    pmulhrsw             m2, m8
+    pmulhrsw             m3, m8
+    palignr              m4, m3, m2, 4
+    punpcklwd            m1, m2, m4   ; 01 12
+    punpckhwd            m2, m4       ; 23 34
+    pshufd               m0, m3, q2121
+    punpcklwd            m3, m0       ; 45 56
+.hv_w4_loop:
+    vpbroadcastq         m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m5, m1, m10  ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m11      ; a1 b1
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, m12      ; a2 b2
+    paddd                m5, m3
+    vpbroadcastq         m3, [srcq+ssq*0]
+    vpblendd             m4, m3, 0xcc ; 7 8
+    pshufb               m4, m6
+    pmaddubsw            m4, m7
+    phaddw               m4, m4
+    pmulhrsw             m4, m8
+    palignr              m3, m4, m0, 12
+    mova                 m0, m4
+    punpcklwd            m3, m0       ; 67 78
+    pmaddwd              m4, m3, m13  ; a3 b3
+    paddd                m5, m9
+    paddd                m5, m4
+    psrad                m5, 10
+    vextracti128        xm4, m5, 1
+    packssdw            xm5, xm4
+    packuswb            xm5, xm5
+    pshuflw             xm5, xm5, q3120
+    movd       [dstq+dsq*0], xm5
+    pextrd     [dstq+dsq*1], xm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    WIN64_PUSH_XMM       16
+    shr                 mxd, 16
+    sub                srcq, 3
+    vpbroadcastd        m10, [r8+mxq*8+subpel_filters-put_avx2+0]
+    vpbroadcastd        m11, [r8+mxq*8+subpel_filters-put_avx2+4]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m0, [r8+myq*8+subpel_filters-put_avx2]
+    lea                ss3q, [ssq*3]
+    sub                srcq, ss3q
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    pshufd              m12, m0, q0000
+    pshufd              m13, m0, q1111
+    pshufd              m14, m0, q2222
+    pshufd              m15, m0, q3333
+    lea                 r6d, [wq*8-64]
+    lea                 r6d, [hq+r6*4]
+.hv_w8_loop0:
+    vbroadcasti128       m7, [subpel_h_shufA]
+    movu                xm4, [srcq+ssq*0]
+    lea                  r4, [srcq+ss3q]
+    vbroadcasti128       m8, [subpel_h_shufB]
+    movu                xm5, [srcq+ssq*1]
+    mov                  r7, dstq
+    vbroadcasti128       m9, [subpel_h_shufC]
+    movu                xm6, [srcq+ssq*2]
+    vbroadcasti128       m0, [r4+ssq*0]
+    vpblendd             m4, m0, 0xf0      ; 0 3
+    vinserti128          m5, [r4+ssq*1], 1 ; 1 4
+    vinserti128          m6, [r4+ssq*2], 1 ; 2 5
+    add                  r4, ss3q
+    vinserti128          m0, [r4+ssq*0], 1 ; 3 6
+%macro HV_H_8TAP_W8 4-7 ; src/dst, tmp[1-3], shuf[1-3]
+    pshufb               %3, %1, %6
+    pshufb               %4, %1, %7
+    pshufb               %1, %5
+    pmaddubsw            %2, %3, m10
+    pmaddubsw            %4, m11
+    pmaddubsw            %3, m11
+    pmaddubsw            %1, m10
+    paddw                %2, %4
+    paddw                %1, %3
+    phaddw               %1, %2
+%endmacro
+    HV_H_8TAP_W8         m4, m1, m2, m3, m7, m8, m9
+    HV_H_8TAP_W8         m5, m1, m2, m3, m7, m8, m9
+    HV_H_8TAP_W8         m6, m1, m2, m3, m7, m8, m9
+    HV_H_8TAP_W8         m0, m1, m2, m3, m7, m8, m9
+    vpbroadcastd         m7, [pw_8192]
+    vpermq               m4, m4, q3120
+    vpermq               m5, m5, q3120
+    vpermq               m6, m6, q3120
+    pmulhrsw             m0, m7
+    pmulhrsw             m4, m7
+    pmulhrsw             m5, m7
+    pmulhrsw             m6, m7
+    vpermq               m7, m0, q3120
+    punpcklwd            m1, m4, m5  ; 01
+    punpckhwd            m4, m5      ; 34
+    punpcklwd            m2, m5, m6  ; 12
+    punpckhwd            m5, m6      ; 45
+    punpcklwd            m3, m6, m7  ; 23
+    punpckhwd            m6, m7      ; 56
+.hv_w8_loop:
+    vextracti128        r6m, m0, 1 ; not enough registers
+    movu                xm0, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+    vinserti128          m0, [r4+ssq*0], 1 ; 7 8
+    pmaddwd              m8, m1, m12 ; a0
+    pmaddwd              m9, m2, m12 ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddwd              m3, m13     ; a1
+    pmaddwd              m4, m13     ; b1
+    paddd                m8, m3
+    paddd                m9, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddwd              m5, m14     ; a2
+    pmaddwd              m6, m14     ; b2
+    paddd                m8, m5
+    paddd                m9, m6
+    vbroadcasti128       m6, [subpel_h_shufB]
+    vbroadcasti128       m7, [subpel_h_shufC]
+    vbroadcasti128       m5, [subpel_h_shufA]
+    HV_H_8TAP_W8         m0, m5, m6, m7, m5, m6, m7
+    vpbroadcastd         m5, [pw_8192]
+    vpbroadcastd         m7, [pd_512]
+    vbroadcasti128       m6, r6m
+    pmulhrsw             m0, m5
+    paddd                m8, m7
+    paddd                m9, m7
+    vpermq               m7, m0, q3120 ; 7 8
+    shufpd               m6, m7, 0x04  ; 6 7
+    punpcklwd            m5, m6, m7  ; 67
+    punpckhwd            m6, m7      ; 78
+    pmaddwd              m7, m5, m15 ; a3
+    paddd                m8, m7
+    pmaddwd              m7, m6, m15 ; b3
+    paddd                m7, m9
+    psrad                m8, 10
+    psrad                m7, 10
+    packssdw             m8, m7
+    vextracti128        xm7, m8, 1
+    packuswb            xm8, xm7
+    pshufd              xm7, xm8, q3120
+    movq         [r7+dsq*0], xm7
+    movhps       [r7+dsq*1], xm7
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 8
+    add                dstq, 8
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .hv_w8_loop0
+    RET
+
+%if WIN64
+DECLARE_REG_TMP 6, 4
+%else
+DECLARE_REG_TMP 6, 7
+%endif
+
+%define PREP_8TAP_FN FN prep_8tap,
+PREP_8TAP_FN smooth,         SMOOTH,  SMOOTH,  prep_6tap_8bpc
+PREP_8TAP_FN smooth_regular, SMOOTH,  REGULAR, prep_6tap_8bpc
+PREP_8TAP_FN regular_smooth, REGULAR, SMOOTH,  prep_6tap_8bpc
+PREP_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal prep_6tap_8bpc, 3, 8, 0, tmp, src, ss, w, h, mx, my, ns
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    lea                  r7, [prep%+SUFFIX]
+    mov                  wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.prep:
+    tzcnt                wd, wd
+    movzx                wd, word [r7+wq*2+table_offset(prep,)]
+    add                  wq, r7
+    lea                  r6, [ssq*3]
+%if WIN64
+    pop                  r7
+%endif
+    jmp                  wq
+.v:
+    WIN64_SPILL_XMM      10, 12
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    lea                 myq, [r7+myq*8+subpel_filters+1-prep%+SUFFIX]
+    vpbroadcastd         m9, [pw_8192]
+    vpbroadcastw         m6, [myq+0]
+    mov                 nsq, ssq
+    vpbroadcastw         m7, [myq+2]
+    neg                 nsq
+    vpbroadcastw         m8, [myq+4]
+    cmp                  wd, 8
+    jg .v_w16
+    je .v_w8
+.v_w4:
+    movd                xm2, [srcq+nsq*2]
+    pinsrd              xm2, [srcq+nsq*1], 1
+    vpbroadcastd         m1, [srcq+ssq*0]
+    vpbroadcastd         m3, [srcq+ssq*1]
+    vpbroadcastd         m0, [srcq+ssq*2]
+    vbroadcasti128       m5, [deint_shuf4]
+    vpblendd             m1, m2, 0xeb
+    punpcklqdq           m3, m0
+    vpblendd             m1, m3, 0x60 ; 0 1 2 _   2 3 4 _
+    pshufb               m1, m5       ; 01  12    23  34
+.v_w4_loop:
+    lea                srcq, [srcq+ssq*4]
+    pinsrd              xm0, [srcq+nsq*1], 1
+    vpbroadcastd         m2, [srcq+ssq*0]
+    vpbroadcastd         m3, [srcq+ssq*1]
+    vpblendd             m2, m0, 0xeb
+    vpbroadcastd         m0, [srcq+ssq*2]
+    punpcklqdq           m3, m0
+    vpblendd             m2, m3, 0x60 ; 4 5 6 _   6 7 8 _
+    pshufb               m2, m5       ; 45  56    67  78
+    pmaddubsw            m3, m1, m6   ; a0  b0    c0  d0
+    vperm2i128           m1, m2, 0x21 ; 23  34    45  56
+    pmaddubsw            m4, m2, m8   ; a2  b2    c2  d2
+    pmaddubsw            m1, m7       ; a1  b1    c1  d1
+    paddw                m3, m4
+    paddw                m3, m1
+    pmulhrsw             m3, m9
+    mova                 m1, m2
+    mova             [tmpq], m3
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq                xm1, [srcq+nsq*2]
+    vpbroadcastq         m3, [srcq+nsq*1]
+    vpbroadcastq         m2, [srcq+ssq*0]
+    vpbroadcastq         m4, [srcq+ssq*1]
+    vpbroadcastq         m0, [srcq+ssq*2]
+    vpblendd             m1, m3, 0x30
+    vpblendd             m3, m2, 0x30
+    punpcklbw            m1, m3     ; 01 12
+    vpblendd             m2, m4, 0x30
+    vpblendd             m4, m0, 0x30
+    punpcklbw            m2, m4     ; 23 34
+.v_w8_loop:
+    lea                srcq, [srcq+ssq*4]
+    pmaddubsw            m1, m6     ; a0
+    vpbroadcastq         m3, [srcq+nsq*1]
+    pmaddubsw            m4, m2, m7 ; a1
+    pmaddubsw            m5, m2, m6 ; b0
+    vpbroadcastq         m2, [srcq+ssq*0]
+    vpblendd             m0, m3, 0x30
+    vpblendd             m3, m2, 0x30
+    paddw                m4, m1
+    punpcklbw            m1, m0, m3 ; 45 56
+    vpbroadcastq         m3, [srcq+ssq*1]
+    vpbroadcastq         m0, [srcq+ssq*2]
+    vpblendd             m2, m3, 0x30
+    vpblendd             m3, m0, 0x30
+    punpcklbw            m2, m3     ; 67 78
+    pmaddubsw            m3, m1, m7 ; b1
+    paddw                m5, m3
+    pmaddubsw            m3, m1, m8 ; a2
+    paddw                m4, m3
+    pmaddubsw            m3, m2, m8 ; b2
+    paddw                m5, m3
+    pmulhrsw             m4, m9
+    pmulhrsw             m5, m9
+    mova        [tmpq+32*0], m4
+    mova        [tmpq+32*1], m5
+    add                tmpq, 32*2
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    lea                 r6d, [wq*2-32]
+    lea                srcq, [srcq+nsq*2]
+    WIN64_PUSH_XMM       12
+    lea                 r6d, [hq+r6*8]
+.v_w16_loop0:
+    vbroadcasti128       m3, [srcq+ssq*0]
+    lea                  r5, [srcq+ssq*2]
+    vbroadcasti128       m4, [srcq+ssq*1]
+    mov                  r7, tmpq
+    vbroadcasti128       m0, [r5+ssq*0]
+    vbroadcasti128       m1, [r5+ssq*1]
+    lea                  r5, [r5+ssq*2]
+    vbroadcasti128       m2, [r5+ssq*0]
+    shufpd               m3, m0, 0x0c
+    shufpd               m4, m1, 0x0c
+    punpcklbw            m1, m3, m4 ; 01
+    punpckhbw            m3, m4     ; 23
+    shufpd               m0, m2, 0x0c
+    punpcklbw            m2, m4, m0 ; 12
+    punpckhbw            m4, m0     ; 34
+.v_w16_loop:
+    vbroadcasti128       m5, [r5+ssq*1]
+    pmaddubsw           m10, m1, m6 ; a0
+    lea                  r5, [r5+ssq*2]
+    pmaddubsw           m11, m2, m6 ; b0
+    mova                 m1, m3
+    pmaddubsw            m3, m7     ; a1
+    mova                 m2, m4
+    pmaddubsw            m4, m7     ; b1
+    paddw               m10, m3
+    vbroadcasti128       m3, [r5+ssq*0]
+    paddw               m11, m4
+    shufpd               m4, m0, m5, 0x0d
+    shufpd               m0, m5, m3, 0x0c
+    punpcklbw            m3, m4, m0 ; 45
+    punpckhbw            m4, m0     ; 56
+    pmaddubsw            m5, m3, m8 ; a2
+    paddw               m10, m5
+    pmaddubsw            m5, m4, m8 ; b2
+    paddw               m11, m5
+    pmulhrsw            m10, m9
+    pmulhrsw            m11, m9
+    mova          [r7+wq*0], m10
+    mova          [r7+wq*2], m11
+    lea                  r7, [r7+wq*4]
+    sub                  hd, 2
+    jg .v_w16_loop
+    add                srcq, 16
+    add                tmpq, 32
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_w16_loop0
+    RET
+.h_w4:
+    RESET_STACK_STATE
+    movzx               mxd, mxb
+    vbroadcasti128       m3, [subpel_h_shufA]
+    dec                srcq
+    vpbroadcastd         m5, [r7+mxq*8+subpel_filters-prep%+SUFFIX+2]
+    lea                  r3, [ssq*3]
+.h_w4_loop:
+    movq                xm0, [srcq+ssq*0]
+    vpbroadcastq         m2, [srcq+ssq*2]
+    movq                xm1, [srcq+ssq*1]
+    vpblendd             m0, m2, 0x30
+    vpbroadcastq         m2, [srcq+r3   ]
+    lea                srcq, [srcq+ssq*4]
+    vpblendd             m1, m2, 0x30
+    pshufb               m0, m3
+    pshufb               m1, m3
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    phaddw               m0, m1
+    pmulhrsw             m0, m4
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4_loop
+    RET
+.h:
+    test                myd, 0xf00
+    jnz .hv
+    vpbroadcastd         m4, [pw_8192]
+    cmp                  wd, 4
+    je .h_w4
+    WIN64_SPILL_XMM      10
+    tzcnt                wd, wd
+    vbroadcasti128       m3, [z_filter_s+ 2]
+    shr                 mxd, 16
+    vbroadcasti128       m5, [z_filter_s+ 6]
+    sub                srcq, 2
+    vbroadcasti128       m6, [z_filter_s+10]
+    lea                 mxq, [r7+mxq*8+subpel_filters+1-prep%+SUFFIX]
+    movzx                wd, word [r7+wq*2+table_offset(prep, _6tap_h)]
+    vpbroadcastw         m7, [mxq+0]
+    vpbroadcastw         m8, [mxq+2]
+    add                  wq, r7
+    vpbroadcastw         m9, [mxq+4]
+    jmp                  wq
+.h_w8:
+    movu                xm0, [srcq+ssq*0]
+    vinserti128          m0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+%macro PREP_6TAP_H 0
+    pshufb               m1, m0, m3
+    pmaddubsw            m1, m7
+    pshufb               m2, m0, m5
+    pmaddubsw            m2, m8
+    pshufb               m0, m6
+    pmaddubsw            m0, m9
+    paddw                m1, m2
+    paddw                m0, m1
+    pmulhrsw             m0, m4
+%endmacro
+    PREP_6TAP_H
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    movu                xm0, [srcq+ssq*0+8*0]
+    vinserti128          m0, [srcq+ssq*0+8*1], 1
+    PREP_6TAP_H
+    mova        [tmpq+32*0], m0
+    movu                xm0, [srcq+ssq*1+8*0]
+    vinserti128          m0, [srcq+ssq*1+8*1], 1
+    lea                srcq, [srcq+ssq*2]
+    PREP_6TAP_H
+    mova        [tmpq+32*1], m0
+    add                tmpq, 32*2
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+    xor                 r6d, r6d
+    jmp .h_start
+.h_w64:
+    mov                  r6, -32*1
+    jmp .h_start
+.h_w128:
+    mov                  r6, -32*3
+.h_start:
+    sub                srcq, r6
+    mov                  r5, r6
+.h_loop:
+    movu                xm0, [srcq+r6+8*0]
+    vinserti128          m0, [srcq+r6+8*1], 1
+    PREP_6TAP_H
+    mova        [tmpq+32*0], m0
+    movu                xm0, [srcq+r6+8*2]
+    vinserti128          m0, [srcq+r6+8*3], 1
+    PREP_6TAP_H
+    mova        [tmpq+32*1], m0
+    add                tmpq, 32*2
+    add                  r6, 32
+    jle .h_loop
+    add                srcq, ssq
+    mov                  r6, r5
+    dec                  hd
+    jg .h_loop
+    RET
+.hv:
+    WIN64_SPILL_XMM      14, 16
+    cmp                  wd, 4
+    jne .hv_w8
+.hv_w4:
+    movzx               mxd, mxb
+    dec                srcq
+    vpbroadcastd         m7, [r7+mxq*8+subpel_filters-prep%+SUFFIX+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    mova                 m6, [subpel_h_shuf4]
+    vpbroadcastq         m0, [r7+myq*8+subpel_filters+1-prep%+SUFFIX]
+    mov                 nsq, ssq
+    pmovzxbd            m13, [deint_shuf4]
+    neg                 nsq
+    vpbroadcastd         m8, [pw_8192]
+    vpbroadcastd         m9, [pd_32]
+    punpcklbw            m0, m0
+    vpbroadcastq         m2, [srcq+nsq*2]
+    psraw                m0, 8 ; sign-extend
+    vpbroadcastq         m4, [srcq+nsq*1]
+    pshufd              m10, m0, q0000
+    vpbroadcastq         m1, [srcq+ssq*0]
+    pshufd              m11, m0, q1111
+    vpbroadcastq         m3, [srcq+ssq*1]
+    pshufd              m12, m0, q2222
+    vpbroadcastq         m0, [srcq+ssq*2]
+    vpblendd             m2, m4, 0xcc ; 0 1
+    vpblendd             m1, m3, 0xcc ; 2 3
+    pshufb               m2, m6
+    pshufb               m1, m6
+    pshufb               m0, m6
+    pmaddubsw            m2, m7
+    pmaddubsw            m1, m7
+    pmaddubsw            m0, m7
+    phaddw               m2, m1       ; 0 1 2 3
+    phaddw               m0, m0       ; 4
+    pmulhrsw             m2, m8
+    pmulhrsw             m0, m8
+    palignr              m0, m2, 4
+    punpcklwd            m1, m2, m0   ; 01 12
+    punpckhwd            m2, m0       ; 23 34
+.hv_w4_loop:
+    pmaddwd              m4, m10, m1  ; a0 b0
+    lea                srcq, [srcq+ssq*4]
+    pmaddwd              m5, m2, m10  ; c0 d0
+    vpbroadcastq         m1, [srcq+nsq*1]
+    pmaddwd              m2, m11      ; a1 b1
+    vpbroadcastq         m3, [srcq+ssq*0]
+    paddd                m4, m2
+    vpbroadcastq         m2, [srcq+ssq*1]
+    vpblendd             m1, m3, 0xcc ; 5 6
+    vpbroadcastq         m3, [srcq+ssq*2]
+    vpblendd             m2, m3, 0xcc ; 7 8
+    pshufb               m1, m6
+    pshufb               m2, m6
+    pmaddubsw            m1, m7
+    pmaddubsw            m2, m7
+    phaddw               m1, m2       ; 5 6 7 8
+    pmulhrsw             m1, m8
+    paddd                m5, m9
+    paddd                m4, m9
+    palignr              m2, m1, m0, 12
+    mova                 m0, m1
+    punpcklwd            m1, m2, m0   ; 45 56
+    punpckhwd            m2, m0       ; 67 78
+    pmaddwd              m3, m11, m1  ; c1 d1
+    paddd                m5, m3
+    pmaddwd              m3, m12, m1  ; a2 b2
+    paddd                m4, m3
+    pmaddwd              m3, m12, m2  ; c2 d2
+    paddd                m5, m3
+    psrad                m4, 6
+    psrad                m5, 6
+    packssdw             m4, m5
+    vpermd               m4, m13, m4
+    mova             [tmpq], m4
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    lea                 mxq, [r7+mxq*8+subpel_filters+1-prep_avx2]
+    WIN64_PUSH_XMM       16
+    vpbroadcastw        m10, [mxq+0]
+    vpbroadcastw        m11, [mxq+2]
+    vpbroadcastw        m12, [mxq+4]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m0, [r7+myq*8+subpel_filters+1-prep_avx2]
+    lea                  r7, [ssq*2+2]
+    vbroadcasti128       m8, [z_filter_s+ 6]
+    punpcklbw            m0, m0
+    vbroadcasti128       m9, [z_filter_s+10]
+    psraw                m0, 8 ; sign-extend
+    lea                 r6d, [wq*8-64]
+    pshufd              m13, m0, q0000
+    sub                srcq, r7
+    pshufd              m14, m0, q1111
+    lea                 r6d, [hq+r6*4]
+    pshufd              m15, m0, q2222
+.hv_w8_loop0:
+    vbroadcasti128       m7, [z_filter_s+2]
+    movu                xm3, [srcq+ssq*0]
+    lea                  r5, [srcq+ssq*2]
+    movu                xm4, [srcq+ssq*1]
+    vbroadcasti128       m0, [r5+ssq*0]
+    mov                  r7, tmpq
+    vinserti128          m4, [r5+ssq*1], 1 ; 1 3
+    lea                  r5, [r5+ssq*2]
+    vpblendd             m3, m0, 0xf0      ; 0 2
+    vinserti128          m0, [r5+ssq*0], 1 ; 2 4
+    vpbroadcastd         m5, [pw_8192]
+    HV_H_6TAP_W8         m3, m1, m2, m7, m8, m9
+    HV_H_6TAP_W8         m4, m1, m2, m7, m8, m9
+    HV_H_6TAP_W8         m0, m1, m2, m7, m8, m9
+    vpermq               m3, m3, q3120
+    vpermq               m4, m4, q3120
+    vpermq               m0, m0, q3120
+    pmulhrsw             m3, m5
+    pmulhrsw             m4, m5
+    pmulhrsw             m0, m5
+    punpcklwd            m1, m3, m4  ; 01
+    punpckhwd            m3, m4      ; 23
+    punpcklwd            m2, m4, m0  ; 12
+    punpckhwd            m4, m0      ; 34
+.hv_w8_loop:
+    movu                xm7, [r5+ssq*1]
+    lea                  r5, [r5+ssq*2]
+    vinserti128          m7, [r5+ssq*0], 1 ; 5 6
+    pmaddwd              m5, m13, m1 ; a0
+    mova                 m1, m3
+    pmaddwd              m6, m13, m2 ; b0
+    mova                 m2, m4
+    pmaddwd              m3, m14     ; a1
+    pmaddwd              m4, m14     ; b1
+    paddd                m5, m3
+    vbroadcasti128       m3, [z_filter_s+2]
+    paddd                m6, m4
+    HV_H_6TAP_W8         m7, m3, m4, m3, m8, m9
+    vpbroadcastd         m3, [pw_8192]
+    vpbroadcastd         m4, [pd_32]
+    pmulhrsw             m7, m3
+    paddd                m5, m4
+    paddd                m6, m4
+    mova                 m4, m0
+    vpermq               m0, m7, q3120
+    shufpd               m4, m0, 0x05
+    punpcklwd            m3, m4, m0  ; 45
+    pmaddwd              m7, m15, m3 ; a2
+    punpckhwd            m4, m0      ; 67
+    paddd                m5, m7
+    pmaddwd              m7, m15, m4 ; b2
+    paddd                m6, m7
+    psrad                m5, 6
+    psrad                m6, 6
+    packssdw             m5, m6
+    vpermq               m5, m5, q3120
+    mova          [r7+wq*0], xm5
+    vextracti128  [r7+wq*2], m5, 1
+    lea                  r7, [r7+wq*4]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 8
+    add                tmpq, 16
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .hv_w8_loop0
+    RET
+
+PREP_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_8bpc
+PREP_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_8bpc
+PREP_8TAP_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_8bpc
+PREP_8TAP_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_8bpc
+PREP_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal prep_8tap_8bpc, 3, 8, 0, tmp, src, stride, w, h, mx, my, stride3
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    lea                  r7, [prep%+SUFFIX]
+    mov                  wd, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _prep_6tap_8bpc_avx2).prep
+.v:
+    WIN64_SPILL_XMM      12, 15
+    movzx               mxd, myb ; Select 4-tap/8-tap filter multipliers.
+    shr                 myd, 16  ; Note that the code is 8-tap only, having
+    cmp                  hd, 4   ; a separate 4-tap code path for (4|8|16)x4
+    cmove               myd, mxd ; had a negligible effect on performance.
+    lea                 myq, [r7+myq*8+subpel_filters-prep%+SUFFIX]
+    lea            stride3q, [strideq*3]
+    sub                srcq, stride3q
+    vpbroadcastd         m7, [pw_8192]
+    vpbroadcastw         m8, [myq+0]
+    vpbroadcastw         m9, [myq+2]
+    vpbroadcastw        m10, [myq+4]
+    vpbroadcastw        m11, [myq+6]
+    cmp                  wd, 8
+    jg .v_w16
+    je .v_w8
+.v_w4:
+    movd                xm0, [srcq+strideq*0]
+    vpbroadcastd         m1, [srcq+strideq*2]
+    vpbroadcastd        xm2, [srcq+strideq*1]
+    add                srcq, stride3q
+    vpbroadcastd         m3, [srcq+strideq*0]
+    vpblendd             m1, m0, 0x01     ; 0 2 2 _   2 _ _ _
+    vpblendd             m3, m2, 0x03     ; 1 1 3 3   3 3 _ _
+    vpbroadcastd         m0, [srcq+strideq*1]
+    vpbroadcastd         m2, [srcq+strideq*2]
+    vpblendd             m1, m0, 0x68     ; 0 2 2 4   2 4 4 _
+    vpbroadcastd         m0, [srcq+stride3q ]
+    vbroadcasti128       m5, [deint_shuf4]
+    vpblendd             m3, m2, 0xc0     ; 1 1 3 3   3 3 5 5
+    vpblendd             m2, m3, m1, 0x55 ; 0 1 2 3   2 3 4 5
+    vpblendd             m3, m1, 0xaa     ; 1 2 3 4   3 4 5 _
+    punpcklbw            m1, m2, m3       ; 01  12    23  34
+    vpblendd             m3, m0, 0x80     ; 1 2 3 4   3 4 5 6
+    punpckhbw            m2, m3           ; 23  34    45  56
+.v_w4_loop:
+    lea                srcq, [srcq+strideq*4]
+    pinsrd              xm0, [srcq+strideq*0], 1
+    vpbroadcastd         m3, [srcq+strideq*1]
+    vpbroadcastd         m4, [srcq+strideq*2]
+    vpblendd             m3, m0, 0x03     ; 6 7 8 _   8 _ _ _
+    vpbroadcastd         m0, [srcq+stride3q ]
+    vpblendd             m3, m4, 0x20     ; 6 7 8 _   8 9 _ _
+    vpblendd             m3, m0, 0x40     ; 6 7 8 _   8 9 a _
+    pshufb               m3, m5           ; 67  78    89  9a
+    pmaddubsw            m4, m1, m8
+    vperm2i128           m1, m2, m3, 0x21 ; 45  56    67  78
+    pmaddubsw            m2, m9
+    paddw                m4, m2
+    mova                 m2, m3
+    pmaddubsw            m3, m11
+    paddw                m3, m4
+    pmaddubsw            m4, m1, m10
+    paddw                m3, m4
+    pmulhrsw             m3, m7
+    mova             [tmpq], m3
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq                xm1, [srcq+strideq*0]
+    vpbroadcastq         m4, [srcq+strideq*1]
+    vpbroadcastq         m2, [srcq+strideq*2]
+    vpbroadcastq         m5, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastq         m3, [srcq+strideq*0]
+    vpbroadcastq         m6, [srcq+strideq*1]
+    vpbroadcastq         m0, [srcq+strideq*2]
+    vpblendd             m1, m4, 0x30
+    vpblendd             m4, m2, 0x30
+    punpcklbw            m1, m4 ; 01 12
+    vpblendd             m2, m5, 0x30
+    vpblendd             m5, m3, 0x30
+    punpcklbw            m2, m5 ; 23 34
+    vpblendd             m3, m6, 0x30
+    vpblendd             m6, m0, 0x30
+    punpcklbw            m3, m6 ; 45 56
+.v_w8_loop:
+    vpbroadcastq         m4, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    pmaddubsw            m5, m2, m9  ; a1
+    pmaddubsw            m6, m2, m8  ; b0
+    vpblendd             m2, m0, m4, 0x30
+    vpbroadcastq         m0, [srcq+strideq*0]
+    vpblendd             m4, m0, 0x30
+    punpcklbw            m2, m4      ; 67 78
+    pmaddubsw            m1, m8      ; a0
+    pmaddubsw            m4, m3, m9  ; b1
+    paddw                m5, m1
+    mova                 m1, m3
+    pmaddubsw            m3, m10     ; a2
+    paddw                m6, m4
+    paddw                m5, m3
+    vpbroadcastq         m4, [srcq+strideq*1]
+    vpblendd             m3, m0, m4, 0x30
+    vpbroadcastq         m0, [srcq+strideq*2]
+    vpblendd             m4, m0, 0x30
+    punpcklbw            m3, m4      ; 89 9a
+    pmaddubsw            m4, m2, m11 ; a3
+    paddw                m5, m4
+    pmaddubsw            m4, m2, m10 ; b2
+    paddw                m6, m4
+    pmaddubsw            m4, m3, m11 ; b3
+    paddw                m6, m4
+    pmulhrsw             m5, m7
+    pmulhrsw             m6, m7
+    mova        [tmpq+32*0], m5
+    mova        [tmpq+32*1], m6
+    add                tmpq, 32*2
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    lea                 r6d, [wq*2-32]
+    WIN64_PUSH_XMM       15
+    lea                 r6d, [hq+r6*8]
+.v_w16_loop0:
+    vbroadcasti128       m4, [srcq+strideq*0]
+    vbroadcasti128       m5, [srcq+strideq*1]
+    lea                  r5, [srcq+strideq*2]
+    vbroadcasti128       m0, [r5+strideq*1]
+    vbroadcasti128       m6, [r5+strideq*0]
+    lea                  r5, [r5+strideq*2]
+    vbroadcasti128       m1, [r5+strideq*0]
+    vbroadcasti128       m2, [r5+strideq*1]
+    lea                  r5, [r5+strideq*2]
+    vbroadcasti128       m3, [r5+strideq*0]
+    mov                  r7, tmpq
+    shufpd               m4, m0, 0x0c
+    shufpd               m5, m1, 0x0c
+    punpcklbw            m1, m4, m5 ; 01
+    punpckhbw            m4, m5     ; 34
+    shufpd               m6, m2, 0x0c
+    punpcklbw            m2, m5, m6 ; 12
+    punpckhbw            m5, m6     ; 45
+    shufpd               m0, m3, 0x0c
+    punpcklbw            m3, m6, m0 ; 23
+    punpckhbw            m6, m0     ; 56
+.v_w16_loop:
+    vbroadcasti128      m12, [r5+strideq*1]
+    lea                  r5, [r5+strideq*2]
+    pmaddubsw           m13, m1, m8  ; a0
+    pmaddubsw           m14, m2, m8  ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddubsw            m3, m9      ; a1
+    pmaddubsw            m4, m9      ; b1
+    paddw               m13, m3
+    paddw               m14, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddubsw            m5, m10     ; a2
+    pmaddubsw            m6, m10     ; b2
+    paddw               m13, m5
+    vbroadcasti128       m5, [r5+strideq*0]
+    paddw               m14, m6
+    shufpd               m6, m0, m12, 0x0d
+    shufpd               m0, m12, m5, 0x0c
+    punpcklbw            m5, m6, m0  ; 67
+    punpckhbw            m6, m0      ; 78
+    pmaddubsw           m12, m5, m11 ; a3
+    paddw               m13, m12
+    pmaddubsw           m12, m6, m11 ; b3
+    paddw               m14, m12
+    pmulhrsw            m13, m7
+    pmulhrsw            m14, m7
+    mova          [r7+wq*0], m13
+    mova          [r7+wq*2], m14
+    lea                  r7, [r7+wq*4]
+    sub                  hd, 2
+    jg .v_w16_loop
+    add                srcq, 16
+    add                tmpq, 32
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_w16_loop0
+    RET
+.h:
+.h_w4:
+    test                myd, 0xf00
+    jnz .hv
+    vpbroadcastd         m4, [pw_8192]
+    cmp                  wd, 4
+    je mangle(private_prefix %+ _prep_6tap_8bpc_avx2).h_w4
+    WIN64_SPILL_XMM      10
+    vbroadcasti128       m5, [subpel_h_shufA]
+    tzcnt                wd, wd
+    vbroadcasti128       m6, [subpel_h_shufB]
+    vbroadcasti128       m7, [subpel_h_shufC]
+    shr                 mxd, 16
+    sub                srcq, 3
+    movzx                wd, word [r7+wq*2+table_offset(prep, _8tap_h)]
+    vpbroadcastd         m8, [r7+mxq*8+subpel_filters-prep%+SUFFIX+0]
+    vpbroadcastd         m9, [r7+mxq*8+subpel_filters-prep%+SUFFIX+4]
+    add                  wq, r7
+    jmp                  wq
+.h_w8:
+    movu                xm0, [srcq+strideq*0]
+    vinserti128          m0, [srcq+strideq*1], 1
+    lea                srcq, [srcq+strideq*2]
+%macro PREP_8TAP_H 0
+    pshufb               m1, m0, m5
+    pshufb               m2, m0, m6
+    pshufb               m3, m0, m7
+    pmaddubsw            m1, m8
+    pmaddubsw            m0, m2, m8
+    pmaddubsw            m2, m9
+    pmaddubsw            m3, m9
+    paddw                m1, m2
+    paddw                m0, m3
+    phaddw               m0, m1, m0
+    pmulhrsw             m0, m4
+%endmacro
+    PREP_8TAP_H
+    mova             [tmpq], m0
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    movu                xm0, [srcq+strideq*0+8*0]
+    vinserti128          m0, [srcq+strideq*0+8*1], 1
+    PREP_8TAP_H
+    mova        [tmpq+32*0], m0
+    movu                xm0, [srcq+strideq*1+8*0]
+    vinserti128          m0, [srcq+strideq*1+8*1], 1
+    lea                srcq, [srcq+strideq*2]
+    PREP_8TAP_H
+    mova        [tmpq+32*1], m0
+    add                tmpq, 32*2
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w32:
+    xor                 r6d, r6d
+    jmp .h_start
+.h_w64:
+    mov                  r6, -32*1
+    jmp .h_start
+.h_w128:
+    mov                  r6, -32*3
+.h_start:
+    sub                srcq, r6
+    mov                  r5, r6
+.h_loop:
+    movu                xm0, [srcq+r6+8*0]
+    vinserti128          m0, [srcq+r6+8*1], 1
+    PREP_8TAP_H
+    mova        [tmpq+32*0], m0
+    movu                xm0, [srcq+r6+8*2]
+    vinserti128          m0, [srcq+r6+8*3], 1
+    PREP_8TAP_H
+    mova        [tmpq+32*1], m0
+    add                tmpq, 32*2
+    add                  r6, 32
+    jle .h_loop
+    add                srcq, strideq
+    mov                  r6, r5
+    dec                  hd
+    jg .h_loop
+    RET
+.hv:
+    WIN64_SPILL_XMM      16
+    cmp                  wd, 4
+    je .hv_w4
+    shr                 mxd, 16
+    sub                srcq, 3
+    vpbroadcastd        m10, [r7+mxq*8+subpel_filters-prep%+SUFFIX+0]
+    vpbroadcastd        m11, [r7+mxq*8+subpel_filters-prep%+SUFFIX+4]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m0, [r7+myq*8+subpel_filters-prep%+SUFFIX]
+    lea            stride3q, [strideq*3]
+    sub                srcq, stride3q
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    pshufd              m12, m0, q0000
+    pshufd              m13, m0, q1111
+    pshufd              m14, m0, q2222
+    pshufd              m15, m0, q3333
+    jmp .hv_w8
+.hv_w4:
+    movzx               mxd, mxb
+    dec                srcq
+    vpbroadcastd         m8, [r7+mxq*8+subpel_filters-prep%+SUFFIX+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m0, [r7+myq*8+subpel_filters-prep%+SUFFIX]
+    lea            stride3q, [strideq*3]
+    sub                srcq, stride3q
+    mova                 m7, [subpel_h_shuf4]
+    pmovzxbd             m9, [deint_shuf4]
+    vpbroadcastd        m10, [pw_8192]
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    vpbroadcastd        m11, [pd_32]
+    pshufd              m12, m0, q0000
+    pshufd              m13, m0, q1111
+    pshufd              m14, m0, q2222
+    pshufd              m15, m0, q3333
+    vpbroadcastq         m2, [srcq+strideq*0]
+    vpbroadcastq         m4, [srcq+strideq*1]
+    vpbroadcastq         m0, [srcq+strideq*2]
+    vpbroadcastq         m5, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastq         m3, [srcq+strideq*0]
+    vpbroadcastq         m6, [srcq+strideq*1]
+    vpbroadcastq         m1, [srcq+strideq*2]
+    vpblendd             m2, m4, 0xcc ; 0 1
+    vpblendd             m0, m5, 0xcc ; 2 3
+    vpblendd             m3, m6, 0xcc ; 4 5
+    pshufb               m2, m7 ; 00 01 10 11  02 03 12 13
+    pshufb               m0, m7 ; 20 21 30 31  22 23 32 33
+    pshufb               m3, m7 ; 40 41 50 51  42 43 52 53
+    pshufb               m1, m7 ; 60 61 60 61  62 63 62 63
+    pmaddubsw            m2, m8
+    pmaddubsw            m0, m8
+    pmaddubsw            m3, m8
+    pmaddubsw            m1, m8
+    phaddw               m2, m0 ; 0a 1a 2a 3a  0b 1b 2b 3b
+    phaddw               m3, m1 ; 4a 5a 6a __  4b 5b 6b __
+    pmulhrsw             m2, m10
+    pmulhrsw             m3, m10
+    palignr              m4, m3, m2, 4 ; 1a 2a 3a 4a  1b 2b 3b 4b
+    punpcklwd            m1, m2, m4  ; 01 12
+    punpckhwd            m2, m4      ; 23 34
+    pshufd               m0, m3, q2121
+    punpcklwd            m3, m0      ; 45 56
+.hv_w4_loop:
+    pmaddwd              m5, m1, m12 ; a0 b0
+    pmaddwd              m6, m2, m12 ; c0 d0
+    pmaddwd              m2, m13     ; a1 b1
+    pmaddwd              m4, m3, m13 ; c1 d1
+    mova                 m1, m3
+    pmaddwd              m3, m14     ; a2 b2
+    paddd                m5, m2
+    vpbroadcastq         m2, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    paddd                m6, m4
+    vpbroadcastq         m4, [srcq+strideq*0]
+    paddd                m5, m3
+    vpbroadcastq         m3, [srcq+strideq*1]
+    vpblendd             m2, m4, 0xcc
+    vpbroadcastq         m4, [srcq+strideq*2]
+    vpblendd             m3, m4, 0xcc
+    pshufb               m2, m7
+    pshufb               m3, m7
+    pmaddubsw            m2, m8
+    pmaddubsw            m3, m8
+    phaddw               m2, m3
+    pmulhrsw             m2, m10
+    palignr              m3, m2, m0, 12
+    mova                 m0, m2
+    punpcklwd            m2, m3, m0  ; 67 78
+    punpckhwd            m3, m0      ; 89 9a
+    pmaddwd              m4, m2, m14 ; c2 d2
+    paddd                m6, m11
+    paddd                m5, m11
+    paddd                m6, m4
+    pmaddwd              m4, m2, m15 ; a3 b3
+    paddd                m5, m4
+    pmaddwd              m4, m3, m15 ; c3 d3
+    paddd                m6, m4
+    psrad                m5, 6
+    psrad                m6, 6
+    packssdw             m5, m6
+    vpermd               m5, m9, m5
+    mova             [tmpq], m5
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    lea                 r6d, [wq*8-64]
+    lea                 r6d, [hq+r6*4]
+.hv_w8_loop0:
+    vbroadcasti128       m7, [subpel_h_shufA]
+    movu                xm4, [srcq+strideq*0]
+    lea                  r5, [srcq+strideq*2]
+    vbroadcasti128       m8, [subpel_h_shufB]
+    movu                xm5, [srcq+strideq*1]
+    mov                  r7, tmpq
+    vbroadcasti128       m9, [subpel_h_shufC]
+    movu                xm6, [r5+strideq*0]
+    vbroadcasti128       m0, [r5+strideq*1]
+    lea                  r5, [r5+strideq*2]
+    vpblendd             m4, m0, 0xf0          ; 0 3
+    vinserti128          m5, [r5+strideq*0], 1 ; 1 4
+    vinserti128          m6, [r5+strideq*1], 1 ; 2 5
+    lea                  r5, [r5+strideq*2]
+    vinserti128          m0, [r5+strideq*0], 1 ; 3 6
+    HV_H_8TAP_W8         m4, m1, m2, m3, m7, m8, m9
+    HV_H_8TAP_W8         m5, m1, m2, m3, m7, m8, m9
+    HV_H_8TAP_W8         m6, m1, m2, m3, m7, m8, m9
+    HV_H_8TAP_W8         m0, m1, m2, m3, m7, m8, m9
+    vpbroadcastd         m7, [pw_8192]
+    vpermq               m4, m4, q3120
+    vpermq               m5, m5, q3120
+    vpermq               m6, m6, q3120
+    pmulhrsw             m0, m7
+    pmulhrsw             m4, m7
+    pmulhrsw             m5, m7
+    pmulhrsw             m6, m7
+    vpermq               m7, m0, q3120
+    punpcklwd            m1, m4, m5  ; 01
+    punpckhwd            m4, m5      ; 34
+    punpcklwd            m2, m5, m6  ; 12
+    punpckhwd            m5, m6      ; 45
+    punpcklwd            m3, m6, m7  ; 23
+    punpckhwd            m6, m7      ; 56
+.hv_w8_loop:
+    vextracti128       [r7], m0, 1 ; not enough registers
+    movu                xm0, [r5+strideq*1]
+    lea                  r5, [r5+strideq*2]
+    vinserti128          m0, [r5+strideq*0], 1 ; 7 8
+    pmaddwd              m8, m1, m12 ; a0
+    pmaddwd              m9, m2, m12 ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddwd              m3, m13     ; a1
+    pmaddwd              m4, m13     ; b1
+    paddd                m8, m3
+    paddd                m9, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddwd              m5, m14     ; a2
+    pmaddwd              m6, m14     ; b2
+    paddd                m8, m5
+    paddd                m9, m6
+    vbroadcasti128       m6, [subpel_h_shufB]
+    vbroadcasti128       m7, [subpel_h_shufC]
+    vbroadcasti128       m5, [subpel_h_shufA]
+    HV_H_8TAP_W8         m0, m5, m6, m7, m5, m6, m7
+    vpbroadcastd         m5, [pw_8192]
+    vpbroadcastd         m7, [pd_32]
+    vbroadcasti128       m6, [r7]
+    pmulhrsw             m0, m5
+    paddd                m8, m7
+    paddd                m9, m7
+    vpermq               m7, m0, q3120 ; 7 8
+    shufpd               m6, m7, 0x04  ; 6 7
+    punpcklwd            m5, m6, m7  ; 67
+    punpckhwd            m6, m7      ; 78
+    pmaddwd              m7, m5, m15 ; a3
+    paddd                m8, m7
+    pmaddwd              m7, m6, m15 ; b3
+    paddd                m7, m9
+    psrad                m8, 6
+    psrad                m7, 6
+    packssdw             m8, m7
+    vpermq               m7, m8, q3120
+    mova          [r7+wq*0], xm7
+    vextracti128  [r7+wq*2], m7, 1
+    lea                  r7, [r7+wq*4]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 8
+    add                tmpq, 16
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .hv_w8_loop0
+    RET
+
+%macro movifprep 2
+ %if isprep
+    mov %1, %2
+ %endif
+%endmacro
+
+%macro REMAP_REG 2
+ %xdefine r%1  r%2
+ %xdefine r%1q r%2q
+ %xdefine r%1d r%2d
+%endmacro
+
+%macro MCT_8TAP_SCALED_REMAP_REGS_TO_PREV 0
+ %if isprep
+  %xdefine r14_save r14
+  %assign %%i 14
+  %rep 14
+   %assign %%j %%i-1
+   REMAP_REG %%i, %%j
+   %assign %%i %%i-1
+  %endrep
+ %endif
+%endmacro
+
+%macro MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT 0
+ %if isprep
+  %assign %%i 1
+  %rep 13
+   %assign %%j %%i+1
+   REMAP_REG %%i, %%j
+   %assign %%i %%i+1
+  %endrep
+  %xdefine r14 r14_save
+  %undef r14_save
+ %endif
+%endmacro
+
+%macro MC_8TAP_SCALED_RET 0-1 1 ; leave_mapping_unchanged
+    MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT
+    RET
+ %if %1
+    MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %endif
+%endmacro
+
+%macro MC_8TAP_SCALED_H 8 ; dst, tmp[0-6]
+    movq               xm%1, [srcq+ r4]
+    movq               xm%2, [srcq+ r6]
+    movhps             xm%1, [srcq+ r7]
+    movhps             xm%2, [srcq+ r9]
+    vinserti128         m%1, [srcq+r10], 1
+    vinserti128         m%2, [srcq+r11], 1
+    vpbroadcastq        m%5, [srcq+r13]
+    vpbroadcastq        m%6, [srcq+ rX]
+    add                srcq, ssq
+    movq               xm%3, [srcq+ r4]
+    movq               xm%4, [srcq+ r6]
+    movhps             xm%3, [srcq+ r7]
+    movhps             xm%4, [srcq+ r9]
+    vinserti128         m%3, [srcq+r10], 1
+    vinserti128         m%4, [srcq+r11], 1
+    vpbroadcastq        m%7, [srcq+r13]
+    vpbroadcastq        m%8, [srcq+ rX]
+    add                srcq, ssq
+    vpblendd            m%1, m%5, 0xc0
+    vpblendd            m%2, m%6, 0xc0
+    vpblendd            m%3, m%7, 0xc0
+    vpblendd            m%4, m%8, 0xc0
+    pmaddubsw           m%1, m15
+    pmaddubsw           m%2, m10
+    pmaddubsw           m%3, m15
+    pmaddubsw           m%4, m10
+    phaddw              m%1, m%2
+    phaddw              m%3, m%4
+    phaddw              m%1, m%3
+    pmulhrsw            m%1, m12
+%endmacro
+
+%macro MC_8TAP_SCALED 1
+%ifidn %1, put
+ %assign isprep 0
+cglobal put_8tap_scaled_8bpc, 4, 14, 16, 128, dst, ds, src, ss, w, h, mx, my, dx, dy
+ %xdefine base_reg r12
+ %define rndshift 10
+%else
+ %assign isprep 1
+cglobal prep_8tap_scaled_8bpc, 4, 14, 16, 128, tmp, src, ss, w, h, mx, my, dx, dy
+ %define tmp_stridem qword [rsp+120]
+ %xdefine base_reg r11
+ %define rndshift 6
+%endif
+    lea            base_reg, [%1_8tap_scaled_8bpc_avx2]
+%define base base_reg-%1_8tap_scaled_8bpc_avx2
+    tzcnt                wd, wm
+    vpbroadcastd         m8, dxm
+%if isprep && UNIX64
+    movd               xm14, mxd
+    vpbroadcastd        m14, xm14
+    mov                 r5d, t0d
+ DECLARE_REG_TMP 5, 7
+%else
+    vpbroadcastd        m14, mxm
+%endif
+    mov                 dyd, dym
+%ifidn %1, put
+ %if WIN64
+    mov                 r8d, hm
+  DEFINE_ARGS dst, ds, src, ss, w, _, _, my, h, dy, ss3
+  %define hm r5m
+  %define dxm r8m
+ %else
+  DEFINE_ARGS dst, ds, src, ss, w, h, _, my, dx, dy, ss3
+  %define hm r6m
+ %endif
+ %define dsm [rsp+112]
+ %define rX r1
+ %define rXd r1d
+%else ; prep
+ %if WIN64
+    mov                 r7d, hm
+  DEFINE_ARGS tmp, src, ss, w, _, _, my, h, dy, ss3
+  %define hm r4m
+  %define dxm r7m
+ %else
+  DEFINE_ARGS tmp, src, ss, w, h, _, my, dx, dy, ss3
+  %define hm [rsp+112]
+ %endif
+ MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %define rX r14
+ %define rXd r14d
+%endif
+    vpbroadcastd        m10, [base+pd_0x3ff]
+    vpbroadcastd        m12, [base+pw_8192]
+%ifidn %1, put
+    vpbroadcastd        m13, [base+pd_512]
+%else
+    vpbroadcastd        m13, [base+pd_32]
+%endif
+    pxor                 m9, m9
+    lea                ss3q, [ssq*3]
+    movzx               r7d, t1b
+    shr                 t1d, 16
+    cmp                  hd, 6
+    cmovs               t1d, r7d
+    sub                srcq, ss3q
+    cmp                 dyd, 1024
+    je .dy1
+    cmp                 dyd, 2048
+    je .dy2
+    movzx                wd, word [base+%1_8tap_scaled_avx2_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%ifidn %1, put
+.w2:
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd               xm15, t0d
+    punpckldq            m8, m9, m8
+    paddd               m14, m8 ; mx+dx*[0,1]
+    vpbroadcastd        m11, [base+pd_0x4000]
+    vpbroadcastd       xm15, xm15
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd              xm15, xm8
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    vbroadcasti128       m5, [base+bdct_lb_dw]
+    vbroadcasti128       m6, [base+subpel_s_shuf2]
+    vpbroadcastd        m15, [base+subpel_filters+r4*8+2]
+    vpbroadcastd         m7, [base+subpel_filters+r6*8+2]
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+    movq                xm0, [srcq+ssq*0]
+    movq                xm1, [srcq+ssq*2]
+    movhps              xm0, [srcq+ssq*1]
+    movhps              xm1, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pshufb              m14, m5
+    paddb               m14, m6
+    vinserti128          m0, [srcq+ssq*0], 1
+    vinserti128          m1, [srcq+ssq*2], 1
+    vpbroadcastq         m2, [srcq+ssq*1]
+    vpbroadcastq         m3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    vpblendd            m15, m7, 0xaa
+    vpblendd             m0, m2, 0xc0       ; 0 1  4 5
+    vpblendd             m1, m3, 0xc0       ; 2 3  6 7
+    pblendvb            m15, m11, m8
+    pshufb               m0, m14
+    pshufb               m1, m14
+    pmaddubsw            m0, m15
+    pmaddubsw            m1, m15
+    phaddw               m0, m1
+    pmulhrsw             m0, m12            ; 0 1 2 3  4 5 6 7
+    vextracti128        xm1, m0, 1          ; 4 5 6 7
+    palignr             xm2, xm1, xm0, 4    ; 1 2 3 4
+    punpcklwd           xm3, xm0, xm2       ; 01 12
+    punpckhwd           xm0, xm2            ; 23 34
+    pshufd              xm4, xm1, q0321     ; 5 6 7 _
+    punpcklwd           xm2, xm1, xm4       ; 45 56
+    punpckhwd           xm4, xm1, xm4       ; 67 __
+.w2_loop:
+    and                 myd, 0x3ff
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq               xm11, r6q
+    pmovsxbw           xm11, xm11
+    pshufd              xm8, xm11, q0000
+    pshufd              xm9, xm11, q1111
+    pshufd             xm10, xm11, q2222
+    pshufd             xm11, xm11, q3333
+    pmaddwd             xm5, xm3, xm8
+    pmaddwd             xm6, xm0, xm9
+    pmaddwd             xm7, xm2, xm10
+    pmaddwd             xm8, xm4, xm11
+    paddd               xm5, xm6
+    paddd               xm7, xm8
+    paddd               xm5, xm13
+    paddd               xm5, xm7
+    psrad               xm5, 10
+    packssdw            xm5, xm5
+    packuswb            xm5, xm5
+    pextrw           [dstq], xm5, 0
+    add                dstq, dsq
+    dec                  hd
+    jz .ret
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .w2_loop
+    movq                xm5, [srcq]
+    test                myd, 0x400
+    jz .w2_skip_line
+    add                srcq, ssq
+    shufps              xm3, xm0, q1032     ; 01 12
+    shufps              xm0, xm2, q1032     ; 23 34
+    shufps              xm2, xm4, q1032     ; 45 56
+    pshufb              xm5, xm14
+    pmaddubsw           xm5, xm15
+    phaddw              xm5, xm5
+    pmulhrsw            xm5, xm12
+    palignr             xm1, xm5, xm1, 12
+    punpcklqdq          xm1, xm1            ; 6 7 6 7
+    punpcklwd           xm4, xm1, xm5       ; 67 __
+    jmp .w2_loop
+.w2_skip_line:
+    movhps              xm5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova                xm3, xm0            ; 01 12
+    mova                xm0, xm2            ; 23 34
+    pshufb              xm5, xm14
+    pmaddubsw           xm5, xm15
+    phaddw              xm5, xm5
+    pmulhrsw            xm5, xm12           ; 6 7 6 7
+    palignr             xm1, xm5, xm1, 8    ; 4 5 6 7
+    pshufd              xm5, xm1, q0321     ; 5 6 7 _
+    punpcklwd           xm2, xm1, xm5       ; 45 56
+    punpckhwd           xm4, xm1, xm5       ; 67 __
+    jmp .w2_loop
+%endif
+.w4:
+    mov                 myd, mym
+    vbroadcasti128       m7, [base+rescale_mul]
+    movzx               t0d, t0b
+    dec                srcq
+    movd               xm15, t0d
+    pmaddwd              m8, m7
+    vpbroadcastd        m11, [base+pd_0x4000]
+    vpbroadcastd       xm15, xm15
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m0, m14, m10
+    psrld                m0, 6
+    paddd              xm15, xm0
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    pextrd             r11d, xm15, 2
+    pextrd             r13d, xm15, 3
+    movd               xm15, [base+subpel_filters+r4*8+2]
+    vbroadcasti128       m5, [base+bdct_lb_dw]
+    vpbroadcastq         m6, [base+subpel_s_shuf2]
+    pinsrd             xm15, [base+subpel_filters+r6*8+2], 1
+    pcmpeqd              m0, m9
+    psrld               m14, 10
+    movu                xm7, [srcq+ssq*0]
+    movu                xm9, [srcq+ssq*1]
+    pinsrd             xm15, [base+subpel_filters+r11*8+2], 2
+    movu                xm8, [srcq+ssq*2]
+    movu               xm10, [srcq+ss3q ]
+    pinsrd             xm15, [base+subpel_filters+r13*8+2], 3
+    lea                srcq, [srcq+ssq*4]
+    pshufb              m14, m5
+    paddb               m14, m6
+    vinserti128          m7, [srcq+ssq*0], 1
+    vinserti128          m9, [srcq+ssq*1], 1
+    vinserti128         m15, xm15, 1
+    vinserti128          m8, [srcq+ssq*2], 1
+    vinserti128         m10, [srcq+ss3q ], 1
+    lea                srcq, [srcq+ssq*4]
+    pblendvb            m15, m11, m0
+    pshufb               m7, m14
+    pshufb               m9, m14
+    pshufb               m8, m14
+    pshufb              m10, m14
+    pmaddubsw            m7, m15
+    pmaddubsw            m9, m15
+    pmaddubsw            m8, m15
+    pmaddubsw           m10, m15
+    phaddw               m7, m9
+    phaddw               m8, m10
+    pmulhrsw             m7, m12                ; 0 1  4 5
+    pmulhrsw             m8, m12                ; 2 3  6 7
+    vextracti128        xm9, m7, 1              ; 4 5
+    vextracti128        xm3, m8, 1              ; 6 7
+    shufps              xm4, xm7, xm8, q1032    ; 1 2
+    shufps              xm5, xm8, xm9, q1032    ; 3 4
+    shufps              xm6, xm9, xm3, q1032    ; 5 6
+    psrldq             xm11, xm3, 8             ; 7 _
+    punpcklwd           xm0, xm7, xm4   ; 01
+    punpckhwd           xm7, xm4        ; 12
+    punpcklwd           xm1, xm8, xm5   ; 23
+    punpckhwd           xm8, xm5        ; 34
+    punpcklwd           xm2, xm9, xm6   ; 45
+    punpckhwd           xm9, xm6        ; 56
+    punpcklwd           xm3, xm11       ; 67
+    mova         [rsp+0x00], xm7
+    mova         [rsp+0x10], xm8
+    mova         [rsp+0x20], xm9
+.w4_loop:
+    and                 myd, 0x3ff
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq               xm10, r6q
+    pmovsxbw           xm10, xm10
+    pshufd              xm7, xm10, q0000
+    pshufd              xm8, xm10, q1111
+    pshufd              xm9, xm10, q2222
+    pshufd             xm10, xm10, q3333
+    pmaddwd             xm4, xm0, xm7
+    pmaddwd             xm5, xm1, xm8
+    pmaddwd             xm6, xm2, xm9
+    pmaddwd             xm7, xm3, xm10
+    paddd               xm4, xm5
+    paddd               xm6, xm7
+    paddd               xm4, xm13
+    paddd               xm4, xm6
+    psrad               xm4, rndshift
+    packssdw            xm4, xm4
+%ifidn %1, put
+    packuswb            xm4, xm4
+    movd             [dstq], xm4
+    add                dstq, dsq
+%else
+    movq             [tmpq], xm4
+    add                tmpq, 8
+%endif
+    dec                  hd
+    jz .ret
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .w4_loop
+    movu                xm4, [srcq]
+    test                myd, 0x400
+    jz .w4_skip_line
+    mova                xm0, [rsp+0x00]
+    mova         [rsp+0x00], xm1
+    mova                xm1, [rsp+0x10]
+    mova         [rsp+0x10], xm2
+    mova                xm2, [rsp+0x20]
+    mova         [rsp+0x20], xm3
+    pshufb              xm4, xm14
+    pmaddubsw           xm4, xm15
+    phaddw              xm4, xm4
+    pmulhrsw            xm4, xm12
+    punpcklwd           xm3, xm11, xm4
+    mova               xm11, xm4
+    add                srcq, ssq
+    jmp .w4_loop
+.w4_skip_line:
+    movu                xm5, [srcq+ssq*1]
+    movu                 m6, [rsp+0x10]
+    pshufb              xm4, xm14
+    pshufb              xm5, xm14
+    pmaddubsw           xm4, xm15
+    pmaddubsw           xm5, xm15
+    movu         [rsp+0x00], m6
+    phaddw              xm4, xm5
+    pmulhrsw            xm4, xm12
+    punpcklwd           xm9, xm11, xm4
+    mova         [rsp+0x20], xm9
+    psrldq             xm11, xm4, 8
+    mova                xm0, xm1
+    mova                xm1, xm2
+    mova                xm2, xm3
+    punpcklwd           xm3, xm4, xm11
+    lea                srcq, [srcq+ssq*2]
+    jmp .w4_loop
+.w8:
+    mov      dword [rsp+48], 1
+    movifprep   tmp_stridem, 16
+    jmp .w_start
+.w16:
+    mov      dword [rsp+48], 2
+    movifprep   tmp_stridem, 32
+    jmp .w_start
+.w32:
+    mov      dword [rsp+48], 4
+    movifprep   tmp_stridem, 64
+    jmp .w_start
+.w64:
+    mov      dword [rsp+48], 8
+    movifprep   tmp_stridem, 128
+    jmp .w_start
+.w128:
+    mov      dword [rsp+48], 16
+    movifprep   tmp_stridem, 256
+.w_start:
+%ifidn %1, put
+    movifnidn           dsm, dsq
+%endif
+    shr                 t0d, 16
+    sub                srcq, 3
+    pmaddwd              m8, [base+rescale_mul]
+    movd               xm15, t0d
+    mov            [rsp+72], t0d
+    mov            [rsp+56], srcq
+    mov            [rsp+64], r0q ; dstq / tmpq
+%if UNIX64
+    mov                  hm, hd
+%endif
+    shl           dword dxm, 3 ; dx*8
+    vpbroadcastd        m15, xm15
+    paddd               m14, m8 ; mx+dx*[0-7]
+    jmp .hloop
+.hloop_prep:
+    dec      dword [rsp+48]
+    jz .ret
+    add      qword [rsp+64], 8*(isprep+1)
+    mov                  hd, hm
+    vpbroadcastd         m8, dxm
+    vpbroadcastd        m10, [base+pd_0x3ff]
+    paddd               m14, m8, [rsp+16]
+    vpbroadcastd        m15, [rsp+72]
+    pxor                 m9, m9
+    mov                srcq, [rsp+56]
+    mov                 r0q, [rsp+64] ; dstq / tmpq
+.hloop:
+    vpbroadcastq        m11, [base+pq_0x40000000]
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd               m15, m6
+    pcmpeqd              m6, m9
+    vextracti128        xm7, m15, 1
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 2
+    pextrd              r7d, xm15, 1
+    pextrd              r9d, xm15, 3
+    movd               r10d, xm7
+    pextrd             r11d, xm7, 2
+    pextrd             r13d, xm7, 1
+    pextrd              rXd, xm7, 3
+    movu           [rsp+16], m14
+    movq               xm15, [base+subpel_filters+ r4*8]
+    movq               xm10, [base+subpel_filters+ r6*8]
+    movhps             xm15, [base+subpel_filters+ r7*8]
+    movhps             xm10, [base+subpel_filters+ r9*8]
+    vinserti128         m15, [base+subpel_filters+r10*8], 1
+    vinserti128         m10, [base+subpel_filters+r11*8], 1
+    vpbroadcastq         m9, [base+subpel_filters+r13*8]
+    vpbroadcastq         m8, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    vextracti128        xm7, m14, 1
+    mova              [rsp], xm14
+    movd                r4d, xm14
+    pextrd              r6d, xm14, 2
+    pextrd              r7d, xm14, 1
+    pextrd              r9d, xm14, 3
+    movd               r10d, xm7
+    pextrd             r11d, xm7, 2
+    pextrd             r13d, xm7, 1
+    pextrd              rXd, xm7, 3
+    pshufd               m5, m6, q1100
+    pshufd               m6, m6, q3322
+    vpblendd            m15, m9, 0xc0
+    vpblendd            m10, m8, 0xc0
+    pblendvb            m15, m11, m5
+    pblendvb            m10, m11, m6
+    vbroadcasti128      m14, [base+subpel_s_shuf8]
+    MC_8TAP_SCALED_H 0, 1, 2, 3, 4, 5, 6, 7  ; 0a 1a 0b 1b
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 7, 8  ; 2a 3a 2b 3b
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 7, 8, 9  ; 4a 5a 4b 5b
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 7, 8, 9, 11 ; 6a 7a 6b 7b
+    mov                 myd, mym
+    mov                 dyd, dym
+    pshufb               m0, m14    ; 01a 01b
+    pshufb               m1, m14    ; 23a 23b
+    pshufb               m2, m14    ; 45a 45b
+    pshufb               m3, m14    ; 67a 67b
+    vbroadcasti128      m14, [base+wswap]
+.vloop:
+    and                 myd, 0x3ff
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq               xm11, r6q
+    punpcklqdq         xm11, xm11
+    pmovsxbw            m11, xm11
+    pshufd               m8, m11, q0000
+    pshufd               m9, m11, q1111
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m9
+    pshufd               m8, m11, q2222
+    pshufd              m11, m11, q3333
+    pmaddwd              m6, m2, m8
+    pmaddwd              m7, m3, m11
+    paddd                m4, m5
+    paddd                m6, m7
+    paddd                m4, m13
+    paddd                m4, m6
+    psrad                m4, rndshift
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+%ifidn %1, put
+    packuswb            xm4, xm4
+    movq             [dstq], xm4
+    add                dstq, dsm
+%else
+    mova             [tmpq], xm4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .hloop_prep
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .vloop
+    test                myd, 0x400
+    mov            [rsp+52], myd
+    mov                 r4d, [rsp+ 0]
+    mov                 r6d, [rsp+ 8]
+    mov                 r7d, [rsp+ 4]
+    mov                 r9d, [rsp+12]
+    jz .skip_line
+    vpbroadcastq         m6, [srcq+r13]
+    vpbroadcastq         m7, [srcq+ rX]
+    movq                xm4, [srcq+ r4]
+    movq                xm5, [srcq+ r6]
+    movhps              xm4, [srcq+ r7]
+    movhps              xm5, [srcq+ r9]
+    vinserti128          m4, [srcq+r10], 1
+    vinserti128          m5, [srcq+r11], 1
+    add                srcq, ssq
+    mov                 myd, [rsp+52]
+    mov                 dyd, dym
+    pshufb               m0, m14
+    pshufb               m1, m14
+    pshufb               m2, m14
+    pshufb               m3, m14
+    vpblendd             m4, m6, 0xc0
+    vpblendd             m5, m7, 0xc0
+    pmaddubsw            m4, m15
+    pmaddubsw            m5, m10
+    phaddw               m4, m5
+    pslld                m5, m4, 16
+    paddw                m4, m5
+    pmulhrsw             m4, m12
+    pblendw              m0, m1, 0xaa
+    pblendw              m1, m2, 0xaa
+    pblendw              m2, m3, 0xaa
+    pblendw              m3, m4, 0xaa
+    jmp .vloop
+.skip_line:
+    mova                 m0, m1
+    mova                 m1, m2
+    mova                 m2, m3
+    vpbroadcastq         m7, [srcq+r13]
+    vpbroadcastq         m8, [srcq+ rX]
+    movq                xm3, [srcq+ r4]
+    movq                xm4, [srcq+ r6]
+    movhps              xm3, [srcq+ r7]
+    movhps              xm4, [srcq+ r9]
+    vinserti128          m3, [srcq+r10], 1
+    vinserti128          m4, [srcq+r11], 1
+    add                srcq, ssq
+    movq                xm5, [srcq+ r4]
+    movq                xm6, [srcq+ r6]
+    movhps              xm5, [srcq+ r7]
+    movhps              xm6, [srcq+ r9]
+    vinserti128          m5, [srcq+r10], 1
+    vinserti128          m6, [srcq+r11], 1
+    vpbroadcastq         m9, [srcq+r13]
+    vpbroadcastq        m11, [srcq+ rX]
+    add                srcq, ssq
+    mov                 myd, [rsp+52]
+    mov                 dyd, dym
+    vpblendd             m3, m7, 0xc0
+    vpblendd             m4, m8, 0xc0
+    vpblendd             m5, m9, 0xc0
+    vpblendd             m6, m11, 0xc0
+    pmaddubsw            m3, m15
+    pmaddubsw            m4, m10
+    pmaddubsw            m5, m15
+    pmaddubsw            m6, m10
+    phaddw               m3, m4
+    phaddw               m5, m6
+    psrld                m4, m3, 16
+    pslld                m6, m5, 16
+    paddw                m3, m4
+    paddw                m5, m6
+    pblendw              m3, m5, 0xaa
+    pmulhrsw             m3, m12
+    jmp .vloop
+.dy1:
+    movzx                wd, word [base+%1_8tap_scaled_avx2_dy1_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%ifidn %1, put
+.dy1_w2:
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd               xm15, t0d
+    punpckldq            m8, m9, m8
+    paddd               m14, m8 ; mx+dx*[0-1]
+    vpbroadcastd        m11, [base+pd_0x4000]
+    vpbroadcastd       xm15, xm15
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd              xm15, xm8
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    vbroadcasti128       m5, [base+bdct_lb_dw]
+    vbroadcasti128       m6, [base+subpel_s_shuf2]
+    vpbroadcastd        m15, [base+subpel_filters+r4*8+2]
+    vpbroadcastd         m7, [base+subpel_filters+r6*8+2]
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+    movq                xm0, [srcq+ssq*0]
+    movq                xm1, [srcq+ssq*2]
+    movhps              xm0, [srcq+ssq*1]
+    movhps              xm1, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pshufb              m14, m5
+    paddb               m14, m6
+    vinserti128          m0, [srcq+ssq*0], 1
+    vinserti128          m1, [srcq+ssq*2], 1
+    vpbroadcastq         m2, [srcq+ssq*1]
+    add                srcq, ss3q
+    movq               xm10, r4q
+    pmovsxbw           xm10, xm10
+    vpblendd            m15, m7, 0xaa
+    pblendvb            m15, m11, m8
+    pshufd              xm8, xm10, q0000
+    pshufd              xm9, xm10, q1111
+    pshufd             xm11, xm10, q3333
+    pshufd             xm10, xm10, q2222
+    vpblendd             m0, m2, 0xc0
+    pshufb               m1, m14
+    pshufb               m0, m14
+    pmaddubsw            m1, m15
+    pmaddubsw            m0, m15
+    phaddw               m0, m1
+    pmulhrsw             m0, m12
+    vextracti128        xm1, m0, 1
+    palignr             xm2, xm1, xm0, 4
+    pshufd              xm4, xm1, q2121
+    punpcklwd           xm3, xm0, xm2       ; 01 12
+    punpckhwd           xm0, xm2            ; 23 34
+    punpcklwd           xm2, xm1, xm4       ; 45 56
+.dy1_w2_loop:
+    movq                xm1, [srcq+ssq*0]
+    movhps              xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd             xm5, xm3, xm8
+    pmaddwd             xm6, xm0, xm9
+    pmaddwd             xm7, xm2, xm10
+    mova                xm3, xm0
+    mova                xm0, xm2
+    paddd               xm5, xm13
+    paddd               xm6, xm7
+    pshufb              xm1, xm14
+    pmaddubsw           xm1, xm15
+    phaddw              xm1, xm1
+    pmulhrsw            xm1, xm12
+    palignr             xm7, xm1, xm4, 12
+    punpcklwd           xm2, xm7, xm1     ; 67 78
+    pmaddwd             xm7, xm2, xm11
+    mova                xm4, xm1
+    paddd               xm5, xm6
+    paddd               xm5, xm7
+    psrad               xm5, rndshift
+    packssdw            xm5, xm5
+    packuswb            xm5, xm5
+    pextrw     [dstq+dsq*0], xm5, 0
+    pextrw     [dstq+dsq*1], xm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .dy1_w2_loop
+    RET
+%endif
+.dy1_w4:
+    mov                 myd, mym
+    vbroadcasti128       m7, [base+rescale_mul]
+    movzx               t0d, t0b
+    dec                srcq
+    movd               xm15, t0d
+    pmaddwd              m8, m7
+    vpbroadcastd        m11, [base+pd_0x4000]
+    vpbroadcastd       xm15, xm15
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd              xm15, xm8
+    vpermq               m8, m8, q3120
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 2
+    pextrd             r11d, xm15, 1
+    pextrd             r13d, xm15, 3
+    movd               xm15, [base+subpel_filters+r4*8+2]
+    vpbroadcastd         m7, [base+subpel_filters+r6*8+2]
+    movu                xm2, [srcq+ssq*0]
+    movu                xm3, [srcq+ssq*2]
+    vbroadcasti128       m5, [base+bdct_lb_dw]
+    vpbroadcastq         m6, [base+subpel_s_shuf2]
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+    pinsrd             xm15, [base+subpel_filters+r11*8+2], 1
+    vpblendd             m7, [base+subpel_filters+r13*8+2-20], 0x20
+    vinserti128          m2, [srcq+ssq*1], 1
+    vinserti128          m3, [srcq+ss3q ], 1
+    lea                srcq, [srcq+ssq*4]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pshufb              m14, m5
+    paddb               m14, m6
+    movu                xm4, [srcq+ssq*0]
+    movu                xm5, [srcq+ssq*2]
+    vinserti128          m4, [srcq+ssq*1], 1
+    add                srcq, ss3q
+    vpblendd            m15, m7, 0x30
+    punpcklqdq          m15, m15
+    pblendvb            m15, m11, m8
+    movq               xm10, r4q
+    punpcklqdq         xm10, xm10
+    pmovsxbw            m10, xm10
+    pshufb               m2, m14
+    pshufb               m3, m14
+    pshufb               m4, m14
+    pshufb              xm5, xm14
+    vpermq               m2, m2, q3120
+    vpermq               m3, m3, q3120
+    vpermq               m4, m4, q3120
+    vpermq               m5, m5, q3120
+    pshufd               m7, m10, q0000
+    pshufd               m8, m10, q1111
+    pshufd               m9, m10, q2222
+    pshufd              m10, m10, q3333
+    pmaddubsw            m2, m15
+    pmaddubsw            m3, m15
+    pmaddubsw            m4, m15
+    pmaddubsw            m5, m15
+    phaddw               m2, m3
+    phaddw               m4, m5
+    pmulhrsw             m2, m12
+    pmulhrsw             m4, m12
+    palignr              m5, m4, m2, 4
+    pshufd               m3, m4, q2121
+    punpcklwd            m0, m2, m5     ; 01 12
+    punpckhwd            m1, m2, m5     ; 23 34
+    punpcklwd            m2, m4, m3     ; 45 56
+.dy1_w4_loop:
+    movu               xm11, [srcq+ssq*0]
+    vinserti128         m11, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m4, m0, m7
+    pmaddwd              m5, m1, m8
+    pmaddwd              m6, m2, m9
+    mova                 m0, m1
+    mova                 m1, m2
+    paddd                m4, m13
+    paddd                m5, m6
+    pshufb              m11, m14
+    vpermq              m11, m11, q3120
+    pmaddubsw           m11, m15
+    phaddw              m11, m11
+    pmulhrsw            m11, m12
+    palignr              m6, m11, m3, 12
+    punpcklwd            m2, m6, m11    ; 67 78
+    mova                 m3, m11
+    pmaddwd              m6, m2, m10
+    paddd                m4, m5
+    paddd                m4, m6
+    psrad                m4, rndshift
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+%ifidn %1, put
+    packuswb            xm4, xm4
+    pshuflw             xm4, xm4, q3120
+    movd       [dstq+dsq*0], xm4
+    pextrd     [dstq+dsq*1], xm4, 1
+    lea                dstq, [dstq+dsq*2]
+%else
+    pshufd              xm4, xm4, q3120
+    mova             [tmpq], xm4
+    add                tmpq, 16
+%endif
+    sub                  hd, 2
+    jg .dy1_w4_loop
+    MC_8TAP_SCALED_RET
+.dy1_w8:
+    mov      dword [rsp+72], 1
+    movifprep   tmp_stridem, 16
+    jmp .dy1_w_start
+.dy1_w16:
+    mov      dword [rsp+72], 2
+    movifprep   tmp_stridem, 32
+    jmp .dy1_w_start
+.dy1_w32:
+    mov      dword [rsp+72], 4
+    movifprep   tmp_stridem, 64
+    jmp .dy1_w_start
+.dy1_w64:
+    mov      dword [rsp+72], 8
+    movifprep   tmp_stridem, 128
+    jmp .dy1_w_start
+.dy1_w128:
+    mov      dword [rsp+72], 16
+    movifprep   tmp_stridem, 256
+.dy1_w_start:
+    mov                 myd, mym
+%ifidn %1, put
+    movifnidn           dsm, dsq
+%endif
+    shr                 t0d, 16
+    sub                srcq, 3
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pmaddwd              m8, [base+rescale_mul]
+    movd               xm15, t0d
+    mov            [rsp+76], t0d
+    mov            [rsp+80], srcq
+    mov            [rsp+88], r0q ; dstq / tmpq
+%if UNIX64
+    mov                  hm, hd
+%endif
+    shl           dword dxm, 3 ; dx*8
+    vpbroadcastd        m15, xm15
+    paddd               m14, m8 ; mx+dx*[0-7]
+    movq                xm0, r4q
+    pmovsxbw            xm0, xm0
+    mova           [rsp+96], xm0
+    jmp .dy1_hloop
+.dy1_hloop_prep:
+    dec      dword [rsp+72]
+    jz .ret
+    add      qword [rsp+88], 8*(isprep+1)
+    mov                  hd, hm
+    vpbroadcastd         m8, dxm
+    vpbroadcastd        m10, [base+pd_0x3ff]
+    paddd               m14, m8, [rsp+32]
+    vpbroadcastd        m15, [rsp+76]
+    pxor                 m9, m9
+    mov                srcq, [rsp+80]
+    mov                 r0q, [rsp+88] ; dstq / tmpq
+.dy1_hloop:
+    vpbroadcastq        m11, [base+pq_0x40000000]
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd               m15, m6
+    pcmpeqd              m6, m9
+    vextracti128        xm7, m15, 1
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 2
+    pextrd              r7d, xm15, 1
+    pextrd              r9d, xm15, 3
+    movd               r10d, xm7
+    pextrd             r11d, xm7, 2
+    pextrd             r13d, xm7, 1
+    pextrd              rXd, xm7, 3
+    movu           [rsp+32], m14
+    movq               xm15, [base+subpel_filters+ r4*8]
+    movq               xm10, [base+subpel_filters+ r6*8]
+    movhps             xm15, [base+subpel_filters+ r7*8]
+    movhps             xm10, [base+subpel_filters+ r9*8]
+    vinserti128         m15, [base+subpel_filters+r10*8], 1
+    vinserti128         m10, [base+subpel_filters+r11*8], 1
+    vpbroadcastq         m9, [base+subpel_filters+r13*8]
+    vpbroadcastq         m8, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    vextracti128        xm7, m14, 1
+    movq           [rsp+64], xm14
+    movd                r4d, xm14
+    pextrd              r6d, xm14, 2
+    pextrd              r7d, xm14, 1
+    pextrd              r9d, xm14, 3
+    movd               r10d, xm7
+    pextrd             r11d, xm7, 2
+    pextrd             r13d, xm7, 1
+    pextrd              rXd, xm7, 3
+    pshufd               m5, m6, q1100
+    pshufd               m6, m6, q3322
+    vpblendd            m15, m9, 0xc0
+    vpblendd            m10, m8, 0xc0
+    pblendvb            m15, m11, m5
+    pblendvb            m10, m11, m6
+    vbroadcasti128      m14, [base+subpel_s_shuf8]
+    MC_8TAP_SCALED_H 0, 1, 2, 3, 4, 5, 6, 7  ; 0a 1a 0b 1b
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 7, 8  ; 2a 3a 2b 3b
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 7, 8, 9  ; 4a 5a 4b 5b
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 7, 8, 9, 11 ; 6a 7a 6b 7b
+    movu              [rsp], m10
+    vpbroadcastd         m8, [rsp+0x60]
+    vpbroadcastd         m9, [rsp+0x64]
+    vpbroadcastd        m10, [rsp+0x68]
+    vpbroadcastd        m11, [rsp+0x6c]
+    pshufb               m0, m14    ; 01a 01b
+    pshufb               m1, m14    ; 23a 23b
+    pshufb               m2, m14    ; 45a 45b
+    pshufb               m3, m14    ; 67a 67b
+    vbroadcasti128      m14, [base+wswap]
+.dy1_vloop:
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m9
+    pmaddwd              m6, m2, m10
+    pmaddwd              m7, m3, m11
+    paddd                m4, m5
+    paddd                m6, m7
+    paddd                m4, m13
+    paddd                m4, m6
+    psrad                m4, rndshift
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+%ifidn %1, put
+    packuswb            xm4, xm4
+    movq             [dstq], xm4
+    add                dstq, dsm
+%else
+    mova             [tmpq], xm4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .dy1_hloop_prep
+    movq                xm4, [srcq+ r4]
+    movq                xm5, [srcq+ r6]
+    movhps              xm4, [srcq+ r7]
+    movhps              xm5, [srcq+ r9]
+    vinserti128          m4, [srcq+r10], 1
+    vinserti128          m5, [srcq+r11], 1
+    vpbroadcastq         m6, [srcq+r13]
+    vpbroadcastq         m7, [srcq+ rX]
+    add                srcq, ssq
+    pshufb               m0, m14
+    pshufb               m1, m14
+    pshufb               m2, m14
+    pshufb               m3, m14
+    vpblendd             m4, m6, 0xc0
+    vpblendd             m5, m7, 0xc0
+    pmaddubsw            m4, m15
+    pmaddubsw            m5, [rsp]
+    phaddw               m4, m5
+    pslld                m5, m4, 16
+    paddw                m4, m5
+    pmulhrsw             m4, m12
+    pblendw              m0, m1, 0xaa
+    pblendw              m1, m2, 0xaa
+    pblendw              m2, m3, 0xaa
+    pblendw              m3, m4, 0xaa
+    jmp .dy1_vloop
+.dy2:
+    movzx                wd, word [base+%1_8tap_scaled_avx2_dy2_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%ifidn %1, put
+.dy2_w2:
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd               xm15, t0d
+    punpckldq            m8, m9, m8
+    paddd               m14, m8 ; mx+dx*[0-1]
+    vpbroadcastd        m11, [base+pd_0x4000]
+    vpbroadcastd       xm15, xm15
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd              xm15, xm8
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    vbroadcasti128       m5, [base+bdct_lb_dw]
+    vbroadcasti128       m6, [base+subpel_s_shuf2]
+    vpbroadcastd        m15, [base+subpel_filters+r4*8+2]
+    vpbroadcastd         m7, [base+subpel_filters+r6*8+2]
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+    movq                xm0, [srcq+ssq*0]
+    vpbroadcastq         m2, [srcq+ssq*1]
+    movhps              xm0, [srcq+ssq*2]
+    vpbroadcastq         m3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pshufb              m14, m5
+    paddb               m14, m6
+    vpblendd            m15, m7, 0xaa
+    pblendvb            m15, m11, m8
+    movhps              xm1, [srcq+ssq*0]
+    vpbroadcastq         m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    vpblendd             m0, m2, 0x30
+    vpblendd             m1, m4, 0xc0
+    vpblendd             m0, m3, 0xc0
+    pshufb               m0, m14
+    pshufb               m1, m14
+    pmaddubsw            m0, m15
+    pmaddubsw            m1, m15
+    movq               xm11, r4q
+    pmovsxbw           xm11, xm11
+    phaddw               m0, m1
+    pmulhrsw             m0, m12            ; 0 2 _ 4  1 3 _ 5
+    pshufd              xm8, xm11, q0000
+    pshufd              xm9, xm11, q1111
+    pshufd             xm10, xm11, q2222
+    pshufd             xm11, xm11, q3333
+    pshufd               m2, m0, q3110      ; 0 2 2 4  1 3 3 5
+    vextracti128        xm1, m2, 1
+    punpcklwd           xm3, xm2, xm1       ; 01 23
+    punpckhwd           xm2, xm1            ; 23 45
+.dy2_w2_loop:
+    movq                xm6, [srcq+ssq*0]
+    vpbroadcastq         m7, [srcq+ssq*1]
+    movhps              xm6, [srcq+ssq*2]
+    vpbroadcastq         m1, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pmaddwd             xm4, xm3, xm8
+    pmaddwd             xm5, xm2, xm9
+    vpblendd             m6, m7, 0x30
+    vpblendd             m6, m1, 0xc0
+    pshufb               m6, m14
+    pmaddubsw            m6, m15
+    phaddw               m6, m6
+    pmulhrsw             m6, m12
+    palignr              m0, m6, m0, 8
+    pshufd               m2, m0, q3221
+    vextracti128        xm1, m2, 1
+    punpcklwd           xm3, xm2, xm1       ; 45 67
+    punpckhwd           xm2, xm1            ; 67 89
+    pmaddwd             xm6, xm3, xm10
+    pmaddwd             xm7, xm2, xm11
+    paddd               xm4, xm5
+    paddd               xm4, xm13
+    paddd               xm6, xm7
+    paddd               xm4, xm6
+    psrad               xm4, rndshift
+    packssdw            xm4, xm4
+    packuswb            xm4, xm4
+    pextrw     [dstq+dsq*0], xm4, 0
+    pextrw     [dstq+dsq*1], xm4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .dy2_w2_loop
+    RET
+%endif
+.dy2_w4:
+    mov                 myd, mym
+    vbroadcasti128       m7, [base+rescale_mul]
+    movzx               t0d, t0b
+    dec                srcq
+    movd               xm15, t0d
+    pmaddwd              m8, m7
+    vpbroadcastd        m11, [base+pd_0x4000]
+    vpbroadcastd       xm15, xm15
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd              xm15, xm8
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 1
+    pextrd             r11d, xm15, 2
+    pextrd             r13d, xm15, 3
+    movd               xm15, [base+subpel_filters+r4*8+2]
+    vbroadcasti128       m5, [base+bdct_lb_dw]
+    vpbroadcastq         m6, [base+subpel_s_shuf2]
+    pinsrd             xm15, [base+subpel_filters+r6*8+2], 1
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+    movu                xm0, [srcq+ssq*0]
+    movu                xm2, [srcq+ssq*2]
+    pinsrd             xm15, [base+subpel_filters+r11*8+2], 2
+    movu                xm1, [srcq+ssq*1]
+    movu                xm3, [srcq+ss3q ]
+    pinsrd             xm15, [base+subpel_filters+r13*8+2], 3
+    lea                srcq, [srcq+ssq*4]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    vinserti128         m15, xm15, 1
+    pshufb              m14, m5
+    paddb               m14, m6
+    vinserti128          m2, [srcq+ssq*0], 1
+    vinserti128          m3, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pblendvb            m15, m11, m8
+    pshufb              xm0, xm14
+    pshufb               m2, m14
+    pshufb              xm1, xm14
+    pshufb               m3, m14
+    pmaddubsw           xm0, xm15
+    pmaddubsw            m2, m15
+    pmaddubsw           xm1, xm15
+    pmaddubsw            m3, m15
+    movq               xm11, r4q
+    punpcklqdq         xm11, xm11
+    pmovsxbw            m11, xm11
+    phaddw               m0, m2
+    phaddw               m1, m3
+    pmulhrsw             m0, m12    ; 0 2  _ 4
+    pmulhrsw             m1, m12    ; 1 3  _ 5
+    pshufd               m8, m11, q0000
+    pshufd               m9, m11, q1111
+    pshufd              m10, m11, q2222
+    pshufd              m11, m11, q3333
+    punpcklwd           xm2, xm0, xm1
+    punpckhwd            m1, m0, m1     ; 23 45
+    vinserti128          m0, m2, xm1, 1 ; 01 23
+.dy2_w4_loop:
+    movu                xm6, [srcq+ssq*0]
+    movu                xm7, [srcq+ssq*1]
+    vinserti128          m6, [srcq+ssq*2], 1
+    vinserti128          m7, [srcq+ss3q ], 1
+    lea                srcq, [srcq+ssq*4]
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m9
+    pshufb               m6, m14
+    pshufb               m7, m14
+    pmaddubsw            m6, m15
+    pmaddubsw            m7, m15
+    psrld                m2, m6, 16
+    pslld                m3, m7, 16
+    paddw                m6, m2
+    paddw                m7, m3
+    pblendw              m6, m7, 0xaa   ; 67 89
+    pmulhrsw             m6, m12
+    paddd                m4, m5
+    vperm2i128           m0, m1, m6, 0x21 ; 45 67
+    mova                 m1, m6
+    pmaddwd              m6, m0, m10
+    pmaddwd              m7, m1, m11
+    paddd                m4, m13
+    paddd                m6, m7
+    paddd                m4, m6
+    psrad                m4, rndshift
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+%ifidn %1, put
+    packuswb            xm4, xm4
+    movd       [dstq+dsq*0], xm4
+    pextrd     [dstq+dsq*1], xm4, 1
+    lea                dstq, [dstq+dsq*2]
+%else
+    mova             [tmpq], xm4
+    add                tmpq, 16
+%endif
+    sub                  hd, 2
+    jg .dy2_w4_loop
+    MC_8TAP_SCALED_RET
+.dy2_w8:
+    mov      dword [rsp+40], 1
+    movifprep   tmp_stridem, 16
+    jmp .dy2_w_start
+.dy2_w16:
+    mov      dword [rsp+40], 2
+    movifprep   tmp_stridem, 32
+    jmp .dy2_w_start
+.dy2_w32:
+    mov      dword [rsp+40], 4
+    movifprep   tmp_stridem, 64
+    jmp .dy2_w_start
+.dy2_w64:
+    mov      dword [rsp+40], 8
+    movifprep   tmp_stridem, 128
+    jmp .dy2_w_start
+.dy2_w128:
+    mov      dword [rsp+40], 16
+    movifprep   tmp_stridem, 256
+.dy2_w_start:
+    mov                 myd, mym
+%ifidn %1, put
+    movifnidn           dsm, dsq
+%endif
+    shr                 t0d, 16
+    sub                srcq, 3
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pmaddwd              m8, [base+rescale_mul]
+    movd               xm15, t0d
+    mov            [rsp+64], t0d
+    mov            [rsp+48], srcq
+    mov            [rsp+56], r0q ; dstq / tmpq
+%if UNIX64
+    mov                  hm, hd
+%endif
+    shl           dword dxm, 3 ; dx*8
+    vpbroadcastd        m15, xm15
+    paddd               m14, m8 ; mx+dx*[0-7]
+    movq                xm0, r4q
+    pmovsxbw            xm0, xm0
+    mova         [rsp+0x50], xm0
+    jmp .dy2_hloop
+.dy2_hloop_prep:
+    dec      dword [rsp+40]
+    jz .ret
+    add      qword [rsp+56], 8*(isprep+1)
+    mov                  hd, hm
+    vpbroadcastd         m8, dxm
+    vpbroadcastd        m10, [base+pd_0x3ff]
+    paddd               m14, m8, [rsp]
+    vpbroadcastd        m15, [rsp+64]
+    pxor                 m9, m9
+    mov                srcq, [rsp+48]
+    mov                 r0q, [rsp+56] ; dstq / tmpq
+.dy2_hloop:
+    vpbroadcastq        m11, [base+pq_0x40000000]
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd               m15, m6
+    pcmpeqd              m6, m9
+    vextracti128        xm7, m15, 1
+    movd                r4d, xm15
+    pextrd              r6d, xm15, 2
+    pextrd              r7d, xm15, 1
+    pextrd              r9d, xm15, 3
+    movd               r10d, xm7
+    pextrd             r11d, xm7, 2
+    pextrd             r13d, xm7, 1
+    pextrd              rXd, xm7, 3
+    movu              [rsp], m14
+    movq               xm15, [base+subpel_filters+ r4*8]
+    movq               xm10, [base+subpel_filters+ r6*8]
+    movhps             xm15, [base+subpel_filters+ r7*8]
+    movhps             xm10, [base+subpel_filters+ r9*8]
+    vinserti128         m15, [base+subpel_filters+r10*8], 1
+    vinserti128         m10, [base+subpel_filters+r11*8], 1
+    vpbroadcastq         m9, [base+subpel_filters+r13*8]
+    vpbroadcastq         m8, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    vextracti128        xm7, m14, 1
+    movd                r4d, xm14
+    pextrd              r6d, xm14, 2
+    pextrd              r7d, xm14, 1
+    pextrd              r9d, xm14, 3
+    movd               r10d, xm7
+    pextrd             r11d, xm7, 2
+    pextrd             r13d, xm7, 1
+    pextrd              rXd, xm7, 3
+    pshufd               m5, m6, q1100
+    pshufd               m6, m6, q3322
+    vpblendd            m15, m9, 0xc0
+    vpblendd            m10, m8, 0xc0
+    pblendvb            m15, m11, m5
+    pblendvb            m10, m11, m6
+    vbroadcasti128      m14, [base+subpel_s_shuf8]
+    MC_8TAP_SCALED_H 0, 1, 2, 3, 4, 5, 6, 7  ; 0a 1a 0b 1b
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 7, 8  ; 2a 3a 2b 3b
+    MC_8TAP_SCALED_H 2, 3, 4, 5, 6, 7, 8, 9  ; 4a 5a 4b 5b
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 7, 8, 9, 11 ; 6a 7a 6b 7b
+    vpbroadcastd         m8, [rsp+0x50]
+    vpbroadcastd         m9, [rsp+0x54]
+    vpbroadcastd        m11, [rsp+0x58]
+    vpbroadcastd         m4, [rsp+0x5c]
+    pshufb               m0, m14    ; 01a 01b
+    pshufb               m1, m14    ; 23a 23b
+    pshufb               m2, m14    ; 45a 45b
+    pshufb               m3, m14    ; 67a 67b
+    SWAP                m14, m4
+.dy2_vloop:
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m9
+    pmaddwd              m6, m2, m11
+    pmaddwd              m7, m3, m14
+    paddd                m4, m5
+    paddd                m6, m7
+    paddd                m4, m13
+    paddd                m4, m6
+    psrad                m4, rndshift
+    vextracti128        xm5, m4, 1
+    packssdw            xm4, xm5
+%ifidn %1, put
+    packuswb            xm4, xm4
+    movq             [dstq], xm4
+    add                dstq, dsm
+%else
+    mova             [tmpq], xm4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .dy2_hloop_prep
+    mova                 m0, m1
+    mova                 m1, m2
+    mova                 m2, m3
+    movq                xm3, [srcq+ r4]
+    movq                xm4, [srcq+ r6]
+    movhps              xm3, [srcq+ r7]
+    movhps              xm4, [srcq+ r9]
+    vinserti128          m3, [srcq+r10], 1
+    vinserti128          m4, [srcq+r11], 1
+    vpbroadcastq         m5, [srcq+r13]
+    vpbroadcastq         m6, [srcq+ rX]
+    add                srcq, ssq
+    vpblendd             m3, m5, 0xc0
+    vpblendd             m4, m6, 0xc0
+    pmaddubsw            m3, m15
+    pmaddubsw            m4, m10
+    phaddw               m3, m4
+    movq                xm4, [srcq+ r4]
+    movq                xm5, [srcq+ r6]
+    movhps              xm4, [srcq+ r7]
+    movhps              xm5, [srcq+ r9]
+    vinserti128          m4, [srcq+r10], 1
+    vinserti128          m5, [srcq+r11], 1
+    vpbroadcastq         m6, [srcq+r13]
+    vpbroadcastq         m7, [srcq+ rX]
+    add                srcq, ssq
+    vpblendd             m4, m6, 0xc0
+    vpblendd             m5, m7, 0xc0
+    pmaddubsw            m4, m15
+    pmaddubsw            m5, m10
+    phaddw               m4, m5
+    psrld                m5, m3, 16
+    pslld                m6, m4, 16
+    paddw                m3, m5
+    paddw                m4, m6
+    pblendw              m3, m4, 0xaa
+    pmulhrsw             m3, m12
+    jmp .dy2_vloop
+.ret:
+    MC_8TAP_SCALED_RET 0
+%undef isprep
+%endmacro
+
+%macro BILIN_SCALED_FN 1
+cglobal %1_bilin_scaled_8bpc
+    mov                 t0d, (5*15 << 16) | 5*15
+    mov                 t1d, t0d
+    jmp mangle(private_prefix %+ _%1_8tap_scaled_8bpc %+ SUFFIX)
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 6, 5
+%else
+DECLARE_REG_TMP 6, 8
+%endif
+
+%define PUT_8TAP_SCALED_FN FN put_8tap_scaled,
+%define PREP_8TAP_SCALED_FN FN prep_8tap_scaled,
+
+BILIN_SCALED_FN put
+PUT_8TAP_SCALED_FN sharp,          SHARP,   SHARP,   put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN sharp_smooth,   SHARP,   SMOOTH,  put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN smooth,         SMOOTH,  SMOOTH,  put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN sharp_regular,  SHARP,   REGULAR, put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN regular_sharp,  REGULAR, SHARP,   put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN smooth_regular, SMOOTH,  REGULAR, put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN regular_smooth, REGULAR, SMOOTH,  put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN regular,        REGULAR, REGULAR
+MC_8TAP_SCALED put
+
+%if WIN64
+DECLARE_REG_TMP 5, 4
+%else
+DECLARE_REG_TMP 6, 7
+%endif
+
+BILIN_SCALED_FN prep
+PREP_8TAP_SCALED_FN sharp,          SHARP,   SHARP,   prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN smooth,         SMOOTH,  SMOOTH,  prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN smooth_regular, SMOOTH,  REGULAR, prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN regular_smooth, REGULAR, SMOOTH,  prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN regular,        REGULAR, REGULAR
+MC_8TAP_SCALED prep
+
+%macro WARP_V 5 ; dst, 02, 46, 13, 57
+    ; Can be done using gathers, but that's terribly slow on many CPU:s
+    lea               tmp1d, [myq+deltaq*4]
+    lea               tmp2d, [myq+deltaq*1]
+    shr                 myd, 10
+    shr               tmp1d, 10
+    movq                xm8, [filterq+myq  *8]
+    vinserti128          m8, [filterq+tmp1q*8], 1 ; a e
+    lea               tmp1d, [tmp2q+deltaq*4]
+    lea                 myd, [tmp2q+deltaq*1]
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    movq                xm0, [filterq+tmp2q*8]
+    vinserti128          m0, [filterq+tmp1q*8], 1 ; b f
+    lea               tmp1d, [myq+deltaq*4]
+    lea               tmp2d, [myq+deltaq*1]
+    shr                 myd, 10
+    shr               tmp1d, 10
+    movq                xm9, [filterq+myq  *8]
+    vinserti128          m9, [filterq+tmp1q*8], 1 ; c g
+    lea               tmp1d, [tmp2q+deltaq*4]
+    lea                 myd, [tmp2q+gammaq]       ; my += gamma
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    punpcklwd            m8, m0
+    movq                xm0, [filterq+tmp2q*8]
+    vinserti128          m0, [filterq+tmp1q*8], 1 ; d h
+    punpcklwd            m0, m9, m0
+    punpckldq            m9, m8, m0
+    punpckhdq            m0, m8, m0
+    punpcklbw            m8, m11, m9 ; a0 a2 b0 b2 c0 c2 d0 d2 << 8
+    punpckhbw            m9, m11, m9 ; a4 a6 b4 b6 c4 c6 d4 d6 << 8
+    pmaddwd             m%2, m8
+    pmaddwd              m9, m%3
+    punpcklbw            m8, m11, m0 ; a1 a3 b1 b3 c1 c3 d1 d3 << 8
+    punpckhbw            m0, m11, m0 ; a5 a7 b5 b7 c5 c7 d5 d7 << 8
+    pmaddwd              m8, m%4
+    pmaddwd              m0, m%5
+    paddd               m%2, m9
+    paddd                m0, m8
+    paddd               m%1, m0, m%2
+%endmacro
+
+cglobal warp_affine_8x8t_8bpc, 0, 14, 0, tmp, ts
+%if WIN64
+    sub                 rsp, 0xa0
+%endif
+    call mangle(private_prefix %+ _warp_affine_8x8_8bpc_avx2).main
+.loop:
+    psrad                m7, 13
+    psrad                m0, 13
+    packssdw             m7, m0
+    pmulhrsw             m7, m14 ; (x + (1 << 6)) >> 7
+    vpermq               m7, m7, q3120
+    mova         [tmpq+tsq*0], xm7
+    vextracti128 [tmpq+tsq*2], m7, 1
+    dec                 r4d
+    jz   mangle(private_prefix %+ _warp_affine_8x8_8bpc_avx2).end
+    call mangle(private_prefix %+ _warp_affine_8x8_8bpc_avx2).main2
+    lea                tmpq, [tmpq+tsq*4]
+    jmp .loop
+
+cglobal warp_affine_8x8_8bpc, 0, 14, 0, dst, ds, src, ss, abcd, mx, tmp2, alpha, \
+                                        beta, filter, tmp1, delta, my, gamma
+%if WIN64
+    %assign xmm_regs_used 16
+    %assign stack_size_padded 0xa0
+    SUB                 rsp, stack_size_padded
+%endif
+    call .main
+    jmp .start
+.loop:
+    call .main2
+    lea                dstq, [dstq+dsq*2]
+.start:
+    psrad                m7, 18
+    psrad                m0, 18
+    packusdw             m7, m0
+    pavgw                m7, m11 ; (x + (1 << 10)) >> 11
+    vextracti128        xm0, m7, 1
+    packuswb            xm7, xm0
+    pshufd              xm7, xm7, q3120
+    movq       [dstq+dsq*0], xm7
+    movhps     [dstq+dsq*1], xm7
+    dec                 r4d
+    jg .loop
+.end:
+    RET
+ALIGN function_align
+.main:
+    ; Stack is offset due to call
+    %assign stack_offset stack_offset + gprsize
+    %assign stack_size stack_size + gprsize
+    %assign stack_size_padded stack_size_padded + gprsize
+    movifnidn         abcdq, abcdmp
+    movifnidn           mxd, mxm
+    WIN64_PUSH_XMM
+    movsx            alphad, word [abcdq+2*0]
+    movsx             betad, word [abcdq+2*1]
+    mova                m12, [warp_8x8_shufA]
+    mova                m13, [warp_8x8_shufB]
+    vpbroadcastd        m14, [pw_8192]
+    vpbroadcastd        m15, [pd_32768]
+    pxor                m11, m11
+    lea             filterq, [mc_warp_filter2]
+    lea               tmp1q, [ssq*3+3]
+    add                 mxd, 512+(64<<10)
+    lea               tmp2d, [alphaq*3]
+    sub                srcq, tmp1q    ; src -= src_stride*3 + 3
+    sub               betad, tmp2d    ; beta -= alpha*3
+    mov                 myd, r6m
+    call .h
+    psrld                m1, m0, 16
+    call .h
+    psrld                m4, m0, 16
+    call .h
+    pblendw              m1, m0, 0xaa ; 02
+    call .h
+    pblendw              m4, m0, 0xaa ; 13
+    call .h
+    psrld                m2, m1, 16
+    pblendw              m2, m0, 0xaa ; 24
+    call .h
+    psrld                m5, m4, 16
+    pblendw              m5, m0, 0xaa ; 35
+    call .h
+    psrld                m3, m2, 16
+    pblendw              m3, m0, 0xaa ; 46
+    movsx            deltad, word [abcdq+2*2]
+    movsx            gammad, word [abcdq+2*3]
+    add                 myd, 512+(64<<10)
+    mov                 r4d, 4
+    lea               tmp1d, [deltaq*3]
+    sub              gammad, tmp1d    ; gamma -= delta*3
+.main2:
+    call .h
+    psrld                m6, m5, 16
+    pblendw              m6, m0, 0xaa ; 57
+    WARP_V                7, 1, 3, 4, 6
+    call .h
+    mova                 m1, m2
+    mova                 m2, m3
+    psrld                m3, 16
+    pblendw              m3, m0, 0xaa ; 68
+    WARP_V                0, 4, 6, 1, 3
+    mova                 m4, m5
+    mova                 m5, m6
+    ret
+ALIGN function_align
+.h:
+    lea               tmp1d, [mxq+alphaq*4]
+    lea               tmp2d, [mxq+alphaq*1]
+    vbroadcasti128      m10, [srcq]
+    shr                 mxd, 10
+    shr               tmp1d, 10
+    movq                xm8, [filterq+mxq  *8]
+    vinserti128          m8, [filterq+tmp1q*8], 1
+    lea               tmp1d, [tmp2q+alphaq*4]
+    lea                 mxd, [tmp2q+alphaq*1]
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    movq                xm0, [filterq+tmp2q*8]
+    vinserti128          m0, [filterq+tmp1q*8], 1
+    lea               tmp1d, [mxq+alphaq*4]
+    lea               tmp2d, [mxq+alphaq*1]
+    shr                 mxd, 10
+    shr               tmp1d, 10
+    movq                xm9, [filterq+mxq  *8]
+    vinserti128          m9, [filterq+tmp1q*8], 1
+    lea               tmp1d, [tmp2q+alphaq*4]
+    lea                 mxd, [tmp2q+betaq] ; mx += beta
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    punpcklqdq           m8, m0  ; 0 1   4 5
+    movq                xm0, [filterq+tmp2q*8]
+    vinserti128          m0, [filterq+tmp1q*8], 1
+    punpcklqdq           m9, m0  ; 2 3   6 7
+    pshufb               m0, m10, m12
+    pmaddubsw            m0, m8
+    pshufb              m10, m13
+    pmaddubsw           m10, m9
+    add                srcq, ssq
+    phaddw               m0, m10
+    pmaddwd              m0, m14 ; 17-bit intermediate, upshifted by 13
+    paddd                m0, m15 ; rounded 14-bit result in upper 16 bits of dword
+    ret
+
+%macro BIDIR_FN 1 ; op
+    %1                    0
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    vextracti128        xm1, m0, 1
+    movd   [dstq          ], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    cmp                  hd, 4
+    je .ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq          ], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+    cmp                  hd, 8
+    je .ret
+    %1                    2
+    lea                dstq, [dstq+strideq*4]
+    vextracti128        xm1, m0, 1
+    movd   [dstq          ], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq          ], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+.ret:
+    RET
+.w8_loop:
+    %1_INC_PTR            2
+    %1                    0
+    lea                dstq, [dstq+strideq*4]
+.w8:
+    vextracti128        xm1, m0, 1
+    movq   [dstq          ], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.w16_loop:
+    %1_INC_PTR            4
+    %1                    0
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    vpermq               m0, m0, q3120
+    mova         [dstq          ], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    %1                    2
+    vpermq               m0, m0, q3120
+    mova         [dstq+strideq*2], xm0
+    vextracti128 [dstq+stride3q ], m0, 1
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    %1_INC_PTR            4
+    %1                    0
+    lea                dstq, [dstq+strideq*2]
+.w32:
+    vpermq               m0, m0, q3120
+    mova   [dstq+strideq*0], m0
+    %1                    2
+    vpermq               m0, m0, q3120
+    mova   [dstq+strideq*1], m0
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    %1_INC_PTR            4
+    %1                    0
+    add                dstq, strideq
+.w64:
+    vpermq               m0, m0, q3120
+    mova             [dstq], m0
+    %1                    2
+    vpermq               m0, m0, q3120
+    mova          [dstq+32], m0
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    %1                    0
+    add                dstq, strideq
+.w128:
+    vpermq               m0, m0, q3120
+    mova        [dstq+0*32], m0
+    %1                    2
+    vpermq               m0, m0, q3120
+    mova        [dstq+1*32], m0
+    %1_INC_PTR            8
+    %1                   -4
+    vpermq               m0, m0, q3120
+    mova        [dstq+2*32], m0
+    %1                   -2
+    vpermq               m0, m0, q3120
+    mova        [dstq+3*32], m0
+    dec                  hd
+    jg .w128_loop
+    RET
+%endmacro
+
+%macro AVG 1 ; src_offset
+    mova                 m0, [tmp1q+(%1+0)*32]
+    paddw                m0, [tmp2q+(%1+0)*32]
+    mova                 m1, [tmp1q+(%1+1)*32]
+    paddw                m1, [tmp2q+(%1+1)*32]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    packuswb             m0, m1
+%endmacro
+
+%macro AVG_INC_PTR 1
+    add               tmp1q, %1*32
+    add               tmp2q, %1*32
+%endmacro
+
+cglobal avg_8bpc, 4, 7, 3, dst, stride, tmp1, tmp2, w, h, stride3
+%define base r6-avg %+ SUFFIX %+ _table
+    lea                  r6, [avg %+ SUFFIX %+ _table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, dword [r6+wq*4]
+    vpbroadcastd         m2, [base+pw_1024]
+    add                  wq, r6
+    BIDIR_FN            AVG
+
+%macro W_AVG 1 ; src_offset
+    ; (a * weight + b * (16 - weight) + 128) >> 8
+    ; = ((a - b) * weight + (b << 4) + 128) >> 8
+    ; = ((((a - b) * ((weight-16) << 12)) >> 16) + a + 8) >> 4
+    ; = ((((b - a) * (-weight     << 12)) >> 16) + b + 8) >> 4
+    mova                 m0,     [tmp1q+(%1+0)*32]
+    psubw                m2, m0, [tmp2q+(%1+0)*32]
+    mova                 m1,     [tmp1q+(%1+1)*32]
+    psubw                m3, m1, [tmp2q+(%1+1)*32]
+    pmulhw               m2, m4
+    pmulhw               m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+%endmacro
+
+%define W_AVG_INC_PTR AVG_INC_PTR
+
+cglobal w_avg_8bpc, 4, 7, 6, dst, stride, tmp1, tmp2, w, h, stride3
+%define base r6-w_avg %+ SUFFIX %+ _table
+    lea                  r6, [w_avg %+ SUFFIX %+ _table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    vpbroadcastw         m4, r6m ; weight
+    movsxd               wq, dword [r6+wq*4]
+    vpbroadcastd         m5, [base+pw_2048]
+    psllw                m4, 12 ; (weight-16) << 12 when interpreted as signed
+    add                  wq, r6
+    cmp           dword r6m, 7
+    jg .weight_gt7
+    mov                  r6, tmp1q
+    pxor                 m0, m0
+    mov               tmp1q, tmp2q
+    psubw                m4, m0, m4 ; -weight
+    mov               tmp2q, r6
+.weight_gt7:
+    BIDIR_FN          W_AVG
+
+%macro MASK 1 ; src_offset
+    ; (a * m + b * (64 - m) + 512) >> 10
+    ; = ((a - b) * m + (b << 6) + 512) >> 10
+    ; = ((((b - a) * (-m << 10)) >> 16) + b + 8) >> 4
+    vpermq               m3,     [maskq+%1*16], q3120
+    mova                 m0,     [tmp2q+(%1+0)*32]
+    psubw                m1, m0, [tmp1q+(%1+0)*32]
+    psubb                m3, m4, m3
+    paddw                m1, m1     ; (b - a) << 1
+    paddb                m3, m3
+    punpcklbw            m2, m4, m3 ; -m << 9
+    pmulhw               m1, m2
+    paddw                m0, m1
+    mova                 m1,     [tmp2q+(%1+1)*32]
+    psubw                m2, m1, [tmp1q+(%1+1)*32]
+    paddw                m2, m2
+    punpckhbw            m3, m4, m3
+    pmulhw               m2, m3
+    paddw                m1, m2
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+%endmacro
+
+%macro MASK_INC_PTR 1
+    add               maskq, %1*16
+    add               tmp2q, %1*32
+    add               tmp1q, %1*32
+%endmacro
+
+cglobal mask_8bpc, 4, 8, 6, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-mask %+ SUFFIX %+ _table
+    lea                  r7, [mask %+ SUFFIX %+ _table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    mov               maskq, maskmp
+    movsxd               wq, dword [r7+wq*4]
+    vpbroadcastd         m5, [base+pw_2048]
+    pxor                 m4, m4
+    add                  wq, r7
+    BIDIR_FN           MASK
+
+%macro W_MASK 4-5 0 ; dst, mask, tmp_offset[1-2], 4:4:4
+    mova                m%1, [tmp1q+32*%3]
+    mova                 m1, [tmp2q+32*%3]
+    psubw                m1, m%1
+    pabsw               m%2, m1
+    psubusw             m%2, m6, m%2
+    psrlw               m%2, 8 ; 64 - m
+    psllw                m2, m%2, 10
+    pmulhw               m1, m2
+    paddw               m%1, m1
+    mova                 m1, [tmp1q+32*%4]
+    mova                 m2, [tmp2q+32*%4]
+    psubw                m2, m1
+    pabsw                m3, m2
+    psubusw              m3, m6, m3
+    psrlw                m3, 8
+%if %5
+    packuswb            m%2, m3
+    psubb               m%2, m5, m%2
+    vpermq              m%2, m%2, q3120
+%else
+    phaddw              m%2, m3
+%endif
+    psllw                m3, 10
+    pmulhw               m2, m3
+    paddw                m1, m2
+    pmulhrsw            m%1, m7
+    pmulhrsw             m1, m7
+    packuswb            m%1, m1
+%endmacro
+
+cglobal blend_8bpc, 3, 7, 7, dst, ds, tmp, w, h, mask
+%define base r6-blend_avx2_table
+    lea                  r6, [blend_avx2_table]
+    tzcnt                wd, wm
+    movifnidn         maskq, maskmp
+    movifnidn            hd, hm
+    movsxd               wq, dword [r6+wq*4]
+    vpbroadcastd         m4, [base+pb_64]
+    vpbroadcastd         m5, [base+pw_512]
+    sub                tmpq, maskq
+    add                  wq, r6
+    lea                  r6, [dsq*3]
+    jmp                  wq
+.w4:
+    movd                xm0, [dstq+dsq*0]
+    pinsrd              xm0, [dstq+dsq*1], 1
+    vpbroadcastd        xm1, [dstq+dsq*2]
+    pinsrd              xm1, [dstq+r6   ], 3
+    mova                xm6, [maskq]
+    psubb               xm3, xm4, xm6
+    punpcklbw           xm2, xm3, xm6
+    punpckhbw           xm3, xm6
+    mova                xm6, [maskq+tmpq]
+    add               maskq, 4*4
+    punpcklbw           xm0, xm6
+    punpckhbw           xm1, xm6
+    pmaddubsw           xm0, xm2
+    pmaddubsw           xm1, xm3
+    pmulhrsw            xm0, xm5
+    pmulhrsw            xm1, xm5
+    packuswb            xm0, xm1
+    movd       [dstq+dsq*0], xm0
+    pextrd     [dstq+dsq*1], xm0, 1
+    pextrd     [dstq+dsq*2], xm0, 2
+    pextrd     [dstq+r6   ], xm0, 3
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+ALIGN function_align
+.w8:
+    movq                xm1, [dstq+dsq*0]
+    movhps              xm1, [dstq+dsq*1]
+    vpbroadcastq         m2, [dstq+dsq*2]
+    vpbroadcastq         m3, [dstq+r6   ]
+    mova                 m0, [maskq]
+    mova                 m6, [maskq+tmpq]
+    add               maskq, 8*4
+    vpblendd             m1, m2, 0x30
+    vpblendd             m1, m3, 0xc0
+    psubb                m3, m4, m0
+    punpcklbw            m2, m3, m0
+    punpckhbw            m3, m0
+    punpcklbw            m0, m1, m6
+    punpckhbw            m1, m6
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    vextracti128        xm1, m0, 1
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    movq       [dstq+dsq*2], xm1
+    movhps     [dstq+r6   ], xm1
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w8
+    RET
+ALIGN function_align
+.w16:
+    mova                 m0, [maskq]
+    mova                xm1, [dstq+dsq*0]
+    vinserti128          m1, [dstq+dsq*1], 1
+    psubb                m3, m4, m0
+    punpcklbw            m2, m3, m0
+    punpckhbw            m3, m0
+    mova                 m6, [maskq+tmpq]
+    add               maskq, 16*2
+    punpcklbw            m0, m1, m6
+    punpckhbw            m1, m6
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w16
+    RET
+ALIGN function_align
+.w32:
+    mova                 m0, [maskq]
+    mova                 m1, [dstq]
+    mova                 m6, [maskq+tmpq]
+    add               maskq, 32
+    psubb                m3, m4, m0
+    punpcklbw            m2, m3, m0
+    punpckhbw            m3, m0
+    punpcklbw            m0, m1, m6
+    punpckhbw            m1, m6
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, dsq
+    dec                  hd
+    jg .w32
+    RET
+
+cglobal blend_v_8bpc, 3, 6, 6, dst, ds, tmp, w, h, mask
+%define base r5-blend_v_avx2_table
+    lea                  r5, [blend_v_avx2_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, dword [r5+wq*4]
+    vpbroadcastd         m5, [base+pw_512]
+    add                  wq, r5
+    add               maskq, obmc_masks-blend_v_avx2_table
+    jmp                  wq
+.w2:
+    vpbroadcastd        xm2, [maskq+2*2]
+.w2_s0_loop:
+    movd                xm0, [dstq+dsq*0]
+    pinsrw              xm0, [dstq+dsq*1], 1
+    movd                xm1, [tmpq]
+    add                tmpq, 2*2
+    punpcklbw           xm0, xm1
+    pmaddubsw           xm0, xm2
+    pmulhrsw            xm0, xm5
+    packuswb            xm0, xm0
+    pextrw     [dstq+dsq*0], xm0, 0
+    pextrw     [dstq+dsq*1], xm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w2_s0_loop
+    RET
+ALIGN function_align
+.w4:
+    vpbroadcastq        xm2, [maskq+4*2]
+.w4_loop:
+    movd                xm0, [dstq+dsq*0]
+    pinsrd              xm0, [dstq+dsq*1], 1
+    movq                xm1, [tmpq]
+    add                tmpq, 4*2
+    punpcklbw           xm0, xm1
+    pmaddubsw           xm0, xm2
+    pmulhrsw            xm0, xm5
+    packuswb            xm0, xm0
+    movd       [dstq+dsq*0], xm0
+    pextrd     [dstq+dsq*1], xm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    mova                xm3, [maskq+8*2]
+.w8_loop:
+    movq                xm0, [dstq+dsq*0]
+    vpbroadcastq        xm1, [dstq+dsq*1]
+    mova                xm2, [tmpq]
+    add                tmpq, 8*2
+    punpcklbw           xm0, xm2
+    punpckhbw           xm1, xm2
+    pmaddubsw           xm0, xm3
+    pmaddubsw           xm1, xm3
+    pmulhrsw            xm0, xm5
+    pmulhrsw            xm1, xm5
+    packuswb            xm0, xm1
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    vbroadcasti128       m3, [maskq+16*2]
+    vbroadcasti128       m4, [maskq+16*3]
+.w16_loop:
+    mova                xm1, [dstq+dsq*0]
+    vinserti128          m1, [dstq+dsq*1], 1
+    mova                 m2, [tmpq]
+    add                tmpq, 16*2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m4
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+ALIGN function_align
+.w32:
+    mova                xm3, [maskq+16*4]
+    vinserti128          m3, [maskq+16*6], 1
+    mova                xm4, [maskq+16*5]
+    vinserti128          m4, [maskq+16*7], 1
+.w32_loop:
+    mova                 m1, [dstq]
+    mova                 m2, [tmpq]
+    add                tmpq, 32
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m4
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, dsq
+    dec                  hd
+    jg .w32_loop
+    RET
+
+cglobal blend_h_8bpc, 4, 7, 6, dst, ds, tmp, w, h, mask
+%define base r5-blend_h_avx2_table
+    lea                  r5, [blend_h_avx2_table]
+    mov                 r6d, wd
+    tzcnt                wd, wd
+    mov                  hd, hm
+    movsxd               wq, dword [r5+wq*4]
+    vpbroadcastd         m5, [base+pw_512]
+    add                  wq, r5
+    lea               maskq, [base+obmc_masks+hq*2]
+    lea                  hd, [hq*3]
+    shr                  hd, 2 ; h * 3/4
+    lea               maskq, [maskq+hq*2]
+    neg                  hq
+    jmp                  wq
+.w2:
+    movd                xm0, [dstq+dsq*0]
+    pinsrw              xm0, [dstq+dsq*1], 1
+    movd                xm2, [maskq+hq*2]
+    movd                xm1, [tmpq]
+    add                tmpq, 2*2
+    punpcklwd           xm2, xm2
+    punpcklbw           xm0, xm1
+    pmaddubsw           xm0, xm2
+    pmulhrsw            xm0, xm5
+    packuswb            xm0, xm0
+    pextrw     [dstq+dsq*0], xm0, 0
+    pextrw     [dstq+dsq*1], xm0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w2
+    RET
+ALIGN function_align
+.w4:
+    mova                xm3, [blend_shuf]
+.w4_loop:
+    movd                xm0, [dstq+dsq*0]
+    pinsrd              xm0, [dstq+dsq*1], 1
+    movd                xm2, [maskq+hq*2]
+    movq                xm1, [tmpq]
+    add                tmpq, 4*2
+    pshufb              xm2, xm3
+    punpcklbw           xm0, xm1
+    pmaddubsw           xm0, xm2
+    pmulhrsw            xm0, xm5
+    packuswb            xm0, xm0
+    movd       [dstq+dsq*0], xm0
+    pextrd     [dstq+dsq*1], xm0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w4_loop
+    RET
+ALIGN function_align
+.w8:
+    vbroadcasti128       m4, [blend_shuf]
+    shufpd               m4, m4, 0x03
+.w8_loop:
+    vpbroadcastq         m1, [dstq+dsq*0]
+    movq                xm0, [dstq+dsq*1]
+    vpblendd             m0, m1, 0x30
+    vpbroadcastd         m3, [maskq+hq*2]
+    movq                xm1, [tmpq+8*1]
+    vinserti128          m1, [tmpq+8*0], 1
+    add                tmpq, 8*2
+    pshufb               m3, m4
+    punpcklbw            m0, m1
+    pmaddubsw            m0, m3
+    pmulhrsw             m0, m5
+    vextracti128        xm1, m0, 1
+    packuswb            xm0, xm1
+    movhps     [dstq+dsq*0], xm0
+    movq       [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w8_loop
+    RET
+ALIGN function_align
+.w16:
+    vbroadcasti128       m4, [blend_shuf]
+    shufpd               m4, m4, 0x0c
+.w16_loop:
+    mova                xm1, [dstq+dsq*0]
+    vinserti128          m1, [dstq+dsq*1], 1
+    vpbroadcastd         m3, [maskq+hq*2]
+    mova                 m2, [tmpq]
+    add                tmpq, 16*2
+    pshufb               m3, m4
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w16_loop
+    RET
+ALIGN function_align
+.w32: ; w32/w64/w128
+    sub                 dsq, r6
+.w32_loop0:
+    vpbroadcastw         m3, [maskq+hq*2]
+    mov                  wd, r6d
+.w32_loop:
+    mova                 m1, [dstq]
+    mova                 m2, [tmpq]
+    add                tmpq, 32
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, 32
+    sub                  wd, 32
+    jg .w32_loop
+    add                dstq, dsq
+    inc                  hq
+    jl .w32_loop0
+    RET
+
+cglobal emu_edge_8bpc, 10, 13, 1, bw, bh, iw, ih, x, y, dst, dstride, src, sstride, \
+                             bottomext, rightext
+    ; we assume that the buffer (stride) is larger than width, so we can
+    ; safely overwrite by a few bytes
+
+    ; ref += iclip(y, 0, ih - 1) * PXSTRIDE(ref_stride)
+    xor                r12d, r12d
+    lea                 r10, [ihq-1]
+    cmp                  yq, ihq
+    cmovs               r10, yq
+    test                 yq, yq
+    cmovs               r10, r12
+    imul                r10, sstrideq
+    add                srcq, r10
+
+    ; ref += iclip(x, 0, iw - 1)
+    lea                 r10, [iwq-1]
+    cmp                  xq, iwq
+    cmovs               r10, xq
+    test                 xq, xq
+    cmovs               r10, r12
+    add                srcq, r10
+
+    ; bottom_ext = iclip(y + bh - ih, 0, bh - 1)
+    lea          bottomextq, [yq+bhq]
+    sub          bottomextq, ihq
+    lea                  r3, [bhq-1]
+    cmovs        bottomextq, r12
+
+    DEFINE_ARGS bw, bh, iw, ih, x, topext, dst, dstride, src, sstride, \
+                bottomext, rightext
+
+    ; top_ext = iclip(-y, 0, bh - 1)
+    neg             topextq
+    cmovs           topextq, r12
+    cmp          bottomextq, bhq
+    cmovns       bottomextq, r3
+    cmp             topextq, bhq
+    cmovg           topextq, r3
+
+    ; right_ext = iclip(x + bw - iw, 0, bw - 1)
+    lea           rightextq, [xq+bwq]
+    sub           rightextq, iwq
+    lea                  r2, [bwq-1]
+    cmovs         rightextq, r12
+
+    DEFINE_ARGS bw, bh, iw, ih, leftext, topext, dst, dstride, src, sstride, \
+                bottomext, rightext
+
+    ; left_ext = iclip(-x, 0, bw - 1)
+    neg            leftextq
+    cmovs          leftextq, r12
+    cmp           rightextq, bwq
+    cmovns        rightextq, r2
+    cmp            leftextq, bwq
+    cmovns         leftextq, r2
+
+    DEFINE_ARGS bw, centerh, centerw, dummy, leftext, topext, \
+                dst, dstride, src, sstride, bottomext, rightext
+
+    ; center_h = bh - top_ext - bottom_ext
+    lea                  r3, [bottomextq+topextq]
+    sub            centerhq, r3
+
+    ; blk += top_ext * PXSTRIDE(dst_stride)
+    mov                  r2, topextq
+    imul                 r2, dstrideq
+    add                dstq, r2
+    mov                 r9m, dstq
+
+    ; center_w = bw - left_ext - right_ext
+    mov            centerwq, bwq
+    lea                  r3, [rightextq+leftextq]
+    sub            centerwq, r3
+
+%macro v_loop 3 ; need_left_ext, need_right_ext, suffix
+.v_loop_%3:
+%if %1
+    ; left extension
+    xor                  r3, r3
+    vpbroadcastb         m0, [srcq]
+.left_loop_%3:
+    mova          [dstq+r3], m0
+    add                  r3, 32
+    cmp                  r3, leftextq
+    jl .left_loop_%3
+
+    ; body
+    lea                 r12, [dstq+leftextq]
+%endif
+    xor                  r3, r3
+.body_loop_%3:
+    movu                 m0, [srcq+r3]
+%if %1
+    movu           [r12+r3], m0
+%else
+    movu          [dstq+r3], m0
+%endif
+    add                  r3, 32
+    cmp                  r3, centerwq
+    jl .body_loop_%3
+
+%if %2
+    ; right extension
+%if %1
+    add                 r12, centerwq
+%else
+    lea                 r12, [dstq+centerwq]
+%endif
+    xor                  r3, r3
+    vpbroadcastb         m0, [srcq+centerwq-1]
+.right_loop_%3:
+    movu           [r12+r3], m0
+    add                  r3, 32
+    cmp                  r3, rightextq
+    jl .right_loop_%3
+
+%endif
+    add                dstq, dstrideq
+    add                srcq, sstrideq
+    dec            centerhq
+    jg .v_loop_%3
+%endmacro
+
+    test           leftextq, leftextq
+    jnz .need_left_ext
+    test          rightextq, rightextq
+    jnz .need_right_ext
+    v_loop                0, 0, 0
+    jmp .body_done
+
+.need_left_ext:
+    test          rightextq, rightextq
+    jnz .need_left_right_ext
+    v_loop                1, 0, 1
+    jmp .body_done
+
+.need_left_right_ext:
+    v_loop                1, 1, 2
+    jmp .body_done
+
+.need_right_ext:
+    v_loop                0, 1, 3
+
+.body_done:
+    ; bottom edge extension
+    test         bottomextq, bottomextq
+    jz .top
+    mov                srcq, dstq
+    sub                srcq, dstrideq
+    xor                  r1, r1
+.bottom_x_loop:
+    mova                 m0, [srcq+r1]
+    lea                  r3, [dstq+r1]
+    mov                  r4, bottomextq
+.bottom_y_loop:
+    mova               [r3], m0
+    add                  r3, dstrideq
+    dec                  r4
+    jg .bottom_y_loop
+    add                  r1, 32
+    cmp                  r1, bwq
+    jl .bottom_x_loop
+
+.top:
+    ; top edge extension
+    test            topextq, topextq
+    jz .end
+    mov                srcq, r9m
+    mov                dstq, dstm
+    xor                  r1, r1
+.top_x_loop:
+    mova                 m0, [srcq+r1]
+    lea                  r3, [dstq+r1]
+    mov                  r4, topextq
+.top_y_loop:
+    mova               [r3], m0
+    add                  r3, dstrideq
+    dec                  r4
+    jg .top_y_loop
+    add                  r1, 32
+    cmp                  r1, bwq
+    jl .top_x_loop
+
+.end:
+    RET
+
+cglobal resize_8bpc, 6, 12, 16, dst, dst_stride, src, src_stride, \
+                                dst_w, h, src_w, dx, mx0
+    sub          dword mx0m, 4<<14
+    sub        dword src_wm, 8
+    vpbroadcastd         m5, dxm
+    vpbroadcastd         m8, mx0m
+    vpbroadcastd         m6, src_wm
+
+    DEFINE_ARGS dst, dst_stride, src, src_stride, dst_w, h, x
+    LEA                  r7, $$
+%define base r7-$$
+
+    vpbroadcastd        xm3, [base+pw_m256]
+    vpbroadcastd         m7, [base+pd_63]
+    vbroadcasti128      m15, [base+pb_8x0_8x8]
+    pmaddwd              m2, m5, [base+rescale_mul] ; dx*[0,1,2,3,4,5,6,7]
+    pslld                m5, 3                      ; dx*8
+    pslld                m6, 14
+    paddd                m8, m2                     ; mx+[0..7]*dx
+    pxor                 m2, m2
+
+    ; m2 = 0, m3 = pmulhrsw constant for x=(x+64)>>7
+    ; m8 = mx+[0..7]*dx, m5 = dx*8, m6 = src_w, m7 = 0x3f, m15=0,8
+
+.loop_y:
+    xor                  xd, xd
+    mova                 m4, m8                     ; per-line working version of mx
+
+.loop_x:
+    pmaxsd               m0, m4, m2
+    psrad                m9, m4, 8                  ; filter offset (unmasked)
+    pminsd               m0, m6                     ; iclip(mx, 0, src_w-8)
+    psubd                m1, m4, m0                 ; pshufb offset
+    psrad                m0, 14                     ; clipped src_x offset
+    psrad                m1, 14                     ; pshufb edge_emu offset
+    pand                 m9, m7                     ; filter offset (masked)
+
+    ; load source pixels - this ugly code is vpgatherdq emulation since
+    ; directly using vpgatherdq on Haswell is quite a bit slower :(
+    movd                r8d, xm0
+    pextrd              r9d, xm0, 1
+    pextrd             r10d, xm0, 2
+    pextrd             r11d, xm0, 3
+    vextracti128        xm0, m0, 1
+    movq               xm12, [srcq+r8]
+    movq               xm13, [srcq+r10]
+    movhps             xm12, [srcq+r9]
+    movhps             xm13, [srcq+r11]
+    movd                r8d, xm0
+    pextrd              r9d, xm0, 1
+    pextrd             r10d, xm0, 2
+    pextrd             r11d, xm0, 3
+    vinserti128         m12, [srcq+r8], 1
+    vinserti128         m13, [srcq+r10], 1
+    vpbroadcastq        m10, [srcq+r9]
+    vpbroadcastq        m11, [srcq+r11]
+    vpblendd            m12, m10, 11000000b
+    vpblendd            m13, m11, 11000000b
+
+    ; if no emulation is required, we don't need to shuffle or emulate edges
+    ; this also saves 2 quasi-vpgatherdqs
+    vptest               m1, m1
+    jz .filter
+
+    movq                 r9, xm1
+    pextrq              r11, xm1, 1
+    movsxd               r8, r9d
+    sar                  r9, 32
+    movsxd              r10, r11d
+    sar                 r11, 32
+    vextracti128        xm1, m1, 1
+    movq               xm14, [base+resize_shuf+4+r8]
+    movq                xm0, [base+resize_shuf+4+r10]
+    movhps             xm14, [base+resize_shuf+4+r9]
+    movhps              xm0, [base+resize_shuf+4+r11]
+    movq                 r9, xm1
+    pextrq              r11, xm1, 1
+    movsxd               r8, r9d
+    sar                  r9, 32
+    movsxd              r10, r11d
+    sar                 r11, 32
+    vinserti128         m14, [base+resize_shuf+4+r8], 1
+    vinserti128          m0, [base+resize_shuf+4+r10], 1
+    vpbroadcastq        m10, [base+resize_shuf+4+r9]
+    vpbroadcastq        m11, [base+resize_shuf+4+r11]
+    vpblendd            m14, m10, 11000000b
+    vpblendd             m0, m11, 11000000b
+
+    paddb               m14, m15
+    paddb                m0, m15
+    pshufb              m12, m14
+    pshufb              m13, m0
+
+.filter:
+    movd                r8d, xm9
+    pextrd              r9d, xm9, 1
+    pextrd             r10d, xm9, 2
+    pextrd             r11d, xm9, 3
+    vextracti128        xm9, m9, 1
+    movq               xm10, [base+resize_filter+r8*8]
+    movq               xm11, [base+resize_filter+r10*8]
+    movhps             xm10, [base+resize_filter+r9*8]
+    movhps             xm11, [base+resize_filter+r11*8]
+    movd                r8d, xm9
+    pextrd              r9d, xm9, 1
+    pextrd             r10d, xm9, 2
+    pextrd             r11d, xm9, 3
+    vinserti128         m10, [base+resize_filter+r8*8], 1
+    vinserti128         m11, [base+resize_filter+r10*8], 1
+    vpbroadcastq        m14, [base+resize_filter+r9*8]
+    vpbroadcastq         m1, [base+resize_filter+r11*8]
+    vpblendd            m10, m14, 11000000b
+    vpblendd            m11, m1, 11000000b
+
+    pmaddubsw           m12, m10
+    pmaddubsw           m13, m11
+    phaddw              m12, m13
+    vextracti128       xm13, m12, 1
+    phaddsw            xm12, xm13
+    pmulhrsw           xm12, xm3                    ; x=(x+64)>>7
+    packuswb           xm12, xm12
+    movq          [dstq+xq], xm12
+
+    paddd                m4, m5
+    add                  xd, 8
+    cmp                  xd, dst_wd
+    jl .loop_x
+
+    add                dstq, dst_strideq
+    add                srcq, src_strideq
+    dec                  hd
+    jg .loop_y
+    RET
+
+cglobal w_mask_420_8bpc, 4, 8, 14, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_420_avx2_table
+    lea                  r7, [w_mask_420_avx2_table]
+    tzcnt                wd, wm
+    mov                 r6d, r7m ; sign
+    movifnidn            hd, hm
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd         m6, [base+pw_6903] ; ((64 - 38) << 8) + 255 - 8
+    vpbroadcastd         m7, [base+pw_2048]
+    pmovzxbd             m9, [base+deint_shuf4]
+    vpbroadcastd         m8, [base+wm_420_sign+r6*4] ; 258 - sign
+    add                  wq, r7
+    W_MASK                0, 4, 0, 1
+    mov               maskq, maskmp
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    cmp                  hd, 8
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+    jg .w4_h16
+.w4_end:
+    vextracti128        xm0, m4, 1
+    vpblendd            xm1, xm4, xm0, 0x05
+    vpblendd            xm4, xm0, 0x0a
+    pshufd              xm1, xm1, q2301
+    psubw               xm4, xm8, xm4
+    psubw               xm4, xm1
+    psrlw               xm4, 2
+    packuswb            xm4, xm4
+    movq            [maskq], xm4
+    RET
+.w4_h16:
+    W_MASK                0, 5, 2, 3
+    lea                dstq, [dstq+strideq*4]
+    phaddd               m4, m5
+    vextracti128        xm1, m0, 1
+    psubw                m4, m8, m4
+    psrlw                m4, 2
+    vpermd               m4, m9, m4
+    vextracti128        xm5, m4, 1
+    packuswb            xm4, xm5
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q], xm1, 1
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+    mova            [maskq], xm4
+    RET
+.w8_loop:
+    add               tmp1q, 2*32
+    add               tmp2q, 2*32
+    W_MASK                0, 4, 0, 1
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 8
+.w8:
+    vextracti128        xm2, m4, 1
+    vextracti128        xm1, m0, 1
+    psubw               xm4, xm8, xm4
+    psubw               xm4, xm2
+    psrlw               xm4, 2
+    packuswb            xm4, xm4
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    movq            [maskq], xm4
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.w16_loop:
+    add               tmp1q, 4*32
+    add               tmp2q, 4*32
+    W_MASK                0, 4, 0, 1
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 16
+.w16:
+    vpermq               m0, m0, q3120
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    W_MASK                0, 5, 2, 3
+    punpckhqdq           m1, m4, m5
+    punpcklqdq           m4, m5
+    psubw                m1, m8, m1
+    psubw                m1, m4
+    psrlw                m1, 2
+    vpermq               m0, m0, q3120
+    packuswb             m1, m1
+    vpermd               m1, m9, m1
+    mova         [dstq+strideq*2], xm0
+    vextracti128 [dstq+stride3q ], m0, 1
+    mova            [maskq], xm1
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    add               tmp1q, 4*32
+    add               tmp2q, 4*32
+    W_MASK                0, 4, 0, 1
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 16
+.w32:
+    vpermq               m0, m0, q3120
+    mova   [dstq+strideq*0], m0
+    W_MASK                0, 5, 2, 3
+    psubw                m4, m8, m4
+    psubw                m4, m5
+    psrlw                m4, 2
+    vpermq               m0, m0, q3120
+    packuswb             m4, m4
+    vpermd               m4, m9, m4
+    mova   [dstq+strideq*1], m0
+    mova            [maskq], xm4
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop_even:
+    psubw               m10, m8, m4
+    psubw               m11, m8, m5
+    dec                  hd
+.w64_loop:
+    add               tmp1q, 4*32
+    add               tmp2q, 4*32
+    W_MASK                0, 4, 0, 1
+    add                dstq, strideq
+.w64:
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*0], m0
+    W_MASK                0, 5, 2, 3
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*1], m0
+    test                 hd, 1
+    jz .w64_loop_even
+    psubw                m4, m10, m4
+    psubw                m5, m11, m5
+    psrlw                m4, 2
+    psrlw                m5, 2
+    packuswb             m4, m5
+    vpermd               m4, m9, m4
+    mova            [maskq], m4
+    add               maskq, 32
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop_even:
+    psubw               m12, m8, m4
+    psubw               m13, m8, m5
+    dec                  hd
+.w128_loop:
+    W_MASK                0, 4, 0, 1
+    add                dstq, strideq
+.w128:
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*0], m0
+    W_MASK                0, 5, 2, 3
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*1], m0
+    add               tmp1q, 8*32
+    add               tmp2q, 8*32
+    test                 hd, 1
+    jz .w128_even
+    psubw                m4, m10, m4
+    psubw                m5, m11, m5
+    psrlw                m4, 2
+    psrlw                m5, 2
+    packuswb             m4, m5
+    vpermd               m4, m9, m4
+    mova       [maskq+32*0], m4
+    jmp .w128_odd
+.w128_even:
+    psubw               m10, m8, m4
+    psubw               m11, m8, m5
+.w128_odd:
+    W_MASK                0, 4, -4, -3
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*2], m0
+    W_MASK                0, 5, -2, -1
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*3], m0
+    test                 hd, 1
+    jz .w128_loop_even
+    psubw                m4, m12, m4
+    psubw                m5, m13, m5
+    psrlw                m4, 2
+    psrlw                m5, 2
+    packuswb             m4, m5
+    vpermd               m4, m9, m4
+    mova       [maskq+32*1], m4
+    add               maskq, 64
+    dec                  hd
+    jg .w128_loop
+    RET
+
+cglobal w_mask_422_8bpc, 4, 8, 11, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_422_avx2_table
+    lea                  r7, [w_mask_422_avx2_table]
+    tzcnt                wd, wm
+    mov                 r6d, r7m ; sign
+    movifnidn            hd, hm
+    pxor                 m9, m9
+    movsxd               wq, dword [r7+wq*4]
+    vpbroadcastd         m6, [base+pw_6903] ; ((64 - 38) << 8) + 255 - 8
+    vpbroadcastd         m7, [base+pw_2048]
+    pmovzxbd            m10, [base+deint_shuf4]
+    vpbroadcastd         m8, [base+wm_422_sign+r6*4] ; 128 - sign
+    add                  wq, r7
+    mov               maskq, maskmp
+    W_MASK                0, 4, 0, 1
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    cmp                  hd, 8
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+    jg .w4_h16
+.w4_end:
+    vextracti128        xm5, m4, 1
+    packuswb            xm4, xm5
+    psubb               xm5, xm8, xm4
+    pavgb               xm5, xm9
+    pshufd              xm5, xm5, q3120
+    mova            [maskq], xm5
+    RET
+.w4_h16:
+    W_MASK                0, 5, 2, 3
+    lea                dstq, [dstq+strideq*4]
+    packuswb             m4, m5
+    psubb                m5, m8, m4
+    pavgb                m5, m9
+    vpermd               m5, m10, m5
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+    mova            [maskq], m5
+    RET
+.w8_loop:
+    add               tmp1q, 32*2
+    add               tmp2q, 32*2
+    W_MASK                0, 4, 0, 1
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 16
+.w8:
+    vextracti128        xm5, m4, 1
+    vextracti128        xm1, m0, 1
+    packuswb            xm4, xm5
+    psubb               xm5, xm8, xm4
+    pavgb               xm5, xm9
+    pshufd              xm5, xm5, q3120
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    mova            [maskq], xm5
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.w16_loop:
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    W_MASK                0, 4, 0, 1
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 32
+.w16:
+    vpermq               m0, m0, q3120
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    W_MASK                0, 5, 2, 3
+    packuswb             m4, m5
+    psubb                m5, m8, m4
+    pavgb                m5, m9
+    vpermq               m0, m0, q3120
+    vpermd               m5, m10, m5
+    mova         [dstq+strideq*2], xm0
+    vextracti128 [dstq+stride3q ], m0, 1
+    mova            [maskq], m5
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32_loop:
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    W_MASK                0, 4, 0, 1
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 32
+.w32:
+    vpermq               m0, m0, q3120
+    mova   [dstq+strideq*0], m0
+    W_MASK                0, 5, 2, 3
+    packuswb             m4, m5
+    psubb                m5, m8, m4
+    pavgb                m5, m9
+    vpermq               m0, m0, q3120
+    vpermd               m5, m10, m5
+    mova   [dstq+strideq*1], m0
+    mova            [maskq], m5
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    W_MASK                0, 4, 0, 1
+    add                dstq, strideq
+    add               maskq, 32
+.w64:
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*0], m0
+    W_MASK                0, 5, 2, 3
+    packuswb             m4, m5
+    psubb                m5, m8, m4
+    pavgb                m5, m9
+    vpermq               m0, m0, q3120
+    vpermd               m5, m10, m5
+    mova        [dstq+32*1], m0
+    mova            [maskq], m5
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    add               tmp1q, 32*8
+    add               tmp2q, 32*8
+    W_MASK                0, 4, 0, 1
+    add                dstq, strideq
+    add               maskq, 32*2
+.w128:
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*0], m0
+    W_MASK                0, 5, 2, 3
+    packuswb             m4, m5
+    psubb                m5, m8, m4
+    pavgb                m5, m9
+    vpermq               m0, m0, q3120
+    vpermd               m5, m10, m5
+    mova        [dstq+32*1], m0
+    mova       [maskq+32*0], m5
+    W_MASK                0, 4, 4, 5
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*2], m0
+    W_MASK                0, 5, 6, 7
+    packuswb             m4, m5
+    psubb                m5, m8, m4
+    pavgb                m5, m9
+    vpermq               m0, m0, q3120
+    vpermd               m5, m10, m5
+    mova        [dstq+32*3], m0
+    mova       [maskq+32*1], m5
+    dec                  hd
+    jg .w128_loop
+    RET
+
+cglobal w_mask_444_8bpc, 4, 8, 8, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_444_avx2_table
+    lea                  r7, [w_mask_444_avx2_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    mov               maskq, maskmp
+    movsxd               wq, dword [r7+wq*4]
+    vpbroadcastd         m6, [base+pw_6903] ; ((64 - 38) << 8) + 255 - 8
+    vpbroadcastd         m5, [base+pb_64]
+    vpbroadcastd         m7, [base+pw_2048]
+    add                  wq, r7
+    W_MASK                0, 4, 0, 1, 1
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    mova       [maskq+32*0], m4
+    cmp                  hd, 8
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+    je .w4_end
+    W_MASK                0, 4, 2, 3, 1
+    lea                dstq, [dstq+strideq*4]
+    vextracti128        xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+    mova       [maskq+32*1], m4
+.w4_end:
+    RET
+.w8_loop:
+    add               tmp1q, 32*2
+    add               tmp2q, 32*2
+    W_MASK                0, 4, 0, 1, 1
+    lea                dstq, [dstq+strideq*4]
+    add               maskq, 32
+.w8:
+    vextracti128        xm1, m0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    mova            [maskq], m4
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.w16_loop:
+    add               tmp1q, 32*2
+    add               tmp2q, 32*2
+    W_MASK                0, 4, 0, 1, 1
+    lea                dstq, [dstq+strideq*2]
+    add               maskq, 32
+.w16:
+    vpermq               m0, m0, q3120
+    mova         [dstq+strideq*0], xm0
+    vextracti128 [dstq+strideq*1], m0, 1
+    mova            [maskq], m4
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32_loop:
+    add               tmp1q, 32*2
+    add               tmp2q, 32*2
+    W_MASK                0, 4, 0, 1, 1
+    add                dstq, strideq
+    add               maskq, 32
+.w32:
+    vpermq               m0, m0, q3120
+    mova             [dstq], m0
+    mova            [maskq], m4
+    dec                  hd
+    jg .w32_loop
+    RET
+.w64_loop:
+    add               tmp1q, 32*4
+    add               tmp2q, 32*4
+    W_MASK                0, 4, 0, 1, 1
+    add                dstq, strideq
+    add               maskq, 32*2
+.w64:
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*0], m0
+    mova       [maskq+32*0], m4
+    W_MASK                0, 4, 2, 3, 1
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*1], m0
+    mova       [maskq+32*1], m4
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    add               tmp1q, 32*8
+    add               tmp2q, 32*8
+    W_MASK                0, 4, 0, 1, 1
+    add                dstq, strideq
+    add               maskq, 32*4
+.w128:
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*0], m0
+    mova       [maskq+32*0], m4
+    W_MASK                0, 4, 2, 3, 1
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*1], m0
+    mova       [maskq+32*1], m4
+    W_MASK                0, 4, 4, 5, 1
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*2], m0
+    mova       [maskq+32*2], m4
+    W_MASK                0, 4, 6, 7, 1
+    vpermq               m0, m0, q3120
+    mova        [dstq+32*3], m0
+    mova       [maskq+32*3], m4
+    dec                  hd
+    jg .w128_loop
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/mc_avx512.asm b/media/libdav1d/src/src/x86/mc_avx512.asm
new file mode 100644
index 0000000000..50e670ec25
--- /dev/null
+++ b/media/libdav1d/src/src/x86/mc_avx512.asm
@@ -0,0 +1,5524 @@
+; Copyright © 2020, VideoLAN and dav1d authors
+; Copyright © 2020, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+%if ARCH_X86_64
+
+SECTION_RODATA 64
+
+obmc_masks:
+pw_512:         times 2 dw 512
+                ; 2
+                db 45, 19, 64,  0
+                ; 4
+                db 39, 25, 50, 14, 59,  5, 64,  0
+                ; 8
+                db 36, 28, 42, 22, 48, 16, 53, 11, 57,  7, 61,  3, 64,  0, 64,  0
+                ; 16
+                db 34, 30, 37, 27, 40, 24, 43, 21, 46, 18, 49, 15, 52, 12, 54, 10
+                db 56,  8, 58,  6, 60,  4, 61,  3, 64,  0, 64,  0, 64,  0, 64,  0
+                ; 32
+                db 33, 31, 35, 29, 36, 28, 38, 26, 40, 24, 41, 23, 43, 21, 44, 20
+                db 45, 19, 47, 17, 48, 16, 50, 14, 51, 13, 52, 12, 53, 11, 55,  9
+                db 56,  8, 57,  7, 58,  6, 59,  5, 60,  4, 60,  4, 61,  3, 62,  2
+                db 64,  0, 64,  0, 64,  0, 64,  0, 64,  0, 64,  0, 64,  0, 64,  0
+
+warp_8x8_permA: db  4,  5,  6,  7, 16, 17, 18, 19,  5,  6,  7,  8, 17, 18, 19, 20
+                db  6,  7,  8,  9, 18, 19, 20, 21,  7,  8,  9, 10, 19, 20, 21, 22
+                db  8,  9, 10, 11, 20, 21, 22, 23,  9, 10, 11, 12, 21, 22, 23, 24
+                db 10, 11, 12, 13, 22, 23, 24, 25, 11, 12, 13, 14, 23, 24, 25, 26
+warp_8x8_permB: db  0,  1,  2,  3, 20, 21, 22, 23,  1,  2,  3,  4, 21, 22, 23, 24
+                db  2,  3,  4,  5, 22, 23, 24, 25,  3,  4,  5,  6, 23, 24, 25, 26
+                db  4,  5,  6,  7, 24, 25, 26, 27,  5,  6,  7,  8, 25, 26, 27, 28
+                db  6,  7,  8,  9, 26, 27, 28, 29,  7,  8,  9, 10, 27, 28, 29, 30
+warp_8x8_permC: db -1,  0, -1,  1, -1,  8, -1,  9, -1,  4, -1,  5, -1, 12, -1, 13
+warp_8x8_permD: db -1,  2, -1,  3, -1, 10, -1, 11, -1,  6, -1,  7, -1, 14, -1, 15
+pd_0to7:        dd  0,  1,  2,  3,  4,  5,  6,  7
+warp_8x8_hpack: db  3, 11,  3, 11, 35, 43, 35, 43
+pd_16384:       dd 16384
+pd_262144:      dd 262144
+warp_8x8_end:   db  0,  4, 16, 20, 32, 36, 48, 52,  2,  6, 18, 22, 34, 38, 50, 54
+warp_8x8t_end:  db  2,  3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59
+                db  6,  7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63
+bidir_sctr_w4:  dd  0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+wm_420_perm4:   db  1,  3,  9, 11,  5,  7, 13, 15, 17, 19, 25, 27, 21, 23, 29, 31
+                db 33, 35, 41, 43, 37, 39, 45, 47, 49, 51, 57, 59, 53, 55, 61, 63
+                db  0,  2,  8, 10,  4,  6, 12, 14, 16, 18, 24, 26, 20, 22, 28, 30
+                db 32, 34, 40, 42, 36, 38, 44, 46, 48, 50, 56, 58, 52, 54, 60, 62
+wm_420_perm8:   db  1,  3, 17, 19,  5,  7, 21, 23,  9, 11, 25, 27, 13, 15, 29, 31
+                db 33, 35, 49, 51, 37, 39, 53, 55, 41, 43, 57, 59, 45, 47, 61, 63
+                db  0,  2, 16, 18,  4,  6, 20, 22,  8, 10, 24, 26, 12, 14, 28, 30
+                db 32, 34, 48, 50, 36, 38, 52, 54, 40, 42, 56, 58, 44, 46, 60, 62
+wm_420_perm16:  db  1,  3, 33, 35,  5,  7, 37, 39,  9, 11, 41, 43, 13, 15, 45, 47
+                db 17, 19, 49, 51, 21, 23, 53, 55, 25, 27, 57, 59, 29, 31, 61, 63
+                db  0,  2, 32, 34,  4,  6, 36, 38,  8, 10, 40, 42, 12, 14, 44, 46
+                db 16, 18, 48, 50, 20, 22, 52, 54, 24, 26, 56, 58, 28, 30, 60, 62
+wm_420_mask:    db  3,  7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63
+                db 67, 71, 75, 79, 83, 87, 91, 95, 99,103,107,111,115,119,123,127
+                db  1,  5,  9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61
+                db 65, 69, 73, 77, 81, 85, 89, 93, 97,101,105,109,113,117,121,125
+wm_422_mask:    db  2,  6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62
+                db  1,  5,  9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61
+                db 66, 70, 74, 78, 82, 86, 90, 94, 98,102,106,110,114,118,122,126
+                db 65, 69, 73, 77, 81, 85, 89, 93, 97,101,105,109,113,117,121,125
+wm_444_mask:    db  1,  3,  5,  7,  9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31
+                db 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63
+                db  0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+                db 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62
+bilin_h_perm16: db  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8
+                db  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16
+                db 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40
+                db 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48
+bilin_h_perm32: db  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8
+                db  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16
+                db 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24
+                db 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32
+bilin_v_perm8:  db  0, 16,  1, 17,  2, 18,  3, 19,  4, 20,  5, 21,  6, 22,  7, 23
+                db 16, 80, 17, 81, 18, 82, 19, 83, 20, 84, 21, 85, 22, 86, 23, 87
+                db 80, 32, 81, 33, 82, 34, 83, 35, 84, 36, 85, 37, 86, 38, 87, 39
+                db 32, 64, 33, 65, 34, 66, 35, 67, 36, 68, 37, 69, 38, 70, 39, 71
+bilin_v_perm16: db  0, 16,  1, 17,  2, 18,  3, 19,  4, 20,  5, 21,  6, 22,  7, 23
+                db  8, 24,  9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31
+                db 16, 64, 17, 65, 18, 66, 19, 67, 20, 68, 21, 69, 22, 70, 23, 71
+                db 24, 72, 25, 73, 26, 74, 27, 75, 28, 76, 29, 77, 30, 78, 31, 79
+bilin_v_perm32: db  0, 64,  1, 65,  2, 66,  3, 67,  4, 68,  5, 69,  6, 70,  7, 71
+                db  8, 72,  9, 73, 10, 74, 11, 75, 12, 76, 13, 77, 14, 78, 15, 79
+                db 16, 80, 17, 81, 18, 82, 19, 83, 20, 84, 21, 85, 22, 86, 23, 87
+                db 24, 88, 25, 89, 26, 90, 27, 91, 28, 92, 29, 93, 30, 94, 31, 95
+bilin_v_perm64: dd  0,  0,  4,  8,  1,  1,  5,  9,  2,  2,  6, 10,  3,  3,  7, 11
+spel_h_perm16:  db  0,  1,  2,  3,  1,  2,  3,  4,  2,  3,  4,  5,  3,  4,  5,  6
+                db  8,  9, 10, 11,  9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14
+                db 32, 33, 34, 35, 33, 34, 35, 36, 34, 35, 36, 37, 35, 36, 37, 38
+                db 40, 41, 42, 43, 41, 42, 43, 44, 42, 43, 44, 45, 43, 44, 45, 46
+spel_h_perm32:  db  0,  1,  2,  3,  1,  2,  3,  4,  2,  3,  4,  5,  3,  4,  5,  6
+                db  8,  9, 10, 11,  9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14
+                db 16, 17, 18, 19, 17, 18, 19, 20, 18, 19, 20, 21, 19, 20, 21, 22
+                db 24, 25, 26, 27, 25, 26, 27, 28, 26, 27, 28, 29, 27, 28, 29, 30
+spel_v_perm8:   db  0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+                db  8, 16,  9, 17, 10, 18, 11, 19, 12, 20, 13, 21, 14, 22, 15, 23
+                db 16, 24, 17, 25, 18, 26, 19, 27, 20, 28, 21, 29, 22, 30, 23, 31
+                db 24, 32, 25, 33, 26, 34, 27, 35, 28, 36, 29, 37, 30, 38, 31, 39
+spel_v_perm16a: db 32,  0, 33,  1, 34,  2, 35,  3, 36,  4, 37,  5, 38,  6, 39,  7
+                db  0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+                db 40, 16, 41, 17, 42, 18, 43, 19, 44, 20, 45, 21, 46, 22, 47, 23
+                db 16, 24, 17, 25, 18, 26, 19, 27, 20, 28, 21, 29, 22, 30, 23, 31
+spel_v_perm16b: db 32,  0, 33,  1, 34,  2, 35,  3, 36,  4, 37,  5, 38,  6, 39,  7
+                db 40, 16, 41, 17, 42, 18, 43, 19, 44, 20, 45, 21, 46, 22, 47, 23
+                db  0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+                db 16, 24, 17, 25, 18, 26, 19, 27, 20, 28, 21, 29, 22, 30, 23, 31
+spel_v_perm32:  db  0, 32,  1, 33,  2, 34,  3, 35,  4, 36,  5, 37,  6, 38,  7, 39
+                db  8, 40,  9, 41, 10, 42, 11, 43, 12, 44, 13, 45, 14, 46, 15, 47
+                db 16, 48, 17, 49, 18, 50, 19, 51, 20, 52, 21, 53, 22, 54, 23, 55
+                db 24, 56, 25, 57, 26, 58, 27, 59, 28, 60, 29, 61, 30, 62, 31, 63
+spel_hv_perm4a: db  8,  9, 16, 17, 10, 11, 18, 19, 12, 13, 20, 21, 14, 15, 22, 23
+                db 16, 17, 24, 25, 18, 19, 26, 27, 20, 21, 28, 29, 22, 23, 30, 31
+spel_hv_perm4b: db 24, 25, 32, 33, 26, 27, 34, 35, 28, 29, 36, 37, 30, 31, 38, 39
+                db 32, 33, 40, 41, 34, 35, 42, 43, 36, 37, 44, 45, 38, 39, 46, 47
+spel_hv_perm4c: db 40, 41, 48, 49, 42, 43, 50, 51, 44, 45, 52, 53, 46, 47, 54, 55
+                db 48, 49, 56, 57, 50, 51, 58, 59, 52, 53, 60, 61, 54, 55, 62, 63
+spel_hv_perm4d: db 18, 19,  0,  1, 22, 23,  4,  5, 26, 27,  8,  9, 30, 31, 12, 13
+                db  0,  1, 16, 17,  4,  5, 20, 21,  8,  9, 24, 25, 12, 13, 28, 29
+spel_hv_perm8a: db  0,  1, 16, 17,  2,  3, 18, 19,  4,  5, 20, 21,  6,  7, 22, 23
+                db  8,  9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31
+                db 16, 17, 32, 33, 18, 19, 34, 35, 20, 21, 36, 37, 22, 23, 38, 39
+                db 24, 25, 40, 41, 26, 27, 42, 43, 28, 29, 44, 45, 30, 31, 46, 47
+spel_hv_perm8b: db 34, 35,  0,  1, 38, 39,  4,  5, 42, 43,  8,  9, 46, 47, 12, 13
+                db 50, 51, 16, 17, 54, 55, 20, 21, 58, 59, 24, 25, 62, 63, 28, 29
+                db  0,  1, 32, 33,  4,  5, 36, 37,  8,  9, 40, 41, 12, 13, 44, 45
+                db 16, 17, 48, 49, 20, 21, 52, 53, 24, 25, 56, 57, 28, 29, 60, 61
+spel_hv_perm16a:db  0,  1,  2,  3, 32, 33, 34, 35,  1,  2,  3,  4, 33, 34, 35, 36
+                db  2,  3,  4,  5, 34, 35, 36, 37,  3,  4,  5,  6, 35, 36, 37, 38
+                db  8,  9, 10, 11, 40, 41, 42, 43,  9, 10, 11, 12, 41, 42, 43, 44
+                db 10, 11, 12, 13, 42, 43, 44, 45, 11, 12, 13, 14, 43, 44, 45, 46
+spel_hv_perm16b:db  0,  1,  2,  3,  1,  2,  3,  4,  4,  5,  6,  7,  5,  6,  7,  8
+                db  2,  3,  4,  5,  3,  4,  5,  6,  6,  7,  8,  9,  7,  8,  9, 10
+                db  8,  9, 10, 11,  9, 10, 11, 12, 12, 13, 14, 15, 13, 14, 15, 16
+                db 10, 11, 12, 13, 11, 12, 13, 14, 14, 15, 16, 17, 15, 16, 17, 18
+spel_hv_end16:  db  1,  3, 17, 19,  5,  7, 21, 23, 33, 35, 49, 51, 37, 39, 53, 55
+                db  9, 11, 25, 27, 13, 15, 29, 31, 41, 43, 57, 59, 45, 47, 61, 63
+spel_hv_end:    db  1,  3,  5,  7, 17, 19, 21, 23, 33, 35, 37, 39, 49, 51, 53, 55
+deint_shuf4:    db  0,  4,  1,  5,  2,  6,  3,  7,  4,  8,  5,  9,  6, 10,  7, 11
+subpel_h_shuf4: db  0,  1,  2,  3,  1,  2,  3,  4,  8,  9, 10, 11,  9, 10, 11, 12
+                db  2,  3,  4,  5,  3,  4,  5,  6, 10, 11, 12, 13, 11, 12, 13, 14
+subpel_h_shufA: db  0,  1,  2,  3,  1,  2,  3,  4,  2,  3,  4,  5,  3,  4,  5,  6
+subpel_h_shufB: db  4,  5,  6,  7,  5,  6,  7,  8,  6,  7,  8,  9,  7,  8,  9, 10
+subpel_h_shufC: db  8,  9, 10, 11,  9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14
+bilin_h_shuf4:  db  0,  1,  1,  2,  2,  3,  3,  4,  8,  9,  9, 10, 10, 11, 11, 12
+bilin_v_shuf4:  db  0,  4,  1,  5,  2,  6,  3,  7,  4,  8,  5,  9,  6, 10,  7, 11
+blend_shuf:     db  0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  2,  3,  2,  3,  2,  3
+rescale_mul:    dd  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+resize_permA:   dd  0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+resize_permB:   dd  1,  3,  5,  7,  9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31
+resize_permC:   dd  0,  4,  8, 12
+resize_shuf:    db  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  7,  7,  7,  7
+pb_02461357:    db  0,  2,  4,  6,  1,  3,  5,  7
+
+wm_420_perm64:  dq 0xfedcba9876543210
+wm_sign:        dd 0x40804080, 0xc0c0c0c0, 0x40404040
+
+pb_8x0_8x8: times 8 db 0
+            times 8 db 8
+pb_4:       times 4 db 4
+pb_32:      times 4 db 32
+pb_127:     times 4 db 127
+pw_m128     times 2 dw -128
+pw_m256:    times 2 dw -256
+pw_1024:    times 2 dw 1024
+pw_2048:    times 2 dw 2048
+pw_6903:    times 2 dw 6903
+pw_8192:    times 2 dw 8192
+pd_32:              dd 32
+pd_34:              dd 34
+pd_63:              dd 63
+pd_512:             dd 512
+
+%define pb_m64 (wm_sign+4)
+%define pb_64  (wm_sign+8)
+%define pd_2   (pd_0to7+8)
+
+cextern mc_subpel_filters
+%define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8)
+cextern mc_warp_filter
+cextern resize_filter
+
+%macro BASE_JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base %1_%2
+    %%table:
+    %rep %0 - 2
+        dw %%base %+ _w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro HV_JMP_TABLE 5-*
+    %xdefine %%prefix mangle(private_prefix %+ _%1_%2_8bpc_%3)
+    %xdefine %%base %1_%3
+    %assign %%types %4
+    %if %%types & 1
+        %xdefine %1_%2_h_%3_table  (%%h  - %5)
+        %%h:
+        %rep %0 - 4
+            dw %%prefix %+ .h_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 2
+        %xdefine %1_%2_v_%3_table  (%%v  - %5)
+        %%v:
+        %rep %0 - 4
+            dw %%prefix %+ .v_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 4
+        %xdefine %1_%2_hv_%3_table (%%hv - %5)
+        %%hv:
+        %rep %0 - 4
+            dw %%prefix %+ .hv_w%5 - %%base
+            %rotate 1
+        %endrep
+    %endif
+%endmacro
+
+%macro BIDIR_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - 2*%3)
+    %xdefine %%base %1_%2_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1_8bpc_%2)
+    %%table:
+    %rep %0 - 2
+        dd %%prefix %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%xdefine put_avx512icl mangle(private_prefix %+ _put_bilin_8bpc_avx512icl.put)
+%xdefine prep_avx512icl mangle(private_prefix %+ _prep_bilin_8bpc_avx512icl.prep)
+
+%define table_offset(type, fn) type %+ fn %+ SUFFIX %+ _table - type %+ SUFFIX
+
+BASE_JMP_TABLE put,  avx512icl,         2, 4, 8, 16, 32, 64, 128
+BASE_JMP_TABLE prep, avx512icl,            4, 8, 16, 32, 64, 128
+HV_JMP_TABLE put,  bilin, avx512icl, 7, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE prep, bilin, avx512icl, 7,    4, 8, 16, 32, 64, 128
+HV_JMP_TABLE put,  6tap,  avx512icl, 2, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE put,  8tap,  avx512icl, 3, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE prep, 6tap,  avx512icl, 2,    4, 8, 16, 32, 64, 128
+HV_JMP_TABLE prep, 8tap,  avx512icl, 3,    4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE avg, avx512icl,            4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_avg, avx512icl,          4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE mask, avx512icl,           4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_420, avx512icl,     4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_422, avx512icl,     4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_444, avx512icl,     4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE blend, avx512icl,          4, 8, 16, 32
+BIDIR_JMP_TABLE blend_v, avx512icl,     2, 4, 8, 16, 32
+BIDIR_JMP_TABLE blend_h, avx512icl,     2, 4, 8, 16, 32, 64, 128
+
+SECTION .text
+
+%macro WRAP_YMM 1+
+INIT_YMM cpuname
+    %1
+INIT_ZMM cpuname
+%endmacro
+
+INIT_ZMM avx512icl
+cglobal put_bilin_8bpc, 4, 8, 0, dst, ds, src, ss, w, h, mxy
+    movifnidn          mxyd, r6m ; mx
+    lea                  r7, [put_avx512icl]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r7m ; my
+    test               mxyd, mxyd
+    jnz .v
+.put:
+    movzx                wd, word [r7+wq*2+table_offset(put,)]
+    add                  wq, r7
+    jmp                  wq
+.put_w2:
+    movzx               r6d, word [srcq+ssq*0]
+    movzx               r7d, word [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6w
+    mov        [dstq+dsq*1], r7w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w2
+    RET
+.put_w4:
+    mov                 r6d, [srcq+ssq*0]
+    mov                 r7d, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6d
+    mov        [dstq+dsq*1], r7d
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w4
+    RET
+.put_w8:
+    mov                  r6, [srcq+ssq*0]
+    mov                  r7, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r6
+    mov        [dstq+dsq*1], r7
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w8
+    RET
+.put_w16:
+    movu               xmm0, [srcq+ssq*0]
+    movu               xmm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], xmm0
+    mova       [dstq+dsq*1], xmm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w16
+    RET
+.put_w32:
+    movu                ym0, [srcq+ssq*0]
+    movu                ym1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], ym0
+    mova       [dstq+dsq*1], ym1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w32
+    RET
+.put_w64:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w64
+    RET
+.put_w128:
+    movu                 m0, [srcq+ssq*0+64*0]
+    movu                 m1, [srcq+ssq*0+64*1]
+    movu                 m2, [srcq+ssq*1+64*0]
+    movu                 m3, [srcq+ssq*1+64*1]
+    lea                srcq, [srcq+ssq*2]
+    mova  [dstq+dsq*0+64*0], m0
+    mova  [dstq+dsq*0+64*1], m1
+    mova  [dstq+dsq*1+64*0], m2
+    mova  [dstq+dsq*1+64*1], m3
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w128
+    RET
+.h:
+    ; (16 * src[x] + (mx * (src[x + 1] - src[x])) + 8) >> 4
+    ; = ((16 - mx) * src[x] + mx * src[x + 1] + 8) >> 4
+    imul               mxyd, 255
+    vbroadcasti128       m4, [bilin_h_perm16]
+    add                mxyd, 16
+    vpbroadcastw         m5, mxyd
+    mov                mxyd, r7m ; my
+    test               mxyd, mxyd
+    jnz .hv
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_h)]
+    vpbroadcastd         m3, [pw_2048]
+    add                  wq, r7
+    jmp                  wq
+.h_w2:
+    movd               xmm0, [srcq+ssq*0]
+    pinsrd             xmm0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pshufb             xmm0, xm4
+    pmaddubsw          xmm0, xm5
+    pmulhrsw           xmm0, xm3
+    packuswb           xmm0, xmm0
+    pextrw     [dstq+dsq*0], xmm0, 0
+    pextrw     [dstq+dsq*1], xmm0, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2
+    RET
+.h_w4:
+    mova               xmm4, [bilin_h_shuf4]
+.h_w4_loop:
+    movq               xmm0, [srcq+ssq*0]
+    movhps             xmm0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb             xmm0, xmm4
+    pmaddubsw          xmm0, xm5
+    pmulhrsw           xmm0, xm3
+    packuswb           xmm0, xmm0
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h_w8:
+    movu                xm0, [srcq+ssq*0]
+    vinserti32x4        ym0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pshufb              ym0, ym4
+    pmaddubsw           ym0, ym5
+    pmulhrsw            ym0, ym3
+    vpmovuswb           xm0, ym0
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    mova                 m4, [bilin_h_perm16]
+.h_w16_loop:
+    movu                ym0, [srcq+ssq*0]
+    vinserti32x8         m0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    vpermb               m0, m4, m0
+    pmaddubsw            m0, m5
+    pmulhrsw             m0, m3
+    vpmovuswb           ym0, m0
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], ym0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16_loop
+    RET
+.h_w32:
+    movu                ym0, [srcq+ssq*0+8*0]
+    vinserti32x8         m0, [srcq+ssq*1+8*0], 1
+    movu                ym1, [srcq+ssq*0+8*1]
+    vinserti32x8         m1, [srcq+ssq*1+8*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w32
+    RET
+.h_w64:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    add                srcq, ssq
+    mova             [dstq], m0
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w64
+    RET
+.h_w128:
+    movu                 m0, [srcq+8*0]
+    movu                 m2, [srcq+8*1]
+    movu                 m1, [srcq+8*8]
+    movu                 m6, [srcq+8*9]
+    add                srcq, ssq
+    REPX  {pshufb    x, m4}, m0, m2, m1, m6
+    REPX  {pmaddubsw x, m5}, m0, m2, m1, m6
+    REPX  {pmulhrsw  x, m3}, m0, m2, m1, m6
+    packuswb             m0, m2
+    packuswb             m1, m6
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w128
+    RET
+.v:
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_v)]
+    imul               mxyd, 255
+    vpbroadcastd         m5, [pw_2048]
+    add                mxyd, 16
+    add                  wq, r7
+    vpbroadcastw         m4, mxyd
+    jmp                  wq
+.v_w2:
+    movd               xmm0,       [srcq+ssq*0]
+.v_w2_loop:
+    pinsrw             xmm1, xmm0, [srcq+ssq*1], 1 ; 0 1
+    lea                srcq,       [srcq+ssq*2]
+    pinsrw             xmm0, xmm1, [srcq+ssq*0], 0 ; 2 1
+    pshuflw            xmm1, xmm1, q2301           ; 1 0
+    punpcklbw          xmm1, xmm0
+    pmaddubsw          xmm1, xm4
+    pmulhrsw           xmm1, xm5
+    packuswb           xmm1, xmm1
+    pextrw     [dstq+dsq*0], xmm1, 1
+    pextrw     [dstq+dsq*1], xmm1, 0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movd               xmm0, [srcq+ssq*0]
+.v_w4_loop:
+    vpbroadcastd       xmm2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd           xmm1, xmm2, xmm0, 0x01 ; 0 1
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm2, xmm0, 0x02       ; 1 2
+    punpcklbw          xmm1, xmm2
+    pmaddubsw          xmm1, xm4
+    pmulhrsw           xmm1, xm5
+    packuswb           xmm1, xmm1
+    movd       [dstq+dsq*0], xmm1
+    pextrd     [dstq+dsq*1], xmm1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq               xmm0, [srcq+ssq*0]
+.v_w8_loop:
+    movq               xmm2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklbw          xmm1, xmm0, xmm2
+    movq               xmm0, [srcq+ssq*0]
+    punpcklbw          xmm2, xmm0
+    pmaddubsw          xmm1, xm4
+    pmaddubsw          xmm2, xm4
+    pmulhrsw           xmm1, xm5
+    pmulhrsw           xmm2, xm5
+    packuswb           xmm1, xmm2
+    movq       [dstq+dsq*0], xmm1
+    movhps     [dstq+dsq*1], xmm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+.v_w16:
+    movu               xmm0, [srcq+ssq*0]
+.v_w16_loop:
+    vbroadcasti128     ymm3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd           ymm2, ymm3, ymm0, 0x0f ; 0 1
+    vbroadcasti128     ymm0, [srcq+ssq*0]
+    vpblendd           ymm3, ymm0, 0xf0       ; 1 2
+    punpcklbw          ymm1, ymm2, ymm3
+    punpckhbw          ymm2, ymm3
+    pmaddubsw          ymm1, ym4
+    pmaddubsw          ymm2, ym4
+    pmulhrsw           ymm1, ym5
+    pmulhrsw           ymm2, ym5
+    packuswb           ymm1, ymm2
+    mova         [dstq+dsq*0], xmm1
+    vextracti128 [dstq+dsq*1], ymm1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    vzeroupper
+    RET
+.v_w32:
+    movu                ym0, [srcq+ssq*0]
+    kxnorb               k1, k1, k1
+.v_w32_loop:
+    vbroadcasti32x8      m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendmd        m2{k1}, m3, m0 ; 0 1
+    vbroadcasti32x8      m0, [srcq+ssq*0]
+    vpblendmd        m3{k1}, m0, m3 ; 1 2
+    punpcklbw            m1, m2, m3
+    punpckhbw            m2, m3
+    pmaddubsw            m1, m4
+    pmaddubsw            m2, m4
+    pmulhrsw             m1, m5
+    pmulhrsw             m2, m5
+    packuswb             m1, m2
+    mova          [dstq+dsq*0], ym1
+    vextracti32x8 [dstq+dsq*1], m1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w32_loop
+    RET
+.v_w64:
+    movu                 m0, [srcq+ssq*0]
+.v_w64_loop:
+    movu                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklbw            m1, m0, m3
+    punpckhbw            m6, m0, m3
+    movu                 m0, [srcq+ssq*0]
+    pmaddubsw            m1, m4
+    pmaddubsw            m6, m4
+    punpcklbw            m2, m3, m0
+    punpckhbw            m3, m0
+    pmaddubsw            m2, m4
+    pmaddubsw            m3, m4
+    REPX   {pmulhrsw x, m5}, m1, m6, m2, m3
+    packuswb             m1, m6
+    packuswb             m2, m3
+    mova       [dstq+dsq*0], m1
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w64_loop
+    RET
+.v_w128:
+    movu                 m0, [srcq+64*0]
+    movu                 m1, [srcq+64*1]
+.v_w128_loop:
+    add                srcq, ssq
+    movu                 m2, [srcq+64*0]
+    movu                 m3, [srcq+64*1]
+    punpcklbw            m6, m0, m2
+    pmaddubsw            m6, m4
+    punpckhbw            m0, m2
+    pmaddubsw            m0, m4
+    punpcklbw            m7, m1, m3
+    pmaddubsw            m7, m4
+    punpckhbw            m1, m3
+    pmaddubsw            m1, m4
+    REPX   {pmulhrsw x, m5}, m6, m0, m7, m1
+    packuswb             m6, m0
+    mova                 m0, m2
+    packuswb             m7, m1
+    mova                 m1, m3
+    mova        [dstq+64*0], m6
+    mova        [dstq+64*1], m7
+    add                dstq, dsq
+    dec                  hd
+    jg .v_w128_loop
+    RET
+.hv:
+    ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 128) >> 8
+    ; = (src[x] + ((my * (src[x + src_stride] - src[x])) >> 4) + 8) >> 4
+    movzx                wd, word [r7+wq*2+table_offset(put, _bilin_hv)]
+    WIN64_SPILL_XMM       8
+    shl                mxyd, 11 ; can't shift by 12 due to signed overflow
+    vpbroadcastd         m7, [pw_2048]
+    add                  wq, r7
+    vpbroadcastw         m6, mxyd
+    jmp                  wq
+.hv_w2:
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    pshufb             xmm0, xm4
+    pmaddubsw          xmm0, xm5
+.hv_w2_loop:
+    movd               xmm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pinsrd             xmm1, [srcq+ssq*0], 1
+    pshufb             xmm1, xm4
+    pmaddubsw          xmm1, xm5               ; 1 _ 2 _
+    shufps             xmm2, xmm0, xmm1, q1032 ; 0 _ 1 _
+    mova               xmm0, xmm1
+    psubw              xmm1, xmm2
+    paddw              xmm1, xmm1
+    pmulhw             xmm1, xm6
+    paddw              xmm1, xmm2
+    pmulhrsw           xmm1, xm7
+    packuswb           xmm1, xmm1
+    pextrw     [dstq+dsq*0], xmm1, 0
+    pextrw     [dstq+dsq*1], xmm1, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    mova               xmm4, [bilin_h_shuf4]
+    movddup            xmm0, [srcq+ssq*0]
+    pshufb             xmm0, xmm4
+    pmaddubsw          xmm0, xm5
+.hv_w4_loop:
+    movq               xmm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps             xmm1, [srcq+ssq*0]
+    pshufb             xmm1, xmm4
+    pmaddubsw          xmm1, xm5               ; 1 2
+    shufps             xmm2, xmm0, xmm1, q1032 ; 0 1
+    mova               xmm0, xmm1
+    psubw              xmm1, xmm2
+    paddw              xmm1, xmm1
+    pmulhw             xmm1, xm6
+    paddw              xmm1, xmm2
+    pmulhrsw           xmm1, xm7
+    packuswb           xmm1, xmm1
+    movd       [dstq+dsq*0], xmm1
+    pextrd     [dstq+dsq*1], xmm1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    vbroadcasti128      ym0, [srcq+ssq*0]
+    pshufb              ym0, ym4
+    pmaddubsw           ym0, ym5
+.hv_w8_loop:
+    movu                xm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti128         ym1, [srcq+ssq*0], 1
+    pshufb              ym1, ym4
+    pmaddubsw           ym1, ym5            ; 1 2
+    valignq             ym2, ym1, ym0, 2
+    mova                ym0, ym1
+    psubw               ym1, ym2
+    paddw               ym1, ym1
+    pmulhw              ym1, ym6
+    paddw               ym1, ym2
+    pmulhrsw            ym1, ym7
+    vpmovuswb           xm1, ym1
+    movq       [dstq+dsq*0], xm1
+    movhps     [dstq+dsq*1], xm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+    vbroadcasti32x8      m0, [srcq+ssq*0]
+    mova                 m4, [bilin_h_perm16]
+    vpermb               m0, m4, m0
+    pmaddubsw            m0, m5
+.hv_w16_loop:
+    movu                ym1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x8         m1, [srcq+ssq*0], 1
+    vpermb               m1, m4, m1
+    pmaddubsw            m1, m5        ; 1 2
+    valignq              m2, m1, m0, 4 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    paddw                m1, m1
+    pmulhw               m1, m6
+    paddw                m1, m2
+    pmulhrsw             m1, m7
+    vpmovuswb           ym1, m1
+    mova          [dstq+dsq*0], xm1
+    vextracti32x4 [dstq+dsq*1], ym1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    RET
+.hv_w32:
+    mova                 m4, [bilin_h_perm32]
+    vpermb               m0, m4, [srcq+ssq*0]
+    pmovzxbq             m8, [pb_02461357]
+    pmaddubsw            m0, m5
+.hv_w32_loop:
+    vpermb               m2, m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpermb               m3, m4, [srcq+ssq*0]
+    pmaddubsw            m2, m5
+    psubw                m1, m2, m0
+    paddw                m1, m1
+    pmulhw               m1, m6
+    paddw                m1, m0
+    pmaddubsw            m0, m3, m5
+    psubw                m3, m0, m2
+    paddw                m3, m3
+    pmulhw               m3, m6
+    paddw                m3, m2
+    pmulhrsw             m1, m7
+    pmulhrsw             m3, m7
+    packuswb             m1, m3
+    vpermq               m1, m8, m1
+    mova          [dstq+dsq*0], ym1
+    vextracti32x8 [dstq+dsq*1], m1, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w32_loop
+    RET
+.hv_w64:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+.hv_w64_loop:
+    add                srcq, ssq
+    movu                 m2, [srcq+8*0]
+    movu                 m3, [srcq+8*1]
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    psubw                m8, m2, m0
+    psubw                m9, m3, m1
+    paddw                m8, m8
+    pmulhw               m8, m6
+    paddw                m9, m9
+    pmulhw               m9, m6
+    paddw                m8, m0
+    pmulhrsw             m8, m7
+    paddw                m9, m1
+    pmulhrsw             m9, m7
+    mova                 m0, m2
+    mova                 m1, m3
+    packuswb             m8, m9
+    mova             [dstq], m8
+    add                dstq, dsq
+    dec                  hd
+    jg .hv_w64_loop
+    RET
+.hv_w128:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    movu                 m2, [srcq+8*8]
+    movu                 m3, [srcq+8*9]
+    REPX  {pshufb    x, m4}, m0, m1, m2, m3
+    REPX  {pmaddubsw x, m5}, m0, m1, m2, m3
+.hv_w128_loop:
+    add                srcq, ssq
+    movu                 m8, [srcq+8*0]
+    movu                 m9, [srcq+8*1]
+    movu                m10, [srcq+8*8]
+    movu                m11, [srcq+8*9]
+    REPX  {pshufb    x, m4}, m8, m9, m10, m11
+    REPX  {pmaddubsw x, m5}, m8, m9, m10, m11
+    psubw               m12, m8, m0
+    psubw               m13, m9, m1
+    psubw               m14, m10, m2
+    psubw               m15, m11, m3
+    paddw               m12, m12
+    pmulhw              m12, m6
+    paddw               m13, m13
+    pmulhw              m13, m6
+    paddw               m14, m14
+    pmulhw              m14, m6
+    paddw               m15, m15
+    pmulhw              m15, m6
+    paddw               m12, m0
+    pmulhrsw            m12, m7
+    paddw               m13, m1
+    pmulhrsw            m13, m7
+    paddw               m14, m2
+    pmulhrsw            m14, m7
+    paddw               m15, m3
+    pmulhrsw            m15, m7
+    mova                 m0, m8
+    mova                 m1, m9
+    mova                 m2, m10
+    mova                 m3, m11
+    packuswb            m12, m13
+    packuswb            m14, m15
+    mova        [dstq+64*0], m12
+    mova        [dstq+64*1], m14
+    add                dstq, dsq
+    dec                  hd
+    jg .hv_w128_loop
+    RET
+
+DECLARE_REG_TMP 3, 5, 6
+
+cglobal prep_bilin_8bpc, 3, 7, 0, tmp, src, stride, w, h, mxy, stride3
+    movifnidn          mxyd, r5m ; mx
+    lea                  t2, [prep_avx512icl]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r6m ; my
+    test               mxyd, mxyd
+    jnz .v
+.prep:
+    movzx                wd, word [t2+wq*2+table_offset(prep,)]
+    add                  wq, t2
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.prep_w4:
+    movd               xmm0, [srcq+strideq*0]
+    pinsrd             xmm0, [srcq+strideq*1], 1
+    pinsrd             xmm0, [srcq+strideq*2], 2
+    pinsrd             xmm0, [srcq+stride3q ], 3
+    lea                srcq, [srcq+strideq*4]
+    pmovzxbw            ym0, xmm0
+    psllw               ym0, 4
+    mova             [tmpq], ym0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .prep_w4
+    RET
+.prep_w8:
+    movq               xmm0, [srcq+strideq*0]
+    movq               xmm1, [srcq+strideq*1]
+    vinserti128         ym0, ymm0, [srcq+strideq*2], 1
+    vinserti128         ym1, ymm1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    punpcklqdq          ym0, ym1
+    pmovzxbw             m0, ym0
+    psllw                m0, 4
+    mova             [tmpq], m0
+    add                tmpq, 32*2
+    sub                  hd, 4
+    jg .prep_w8
+    RET
+.prep_w16:
+    movu               xmm0, [srcq+strideq*0]
+    vinserti128         ym0, ymm0, [srcq+strideq*1], 1
+    movu               xmm1, [srcq+strideq*2]
+    vinserti128         ym1, ymm1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    pmovzxbw             m0, ym0
+    pmovzxbw             m1, ym1
+    psllw                m0, 4
+    psllw                m1, 4
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    add                tmpq, 32*4
+    sub                  hd, 4
+    jg .prep_w16
+    RET
+.prep_w32:
+    pmovzxbw             m0, [srcq+strideq*0]
+    pmovzxbw             m1, [srcq+strideq*1]
+    pmovzxbw             m2, [srcq+strideq*2]
+    pmovzxbw             m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    REPX       {psllw x, 4}, m0, m1, m2, m3
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    sub                  hd, 4
+    jg .prep_w32
+    RET
+.prep_w64:
+    pmovzxbw             m0, [srcq+strideq*0+32*0]
+    pmovzxbw             m1, [srcq+strideq*0+32*1]
+    pmovzxbw             m2, [srcq+strideq*1+32*0]
+    pmovzxbw             m3, [srcq+strideq*1+32*1]
+    lea                srcq, [srcq+strideq*2]
+    REPX       {psllw x, 4}, m0, m1, m2, m3
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    sub                  hd, 2
+    jg .prep_w64
+    RET
+.prep_w128:
+    pmovzxbw             m0, [srcq+32*0]
+    pmovzxbw             m1, [srcq+32*1]
+    pmovzxbw             m2, [srcq+32*2]
+    pmovzxbw             m3, [srcq+32*3]
+    REPX       {psllw x, 4}, m0, m1, m2, m3
+    mova    [tmpq+64*0], m0
+    mova    [tmpq+64*1], m1
+    mova    [tmpq+64*2], m2
+    mova    [tmpq+64*3], m3
+    add                tmpq, 64*4
+    add                srcq, strideq
+    dec                  hd
+    jg .prep_w128
+    RET
+.h:
+    ; 16 * src[x] + (mx * (src[x + 1] - src[x]))
+    ; = (16 - mx) * src[x] + mx * src[x + 1]
+    imul               mxyd, 255
+    add                mxyd, 16
+    vpbroadcastw         m5, mxyd
+    mov                mxyd, r6m ; my
+    test               mxyd, mxyd
+    jnz .hv
+    movzx                wd, word [t2+wq*2+table_offset(prep, _bilin_h)]
+    add                  wq, t2
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.h_w4:
+    vbroadcasti32x4     ym4, [bilin_h_shuf4]
+.h_w4_loop:
+    movq               xmm0, [srcq+strideq*0]
+    movq               xmm1, [srcq+strideq*1]
+    vinserti32x4        ym0, ymm0, [srcq+strideq*2], 1
+    vinserti32x4        ym1, ymm1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    punpcklqdq          ym0, ym1
+    pshufb              ym0, ym4
+    pmaddubsw           ym0, ym5
+    mova             [tmpq], ym0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4_loop
+    RET
+.h_w8:
+    vbroadcasti32x4      m4, [bilin_h_perm16]
+.h_w8_loop:
+    movu               xmm0, [srcq+strideq*0]
+    vinserti32x4        ym0, ymm0, [srcq+strideq*1], 1
+    vinserti32x4         m0, [srcq+strideq*2], 2
+    vinserti32x4         m0, [srcq+stride3q ], 3
+    lea                srcq, [srcq+strideq*4]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .h_w8_loop
+    RET
+.h_w16:
+    mova                 m4, [bilin_h_perm16]
+.h_w16_loop:
+    movu                ym0, [srcq+strideq*0]
+    vinserti32x8         m0, [srcq+strideq*1], 1
+    movu                ym1, [srcq+strideq*2]
+    vinserti32x8         m1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    vpermb               m0, m4, m0
+    vpermb               m1, m4, m1
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    add                tmpq, 64*2
+    sub                  hd, 4
+    jg .h_w16_loop
+    RET
+.h_w32:
+    mova                 m4, [bilin_h_perm32]
+.h_w32_loop:
+    vpermb               m0, m4, [srcq+strideq*0]
+    vpermb               m1, m4, [srcq+strideq*1]
+    vpermb               m2, m4, [srcq+strideq*2]
+    vpermb               m3, m4, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    sub                  hd, 4
+    jg .h_w32_loop
+    RET
+.h_w64:
+    mova                 m4, [bilin_h_perm32]
+.h_w64_loop:
+    vpermb               m0, m4, [srcq+strideq*0+32*0]
+    vpermb               m1, m4, [srcq+strideq*0+32*1]
+    vpermb               m2, m4, [srcq+strideq*1+32*0]
+    vpermb               m3, m4, [srcq+strideq*1+32*1]
+    lea                srcq, [srcq+strideq*2]
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    sub                  hd, 2
+    jg .h_w64_loop
+    RET
+.h_w128:
+    mova                 m4, [bilin_h_perm32]
+.h_w128_loop:
+    vpermb               m0, m4, [srcq+32*0]
+    vpermb               m1, m4, [srcq+32*1]
+    vpermb               m2, m4, [srcq+32*2]
+    vpermb               m3, m4, [srcq+32*3]
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+    mova        [tmpq+64*2], m2
+    mova        [tmpq+64*3], m3
+    add                tmpq, 64*4
+    add                srcq, strideq
+    dec                  hd
+    jg .h_w128_loop
+    RET
+.v:
+    WIN64_SPILL_XMM       7
+    movzx                wd, word [t2+wq*2+table_offset(prep, _bilin_v)]
+    imul               mxyd, 255
+    add                mxyd, 16
+    add                  wq, t2
+    lea            stride3q, [strideq*3]
+    vpbroadcastw         m6, mxyd
+    jmp                  wq
+.v_w4:
+    vpbroadcastd        xm0, [srcq+strideq*0]
+    mov                 r3d, 0x29
+    vbroadcasti32x4     ym3, [bilin_v_shuf4]
+    kmovb                k1, r3d
+.v_w4_loop:
+    vpblendmd       xm1{k1}, xm0, [srcq+strideq*1] {1to4} ; __01 ____
+    vpbroadcastd        ym2, [srcq+strideq*2]
+    vpbroadcastd    ym2{k1}, [srcq+stride3q ]             ; __2_ 23__
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastd        ym0, [srcq+strideq*0]
+    punpckhqdq      ym2{k1}, ym1, ym0                     ; 012_ 234_
+    pshufb              ym2, ym3
+    pmaddubsw           ym2, ym6
+    mova             [tmpq], ym2
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    RET
+.v_w8:
+    mova                 m5, [bilin_v_perm8]
+    vbroadcasti32x4     ym0, [srcq+strideq*0]
+.v_w8_loop:
+    vinserti32x4        ym1, ym0, [srcq+strideq*1], 1
+    vpbroadcastq        ym0, [srcq+strideq*2]
+    vinserti32x4         m1, [srcq+stride3q ], 2
+    lea                srcq, [srcq+strideq*4]
+    vinserti32x4        ym0, [srcq+strideq*0], 0
+    vpermt2b             m1, m5, m0
+    pmaddubsw            m1, m6
+    mova             [tmpq], m1
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    mova                 m5, [bilin_v_perm16]
+    movu                xm0, [srcq+strideq*0]
+.v_w16_loop:
+    movu                xm2, [srcq+strideq*2]
+    vinserti32x4        ym1, ym0, [srcq+strideq*1], 1
+    vpermt2b             m1, m5, m2
+    vinserti32x4        ym2, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    movu                xm0, [srcq+strideq*0]
+    vpermt2b             m2, m5, m0
+    pmaddubsw            m1, m6
+    pmaddubsw            m2, m6
+    mova        [tmpq+64*0], m1
+    mova        [tmpq+64*1], m2
+    add                tmpq, 64*2
+    sub                  hd, 4
+    jg .v_w16_loop
+    RET
+.v_w32:
+    mova                 m5, [bilin_v_perm32]
+    movu                ym0, [srcq+strideq*0]
+.v_w32_loop:
+    movu                ym2, [srcq+strideq*1]
+    movu                ym3, [srcq+strideq*2]
+    movu                ym4, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpermt2b             m0, m5, m2
+    vpermt2b             m2, m5, m3
+    vpermt2b             m3, m5, m4
+    pmaddubsw            m1, m0, m6
+    movu                ym0, [srcq+strideq*0]
+    vpermt2b             m4, m5, m0
+    pmaddubsw            m2, m6
+    pmaddubsw            m3, m6
+    pmaddubsw            m4, m6
+    mova        [tmpq+64*0], m1
+    mova        [tmpq+64*1], m2
+    mova        [tmpq+64*2], m3
+    mova        [tmpq+64*3], m4
+    add                tmpq, 64*4
+    sub                  hd, 4
+    jg .v_w32_loop
+    RET
+.v_w64:
+    mova                 m5, [bilin_v_perm64]
+    vpermq               m0, m5, [srcq+strideq*0]
+.v_w64_loop:
+    vpermq               m1, m5, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    punpcklbw            m4, m0, m1
+    punpckhbw            m2, m0, m1
+    vpermq               m0, m5, [srcq+strideq*0]
+    punpcklbw            m3, m1, m0
+    punpckhbw            m1, m0
+    pmaddubsw            m4, m6
+    pmaddubsw            m2, m6
+    pmaddubsw            m3, m6
+    pmaddubsw            m1, m6
+    mova        [tmpq+64*0], m4
+    mova        [tmpq+64*1], m2
+    mova        [tmpq+64*2], m3
+    mova        [tmpq+64*3], m1
+    add                tmpq, 64*4
+    sub                  hd, 2
+    jg .v_w64_loop
+    RET
+.v_w128:
+    mova                 m5, [bilin_v_perm64]
+    vpermq               m0, m5, [srcq+strideq*0+ 0]
+    vpermq               m1, m5, [srcq+strideq*0+64]
+.v_w128_loop:
+    vpermq               m2, m5, [srcq+strideq*1+ 0]
+    vpermq               m3, m5, [srcq+strideq*1+64]
+    lea                srcq, [srcq+strideq*2]
+    punpcklbw            m4, m0, m2
+    punpckhbw            m0, m2
+    pmaddubsw            m4, m6
+    pmaddubsw            m0, m6
+    mova        [tmpq+64*0], m4
+    mova        [tmpq+64*1], m0
+    punpcklbw            m4, m1, m3
+    punpckhbw            m1, m3
+    pmaddubsw            m4, m6
+    pmaddubsw            m1, m6
+    mova        [tmpq+64*2], m4
+    mova        [tmpq+64*3], m1
+    vpermq               m0, m5, [srcq+strideq*0+ 0]
+    vpermq               m1, m5, [srcq+strideq*0+64]
+    punpcklbw            m4, m2, m0
+    punpckhbw            m2, m0
+    pmaddubsw            m4, m6
+    pmaddubsw            m2, m6
+    mova        [tmpq+64*4], m4
+    mova        [tmpq+64*5], m2
+    punpcklbw            m4, m3, m1
+    punpckhbw            m3, m1
+    pmaddubsw            m4, m6
+    pmaddubsw            m3, m6
+    mova        [tmpq+64*6], m4
+    mova        [tmpq+64*7], m3
+    add                tmpq, 64*8
+    sub                  hd, 2
+    jg .v_w128_loop
+    RET
+.hv:
+    ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 8) >> 4
+    ; = src[x] + (((my * (src[x + src_stride] - src[x])) + 8) >> 4)
+    WIN64_SPILL_XMM       7
+    movzx                wd, word [t2+wq*2+table_offset(prep, _bilin_hv)]
+    shl                mxyd, 11
+    vpbroadcastw         m6, mxyd
+    add                  wq, t2
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.hv_w4:
+    vbroadcasti32x4     ym4, [bilin_h_shuf4]
+    vpbroadcastq        ym0, [srcq+strideq*0]
+    pshufb              ym0, ym4
+    pmaddubsw           ym0, ym5
+.hv_w4_loop:
+    movq               xmm1, [srcq+strideq*1]
+    movq               xmm2, [srcq+strideq*2]
+    vinserti32x4        ym1, ymm1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    vinserti32x4        ym2, ymm2, [srcq+strideq*0], 1
+    punpcklqdq          ym1, ym2
+    pshufb              ym1, ym4
+    pmaddubsw           ym1, ym5         ; 1 2 3 4
+    valignq             ym2, ym1, ym0, 3 ; 0 1 2 3
+    mova                ym0, ym1
+    psubw               ym1, ym2
+    pmulhrsw            ym1, ym6
+    paddw               ym1, ym2
+    mova             [tmpq], ym1
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    vbroadcasti32x4      m4, [bilin_h_perm16]
+    vbroadcasti32x4      m0, [srcq+strideq*0]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w8_loop:
+    movu               xmm1, [srcq+strideq*1]
+    vinserti128         ym1, ymm1, [srcq+strideq*2], 1
+    vinserti128          m1, [srcq+stride3q ], 2
+    lea                srcq, [srcq+strideq*4]
+    vinserti128          m1, [srcq+strideq*0], 3
+    pshufb               m1, m4
+    pmaddubsw            m1, m5        ; 1 2 3 4
+    valignq              m2, m1, m0, 6 ; 0 1 2 3
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhrsw             m1, m6
+    paddw                m1, m2
+    mova             [tmpq], m1
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+    mova                 m4, [bilin_h_perm16]
+    vbroadcasti32x8      m0, [srcq+strideq*0]
+    vpermb               m0, m4, m0
+    pmaddubsw            m0, m5
+.hv_w16_loop:
+    movu                ym1, [srcq+strideq*1]
+    vinserti32x8         m1, [srcq+strideq*2], 1
+    movu                ym2, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vinserti32x8         m2, [srcq+strideq*0], 1
+    vpermb               m1, m4, m1
+    vpermb               m2, m4, m2
+    pmaddubsw            m1, m5            ; 1 2
+    vshufi32x4           m3, m0, m1, q1032 ; 0 1
+    pmaddubsw            m0, m2, m5        ; 3 4
+    vshufi32x4           m2, m1, m0, q1032 ; 2 3
+    psubw                m1, m3
+    pmulhrsw             m1, m6
+    paddw                m1, m3
+    psubw                m3, m0, m2
+    pmulhrsw             m3, m6
+    paddw                m3, m2
+    mova        [tmpq+64*0], m1
+    mova        [tmpq+64*1], m3
+    add                tmpq, 64*2
+    sub                  hd, 4
+    jg .hv_w16_loop
+    RET
+.hv_w32:
+    mova                 m4, [bilin_h_perm32]
+    vpermb               m0, m4, [srcq+strideq*0]
+    pmaddubsw            m0, m5
+.hv_w32_loop:
+    vpermb               m1, m4, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    vpermb               m2, m4, [srcq+strideq*0]
+    pmaddubsw            m1, m5
+    psubw                m3, m1, m0
+    pmulhrsw             m3, m6
+    paddw                m3, m0
+    pmaddubsw            m0, m2, m5
+    psubw                m2, m0, m1
+    pmulhrsw             m2, m6
+    paddw                m2, m1
+    mova        [tmpq+64*0], m3
+    mova        [tmpq+64*1], m2
+    add                tmpq, 64*2
+    sub                  hd, 2
+    jg .hv_w32_loop
+    RET
+.hv_w64:
+    mova                 m4, [bilin_h_perm32]
+    vpermb               m0, m4, [srcq+32*0]
+    vpermb               m1, m4, [srcq+32*1]
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+.hv_w64_loop:
+    add                srcq, strideq
+    vpermb               m2, m4, [srcq+32*0]
+    vpermb               m3, m4, [srcq+32*1]
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    psubw                m7, m2, m0
+    psubw                m8, m3, m1
+    pmulhrsw             m7, m6
+    pmulhrsw             m8, m6
+    paddw                m7, m0
+    mova                 m0, m2
+    paddw                m8, m1
+    mova                 m1, m3
+    mova        [tmpq+64*0], m7
+    mova        [tmpq+64*1], m8
+    add                tmpq, 64*2
+    dec                  hd
+    jg .hv_w64_loop
+    RET
+.hv_w128:
+    mova                 m4, [bilin_h_perm32]
+    vpermb               m0, m4, [srcq+32*0]
+    vpermb               m1, m4, [srcq+32*1]
+    vpermb               m2, m4, [srcq+32*2]
+    vpermb               m3, m4, [srcq+32*3]
+    REPX  {pmaddubsw x, m5}, m0, m1, m2, m3
+.hv_w128_loop:
+    add                srcq, strideq
+    vpermb               m7, m4, [srcq+32*0]
+    vpermb               m8, m4, [srcq+32*1]
+    vpermb               m9, m4, [srcq+32*2]
+    vpermb              m10, m4, [srcq+32*3]
+    REPX  {pmaddubsw x, m5}, m7, m8, m9, m10
+    psubw               m11, m7, m0
+    psubw               m12, m8, m1
+    psubw               m13, m9, m2
+    psubw               m14, m10, m3
+    REPX  {pmulhrsw  x, m6}, m11, m12, m13, m14
+    paddw               m11, m0
+    mova                 m0, m7
+    paddw               m12, m1
+    mova                 m1, m8
+    paddw               m13, m2
+    mova                 m2, m9
+    paddw               m14, m3
+    mova                 m3, m10
+    mova        [tmpq+64*0], m11
+    mova        [tmpq+64*1], m12
+    mova        [tmpq+64*2], m13
+    mova        [tmpq+64*3], m14
+    add                tmpq, 64*4
+    dec                  hd
+    jg .hv_w128_loop
+    RET
+
+; int8_t subpel_filters[5][15][8]
+%assign FILTER_REGULAR (0*15 << 16) | 3*15
+%assign FILTER_SMOOTH  (1*15 << 16) | 4*15
+%assign FILTER_SHARP   (2*15 << 16) | 3*15
+
+%macro FN 4-5 ; fn, type, type_h, type_v, jmp_to
+cglobal %1_%2_8bpc
+    mov                 t0d, FILTER_%3
+%ifidn %3, %4
+    mov                 t1d, t0d
+%else
+    mov                 t1d, FILTER_%4
+%endif
+%if %0 == 5 ; skip the jump in the last filter
+    jmp mangle(private_prefix %+ _%5 %+ SUFFIX)
+%endif
+%endmacro
+
+%macro PUT_8TAP_H 4-5 0 ; dst/src, tmp[1-3], vpermb
+%if %5
+    vpermb              m%2, m6, m%1
+    vpermb              m%3, m7, m%1
+    vpermb              m%4, m8, m%1
+%else
+%if %2 < %4 ; reuse a previous value if possible
+    pshufb              m%2, m%1, m6
+%endif
+    pshufb              m%3, m%1, m7
+    pshufb              m%4, m%1, m8
+%endif
+    mova                m%1, m5
+    vpdpbusd            m%1, m%2, m9
+    mova                m%2, m5
+    vpdpbusd            m%2, m%3, m9
+    vpdpbusd            m%1, m%3, m10
+    vpdpbusd            m%2, m%4, m10
+    packusdw            m%1, m%2
+    psrlw               m%1, 6
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 4, 5
+%else
+DECLARE_REG_TMP 7, 8
+%endif
+
+; Due to the use of vpdpbusd (which does 4 pixels per instruction) in
+; the horizontal filter, 6-tap is only used for the vertical filter.
+%define PUT_8TAP_FN FN put_8tap,
+PUT_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  put_6tap_8bpc
+PUT_8TAP_FN sharp_regular,  SHARP,   REGULAR, put_6tap_8bpc
+PUT_8TAP_FN smooth,         SMOOTH,  SMOOTH,  put_6tap_8bpc
+PUT_8TAP_FN smooth_regular, SMOOTH,  REGULAR, put_6tap_8bpc
+PUT_8TAP_FN regular_smooth, REGULAR, SMOOTH,  put_6tap_8bpc
+PUT_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal put_6tap_8bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my, ns
+%define base r8-put_avx512icl
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    lea                  r8, [put_avx512icl]
+    movsxd               wq, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.put:
+    tzcnt                wd, wd
+    movzx                wd, word [r8+wq*2+table_offset(put,)]
+    add                  wq, r8
+    lea                  r6, [ssq*3]
+    lea                  r7, [dsq*3]
+%if WIN64
+    pop                  r8
+%endif
+    jmp                  wq
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    tzcnt               r6d, wd
+    movzx               r6d, word [r8+r6*2+table_offset(put, _6tap_v)]
+    vpbroadcastd         m6, [pw_512]
+    lea                 myq, [base+subpel_filters+1+myq*8]
+    vpbroadcastw         m7, [myq+0]
+    add                  r6, r8
+    vpbroadcastw         m8, [myq+2]
+    mov                 nsq, ssq
+    vpbroadcastw         m9, [myq+4]
+    neg                 nsq
+    jmp                  r6
+.v_w2:
+    movd               xmm2, [srcq+nsq*2]
+    pinsrw             xmm2, [srcq+nsq*1], 2
+    pinsrw             xmm2, [srcq+ssq*0], 4
+    pinsrw             xmm2, [srcq+ssq*1], 6  ; 0 1 2 3
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    palignr            xmm3, xmm0, xmm2, 4    ; 1 2 3 4
+    punpcklbw          xmm1, xmm2, xmm3       ; 01 12
+    punpckhbw          xmm2, xmm3             ; 23 34
+.v_w2_loop:
+    vpbroadcastd       xmm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw          xmm3, xmm1, xm7        ; a0 b0
+    mova               xmm1, xmm2
+    pmaddubsw          xmm2, xm8              ; a1 b1
+    paddw              xmm3, xmm2
+    vpblendd           xmm2, xmm0, xmm4, 0x02 ; 4 5
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm4, xmm0, 0x02       ; 5 6
+    punpcklbw          xmm2, xmm4             ; 67 78
+    pmaddubsw          xmm4, xmm2, xm9        ; a3 b3
+    paddw              xmm3, xmm4
+    pmulhrsw           xmm3, xm6
+    packuswb           xmm3, xmm3
+    pextrw     [dstq+dsq*0], xmm3, 0
+    pextrw     [dstq+dsq*1], xmm3, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movd               xmm2, [srcq+nsq*2]
+    pinsrd             xmm2, [srcq+nsq*1], 1
+    pinsrd             xmm2, [srcq+ssq*0], 2
+    pinsrd             xmm2, [srcq+ssq*1], 3  ; 0 1 2 3
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    palignr            xmm3, xmm0, xmm2, 4    ; 1 2 3 4
+    punpcklbw          xmm1, xmm2, xmm3       ; 01 12
+    punpckhbw          xmm2, xmm3             ; 23 34
+.v_w4_loop:
+    vpbroadcastd       xmm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw          xmm3, xmm1, xm7        ; a0 b0
+    mova               xmm1, xmm2
+    pmaddubsw          xmm2, xm8              ; a1 b1
+    paddw              xmm3, xmm2
+    vpblendd           xmm2, xmm0, xmm4, 0x02 ; 4 5
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm4, xmm0, 0x02       ; 5 6
+    punpcklbw          xmm2, xmm4             ; 45 56
+    pmaddubsw          xmm4, xmm2, xm9        ; a2 b2
+    paddw              xmm3, xmm4
+    pmulhrsw           xmm3, xm6
+    packuswb           xmm3, xmm3
+    movd       [dstq+dsq*0], xmm3
+    pextrd     [dstq+dsq*1], xmm3, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq               xmm1, [srcq+nsq*2]
+    vpbroadcastq       ymm3, [srcq+nsq*1]
+    vpbroadcastq       ymm2, [srcq+ssq*0]
+    vpbroadcastq       ymm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastq       ymm0, [srcq+ssq*0]
+    vpblendd           ymm1, ymm3, 0x30
+    vpblendd           ymm3, ymm2, 0x30
+    punpcklbw          ymm1, ymm3      ; 01 12
+    vpblendd           ymm2, ymm4, 0x30
+    vpblendd           ymm4, ymm0, 0x30
+    punpcklbw          ymm2, ymm4      ; 23 34
+.v_w8_loop:
+    vpbroadcastq       ymm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw          ymm3, ymm1, ym7 ; a0 b0
+    mova               ymm1, ymm2
+    pmaddubsw          ymm2, ym8       ; a1 b1
+    paddw              ymm3, ymm2
+    vpblendd           ymm2, ymm0, ymm4, 0x30
+    vpbroadcastq       ymm0, [srcq+ssq*0]
+    vpblendd           ymm4, ymm0, 0x30
+    punpcklbw          ymm2, ymm4      ; 45 56
+    pmaddubsw          ymm4, ymm2, ym9 ; a2 b2
+    paddw              ymm3, ymm4
+    pmulhrsw           ymm3, ym6
+    vextracti128       xmm4, ymm3, 1
+    packuswb           xmm3, xmm4
+    movq       [dstq+dsq*0], xmm3
+    movhps     [dstq+dsq*1], xmm3
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    vzeroupper
+    RET
+.v_w16:
+    mova                 m5, [spel_v_perm16a]
+    vbroadcasti32x4      m1, [srcq+nsq*2]
+    vbroadcasti32x4     ym3, [srcq+nsq*1]
+    mov                 r6d, 0x0f
+    vbroadcasti32x4      m2, [srcq+ssq*0]
+    kmovb                k1, r6d
+    vbroadcasti32x4     ym4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vbroadcasti32x4      m0, [srcq+ssq*0]
+    vshufpd          m1{k1}, m3, m2, 0xcc
+    vshufpd          m2{k1}, m4, m0, 0xcc
+    vpermb               m1, m5, m1 ; 01 12
+    vpermb               m2, m5, m2 ; 23 34
+.v_w16_loop:
+    vbroadcasti32x4     ym4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw            m3, m1, m7 ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, m8     ; a1 b1
+    paddw                m3, m2
+    mova                 m2, m0
+    vbroadcasti32x4      m0, [srcq+ssq*0]
+    vshufpd          m2{k1}, m4, m0, 0xcc
+    vpermb               m2, m5, m2 ; 45 56
+    pmaddubsw            m4, m2, m9 ; a2 b2
+    paddw                m3, m4
+    pmulhrsw             m3, m6
+    vextracti32x8       ym4, m3, 1
+    packuswb            ym3, ym4
+    mova          [dstq+dsq*0], xm3
+    vextracti32x4 [dstq+dsq*1], ym3, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+    mova                m10, [spel_v_perm32]
+    pmovzxbq             m5, [pb_02461357]
+    vpshrdw             m11, m10, m10, 8
+    movu                ym0, [srcq+nsq*2]
+    vinserti32x8         m0, [srcq+nsq*1], 1
+    vpermb               m1, m10, m0 ; 01
+    vinserti32x8         m0, [srcq+ssq*0], 0
+    vpermb               m2, m11, m0 ; 12
+    vinserti32x8         m0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    vpermb               m3, m10, m0 ; 23
+    vinserti32x8         m0, [srcq+ssq*0], 0
+    vpermb               m4, m11, m0 ; 34
+.v_w32_loop:
+    vinserti32x8         m0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw           m12, m1, m7
+    mova                 m1, m3
+    pmaddubsw           m13, m2, m7
+    mova                 m2, m4
+    pmaddubsw           m14, m3, m8
+    vpermb               m3, m10, m0 ; 45
+    vinserti32x8         m0, [srcq+ssq*0], 0
+    pmaddubsw           m15, m4, m8
+    vpermb               m4, m11, m0 ; 56
+    paddw               m12, m14
+    pmaddubsw           m14, m3, m9
+    paddw               m13, m15
+    pmaddubsw           m15, m4, m9
+    paddw               m12, m14
+    paddw               m13, m15
+    pmulhrsw            m12, m6
+    pmulhrsw            m13, m6
+    packuswb            m12, m13
+    vpermq              m12, m5, m12
+    mova          [dstq+dsq*0], ym12
+    vextracti32x8 [dstq+dsq*1], m12, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w32_loop
+    RET
+.v_w64:
+.v_w128:
+    lea                 r6d, [hq+wq*4-256]
+.v_loop0:
+    movu                 m2, [srcq+nsq*2]
+    movu                 m4, [srcq+nsq*1]
+    lea                  r4, [srcq+ssq*2]
+    movu                m11, [srcq+ssq*0]
+    movu                m13, [srcq+ssq*1]
+    mov                  r7, dstq
+    movu                 m0, [r4  +ssq*0]
+    punpcklbw            m1, m2, m4   ; 01l
+    punpckhbw            m2, m4       ; 01h
+    punpcklbw            m3, m4, m11  ; 12l
+    punpckhbw            m4, m11      ; 12h
+    punpcklbw           m10, m11, m13 ; 23l
+    punpckhbw           m11, m13      ; 23h
+    punpcklbw           m12, m13, m0  ; 34l
+    punpckhbw           m13, m0       ; 34h
+.v_loop:
+    movu                 m5, [r4+ssq*1]
+    pmaddubsw           m14, m1, m7   ; a0l
+    mova                 m1, m10
+    pmaddubsw           m10, m8       ; a1l
+    lea                  r4, [r4+ssq*2]
+    pmaddubsw           m15, m2, m7   ; a0h
+    mova                 m2, m11
+    pmaddubsw           m11, m8       ; a1h
+    paddw               m14, m10
+    punpcklbw           m10, m0, m5   ; 45l
+    paddw               m15, m11
+    punpckhbw           m11, m0, m5   ; 45h
+    pmaddubsw            m0, m10, m9  ; a2l
+    paddw               m14, m0
+    pmaddubsw            m0, m11, m9  ; a2h
+    paddw               m15, m0
+    movu                 m0, [r4+ssq*0]
+    pmulhrsw            m14, m6
+    pmulhrsw            m15, m6
+    packuswb            m14, m15
+    pmaddubsw           m15, m3, m7   ; b0l
+    mova                 m3, m12
+    pmaddubsw           m12, m8       ; b1l
+    mova         [r7+dsq*0], m14
+    pmaddubsw           m14, m4, m7   ; b0h
+    mova                 m4, m13
+    pmaddubsw           m13, m8       ; b1h
+    paddw               m15, m12
+    punpcklbw           m12, m5, m0   ; 56l
+    paddw               m14, m13
+    punpckhbw           m13, m5, m0   ; 56h
+    pmaddubsw            m5, m12, m9  ; b2l
+    paddw               m15, m5
+    pmaddubsw            m5, m13, m9  ; b2h
+    paddw               m14, m5
+    pmulhrsw            m15, m6
+    pmulhrsw            m14, m6
+    packuswb            m15, m14
+    mova         [r7+dsq*1], m15
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .v_loop
+    add                srcq, 64
+    add                dstq, 64
+    movzx                hd, r6b
+    sub                 r6d, 256
+    jg .v_loop0
+    RET
+.h:
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _put_8tap_8bpc_avx512icl).h2
+.hv:
+    vpbroadcastd         m9, [pd_34]
+    mova               xm10, [spel_hv_end]
+    pxor                xm0, xm0
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    dec                srcq
+    vpbroadcastd         m7, [base+subpel_filters+mxq*8+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq        ym1, [base+subpel_filters+1+myq*8]
+    mov                 nsq, ssq
+    punpcklbw           ym0, ym1
+    neg                 nsq
+    psraw               ym0, 2 ; << 6
+    pshufd             ym11, ym0, q0000
+    pshufd             ym12, ym0, q1111
+    pshufd             ym13, ym0, q2222
+    cmp                  wd, 4
+    je .hv_w4
+    vbroadcasti128      ym5, [subpel_h_shuf4]
+    movq               xmm0, [srcq+nsq*2]
+    movhps             xmm0, [srcq+nsq*1]
+    movq               xmm2, [srcq+ssq*0]
+    movhps             xmm2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpbroadcastq       ymm1, [srcq+ssq*0]
+    vpblendd           ymm0, ymm1, 0x30
+    pshufb             xmm2, xm5        ; 2 3
+    pshufb             ymm0, ym5        ; 0 1   4
+    mova               xmm1, xm9
+    vpdpbusd           xmm1, xmm2, xm7
+    mova               ymm2, ym9
+    vpdpbusd           ymm2, ymm0, ym7
+    packssdw           ymm2, ymm1
+    psraw              ymm2, 2
+    vextracti128       xmm0, ymm2, 1
+    vzeroupper
+    palignr            xmm0, xmm2, 4
+    punpcklwd          xmm1, xmm2, xmm0 ; 01 12
+    punpckhwd          xmm2, xmm0       ; 23 34
+.hv_w2_loop:
+    movq               xmm3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps             xmm3, [srcq+ssq*0]
+    pmaddwd            xmm4, xmm1, xm11 ; a0 b0
+    mova               xmm1, xmm2
+    vpdpwssd           xmm4, xmm2, xm12 ; a1 b1
+    pshufb             xmm3, xm5
+    mova               xmm2, xm9
+    vpdpbusd           xmm2, xmm3, xm7
+    packssdw           xmm3, xmm2, xmm2
+    psraw              xmm3, 2
+    palignr            xmm2, xmm3, xmm0, 12
+    mova               xmm0, xmm3
+    punpcklwd          xmm2, xmm3       ; 45 56
+    vpdpwssd           xmm4, xmm2, xm13 ; a2 b2
+    packuswb           xmm4, xmm4
+    pshufb             xmm4, xm10
+    pextrw     [dstq+dsq*0], xmm4, 0
+    pextrw     [dstq+dsq*1], xmm4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    movq                xm2, [srcq+nsq*2]
+    vpbroadcastq        ym1, [srcq+nsq*1]
+    vinserti32x4        ym2, [srcq+ssq*0], 1
+    vinserti32x4         m1, [srcq+ssq*1], 2 ; _ 1 3
+    lea                srcq, [srcq+ssq*2]
+    vbroadcasti32x4      m5, [subpel_h_shufA]
+    vinserti32x4         m2, [srcq+ssq*0], 2 ; 0 2 4
+    pshufb               m1, m5
+    mova                 m0, m9
+    pshufb               m2, m5
+    mova                 m3, m9
+    vpdpbusd             m0, m1, m7
+    mova                ym1, [spel_hv_perm4a]
+    vpdpbusd             m3, m2, m7
+    mova                ym2, [spel_hv_perm4b]
+    mov                 r6d, 0x5555
+    mova                ym6, [spel_hv_perm4d]
+    packssdw             m0, m3
+    kmovw                k1, r6d
+    psraw                m0, 2 ; _ 0   1 2   3 4   5 6
+    vpermb              ym1, ym1, ym0 ; 01 12
+    vpermb               m2, m2, m0   ; 23 34
+.hv_w4_loop:
+    movq                xm3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x4        ym3, [srcq+ssq*0], 1
+    pmaddwd             ym4, ym1, ym11 ; a0 b0
+    mova                ym1, ym2
+    pshufb              ym3, ym5
+    mova                ym0, ym9
+    vpdpbusd            ym0, ym3, ym7
+    vpdpwssd            ym4, ym2, ym12 ; a1 b1
+    vpsraw          ym2{k1}, ym0, 2    ; 5 6
+    vpermb              ym2, ym6, ym2  ; 45 56
+    vpdpwssd            ym4, ym2, ym13 ; a2 b2
+    packuswb            ym4, ym4
+    vpermb              ym4, ym10, ym4
+    movd       [dstq+dsq*0], xm4
+    pextrd     [dstq+dsq*1], xm4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    sub                srcq, 3
+    vpbroadcastd        m11, [base+subpel_filters+mxq*8+0]
+    vpbroadcastd        m12, [base+subpel_filters+mxq*8+4]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m1, [base+subpel_filters+1+myq*8]
+    mov                 nsq, ssq
+    punpcklbw            m0, m1
+    neg                 nsq
+    psraw                m0, 2 ; << 6
+    pshufd              m13, m0, q0000
+    pshufd              m14, m0, q1111
+    pshufd              m15, m0, q2222
+    cmp                  wd, 8
+    jne .hv_w16
+    movu                xm0, [srcq+nsq*2]
+    vinserti32x4        ym0, [srcq+nsq*1], 1
+    vbroadcasti32x4      m1, [subpel_h_shufA]
+    vinserti32x4         m0, [srcq+ssq*0], 2
+    vbroadcasti32x4      m4, [subpel_h_shufB]
+    vinserti32x4         m0, [srcq+ssq*1], 3
+    lea                srcq, [srcq+ssq*2]
+    vbroadcasti32x4      m7, [subpel_h_shufC]
+    vbroadcasti32x4     ym5, [srcq+ssq*0]
+    vbroadcasti32x8      m6, [subpel_h_shufA]
+    pshufb               m1, m0, m1   ; 0 1 2 3    0123
+    mova                 m2, m9
+    vpdpbusd             m2, m1, m11
+    pshufb               m4, m0, m4   ; 0 1 2 3    4567
+    mova                 m1, m9
+    vpdpbusd             m1, m4, m11
+    pshufb               m0, m7       ; 0 1 2 3    89ab
+    pshufb              ym7, ym5, ym6 ; 4     0123 4567
+    mova                ym3, ym9
+    vpdpbusd            ym3, ym7, ym11
+    vbroadcasti32x8      m7, [subpel_h_shufB]
+    vpdpbusd             m2, m4, m12
+    mova                 m4, [spel_hv_perm8a]
+    pshufb              ym5, ym7      ; 4     4567 89ab
+    vpdpbusd             m1, m0, m12
+    vpaddd               m0, m4, [pb_32] {1to16}
+    vpdpbusd            ym3, ym5, ym12
+    mova                 m5, [spel_hv_perm8b]
+    mov                  r6, 0x55555555ff00
+    packssdw             m2, m1
+    vpmovsdw            xm3, ym3
+    kmovq                k1, r6
+    psraw                m2, 2        ; 0 1 2 3
+    psraw               xm3, 2        ; 4
+    vpermb               m1, m4, m2   ; 01 12
+    kshiftrq             k2, k1, 16
+    vpermt2b             m2, m0, m3   ; 23 34
+.hv_w8_loop:
+    vbroadcasti32x4     ym3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vbroadcasti32x4  m3{k1}, [srcq+ssq*0]
+    pmaddwd              m0, m1, m13  ; a0 b0
+    pshufb               m1, m3, m6   ; 5 6   0123 4567
+    mova                 m4, m9
+    vpdpbusd             m4, m1, m11
+    pshufb               m3, m7       ; 5 6   4567 89ab
+    vpdpwssd             m0, m2, m14  ; a1 b1
+    mova                 m1, m2
+    vpdpbusd             m4, m3, m12
+    psraw            m2{k2}, m4, 2    ; 53 64
+    vpermb               m2, m5, m2   ; 45 56
+    vpdpwssd             m0, m2, m15  ; a2 b2
+    packuswb             m0, m0
+    vpermb               m0, m10, m0
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w16:
+    movu                m19, [spel_hv_perm16a]
+    vpbroadcastd         m7, [pb_4]
+    lea                 r6d, [wq*2-32]
+    mova                 m6, [spel_hv_perm16b]
+    paddb               m20, m7, m19
+    lea                 r6d, [hq+r6*8]
+    paddb               m21, m7, m20
+    mova               ym10, [spel_hv_end16]
+    paddb                m7, m6
+.hv_w16_loop0:
+    movu               ym16, [srcq+nsq*2]
+    vinserti32x8        m16, [srcq+nsq*1], 1
+    lea                  r4, [srcq+ssq*2]
+    movu               ym17, [srcq+ssq*0]
+    vinserti32x8        m17, [srcq+ssq*1], 1
+    mov                  r7, dstq
+    movu               ym18, [r4  +ssq*0]
+    vpermb               m2, m19, m16    ; 0 1   0123   89ab
+    mova                 m1, m9
+    vpermb               m3, m21, m16    ; 0 1   89ab   ghij
+    vpdpbusd             m1, m2, m11
+    mova                 m2, m9
+    vpermb               m4, m19, m17    ; 2 3   0123   89ab
+    vpdpbusd             m2, m3, m12
+    mova                 m3, m9
+    vpermb               m5, m21, m17    ; 2 3   89ab   ghij
+    vpdpbusd             m3, m4, m11
+    mova                 m4, m9
+    vpermb               m0, m6, m18     ; 4     0145   2367   89cd   abef
+    vpdpbusd             m4, m5, m12
+    mova                 m5, m9
+    vpermb              m16, m20, m16    ; 0 1   4567   cdef
+    vpdpbusd             m5, m0, m11
+    vpermb              m17, m20, m17    ; 2 3   4567   cdef
+    vpdpbusd             m1, m16, m12
+    vpermb              m18, m7, m18     ; 4     4589   67ab   cdgh   efij
+    vpdpbusd             m2, m16, m11
+    vpdpbusd             m3, m17, m12
+    vpdpbusd             m4, m17, m11
+    vpdpbusd             m5, m18, m12
+    packssdw             m1, m2          ; 01
+    packssdw             m3, m4          ; 23
+    REPX       {psraw x, 2}, m1, m3, m5
+    vpshrdd              m2, m1, m3, 16  ; 12
+    vpshrdd              m4, m3, m5, 16  ; 34
+.hv_w16_loop:
+    movu               ym18, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+    vinserti32x8        m18, [r4+ssq*0], 1
+    pmaddwd             m16, m1, m13     ; a0
+    vpermb               m1, m19, m18    ; 5 6   0123   89ab
+    pmaddwd             m17, m2, m13     ; b0
+    vpermb               m2, m20, m18    ; 5 6   4567   cdef
+    mova                 m0, m9
+    vpdpbusd             m0, m1, m11
+    vpermb              m18, m21, m18
+    mova                 m1, m9
+    vpdpbusd             m1, m2, m11
+    vpdpwssd            m16, m3, m14    ; a1
+    vpdpwssd            m17, m4, m14    ; b1
+    vpdpbusd             m0, m2, m12
+    mova                 m2, m4
+    vpdpbusd             m1, m18, m12
+    packssdw             m0, m1
+    mova                 m1, m3
+    psraw                m4, m0, 2      ; 5 6
+    vpshrdd              m3, m2, m4, 16 ; 4 5
+    vpdpwssd            m17, m4, m15    ; b2
+    vpdpwssd            m16, m3, m15    ; a2
+    packuswb            m16, m17
+    vpermb              m16, m10, m16
+    mova         [r7+dsq*0], xm16
+    vextracti128 [r7+dsq*1], ym16, 1
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .hv_w16_loop0
+    vzeroupper
+    RET
+
+PUT_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_8bpc
+PUT_8TAP_FN regular_sharp,  REGULAR, SHARP,   put_8tap_8bpc
+PUT_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal put_8tap_8bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    lea                  r8, [put_avx512icl]
+    movsxd               wq, wm
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _put_6tap_8bpc_avx512icl).put
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    tzcnt               r6d, wd
+    lea                 myq, [base+subpel_filters+myq*8]
+    movzx               r6d, word [r8+r6*2+table_offset(put, _8tap_v)]
+    vpbroadcastd         m7, [pw_512]
+    vpbroadcastw         m8, [myq+0]
+    add                  r6, r8
+    vpbroadcastw         m9, [myq+2]
+    lea                ss3q, [ssq*3]
+    vpbroadcastw        m10, [myq+4]
+    sub                srcq, ss3q
+    vpbroadcastw        m11, [myq+6]
+    jmp                  r6
+.v_w2:
+    movd               xmm2, [srcq+ssq*0]
+    pinsrw             xmm2, [srcq+ssq*1], 2
+    pinsrw             xmm2, [srcq+ssq*2], 4
+    add                srcq, ss3q
+    pinsrw             xmm2, [srcq+ssq*0], 6  ; 0 1 2 3
+    movd               xmm3, [srcq+ssq*1]
+    vpbroadcastd       xmm1, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm3, xmm3, xmm1, 0x02 ; 4 5
+    vpblendd           xmm1, xmm1, xmm0, 0x02 ; 5 6
+    palignr            xmm4, xmm3, xmm2, 4    ; 1 2 3 4
+    punpcklbw          xmm3, xmm1             ; 45 56
+    punpcklbw          xmm1, xmm2, xmm4       ; 01 12
+    punpckhbw          xmm2, xmm4             ; 23 34
+.v_w2_loop:
+    pmaddubsw          xmm5, xmm1, xm8        ; a0 b0
+    mova               xmm1, xmm2
+    pmaddubsw          xmm2, xm9              ; a1 b1
+    paddw              xmm5, xmm2
+    mova               xmm2, xmm3
+    pmaddubsw          xmm3, xm10             ; a2 b2
+    paddw              xmm5, xmm3
+    vpbroadcastd       xmm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vpblendd           xmm3, xmm0, xmm4, 0x02 ; 6 7
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm4, xmm4, xmm0, 0x02 ; 7 8
+    punpcklbw          xmm3, xmm4             ; 67 78
+    pmaddubsw          xmm4, xmm3, xm11       ; a3 b3
+    paddw              xmm5, xmm4
+    pmulhrsw           xmm5, xm7
+    packuswb           xmm5, xmm5
+    pextrw     [dstq+dsq*0], xmm5, 0
+    pextrw     [dstq+dsq*1], xmm5, 2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movd               xmm2, [srcq+ssq*0]
+    pinsrd             xmm2, [srcq+ssq*1], 1
+    pinsrd             xmm2, [srcq+ssq*2], 2
+    add                srcq, ss3q
+    pinsrd             xmm2, [srcq+ssq*0], 3  ; 0 1 2 3
+    movd               xmm3, [srcq+ssq*1]
+    vpbroadcastd       xmm1, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm3, xmm3, xmm1, 0x02 ; 4 5
+    vpblendd           xmm1, xmm1, xmm0, 0x02 ; 5 6
+    palignr            xmm4, xmm3, xmm2, 4    ; 1 2 3 4
+    punpcklbw          xmm3, xmm1             ; 45 56
+    punpcklbw          xmm1, xmm2, xmm4       ; 01 12
+    punpckhbw          xmm2, xmm4             ; 23 34
+.v_w4_loop:
+    vpbroadcastd       xmm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw          xmm5, xmm1, xm8        ; a0 b0
+    mova               xmm1, xmm2
+    pmaddubsw          xmm2, xm9              ; a1 b1
+    paddw              xmm5, xmm2
+    mova               xmm2, xmm3
+    pmaddubsw          xmm3, xm10             ; a2 b2
+    paddw              xmm5, xmm3
+    vpblendd           xmm3, xmm0, xmm4, 0x02 ; 6 7
+    vpbroadcastd       xmm0, [srcq+ssq*0]
+    vpblendd           xmm4, xmm4, xmm0, 0x02 ; 7 8
+    punpcklbw          xmm3, xmm4             ; 67 78
+    pmaddubsw          xmm4, xmm3, xm11       ; a3 b3
+    paddw              xmm5, xmm4
+    pmulhrsw           xmm5, xm7
+    packuswb           xmm5, xmm5
+    movd       [dstq+dsq*0], xmm5
+    pextrd     [dstq+dsq*1], xmm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq               xmm1, [srcq+ssq*0]
+    vpbroadcastq       ymm0, [srcq+ssq*1]
+    vpbroadcastq       ymm2, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastq       ymm5, [srcq+ssq*0]
+    vpbroadcastq       ymm3, [srcq+ssq*1]
+    vpbroadcastq       ymm4, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpblendd           ymm1, ymm0, 0x30
+    vpblendd           ymm0, ymm2, 0x30
+    punpcklbw          ymm1, ymm0 ; 01 12
+    vpbroadcastq       ymm0, [srcq+ssq*0]
+    vpblendd           ymm2, ymm5, 0x30
+    vpblendd           ymm5, ymm3, 0x30
+    punpcklbw          ymm2, ymm5 ; 23 34
+    vpblendd           ymm3, ymm4, 0x30
+    vpblendd           ymm4, ymm0, 0x30
+    punpcklbw          ymm3, ymm4 ; 45 56
+.v_w8_loop:
+    vpbroadcastq       ymm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw          ymm5, ymm1, ym8  ; a0 b0
+    mova               ymm1, ymm2
+    pmaddubsw          ymm2, ym9        ; a1 b1
+    paddw              ymm5, ymm2
+    mova               ymm2, ymm3
+    pmaddubsw          ymm3, ym10       ; a2 b2
+    paddw              ymm5, ymm3
+    vpblendd           ymm3, ymm0, ymm4, 0x30
+    vpbroadcastq       ymm0, [srcq+ssq*0]
+    vpblendd           ymm4, ymm4, ymm0, 0x30
+    punpcklbw          ymm3, ymm4       ; 67 78
+    pmaddubsw          ymm4, ymm3, ym11 ; a3 b3
+    paddw              ymm5, ymm4
+    pmulhrsw           ymm5, ym7
+    vextracti128       xmm4, ymm5, 1
+    packuswb           xmm5, xmm4
+    movq       [dstq+dsq*0], xmm5
+    movhps     [dstq+dsq*1], xmm5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    vzeroupper
+    RET
+.v_w16:
+    mova                m12, [spel_v_perm16a]
+    vbroadcasti32x4      m1, [srcq+ssq*0]
+    vbroadcasti32x4     ym4, [srcq+ssq*1]
+    mov                 r6d, 0x0f
+    vbroadcasti32x4      m2, [srcq+ssq*2]
+    add                srcq, ss3q
+    vbroadcasti32x4     ym5, [srcq+ssq*0]
+    kmovb                k1, r6d
+    vbroadcasti32x4      m3, [srcq+ssq*1]
+    vbroadcasti32x4     ym6, [srcq+ssq*2]
+    add                srcq, ss3q
+    vbroadcasti32x4      m0, [srcq+ssq*0]
+    vshufpd          m1{k1}, m4, m2, 0xcc
+    vshufpd          m2{k1}, m5, m3, 0xcc
+    vshufpd          m3{k1}, m6, m0, 0xcc
+    vpermb               m1, m12, m1 ; 01 12
+    vpermb               m2, m12, m2 ; 23 34
+    vpermb               m3, m12, m3 ; 45 56
+.v_w16_loop:
+    pmaddubsw            m4, m1, m8  ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m5, m2, m9  ; a1 b1
+    mova                 m2, m3
+    pmaddubsw            m6, m3, m10 ; a2 b2
+    mova                 m3, m0
+    paddw                m4, m5
+    vbroadcasti32x4     ym5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vbroadcasti32x4      m0, [srcq+ssq*0]
+    vshufpd          m3{k1}, m5, m0, 0xcc
+    vpermb               m3, m12, m3 ; 67 78
+    pmaddubsw            m5, m3, m11 ; a3 b3
+    paddw                m4, m6
+    paddw                m4, m5
+    pmulhrsw             m4, m7
+    vextracti32x8       ym5, m4, 1
+    packuswb            ym4, ym5
+    mova          [dstq+dsq*0], xm4
+    vextracti32x4 [dstq+dsq*1], ym4, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w16_loop
+    RET
+.v_w32:
+    mova                m12, [spel_v_perm32]
+    pmovzxbq            m14, [pb_02461357]
+    vpshrdw             m13, m12, m12, 8
+    movu                ym0, [srcq+ssq*0]
+    vinserti32x8         m0, [srcq+ssq*1], 1
+    vpermb               m1, m12, m0 ; 01
+    vinserti32x8         m0, [srcq+ssq*2], 0
+    add                srcq, ss3q
+    vpermb               m2, m13, m0 ; 12
+    vinserti32x8         m0, [srcq+ssq*0], 1
+    vpermb               m3, m12, m0 ; 23
+    vinserti32x8         m0, [srcq+ssq*1], 0
+    vpermb               m4, m13, m0 ; 34
+    vinserti32x8         m0, [srcq+ssq*2], 1
+    add                srcq, ss3q
+    vpermb               m5, m12, m0 ; 45
+    vinserti32x8         m0, [srcq+ssq*0], 0
+    vpermb               m6, m13, m0 ; 56
+.v_w32_loop:
+    vinserti32x8         m0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw           m15, m1, m8
+    mova                 m1, m3
+    pmaddubsw           m16, m2, m8
+    mova                 m2, m4
+    pmaddubsw           m17, m3, m9
+    mova                 m3, m5
+    pmaddubsw           m18, m4, m9
+    mova                 m4, m6
+    pmaddubsw           m19, m5, m10
+    vpermb               m5, m12, m0 ; 67
+    vinserti32x8         m0, [srcq+ssq*0], 0
+    pmaddubsw           m20, m6, m10
+    vpermb               m6, m13, m0 ; 78
+    paddw               m15, m17
+    pmaddubsw           m17, m5, m11
+    paddw               m16, m18
+    pmaddubsw           m18, m6, m11
+    paddw               m15, m19
+    paddw               m16, m20
+    paddw               m15, m17
+    paddw               m16, m18
+    pmulhrsw            m15, m7
+    pmulhrsw            m16, m7
+    packuswb            m15, m16
+    vpermq              m15, m14, m15
+    mova          [dstq+dsq*0], ym15
+    vextracti32x8 [dstq+dsq*1], m15, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w32_loop
+    vzeroupper
+    RET
+.v_w64:
+.v_w128:
+    lea                 r6d, [hq+wq*4-256]
+    mov                  r4, srcq
+    mov                  r7, dstq
+.v_loop0:
+    movu                 m2, [srcq+ssq*0]
+    movu                 m4, [srcq+ssq*1]
+    movu                 m6, [srcq+ssq*2]
+    add                srcq, ss3q
+    movu                m13, [srcq+ssq*0]
+    movu                m15, [srcq+ssq*1]
+    movu                m17, [srcq+ssq*2]
+    add                srcq, ss3q
+    movu                 m0, [srcq+ssq*0]
+    punpcklbw            m1, m2, m4    ; 01l
+    punpckhbw            m2, m4        ; 01h
+    punpcklbw            m3, m4, m6    ; 12l
+    punpckhbw            m4, m6        ; 12h
+    punpcklbw            m5, m6, m13   ; 23l
+    punpckhbw            m6, m13       ; 23h
+    punpcklbw           m12, m13, m15  ; 34l
+    punpckhbw           m13, m15       ; 34h
+    punpcklbw           m14, m15, m17  ; 45l
+    punpckhbw           m15, m17       ; 45h
+    punpcklbw           m16, m17, m0   ; 56l
+    punpckhbw           m17, m0        ; 56h
+.v_loop:
+    pmaddubsw           m18, m1, m8    ; a0l
+    mova                 m1, m5
+    pmaddubsw           m19, m2, m8    ; a0h
+    mova                 m2, m6
+    pmaddubsw           m20, m3, m8    ; b0l
+    mova                 m3, m12
+    pmaddubsw           m21, m4, m8    ; b0h
+    mova                 m4, m13
+    pmaddubsw            m5, m9        ; a1l
+    pmaddubsw            m6, m9        ; a1h
+    pmaddubsw           m12, m9        ; b1l
+    pmaddubsw           m13, m9        ; b1h
+    paddw               m18, m5
+    mova                 m5, m14
+    pmaddubsw           m14, m10       ; a2l
+    paddw               m19, m6
+    mova                 m6, m15
+    pmaddubsw           m15, m10       ; a2h
+    paddw               m20, m12
+    mova                m12, m16
+    pmaddubsw           m16, m10       ; b2l
+    paddw               m21, m13
+    mova                m13, m17
+    pmaddubsw           m17, m10       ; b2h
+    paddw               m18, m14
+    paddw               m19, m15
+    paddw               m20, m16
+    paddw               m21, m17
+    movu                m17, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklbw           m14, m0, m17  ; 67l
+    punpckhbw           m15, m0, m17  ; 67h
+    pmaddubsw           m16, m14, m11 ; a3l
+    pmaddubsw            m0, m15, m11 ; a3h
+    paddw               m18, m16
+    paddw               m19, m0
+    movu                 m0, [srcq+ssq*0]
+    punpcklbw           m16, m17, m0  ; 78l
+    punpckhbw           m17, m0       ; 78h
+    pmulhrsw            m18, m7
+    pmulhrsw            m19, m7
+    packuswb            m18, m19
+    mova       [dstq+dsq*0], m18
+    pmaddubsw           m18, m16, m11 ; b3l
+    pmaddubsw           m19, m17, m11 ; b3h
+    paddw               m18, m20
+    paddw               m19, m21
+    pmulhrsw            m18, m7
+    pmulhrsw            m19, m7
+    packuswb            m18, m19
+    mova       [dstq+dsq*1], m18
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_loop
+    add                  r4, 64
+    add                  r7, 64
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+    sub                 r6d, 256
+    jg .v_loop0
+    vzeroupper
+    RET
+.h:
+    test                myd, 0xf00
+    jnz .hv
+.h2:
+    vpbroadcastd         m5, [pd_34] ; 2 + (8 << 2)
+    cmp                  wd, 4
+    jl .h_w2
+    vbroadcasti128       m6, [subpel_h_shufA]
+    je .h_w4
+    tzcnt                wd, wd
+    vbroadcasti128       m7, [subpel_h_shufB]
+    vbroadcasti128       m8, [subpel_h_shufC]
+    shr                 mxd, 16
+    sub                srcq, 3
+    movzx                wd, word [r8+wq*2+table_offset(put, _8tap_h)]
+    vpbroadcastd         m9, [base+mxq*8+subpel_filters+0]
+    vpbroadcastd        m10, [base+mxq*8+subpel_filters+4]
+    add                  wq, r8
+    jmp                  wq
+.h_w2:
+    movzx               mxd, mxb
+    dec                srcq
+    mova               xmm4, [subpel_h_shuf4]
+    vpbroadcastd       xmm3, [base+mxq*8+subpel_filters+2]
+.h_w2_loop:
+    movq               xmm0, [srcq+ssq*0]
+    movhps             xmm0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb             xmm0, xmm4
+    mova               xmm1, xm5
+    vpdpbusd           xmm1, xmm0, xmm3
+    packssdw           xmm0, xmm1, xmm1
+    psraw              xmm0, 6
+    packuswb           xmm0, xm0
+    pextrw     [dstq+dsq*0], xmm0, 0
+    pextrw     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2_loop
+    RET
+.h_w4:
+    movzx               mxd, mxb
+    dec                srcq
+    vpbroadcastd       xmm3, [base+mxq*8+subpel_filters+2]
+.h_w4_loop:
+    movq               xmm0, [srcq+ssq*0]
+    movq               xmm1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb             xmm0, xm6
+    pshufb             xmm1, xm6
+    mova               xmm2, xm5
+    vpdpbusd           xmm2, xmm0, xmm3
+    mova               xmm0, xm5
+    vpdpbusd           xmm0, xmm1, xmm3
+    packssdw           xmm0, xmm2, xmm0
+    psraw              xmm0, 6
+    packuswb           xmm0, xmm0
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h_w8:
+    movu                xm0, [srcq+ssq*0]
+    vinserti32x4        ym0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    WRAP_YMM PUT_8TAP_H   0, 1, 2, 3
+    vpmovuswb           xm0, ym0
+    movq       [dstq+dsq*0], xm0
+    movhps     [dstq+dsq*1], xm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    mova                 m6, [spel_h_perm16]
+    vpbroadcastd         m8, [pb_4]
+    paddb                m7, m8, m6
+    paddb                m8, m7
+.h_w16_loop:
+    movu                ym0, [srcq+ssq*0]
+    vinserti32x8         m0, [srcq+ssq*1], 1
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_H            0, 1, 2, 3, 1
+    vpmovuswb           ym0, m0
+    mova         [dstq+dsq*0], xm0
+    vextracti128 [dstq+dsq*1], ym0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w16_loop
+    RET
+.h_w32:
+    movu                ym0, [srcq+ssq*0+8*0]
+    vinserti32x8         m0, [srcq+ssq*1+8*0], 1
+    movu                ym1, [srcq+ssq*0+8*1]
+    vinserti32x8         m1, [srcq+ssq*1+8*1], 1
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_H            0, 2, 3, 4
+    PUT_8TAP_H            1, 4, 3, 2
+    packuswb             m0, m1
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w32
+    RET
+.h_w64:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    add                srcq, ssq
+    PUT_8TAP_H            0, 2, 3, 4
+    PUT_8TAP_H            1, 4, 3, 2
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w64
+    RET
+.h_w128:
+    movu                 m0, [srcq+8*0]
+    movu                 m2, [srcq+8*1]
+    movu                 m1, [srcq+8*8]
+    movu                 m3, [srcq+8*9]
+    add                srcq, ssq
+    PUT_8TAP_H            0,  4, 11, 12
+    PUT_8TAP_H            2, 12, 11,  4
+    PUT_8TAP_H            1,  4, 11, 12
+    PUT_8TAP_H            3, 12, 11,  4
+    packuswb             m0, m2
+    packuswb             m1, m3
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w128
+    RET
+.hv:
+    vpbroadcastd         m9, [pd_34]
+    pxor                xm0, xm0
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    dec                srcq
+    vpbroadcastd         m7, [base+subpel_filters+mxq*8+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq        ym1, [base+subpel_filters+myq*8]
+    lea                ss3q, [ssq*3]
+    mov                  r6, srcq
+    punpcklbw           ym0, ym1
+    sub                  r6, ss3q
+    psraw               ym0, 2 ; << 6
+    mova               xm14, [spel_hv_end]
+    pshufd             ym10, ym0, q0000
+    pshufd             ym11, ym0, q1111
+    pshufd             ym12, ym0, q2222
+    pshufd             ym13, ym0, q3333
+    cmp                  wd, 4
+    je .hv_w4
+    vbroadcasti128      ym6, [subpel_h_shuf4]
+    movq               xmm2, [r6+ssq*0]
+    movhps             xmm2, [r6+ssq*1]
+    movq               xmm0, [r6+ssq*2]
+    movhps             xmm0, [srcq+ssq*0]
+    vpbroadcastq       ymm3, [srcq+ssq*1]
+    vpbroadcastq       ymm4, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastq       ymm1, [srcq+ssq*0]
+    vpblendd           ymm2, ymm3, 0x30
+    vpblendd           ymm0, ymm1, 0x30 ; 2 3   6 _
+    vpblendd           ymm2, ymm4, 0xc0 ; 0 1   4 5
+    pshufb             ymm2, ym6
+    pshufb             ymm0, ym6
+    mova               ymm1, ym9
+    vpdpbusd           ymm1, ymm2, ym7
+    mova               ymm2, ym9
+    vpdpbusd           ymm2, ymm0, ym7
+    packssdw           ymm2, ymm1, ymm2
+    psraw              ymm2, 2
+    vextracti128       xmm3, ymm2, 1
+    palignr            xmm4, xmm3, xmm2, 4
+    punpcklwd          xmm1, xmm2, xmm4 ; 01 12
+    punpckhwd          xmm2, xmm4       ; 23 34
+    pshufd             xmm0, xmm3, q2121
+    punpcklwd          xmm3, xmm0       ; 45 56
+.hv_w2_loop:
+    movq               xmm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps             xmm4, [srcq+ssq*0]
+    pmaddwd            xmm5, xmm1, xm10 ; a0 b0
+    mova               xmm1, xmm2
+    vpdpwssd           xmm5, xmm2, xm11 ; a1 b1
+    pshufb             xmm4, xm6
+    mova               xmm2, xmm3
+    vpdpwssd           xmm5, xmm3, xm12 ; a2 b2
+    mova               xmm3, xm9
+    vpdpbusd           xmm3, xmm4, xm7
+    packssdw           xmm4, xmm3, xmm3
+    psraw              xmm4, 2
+    palignr            xmm3, xmm4, xmm0, 12
+    mova               xmm0, xmm4
+    punpcklwd          xmm3, xmm4       ; 67 78
+    vpdpwssd           xmm5, xmm3, xm13 ; a3 b3
+    packuswb           xmm5, xmm5
+    pshufb             xmm5, xm14
+    pextrw     [dstq+dsq*0], xmm5, 0
+    pextrw     [dstq+dsq*1], xmm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    vzeroupper
+    RET
+.hv_w4:
+    movq               xmm1, [r6+ssq*0]
+    vpbroadcastq        ym2, [r6+ssq*1]
+    vinserti32x4        ym1, ymm1, [r6+ssq*2], 1
+    vinserti32x4         m2, [srcq+ssq*0], 2
+    vinserti32x4         m1, [srcq+ssq*1], 2
+    vinserti32x4         m2, [srcq+ssq*2], 3 ; _ 1 3 5
+    vbroadcasti32x4      m6, [subpel_h_shufA]
+    add                srcq, ss3q
+    vinserti32x4         m1, [srcq+ssq*0], 3 ; 0 2 4 6
+    pshufb               m2, m6
+    pshufb               m1, m6
+    mova                 m0, m9
+    vpdpbusd             m0, m2, m7
+    mova                 m4, m9
+    vpdpbusd             m4, m1, m7
+    mova                ym1, [spel_hv_perm4a]
+    mova                ym2, [spel_hv_perm4b]
+    mova                ym3, [spel_hv_perm4c]
+    packssdw             m0, m4
+    psraw                m0, 2 ; _ 0   1 2   3 4   5 6
+    mov                 r6d, 0x5555
+    vpermb              ym1, ym1, ym0 ; 01 12
+    vpermb               m2, m2, m0   ; 23 34
+    vpermb               m3, m3, m0   ; 45 56
+    kmovw                k1, r6d
+    mova               ym15, [spel_hv_perm4d]
+.hv_w4_loop:
+    movq               xmm4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x4        ym4, ymm4, [srcq+ssq*0], 1
+    pmaddwd             ym5, ym1, ym10 ; a0 b0
+    mova                ym1, ym2
+    pshufb              ym4, ym6
+    mova                ym0, ym9
+    vpdpbusd            ym0, ym4, ym7
+    vpdpwssd            ym5, ym2, ym11 ; a1 b1
+    mova                ym2, ym3
+    vpdpwssd            ym5, ym3, ym12 ; a2 b2
+    vpsraw          ym3{k1}, ym0, 2    ; 7 8
+    vpermb              ym3, ym15, ym3 ; 67 78
+    vpdpwssd            ym5, ym3, ym13 ; a3 b3
+    packuswb            ym5, ym5
+    vpermb              ym5, ym14, ym5
+    movd       [dstq+dsq*0], xm5
+    pextrd     [dstq+dsq*1], xm5, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    sub                srcq, 3
+    vpbroadcastd        m10, [base+subpel_filters+mxq*8+0]
+    vpbroadcastd        m11, [base+subpel_filters+mxq*8+4]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    vpbroadcastq         m1, [base+subpel_filters+myq*8]
+    punpcklbw            m0, m1
+    lea                ss3q, [ssq*3]
+    psraw                m0, 2 ; << 6
+    pshufd              m12, m0, q0000
+    pshufd              m13, m0, q1111
+    pshufd              m14, m0, q2222
+    pshufd              m15, m0, q3333
+    cmp                  wd, 8
+    jne .hv_w16
+    mov                  r6, srcq
+    sub                  r6, ss3q
+    movu               xmm1, [r6+ssq*0]
+    vinserti128        ymm1, [r6+ssq*1], 1
+    movu               xmm2, [srcq+ssq*1]
+    vinserti32x4         m6, zmm1, [r6+ssq*2], 2
+    vinserti128        ymm2, [srcq+ssq*2], 1
+    vinserti32x4         m6, [srcq+ssq*0], 3 ; 0 1 2 3
+    add                srcq, ss3q
+    vbroadcasti32x4      m4, [subpel_h_shufA]
+    vinserti32x4         m0, zmm2, [srcq+ssq*0], 2 ; 4 5 6 _
+    vbroadcasti32x4      m7, [subpel_h_shufB]
+    vbroadcasti32x4      m8, [subpel_h_shufC]
+    pshufb               m1, m6, m4  ; 0 1 2 3   0123
+    mova                 m2, m9
+    vpdpbusd             m2, m1, m10
+    pshufb               m5, m6, m7  ; 0 1 2 3   4567
+    mova                 m1, m9
+    vpdpbusd             m1, m5, m10
+    pshufb               m4, m0, m4  ; 4 5 6 _   0123
+    mova                 m3, m9
+    vpdpbusd             m3, m4, m10
+    pshufb               m7, m0, m7  ; 4 5 6 _   4567
+    mova                 m4, m9
+    vpdpbusd             m4, m7, m10
+    pshufb               m6, m8
+    vpdpbusd             m2, m5, m11
+    vpdpbusd             m1, m6, m11
+    pshufb               m6, m0, m8
+    vpdpbusd             m3, m7, m11
+    vpdpbusd             m4, m6, m11
+    mova                 m5, [spel_hv_perm8a]
+    vpaddd               m0, m5, [pb_32] {1to16}
+    mov                  r6, 0x55555555ff00
+    packssdw             m2, m1
+    packssdw             m3, m4
+    mova                 m8, [spel_hv_perm8b]
+    psraw                m2, 2 ; 0 1 2 3
+    psraw                m3, 2 ; 4 5 6 _
+    vpermb               m1, m5, m2 ; 01 12
+    vbroadcasti32x8      m6, [subpel_h_shufA]
+    kmovq                k1, r6
+    vpermt2b             m2, m0, m3 ; 23 34
+    vbroadcasti32x8      m7, [subpel_h_shufB]
+    kshiftrq             k2, k1, 16
+    mova               xm16, [spel_hv_end]
+    vpermb               m3, m5, m3 ; 45 56
+.hv_w8_loop:
+    vbroadcasti32x4     ym4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    vbroadcasti32x4  m4{k1}, [srcq+ssq*0]
+    pmaddwd              m0, m1, m12 ; a0 b0
+    pshufb               m1, m4, m6  ; 7 8   0123 4567
+    mova                 m5, m9
+    vpdpbusd             m5, m1, m10
+    pshufb               m4, m7      ; 7 8   4567 89ab
+    vpdpwssd             m0, m2, m13 ; a1 b1
+    mova                 m1, m2
+    vpdpbusd             m5, m4, m11
+    mova                 m2, m3
+    vpdpwssd             m0, m3, m14 ; a2 b2
+    psraw            m3{k2}, m5, 2   ; 75 86
+    vpermb               m3, m8, m3  ; 67 78
+    vpdpwssd             m0, m3, m15 ; a3 b3
+    packuswb             m0, m0
+    vpermb             zmm1, m16, m0
+    movq       [dstq+dsq*0], xmm1
+    movhps     [dstq+dsq*1], xmm1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    vzeroupper
+    RET
+.hv_w16:
+    WIN64_SPILL_XMM      23
+    movu                m22, [spel_hv_perm16a]
+    sub                srcq, ss3q
+    vpbroadcastd         m8, [pb_4]
+    lea                 r6d, [wq*2-32]
+    mova                 m7, [spel_hv_perm16b]
+    paddb               m20, m8, m22
+    mova               ym16, [spel_hv_end16]
+    paddb               m21, m8, m20
+    lea                 r6d, [hq+r6*8]
+    paddb                m8, m7
+.hv_w16_loop0:
+    movu               ym17, [srcq+ssq*0]
+    vinserti32x8        m17, [srcq+ssq*1], 1 ; 0 1
+    lea                  r4, [srcq+ss3q]
+    movu               ym18, [srcq+ssq*2]
+    vinserti32x8        m18, [r4  +ssq*0], 1 ; 2 3
+    mov                  r7, dstq
+    movu               ym19, [r4  +ssq*1]
+    vinserti32x8        m19, [r4  +ssq*2], 1 ; 4 5
+    add                  r4, ss3q
+    vpermb               m2, m22, m17    ; 0 1   0123   89ab
+    mova                 m1, m9
+    vpermb               m3, m21, m17    ; 0 1   89ab   ghij
+    vpdpbusd             m1, m2, m10
+    mova                 m2, m9
+    vpermb               m4, m22, m18    ; 2 3   0123   89ab
+    vpdpbusd             m2, m3, m11
+    mova                 m3, m9
+    vpermb               m5, m21, m18    ; 2 3   89ab   ghij
+    vpdpbusd             m3, m4, m10
+    mova                 m4, m9
+    vpermb               m6, m22, m19    ; 4 5   0123   89ab
+    vpdpbusd             m4, m5, m11
+    mova                 m5, m9
+    vpermb              m17, m20, m17    ; 0 1   4567   cdef
+    vpdpbusd             m5, m6, m10
+    mova                 m6, m9
+    vpermb               m0, m21, m19    ; 4 5   89ab   ghij
+    vpdpbusd             m1, m17, m11
+    vpdpbusd             m2, m17, m10
+    movu               ym17, [r4+ssq*0]  ; 6
+    vpermb              m18, m20, m18    ; 2 3   4567   cdef
+    vpdpbusd             m6, m0, m11
+    vpermb               m0, m7, m17     ; 6     0145   2367   89cd   abef
+    vpdpbusd             m3, m18, m11
+    vpermb              m19, m20, m19    ; 4 5   4567   cdef
+    vpdpbusd             m4, m18, m10
+    mova                m18, m9
+    vpermb              m17, m8, m17     ; 6     4589   67ab   cdgh   efij
+    vpdpbusd            m18, m0, m10
+    packssdw             m1, m2
+    vpdpbusd             m5, m19, m11
+    vpdpbusd             m6, m19, m10
+    packssdw             m3, m4
+    vpdpbusd            m18, m17, m11
+    psraw                m1, 2           ; 01
+    psraw                m3, 2           ; 23
+    packssdw             m5, m6
+    vpshrdd              m2, m1, m3, 16  ; 12
+    psraw                m5, 2           ; 45
+    vpshrdd              m4, m3, m5, 16  ; 34
+    psraw               m18, 2
+    vpshrdd              m6, m5, m18, 16 ; 56
+.hv_w16_loop:
+    movu               ym19, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+    vinserti32x8        m19, [r4+ssq*0], 1
+    pmaddwd             m17, m1, m12     ; a0
+    vpermb               m1, m22, m19    ; 7 8   0123   89ab
+    pmaddwd             m18, m2, m12     ; b0
+    mova                 m0, m9
+    vpermb               m2, m21, m19    ; 7 8   89ab   ghij
+    vpdpbusd             m0, m1, m10
+    mova                 m1, m9
+    vpermb              m19, m20, m19    ; 7 8   4567   cdef
+    vpdpbusd             m1, m2, m11
+    mova                 m2, m4
+    vpdpwssd            m17, m3, m13     ; a1
+    vpdpwssd            m18, m4, m13     ; b1
+    mova                 m4, m6
+    vpdpbusd             m0, m19, m11
+    vpdpbusd             m1, m19, m10
+    vpdpwssd            m17, m5, m14     ; a2
+    vpdpwssd            m18, m6, m14     ; b2
+    packssdw             m0, m1
+    mova                 m1, m3
+    psraw                m6, m0, 2       ; 78
+    mova                 m3, m5
+    vpshrdd              m5, m4, m6, 16  ; 67
+    vpdpwssd            m18, m6, m15     ; b3
+    vpdpwssd            m17, m5, m15     ; a3
+    packuswb            m17, m18
+    vpermb              m17, m16, m17
+    mova         [r7+dsq*0], xm17
+    vextracti128 [r7+dsq*1], ym17, 1
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    add                srcq, 16
+    add                dstq, 16
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .hv_w16_loop0
+    RET
+
+%if WIN64
+DECLARE_REG_TMP 6, 4
+%else
+DECLARE_REG_TMP 6, 7
+%endif
+
+%define PREP_8TAP_FN FN prep_8tap,
+PREP_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  prep_6tap_8bpc
+PREP_8TAP_FN sharp_regular,  SHARP,   REGULAR, prep_6tap_8bpc
+PREP_8TAP_FN smooth,         SMOOTH,  SMOOTH,  prep_6tap_8bpc
+PREP_8TAP_FN smooth_regular, SMOOTH,  REGULAR, prep_6tap_8bpc
+PREP_8TAP_FN regular_smooth, REGULAR, SMOOTH,  prep_6tap_8bpc
+PREP_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal prep_6tap_8bpc, 4, 8, 0, tmp, src, ss, w, h, mx, my, ss3
+%define base r7-prep_avx512icl
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 6tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 6tap_v, my, 4tap_v
+    lea                  r7, [prep_avx512icl]
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.prep:
+    tzcnt                wd, wd
+    movzx                wd, word [r7+wq*2+table_offset(prep,)]
+    add                  wq, r7
+    lea                  r6, [ssq*3]
+%if WIN64
+    pop                  r7
+%endif
+    jmp                  wq
+.v:
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    tzcnt               r5d, wd
+    lea                 myq, [base+subpel_filters+1+myq*8]
+    movzx               r5d, word [r7+r5*2+table_offset(prep, _6tap_v)]
+    vpbroadcastd         m7, [pw_8192]
+    sub                srcq, ssq
+    vpbroadcastw         m8, [myq+0]
+    add                  r5, r7
+    vpbroadcastw         m9, [myq+2]
+    lea                ss3q, [ssq*3]
+    vpbroadcastw        m10, [myq+4]
+    sub                srcq, ssq
+    jmp                  r5
+.v_w4:
+    movd               xmm2, [srcq+ssq*0]
+    pinsrd             xmm2, [srcq+ssq*1], 1
+    vpbroadcastd       ymm1, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastd       ymm3, [srcq+ssq*0]
+    vpbroadcastd       ymm0, [srcq+ssq*1]
+    vbroadcasti128     ymm5, [deint_shuf4]
+    vpblendd           ymm1, ymm2, 0xeb
+    punpcklqdq         ymm3, ymm0
+    vpblendd           ymm1, ymm3, 0x60 ; 0 1 2 _   2 3 4 _
+    pshufb             ymm1, ymm5       ; 01 12 23 34
+.v_w4_loop:
+    pinsrd             xmm0, [srcq+ssq*2], 1
+    vpbroadcastd       ymm2, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    vpbroadcastd       ymm3, [srcq+ssq*0]
+    vpblendd           ymm2, ymm0, 0xeb
+    vpbroadcastd       ymm0, [srcq+ssq*1]
+    punpcklqdq         ymm3, ymm0
+    vpblendd           ymm2, ymm3, 0x60 ; 4 5 6 _   6 7 8 _
+    pshufb             ymm2, ymm5       ; 45 56 67 78
+    pmaddubsw          ymm3, ymm1, ym8  ; a0 b0 c0 d0
+    vperm2i128         ymm1, ymm2, 0x21 ; 23 34 45 56
+    pmaddubsw          ymm4, ymm2, ym10 ; a2 b2 c2 d2
+    pmaddubsw          ymm1, ym9        ; a1 b1 c1 d1
+    paddw              ymm3, ymm4
+    paddw              ymm3, ymm1
+    pmulhrsw           ymm3, ym7
+    mova               ymm1, ymm2
+    mova             [tmpq], ymm3
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    vzeroupper
+    RET
+.v_w8:
+    mova                 m6, [spel_v_perm8]
+    movq                xm1, [srcq+ssq*0]
+    mov                 r6d, 0x3e
+    movq                xm2, [srcq+ssq*1]
+    kmovb                k1, r6d
+    vpbroadcastq        ym3, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpunpcklqdq         ym2, [srcq+ssq*0] {1to4}
+    vpunpcklqdq      m1{k1}, m3, [srcq+ssq*1] {1to8}
+    movq                xm0, [srcq+ssq*1]
+    kshiftlb             k2, k1, 2
+    shufpd               m1, m2, 0x18  ; 0 1   2 3   4
+    vpermb               m1, m6, m1    ; 01 12 23 34
+.v_w8_loop:
+    vpbroadcastq        ym3, [srcq+ss3q ]
+    vpunpcklqdq     ym0{k1}, ym3, [srcq+ssq*2] {1to4}
+    lea                srcq, [srcq+ssq*4]
+    vpbroadcastq         m3, [srcq+ssq*1]
+    vpunpcklqdq      m0{k2}, m3, [srcq+ssq*0] {1to8}
+    pmaddubsw            m4, m1, m8    ; a0 b0 c0 d0
+    vpermb               m2, m6, m0    ; 45 56 67 78
+    mova                xm0, xm3
+    vshufi32x4           m1, m2, q1032 ; 23 34 45 56
+    pmaddubsw            m3, m2, m10   ; a3 b3 c3 d3
+    pmaddubsw            m5, m1, m9    ; a2 b2 c2 d2
+    mova                 m1, m2
+    paddw                m4, m3
+    paddw                m4, m5
+    pmulhrsw             m4, m7
+    mova             [tmpq], m4
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    mova                m11, [spel_v_perm16b]
+    vbroadcasti32x4      m1, [srcq+ssq*0]
+    mov                 r6d, 0x0f
+    vbroadcasti32x4     ym3, [srcq+ssq*1]
+    vbroadcasti32x4      m2, [srcq+ssq*2]
+    kmovb                k1, r6d
+    add                srcq, ss3q
+    vbroadcasti32x4     ym4, [srcq+ssq*0]
+    vbroadcasti32x4      m0, [srcq+ssq*1]
+    vshufpd          m1{k1}, m3, m2, 0xcc
+    vshufpd          m2{k1}, m4, m0, 0xcc
+    vpermb               m1, m11, m1 ; 01 12
+    vpermb               m2, m11, m2 ; 23 34
+.v_w16_loop:
+    pmaddubsw            m3, m1, m8  ; a0 b0
+    pmaddubsw            m5, m2, m9  ; a1 b1
+    vbroadcasti32x4     ym6, [srcq+ssq*2]
+    pmaddubsw            m4, m2, m8  ; c0 d0
+    vbroadcasti32x4      m2, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    vshufpd          m0{k1}, m6, m2, 0xcc
+    vbroadcasti32x4     ym6, [srcq+ssq*0]
+    vpermb               m1, m11, m0 ; 45 56
+    vbroadcasti32x4      m0, [srcq+ssq*1]
+    vshufpd          m2{k1}, m6, m0, 0xcc
+    pmaddubsw            m6, m1, m9  ; c1 d1
+    vpermb               m2, m11, m2 ; 67 78
+    paddw                m3, m5
+    pmaddubsw            m5, m1, m10 ; a2 b2
+    paddw                m4, m6
+    pmaddubsw            m6, m2, m10 ; c2 d2
+    paddw                m3, m5
+    paddw                m4, m6
+    pmulhrsw             m3, m7
+    pmulhrsw             m4, m7
+    mova          [tmpq+ 0], m3
+    mova          [tmpq+64], m4
+    add                tmpq, 64*2
+    sub                  hd, 4
+    jg .v_w16_loop
+    RET
+.v_w32:
+    movshdup             m6, [bilin_v_perm64]
+    movu               ym16, [srcq+ssq*0]
+    movu               ym17, [srcq+ssq*1]
+    movu               ym18, [srcq+ssq*2]
+    add                srcq, ss3q
+    movu               ym19, [srcq+ssq*0]
+    add                srcq, ssq
+    movu               ym20, [srcq+ssq*0]
+    vpermt2q            m16, m6, m18   ; 0 2
+    vpermt2q            m17, m6, m19   ; 1 3
+    vpermt2q            m18, m6, m20   ; 2 4
+    punpcklbw            m0, m16, m17  ; 01
+    punpcklbw            m1, m17, m18  ; 12
+    punpckhbw            m2, m16, m17  ; 23
+    punpckhbw            m3, m17, m18  ; 34
+.v_w32_loop:
+    movu               ym16, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movu               ym17, [srcq+ssq*0]
+    pmaddubsw            m4, m0, m8    ; a0
+    mova                 m0, m2
+    pmaddubsw            m2, m9        ; a1
+    vpermt2q            m16, m6, m17   ; 5 6
+    pmaddubsw            m5, m1, m8    ; b0
+    mova                 m1, m3
+    pmaddubsw            m3, m9        ; b1
+    shufpd              m18, m16, 0x55 ; 4 5
+    paddw                m4, m2
+    punpcklbw            m2, m18, m16  ; 45
+    paddw                m5, m3
+    punpckhbw            m3, m18, m16  ; 56
+    mova                m18, m16
+    pmaddubsw           m16, m2, m10   ; a2
+    pmaddubsw           m17, m3, m10   ; b2
+    paddw                m4, m16
+    paddw                m5, m17
+    pmulhrsw             m4, m7
+    pmulhrsw             m5, m7
+    mova          [tmpq+ 0], m4
+    mova          [tmpq+64], m5
+    add                tmpq, 64*2
+    sub                  hd, 2
+    jg .v_w32_loop
+    vzeroupper
+    RET
+.v_w64:
+.v_w128:
+    mova                 m6, [bilin_v_perm64]
+    add                  wd, wd
+    lea                 r6d, [hq+wq]
+.v_loop0:
+    vpermq              m12, m6, [srcq+ssq*0]
+    vpermq              m13, m6, [srcq+ssq*1]
+    lea                  r5, [srcq+ssq*2]
+    vpermq              m14, m6, [r5  +ssq*0]
+    vpermq              m15, m6, [r5  +ssq*1]
+    lea                  r5, [r5+ssq*2]
+    vpermq              m16, m6, [r5  +ssq*0]
+    mov                  r7, tmpq
+    punpcklbw            m0, m12, m13 ; 01
+    punpckhbw           m12, m13
+    punpcklbw            m1, m13, m14 ; 12
+    punpckhbw           m13, m14
+    punpcklbw            m2, m14, m15 ; 23
+    punpckhbw           m14, m15
+    punpcklbw            m3, m15, m16 ; 34
+    punpckhbw           m15, m16
+.v_loop:
+    pmaddubsw           m17, m0, m8   ; a0
+    vpermq               m5, m6, [r5+ssq*1]
+    pmaddubsw           m18, m12, m8
+    mova                 m0, m2
+    pmaddubsw            m2, m9       ; a1
+    mova                m12, m14
+    pmaddubsw           m14, m9
+    lea                  r5, [r5+ssq*2]
+    pmaddubsw           m19, m1, m8   ; b0
+    pmaddubsw           m20, m13, m8
+    mova                 m1, m3
+    pmaddubsw            m3, m9       ; b1
+    mova                m13, m15
+    pmaddubsw           m15, m9
+    paddw               m17, m2
+    punpcklbw            m2, m16, m5  ; 67
+    paddw               m18, m14
+    punpckhbw           m14, m16, m5
+    vpermq              m16, m6, [r5+ssq*0]
+    paddw               m19, m3
+    pmaddubsw            m3, m2, m10  ; a3
+    paddw               m20, m15
+    pmaddubsw           m15, m14, m10
+    paddw               m17, m3
+    punpcklbw            m3, m5, m16  ; 78
+    pmaddubsw            m4, m3, m10  ; b3
+    paddw               m18, m15
+    punpckhbw           m15, m5, m16
+    pmaddubsw            m5, m15, m10
+    paddw               m19, m4
+    paddw               m20, m5
+    REPX   {pmulhrsw x, m7}, m17, m18, m19, m20
+    mova       [r7+wq*0+ 0], m17
+    mova       [r7+wq*0+64], m18
+    mova       [r7+wq*1+ 0], m19
+    mova       [r7+wq*1+64], m20
+    lea                  r7, [r7+wq*2]
+    sub                  hd, 2
+    jg .v_loop
+    add                srcq, 64
+    add                tmpq, 128
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_loop0
+    vzeroupper
+    RET
+.h:
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _prep_8tap_8bpc_avx512icl).h2
+.hv:
+    vpbroadcastd         m8, [pd_2]
+    vpbroadcastd         m9, [pd_32]
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    vpbroadcastd        m11, [base+subpel_filters+mxq*8+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m3, [base+subpel_filters+1+myq*8]
+    vbroadcasti128      m10, [subpel_h_shufA]
+    lea                  r6, [ssq*2+1]
+    mov                 r3d, 0x30
+    sub                srcq, r6
+    kmovb                k1, r3d
+    vpbroadcastq        ym2, [srcq+ssq*0]
+    lea                ss3q, [ssq*3]
+    vpbroadcastq         m1, [srcq+ssq*1]
+    kaddb                k2, k1, k1
+    vpbroadcastq     m2{k1}, [srcq+ssq*2]
+    add                srcq, ss3q
+    vpbroadcastq     m1{k2}, [srcq+ssq*0] ; _ _ 1 3
+    punpcklbw            m3, m3
+    vpbroadcastq     m2{k2}, [srcq+ssq*1] ; _ 0 2 4
+    psraw                m3, 8 ; sign-extend
+    mova                 m6, [spel_hv_perm4a]
+    kshiftrb             k1, k1, 2
+    movu                 m7, [spel_hv_perm4b]
+    pshufb               m1, m10
+    mova                 m0, m8
+    vpdpbusd             m0, m1, m11
+    pshufb               m2, m10
+    mova                 m1, m8
+    vpdpbusd             m1, m2, m11
+    pshufd              m12, m3, q0000
+    pshufd              m13, m3, q1111
+    pshufd              m14, m3, q2222
+    packssdw             m0, m1           ; _ _   _ 0   1 2   3 4
+    psraw                m0, 2
+    vpermb               m1, m7, m0       ; 01 12 23 34
+.hv_w4_loop:
+    movq                xm3, [srcq+ssq*2]
+    movq                xm4, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    vpbroadcastq    ym3{k1}, [srcq+ssq*0] ; 5 7
+    vpbroadcastq    ym4{k1}, [srcq+ssq*1] ; 6 8
+    pshufb              ym3, ym10
+    mova                ym2, ym8
+    vpdpbusd            ym2, ym3, ym11
+    pshufb              ym4, ym10
+    mova                ym3, ym8
+    vpdpbusd            ym3, ym4, ym11
+    mova                 m4, m9
+    vpdpwssd             m4, m1, m12      ; a0 b0 c0 d0
+    packssdw            ym2, ym3          ; 5 6   7 8
+    psraw               ym2, 2
+    vshufi32x4           m0, m2, q1032    ; _ 2   3 4   5 6   7 8
+    vpermb               m2, m6, m0       ; 23 34 45 56
+    vpermb               m1, m7, m0       ; 45 56 67 78
+    vpdpwssd             m4, m2, m13      ; a1 b1 c1 d1
+    vpdpwssd             m4, m1, m14      ; a2 b2 c2 d2
+    psrad                m4, 6
+    vpmovdw          [tmpq], m4
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    vpbroadcastd        m10, [base+subpel_filters+mxq*8+0]
+    vpbroadcastd        m11, [base+subpel_filters+mxq*8+4]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m0, [base+subpel_filters+1+myq*8]
+    lea                  r6, [ssq*2+3]
+    punpcklbw            m0, m0
+    sub                srcq, r6
+    psraw                m0, 8 ; sign-extend
+    lea                ss3q, [ssq*3]
+    pshufd              m12, m0, q0000
+    pshufd              m13, m0, q1111
+    pshufd              m14, m0, q2222
+    cmp                  wd, 8
+    jg .hv_w16
+    movu               xm16, [srcq+ssq*0]
+    vbroadcasti32x4     m19, [subpel_h_shufA]
+    vinserti128        ym16, [srcq+ssq*1], 1
+    vbroadcasti32x4     m21, [subpel_h_shufC]
+    vinserti32x4        m16, [srcq+ssq*2], 2
+    add                srcq, ss3q
+    vinserti32x4        m16, [srcq+ssq*0], 3
+    movu               xm17, [srcq+ssq*1]
+    vbroadcasti32x4     m20, [subpel_h_shufB]
+    pshufb               m3, m16, m19   ; 0 1 2 3   0123
+    mova                 m2, m8
+    pshufb               m0, m16, m21   ; 0 1 2 3   89ab
+    vpdpbusd             m2, m3, m10
+    mova                 m3, m8
+    pshufb              xm1, xm17, xm19 ; 3 4 5 6   0123
+    vpdpbusd             m3, m0, m11
+    mova                xm0, xm8
+    pshufb             xm18, xm17, xm21 ; 3 4 5 6   89ab
+    vpdpbusd            xm0, xm1, xm10
+    mova                xm1, xm8
+    pshufb              m16, m20        ; 0 1 2 3   4567
+    vpdpbusd            xm1, xm18, xm11
+    pshufb             xm17, xm20       ; 3 4 5 6   4567
+    vpdpbusd             m2, m16, m11
+    vpdpbusd             m3, m16, m10
+    vpdpbusd            xm0, xm17, xm11
+    vpdpbusd            xm1, xm17, xm10
+    packssdw             m2, m3
+    packssdw            xm0, xm1
+    psraw                m2, 2          ; 0 1 2 3
+    psraw               xm0, 2          ; 4
+    valignq              m0, m2, 2      ; 1 2 3 4
+    punpcklwd            m1, m2, m0     ; 01 12 23 34
+    punpckhwd            m2, m0
+.hv_w8_loop:
+    movu               xm16, [srcq+ssq*2]
+    vinserti128        ym16, [srcq+ss3q ], 1
+    lea                srcq, [srcq+ssq*4]
+    vinserti32x4        m16, [srcq+ssq*0], 2
+    vinserti32x4        m16, [srcq+ssq*1], 3
+    pshufb               m6, m16, m19   ; 5 6 7 8   0123
+    mova                 m5, m8
+    pshufb               m3, m16, m21   ; 5 6 7 8   89ab
+    vpdpbusd             m5, m6, m10
+    mova                 m6, m8
+    pshufb              m16, m20        ; 5 6 7 8   4567
+    vpdpbusd             m6, m3, m11
+    mova                 m3, m9
+    vpdpwssd             m3, m1, m12    ; a0 b0 c0 d0
+    mova                 m4, m9
+    vpdpwssd             m4, m2, m12
+    vpdpbusd             m5, m16, m11
+    vpdpbusd             m6, m16, m10
+    mova                m16, m1
+    packssdw             m5, m6
+    mova                 m6, m2
+    psraw                m5, 2          ; 5 6 7 8
+    valignq              m2, m5, m0, 6  ; 4 5 6 7
+    mova                 m0, m5
+    punpcklwd            m1, m2, m5     ; 45 56 67 78
+    punpckhwd            m2, m5
+    vpdpwssd             m3, m1, m14    ; a2 b2 c2 d2
+    vpdpwssd             m4, m2, m14
+    vshufi32x4          m16, m1, q1032  ; 23 34 45 56
+    vshufi32x4           m6, m2, q1032
+    vpdpwssd             m3, m16, m13   ; a1 b1 c1 d1
+    vpdpwssd             m4, m6, m13
+    psrad                m3, 6
+    psrad                m4, 6
+    packssdw             m3, m4
+    mova             [tmpq], m3
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .hv_w8_loop
+    vzeroupper
+    RET
+.hv_w16:
+    mova                m16, [spel_h_perm16]
+    vpbroadcastd        m18, [pb_4]
+    add                  wd, wd
+    paddb               m17, m18, m16
+    lea                 r6d, [hq+wq*8-256]
+    paddb               m18, m17
+.hv_w16_loop0:
+    movu               ym19, [srcq+ssq*0]
+    vinserti32x8        m19, [srcq+ssq*1], 1
+    lea                  r5, [srcq+ssq*2]
+    movu               ym20, [r5  +ssq*0]
+    vinserti32x8        m20, [r5  +ssq*1], 1
+    lea                  r5, [r5  +ssq*2]
+    movu               ym21, [r5  +ssq*0]
+    mov                  r7, tmpq
+    vpermb               m3, m16, m19      ; 0 1   0123   89ab
+    mova                 m2, m8
+    vpermb               m4, m18, m19      ; 0 1   89ab   ghij
+    vpdpbusd             m2, m3, m10
+    mova                 m3, m8
+    vpermb               m5, m16, m20      ; 2 3   0123   89ab
+    vpdpbusd             m3, m4, m11
+    mova                 m4, m8
+    vpermb               m0, m18, m20      ; 2 3   89ab   ghij
+    vpdpbusd             m4, m5, m10
+    mova                 m5, m8
+    vpermb              ym1, ym16, ym21    ; 4     0123   89ab
+    vpdpbusd             m5, m0, m11
+    mova                ym0, ym8
+    vpermb              ym6, ym18, ym21    ; 4     89ab   ghij
+    vpdpbusd            ym0, ym1, ym10
+    mova                ym1, ym8
+    vpermb              m19, m17, m19      ; 0 1   4567   cdef
+    vpdpbusd            ym1, ym6, ym11
+    vpermb              m20, m17, m20      ; 2 3   4567   cdef
+    vpdpbusd             m2, m19, m11
+    vpdpbusd             m3, m19, m10
+    vpermb             ym21, ym17, ym21    ; 4     4567   cdef
+    vpdpbusd             m4, m20, m11
+    vpdpbusd             m5, m20, m10
+    vpdpbusd            ym0, ym21, ym11
+    vpdpbusd            ym1, ym21, ym10
+    packssdw             m2, m3            ; 0 1
+    packssdw             m4, m5            ; 2 3
+    packssdw            ym0, ym1           ; 4
+    REPX       {psraw x, 2}, m2, m4, ym0
+    vshufi32x4           m3, m2, m4, q1032 ; 1 2
+    vshufi32x4           m0, m4, m0, q1032 ; 3 4
+    punpcklwd            m1, m2, m3        ; 01 12
+    punpckhwd            m2, m3
+    punpcklwd            m3, m4, m0        ; 23 34
+    punpckhwd            m4, m0
+.hv_w16_loop:
+    movu               ym19, [r5+ssq*1]
+    lea                  r5, [r5+ssq*2]
+    vinserti32x8        m19, [r5+ssq*0], 1
+    vpermb               m6, m16, m19      ; 5 6   0123   89ab
+    mova                 m5, m8
+    vpermb              m20, m18, m19      ; 5 6   89ab   ghij
+    vpdpbusd             m5, m6, m10
+    mova                 m6, m8
+    vpermb              m19, m17, m19      ; 5 6   4567   cdef
+    vpdpbusd             m6, m20, m11
+    mova                m20, m9
+    vpdpwssd            m20, m1, m12       ; a0 b0
+    mova                m21, m9
+    vpdpwssd            m21, m2, m12
+    vpdpbusd             m5, m19, m11
+    vpdpbusd             m6, m19, m10
+    vpdpwssd            m20, m3, m13       ; a1 b1
+    vpdpwssd            m21, m4, m13
+    packssdw             m5, m6
+    mova                 m1, m3
+    psraw                m5, 2             ; 5 6
+    mova                 m2, m4
+    vshufi32x4           m4, m0, m5, q1032 ; 4 5
+    mova                 m0, m5
+    punpcklwd            m3, m4, m0        ; 45 56
+    punpckhwd            m4, m0
+    vpdpwssd            m20, m3, m14       ; a2 b2
+    vpdpwssd            m21, m4, m14
+    psrad               m20, 6
+    psrad               m21, 6
+    packssdw            m20, m21
+    mova          [r7+wq*0], ym20
+    vextracti32x8 [r7+wq*1], m20, 1
+    lea                  r7, [r7+wq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    add                srcq, 16
+    add                tmpq, 32
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .hv_w16_loop0
+    vzeroupper
+    RET
+
+%macro PREP_8TAP_H 0
+    vpermb              m10, m5, m0
+    vpermb              m11, m5, m1
+    vpermb              m12, m6, m0
+    vpermb              m13, m6, m1
+    vpermb              m14, m7, m0
+    vpermb              m15, m7, m1
+    mova                 m0, m4
+    vpdpbusd             m0, m10, m8
+    mova                 m2, m4
+    vpdpbusd             m2, m12, m8
+    mova                 m1, m4
+    vpdpbusd             m1, m11, m8
+    mova                 m3, m4
+    vpdpbusd             m3, m13, m8
+    vpdpbusd             m0, m12, m9
+    vpdpbusd             m2, m14, m9
+    vpdpbusd             m1, m13, m9
+    vpdpbusd             m3, m15, m9
+    packssdw             m0, m2
+    packssdw             m1, m3
+    psraw                m0, 2
+    psraw                m1, 2
+    mova        [tmpq+64*0], m0
+    mova        [tmpq+64*1], m1
+%endmacro
+
+PREP_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_8bpc
+PREP_8TAP_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_8bpc
+PREP_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal prep_8tap_8bpc, 4, 8, 0, tmp, src, stride, w, h, mx, my, stride3
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    lea                  r7, [prep_avx512icl]
+    movifnidn            hd, hm
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _prep_6tap_8bpc_avx512icl).prep
+.v:
+    movzx               mxd, myb ; Select 4-tap/8-tap filter multipliers.
+    shr                 myd, 16  ; Note that the code is 8-tap only, having
+    cmp                  hd, 4   ; a separate 4-tap code path for (4|8|16)x4
+    cmove               myd, mxd ; had a negligible effect on performance.
+    tzcnt               r5d, wd
+    lea                 myq, [base+subpel_filters+myq*8]
+    movzx               r5d, word [r7+r5*2+table_offset(prep, _8tap_v)]
+    vpbroadcastd         m7, [pw_8192]
+    vpbroadcastw         m8, [myq+0]
+    add                  r5, r7
+    vpbroadcastw         m9, [myq+2]
+    lea            stride3q, [strideq*3]
+    vpbroadcastw        m10, [myq+4]
+    sub                srcq, stride3q
+    vpbroadcastw        m11, [myq+6]
+    jmp                  r5
+.v_w4:
+    movd               xmm0, [srcq+strideq*0]
+    vpbroadcastd       ymm1, [srcq+strideq*2]
+    vpbroadcastd       xmm2, [srcq+strideq*1]
+    vpbroadcastd       ymm3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpblendd           ymm1, ymm0, 0x01       ; 0 2 2 _   2 _ _ _
+    vpblendd           ymm3, ymm2, 0x03       ; 1 1 3 3   3 3 _ _
+    vpbroadcastd       ymm0, [srcq+strideq*0]
+    vpbroadcastd       ymm2, [srcq+strideq*1]
+    vpblendd           ymm1, ymm0, 0x68       ; 0 2 2 4   2 4 4 _
+    vpbroadcastd       ymm0, [srcq+strideq*2]
+    vbroadcasti128     ymm5, [deint_shuf4]
+    vpblendd           ymm3, ymm2, 0xc0       ; 1 1 3 3   3 3 5 5
+    vpblendd           ymm2, ymm3, ymm1, 0x55 ; 0 1 2 3   2 3 4 5
+    vpblendd           ymm3, ymm1, 0xaa       ; 1 2 3 4   3 4 5 _
+    punpcklbw          ymm1, ymm2, ymm3       ; 01  12    23  34
+    vpblendd           ymm3, ymm0, 0x80       ; 1 2 3 4   3 4 5 6
+    punpckhbw          ymm2, ymm3             ; 23  34    45  56
+.v_w4_loop:
+    pinsrd             xmm0, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastd       ymm3, [srcq+strideq*0]
+    vpbroadcastd       ymm4, [srcq+strideq*1]
+    vpblendd           ymm3, ymm4, 0x20       ; _ _ 8 _   8 9 _ _
+    vpblendd           ymm3, ymm0, 0x03       ; 6 7 8 _   8 9 _ _
+    vpbroadcastd       ymm0, [srcq+strideq*2]
+    vpblendd           ymm3, ymm0, 0x40       ; 6 7 8 _   8 9 a _
+    pshufb             ymm3, ymm5             ; 67  78    89  9a
+    pmaddubsw          ymm4, ymm1, ym8
+    vperm2i128         ymm1, ymm2, ymm3, 0x21 ; 45  56    67  78
+    pmaddubsw          ymm2, ym9
+    paddw              ymm4, ymm2
+    mova               ymm2, ymm3
+    pmaddubsw          ymm3, ym11
+    paddw              ymm3, ymm4
+    pmaddubsw          ymm4, ymm1, ym10
+    paddw              ymm3, ymm4
+    pmulhrsw           ymm3, ym7
+    mova             [tmpq], ymm3
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .v_w4_loop
+    vzeroupper
+    RET
+.v_w8:
+    mova                 m6, [spel_v_perm8]
+    movq                xm1, [srcq+strideq*0]
+    mov                 r6d, 0x3e
+    movq                xm2, [srcq+strideq*1]
+    vpbroadcastq        ym3, [srcq+strideq*2]
+    kmovb                k1, r6d
+    vpbroadcastq        ym4, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpunpcklqdq      m1{k1}, m3, [srcq+strideq*0] {1to8}
+    vpunpcklqdq      m2{k1}, m4, [srcq+strideq*1] {1to8}
+    movq                xm0, [srcq+strideq*2]
+    kshiftlb             k2, k1, 2
+    shufpd               m1, m2, 0x30      ; 0 1   2 3   4 5
+    vshufi32x4           m2, m1, m0, q0021 ; 2 3   4 5   6 _
+    vpermb               m1, m6, m1        ; 01 12 23 34
+    vpermb               m2, m6, m2        ; 23 34 45 56
+.v_w8_loop:
+    vpbroadcastq        ym3, [srcq+strideq*4]
+    vpunpcklqdq     ym0{k1}, ym3, [srcq+stride3q] {1to4}
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastq         m3, [srcq+strideq*2]
+    vpunpcklqdq      m0{k2}, m3, [srcq+strideq*1] {1to8}
+    pmaddubsw            m4, m1, m8        ; a0 b0 c0 d0
+    mova                 m1, m2
+    pmaddubsw            m5, m2, m9        ; a1 b1 c1 d1
+    vpermb               m2, m6, m0        ; 67 78 89 9a
+    mova                xm0, xm3
+    vshufi32x4           m1, m2, q1032     ; 45 56 67 78
+    pmaddubsw            m3, m2, m11       ; a3 b3 c3 d3
+    paddw                m4, m5
+    pmaddubsw            m5, m1, m10       ; a2 b2 c2 d2
+    paddw                m4, m3
+    paddw                m4, m5
+    pmulhrsw             m4, m7
+    mova             [tmpq], m4
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    mova                m12, [spel_v_perm16b]
+    vbroadcasti32x4      m1, [srcq+strideq*0]
+    mov                 r6d, 0x0f
+    vbroadcasti32x4     ym4, [srcq+strideq*1]
+    vbroadcasti32x4      m2, [srcq+strideq*2]
+    kmovb                k1, r6d
+    vbroadcasti32x4     ym5, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vbroadcasti32x4      m3, [srcq+strideq*0]
+    vbroadcasti32x4     ym6, [srcq+strideq*1]
+    vbroadcasti32x4      m0, [srcq+strideq*2]
+    vshufpd          m1{k1}, m4, m2, 0xcc
+    vshufpd          m2{k1}, m5, m3, 0xcc
+    vshufpd          m3{k1}, m6, m0, 0xcc
+    vpermb               m1, m12, m1 ; 01 12
+    vpermb               m2, m12, m2 ; 23 34
+    vpermb               m3, m12, m3 ; 45 56
+.v_w16_loop:
+    pmaddubsw            m4, m1, m8  ; a0 b0
+    mova                 m1, m3
+    pmaddubsw           m13, m2, m9  ; a1 b1
+    vbroadcasti32x4     ym6, [srcq+stride3q ]
+    pmaddubsw            m5, m2, m8  ; c0 d0
+    lea                srcq, [srcq+strideq*4]
+    pmaddubsw           m14, m3, m9  ; c1 d1
+    vbroadcasti32x4      m3, [srcq+strideq*0]
+    vshufpd          m0{k1}, m6, m3, 0xcc
+    vbroadcasti32x4     ym6, [srcq+strideq*1]
+    vpermb               m2, m12, m0 ; 67 78
+    vbroadcasti32x4      m0, [srcq+strideq*2]
+    vshufpd          m3{k1}, m6, m0, 0xcc
+    paddw                m4, m13
+    pmaddubsw           m13, m1, m10 ; a2 b2
+    vpermb               m3, m12, m3 ; 89 9a
+    paddw                m5, m14
+    pmaddubsw           m14, m2, m10 ; c2 d2
+    pmaddubsw           m15, m2, m11 ; a3 b3
+    pmaddubsw            m6, m3, m11 ; c3 d3
+    paddw                m4, m13
+    paddw                m5, m14
+    paddw                m4, m15
+    paddw                m5, m6
+    pmulhrsw             m4, m7
+    pmulhrsw             m5, m7
+    mova          [tmpq+ 0], m4
+    mova          [tmpq+64], m5
+    add                tmpq, 64*2
+    sub                  hd, 4
+    jg .v_w16_loop
+    RET
+.v_w32:
+    movshdup            m21, [bilin_v_perm64]
+    movu               ym16, [srcq+strideq*0]
+    movu               ym17, [srcq+strideq*1]
+    movu               ym18, [srcq+strideq*2]
+    add                srcq, stride3q
+    movu               ym19, [srcq+strideq*0]
+    vpermt2q            m16, m21, m19  ; 0 3
+    movu               ym20, [srcq+strideq*1]
+    vpermt2q            m17, m21, m20  ; 1 4
+    movu               ym20, [srcq+strideq*2]
+    add                srcq, stride3q
+    vpermt2q            m18, m21, m20  ; 2 5
+    movu               ym20, [srcq+strideq*0]
+    vpermt2q            m19, m21, m20  ; 3 6
+    punpcklbw            m0, m16, m17  ; 01
+    punpcklbw            m1, m17, m18  ; 12
+    punpcklbw            m2, m18, m19  ; 23
+    punpckhbw            m3, m16, m17  ; 34
+    punpckhbw            m4, m17, m18  ; 45
+    punpckhbw            m5, m18, m19  ; 56
+.v_w32_loop:
+    movu               ym16, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    movu               ym17, [srcq+strideq*0]
+    pmaddubsw           m14, m0, m8
+    mova                 m0, m2
+    pmaddubsw           m15, m1, m8
+    mova                 m1, m3
+    pmaddubsw            m2, m9
+    vpermt2q            m16, m21, m17  ; 7 8
+    pmaddubsw            m3, m9
+    pmaddubsw           m12, m4, m10
+    pmaddubsw           m13, m5, m10
+    shufpd              m19, m16, 0x55 ; 6 7
+    paddw               m14, m2
+    mova                 m2, m4
+    punpcklbw            m4, m19, m16  ; 67
+    paddw               m15, m3
+    mova                 m3, m5
+    punpckhbw            m5, m19, m16  ; 78
+    paddw               m14, m12
+    paddw               m15, m13
+    pmaddubsw           m12, m4, m11
+    pmaddubsw           m13, m5, m11
+    mova                m19, m16
+    paddw               m14, m12
+    paddw               m15, m13
+    pmulhrsw            m14, m7
+    pmulhrsw            m15, m7
+    mova          [tmpq+ 0], m14
+    mova          [tmpq+64], m15
+    add                tmpq, 64*2
+    sub                  hd, 2
+    jg .v_w32_loop
+    vzeroupper
+    RET
+.v_w64:
+.v_w128:
+    WIN64_SPILL_XMM      24
+    mova                m23, [bilin_v_perm64]
+    add                  wd, wd
+    lea                 r6d, [hq+wq]
+.v_loop0:
+    vpermq              m12, m23, [srcq+strideq*0]
+    vpermq              m13, m23, [srcq+strideq*1]
+    lea                  r5, [srcq+strideq*2]
+    vpermq              m14, m23, [r5  +strideq*0]
+    vpermq              m15, m23, [r5  +strideq*1]
+    lea                  r5, [r5+strideq*2]
+    vpermq              m16, m23, [r5  +strideq*0]
+    vpermq              m17, m23, [r5  +strideq*1]
+    lea                  r5, [r5+strideq*2]
+    vpermq              m18, m23, [r5  +strideq*0]
+    mov                  r7, tmpq
+    punpcklbw            m0, m12, m13 ; 01
+    punpckhbw           m12, m13
+    punpcklbw            m1, m13, m14 ; 12
+    punpckhbw           m13, m14
+    punpcklbw            m2, m14, m15 ; 23
+    punpckhbw           m14, m15
+    punpcklbw            m3, m15, m16 ; 34
+    punpckhbw           m15, m16
+    punpcklbw            m4, m16, m17 ; 45
+    punpckhbw           m16, m17
+    punpcklbw            m5, m17, m18 ; 56
+    punpckhbw           m17, m18
+.v_loop:
+    pmaddubsw           m19, m0, m8   ; a0
+    vpermq               m6, m23, [r5+strideq*1]
+    pmaddubsw           m20, m12, m8
+    mova                 m0, m2
+    pmaddubsw            m2, m9       ; a1
+    mova                m12, m14
+    pmaddubsw           m14, m9
+    lea                  r5, [r5+strideq*2]
+    pmaddubsw           m21, m1, m8   ; b0
+    pmaddubsw           m22, m13, m8
+    mova                 m1, m3
+    pmaddubsw            m3, m9       ; b1
+    mova                m13, m15
+    pmaddubsw           m15, m9
+    paddw               m19, m2
+    mova                 m2, m4
+    pmaddubsw            m4, m10      ; a2
+    paddw               m20, m14
+    mova                m14, m16
+    pmaddubsw           m16, m10
+    paddw               m21, m3
+    mova                 m3, m5
+    pmaddubsw            m5, m10      ; b2
+    paddw               m22, m15
+    mova                m15, m17
+    pmaddubsw           m17, m10
+    paddw               m19, m4
+    punpcklbw            m4, m18, m6  ; 67
+    paddw               m20, m16
+    punpckhbw           m16, m18, m6
+    vpermq              m18, m23, [r5+strideq*0]
+    paddw               m21, m5
+    pmaddubsw            m5, m4, m11  ; a3
+    paddw               m22, m17
+    pmaddubsw           m17, m16, m11
+    paddw               m19, m5
+    punpcklbw            m5, m6, m18  ; 78
+    paddw               m20, m17
+    punpckhbw           m17, m6, m18
+    pmaddubsw            m6, m5, m11  ; b3
+    paddw               m21, m6
+    pmaddubsw            m6, m17, m11
+    paddw               m22, m6
+    REPX   {pmulhrsw x, m7}, m19, m20, m21, m22
+    mova       [r7+wq*0+ 0], m19
+    mova       [r7+wq*0+64], m20
+    mova       [r7+wq*1+ 0], m21
+    mova       [r7+wq*1+64], m22
+    lea                  r7, [r7+wq*2]
+    sub                  hd, 2
+    jg .v_loop
+    add                srcq, 64
+    add                tmpq, 128
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_loop0
+    RET
+.h:
+    RESET_STACK_STATE
+    test                myd, 0xf00
+    jnz .hv
+.h2:
+    vpbroadcastd         m4, [pd_2]
+    cmp                  wd, 4
+    je .h_w4
+    tzcnt                wd, wd
+    shr                 mxd, 16
+    sub                srcq, 3
+    movzx                wd, word [r7+wq*2+table_offset(prep, _8tap_h)]
+    vpbroadcastd         m8, [base+subpel_filters+mxq*8+0]
+    vpbroadcastd         m9, [base+subpel_filters+mxq*8+4]
+    add                  wq, r7
+    jmp                  wq
+.h_w4:
+    movzx               mxd, mxb
+    vbroadcasti128      ym5, [subpel_h_shufA]
+    mov                 r3d, 0x4
+    dec                srcq
+    vpbroadcastd        ym6, [base+subpel_filters+mxq*8+2]
+    kmovb                k1, r3d
+    lea            stride3q, [strideq*3]
+.h_w4_loop:
+    movq                xm2, [srcq+strideq*0]
+    movq                xm3, [srcq+strideq*1]
+    vpbroadcastq    ym2{k1}, [srcq+strideq*2]
+    vpbroadcastq    ym3{k1}, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    pshufb              ym2, ym5
+    pshufb              ym3, ym5
+    mova                ym0, ym4
+    vpdpbusd            ym0, ym2, ym6
+    mova                ym1, ym4
+    vpdpbusd            ym1, ym3, ym6
+    packssdw            ym0, ym1
+    psraw               ym0, 2
+    mova             [tmpq], ym0
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4_loop
+    RET
+.h_w8:
+    vbroadcasti128       m5, [subpel_h_shufA]
+    vbroadcasti128       m6, [subpel_h_shufB]
+    vbroadcasti128       m7, [subpel_h_shufC]
+    lea            stride3q, [strideq*3]
+.h_w8_loop:
+    movu               xmm3, [srcq+strideq*0]
+    vinserti128         ym3, ymm3, [srcq+strideq*1], 1
+    vinserti128          m3, [srcq+strideq*2], 2
+    vinserti128          m3, [srcq+stride3q ], 3
+    lea                srcq, [srcq+strideq*4]
+    pshufb               m1, m3, m5
+    pshufb               m2, m3, m6
+    mova                 m0, m4
+    vpdpbusd             m0, m1, m8
+    mova                 m1, m4
+    vpdpbusd             m1, m2, m8
+    pshufb               m3, m7
+    vpdpbusd             m0, m2, m9
+    vpdpbusd             m1, m3, m9
+    packssdw             m0, m1
+    psraw                m0, 2
+    mova             [tmpq], m0
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .h_w8_loop
+    RET
+.h_w16:
+    mova                 m5, [spel_h_perm16]
+    vpbroadcastd         m7, [pb_4]
+    lea            stride3q, [strideq*3]
+    paddb                m6, m7, m5
+    paddb                m7, m6
+.h_w16_loop:
+    movu                ym0, [srcq+strideq*0]
+    movu                ym1, [srcq+strideq*2]
+    vinserti32x8         m0, [srcq+strideq*1], 1
+    vinserti32x8         m1, [srcq+stride3q ], 1
+    lea                srcq, [srcq+strideq*4]
+    PREP_8TAP_H
+    add                tmpq, 64*2
+    sub                  hd, 4
+    jg .h_w16_loop
+    RET
+.h_w32:
+    mova                 m5, [spel_h_perm32]
+    vpbroadcastd         m7, [pb_4]
+    paddb                m6, m7, m5
+    paddb                m7, m6
+.h_w32_loop:
+    movu                 m0, [srcq+strideq*0]
+    movu                 m1, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    PREP_8TAP_H
+    add                tmpq, 64*2
+    sub                  hd, 2
+    jg .h_w32_loop
+    RET
+.h_w64:
+    xor                 r6d, r6d
+    jmp .h_start
+.h_w128:
+    mov                  r6, -64*1
+.h_start:
+    mova                 m5, [spel_h_perm32]
+    vpbroadcastd         m7, [pb_4]
+    sub                srcq, r6
+    paddb                m6, m7, m5
+    paddb                m7, m6
+.h_loop0:
+    mov                  r5, r6
+.h_loop:
+    movu                 m0, [srcq+r5+32*0]
+    movu                 m1, [srcq+r5+32*1]
+    PREP_8TAP_H
+    add                tmpq, 64*2
+    add                  r5, 64
+    jle .h_loop
+    add                srcq, strideq
+    dec                  hd
+    jg .h_loop0
+    RET
+.hv:
+    RESET_STACK_STATE
+    vpbroadcastd         m8, [pd_2]
+    vpbroadcastd         m9, [pd_32]
+    cmp                  wd, 4
+    jg .hv_w8
+    movzx               mxd, mxb
+    dec                srcq
+    vpbroadcastd        m11, [base+subpel_filters+mxq*8+2]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m0, [base+subpel_filters+myq*8]
+    lea            stride3q, [strideq*3]
+    sub                srcq, stride3q
+    mov                 r3d, 0x04
+    kmovb                k1, r3d
+    kshiftlb             k2, k1, 2
+    kshiftlb             k3, k1, 4
+    vbroadcasti128      m10, [subpel_h_shufA]
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    pshufd              m12, m0, q0000
+    pshufd              m13, m0, q1111
+    pshufd              m14, m0, q2222
+    pshufd              m15, m0, q3333
+    movq                xm3, [srcq+strideq*0]
+    vpbroadcastq        ym2, [srcq+strideq*1]
+    vpbroadcastq    ym3{k1}, [srcq+strideq*2]
+    vpbroadcastq     m2{k2}, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vpbroadcastq     m3{k2}, [srcq+strideq*0]
+    vpbroadcastq     m2{k3}, [srcq+strideq*1]
+    vpbroadcastq     m3{k3}, [srcq+strideq*2]
+    mova                 m6, [spel_hv_perm4a]
+    movu                 m7, [spel_hv_perm4b]
+    mova                 m0, m8
+    mova                 m1, m8
+    pshufb               m2, m10
+    pshufb               m3, m10
+    vpdpbusd             m0, m2, m11
+    vpdpbusd             m1, m3, m11
+    packssdw             m0, m1        ; _ 0  1 2  3 4  5 6
+    psraw                m0, 2
+    vpermb               m1, m6, m0    ; 01 12 23 34
+    vpermb               m2, m7, m0    ; 23 34 45 56
+.hv_w4_loop:
+    movq                xm3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    movq                xm4, [srcq+strideq*0]
+    vpbroadcastq    ym3{k1}, [srcq+strideq*1]
+    vpbroadcastq    ym4{k1}, [srcq+strideq*2]
+    mova                 m5, m9
+    pshufb              ym3, ym10
+    vpdpwssd             m5, m1, m12   ; a0 b0 c0 d0
+    mova                ym1, ym8
+    pshufb              ym4, ym10
+    vpdpbusd            ym1, ym3, ym11
+    mova                ym3, ym8
+    vpdpbusd            ym3, ym4, ym11
+    vpdpwssd             m5, m2, m13   ; a1 b1 c1 d1
+    packssdw            ym1, ym3       ; 7 8  9 a
+    psraw               ym1, 2
+    vshufi32x4           m0, m1, q1032 ; _ 4  5 6  7 8  9 a
+    vpermb               m1, m6, m0    ; 45 56 67 78
+    vpermb               m2, m7, m0    ; 67 78 89 9a
+    vpdpwssd             m5, m1, m14   ; a2 b2 c2 d2
+    vpdpwssd             m5, m2, m15   ; a3 b3 c3 d3
+    psrad                m5, 6
+    vpmovdw          [tmpq], m5
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    shr                 mxd, 16
+    sub                srcq, 3
+    vpbroadcastd        m10, [base+subpel_filters+mxq*8+0]
+    vpbroadcastd        m11, [base+subpel_filters+mxq*8+4]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 4
+    cmove               myd, mxd
+    vpbroadcastq         m0, [base+subpel_filters+myq*8]
+    lea            stride3q, [strideq*3]
+    sub                srcq, stride3q
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    pshufd              m12, m0, q0000
+    pshufd              m13, m0, q1111
+    pshufd              m14, m0, q2222
+    pshufd              m15, m0, q3333
+    cmp                  wd, 8
+    jg .hv_w16
+    vbroadcasti32x4     m17, [srcq+stride3q ]
+    vinserti32x4        m16, m17, [srcq+strideq*0], 0
+    vbroadcasti32x4     m19, [subpel_h_shufA]
+    vinserti32x4        m16, [srcq+strideq*1], 1
+    vbroadcasti32x4     m21, [subpel_h_shufC]
+    vinserti32x4        m16, [srcq+strideq*2], 2
+    lea                srcq, [srcq+strideq*4]
+    vinserti128        ym17, [srcq+strideq*0], 1
+    vbroadcasti32x4     m20, [subpel_h_shufB]
+    vinserti32x4        m17, [srcq+strideq*1], 2
+    vinserti32x4        m17, [srcq+strideq*2], 3
+    pshufb               m3, m16, m19      ; 0 1 2 3   0123
+    mova                 m2, m8
+    pshufb               m0, m16, m21      ; 0 1 2 3   89ab
+    vpdpbusd             m2, m3, m10
+    mova                 m3, m8
+    pshufb               m1, m17, m19      ; 3 4 5 6   0123
+    vpdpbusd             m3, m0, m11
+    mova                 m0, m8
+    pshufb               m4, m17, m21      ; 3 4 5 6   89ab
+    vpdpbusd             m0, m1, m10
+    mova                 m1, m8
+    pshufb              m16, m20           ; 0 1 2 3   4567
+    vpdpbusd             m1, m4, m11
+    pshufb              m17, m20           ; 3 4 5 6   4567
+    vpdpbusd             m2, m16, m11
+    vpdpbusd             m3, m16, m10
+    vpdpbusd             m0, m17, m11
+    vpdpbusd             m1, m17, m10
+    packssdw             m2, m3
+    packssdw             m0, m1
+    psraw                m2, 2             ; 0 1 2 3
+    psraw                m0, 2             ; 3 4 5 6
+    vshufi32x4           m4, m2, m0, q2132 ; 2 3 4 5
+    vshufi32x4           m5, m2, m0, q1021 ; 1 2 3 4
+    punpcklwd            m3, m4, m0        ; 23 34 45 56
+    punpckhwd            m4, m0
+    punpcklwd            m1, m2, m5        ; 01 12 23 34
+    punpckhwd            m2, m5
+.hv_w8_loop:
+    movu               xm18, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    vinserti128        ym18, [srcq+strideq*0], 1
+    vinserti32x4        m18, [srcq+strideq*1], 2
+    vinserti32x4        m18, [srcq+strideq*2], 3
+    pshufb              m17, m18, m19      ; 7 8 9 a   0123
+    mova                m16, m8
+    pshufb               m5, m18, m21      ; 7 8 9 a   89ab
+    vpdpbusd            m16, m17, m10
+    mova                m17, m8
+    pshufb              m18, m20           ; 7 8 9 a   4567
+    vpdpbusd            m17, m5, m11
+    mova                 m5, m9
+    vpdpwssd             m5, m3, m13       ; a1 b1 c1 d1
+    mova                 m6, m9
+    vpdpwssd             m6, m4, m13
+    vpdpbusd            m16, m18, m11
+    vpdpbusd            m17, m18, m10
+    vpdpwssd             m5, m1, m12       ; a0 b0 c0 d0
+    mova                 m1, m3
+    vpdpwssd             m6, m2, m12
+    mova                 m2, m4
+    packssdw            m16, m17
+    psraw               m16, 2             ; 7 8 9 a
+    valignq              m4, m16, m0, 6    ; 6 7 8 9
+    mova                 m0, m16
+    punpcklwd            m3, m4, m16       ; 67 78 89 9a
+    punpckhwd            m4, m16
+    vpdpwssd             m5, m3, m15       ; a3 b3 c3 d3
+    vpdpwssd             m6, m4, m15
+    vshufi32x4           m1, m3, q1032     ; 45 56 67 78
+    vshufi32x4           m2, m4, q1032
+    vpdpwssd             m5, m1, m14       ; a2 b2 c2 d2
+    vpdpwssd             m6, m2, m14
+    psrad                m5, 6
+    psrad                m6, 6
+    packssdw             m5, m6
+    mova             [tmpq], m5
+    add                tmpq, 64
+    sub                  hd, 4
+    jg .hv_w8_loop
+    vzeroupper
+    RET
+.hv_w16:
+    WIN64_SPILL_XMM      23
+    mova                m16, [spel_h_perm16]
+    vpbroadcastd        m18, [pb_4]
+    add                  wd, wd
+    paddb               m17, m18, m16
+    lea                 r6d, [hq+wq*8-256]
+    paddb               m18, m17
+.hv_w16_loop0:
+    movu               ym19, [srcq+strideq*0]
+    vinserti32x8        m19, [srcq+strideq*1], 1
+    lea                  r5, [srcq+strideq*2]
+    movu               ym20, [r5  +strideq*0]
+    vinserti32x8        m20, [r5  +strideq*1], 1
+    lea                  r5, [r5  +strideq*2]
+    movu               ym21, [r5  +strideq*0]
+    vinserti32x8        m21, [r5  +strideq*1], 1
+    lea                  r5, [r5  +strideq*2]
+    movu               ym22, [r5  +strideq*0]
+    mov                  r7, tmpq
+    vpermb               m3, m16, m19      ; 0 1   0123   89ab
+    mova                 m2, m8
+    vpermb               m4, m18, m19      ; 0 1   89ab   ghij
+    vpdpbusd             m2, m3, m10
+    mova                 m3, m8
+    vpermb               m5, m16, m20      ; 2 3   0123   89ab
+    vpdpbusd             m3, m4, m11
+    mova                 m4, m8
+    vpermb               m6, m18, m20      ; 2 3   89ab   ghij
+    vpdpbusd             m4, m5, m10
+    mova                 m5, m8
+    vpermb               m7, m16, m21      ; 4 5   0123   89ab
+    vpdpbusd             m5, m6, m11
+    mova                 m6, m8
+    vpermb               m0, m18, m21      ; 4 5   89ab   ghij
+    vpdpbusd             m6, m7, m10
+    mova                 m7, m8
+    vpermb              ym1, ym16, ym22    ; 6     0123   89ab
+    vpdpbusd             m7, m0, m11
+    mova                ym0, ym8
+    vpermb              m19, m17, m19      ; 0 1   4567   cdef
+    vpdpbusd            ym0, ym1, ym10
+    vpermb              ym1, ym18, ym22    ; 6     89ab   ghij
+    vpdpbusd             m2, m19, m11
+    vpdpbusd             m3, m19, m10
+    mova               ym19, ym8
+    vpermb              m20, m17, m20      ; 2 3   4567   cdef
+    vpdpbusd           ym19, ym1, ym11
+    vpermb              m21, m17, m21      ; 4 5   4567   cdef
+    vpdpbusd             m4, m20, m11
+    vpdpbusd             m5, m20, m10
+    vpermb             ym22, ym17, ym22    ; 6     4567   cdef
+    vpdpbusd             m6, m21, m11
+    vpdpbusd             m7, m21, m10
+    packssdw             m2, m3            ; 0 1
+    vpdpbusd            ym0, ym22, ym11
+    packssdw             m4, m5            ; 2 3
+    vpdpbusd           ym19, ym22, ym10
+    packssdw             m6, m7            ; 4 5
+    packssdw            ym0, ym19          ; 6
+    REPX       {psraw x, 2}, m2, m4, m6, ym0
+    vshufi32x4           m3, m2, m4, q1032 ; 1 2
+    vshufi32x4           m5, m4, m6, q1032 ; 3 4
+    vshufi32x4           m0, m6, m0, q1032 ; 5 6
+    punpcklwd            m1, m2, m3  ; 01 12
+    punpckhwd            m2, m3
+    punpcklwd            m3, m4, m5  ; 23 34
+    punpckhwd            m4, m5
+    punpcklwd            m5, m6, m0  ; 45 56
+    punpckhwd            m6, m0
+.hv_w16_loop:
+    movu               ym19, [r5+strideq*1]
+    lea                  r5, [r5+strideq*2]
+    vinserti32x8        m19, [r5+strideq*0], 1
+    mova                m20, m9
+    vpdpwssd            m20, m1, m12 ; a0
+    vpermb               m1, m16, m19
+    mova                m21, m9
+    vpdpwssd            m21, m2, m12 ; b0
+    vpermb               m2, m17, m19
+    mova                m22, m8
+    vpdpbusd            m22, m1, m10
+    mova                 m1, m8
+    vpermb              m19, m18, m19
+    vpdpbusd             m1, m2, m10
+    vpdpwssd            m20, m3, m13 ; a1
+    vpdpwssd            m21, m4, m13 ; b1
+    vpdpbusd            m22, m2, m11
+    mova                 m2, m4
+    vpdpbusd             m1, m19, m11
+    mova                 m4, m6
+    vpdpwssd            m20, m5, m14 ; a2
+    vpdpwssd            m21, m6, m14 ; b2
+    packssdw            m22, m1
+    mova                 m1, m3
+    psraw               m22, 2              ; 7 8
+    mova                 m3, m5
+    vshufi32x4           m6, m0, m22, q1032 ; 6 7
+    mova                 m0, m22
+    punpcklwd            m5, m6, m0  ; 67 78
+    punpckhwd            m6, m0
+    vpdpwssd            m20, m5, m15 ; a3
+    vpdpwssd            m21, m6, m15 ; b3
+    psrad               m20, 6
+    psrad               m21, 6
+    packssdw            m20, m21
+    mova          [r7+wq*0], ym20
+    vextracti32x8 [r7+wq*1], m20, 1
+    lea                  r7, [r7+wq*2]
+    sub                  hd, 2
+    jg .hv_w16_loop
+    add                srcq, 16
+    add                tmpq, 32
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .hv_w16_loop0
+    RET
+
+cglobal warp_affine_8x8t_8bpc, 4, 7, 22, tmp, ts
+    vpbroadcastd         m9, [pd_16384]
+    mova               ym15, [warp_8x8t_end]
+    call mangle(private_prefix %+ _warp_affine_8x8_8bpc_avx512icl).main
+    jmp .start
+.loop:
+    call mangle(private_prefix %+ _warp_affine_8x8_8bpc_avx512icl).main2
+    lea                tmpq, [tmpq+tsq*4]
+.start:
+    paddd               m16, m16
+    vpermb              m16, m15, m16
+    mova         [tmpq+tsq*0], xm16
+    vextracti128 [tmpq+tsq*2], ym16, 1
+    sub                 r6d, 0x1800
+    jg .loop
+    RET
+
+cglobal warp_affine_8x8_8bpc, 4, 7, 22, dst, ds, src, ss, abcd, filter
+    vpbroadcastd         m9, [pd_262144]
+    mova               xm15, [warp_8x8_end]
+    call .main
+    jmp .start
+.loop:
+    call .main2
+    lea                dstq, [dstq+dsq*2]
+.start:
+    psrad               m16, 19
+    packuswb            m16, m16
+    vpermb              m16, m15, m16
+    movq       [dstq+dsq*0], xm16
+    movhps     [dstq+dsq*1], xm16
+    sub                 r6d, 0x1800
+    jg .loop
+    RET
+ALIGN function_align
+.main:
+    vpbroadcastd         m1, [pd_512]
+%if WIN64
+    mov               abcdq, r5mp
+    vpaddd             ym18, ym1, r6m {1to8} ; mx
+%else
+    add                 r5d, 512
+    vpbroadcastd       ym18, r5d
+%endif
+    vpaddd             ym20, ym1, r7m {1to8} ; my
+    mova               ym16, [pd_0to7]
+    vpbroadcastd       ym19, [abcdq+4*0]
+    vpbroadcastd       ym21, [abcdq+4*1]
+    lea                  r4, [ssq*3+3]
+    mova                m10, [warp_8x8_permA]
+    mov                 r6d, 0x5555
+    mova                m11, [warp_8x8_permB]
+    lea             filterq, [mc_warp_filter+64*8]
+    vpbroadcastq        m12, [warp_8x8_hpack]
+    sub                srcq, r4               ; src -= src_stride*3 + 3
+    vbroadcasti32x4     m13, [warp_8x8_permC]
+    kxnorb               k2, k2, k2
+    vbroadcasti32x4     m14, [warp_8x8_permD]
+    vpdpwssd           ym18, ym19, ym16       ; alpha
+    vpdpwssd           ym20, ym21, ym16       ; gamma
+    vbroadcasti32x4      m0, [srcq]
+    psrad              ym19, 16               ; beta
+    psrad              ym21, 16               ; delta
+    kmovw                k1, r6d
+    psrad              ym16, ym18, 10
+    kmovb                k3, k2
+    paddd              ym18, ym19
+    vpgatherdq       m2{k2}, [filterq+ym16*8] ; filter_x0
+    psrld                m1, 8                ; pd_2
+    pshufb               m0, m11
+    paddd                m8, m1, m1           ; pd_4
+    vpdpbusd             m1, m0, m2
+    call .h
+    psllq                m2, m1, 45
+    pslld                m1, 13
+    paddd                m1, m2
+    vpshrdq              m1, m0, 48           ; 01 12
+    call .h
+    vpshrdq              m2, m1, m0, 48       ; 23 34
+    call .h
+    vpshrdq              m3, m2, m0, 48       ; 45 56
+.main2:
+    call .h
+    psrad              ym17, ym20, 10
+    kmovb                k2, k3
+    paddd              ym20, ym21
+    vpgatherdq       m7{k3}, [filterq+ym17*8] ; filter_y0
+    psrad              ym16, ym20, 10
+    kmovb                k3, k2
+    paddd              ym20, ym21
+    vpgatherdq      m17{k2}, [filterq+ym16*8] ; filter_y1
+    shufps               m5, m7, m17, q2020   ; a0 a1 a2 a3 b0 b1 b2 b3 A0 A1 A2 A3 B0 B1 B2 B3
+    mova                m16, m9
+    pshufb               m4, m5, m13          ;    a0    a1    A0    A1    b0    b1    B0    B1
+    vpdpwssd            m16, m1, m4
+    pshufb               m5, m14              ;    a2    a3    A2    A3    b2    b3    B2    B3
+    mova                 m1, m2
+    vpdpwssd            m16, m2, m5
+    shufps               m5, m7, m17, q3131   ; a4 a5 a6 a7 b4 b5 b6 b7 A4 A5 A6 A7 B4 B5 B6 B7
+    mova                 m2, m3
+    pshufb               m4, m5, m13          ;    a4    a5    A4    A5    b4    b5    B4    B5
+    vpdpwssd            m16, m3, m4
+    vpshrdq              m3, m0, 48           ; 67 78
+    pshufb               m5, m14              ;    a6    a7    A6    A7    b6    b7    B6    B7
+    vpdpwssd            m16, m3, m5
+    ret
+ALIGN function_align
+.h:
+    movu                xm5, [srcq+ssq*1]
+    psrad              ym16, ym18, 10
+    lea                srcq, [srcq+ssq*2]
+    vinserti32x4        ym5, [srcq+ssq*0], 1
+    kmovb                k2, k3
+    paddd              ym18, ym19
+    vpgatherdq       m6{k3}, [filterq+ym16*8] ; filter_x1
+    psrad              ym17, ym18, 10
+    kmovb                k3, k2
+    paddd              ym18, ym19
+    vpgatherdq      m16{k2}, [filterq+ym17*8] ; filter_x2
+    mova                 m0, m8
+    vpermb               m4, m10, m5          ; a4 b0 a5 b1   a6 b2 a7 b3   a8 b4 a9 b5   aa b6 ab b7
+    vpshldq             m17, m16, m6, 32      ; a4 a5 a6 a7   b0 b1 b2 b3
+    vpdpbusd             m0, m4, m17
+    vpermb               m5, m11, m5          ; a0 b4 a1 b5   a2 b6 a3 b7   a4 b8 a5 b9   a6 ba a7 bb
+    vmovdqa32       m16{k1}, m6               ; a0 a1 a2 a3   b4 b5 b6 b7
+    vpdpbusd             m0, m5, m16
+    vpmultishiftqb       m0, m12, m0          ; 1 1 2 2 (>> 3)
+    ret
+
+%macro BIDIR_FN 1 ; op
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    cmp                  hd, 8
+    jg .w4_h16
+    WRAP_YMM %1           0
+    vextracti32x4       xm1, ym0, 1
+    movd   [dstq          ], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    jl .w4_ret
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq          ], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+.w4_ret:
+    RET
+.w4_h16:
+    vpbroadcastd         m7, strided
+    pmulld               m7, [bidir_sctr_w4]
+    %1                    0
+    kxnorw               k1, k1, k1
+    vpscatterdd [dstq+m7]{k1}, m0
+    RET
+.w8:
+    cmp                  hd, 4
+    jne .w8_h8
+    WRAP_YMM %1           0
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq          ], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    RET
+.w8_loop:
+    %1_INC_PTR            2
+    lea                dstq, [dstq+strideq*4]
+.w8_h8:
+    %1                    0
+    vextracti32x4       xm1, ym0, 1
+    vextracti32x4       xm2, m0, 2
+    vextracti32x4       xm3, m0, 3
+    movq   [dstq          ], xm0
+    movq   [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm2
+    movq   [dstq+stride3q ], xm3
+    lea                dstq, [dstq+strideq*4]
+    movhps [dstq          ], xm0
+    movhps [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm3
+    sub                  hd, 8
+    jg .w8_loop
+    RET
+.w16_loop:
+    %1_INC_PTR            2
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    %1                    0
+    vpermq               m0, m0, q3120
+    mova          [dstq          ], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32:
+    pmovzxbq             m7, [pb_02461357]
+.w32_loop:
+    %1                    0
+    %1_INC_PTR            2
+    vpermq               m0, m7, m0
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64:
+    pmovzxbq             m7, [pb_02461357]
+.w64_loop:
+    %1                    0
+    %1_INC_PTR            2
+    vpermq               m0, m7, m0
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128:
+    pmovzxbq             m7, [pb_02461357]
+.w128_loop:
+    %1                    0
+    vpermq               m6, m7, m0
+    %1                    2
+    mova        [dstq+64*0], m6
+    %1_INC_PTR            4
+    vpermq               m6, m7, m0
+    mova        [dstq+64*1], m6
+    add                dstq, strideq
+    dec                  hd
+    jg .w128_loop
+    RET
+%endmacro
+
+%macro AVG 1 ; src_offset
+    mova                 m0, [tmp1q+(%1+0)*mmsize]
+    paddw                m0, [tmp2q+(%1+0)*mmsize]
+    mova                 m1, [tmp1q+(%1+1)*mmsize]
+    paddw                m1, [tmp2q+(%1+1)*mmsize]
+    pmulhrsw             m0, m4
+    pmulhrsw             m1, m4
+    packuswb             m0, m1
+%endmacro
+
+%macro AVG_INC_PTR 1
+    add               tmp1q, %1*mmsize
+    add               tmp2q, %1*mmsize
+%endmacro
+
+cglobal avg_8bpc, 4, 7, 5, dst, stride, tmp1, tmp2, w, h, stride3
+%define base r6-avg_avx512icl_table
+    lea                  r6, [avg_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, dword [r6+wq*4]
+    vpbroadcastd         m4, [base+pw_1024]
+    add                  wq, r6
+    BIDIR_FN            AVG
+
+%macro W_AVG 1 ; src_offset
+    ; (a * weight + b * (16 - weight) + 128) >> 8
+    ; = ((a - b) * weight + (b << 4) + 128) >> 8
+    ; = ((((a - b) * ((weight-16) << 12)) >> 16) + a + 8) >> 4
+    ; = ((((b - a) * (-weight     << 12)) >> 16) + b + 8) >> 4
+    mova                 m0,     [tmp1q+(%1+0)*mmsize]
+    psubw                m2, m0, [tmp2q+(%1+0)*mmsize]
+    mova                 m1,     [tmp1q+(%1+1)*mmsize]
+    psubw                m3, m1, [tmp2q+(%1+1)*mmsize]
+    pmulhw               m2, m4
+    pmulhw               m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+%endmacro
+
+%define W_AVG_INC_PTR AVG_INC_PTR
+
+cglobal w_avg_8bpc, 4, 7, 6, dst, stride, tmp1, tmp2, w, h, stride3
+%define base r6-w_avg_avx512icl_table
+    lea                  r6, [w_avg_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    vpbroadcastw         m4, r6m ; weight
+    movsxd               wq, dword [r6+wq*4]
+    vpbroadcastd         m5, [base+pw_2048]
+    psllw                m4, 12 ; (weight-16) << 12 when interpreted as signed
+    add                  wq, r6
+    cmp           dword r6m, 7
+    jg .weight_gt7
+    mov                  r6, tmp1q
+    pxor                 m0, m0
+    mov               tmp1q, tmp2q
+    psubw                m4, m0, m4 ; -weight
+    mov               tmp2q, r6
+.weight_gt7:
+    BIDIR_FN          W_AVG
+
+%macro MASK 1 ; src_offset
+    ; (a * m + b * (64 - m) + 512) >> 10
+    ; = ((a - b) * m + (b << 6) + 512) >> 10
+    ; = ((((b - a) * (-m << 10)) >> 16) + b + 8) >> 4
+%if mmsize == 64
+    vpermq               m3, m8, [maskq+%1*32]
+%else
+    vpermq               m3,     [maskq+%1*16], q3120
+%endif
+    mova                 m0,     [tmp2q+(%1+0)*mmsize]
+    psubw                m1, m0, [tmp1q+(%1+0)*mmsize]
+    psubb                m3, m4, m3
+    paddw                m1, m1     ; (b - a) << 1
+    paddb                m3, m3
+    punpcklbw            m2, m4, m3 ; -m << 9
+    pmulhw               m1, m2
+    paddw                m0, m1
+    mova                 m1,     [tmp2q+(%1+1)*mmsize]
+    psubw                m2, m1, [tmp1q+(%1+1)*mmsize]
+    paddw                m2, m2
+    punpckhbw            m3, m4, m3
+    pmulhw               m2, m3
+    paddw                m1, m2
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+%endmacro
+
+%macro MASK_INC_PTR 1
+    add               maskq, %1*32
+    add               tmp2q, %1*64
+    add               tmp1q, %1*64
+%endmacro
+
+cglobal mask_8bpc, 4, 8, 6, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-mask_avx512icl_table
+    lea                  r7, [mask_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    mov               maskq, maskmp
+    movsxd               wq, dword [r7+wq*4]
+    pxor                 m4, m4
+    mova                 m8, [base+bilin_v_perm64]
+    vpbroadcastd         m5, [base+pw_2048]
+    add                  wq, r7
+    BIDIR_FN           MASK
+
+%macro W_MASK 4-5 0 ; dst, mask, tmp_offset[1-2], 4:4:4
+    mova                m%1, [tmp1q+mmsize*%3]
+    mova                 m1, [tmp2q+mmsize*%3]
+    psubw                m1, m%1
+    pabsw               m%2, m1
+    psubusw             m%2, m6, m%2
+    psrlw               m%2, 8 ; 64 - m
+    psllw                m2, m%2, 10
+    pmulhw               m1, m2
+    paddw               m%1, m1
+    mova                 m1, [tmp1q+mmsize*%4]
+    mova                 m2, [tmp2q+mmsize*%4]
+    psubw                m2, m1
+    pabsw                m3, m2
+    psubusw              m3, m6, m3
+    vpshldw             m%2, m3, 8
+    psllw                m3, m%2, 10
+%if %5
+    psubb               m%2, m5, m%2
+%endif
+    pmulhw               m2, m3
+    paddw                m1, m2
+    pmulhrsw            m%1, m7
+    pmulhrsw             m1, m7
+    packuswb            m%1, m1
+%endmacro
+
+cglobal w_mask_420_8bpc, 4, 8, 16, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_420_avx512icl_table
+    lea                  r7, [w_mask_420_avx512icl_table]
+    tzcnt                wd, wm
+    mov                 r6d, r7m ; sign
+    movifnidn            hd, hm
+    movsxd               wq, [r7+wq*4]
+    vpbroadcastd         m6, [base+pw_6903] ; ((64 - 38) << 8) + 255 - 8
+    vpbroadcastd         m7, [base+pw_2048]
+    vpbroadcastd         m9, [base+pb_m64]             ; -1 << 6
+    mova               ym10, [base+wm_420_mask+32]
+    vpbroadcastd         m8, [base+wm_sign+r6*8] ; (258 - sign) << 6
+    add                  wq, r7
+    mov               maskq, maskmp
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    mova                 m5, [wm_420_perm4]
+    cmp                  hd, 8
+    jg .w4_h16
+    WRAP_YMM W_MASK       0, 4, 0, 1
+    vinserti128         ym5, [wm_420_perm4+32], 1
+    vpermb              ym4, ym5, ym4
+    vpdpbusd            ym8, ym4, ym9
+    vextracti32x4       xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+.w4_end:
+    vpermb              ym8, ym10, ym8
+    movq            [maskq], xm8
+    RET
+.w4_h16:
+    vpbroadcastd        m11, strided
+    pmulld              m11, [bidir_sctr_w4]
+    W_MASK                0, 4, 0, 1
+    vpermb               m4, m5, m4
+    vpdpbusd             m8, m4, m9
+    kxnorw               k1, k1, k1
+    vpermb               m8, m10, m8
+    mova            [maskq], xm8
+    vpscatterdd [dstq+m11]{k1}, m0
+    RET
+.w8:
+    mova                 m5, [wm_420_perm8]
+    cmp                  hd, 4
+    jne .w8_h8
+    WRAP_YMM W_MASK       0, 4, 0, 1
+    vinserti128         ym5, [wm_420_perm8+32], 1
+    vpermb              ym4, ym5, ym4
+    vpdpbusd            ym8, ym4, ym9
+    vpermb               m8, m10, m8
+    mova            [maskq], xm8
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    RET
+.w8_loop:
+    add               tmp1q, 128
+    add               tmp2q, 128
+    add               maskq, 16
+    lea                dstq, [dstq+strideq*4]
+.w8_h8:
+    W_MASK                0, 4, 0, 1
+    vpermb               m4, m5, m4
+    mova                 m1, m8
+    vpdpbusd             m1, m4, m9
+    vpermb               m1, m10, m1
+    mova            [maskq], xm1
+    vextracti32x4       xm1, ym0, 1
+    vextracti32x4       xm2, m0, 2
+    vextracti32x4       xm3, m0, 3
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm2
+    movq   [dstq+stride3q ], xm3
+    lea                dstq, [dstq+strideq*4]
+    movhps [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm3
+    sub                  hd, 8
+    jg .w8_loop
+    RET
+.w16:
+    mova                 m5, [wm_420_perm16]
+.w16_loop:
+    W_MASK                0, 4, 0, 1
+    vpermb               m4, m5, m4
+    mova                 m1, m8
+    vpdpbusd             m1, m4, m9
+    add               tmp1q, 128
+    add               tmp2q, 128
+    vpermb               m1, m10, m1
+    vpermq               m0, m0, q3120
+    mova            [maskq], xm1
+    add               maskq, 16
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    lea                dstq, [dstq+strideq*4]
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32:
+    pmovzxbq             m5, [pb_02461357]
+.w32_loop:
+    W_MASK                0, 4, 0, 1
+    mova                 m1, m8
+    vpdpbusd             m1, m4, m9
+    add               tmp1q, 128
+    add               tmp2q, 128
+    vpermb               m1, m10, m1
+    vpermq               m0, m5, m0
+    mova            [maskq], xm1
+    add               maskq, 16
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64:
+    pmovzxbq            m12, [wm_420_perm64] ; 0, 2, 4, 6, 8, 10, 12, 14
+    psrlq               m13, m12, 4          ; 1, 3, 5, 7, 9, 11, 13, 15
+.w64_loop:
+    W_MASK                0, 4, 0, 2
+    W_MASK               11, 5, 1, 3
+    mova                 m2, m8
+    vpdpbusd             m2, m4, m9
+    mova                 m3, m8
+    vpdpbusd             m3, m5, m9
+    add               tmp1q, 256
+    add               tmp2q, 256
+    vpermt2b             m2, m10, m3
+    mova                 m1, m0
+    vpermt2q             m0, m12, m11
+    vpermt2q             m1, m13, m11
+    mova            [maskq], ym2
+    add               maskq, 32
+    mova   [dstq+strideq*0], m0
+    mova   [dstq+strideq*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w64_loop
+    RET
+.w128:
+    pmovzxbq            m14, [wm_420_perm64]
+    mova                m10, [wm_420_mask]
+    psrlq               m15, m14, 4
+.w128_loop:
+    W_MASK                0, 12, 0, 4
+    W_MASK               11, 13, 1, 5
+    mova                 m4, m8
+    vpdpbusd             m4, m12, m9
+    mova                 m5, m8
+    vpdpbusd             m5, m13, m9
+    mova                 m1, m0
+    vpermt2q             m0, m14, m11
+    vpermt2q             m1, m15, m11
+    mova [dstq+strideq*0+64*0], m0
+    mova [dstq+strideq*1+64*0], m1
+    W_MASK                0, 12, 2, 6
+    W_MASK               11, 13, 3, 7
+    vprold               m4, 16
+    vprold               m5, 16
+    vpdpbusd             m4, m12, m9
+    vpdpbusd             m5, m13, m9
+    add               tmp1q, 512
+    add               tmp2q, 512
+    vpermt2b             m4, m10, m5
+    mova                 m1, m0
+    vpermt2q             m0, m14, m11
+    vpermt2q             m1, m15, m11
+    mova            [maskq], m4
+    add               maskq, 64
+    mova [dstq+strideq*0+64*1], m0
+    mova [dstq+strideq*1+64*1], m1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w128_loop
+    RET
+
+cglobal w_mask_422_8bpc, 4, 8, 14, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_422_avx512icl_table
+    lea                  r7, [w_mask_422_avx512icl_table]
+    tzcnt                wd, wm
+    mov                 r6d, r7m ; sign
+    movifnidn            hd, hm
+    movsxd               wq, dword [r7+wq*4]
+    vpbroadcastd         m6, [base+pw_6903] ; ((64 - 38) << 8) + 255 - 8
+    vpbroadcastd         m7, [base+pw_2048]
+    vpbroadcastd         m9, [base+pw_m128]
+    mova                m10, [base+wm_422_mask]
+    vpbroadcastd        m11, [base+pb_127]
+    add                  wq, r7
+    vpbroadcastd         m8, [base+wm_sign+4+r6*4]
+    mov               maskq, maskmp
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    cmp                  hd, 8
+    jg .w4_h16
+    WRAP_YMM W_MASK       0, 4, 0, 1
+    movhps             xm10, [wm_422_mask+16]
+    vpdpwssd            ym8, ym4, ym9
+    vpermb              ym8, ym10, ym8
+    vextracti32x4       xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+.w4_end:
+    pand                xm8, xm11
+    mova            [maskq], xm8
+    RET
+.w4_h16:
+    vpbroadcastd         m5, strided
+    pmulld               m5, [bidir_sctr_w4]
+    W_MASK                0, 4, 0, 1
+    vpdpwssd             m8, m4, m9
+    kxnorw               k1, k1, k1
+    vpermb               m8, m10, m8
+    pand                ym8, ym11
+    mova            [maskq], ym8
+    vpscatterdd [dstq+m5]{k1}, m0
+    RET
+.w8:
+    cmp                  hd, 4
+    jne .w8_h8
+    WRAP_YMM W_MASK       0, 4, 0, 1
+    movhps             xm10, [wm_422_mask+16]
+    vpdpwssd            ym8, ym4, ym9
+    vpermb              ym8, ym10, ym8
+    pand                xm8, xm11
+    mova            [maskq], xm8
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    RET
+.w8_loop:
+    add               tmp1q, 128
+    add               tmp2q, 128
+    add               maskq, 32
+    lea                dstq, [dstq+strideq*4]
+.w8_h8:
+    W_MASK                0, 4, 0, 1
+    mova                 m1, m8
+    vpdpwssd             m1, m4, m9
+    vpermb               m1, m10, m1
+    pand                ym1, ym11
+    mova            [maskq], ym1
+    vextracti32x4       xm1, ym0, 1
+    vextracti32x4       xm2, m0, 2
+    vextracti32x4       xm3, m0, 3
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm2
+    movq   [dstq+stride3q ], xm3
+    lea                dstq, [dstq+strideq*4]
+    movhps [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm3
+    sub                  hd, 8
+    jg .w8_loop
+    RET
+.w16_loop:
+    add               tmp1q, 128
+    add               tmp2q, 128
+    add               maskq, 32
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    W_MASK                0, 4, 0, 1
+    mova                 m1, m8
+    vpdpwssd             m1, m4, m9
+    vpermb               m1, m10, m1
+    vpermq               m0, m0, q3120
+    pand                ym1, ym11
+    mova            [maskq], ym1
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32:
+    pmovzxbq             m5, [pb_02461357]
+.w32_loop:
+    W_MASK                0, 4, 0, 1
+    mova                 m1, m8
+    vpdpwssd             m1, m4, m9
+    add               tmp1q, 128
+    add               tmp2q, 128
+    vpermb               m1, m10, m1
+    vpermq               m0, m5, m0
+    pand                ym1, ym11
+    mova            [maskq], ym1
+    add               maskq, 32
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64:
+    pmovzxbq             m5, [pb_02461357]
+.w64_loop:
+    W_MASK                0, 4, 0, 1
+    mova                 m1, m8
+    vpdpwssd             m1, m4, m9
+    add               tmp1q, 128
+    add               tmp2q, 128
+    vpermb               m1, m10, m1
+    vpermq               m0, m5, m0
+    pand                ym1, ym11
+    mova            [maskq], ym1
+    add               maskq, 32
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128:
+    pmovzxbq            m13, [pb_02461357]
+.w128_loop:
+    W_MASK                0, 4, 0, 1
+    W_MASK               12, 5, 2, 3
+    mova                 m2, m8
+    vpdpwssd             m2, m4, m9
+    mova                 m3, m8
+    vpdpwssd             m3, m5, m9
+    add               tmp1q, 256
+    add               tmp2q, 256
+    vpermt2b             m2, m10, m3
+    vpermq               m0, m13, m0
+    vpermq               m1, m13, m12
+    pand                 m2, m11
+    mova            [maskq], m2
+    add               maskq, 64
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    add                dstq, strideq
+    dec                  hd
+    jg .w128_loop
+    RET
+
+cglobal w_mask_444_8bpc, 4, 8, 12, dst, stride, tmp1, tmp2, w, h, mask, stride3
+%define base r7-w_mask_444_avx512icl_table
+    lea                  r7, [w_mask_444_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, dword [r7+wq*4]
+    vpbroadcastd         m6, [base+pw_6903] ; ((64 - 38) << 8) + 255 - 8
+    vpbroadcastd         m5, [base+pb_64]
+    vpbroadcastd         m7, [base+pw_2048]
+    mova                 m8, [base+wm_444_mask]
+    add                  wq, r7
+    mov               maskq, maskmp
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4:
+    cmp                  hd, 8
+    jg .w4_h16
+    WRAP_YMM W_MASK       0, 4, 0, 1, 1
+    vinserti128         ym8, [wm_444_mask+32], 1
+    vpermb              ym4, ym8, ym4
+    mova            [maskq], ym4
+    vextracti32x4      xm1, m0, 1
+    movd   [dstq+strideq*0], xm0
+    pextrd [dstq+strideq*1], xm0, 1
+    movd   [dstq+strideq*2], xm1
+    pextrd [dstq+stride3q ], xm1, 1
+    jl .w4_end
+    lea                dstq, [dstq+strideq*4]
+    pextrd [dstq+strideq*0], xm0, 2
+    pextrd [dstq+strideq*1], xm0, 3
+    pextrd [dstq+strideq*2], xm1, 2
+    pextrd [dstq+stride3q ], xm1, 3
+.w4_end:
+    RET
+.w4_h16:
+    vpbroadcastd         m9, strided
+    pmulld               m9, [bidir_sctr_w4]
+    W_MASK                0, 4, 0, 1, 1
+    vpermb               m4, m8, m4
+    kxnorw               k1, k1, k1
+    mova            [maskq], m4
+    vpscatterdd [dstq+m9]{k1}, m0
+    RET
+.w8:
+    cmp                  hd, 4
+    jne .w8_h8
+    WRAP_YMM W_MASK       0, 4, 0, 1, 1
+    vinserti128         ym8, [wm_444_mask+32], 1
+    vpermb              ym4, ym8, ym4
+    mova            [maskq], ym4
+    vextracti32x4       xm1, ym0, 1
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm0
+    movhps [dstq+stride3q ], xm1
+    RET
+.w8_loop:
+    add               tmp1q, 128
+    add               tmp2q, 128
+    add               maskq, 64
+    lea                dstq, [dstq+strideq*4]
+.w8_h8:
+    W_MASK                0, 4, 0, 1, 1
+    vpermb               m4, m8, m4
+    mova            [maskq], m4
+    vextracti32x4       xm1, ym0, 1
+    vextracti32x4       xm2, m0, 2
+    vextracti32x4       xm3, m0, 3
+    movq   [dstq+strideq*0], xm0
+    movq   [dstq+strideq*1], xm1
+    movq   [dstq+strideq*2], xm2
+    movq   [dstq+stride3q ], xm3
+    lea                dstq, [dstq+strideq*4]
+    movhps [dstq+strideq*0], xm0
+    movhps [dstq+strideq*1], xm1
+    movhps [dstq+strideq*2], xm2
+    movhps [dstq+stride3q ], xm3
+    sub                  hd, 8
+    jg .w8_loop
+    RET
+.w16_loop:
+    add               tmp1q, 128
+    add               tmp2q, 128
+    add               maskq, 64
+    lea                dstq, [dstq+strideq*4]
+.w16:
+    W_MASK                0, 4, 0, 1, 1
+    vpermb               m4, m8, m4
+    vpermq               m0, m0, q3120
+    mova            [maskq], m4
+    mova          [dstq+strideq*0], xm0
+    vextracti32x4 [dstq+strideq*1], m0, 2
+    vextracti32x4 [dstq+strideq*2], ym0, 1
+    vextracti32x4 [dstq+stride3q ], m0, 3
+    sub                  hd, 4
+    jg .w16_loop
+    RET
+.w32:
+    pmovzxbq             m9, [pb_02461357]
+.w32_loop:
+    W_MASK                0, 4, 0, 1, 1
+    vpermb               m4, m8, m4
+    add               tmp1q, 128
+    add               tmp2q, 128
+    vpermq               m0, m9, m0
+    mova            [maskq], m4
+    add               maskq, 64
+    mova          [dstq+strideq*0], ym0
+    vextracti32x8 [dstq+strideq*1], m0, 1
+    lea                dstq, [dstq+strideq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64:
+    pmovzxbq             m9, [pb_02461357]
+.w64_loop:
+    W_MASK                0, 4, 0, 1, 1
+    vpermb               m4, m8, m4
+    add               tmp1q, 128
+    add               tmp2q, 128
+    vpermq               m0, m9, m0
+    mova            [maskq], m4
+    add               maskq, 64
+    mova             [dstq], m0
+    add                dstq, strideq
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128:
+    pmovzxbq            m11, [pb_02461357]
+.w128_loop:
+    W_MASK                0, 4, 0, 1, 1
+    W_MASK               10, 9, 2, 3, 1
+    vpermb               m4, m8, m4
+    vpermb               m9, m8, m9
+    add               tmp1q, 256
+    add               tmp2q, 256
+    vpermq               m0, m11, m0
+    vpermq              m10, m11, m10
+    mova       [maskq+64*0], m4
+    mova       [maskq+64*1], m9
+    add               maskq, 128
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m10
+    add                dstq, strideq
+    dec                  hd
+    jg .w128_loop
+    RET
+
+cglobal blend_8bpc, 3, 7, 8, dst, ds, tmp, w, h, mask
+%define base r6-blend_avx512icl_table
+    lea                  r6, [blend_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn         maskq, maskmp
+    movifnidn            hd, hm
+    movsxd               wq, [r6+wq*4]
+    vpbroadcastd         m6, [base+pb_64]
+    vpbroadcastd         m7, [base+pw_512]
+    sub                tmpq, maskq
+    add                  wq, r6
+    lea                  r6, [dsq*3]
+    jmp                  wq
+.w4:
+    movd               xmm0, [dstq+dsq*0]
+    pinsrd             xmm0, [dstq+dsq*1], 1
+    vpbroadcastd       xmm1, [dstq+dsq*2]
+    pinsrd             xmm1, [dstq+r6   ], 3
+    mova               xmm4, [maskq]
+    mova               xmm5, [maskq+tmpq]
+    add               maskq, 4*4
+    psubb              xmm3, xm6, xmm4
+    punpcklbw          xmm0, xmm5
+    punpcklbw          xmm2, xmm3, xmm4
+    punpckhbw          xmm1, xmm5
+    punpckhbw          xmm3, xmm4
+    pmaddubsw          xmm0, xmm2
+    pmaddubsw          xmm1, xmm3
+    pmulhrsw           xmm0, xm7
+    pmulhrsw           xmm1, xm7
+    packuswb           xmm0, xmm1
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    pextrd     [dstq+dsq*2], xmm0, 2
+    pextrd     [dstq+r6   ], xmm0, 3
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w4
+    RET
+.w8:
+    movq               xmm0, [dstq+dsq*0]
+    vpbroadcastq       xmm1, [dstq+dsq*1]
+    vpbroadcastq       ymm2, [dstq+dsq*2]
+    vpbroadcastq       ymm3, [dstq+r6   ]
+    mova               ymm4, [maskq]
+    mova               ymm5, [maskq+tmpq]
+    add               maskq, 8*4
+    vpblendd           ymm0, ymm2, 0x30
+    vpblendd           ymm1, ymm3, 0xc0
+    psubb              ymm3, ym6, ymm4
+    punpcklbw          ymm0, ymm5
+    punpcklbw          ymm2, ymm3, ymm4
+    punpckhbw          ymm1, ymm5
+    punpckhbw          ymm3, ymm4
+    pmaddubsw          ymm0, ymm2
+    pmaddubsw          ymm1, ymm3
+    pmulhrsw           ymm0, ym7
+    pmulhrsw           ymm1, ym7
+    packuswb           ymm0, ymm1
+    vextracti128       xmm1, ymm0, 1
+    movq       [dstq+dsq*0], xmm0
+    movhps     [dstq+dsq*1], xmm0
+    movq       [dstq+dsq*2], xmm1
+    movhps     [dstq+r6   ], xmm1
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w8
+    vzeroupper
+    RET
+.w16:
+    mova                xm1, [dstq+dsq*0]
+    vinserti32x4        ym1, [dstq+dsq*1], 1
+    vinserti32x4         m1, [dstq+dsq*2], 2
+    mova                 m4, [maskq]
+    vinserti32x4         m1, [dstq+r6   ], 3
+    mova                 m5, [maskq+tmpq]
+    add               maskq, 16*4
+    psubb                m3, m6, m4
+    punpcklbw            m0, m1, m5
+    punpcklbw            m2, m3, m4
+    punpckhbw            m1, m5
+    punpckhbw            m3, m4
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m7
+    pmulhrsw             m1, m7
+    packuswb             m0, m1
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], ym0, 1
+    vextracti32x4 [dstq+dsq*2], m0, 2
+    vextracti32x4 [dstq+r6   ], m0, 3
+    lea                dstq, [dstq+dsq*4]
+    sub                  hd, 4
+    jg .w16
+    RET
+.w32:
+    mova                ym1, [dstq+dsq*0]
+    vinserti32x8         m1, [dstq+dsq*1], 1
+    mova                 m4, [maskq]
+    mova                 m5, [maskq+tmpq]
+    add               maskq, 32*2
+    psubb                m3, m6, m4
+    punpcklbw            m0, m1, m5
+    punpcklbw            m2, m3, m4
+    punpckhbw            m1, m5
+    punpckhbw            m3, m4
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m7
+    pmulhrsw             m1, m7
+    packuswb             m0, m1
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w32
+    RET
+
+cglobal blend_v_8bpc, 3, 6, 6, dst, ds, tmp, w, h, mask
+%define base r5-blend_v_avx512icl_table
+    lea                  r5, [blend_v_avx512icl_table]
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, [r5+wq*4]
+    vpbroadcastd         m5, [base+pw_512]
+    add                  wq, r5
+    add               maskq, obmc_masks-blend_v_avx512icl_table
+    jmp                  wq
+.w2:
+    vpbroadcastd       xmm2, [maskq+2*2]
+.w2_s0_loop:
+    movd               xmm0, [dstq+dsq*0]
+    pinsrw             xmm0, [dstq+dsq*1], 1
+    movd               xmm1, [tmpq]
+    add                tmpq, 2*2
+    punpcklbw          xmm0, xmm1
+    pmaddubsw          xmm0, xmm2
+    pmulhrsw           xmm0, xm5
+    packuswb           xmm0, xmm0
+    pextrw     [dstq+dsq*0], xmm0, 0
+    pextrw     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w2_s0_loop
+    RET
+.w4:
+    vpbroadcastq       xmm2, [maskq+4*2]
+.w4_loop:
+    movd               xmm0, [dstq+dsq*0]
+    pinsrd             xmm0, [dstq+dsq*1], 1
+    movq               xmm1, [tmpq]
+    add                tmpq, 4*2
+    punpcklbw          xmm0, xmm1
+    pmaddubsw          xmm0, xmm2
+    pmulhrsw           xmm0, xm5
+    packuswb           xmm0, xmm0
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+.w8:
+    mova               xmm3, [maskq+8*2]
+.w8_loop:
+    movq               xmm0, [dstq+dsq*0]
+    vpbroadcastq       xmm1, [dstq+dsq*1]
+    mova               xmm2, [tmpq]
+    add                tmpq, 8*2
+    punpcklbw          xmm0, xmm2
+    punpckhbw          xmm1, xmm2
+    pmaddubsw          xmm0, xmm3
+    pmaddubsw          xmm1, xmm3
+    pmulhrsw           xmm0, xm5
+    pmulhrsw           xmm1, xm5
+    packuswb           xmm0, xmm1
+    movq       [dstq+dsq*0], xmm0
+    movhps     [dstq+dsq*1], xmm0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16:
+    vbroadcasti32x4     ym3, [maskq+16*2]
+    vbroadcasti32x4     ym4, [maskq+16*3]
+.w16_loop:
+    mova                xm1, [dstq+dsq*0]
+    vinserti32x4        ym1, [dstq+dsq*1], 1
+    mova                ym2, [tmpq]
+    add                tmpq, 16*2
+    punpcklbw           ym0, ym1, ym2
+    punpckhbw           ym1, ym2
+    pmaddubsw           ym0, ym3
+    pmaddubsw           ym1, ym4
+    pmulhrsw            ym0, ym5
+    pmulhrsw            ym1, ym5
+    packuswb            ym0, ym1
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32:
+    mova                 m4, [maskq+32*2]
+    vshufi32x4           m3, m4, m4, q2020
+    vshufi32x4           m4, m4, q3131
+.w32_loop:
+    mova                ym1, [dstq+dsq*0]
+    vinserti32x8         m1, [dstq+dsq*1], 1
+    mova                 m2, [tmpq]
+    add                tmpq, 32*2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m4
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+
+cglobal blend_h_8bpc, 3, 7, 6, dst, ds, tmp, w, h, mask
+%define base r6-blend_h_avx512icl_table
+    lea                  r6, [blend_h_avx512icl_table]
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, [r6+wq*4]
+    lea               maskq, [base+obmc_masks+hq*2]
+    vpbroadcastd         m5, [base+pw_512]
+    lea                  hd, [hq*3]
+    add                  wq, r6
+    shr                  hd, 2 ; h * 3/4
+    lea               maskq, [maskq+hq*2]
+    neg                  hq
+    jmp                  wq
+.w2:
+    movd               xmm0, [dstq+dsq*0]
+    pinsrw             xmm0, [dstq+dsq*1], 1
+    movd               xmm2, [maskq+hq*2]
+    movd               xmm1, [tmpq]
+    add                tmpq, 2*2
+    punpcklwd          xmm2, xmm2
+    punpcklbw          xmm0, xmm1
+    pmaddubsw          xmm0, xmm2
+    pmulhrsw           xmm0, xm5
+    packuswb           xmm0, xmm0
+    pextrw     [dstq+dsq*0], xmm0, 0
+    pextrw     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w2
+    RET
+.w4:
+    mova               xmm3, [blend_shuf]
+.w4_loop:
+    movd               xmm0, [dstq+dsq*0]
+    pinsrd             xmm0, [dstq+dsq*1], 1
+    movd               xmm2, [maskq+hq*2]
+    movq               xmm1, [tmpq]
+    add                tmpq, 4*2
+    pshufb             xmm2, xmm3
+    punpcklbw          xmm0, xmm1
+    pmaddubsw          xmm0, xmm2
+    pmulhrsw           xmm0, xm5
+    packuswb           xmm0, xmm0
+    movd       [dstq+dsq*0], xmm0
+    pextrd     [dstq+dsq*1], xmm0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w4_loop
+    RET
+.w8:
+    vbroadcasti128     ymm4, [blend_shuf]
+    shufpd             ymm4, ymm4, 0x03
+.w8_loop:
+    vpbroadcastq       ymm1, [dstq+dsq*0]
+    movq               xmm0, [dstq+dsq*1]
+    vpblendd           ymm0, ymm1, 0x30
+    vpbroadcastd       ymm3, [maskq+hq*2]
+    movq               xmm1, [tmpq+8*1]
+    vinserti128        ymm1, [tmpq+8*0], 1
+    add                tmpq, 8*2
+    pshufb             ymm3, ymm4
+    punpcklbw          ymm0, ymm1
+    pmaddubsw          ymm0, ymm3
+    pmulhrsw           ymm0, ym5
+    vextracti128       xmm1, ymm0, 1
+    packuswb           xmm0, xmm1
+    movhps     [dstq+dsq*0], xmm0
+    movq       [dstq+dsq*1], xmm0
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w8_loop
+    vzeroupper
+    RET
+.w16:
+    vbroadcasti32x4     ym4, [blend_shuf]
+    shufpd              ym4, ym4, 0x0c
+.w16_loop:
+    mova                xm1, [dstq+dsq*0]
+    vinserti32x4        ym1, [dstq+dsq*1], 1
+    vpbroadcastd        ym3, [maskq+hq*2]
+    mova                ym2, [tmpq]
+    add                tmpq, 16*2
+    pshufb              ym3, ym4
+    punpcklbw           ym0, ym1, ym2
+    punpckhbw           ym1, ym2
+    pmaddubsw           ym0, ym3
+    pmaddubsw           ym1, ym3
+    pmulhrsw            ym0, ym5
+    pmulhrsw            ym1, ym5
+    packuswb            ym0, ym1
+    mova          [dstq+dsq*0], xm0
+    vextracti32x4 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w16_loop
+    RET
+.w32:
+    vbroadcasti32x4      m4, [blend_shuf]
+    shufpd               m4, m4, 0xf0
+.w32_loop:
+    mova                ym1, [dstq+dsq*0]
+    vinserti32x8         m1, [dstq+dsq*1], 1
+    vpbroadcastd         m3, [maskq+hq*2]
+    mova                 m2, [tmpq]
+    add                tmpq, 32*2
+    pshufb               m3, m4
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova          [dstq+dsq*0], ym0
+    vextracti32x8 [dstq+dsq*1], m0, 1
+    lea                dstq, [dstq+dsq*2]
+    add                  hq, 2
+    jl .w32_loop
+    RET
+.w64:
+    vpbroadcastw         m3, [maskq+hq*2]
+    mova                 m1, [dstq]
+    mova                 m2, [tmpq]
+    add                tmpq, 32*2
+    punpcklbw            m0, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, dsq
+    inc                  hq
+    jl .w64
+    RET
+.w128:
+    vpbroadcastw         m6, [maskq+hq*2]
+    mova                 m2, [dstq+64*0]
+    mova                 m1, [tmpq+64*0]
+    mova                 m3, [dstq+64*1]
+    mova                 m4, [tmpq+64*1]
+    add                tmpq, 64*2
+    punpcklbw            m0, m2, m1
+    punpckhbw            m2, m1
+    pmaddubsw            m0, m6
+    pmaddubsw            m2, m6
+    punpcklbw            m1, m3, m4
+    punpckhbw            m3, m4
+    pmaddubsw            m1, m6
+    pmaddubsw            m3, m6
+    REPX   {pmulhrsw x, m5}, m0, m2, m1, m3
+    packuswb             m0, m2
+    packuswb             m1, m3
+    mova        [dstq+64*0], m0
+    mova        [dstq+64*1], m1
+    add                dstq, dsq
+    inc                  hq
+    jl .w128
+    RET
+
+cglobal resize_8bpc, 6, 12, 19, dst, dst_stride, src, src_stride, \
+                                dst_w, h, src_w, dx, mx0
+    sub          dword mx0m, 4<<14
+    sub        dword src_wm, 8
+    mov                  r6, ~0
+    vpbroadcastd         m5, dxm
+    vpbroadcastd         m8, mx0m
+    vpbroadcastd         m6, src_wm
+    kmovq                k3, r6
+ DEFINE_ARGS dst, dst_stride, src, src_stride, dst_w, h, x
+    LEA                  r7, $$
+%define base r7-$$
+    vpbroadcastd         m3, [base+pw_m256]
+    vpbroadcastd         m7, [base+pd_63]
+    vbroadcasti32x4     m15, [base+pb_8x0_8x8]
+    vpdpwssd             m8, m5, [base+rescale_mul] ; mx+dx*[0-15]
+    pslld                m5, 4                      ; dx*16
+    pslld                m6, 14
+    pxor                 m2, m2
+    mova                m16, [base+resize_permA]
+    mova                m17, [base+resize_permB]
+    mova               xm18, [base+resize_permC]
+.loop_y:
+    xor                  xd, xd
+    mova                 m4, m8     ; per-line working version of mx
+.loop_x:
+    pmaxsd               m0, m4, m2
+    psrad                m9, m4, 8  ; filter offset (unmasked)
+    pminsd               m0, m6     ; iclip(mx, 0, src_w-8)
+    psubd                m1, m4, m0 ; pshufb offset
+    psrad                m0, 14     ; clipped src_x offset
+    psrad                m1, 14     ; pshufb edge_emu offset
+    vptestmd             k4, m1, m1
+    pand                 m9, m7     ; filter offset (masked)
+    ktestw               k4, k4
+    jz .load
+    vextracti32x8      ym12, m0, 1
+    vextracti32x8      ym13, m1, 1
+    kmovq                k1, k3
+    kmovq                k2, k3
+    vpgatherdq      m10{k1}, [srcq+ym0]
+    vpgatherdq      m11{k2}, [srcq+ym12]
+    kmovq                k1, k3
+    kmovq                k2, k3
+    vpgatherdq      m14{k1}, [base+resize_shuf+4+ym1]
+    vpgatherdq       m0{k2}, [base+resize_shuf+4+ym13]
+    mova                m12, m16
+    mova                m13, m17
+    paddb               m14, m15
+    paddb                m0, m15
+    pshufb              m10, m14
+    pshufb              m11, m0
+    vpermi2d            m12, m10, m11
+    vpermi2d            m13, m10, m11
+    jmp .filter
+.load:
+    kmovq                k1, k3
+    kmovq                k2, k3
+    vpgatherdd      m12{k1}, [srcq+m0+0]
+    vpgatherdd      m13{k2}, [srcq+m0+4]
+.filter:
+    kmovq                k1, k3
+    kmovq                k2, k3
+    vpgatherdd      m10{k1}, [base+resize_filter+m9*8+0]
+    vpgatherdd      m11{k2}, [base+resize_filter+m9*8+4]
+    mova                m14, m2
+    vpdpbusd            m14, m12, m10
+    vpdpbusd            m14, m13, m11
+    packssdw            m14, m14
+    pmulhrsw            m14, m3
+    packuswb            m14, m14
+    vpermd              m14, m18, m14
+    mova          [dstq+xq], xm14
+    paddd                m4, m5
+    add                  xd, 16
+    cmp                  xd, dst_wd
+    jl .loop_x
+    add                dstq, dst_strideq
+    add                srcq, src_strideq
+    dec                  hd
+    jg .loop_y
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/mc_sse.asm b/media/libdav1d/src/src/x86/mc_sse.asm
new file mode 100644
index 0000000000..deeb6dbc45
--- /dev/null
+++ b/media/libdav1d/src/src/x86/mc_sse.asm
@@ -0,0 +1,10144 @@
+; Copyright © 2018, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; Copyright © 2018, VideoLabs
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 16
+
+; dav1d_obmc_masks[] with 64-x interleaved
+obmc_masks: db  0,  0,  0,  0
+            ; 2 @4
+            db 45, 19, 64,  0
+            ; 4 @8
+            db 39, 25, 50, 14, 59,  5, 64,  0
+            ; 8 @16
+            db 36, 28, 42, 22, 48, 16, 53, 11, 57,  7, 61,  3, 64,  0, 64,  0
+            ; 16 @32
+            db 34, 30, 37, 27, 40, 24, 43, 21, 46, 18, 49, 15, 52, 12, 54, 10
+            db 56,  8, 58,  6, 60,  4, 61,  3, 64,  0, 64,  0, 64,  0, 64,  0
+            ; 32 @64
+            db 33, 31, 35, 29, 36, 28, 38, 26, 40, 24, 41, 23, 43, 21, 44, 20
+            db 45, 19, 47, 17, 48, 16, 50, 14, 51, 13, 52, 12, 53, 11, 55,  9
+            db 56,  8, 57,  7, 58,  6, 59,  5, 60,  4, 60,  4, 61,  3, 62,  2
+
+warp_8x8_shufA: db 0,  2,  4,  6,  1,  3,  5,  7,  1,  3,  5,  7,  2,  4,  6,  8
+warp_8x8_shufB: db 4,  6,  8, 10,  5,  7,  9, 11,  5,  7,  9, 11,  6,  8, 10, 12
+warp_8x8_shufC: db 2,  4,  6,  8,  3,  5,  7,  9,  3,  5,  7,  9,  4,  6,  8, 10
+warp_8x8_shufD: db 6,  8, 10, 12,  7,  9, 11, 13,  7,  9, 11, 13,  8, 10, 12, 14
+blend_shuf:     db 0,  1,  0,  1,  0,  1,  0,  1,  2,  3,  2,  3,  2,  3,  2,  3
+subpel_h_shuf4: db 0,  1,  2,  3,  1,  2,  3,  4,  8,  9, 10, 11,  9, 10, 11, 12
+                db 2,  3,  4,  5,  3,  4,  5,  6, 10, 11, 12, 13, 11, 12, 13, 14
+subpel_h_shufA: db 0,  1,  2,  3,  1,  2,  3,  4,  2,  3,  4,  5,  3,  4,  5,  6
+subpel_h_shufB: db 4,  5,  6,  7,  5,  6,  7,  8,  6,  7,  8,  9,  7,  8,  9, 10
+subpel_h_shufC: db 8,  9, 10, 11,  9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14
+subpel_h_shufD: db 0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8
+subpel_h_shufE: db 2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8,  8,  9,  9, 10
+subpel_h_shufF: db 4,  5,  5,  6,  6,  7,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12
+subpel_s_shuf2: db 0,  1,  2,  3,  0,  1,  2,  3,  8,  9, 10, 11,  8,  9, 10, 11
+subpel_s_shuf8: db 0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+bilin_h_shuf4:  db 0,  1,  1,  2,  2,  3,  3,  4,  8,  9,  9, 10, 10, 11, 11, 12
+unpckw:         db 0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+rescale_mul:    dd 0,  1,  2,  3
+resize_shuf:    db 0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  7,  7,  7,  7
+
+wm_420_sign:    times 4 dw 258
+                times 4 dw 257
+wm_422_sign:    times 8 db 128
+                times 8 db 127
+
+pb_8x0_8x8: times 8 db 0
+            times 8 db 8
+bdct_lb_dw: times 4 db 0
+            times 4 db 4
+            times 4 db 8
+            times 4 db 12
+
+pb_64:    times 16 db 64
+pw_m256:  times 8 dw -256
+pw_1:     times 8 dw 1
+pw_2:     times 8 dw 2
+pw_8:     times 8 dw 8
+pw_15:    times 8 dw 15
+pw_26:    times 8 dw 26
+pw_34:    times 8 dw 34
+pw_512:   times 8 dw 512
+pw_1024:  times 8 dw 1024
+pw_2048:  times 8 dw 2048
+pw_6903:  times 8 dw 6903
+pw_8192:  times 8 dw 8192
+pd_32:    times 4 dd 32
+pd_63:    times 4 dd 63
+pd_512:   times 4 dd 512
+pd_16384: times 4 dd 16484
+pd_32768: times 4 dd 32768
+pd_262144:times 4 dd 262144
+pd_0x3ff: times 4 dd 0x3ff
+pd_0x4000:times 4 dd 0x4000
+pq_0x40000000: times 2 dq 0x40000000
+
+const mc_warp_filter2 ; dav1d_mc_warp_filter[] reordered for pmaddubsw usage
+    ; [-1, 0)
+    db 0, 127,   0, 0,   0,   1, 0, 0, 0, 127,   0, 0,  -1,   2, 0, 0
+    db 1, 127,  -1, 0,  -3,   4, 0, 0, 1, 126,  -2, 0,  -4,   6, 1, 0
+    db 1, 126,  -3, 0,  -5,   8, 1, 0, 1, 125,  -4, 0,  -6,  11, 1, 0
+    db 1, 124,  -4, 0,  -7,  13, 1, 0, 2, 123,  -5, 0,  -8,  15, 1, 0
+    db 2, 122,  -6, 0,  -9,  18, 1, 0, 2, 121,  -6, 0, -10,  20, 1, 0
+    db 2, 120,  -7, 0, -11,  22, 2, 0, 2, 119,  -8, 0, -12,  25, 2, 0
+    db 3, 117,  -8, 0, -13,  27, 2, 0, 3, 116,  -9, 0, -13,  29, 2, 0
+    db 3, 114, -10, 0, -14,  32, 3, 0, 3, 113, -10, 0, -15,  35, 2, 0
+    db 3, 111, -11, 0, -15,  37, 3, 0, 3, 109, -11, 0, -16,  40, 3, 0
+    db 3, 108, -12, 0, -16,  42, 3, 0, 4, 106, -13, 0, -17,  45, 3, 0
+    db 4, 104, -13, 0, -17,  47, 3, 0, 4, 102, -14, 0, -17,  50, 3, 0
+    db 4, 100, -14, 0, -17,  52, 3, 0, 4,  98, -15, 0, -18,  55, 4, 0
+    db 4,  96, -15, 0, -18,  58, 3, 0, 4,  94, -16, 0, -18,  60, 4, 0
+    db 4,  91, -16, 0, -18,  63, 4, 0, 4,  89, -16, 0, -18,  65, 4, 0
+    db 4,  87, -17, 0, -18,  68, 4, 0, 4,  85, -17, 0, -18,  70, 4, 0
+    db 4,  82, -17, 0, -18,  73, 4, 0, 4,  80, -17, 0, -18,  75, 4, 0
+    db 4,  78, -18, 0, -18,  78, 4, 0, 4,  75, -18, 0, -17,  80, 4, 0
+    db 4,  73, -18, 0, -17,  82, 4, 0, 4,  70, -18, 0, -17,  85, 4, 0
+    db 4,  68, -18, 0, -17,  87, 4, 0, 4,  65, -18, 0, -16,  89, 4, 0
+    db 4,  63, -18, 0, -16,  91, 4, 0, 4,  60, -18, 0, -16,  94, 4, 0
+    db 3,  58, -18, 0, -15,  96, 4, 0, 4,  55, -18, 0, -15,  98, 4, 0
+    db 3,  52, -17, 0, -14, 100, 4, 0, 3,  50, -17, 0, -14, 102, 4, 0
+    db 3,  47, -17, 0, -13, 104, 4, 0, 3,  45, -17, 0, -13, 106, 4, 0
+    db 3,  42, -16, 0, -12, 108, 3, 0, 3,  40, -16, 0, -11, 109, 3, 0
+    db 3,  37, -15, 0, -11, 111, 3, 0, 2,  35, -15, 0, -10, 113, 3, 0
+    db 3,  32, -14, 0, -10, 114, 3, 0, 2,  29, -13, 0,  -9, 116, 3, 0
+    db 2,  27, -13, 0,  -8, 117, 3, 0, 2,  25, -12, 0,  -8, 119, 2, 0
+    db 2,  22, -11, 0,  -7, 120, 2, 0, 1,  20, -10, 0,  -6, 121, 2, 0
+    db 1,  18,  -9, 0,  -6, 122, 2, 0, 1,  15,  -8, 0,  -5, 123, 2, 0
+    db 1,  13,  -7, 0,  -4, 124, 1, 0, 1,  11,  -6, 0,  -4, 125, 1, 0
+    db 1,   8,  -5, 0,  -3, 126, 1, 0, 1,   6,  -4, 0,  -2, 126, 1, 0
+    db 0,   4,  -3, 0,  -1, 127, 1, 0, 0,   2,  -1, 0,   0, 127, 0, 0
+    ; [0, 1)
+    db  0,   0,   1, 0, 0, 127,   0,  0,  0,  -1,   2, 0, 0, 127,   0,  0
+    db  0,  -3,   4, 1, 1, 127,  -2,  0,  0,  -5,   6, 1, 1, 127,  -2,  0
+    db  0,  -6,   8, 1, 2, 126,  -3,  0, -1,  -7,  11, 2, 2, 126,  -4, -1
+    db -1,  -8,  13, 2, 3, 125,  -5, -1, -1, -10,  16, 3, 3, 124,  -6, -1
+    db -1, -11,  18, 3, 4, 123,  -7, -1, -1, -12,  20, 3, 4, 122,  -7, -1
+    db -1, -13,  23, 3, 4, 121,  -8, -1, -2, -14,  25, 4, 5, 120,  -9, -1
+    db -1, -15,  27, 4, 5, 119, -10, -1, -1, -16,  30, 4, 5, 118, -11, -1
+    db -2, -17,  33, 5, 6, 116, -12, -1, -2, -17,  35, 5, 6, 114, -12, -1
+    db -2, -18,  38, 5, 6, 113, -13, -1, -2, -19,  41, 6, 7, 111, -14, -2
+    db -2, -19,  43, 6, 7, 110, -15, -2, -2, -20,  46, 6, 7, 108, -15, -2
+    db -2, -20,  49, 6, 7, 106, -16, -2, -2, -21,  51, 7, 7, 104, -16, -2
+    db -2, -21,  54, 7, 7, 102, -17, -2, -2, -21,  56, 7, 8, 100, -18, -2
+    db -2, -22,  59, 7, 8,  98, -18, -2, -2, -22,  62, 7, 8,  96, -19, -2
+    db -2, -22,  64, 7, 8,  94, -19, -2, -2, -22,  67, 8, 8,  91, -20, -2
+    db -2, -22,  69, 8, 8,  89, -20, -2, -2, -22,  72, 8, 8,  87, -21, -2
+    db -2, -21,  74, 8, 8,  84, -21, -2, -2, -22,  77, 8, 8,  82, -21, -2
+    db -2, -21,  79, 8, 8,  79, -21, -2, -2, -21,  82, 8, 8,  77, -22, -2
+    db -2, -21,  84, 8, 8,  74, -21, -2, -2, -21,  87, 8, 8,  72, -22, -2
+    db -2, -20,  89, 8, 8,  69, -22, -2, -2, -20,  91, 8, 8,  67, -22, -2
+    db -2, -19,  94, 8, 7,  64, -22, -2, -2, -19,  96, 8, 7,  62, -22, -2
+    db -2, -18,  98, 8, 7,  59, -22, -2, -2, -18, 100, 8, 7,  56, -21, -2
+    db -2, -17, 102, 7, 7,  54, -21, -2, -2, -16, 104, 7, 7,  51, -21, -2
+    db -2, -16, 106, 7, 6,  49, -20, -2, -2, -15, 108, 7, 6,  46, -20, -2
+    db -2, -15, 110, 7, 6,  43, -19, -2, -2, -14, 111, 7, 6,  41, -19, -2
+    db -1, -13, 113, 6, 5,  38, -18, -2, -1, -12, 114, 6, 5,  35, -17, -2
+    db -1, -12, 116, 6, 5,  33, -17, -2, -1, -11, 118, 5, 4,  30, -16, -1
+    db -1, -10, 119, 5, 4,  27, -15, -1, -1,  -9, 120, 5, 4,  25, -14, -2
+    db -1,  -8, 121, 4, 3,  23, -13, -1, -1,  -7, 122, 4, 3,  20, -12, -1
+    db -1,  -7, 123, 4, 3,  18, -11, -1, -1,  -6, 124, 3, 3,  16, -10, -1
+    db -1,  -5, 125, 3, 2,  13,  -8, -1, -1,  -4, 126, 2, 2,  11,  -7, -1
+    db  0,  -3, 126, 2, 1,   8,  -6,  0,  0,  -2, 127, 1, 1,   6,  -5,  0
+    db  0,  -2, 127, 1, 1,   4,  -3,  0,  0,   0, 127, 0, 0,   2,  -1,  0
+    ; [1, 2)
+    db 0, 0, 127,   0, 0,   1,   0, 0, 0, 0, 127,   0, 0,  -1,   2, 0
+    db 0, 1, 127,  -1, 0,  -3,   4, 0, 0, 1, 126,  -2, 0,  -4,   6, 1
+    db 0, 1, 126,  -3, 0,  -5,   8, 1, 0, 1, 125,  -4, 0,  -6,  11, 1
+    db 0, 1, 124,  -4, 0,  -7,  13, 1, 0, 2, 123,  -5, 0,  -8,  15, 1
+    db 0, 2, 122,  -6, 0,  -9,  18, 1, 0, 2, 121,  -6, 0, -10,  20, 1
+    db 0, 2, 120,  -7, 0, -11,  22, 2, 0, 2, 119,  -8, 0, -12,  25, 2
+    db 0, 3, 117,  -8, 0, -13,  27, 2, 0, 3, 116,  -9, 0, -13,  29, 2
+    db 0, 3, 114, -10, 0, -14,  32, 3, 0, 3, 113, -10, 0, -15,  35, 2
+    db 0, 3, 111, -11, 0, -15,  37, 3, 0, 3, 109, -11, 0, -16,  40, 3
+    db 0, 3, 108, -12, 0, -16,  42, 3, 0, 4, 106, -13, 0, -17,  45, 3
+    db 0, 4, 104, -13, 0, -17,  47, 3, 0, 4, 102, -14, 0, -17,  50, 3
+    db 0, 4, 100, -14, 0, -17,  52, 3, 0, 4,  98, -15, 0, -18,  55, 4
+    db 0, 4,  96, -15, 0, -18,  58, 3, 0, 4,  94, -16, 0, -18,  60, 4
+    db 0, 4,  91, -16, 0, -18,  63, 4, 0, 4,  89, -16, 0, -18,  65, 4
+    db 0, 4,  87, -17, 0, -18,  68, 4, 0, 4,  85, -17, 0, -18,  70, 4
+    db 0, 4,  82, -17, 0, -18,  73, 4, 0, 4,  80, -17, 0, -18,  75, 4
+    db 0, 4,  78, -18, 0, -18,  78, 4, 0, 4,  75, -18, 0, -17,  80, 4
+    db 0, 4,  73, -18, 0, -17,  82, 4, 0, 4,  70, -18, 0, -17,  85, 4
+    db 0, 4,  68, -18, 0, -17,  87, 4, 0, 4,  65, -18, 0, -16,  89, 4
+    db 0, 4,  63, -18, 0, -16,  91, 4, 0, 4,  60, -18, 0, -16,  94, 4
+    db 0, 3,  58, -18, 0, -15,  96, 4, 0, 4,  55, -18, 0, -15,  98, 4
+    db 0, 3,  52, -17, 0, -14, 100, 4, 0, 3,  50, -17, 0, -14, 102, 4
+    db 0, 3,  47, -17, 0, -13, 104, 4, 0, 3,  45, -17, 0, -13, 106, 4
+    db 0, 3,  42, -16, 0, -12, 108, 3, 0, 3,  40, -16, 0, -11, 109, 3
+    db 0, 3,  37, -15, 0, -11, 111, 3, 0, 2,  35, -15, 0, -10, 113, 3
+    db 0, 3,  32, -14, 0, -10, 114, 3, 0, 2,  29, -13, 0,  -9, 116, 3
+    db 0, 2,  27, -13, 0,  -8, 117, 3, 0, 2,  25, -12, 0,  -8, 119, 2
+    db 0, 2,  22, -11, 0,  -7, 120, 2, 0, 1,  20, -10, 0,  -6, 121, 2
+    db 0, 1,  18,  -9, 0,  -6, 122, 2, 0, 1,  15,  -8, 0,  -5, 123, 2
+    db 0, 1,  13,  -7, 0,  -4, 124, 1, 0, 1,  11,  -6, 0,  -4, 125, 1
+    db 0, 1,   8,  -5, 0,  -3, 126, 1, 0, 1,   6,  -4, 0,  -2, 126, 1
+    db 0, 0,   4,  -3, 0,  -1, 127, 1, 0, 0,   2,  -1, 0,   0, 127, 0
+    db 0, 0,   2,  -1, 0,   0, 127, 0
+
+pw_258:  times 2 dw 258
+
+cextern mc_subpel_filters
+%define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8)
+
+%macro BIDIR_JMP_TABLE 2-*
+    ;evaluated at definition time (in loop below)
+    %xdefine %1_%2_table (%%table - 2*%3)
+    %xdefine %%base %1_%2_table
+    %xdefine %%prefix mangle(private_prefix %+ _%1_8bpc_%2)
+    ; dynamically generated label
+    %%table:
+    %rep %0 - 2 ; repeat for num args
+        dd %%prefix %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+BIDIR_JMP_TABLE avg, ssse3,        4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_avg, ssse3,      4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE mask, ssse3,       4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_420, ssse3, 4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_422, ssse3, 4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE w_mask_444, ssse3, 4, 8, 16, 32, 64, 128
+BIDIR_JMP_TABLE blend, ssse3,      4, 8, 16, 32
+BIDIR_JMP_TABLE blend_v, ssse3, 2, 4, 8, 16, 32
+BIDIR_JMP_TABLE blend_h, ssse3, 2, 4, 8, 16, 16, 16, 16
+
+%macro BASE_JMP_TABLE 3-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base %1_%2
+    %%table:
+    %rep %0 - 2
+        dw %%base %+ _w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%xdefine put_ssse3 mangle(private_prefix %+ _put_bilin_8bpc_ssse3.put)
+%xdefine prep_ssse3 mangle(private_prefix %+ _prep_bilin_8bpc_ssse3.prep)
+
+BASE_JMP_TABLE put,  ssse3, 2, 4, 8, 16, 32, 64, 128
+BASE_JMP_TABLE prep, ssse3,    4, 8, 16, 32, 64, 128
+
+%macro HV_JMP_TABLE 5-*
+    %xdefine %%prefix mangle(private_prefix %+ _%1_%2_8bpc_%3)
+    %xdefine %%base %1_%3
+    %assign %%types %4
+    %if %%types & 1
+        %xdefine %1_%2_h_%3_table  (%%h  - %5)
+        %%h:
+        %rep %0 - 4
+            dw %%prefix %+ .h_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 2
+        %xdefine %1_%2_v_%3_table  (%%v  - %5)
+        %%v:
+        %rep %0 - 4
+            dw %%prefix %+ .v_w%5 - %%base
+            %rotate 1
+        %endrep
+        %rotate 4
+    %endif
+    %if %%types & 4
+        %xdefine %1_%2_hv_%3_table (%%hv - %5)
+        %%hv:
+        %rep %0 - 4
+            dw %%prefix %+ .hv_w%5 - %%base
+            %rotate 1
+        %endrep
+    %endif
+%endmacro
+
+HV_JMP_TABLE prep,  8tap, ssse3, 1,    4, 8, 16, 32, 64, 128
+HV_JMP_TABLE put,  bilin, ssse3, 7, 2, 4, 8, 16, 32, 64, 128
+HV_JMP_TABLE prep, bilin, ssse3, 7,    4, 8, 16, 32, 64, 128
+
+%macro SCALED_JMP_TABLE 2-*
+    %xdefine %1_%2_table (%%table - %3)
+    %xdefine %%base mangle(private_prefix %+ _%1_8bpc_%2)
+%%table:
+    %rep %0 - 2
+        dw %%base %+ .w%3 - %%base
+        %rotate 1
+    %endrep
+    %rotate 2
+%%dy_1024:
+    %xdefine %1_%2_dy1_table (%%dy_1024 - %3)
+    %rep %0 - 2
+        dw %%base %+ .dy1_w%3 - %%base
+        %rotate 1
+    %endrep
+    %rotate 2
+%%dy_2048:
+    %xdefine %1_%2_dy2_table (%%dy_2048 - %3)
+    %rep %0 - 2
+        dw %%base %+ .dy2_w%3 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+SCALED_JMP_TABLE put_8tap_scaled, ssse3, 2, 4, 8, 16, 32, 64, 128
+SCALED_JMP_TABLE prep_8tap_scaled, ssse3,   4, 8, 16, 32, 64, 128
+
+%define table_offset(type, fn) type %+ fn %+ SUFFIX %+ _table - type %+ SUFFIX
+
+SECTION .text
+
+INIT_XMM ssse3
+
+%if ARCH_X86_32
+ DECLARE_REG_TMP 1
+ %define base t0-put_ssse3
+%else
+ DECLARE_REG_TMP 7
+ %define base 0
+%endif
+
+%macro RESTORE_DSQ_32 1
+ %if ARCH_X86_32
+   mov                  %1, dsm ; restore dsq
+ %endif
+%endmacro
+
+cglobal put_bilin_8bpc, 1, 8, 0, dst, ds, src, ss, w, h, mxy
+    movifnidn          mxyd, r6m ; mx
+    LEA                  t0, put_ssse3
+    movifnidn          srcq, srcmp
+    movifnidn           ssq, ssmp
+    tzcnt                wd, wm
+    mov                  hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r7m ; my
+    test               mxyd, mxyd
+    jnz .v
+.put:
+    movzx                wd, word [t0+wq*2+table_offset(put,)]
+    add                  wq, t0
+    RESTORE_DSQ_32       t0
+    jmp                  wq
+.put_w2:
+    movzx               r4d, word [srcq+ssq*0]
+    movzx               r6d, word [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r4w
+    mov        [dstq+dsq*1], r6w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w2
+    RET
+.put_w4:
+    mov                 r4d, [srcq+ssq*0]
+    mov                 r6d, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov        [dstq+dsq*0], r4d
+    mov        [dstq+dsq*1], r6d
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w4
+    RET
+.put_w8:
+    movq                 m0, [srcq+ssq*0]
+    movq                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq       [dstq+dsq*0], m0
+    movq       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w8
+    RET
+.put_w16:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova       [dstq+dsq*0], m0
+    mova       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w16
+    RET
+.put_w32:
+    movu                 m0, [srcq+ssq*0+16*0]
+    movu                 m1, [srcq+ssq*0+16*1]
+    movu                 m2, [srcq+ssq*1+16*0]
+    movu                 m3, [srcq+ssq*1+16*1]
+    lea                srcq, [srcq+ssq*2]
+    mova  [dstq+dsq*0+16*0], m0
+    mova  [dstq+dsq*0+16*1], m1
+    mova  [dstq+dsq*1+16*0], m2
+    mova  [dstq+dsq*1+16*1], m3
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .put_w32
+    RET
+.put_w64:
+    movu                 m0, [srcq+16*0]
+    movu                 m1, [srcq+16*1]
+    movu                 m2, [srcq+16*2]
+    movu                 m3, [srcq+16*3]
+    add                srcq, ssq
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    mova        [dstq+16*2], m2
+    mova        [dstq+16*3], m3
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w64
+    RET
+.put_w128:
+    movu                 m0, [srcq+16*0]
+    movu                 m1, [srcq+16*1]
+    movu                 m2, [srcq+16*2]
+    movu                 m3, [srcq+16*3]
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    mova        [dstq+16*2], m2
+    mova        [dstq+16*3], m3
+    movu                 m0, [srcq+16*4]
+    movu                 m1, [srcq+16*5]
+    movu                 m2, [srcq+16*6]
+    movu                 m3, [srcq+16*7]
+    mova        [dstq+16*4], m0
+    mova        [dstq+16*5], m1
+    mova        [dstq+16*6], m2
+    mova        [dstq+16*7], m3
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .put_w128
+    RET
+.h:
+    ; (16 * src[x] + (mx * (src[x + 1] - src[x])) + 8) >> 4
+    ; = ((16 - mx) * src[x] + mx * src[x + 1] + 8) >> 4
+    imul               mxyd, 0x00ff00ff
+    mova                 m4, [base+subpel_h_shufD]
+    mova                 m0, [base+bilin_h_shuf4]
+    add                mxyd, 0x00100010
+    movd                 m5, mxyd
+    mov                mxyd, r7m ; my
+    pshufd               m5, m5, q0000
+    test               mxyd, mxyd
+    jnz .hv
+    movzx                wd, word [t0+wq*2+table_offset(put, _bilin_h)]
+    mova                 m3, [base+pw_2048]
+    add                  wq, t0
+    movifnidn           dsq, dsmp
+    jmp                  wq
+.h_w2:
+    pshufd               m4, m4, q3120 ; m4 = {1, 0, 2, 1, 5, 4, 6, 5}
+.h_w2_loop:
+    movd                 m0, [srcq+ssq*0]
+    movd                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpckldq            m0, m1
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+    pmulhrsw             m0, m3
+    packuswb             m0, m0
+    movd                r6d, m0
+    mov        [dstq+dsq*0], r6w
+    shr                 r6d, 16
+    mov        [dstq+dsq*1], r6w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2_loop
+    RET
+.h_w4:
+    movq                 m4, [srcq+ssq*0]
+    movhps               m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m4, m0
+    pmaddubsw            m4, m5
+    pmulhrsw             m4, m3
+    packuswb             m4, m4
+    movd       [dstq+dsq*0], m4
+    psrlq                m4, 32
+    movd       [dstq+dsq*1], m4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4
+    RET
+.h_w8:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    add                srcq, ssq
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    mova             [dstq], m0
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w16
+    RET
+.h_w32:
+    movu                 m0, [srcq+mmsize*0+8*0]
+    movu                 m1, [srcq+mmsize*0+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    movu                 m1, [srcq+mmsize*1+8*0]
+    movu                 m2, [srcq+mmsize*1+8*1]
+    add                srcq, ssq
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pmaddubsw            m1, m5
+    pmaddubsw            m2, m5
+    pmulhrsw             m1, m3
+    pmulhrsw             m2, m3
+    packuswb             m1, m2
+    mova        [dstq+16*0], m0
+    mova        [dstq+16*1], m1
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w32
+    RET
+.h_w64:
+    mov                  r6, -16*3
+.h_w64_loop:
+    movu                 m0, [srcq+r6+16*3+8*0]
+    movu                 m1, [srcq+r6+16*3+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    mova     [dstq+r6+16*3], m0
+    add                  r6, 16
+    jle .h_w64_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w64
+    RET
+.h_w128:
+    mov                  r6, -16*7
+.h_w128_loop:
+    movu                 m0, [srcq+r6+16*7+8*0]
+    movu                 m1, [srcq+r6+16*7+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    pmulhrsw             m0, m3
+    pmulhrsw             m1, m3
+    packuswb             m0, m1
+    mova     [dstq+r6+16*7], m0
+    add                  r6, 16
+    jle .h_w128_loop
+    add                srcq, ssq
+    add                dstq, dsq
+    dec                  hd
+    jg .h_w128
+    RET
+.v:
+    movzx                wd, word [t0+wq*2+table_offset(put, _bilin_v)]
+    imul               mxyd, 0x00ff00ff
+    mova                 m5, [base+pw_2048]
+    add                mxyd, 0x00100010
+    add                  wq, t0
+    movd                 m4, mxyd
+    pshufd               m4, m4, q0000
+    movifnidn           dsq, dsmp
+    jmp                  wq
+.v_w2:
+    movd                 m0, [srcq+ssq*0]
+.v_w2_loop:
+    pinsrw               m0, [srcq+ssq*1], 1 ; 0 1
+    lea                srcq, [srcq+ssq*2]
+    pshuflw              m1, m0, q2301
+    pinsrw               m0, [srcq+ssq*0], 0 ; 2 1
+    punpcklbw            m1, m0
+    pmaddubsw            m1, m4
+    pmulhrsw             m1, m5
+    packuswb             m1, m1
+    movd                r6d, m1
+    mov        [dstq+dsq*1], r6w
+    shr                 r6d, 16
+    mov        [dstq+dsq*0], r6w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+    movd                 m0, [srcq+ssq*0]
+.v_w4_loop:
+    movd                 m2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova                 m1, m0
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m1, m2 ; 0 1
+    punpckldq            m2, m0 ; 1 2
+    punpcklbw            m1, m2
+    pmaddubsw            m1, m4
+    pmulhrsw             m1, m5
+    packuswb             m1, m1
+    movd       [dstq+dsq*0], m1
+    psrlq                m1, 32
+    movd       [dstq+dsq*1], m1
+    ;
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq                 m0, [srcq+ssq*0]
+.v_w8_loop:
+    movq                 m2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova                 m1, m0
+    movq                 m0, [srcq+ssq*0]
+    punpcklbw            m1, m2
+    punpcklbw            m2, m0
+    pmaddubsw            m1, m4
+    pmaddubsw            m2, m4
+    pmulhrsw             m1, m5
+    pmulhrsw             m2, m5
+    packuswb             m1, m2
+    movq       [dstq+dsq*0], m1
+    movhps     [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    RET
+%macro PUT_BILIN_V_W16 0
+    movu                 m0, [srcq+ssq*0]
+%%loop:
+    movu                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova                 m1, m0
+    mova                 m2, m0
+    movu                 m0, [srcq+ssq*0]
+    punpcklbw            m1, m3
+    punpckhbw            m2, m3
+    pmaddubsw            m1, m4
+    pmaddubsw            m2, m4
+    pmulhrsw             m1, m5
+    pmulhrsw             m2, m5
+    packuswb             m1, m2
+    punpcklbw            m2, m3, m0
+    punpckhbw            m3, m0
+    pmaddubsw            m2, m4
+    pmaddubsw            m3, m4
+    pmulhrsw             m2, m5
+    pmulhrsw             m3, m5
+    packuswb             m2, m3
+    mova       [dstq+dsq*0], m1
+    mova       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg %%loop
+%endmacro
+.v_w16:
+    PUT_BILIN_V_W16
+    RET
+.v_w128:
+    lea                 r6d, [hq+(7<<16)]
+    jmp .v_w16gt
+.v_w64:
+    lea                 r6d, [hq+(3<<16)]
+    jmp .v_w16gt
+.v_w32:
+    lea                 r6d, [hq+(1<<16)]
+.v_w16gt:
+    mov                  r4, srcq
+%if ARCH_X86_64
+    mov                  r7, dstq
+%endif
+.v_w16gt_loop:
+    PUT_BILIN_V_W16
+%if ARCH_X86_64
+    add                  r4, 16
+    add                  r7, 16
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+%else
+    mov                dstq, dstmp
+    add                  r4, 16
+    movzx                hd, r6w
+    add                dstq, 16
+    mov                srcq, r4
+    mov               dstmp, dstq
+%endif
+    sub                 r6d, 1<<16
+    jg .v_w16gt
+    RET
+.hv:
+    ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 128) >> 8
+    ; = (src[x] + ((my * (src[x + src_stride] - src[x])) >> 4) + 8) >> 4
+    movzx                wd, word [t0+wq*2+table_offset(put, _bilin_hv)]
+    WIN64_SPILL_XMM       8
+    shl                mxyd, 11 ; can't shift by 12 due to signed overflow
+    mova                 m7, [base+pw_15]
+    movd                 m6, mxyd
+    add                  wq, t0
+    pshuflw              m6, m6, q0000
+    paddb                m5, m5
+    punpcklqdq           m6, m6
+    jmp                  wq
+.hv_w2:
+    RESTORE_DSQ_32       t0
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m0, m0
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w2_loop:
+    movd                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movd                 m2, [srcq+ssq*0]
+    punpckldq            m1, m2
+    pshufb               m1, m4
+    pmaddubsw            m1, m5             ; 1 _ 2 _
+    shufps               m2, m0, m1, q1032  ; 0 _ 1 _
+    mova                 m0, m1
+    psubw                m1, m2   ; 2 * (src[x + src_stride] - src[x])
+    pmulhw               m1, m6   ; (my * (src[x + src_stride] - src[x]) >> 4
+    pavgw                m2, m7   ; src[x] + 8
+    paddw                m1, m2   ; src[x] + ((my * (src[x + src_stride] - src[x])) >> 4) + 8
+    psrlw                m1, 4
+    packuswb             m1, m1
+%if ARCH_X86_64
+    movq                 r6, m1
+%else
+    pshuflw              m1, m1, q2020
+    movd                r6d, m1
+%endif
+    mov        [dstq+dsq*0], r6w
+    shr                  r6, gprsize*4
+    mov        [dstq+dsq*1], r6w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+    mova                 m4, [base+bilin_h_shuf4]
+    movddup              m0, [srcq+ssq*0]
+    movifnidn           dsq, dsmp
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w4_loop:
+    movq                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps               m1, [srcq+ssq*0]
+    pshufb               m1, m4
+    pmaddubsw            m1, m5            ; 1 2
+    shufps               m2, m0, m1, q1032 ; 0 1
+    mova                 m0, m1
+    psubw                m1, m2
+    pmulhw               m1, m6
+    pavgw                m2, m7
+    paddw                m1, m2
+    psrlw                m1, 4
+    packuswb             m1, m1
+    movd       [dstq+dsq*0], m1
+    psrlq                m1, 32
+    movd       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    movu                 m0, [srcq+ssq*0]
+    movifnidn           dsq, dsmp
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+.hv_w8_loop:
+    movu                 m2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m2, m4
+    pmaddubsw            m2, m5
+    psubw                m1, m2, m0
+    pmulhw               m1, m6
+    pavgw                m0, m7
+    paddw                m1, m0
+    movu                 m0, [srcq+ssq*0]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5
+    psubw                m3, m0, m2
+    pmulhw               m3, m6
+    pavgw                m2, m7
+    paddw                m3, m2
+    psrlw                m1, 4
+    psrlw                m3, 4
+    packuswb             m1, m3
+    movq       [dstq+dsq*0], m1
+    movhps     [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w128:
+    lea                 r6d, [hq+(7<<16)]
+    jmp .hv_w16_start
+.hv_w64:
+    lea                 r6d, [hq+(3<<16)]
+    jmp .hv_w16_start
+.hv_w32:
+    lea                 r6d, [hq+(1<<16)]
+.hv_w16_start:
+    mov                  r4, srcq
+%if ARCH_X86_32
+    %define m8 [dstq]
+%else
+    mov                  r7, dstq
+%endif
+.hv_w16:
+    movifnidn           dsq, dsmp
+%if WIN64
+    movaps              r4m, m8
+%endif
+.hv_w16_loop0:
+    movu                 m0, [srcq+8*0]
+    movu                 m1, [srcq+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+.hv_w16_loop:
+    add                srcq, ssq
+    movu                 m2, [srcq+8*0]
+    movu                 m3, [srcq+8*1]
+    pshufb               m2, m4
+    pshufb               m3, m4
+    pmaddubsw            m2, m5
+    pmaddubsw            m3, m5
+    mova                 m8, m2
+    psubw                m2, m0
+    pmulhw               m2, m6
+    pavgw                m0, m7
+    paddw                m2, m0
+    mova                 m0, m3
+    psubw                m3, m1
+    pmulhw               m3, m6
+    pavgw                m1, m7
+    paddw                m3, m1
+    mova                 m1, m0
+    mova                 m0, m8
+    psrlw                m2, 4
+    psrlw                m3, 4
+    packuswb             m2, m3
+    mova             [dstq], m2
+    add                dstq, dsmp
+    dec                  hd
+    jg .hv_w16_loop
+%if ARCH_X86_32
+    mov                dstq, dstm
+    add                  r4, 16
+    movzx                hd, r6w
+    add                dstq, 16
+    mov                srcq, r4
+    mov                dstm, dstq
+%else
+    add                  r4, 16
+    add                  r7, 16
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+%endif
+    sub                 r6d, 1<<16
+    jg .hv_w16_loop0
+%if WIN64
+    movaps               m8, r4m
+%endif
+    RET
+
+%if ARCH_X86_32
+    %define base r6-prep%+SUFFIX
+%else
+    %define base 0
+%endif
+
+cglobal prep_bilin_8bpc, 3, 7, 0, tmp, src, stride, w, h, mxy, stride3
+    movifnidn          mxyd, r5m ; mx
+    LEA                  r6, prep_ssse3
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    test               mxyd, mxyd
+    jnz .h
+    mov                mxyd, r6m ; my
+    test               mxyd, mxyd
+    jnz .v
+.prep:
+    movzx                wd, word [r6+wq*2+table_offset(prep,)]
+    pxor                 m4, m4
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.prep_w4:
+    movd                 m0, [srcq+strideq*0]
+    movd                 m1, [srcq+strideq*1]
+    movd                 m2, [srcq+strideq*2]
+    movd                 m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    punpckldq            m0, m1
+    punpckldq            m2, m3
+    punpcklbw            m0, m4
+    punpcklbw            m2, m4
+    psllw                m0, 4
+    psllw                m2, 4
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m2
+    add                tmpq, 16*2
+    sub                  hd, 4
+    jg .prep_w4
+    RET
+.prep_w8:
+    movq                 m0, [srcq+strideq*0]
+    movq                 m1, [srcq+strideq*1]
+    movq                 m2, [srcq+strideq*2]
+    movq                 m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    punpcklbw            m0, m4
+    punpcklbw            m1, m4
+    punpcklbw            m2, m4
+    punpcklbw            m3, m4
+    psllw                m0, 4
+    psllw                m1, 4
+    psllw                m2, 4
+    psllw                m3, 4
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    sub                  hd, 4
+    jg .prep_w8
+    RET
+.prep_w16:
+    movu                 m1, [srcq+strideq*0]
+    movu                 m3, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    punpcklbw            m0, m1, m4
+    punpckhbw            m1, m4
+    punpcklbw            m2, m3, m4
+    punpckhbw            m3, m4
+    psllw                m0, 4
+    psllw                m1, 4
+    psllw                m2, 4
+    psllw                m3, 4
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    sub                  hd, 2
+    jg .prep_w16
+    RET
+.prep_w128:
+    mov                  r3, -128
+    jmp .prep_w32_start
+.prep_w64:
+    mov                  r3, -64
+    jmp .prep_w32_start
+.prep_w32:
+    mov                  r3, -32
+.prep_w32_start:
+    sub                srcq, r3
+.prep_w32_vloop:
+    mov                  r6, r3
+.prep_w32_hloop:
+    movu                 m1, [srcq+r6+16*0]
+    movu                 m3, [srcq+r6+16*1]
+    punpcklbw            m0, m1, m4
+    punpckhbw            m1, m4
+    punpcklbw            m2, m3, m4
+    punpckhbw            m3, m4
+    psllw                m0, 4
+    psllw                m1, 4
+    psllw                m2, 4
+    psllw                m3, 4
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    add                  r6, 32
+    jl .prep_w32_hloop
+    add                srcq, strideq
+    dec                  hd
+    jg .prep_w32_vloop
+    RET
+.h:
+    ; 16 * src[x] + (mx * (src[x + 1] - src[x]))
+    ; = (16 - mx) * src[x] + mx * src[x + 1]
+    imul               mxyd, 0x00ff00ff
+    mova                 m4, [base+subpel_h_shufD]
+    add                mxyd, 0x00100010
+    movd                 m5, mxyd
+    mov                mxyd, r6m ; my
+    pshufd               m5, m5, q0000
+    test               mxyd, mxyd
+    jnz .hv
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_h)]
+    add                  wq, r6
+    jmp                  wq
+.h_w4:
+    mova                 m4, [base+bilin_h_shuf4]
+    lea            stride3q, [strideq*3]
+.h_w4_loop:
+    movq                 m0, [srcq+strideq*0]
+    movhps               m0, [srcq+strideq*1]
+    movq                 m1, [srcq+strideq*2]
+    movhps               m1, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    mova          [tmpq+0 ], m0
+    mova          [tmpq+16], m1
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4_loop
+    RET
+.h_w8:
+    lea            stride3q, [strideq*3]
+.h_w8_loop:
+    movu                 m0, [srcq+strideq*0]
+    movu                 m1, [srcq+strideq*1]
+    movu                 m2, [srcq+strideq*2]
+    movu                 m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    REPX  {pshufb    x, m4}, m0, m1, m2, m3
+    REPX  {pmaddubsw x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    sub                  hd, 4
+    jg .h_w8_loop
+    RET
+.h_w16:
+    movu                 m0, [srcq+strideq*0+8*0]
+    movu                 m1, [srcq+strideq*0+8*1]
+    movu                 m2, [srcq+strideq*1+8*0]
+    movu                 m3, [srcq+strideq*1+8*1]
+    lea                srcq, [srcq+strideq*2]
+    REPX  {pshufb    x, m4}, m0, m1, m2, m3
+    REPX  {pmaddubsw x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    sub                  hd, 2
+    jg .h_w16
+    RET
+.h_w128:
+    mov                  r3, -128
+    jmp .h_w32_start
+.h_w64:
+    mov                  r3, -64
+    jmp .h_w32_start
+.h_w32:
+    mov                  r3, -32
+.h_w32_start:
+    sub                srcq, r3
+.h_w32_vloop:
+    mov                  r6, r3
+.h_w32_hloop:
+    movu                 m0, [srcq+r6+8*0]
+    movu                 m1, [srcq+r6+8*1]
+    movu                 m2, [srcq+r6+8*2]
+    movu                 m3, [srcq+r6+8*3]
+    REPX  {pshufb    x, m4}, m0, m1, m2, m3
+    REPX  {pmaddubsw x, m5}, m0, m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    add                  r6, 32
+    jl .h_w32_hloop
+    add                srcq, strideq
+    dec                  hd
+    jg .h_w32_vloop
+    RET
+.v:
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_v)]
+    imul               mxyd, 0x00ff00ff
+    add                mxyd, 0x00100010
+    add                  wq, r6
+    lea            stride3q, [strideq*3]
+    movd                 m5, mxyd
+    pshufd               m5, m5, q0000
+    jmp                  wq
+.v_w4:
+    movd                 m0, [srcq+strideq*0]
+.v_w4_loop:
+    movd                 m1, [srcq+strideq*1]
+    movd                 m2, [srcq+strideq*2]
+    movd                 m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    punpckldq            m0, m1
+    punpckldq            m1, m2
+    punpcklbw            m0, m1 ; 01 12
+    pmaddubsw            m0, m5
+    mova        [tmpq+16*0], m0
+    movd                 m0, [srcq+strideq*0]
+    punpckldq            m2, m3
+    punpckldq            m3, m0
+    punpcklbw            m2, m3 ; 23 34
+    pmaddubsw            m2, m5
+    mova        [tmpq+16*1], m2
+    add                tmpq, 16*2
+    sub                  hd, 4
+    jg .v_w4_loop
+    RET
+.v_w8:
+    movq                 m0, [srcq+strideq*0]
+.v_w8_loop:
+    movq                 m1, [srcq+strideq*1]
+    movq                 m2, [srcq+strideq*2]
+    movq                 m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    punpcklbw            m0, m1 ; 01
+    punpcklbw            m1, m2 ; 12
+    pmaddubsw            m0, m5
+    pmaddubsw            m1, m5
+    mova        [tmpq+16*0], m0
+    movq                 m0, [srcq+strideq*0]
+    punpcklbw            m2, m3 ; 23
+    punpcklbw            m3, m0 ; 34
+    pmaddubsw            m2, m5
+    mova        [tmpq+16*1], m1
+    pmaddubsw            m3, m5
+    mova        [tmpq+16*2], m2
+    mova        [tmpq+16*3], m3
+    add                tmpq, 16*4
+    sub                  hd, 4
+    jg .v_w8_loop
+    RET
+.v_w16:
+    movu                 m0, [srcq+strideq*0]
+.v_w16_loop:
+    movu                 m1, [srcq+strideq*1]
+    movu                 m2, [srcq+strideq*2]
+    movu                 m3, [srcq+stride3q ]
+    lea                srcq, [srcq+strideq*4]
+    punpcklbw            m4, m0, m1
+    punpckhbw            m0, m1
+    pmaddubsw            m4, m5
+    pmaddubsw            m0, m5
+    mova        [tmpq+16*0], m4
+    punpcklbw            m4, m1, m2
+    punpckhbw            m1, m2
+    pmaddubsw            m4, m5
+    mova        [tmpq+16*1], m0
+    movu                 m0, [srcq+strideq*0]
+    pmaddubsw            m1, m5
+    mova        [tmpq+16*2], m4
+    punpcklbw            m4, m2, m3
+    punpckhbw            m2, m3
+    pmaddubsw            m4, m5
+    mova        [tmpq+16*3], m1
+    pmaddubsw            m2, m5
+    mova        [tmpq+16*4], m4
+    punpcklbw            m4, m3, m0
+    punpckhbw            m3, m0
+    pmaddubsw            m4, m5
+    mova        [tmpq+16*5], m2
+    pmaddubsw            m3, m5
+    mova        [tmpq+16*6], m4
+    mova        [tmpq+16*7], m3
+    add                tmpq, 16*8
+    sub                  hd, 4
+    jg .v_w16_loop
+    RET
+.v_w128:
+    lea                 r3d, [hq+(3<<8)]
+    mov                 r6d, 256
+    jmp .v_w32_start
+.v_w64:
+    lea                 r3d, [hq+(1<<8)]
+    mov                 r6d, 128
+    jmp .v_w32_start
+.v_w32:
+    xor                 r3d, r3d
+    mov                 r6d, 64
+.v_w32_start:
+%if ARCH_X86_64
+ %if WIN64
+    PUSH                 r7
+ %endif
+    mov                  r7, tmpq
+%endif
+    mov                  r5, srcq
+.v_w32_hloop:
+    movu                 m0, [srcq+strideq*0+16*0]
+    movu                 m1, [srcq+strideq*0+16*1]
+.v_w32_vloop:
+    movu                 m2, [srcq+strideq*1+16*0]
+    movu                 m3, [srcq+strideq*1+16*1]
+    lea                srcq, [srcq+strideq*2]
+    punpcklbw            m4, m0, m2
+    punpckhbw            m0, m2
+    pmaddubsw            m4, m5
+    pmaddubsw            m0, m5
+    mova        [tmpq+16*0], m4
+    mova        [tmpq+16*1], m0
+    movu                 m0, [srcq+strideq*0+16*0]
+    punpcklbw            m4, m1, m3
+    punpckhbw            m1, m3
+    pmaddubsw            m4, m5
+    pmaddubsw            m1, m5
+    mova        [tmpq+16*2], m4
+    mova        [tmpq+16*3], m1
+    movu                 m1, [srcq+strideq*0+16*1]
+    add                tmpq, r6
+    punpcklbw            m4, m2, m0
+    punpckhbw            m2, m0
+    pmaddubsw            m4, m5
+    pmaddubsw            m2, m5
+    mova        [tmpq+16*0], m4
+    mova        [tmpq+16*1], m2
+    punpcklbw            m4, m3, m1
+    punpckhbw            m3, m1
+    pmaddubsw            m4, m5
+    pmaddubsw            m3, m5
+    mova        [tmpq+16*2], m4
+    mova        [tmpq+16*3], m3
+    add                tmpq, r6
+    sub                  hd, 2
+    jg .v_w32_vloop
+    add                  r5, 32
+    movzx                hd, r3b
+    mov                srcq, r5
+%if ARCH_X86_64
+    add                  r7, 16*4
+    mov                tmpq, r7
+%else
+    mov                tmpq, tmpmp
+    add                tmpq, 16*4
+    mov               tmpmp, tmpq
+%endif
+    sub                 r3d, 1<<8
+    jg .v_w32_hloop
+%if WIN64
+    POP                  r7
+%endif
+    RET
+.hv:
+    ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 8) >> 4
+    ; = src[x] + (((my * (src[x + src_stride] - src[x])) + 8) >> 4)
+    movzx                wd, word [r6+wq*2+table_offset(prep, _bilin_hv)]
+    imul               mxyd, 0x08000800
+    WIN64_SPILL_XMM 8
+    movd                 m6, mxyd
+    add                  wq, r6
+    pshufd               m6, m6, q0000
+    jmp                  wq
+.hv_w4:
+    mova                 m4, [base+bilin_h_shuf4]
+    movddup              m0, [srcq+strideq*0]
+    lea                  r3, [strideq*3]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5            ; _ 0
+.hv_w4_loop:
+    movq                 m1, [srcq+strideq*1]
+    movhps               m1, [srcq+strideq*2]
+    movq                 m2, [srcq+r3       ]
+    lea                srcq, [srcq+strideq*4]
+    movhps               m2, [srcq+strideq*0]
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pmaddubsw            m1, m5            ; 1 2
+    pmaddubsw            m2, m5            ; 3 4
+    shufpd               m0, m1, 0x01      ; 0 1
+    shufpd               m3, m1, m2, 0x01  ; 2 3
+    psubw                m1, m0
+    pmulhrsw             m1, m6
+    paddw                m1, m0
+    mova                 m0, m2
+    psubw                m2, m3
+    pmulhrsw             m2, m6
+    paddw                m2, m3
+    mova        [tmpq+16*0], m1
+    mova        [tmpq+16*1], m2
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    movu                 m0, [srcq+strideq*0]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5 ; 0
+.hv_w8_loop:
+    movu                 m1, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    movu                 m2, [srcq+strideq*0]
+    pshufb               m1, m4
+    pshufb               m2, m4
+    pmaddubsw            m1, m5 ; 1
+    pmaddubsw            m2, m5 ; 2
+    psubw                m3, m1, m0
+    pmulhrsw             m3, m6
+    paddw                m3, m0
+    mova                 m0, m2
+    psubw                m2, m1
+    pmulhrsw             m2, m6
+    paddw                m2, m1
+    mova        [tmpq+16*0], m3
+    mova        [tmpq+16*1], m2
+    add                tmpq, 16*2
+    sub                  hd, 2
+    jg .hv_w8_loop
+    RET
+.hv_w128:
+    lea                 r3d, [hq+(7<<8)]
+    mov                 r5d, 256
+    jmp .hv_w16_start
+.hv_w64:
+    lea                 r3d, [hq+(3<<8)]
+    mov                 r5d, 128
+    jmp .hv_w16_start
+.hv_w32:
+    lea                 r3d, [hq+(1<<8)]
+    mov                 r5d, 64
+    jmp .hv_w16_start
+.hv_w16:
+    xor                 r3d, r3d
+    mov                 r5d, 32
+.hv_w16_start:
+    mov                  r6, srcq
+%if ARCH_X86_64
+ %if WIN64
+    PUSH                 r7
+ %endif
+    mov                  r7, tmpq
+%endif
+.hv_w16_hloop:
+    movu                 m0, [srcq+strideq*0+8*0]
+    movu                 m1, [srcq+strideq*0+8*1]
+    pshufb               m0, m4
+    pshufb               m1, m4
+    pmaddubsw            m0, m5 ; 0a
+    pmaddubsw            m1, m5 ; 0b
+.hv_w16_vloop:
+    movu                 m2, [srcq+strideq*1+8*0]
+    pshufb               m2, m4
+    pmaddubsw            m2, m5 ; 1a
+    psubw                m3, m2, m0
+    pmulhrsw             m3, m6
+    paddw                m3, m0
+    mova        [tmpq+16*0], m3
+    movu                 m3, [srcq+strideq*1+8*1]
+    lea                srcq, [srcq+strideq*2]
+    pshufb               m3, m4
+    pmaddubsw            m3, m5 ; 1b
+    psubw                m0, m3, m1
+    pmulhrsw             m0, m6
+    paddw                m0, m1
+    mova        [tmpq+16*1], m0
+    add                tmpq, r5
+    movu                 m0, [srcq+strideq*0+8*0]
+    pshufb               m0, m4
+    pmaddubsw            m0, m5 ; 2a
+    psubw                m1, m0, m2
+    pmulhrsw             m1, m6
+    paddw                m1, m2
+    mova        [tmpq+16*0], m1
+    movu                 m1, [srcq+strideq*0+8*1]
+    pshufb               m1, m4
+    pmaddubsw            m1, m5 ; 2b
+    psubw                m2, m1, m3
+    pmulhrsw             m2, m6
+    paddw                m2, m3
+    mova        [tmpq+16*1], m2
+    add                tmpq, r5
+    sub                  hd, 2
+    jg .hv_w16_vloop
+    movzx                hd, r3b
+%if ARCH_X86_64
+    add                  r6, 16
+    add                  r7, 2*16
+    mov                srcq, r6
+    mov                tmpq, r7
+%else
+    mov                tmpq, tmpm
+    add                  r6, 16
+    add                tmpq, 2*16
+    mov                srcq, r6
+    mov                tmpm, tmpq
+%endif
+    sub                 r3d, 1<<8
+    jg .hv_w16_hloop
+%if WIN64
+    POP                  r7
+%endif
+    RET
+
+; int8_t subpel_filters[5][15][8]
+%assign FILTER_REGULAR (0*15 << 16) | 3*15
+%assign FILTER_SMOOTH  (1*15 << 16) | 4*15
+%assign FILTER_SHARP   (2*15 << 16) | 3*15
+
+%macro FN 4-5 ; prefix, type, type_h, type_v, jmp_to
+cglobal %1_%2_8bpc
+    mov                 t0d, FILTER_%3
+%ifidn %3, %4
+    mov                 t1d, t0d
+%else
+    mov                 t1d, FILTER_%4
+%endif
+%if %0 == 5 ; skip the jump in the last filter
+    jmp mangle(private_prefix %+ _%5 %+ SUFFIX)
+%endif
+%endmacro
+
+%if ARCH_X86_32
+DECLARE_REG_TMP 1, 2
+%elif WIN64
+DECLARE_REG_TMP 4, 5
+%else
+DECLARE_REG_TMP 7, 8
+%endif
+
+%if ARCH_X86_32
+ %define base_reg r1
+ %define base base_reg-put_ssse3
+%else
+ %define base_reg r8
+ %define base 0
+%endif
+
+%define PUT_8TAP_FN FN put_8tap,
+PUT_8TAP_FN smooth,         SMOOTH,  SMOOTH,  put_6tap_8bpc
+PUT_8TAP_FN smooth_regular, SMOOTH,  REGULAR, put_6tap_8bpc
+PUT_8TAP_FN regular_smooth, REGULAR, SMOOTH,  put_6tap_8bpc
+PUT_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal put_6tap_8bpc, 1, 9, 0, dst, ds, src, ss, w, h, mx, my, ns
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+%if ARCH_X86_64
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+%else
+    imul                ssd, mym, 0x010101
+    add                 ssd, t1d ; 8tap_v, my, 4tap_v
+    mov                srcq, srcm
+%endif
+    mov                  wd, wm
+    movifnidn            hd, hm
+    LEA            base_reg, put_ssse3
+    test                mxd, 0xf00
+    jnz .h
+%if ARCH_X86_32
+    test                ssd, 0xf00
+%else
+    test                myd, 0xf00
+%endif
+    jnz .v
+.put:
+    tzcnt                wd, wd
+    movzx                wd, word [base_reg+wq*2+table_offset(put,)]
+    movifnidn           ssq, ssmp
+    add                  wq, base_reg
+    movifnidn           dsq, dsmp
+%if WIN64
+    pop                  r8
+%endif
+    lea                  r6, [ssq*3]
+    jmp                  wq
+.h:
+%if ARCH_X86_32
+    test                ssd, 0xf00
+%else
+    test                myd, 0xf00
+%endif
+    jnz .hv
+    movifnidn           ssq, ssmp
+    mova                 m5, [base+pw_34] ; 2 + (8 << 2)
+    cmp                  wd, 4
+    jle mangle(private_prefix %+ _put_8tap_8bpc %+ SUFFIX).h_w4
+    WIN64_SPILL_XMM      11
+%if ARCH_X86_64
+    mova                 m8, [base+subpel_h_shufD]
+    mova                 m9, [base+subpel_h_shufE]
+    mova                m10, [base+subpel_h_shufF]
+%endif
+    shr                 mxd, 16
+    sub                srcq, 2
+    movq                 m7, [base_reg-put_ssse3+subpel_filters+1+mxq*8]
+    punpcklwd            m7, m7
+    pshufd               m4, m7, q0000
+    pshufd               m6, m7, q1111
+    pshufd               m7, m7, q2222
+    sub                  wd, 16
+    jge .h_w16
+%macro PUT_6TAP_H 3 ; dst/src, tmp[1-2]
+%if ARCH_X86_32
+    pshufb               %2, %1, [base+subpel_h_shufD]
+    pshufb               %3, %1, [base+subpel_h_shufE]
+    pshufb               %1, [base+subpel_h_shufF]
+%else
+    pshufb               %2, %1, m8
+    pshufb               %3, %1, m9
+    pshufb               %1, m10
+%endif
+    pmaddubsw            %2, m4
+    pmaddubsw            %3, m6
+    pmaddubsw            %1, m7
+    paddw                %2, m5
+    paddw                %2, %3
+    paddw                %1, %2
+    psraw                %1, 6
+%endmacro
+%if ARCH_X86_32
+    mov                  r4, dsm
+%endif
+.h_w8:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    PUT_6TAP_H           m0, m2, m3
+    PUT_6TAP_H           m1, m2, m3
+    packuswb             m0, m1
+%if ARCH_X86_32
+    movq        [dstq+r4*0], m0
+    movhps      [dstq+r4*1], m0
+    lea                dstq, [dstq+r4*2]
+%else
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+%endif
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    add                srcq, wq
+    add                dstq, wq
+    neg                  wq
+.h_w16_loop_v:
+    mov                  r6, wq
+.h_w16_loop_h:
+    movu                 m0, [srcq+r6+8*0]
+    movu                 m1, [srcq+r6+8*1]
+    PUT_6TAP_H           m0, m2, m3
+    PUT_6TAP_H           m1, m2, m3
+    packuswb             m0, m1
+    mova          [dstq+r6], m0
+    add                  r6, 16
+    jle .h_w16_loop_h
+    add                srcq, ssq
+    add                dstq, dsmp
+    dec                  hd
+    jg .h_w16_loop_v
+    RET
+.v:
+%if ARCH_X86_32
+    %define             dsq  r4
+    %define              m8  [base+pw_512]
+    movzx               mxd, ssb
+    shr                 ssd, 16
+    cmp                  hd, 6
+    cmovs               ssd, mxd
+    movq                 m7, [base_reg-put_ssse3+subpel_filters+1+ssq*8]
+    mov                 ssq, ssm
+    punpcklwd            m7, m7
+    pshufd               m5, m7, q0000
+    mov                  r6, ssq
+    pshufd               m6, m7, q1111
+    neg                  r6
+    pshufd               m7, m7, q2222
+    cmp                  wd, 4
+    jge .v_w4
+%else
+    WIN64_SPILL_XMM       9, 12
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m7, [base_reg-put_ssse3+subpel_filters+1+myq*8]
+    mova                 m8, [base+pw_512]
+    punpcklwd            m7, m7
+    pshufd               m5, m7, q0000
+    mov                 nsq, ssq
+    pshufd               m6, m7, q1111
+    neg                 nsq
+    pshufd               m7, m7, q2222
+    cmp                  wd, 4
+    je .v_w4
+    jg .v_w8
+%endif
+.v_w2:
+%if ARCH_X86_32
+    mov                 dsq, dsm
+    movd                 m1, [srcq+r6 *2]
+    movd                 m3, [srcq+r6 *1]
+%else
+    movd                 m1, [srcq+nsq*2]
+    movd                 m3, [srcq+nsq*1]
+%endif
+    movd                 m2, [srcq+ssq*0]
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movd                 m0, [srcq+ssq*0]
+    punpcklwd            m1, m3     ; 0 1
+    punpcklwd            m3, m2     ; 1 2
+    punpcklwd            m2, m4     ; 2 3
+    punpcklwd            m4, m0     ; 3 4
+    punpcklbw            m1, m3     ; 01 12
+    punpcklbw            m2, m4     ; 23 34
+.v_w2_loop:
+    movd                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw            m4, m1, m5 ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, m6     ; a1 b1
+    paddw                m4, m2
+    punpcklwd            m2, m0, m3 ; 4 5
+    movd                 m0, [srcq+ssq*0]
+    punpcklwd            m3, m0     ; 5 6
+    punpcklbw            m2, m3     ; 67 78
+    pmaddubsw            m3, m2, m7 ; a2 b2
+    paddw                m4, m3
+    pmulhrsw             m4, m8
+    packuswb             m4, m4
+    movd                r6d, m4
+    mov        [dstq+dsq*0], r6w
+    shr                 r6d, 16
+    mov        [dstq+dsq*1], r6w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+%if ARCH_X86_32
+    shl                  wd, 14
+    lea                srcq, [srcq+r6*2]
+    lea                 r6d, [hq+wq-(1<<16)]
+    mov                srcm, srcq
+    mov                 dsq, dsm
+.v_w4_loop0:
+    movd                 m1, [srcq+ssq*0]
+    movd                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+%else
+    movd                 m1, [srcq+nsq*2]
+    movd                 m3, [srcq+nsq*1]
+%endif
+    movd                 m2, [srcq+ssq*0]
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m1, m3     ; 0 1
+    punpckldq            m3, m2     ; 1 2
+    punpckldq            m2, m4     ; 2 3
+    punpckldq            m4, m0     ; 3 4
+    punpcklbw            m1, m3     ; 01 12
+    punpcklbw            m2, m4     ; 23 34
+.v_w4_loop:
+    movd                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw            m4, m1, m5 ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, m6     ; a1 b1
+    paddw                m4, m2
+    punpckldq            m2, m0, m3 ; 4 5
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m3, m0     ; 5 6
+    punpcklbw            m2, m3     ; 67 78
+    pmaddubsw            m3, m2, m7 ; a2 b2
+    paddw                m4, m3
+    pmulhrsw             m4, m8
+    packuswb             m4, m4
+    movd       [dstq+dsq*0], m4
+    psrlq                m4, 32
+    movd       [dstq+dsq*1], m4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+%if ARCH_X86_32
+    mov                srcq, srcm
+    mov                dstq, dstm
+    movzx                hd, r6w
+    add                srcq, 4
+    add                dstq, 4
+    mov                srcm, srcq
+    mov                dstm, dstq
+    sub                 r6d, 1<<16
+    jg .v_w4_loop0
+%endif
+    RET
+%if ARCH_X86_64
+.v_w8:
+    WIN64_PUSH_XMM       12
+    shl                  wd, 5
+    lea                 r6d, [hq+wq-256]
+.v_w8_loop0:
+    movq                 m1, [srcq+nsq*2]
+    movq                 m2, [srcq+nsq*1]
+    lea                  r4, [srcq+ssq*2]
+    movq                 m3, [srcq+ssq*0]
+    movq                 m4, [srcq+ssq*1]
+    mov                  r7, dstq
+    movq                 m0, [r4  +ssq*0]
+    punpcklbw            m1, m2     ; 01
+    punpcklbw            m2, m3     ; 12
+    punpcklbw            m3, m4     ; 23
+    punpcklbw            m4, m0     ; 34
+.v_w8_loop:
+    pmaddubsw           m10, m1, m5 ; a0
+    mova                 m1, m3
+    pmaddubsw           m11, m2, m5 ; b0
+    mova                 m2, m4
+    pmaddubsw            m3, m6     ; a1
+    pmaddubsw            m4, m6     ; b1
+    paddw               m10, m3
+    paddw               m11, m4
+    movq                 m4, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+    punpcklbw            m3, m0, m4 ; 67
+    movq                 m0, [r4+ssq*0]
+    punpcklbw            m4, m0     ; 78
+    pmaddubsw            m9, m3, m7 ; a2
+    paddw               m10, m9
+    pmaddubsw            m9, m4, m7 ; b2
+    paddw               m11, m9
+    pmulhrsw            m10, m8
+    pmulhrsw            m11, m8
+    packuswb            m10, m11
+    movq         [r7+dsq*0], m10
+    movhps       [r7+dsq*1], m10
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 8
+    add                dstq, 8
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_w8_loop0
+    RET
+%endif ;ARCH_X86_64
+.hv:
+    RESET_STACK_STATE
+    cmp                  wd, 4
+    jg .hv_w8
+%if ARCH_X86_32
+    and                 mxd, 0x7f
+%else
+    movzx               mxd, mxb
+%endif
+    dec                srcq
+    movd                 m1, [base_reg-put_ssse3+subpel_filters+2+mxq*8]
+%if ARCH_X86_32
+    movzx               mxd, ssb
+    shr                 ssd, 16
+    cmp                  hd, 6
+    cmovs               ssd, mxd
+    movq                 m0, [base_reg-put_ssse3+subpel_filters+1+ssq*8]
+    mov                 ssq, ssmp
+    ALLOC_STACK   -mmsize*4
+    %define              m8  [rsp+mmsize*0]
+    %define              m9  [rsp+mmsize*1]
+    %define             m10  [rsp+mmsize*2]
+    punpcklbw            m0, m0
+    sub                srcq, ssq
+    psraw                m0, 8 ; sign-extend
+    sub                srcq, ssq
+    pshufd               m2, m0, q0000
+    mova                 m8, m2
+    pshufd               m2, m0, q1111
+    mova                 m9, m2
+    pshufd               m2, m0, q2222
+    mova                m10, m2
+%else
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m0, [base_reg-put_ssse3+subpel_filters+1+myq*8]
+    WIN64_SPILL_XMM      11, 14
+    mov                 nsq, ssq
+    punpcklbw            m0, m0
+    neg                 nsq
+    psraw                m0, 8 ; sign-extend
+    pshufd               m8, m0, q0000
+    pshufd               m9, m0, q1111
+    pshufd              m10, m0, q2222
+%endif
+    cmp                  wd, 4
+    je .hv_w4
+.hv_w2:
+    mova                 m5, [base+subpel_h_shuf4]
+    mova                 m6, [base+pw_34]
+    pshufd               m7, m1, q0000
+%if ARCH_X86_32
+    movq                 m2, [srcq+ssq*0]
+    movhps               m2, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov                 dsq, [rstk+stack_offset+gprsize*2]
+%else
+    movq                 m2, [srcq+nsq*2]
+    movhps               m2, [srcq+nsq*1] ; 0 1
+%endif
+    movq                 m1, [srcq+ssq*0]
+    movhps               m1, [srcq+ssq*1] ; 2 3
+    lea                srcq, [srcq+ssq*2]
+    movq                 m0, [srcq+ssq*0] ; 4
+    REPX  {pshufb    x, m5}, m2, m1, m0
+    REPX  {pmaddubsw x, m7}, m2, m1, m0
+    phaddw               m2, m1
+    phaddw               m0, m0
+    paddw                m2, m6
+    paddw                m0, m6
+    psraw                m2, 2            ; 0 1 2 3
+    psraw                m0, 2
+    palignr              m0, m2, 4        ; 1 2 3 4
+    punpcklwd            m1, m2, m0       ; 01 12
+    punpckhwd            m2, m0           ; 23 34
+.hv_w2_loop:
+    movq                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movhps               m3, [srcq+ssq*0] ; 5 6
+    pshufb               m3, m5
+    pmaddubsw            m3, m7
+    pmaddwd              m4, m8, m1       ; a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, m9           ; a1 b1
+    phaddw               m3, m3
+    paddw                m3, m6
+    psraw                m3, 2
+    paddd                m4, m2
+    palignr              m2, m3, m0, 12   ; 4 5
+    mova                 m0, m3
+    punpcklwd            m2, m3           ; 45 56
+    pmaddwd              m3, m10, m2      ; a2 b2
+    paddd                m4, m3
+    psrad                m4, 10
+    packssdw             m4, m5
+    packuswb             m4, m4
+    movd                r6d, m4
+    mov        [dstq+dsq*0], r6w
+    shr                 r6d, 16
+    mov        [dstq+dsq*1], r6w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+.hv_w4:
+%if ARCH_X86_32
+    movq                 m3, [srcq+ssq*0]
+    movq                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mov                 dsq, [rstk+stack_offset+gprsize*2]
+    %define             m11  [base+pw_34]
+    %define             m12  [base+subpel_h_shufA]
+    %define             m13  [rsp+mmsize*3]
+    pshufd               m1, m1, q0000
+    mova                m13, m1
+%else
+    WIN64_PUSH_XMM       14
+    movq                 m3, [srcq+nsq*2]
+    movq                 m4, [srcq+nsq*1]
+    pshufd              m13, m1, q0000
+    mova                m12, [base+subpel_h_shufA]
+    mova                m11, [base+pw_34]
+%endif
+    movq                 m0, [srcq+ssq*0]
+    movq                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m2, [srcq+ssq*0]
+%if ARCH_X86_32
+    mova                 m5, m12
+    mova                 m6, m13
+    REPX {pshufb    x, m5 }, m3, m4, m0, m1, m2
+    mova                 m5, m11
+    REPX {pmaddubsw x, m6 }, m3, m4, m0, m1, m2
+%else
+    REPX {pshufb    x, m12}, m3, m4, m0, m1, m2
+    REPX {pmaddubsw x, m13}, m3, m4, m0, m1, m2
+%endif
+    phaddw               m3, m0      ; 0 2
+    phaddw               m4, m1      ; 1 3
+    phaddw               m0, m2      ; 2 4
+%if ARCH_X86_32
+    REPX     {paddw x, m5 }, m3, m4, m0
+%else
+    REPX     {paddw x, m11}, m3, m4, m0
+%endif
+    REPX     {psraw x, 2  }, m3, m4, m0
+    punpcklwd            m1, m3, m4  ; 01
+    punpckhwd            m3, m4      ; 23
+    punpcklwd            m2, m4, m0  ; 12
+    punpckhwd            m4, m0      ; 34
+.hv_w4_loop:
+    movq                 m7, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m6, [srcq+ssq*0]
+    pshufb               m7, m12
+    pshufb               m6, m12
+    pmaddubsw            m7, m13
+    pmaddubsw            m6, m13
+    pmaddwd              m5, m8, m1  ; a0
+    mova                 m1, m3
+    phaddw               m7, m6      ; 5 6
+    pmaddwd              m6, m8, m2  ; b0
+    mova                 m2, m4
+    pmaddwd              m3, m9      ; a1
+    pmaddwd              m4, m9      ; b1
+    paddw                m7, m11
+    psraw                m7, 2
+    paddd                m5, m3
+    paddd                m6, m4
+    shufpd               m4, m0, m7, 0x01 ; 4 5
+    mova                 m0, m7
+    punpcklwd            m3, m4, m7  ; 45
+    punpckhwd            m4, m7      ; 56
+    pmaddwd              m7, m10, m3 ; a2
+    paddd                m5, m7
+    pmaddwd              m7, m10, m4 ; b2
+    paddd                m6, m7
+    psrad                m5, 10
+    psrad                m6, 10
+    packssdw             m5, m6
+    packuswb             m5, m5
+    movd       [dstq+dsq*0], m5
+    psrlq                m5, 32
+    movd       [dstq+dsq*1], m5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    RESET_STACK_STATE
+    shr                 mxd, 16
+    sub                srcq, 2
+%if ARCH_X86_32
+    movq                 m0, [base_reg-put_ssse3+subpel_filters+1+mxq*8]
+    movzx               mxd, ssb
+    shr                 ssd, 16
+    cmp                  hd, 6
+    cmovs               ssd, mxd
+    movq                 m1, [base_reg-put_ssse3+subpel_filters+1+ssq*8]
+    shl                  wd, 13
+    mov                 ssq, ssm
+    lea                 r6d, [hq+wq-(1<<16)]
+%assign regs_used 5
+    ALLOC_STACK  -mmsize*16
+%assign regs_used 7
+    mov                 dsq, [rstk+stack_offset+gprsize*2]
+    sub                srcq, ssq
+    sub                srcq, ssq
+%if STACK_ALIGNMENT < 16
+    %define            srcm  [esp+mmsize*15+gprsize*0]
+    %define            dstm  [esp+mmsize*15+gprsize*1]
+    mov                dstm, dstq
+%endif
+    mov                srcm, srcq
+%else
+    ALLOC_STACK        16*6, 16
+    movq                 m0, [base_reg-put_ssse3+subpel_filters+1+mxq*8]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m1, [base_reg-put_ssse3+subpel_filters+1+myq*8]
+    mov                 nsq, ssq
+    shl                  wd, 13
+    neg                 nsq
+    lea                 r6d, [hq+wq-(1<<16)]
+%endif
+    mova                 m7, [base+pw_34]
+    punpcklwd            m0, m0
+    punpcklbw            m1, m1
+    psraw                m1, 8 ; sign-extend
+    pshufd               m2, m0, q0000
+    mova         [rsp+16*0], m2
+    pshufd               m2, m0, q1111
+    mova         [rsp+16*1], m2
+    pshufd               m0, m0, q2222
+    mova         [rsp+16*2], m0
+    pshufd               m2, m1, q0000
+    mova         [rsp+16*3], m2
+    pshufd               m2, m1, q1111
+    mova         [rsp+16*4], m2
+    pshufd               m1, m1, q2222
+    mova         [rsp+16*5], m1
+%macro HV_H_6TAP 3-8 [base+subpel_h_shufD], [base+subpel_h_shufF], \
+                     [rsp+16*0], [rsp+16*1], [rsp+16*2] ; src/dst, tmp[1-2], shuf[1-2], mul[1-3]
+    pshufb               %2, %1, %4
+    pshufb               %1, %5
+    pmaddubsw            %3, %2, %6
+    shufps               %2, %1, q2121
+    pmaddubsw            %1, %8
+    pmaddubsw            %2, %7
+    paddw                %3, m7
+    paddw                %1, %3
+    paddw                %1, %2
+    psraw                %1, 2
+%endmacro
+.hv_w8_loop0:
+    mova                 m2, [base+subpel_h_shufD]
+    mova                 m3, [base+subpel_h_shufF]
+    mova                 m4, [rsp+16*0]
+%if ARCH_X86_32
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    HV_H_6TAP            m0, m5, m6, m2, m3, m4
+    HV_H_6TAP            m1, m5, m6, m2, m3, m4
+    movu                 m5, [srcq+ssq*0]
+    punpcklwd            m6, m0, m1   ; 01
+    punpckhwd            m0, m1
+    mova        [rsp+16* 6], m6
+    mova        [rsp+16* 7], m0
+    HV_H_6TAP            m5, m0, m6, m2, m3, m4
+    movu                 m0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklwd            m6, m1, m5   ; 12
+    punpckhwd            m1, m5
+    mova        [rsp+16* 8], m6
+    mova        [rsp+16* 9], m1
+    HV_H_6TAP            m0, m1, m6, m2, m3, m4
+    movu                 m1, [srcq+ssq*0]
+    punpcklwd            m6, m5, m0   ; 23
+    punpckhwd            m5, m0
+    mova        [rsp+16*10], m6
+    mova        [rsp+16*11], m5
+    HV_H_6TAP            m1, m5, m6, m2, m3, m4
+    mova        [rsp+16*14], m1
+    punpcklwd            m6, m0, m1   ; 34
+    punpckhwd            m0, m1
+    mova        [rsp+16*12], m6
+    mova        [rsp+16*13], m0
+.hv_w8_loop:
+    mova                 m3, [rsp+16* 3]
+    pmaddwd              m0, m3, [rsp+16* 6] ; a0
+    pmaddwd              m2, m3, [rsp+16* 7] ; a0'
+    pmaddwd              m1, m3, [rsp+16* 8] ; b0
+    pmaddwd              m3, [rsp+16* 9]     ; b0'
+    mova                 m6, [rsp+16* 4]
+    mova                 m4, [rsp+16*10]
+    mova                 m5, [rsp+16*11]
+    mova        [rsp+16* 6], m4
+    pmaddwd              m4, m6       ; a1
+    mova        [rsp+16* 7], m5
+    pmaddwd              m5, m6       ; a1'
+    paddd                m0, m4
+    mova                 m4, [rsp+16*12]
+    paddd                m2, m5
+    mova                 m5, [rsp+16*13]
+    mova        [rsp+16* 8], m4
+    pmaddwd              m4, m6       ; b1
+    mova        [rsp+16* 9], m5
+    pmaddwd              m5, m6       ; b1'
+    movu                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    paddd                m1, m4
+    paddd                m3, m5
+    HV_H_6TAP            m6, m4, m5
+    mova                 m5, [rsp+16*14]
+    punpcklwd            m4, m5, m6   ; 45
+    punpckhwd            m5, m6
+    mova        [rsp+16*10], m4
+    mova        [rsp+16*11], m5
+    pmaddwd              m4, [rsp+16*5] ; a2
+    pmaddwd              m5, [rsp+16*5] ; a2'
+    paddd                m0, m4
+    movu                 m4, [srcq+ssq*0]
+    paddd                m2, m5
+    psrad                m0, 10
+    psrad                m2, 10
+    packssdw             m0, m2
+    HV_H_6TAP            m4, m2, m5
+    mova                 m2, [rsp+16*5]
+    punpcklwd            m5, m6, m4   ; 56
+    mova        [rsp+16*14], m4
+    punpckhwd            m6, m4
+    mova        [rsp+16*12], m5
+    pmaddwd              m5, m2       ; b2
+    mova        [rsp+16*13], m6
+    pmaddwd              m6, m2       ; b2'
+    paddd                m1, m5
+    paddd                m3, m6
+    psrad                m1, 10
+    psrad                m3, 10
+    packssdw             m1, m3
+    packuswb             m0, m1
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    mov                srcq, srcm
+    mov                dstq, dstm
+    movzx                hd, r6w
+    add                srcq, 8
+    add                dstq, 8
+    mov                srcm, srcq
+    mov                dstm, dstq
+%else
+    movu                 m9, [srcq+nsq*2]
+    movu                m11, [srcq+nsq*1]
+    lea                  r4, [srcq+ssq*2]
+    movu                m13, [srcq+ssq*0]
+    movu                m15, [srcq+ssq*1]
+    mov                  r7, dstq
+    movu                 m6, [r4  +ssq*0]
+    mova                 m5, [rsp+16*1]
+    mova                 m8, [rsp+16*2]
+    HV_H_6TAP            m9, m0, m1, m2, m3, m4, m5, m8
+    HV_H_6TAP           m11, m0, m1, m2, m3, m4, m5, m8
+    HV_H_6TAP           m13, m0, m1, m2, m3, m4, m5, m8
+    HV_H_6TAP           m15, m0, m1, m2, m3, m4, m5, m8
+    HV_H_6TAP            m6, m0, m1, m2, m3, m4, m5, m8
+    punpcklwd            m8, m9, m11  ; 01
+    punpckhwd            m9, m11
+    punpcklwd           m10, m11, m13 ; 12
+    punpckhwd           m11, m13
+    punpcklwd           m12, m13, m15 ; 23
+    punpckhwd           m13, m15
+    punpcklwd           m14, m15, m6  ; 34
+    punpckhwd           m15, m6
+.hv_w8_loop:
+    mova                 m3, [rsp+16*3]
+    mova                 m4, [rsp+16*4]
+    pmaddwd              m0, m8, m3  ; a0
+    mova                 m8, m12
+    pmaddwd              m2, m9, m3  ; a0'
+    mova                 m9, m13
+    pmaddwd              m1, m10, m3 ; b0
+    mova                m10, m14
+    pmaddwd              m3, m11     ; b0'
+    mova                m11, m15
+    REPX    {pmaddwd x, m4}, m12, m13, m14, m15
+    paddd                m0, m12
+    paddd                m2, m13
+    paddd                m1, m14
+    paddd                m3, m15
+    movu                m15, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+    HV_H_6TAP           m15, m4, m5
+    punpcklwd           m12, m6, m15
+    punpckhwd           m13, m6, m15
+    movu                 m6, [r4+ssq*0]
+    HV_H_6TAP            m6, m4, m5
+    mova                 m4, [rsp+16*5]
+    punpcklwd           m14, m15, m6
+    punpckhwd           m15, m6
+    pmaddwd              m5, m12, m4  ; a2
+    paddd                m0, m5
+    pmaddwd              m5, m13, m4  ; a2'
+    paddd                m2, m5
+    pmaddwd              m5, m14, m4  ; b2
+    paddd                m1, m5
+    pmaddwd              m4, m15      ; b2'
+    paddd                m3, m4
+    REPX      {psrad x, 10}, m0, m2, m1, m3
+    packssdw             m0, m2
+    packssdw             m1, m3
+    packuswb             m0, m1
+    movq         [r7+dsq*0], m0
+    movhps       [r7+dsq*1], m0
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 8
+    add                dstq, 8
+    movzx                hd, r6b
+%endif
+    sub                 r6d, 1<<16
+    jg .hv_w8_loop0
+    RET
+
+PUT_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_8bpc
+PUT_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  put_8tap_8bpc
+PUT_8TAP_FN regular_sharp,  REGULAR, SHARP,   put_8tap_8bpc
+PUT_8TAP_FN sharp_regular,  SHARP,   REGULAR, put_8tap_8bpc
+PUT_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal put_8tap_8bpc, 1, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+%if ARCH_X86_64
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+%else
+    imul                ssd, mym, 0x010101
+    add                 ssd, t1d ; 8tap_v, my, 4tap_v
+    mov                srcq, srcm
+%endif
+    mov                  wd, wm
+    movifnidn            hd, hm
+    LEA            base_reg, put_ssse3
+    test                mxd, 0xf00
+    jnz .h
+%if ARCH_X86_32
+    test                ssd, 0xf00
+%else
+    test                myd, 0xf00
+%endif
+    jnz .v
+    tzcnt                wd, wd
+    movzx                wd, word [base_reg+wq*2+table_offset(put,)]
+    movifnidn           ssq, ssmp
+    add                  wq, base_reg
+    movifnidn           dsq, dsmp
+%if WIN64
+    pop                  r8
+%endif
+    lea                  r6, [ssq*3]
+    jmp                  wq
+.h_w2:
+    mova                 m3, [base+subpel_h_shuf4]
+    movifnidn           dsq, dsmp
+.h_w2_loop:
+    movq                 m0, [srcq+ssq*0]
+    movhps               m0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m0, m3
+    pmaddubsw            m0, m4
+    phaddw               m0, m0
+    paddw                m0, m5 ; pw34
+    psraw                m0, 6
+    packuswb             m0, m0
+    movd                r6d, m0
+    mov        [dstq+dsq*0], r6w
+    shr                 r6d, 16
+    mov        [dstq+dsq*1], r6w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w2_loop
+    RET
+.h_w4:
+%if ARCH_X86_32
+    and                 mxd, 0x7f
+%else
+    movzx               mxd, mxb
+%endif
+    movd                 m4, [base_reg+mxq*8+subpel_filters-put_ssse3+2]
+    dec                srcq
+    pshufd               m4, m4, q0000
+    cmp                  wd, 4
+    jl .h_w2
+    mova                 m3, [base+subpel_h_shufA]
+    movifnidn           dsq, dsmp
+.h_w4_loop:
+    movq                 m0, [srcq+ssq*0] ; 1
+    movq                 m1, [srcq+ssq*1] ; 2
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m0, m3 ; subpel_h_shufA
+    pshufb               m1, m3 ; subpel_h_shufA
+    pmaddubsw            m0, m4 ; subpel_filters
+    pmaddubsw            m1, m4 ; subpel_filters
+    phaddw               m0, m1
+    paddw                m0, m5 ; pw34
+    psraw                m0, 6
+    packuswb             m0, m0
+    movd       [dstq+dsq*0], m0
+    psrlq                m0, 32
+    movd       [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .h_w4_loop
+    RET
+.h:
+%if ARCH_X86_32
+    test                ssd, 0xf00
+%else
+    test                myd, 0xf00
+%endif
+    jnz .hv
+    movifnidn           ssq, ssmp
+    mova                 m5, [base+pw_34] ; 2 + (8 << 2)
+    cmp                  wd, 4
+    jle .h_w4
+    WIN64_SPILL_XMM      12
+%if ARCH_X86_64
+    mova                m10, [base+subpel_h_shufA]
+    mova                m11, [base+subpel_h_shufB]
+    mova                 m9, [base+subpel_h_shufC]
+%endif
+    shr                 mxd, 16
+    sub                srcq, 3
+    movq                 m7, [base_reg+mxq*8+subpel_filters-put_ssse3]
+    pshufd               m6, m7, q0000
+    pshufd               m7, m7, q1111
+    sub                  wd, 16
+    jge .h_w16
+%macro PUT_8TAP_H 4 ; dst/src, tmp[1-3]
+ %if ARCH_X86_32
+    pshufb              %2, %1, [base+subpel_h_shufB]
+    pshufb              %3, %1, [base+subpel_h_shufC]
+    pshufb              %1,     [base+subpel_h_shufA]
+ %else
+    pshufb              %2, %1, m11; subpel_h_shufB
+    pshufb              %3, %1, m9 ; subpel_h_shufC
+    pshufb              %1, m10    ; subpel_h_shufA
+ %endif
+    pmaddubsw           %4, %2, m6 ; subpel +0 B0
+    pmaddubsw           %2, m7     ; subpel +4 B4
+    pmaddubsw           %3, m7     ; C4
+    pmaddubsw           %1, m6     ; A0
+    paddw               %3, %4     ; C4+B0
+    paddw               %1, %2     ; A0+B4
+    phaddw              %1, %3
+    paddw               %1, m5     ; pw34
+    psraw               %1, 6
+%endmacro
+.h_w8:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    PUT_8TAP_H           m0, m2, m3, m4
+    PUT_8TAP_H           m1, m2, m3, m4
+    packuswb             m0, m1
+%if ARCH_X86_32
+    movq             [dstq], m0
+    add                dstq, dsm
+    movhps           [dstq], m0
+    add                dstq, dsm
+%else
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+%endif
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    add                srcq, wq
+    add                dstq, wq
+    neg                  wq
+.h_w16_loop_v:
+    mov                  r6, wq
+.h_w16_loop_h:
+    movu                 m0, [srcq+r6+8*0]
+    movu                 m1, [srcq+r6+8*1]
+    PUT_8TAP_H           m0, m2, m3, m4
+    PUT_8TAP_H           m1, m2, m3, m4
+    packuswb             m0, m1
+    mova          [dstq+r6], m0
+    add                  r6, 16
+    jle .h_w16_loop_h
+    add                srcq, ssq
+    add                dstq, dsmp
+    dec                  hd
+    jg .h_w16_loop_v
+    RET
+.v:
+%if ARCH_X86_32
+    movzx               mxd, ssb
+    shr                 ssd, 16
+    cmp                  hd, 6
+    cmovs               ssd, mxd
+    movq                 m0, [base_reg+ssq*8+subpel_filters-put_ssse3]
+%else
+    WIN64_SPILL_XMM      16
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m0, [base_reg+myq*8+subpel_filters-put_ssse3]
+%endif
+    punpcklwd            m0, m0
+    mova                 m7, [base+pw_512]
+%if ARCH_X86_32
+ %define            subpel0  [rsp+mmsize*0]
+ %define            subpel1  [rsp+mmsize*1]
+ %define            subpel2  [rsp+mmsize*2]
+ %define            subpel3  [rsp+mmsize*3]
+%assign regs_used 2 ; use r1 (ds) as tmp for stack alignment if needed
+    ALLOC_STACK       -16*4
+%assign regs_used 7
+    pshufd               m1, m0, q0000
+    mova            subpel0, m1
+    pshufd               m1, m0, q1111
+    mova            subpel1, m1
+    pshufd               m1, m0, q2222
+    mova            subpel2, m1
+    pshufd               m1, m0, q3333
+    mova            subpel3, m1
+    mov                 ssq, [rstk+stack_offset+gprsize*4]
+    lea                 ssq, [ssq*3]
+    sub                srcq, ssq
+    mov                 ssq, [rstk+stack_offset+gprsize*4]
+    mov                 dsq, [rstk+stack_offset+gprsize*2]
+    cmp                  wd, 2
+    jne .v_w4
+%else
+ %define            subpel0  m8
+ %define            subpel1  m9
+ %define            subpel2  m10
+ %define            subpel3  m11
+    lea                ss3q, [ssq*3]
+    pshufd               m8, m0, q0000
+    sub                srcq, ss3q
+    pshufd               m9, m0, q1111
+    pshufd              m10, m0, q2222
+    pshufd              m11, m0, q3333
+    cmp                  wd, 4
+    je .v_w4
+    jg .v_w8
+%endif
+.v_w2:
+    movd                 m1, [srcq+ssq*0]
+    movd                 m0, [srcq+ssq*1]
+%if ARCH_X86_32
+    lea                srcq, [srcq+ssq*2]
+    movd                 m2, [srcq+ssq*0]
+    movd                 m5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movd                 m3, [srcq+ssq*0]
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+%else
+    movd                 m2, [srcq+ssq*2]
+    add                srcq, ss3q
+    movd                 m5, [srcq+ssq*0]
+    movd                 m3, [srcq+ssq*1]
+    movd                 m4, [srcq+ssq*2]
+    add                srcq, ss3q
+%endif
+    punpcklwd            m1, m0           ; 0 1
+    punpcklwd            m0, m2           ; 1 2
+    punpcklbw            m1, m0           ; 01 12
+    movd                 m0, [srcq+ssq*0]
+    punpcklwd            m2, m5           ; 2 3
+    punpcklwd            m5, m3           ; 3 4
+    punpcklwd            m3, m4           ; 4 5
+    punpcklwd            m4, m0           ; 5 6
+    punpcklbw            m2, m5           ; 23 34
+    punpcklbw            m3, m4           ; 45 56
+.v_w2_loop:
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw            m5, m1, subpel0     ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, subpel1         ; a1 b1
+    paddw                m5, m2
+    mova                 m2, m3
+    pmaddubsw            m3, subpel2         ; a2 b2
+    paddw                m5, m3
+    punpcklwd            m3, m0, m4          ; 6 7
+    movd                 m0, [srcq+ssq*0]
+    punpcklwd            m4, m0              ; 7 8
+    punpcklbw            m3, m4              ; 67 78
+    pmaddubsw            m4, m3, subpel3     ; a3 b3
+    paddw                m5, m4
+    pmulhrsw             m5, m7
+    packuswb             m5, m5
+    movd                r6d, m5
+    mov        [dstq+dsq*0], r6w
+    shr                 r6d, 16
+    mov        [dstq+dsq*1], r6w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w2_loop
+    RET
+.v_w4:
+%if ARCH_X86_32
+    shl                  wd, 14
+%if STACK_ALIGNMENT < 16
+ %define               dstm [rsp+mmsize*4+gprsize]
+    mov                dstm, dstq
+%endif
+    lea                 r6d, [hq+wq-(1<<16)]
+    mov                  r4, srcq
+.v_w4_loop0:
+%endif
+    movd                 m1, [srcq+ssq*0]
+    movd                 m0, [srcq+ssq*1]
+%if ARCH_X86_32
+    lea                srcq, [srcq+ssq*2]
+    movd                 m2, [srcq+ssq*0]
+    movd                 m5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movd                 m3, [srcq+ssq*0]
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+%else
+    movd                 m2, [srcq+ssq*2]
+    add                srcq, ss3q
+    movd                 m5, [srcq+ssq*0]
+    movd                 m3, [srcq+ssq*1]
+    movd                 m4, [srcq+ssq*2]
+    add                srcq, ss3q
+%endif
+    punpckldq            m1, m0           ; 0 1
+    punpckldq            m0, m2           ; 1 2
+    punpcklbw            m1, m0           ; 01 12
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m2, m5           ; 2 3
+    punpckldq            m5, m3           ; 3 4
+    punpckldq            m3, m4           ; 4 5
+    punpckldq            m4, m0           ; 5 6
+    punpcklbw            m2, m5           ; 23 34
+    punpcklbw            m3, m4           ; 45 56
+.v_w4_loop:
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw            m5, m1, subpel0  ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, subpel1      ; a1 b1
+    paddw                m5, m2
+    mova                 m2, m3
+    pmaddubsw            m3, subpel2      ; a2 b2
+    paddw                m5, m3
+    punpckldq            m3, m0, m4       ; 6 7 _ _
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m4, m0           ; 7 8 _ _
+    punpcklbw            m3, m4           ; 67 78
+    pmaddubsw            m4, m3, subpel3  ; a3 b3
+    paddw                m5, m4
+    pmulhrsw             m5, m7
+    packuswb             m5, m5
+    movd       [dstq+dsq*0], m5
+    psrlq                m5, 32
+    movd       [dstq+dsq*1], m5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .v_w4_loop
+%if ARCH_X86_32
+    mov                dstq, dstm
+    add                  r4, 4
+    movzx                hd, r6w
+    add                dstq, 4
+    mov                srcq, r4
+    mov                dstm, dstq
+    sub                 r6d, 1<<16
+    jg .v_w4_loop0
+%endif
+    RET
+%if ARCH_X86_64
+.v_w8:
+    shl                  wd, 5
+    lea                 r6d, [hq+wq-256]
+.v_w8_loop0:
+    movq                 m1, [srcq+ssq*0]
+    movq                 m2, [srcq+ssq*1]
+    lea                  r4, [srcq+ss3q]
+    movq                 m3, [srcq+ssq*2]
+    movq                 m4, [r4  +ssq*0]
+    mov                  r7, dstq
+    movq                 m5, [r4  +ssq*1]
+    movq                 m6, [r4  +ssq*2]
+    add                  r4, ss3q
+    movq                 m0, [r4  +ssq*0]
+    punpcklbw            m1, m2 ; 01
+    punpcklbw            m2, m3 ; 12
+    punpcklbw            m3, m4 ; 23
+    punpcklbw            m4, m5 ; 34
+    punpcklbw            m5, m6 ; 45
+    punpcklbw            m6, m0 ; 56
+.v_w8_loop:
+    movq                m13, [r4+ssq*1]
+    lea                  r4, [r4+ssq*2]
+    pmaddubsw           m14, m1, subpel0 ; a0
+    mova                 m1, m3
+    pmaddubsw           m15, m2, subpel0 ; b0
+    mova                 m2, m4
+    pmaddubsw            m3, subpel1 ; a1
+    mova                m12, m0
+    pmaddubsw            m4, subpel1 ; b1
+    movq                 m0, [r4+ssq*0]
+    paddw               m14, m3
+    paddw               m15, m4
+    mova                 m3, m5
+    pmaddubsw            m5, subpel2 ; a2
+    mova                 m4, m6
+    pmaddubsw            m6, subpel2 ; b2
+    punpcklbw           m12, m13     ; 67
+    punpcklbw           m13, m0      ; 78
+    paddw               m14, m5
+    mova                 m5, m12
+    pmaddubsw           m12, subpel3 ; a3
+    paddw               m15, m6
+    mova                 m6, m13
+    pmaddubsw           m13, subpel3 ; b3
+    paddw               m14, m12
+    paddw               m15, m13
+    pmulhrsw            m14, m7
+    pmulhrsw            m15, m7
+    packuswb            m14, m15
+    movq         [r7+dsq*0], m14
+    movhps       [r7+dsq*1], m14
+    lea                  r7, [r7+dsq*2]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 8
+    add                dstq, 8
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_w8_loop0
+    RET
+%endif ;ARCH_X86_64
+%undef subpel0
+%undef subpel1
+%undef subpel2
+%undef subpel3
+.hv:
+    RESET_STACK_STATE
+    cmp                  wd, 4
+    jg .hv_w8
+%if ARCH_X86_32
+    and                 mxd, 0x7f
+%else
+    movzx               mxd, mxb
+%endif
+    dec                srcq
+    movd                 m1, [base_reg+mxq*8+subpel_filters-put_ssse3+2]
+%if ARCH_X86_32
+    movzx               mxd, ssb
+    shr                 ssd, 16
+    cmp                  hd, 6
+    cmovs               ssd, mxd
+    movq                 m0, [base_reg+ssq*8+subpel_filters-put_ssse3]
+    mov                 ssq, ssmp
+    lea                  r6, [ssq*3]
+    sub                srcq, r6
+ %define           base_reg  r6
+    mov                  r6, r1; use as new base
+ %assign regs_used 2
+    ALLOC_STACK  -mmsize*14
+ %assign regs_used 7
+    mov                 dsq, [rstk+stack_offset+gprsize*2]
+ %define           subpelv0  [rsp+mmsize*0]
+ %define           subpelv1  [rsp+mmsize*1]
+ %define           subpelv2  [rsp+mmsize*2]
+ %define           subpelv3  [rsp+mmsize*3]
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    pshufd               m6, m0, q0000
+    mova           subpelv0, m6
+    pshufd               m6, m0, q1111
+    mova           subpelv1, m6
+    pshufd               m6, m0, q2222
+    mova           subpelv2, m6
+    pshufd               m6, m0, q3333
+    mova           subpelv3, m6
+%else
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m0, [base_reg+myq*8+subpel_filters-put_ssse3]
+    ALLOC_STACK   mmsize*14, 14
+    lea                ss3q, [ssq*3]
+    sub                srcq, ss3q
+ %define           subpelv0  m10
+ %define           subpelv1  m11
+ %define           subpelv2  m12
+ %define           subpelv3  m13
+    punpcklbw            m0, m0
+    psraw                m0, 8 ; sign-extend
+    mova                 m8, [base+pw_8192]
+    mova                 m9, [base+pd_512]
+    pshufd              m10, m0, q0000
+    pshufd              m11, m0, q1111
+    pshufd              m12, m0, q2222
+    pshufd              m13, m0, q3333
+%endif
+    pshufd               m7, m1, q0000
+    cmp                  wd, 4
+    je .hv_w4
+.hv_w2:
+    mova                 m6, [base+subpel_h_shuf4]
+    movq                 m2, [srcq+ssq*0]     ; 0
+    movhps               m2, [srcq+ssq*1]     ; 0 _ 1
+%if ARCH_X86_32
+ %define           w8192reg  [base+pw_8192]
+ %define            d512reg  [base+pd_512]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m0, [srcq+ssq*0]     ; 2
+    movhps               m0, [srcq+ssq*1]     ; 2 _ 3
+    lea                srcq, [srcq+ssq*2]
+%else
+ %define           w8192reg  m8
+ %define            d512reg  m9
+    movq                 m0, [srcq+ssq*2]     ; 2
+    add                srcq, ss3q
+    movhps               m0, [srcq+ssq*0]     ; 2 _ 3
+%endif
+    pshufb               m2, m6 ; 0 ~ 1 ~
+    pshufb               m0, m6 ; 2 ~ 3 ~
+    pmaddubsw            m2, m7 ; subpel_filters
+    pmaddubsw            m0, m7 ; subpel_filters
+    phaddw               m2, m0 ; 0 1 2 3
+    pmulhrsw             m2, w8192reg
+%if ARCH_X86_32
+    movq                 m3, [srcq+ssq*0]     ; 4
+    movhps               m3, [srcq+ssq*1]     ; 4 _ 5
+    lea                srcq, [srcq+ssq*2]
+%else
+    movq                 m3, [srcq+ssq*1]     ; 4
+    movhps               m3, [srcq+ssq*2]     ; 4 _ 5
+    add                srcq, ss3q
+%endif
+    movq                 m0, [srcq+ssq*0]     ; 6
+    pshufb               m3, m6 ; 4 ~ 5 ~
+    pshufb               m0, m6 ; 6 ~
+    pmaddubsw            m3, m7 ; subpel_filters
+    pmaddubsw            m0, m7 ; subpel_filters
+    phaddw               m3, m0 ; 4 5 6 _
+    pmulhrsw             m3, w8192reg
+    palignr              m4, m3, m2, 4; V        1 2 3 4
+    punpcklwd            m1, m2, m4   ; V 01 12    0 1 1 2
+    punpckhwd            m2, m4       ; V 23 34    2 3 3 4
+    pshufd               m0, m3, q2121; V          5 6 5 6
+    punpcklwd            m3, m0       ; V 45 56    4 5 5 6
+.hv_w2_loop:
+    movq                 m4, [srcq+ssq*1] ; V 7
+    lea                srcq, [srcq+ssq*2] ; V
+    movhps               m4, [srcq+ssq*0] ; V 7 8
+    pshufb               m4, m6
+    pmaddubsw            m4, m7
+    pmaddwd              m5, m1, subpelv0; V a0 b0
+    mova                 m1, m2       ; V
+    pmaddwd              m2, subpelv1 ; V a1 b1
+    paddd                m5, m2       ; V
+    mova                 m2, m3       ; V
+    pmaddwd              m3, subpelv2 ; a2 b2
+    phaddw               m4, m4
+    pmulhrsw             m4, w8192reg
+    paddd                m5, m3       ; V
+    palignr              m3, m4, m0, 12
+    mova                 m0, m4
+    punpcklwd            m3, m0           ; V 67 78
+    pmaddwd              m4, m3, subpelv3 ; V a3 b3
+    paddd                m5, d512reg
+    paddd                m5, m4
+    psrad                m5, 10
+    packssdw             m5, m5
+    packuswb             m5, m5
+    movd                r4d, m5
+    mov        [dstq+dsq*0], r4w
+    shr                 r4d, 16
+    mov        [dstq+dsq*1], r4w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .hv_w2_loop
+    RET
+%undef w8192reg
+%undef d512reg
+.hv_w4:
+%define hv4_line_0_0 4
+%define hv4_line_0_1 5
+%define hv4_line_0_2 6
+%define hv4_line_0_3 7
+%define hv4_line_0_4 8
+%define hv4_line_0_5 9
+%define hv4_line_1_0 10
+%define hv4_line_1_1 11
+%define hv4_line_1_2 12
+%define hv4_line_1_3 13
+%macro SAVELINE_W4 3
+    mova     [rsp+mmsize*hv4_line_%3_%2], %1
+%endmacro
+%macro RESTORELINE_W4 3
+    mova     %1, [rsp+mmsize*hv4_line_%3_%2]
+%endmacro
+%if ARCH_X86_32
+ %define           w8192reg  [base+pw_8192]
+ %define            d512reg  [base+pd_512]
+%else
+ %define           w8192reg  m8
+ %define            d512reg  m9
+%endif
+    ; lower shuffle 0 1 2 3 4
+    mova                 m6, [base+subpel_h_shuf4]
+    movq                 m5, [srcq+ssq*0]   ; 0 _ _ _
+    movhps               m5, [srcq+ssq*1]   ; 0 _ 1 _
+%if ARCH_X86_32
+    lea                srcq, [srcq+ssq*2]
+    movq                 m4, [srcq+ssq*0]   ; 2 _ _ _
+    movhps               m4, [srcq+ssq*1]   ; 2 _ 3 _
+    lea                srcq, [srcq+ssq*2]
+%else
+    movq                 m4, [srcq+ssq*2]   ; 2 _ _ _
+    movhps               m4, [srcq+ss3q ]   ; 2 _ 3 _
+    lea                srcq, [srcq+ssq*4]
+%endif
+    pshufb               m2, m5, m6 ;H subpel_h_shuf4 0 ~ 1 ~
+    pshufb               m0, m4, m6 ;H subpel_h_shuf4 2 ~ 3 ~
+    pmaddubsw            m2, m7 ;H subpel_filters
+    pmaddubsw            m0, m7 ;H subpel_filters
+    phaddw               m2, m0 ;H 0 1 2 3
+    pmulhrsw             m2, w8192reg ;H pw_8192
+    SAVELINE_W4          m2, 2, 0
+    ; upper shuffle 2 3 4 5 6
+    mova                 m6, [base+subpel_h_shuf4+16]
+    pshufb               m2, m5, m6 ;H subpel_h_shuf4 0 ~ 1 ~
+    pshufb               m0, m4, m6 ;H subpel_h_shuf4 2 ~ 3 ~
+    pmaddubsw            m2, m7 ;H subpel_filters
+    pmaddubsw            m0, m7 ;H subpel_filters
+    phaddw               m2, m0 ;H 0 1 2 3
+    pmulhrsw             m2, w8192reg ;H pw_8192
+    ;
+    ; lower shuffle
+    mova                 m6, [base+subpel_h_shuf4]
+    movq                 m5, [srcq+ssq*0]   ; 4 _ _ _
+    movhps               m5, [srcq+ssq*1]   ; 4 _ 5 _
+%if ARCH_X86_32
+    lea                srcq, [srcq+ssq*2]
+    movq                 m4, [srcq+ssq*0]   ; 6 _ _ _
+    add                srcq, ssq
+%else
+    movq                 m4, [srcq+ssq*2]   ; 6 _ _ _
+    add                srcq, ss3q
+%endif
+    pshufb               m3, m5, m6 ;H subpel_h_shuf4 4 ~ 5 ~
+    pshufb               m0, m4, m6 ;H subpel_h_shuf4 6 ~ 6 ~
+    pmaddubsw            m3, m7 ;H subpel_filters
+    pmaddubsw            m0, m7 ;H subpel_filters
+    phaddw               m3, m0 ;H 4 5 6 7
+    pmulhrsw             m3, w8192reg ;H pw_8192
+    SAVELINE_W4          m3, 3, 0
+    ; upper shuffle
+    mova                 m6, [base+subpel_h_shuf4+16]
+    pshufb               m3, m5, m6 ;H subpel_h_shuf4 4 ~ 5 ~
+    pshufb               m0, m4, m6 ;H subpel_h_shuf4 6 ~ 6 ~
+    pmaddubsw            m3, m7 ;H subpel_filters
+    pmaddubsw            m0, m7 ;H subpel_filters
+    phaddw               m3, m0 ;H 4 5 6 7
+    pmulhrsw             m3, w8192reg ;H pw_8192
+    ;process high
+    palignr              m4, m3, m2, 4;V 1 2 3 4
+    punpcklwd            m1, m2, m4  ; V 01 12
+    punpckhwd            m2, m4      ; V 23 34
+    pshufd               m0, m3, q2121;V 5 6 5 6
+    punpcklwd            m3, m0      ; V 45 56
+    SAVELINE_W4          m0, 0, 1
+    SAVELINE_W4          m1, 1, 1
+    SAVELINE_W4          m2, 2, 1
+    SAVELINE_W4          m3, 3, 1
+    ;process low
+    RESTORELINE_W4       m2, 2, 0
+    RESTORELINE_W4       m3, 3, 0
+    palignr              m4, m3, m2, 4;V 1 2 3 4
+    punpcklwd            m1, m2, m4  ; V 01 12
+    punpckhwd            m2, m4      ; V 23 34
+    pshufd               m0, m3, q2121;V 5 6 5 6
+    punpcklwd            m3, m0      ; V 45 56
+.hv_w4_loop:
+    ;process low
+    pmaddwd              m5, m1, subpelv0 ; V a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, subpelv1; V a1 b1
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, subpelv2; V a2 b2
+    paddd                m5, m3
+    mova                 m6, [base+subpel_h_shuf4]
+    movq                 m4, [srcq+ssq*0] ; 7
+    movhps               m4, [srcq+ssq*1] ; 7 _ 8 _
+    pshufb               m4, m6 ;H subpel_h_shuf4 7 ~ 8 ~
+    pmaddubsw            m4, m7 ;H subpel_filters
+    phaddw               m4, m4 ;H                7 8 7 8
+    pmulhrsw             m4, w8192reg ;H pw_8192
+    palignr              m3, m4, m0, 12         ; 6 7 8 7
+    mova                 m0, m4
+    punpcklwd            m3, m4      ; 67 78
+    pmaddwd              m4, m3, subpelv3; a3 b3
+    paddd                m5, d512reg ; pd_512
+    paddd                m5, m4
+    psrad                m5, 10
+    SAVELINE_W4          m0, 0, 0
+    SAVELINE_W4          m1, 1, 0
+    SAVELINE_W4          m2, 2, 0
+    SAVELINE_W4          m3, 3, 0
+    SAVELINE_W4          m5, 5, 0
+    ;process high
+    RESTORELINE_W4       m0, 0, 1
+    RESTORELINE_W4       m1, 1, 1
+    RESTORELINE_W4       m2, 2, 1
+    RESTORELINE_W4       m3, 3, 1
+    pmaddwd              m5, m1, subpelv0; V a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, subpelv1; V a1 b1
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, subpelv2; V a2 b2
+    paddd                m5, m3
+    mova                 m6, [base+subpel_h_shuf4+16]
+    movq                 m4, [srcq+ssq*0] ; 7
+    movhps               m4, [srcq+ssq*1] ; 7 _ 8 _
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m4, m6 ;H subpel_h_shuf4 7 ~ 8 ~
+    pmaddubsw            m4, m7 ;H subpel_filters
+    phaddw               m4, m4 ;H                7 8 7 8
+    pmulhrsw             m4, w8192reg ;H pw_8192
+    palignr              m3, m4, m0, 12         ; 6 7 8 7
+    mova                 m0, m4
+    punpcklwd            m3, m4      ; 67 78
+    pmaddwd              m4, m3, subpelv3; a3 b3
+    paddd                m5, d512reg ; pd_512
+    paddd                m5, m4
+    psrad                m4, m5, 10
+    RESTORELINE_W4       m5, 5, 0
+    packssdw             m5, m4 ; d -> w
+    packuswb             m5, m5 ; w -> b
+    pshuflw              m5, m5, q3120
+    movd       [dstq+dsq*0], m5
+    psrlq                m5, 32
+    movd       [dstq+dsq*1], m5
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    SAVELINE_W4          m0, 0, 1
+    SAVELINE_W4          m1, 1, 1
+    SAVELINE_W4          m2, 2, 1
+    SAVELINE_W4          m3, 3, 1
+    RESTORELINE_W4       m0, 0, 0
+    RESTORELINE_W4       m1, 1, 0
+    RESTORELINE_W4       m2, 2, 0
+    RESTORELINE_W4       m3, 3, 0
+    jg .hv_w4_loop
+    RET
+%undef subpelv0
+%undef subpelv1
+%undef subpelv2
+%undef subpelv3
+.hv_w8:
+    RESET_STACK_STATE
+%define hv8_line_1 0
+%define hv8_line_2 1
+%define hv8_line_3 2
+%define hv8_line_4 3
+%define hv8_line_6 4
+%macro SAVELINE_W8 2
+    mova     [rsp+hv8_line_%1*mmsize], %2
+%endmacro
+%macro RESTORELINE_W8 2
+    mova     %2, [rsp+hv8_line_%1*mmsize]
+%endmacro
+    shr                 mxd, 16
+    sub                srcq, 3
+%if ARCH_X86_32
+ %define           base_reg  r1
+ %define           subpelh0  [rsp+mmsize*5]
+ %define           subpelh1  [rsp+mmsize*6]
+ %define           subpelv0  [rsp+mmsize*7]
+ %define           subpelv1  [rsp+mmsize*8]
+ %define           subpelv2  [rsp+mmsize*9]
+ %define           subpelv3  [rsp+mmsize*10]
+ %define             accuv0  [rsp+mmsize*11]
+ %define             accuv1  [rsp+mmsize*12]
+    movq                 m1, [base_reg+mxq*8+subpel_filters-put_ssse3]
+    movzx               mxd, ssb
+    shr                 ssd, 16
+    cmp                  hd, 6
+    cmovs               ssd, mxd
+    movq                 m5, [base_reg+ssq*8+subpel_filters-put_ssse3]
+    mov                 ssq, ssmp
+    ALLOC_STACK  -mmsize*13
+%if STACK_ALIGNMENT < 16
+ %define               dstm  [rsp+mmsize*13+gprsize*1]
+ %define                dsm  [rsp+mmsize*13+gprsize*2]
+    mov                  r6, [rstk+stack_offset+gprsize*2]
+    mov                 dsm, r6
+%endif
+    pshufd               m0, m1, q0000
+    pshufd               m1, m1, q1111
+    punpcklbw            m5, m5
+    psraw                m5, 8 ; sign-extend
+    pshufd               m2, m5, q0000
+    pshufd               m3, m5, q1111
+    pshufd               m4, m5, q2222
+    pshufd               m5, m5, q3333
+    mova           subpelh0, m0
+    mova           subpelh1, m1
+    mova           subpelv0, m2
+    mova           subpelv1, m3
+    mova           subpelv2, m4
+    mova           subpelv3, m5
+    lea                  r6, [ssq*3]
+    mov                dstm, dstq
+    sub                srcq, r6
+%else
+    ALLOC_STACK        16*5, 16
+ %define           subpelh0  m10
+ %define           subpelh1  m11
+ %define           subpelv0  m12
+ %define           subpelv1  m13
+ %define           subpelv2  m14
+ %define           subpelv3  m15
+ %define             accuv0  m8
+ %define             accuv1  m9
+    movq                 m0, [base_reg+mxq*8+subpel_filters-put_ssse3]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m1, [base_reg+myq*8+subpel_filters-put_ssse3]
+    pshufd         subpelh0, m0, q0000
+    pshufd         subpelh1, m0, q1111
+    punpcklbw            m1, m1
+    psraw                m1, 8 ; sign-extend
+    pshufd         subpelv0, m1, q0000
+    pshufd         subpelv1, m1, q1111
+    pshufd         subpelv2, m1, q2222
+    pshufd         subpelv3, m1, q3333
+    lea                ss3q, [ssq*3]
+    mov                  r7, dstq
+    sub                srcq, ss3q
+%endif
+    shl                  wd, 14
+    lea                 r6d, [hq+wq-(1<<16)]
+    mov                  r4, srcq
+.hv_w8_loop0:
+    movu                 m4, [srcq+ssq*0] ; 0 = _ _
+    movu                 m5, [srcq+ssq*1] ; 1 = _ _
+%if ARCH_X86_32
+    lea                srcq, [srcq+ssq*2]
+%endif
+%macro HV_H_W8 4-7 ; src/dst, tmp[1-3], shuf[1-3]
+ %if ARCH_X86_32
+    pshufb               %3, %1, [base+subpel_h_shufB]
+    pshufb               %4, %1, [base+subpel_h_shufC]
+    pshufb               %1,     [base+subpel_h_shufA]
+ %else
+    pshufb               %3, %1, %6  ; subpel_h_shufB
+    pshufb               %4, %1, %7  ; subpel_h_shufC
+    pshufb               %1, %5      ; subpel_h_shufA
+ %endif
+    pmaddubsw            %2, %3, subpelh0 ; subpel +0 C0
+    pmaddubsw            %4, subpelh1; subpel +4 B4
+    pmaddubsw            %3, subpelh1; C4
+    pmaddubsw            %1, subpelh0; A0
+    paddw                %2, %4      ; C0+B4
+    paddw                %1, %3      ; A0+C4
+    phaddw               %1, %2
+%endmacro
+%if ARCH_X86_64
+    mova                 m7, [base+subpel_h_shufA]
+    mova                 m8, [base+subpel_h_shufB]
+    mova                 m9, [base+subpel_h_shufC]
+%endif
+    HV_H_W8              m4, m1, m2, m3, m7, m8, m9 ; 0 ~ ~ ~
+    HV_H_W8              m5, m1, m2, m3, m7, m8, m9 ; 1 ~ ~ ~
+%if ARCH_X86_32
+    movu                 m6, [srcq+ssq*0] ; 2 = _ _
+    movu                 m0, [srcq+ssq*1] ; 3 = _ _
+    lea                srcq, [srcq+ssq*2]
+%else
+    movu                 m6, [srcq+ssq*2] ; 2 = _ _
+    add                srcq, ss3q
+    movu                 m0, [srcq+ssq*0] ; 3 = _ _
+%endif
+    HV_H_W8              m6, m1, m2, m3, m7, m8, m9 ; 2 ~ ~ ~
+    HV_H_W8              m0, m1, m2, m3, m7, m8, m9 ; 3 ~ ~ ~
+    mova                 m7, [base+pw_8192]
+    pmulhrsw             m4, m7 ; H pw_8192
+    pmulhrsw             m5, m7 ; H pw_8192
+    pmulhrsw             m6, m7 ; H pw_8192
+    pmulhrsw             m0, m7 ; H pw_8192
+    punpcklwd            m1, m4, m5  ; 0 1 ~
+    punpcklwd            m2, m5, m6  ; 1 2 ~
+    punpcklwd            m3, m6, m0  ; 2 3 ~
+    SAVELINE_W8           1, m1
+    SAVELINE_W8           2, m2
+    SAVELINE_W8           3, m3
+    mova                 m7, [base+subpel_h_shufA]
+%if ARCH_X86_32
+    movu                 m4, [srcq+ssq*0]       ; 4 = _ _
+    movu                 m5, [srcq+ssq*1]       ; 5 = _ _
+    lea                srcq, [srcq+ssq*2]
+%else
+    movu                 m4, [srcq+ssq*1]       ; 4 = _ _
+    movu                 m5, [srcq+ssq*2]       ; 5 = _ _
+    add                srcq, ss3q
+%endif
+    movu                 m6, [srcq+ssq*0]       ; 6 = _ _
+    HV_H_W8              m4, m1, m2, m3, m7, m8, m9 ; 4 ~ ~ ~
+    HV_H_W8              m5, m1, m2, m3, m7, m8, m9 ; 5 ~ ~ ~
+    HV_H_W8              m6, m1, m2, m3, m7, m8, m9 ; 6 ~ ~ ~
+    mova                 m7, [base+pw_8192]
+    pmulhrsw             m1, m4, m7 ; H pw_8192 4 ~
+    pmulhrsw             m2, m5, m7 ; H pw_8192 5 ~
+    pmulhrsw             m3, m6, m7 ; H pw_8192 6 ~
+    punpcklwd            m4, m0, m1  ; 3 4 ~
+    punpcklwd            m5, m1, m2  ; 4 5 ~
+    punpcklwd            m6, m2, m3  ; 5 6 ~
+    SAVELINE_W8           6, m3
+    RESTORELINE_W8        1, m1
+    RESTORELINE_W8        2, m2
+    RESTORELINE_W8        3, m3
+.hv_w8_loop:
+    ; m8 accu for V a
+    ; m9 accu for V b
+    SAVELINE_W8           1, m3
+    SAVELINE_W8           2, m4
+    SAVELINE_W8           3, m5
+    SAVELINE_W8           4, m6
+%if ARCH_X86_32
+    pmaddwd              m0, m1, subpelv0 ; a0
+    pmaddwd              m7, m2, subpelv0 ; b0
+    pmaddwd              m3, subpelv1     ; a1
+    pmaddwd              m4, subpelv1     ; b1
+    paddd                m0, m3
+    paddd                m7, m4
+    pmaddwd              m5, subpelv2     ; a2
+    pmaddwd              m6, subpelv2     ; b2
+    paddd                m0, m5
+    paddd                m7, m6
+    mova                 m5, [base+pd_512]
+    paddd                m0, m5 ;   pd_512
+    paddd                m7, m5 ;   pd_512
+    mova             accuv0, m0
+    mova             accuv1, m7
+%else
+    pmaddwd              m8, m1, subpelv0 ; a0
+    pmaddwd              m9, m2, subpelv0 ; b0
+    pmaddwd              m3, subpelv1     ; a1
+    pmaddwd              m4, subpelv1     ; b1
+    paddd                m8, m3
+    paddd                m9, m4
+    pmaddwd              m5, subpelv2     ; a2
+    pmaddwd              m6, subpelv2     ; b2
+    paddd                m8, m5
+    paddd                m9, m6
+    mova                 m7, [base+pd_512]
+    paddd                m8, m7 ;   pd_512
+    paddd                m9, m7 ;   pd_512
+    mova                 m7, [base+subpel_h_shufB]
+    mova                 m6, [base+subpel_h_shufC]
+    mova                 m5, [base+subpel_h_shufA]
+%endif
+    movu                 m0, [srcq+ssq*1] ; 7
+    movu                 m4, [srcq+ssq*2] ; 8
+    lea                srcq, [srcq+ssq*2]
+    HV_H_W8              m0, m1, m2, m3, m5, m7, m6
+    HV_H_W8              m4, m1, m2, m3, m5, m7, m6
+    mova                 m5, [base+pw_8192]
+    pmulhrsw             m0, m5 ; H pw_8192
+    pmulhrsw             m4, m5 ; H pw_8192
+    RESTORELINE_W8        6, m6
+    punpcklwd            m5, m6, m0  ; 6 7  ~
+    punpcklwd            m6, m0, m4  ; 7 8 ~
+    pmaddwd              m1, m5, subpelv3 ; a3
+    paddd                m2, m1, accuv0
+    pmaddwd              m1, m6, subpelv3 ; b3
+    paddd                m1, m1, accuv1 ; H + V
+    psrad                m2, 10
+    psrad                m1, 10
+    packssdw             m2, m1  ; d -> w
+    packuswb             m2, m1 ; w -> b
+    movd       [dstq+dsq*0], m2
+    psrlq                m2, 32
+%if ARCH_X86_32
+    add                dstq, dsm
+    movd       [dstq+dsq*0], m2
+    add                dstq, dsm
+%else
+    movd       [dstq+dsq*1], m2
+    lea                dstq, [dstq+dsq*2]
+%endif
+    sub                  hd, 2
+    jle .hv_w8_outer
+    SAVELINE_W8           6, m4
+    RESTORELINE_W8        1, m1
+    RESTORELINE_W8        2, m2
+    RESTORELINE_W8        3, m3
+    RESTORELINE_W8        4, m4
+    jmp .hv_w8_loop
+.hv_w8_outer:
+%if ARCH_X86_32
+    mov                dstq, dstm
+    add                  r4, 4
+    movzx                hd, r6w
+    add                dstq, 4
+    mov                srcq, r4
+    mov                dstm, dstq
+%else
+    add                  r4, 4
+    add                  r7, 4
+    movzx                hd, r6b
+    mov                srcq, r4
+    mov                dstq, r7
+%endif
+    sub                 r6d, 1<<16
+    jg .hv_w8_loop0
+    RET
+
+%if ARCH_X86_32
+ DECLARE_REG_TMP 1, 2
+%elif WIN64
+ DECLARE_REG_TMP 6, 4
+%else
+ DECLARE_REG_TMP 6, 7
+%endif
+
+%if ARCH_X86_32
+ %define base_reg r2
+ %define base base_reg-prep_ssse3
+%else
+ %define base_reg r7
+ %define base 0
+%endif
+
+%define PREP_8TAP_FN FN prep_8tap,
+PREP_8TAP_FN smooth,         SMOOTH,  SMOOTH,  prep_6tap_8bpc
+PREP_8TAP_FN smooth_regular, SMOOTH,  REGULAR, prep_6tap_8bpc
+PREP_8TAP_FN regular_smooth, REGULAR, SMOOTH,  prep_6tap_8bpc
+PREP_8TAP_FN regular,        REGULAR, REGULAR
+
+cglobal prep_6tap_8bpc, 1, 9, 0, tmp, src, ss, w, h, mx, my, ns
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    mov                  wd, wm
+    movifnidn          srcd, srcm
+    movifnidn            hd, hm
+    LEA            base_reg, prep_ssse3
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jnz .v
+.prep:
+    tzcnt                wd, wd
+    movzx                wd, word [base_reg-prep_ssse3+prep_ssse3_table+wq*2]
+    pxor                 m4, m4
+    add                  wq, base_reg
+    movifnidn           ssq, ssmp
+    lea                  r6, [ssq*3]
+%if WIN64
+    pop                  r8
+    pop                  r7
+%endif
+    jmp                  wq
+.h:
+    test                myd, 0xf00
+    jnz .hv
+    test                myd, 0xf00
+    jnz .hv
+%if ARCH_X86_32
+ %define ssq r6
+    mov                 ssq, ssmp
+%endif
+    cmp                  wd, 4
+    jle mangle(private_prefix %+ _prep_8tap_8bpc %+ SUFFIX).h_w4
+    WIN64_SPILL_XMM      11
+    mova                 m5, [base+pw_8192]
+%if ARCH_X86_64
+    mova                 m8, [base+subpel_h_shufD]
+    mova                 m9, [base+subpel_h_shufE]
+    mova                m10, [base+subpel_h_shufF]
+%endif
+    shr                 mxd, 16
+    sub                srcq, 2
+    movq                 m7, [base_reg-prep_ssse3+subpel_filters+1+mxq*8]
+    punpcklwd            m7, m7
+    pshufd               m4, m7, q0000
+    pshufd               m6, m7, q1111
+    pshufd               m7, m7, q2222
+    sub                  wd, 16
+    jge .h_w16
+%macro PREP_6TAP_H 3 ; dst/src, tmp[1-2]
+%if ARCH_X86_32
+    pshufb               %2, %1, [base+subpel_h_shufD]
+    pshufb               %3, %1, [base+subpel_h_shufE]
+    pshufb               %1, [base+subpel_h_shufF]
+%else
+    pshufb               %2, %1, m8
+    pshufb               %3, %1, m9
+    pshufb               %1, m10
+%endif
+    pmaddubsw            %2, m4
+    pmaddubsw            %3, m6
+    pmaddubsw            %1, m7
+    paddw                %2, %3
+    paddw                %1, %2
+    pmulhrsw             %1, m5
+%endmacro
+.h_w8:
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    PREP_6TAP_H          m0, m2, m3
+    PREP_6TAP_H          m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    add                srcq, wq
+    neg                  wq
+.h_w16_loop_v:
+    mov                  r5, wq
+.h_w16_loop_h:
+    movu                 m0, [srcq+r5+8*0]
+    movu                 m1, [srcq+r5+8*1]
+    PREP_6TAP_H          m0, m2, m3
+    PREP_6TAP_H          m1, m2, m3
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    add                tmpq, 32
+    add                  r5, 16
+    jle .h_w16_loop_h
+    add                srcq, ssq
+    dec                  hd
+    jg .h_w16_loop_v
+    RET
+.v:
+%if ARCH_X86_32
+    mov                 mxd, myd
+    and                 mxd, 0x7f
+%else
+    WIN64_SPILL_XMM       9, 12
+    movzx               mxd, myb
+%endif
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m7, [base_reg-prep_ssse3+subpel_filters+1+myq*8]
+    punpcklwd            m7, m7
+    pshufd               m5, m7, q0000
+    pshufd               m6, m7, q1111
+    pshufd               m7, m7, q2222
+%if ARCH_X86_32
+    %define              m8  [base+pw_8192]
+    mov                 ssq, ssm
+    sub                srcq, ssq
+    sub                srcq, ssq
+%else
+    mova                 m8, [base+pw_8192]
+    mov                 nsq, ssq
+    neg                 nsq
+    cmp                  wd, 4
+    jg .v_w8
+%endif
+.v_w4:
+%if ARCH_X86_32
+    lea                 r5d, [wq-4]
+    shl                 r5d, 14
+    add                 r5d, hd
+    mov                srcm, srcq
+.v_w4_loop0:
+    movd                 m1, [srcq+ssq*0]
+    movd                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+%else
+    movd                 m1, [srcq+nsq*2]
+    movd                 m3, [srcq+nsq*1]
+%endif
+    movd                 m2, [srcq+ssq*0]
+    movd                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m1, m3     ; 0 1
+    punpckldq            m3, m2     ; 1 2
+    punpckldq            m2, m4     ; 2 3
+    punpckldq            m4, m0     ; 3 4
+    punpcklbw            m1, m3     ; 01 12
+    punpcklbw            m2, m4     ; 23 34
+.v_w4_loop:
+    movd                 m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddubsw            m4, m1, m5 ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, m6     ; a1 b1
+    paddw                m4, m2
+    punpckldq            m2, m0, m3 ; 4 5
+    movd                 m0, [srcq+ssq*0]
+    punpckldq            m3, m0     ; 5 6
+    punpcklbw            m2, m3     ; 67 78
+    pmaddubsw            m3, m2, m7 ; a2 b2
+    paddw                m4, m3
+    pmulhrsw             m4, m8
+%if ARCH_X86_32
+    movq        [tmpq+wq*0], m4
+    movhps      [tmpq+wq*2], m4
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jg .v_w4_loop
+    mov                srcq, srcm
+    mov                tmpq, tmpm
+    movzx                hd, r5w
+    add                srcq, 4
+    add                tmpq, 8
+    mov                srcm, srcq
+    mov                tmpm, tmpq
+    sub                 r5d, 1<<16
+    jg .v_w4_loop0
+%else
+    mova             [tmpq], m4
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .v_w4_loop
+%endif
+    RET
+%if ARCH_X86_64
+.v_w8:
+    WIN64_PUSH_XMM       12
+    lea                 r6d, [wq*4-32]
+    lea                 r6d, [r6*8+hq]
+.v_w8_loop0:
+    movq                 m1, [srcq+nsq*2]
+    movq                 m2, [srcq+nsq*1]
+    lea                  r5, [srcq+ssq*2]
+    movq                 m3, [srcq+ssq*0]
+    movq                 m4, [srcq+ssq*1]
+    mov                  r8, tmpq
+    movq                 m0, [r5  +ssq*0]
+    punpcklbw            m1, m2     ; 01
+    punpcklbw            m2, m3     ; 12
+    punpcklbw            m3, m4     ; 23
+    punpcklbw            m4, m0     ; 34
+.v_w8_loop:
+    pmaddubsw           m10, m1, m5 ; a0
+    mova                 m1, m3
+    pmaddubsw           m11, m2, m5 ; b0
+    mova                 m2, m4
+    pmaddubsw            m3, m6     ; a1
+    pmaddubsw            m4, m6     ; b1
+    paddw               m10, m3
+    paddw               m11, m4
+    movq                 m4, [r5+ssq*1]
+    lea                  r5, [r5+ssq*2]
+    punpcklbw            m3, m0, m4 ; 67
+    movq                 m0, [r5+ssq*0]
+    punpcklbw            m4, m0     ; 78
+    pmaddubsw            m9, m3, m7 ; a2
+    paddw               m10, m9
+    pmaddubsw            m9, m4, m7 ; b2
+    paddw               m11, m9
+    pmulhrsw            m10, m8
+    pmulhrsw            m11, m8
+    mova          [r8+wq*0], m10
+    mova          [r8+wq*2], m11
+    lea                  r8, [r8+wq*4]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                srcq, 8
+    add                tmpq, 16
+    movzx                hd, r6b
+    sub                 r6d, 1<<8
+    jg .v_w8_loop0
+    RET
+%endif ;ARCH_X86_64
+.hv:
+    RESET_STACK_STATE
+    cmp                  wd, 4
+    jg .hv_w8
+%if ARCH_X86_32
+    and                 mxd, 0x7f
+%else
+    movzx               mxd, mxb
+%endif
+    dec                srcq
+    movd                 m1, [base_reg-prep_ssse3+subpel_filters+2+mxq*8]
+%if ARCH_X86_32
+    mov                 mxd, myd
+    and                 mxd, 0x7f
+%else
+    movzx               mxd, myb
+%endif
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m0, [base_reg-prep_ssse3+subpel_filters+1+myq*8]
+%if ARCH_X86_32
+    mov                 ssq, ssmp
+%define regs_used 6
+    ALLOC_STACK   -mmsize*4
+%define regs_used 7
+    %define              m8  [rsp+mmsize*0]
+    %define              m9  [rsp+mmsize*1]
+    %define             m10  [rsp+mmsize*2]
+    punpcklbw            m0, m0
+    sub                srcq, ssq
+    psraw                m0, 8 ; sign-extend
+    sub                srcq, ssq
+    pshufd               m2, m0, q0000
+    mova                 m8, m2
+    pshufd               m2, m0, q1111
+    mova                 m9, m2
+    pshufd               m2, m0, q2222
+    mova                m10, m2
+    movq                 m3, [srcq+ssq*0]
+    movq                 m4, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    %define             m11  [base+pw_8192]
+    %define             m12  [base+subpel_h_shufA]
+    %define             m13  [rsp+mmsize*3]
+    %define             m14  [base+pd_32]
+    pshufd               m1, m1, q0000
+    mova                m13, m1
+%else
+    WIN64_SPILL_XMM      15
+    mov                 nsq, ssq
+    punpcklbw            m0, m0
+    neg                 nsq
+    psraw                m0, 8 ; sign-extend
+    pshufd               m8, m0, q0000
+    pshufd               m9, m0, q1111
+    pshufd              m10, m0, q2222
+    movq                 m3, [srcq+nsq*2]
+    movq                 m4, [srcq+nsq*1]
+    pshufd              m13, m1, q0000
+    mova                m12, [base+subpel_h_shufA]
+    mova                m11, [base+pw_8192]
+    mova                m14, [base+pd_32]
+%endif
+    movq                 m0, [srcq+ssq*0]
+    movq                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m2, [srcq+ssq*0]
+%if ARCH_X86_32
+    mova                 m5, m12
+    mova                 m6, m13
+    REPX {pshufb    x, m5 }, m3, m4, m0, m1, m2
+    mova                 m5, m11
+    REPX {pmaddubsw x, m6 }, m3, m4, m0, m1, m2
+%else
+    REPX {pshufb    x, m12}, m3, m4, m0, m1, m2
+    REPX {pmaddubsw x, m13}, m3, m4, m0, m1, m2
+%endif
+    phaddw               m3, m0      ; 0 2
+    phaddw               m4, m1      ; 1 3
+    phaddw               m0, m2      ; 2 4
+%if ARCH_X86_32
+    REPX  {pmulhrsw x, m5 }, m3, m4, m0
+%else
+    REPX  {pmulhrsw x, m11}, m3, m4, m0
+%endif
+    punpcklwd            m1, m3, m4  ; 01
+    punpckhwd            m3, m4      ; 23
+    punpcklwd            m2, m4, m0  ; 12
+    punpckhwd            m4, m0      ; 34
+.hv_w4_loop:
+    movq                 m7, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    movq                 m6, [srcq+ssq*0]
+    pshufb               m7, m12
+    pshufb               m6, m12
+    pmaddubsw            m7, m13
+    pmaddubsw            m6, m13
+    pmaddwd              m5, m8, m1  ; a0
+    mova                 m1, m3
+    phaddw               m7, m6      ; 5 6
+    pmaddwd              m6, m8, m2  ; b0
+    mova                 m2, m4
+    pmaddwd              m3, m9      ; a1
+    pmaddwd              m4, m9      ; b1
+    pmulhrsw             m7, m11
+    paddd                m5, m14
+    paddd                m6, m14
+    paddd                m5, m3
+    paddd                m6, m4
+    shufpd               m4, m0, m7, 0x01 ; 4 5
+    mova                 m0, m7
+    punpcklwd            m3, m4, m7  ; 45
+    punpckhwd            m4, m7      ; 56
+    pmaddwd              m7, m10, m3 ; a2
+    paddd                m5, m7
+    pmaddwd              m7, m10, m4 ; b2
+    paddd                m6, m7
+    psrad                m5, 6
+    psrad                m6, 6
+    packssdw             m5, m6
+    mova             [tmpq], m5
+    add                tmpq, 16
+    sub                  hd, 2
+    jg .hv_w4_loop
+    RET
+.hv_w8:
+    RESET_STACK_STATE
+    shr                 mxd, 16
+    sub                srcq, 2
+    movq                 m0, [base_reg-prep_ssse3+subpel_filters+1+mxq*8]
+%if ARCH_X86_32
+    mov                 mxd, myd
+    and                 mxd, 0x7f
+%else
+    movzx               mxd, myb
+%endif
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m1, [base_reg-prep_ssse3+subpel_filters+1+myq*8]
+%if ARCH_X86_32
+    mov                 ssq, ssm
+%assign regs_used 6
+    ALLOC_STACK  -mmsize*16
+%assign regs_used 7
+    sub                srcq, ssq
+    sub                srcq, ssq
+%if STACK_ALIGNMENT < 16
+    %define            srcm  [esp+mmsize*15+gprsize*0]
+    %define            tmpm  [esp+mmsize*15+gprsize*1]
+    mov                tmpm, tmpq
+%endif
+    mov                srcm, srcq
+%else
+    ALLOC_STACK        16*6, 16
+    mov                 nsq, ssq
+    neg                 nsq
+%endif
+    mova                 m7, [base+pw_8192]
+    lea                 r5d, [wq-8]
+    punpcklwd            m0, m0
+    shl                 r5d, 13
+    punpcklbw            m1, m1
+    add                 r5d, hd
+    psraw                m1, 8 ; sign-extend
+    pshufd               m2, m0, q0000
+    mova         [rsp+16*0], m2
+    pshufd               m2, m0, q1111
+    mova         [rsp+16*1], m2
+    pshufd               m0, m0, q2222
+    mova         [rsp+16*2], m0
+    pshufd               m2, m1, q0000
+    mova         [rsp+16*3], m2
+    pshufd               m2, m1, q1111
+    mova         [rsp+16*4], m2
+    pshufd               m1, m1, q2222
+    mova         [rsp+16*5], m1
+%macro PREP_HV_H_6TAP 3-8 [base+subpel_h_shufD], [base+subpel_h_shufF], \
+                          [rsp+16*0], [rsp+16*1], [rsp+16*2] ; src/dst, tmp[1-2], shuf[1-2], mul[1-3]
+    pshufb               %2, %1, %4
+    pshufb               %1, %5
+    pmaddubsw            %3, %2, %6
+    shufps               %2, %1, q2121
+    pmaddubsw            %1, %8
+    pmaddubsw            %2, %7
+    paddw                %1, %3
+    paddw                %1, %2
+    pmulhrsw             %1, m7
+%endmacro
+.hv_w8_loop0:
+    mova                 m2, [base+subpel_h_shufD]
+    mova                 m3, [base+subpel_h_shufF]
+    mova                 m4, [rsp+16*0]
+%if ARCH_X86_32
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    PREP_HV_H_6TAP       m0, m5, m6, m2, m3, m4
+    PREP_HV_H_6TAP       m1, m5, m6, m2, m3, m4
+    movu                 m5, [srcq+ssq*0]
+    punpcklwd            m6, m0, m1   ; 01
+    punpckhwd            m0, m1
+    mova        [rsp+16* 6], m6
+    mova        [rsp+16* 7], m0
+    PREP_HV_H_6TAP       m5, m0, m6, m2, m3, m4
+    movu                 m0, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklwd            m6, m1, m5   ; 12
+    punpckhwd            m1, m5
+    mova        [rsp+16* 8], m6
+    mova        [rsp+16* 9], m1
+    PREP_HV_H_6TAP       m0, m1, m6, m2, m3, m4
+    movu                 m1, [srcq+ssq*0]
+    punpcklwd            m6, m5, m0   ; 23
+    punpckhwd            m5, m0
+    mova        [rsp+16*10], m6
+    mova        [rsp+16*11], m5
+    PREP_HV_H_6TAP       m1, m5, m6, m2, m3, m4
+    mova        [rsp+16*14], m1
+    punpcklwd            m6, m0, m1   ; 34
+    punpckhwd            m0, m1
+    mova        [rsp+16*12], m6
+    mova        [rsp+16*13], m0
+.hv_w8_loop:
+    mova                 m3, [rsp+16* 3]
+    pmaddwd              m0, m3, [rsp+16* 6] ; a0
+    pmaddwd              m2, m3, [rsp+16* 7] ; a0'
+    pmaddwd              m1, m3, [rsp+16* 8] ; b0
+    pmaddwd              m3, [rsp+16* 9]     ; b0'
+    mova                 m6, [rsp+16* 4]
+    mova                 m4, [rsp+16*10]
+    mova                 m5, [rsp+16*11]
+    mova        [rsp+16* 6], m4
+    pmaddwd              m4, m6       ; a1
+    mova        [rsp+16* 7], m5
+    pmaddwd              m5, m6       ; a1'
+    paddd                m0, m4
+    mova                 m4, [rsp+16*12]
+    paddd                m2, m5
+    mova                 m5, [rsp+16*13]
+    mova        [rsp+16* 8], m4
+    pmaddwd              m4, m6       ; b1
+    mova        [rsp+16* 9], m5
+    pmaddwd              m5, m6       ; b1'
+    movu                 m6, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    paddd                m1, m4
+    paddd                m3, m5
+    PREP_HV_H_6TAP       m6, m4, m5
+    mova                 m4, [base+pd_32]
+    mova                 m5, [rsp+16*14]
+    REPX      {paddd x, m4}, m0, m2, m1, m3
+    punpcklwd            m4, m5, m6   ; 45
+    punpckhwd            m5, m6
+    mova        [rsp+16*10], m4
+    mova        [rsp+16*11], m5
+    pmaddwd              m4, [rsp+16*5] ; a2
+    pmaddwd              m5, [rsp+16*5] ; a2'
+    paddd                m0, m4
+    movu                 m4, [srcq+ssq*0]
+    paddd                m2, m5
+    psrad                m0, 6
+    psrad                m2, 6
+    packssdw             m0, m2
+    PREP_HV_H_6TAP       m4, m2, m5
+    mova                 m2, [rsp+16*5]
+    punpcklwd            m5, m6, m4   ; 56
+    mova        [rsp+16*14], m4
+    punpckhwd            m6, m4
+    mova        [rsp+16*12], m5
+    pmaddwd              m5, m2       ; b2
+    mova        [rsp+16*13], m6
+    pmaddwd              m6, m2       ; b2'
+    paddd                m1, m5
+    paddd                m3, m6
+    psrad                m1, 6
+    psrad                m3, 6
+    packssdw             m1, m3
+    mova        [tmpq+wq*0], m0
+    mova        [tmpq+wq*2], m1
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    mov                srcq, srcm
+    mov                tmpq, tmpm
+    movzx                hd, r5w
+    add                srcq, 8
+    add                tmpq, 16
+    mov                srcm, srcq
+    mov                tmpm, tmpq
+%else
+    movu                 m9, [srcq+nsq*2]
+    movu                m11, [srcq+nsq*1]
+    lea                  r6, [srcq+ssq*2]
+    movu                m13, [srcq+ssq*0]
+    movu                m15, [srcq+ssq*1]
+    mov                  r8, tmpq
+    movu                 m6, [r6  +ssq*0]
+    mova                 m5, [rsp+16*1]
+    mova                 m8, [rsp+16*2]
+    PREP_HV_H_6TAP       m9, m0, m1, m2, m3, m4, m5, m8
+    PREP_HV_H_6TAP      m11, m0, m1, m2, m3, m4, m5, m8
+    PREP_HV_H_6TAP      m13, m0, m1, m2, m3, m4, m5, m8
+    PREP_HV_H_6TAP      m15, m0, m1, m2, m3, m4, m5, m8
+    PREP_HV_H_6TAP       m6, m0, m1, m2, m3, m4, m5, m8
+    punpcklwd            m8, m9, m11  ; 01
+    punpckhwd            m9, m11
+    punpcklwd           m10, m11, m13 ; 12
+    punpckhwd           m11, m13
+    punpcklwd           m12, m13, m15 ; 23
+    punpckhwd           m13, m15
+    punpcklwd           m14, m15, m6  ; 34
+    punpckhwd           m15, m6
+.hv_w8_loop:
+    mova                 m3, [rsp+16*3]
+    mova                 m4, [rsp+16*4]
+    mova                 m5, [base+pd_32]
+    pmaddwd              m0, m8, m3  ; a0
+    mova                 m8, m12
+    pmaddwd              m2, m9, m3  ; a0'
+    mova                 m9, m13
+    pmaddwd              m1, m10, m3 ; b0
+    mova                m10, m14
+    pmaddwd              m3, m11     ; b0'
+    mova                m11, m15
+    REPX    {pmaddwd x, m4}, m12, m13, m14, m15
+    REPX    {paddd   x, m5}, m0, m2, m1, m3
+    paddd                m0, m12
+    paddd                m2, m13
+    paddd                m1, m14
+    paddd                m3, m15
+    movu                m15, [r6+ssq*1]
+    lea                  r6, [r6+ssq*2]
+    PREP_HV_H_6TAP      m15, m4, m5
+    punpcklwd           m12, m6, m15
+    punpckhwd           m13, m6, m15
+    movu                 m6, [r6+ssq*0]
+    PREP_HV_H_6TAP       m6, m4, m5
+    mova                 m4, [rsp+16*5]
+    punpcklwd           m14, m15, m6
+    punpckhwd           m15, m6
+    pmaddwd              m5, m12, m4  ; a2
+    paddd                m0, m5
+    pmaddwd              m5, m13, m4  ; a2'
+    paddd                m2, m5
+    pmaddwd              m5, m14, m4  ; b2
+    paddd                m1, m5
+    pmaddwd              m4, m15      ; b2'
+    paddd                m3, m4
+    REPX       {psrad x, 6}, m0, m2, m1, m3
+    packssdw             m0, m2
+    packssdw             m1, m3
+    mova          [r8+wq*0], m0
+    mova          [r8+wq*2], m1
+    lea                  r8, [r8+wq*4]
+    sub                  hd, 2
+    jg .hv_w8_loop
+    add                srcq, 8
+    add                tmpq, 16
+    movzx                hd, r5b
+%endif
+    sub                 r5d, 1<<16
+    jg .hv_w8_loop0
+    RET
+
+PREP_8TAP_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_8bpc
+PREP_8TAP_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_8bpc
+PREP_8TAP_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_8bpc
+PREP_8TAP_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_8bpc
+PREP_8TAP_FN sharp,          SHARP,   SHARP
+
+cglobal prep_8tap_8bpc, 1, 9, 0, tmp, src, stride, w, h, mx, my, stride3
+    imul                mxd, mxm, 0x010101
+    add                 mxd, t0d ; 8tap_h, mx, 4tap_h
+    imul                myd, mym, 0x010101
+    add                 myd, t1d ; 8tap_v, my, 4tap_v
+    mov                  wd, wm
+    movifnidn          srcd, srcm
+    movifnidn            hd, hm
+    LEA            base_reg, prep_ssse3
+    test                mxd, 0xf00
+    jnz .h
+    test                myd, 0xf00
+    jz mangle(private_prefix %+ _prep_6tap_8bpc_ssse3).prep
+.v:
+%if ARCH_X86_32
+    mov                 mxd, myd
+    and                 mxd, 0x7f
+%else
+    WIN64_SPILL_XMM      16
+    movzx               mxd, myb
+%endif
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m0, [base_reg+myq*8+subpel_filters-prep_ssse3]
+    mova                 m2, [base+pw_512]
+    mova                 m7, [base+pw_8192]
+    punpcklwd            m0, m0
+%if ARCH_X86_32
+ %define            subpel0  [rsp+mmsize*0]
+ %define            subpel1  [rsp+mmsize*1]
+ %define            subpel2  [rsp+mmsize*2]
+ %define            subpel3  [rsp+mmsize*3]
+%assign regs_used 6 ; use r5 (mx) as tmp for stack alignment if needed
+    ALLOC_STACK   -mmsize*4
+%assign regs_used 7
+    mov             strideq, [rstk+stack_offset+gprsize*3]
+    pshufd               m1, m0, q0000
+    mova            subpel0, m1
+    pshufd               m1, m0, q1111
+    mova            subpel1, m1
+    lea                  r5, [strideq*3]
+    pshufd               m1, m0, q2222
+    mova            subpel2, m1
+    pshufd               m1, m0, q3333
+    mova            subpel3, m1
+    sub                srcq, r5
+%else
+ %define            subpel0  m8
+ %define            subpel1  m9
+ %define            subpel2  m10
+ %define            subpel3  m11
+    pshufd               m8, m0, q0000
+    pshufd               m9, m0, q1111
+    lea            stride3q, [strideq*3]
+    pshufd              m10, m0, q2222
+    pshufd              m11, m0, q3333
+    sub                srcq, stride3q
+    cmp                  wd, 8
+    jns .v_w8
+%endif
+.v_w4:
+%if ARCH_X86_32
+ %if STACK_ALIGNMENT < mmsize
+  %define srcm [esp+stack_size+gprsize*1]
+  %define tmpm [esp+stack_size+gprsize*2]
+ %endif
+    mov                tmpm, tmpq
+    mov                srcm, srcq
+    lea                 r5d, [wq - 4] ; horizontal loop
+    shl                 r5d, (16 - 2)  ; (wq / 4) << 16
+    mov                 r5w, hw
+.v_w4_loop0:
+%endif
+    movd                 m1, [srcq+strideq*0]
+    movd                 m0, [srcq+strideq*1]
+%if ARCH_X86_32
+    lea                srcq, [srcq+strideq*2]
+    movd                 m2, [srcq+strideq*0]
+    movd                 m4, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    movd                 m3, [srcq+strideq*0]
+    movd                 m5, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+%else
+    movd                 m2, [srcq+strideq*2]
+    add                srcq, stride3q
+    movd                 m4, [srcq+strideq*0]
+    movd                 m3, [srcq+strideq*1]
+    movd                 m5, [srcq+strideq*2]
+    add                srcq, stride3q
+%endif
+    punpckldq            m1, m0 ; 0 1
+    punpckldq            m0, m2 ; 1 2
+    punpcklbw            m1, m0 ; 01 12
+    movd                 m0, [srcq+strideq*0]
+    punpckldq            m2, m4 ; 2 3
+    punpckldq            m4, m3 ; 3 4
+    punpckldq            m3, m5 ; 4 5
+    punpckldq            m5, m0 ; 5 6
+    punpcklbw            m2, m4 ; 23 34
+    punpcklbw            m3, m5 ; 45 56
+.v_w4_loop:
+    mova                 m5, m1
+    pmaddubsw            m5, subpel0      ; a0 b0
+    mova                 m1, m2
+    pmaddubsw            m2, subpel1      ; a1 b1
+    paddw                m5, m2
+    mova                 m2, m3
+    pmaddubsw            m3, subpel2      ; a2 b2
+    movd                 m4, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    paddw                m5, m3
+    punpckldq            m3, m0, m4       ; 6 7 _ _
+    movd                 m0, [srcq+strideq*0]
+    punpckldq            m4, m0           ; 7 8 _ _
+    punpcklbw            m3, m4           ; 67 78
+    mova                 m4, m3
+    pmaddubsw            m4, subpel3      ; a3 b3
+    paddw                m5, m4
+    pmulhrsw             m5, m7
+    movq        [tmpq+wq*0], m5
+    movhps      [tmpq+wq*2], m5
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jg .v_w4_loop
+%if ARCH_X86_32
+    mov                srcq, srcm
+    mov                tmpq, tmpm
+    movzx                hd, r5w
+    add                srcq, 4
+    add                tmpq, 8
+    mov                srcm, srcq
+    mov                tmpm, tmpq
+    sub                 r5d, 1<<16 ; horizontal--
+    jg .v_w4_loop0
+%endif
+    RET
+%if ARCH_X86_64
+.v_w8:
+    lea                 r6d, [wq*8-64]
+    mov                  r5, srcq
+    mov                  r8, tmpq
+    lea                 r6d, [hq+r6*4]
+.v_w8_loop0:
+    movq                 m1, [srcq+strideq*0]
+    movq                 m2, [srcq+strideq*1]
+    movq                 m3, [srcq+strideq*2]
+    add                srcq, stride3q
+    movq                 m4, [srcq+strideq*0]
+    movq                 m5, [srcq+strideq*1]
+    movq                 m6, [srcq+strideq*2]
+    add                srcq, stride3q
+    movq                 m0, [srcq+strideq*0]
+    punpcklbw            m1, m2 ; 01
+    punpcklbw            m2, m3 ; 12
+    punpcklbw            m3, m4 ; 23
+    punpcklbw            m4, m5 ; 34
+    punpcklbw            m5, m6 ; 45
+    punpcklbw            m6, m0 ; 56
+.v_w8_loop:
+    movq                m13, [srcq+strideq*1]
+    lea                srcq, [srcq+strideq*2]
+    pmaddubsw           m14, m1, subpel0 ; a0
+    pmaddubsw           m15, m2, subpel0 ; b0
+    mova                 m1, m3
+    mova                 m2, m4
+    pmaddubsw            m3, subpel1 ; a1
+    pmaddubsw            m4, subpel1 ; b1
+    paddw               m14, m3
+    paddw               m15, m4
+    mova                 m3, m5
+    mova                 m4, m6
+    pmaddubsw            m5, subpel2 ; a2
+    pmaddubsw            m6, subpel2 ; b2
+    punpcklbw           m12, m0, m13 ; 67
+    movq                 m0, [srcq+strideq*0]
+    punpcklbw           m13, m0      ; 78
+    paddw               m14, m5
+    mova                 m5, m12
+    pmaddubsw           m12, subpel3 ; a3
+    paddw               m15, m6
+    mova                 m6, m13
+    pmaddubsw           m13, subpel3 ; b3
+    paddw               m14, m12
+    paddw               m15, m13
+    pmulhrsw            m14, m7
+    pmulhrsw            m15, m7
+    movu        [tmpq+wq*0], m14
+    movu        [tmpq+wq*2], m15
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jg .v_w8_loop
+    add                  r5, 8
+    add                  r8, 16
+    movzx                hd, r6b
+    mov                srcq, r5
+    mov                tmpq, r8
+    sub                 r6d, 1<<8
+    jg .v_w8_loop0
+    RET
+%endif ;ARCH_X86_64
+%undef subpel0
+%undef subpel1
+%undef subpel2
+%undef subpel3
+.h_w4:
+    WIN64_SPILL_XMM       7
+%if ARCH_X86_32
+    and                 mxd, 0x7f
+%else
+    movzx               mxd, mxb
+%endif
+    dec                srcq
+    movd                 m4, [base_reg+mxq*8+subpel_filters-prep_ssse3+2]
+    mova                 m5, [base+subpel_h_shufA]
+    mova                 m6, [base+pw_8192]
+    movifnidn            r2, stridemp
+    pshufd               m4, m4, q0000
+    lea                  r3, [r2*3]
+.h_w4_loop:
+    movq                 m0, [srcq+r2*0]
+    movq                 m1, [srcq+r2*1]
+    movq                 m2, [srcq+r2*2]
+    movq                 m3, [srcq+r3  ]
+    lea                srcq, [srcq+r2*4]
+    REPX  {pshufb    x, m5}, m0, m1, m2, m3
+    REPX  {pmaddubsw x, m4}, m0, m1, m2, m3
+    phaddw               m0, m1
+    phaddw               m2, m3
+    pmulhrsw             m0, m6
+    pmulhrsw             m2, m6
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m2
+    add                tmpq, 32
+    sub                  hd, 4
+    jg .h_w4_loop
+    RET
+.h:
+    test                myd, 0xf00
+    jnz .hv
+    cmp                  wd, 4
+    je .h_w4
+    WIN64_SPILL_XMM      12
+%if ARCH_X86_32
+ %define strideq r6
+    mov             strideq, stridem
+%endif
+    tzcnt                wd, wd
+%if ARCH_X86_64
+    mova                m10, [base+subpel_h_shufA]
+    mova                m11, [base+subpel_h_shufB]
+    mova                 m9, [base+subpel_h_shufC]
+%else
+    %define             m10  [base+subpel_h_shufA]
+    %define             m11  [base+subpel_h_shufB]
+    %define              m9  [base+subpel_h_shufC]
+%endif
+    shr                 mxd, 16
+    sub                srcq, 3
+    movzx                wd, word [base_reg+wq*2+table_offset(prep, _8tap_h)]
+    movq                 m6, [base_reg+mxq*8+subpel_filters-prep_ssse3]
+    mova                 m7, [base+pw_8192]
+    pshufd               m5, m6, q0000
+    pshufd               m6, m6, q1111
+    add                  wq, base_reg
+    jmp                  wq
+%macro PREP_8TAP_H 2 ; dst, src_memloc
+    movu                m%1, [%2]
+    pshufb               m2, m%1, m11 ; subpel_h_shufB
+    pshufb               m3, m%1, m9  ; subpel_h_shufC
+    pshufb              m%1, m10      ; subpel_h_shufA
+    mova                 m4, m2
+    pmaddubsw            m4, m5       ; subpel +0 B0
+    pmaddubsw            m2, m6       ; subpel +4 B4
+    pmaddubsw            m3, m6       ; subpel +4 C4
+    pmaddubsw           m%1, m5       ; subpel +0 A0
+    paddw                m3, m4
+    paddw               m%1, m2
+    phaddw              m%1, m3
+    pmulhrsw            m%1, m7
+%endmacro
+.h_w8:
+    PREP_8TAP_H           0, srcq+strideq*0
+    PREP_8TAP_H           1, srcq+strideq*1
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    lea                srcq, [srcq+strideq*2]
+    add                tmpq, 32
+    sub                  hd, 2
+    jg .h_w8
+    RET
+.h_w16:
+    mov                  r3, -16*1
+    jmp .h_start
+.h_w32:
+    mov                  r3, -16*2
+    jmp .h_start
+.h_w64:
+    mov                  r3, -16*4
+    jmp .h_start
+.h_w128:
+    mov                  r3, -16*8
+.h_start:
+    sub                srcq, r3
+    mov                  r5, r3
+.h_loop:
+    PREP_8TAP_H           0, srcq+r3+8*0
+    PREP_8TAP_H           1, srcq+r3+8*1
+    mova        [tmpq+16*0], m0
+    mova        [tmpq+16*1], m1
+    add                tmpq, 32
+    add                  r3, 16
+    jl .h_loop
+    add                srcq, strideq
+    mov                  r3, r5
+    dec                  hd
+    jg .h_loop
+    RET
+.hv:
+    RESET_STACK_STATE
+    cmp                  wd, 4
+    jg .hv_w8
+    and                 mxd, 0x7f
+    movd                 m1, [base_reg+mxq*8+subpel_filters-prep_ssse3+2]
+%if ARCH_X86_32
+    mov                 mxd, myd
+    shr                 myd, 16
+    and                 mxd, 0x7f
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m0, [base_reg+myq*8+subpel_filters-prep_ssse3]
+    mov             strideq, stridem
+ %assign regs_used 6
+    ALLOC_STACK  -mmsize*14
+ %assign regs_used 7
+    lea                  r5, [strideq*3+1]
+    sub                srcq, r5
+ %define           subpelv0  [rsp+mmsize*0]
+ %define           subpelv1  [rsp+mmsize*1]
+ %define           subpelv2  [rsp+mmsize*2]
+ %define           subpelv3  [rsp+mmsize*3]
+    punpcklbw            m0, m0
+    psraw                m0, 8
+    pshufd               m6, m0, q0000
+    mova           subpelv0, m6
+    pshufd               m6, m0, q1111
+    mova           subpelv1, m6
+    pshufd               m6, m0, q2222
+    mova           subpelv2, m6
+    pshufd               m6, m0, q3333
+    mova           subpelv3, m6
+%else
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m0, [base_reg+myq*8+subpel_filters-prep_ssse3]
+    ALLOC_STACK   mmsize*14, 14
+    lea            stride3q, [strideq*3]
+    sub                srcq, stride3q
+    dec                srcq
+ %define           subpelv0  m10
+ %define           subpelv1  m11
+ %define           subpelv2  m12
+ %define           subpelv3  m13
+    punpcklbw            m0, m0
+    psraw                m0, 8
+    mova                 m8, [base+pw_8192]
+    mova                 m9, [base+pd_32]
+    pshufd              m10, m0, q0000
+    pshufd              m11, m0, q1111
+    pshufd              m12, m0, q2222
+    pshufd              m13, m0, q3333
+%endif
+    pshufd               m7, m1, q0000
+%define hv4_line_0_0 4
+%define hv4_line_0_1 5
+%define hv4_line_0_2 6
+%define hv4_line_0_3 7
+%define hv4_line_0_4 8
+%define hv4_line_0_5 9
+%define hv4_line_1_0 10
+%define hv4_line_1_1 11
+%define hv4_line_1_2 12
+%define hv4_line_1_3 13
+%if ARCH_X86_32
+    %define        w8192reg  [base+pw_8192]
+    %define          d32reg  [base+pd_32]
+%else
+    %define        w8192reg  m8
+    %define          d32reg  m9
+%endif
+    ; lower shuffle 0 1 2 3 4
+    mova                 m6, [base+subpel_h_shuf4]
+    movq                 m5, [srcq+strideq*0]   ; 0 _ _ _
+    movhps               m5, [srcq+strideq*1]   ; 0 _ 1 _
+%if ARCH_X86_32
+    lea                srcq, [srcq+strideq*2]
+    movq                 m4, [srcq+strideq*0]   ; 2 _ _ _
+    movhps               m4, [srcq+strideq*1]   ; 2 _ 3 _
+    lea                srcq, [srcq+strideq*2]
+%else
+    movq                 m4, [srcq+strideq*2]   ; 2 _ _ _
+    movhps               m4, [srcq+stride3q ]   ; 2 _ 3 _
+    lea                srcq, [srcq+strideq*4]
+%endif
+    pshufb               m2, m5, m6             ;H subpel_h_shuf4 0~1~
+    pshufb               m0, m4, m6             ;H subpel_h_shuf4 2~3~
+    pmaddubsw            m2, m7                 ;H subpel_filters
+    pmaddubsw            m0, m7                 ;H subpel_filters
+    phaddw               m2, m0
+    pmulhrsw             m2, w8192reg
+    SAVELINE_W4          m2, 2, 0
+    ; upper shuffle 2 3 4 5 6
+    mova                 m6, [base+subpel_h_shuf4+16]
+    pshufb               m2, m5, m6             ;H subpel_h_shuf4 0~1~
+    pshufb               m0, m4, m6             ;H subpel_h_shuf4 2~3~
+    pmaddubsw            m2, m7                 ;H subpel_filters
+    pmaddubsw            m0, m7                 ;H subpel_filters
+    phaddw               m2, m0                 ;H 0 1 2 3
+    pmulhrsw             m2, w8192reg
+    ; lower shuffle
+    mova                 m6, [base+subpel_h_shuf4]
+    movq                 m5, [srcq+strideq*0]   ; 4 _ _ _
+    movhps               m5, [srcq+strideq*1]   ; 4 _ 5 _
+%if ARCH_X86_32
+    lea                srcq, [srcq+strideq*2]
+    movq                 m4, [srcq+strideq*0]   ; 6 _ _ _
+    add                srcq, strideq
+%else
+    movq                 m4, [srcq+strideq*2]   ; 6 _ _ _
+    add                srcq, stride3q
+%endif
+    pshufb               m3, m5, m6             ;H subpel_h_shuf4 4~5~
+    pshufb               m0, m4, m6             ;H subpel_h_shuf4 6~6~
+    pmaddubsw            m3, m7                 ;H subpel_filters
+    pmaddubsw            m0, m7                 ;H subpel_filters
+    phaddw               m3, m0                 ;H 4 5 6 7
+    pmulhrsw             m3, w8192reg
+    SAVELINE_W4          m3, 3, 0
+    ; upper shuffle
+    mova                 m6, [base+subpel_h_shuf4+16]
+    pshufb               m3, m5, m6             ;H subpel_h_shuf4 4~5~
+    pshufb               m0, m4, m6             ;H subpel_h_shuf4 6~6~
+    pmaddubsw            m3, m7                 ;H subpel_filters
+    pmaddubsw            m0, m7                 ;H subpel_filters
+    phaddw               m3, m0                 ;H 4 5 6 7
+    pmulhrsw             m3, w8192reg
+    ;process high
+    palignr              m4, m3, m2, 4;V 1 2 3 4
+    punpcklwd            m1, m2, m4  ; V 01 12
+    punpckhwd            m2, m4      ; V 23 34
+    pshufd               m0, m3, q2121;V 5 6 5 6
+    punpcklwd            m3, m0      ; V 45 56
+    SAVELINE_W4          m0, 0, 1
+    SAVELINE_W4          m1, 1, 1
+    SAVELINE_W4          m2, 2, 1
+    SAVELINE_W4          m3, 3, 1
+    ;process low
+    RESTORELINE_W4       m2, 2, 0
+    RESTORELINE_W4       m3, 3, 0
+    palignr              m4, m3, m2, 4;V 1 2 3 4
+    punpcklwd            m1, m2, m4  ; V 01 12
+    punpckhwd            m2, m4      ; V 23 34
+    pshufd               m0, m3, q2121;V 5 6 5 6
+    punpcklwd            m3, m0      ; V 45 56
+.hv_w4_loop:
+    ;process low
+    pmaddwd              m5, m1, subpelv0 ; V a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, subpelv1; V a1 b1
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, subpelv2; V a2 b2
+    paddd                m5, m3
+    mova                 m6, [base+subpel_h_shuf4]
+    movq                 m4, [srcq+strideq*0] ; 7
+    movhps               m4, [srcq+strideq*1] ; 7 _ 8 _
+    pshufb               m4, m6               ; H subpel_h_shuf4 7~8~
+    pmaddubsw            m4, m7               ; H subpel_filters
+    phaddw               m4, m4               ; H                7878
+    pmulhrsw             m4, w8192reg
+    palignr              m3, m4, m0, 12       ;                  6787
+    mova                 m0, m4
+    punpcklwd            m3, m4      ; 67 78
+    pmaddwd              m4, m3, subpelv3; a3 b3
+    paddd                m5, d32reg ; pd_32
+    paddd                m5, m4
+    psrad                m5, 6
+    SAVELINE_W4          m0, 0, 0
+    SAVELINE_W4          m1, 1, 0
+    SAVELINE_W4          m2, 2, 0
+    SAVELINE_W4          m3, 3, 0
+    SAVELINE_W4          m5, 5, 0
+    ;process high
+    RESTORELINE_W4       m0, 0, 1
+    RESTORELINE_W4       m1, 1, 1
+    RESTORELINE_W4       m2, 2, 1
+    RESTORELINE_W4       m3, 3, 1
+    pmaddwd              m5, m1, subpelv0; V a0 b0
+    mova                 m1, m2
+    pmaddwd              m2, subpelv1; V a1 b1
+    paddd                m5, m2
+    mova                 m2, m3
+    pmaddwd              m3, subpelv2; V a2 b2
+    paddd                m5, m3
+    mova                 m6, [base+subpel_h_shuf4+16]
+    movq                 m4, [srcq+strideq*0] ; 7
+    movhps               m4, [srcq+strideq*1] ; 7 _ 8 _
+    pshufb               m4, m6               ; H subpel_h_shuf4 7~8~
+    pmaddubsw            m4, m7               ; H subpel_filters
+    phaddw               m4, m4               ; H                7878
+    pmulhrsw             m4, w8192reg
+    palignr              m3, m4, m0, 12       ;                  6787
+    mova                 m0, m4
+    punpcklwd            m3, m4      ; 67 78
+    pmaddwd              m4, m3, subpelv3; a3 b3
+    paddd                m5, d32reg ; pd_32
+    paddd                m5, m4
+    psrad                m4, m5, 6
+    RESTORELINE_W4       m5, 5, 0
+    packssdw             m5, m4
+    pshufd               m5, m5, q3120
+    movu             [tmpq], m5
+    lea                srcq, [srcq+strideq*2]
+    add                tmpq, 16
+    sub                  hd, 2
+    SAVELINE_W4          m0, 0, 1
+    SAVELINE_W4          m1, 1, 1
+    SAVELINE_W4          m2, 2, 1
+    SAVELINE_W4          m3, 3, 1
+    RESTORELINE_W4       m0, 0, 0
+    RESTORELINE_W4       m1, 1, 0
+    RESTORELINE_W4       m2, 2, 0
+    RESTORELINE_W4       m3, 3, 0
+    jg .hv_w4_loop
+    RET
+%undef subpelv0
+%undef subpelv1
+%undef subpelv2
+%undef subpelv3
+.hv_w8:
+    RESET_STACK_STATE
+%define hv8_line_1 0
+%define hv8_line_2 1
+%define hv8_line_3 2
+%define hv8_line_4 3
+%define hv8_line_6 4
+    shr                 mxd, 16
+%if ARCH_X86_32
+ %define           subpelh0  [rsp+mmsize*5]
+ %define           subpelh1  [rsp+mmsize*6]
+ %define           subpelv0  [rsp+mmsize*7]
+ %define           subpelv1  [rsp+mmsize*8]
+ %define           subpelv2  [rsp+mmsize*9]
+ %define           subpelv3  [rsp+mmsize*10]
+ %define             accuv0  [rsp+mmsize*11]
+ %define             accuv1  [rsp+mmsize*12]
+    movq                 m1, [base_reg+mxq*8+subpel_filters-prep_ssse3]
+    mov                 mxd, myd
+    shr                 myd, 16
+    and                 mxd, 0x7f
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m5, [base_reg+myq*8+subpel_filters-prep_ssse3]
+    mov             strideq, stridem
+ %assign regs_used 6
+    ALLOC_STACK  -mmsize*14
+ %assign regs_used 7
+ %if STACK_ALIGNMENT < mmsize
+  %define              tmpm  [rsp+mmsize*13+gprsize*1]
+  %define              srcm  [rsp+mmsize*13+gprsize*2]
+  %define           stridem  [rsp+mmsize*13+gprsize*3]
+    mov                tmpm, tmpq
+    mov             stridem, strideq
+ %endif
+    pshufd               m0, m1, q0000
+    pshufd               m1, m1, q1111
+    punpcklbw            m5, m5
+    psraw                m5, 8
+    pshufd               m2, m5, q0000
+    pshufd               m3, m5, q1111
+    pshufd               m4, m5, q2222
+    pshufd               m5, m5, q3333
+    mova           subpelh0, m0
+    mova           subpelh1, m1
+    mova           subpelv0, m2
+    mova           subpelv1, m3
+    mova           subpelv2, m4
+    mova           subpelv3, m5
+    lea                  r5, [strideq*3+3]
+    sub                srcq, r5
+    mov                srcm, srcq
+%else
+    ALLOC_STACK    mmsize*5, 16
+ %define           subpelh0  m10
+ %define           subpelh1  m11
+ %define           subpelv0  m12
+ %define           subpelv1  m13
+ %define           subpelv2  m14
+ %define           subpelv3  m15
+ %define             accuv0  m8
+ %define             accuv1  m9
+    movq                 m0, [base_reg+mxq*8+subpel_filters-prep_ssse3]
+    movzx               mxd, myb
+    shr                 myd, 16
+    cmp                  hd, 6
+    cmovs               myd, mxd
+    movq                 m1, [base_reg+myq*8+subpel_filters-prep_ssse3]
+    pshufd         subpelh0, m0, q0000
+    pshufd         subpelh1, m0, q1111
+    punpcklbw            m1, m1
+    psraw                m1, 8
+    pshufd         subpelv0, m1, q0000
+    pshufd         subpelv1, m1, q1111
+    pshufd         subpelv2, m1, q2222
+    pshufd         subpelv3, m1, q3333
+    lea            stride3q, [strideq*3]
+    sub                srcq, 3
+    sub                srcq, stride3q
+    mov                  r6, srcq
+    mov                  r8, tmpq
+%endif
+    lea                 r5d, [wq-4]
+    shl                 r5d, 14
+    add                 r5d, hd
+.hv_w8_loop0:
+%if ARCH_X86_64
+    mova                 m7, [base+subpel_h_shufA]
+    mova                 m8, [base+subpel_h_shufB]
+    mova                 m9, [base+subpel_h_shufC]
+    %define           shufA  m7
+    %define           shufB  m8
+    %define           shufC  m9
+%else
+    %define           shufA  [base+subpel_h_shufA]
+    %define           shufB  [base+subpel_h_shufB]
+    %define           shufC  [base+subpel_h_shufC]
+%endif
+%macro PREP_8TAP_HV 2 ; dst, src_memloc, tmp[1-2]
+    movu                 %1, [%2]
+    pshufb               m2, %1, shufB
+    pshufb               m3, %1, shufC
+    pshufb               %1, shufA
+    mova                 m1, m2
+    pmaddubsw            m1, subpelh0 ; subpel +0 C0
+    pmaddubsw            m3, subpelh1 ; subpel +4 B4
+    pmaddubsw            m2, subpelh1 ; C4
+    pmaddubsw            %1, subpelh0 ; A0
+    paddw                m1, m3       ; C0+B4
+    paddw                %1, m2       ; A0+C4
+    phaddw               %1, m1
+%endmacro
+    PREP_8TAP_HV         m4, srcq+strideq*0
+    PREP_8TAP_HV         m5, srcq+strideq*1
+%if ARCH_X86_64
+    PREP_8TAP_HV         m6, srcq+strideq*2
+    add                srcq, stride3q
+    PREP_8TAP_HV         m0, srcq+strideq*0
+%else
+    lea                srcq, [srcq+strideq*2]
+    PREP_8TAP_HV         m6, srcq+strideq*0
+    PREP_8TAP_HV         m0, srcq+strideq*1
+    lea                srcq, [srcq+strideq*2]
+%endif
+    mova                 m7, [base+pw_8192]
+    REPX   {pmulhrsw x, m7}, m4, m5, m6, m0
+    punpcklwd            m1, m4, m5 ; 01
+    punpcklwd            m2, m5, m6 ; 12
+    punpcklwd            m3, m6, m0 ; 23
+    SAVELINE_W8           1, m1
+    SAVELINE_W8           2, m2
+    SAVELINE_W8           3, m3
+    mova                 m7, [base+subpel_h_shufA]
+%if ARCH_X86_64
+    PREP_8TAP_HV         m4, srcq+strideq*1
+    PREP_8TAP_HV         m5, srcq+strideq*2
+    add                srcq, stride3q
+    PREP_8TAP_HV         m6, srcq+strideq*0
+%else
+    PREP_8TAP_HV         m4, srcq+strideq*0
+    PREP_8TAP_HV         m5, srcq+strideq*1
+    lea                srcq, [srcq+strideq*2]
+    PREP_8TAP_HV         m6, srcq+strideq*0
+%endif
+    mova                 m3, [base+pw_8192]
+    pmulhrsw             m1, m3, m4
+    pmulhrsw             m2, m3, m5
+    pmulhrsw             m3, m6
+    punpcklwd            m4, m0, m1 ; 34
+    punpcklwd            m5, m1, m2 ; 45
+    punpcklwd            m6, m2, m3 ; 56
+    SAVELINE_W8           6, m3
+    RESTORELINE_W8        1, m1
+    RESTORELINE_W8        2, m2
+    RESTORELINE_W8        3, m3
+.hv_w8_loop:
+    SAVELINE_W8           1, m3
+    SAVELINE_W8           2, m4
+    SAVELINE_W8           3, m5
+    SAVELINE_W8           4, m6
+%if ARCH_X86_32
+    pmaddwd              m0, m1, subpelv0 ; a0
+    pmaddwd              m7, m2, subpelv0 ; b0
+    pmaddwd              m3, subpelv1     ; a1
+    pmaddwd              m4, subpelv1     ; b1
+    paddd                m0, m3
+    paddd                m7, m4
+    pmaddwd              m5, subpelv2     ; a2
+    pmaddwd              m6, subpelv2     ; b2
+    paddd                m0, m5
+    paddd                m7, m6
+    mova                 m5, [base+pd_32]
+    paddd                m0, m5
+    paddd                m7, m5
+    mova             accuv0, m0
+    mova             accuv1, m7
+%else
+    pmaddwd          accuv0, m1, subpelv0 ; a0
+    pmaddwd          accuv1, m2, subpelv0 ; b0
+    pmaddwd              m3, subpelv1     ; a1
+    pmaddwd              m4, subpelv1     ; b1
+    paddd            accuv0, m3
+    paddd            accuv1, m4
+    pmaddwd              m5, subpelv2     ; a2
+    pmaddwd              m6, subpelv2     ; b2
+    paddd            accuv0, m5
+    paddd            accuv1, m6
+    mova                 m7, [base+pd_32]
+    paddd            accuv0, m7
+    paddd            accuv1, m7
+    mova                 m7, [base+subpel_h_shufB]
+    mova                 m6, [base+subpel_h_shufC]
+    mova                 m5, [base+subpel_h_shufA]
+    %define           shufA  m5
+    %define           shufB  m7
+    %define           shufC  m6
+%endif
+    PREP_8TAP_HV         m0, srcq+strideq*1
+    lea                srcq, [srcq+strideq*2]
+    PREP_8TAP_HV         m4, srcq+strideq*0
+    mova                 m5, [base+pw_8192]
+    pmulhrsw             m0, m5
+    pmulhrsw             m4, m5
+    RESTORELINE_W8        6, m6
+    punpcklwd            m5, m6, m0 ; 67
+    punpcklwd            m6, m0, m4 ; 78
+    pmaddwd              m1, m5, subpelv3 ; a3
+    paddd                m2, m1, accuv0
+    pmaddwd              m1, m6, subpelv3 ; b3
+    paddd                m1, m1, accuv1
+    psrad                m2, 6
+    psrad                m1, 6
+    packssdw             m2, m1
+    movq        [tmpq+wq*0], m2
+    movhps      [tmpq+wq*2], m2
+    lea                tmpq, [tmpq+wq*4]
+    sub                  hd, 2
+    jle .hv_w8_outer
+    SAVELINE_W8           6, m4
+    RESTORELINE_W8        1, m1
+    RESTORELINE_W8        2, m2
+    RESTORELINE_W8        3, m3
+    RESTORELINE_W8        4, m4
+    jmp .hv_w8_loop
+.hv_w8_outer:
+%if ARCH_X86_32
+    mov                srcq, srcm
+    mov                tmpq, tmpm
+    movzx                hd, r5w
+    add                srcq, 4
+    add                tmpq, 8
+    mov                srcm, srcq
+    mov                tmpm, tmpq
+%else
+    add                  r6, 4
+    add                  r8, 8
+    movzx                hd, r5b
+    mov                srcq, r6
+    mov                tmpq, r8
+%endif
+    sub                 r5d, 1<<16
+    jg .hv_w8_loop0
+    RET
+
+%macro movifprep 2
+ %if isprep
+    mov %1, %2
+ %endif
+%endmacro
+
+%macro SAVE_REG 1
+ %xdefine r%1_save  r%1
+ %xdefine r%1q_save r%1q
+ %xdefine r%1d_save r%1d
+ %if ARCH_X86_32
+  %define r%1m_save [rstk+stack_offset+(%1+1)*4]
+ %endif
+%endmacro
+
+%macro LOAD_REG 1
+ %xdefine r%1  r%1_save
+ %xdefine r%1q r%1q_save
+ %xdefine r%1d r%1d_save
+ %if ARCH_X86_32
+  %define r%1m r%1m_save
+ %endif
+ %undef r%1d_save
+ %undef r%1q_save
+ %undef r%1_save
+%endmacro
+
+%macro REMAP_REG 2-3
+ %xdefine r%1  r%2
+ %xdefine r%1q r%2q
+ %xdefine r%1d r%2d
+ %if ARCH_X86_32
+  %if %3 == 0
+   %xdefine r%1m r%2m
+  %else
+   %define r%1m [rstk+stack_offset+(%1+1)*4]
+  %endif
+ %endif
+%endmacro
+
+%macro MCT_8TAP_SCALED_REMAP_REGS_TO_PREV 0
+ %if isprep
+  %if ARCH_X86_64
+   SAVE_REG 14
+   %assign %%i 14
+   %rep 14
+    %assign %%j %%i-1
+    REMAP_REG %%i, %%j
+    %assign %%i %%i-1
+   %endrep
+  %else
+   SAVE_REG 5
+   %assign %%i 5
+   %rep 5
+    %assign %%j %%i-1
+    REMAP_REG %%i, %%j, 0
+    %assign %%i %%i-1
+   %endrep
+  %endif
+ %endif
+%endmacro
+
+%macro MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT 0
+ %if isprep
+  %assign %%i 1
+  %if ARCH_X86_64
+   %rep 13
+    %assign %%j %%i+1
+    REMAP_REG %%i, %%j
+    %assign %%i %%i+1
+   %endrep
+   LOAD_REG 14
+  %else
+   %rep 4
+    %assign %%j %%i+1
+    REMAP_REG %%i, %%j, 1
+    %assign %%i %%i+1
+   %endrep
+   LOAD_REG 5
+  %endif
+ %endif
+%endmacro
+
+%macro MC_8TAP_SCALED_RET 0-1 1 ; leave_mapping_unchanged
+    MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT
+    RET
+ %if %1
+    MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %endif
+%endmacro
+
+%if ARCH_X86_64
+ %macro MC_8TAP_SCALED_H 12 ; dst[0-1], tmp[0-5], weights[0-3]
+    SWAP                m%2, m%5
+    movq                m%1, [srcq+ r4]
+    movq                m%2, [srcq+ r6]
+    movhps              m%1, [srcq+ r7]
+    movhps              m%2, [srcq+ r9]
+    movq                m%3, [srcq+r10]
+    movq                m%4, [srcq+r11]
+    movhps              m%3, [srcq+r13]
+    movhps              m%4, [srcq+ rX]
+    add                srcq, ssq
+    movq                m%5, [srcq+ r4]
+    movq                m%6, [srcq+ r6]
+    movhps              m%5, [srcq+ r7]
+    movhps              m%6, [srcq+ r9]
+    movq                m%7, [srcq+r10]
+    movq                m%8, [srcq+r11]
+    movhps              m%7, [srcq+r13]
+    movhps              m%8, [srcq+ rX]
+    add                srcq, ssq
+    pmaddubsw           m%1, m%9
+    pmaddubsw           m%5, m%9
+    pmaddubsw           m%2, m%10
+    pmaddubsw           m%6, m%10
+    pmaddubsw           m%3, m%11
+    pmaddubsw           m%7, m%11
+    pmaddubsw           m%4, m%12
+    pmaddubsw           m%8, m%12
+    phaddw              m%1, m%2
+    phaddw              m%5, m%6
+    phaddw              m%3, m%4
+    phaddw              m%7, m%8
+    phaddw              m%1, m%3
+    phaddw              m%5, m%7
+    pmulhrsw            m%1, m12
+    pmulhrsw            m%5, m12
+    SWAP                m%2, m%5
+ %endmacro
+%else
+ %macro MC_8TAP_SCALED_H 2-3 1 ; weights_mem_start, h_mem_start, load_fh_offsets
+  %if %3 == 1
+    mov                  r0, [esp+ 0]
+    mov                  rX, [esp+ 8]
+    mov                  r4, [esp+ 4]
+    mov                  r5, [esp+12]
+  %endif
+    movq                 m0, [srcq+r0]
+    movq                 m1, [srcq+rX]
+    movhps               m0, [srcq+r4]
+    movhps               m1, [srcq+r5]
+    add                srcq, ssq
+    movq                 m4, [srcq+r0]
+    movq                 m5, [srcq+rX]
+    movhps               m4, [srcq+r4]
+    movhps               m5, [srcq+r5]
+    mov                  r0, [esp+16]
+    mov                  rX, [esp+24]
+    mov                  r4, [esp+20]
+    mov                  r5, [esp+28]
+    sub                srcq, ssq
+    movq                 m2, [srcq+r0]
+    movq                 m3, [srcq+rX]
+    movhps               m2, [srcq+r4]
+    movhps               m3, [srcq+r5]
+    add                srcq, ssq
+    movq                 m6, [srcq+r0]
+    movq                 m7, [srcq+rX]
+    movhps               m6, [srcq+r4]
+    movhps               m7, [srcq+r5]
+    add                srcq, ssq
+    pmaddubsw            m0, [esp+%1+ 0]
+    pmaddubsw            m4, [esp+%1+ 0]
+    pmaddubsw            m1, [esp+%1+16]
+    pmaddubsw            m5, [esp+%1+16]
+    pmaddubsw            m2, [esp+%1+32]
+    pmaddubsw            m6, [esp+%1+32]
+    pmaddubsw            m3, [esp+%1+48]
+    pmaddubsw            m7, [esp+%1+48]
+    phaddw               m0, m1
+    phaddw               m4, m5
+    phaddw               m2, m3
+    phaddw               m6, m7
+    phaddw               m0, m2
+    phaddw               m4, m6
+    pmulhrsw             m0, m12
+    pmulhrsw             m4, m12
+  %if %2 != 0
+    mova        [esp+%2+ 0], m0
+    mova        [esp+%2+16], m4
+  %endif
+ %endmacro
+%endif
+
+%macro MC_8TAP_SCALED 1
+%ifidn %1, put
+ %assign isprep 0
+ %if ARCH_X86_64
+  %if required_stack_alignment <= STACK_ALIGNMENT
+cglobal put_8tap_scaled_8bpc, 2, 15, 16, 0x180, dst, ds, src, ss, w, h, mx, my, dx, dy
+  %else
+cglobal put_8tap_scaled_8bpc, 2, 14, 16, 0x180, dst, ds, src, ss, w, h, mx, my, dx, dy
+  %endif
+ %else ; ARCH_X86_32
+  %if required_stack_alignment <= STACK_ALIGNMENT
+cglobal put_8tap_scaled_8bpc, 0, 7, 8, 0x200, dst, ds, src, ss, w, h, mx, my, dx, dy
+  %else
+cglobal put_8tap_scaled_8bpc, 0, 7, 8, -0x200-0x20, dst, ds, src, ss, w, h, mx, my, dx, dy
+  %endif
+ %endif
+ %xdefine base_reg r12
+ %define rndshift 10
+%else ; prep
+ %assign isprep 1
+ %if ARCH_X86_64
+  %if required_stack_alignment <= STACK_ALIGNMENT
+cglobal prep_8tap_scaled_8bpc, 2, 15, 16, 0x180, tmp, src, ss, w, h, mx, my, dx, dy
+   %xdefine tmp_stridem r14q
+  %else
+cglobal prep_8tap_scaled_8bpc, 2, 14, 16, 0x180, tmp, src, ss, w, h, mx, my, dx, dy
+   %define tmp_stridem qword [rsp+0x138]
+  %endif
+  %xdefine base_reg r11
+ %else ; ARCH_X86_32
+  %if required_stack_alignment <= STACK_ALIGNMENT
+cglobal prep_8tap_scaled_8bpc, 0, 7, 8, 0x200, tmp, src, ss, w, h, mx, my, dx, dy
+  %else
+cglobal prep_8tap_scaled_8bpc, 0, 6, 8, 0x200, tmp, src, ss, w, h, mx, my, dx, dy
+  %endif
+  %define tmp_stridem dword [esp+0x138]
+ %endif
+ %define rndshift 6
+%endif
+%if ARCH_X86_32
+    mov         [esp+0x1f0], t0d
+    mov         [esp+0x1f4], t1d
+ %if !isprep && required_stack_alignment > STACK_ALIGNMENT
+    mov                dstd, dstm
+    mov                 dsd, dsm
+    mov                srcd, srcm
+    mov                 ssd, ssm
+    mov                  hd, hm
+    mov                  r4, mxm
+  %define r0m  [esp+0x200]
+  %define dsm  [esp+0x204]
+  %define dsmp dsm
+  %define r1m  dsm
+  %define r2m  [esp+0x208]
+  %define ssm  [esp+0x20c]
+  %define r3m  ssm
+  %define hm   [esp+0x210]
+  %define mxm  [esp+0x214]
+    mov                 r0m, dstd
+    mov                 dsm, dsd
+    mov                 r2m, srcd
+    mov                 ssm, ssd
+    mov                  hm, hd
+    mov                  r0, mym
+    mov                  r1, dxm
+    mov                  r2, dym
+  %define mym [esp+0x218]
+  %define dxm [esp+0x09c]
+  %define dym [esp+0x21c]
+    mov                 mxm, r4
+    mov                 mym, r0
+    mov                 dxm, r1
+    mov                 dym, r2
+    tzcnt                wd, wm
+ %endif
+ %if isprep && required_stack_alignment > STACK_ALIGNMENT
+  %xdefine base_reg r5
+ %else
+  %xdefine base_reg r6
+ %endif
+    mov                 ssd, ssm
+%endif
+    LEA            base_reg, %1_8tap_scaled_8bpc_ssse3
+%xdefine base base_reg-%1_8tap_scaled_8bpc_ssse3
+%if ARCH_X86_64 || isprep || required_stack_alignment <= STACK_ALIGNMENT
+    tzcnt                wd, wm
+%endif
+%if ARCH_X86_32
+ %define m8  m0
+ %define m9  m1
+ %define m14 m4
+ %define m15 m3
+%endif
+    movd                 m8, dxm
+    movd                m14, mxm
+    pshufd               m8, m8, q0000
+    pshufd              m14, m14, q0000
+%if isprep && UNIX64
+    mov                 r5d, t0d
+ DECLARE_REG_TMP 5, 7
+%endif
+%if ARCH_X86_64
+    mov                 dyd, dym
+%endif
+%ifidn %1, put
+ %if WIN64
+    mov                 r8d, hm
+  DEFINE_ARGS dst, ds, src, ss, w, _, _, my, h, dy, ss3
+  %define hm r5m
+  %define dxm r8m
+ %elif ARCH_X86_64
+  DEFINE_ARGS dst, ds, src, ss, w, h, _, my, dx, dy, ss3
+  %define hm r6m
+ %endif
+ %if ARCH_X86_64
+  %if required_stack_alignment > STACK_ALIGNMENT
+   %define dsm [rsp+0x138]
+   %define rX r1
+   %define rXd r1d
+  %else
+   %define dsm dsq
+   %define rX r14
+   %define rXd r14d
+  %endif
+ %else
+  %define rX r1
+ %endif
+%else ; prep
+ %if WIN64
+    mov                 r7d, hm
+  DEFINE_ARGS tmp, src, ss, w, _, _, my, h, dy, ss3
+  %define hm r4m
+  %define dxm r7m
+ %elif ARCH_X86_64
+  DEFINE_ARGS tmp, src, ss, w, h, _, my, dx, dy, ss3
+  %define hm [rsp+0x94]
+ %endif
+ MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %if ARCH_X86_64
+  %define rX r14
+  %define rXd r14d
+ %else
+  %define rX r3
+ %endif
+%endif
+%if ARCH_X86_64
+    mova                m10, [base+pd_0x3ff]
+    mova                m12, [base+pw_8192]
+ %ifidn %1, put
+    mova                m13, [base+pd_512]
+ %else
+    mova                m13, [base+pd_32]
+ %endif
+%else
+ %define m10 [base+pd_0x3ff]
+ %define m12 [base+pw_8192]
+ %ifidn %1, put
+  %define m13 [base+pd_512]
+ %else
+  %define m13 [base+pd_32]
+ %endif
+%endif
+    pxor                 m9, m9
+%if ARCH_X86_64
+    lea                ss3q, [ssq*3]
+    movzx               r7d, t1b
+    shr                 t1d, 16
+    cmp                  hd, 6
+    cmovs               t1d, r7d
+    sub                srcq, ss3q
+%else
+ MCT_8TAP_SCALED_REMAP_REGS_TO_DEFAULT
+    mov                  r1, [esp+0x1f4]
+    lea                  r0, [ssq*3]
+    movzx                r2, r1b
+    shr                  r1, 16
+    cmp            dword hm, 6
+    cmovs                r1, r2
+    mov         [esp+0x1f4], r1
+    mov                  r1, r1m
+    mov                  r2, r2m
+    sub                srcq, r0
+ MCT_8TAP_SCALED_REMAP_REGS_TO_PREV
+ %define ss3q r0
+ %define myd r4
+ %define dyd dword dym
+ %define hd  dword hm
+%endif
+    cmp                 dyd, 1024
+    je .dy1
+    cmp                 dyd, 2048
+    je .dy2
+    movzx                wd, word [base+%1_8tap_scaled_ssse3_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%ifidn %1, put
+.w2:
+ %if ARCH_X86_64
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd                m15, t0d
+ %else
+    movzx                r4, byte [esp+0x1f0]
+    dec                srcq
+    movd                m15, r4
+ %endif
+    punpckldq            m9, m8
+    SWAP                 m8, m9
+    paddd               m14, m8 ; mx+dx*[0-1]
+ %if ARCH_X86_64
+    mova                m11, [base+pd_0x4000]
+ %else
+  %define m11 [base+pd_0x4000]
+ %endif
+    pshufd              m15, m15, q0000
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd               m15, m8
+    movd                r4d, m15
+    psrldq              m15, 4
+ %if ARCH_X86_64
+    movd                r6d, m15
+ %else
+    movd                r3d, m15
+ %endif
+    mova                 m5, [base+bdct_lb_dw]
+    mova                 m6, [base+subpel_s_shuf2]
+    movd                m15, [base+subpel_filters+r4*8+2]
+ %if ARCH_X86_64
+    movd                 m7, [base+subpel_filters+r6*8+2]
+ %else
+    movd                 m7, [base+subpel_filters+r3*8+2]
+ %endif
+    pxor                 m9, m9
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+ %if ARCH_X86_32
+    mov                  r3, r3m
+    pshufb              m14, m5
+    paddb               m14, m6
+    mova        [rsp+0x180], m14
+    SWAP                 m5, m0
+    SWAP                 m6, m3
+  %define m8  m5
+  %define m15 m6
+ %endif
+    movq                 m0, [srcq+ssq*0]
+    movq                 m2, [srcq+ssq*2]
+    movhps               m0, [srcq+ssq*1]
+    movhps               m2, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+ %if ARCH_X86_64
+    pshufb              m14, m5
+    paddb               m14, m6
+ %endif
+    movq                 m1, [srcq+ssq*0]
+    movq                 m3, [srcq+ssq*2]
+    movhps               m1, [srcq+ssq*1]
+    movhps               m3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    punpckldq           m15, m7
+    punpcklqdq          m15, m15
+ %if ARCH_X86_64
+    pand                m11, m8
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m11
+ %else
+    pand                 m7, m8, m11
+    pandn                m8, m15
+  %define m8  m6
+  %define m15 m5
+    por                 m15, m7
+    mova        [rsp+0x190], m15
+ %endif
+    pshufb               m0, m14
+    pshufb               m2, m14
+    pshufb               m1, m14
+    pshufb               m3, m14
+    pmaddubsw            m0, m15
+    pmaddubsw            m2, m15
+    pmaddubsw            m1, m15
+    pmaddubsw            m3, m15
+    phaddw               m0, m2
+    phaddw               m1, m3
+    pmulhrsw             m0, m12       ; 0 1 2 3
+    pmulhrsw             m1, m12       ; 4 5 6 7
+    palignr              m2, m1, m0, 4 ; 1 2 3 4
+    punpcklwd            m3, m0, m2    ; 01 12
+    punpckhwd            m0, m2        ; 23 34
+    pshufd               m5, m1, q0321 ; 5 6 7 _
+    punpcklwd            m2, m1, m5    ; 45 56
+    punpckhwd            m4, m1, m5    ; 67 __
+ %if ARCH_X86_32
+    mov                 myd, mym
+    mov                  r0, r0m
+    mova        [rsp+0x1a0], m3
+    mova        [rsp+0x1b0], m0
+    mova        [rsp+0x1c0], m2
+    mova        [rsp+0x1d0], m4
+ %endif
+.w2_loop:
+    and                 myd, 0x3ff
+ %if ARCH_X86_64
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq                m11, r6q
+    punpcklbw           m11, m11
+    psraw               m11, 8
+    pshufd               m8, m11, q0000
+    pshufd               m9, m11, q1111
+    pshufd              m10, m11, q2222
+    pshufd              m11, m11, q3333
+    pmaddwd              m5, m3, m8
+    pmaddwd              m6, m0, m9
+    pmaddwd              m7, m2, m10
+    pmaddwd              m8, m4, m11
+    paddd                m5, m6
+    paddd                m7, m8
+ %else
+    mov                 mym, myd
+    mov                  r1, [esp+0x1f4]
+    xor                  r3, r3
+    shr                  r4, 6
+    lea                  r1, [r1+r4]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r1*8+0]
+    cmovnz               r3, [base+subpel_filters+r1*8+4]
+    movd                 m7, r4
+    movd                 m6, r3
+    punpckldq            m7, m6
+    punpcklbw            m7, m7
+    psraw                m7, 8
+    pshufd               m5, m7, q0000
+    pshufd               m6, m7, q1111
+    pmaddwd              m3, m5
+    pmaddwd              m0, m6
+    pshufd               m5, m7, q2222
+    pshufd               m7, m7, q3333
+    pmaddwd              m2, m5
+    pmaddwd              m4, m7
+    paddd                m3, m0
+    paddd                m2, m4
+    SWAP                 m5, m3
+    SWAP                 m7, m2
+ %endif
+    paddd                m5, m13
+    paddd                m5, m7
+    psrad                m5, 10
+    packssdw             m5, m5
+    packuswb             m5, m5
+ %if ARCH_X86_64
+    pextrw              r6d, m5, 0
+    mov              [dstq], r6w
+    add                dstq, dsq
+    dec                  hd
+    jz .ret
+    add                 myd, dyd
+ %else
+    pextrw              r3d, m5, 0
+    mov              [dstq], r3w
+    add                dstq, dsm
+    dec                  hd
+    jz .ret
+    mov                 myd, mym
+    add                 myd, dym
+ %endif
+    test                myd, ~0x3ff
+ %if ARCH_X86_32
+    SWAP                 m3, m5
+    SWAP                 m2, m7
+    mova                 m3, [rsp+0x1a0]
+    mova                 m0, [rsp+0x1b0]
+    mova                 m2, [rsp+0x1c0]
+    mova                 m4, [rsp+0x1d0]
+  %define m14 [esp+0x180]
+  %define m15 [esp+0x190]
+ %endif
+    jz .w2_loop
+ %if ARCH_X86_32
+    mov                  r3, r3m
+ %endif
+    movq                 m5, [srcq]
+    test                myd, 0x400
+    jz .w2_skip_line
+    add                srcq, ssq
+    shufps               m3, m0, q1032      ; 01 12
+    shufps               m0, m2, q1032      ; 23 34
+    shufps               m2, m4, q1032      ; 45 56
+    pshufb               m5, m14
+    pmaddubsw            m5, m15
+    phaddw               m5, m5
+    pmulhrsw             m5, m12
+    palignr              m4, m5, m1, 12
+    punpcklqdq           m1, m4, m4         ; 6 7 6 7
+    punpcklwd            m4, m1, m5         ; 67 __
+ %if ARCH_X86_32
+    mova        [rsp+0x1a0], m3
+    mova        [rsp+0x1b0], m0
+    mova        [rsp+0x1c0], m2
+    mova        [rsp+0x1d0], m4
+ %endif
+    jmp .w2_loop
+.w2_skip_line:
+    movhps               m5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova                 m3, m0             ; 01 12
+    mova                 m0, m2             ; 23 34
+    pshufb               m5, m14
+    pmaddubsw            m5, m15
+    phaddw               m5, m5
+    pmulhrsw             m5, m12            ; 6 7 6 7
+    palignr              m4, m5, m1, 8      ; 4 5 6 7
+    pshufd               m5, m4, q0321      ; 5 6 7 _
+    mova                 m1, m4
+    punpcklwd            m2, m4, m5         ; 45 56
+    punpckhwd            m4, m5             ; 67 __
+ %if ARCH_X86_32
+    mova        [rsp+0x1a0], m3
+    mova        [rsp+0x1b0], m0
+    mova        [rsp+0x1c0], m2
+    mova        [rsp+0x1d0], m4
+ %endif
+    jmp .w2_loop
+%endif
+INIT_XMM ssse3
+.w4:
+%if ARCH_X86_64
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd                m15, t0d
+%else
+ %define m8  m0
+ %xdefine m14 m4
+ %define m15 m3
+    movzx                r4, byte [esp+0x1f0]
+    dec                srcq
+    movd                m15, r4
+%endif
+    pmaddwd              m8, [base+rescale_mul]
+%if ARCH_X86_64
+    mova                m11, [base+pd_0x4000]
+%else
+  %define m11 [base+pd_0x4000]
+%endif
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m0, m14, m10
+    psrld                m0, 6
+    paddd               m15, m0
+    psrldq               m7, m15, 8
+%if ARCH_X86_64
+    movd                r4d, m15
+    movd               r11d, m7
+    psrldq              m15, 4
+    psrldq               m7, 4
+    movd                r6d, m15
+    movd               r13d, m7
+    movd                m15, [base+subpel_filters+ r4*8+2]
+    movd                 m2, [base+subpel_filters+r11*8+2]
+    movd                 m3, [base+subpel_filters+ r6*8+2]
+    movd                 m4, [base+subpel_filters+r13*8+2]
+%else
+    movd                 r0, m15
+    movd                 rX, m7
+    psrldq              m15, 4
+    psrldq               m7, 4
+    movd                 r4, m15
+    movd                 r5, m7
+    movd                 m1, [base+subpel_filters+r0*8+2]
+    movd                 m2, [base+subpel_filters+rX*8+2]
+    movd                 m3, [base+subpel_filters+r4*8+2]
+    movd                 m7, [base+subpel_filters+r5*8+2]
+    movifprep            r3, r3m
+    SWAP                 m4, m7
+ %define m15 m1
+%endif
+    mova                 m5, [base+bdct_lb_dw]
+    movq                 m6, [base+subpel_s_shuf2]
+    psrld               m14, 10
+    punpckldq           m15, m3
+    punpckldq            m2, m4
+    punpcklqdq          m15, m2
+    punpcklqdq           m6, m6
+    pshufb              m14, m5
+    paddb               m14, m6
+%if ARCH_X86_64
+    pcmpeqd              m0, m9
+    pand                m11, m0
+%else
+    mova        [esp+0x180], m14
+    SWAP                 m7, m4
+    pxor                 m3, m3
+    pcmpeqd              m0, m3
+    pand                 m2, m11, m0
+ %define m11 m2
+%endif
+    pandn                m0, m15
+%if ARCH_X86_64
+    SWAP                m15, m0
+%else
+ %define m15 m0
+%endif
+    por                 m15, m11
+%if ARCH_X86_64
+    movu                 m7, [srcq+ssq*0]
+    movu                 m9, [srcq+ssq*1]
+    movu                 m8, [srcq+ssq*2]
+    movu                m10, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    movu                 m2, [srcq+ssq*0]
+    movu                 m4, [srcq+ssq*1]
+    movu                 m3, [srcq+ssq*2]
+    movu                 m5, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pshufb               m7, m14
+    pshufb               m9, m14
+    pshufb               m8, m14
+    pshufb              m10, m14
+    pshufb               m2, m14
+    pshufb               m4, m14
+    pshufb               m3, m14
+    pshufb               m5, m14
+    pmaddubsw            m7, m15
+    pmaddubsw            m9, m15
+    pmaddubsw            m8, m15
+    pmaddubsw           m10, m15
+    pmaddubsw            m2, m15
+    pmaddubsw            m4, m15
+    pmaddubsw            m3, m15
+    pmaddubsw            m5, m15
+    phaddw               m7, m9
+    phaddw               m8, m10
+    phaddw               m9, m2, m4
+    phaddw               m3, m5
+    pmulhrsw             m7, m12            ; 0 1
+    pmulhrsw             m8, m12            ; 2 3
+    pmulhrsw             m9, m12            ; 4 5
+    pmulhrsw             m3, m12            ; 6 7
+    shufps               m4, m7, m8, q1032  ; 1 2
+    shufps               m5, m8, m9, q1032  ; 3 4
+    shufps               m6, m9, m3, q1032  ; 5 6
+    psrldq              m11, m3, 8          ; 7 _
+    punpcklwd            m0, m7, m4 ; 01
+    punpckhwd            m7, m4     ; 12
+    punpcklwd            m1, m8, m5 ; 23
+    punpckhwd            m8, m5     ; 34
+    punpcklwd            m2, m9, m6 ; 45
+    punpckhwd            m9, m6     ; 56
+    punpcklwd            m3, m11    ; 67
+    mova         [rsp+0x00], m7
+    mova         [rsp+0x10], m8
+    mova         [rsp+0x20], m9
+%else
+    mova        [esp+0x190], m15
+    lea                ss3q, [ssq*3]
+    movu                 m2, [srcq+ssq*0]
+    movu                 m3, [srcq+ssq*1]
+    movu                 m7, [srcq+ssq*2]
+    movu                 m6, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pshufb               m2, m14
+    pshufb               m3, m14
+    pshufb               m7, m14
+    pshufb               m6, m14
+    pmaddubsw            m2, m15
+    pmaddubsw            m3, m15
+    pmaddubsw            m7, m15
+    pmaddubsw            m6, m15
+    phaddw               m2, m3
+    phaddw               m7, m6
+    movu                 m1, [srcq+ssq*0]
+    movu                 m5, [srcq+ssq*1]
+    movu                 m3, [srcq+ssq*2]
+    movu                 m6, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pshufb               m1, m14
+    pshufb               m5, m14
+    pshufb               m3, m14
+    pshufb               m6, m14
+    pmaddubsw            m1, m15
+    pmaddubsw            m5, m15
+    pmaddubsw            m3, m15
+    pmaddubsw            m6, m15
+    phaddw               m1, m5
+    phaddw               m3, m6
+    pmulhrsw             m2, m12
+    pmulhrsw             m7, m12
+    pmulhrsw             m1, m12
+    pmulhrsw             m3, m12
+    shufps               m4, m2, m7, q1032  ; 1 2
+    shufps               m5, m7, m1, q1032  ; 3 4
+    shufps               m6, m1, m3, q1032  ; 5 6
+    psrldq               m0, m3, 8          ; 7 _
+    mova        [esp+0x1a0], m0
+ %define m11 [esp+0x1a0]
+    punpcklwd            m0, m2, m4      ; 01
+    punpckhwd            m2, m4          ; 12
+    punpcklwd            m4, m7, m5      ; 23
+    punpckhwd            m7, m5          ; 34
+    punpcklwd            m5, m1, m6      ; 45
+    punpckhwd            m1, m6          ; 56
+    punpcklwd            m3, [esp+0x1a0] ; 67
+    mov                 myd, mym
+    mov                  r0, r0m
+    mova        [esp+0x1b0], m0 ; 01
+    mova        [esp+0x1c0], m4 ; 23
+    mova        [esp+0x1d0], m5 ; 45
+    mova        [esp+0x1e0], m3 ; 67
+    mova         [rsp+0x00], m2 ; 12
+    mova         [rsp+0x10], m7 ; 34
+    mova         [rsp+0x20], m1 ; 56
+    SWAP                 m1, m4
+    SWAP                 m2, m5
+%endif
+.w4_loop:
+    and                 myd, 0x3ff
+%if ARCH_X86_64
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq                m10, r6q
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    pshufd               m7, m10, q0000
+    pshufd               m8, m10, q1111
+    pshufd               m9, m10, q2222
+    pshufd              m10, m10, q3333
+    pmaddwd              m4, m0, m7
+    pmaddwd              m5, m1, m8
+    pmaddwd              m6, m2, m9
+    pmaddwd              m7, m3, m10
+    paddd                m4, m5
+    paddd                m6, m7
+    paddd                m4, m13
+    paddd                m4, m6
+%else
+    mov                 mym, myd
+    mov                  r5, [esp+0x1f4]
+    xor                  r3, r3
+    shr                  r4, 6
+    lea                  r5, [r5+r4]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r5*8+0]
+    cmovnz               r3, [base+subpel_filters+r5*8+4]
+    movd                 m7, r4
+    movd                 m6, r3
+    punpckldq            m7, m6
+    punpcklbw            m7, m7
+    psraw                m7, 8
+    pshufd               m4, m7, q0000
+    pshufd               m5, m7, q1111
+    pshufd               m6, m7, q2222
+    pshufd               m7, m7, q3333
+    pmaddwd              m0, m4
+    pmaddwd              m1, m5
+    pmaddwd              m2, m6
+    pmaddwd              m3, m7
+    paddd                m0, m1
+    paddd                m2, m3
+    paddd                m0, m13
+    paddd                m0, m2
+    SWAP                 m4, m0
+%endif
+    psrad                m4, rndshift
+    packssdw             m4, m4
+%ifidn %1, put
+    packuswb             m4, m4
+    movd             [dstq], m4
+    add                dstq, dsmp
+%else
+    movq             [tmpq], m4
+    add                tmpq, 8
+%endif
+    dec                  hd
+    jz .ret
+%if ARCH_X86_64
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .w4_loop
+%else
+    SWAP                 m0, m4
+    mov                 myd, mym
+    mov                  r3, r3m
+    add                 myd, dym
+    test                myd, ~0x3ff
+    jnz .w4_next_line
+    mova                 m0, [esp+0x1b0]
+    mova                 m1, [esp+0x1c0]
+    mova                 m2, [esp+0x1d0]
+    mova                 m3, [esp+0x1e0]
+    jmp .w4_loop
+.w4_next_line:
+  %define m14 [esp+0x180]
+  %define m15 [esp+0x190]
+%endif
+    movu                 m4, [srcq]
+    test                myd, 0x400
+    jz .w4_skip_line
+%if ARCH_X86_64
+    mova                 m0, [rsp+0x00]
+    mova         [rsp+0x00], m1
+    mova                 m1, [rsp+0x10]
+    mova         [rsp+0x10], m2
+    mova                 m2, [rsp+0x20]
+    mova         [rsp+0x20], m3
+%else
+    mova                 m5, [esp+0x1c0]
+    mova                 m0, [rsp+0x000]
+    mova         [rsp+0x00], m5
+    mova        [esp+0x1b0], m0
+    mova                 m6, [esp+0x1d0]
+    mova                 m1, [rsp+0x010]
+    mova         [rsp+0x10], m6
+    mova        [esp+0x1c0], m1
+    mova                 m7, [esp+0x1e0]
+    mova                 m2, [rsp+0x020]
+    mova         [rsp+0x20], m7
+    mova        [esp+0x1d0], m2
+%endif
+    pshufb               m4, m14
+    pmaddubsw            m4, m15
+    phaddw               m4, m4
+    pmulhrsw             m4, m12
+    punpcklwd            m3, m11, m4
+%if ARCH_X86_32
+    mova        [esp+0x1e0], m3
+%endif
+    mova                m11, m4
+    add                srcq, ssq
+    jmp .w4_loop
+.w4_skip_line:
+%if ARCH_X86_32
+    mova                 m0, [esp+0x1c0]
+    mova                 m1, [esp+0x1d0]
+    mova                 m2, [esp+0x1e0]
+%endif
+    movu                 m5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    mova                 m6, [rsp+0x10]
+    mova                 m7, [rsp+0x20]
+    pshufb               m4, m14
+    pshufb               m5, m14
+    pmaddubsw            m4, m15
+    pmaddubsw            m5, m15
+    phaddw               m4, m5
+    pmulhrsw             m4, m12
+    punpcklwd            m5, m11, m4
+    mova         [rsp+0x00], m6
+    mova         [rsp+0x10], m7
+    mova         [rsp+0x20], m5
+%if ARCH_X86_64
+    psrldq              m11, m4, 8
+    mova                 m0, m1
+    mova                 m1, m2
+    mova                 m2, m3
+    punpcklwd            m3, m4, m11
+%else
+    psrldq               m6, m4, 8
+    punpcklwd            m3, m4, m6
+    mova        [esp+0x1a0], m6
+    mova        [esp+0x1b0], m0
+    mova        [esp+0x1c0], m1
+    mova        [esp+0x1d0], m2
+    mova        [esp+0x1e0], m3
+%endif
+    jmp .w4_loop
+INIT_XMM ssse3
+.w8:
+    mov    dword [rsp+0x90], 1
+    movifprep   tmp_stridem, 16
+    jmp .w_start
+.w16:
+    mov    dword [rsp+0x90], 2
+    movifprep   tmp_stridem, 32
+    jmp .w_start
+.w32:
+    mov    dword [rsp+0x90], 4
+    movifprep   tmp_stridem, 64
+    jmp .w_start
+.w64:
+    mov    dword [rsp+0x90], 8
+    movifprep   tmp_stridem, 128
+    jmp .w_start
+.w128:
+    mov    dword [rsp+0x90], 16
+    movifprep   tmp_stridem, 256
+.w_start:
+%ifidn %1, put
+    movifnidn           dsm, dsq
+%endif
+%if ARCH_X86_64
+    shr                 t0d, 16
+    movd                m15, t0d
+%else
+ %define m8  m0
+ %xdefine m14 m4
+ %define m15 m3
+ %if isprep
+  %define ssq ssm
+ %endif
+    mov                  r4, [esp+0x1f0]
+    shr                  r4, 16
+    movd                m15, r4
+    mov                  r0, r0m
+    mov                 myd, mym
+%endif
+    sub                srcq, 3
+    pslld                m7, m8, 2 ; dx*4
+    pmaddwd              m8, [base+rescale_mul] ; dx*[0-3]
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+    mova        [rsp+0x100], m7
+    mova        [rsp+0x120], m15
+    mov         [rsp+0x098], srcq
+    mov         [rsp+0x130], r0q ; dstq / tmpq
+%if ARCH_X86_64 && UNIX64
+    mov                  hm, hd
+%elif ARCH_X86_32
+    mov                  r5, hm
+    mov         [esp+0x094], myd
+    mov         [esp+0x134], r5
+%endif
+    jmp .hloop
+.hloop_prep:
+    dec   dword [rsp+0x090]
+    jz .ret
+%if ARCH_X86_64
+    add   qword [rsp+0x130], 8*(isprep+1)
+    mov                  hd, hm
+%else
+    add   dword [esp+0x130], 8*(isprep+1)
+    mov                 myd, [esp+0x094]
+    mov                  r5, [esp+0x134]
+    mov                  r0, [esp+0x130]
+%endif
+    mova                 m7, [rsp+0x100]
+    mova                m14, [rsp+0x110]
+%if ARCH_X86_64
+    mova                m10, [base+pd_0x3ff]
+%endif
+    mova                m15, [rsp+0x120]
+    pxor                 m9, m9
+    mov                srcq, [rsp+0x098]
+%if ARCH_X86_64
+    mov                 r0q, [rsp+0x130] ; dstq / tmpq
+%else
+    mov                 mym, myd
+    mov                  hm, r5
+    mov                 r0m, r0
+    mov                  r3, r3m
+%endif
+    paddd               m14, m7
+.hloop:
+%if ARCH_X86_64
+    mova                m11, [base+pq_0x40000000]
+%else
+ %define m11 [base+pq_0x40000000]
+%endif
+    psrld                m2, m14, 10
+    mova              [rsp], m2
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd                m5, m15, m6
+    pcmpeqd              m6, m9
+    psrldq               m2, m5, 8
+%if ARCH_X86_64
+    movd                r4d, m5
+    movd                r6d, m2
+    psrldq               m5, 4
+    psrldq               m2, 4
+    movd                r7d, m5
+    movd                r9d, m2
+    movq                 m0, [base+subpel_filters+r4*8]
+    movq                 m1, [base+subpel_filters+r6*8]
+    movhps               m0, [base+subpel_filters+r7*8]
+    movhps               m1, [base+subpel_filters+r9*8]
+%else
+    movd                 r0, m5
+    movd                 rX, m2
+    psrldq               m5, 4
+    psrldq               m2, 4
+    movd                 r4, m5
+    movd                 r5, m2
+    movq                 m0, [base+subpel_filters+r0*8]
+    movq                 m1, [base+subpel_filters+rX*8]
+    movhps               m0, [base+subpel_filters+r4*8]
+    movhps               m1, [base+subpel_filters+r5*8]
+    pxor                 m2, m2
+ %define m9 m2
+%endif
+    paddd               m14, m7 ; mx+dx*[4-7]
+    pand                 m5, m14, m10
+    psrld                m5, 6
+    paddd               m15, m5
+    pcmpeqd              m5, m9
+    mova        [rsp+0x110], m14
+    psrldq               m4, m15, 8
+%if ARCH_X86_64
+    movd               r10d, m15
+    movd               r11d, m4
+    psrldq              m15, 4
+    psrldq               m4, 4
+    movd               r13d, m15
+    movd                rXd, m4
+    movq                 m2, [base+subpel_filters+r10*8]
+    movq                 m3, [base+subpel_filters+r11*8]
+    movhps               m2, [base+subpel_filters+r13*8]
+    movhps               m3, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    psrldq               m4, m14, 8
+    movd               r10d, m14
+    movd               r11d, m4
+    psrldq              m14, 4
+    psrldq               m4, 4
+    movd               r13d, m14
+    movd                rXd, m4
+    mov                 r4d, [rsp+ 0]
+    mov                 r6d, [rsp+ 8]
+    mov                 r7d, [rsp+ 4]
+    mov                 r9d, [rsp+12]
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd              m14, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m7, m11, m4
+    pand                 m8, m11, m6
+    pand                m15, m11, m14
+    pand                m11, m11, m5
+    pandn                m4, m0
+    pandn                m6, m1
+    pandn               m14, m2
+    pandn                m5, m3
+    por                  m7, m4
+    por                  m8, m6
+    por                 m15, m14
+    por                 m11, m5
+    mova         [rsp+0x10], m7
+    mova         [rsp+0x20], m8
+    mova         [rsp+0x30], m15
+    mova         [rsp+0x40], m11
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 9, 10, 7, 8, 15, 11 ; 0-1
+    mova         [rsp+0x50], m1
+    mova         [rsp+0x60], m2
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 1, 2, 9, 10, 7, 8, 15, 11 ; 2-3
+    mova         [rsp+0x70], m3
+    mova         [rsp+0x80], m4
+    MC_8TAP_SCALED_H 5, 6, 1, 2, 3, 4, 9, 10, 7, 8, 15, 11 ; 4-5
+    MC_8TAP_SCALED_H 0,14, 1, 2, 3, 4, 9, 10, 7, 8, 15, 11 ; 6-7
+    SWAP                 m7, m0
+    SWAP                 m8, m14
+    mova                 m1, [rsp+0x50]
+    mova                 m2, [rsp+0x60]
+    mova                 m3, [rsp+0x70]
+    mova                 m9, [rsp+0x80]
+    mov                 myd, mym
+    mov                 dyd, dym
+    punpcklwd            m4, m5, m6 ; 45a
+    punpckhwd            m5, m6     ; 45b
+    punpcklwd            m6, m7, m8 ; 67a
+    punpckhwd            m7, m8     ; 67b
+    punpcklwd            m0, m1, m2 ; 01a
+    punpckhwd            m1, m2     ; 01b
+    punpcklwd            m2, m3, m9 ; 23a
+    punpckhwd            m3, m9     ; 23b
+    mova         [rsp+0x50], m4
+    mova         [rsp+0x60], m5
+    mova         [rsp+0x70], m6
+    mova         [rsp+0x80], m7
+    SWAP                m14, m8
+.vloop:
+    and                 myd, 0x3ff
+    mov                 r6d, 64 << 24
+    mov                 r4d, myd
+    shr                 r4d, 6
+    lea                 r4d, [t1+r4]
+    cmovnz              r6q, [base+subpel_filters+r4*8]
+    movq                m11, r6q
+    punpcklbw           m11, m11
+    psraw               m11, 8
+    pshufd               m5, m11, q0000
+    pshufd               m7, m11, q1111
+    pshufd              m10, m11, q2222
+    pshufd              m11, m11, q3333
+    pmaddwd              m4, m5, m0
+    pmaddwd              m5, m5, m1
+    pmaddwd              m6, m7, m2
+    pmaddwd              m7, m7, m3
+    paddd                m4, m13
+    paddd                m5, m13
+    paddd                m4, m6
+    paddd                m5, m7
+    pmaddwd              m6, [rsp+0x50], m10
+    pmaddwd              m7, [rsp+0x60], m10
+    pmaddwd              m8, [rsp+0x70], m11
+    pmaddwd              m9, [rsp+0x80], m11
+    paddd                m4, m6
+    paddd                m5, m7
+    paddd                m4, m8
+    paddd                m5, m9
+%else
+    movd                 r0, m15
+    movd                 rX, m4
+    psrldq              m15, 4
+    psrldq               m4, 4
+    movd                 r4, m15
+    movd                 r5, m4
+    mova                m14, [esp+0x110]
+    movq                 m2, [base+subpel_filters+r0*8]
+    movq                 m3, [base+subpel_filters+rX*8]
+    movhps               m2, [base+subpel_filters+r4*8]
+    movhps               m3, [base+subpel_filters+r5*8]
+    psrld               m14, 10
+    mova           [esp+16], m14
+    mov                  r0, [esp+ 0]
+    mov                  rX, [esp+ 8]
+    mov                  r4, [esp+ 4]
+    mov                  r5, [esp+12]
+    mova         [esp+0x20], m0
+    mova         [esp+0x30], m1
+    mova         [esp+0x40], m2
+    mova         [esp+0x50], m3
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd               m7, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m0, m11, m4
+    pand                 m1, m11, m6
+    pand                 m2, m11, m7
+    pand                 m3, m11, m5
+    pandn                m4, [esp+0x20]
+    pandn                m6, [esp+0x30]
+    pandn                m7, [esp+0x40]
+    pandn                m5, [esp+0x50]
+    por                  m0, m4
+    por                  m1, m6
+    por                  m2, m7
+    por                  m3, m5
+    mova         [esp+0x20], m0
+    mova         [esp+0x30], m1
+    mova         [esp+0x40], m2
+    mova         [esp+0x50], m3
+    MC_8TAP_SCALED_H   0x20, 0x140, 0 ; 0-1
+    MC_8TAP_SCALED_H   0x20, 0x160    ; 2-3
+    MC_8TAP_SCALED_H   0x20, 0x180    ; 4-5
+    MC_8TAP_SCALED_H   0x20, 0x1a0    ; 6-7
+    mova                 m5, [esp+0x180]
+    mova                 m6, [esp+0x190]
+    mova                 m7, [esp+0x1a0]
+    mova                 m0, [esp+0x1b0]
+    mov                 myd, mym
+    punpcklwd            m4, m5, m6      ; 45a
+    punpckhwd            m5, m6          ; 45b
+    punpcklwd            m6, m7, m0      ; 67a
+    punpckhwd            m7, m0          ; 67b
+    mova        [esp+0x180], m4
+    mova        [esp+0x190], m5
+    mova        [esp+0x1a0], m6
+    mova        [esp+0x1b0], m7
+    mova                 m1, [esp+0x140]
+    mova                 m2, [esp+0x150]
+    mova                 m3, [esp+0x160]
+    mova                 m4, [esp+0x170]
+    punpcklwd            m0, m1, m2      ; 01a
+    punpckhwd            m1, m2          ; 01b
+    punpcklwd            m2, m3, m4      ; 23a
+    punpckhwd            m3, m4          ; 23b
+    mova        [esp+0x140], m0
+    mova        [esp+0x150], m1
+    mova        [esp+0x160], m2
+    mova        [esp+0x170], m3
+.vloop:
+    mov                  r0, r0m
+    mov                  r5, [esp+0x1f4]
+    and                 myd, 0x3ff
+    mov                 mym, myd
+    xor                  r3, r3
+    shr                  r4, 6
+    lea                  r5, [r5+r4]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r5*8+0]
+    cmovnz               r3, [base+subpel_filters+r5*8+4]
+    movd                 m7, r4
+    movd                 m6, r3
+    punpckldq            m7, m6
+    punpcklbw            m7, m7
+    psraw                m7, 8
+    pshufd               m4, m7, q0000
+    pshufd               m5, m7, q1111
+    pmaddwd              m0, m4
+    pmaddwd              m1, m4
+    pmaddwd              m2, m5
+    pmaddwd              m3, m5
+    pshufd               m6, m7, q2222
+    pshufd               m7, m7, q3333
+    paddd                m0, m2
+    paddd                m1, m3
+    pmaddwd              m2, [esp+0x180], m6
+    pmaddwd              m3, [esp+0x190], m6
+    pmaddwd              m4, [esp+0x1a0], m7
+    pmaddwd              m5, [esp+0x1b0], m7
+    paddd                m0, m2
+    paddd                m1, m3
+    paddd                m0, m13
+    paddd                m1, m13
+    paddd                m4, m0
+    paddd                m5, m1
+%endif
+    psrad                m4, rndshift
+    psrad                m5, rndshift
+    packssdw             m4, m5
+%ifidn %1, put
+    packuswb             m4, m4
+    movq             [dstq], m4
+    add                dstq, dsm
+%else
+    mova             [tmpq], m4
+    add                tmpq, tmp_stridem
+%endif
+    dec                  hd
+    jz .hloop_prep
+%if ARCH_X86_64
+    add                 myd, dyd
+    test                myd, ~0x3ff
+    jz .vloop
+    test                myd, 0x400
+    mov         [rsp+0x140], myd
+    mov                 r4d, [rsp+ 0]
+    mov                 r6d, [rsp+ 8]
+    mov                 r7d, [rsp+ 4]
+    mov                 r9d, [rsp+12]
+    jz .skip_line
+    mova                m14, [base+unpckw]
+    movq                 m6, [srcq+r10]
+    movq                 m7, [srcq+r11]
+    movhps               m6, [srcq+r13]
+    movhps               m7, [srcq+ rX]
+    movq                 m4, [srcq+ r4]
+    movq                 m5, [srcq+ r6]
+    movhps               m4, [srcq+ r7]
+    movhps               m5, [srcq+ r9]
+    add                srcq, ssq
+    mov                 myd, [rsp+0x140]
+    mov                 dyd, dym
+    pshufd               m9, m14, q1032
+    pshufb               m0, m14                ; 0a 1a
+    pshufb               m1, m14                ; 0b 1b
+    pshufb               m2, m9                 ; 3a 2a
+    pshufb               m3, m9                 ; 3b 2b
+    pmaddubsw            m6, [rsp+0x30]
+    pmaddubsw            m7, [rsp+0x40]
+    pmaddubsw            m4, [rsp+0x10]
+    pmaddubsw            m5, [rsp+0x20]
+    phaddw               m6, m7
+    phaddw               m4, m5
+    phaddw               m4, m6
+    pmulhrsw             m4, m12
+    pshufb               m5, [rsp+0x50], m14    ; 4a 5a
+    pshufb               m6, [rsp+0x60], m14    ; 4b 5b
+    pshufb               m7, [rsp+0x70], m9     ; 7a 6a
+    pshufb               m8, [rsp+0x80], m9     ; 7b 6b
+    punpckhwd            m0, m2 ; 12a
+    punpckhwd            m1, m3 ; 12b
+    punpcklwd            m2, m5 ; 34a
+    punpcklwd            m3, m6 ; 34b
+    punpckhwd            m5, m7 ; 56a
+    punpckhwd            m6, m8 ; 56b
+    punpcklwd            m7, m4 ; 78a
+    punpckhqdq           m4, m4
+    punpcklwd            m8, m4 ; 78b
+    mova         [rsp+0x50], m5
+    mova         [rsp+0x60], m6
+    mova         [rsp+0x70], m7
+    mova         [rsp+0x80], m8
+    jmp .vloop
+.skip_line:
+    mova                 m0, [rsp+0x10]
+    mova                 m1, [rsp+0x20]
+    mova                m14, [rsp+0x30]
+    mova                m15, [rsp+0x40]
+    MC_8TAP_SCALED_H 4, 8, 5, 6, 7, 9, 10, 11, 0, 1, 14, 15
+    mov                 myd, [rsp+0x140]
+    mov                 dyd, dym
+    mova                 m0, m2         ; 01a
+    mova                 m1, m3         ; 01b
+    mova                 m2, [rsp+0x50] ; 23a
+    mova                 m3, [rsp+0x60] ; 23b
+    mova                 m5, [rsp+0x70] ; 45a
+    mova                 m6, [rsp+0x80] ; 45b
+    punpcklwd            m7, m4, m8     ; 67a
+    punpckhwd            m4, m8         ; 67b
+    mova         [rsp+0x50], m5
+    mova         [rsp+0x60], m6
+    mova         [rsp+0x70], m7
+    mova         [rsp+0x80], m4
+%else
+    mov                 r0m, r0
+    mov                 myd, mym
+    mov                  r3, r3m
+    add                 myd, dym
+    test                myd, ~0x3ff
+    mov                 mym, myd
+    jnz .next_line
+    mova                 m0, [esp+0x140]
+    mova                 m1, [esp+0x150]
+    mova                 m2, [esp+0x160]
+    mova                 m3, [esp+0x170]
+    jmp .vloop
+.next_line:
+    test                myd, 0x400
+    mov                  r0, [esp+ 0]
+    mov                  rX, [esp+ 8]
+    mov                  r4, [esp+ 4]
+    mov                  r5, [esp+12]
+    jz .skip_line
+    mova                 m6, [base+unpckw]
+    mova                 m0, [esp+0x140]
+    mova                 m1, [esp+0x150]
+    mova                 m7, [esp+0x180]
+    movq                 m4, [srcq+r0]
+    movq                 m5, [srcq+rX]
+    movhps               m4, [srcq+r4]
+    movhps               m5, [srcq+r5]
+    pshufb               m0, m6         ; 0a 1a
+    pshufb               m1, m6         ; 0b 1b
+    pshufb               m7, m6         ; 4a 5a
+    mov                  r0, [esp+16]
+    mov                  rX, [esp+24]
+    mov                  r4, [esp+20]
+    mov                  r5, [esp+28]
+    movq                 m3, [srcq+r0]
+    movq                 m2, [srcq+rX]
+    movhps               m3, [srcq+r4]
+    movhps               m2, [srcq+r5]
+    add                srcq, ssq
+    pmaddubsw            m4, [esp+0x20]
+    pmaddubsw            m5, [esp+0x30]
+    pmaddubsw            m3, [esp+0x40]
+    pmaddubsw            m2, [esp+0x50]
+    phaddw               m4, m5
+    phaddw               m3, m2
+    mova                 m5, [esp+0x190]
+    mova                 m2, [esp+0x160]
+    phaddw               m4, m3
+    mova                 m3, [esp+0x170]
+    pmulhrsw             m4, m12        ; 8a 8b
+    mov                 myd, mym
+    pshufb               m5, m6         ; 4b 5b
+    pshufd               m6, m6, q1032
+    pshufb               m2, m6         ; 3a 2a
+    pshufb               m3, m6         ; 3b 2b
+    punpckhwd            m0, m2         ; 12a
+    punpckhwd            m1, m3         ; 12b
+    mova        [esp+0x140], m0
+    mova        [esp+0x150], m1
+    mova                 m0, [esp+0x1a0]
+    mova                 m1, [esp+0x1b0]
+    punpcklwd            m2, m7         ; 34a
+    punpcklwd            m3, m5         ; 34b
+    mova        [esp+0x160], m2
+    mova        [esp+0x170], m3
+    pshufb               m0, m6         ; 7a 6a
+    pshufb               m1, m6         ; 7b 6b
+    punpckhwd            m7, m0         ; 56a
+    punpckhwd            m5, m1         ; 56b
+    punpcklwd            m0, m4
+    punpckhqdq           m4, m4
+    punpcklwd            m1, m4
+    mova        [esp+0x180], m7
+    mova        [esp+0x190], m5
+    mova        [esp+0x1a0], m0
+    mova        [esp+0x1b0], m1
+    mova                 m0, [esp+0x140]
+    mova                 m1, [esp+0x150]
+    jmp .vloop
+.skip_line:
+    MC_8TAP_SCALED_H   0x20, 0x1c0, 0
+    mov                 myd, mym
+    mova                 m0, [esp+0x160]
+    mova                 m1, [esp+0x170]
+    mova                 m2, [esp+0x180]
+    mova                 m3, [esp+0x190]
+    mova         [esp+0x140], m0
+    mova         [esp+0x150], m1
+    mova                 m4, [esp+0x1a0]
+    mova                 m5, [esp+0x1b0]
+    mova        [esp+0x160], m2
+    mova        [esp+0x170], m3
+    mova                 m6, [esp+0x1c0]
+    mova                 m7, [esp+0x1d0]
+    mova        [esp+0x180], m4
+    mova        [esp+0x190], m5
+    punpcklwd            m4, m6, m7
+    punpckhwd            m6, m7
+    mova        [esp+0x1a0], m4
+    mova        [esp+0x1b0], m6
+%endif
+    jmp .vloop
+INIT_XMM ssse3
+.dy1:
+    movzx                wd, word [base+%1_8tap_scaled_ssse3_dy1_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%ifidn %1, put
+.dy1_w2:
+ %if ARCH_X86_64
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd                m15, t0d
+ %else
+  %define m8  m0
+  %define m9  m1
+  %define m14 m4
+  %define m15 m3
+    movzx                r5, byte [esp+0x1f0]
+    dec                srcd
+    movd                m15, r5
+ %endif
+    punpckldq            m9, m8
+    SWAP                 m8, m9
+    paddd               m14, m8 ; mx+dx*[0-1]
+ %if ARCH_X86_64
+    mova                m11, [base+pd_0x4000]
+ %else
+  %define m11 [base+pd_0x4000]
+ %endif
+    pshufd              m15, m15, q0000
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd               m15, m8
+    movd                r4d, m15
+    psrldq              m15, 4
+ %if ARCH_X86_64
+    movd                r6d, m15
+ %else
+    movd                r3d, m15
+ %endif
+    mova                 m5, [base+bdct_lb_dw]
+    mova                 m6, [base+subpel_s_shuf2]
+    movd                m15, [base+subpel_filters+r4*8+2]
+ %if ARCH_X86_64
+    movd                 m7, [base+subpel_filters+r6*8+2]
+ %else
+    movd                 m7, [base+subpel_filters+r3*8+2]
+ %endif
+    pxor                 m9, m9
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+ %if ARCH_X86_32
+    mov                  r3, r3m
+    pshufb              m14, m5
+    paddb               m14, m6
+    mova         [esp+0x00], m14
+  %define m14 [esp+0x00]
+    SWAP                 m5, m0
+    SWAP                 m6, m3
+  %define m8  m5
+  %define m15 m6
+ %endif
+    movq                 m0, [srcq+ssq*0]
+    movq                 m2, [srcq+ssq*2]
+    movhps               m0, [srcq+ssq*1]
+    movhps               m2, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+ %if ARCH_X86_64
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pshufb              m14, m5
+    paddb               m14, m6
+    movq                m10, r4
+ %else
+    mov                 myd, mym
+    mov                  r5, [esp+0x1f4]
+    xor                  r3, r3
+    shr                 myd, 6
+    lea                  r5, [r5+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r5*8+0]
+    cmovnz               r3, [base+subpel_filters+r5*8+4]
+  %define m10 m4
+    movd                m10, r4
+    movd                 m3, r3
+    mov                  r3, r3m
+    punpckldq           m10, m3
+ %endif
+    movq                 m1, [srcq+ssq*0]
+    movq                 m3, [srcq+ssq*2]
+    movhps               m1, [srcq+ssq*1]
+    add                srcq, ss3q
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    punpckldq           m15, m7
+    punpcklqdq          m15, m15
+ %if ARCH_X86_64
+    pand                m11, m8
+ %else
+    pand                 m7, m11, m8
+  %define m11 m7
+ %endif
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m11
+ %if ARCH_X86_64
+    pshufd               m8, m10, q0000
+    pshufd               m9, m10, q1111
+    pshufd              m11, m10, q3333
+    pshufd              m10, m10, q2222
+ %else
+    mova         [esp+0x10], m15
+  %define m15 [esp+0x10]
+    mov                  r0, r0m
+    pshufd               m5, m4, q0000
+    pshufd               m6, m4, q1111
+    pshufd               m7, m4, q2222
+    pshufd               m4, m4, q3333
+  %define m8  [esp+0x20]
+  %define m9  [esp+0x30]
+  %define m10 [esp+0x40]
+  %define m11 [esp+0x50]
+    mova                 m8, m5
+    mova                 m9, m6
+    mova                m10, m7
+    mova                m11, m4
+ %endif
+    pshufb               m0, m14
+    pshufb               m2, m14
+    pshufb               m1, m14
+    pshufb               m3, m14
+    pmaddubsw            m0, m15
+    pmaddubsw            m2, m15
+    pmaddubsw            m1, m15
+    pmaddubsw            m3, m15
+    phaddw               m0, m2
+    phaddw               m1, m3
+    pmulhrsw             m0, m12
+    pmulhrsw             m1, m12
+    palignr              m2, m1, m0, 4
+    pshufd               m4, m1, q2121
+    punpcklwd            m3, m0, m2     ; 01 12
+    punpckhwd            m0, m2         ; 23 34
+    punpcklwd            m2, m1, m4     ; 45 56
+.dy1_w2_loop:
+    movq                 m1, [srcq+ssq*0]
+    movhps               m1, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pmaddwd              m5, m3, m8
+    pmaddwd              m6, m0, m9
+    pmaddwd              m7, m2, m10
+    mova                 m3, m0
+    mova                 m0, m2
+    paddd                m5, m13
+    paddd                m6, m7
+    pshufb               m1, m14
+    pmaddubsw            m1, m15
+    phaddw               m1, m1
+    pmulhrsw             m1, m12
+    palignr              m7, m1, m4, 12
+    punpcklwd            m2, m7, m1     ; 67 78
+    pmaddwd              m7, m2, m11
+    mova                 m4, m1
+    paddd                m5, m6
+    paddd                m5, m7
+    psrad                m5, rndshift
+    packssdw             m5, m5
+    packuswb             m5, m5
+    movd                r4d, m5
+    mov        [dstq+dsq*0], r4w
+    shr                 r4d, 16
+    mov        [dstq+dsq*1], r4w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .dy1_w2_loop
+    RET
+%endif
+INIT_XMM ssse3
+.dy1_w4:
+%if ARCH_X86_64
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd                m15, t0d
+%else
+ %define m10 [base+pd_0x3ff]
+ %define m11 [base+pd_0x4000]
+ %define m8  m0
+ %xdefine m14 m4
+ %define m15 m3
+ %if isprep
+  %define ssq r3
+ %endif
+    movzx                r4, byte [esp+0x1f0]
+    dec                srcq
+    movd                m15, r4
+%endif
+    pmaddwd              m8, [base+rescale_mul]
+%if ARCH_X86_64
+    mova                m11, [base+pd_0x4000]
+%endif
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd               m15, m8
+    psrldq               m7, m15, 8
+%if ARCH_X86_64
+    movd                r4d, m15
+    movd               r11d, m7
+    psrldq              m15, 4
+    psrldq               m7, 4
+    movd                r6d, m15
+    movd               r13d, m7
+    movd                m15, [base+subpel_filters+ r4*8+2]
+    movd                 m2, [base+subpel_filters+r11*8+2]
+    movd                 m3, [base+subpel_filters+ r6*8+2]
+    movd                 m4, [base+subpel_filters+r13*8+2]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+%else
+    movd                 r1, m15
+    movd                 r3, m7
+    psrldq              m15, 4
+    psrldq               m7, 4
+    movd                 r4, m15
+    movd                 r5, m7
+ %define m15 m5
+    SWAP                 m4, m7
+    movd                m15, [base+subpel_filters+r1*8+2]
+    movd                 m2, [base+subpel_filters+r3*8+2]
+    movd                 m3, [base+subpel_filters+r4*8+2]
+    movd                 m4, [base+subpel_filters+r5*8+2]
+    mov                 myd, mym
+    mov                  rX, [esp+0x1f4]
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  rX, [rX+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+rX*8+0]
+    cmovnz               r5, [base+subpel_filters+rX*8+4]
+    mov                  r3, r3m
+ %if isprep
+    lea                ss3q, [ssq*3]
+ %endif
+%endif
+    punpckldq           m15, m3
+    punpckldq            m2, m4
+    punpcklqdq          m15, m2
+    movq                 m6, [base+subpel_s_shuf2]
+%if ARCH_X86_64
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+    pshufb              m14, [base+bdct_lb_dw]
+    movu                 m0, [srcq+ssq*0]
+    movu                 m1, [srcq+ssq*1]
+    movu                 m2, [srcq+ssq*2]
+    movu                 m3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    punpcklqdq           m6, m6
+    movu                 m4, [srcq+ssq*0]
+    movu                 m5, [srcq+ssq*1]
+    movu                 m7, [srcq+ssq*2]
+    add                srcq, ss3q
+    pand                m11, m8
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m11
+    paddb               m14, m6
+    movq                m10, r4q
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    pshufb               m0, m14
+    pshufb               m1, m14
+    pshufb               m2, m14
+    pshufb               m3, m14
+    pshufb               m4, m14
+    pshufb               m5, m14
+    pshufb               m7, m14
+    pmaddubsw            m0, m15
+    pmaddubsw            m1, m15
+    pmaddubsw            m2, m15
+    pmaddubsw            m3, m15
+    pmaddubsw            m4, m15
+    pmaddubsw            m5, m15
+    pmaddubsw            m7, m15
+    phaddw               m0, m1
+    phaddw               m2, m3
+    phaddw               m4, m5
+    phaddw               m6, m7, m7
+    pmulhrsw             m0, m12    ; 0 1
+    pmulhrsw             m2, m12    ; 2 3
+    pmulhrsw             m4, m12    ; 4 5
+    pmulhrsw             m6, m12    ; 6 _
+    shufps               m1, m0, m2, q1032  ; 1 2
+    shufps               m3, m2, m4, q1032  ; 3 4
+    shufps               m5, m4, m6, q1032  ; 5 6
+    punpcklwd            m7, m0, m1 ; 01
+    punpckhwd            m0, m1     ; 12
+    punpcklwd            m8, m2, m3 ; 23
+    punpckhwd            m2, m3     ; 34
+    punpcklwd            m9, m4, m5 ; 45
+    punpckhwd            m4, m5     ; 56
+%else
+    pxor                 m3, m3
+    pcmpeqd              m8, m3
+    psrld               m14, 10
+    pshufb              m14, [base+bdct_lb_dw]
+    movu                 m1, [srcq+ssq*0]
+    movu                 m2, [srcq+ssq*1]
+    movu                 m3, [srcq+ssq*2]
+    add                srcq, ss3q
+    punpcklqdq           m6, m6
+    SWAP                 m4, m7
+    pand                 m7, m11, m8
+    pandn                m8, m15
+    SWAP                 m5, m0
+    por                 m15, m7
+    paddb               m14, m6
+    movu                 m0, [srcq+ssq*0]
+    movu                 m7, [srcq+ssq*1]
+    movu                 m6, [srcq+ssq*2]
+    pshufb               m1, m14
+    pshufb               m2, m14
+    pshufb               m3, m14
+    pshufb               m0, m14
+    pshufb               m7, m14
+    pshufb               m6, m14
+    pmaddubsw            m1, m15
+    pmaddubsw            m2, m15
+    pmaddubsw            m3, m15
+    mova         [esp+0x00], m14
+    mova         [esp+0x10], m15
+    pmaddubsw            m0, m15
+    pmaddubsw            m7, m15
+    pmaddubsw            m6, m15
+    phaddw               m1, m2
+    movu                 m2, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    mov                  r0, r0m
+    phaddw               m3, m0
+    pshufb               m2, m14
+    pmaddubsw            m2, m15
+ %define m14 [esp+0x00]
+ %define m15 [esp+0x10]
+    phaddw               m7, m6
+    phaddw               m2, m2
+    movd                 m6, r4
+    movd                 m0, r5
+    punpckldq            m6, m0
+    punpcklbw            m6, m6
+    psraw                m6, 8
+    mova         [esp+0x20], m6
+    pmulhrsw             m1, m12 ; 0 1
+    pmulhrsw             m3, m12 ; 2 3
+    pmulhrsw             m7, m12 ; 4 5
+    pmulhrsw             m2, m12 ; 6 _
+    shufps               m0, m1, m3, q1032  ; 1 2
+    shufps               m4, m3, m7, q1032  ; 3 4
+    shufps               m5, m7, m2, q1032  ; 5 6
+    punpcklwd            m6, m1, m0 ; 01
+    punpckhwd            m1, m0     ; 12
+    mova         [esp+0x30], m1
+    punpcklwd            m1, m3, m4 ; 23
+    punpckhwd            m3, m4     ; 34
+    mova         [esp+0x40], m3
+    punpcklwd            m3, m7, m5 ; 45
+    punpckhwd            m7, m5     ; 56
+    mova         [esp+0x50], m7
+    mova         [esp+0x60], m2
+    mova                 m0, [esp+0x20]
+ %xdefine m8 m1
+ %xdefine m9 m3
+ %xdefine m10 m0
+    SWAP                 m7, m6
+    SWAP                 m1, m4
+    SWAP                 m3, m2
+%endif
+    pshufd               m1, m10, q0000
+    pshufd               m3, m10, q1111
+    pshufd               m5, m10, q2222
+    pshufd              m10, m10, q3333
+%if ARCH_X86_64
+    mova         [rsp+0x00], m8
+    mova         [rsp+0x10], m2
+    mova         [rsp+0x20], m9
+    mova         [rsp+0x30], m4
+%else
+    mova         [esp+0x70], m8
+    mova         [esp+0x80], m9
+    mova         [esp+0x90], m1
+    mova         [esp+0xa0], m3
+    mova         [esp+0xb0], m5
+    mova         [esp+0xc0], m10
+ %ifidn %1, put
+    mov                 dsd, dsm
+ %endif
+ %define m11 m6
+%endif
+.dy1_w4_loop:
+%if ARCH_X86_64
+    movu                m11, [srcq+ssq*0]
+    pmaddwd              m7, m1
+    pmaddwd              m8, m3
+    pmaddwd              m0, m1
+    pmaddwd              m2, m3
+    pmaddwd              m9, m5
+    pmaddwd              m4, m5
+    paddd                m7, m8
+    paddd                m0, m2
+    movu                 m8, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb              m11, m14
+    pmaddubsw           m11, m15
+    paddd                m7, m13
+    paddd                m0, m13
+    paddd                m7, m9
+    paddd                m0, m4
+    pshufb               m8, m14
+    pmaddubsw            m8, m15
+    phaddw              m11, m8
+    mova                 m8, [rsp+0x20]
+    pmulhrsw            m11, m12
+    punpcklwd            m9, m6, m11    ; 67
+    psrldq               m6, m11, 8
+    punpcklwd            m4, m11, m6    ; 78
+    pmaddwd              m2, m9, m10
+    pmaddwd             m11, m4, m10
+    paddd                m7, m2
+    mova                 m2, [rsp+0x30]
+    paddd                m0, m11
+%else
+    SWAP                 m7, m6
+    SWAP                 m1, m4
+    SWAP                 m3, m2
+    movu                 m5, [srcq+ssq*0]
+    mova                 m0, [esp+0x30]
+    mova                 m2, [esp+0x40]
+    mova                 m4, [esp+0x50]
+    pmaddwd              m6, [esp+0x90]
+    pmaddwd              m1, [esp+0xa0]
+    pmaddwd              m0, [esp+0x90]
+    pmaddwd              m2, [esp+0xa0]
+    pmaddwd              m3, [esp+0xb0]
+    pmaddwd              m4, [esp+0xb0]
+    paddd                m6, m1
+    paddd                m0, m2
+    movu                 m7, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pshufb               m5, m14
+    pmaddubsw            m5, m15
+    paddd                m6, m13
+    paddd                m0, m13
+    paddd                m6, m3
+    paddd                m0, m4
+    pshufb               m7, m14
+    pmaddubsw            m7, m15
+    phaddw               m5, m7
+    mova                 m7, [rsp+0x80]
+    pmulhrsw             m5, m12
+    punpcklwd            m3, [esp+0x60], m5 ; 67
+    psrldq               m1, m5, 8
+    punpcklwd            m4, m5, m1         ; 78
+    pmaddwd              m2, m3, [esp+0xc0]
+    pmaddwd              m5, m4, [esp+0xc0]
+    mova         [esp+0x60], m1
+    paddd                m6, m2
+    mova                 m2, [esp+0x50]
+    paddd                m0, m5
+    SWAP                 m7, m6
+%endif
+    psrad                m7, rndshift
+    psrad                m0, rndshift
+    packssdw             m7, m0
+%if ARCH_X86_64
+    mova                 m0, [rsp+0x10]
+%else
+    mova                 m0, [esp+0x40]
+%define m11 m5
+%endif
+%ifidn %1, put
+    packuswb             m7, m7
+    psrldq              m11, m7, 4
+    movd       [dstq+dsq*0], m7
+    movd       [dstq+dsq*1], m11
+    lea                dstq, [dstq+dsq*2]
+%else
+    mova             [tmpq], m7
+    add                tmpq, 16
+%endif
+    sub                  hd, 2
+    jz .ret
+%if ARCH_X86_64
+    mova                 m7, [rsp+0x00]
+    mova         [rsp+0x00], m8
+    mova         [rsp+0x10], m2
+    mova         [rsp+0x20], m9
+    mova         [rsp+0x30], m4
+%else
+    mova                 m7, [esp+0x70] ; 01
+    mova                 m1, [esp+0x80] ; 23
+    mova                 m2, [esp+0x50] ; 34
+    mova         [esp+0x30], m0
+    mova         [esp+0x70], m1
+    mova         [esp+0x40], m2
+    mova         [esp+0x80], m3
+    mova         [esp+0x50], m4
+%endif
+    jmp .dy1_w4_loop
+INIT_XMM ssse3
+.dy1_w8:
+    mov    dword [rsp+0x90], 1
+    movifprep   tmp_stridem, 16
+    jmp .dy1_w_start
+.dy1_w16:
+    mov    dword [rsp+0x90], 2
+    movifprep   tmp_stridem, 32
+    jmp .dy1_w_start
+.dy1_w32:
+    mov    dword [rsp+0x90], 4
+    movifprep   tmp_stridem, 64
+    jmp .dy1_w_start
+.dy1_w64:
+    mov    dword [rsp+0x90], 8
+    movifprep   tmp_stridem, 128
+    jmp .dy1_w_start
+.dy1_w128:
+    mov    dword [rsp+0x90], 16
+    movifprep   tmp_stridem, 256
+.dy1_w_start:
+    mov                 myd, mym
+%ifidn %1, put
+    movifnidn           dsm, dsq
+%endif
+%if ARCH_X86_64
+    shr                 t0d, 16
+    sub                srcq, 3
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    movd                m15, t0d
+%else
+ %define m8   m0
+ %define m9   m1
+ %xdefine m14 m4
+ %xdefine m15 m3
+ %if isprep
+  %define ssq ssm
+ %endif
+    mov                  r5, [esp+0x1f0]
+    mov                  r3, [esp+0x1f4]
+    shr                  r5, 16
+    sub                srcq, 3
+    movd                m15, r5
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  r3, [r3+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r3*8+0]
+    cmovnz               r5, [base+subpel_filters+r3*8+4]
+    mov                  r0, r0m
+    mov                  r3, r3m
+%endif
+    pslld                m7, m8, 2 ; dx*4
+    pmaddwd              m8, [base+rescale_mul] ; dx*[0-3]
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+%if ARCH_X86_64
+    movq                 m3, r4q
+    punpcklbw            m3, m3
+    psraw                m3, 8
+%else
+    movd                 m5, r4
+    movd                 m6, r5
+    punpckldq            m5, m6
+    punpcklbw            m5, m5
+    psraw                m5, 8
+    SWAP                 m3, m5
+%endif
+    mova        [rsp+0x100], m7
+    mova        [rsp+0x120], m15
+    mov         [rsp+0x098], srcq
+    mov         [rsp+0x130], r0q ; dstq / tmpq
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    mova        [rsp+0x140], m0
+    mova        [rsp+0x150], m1
+    mova        [rsp+0x160], m2
+    mova        [rsp+0x170], m3
+%if ARCH_X86_64 && UNIX64
+    mov                  hm, hd
+%elif ARCH_X86_32
+    SWAP                  m5, m3
+    mov                   r5, hm
+    mov          [esp+0x134], r5
+%endif
+    jmp .dy1_hloop
+.dy1_hloop_prep:
+    dec   dword [rsp+0x090]
+    jz .ret
+%if ARCH_X86_64
+    add   qword [rsp+0x130], 8*(isprep+1)
+    mov                  hd, hm
+%else
+    add   dword [rsp+0x130], 8*(isprep+1)
+    mov                  r5, [esp+0x134]
+    mov                  r0, [esp+0x130]
+%endif
+    mova                 m7, [rsp+0x100]
+    mova                m14, [rsp+0x110]
+%if ARCH_X86_64
+    mova                m10, [base+pd_0x3ff]
+%else
+ %define m10 [base+pd_0x3ff]
+%endif
+    mova                m15, [rsp+0x120]
+    mov                srcq, [rsp+0x098]
+%if ARCH_X86_64
+    mov                 r0q, [rsp+0x130] ; dstq / tmpq
+%else
+    mov                  hm, r5
+    mov                 r0m, r0
+    mov                  r3, r3m
+%endif
+    paddd               m14, m7
+.dy1_hloop:
+    pxor                 m9, m9
+%if ARCH_X86_64
+    mova                m11, [base+pq_0x40000000]
+%else
+ %define m11 [base+pq_0x40000000]
+%endif
+    psrld                m2, m14, 10
+    mova              [rsp], m2
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd                m5, m15, m6
+    pcmpeqd              m6, m9
+    psrldq               m2, m5, 8
+%if ARCH_X86_64
+    movd                r4d, m5
+    movd                r6d, m2
+    psrldq               m5, 4
+    psrldq               m2, 4
+    movd                r7d, m5
+    movd                r9d, m2
+    movq                 m0, [base+subpel_filters+r4*8]
+    movq                 m1, [base+subpel_filters+r6*8]
+    movhps               m0, [base+subpel_filters+r7*8]
+    movhps               m1, [base+subpel_filters+r9*8]
+%else
+    movd                 r0, m5
+    movd                 rX, m2
+    psrldq               m5, 4
+    psrldq               m2, 4
+    movd                 r4, m5
+    movd                 r5, m2
+    movq                 m0, [base+subpel_filters+r0*8]
+    movq                 m1, [base+subpel_filters+rX*8]
+    movhps               m0, [base+subpel_filters+r4*8]
+    movhps               m1, [base+subpel_filters+r5*8]
+    pxor                 m2, m2
+ %define m9 m2
+%endif
+    paddd               m14, m7 ; mx+dx*[4-7]
+    pand                 m5, m14, m10
+    psrld                m5, 6
+    paddd               m15, m5
+    pcmpeqd              m5, m9
+    mova        [rsp+0x110], m14
+    psrldq               m4, m15, 8
+%if ARCH_X86_64
+    movd               r10d, m15
+    movd               r11d, m4
+    psrldq              m15, 4
+    psrldq               m4, 4
+    movd               r13d, m15
+    movd                rXd, m4
+    movq                 m2, [base+subpel_filters+r10*8]
+    movq                 m3, [base+subpel_filters+r11*8]
+    movhps               m2, [base+subpel_filters+r13*8]
+    movhps               m3, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    psrldq               m4, m14, 8
+    movd               r10d, m14
+    movd               r11d, m4
+    psrldq              m14, 4
+    psrldq               m4, 4
+    movd               r13d, m14
+    movd                rXd, m4
+    mov                 r4d, [rsp+ 0]
+    mov                 r6d, [rsp+ 8]
+    mov                 r7d, [rsp+ 4]
+    mov                 r9d, [rsp+12]
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd               m7, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m8, m11, m4
+    pand                 m9, m11, m6
+    pand                m15, m11, m7
+    pand                m11, m11, m5
+    pandn                m4, m0
+    pandn                m6, m1
+    pandn                m7, m2
+    pandn                m5, m3
+    por                  m8, m4
+    por                  m9, m6
+    por                 m15, m7
+    por                 m11, m5
+    mova         [rsp+0x10], m8
+    mova         [rsp+0x20], m9
+    mova         [rsp+0x30], m15
+    mova         [rsp+0x40], m11
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 7, 10, 8, 9, 15, 11 ; 0-1
+    mova         [rsp+0x50], m1
+    mova         [rsp+0x60], m2
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 1, 2, 7, 10, 8, 9, 15, 11 ; 2-3
+    mova         [rsp+0x70], m3
+    mova         [rsp+0x80], m4
+    MC_8TAP_SCALED_H 5, 6, 1, 2, 3, 4, 7, 10, 8, 9, 15, 11 ; 4-5
+    MC_8TAP_SCALED_H 0,14, 1, 2, 3, 4, 7, 10, 8, 9, 15, 11 ; 6-7
+    SWAP                 m7, m0
+    SWAP                 m8, m14
+    mova                 m1, [rsp+0x50]
+    mova                 m2, [rsp+0x60]
+    mova                 m3, [rsp+0x70]
+    mova                m15, [rsp+0x80]
+    punpcklwd            m4, m5, m6 ; 45a
+    punpckhwd            m5, m6     ; 45b
+    punpcklwd            m6, m7, m8 ; 67a
+    punpckhwd            m7, m8     ; 67b
+    SWAP                m14, m8
+    mova                 m8, [rsp+0x140]
+    mova                 m9, [rsp+0x150]
+    mova                m10, [rsp+0x160]
+    mova                m11, [rsp+0x170]
+    punpcklwd            m0, m1, m2 ; 01a
+    punpckhwd            m1, m2     ; 01b
+    punpcklwd            m2, m3, m15; 23a
+    punpckhwd            m3, m15    ; 23b
+    mova         [rsp+0x50], m4
+    mova         [rsp+0x60], m5
+    mova         [rsp+0x70], m6
+    mova         [rsp+0x80], m7
+    mova                m14, [base+unpckw]
+%else
+    movd                 r0, m15
+    movd                 rX, m4
+    psrldq              m15, 4
+    psrldq               m4, 4
+    movd                 r4, m15
+    movd                 r5, m4
+    mova                m14, [esp+0x110]
+    movq                 m2, [base+subpel_filters+r0*8]
+    movq                 m3, [base+subpel_filters+rX*8]
+    movhps               m2, [base+subpel_filters+r4*8]
+    movhps               m3, [base+subpel_filters+r5*8]
+    psrld               m14, 10
+    mova           [esp+16], m14
+    mov                  r0, [esp+ 0]
+    mov                  rX, [esp+ 8]
+    mov                  r4, [esp+ 4]
+    mov                  r5, [esp+12]
+    mova         [esp+0x20], m0
+    mova         [esp+0x30], m1
+    mova         [esp+0x40], m2
+    mova         [esp+0x50], m3
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd               m7, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m0, m11, m4
+    pand                 m1, m11, m6
+    pand                 m2, m11, m7
+    pand                 m3, m11, m5
+    pandn                m4, [esp+0x20]
+    pandn                m6, [esp+0x30]
+    pandn                m7, [esp+0x40]
+    pandn                m5, [esp+0x50]
+    por                  m0, m4
+    por                  m1, m6
+    por                  m2, m7
+    por                  m3, m5
+    mova        [esp+0x20], m0
+    mova        [esp+0x30], m1
+    mova        [esp+0x40], m2
+    mova        [esp+0x50], m3
+    MC_8TAP_SCALED_H   0x20, 0x60, 0 ; 0-1
+    MC_8TAP_SCALED_H   0x20, 0x180   ; 2-3
+    MC_8TAP_SCALED_H   0x20, 0x1a0   ; 4-5
+    MC_8TAP_SCALED_H   0x20, 0x1c0   ; 6-7
+    mova                 m5, [esp+0x1a0]
+    mova                 m6, [esp+0x1b0]
+    mova                 m7, [esp+0x1c0]
+    mova                 m0, [esp+0x1d0]
+    punpcklwd            m4, m5, m6      ; 45a
+    punpckhwd            m5, m6          ; 45b
+    punpcklwd            m6, m7, m0      ; 67a
+    punpckhwd            m7, m0          ; 67b
+    mova        [esp+0x1a0], m4
+    mova        [esp+0x1b0], m5
+    mova        [esp+0x1c0], m6
+    mova        [esp+0x1d0], m7
+    mova                 m1, [esp+0x060]
+    mova                 m2, [esp+0x070]
+    mova                 m3, [esp+0x180]
+    mova                 m4, [esp+0x190]
+    punpcklwd            m0, m1, m2      ; 01a
+    punpckhwd            m1, m2          ; 01b
+    punpcklwd            m2, m3, m4      ; 23a
+    punpckhwd            m3, m4          ; 23b
+    mova        [esp+0x060], m0
+    mova        [esp+0x070], m1
+    mova        [esp+0x180], m2
+    mova        [esp+0x190], m3
+ %define m8  [esp+0x140]
+ %define m9  [esp+0x150]
+ %define m10 [esp+0x160]
+ %define m11 [esp+0x170]
+%endif
+.dy1_vloop:
+%if ARCH_X86_32
+    mov                  r0, r0m
+%endif
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m8
+    pmaddwd              m6, m2, m9
+    pmaddwd              m7, m3, m9
+    paddd                m4, m13
+    paddd                m5, m13
+    paddd                m4, m6
+    paddd                m5, m7
+%if ARCH_X86_64
+    pmaddwd              m6, [rsp+0x50], m10
+    pmaddwd              m7, [rsp+0x60], m10
+%else
+    pmaddwd              m6, [rsp+0x1a0], m10
+    pmaddwd              m7, [rsp+0x1b0], m10
+%endif
+    paddd                m4, m6
+    paddd                m5, m7
+%if ARCH_X86_64
+    pmaddwd              m6, [rsp+0x70], m11
+    pmaddwd              m7, [rsp+0x80], m11
+%else
+    pmaddwd              m6, [rsp+0x1c0], m11
+    pmaddwd              m7, [rsp+0x1d0], m11
+%endif
+    paddd                m4, m6
+    paddd                m5, m7
+    psrad                m4, rndshift
+    psrad                m5, rndshift
+    packssdw             m4, m5
+%ifidn %1, put
+    packuswb             m4, m4
+    movq             [dstq], m4
+    add                dstq, dsm
+%else
+    mova             [tmpq], m4
+    add                tmpq, tmp_stridem
+%endif
+%if ARCH_X86_32
+    mov                 r0m, r0
+%endif
+    dec                  hd
+    jz .dy1_hloop_prep
+%if ARCH_X86_64
+    movq                 m4, [srcq+ r4]
+    movq                 m5, [srcq+ r6]
+    movhps               m4, [srcq+ r7]
+    movhps               m5, [srcq+ r9]
+    movq                 m6, [srcq+r10]
+    movq                 m7, [srcq+r11]
+    movhps               m6, [srcq+r13]
+    movhps               m7, [srcq+ rX]
+    add                srcq, ssq
+    pshufd              m15, m14, q1032
+    pshufb               m0, m14                ; 0a 1a
+    pshufb               m1, m14                ; 0b 1b
+    pshufb               m2, m15                ; 3a 2a
+    pshufb               m3, m15                ; 3b 2b
+    pmaddubsw            m4, [rsp+0x10]
+    pmaddubsw            m5, [rsp+0x20]
+    pmaddubsw            m6, [rsp+0x30]
+    pmaddubsw            m7, [rsp+0x40]
+    phaddw               m4, m5
+    phaddw               m6, m7
+    phaddw               m4, m6
+    pmulhrsw             m4, m12
+    pshufb               m5, [rsp+0x70], m15    ; 7a 6a
+    pshufb               m7, [rsp+0x80], m15    ; 7b 6b
+    pshufb               m6, [rsp+0x50], m14    ; 4a 5a
+    pshufb              m15, [rsp+0x60], m14    ; 4b 5b
+    punpckhwd            m0, m2  ; 12a
+    punpckhwd            m1, m3  ; 12b
+    punpcklwd            m2, m6  ; 34a
+    punpcklwd            m3, m15 ; 34b
+    punpckhwd            m6, m5  ; 56a
+    punpckhwd           m15, m7  ; 56b
+    punpcklwd            m5, m4  ; 78a
+    psrldq               m4, 8
+    punpcklwd            m7, m4  ; 78b
+    mova         [rsp+0x50], m6
+    mova         [rsp+0x60], m15
+    mova         [rsp+0x70], m5
+    mova         [rsp+0x80], m7
+%else
+    mov                  r0, [esp+ 0]
+    mov                  rX, [esp+ 8]
+    mov                  r4, [esp+ 4]
+    mov                  r5, [esp+12]
+    mova                 m6, [base+unpckw]
+    mova                 m0, [esp+0x060]
+    mova                 m1, [esp+0x070]
+    mova                 m7, [esp+0x1a0]
+    movq                 m4, [srcq+r0]
+    movq                 m5, [srcq+rX]
+    movhps               m4, [srcq+r4]
+    movhps               m5, [srcq+r5]
+    pshufb               m0, m6         ; 0a 1a
+    pshufb               m1, m6         ; 0b 1b
+    pshufb               m7, m6         ; 4a 5a
+    mov                  r0, [esp+16]
+    mov                  rX, [esp+24]
+    mov                  r4, [esp+20]
+    mov                  r5, [esp+28]
+    movq                 m3, [srcq+r0]
+    movq                 m2, [srcq+rX]
+    movhps               m3, [srcq+r4]
+    movhps               m2, [srcq+r5]
+    add                srcq, ssq
+    pmaddubsw            m4, [esp+0x20]
+    pmaddubsw            m5, [esp+0x30]
+    pmaddubsw            m3, [esp+0x40]
+    pmaddubsw            m2, [esp+0x50]
+    phaddw               m4, m5
+    phaddw               m3, m2
+    mova                 m5, [esp+0x1b0]
+    mova                 m2, [esp+0x180]
+    phaddw               m4, m3
+    mova                 m3, [esp+0x190]
+    pmulhrsw             m4, m12        ; 8a 8b
+    pshufb               m5, m6         ; 4b 5b
+    pshufd               m6, m6, q1032
+    pshufb               m2, m6         ; 3a 2a
+    pshufb               m3, m6         ; 3b 2b
+    punpckhwd            m0, m2         ; 12a
+    punpckhwd            m1, m3         ; 12b
+    mova         [esp+0x60], m0
+    mova         [esp+0x70], m1
+    mova                 m0, [esp+0x1c0]
+    mova                 m1, [esp+0x1d0]
+    punpcklwd            m2, m7         ; 34a
+    punpcklwd            m3, m5         ; 34b
+    mova        [esp+0x180], m2
+    mova        [esp+0x190], m3
+    pshufb               m0, m6         ; 7a 6a
+    pshufb               m1, m6         ; 7b 6b
+    punpckhwd            m7, m0         ; 56a
+    punpckhwd            m5, m1         ; 56b
+    punpcklwd            m0, m4
+    punpckhqdq           m4, m4
+    punpcklwd            m1, m4
+    mova        [esp+0x1a0], m7
+    mova        [esp+0x1b0], m5
+    mova        [esp+0x1c0], m0
+    mova        [esp+0x1d0], m1
+    mova                 m0, [esp+0x60]
+    mova                 m1, [esp+0x70]
+%endif
+    jmp .dy1_vloop
+INIT_XMM ssse3
+.dy2:
+    movzx                wd, word [base+%1_8tap_scaled_ssse3_dy2_table+wq*2]
+    add                  wq, base_reg
+    jmp                  wq
+%ifidn %1, put
+.dy2_w2:
+ %if ARCH_X86_64
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd                m15, t0d
+ %else
+  %define m10 [base+pd_0x3ff]
+  %define m11 [base+pd_0x4000]
+  %define m8  m0
+  %define m9  m1
+  %define m14 m4
+  %define m15 m3
+    movzx                r5, byte [esp+0x1f0]
+    dec                srcd
+    movd                m15, r5
+ %endif
+    punpckldq            m9, m8
+    SWAP                 m8, m9
+    paddd               m14, m8 ; mx+dx*[0-1]
+ %if ARCH_X86_64
+    mova                m11, [base+pd_0x4000]
+ %endif
+    pshufd              m15, m15, q0000
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd               m15, m8
+    movd                r4d, m15
+    psrldq              m15, 4
+ %if ARCH_X86_64
+    movd                r6d, m15
+ %else
+    movd                r3d, m15
+ %endif
+    mova                 m5, [base+bdct_lb_dw]
+    mova                 m6, [base+subpel_s_shuf2]
+    movd                m15, [base+subpel_filters+r4*8+2]
+ %if ARCH_X86_64
+    movd                 m7, [base+subpel_filters+r6*8+2]
+ %else
+    movd                 m7, [base+subpel_filters+r3*8+2]
+ %endif
+    pxor                 m9, m9
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+ %if ARCH_X86_32
+    mov                  r3, r3m
+    pshufb              m14, m5
+    paddb               m14, m6
+    mova         [esp+0x00], m14
+  %define m14 [esp+0x00]
+    SWAP                 m5, m0
+    SWAP                 m6, m3
+  %define m8  m5
+  %define m15 m6
+ %endif
+    movq                 m0, [srcq+ssq*0]
+    movq                 m1, [srcq+ssq*1]
+    movhps               m0, [srcq+ssq*2]
+    movhps               m1, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+ %if ARCH_X86_64
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    pshufb              m14, m5
+    paddb               m14, m6
+    movq                m10, r4q
+ %else
+    mov                 myd, mym
+    mov                  r3, [esp+0x1f4]
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  r3, [r3+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r3*8+0]
+    cmovnz               r5, [base+subpel_filters+r3*8+4]
+    mov                  r3, r3m
+  %define m10 m4
+    movd                m10, r4
+    movd                 m3, r5
+    punpckldq           m10, m3
+ %endif
+    movq                 m3, [srcq+ssq*0]
+    movhps               m3, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    punpcklbw           m10, m10
+    psraw               m10, 8
+    punpckldq           m15, m7
+    punpcklqdq          m15, m15
+ %if ARCH_X86_64
+    pand                m11, m8
+ %else
+    pand                 m7, m11, m8
+  %define m11 m7
+ %endif
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m11
+ %if ARCH_X86_64
+    pshufd               m8, m10, q0000
+    pshufd               m9, m10, q1111
+    pshufd              m11, m10, q3333
+    pshufd              m10, m10, q2222
+ %else
+    mova         [esp+0x10], m15
+  %define m15 [esp+0x10]
+    mov                  r5, r0m
+  %define dstq r5
+    mov                 dsd, dsm
+    pshufd               m5, m4, q0000
+    pshufd               m6, m4, q1111
+    pshufd               m7, m4, q2222
+    pshufd               m4, m4, q3333
+  %define m8  [esp+0x20]
+  %define m9  [esp+0x30]
+  %define m10 [esp+0x40]
+  %define m11 [esp+0x50]
+    mova                 m8, m5
+    mova                 m9, m6
+    mova                m10, m7
+    mova                m11, m4
+ %endif
+    pshufb               m0, m14
+    pshufb               m1, m14
+    pshufb               m3, m14
+    pmaddubsw            m0, m15
+    pmaddubsw            m1, m15
+    pmaddubsw            m3, m15
+    pslldq               m2, m3, 8
+    phaddw               m0, m2
+    phaddw               m1, m3
+    pmulhrsw             m0, m12            ; 0 2 _ 4
+    pmulhrsw             m1, m12            ; 1 3 _ 5
+    pshufd               m2, m0, q3110      ; 0 2 2 4
+    pshufd               m1, m1, q3110      ; 1 3 3 5
+    punpcklwd            m3, m2, m1         ; 01 23
+    punpckhwd            m2, m1             ; 23 45
+.dy2_w2_loop:
+    movq                 m6, [srcq+ssq*0]
+    movq                 m7, [srcq+ssq*1]
+    movhps               m6, [srcq+ssq*2]
+    movhps               m7, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pmaddwd              m4, m3, m8
+    pmaddwd              m5, m2, m9
+    pshufb               m6, m14
+    pshufb               m7, m14
+    pmaddubsw            m6, m15
+    pmaddubsw            m7, m15
+    phaddw               m6, m7
+    pmulhrsw             m6, m12
+    psrldq               m7, m6, 8
+    palignr              m6, m0, 8
+    palignr              m7, m1, 8
+    mova                 m0, m6
+    mova                 m1, m7
+    pshufd               m6, m6, q3221
+    pshufd               m7, m7, q3221
+    punpcklwd            m3, m6, m7       ; 45 67
+    punpckhwd            m2, m6, m7       ; 67 89
+    pmaddwd              m6, m3, m10
+    pmaddwd              m7, m2, m11
+    paddd                m4, m5
+    paddd                m4, m13
+    paddd                m6, m7
+    paddd                m4, m6
+    psrad                m4, rndshift
+    packssdw             m4, m4
+    packuswb             m4, m4
+    movd                r4d, m4
+    mov        [dstq+dsq*0], r4w
+    shr                 r4d, 16
+    mov        [dstq+dsq*1], r4w
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .dy2_w2_loop
+    RET
+%endif
+INIT_XMM ssse3
+.dy2_w4:
+%if ARCH_X86_64
+    mov                 myd, mym
+    movzx               t0d, t0b
+    dec                srcq
+    movd                m15, t0d
+%else
+ %define m10 [base+pd_0x3ff]
+ %define m11 [base+pd_0x4000]
+ %define m8  m0
+ %xdefine m14 m4
+ %define m15 m3
+ %define dstq r0
+ %if isprep
+  %define ssq r3
+ %endif
+    movzx                r4, byte [esp+0x1f0]
+    dec                srcq
+    movd                m15, r4
+%endif
+    pmaddwd              m8, [base+rescale_mul]
+%if ARCH_X86_64
+    mova                m11, [base+pd_0x4000]
+%endif
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+    pand                 m8, m14, m10
+    psrld                m8, 6
+    paddd               m15, m8
+    psrldq               m7, m15, 8
+%if ARCH_X86_64
+    movd                r4d, m15
+    movd               r11d, m7
+    psrldq              m15, 4
+    psrldq               m7, 4
+    movd                r6d, m15
+    movd               r13d, m7
+    movd                m15, [base+subpel_filters+ r4*8+2]
+    movd                 m2, [base+subpel_filters+r11*8+2]
+    movd                 m3, [base+subpel_filters+ r6*8+2]
+    movd                 m4, [base+subpel_filters+r13*8+2]
+    movq                 m6, [base+subpel_s_shuf2]
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+%else
+    movd                 r1, m15
+    movd                 r3, m7
+    psrldq              m15, 4
+    psrldq               m7, 4
+    movd                 r4, m15
+    movd                 r5, m7
+ %define m15 m5
+    SWAP                 m4, m7
+    movd                m15, [base+subpel_filters+r1*8+2]
+    movd                 m2, [base+subpel_filters+r3*8+2]
+    movd                 m3, [base+subpel_filters+r4*8+2]
+    movd                 m4, [base+subpel_filters+r5*8+2]
+    movq                 m6, [base+subpel_s_shuf2]
+    mov                 myd, mym
+    mov                  r3, [esp+0x1f4]
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  r3, [r3+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r3*8+0]
+    cmovnz               r5, [base+subpel_filters+r3*8+4]
+    mov                  r3, r3m
+ %if isprep
+    lea                ss3q, [ssq*3]
+ %endif
+%endif
+    punpckldq           m15, m3
+    punpckldq            m2, m4
+    punpcklqdq          m15, m2
+%if ARCH_X86_64
+    pcmpeqd              m8, m9
+    psrld               m14, 10
+    movu                 m0, [srcq+ssq*0]
+    movu                 m2, [srcq+ssq*2]
+    movu                 m1, [srcq+ssq*1]
+    movu                 m3, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    punpcklqdq           m6, m6
+    pshufb              m14, [base+bdct_lb_dw]
+    movu                 m4, [srcq+ssq*0]
+    movu                 m5, [srcq+ssq*1]
+    lea                srcq, [srcq+ssq*2]
+    pand                m11, m8
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m11
+    paddb               m14, m6
+    movq                m11, r4q
+    punpcklbw           m11, m11
+    psraw               m11, 8
+    pshufb               m0, m14
+    pshufb               m2, m14
+    pshufb               m1, m14
+    pshufb               m3, m14
+    pshufb               m4, m14
+    pshufb               m5, m14
+    pmaddubsw            m0, m15
+    pmaddubsw            m2, m15
+    pmaddubsw            m1, m15
+    pmaddubsw            m3, m15
+    pmaddubsw            m4, m15
+    pmaddubsw            m5, m15
+    phaddw               m0, m2
+    phaddw               m1, m3
+    phaddw               m4, m5
+    pmulhrsw             m0, m12    ; 0 2
+    pmulhrsw             m1, m12    ; 1 3
+    pmulhrsw             m4, m12    ; 4 5
+    pshufd               m8, m11, q0000
+    pshufd               m9, m11, q1111
+    pshufd              m10, m11, q2222
+    pshufd              m11, m11, q3333
+%else
+    pxor                 m3, m3
+    pcmpeqd              m8, m3
+    psrld               m14, 10
+    pshufb              m14, [base+bdct_lb_dw]
+    movu                 m1, [srcq+ssq*0]
+    movu                 m2, [srcq+ssq*2]
+    movu                 m3, [srcq+ssq*1]
+    add                srcq, ss3q
+    punpcklqdq           m6, m6
+    SWAP                 m4, m7
+    pand                 m7, m11, m8
+    pandn                m8, m15
+    SWAP                m15, m8
+    por                 m15, m7
+    paddb               m14, m6
+    movu                 m0, [srcq+ssq*0]
+    movu                 m7, [srcq+ssq*1]
+    movu                 m6, [srcq+ssq*2]
+    add                srcq, ss3q
+    pshufb               m1, m14
+    pshufb               m2, m14
+    pshufb               m3, m14
+    pshufb               m0, m14
+    pshufb               m7, m14
+    pshufb               m6, m14
+    pmaddubsw            m1, m15
+    pmaddubsw            m2, m15
+    pmaddubsw            m3, m15
+    mova         [esp+0x00], m14
+    mova         [esp+0x10], m15
+    pmaddubsw            m0, m15
+    pmaddubsw            m7, m15
+    pmaddubsw            m6, m15
+ %define m14 [esp+0x00]
+ %define m15 [esp+0x10]
+    phaddw               m1, m2
+    phaddw               m3, m0
+    phaddw               m7, m6
+ %ifidn %1, put
+    mov                 dsd, dsm
+  %define dstq r5
+ %else
+  %define tmpq r5
+ %endif
+    movd                 m6, r4
+    movd                 m0, r5
+    punpckldq            m6, m0
+    punpcklbw            m6, m6
+    psraw                m6, 8
+    mov                  r5, r0m
+    pmulhrsw             m1, m12 ; 0 2
+    pmulhrsw             m3, m12 ; 1 3
+    pmulhrsw             m7, m12 ; 4 5
+    SWAP                 m0, m1, m3
+    SWAP                 m4, m7
+    pshufd               m2, m6, q0000
+    pshufd               m3, m6, q1111
+    pshufd               m7, m6, q2222
+    pshufd               m6, m6, q3333
+    mova         [esp+0x30], m2
+    mova         [esp+0x40], m3
+    mova         [esp+0x50], m7
+    mova         [esp+0x60], m6
+ %define m8  [esp+0x30]
+ %define m9  [esp+0x40]
+ %define m10 [esp+0x50]
+ %define m11 [esp+0x60]
+%endif
+    psrldq               m5, m4, 8  ; 5 _
+    punpckhwd            m2, m0, m1 ; 23
+    punpcklwd            m0, m1     ; 01
+    punpcklwd            m4, m5     ; 45
+.dy2_w4_loop:
+    pmaddwd              m0, m8         ; a0
+    pmaddwd              m5, m2, m8     ; b0
+    pmaddwd              m2, m9         ; a1
+    pmaddwd              m7, m4, m9     ; b1
+    pmaddwd              m3, m4, m10    ; a2
+    paddd                m0, m13
+    paddd                m5, m13
+    paddd                m0, m2
+    paddd                m5, m7
+    paddd                m0, m3
+    movu                 m6, [srcq+ssq*0]
+    movu                 m7, [srcq+ssq*1]
+    movu                 m3, [srcq+ssq*2]
+    movu                 m1, [srcq+ss3q ]
+    lea                srcq, [srcq+ssq*4]
+    pshufb               m6, m14
+    pshufb               m7, m14
+    pshufb               m3, m14
+    pshufb               m1, m14
+    pmaddubsw            m6, m15
+    pmaddubsw            m7, m15
+    pmaddubsw            m3, m15
+    pmaddubsw            m1, m15
+    phaddw               m6, m7
+    phaddw               m3, m1
+    pmulhrsw             m6, m12    ; 6 7
+    pmulhrsw             m3, m12    ; 8 9
+    psrldq               m7, m6, 8
+    psrldq               m1, m3, 8
+    punpcklwd            m6, m7     ; 67
+    punpcklwd            m3, m1     ; 89
+    mova                 m2, m6
+    pmaddwd              m1, m6, m10    ; b2
+    pmaddwd              m6, m11        ; a3
+    pmaddwd              m7, m3, m11    ; b3
+    paddd                m5, m1
+    paddd                m0, m6
+    paddd                m5, m7
+    psrad                m0, rndshift
+    psrad                m5, rndshift
+    packssdw             m0, m5
+%ifidn %1, put
+    packuswb             m0, m0
+    psrldq               m1, m0, 4
+    movd       [dstq+dsq*0], m0
+    movd       [dstq+dsq*1], m1
+    lea                dstq, [dstq+dsq*2]
+%else
+    mova             [tmpq], m0
+    add                tmpq, 16
+%endif
+    mova                 m0, m4
+    mova                 m4, m3
+    sub                  hd, 2
+    jg .dy2_w4_loop
+    MC_8TAP_SCALED_RET
+INIT_XMM ssse3
+.dy2_w8:
+    mov    dword [rsp+0x90], 1
+    movifprep   tmp_stridem, 16
+    jmp .dy2_w_start
+.dy2_w16:
+    mov    dword [rsp+0x90], 2
+    movifprep   tmp_stridem, 32
+    jmp .dy2_w_start
+.dy2_w32:
+    mov    dword [rsp+0x90], 4
+    movifprep   tmp_stridem, 64
+    jmp .dy2_w_start
+.dy2_w64:
+    mov    dword [rsp+0x90], 8
+    movifprep   tmp_stridem, 128
+    jmp .dy2_w_start
+.dy2_w128:
+    mov    dword [rsp+0x90], 16
+    movifprep   tmp_stridem, 256
+.dy2_w_start:
+    mov                 myd, mym
+%ifidn %1, put
+    movifnidn           dsm, dsq
+%endif
+%if ARCH_X86_64
+    shr                 t0d, 16
+    sub                srcq, 3
+    shr                 myd, 6
+    mov                 r4d, 64 << 24
+    lea                 myd, [t1+myq]
+    cmovnz              r4q, [base+subpel_filters+myq*8]
+    movd                m15, t0d
+%else
+ %define m10 [base+pd_0x3ff]
+ %define m11 [base+pd_0x4000]
+ %define m8   m0
+ %define m9   m1
+ %xdefine m14 m4
+ %xdefine m15 m3
+ %if isprep
+  %define tmpq r0
+  %define ssq ssm
+ %else
+  %define dstq r0
+ %endif
+    mov                  r5, [esp+0x1f0]
+    mov                  r3, [esp+0x1f4]
+    shr                  r5, 16
+    sub                srcq, 3
+    movd                m15, r5
+    xor                  r5, r5
+    shr                 myd, 6
+    lea                  r3, [r3+myd]
+    mov                  r4, 64 << 24
+    cmovnz               r4, [base+subpel_filters+r3*8+0]
+    cmovnz               r5, [base+subpel_filters+r3*8+4]
+    mov                  r0, r0m
+    mov                  r3, r3m
+%endif
+    pslld                m7, m8, 2 ; dx*4
+    pmaddwd              m8, [base+rescale_mul] ; dx*[0-3]
+    pshufd              m15, m15, q0000
+    paddd               m14, m8 ; mx+dx*[0-3]
+%if ARCH_X86_64
+    movq                 m3, r4q
+    punpcklbw            m3, m3
+    psraw                m3, 8
+%else
+    movd                 m5, r4
+    movd                 m6, r5
+    punpckldq            m5, m6
+    punpcklbw            m5, m5
+    psraw                m5, 8
+    SWAP                 m3, m5
+%endif
+    mova        [rsp+0x100], m7
+    mova        [rsp+0x120], m15
+    mov         [rsp+0x098], srcq
+    mov         [rsp+0x130], r0q ; dstq / tmpq
+    pshufd               m0, m3, q0000
+    pshufd               m1, m3, q1111
+    pshufd               m2, m3, q2222
+    pshufd               m3, m3, q3333
+    mova        [rsp+0x140], m0
+    mova        [rsp+0x150], m1
+    mova        [rsp+0x160], m2
+    mova        [rsp+0x170], m3
+%if ARCH_X86_64 && UNIX64
+    mov                  hm, hd
+%elif ARCH_X86_32
+    SWAP                  m5, m3
+    mov                   r5, hm
+    mov          [esp+0x134], r5
+%endif
+    jmp .dy2_hloop
+.dy2_hloop_prep:
+    dec   dword [rsp+0x090]
+    jz .ret
+%if ARCH_X86_64
+    add   qword [rsp+0x130], 8*(isprep+1)
+    mov                  hd, hm
+%else
+    add   dword [rsp+0x130], 8*(isprep+1)
+    mov                  r5, [esp+0x134]
+    mov                  r0, [esp+0x130]
+%endif
+    mova                 m7, [rsp+0x100]
+    mova                m14, [rsp+0x110]
+%if ARCH_X86_64
+    mova                m10, [base+pd_0x3ff]
+%else
+ %define m10 [base+pd_0x3ff]
+%endif
+    mova                m15, [rsp+0x120]
+    mov                srcq, [rsp+0x098]
+%if ARCH_X86_64
+    mov                 r0q, [rsp+0x130] ; dstq / tmpq
+%else
+    mov                  hm, r5
+    mov                 r0m, r0
+    mov                  r3, r3m
+%endif
+    paddd               m14, m7
+.dy2_hloop:
+    pxor                 m9, m9
+%if ARCH_X86_64
+    mova                m11, [base+pq_0x40000000]
+%else
+ %define m11 [base+pq_0x40000000]
+%endif
+    psrld                m2, m14, 10
+    mova              [rsp], m2
+    pand                 m6, m14, m10
+    psrld                m6, 6
+    paddd                m5, m15, m6
+    pcmpeqd              m6, m9
+    psrldq               m2, m5, 8
+%if ARCH_X86_64
+    movd                r4d, m5
+    movd                r6d, m2
+    psrldq               m5, 4
+    psrldq               m2, 4
+    movd                r7d, m5
+    movd                r9d, m2
+    movq                 m0, [base+subpel_filters+r4*8]
+    movq                 m1, [base+subpel_filters+r6*8]
+    movhps               m0, [base+subpel_filters+r7*8]
+    movhps               m1, [base+subpel_filters+r9*8]
+%else
+    movd                 r0, m5
+    movd                 rX, m2
+    psrldq               m5, 4
+    psrldq               m2, 4
+    movd                 r4, m5
+    movd                 r5, m2
+    movq                 m0, [base+subpel_filters+r0*8]
+    movq                 m1, [base+subpel_filters+rX*8]
+    movhps               m0, [base+subpel_filters+r4*8]
+    movhps               m1, [base+subpel_filters+r5*8]
+    pxor                 m2, m2
+ %define m9 m2
+%endif
+    paddd               m14, m7 ; mx+dx*[4-7]
+    pand                 m5, m14, m10
+    psrld                m5, 6
+    paddd               m15, m5
+    pcmpeqd              m5, m9
+    mova        [rsp+0x110], m14
+    psrldq               m4, m15, 8
+%if ARCH_X86_64
+    movd               r10d, m15
+    movd               r11d, m4
+    psrldq              m15, 4
+    psrldq               m4, 4
+    movd               r13d, m15
+    movd                rXd, m4
+    movq                 m2, [base+subpel_filters+r10*8]
+    movq                 m3, [base+subpel_filters+r11*8]
+    movhps               m2, [base+subpel_filters+r13*8]
+    movhps               m3, [base+subpel_filters+ rX*8]
+    psrld               m14, 10
+    psrldq               m4, m14, 8
+    movd               r10d, m14
+    movd               r11d, m4
+    psrldq              m14, 4
+    psrldq               m4, 4
+    movd               r13d, m14
+    movd                rXd, m4
+    mov                 r4d, [rsp+ 0]
+    mov                 r6d, [rsp+ 8]
+    mov                 r7d, [rsp+ 4]
+    mov                 r9d, [rsp+12]
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd               m7, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m8, m11, m4
+    pand                 m9, m11, m6
+    pand                m15, m11, m7
+    pand                m11, m11, m5
+    pandn                m4, m0
+    pandn                m6, m1
+    pandn                m7, m2
+    pandn                m5, m3
+    por                  m8, m4
+    por                  m9, m6
+    por                 m15, m7
+    por                 m11, m5
+    mova         [rsp+0x10], m8
+    mova         [rsp+0x20], m9
+    mova         [rsp+0x30], m15
+    mova         [rsp+0x40], m11
+    MC_8TAP_SCALED_H 1, 2, 3, 4, 5, 6, 7, 10, 8, 9, 15, 11 ; 0-1
+    mova         [rsp+0x50], m1
+    mova         [rsp+0x60], m2
+    MC_8TAP_SCALED_H 3, 4, 5, 6, 1, 2, 7, 10, 8, 9, 15, 11 ; 2-3
+    mova         [rsp+0x70], m3
+    mova         [rsp+0x80], m4
+    MC_8TAP_SCALED_H 5, 6, 1, 2, 3, 4, 7, 10, 8, 9, 15, 11 ; 4-5
+    MC_8TAP_SCALED_H 0,14, 1, 2, 3, 4, 7, 10, 8, 9, 15, 11 ; 6-7
+    SWAP                 m7, m0
+    SWAP                 m8, m14
+    mova                 m1, [rsp+0x50]
+    mova                 m2, [rsp+0x60]
+    mova                 m3, [rsp+0x70]
+    mova                m15, [rsp+0x80]
+    punpcklwd            m4, m5, m6 ; 45a
+    punpckhwd            m5, m6     ; 45b
+    punpcklwd            m6, m7, m8 ; 67a
+    punpckhwd            m7, m8     ; 67b
+    SWAP                m14, m8
+    mova                 m8, [rsp+0x140]
+    mova                 m9, [rsp+0x150]
+    mova                m10, [rsp+0x160]
+    mova                m11, [rsp+0x170]
+    punpcklwd            m0, m1, m2 ; 01a
+    punpckhwd            m1, m2     ; 01b
+    punpcklwd            m2, m3, m15; 23a
+    punpckhwd            m3, m15    ; 23b
+    mova         [rsp+0x50], m4
+    mova         [rsp+0x60], m5
+    mova         [rsp+0x70], m6
+    mova         [rsp+0x80], m7
+%else
+    movd                 r0, m15
+    movd                 rX, m4
+    psrldq              m15, 4
+    psrldq               m4, 4
+    movd                 r4, m15
+    movd                 r5, m4
+    mova                m14, [esp+0x110]
+    movq                 m2, [base+subpel_filters+r0*8]
+    movq                 m3, [base+subpel_filters+rX*8]
+    movhps               m2, [base+subpel_filters+r4*8]
+    movhps               m3, [base+subpel_filters+r5*8]
+    psrld               m14, 10
+    mova           [esp+16], m14
+    mov                  r0, [esp+ 0]
+    mov                  rX, [esp+ 8]
+    mov                  r4, [esp+ 4]
+    mov                  r5, [esp+12]
+    mova         [esp+0x20], m0
+    mova         [esp+0x30], m1
+    mova         [esp+0x40], m2
+    mova         [esp+0x50], m3
+    pshufd               m4, m6, q1100
+    pshufd               m6, m6, q3322
+    pshufd               m7, m5, q1100
+    pshufd               m5, m5, q3322
+    pand                 m0, m11, m4
+    pand                 m1, m11, m6
+    pand                 m2, m11, m7
+    pand                 m3, m11, m5
+    pandn                m4, [esp+0x20]
+    pandn                m6, [esp+0x30]
+    pandn                m7, [esp+0x40]
+    pandn                m5, [esp+0x50]
+    por                  m0, m4
+    por                  m1, m6
+    por                  m2, m7
+    por                  m3, m5
+    mova        [esp+0x20], m0
+    mova        [esp+0x30], m1
+    mova        [esp+0x40], m2
+    mova        [esp+0x50], m3
+    MC_8TAP_SCALED_H   0x20, 0x60, 0 ; 0-1
+    MC_8TAP_SCALED_H   0x20, 0x180   ; 2-3
+    MC_8TAP_SCALED_H   0x20, 0x1a0   ; 4-5
+    MC_8TAP_SCALED_H   0x20, 0x1c0   ; 6-7
+    mova                 m5, [esp+0x1a0]
+    mova                 m6, [esp+0x1b0]
+    mova                 m7, [esp+0x1c0]
+    mova                 m0, [esp+0x1d0]
+    punpcklwd            m4, m5, m6      ; 45a
+    punpckhwd            m5, m6          ; 45b
+    punpcklwd            m6, m7, m0      ; 67a
+    punpckhwd            m7, m0          ; 67b
+    mova        [esp+0x1a0], m4
+    mova        [esp+0x1b0], m5
+    mova        [esp+0x1c0], m6
+    mova        [esp+0x1d0], m7
+    mova                 m1, [esp+0x060]
+    mova                 m2, [esp+0x070]
+    mova                 m3, [esp+0x180]
+    mova                 m4, [esp+0x190]
+    punpcklwd            m0, m1, m2      ; 01a
+    punpckhwd            m1, m2          ; 01b
+    punpcklwd            m2, m3, m4      ; 23a
+    punpckhwd            m3, m4          ; 23b
+    mova        [esp+0x180], m2
+    mova        [esp+0x190], m3
+ %define m8  [esp+0x140]
+ %define m9  [esp+0x150]
+ %define m10 [esp+0x160]
+ %define m11 [esp+0x170]
+%endif
+.dy2_vloop:
+%if ARCH_X86_32
+    mov                  r0, r0m
+%endif
+    pmaddwd              m4, m0, m8
+    pmaddwd              m5, m1, m8
+    pmaddwd              m6, m2, m9
+    pmaddwd              m7, m3, m9
+    paddd                m4, m13
+    paddd                m5, m13
+    paddd                m4, m6
+    paddd                m5, m7
+%if ARCH_X86_64
+    pmaddwd              m6, [rsp+0x50], m10
+    pmaddwd              m7, [rsp+0x60], m10
+%else
+    pmaddwd              m6, [esp+0x1a0], m10
+    pmaddwd              m7, [esp+0x1b0], m10
+%endif
+    paddd                m4, m6
+    paddd                m5, m7
+%if ARCH_X86_64
+    pmaddwd              m6, [rsp+0x70], m11
+    pmaddwd              m7, [rsp+0x80], m11
+%else
+    pmaddwd              m6, [esp+0x1c0], m11
+    pmaddwd              m7, [esp+0x1d0], m11
+%endif
+    paddd                m4, m6
+    paddd                m5, m7
+    psrad                m4, rndshift
+    psrad                m5, rndshift
+    packssdw             m4, m5
+%ifidn %1, put
+    packuswb             m4, m4
+    movq             [dstq], m4
+    add                dstq, dsm
+%else
+    mova             [tmpq], m4
+    add                tmpq, tmp_stridem
+%endif
+%if ARCH_X86_32
+    mov                 r0m, r0
+%endif
+    dec                  hd
+    jz .dy2_hloop_prep
+%if ARCH_X86_64
+    mova                 m8, [rsp+0x10]
+    mova                 m9, [rsp+0x20]
+    mova                m10, [rsp+0x30]
+    mova                m11, [rsp+0x40]
+    mova                 m0, m2             ; 01a
+    mova                 m1, m3             ; 01b
+    MC_8TAP_SCALED_H 2, 6, 3, 4, 5, 7, 14, 15, 8, 9, 10, 11
+    mova                 m3, [rsp+0x50] ; 23a
+    mova                 m4, [rsp+0x60] ; 23b
+    mova                 m5, [rsp+0x70] ; 45a
+    mova                 m7, [rsp+0x80] ; 45b
+    mova                 m8, [rsp+0x140]
+    mova                 m9, [rsp+0x150]
+    mova                m10, [rsp+0x160]
+    mova                m11, [rsp+0x170]
+    punpcklwd           m14, m2, m6     ; 67a
+    punpckhwd            m2, m6         ; 67b
+    mova         [rsp+0x50], m5
+    mova         [rsp+0x60], m7
+    mova         [rsp+0x70], m14
+    mova         [rsp+0x80], m2
+    mova                 m2, m3
+    mova                 m3, m4
+%else
+    MC_8TAP_SCALED_H   0x20, 0
+    punpcklwd            m6, m0, m4
+    punpckhwd            m7, m0, m4
+    mova                 m0, [esp+0x180] ; 01a
+    mova                 m1, [esp+0x190] ; 01b
+    mova                 m2, [rsp+0x1a0]  ; 23a
+    mova                 m3, [esp+0x1b0]  ; 23b
+    mova                 m4, [esp+0x1c0]  ; 45a
+    mova                 m5, [esp+0x1d0]  ; 45b
+    mova        [esp+0x180], m2
+    mova        [esp+0x190], m3
+    mova        [esp+0x1a0], m4
+    mova        [esp+0x1b0], m5
+    mova        [esp+0x1c0], m6          ; 67a
+    mova        [esp+0x1d0], m7          ; 67b
+%endif
+    jmp .dy2_vloop
+.ret:
+    MC_8TAP_SCALED_RET 0
+%if ARCH_X86_32 && !isprep && required_stack_alignment > STACK_ALIGNMENT
+ %define r0m [rstk+stack_offset+ 4]
+ %define r1m [rstk+stack_offset+ 8]
+ %define r2m [rstk+stack_offset+12]
+ %define r3m [rstk+stack_offset+16]
+%endif
+%undef isprep
+%endmacro
+
+%macro BILIN_SCALED_FN 1
+cglobal %1_bilin_scaled_8bpc
+    mov                 t0d, (5*15 << 16) | 5*15
+    mov                 t1d, (5*15 << 16) | 5*15
+    jmp mangle(private_prefix %+ _%1_8tap_scaled_8bpc %+ SUFFIX)
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 6, 5
+%elif ARCH_X86_64
+DECLARE_REG_TMP 6, 8
+%else
+DECLARE_REG_TMP 1, 2
+%endif
+%define PUT_8TAP_SCALED_FN FN put_8tap_scaled,
+BILIN_SCALED_FN put
+PUT_8TAP_SCALED_FN sharp,          SHARP,   SHARP,   put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN sharp_smooth,   SHARP,   SMOOTH,  put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN smooth_sharp,   SMOOTH,  SHARP,   put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN smooth,         SMOOTH,  SMOOTH,  put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN sharp_regular,  SHARP,   REGULAR, put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN regular_sharp,  REGULAR, SHARP,   put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN smooth_regular, SMOOTH,  REGULAR, put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN regular_smooth, REGULAR, SMOOTH,  put_8tap_scaled_8bpc
+PUT_8TAP_SCALED_FN regular,        REGULAR, REGULAR
+MC_8TAP_SCALED put
+
+%if WIN64
+DECLARE_REG_TMP 5, 4
+%elif ARCH_X86_64
+DECLARE_REG_TMP 6, 7
+%else
+DECLARE_REG_TMP 1, 2
+%endif
+%define PREP_8TAP_SCALED_FN FN prep_8tap_scaled,
+BILIN_SCALED_FN prep
+PREP_8TAP_SCALED_FN sharp,          SHARP,   SHARP,   prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN sharp_smooth,   SHARP,   SMOOTH,  prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN smooth_sharp,   SMOOTH,  SHARP,   prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN smooth,         SMOOTH,  SMOOTH,  prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN sharp_regular,  SHARP,   REGULAR, prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN regular_sharp,  REGULAR, SHARP,   prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN smooth_regular, SMOOTH,  REGULAR, prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN regular_smooth, REGULAR, SMOOTH,  prep_8tap_scaled_8bpc
+PREP_8TAP_SCALED_FN regular,        REGULAR, REGULAR
+MC_8TAP_SCALED prep
+
+%if ARCH_X86_32
+ %macro SAVE_ALPHA_BETA 0
+    mov              alpham, alphad
+    mov               betam, betad
+ %endmacro
+
+ %macro SAVE_DELTA_GAMMA 0
+    mov              deltam, deltad
+    mov              gammam, gammad
+ %endmacro
+
+ %macro LOAD_ALPHA_BETA_MX 0
+    mov                 mym, myd
+    mov              alphad, alpham
+    mov               betad, betam
+    mov                 mxd, mxm
+ %endmacro
+
+ %macro LOAD_DELTA_GAMMA_MY 0
+    mov                 mxm, mxd
+    mov              deltad, deltam
+    mov              gammad, gammam
+    mov                 myd, mym
+ %endmacro
+
+ %define PIC_reg r2
+ %define PIC_base_offset $$
+ %define PIC_sym(sym) (PIC_reg+(sym)-PIC_base_offset)
+%else
+ %define SAVE_ALPHA_BETA
+ %define SAVE_DELTA_GAMMA
+ %define PIC_sym(sym) sym
+%endif
+
+%if ARCH_X86_32
+ %if STACK_ALIGNMENT < required_stack_alignment
+  %assign copy_args 8*4
+ %else
+  %assign copy_args 0
+ %endif
+%endif
+
+%macro RELOC_ARGS 0
+ %if copy_args
+    mov                  r0, r0m
+    mov                  r1, r1m
+    mov                  r2, r2m
+    mov                  r3, r3m
+    mov                  r5, r5m
+    mov                dstm, r0
+    mov                 dsm, r1
+    mov                srcm, r2
+    mov                 ssm, r3
+    mov                 mxm, r5
+    mov                  r0, r6m
+    mov                 mym, r0
+ %endif
+%endmacro
+
+%macro BLENDHWDW 2 ; blend high words from dwords, src1, src2
+ %if cpuflag(sse4)
+    pblendw              %1, %2, 0xAA
+ %else
+    pand                 %2, m10
+    por                  %1, %2
+ %endif
+%endmacro
+
+%macro WARP_V 10 ; dst0, dst1, 0, 2, 4, 6, 1, 3, 5, 7
+ %if ARCH_X86_32
+  %define m8  m4
+  %define m9  m5
+  %define m14 m6
+  %define m15 m7
+  %define m11 m7
+ %endif
+ %if ARCH_X86_32
+    pxor                m11, m11
+ %endif
+    lea               tmp1d, [myq+deltaq*4]
+    lea               tmp2d, [myq+deltaq*1]
+    shr                 myd, 10
+    shr               tmp1d, 10
+    movq                 m2, [filterq+myq  *8] ; a
+    movq                 m8, [filterq+tmp1q*8] ; e
+    lea               tmp1d, [tmp2q+deltaq*4]
+    lea                 myd, [tmp2q+deltaq*1]
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    movq                 m3, [filterq+tmp2q*8] ; b
+    movq                 m0, [filterq+tmp1q*8] ; f
+    punpcklwd            m2, m3
+    punpcklwd            m8, m0
+    lea               tmp1d, [myq+deltaq*4]
+    lea               tmp2d, [myq+deltaq*1]
+    shr                 myd, 10
+    shr               tmp1d, 10
+    movq                 m0, [filterq+myq  *8] ; c
+    movq                 m9, [filterq+tmp1q*8] ; g
+    lea               tmp1d, [tmp2q+deltaq*4]
+    lea                 myd, [tmp2q+gammaq]       ; my += gamma
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    movq                 m3, [filterq+tmp2q*8] ; d
+    movq                 m1, [filterq+tmp1q*8] ; h
+    punpcklwd            m0, m3
+    punpcklwd            m9, m1
+    punpckldq            m1, m2, m0
+    punpckhdq            m2, m0
+    punpcklbw            m0, m11, m1 ; a0 a2 b0 b2 c0 c2 d0 d2 << 8
+    punpckhbw            m3, m11, m1 ; a4 a6 b4 b6 c4 c6 d4 d6 << 8
+    punpcklbw            m1, m11, m2 ; a1 a3 b1 b3 c1 c3 d1 d3 << 8
+    punpckhbw           m14, m11, m2 ; a5 a7 b5 b7 c5 c7 d5 d7 << 8
+    pmaddwd              m0, %3
+    pmaddwd              m3, %5
+    pmaddwd              m1, %7
+    pmaddwd             m14, %9
+    paddd                m0, m3
+    paddd                m1, m14
+    paddd                m0, m1
+    mova                 %1, m0
+ %if ARCH_X86_64
+    SWAP                 m3, m14
+ %endif
+    punpckldq            m0, m8, m9
+    punpckhdq            m8, m9
+    punpcklbw            m1, m11, m0 ; e0 e2 f0 f2 g0 g2 h0 h2 << 8
+    punpckhbw           m14, m11, m0 ; e4 e6 f4 f6 g4 g6 h4 h6 << 8
+    punpcklbw            m2, m11, m8 ; e1 e3 f1 f3 g1 g3 h1 h3 << 8
+    punpckhbw           m15, m11, m8 ; e5 e7 f5 f7 g5 g7 h5 h7 << 8
+    pmaddwd              m1, %4
+    pmaddwd             m14, %6
+    pmaddwd              m2, %8
+    pmaddwd             m15, %10
+    paddd                m1, m14
+    paddd                m2, m15
+    paddd                m1, m2
+    mova                 %2, m1
+ %if ARCH_X86_64
+    SWAP                m14, m3
+ %endif
+%endmacro
+
+%if ARCH_X86_64
+ %define counterd r4d
+%else
+ %if copy_args == 0
+  %define counterd dword r4m
+ %else
+  %define counterd dword [esp+stack_size-4*7]
+ %endif
+%endif
+
+%macro WARP_AFFINE_8X8 0
+%if ARCH_X86_64
+cglobal warp_affine_8x8t_8bpc, 6, 14, 16, 0x90, tmp, ts
+%else
+cglobal warp_affine_8x8t_8bpc, 0, 7, 16, -0x130-copy_args, tmp, ts
+ %if copy_args
+  %define tmpm [esp+stack_size-4*1]
+  %define tsm  [esp+stack_size-4*2]
+ %endif
+%endif
+    call mangle(private_prefix %+ _warp_affine_8x8_8bpc_%+cpuname).main
+.loop:
+%if ARCH_X86_32
+ %define m12 m4
+ %define m13 m5
+ %define m14 m6
+ %define m15 m7
+    mova                m12, [esp+0xC0]
+    mova                m13, [esp+0xD0]
+    mova                m14, [esp+0xE0]
+    mova                m15, [esp+0xF0]
+%endif
+    psrad               m12, 13
+    psrad               m13, 13
+    psrad               m14, 13
+    psrad               m15, 13
+    packssdw            m12, m13
+    packssdw            m14, m15
+    mova                m13, [PIC_sym(pw_8192)]
+    pmulhrsw            m12, m13 ; (x + (1 << 6)) >> 7
+    pmulhrsw            m14, m13
+    mova       [tmpq+tsq*0], m12
+    mova       [tmpq+tsq*2], m14
+    dec            counterd
+    jz   mangle(private_prefix %+ _warp_affine_8x8_8bpc_%+cpuname).end
+%if ARCH_X86_32
+    mov                tmpm, tmpd
+    mov                  r0, [esp+0x100]
+    mov                  r1, [esp+0x104]
+%endif
+    call mangle(private_prefix %+ _warp_affine_8x8_8bpc_%+cpuname).main2
+    lea                tmpq, [tmpq+tsq*4]
+    jmp .loop
+
+%if ARCH_X86_64
+cglobal warp_affine_8x8_8bpc, 6, 14, 16, 0x90, \
+                              dst, ds, src, ss, abcd, mx, tmp2, alpha, beta, \
+                              filter, tmp1, delta, my, gamma
+%else
+cglobal warp_affine_8x8_8bpc, 0, 7, 16, -0x130-copy_args, \
+                              dst, ds, src, ss, abcd, mx, tmp2, alpha, beta, \
+                              filter, tmp1, delta, my, gamma
+ %define alphaq     r0
+ %define alphad     r0
+ %define alpham     [esp+gprsize+0x100]
+ %define betaq      r1
+ %define betad      r1
+ %define betam      [esp+gprsize+0x104]
+ %define deltaq     r0
+ %define deltad     r0
+ %define deltam     [esp+gprsize+0x108]
+ %define gammaq     r1
+ %define gammad     r1
+ %define gammam     [esp+gprsize+0x10C]
+ %define filterq    r3
+ %define tmp1q      r4
+ %define tmp1d      r4
+ %define tmp1m      [esp+gprsize+0x110]
+ %define myq        r5
+ %define myd        r5
+ %define mym        r6m
+ %if copy_args
+  %define dstm [esp+stack_size-4*1]
+  %define dsm  [esp+stack_size-4*2]
+  %define srcm [esp+stack_size-4*3]
+  %define ssm  [esp+stack_size-4*4]
+  %define mxm  [esp+stack_size-4*5]
+  %define mym  [esp+stack_size-4*6]
+ %endif
+%endif
+    call .main
+    jmp .start
+.loop:
+%if ARCH_X86_32
+    mov                dstm, dstd
+    mov              alphad, [esp+0x100]
+    mov               betad, [esp+0x104]
+%endif
+    call .main2
+    lea                dstq, [dstq+dsq*2]
+.start:
+%if notcpuflag(sse4)
+  %define roundval pw_8192
+ %if ARCH_X86_64
+    mova                m10, [PIC_sym(roundval)]
+ %else
+  %define m10 [PIC_sym(roundval)]
+ %endif
+%endif
+%if ARCH_X86_32
+ %define m12 m5
+ %define m13 m6
+    mova                m12, [esp+0xC0]
+    mova                m13, [esp+0xD0]
+%endif
+%if cpuflag(sse4)
+ %if ARCH_X86_32
+  %define m11 m4
+    pxor                m11, m11
+ %endif
+    psrad               m12, 18
+    psrad               m13, 18
+    packusdw            m12, m13
+    pavgw               m12, m11 ; (x + (1 << 10)) >> 11
+%else
+    psrad               m12, 17
+    psrad               m13, 17
+    packssdw            m12, m13
+    pmulhrsw            m12, m10
+%endif
+%if ARCH_X86_32
+ %define m14 m6
+ %define m15 m7
+    mova                m14, [esp+0xE0]
+    mova                m15, [esp+0xF0]
+%endif
+%if cpuflag(sse4)
+    psrad               m14, 18
+    psrad               m15, 18
+    packusdw            m14, m15
+    pavgw               m14, m11 ; (x + (1 << 10)) >> 11
+%else
+    psrad               m14, 17
+    psrad               m15, 17
+    packssdw            m14, m15
+    pmulhrsw            m14, m10
+%endif
+    packuswb            m12, m14
+    movq       [dstq+dsq*0], m12
+    movhps     [dstq+dsq*1], m12
+    dec            counterd
+    jg .loop
+.end:
+    RET
+ALIGN function_align
+.main:
+%assign stack_offset stack_offset+gprsize
+%if ARCH_X86_32
+ %assign stack_size stack_size+4
+ %if copy_args
+  %assign stack_offset stack_offset-4
+ %endif
+    RELOC_ARGS
+    LEA             PIC_reg, $$
+ %define PIC_mem [esp+gprsize+0x114]
+    mov               abcdd, abcdm
+ %if copy_args == 0
+    mov                 ssd, ssm
+    mov                 mxd, mxm
+ %endif
+    mov             PIC_mem, PIC_reg
+    mov                srcd, srcm
+%endif
+    movsx            deltad, word [abcdq+2*2]
+    movsx            gammad, word [abcdq+2*3]
+    lea               tmp1d, [deltaq*3]
+    sub              gammad, tmp1d    ; gamma -= delta*3
+    SAVE_DELTA_GAMMA
+%if ARCH_X86_32
+    mov               abcdd, abcdm
+%endif
+    movsx            alphad, word [abcdq+2*0]
+    movsx             betad, word [abcdq+2*1]
+    lea               tmp1q, [ssq*3+3]
+    add                 mxd, 512+(64<<10)
+    lea               tmp2d, [alphaq*3]
+    sub                srcq, tmp1q    ; src -= src_stride*3 + 3
+%if ARCH_X86_32
+    mov                srcm, srcd
+    mov             PIC_reg, PIC_mem
+%endif
+    sub               betad, tmp2d    ; beta -= alpha*3
+    lea             filterq, [PIC_sym(mc_warp_filter2)]
+%if ARCH_X86_64
+    mov                 myd, r6m
+    pxor                m11, m11
+%endif
+    call .h
+    psrld                m2, m0, 16
+    psrld                m3, m1, 16
+%if ARCH_X86_32
+    mova [esp+gprsize+0x10], m3
+%endif
+    call .h
+    psrld                m4, m0, 16
+    psrld                m5, m1, 16
+%if ARCH_X86_32
+    mova [esp+gprsize+0x20], m4
+    mova [esp+gprsize+0x30], m5
+%endif
+    call .h
+%if ARCH_X86_64
+ %define blendmask [rsp+gprsize+0x80]
+%else
+    mova                 m3, [esp+gprsize+0x10]
+ %define blendmask [esp+gprsize+0x120]
+ %define m10 m7
+%endif
+    pcmpeqd             m10, m10
+    pslld               m10, 16
+    mova          blendmask, m10
+    BLENDHWDW            m2, m0 ; 0
+    BLENDHWDW            m3, m1 ; 2
+    mova [rsp+gprsize+0x00], m2
+    mova [rsp+gprsize+0x10], m3
+    call .h
+%if ARCH_X86_32
+    mova                 m4, [esp+gprsize+0x20]
+    mova                 m5, [esp+gprsize+0x30]
+%endif
+    mova                m10, blendmask
+    BLENDHWDW            m4, m0 ; 1
+    BLENDHWDW            m5, m1 ; 3
+    mova [rsp+gprsize+0x20], m4
+    mova [rsp+gprsize+0x30], m5
+    call .h
+%if ARCH_X86_32
+    mova                 m3, [esp+gprsize+0x10]
+ %define m10 m5
+%endif
+    psrld                m6, m2, 16
+    psrld                m7, m3, 16
+    mova                m10, blendmask
+    BLENDHWDW            m6, m0 ; 2
+    BLENDHWDW            m7, m1 ; 4
+    mova [rsp+gprsize+0x40], m6
+    mova [rsp+gprsize+0x50], m7
+    call .h
+%if ARCH_X86_32
+    mova                m4, [esp+gprsize+0x20]
+    mova                m5, [esp+gprsize+0x30]
+%endif
+    psrld               m2, m4, 16
+    psrld               m3, m5, 16
+    mova                m10, blendmask
+    BLENDHWDW           m2, m0 ; 3
+    BLENDHWDW           m3, m1 ; 5
+    mova [rsp+gprsize+0x60], m2
+    mova [rsp+gprsize+0x70], m3
+    call .h
+%if ARCH_X86_32
+    mova                 m6, [esp+gprsize+0x40]
+    mova                 m7, [esp+gprsize+0x50]
+ %define m10 m7
+%endif
+    psrld                m4, m6, 16
+    psrld                m5, m7, 16
+    mova                m10, blendmask
+    BLENDHWDW            m4, m0 ; 4
+    BLENDHWDW            m5, m1 ; 6
+%if ARCH_X86_64
+    add                 myd, 512+(64<<10)
+    mova                 m6, m2
+    mova                 m7, m3
+%else
+    mova [esp+gprsize+0x80], m4
+    mova [esp+gprsize+0x90], m5
+    add           dword mym, 512+(64<<10)
+%endif
+    mov            counterd, 4
+    SAVE_ALPHA_BETA
+.main2:
+    call .h
+%if ARCH_X86_32
+    mova                 m6, [esp+gprsize+0x60]
+    mova                 m7, [esp+gprsize+0x70]
+ %define m10 m5
+%endif
+    psrld                m6, 16
+    psrld                m7, 16
+    mova                m10, blendmask
+    BLENDHWDW            m6, m0 ; 5
+    BLENDHWDW            m7, m1 ; 7
+%if ARCH_X86_64
+    WARP_V              m12, m13, [rsp+gprsize+0x00], [rsp+gprsize+0x10], \
+                                  m4, m5, \
+                                  [rsp+gprsize+0x20], [rsp+gprsize+0x30], \
+                                  m6, m7
+%else
+    mova [esp+gprsize+0xA0], m6
+    mova [esp+gprsize+0xB0], m7
+    LOAD_DELTA_GAMMA_MY
+    WARP_V [esp+gprsize+0xC0], [esp+gprsize+0xD0], \
+           [esp+gprsize+0x00], [esp+gprsize+0x10], \
+           [esp+gprsize+0x80], [esp+gprsize+0x90], \
+           [esp+gprsize+0x20], [esp+gprsize+0x30], \
+           [esp+gprsize+0xA0], [esp+gprsize+0xB0]
+    LOAD_ALPHA_BETA_MX
+%endif
+    call .h
+    mova                 m2, [rsp+gprsize+0x40]
+    mova                 m3, [rsp+gprsize+0x50]
+%if ARCH_X86_32
+    mova                 m4, [rsp+gprsize+0x80]
+    mova                 m5, [rsp+gprsize+0x90]
+ %define m10 m7
+%endif
+    mova [rsp+gprsize+0x00], m2
+    mova [rsp+gprsize+0x10], m3
+    mova [rsp+gprsize+0x40], m4
+    mova [rsp+gprsize+0x50], m5
+    psrld                m4, 16
+    psrld                m5, 16
+    mova                m10, blendmask
+    BLENDHWDW            m4, m0 ; 6
+    BLENDHWDW            m5, m1 ; 8
+%if ARCH_X86_64
+    WARP_V              m14, m15, [rsp+gprsize+0x20], [rsp+gprsize+0x30], \
+                                  m6, m7, \
+                                  [rsp+gprsize+0x00], [rsp+gprsize+0x10], \
+                                  m4, m5
+%else
+    mova [esp+gprsize+0x80], m4
+    mova [esp+gprsize+0x90], m5
+    LOAD_DELTA_GAMMA_MY
+    WARP_V [esp+gprsize+0xE0], [esp+gprsize+0xF0], \
+           [esp+gprsize+0x20], [esp+gprsize+0x30], \
+           [esp+gprsize+0xA0], [esp+gprsize+0xB0], \
+           [esp+gprsize+0x00], [esp+gprsize+0x10], \
+           [esp+gprsize+0x80], [esp+gprsize+0x90]
+    mov                 mym, myd
+    mov                dstd, dstm
+    mov                 dsd, dsm
+    mov                 mxd, mxm
+%endif
+    mova                 m2, [rsp+gprsize+0x60]
+    mova                 m3, [rsp+gprsize+0x70]
+%if ARCH_X86_32
+    mova                 m6, [esp+gprsize+0xA0]
+    mova                 m7, [esp+gprsize+0xB0]
+%endif
+    mova [rsp+gprsize+0x20], m2
+    mova [rsp+gprsize+0x30], m3
+    mova [rsp+gprsize+0x60], m6
+    mova [rsp+gprsize+0x70], m7
+    ret
+ALIGN function_align
+.h:
+%if ARCH_X86_32
+ %define m8  m3
+ %define m9  m4
+ %define m10 m5
+ %define m14 m6
+ %define m15 m7
+%endif
+    lea               tmp1d, [mxq+alphaq*4]
+    lea               tmp2d, [mxq+alphaq*1]
+%if ARCH_X86_32
+ %assign stack_offset stack_offset+4
+ %assign stack_size stack_size+4
+ %define PIC_mem [esp+gprsize*2+0x114]
+    mov             PIC_mem, PIC_reg
+    mov                srcd, srcm
+%endif
+    movu                m10, [srcq]
+%if ARCH_X86_32
+    add                srcd, ssm
+    mov                srcm, srcd
+    mov             PIC_reg, PIC_mem
+%else
+    add                srcq, ssq
+%endif
+    shr                 mxd, 10
+    shr               tmp1d, 10
+    movq                 m1, [filterq+mxq  *8]  ; 0 X
+    movq                 m8, [filterq+tmp1q*8]  ; 4 X
+    lea               tmp1d, [tmp2q+alphaq*4]
+    lea                 mxd, [tmp2q+alphaq*1]
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    movhps               m1, [filterq+tmp2q*8]  ; 0 1
+    movhps               m8, [filterq+tmp1q*8]  ; 4 5
+    lea               tmp1d, [mxq+alphaq*4]
+    lea               tmp2d, [mxq+alphaq*1]
+    shr                 mxd, 10
+    shr               tmp1d, 10
+    movq                m14, [filterq+mxq  *8]  ; 2 X
+    movq                 m9, [filterq+tmp1q*8]  ; 6 X
+    lea               tmp1d, [tmp2q+alphaq*4]
+    lea                 mxd, [tmp2q+betaq]  ; mx += beta
+    shr               tmp2d, 10
+    shr               tmp1d, 10
+    movhps              m14, [filterq+tmp2q*8]  ; 2 3
+    movhps               m9, [filterq+tmp1q*8]  ; 6 7
+    pshufb               m0, m10, [PIC_sym(warp_8x8_shufA)]
+    pmaddubsw            m0, m1
+    pshufb               m1, m10, [PIC_sym(warp_8x8_shufB)]
+    pmaddubsw            m1, m8
+    pshufb              m15, m10, [PIC_sym(warp_8x8_shufC)]
+    pmaddubsw           m15, m14
+    pshufb              m10, m10, [PIC_sym(warp_8x8_shufD)]
+    pmaddubsw           m10, m9
+    phaddw               m0, m15
+    phaddw               m1, m10
+    mova                m14, [PIC_sym(pw_8192)]
+    mova                 m9, [PIC_sym(pd_32768)]
+    pmaddwd              m0, m14 ; 17-bit intermediate, upshifted by 13
+    pmaddwd              m1, m14
+    paddd                m0, m9  ; rounded 14-bit result in upper 16 bits of dword
+    paddd                m1, m9
+    ret
+%endmacro
+
+%if WIN64
+DECLARE_REG_TMP 6, 4
+%else
+DECLARE_REG_TMP 6, 7
+%endif
+
+%macro BIDIR_FN 1 ; op
+    %1                    0
+    lea            stride3q, [strideq*3]
+    jmp                  wq
+.w4_loop:
+    %1_INC_PTR            2
+    %1                    0
+    lea                dstq, [dstq+strideq*4]
+.w4: ; tile 4x
+    movd   [dstq          ], m0      ; copy dw[0]
+    pshuflw              m1, m0, q1032 ; swap dw[1] and dw[0]
+    movd   [dstq+strideq*1], m1      ; copy dw[1]
+    punpckhqdq           m0, m0      ; swap dw[3,2] with dw[1,0]
+    movd   [dstq+strideq*2], m0      ; dw[2]
+    psrlq                m0, 32      ; shift right in dw[3]
+    movd   [dstq+stride3q ], m0      ; copy
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+.w8_loop:
+    %1_INC_PTR            2
+    %1                    0
+    lea                dstq, [dstq+strideq*2]
+.w8:
+    movq   [dstq          ], m0
+    movhps [dstq+strideq*1], m0
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16_loop:
+    %1_INC_PTR            2
+    %1                    0
+    lea                dstq, [dstq+strideq]
+.w16:
+    mova   [dstq          ], m0
+    dec                  hd
+    jg .w16_loop
+    RET
+.w32_loop:
+    %1_INC_PTR            4
+    %1                    0
+    lea                dstq, [dstq+strideq]
+.w32:
+    mova   [dstq          ], m0
+    %1                    2
+    mova   [dstq + 16     ], m0
+    dec                  hd
+    jg .w32_loop
+    RET
+.w64_loop:
+    %1_INC_PTR            8
+    %1                    0
+    add                dstq, strideq
+.w64:
+    %assign i 0
+    %rep 4
+    mova   [dstq + i*16   ], m0
+    %assign i i+1
+    %if i < 4
+    %1                    2*i
+    %endif
+    %endrep
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    %1_INC_PTR            16
+    %1                    0
+    add                dstq, strideq
+.w128:
+    %assign i 0
+    %rep 8
+    mova   [dstq + i*16   ], m0
+    %assign i i+1
+    %if i < 8
+    %1                    2*i
+    %endif
+    %endrep
+    dec                  hd
+    jg .w128_loop
+    RET
+%endmacro
+
+%macro AVG 1 ; src_offset
+    ; writes AVG of tmp1 tmp2 uint16 coeffs into uint8 pixel
+    mova                 m0, [tmp1q+(%1+0)*mmsize] ; load 8 coef(2bytes) from tmp1
+    paddw                m0, [tmp2q+(%1+0)*mmsize] ; load/add 8 coef(2bytes) tmp2
+    mova                 m1, [tmp1q+(%1+1)*mmsize]
+    paddw                m1, [tmp2q+(%1+1)*mmsize]
+    pmulhrsw             m0, m2
+    pmulhrsw             m1, m2
+    packuswb             m0, m1 ; pack/trunc 16 bits from m0 & m1 to 8 bit
+%endmacro
+
+%macro AVG_INC_PTR 1
+    add               tmp1q, %1*mmsize
+    add               tmp2q, %1*mmsize
+%endmacro
+
+cglobal avg_8bpc, 4, 7, 3, dst, stride, tmp1, tmp2, w, h, stride3
+    LEA                  r6, avg_ssse3_table
+    tzcnt                wd, wm ; leading zeros
+    movifnidn            hd, hm ; move h(stack) to h(register) if not already that register
+    movsxd               wq, dword [r6+wq*4] ; push table entry matching the tile width (tzcnt) in widen reg
+    mova                 m2, [pw_1024+r6-avg_ssse3_table] ; fill m2 with shift/align
+    add                  wq, r6
+    BIDIR_FN            AVG
+
+%macro W_AVG 1 ; src_offset
+    ; (a * weight + b * (16 - weight) + 128) >> 8
+    ; = ((a - b) * weight + (b << 4) + 128) >> 8
+    ; = ((((a - b) * ((weight-16) << 12)) >> 16) + a + 8) >> 4
+    ; = ((((b - a) * (-weight     << 12)) >> 16) + b + 8) >> 4
+    mova                 m2, [tmp1q+(%1+0)*mmsize]
+    mova                 m0, m2
+    psubw                m2, [tmp2q+(%1+0)*mmsize]
+    mova                 m3, [tmp1q+(%1+1)*mmsize]
+    mova                 m1, m3
+    psubw                m3, [tmp2q+(%1+1)*mmsize]
+    pmulhw               m2, m4
+    pmulhw               m3, m4
+    paddw                m0, m2
+    paddw                m1, m3
+    pmulhrsw             m0, m5
+    pmulhrsw             m1, m5
+    packuswb             m0, m1
+%endmacro
+
+%define W_AVG_INC_PTR AVG_INC_PTR
+
+cglobal w_avg_8bpc, 4, 7, 6, dst, stride, tmp1, tmp2, w, h, stride3
+    LEA                  r6, w_avg_ssse3_table
+    tzcnt                wd, wm
+    movd                 m4, r6m
+    movifnidn            hd, hm
+    pxor                 m0, m0
+    movsxd               wq, dword [r6+wq*4]
+    mova                 m5, [pw_2048+r6-w_avg_ssse3_table]
+    pshufb               m4, m0
+    psllw                m4, 12 ; (weight-16) << 12 when interpreted as signed
+    add                  wq, r6
+    cmp           dword r6m, 7
+    jg .weight_gt7
+    mov                  r6, tmp1q
+    psubw                m0, m4
+    mov               tmp1q, tmp2q
+    mova                 m4, m0 ; -weight
+    mov               tmp2q, r6
+.weight_gt7:
+    BIDIR_FN          W_AVG
+
+%macro MASK 1 ; src_offset
+    ; (a * m + b * (64 - m) + 512) >> 10
+    ; = ((a - b) * m + (b << 6) + 512) >> 10
+    ; = ((((b - a) * (-m << 10)) >> 16) + b + 8) >> 4
+    mova                 m3,     [maskq+(%1+0)*(mmsize/2)]
+    mova                 m0,     [tmp2q+(%1+0)*mmsize] ; b
+    psubw                m1, m0, [tmp1q+(%1+0)*mmsize] ; b - a
+    mova                 m6, m3      ; m
+    psubb                m3, m4, m6  ; -m
+    paddw                m1, m1     ; (b - a) << 1
+    paddb                m3, m3     ; -m << 1
+    punpcklbw            m2, m4, m3 ; -m << 9 (<< 8 when ext as uint16)
+    pmulhw               m1, m2     ; (-m * (b - a)) << 10
+    paddw                m0, m1     ; + b
+    mova                 m1,     [tmp2q+(%1+1)*mmsize] ; b
+    psubw                m2, m1, [tmp1q+(%1+1)*mmsize] ; b - a
+    paddw                m2, m2  ; (b - a) << 1
+    mova                 m6, m3  ; (-m << 1)
+    punpckhbw            m3, m4, m6 ; (-m << 9)
+    pmulhw               m2, m3 ; (-m << 9)
+    paddw                m1, m2 ; (-m * (b - a)) << 10
+    pmulhrsw             m0, m5 ; round
+    pmulhrsw             m1, m5 ; round
+    packuswb             m0, m1 ; interleave 16 -> 8
+%endmacro
+
+%macro MASK_INC_PTR 1
+    add               maskq, %1*mmsize/2
+    add               tmp1q, %1*mmsize
+    add               tmp2q, %1*mmsize
+%endmacro
+
+%if ARCH_X86_64
+cglobal mask_8bpc, 4, 8, 7, dst, stride, tmp1, tmp2, w, h, mask, stride3
+    movifnidn            hd, hm
+%else
+cglobal mask_8bpc, 4, 7, 7, dst, stride, tmp1, tmp2, w, mask, stride3
+%define hd dword r5m
+%endif
+%define base r6-mask_ssse3_table
+    LEA                  r6, mask_ssse3_table
+    tzcnt                wd, wm
+    movsxd               wq, dword [r6+wq*4]
+    pxor                 m4, m4
+    mova                 m5, [base+pw_2048]
+    add                  wq, r6
+    mov               maskq, r6m
+    BIDIR_FN           MASK
+%undef hd
+
+%macro W_MASK_420_END 1-*
+%rep %0
+    call .main
+    paddw                m2, [maskq+16*%1]
+    mova      [maskq+16*%1], m2
+    mova [dstq+strideq*1+16*(2*%1+0)], m0
+    call .main
+    psubw                m3, m7, m2
+    psubw                m1, m7, [maskq+16*%1]
+    psubw                m3, [dstq+strideq*1+16*(2*%1+1)]
+    psrlw                m1, 2
+    psrlw                m3, 2
+    packuswb             m1, m3
+    mova      [maskq+16*%1], m1
+    mova [dstq+strideq*1+16*(2*%1+1)], m0
+    %rotate 1
+%endrep
+%endmacro
+
+%if UNIX64
+DECLARE_REG_TMP 7
+%else
+DECLARE_REG_TMP 5
+%endif
+
+cglobal w_mask_420_8bpc, 4, 7, 9, dst, stride, tmp1, tmp2, w, h, mask
+%define base t0-w_mask_420_ssse3_table
+    LEA                  t0, w_mask_420_ssse3_table
+    tzcnt                wd, wm
+    mov                 r6d, r7m ; sign
+    sub               tmp2q, tmp1q
+    movsxd               wq, [t0+wq*4]
+    mova                 m6, [base+pw_2048]
+    movddup              m7, [base+wm_420_sign+r6*8] ; 258 - sign
+    add                  wq, t0
+%if ARCH_X86_64
+    mova                 m8, [base+pw_6903] ; ((64 - 38) << 8) + 255 - 8
+    movifnidn            hd, hm
+%else
+    %define              m8  [base+pw_6903]
+    %define              hd  dword hm
+%endif
+    mov               maskq, maskmp
+    call .main
+    jmp                  wq
+.w4_loop:
+    call .main
+    add               maskq, 4
+    lea                dstq, [dstq+strideq*2]
+.w4:
+    pshufd               m3, m2, q2020
+    pshufd               m2, m2, q3131
+    psubw                m1, m7, m3
+    psubw                m1, m2
+    psrlw                m1, 2
+    packuswb             m1, m1
+    movd            [maskq], m1
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    punpckhqdq           m0, m0
+    lea                dstq, [dstq+strideq*2]
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+.w8_loop:
+    call .main
+    add               maskq, 4
+    lea                dstq, [dstq+strideq*2]
+.w8:
+    movhlps              m3, m2
+    psubw                m1, m7, m2
+    psubw                m1, m3
+    psrlw                m1, 2
+    packuswb             m1, m1
+    movd            [maskq], m1
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16_loop:
+    call .main
+    add               maskq, 8
+    lea                dstq, [dstq+strideq*2]
+.w16:
+    mova   [dstq+strideq*1], m2
+    mova   [dstq+strideq*0], m0
+    call .main
+    psubw                m1, m7, [dstq+strideq*1]
+    psubw                m1, m2
+    psrlw                m1, 2
+    packuswb             m1, m1
+    movq            [maskq], m1
+    mova   [dstq+strideq*1], m0
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    add               maskq, 16
+    lea                dstq, [dstq+strideq*2]
+.w32:
+    mova            [maskq], m2
+    mova [dstq+strideq*0+16*0], m0
+    call .main
+    mova [dstq+strideq*1+16*1], m2
+    mova [dstq+strideq*0+16*1], m0
+    W_MASK_420_END        0
+    sub                  hd, 2
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add               maskq, 16*2
+    lea                dstq, [dstq+strideq*2]
+.w64:
+    mova       [maskq+16*0], m2
+    mova [dstq+strideq*0+16*0], m0
+    call .main
+    mova [dstq+strideq*1+16*1], m2
+    mova [dstq+strideq*0+16*1], m0
+    call .main
+    mova       [maskq+16*1], m2
+    mova [dstq+strideq*0+16*2], m0
+    call .main
+    mova [dstq+strideq*1+16*3], m2
+    mova [dstq+strideq*0+16*3], m0
+    W_MASK_420_END        0, 1
+    sub                  hd, 2
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add               maskq, 16*4
+    lea                dstq, [dstq+strideq*2]
+.w128:
+    mova       [maskq+16*0], m2
+    mova [dstq+strideq*0+16*0], m0
+    call .main
+    mova [dstq+strideq*1+16*1], m2
+    mova [dstq+strideq*0+16*1], m0
+    call .main
+    mova       [maskq+16*1], m2
+    mova [dstq+strideq*0+16*2], m0
+    call .main
+    mova [dstq+strideq*1+16*3], m2
+    mova [dstq+strideq*0+16*3], m0
+    call .main
+    mova       [maskq+16*2], m2
+    mova [dstq+strideq*0+16*4], m0
+    call .main
+    mova [dstq+strideq*1+16*5], m2
+    mova [dstq+strideq*0+16*5], m0
+    call .main
+    mova       [maskq+16*3], m2
+    mova [dstq+strideq*0+16*6], m0
+    call .main
+    mova [dstq+strideq*1+16*7], m2
+    mova [dstq+strideq*0+16*7], m0
+    W_MASK_420_END        0, 1, 2, 3
+    sub                  hd, 2
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [tmp1q      +16*0]
+    mova                 m3, [tmp1q+tmp2q+16*0]
+    mova                 m1, [tmp1q      +16*1]
+    mova                 m4, [tmp1q+tmp2q+16*1]
+    add               tmp1q, 16*2
+    psubw                m3, m0
+    psubw                m4, m1
+    pabsw                m5, m3
+    psubusw              m2, m8, m5
+    psrlw                m2, 8 ; 64 - m
+    psllw                m5, m2, 10
+    pmulhw               m3, m5
+    pabsw                m5, m4
+    paddw                m0, m3
+    psubusw              m3, m8, m5
+    psrlw                m3, 8
+    phaddw               m2, m3
+    psllw                m3, 10
+    pmulhw               m4, m3
+    paddw                m1, m4
+    pmulhrsw             m0, m6
+    pmulhrsw             m1, m6
+    packuswb             m0, m1
+    ret
+
+%macro W_MASK_422_BACKUP 1 ; mask_offset
+%if ARCH_X86_64
+    mova                m10, m2
+%else
+    mova      [maskq+16*%1], m2
+%endif
+%endmacro
+
+%macro W_MASK_422_END 1 ; mask_offset
+%if ARCH_X86_64
+    packuswb            m10, m2
+    psubb                m1, m7, m10
+    pavgb                m1, m9
+%else
+    mova                 m3, [maskq+16*%1]
+    packuswb             m3, m2
+    pxor                 m2, m2
+    psubb                m1, m7, m3
+    pavgb                m1, m2
+%endif
+    mova      [maskq+16*%1], m1
+%endmacro
+
+cglobal w_mask_422_8bpc, 4, 7, 11, dst, stride, tmp1, tmp2, w, h, mask
+%define base t0-w_mask_422_ssse3_table
+    LEA                  t0, w_mask_422_ssse3_table
+    tzcnt                wd, wm
+    mov                 r6d, r7m ; sign
+    sub               tmp2q, tmp1q
+    movsxd               wq, [t0+wq*4]
+    mova                 m6, [base+pw_2048]
+    movddup              m7, [base+wm_422_sign+r6*8] ; 128 - sign
+    add                  wq, t0
+%if ARCH_X86_64
+    mova                 m8, [base+pw_6903]
+    pxor                 m9, m9
+    movifnidn            hd, hm
+%else
+    add                  t0, w_mask_420_ssse3_table-w_mask_422_ssse3_table
+    %define              hd  dword hm
+%endif
+    mov               maskq, maskmp
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    jmp                  wq
+.w4_loop:
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    add               maskq, 8
+    lea                dstq, [dstq+strideq*2]
+.w4:
+    packuswb             m2, m2
+    psubb                m1, m7, m2
+%if ARCH_X86_64
+    pavgb                m1, m9
+%else
+    pxor                 m2, m2
+    pavgb                m1, m2
+%endif
+    movq            [maskq], m1
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    punpckhqdq           m0, m0
+    lea                dstq, [dstq+strideq*2]
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+.w8_loop:
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    add               maskq, 16
+    lea                dstq, [dstq+strideq*2]
+.w8:
+    W_MASK_422_BACKUP     0
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    lea                dstq, [dstq+strideq*2]
+    W_MASK_422_END        0
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    sub                  hd, 4
+    jg .w8_loop
+    RET
+.w16_loop:
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    add               maskq, 16
+    lea                dstq, [dstq+strideq*2]
+.w16:
+    W_MASK_422_BACKUP     0
+    mova   [dstq+strideq*0], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_END        0
+    mova   [dstq+strideq*1], m0
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32_loop:
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    add               maskq, 16
+    add                dstq, strideq
+.w32:
+    W_MASK_422_BACKUP     0
+    mova        [dstq+16*0], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_END        0
+    mova        [dstq+16*1], m0
+    dec                  hd
+    jg .w32_loop
+    RET
+.w64_loop:
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    add               maskq, 16*2
+    add                dstq, strideq
+.w64:
+    W_MASK_422_BACKUP     0
+    mova        [dstq+16*0], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_END        0
+    mova        [dstq+16*1], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_BACKUP     1
+    mova        [dstq+16*2], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_END        1
+    mova        [dstq+16*3], m0
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    add               maskq, 16*4
+    add                dstq, strideq
+.w128:
+    W_MASK_422_BACKUP     0
+    mova        [dstq+16*0], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_END        0
+    mova        [dstq+16*1], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_BACKUP     1
+    mova        [dstq+16*2], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_END        1
+    mova        [dstq+16*3], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_BACKUP     2
+    mova        [dstq+16*4], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_END        2
+    mova        [dstq+16*5], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_BACKUP     3
+    mova        [dstq+16*6], m0
+    call mangle(private_prefix %+ _w_mask_420_8bpc_ssse3).main
+    W_MASK_422_END        3
+    mova        [dstq+16*7], m0
+    dec                  hd
+    jg .w128_loop
+    RET
+
+cglobal w_mask_444_8bpc, 4, 7, 9, dst, stride, tmp1, tmp2, w, h, mask
+%define base t0-w_mask_444_ssse3_table
+    LEA                  t0, w_mask_444_ssse3_table
+    tzcnt                wd, wm
+    mov               maskq, maskmp
+    sub               tmp2q, tmp1q
+    movsxd               wq, [t0+wq*4]
+    mova                 m6, [base+pw_6903]
+    mova                 m7, [base+pw_2048]
+    add                  wq, t0
+%if ARCH_X86_64
+    mova                 m8, [base+pb_64]
+    movifnidn            hd, hm
+%else
+    %define              m8  [base+pb_64]
+    %define              hd  dword hm
+%endif
+    call .main
+    jmp                  wq
+.w4_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w4:
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    punpckhqdq           m0, m0
+    lea                dstq, [dstq+strideq*2]
+    movd   [dstq+strideq*0], m0
+    pshuflw              m1, m0, q1032
+    movd   [dstq+strideq*1], m1
+    sub                  hd, 4
+    jg .w4_loop
+    RET
+.w8_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w8:
+    movq   [dstq+strideq*0], m0
+    movhps [dstq+strideq*1], m0
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16_loop:
+    call .main
+    lea                dstq, [dstq+strideq*2]
+.w16:
+    mova   [dstq+strideq*0], m0
+    call .main
+    mova   [dstq+strideq*1], m0
+    sub                  hd, 2
+    jg .w16_loop
+    RET
+.w32_loop:
+    call .main
+    add                dstq, strideq
+.w32:
+    mova        [dstq+16*0], m0
+    call .main
+    mova        [dstq+16*1], m0
+    dec                  hd
+    jg .w32_loop
+    RET
+.w64_loop:
+    call .main
+    add                dstq, strideq
+.w64:
+    mova        [dstq+16*0], m0
+    call .main
+    mova        [dstq+16*1], m0
+    call .main
+    mova        [dstq+16*2], m0
+    call .main
+    mova        [dstq+16*3], m0
+    dec                  hd
+    jg .w64_loop
+    RET
+.w128_loop:
+    call .main
+    add                dstq, strideq
+.w128:
+    mova        [dstq+16*0], m0
+    call .main
+    mova        [dstq+16*1], m0
+    call .main
+    mova        [dstq+16*2], m0
+    call .main
+    mova        [dstq+16*3], m0
+    call .main
+    mova        [dstq+16*4], m0
+    call .main
+    mova        [dstq+16*5], m0
+    call .main
+    mova        [dstq+16*6], m0
+    call .main
+    mova        [dstq+16*7], m0
+    dec                  hd
+    jg .w128_loop
+    RET
+ALIGN function_align
+.main:
+    mova                 m0, [tmp1q      +16*0]
+    mova                 m3, [tmp1q+tmp2q+16*0]
+    mova                 m1, [tmp1q      +16*1]
+    mova                 m4, [tmp1q+tmp2q+16*1]
+    add               tmp1q, 16*2
+    psubw                m3, m0
+    psubw                m4, m1
+    pabsw                m5, m3
+    psubusw              m2, m6, m5
+    psrlw                m2, 8 ; 64 - m
+    psllw                m5, m2, 10
+    pmulhw               m3, m5
+    pabsw                m5, m4
+    paddw                m0, m3
+    psubusw              m3, m6, m5
+    psrlw                m3, 8
+    packuswb             m2, m3
+    psllw                m3, 10
+    pmulhw               m4, m3
+    psubb                m3, m8, m2
+    paddw                m1, m4
+    pmulhrsw             m0, m7
+    pmulhrsw             m1, m7
+    mova            [maskq], m3
+    add               maskq, 16
+    packuswb             m0, m1
+    ret
+
+%macro BLEND_64M 4; a, b, mask1, mask2
+    punpcklbw            m0, %1, %2; {b;a}[7..0]
+    punpckhbw            %1, %2    ; {b;a}[15..8]
+    pmaddubsw            m0, %3    ; {b*m[0] + (64-m[0])*a}[7..0] u16
+    pmaddubsw            %1, %4    ; {b*m[1] + (64-m[1])*a}[15..8] u16
+    pmulhrsw             m0, m5    ; {((b*m[0] + (64-m[0])*a) + 1) / 32}[7..0] u16
+    pmulhrsw             %1, m5    ; {((b*m[1] + (64-m[0])*a) + 1) / 32}[15..8] u16
+    packuswb             m0, %1    ; {blendpx}[15..0] u8
+%endmacro
+
+%macro BLEND 2; a, b
+    psubb                m3, m4, m0 ; m3 = (64 - m)
+    punpcklbw            m2, m3, m0 ; {m;(64-m)}[7..0]
+    punpckhbw            m3, m0     ; {m;(64-m)}[15..8]
+    BLEND_64M            %1, %2, m2, m3
+%endmacro
+
+cglobal blend_8bpc, 3, 7, 7, dst, ds, tmp, w, h, mask
+%define base r6-blend_ssse3_table
+    LEA                  r6, blend_ssse3_table
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movifnidn         maskq, maskmp
+    movsxd               wq, dword [r6+wq*4]
+    mova                 m4, [base+pb_64]
+    mova                 m5, [base+pw_512]
+    add                  wq, r6
+    lea                  r6, [dsq*3]
+    jmp                  wq
+.w4:
+    movq                 m0, [maskq]; m
+    movd                 m1, [dstq+dsq*0] ; a
+    movd                 m6, [dstq+dsq*1]
+    punpckldq            m1, m6
+    movq                 m6, [tmpq] ; b
+    psubb                m3, m4, m0 ; m3 = (64 - m)
+    punpcklbw            m2, m3, m0 ; {m;(64-m)}[7..0]
+    punpcklbw            m1, m6    ; {b;a}[7..0]
+    pmaddubsw            m1, m2    ; {b*m[0] + (64-m[0])*a}[7..0] u16
+    pmulhrsw             m1, m5    ; {((b*m[0] + (64-m[0])*a) + 1) / 32}[7..0] u16
+    packuswb             m1, m0    ; {blendpx}[15..0] u8
+    movd       [dstq+dsq*0], m1
+    psrlq                m1, 32
+    movd       [dstq+dsq*1], m1
+    add               maskq, 8
+    add                tmpq, 8
+    lea                dstq, [dstq+dsq*2] ; dst_stride * 2
+    sub                  hd, 2
+    jg .w4
+    RET
+.w8:
+    mova                 m0, [maskq]; m
+    movq                 m1, [dstq+dsq*0] ; a
+    movhps               m1, [dstq+dsq*1]
+    mova                 m6, [tmpq] ; b
+    BLEND                m1, m6
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    add               maskq, 16
+    add                tmpq, 16
+    lea                dstq, [dstq+dsq*2] ; dst_stride * 2
+    sub                  hd, 2
+    jg .w8
+    RET
+.w16:
+    mova                 m0, [maskq]; m
+    mova                 m1, [dstq] ; a
+    mova                 m6, [tmpq] ; b
+    BLEND                m1, m6
+    mova             [dstq], m0
+    add               maskq, 16
+    add                tmpq, 16
+    add                dstq, dsq ; dst_stride
+    dec                  hd
+    jg .w16
+    RET
+.w32:
+    %assign i 0
+    %rep 2
+    mova                 m0, [maskq+16*i]; m
+    mova                 m1, [dstq+16*i] ; a
+    mova                 m6, [tmpq+16*i] ; b
+    BLEND                m1, m6
+    mova        [dstq+i*16], m0
+    %assign i i+1
+    %endrep
+    add               maskq, 32
+    add                tmpq, 32
+    add                dstq, dsq ; dst_stride
+    dec                  hd
+    jg .w32
+    RET
+
+cglobal blend_v_8bpc, 3, 6, 6, dst, ds, tmp, w, h, mask
+%define base r5-blend_v_ssse3_table
+    LEA                  r5, blend_v_ssse3_table
+    tzcnt                wd, wm
+    movifnidn            hd, hm
+    movsxd               wq, dword [r5+wq*4]
+    mova                 m5, [base+pw_512]
+    add                  wq, r5
+    add               maskq, obmc_masks-blend_v_ssse3_table
+    jmp                  wq
+.w2:
+    movd                 m3, [maskq+4]
+    punpckldq            m3, m3
+    ; 2 mask blend is provided for 4 pixels / 2 lines
+.w2_loop:
+    movd                 m1, [dstq+dsq*0] ; a {..;a;a}
+    pinsrw               m1, [dstq+dsq*1], 1
+    movd                 m2, [tmpq] ; b
+    punpcklbw            m0, m1, m2; {b;a}[7..0]
+    pmaddubsw            m0, m3    ; {b*m + (64-m)*a}[7..0] u16
+    pmulhrsw             m0, m5    ; {((b*m + (64-m)*a) + 1) / 32}[7..0] u16
+    packuswb             m0, m1    ; {blendpx}[8..0] u8
+    movd                r3d, m0
+    mov        [dstq+dsq*0], r3w
+    shr                 r3d, 16
+    mov        [dstq+dsq*1], r3w
+    add                tmpq, 2*2
+    lea                dstq, [dstq + dsq * 2]
+    sub                  hd, 2
+    jg .w2_loop
+    RET
+.w4:
+    movddup              m3, [maskq+8]
+    ; 4 mask blend is provided for 8 pixels / 2 lines
+.w4_loop:
+    movd                 m1, [dstq+dsq*0] ; a
+    movd                 m2, [dstq+dsq*1] ;
+    punpckldq            m1, m2
+    movq                 m2, [tmpq] ; b
+    punpcklbw            m1, m2    ; {b;a}[7..0]
+    pmaddubsw            m1, m3    ; {b*m + (64-m)*a}[7..0] u16
+    pmulhrsw             m1, m5    ; {((b*m + (64-m)*a) + 1) / 32}[7..0] u16
+    packuswb             m1, m1    ; {blendpx}[8..0] u8
+    movd             [dstq], m1
+    psrlq                m1, 32
+    movd       [dstq+dsq*1], m1
+    add                tmpq, 2*4
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w4_loop
+    RET
+.w8:
+    mova                 m3, [maskq+16]
+    ; 8 mask blend is provided for 16 pixels
+.w8_loop:
+    movq                 m1, [dstq+dsq*0] ; a
+    movhps               m1, [dstq+dsq*1]
+    mova                 m2, [tmpq]; b
+    BLEND_64M            m1, m2, m3, m3
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    add                tmpq, 16
+    lea                dstq, [dstq+dsq*2]
+    sub                  hd, 2
+    jg .w8_loop
+    RET
+.w16:
+    ; 16 mask blend is provided for 32 pixels
+    mova                  m3, [maskq+32] ; obmc_masks_16[0] (64-m[0])
+    mova                  m4, [maskq+48] ; obmc_masks_16[1] (64-m[1])
+.w16_loop:
+    mova                 m1, [dstq] ; a
+    mova                 m2, [tmpq] ; b
+    BLEND_64M            m1, m2, m3, m4
+    mova             [dstq], m0
+    add                tmpq, 16
+    add                dstq, dsq
+    dec                  hd
+    jg .w16_loop
+    RET
+.w32:
+%if WIN64
+    mova            [rsp+8], xmm6
+%endif
+    mova                 m3, [maskq+64] ; obmc_masks_32[0] (64-m[0])
+    mova                 m4, [maskq+80] ; obmc_masks_32[1] (64-m[1])
+    mova                 m6, [maskq+96] ; obmc_masks_32[2] (64-m[2])
+    ; 16 mask blend is provided for 64 pixels
+.w32_loop:
+    mova                 m1, [dstq+16*0] ; a
+    mova                 m2, [tmpq+16*0] ; b
+    BLEND_64M            m1, m2, m3, m4
+    movq                 m1, [dstq+16*1] ; a
+    punpcklbw            m1, [tmpq+16*1] ; b
+    pmaddubsw            m1, m6
+    pmulhrsw             m1, m5
+    packuswb             m1, m1
+    mova        [dstq+16*0], m0
+    movq        [dstq+16*1], m1
+    add                tmpq, 32
+    add                dstq, dsq
+    dec                  hd
+    jg .w32_loop
+%if WIN64
+    mova               xmm6, [rsp+8]
+%endif
+    RET
+
+cglobal blend_h_8bpc, 3, 7, 6, dst, ds, tmp, w, h, mask
+%define base t0-blend_h_ssse3_table
+%if ARCH_X86_32
+    ; We need to keep the PIC pointer for w4, reload wd from stack instead
+    DECLARE_REG_TMP 6
+%else
+    DECLARE_REG_TMP 5
+    mov                 r6d, wd
+%endif
+    LEA                  t0, blend_h_ssse3_table
+    tzcnt                wd, wm
+    mov                  hd, hm
+    movsxd               wq, dword [t0+wq*4]
+    mova                 m5, [base+pw_512]
+    add                  wq, t0
+    lea               maskq, [base+obmc_masks+hq*2]
+    lea                  hd, [hq*3]
+    shr                  hd, 2 ; h * 3/4
+    lea               maskq, [maskq+hq*2]
+    neg                  hq
+    jmp                  wq
+.w2:
+    movd                 m0, [dstq+dsq*0]
+    pinsrw               m0, [dstq+dsq*1], 1
+    movd                 m2, [maskq+hq*2]
+    movd                 m1, [tmpq]
+    punpcklwd            m2, m2
+    punpcklbw            m0, m1
+    pmaddubsw            m0, m2
+    pmulhrsw             m0, m5
+    packuswb             m0, m0
+    movd                r3d, m0
+    mov        [dstq+dsq*0], r3w
+    shr                 r3d, 16
+    mov        [dstq+dsq*1], r3w
+    lea                dstq, [dstq+dsq*2]
+    add                tmpq, 2*2
+    add                  hq, 2
+    jl .w2
+    RET
+.w4:
+%if ARCH_X86_32
+    mova                 m3, [base+blend_shuf]
+%else
+    mova                 m3, [blend_shuf]
+%endif
+.w4_loop:
+    movd                 m0, [dstq+dsq*0]
+    movd                 m2, [dstq+dsq*1]
+    punpckldq            m0, m2 ; a
+    movq                 m1, [tmpq] ; b
+    movq                 m2, [maskq+hq*2] ; m
+    pshufb               m2, m3
+    punpcklbw            m0, m1
+    pmaddubsw            m0, m2
+    pmulhrsw             m0, m5
+    packuswb             m0, m0
+    movd       [dstq+dsq*0], m0
+    psrlq                m0, 32
+    movd       [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    add                tmpq, 4*2
+    add                  hq, 2
+    jl .w4_loop
+    RET
+.w8:
+    movd                 m4, [maskq+hq*2]
+    punpcklwd            m4, m4
+    pshufd               m3, m4, q0000
+    pshufd               m4, m4, q1111
+    movq                 m1, [dstq+dsq*0] ; a
+    movhps               m1, [dstq+dsq*1]
+    mova                 m2, [tmpq]
+    BLEND_64M            m1, m2, m3, m4
+    movq       [dstq+dsq*0], m0
+    movhps     [dstq+dsq*1], m0
+    lea                dstq, [dstq+dsq*2]
+    add                tmpq, 8*2
+    add                  hq, 2
+    jl .w8
+    RET
+; w16/w32/w64/w128
+.w16:
+%if ARCH_X86_32
+    mov                 r6d, wm
+%endif
+    sub                 dsq, r6
+.w16_loop0:
+    movd                 m3, [maskq+hq*2]
+    pshuflw              m3, m3, q0000
+    punpcklqdq           m3, m3
+    mov                  wd, r6d
+.w16_loop:
+    mova                 m1, [dstq] ; a
+    mova                 m2, [tmpq] ; b
+    BLEND_64M            m1, m2, m3, m3
+    mova             [dstq], m0
+    add                dstq, 16
+    add                tmpq, 16
+    sub                  wd, 16
+    jg .w16_loop
+    add                dstq, dsq
+    inc                  hq
+    jl .w16_loop0
+    RET
+
+; emu_edge args:
+; const intptr_t bw, const intptr_t bh, const intptr_t iw, const intptr_t ih,
+; const intptr_t x, const intptr_t y, pixel *dst, const ptrdiff_t dst_stride,
+; const pixel *ref, const ptrdiff_t ref_stride
+;
+; bw, bh total filled size
+; iw, ih, copied block -> fill bottom, right
+; x, y, offset in bw/bh -> fill top, left
+cglobal emu_edge_8bpc, 10, 13, 2, bw, bh, iw, ih, x, \
+                                  y, dst, dstride, src, sstride, \
+                                  bottomext, rightext, blk
+    ; we assume that the buffer (stride) is larger than width, so we can
+    ; safely overwrite by a few bytes
+    pxor                 m1, m1
+
+%if ARCH_X86_64
+ %define reg_zero       r12q
+ %define reg_tmp        r10
+ %define reg_src        srcq
+ %define reg_bottomext  bottomextq
+ %define reg_rightext   rightextq
+ %define reg_blkm       r9m
+%else
+ %define reg_zero       r6
+ %define reg_tmp        r0
+ %define reg_src        r1
+ %define reg_bottomext  r0
+ %define reg_rightext   r1
+ %define reg_blkm       r2m
+%endif
+    ;
+    ; ref += iclip(y, 0, ih - 1) * PXSTRIDE(ref_stride)
+    xor            reg_zero, reg_zero
+    lea             reg_tmp, [ihq-1]
+    cmp                  yq, ihq
+    cmovs           reg_tmp, yq
+    test                 yq, yq
+    cmovs           reg_tmp, reg_zero
+%if ARCH_X86_64
+    imul            reg_tmp, sstrideq
+    add                srcq, reg_tmp
+%else
+    imul            reg_tmp, sstridem
+    mov             reg_src, srcm
+    add             reg_src, reg_tmp
+%endif
+    ;
+    ; ref += iclip(x, 0, iw - 1)
+    lea             reg_tmp, [iwq-1]
+    cmp                  xq, iwq
+    cmovs           reg_tmp, xq
+    test                 xq, xq
+    cmovs           reg_tmp, reg_zero
+    add             reg_src, reg_tmp
+%if ARCH_X86_32
+    mov                srcm, reg_src
+%endif
+    ;
+    ; bottom_ext = iclip(y + bh - ih, 0, bh - 1)
+%if ARCH_X86_32
+    mov                  r1, r1m ; restore bh
+%endif
+    lea       reg_bottomext, [yq+bhq]
+    sub       reg_bottomext, ihq
+    lea                  r3, [bhq-1]
+    cmovs     reg_bottomext, reg_zero
+    ;
+
+    DEFINE_ARGS bw, bh, iw, ih, x, \
+                topext, dst, dstride, src, sstride, \
+                bottomext, rightext, blk
+
+    ; top_ext = iclip(-y, 0, bh - 1)
+    neg             topextq
+    cmovs           topextq, reg_zero
+    cmp       reg_bottomext, bhq
+    cmovns    reg_bottomext, r3
+    cmp             topextq, bhq
+    cmovg           topextq, r3
+ %if ARCH_X86_32
+    mov                 r4m, reg_bottomext
+    ;
+    ; right_ext = iclip(x + bw - iw, 0, bw - 1)
+    mov                  r0, r0m ; restore bw
+ %endif
+    lea        reg_rightext, [xq+bwq]
+    sub        reg_rightext, iwq
+    lea                  r2, [bwq-1]
+    cmovs      reg_rightext, reg_zero
+
+    DEFINE_ARGS bw, bh, iw, ih, leftext, \
+                topext, dst, dstride, src, sstride, \
+                bottomext, rightext, blk
+
+    ; left_ext = iclip(-x, 0, bw - 1)
+    neg            leftextq
+    cmovs          leftextq, reg_zero
+    cmp        reg_rightext, bwq
+    cmovns     reg_rightext, r2
+ %if ARCH_X86_32
+    mov                 r3m, r1
+ %endif
+    cmp            leftextq, bwq
+    cmovns         leftextq, r2
+
+%undef reg_zero
+%undef reg_tmp
+%undef reg_src
+%undef reg_bottomext
+%undef reg_rightext
+
+    DEFINE_ARGS bw, centerh, centerw, dummy, leftext, \
+                topext, dst, dstride, src, sstride, \
+                bottomext, rightext, blk
+
+    ; center_h = bh - top_ext - bottom_ext
+%if ARCH_X86_64
+    lea                  r3, [bottomextq+topextq]
+    sub            centerhq, r3
+%else
+    mov                   r1, centerhm ; restore r1
+    sub             centerhq, topextq
+    sub             centerhq, r4m
+    mov                  r1m, centerhq
+%endif
+    ;
+    ; blk += top_ext * PXSTRIDE(dst_stride)
+    mov                  r2, topextq
+%if ARCH_X86_64
+    imul                 r2, dstrideq
+%else
+    mov                  r6, r6m ; restore dstq
+    imul                 r2, dstridem
+%endif
+    add                dstq, r2
+    mov            reg_blkm, dstq ; save pointer for ext
+    ;
+    ; center_w = bw - left_ext - right_ext
+    mov            centerwq, bwq
+%if ARCH_X86_64
+    lea                  r3, [rightextq+leftextq]
+    sub            centerwq, r3
+%else
+    sub            centerwq, r3m
+    sub            centerwq, leftextq
+%endif
+
+; vloop Macro
+%macro v_loop 3 ; need_left_ext, need_right_ext, suffix
+  %if ARCH_X86_64
+    %define reg_tmp        r12
+  %else
+    %define reg_tmp        r0
+  %endif
+.v_loop_%3:
+  %if ARCH_X86_32
+    mov                  r0, r0m
+    mov                  r1, r1m
+  %endif
+%if %1
+    ; left extension
+  %if ARCH_X86_64
+    movd                 m0, [srcq]
+  %else
+    mov                  r3, srcm
+    movd                 m0, [r3]
+  %endif
+    pshufb               m0, m1
+    xor                  r3, r3
+.left_loop_%3:
+    mova          [dstq+r3], m0
+    add                  r3, mmsize
+    cmp                  r3, leftextq
+    jl .left_loop_%3
+    ; body
+    lea             reg_tmp, [dstq+leftextq]
+%endif
+    xor                  r3, r3
+.body_loop_%3:
+  %if ARCH_X86_64
+    movu                 m0, [srcq+r3]
+  %else
+    mov                  r1, srcm
+    movu                 m0, [r1+r3]
+  %endif
+%if %1
+    movu       [reg_tmp+r3], m0
+%else
+    movu          [dstq+r3], m0
+%endif
+    add                  r3, mmsize
+    cmp                  r3, centerwq
+    jl .body_loop_%3
+%if %2
+    ; right extension
+%if %1
+    add             reg_tmp, centerwq
+%else
+    lea             reg_tmp, [dstq+centerwq]
+%endif
+  %if ARCH_X86_64
+    movd                 m0, [srcq+centerwq-1]
+  %else
+    mov                  r3, srcm
+    movd                 m0, [r3+centerwq-1]
+  %endif
+    pshufb               m0, m1
+    xor                  r3, r3
+.right_loop_%3:
+    movu       [reg_tmp+r3], m0
+    add                  r3, mmsize
+  %if ARCH_X86_64
+    cmp                  r3, rightextq
+  %else
+    cmp                  r3, r3m
+  %endif
+    jl .right_loop_%3
+%endif
+  %if ARCH_X86_64
+    add                dstq, dstrideq
+    add                srcq, sstrideq
+    dec            centerhq
+    jg .v_loop_%3
+  %else
+    add                dstq, dstridem
+    mov                  r0, sstridem
+    add                srcm, r0
+    sub       dword centerhm, 1
+    jg .v_loop_%3
+    mov                  r0, r0m ; restore r0
+  %endif
+%endmacro ; vloop MACRO
+
+    test           leftextq, leftextq
+    jnz .need_left_ext
+ %if ARCH_X86_64
+    test          rightextq, rightextq
+    jnz .need_right_ext
+ %else
+    cmp            leftextq, r3m ; leftextq == 0
+    jne .need_right_ext
+ %endif
+    v_loop                0, 0, 0
+    jmp .body_done
+
+    ;left right extensions
+.need_left_ext:
+ %if ARCH_X86_64
+    test          rightextq, rightextq
+ %else
+    mov                  r3, r3m
+    test                 r3, r3
+ %endif
+    jnz .need_left_right_ext
+    v_loop                1, 0, 1
+    jmp .body_done
+
+.need_left_right_ext:
+    v_loop                1, 1, 2
+    jmp .body_done
+
+.need_right_ext:
+    v_loop                0, 1, 3
+
+.body_done:
+; r0 ; bw
+; r1 ;; x loop
+; r4 ;; y loop
+; r5 ; topextq
+; r6 ;dstq
+; r7 ;dstrideq
+; r8 ; srcq
+%if ARCH_X86_64
+ %define reg_dstride    dstrideq
+%else
+ %define reg_dstride    r2
+%endif
+    ;
+    ; bottom edge extension
+ %if ARCH_X86_64
+    test         bottomextq, bottomextq
+    jz .top
+ %else
+    xor                  r1, r1
+    cmp                  r1, r4m
+    je .top
+ %endif
+    ;
+ %if ARCH_X86_64
+    mov                srcq, dstq
+    sub                srcq, dstrideq
+    xor                  r1, r1
+ %else
+    mov                  r3, dstq
+    mov         reg_dstride, dstridem
+    sub                  r3, reg_dstride
+    mov                srcm, r3
+ %endif
+    ;
+.bottom_x_loop:
+ %if ARCH_X86_64
+    mova                 m0, [srcq+r1]
+    lea                  r3, [dstq+r1]
+    mov                  r4, bottomextq
+ %else
+    mov                  r3, srcm
+    mova                 m0, [r3+r1]
+    lea                  r3, [dstq+r1]
+    mov                  r4, r4m
+ %endif
+    ;
+.bottom_y_loop:
+    mova               [r3], m0
+    add                  r3, reg_dstride
+    dec                  r4
+    jg .bottom_y_loop
+    add                  r1, mmsize
+    cmp                  r1, bwq
+    jl .bottom_x_loop
+
+.top:
+    ; top edge extension
+    test            topextq, topextq
+    jz .end
+%if ARCH_X86_64
+    mov                srcq, reg_blkm
+%else
+    mov                  r3, reg_blkm
+    mov         reg_dstride, dstridem
+%endif
+    mov                dstq, dstm
+    xor                  r1, r1
+    ;
+.top_x_loop:
+%if ARCH_X86_64
+    mova                 m0, [srcq+r1]
+%else
+    mov                  r3, reg_blkm
+    mova                 m0, [r3+r1]
+%endif
+    lea                  r3, [dstq+r1]
+    mov                  r4, topextq
+    ;
+.top_y_loop:
+    mova               [r3], m0
+    add                  r3, reg_dstride
+    dec                  r4
+    jg .top_y_loop
+    add                  r1, mmsize
+    cmp                  r1, bwq
+    jl .top_x_loop
+
+.end:
+    RET
+
+%undef reg_dstride
+%undef reg_blkm
+%undef reg_tmp
+
+cextern resize_filter
+
+%macro SCRATCH 3
+%if ARCH_X86_32
+    mova [rsp+%3*mmsize], m%1
+%define m%2 [rsp+%3*mmsize]
+%else
+    SWAP             %1, %2
+%endif
+%endmacro
+
+%if ARCH_X86_64
+cglobal resize_8bpc, 0, 12, 14, dst, dst_stride, src, src_stride, \
+                                dst_w, h, src_w, dx, mx0
+%elif STACK_ALIGNMENT >= 16
+cglobal resize_8bpc, 0, 7, 8, 3 * 16, dst, dst_stride, src, src_stride, \
+                                      dst_w, h, src_w, dx, mx0
+%else
+cglobal resize_8bpc, 0, 6, 8, 3 * 16, dst, dst_stride, src, src_stride, \
+                                      dst_w, h, src_w, dx, mx0
+%endif
+    movifnidn          dstq, dstmp
+    movifnidn          srcq, srcmp
+%if STACK_ALIGNMENT >= 16
+    movifnidn        dst_wd, dst_wm
+%endif
+%if ARCH_X86_64
+    movifnidn            hd, hm
+%endif
+    sub          dword mx0m, 4<<14
+    sub        dword src_wm, 8
+    movd                 m7, dxm
+    movd                 m6, mx0m
+    movd                 m5, src_wm
+    pshufd               m7, m7, q0000
+    pshufd               m6, m6, q0000
+    pshufd               m5, m5, q0000
+
+%if ARCH_X86_64
+    DEFINE_ARGS dst, dst_stride, src, src_stride, dst_w, h, x
+    LEA                  r7, $$
+%define base r7-$$
+%else
+    DEFINE_ARGS dst, dst_stride, src, src_stride, dst_w, x
+%define hd dword r5m
+%if STACK_ALIGNMENT >= 16
+    LEA                  r6, $$
+%define base r6-$$
+%else
+    LEA                  r4, $$
+%define base r4-$$
+%endif
+%endif
+
+%if ARCH_X86_64
+    mova                m10, [base+pw_m256]
+    mova                 m9, [base+pd_63]
+    mova                 m8, [base+pb_8x0_8x8]
+%else
+%define m10 [base+pw_m256]
+%define m9  [base+pd_63]
+%define m8  [base+pb_8x0_8x8]
+%endif
+    pmaddwd              m4, m7, [base+rescale_mul] ; dx*[0,1,2,3]
+    pslld                m7, 2                      ; dx*4
+    pslld                m5, 14
+    paddd                m6, m4                     ; mx+[0..3]*dx
+    SCRATCH               7, 13, 0
+    SCRATCH               6, 12, 1
+    SCRATCH               5, 11, 2
+
+    ; m10 = pmulhrsw constant for x=(x+64)>>7
+    ; m12 = mx+[0..3]*dx, m13 = dx*4, m11 = src_w, m9 = 0x3f, m8=0,8
+
+.loop_y:
+    xor                  xd, xd
+    mova                 m0, m12                    ; per-line working version of mx
+
+.loop_x:
+    pxor                 m1, m1
+    pcmpgtd              m1, m0
+    pandn                m1, m0
+    psrad                m2, m0, 8                  ; filter offset (unmasked)
+    pcmpgtd              m3, m11, m1
+    pand                 m1, m3
+    pandn                m3, m11
+    por                  m1, m3
+    psubd                m3, m0, m1                 ; pshufb offset
+    psrad                m1, 14                     ; clipped src_x offset
+    psrad                m3, 14                     ; pshufb edge_emu offset
+    pand                 m2, m9                     ; filter offset (masked)
+
+    ; load source pixels
+%if ARCH_X86_64
+    movd                r8d, m1
+    pshuflw              m1, m1, q3232
+    movd                r9d, m1
+    punpckhqdq           m1, m1
+    movd               r10d, m1
+    psrlq                m1, 32
+    movd               r11d, m1
+    movq                 m4, [srcq+r8]
+    movq                 m5, [srcq+r10]
+    movhps               m4, [srcq+r9]
+    movhps               m5, [srcq+r11]
+%else
+    movd                r3d,  m1
+    pshufd               m1,  m1, q3312
+    movd                r1d,  m1
+    pshuflw              m1,  m1, q3232
+    movq                 m4, [srcq+r3]
+    movq                 m5, [srcq+r1]
+    movd                r3d,  m1
+    punpckhqdq           m1,  m1
+    movd                r1d,  m1
+    movhps               m4, [srcq+r3]
+    movhps               m5, [srcq+r1]
+%endif
+
+    ; if no emulation is required, we don't need to shuffle or emulate edges
+    ; this also saves 2 quasi-vpgatherdqs
+    pxor                 m6, m6
+    pcmpeqb              m6, m3
+%if ARCH_X86_64
+    pmovmskb            r8d, m6
+    cmp                 r8d, 0xffff
+%else
+    pmovmskb            r3d, m6
+    cmp                 r3d, 0xffff
+%endif
+    je .filter
+
+%if ARCH_X86_64
+    movd                r8d, m3
+    pshuflw              m3, m3, q3232
+    movd                r9d, m3
+    punpckhqdq           m3, m3
+    movd               r10d, m3
+    psrlq                m3, 32
+    movd               r11d, m3
+    movsxd               r8, r8d
+    movsxd               r9, r9d
+    movsxd              r10, r10d
+    movsxd              r11, r11d
+    movq                 m6, [base+resize_shuf+4+r8]
+    movq                 m7, [base+resize_shuf+4+r10]
+    movhps               m6, [base+resize_shuf+4+r9]
+    movhps               m7, [base+resize_shuf+4+r11]
+%else
+    movd                r3d, m3
+    pshufd               m3, m3, q3312
+    movd                r1d, m3
+    pshuflw              m3, m3, q3232
+    movq                 m6, [base+resize_shuf+4+r3]
+    movq                 m7, [base+resize_shuf+4+r1]
+    movd                r3d, m3
+    punpckhqdq           m3, m3
+    movd                r1d, m3
+    movhps               m6, [base+resize_shuf+4+r3]
+    movhps               m7, [base+resize_shuf+4+r1]
+%endif
+
+    paddb                m6, m8
+    paddb                m7, m8
+    pshufb               m4, m6
+    pshufb               m5, m7
+
+.filter:
+%if ARCH_X86_64
+    movd                r8d, m2
+    pshuflw              m2, m2, q3232
+    movd                r9d, m2
+    punpckhqdq           m2, m2
+    movd               r10d, m2
+    psrlq                m2, 32
+    movd               r11d, m2
+    movq                 m6, [base+resize_filter+r8*8]
+    movq                 m7, [base+resize_filter+r10*8]
+    movhps               m6, [base+resize_filter+r9*8]
+    movhps               m7, [base+resize_filter+r11*8]
+%else
+    movd                r3d, m2
+    pshufd               m2, m2, q3312
+    movd                r1d, m2
+    pshuflw              m2, m2, q3232
+    movq                 m6, [base+resize_filter+r3*8]
+    movq                 m7, [base+resize_filter+r1*8]
+    movd                r3d, m2
+    punpckhqdq           m2, m2
+    movd                r1d, m2
+    movhps               m6, [base+resize_filter+r3*8]
+    movhps               m7, [base+resize_filter+r1*8]
+%endif
+
+    pmaddubsw            m4, m6
+    pmaddubsw            m5, m7
+    phaddw               m4, m5
+    phaddsw              m4, m4
+    pmulhrsw             m4, m10                    ; x=(x+64)>>7
+    packuswb             m4, m4
+    movd          [dstq+xq], m4
+
+    paddd                m0, m13
+    add                  xd, 4
+%if STACK_ALIGNMENT >= 16
+    cmp                  xd, dst_wd
+%else
+    cmp                  xd, dst_wm
+%endif
+    jl .loop_x
+
+    add                dstq, dst_stridemp
+    add                srcq, src_stridemp
+    dec                  hd
+    jg .loop_y
+    RET
+
+INIT_XMM ssse3
+WARP_AFFINE_8X8
+
+INIT_XMM sse4
+WARP_AFFINE_8X8
diff --git a/media/libdav1d/src/src/x86/msac.asm b/media/libdav1d/src/src/x86/msac.asm
new file mode 100644
index 0000000000..4156efe914
--- /dev/null
+++ b/media/libdav1d/src/src/x86/msac.asm
@@ -0,0 +1,671 @@
+; Copyright © 2019, VideoLAN and dav1d authors
+; Copyright © 2019, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 64 ; avoids cacheline splits
+
+min_prob:  dw 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0
+pw_0xff00: times 8 dw 0xff00
+pw_32:     times 8 dw 32
+
+%if ARCH_X86_64
+%define resp   resq
+%define movp   movq
+%define c_shuf q3333
+%macro DECODE_SYMBOL_ADAPT_INIT 0-1
+%endmacro
+%else
+%define resp   resd
+%define movp   movd
+%define c_shuf q1111
+%macro DECODE_SYMBOL_ADAPT_INIT 0-1 0 ; hi_tok
+    mov            t0, r0m
+    mov            t1, r1m
+%if %1 == 0
+    mov            t2, r2m
+%endif
+%if STACK_ALIGNMENT >= 16
+    sub           esp, 40-%1*4
+%else
+    mov           eax, esp
+    and           esp, ~15
+    sub           esp, 40-%1*4
+    mov         [esp], eax
+%endif
+%endmacro
+%endif
+
+struc msac
+    .buf:        resp 1
+    .end:        resp 1
+    .dif:        resp 1
+    .rng:        resd 1
+    .cnt:        resd 1
+    .update_cdf: resd 1
+endstruc
+
+%define m(x, y) mangle(private_prefix %+ _ %+ x %+ y)
+
+SECTION .text
+
+%if WIN64
+DECLARE_REG_TMP 0, 1, 2, 3, 4, 5, 7, 3, 8
+%define buf rsp+stack_offset+8 ; shadow space
+%elif UNIX64
+DECLARE_REG_TMP 0, 1, 2, 3, 4, 5, 7, 0, 8
+%define buf rsp-40 ; red zone
+%else
+DECLARE_REG_TMP 2, 3, 4, 1, 5, 6, 5, 2, 3
+%define buf esp+8
+%endif
+
+INIT_XMM sse2
+cglobal msac_decode_symbol_adapt4, 0, 6, 6
+    DECODE_SYMBOL_ADAPT_INIT
+    LEA           rax, pw_0xff00
+    movd           m2, [t0+msac.rng]
+    movq           m1, [t1]
+    movp           m3, [t0+msac.dif]
+    mov           t3d, [t0+msac.update_cdf]
+    mov           t4d, t2d
+    not            t2     ; -(n_symbols + 1)
+    pshuflw        m2, m2, q0000
+    movd     [buf+12], m2
+    pand           m2, [rax]
+    mova           m0, m1
+    psrlw          m1, 6
+    psllw          m1, 7
+    pmulhuw        m1, m2
+    movq           m2, [rax+t2*2]
+    pshuflw        m3, m3, c_shuf
+    paddw          m1, m2
+    mova     [buf+16], m1
+    psubusw        m1, m3
+    pxor           m2, m2
+    pcmpeqw        m1, m2 ; c >= v
+    pmovmskb      eax, m1
+    test          t3d, t3d
+    jz .renorm ; !allow_update_cdf
+
+; update_cdf:
+    movzx         t3d, word [t1+t4*2] ; count
+    pcmpeqw        m2, m2
+    mov           t2d, t3d
+    shr           t3d, 4
+    cmp           t4d, 3
+    sbb           t3d, -5 ; (count >> 4) + (n_symbols > 2) + 4
+    cmp           t2d, 32
+    adc           t2d, 0  ; count + (count < 32)
+    movd           m3, t3d
+    pavgw          m2, m1 ; i >= val ? -1 : 32768
+    psubw          m2, m0 ; for (i = 0; i < val; i++)
+    psubw          m0, m1 ;     cdf[i] += (32768 - cdf[i]) >> rate;
+    psraw          m2, m3 ; for (; i < n_symbols; i++)
+    paddw          m0, m2 ;     cdf[i] += ((  -1 - cdf[i]) >> rate) + 1;
+    movq         [t1], m0
+    mov     [t1+t4*2], t2w
+
+.renorm:
+    tzcnt         eax, eax
+    mov            t4, [t0+msac.dif]
+    movzx         t1d, word [buf+rax+16] ; v
+    movzx         t2d, word [buf+rax+14] ; u
+    shr           eax, 1
+.renorm2:
+%if ARCH_X86_64 == 0
+%if STACK_ALIGNMENT >= 16
+    add           esp, 40
+%else
+    mov           esp, [esp]
+%endif
+%endif
+    sub           t2d, t1d ; rng
+    shl            t1, gprsize*8-16
+    sub            t4, t1  ; dif - v
+.renorm3:
+    mov           t1d, [t0+msac.cnt]
+    movifnidn      t7, t0
+.renorm4:
+    bsr           ecx, t2d
+    xor           ecx, 15  ; d
+.renorm5:
+    shl           t2d, cl
+    shl            t4, cl
+    mov [t7+msac.rng], t2d
+    sub           t1d, ecx
+    jae .end ; no refill required
+
+; refill:
+%if ARCH_X86_64 == 0
+    push           t5
+%endif
+    mov            t2, [t7+msac.buf]
+    mov            t5, [t7+msac.end]
+    lea           rcx, [t2+gprsize]
+    sub           rcx, t5
+    ja .refill_eob
+    mov            t5, [t2]
+    lea           ecx, [t1+16-gprsize*8]
+    not            t5
+    bswap          t5
+    shr            t5, cl
+    neg           ecx
+    shr           ecx, 3 ; num_bytes_read
+    or             t4, t5
+.refill_end:
+    add            t2, rcx
+    lea           t1d, [t1+rcx*8] ; cnt += num_bits_read
+    mov [t7+msac.buf], t2
+.refill_end2:
+%if ARCH_X86_64 == 0
+    pop            t5
+%endif
+.end:
+    mov [t7+msac.cnt], t1d
+    mov [t7+msac.dif], t4
+    RET
+.pad_with_ones:
+    lea           ecx, [t1-16]
+%if ARCH_X86_64
+    ror           rcx, cl
+%else
+    shr           ecx, cl
+%endif
+    or             t4, rcx
+    jmp .refill_end2
+.refill_eob: ; avoid overreading the input buffer
+    cmp            t2, t5
+    jae .pad_with_ones ; eob reached
+    ; We can safely do a register-sized load of the last bytes of the buffer
+    ; as this code is only reached if the msac buffer size is >= gprsize.
+    mov            t5, [t5-gprsize]
+    shl           ecx, 3
+    shr            t5, cl
+    lea           ecx, [t1+16-gprsize*8]
+    not            t5
+    bswap          t5
+    shr            t5, cl
+    neg           ecx
+    or             t4, t5
+    mov           t5d, [t7+msac.end]
+    shr           ecx, 3
+    sub           t5d, t2d ; num_bytes_left
+    cmp           ecx, t5d
+    cmovae        ecx, t5d ; num_bytes_read
+    jmp .refill_end
+
+cglobal msac_decode_symbol_adapt8, 0, 6, 6
+    DECODE_SYMBOL_ADAPT_INIT
+    LEA           rax, pw_0xff00
+    movd           m2, [t0+msac.rng]
+    mova           m1, [t1]
+    movp           m3, [t0+msac.dif]
+    mov           t3d, [t0+msac.update_cdf]
+    mov           t4d, t2d
+    not            t2
+    pshuflw        m2, m2, q0000
+    movd     [buf+12], m2
+    punpcklqdq     m2, m2
+    mova           m0, m1
+    psrlw          m1, 6
+    pand           m2, [rax]
+    psllw          m1, 7
+    pmulhuw        m1, m2
+    movu           m2, [rax+t2*2]
+    pshuflw        m3, m3, c_shuf
+    paddw          m1, m2
+    punpcklqdq     m3, m3
+    mova     [buf+16], m1
+    psubusw        m1, m3
+    pxor           m2, m2
+    pcmpeqw        m1, m2
+    pmovmskb      eax, m1
+    test          t3d, t3d
+    jz m(msac_decode_symbol_adapt4, SUFFIX).renorm
+    movzx         t3d, word [t1+t4*2]
+    pcmpeqw        m2, m2
+    mov           t2d, t3d
+    shr           t3d, 4
+    cmp           t4d, 3 ; may be called with n_symbols <= 2
+    sbb           t3d, -5
+    cmp           t2d, 32
+    adc           t2d, 0
+    movd           m3, t3d
+    pavgw          m2, m1
+    psubw          m2, m0
+    psubw          m0, m1
+    psraw          m2, m3
+    paddw          m0, m2
+    mova         [t1], m0
+    mov     [t1+t4*2], t2w
+    jmp m(msac_decode_symbol_adapt4, SUFFIX).renorm
+
+cglobal msac_decode_symbol_adapt16, 0, 6, 6
+    DECODE_SYMBOL_ADAPT_INIT
+    LEA           rax, pw_0xff00
+    movd           m4, [t0+msac.rng]
+    mova           m2, [t1]
+    mova           m3, [t1+16]
+    movp           m5, [t0+msac.dif]
+    mov           t3d, [t0+msac.update_cdf]
+    mov           t4d, t2d
+    not            t2
+%if WIN64
+    sub           rsp, 48 ; need 36 bytes, shadow space is only 32
+%endif
+    pshuflw        m4, m4, q0000
+    movd      [buf-4], m4
+    punpcklqdq     m4, m4
+    mova           m0, m2
+    psrlw          m2, 6
+    mova           m1, m3
+    psrlw          m3, 6
+    pand           m4, [rax]
+    psllw          m2, 7
+    psllw          m3, 7
+    pmulhuw        m2, m4
+    pmulhuw        m3, m4
+    movu           m4, [rax+t2*2]
+    pshuflw        m5, m5, c_shuf
+    paddw          m2, m4
+    psubw          m4, [rax-pw_0xff00+pw_32]
+    punpcklqdq     m5, m5
+    paddw          m3, m4
+    mova        [buf], m2
+    psubusw        m2, m5
+    mova     [buf+16], m3
+    psubusw        m3, m5
+    pxor           m4, m4
+    pcmpeqw        m2, m4
+    pcmpeqw        m3, m4
+    packsswb       m5, m2, m3
+    pmovmskb      eax, m5
+    test          t3d, t3d
+    jz .renorm
+    movzx         t3d, word [t1+t4*2]
+    pcmpeqw        m4, m4
+    mova           m5, m4
+    lea           t2d, [t3+80] ; only support n_symbols > 2
+    shr           t2d, 4
+    cmp           t3d, 32
+    adc           t3d, 0
+    pavgw          m4, m2
+    pavgw          m5, m3
+    psubw          m4, m0
+    psubw          m0, m2
+    movd           m2, t2d
+    psubw          m5, m1
+    psubw          m1, m3
+    psraw          m4, m2
+    psraw          m5, m2
+    paddw          m0, m4
+    paddw          m1, m5
+    mova         [t1], m0
+    mova      [t1+16], m1
+    mov     [t1+t4*2], t3w
+.renorm:
+    tzcnt         eax, eax
+    mov            t4, [t0+msac.dif]
+    movzx         t1d, word [buf+rax*2]
+    movzx         t2d, word [buf+rax*2-2]
+%if WIN64
+    add           rsp, 48
+%endif
+    jmp m(msac_decode_symbol_adapt4, SUFFIX).renorm2
+
+cglobal msac_decode_bool_adapt, 0, 6, 0
+    movifnidn      t1, r1mp
+    movifnidn      t0, r0mp
+    movzx         eax, word [t1]
+    movzx         t3d, byte [t0+msac.rng+1]
+    mov            t4, [t0+msac.dif]
+    mov           t2d, [t0+msac.rng]
+%if ARCH_X86_64
+    mov           t5d, eax
+%endif
+    and           eax, ~63
+    imul          eax, t3d
+%if UNIX64
+    mov            t6, t4
+%endif
+    shr           eax, 7
+    add           eax, 4            ; v
+    mov           t3d, eax
+    shl           rax, gprsize*8-16 ; vw
+    sub           t2d, t3d          ; r - v
+    sub            t4, rax          ; dif - vw
+    setb           al
+    cmovb         t2d, t3d
+    mov           t3d, [t0+msac.update_cdf]
+%if UNIX64
+    cmovb          t4, t6
+%else
+    cmovb          t4, [t0+msac.dif]
+%endif
+%if ARCH_X86_64 == 0
+    movzx         eax, al
+%endif
+    test          t3d, t3d
+    jz m(msac_decode_symbol_adapt4, SUFFIX).renorm3
+%if UNIX64 == 0
+    push           t6
+%endif
+    movzx         t6d, word [t1+2]
+%if ARCH_X86_64 == 0
+    push           t5
+    movzx         t5d, word [t1]
+%endif
+    movifnidn      t7, t0
+    lea           ecx, [t6+64]
+    cmp           t6d, 32
+    adc           t6d, 0
+    mov        [t1+2], t6w
+    imul          t6d, eax, -32769
+    shr           ecx, 4   ; rate
+    add           t6d, t5d ; if (bit)
+    sub           t5d, eax ;     cdf[0] -= ((cdf[0] - 32769) >> rate) + 1;
+    sar           t6d, cl  ; else
+    sub           t5d, t6d ;     cdf[0] -= cdf[0] >> rate;
+    mov          [t1], t5w
+%if WIN64
+    mov           t1d, [t7+msac.cnt]
+    pop            t6
+    jmp m(msac_decode_symbol_adapt4, SUFFIX).renorm4
+%else
+%if ARCH_X86_64 == 0
+    pop            t5
+    pop            t6
+%endif
+    jmp m(msac_decode_symbol_adapt4, SUFFIX).renorm3
+%endif
+
+cglobal msac_decode_bool_equi, 0, 6, 0
+    movifnidn      t0, r0mp
+    mov           t1d, [t0+msac.rng]
+    mov            t4, [t0+msac.dif]
+    mov           t2d, t1d
+    mov           t1b, 8
+    mov            t3, t4
+    mov           eax, t1d
+    shr           t1d, 1            ; v
+    shl           rax, gprsize*8-17 ; vw
+    sub           t2d, t1d          ; r - v
+    sub            t4, rax          ; dif - vw
+    cmovb         t2d, t1d
+    mov           t1d, [t0+msac.cnt]
+    cmovb          t4, t3
+    movifnidn      t7, t0
+    mov           ecx, 0xbfff
+    setb           al ; the upper 32 bits contains garbage but that's OK
+    sub           ecx, t2d
+    ; In this case of this function, (d =) 16 - clz(v) = 2 - (v >> 14)
+    ;   i.e. (0 <= d <= 2) and v < (3 << 14)
+    shr           ecx, 14           ; d
+%if ARCH_X86_64 == 0
+    movzx         eax, al
+%endif
+    jmp m(msac_decode_symbol_adapt4, SUFFIX).renorm5
+
+cglobal msac_decode_bool, 0, 6, 0
+    movifnidn      t0, r0mp
+    movifnidn     t1d, r1m
+    movzx         eax, byte [t0+msac.rng+1] ; r >> 8
+    mov            t4, [t0+msac.dif]
+    mov           t2d, [t0+msac.rng]
+    and           t1d, ~63
+    imul          eax, t1d
+    mov            t3, t4
+    shr           eax, 7
+    add           eax, 4            ; v
+    mov           t1d, eax
+    shl           rax, gprsize*8-16 ; vw
+    sub           t2d, t1d          ; r - v
+    sub            t4, rax          ; dif - vw
+    cmovb         t2d, t1d
+    cmovb          t4, t3
+    setb           al
+%if ARCH_X86_64 == 0
+    movzx         eax, al
+%endif
+    jmp m(msac_decode_symbol_adapt4, SUFFIX).renorm3
+
+%macro HI_TOK 1 ; update_cdf
+%if ARCH_X86_64 == 0
+    mov           eax, -24
+%endif
+%%loop:
+%if %1
+    movzx         t2d, word [t1+3*2]
+%endif
+    mova           m1, m0
+    pshuflw        m2, m2, q0000
+    psrlw          m1, 6
+    movd     [buf+12], m2
+    pand           m2, m4
+    psllw          m1, 7
+    pmulhuw        m1, m2
+%if ARCH_X86_64 == 0
+    add           eax, 5
+    mov       [buf+8], eax
+%endif
+    pshuflw        m3, m3, c_shuf
+    paddw          m1, m5
+    movq     [buf+16], m1
+    psubusw        m1, m3
+    pxor           m2, m2
+    pcmpeqw        m1, m2
+    pmovmskb      eax, m1
+%if %1
+    lea           ecx, [t2+80]
+    pcmpeqw        m2, m2
+    shr           ecx, 4
+    cmp           t2d, 32
+    adc           t2d, 0
+    movd           m3, ecx
+    pavgw          m2, m1
+    psubw          m2, m0
+    psubw          m0, m1
+    psraw          m2, m3
+    paddw          m0, m2
+    movq         [t1], m0
+    mov      [t1+3*2], t2w
+%endif
+    tzcnt         eax, eax
+    movzx         ecx, word [buf+rax+16]
+    movzx         t2d, word [buf+rax+14]
+%if ARCH_X86_64
+    add           t6d, 5
+%endif
+    sub           eax, 5   ; setup for merging the tok_br and tok branches
+    sub           t2d, ecx
+    shl           rcx, gprsize*8-16
+    sub            t4, rcx
+    bsr           ecx, t2d
+    xor           ecx, 15
+    shl           t2d, cl
+    shl            t4, cl
+    movd           m2, t2d
+    mov [t7+msac.rng], t2d
+    sub           t5d, ecx
+    jae %%end
+%if UNIX64 == 0
+    push           t8
+%endif
+    mov            t2, [t7+msac.buf]
+    mov            t8, [t7+msac.end]
+    lea           rcx, [t2+gprsize]
+    sub           rcx, t8
+    ja %%refill_eob
+    mov            t8, [t2]
+    lea           ecx, [t5+16-gprsize*8]
+    not            t8
+    bswap          t8
+    shr            t8, cl
+    neg           ecx
+    shr           ecx, 3
+    or             t4, t8
+%%refill_end:
+    add            t2, rcx
+    lea           t5d, [t5+rcx*8]
+    mov [t7+msac.buf], t2
+%%refill_end2:
+%if UNIX64 == 0
+    pop            t8
+%endif
+%%end:
+    movp           m3, t4
+%if ARCH_X86_64
+    add           t6d, eax ; CF = tok_br < 3 || tok == 15
+    jnc %%loop
+    lea           eax, [t6+30]
+%else
+    add           eax, [buf+8]
+    jnc %%loop
+    add           eax, 30
+%if STACK_ALIGNMENT >= 16
+    add           esp, 36
+%else
+    mov           esp, [esp]
+%endif
+%endif
+    mov [t7+msac.dif], t4
+    shr           eax, 1
+    mov [t7+msac.cnt], t5d
+    RET
+%%pad_with_ones:
+    ; ensure that dif is padded with at least 15 bits of ones at the end
+    lea           ecx, [t5-16]
+%if ARCH_X86_64
+    ror           rcx, cl
+%else
+    shr           ecx, cl
+%endif
+    or             t4, rcx
+    jmp %%refill_end2
+%%refill_eob:
+    cmp            t2, t8
+    jae %%pad_with_ones
+    mov            t8, [t8-gprsize]
+    shl           ecx, 3
+    shr            t8, cl
+    lea           ecx, [t5+16-gprsize*8]
+    not            t8
+    bswap          t8
+    shr            t8, cl
+    neg           ecx
+    or             t4, t8
+    mov           t8d, [t7+msac.end]
+    shr           ecx, 3
+    sub           t8d, t2d
+    cmp           ecx, t8d
+    cmovae        ecx, t8d
+    jmp %%refill_end
+%endmacro
+
+cglobal msac_decode_hi_tok, 0, 7 + ARCH_X86_64, 6
+    DECODE_SYMBOL_ADAPT_INIT 1
+%if ARCH_X86_64 == 0 && PIC
+    LEA            t2, min_prob+12*2
+    %define base t2-(min_prob+12*2)
+%else
+    %define base 0
+%endif
+    movq           m0, [t1]
+    movd           m2, [t0+msac.rng]
+    mov           eax, [t0+msac.update_cdf]
+    movq           m4, [base+pw_0xff00]
+    movp           m3, [t0+msac.dif]
+    movq           m5, [base+min_prob+12*2]
+    mov            t4, [t0+msac.dif]
+    mov           t5d, [t0+msac.cnt]
+%if ARCH_X86_64
+    mov           t6d, -24
+%endif
+    movifnidn      t7, t0
+    test          eax, eax
+    jz .no_update_cdf
+    HI_TOK          1
+.no_update_cdf:
+    HI_TOK          0
+
+%if ARCH_X86_64
+INIT_YMM avx2
+cglobal msac_decode_symbol_adapt16, 3, 6, 6
+    lea           rax, [pw_0xff00]
+    vpbroadcastw   m2, [t0+msac.rng]
+    mova           m0, [t1]
+    vpbroadcastw   m3, [t0+msac.dif+6]
+    vbroadcasti128 m4, [rax]
+    mov           t3d, [t0+msac.update_cdf]
+    mov           t4d, t2d
+    not            t2
+    mov            r5, rsp
+%if WIN64
+    and           rsp, ~31
+    sub           rsp, 40
+%else
+    and            r5, ~31
+    %define buf r5-32
+%endif
+    psrlw          m1, m0, 6
+    movd      [buf-4], xm2
+    pand           m2, m4
+    psllw          m1, 7
+    pmulhuw        m1, m2
+    paddw          m1, [rax+t2*2]
+    mova        [buf], m1
+    pmaxuw         m1, m3
+    pcmpeqw        m1, m3
+    pmovmskb      eax, m1
+    test          t3d, t3d
+    jz .renorm
+    movzx         t3d, word [t1+t4*2]
+    pcmpeqw        m2, m2
+    lea           t2d, [t3+80]
+    shr           t2d, 4
+    cmp           t3d, 32
+    adc           t3d, 0
+    movd          xm3, t2d
+    pavgw          m2, m1
+    psubw          m2, m0
+    psubw          m0, m1
+    psraw          m2, xm3
+    paddw          m0, m2
+    mova         [t1], m0
+    mov     [t1+t4*2], t3w
+.renorm:
+    tzcnt         eax, eax
+    mov            t4, [t0+msac.dif]
+    movzx         t1d, word [buf+rax-0]
+    movzx         t2d, word [buf+rax-2]
+    shr           eax, 1
+%if WIN64
+    mov           rsp, r5
+%endif
+    vzeroupper
+    jmp m(msac_decode_symbol_adapt4, _sse2).renorm2
+%endif
diff --git a/media/libdav1d/src/src/x86/msac.h b/media/libdav1d/src/src/x86/msac.h
new file mode 100644
index 0000000000..0bb632fb31
--- /dev/null
+++ b/media/libdav1d/src/src/x86/msac.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_SRC_X86_MSAC_H
+#define DAV1D_SRC_X86_MSAC_H
+
+#include "src/cpu.h"
+
+unsigned dav1d_msac_decode_symbol_adapt4_sse2(MsacContext *s, uint16_t *cdf,
+                                              size_t n_symbols);
+unsigned dav1d_msac_decode_symbol_adapt8_sse2(MsacContext *s, uint16_t *cdf,
+                                              size_t n_symbols);
+unsigned dav1d_msac_decode_symbol_adapt16_sse2(MsacContext *s, uint16_t *cdf,
+                                               size_t n_symbols);
+unsigned dav1d_msac_decode_symbol_adapt16_avx2(MsacContext *s, uint16_t *cdf,
+                                               size_t n_symbols);
+unsigned dav1d_msac_decode_bool_adapt_sse2(MsacContext *s, uint16_t *cdf);
+unsigned dav1d_msac_decode_bool_equi_sse2(MsacContext *s);
+unsigned dav1d_msac_decode_bool_sse2(MsacContext *s, unsigned f);
+unsigned dav1d_msac_decode_hi_tok_sse2(MsacContext *s, uint16_t *cdf);
+
+#if ARCH_X86_64 || defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+#define dav1d_msac_decode_symbol_adapt4  dav1d_msac_decode_symbol_adapt4_sse2
+#define dav1d_msac_decode_symbol_adapt8  dav1d_msac_decode_symbol_adapt8_sse2
+#define dav1d_msac_decode_hi_tok         dav1d_msac_decode_hi_tok_sse2
+#endif
+
+#define dav1d_msac_decode_bool_adapt     dav1d_msac_decode_bool_adapt_sse2
+#define dav1d_msac_decode_bool_equi      dav1d_msac_decode_bool_equi_sse2
+#define dav1d_msac_decode_bool           dav1d_msac_decode_bool_sse2
+
+#if ARCH_X86_64
+#define dav1d_msac_decode_symbol_adapt16(ctx, cdf, symb) ((ctx)->symbol_adapt16(ctx, cdf, symb))
+
+static ALWAYS_INLINE void msac_init_x86(MsacContext *const s) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (flags & DAV1D_X86_CPU_FLAG_SSE2) {
+        s->symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_sse2;
+    }
+
+    if (flags & DAV1D_X86_CPU_FLAG_AVX2) {
+        s->symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_avx2;
+    }
+}
+
+#elif defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+#define dav1d_msac_decode_symbol_adapt16 dav1d_msac_decode_symbol_adapt16_sse2
+#endif
+
+#endif /* DAV1D_SRC_X86_MSAC_H */
diff --git a/media/libdav1d/src/src/x86/pal.asm b/media/libdav1d/src/src/x86/pal.asm
new file mode 100644
index 0000000000..92075b9ba8
--- /dev/null
+++ b/media/libdav1d/src/src/x86/pal.asm
@@ -0,0 +1,641 @@
+; Copyright © 2023, VideoLAN and dav1d authors
+; Copyright © 2023, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 64
+
+const pb_0to63,  db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
+%if ARCH_X86_64
+                 db 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+                 db 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
+                 db 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
+%endif
+pal_idx_w8_padh: db  0,  1,  2,  3,  3,  3,  3,  3,  8,  9, 10, 11, 11, 11, 11, 11
+
+pb_1_16: times 4 db  1, 16
+%if ARCH_X86_64
+pb_32:   times 4 db 32
+%endif
+
+%macro JMP_TABLE 2-*
+    %xdefine %1_table (%%table - 2*4)
+    %xdefine %%base mangle(private_prefix %+ _%1)
+    %%table:
+    %rep %0 - 1
+        dd %%base %+ .w%2 - (%%table - 2*4)
+        %rotate 1
+    %endrep
+%endmacro
+
+JMP_TABLE pal_idx_finish_ssse3,     4, 8, 16, 32, 64
+%if ARCH_X86_64
+JMP_TABLE pal_idx_finish_avx2,      4, 8, 16, 32, 64
+JMP_TABLE pal_idx_finish_avx512icl, 4, 8, 16, 32, 64
+%endif
+
+SECTION .text
+
+INIT_XMM ssse3
+cglobal pal_idx_finish, 2, 7, 6, dst, src, bw, bh, w, h
+%define base r6-pal_idx_finish_ssse3_table
+    LEA                  r6, pal_idx_finish_ssse3_table
+    tzcnt               bwd, bwm
+    movifnidn           bhd, bhm
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    movsxd              bwq, [r6+bwq*4]
+    movddup              m3, [base+pb_1_16]
+    add                 bwq, r6
+    sub                 bhd, hd
+    jmp                 bwq
+.w4:
+    mova                 m0, [srcq]
+    add                srcq, 16
+    pmaddubsw            m0, m3
+    packuswb             m0, m0
+    movq             [dstq], m0
+    add                dstq, 8
+    sub                  hd, 4
+    jg .w4
+    test                bhd, bhd
+    jz .w4_end
+    pshuflw              m0, m0, q3333
+.w4_padv:
+    movq             [dstq], m0
+    add                dstq, 8
+    sub                 bhd, 4
+    jg .w4_padv
+.w4_end:
+    RET
+.w8_padh:
+    pshufb               m0, m2
+    pshufb               m1, m2
+    jmp .w8_main
+.w8:
+    mova                 m2, [base+pal_idx_w8_padh]
+.w8_loop:
+    mova                 m0, [srcq+16*0]
+    mova                 m1, [srcq+16*1]
+    cmp                  wd, 8
+    jl .w8_padh
+.w8_main:
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    add                srcq, 16*2
+    packuswb             m0, m1
+    movu             [dstq], m0
+    add                dstq, 16
+    sub                  hd, 4
+    jg .w8_loop
+    test                bhd, bhd
+    jz .w8_end
+    pshufd               m0, m0, q3333
+.w8_padv:
+    movu             [dstq], m0
+    add                dstq, 16
+    sub                 bhd, 4
+    jg .w8_padv
+.w8_end:
+    RET
+.w16_padh:
+    pshufb               m0, m4
+    pshufb               m1, m4
+    jmp .w16_main
+.w16:
+    cmp                  wd, 16
+    je .w16_loop
+    call .setup_padh
+.w16_loop:
+    mova                 m0, [srcq+16*0]
+    mova                 m1, [srcq+16*1]
+    cmp                  wd, 16
+    jl .w16_padh
+.w16_main:
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    add                srcq, 16*2
+    packuswb             m0, m1
+    movu             [dstq], m0
+    add                dstq, 16
+    sub                  hd, 2
+    jg .w16_loop
+    test                bhd, bhd
+    jz .w16_end
+    punpckhqdq           m0, m0
+.w16_padv:
+    movu        [dstq+16*0], m0
+    movu        [dstq+16*1], m0
+    add                dstq, 16*2
+    sub                 bhd, 4
+    jg .w16_padv
+.w16_end:
+    RET
+.w32_padh:
+    cmp                  wd, 16
+    jg .w32_padh2
+    pshufb               m1, m0, m5
+    pshufb               m0, m4
+    jmp .w32_main
+.w32_padh2:
+    pshufb               m1, m4
+    jmp .w32_main
+.w32:
+    cmp                  wd, 32
+    je .w32_loop
+    call .setup_padh
+.w32_loop:
+    mova                 m0, [srcq+16*0]
+    mova                 m1, [srcq+16*1]
+    cmp                  wd, 32
+    jl .w32_padh
+.w32_main:
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    add                srcq, 16*2
+    packuswb             m0, m1
+    movu             [dstq], m0
+    add                dstq, 16
+    dec                  hd
+    jg .w32_loop
+    test                bhd, bhd
+    jz .w32_end
+.w32_padv:
+    movu        [dstq+16*0], m0
+    movu        [dstq+16*1], m0
+    movu        [dstq+16*2], m0
+    movu        [dstq+16*3], m0
+    add                dstq, 16*4
+    sub                 bhd, 4
+    jg .w32_padv
+.w32_end:
+    RET
+.w64_padh:
+    cmp                  wd, 16
+    jg .w64_padh2
+    pshufb               m1, m0, m5
+    pshufb               m0, m4
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    packuswb             m0, m1
+    packuswb             m1, m1
+    jmp .w64_main
+.w64_padh2:
+    pshufb               m1, m4
+    pmaddubsw            m0, m3
+    pmaddubsw            m2, m1, m3
+    pshufb               m1, m5
+    pmaddubsw            m1, m3
+    packuswb             m0, m2
+    packuswb             m1, m1
+    jmp .w64_main
+.w64_padh3:
+    cmp                  wd, 48
+    jg .w64_padh4
+    pshufb               m2, m1, m5
+    pshufb               m1, m4
+    jmp .w64_main2
+.w64_padh4:
+    pshufb               m2, m4
+    jmp .w64_main2
+.w64:
+    cmp                  wd, 64
+    je .w64_loop
+    call .setup_padh
+.w64_loop:
+    mova                 m0, [srcq+16*0]
+    mova                 m1, [srcq+16*1]
+    cmp                  wd, 32
+    jle .w64_padh
+    pmaddubsw            m0, m3
+    pmaddubsw            m1, m3
+    packuswb             m0, m1
+    mova                 m1, [srcq+16*2]
+    mova                 m2, [srcq+16*3]
+    cmp                  wd, 64
+    jl .w64_padh3
+.w64_main2:
+    pmaddubsw            m1, m3
+    pmaddubsw            m2, m3
+    packuswb             m1, m2
+.w64_main:
+    add                srcq, 16*4
+    movu        [dstq+16*0], m0
+    movu        [dstq+16*1], m1
+    add                dstq, 16*2
+    dec                  hd
+    jg .w64_loop
+    test                bhd, bhd
+    jz .w64_end
+.w64_padv:
+    movu        [dstq+16*0], m0
+    movu        [dstq+16*1], m1
+    movu        [dstq+16*2], m0
+    movu        [dstq+16*3], m1
+    add                dstq, 16*4
+    sub                 bhd, 2
+    jg .w64_padv
+.w64_end:
+    RET
+.setup_padh:
+    mova                 m4, [base+pb_0to63]
+    lea                 r6d, [wq-1]
+    and                 r6d, 15
+    movd                 m5, r6d
+    pxor                 m0, m0
+    pshufb               m5, m0
+    pminub               m4, m5
+    ret
+
+%if ARCH_X86_64
+
+INIT_YMM avx2
+cglobal pal_idx_finish, 4, 7, 5, dst, src, bw, bh, w, h
+%define base r6-pal_idx_finish_avx2_table
+    lea                  r6, [pal_idx_finish_avx2_table]
+    tzcnt               bwd, bwd
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    movsxd              bwq, [r6+bwq*4]
+    vpbroadcastd         m2, [base+pb_1_16]
+    dec                  wd
+    add                 bwq, r6
+    sub                 bhd, hd
+    jmp                 bwq
+.w4:
+    mova                xm0, [srcq]
+    add                srcq, 16
+    pmaddubsw           xm0, xm2
+    packuswb            xm0, xm0
+    movq             [dstq], xm0
+    add                dstq, 8
+    sub                  hd, 4
+    jg .w4
+    test                bhd, bhd
+    jz .w4_end
+    pshuflw             xm0, xm0, q3333
+.w4_padv:
+    movq             [dstq], xm0
+    add                dstq, 8
+    sub                 bhd, 4
+    jg .w4_padv
+.w4_end:
+    RET
+.w8_padh:
+    pshufb              xm0, xm3
+    pshufb              xm1, xm3
+    jmp .w8_main
+.w8:
+    mova                xm3, [base+pal_idx_w8_padh]
+.w8_loop:
+    mova                xm0, [srcq+16*0]
+    mova                xm1, [srcq+16*1]
+    cmp                  wd, 7
+    jl .w8_padh
+.w8_main:
+    pmaddubsw           xm0, xm2
+    pmaddubsw           xm1, xm2
+    add                srcq, 16*2
+    packuswb            xm0, xm1
+    movu             [dstq], xm0
+    add                dstq, 16
+    sub                  hd, 4
+    jg .w8_loop
+    test                bhd, bhd
+    jz .w8_end
+    pshufd              xm0, xm0, q3333
+.w8_padv:
+    movu             [dstq], xm0
+    add                dstq, 16
+    sub                 bhd, 4
+    jg .w8_padv
+.w8_end:
+    RET
+.w16_padh:
+    pshufb               m0, m3
+    pshufb               m1, m3
+    jmp .w16_main
+.w16:
+    cmp                  wd, 15
+    je .w16_loop
+    vbroadcasti128       m0, [base+pb_0to63]
+    movd                xm3, wd
+    vpbroadcastb         m3, xm3
+    pminub               m3, m0
+.w16_loop:
+    mova                 m0, [srcq+32*0]
+    mova                 m1, [srcq+32*1]
+    cmp                  wd, 15
+    jl .w16_padh
+.w16_main:
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    add                srcq, 32*2
+    packuswb             m0, m1
+    vpermq               m1, m0, q3120
+    movu             [dstq], m1
+    add                dstq, 32
+    sub                  hd, 4
+    jg .w16_loop
+    test                bhd, bhd
+    jz .w16_end
+    vpermq               m0, m0, q3333
+.w16_padv:
+    movu             [dstq], m0
+    add                dstq, 32
+    sub                 bhd, 4
+    jg .w16_padv
+.w16_end:
+    RET
+.w32_padh:
+    cmp                  wd, 15
+    jg .w32_padh2
+    vinserti128          m0, xm0, 1
+    vinserti128          m1, xm1, 1
+.w32_padh2:
+    pshufb               m0, m3
+    pshufb               m1, m3
+    jmp .w32_main
+.w32:
+    cmp                  wd, 31
+    je .w32_loop
+    movd                xm3, wd
+    vpbroadcastb         m3, xm3
+    pminub               m3, [base+pb_0to63]
+.w32_loop:
+    mova                 m0, [srcq+32*0]
+    mova                 m1, [srcq+32*1]
+    cmp                  wd, 31
+    jl .w32_padh
+.w32_main:
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    add                srcq, 32*2
+    packuswb             m0, m1
+    vpermq               m1, m0, q3120
+    movu             [dstq], m1
+    add                dstq, 32
+    sub                  hd, 2
+    jg .w32_loop
+    test                bhd, bhd
+    jz .w32_end
+    vpermq               m0, m0, q3131
+.w32_padv:
+    movu        [dstq+32*0], m0
+    movu        [dstq+32*1], m0
+    add                dstq, 32*2
+    sub                 bhd, 4
+    jg .w32_padv
+.w32_end:
+    RET
+.w64_padh:
+    cmp                  wd, 15
+    jg .w64_padh2
+    vinserti128          m1, m0, xm0, 1
+    pshufb               m0, m1, m3
+    pshufb               m1, m4
+    jmp .w64_main
+.w64_padh2:
+    cmp                  wd, 31
+    jg .w64_padh3
+    vperm2i128           m1, m0, m0, 0x11
+    pshufb               m0, m3
+    pshufb               m1, m4
+    jmp .w64_main
+.w64_padh3:
+    cmp                  wd, 47
+    jg .w64_padh4
+    vinserti128          m1, xm1, 1
+.w64_padh4:
+    pshufb               m1, m3
+    jmp .w64_main
+.w64:
+    cmp                  wd, 63
+    je .w64_loop
+    mov                 r6d, wd
+    and                 r6d, 31
+    movd                xm4, r6d
+    vpbroadcastb         m4, xm4
+    pminub               m3, m4, [pb_0to63]
+.w64_loop:
+    mova                 m0, [srcq+32*0]
+    mova                 m1, [srcq+32*1]
+    cmp                  wd, 63
+    jl .w64_padh
+.w64_main:
+    pmaddubsw            m0, m2
+    pmaddubsw            m1, m2
+    add                srcq, 32*2
+    packuswb             m0, m1
+    vpermq               m0, m0, q3120
+    movu             [dstq], m0
+    add                dstq, 32
+    dec                  hd
+    jg .w64_loop
+    test                bhd, bhd
+    jz .w64_end
+.w64_padv:
+    movu        [dstq+32*0], m0
+    movu        [dstq+32*1], m0
+    movu        [dstq+32*2], m0
+    movu        [dstq+32*3], m0
+    add                dstq, 32*4
+    sub                 bhd, 4
+    jg .w64_padv
+.w64_end:
+    RET
+
+INIT_ZMM avx512icl
+cglobal pal_idx_finish, 4, 7, 7, dst, src, bw, bh, w, h
+%define base r6-pal_idx_finish_avx512icl_table
+    lea                  r6, [pal_idx_finish_avx512icl_table]
+    tzcnt               bwd, bwd
+    movifnidn            wd, wm
+    movifnidn            hd, hm
+    movsxd              bwq, [r6+bwq*4]
+    vpbroadcastd         m4, [base+pb_1_16]
+    dec                  wd
+    add                 bwq, r6
+    sub                 bhd, hd
+    jmp                 bwq
+.w4:
+    mova               xmm0, [srcq]
+    add                srcq, 16
+    pmaddubsw          xmm0, xm4
+    packuswb           xmm0, xmm0
+    movq             [dstq], xmm0
+    add                dstq, 8
+    sub                  hd, 4
+    jg .w4
+    test                bhd, bhd
+    jz .w4_end
+    pshuflw            xmm0, xmm0, q3333
+.w4_padv:
+    movq             [dstq], xmm0
+    add                dstq, 8
+    sub                 bhd, 4
+    jg .w4_padv
+.w4_end:
+    RET
+.w8_padh:
+    pshufb             xmm0, xmm2
+    pshufb             xmm1, xmm2
+    jmp .w8_main
+.w8:
+    mova               xmm2, [base+pal_idx_w8_padh]
+.w8_loop:
+    mova               xmm0, [srcq+16*0]
+    mova               xmm1, [srcq+16*1]
+    cmp                  wd, 7
+    jl .w8_padh
+.w8_main:
+    pmaddubsw          xmm0, xm4
+    pmaddubsw          xmm1, xm4
+    add                srcq, 16*2
+    packuswb           xmm0, xmm1
+    movu             [dstq], xmm0
+    add                dstq, 16
+    sub                  hd, 4
+    jg .w8_loop
+    test                bhd, bhd
+    jz .w8_end
+    pshufd             xmm0, xmm0, q3333
+.w8_padv:
+    movu             [dstq], xmm0
+    add                dstq, 16
+    sub                 bhd, 4
+    jg .w8_padv
+.w8_end:
+    RET
+.w16_padh:
+    pshufb               m0, m2
+    jmp .w16_main
+.w16:
+    cmp                  wd, 15
+    je .w16_loop
+    vbroadcasti32x4      m2, [base+pb_0to63]
+    vpbroadcastb         m0, wd
+    pminub               m2, m0
+.w16_loop:
+    mova                 m0, [srcq]
+    cmp                  wd, 15
+    jl .w16_padh
+.w16_main:
+    pmaddubsw            m0, m4
+    add                srcq, 64
+    vpmovwb             ym0, m0
+    movu             [dstq], ym0
+    add                dstq, 32
+    sub                  hd, 4
+    jg .w16_loop
+    test                bhd, bhd
+    jz .w16_end
+    vpermq              ym0, ym0, q3333
+.w16_padv:
+    movu             [dstq], ym0
+    add                dstq, 32
+    sub                 bhd, 4
+    jg .w16_padv
+.w16_end:
+    RET
+.w32_padh:
+    vpermb               m0, m2, m0
+    vpermb               m1, m2, m1
+    jmp .w32_main
+.w32:
+    mova                 m2, [base+pb_0to63]
+    paddb                m3, m2, m2
+    cmp                  wd, 31
+    je .w32_loop
+    vpbroadcastb         m0, wd
+    mov                 r6d, 0xff00
+    kmovw                k1, r6d
+    vpaddd           m0{k1}, [pb_32] {1to16}
+    pminub               m2, m0
+.w32_loop:
+    mova                 m0, [srcq+64*0]
+    mova                 m1, [srcq+64*1]
+    cmp                  wd, 31
+    jl .w32_padh
+.w32_main:
+    pmaddubsw            m0, m4
+    pmaddubsw            m1, m4
+    add                srcq, 64*2
+    vpermt2b             m0, m3, m1
+    movu             [dstq], m0
+    add                dstq, 64
+    sub                  hd, 4
+    jg .w32_loop
+    test                bhd, bhd
+    jz .w32_end
+    vshufi32x4           m0, m0, q3333
+.w32_padv:
+    movu             [dstq], m0
+    add                dstq, 64
+    sub                 bhd, 4
+    jg .w32_padv
+.w32_end:
+    RET
+.w64_padh:
+    REPX  {vpermb x, m5, x}, m0, m1, m2, m3
+    jmp .w64_main
+.w64:
+    mova                 m5, [base+pb_0to63]
+    paddb                m6, m5, m5
+    cmp                  wd, 63
+    je .w64_loop
+    vpbroadcastb         m0, wd
+    pminub               m5, m0
+.w64_loop:
+    mova                 m0, [srcq+64*0]
+    mova                 m1, [srcq+64*1]
+    mova                 m2, [srcq+64*2]
+    mova                 m3, [srcq+64*3]
+    cmp                  wd, 63
+    jl .w64_padh
+.w64_main:
+    REPX  {pmaddubsw x, m4}, m0, m1, m2, m3
+    add                srcq, 64*4
+    vpermt2b             m0, m6, m1
+    vpermt2b             m2, m6, m3
+    movu        [dstq+64*0], m0
+    movu        [dstq+64*1], m2
+    add                dstq, 64*2
+    sub                  hd, 4
+    jg .w64_loop
+    test                bhd, bhd
+    jz .w64_end
+    vshufi32x4           m2, m2, q3232
+.w64_padv:
+    movu        [dstq+64*0], m2
+    movu        [dstq+64*1], m2
+    add                dstq, 64*2
+    sub                 bhd, 4
+    jg .w64_padv
+.w64_end:
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/pal.h b/media/libdav1d/src/src/x86/pal.h
new file mode 100644
index 0000000000..7cd2e68d5b
--- /dev/null
+++ b/media/libdav1d/src/src/x86/pal.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * Copyright © 2023, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+
+decl_pal_idx_finish_fn(dav1d_pal_idx_finish_ssse3);
+decl_pal_idx_finish_fn(dav1d_pal_idx_finish_avx2);
+decl_pal_idx_finish_fn(dav1d_pal_idx_finish_avx512icl);
+
+static ALWAYS_INLINE void pal_dsp_init_x86(Dav1dPalDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSSE3)) return;
+
+    c->pal_idx_finish = dav1d_pal_idx_finish_ssse3;
+
+#if ARCH_X86_64
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2)) return;
+
+    c->pal_idx_finish = dav1d_pal_idx_finish_avx2;
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL)) return;
+
+    c->pal_idx_finish = dav1d_pal_idx_finish_avx512icl;
+#endif
+}
diff --git a/media/libdav1d/src/src/x86/refmvs.asm b/media/libdav1d/src/src/x86/refmvs.asm
new file mode 100644
index 0000000000..84d70cf390
--- /dev/null
+++ b/media/libdav1d/src/src/x86/refmvs.asm
@@ -0,0 +1,935 @@
+; Copyright © 2021, VideoLAN and dav1d authors
+; Copyright © 2021, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 64
+
+%macro JMP_TABLE 2-*
+    %xdefine %%prefix mangle(private_prefix %+ _%1)
+    %1_table:
+    %xdefine %%base %1_table
+    %rep %0 - 1
+        dd %%prefix %+ .w%2 - %%base
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro SAVE_TMVS_TABLE 3 ; num_entries, w, suffix
+    %rep %1
+        db %2*3
+        db mangle(private_prefix %+ _save_tmvs_%3).write%2 - \
+           mangle(private_prefix %+ _save_tmvs_%3).write1
+    %endrep
+%endmacro
+
+%if ARCH_X86_64
+mv_proj:       dw    0, 16384, 8192, 5461, 4096, 3276, 2730, 2340
+               dw 2048,  1820, 1638, 1489, 1365, 1260, 1170, 1092
+               dw 1024,   963,  910,  862,  819,  780,  744,  712
+               dw  682,   655,  630,  606,  585,  564,  546,  528
+splat_mv_shuf: db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3
+               db  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7
+               db  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11
+               db  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3
+%endif
+save_pack0:    db  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0
+               db  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1
+save_pack1:    db  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2
+               db  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3,  4,  0,  1,  2,  3
+save_ref_shuf: db  0, -1, -1, -1,  1, -1, -1, -1,  8, -1, -1, -1,  9, -1, -1, -1
+cond_shuf512:  db  3,  3,  3,  3,  7,  7,  7,  7,  7,  7,  7,  7,  3,  3,  3,  3
+save_cond0:    db  0x80, 0x81, 0x82, 0x83, 0x89, 0x84, 0x00, 0x00
+save_cond1:    db  0x84, 0x85, 0x86, 0x87, 0x88, 0x80, 0x00, 0x00
+pb_128:        times 16 db 128
+pq_8192:       dq 8192
+
+save_tmvs_ssse3_table: SAVE_TMVS_TABLE 2, 16, ssse3
+                       SAVE_TMVS_TABLE 4,  8, ssse3
+                       SAVE_TMVS_TABLE 4,  4, ssse3
+                       SAVE_TMVS_TABLE 5,  2, ssse3
+                       SAVE_TMVS_TABLE 7,  1, ssse3
+
+%if ARCH_X86_64
+save_tmvs_avx2_table: SAVE_TMVS_TABLE 2, 16, avx2
+                      SAVE_TMVS_TABLE 4,  8, avx2
+                      SAVE_TMVS_TABLE 4,  4, avx2
+                      SAVE_TMVS_TABLE 5,  2, avx2
+                      SAVE_TMVS_TABLE 7,  1, avx2
+
+save_tmvs_avx512icl_table: SAVE_TMVS_TABLE 2, 16, avx512icl
+                           SAVE_TMVS_TABLE 4,  8, avx512icl
+                           SAVE_TMVS_TABLE 4,  4, avx512icl
+                           SAVE_TMVS_TABLE 5,  2, avx512icl
+                           SAVE_TMVS_TABLE 7,  1, avx512icl
+
+JMP_TABLE splat_mv_avx512icl, 1, 2, 4, 8, 16, 32
+JMP_TABLE splat_mv_avx2,      1, 2, 4, 8, 16, 32
+%endif
+
+JMP_TABLE splat_mv_sse2,      1, 2, 4, 8, 16, 32
+
+struc rf
+    .frm_hdr:         resq 1
+    .iw4:             resd 1
+    .ih4:             resd 1
+    .iw8:             resd 1
+    .ih8:             resd 1
+    .sbsz:            resd 1
+    .use_rf_mvs:      resd 1
+    .sign_bias:       resb 7
+    .mfmv_sign:       resb 7
+    .pocdiff:         resb 7
+    .mfmv_ref:        resb 3
+    .mfmv_ref2cur:    resb 3
+    .mfmv_ref2ref:    resb 3*7
+    .n_mfmvs:         resd 1
+    .n_blocks:        resd 1
+    .rp:              resq 1
+    .rp_ref:          resq 1
+    .rp_proj:         resq 1
+    .rp_stride:       resq 1
+    .r:               resq 1
+    .n_tile_threads:  resd 1
+    .n_frame_threads: resd 1
+endstruc
+
+SECTION .text
+
+%macro movif32 2
+%if ARCH_X86_32
+    mov             %1, %2
+%endif
+%endmacro
+
+INIT_XMM ssse3
+; refmvs_temporal_block *rp, ptrdiff_t stride,
+; refmvs_block **rr, uint8_t *ref_sign,
+; int col_end8, int row_end8, int col_start8, int row_start8
+%if ARCH_X86_64
+cglobal save_tmvs, 4, 13, 11, rp, stride, rr, ref_sign, \
+                             xend, yend, xstart, ystart
+%define base_reg r12
+%else
+cglobal save_tmvs, 6, 7, 8, rp, stride, rr, ref_sign, \
+                            xend, yend, xstart, ystart
+    movq            m5, [ref_signq]
+    lea        strided, [strided*5]
+    mov        stridem, strided
+    mov             r3, xstartm
+    mov             r1, ystartm
+ DEFINE_ARGS b, ystart, rr, cand, xend, x
+%define stridemp r1m
+%define m8  [base+pb_128]
+%define m9  [base+save_pack0+ 0]
+%define m10 [base+save_pack0+16]
+%define base_reg r6
+%endif
+%define base base_reg-.write1
+    LEA       base_reg, .write1
+%if ARCH_X86_64
+    movifnidn    xendd, xendm
+    movifnidn    yendd, yendm
+    mov        xstartd, xstartm
+    mov        ystartd, ystartm
+    movq            m5, [ref_signq]
+%endif
+    movu            m4, [base+save_ref_shuf]
+    movddup         m6, [base+save_cond0]
+    movddup         m7, [base+save_cond1]
+%if ARCH_X86_64
+    mova            m8, [base+pb_128]
+    mova            m9, [base+save_pack0+ 0]
+    mova           m10, [base+save_pack0+16]
+%endif
+    psllq           m5, 8
+%if ARCH_X86_64
+    lea            r9d, [xendq*5]
+    lea        xstartd, [xstartq*5]
+    sub          yendd, ystartd
+    add        ystartd, ystartd
+    lea        strideq, [strideq*5]
+    sub        xstartq, r9
+    add          xendd, r9d
+    add            rpq, r9
+ DEFINE_ARGS rp, stride, rr, x, xend, h, xstart, ystart, b, cand
+%else
+    lea             r0, [xendd*5]   ; xend5
+    lea             r3, [r3*5]      ; xstart5
+    sub             r3, r0          ; -w5
+    mov            r6m, r3
+%define xstartq r6m
+    add          xendd, r0          ; xend6
+    add            r0m, r0          ; rp+xend5
+    mov          xendm, xendd
+    sub             r5, r1          ; h
+    add             r1, r1
+    mov            r7m, r1
+    mov            r5m, r5
+%define hd r5mp
+    jmp .loop_y_noload
+%endif
+.loop_y:
+    movif32    ystartd, r7m
+    movif32      xendd, xendm
+.loop_y_noload:
+    and        ystartd, 30
+    mov             xq, xstartq
+    mov             bq, [rrq+ystartq*gprsize]
+    add        ystartd, 2
+    movif32        r7m, ystartd
+    lea             bq, [bq+xendq*4]
+.loop_x:
+%if ARCH_X86_32
+%define rpq  r3
+%define r10  r1
+%define r10d r1
+%define r11  r4
+%define r11d r4
+%endif
+    imul         candq, xq, 0x9999  ; x / 5 * 3
+    sar          candq, 16
+    movzx         r10d, byte [bq+candq*8+22] ; cand_b->bs
+    movu            m0, [bq+candq*8+12]      ; cand_b
+    movzx         r11d, byte [base+save_tmvs_ssse3_table+r10*2+0]
+    movzx         r10d, byte [base+save_tmvs_ssse3_table+r10*2+1]
+    add            r10, base_reg
+    add          candq, r11
+    jge .calc
+    movu            m1, [bq+candq*8+12]
+    movzx         r11d, byte [bq+candq*8+22]
+    movzx         r11d, byte [base+save_tmvs_ssse3_table+r11*2+1]
+    add            r11, base_reg
+.calc:
+    movif32        rpq, r0m
+    ; ref check
+    punpckhqdq      m2, m0, m1
+    pshufb          m2, m4      ; b0.ref0 b0.ref1 b1.ref0 b1.ref1 | ...
+    pshufb          m3, m5, m2  ; ref > 0 && res_sign[ref - 1]
+    ; mv check
+    punpcklqdq      m2, m0, m1  ; b0.mv0 b0.mv1 b1.mv0 b1.mv1 | ...
+    pabsw           m2, m2
+    psrlw           m2, 12      ; (abs(mv.x) | abs(mv.y)) < 4096
+    ; res
+    pcmpgtd         m3, m2
+    pshufd          m2, m3, q2301
+    pand            m3, m6      ; b0c0 b0c1 b1c0 b1c1 | ...
+    pand            m2, m7      ; b0c1 b0c0 b1c1 b1c0 | ...
+    por             m3, m2      ; b0.shuf b1.shuf | ...
+    pxor            m3, m8      ; if cond0|cond1 == 0 => zero out
+    pshufb          m0, m3
+    pshufb          m1, m3
+    call           r10
+    jge .next_line
+    pshufd          m0, m1, q3232
+    call           r11
+    jl .loop_x
+.next_line:
+    add            rpq, stridemp
+    movif32        r0m, rpq
+    dec             hd
+    jg .loop_y
+    RET
+.write1:
+    movd    [rpq+xq+0], m0
+    psrlq           m0, 8
+    movd    [rpq+xq+1], m0
+    add             xq, 5*1
+    ret
+.write2:
+    movq    [rpq+xq+0], m0
+    psrlq           m0, 8
+    movd    [rpq+xq+6], m0
+    add             xq, 5*2
+    ret
+.write4:
+    pshufb          m0, m9
+    movu   [rpq+xq+ 0], m0
+    psrlq           m0, 8
+    movd   [rpq+xq+16], m0
+    add             xq, 5*4
+    ret
+.write8:
+    pshufb          m2, m0, m9
+    movu   [rpq+xq+ 0], m2
+    pshufb          m0, m10
+    movu   [rpq+xq+16], m0
+    psrldq          m2, 2
+    movq   [rpq+xq+32], m2
+    add             xq, 5*8
+    ret
+.write16:
+    pshufb          m2, m0, m9
+    movu   [rpq+xq+ 0], m2
+    pshufb          m0, m10
+    movu   [rpq+xq+16], m0
+    shufps          m2, m0, q1032
+    movu   [rpq+xq+48], m2
+    shufps          m2, m0, q2121
+    movu   [rpq+xq+32], m2
+    shufps          m0, m2, q1032
+    movu   [rpq+xq+64], m0
+    add             xq, 5*16
+    ret
+
+INIT_XMM sse2
+; refmvs_block **rr, refmvs_block *a, int bx4, int bw4, int bh4
+cglobal splat_mv, 4, 5, 3, rr, a, bx4, bw4, bh4
+    add           bx4d, bw4d
+    tzcnt         bw4d, bw4d
+    mova            m2, [aq]
+    LEA             aq, splat_mv_sse2_table
+    lea           bx4q, [bx4q*3-32]
+    movsxd        bw4q, [aq+bw4q*4]
+    movifnidn     bh4d, bh4m
+    pshufd          m0, m2, q0210
+    pshufd          m1, m2, q1021
+    pshufd          m2, m2, q2102
+    add           bw4q, aq
+.loop:
+    mov             aq, [rrq]
+    add            rrq, gprsize
+    lea             aq, [aq+bx4q*4]
+    jmp           bw4q
+.w32:
+    mova    [aq-16*16], m0
+    mova    [aq-16*15], m1
+    mova    [aq-16*14], m2
+    mova    [aq-16*13], m0
+    mova    [aq-16*12], m1
+    mova    [aq-16*11], m2
+    mova    [aq-16*10], m0
+    mova    [aq-16* 9], m1
+    mova    [aq-16* 8], m2
+    mova    [aq-16* 7], m0
+    mova    [aq-16* 6], m1
+    mova    [aq-16* 5], m2
+.w16:
+    mova    [aq-16* 4], m0
+    mova    [aq-16* 3], m1
+    mova    [aq-16* 2], m2
+    mova    [aq-16* 1], m0
+    mova    [aq+16* 0], m1
+    mova    [aq+16* 1], m2
+.w8:
+    mova    [aq+16* 2], m0
+    mova    [aq+16* 3], m1
+    mova    [aq+16* 4], m2
+.w4:
+    mova    [aq+16* 5], m0
+    mova    [aq+16* 6], m1
+    mova    [aq+16* 7], m2
+    dec           bh4d
+    jg .loop
+    RET
+.w2:
+    movu      [aq+104], m0
+    movq      [aq+120], m1
+    dec           bh4d
+    jg .loop
+    RET
+.w1:
+    movq      [aq+116], m0
+    movd      [aq+124], m2
+    dec           bh4d
+    jg .loop
+    RET
+
+%if ARCH_X86_64
+INIT_XMM sse4
+; refmvs_frame *rf, int tile_row_idx,
+; int col_start8, int col_end8, int row_start8, int row_end8
+cglobal load_tmvs, 6, 15, 4, -0x50, rf, tridx, xstart, xend, ystart, yend, \
+                                    stride, rp_proj, roff, troff, \
+                                    xendi, xstarti, iw8, ih8, dst
+    xor           r14d, r14d
+    cmp dword [rfq+rf.n_tile_threads], 1
+    mov           ih8d, [rfq+rf.ih8]
+    mov           iw8d, [rfq+rf.iw8]
+    mov        xstartd, xstartd
+    mov          xendd, xendd
+    cmove       tridxd, r14d
+    lea       xstartid, [xstartq-8]
+    lea         xendid, [xendq+8]
+    mov        strideq, [rfq+rf.rp_stride]
+    mov       rp_projq, [rfq+rf.rp_proj]
+    cmp           ih8d, yendd
+    mov     [rsp+0x30], strideq
+    cmovs        yendd, ih8d
+    test      xstartid, xstartid
+    cmovs     xstartid, r14d
+    cmp           iw8d, xendid
+    cmovs       xendid, iw8d
+    mov         troffq, strideq
+    shl         troffq, 4
+    imul        troffq, tridxq
+    mov           dstd, ystartd
+    and           dstd, 15
+    imul          dstq, strideq
+    add           dstq, troffq      ; (16 * tridx + (ystart & 15)) * stride
+    lea           dstq, [dstq*5]
+    add           dstq, rp_projq
+    lea         troffq, [troffq*5]  ; 16 * tridx * stride * 5
+    lea           r13d, [xendq*5]
+    lea            r12, [strideq*5]
+ DEFINE_ARGS rf, w5, xstart, xend, ystart, yend, h, x5, \
+             _, troff, xendi, xstarti, stride5, _, dst
+    lea            w5d, [xstartq*5]
+    add             r7, troffq      ; rp_proj + tile_row_offset
+    mov             hd, yendd
+    mov     [rsp+0x28], r7
+    add           dstq, r13
+    sub            w5q, r13
+    sub             hd, ystartd
+.init_xloop_start:
+    mov            x5q, w5q
+    test           w5b, 1
+    jz .init_2blk
+    mov dword [dstq+x5q], 0x80008000
+    add            x5q, 5
+    jz .init_next_row
+.init_2blk:
+    mov dword [dstq+x5q+0], 0x80008000
+    mov dword [dstq+x5q+5], 0x80008000
+    add            x5q, 10
+    jl .init_2blk
+.init_next_row:
+    add           dstq, stride5q
+    dec             hd
+    jg .init_xloop_start
+ DEFINE_ARGS rf, _, xstart, xend, ystart, yend, n7, stride, \
+             _, _, xendi, xstarti, stride5, _, n
+    mov           r13d, [rfq+rf.n_mfmvs]
+    test          r13d, r13d
+    jz .ret
+    mov     [rsp+0x0c], r13d
+    mov        strideq, [rsp+0x30]
+    movddup         m3, [pq_8192]
+    mov            r9d, ystartd
+    mov     [rsp+0x38], yendd
+    mov     [rsp+0x20], xstartid
+    xor             nd, nd
+    lea            n7q, [rfq+rf.mfmv_ref2ref-1]
+    imul            r9, strideq     ; ystart * stride
+    mov     [rsp+0x48], rfq
+    mov     [rsp+0x18], stride5q
+    lea             r7, [r9*5]
+    mov     [rsp+0x24], ystartd
+    mov     [rsp+0x00], r7
+.nloop:
+ DEFINE_ARGS y, off, xstart, xend, ystart, rf, n7, refsign, \
+             ref, rp_ref, xendi, xstarti, _, _, n
+    mov            rfq, [rsp+0x48]
+    movsx         refd, byte [rfq+rf.mfmv_ref2cur+nq]
+    cmp           refd, -32                 ; INVALID_REF2CUR
+    je .next_n
+    mov     [rsp+0x40], refd
+    mov           offq, [rsp+0x00]          ; ystart * stride * 5
+    movzx         refd, byte [rfq+rf.mfmv_ref+nq]
+    lea       refsignq, [refq-4]
+    mov        rp_refq, [rfq+rf.rp_ref]
+    movq            m2, refsignq
+    add           offq, [rp_refq+refq*8]    ; r = rp_ref[ref] + row_offset
+    mov     [rsp+0x14], nd
+    mov             yd, ystartd
+.yloop:
+    mov           r11d, [rsp+0x24]          ; ystart
+    mov           r12d, [rsp+0x38]          ; yend
+    mov           r14d, yd
+    and           r14d, ~7                  ; y_sb_align
+    cmp           r11d, r14d
+    cmovs         r11d, r14d                ; imax(y_sb_align, ystart)
+    mov     [rsp+0x44], r11d                ; y_proj_start
+    add           r14d, 8
+    cmp           r12d, r14d
+    cmovs         r14d, r12d                ; imin(y_sb_align + 8, yend)
+    mov     [rsp+0x3c], r14d                ; y_proj_end
+ DEFINE_ARGS y, src, xstart, xend, frac, rf, n7, mv, \
+             ref, x, xendi, mvx, mvy, rb, ref2ref
+    mov             xd, [rsp+0x20] ; xstarti
+.xloop:
+    lea            rbd, [xq*5]
+    add            rbq, srcq
+    movzx         refd, byte [rbq+4]
+    test          refd, refd
+    jz .next_x_bad_ref
+    movzx     ref2refd, byte [n7q+refq]     ; rf->mfmv_ref2ref[n][b_ref-1]
+    test      ref2refd, ref2refd
+    jz .next_x_bad_ref
+    lea          fracq, [mv_proj]
+    movzx        fracd, word [fracq+ref2refq*2]
+    mov            mvd, [rbq]
+    imul         fracd, [rsp+0x40] ; ref2cur
+    pmovsxwq        m0, [rbq]
+    movd            m1, fracd
+    punpcklqdq      m1, m1
+    pmuldq          m0, m1          ; mv * frac
+    pshufd          m1, m0, q3311
+    paddd           m0, m3
+    paddd           m0, m1
+    psrad           m0, 14          ; offset = (xy + (xy >> 31) + 8192) >> 14
+    pabsd           m1, m0
+    packssdw        m0, m0
+    psrld           m1, 6
+    packuswb        m1, m1
+    pxor            m0, m2          ; offset ^ ref_sign
+    psignd          m1, m0          ; apply_sign(abs(offset) >> 6, offset ^ refsign)
+    movq          mvxq, m1
+    lea           mvyd, [mvxq+yq]   ; ypos
+    sar           mvxq, 32
+ DEFINE_ARGS y, src, xstart, xend, _, _, n7, mv, \
+             ref, x, xendi, mvx, ypos, rb, ref2ref
+    cmp          yposd, [rsp+0x44] ; y_proj_start
+    jl .next_x_bad_pos_y
+    cmp          yposd, [rsp+0x3c] ; y_proj_end
+    jge .next_x_bad_pos_y
+    and          yposd, 15
+    add           mvxq, xq          ; xpos
+    imul         yposq, [rsp+0x30]  ; pos = (ypos & 15) * stride
+ DEFINE_ARGS y, src, xstart, xend, dst, _, n7, mv, \
+             ref, x, xendi, xpos, pos, rb, ref2ref
+    mov           dstq, [rsp+0x28]  ; dst = rp_proj + tile_row_offset
+    add           posq, xposq       ; pos += xpos
+    lea           posq, [posq*5]
+    add           dstq, posq        ; dst += pos5
+    jmp .write_loop_entry
+.write_loop:
+    add            rbq, 5
+    cmp           refb, byte [rbq+4]
+    jne .xloop
+    cmp            mvd, [rbq]
+    jne .xloop
+    add           dstq, 5
+    inc          xposd
+.write_loop_entry:
+    mov           r12d, xd
+    and           r12d, ~7
+    lea            r5d, [r12-8]
+    cmp            r5d, xstartd
+    cmovs          r5d, xstartd     ; x_proj_start
+    cmp          xposd, r5d
+    jl .next_xpos
+    add           r12d, 16
+    cmp          xendd, r12d
+    cmovs         r12d, xendd       ; x_proj_end
+    cmp          xposd, r12d
+    jge .next_xpos
+    mov       [dstq+0], mvd
+    mov  byte [dstq+4], ref2refb
+.next_xpos:
+    inc             xd
+    cmp             xd, xendid
+    jl .write_loop
+.next_y:
+ DEFINE_ARGS y, src, xstart, xend, ystart, _, n7, _, _, x, xendi, _, _, _, n
+    add           srcq, [rsp+0x18] ; stride5
+    inc             yd
+    cmp             yd, [rsp+0x38] ; yend
+    jne .yloop
+    mov             nd, [rsp+0x14]
+    mov        ystartd, [rsp+0x24]
+.next_n:
+    add            n7q, 7
+    inc             nd
+    cmp             nd, [rsp+0x0c] ; n_mfmvs
+    jne .nloop
+.ret:
+    RET
+.next_x:
+ DEFINE_ARGS y, src, xstart, xend, _, _, n7, mv, ref, x, xendi, _, _, rb, _
+    add            rbq, 5
+    cmp           refb, byte [rbq+4]
+    jne .xloop
+    cmp            mvd, [rbq]
+    jne .xloop
+.next_x_bad_pos_y:
+    inc             xd
+    cmp             xd, xendid
+    jl .next_x
+    jmp .next_y
+.next_x_bad_ref:
+    inc             xd
+    cmp             xd, xendid
+    jl .xloop
+    jmp .next_y
+
+INIT_YMM avx2
+; refmvs_temporal_block *rp, ptrdiff_t stride,
+; refmvs_block **rr, uint8_t *ref_sign,
+; int col_end8, int row_end8, int col_start8, int row_start8
+cglobal save_tmvs, 4, 13, 10, rp, stride, rr, ref_sign, \
+                              xend, yend, xstart, ystart
+%define base r12-.write1
+    lea            r12, [.write1]
+    movifnidn    xendd, xendm
+    movifnidn    yendd, yendm
+    mov        xstartd, xstartm
+    mov        ystartd, ystartm
+    vpbroadcastq    m4, [ref_signq]
+    vpbroadcastq    m3, [base+save_ref_shuf+8]
+    vpbroadcastq    m5, [base+save_cond0]
+    vpbroadcastq    m6, [base+save_cond1]
+    vpbroadcastd    m7, [base+pb_128]
+    mova            m8, [base+save_pack0]
+    mova            m9, [base+save_pack1]
+    psllq           m4, 8
+    lea            r9d, [xendq*5]
+    lea        xstartd, [xstartq*5]
+    sub          yendd, ystartd
+    add        ystartd, ystartd
+    lea        strideq, [strideq*5]
+    sub        xstartq, r9
+    add          xendd, r9d
+    add            rpq, r9
+ DEFINE_ARGS rp, stride, rr, x, xend, h, xstart, ystart, b, cand
+.loop_y:
+    and        ystartd, 30
+    mov             xq, xstartq
+    mov             bq, [rrq+ystartq*8]
+    add        ystartd, 2
+    lea             bq, [bq+xendq*4]
+.loop_x:
+    imul         candq, xq, 0x9999
+    sar          candq, 16                   ; x / 5 * 3
+    movzx         r10d, byte [bq+candq*8+22] ; cand_b->bs
+    movu           xm0, [bq+candq*8+12]      ; cand_b
+    movzx         r11d, byte [base+save_tmvs_avx2_table+r10*2+0]
+    movzx         r10d, byte [base+save_tmvs_avx2_table+r10*2+1]
+    add            r10, r12
+    add          candq, r11
+    jge .calc
+    vinserti128     m0, [bq+candq*8+12], 1
+    movzx         r11d, byte [bq+candq*8+22]
+    movzx         r11d, byte [base+save_tmvs_avx2_table+r11*2+1]
+    add            r11, r12
+.calc:
+    pshufb          m1, m0, m3
+    pabsw           m2, m0
+    pshufb          m1, m4, m1  ; ref > 0 && res_sign[ref - 1]
+    psrlw           m2, 12      ; (abs(mv.x) | abs(mv.y)) < 4096
+    pcmpgtd         m1, m2
+    pshufd          m2, m1, q2301
+    pand            m1, m5      ; b0.cond0 b1.cond0
+    pand            m2, m6      ; b0.cond1 b1.cond1
+    por             m1, m2      ; b0.shuf b1.shuf
+    pxor            m1, m7      ; if cond0|cond1 == 0 => zero out
+    pshufb          m0, m1
+    call           r10
+    jge .next_line
+    vextracti128   xm0, m0, 1
+    call           r11
+    jl .loop_x
+.next_line:
+    add            rpq, strideq
+    dec             hd
+    jg .loop_y
+    RET
+.write1:
+    movd   [rpq+xq+ 0], xm0
+    pextrb [rpq+xq+ 4], xm0, 4
+    add             xq, 5*1
+    ret
+.write2:
+    movq    [rpq+xq+0], xm0
+    psrlq          xm1, xm0, 8
+    movd    [rpq+xq+6], xm1
+    add             xq, 5*2
+    ret
+.write4:
+    pshufb         xm1, xm0, xm8
+    movu   [rpq+xq+ 0], xm1
+    psrlq          xm1, 8
+    movd   [rpq+xq+16], xm1
+    add             xq, 5*4
+    ret
+.write8:
+    vinserti128     m1, m0, xm0, 1
+    pshufb          m1, m8
+    movu   [rpq+xq+ 0], m1
+    psrldq         xm1, 2
+    movq   [rpq+xq+32], xm1
+    add             xq, 5*8
+    ret
+.write16:
+    vinserti128     m1, m0, xm0, 1
+    pshufb          m2, m1, m8
+    movu   [rpq+xq+ 0], m2
+    pshufb          m1, m9
+    movu   [rpq+xq+32], m1
+    shufps         xm2, xm1, q1021
+    movu   [rpq+xq+64], xm2
+    add             xq, 5*16
+    ret
+
+cglobal splat_mv, 4, 5, 3, rr, a, bx4, bw4, bh4
+    add           bx4d, bw4d
+    tzcnt         bw4d, bw4d
+    vbroadcasti128  m0, [aq]
+    lea             aq, [splat_mv_avx2_table]
+    lea           bx4q, [bx4q*3-32]
+    movsxd        bw4q, [aq+bw4q*4]
+    pshufb          m0, [splat_mv_shuf]
+    movifnidn     bh4d, bh4m
+    pshufd          m1, m0, q2102
+    pshufd          m2, m0, q1021
+    add           bw4q, aq
+.loop:
+    mov             aq, [rrq]
+    add            rrq, gprsize
+    lea             aq, [aq+bx4q*4]
+    jmp           bw4q
+.w32:
+    mova     [aq-32*8], m0
+    mova     [aq-32*7], m1
+    mova     [aq-32*6], m2
+    mova     [aq-32*5], m0
+    mova     [aq-32*4], m1
+    mova     [aq-32*3], m2
+.w16:
+    mova     [aq-32*2], m0
+    mova     [aq-32*1], m1
+    mova     [aq+32*0], m2
+.w8:
+    mova     [aq+32*1], m0
+    mova     [aq+32*2], m1
+    mova     [aq+32*3], m2
+    dec           bh4d
+    jg .loop
+    RET
+.w4:
+    movu      [aq+ 80], m0
+    mova      [aq+112], xm1
+    dec           bh4d
+    jg .loop
+    RET
+.w2:
+    movu      [aq+104], xm0
+    movq      [aq+120], xm2
+    dec           bh4d
+    jg .loop
+    RET
+.w1:
+    movq      [aq+116], xm0
+    movd      [aq+124], xm1
+    dec           bh4d
+    jg .loop
+    RET
+
+INIT_ZMM avx512icl
+; refmvs_temporal_block *rp, ptrdiff_t stride,
+; refmvs_block **rr, uint8_t *ref_sign,
+; int col_end8, int row_end8, int col_start8, int row_start8
+cglobal save_tmvs, 4, 15, 10, rp, stride, rr, ref_sign, \
+                              xend, yend, xstart, ystart
+%define base r14-.write1
+    lea            r14, [.write1]
+    movifnidn    xendd, xendm
+    movifnidn    yendd, yendm
+    mov        xstartd, xstartm
+    mov        ystartd, ystartm
+    psllq           m4, [ref_signq]{bcstq}, 8
+    vpbroadcastq    m3, [base+save_ref_shuf+8]
+    vbroadcasti32x4 m5, [base+cond_shuf512]
+    vbroadcasti32x4 m6, [base+save_cond0]
+    vpbroadcastd    m7, [base+pb_128]
+    mova            m8, [base+save_pack0]
+    movu           xm9, [base+save_pack0+4]
+    lea            r9d, [xendq*5]
+    lea        xstartd, [xstartq*5]
+    sub          yendd, ystartd
+    add        ystartd, ystartd
+    lea        strideq, [strideq*5]
+    sub        xstartq, r9
+    add          xendd, r9d
+    add            rpq, r9
+    mov           r10d, 0x1f
+    kmovb           k2, r10d
+ DEFINE_ARGS rp, stride, rr, x, xend, h, xstart, ystart, b, cand
+.loop_y:
+    and        ystartd, 30
+    mov             xq, xstartq
+    mov             bq, [rrq+ystartq*8]
+    add        ystartd, 2
+    lea             bq, [bq+xendq*4]
+.loop_x:
+    imul         candq, xq, 0x9999
+    sar          candq, 16                   ; x / 5 * 3
+    movzx         r10d, byte [bq+candq*8+22] ; cand_b->bs
+    movu           xm0, [bq+candq*8+12]      ; cand_b
+    movzx         r11d, byte [base+save_tmvs_avx512icl_table+r10*2+0]
+    movzx         r10d, byte [base+save_tmvs_avx512icl_table+r10*2+1]
+    add            r10, r14
+    add          candq, r11
+    jge .calc
+    movzx         r11d, byte [bq+candq*8+22]
+    vinserti32x4   ym0, [bq+candq*8+12], 1
+    movzx         r12d, byte [base+save_tmvs_avx512icl_table+r11*2+0]
+    movzx         r11d, byte [base+save_tmvs_avx512icl_table+r11*2+1]
+    add            r11, r14
+    add          candq, r12
+    jge .calc
+    movzx         r12d, byte [bq+candq*8+22]
+    vinserti32x4    m0, [bq+candq*8+12], 2
+    movzx         r13d, byte [base+save_tmvs_avx512icl_table+r12*2+0]
+    movzx         r12d, byte [base+save_tmvs_avx512icl_table+r12*2+1]
+    add            r12, r14
+    add          candq, r13
+    jge .calc
+    vinserti32x4    m0, [bq+candq*8+12], 3
+    movzx         r13d, byte [bq+candq*8+22]
+    movzx         r13d, byte [base+save_tmvs_avx512icl_table+r13*2+1]
+    add            r13, r14
+.calc:
+    pshufb          m1, m0, m3
+    pabsw           m2, m0
+    pshufb          m1, m4, m1      ; ref > 0 && res_sign[ref - 1]
+    psrlw           m2, 12          ; (abs(mv.x) | abs(mv.y)) < 4096
+    psubd           m2, m1
+    pshufb          m2, m5           ; c0 c1 c1 c0
+    pand            m2, m6
+    punpckhqdq      m1, m2, m2
+    vpternlogd      m1, m2, m7, 0x56 ; (c0shuf | c1shuf) ^ 0x80
+    pshufb          m2, m0, m1
+    mova           xm0, xm2
+    call           r10
+    jge .next_line
+    vextracti32x4  xm0, m2, 1
+    call           r11
+    jge .next_line
+    vextracti32x4  xm0, m2, 2
+    call           r12
+    jge .next_line
+    vextracti32x4  xm0, m2, 3
+    call           r13
+    jl .loop_x
+.next_line:
+    add            rpq, strideq
+    dec             hd
+    jg .loop_y
+    RET
+.write1:
+    vmovdqu8 [rpq+xq]{k2}, xm0
+    add             xq, 5*1
+    ret
+.write2:
+    pshufb         xm0, xm8
+    vmovdqu16 [rpq+xq]{k2}, xm0
+    add             xq, 5*2
+    ret
+.write4:
+    vpermb         ym0, ym8, ym0
+    vmovdqu32 [rpq+xq]{k2}, ym0
+    add             xq, 5*4
+    ret
+.write8:
+    vpermb          m0, m8, m0
+    vmovdqu64 [rpq+xq]{k2}, m0
+    add             xq, 5*8
+    ret
+.write16:
+    vpermb          m1, m8, m0
+    movu   [rpq+xq+ 0], m1
+    pshufb         xm0, xm9
+    movu   [rpq+xq+64], xm0
+    add             xq, 5*16
+    ret
+
+INIT_ZMM avx512icl
+cglobal splat_mv, 4, 7, 3, rr, a, bx4, bw4, bh4
+    vbroadcasti32x4    m0, [aq]
+    lea                r1, [splat_mv_avx512icl_table]
+    tzcnt            bw4d, bw4d
+    lea              bx4d, [bx4q*3]
+    pshufb             m0, [splat_mv_shuf]
+    movsxd           bw4q, [r1+bw4q*4]
+    mov               r6d, bh4m
+    add              bw4q, r1
+    lea               rrq, [rrq+r6*8]
+    mov               r1d, 0x3f
+    neg                r6
+    kmovb              k1, r1d
+    jmp              bw4q
+.w1:
+    mov                r1, [rrq+r6*8]
+    vmovdqu16 [r1+bx4q*4]{k1}, xm0
+    inc                r6
+    jl .w1
+    RET
+.w2:
+    mov                r1, [rrq+r6*8]
+    vmovdqu32 [r1+bx4q*4]{k1}, ym0
+    inc                r6
+    jl .w2
+    RET
+.w4:
+    mov                r1, [rrq+r6*8]
+    vmovdqu64 [r1+bx4q*4]{k1}, m0
+    inc                r6
+    jl .w4
+    RET
+.w8:
+    pshufd            ym1, ym0, q1021
+.w8_loop:
+    mov                r1, [rrq+r6*8+0]
+    mov                r3, [rrq+r6*8+8]
+    movu   [r1+bx4q*4+ 0], m0
+    mova   [r1+bx4q*4+64], ym1
+    movu   [r3+bx4q*4+ 0], m0
+    mova   [r3+bx4q*4+64], ym1
+    add                r6, 2
+    jl .w8_loop
+    RET
+.w16:
+    pshufd             m1, m0, q1021
+    pshufd             m2, m0, q2102
+.w16_loop:
+    mov                r1, [rrq+r6*8+0]
+    mov                r3, [rrq+r6*8+8]
+    mova [r1+bx4q*4+64*0], m0
+    mova [r1+bx4q*4+64*1], m1
+    mova [r1+bx4q*4+64*2], m2
+    mova [r3+bx4q*4+64*0], m0
+    mova [r3+bx4q*4+64*1], m1
+    mova [r3+bx4q*4+64*2], m2
+    add                r6, 2
+    jl .w16_loop
+    RET
+.w32:
+    pshufd             m1, m0, q1021
+    pshufd             m2, m0, q2102
+.w32_loop:
+    mov                r1, [rrq+r6*8]
+    lea                r1, [r1+bx4q*4]
+    mova        [r1+64*0], m0
+    mova        [r1+64*1], m1
+    mova        [r1+64*2], m2
+    mova        [r1+64*3], m0
+    mova        [r1+64*4], m1
+    mova        [r1+64*5], m2
+    inc                r6
+    jl .w32_loop
+    RET
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/src/x86/refmvs.h b/media/libdav1d/src/src/x86/refmvs.h
new file mode 100644
index 0000000000..c9978561ec
--- /dev/null
+++ b/media/libdav1d/src/src/x86/refmvs.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * Copyright © 2021, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "src/cpu.h"
+#include "src/refmvs.h"
+
+decl_load_tmvs_fn(dav1d_load_tmvs_sse4);
+
+decl_save_tmvs_fn(dav1d_save_tmvs_ssse3);
+decl_save_tmvs_fn(dav1d_save_tmvs_avx2);
+decl_save_tmvs_fn(dav1d_save_tmvs_avx512icl);
+
+decl_splat_mv_fn(dav1d_splat_mv_sse2);
+decl_splat_mv_fn(dav1d_splat_mv_avx2);
+decl_splat_mv_fn(dav1d_splat_mv_avx512icl);
+
+static ALWAYS_INLINE void refmvs_dsp_init_x86(Dav1dRefmvsDSPContext *const c) {
+    const unsigned flags = dav1d_get_cpu_flags();
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSE2)) return;
+
+    c->splat_mv = dav1d_splat_mv_sse2;
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSSE3)) return;
+
+    c->save_tmvs = dav1d_save_tmvs_ssse3;
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_SSE41)) return;
+#if ARCH_X86_64
+    c->load_tmvs = dav1d_load_tmvs_sse4;
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX2)) return;
+
+    c->save_tmvs = dav1d_save_tmvs_avx2;
+    c->splat_mv = dav1d_splat_mv_avx2;
+
+    if (!(flags & DAV1D_X86_CPU_FLAG_AVX512ICL)) return;
+
+    c->save_tmvs = dav1d_save_tmvs_avx512icl;
+    c->splat_mv = dav1d_splat_mv_avx512icl;
+#endif
+}
diff --git a/media/libdav1d/src/tests/checkasm/arm/checkasm_32.S b/media/libdav1d/src/tests/checkasm/arm/checkasm_32.S
new file mode 100644
index 0000000000..c3df73cbc6
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/arm/checkasm_32.S
@@ -0,0 +1,201 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2015 Martin Storsjo
+ * Copyright © 2015 Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#define PRIVATE_PREFIX checkasm_
+
+#include "src/arm/asm.S"
+#include "src/arm/32/util.S"
+
+const register_init, align=3
+        .quad 0x21f86d66c8ca00ce
+        .quad 0x75b6ba21077c48ad
+        .quad 0xed56bb2dcb3c7736
+        .quad 0x8bda43d3fd1a7e06
+        .quad 0xb64a9c9e5d318408
+        .quad 0xdf9a54b303f1d3a3
+        .quad 0x4a75479abd64e097
+        .quad 0x249214109d5d1c88
+endconst
+
+const error_message_fpscr
+        .asciz "failed to preserve register FPSCR, changed bits: %x"
+error_message_gpr:
+        .asciz "failed to preserve register r%d"
+error_message_vfp:
+        .asciz "failed to preserve register d%d"
+error_message_stack:
+        .asciz "failed to preserve stack"
+endconst
+
+@ max number of args used by any asm function.
+#define MAX_ARGS 15
+
+#define ARG_STACK 4*(MAX_ARGS - 4)
+
+@ Align the used stack space to 8 to preserve the stack alignment.
+@ +8 for stack canary reference.
+#define ARG_STACK_A (((ARG_STACK + pushed + 7) & ~7) - pushed + 8)
+
+.macro clobbercheck variant
+.equ pushed, 4*9
+function checked_call_\variant, export=1
+        push            {r4-r11, lr}
+.ifc \variant, vfp
+        vpush           {d8-d15}
+        fmrx            r4,  FPSCR
+        push            {r4}
+.equ pushed, pushed + 16*4 + 4
+.endif
+
+        movrel          r12, register_init
+.ifc \variant, vfp
+        vldm            r12, {d8-d15}
+.endif
+        ldm             r12, {r4-r11}
+
+        sub             sp,  sp,  #ARG_STACK_A
+.equ pos, 0
+.rept MAX_ARGS-4
+        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + pos]
+        str             r12, [sp, #pos]
+.equ pos, pos + 4
+.endr
+
+        @ For stack overflows, the callee is free to overwrite the parameters
+        @ that were passed on the stack (if any), so we can only check after
+        @ that point. First figure out how many parameters the function
+        @ really took on the stack:
+        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + 4*(MAX_ARGS-4)]
+        @ Load the first non-parameter value from the stack, that should be
+        @ left untouched by the function. Store a copy of it inverted, so that
+        @ e.g. overwriting everything with zero would be noticed.
+        ldr             r12, [sp, r12, lsl #2]
+        mvn             r12, r12
+        str             r12, [sp, #ARG_STACK_A - 4]
+
+        mov             r12, r0
+        mov             r0,  r2
+        mov             r1,  r3
+        ldr             r2,  [sp, #ARG_STACK_A + pushed]
+        ldr             r3,  [sp, #ARG_STACK_A + pushed + 4]
+        @ Call the target function
+        v4blx           r12
+
+        @ Load the number of stack parameters, stack canary and its reference
+        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + 4*(MAX_ARGS-4)]
+        ldr             r2,  [sp, r12, lsl #2]
+        ldr             r3,  [sp, #ARG_STACK_A - 4]
+
+        add             sp,  sp,  #ARG_STACK_A
+        push            {r0, r1}
+
+        mvn             r3,  r3
+        cmp             r2,  r3
+        bne             5f
+
+        movrel          r12, register_init
+.ifc \variant, vfp
+.macro check_reg_vfp, dreg, offset
+        ldr             r2,  [r12, #(8 * (\offset))]
+        ldr             r3,  [r12, #(8 * (\offset)) + 4]
+        vmov            r0,  lr,  \dreg
+        eor             r2,  r2,  r0
+        eor             r3,  r3,  lr
+        orrs            r2,  r2,  r3
+        bne             4f
+.endm
+
+.irp n, 8, 9, 10, 11, 12, 13, 14, 15
+        @ keep track of the checked double/SIMD register
+        mov             r1,  #\n
+        check_reg_vfp   d\n, \n-8
+.endr
+.purgem check_reg_vfp
+
+        fmrx            r1,  FPSCR
+        ldr             r3,  [sp, #8]
+        eor             r1,  r1,  r3
+        @ Ignore changes in bits 0-4 and 7
+        bic             r1,  r1,  #0x9f
+        @ Ignore changes in the topmost 5 bits
+        bics            r1,  r1,  #0xf8000000
+        bne             3f
+.endif
+
+        @ keep track of the checked GPR
+        mov             r1,  #4
+.macro check_reg reg1, reg2=
+        ldr             r2,  [r12], #4
+        ldr             r3,  [r12], #4
+        eors            r2,  r2,  \reg1
+        bne             2f
+        add             r1,  r1,  #1
+.ifnb \reg2
+        eors            r3,  r3,  \reg2
+        bne             2f
+.endif
+        add             r1,  r1,  #1
+.endm
+        check_reg       r4,  r5
+        check_reg       r6,  r7
+@ r9 is a volatile register in the ios ABI
+#ifdef __APPLE__
+        check_reg       r8
+#else
+        check_reg       r8,  r9
+#endif
+        check_reg       r10, r11
+.purgem check_reg
+
+        b               0f
+5:
+        movrel          r0, error_message_stack
+        b               1f
+4:
+        movrel          r0, error_message_vfp
+        b               1f
+3:
+        movrel          r0, error_message_fpscr
+        b               1f
+2:
+        movrel          r0, error_message_gpr
+1:
+        bl              X(fail_func)
+0:
+        pop             {r0, r1}
+.ifc \variant, vfp
+        pop             {r2}
+        fmxr            FPSCR, r2
+        vpop            {d8-d15}
+.endif
+        pop             {r4-r11, pc}
+endfunc
+.endm
+
+clobbercheck novfp
+clobbercheck vfp
diff --git a/media/libdav1d/src/tests/checkasm/arm/checkasm_64.S b/media/libdav1d/src/tests/checkasm/arm/checkasm_64.S
new file mode 100644
index 0000000000..be7668ac61
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/arm/checkasm_64.S
@@ -0,0 +1,217 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2015 Martin Storsjo
+ * Copyright © 2015 Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#define PRIVATE_PREFIX checkasm_
+
+#include "src/arm/asm.S"
+#include "src/arm/64/util.S"
+
+const register_init, align=4
+        .quad 0x21f86d66c8ca00ce
+        .quad 0x75b6ba21077c48ad
+        .quad 0xed56bb2dcb3c7736
+        .quad 0x8bda43d3fd1a7e06
+        .quad 0xb64a9c9e5d318408
+        .quad 0xdf9a54b303f1d3a3
+        .quad 0x4a75479abd64e097
+        .quad 0x249214109d5d1c88
+        .quad 0x1a1b2550a612b48c
+        .quad 0x79445c159ce79064
+        .quad 0x2eed899d5a28ddcd
+        .quad 0x86b2536fcd8cf636
+        .quad 0xb0856806085e7943
+        .quad 0x3f2bf84fc0fcca4e
+        .quad 0xacbd382dcf5b8de2
+        .quad 0xd229e1f5b281303f
+        .quad 0x71aeaff20b095fd9
+        .quad 0xab63e2e11fa38ed9
+endconst
+
+
+const error_message_register
+        .asciz "failed to preserve register"
+error_message_stack:
+        .asciz "stack clobbered"
+endconst
+
+
+// max number of args used by any asm function.
+#define MAX_ARGS 15
+
+#define CLOBBER_STACK ((8*MAX_ARGS + 15) & ~15)
+
+function stack_clobber, export=1
+        mov             x3,  sp
+        mov             x2,  #CLOBBER_STACK
+1:
+        stp             x0,  x1,  [sp, #-16]!
+        subs            x2,  x2,  #16
+        b.gt            1b
+        mov             sp,  x3
+        ret
+endfunc
+
+// + 16 for stack canary reference
+#define ARG_STACK ((8*(MAX_ARGS - 8) + 15) & ~15 + 16)
+
+function checked_call, export=1
+        stp             x29, x30, [sp, #-16]!
+        mov             x29, sp
+        stp             x19, x20, [sp, #-16]!
+        stp             x21, x22, [sp, #-16]!
+        stp             x23, x24, [sp, #-16]!
+        stp             x25, x26, [sp, #-16]!
+        stp             x27, x28, [sp, #-16]!
+        stp             d8,  d9,  [sp, #-16]!
+        stp             d10, d11, [sp, #-16]!
+        stp             d12, d13, [sp, #-16]!
+        stp             d14, d15, [sp, #-16]!
+
+        movrel          x9, register_init
+        ldp             d8,  d9,  [x9], #16
+        ldp             d10, d11, [x9], #16
+        ldp             d12, d13, [x9], #16
+        ldp             d14, d15, [x9], #16
+        ldp             x19, x20, [x9], #16
+        ldp             x21, x22, [x9], #16
+        ldp             x23, x24, [x9], #16
+        ldp             x25, x26, [x9], #16
+        ldp             x27, x28, [x9], #16
+
+        sub             sp,  sp,  #ARG_STACK
+.equ pos, 0
+.rept MAX_ARGS-8
+        // Skip the first 8 args, that are loaded into registers
+        ldr             x9, [x29, #16 + 8*8 + pos]
+        str             x9, [sp, #pos]
+.equ pos, pos + 8
+.endr
+
+        // Fill x8-x17 with garbage. This doesn't have to be preserved,
+        // but avoids relying on them having any particular value.
+        movrel          x9, register_init
+        ldp             x10, x11, [x9], #32
+        ldp             x12, x13, [x9], #32
+        ldp             x14, x15, [x9], #32
+        ldp             x16, x17, [x9], #32
+        ldp             x8,  x9,  [x9]
+
+        // For stack overflows, the callee is free to overwrite the parameters
+        // that were passed on the stack (if any), so we can only check after
+        // that point. First figure out how many parameters the function
+        // really took on the stack:
+        ldr             w2,  [x29, #16 + 8*8 + (MAX_ARGS-8)*8]
+        // Load the first non-parameter value from the stack, that should be
+        // left untouched by the function. Store a copy of it inverted, so that
+        // e.g. overwriting everything with zero would be noticed.
+        ldr             x2,  [sp, x2, lsl #3]
+        mvn             x2,  x2
+        str             x2,  [sp, #ARG_STACK-8]
+
+        // Load the in-register arguments
+        mov             x12, x0
+        ldp             x0,  x1,  [x29, #16]
+        ldp             x2,  x3,  [x29, #32]
+        ldp             x4,  x5,  [x29, #48]
+        ldp             x6,  x7,  [x29, #64]
+        // Call the target function
+        blr             x12
+
+        // Load the number of stack parameters, stack canary and its reference
+        ldr             w2,  [x29, #16 + 8*8 + (MAX_ARGS-8)*8]
+        ldr             x2,  [sp, x2, lsl #3]
+        ldr             x3,  [sp, #ARG_STACK-8]
+
+        add             sp,  sp,  #ARG_STACK
+        stp             x0,  x1,  [sp, #-16]!
+
+        mvn             x3,  x3
+        cmp             x2,  x3
+        b.ne            2f
+
+        movrel          x9, register_init
+        movi            v3.8h,  #0
+
+.macro check_reg_neon reg1, reg2
+        ldr             q1,  [x9], #16
+        uzp1            v2.2d,  v\reg1\().2d, v\reg2\().2d
+        eor             v1.16b, v1.16b, v2.16b
+        orr             v3.16b, v3.16b, v1.16b
+.endm
+        check_reg_neon  8,  9
+        check_reg_neon  10, 11
+        check_reg_neon  12, 13
+        check_reg_neon  14, 15
+        uqxtn           v3.8b,  v3.8h
+        umov            x3,  v3.d[0]
+
+.macro check_reg reg1, reg2
+        ldp             x0,  x1,  [x9], #16
+        eor             x0,  x0,  \reg1
+        eor             x1,  x1,  \reg2
+        orr             x3,  x3,  x0
+        orr             x3,  x3,  x1
+.endm
+        check_reg       x19, x20
+        check_reg       x21, x22
+        check_reg       x23, x24
+        check_reg       x25, x26
+        check_reg       x27, x28
+
+        cbz             x3,  0f
+
+        movrel          x0, error_message_register
+        b               1f
+2:
+        movrel          x0, error_message_stack
+1:
+        bl              X(fail_func)
+0:
+        ldp             x0,  x1,  [sp], #16
+        ldp             d14, d15, [sp], #16
+        ldp             d12, d13, [sp], #16
+        ldp             d10, d11, [sp], #16
+        ldp             d8,  d9,  [sp], #16
+        ldp             x27, x28, [sp], #16
+        ldp             x25, x26, [sp], #16
+        ldp             x23, x24, [sp], #16
+        ldp             x21, x22, [sp], #16
+        ldp             x19, x20, [sp], #16
+        ldp             x29, x30, [sp], #16
+        ret
+endfunc
+
+#if HAVE_SVE
+ENABLE_SVE
+function sve_length, export=1
+        cntb            x0
+        lsl             x0,  x0,  #3
+        ret
+endfunc
+DISABLE_SVE
+#endif
diff --git a/media/libdav1d/src/tests/checkasm/cdef.c b/media/libdav1d/src/tests/checkasm/cdef.c
new file mode 100644
index 0000000000..b96339a6ba
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/cdef.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+
+#include 
+#include 
+
+#include "common/dump.h"
+
+#include "src/levels.h"
+#include "src/cdef.h"
+
+static int to_binary(int x) { /* 0-15 -> 0000-1111 */
+    return (x & 1) + 5 * (x & 2) + 25 * (x & 4) + 125 * (x & 8);
+}
+
+static void init_tmp(pixel *buf, int n, const int bitdepth_max) {
+    const int fill_type = rnd() & 7;
+    if (fill_type == 0)
+        while (n--) /* check for cdef_filter underflows */
+            *buf++ = rnd() & 1;
+    else if (fill_type == 1)
+        while (n--) /* check for cdef_filter overflows */
+            *buf++ = bitdepth_max - (rnd() & 1);
+    else
+        while (n--)
+            *buf++ = rnd() & bitdepth_max;
+}
+
+static void check_cdef_filter(const cdef_fn fn, const int w, const int h) {
+    ALIGN_STK_64(pixel, c_src,   16 * 10 + 16, ), *const c_dst = c_src + 8;
+    ALIGN_STK_64(pixel, a_src,   16 * 10 + 16, ), *const a_dst = a_src + 8;
+    ALIGN_STK_64(pixel, top_buf, 16 *  2 + 16, ), *const top = top_buf + 8;
+    ALIGN_STK_64(pixel, bot_buf, 16 *  2 + 16, ), *const bot = bot_buf + 8;
+    ALIGN_STK_16(pixel, left, 8,[2]);
+    const ptrdiff_t stride = 16 * sizeof(pixel);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel (*left)[2],
+                 const pixel *top, const pixel *bot, int pri_strength,
+                 int sec_strength, int dir, int damping,
+                 enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+    for (int s = 0x1; s <= 0x3; s++) {
+        if (check_func(fn, "cdef_filter_%dx%d_%02d_%dbpc", w, h, to_binary(s), BITDEPTH)) {
+            for (int dir = 0; dir < 8; dir++) {
+                for (enum CdefEdgeFlags edges = 0x0; edges <= 0xf; edges++) {
+#if BITDEPTH == 16
+                    const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                    const int bitdepth_max = 0xff;
+#endif
+                    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+
+                    init_tmp(c_src, 16 * 10 + 16, bitdepth_max);
+                    init_tmp(top_buf, 16 * 2 + 16, bitdepth_max);
+                    init_tmp(bot_buf, 16 * 2 + 16, bitdepth_max);
+                    init_tmp((pixel *) left, 8 * 2, bitdepth_max);
+                    memcpy(a_src, c_src, (16 * 10 + 16) * sizeof(pixel));
+
+                    const int pri_strength = s & 2 ? (1 + (rnd() % 15)) << bitdepth_min_8 : 0;
+                    const int sec_strength = s & 1 ? 1 << ((rnd() % 3) + bitdepth_min_8) : 0;
+                    const int damping = 3 + (rnd() & 3) + bitdepth_min_8 - (w == 4 || (rnd() & 1));
+                    call_ref(c_dst, stride, left, top, bot, pri_strength, sec_strength,
+                             dir, damping, edges HIGHBD_TAIL_SUFFIX);
+                    call_new(a_dst, stride, left, top, bot, pri_strength, sec_strength,
+                             dir, damping, edges HIGHBD_TAIL_SUFFIX);
+                    if (checkasm_check_pixel(c_dst, stride, a_dst, stride, w, h, "dst")) {
+                        fprintf(stderr, "strength = %d:%d, dir = %d, damping = %d, edges = %04d\n",
+                                pri_strength, sec_strength, dir, damping, to_binary(edges));
+                        return;
+                    }
+                    if (dir == 7 && (edges == 0x5 || edges == 0xa || edges == 0xf))
+                        bench_new(alternate(c_dst, a_dst), stride, left, top, bot, pri_strength,
+                                  sec_strength, dir, damping, edges HIGHBD_TAIL_SUFFIX);
+                }
+            }
+        }
+    }
+}
+
+static void check_cdef_direction(const cdef_dir_fn fn) {
+    ALIGN_STK_64(pixel, src, 8 * 8,);
+
+    declare_func(int, const pixel *src, ptrdiff_t dst_stride, unsigned *var
+                 HIGHBD_DECL_SUFFIX);
+
+    if (check_func(fn, "cdef_dir_%dbpc", BITDEPTH)) {
+        unsigned c_var, a_var;
+#if BITDEPTH == 16
+        const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+        const int bitdepth_max = 0xff;
+#endif
+        init_tmp(src, 64, bitdepth_max);
+
+        const int c_dir = call_ref(src, 8 * sizeof(pixel), &c_var HIGHBD_TAIL_SUFFIX);
+        const int a_dir = call_new(src, 8 * sizeof(pixel), &a_var HIGHBD_TAIL_SUFFIX);
+        if (c_var != a_var || c_dir != a_dir) {
+            if (fail()) {
+                hex_fdump(stderr, src, 8 * sizeof(pixel), 8, 8, "src");
+                fprintf(stderr, "c_dir %d a_dir %d\n", c_dir, a_dir);
+            }
+        }
+        bench_new(src, 8 * sizeof(pixel), &a_var HIGHBD_TAIL_SUFFIX);
+    }
+    report("cdef_dir");
+}
+
+void bitfn(checkasm_check_cdef)(void) {
+    Dav1dCdefDSPContext c;
+    bitfn(dav1d_cdef_dsp_init)(&c);
+
+    check_cdef_direction(c.dir);
+
+    check_cdef_filter(c.fb[0], 8, 8);
+    check_cdef_filter(c.fb[1], 4, 8);
+    check_cdef_filter(c.fb[2], 4, 4);
+    report("cdef_filter");
+}
diff --git a/media/libdav1d/src/tests/checkasm/checkasm.c b/media/libdav1d/src/tests/checkasm/checkasm.c
new file mode 100644
index 0000000000..6a6b8414d2
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/checkasm.c
@@ -0,0 +1,1139 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "tests/checkasm/checkasm.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "src/cpu.h"
+
+#ifdef _WIN32
+#ifndef SIGBUS
+/* non-standard, use the same value as mingw-w64 */
+#define SIGBUS 10
+#endif
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x04
+#endif
+#else
+#include 
+#if HAVE_UNISTD_H
+#include 
+#endif
+#if HAVE_PTHREAD_SETAFFINITY_NP
+#include 
+#if HAVE_PTHREAD_NP_H
+#include 
+#endif
+#endif
+#ifdef __APPLE__
+#include 
+#endif
+#endif
+#if CONFIG_MACOS_KPERF
+#include 
+#endif
+
+#define COLOR_RED    31
+#define COLOR_GREEN  32
+#define COLOR_YELLOW 33
+
+/* List of tests to invoke */
+static const struct {
+    const char *name;
+    void (*func)(void);
+} tests[] = {
+    { "msac", checkasm_check_msac },
+    { "pal", checkasm_check_pal },
+    { "refmvs", checkasm_check_refmvs },
+#if CONFIG_8BPC
+    { "cdef_8bpc", checkasm_check_cdef_8bpc },
+    { "filmgrain_8bpc", checkasm_check_filmgrain_8bpc },
+    { "ipred_8bpc", checkasm_check_ipred_8bpc },
+    { "itx_8bpc", checkasm_check_itx_8bpc },
+    { "loopfilter_8bpc", checkasm_check_loopfilter_8bpc },
+    { "looprestoration_8bpc", checkasm_check_looprestoration_8bpc },
+    { "mc_8bpc", checkasm_check_mc_8bpc },
+#endif
+#if CONFIG_16BPC
+    { "cdef_16bpc", checkasm_check_cdef_16bpc },
+    { "filmgrain_16bpc", checkasm_check_filmgrain_16bpc },
+    { "ipred_16bpc", checkasm_check_ipred_16bpc },
+    { "itx_16bpc", checkasm_check_itx_16bpc },
+    { "loopfilter_16bpc", checkasm_check_loopfilter_16bpc },
+    { "looprestoration_16bpc", checkasm_check_looprestoration_16bpc },
+    { "mc_16bpc", checkasm_check_mc_16bpc },
+#endif
+    { 0 }
+};
+
+/* List of cpu flags to check */
+static const struct {
+    const char *name;
+    const char *suffix;
+    unsigned flag;
+} cpus[] = {
+#if ARCH_X86
+    { "SSE2",               "sse2",      DAV1D_X86_CPU_FLAG_SSE2 },
+    { "SSSE3",              "ssse3",     DAV1D_X86_CPU_FLAG_SSSE3 },
+    { "SSE4.1",             "sse4",      DAV1D_X86_CPU_FLAG_SSE41 },
+    { "AVX2",               "avx2",      DAV1D_X86_CPU_FLAG_AVX2 },
+    { "AVX-512 (Ice Lake)", "avx512icl", DAV1D_X86_CPU_FLAG_AVX512ICL },
+#elif ARCH_AARCH64 || ARCH_ARM
+    { "NEON",               "neon",      DAV1D_ARM_CPU_FLAG_NEON },
+    { "DOTPROD",            "dotprod",   DAV1D_ARM_CPU_FLAG_DOTPROD },
+    { "I8MM",               "i8mm",      DAV1D_ARM_CPU_FLAG_I8MM },
+#if ARCH_AARCH64
+    { "SVE",                "sve",       DAV1D_ARM_CPU_FLAG_SVE },
+    { "SVE2",               "sve2",      DAV1D_ARM_CPU_FLAG_SVE2 },
+#endif /* ARCH_AARCH64 */
+#elif ARCH_LOONGARCH
+    { "LSX",                "lsx",       DAV1D_LOONGARCH_CPU_FLAG_LSX },
+    { "LASX",               "lasx",      DAV1D_LOONGARCH_CPU_FLAG_LASX },
+#elif ARCH_PPC64LE
+    { "VSX",                "vsx",       DAV1D_PPC_CPU_FLAG_VSX },
+    { "PWR9",               "pwr9",      DAV1D_PPC_CPU_FLAG_PWR9 },
+#elif ARCH_RISCV
+    { "RVV",                "rvv",       DAV1D_RISCV_CPU_FLAG_V },
+#endif
+    { 0 }
+};
+
+#if ARCH_AARCH64 && HAVE_SVE
+int checkasm_sve_length(void);
+#endif
+
+typedef struct CheckasmFuncVersion {
+    struct CheckasmFuncVersion *next;
+    void *func;
+    int ok;
+    unsigned cpu;
+    int iterations;
+    uint64_t cycles;
+} CheckasmFuncVersion;
+
+/* Binary search tree node */
+typedef struct CheckasmFunc {
+    struct CheckasmFunc *child[2];
+    CheckasmFuncVersion versions;
+    uint8_t color; /* 0 = red, 1 = black */
+    char name[];
+} CheckasmFunc;
+
+typedef enum {
+    RUN_NORMAL = 0,
+    RUN_BENCHMARK,
+    RUN_CPUFLAG_LISTING,
+    RUN_FUNCTION_LISTING,
+} CheckasmRunMode;
+
+/* Internal state */
+static struct {
+    CheckasmFunc *funcs;
+    CheckasmFunc *current_func;
+    CheckasmFuncVersion *current_func_ver;
+    const char *current_test_name;
+    int num_checked;
+    int num_failed;
+    double nop_time;
+    unsigned cpu_flag;
+    const char *cpu_flag_name;
+    const char *test_pattern;
+    const char *function_pattern;
+    unsigned seed;
+    CheckasmRunMode run_mode;
+    int verbose;
+    volatile sig_atomic_t sig; // SIG_ATOMIC_MAX = signal handling enabled
+    int suffix_length;
+    int max_function_name_length;
+#if ARCH_X86_64
+    void (*simd_warmup)(void);
+#endif
+} state;
+
+/* float compare support code */
+typedef union {
+    float f;
+    uint32_t i;
+} intfloat;
+
+static uint32_t xs_state[4];
+
+static void xor128_srand(unsigned seed) {
+    xs_state[0] = seed;
+    xs_state[1] = ( seed & 0xffff0000) | (~seed & 0x0000ffff);
+    xs_state[2] = (~seed & 0xffff0000) | ( seed & 0x0000ffff);
+    xs_state[3] = ~seed;
+}
+
+// xor128 from Marsaglia, George (July 2003). "Xorshift RNGs".
+//             Journal of Statistical Software. 8 (14).
+//             doi:10.18637/jss.v008.i14.
+int xor128_rand(void) {
+    const uint32_t x = xs_state[0];
+    const uint32_t t = x ^ (x << 11);
+
+    xs_state[0] = xs_state[1];
+    xs_state[1] = xs_state[2];
+    xs_state[2] = xs_state[3];
+    uint32_t w = xs_state[3];
+
+    w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
+    xs_state[3] = w;
+
+    return w >> 1;
+}
+
+#if CONFIG_MACOS_KPERF
+
+static int (*kpc_get_thread_counters)(int, unsigned int, void *);
+
+#define CFGWORD_EL0A64EN_MASK (0x20000)
+
+#define CPMU_CORE_CYCLE 0x02
+
+#define KPC_CLASS_FIXED_MASK        (1 << 0)
+#define KPC_CLASS_CONFIGURABLE_MASK (1 << 1)
+
+#define COUNTERS_COUNT 10
+#define CONFIG_COUNT 8
+#define KPC_MASK (KPC_CLASS_CONFIGURABLE_MASK | KPC_CLASS_FIXED_MASK)
+
+static int kperf_init(void) {
+    uint64_t config[COUNTERS_COUNT] = { 0 };
+
+    void *kperf = dlopen("/System/Library/PrivateFrameworks/kperf.framework/kperf", RTLD_LAZY);
+    if (!kperf) {
+        fprintf(stderr, "checkasm: Unable to load kperf: %s\n", dlerror());
+        return 1;
+    }
+
+    int (*kpc_force_all_ctrs_set)(int) = dlsym(kperf, "kpc_force_all_ctrs_set");
+    int (*kpc_set_counting)(uint32_t) = dlsym(kperf, "kpc_set_counting");
+    int (*kpc_set_thread_counting)(uint32_t) = dlsym(kperf, "kpc_set_thread_counting");
+    int (*kpc_set_config)(uint32_t, void *) = dlsym(kperf, "kpc_set_config");
+    uint32_t (*kpc_get_counter_count)(uint32_t) = dlsym(kperf, "kpc_get_counter_count");
+    uint32_t (*kpc_get_config_count)(uint32_t) = dlsym(kperf, "kpc_get_config_count");
+    kpc_get_thread_counters = dlsym(kperf, "kpc_get_thread_counters");
+
+    if (!kpc_get_thread_counters) {
+        fprintf(stderr, "checkasm: Unable to load kpc_get_thread_counters\n");
+        return 1;
+    }
+
+    if (!kpc_get_counter_count || kpc_get_counter_count(KPC_MASK) != COUNTERS_COUNT) {
+        fprintf(stderr, "checkasm: Unxpected kpc_get_counter_count\n");
+        return 1;
+    }
+    if (!kpc_get_config_count || kpc_get_config_count(KPC_MASK) != CONFIG_COUNT) {
+        fprintf(stderr, "checkasm: Unxpected kpc_get_config_count\n");
+        return 1;
+    }
+
+    config[0] = CPMU_CORE_CYCLE | CFGWORD_EL0A64EN_MASK;
+
+    if (!kpc_set_config || kpc_set_config(KPC_MASK, config)) {
+        fprintf(stderr, "checkasm: The kperf API needs to be run as root\n");
+        return 1;
+    }
+    if (!kpc_force_all_ctrs_set || kpc_force_all_ctrs_set(1)) {
+        fprintf(stderr, "checkasm: kpc_force_all_ctrs_set failed\n");
+        return 1;
+    }
+    if (!kpc_set_counting || kpc_set_counting(KPC_MASK)) {
+        fprintf(stderr, "checkasm: kpc_set_counting failed\n");
+        return 1;
+    }
+    if (!kpc_set_counting || kpc_set_thread_counting(KPC_MASK)) {
+        fprintf(stderr, "checkasm: kpc_set_thread_counting failed\n");
+        return 1;
+    }
+    return 0;
+}
+
+uint64_t checkasm_kperf_cycles(void) {
+    uint64_t counters[COUNTERS_COUNT];
+    if (kpc_get_thread_counters(0, COUNTERS_COUNT, counters))
+        return -1;
+
+    return counters[0];
+}
+#endif
+
+static int is_negative(const intfloat u) {
+    return u.i >> 31;
+}
+
+int float_near_ulp(const float a, const float b, const unsigned max_ulp) {
+    intfloat x, y;
+
+    x.f = a;
+    y.f = b;
+
+    if (is_negative(x) != is_negative(y)) {
+        // handle -0.0 == +0.0
+        return a == b;
+    }
+
+    if (llabs((int64_t)x.i - y.i) <= max_ulp)
+        return 1;
+
+    return 0;
+}
+
+int float_near_ulp_array(const float *const a, const float *const b,
+                         const unsigned max_ulp, const int len)
+{
+    for (int i = 0; i < len; i++)
+        if (!float_near_ulp(a[i], b[i], max_ulp))
+            return 0;
+
+    return 1;
+}
+
+int float_near_abs_eps(const float a, const float b, const float eps) {
+    return fabsf(a - b) < eps;
+}
+
+int float_near_abs_eps_array(const float *const a, const float *const b,
+                             const float eps, const int len)
+{
+    for (int i = 0; i < len; i++)
+        if (!float_near_abs_eps(a[i], b[i], eps))
+            return 0;
+
+    return 1;
+}
+
+int float_near_abs_eps_ulp(const float a, const float b, const float eps,
+                           const unsigned max_ulp)
+{
+    return float_near_ulp(a, b, max_ulp) || float_near_abs_eps(a, b, eps);
+}
+
+int float_near_abs_eps_array_ulp(const float *const a, const float *const b,
+                                 const float eps, const unsigned max_ulp,
+                                 const int len)
+{
+    for (int i = 0; i < len; i++)
+        if (!float_near_abs_eps_ulp(a[i], b[i], eps, max_ulp))
+            return 0;
+
+    return 1;
+}
+
+/* Print colored text to stderr if the terminal supports it */
+static int use_printf_color;
+static void color_fprintf(FILE *const f, const int color, const char *const fmt, ...) {
+    va_list arg;
+
+    if (use_printf_color)
+        fprintf(f, "\x1b[0;%dm", color);
+
+    va_start(arg, fmt);
+    vfprintf(f, fmt, arg);
+    va_end(arg);
+
+    if (use_printf_color)
+        fprintf(f, "\x1b[0m");
+}
+
+/* Deallocate a tree */
+static void destroy_func_tree(CheckasmFunc *const f) {
+    if (f) {
+        CheckasmFuncVersion *v = f->versions.next;
+        while (v) {
+            CheckasmFuncVersion *next = v->next;
+            free(v);
+            v = next;
+        }
+
+        destroy_func_tree(f->child[0]);
+        destroy_func_tree(f->child[1]);
+        free(f);
+    }
+}
+
+/* Allocate a zero-initialized block, clean up and exit on failure */
+static void *checkasm_malloc(const size_t size) {
+    void *const ptr = calloc(1, size);
+    if (!ptr) {
+        fprintf(stderr, "checkasm: malloc failed\n");
+        destroy_func_tree(state.funcs);
+        exit(1);
+    }
+    return ptr;
+}
+
+/* Get the suffix of the specified cpu flag */
+static const char *cpu_suffix(const unsigned cpu) {
+    for (int i = (int)(sizeof(cpus) / sizeof(*cpus)) - 2; i >= 0; i--)
+        if (cpu & cpus[i].flag)
+            return cpus[i].suffix;
+
+    return "c";
+}
+
+#ifdef readtime
+static int cmp_nop(const void *a, const void *b) {
+    return *(const uint16_t*)a - *(const uint16_t*)b;
+}
+
+/* Measure the overhead of the timing code (in decicycles) */
+static double measure_nop_time(void) {
+    uint16_t nops[10000];
+    int nop_sum = 0;
+
+    for (int i = 0; i < 10000; i++) {
+        uint64_t t = readtime();
+        nops[i] = (uint16_t) (readtime() - t);
+    }
+
+    qsort(nops, 10000, sizeof(uint16_t), cmp_nop);
+    for (int i = 2500; i < 7500; i++)
+        nop_sum += nops[i];
+
+    return nop_sum / 5000.0;
+}
+
+static double avg_cycles_per_call(const CheckasmFuncVersion *const v) {
+    if (v->iterations) {
+        const double cycles = (double)v->cycles / v->iterations - state.nop_time;
+        if (cycles > 0.0)
+            return cycles / 4.0; /* 4 calls per iteration */
+    }
+    return 0.0;
+}
+
+/* Print benchmark results */
+static void print_benchs(const CheckasmFunc *const f) {
+    if (f) {
+        print_benchs(f->child[0]);
+
+        const CheckasmFuncVersion *v = &f->versions;
+        if (v->iterations) {
+            const double baseline = avg_cycles_per_call(v);
+            do {
+                const int pad_length = 10 + state.max_function_name_length -
+                    printf("%s_%s:", f->name, cpu_suffix(v->cpu));
+                const double cycles = avg_cycles_per_call(v);
+                const double ratio = cycles ? baseline / cycles : 0.0;
+                printf("%*.1f (%5.2fx)\n", imax(pad_length, 0), cycles, ratio);
+            } while ((v = v->next));
+        }
+
+        print_benchs(f->child[1]);
+    }
+}
+#endif
+
+static void print_functions(const CheckasmFunc *const f) {
+    if (f) {
+        print_functions(f->child[0]);
+        const CheckasmFuncVersion *v = &f->versions;
+        printf("%s (%s", f->name, cpu_suffix(v->cpu));
+        while ((v = v->next))
+            printf(", %s", cpu_suffix(v->cpu));
+        printf(")\n");
+        print_functions(f->child[1]);
+    }
+}
+
+#define is_digit(x) ((x) >= '0' && (x) <= '9')
+
+/* ASCIIbetical sort except preserving natural order for numbers */
+static int cmp_func_names(const char *a, const char *b) {
+    const char *const start = a;
+    int ascii_diff, digit_diff;
+
+    for (; !(ascii_diff = *(const unsigned char*)a -
+                          *(const unsigned char*)b) && *a; a++, b++);
+    for (; is_digit(*a) && is_digit(*b); a++, b++);
+
+    if (a > start && is_digit(a[-1]) &&
+        (digit_diff = is_digit(*a) - is_digit(*b)))
+    {
+        return digit_diff;
+    }
+
+    return ascii_diff;
+}
+
+/* Perform a tree rotation in the specified direction and return the new root */
+static CheckasmFunc *rotate_tree(CheckasmFunc *const f, const int dir) {
+    CheckasmFunc *const r = f->child[dir^1];
+    f->child[dir^1] = r->child[dir];
+    r->child[dir] = f;
+    r->color = f->color;
+    f->color = 0;
+    return r;
+}
+
+#define is_red(f) ((f) && !(f)->color)
+
+/* Balance a left-leaning red-black tree at the specified node */
+static void balance_tree(CheckasmFunc **const root) {
+    CheckasmFunc *const f = *root;
+
+    if (is_red(f->child[0]) && is_red(f->child[1])) {
+        f->color ^= 1;
+        f->child[0]->color = f->child[1]->color = 1;
+    }
+    else if (!is_red(f->child[0]) && is_red(f->child[1]))
+        *root = rotate_tree(f, 0); /* Rotate left */
+    else if (is_red(f->child[0]) && is_red(f->child[0]->child[0]))
+        *root = rotate_tree(f, 1); /* Rotate right */
+}
+
+/* Get a node with the specified name, creating it if it doesn't exist */
+static CheckasmFunc *get_func(CheckasmFunc **const root, const char *const name) {
+    CheckasmFunc *f = *root;
+
+    if (f) {
+        /* Search the tree for a matching node */
+        const int cmp = cmp_func_names(name, f->name);
+        if (cmp) {
+            f = get_func(&f->child[cmp > 0], name);
+
+            /* Rebalance the tree on the way up if a new node was inserted */
+            if (!f->versions.func)
+                balance_tree(root);
+        }
+    } else {
+        /* Allocate and insert a new node into the tree */
+        const size_t name_length = strlen(name) + 1;
+        f = *root = checkasm_malloc(offsetof(CheckasmFunc, name) + name_length);
+        memcpy(f->name, name, name_length);
+    }
+
+    return f;
+}
+
+checkasm_context checkasm_context_buf;
+
+/* Crash handling: attempt to catch crashes and handle them
+ * gracefully instead of just aborting abruptly. */
+#ifdef _WIN32
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+static LONG NTAPI signal_handler(EXCEPTION_POINTERS *const e) {
+    if (state.sig == SIG_ATOMIC_MAX) {
+        int s;
+        switch (e->ExceptionRecord->ExceptionCode) {
+        case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+        case EXCEPTION_INT_DIVIDE_BY_ZERO:
+            s = SIGFPE;
+            break;
+        case EXCEPTION_ILLEGAL_INSTRUCTION:
+        case EXCEPTION_PRIV_INSTRUCTION:
+            s = SIGILL;
+            break;
+        case EXCEPTION_ACCESS_VIOLATION:
+        case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+        case EXCEPTION_DATATYPE_MISALIGNMENT:
+        case EXCEPTION_STACK_OVERFLOW:
+            s = SIGSEGV;
+            break;
+        case EXCEPTION_IN_PAGE_ERROR:
+            s = SIGBUS;
+            break;
+        default:
+            return EXCEPTION_CONTINUE_SEARCH;
+        }
+        state.sig = s;
+        checkasm_load_context();
+    }
+    return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif
+#else
+static void signal_handler(int s);
+
+static const struct sigaction signal_handler_act = {
+    .sa_handler = signal_handler,
+    .sa_flags = SA_RESETHAND,
+};
+
+static void signal_handler(const int s) {
+    if (state.sig == SIG_ATOMIC_MAX) {
+        state.sig = s;
+        sigaction(s, &signal_handler_act, NULL);
+        checkasm_load_context();
+    }
+}
+#endif
+
+/* Compares a string with a wildcard pattern. */
+static int wildstrcmp(const char *str, const char *pattern) {
+    const char *wild = strchr(pattern, '*');
+    if (wild) {
+        const size_t len = wild - pattern;
+        if (strncmp(str, pattern, len)) return 1;
+        while (*++wild == '*');
+        if (!*wild) return 0;
+        str += len;
+        while (*str && wildstrcmp(str, wild)) str++;
+        return !*str;
+    }
+    return strcmp(str, pattern);
+}
+
+/* Perform tests and benchmarks for the specified
+ * cpu flag if supported by the host */
+static void check_cpu_flag(const char *const name, unsigned flag) {
+    const unsigned old_cpu_flag = state.cpu_flag;
+
+    flag |= old_cpu_flag;
+    dav1d_set_cpu_flags_mask(flag);
+    state.cpu_flag = dav1d_get_cpu_flags();
+
+    if (!flag || state.cpu_flag != old_cpu_flag) {
+        state.cpu_flag_name = name;
+        state.suffix_length = (int)strlen(cpu_suffix(flag)) + 1;
+        for (int i = 0; tests[i].func; i++) {
+            if (state.test_pattern && wildstrcmp(tests[i].name, state.test_pattern))
+                continue;
+            xor128_srand(state.seed);
+            state.current_test_name = tests[i].name;
+            tests[i].func();
+        }
+    }
+}
+
+/* Print the name of the current CPU flag, but only do it once */
+static void print_cpu_name(void) {
+    if (state.cpu_flag_name) {
+        color_fprintf(stderr, COLOR_YELLOW, "%s:\n", state.cpu_flag_name);
+        state.cpu_flag_name = NULL;
+    }
+}
+
+static unsigned get_seed(void) {
+#ifdef _WIN32
+    LARGE_INTEGER i;
+    QueryPerformanceCounter(&i);
+    return i.LowPart;
+#elif defined(__APPLE__)
+    return (unsigned) mach_absolute_time();
+#else
+    struct timespec ts;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    return (unsigned) (1000000000ULL * ts.tv_sec + ts.tv_nsec);
+#endif
+}
+
+static int checkasm_strtoul(unsigned long *const dst, const char *const str, const int base) {
+    char *end;
+    errno = 0;
+    *dst = strtoul(str, &end, base);
+    return errno || end == str || *end;
+}
+
+int main(int argc, char *argv[]) {
+    state.seed = get_seed();
+
+    while (argc > 1) {
+        if (!strncmp(argv[1], "--help", 6) || !strcmp(argv[1], "-h")) {
+            fprintf(stderr,
+                    "checkasm [options] \n"
+                    "                  Numeric value to seed the rng\n"
+                    "Options:\n"
+                    "    --affinity=           Run the process on CPU \n"
+                    "    --test= -t        Test only \n"
+                    "    --function= -f    Test only the functions matching \n"
+                    "    --bench -b                 Benchmark the tested functions\n"
+                    "    --list-cpuflags            List available cpu flags\n"
+                    "    --list-functions           List available functions\n"
+                    "    --list-tests               List available tests\n"
+                    "    --verbose -v               Print verbose output\n");
+            return 0;
+        } else if (!strcmp(argv[1], "--bench") || !strcmp(argv[1], "-b")) {
+#ifndef readtime
+            fprintf(stderr,
+                    "checkasm: --bench is not supported on your system\n");
+            return 1;
+#endif
+            state.run_mode = RUN_BENCHMARK;
+        } else if (!strncmp(argv[1], "--test=", 7)) {
+            state.test_pattern = argv[1] + 7;
+        } else if (!strcmp(argv[1], "-t")) {
+            state.test_pattern = argc > 1 ? argv[2] : "";
+            argc--;
+            argv++;
+        } else if (!strncmp(argv[1], "--function=", 11)) {
+            state.function_pattern = argv[1] + 11;
+        } else if (!strcmp(argv[1], "-f")) {
+            state.function_pattern = argc > 1 ? argv[2] : "";
+            argc--;
+            argv++;
+        } else if (!strcmp(argv[1], "--list-cpuflags")) {
+            state.run_mode = RUN_CPUFLAG_LISTING;
+            break;
+        } else if (!strcmp(argv[1], "--list-functions")) {
+            state.run_mode = RUN_FUNCTION_LISTING;
+        } else if (!strcmp(argv[1], "--list-tests")) {
+            for (int i = 0; tests[i].name; i++)
+                printf("%s\n", tests[i].name);
+            return 0;
+        } else if (!strcmp(argv[1], "--verbose") || !strcmp(argv[1], "-v")) {
+            state.verbose = 1;
+        } else if (!strncmp(argv[1], "--affinity=", 11)) {
+            const char *const s = argv[1] + 11;
+            unsigned long affinity;
+            if (checkasm_strtoul(&affinity, s, 16)) {
+                fprintf(stderr, "checkasm: invalid cpu affinity (%s)\n", s);
+                return 1;
+            }
+#ifdef _WIN32
+            int affinity_err;
+            HANDLE process = GetCurrentProcess();
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+            BOOL (WINAPI *spdcs)(HANDLE, const ULONG*, ULONG) =
+                (void*)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetProcessDefaultCpuSets");
+            if (spdcs)
+                affinity_err = !spdcs(process, (ULONG[]){ affinity + 256 }, 1);
+            else
+#endif
+            {
+                if (affinity < sizeof(DWORD_PTR) * 8)
+                    affinity_err = !SetProcessAffinityMask(process, (DWORD_PTR)1 << affinity);
+                else
+                    affinity_err = 1;
+            }
+            if (affinity_err) {
+                fprintf(stderr, "checkasm: invalid cpu affinity (%lu)\n", affinity);
+                return 1;
+            } else {
+                fprintf(stderr, "checkasm: running on cpu %lu\n", affinity);
+            }
+#elif HAVE_PTHREAD_SETAFFINITY_NP && defined(CPU_SET)
+            cpu_set_t set;
+            CPU_ZERO(&set);
+            CPU_SET(affinity, &set);
+            if (pthread_setaffinity_np(pthread_self(), sizeof(set), &set)) {
+                fprintf(stderr, "checkasm: invalid cpu affinity (%lu)\n", affinity);
+                return 1;
+            } else {
+                fprintf(stderr, "checkasm: running on cpu %lu\n", affinity);
+            }
+#else
+            (void)affinity;
+            fprintf(stderr,
+                    "checkasm: --affinity is not supported on your system\n");
+            return 1;
+#endif
+        } else {
+            unsigned long seed;
+            if (checkasm_strtoul(&seed, argv[1], 10)) {
+                fprintf(stderr, "checkasm: unknown option (%s)\n", argv[1]);
+                return 1;
+            }
+            state.seed = (unsigned)seed;
+        }
+
+        argc--;
+        argv++;
+    }
+
+#if TRIM_DSP_FUNCTIONS
+    fprintf(stderr, "checkasm: reference functions unavailable, reconfigure using '-Dtrim_dsp=false'\n");
+    return 0;
+#endif
+
+    dav1d_init_cpu();
+
+#ifdef _WIN32
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+    AddVectoredExceptionHandler(0, signal_handler);
+
+    HANDLE con = GetStdHandle(state.run_mode >= RUN_CPUFLAG_LISTING ?
+                              STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
+    DWORD con_mode = 0;
+    use_printf_color = con && con != INVALID_HANDLE_VALUE &&
+                       GetConsoleMode(con, &con_mode) &&
+                       SetConsoleMode(con, con_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
+#endif
+#else
+    sigaction(SIGBUS,  &signal_handler_act, NULL);
+    sigaction(SIGFPE,  &signal_handler_act, NULL);
+    sigaction(SIGILL,  &signal_handler_act, NULL);
+    sigaction(SIGSEGV, &signal_handler_act, NULL);
+
+    if (isatty(state.run_mode >= RUN_CPUFLAG_LISTING ? 1 : 2)) {
+        const char *const term = getenv("TERM");
+        use_printf_color = term && strcmp(term, "dumb");
+    }
+#endif
+
+#ifdef readtime
+    if (state.run_mode == RUN_BENCHMARK) {
+#if CONFIG_MACOS_KPERF
+        if (kperf_init())
+            return 1;
+#endif
+        if (!checkasm_save_context()) {
+            checkasm_set_signal_handler_state(1);
+            readtime();
+            checkasm_set_signal_handler_state(0);
+        } else {
+            fprintf(stderr, "checkasm: unable to access cycle counter\n");
+            return 1;
+        }
+    }
+#endif
+
+    int ret = 0;
+
+    if (state.run_mode != RUN_FUNCTION_LISTING) {
+        const unsigned cpu_flags = dav1d_get_cpu_flags();
+        if (state.run_mode == RUN_CPUFLAG_LISTING) {
+            const int last_i = (int)(sizeof(cpus) / sizeof(*cpus)) - 2;
+            for (int i = 0; i <= last_i ; i++) {
+                if (cpus[i].flag & cpu_flags)
+                    color_fprintf(stdout, COLOR_GREEN, "%s", cpus[i].suffix);
+                else
+                    color_fprintf(stdout, COLOR_RED, "~%s", cpus[i].suffix);
+                printf(i == last_i ? "\n" : ", ");
+            }
+            return 0;
+        }
+#if ARCH_X86_64
+        void checkasm_warmup_avx2(void);
+        void checkasm_warmup_avx512(void);
+        if (cpu_flags & DAV1D_X86_CPU_FLAG_AVX512ICL)
+            state.simd_warmup = checkasm_warmup_avx512;
+        else if (cpu_flags & DAV1D_X86_CPU_FLAG_AVX2)
+            state.simd_warmup = checkasm_warmup_avx2;
+        checkasm_simd_warmup();
+#endif
+#if ARCH_ARM
+        void checkasm_checked_call_vfp(void *func, int dummy, ...);
+        void checkasm_checked_call_novfp(void *func, int dummy, ...);
+        if (cpu_flags & DAV1D_ARM_CPU_FLAG_NEON)
+            checkasm_checked_call_ptr = checkasm_checked_call_vfp;
+        else
+            checkasm_checked_call_ptr = checkasm_checked_call_novfp;
+#endif
+#if ARCH_X86
+        unsigned checkasm_init_x86(char *name);
+        char name[48];
+        const unsigned cpuid = checkasm_init_x86(name);
+        for (size_t len = strlen(name); len && name[len-1] == ' '; len--)
+            name[len-1] = '\0'; /* trim trailing whitespace */
+        fprintf(stderr, "checkasm: %s (%08X) using random seed %u\n", name, cpuid, state.seed);
+#elif ARCH_RISCV
+        char buf[32] = "";
+        if (cpu_flags & DAV1D_RISCV_CPU_FLAG_V)
+            snprintf(buf, sizeof(buf), "VLEN=%i bits, ", dav1d_get_vlen());
+        fprintf(stderr, "checkasm: %susing random seed %u\n", buf, state.seed);
+#elif ARCH_AARCH64 && HAVE_SVE
+        char buf[48] = "";
+        if (cpu_flags & DAV1D_ARM_CPU_FLAG_SVE)
+            snprintf(buf, sizeof(buf), "SVE %d bits, ", checkasm_sve_length());
+        fprintf(stderr, "checkasm: %susing random seed %u\n", buf, state.seed);
+#else
+        fprintf(stderr, "checkasm: using random seed %u\n", state.seed);
+#endif
+    }
+
+    check_cpu_flag(NULL, 0);
+    for (int i = 0; cpus[i].flag; i++)
+        check_cpu_flag(cpus[i].name, cpus[i].flag);
+
+    if (state.run_mode == RUN_FUNCTION_LISTING) {
+        print_functions(state.funcs);
+    } else if (state.num_failed) {
+        fprintf(stderr, "checkasm: %d of %d tests failed\n",
+                state.num_failed, state.num_checked);
+        ret = 1;
+    } else {
+        if (state.num_checked)
+            fprintf(stderr, "checkasm: all %d tests passed\n", state.num_checked);
+        else
+            fprintf(stderr, "checkasm: no tests to perform\n");
+#ifdef readtime
+        if (state.run_mode == RUN_BENCHMARK && state.max_function_name_length) {
+            state.nop_time = measure_nop_time();
+            if (state.verbose)
+                printf("nop:%*.1f\n", state.max_function_name_length + 6, state.nop_time);
+            print_benchs(state.funcs);
+        }
+#endif
+    }
+
+    destroy_func_tree(state.funcs);
+    return ret;
+}
+
+/* Decide whether or not the specified function needs to be tested and
+ * allocate/initialize data structures if needed. Returns a pointer to a
+ * reference function if the function should be tested, otherwise NULL */
+void *checkasm_check_func(void *const func, const char *const name, ...) {
+    char name_buf[256];
+    va_list arg;
+
+    va_start(arg, name);
+    int name_length = vsnprintf(name_buf, sizeof(name_buf), name, arg);
+    va_end(arg);
+
+    if (!func || name_length <= 0 || (size_t)name_length >= sizeof(name_buf) ||
+        (state.function_pattern && wildstrcmp(name_buf, state.function_pattern)))
+    {
+        return NULL;
+    }
+
+    state.current_func = get_func(&state.funcs, name_buf);
+
+    state.funcs->color = 1;
+    CheckasmFuncVersion *v = &state.current_func->versions;
+    void *ref = func;
+
+    if (v->func) {
+        CheckasmFuncVersion *prev;
+        do {
+            /* Only test functions that haven't already been tested */
+            if (v->func == func)
+                return NULL;
+
+            if (v->ok)
+                ref = v->func;
+
+            prev = v;
+        } while ((v = v->next));
+
+        v = prev->next = checkasm_malloc(sizeof(CheckasmFuncVersion));
+    }
+
+    name_length += state.suffix_length;
+    if (name_length > state.max_function_name_length)
+        state.max_function_name_length = name_length;
+
+    v->func = func;
+    v->ok = 1;
+    v->cpu = state.cpu_flag;
+    state.current_func_ver = v;
+    if (state.run_mode == RUN_FUNCTION_LISTING) /* Save function names without running tests */
+        return NULL;
+
+    xor128_srand(state.seed);
+
+    if (state.cpu_flag)
+        state.num_checked++;
+
+    return ref;
+}
+
+/* Decide whether or not the current function needs to be benchmarked */
+int checkasm_bench_func(void) {
+    return !state.num_failed && state.run_mode == RUN_BENCHMARK;
+}
+
+/* Indicate that the current test has failed, return whether verbose printing
+ * is requested. */
+int checkasm_fail_func(const char *const msg, ...) {
+    if (state.current_func_ver && state.current_func_ver->cpu &&
+        state.current_func_ver->ok)
+    {
+        va_list arg;
+
+        print_cpu_name();
+        fprintf(stderr, "   %s_%s (", state.current_func->name,
+                cpu_suffix(state.current_func_ver->cpu));
+        va_start(arg, msg);
+        vfprintf(stderr, msg, arg);
+        va_end(arg);
+        fprintf(stderr, ")\n");
+
+        state.current_func_ver->ok = 0;
+        state.num_failed++;
+    }
+    return state.verbose;
+}
+
+/* Update benchmark results of the current function */
+void checkasm_update_bench(const int iterations, const uint64_t cycles) {
+    state.current_func_ver->iterations += iterations;
+    state.current_func_ver->cycles += cycles;
+}
+
+/* Print the outcome of all tests performed since
+ * the last time this function was called */
+void checkasm_report(const char *const name, ...) {
+    static int prev_checked, prev_failed;
+    static size_t max_length;
+
+    if (state.num_checked > prev_checked) {
+        int pad_length = (int) max_length + 4;
+        va_list arg;
+
+        print_cpu_name();
+        pad_length -= fprintf(stderr, " - %s.", state.current_test_name);
+        va_start(arg, name);
+        pad_length -= vfprintf(stderr, name, arg);
+        va_end(arg);
+        fprintf(stderr, "%*c", imax(pad_length, 0) + 2, '[');
+
+        if (state.num_failed == prev_failed)
+            color_fprintf(stderr, COLOR_GREEN, "OK");
+        else
+            color_fprintf(stderr, COLOR_RED, "FAILED");
+        fprintf(stderr, "]\n");
+
+        prev_checked = state.num_checked;
+        prev_failed  = state.num_failed;
+    } else if (!state.cpu_flag) {
+        /* Calculate the amount of padding required
+         * to make the output vertically aligned */
+        size_t length = strlen(state.current_test_name);
+        va_list arg;
+
+        va_start(arg, name);
+        length += vsnprintf(NULL, 0, name, arg);
+        va_end(arg);
+
+        if (length > max_length)
+            max_length = length;
+    }
+}
+
+void checkasm_set_signal_handler_state(const int enabled) {
+    state.sig = enabled ? SIG_ATOMIC_MAX : 0;
+}
+
+void checkasm_handle_signal(void) {
+    const int s = state.sig;
+    checkasm_fail_func(s == SIGFPE ? "fatal arithmetic error" :
+                       s == SIGILL ? "illegal instruction" :
+                       s == SIGBUS ? "bus error" :
+                                     "segmentation fault");
+}
+
+static int check_err(const char *const file, const int line,
+                     const char *const name, const int w, const int h,
+                     int *const err)
+{
+    if (*err)
+        return 0;
+    if (!checkasm_fail_func("%s:%d", file, line))
+        return 1;
+    *err = 1;
+    fprintf(stderr, "%s (%dx%d):\n", name, w, h);
+    return 0;
+}
+
+#define DEF_CHECKASM_CHECK_FUNC(type, fmt) \
+int checkasm_check_##type(const char *const file, const int line, \
+                          const type *buf1, ptrdiff_t stride1, \
+                          const type *buf2, ptrdiff_t stride2, \
+                          const int w, int h, const char *const name, \
+                          const int align_w, const int align_h, \
+                          const int padding) \
+{ \
+    int aligned_w = (w + align_w - 1) & ~(align_w - 1); \
+    int aligned_h = (h + align_h - 1) & ~(align_h - 1); \
+    int err = 0; \
+    stride1 /= sizeof(*buf1); \
+    stride2 /= sizeof(*buf2); \
+    int y = 0; \
+    for (y = 0; y < h; y++) \
+        if (memcmp(&buf1[y*stride1], &buf2[y*stride2], w*sizeof(*buf1))) \
+            break; \
+    if (y != h) { \
+        if (check_err(file, line, name, w, h, &err)) \
+            return 1; \
+        for (y = 0; y < h; y++) { \
+            for (int x = 0; x < w; x++) \
+                fprintf(stderr, " " fmt, buf1[x]); \
+            fprintf(stderr, "    "); \
+            for (int x = 0; x < w; x++) \
+                fprintf(stderr, " " fmt, buf2[x]); \
+            fprintf(stderr, "    "); \
+            for (int x = 0; x < w; x++) \
+                fprintf(stderr, "%c", buf1[x] != buf2[x] ? 'x' : '.'); \
+            buf1 += stride1; \
+            buf2 += stride2; \
+            fprintf(stderr, "\n"); \
+        } \
+        buf1 -= h*stride1; \
+        buf2 -= h*stride2; \
+    } \
+    for (y = -padding; y < 0; y++) \
+        if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
+                   (w + 2*padding)*sizeof(*buf1))) { \
+            if (check_err(file, line, name, w, h, &err)) \
+                return 1; \
+            fprintf(stderr, " overwrite above\n"); \
+            break; \
+        } \
+    for (y = aligned_h; y < aligned_h + padding; y++) \
+        if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
+                   (w + 2*padding)*sizeof(*buf1))) { \
+            if (check_err(file, line, name, w, h, &err)) \
+                return 1; \
+            fprintf(stderr, " overwrite below\n"); \
+            break; \
+        } \
+    for (y = 0; y < h; y++) \
+        if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
+                   padding*sizeof(*buf1))) { \
+            if (check_err(file, line, name, w, h, &err)) \
+                return 1; \
+            fprintf(stderr, " overwrite left\n"); \
+            break; \
+        } \
+    for (y = 0; y < h; y++) \
+        if (memcmp(&buf1[y*stride1 + aligned_w], &buf2[y*stride2 + aligned_w], \
+                   padding*sizeof(*buf1))) { \
+            if (check_err(file, line, name, w, h, &err)) \
+                return 1; \
+            fprintf(stderr, " overwrite right\n"); \
+            break; \
+        } \
+    return err; \
+}
+
+DEF_CHECKASM_CHECK_FUNC(int8_t,   "%4d")
+DEF_CHECKASM_CHECK_FUNC(int16_t,  "%6d")
+DEF_CHECKASM_CHECK_FUNC(int32_t,  "%9d")
+DEF_CHECKASM_CHECK_FUNC(uint8_t,  "%02x")
+DEF_CHECKASM_CHECK_FUNC(uint16_t, "%04x")
+DEF_CHECKASM_CHECK_FUNC(uint32_t, "%08x")
+
+#if ARCH_X86_64
+void checkasm_simd_warmup(void)
+{
+    if (state.simd_warmup)
+        state.simd_warmup();
+}
+#endif
+
+#if ARCH_ARM
+void (*checkasm_checked_call_ptr)(void *func, int dummy, ...);
+#endif
diff --git a/media/libdav1d/src/tests/checkasm/checkasm.h b/media/libdav1d/src/tests/checkasm/checkasm.h
new file mode 100644
index 0000000000..30a9844d98
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/checkasm.h
@@ -0,0 +1,458 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_TESTS_CHECKASM_CHECKASM_H
+#define DAV1D_TESTS_CHECKASM_CHECKASM_H
+
+#include "config.h"
+
+#include 
+#include 
+
+#ifdef _WIN32
+#include 
+#if ARCH_X86_32
+#include 
+typedef jmp_buf checkasm_context;
+#define checkasm_save_context() setjmp(checkasm_context_buf)
+#define checkasm_load_context() longjmp(checkasm_context_buf, 1)
+#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+/* setjmp/longjmp on Windows on architectures using SEH (all except x86_32)
+ * will try to use SEH to unwind the stack, which doesn't work for assembly
+ * functions without unwind information. */
+typedef struct { CONTEXT c; int status; } checkasm_context;
+#define checkasm_save_context() \
+    (checkasm_context_buf.status = 0, \
+     RtlCaptureContext(&checkasm_context_buf.c), \
+     checkasm_context_buf.status)
+#define checkasm_load_context() \
+    (checkasm_context_buf.status = 1, \
+     RtlRestoreContext(&checkasm_context_buf.c, NULL))
+#else
+typedef void* checkasm_context;
+#define checkasm_save_context() 0
+#define checkasm_load_context() do {} while (0)
+#endif
+#else
+#include 
+typedef sigjmp_buf checkasm_context;
+#define checkasm_save_context() sigsetjmp(checkasm_context_buf, 1)
+#define checkasm_load_context() siglongjmp(checkasm_context_buf, 1)
+#endif
+
+#include "include/common/attributes.h"
+#include "include/common/bitdepth.h"
+#include "include/common/intops.h"
+
+#if ARCH_ARM
+#include "src/arm/arm-arch.h"
+#endif
+
+int xor128_rand(void);
+#define rnd xor128_rand
+
+#define decl_check_bitfns(name) \
+name##_8bpc(void); \
+name##_16bpc(void)
+
+void checkasm_check_msac(void);
+void checkasm_check_pal(void);
+void checkasm_check_refmvs(void);
+decl_check_bitfns(void checkasm_check_cdef);
+decl_check_bitfns(void checkasm_check_filmgrain);
+decl_check_bitfns(void checkasm_check_ipred);
+decl_check_bitfns(void checkasm_check_itx);
+decl_check_bitfns(void checkasm_check_loopfilter);
+decl_check_bitfns(void checkasm_check_looprestoration);
+decl_check_bitfns(void checkasm_check_mc);
+
+void *checkasm_check_func(void *func, const char *name, ...);
+int checkasm_bench_func(void);
+int checkasm_fail_func(const char *msg, ...);
+void checkasm_update_bench(int iterations, uint64_t cycles);
+void checkasm_report(const char *name, ...);
+void checkasm_set_signal_handler_state(int enabled);
+void checkasm_handle_signal(void);
+extern checkasm_context checkasm_context_buf;
+
+/* float compare utilities */
+int float_near_ulp(float a, float b, unsigned max_ulp);
+int float_near_abs_eps(float a, float b, float eps);
+int float_near_abs_eps_ulp(float a, float b, float eps, unsigned max_ulp);
+int float_near_ulp_array(const float *a, const float *b, unsigned max_ulp,
+                         int len);
+int float_near_abs_eps_array(const float *a, const float *b, float eps,
+                             int len);
+int float_near_abs_eps_array_ulp(const float *a, const float *b, float eps,
+                                 unsigned max_ulp, int len);
+
+#define BENCH_RUNS (1 << 12) /* Trade-off between accuracy and speed */
+
+/* Decide whether or not the specified function needs to be tested */
+#define check_func(func, ...)\
+    (func_ref = checkasm_check_func((func_new = func), __VA_ARGS__))
+
+/* Declare the function prototype. The first argument is the return value,
+ * the remaining arguments are the function parameters. Naming parameters
+ * is optional. */
+#define declare_func(ret, ...)\
+    declare_new(ret, __VA_ARGS__)\
+    void *func_ref, *func_new;\
+    typedef ret func_type(__VA_ARGS__);\
+    if (checkasm_save_context()) checkasm_handle_signal()
+
+/* Indicate that the current test has failed */
+#define fail() checkasm_fail_func("%s:%d", __FILE__, __LINE__)
+
+/* Print the test outcome */
+#define report checkasm_report
+
+/* Call the reference function */
+#define call_ref(...)\
+    (checkasm_set_signal_handler_state(1),\
+     ((func_type *)func_ref)(__VA_ARGS__));\
+    checkasm_set_signal_handler_state(0)
+
+#if HAVE_ASM
+#if ARCH_X86
+#if defined(_MSC_VER) && !defined(__clang__)
+#include 
+#define readtime() (_mm_lfence(), __rdtsc())
+#else
+static inline uint64_t readtime(void) {
+    uint32_t eax, edx;
+    __asm__ __volatile__("lfence\nrdtsc" : "=a"(eax), "=d"(edx));
+    return (((uint64_t)edx) << 32) | eax;
+}
+#define readtime readtime
+#endif
+#elif CONFIG_MACOS_KPERF
+uint64_t checkasm_kperf_cycles(void);
+#define readtime() checkasm_kperf_cycles()
+#elif (ARCH_AARCH64 || ARCH_ARM) && defined(__APPLE__)
+#include 
+#define readtime() mach_absolute_time()
+#elif ARCH_AARCH64
+#ifdef _MSC_VER
+#include 
+#define readtime() (_InstructionSynchronizationBarrier(), ReadTimeStampCounter())
+#else
+static inline uint64_t readtime(void) {
+    uint64_t cycle_counter;
+    /* This requires enabling user mode access to the cycle counter (which
+     * can only be done from kernel space).
+     * This could also read cntvct_el0 instead of pmccntr_el0; that register
+     * might also be readable (depending on kernel version), but it has much
+     * worse precision (it's a fixed 50 MHz timer). */
+    __asm__ __volatile__("isb\nmrs %0, pmccntr_el0"
+                         : "=r"(cycle_counter)
+                         :: "memory");
+    return cycle_counter;
+}
+#define readtime readtime
+#endif
+#elif ARCH_ARM && !defined(_MSC_VER) && __ARM_ARCH >= 7
+static inline uint64_t readtime(void) {
+    uint32_t cycle_counter;
+    /* This requires enabling user mode access to the cycle counter (which
+     * can only be done from kernel space). */
+    __asm__ __volatile__("isb\nmrc p15, 0, %0, c9, c13, 0"
+                         : "=r"(cycle_counter)
+                         :: "memory");
+    return cycle_counter;
+}
+#define readtime readtime
+#elif ARCH_PPC64LE
+static inline uint64_t readtime(void) {
+    uint32_t tbu, tbl, temp;
+
+    __asm__ __volatile__(
+        "1:\n"
+        "mfspr %2,269\n"
+        "mfspr %0,268\n"
+        "mfspr %1,269\n"
+        "cmpw   %2,%1\n"
+        "bne    1b\n"
+    : "=r"(tbl), "=r"(tbu), "=r"(temp)
+    :
+    : "cc");
+
+    return (((uint64_t)tbu) << 32) | (uint64_t)tbl;
+}
+#define readtime readtime
+#elif ARCH_RISCV
+#include 
+static inline uint64_t clock_gettime_nsec(void) {
+  struct timespec ts;
+#ifdef CLOCK_MONOTONIC_RAW
+  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+#else
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+#endif
+  return ((uint64_t)ts.tv_sec*1000000000u) + (uint64_t)ts.tv_nsec;
+}
+#define readtime clock_gettime_nsec
+#elif ARCH_LOONGARCH
+static inline uint64_t readtime(void) {
+#if ARCH_LOONGARCH64
+    uint64_t a, id;
+    __asm__ __volatile__("rdtime.d  %0, %1"
+                         : "=r"(a), "=r"(id)
+                         :: );
+    return a;
+#else
+    uint32_t a, id;
+    __asm__ __volatile__("rdtimel.w  %0, %1"
+                         : "=r"(a), "=r"(id)
+                         :: );
+    return (uint64_t)a;
+#endif
+}
+#define readtime readtime
+#endif
+
+/* Verifies that clobbered callee-saved registers
+ * are properly saved and restored */
+void checkasm_checked_call(void *func, ...);
+
+#if ARCH_X86_64
+/* YMM and ZMM registers on x86 are turned off to save power when they haven't
+ * been used for some period of time. When they are used there will be a
+ * "warmup" period during which performance will be reduced and inconsistent
+ * which is problematic when trying to benchmark individual functions. We can
+ * work around this by periodically issuing "dummy" instructions that uses
+ * those registers to keep them powered on. */
+void checkasm_simd_warmup(void);
+
+/* The upper 32 bits of 32-bit data types are undefined when passed as function
+ * parameters. In practice those bits usually end up being zero which may hide
+ * certain bugs, such as using a register containing undefined bits as a pointer
+ * offset, so we want to intentionally clobber those bits with junk to expose
+ * any issues. The following set of macros automatically calculates a bitmask
+ * specifying which parameters should have their upper halves clobbered. */
+#ifdef _WIN32
+/* Integer and floating-point parameters share "register slots". */
+#define IGNORED_FP_ARGS 0
+#else
+/* Up to 8 floating-point parameters are passed in XMM registers, which are
+ * handled orthogonally from integer parameters passed in GPR registers. */
+#define IGNORED_FP_ARGS 8
+#endif
+#if HAVE_C11_GENERIC
+#define clobber_type(arg) _Generic((void (*)(void*, arg))NULL,\
+     void (*)(void*, int32_t ): clobber_mask |= 1 << mpos++,\
+     void (*)(void*, uint32_t): clobber_mask |= 1 << mpos++,\
+     void (*)(void*, float   ): mpos += (fp_args++ >= IGNORED_FP_ARGS),\
+     void (*)(void*, double  ): mpos += (fp_args++ >= IGNORED_FP_ARGS),\
+     default:                   mpos++)
+#define init_clobber_mask(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, ...)\
+    unsigned clobber_mask = 0;\
+    {\
+        int mpos = 0, fp_args = 0;\
+        clobber_type(a); clobber_type(b); clobber_type(c); clobber_type(d);\
+        clobber_type(e); clobber_type(f); clobber_type(g); clobber_type(h);\
+        clobber_type(i); clobber_type(j); clobber_type(k); clobber_type(l);\
+        clobber_type(m); clobber_type(n); clobber_type(o); clobber_type(p);\
+    }
+#else
+/* Skip parameter clobbering on compilers without support for _Generic() */
+#define init_clobber_mask(...) unsigned clobber_mask = 0
+#endif
+#define declare_new(ret, ...)\
+    ret (*checked_call)(__VA_ARGS__, int, int, int, int, int, int, int,\
+                        int, int, int, int, int, int, int, int, int,\
+                        void*, unsigned) =\
+        (void*)checkasm_checked_call;\
+    init_clobber_mask(__VA_ARGS__, void*, void*, void*, void*,\
+                      void*, void*, void*, void*, void*, void*,\
+                      void*, void*, void*, void*, void*);
+#define call_new(...)\
+    (checkasm_set_signal_handler_state(1),\
+     checkasm_simd_warmup(),\
+     checked_call(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8,\
+                  7, 6, 5, 4, 3, 2, 1, func_new, clobber_mask));\
+    checkasm_set_signal_handler_state(0)
+#elif ARCH_X86_32
+#define declare_new(ret, ...)\
+    ret (*checked_call)(void *, __VA_ARGS__, int, int, int, int, int, int,\
+                        int, int, int, int, int, int, int, int, int) =\
+        (void *)checkasm_checked_call;
+#define call_new(...)\
+    (checkasm_set_signal_handler_state(1),\
+     checked_call(func_new, __VA_ARGS__, 15, 14, 13, 12,\
+                  11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));\
+    checkasm_set_signal_handler_state(0)
+#elif ARCH_ARM
+/* Use a dummy argument, to offset the real parameters by 2, not only 1.
+ * This makes sure that potential 8-byte-alignment of parameters is kept
+ * the same even when the extra parameters have been removed. */
+extern void (*checkasm_checked_call_ptr)(void *func, int dummy, ...);
+#define declare_new(ret, ...)\
+    ret (*checked_call)(void *, int dummy, __VA_ARGS__,\
+                        int, int, int, int, int, int, int, int,\
+                        int, int, int, int, int, int, int) =\
+    (void *)checkasm_checked_call_ptr;
+#define call_new(...)\
+    (checkasm_set_signal_handler_state(1),\
+     checked_call(func_new, 0, __VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0));\
+    checkasm_set_signal_handler_state(0)
+#elif ARCH_AARCH64 && !defined(__APPLE__)
+void checkasm_stack_clobber(uint64_t clobber, ...);
+#define declare_new(ret, ...)\
+    ret (*checked_call)(void *, int, int, int, int, int, int, int,\
+                        __VA_ARGS__, int, int, int, int, int, int, int, int,\
+                        int, int, int, int, int, int, int) =\
+    (void *)checkasm_checked_call;
+#define CLOB (UINT64_C(0xdeadbeefdeadbeef))
+#define call_new(...)\
+    (checkasm_set_signal_handler_state(1),\
+     checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
+                            CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
+                            CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
+                            CLOB, CLOB, CLOB, CLOB, CLOB),\
+     checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__,\
+                  7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0));\
+    checkasm_set_signal_handler_state(0)
+#elif ARCH_RISCV
+#define declare_new(ret, ...)\
+    ret (*checked_call)(void *, int, int, int, int, int, int, int,\
+                        __VA_ARGS__, int, int, int, int, int, int, int, int,\
+                        int, int, int, int, int, int, int) =\
+    (void *)checkasm_checked_call;
+#define call_new(...)\
+    (checkasm_set_signal_handler_state(1),\
+     checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__,\
+                  7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0));\
+    checkasm_set_signal_handler_state(0)
+#elif ARCH_LOONGARCH
+#define declare_new(ret, ...)\
+    ret (*checked_call)(void *, int, int, int, int, int, int, int,\
+                        __VA_ARGS__, int, int, int, int, int, int, int, int,\
+                        int, int, int, int, int, int, int) =\
+    (void *)checkasm_checked_call;
+#define call_new(...)\
+    (checkasm_set_signal_handler_state(1),\
+     checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__,\
+                  7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0));\
+    checkasm_set_signal_handler_state(0)
+#else
+#define declare_new(ret, ...)
+#define call_new(...)\
+    (checkasm_set_signal_handler_state(1),\
+     ((func_type *)func_new)(__VA_ARGS__));\
+    checkasm_set_signal_handler_state(0)
+#endif
+#else /* HAVE_ASM */
+#define declare_new(ret, ...)
+/* Call the function */
+#define call_new(...)\
+    (checkasm_set_signal_handler_state(1),\
+     ((func_type *)func_new)(__VA_ARGS__));\
+    checkasm_set_signal_handler_state(0)
+#endif /* HAVE_ASM */
+
+/* Benchmark the function */
+#ifdef readtime
+#define bench_new(...)\
+    do {\
+        if (checkasm_bench_func()) {\
+            func_type *const tfunc = func_new;\
+            checkasm_set_signal_handler_state(1);\
+            uint64_t tsum = 0;\
+            int tcount = 0;\
+            for (int ti = 0; ti < BENCH_RUNS; ti++) {\
+                uint64_t t = readtime();\
+                int talt = 0; (void)talt;\
+                tfunc(__VA_ARGS__);\
+                talt = 1;\
+                tfunc(__VA_ARGS__);\
+                talt = 0;\
+                tfunc(__VA_ARGS__);\
+                talt = 1;\
+                tfunc(__VA_ARGS__);\
+                t = readtime() - t;\
+                if (t*tcount <= tsum*4 && ti > 0) {\
+                    tsum += t;\
+                    tcount++;\
+                }\
+            }\
+            checkasm_set_signal_handler_state(0);\
+            checkasm_update_bench(tcount, tsum);\
+        } else {\
+            const int talt = 0; (void)talt;\
+            call_new(__VA_ARGS__);\
+        }\
+    } while (0)
+#else
+#define bench_new(...) do {} while (0)
+#endif
+
+/* Alternates between two pointers. Intended to be used within bench_new()
+ * calls for functions which modifies their input buffer(s) to ensure that
+ * throughput, and not latency, is measured. */
+#define alternate(a, b) (talt ? (b) : (a))
+
+#define ROUND_UP(x,a) (((x)+((a)-1)) & ~((a)-1))
+#define PIXEL_RECT(name, w, h) \
+    ALIGN_STK_64(pixel, name##_buf, ((h)+32)*(ROUND_UP(w,64)+64) + 64,); \
+    ptrdiff_t name##_stride = sizeof(pixel)*(ROUND_UP(w,64)+64); \
+    (void)name##_stride; \
+    int name##_buf_h = (h)+32; \
+    (void)name##_buf_h;\
+    pixel *name = name##_buf + (ROUND_UP(w,64)+64)*16 + 64
+
+#define CLEAR_PIXEL_RECT(name) \
+    memset(name##_buf, 0x99, sizeof(name##_buf)) \
+
+#define DECL_CHECKASM_CHECK_FUNC(type) \
+int checkasm_check_##type(const char *const file, const int line, \
+                          const type *const buf1, const ptrdiff_t stride1, \
+                          const type *const buf2, const ptrdiff_t stride2, \
+                          const int w, const int h, const char *const name, \
+                          const int align_w, const int align_h, \
+                          const int padding)
+
+DECL_CHECKASM_CHECK_FUNC(int8_t);
+DECL_CHECKASM_CHECK_FUNC(int16_t);
+DECL_CHECKASM_CHECK_FUNC(int32_t);
+DECL_CHECKASM_CHECK_FUNC(uint8_t);
+DECL_CHECKASM_CHECK_FUNC(uint16_t);
+DECL_CHECKASM_CHECK_FUNC(uint32_t);
+
+#define CONCAT(a,b) a ## b
+
+#define checkasm_check2(prefix, ...) CONCAT(checkasm_check_, prefix)(__FILE__, __LINE__, __VA_ARGS__)
+#define checkasm_check(prefix, ...) checkasm_check2(prefix, __VA_ARGS__, 0, 0, 0)
+
+#ifdef BITDEPTH
+#define checkasm_check_pixel(...) checkasm_check(PIXEL_TYPE, __VA_ARGS__)
+#define checkasm_check_pixel_padded(...) checkasm_check2(PIXEL_TYPE, __VA_ARGS__, 1, 1, 8)
+#define checkasm_check_pixel_padded_align(...) checkasm_check2(PIXEL_TYPE, __VA_ARGS__, 8)
+#define checkasm_check_coef(...)  checkasm_check(COEF_TYPE,  __VA_ARGS__)
+#endif
+
+#endif /* DAV1D_TESTS_CHECKASM_CHECKASM_H */
diff --git a/media/libdav1d/src/tests/checkasm/filmgrain.c b/media/libdav1d/src/tests/checkasm/filmgrain.c
new file mode 100644
index 0000000000..638e83fd11
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/filmgrain.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+
+#include 
+
+#include "src/levels.h"
+#include "src/filmgrain.h"
+#define UNIT_TEST 1
+#include "src/fg_apply_tmpl.c"
+
+#if BITDEPTH == 8
+#define checkasm_check_entry(...) checkasm_check(int8_t, __VA_ARGS__)
+#else
+#define checkasm_check_entry(...) checkasm_check(int16_t, __VA_ARGS__)
+#endif
+
+static const char ss_name[][4] = {
+    [DAV1D_PIXEL_LAYOUT_I420 - 1] = "420",
+    [DAV1D_PIXEL_LAYOUT_I422 - 1] = "422",
+    [DAV1D_PIXEL_LAYOUT_I444 - 1] = "444",
+};
+
+static void check_gen_grny(const Dav1dFilmGrainDSPContext *const dsp) {
+    ALIGN_STK_16(entry, grain_lut_c, GRAIN_HEIGHT,[GRAIN_WIDTH]);
+    ALIGN_STK_16(entry, grain_lut_a, GRAIN_HEIGHT + 1,[GRAIN_WIDTH]);
+
+    declare_func(void, entry grain_lut[][GRAIN_WIDTH],
+                 const Dav1dFilmGrainData *data HIGHBD_DECL_SUFFIX);
+
+    for (int i = 0; i < 4; i++) {
+        if (check_func(dsp->generate_grain_y, "gen_grain_y_ar%d_%dbpc", i, BITDEPTH)) {
+            ALIGN_STK_16(Dav1dFilmGrainData, fg_data, 1,);
+            fg_data[0].seed = rnd() & 0xFFFF;
+
+#if BITDEPTH == 16
+            const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#endif
+
+            fg_data[0].grain_scale_shift = rnd() & 3;
+            fg_data[0].ar_coeff_shift = (rnd() & 3) + 6;
+            fg_data[0].ar_coeff_lag = i;
+            const int num_y_pos = 2 * fg_data[0].ar_coeff_lag * (fg_data[0].ar_coeff_lag + 1);
+            for (int n = 0; n < num_y_pos; n++)
+                fg_data[0].ar_coeffs_y[n] = (rnd() & 0xff) - 128;
+
+            call_ref(grain_lut_c, fg_data HIGHBD_TAIL_SUFFIX);
+            call_new(grain_lut_a, fg_data HIGHBD_TAIL_SUFFIX);
+            checkasm_check_entry(grain_lut_c[0], sizeof(entry) * GRAIN_WIDTH,
+                                 grain_lut_a[0], sizeof(entry) * GRAIN_WIDTH,
+                                 GRAIN_WIDTH, GRAIN_HEIGHT, "grain_lut");
+
+            bench_new(grain_lut_a, fg_data HIGHBD_TAIL_SUFFIX);
+        }
+    }
+
+    report("gen_grain_y");
+}
+
+static void check_gen_grnuv(const Dav1dFilmGrainDSPContext *const dsp) {
+    ALIGN_STK_16(entry, grain_lut_y, GRAIN_HEIGHT + 1,[GRAIN_WIDTH]);
+    ALIGN_STK_16(entry, grain_lut_c, GRAIN_HEIGHT,    [GRAIN_WIDTH]);
+    ALIGN_STK_16(entry, grain_lut_a, GRAIN_HEIGHT + 1,[GRAIN_WIDTH]);
+
+    declare_func(void, entry grain_lut[][GRAIN_WIDTH],
+                 const entry grain_lut_y[][GRAIN_WIDTH],
+                 const Dav1dFilmGrainData *data, intptr_t uv HIGHBD_DECL_SUFFIX);
+
+    for (int layout_idx = 0; layout_idx < 3; layout_idx++) {
+        const enum Dav1dPixelLayout layout = layout_idx + 1;
+        const int ss_x = layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int ss_y = layout == DAV1D_PIXEL_LAYOUT_I420;
+
+        for (int i = 0; i < 4; i++) {
+            if (check_func(dsp->generate_grain_uv[layout_idx],
+                           "gen_grain_uv_ar%d_%dbpc_%s",
+                           i, BITDEPTH, ss_name[layout_idx]))
+            {
+                ALIGN_STK_16(Dav1dFilmGrainData, fg_data, 1,);
+                fg_data[0].seed = rnd() & 0xFFFF;
+
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#endif
+
+                fg_data[0].num_y_points = rnd() & 1;
+                fg_data[0].grain_scale_shift = rnd() & 3;
+                fg_data[0].ar_coeff_shift = (rnd() & 3) + 6;
+                fg_data[0].ar_coeff_lag = i;
+                const int num_y_pos = 2 * fg_data[0].ar_coeff_lag * (fg_data[0].ar_coeff_lag + 1);
+                for (int n = 0; n < num_y_pos; n++)
+                    fg_data[0].ar_coeffs_y[n] = (rnd() & 0xff) - 128;
+                dsp->generate_grain_y(grain_lut_y, fg_data HIGHBD_TAIL_SUFFIX);
+
+                const int uv = rnd() & 1;
+                const int num_uv_pos = num_y_pos + !!fg_data[0].num_y_points;
+                for (int n = 0; n < num_uv_pos; n++)
+                    fg_data[0].ar_coeffs_uv[uv][n] = (rnd() & 0xff) - 128;
+                if (!fg_data[0].num_y_points)
+                    fg_data[0].ar_coeffs_uv[uv][num_uv_pos] = 0;
+                memset(grain_lut_c, 0xff, sizeof(grain_lut_c));
+                memset(grain_lut_a, 0xff, sizeof(grain_lut_a));
+                call_ref(grain_lut_c, grain_lut_y, fg_data, uv HIGHBD_TAIL_SUFFIX);
+                call_new(grain_lut_a, grain_lut_y, fg_data, uv HIGHBD_TAIL_SUFFIX);
+                int w = ss_x ? 44 : GRAIN_WIDTH;
+                int h = ss_y ? 38 : GRAIN_HEIGHT;
+                checkasm_check_entry(grain_lut_c[0], sizeof(entry) * GRAIN_WIDTH,
+                                     grain_lut_a[0], sizeof(entry) * GRAIN_WIDTH,
+                                     w, h, "grain_lut");
+
+                bench_new(grain_lut_a, grain_lut_y, fg_data, uv HIGHBD_TAIL_SUFFIX);
+            }
+        }
+    }
+
+    report("gen_grain_uv");
+}
+
+static void check_fgy_sbrow(const Dav1dFilmGrainDSPContext *const dsp) {
+    PIXEL_RECT(c_dst, 128, 32);
+    PIXEL_RECT(a_dst, 128, 32);
+    PIXEL_RECT(src,   128, 32);
+    const ptrdiff_t stride = c_dst_stride;
+
+    declare_func(void, pixel *dst_row, const pixel *src_row, ptrdiff_t stride,
+                 const Dav1dFilmGrainData *data, size_t pw,
+                 const uint8_t scaling[SCALING_SIZE],
+                 const entry grain_lut[][GRAIN_WIDTH],
+                 int bh, int row_num HIGHBD_DECL_SUFFIX);
+
+    if (check_func(dsp->fgy_32x32xn, "fgy_32x32xn_%dbpc", BITDEPTH)) {
+        ALIGN_STK_16(Dav1dFilmGrainData, fg_data, 16,);
+        ALIGN_STK_16(entry, grain_lut, GRAIN_HEIGHT + 1,[GRAIN_WIDTH]);
+        ALIGN_STK_64(uint8_t, scaling, SCALING_SIZE,);
+        fg_data[0].seed = rnd() & 0xFFFF;
+
+#if BITDEPTH == 16
+        const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+        const int bitdepth_max = 0xff;
+#endif
+
+        fg_data[0].grain_scale_shift = rnd() & 3;
+        fg_data[0].ar_coeff_shift = (rnd() & 3) + 6;
+        fg_data[0].ar_coeff_lag = rnd() & 3;
+        const int num_y_pos = 2 * fg_data[0].ar_coeff_lag * (fg_data[0].ar_coeff_lag + 1);
+        for (int n = 0; n < num_y_pos; n++)
+            fg_data[0].ar_coeffs_y[n] = (rnd() & 0xff) - 128;
+        dsp->generate_grain_y(grain_lut, fg_data HIGHBD_TAIL_SUFFIX);
+
+        fg_data[0].num_y_points = 2 + (rnd() % 13);
+        const int pad = 0xff / fg_data[0].num_y_points;
+        for (int n = 0; n < fg_data[0].num_y_points; n++) {
+            fg_data[0].y_points[n][0] = 0xff * n / fg_data[0].num_y_points;
+            fg_data[0].y_points[n][0] += rnd() % pad;
+            fg_data[0].y_points[n][1] = rnd() & 0xff;
+        }
+        generate_scaling(bitdepth_from_max(bitdepth_max), fg_data[0].y_points,
+                         fg_data[0].num_y_points, scaling);
+
+        fg_data[0].clip_to_restricted_range = rnd() & 1;
+        fg_data[0].scaling_shift = (rnd() & 3) + 8;
+        for (fg_data[0].overlap_flag = 0; fg_data[0].overlap_flag <= 1;
+             fg_data[0].overlap_flag++)
+        {
+            for (int i = 0; i <= 2 * fg_data[0].overlap_flag; i++) {
+                int w, h, row_num;
+                if (fg_data[0].overlap_flag) {
+                    w = 35 + (rnd() % 93);
+                    if (i == 0) {
+                        row_num = 0;
+                        h = 1 + (rnd() % 31);
+                    } else {
+                        row_num = 1 + (rnd() & 0x7ff);
+                        if (i == 1) {
+                            h = 3 + (rnd() % 30);
+                        } else {
+                            h = 1 + (rnd() & 1);
+                        }
+                    }
+                } else {
+                    w = 1 + (rnd() & 127);
+                    h = 1 + (rnd() & 31);
+                    row_num = rnd() & 0x7ff;
+                }
+
+                for (int y = 0; y < 32; y++) {
+                    // Src pixels past the right edge can be uninitialized
+                    for (int x = 0; x < 128; x++)
+                        src[y * PXSTRIDE(stride) + x] = rnd();
+                    for (int x = 0; x < w; x++)
+                        src[y * PXSTRIDE(stride) + x] &= bitdepth_max;
+                }
+
+                CLEAR_PIXEL_RECT(c_dst);
+                CLEAR_PIXEL_RECT(a_dst);
+                call_ref(c_dst, src, stride, fg_data, w, scaling, grain_lut, h,
+                         row_num HIGHBD_TAIL_SUFFIX);
+                call_new(a_dst, src, stride, fg_data, w, scaling, grain_lut, h,
+                         row_num HIGHBD_TAIL_SUFFIX);
+
+                checkasm_check_pixel_padded_align(c_dst, stride, a_dst, stride,
+                                                  w, h, "dst", 32, 2);
+            }
+        }
+        fg_data[0].overlap_flag = 1;
+        for (int y = 0; y < 32; y++) {
+            // Make sure all pixels are in range
+            for (int x = 0; x < 128; x++)
+                src[y * PXSTRIDE(stride) + x] &= bitdepth_max;
+        }
+        bench_new(a_dst, src, stride, fg_data, 64, scaling, grain_lut, 32,
+                  1 HIGHBD_TAIL_SUFFIX);
+    }
+
+    report("fgy_32x32xn");
+}
+
+static void check_fguv_sbrow(const Dav1dFilmGrainDSPContext *const dsp) {
+    PIXEL_RECT(c_dst,    128, 32);
+    PIXEL_RECT(a_dst,    128, 32);
+    PIXEL_RECT(src,      128, 32);
+    PIXEL_RECT(luma_src, 128, 32);
+    const ptrdiff_t lstride = luma_src_stride;
+
+    declare_func(void, pixel *dst_row, const pixel *src_row, ptrdiff_t stride,
+                 const Dav1dFilmGrainData *data, size_t pw,
+                 const uint8_t scaling[SCALING_SIZE],
+                 const entry grain_lut[][GRAIN_WIDTH], int bh, int row_num,
+                 const pixel *luma_row, ptrdiff_t luma_stride, int uv_pl,
+                 int is_identity HIGHBD_DECL_SUFFIX);
+
+    for (int layout_idx = 0; layout_idx < 3; layout_idx++) {
+        const enum Dav1dPixelLayout layout = layout_idx + 1;
+        const int ss_x = layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int ss_y = layout == DAV1D_PIXEL_LAYOUT_I420;
+        const ptrdiff_t stride = c_dst_stride;
+
+        for (int csfl = 0; csfl <= 1; csfl++) {
+            if (check_func(dsp->fguv_32x32xn[layout_idx],
+                           "fguv_32x32xn_%dbpc_%s_csfl%d",
+                           BITDEPTH, ss_name[layout_idx], csfl))
+            {
+                ALIGN_STK_16(Dav1dFilmGrainData, fg_data, 1,);
+                ALIGN_STK_16(entry, grain_lut, 2,[GRAIN_HEIGHT + 1][GRAIN_WIDTH]);
+                ALIGN_STK_64(uint8_t, scaling, SCALING_SIZE,);
+
+                fg_data[0].seed = rnd() & 0xFFFF;
+
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                const int bitdepth_max = 0xff;
+#endif
+                const int uv_pl = rnd() & 1;
+                const int is_identity = rnd() & 1;
+
+                fg_data[0].grain_scale_shift = rnd() & 3;
+                fg_data[0].ar_coeff_shift = (rnd() & 3) + 6;
+                fg_data[0].ar_coeff_lag = rnd() & 3;
+                fg_data[0].num_y_points = csfl ? 2 + (rnd() % 13) : 0;
+                const int num_y_pos = 2 * fg_data[0].ar_coeff_lag * (fg_data[0].ar_coeff_lag + 1);
+                for (int n = 0; n < num_y_pos; n++)
+                    fg_data[0].ar_coeffs_y[n] = (rnd() & 0xff) - 128;
+                const int num_uv_pos = num_y_pos + 1;
+                for (int n = 0; n < num_uv_pos; n++)
+                    fg_data[0].ar_coeffs_uv[uv_pl][n] = (rnd() & 0xff) - 128;
+                dsp->generate_grain_y(grain_lut[0], fg_data HIGHBD_TAIL_SUFFIX);
+                dsp->generate_grain_uv[layout_idx](grain_lut[1], grain_lut[0],
+                                                   fg_data, uv_pl HIGHBD_TAIL_SUFFIX);
+
+                if (csfl) {
+                    const int pad = 0xff / fg_data[0].num_y_points;
+                    for (int n = 0; n < fg_data[0].num_y_points; n++) {
+                        fg_data[0].y_points[n][0] = 0xff * n / fg_data[0].num_y_points;
+                        fg_data[0].y_points[n][0] += rnd() % pad;
+                        fg_data[0].y_points[n][1] = rnd() & 0xff;
+                    }
+                    generate_scaling(bitdepth_from_max(bitdepth_max), fg_data[0].y_points,
+                                     fg_data[0].num_y_points, scaling);
+                } else {
+                    fg_data[0].num_uv_points[uv_pl] = 2 + (rnd() % 9);
+                    const int pad = 0xff / fg_data[0].num_uv_points[uv_pl];
+                    for (int n = 0; n < fg_data[0].num_uv_points[uv_pl]; n++) {
+                        fg_data[0].uv_points[uv_pl][n][0] = 0xff * n / fg_data[0].num_uv_points[uv_pl];
+                        fg_data[0].uv_points[uv_pl][n][0] += rnd() % pad;
+                        fg_data[0].uv_points[uv_pl][n][1] = rnd() & 0xff;
+                    }
+                    generate_scaling(bitdepth_from_max(bitdepth_max), fg_data[0].uv_points[uv_pl],
+                                     fg_data[0].num_uv_points[uv_pl], scaling);
+
+                    fg_data[0].uv_mult[uv_pl] = (rnd() & 0xff) - 128;
+                    fg_data[0].uv_luma_mult[uv_pl] = (rnd() & 0xff) - 128;
+                    fg_data[0].uv_offset[uv_pl] = (rnd() & 0x1ff) - 256;
+                }
+
+                fg_data[0].clip_to_restricted_range = rnd() & 1;
+                fg_data[0].scaling_shift = (rnd() & 3) + 8;
+                fg_data[0].chroma_scaling_from_luma = csfl;
+                for (fg_data[0].overlap_flag = 0; fg_data[0].overlap_flag <= 1;
+                     fg_data[0].overlap_flag++)
+                {
+                    for (int i = 0; i <= 2 * fg_data[0].overlap_flag; i++) {
+                        int w, h, row_num;
+                        if (fg_data[0].overlap_flag) {
+                            w = (36 >> ss_x) + (rnd() % (92 >> ss_x));
+                            if (i == 0) {
+                                row_num = 0;
+                                h = 1 + (rnd() & (31 >> ss_y));
+                            } else {
+                                row_num = 1 + (rnd() & 0x7ff);
+                                if (i == 1) {
+                                    h = (ss_y ? 2 : 3) + (rnd() % (ss_y ? 15 : 30));
+                                } else {
+                                    h = ss_y ? 1 : 1 + (rnd() & 1);
+                                }
+                            }
+                        } else {
+                            w = 1 + (rnd() & (127 >> ss_x));
+                            h = 1 + (rnd() & (31 >> ss_y));
+                            row_num = rnd() & 0x7ff;
+                        }
+
+                        for (int y = 0; y < 32; y++) {
+                            // Src pixels past the right edge can be uninitialized
+                            for (int x = 0; x < 128; x++) {
+                                src[y * PXSTRIDE(stride) + x] = rnd();
+                                luma_src[y * PXSTRIDE(lstride) + x] = rnd();
+                            }
+                            for (int x = 0; x < w; x++)
+                                src[y * PXSTRIDE(stride) + x] &= bitdepth_max;
+                            for (int x = 0; x < (w << ss_x); x++)
+                                luma_src[y * PXSTRIDE(lstride) + x] &= bitdepth_max;
+                        }
+
+                        CLEAR_PIXEL_RECT(c_dst);
+                        CLEAR_PIXEL_RECT(a_dst);
+                        call_ref(c_dst, src, stride, fg_data, w, scaling, grain_lut[1], h,
+                                 row_num, luma_src, lstride, uv_pl, is_identity HIGHBD_TAIL_SUFFIX);
+                        call_new(a_dst, src, stride, fg_data, w, scaling, grain_lut[1], h,
+                                 row_num, luma_src, lstride, uv_pl, is_identity HIGHBD_TAIL_SUFFIX);
+
+                        checkasm_check_pixel_padded_align(c_dst, stride,
+                                                          a_dst, stride,
+                                                          w, h, "dst",
+                                                          32 >> ss_x, 4);
+                    }
+                }
+
+                fg_data[0].overlap_flag = 1;
+                for (int y = 0; y < 32; y++) {
+                    // Make sure all pixels are in range
+                    for (int x = 0; x < 128; x++) {
+                        src[y * PXSTRIDE(stride) + x] &= bitdepth_max;
+                        luma_src[y * PXSTRIDE(lstride) + x] &= bitdepth_max;
+                    }
+                }
+                bench_new(a_dst, src, stride, fg_data, 64 >> ss_x, scaling, grain_lut[1], 32 >> ss_y,
+                          1, luma_src, lstride, uv_pl, is_identity HIGHBD_TAIL_SUFFIX);
+            }
+        }
+    }
+
+    report("fguv_32x32xn");
+}
+
+void bitfn(checkasm_check_filmgrain)(void) {
+    Dav1dFilmGrainDSPContext c;
+
+    bitfn(dav1d_film_grain_dsp_init)(&c);
+
+    check_gen_grny(&c);
+    check_gen_grnuv(&c);
+    check_fgy_sbrow(&c);
+    check_fguv_sbrow(&c);
+}
diff --git a/media/libdav1d/src/tests/checkasm/ipred.c b/media/libdav1d/src/tests/checkasm/ipred.c
new file mode 100644
index 0000000000..ad54f1bbe1
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/ipred.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+#include "src/ipred.h"
+#include "src/levels.h"
+
+#include 
+
+static const char *const intra_pred_mode_names[N_IMPL_INTRA_PRED_MODES] = {
+    [DC_PRED]       = "dc",
+    [DC_128_PRED]   = "dc_128",
+    [TOP_DC_PRED]   = "dc_top",
+    [LEFT_DC_PRED]  = "dc_left",
+    [HOR_PRED]      = "h",
+    [VERT_PRED]     = "v",
+    [PAETH_PRED]    = "paeth",
+    [SMOOTH_PRED]   = "smooth",
+    [SMOOTH_V_PRED] = "smooth_v",
+    [SMOOTH_H_PRED] = "smooth_h",
+    [Z1_PRED]       = "z1",
+    [Z2_PRED]       = "z2",
+    [Z3_PRED]       = "z3",
+    [FILTER_PRED]   = "filter"
+};
+
+static const char *const cfl_ac_names[3] = { "420", "422", "444" };
+
+static const char *const cfl_pred_mode_names[DC_128_PRED + 1] = {
+    [DC_PRED]       = "cfl",
+    [DC_128_PRED]   = "cfl_128",
+    [TOP_DC_PRED]   = "cfl_top",
+    [LEFT_DC_PRED]  = "cfl_left",
+};
+
+static const uint8_t z_angles[27] = {
+     3,  6,  9,
+    14, 17, 20, 23, 26, 29, 32,
+    36, 39, 42, 45, 48, 51, 54,
+    58, 61, 64, 67, 70, 73, 76,
+    81, 84, 87
+};
+
+/* Generate max_width/max_height values that covers all edge cases */
+static int gen_z2_max_wh(const int sz) {
+    const int n = rnd();
+    if (n & (1 << 17)) /* edge block */
+        return (n & (sz - 1)) + 1;
+    if (n & (1 << 16)) /* max size, exceeds uint16_t */
+        return 65536;
+    return (n & 65535) + 1;
+}
+
+static void check_intra_pred(Dav1dIntraPredDSPContext *const c) {
+    PIXEL_RECT(c_dst, 64, 64);
+    PIXEL_RECT(a_dst, 64, 64);
+    ALIGN_STK_64(pixel, topleft_buf, 257,);
+    pixel *const topleft = topleft_buf + 128;
+
+    declare_func(void, pixel *dst, ptrdiff_t stride, const pixel *topleft,
+                 int width, int height, int angle, int max_width, int max_height
+                 HIGHBD_DECL_SUFFIX);
+
+    for (int mode = 0; mode < N_IMPL_INTRA_PRED_MODES; mode++) {
+        int bpc_min = BITDEPTH, bpc_max = BITDEPTH;
+        if (mode == FILTER_PRED && BITDEPTH == 16) {
+            bpc_min = 10;
+            bpc_max = 12;
+        }
+        for (int bpc = bpc_min; bpc <= bpc_max; bpc += 2)
+            for (int w = 4; w <= (mode == FILTER_PRED ? 32 : 64); w <<= 1)
+                if (check_func(c->intra_pred[mode], "intra_pred_%s_w%d_%dbpc",
+                    intra_pred_mode_names[mode], w, bpc))
+                {
+                    for (int h = imax(w / 4, 4); h <= imin(w * 4,
+                        (mode == FILTER_PRED ? 32 : 64)); h <<= 1)
+                    {
+                        const ptrdiff_t stride = c_dst_stride;
+                        int nb_iters = (mode >= Z1_PRED && mode <= Z3_PRED) ? 5 : 1;
+
+                        for (int iter = 0; iter < nb_iters; iter++) {
+                            int a = 0, maxw = 0, maxh = 0;
+                            if (mode >= Z1_PRED && mode <= Z3_PRED) { /* angle */
+                                a = (90 * (mode - Z1_PRED) + z_angles[rnd() % 27]) |
+                                    (rnd() & 0x600);
+                                if (mode == Z2_PRED) {
+                                    maxw = gen_z2_max_wh(w);
+                                    maxh = gen_z2_max_wh(h);
+                                }
+                            } else if (mode == FILTER_PRED) /* filter_idx */
+                                a = (rnd() % 5) | (rnd() & ~511);
+
+                            int bitdepth_max;
+                            if (bpc == 16)
+                                bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+                            else
+                                bitdepth_max = (1 << bpc) - 1;
+
+                            for (int i = -h * 2; i <= w * 2; i++)
+                                topleft[i] = rnd() & bitdepth_max;
+
+                            CLEAR_PIXEL_RECT(c_dst);
+                            CLEAR_PIXEL_RECT(a_dst);
+                            call_ref(c_dst, stride, topleft, w, h, a, maxw, maxh
+                                     HIGHBD_TAIL_SUFFIX);
+                            call_new(a_dst, stride, topleft, w, h, a, maxw, maxh
+                                     HIGHBD_TAIL_SUFFIX);
+                            if (checkasm_check_pixel_padded(c_dst, stride,
+                                                            a_dst, stride,
+                                                            w, h, "dst"))
+                            {
+                                if (mode == Z1_PRED || mode == Z3_PRED)
+                                    fprintf(stderr, "angle = %d (0x%03x)\n",
+                                            a & 0x1ff, a & 0x600);
+                                else if (mode == Z2_PRED)
+                                    fprintf(stderr, "angle = %d (0x%03x), "
+                                            "max_width = %d, max_height = %d\n",
+                                            a & 0x1ff, a & 0x600, maxw, maxh);
+                                else if (mode == FILTER_PRED)
+                                    fprintf(stderr, "filter_idx = %d\n", a & 0x1ff);
+                                break;
+                            }
+
+                            bench_new(a_dst, stride, topleft, w, h, a, 128, 128
+                                      HIGHBD_TAIL_SUFFIX);
+                        }
+                    }
+                }
+    }
+    report("intra_pred");
+}
+
+static void check_cfl_ac(Dav1dIntraPredDSPContext *const c) {
+    ALIGN_STK_64(int16_t, c_dst, 32 * 32,);
+    ALIGN_STK_64(int16_t, a_dst, 32 * 32,);
+    ALIGN_STK_64(pixel, luma, 32 * 32,);
+
+    declare_func(void, int16_t *ac, const pixel *y, ptrdiff_t stride,
+                 int w_pad, int h_pad, int cw, int ch);
+
+    for (int layout = 1; layout <= DAV1D_PIXEL_LAYOUT_I444; layout++) {
+        const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int h_step = 2 >> ss_hor, v_step = 2 >> ss_ver;
+        for (int w = 4; w <= (32 >> ss_hor); w <<= 1)
+            if (check_func(c->cfl_ac[layout - 1], "cfl_ac_%s_w%d_%dbpc",
+                cfl_ac_names[layout - 1], w, BITDEPTH))
+            {
+                for (int h = imax(w / 4, 4);
+                     h <= imin(w * 4, (32 >> ss_ver)); h <<= 1)
+                {
+                    const ptrdiff_t stride = 32 * sizeof(pixel);
+                    for (int w_pad = imax((w >> 2) - h_step, 0);
+                         w_pad >= 0; w_pad -= h_step)
+                    {
+                        for (int h_pad = imax((h >> 2) - v_step, 0);
+                             h_pad >= 0; h_pad -= v_step)
+                        {
+#if BITDEPTH == 16
+                            const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                            const int bitdepth_max = 0xff;
+#endif
+                            for (int y = 0; y < (h << ss_ver); y++)
+                                for (int x = 0; x < (w << ss_hor); x++)
+                                    luma[y * 32 + x] = rnd() & bitdepth_max;
+
+                            call_ref(c_dst, luma, stride, w_pad, h_pad, w, h);
+                            call_new(a_dst, luma, stride, w_pad, h_pad, w, h);
+                            checkasm_check(int16_t, c_dst, w * sizeof(*c_dst),
+                                                    a_dst, w * sizeof(*a_dst),
+                                                    w, h, "dst");
+                        }
+                    }
+
+                    bench_new(a_dst, luma, stride, 0, 0, w, h);
+                }
+            }
+    }
+    report("cfl_ac");
+}
+
+static void check_cfl_pred(Dav1dIntraPredDSPContext *const c) {
+    PIXEL_RECT(c_dst, 32, 32);
+    PIXEL_RECT(a_dst, 32, 32);
+    ALIGN_STK_64(int16_t, ac, 32 * 32,);
+    ALIGN_STK_64(pixel, topleft_buf, 257,);
+    pixel *const topleft = topleft_buf + 128;
+
+    declare_func(void, pixel *dst, ptrdiff_t stride, const pixel *topleft,
+                 int width, int height, const int16_t *ac, int alpha
+                 HIGHBD_DECL_SUFFIX);
+
+    for (int mode = 0; mode <= DC_128_PRED; mode += 1 + 2 * !mode)
+        for (int w = 4; w <= 32; w <<= 1)
+            if (check_func(c->cfl_pred[mode], "cfl_pred_%s_w%d_%dbpc",
+                cfl_pred_mode_names[mode], w, BITDEPTH))
+            {
+                for (int h = imax(w / 4, 4); h <= imin(w * 4, 32); h <<= 1)
+                {
+#if BITDEPTH == 16
+                    const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                    const int bitdepth_max = 0xff;
+#endif
+
+                    int alpha = ((rnd() & 15) + 1) * (1 - (rnd() & 2));
+
+                    for (int i = -h * 2; i <= w * 2; i++)
+                        topleft[i] = rnd() & bitdepth_max;
+
+                    int luma_avg = w * h >> 1;
+                    for (int i = 0; i < w * h; i++)
+                        luma_avg += ac[i] = rnd() & (bitdepth_max << 3);
+                    luma_avg /= w * h;
+                    for (int i = 0; i < w * h; i++)
+                        ac[i] -= luma_avg;
+
+                    CLEAR_PIXEL_RECT(c_dst);
+                    CLEAR_PIXEL_RECT(a_dst);
+
+                    call_ref(c_dst, c_dst_stride, topleft, w, h, ac, alpha
+                             HIGHBD_TAIL_SUFFIX);
+                    call_new(a_dst, a_dst_stride, topleft, w, h, ac, alpha
+                             HIGHBD_TAIL_SUFFIX);
+                    checkasm_check_pixel_padded(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                                w, h, "dst");
+
+                    bench_new(a_dst, a_dst_stride, topleft, w, h, ac, alpha
+                              HIGHBD_TAIL_SUFFIX);
+                }
+            }
+    report("cfl_pred");
+}
+
+static void check_pal_pred(Dav1dIntraPredDSPContext *const c) {
+    PIXEL_RECT(c_dst, 64, 64);
+    PIXEL_RECT(a_dst, 64, 64);
+    ALIGN_STK_64(uint8_t, idx, 32 * 64,);
+    ALIGN_STK_16(pixel, pal, 8,);
+
+    declare_func(void, pixel *dst, ptrdiff_t stride, const pixel *pal,
+                 const uint8_t *idx, int w, int h);
+
+    for (int w = 4; w <= 64; w <<= 1)
+        if (check_func(c->pal_pred, "pal_pred_w%d_%dbpc", w, BITDEPTH))
+            for (int h = imax(w / 4, 4); h <= imin(w * 4, 64); h <<= 1)
+            {
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                const int bitdepth_max = 0xff;
+#endif
+
+                for (int i = 0; i < 8; i++)
+                    pal[i] = rnd() & bitdepth_max;
+
+                for (int i = 0; i < w * h / 2; i++)
+                    idx[i] = rnd() & 0x77;
+
+                CLEAR_PIXEL_RECT(c_dst);
+                CLEAR_PIXEL_RECT(a_dst);
+
+                call_ref(c_dst, c_dst_stride, pal, idx, w, h);
+                call_new(a_dst, a_dst_stride, pal, idx, w, h);
+                checkasm_check_pixel_padded(c_dst, c_dst_stride,
+                                            a_dst, a_dst_stride, w, h, "dst");
+
+                bench_new(a_dst, a_dst_stride, pal, idx, w, h);
+            }
+    report("pal_pred");
+}
+
+void bitfn(checkasm_check_ipred)(void) {
+    Dav1dIntraPredDSPContext c;
+    bitfn(dav1d_intra_pred_dsp_init)(&c);
+
+    check_intra_pred(&c);
+    check_cfl_ac(&c);
+    check_cfl_pred(&c);
+    check_pal_pred(&c);
+}
diff --git a/media/libdav1d/src/tests/checkasm/itx.c b/media/libdav1d/src/tests/checkasm/itx.c
new file mode 100644
index 0000000000..9686769e4d
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/itx.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+
+#include 
+
+#include "src/itx.h"
+#include "src/levels.h"
+#include "src/scan.h"
+#include "src/tables.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.707106781186547524401
+#endif
+
+enum Tx1D { DCT, ADST, FLIPADST, IDENTITY, WHT };
+
+static const uint8_t itx_1d_types[N_TX_TYPES_PLUS_LL][2] = {
+    [DCT_DCT]           = { DCT,      DCT      },
+    [ADST_DCT]          = { DCT,      ADST     },
+    [DCT_ADST]          = { ADST,     DCT      },
+    [ADST_ADST]         = { ADST,     ADST     },
+    [FLIPADST_DCT]      = { DCT,      FLIPADST },
+    [DCT_FLIPADST]      = { FLIPADST, DCT      },
+    [FLIPADST_FLIPADST] = { FLIPADST, FLIPADST },
+    [ADST_FLIPADST]     = { FLIPADST, ADST     },
+    [FLIPADST_ADST]     = { ADST,     FLIPADST },
+    [IDTX]              = { IDENTITY, IDENTITY },
+    [V_DCT]             = { IDENTITY, DCT      },
+    [H_DCT]             = { DCT,      IDENTITY },
+    [V_ADST]            = { IDENTITY, ADST     },
+    [H_ADST]            = { ADST,     IDENTITY },
+    [V_FLIPADST]        = { IDENTITY, FLIPADST },
+    [H_FLIPADST]        = { FLIPADST, IDENTITY },
+    [WHT_WHT]           = { WHT,      WHT      },
+};
+
+static const char *const itx_1d_names[5] = {
+    [DCT]      = "dct",
+    [ADST]     = "adst",
+    [FLIPADST] = "flipadst",
+    [IDENTITY] = "identity",
+    [WHT]      = "wht"
+};
+
+static const double scaling_factors[9] = {
+    4.0000,             /*  4x4                          */
+    4.0000 * M_SQRT1_2, /*  4x8   8x4                    */
+    2.0000,             /*  4x16  8x8  16x4              */
+    2.0000 * M_SQRT1_2, /*        8x16 16x8              */
+    1.0000,             /*        8x32 16x16 32x8        */
+    0.5000 * M_SQRT1_2, /*             16x32 32x16       */
+    0.2500,             /*             16x64 32x32 64x16 */
+    0.1250 * M_SQRT1_2, /*                   32x64 64x32 */
+    0.0625,             /*                         64x64 */
+};
+
+/* FIXME: Ensure that those forward transforms are similar to the real AV1
+ * transforms. The FLIPADST currently uses the ADST forward transform for
+ * example which is obviously "incorrect", but we're just using it for now
+ * since it does produce coefficients in the correct range at least. */
+
+/* DCT-II */
+static void fdct_1d(double *const out, const double *const in, const int sz) {
+    for (int i = 0; i < sz; i++) {
+        out[i] = 0.0;
+        for (int j = 0; j < sz; j++)
+            out[i] += in[j] * cos(M_PI * (2 * j + 1) * i / (sz * 2.0));
+    }
+    out[0] *= M_SQRT1_2;
+}
+
+/* See "Towards jointly optimal spatial prediction and adaptive transform in
+ * video/image coding", by J. Han, A. Saxena, and K. Rose
+ * IEEE Proc. ICASSP, pp. 726-729, Mar. 2010.
+ * and "A Butterfly Structured Design of The Hybrid Transform Coding Scheme",
+ * by Jingning Han, Yaowu Xu, and Debargha Mukherjee
+ * http://research.google.com/pubs/archive/41418.pdf
+ */
+static void fadst_1d(double *const out, const double *const in, const int sz) {
+    for (int i = 0; i < sz; i++) {
+        out[i] = 0.0;
+        for (int j = 0; j < sz; j++)
+            out[i] += in[j] * sin(M_PI *
+            (sz == 4 ? (    j + 1) * (2 * i + 1) / (8.0 + 1.0) :
+                       (2 * j + 1) * (2 * i + 1) / (sz * 4.0)));
+    }
+}
+
+static void fwht4_1d(double *const out, const double *const in)
+{
+    const double t0 = in[0] + in[1];
+    const double t3 = in[3] - in[2];
+    const double t4 = (t0 - t3) * 0.5;
+    const double t1 = t4 - in[1];
+    const double t2 = t4 - in[2];
+    out[0] = t0 - t2;
+    out[1] = t2;
+    out[2] = t3 + t1;
+    out[3] = t1;
+}
+
+static int copy_subcoefs(coef *coeff,
+                         const enum RectTxfmSize tx, const enum TxfmType txtp,
+                         const int sw, const int sh, const int subsh,
+                         int *const max_eob)
+{
+    /* copy the topleft coefficients such that the return value (being the
+     * coefficient scantable index for the eob token) guarantees that only
+     * the topleft $sub out of $sz (where $sz >= $sub) coefficients in both
+     * dimensions are non-zero. This leads to braching to specific optimized
+     * simd versions (e.g. dc-only) so that we get full asm coverage in this
+     * test */
+
+    const enum TxClass tx_class = dav1d_tx_type_class[txtp];
+    const uint16_t *const scan = dav1d_scans[tx];
+    const int sub_high = subsh > 0 ? subsh * 8 - 1 : 0;
+    const int sub_low  = subsh > 1 ? sub_high - 8 : 0;
+    int n, eob;
+
+    for (n = 0, eob = 0; n < sw * sh; n++) {
+        int rc, rcx, rcy;
+        if (tx_class == TX_CLASS_2D)
+            rc = scan[n], rcx = rc % sh, rcy = rc / sh;
+        else if (tx_class == TX_CLASS_H)
+            rcx = n % sh, rcy = n / sh, rc = n;
+        else /* tx_class == TX_CLASS_V */
+            rcx = n / sw, rcy = n % sw, rc = rcy * sh + rcx;
+
+        /* Pick a random eob within this sub-itx */
+        if (rcx > sub_high || rcy > sub_high) {
+            break; /* upper boundary */
+        } else if (!eob && (rcx > sub_low || rcy > sub_low))
+            eob = n; /* lower boundary */
+    }
+    *max_eob = n - 1;
+
+    if (eob)
+        eob += rnd() % (n - eob - 1);
+    if (tx_class == TX_CLASS_2D)
+        for (n = eob + 1; n < sw * sh; n++)
+            coeff[scan[n]] = 0;
+    else if (tx_class == TX_CLASS_H)
+        for (n = eob + 1; n < sw * sh; n++)
+            coeff[n] = 0;
+    else /* tx_class == TX_CLASS_V */ {
+        for (int rcx = eob / sw, rcy = eob % sw; rcx < sh; rcx++, rcy = -1)
+            while (++rcy < sw)
+                coeff[rcy * sh + rcx] = 0;
+        n = sw * sh;
+    }
+    for (; n < 32 * 32; n++)
+        coeff[n] = rnd();
+    return eob;
+}
+
+static int ftx(coef *const buf, const enum RectTxfmSize tx,
+               const enum TxfmType txtp, const int w, const int h,
+               const int subsh, int *const max_eob, const int bitdepth_max)
+{
+    double out[64 * 64], temp[64 * 64];
+    const double scale = scaling_factors[ctz(w * h) - 4];
+    const int sw = imin(w, 32), sh = imin(h, 32);
+
+    for (int i = 0; i < h; i++) {
+        double in[64], temp_out[64];
+
+        for (int i = 0; i < w; i++)
+            in[i] = (rnd() & (2 * bitdepth_max + 1)) - bitdepth_max;
+
+        switch (itx_1d_types[txtp][0]) {
+        case DCT:
+            fdct_1d(temp_out, in, w);
+            break;
+        case ADST:
+        case FLIPADST:
+            fadst_1d(temp_out, in, w);
+            break;
+        case WHT:
+            fwht4_1d(temp_out, in);
+            break;
+        case IDENTITY:
+            memcpy(temp_out, in, w * sizeof(*temp_out));
+            break;
+        }
+
+        for (int j = 0; j < w; j++)
+            temp[j * h + i] = temp_out[j] * scale;
+    }
+
+    for (int i = 0; i < w; i++) {
+        switch (itx_1d_types[txtp][0]) {
+        case DCT:
+            fdct_1d(&out[i * h], &temp[i * h], h);
+            break;
+        case ADST:
+        case FLIPADST:
+            fadst_1d(&out[i * h], &temp[i * h], h);
+            break;
+        case WHT:
+            fwht4_1d(&out[i * h], &temp[i * h]);
+            break;
+        case IDENTITY:
+            memcpy(&out[i * h], &temp[i * h], h * sizeof(*out));
+            break;
+        }
+    }
+
+    for (int y = 0; y < sh; y++)
+        for (int x = 0; x < sw; x++)
+            buf[y * sw + x] = (coef) (out[y * w + x] + 0.5);
+
+    return copy_subcoefs(buf, tx, txtp, sw, sh, subsh, max_eob);
+}
+
+static void check_itxfm_add(Dav1dInvTxfmDSPContext *const c,
+                            const enum RectTxfmSize tx)
+{
+    ALIGN_STK_64(coef, coeff, 2, [32 * 32]);
+    PIXEL_RECT(c_dst, 64, 64);
+    PIXEL_RECT(a_dst, 64, 64);
+
+    static const uint8_t subsh_iters[5] = { 2, 2, 3, 5, 5 };
+
+    const int w = dav1d_txfm_dimensions[tx].w * 4;
+    const int h = dav1d_txfm_dimensions[tx].h * 4;
+    const int subsh_max = subsh_iters[imax(dav1d_txfm_dimensions[tx].lw,
+                                           dav1d_txfm_dimensions[tx].lh)];
+#if BITDEPTH == 16
+    const int bpc_min = 10, bpc_max = 12;
+#else
+    const int bpc_min = 8, bpc_max = 8;
+#endif
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, coef *coeff,
+                 int eob HIGHBD_DECL_SUFFIX);
+
+    for (int bpc = bpc_min; bpc <= bpc_max; bpc += 2) {
+        bitfn(dav1d_itx_dsp_init)(c, bpc);
+        for (enum TxfmType txtp = 0; txtp < N_TX_TYPES_PLUS_LL; txtp++)
+            for (int subsh = !!txtp; subsh < subsh_max; subsh++)
+                if (check_func(c->itxfm_add[tx][txtp],
+                               "inv_txfm_add_%dx%d_%s_%s_%d_%dbpc",
+                               w, h, itx_1d_names[itx_1d_types[txtp][0]],
+                               itx_1d_names[itx_1d_types[txtp][1]], subsh,
+                               bpc))
+                {
+                    const int bitdepth_max = (1 << bpc) - 1;
+                    int max_eob;
+                    const int eob = ftx(coeff[0], tx, txtp, w, h, subsh, &max_eob,
+                                        bitdepth_max);
+                    memcpy(coeff[1], coeff[0], sizeof(*coeff));
+
+                    CLEAR_PIXEL_RECT(c_dst);
+                    CLEAR_PIXEL_RECT(a_dst);
+
+                    for (int y = 0; y < h; y++)
+                        for (int x = 0; x < w; x++)
+                            c_dst[y*PXSTRIDE(c_dst_stride) + x] =
+                            a_dst[y*PXSTRIDE(a_dst_stride) + x] = rnd() & bitdepth_max;
+
+                    call_ref(c_dst, c_dst_stride, coeff[0], eob
+                             HIGHBD_TAIL_SUFFIX);
+                    call_new(a_dst, a_dst_stride, coeff[1], eob
+                             HIGHBD_TAIL_SUFFIX);
+
+                    checkasm_check_pixel_padded(c_dst, c_dst_stride,
+                                                a_dst, a_dst_stride,
+                                                w, h, "dst");
+                    if (memcmp(coeff[0], coeff[1], sizeof(*coeff)))
+                        fail();
+
+                    bench_new(alternate(c_dst, a_dst), a_dst_stride,
+                              alternate(coeff[0], coeff[1]), max_eob HIGHBD_TAIL_SUFFIX);
+                }
+    }
+}
+
+void bitfn(checkasm_check_itx)(void) {
+    static const uint8_t txfm_size_order[N_RECT_TX_SIZES] = {
+        TX_4X4,                                               // tx4
+        RTX_4X8,   RTX_8X4,   TX_8X8,                         // tx8
+        RTX_4X16,  RTX_16X4,  RTX_8X16,  RTX_16X8,  TX_16X16, // tx16
+        RTX_8X32,  RTX_32X8,  RTX_16X32, RTX_32X16, TX_32X32, // tx32
+        RTX_16X64, RTX_64X16, RTX_32X64, RTX_64X32, TX_64X64, // tx64
+    };
+
+    /* Zero unused function pointer elements. */
+    Dav1dInvTxfmDSPContext c = { { { 0 } } };
+
+    int idx = 0, tx;
+    do {
+        do {
+            tx = txfm_size_order[idx++];
+            check_itxfm_add(&c, tx);
+        } while (tx >= N_TX_SIZES);
+        report("add_tx%d", 4 << tx);
+    } while (tx < N_TX_SIZES - 1);
+    assert(idx == N_RECT_TX_SIZES);
+}
diff --git a/media/libdav1d/src/tests/checkasm/loongarch/checkasm.S b/media/libdav1d/src/tests/checkasm/loongarch/checkasm.S
new file mode 100644
index 0000000000..bf5a2aa631
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/loongarch/checkasm.S
@@ -0,0 +1,213 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2024, Loongson Technology Corporation Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#define PRIVATE_PREFIX checkasm_
+
+#include "src/loongarch/loongson_asm.S"
+
+const register_init, align=4
+.quad 0x21f86d66c8ca00ce
+.quad 0x75b6ba21077c48ad
+.quad 0xed56bb2dcb3c7736
+.quad 0x8bda43d3fd1a7e06
+.quad 0xb64a9c9e5d318408
+.quad 0xdf9a54b303f1d3a3
+.quad 0x4a75479abd64e097
+.quad 0x249214109d5d1c88
+.quad 0x1a1b2550a612b48c
+.quad 0x79445c159ce79064
+.quad 0x2eed899d5a28ddcd
+.quad 0x86b2536fcd8cf636
+.quad 0xb0856806085e7943
+.quad 0x3f2bf84fc0fcca4e
+.quad 0xacbd382dcf5b8de2
+.quad 0xd229e1f5b281303f
+.quad 0x71aeaff20b095fd9
+.quad 0xab63e2e11fa38ed9
+endconst
+
+const error_message
+.asciz "failed to preserve register"
+endconst
+
+// max number of args used by any asm function.
+#define MAX_ARGS 15
+
+#define CLOBBER_STACK ((8*MAX_ARGS + 15) & ~15)
+
+// Fill dirty data at stack space
+function stack_clobber
+    move    t0,     sp
+    addi.d  t1,     zero,   CLOBBER_STACK
+1:
+    st.d    a0,     sp,     0x00
+    st.d    a1,     sp,    -0x08
+    addi.d  sp,     sp,    -0x10
+    addi.d  t1,     t1,    -0x10
+    blt     zero,   t1,     1b
+    move    sp,     t0
+endfunc
+
+#define ARG_STACK ((8*(MAX_ARGS - 8) + 15) & ~15)
+
+function checked_call
+    // Saved s0 - s8, fs0 - fs7
+    move    t4,     sp
+    addi.d  sp,     sp,     -136
+    st.d    s0,     sp,     0
+    st.d    s1,     sp,     8
+    st.d    s2,     sp,     16
+    st.d    s3,     sp,     24
+    st.d    s4,     sp,     32
+    st.d    s5,     sp,     40
+    st.d    s6,     sp,     48
+    st.d    s7,     sp,     56
+    st.d    s8,     sp,     64
+    fst.d   fs0,    sp,     72
+    fst.d   fs1,    sp,     80
+    fst.d   fs2,    sp,     88
+    fst.d   fs3,    sp,     96
+    fst.d   fs4,    sp,     104
+    fst.d   fs5,    sp,     112
+    fst.d   fs6,    sp,     120
+    fst.d   fs7,    sp,     128
+
+    la.local    t1,   register_init
+    ld.d    s0,     t1,     0
+    ld.d    s1,     t1,     8
+    ld.d    s2,     t1,     16
+    ld.d    s3,     t1,     24
+    ld.d    s4,     t1,     32
+    ld.d    s5,     t1,     40
+    ld.d    s6,     t1,     48
+    ld.d    s7,     t1,     56
+    ld.d    s8,     t1,     64
+    fld.d   fs0,    t1,     72
+    fld.d   fs1,    t1,     80
+    fld.d   fs2,    t1,     88
+    fld.d   fs3,    t1,     96
+    fld.d   fs4,    t1,     104
+    fld.d   fs5,    t1,     112
+    fld.d   fs6,    t1,     120
+    fld.d   fs7,    t1,     128
+
+    addi.d  sp,     sp,     -16
+    st.d    a1,     sp,     0 // ok
+    st.d    ra,     sp,     8 // Ret address
+
+    addi.d  sp,     sp,     -ARG_STACK
+
+    addi.d  t0,     zero,   8*8
+    xor     t1,     t1,     t1
+.rept MAX_ARGS - 8
+    // Skip the first 8 args, that are loaded into registers
+    ldx.d   t2,     t4,     t0
+    stx.d   t2,     sp,     t1
+    addi.d  t0,     t0,     8
+    addi.d  t1,     t1,     8
+.endr
+    move    t3,     a0  // Func
+    ld.d    a0,     t4,     0
+    ld.d    a1,     t4,     8
+    ld.d    a2,     t4,     16
+    ld.d    a3,     t4,     24
+    ld.d    a4,     t4,     32
+    ld.d    a5,     t4,     40
+    ld.d    a6,     t4,     48
+    ld.d    a7,     t4,     56
+
+    jirl    ra,     t3,     0
+
+    addi.d  sp,     sp,     ARG_STACK
+    ld.d    t2,     sp,     0 // ok
+    ld.d    ra,     sp,     8 // Ret address
+    addi.d  sp,     sp,     16
+
+    la.local    t1,   register_init
+    xor         t3,   t3,   t3
+
+.macro check_reg_gr reg1
+    ld.d    t0,     t1,      0
+    xor     t0,     $s\reg1, t0
+    or      t3,     t3,      t0
+    addi.d  t1,     t1,      8
+.endm
+    check_reg_gr 0
+    check_reg_gr 1
+    check_reg_gr 2
+    check_reg_gr 3
+    check_reg_gr 4
+    check_reg_gr 5
+    check_reg_gr 6
+    check_reg_gr 7
+    check_reg_gr 8
+
+.macro check_reg_fr reg1
+    ld.d        t0,     t1,     0
+    movfr2gr.d  t4,     $fs\reg1
+    xor         t0,     t0,     t4
+    or          t3,     t3,     t0
+    addi.d      t1,     t1,     8
+.endm
+    check_reg_fr 0
+    check_reg_fr 1
+    check_reg_fr 2
+    check_reg_fr 3
+    check_reg_fr 4
+    check_reg_fr 5
+    check_reg_fr 6
+    check_reg_fr 7
+
+    beqz    t3,     0f
+
+    st.d        zero,   t2,     0x00 // Set OK to 0
+    la.local    a0,     error_message
+    addi.d      sp,     sp,     -8
+    st.d        ra,     sp,     0
+    bl          puts
+    ld.d        ra,     sp,     0
+    addi.d      sp,     sp,     8
+0:
+    ld.d    s0,     sp,     0
+    ld.d    s1,     sp,     8
+    ld.d    s2,     sp,     16
+    ld.d    s3,     sp,     24
+    ld.d    s4,     sp,     32
+    ld.d    s5,     sp,     40
+    ld.d    s6,     sp,     48
+    ld.d    s7,     sp,     56
+    ld.d    s8,     sp,     64
+    fld.d   fs0,    sp,     72
+    fld.d   fs1,    sp,     80
+    fld.d   fs2,    sp,     88
+    fld.d   fs3,    sp,     96
+    fld.d   fs4,    sp,     104
+    fld.d   fs5,    sp,     112
+    fld.d   fs6,    sp,     120
+    fld.d   fs7,    sp,     128
+    addi.d  sp,     sp,     136
+endfunc
diff --git a/media/libdav1d/src/tests/checkasm/loopfilter.c b/media/libdav1d/src/tests/checkasm/loopfilter.c
new file mode 100644
index 0000000000..7d70d0648c
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/loopfilter.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+
+#include 
+
+#include "src/levels.h"
+#include "src/loopfilter.h"
+
+static void init_lpf_border(pixel *const dst, const ptrdiff_t stride,
+                            int E, int I, const int bitdepth_max)
+{
+    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
+    const int F = 1 << bitdepth_min_8;
+    E <<= bitdepth_min_8;
+    I <<= bitdepth_min_8;
+
+    const int filter_type = rnd() % 4;
+    const int edge_diff = rnd() % ((E + 2) * 4) - 2 * (E + 2);
+    switch (filter_type) {
+    case 0: // random, unfiltered
+        for (int i = -8; i < 8; i++)
+            dst[i * stride] = rnd() & bitdepth_max;
+        break;
+    case 1: // long flat
+        dst[-8 * stride] = rnd() & bitdepth_max;
+        dst[+7 * stride] = rnd() & bitdepth_max;
+        dst[+0 * stride] = rnd() & bitdepth_max;
+        dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
+        for (int i = 1; i < 7; i++) {
+            dst[-(1 + i) * stride] = iclip_pixel(dst[-1 * stride] +
+                                                 rnd() % (2 * (F + 1)) - (F + 1));
+            dst[+(0 + i) * stride] = iclip_pixel(dst[+0 * stride] +
+                                                 rnd() % (2 * (F + 1)) - (F + 1));
+        }
+        break;
+    case 2: // short flat
+        for (int i = 4; i < 8; i++) {
+            dst[-(1 + i) * stride] = rnd() & bitdepth_max;
+            dst[+(0 + i) * stride] = rnd() & bitdepth_max;
+        }
+        dst[+0 * stride] = rnd() & bitdepth_max;
+        dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
+        for (int i = 1; i < 4; i++) {
+            dst[-(1 + i) * stride] = iclip_pixel(dst[-1 * stride] +
+                                                 rnd() % (2 * (F + 1)) - (F + 1));
+            dst[+(0 + i) * stride] = iclip_pixel(dst[+0 * stride] +
+                                                 rnd() % (2 * (F + 1)) - (F + 1));
+        }
+        break;
+    case 3: // normal or hev
+        for (int i = 4; i < 8; i++) {
+            dst[-(1 + i) * stride] = rnd() & bitdepth_max;
+            dst[+(0 + i) * stride] = rnd() & bitdepth_max;
+        }
+        dst[+0 * stride] = rnd() & bitdepth_max;
+        dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
+        for (int i = 1; i < 4; i++) {
+            dst[-(1 + i) * stride] = iclip_pixel(dst[-(0 + i) * stride] +
+                                                 rnd() % (2 * (I + 1)) - (I + 1));
+            dst[+(0 + i) * stride] = iclip_pixel(dst[+(i - 1) * stride] +
+                                                 rnd() % (2 * (I + 1)) - (I + 1));
+        }
+        break;
+    }
+}
+
+static void check_lpf_sb(loopfilter_sb_fn fn, const char *const name,
+                         const int n_blks, const int lf_idx,
+                         const int is_chroma, const int dir)
+{
+    ALIGN_STK_64(pixel, c_dst_mem, 128 * 16,);
+    ALIGN_STK_64(pixel, a_dst_mem, 128 * 16,);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const uint32_t *mask,
+                 const uint8_t (*l)[4], ptrdiff_t b4_stride,
+                 const Av1FilterLUT *lut, int w HIGHBD_DECL_SUFFIX);
+
+    pixel *a_dst, *c_dst;
+    ptrdiff_t stride, b4_stride;
+    int w, h;
+    if (dir) {
+        a_dst = a_dst_mem + n_blks * 4 * 8;
+        c_dst = c_dst_mem + n_blks * 4 * 8;
+        w = n_blks * 4;
+        h = 16;
+        b4_stride = 32;
+    } else {
+        a_dst = a_dst_mem + 8;
+        c_dst = c_dst_mem + 8;
+        w = 16;
+        h = n_blks * 4;
+        b4_stride = 2;
+    }
+    stride = w * sizeof(pixel);
+
+    Av1FilterLUT lut;
+    const int sharp = rnd() & 7;
+    for (int level = 0; level < 64; level++) {
+        int limit = level;
+
+        if (sharp > 0) {
+            limit >>= (sharp + 3) >> 2;
+            limit = imin(limit, 9 - sharp);
+        }
+        limit = imax(limit, 1);
+
+        lut.i[level] = limit;
+        lut.e[level] = 2 * (level + 2) + limit;
+    }
+    lut.sharp[0] = (sharp + 3) >> 2;
+    lut.sharp[1] = sharp ? 9 - sharp : 0xff;
+
+    const int n_strengths = is_chroma ? 2 : 3;
+    for (int i = 0; i < n_strengths; i++) {
+        if (check_func(fn, "%s_w%d_%dbpc", name,
+                       is_chroma ? 4 + 2 * i : 4 << i, BITDEPTH))
+        {
+            uint32_t vmask[4] = { 0 };
+            uint8_t l[32 * 2][4];
+
+            for (int j = 0; j < n_blks; j++) {
+                const int idx = rnd() % (i + 2);
+                if (idx) vmask[idx - 1] |= 1U << j;
+                if (dir) {
+                    l[j][lf_idx] = rnd() & 63;
+                    l[j + 32][lf_idx] = rnd() & 63;
+                } else {
+                    l[j * 2][lf_idx] = rnd() & 63;
+                    l[j * 2 + 1][lf_idx] = rnd() & 63;
+                }
+            }
+#if BITDEPTH == 16
+            const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+            const int bitdepth_max = 0xff;
+#endif
+
+            for (int i = 0; i < 4 * n_blks; i++) {
+                const int x = i >> 2;
+                int L;
+                if (dir) {
+                    L = l[32 + x][lf_idx] ? l[32 + x][lf_idx] : l[x][lf_idx];
+                } else {
+                    L = l[2 * x + 1][lf_idx] ? l[2 * x + 1][lf_idx] : l[2 * x][lf_idx];
+                }
+                init_lpf_border(c_dst + i * (dir ? 1 : 16), dir ? n_blks * 4 : 1,
+                                lut.e[L], lut.i[L], bitdepth_max);
+            }
+            memcpy(a_dst_mem, c_dst_mem, 128 * sizeof(pixel) * 16);
+
+            call_ref(c_dst, stride, vmask,
+                     (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx],
+                     b4_stride, &lut, n_blks HIGHBD_TAIL_SUFFIX);
+            call_new(a_dst, stride, vmask,
+                     (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx],
+                     b4_stride, &lut, n_blks HIGHBD_TAIL_SUFFIX);
+
+            checkasm_check_pixel(c_dst_mem, stride, a_dst_mem, stride,
+                                 w, h, "dst");
+            bench_new(alternate(c_dst, a_dst), stride, vmask,
+                      (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx],
+                      b4_stride, &lut, n_blks HIGHBD_TAIL_SUFFIX);
+        }
+    }
+    report(name);
+}
+
+void bitfn(checkasm_check_loopfilter)(void) {
+    Dav1dLoopFilterDSPContext c;
+
+    bitfn(dav1d_loop_filter_dsp_init)(&c);
+
+    check_lpf_sb(c.loop_filter_sb[0][0], "lpf_h_sb_y", 32, 0, 0, 0);
+    check_lpf_sb(c.loop_filter_sb[0][1], "lpf_v_sb_y", 32, 1, 0, 1);
+    check_lpf_sb(c.loop_filter_sb[1][0], "lpf_h_sb_uv", 16, 2, 1, 0);
+    check_lpf_sb(c.loop_filter_sb[1][1], "lpf_v_sb_uv", 16, 2, 1, 1);
+}
diff --git a/media/libdav1d/src/tests/checkasm/looprestoration.c b/media/libdav1d/src/tests/checkasm/looprestoration.c
new file mode 100644
index 0000000000..eee9d31f2d
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/looprestoration.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+
+#include 
+#include 
+
+#include "src/levels.h"
+#include "src/looprestoration.h"
+#include "src/tables.h"
+
+static int to_binary(int x) { /* 0-15 -> 0000-1111 */
+    return (x & 1) + 5 * (x & 2) + 25 * (x & 4) + 125 * (x & 8);
+}
+
+static void init_tmp(pixel *buf, const ptrdiff_t stride,
+                     const int w, const int h, const int bitdepth_max)
+{
+    const int noise_mask = bitdepth_max >> 4;
+    const int x_off = rnd() & 7, y_off = rnd() & 7;
+
+    for (int y = 0; y < h; y++) {
+        for (int x = 0; x < w; x++) {
+            buf[x] = (((x + x_off) ^ (y + y_off)) & 8 ? bitdepth_max : 0) ^
+                     (rnd() & noise_mask);
+        }
+        buf += PXSTRIDE(stride);
+    }
+}
+
+static void check_wiener(Dav1dLoopRestorationDSPContext *const c, const int bpc) {
+    PIXEL_RECT(c_dst, 384, 64);
+    PIXEL_RECT(a_dst, 384, 64);
+    PIXEL_RECT(h_edge, 384, 8);
+    pixel left[64][4];
+    LooprestorationParams params;
+    int16_t (*const filter)[8] = params.filter;
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride,
+                 const pixel (*const left)[4],
+                 const pixel *lpf, int w, int h,
+                 const LooprestorationParams *params,
+                 enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+    for (int t = 0; t < 2; t++) {
+        if (check_func(c->wiener[t], "wiener_%dtap_%dbpc", t ? 5 : 7, bpc)) {
+            filter[0][0] = filter[0][6] = t ? 0 : (rnd() & 15) - 5;
+            filter[0][1] = filter[0][5] = (rnd() & 31) - 23;
+            filter[0][2] = filter[0][4] = (rnd() & 63) - 17;
+            filter[0][3] = -(filter[0][0] + filter[0][1] + filter[0][2]) * 2;
+#if BITDEPTH != 8
+            filter[0][3] += 128;
+#endif
+
+            filter[1][0] = filter[1][6] = t ? 0 : (rnd() & 15) - 5;
+            filter[1][1] = filter[1][5] = (rnd() & 31) - 23;
+            filter[1][2] = filter[1][4] = (rnd() & 63) - 17;
+            filter[1][3] = 128 - (filter[1][0] + filter[1][1] + filter[1][2]) * 2;
+
+            const int base_w = 1 + (rnd() % 384);
+            const int base_h = 1 + (rnd() & 63);
+            const int bitdepth_max = (1 << bpc) - 1;
+
+            CLEAR_PIXEL_RECT(c_dst);
+            /* We potentially read 3 pixels to the left of the input
+             * pointer, and up to the max width, horizontally.
+             * (In the case of LR_HAVE_RIGHT we read 3 pixels past the
+             * input dimensions, but if LR_HAVE_RIGHT we have w == 256.)
+             * Therefore, initialize (384+4) x 64 pixels. */
+            init_tmp(c_dst - 4, c_dst_stride, 384 + 4, 64, bitdepth_max);
+            init_tmp(h_edge - 4, h_edge_stride, 384 + 4, 8, bitdepth_max);
+            init_tmp((pixel *) left, 4 * sizeof(pixel), 4, 64, bitdepth_max);
+
+            for (enum LrEdgeFlags edges = 0; edges <= 0xf; edges++) {
+                const int w = edges & LR_HAVE_RIGHT ? 256 : base_w;
+                const int h = edges & LR_HAVE_BOTTOM ? 64 : base_h;
+
+                assert(c_dst_stride == a_dst_stride);
+                assert(c_dst_buf_h == a_dst_buf_h);
+                memcpy(a_dst_buf, c_dst_buf, a_dst_stride * a_dst_buf_h);
+
+                assert(c_dst_stride == h_edge_stride);
+                call_ref(c_dst, c_dst_stride, left, h_edge,
+                         w, h, ¶ms, edges HIGHBD_TAIL_SUFFIX);
+                call_new(a_dst, a_dst_stride, left, h_edge,
+                         w, h, ¶ms, edges HIGHBD_TAIL_SUFFIX);
+                if (checkasm_check_pixel_padded_align(c_dst, c_dst_stride,
+                                                      a_dst, a_dst_stride,
+                                                      w, h, "dst", 64, 1))
+                {
+                    fprintf(stderr, "size = %dx%d, edges = %04d\n",
+                            w, h, to_binary(edges));
+                    break;
+                }
+            }
+            bench_new(alternate(c_dst, a_dst), a_dst_stride, left,
+                      h_edge, 256, 64, ¶ms, 0xf HIGHBD_TAIL_SUFFIX);
+        }
+    }
+}
+
+static void check_sgr(Dav1dLoopRestorationDSPContext *const c, const int bpc) {
+    PIXEL_RECT(c_dst, 384, 64);
+    PIXEL_RECT(a_dst, 384, 64);
+    PIXEL_RECT(h_edge, 384, 8);
+    pixel left[64][4];
+    LooprestorationParams params;
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride,
+                 const pixel (*const left)[4],
+                 const pixel *lpf, int w, int h,
+                 const LooprestorationParams *params,
+                 enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
+
+    static const struct { char name[4]; uint8_t idx; } sgr_data[3] = {
+        { "5x5", 14 },
+        { "3x3", 10 },
+        { "mix",  0 },
+    };
+
+    for (int i = 0; i < 3; i++) {
+        if (check_func(c->sgr[i], "sgr_%s_%dbpc", sgr_data[i].name, bpc)) {
+            const uint16_t *const sgr_params = dav1d_sgr_params[sgr_data[i].idx];
+            params.sgr.s0 = sgr_params[0];
+            params.sgr.s1 = sgr_params[1];
+            params.sgr.w0 = sgr_params[0] ? (rnd() & 127) - 96 : 0;
+            params.sgr.w1 = (sgr_params[1] ? 160 - (rnd() & 127) : 33) - params.sgr.w0;
+
+            const int base_w = 1 + (rnd() % 384);
+            const int base_h = 1 + (rnd() & 63);
+            const int bitdepth_max = (1 << bpc) - 1;
+
+            CLEAR_PIXEL_RECT(c_dst);
+            /* We potentially read 3 pixels to the left of the input
+             * pointer, and up to the max width, horizontally.
+             * (In the case of LR_HAVE_RIGHT we read 3 pixels past the
+             * input dimensions, but if LR_HAVE_RIGHT we have w == 256.)
+             * Therefore, initialize (384+4) x 64 pixels. */
+            init_tmp(c_dst - 4, c_dst_stride, 384 + 4, 64, bitdepth_max);
+            init_tmp(h_edge - 4, h_edge_stride, 384 + 4, 8, bitdepth_max);
+            init_tmp((pixel *) left, 4 * sizeof(pixel), 4, 64, bitdepth_max);
+
+            for (enum LrEdgeFlags edges = 0; edges <= 0xf; edges++) {
+                const int w = edges & LR_HAVE_RIGHT ? 256 : base_w;
+                const int h = edges & LR_HAVE_BOTTOM ? 64 : base_h;
+
+                assert(c_dst_stride == a_dst_stride);
+                assert(c_dst_buf_h == a_dst_buf_h);
+                memcpy(a_dst_buf, c_dst_buf, a_dst_stride * a_dst_buf_h);
+
+                assert(c_dst_stride == h_edge_stride);
+                call_ref(c_dst, c_dst_stride, left, h_edge,
+                         w, h, ¶ms, edges HIGHBD_TAIL_SUFFIX);
+                call_new(a_dst, a_dst_stride, left, h_edge,
+                         w, h, ¶ms, edges HIGHBD_TAIL_SUFFIX);
+                if (checkasm_check_pixel_padded_align(c_dst, c_dst_stride,
+                                                      a_dst, a_dst_stride,
+                                                      w, h, "dst", 64, 1))
+                {
+                    fprintf(stderr, "size = %dx%d, edges = %04d\n",
+                            w, h, to_binary(edges));
+                    break;
+                }
+            }
+            bench_new(alternate(c_dst, a_dst), a_dst_stride, left,
+                      h_edge, 256, 64, ¶ms, 0xf HIGHBD_TAIL_SUFFIX);
+        }
+    }
+}
+
+void bitfn(checkasm_check_looprestoration)(void) {
+#if BITDEPTH == 16
+    const int bpc_min = 10, bpc_max = 12;
+#else
+    const int bpc_min = 8, bpc_max = 8;
+#endif
+    for (int bpc = bpc_min; bpc <= bpc_max; bpc += 2) {
+        Dav1dLoopRestorationDSPContext c;
+        bitfn(dav1d_loop_restoration_dsp_init)(&c, bpc);
+        check_wiener(&c, bpc);
+    }
+    report("wiener");
+    for (int bpc = bpc_min; bpc <= bpc_max; bpc += 2) {
+        Dav1dLoopRestorationDSPContext c;
+        bitfn(dav1d_loop_restoration_dsp_init)(&c, bpc);
+        check_sgr(&c, bpc);
+    }
+    report("sgr");
+}
diff --git a/media/libdav1d/src/tests/checkasm/mc.c b/media/libdav1d/src/tests/checkasm/mc.c
new file mode 100644
index 0000000000..f1f5dc3f6d
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/mc.c
@@ -0,0 +1,792 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+
+#include "src/levels.h"
+#include "src/mc.h"
+
+static const char *const filter_names[] = {
+    "8tap_regular",        "8tap_regular_smooth", "8tap_regular_sharp",
+    "8tap_sharp_regular",  "8tap_sharp_smooth",   "8tap_sharp",
+    "8tap_smooth_regular", "8tap_smooth",         "8tap_smooth_sharp",
+    "bilinear"
+};
+
+static const char *const mxy_names[] = { "0", "h", "v", "hv" };
+static const char *const scaled_paths[] = { "", "_dy1", "_dy2" };
+
+static int mc_h_next(const int h) {
+    switch (h) {
+    case 4:
+    case 8:
+    case 16:
+        return (h * 3) >> 1;
+    case 6:
+    case 12:
+    case 24:
+        return (h & (h - 1)) * 2;
+    default:
+        return h * 2;
+    }
+}
+
+static void check_mc(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, src_buf, 135 * 135,);
+    PIXEL_RECT(c_dst, 128, 128);
+    PIXEL_RECT(a_dst, 128, 128);
+    const pixel *src = src_buf + 135 * 3 + 3;
+    const ptrdiff_t src_stride = 135 * sizeof(pixel);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *src,
+                 ptrdiff_t src_stride, int w, int h, int mx, int my
+                 HIGHBD_DECL_SUFFIX);
+
+    for (int filter = 0; filter < N_2D_FILTERS; filter++)
+        for (int w = 2; w <= 128; w <<= 1) {
+            for (int mxy = 0; mxy < 4; mxy++)
+                if (check_func(c->mc[filter], "mc_%s_w%d_%s_%dbpc",
+                    filter_names[filter], w, mxy_names[mxy], BITDEPTH))
+                {
+                    const int h_min = w <= 32 ? 2 : w / 4;
+                    const int h_max = imax(imin(w * 4, 128), 32);
+                    for (int h = h_min; h <= h_max; h = mc_h_next(h)) {
+                        const int mx = (mxy & 1) ? rnd() % 15 + 1 : 0;
+                        const int my = (mxy & 2) ? rnd() % 15 + 1 : 0;
+#if BITDEPTH == 16
+                        const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                        const int bitdepth_max = 0xff;
+#endif
+
+                        for (int i = 0; i < 135 * 135; i++)
+                            src_buf[i] = rnd() & bitdepth_max;
+
+                        CLEAR_PIXEL_RECT(c_dst);
+                        CLEAR_PIXEL_RECT(a_dst);
+
+                        call_ref(c_dst, c_dst_stride, src, src_stride, w, h,
+                                 mx, my HIGHBD_TAIL_SUFFIX);
+                        call_new(a_dst, a_dst_stride, src, src_stride, w, h,
+                                 mx, my HIGHBD_TAIL_SUFFIX);
+                        checkasm_check_pixel_padded(c_dst, c_dst_stride,
+                                                    a_dst, a_dst_stride,
+                                                    w, h, "dst");
+
+                        if (filter == FILTER_2D_8TAP_REGULAR ||
+                            filter == FILTER_2D_8TAP_SHARP ||
+                            filter == FILTER_2D_BILINEAR)
+                        {
+                            bench_new(a_dst, a_dst_stride, src, src_stride, w, h,
+                                      mx, my HIGHBD_TAIL_SUFFIX);
+                        }
+                    }
+                }
+        }
+    report("mc");
+}
+
+/* Generate worst case input in the topleft corner, randomize the rest */
+static void generate_mct_input(pixel *const buf, const int bitdepth_max) {
+    static const int8_t pattern[8] = { -1,  0, -1,  0,  0, -1,  0, -1 };
+    const int sign = -(rnd() & 1);
+
+    for (int y = 0; y < 135; y++)
+        for (int x = 0; x < 135; x++)
+            buf[135*y+x] = ((x | y) < 8 ? (pattern[x] ^ pattern[y] ^ sign)
+                                        : rnd()) & bitdepth_max;
+}
+
+static void check_mct(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, src_buf, 135 * 135,);
+    ALIGN_STK_64(int16_t, c_tmp, 128 * 128,);
+    ALIGN_STK_64(int16_t, a_tmp, 128 * 128,);
+    const pixel *src = src_buf + 135 * 3 + 3;
+    const ptrdiff_t src_stride = 135 * sizeof(pixel);
+
+    declare_func(void, int16_t *tmp, const pixel *src, ptrdiff_t src_stride,
+                 int w, int h, int mx, int my HIGHBD_DECL_SUFFIX);
+
+    for (int filter = 0; filter < N_2D_FILTERS; filter++)
+        for (int w = 4; w <= 128; w <<= 1)
+            for (int mxy = 0; mxy < 4; mxy++)
+                if (check_func(c->mct[filter], "mct_%s_w%d_%s_%dbpc",
+                    filter_names[filter], w, mxy_names[mxy], BITDEPTH))
+                    for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
+                    {
+                        const int mx = (mxy & 1) ? rnd() % 15 + 1 : 0;
+                        const int my = (mxy & 2) ? rnd() % 15 + 1 : 0;
+#if BITDEPTH == 16
+                        const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                        const int bitdepth_max = 0xff;
+#endif
+                        generate_mct_input(src_buf, bitdepth_max);
+
+                        call_ref(c_tmp, src, src_stride, w, h,
+                                 mx, my HIGHBD_TAIL_SUFFIX);
+                        call_new(a_tmp, src, src_stride, w, h,
+                                 mx, my HIGHBD_TAIL_SUFFIX);
+                        checkasm_check(int16_t, c_tmp, w * sizeof(*c_tmp),
+                                                a_tmp, w * sizeof(*a_tmp),
+                                                w, h, "tmp");
+
+                        if (filter == FILTER_2D_8TAP_REGULAR ||
+                            filter == FILTER_2D_8TAP_SHARP ||
+                            filter == FILTER_2D_BILINEAR)
+                        {
+                            bench_new(a_tmp, src, src_stride, w, h,
+                                      mx, my HIGHBD_TAIL_SUFFIX);
+                        }
+                    }
+    report("mct");
+}
+
+static void check_mc_scaled(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, src_buf, 263 * 263,);
+    PIXEL_RECT(c_dst, 128, 128);
+    PIXEL_RECT(a_dst, 128, 128);
+    const pixel *src = src_buf + 263 * 3 + 3;
+    const ptrdiff_t src_stride = 263 * sizeof(pixel);
+#if BITDEPTH == 16
+    const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+    const int bitdepth_max = 0xff;
+#endif
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *src,
+                 ptrdiff_t src_stride, int w, int h,
+                 int mx, int my, int dx, int dy HIGHBD_DECL_SUFFIX);
+
+    for (int filter = 0; filter < N_2D_FILTERS; filter++)
+        for (int w = 2; w <= 128; w <<= 1) {
+            for (int p = 0; p < 3; ++p) {
+                if (check_func(c->mc_scaled[filter], "mc_scaled_%s_w%d%s_%dbpc",
+                               filter_names[filter], w, scaled_paths[p], BITDEPTH))
+                {
+                    const int h_min = w <= 32 ? 2 : w / 4;
+                    const int h_max = imax(imin(w * 4, 128), 32);
+                    for (int h = h_min; h <= h_max; h = mc_h_next(h)) {
+                        const int mx = rnd() % 1024;
+                        const int my = rnd() % 1024;
+                        const int dx = rnd() % 2048 + 1;
+                        const int dy = !p
+                            ? rnd() % 2048 + 1
+                            : p << 10; // ystep=1.0 and ystep=2.0 paths
+
+                        for (int k = 0; k < 263 * 263; k++)
+                            src_buf[k] = rnd() & bitdepth_max;
+
+                        CLEAR_PIXEL_RECT(c_dst);
+                        CLEAR_PIXEL_RECT(a_dst);
+
+                        call_ref(c_dst, c_dst_stride, src, src_stride,
+                                 w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
+                        call_new(a_dst, a_dst_stride, src, src_stride,
+                                 w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
+                        checkasm_check_pixel_padded(c_dst, c_dst_stride,
+                                                    a_dst, a_dst_stride,
+                                                    w, h, "dst");
+
+                        if (filter == FILTER_2D_8TAP_REGULAR ||
+                            filter == FILTER_2D_BILINEAR)
+                            bench_new(a_dst, a_dst_stride, src, src_stride,
+                                      w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
+                    }
+                }
+            }
+        }
+    report("mc_scaled");
+}
+
+static void check_mct_scaled(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, src_buf, 263 * 263,);
+    ALIGN_STK_64(int16_t, c_tmp,   128 * 128,);
+    ALIGN_STK_64(int16_t, a_tmp,   128 * 128,);
+    const pixel *src = src_buf + 263 * 3 + 3;
+    const ptrdiff_t src_stride = 263 * sizeof(pixel);
+#if BITDEPTH == 16
+    const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+    const int bitdepth_max = 0xff;
+#endif
+
+    declare_func(void, int16_t *tmp, const pixel *src, ptrdiff_t src_stride,
+                 int w, int h, int mx, int my, int dx, int dy HIGHBD_DECL_SUFFIX);
+
+    for (int filter = 0; filter < N_2D_FILTERS; filter++)
+        for (int w = 4; w <= 128; w <<= 1)
+            for (int p = 0; p < 3; ++p) {
+                if (check_func(c->mct_scaled[filter], "mct_scaled_%s_w%d%s_%dbpc",
+                               filter_names[filter], w, scaled_paths[p], BITDEPTH))
+                {
+                    const int h_min = imax(w / 4, 4);
+                    const int h_max = imin(w * 4, 128);
+                    for (int h = h_min; h <= h_max; h = mc_h_next(h)) {
+                        const int mx = rnd() % 1024;
+                        const int my = rnd() % 1024;
+                        const int dx = rnd() % 2048 + 1;
+                        const int dy = !p
+                            ? rnd() % 2048 + 1
+                            : p << 10; // ystep=1.0 and ystep=2.0 paths
+
+                        for (int k = 0; k < 263 * 263; k++)
+                            src_buf[k] = rnd() & bitdepth_max;
+
+                        call_ref(c_tmp, src, src_stride,
+                                 w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
+                        call_new(a_tmp, src, src_stride,
+                                 w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
+                        checkasm_check(int16_t, c_tmp, w * sizeof(*c_tmp),
+                                                a_tmp, w * sizeof(*a_tmp),
+                                                w, h, "tmp");
+
+                        if (filter == FILTER_2D_8TAP_REGULAR ||
+                            filter == FILTER_2D_BILINEAR)
+                            bench_new(a_tmp, src, src_stride,
+                                      w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
+                    }
+                }
+            }
+    report("mct_scaled");
+}
+
+static void init_tmp(Dav1dMCDSPContext *const c, pixel *const buf,
+                     int16_t (*const tmp)[128 * 128], const int bitdepth_max)
+{
+    for (int i = 0; i < 2; i++) {
+        generate_mct_input(buf, bitdepth_max);
+        c->mct[FILTER_2D_8TAP_SHARP](tmp[i], buf + 135 * 3 + 3,
+                                      135 * sizeof(pixel), 128, 128,
+                                      8, 8 HIGHBD_TAIL_SUFFIX);
+    }
+}
+
+static void check_avg(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(int16_t, tmp, 2, [128 * 128]);
+    PIXEL_RECT(c_dst, 135, 135);
+    PIXEL_RECT(a_dst, 128, 128);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const int16_t *tmp1,
+                 const int16_t *tmp2, int w, int h HIGHBD_DECL_SUFFIX);
+
+    for (int w = 4; w <= 128; w <<= 1)
+        if (check_func(c->avg, "avg_w%d_%dbpc", w, BITDEPTH)) {
+            for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
+            {
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                const int bitdepth_max = 0xff;
+#endif
+
+                init_tmp(c, c_dst, tmp, bitdepth_max);
+
+                CLEAR_PIXEL_RECT(c_dst);
+                CLEAR_PIXEL_RECT(a_dst);
+
+                call_ref(c_dst, c_dst_stride, tmp[0], tmp[1], w, h HIGHBD_TAIL_SUFFIX);
+                call_new(a_dst, a_dst_stride, tmp[0], tmp[1], w, h HIGHBD_TAIL_SUFFIX);
+                checkasm_check_pixel_padded(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                            w, h, "dst");
+
+                bench_new(a_dst, a_dst_stride, tmp[0], tmp[1], w, h HIGHBD_TAIL_SUFFIX);
+            }
+        }
+    report("avg");
+}
+
+static void check_w_avg(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(int16_t, tmp, 2, [128 * 128]);
+    PIXEL_RECT(c_dst, 135, 135);
+    PIXEL_RECT(a_dst, 128, 128);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const int16_t *tmp1,
+                 const int16_t *tmp2, int w, int h, int weight HIGHBD_DECL_SUFFIX);
+
+    for (int w = 4; w <= 128; w <<= 1)
+        if (check_func(c->w_avg, "w_avg_w%d_%dbpc", w, BITDEPTH)) {
+            for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
+            {
+                int weight = rnd() % 15 + 1;
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                const int bitdepth_max = 0xff;
+#endif
+                init_tmp(c, c_dst, tmp, bitdepth_max);
+
+                CLEAR_PIXEL_RECT(c_dst);
+                CLEAR_PIXEL_RECT(a_dst);
+
+                call_ref(c_dst, c_dst_stride, tmp[0], tmp[1], w, h, weight HIGHBD_TAIL_SUFFIX);
+                call_new(a_dst, a_dst_stride, tmp[0], tmp[1], w, h, weight HIGHBD_TAIL_SUFFIX);
+                checkasm_check_pixel_padded(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                            w, h, "dst");
+
+                bench_new(a_dst, a_dst_stride, tmp[0], tmp[1], w, h, weight HIGHBD_TAIL_SUFFIX);
+            }
+        }
+    report("w_avg");
+}
+
+static void check_mask(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(int16_t, tmp, 2, [128 * 128]);
+    PIXEL_RECT(c_dst, 135, 135);
+    PIXEL_RECT(a_dst, 128, 128);
+    ALIGN_STK_64(uint8_t, mask,  128 * 128,);
+
+    for (int i = 0; i < 128 * 128; i++)
+        mask[i] = rnd() % 65;
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const int16_t *tmp1,
+                 const int16_t *tmp2, int w, int h, const uint8_t *mask
+                 HIGHBD_DECL_SUFFIX);
+
+    for (int w = 4; w <= 128; w <<= 1)
+        if (check_func(c->mask, "mask_w%d_%dbpc", w, BITDEPTH)) {
+            for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
+            {
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                const int bitdepth_max = 0xff;
+#endif
+                init_tmp(c, c_dst, tmp, bitdepth_max);
+
+                CLEAR_PIXEL_RECT(c_dst);
+                CLEAR_PIXEL_RECT(a_dst);
+
+                call_ref(c_dst, c_dst_stride, tmp[0], tmp[1], w, h, mask HIGHBD_TAIL_SUFFIX);
+                call_new(a_dst, a_dst_stride, tmp[0], tmp[1], w, h, mask HIGHBD_TAIL_SUFFIX);
+                checkasm_check_pixel_padded(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                            w, h, "dst");
+
+                bench_new(a_dst, a_dst_stride, tmp[0], tmp[1], w, h, mask HIGHBD_TAIL_SUFFIX);
+            }
+        }
+    report("mask");
+}
+
+static void check_w_mask(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(int16_t, tmp, 2, [128 * 128]);
+    PIXEL_RECT(c_dst, 135, 135);
+    PIXEL_RECT(a_dst, 128, 128);
+    ALIGN_STK_64(uint8_t, c_mask, 128 * 128,);
+    ALIGN_STK_64(uint8_t, a_mask, 128 * 128,);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const int16_t *tmp1,
+                 const int16_t *tmp2, int w, int h, uint8_t *mask, int sign
+                 HIGHBD_DECL_SUFFIX);
+
+    static const uint16_t ss[] = { 444, 422, 420 };
+    static const uint8_t ss_hor[] = { 0, 1, 1 };
+    static const uint8_t ss_ver[] = { 0, 0, 1 };
+
+    for (int i = 0; i < 3; i++)
+        for (int w = 4; w <= 128; w <<= 1)
+            if (check_func(c->w_mask[i], "w_mask_%d_w%d_%dbpc", ss[i], w,
+                           BITDEPTH))
+            {
+                for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
+                {
+                    int sign = rnd() & 1;
+#if BITDEPTH == 16
+                    const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                    const int bitdepth_max = 0xff;
+#endif
+                    init_tmp(c, c_dst, tmp, bitdepth_max);
+
+                    CLEAR_PIXEL_RECT(c_dst);
+                    CLEAR_PIXEL_RECT(a_dst);
+
+                    call_ref(c_dst, c_dst_stride, tmp[0], tmp[1], w, h,
+                             c_mask, sign HIGHBD_TAIL_SUFFIX);
+                    call_new(a_dst, a_dst_stride, tmp[0], tmp[1], w, h,
+                             a_mask, sign HIGHBD_TAIL_SUFFIX);
+                    checkasm_check_pixel_padded(c_dst, c_dst_stride,
+                                                a_dst, a_dst_stride,
+                                                w, h, "dst");
+                    checkasm_check(uint8_t, c_mask, w >> ss_hor[i],
+                                            a_mask, w >> ss_hor[i],
+                                            w >> ss_hor[i], h >> ss_ver[i],
+                                            "mask");
+
+                    bench_new(a_dst, a_dst_stride, tmp[0], tmp[1], w, h,
+                              a_mask, sign HIGHBD_TAIL_SUFFIX);
+                }
+            }
+    report("w_mask");
+}
+
+static void check_blend(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, tmp, 32 * 32,);
+    PIXEL_RECT(c_dst, 32, 32);
+    PIXEL_RECT(a_dst, 32, 32);
+    ALIGN_STK_64(uint8_t, mask, 32 * 32,);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *tmp,
+                 int w, int h, const uint8_t *mask);
+
+    for (int w = 4; w <= 32; w <<= 1) {
+        if (check_func(c->blend, "blend_w%d_%dbpc", w, BITDEPTH))
+            for (int h = imax(w / 2, 4); h <= imin(w * 2, 32); h <<= 1) {
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                const int bitdepth_max = 0xff;
+#endif
+                for (int i = 0; i < 32 * 32; i++) {
+                    tmp[i] = rnd() & bitdepth_max;
+                    mask[i] = rnd() % 65;
+                }
+
+                CLEAR_PIXEL_RECT(c_dst);
+                CLEAR_PIXEL_RECT(a_dst);
+
+                for (int y = 0; y < h; y++)
+                    for (int x = 0; x < w; x++)
+                        c_dst[y*PXSTRIDE(c_dst_stride) + x] =
+                        a_dst[y*PXSTRIDE(a_dst_stride) + x] = rnd() & bitdepth_max;
+
+                call_ref(c_dst, c_dst_stride, tmp, w, h, mask);
+                call_new(a_dst, a_dst_stride, tmp, w, h, mask);
+                checkasm_check_pixel_padded(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                            w, h, "dst");
+
+                bench_new(alternate(c_dst, a_dst), a_dst_stride, tmp, w, h, mask);
+            }
+    }
+    report("blend");
+}
+
+static void check_blend_v(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, tmp,   32 * 128,);
+    PIXEL_RECT(c_dst, 32, 128);
+    PIXEL_RECT(a_dst, 32, 128);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *tmp,
+                 int w, int h);
+
+    for (int w = 2; w <= 32; w <<= 1) {
+        if (check_func(c->blend_v, "blend_v_w%d_%dbpc", w, BITDEPTH))
+            for (int h = 2; h <= (w == 2 ? 64 : 128); h <<= 1) {
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                const int bitdepth_max = 0xff;
+#endif
+
+                CLEAR_PIXEL_RECT(c_dst);
+                CLEAR_PIXEL_RECT(a_dst);
+
+                for (int y = 0; y < h; y++)
+                    for (int x = 0; x < w; x++)
+                        c_dst[y*PXSTRIDE(c_dst_stride) + x] =
+                        a_dst[y*PXSTRIDE(a_dst_stride) + x] = rnd() & bitdepth_max;
+
+                for (int i = 0; i < 32 * 128; i++)
+                    tmp[i] = rnd() & bitdepth_max;
+
+                call_ref(c_dst, c_dst_stride, tmp, w, h);
+                call_new(a_dst, a_dst_stride, tmp, w, h);
+                checkasm_check_pixel_padded(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                            w, h, "dst");
+
+                bench_new(alternate(c_dst, a_dst), a_dst_stride, tmp, w, h);
+            }
+    }
+    report("blend_v");
+}
+
+static void check_blend_h(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, tmp,   128 * 32,);
+    PIXEL_RECT(c_dst, 128, 32);
+    PIXEL_RECT(a_dst, 128, 32);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *tmp,
+                 int w, int h);
+
+    for (int w = 2; w <= 128; w <<= 1) {
+        if (check_func(c->blend_h, "blend_h_w%d_%dbpc", w, BITDEPTH))
+            for (int h = (w == 128 ? 4 : 2); h <= 32; h <<= 1) {
+#if BITDEPTH == 16
+                const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+                const int bitdepth_max = 0xff;
+#endif
+                CLEAR_PIXEL_RECT(c_dst);
+                CLEAR_PIXEL_RECT(a_dst);
+
+                for (int y = 0; y < h; y++)
+                    for (int x = 0; x < w; x++)
+                        c_dst[y*PXSTRIDE(c_dst_stride) + x] =
+                        a_dst[y*PXSTRIDE(a_dst_stride) + x] = rnd() & bitdepth_max;
+
+                for (int i = 0; i < 128 * 32; i++)
+                    tmp[i] = rnd() & bitdepth_max;
+
+                call_ref(c_dst, c_dst_stride, tmp, w, h);
+                call_new(a_dst, a_dst_stride, tmp, w, h);
+                checkasm_check_pixel_padded(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                            w, h, "dst");
+
+                bench_new(alternate(c_dst, a_dst), a_dst_stride, tmp, w, h);
+            }
+    }
+    report("blend_h");
+}
+
+static void check_warp8x8(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, src_buf, 15 * 15,);
+    PIXEL_RECT(c_dst, 8, 8);
+    PIXEL_RECT(a_dst, 8, 8);
+    int16_t abcd[4];
+    const pixel *src = src_buf + 15 * 3 + 3;
+    const ptrdiff_t src_stride = 15 * sizeof(pixel);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *src,
+                 ptrdiff_t src_stride, const int16_t *abcd, int mx, int my
+                 HIGHBD_DECL_SUFFIX);
+
+    if (check_func(c->warp8x8, "warp_8x8_%dbpc", BITDEPTH)) {
+        const int mx = (rnd() & 0x1fff) - 0xa00;
+        const int my = (rnd() & 0x1fff) - 0xa00;
+#if BITDEPTH == 16
+        const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+        const int bitdepth_max = 0xff;
+#endif
+
+        for (int i = 0; i < 4; i++)
+            abcd[i] = (rnd() & 0x1fff) - 0xa00;
+
+        for (int i = 0; i < 15 * 15; i++)
+            src_buf[i] = rnd() & bitdepth_max;
+
+        CLEAR_PIXEL_RECT(c_dst);
+        CLEAR_PIXEL_RECT(a_dst);
+
+        call_ref(c_dst, c_dst_stride, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
+        call_new(a_dst, a_dst_stride, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
+        checkasm_check_pixel_padded(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                    8, 8, "dst");
+
+        bench_new(a_dst, a_dst_stride, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
+    }
+    report("warp8x8");
+}
+
+static void check_warp8x8t(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, src_buf, 15 * 15,);
+    ALIGN_STK_64(int16_t, c_tmp,  8 *  8,);
+    ALIGN_STK_64(int16_t, a_tmp,  8 *  8,);
+    int16_t abcd[4];
+    const pixel *src = src_buf + 15 * 3 + 3;
+    const ptrdiff_t src_stride = 15 * sizeof(pixel);
+
+    declare_func(void, int16_t *tmp, ptrdiff_t tmp_stride, const pixel *src,
+                 ptrdiff_t src_stride, const int16_t *abcd, int mx, int my
+                 HIGHBD_DECL_SUFFIX);
+
+    if (check_func(c->warp8x8t, "warp_8x8t_%dbpc", BITDEPTH)) {
+        const int mx = (rnd() & 0x1fff) - 0xa00;
+        const int my = (rnd() & 0x1fff) - 0xa00;
+#if BITDEPTH == 16
+        const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+        const int bitdepth_max = 0xff;
+#endif
+
+        for (int i = 0; i < 4; i++)
+            abcd[i] = (rnd() & 0x1fff) - 0xa00;
+
+        for (int i = 0; i < 15 * 15; i++)
+            src_buf[i] = rnd() & bitdepth_max;
+
+        call_ref(c_tmp, 8, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
+        call_new(a_tmp, 8, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
+        checkasm_check(int16_t, c_tmp, 8 * sizeof(*c_tmp),
+                                a_tmp, 8 * sizeof(*a_tmp),
+                                8, 8, "tmp");
+
+        bench_new(a_tmp, 8, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
+    }
+    report("warp8x8t");
+}
+
+enum EdgeFlags {
+    HAVE_TOP = 1,
+    HAVE_BOTTOM = 2,
+    HAVE_LEFT = 4,
+    HAVE_RIGHT = 8,
+};
+
+static void random_offset_for_edge(int *const x, int *const y,
+                                   const int bw, const int bh,
+                                   int *const iw, int *const ih,
+                                   const enum EdgeFlags edge)
+{
+#define set_off(edge1, edge2, pos, dim) \
+    *i##dim = edge & (HAVE_##edge1 | HAVE_##edge2) ? 160 : 1 + (rnd() % (b##dim - 2)); \
+    switch (edge & (HAVE_##edge1 | HAVE_##edge2)) { \
+    case HAVE_##edge1 | HAVE_##edge2: \
+        assert(b##dim <= *i##dim); \
+        *pos = rnd() % (*i##dim - b##dim + 1); \
+        break; \
+    case HAVE_##edge1: \
+        *pos = (*i##dim - b##dim) + 1 + (rnd() % (b##dim - 1)); \
+        break; \
+    case HAVE_##edge2: \
+        *pos = -(1 + (rnd() % (b##dim - 1))); \
+        break; \
+    case 0: \
+        assert(b##dim - 1 > *i##dim); \
+        *pos = -(1 + (rnd() % (b##dim - *i##dim - 1))); \
+        break; \
+    }
+    set_off(LEFT, RIGHT, x, w);
+    set_off(TOP, BOTTOM, y, h);
+}
+
+static void check_emuedge(Dav1dMCDSPContext *const c) {
+    ALIGN_STK_64(pixel, c_dst, 135 * 192,);
+    ALIGN_STK_64(pixel, a_dst, 135 * 192,);
+    ALIGN_STK_64(pixel, src,   160 * 160,);
+
+    for (int i = 0; i < 160 * 160; i++)
+        src[i] = rnd() & ((1U << BITDEPTH) - 1);
+
+    declare_func(void, intptr_t bw, intptr_t bh, intptr_t iw, intptr_t ih,
+                 intptr_t x, intptr_t y,
+                 pixel *dst, ptrdiff_t dst_stride,
+                 const pixel *src, ptrdiff_t src_stride);
+
+    int x, y, iw, ih;
+    for (int w = 4; w <= 128; w <<= 1)
+        if (check_func(c->emu_edge, "emu_edge_w%d_%dbpc", w, BITDEPTH)) {
+            for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1) {
+                // we skip 0xf, since it implies that we don't need emu_edge
+                for (enum EdgeFlags edge = 0; edge < 0xf; edge++) {
+                    const int bw = w + (rnd() & 7);
+                    const int bh = h + (rnd() & 7);
+                    random_offset_for_edge(&x, &y, bw, bh, &iw, &ih, edge);
+                    call_ref(bw, bh, iw, ih, x, y,
+                             c_dst, 192 * sizeof(pixel), src, 160 * sizeof(pixel));
+                    call_new(bw, bh, iw, ih, x, y,
+                             a_dst, 192 * sizeof(pixel), src, 160 * sizeof(pixel));
+                    checkasm_check_pixel(c_dst, 192 * sizeof(pixel),
+                                         a_dst, 192 * sizeof(pixel),
+                                         bw, bh, "dst");
+                }
+            }
+            for (enum EdgeFlags edge = 1; edge < 0xf; edge <<= 1) {
+                random_offset_for_edge(&x, &y, w + 7, w + 7, &iw, &ih, edge);
+                bench_new(w + 7, w + 7, iw, ih, x, y,
+                          a_dst, 192 * sizeof(pixel), src, 160 * sizeof(pixel));
+            }
+        }
+    report("emu_edge");
+}
+
+static int get_upscale_x0(const int in_w, const int out_w, const int step) {
+    const int err = out_w * step - (in_w << 14);
+    const int x0 = (-((out_w - in_w) << 13) + (out_w >> 1)) / out_w + 128 - (err >> 1);
+    return x0 & 0x3fff;
+}
+
+static void check_resize(Dav1dMCDSPContext *const c) {
+    PIXEL_RECT(c_dst, 1024, 64);
+    PIXEL_RECT(a_dst, 1024, 64);
+    ALIGN_STK_64(pixel, src, 512 * 64,);
+
+    const int height = 64;
+    const int max_src_width = 512;
+    const ptrdiff_t src_stride = 512 * sizeof(pixel);
+
+    declare_func(void, pixel *dst, ptrdiff_t dst_stride,
+                 const pixel *src, ptrdiff_t src_stride,
+                 int dst_w, int src_w, int h, int dx, int mx0
+                 HIGHBD_DECL_SUFFIX);
+
+    if (check_func(c->resize, "resize_%dbpc", BITDEPTH)) {
+#if BITDEPTH == 16
+        const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
+#else
+        const int bitdepth_max = 0xff;
+#endif
+
+        for (int i = 0; i < max_src_width * height; i++)
+            src[i] = rnd() & bitdepth_max;
+
+        const int w_den = 9 + (rnd() & 7);
+        const int src_w = 16 + (rnd() % (max_src_width - 16 + 1));
+        const int dst_w = w_den * src_w >> 3;
+#define scale_fac(ref_sz, this_sz) \
+    ((((ref_sz) << 14) + ((this_sz) >> 1)) / (this_sz))
+        const int dx = scale_fac(src_w, dst_w);
+#undef scale_fac
+        const int mx0 = get_upscale_x0(src_w, dst_w, dx);
+
+        CLEAR_PIXEL_RECT(c_dst);
+        CLEAR_PIXEL_RECT(a_dst);
+
+        call_ref(c_dst, c_dst_stride, src, src_stride,
+                 dst_w, height, src_w, dx, mx0 HIGHBD_TAIL_SUFFIX);
+        call_new(a_dst, a_dst_stride, src, src_stride,
+                 dst_w, height, src_w, dx, mx0 HIGHBD_TAIL_SUFFIX);
+        checkasm_check_pixel_padded_align(c_dst, c_dst_stride, a_dst, a_dst_stride,
+                                          dst_w, height, "dst", 16, 1);
+
+        bench_new(a_dst, a_dst_stride, src, src_stride,
+                  512, height, 512 * 8 / w_den, dx, mx0 HIGHBD_TAIL_SUFFIX);
+    }
+
+    report("resize");
+}
+
+void bitfn(checkasm_check_mc)(void) {
+    Dav1dMCDSPContext c;
+    bitfn(dav1d_mc_dsp_init)(&c);
+
+    check_mc(&c);
+    check_mct(&c);
+    check_mc_scaled(&c);
+    check_mct_scaled(&c);
+    check_avg(&c);
+    check_w_avg(&c);
+    check_mask(&c);
+    check_w_mask(&c);
+    check_blend(&c);
+    check_blend_v(&c);
+    check_blend_h(&c);
+    check_warp8x8(&c);
+    check_warp8x8t(&c);
+    check_emuedge(&c);
+    check_resize(&c);
+}
diff --git a/media/libdav1d/src/tests/checkasm/msac.c b/media/libdav1d/src/tests/checkasm/msac.c
new file mode 100644
index 0000000000..3771c22776
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/msac.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+
+#include "src/cpu.h"
+#include "src/msac.h"
+
+#include 
+#include 
+
+#define BUF_SIZE 128
+
+/* The normal code doesn't use function pointers */
+typedef unsigned (*decode_symbol_adapt_fn)(MsacContext *s, uint16_t *cdf,
+                                           size_t n_symbols);
+typedef unsigned (*decode_adapt_fn)(MsacContext *s, uint16_t *cdf);
+typedef unsigned (*decode_bool_equi_fn)(MsacContext *s);
+typedef unsigned (*decode_bool_fn)(MsacContext *s, unsigned f);
+
+typedef struct {
+    decode_symbol_adapt_fn decode_symbol_adapt4;
+    decode_symbol_adapt_fn decode_symbol_adapt8;
+    decode_symbol_adapt_fn decode_symbol_adapt16;
+    decode_adapt_fn        decode_bool_adapt;
+    decode_bool_equi_fn    decode_bool_equi;
+    decode_bool_fn         decode_bool;
+    decode_adapt_fn        decode_hi_tok;
+} MsacDSPContext;
+
+static void randomize_cdf(uint16_t *const cdf, const int n) {
+    int i;
+    for (i = 15; i > n; i--)
+        cdf[i] = 0; // padding
+    cdf[i] = 0;     // count
+    do {
+        cdf[i - 1] = cdf[i] + rnd() % (32768 - cdf[i] - i) + 1;
+    } while (--i > 0);
+}
+
+/* memcmp() on structs can have weird behavior due to padding etc. */
+static int msac_cmp(const MsacContext *const a, const MsacContext *const b) {
+    if (a->buf_pos != b->buf_pos || a->buf_end != b->buf_end ||
+        a->rng != b->rng || a->cnt != b->cnt ||
+        a->allow_update_cdf != b->allow_update_cdf)
+    {
+        return 1;
+    }
+
+    /* Only check valid dif bits, ignoring partial bytes at the end */
+    const ec_win dif_mask = ~((~(ec_win)0) >> (imax(a->cnt, 0) + 16));
+    return !!((a->dif ^ b->dif) & dif_mask);
+}
+
+static void msac_dump(unsigned c_res, unsigned a_res,
+                      const MsacContext *const a, const MsacContext *const b,
+                      const uint16_t *const cdf_a, const uint16_t *const cdf_b,
+                      const int num_cdf)
+{
+    if (c_res != a_res)
+        fprintf(stderr, "c_res %u a_res %u\n", c_res, a_res);
+    if (a->buf_pos != b->buf_pos)
+        fprintf(stderr, "buf_pos %p vs %p\n", a->buf_pos, b->buf_pos);
+    if (a->buf_end != b->buf_end)
+        fprintf(stderr, "buf_end %p vs %p\n", a->buf_end, b->buf_end);
+    if (a->dif != b->dif)
+        fprintf(stderr, "dif %zx vs %zx\n", a->dif, b->dif);
+    if (a->rng != b->rng)
+        fprintf(stderr, "rng %u vs %u\n", a->rng, b->rng);
+    if (a->cnt != b->cnt)
+        fprintf(stderr, "cnt %d vs %d\n", a->cnt, b->cnt);
+    if (a->allow_update_cdf != b->allow_update_cdf)
+        fprintf(stderr, "allow_update_cdf %d vs %d\n",
+                a->allow_update_cdf, b->allow_update_cdf);
+    if (num_cdf && memcmp(cdf_a, cdf_b, sizeof(*cdf_a) * (num_cdf + 1))) {
+        fprintf(stderr, "cdf:\n");
+        for (int i = 0; i <= num_cdf; i++)
+            fprintf(stderr, " %5u", cdf_a[i]);
+        fprintf(stderr, "\n");
+        for (int i = 0; i <= num_cdf; i++)
+            fprintf(stderr, " %5u", cdf_b[i]);
+        fprintf(stderr, "\n");
+        for (int i = 0; i <= num_cdf; i++)
+            fprintf(stderr, "     %c", cdf_a[i] != cdf_b[i] ? 'x' : '.');
+        fprintf(stderr, "\n");
+    }
+}
+
+#define CHECK_SYMBOL_ADAPT(n, n_min, n_max) do {                           \
+    if (check_func(c->decode_symbol_adapt##n,                              \
+                   "msac_decode_symbol_adapt%d", n))                       \
+    {                                                                      \
+        for (int cdf_update = 0; cdf_update <= 1; cdf_update++) {          \
+            for (int ns = n_min; ns <= n_max; ns++) {                      \
+                dav1d_msac_init(&s_c, buf, BUF_SIZE, !cdf_update);         \
+                s_a = s_c;                                                 \
+                randomize_cdf(cdf[0], ns);                                 \
+                memcpy(cdf[1], cdf[0], sizeof(*cdf));                      \
+                while (s_c.cnt >= 0) {                                     \
+                    unsigned c_res = call_ref(&s_c, cdf[0], ns);           \
+                    unsigned a_res = call_new(&s_a, cdf[1], ns);           \
+                    if (c_res != a_res || msac_cmp(&s_c, &s_a) ||          \
+                        memcmp(cdf[0], cdf[1], sizeof(**cdf) * (ns + 1)))  \
+                    {                                                      \
+                        if (fail())                                        \
+                            msac_dump(c_res, a_res, &s_c, &s_a,            \
+                                      cdf[0], cdf[1], ns);                 \
+                    }                                                      \
+                }                                                          \
+                if (cdf_update && ns == n - 1)                             \
+                    bench_new(alternate(&s_c, &s_a),                       \
+                              alternate(cdf[0], cdf[1]), ns);              \
+            }                                                              \
+        }                                                                  \
+    }                                                                      \
+} while (0)
+
+static void check_decode_symbol(MsacDSPContext *const c, uint8_t *const buf) {
+    ALIGN_STK_32(uint16_t, cdf, 2, [16]);
+    MsacContext s_c, s_a;
+
+    declare_func(unsigned, MsacContext *s, uint16_t *cdf, size_t n_symbols);
+    CHECK_SYMBOL_ADAPT( 4, 1,  3);
+    CHECK_SYMBOL_ADAPT( 8, 1,  7);
+    CHECK_SYMBOL_ADAPT(16, 3, 15);
+    report("decode_symbol");
+}
+
+static void check_decode_bool_adapt(MsacDSPContext *const c, uint8_t *const buf) {
+    MsacContext s_c, s_a;
+
+    declare_func(unsigned, MsacContext *s, uint16_t *cdf);
+    if (check_func(c->decode_bool_adapt, "msac_decode_bool_adapt")) {
+        uint16_t cdf[2][2];
+        for (int cdf_update = 0; cdf_update <= 1; cdf_update++) {
+            dav1d_msac_init(&s_c, buf, BUF_SIZE, !cdf_update);
+            s_a = s_c;
+            cdf[0][0] = cdf[1][0] = rnd() % 32767 + 1;
+            cdf[0][1] = cdf[1][1] = 0;
+            while (s_c.cnt >= 0) {
+                unsigned c_res = call_ref(&s_c, cdf[0]);
+                unsigned a_res = call_new(&s_a, cdf[1]);
+                if (c_res != a_res || msac_cmp(&s_c, &s_a) ||
+                    memcmp(cdf[0], cdf[1], sizeof(*cdf)))
+                {
+                    if (fail())
+                        msac_dump(c_res, a_res, &s_c, &s_a, cdf[0], cdf[1], 1);
+                }
+            }
+            if (cdf_update)
+                bench_new(alternate(&s_c, &s_a), alternate(cdf[0], cdf[1]));
+        }
+    }
+}
+
+static void check_decode_bool_equi(MsacDSPContext *const c, uint8_t *const buf) {
+    MsacContext s_c, s_a;
+
+    declare_func(unsigned, MsacContext *s);
+    if (check_func(c->decode_bool_equi, "msac_decode_bool_equi")) {
+        dav1d_msac_init(&s_c, buf, BUF_SIZE, 1);
+        s_a = s_c;
+        while (s_c.cnt >= 0) {
+            unsigned c_res = call_ref(&s_c);
+            unsigned a_res = call_new(&s_a);
+            if (c_res != a_res || msac_cmp(&s_c, &s_a)) {
+                if (fail())
+                    msac_dump(c_res, a_res, &s_c, &s_a, NULL, NULL, 0);
+            }
+        }
+        bench_new(alternate(&s_c, &s_a));
+    }
+}
+
+static void check_decode_bool(MsacDSPContext *const c, uint8_t *const buf) {
+    MsacContext s_c, s_a;
+
+    declare_func(unsigned, MsacContext *s, unsigned f);
+    if (check_func(c->decode_bool, "msac_decode_bool")) {
+        dav1d_msac_init(&s_c, buf, BUF_SIZE, 1);
+        s_a = s_c;
+        while (s_c.cnt >= 0) {
+            const unsigned f = rnd() & 0x7fff;
+            unsigned c_res = call_ref(&s_c, f);
+            unsigned a_res = call_new(&s_a, f);
+            if (c_res != a_res || msac_cmp(&s_c, &s_a)) {
+                if (fail())
+                    msac_dump(c_res, a_res, &s_c, &s_a, NULL, NULL, 0);
+            }
+        }
+        bench_new(alternate(&s_c, &s_a), 16384);
+    }
+
+}
+
+static void check_decode_bool_funcs(MsacDSPContext *const c, uint8_t *const buf) {
+    check_decode_bool_adapt(c, buf);
+    check_decode_bool_equi(c, buf);
+    check_decode_bool(c, buf);
+    report("decode_bool");
+}
+
+static void check_decode_hi_tok(MsacDSPContext *const c, uint8_t *const buf) {
+    ALIGN_STK_16(uint16_t, cdf, 2, [16]);
+    MsacContext s_c, s_a;
+
+    declare_func(unsigned, MsacContext *s, uint16_t *cdf);
+    if (check_func(c->decode_hi_tok, "msac_decode_hi_tok")) {
+        for (int cdf_update = 0; cdf_update <= 1; cdf_update++) {
+            dav1d_msac_init(&s_c, buf, BUF_SIZE, !cdf_update);
+            s_a = s_c;
+            randomize_cdf(cdf[0], 3);
+            memcpy(cdf[1], cdf[0], sizeof(*cdf));
+            while (s_c.cnt >= 0) {
+                unsigned c_res = call_ref(&s_c, cdf[0]);
+                unsigned a_res = call_new(&s_a, cdf[1]);
+                if (c_res != a_res || msac_cmp(&s_c, &s_a) ||
+                    memcmp(cdf[0], cdf[1], sizeof(*cdf)))
+                {
+                    if (fail())
+                        msac_dump(c_res, a_res, &s_c, &s_a, cdf[0], cdf[1], 3);
+                    break;
+                }
+            }
+            if (cdf_update)
+                bench_new(alternate(&s_c, &s_a), alternate(cdf[0], cdf[1]));
+        }
+    }
+    report("decode_hi_tok");
+}
+
+void checkasm_check_msac(void) {
+    MsacDSPContext c;
+    c.decode_symbol_adapt4  = dav1d_msac_decode_symbol_adapt_c;
+    c.decode_symbol_adapt8  = dav1d_msac_decode_symbol_adapt_c;
+    c.decode_symbol_adapt16 = dav1d_msac_decode_symbol_adapt_c;
+    c.decode_bool_adapt     = dav1d_msac_decode_bool_adapt_c;
+    c.decode_bool_equi      = dav1d_msac_decode_bool_equi_c;
+    c.decode_bool           = dav1d_msac_decode_bool_c;
+    c.decode_hi_tok         = dav1d_msac_decode_hi_tok_c;
+
+#if (ARCH_AARCH64 || ARCH_ARM) && HAVE_ASM
+    if (dav1d_get_cpu_flags() & DAV1D_ARM_CPU_FLAG_NEON) {
+        c.decode_symbol_adapt4  = dav1d_msac_decode_symbol_adapt4_neon;
+        c.decode_symbol_adapt8  = dav1d_msac_decode_symbol_adapt8_neon;
+        c.decode_symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_neon;
+        c.decode_bool_adapt     = dav1d_msac_decode_bool_adapt_neon;
+        c.decode_bool_equi      = dav1d_msac_decode_bool_equi_neon;
+        c.decode_bool           = dav1d_msac_decode_bool_neon;
+        c.decode_hi_tok         = dav1d_msac_decode_hi_tok_neon;
+    }
+#elif ARCH_LOONGARCH64 && HAVE_ASM
+    if (dav1d_get_cpu_flags() & DAV1D_LOONGARCH_CPU_FLAG_LSX) {
+        c.decode_symbol_adapt4  = dav1d_msac_decode_symbol_adapt4_lsx;
+        c.decode_symbol_adapt8  = dav1d_msac_decode_symbol_adapt8_lsx;
+        c.decode_symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_lsx;
+        c.decode_bool_adapt     = dav1d_msac_decode_bool_adapt_lsx;
+        c.decode_bool           = dav1d_msac_decode_bool_lsx;
+        c.decode_bool_equi      = dav1d_msac_decode_bool_equi_lsx;
+        c.decode_hi_tok         = dav1d_msac_decode_hi_tok_lsx;
+    }
+#elif ARCH_X86 && HAVE_ASM
+    if (dav1d_get_cpu_flags() & DAV1D_X86_CPU_FLAG_SSE2) {
+        c.decode_symbol_adapt4  = dav1d_msac_decode_symbol_adapt4_sse2;
+        c.decode_symbol_adapt8  = dav1d_msac_decode_symbol_adapt8_sse2;
+        c.decode_symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_sse2;
+        c.decode_bool_adapt     = dav1d_msac_decode_bool_adapt_sse2;
+        c.decode_bool_equi      = dav1d_msac_decode_bool_equi_sse2;
+        c.decode_bool           = dav1d_msac_decode_bool_sse2;
+        c.decode_hi_tok         = dav1d_msac_decode_hi_tok_sse2;
+    }
+
+#if ARCH_X86_64
+    if (dav1d_get_cpu_flags() & DAV1D_X86_CPU_FLAG_AVX2) {
+        c.decode_symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_avx2;
+    }
+#endif
+#endif
+
+    uint8_t buf[BUF_SIZE];
+    for (int i = 0; i < BUF_SIZE; i++)
+        buf[i] = rnd();
+
+    check_decode_symbol(&c, buf);
+    check_decode_bool_funcs(&c, buf);
+    check_decode_hi_tok(&c, buf);
+}
diff --git a/media/libdav1d/src/tests/checkasm/pal.c b/media/libdav1d/src/tests/checkasm/pal.c
new file mode 100644
index 0000000000..4ab4b619e9
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/pal.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2023, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+#include "src/pal.h"
+
+#include 
+
+static void check_pal_idx_finish(const Dav1dPalDSPContext *const c) {
+    ALIGN_STK_64(uint8_t, src, 64 * 64,);
+    ALIGN_STK_64(uint8_t, c_dst, 32 * 64,);
+    ALIGN_STK_64(uint8_t, a_dst, 32 * 64,);
+
+    declare_func(void, uint8_t *dst, const uint8_t *src,
+                 int bw, int bh, int w, int h);
+
+    for (int bw = 4; bw <= 64; bw <<= 1) {
+        if (check_func(c->pal_idx_finish, "pal_idx_finish_w%d", bw)) {
+            for (int bh = imax(bw / 4, 4); bh <= imin(bw * 4, 64); bh <<= 1) {
+                const int w = (rnd() & (bw - 4)) + 4;
+                const int h = (rnd() & (bh - 4)) + 4;
+                const int dst_bw = bw / 2;
+
+                for (int i = 0; i < bw * bh; i++)
+                    src[i] = rnd() & 7;
+
+                memset(c_dst, 0x88, dst_bw * bh);
+                memset(a_dst, 0x88, dst_bw * bh);
+
+                call_ref(c_dst, src, bw, bh, w, h);
+                call_new(a_dst, src, bw, bh, w, h);
+                checkasm_check(uint8_t, c_dst, dst_bw, a_dst, dst_bw,
+                                        dst_bw, bh, "dst");
+
+                bench_new(a_dst, src, bw, bh, bw, bh);
+            }
+        }
+    }
+
+    report("pal_idx_finish");
+}
+
+void checkasm_check_pal(void) {
+    Dav1dPalDSPContext c;
+    dav1d_pal_dsp_init(&c);
+
+    check_pal_idx_finish(&c);
+}
diff --git a/media/libdav1d/src/tests/checkasm/refmvs.c b/media/libdav1d/src/tests/checkasm/refmvs.c
new file mode 100644
index 0000000000..db39f86796
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/refmvs.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright © 2021, VideoLAN and dav1d authors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests/checkasm/checkasm.h"
+#include "src/refmvs.h"
+
+#include 
+
+static inline int gen_mv(const int total_bits, int spel_bits) {
+    int bits = rnd() & ((1 << spel_bits) - 1);
+    do {
+        bits |= (rnd() & 1) << spel_bits;
+    } while (rnd() & 1 && ++spel_bits < total_bits);
+    // the do/while makes it relatively more likely to be close to zero (fpel)
+    // than far away
+    return rnd() & 1 ? -bits : bits;
+}
+
+#define ARRAY_SIZE(n) (sizeof(n)/sizeof(*(n)))
+
+static inline int get_min_mv_val(const int idx) {
+    if      (idx <= 9)  return idx;
+    else if (idx <= 18) return (idx - 9) * 10;
+    else if (idx <= 27) return (idx - 18) * 100;
+    else if (idx <= 36) return (idx - 27) * 1000;
+    else                return (idx - 36) * 10000;
+}
+
+static inline void gen_tmv(refmvs_temporal_block *const rb, const uint8_t *const ref2ref) {
+    rb->ref = rnd() % 7;
+    if (!rb->ref) return;
+    static const int x_prob[] = {
+        26447556, 6800591, 3708783,  2198592, 1635940, 1145901, 1052602, 1261759,
+         1099739,  755108, 6075404,  4355916, 3254908, 2897157, 2273676, 2154432,
+         1937436, 1694818, 1466863, 10203087, 5241546, 3328819, 2187483, 1458997,
+         1030842,  806863,  587219,   525024, 1858953,  422368,  114626,   16992
+    };
+    static const int y_prob[] = {
+        33845001, 7591218,  6425971, 4115838, 4032161, 2515962, 2614601, 2343656,
+         2898897, 1397254, 10125350, 5124449, 3232914, 2185499, 1608775, 1342585,
+          980208,  795714,   649665, 3369250, 1298716,  486002,  279588,  235990,
+          110318,   89372,    66895,   46980,  153322,   32960,    4500,     389
+    };
+    const int prob = rnd() % 100000000;
+    int acc = 0;
+    for (unsigned i = 0; i < ARRAY_SIZE(x_prob); i++) {
+        acc += x_prob[i];
+        if (prob < acc) {
+            const int min = get_min_mv_val(i);
+            const int max = get_min_mv_val(i + 1);
+            const int val = min + rnd() % (max - min);
+            rb->mv.x = iclip(val * ref2ref[rb->ref], -(1 << 15), (1 << 15) - 1);
+            break;
+        }
+    }
+    acc = 0;
+    for (unsigned i = 0; i < ARRAY_SIZE(y_prob); i++) {
+        acc += y_prob[i];
+        if (prob < acc) {
+            const int min = get_min_mv_val(i);
+            const int max = get_min_mv_val(i + 1);
+            const int val = min + rnd() % (max - min);
+            rb->mv.y = iclip(val * ref2ref[rb->ref], -(1 << 15), (1 << 15) - 1);
+            break;
+        }
+    }
+}
+
+static inline int get_ref2cur(void) {
+    const int prob = rnd() % 100;
+    static const uint8_t ref2cur[11] = { 35, 55, 67, 73, 78, 83, 84, 87, 90, 93, 100 };
+    for (int i = 0; i < 11; i++)
+        if (prob < ref2cur[i])
+            return rnd() & 1 ? -(i + 1) : i + 1;
+    return 0;
+}
+
+static inline int get_seqlen(void) {
+    int len = 0, max_len;
+    const int prob = rnd() % 100000;
+    // =1 =2 =3 =4  <8  =8 <16 =16 <32 =32 <48 =48 <64 =64 >64 eq240
+    //  5 17 1.5 16  5  10  5   7   4   3  1.5  2   1    2   20   15   chimera blocks
+    // 25 38 2.5 19 3.5 5.5 2 1.87 .86 .4  .18 .2 .067 .165 .478 .28   chimera sequences
+
+    if      (prob < 25000) len = 1;       // =1   5%
+    else if (prob < 63000) len = 2;       // =2   17%
+    else if (prob < 65500) len = 3;       // =3   1.5%
+    else if (prob < 84500) len = 4;       // =4   16%
+    else if (prob < 88000) max_len = 7;   // <8   5% (43.5% tot <8)
+    else if (prob < 93500) len = 8;       // =8   10%
+    else if (prob < 95500) max_len = 15;  // <16  5%
+    else if (prob < 97370) len = 16;      // =16  7%
+    else if (prob < 98230) max_len = 31;  // <32  4%
+    else if (prob < 98630) len = 32;      // =32  3%
+    else if (prob < 98810) max_len = 47;  // <48  1.5%
+    else if (prob < 99010) len = 48;      // =48  2%
+    else if (prob < 99077) max_len = 63;  // <64  1%
+    else if (prob < 99242) len = 64;      // =64  2%
+    else if (prob < 99720) max_len = 239; // <240 5%
+    else                   len = 240;     // =240 15%
+
+    if (!len) len = 1 + rnd() % max_len;
+    return len;
+}
+
+static inline void init_rp_ref(refmvs_frame const *const rf,
+                               const int col_start8, const int col_end8,
+                               const int row_start8, const int row_end8)
+{
+    const int col_start8i = imax(col_start8 - 8, 0);
+    const int col_end8i = imin(col_end8 + 8, rf->iw8);
+    for (int n = 0; n < rf->n_mfmvs; n++) {
+        refmvs_temporal_block *rp_ref = rf->rp_ref[rf->mfmv_ref[n]];
+        for (int i = row_start8; i < imin(row_end8, rf->ih8); i++) {
+            for (int j = col_start8i; j < col_end8i;) {
+                refmvs_temporal_block rb;
+                gen_tmv(&rb, rf->mfmv_ref2ref[n]);
+                for (int k = get_seqlen(); k && j < col_end8i; k--, j++)
+                    rp_ref[i * rf->iw8 + j] = rb;
+            }
+        }
+    }
+}
+
+static void check_load_tmvs(const Dav1dRefmvsDSPContext *const c) {
+    refmvs_temporal_block *rp_ref[7] = {0};
+    refmvs_temporal_block c_rp_proj[240 * 63];
+    refmvs_temporal_block a_rp_proj[240 * 63];
+    refmvs_frame rf = {
+        .rp_ref = rp_ref,
+        .rp_stride = 240, .iw8 = 240, .ih8 = 63,
+        .n_mfmvs = 3
+    };
+    const size_t rp_ref_sz = rf.ih8 * rf.rp_stride * sizeof(refmvs_temporal_block);
+
+    declare_func(void, const refmvs_frame *rf, int tile_row_idx,
+                 int col_start8, int col_end8, int row_start8, int row_end8);
+
+    if (check_func(c->load_tmvs, "load_tmvs")) {
+        const int row_start8 = (rnd() & 3) << 4;
+        const int row_end8 = row_start8 + 16;
+        const int col_start8 = rnd() & 31;
+        const int col_end8 = rf.iw8 - (rnd() & 31);
+
+        for (int n = 0; n < rf.n_mfmvs; n++) {
+            rf.mfmv_ref[n] = rnd() % 7;
+            rf.mfmv_ref2cur[n] = get_ref2cur();
+            for (int r = 0; r < 7; r++)
+                rf.mfmv_ref2ref[n][r] = rnd() & 31;
+        }
+        for (int n = 0; n < rf.n_mfmvs; n++) {
+            refmvs_temporal_block **p_rp_ref = &rp_ref[rf.mfmv_ref[n]];
+            if (!*p_rp_ref)
+                *p_rp_ref = malloc(rp_ref_sz);
+        }
+        init_rp_ref(&rf, 0, rf.iw8, row_start8, row_end8);
+        for (int i = 0; i < rf.iw8 * rf.ih8; i++) {
+            c_rp_proj[i].mv.n = a_rp_proj[i].mv.n = 0xdeadbeef;
+            c_rp_proj[i].ref = a_rp_proj[i].ref = 0xdd;
+        }
+
+        rf.n_tile_threads = 1;
+
+        rf.rp_proj = c_rp_proj;
+        call_ref(&rf, 0, col_start8, col_end8, row_start8, row_end8);
+        rf.rp_proj = a_rp_proj;
+        call_new(&rf, 0, col_start8, col_end8, row_start8, row_end8);
+
+        for (int i = 0; i < rf.ih8; i++)
+            for (int j = 0; j < rf.iw8; j++)
+                if (c_rp_proj[i * rf.iw8 + j].mv.n != a_rp_proj[i * rf.iw8 + j].mv.n ||
+                    (c_rp_proj[i * rf.iw8 + j].ref != a_rp_proj[i * rf.iw8 + j].ref &&
+                     c_rp_proj[i * rf.iw8 + j].mv.n != INVALID_MV))
+                {
+                    if (fail()) {
+                        fprintf(stderr, "[%d][%d] c_rp.mv.x = 0x%x a_rp.mv.x = 0x%x\n",
+                                i, j, c_rp_proj[i * rf.iw8 + j].mv.x, a_rp_proj[i * rf.iw8 + j].mv.x);
+                        fprintf(stderr, "[%d][%d] c_rp.mv.y = 0x%x a_rp.mv.y = 0x%x\n",
+                                i, j, c_rp_proj[i * rf.iw8 + j].mv.y, a_rp_proj[i * rf.iw8 + j].mv.y);
+                        fprintf(stderr, "[%d][%d] c_rp.ref = %u a_rp.ref = %u\n",
+                                i, j, c_rp_proj[i * rf.iw8 + j].ref, a_rp_proj[i * rf.iw8 + j].ref);
+                    }
+                }
+
+        if (checkasm_bench_func()) {
+            for (int n = 0; n < rf.n_mfmvs; n++) {
+                rf.mfmv_ref2cur[n] = 1;
+                for (int r = 0; r < 7; r++)
+                    rf.mfmv_ref2ref[n][r] = 1;
+            }
+            bench_new(&rf, 0, 0, rf.iw8, row_start8, row_end8);
+        }
+
+        for (int n = 0; n < rf.n_mfmvs; n++) {
+            free(rp_ref[rf.mfmv_ref[n]]);
+            rp_ref[rf.mfmv_ref[n]] = NULL;
+        }
+    }
+
+    report("load_tmvs");
+}
+
+static void check_save_tmvs(const Dav1dRefmvsDSPContext *const c) {
+    refmvs_block *rr[31];
+    refmvs_block r[31 * 256];
+    ALIGN_STK_64(refmvs_temporal_block, c_rp, 128 * 16,);
+    ALIGN_STK_64(refmvs_temporal_block, a_rp, 128 * 16,);
+    uint8_t ref_sign[7];
+
+    for (int i = 0; i < 31; i++)
+        rr[i] = &r[i * 256];
+
+    declare_func(void, refmvs_temporal_block *rp, const ptrdiff_t stride,
+                 refmvs_block *const *const rr, const uint8_t *const ref_sign,
+                 int col_end8, int row_end8, int col_start8, int row_start8);
+
+    if (check_func(c->save_tmvs, "save_tmvs")) {
+        const int row_start8 = rnd() & 7;
+        const int row_end8 = 8 + (rnd() & 7);
+        const int col_start8 = rnd() & 31;
+        const int col_end8 = 96 + (rnd() & 31);
+
+        for (int i = 0; i < 7; i++)
+            ref_sign[i] = rnd() & 1;
+
+        for (int i = row_start8; i < row_end8; i++)
+            for (int j = col_start8; j < col_end8;) {
+                int bs = rnd() % N_BS_SIZES;
+                while (j + ((dav1d_block_dimensions[bs][0] + 1) >> 1) > col_end8)
+                    bs++;
+                rr[i * 2][j * 2 + 1] = (refmvs_block) {
+                    .mv.mv[0].x = gen_mv(14, 10),
+                    .mv.mv[0].y = gen_mv(14, 10),
+                    .mv.mv[1].x = gen_mv(14, 10),
+                    .mv.mv[1].y = gen_mv(14, 10),
+                    .ref.ref = { (rnd() % 9) - 1, (rnd() % 9) - 1 },
+                    .bs = bs
+                };
+                for (int k = 0; k < (dav1d_block_dimensions[bs][0] + 1) >> 1; k++, j++) {
+                    c_rp[i * 128 + j].mv.n = 0xdeadbeef;
+                    c_rp[i * 128 + j].ref = 0xdd;
+                }
+            }
+
+        call_ref(c_rp + row_start8 * 128, 128, rr, ref_sign,
+                 col_end8, row_end8, col_start8, row_start8);
+        call_new(a_rp + row_start8 * 128, 128, rr, ref_sign,
+                 col_end8, row_end8, col_start8, row_start8);
+        for (int i = row_start8; i < row_end8; i++)
+            for (int j = col_start8; j < col_end8; j++)
+                if (c_rp[i * 128 + j].mv.n != a_rp[i * 128 + j].mv.n ||
+                    c_rp[i * 128 + j].ref != a_rp[i * 128 + j].ref)
+                {
+                    if (fail()) {
+                        fprintf(stderr, "[%d][%d] c_rp.mv.x = 0x%x a_rp.mv.x = 0x%x\n",
+                                i, j, c_rp[i * 128 + j].mv.x, a_rp[i * 128 + j].mv.x);
+                        fprintf(stderr, "[%d][%d] c_rp.mv.y = 0x%x a_rp.mv.y = 0x%x\n",
+                                i, j, c_rp[i * 128 + j].mv.y, a_rp[i * 128 + j].mv.y);
+                        fprintf(stderr, "[%d][%d] c_rp.ref = %u a_rp.ref = %u\n",
+                                i, j, c_rp[i * 128 + j].ref, a_rp[i * 128 + j].ref);
+                    }
+                }
+
+        for (int bs = BS_4x4; bs < N_BS_SIZES; bs++) {
+            const int bw8 = (dav1d_block_dimensions[bs][0] + 1) >> 1;
+            for (int i = 0; i < 16; i++)
+                for (int j = 0; j < 128; j += bw8) {
+                    rr[i * 2][j * 2 + 1].ref.ref[0] = (rnd() % 9) - 1;
+                    rr[i * 2][j * 2 + 1].ref.ref[1] = (rnd() % 9) - 1;
+                    rr[i * 2][j * 2 + 1].bs = bs;
+                }
+            bench_new(alternate(c_rp, a_rp), 128, rr, ref_sign, 128, 16, 0, 0);
+        }
+    }
+
+    report("save_tmvs");
+}
+
+static void check_splat_mv(const Dav1dRefmvsDSPContext *const c) {
+    ALIGN_STK_64(refmvs_block, c_buf, 32 * 32,);
+    ALIGN_STK_64(refmvs_block, a_buf, 32 * 32,);
+    refmvs_block *c_dst[32];
+    refmvs_block *a_dst[32];
+    const size_t stride = 32 * sizeof(refmvs_block);
+
+    for (int i = 0; i < 32; i++) {
+        c_dst[i] = c_buf + 32 * i;
+        a_dst[i] = a_buf + 32 * i;
+    }
+
+    declare_func(void, refmvs_block **rr, const refmvs_block *rmv,
+                 int bx4, int bw4, int bh4);
+
+    for (int w = 1; w <= 32; w *= 2) {
+        if (check_func(c->splat_mv, "splat_mv_w%d", w)) {
+            const int h_min = imax(w / 4, 1);
+            const int h_max = imin(w * 4, 32);
+            const int w_uint32 = w * sizeof(refmvs_block) / sizeof(uint32_t);
+            for (int h = h_min; h <= h_max; h *= 2) {
+                const int offset = (int) ((unsigned) w * rnd()) & 31;
+                union {
+                    refmvs_block rmv;
+                    uint32_t u32[3];
+                } ALIGN(tmp, 16);
+                tmp.u32[0] = rnd();
+                tmp.u32[1] = rnd();
+                tmp.u32[2] = rnd();
+
+                call_ref(c_dst, &tmp.rmv, offset, w, h);
+                call_new(a_dst, &tmp.rmv, offset, w, h);
+                checkasm_check(uint32_t, (uint32_t*)(c_buf + offset), stride,
+                                         (uint32_t*)(a_buf + offset), stride,
+                                         w_uint32, h, "dst");
+
+                bench_new(a_dst, &tmp.rmv, 0, w, h);
+            }
+        }
+    }
+    report("splat_mv");
+}
+
+void checkasm_check_refmvs(void) {
+    Dav1dRefmvsDSPContext c;
+    dav1d_refmvs_dsp_init(&c);
+
+    check_load_tmvs(&c);
+    check_save_tmvs(&c);
+    check_splat_mv(&c);
+}
diff --git a/media/libdav1d/src/tests/checkasm/riscv/checkasm_64.S b/media/libdav1d/src/tests/checkasm/riscv/checkasm_64.S
new file mode 100644
index 0000000000..0d02e5f1be
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/riscv/checkasm_64.S
@@ -0,0 +1,252 @@
+/******************************************************************************
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2023, Nathan Egge
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#define PRIVATE_PREFIX checkasm_
+
+#include "src/riscv/asm.S"
+
+// max number of args used by any asm function.
+#define MAX_ARGS 15
+
+// + 16 for stack canary reference
+#define ARG_STACK ((8*(MAX_ARGS - 8) + 15) & ~15 + 16)
+
+const register_init, align=4
+        .quad 0x68909d060f4a7fdd
+        .quad 0x924f739e310218a1
+        .quad 0xb988385a8254174c
+        .quad 0x4c1110430bf09fd7
+        .quad 0x2b310edf6a5d7ecf
+        .quad 0xda8112e98ddbb559
+        .quad 0x6da5854aa2f84b62
+        .quad 0x72b761199e9b1f38
+        .quad 0x13f27aa74ae5dcdf
+        .quad 0x36a6c12a7380e827
+        .quad 0x5c452889aefc8548
+        .quad 0x6a9ea1ddb236235f
+        .quad 0x0449854bdfc94b1e
+        .quad 0x4f849b7076a156f5
+        .quad 0x1baa4275e734930e
+        .quad 0x77df3503ba3e073d
+        .quad 0x6060e073705a4bf2
+        .quad 0xa7b482508471e44b
+        .quad 0xd296a3158d6da2b9
+        .quad 0x1c0ed711a93d970b
+        .quad 0x9359537fdd79569d
+        .quad 0x2b1dc95c1e232d62
+        .quad 0xab06cd578e2bb5a0
+        .quad 0x4100b4987a0af30f
+        .quad 0x2523e36f9bb1e36f
+        .quad 0xfb0b815930c6d25c
+        .quad 0x89acc810c2902fcf
+        .quad 0xa65854b4c2b381f1
+        .quad 0x78150d69a1accedf
+        .quad 0x057e24868e022de1
+        .quad 0x88f6e79ed4b8d362
+        .quad 0x1f4a420e262c9035
+endconst
+
+const error_message_register
+error_message_rsvd:
+        .asciz "unallocatable register clobbered"
+error_message_sreg:
+        .asciz "callee-saved integer register s%i modified"
+error_message_fsreg:
+        .asciz "callee-saved floating-point register fs%i modified"
+error_message_stack:
+        .asciz "stack clobbered"
+endconst
+
+thread_local saved_regs, quads=29 # 5 + 12 + 12
+
+function checked_call, export=1, ext=v
+  /* Save the function ptr, RA, SP, unallocatable and callee-saved registers */
+  la.tls.ie t0, saved_regs
+  add t0, tp, t0
+  sd a0, (t0)
+  sd ra, 8(t0)
+  sd sp, 16(t0)
+  sd gp, 24(t0)
+  sd tp, 32(t0)
+.irp n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+  sd s\n, 40 + 16*\n(t0)
+#ifdef __riscv_float_abi_double
+  fsd fs\n, 48 + 16*\n(t0)
+#endif
+.endr
+
+  /* Check for vector extension */
+  call dav1d_get_cpu_flags_riscv
+  and a0, a0, 1 # DAV1D_RISCV_CPU_FLAG_RVV
+  beqz a0, 0f
+
+  /* Clobber vector configuration */
+  vsetvli t0, zero, e32, m8, ta, ma
+  lla t0, register_init
+  ld t0, (t0)
+.irp n, 0, 8, 16, 24
+  vmv.v.x v0, t0
+.endr
+  li t0, -1 << 31
+  vsetvl zero, zero, t0
+  csrwi vxrm, 3
+  csrwi vxsat, 1
+
+0:
+  /* Load the register arguments */
+.irp n, 0, 1, 2, 3, 4, 5, 6, 7
+  ld a\n, 8*\n(sp)
+.endr
+
+  /* Load the stack arguments */
+.irp n, 8, 9, 10, 11, 12, 13, 14, 15
+   ld t0, 8*\n(sp)
+   sd t0, 8*(\n - 8) - ARG_STACK(sp)
+.endr
+
+  /* Setup the stack canary */
+  ld t0, MAX_ARGS*8(sp)
+  addi sp, sp, -ARG_STACK
+  slli t0, t0, 3
+  add t0, t0, sp
+  ld t0, (t0)
+  not t0, t0
+  sd t0, ARG_STACK - 8(sp)
+
+  /* Clobber the stack space right below SP */
+  lla t0, register_init
+  ld t1, (t0)
+.rept 16
+  addi sp, sp, -16
+  sd t1, (sp)
+  sd t1, 8(sp)
+.endr
+  addi sp, sp, 16*16
+
+  /* Clobber the callee-saved and temporary registers */
+.irp n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+.if (\n > 0 && \n < 7)
+  ld t\n, 16*\n(t0)
+.endif
+  ld s\n, 8 + 8*\n(t0)
+#ifdef __riscv_float_abi_double
+  fld ft\n, 16 + 16*\n(t0)
+  fld fs\n, 24 + 8*\n(t0)
+#endif
+.endr
+
+  /* Call the checked function */
+  la.tls.ie t0, saved_regs
+  add t0, tp, t0
+  ld t0, (t0)
+  jalr t0
+
+  /* Check the value of callee-saved registers */
+  lla t0, register_init
+.irp n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+  ld t1, 8 + 8*\n(t0)
+  li a1, \n
+  bne t1, s\n, 2f
+#ifdef __riscv_float_abi_double
+  ld t1, 24 + 8*\n(t0)
+  fmv.x.d t2, fs\n
+  bne t1, t2, 3f
+#endif
+.endr
+
+  /* Check unallocatable register values */
+  la.tls.ie t0, saved_regs
+  add t0, tp, t0
+  ld t1, 16(t0)
+  addi t1, t1, -ARG_STACK
+  bne t1, sp, 4f
+  ld t1, 24(t0)
+  bne t1, gp, 4f
+  ld t1, 32(t0)
+  bne t1, tp, 4f
+
+  /* Check the stack canary */
+  ld t0, ARG_STACK + MAX_ARGS*8(sp)
+  slli t0, t0, 3
+  add t0, t0, sp
+  ld t0, (t0)
+  not t0, t0
+  ld t1, ARG_STACK - 8(sp)
+  bne t0, t1, 5f
+
+1:
+  /* Restore RA, SP and callee-saved registers from thread local storage */
+  la.tls.ie t0, saved_regs
+  add t0, tp, t0
+  ld ra, 8(t0)
+  ld sp, 16(t0)
+.irp n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+  ld s\n, 40 + 16*\n(t0)
+#ifdef __riscv_float_abi_double
+  fld fs\n, 48 + 16*\n(t0)
+#endif
+.endr
+  ret
+
+2:
+  lla a0, error_message_sreg
+#ifdef PREFIX
+  call _checkasm_fail_func
+#else
+  call checkasm_fail_func
+#endif
+  j 1b
+
+#ifdef __riscv_float_abi_double
+3:
+  lla a0, error_message_fsreg
+#ifdef PREFIX
+  call _checkasm_fail_func
+#else
+  call checkasm_fail_func
+#endif
+  j 1b
+#endif
+
+4:
+  lla a0, error_message_rsvd
+#ifdef PREFIX
+  call _checkasm_fail_func
+#else
+  call checkasm_fail_func
+#endif
+  j 1b
+
+5:
+  lla a0, error_message_stack
+#ifdef PREFIX
+  call _checkasm_fail_func
+#else
+  call checkasm_fail_func
+#endif
+  j 1b
+endfunc
diff --git a/media/libdav1d/src/tests/checkasm/x86/checkasm.asm b/media/libdav1d/src/tests/checkasm/x86/checkasm.asm
new file mode 100644
index 0000000000..8f19ef97f7
--- /dev/null
+++ b/media/libdav1d/src/tests/checkasm/x86/checkasm.asm
@@ -0,0 +1,475 @@
+; Copyright © 2018, VideoLAN and dav1d authors
+; Copyright © 2018, Two Orioles, LLC
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice, this
+;    list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+;    this list of conditions and the following disclaimer in the documentation
+;    and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+%include "config.asm"
+%undef private_prefix
+%define private_prefix checkasm
+%include "ext/x86/x86inc.asm"
+
+SECTION_RODATA 16
+
+%if ARCH_X86_64
+; just random numbers to reduce the chance of incidental match
+%if WIN64
+x6:  dq 0x1a1b2550a612b48c,0x79445c159ce79064
+x7:  dq 0x2eed899d5a28ddcd,0x86b2536fcd8cf636
+x8:  dq 0xb0856806085e7943,0x3f2bf84fc0fcca4e
+x9:  dq 0xacbd382dcf5b8de2,0xd229e1f5b281303f
+x10: dq 0x71aeaff20b095fd9,0xab63e2e11fa38ed9
+x11: dq 0x89b0c0765892729a,0x77d410d5c42c882d
+x12: dq 0xc45ea11a955d8dd5,0x24b3c1d2a024048b
+x13: dq 0x2e8ec680de14b47c,0xdd7b8919edd42786
+x14: dq 0x135ce6888fa02cbf,0x11e53e2b2ac655ef
+x15: dq 0x011ff554472a7a10,0x6de8f4c914c334d5
+n7:  dq 0x21f86d66c8ca00ce
+n8:  dq 0x75b6ba21077c48ad
+%endif
+n9:  dq 0xed56bb2dcb3c7736
+n10: dq 0x8bda43d3fd1a7e06
+n11: dq 0xb64a9c9e5d318408
+n12: dq 0xdf9a54b303f1d3a3
+n13: dq 0x4a75479abd64e097
+n14: dq 0x249214109d5d1c88
+%endif
+
+errmsg_stack: db "stack corruption", 0
+errmsg_register: db "failed to preserve register:%s", 0
+errmsg_vzeroupper: db "missing vzeroupper", 0
+
+SECTION .bss
+
+check_vzeroupper: resd 1
+
+SECTION .text
+
+cextern fail_func
+
+; max number of args used by any asm function.
+; (max_args % 4) must equal 3 for stack alignment
+%define max_args 15
+
+%if UNIX64
+    DECLARE_REG_TMP 0
+%else
+    DECLARE_REG_TMP 4
+%endif
+
+;-----------------------------------------------------------------------------
+; unsigned checkasm_init_x86(char *name)
+;-----------------------------------------------------------------------------
+cglobal init_x86, 0, 5
+%if ARCH_X86_64
+    push          rbx
+%endif
+    movifnidn      t0, r0mp
+    mov           eax, 0x80000000
+    cpuid
+    cmp           eax, 0x80000004
+    jb .no_brand ; processor brand string not supported
+    mov           eax, 0x80000002
+    cpuid
+    mov     [t0+4* 0], eax
+    mov     [t0+4* 1], ebx
+    mov     [t0+4* 2], ecx
+    mov     [t0+4* 3], edx
+    mov           eax, 0x80000003
+    cpuid
+    mov     [t0+4* 4], eax
+    mov     [t0+4* 5], ebx
+    mov     [t0+4* 6], ecx
+    mov     [t0+4* 7], edx
+    mov           eax, 0x80000004
+    cpuid
+    mov     [t0+4* 8], eax
+    mov     [t0+4* 9], ebx
+    mov     [t0+4*10], ecx
+    mov     [t0+4*11], edx
+    xor           eax, eax
+    cpuid
+    jmp .check_xcr1
+.no_brand: ; use manufacturer id as a fallback
+    xor           eax, eax
+    mov      [t0+4*3], eax
+    cpuid
+    mov      [t0+4*0], ebx
+    mov      [t0+4*1], edx
+    mov      [t0+4*2], ecx
+.check_xcr1:
+    test          eax, eax
+    jz .end2 ; cpuid leaf 1 not supported
+    mov           t0d, eax ; max leaf
+    mov           eax, 1
+    cpuid
+    and           ecx, 0x18000000
+    cmp           ecx, 0x18000000
+    jne .end2 ; osxsave/avx not supported
+    cmp           t0d, 13 ; cpuid leaf 13 not supported
+    jb .end2
+    mov           t0d, eax ; cpuid signature
+    mov           eax, 13
+    mov           ecx, 1
+    cpuid
+    test           al, 0x04
+    jz .end ; xcr1 not supported
+    mov           ecx, 1
+    xgetbv
+    test           al, 0x04
+    jnz .end ; always-dirty ymm state
+%if ARCH_X86_64 == 0 && PIC
+    LEA           eax, check_vzeroupper
+    mov         [eax], ecx
+%else
+    mov [check_vzeroupper], ecx
+%endif
+.end:
+    mov           eax, t0d
+.end2:
+%if ARCH_X86_64
+    pop           rbx
+%endif
+    RET
+
+%if ARCH_X86_64
+%if WIN64
+    %define stack_param rsp+32 ; shadow space
+    %define num_fn_args rsp+stack_offset+17*8
+    %assign num_reg_args 4
+    %assign free_regs 7
+    %assign clobber_mask_stack_bit 16
+    DECLARE_REG_TMP 4
+%else
+    %define stack_param rsp
+    %define num_fn_args rsp+stack_offset+11*8
+    %assign num_reg_args 6
+    %assign free_regs 9
+    %assign clobber_mask_stack_bit 64
+    DECLARE_REG_TMP 7
+%endif
+
+%macro CLOBBER_UPPER 2 ; reg, mask_bit
+    mov          r13d, %1d
+    or            r13, r8
+    test          r9b, %2
+    cmovnz         %1, r13
+%endmacro
+
+cglobal checked_call, 2, 15, 16, max_args*8+64+8
+    mov          r10d, [num_fn_args]
+    mov            r8, 0xdeadbeef00000000
+    mov           r9d, [num_fn_args+r10*8+8] ; clobber_mask
+    mov            t0, [num_fn_args+r10*8]   ; func
+
+    ; Clobber the upper halves of 32-bit parameters
+    CLOBBER_UPPER  r0, 1
+    CLOBBER_UPPER  r1, 2
+    CLOBBER_UPPER  r2, 4
+    CLOBBER_UPPER  r3, 8
+%if UNIX64
+    CLOBBER_UPPER  r4, 16
+    CLOBBER_UPPER  r5, 32
+%else ; WIN64
+%assign i 6
+%rep 16-6
+    mova       m %+ i, [x %+ i]
+    %assign i i+1
+%endrep
+%endif
+
+    xor          r11d, r11d
+    sub          r10d, num_reg_args
+    cmovs        r10d, r11d ; num stack args
+
+    ; write stack canaries to the area above parameters passed on the stack
+    mov           r12, [rsp+stack_offset] ; return address
+    not           r12
+%assign i 0
+%rep 8 ; 64 bytes
+    mov [stack_param+(r10+i)*8], r12
+    %assign i i+1
+%endrep
+
+    test         r10d, r10d
+    jz .stack_setup_done ; no stack parameters
+.copy_stack_parameter:
+    mov           r12, [stack_param+stack_offset+8+r11*8]
+    CLOBBER_UPPER r12, clobber_mask_stack_bit
+    shr           r9d, 1
+    mov [stack_param+r11*8], r12
+    inc          r11d
+    cmp          r11d, r10d
+    jl .copy_stack_parameter
+.stack_setup_done:
+
+%assign i 14
+%rep 15-free_regs
+    mov        r %+ i, [n %+ i]
+    %assign i i-1
+%endrep
+    call           t0
+
+    ; check for stack corruption
+    mov           r0d, [num_fn_args]
+    xor           r3d, r3d
+    sub           r0d, num_reg_args
+    cmovs         r0d, r3d ; num stack args
+
+    mov            r3, [rsp+stack_offset]
+    mov            r4, [stack_param+r0*8]
+    not            r3
+    xor            r4, r3
+%assign i 1
+%rep 6
+    mov            r5, [stack_param+(r0+i)*8]
+    xor            r5, r3
+    or             r4, r5
+    %assign i i+1
+%endrep
+    xor            r3, [stack_param+(r0+7)*8]
+    or             r4, r3
+    jz .stack_ok
+    ; Save the return value located in rdx:rax first to prevent clobbering.
+    mov           r10, rax
+    mov           r11, rdx
+    lea            r0, [errmsg_stack]
+    jmp .fail
+.stack_ok:
+
+    ; check for failure to preserve registers
+%assign i 14
+%rep 15-free_regs
+    cmp        r %+ i, [n %+ i]
+    setne         r4b
+    lea           r3d, [r4+r3*2]
+    %assign i i-1
+%endrep
+%if WIN64
+    lea            r0, [rsp+32] ; account for shadow space
+    mov            r5, r0
+    test          r3d, r3d
+    jz .gpr_ok
+%else
+    test          r3d, r3d
+    jz .gpr_xmm_ok
+    mov            r0, rsp
+%endif
+%assign i free_regs
+%rep 15-free_regs
+%if i < 10
+    mov    dword [r0], " r0" + (i << 16)
+    lea            r4, [r0+3]
+%else
+    mov    dword [r0], " r10" + ((i - 10) << 24)
+    lea            r4, [r0+4]
+%endif
+    test          r3b, 1 << (i - free_regs)
+    cmovnz         r0, r4
+    %assign i i+1
+%endrep
+%if WIN64 ; xmm registers
+.gpr_ok:
+%assign i 6
+%rep 16-6
+    pxor       m %+ i, [x %+ i]
+    %assign i i+1
+%endrep
+    packsswb       m6, m7
+    packsswb       m8, m9
+    packsswb      m10, m11
+    packsswb      m12, m13
+    packsswb      m14, m15
+    packsswb       m6, m6
+    packsswb       m8, m10
+    packsswb      m12, m14
+    packsswb       m6, m6
+    packsswb       m8, m12
+    packsswb       m6, m8
+    pxor           m7, m7
+    pcmpeqb        m6, m7
+    pmovmskb      r3d, m6
+    cmp           r3d, 0xffff
+    je .xmm_ok
+    mov           r7d, " xmm"
+%assign i 6
+%rep 16-6
+    mov        [r0+0], r7d
+%if i < 10
+    mov   byte [r0+4], "0" + i
+    lea            r4, [r0+5]
+%else
+    mov   word [r0+4], "10" + ((i - 10) << 8)
+    lea            r4, [r0+6]
+%endif
+    test          r3d, 1 << i
+    cmovz          r0, r4
+    %assign i i+1
+%endrep
+.xmm_ok:
+    cmp            r0, r5
+    je .gpr_xmm_ok
+    mov     byte [r0], 0
+    mov           r11, rdx
+    mov            r1, r5
+%else
+    mov     byte [r0], 0
+    mov           r11, rdx
+    mov            r1, rsp
+%endif
+    mov           r10, rax
+    lea            r0, [errmsg_register]
+    jmp .fail
+.gpr_xmm_ok:
+    ; Check for dirty YMM state, i.e. missing vzeroupper
+    mov           ecx, [check_vzeroupper]
+    test          ecx, ecx
+    jz .ok ; not supported, skip
+    mov           r10, rax
+    mov           r11, rdx
+    xgetbv
+    test           al, 0x04
+    jz .restore_retval ; clean ymm state
+    lea            r0, [errmsg_vzeroupper]
+    vzeroupper
+.fail:
+    ; Call fail_func() with a descriptive message to mark it as a failure.
+    xor           eax, eax
+    call fail_func
+.restore_retval:
+    mov           rax, r10
+    mov           rdx, r11
+.ok:
+    RET
+
+; trigger a warmup of vector units
+%macro WARMUP 0
+cglobal warmup, 0, 0
+    xorps          m0, m0
+    mulps          m0, m0
+    RET
+%endmacro
+
+INIT_YMM avx2
+WARMUP
+INIT_ZMM avx512
+WARMUP
+
+%else
+
+; just random numbers to reduce the chance of incidental match
+%assign n3 0x6549315c
+%assign n4 0xe02f3e23
+%assign n5 0xb78d0d1d
+%assign n6 0x33627ba7
+
+;-----------------------------------------------------------------------------
+; void checkasm_checked_call(void *func, ...)
+;-----------------------------------------------------------------------------
+cglobal checked_call, 1, 7
+    mov            r3, [esp+stack_offset]      ; return address
+    mov            r1, [esp+stack_offset+17*4] ; num_stack_params
+    mov            r2, 27
+    not            r3
+    sub            r2, r1
+.push_canary:
+    push           r3
+    dec            r2
+    jg .push_canary
+.push_parameter:
+    push dword [esp+32*4]
+    dec            r1
+    jg .push_parameter
+    mov            r3, n3
+    mov            r4, n4
+    mov            r5, n5
+    mov            r6, n6
+    call           r0
+
+    ; check for failure to preserve registers
+    cmp            r3, n3
+    setne         r3h
+    cmp            r4, n4
+    setne         r3b
+    shl           r3d, 16
+    cmp            r5, n5
+    setne         r3h
+    cmp            r6, n6
+    setne         r3b
+    test           r3, r3
+    jz .gpr_ok
+    lea            r1, [esp+16]
+    mov       [esp+4], r1
+%assign i 3
+%rep 4
+    mov    dword [r1], " r0" + (i << 16)
+    lea            r4, [r1+3]
+    test           r3, 1 << ((6 - i) * 8)
+    cmovnz         r1, r4
+    %assign i i+1
+%endrep
+    mov     byte [r1], 0
+    mov            r5, eax
+    mov            r6, edx
+    LEA            r1, errmsg_register
+    jmp .fail
+.gpr_ok:
+    ; check for stack corruption
+    mov            r3, [esp+48*4] ; num_stack_params
+    mov            r6, [esp+31*4] ; return address
+    mov            r4, [esp+r3*4]
+    sub            r3, 26
+    not            r6
+    xor            r4, r6
+.check_canary:
+    mov            r5, [esp+(r3+27)*4]
+    xor            r5, r6
+    or             r4, r5
+    inc            r3
+    jl .check_canary
+    mov            r5, eax
+    mov            r6, edx
+    test           r4, r4
+    jz .stack_ok
+    LEA            r1, errmsg_stack
+    jmp .fail
+.stack_ok:
+    ; check for dirty YMM state, i.e. missing vzeroupper
+    LEA           ecx, check_vzeroupper
+    mov           ecx, [ecx]
+    test          ecx, ecx
+    jz .ok ; not supported, skip
+    xgetbv
+    test           al, 0x04
+    jz .ok ; clean ymm state
+    LEA            r1, errmsg_vzeroupper
+    vzeroupper
+.fail:
+    mov         [esp], r1
+    call fail_func
+.ok:
+    add           esp, 27*4
+    mov           eax, r5
+    mov           edx, r6
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/media/libdav1d/src/tests/dav1d_argon.bash b/media/libdav1d/src/tests/dav1d_argon.bash
new file mode 100755
index 0000000000..fd5bade361
--- /dev/null
+++ b/media/libdav1d/src/tests/dav1d_argon.bash
@@ -0,0 +1,196 @@
+#!/usr/bin/env bash
+
+DAV1D="tools/dav1d"
+ARGON_DIR='.'
+FILMGRAIN=1
+CPUMASK=-1
+THREADS=1
+JOBS=0
+WRAP=""
+FAIL_FAST=0
+
+
+usage() {
+    NAME=$(basename "$0")
+    {
+        printf "Usage:   %s [-d dav1d] [-a argondir] [-g \$filmgrain] [-c \$cpumask] [-t threads] [-j jobs] [DIRECTORY]...\n" "$NAME"
+        printf "Example: %s -d /path/to/dav1d -a /path/to/argon/ -g 0 -c avx2 profile0_core\n" "$NAME"
+        printf "Used to verify that dav1d can decode the Argon AV1 test vectors correctly.\n\n"
+        printf " DIRECTORY one or more dirs in the argon folder to check against\n"
+        printf "             (default: everything except large scale tiles and stress files)\n"
+        printf " -f        fail fast\n"
+        printf " -d dav1d  path to dav1d executable (default: tools/dav1d)\n"
+        printf " -a dir    path to argon dir (default: 'tests/argon' if found; '.' otherwise)\n"
+        printf " -g \$num   enable filmgrain (default: 1)\n"
+        printf " -c \$mask  use restricted cpumask (default: -1)\n"
+        printf " -t \$num   number of threads per dav1d (default: 1)\n"
+        printf " -j \$num   number of parallel dav1d processes (default: 0)\n"
+        printf " -w tool   execute dav1d with a wrapper tool\n\n"
+    } >&2
+    exit 1
+}
+
+error() {
+    printf "\033[1;91m%s\033[0m\n" "$*" >&2
+    exit 1
+}
+
+fail() {
+    printf "\033[1K\rMismatch in %s\n" "$1"
+    [[ $FAIL_FAST = 1 ]] && exit 1
+    (( failed++ ))
+}
+
+check_pids() {
+    new_pids=()
+    done_pids=()
+    for p in "${pids[@]}"; do
+        if kill -0 "$p" 2>/dev/null; then
+            new_pids+=("$p")
+        else
+            done_pids+=("$p")
+        fi
+    done
+    pids=("${new_pids[@]}")
+}
+
+wait_pids() {
+    pid_list=("$@")
+    for p in "${pid_list[@]}"; do
+        if ! wait "$p"; then
+            local file_varname="file$p"
+            fail "${!file_varname}"
+        fi
+    done
+}
+
+block_pids() {
+    while [ ${#pids[@]} -ge "$JOBS" ]; do
+        check_pids
+        if [ ${#done_pids} -eq 0 ]; then
+            sleep 0.2
+        else
+            wait_pids "${done_pids[@]}"
+        fi
+    done
+}
+
+wait_all_pids() {
+    wait_pids "${pids[@]}"
+}
+
+# find tests/argon
+tests_dir=$(dirname "$(readlink -f "$0")")
+if [ -d "$tests_dir/argon" ]; then
+    ARGON_DIR="$tests_dir/argon"
+fi
+
+while getopts ":d:a:g:c:t:j:w:f" opt; do
+    case "$opt" in
+        f)
+            FAIL_FAST=1
+            ;;
+        d)
+            DAV1D="$OPTARG"
+            ;;
+        a)
+            ARGON_DIR="$OPTARG"
+            ;;
+        g)
+            FILMGRAIN="$OPTARG"
+            ;;
+        c)
+            CPUMASK="$OPTARG"
+            ;;
+        t)
+            THREADS="$OPTARG"
+            ;;
+        j)
+            JOBS="$OPTARG"
+            ;;
+        w)
+            WRAP="$OPTARG"
+            ;;
+        \?)
+            printf "Error! Invalid option: -%s\n" "$OPTARG" >&2
+            usage
+            ;;
+        *)
+            usage
+            ;;
+    esac
+done
+shift $((OPTIND-1))
+
+if [ "$JOBS" -eq 0 ]; then
+    if [ "$THREADS" -gt 0 ]; then
+        JOBS="$((($( (nproc || sysctl -n hw.logicalcpu || getconf _NPROCESSORS_ONLN || echo 1) 2>/dev/null)+THREADS-1)/THREADS))"
+    else
+        JOBS=1
+    fi
+fi
+
+if [ "$#" -eq 0 ]; then
+    # Everything except large scale tiles and stress files.
+    dirs=("$ARGON_DIR/profile0_core"       "$ARGON_DIR/profile0_core_special"
+          "$ARGON_DIR/profile0_not_annexb" "$ARGON_DIR/profile0_not_annexb_special"
+          "$ARGON_DIR/profile1_core"       "$ARGON_DIR/profile1_core_special"
+          "$ARGON_DIR/profile1_not_annexb" "$ARGON_DIR/profile1_not_annexb_special"
+          "$ARGON_DIR/profile2_core"       "$ARGON_DIR/profile2_core_special"
+          "$ARGON_DIR/profile2_not_annexb" "$ARGON_DIR/profile2_not_annexb_special"
+          "$ARGON_DIR/profile_switching")
+else
+    mapfile -t dirs < <(printf "${ARGON_DIR}/%s\n" "$@" | sort -u)
+fi
+
+ver_info="dav1d $("$DAV1D" --filmgrain "$FILMGRAIN" --cpumask "$CPUMASK" --threads "$THREADS" -v 2>&1) filmgrain=$FILMGRAIN cpumask=$CPUMASK" || error "Error! Can't run $DAV1D"
+files=()
+
+for d in "${dirs[@]}"; do
+    if [ -d "$d/streams" ]; then
+        files+=("${d/%\//}"/streams/*.obu)
+    fi
+done
+
+num_files="${#files[@]}"
+if [ "$num_files" -eq 0 ]; then
+    error "Error! No files found at ${dirs[*]}"
+fi
+
+failed=0
+pids=()
+for i in "${!files[@]}"; do
+    f="${files[i]}"
+    if [ "$FILMGRAIN" -eq 0 ]; then
+        md5=${f/\/streams\//\/md5_no_film_grain\/}
+    else
+        md5=${f/\/streams\//\/md5_ref\/}
+    fi
+    md5=$(<"${md5/%obu/md5}") || error "Error! Can't read md5 ${md5} for file ${f}"
+    md5=${md5/ */}
+
+    printf '\033[1K\r[%3d%% %*d/%d] Verifying %s' "$(((i+1)*100/num_files))" "${#num_files}" "$((i+1))" "$num_files" "${f#"$ARGON_DIR"/}"
+    cmd=($WRAP "$DAV1D" -i "$f" --filmgrain "$FILMGRAIN" --verify "$md5" --cpumask "$CPUMASK" --threads "$THREADS" -q)
+    if [ "$JOBS" -gt 1 ]; then
+        "${cmd[@]}" 2>/dev/null &
+        p=$!
+        pids+=("$p")
+        declare "file$p=${f#"$ARGON_DIR"/}"
+        block_pids
+    else
+        if ! "${cmd[@]}" 2>/dev/null; then
+            fail "${f#"$ARGON_DIR"/}"
+        fi
+    fi
+done
+
+wait_all_pids
+
+if [ "$failed" -ne 0 ]; then
+    printf "\033[1K\r%d/%d files \033[1;91mfailed\033[0m to verify" "$failed" "$num_files"
+else
+    printf "\033[1K\r%d files \033[1;92msuccessfully\033[0m verified" "$num_files"
+fi
+printf " in %dm%ds (%s)\n" "$((SECONDS/60))" "$((SECONDS%60))" "$ver_info"
+
+exit $failed
diff --git a/media/libdav1d/src/tests/header_test.c b/media/libdav1d/src/tests/header_test.c
new file mode 100644
index 0000000000..2cd9eca7f9
--- /dev/null
+++ b/media/libdav1d/src/tests/header_test.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include DAV1D_TEST_HEADER
+
+int main(void)
+{
+    return 0;
+}
diff --git a/media/libdav1d/src/tests/libfuzzer/alloc_fail.c b/media/libdav1d/src/tests/libfuzzer/alloc_fail.c
new file mode 100644
index 0000000000..ddd1dd71ab
--- /dev/null
+++ b/media/libdav1d/src/tests/libfuzzer/alloc_fail.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "alloc_fail.h"
+
+static int fail_probability;
+
+void dav1d_setup_alloc_fail(unsigned seed, unsigned probability) {
+    srand(seed);
+
+    while (probability >= RAND_MAX)
+        probability >>= 1;
+
+    fail_probability = probability;
+}
+
+void * __wrap_malloc(size_t);
+
+void * __wrap_malloc(size_t sz) {
+    if (rand() < fail_probability)
+        return NULL;
+    return malloc(sz);
+}
+
+#if defined(HAVE_POSIX_MEMALIGN)
+int __wrap_posix_memalign(void **memptr, size_t alignment, size_t size);
+
+int __wrap_posix_memalign(void **memptr, size_t alignment, size_t size) {
+    if (rand() < fail_probability)
+        return ENOMEM;
+    return posix_memalign(memptr, alignment, size);
+}
+#else
+#error "HAVE_POSIX_MEMALIGN required"
+#endif
+
+int __wrap_pthread_create(pthread_t *, const pthread_attr_t *,
+                          void *(*) (void *), void *);
+
+int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+                          void *(*start_routine) (void *), void *arg)
+{
+    if (rand() < (fail_probability + RAND_MAX/16))
+        return EAGAIN;
+
+    return pthread_create(thread, attr, start_routine, arg);
+}
+
+int __wrap_pthread_mutex_init(pthread_mutex_t *,
+                              const pthread_mutexattr_t *);
+
+int __wrap_pthread_mutex_init(pthread_mutex_t *restrict mutex,
+                              const pthread_mutexattr_t *restrict attr)
+{
+    if (rand() < (fail_probability + RAND_MAX/8))
+        return ENOMEM;
+
+    return pthread_mutex_init(mutex, attr);
+}
+
+int __wrap_pthread_cond_init(pthread_cond_t *,
+                             const pthread_condattr_t *);
+
+int __wrap_pthread_cond_init(pthread_cond_t *restrict cond,
+                             const pthread_condattr_t *restrict attr)
+{
+    if (rand() < (fail_probability + RAND_MAX/16))
+        return ENOMEM;
+
+    return pthread_cond_init(cond, attr);
+}
diff --git a/media/libdav1d/src/tests/libfuzzer/alloc_fail.h b/media/libdav1d/src/tests/libfuzzer/alloc_fail.h
new file mode 100644
index 0000000000..5ace870beb
--- /dev/null
+++ b/media/libdav1d/src/tests/libfuzzer/alloc_fail.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_TESTS_LIBFUZZER_ALLOC_FAIL_H
+#define DAV1D_TESTS_LIBFUZZER_ALLOC_FAIL_H
+
+#include 
+
+DAV1D_API void dav1d_setup_alloc_fail(unsigned seed, unsigned probability);
+
+#endif /* DAV1D_TESTS_LIBFUZZER_ALLOC_FAIL_H */
diff --git a/media/libdav1d/src/tests/libfuzzer/dav1d_fuzzer.c b/media/libdav1d/src/tests/libfuzzer/dav1d_fuzzer.c
new file mode 100644
index 0000000000..502ee22b06
--- /dev/null
+++ b/media/libdav1d/src/tests/libfuzzer/dav1d_fuzzer.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include "src/cpu.h"
+#include "dav1d_fuzzer.h"
+
+#ifdef DAV1D_ALLOC_FAIL
+
+#include "alloc_fail.h"
+
+static unsigned djb_xor(const uint8_t * c, size_t len) {
+    unsigned hash = 5381;
+    for(size_t i = 0; i < len; i++)
+        hash = hash * 33 ^ c[i];
+    return hash;
+}
+#endif
+
+static unsigned r32le(const uint8_t *const p) {
+    return ((uint32_t)p[3] << 24U) | (p[2] << 16U) | (p[1] << 8U) | p[0];
+}
+
+#define DAV1D_FUZZ_MAX_SIZE 4096 * 4096
+
+// search for "--cpumask xxx" in argv and remove both parameters
+int LLVMFuzzerInitialize(int *argc, char ***argv) {
+    int i = 1;
+    for (; i < *argc; i++) {
+        if (!strcmp((*argv)[i], "--cpumask")) {
+            const char * cpumask = (*argv)[i+1];
+            if (cpumask) {
+                char *end;
+                unsigned res;
+                if (!strncmp(cpumask, "0x", 2)) {
+                    cpumask += 2;
+                    res = (unsigned) strtoul(cpumask, &end, 16);
+                } else {
+                    res = (unsigned) strtoul(cpumask, &end, 0);
+                }
+                if (end != cpumask && !end[0]) {
+                    dav1d_set_cpu_flags_mask(res);
+                }
+            }
+            break;
+        }
+    }
+
+    for (; i < *argc - 2; i++) {
+        (*argv)[i] = (*argv)[i + 2];
+    }
+
+    *argc = i;
+
+    return 0;
+}
+
+
+// expects ivf input
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+    Dav1dSettings settings = { 0 };
+    Dav1dContext * ctx = NULL;
+    Dav1dPicture pic;
+    const uint8_t *ptr = data;
+    int have_seq_hdr = 0;
+    int err;
+
+    dav1d_version();
+
+    if (size < 32) goto end;
+#ifdef DAV1D_ALLOC_FAIL
+    unsigned h = djb_xor(ptr, 32);
+    unsigned seed = h;
+    unsigned probability = h > (RAND_MAX >> 5) ? RAND_MAX >> 5 : h;
+    int max_frame_delay = (h & 0xf) + 1;
+    int n_threads = ((h >> 4) & 0x7) + 1;
+    if (max_frame_delay > 5) max_frame_delay = 1;
+    if (n_threads > 3) n_threads = 1;
+#endif
+    ptr += 32; // skip ivf header
+
+    dav1d_default_settings(&settings);
+
+#ifdef DAV1D_MT_FUZZING
+    settings.max_frame_delay = settings.n_threads = 4;
+#elif defined(DAV1D_ALLOC_FAIL)
+    settings.max_frame_delay = max_frame_delay;
+    settings.n_threads = n_threads;
+    dav1d_setup_alloc_fail(seed, probability);
+#else
+    settings.max_frame_delay = settings.n_threads = 1;
+#endif
+#if defined(DAV1D_FUZZ_MAX_SIZE)
+    settings.frame_size_limit = DAV1D_FUZZ_MAX_SIZE;
+#endif
+
+    err = dav1d_open(&ctx, &settings);
+    if (err < 0) goto end;
+
+    while (ptr <= data + size - 12) {
+        Dav1dData buf;
+        uint8_t *p;
+
+        size_t frame_size = r32le(ptr);
+        ptr += 12;
+
+        if (frame_size > size || ptr > data + size - frame_size)
+            break;
+
+        if (!frame_size) continue;
+
+        if (!have_seq_hdr) {
+            Dav1dSequenceHeader seq;
+            int err = dav1d_parse_sequence_header(&seq, ptr, frame_size);
+            // skip frames until we see a sequence header
+            if  (err != 0) {
+                ptr += frame_size;
+                continue;
+            }
+            have_seq_hdr = 1;
+        }
+
+        // copy frame data to a new buffer to catch reads past the end of input
+        p = dav1d_data_create(&buf, frame_size);
+        if (!p) goto cleanup;
+        memcpy(p, ptr, frame_size);
+        ptr += frame_size;
+
+        do {
+            if ((err = dav1d_send_data(ctx, &buf)) < 0) {
+                if (err != DAV1D_ERR(EAGAIN))
+                    break;
+            }
+            memset(&pic, 0, sizeof(pic));
+            err = dav1d_get_picture(ctx, &pic);
+            if (err == 0) {
+                dav1d_picture_unref(&pic);
+            } else if (err != DAV1D_ERR(EAGAIN)) {
+                break;
+            }
+        } while (buf.sz > 0);
+
+        if (buf.sz > 0)
+            dav1d_data_unref(&buf);
+    }
+
+    memset(&pic, 0, sizeof(pic));
+    if ((err = dav1d_get_picture(ctx, &pic)) == 0) {
+        /* Test calling dav1d_picture_unref() after dav1d_close() */
+        do {
+            Dav1dPicture pic2 = { 0 };
+            if ((err = dav1d_get_picture(ctx, &pic2)) == 0)
+                dav1d_picture_unref(&pic2);
+        } while (err != DAV1D_ERR(EAGAIN));
+
+        dav1d_close(&ctx);
+        dav1d_picture_unref(&pic);
+        return 0;
+    }
+
+cleanup:
+    dav1d_close(&ctx);
+end:
+    return 0;
+}
diff --git a/media/libdav1d/src/tests/libfuzzer/dav1d_fuzzer.h b/media/libdav1d/src/tests/libfuzzer/dav1d_fuzzer.h
new file mode 100644
index 0000000000..0cbbad46b0
--- /dev/null
+++ b/media/libdav1d/src/tests/libfuzzer/dav1d_fuzzer.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_TESTS_LIBFUZZER_DAV1D_FUZZER_H
+#define DAV1D_TESTS_LIBFUZZER_DAV1D_FUZZER_H
+
+#include 
+#include 
+
+int LLVMFuzzerInitialize(int *argc, char ***argv);
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+#endif /* DAV1D_TESTS_LIBFUZZER_DAV1D_FUZZER_H */
diff --git a/media/libdav1d/src/tests/libfuzzer/main.c b/media/libdav1d/src/tests/libfuzzer/main.c
new file mode 100644
index 0000000000..8647738666
--- /dev/null
+++ b/media/libdav1d/src/tests/libfuzzer/main.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Janne Grunau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "dav1d_fuzzer.h"
+
+// expects ivf input
+
+int main(int argc, char *argv[]) {
+    int ret = -1;
+    FILE *f = NULL;
+    int64_t fsize;
+    const char *filename = NULL;
+    uint8_t *data = NULL;
+    size_t size = 0;
+
+    if (LLVMFuzzerInitialize(&argc, &argv)) {
+        return 1;
+    }
+
+    if (argc != 2) {
+        fprintf(stdout, "Usage:\n%s fuzzing_testcase.ivf\n", argv[0]);
+        return -1;
+    }
+    filename = argv[1];
+
+    if (!(f = fopen(filename, "rb"))) {
+        fprintf(stderr, "failed to open %s: %s\n", filename, strerror(errno));
+        goto error;
+    }
+
+    if (fseeko(f, 0, SEEK_END) == -1) {
+        fprintf(stderr, "fseek(%s, 0, SEEK_END) failed: %s\n", filename,
+                strerror(errno));
+        goto error;
+    }
+    if ((fsize = ftello(f)) == -1) {
+        fprintf(stderr, "ftell(%s) failed: %s\n", filename, strerror(errno));
+        goto error;
+    }
+    rewind(f);
+
+    if (fsize < 0 || fsize > INT_MAX) {
+        fprintf(stderr, "%s is too large: %"PRId64"\n", filename, fsize);
+        goto error;
+    }
+    size = (size_t)fsize;
+
+    if (!(data = malloc(size))) {
+        fprintf(stderr, "failed to allocate: %zu bytes\n", size);
+        goto error;
+    }
+
+    if (fread(data, size, 1, f) == size) {
+        fprintf(stderr, "failed to read %zu bytes from %s: %s\n", size,
+                filename, strerror(errno));
+        goto error;
+    }
+
+    ret = LLVMFuzzerTestOneInput(data, size);
+
+error:
+    free(data);
+    if (f) fclose(f);
+    return ret;
+}
diff --git a/media/libdav1d/src/tests/libfuzzer/meson.build b/media/libdav1d/src/tests/libfuzzer/meson.build
new file mode 100644
index 0000000000..45d28562c1
--- /dev/null
+++ b/media/libdav1d/src/tests/libfuzzer/meson.build
@@ -0,0 +1,101 @@
+# Copyright © 2020, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Build definition for the dav1d fuzzing binaries
+#
+
+if fuzzing_engine == 'none' and not have_fseeko
+    subdir_done()
+endif
+
+dav1d_fuzzer_sources =  files('dav1d_fuzzer.c')
+fuzzer_ldflags = []
+fuzzer_link_lang = {}
+
+if get_option('fuzzer_ldflags') != ''
+    fuzzer_ldflags += [get_option('fuzzer_ldflags')]
+endif
+
+if fuzzing_engine == 'none'
+    dav1d_fuzzer_sources += files('main.c')
+elif fuzzing_engine == 'libfuzzer'
+    fuzzer_ldflags += ['-fsanitize=fuzzer']
+elif fuzzing_engine == 'oss-fuzz'
+    # libFuzzingEngine needs c++
+    add_languages('cpp')
+    fuzzer_link_lang = {'link_language': 'cpp'}
+endif
+
+dav1d_fuzzer = executable('dav1d_fuzzer',
+    dav1d_fuzzer_sources,
+    include_directories: dav1d_inc_dirs,
+    link_args: fuzzer_ldflags,
+    link_with : libdav1d,
+    build_by_default: true,
+    dependencies : [thread_dependency],
+    kwargs: fuzzer_link_lang
+    )
+
+dav1d_fuzzer_mt = executable('dav1d_fuzzer_mt',
+    dav1d_fuzzer_sources,
+    include_directories: dav1d_inc_dirs,
+    c_args: ['-DDAV1D_MT_FUZZING'],
+    link_args: fuzzer_ldflags,
+    link_with : libdav1d,
+    build_by_default: true,
+    dependencies : [thread_dependency],
+    kwargs: fuzzer_link_lang
+    )
+
+objcopy = find_program('objcopy',
+                       required: false)
+if (objcopy.found() and
+    not get_option('b_lto') and
+    get_option('default_library') == 'static' and
+    cc.has_function('posix_memalign', prefix : '#include ', args : test_args))
+
+    libdav1d_af = custom_target('libdav1d_af',
+                                input: libdav1d,
+                                output: 'libdav1d_af.a',
+                                depends: libdav1d,
+                                command: [objcopy,
+                                          '--redefine-sym', 'malloc=__wrap_malloc',
+                                          '--redefine-sym', 'posix_memalign=__wrap_posix_memalign',
+                                          '--redefine-sym', 'pthread_create=__wrap_pthread_create',
+                                          '--redefine-sym', 'pthread_cond_init=__wrap_pthread_cond_init',
+                                          '--redefine-sym', 'pthread_mutex_init=__wrap_pthread_mutex_init',
+                                          '@INPUT@', '@OUTPUT@'])
+
+    dav1d_fuzzer_mem = executable('dav1d_fuzzer_mem',
+        dav1d_fuzzer_sources + ['alloc_fail.c'],
+        include_directories: dav1d_inc_dirs,
+        c_args: ['-DDAV1D_ALLOC_FAIL'],
+        link_args: fuzzer_ldflags + [join_paths(libdav1d_af.full_path())],
+        link_depends: libdav1d_af,
+        build_by_default: false,
+        dependencies : [thread_dependency],
+        kwargs: fuzzer_link_lang
+        )
+endif
diff --git a/media/libdav1d/src/tests/meson.build b/media/libdav1d/src/tests/meson.build
new file mode 100644
index 0000000000..934576c480
--- /dev/null
+++ b/media/libdav1d/src/tests/meson.build
@@ -0,0 +1,157 @@
+# Copyright © 2018, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Build definition for the dav1d tests
+#
+
+# Leave subdir if tests are disabled
+if not get_option('enable_tests')
+    subdir_done()
+endif
+
+if is_asm_enabled
+    checkasm_sources = files(
+        'checkasm/checkasm.c',
+        'checkasm/msac.c',
+        'checkasm/pal.c',
+        'checkasm/refmvs.c',
+    )
+
+    checkasm_tmpl_sources = files(
+        'checkasm/cdef.c',
+        'checkasm/filmgrain.c',
+        'checkasm/ipred.c',
+        'checkasm/itx.c',
+        'checkasm/loopfilter.c',
+        'checkasm/looprestoration.c',
+        'checkasm/mc.c',
+    )
+
+    checkasm_bitdepth_objs = []
+    foreach bitdepth : dav1d_bitdepths
+        checkasm_bitdepth_lib = static_library(
+            'checkasm_bitdepth_@0@'.format(bitdepth),
+            checkasm_tmpl_sources,
+            include_directories: dav1d_inc_dirs,
+            dependencies : [stdatomic_dependencies],
+            c_args: ['-DBITDEPTH=@0@'.format(bitdepth)],
+            install: false,
+            build_by_default: false,
+        )
+        checkasm_bitdepth_objs += checkasm_bitdepth_lib.extract_all_objects(recursive: true)
+    endforeach
+
+    checkasm_asm_objs = []
+    checkasm_asm_sources = []
+    if host_machine.cpu_family() == 'aarch64' or host_machine.cpu() == 'arm64'
+        checkasm_asm_sources += files('checkasm/arm/checkasm_64.S')
+    elif host_machine.cpu_family().startswith('arm')
+        checkasm_asm_sources += files('checkasm/arm/checkasm_32.S')
+    elif host_machine.cpu_family() == 'riscv64'
+        checkasm_asm_sources += files('checkasm/riscv/checkasm_64.S')
+    elif host_machine.cpu_family().startswith('x86')
+        checkasm_asm_objs += nasm_gen.process(files('checkasm/x86/checkasm.asm'))
+    elif host_machine.cpu_family().startswith('loongarch')
+        checkasm_asm_sources += files('checkasm/loongarch/checkasm.S')
+    endif
+
+    if use_gaspp
+        checkasm_asm_objs += gaspp_gen.process(checkasm_asm_sources)
+    else
+        checkasm_sources += checkasm_asm_sources
+    endif
+
+    checkasm = executable('checkasm',
+        checkasm_sources,
+        checkasm_asm_objs,
+
+        objects: [
+            checkasm_bitdepth_objs,
+            libdav1d.extract_all_objects(recursive: true),
+            ],
+
+        include_directories: dav1d_inc_dirs,
+        build_by_default: false,
+        dependencies : [
+            thread_dependency,
+            rt_dependency,
+            libdl_dependency,
+            libm_dependency,
+            ],
+        )
+
+    test('checkasm', checkasm, suite: 'checkasm', timeout: 180)
+    benchmark('checkasm', checkasm, suite: 'checkasm', timeout: 3600, args: '--bench')
+endif
+
+c99_extension_flag = cc.first_supported_argument(
+    '-Werror=c11-extensions',
+    '-Werror=c99-c11-compat',
+    '-Wc11-extensions',
+    '-Wc99-c11-compat',
+)
+
+# dav1d_api_headers
+foreach header : dav1d_api_headers
+    target = header + '_test'
+
+    header_test_exe = executable(target,
+        'header_test.c',
+        include_directories: dav1d_inc_dirs,
+        c_args: ['-DDAV1D_TEST_HEADER="@0@"'.format(header), c99_extension_flag],
+        build_by_default: true
+    )
+
+    test(target, header_test_exe, suite: 'headers')
+endforeach
+
+
+# fuzzing binaries
+subdir('libfuzzer')
+
+# seek stress test binary, depends on dav1d cli tool
+if (get_option('enable_tools') and get_option('enable_seek_stress'))
+    seek_stress_sources = files('seek_stress.c')
+    seek_stress = executable('seek_stress',
+        seek_stress_sources, rev_target,
+        objects: [
+            dav1d.extract_objects('dav1d_cli_parse.c'),
+            dav1d_input_objs.extract_objects('input/input.c', 'input/ivf.c'),
+        ],
+        include_directories: [dav1d_inc_dirs, include_directories('../tools')],
+        link_with: libdav1d,
+        dependencies: [
+            thread_dependency,
+            rt_dependency,
+            getopt_dependency,
+            libm_dependency,
+        ],
+    )
+endif
+
+# Include dav1d test data repository with additional tests
+if get_option('testdata_tests')
+    subdir('dav1d-test-data')
+endif
diff --git a/media/libdav1d/src/tests/seek_stress.c b/media/libdav1d/src/tests/seek_stress.c
new file mode 100644
index 0000000000..2a3d058559
--- /dev/null
+++ b/media/libdav1d/src/tests/seek_stress.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright © 2020, VideoLAN and dav1d authors
+ * Copyright © 2020, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "vcs_version.h"
+#include "cli_config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "dav1d/dav1d.h"
+#include "input/input.h"
+#include "input/demuxer.h"
+#include "dav1d_cli_parse.h"
+
+#define NUM_RAND_SEEK 3
+#define NUM_REL_SEEK  4
+#define NUM_END_SEEK  2
+
+const Demuxer annexb_demuxer = { .name = "" };
+const Demuxer section5_demuxer = { .name = "" };
+
+#ifdef _WIN32
+#include 
+static unsigned get_seed(void) {
+    return GetTickCount();
+}
+#else
+#ifdef __APPLE__
+#include 
+#else
+#include 
+#endif
+static unsigned get_seed(void) {
+#ifdef __APPLE__
+    return (unsigned) mach_absolute_time();
+#elif HAVE_CLOCK_GETTIME
+    struct timespec ts;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    return (unsigned) (1000000000ULL * ts.tv_sec + ts.tv_nsec);
+#endif
+}
+#endif
+
+static uint32_t xs_state[4];
+
+static void xor128_srand(unsigned seed) {
+    xs_state[0] = seed;
+    xs_state[1] = ( seed & 0xffff0000) | (~seed & 0x0000ffff);
+    xs_state[2] = (~seed & 0xffff0000) | ( seed & 0x0000ffff);
+    xs_state[3] = ~seed;
+}
+
+// xor128 from Marsaglia, George (July 2003). "Xorshift RNGs".
+//             Journal of Statistical Software. 8 (14).
+//             doi:10.18637/jss.v008.i14.
+static int xor128_rand(void) {
+    const uint32_t x = xs_state[0];
+    const uint32_t t = x ^ (x << 11);
+
+    xs_state[0] = xs_state[1];
+    xs_state[1] = xs_state[2];
+    xs_state[2] = xs_state[3];
+    uint32_t w = xs_state[3];
+
+    w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
+    xs_state[3] = w;
+
+    return w >> 1;
+}
+
+static inline int decode_frame(Dav1dPicture *const p,
+                               Dav1dContext *const c, Dav1dData *const data)
+{
+    int res;
+    memset(p, 0, sizeof(*p));
+    if ((res = dav1d_send_data(c, data)) < 0) {
+        if (res != DAV1D_ERR(EAGAIN)) {
+            fprintf(stderr, "Error decoding frame: %s\n",
+                    strerror(DAV1D_ERR(res)));
+            return res;
+        }
+    }
+    if ((res = dav1d_get_picture(c, p)) < 0) {
+        if (res != DAV1D_ERR(EAGAIN)) {
+            fprintf(stderr, "Error decoding frame: %s\n",
+                    strerror(DAV1D_ERR(res)));
+            return res;
+        }
+    } else dav1d_picture_unref(p);
+    return 0;
+}
+
+static int decode_rand(DemuxerContext *const in, Dav1dContext *const c,
+                       Dav1dData *const data, const double fps)
+{
+    int res = 0;
+    Dav1dPicture p;
+    const int num_frames = xor128_rand() % (int)(fps * 5);
+    for (int i = 0; i < num_frames; i++) {
+        if ((res = decode_frame(&p, c, data))) break;
+        if (input_read(in, data) || data->sz == 0) break;
+    }
+    return res;
+}
+
+static int decode_all(DemuxerContext *const in,
+                      Dav1dContext *const c, Dav1dData *const data)
+{
+    int res = 0;
+    Dav1dPicture p;
+    do { if ((res = decode_frame(&p, c, data))) break;
+    } while (!input_read(in, data) && data->sz > 0);
+    return res;
+}
+
+static int seek(DemuxerContext *const in, Dav1dContext *const c,
+                const uint64_t pts, Dav1dData *const data)
+{
+    int res;
+    if ((res = input_seek(in, pts))) return res;
+    Dav1dSequenceHeader seq;
+    do { if ((res = input_read(in, data))) break;
+    } while (dav1d_parse_sequence_header(&seq, data->data, data->sz));
+    dav1d_flush(c);
+    return res;
+}
+
+int main(const int argc, char *const *const argv) {
+    const char *version = dav1d_version();
+    if (strcmp(version, DAV1D_VERSION)) {
+        fprintf(stderr, "Version mismatch (library: %s, executable: %s)\n",
+                version, DAV1D_VERSION);
+        return EXIT_FAILURE;
+    }
+
+    CLISettings cli_settings;
+    Dav1dSettings lib_settings;
+    DemuxerContext *in;
+    Dav1dContext *c;
+    Dav1dData data;
+    unsigned total, i_fps[2], i_timebase[2];
+    double timebase, spf, fps;
+    uint64_t pts;
+
+    xor128_srand(get_seed());
+    parse(argc, argv, &cli_settings, &lib_settings);
+
+    if (input_open(&in, "ivf", cli_settings.inputfile,
+                   i_fps, &total, i_timebase) < 0 ||
+        !i_timebase[0] || !i_timebase[1] ||  !i_fps[0] || !i_fps[1])
+    {
+        return EXIT_SUCCESS;
+    }
+    if (dav1d_open(&c, &lib_settings))
+        return EXIT_FAILURE;
+
+    timebase = (double)i_timebase[1] / i_timebase[0];
+    spf = (double)i_fps[1] / i_fps[0];
+    fps = (double)i_fps[0] / i_fps[1];
+    if (fps < 1) goto end;
+
+#define FRAME_OFFSET_TO_PTS(foff) \
+    (uint64_t)llround(((foff) * spf) * 1000000000.0)
+#define TS_TO_PTS(ts) \
+    (uint64_t)llround(((ts) * timebase) * 1000000000.0)
+
+    // seek at random pts
+    for (int i = 0; i < NUM_RAND_SEEK; i++) {
+        pts = FRAME_OFFSET_TO_PTS(xor128_rand() % total);
+        if (seek(in, c, pts, &data)) continue;
+        if (decode_rand(in, c, &data, fps)) goto end;
+    }
+    pts = TS_TO_PTS(data.m.timestamp);
+
+    // seek left / right randomly with random intervals within 1s
+    for (int i = 0, tries = 0;
+         i - tries < NUM_REL_SEEK && tries < NUM_REL_SEEK / 2;
+         i++)
+    {
+        const int sign = xor128_rand() & 1 ? -1 : +1;
+        const float diff = (xor128_rand() % 100) / 100.f;
+        int64_t new_pts = pts + sign * FRAME_OFFSET_TO_PTS(diff * fps);
+        const int64_t new_ts = llround(new_pts / (timebase * 1000000000.0));
+        new_pts = TS_TO_PTS(new_ts);
+        if (new_pts < 0 || (uint64_t)new_pts >= FRAME_OFFSET_TO_PTS(total)) {
+            if (seek(in, c, FRAME_OFFSET_TO_PTS(total / 2), &data)) break;
+            pts = TS_TO_PTS(data.m.timestamp);
+            tries++;
+            continue;
+        }
+        if (seek(in, c, new_pts, &data))
+            if (seek(in, c, 0, &data)) goto end;
+        if (decode_rand(in, c, &data, fps)) goto end;
+        pts = TS_TO_PTS(data.m.timestamp);
+    }
+
+    unsigned shift = 0;
+    do {
+        shift += 5;
+        if (shift > total)
+            shift = total;
+    } while (seek(in, c, FRAME_OFFSET_TO_PTS(total - shift), &data));
+
+    // simulate seeking after the end of the file
+    for (int i = 0; i < NUM_END_SEEK; i++) {
+        if (seek(in, c, FRAME_OFFSET_TO_PTS(total - shift), &data)) goto end;
+        if (decode_all(in, c, &data)) goto end;
+        int num_flush = 1 + 64 + xor128_rand() % 64;
+        while (num_flush--) dav1d_flush(c);
+    }
+
+end:
+    input_close(in);
+    dav1d_close(&c);
+    return EXIT_SUCCESS;
+}
diff --git a/media/libdav1d/src/tools/compat/getopt.c b/media/libdav1d/src/tools/compat/getopt.c
new file mode 100644
index 0000000000..ab375bdb17
--- /dev/null
+++ b/media/libdav1d/src/tools/compat/getopt.c
@@ -0,0 +1,568 @@
+/*	$OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $	*/
+/*	$NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $	*/
+
+/*
+ * Copyright (c) 2002 Todd C. Miller 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#ifdef _WIN32
+#include 
+#else
+#include 
+#endif
+
+#define	REPLACE_GETOPT		/* use this getopt as the system getopt(3) */
+
+#ifdef REPLACE_GETOPT
+int	opterr = 1;		/* if error message should be printed */
+int	optind = 1;		/* index into parent argv vector */
+int	optopt = '?';		/* character checked for validity */
+#undef	optreset		/* see getopt.h */
+#define	optreset		__mingw_optreset
+int	optreset;		/* reset getopt */
+char    *optarg;		/* argument associated with option */
+#endif
+
+#define PRINT_ERROR	((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
+#define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
+
+/* return values */
+#define	BADCH		(int)'?'
+#define	BADARG		((*options == ':') ? (int)':' : (int)'?')
+#define	INORDER 	(int)1
+
+#ifdef __CYGWIN__
+static char EMSG[] = "";
+#else
+#define	EMSG		""
+#endif
+
+static int getopt_internal(int, char * const *, const char *,
+			   const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+			      const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1;   /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+#ifdef _WIN32
+#ifndef __CYGWIN__
+#define __progname __argv[0]
+#else
+extern char __declspec(dllimport) *__progname;
+#endif
+
+static void
+_vwarnx(const char *fmt,va_list ap)
+{
+  (void)fprintf(stderr,"%s: ",__progname);
+  if (fmt != NULL)
+    (void)vfprintf(stderr,fmt,ap);
+  (void)fprintf(stderr,"\n");
+}
+
+static void
+warnx(const char *fmt,...)
+{
+  va_list ap;
+  va_start(ap,fmt);
+  _vwarnx(fmt,ap);
+  va_end(ap);
+}
+#endif
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+	int c;
+
+	c = a % b;
+	while (c != 0) {
+		a = b;
+		b = c;
+		c = a % b;
+	}
+
+	return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+	char * const *nargv)
+{
+	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+	char *swap;
+
+	/*
+	 * compute lengths of blocks and number and size of cycles
+	 */
+	nnonopts = panonopt_end - panonopt_start;
+	nopts = opt_end - panonopt_end;
+	ncycle = gcd(nnonopts, nopts);
+	cyclelen = (opt_end - panonopt_start) / ncycle;
+
+	for (i = 0; i < ncycle; i++) {
+		cstart = panonopt_end+i;
+		pos = cstart;
+		for (j = 0; j < cyclelen; j++) {
+			if (pos >= panonopt_end)
+				pos -= nnonopts;
+			else
+				pos += nopts;
+			swap = nargv[pos];
+			/* LINTED const cast */
+			((char **) nargv)[pos] = nargv[cstart];
+			/* LINTED const cast */
+			((char **)nargv)[cstart] = swap;
+		}
+	}
+}
+
+/*
+ * parse_long_options --
+ *	Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+	const struct option *long_options, int *idx, int short_too)
+{
+	char *current_argv, *has_equal;
+	size_t current_argv_len;
+	int i, ambiguous, match;
+
+#define IDENTICAL_INTERPRETATION(_x, _y)                                \
+	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
+	 long_options[(_x)].flag == long_options[(_y)].flag &&          \
+	 long_options[(_x)].val == long_options[(_y)].val)
+
+	current_argv = place;
+	match = -1;
+	ambiguous = 0;
+
+	optind++;
+
+	if ((has_equal = strchr(current_argv, '=')) != NULL) {
+		/* argument found (--option=arg) */
+		current_argv_len = has_equal - current_argv;
+		has_equal++;
+	} else
+		current_argv_len = strlen(current_argv);
+
+	for (i = 0; long_options[i].name; i++) {
+		/* find matching long option */
+		if (strncmp(current_argv, long_options[i].name,
+		    current_argv_len))
+			continue;
+
+		if (strlen(long_options[i].name) == current_argv_len) {
+			/* exact match */
+			match = i;
+			ambiguous = 0;
+			break;
+		}
+		/*
+		 * If this is a known short option, don't allow
+		 * a partial match of a single character.
+		 */
+		if (short_too && current_argv_len == 1)
+			continue;
+
+		if (match == -1)	/* partial match */
+			match = i;
+		else if (!IDENTICAL_INTERPRETATION(i, match))
+			ambiguous = 1;
+	}
+	if (ambiguous) {
+		/* ambiguous abbreviation */
+		if (PRINT_ERROR)
+			warnx(ambig, (int)current_argv_len,
+			     current_argv);
+		optopt = 0;
+		return (BADCH);
+	}
+	if (match != -1) {		/* option found */
+		if (long_options[match].has_arg == no_argument
+		    && has_equal) {
+			if (PRINT_ERROR)
+				warnx(noarg, (int)current_argv_len,
+				     current_argv);
+			/*
+			 * XXX: GNU sets optopt to val regardless of flag
+			 */
+			if (long_options[match].flag == NULL)
+				optopt = long_options[match].val;
+			else
+				optopt = 0;
+			return (BADARG);
+		}
+		if (long_options[match].has_arg == required_argument ||
+		    long_options[match].has_arg == optional_argument) {
+			if (has_equal)
+				optarg = has_equal;
+			else if (long_options[match].has_arg ==
+			    required_argument) {
+				/*
+				 * optional argument doesn't use next nargv
+				 */
+				optarg = nargv[optind++];
+			}
+		}
+		if ((long_options[match].has_arg == required_argument)
+		    && (optarg == NULL)) {
+			/*
+			 * Missing argument; leading ':' indicates no error
+			 * should be generated.
+			 */
+			if (PRINT_ERROR)
+				warnx(recargstring,
+				    current_argv);
+			/*
+			 * XXX: GNU sets optopt to val regardless of flag
+			 */
+			if (long_options[match].flag == NULL)
+				optopt = long_options[match].val;
+			else
+				optopt = 0;
+			--optind;
+			return (BADARG);
+		}
+	} else {			/* unknown option */
+		if (short_too) {
+			--optind;
+			return (-1);
+		}
+		if (PRINT_ERROR)
+			warnx(illoptstring, current_argv);
+		optopt = 0;
+		return (BADCH);
+	}
+	if (idx)
+		*idx = match;
+	if (long_options[match].flag) {
+		*long_options[match].flag = long_options[match].val;
+		return (0);
+	} else
+		return (long_options[match].val);
+#undef IDENTICAL_INTERPRETATION
+}
+
+/*
+ * getopt_internal --
+ *	Parse argc/argv argument vector.  Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+	const struct option *long_options, int *idx, int flags)
+{
+	char *oli;				/* option letter list index */
+	int optchar, short_too;
+	static int posixly_correct = -1;
+
+	if (options == NULL)
+		return (-1);
+
+	/*
+	 * XXX Some GNU programs (like cvs) set optind to 0 instead of
+	 * XXX using optreset.  Work around this braindamage.
+	 */
+	if (optind == 0)
+		optind = optreset = 1;
+
+	/*
+	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
+	 * string begins with a '+'.
+	 *
+	 * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
+	 *                 optreset != 0 for GNU compatibility.
+	 */
+	if (posixly_correct == -1 || optreset != 0)
+		posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+	if (*options == '-')
+		flags |= FLAG_ALLARGS;
+	else if (posixly_correct || *options == '+')
+		flags &= ~FLAG_PERMUTE;
+	if (*options == '+' || *options == '-')
+		options++;
+
+	optarg = NULL;
+	if (optreset)
+		nonopt_start = nonopt_end = -1;
+start:
+	if (optreset || !*place) {		/* update scanning pointer */
+		optreset = 0;
+		if (optind >= nargc) {          /* end of argument vector */
+			place = EMSG;
+			if (nonopt_end != -1) {
+				/* do permutation, if we have to */
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			else if (nonopt_start != -1) {
+				/*
+				 * If we skipped non-options, set optind
+				 * to the first of them.
+				 */
+				optind = nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return (-1);
+		}
+		if (*(place = nargv[optind]) != '-' ||
+		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
+			place = EMSG;		/* found non-option */
+			if (flags & FLAG_ALLARGS) {
+				/*
+				 * GNU extension:
+				 * return non-option as argument to option 1
+				 */
+				optarg = nargv[optind++];
+				return (INORDER);
+			}
+			if (!(flags & FLAG_PERMUTE)) {
+				/*
+				 * If no permutation wanted, stop parsing
+				 * at first non-option.
+				 */
+				return (-1);
+			}
+			/* do permutation */
+			if (nonopt_start == -1)
+				nonopt_start = optind;
+			else if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				nonopt_start = optind -
+				    (nonopt_end - nonopt_start);
+				nonopt_end = -1;
+			}
+			optind++;
+			/* process next argument */
+			goto start;
+		}
+		if (nonopt_start != -1 && nonopt_end == -1)
+			nonopt_end = optind;
+
+		/*
+		 * If we have "-" do nothing, if "--" we are done.
+		 */
+		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+			optind++;
+			place = EMSG;
+			/*
+			 * We found an option (--), so if we skipped
+			 * non-options, we have to permute.
+			 */
+			if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return (-1);
+		}
+	}
+
+	/*
+	 * Check long options if:
+	 *  1) we were passed some
+	 *  2) the arg is not just "-"
+	 *  3) either the arg starts with -- we are getopt_long_only()
+	 */
+	if (long_options != NULL && place != nargv[optind] &&
+	    (*place == '-' || (flags & FLAG_LONGONLY))) {
+		short_too = 0;
+		if (*place == '-')
+			place++;		/* --foo long option */
+		else if (*place != ':' && strchr(options, *place) != NULL)
+			short_too = 1;		/* could be short option too */
+
+		optchar = parse_long_options(nargv, options, long_options,
+		    idx, short_too);
+		if (optchar != -1) {
+			place = EMSG;
+			return (optchar);
+		}
+	}
+
+	if ((optchar = (int)*place++) == (int)':' ||
+	    (optchar == (int)'-' && *place != '\0') ||
+	    (oli = strchr(options, optchar)) == NULL) {
+		/*
+		 * If the user specified "-" and  '-' isn't listed in
+		 * options, return -1 (non-option) as per POSIX.
+		 * Otherwise, it is an unknown option character (or ':').
+		 */
+		if (optchar == (int)'-' && *place == '\0')
+			return (-1);
+		if (!*place)
+			++optind;
+		if (PRINT_ERROR)
+			warnx(illoptchar, optchar);
+		optopt = optchar;
+		return (BADCH);
+	}
+	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+		/* -W long-option */
+		if (*place)			/* no space */
+			/* NOTHING */;
+		else if (++optind >= nargc) {	/* no arg */
+			place = EMSG;
+			if (PRINT_ERROR)
+				warnx(recargchar, optchar);
+			optopt = optchar;
+			return (BADARG);
+		} else				/* white space */
+			place = nargv[optind];
+		optchar = parse_long_options(nargv, options, long_options,
+		    idx, 0);
+		place = EMSG;
+		return (optchar);
+	}
+	if (*++oli != ':') {			/* doesn't take argument */
+		if (!*place)
+			++optind;
+	} else {				/* takes (optional) argument */
+		optarg = NULL;
+		if (*place)			/* no white space */
+			optarg = place;
+		else if (oli[1] != ':') {	/* arg not optional */
+			if (++optind >= nargc) {	/* no arg */
+				place = EMSG;
+				if (PRINT_ERROR)
+					warnx(recargchar, optchar);
+				optopt = optchar;
+				return (BADARG);
+			} else
+				optarg = nargv[optind];
+		}
+		place = EMSG;
+		++optind;
+	}
+	/* dump back option letter */
+	return (optchar);
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+	/*
+	 * We don't pass FLAG_PERMUTE to getopt_internal() since
+	 * the BSD getopt(3) (unlike GNU) has never done this.
+	 *
+	 * Furthermore, since many privileged programs call getopt()
+	 * before dropping privileges it makes sense to keep things
+	 * as simple (and bug-free) as possible.
+	 */
+	return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+/*
+ * getopt_long --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx)
+{
+
+	return (getopt_internal(nargc, nargv, options, long_options, idx,
+	    FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx)
+{
+
+	return (getopt_internal(nargc, nargv, options, long_options, idx,
+	    FLAG_PERMUTE|FLAG_LONGONLY));
+}
diff --git a/media/libdav1d/src/tools/dav1d.c b/media/libdav1d/src/tools/dav1d.c
new file mode 100644
index 0000000000..e2567210d3
--- /dev/null
+++ b/media/libdav1d/src/tools/dav1d.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "vcs_version.h"
+#include "cli_config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#if HAVE_UNISTD_H
+# include 
+#endif
+#if HAVE_IO_H
+# include 
+#endif
+#ifdef _WIN32
+# include 
+#endif
+#ifdef __APPLE__
+#include 
+#endif
+
+#include "dav1d/dav1d.h"
+
+#include "input/input.h"
+
+#include "output/output.h"
+
+#include "dav1d_cli_parse.h"
+
+static uint64_t get_time_nanos(void) {
+#ifdef _WIN32
+    LARGE_INTEGER frequency;
+    QueryPerformanceFrequency(&frequency);
+    LARGE_INTEGER t;
+    QueryPerformanceCounter(&t);
+    uint64_t seconds = t.QuadPart / frequency.QuadPart;
+    uint64_t fractions = t.QuadPart % frequency.QuadPart;
+    return 1000000000 * seconds + 1000000000 * fractions / frequency.QuadPart;
+#elif HAVE_CLOCK_GETTIME
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    return 1000000000ULL * ts.tv_sec + ts.tv_nsec;
+#elif defined(__APPLE__)
+    mach_timebase_info_data_t info;
+    mach_timebase_info(&info);
+    return mach_absolute_time() * info.numer / info.denom;
+#endif
+}
+
+static void sleep_nanos(uint64_t d) {
+#ifdef _WIN32
+    Sleep((unsigned)(d / 1000000));
+#else
+    const struct timespec ts = {
+        .tv_sec = (time_t)(d / 1000000000),
+        .tv_nsec = d % 1000000000,
+    };
+    nanosleep(&ts, NULL);
+#endif
+}
+
+static void synchronize(const int realtime, const unsigned cache,
+                        const unsigned n_out, const uint64_t nspf,
+                        const uint64_t tfirst, uint64_t *const elapsed,
+                        FILE *const frametimes)
+{
+    const uint64_t tcurr = get_time_nanos();
+    const uint64_t last = *elapsed;
+    *elapsed = tcurr - tfirst;
+    if (realtime) {
+        const uint64_t deadline = nspf * n_out;
+        if (*elapsed < deadline) {
+            const uint64_t remaining = deadline - *elapsed;
+            if (remaining > nspf * cache) sleep_nanos(remaining - nspf * cache);
+            *elapsed = deadline;
+        }
+    }
+    if (frametimes) {
+        const uint64_t frametime = *elapsed - last;
+        fprintf(frametimes, "%" PRIu64 "\n", frametime);
+        fflush(frametimes);
+    }
+}
+
+static void print_stats(const int istty, const unsigned n, const unsigned num,
+                        const uint64_t elapsed, const double i_fps)
+{
+    char buf[80], *b = buf, *const end = buf + 80;
+
+    if (istty)
+        *b++ = '\r';
+    if (num == 0xFFFFFFFF)
+        b += snprintf(b, end - b, "Decoded %u frames", n);
+    else
+        b += snprintf(b, end - b, "Decoded %u/%u frames (%.1lf%%)",
+                      n, num, 100.0 * n / num);
+    if (b < end) {
+        const double d_fps = 1e9 * n / elapsed;
+        if (i_fps) {
+            const double speed = d_fps / i_fps;
+            b += snprintf(b, end - b, " - %.2lf/%.2lf fps (%.2lfx)",
+                          d_fps, i_fps, speed);
+        } else {
+            b += snprintf(b, end - b, " - %.2lf fps", d_fps);
+        }
+    }
+    if (!istty)
+        strcpy(b > end - 2 ? end - 2 : b, "\n");
+    fputs(buf, stderr);
+}
+
+static int picture_alloc(Dav1dPicture *const p, void *const _) {
+    const int hbd = p->p.bpc > 8;
+    const int aligned_w = (p->p.w + 127) & ~127;
+    const int aligned_h = (p->p.h + 127) & ~127;
+    const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400;
+    const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+    const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
+    ptrdiff_t y_stride = aligned_w << hbd;
+    ptrdiff_t uv_stride = has_chroma ? y_stride >> ss_hor : 0;
+    /* Due to how mapping of addresses to sets works in most L1 and L2 cache
+     * implementations, strides of multiples of certain power-of-two numbers
+     * may cause multiple rows of the same superblock to map to the same set,
+     * causing evictions of previous rows resulting in a reduction in cache
+     * hit rate. Avoid that by slightly padding the stride when necessary. */
+    if (!(y_stride & 1023))
+        y_stride += DAV1D_PICTURE_ALIGNMENT;
+    if (!(uv_stride & 1023) && has_chroma)
+        uv_stride += DAV1D_PICTURE_ALIGNMENT;
+    p->stride[0] = -y_stride;
+    p->stride[1] = -uv_stride;
+    const size_t y_sz = y_stride * aligned_h;
+    const size_t uv_sz = uv_stride * (aligned_h >> ss_ver);
+    const size_t pic_size = y_sz + 2 * uv_sz;
+
+    uint8_t *const buf = malloc(pic_size + DAV1D_PICTURE_ALIGNMENT * 2);
+    if (!buf) return DAV1D_ERR(ENOMEM);
+    p->allocator_data = buf;
+
+    const ptrdiff_t align_m1 = DAV1D_PICTURE_ALIGNMENT - 1;
+    uint8_t *const data = (uint8_t *)(((ptrdiff_t)buf + align_m1) & ~align_m1);
+    p->data[0] = data + y_sz - y_stride;
+    p->data[1] = has_chroma ? data + y_sz + uv_sz * 1 - uv_stride : NULL;
+    p->data[2] = has_chroma ? data + y_sz + uv_sz * 2 - uv_stride : NULL;
+
+    return 0;
+}
+
+static void picture_release(Dav1dPicture *const p, void *const _) {
+    free(p->allocator_data);
+}
+
+static volatile sig_atomic_t signal_terminate;
+static void signal_handler(const int s) {
+    signal_terminate = 1;
+}
+
+int main(const int argc, char *const *const argv) {
+    const int istty = isatty(fileno(stderr));
+    int res = 0;
+    CLISettings cli_settings;
+    Dav1dSettings lib_settings;
+    DemuxerContext *in;
+    MuxerContext *out = NULL;
+    Dav1dPicture p;
+    Dav1dContext *c;
+    Dav1dData data;
+    unsigned n_out = 0, total, fps[2], timebase[2];
+    uint64_t nspf, tfirst, elapsed = 0;
+    double i_fps;
+    FILE *frametimes = NULL;
+    const unsigned version = dav1d_version_api();
+    const int major = DAV1D_API_MAJOR(version);
+    const int minor = DAV1D_API_MINOR(version);
+    const int patch = DAV1D_API_PATCH(version);
+
+    if (DAV1D_API_VERSION_MAJOR != major ||
+        DAV1D_API_VERSION_MINOR  > minor) {
+        fprintf(stderr, "Version mismatch (library: %d.%d.%d, executable: %d.%d.%d)\n",
+                major, minor, patch,
+                DAV1D_API_VERSION_MAJOR,
+                DAV1D_API_VERSION_MINOR,
+                DAV1D_API_VERSION_PATCH);
+        return EXIT_FAILURE;
+    }
+
+    parse(argc, argv, &cli_settings, &lib_settings);
+    if (cli_settings.neg_stride) {
+        lib_settings.allocator.alloc_picture_callback = picture_alloc;
+        lib_settings.allocator.release_picture_callback = picture_release;
+    }
+
+    if ((res = input_open(&in, cli_settings.demuxer,
+                          cli_settings.inputfile,
+                          fps, &total, timebase)) < 0)
+    {
+        return EXIT_FAILURE;
+    }
+    for (unsigned i = 0; i <= cli_settings.skip; i++) {
+        if ((res = input_read(in, &data)) < 0) {
+            input_close(in);
+            return EXIT_FAILURE;
+        }
+        if (i < cli_settings.skip) dav1d_data_unref(&data);
+    }
+
+    if (!cli_settings.quiet)
+        fprintf(stderr, "dav1d %s - by VideoLAN\n", dav1d_version());
+
+    // skip frames until a sequence header is found
+    if (cli_settings.skip) {
+        Dav1dSequenceHeader seq;
+        unsigned seq_skip = 0;
+        while (dav1d_parse_sequence_header(&seq, data.data, data.sz)) {
+            if ((res = input_read(in, &data)) < 0) {
+                input_close(in);
+                return EXIT_FAILURE;
+            }
+            seq_skip++;
+        }
+        if (seq_skip && !cli_settings.quiet)
+            fprintf(stderr,
+                    "skipped %u packets due to missing sequence header\n",
+                    seq_skip);
+    }
+
+    if (cli_settings.limit != 0 && cli_settings.limit < total)
+        total = cli_settings.limit;
+
+    if ((res = dav1d_open(&c, &lib_settings)))
+        return EXIT_FAILURE;
+
+    if (cli_settings.frametimes)
+        frametimes = fopen(cli_settings.frametimes, "w");
+
+    if (cli_settings.realtime != REALTIME_CUSTOM) {
+        if (fps[1] == 0) {
+            i_fps = 0;
+            nspf = 0;
+        } else {
+            i_fps = (double)fps[0] / fps[1];
+            nspf = 1000000000ULL * fps[1] / fps[0];
+        }
+    } else {
+        i_fps = cli_settings.realtime_fps;
+        nspf = (uint64_t)(1000000000.0 / cli_settings.realtime_fps);
+    }
+    tfirst = get_time_nanos();
+
+#ifdef _WIN32
+    signal(SIGINT,  signal_handler);
+    signal(SIGTERM, signal_handler);
+#else
+    static const struct sigaction sa = {
+        .sa_handler = signal_handler,
+        .sa_flags = SA_RESETHAND,
+    };
+    sigaction(SIGINT,  &sa, NULL);
+    sigaction(SIGTERM, &sa, NULL);
+#endif
+
+    do {
+        if ((res = signal_terminate)) break;
+
+        memset(&p, 0, sizeof(p));
+        if ((res = dav1d_send_data(c, &data)) < 0) {
+            if (res != DAV1D_ERR(EAGAIN)) {
+                dav1d_data_unref(&data);
+                fprintf(stderr, "Error decoding frame: %s\n",
+                        strerror(DAV1D_ERR(res)));
+                if (res != DAV1D_ERR(EINVAL)) break;
+            }
+        }
+
+        if ((res = dav1d_get_picture(c, &p)) < 0) {
+            if (res != DAV1D_ERR(EAGAIN)) {
+                fprintf(stderr, "Error decoding frame: %s\n",
+                        strerror(DAV1D_ERR(res)));
+                if (res != DAV1D_ERR(EINVAL)) break;
+            }
+            res = 0;
+        } else {
+            if (!n_out) {
+                if ((res = output_open(&out, cli_settings.muxer,
+                                       cli_settings.outputfile,
+                                       &p.p, fps)) < 0)
+                {
+                    if (frametimes) fclose(frametimes);
+                    return EXIT_FAILURE;
+                }
+            }
+            if ((res = output_write(out, &p)) < 0)
+                break;
+            n_out++;
+            if (nspf || !cli_settings.quiet) {
+                synchronize(cli_settings.realtime, cli_settings.realtime_cache,
+                            n_out, nspf, tfirst, &elapsed, frametimes);
+            }
+            if (!cli_settings.quiet)
+                print_stats(istty, n_out, total, elapsed, i_fps);
+        }
+
+        if (cli_settings.limit && n_out == cli_settings.limit)
+            break;
+    } while (data.sz > 0 || !input_read(in, &data));
+
+    if (data.sz > 0) dav1d_data_unref(&data);
+
+    // flush
+    if (res == 0) while (!cli_settings.limit || n_out < cli_settings.limit) {
+        if ((res = signal_terminate)) break;
+
+        if ((res = dav1d_get_picture(c, &p)) < 0) {
+            if (res != DAV1D_ERR(EAGAIN)) {
+                fprintf(stderr, "Error decoding frame: %s\n",
+                        strerror(DAV1D_ERR(res)));
+                if (res != DAV1D_ERR(EINVAL)) break;
+            } else {
+                res = 0;
+                break;
+            }
+        } else {
+            if (!n_out) {
+                if ((res = output_open(&out, cli_settings.muxer,
+                                       cli_settings.outputfile,
+                                       &p.p, fps)) < 0)
+                {
+                    if (frametimes) fclose(frametimes);
+                    return EXIT_FAILURE;
+                }
+            }
+            if ((res = output_write(out, &p)) < 0)
+                break;
+            n_out++;
+            if (nspf || !cli_settings.quiet) {
+                synchronize(cli_settings.realtime, cli_settings.realtime_cache,
+                            n_out, nspf, tfirst, &elapsed, frametimes);
+            }
+            if (!cli_settings.quiet)
+                print_stats(istty, n_out, total, elapsed, i_fps);
+        }
+    }
+
+    if (frametimes) fclose(frametimes);
+
+    input_close(in);
+    if (out) {
+        if (!cli_settings.quiet && istty)
+            fprintf(stderr, "\n");
+        if (cli_settings.verify)
+            res |= output_verify(out, cli_settings.verify);
+        else
+            output_close(out);
+    } else {
+        fprintf(stderr, "No data decoded\n");
+        res = 1;
+    }
+    dav1d_close(&c);
+
+    return (res == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/media/libdav1d/src/tools/dav1d.manifest b/media/libdav1d/src/tools/dav1d.manifest
new file mode 100644
index 0000000000..68cd1856d7
--- /dev/null
+++ b/media/libdav1d/src/tools/dav1d.manifest
@@ -0,0 +1,10 @@
+
+
+    
+    
+        
+            true
+            UTF-8
+        
+    
+
diff --git a/media/libdav1d/src/tools/dav1d.rc.in b/media/libdav1d/src/tools/dav1d.rc.in
new file mode 100644
index 0000000000..ab01f3b924
--- /dev/null
+++ b/media/libdav1d/src/tools/dav1d.rc.in
@@ -0,0 +1,33 @@
+#define API_VERSION_NUMBER @API_VERSION_MAJOR@,@API_VERSION_MINOR@,@API_VERSION_REVISION@,0
+#define API_VERSION_NUMBER_STR "@API_VERSION_MAJOR@.@API_VERSION_MINOR@.@API_VERSION_REVISION@"
+#define PROJECT_VERSION_NUMBER @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_REVISION@,0
+#define PROJECT_VERSION_NUMBER_STR "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_REVISION@"
+
+#include 
+
+1 RT_MANIFEST "dav1d.manifest"
+1 VERSIONINFO
+FILETYPE VFT_APP
+FILEOS VOS_NT_WINDOWS32
+PRODUCTVERSION PROJECT_VERSION_NUMBER
+FILEVERSION API_VERSION_NUMBER
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904E4"
+    BEGIN
+      VALUE "CompanyName", "VideoLAN"
+      VALUE "ProductName", "dav1d"
+      VALUE "ProductVersion", PROJECT_VERSION_NUMBER_STR
+      VALUE "FileVersion", API_VERSION_NUMBER_STR
+      VALUE "FileDescription", "dav1d " PROJECT_VERSION_NUMBER_STR " - AV1 decoder"
+      VALUE "InternalName", "dav1d"
+      VALUE "OriginalFilename", "dav1d.exe"
+      VALUE "LegalCopyright", L"Copyright \251 @COPYRIGHT_YEARS@ VideoLAN and dav1d Authors"
+    END
+  END
+  BLOCK "VarFileInfo"
+  BEGIN
+    VALUE "Translation", 0x409, 1252
+  END
+END
diff --git a/media/libdav1d/src/tools/dav1d_cli_parse.c b/media/libdav1d/src/tools/dav1d_cli_parse.c
new file mode 100644
index 0000000000..134be46b2f
--- /dev/null
+++ b/media/libdav1d/src/tools/dav1d_cli_parse.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "cli_config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#if HAVE_UNISTD_H
+# include 
+#endif
+
+#include "dav1d_cli_parse.h"
+#include "src/cpu.h"
+
+static const char short_opts[] = "i:o:vql:s:";
+
+enum {
+    ARG_DEMUXER = 256,
+    ARG_MUXER,
+    ARG_FRAME_TIMES,
+    ARG_REALTIME,
+    ARG_REALTIME_CACHE,
+    ARG_THREADS,
+    ARG_FRAME_DELAY,
+    ARG_VERIFY,
+    ARG_FILM_GRAIN,
+    ARG_OPPOINT,
+    ARG_ALL_LAYERS,
+    ARG_SIZE_LIMIT,
+    ARG_STRICT_STD_COMPLIANCE,
+    ARG_CPU_MASK,
+    ARG_NEG_STRIDE,
+    ARG_OUTPUT_INVISIBLE,
+    ARG_INLOOP_FILTERS,
+    ARG_DECODE_FRAME_TYPE,
+};
+
+static const struct option long_opts[] = {
+    { "input",           1, NULL, 'i' },
+    { "output",          1, NULL, 'o' },
+    { "quiet",           0, NULL, 'q' },
+    { "demuxer",         1, NULL, ARG_DEMUXER },
+    { "muxer",           1, NULL, ARG_MUXER },
+    { "version",         0, NULL, 'v' },
+    { "frametimes",      1, NULL, ARG_FRAME_TIMES },
+    { "limit",           1, NULL, 'l' },
+    { "skip",            1, NULL, 's' },
+    { "realtime",        2, NULL, ARG_REALTIME },
+    { "realtimecache",   1, NULL, ARG_REALTIME_CACHE },
+    { "threads",         1, NULL, ARG_THREADS },
+    { "framedelay",      1, NULL, ARG_FRAME_DELAY },
+    { "verify",          1, NULL, ARG_VERIFY },
+    { "filmgrain",       1, NULL, ARG_FILM_GRAIN },
+    { "oppoint",         1, NULL, ARG_OPPOINT },
+    { "alllayers",       1, NULL, ARG_ALL_LAYERS },
+    { "sizelimit",       1, NULL, ARG_SIZE_LIMIT },
+    { "strict",          1, NULL, ARG_STRICT_STD_COMPLIANCE },
+    { "cpumask",         1, NULL, ARG_CPU_MASK },
+    { "negstride",       0, NULL, ARG_NEG_STRIDE },
+    { "outputinvisible", 1, NULL, ARG_OUTPUT_INVISIBLE },
+    { "inloopfilters",   1, NULL, ARG_INLOOP_FILTERS },
+    { "decodeframetype", 1, NULL, ARG_DECODE_FRAME_TYPE },
+    { NULL,              0, NULL, 0 },
+};
+
+#if HAVE_XXHASH_H
+#define AVAILABLE_MUXERS "'md5', 'xxh3', 'yuv', 'yuv4mpeg2' or 'null'"
+#else
+#define AVAILABLE_MUXERS "'md5', 'yuv', 'yuv4mpeg2' or 'null'"
+#endif
+
+#if ARCH_AARCH64 || ARCH_ARM
+#define ALLOWED_CPU_MASKS ", 'neon', 'dotprod' or 'i8mm'"
+#elif ARCH_LOONGARCH
+#define ALLOWED_CPU_MASKS ", 'lsx' or 'lasx'"
+#elif ARCH_PPC64LE
+#define ALLOWED_CPU_MASKS ", 'vsx' or 'pwr9'"
+#elif ARCH_RISCV
+#define ALLOWED_CPU_MASKS " or 'rvv'"
+#elif ARCH_X86
+#define ALLOWED_CPU_MASKS \
+    ", 'sse2', 'ssse3', 'sse41', 'avx2' or 'avx512icl'"
+#else
+#define ALLOWED_CPU_MASKS "not yet implemented for this architecture"
+#endif
+
+static void usage(const char *const app, const char *const reason, ...) {
+    if (reason) {
+        va_list args;
+
+        va_start(args, reason);
+        vfprintf(stderr, reason, args);
+        va_end(args);
+        fprintf(stderr, "\n\n");
+    }
+    fprintf(stderr, "Usage: %s [options]\n\n", app);
+    fprintf(stderr, "Supported options:\n"
+            " --input/-i $file:     input file\n"
+            " --output/-o $file:    output file (%%n, %%w or %%h will be filled in for per-frame files)\n"
+            " --demuxer $name:      force demuxer type ('ivf', 'section5' or 'annexb'; default: detect from content)\n"
+            " --muxer $name:        force muxer type (" AVAILABLE_MUXERS "; default: detect from extension)\n"
+            "                       use 'frame' as prefix to write per-frame files; if filename contains %%n, will default to writing per-frame files\n"
+            " --quiet/-q:           disable status messages\n"
+            " --frametimes $file:   dump frame times to file\n"
+            " --limit/-l $num:      stop decoding after $num frames\n"
+            " --skip/-s $num:       skip decoding of the first $num frames\n"
+            " --realtime [$fract]:  limit framerate, optional argument to override input framerate\n"
+            " --realtimecache $num: set the size of the cache in realtime mode (default: 0)\n"
+            " --version/-v:         print version and exit\n"
+            " --threads $num:       number of threads (default: 0)\n"
+            " --framedelay $num:    maximum frame delay, capped at $threads (default: 0);\n"
+            "                       set to 1 for low-latency decoding\n"
+            " --filmgrain $num:     enable film grain application (default: 1, except if muxer is md5 or xxh3)\n"
+            " --oppoint $num:       select an operating point of a scalable AV1 bitstream (0 - 31)\n"
+            " --alllayers $num:     output all spatial layers of a scalable AV1 bitstream (default: 1)\n"
+            " --sizelimit $num:     stop decoding if the frame size exceeds the specified limit\n"
+            " --strict $num:        whether to abort decoding on standard compliance violations\n"
+            "                       that don't affect bitstream decoding (default: 1)\n"
+            " --verify $md5:        verify decoded md5. implies --muxer md5, no output\n"
+            " --cpumask $mask:      restrict permitted CPU instruction sets (0" ALLOWED_CPU_MASKS "; default: -1)\n"
+            " --negstride:          use negative picture strides\n"
+            "                       this is mostly meant as a developer option\n"
+            " --outputinvisible $num: whether to output invisible (alt-ref) frames (default: 0)\n"
+            " --inloopfilters $str: which in-loop filters to enable (none, (no)deblock, (no)cdef, (no)restoration or all; default: all)\n"
+            " --decodeframetype $str: which frame types to decode (reference, intra, key or all; default: all)\n"
+            );
+    exit(1);
+}
+
+static void error(const char *const app, const char *const optarg,
+                  const int option, const char *const shouldbe)
+{
+    char optname[256];
+    int n;
+
+    for (n = 0; long_opts[n].name; n++)
+        if (long_opts[n].val == option)
+            break;
+    assert(long_opts[n].name);
+    if (long_opts[n].val < 256) {
+        sprintf(optname, "-%c/--%s", long_opts[n].val, long_opts[n].name);
+    } else {
+        sprintf(optname, "--%s", long_opts[n].name);
+    }
+
+    usage(app, "Invalid argument \"%s\" for option %s; should be %s",
+          optarg, optname, shouldbe);
+}
+
+static unsigned parse_unsigned(const char *const optarg, const int option,
+                               const char *const app)
+{
+    char *end;
+    const unsigned res = (unsigned) strtoul(optarg, &end, 0);
+    if (*end || end == optarg) error(app, optarg, option, "an integer");
+    return res;
+}
+
+static int parse_optional_fraction(const char *const optarg, const int option,
+                                   const char *const app, double *value)
+{
+    if (optarg == NULL) return 0;
+    char *end;
+    *value = strtod(optarg, &end);
+    if (*end == '/' && end != optarg) {
+        const char *optarg2 = end + 1;
+        *value /= strtod(optarg2, &end);
+        if (*end || end == optarg2) error(app, optarg, option, "a fraction");
+    } else if (*end || end == optarg) {
+        error(app, optarg, option, "a fraction");
+    }
+    return 1;
+}
+
+typedef struct EnumParseTable {
+    const char *str;
+    const int val;
+} EnumParseTable;
+
+#if ARCH_X86
+enum CpuMask {
+    X86_CPU_MASK_SSE2      = DAV1D_X86_CPU_FLAG_SSE2,
+    X86_CPU_MASK_SSSE3     = DAV1D_X86_CPU_FLAG_SSSE3     | X86_CPU_MASK_SSE2,
+    X86_CPU_MASK_SSE41     = DAV1D_X86_CPU_FLAG_SSE41     | X86_CPU_MASK_SSSE3,
+    X86_CPU_MASK_AVX2      = DAV1D_X86_CPU_FLAG_AVX2      | X86_CPU_MASK_SSE41,
+    X86_CPU_MASK_AVX512ICL = DAV1D_X86_CPU_FLAG_AVX512ICL | X86_CPU_MASK_AVX2,
+};
+#elif ARCH_AARCH64 || ARCH_ARM
+enum CpuMask {
+    ARM_CPU_MASK_NEON      = DAV1D_ARM_CPU_FLAG_NEON,
+    ARM_CPU_MASK_DOTPROD   = DAV1D_ARM_CPU_FLAG_DOTPROD | ARM_CPU_MASK_NEON,
+    ARM_CPU_MASK_I8MM      = DAV1D_ARM_CPU_FLAG_I8MM    | ARM_CPU_MASK_DOTPROD,
+#if ARCH_AARCH64
+    // SVE doesn't imply DOTPROD or I8MM.
+    ARM_CPU_MASK_SVE       = DAV1D_ARM_CPU_FLAG_SVE     | ARM_CPU_MASK_NEON,
+    // SVE2 implies DOTPROD, but not I8MM.
+    ARM_CPU_MASK_SVE2      = DAV1D_ARM_CPU_FLAG_SVE2    | ARM_CPU_MASK_SVE | ARM_CPU_MASK_DOTPROD,
+#endif
+};
+#endif
+
+#if ARCH_PPC64LE
+enum CpuMask {
+    PPC_CPU_MASK_VSX       = DAV1D_PPC_CPU_FLAG_VSX,
+    PPC_CPU_MASK_PWR9      = DAV1D_PPC_CPU_FLAG_VSX | DAV1D_PPC_CPU_FLAG_PWR9,
+};
+#endif
+
+
+static const EnumParseTable cpu_mask_tbl[] = {
+#if ARCH_AARCH64 || ARCH_ARM
+    { "neon",    ARM_CPU_MASK_NEON },
+    { "dotprod", ARM_CPU_MASK_DOTPROD },
+    { "i8mm",    ARM_CPU_MASK_I8MM },
+#if ARCH_AARCH64
+    { "sve",     ARM_CPU_MASK_SVE },
+    { "sve2",    ARM_CPU_MASK_SVE2 },
+#endif /* ARCH_AARCH64 */
+#elif ARCH_LOONGARCH
+    { "lsx", DAV1D_LOONGARCH_CPU_FLAG_LSX },
+    { "lasx", DAV1D_LOONGARCH_CPU_FLAG_LASX },
+#elif ARCH_PPC64LE
+    { "vsx",  PPC_CPU_MASK_VSX },
+    { "pwr9", PPC_CPU_MASK_PWR9 },
+#elif ARCH_RISCV
+    { "rvv", DAV1D_RISCV_CPU_FLAG_V },
+#elif ARCH_X86
+    { "sse2",      X86_CPU_MASK_SSE2 },
+    { "ssse3",     X86_CPU_MASK_SSSE3 },
+    { "sse41",     X86_CPU_MASK_SSE41 },
+    { "avx2",      X86_CPU_MASK_AVX2 },
+    { "avx512icl", X86_CPU_MASK_AVX512ICL },
+#endif
+    { "none",      0 },
+};
+
+static const EnumParseTable inloop_filters_tbl[] = {
+    { "none",          DAV1D_INLOOPFILTER_NONE },
+    { "deblock",       DAV1D_INLOOPFILTER_DEBLOCK },
+    { "nodeblock",     DAV1D_INLOOPFILTER_ALL - DAV1D_INLOOPFILTER_DEBLOCK },
+    { "cdef",          DAV1D_INLOOPFILTER_CDEF },
+    { "nocdef",        DAV1D_INLOOPFILTER_ALL - DAV1D_INLOOPFILTER_CDEF },
+    { "restoration",   DAV1D_INLOOPFILTER_RESTORATION },
+    { "norestoration", DAV1D_INLOOPFILTER_ALL - DAV1D_INLOOPFILTER_RESTORATION },
+    { "all",           DAV1D_INLOOPFILTER_ALL },
+};
+
+static const EnumParseTable decode_frame_type_tbl[] = {
+    { "all",           DAV1D_DECODEFRAMETYPE_ALL },
+    { "reference",     DAV1D_DECODEFRAMETYPE_REFERENCE },
+    { "intra",         DAV1D_DECODEFRAMETYPE_INTRA },
+    { "key",           DAV1D_DECODEFRAMETYPE_KEY },
+};
+
+#define ARRAY_SIZE(n) (sizeof(n)/sizeof(*(n)))
+
+static unsigned parse_enum(char *optarg, const EnumParseTable *const tbl,
+                           const int tbl_sz, const int option, const char *app)
+{
+    char str[1024];
+
+    strcpy(str, "any of ");
+    for (int n = 0; n < tbl_sz; n++) {
+        if (!strcmp(tbl[n].str, optarg))
+            return tbl[n].val;
+
+        if (n) {
+            if (n < tbl_sz - 1)
+                strcat(str, ", ");
+            else
+                strcat(str, " or ");
+        }
+        strcat(str, tbl[n].str);
+    }
+
+    char *end;
+    unsigned res;
+    if (!strncmp(optarg, "0x", 2)) {
+        res = (unsigned) strtoul(&optarg[2], &end, 16);
+    } else {
+        res = (unsigned) strtoul(optarg, &end, 0);
+    }
+
+    if (*end || end == optarg) {
+        strcat(str, ", a hexadecimal (starting with 0x), or an integer");
+        error(app, optarg, option, str);
+    }
+
+    return res;
+}
+
+void parse(const int argc, char *const *const argv,
+           CLISettings *const cli_settings, Dav1dSettings *const lib_settings)
+{
+    int o;
+
+    memset(cli_settings, 0, sizeof(*cli_settings));
+    dav1d_default_settings(lib_settings);
+    lib_settings->strict_std_compliance = 1; // override library default
+    int grain_specified = 0;
+
+    while ((o = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
+        switch (o) {
+        case 'o':
+            cli_settings->outputfile = optarg;
+            break;
+        case 'i':
+            cli_settings->inputfile = optarg;
+            break;
+        case 'q':
+            cli_settings->quiet = 1;
+            break;
+        case 'l':
+            cli_settings->limit = parse_unsigned(optarg, 'l', argv[0]);
+            break;
+        case 's':
+            cli_settings->skip = parse_unsigned(optarg, 's', argv[0]);
+            break;
+        case ARG_DEMUXER:
+            cli_settings->demuxer = optarg;
+            break;
+        case ARG_MUXER:
+            cli_settings->muxer = optarg;
+            break;
+        case ARG_FRAME_TIMES:
+            cli_settings->frametimes = optarg;
+            break;
+        case ARG_REALTIME:
+            // workaround to parse an optional argument of the form `--a b`
+            // (getopt only allows `--a=b`)
+            if (optarg == NULL && optind < argc && argv[optind] != NULL &&
+                argv[optind][0] != '-')
+            {
+                optarg = argv[optind];
+                optind++;
+            }
+            cli_settings->realtime = 1 + parse_optional_fraction(optarg,
+                ARG_REALTIME, argv[0], &cli_settings->realtime_fps);
+            break;
+        case ARG_REALTIME_CACHE:
+            cli_settings->realtime_cache =
+                parse_unsigned(optarg, ARG_REALTIME_CACHE, argv[0]);
+            break;
+        case ARG_FRAME_DELAY:
+            lib_settings->max_frame_delay =
+                parse_unsigned(optarg, ARG_FRAME_DELAY, argv[0]);
+            break;
+        case ARG_THREADS:
+            lib_settings->n_threads =
+                parse_unsigned(optarg, ARG_THREADS, argv[0]);
+            break;
+        case ARG_VERIFY:
+            cli_settings->verify = optarg;
+            break;
+        case ARG_FILM_GRAIN:
+            lib_settings->apply_grain =
+                !!parse_unsigned(optarg, ARG_FILM_GRAIN, argv[0]);
+            grain_specified = 1;
+            break;
+        case ARG_OPPOINT:
+            lib_settings->operating_point =
+                parse_unsigned(optarg, ARG_OPPOINT, argv[0]);
+            break;
+        case ARG_ALL_LAYERS:
+            lib_settings->all_layers =
+                !!parse_unsigned(optarg, ARG_ALL_LAYERS, argv[0]);
+            break;
+        case ARG_SIZE_LIMIT: {
+            char *arg = optarg, *end;
+            uint64_t res = strtoul(arg, &end, 0);
+            if (*end == 'x') // NxM
+                res *= strtoul((arg = end + 1), &end, 0);
+            if (*end || end == arg || res >= UINT_MAX)
+                error(argv[0], optarg, ARG_SIZE_LIMIT, "an integer or dimension");
+            lib_settings->frame_size_limit = (unsigned) res;
+            break;
+        }
+        case ARG_STRICT_STD_COMPLIANCE:
+            lib_settings->strict_std_compliance =
+                parse_unsigned(optarg, ARG_STRICT_STD_COMPLIANCE, argv[0]);
+            break;
+        case 'v':
+            fprintf(stderr, "%s\n", dav1d_version());
+            exit(0);
+        case ARG_CPU_MASK:
+            dav1d_set_cpu_flags_mask(parse_enum(optarg, cpu_mask_tbl, ARRAY_SIZE(cpu_mask_tbl),
+                                                ARG_CPU_MASK, argv[0]));
+            break;
+        case ARG_NEG_STRIDE:
+            cli_settings->neg_stride = 1;
+            break;
+        case ARG_OUTPUT_INVISIBLE:
+            lib_settings->output_invisible_frames =
+                !!parse_unsigned(optarg, ARG_OUTPUT_INVISIBLE, argv[0]);
+            break;
+        case ARG_INLOOP_FILTERS:
+            lib_settings->inloop_filters =
+                parse_enum(optarg, inloop_filters_tbl,
+                           ARRAY_SIZE(inloop_filters_tbl),ARG_INLOOP_FILTERS, argv[0]);
+            break;
+        case ARG_DECODE_FRAME_TYPE:
+            lib_settings->decode_frame_type =
+                parse_enum(optarg, decode_frame_type_tbl,
+                           ARRAY_SIZE(decode_frame_type_tbl), ARG_DECODE_FRAME_TYPE, argv[0]);
+            break;
+        default:
+            usage(argv[0], NULL);
+        }
+    }
+
+    if (optind < argc)
+        usage(argv[0], "Extra/unused arguments found, e.g. '%s'\n", argv[optind]);
+    if (cli_settings->verify) {
+        if (cli_settings->outputfile)
+            usage(argv[0], "Verification (--verify) requires output file (-o/--output) to not set");
+        if (cli_settings->muxer && strcmp(cli_settings->muxer, "md5") &&
+            strcmp(cli_settings->muxer, "xxh3"))
+        {
+            usage(argv[0], "Verification (--verify) requires a checksum muxer (md5 or xxh3)");
+        }
+
+        cli_settings->outputfile = "-";
+        if (!cli_settings->muxer)
+            cli_settings->muxer = "md5";
+    }
+
+    if (!grain_specified && cli_settings->muxer &&
+        (!strcmp(cli_settings->muxer, "md5") ||
+        !strcmp(cli_settings->muxer, "xxh3")))
+    {
+        lib_settings->apply_grain = 0;
+    }
+
+    if (!cli_settings->inputfile)
+        usage(argv[0], "Input file (-i/--input) is required");
+    if ((!cli_settings->muxer || strcmp(cli_settings->muxer, "null")) &&
+        !cli_settings->outputfile)
+    {
+        usage(argv[0], "Output file (-o/--output) is required");
+    }
+}
diff --git a/media/libdav1d/src/tools/dav1d_cli_parse.h b/media/libdav1d/src/tools/dav1d_cli_parse.h
new file mode 100644
index 0000000000..50cfeb817e
--- /dev/null
+++ b/media/libdav1d/src/tools/dav1d_cli_parse.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_CLI_PARSE_H
+#define DAV1D_CLI_PARSE_H
+
+#include "dav1d/dav1d.h"
+
+typedef struct {
+    const char *outputfile;
+    const char *inputfile;
+    const char *demuxer;
+    const char *muxer;
+    const char *frametimes;
+    const char *verify;
+    unsigned limit, skip;
+    int quiet;
+    enum {
+        REALTIME_DISABLE = 0,
+        REALTIME_INPUT,
+        REALTIME_CUSTOM,
+    } realtime;
+    double realtime_fps;
+    unsigned realtime_cache;
+    int neg_stride;
+} CLISettings;
+
+void parse(const int argc, char *const *const argv,
+           CLISettings *const cli_settings, Dav1dSettings *const lib_settings);
+
+#endif /* DAV1D_CLI_PARSE_H */
diff --git a/media/libdav1d/src/tools/input/annexb.c b/media/libdav1d/src/tools/input/annexb.c
new file mode 100644
index 0000000000..8add61c355
--- /dev/null
+++ b/media/libdav1d/src/tools/input/annexb.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * Copyright © 2019, James Almer 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "common/intops.h"
+
+#include "dav1d/headers.h"
+
+#include "input/demuxer.h"
+#include "input/parse.h"
+
+// these functions are based on an implementation from FFmpeg, and relicensed
+// with author's permission
+
+#define PROBE_SIZE 2048
+
+static int annexb_probe(const uint8_t *data) {
+    int ret, cnt = 0;
+
+    size_t temporal_unit_size;
+    ret = leb(data + cnt, PROBE_SIZE - cnt, &temporal_unit_size);
+    if (ret < 0)
+        return 0;
+    cnt += ret;
+
+    size_t frame_unit_size;
+    ret = leb(data + cnt, PROBE_SIZE - cnt, &frame_unit_size);
+    if (ret < 0 || ((uint64_t)frame_unit_size + ret) > temporal_unit_size)
+        return 0;
+    cnt += ret;
+
+    temporal_unit_size -= ret;
+
+    size_t obu_unit_size;
+    ret = leb(data + cnt, PROBE_SIZE - cnt, &obu_unit_size);
+    if (ret < 0 || ((uint64_t)obu_unit_size + ret) >= frame_unit_size)
+        return 0;
+    cnt += ret;
+
+    temporal_unit_size -= obu_unit_size + ret;
+    frame_unit_size -= obu_unit_size + ret;
+
+    // Check that the first OBU is a Temporal Delimiter.
+    size_t obu_size;
+    enum Dav1dObuType type;
+    ret = parse_obu_header(data + cnt, imin(PROBE_SIZE - cnt, (int) obu_unit_size),
+                           &obu_size, &type, 1);
+    if (ret < 0 || type != DAV1D_OBU_TD || obu_size > 0)
+        return 0;
+    cnt += (int)obu_unit_size;
+
+    // look for first frame and accompanying sequence header
+    int seq = 0;
+    while (cnt < PROBE_SIZE) {
+        ret = leb(data + cnt, PROBE_SIZE - cnt, &obu_unit_size);
+        if (ret < 0 || ((uint64_t)obu_unit_size + ret) > frame_unit_size)
+            return 0;
+        cnt += ret;
+        temporal_unit_size -= ret;
+        frame_unit_size -= ret;
+
+        ret = parse_obu_header(data + cnt, imin(PROBE_SIZE - cnt, (int) obu_unit_size),
+                               &obu_size, &type, 1);
+        if (ret < 0)
+            return 0;
+        cnt += (int)obu_unit_size;
+
+        switch (type) {
+        case DAV1D_OBU_SEQ_HDR:
+            seq = 1;
+            break;
+        case DAV1D_OBU_FRAME:
+        case DAV1D_OBU_FRAME_HDR:
+            return seq;
+        case DAV1D_OBU_TD:
+        case DAV1D_OBU_TILE_GRP:
+            return 0;
+        default:
+            break;
+        }
+
+        temporal_unit_size -= obu_unit_size;
+        frame_unit_size -= obu_unit_size;
+        if (frame_unit_size <= 0)
+            return 0;
+    }
+
+    return seq;
+}
+
+typedef struct DemuxerPriv {
+    FILE *f;
+    size_t temporal_unit_size;
+    size_t frame_unit_size;
+} AnnexbInputContext;
+
+static int annexb_open(AnnexbInputContext *const c, const char *const file,
+                       unsigned fps[2], unsigned *const num_frames, unsigned timebase[2])
+{
+    int res;
+    size_t len;
+
+    if (!(c->f = fopen(file, "rb"))) {
+        fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+        return -1;
+    }
+
+    // TODO: Parse sequence header and read timing info if any.
+    fps[0] = 25;
+    fps[1] = 1;
+    timebase[0] = 25;
+    timebase[1] = 1;
+    for (*num_frames = 0;; (*num_frames)++) {
+        res = leb128(c->f, &len);
+        if (res < 0)
+            break;
+        fseeko(c->f, len, SEEK_CUR);
+    }
+    fseeko(c->f, 0, SEEK_SET);
+
+    return 0;
+}
+
+static int annexb_read(AnnexbInputContext *const c, Dav1dData *const data) {
+    size_t len;
+    int res;
+
+    if (!c->temporal_unit_size) {
+        res = leb128(c->f, &c->temporal_unit_size);
+        if (res < 0) return -1;
+    }
+    if (!c->frame_unit_size) {
+        res = leb128(c->f, &c->frame_unit_size);
+        if (res < 0 || (c->frame_unit_size + res) > c->temporal_unit_size) return -1;
+        c->temporal_unit_size -= res;
+    }
+    res = leb128(c->f, &len);
+    if (res < 0 || (len + res) > c->frame_unit_size) return -1;
+    uint8_t *ptr = dav1d_data_create(data, len);
+    if (!ptr) return -1;
+    c->temporal_unit_size -= len + res;
+    c->frame_unit_size -= len + res;
+    if (fread(ptr, len, 1, c->f) != 1) {
+        fprintf(stderr, "Failed to read frame data: %s\n", strerror(errno));
+        dav1d_data_unref(data);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void annexb_close(AnnexbInputContext *const c) {
+    fclose(c->f);
+}
+
+const Demuxer annexb_demuxer = {
+    .priv_data_size = sizeof(AnnexbInputContext),
+    .name = "annexb",
+    .probe = annexb_probe,
+    .probe_sz = PROBE_SIZE,
+    .open = annexb_open,
+    .read = annexb_read,
+    .seek = NULL,
+    .close = annexb_close,
+};
diff --git a/media/libdav1d/src/tools/input/demuxer.h b/media/libdav1d/src/tools/input/demuxer.h
new file mode 100644
index 0000000000..354db7695a
--- /dev/null
+++ b/media/libdav1d/src/tools/input/demuxer.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_INPUT_DEMUXER_H
+#define DAV1D_INPUT_DEMUXER_H
+
+#include "data.h"
+
+typedef struct DemuxerPriv DemuxerPriv;
+typedef struct Demuxer {
+    int priv_data_size;
+    const char *name;
+    int probe_sz;
+    int (*probe)(const uint8_t *data);
+    int (*open)(DemuxerPriv *ctx, const char *filename,
+                unsigned fps[2], unsigned *num_frames, unsigned timebase[2]);
+    int (*read)(DemuxerPriv *ctx, Dav1dData *data);
+    int (*seek)(DemuxerPriv *ctx, uint64_t pts);
+    void (*close)(DemuxerPriv *ctx);
+} Demuxer;
+
+#endif /* DAV1D_INPUT_DEMUXER_H */
diff --git a/media/libdav1d/src/tools/input/input.c b/media/libdav1d/src/tools/input/input.c
new file mode 100644
index 0000000000..c4b4e60caa
--- /dev/null
+++ b/media/libdav1d/src/tools/input/input.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "input/input.h"
+#include "input/demuxer.h"
+
+struct DemuxerContext {
+    DemuxerPriv *data;
+    const Demuxer *impl;
+    uint64_t priv_data[];
+};
+
+extern const Demuxer ivf_demuxer;
+extern const Demuxer annexb_demuxer;
+extern const Demuxer section5_demuxer;
+static const Demuxer *const demuxers[] = {
+    &ivf_demuxer,
+    &annexb_demuxer,
+    §ion5_demuxer,
+    NULL
+};
+
+int input_open(DemuxerContext **const c_out,
+               const char *const name, const char *const filename,
+               unsigned fps[2], unsigned *const num_frames, unsigned timebase[2])
+{
+    const Demuxer *impl;
+    DemuxerContext *c;
+    int res, i;
+
+    if (name) {
+        for (i = 0; demuxers[i]; i++) {
+            if (!strcmp(demuxers[i]->name, name)) {
+                impl = demuxers[i];
+                break;
+            }
+        }
+        if (!demuxers[i]) {
+            fprintf(stderr, "Failed to find demuxer named \"%s\"\n", name);
+            return DAV1D_ERR(ENOPROTOOPT);
+        }
+    } else {
+        int probe_sz = 0;
+        for (i = 0; demuxers[i]; i++)
+            probe_sz = imax(probe_sz, demuxers[i]->probe_sz);
+        uint8_t *const probe_data = malloc(probe_sz);
+        if (!probe_data) {
+            fprintf(stderr, "Failed to allocate memory\n");
+            return DAV1D_ERR(ENOMEM);
+        }
+        FILE *f = fopen(filename, "rb");
+        if (!f) {
+            free(probe_data);
+            fprintf(stderr, "Failed to open input file %s: %s\n", filename, strerror(errno));
+            return errno ? DAV1D_ERR(errno) : DAV1D_ERR(EIO);
+        }
+        res = !!fread(probe_data, 1, probe_sz, f);
+        fclose(f);
+        if (!res) {
+            free(probe_data);
+            fprintf(stderr, "Failed to read probe data\n");
+            return errno ? DAV1D_ERR(errno) : DAV1D_ERR(EIO);
+        }
+
+        for (i = 0; demuxers[i]; i++) {
+            if (demuxers[i]->probe(probe_data)) {
+                impl = demuxers[i];
+                break;
+            }
+        }
+        free(probe_data);
+        if (!demuxers[i]) {
+            fprintf(stderr,
+                    "Failed to probe demuxer for file %s\n",
+                    filename);
+            return DAV1D_ERR(ENOPROTOOPT);
+        }
+    }
+
+    if (!(c = calloc(1, offsetof(DemuxerContext, priv_data) + impl->priv_data_size))) {
+        fprintf(stderr, "Failed to allocate memory\n");
+        return DAV1D_ERR(ENOMEM);
+    }
+    c->impl = impl;
+    c->data = (DemuxerPriv *) c->priv_data;
+    if ((res = impl->open(c->data, filename, fps, num_frames, timebase)) < 0) {
+        free(c);
+        return res;
+    }
+    *c_out = c;
+
+    return 0;
+}
+
+int input_read(DemuxerContext *const ctx, Dav1dData *const data) {
+    return ctx->impl->read(ctx->data, data);
+}
+
+int input_seek(DemuxerContext *const ctx, const uint64_t pts) {
+    return ctx->impl->seek ? ctx->impl->seek(ctx->data, pts) : -1;
+}
+
+void input_close(DemuxerContext *const ctx) {
+    ctx->impl->close(ctx->data);
+    free(ctx);
+}
diff --git a/media/libdav1d/src/tools/input/input.h b/media/libdav1d/src/tools/input/input.h
new file mode 100644
index 0000000000..098219ce91
--- /dev/null
+++ b/media/libdav1d/src/tools/input/input.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_INPUT_INPUT_H
+#define DAV1D_INPUT_INPUT_H
+
+#include "data.h"
+
+typedef struct DemuxerContext DemuxerContext;
+
+int input_open(DemuxerContext **const c_out,
+               const char *const name, const char *const filename,
+               unsigned fps[2], unsigned *num_frames, unsigned timebase[2]);
+int input_read(DemuxerContext *ctx, Dav1dData *data);
+int input_seek(DemuxerContext *ctx, uint64_t pts);
+void input_close(DemuxerContext *ctx);
+
+#endif /* DAV1D_INPUT_INPUT_H */
diff --git a/media/libdav1d/src/tools/input/ivf.c b/media/libdav1d/src/tools/input/ivf.c
new file mode 100644
index 0000000000..247bf7c8bd
--- /dev/null
+++ b/media/libdav1d/src/tools/input/ivf.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "input/demuxer.h"
+
+typedef struct DemuxerPriv {
+    FILE *f;
+    int broken;
+    double timebase;
+    uint64_t last_ts;
+    uint64_t step;
+} IvfInputContext;
+
+static const uint8_t probe_data[] = {
+    'D', 'K', 'I', 'F',
+    0, 0, 0x20, 0,
+    'A', 'V', '0', '1',
+};
+
+static int ivf_probe(const uint8_t *const data) {
+    return !memcmp(data, probe_data, sizeof(probe_data));
+}
+
+static unsigned rl32(const uint8_t *const p) {
+    return ((uint32_t)p[3] << 24U) | (p[2] << 16U) | (p[1] << 8U) | p[0];
+}
+
+static int64_t rl64(const uint8_t *const p) {
+    return (((uint64_t) rl32(&p[4])) << 32) | rl32(p);
+}
+
+static int ivf_open(IvfInputContext *const c, const char *const file,
+                    unsigned fps[2], unsigned *const num_frames, unsigned timebase[2])
+{
+    uint8_t hdr[32];
+
+    if (!(c->f = fopen(file, "rb"))) {
+        fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+        return -1;
+    } else if (fread(hdr, 32, 1, c->f) != 1) {
+        fprintf(stderr, "Failed to read stream header: %s\n", strerror(errno));
+        fclose(c->f);
+        return -1;
+    } else if (memcmp(hdr, "DKIF", 4)) {
+        fprintf(stderr, "%s is not an IVF file [tag=%.4s|0x%02x%02x%02x%02x]\n",
+                file, hdr, hdr[0], hdr[1], hdr[2], hdr[3]);
+        fclose(c->f);
+        return -1;
+    } else if (memcmp(&hdr[8], "AV01", 4)) {
+        fprintf(stderr, "%s is not an AV1 file [tag=%.4s|0x%02x%02x%02x%02x]\n",
+                file, &hdr[8], hdr[8], hdr[9], hdr[10], hdr[11]);
+        fclose(c->f);
+        return -1;
+    }
+
+    timebase[0] = rl32(&hdr[16]);
+    timebase[1] = rl32(&hdr[20]);
+    const unsigned duration = rl32(&hdr[24]);
+
+    uint8_t data[8];
+    c->broken = 0;
+    for (*num_frames = 0;; (*num_frames)++) {
+        if (fread(data, 4, 1, c->f) != 1) break; // EOF
+        size_t sz = rl32(data);
+        if (fread(data, 8, 1, c->f) != 1) break; // EOF
+        const uint64_t ts = rl64(data);
+        if (*num_frames && ts <= c->last_ts)
+            c->broken = 1;
+        c->last_ts = ts;
+        fseeko(c->f, sz, SEEK_CUR);
+    }
+
+    if (*num_frames == 0) { /* Reading bailed early */
+        fprintf(stderr, "No frames read from %s\n", file);
+        fclose(c->f);
+        return -1;
+    }
+
+    uint64_t fps_num = (uint64_t) timebase[0] * *num_frames;
+    uint64_t fps_den = (uint64_t) timebase[1] * duration;
+    if (fps_num && fps_den) { /* Reduce fraction */
+        uint64_t gcd = fps_num;
+        for (uint64_t a = fps_den, b; (b = a % gcd); a = gcd, gcd = b);
+        fps_num /= gcd;
+        fps_den /= gcd;
+
+        while ((fps_num | fps_den) > UINT_MAX) {
+            fps_num >>= 1;
+            fps_den >>= 1;
+        }
+    }
+    if (fps_num && fps_den) {
+        fps[0] = (unsigned) fps_num;
+        fps[1] = (unsigned) fps_den;
+    } else {
+        fps[0] = fps[1] = 0;
+    }
+    c->timebase = (double)timebase[0] / timebase[1];
+    c->step = duration / *num_frames;
+
+    fseeko(c->f, 32, SEEK_SET);
+    c->last_ts = 0;
+
+    return 0;
+}
+
+static inline int ivf_read_header(IvfInputContext *const c, ptrdiff_t *const sz,
+                                  int64_t *const off_, uint64_t *const ts)
+{
+    uint8_t data[8];
+    int64_t const off = ftello(c->f);
+    if (off_) *off_ = off;
+    if (fread(data, 4, 1, c->f) != 1) return -1; // EOF
+    *sz = rl32(data);
+    if (!c->broken) {
+        if (fread(data, 8, 1, c->f) != 1) return -1;
+        *ts = rl64(data);
+    } else {
+        if (fseeko(c->f, 8, SEEK_CUR)) return -1;
+        *ts = off > 32 ? c->last_ts + c->step : 0;
+    }
+    return 0;
+}
+
+static int ivf_read(IvfInputContext *const c, Dav1dData *const buf) {
+    uint8_t *ptr;
+    ptrdiff_t sz;
+    int64_t off;
+    uint64_t ts;
+    if (ivf_read_header(c, &sz, &off, &ts)) return -1;
+    if (!(ptr = dav1d_data_create(buf, sz))) return -1;
+    if (fread(ptr, sz, 1, c->f) != 1) {
+        fprintf(stderr, "Failed to read frame data: %s\n", strerror(errno));
+        dav1d_data_unref(buf);
+        return -1;
+    }
+    buf->m.offset = off;
+    buf->m.timestamp = ts;
+    c->last_ts = ts;
+    return 0;
+}
+
+static int ivf_seek(IvfInputContext *const c, const uint64_t pts) {
+    uint64_t cur;
+    const uint64_t ts = llround((pts * c->timebase) / 1000000000.0);
+    if (ts <= c->last_ts)
+        if (fseeko(c->f, 32, SEEK_SET)) goto error;
+    while (1) {
+        ptrdiff_t sz;
+        if (ivf_read_header(c, &sz, NULL, &cur)) goto error;
+        if (cur >= ts) break;
+        if (fseeko(c->f, sz, SEEK_CUR)) goto error;
+        c->last_ts = cur;
+    }
+    if (fseeko(c->f, -12, SEEK_CUR)) goto error;
+    return 0;
+error:
+    fprintf(stderr, "Failed to seek: %s\n", strerror(errno));
+    return -1;
+}
+
+static void ivf_close(IvfInputContext *const c) {
+    fclose(c->f);
+}
+
+const Demuxer ivf_demuxer = {
+    .priv_data_size = sizeof(IvfInputContext),
+    .name = "ivf",
+    .probe = ivf_probe,
+    .probe_sz = sizeof(probe_data),
+    .open = ivf_open,
+    .read = ivf_read,
+    .seek = ivf_seek,
+    .close = ivf_close,
+};
diff --git a/media/libdav1d/src/tools/input/parse.h b/media/libdav1d/src/tools/input/parse.h
new file mode 100644
index 0000000000..f39f80f2c6
--- /dev/null
+++ b/media/libdav1d/src/tools/input/parse.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * Copyright © 2019, James Almer 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_INPUT_PARSE_H
+#define DAV1D_INPUT_PARSE_H
+
+#include 
+
+#include "dav1d/headers.h"
+
+static int leb128(FILE *const f, size_t *const len) {
+    uint64_t val = 0;
+    unsigned i = 0, more;
+    do {
+        uint8_t v;
+        if (fread(&v, 1, 1, f) < 1)
+            return -1;
+        more = v & 0x80;
+        val |= ((uint64_t) (v & 0x7F)) << (i * 7);
+        i++;
+    } while (more && i < 8);
+    if (val > UINT_MAX || more)
+        return -1;
+    *len = (size_t) val;
+    return i;
+}
+
+// these functions are based on an implementation from FFmpeg, and relicensed
+// with author's permission
+
+static int leb(const uint8_t *ptr, int sz, size_t *const len) {
+    uint64_t val = 0;
+    unsigned i = 0, more;
+    do {
+        if (!sz--) return -1;
+        const int v = *ptr++;
+        more = v & 0x80;
+        val |= ((uint64_t) (v & 0x7F)) << (i * 7);
+        i++;
+    } while (more && i < 8);
+    if (val > UINT_MAX || more)
+        return -1;
+    *len = (size_t) val;
+    return i;
+}
+
+static inline int parse_obu_header(const uint8_t *buf, int buf_size,
+                                   size_t *const obu_size,
+                                   enum Dav1dObuType *const type,
+                                   const int allow_implicit_size)
+{
+    int ret, extension_flag, has_size_flag;
+
+    if (!buf_size)
+        return -1;
+    if (*buf & 0x80) // obu_forbidden_bit
+        return -1;
+
+    *type = (*buf & 0x78) >> 3;
+    extension_flag = (*buf & 0x4) >> 2;
+    has_size_flag  = (*buf & 0x2) >> 1;
+    // ignore obu_reserved_1bit
+    buf++;
+    buf_size--;
+
+    if (extension_flag) {
+        if (!buf_size)
+            return -1;
+        buf++;
+        buf_size--;
+        // ignore fields
+    }
+
+    if (has_size_flag) {
+        ret = leb(buf, buf_size, obu_size);
+        if (ret < 0)
+            return -1;
+        return (int) *obu_size + ret + 1 + extension_flag;
+    } else if (!allow_implicit_size)
+        return -1;
+
+    *obu_size = buf_size;
+    return buf_size + 1 + extension_flag;
+}
+
+#endif /* DAV1D_INPUT_PARSE_H */
diff --git a/media/libdav1d/src/tools/input/section5.c b/media/libdav1d/src/tools/input/section5.c
new file mode 100644
index 0000000000..99cb7615d6
--- /dev/null
+++ b/media/libdav1d/src/tools/input/section5.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright © 2019, VideoLAN and dav1d authors
+ * Copyright © 2019, Two Orioles, LLC
+ * Copyright © 2019, James Almer 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#if HAVE_SYS_TYPES_H
+#include 
+#endif
+
+#include "dav1d/headers.h"
+
+#include "input/demuxer.h"
+#include "input/parse.h"
+
+#define PROBE_SIZE 2048
+
+static int section5_probe(const uint8_t *data) {
+    int ret, cnt = 0;
+
+    // Check that the first OBU is a Temporal Delimiter.
+    size_t obu_size;
+    enum Dav1dObuType type;
+    ret = parse_obu_header(data + cnt, PROBE_SIZE - cnt,
+                           &obu_size, &type, 0);
+    if (ret < 0 || type != DAV1D_OBU_TD || obu_size > 0)
+        return 0;
+    cnt += ret;
+
+    // look for first frame and accompanying sequence header
+    int seq = 0;
+    while (cnt < PROBE_SIZE) {
+        ret = parse_obu_header(data + cnt, PROBE_SIZE - cnt,
+                               &obu_size, &type, 0);
+        if (ret < 0)
+            return 0;
+        cnt += ret;
+
+        switch (type) {
+        case DAV1D_OBU_SEQ_HDR:
+            seq = 1;
+            break;
+        case DAV1D_OBU_FRAME:
+        case DAV1D_OBU_FRAME_HDR:
+            return seq;
+        case DAV1D_OBU_TD:
+        case DAV1D_OBU_TILE_GRP:
+            return 0;
+        default:
+            break;
+        }
+    }
+
+    return seq;
+}
+
+typedef struct DemuxerPriv {
+    FILE *f;
+} Section5InputContext;
+
+static int section5_open(Section5InputContext *const c, const char *const file,
+                         unsigned fps[2], unsigned *const num_frames, unsigned timebase[2])
+{
+    if (!(c->f = fopen(file, "rb"))) {
+        fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+        return -1;
+    }
+
+    // TODO: Parse sequence header and read timing info if any.
+    fps[0] = 25;
+    fps[1] = 1;
+    timebase[0] = 25;
+    timebase[1] = 1;
+    *num_frames = 0;
+    for (;;) {
+        uint8_t byte[2];
+
+        if (fread(&byte[0], 1, 1, c->f) < 1)
+            break;
+        const enum Dav1dObuType obu_type = (byte[0] >> 3) & 0xf;
+        if (obu_type == DAV1D_OBU_TD)
+            (*num_frames)++;
+        const int has_length_field = byte[0] & 0x2;
+        if (!has_length_field)
+            return -1;
+        const int has_extension = byte[0] & 0x4;
+        if (has_extension && fread(&byte[1], 1, 1, c->f) < 1)
+            return -1;
+        size_t len;
+        const int res = leb128(c->f, &len);
+        if (res < 0)
+            return -1;
+        fseeko(c->f, len, SEEK_CUR); // skip packet
+    }
+    fseeko(c->f, 0, SEEK_SET);
+
+    return 0;
+}
+
+static int section5_read(Section5InputContext *const c, Dav1dData *const data) {
+    size_t total_bytes = 0;
+
+    for (int first = 1;; first = 0) {
+        uint8_t byte[2];
+
+        if (fread(&byte[0], 1, 1, c->f) < 1) {
+            if (!first && feof(c->f)) break;
+            return -1;
+        }
+        const enum Dav1dObuType obu_type = (byte[0] >> 3) & 0xf;
+        if (first) {
+            if (obu_type != DAV1D_OBU_TD)
+                return -1;
+        } else {
+            if (obu_type == DAV1D_OBU_TD) {
+                // include TD in next packet
+                fseeko(c->f, -1, SEEK_CUR);
+                break;
+            }
+        }
+        const int has_length_field = byte[0] & 0x2;
+        if (!has_length_field)
+            return -1;
+        const int has_extension = !!(byte[0] & 0x4);
+        if (has_extension && fread(&byte[1], 1, 1, c->f) < 1)
+            return -1;
+        size_t len;
+        const int res = leb128(c->f, &len);
+        if (res < 0)
+            return -1;
+        total_bytes += 1 + has_extension + res + len;
+        fseeko(c->f, len, SEEK_CUR); // skip packet, we'll read it below
+    }
+
+    fseeko(c->f, -(off_t)total_bytes, SEEK_CUR);
+    uint8_t *ptr = dav1d_data_create(data, total_bytes);
+    if (!ptr) return -1;
+    if (fread(ptr, total_bytes, 1, c->f) != 1) {
+        fprintf(stderr, "Failed to read frame data: %s\n", strerror(errno));
+        dav1d_data_unref(data);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void section5_close(Section5InputContext *const c) {
+    fclose(c->f);
+}
+
+const Demuxer section5_demuxer = {
+    .priv_data_size = sizeof(Section5InputContext),
+    .name = "section5",
+    .probe = section5_probe,
+    .probe_sz = PROBE_SIZE,
+    .open = section5_open,
+    .read = section5_read,
+    .seek = NULL,
+    .close = section5_close,
+};
diff --git a/media/libdav1d/src/tools/meson.build b/media/libdav1d/src/tools/meson.build
new file mode 100644
index 0000000000..2d22e2e622
--- /dev/null
+++ b/media/libdav1d/src/tools/meson.build
@@ -0,0 +1,121 @@
+# Copyright © 2018, VideoLAN and dav1d authors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Common source files used by tools and examples
+
+dav1d_input_sources = files(
+    'input/input.c',
+    'input/annexb.c',
+    'input/ivf.c',
+    'input/section5.c',
+)
+
+dav1d_input_objs = static_library('dav1d_input',
+    dav1d_input_sources,
+
+    include_directories : dav1d_inc_dirs,
+    install : false,
+    build_by_default : false,
+)
+
+# Leave subdir if tools are disabled
+if not get_option('enable_tools')
+    subdir_done()
+endif
+
+dav1d_output_sources = files(
+    'output/md5.c',
+    'output/null.c',
+    'output/output.c',
+    'output/y4m2.c',
+    'output/yuv.c',
+)
+
+# hacky check for xxhash.h to allow copying it to tools/output
+if not get_option('xxhash_muxer').disabled()
+    xxhash_include = '-I' + meson.current_source_dir() / 'output'
+    if cc.has_header_symbol('xxhash.h', 'XXH3_createState', args : xxhash_include)
+        dav1d_output_sources += 'output/xxhash.c'
+        xxh3_found = true
+    elif get_option('xxhash_muxer').enabled()
+        # manual error since 'required' kw arg in has_header_symbol() was only added in meson 0.50
+        error( 'Requested xxhash_muxer to be built, but no usable xxhash.h was found.')
+    endif
+endif
+
+dav1d_output_objs = static_library('dav1d_output',
+    dav1d_output_sources,
+
+    include_directories : dav1d_inc_dirs,
+    install : false,
+    build_by_default : false,
+)
+
+#
+# Build definition for the dav1d tools
+#
+
+# Configuratin data for cli_config.h
+cli_cdata = configuration_data()
+
+cli_cdata.set10('HAVE_XXHASH_H', get_variable('xxh3_found', false))
+
+cli_config_h_target = configure_file(output: 'cli_config.h', configuration: cli_cdata)
+
+# dav1d cli tool sources
+dav1d_sources = files(
+    'dav1d.c',
+    'dav1d_cli_parse.c',
+)
+
+if host_machine.system() == 'windows'
+    rc_file = configure_file(
+        input : 'dav1d.rc.in',
+        output : 'dav1d.rc',
+        configuration : rc_data
+    )
+
+    dav1d_rc_obj = winmod.compile_resources(rc_file,
+       depend_files : files('dav1d.manifest'),
+       include_directories : include_directories('.')
+    )
+else
+    dav1d_rc_obj = []
+endif
+
+dav1d = executable('dav1d',
+    dav1d_sources,
+    dav1d_rc_obj,
+    rev_target, cli_config_h_target,
+
+    link_with : [libdav1d, dav1d_input_objs, dav1d_output_objs],
+    include_directories : [dav1d_inc_dirs],
+    dependencies : [
+        getopt_dependency,
+        thread_dependency,
+        rt_dependency,
+        libm_dependency,
+        ],
+    install : true,
+)
diff --git a/media/libdav1d/src/tools/output/md5.c b/media/libdav1d/src/tools/output/md5.c
new file mode 100644
index 0000000000..cfad4f0bfb
--- /dev/null
+++ b/media/libdav1d/src/tools/output/md5.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "common/intops.h"
+
+#include "output/muxer.h"
+
+static const uint32_t k[64] = {
+    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+    0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+    0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+    0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+    0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+    0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+    0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+    0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+    0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
+};
+
+#if ENDIANNESS_BIG
+#define NE2LE_32(x) (((x & 0x00ff) << 24) |\
+                     ((x & 0xff00) <<  8) |\
+                     ((x >>  8) & 0xff00) |\
+                     ((x >> 24) & 0x00ff))
+
+#define NE2LE_64(x) (((x & 0x000000ff) << 56) |\
+                     ((x & 0x0000ff00) << 40) |\
+                     ((x & 0x00ff0000) << 24) |\
+                     ((x & 0xff000000) <<  8) |\
+                     ((x >>  8) & 0xff000000) |\
+                     ((x >> 24) & 0x00ff0000) |\
+                     ((x >> 40) & 0x0000ff00) |\
+                     ((x >> 56) & 0x000000ff))
+
+#else
+#define NE2LE_32(x) (x)
+#define NE2LE_64(x) (x)
+#endif
+
+typedef struct MuxerPriv {
+    uint32_t abcd[4];
+    union {
+        uint8_t data[64];
+        uint32_t data32[16];
+    };
+    uint64_t len;
+    FILE *f;
+#if ENDIANNESS_BIG
+    uint8_t *bswap;
+    int bswap_w;
+#endif
+} MD5Context;
+
+static int md5_open(MD5Context *const md5, const char *const file,
+                    const Dav1dPictureParameters *const p,
+                    const unsigned fps[2])
+{
+    if (!strcmp(file, "-")) {
+        md5->f = stdout;
+    } else if (!(md5->f = fopen(file, "wb"))) {
+        fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+        return -1;
+    }
+
+#if ENDIANNESS_BIG
+    md5->bswap = NULL;
+    md5->bswap_w = 0;
+#endif
+
+    md5->abcd[0] = 0x67452301;
+    md5->abcd[1] = 0xefcdab89;
+    md5->abcd[2] = 0x98badcfe;
+    md5->abcd[3] = 0x10325476;
+    md5->len = 0;
+
+    return 0;
+}
+
+static inline uint32_t leftrotate(const uint32_t x, const int c) {
+    return (x << c) | (x >> (32 - c));
+}
+
+#define F(i) do { \
+    a = b + leftrotate(a + ((b & c) | (~b & d)) + k[i + 0] + NE2LE_32(data[i + 0]),  7); \
+    d = a + leftrotate(d + ((a & b) | (~a & c)) + k[i + 1] + NE2LE_32(data[i + 1]), 12); \
+    c = d + leftrotate(c + ((d & a) | (~d & b)) + k[i + 2] + NE2LE_32(data[i + 2]), 17); \
+    b = c + leftrotate(b + ((c & d) | (~c & a)) + k[i + 3] + NE2LE_32(data[i + 3]), 22); \
+} while (0)
+
+#define G(i) do { \
+    a = b + leftrotate(a + ((d & b) | (~d & c)) + k[i + 0] + NE2LE_32(data[(i +  1) & 15]),  5); \
+    d = a + leftrotate(d + ((c & a) | (~c & b)) + k[i + 1] + NE2LE_32(data[(i +  6) & 15]),  9); \
+    c = d + leftrotate(c + ((b & d) | (~b & a)) + k[i + 2] + NE2LE_32(data[(i + 11) & 15]), 14); \
+    b = c + leftrotate(b + ((a & c) | (~a & d)) + k[i + 3] + NE2LE_32(data[(i +  0) & 15]), 20); \
+} while (0)
+
+#define H(i) do { \
+    a = b + leftrotate(a + (b ^ c ^ d) + k[i + 0] + NE2LE_32(data[( 5 - i) & 15]),  4); \
+    d = a + leftrotate(d + (a ^ b ^ c) + k[i + 1] + NE2LE_32(data[( 8 - i) & 15]), 11); \
+    c = d + leftrotate(c + (d ^ a ^ b) + k[i + 2] + NE2LE_32(data[(11 - i) & 15]), 16); \
+    b = c + leftrotate(b + (c ^ d ^ a) + k[i + 3] + NE2LE_32(data[(14 - i) & 15]), 23); \
+} while (0)
+
+#define I(i) do { \
+    a = b + leftrotate(a + (c ^ (b | ~d)) + k[i + 0] + NE2LE_32(data[( 0 - i) & 15]),  6); \
+    d = a + leftrotate(d + (b ^ (a | ~c)) + k[i + 1] + NE2LE_32(data[( 7 - i) & 15]), 10); \
+    c = d + leftrotate(c + (a ^ (d | ~b)) + k[i + 2] + NE2LE_32(data[(14 - i) & 15]), 15); \
+    b = c + leftrotate(b + (d ^ (c | ~a)) + k[i + 3] + NE2LE_32(data[( 5 - i) & 15]), 21); \
+} while (0)
+
+static void md5_body(MD5Context *const md5, const uint32_t *const data) {
+    uint32_t a = md5->abcd[0];
+    uint32_t b = md5->abcd[1];
+    uint32_t c = md5->abcd[2];
+    uint32_t d = md5->abcd[3];
+
+    F( 0); F( 4); F( 8); F(12);
+    G(16); G(20); G(24); G(28);
+    H(32); H(36); H(40); H(44);
+    I(48); I(52); I(56); I(60);
+
+    md5->abcd[0] += a;
+    md5->abcd[1] += b;
+    md5->abcd[2] += c;
+    md5->abcd[3] += d;
+}
+
+static void md5_update(MD5Context *const md5, const uint8_t *data, unsigned len) {
+    if (!len) return;
+
+    if (md5->len & 63) {
+        const unsigned tmp = umin(len, 64 - (md5->len & 63));
+
+        memcpy(&md5->data[md5->len & 63], data, tmp);
+        len -= tmp;
+        data += tmp;
+        md5->len += tmp;
+        if (!(md5->len & 63))
+            md5_body(md5, md5->data32);
+    }
+
+    while (len >= 64) {
+        memcpy(md5->data, data, 64);
+        md5_body(md5, md5->data32);
+        md5->len += 64;
+        data += 64;
+        len -= 64;
+    }
+
+    if (len) {
+        memcpy(md5->data, data, len);
+        md5->len += len;
+    }
+}
+
+static int md5_write(MD5Context *const md5, Dav1dPicture *const p) {
+    const int hbd = p->p.bpc > 8;
+    const int w = p->p.w, h = p->p.h;
+    uint8_t *yptr = p->data[0];
+
+#if ENDIANNESS_BIG
+    if (hbd && (!md5->bswap || md5->bswap_w < p->p.w)) {
+        free(md5->bswap);
+        md5->bswap_w = 0;
+        md5->bswap = malloc(p->p.w << 1);
+        if (!md5->bswap) return -1;
+        md5->bswap_w = p->p.w;
+    }
+#endif
+
+    for (int y = 0; y < h; y++) {
+#if ENDIANNESS_BIG
+        if (hbd) {
+            for (int x = 0; x < w; x++) {
+                md5->bswap[2 * x + 1] = yptr[2 * x];
+                md5->bswap[2 * x]     = yptr[2 * x + 1];
+            }
+            md5_update(md5, md5->bswap, w << hbd);
+        } else
+#endif
+        md5_update(md5, yptr, w << hbd);
+        yptr += p->stride[0];
+    }
+
+    if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
+        const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int cw = (w + ss_hor) >> ss_hor;
+        const int ch = (h + ss_ver) >> ss_ver;
+        for (int pl = 1; pl <= 2; pl++) {
+            uint8_t *uvptr = p->data[pl];
+
+            for (int y = 0; y < ch; y++) {
+#if ENDIANNESS_BIG
+                if (hbd) {
+                    for (int x = 0; x < cw; x++){
+                        md5->bswap[2 * x + 1] = uvptr[2 * x];
+                        md5->bswap[2 * x]     = uvptr[2 * x + 1];
+                    }
+                    md5_update(md5, md5->bswap, cw << hbd);
+                } else
+#endif
+                md5_update(md5, uvptr, cw << hbd);
+                uvptr += p->stride[1];
+            }
+        }
+    }
+
+    dav1d_picture_unref(p);
+
+    return 0;
+}
+
+static void md5_finish(MD5Context *const md5) {
+    static const uint8_t bit[2] = { 0x80, 0x00 };
+    const uint64_t len = NE2LE_64(md5->len << 3);
+
+    md5_update(md5, &bit[0], 1);
+    while ((md5->len & 63) != 56)
+        md5_update(md5, &bit[1], 1);
+    md5_update(md5, (const uint8_t *) &len, 8);
+}
+
+static void md5_close(MD5Context *const md5) {
+    md5_finish(md5);
+    for (int i = 0; i < 4; i++)
+        fprintf(md5->f, "%2.2x%2.2x%2.2x%2.2x",
+                md5->abcd[i] & 0xff,
+                (md5->abcd[i] >> 8) & 0xff,
+                (md5->abcd[i] >> 16) & 0xff,
+                md5->abcd[i] >> 24);
+    fprintf(md5->f, "\n");
+
+#if ENDIANNESS_BIG
+    free(md5->bswap);
+    md5->bswap_w = 0;
+#endif
+
+    if (md5->f != stdout)
+        fclose(md5->f);
+}
+
+static int md5_verify(MD5Context *const md5, const char *md5_str) {
+    md5_finish(md5);
+
+    if (strlen(md5_str) < 32)
+        return -1;
+
+    uint32_t abcd[4] = { 0 };
+    char t[3] = { 0 };
+    for (int i = 0; i < 4; i++) {
+        for (int j = 0; j < 32; j += 8) {
+            char *ignore;
+            memcpy(t, md5_str, 2);
+            md5_str += 2;
+            abcd[i] |= (uint32_t) strtoul(t, &ignore, 16) << j;
+        }
+    }
+
+#if ENDIANNESS_BIG
+    free(md5->bswap);
+    md5->bswap_w = 0;
+#endif
+
+    return !!memcmp(abcd, md5->abcd, sizeof(abcd));
+}
+
+const Muxer md5_muxer = {
+    .priv_data_size = sizeof(MD5Context),
+    .name = "md5",
+    .extension = "md5",
+    .write_header = md5_open,
+    .write_picture = md5_write,
+    .write_trailer = md5_close,
+    .verify = md5_verify,
+};
diff --git a/media/libdav1d/src/tools/output/muxer.h b/media/libdav1d/src/tools/output/muxer.h
new file mode 100644
index 0000000000..54b3f6aa13
--- /dev/null
+++ b/media/libdav1d/src/tools/output/muxer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_OUTPUT_MUXER_H
+#define DAV1D_OUTPUT_MUXER_H
+
+#include "picture.h"
+
+typedef struct MuxerPriv MuxerPriv;
+typedef struct Muxer {
+    int priv_data_size;
+    const char *name;
+    const char *extension;
+    int (*write_header)(MuxerPriv *ctx, const char *filename,
+                        const Dav1dPictureParameters *p, const unsigned fps[2]);
+    int (*write_picture)(MuxerPriv *ctx, Dav1dPicture *p);
+    void (*write_trailer)(MuxerPriv *ctx);
+    /**
+     * Verifies the muxed data (for example in the md5 muxer). Replaces write_trailer.
+     *
+     * @param  hash_string Muxer specific reference value.
+     *
+     * @return 0 on success.
+     */
+    int (*verify)(MuxerPriv *ctx, const char *hash_string);
+} Muxer;
+
+#endif /* DAV1D_OUTPUT_MUXER_H */
diff --git a/media/libdav1d/src/tools/output/null.c b/media/libdav1d/src/tools/output/null.c
new file mode 100644
index 0000000000..f8633f3e67
--- /dev/null
+++ b/media/libdav1d/src/tools/output/null.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "output/muxer.h"
+
+typedef struct MuxerPriv NullOutputContext;
+
+static int null_write(NullOutputContext *const c, Dav1dPicture *const p) {
+    dav1d_picture_unref(p);
+    return 0;
+}
+
+const Muxer null_muxer = {
+    .priv_data_size = 0,
+    .name = "null",
+    .extension = "null",
+    .write_picture = null_write,
+};
diff --git a/media/libdav1d/src/tools/output/output.c b/media/libdav1d/src/tools/output/output.c
new file mode 100644
index 0000000000..f8910d4894
--- /dev/null
+++ b/media/libdav1d/src/tools/output/output.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "cli_config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "common/attributes.h"
+#include "common/intops.h"
+
+#include "output/output.h"
+#include "output/muxer.h"
+
+struct MuxerContext {
+    MuxerPriv *data;
+    const Muxer *impl;
+    int one_file_per_frame;
+    unsigned fps[2];
+    const char *filename;
+    int framenum;
+    uint64_t priv_data[];
+};
+
+extern const Muxer null_muxer;
+extern const Muxer md5_muxer;
+extern const Muxer xxh3_muxer;
+extern const Muxer yuv_muxer;
+extern const Muxer y4m2_muxer;
+static const Muxer *muxers[] = {
+    &null_muxer,
+    &md5_muxer,
+#if HAVE_XXHASH_H
+    &xxh3_muxer,
+#endif
+    &yuv_muxer,
+    &y4m2_muxer,
+    NULL
+};
+
+static const char *find_extension(const char *const f) {
+    const size_t l = strlen(f);
+
+    if (l == 0) return NULL;
+
+    const char *const end = &f[l - 1], *step = end;
+    while ((*step >= 'a' && *step <= 'z') ||
+           (*step >= 'A' && *step <= 'Z') ||
+           (*step >= '0' && *step <= '9'))
+    {
+        step--;
+    }
+
+    return (step < end && step > f && *step == '.' && step[-1] != '/') ?
+           &step[1] : NULL;
+}
+
+int output_open(MuxerContext **const c_out,
+                const char *const name, const char *const filename,
+                const Dav1dPictureParameters *const p, const unsigned fps[2])
+{
+    const Muxer *impl;
+    MuxerContext *c;
+    unsigned i;
+    int res;
+    int name_offset = 0;
+
+    if (name) {
+        name_offset = 5 * !strncmp(name, "frame", 5);
+        for (i = 0; muxers[i]; i++) {
+            if (!strcmp(muxers[i]->name, &name[name_offset])) {
+                impl = muxers[i];
+                break;
+            }
+        }
+        if (!muxers[i]) {
+            fprintf(stderr, "Failed to find muxer named \"%s\"\n", name);
+            return DAV1D_ERR(ENOPROTOOPT);
+        }
+    } else if (!strcmp(filename, "/dev/null")) {
+        impl = muxers[0];
+    } else {
+        const char *const ext = find_extension(filename);
+        if (!ext) {
+            fprintf(stderr, "No extension found for file %s\n", filename);
+            return -1;
+        }
+        for (i = 0; muxers[i]; i++) {
+            if (!strcmp(muxers[i]->extension, ext)) {
+                impl = muxers[i];
+                break;
+            }
+        }
+        if (!muxers[i]) {
+            fprintf(stderr, "Failed to find muxer for extension \"%s\"\n", ext);
+            return DAV1D_ERR(ENOPROTOOPT);
+        }
+    }
+
+    if (!(c = malloc(offsetof(MuxerContext, priv_data) + impl->priv_data_size))) {
+        fprintf(stderr, "Failed to allocate memory\n");
+        return DAV1D_ERR(ENOMEM);
+    }
+    c->impl = impl;
+    c->data = (MuxerPriv *) c->priv_data;
+    int have_num_pattern = 0;
+    for (const char *ptr = filename ? strchr(filename, '%') : NULL;
+         !have_num_pattern && ptr; ptr = strchr(ptr, '%'))
+    {
+        ptr++; // skip '%'
+        while (*ptr >= '0' && *ptr <= '9')
+            ptr++; // skip length indicators
+        have_num_pattern = *ptr == 'n';
+    }
+    c->one_file_per_frame = name_offset || (!name && have_num_pattern);
+
+    if (c->one_file_per_frame) {
+        c->fps[0] = fps[0];
+        c->fps[1] = fps[1];
+        c->filename = filename;
+        c->framenum = 0;
+    } else if (impl->write_header &&
+               (res = impl->write_header(c->data, filename, p, fps)) < 0)
+    {
+        free(c);
+        return res;
+    }
+    *c_out = c;
+
+    return 0;
+}
+
+static void safe_strncat(char *const dst, const int dst_len,
+                         const char *const src, const int src_len)
+{
+    if (!src_len) return;
+    const int dst_fill = (int) strlen(dst);
+    assert(dst_fill < dst_len);
+    const int to_copy = imin(src_len, dst_len - dst_fill - 1);
+    if (!to_copy) return;
+    memcpy(dst + dst_fill, src, to_copy);
+    dst[dst_fill + to_copy] = 0;
+}
+
+static void assemble_field(char *const dst, const int dst_len,
+                           const char *const fmt, const int fmt_len,
+                           const int field)
+{
+    char fmt_copy[32];
+
+    assert(fmt[0] == '%');
+    fmt_copy[0] = '%';
+    if (fmt[1] >= '1' && fmt[1] <= '9') {
+        fmt_copy[1] = '0'; // pad with zeroes, not spaces
+        fmt_copy[2] = 0;
+    } else {
+        fmt_copy[1] = 0;
+    }
+    safe_strncat(fmt_copy, sizeof(fmt_copy), &fmt[1], fmt_len - 1);
+    safe_strncat(fmt_copy, sizeof(fmt_copy), "d", 1);
+
+    char tmp[32];
+    snprintf(tmp, sizeof(tmp), fmt_copy, field);
+
+    safe_strncat(dst, dst_len, tmp, (int) strlen(tmp));
+}
+
+static void assemble_filename(MuxerContext *const ctx, char *const filename,
+                              const int filename_size,
+                              const Dav1dPictureParameters *const p)
+{
+    filename[0] = 0;
+    const int framenum = ctx->framenum++;
+    assert(ctx->filename);
+    const char *ptr = ctx->filename, *iptr;
+    while ((iptr = strchr(ptr, '%'))) {
+        safe_strncat(filename, filename_size, ptr, (int) (iptr - ptr));
+        ptr = iptr;
+
+        const char *iiptr = &iptr[1]; // skip '%'
+        while (*iiptr >= '0' && *iiptr <= '9')
+            iiptr++; // skip length indicators
+
+        switch (*iiptr) {
+        case 'w':
+            assemble_field(filename, filename_size, ptr, (int) (iiptr - ptr), p->w);
+            break;
+        case 'h':
+            assemble_field(filename, filename_size, ptr, (int) (iiptr - ptr), p->h);
+            break;
+        case 'n':
+            assemble_field(filename, filename_size, ptr, (int) (iiptr - ptr), framenum);
+            break;
+        default:
+            safe_strncat(filename, filename_size, "%", 1);
+            ptr = &iptr[1];
+            continue;
+        }
+
+        ptr = &iiptr[1];
+    }
+    safe_strncat(filename, filename_size, ptr, (int) strlen(ptr));
+}
+
+int output_write(MuxerContext *const ctx, Dav1dPicture *const p) {
+    int res;
+
+    if (ctx->one_file_per_frame && ctx->impl->write_header) {
+        char filename[1024];
+        assemble_filename(ctx, filename, sizeof(filename), &p->p);
+        res = ctx->impl->write_header(ctx->data, filename, &p->p, ctx->fps);
+        if (res < 0)
+            return res;
+    }
+    if ((res = ctx->impl->write_picture(ctx->data, p)) < 0)
+        return res;
+    if (ctx->one_file_per_frame && ctx->impl->write_trailer)
+        ctx->impl->write_trailer(ctx->data);
+
+    return 0;
+}
+
+void output_close(MuxerContext *const ctx) {
+    if (!ctx->one_file_per_frame && ctx->impl->write_trailer)
+        ctx->impl->write_trailer(ctx->data);
+    free(ctx);
+}
+
+int output_verify(MuxerContext *const ctx, const char *const md5_str) {
+    const int res = ctx->impl->verify ?
+        ctx->impl->verify(ctx->data, md5_str) : 0;
+    free(ctx);
+    return res;
+}
diff --git a/media/libdav1d/src/tools/output/output.h b/media/libdav1d/src/tools/output/output.h
new file mode 100644
index 0000000000..6111c8682b
--- /dev/null
+++ b/media/libdav1d/src/tools/output/output.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV1D_OUTPUT_OUTPUT_H
+#define DAV1D_OUTPUT_OUTPUT_H
+
+#include "picture.h"
+
+typedef struct MuxerContext MuxerContext;
+
+int output_open(MuxerContext **c, const char *name, const char *filename,
+                const Dav1dPictureParameters *p, const unsigned fps[2]);
+int output_write(MuxerContext *ctx, Dav1dPicture *pic);
+void output_close(MuxerContext *ctx);
+/**
+ * Verifies the muxed data (for example in the md5 muxer). Replaces output_close.
+ *
+ * @param  hash_string Muxer specific reference value.
+ *
+ * @return 0 on success.
+ */
+int output_verify(MuxerContext *ctx, const char *hash_string);
+
+#endif /* DAV1D_OUTPUT_OUTPUT_H */
diff --git a/media/libdav1d/src/tools/output/xxhash.c b/media/libdav1d/src/tools/output/xxhash.c
new file mode 100644
index 0000000000..53e7f2b1e5
--- /dev/null
+++ b/media/libdav1d/src/tools/output/xxhash.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 2018-2021, VideoLAN and dav1d authors
+ * Copyright © 2018-2021, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#define XXH_INLINE_ALL
+#include "xxhash.h"
+
+#include "output/muxer.h"
+
+typedef struct MuxerPriv {
+    XXH3_state_t* state;
+    FILE *f;
+} xxh3Context;
+
+static int xxh3_open(xxh3Context *const xxh3, const char *const file,
+                    const Dav1dPictureParameters *const p,
+                    const unsigned fps[2])
+{
+    xxh3->state = XXH3_createState();
+    if (!xxh3->state) return DAV1D_ERR(ENOMEM);
+    XXH_errorcode err = XXH3_128bits_reset(xxh3->state);
+    if (err != XXH_OK) {
+        XXH3_freeState(xxh3->state);
+        xxh3->state = NULL;
+        return DAV1D_ERR(ENOMEM);
+    }
+
+    if (!strcmp(file, "-")) {
+        xxh3->f = stdout;
+    } else if (!(xxh3->f = fopen(file, "wb"))) {
+        XXH3_freeState(xxh3->state);
+        xxh3->state = NULL;
+        fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int xxh3_write(xxh3Context *const xxh3, Dav1dPicture *const p) {
+    const int hbd = p->p.bpc > 8;
+    const int w = p->p.w, h = p->p.h;
+    uint8_t *yptr = p->data[0];
+
+    for (int y = 0; y < h; y++) {
+        XXH3_128bits_update(xxh3->state, yptr, w << hbd);
+        yptr += p->stride[0];
+    }
+
+    if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
+        const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int cw = (w + ss_hor) >> ss_hor;
+        const int ch = (h + ss_ver) >> ss_ver;
+        for (int pl = 1; pl <= 2; pl++) {
+            uint8_t *uvptr = p->data[pl];
+
+            for (int y = 0; y < ch; y++) {
+                XXH3_128bits_update(xxh3->state, uvptr, cw << hbd);
+                uvptr += p->stride[1];
+            }
+        }
+    }
+
+    dav1d_picture_unref(p);
+
+    return 0;
+}
+
+static void xxh3_close(xxh3Context *const xxh3) {
+    XXH128_hash_t hash = XXH3_128bits_digest(xxh3->state);
+    XXH3_freeState(xxh3->state);
+    XXH128_canonical_t c;
+    XXH128_canonicalFromHash(&c, hash);
+
+    for (int i = 0; i < 16; i++)
+        fprintf(xxh3->f, "%2.2x", c.digest[i]);
+    fprintf(xxh3->f, "\n");
+
+    if (xxh3->f != stdout)
+        fclose(xxh3->f);
+}
+
+static int xxh3_verify(xxh3Context *const xxh3, const char * xxh3_str) {
+    XXH128_hash_t hash = XXH3_128bits_digest(xxh3->state);
+    XXH3_freeState(xxh3->state);
+
+    if (strlen(xxh3_str) < 32)
+        return -1;
+
+    XXH128_canonical_t c;
+    char t[3] = { 0 };
+    for (int i = 0; i < 16; i++) {
+        char *ignore;
+        memcpy(t, xxh3_str, 2);
+        xxh3_str += 2;
+        c.digest[i] = (unsigned char) strtoul(t, &ignore, 16);
+    }
+    XXH128_hash_t verify = XXH128_hashFromCanonical(&c);
+
+    return !XXH128_isEqual(hash, verify);
+}
+
+const Muxer xxh3_muxer = {
+    .priv_data_size = sizeof(xxh3Context),
+    .name = "xxh3",
+    .extension = "xxh3",
+    .write_header = xxh3_open,
+    .write_picture = xxh3_write,
+    .write_trailer = xxh3_close,
+    .verify = xxh3_verify,
+};
diff --git a/media/libdav1d/src/tools/output/y4m2.c b/media/libdav1d/src/tools/output/y4m2.c
new file mode 100644
index 0000000000..40411d15ab
--- /dev/null
+++ b/media/libdav1d/src/tools/output/y4m2.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "output/muxer.h"
+
+typedef struct MuxerPriv {
+    FILE *f;
+    int first;
+    unsigned fps[2];
+} Y4m2OutputContext;
+
+static int y4m2_open(Y4m2OutputContext *const c, const char *const file,
+                     const Dav1dPictureParameters *p, const unsigned fps[2])
+{
+    if (!strcmp(file, "-")) {
+        c->f = stdout;
+    } else if (!(c->f = fopen(file, "wb"))) {
+        fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+        return -1;
+    }
+
+    c->first = 1;
+    c->fps[0] = fps[0];
+    c->fps[1] = fps[1];
+
+    return 0;
+}
+
+static int write_header(Y4m2OutputContext *const c, const Dav1dPicture *const p) {
+    static const char *const ss_names[][3] = {
+        [DAV1D_PIXEL_LAYOUT_I400] = { "mono", "mono10", "mono12" },
+        [DAV1D_PIXEL_LAYOUT_I420] = { NULL,   "420p10", "420p12" },
+        [DAV1D_PIXEL_LAYOUT_I422] = { "422",  "422p10", "422p12" },
+        [DAV1D_PIXEL_LAYOUT_I444] = { "444",  "444p10", "444p12" }
+    };
+
+    static const char *const chr_names_8bpc_i420[] = {
+        [DAV1D_CHR_UNKNOWN] = "420jpeg",
+        [DAV1D_CHR_VERTICAL] = "420mpeg2",
+        [DAV1D_CHR_COLOCATED] = "420"
+    };
+
+    const char *const ss_name =
+        p->p.layout == DAV1D_PIXEL_LAYOUT_I420 && p->p.bpc == 8 ?
+        chr_names_8bpc_i420[p->seq_hdr->chr > 2 ? DAV1D_CHR_UNKNOWN : p->seq_hdr->chr] :
+        ss_names[p->p.layout][p->seq_hdr->hbd];
+
+    const unsigned fw = p->p.w;
+    const unsigned fh = p->p.h;
+    uint64_t aw = (uint64_t)fh * p->frame_hdr->render_width;
+    uint64_t ah = (uint64_t)fw * p->frame_hdr->render_height;
+    uint64_t gcd = ah;
+    for (uint64_t a = aw, b; (b = a % gcd); a = gcd, gcd = b);
+    aw /= gcd;
+    ah /= gcd;
+
+    fprintf(c->f, "YUV4MPEG2 W%u H%u F%u:%u Ip A%"PRIu64":%"PRIu64" C%s\n",
+            fw, fh, c->fps[0], c->fps[1], aw, ah, ss_name);
+
+    return 0;
+}
+
+static int y4m2_write(Y4m2OutputContext *const c, Dav1dPicture *const p) {
+    if (c->first) {
+        c->first = 0;
+        const int res = write_header(c, p);
+        if (res < 0) return res;
+    }
+    fprintf(c->f, "FRAME\n");
+
+    uint8_t *ptr;
+    const int hbd = p->p.bpc > 8;
+
+    ptr = p->data[0];
+    for (int y = 0; y < p->p.h; y++) {
+        if (fwrite(ptr, p->p.w << hbd, 1, c->f) != 1)
+            goto error;
+        ptr += p->stride[0];
+    }
+
+    if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
+        // u/v
+        const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int cw = (p->p.w + ss_hor) >> ss_hor;
+        const int ch = (p->p.h + ss_ver) >> ss_ver;
+        for (int pl = 1; pl <= 2; pl++) {
+            ptr = p->data[pl];
+            for (int y = 0; y < ch; y++) {
+                if (fwrite(ptr, cw << hbd, 1, c->f) != 1)
+                    goto error;
+                ptr += p->stride[1];
+            }
+        }
+    }
+
+    dav1d_picture_unref(p);
+    return 0;
+
+error:
+    dav1d_picture_unref(p);
+    fprintf(stderr, "Failed to write frame data: %s\n", strerror(errno));
+    return -1;
+}
+
+static void y4m2_close(Y4m2OutputContext *const c) {
+    if (c->f != stdout)
+        fclose(c->f);
+}
+
+const Muxer y4m2_muxer = {
+    .priv_data_size = sizeof(Y4m2OutputContext),
+    .name = "yuv4mpeg2",
+    .extension = "y4m",
+    .write_header = y4m2_open,
+    .write_picture = y4m2_write,
+    .write_trailer = y4m2_close,
+};
diff --git a/media/libdav1d/src/tools/output/yuv.c b/media/libdav1d/src/tools/output/yuv.c
new file mode 100644
index 0000000000..e0c0ec47d9
--- /dev/null
+++ b/media/libdav1d/src/tools/output/yuv.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "output/muxer.h"
+
+typedef struct MuxerPriv {
+    FILE *f;
+} YuvOutputContext;
+
+static int yuv_open(YuvOutputContext *const c, const char *const file,
+                    const Dav1dPictureParameters *const p,
+                    const unsigned fps[2])
+{
+    if (!strcmp(file, "-")) {
+        c->f = stdout;
+    } else if (!(c->f = fopen(file, "wb"))) {
+        fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int yuv_write(YuvOutputContext *const c, Dav1dPicture *const p) {
+    uint8_t *ptr;
+    const int hbd = p->p.bpc > 8;
+
+    ptr = p->data[0];
+    for (int y = 0; y < p->p.h; y++) {
+        if (fwrite(ptr, p->p.w << hbd, 1, c->f) != 1)
+            goto error;
+        ptr += p->stride[0];
+    }
+
+    if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
+        // u/v
+        const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+        const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
+        const int cw = (p->p.w + ss_hor) >> ss_hor;
+        const int ch = (p->p.h + ss_ver) >> ss_ver;
+        for (int pl = 1; pl <= 2; pl++) {
+            ptr = p->data[pl];
+            for (int y = 0; y < ch; y++) {
+                if (fwrite(ptr, cw << hbd, 1, c->f) != 1)
+                    goto error;
+                ptr += p->stride[1];
+            }
+        }
+    }
+
+    dav1d_picture_unref(p);
+    return 0;
+
+error:
+    dav1d_picture_unref(p);
+    fprintf(stderr, "Failed to write frame data: %s\n", strerror(errno));
+    return -1;
+}
+
+static void yuv_close(YuvOutputContext *const c) {
+    if (c->f != stdout)
+        fclose(c->f);
+}
+
+const Muxer yuv_muxer = {
+    .priv_data_size = sizeof(YuvOutputContext),
+    .name = "yuv",
+    .extension = "yuv",
+    .write_header = yuv_open,
+    .write_picture = yuv_write,
+    .write_trailer = yuv_close,
+};
diff --git a/media/libdav1d/x86/moz.build b/media/libdav1d/x86/moz.build
new file mode 100644
index 0000000000..05aec40331
--- /dev/null
+++ b/media/libdav1d/x86/moz.build
@@ -0,0 +1,79 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+SOURCES += [
+    '/media/libdav1d/src/src/x86/cdef16_avx2.asm',
+    '/media/libdav1d/src/src/x86/cdef16_avx512.asm',
+    '/media/libdav1d/src/src/x86/cdef16_sse.asm',
+    '/media/libdav1d/src/src/x86/cdef_avx2.asm',
+    '/media/libdav1d/src/src/x86/cdef_avx512.asm',
+    '/media/libdav1d/src/src/x86/cdef_sse.asm',
+    '/media/libdav1d/src/src/x86/cpu.c',
+    '/media/libdav1d/src/src/x86/cpuid.asm',
+    '/media/libdav1d/src/src/x86/filmgrain16_avx2.asm',
+    '/media/libdav1d/src/src/x86/filmgrain16_avx512.asm',
+    '/media/libdav1d/src/src/x86/filmgrain16_sse.asm',
+    '/media/libdav1d/src/src/x86/filmgrain_avx2.asm',
+    '/media/libdav1d/src/src/x86/filmgrain_avx512.asm',
+    '/media/libdav1d/src/src/x86/filmgrain_sse.asm',
+    '/media/libdav1d/src/src/x86/ipred16_avx2.asm',
+    '/media/libdav1d/src/src/x86/ipred16_avx512.asm',
+    '/media/libdav1d/src/src/x86/ipred16_sse.asm',
+    '/media/libdav1d/src/src/x86/ipred_avx2.asm',
+    '/media/libdav1d/src/src/x86/ipred_avx512.asm',
+    '/media/libdav1d/src/src/x86/ipred_sse.asm',
+    '/media/libdav1d/src/src/x86/itx16_avx2.asm',
+    '/media/libdav1d/src/src/x86/itx16_avx512.asm',
+    '/media/libdav1d/src/src/x86/itx16_sse.asm',
+    '/media/libdav1d/src/src/x86/itx_avx2.asm',
+    '/media/libdav1d/src/src/x86/itx_avx512.asm',
+    '/media/libdav1d/src/src/x86/itx_sse.asm',
+    '/media/libdav1d/src/src/x86/loopfilter16_avx2.asm',
+    '/media/libdav1d/src/src/x86/loopfilter16_avx512.asm',
+    '/media/libdav1d/src/src/x86/loopfilter16_sse.asm',
+    '/media/libdav1d/src/src/x86/loopfilter_avx2.asm',
+    '/media/libdav1d/src/src/x86/loopfilter_avx512.asm',
+    '/media/libdav1d/src/src/x86/loopfilter_sse.asm',
+    '/media/libdav1d/src/src/x86/looprestoration16_avx2.asm',
+    '/media/libdav1d/src/src/x86/looprestoration16_avx512.asm',
+    '/media/libdav1d/src/src/x86/looprestoration16_sse.asm',
+    '/media/libdav1d/src/src/x86/looprestoration_avx2.asm',
+    '/media/libdav1d/src/src/x86/looprestoration_avx512.asm',
+    '/media/libdav1d/src/src/x86/looprestoration_sse.asm',
+    '/media/libdav1d/src/src/x86/mc16_avx2.asm',
+    '/media/libdav1d/src/src/x86/mc16_avx512.asm',
+    '/media/libdav1d/src/src/x86/mc16_sse.asm',
+    '/media/libdav1d/src/src/x86/mc_avx2.asm',
+    '/media/libdav1d/src/src/x86/mc_avx512.asm',
+    '/media/libdav1d/src/src/x86/mc_sse.asm',
+    '/media/libdav1d/src/src/x86/msac.asm',
+    '/media/libdav1d/src/src/x86/pal.asm',
+    '/media/libdav1d/src/src/x86/refmvs.asm',
+]
+
+USE_NASM = True
+
+ASFLAGS += [
+    '-I%s/media/libdav1d/config/' % TOPSRCDIR,
+    '-I%s/media/libdav1d/src/src/' % TOPSRCDIR,
+]
+
+LOCAL_INCLUDES += [
+    '/media/libdav1d/config',
+    '/media/libdav1d/src',
+    '/media/libdav1d/src/include',
+    '/media/libdav1d/src/include/dav1d',
+]
+
+FINAL_LIBRARY = 'gkmedias'
+
+ALLOW_COMPILER_WARNINGS = True
+
+if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
+    CFLAGS += [
+        '-Wno-sign-compare',
+        '-Wno-unused-function',
+        '-Wno-unused-parameter',
+    ]
diff --git a/media/libsoundtouch/src/FIRFilter.cpp b/media/libsoundtouch/src/FIRFilter.cpp
index 201395bd51..604ec951c6 100644
--- a/media/libsoundtouch/src/FIRFilter.cpp
+++ b/media/libsoundtouch/src/FIRFilter.cpp
@@ -86,8 +86,11 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui
     assert((length != 0) && (length == ilength) && (src != NULL) && (dest != NULL) && (filterCoeffs != NULL));
 
     end = 2 * (numSamples - ilength);
+    const SAMPLETYPE *coeffsStereo = filterCoeffsStereo;
 
-    #pragma omp parallel for
+#if defined(_OPENMP)
+    #pragma omp parallel for default(none) shared(src, dest, end, ilength, coeffsStereo) private(j) schedule(static)
+#endif
     for (j = 0; j < end; j += 2) 
     {
         const SAMPLETYPE *ptr;
@@ -98,8 +101,8 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui
 
         for (int i = 0; i < ilength; i ++)
         {
-            suml += ptr[2 * i] * filterCoeffsStereo[2 * i];
-            sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1];
+            suml += ptr[2 * i] * coeffsStereo[2 * i];
+            sumr += ptr[2 * i + 1] * coeffsStereo[2 * i + 1];
         }
 
 #ifdef SOUNDTOUCH_INTEGER_SAMPLES
@@ -133,7 +136,10 @@ uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint
     assert(ilength != 0);
 
     end = numSamples - ilength;
-    #pragma omp parallel for
+    const SAMPLETYPE *coeffs = filterCoeffs;
+#if defined(_OPENMP)
+    #pragma omp parallel for default(none) shared(src, dest, end, ilength, coeffs) private(j) schedule(static)
+#endif
     for (j = 0; j < end; j ++)
     {
         const SAMPLETYPE *pSrc = src + j;
@@ -143,7 +149,7 @@ uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint
         sum = 0;
         for (i = 0; i < ilength; i ++)
         {
-            sum += pSrc[i] * filterCoeffs[i];
+            sum += pSrc[i] * coeffs[i];
         }
 #ifdef SOUNDTOUCH_INTEGER_SAMPLES
         sum >>= resultDivFactor;
@@ -176,8 +182,11 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin
     int ilength = length & -8;
 
     end = numChannels * (numSamples - ilength);
+    const SAMPLETYPE *coeffs = filterCoeffs;
 
-    #pragma omp parallel for
+#if defined(_OPENMP)
+    #pragma omp parallel for default(none) shared(src, dest, end, ilength, numChannels, coeffs) private(j) schedule(static)
+#endif
     for (j = 0; j < end; j += numChannels)
     {
         const SAMPLETYPE *ptr;
@@ -194,7 +203,7 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin
 
         for (i = 0; i < ilength; i ++)
         {
-            SAMPLETYPE coef=filterCoeffs[i];
+            SAMPLETYPE coef=coeffs[i];
             for (c = 0; c < numChannels; c ++)
             {
                 sums[c] += ptr[0] * coef;
diff --git a/media/libsoundtouch/src/TDStretch.cpp b/media/libsoundtouch/src/TDStretch.cpp
index 709e979d1d..ef8b8a2d1d 100644
--- a/media/libsoundtouch/src/TDStretch.cpp
+++ b/media/libsoundtouch/src/TDStretch.cpp
@@ -292,10 +292,10 @@ inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, ui
 // The best position is determined as the position where the two overlapped
 // sample sequences are 'most alike', in terms of the highest cross-correlation
 // value over the overlapping period
-int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) 
+int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
 {
-    int bestOffs;
     double bestCorr;
+    int bestOffs;
     int i;
     double norm;
 
@@ -307,33 +307,38 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
     bestCorr = calcCrossCorr(refPos, pMidBuffer, norm);
     bestCorr = (bestCorr + 0.1) * 0.75;
 
-    #pragma omp parallel for
-    for (i = 1; i < seekLength; i ++)
+    const int seekLen = seekLength;
+    const int nChannels = channels;
+    const SAMPLETYPE *midBuffer = pMidBuffer;
+
+#if defined(_OPENMP)
+    #pragma omp parallel for default(none) \
+        shared(refPos, bestCorr, bestOffs, midBuffer, seekLen, nChannels) \
+        private(i) schedule(static)
+#endif
+    for (i = 1; i < seekLen; i ++)
     {
         double corr;
+        double localNorm;
+
         // Calculates correlation value for the mixing position corresponding to 'i'
 #if defined(_OPENMP) || defined(ST_SIMD_AVOID_UNALIGNED)
-        // in parallel OpenMP mode, can't use norm accumulator version as parallel executor won't
-        // iterate the loop in sequential order
-        // in SIMD mode, avoid accumulator version to allow avoiding unaligned positions
-        corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm);
+        corr = calcCrossCorr(refPos + nChannels * i, midBuffer, localNorm);
 #else
-        // In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same
-        // as "calcCrossCorr", but saves time by reusing & updating previously stored 
-        // "norm" value
-        corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm);
+        corr = calcCrossCorrAccumulate(refPos + nChannels * i, midBuffer, norm);
 #endif
+
         // heuristic rule to slightly favour values close to mid of the range
-        double tmp = (double)(2 * i - seekLength) / (double)seekLength;
+        double tmp = (double)(2 * i - seekLen) / (double)seekLen;
         corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
 
         // Checks for the highest correlation value
         if (corr > bestCorr) 
         {
             // For optimal performance, enter critical section only in case that best value found.
-            // in such case repeat 'if' condition as it's possible that parallel execution may have
-            // updated the bestCorr value in the mean time
-            #pragma omp critical
+#if defined(_OPENMP)
+            #pragma omp critical(soundtouch_bestcorr)
+#endif
             if (corr > bestCorr)
             {
                 bestCorr = corr;
@@ -346,7 +351,7 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
     adaptNormalizer();
 #endif
 
-    // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+    // clear cross correlation routine state if necessary
     clearCrossCorrState();
 
     return bestOffs;
@@ -910,7 +915,9 @@ double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, do
     if (lnorm > maxnorm)
     {
         // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode
-        #pragma omp critical
+    #if defined(_OPENMP)
+        #pragma omp critical(soundtouch_maxnorm)
+    #endif
         if (lnorm > maxnorm)
         {
             maxnorm = lnorm;
diff --git a/media/libsoundtouch/src/mmx_optimized.cpp b/media/libsoundtouch/src/mmx_optimized.cpp
index 0bc7fe86f7..6ce2f635a2 100644
--- a/media/libsoundtouch/src/mmx_optimized.cpp
+++ b/media/libsoundtouch/src/mmx_optimized.cpp
@@ -119,7 +119,9 @@ double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &d
     if (norm > (long)maxnorm)
     {
         // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode
-        #pragma omp critical
+    #if defined(_OPENMP)
+        #pragma omp critical(soundtouch_maxnorm)
+    #endif
         if (norm > (long)maxnorm)
         {
             maxnorm = norm;
diff --git a/media/libsoundtouch/src/moz.build b/media/libsoundtouch/src/moz.build
index dabb2754e1..b24e88eb0b 100644
--- a/media/libsoundtouch/src/moz.build
+++ b/media/libsoundtouch/src/moz.build
@@ -41,6 +41,13 @@ else:
     # Windows need alloca renamed to _alloca
     DEFINES['alloca'] = '_alloca'
 
+# Use standardized OpenMP parallelization for SoundTouch hot loops.
+if CONFIG['CC_TYPE'] == 'gcc':
+    CXXFLAGS += ['-fopenmp']
+    OS_LIBS += ['gomp']
+    if CONFIG['OS_ARCH'] == 'WINNT':
+        OS_LIBS += ['dl']
+
 DEFINES['BUILDING_SOUNDTOUCH'] = 1
 
 # We allow warnings for third-party code that can be updated from upstream.
diff --git a/media/libsoundtouch/src/sse_optimized.cpp b/media/libsoundtouch/src/sse_optimized.cpp
index 9c16ea8f89..1ca274fe7b 100644
--- a/media/libsoundtouch/src/sse_optimized.cpp
+++ b/media/libsoundtouch/src/sse_optimized.cpp
@@ -252,7 +252,13 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n
     assert(((ulongptr)filterCoeffsAlign) % 16 == 0);
 
     // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'
-    #pragma omp parallel for
+const uint filterLength = length;
+    const float *coeffsAlign = filterCoeffsAlign;
+#if defined(_OPENMP)
+    #pragma omp parallel for default(none) \
+        shared(source, dest, count, coeffsAlign, filterLength) \
+        private(j) schedule(static)
+#endif
     for (j = 0; j < count; j += 2)
     {
         const float *pSrc;
@@ -263,11 +269,11 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n
 
         pSrc = (const float*)source + j * 2;      // source audio data
         pDest = dest + j * 2;                     // destination audio data
-        pFil = (const __m128*)filterCoeffsAlign;  // filter coefficients. NOTE: Assumes coefficients 
-                                                  // are aligned to 16-byte boundary
+        pFil = (const __m128*)coeffsAlign;
+
         sum1 = sum2 = _mm_setzero_ps();
 
-        for (i = 0; i < length / 8; i ++) 
+        for (i = 0; i < filterLength / 8; i ++) 
         {
             // Unroll loop for efficiency & calculate filter for 2*2 stereo samples 
             // at each pass
diff --git a/mobile/ios/.gitattributes b/mobile/ios/.gitattributes
new file mode 100644
index 0000000000..f301122286
--- /dev/null
+++ b/mobile/ios/.gitattributes
@@ -0,0 +1,3 @@
+# Don't include third party files in the Github language stats!
+ThirdParty/* linguist-vendored=true
+FxA/* linguist-vendored=true
\ No newline at end of file
diff --git a/mobile/ios/.gitignore b/mobile/ios/.gitignore
new file mode 100644
index 0000000000..ad0f13f34d
--- /dev/null
+++ b/mobile/ios/.gitignore
@@ -0,0 +1,77 @@
+# Xcode
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+*.xcuserstate
+*.xcscmblueprint
+
+/fastlane/scripts/upload.sh
+/fastlane/README.md
+/firefox-ios-l10n
+# fastlane temporary profiling data
+/fastlane/report.xml
+# deliver temporary error output
+/fastlane/Error*.png
+# deliver temporary preview output
+/fastlane/Preview.html
+# snapshot generated screenshots
+/fastlane/screenshots
+/fastlane/screenshots/*/*-portrait.png
+/fastlane/screenshots/*/*-landscape.png
+/fastlane/screenshots/screenshots.html
+# frameit generated screenshots
+/fastlane/screenshots/*/*-portrait_framed.png
+/fastlane/screenshots/*/*-landscape_framed.png
+# folders for storing builds and prov profiles
+/builds
+/provisioning-profiles
+/assets
+#build tools
+/fastlane/Appfile
+/fastlane/Snapfile
+/fastlane/SnapshotHelper.swift
+/fastlane/frames
+/fastlane/scripts
+/fastlane/templates
+
+#python environment
+python-env/
+
+# OS X
+.DS_Store
+
+# Vim
+*~
+.*.sw*
+
+# IDEA
+.idea
+
+Carthage/
+
+ThirdParty/google-breakpad
+
+# Saved Sync credentials for tests.
+signedInUser.json
+
+# Generated config file
+MozBuildID.xcconfig
+
+# Python.
+*.pyc
+
+# SQLite
+*.db-shm
+*.db-wal
diff --git a/mobile/ios/.swiftlint.yml b/mobile/ios/.swiftlint.yml
new file mode 100644
index 0000000000..d14570aae3
--- /dev/null
+++ b/mobile/ios/.swiftlint.yml
@@ -0,0 +1,92 @@
+disabled_rules: # rule identifiers to exclude from running
+  - variable_name
+  - todo
+  - trailing_newline
+  - type_name
+  - function_body_length
+  - missing_docs
+  - valid_docs
+  - cyclomatic_complexity
+  - type_body_length
+  - function_parameter_count
+  - file_length
+  - mark
+  - unused_closure_parameter
+  - empty_parentheses_with_trailing_closure
+  - redundant_string_enum_value
+  - large_tuple
+  - class_delegate_protocol
+  - syntactic_sugar
+  - implicit_getter
+  - weak_delegate
+  - shorthand_operator
+  - trailing_comma
+  - unused_optional_binding
+  - private_over_fileprivate
+  - empty_enum_arguments
+  - discarded_notification_center_observer
+  - block_based_kvo
+  - nesting
+  - is_disjoint
+  - multiple_closures_with_trailing_closure
+  - fallthrough
+  - switch_case_alignment
+  - trailing_whitespace
+  - leading_whitespace
+  - operator_whitespace
+  - legacy_cggeometry_functions
+  - unneeded_break_in_switch
+  - closure_parameter_position
+opt_in_rules: # some rules are only opt-in
+  - closing_brace
+  - opening_brace
+  - return_arrow_whitespace
+  - trailing_semicolon
+  - statement_position
+  - explicit_init
+  - shorthand_operator
+  - file_header
+  # Find all the available rules by running:
+  # swiftlint rules
+included: # paths to include during linting. `--path` is ignored if present.
+excluded: # paths to ignore during linting. Takes precedence over `included`.
+  - Carthage
+  - Pods
+  - Source/ExcludedFolder
+  - Source/ExcludedFile.swift
+  - ThirdParty
+  - FxA
+  - FxAClient
+  - build
+  - UITests/EarlGrey.swift
+  - Storage/ThirdParty/SwiftData.swift
+  - UITests/
+  - XCUITests/
+  - SyncTests/
+  - StorageTests/
+  - ReadingListTests/
+  - ClientTests/
+  - AccountTests/
+  - fastlane/
+  - SharedTests/
+  - Client/Assets/Search/get_supported_locales.swift
+
+# configurable rules can be customized from this configuration file
+# binary rules can set their severity level
+trailing_semicolon: error
+empty_count: error
+closing_brace: error
+opening_brace: error
+return_arrow_whitespace: error
+statement_position: error
+colon: error
+comma: error
+force_try: warning
+force_cast: warning
+
+
+file_header:
+  required_string: "/* This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/. */"
+line_length: 1000
+
+reporter: "json" # reporter type (xcode, json, csv, checkstyle)
diff --git a/mobile/ios/AUTHORS b/mobile/ios/AUTHORS
new file mode 100644
index 0000000000..99c62e8631
--- /dev/null
+++ b/mobile/ios/AUTHORS
@@ -0,0 +1,25 @@
+This is an (incomplete) list of people who have contributed to the
+codebase which lives in this repository. If you make a contribution
+here, you may add your name and, optionally, email address in the
+appropriate place.
+
+For a full list of the people who are credited with making a
+contribution to Mozilla, see http://www.mozilla.org/credits/.
+
+Boris Dušek
+Brian Nicholson
+Bryan Munar
+Emily Toop
+Farhan Patel
+Jacob White
+James Hugman
+Le Van Nghia
+Maurya Talisetti
+Nick Alexander
+Richard Newman
+Sachin Palewar
+Sahil Wasan
+Stefan Arentz
+Steph Leroux
+Thomas Bonnin
+Wes Johnston
diff --git a/mobile/ios/Account/Account-Bridging-Header.h b/mobile/ios/Account/Account-Bridging-Header.h
new file mode 100644
index 0000000000..4131450754
--- /dev/null
+++ b/mobile/ios/Account/Account-Bridging-Header.h
@@ -0,0 +1,7 @@
+#ifndef Client_Account_Bridging_Header_h
+#define Client_Account_Bridging_Header_h
+
+#import 
+#import "Shared-Bridging-Header.h"
+
+#endif
diff --git a/mobile/ios/Account/FirefoxAccount.swift b/mobile/ios/Account/FirefoxAccount.swift
new file mode 100644
index 0000000000..e065501a90
--- /dev/null
+++ b/mobile/ios/Account/FirefoxAccount.swift
@@ -0,0 +1,425 @@
+/* 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/. */
+
+import Foundation
+import Shared
+import XCGLogger
+import Deferred
+import SwiftyJSON
+import FxA
+import SDWebImage
+
+private let log = Logger.syncLogger
+
+// The version of the account schema we persist.
+let AccountSchemaVersion = 2
+
+/// A FirefoxAccount mediates access to identity attached services.
+///
+/// All data maintained as part of the account or its state should be
+/// considered sensitive and stored appropriately.  Usually, that means
+/// storing account data in the iOS keychain.
+///
+/// Non-sensitive but persistent data should be maintained outside of
+/// the account itself.
+open class FirefoxAccount {
+    /// The email address identifying the account.  A Firefox Account is uniquely identified on a particular server
+    /// (auth endpoint) by its email address.
+    open let email: String
+
+    /// The auth endpoint user identifier identifying the account.  A Firefox Account is uniquely identified on a
+    /// particular server (auth endpoint) by its assigned uid.
+    open let uid: String
+
+    open var fxaProfile: FxAProfile?
+    
+    open var deviceRegistration: FxADeviceRegistration?
+
+    open var configuration: FirefoxAccountConfiguration
+
+    open var pushRegistration: PushRegistration?
+
+    fileprivate let stateCache: KeychainCache
+    open var syncAuthState: SyncAuthState! // We can't give a reference to self if this is a let.
+
+    // To prevent advance() consumers racing, we maintain a shared advance() deferred (`advanceDeferred`).  If an
+    // advance() is in progress, the shared deferred will be returned.  (Multiple consumers can chain off a single
+    // deferred safely.)  If no advance() is in progress, a new shared deferred will be scheduled and returned.  To
+    // prevent data races against the shared deferred, advance() locks accesses to `advanceDeferred` using
+    // `advanceLock`.
+    fileprivate var advanceLock = OSSpinLock()
+    fileprivate var advanceDeferred: Deferred?
+
+    open var actionNeeded: FxAActionNeeded {
+        return stateCache.value!.actionNeeded
+    }
+
+    public convenience init(configuration: FirefoxAccountConfiguration, email: String, uid: String, deviceRegistration: FxADeviceRegistration?, stateKeyLabel: String, state: FxAState) {
+        self.init(configuration: configuration, email: email, uid: uid, deviceRegistration: deviceRegistration, stateCache: KeychainCache(branch: "account.state", label: stateKeyLabel, value: state))
+    }
+
+    public init(configuration: FirefoxAccountConfiguration, email: String, uid: String, deviceRegistration: FxADeviceRegistration?, stateCache: KeychainCache) {
+        self.email = email
+        self.uid = uid
+        self.deviceRegistration = deviceRegistration
+        self.configuration = configuration
+        self.stateCache = stateCache
+        self.stateCache.checkpoint()
+        self.fxaProfile = nil
+        self.syncAuthState = FirefoxAccountSyncAuthState(account: self,
+            cache: KeychainCache.fromBranch("account.syncAuthState", withLabel: self.stateCache.label, factory: syncAuthStateCachefromJSON))
+    }
+
+    open class func from(_ configuration: FirefoxAccountConfiguration, andJSON data: JSON) -> FirefoxAccount? {
+        guard let email = data["email"].string ,
+            let uid = data["uid"].string,
+            let sessionToken = data["sessionToken"].string?.hexDecodedData,
+            let keyFetchToken = data["keyFetchToken"].string?.hexDecodedData,
+            let unwrapkB = data["unwrapBKey"].string?.hexDecodedData else {
+                return nil
+        }
+
+        let verified = data["verified"].bool ?? false
+        return FirefoxAccount.from(configuration: configuration,
+            andParametersWithEmail: email, uid: uid, deviceRegistration: nil, verified: verified,
+            sessionToken: sessionToken, keyFetchToken: keyFetchToken, unwrapkB: unwrapkB)
+    }
+
+    open class func from(_ configuration: FirefoxAccountConfiguration,
+                         andLoginResponse response: FxALoginResponse,
+                         unwrapkB: Data) -> FirefoxAccount {
+        return FirefoxAccount.from(configuration: configuration,
+            andParametersWithEmail: response.remoteEmail, uid: response.uid, deviceRegistration: nil, verified: response.verified,
+            sessionToken: response.sessionToken as Data, keyFetchToken: response.keyFetchToken as Data, unwrapkB: unwrapkB)
+    }
+
+    fileprivate class func from(configuration: FirefoxAccountConfiguration,
+                                andParametersWithEmail email: String,
+                                uid: String,
+                                deviceRegistration: FxADeviceRegistration?,
+                                verified: Bool,
+                                sessionToken: Data,
+                                keyFetchToken: Data,
+                                unwrapkB: Data) -> FirefoxAccount {
+        var state: FxAState! = nil
+        if !verified {
+            let now = Date.now()
+            state = EngagedBeforeVerifiedState(knownUnverifiedAt: now,
+                lastNotifiedUserAt: now,
+                sessionToken: sessionToken,
+                keyFetchToken: keyFetchToken,
+                unwrapkB: unwrapkB
+            )
+        } else {
+            state = EngagedAfterVerifiedState(
+                sessionToken: sessionToken,
+                keyFetchToken: keyFetchToken,
+                unwrapkB: unwrapkB
+            )
+        }
+
+        let account = FirefoxAccount(
+            configuration: configuration,
+            email: email,
+            uid: uid,
+            deviceRegistration: deviceRegistration,
+            stateKeyLabel: Bytes.generateGUID(),
+            state: state
+        )
+        return account
+    }
+
+    open func dictionary() -> [String: Any] {
+        var dict: [String: Any] = [:]
+        dict["version"] = AccountSchemaVersion
+        dict["email"] = email
+        dict["uid"] = uid
+        dict["deviceRegistration"] = deviceRegistration
+        dict["pushRegistration"] = pushRegistration
+        dict["configurationLabel"] = configuration.label.rawValue
+        dict["stateKeyLabel"] = stateCache.label
+        return dict
+    }
+
+    open class func fromDictionary(_ dictionary: [String: Any]) -> FirefoxAccount? {
+        if let version = dictionary["version"] as? Int {
+            // As of this writing, the current version, v2, is backward compatible with v1. The only
+            // field added is pushRegistration, which is ok to be nil. If it is nil, then the app
+            // will attempt registration when it starts up.
+            if version <= AccountSchemaVersion {
+                return FirefoxAccount.fromDictionaryV1(dictionary)
+            }
+        }
+        return nil
+    }
+
+    fileprivate class func fromDictionaryV1(_ dictionary: [String: Any]) -> FirefoxAccount? {
+        var configurationLabel: FirefoxAccountConfigurationLabel? = nil
+        if let rawValue = dictionary["configurationLabel"] as? String {
+            configurationLabel = FirefoxAccountConfigurationLabel(rawValue: rawValue)
+        }
+        if let
+            configurationLabel = configurationLabel,
+            let email = dictionary["email"] as? String,
+            let uid = dictionary["uid"] as? String {
+                let deviceRegistration = dictionary["deviceRegistration"] as? FxADeviceRegistration
+                let stateCache = KeychainCache.fromBranch("account.state", withLabel: dictionary["stateKeyLabel"] as? String, withDefault: SeparatedState(), factory: state)
+                let account = FirefoxAccount(
+                    configuration: configurationLabel.toConfiguration(),
+                    email: email, uid: uid,
+                    deviceRegistration: deviceRegistration,
+                    stateCache: stateCache)
+                account.pushRegistration = dictionary["pushRegistration"] as? PushRegistration
+                return account
+        }
+        return nil
+    }
+
+    public enum AccountError: MaybeErrorType {
+        case notMarried
+
+        public var description: String {
+            switch self {
+            case .notMarried: return "Not married."
+            }
+        }
+    }
+
+    public class NotATokenStateError: MaybeErrorType {
+        let state: FxAState?
+        init(state: FxAState?) {
+            self.state = state
+        }
+        public var description: String {
+            return "Not in a Token State: \(state?.label.rawValue ?? "Empty State")"
+        }
+    }
+    
+    public class FxAProfile {
+        open var displayName: String?
+        open let email: String
+        open let avatar: Avatar
+        
+        init(email: String, displayName: String?, avatar: String?) {
+            self.email = email
+            self.displayName = displayName
+            self.avatar = Avatar(url: avatar?.asURL)
+        }
+        
+        enum ImageDownloadState {
+            case notStarted
+            case started
+            case failedCanRetry
+            case failedCanNotRetry
+            case succeededMalformed
+            case succeeded
+        }
+        
+        open class Avatar {
+            open var image: UIImage?
+            open let url: URL?
+            var currentImageState: ImageDownloadState = .notStarted
+            
+            init(url: URL?) {
+                self.image = UIImage(named: "placeholder-avatar")
+                self.url = url
+                self.updateAvatarImageState()
+            }
+            
+            func updateAvatarImageState() {
+                switch currentImageState {
+                case .notStarted:
+                    self.currentImageState = .started
+                    self.downloadAvatar()
+                    break
+                case .failedCanRetry:
+                    self.downloadAvatar()
+                    break
+                default:
+                    break
+                }
+            }
+            
+            func downloadAvatar() {
+                SDWebImageManager.shared().loadImage(with: url, options: [.continueInBackground, .lowPriority], progress: nil) { (image, _, error, _, success, _) in
+                    if let error = error {
+                        if (error as NSError).code == 404 || self.currentImageState == .failedCanRetry {
+                            // Image is not found or failed to download a second time
+                            self.currentImageState = .failedCanNotRetry
+                        } else {
+                            // This could have been a transient error, attempt to download the image only once more
+                            self.currentImageState = .failedCanRetry
+                            self.updateAvatarImageState()
+                        }
+                        return
+                    }
+                    
+                    if success == true && image == nil {
+                        self.currentImageState = .succeededMalformed
+                        return
+                    }
+                    
+                    self.image = image
+                    self.currentImageState = .succeeded
+                    NotificationCenter.default.post(name: NotificationFirefoxAccountProfileChanged, object: self)
+                }
+            }
+        }
+    }
+    
+    // Fetch current user's FxA profile. It contains the most updated email, displayName and avatar. This
+    // emits two `NotificationFirefoxAccountProfileChanged`, once when the profile has been downloaded and
+    // another when the avatar image has been downloaded.
+    open func updateProfile() {
+        guard let session = stateCache.value as? TokenState else {
+            return
+        }
+        
+        let client = FxAClient10(authEndpoint: self.configuration.authEndpointURL, oauthEndpoint: self.configuration.oauthEndpointURL, profileEndpoint: self.configuration.profileEndpointURL)
+        client.getProfile(withSessionToken: session.sessionToken as NSData) >>== { result in
+            self.fxaProfile = FxAProfile(email: result.email, displayName: result.displayName, avatar: result.avatarURL)
+            NotificationCenter.default.post(name: NotificationFirefoxAccountProfileChanged, object: self)
+        }
+    }
+    
+    // Fetch the devices list from FxA then replace the current stored remote devices.
+    open func updateFxADevices(remoteDevices: RemoteDevices) -> Success {
+        guard let session = stateCache.value as? TokenState else {
+            return deferMaybe(NotATokenStateError(state: stateCache.value))
+        }
+        let client = FxAClient10(authEndpoint: self.configuration.authEndpointURL)
+        return client.devices(withSessionToken: session.sessionToken as NSData) >>== { resp in
+            return remoteDevices.replaceRemoteDevices(resp.devices)
+        }
+    }
+
+    public class NotifyError: MaybeErrorType {
+        public var description = "The server could not notify the clients."
+    }
+
+    @discardableResult open func notify(deviceIDs: [GUID], collectionsChanged collections: [String], reason: String) -> Success {
+        guard let session = stateCache.value as? TokenState else {
+            return deferMaybe(NotATokenStateError(state: stateCache.value))
+        }
+        let client = FxAClient10(authEndpoint: self.configuration.authEndpointURL)
+        return client.notify(deviceIDs: deviceIDs, collectionsChanged: collections, reason: reason, withSessionToken: session.sessionToken as NSData) >>== { resp in
+            guard resp.success else {
+                return deferMaybe(NotifyError())
+            }
+            return succeed()
+        }
+    }
+
+    @discardableResult open func notifyAll(collectionsChanged collections: [String], reason: String) -> Success {
+        guard let session = stateCache.value as? TokenState else {
+            return deferMaybe(NotATokenStateError(state: stateCache.value))
+        }
+        guard let ownDeviceId = self.deviceRegistration?.id else {
+            return deferMaybe(FxAClientError.local(NSError()))
+        }
+        let client = FxAClient10(authEndpoint: self.configuration.authEndpointURL)
+        return client.notifyAll(ownDeviceId: ownDeviceId, collectionsChanged: collections, reason: reason, withSessionToken: session.sessionToken as NSData) >>== { resp in
+            guard resp.success else {
+                return deferMaybe(NotifyError())
+            }
+            return succeed()
+        }
+    }
+
+    @discardableResult open func destroyDevice() -> Success {
+        guard let session = stateCache.value as? TokenState else {
+            return deferMaybe(NotATokenStateError(state: stateCache.value))
+        }
+        guard let ownDeviceId = self.deviceRegistration?.id else {
+            return deferMaybe(FxAClientError.local(NSError()))
+        }
+        let client = FxAClient10(authEndpoint: self.configuration.authEndpointURL)
+
+        return client.destroyDevice(ownDeviceId: ownDeviceId, withSessionToken: session.sessionToken as NSData) >>> succeed
+    }
+
+    @discardableResult open func advance() -> Deferred {
+        OSSpinLockLock(&advanceLock)
+        if let deferred = advanceDeferred {
+            // We already have an advance() in progress.  This consumer can chain from it.
+            log.debug("advance already in progress; returning shared deferred.")
+            OSSpinLockUnlock(&advanceLock)
+            return deferred
+        }
+
+        // Alright, we haven't an advance() in progress.  Schedule a new deferred to chain from.
+        let cachedState = stateCache.value!
+        var registration = succeed()
+        if let session = cachedState as? TokenState {
+            registration = FxADeviceRegistrator.registerOrUpdateDevice(self, sessionToken: session.sessionToken as NSData).bind { result in
+                if result.successValue != FxADeviceRegistrationResult.alreadyRegistered {
+                    NotificationCenter.default.post(name: NotificationFirefoxAccountDeviceRegistrationUpdated, object: nil)
+                }
+                return succeed()
+            }
+        }
+
+        let deferred: Deferred = registration.bind { _ in
+            let client = FxAClient10(authEndpoint: self.configuration.authEndpointURL, oauthEndpoint: self.configuration.oauthEndpointURL, profileEndpoint: self.configuration.profileEndpointURL)
+            let stateMachine = FxALoginStateMachine(client: client)
+            let now = Date.now()
+            return stateMachine.advance(fromState: cachedState, now: now).map { newState in
+                self.stateCache.value = newState
+                return newState
+            }
+        }
+
+        advanceDeferred = deferred
+        log.debug("no advance() in progress; setting and returning new shared deferred.")
+        OSSpinLockUnlock(&advanceLock)
+
+        deferred.upon { _ in
+            // This advance() is complete.  Clear the shared deferred.
+            OSSpinLockLock(&self.advanceLock)
+            if let existingDeferred = self.advanceDeferred, existingDeferred === deferred {
+                // The guard should not be needed, but should prevent trampling racing consumers.
+                self.advanceDeferred = nil
+                log.debug("advance() completed and shared deferred is existing deferred; clearing shared deferred.")
+            } else {
+                log.warning("advance() completed but shared deferred is not existing deferred; ignoring potential bug!")
+            }
+            OSSpinLockUnlock(&self.advanceLock)
+        }
+        return deferred
+    }
+
+    open func marriedState() -> Deferred> {
+        return advance().map { newState in
+            if newState.label == FxAStateLabel.married {
+                if let married = newState as? MarriedState {
+                    return Maybe(success: married)
+                }
+            }
+            return Maybe(failure: AccountError.notMarried)
+        }
+    }
+
+    @discardableResult open func makeSeparated() -> Bool {
+        log.info("Making Account State be Separated.")
+        self.stateCache.value = SeparatedState()
+        return true
+    }
+
+    @discardableResult open func makeDoghouse() -> Bool {
+        log.info("Making Account State be Doghouse.")
+        self.stateCache.value = DoghouseState()
+        return true
+    }
+
+    open func makeCohabitingWithoutKeyPair() -> Bool {
+        if let married = self.stateCache.value as? MarriedState {
+            log.info("Making Account State be CohabitingWithoutKeyPair.")
+            self.stateCache.value = married.withoutKeyPair()
+            return true
+        }
+
+        log.info("Cannot make Account State be CohabitingWithoutKeyPair from state with label \(self.stateCache.value?.label ??? "nil").")
+        return false
+    }
+}
diff --git a/mobile/ios/Account/FirefoxAccountConfiguration.swift b/mobile/ios/Account/FirefoxAccountConfiguration.swift
new file mode 100644
index 0000000000..1daca26f6b
--- /dev/null
+++ b/mobile/ios/Account/FirefoxAccountConfiguration.swift
@@ -0,0 +1,266 @@
+/* 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/. */
+
+import Foundation
+import Shared
+
+public enum FirefoxAccountConfigurationLabel: String {
+    case latestDev = "LatestDev"
+    case stableDev = "StableDev"
+    case stage = "Stage"
+    case production = "Production"
+    case chinaEdition = "ChinaEdition"
+    case custom = "Custom"
+
+    public func toConfiguration(prefs: Prefs? = nil) -> FirefoxAccountConfiguration {
+        switch self {
+        case .latestDev: return LatestDevFirefoxAccountConfiguration()
+        case .stableDev: return StableDevFirefoxAccountConfiguration()
+        case .stage: return StageFirefoxAccountConfiguration()
+        case .production: return ProductionFirefoxAccountConfiguration()
+        case .chinaEdition: return ChinaEditionFirefoxAccountConfiguration()
+        case .custom: return CustomFirefoxAccountConfiguration(prefs: prefs)
+        }
+    }
+}
+
+/**
+ * In the URLs below, service=sync ensures that we always get the keys with signin messages,
+ * and context=fx_ios_v1 opts us in to the Desktop Sync postMessage interface.
+ */
+public protocol FirefoxAccountConfiguration {
+    var label: FirefoxAccountConfigurationLabel { get }
+
+    /// A Firefox Account exists on a particular server.  The auth endpoint should speak the protocol documented at
+    /// https://github.com/mozilla/fxa-auth-server/blob/02f88502700b0c5ef5a4768a8adf332f062ad9bf/docs/api.md
+    var authEndpointURL: URL { get }
+
+    /// The associated oauth server should speak the protocol documented at
+    /// https://github.com/mozilla/fxa-oauth-server/blob/6cc91e285fc51045a365dbacb3617ef29093dbc3/docs/api.md
+    var oauthEndpointURL: URL { get }
+
+    var profileEndpointURL: URL { get }
+
+    /// The associated content server should speak the protocol implemented (but not yet documented) at
+    /// https://github.com/mozilla/fxa-content-server/blob/161bff2d2b50bac86ec46c507e597441c8575189/app/scripts/models/auth_brokers/fx-desktop.js
+    var signInURL: URL { get }
+    var settingsURL: URL { get }
+    var forceAuthURL: URL { get }
+
+    var sync15Configuration: Sync15Configuration { get }
+
+    var pushConfiguration: PushConfiguration { get }
+}
+
+public struct LatestDevFirefoxAccountConfiguration: FirefoxAccountConfiguration {
+    public init() {
+    }
+
+    public let label = FirefoxAccountConfigurationLabel.latestDev
+
+    public let authEndpointURL = URL(string: "https://latest.dev.lcip.org/auth/v1")!
+    public let oauthEndpointURL = URL(string: "https://oauth-latest.dev.lcip.org")!
+    public let profileEndpointURL = URL(string: "https://latest.dev.lcip.org/profile")!
+
+    public let signInURL = URL(string: "https://latest.dev.lcip.org/signin?service=sync&context=fx_ios_v1")!
+    public let settingsURL = URL(string: "https://latest.dev.lcip.org/settings?context=fx_ios_v1")!
+    public let forceAuthURL = URL(string: "https://latest.dev.lcip.org/force_auth?service=sync&context=fx_ios_v1")!
+
+    public let sync15Configuration: Sync15Configuration = StageSync15Configuration()
+
+    public let pushConfiguration: PushConfiguration = FennecPushConfiguration()
+}
+
+public struct StableDevFirefoxAccountConfiguration: FirefoxAccountConfiguration {
+    public init() {
+    }
+
+    public let label = FirefoxAccountConfigurationLabel.stableDev
+
+    public let authEndpointURL = URL(string: "https://stable.dev.lcip.org/auth/v1")!
+    public let oauthEndpointURL = URL(string: "https://oauth-stable.dev.lcip.org")!
+    public let profileEndpointURL = URL(string: "https://stable.dev.lcip.org/profile")!
+
+    public let signInURL = URL(string: "https://stable.dev.lcip.org/signin?service=sync&context=fx_ios_v1")!
+    public let settingsURL = URL(string: "https://stable.dev.lcip.org/settings?context=fx_ios_v1")!
+    public let forceAuthURL = URL(string: "https://stable.dev.lcip.org/force_auth?service=sync&context=fx_ios_v1")!
+
+    public let sync15Configuration: Sync15Configuration = StageSync15Configuration()
+
+    public let pushConfiguration: PushConfiguration = FennecPushConfiguration()
+}
+
+public struct StageFirefoxAccountConfiguration: FirefoxAccountConfiguration {
+    public init() {
+    }
+
+    public let label = FirefoxAccountConfigurationLabel.stage
+
+    public let authEndpointURL = URL(string: "https://api-accounts.stage.mozaws.net/v1")!
+    public let oauthEndpointURL = URL(string: "https://oauth.stage.mozaws.net/v1")!
+    public let profileEndpointURL = URL(string: "https://profile.stage.mozaws.net/v1")!
+
+    public let signInURL = URL(string: "https://accounts.stage.mozaws.net/signin?service=sync&context=fx_ios_v1")!
+    public let settingsURL = URL(string: "https://accounts.stage.mozaws.net/settings?context=fx_ios_v1")!
+    public let forceAuthURL = URL(string: "https://accounts.stage.mozaws.net/force_auth?service=sync&context=fx_ios_v1")!
+
+    public let sync15Configuration: Sync15Configuration = StageSync15Configuration()
+
+    public var pushConfiguration: PushConfiguration {
+        get {
+            #if MOZ_CHANNEL_RELEASE
+                return FirefoxStagingPushConfiguration()
+            #elseif MOZ_CHANNEL_BETA
+                return FirefoxBetaStagingPushConfiguration()
+            #elseif MOZ_CHANNEL_FENNEC
+                return FennecStagingPushConfiguration()
+            #endif
+        }
+    }
+}
+
+public struct ProductionFirefoxAccountConfiguration: FirefoxAccountConfiguration {
+    public init() {
+    }
+
+    public let label = FirefoxAccountConfigurationLabel.production
+
+    public let authEndpointURL = URL(string: "https://api.accounts.firefox.com/v1")!
+    public let oauthEndpointURL = URL(string: "https://oauth.accounts.firefox.com/v1")!
+    public let profileEndpointURL = URL(string: "https://profile.accounts.firefox.com/v1")!
+
+    public let signInURL = URL(string: "https://accounts.firefox.com/signin?service=sync&context=fx_ios_v1")!
+    public let settingsURL = URL(string: "https://accounts.firefox.com/settings?context=fx_ios_v1")!
+    public let forceAuthURL = URL(string: "https://accounts.firefox.com/force_auth?service=sync&context=fx_ios_v1")!
+
+    public let sync15Configuration: Sync15Configuration = ProductionSync15Configuration()
+
+    public let pushConfiguration: PushConfiguration = FirefoxPushConfiguration()
+}
+
+public struct CustomFirefoxAccountConfiguration: FirefoxAccountConfiguration {
+    public init(prefs: Prefs? = nil) {
+        self.prefs = prefs
+    }
+    
+    public var prefs: Prefs?
+    
+    public let label = FirefoxAccountConfigurationLabel.custom
+    
+    public var authEndpointURL: URL {
+        get {
+            if let authServer = self.prefs?.stringForKey(PrefsKeys.KeyCustomSyncAuth), let url = URL(string: authServer + "/v1") {
+                return url
+            }
+            
+            // If somehow an invalid url was stored, fallback to the production URL
+            return ProductionFirefoxAccountConfiguration().authEndpointURL
+        }
+    }
+
+    public var oauthEndpointURL: URL {
+        get {
+            if let oauthServer = self.prefs?.stringForKey(PrefsKeys.KeyCustomSyncOauth), let url = URL(string: oauthServer + "/v1") {
+                return url
+            }
+            return ProductionFirefoxAccountConfiguration().oauthEndpointURL
+        }
+    }
+    
+    public var profileEndpointURL: URL {
+        get {
+            if let profileServer = self.prefs?.stringForKey(PrefsKeys.KeyCustomSyncProfile), let url = URL(string: profileServer + "/v1") {
+                return url
+            }
+            return ProductionFirefoxAccountConfiguration().profileEndpointURL
+        }
+    }
+    
+    public var signInURL: URL {
+        get {
+            if let signIn = self.prefs?.stringForKey(PrefsKeys.KeyCustomSyncWeb), let url = URL(string: signIn + "/signin?service=sync&context=fx_ios_v1") {
+                return url
+            }
+            return ProductionFirefoxAccountConfiguration().signInURL
+        }
+    }
+    
+    public var forceAuthURL: URL {
+        get {
+            if let forceAuth = self.prefs?.stringForKey(PrefsKeys.KeyCustomSyncWeb), let url = URL(string: forceAuth + "/force_auth?service=sync&context=fx_ios_v1") {
+                return url
+            }
+            return ProductionFirefoxAccountConfiguration().forceAuthURL
+        }
+    }
+    
+    public var settingsURL: URL {
+        get {
+            if let settings = self.prefs?.stringForKey(PrefsKeys.KeyCustomSyncWeb), let url = URL(string: settings + "/settings?service=sync&context=fx_ios_v1") {
+                return url
+            }
+            return ProductionFirefoxAccountConfiguration().settingsURL
+        }
+    }
+    
+    public var sync15Configuration: Sync15Configuration {
+        get {
+            return CustomSync15Configuration(prefs: self.prefs)
+        }
+    }
+    
+    public let pushConfiguration: PushConfiguration = FirefoxPushConfiguration()
+}
+
+public struct ChinaEditionFirefoxAccountConfiguration: FirefoxAccountConfiguration {
+    public init() {
+    }
+
+    public let label = FirefoxAccountConfigurationLabel.chinaEdition
+
+    public let authEndpointURL = URL(string: "https://api-accounts.firefox.com.cn/v1")!
+    public let oauthEndpointURL = URL(string: "https://oauth.firefox.com.cn/v1")!
+    public let profileEndpointURL = URL(string: "https://profile.firefox.com.cn/v1")!
+
+    public let signInURL = URL(string: "https://accounts.firefox.com.cn/signin?service=sync&context=fx_ios_v1")!
+    public let settingsURL = URL(string: "https://accounts.firefox.com.cn/settings?context=fx_ios_v1")!
+    public let forceAuthURL = URL(string: "https://accounts.firefox.com.cn/force_auth?service=sync&context=fx_ios_v1")!
+
+    public let sync15Configuration: Sync15Configuration = ChinaEditionSync15Configuration()
+
+    public let pushConfiguration: PushConfiguration = FirefoxPushConfiguration()
+}
+
+public protocol Sync15Configuration {
+    var tokenServerEndpointURL: URL { get }
+}
+
+public struct ChinaEditionSync15Configuration: Sync15Configuration {
+    public let tokenServerEndpointURL = URL(string: "https://sync.firefox.com.cn/token/1.0/sync/1.5")!
+}
+
+public struct ProductionSync15Configuration: Sync15Configuration {
+    public let tokenServerEndpointURL = URL(string: "https://token.services.mozilla.com/1.0/sync/1.5")!
+}
+
+public struct StageSync15Configuration: Sync15Configuration {
+    public let tokenServerEndpointURL = URL(string: "https://token.stage.mozaws.net/1.0/sync/1.5")!
+}
+
+public struct CustomSync15Configuration: Sync15Configuration {
+    public init(prefs: Prefs? = nil) {
+        self.prefs = prefs
+    }
+    
+    public var prefs: Prefs?
+    
+    public var tokenServerEndpointURL: URL {
+        get {
+            if let tokenServer = self.prefs?.stringForKey(PrefsKeys.KeyCustomSyncToken), let url = URL(string: tokenServer + "/1.0/sync/1.5") {
+                return url
+            }
+            return ProductionSync15Configuration().tokenServerEndpointURL
+        }
+    }
+}
diff --git a/mobile/ios/Account/FxAClient10.swift b/mobile/ios/Account/FxAClient10.swift
new file mode 100644
index 0000000000..08e5edf5b9
--- /dev/null
+++ b/mobile/ios/Account/FxAClient10.swift
@@ -0,0 +1,562 @@
+/* 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/. */
+
+import Alamofire
+import Shared
+import Foundation
+import FxA
+import Deferred
+import SwiftyJSON
+
+public let FxAClientErrorDomain = "org.mozilla.fxa.error"
+public let FxAClientUnknownError = NSError(domain: FxAClientErrorDomain, code: 999,
+    userInfo: [NSLocalizedDescriptionKey: "Invalid server response"])
+
+let KeyLength: Int = 32
+
+public struct FxALoginResponse {
+    public let remoteEmail: String
+    public let uid: String
+    public let verified: Bool
+    public let sessionToken: Data
+    public let keyFetchToken: Data
+}
+
+public struct FxAccountRemoteError {
+    static let AttemptToOperateOnAnUnverifiedAccount: Int32     = 104
+    static let InvalidAuthenticationToken: Int32                = 110
+    static let EndpointIsNoLongerSupported: Int32               = 116
+    static let IncorrectLoginMethodForThisAccount: Int32        = 117
+    static let IncorrectKeyRetrievalMethodForThisAccount: Int32 = 118
+    static let IncorrectAPIVersionForThisAccount: Int32         = 119
+    static let UnknownDevice: Int32                             = 123
+    static let DeviceSessionConflict: Int32                     = 124
+    static let UnknownError: Int32                              = 999
+}
+
+public struct FxAKeysResponse {
+    let kA: Data
+    let wrapkB: Data
+}
+
+public struct FxASignResponse {
+    let certificate: String
+}
+
+public struct FxAStatusResponse {
+    let exists: Bool
+}
+
+public struct FxADevicesResponse {
+    let devices: [FxADevice]
+}
+
+public struct FxANotifyResponse {
+    let success: Bool
+}
+
+public struct FxAOAuthResponse {
+    let accessToken: String
+}
+
+public struct FxAProfileResponse {
+    let email: String
+    let uid: String
+    let avatarURL: String?
+    let displayName: String?
+}
+
+public struct FxADeviceDestroyResponse {
+    let success: Bool
+}
+
+// fxa-auth-server produces error details like:
+//        {
+//            "code": 400, // matches the HTTP status code
+//            "errno": 107, // stable application-level error number
+//            "error": "Bad Request", // string description of the error type
+//            "message": "the value of salt is not allowed to be undefined",
+//            "info": "https://docs.dev.lcip.og/errors/1234" // link to more info on the error
+//        }
+
+public enum FxAClientError {
+    case remote(RemoteError)
+    case local(NSError)
+}
+
+// Be aware that string interpolation doesn't work: rdar://17318018, much good that it will do.
+extension FxAClientError: MaybeErrorType {
+    public var description: String {
+        switch self {
+        case let .remote(error):
+            let errorString = error.error ?? NSLocalizedString("Missing error", comment: "Error for a missing remote error number")
+            let messageString = error.message ?? NSLocalizedString("Missing message", comment: "Error for a missing remote error message")
+            return ""
+        case let .local(error):
+            return ""
+        }
+    }
+}
+
+public struct RemoteError {
+    let code: Int32
+    let errno: Int32
+    let error: String?
+    let message: String?
+    let info: String?
+
+    var isUpgradeRequired: Bool {
+        return errno == FxAccountRemoteError.EndpointIsNoLongerSupported
+            || errno == FxAccountRemoteError.IncorrectLoginMethodForThisAccount
+            || errno == FxAccountRemoteError.IncorrectKeyRetrievalMethodForThisAccount
+            || errno == FxAccountRemoteError.IncorrectAPIVersionForThisAccount
+    }
+
+    var isInvalidAuthentication: Bool {
+        return code == 401
+    }
+
+    var isUnverified: Bool {
+        return errno == FxAccountRemoteError.AttemptToOperateOnAnUnverifiedAccount
+    }
+}
+
+open class FxAClient10 {
+    let authURL: URL
+    let oauthURL: URL
+    let profileURL: URL
+
+    public init(authEndpoint: URL? = nil, oauthEndpoint: URL? = nil, profileEndpoint: URL? = nil) {
+        self.authURL = authEndpoint ?? ProductionFirefoxAccountConfiguration().authEndpointURL as URL
+        self.oauthURL = oauthEndpoint ?? ProductionFirefoxAccountConfiguration().oauthEndpointURL as URL
+        self.profileURL = profileEndpoint ?? ProductionFirefoxAccountConfiguration().profileEndpointURL as URL
+    }
+
+    open class func KW(_ kw: String) -> Data {
+        return ("identity.mozilla.com/picl/v1/" + kw).utf8EncodedData
+    }
+
+    /**
+     * The token server accepts an X-Client-State header, which is the
+     * lowercase-hex-encoded first 16 bytes of the SHA-256 hash of the
+     * bytes of kB.
+     */
+    open class func computeClientState(_ kB: Data) -> String? {
+        if kB.count != 32 {
+            return nil
+        }
+        return kB.sha256.subdata(in: 0..<16).hexEncodedString
+    }
+
+    open class func quickStretchPW(_ email: Data, password: Data) -> Data {
+        var salt = KW("quickStretch")
+        salt.append(":".utf8EncodedData)
+        salt.append(email)
+        return (password as NSData).derivePBKDF2HMACSHA256Key(withSalt: salt as Data!, iterations: 1000, length: 32)
+    }
+
+    open class func computeUnwrapKey(_ stretchedPW: Data) -> Data {
+        let salt: Data = Data()
+        let contextInfo: Data = KW("unwrapBkey")
+        let bytes = (stretchedPW as NSData).deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(KeyLength))
+        return bytes!
+    }
+
+    fileprivate class func remoteError(fromJSON json: JSON, statusCode: Int) -> RemoteError? {
+        if json.error != nil || 200 <= statusCode && statusCode <= 299 {
+            return nil
+        }
+
+        if let code = json["code"].int32 {
+            if let errno = json["errno"].int32 {
+                return RemoteError(code: code, errno: errno,
+                                   error: json["error"].string,
+                                   message: json["message"].string,
+                                   info: json["info"].string)
+            }
+        }
+        return nil
+    }
+
+    fileprivate class func loginResponse(fromJSON json: JSON) -> FxALoginResponse? {
+        guard json.error == nil,
+            let uid = json["uid"].string,
+            let verified = json["verified"].bool,
+            let sessionToken = json["sessionToken"].string,
+            let keyFetchToken = json["keyFetchToken"].string else {
+                return nil
+        }
+
+        return FxALoginResponse(remoteEmail: "", uid: uid, verified: verified,
+            sessionToken: sessionToken.hexDecodedData, keyFetchToken: keyFetchToken.hexDecodedData)
+    }
+
+    fileprivate class func keysResponse(fromJSON keyRequestKey: Data, json: JSON) -> FxAKeysResponse? {
+        guard json.error == nil,
+            let bundle = json["bundle"].string else {
+                return nil
+        }
+
+        let data = bundle.hexDecodedData
+        guard data.count == 3 * KeyLength else {
+            return nil
+        }
+
+        let ciphertext = data.subdata(in: 0..<(2 * KeyLength))
+        let MAC = data.subdata(in: (2 * KeyLength)..<(3 * KeyLength))
+
+        let salt: Data = Data()
+        let contextInfo: Data = KW("account/keys")
+        let bytes = (keyRequestKey as NSData).deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(3 * KeyLength))
+        let respHMACKey = bytes?.subdata(in: 0.. FxASignResponse? {
+        guard json.error == nil,
+            let cert = json["cert"].string else {
+                return nil
+        }
+
+        return FxASignResponse(certificate: cert)
+    }
+
+    fileprivate class func statusResponse(fromJSON json: JSON) -> FxAStatusResponse? {
+        guard json.error == nil,
+            let exists = json["exists"].bool else {
+                return nil
+        }
+
+        return FxAStatusResponse(exists: exists)
+    }
+
+    fileprivate class func devicesResponse(fromJSON json: JSON) -> FxADevicesResponse? {
+        guard json.error == nil,
+            let jsonDevices = json.array else {
+                return nil
+        }
+
+        let devices = jsonDevices.flatMap { (jsonDevice) -> FxADevice? in
+            return FxADevice.fromJSON(jsonDevice)
+        }
+
+        return FxADevicesResponse(devices: devices)
+    }
+    
+    fileprivate class func notifyResponse(fromJSON json: JSON) -> FxANotifyResponse {
+        return FxANotifyResponse(success: json.error == nil)
+    }
+    
+    fileprivate class func deviceDestroyResponse(fromJSON json: JSON) -> FxADeviceDestroyResponse {
+        return FxADeviceDestroyResponse(success: json.error == nil)
+    }
+
+    fileprivate class func oauthResponse(fromJSON json: JSON) -> FxAOAuthResponse? {
+        guard json.error == nil,
+            let accessToken = json["access_token"].string else {
+                return nil
+        }
+        
+        return FxAOAuthResponse(accessToken: accessToken)
+    }
+    
+    fileprivate class func profileResponse(fromJSON json: JSON) -> FxAProfileResponse? {
+        guard json.error == nil,
+            let uid = json["uid"].string,
+            let email = json["email"].string else {
+                return nil
+        }
+        
+        let avatarURL = json["avatar"].string
+        let displayName = json["displayName"].string
+        
+        return FxAProfileResponse(email: email, uid: uid, avatarURL: avatarURL, displayName: displayName)
+    }
+
+    lazy fileprivate var alamofire: SessionManager = {
+        let ua = UserAgent.fxaUserAgent
+        let configuration = URLSessionConfiguration.ephemeral
+        var defaultHeaders = SessionManager.default.session.configuration.httpAdditionalHeaders ?? [:]
+        defaultHeaders["User-Agent"] = ua
+        configuration.httpAdditionalHeaders = defaultHeaders
+        return SessionManager(configuration: configuration)
+    }()
+
+    open func login(_ emailUTF8: Data, quickStretchedPW: Data, getKeys: Bool) -> Deferred> {
+        let authPW = (quickStretchedPW as NSData).deriveHKDFSHA256Key(withSalt: Data(), contextInfo: FxAClient10.KW("authPW"), length: 32) as NSData
+
+        let parameters = [
+            "email": NSString(data: emailUTF8, encoding: String.Encoding.utf8.rawValue)!,
+            "authPW": authPW.base16EncodedString(options: NSDataBase16EncodingOptions.lowerCase) as NSString,
+        ]
+
+        var URL: URL = self.authURL.appendingPathComponent("/account/login")
+        if getKeys {
+            var components = URLComponents(url: URL, resolvingAgainstBaseURL: false)!
+            components.query = "keys=true"
+            URL = components.url!
+        }
+        var mutableURLRequest = URLRequest(url: URL)
+        mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
+
+        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        mutableURLRequest.httpBody = JSON(parameters).stringValue()?.utf8EncodedData
+
+        return makeRequest(mutableURLRequest, responseHandler: FxAClient10.loginResponse)
+    }
+
+    open func status(forUID uid: String) -> Deferred> {
+        let statusURL = self.authURL.appendingPathComponent("/account/status").withQueryParam("uid", value: uid)
+        var mutableURLRequest = URLRequest(url: statusURL)
+        mutableURLRequest.httpMethod = HTTPMethod.get.rawValue
+
+        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+
+        return makeRequest(mutableURLRequest, responseHandler: FxAClient10.statusResponse)
+    }
+
+    open func devices(withSessionToken sessionToken: NSData) -> Deferred> {
+        let URL = self.authURL.appendingPathComponent("/account/devices")
+        var mutableURLRequest = URLRequest(url: URL)
+        mutableURLRequest.httpMethod = HTTPMethod.get.rawValue
+
+        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+
+        let salt: Data = Data()
+        let contextInfo: Data = FxAClient10.KW("sessionToken")
+        let key = sessionToken.deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(2 * KeyLength))!
+        mutableURLRequest.addAuthorizationHeader(forHKDFSHA256Key: key)
+
+        return makeRequest(mutableURLRequest, responseHandler: FxAClient10.devicesResponse)
+    }
+    
+    open func notify(deviceIDs: [GUID], collectionsChanged collections: [String], reason: String, withSessionToken sessionToken: NSData) -> Deferred> {
+        let httpBody = JSON([
+            "to": deviceIDs,
+            "payload": [
+                "version": 1,
+                "command": "sync:collection_changed",
+                "data": [
+                    "collections": collections,
+                    "reason": reason
+                ]
+            ]
+        ])
+        return self.notify(httpBody: httpBody, withSessionToken: sessionToken)
+    }
+
+    open func notifyAll(ownDeviceId: GUID, collectionsChanged collections: [String], reason: String, withSessionToken sessionToken: NSData) -> Deferred> {
+        let httpBody = JSON([
+            "to": "all",
+            "excluded": [ownDeviceId],
+            "payload": [
+                "version": 1,
+                "command": "sync:collection_changed",
+                "data": [
+                    "collections": collections,
+                    "reason": reason
+                ]
+            ]
+        ])
+        return self.notify(httpBody: httpBody, withSessionToken: sessionToken)
+    }
+
+    fileprivate func notify(httpBody: JSON, withSessionToken sessionToken: NSData) -> Deferred> {
+        let URL = self.authURL.appendingPathComponent("/account/devices/notify")
+        var mutableURLRequest = URLRequest(url: URL)
+        mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
+        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        mutableURLRequest.httpBody = httpBody.stringValue()?.utf8EncodedData
+
+        let salt: Data = Data()
+        let contextInfo: Data = FxAClient10.KW("sessionToken")
+        let key = sessionToken.deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(2 * KeyLength))!
+        mutableURLRequest.addAuthorizationHeader(forHKDFSHA256Key: key)
+
+        return makeRequest(mutableURLRequest, responseHandler: FxAClient10.notifyResponse)
+    }
+
+    open func destroyDevice(ownDeviceId: GUID, withSessionToken sessionToken: NSData) -> Deferred> {
+        let URL = self.authURL.appendingPathComponent("/account/device/destroy")
+        var mutableURLRequest = URLRequest(url: URL)
+        let httpBody: JSON = JSON(["id": ownDeviceId])
+        mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
+        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        mutableURLRequest.httpBody = httpBody.stringValue()?.utf8EncodedData
+
+        let salt: Data = Data()
+        let contextInfo: Data = FxAClient10.KW("sessionToken")
+        let key = sessionToken.deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(2 * KeyLength))!
+        mutableURLRequest.addAuthorizationHeader(forHKDFSHA256Key: key)
+
+        return makeRequest(mutableURLRequest, responseHandler: FxAClient10.deviceDestroyResponse)
+    }
+
+    open func registerOrUpdate(device: FxADevice, withSessionToken sessionToken: NSData) -> Deferred> {
+        let URL = self.authURL.appendingPathComponent("/account/device")
+        var mutableURLRequest = URLRequest(url: URL)
+        mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
+
+        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        mutableURLRequest.httpBody = device.toJSON().stringValue()?.utf8EncodedData
+
+        let salt: Data = Data()
+        let contextInfo: Data = FxAClient10.KW("sessionToken")
+        let key = sessionToken.deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(2 * KeyLength))!
+        mutableURLRequest.addAuthorizationHeader(forHKDFSHA256Key: key)
+
+        return makeRequest(mutableURLRequest, responseHandler: FxADevice.fromJSON)
+    }
+    
+    open func oauthAuthorize(withSessionToken sessionToken: NSData, keyPair: RSAKeyPair, certificate: String) -> Deferred> {
+        let audience = self.getAudience(forURL: self.oauthURL)
+        
+        let assertion = JSONWebTokenUtils.createAssertionWithPrivateKeyToSign(with: keyPair.privateKey,
+                                                                              certificate: certificate,
+                                                                              audience: audience)
+        
+        let oauthAuthorizationURL = self.oauthURL.appendingPathComponent("/authorization")
+        var mutableURLRequest = URLRequest(url: oauthAuthorizationURL)
+        mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
+        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        
+        let parameters = [
+            "assertion": assertion,
+            "client_id": AppConstants.FxAiOSClientId,
+            "response_type": "token",
+            "scope": "profile",
+            "ttl": "300"
+        ]
+        
+        let salt: Data = Data()
+        let contextInfo: Data = FxAClient10.KW("sessionToken")
+        let key = sessionToken.deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(2 * KeyLength))!
+        
+        guard let httpBody = JSON(parameters as NSDictionary).stringValue()?.utf8EncodedData else {
+            return deferMaybe(FxAClientError.local(FxAClientUnknownError))
+        }
+        
+        mutableURLRequest.httpBody = httpBody
+        mutableURLRequest.addAuthorizationHeader(forHKDFSHA256Key: key)
+        
+        return makeRequest(mutableURLRequest, responseHandler: FxAClient10.oauthResponse)
+    }
+    
+    open func getProfile(withSessionToken sessionToken: NSData) -> Deferred> {
+        let keyPair = RSAKeyPair.generate(withModulusSize: 1024)!
+        return self.sign(sessionToken as Data, publicKey: keyPair.publicKey) >>== { signResult in
+            return self.oauthAuthorize(withSessionToken: sessionToken, keyPair: keyPair, certificate: signResult.certificate) >>== { oauthResult in
+                
+                let profileURL = self.profileURL.appendingPathComponent("/profile")
+                var mutableURLRequest = URLRequest(url: profileURL)
+                mutableURLRequest.httpMethod = HTTPMethod.get.rawValue
+                
+                mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+                mutableURLRequest.setValue("Bearer " + oauthResult.accessToken, forHTTPHeaderField: "Authorization")
+                
+                return self.makeRequest(mutableURLRequest, responseHandler: FxAClient10.profileResponse)
+            }
+        }
+    }
+    
+    open func getAudience(forURL URL: URL) -> String {
+        if let port = URL.port {
+            return "\(URL.scheme!)://\(URL.host!):\(port)"
+        } else {
+            return "\(URL.scheme!)://\(URL.host!)"
+        }
+    }
+
+    fileprivate func makeRequest(_ request: URLRequest, responseHandler: @escaping (JSON) -> T?) -> Deferred> {
+        let deferred = Deferred>()
+
+        alamofire.request(request)
+            .validate(contentType: ["application/json"])
+            .responseJSON { response in
+                withExtendedLifetime(self.alamofire) {
+                    if let error = response.result.error {
+                        deferred.fill(Maybe(failure: FxAClientError.local(error as NSError)))
+                        return
+                    }
+
+                    if let data = response.result.value {
+                        let json = JSON(data)
+                        if let remoteError = FxAClient10.remoteError(fromJSON: json, statusCode: response.response!.statusCode) {
+                            deferred.fill(Maybe(failure: FxAClientError.remote(remoteError)))
+                            return
+                        }
+
+                        if let response = responseHandler(json) {
+                            deferred.fill(Maybe(success: response))
+                            return
+                        }
+                    }
+
+                    deferred.fill(Maybe(failure: FxAClientError.local(FxAClientUnknownError)))
+                }
+        }
+
+        return deferred
+    }
+}
+
+extension FxAClient10: FxALoginClient {
+
+    func keyPair() -> Deferred> {
+        let result = RSAKeyPair.generate(withModulusSize: 2048)! // TODO: debate key size and extract this constant.
+        return Deferred(value: Maybe(success: result))
+    }
+
+    open func keys(_ keyFetchToken: Data) -> Deferred> {
+        let URL = self.authURL.appendingPathComponent("/account/keys")
+        var mutableURLRequest = URLRequest(url: URL)
+        mutableURLRequest.httpMethod = HTTPMethod.get.rawValue
+
+        let salt: Data = Data()
+        let contextInfo: Data = FxAClient10.KW("keyFetchToken")
+        let key = (keyFetchToken as NSData).deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(3 * KeyLength))!
+        mutableURLRequest.addAuthorizationHeader(forHKDFSHA256Key: key)
+
+        let rangeStart = 2 * KeyLength
+        let keyRequestKey = key.subdata(in: rangeStart..<(rangeStart + KeyLength))
+
+        return makeRequest(mutableURLRequest) { FxAClient10.keysResponse(fromJSON: keyRequestKey, json: $0) }
+    }
+
+    open func sign(_ sessionToken: Data, publicKey: PublicKey) -> Deferred> {
+        let parameters = [
+            "publicKey": publicKey.jsonRepresentation() as NSDictionary,
+            "duration": NSNumber(value: OneDayInMilliseconds), // The maximum the server will allow.
+        ]
+        
+        let url = self.authURL.appendingPathComponent("/certificate/sign")
+        var mutableURLRequest = URLRequest(url: url)
+        mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
+
+        mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        mutableURLRequest.httpBody = JSON(parameters as NSDictionary).stringValue()?.utf8EncodedData
+
+        let salt: Data = Data()
+        let contextInfo: Data = FxAClient10.KW("sessionToken")
+        let key = (sessionToken as NSData).deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: UInt(2 * KeyLength))!
+        mutableURLRequest.addAuthorizationHeader(forHKDFSHA256Key: key)
+
+        return makeRequest(mutableURLRequest, responseHandler: FxAClient10.signResponse)
+    }
+}
diff --git a/mobile/ios/Account/FxADevice.swift b/mobile/ios/Account/FxADevice.swift
new file mode 100644
index 0000000000..40ec27170c
--- /dev/null
+++ b/mobile/ios/Account/FxADevice.swift
@@ -0,0 +1,66 @@
+/* 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/. */
+
+import Foundation
+import Shared
+import SwiftyJSON
+
+public struct FxADevicePushParams {
+    let callback: String
+    let publicKey: String
+    let authKey: String
+}
+
+public class FxADevice: RemoteDevice {
+    let pushParams: FxADevicePushParams?
+
+    fileprivate init(name: String, id: String?, type: String?, isCurrentDevice: Bool = false, push: FxADevicePushParams?, lastAccessTime: Timestamp?) {
+        self.pushParams = push
+        super.init(id: id, name: name, type: type, isCurrentDevice: isCurrentDevice, lastAccessTime: lastAccessTime)
+    }
+
+    static func forRegister(_ name: String, type: String, push: FxADevicePushParams?) -> FxADevice {
+        return FxADevice(name: name, id: nil, type: type, push: push, lastAccessTime: nil)
+    }
+
+    static func forUpdate(_ name: String, id: String, push: FxADevicePushParams?) -> FxADevice {
+        return FxADevice(name: name, id: id, type: nil, push: push, lastAccessTime: nil)
+    }
+
+    func toJSON() -> JSON {
+        var parameters = [String: String]()
+        parameters["name"] = name
+        parameters["id"] = id
+        parameters["type"] = type
+        if let push = self.pushParams {
+            parameters["pushCallback"] = push.callback
+            parameters["pushPublicKey"] = push.publicKey
+            parameters["pushAuthKey"] = push.authKey
+        }
+        return JSON(parameters as NSDictionary)
+    }
+
+    static func fromJSON(_ json: JSON) -> FxADevice? {
+        guard json.error == nil,
+            let id = json["id"].string,
+            let name = json["name"].string else {
+                return nil
+        }
+
+        let isCurrentDevice = json["isCurrentDevice"].bool ?? false
+        let lastAccessTime = json["lastAccessTime"].uInt64
+        let type = json["type"].string
+
+        let push: FxADevicePushParams?
+        if let pushCallback = json["pushCallback"].stringValue(),
+            let publicKey = json["pushPublicKey"].stringValue(), publicKey != "",
+            let authKey   = json["pushAuthKey"].stringValue(), authKey != "" {
+            push = FxADevicePushParams(callback: pushCallback, publicKey: publicKey, authKey: authKey)
+        } else {
+            push = nil
+        }
+
+        return FxADevice(name: name, id: id, type: type, isCurrentDevice: isCurrentDevice, push: push, lastAccessTime: lastAccessTime)
+    }
+}
diff --git a/mobile/ios/Account/FxADeviceRegistration.swift b/mobile/ios/Account/FxADeviceRegistration.swift
new file mode 100644
index 0000000000..ac809cf70a
--- /dev/null
+++ b/mobile/ios/Account/FxADeviceRegistration.swift
@@ -0,0 +1,184 @@
+/* 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/. */
+
+import Foundation
+import Deferred
+import Shared
+import SwiftyJSON
+
+private let log = Logger.syncLogger
+
+/// The current version of the device registration. We use this to re-register
+/// devices after we update what we send on device registration.
+private let DeviceRegistrationVersion = 2
+
+public enum FxADeviceRegistrationResult {
+    case registered
+    case updated
+    case alreadyRegistered
+}
+
+public enum FxADeviceRegistratorError: MaybeErrorType {
+    case accountDeleted
+    case currentDeviceNotFound
+    case invalidSession
+    case unknownDevice
+
+    public var description: String {
+        switch self {
+        case .accountDeleted: return "Account no longer exists."
+        case .currentDeviceNotFound: return "Current device not found."
+        case .invalidSession: return "Session token was invalid."
+        case .unknownDevice: return "Unknown device."
+        }
+    }
+}
+
+open class FxADeviceRegistration: NSObject, NSCoding {
+    /// The device identifier identifying this device.  A device is uniquely identified
+    /// across the lifetime of a Firefox Account.
+    public let id: String
+
+    /// The version of the device registration. We use this to re-register
+    /// devices after we update what we send on device registration.
+    let version: Int
+
+    /// The last time we successfully (re-)registered with the server.
+    let lastRegistered: Timestamp
+
+    init(id: String, version: Int, lastRegistered: Timestamp) {
+        self.id = id
+        self.version = version
+        self.lastRegistered = lastRegistered
+    }
+
+    public convenience required init(coder: NSCoder) {
+        let id = coder.decodeObject(forKey: "id") as! String
+        let version = coder.decodeAsInt(forKey: "version")
+        let lastRegistered = coder.decodeAsUInt64(forKey: "lastRegistered")
+        self.init(id: id, version: version, lastRegistered: lastRegistered)
+    }
+
+    open func encode(with aCoder: NSCoder) {
+        aCoder.encode(id, forKey: "id")
+        aCoder.encode(version, forKey: "version")
+        aCoder.encode(NSNumber(value: lastRegistered), forKey: "lastRegistered")
+    }
+
+    open func toJSON() -> JSON {
+        return JSON(object: [
+            "id": id,
+            "version": version,
+            "lastRegistered": lastRegistered,
+        ])
+    }
+}
+
+open class FxADeviceRegistrator {
+    open static func registerOrUpdateDevice(_ account: FirefoxAccount, sessionToken: NSData, client: FxAClient10? = nil) -> Deferred> {
+        // If we've already registered, the registration version is up-to-date, *and* we've (re-)registered
+        // within the last week, do nothing. We re-register weekly as a sanity check.
+        if let registration = account.deviceRegistration, registration.version == DeviceRegistrationVersion &&
+            Date.now() < registration.lastRegistered + OneWeekInMilliseconds {
+                return deferMaybe(FxADeviceRegistrationResult.alreadyRegistered)
+        }
+
+        let pushParams: FxADevicePushParams?
+        if AppConstants.MOZ_FXA_PUSH, let pushRegistration = account.pushRegistration {
+            let subscription = pushRegistration.defaultSubscription
+            pushParams = FxADevicePushParams(callback: subscription.endpoint.absoluteString, publicKey: subscription.p256dhPublicKey, authKey: subscription.authKey)
+        } else {
+            pushParams = nil
+        }
+
+        let client = client ?? FxAClient10(authEndpoint: account.configuration.authEndpointURL, oauthEndpoint: account.configuration.oauthEndpointURL, profileEndpoint: account.configuration.profileEndpointURL)
+        let name = DeviceInfo.defaultClientName()
+        let device: FxADevice
+        let registrationResult: FxADeviceRegistrationResult
+        if let registration = account.deviceRegistration {
+            device = FxADevice.forUpdate(name, id: registration.id, push: pushParams)
+            registrationResult = FxADeviceRegistrationResult.updated
+        } else {
+            device = FxADevice.forRegister(name, type: "mobile", push: pushParams)
+            registrationResult = FxADeviceRegistrationResult.registered
+        }
+
+        let registeredDevice = client.registerOrUpdate(device: device, withSessionToken: sessionToken)
+        let registration: Deferred> = registeredDevice.bind { result in
+            if let device = result.successValue {
+                return deferMaybe(FxADeviceRegistration(id: device.id!, version: DeviceRegistrationVersion, lastRegistered: Date.now()))
+            }
+
+            // Recover from the error -- if we can.
+            if let error = result.failureValue as? FxAClientError,
+               case .remote(let remoteError) = error {
+                switch remoteError.code {
+                case FxAccountRemoteError.DeviceSessionConflict:
+                    return recoverFromDeviceSessionConflict(account, client: client, sessionToken: sessionToken)
+                case FxAccountRemoteError.InvalidAuthenticationToken:
+                    return recoverFromTokenError(account, client: client)
+                case FxAccountRemoteError.UnknownDevice:
+                    return recoverFromUnknownDevice(account)
+                default: break
+                }
+            }
+
+            // Not an error we can recover from. Rethrow it and fall back to the failure handler.
+            return deferMaybe(result.failureValue!)
+        }
+
+        // Post-recovery. We either registered or we didn't, but update the account either way.
+        return registration.bind { result in
+            switch result {
+            case .success(let registration):
+                account.deviceRegistration = registration.value
+                return deferMaybe(registrationResult)
+            case .failure(let error):
+                log.error("Device registration failed: \(error.description)")
+                if let registration = account.deviceRegistration {
+                    account.deviceRegistration = FxADeviceRegistration(id: registration.id, version: 0, lastRegistered: registration.lastRegistered)
+                }
+                return deferMaybe(error)
+            }
+        }
+    }
+
+    fileprivate static func recoverFromDeviceSessionConflict(_ account: FirefoxAccount, client: FxAClient10, sessionToken: NSData) -> Deferred> {
+        // FxA has already associated this session with a different device id.
+        // Perhaps we were beaten in a race to register. Handle the conflict:
+        //   1. Fetch the list of devices for the current user from FxA.
+        //   2. Look for ourselves in the list.
+        //   3. If we find a match, set the correct device id and device registration
+        //      version on the account data and return the correct device id. At next
+        //      sync or next sign-in, registration is retried and should succeed.
+        log.warning("Device session conflict. Attempting to find the current device ID…")
+        return client.devices(withSessionToken: sessionToken) >>== { response in
+            guard let currentDevice = response.devices.find({ $0.isCurrentDevice }) else {
+                return deferMaybe(FxADeviceRegistratorError.currentDeviceNotFound)
+            }
+
+            return deferMaybe(FxADeviceRegistration(id: currentDevice.id!, version: 0, lastRegistered: Date.now()))
+        }
+    }
+
+    fileprivate static func recoverFromTokenError(_ account: FirefoxAccount, client: FxAClient10) -> Deferred> {
+        return client.status(forUID: account.uid) >>== { status in
+            _ = account.makeDoghouse()
+            if !status.exists {
+                // TODO: Should be in an "I have an iOS account, but the FxA is gone." state.
+                // This will do for now...
+                return deferMaybe(FxADeviceRegistratorError.accountDeleted)
+            }
+            return deferMaybe(FxADeviceRegistratorError.invalidSession)
+        }
+    }
+
+    fileprivate static func recoverFromUnknownDevice(_ account: FirefoxAccount) -> Deferred> {
+        // FxA did not recognize the device ID. Handle it by clearing the registration on the account data.
+        // At next sync or next sign-in, registration is retried and should succeed.
+        log.warning("Unknown device ID. Clearing the local device data.")
+        account.deviceRegistration = nil
+        return deferMaybe(FxADeviceRegistratorError.unknownDevice)
+    }
+}
diff --git a/mobile/ios/Account/FxALoginStateMachine.swift b/mobile/ios/Account/FxALoginStateMachine.swift
new file mode 100644
index 0000000000..a10c058822
--- /dev/null
+++ b/mobile/ios/Account/FxALoginStateMachine.swift
@@ -0,0 +1,182 @@
+/* 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/. */
+
+import Foundation
+import FxA
+import Shared
+import XCGLogger
+import Deferred
+
+// TODO: log to an FxA-only, persistent log file.
+private let log = Logger.syncLogger
+
+// TODO: fill this in!
+private let KeyUnwrappingError = NSError(domain: "org.mozilla", code: 1, userInfo: nil)
+
+protocol FxALoginClient {
+    func keyPair() -> Deferred>
+    func keys(_ keyFetchToken: Data) -> Deferred>
+    func sign(_ sessionToken: Data, publicKey: PublicKey) -> Deferred>
+}
+
+class FxALoginStateMachine {
+    let client: FxALoginClient
+
+    // The keys are used as a set, to prevent cycles in the state machine.
+    var stateLabelsSeen = [FxAStateLabel: Bool]()
+
+    init(client: FxALoginClient) {
+        self.client = client
+    }
+
+    func advance(fromState state: FxAState, now: Timestamp) -> Deferred {
+        stateLabelsSeen.updateValue(true, forKey: state.label)
+        return self.advanceOne(fromState: state, now: now).bind { (newState: FxAState) in
+            let labelAlreadySeen = self.stateLabelsSeen.updateValue(true, forKey: newState.label) != nil
+            if labelAlreadySeen {
+                // Last stop!
+                return Deferred(value: newState)
+            }
+            return self.advance(fromState: newState, now: now)
+        }
+    }
+
+    fileprivate func advanceOne(fromState state: FxAState, now: Timestamp) -> Deferred {
+        // For convenience.  Without type annotation, Swift complains about types not being exact.
+        let separated: Deferred = Deferred(value: SeparatedState())
+        let doghouse: Deferred = Deferred(value: DoghouseState())
+        let same: Deferred = Deferred(value: state)
+
+        log.info("Advancing from state: \(state.label.rawValue)")
+        switch state.label {
+        case .married:
+            let state = state as! MarriedState
+            log.debug("Checking key pair freshness.")
+            if state.isKeyPairExpired(now) {
+                log.info("Key pair has expired; transitioning to CohabitingBeforeKeyPair.")
+                return advanceOne(fromState: state.withoutKeyPair(), now: now)
+            }
+            log.debug("Checking certificate freshness.")
+            if state.isCertificateExpired(now) {
+                log.info("Certificate has expired; transitioning to CohabitingAfterKeyPair.")
+                return advanceOne(fromState: state.withoutCertificate(), now: now)
+            }
+            log.info("Key pair and certificate are fresh; staying Married.")
+            return same
+
+        case .cohabitingBeforeKeyPair:
+            let state = state as! CohabitingBeforeKeyPairState
+            log.debug("Generating key pair.")
+            return self.client.keyPair().bind { result in
+                if let keyPair = result.successValue {
+                    log.info("Generated key pair!  Transitioning to CohabitingAfterKeyPair.")
+                    let newState = CohabitingAfterKeyPairState(sessionToken: state.sessionToken,
+                        kA: state.kA, kB: state.kB,
+                        keyPair: keyPair, keyPairExpiresAt: now + OneMonthInMilliseconds)
+                    return Deferred(value: newState)
+                } else {
+                    log.error("Failed to generate key pair!  Something is horribly wrong; transitioning to Separated in the hope that the error is transient.")
+                    return separated
+                }
+            }
+
+        case .cohabitingAfterKeyPair:
+            let state = state as! CohabitingAfterKeyPairState
+            log.debug("Signing public key.")
+            return client.sign(state.sessionToken, publicKey: state.keyPair.publicKey).bind { result in
+                if let response = result.successValue {
+                    log.info("Signed public key!  Transitioning to Married.")
+                    let newState = MarriedState(sessionToken: state.sessionToken,
+                        kA: state.kA, kB: state.kB,
+                        keyPair: state.keyPair, keyPairExpiresAt: state.keyPairExpiresAt,
+                        certificate: response.certificate, certificateExpiresAt: now + OneDayInMilliseconds)
+                    return Deferred(value: newState)
+                } else {
+                    if let error = result.failureValue as? FxAClientError {
+                        switch error {
+                        case let .remote(remoteError):
+                            if remoteError.isUpgradeRequired {
+                                log.error("Upgrade required: \(error.description)!  Transitioning to Doghouse.")
+                                return doghouse
+                            } else if remoteError.isInvalidAuthentication {
+                                log.error("Invalid authentication: \(error.description)!  Transitioning to Separated.")
+                                return separated
+                            } else if remoteError.code < 200 || remoteError.code >= 300 {
+                                log.error("Unsuccessful HTTP request: \(error.description)!  Assuming error is transient and not transitioning.")
+                                return same
+                            } else {
+                                log.error("Unknown error: \(error.description).  Transitioning to Separated.")
+                                return separated
+                            }
+                        case let .local(localError) where localError.domain == NSURLErrorDomain:
+                            log.warning("Local networking error: \(result.failureValue!).  Assuming transient and not transitioning.")
+                            return same
+                        default:
+                            break
+                        }
+                    }
+                    log.error("Unknown error: \(result.failureValue!).  Transitioning to Separated.")
+                    return separated
+                }
+            }
+
+        case .engagedBeforeVerified, .engagedAfterVerified:
+            let state = state as! ReadyForKeys
+            log.debug("Fetching keys.")
+            return client.keys(state.keyFetchToken).bind { result in
+                if let response = result.successValue {
+                    if let kB = response.wrapkB.xoredWith(state.unwrapkB) {
+                        log.info("Unwrapped keys response.  Transition to CohabitingBeforeKeyPair.")
+                        self.notifyAccountVerified()
+                        let newState = CohabitingBeforeKeyPairState(sessionToken: state.sessionToken,
+                            kA: response.kA, kB: kB)
+                        return Deferred(value: newState)
+                    } else {
+                        log.error("Failed to unwrap keys response!  Transitioning to Separated in order to fetch new initial datum.")
+                        return separated
+                    }
+                } else {
+                    if let error = result.failureValue as? FxAClientError {
+                        log.error("Error \(error.description) \(error.description)")
+                        switch error {
+                        case let .remote(remoteError):
+                            if remoteError.isUpgradeRequired {
+                                log.error("Upgrade required: \(error.description)!  Transitioning to Doghouse.")
+                                return doghouse
+                            } else if remoteError.isInvalidAuthentication {
+                                log.error("Invalid authentication: \(error.description)!  Transitioning to Separated in order to fetch new initial datum.")
+                                return separated
+                            } else if remoteError.isUnverified {
+                                log.warning("Account is not yet verified; not transitioning.")
+                                return same
+                            } else if remoteError.code < 200 || remoteError.code >= 300 {
+                                log.error("Unsuccessful HTTP request: \(error.description)!  Assuming error is transient and not transitioning.")
+                                return same
+                            } else {
+                                log.error("Unknown error: \(error.description).  Transitioning to Separated.")
+                                return separated
+                            }
+                        case let .local(localError) where localError.domain == NSURLErrorDomain:
+                            log.warning("Local networking error: \(result.failureValue!).  Assuming transient and not transitioning.")
+                            return same
+                        default:
+                            break
+                        }
+                    }
+                    log.error("Unknown error: \(result.failureValue!).  Transitioning to Separated.")
+                    return separated
+                }
+            }
+
+        case .separated, .doghouse:
+            // We can't advance from the separated state (we need user input) or the doghouse (we need a client upgrade).
+            log.warning("User interaction required; not transitioning.")
+            return same
+        }
+    }
+
+    fileprivate func notifyAccountVerified() {
+        NotificationCenter.default.post(name: NotificationFirefoxAccountVerified, object: nil, userInfo: nil)
+    }
+}
diff --git a/mobile/ios/Account/FxAPushMessageHandler.swift b/mobile/ios/Account/FxAPushMessageHandler.swift
new file mode 100644
index 0000000000..0c209eff91
--- /dev/null
+++ b/mobile/ios/Account/FxAPushMessageHandler.swift
@@ -0,0 +1,294 @@
+/* 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/. */
+
+import Deferred
+import Shared
+import SwiftyJSON
+
+let PendingAccountDisconnectedKey = "PendingAccountDisconnect"
+
+/// This class provides handles push messages from FxA.
+/// For reference, the [message schema][0] and [Android implementation][1] are both useful resources.
+/// [0]: https://github.com/mozilla/fxa-auth-server/blob/master/docs/pushpayloads.schema.json#L26
+/// [1]: https://dxr.mozilla.org/mozilla-central/source/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/FxAccountPushHandler.java
+/// The main entry points are `handle` methods, to accept the raw APNS `userInfo` and then to process the resulting JSON.
+class FxAPushMessageHandler {
+    let profile: Profile
+
+    init(with profile: Profile) {
+        self.profile = profile
+    }
+}
+
+extension FxAPushMessageHandler {
+    /// Accepts the raw Push message from Autopush.
+    /// This method then decrypts it according to the content-encoding (aes128gcm or aesgcm)
+    /// and then effects changes on the logged in account.
+    @discardableResult func handle(userInfo: [AnyHashable: Any]) -> PushMessageResult {
+        guard let subscription = profile.getAccount()?.pushRegistration?.defaultSubscription else {
+            return deferMaybe(PushMessageError.notDecrypted)
+        }
+
+        guard let encoding = userInfo["con"] as? String, // content-encoding
+            let payload = userInfo["body"] as? String else {
+                return handleVerification()
+        }
+        // ver == endpointURL path, chid == channel id, aps == alert text and content_available.
+
+        let plaintext: String?
+        if let cryptoKeyHeader = userInfo["cryptokey"] as? String,  // crypto-key
+            let encryptionHeader = userInfo["enc"] as? String, // encryption
+            encoding == "aesgcm" {
+            plaintext = subscription.aesgcm(payload: payload, encryptionHeader: encryptionHeader, cryptoHeader: cryptoKeyHeader)
+        } else if encoding == "aes128gcm" {
+            plaintext = subscription.aes128gcm(payload: payload)
+        } else {
+            plaintext = nil
+        }
+
+        guard let string = plaintext else {
+            return deferMaybe(PushMessageError.notDecrypted)
+        }
+
+        return handle(plaintext: string)
+    }
+
+    func handle(plaintext: String) -> PushMessageResult {
+        return handle(message: JSON(parseJSON: plaintext))
+    }
+
+    /// The main entry point to the handler for decrypted messages.
+    func handle(message json: JSON) -> PushMessageResult {
+        if !json.isDictionary() || json.isEmpty {
+            return handleVerification()
+        }
+
+        let rawValue = json["command"].stringValue
+        guard let command = PushMessageType(rawValue: rawValue) else {
+            print("Command \(rawValue) received but not recognized")
+            return deferMaybe(PushMessageError.messageIncomplete)
+        }
+
+        let result: PushMessageResult
+        switch command {
+        case .deviceConnected:
+            result = handleDeviceConnected(json["data"])
+        case .deviceDisconnected:
+            result = handleDeviceDisconnected(json["data"])
+        case .profileUpdated:
+            result = handleProfileUpdated()
+        case .passwordChanged:
+            result = handlePasswordChanged()
+        case .passwordReset:
+            result = handlePasswordReset()
+        case .collectionChanged:
+            result = handleCollectionChanged(json["data"])
+        case .accountVerified:
+            result = handleVerification()
+        }
+        return result
+    }
+}
+
+extension FxAPushMessageHandler {
+    func handleVerification() -> PushMessageResult {
+        // What we'd really like to be able to start syncing immediately we receive this
+        // message, but this method is run by the extension, so we can't do it here.
+        return deferMaybe(.accountVerified)
+    }
+
+    // This will be executed by the app, not the extension.
+    // This isn't guaranteed to be run (when the app is backgrounded, and the user
+    // doesn't tap on the notification), but that's okay because:
+    // We'll naturally be syncing shortly after startup.
+    func postVerification() -> Success {
+        if let account = profile.getAccount(),
+            let syncManager = profile.syncManager {
+            return account.advance().bind { _ in
+                return syncManager.syncEverything(why: .didLogin)
+            } >>> succeed
+        }
+        return succeed()
+    }
+}
+
+/// An extension to handle each of the messages.
+extension FxAPushMessageHandler {
+    func handleDeviceConnected(_ data: JSON?) -> PushMessageResult {
+        guard let deviceName = data?["deviceName"].string else {
+            return messageIncomplete(.deviceConnected)
+        }
+        let message = PushMessage.deviceConnected(deviceName)
+        return deferMaybe(message)
+    }
+}
+
+extension FxAPushMessageHandler {
+    func handleDeviceDisconnected(_ data: JSON?) -> PushMessageResult {
+        guard let deviceId = data?["id"].string else {
+            return messageIncomplete(.deviceDisconnected)
+        }
+
+        if let ourDeviceId = self.getOurDeviceId(), deviceId == ourDeviceId {
+            // We can't disconnect the device from the account until we have 
+            // access to the application, so we'll handle this properly in the AppDelegate,
+            // by calling the FxALoginHelper.applicationDidDisonnect(application).
+            profile.prefs.setBool(true, forKey: PendingAccountDisconnectedKey)
+            return deferMaybe(PushMessage.thisDeviceDisconnected)
+        }
+
+        guard let profile = self.profile as? BrowserProfile else {
+            // We can't look up a name in testing, so this is the same as
+            // not knowing about it.
+            return deferMaybe(PushMessage.deviceDisconnected(nil))
+        }
+
+        let clients = profile.remoteClientsAndTabs
+        let getClient = clients.getClient(fxaDeviceId: deviceId)
+        
+        return getClient >>== { device in
+            let message = PushMessage.deviceDisconnected(device?.name)
+            if let id = device?.guid {
+                return clients.deleteClient(guid: id) >>== { _ in deferMaybe(message) }
+            }
+
+            return deferMaybe(message)
+        }
+    }
+
+    fileprivate func getOurDeviceId() -> String? {
+        return profile.getAccount()?.deviceRegistration?.id
+    }
+}
+
+extension FxAPushMessageHandler {
+    func handleProfileUpdated() -> PushMessageResult {
+        return unimplemented(.profileUpdated)
+    }
+}
+
+extension FxAPushMessageHandler {
+    func handlePasswordChanged() -> PushMessageResult {
+        return unimplemented(.passwordChanged)
+    }
+}
+
+extension FxAPushMessageHandler {
+    func handlePasswordReset() -> PushMessageResult {
+        return unimplemented(.passwordReset)
+    }
+}
+
+extension FxAPushMessageHandler {
+    func handleCollectionChanged(_ data: JSON?) -> PushMessageResult {
+        guard let collections = data?["collections"].arrayObject as? [String] else {
+            print("collections_changed received but incomplete: \(data ?? "nil")")
+            return deferMaybe(PushMessageError.messageIncomplete)
+        }
+        // Possible values: "addons", "bookmarks", "history", "forms", "prefs", "tabs", "passwords", "clients"
+
+        // syncManager will only do a subset; others will be ignored.
+        return profile.syncManager.syncNamedCollections(why: .push, names: collections) >>== { deferMaybe(.collectionChanged(collections: collections)) }
+    }
+}
+
+/// Some utility methods
+fileprivate extension FxAPushMessageHandler {
+    func unimplemented(_ messageType: PushMessageType, with param: String? = nil) -> PushMessageResult {
+        if let param = param {
+            print("\(messageType) message received with parameter = \(param), but unimplemented")
+        } else {
+            print("\(messageType) message received, but unimplemented")
+        }
+        return deferMaybe(PushMessageError.unimplemented(messageType))
+    }
+
+    func messageIncomplete(_ messageType: PushMessageType) -> PushMessageResult {
+        print("\(messageType) message received, but incomplete")
+        return deferMaybe(PushMessageError.messageIncomplete)
+    }
+}
+
+enum PushMessageType: String {
+    case deviceConnected = "fxaccounts:device_connected"
+    case deviceDisconnected = "fxaccounts:device_disconnected"
+    case profileUpdated = "fxaccounts:profile_updated"
+    case passwordChanged = "fxaccounts:password_changed"
+    case passwordReset = "fxaccounts:password_reset"
+    case collectionChanged = "sync:collection_changed"
+
+    // This isn't a real message type, just the absence of one.
+    case accountVerified = "account_verified"
+}
+
+enum PushMessage: Equatable {
+    case deviceConnected(String)
+    case deviceDisconnected(String?)
+    case profileUpdated
+    case passwordChanged
+    case passwordReset
+    case collectionChanged(collections: [String])
+    case accountVerified
+
+    // This is returned when we detect that it is us that has been disconnected.
+    case thisDeviceDisconnected
+
+    var messageType: PushMessageType {
+        switch self {
+        case .deviceConnected(_):
+            return .deviceConnected
+        case .deviceDisconnected(_):
+            return .deviceDisconnected
+        case .thisDeviceDisconnected:
+            return .deviceDisconnected
+        case .profileUpdated:
+            return .profileUpdated
+        case .passwordChanged:
+            return .passwordChanged
+        case .passwordReset:
+            return .passwordReset
+        case .collectionChanged(collections: _):
+            return .collectionChanged
+        case .accountVerified:
+            return .accountVerified
+        }
+    }
+
+    public static func ==(lhs: PushMessage, rhs: PushMessage) -> Bool {
+        guard lhs.messageType == rhs.messageType else {
+            return false
+        }
+
+        switch (lhs, rhs) {
+        case (.deviceConnected(let lName), .deviceConnected(let rName)):
+            return lName == rName
+        case (.collectionChanged(let lList), .collectionChanged(let rList)):
+            return lList == rList
+        default:
+            return true
+        }
+    }
+}
+
+typealias PushMessageResult = Deferred>
+
+enum PushMessageError: MaybeErrorType {
+    case notDecrypted
+    case messageIncomplete
+    case unimplemented(PushMessageType)
+    case timeout
+    case accountError
+    case noProfile
+
+    public var description: String {
+        switch self {
+        case .notDecrypted: return "notDecrypted"
+        case .messageIncomplete: return "messageIncomplete"
+        case .unimplemented(let what): return "unimplemented=\(what)"
+        case .timeout: return "timeout"
+        case .accountError: return "accountError"
+        case .noProfile: return "noProfile"
+        }
+    }
+}
diff --git a/mobile/ios/Account/FxAState.swift b/mobile/ios/Account/FxAState.swift
new file mode 100644
index 0000000000..dbd865049c
--- /dev/null
+++ b/mobile/ios/Account/FxAState.swift
@@ -0,0 +1,338 @@
+/* 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/. */
+
+import Foundation
+import FxA
+import Shared
+import SwiftyJSON
+
+// The version of the state schema we persist.
+let StateSchemaVersion = 1
+
+// We want an enum because the set of states is closed.  However, each state has state-specific
+// behaviour, and the state's behaviour accumulates, so each state is a class.  Switch on the
+// label to get exhaustive cases.
+public enum FxAStateLabel: String {
+    case engagedBeforeVerified = "engagedBeforeVerified"
+    case engagedAfterVerified = "engagedAfterVerified"
+    case cohabitingBeforeKeyPair = "cohabitingBeforeKeyPair"
+    case cohabitingAfterKeyPair = "cohabitingAfterKeyPair"
+    case married = "married"
+    case separated = "separated"
+    case doghouse = "doghouse"
+
+    // See http://stackoverflow.com/a/24137319
+    static let allValues: [FxAStateLabel] = [
+        engagedBeforeVerified,
+        engagedAfterVerified,
+        cohabitingBeforeKeyPair,
+        cohabitingAfterKeyPair,
+        married,
+        separated,
+        doghouse,
+    ]
+}
+
+public enum FxAActionNeeded {
+    case none
+    case needsVerification
+    case needsPassword
+    case needsUpgrade
+}
+
+func state(fromJSON json: JSON) -> FxAState? {
+    if json.error != nil {
+        return nil
+    }
+    if let version = json["version"].int {
+        if version == StateSchemaVersion {
+            return stateV1(fromJSON: json)
+        }
+    }
+    return nil
+}
+
+func stateV1(fromJSON json: JSON) -> FxAState? {
+    if let labelString = json["label"].string {
+        if let label = FxAStateLabel(rawValue: labelString) {
+            switch label {
+            case .engagedBeforeVerified:
+                if let
+                    sessionToken = json["sessionToken"].string?.hexDecodedData,
+                    let keyFetchToken = json["keyFetchToken"].string?.hexDecodedData,
+                    let unwrapkB = json["unwrapkB"].string?.hexDecodedData,
+                    let knownUnverifiedAt = json["knownUnverifiedAt"].int64,
+                    let lastNotifiedUserAt = json["lastNotifiedUserAt"].int64 {
+                    return EngagedBeforeVerifiedState(
+                        knownUnverifiedAt: UInt64(knownUnverifiedAt), lastNotifiedUserAt: UInt64(lastNotifiedUserAt),
+                        sessionToken: sessionToken, keyFetchToken: keyFetchToken, unwrapkB: unwrapkB)
+                }
+
+            case .engagedAfterVerified:
+                if let
+                    sessionToken = json["sessionToken"].string?.hexDecodedData,
+                    let keyFetchToken = json["keyFetchToken"].string?.hexDecodedData,
+                    let unwrapkB = json["unwrapkB"].string?.hexDecodedData {
+                    return EngagedAfterVerifiedState(sessionToken: sessionToken, keyFetchToken: keyFetchToken, unwrapkB: unwrapkB)
+                }
+
+            case .cohabitingBeforeKeyPair:
+                if let
+                    sessionToken = json["sessionToken"].string?.hexDecodedData,
+                    let kA = json["kA"].string?.hexDecodedData,
+                    let kB = json["kB"].string?.hexDecodedData {
+                    return CohabitingBeforeKeyPairState(sessionToken: sessionToken, kA: kA, kB: kB)
+                }
+
+            case .cohabitingAfterKeyPair:
+                if let
+                    sessionToken = json["sessionToken"].string?.hexDecodedData,
+                    let kA = json["kA"].string?.hexDecodedData,
+                    let kB = json["kB"].string?.hexDecodedData,
+                    let keyPairJSON = json["keyPair"].dictionaryObject,
+                    let keyPair = RSAKeyPair(jsonRepresentation: keyPairJSON),
+                    let keyPairExpiresAt = json["keyPairExpiresAt"].int64 {
+                        return CohabitingAfterKeyPairState(sessionToken: sessionToken, kA: kA, kB: kB,
+                            keyPair: keyPair, keyPairExpiresAt: UInt64(keyPairExpiresAt))
+                }
+
+            case .married:
+                if let
+                    sessionToken = json["sessionToken"].string?.hexDecodedData,
+                    let kA = json["kA"].string?.hexDecodedData,
+                    let kB = json["kB"].string?.hexDecodedData,
+                    let keyPairJSON = json["keyPair"].dictionaryObject,
+                    let keyPair = RSAKeyPair(jsonRepresentation: keyPairJSON),
+                    let keyPairExpiresAt = json["keyPairExpiresAt"].int64,
+                    let certificate = json["certificate"].string,
+                    let certificateExpiresAt = json["certificateExpiresAt"].int64 {
+                    return MarriedState(sessionToken: sessionToken, kA: kA, kB: kB,
+                        keyPair: keyPair, keyPairExpiresAt: UInt64(keyPairExpiresAt),
+                        certificate: certificate, certificateExpiresAt: UInt64(certificateExpiresAt))
+                }
+
+            case .separated:
+                return SeparatedState()
+
+            case .doghouse:
+                return DoghouseState()
+            }
+        }
+    }
+    return nil
+}
+
+// Not an externally facing state!
+open class FxAState: JSONLiteralConvertible {
+    open var label: FxAStateLabel { return FxAStateLabel.separated } // This is bogus, but we have to do something!
+
+    open var actionNeeded: FxAActionNeeded {
+        // Kind of nice to have this in one place.
+        switch label {
+        case .engagedBeforeVerified: return .needsVerification
+        case .engagedAfterVerified: return .none
+        case .cohabitingBeforeKeyPair: return .none
+        case .cohabitingAfterKeyPair: return .none
+        case .married: return .none
+        case .separated: return .needsPassword
+        case .doghouse: return .needsUpgrade
+        }
+    }
+
+    open func asJSON() -> JSON {
+        return JSON([
+            "version": StateSchemaVersion,
+            "label": self.label.rawValue,
+        ])
+    }
+}
+
+open class SeparatedState: FxAState {
+    override open var label: FxAStateLabel { return FxAStateLabel.separated }
+
+    override public init() {
+        super.init()
+    }
+}
+
+// Not an externally facing state!
+open class TokenState: FxAState {
+    let sessionToken: Data
+
+    init(sessionToken: Data) {
+        self.sessionToken = sessionToken
+        super.init()
+    }
+
+    open override func asJSON() -> JSON {
+        var d: [String: JSON] = super.asJSON().dictionary!
+        d["sessionToken"] = JSON(sessionToken.hexEncodedString as NSString)
+        return JSON(d)
+    }
+}
+
+// Not an externally facing state!
+open class ReadyForKeys: TokenState {
+    let keyFetchToken: Data
+    let unwrapkB: Data
+
+    init(sessionToken: Data, keyFetchToken: Data, unwrapkB: Data) {
+        self.keyFetchToken = keyFetchToken
+        self.unwrapkB = unwrapkB
+        super.init(sessionToken: sessionToken)
+    }
+
+    open override func asJSON() -> JSON {
+        var d: [String: JSON] = super.asJSON().dictionary!
+        d["keyFetchToken"] = JSON(keyFetchToken.hexEncodedString as NSString)
+        d["unwrapkB"] = JSON(unwrapkB.hexEncodedString as NSString)
+        return JSON(d)
+    }
+}
+
+open class EngagedBeforeVerifiedState: ReadyForKeys {
+    override open var label: FxAStateLabel { return FxAStateLabel.engagedBeforeVerified }
+
+    // Timestamp, in milliseconds after the epoch, when we first knew the account was unverified.
+    // Use this to avoid nagging the user to verify her account immediately after connecting.
+    let knownUnverifiedAt: Timestamp
+    let lastNotifiedUserAt: Timestamp
+
+    public init(knownUnverifiedAt: Timestamp, lastNotifiedUserAt: Timestamp, sessionToken: Data, keyFetchToken: Data, unwrapkB: Data) {
+        self.knownUnverifiedAt = knownUnverifiedAt
+        self.lastNotifiedUserAt = lastNotifiedUserAt
+        super.init(sessionToken: sessionToken, keyFetchToken: keyFetchToken, unwrapkB: unwrapkB)
+    }
+
+    open override func asJSON() -> JSON {
+        var d = super.asJSON().dictionary!
+        d["knownUnverifiedAt"] = JSON(NSNumber(value: knownUnverifiedAt))
+        d["lastNotifiedUserAt"] = JSON(NSNumber(value: lastNotifiedUserAt))
+        return JSON(d)
+    }
+
+    func withUnwrapKey(_ unwrapkB: Data) -> EngagedBeforeVerifiedState {
+        return EngagedBeforeVerifiedState(
+            knownUnverifiedAt: knownUnverifiedAt, lastNotifiedUserAt: lastNotifiedUserAt,
+            sessionToken: sessionToken, keyFetchToken: keyFetchToken, unwrapkB: unwrapkB)
+    }
+}
+
+open class EngagedAfterVerifiedState: ReadyForKeys {
+    override open var label: FxAStateLabel { return FxAStateLabel.engagedAfterVerified }
+
+    override public init(sessionToken: Data, keyFetchToken: Data, unwrapkB: Data) {
+        super.init(sessionToken: sessionToken, keyFetchToken: keyFetchToken, unwrapkB: unwrapkB)
+    }
+
+    func withUnwrapKey(_ unwrapkB: Data) -> EngagedAfterVerifiedState {
+        return EngagedAfterVerifiedState(sessionToken: sessionToken, keyFetchToken: keyFetchToken, unwrapkB: unwrapkB)
+    }
+}
+
+// Not an externally facing state!
+open class TokenAndKeys: TokenState {
+    open let kA: Data
+    open let kB: Data
+
+    init(sessionToken: Data, kA: Data, kB: Data) {
+        self.kA = kA
+        self.kB = kB
+        super.init(sessionToken: sessionToken)
+    }
+
+    open override func asJSON() -> JSON {
+        var d = super.asJSON().dictionary!
+        d["kA"] = JSON(kA.hexEncodedString as NSString)
+        d["kB"] = JSON(kB.hexEncodedString as NSString)
+        return JSON(d)
+    }
+}
+
+open class CohabitingBeforeKeyPairState: TokenAndKeys {
+    override open var label: FxAStateLabel { return FxAStateLabel.cohabitingBeforeKeyPair }
+}
+
+// Not an externally facing state!
+open class TokenKeysAndKeyPair: TokenAndKeys {
+    let keyPair: KeyPair
+    // Timestamp, in milliseconds after the epoch, when keyPair expires.  After this time, generate a new keyPair.
+    let keyPairExpiresAt: Timestamp
+
+    init(sessionToken: Data, kA: Data, kB: Data, keyPair: KeyPair, keyPairExpiresAt: Timestamp) {
+        self.keyPair = keyPair
+        self.keyPairExpiresAt = keyPairExpiresAt
+        super.init(sessionToken: sessionToken, kA: kA, kB: kB)
+    }
+
+    open override func asJSON() -> JSON {
+        var d = super.asJSON().dictionary!
+        d["keyPair"] = JSON(keyPair.jsonRepresentation())
+        d["keyPairExpiresAt"] = JSON(NSNumber(value: keyPairExpiresAt))
+        return JSON(d)
+    }
+
+    func isKeyPairExpired(_ now: Timestamp) -> Bool {
+        return keyPairExpiresAt < now
+    }
+}
+
+open class CohabitingAfterKeyPairState: TokenKeysAndKeyPair {
+    override open var label: FxAStateLabel { return FxAStateLabel.cohabitingAfterKeyPair }
+}
+
+open class MarriedState: TokenKeysAndKeyPair {
+    override open var label: FxAStateLabel { return FxAStateLabel.married }
+
+    let certificate: String
+    let certificateExpiresAt: Timestamp
+
+    init(sessionToken: Data, kA: Data, kB: Data, keyPair: KeyPair, keyPairExpiresAt: Timestamp, certificate: String, certificateExpiresAt: Timestamp) {
+        self.certificate = certificate
+        self.certificateExpiresAt = certificateExpiresAt
+        super.init(sessionToken: sessionToken, kA: kA, kB: kB, keyPair: keyPair, keyPairExpiresAt: keyPairExpiresAt)
+    }
+
+    open override func asJSON() -> JSON {
+        var d = super.asJSON().dictionary!
+        d["certificate"] = JSON(certificate as NSString)
+        d["certificateExpiresAt"] = JSON(NSNumber(value: certificateExpiresAt))
+        return JSON(d)
+    }
+
+    func isCertificateExpired(_ now: Timestamp) -> Bool {
+        return certificateExpiresAt < now
+    }
+
+    func withoutKeyPair() -> CohabitingBeforeKeyPairState {
+        let newState = CohabitingBeforeKeyPairState(sessionToken: sessionToken,
+            kA: kA, kB: kB)
+        return newState
+    }
+
+    func withoutCertificate() -> CohabitingAfterKeyPairState {
+        let newState = CohabitingAfterKeyPairState(sessionToken: sessionToken,
+            kA: kA, kB: kB,
+            keyPair: keyPair, keyPairExpiresAt: keyPairExpiresAt)
+        return newState
+    }
+
+    open func generateAssertionForAudience(_ audience: String, now: Timestamp) -> String {
+        let assertion = JSONWebTokenUtils.createAssertionWithPrivateKeyToSign(with: keyPair.privateKey,
+            certificate: certificate,
+            audience: audience,
+            issuer: "127.0.0.1",
+            issuedAt: now,
+            duration: OneHourInMilliseconds)
+        return assertion!
+    }
+}
+
+open class DoghouseState: FxAState {
+    override open var label: FxAStateLabel { return FxAStateLabel.doghouse }
+
+    override public init() {
+        super.init()
+    }
+}
diff --git a/mobile/ios/Account/HawkHelper.swift b/mobile/ios/Account/HawkHelper.swift
new file mode 100644
index 0000000000..55cc23a468
--- /dev/null
+++ b/mobile/ios/Account/HawkHelper.swift
@@ -0,0 +1,150 @@
+/* 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/. */
+
+import Foundation
+import FxA
+import Shared
+
+open class HawkHelper {
+    fileprivate let nonceLengthInBytes: UInt = 8
+
+    let id: String
+    let key: Data
+
+    public init(id: String, key: Data) {
+        self.id = id
+        self.key = key
+    }
+
+    // Produce a HAWK value suitable for an "Authorization: value" header, timestamped now.
+    open func getAuthorizationValueFor(_ request: URLRequest) -> String {
+        let timestampInSeconds: Int64 = Int64(Date().timeIntervalSince1970)
+        return getAuthorizationValueFor(request, at: timestampInSeconds)
+    }
+
+    // Produce a HAWK value suitable for an "Authorization: value" header.
+    func getAuthorizationValueFor(_ request: URLRequest, at timestampInSeconds: Int64) -> String {
+        let nonce = Data.randomOfLength(nonceLengthInBytes)!.base64EncodedString
+        let extra = ""
+        return getAuthorizationValueFor(request, at: timestampInSeconds, nonce: nonce, extra: extra)
+    }
+
+    func getAuthorizationValueFor(_ request: URLRequest, at timestampInSeconds: Int64, nonce: String, extra: String) -> String {
+        let timestampString = String(timestampInSeconds)
+        let hashString = HawkHelper.getPayloadHashFor(request)
+        let requestString = HawkHelper.getRequestStringFor(request, timestampString: timestampString, nonce: nonce, hash: hashString, extra: extra)
+        let macString = HawkHelper.getSignatureFor(requestString.utf8EncodedData, key: self.key)
+
+        let s = NSMutableString(string: "Hawk ")
+        func append(_ key: String, value: String) {
+            s.append(key)
+            s.append("=\"")
+            s.append(value)
+            s.append("\", ")
+        }
+        append("id", value: id)
+        append("ts", value: timestampString)
+        append("nonce", value: nonce)
+        if !hashString.isEmpty {
+            append("hash", value: hashString)
+        }
+        if !extra.isEmpty {
+            append("ext", value: HawkHelper.escapeExtraHeaderAttribute(extra))
+        }
+        append("mac", value: macString)
+        // Drop the trailing "\",".
+        return s.substring(to: s.length - 2)
+    }
+
+    class func getSignatureFor(_ input: Data, key: Data) -> String {
+        return input.hmacSha256WithKey(key).base64EncodedString
+    }
+
+    class func getRequestStringFor(_ request: URLRequest, timestampString: String, nonce: String, hash: String, extra: String) -> String {
+        let s = NSMutableString(string: "hawk.1.header\n")
+        func append(_ line: String) {
+            s.append(line)
+            s.append("\n")
+        }
+        append(timestampString)
+        append(nonce)
+        append((request as NSURLRequest).httpMethod?.uppercased() ?? "GET")
+        let url = request.url!
+        s.append(url.path)
+        if let query = url.query {
+            s.append("?")
+            s.append(query)
+        }
+        if let fragment = url.fragment {
+            s.append("#")
+            s.append(fragment)
+        }
+        s.append("\n")
+        append(url.host!)
+        if let port = (url as NSURL).port {
+            append(String(describing: port))
+        } else {
+            if url.scheme?.lowercased() == "https" {
+                append("443")
+            } else {
+                append("80")
+            }
+        }
+        append(hash)
+        if !extra.isEmpty {
+            append(HawkHelper.escapeExtraString(extra))
+        } else {
+            append("")
+        }
+        return s as String
+    }
+
+    class func getPayloadHashFor(_ request: URLRequest) -> String {
+        if let body = request.httpBody {
+            var d = Data()
+            func append(_ s: String) {
+                let data = s.utf8EncodedData
+                d.append(data)
+            }
+            append("hawk.1.payload\n")
+            append(getBaseContentTypeFor(request.value(forHTTPHeaderField: "Content-Type")))
+            append("\n") // Trailing newline is specified by Hawk.
+            d.append(body)
+            append("\n") // Trailing newline is specified by Hawk.
+            return d.sha256.base64EncodedString
+        } else {
+            return ""
+        }
+    }
+
+    class func getBaseContentTypeFor(_ contentType: String?) -> String {
+        if let contentType = contentType {
+            if let index = contentType.characters.index(of: ";") {
+                return contentType.substring(to: index).trimmingCharacters(in: CharacterSet.whitespaces)
+            } else {
+                return contentType.trimmingCharacters(in: CharacterSet.whitespaces)
+            }
+        } else {
+            return "text/plain"
+        }
+    }
+
+    class func escapeExtraHeaderAttribute(_ extra: String) -> String {
+        return extra.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: "\"", with: "\\\"")
+    }
+
+    class func escapeExtraString(_ extra: String) -> String {
+        return extra.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: "\n", with: "\\n")
+    }
+}
+
+extension URLRequest {
+    mutating func addAuthorizationHeader(forHKDFSHA256Key bytes: Data) {
+        let tokenId = bytes.subdata(in: 0..
+
+
+
+	CFBundleDevelopmentRegion
+	en
+	CFBundleExecutable
+	$(EXECUTABLE_NAME)
+	CFBundleIdentifier
+	$(PRODUCT_BUNDLE_IDENTIFIER)
+	CFBundleInfoDictionaryVersion
+	6.0
+	CFBundleName
+	$(PRODUCT_NAME)
+	CFBundlePackageType
+	FMWK
+	CFBundleShortVersionString
+	10.6
+	CFBundleSignature
+	????
+	CFBundleVersion
+	1
+	NSPrincipalClass
+	
+
+
diff --git a/mobile/ios/Account/SyncAuthState.swift b/mobile/ios/Account/SyncAuthState.swift
new file mode 100644
index 0000000000..40fef5b570
--- /dev/null
+++ b/mobile/ios/Account/SyncAuthState.swift
@@ -0,0 +1,149 @@
+/* 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/. */
+
+import Foundation
+import Shared
+import XCGLogger
+import Deferred
+import SwiftyJSON
+
+private let CurrentSyncAuthStateCacheVersion = 1
+
+private let log = Logger.syncLogger
+
+public struct SyncAuthStateCache {
+    let token: TokenServerToken
+    let forKey: Data
+    let expiresAt: Timestamp
+}
+
+public protocol SyncAuthState {
+    func invalidate()
+    func token(_ now: Timestamp, canBeExpired: Bool) -> Deferred>
+    var deviceID: String? { get }
+}
+
+public func syncAuthStateCachefromJSON(_ json: JSON) -> SyncAuthStateCache? {
+    if let version = json["version"].int {
+        if version != CurrentSyncAuthStateCacheVersion {
+            log.warning("Sync Auth State Cache is wrong version; dropping.")
+            return nil
+        }
+        if let
+            token = TokenServerToken.fromJSON(json["token"]),
+            let forKey = json["forKey"].string?.hexDecodedData,
+            let expiresAt = json["expiresAt"].int64 {
+            return SyncAuthStateCache(token: token, forKey: forKey, expiresAt: Timestamp(expiresAt))
+        }
+    }
+    return nil
+}
+
+extension SyncAuthStateCache: JSONLiteralConvertible {
+    public func asJSON() -> JSON {
+        return JSON([
+            "version": CurrentSyncAuthStateCacheVersion,
+            "token": token.asJSON(),
+            "forKey": forKey.hexEncodedString,
+            "expiresAt": NSNumber(value: expiresAt),
+        ] as NSDictionary)
+    }
+}
+
+open class FirefoxAccountSyncAuthState: SyncAuthState {
+    fileprivate let account: FirefoxAccount
+    fileprivate let cache: KeychainCache
+    public var deviceID: String? {
+        return account.deviceRegistration?.id
+    }
+
+    init(account: FirefoxAccount, cache: KeychainCache) {
+        self.account = account
+        self.cache = cache
+    }
+
+    // If a token gives you a 401, invalidate it and request a new one.
+    open func invalidate() {
+        log.info("Invalidating cached token server token.")
+        self.cache.value = nil
+    }
+
+    // Generate an assertion and try to fetch a token server token, retrying at most a fixed number
+    // of times.
+    //
+    // It's tricky to get Swift to recurse into a closure that captures from the environment without
+    // segfaulting the compiler, so we pass everything around, like barbarians.
+    fileprivate func generateAssertionAndFetchTokenAt(_ audience: String,
+                                                      client: TokenServerClient,
+                                                      clientState: String?,
+                                                      married: MarriedState,
+                                                      now: Timestamp,
+                                                      retryCount: Int) -> Deferred> {
+        let assertion = married.generateAssertionForAudience(audience, now: now)
+        return client.token(assertion, clientState: clientState).bind { result in
+            if retryCount > 0 {
+                if let tokenServerError = result.failureValue as? TokenServerError {
+                    switch tokenServerError {
+                    case let .remote(code, status, remoteTimestamp) where code == 401 && status == "invalid-timestamp":
+                        if let remoteTimestamp = remoteTimestamp {
+                            let skew = Int64(remoteTimestamp) - Int64(now) // Without casts, runtime crash due to overflow.
+                            log.info("Token server responded with 401/invalid-timestamp: retrying with remote timestamp \(remoteTimestamp), which is local timestamp + skew = \(now) + \(skew).")
+                            return self.generateAssertionAndFetchTokenAt(audience, client: client, clientState: clientState, married: married, now: remoteTimestamp, retryCount: retryCount - 1)
+                        }
+                    default:
+                        break
+                    }
+                }
+            }
+            // Fall-through.
+            return Deferred(value: result)
+        }
+    }
+
+    open func token(_ now: Timestamp, canBeExpired: Bool) -> Deferred> {
+        if let value = cache.value {
+            // Give ourselves some room to do work.
+            let isExpired = value.expiresAt < now + 5 * OneMinuteInMilliseconds
+            if canBeExpired {
+                if isExpired {
+                    log.info("Returning cached expired token.")
+                } else {
+                    log.info("Returning cached token, which should be valid.")
+                }
+                return deferMaybe((token: value.token, forKey: value.forKey))
+            }
+
+            if !isExpired {
+                log.info("Returning cached token, which should be valid.")
+                return deferMaybe((token: value.token, forKey: value.forKey))
+            }
+        }
+
+        log.debug("Advancing Account state.")
+        return account.marriedState().bind { result in
+            if let married = result.successValue {
+                log.info("Account is in Married state; generating assertion.")
+                let tokenServerEndpointURL = self.account.configuration.sync15Configuration.tokenServerEndpointURL
+                let audience = TokenServerClient.getAudience(forURL: tokenServerEndpointURL)
+                let client = TokenServerClient(URL: tokenServerEndpointURL)
+                let clientState = FxAClient10.computeClientState(married.kB)
+                log.debug("Fetching token server token.")
+                let deferred = self.generateAssertionAndFetchTokenAt(audience, client: client, clientState: clientState, married: married, now: now, retryCount: 1)
+                deferred.upon { result in
+                    // This could race to update the cache with multiple token results.
+                    // One racer will win -- that's fine, presumably she has the freshest token.
+                    // If not, that's okay, 'cuz the slightly dated token is still a valid token.
+                    if let token = result.successValue {
+                        let newCache = SyncAuthStateCache(token: token, forKey: married.kB,
+                            expiresAt: now + 1000 * token.durationInSeconds)
+                        log.debug("Fetched token server token!  Token expires at \(newCache.expiresAt).")
+                        self.cache.value = newCache
+                    }
+                }
+                return chain(deferred, f: { (token: $0, forKey: married.kB) })
+            }
+            return deferMaybe(result.failureValue!)
+        }
+    }
+}
diff --git a/mobile/ios/Account/TokenServerClient.swift b/mobile/ios/Account/TokenServerClient.swift
new file mode 100644
index 0000000000..7ce70a92cf
--- /dev/null
+++ b/mobile/ios/Account/TokenServerClient.swift
@@ -0,0 +1,189 @@
+/* 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/. */
+
+import Alamofire
+import Shared
+import Foundation
+import Deferred
+import SwiftyJSON
+
+let TokenServerClientErrorDomain = "org.mozilla.token.error"
+let TokenServerClientUnknownError = TokenServerError.local(
+    NSError(domain: TokenServerClientErrorDomain, code: 999,
+    userInfo: [NSLocalizedDescriptionKey: "Invalid server response"]))
+
+public struct TokenServerToken {
+    public let id: String
+    public let key: String
+    public let api_endpoint: String
+    public let uid: UInt64
+    public let hashedFxAUID: String
+    public let durationInSeconds: UInt64
+    // A healthy token server reports its timestamp.
+    public let remoteTimestamp: Timestamp
+
+    /**
+     * Return true if this token points to the same place as the other token.
+     */
+    public func sameDestination(_ other: TokenServerToken) -> Bool {
+        return self.uid == other.uid &&
+               self.api_endpoint == other.api_endpoint
+    }
+
+    public static func fromJSON(_ json: JSON) -> TokenServerToken? {
+        if let
+            id = json["id"].string,
+            let key = json["key"].string,
+            let api_endpoint = json["api_endpoint"].string,
+            let uid = json["uid"].int64,
+            let hashedFxAUID = json["hashed_fxa_uid"].string,
+            let durationInSeconds = json["duration"].int64,
+            let remoteTimestamp = json["remoteTimestamp"].int64 {
+                return TokenServerToken(id: id, key: key, api_endpoint: api_endpoint, uid: UInt64(uid),
+                                        hashedFxAUID: hashedFxAUID, durationInSeconds: UInt64(durationInSeconds),
+                                        remoteTimestamp: Timestamp(remoteTimestamp))
+        }
+        return nil
+    }
+
+    public func asJSON() -> JSON {
+        let D: [String: AnyObject] = [
+            "id": id as AnyObject,
+            "key": key as AnyObject,
+            "api_endpoint": api_endpoint as AnyObject,
+            "uid": NSNumber(value: uid as UInt64),
+            "hashed_fxa_uid": hashedFxAUID as AnyObject,
+            "duration": NSNumber(value: durationInSeconds as UInt64),
+            "remoteTimestamp": NSNumber(value: remoteTimestamp),
+        ]
+        return JSON(D as NSDictionary)
+    }
+}
+
+enum TokenServerError {
+    // A Remote error definitely has a status code, but we may not have a well-formed JSON response
+    // with a status; and we could have an unhealthy server that is not reporting its timestamp.
+    case remote(code: Int32, status: String?, remoteTimestamp: Timestamp?)
+    case local(NSError)
+}
+
+extension TokenServerError: MaybeErrorType {
+    var description: String {
+        switch self {
+        case let .remote(code: code, status: status, remoteTimestamp: _):
+            if let status = status {
+                return ""
+            } else {
+                return ""
+            }
+        case let .local(error):
+            return ""
+        }
+    }
+}
+
+open class TokenServerClient {
+    let URL: URL
+
+    public init(URL: URL? = nil) {
+        self.URL = URL ?? ProductionSync15Configuration().tokenServerEndpointURL
+    }
+
+    open class func getAudience(forURL URL: URL) -> String {
+        if let port = URL.port {
+            return "\(URL.scheme!)://\(URL.host!):\(port)"
+        } else {
+            return "\(URL.scheme!)://\(URL.host!)"
+        }
+    }
+
+    fileprivate class func parseTimestampHeader(_ header: String?) -> Timestamp? {
+        if let timestampString = header {
+            return decimalSecondsStringToTimestamp(timestampString)
+        } else {
+            return nil
+        }
+    }
+
+    fileprivate class func remoteError(fromJSON json: JSON, statusCode: Int, remoteTimestampHeader: String?) -> TokenServerError? {
+        if json.error != nil {
+            return nil
+        }
+        if 200 <= statusCode && statusCode <= 299 {
+            return nil
+        }
+        return TokenServerError.remote(code: Int32(statusCode), status: json["status"].string,
+            remoteTimestamp: parseTimestampHeader(remoteTimestampHeader))
+    }
+
+    fileprivate class func token(fromJSON json: JSON, remoteTimestampHeader: String?) -> TokenServerToken? {
+        if json.error != nil {
+            return nil
+        }
+        if let
+            remoteTimestamp = parseTimestampHeader(remoteTimestampHeader), // A token server that is not providing its timestamp is not healthy.
+            let id = json["id"].string,
+            let key = json["key"].string,
+            let api_endpoint = json["api_endpoint"].string,
+            let uid = json["uid"].int,
+            let hashedFxAUID = json["hashed_fxa_uid"].string,
+            let durationInSeconds = json["duration"].int64, durationInSeconds > 0 {
+            return TokenServerToken(id: id, key: key, api_endpoint: api_endpoint, uid: UInt64(uid),
+                                    hashedFxAUID: hashedFxAUID, durationInSeconds: UInt64(durationInSeconds),
+                                    remoteTimestamp: remoteTimestamp)
+        }
+        return nil
+    }
+
+    lazy fileprivate var alamofire: SessionManager = {
+        let ua = UserAgent.tokenServerClientUserAgent
+        let configuration = URLSessionConfiguration.ephemeral
+        var defaultHeaders = SessionManager.default.session.configuration.httpAdditionalHeaders ?? [:]
+        defaultHeaders["User-Agent"] = ua
+        configuration.httpAdditionalHeaders = defaultHeaders
+        return SessionManager(configuration: configuration)
+    }()
+
+    open func token(_ assertion: String, clientState: String? = nil) -> Deferred> {
+        let deferred = Deferred>()
+
+        var mutableURLRequest = URLRequest(url: URL)
+        mutableURLRequest.setValue("BrowserID " + assertion, forHTTPHeaderField: "Authorization")
+        if let clientState = clientState {
+            mutableURLRequest.setValue(clientState, forHTTPHeaderField: "X-Client-State")
+        }
+
+        alamofire.request(mutableURLRequest)
+                 .validate(contentType: ["application/json"])
+                 .responseJSON { response in
+
+                    // Don't cancel requests just because our Manager is deallocated.
+                    withExtendedLifetime(self.alamofire) {
+                        if let error = response.result.error {
+                            deferred.fill(Maybe(failure: TokenServerError.local(error as NSError)))
+                            return
+                        }
+
+                        if let data = response.result.value as AnyObject? { // Declaring the type quiets a Swift warning about inferring AnyObject.
+                            let json = JSON(data)
+                            let remoteTimestampHeader = response.response?.allHeaderFields["X-Timestamp"] as? String
+
+                            if let remoteError = TokenServerClient.remoteError(fromJSON: json, statusCode: response.response!.statusCode,
+                                remoteTimestampHeader: remoteTimestampHeader) {
+                                    deferred.fill(Maybe(failure: remoteError))
+                                    return
+                            }
+
+                            if let token = TokenServerClient.token(fromJSON: json, remoteTimestampHeader: remoteTimestampHeader) {
+                                deferred.fill(Maybe(success: token))
+                                return
+                            }
+                        }
+
+                        deferred.fill(Maybe(failure: TokenServerClientUnknownError))
+                    }
+        }
+        return deferred
+    }
+}
diff --git a/mobile/ios/AccountTests/FirefoxAccountTests.swift b/mobile/ios/AccountTests/FirefoxAccountTests.swift
new file mode 100644
index 0000000000..1622d80a92
--- /dev/null
+++ b/mobile/ios/AccountTests/FirefoxAccountTests.swift
@@ -0,0 +1,63 @@
+/* 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/. */
+
+@testable import Account
+import Shared
+import UIKit
+
+import XCTest
+
+class FirefoxAccountTests: XCTestCase {
+    override func setUp() {
+        super.setUp()
+        continueAfterFailure = false
+    }
+
+    func testSerialization() {
+        let ogPushSub = PushSubscription(channelID: "channel-id",
+                                       endpoint: URL(string: "https://mozilla.com")!,
+                                       p256dhPrivateKey: "private-key",
+                                       p256dhPublicKey: "public-key",
+                                       authKey: "auth-key")
+
+        let d: [String: Any] = [
+            "version": 1,
+            "configurationLabel": FirefoxAccountConfigurationLabel.production.rawValue,
+            "email": "testtest@test.com",
+            "uid": "uid",
+            "deviceRegistration": FxADeviceRegistration(id: "bogus-device", version: 0, lastRegistered: Date.now()),
+            "pushRegistration": PushRegistration(uaid: "bogus-device-uaid", secret: "secret", subscription: ogPushSub),
+        ]
+
+        let account1 = FirefoxAccount(
+                configuration: FirefoxAccountConfigurationLabel.production.toConfiguration(),
+                email: d["email"] as! String,
+                uid: d["uid"] as! String,
+                deviceRegistration: (d["deviceRegistration"] as! FxADeviceRegistration),
+                stateKeyLabel: Bytes.generateGUID(),
+                state: SeparatedState())
+
+        account1.pushRegistration = d["pushRegistration"] as? PushRegistration
+
+        let d1 = account1.dictionary()
+
+        let account2 = FirefoxAccount.fromDictionary(d1)
+        XCTAssertNotNil(account2)
+        let d2 = account2!.dictionary()
+
+        for (k, v) in d {
+            // Skip version, which is an Int.
+            if let s = v as? String {
+                XCTAssertEqual(s, d1[k] as? String, "Value for '\(k)' does not agree for manually created account.")
+                XCTAssertEqual(s, d2[k] as? String, "Value for '\(k)' does not agree for deserialized account.")
+            }
+        }
+
+        if let pubSub = account2?.pushRegistration?.defaultSubscription {
+            XCTAssertEqual(pubSub, ogPushSub)
+        } else {
+            XCTFail("PushSubscription did not get decoded")
+        }
+    }
+}
diff --git a/mobile/ios/AccountTests/FxAClient10Tests.swift b/mobile/ios/AccountTests/FxAClient10Tests.swift
new file mode 100644
index 0000000000..3250c76ad7
--- /dev/null
+++ b/mobile/ios/AccountTests/FxAClient10Tests.swift
@@ -0,0 +1,165 @@
+/* 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/. */
+
+@testable import Account
+import FxA
+import Shared
+import UIKit
+import Deferred
+
+import XCTest
+
+class FxAClient10Tests: LiveAccountTest {
+    func testUnwrapKey() {
+        let stretchedPW = "e4e8889bd8bd61ad6de6b95c059d56e7b50dacdaf62bd84644af7e2add84345d".hexDecodedData
+        let unwrapKey = FxAClient10.computeUnwrapKey(stretchedPW)
+        XCTAssertEqual(unwrapKey.hexEncodedString, "de6a2648b78284fcb9ffa81ba95803309cfba7af583c01a8a1a63e567234dd28")
+    }
+
+    func testClientState() {
+        let kB = "fd5c747806c07ce0b9d69dcfea144663e630b65ec4963596a22f24910d7dd15d".hexDecodedData
+        let clientState = FxAClient10.computeClientState(kB)!
+        XCTAssertEqual(clientState, "6ae94683571c7a7c54dab4700aa3995f")
+    }
+
+    func testErrorOutput() {
+        // Make sure we don't hide error details.
+        let error = NSError(domain: "test", code: 123, userInfo: nil)
+
+        let localError = FxAClientError.local(error)
+        XCTAssertEqual(
+            localError.description,
+            "")
+        XCTAssertEqual(
+            "\(localError)",
+            "")
+
+        let remoteError = FxAClientError.remote(RemoteError(code: 401, errno: 104,
+            error: "error", message: "message", info: "info"))
+        XCTAssertEqual(
+            remoteError.description,
+            "")
+        XCTAssertEqual(
+            "\(remoteError)",
+            "")
+    }
+
+    func testLoginSuccess() {
+        withVerifiedAccount { emailUTF8, quickStretchedPW in
+            let e = self.expectation(description: "")
+
+            let client = FxAClient10()
+            let result = client.login(emailUTF8, quickStretchedPW: quickStretchedPW, getKeys: true)
+            result.upon { result in
+                if let response = result.successValue {
+                    XCTAssertNotNil(response.uid)
+                    XCTAssertEqual(response.verified, true)
+                    XCTAssertNotNil(response.sessionToken)
+                    XCTAssertNotNil(response.keyFetchToken)
+                } else {
+                    XCTAssertEqual(result.failureValue!.description, "")
+                }
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testLoginFailure() {
+        withVerifiedAccount { emailUTF8, _ in
+            let e = self.expectation(description: "")
+
+            let badPassword = FxAClient10.quickStretchPW(emailUTF8, password: "BAD PASSWORD".utf8EncodedData)
+
+            let client = FxAClient10()
+            let result = client.login(emailUTF8, quickStretchedPW: badPassword, getKeys: true)
+            result.upon { result in
+                if let response = result.successValue {
+                    XCTFail("Got response: \(response)")
+                } else {
+                    if let error = result.failureValue as? FxAClientError {
+                        switch error {
+                        case let .remote(remoteError):
+                            XCTAssertEqual(remoteError.code, Int32(400)) // Bad auth.
+                            XCTAssertEqual(remoteError.errno, Int32(103)) // Incorrect password.
+                        case let .local(error):
+                            XCTAssertEqual(error.description, "")
+                        }
+                    } else {
+                        XCTAssertEqual(result.failureValue!.description, "")
+                    }
+                }
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testKeysSuccess() {
+        withVerifiedAccount { emailUTF8, quickStretchedPW in
+            let e = self.expectation(description: "")
+
+            let client = FxAClient10()
+            let login: Deferred> = client.login(emailUTF8, quickStretchedPW: quickStretchedPW, getKeys: true)
+            let keys: Deferred> = login.bind { (result: Maybe) in
+                switch result {
+                case let .failure(error):
+                    return Deferred(value: .failure(error))
+                case let .success(loginResponse):
+                    return client.keys(loginResponse.value.keyFetchToken)
+                }
+            }
+            keys.upon { result in
+                if let response = result.successValue {
+                    XCTAssertEqual(32, response.kA.count)
+                    XCTAssertEqual(32, response.wrapkB.count)
+                } else {
+                    XCTAssertEqual(result.failureValue!.description, "")
+                }
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testSignSuccess() {
+        withVerifiedAccount { emailUTF8, quickStretchedPW in
+            let e = self.expectation(description: "")
+
+            let client = FxAClient10()
+            let login: Deferred> = client.login(emailUTF8, quickStretchedPW: quickStretchedPW, getKeys: true)
+            let sign: Deferred> = login.bind { (result: Maybe) in
+                switch result {
+                case let .failure(error):
+                    return Deferred(value: .failure(error))
+                case let .success(loginResponse):
+                    let keyPair = RSAKeyPair.generate(withModulusSize: 1024)!
+                    return client.sign(loginResponse.value.sessionToken, publicKey: keyPair.publicKey)
+                }
+            }
+            sign.upon { result in
+                if let response = result.successValue {
+                    XCTAssertNotNil(response.certificate)
+                    // A simple test that we got a reasonable certificate back.
+                    XCTAssertEqual(3, response.certificate.components(separatedBy: ".").count)
+                } else {
+                    XCTAssertEqual(result.failureValue!.description, "")
+                }
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+    
+    func testProfileSuccess() {
+        withVerifiedAccountNoExpectations { emailUTF8, quickStretchedPW in
+            let stageConfiguration = StageFirefoxAccountConfiguration()
+            let client = FxAClient10(authEndpoint: stageConfiguration.authEndpointURL, oauthEndpoint: stageConfiguration.oauthEndpointURL, profileEndpoint: stageConfiguration.profileEndpointURL)
+            let response = (client.login(emailUTF8, quickStretchedPW: quickStretchedPW, getKeys: true) >>== { login in
+                return client.getProfile(withSessionToken: login.sessionToken as NSData)
+            }).value.successValue
+            XCTAssertNotNil(response?.uid)
+        }
+    }
+}
diff --git a/mobile/ios/AccountTests/FxALoginStateMachineTests.swift b/mobile/ios/AccountTests/FxALoginStateMachineTests.swift
new file mode 100644
index 0000000000..3a20e0fba5
--- /dev/null
+++ b/mobile/ios/AccountTests/FxALoginStateMachineTests.swift
@@ -0,0 +1,249 @@
+/* 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/. */
+
+@testable import Account
+import Foundation
+import FxA
+import Shared
+import Deferred
+
+import XCTest
+
+class MockFxALoginClient: FxALoginClient {
+    // Fixed per mock client, for testing.
+    let kA = Data.randomOfLength(UInt(KeyLength))!
+    let wrapkB = Data.randomOfLength(UInt(KeyLength))!
+
+    func keyPair() -> Deferred> {
+        let keyPair: KeyPair = RSAKeyPair.generate(withModulusSize: 512)
+        return Deferred(value: Maybe(success: keyPair))
+    }
+
+    func keys(_ keyFetchToken: Data) -> Deferred> {
+        let response = FxAKeysResponse(kA: kA, wrapkB: wrapkB)
+        return Deferred(value: Maybe(success: response))
+    }
+
+    func sign(_ sessionToken: Data, publicKey: PublicKey) -> Deferred> {
+        let response = FxASignResponse(certificate: "certificate")
+        return Deferred(value: Maybe(success: response))
+    }
+}
+
+// A mock client that fails locally (i.e., cannot connect to the network).
+class MockFxALoginClientWithoutNetwork: MockFxALoginClient {
+    override func keys(_ keyFetchToken: Data) -> Deferred> {
+        // Fail!
+        return Deferred(value: Maybe(failure: FxAClientError.local(NSError(domain: NSURLErrorDomain, code: -1000, userInfo: nil))))
+    }
+
+    override func sign(_ sessionToken: Data, publicKey: PublicKey) -> Deferred> {
+        // Fail!
+        return Deferred(value: Maybe(failure: FxAClientError.local(NSError(domain: NSURLErrorDomain, code: -1000, userInfo: nil))))
+    }
+}
+
+// A mock client that responds to keys and sign with 401 errors.
+class MockFxALoginClientAfterPasswordChange: MockFxALoginClient {
+    override func keys(_ keyFetchToken: Data) -> Deferred> {
+        let response = FxAClientError.remote(RemoteError(code: 401, errno: 103, error: "Bad auth", message: "Bad auth message", info: "Bad auth info"))
+        return Deferred(value: Maybe(failure: response))
+    }
+
+    override func sign(_ sessionToken: Data, publicKey: PublicKey) -> Deferred> {
+        let response = FxAClientError.remote(RemoteError(code: 401, errno: 103, error: "Bad auth", message: "Bad auth message", info: "Bad auth info"))
+        return Deferred(value: Maybe(failure: response))
+    }
+}
+
+// A mock client that responds to keys with 400/104 (needs verification responses).
+class MockFxALoginClientBeforeVerification: MockFxALoginClient {
+    override func keys(_ keyFetchToken: Data) -> Deferred> {
+        let response = FxAClientError.remote(RemoteError(code: 400, errno: 104,
+            error: "Unverified", message: "Unverified message", info: "Unverified info"))
+        return Deferred(value: Maybe(failure: response))
+    }
+}
+
+// A mock client that responds to sign with 503/999 (unknown server error).
+class MockFxALoginClientDuringOutage: MockFxALoginClient {
+    override func sign(_ sessionToken: Data, publicKey: PublicKey) -> Deferred> {
+        let response = FxAClientError.remote(RemoteError(code: 503, errno: 999,
+            error: "Unknown", message: "Unknown error", info: "Unknown err info"))
+        return Deferred(value: Maybe(failure: response))
+    }
+}
+
+class FxALoginStateMachineTests: XCTestCase {
+    let marriedState = FxAStateTests.stateForLabel(FxAStateLabel.married) as! MarriedState
+
+    override func setUp() {
+        super.setUp()
+        self.continueAfterFailure = false
+    }
+
+    func withMachine(_ client: FxALoginClient, callback: (FxALoginStateMachine) -> Void) {
+        let stateMachine = FxALoginStateMachine(client: client)
+        callback(stateMachine)
+    }
+
+    func withMachineAndClient(_ callback: (FxALoginStateMachine, MockFxALoginClient) -> Void) {
+        let client = MockFxALoginClient()
+        withMachine(client) { stateMachine in
+            callback(stateMachine, client)
+        }
+    }
+
+    func testAdvanceWhenInteractionRequired() {
+        // The simple cases are when we get to Separated and Doghouse.  There's nothing to do!
+        // We just have to wait for user interaction.
+        for stateLabel in [FxAStateLabel.separated, FxAStateLabel.doghouse] {
+            let e = expectation(description: "Wait for login state machine.")
+            let state = FxAStateTests.stateForLabel(stateLabel)
+            withMachineAndClient { stateMachine, _ in
+                stateMachine.advance(fromState: state, now: 0).upon { newState in
+                    XCTAssertEqual(newState.label, stateLabel)
+                    e.fulfill()
+                }
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromEngagedBeforeVerified() {
+        // Advancing from engaged before verified stays put.
+        let e = self.expectation(description: "Wait for login state machine.")
+        let engagedState = (FxAStateTests.stateForLabel(.engagedBeforeVerified) as! EngagedBeforeVerifiedState)
+        withMachine(MockFxALoginClientBeforeVerification()) { stateMachine in
+            stateMachine.advance(fromState: engagedState, now: engagedState.knownUnverifiedAt).upon { newState in
+                XCTAssertEqual(newState.label.rawValue, engagedState.label.rawValue)
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromEngagedAfterVerified() {
+        // Advancing from an Engaged state correctly XORs the keys.
+        withMachineAndClient { stateMachine, client in
+            // let unwrapkB = Bytes.generateRandomBytes(UInt(KeyLength))
+            let unwrapkB = client.wrapkB // This way we get all 0s, which is easy to test.
+            let engagedState = (FxAStateTests.stateForLabel(.engagedAfterVerified) as! EngagedAfterVerifiedState).withUnwrapKey(unwrapkB)
+
+            let e = self.expectation(description: "Wait for login state machine.")
+            stateMachine.advance(fromState: engagedState, now: 0).upon { newState in
+                XCTAssertEqual(newState.label.rawValue, FxAStateLabel.married.rawValue)
+                if let newState = newState as? MarriedState {
+                    // We get kA from the client directly.
+                    XCTAssertEqual(newState.kA.hexEncodedString, client.kA.hexEncodedString)
+                    // We unwrap kB by XORing.  The result is KeyLength (32) 0s.
+                    XCTAssertEqual(newState.kB.hexEncodedString, "0000000000000000000000000000000000000000000000000000000000000000")
+                }
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromEngagedAfterVerifiedWithoutNetwork() {
+        // Advancing from engaged after verified, but during outage, stays put.
+        withMachine(MockFxALoginClientWithoutNetwork()) { stateMachine in
+            let engagedState = FxAStateTests.stateForLabel(.engagedAfterVerified)
+
+            let e = self.expectation(description: "Wait for login state machine.")
+            stateMachine.advance(fromState: engagedState, now: 0).upon { newState in
+                XCTAssertEqual(newState.label.rawValue, engagedState.label.rawValue)
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromCohabitingAfterVerifiedDuringOutage() {
+        // Advancing from engaged after verified, but during outage, stays put.
+        let e = self.expectation(description: "Wait for login state machine.")
+        let state = (FxAStateTests.stateForLabel(.cohabitingAfterKeyPair) as! CohabitingAfterKeyPairState)
+        withMachine(MockFxALoginClientDuringOutage()) { stateMachine in
+            stateMachine.advance(fromState: state, now: 0).upon { newState in
+                XCTAssertEqual(newState.label.rawValue, state.label.rawValue)
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromCohabitingAfterVerifiedWithoutNetwork() {
+        // Advancing from cohabiting after verified, but when the network is not available, stays put.
+        let e = self.expectation(description: "Wait for login state machine.")
+        let state = (FxAStateTests.stateForLabel(.cohabitingAfterKeyPair) as! CohabitingAfterKeyPairState)
+        withMachine(MockFxALoginClientWithoutNetwork()) { stateMachine in
+            stateMachine.advance(fromState: state, now: 0).upon { newState in
+                XCTAssertEqual(newState.label.rawValue, state.label.rawValue)
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromMarried() {
+        // Advancing from a healthy Married state is easy.
+        let e = self.expectation(description: "Wait for login state machine.")
+        withMachineAndClient { stateMachine, _ in
+            stateMachine.advance(fromState: self.marriedState, now: 0).upon { newState in
+                XCTAssertEqual(newState.label, FxAStateLabel.married)
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromMarriedWithExpiredCertificate() {
+        // Advancing from a Married state with an expired certificate gets back to Married.
+        let e = self.expectation(description: "Wait for login state machine.")
+        let now = self.marriedState.certificateExpiresAt + OneWeekInMilliseconds + 1
+        withMachineAndClient { stateMachine, _ in
+            stateMachine.advance(fromState: self.marriedState, now: now).upon { newState in
+                XCTAssertEqual(newState.label.rawValue, FxAStateLabel.married.rawValue)
+                if let newState = newState as? MarriedState {
+                    // We should have a fresh certificate.
+                    XCTAssertLessThan(self.marriedState.certificateExpiresAt, now)
+                    XCTAssertGreaterThan(newState.certificateExpiresAt, now)
+                }
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromMarriedWithExpiredKeyPair() {
+        // Advancing from a Married state with an expired keypair gets back to Married too.
+        let e = self.expectation(description: "Wait for login state machine.")
+        let now = self.marriedState.certificateExpiresAt + OneMonthInMilliseconds + 1
+        withMachineAndClient { stateMachine, _ in
+            stateMachine.advance(fromState: self.marriedState, now: now).upon { newState in
+                XCTAssertEqual(newState.label.rawValue, FxAStateLabel.married.rawValue)
+                if let newState = newState as? MarriedState {
+                    // We should have a fresh key pair (and certificate, but we don't verify that).
+                    XCTAssertLessThan(self.marriedState.keyPairExpiresAt, now)
+                    XCTAssertGreaterThan(newState.keyPairExpiresAt, now)
+                }
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func testAdvanceFromMarriedAfterPasswordChange() {
+        // Advancing from a Married state with a 401 goes to Separated if it needs a new certificate.
+        let e = self.expectation(description: "Wait for login state machine.")
+        let now = self.marriedState.certificateExpiresAt + OneDayInMilliseconds + 1
+        withMachine(MockFxALoginClientAfterPasswordChange()) { stateMachine in
+            stateMachine.advance(fromState: self.marriedState, now: now).upon { newState in
+                XCTAssertEqual(newState.label.rawValue, FxAStateLabel.separated.rawValue)
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+}
diff --git a/mobile/ios/AccountTests/FxAStateTests.swift b/mobile/ios/AccountTests/FxAStateTests.swift
new file mode 100644
index 0000000000..06f7d2428f
--- /dev/null
+++ b/mobile/ios/AccountTests/FxAStateTests.swift
@@ -0,0 +1,81 @@
+/* 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/. */
+
+@testable import Account
+import FxA
+import Shared
+import SwiftyJSON
+
+import XCTest
+
+class FxAStateTests: XCTestCase {
+    class func stateForLabel(_ label: FxAStateLabel) -> FxAState {
+        let keyLength = UInt(KeyLength) // Ah, Swift.
+        let now = Date.now()
+
+        switch label {
+        case .engagedBeforeVerified:
+            return EngagedBeforeVerifiedState(
+                knownUnverifiedAt: now + 1, lastNotifiedUserAt: now + 2,
+                sessionToken: Data.randomOfLength(keyLength)!,
+                keyFetchToken: Data.randomOfLength(keyLength)!,
+                unwrapkB: Data.randomOfLength(keyLength)!)
+
+        case .engagedAfterVerified:
+            return EngagedAfterVerifiedState(
+                sessionToken: Data.randomOfLength(keyLength)!,
+                keyFetchToken: Data.randomOfLength(keyLength)!,
+                unwrapkB: Data.randomOfLength(keyLength)!)
+
+        case .cohabitingBeforeKeyPair:
+            return CohabitingBeforeKeyPairState(sessionToken: Data.randomOfLength(keyLength)!,
+                kA: Data.randomOfLength(keyLength)!, kB: Data.randomOfLength(keyLength)!)
+
+        case .cohabitingAfterKeyPair:
+            let keyPair = RSAKeyPair.generate(withModulusSize: 512)!
+            return CohabitingAfterKeyPairState(sessionToken: Data.randomOfLength(keyLength)!,
+                kA: Data.randomOfLength(keyLength)!, kB: Data.randomOfLength(keyLength)!,
+                keyPair: keyPair, keyPairExpiresAt: now + 1)
+
+        case .married:
+            let keyPair = RSAKeyPair.generate(withModulusSize: 512)!
+            return MarriedState(sessionToken: Data.randomOfLength(keyLength)!,
+                kA: Data.randomOfLength(keyLength)!, kB: Data.randomOfLength(keyLength)!,
+                keyPair: keyPair, keyPairExpiresAt: now + 1,
+                certificate: "certificate", certificateExpiresAt: now + 2)
+
+        case .separated:
+            return SeparatedState()
+
+        case .doghouse:
+            return DoghouseState()
+        }
+    }
+
+    func testSerialization() {
+        // Journal of Negative Results: make sure we aren't *always* succeeding.
+        // This Married state will have an earlier timestamp than the one generated after the loop.
+        let state1 = FxAStateTests.stateForLabel(.married) as! MarriedState
+
+        for stateLabel in FxAStateLabel.allValues {
+            let stateFromLabel = FxAStateTests.stateForLabel(stateLabel)
+            let d = stateFromLabel.asJSON()
+            if let e = state(fromJSON:d)?.asJSON() {
+                // We can't compare arbitrary Swift Dictionary instances directly, but the following appears to work.
+                XCTAssertEqual(
+                    NSDictionary(dictionary: d.dictionaryObject!),
+                    NSDictionary(dictionary: e.dictionaryObject!))
+            } else {
+                XCTFail("Expected to create state.")
+            }
+        }
+
+        // This Married state will have a later timestamp than the one generated before the loop.
+        let state2 = FxAStateTests.stateForLabel(.married) as! MarriedState
+        // We can't compare arbitrary Swift Dictionary instances directly, but the following appears to work.
+        XCTAssertNotEqual(
+            NSDictionary(dictionary: state1.asJSON().dictionaryObject!),
+            NSDictionary(dictionary: state2.asJSON().dictionaryObject!))
+    }
+}
diff --git a/mobile/ios/AccountTests/HawkHelperTests.swift b/mobile/ios/AccountTests/HawkHelperTests.swift
new file mode 100644
index 0000000000..db0a9b3b89
--- /dev/null
+++ b/mobile/ios/AccountTests/HawkHelperTests.swift
@@ -0,0 +1,90 @@
+/* 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/. */
+
+@testable import Account
+import Alamofire
+import Foundation
+import FxA
+
+import XCTest
+
+class HawkHelperTests: XCTestCase {
+    func testSpecSignatureExample() {
+        let input = "hawk.1.header\n" +
+        "1353832234\n" +
+        "j4h3g2\n" +
+        "GET\n" +
+        "/resource/1?b=1&a=2\n" +
+        "example.com\n" +
+        "8000\n" +
+        "\n" +
+        "some-app-ext-data\n"
+
+        let expected = HawkHelper.getSignatureFor(input.utf8EncodedData, key: "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".utf8EncodedData)
+        XCTAssertEqual("6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=", expected)
+    }
+
+    func testSpecRequestString() {
+        let timestamp = Int64(1353832234)
+        let nonce = "j4h3g2"
+        let extra = "some-app-ext-data"
+
+        let req = Alamofire.request(URL(string: "http://example.com:8000/resource/1?b=1&a=2")!)
+        let expected = "hawk.1.header\n" +
+            "1353832234\n" +
+            "j4h3g2\n" +
+            "GET\n" +
+            "/resource/1?b=1&a=2\n" +
+            "example.com\n" +
+            "8000\n" +
+            "\n" +
+            "some-app-ext-data\n"
+        XCTAssertEqual(HawkHelper.getRequestStringFor(req.request!, timestampString: String(timestamp), nonce: nonce, hash: "", extra: extra).components(separatedBy: "\n"),
+            expected.components(separatedBy: "\n"))
+    }
+
+    func testSpecWithoutPayloadExample() {
+        let helper = HawkHelper(id: "dh37fgj492je",
+            key: "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".utf8EncodedData)
+        let req = Alamofire.request(URL(string: "http://example.com:8000/resource/1?b=1&a=2")!)
+        let timestamp = Int64(1353832234)
+        let nonce = "j4h3g2"
+        let extra = "some-app-ext-data"
+        let value = helper.getAuthorizationValueFor(req.request!, at: timestamp, nonce: nonce, extra: extra)
+        let expected = "Hawk id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", ext=\"some-app-ext-data\", mac=\"6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\""
+        XCTAssertEqual(value, expected)
+    }
+
+    func testSpecWithPayloadExample() {
+        let helper = HawkHelper(id: "dh37fgj492je",
+            key: "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".utf8EncodedData)
+        let body = "Thank you for flying Hawk"
+
+        let req = Alamofire.request("http://example.com:8000/resource/1?b=1&a=2", method: .post, parameters: [:], encoding: URF8BodyEncoding(body: body))
+        let timestamp = Int64(1353832234)
+        let nonce = "j4h3g2"
+        let extra = "some-app-ext-data"
+        let value = helper.getAuthorizationValueFor(req.request!, at: timestamp, nonce: nonce, extra: extra)
+        let expected = "Hawk id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", hash=\"Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\", ext=\"some-app-ext-data\", mac=\"aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw=\""
+        XCTAssertEqual(value, expected)
+    }
+
+    func testGetBaseContentType() {
+        XCTAssertEqual("text/plain", HawkHelper.getBaseContentTypeFor("text/plain"))
+        XCTAssertEqual("text/plain", HawkHelper.getBaseContentTypeFor("text/plain;one"))
+        XCTAssertEqual("text/plain", HawkHelper.getBaseContentTypeFor("text/plain;one;two"))
+        XCTAssertEqual("text/html", HawkHelper.getBaseContentTypeFor("text/html;charset=UTF-8"))
+        XCTAssertEqual("text/html", HawkHelper.getBaseContentTypeFor("text/html; charset=UTF-8"))
+        XCTAssertEqual("text/html", HawkHelper.getBaseContentTypeFor("text/html ;charset=UTF-8"))
+    }
+}
+
+struct URF8BodyEncoding: ParameterEncoding {
+    var body: String
+    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
+        var mutableRequest = urlRequest.urlRequest
+        mutableRequest?.httpBody = body.utf8EncodedData
+        return mutableRequest!
+    }
+}
diff --git a/mobile/ios/AccountTests/Info.plist b/mobile/ios/AccountTests/Info.plist
new file mode 100644
index 0000000000..9411e4a06e
--- /dev/null
+++ b/mobile/ios/AccountTests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+	CFBundleDevelopmentRegion
+	en
+	CFBundleExecutable
+	$(EXECUTABLE_NAME)
+	CFBundleIdentifier
+	$(PRODUCT_BUNDLE_IDENTIFIER)
+	CFBundleInfoDictionaryVersion
+	6.0
+	CFBundleName
+	$(PRODUCT_NAME)
+	CFBundlePackageType
+	BNDL
+	CFBundleShortVersionString
+	10.6
+	CFBundleSignature
+	????
+	CFBundleVersion
+	1
+
+
diff --git a/mobile/ios/AccountTests/LiveAccountTest.swift b/mobile/ios/AccountTests/LiveAccountTest.swift
new file mode 100644
index 0000000000..a1d389a8a2
--- /dev/null
+++ b/mobile/ios/AccountTests/LiveAccountTest.swift
@@ -0,0 +1,158 @@
+/* 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/. */
+
+@testable import Account
+import Foundation
+import FxA
+import Shared
+import Deferred
+import SwiftyJSON
+
+import XCTest
+
+// Note: All live account tests have been disabled. Please see https://bugzilla.mozilla.org/show_bug.cgi?id=1332028.
+
+/*
+ * A base test type for tests that need a live Firefox Account.
+ */
+open class LiveAccountTest: XCTestCase {
+    lazy var signedInUser: JSON? = {
+        if let path = Bundle(for: type(of: self)).path(forResource: "signedInUser.json", ofType: nil) {
+            if let contents = try? String(contentsOfFile: path, encoding: String.Encoding.utf8) {
+                let json = JSON(parseJSON: contents)
+                if json.isError() {
+                    return nil
+                }
+                if let email = json["email"].string {
+                    return json
+                } else {
+                    // This is the standard case: signedInUser.json is {}.
+                    return nil
+                }
+            }
+        }
+        XCTFail("Expected to read signedInUser.json!")
+        return nil
+    }()
+
+    // It's not easy to have an optional resource, so we always include signedInUser.json in the test bundle.
+    // If signedInUser.json contains an email address, we use that email address.
+    // Since there's no way to get the corresponding password (from any client!), we assume that any
+    // test account has password identical to its email address.
+    fileprivate func withExistingAccount(_ mustBeVerified: Bool, completion: (Data, Data) -> Void) {
+        // If we don't create at least one expectation, waitForExpectations fails.
+        // So we unconditionally create one, even though the callback may not execute.
+        self.expectation(description: "withExistingAccount").fulfill()
+        if let json = self.signedInUser {
+            if mustBeVerified {
+                XCTAssertTrue(json["verified"].bool ?? false)
+            }
+            let email = json["email"].stringValue
+            let password = json["password"].stringValue
+            let emailUTF8 = email.utf8EncodedData
+            let passwordUT8 = password.utf8EncodedData
+            let stretchedPW = FxAClient10.quickStretchPW(emailUTF8, password: passwordUT8)
+            completion(emailUTF8, stretchedPW)
+        } else {
+            // This is the standard case: signedInUser.json is {}.
+            NSLog("Skipping test because signedInUser.json does not include email address.")
+        }
+    }
+
+    func withVerifiedAccount(_ completion: (Data, Data) -> Void) {
+        withExistingAccount(true, completion: completion)
+    }
+    
+    // Helper function that waits for expectations to clear
+    func withVerifiedAccountNoExpectations(_ completion: (Data, Data) -> Void) {
+        withExistingAccount(true, completion: completion)
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+
+    func withCertificate(_ completion: @escaping (XCTestExpectation, Data, KeyPair, String) -> Void) {
+        withVerifiedAccount { emailUTF8, quickStretchedPW in
+            let expectation = self.expectation(description: "withCertificate")
+
+            let keyPair = RSAKeyPair.generate(withModulusSize: 1024)!
+            let client = FxAClient10()
+            let login: Deferred> = client.login(emailUTF8, quickStretchedPW: quickStretchedPW, getKeys: true)
+            let sign: Deferred> = login.bind { (result: Maybe) in
+                switch result {
+                case let .failure(error):
+                    expectation.fulfill()
+                    return Deferred(value: .failure(error))
+                case let .success(loginResponse):
+                    return client.sign(loginResponse.value.sessionToken, publicKey: keyPair.publicKey)
+                }
+            }
+            sign.upon { result in
+                if let response = result.successValue {
+                    XCTAssertNotNil(response.certificate)
+                    completion(expectation, emailUTF8, keyPair, response.certificate)
+                } else {
+                    XCTAssertEqual(result.failureValue!.description, "")
+                    expectation.fulfill()
+                }
+            }
+        }
+    }
+
+    public enum AccountError: MaybeErrorType {
+        case badParameters
+        case noSignedInUser
+        case unverifiedSignedInUser
+
+        public var description: String {
+            switch self {
+            case .badParameters: return "Bad account parameters (email, password, or a derivative thereof)."
+            case .noSignedInUser: return "No signedInUser.json (missing, no email, etc)."
+            case .unverifiedSignedInUser: return "signedInUser.json describes an unverified account."
+            }
+        }
+    }
+
+    // Internal helper.
+    func account(_ email: String, password: String, configuration: FirefoxAccountConfiguration) -> Deferred> {
+        let client = FxAClient10(authEndpoint: configuration.authEndpointURL)
+        let emailUTF8 = email.utf8EncodedData
+        let passwordUTF8 = password.utf8EncodedData
+        let quickStretchedPW = FxAClient10.quickStretchPW(emailUTF8, password: passwordUTF8)
+        let login = client.login(emailUTF8, quickStretchedPW: quickStretchedPW, getKeys: true)
+        return login.bind { result in
+            if let response = result.successValue {
+                let unwrapkB = FxAClient10.computeUnwrapKey(quickStretchedPW)
+                return Deferred(value: Maybe(success: FirefoxAccount.from(configuration, andLoginResponse: response, unwrapkB: unwrapkB)))
+            } else {
+                return Deferred(value: Maybe(failure: result.failureValue!))
+            }
+        }
+    }
+
+    func getTestAccount() -> Deferred> {
+        // TODO: Use signedInUser.json here.  It's hard to include the same resource file in two Xcode targets.
+        return self.account("998797987.sync@restmail.net", password: "998797987.sync@restmail.net",
+            configuration: ProductionFirefoxAccountConfiguration())
+    }
+
+    open func getAuthState(_ now: Timestamp) -> Deferred> {
+        let account = self.getTestAccount()
+        print("Got test account.")
+        return account.map { result in
+            print("Result was successful? \(result.isSuccess)")
+            if let account = result.successValue {
+                return Maybe(success: account.syncAuthState)
+            }
+            return Maybe(failure: result.failureValue!)
+        }
+    }
+
+    open func syncAuthState(_ now: Timestamp) -> Deferred> {
+        return getAuthState(now).bind { result in
+            if let authState = result.successValue {
+                return authState.token(now, canBeExpired: false)
+            }
+            return Deferred(value: Maybe(failure: result.failureValue!))
+        }
+    }
+}
diff --git a/mobile/ios/AccountTests/SyncAuthStateTests.swift b/mobile/ios/AccountTests/SyncAuthStateTests.swift
new file mode 100644
index 0000000000..a441c98a03
--- /dev/null
+++ b/mobile/ios/AccountTests/SyncAuthStateTests.swift
@@ -0,0 +1,32 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+@testable import Account
+import Foundation
+import FxA
+import Shared
+import UIKit
+
+import XCTest
+
+class SyncAuthStateTests: LiveAccountTest {
+    func testLive() {
+        let e = self.expectation(description: "Wait for token.")
+        syncAuthState(Date.now()).upon { result in
+            if let (token, forKey) = result.successValue {
+                let uidString = NSNumber(value: token.uid).stringValue
+                XCTAssertTrue(token.api_endpoint.endsWith(uidString))
+                XCTAssertNotNil(forKey)
+            } else {
+                if let error = result.failureValue as? AccountError {
+                    XCTAssertEqual(error, AccountError.noSignedInUser)
+                } else {
+                    XCTAssertEqual(result.failureValue!.description, "")
+                }
+            }
+            e.fulfill()
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+}
diff --git a/mobile/ios/AccountTests/TokenServerClientTests.swift b/mobile/ios/AccountTests/TokenServerClientTests.swift
new file mode 100644
index 0000000000..846758d2af
--- /dev/null
+++ b/mobile/ios/AccountTests/TokenServerClientTests.swift
@@ -0,0 +1,112 @@
+/* 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/. */
+
+@testable import Account
+import Foundation
+import FxA
+import Shared
+import UIKit
+
+import XCTest
+
+// Testing client state is so delicate that I'm not going to test this.  The test below does two
+// requests; we would need a third, and a guarantee of the server state, to test this completely.
+// The rule is: if you turn up with a never-before-seen client state; you win.  If you turn up with
+// a seen-before client state, you lose.
+class TokenServerClientTests: LiveAccountTest {
+    func testErrorOutput() {
+        // Make sure we don't hide error details.
+        let error = NSError(domain: "test", code: 123, userInfo: nil)
+        XCTAssertEqual(
+            "",
+            TokenServerError.local(error).description)
+    }
+
+    func testAudienceForEndpoint() {
+        func audienceFor(_ endpoint: String) -> String {
+            return TokenServerClient.getAudience(forURL: URL(string: endpoint)!)
+        }
+
+        // Sub-domains and path components.
+        XCTAssertEqual("http://sub.test.com", audienceFor("http://sub.test.com"))
+        XCTAssertEqual("http://test.com", audienceFor("http://test.com/"))
+        XCTAssertEqual("http://test.com", audienceFor("http://test.com/path/component"))
+        XCTAssertEqual("http://test.com", audienceFor("http://test.com/path/component/"))
+
+        // No port and default port.
+        XCTAssertEqual("http://test.com", audienceFor("http://test.com"))
+        XCTAssertEqual("http://test.com:80", audienceFor("http://test.com:80"))
+
+        XCTAssertEqual("https://test.com", audienceFor("https://test.com"))
+        XCTAssertEqual("https://test.com:443", audienceFor("https://test.com:443"))
+
+        // Ports that are the default ports for a different scheme.
+        XCTAssertEqual("https://test.com:80", audienceFor("https://test.com:80"))
+        XCTAssertEqual("http://test.com:443", audienceFor("http://test.com:443"))
+
+        // Arbitrary ports.
+        XCTAssertEqual("http://test.com:8080", audienceFor("http://test.com:8080"))
+        XCTAssertEqual("https://test.com:4430", audienceFor("https://test.com:4430"))
+    }
+
+    func testTokenSuccess() {
+        let audience = TokenServerClient.getAudience(forURL: ProductionSync15Configuration().tokenServerEndpointURL)
+
+        withCertificate { expectation, emailUTF8, keyPair, certificate in
+            let assertion = JSONWebTokenUtils.createAssertionWithPrivateKeyToSign(with: keyPair.privateKey,
+                certificate: certificate, audience: audience)
+
+            let client = TokenServerClient()
+            client.token(assertion!).upon { result in
+                if let token = result.successValue {
+                    XCTAssertNotNil(token.id)
+                    XCTAssertNotNil(token.key)
+                    XCTAssertNotNil(token.api_endpoint)
+                    XCTAssertNotNil(token.hashedFxAUID)
+                    XCTAssertTrue(token.uid >= 0)
+                    XCTAssertTrue(token.api_endpoint.hasSuffix(String(token.uid)))
+                    let expectedRemoteTimestamp: Timestamp = 1429121686000
+                    XCTAssertTrue(token.remoteTimestamp >= expectedRemoteTimestamp) // Not a special timestamp; just a sanity check.
+                } else {
+                    XCTAssertEqual(result.failureValue!.description, "")
+                }
+                expectation.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 100, handler: nil)
+    }
+
+    func testTokenFailure() {
+        withVerifiedAccount { _, _ in
+            // Account details aren't used, but we want to skip when we're not running live tests.
+            let e = self.expectation(description: "")
+
+            let assertion = "BAD ASSERTION"
+
+            let client = TokenServerClient()
+            client.token(assertion).upon { result in
+                if let token = result.successValue {
+                    XCTFail("Got token: \(token)")
+                } else {
+                    if let error = result.failureValue as? TokenServerError {
+                        switch error {
+                        case let .remote(code, status, remoteTimestamp):
+                            XCTAssertEqual(code, Int32(401)) // Bad auth.
+                            XCTAssertEqual(status!, "error")
+                            XCTAssertFalse(remoteTimestamp == nil)
+                            let expectedRemoteTimestamp: Timestamp = 1429121686000
+                            XCTAssertTrue(remoteTimestamp! >= expectedRemoteTimestamp) // Not a special timestamp; just a sanity check.
+                        case let .local(error):
+                            XCTAssertNil(error)
+                        }
+                    } else {
+                        XCTFail("Expected TokenServerError")
+                    }
+                }
+                e.fulfill()
+            }
+        }
+        self.waitForExpectations(timeout: 10, handler: nil)
+    }
+}
diff --git a/mobile/ios/Cartfile b/mobile/ios/Cartfile
new file mode 100644
index 0000000000..92985f159f
--- /dev/null
+++ b/mobile/ios/Cartfile
@@ -0,0 +1,18 @@
+github "getsentry/sentry-cocoa"             "3.11.1"
+github "Alamofire/Alamofire"                ~> 4.0
+github "sleroux/Deferred"                   "Swift3.0"
+github "SnapKit/SnapKit"                    "3.1.2"
+github "rs/SDWebImage"                      "4.1.0"
+github "swisspol/GCDWebServer"              "3.3.2"
+github "kif-framework/KIF"                  "v3.6.0"
+github "adjust/ios_sdk"                     "v4.11.5"
+github "AgileBits/onepassword-extension"    "new/carthage+ios10"
+github "mozilla/readability"                "master"
+github "jrendel/SwiftKeychainWrapper"       "3.0.1"
+github "DaveWoodCom/XCGLogger"              "Version_4.0.0"
+github "cezheng/Fuzi"                       "1.0.1"
+github "SwiftyJSON/SwiftyJSON"              "3.1.4"
+github "farhanpatel/JSONSchema.swift"       "master"
+github "google/EarlGrey"                    "1.12.1"
+github "jhugman/SwiftRouter"                "master"
+github "mozilla-mobile/telemetry-ios"       "v1.0.10"
diff --git a/mobile/ios/Cartfile.resolved b/mobile/ios/Cartfile.resolved
new file mode 100644
index 0000000000..abc624f3de
--- /dev/null
+++ b/mobile/ios/Cartfile.resolved
@@ -0,0 +1,18 @@
+github "getsentry/sentry-cocoa" "3.11.1"
+github "Alamofire/Alamofire" "4.3.0"
+github "sleroux/Deferred" "35b8927c1b94ce074e10793c57e1f80d0e2227fa"
+github "cezheng/Fuzi" "1.0.1"
+github "swisspol/GCDWebServer" "3.3.2"
+github "kif-framework/KIF" "v3.6.0"
+github "SnapKit/SnapKit" "3.1.2"
+github "jrendel/SwiftKeychainWrapper" "3.0.1"
+github "DaveWoodCom/XCGLogger" "Version_4.0.0"
+github "adjust/ios_sdk" "v4.11.5"
+github "AgileBits/onepassword-extension" "a614e290396346e3cb69e4951656eb8033390f8c"
+github "mozilla/readability" "ccc8e9bf4c5400814d9b7a3ea83c21540da4c76f"
+github "SwiftyJSON/SwiftyJSON" "3.1.4"
+github "farhanpatel/JSONSchema.swift" "1c052b83baa8c497e12cde6a8afca0f54574612f"
+github "google/EarlGrey" "1.12.1"
+github "jhugman/SwiftRouter" "7b446fd063846ce2961b7518bb2386ffcbcc94d8"
+github "rs/SDWebImage" "4.1.0"
+github "mozilla-mobile/telemetry-ios" "v1.0.10"
diff --git a/mobile/ios/Client-Bridging-Header.h b/mobile/ios/Client-Bridging-Header.h
new file mode 100644
index 0000000000..485e3abdca
--- /dev/null
+++ b/mobile/ios/Client-Bridging-Header.h
@@ -0,0 +1,18 @@
+#ifndef Client_Client_Bridging_Header_h
+#define Client_Client_Bridging_Header_h
+
+#import 
+#import 
+
+#import "FSReadingList.h"
+#import "Try.h"
+
+#import "ThirdParty/UIImageViewAligned/UIImageViewAligned/UIImageViewAligned.h"
+#import "ThirdParty/Apple/UIImage+ImageEffects.h"
+
+#import 
+
+#import "Shared-Bridging-Header.h"
+#import "Storage-Bridging-Header.h"
+
+#endif
diff --git a/mobile/ios/Client.xcodeproj/project.pbxproj b/mobile/ios/Client.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..f27661167a
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/project.pbxproj
@@ -0,0 +1,9468 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		03CCC9181AF05E7300DBF30D /* RelativeDatesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CCC9171AF05E7300DBF30D /* RelativeDatesTests.swift */; };
+		0B1C05D71A798B1F004C78B0 /* UIImageViewAligned.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B1C05D61A798B1F004C78B0 /* UIImageViewAligned.m */; };
+		0B21E8061E26CCB7000C8779 /* EarlGrey.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0B21E8051E26CCB7000C8779 /* EarlGrey.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+		0B305E1B1E3A98A900BE0767 /* BookmarkingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B305E1A1E3A98A900BE0767 /* BookmarkingTests.swift */; };
+		0B3D670E1E09B90B00C1EFC7 /* AuthenticationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3D670D1E09B90B00C1EFC7 /* AuthenticationTest.swift */; };
+		0B3E7D951B27A7CE00E2E84D /* AboutHomeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3E7D931B27A7CE00E2E84D /* AboutHomeHandler.swift */; };
+		0B54BD191B698B7C004C822C /* SuggestedSites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B54BD181B698B7C004C822C /* SuggestedSites.swift */; };
+		0B5A93221B1EB4C8004F47A2 /* ReadingListTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B5A93211B1EB4C8004F47A2 /* ReadingListTest.swift */; };
+		0B5A93421B1EB572004F47A2 /* readablePage.html in Resources */ = {isa = PBXBuildFile; fileRef = 0B5A93411B1EB572004F47A2 /* readablePage.html */; };
+		0B62EFD21AD63CD100ACB9CD /* Clearables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B62EFD11AD63CD100ACB9CD /* Clearables.swift */; };
+		0B6FBAB21AC1F830007EC669 /* numberedPage.html in Resources */ = {isa = PBXBuildFile; fileRef = 0B6FBAB11AC1F830007EC669 /* numberedPage.html */; };
+		0B729D371E047D6A008E6859 /* HomePageSettingsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B729D361E047D6A008E6859 /* HomePageSettingsTest.swift */; };
+		0B742CCF1B32493E00EE9264 /* libsqlcipher.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B742CCC1B32491400EE9264 /* libsqlcipher.a */; };
+		0B75AEA91AC20FB20015E5DC /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B8E0FF31A932BD500161DC3 /* ImageIO.framework */; };
+		0B75AEAA1AC20FBC0015E5DC /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B8E0FF31A932BD500161DC3 /* ImageIO.framework */; };
+		0B7C1E951F6097AD006A8869 /* TrackingProtectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B7C1E941F6097AD006A8869 /* TrackingProtectionTests.swift */; };
+		0B8E0FF41A932BD500161DC3 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B8E0FF31A932BD500161DC3 /* ImageIO.framework */; };
+		0BA1E00E1B03FB0B007675AF /* NetError.html in Resources */ = {isa = PBXBuildFile; fileRef = 0BA1E00D1B03FB0B007675AF /* NetError.html */; };
+		0BA1E02E1B046F1E007675AF /* ErrorPageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA1E02D1B046F1E007675AF /* ErrorPageHelper.swift */; };
+		0BA1E0301B051A07007675AF /* NetError.css in Resources */ = {isa = PBXBuildFile; fileRef = 0BA1E02F1B051A07007675AF /* NetError.css */; };
+		0BA8964B1A250E6500C1010C /* ProfileTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA896491A250E6500C1010C /* ProfileTest.swift */; };
+		0BA8964C1A250E6500C1010C /* TestBookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA8964A1A250E6500C1010C /* TestBookmarks.swift */; };
+		0BB5B2881AC0A2B90052877D /* SnackBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB5B2861AC0A2B90052877D /* SnackBar.swift */; };
+		0BB5B2891AC0A2B90052877D /* Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB5B2871AC0A2B90052877D /* Toolbar.swift */; };
+		0BB5B30B1AC0AD1F0052877D /* LoginsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB5B30A1AC0AD1F0052877D /* LoginsHelper.swift */; };
+		0BC9C9C41F26F54D000E8AB5 /* SiteLoadTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BC9C9C31F26F54D000E8AB5 /* SiteLoadTest.swift */; };
+		0BD19A671A25309B0084FBA7 /* NSUserDefaultsPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD19A661A25309B0084FBA7 /* NSUserDefaultsPrefs.swift */; };
+		0BDA568B1B26B1BE008C9B96 /* LoginsHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = 0BDA568A1B26B1BE008C9B96 /* LoginsHelper.js */; };
+		0BDA56B01B26B1D5008C9B96 /* TestLogins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BDA56AE1B26B1D5008C9B96 /* TestLogins.swift */; };
+		0BDA56B21B26B1E4008C9B96 /* Logins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BDA56B11B26B1E4008C9B96 /* Logins.swift */; };
+		0BDA56B41B26B203008C9B96 /* SQLiteLogins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BDA56B31B26B203008C9B96 /* SQLiteLogins.swift */; };
+		0BEF44631E31165700187C32 /* EarlGrey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEF44621E31165700187C32 /* EarlGrey.swift */; };
+		0BF0DB4A1E57B05E009172B0 /* LaunchArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075861E37F7AB006961AC /* LaunchArguments.swift */; };
+		0BF0DB941A8545800039F300 /* URLBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF0DB931A8545800039F300 /* URLBarView.swift */; };
+		0BF1B7E31AC60DEA00A7B407 /* InsetButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF1B7E21AC60DEA00A7B407 /* InsetButton.swift */; };
+		0BF42D371A7C0B8E00889E28 /* FaviconManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D361A7C0B8E00889E28 /* FaviconManager.swift */; };
+		0BF42D391A7C0E8900889E28 /* Favicons.js in Resources */ = {isa = PBXBuildFile; fileRef = 0BF42D381A7C0E8900889E28 /* Favicons.js */; };
+		0BF42D4F1A7CD09600889E28 /* TestFavicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D4E1A7CD09600889E28 /* TestFavicons.swift */; };
+		0BF8F8DA1AEFF1C900E90BC2 /* noTitle.html in Resources */ = {isa = PBXBuildFile; fileRef = 0BF8F8D91AEFF1C900E90BC2 /* noTitle.html */; };
+		19DE1F671EC13B6400428B8C /* LeanplumIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DE1F661EC13B6400428B8C /* LeanplumIntegration.swift */; };
+		2805F5A61B8BCA7A00268FD1 /* ReadingList.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4D567181ADECE2700F1EFE7 /* ReadingList.framework */; };
+		28078A471B1507EF0053B46A /* ReadingList.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4D567181ADECE2700F1EFE7 /* ReadingList.framework */; };
+		280CB1371C20E0A3005AF147 /* BookmarksSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 280CB1361C20E0A3005AF147 /* BookmarksSynchronizer.swift */; };
+		28126F481C2F948E006466CC /* SQLiteBookmarksHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28126F471C2F948E006466CC /* SQLiteBookmarksHelpers.swift */; };
+		28126F6E1C2F94F9006466CC /* SQLiteBookmarksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28126F6D1C2F94F9006466CC /* SQLiteBookmarksModel.swift */; };
+		28126F741C2F96F1006466CC /* SQLiteBookmarksResetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28126F731C2F96F1006466CC /* SQLiteBookmarksResetting.swift */; };
+		28126F771C2F9833006466CC /* SQLiteBookmarksBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28126F761C2F9833006466CC /* SQLiteBookmarksBase.swift */; };
+		2816F0001B33E05400522243 /* UIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2816EFFF1B33E05400522243 /* UIConstants.swift */; };
+		281B029A1C037C1F005202C3 /* TestBrowserDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 281B02991C037C1F005202C3 /* TestBrowserDB.swift */; };
+		281B2BEA1ADF4D90002917DC /* MockProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 281B2BE91ADF4D90002917DC /* MockProfile.swift */; };
+		282731631ABC9BE600AA1954 /* Sync-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = 282731621ABC9BE600AA1954 /* Sync-Bridging-Header.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		282731691ABC9BE700AA1954 /* Sync.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2827315E1ABC9BE600AA1954 /* Sync.framework */; };
+		282731751ABC9BE700AA1954 /* Sync.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2827315E1ABC9BE600AA1954 /* Sync.framework */; };
+		282731991ABC9C2F00AA1954 /* ClientPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28CE83BB1A1D1D3200576538 /* ClientPayload.swift */; };
+		2827319A1ABC9C2F00AA1954 /* KeyBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28CE83BC1A1D1D3200576538 /* KeyBundle.swift */; };
+		2827319B1ABC9C2F00AA1954 /* KeysPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28CE83BD1A1D1D3200576538 /* KeysPayload.swift */; };
+		2827319C1ABC9C2F00AA1954 /* Record.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28CE83BE1A1D1D3200576538 /* Record.swift */; };
+		2827319D1ABC9C2F00AA1954 /* SyncMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28CE83BF1A1D1D3200576538 /* SyncMeta.swift */; };
+		2827319E1ABC9C5900AA1954 /* RecordTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C0779D1A3B066000834FE5 /* RecordTests.swift */; };
+		28293BB51B333EA2004A65EC /* ReadingList.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4D567181ADECE2700F1EFE7 /* ReadingList.framework */; };
+		2829D37A1C2F0A7F00DCF931 /* BookmarksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2829D3791C2F0A7F00DCF931 /* BookmarksModel.swift */; };
+		2829D3A01C2F0AD400DCF931 /* Sharing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2829D39F1C2F0AD400DCF931 /* Sharing.swift */; };
+		282DA4731A68C1E700A406E2 /* OpenSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3FA77831A43B2CE0010CD32 /* OpenSearch.swift */; };
+		28302E401AF0747800521E2E /* DatabaseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28302E3F1AF0747800521E2E /* DatabaseError.swift */; };
+		283586FD1C73F18E00A55435 /* CachingItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 283586FC1C73F18E00A55435 /* CachingItemSource.swift */; };
+		2852B8441C51996B00591EAC /* Trees.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2852B8431C51996B00591EAC /* Trees.swift */; };
+		28532BE91C471FFB000072D9 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FEBABAE1AB3659000DB5728 /* ResultTests.swift */; };
+		28532BEA1C472008000072D9 /* DeferredTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28786E541AB0F5FA009EA9EF /* DeferredTests.swift */; };
+		28532BEB1C472015000072D9 /* UtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A6CE891AC082E200C1A2D4 /* UtilsTests.swift */; };
+		28532CC11C473977000072D9 /* MockFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2791ABB533A00877008 /* MockFiles.swift */; };
+		28532CE61C48098D000072D9 /* ThreeWayTreeMerger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28532CE51C48098D000072D9 /* ThreeWayTreeMerger.swift */; };
+		28532D321C483E3D000072D9 /* CompletionOps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28532D311C483E3D000072D9 /* CompletionOps.swift */; };
+		2853C5411AD84C6800C4F31D /* TabsPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2853C5401AD84C6800C4F31D /* TabsPayload.swift */; };
+		2855611F1AEFFA1C00D5ED5B /* HistorySynchronizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2855611E1AEFFA1C00D5ED5B /* HistorySynchronizerTests.swift */; };
+		285D37E31ABCA69E000E1CF9 /* CryptoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C077971A3B064000834FE5 /* CryptoTests.swift */; };
+		285D3B681B4380B70035FD22 /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285D3B671B4380B70035FD22 /* Queue.swift */; };
+		285D3B901B4386520035FD22 /* SQLiteQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285D3B8F1B4386520035FD22 /* SQLiteQueue.swift */; };
+		285F2DC11AF80B4600211843 /* SQLiteBookmarksSyncing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F2DC01AF80B4600211843 /* SQLiteBookmarksSyncing.swift */; };
+		2868FA061ADF7B69000D9B1D /* Sync.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2827315E1ABC9BE600AA1954 /* Sync.framework */; };
+		2868FA231ADF7B70000D9B1D /* Sync.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2827315E1ABC9BE600AA1954 /* Sync.framework */; };
+		287AC8661AF4776D00101515 /* TestSQLiteHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE27D1ABB533A00877008 /* TestSQLiteHistory.swift */; };
+		288501DE1AC0F61D00E7F670 /* RequestExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 288501DD1AC0F61D00E7F670 /* RequestExtensions.swift */; };
+		2885023F1AC117A500E7F670 /* SyncStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2885023E1AC117A500E7F670 /* SyncStateMachine.swift */; };
+		288A2D9D1AB8B3260023ABC3 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		288A2DAA1AB8B3700023ABC3 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 288A2DA71AB8B3700023ABC3 /* Box.swift */; };
+		288A2DAB1AB8B3700023ABC3 /* BoxType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 288A2DA81AB8B3700023ABC3 /* BoxType.swift */; };
+		288A2DAC1AB8B3700023ABC3 /* MutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 288A2DA91AB8B3700023ABC3 /* MutableBox.swift */; };
+		288A2DB51AB8B38D0023ABC3 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 288A2DB31AB8B38D0023ABC3 /* Error.swift */; };
+		288A2DB61AB8B38D0023ABC3 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 288A2DB41AB8B38D0023ABC3 /* Result.swift */; };
+		288E67C21B9E730900AE2C6A /* BookmarksDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 288E67C11B9E730900AE2C6A /* BookmarksDownloader.swift */; };
+		2891F2CB1F991185001B105E /* v33.db in Resources */ = {isa = PBXBuildFile; fileRef = 2891F2BA1F991185001B105E /* v33.db */; };
+		28926B1A1AC0F074009C0B1D /* EncryptedJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28926B191AC0F074009C0B1D /* EncryptedJSON.swift */; };
+		28926B371AC0F0DD009C0B1D /* EnvelopeJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28926B361AC0F0DD009C0B1D /* EnvelopeJSON.swift */; };
+		28926B3A1AC0F128009C0B1D /* CleartextPayloadJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28926B391AC0F128009C0B1D /* CleartextPayloadJSON.swift */; };
+		2894C1431AE89D8900F1F92F /* HistorySynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2894C1421AE89D8900F1F92F /* HistorySynchronizer.swift */; };
+		2894C1661AE89DD200F1F92F /* TabsSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2894C1651AE89DD200F1F92F /* TabsSynchronizer.swift */; };
+		2894C1691AE89DDC00F1F92F /* ClientsSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2894C1681AE89DDC00F1F92F /* ClientsSynchronizer.swift */; };
+		2894C16C1AE89FD500F1F92F /* HistoryPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2894C16B1AE89FD500F1F92F /* HistoryPayload.swift */; };
+		289A4C131C4EB90600A460E3 /* StorageTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289A4C121C4EB90600A460E3 /* StorageTestUtils.swift */; };
+		289A4C141C4EB90600A460E3 /* StorageTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289A4C121C4EB90600A460E3 /* StorageTestUtils.swift */; };
+		28A17B671BEC727500BC14ED /* Downloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A17B661BEC727500BC14ED /* Downloader.swift */; };
+		28AA941D1B97DCA800703DC6 /* BookmarkPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28AA941C1B97DCA800703DC6 /* BookmarkPayload.swift */; };
+		28B62ACE1BC745E7004A585A /* Syncable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B62ACD1BC745E7004A585A /* Syncable.swift */; };
+		28C28BFD1C51A3B900D5460E /* Merging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C28BFC1C51A3B900D5460E /* Merging.swift */; };
+		28C4AB721AD42D4300D9ACE3 /* Clients.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C4AB711AD42D4300D9ACE3 /* Clients.swift */; };
+		28C8B7851C852535006D8318 /* BookmarksPanelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C8B7841C852535006D8318 /* BookmarksPanelTests.swift */; };
+		28C8D11D1AD4CE8900F62011 /* Storage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* Storage.framework */; };
+		28C8D1391AD4CE9100F62011 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		28C8D13B1AD4CEB100F62011 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		28C8D13C1AD4CEB400F62011 /* Storage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* Storage.framework */; };
+		28CDA55C1A43C37C005C318C /* NSUserDefaultsPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD19A661A25309B0084FBA7 /* NSUserDefaultsPrefs.swift */; };
+		28CDA5641A43C37D005C318C /* NSUserDefaultsPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD19A661A25309B0084FBA7 /* NSUserDefaultsPrefs.swift */; };
+		28D158AD1AFD90E500F9C065 /* TestSQLiteBookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D158AC1AFD90E500F9C065 /* TestSQLiteBookmarks.swift */; };
+		28D52E2F1BCDF53900187A1D /* ResetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D52E081BCDF44100187A1D /* ResetTests.swift */; };
+		28D980231C47149000277055 /* TestBookmarkTreeMerging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D980221C47149000277055 /* TestBookmarkTreeMerging.swift */; };
+		28E08C991AF44EF9009BA2FA /* SQLiteHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2551ABB531100877008 /* SQLiteHistory.swift */; };
+		28E08C9A1AF44F00009BA2FA /* BrowserSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282915E51AF1A7920006EEB5 /* BrowserSchema.swift */; };
+		28E23C121AC5A5EE00F5AC85 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28E23C111AC5A5EE00F5AC85 /* State.swift */; };
+		28E91E751B443AD5009DF274 /* SyncConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28E91E741B443AD5009DF274 /* SyncConstants.swift */; };
+		28EADE5D1AFC3A78007FB2FB /* UIImageViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EADE381AFC3898007FB2FB /* UIImageViewExtensions.swift */; };
+		28ECD97A1BA1EA2200D829DA /* MockSyncServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28ECD9791BA1EA2200D829DA /* MockSyncServer.swift */; };
+		28ECD9BF1BA1F19900D829DA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6231C001B90A44F005ABB0D /* libz.tbd */; };
+		28ECD9F41BA1F59800D829DA /* DownloadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28ECD9F31BA1F59800D829DA /* DownloadTests.swift */; };
+		28ED02021B26123E003948B2 /* LoginPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28ED02011B26123E003948B2 /* LoginPayload.swift */; };
+		28ED02261B262B5E003948B2 /* LoginsSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28ED02251B262B5E003948B2 /* LoginsSynchronizer.swift */; };
+		28ED02291B262E0A003948B2 /* IndependentRecordSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28ED02281B262E0A003948B2 /* IndependentRecordSynchronizer.swift */; };
+		28F596A11ACA13CA0071DDCC /* InfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28F596A01ACA13CA0071DDCC /* InfoTests.swift */; };
+		28F657EA1ABFCA7A00A608BD /* LiveAccountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA4363B1ABB8448008031D1 /* LiveAccountTest.swift */; };
+		28FDFF0C1C1F725800840F86 /* SeparatorTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FDFF0B1C1F725800840F86 /* SeparatorTableCell.swift */; };
+		2C2A5EF41E68469500F02659 /* PrivateBrowsingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2A5EF31E68469500F02659 /* PrivateBrowsingTest.swift */; };
+		2C2A91291FA2410D002E36BD /* HistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2A91281FA2410D002E36BD /* HistoryTests.swift */; };
+		2C31A7A91E8BFB2200DAC646 /* ReaderViewUITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C31A7A81E8BFB2200DAC646 /* ReaderViewUITest.swift */; };
+		2C31A8471E8D447F00DAC646 /* HomePageSettingsUITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C31A8461E8D447F00DAC646 /* HomePageSettingsUITest.swift */; };
+		2C3406C81E719F00000FD889 /* SettingsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3406C71E719F00000FD889 /* SettingsTest.swift */; };
+		2C8C07771E7800EA00DC1237 /* FindInPageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8C07761E7800EA00DC1237 /* FindInPageTest.swift */; };
+		2C97EC711E72C80E0092EC18 /* TopTabsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C97EC701E72C80E0092EC18 /* TopTabsTest.swift */; };
+		2CA16FDE1E5F089100332277 /* SearchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA16FDD1E5F089100332277 /* SearchTest.swift */; };
+		2CB56E3F1E926BFB00AF7586 /* ToolbarTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB56E3E1E926BFB00AF7586 /* ToolbarTest.swift */; };
+		2CC1B3F01E9B861400814EEC /* DomainAutocompleteTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC1B3EF1E9B861400814EEC /* DomainAutocompleteTest.swift */; };
+		2CEA6F791E93E3A600D4100E /* SearchSettingsUITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEA6F781E93E3A600D4100E /* SearchSettingsUITest.swift */; };
+		2CF449A51E7BFE2C00FD7595 /* NavigationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CF449A41E7BFE2C00FD7595 /* NavigationTest.swift */; };
+		2F13E79B1AC0C02700D75081 /* StringExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F13E79A1AC0C02700D75081 /* StringExtensionsTests.swift */; };
+		2F14E13A1ABB890800FF98DB /* Account-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F14E1391ABB890800FF98DB /* Account-Bridging-Header.h */; };
+		2F1A3DE11ABE3C90002F1E15 /* FxALoginStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F1A3DE01ABE3C90002F1E15 /* FxALoginStateMachine.swift */; };
+		2F1A3DFE1ABE3C9C002F1E15 /* FxALoginStateMachineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F1A3DFD1ABE3C9C002F1E15 /* FxALoginStateMachineTests.swift */; };
+		2F3724C61ABF3C01007607FA /* LiveStorageClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F3724C41ABF3C01007607FA /* LiveStorageClientTests.swift */; };
+		2F3724C71ABF3C01007607FA /* StorageClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F3724C51ABF3C01007607FA /* StorageClientTests.swift */; };
+		2F3724E51ABF3C19007607FA /* Info.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F3724E21ABF3C19007607FA /* Info.swift */; };
+		2F3724E71ABF3C19007607FA /* StorageClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F3724E31ABF3C19007607FA /* StorageClient.swift */; };
+		2F3724E91ABF3C19007607FA /* Synchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F3724E41ABF3C19007607FA /* Synchronizer.swift */; };
+		2F44FA1B1A9D426A00FD20CC /* TestHashExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F44FA1A1A9D426A00FD20CC /* TestHashExtensions.swift */; };
+		2F44FB2C1A9D5D8500FD20CC /* Home.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F84B22261A09127C00AAB793 /* Home.xcassets */; };
+		2F44FB2D1A9D5D8500FD20CC /* FiraSans-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7421A793CF20022C5E0 /* FiraSans-BoldItalic.ttf */; };
+		2F44FC721A9E840300FD20CC /* SettingsNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F44FC711A9E840300FD20CC /* SettingsNavigationController.swift */; };
+		2F44FCC51A9E85E900FD20CC /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F44FCC41A9E85E900FD20CC /* SettingsTableViewController.swift */; };
+		2F44FCC71A9E8CF500FD20CC /* SearchSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F44FCC61A9E8CF500FD20CC /* SearchSettingsTableViewController.swift */; };
+		2F44FCCB1A9E972E00FD20CC /* SearchEnginePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F44FCCA1A9E972E00FD20CC /* SearchEnginePicker.swift */; };
+		2F67C5261BB0CB4E00E7B73A /* MetaGlobalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F67C5251BB0CB4E00E7B73A /* MetaGlobalTests.swift */; };
+		2F697F7E1A9FD22D009E03AE /* SearchEnginesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F697F7D1A9FD22D009E03AE /* SearchEnginesTests.swift */; };
+		2F8C76571BC32F3C00D5E4E0 /* MockSyncServerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F8C76561BC32F3C00D5E4E0 /* MockSyncServerTests.swift */; };
+		2FA436061ABB83B4008031D1 /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FA435FB1ABB83B4008031D1 /* Account.framework */; };
+		2FA436121ABB83B4008031D1 /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FA435FB1ABB83B4008031D1 /* Account.framework */; };
+		2FA436291ABB8436008031D1 /* FirefoxAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA436221ABB8436008031D1 /* FirefoxAccount.swift */; };
+		2FA4362B1ABB8436008031D1 /* FirefoxAccountConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA436231ABB8436008031D1 /* FirefoxAccountConfiguration.swift */; };
+		2FA4362F1ABB8436008031D1 /* FxAClient10.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA436251ABB8436008031D1 /* FxAClient10.swift */; };
+		2FA436331ABB8436008031D1 /* HawkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA436271ABB8436008031D1 /* HawkHelper.swift */; };
+		2FA436351ABB8436008031D1 /* TokenServerClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA436281ABB8436008031D1 /* TokenServerClient.swift */; };
+		2FA4363D1ABB8448008031D1 /* FirefoxAccountTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA436371ABB8448008031D1 /* FirefoxAccountTests.swift */; };
+		2FA4363E1ABB8448008031D1 /* FxAClient10Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA436381ABB8448008031D1 /* FxAClient10Tests.swift */; };
+		2FA436401ABB8448008031D1 /* HawkHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA4363A1ABB8448008031D1 /* HawkHelperTests.swift */; };
+		2FA436411ABB8448008031D1 /* LiveAccountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA4363B1ABB8448008031D1 /* LiveAccountTest.swift */; };
+		2FA436421ABB8448008031D1 /* TokenServerClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA4363C1ABB8448008031D1 /* TokenServerClientTests.swift */; };
+		2FC244B31A855E05007CE41D /* FxA.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28CE83D01A1D1D5100576538 /* FxA.framework */; };
+		2FC244B81A855E0D007CE41D /* FxA.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28CE83D01A1D1D5100576538 /* FxA.framework */; };
+		2FCAE2251ABB51F800877008 /* Storage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* Storage.framework */; };
+		2FCAE2311ABB51F800877008 /* Storage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* Storage.framework */; };
+		2FCAE25D1ABB531100877008 /* Bookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE23F1ABB531100877008 /* Bookmarks.swift */; };
+		2FCAE25F1ABB531100877008 /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2411ABB531100877008 /* Cursor.swift */; };
+		2FCAE2601ABB531100877008 /* Favicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2421ABB531100877008 /* Favicons.swift */; };
+		2FCAE2611ABB531100877008 /* FileAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2431ABB531100877008 /* FileAccessor.swift */; };
+		2FCAE2621ABB531100877008 /* History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2441ABB531100877008 /* History.swift */; };
+		2FCAE2651ABB531100877008 /* RemoteTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2471ABB531100877008 /* RemoteTabs.swift */; };
+		2FCAE2661ABB531100877008 /* Site.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2481ABB531100877008 /* Site.swift */; };
+		2FCAE2681ABB531100877008 /* BrowserDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE24B1ABB531100877008 /* BrowserDB.swift */; };
+		2FCAE2751ABB531100877008 /* SQLiteRemoteClientsAndTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2581ABB531100877008 /* SQLiteRemoteClientsAndTabs.swift */; };
+		2FCAE2771ABB531100877008 /* SwiftData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE25B1ABB531100877008 /* SwiftData.swift */; };
+		2FCAE2781ABB531100877008 /* Visit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE25C1ABB531100877008 /* Visit.swift */; };
+		2FCAE2841ABB533A00877008 /* MockFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE2791ABB533A00877008 /* MockFiles.swift */; };
+		2FCAE2851ABB533A00877008 /* TestSQLiteRemoteClientsAndTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCAE27A1ABB533A00877008 /* TestSQLiteRemoteClientsAndTabs.swift */; };
+		2FCAE33E1ABB5F1800877008 /* Storage-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FCAE33D1ABB5F1800877008 /* Storage-Bridging-Header.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2FDB10931A9FBEC5006CF312 /* PrefsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FDB10921A9FBEC5006CF312 /* PrefsTests.swift */; };
+		2FDBCF611ABFC9DE00AFF7F0 /* SyncAuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FDBCF601ABFC9DE00AFF7F0 /* SyncAuthState.swift */; };
+		2FDBCF9B1AC0ADB500AFF7F0 /* SyncAuthStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FDBCF9A1AC0ADB500AFF7F0 /* SyncAuthStateTests.swift */; };
+		2FDE87FE1ABB3817005317B1 /* RemoteTabsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FDE87FD1ABB3817005317B1 /* RemoteTabsPanel.swift */; };
+		2FFC4D1B1ABE3C360081D675 /* FxAState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FFC4D1A1ABE3C360081D675 /* FxAState.swift */; };
+		2FFC4D381ABE3C420081D675 /* FxAStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FFC4D371ABE3C420081D675 /* FxAStateTests.swift */; };
+		315D05561E58DD60001F349B /* UIPasteboardExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83E5AB61C1D993D0026D912 /* UIPasteboardExtensions.swift */; };
+		318FB6EB1DB5600D0004E40F /* SQLiteHistoryFactories.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318FB6EA1DB5600D0004E40F /* SQLiteHistoryFactories.swift */; };
+		31ADB5DA1E58CEC300E87909 /* ClipboardBarDisplayHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31ADB5D91E58CEC300E87909 /* ClipboardBarDisplayHandler.swift */; };
+		3905274C1C874D35007E0BB7 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3905274B1C874D35007E0BB7 /* NotificationCenter.framework */; };
+		3905274F1C874D35007E0BB7 /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3905274E1C874D35007E0BB7 /* TodayViewController.swift */; };
+		390527561C874D35007E0BB7 /* Today.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 3905274A1C874D35007E0BB7 /* Today.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+		39098DC41CAD5ACB00AE87F3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 391AEFD11C8F11ED00691F84 /* Images.xcassets */; };
+		391B4FFF1F9767F50094F841 /* FxScreenGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39EB46981E26DDB4006346E8 /* FxScreenGraph.swift */; };
+		391B500E1F9768EA0094F841 /* ScreenGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39EB46971E26DDB4006346E8 /* ScreenGraph.swift */; };
+		39236E721FCC600200A38F1B /* TabEventHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39236E711FCC600200A38F1B /* TabEventHandlerTests.swift */; };
+		392ED6B71D06E85E009D9B62 /* NewTabChoiceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392ED6B61D06E85E009D9B62 /* NewTabChoiceViewController.swift */; };
+		392ED7E41D0AEF56009D9B62 /* NewTabAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392ED7E31D0AEF56009D9B62 /* NewTabAccessors.swift */; };
+		392ED7E61D0AEFEF009D9B62 /* HomePageAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392ED7E51D0AEFEF009D9B62 /* HomePageAccessors.swift */; };
+		39409A3F1C90E68300DAE683 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		3943A81D1E9807C700D4F6DC /* FxAPushMessageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3943A81C1E9807C700D4F6DC /* FxAPushMessageTest.swift */; };
+		39455F771FC83F430088A22C /* TabEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39455F761FC83F430088A22C /* TabEventHandler.swift */; };
+		394CF6CF1BAA493C00906917 /* DefaultSuggestedSites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394CF6CE1BAA493C00906917 /* DefaultSuggestedSites.swift */; };
+		3964B09A1EA8F06F00F2EEF4 /* FeatureSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3964B0991EA8F06F00F2EEF4 /* FeatureSwitch.swift */; };
+		3964B09C1EA8F32C00F2EEF4 /* FeatureSwitchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3964B09B1EA8F32C00F2EEF4 /* FeatureSwitchTests.swift */; };
+		396E38CC1EE0816C00CC180F /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34DC84D1A16C40C00D49B7B /* Profile.swift */; };
+		396E38DD1EE081DA00CC180F /* SyncStatusResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E60D03171D511398002FE3F6 /* SyncStatusResolver.swift */; };
+		396E38E01EE0821B00CC180F /* NSUserDefaultsPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD19A661A25309B0084FBA7 /* NSUserDefaultsPrefs.swift */; };
+		396E38E31EE083A400CC180F /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		396E38E61EE0843500CC180F /* Storage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* Storage.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		396E38ED1EE0C63500CC180F /* Sync.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2827315E1ABC9BE600AA1954 /* Sync.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		396E38EE1EE0C6ED00CC180F /* ExtensionProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 396E38DB1EE0818800CC180F /* ExtensionProfile.swift */; };
+		396E38F11EE0C8EC00CC180F /* FxAPushMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3905B4D41E8E7A6B0027D953 /* FxAPushMessageHandler.swift */; };
+		396E38F21EE0C8ED00CC180F /* FxAPushMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3905B4D41E8E7A6B0027D953 /* FxAPushMessageHandler.swift */; };
+		396E38F31EE0C90D00CC180F /* FxALoginHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F99FED1E3A71F800F353B4 /* FxALoginHelper.swift */; };
+		397848DE1ED86605004C0C0B /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397848DD1ED86605004C0C0B /* NotificationService.swift */; };
+		397848E21ED86605004C0C0B /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 397848DB1ED86605004C0C0B /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+		39A359E41BFCCE94006B9E87 /* UserActivityHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39A359E31BFCCE94006B9E87 /* UserActivityHandler.swift */; };
+		39A35AED1C0662A3006B9E87 /* SpotlightHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = 39A35AEC1C0662A3006B9E87 /* SpotlightHelper.js */; };
+		39AC591A1CC574AB0042C2F5 /* HomePageSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39AC59191CC574AA0042C2F5 /* HomePageSettingsViewController.swift */; };
+		39C22C291E89791C000C0E56 /* PushCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 395C8F201E796AD600A68E8C /* PushCrypto.swift */; };
+		39C22C2A1E897926000C0E56 /* PushCryptoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B0647C1E7ADAC2000BE173 /* PushCryptoTests.swift */; };
+		39C22C2F1E897BA7000C0E56 /* LivePushClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C22C2C1E897B9A000C0E56 /* LivePushClientTests.swift */; };
+		39D9E6851C89E9690071FADA /* SnapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FA11C495268006EEEC3 /* SnapKit.framework */; };
+		39DD030D1CD53E1900BC09B3 /* HomePageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39DD030C1CD53E1900BC09B3 /* HomePageHelper.swift */; };
+		39E65D191CA455A900C63CE3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 391AEFD11C8F11ED00691F84 /* Images.xcassets */; };
+		39E65D271CA5B92000C63CE3 /* AsyncReducerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E65D261CA5B92000C63CE3 /* AsyncReducerTests.swift */; };
+		39EB46991E26DDB4006346E8 /* ScreenGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39EB46971E26DDB4006346E8 /* ScreenGraph.swift */; };
+		39EB469A1E26DDB4006346E8 /* FxScreenGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39EB46981E26DDB4006346E8 /* FxScreenGraph.swift */; };
+		39F819C61FD70F5D009E31E4 /* TabEventHandlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F819C51FD70F5D009E31E4 /* TabEventHandlers.swift */; };
+		39F99FE41E3A6F1700F353B4 /* PushClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F99FD91E3A6DE300F353B4 /* PushClient.swift */; };
+		39F99FE51E3A6F1700F353B4 /* PushConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F99FDA1E3A6DE300F353B4 /* PushConfiguration.swift */; };
+		39F99FE61E3A6F1700F353B4 /* PushRegistration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F99FDB1E3A6DE300F353B4 /* PushRegistration.swift */; };
+		3B0943811D6CC4FC004F24E1 /* FilledPageControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B0943801D6CC4FC004F24E1 /* FilledPageControl.swift */; };
+		3B39EDBA1E16E18900EF029F /* CustomSearchEnginesTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B39EDB91E16E18900EF029F /* CustomSearchEnginesTest.swift */; };
+		3B39EDCB1E16E1AA00EF029F /* CustomSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B39EDCA1E16E1AA00EF029F /* CustomSearchViewController.swift */; };
+		3B4262E51E538EC400CA681C /* MetadataHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = 3B4262E21E538EC400CA681C /* MetadataHelper.js */; };
+		3B4262E61E538EC400CA681C /* MetadataParserHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B4262E31E538EC400CA681C /* MetadataParserHelper.swift */; };
+		3B4262E71E538EC400CA681C /* page-metadata-parser.js in Resources */ = {isa = PBXBuildFile; fileRef = 3B4262E41E538EC400CA681C /* page-metadata-parser.js */; };
+		3B43E3D31D95C48D00BBA9DB /* StoragePerfTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B43E3D21D95C48D00BBA9DB /* StoragePerfTests.swift */; };
+		3B4988CE1E42B01800A12FDA /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B4988CD1E42B01800A12FDA /* SwiftyJSON.framework */; };
+		3B4AA24B1D8B8C4C00A2E008 /* ArrayExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B4AA24A1D8B8C4C00A2E008 /* ArrayExtensionTests.swift */; };
+		3B546EC01D95ECAE00BDBE36 /* ActivityStreamTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B546EBF1D95ECAE00BDBE36 /* ActivityStreamTest.swift */; };
+		3B61CD491F2A74EF00D38DE1 /* PocketFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B61CD481F2A74EF00D38DE1 /* PocketFeed.swift */; };
+		3B61CD591F2A750800D38DE1 /* PocketFeedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B61CD581F2A750800D38DE1 /* PocketFeedTests.swift */; };
+		3B61CD631F2A769D00D38DE1 /* pocketglobalfeed.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B61CD621F2A769D00D38DE1 /* pocketglobalfeed.json */; };
+		3B6889C51D66950E002AC85E /* UIImageColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6889C41D66950E002AC85E /* UIImageColors.swift */; };
+		3B6F40181DC7849C00656CC6 /* ActivityStreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6F40171DC7849C00656CC6 /* ActivityStreamTests.swift */; };
+		3BA9A0231D2C208C00BD418C /* Fuzi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BA9A0221D2C208C00BD418C /* Fuzi.framework */; };
+		3BA9A0311D2C2C0400BD418C /* Fuzi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BA9A0221D2C208C00BD418C /* Fuzi.framework */; };
+		3BA9A0321D2C2C0500BD418C /* Fuzi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BA9A0221D2C208C00BD418C /* Fuzi.framework */; };
+		3BB50E111D6274CD004B33DF /* ActivityStreamTopSitesCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BB50E101D6274CD004B33DF /* ActivityStreamTopSitesCell.swift */; };
+		3BB50E201D627539004B33DF /* ActivityStreamPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BB50E1F1D627539004B33DF /* ActivityStreamPanel.swift */; };
+		3BB54B311E68EB2B0021DAC4 /* AuthenticationKeychainInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BB54B301E68EB2B0021DAC4 /* AuthenticationKeychainInfoTests.swift */; };
+		3BC659491E5BA4AE006D560F /* TopSites in Resources */ = {isa = PBXBuildFile; fileRef = 3BC659481E5BA4AE006D560F /* TopSites */; };
+		3BC659591E5BA505006D560F /* top_sites.json in Resources */ = {isa = PBXBuildFile; fileRef = 3BC659581E5BA505006D560F /* top_sites.json */; };
+		3BCE6D3C1CEB9E4D0080928C /* ThirdPartySearchAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BCE6D3B1CEB9E4D0080928C /* ThirdPartySearchAlerts.swift */; };
+		3BE7274E1CCFE8A30099189F /* CustomSearchHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = 3BE7274D1CCFE8A30099189F /* CustomSearchHelper.js */; };
+		3BE7275D1CCFE8B60099189F /* CustomSearchHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE7275C1CCFE8B60099189F /* CustomSearchHandler.swift */; };
+		3BF4B8E91D38497A00493393 /* BaseTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF4B8E81D38497A00493393 /* BaseTestCase.swift */; };
+		3BF56D271CDBBE1F00AC4D75 /* SimpleToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF56D261CDBBE1F00AC4D75 /* SimpleToast.swift */; };
+		3BFCBF201E04B1C50070C042 /* UIImageViewExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BFCBF1F1E04B1C50070C042 /* UIImageViewExtensionsTests.swift */; };
+		3BFE4B501D34673D00DDF53F /* ThirdPartySearchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BFE4B4F1D34673D00DDF53F /* ThirdPartySearchTest.swift */; };
+		3D71C89E1F5703A1008D8646 /* CopiedLinksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D71C89D1F5703A1008D8646 /* CopiedLinksTests.swift */; };
+		3D9CA9841EF456A8002434DD /* NightModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9CA9831EF456A8002434DD /* NightModeTests.swift */; };
+		3D9CA9A81EF84D04002434DD /* NoImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9CA9A71EF84D04002434DD /* NoImageTests.swift */; };
+		3D9CAA1C1EFCD655002434DD /* ClipBoardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9CAA1B1EFCD655002434DD /* ClipBoardTests.swift */; };
+		3DEFED081F55EBE300F8620C /* TrackingProtectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DEFED071F55EBE300F8620C /* TrackingProtectionTests.swift */; };
+		4A59B58AD11B5EE1F80BBDEB /* TestHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59BF410BBD9B3BE71F4C7C /* TestHistory.swift */; };
+		4F514FD41ACD8F2C0022D7EA /* HistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F514FD31ACD8F2C0022D7EA /* HistoryTests.swift */; };
+		4F97573B1AFA6F37006ECC24 /* readerContent.html in Resources */ = {isa = PBXBuildFile; fileRef = 4F9757391AFA6F37006ECC24 /* readerContent.html */; };
+		5002717C41BC7C50F67F1CAD /* StateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50027345B49B967409DDA348 /* StateTests.swift */; };
+		554867231DC3935A00183DAA /* HomePageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554867221DC3935A00183DAA /* HomePageTests.swift */; };
+		55A747171DC46FC400CE1B57 /* HomePageUITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55A747161DC46FC400CE1B57 /* HomePageUITest.swift */; };
+		59A681BDFC95A19F05E07223 /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59A68CCB63E2A565CB03F832 /* SearchViewController.swift */; };
+		59A68B280D62462B85CF57A4 /* HistoryPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59A6825233896FC846499289 /* HistoryPanel.swift */; };
+		59A68D66379CFA85C4EAF00B /* TwoLineCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59A68B1F857A8638598A63A0 /* TwoLineCell.swift */; };
+		59A68E0B4ABBF55E14819668 /* BookmarksPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59A6839879D615FC1C0D71CE /* BookmarksPanel.swift */; };
+		59A68FD5260B8D520F890F4A /* ReaderPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59A685F4EAD19EDEC854BCA4 /* ReaderPanel.swift */; };
+		742A56391D80B54A00BDB803 /* PhotonActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742A56381D80B54A00BDB803 /* PhotonActionSheet.swift */; };
+		744B0FFE1B4F172E00100422 /* ToolbarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 744B0FFD1B4F172E00100422 /* ToolbarTests.swift */; };
+		744ED5611DBFEB8D00A2B5BE /* MailtoLinkHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 744ED5601DBFEB8D00A2B5BE /* MailtoLinkHandler.swift */; };
+		745DAB301CDAAFAA00D44181 /* RecentlyClosedTabsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745DAB2F1CDAAFAA00D44181 /* RecentlyClosedTabsPanel.swift */; };
+		745DAB3F1CDAB09E00D44181 /* HistoryBackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745DAB3E1CDAB09E00D44181 /* HistoryBackButton.swift */; };
+		7479B4EF1C5306A200DF000B /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7479B4ED1C5306A200DF000B /* Reachability.swift */; };
+		74821F8E1DAD8F1400EEEA72 /* ActivityStreamHighlightCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74821F8D1DAD8F1300EEEA72 /* ActivityStreamHighlightCell.swift */; };
+		74821FC51DB56A2500EEEA72 /* OpenWithSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74821FC41DB56A2500EEEA72 /* OpenWithSettingsViewController.swift */; };
+		74821FFE1DB6D3AC00EEEA72 /* MailSchemes.plist in Resources */ = {isa = PBXBuildFile; fileRef = 74821FFD1DB6D3AC00EEEA72 /* MailSchemes.plist */; };
+		7482205C1DBAB56300EEEA72 /* MailProviders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7482205B1DBAB56300EEEA72 /* MailProviders.swift */; };
+		74B195441CF503FC007F36EF /* RecentlyClosedTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74B195431CF503FC007F36EF /* RecentlyClosedTabs.swift */; };
+		74C027451B2A348C001B1E88 /* SessionData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C027441B2A348C001B1E88 /* SessionData.swift */; };
+		74E36D781B71323500D69DA1 /* SettingsContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E36D771B71323500D69DA1 /* SettingsContentViewController.swift */; };
+		7B0B1B791C1B69C900DF4AB5 /* ClientPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BCAAD81B05380B00855D82 /* ClientPickerViewController.swift */; };
+		7B0B1B9D1C1B6A3F00DF4AB5 /* InstructionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BCAAB81B0537E300855D82 /* InstructionsViewController.swift */; };
+		7B10AA9F1E3A15020002DD08 /* DataExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B10AA9E1E3A15020002DD08 /* DataExtensions.swift */; };
+		7B10AABB1E3A1F650002DD08 /* URLRequestExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B10AABA1E3A1F650002DD08 /* URLRequestExtensions.swift */; };
+		7B2142FE1E5E055000CDD3FC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7B2142FC1E5E055000CDD3FC /* InfoPlist.strings */; };
+		7B2142FF1E5E059900CDD3FC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7B2142F31E5E03F800CDD3FC /* InfoPlist.strings */; };
+		7B2143001E5E05A000CDD3FC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7B2142F61E5E040200CDD3FC /* InfoPlist.strings */; };
+		7B24DC9C1B67B3590005766B /* ClearPrivateDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B24DC9B1B67B3590005766B /* ClearPrivateDataTests.swift */; };
+		7B3631EA1C244FEE00D12AF9 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3631E91C244FEE00D12AF9 /* Theme.swift */; };
+		7B3D9E651E4CBFDB007A50DA /* NSCoderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3D9E641E4CBFDB007A50DA /* NSCoderExtensions.swift */; };
+		7B42406E1CA04CAC009B5C28 /* Menu.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B42406D1CA04CAC009B5C28 /* Menu.xcassets */; };
+		7B4980A81CE363ED0017547C /* Settings.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B4980A71CE363ED0017547C /* Settings.xcassets */; };
+		7B604F861C494983006EEEC3 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F851C494983006EEEC3 /* Alamofire.framework */; };
+		7B604F871C494995006EEEC3 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F851C494983006EEEC3 /* Alamofire.framework */; };
+		7B604F891C4949B1006EEEC3 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F851C494983006EEEC3 /* Alamofire.framework */; };
+		7B604F8A1C4949C1006EEEC3 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F851C494983006EEEC3 /* Alamofire.framework */; };
+		7B604F901C494B0F006EEEC3 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F851C494983006EEEC3 /* Alamofire.framework */; };
+		7B604F911C494B3C006EEEC3 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F851C494983006EEEC3 /* Alamofire.framework */; };
+		7B604F991C494F74006EEEC3 /* KIF.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F981C494F74006EEEC3 /* KIF.framework */; };
+		7B604F9B1C4950F2006EEEC3 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F9A1C4950F2006EEEC3 /* SDWebImage.framework */; };
+		7B604F9C1C495135006EEEC3 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F9A1C4950F2006EEEC3 /* SDWebImage.framework */; };
+		7B604F9D1C495143006EEEC3 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F9A1C4950F2006EEEC3 /* SDWebImage.framework */; };
+		7B604F9E1C49514A006EEEC3 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604F9A1C4950F2006EEEC3 /* SDWebImage.framework */; };
+		7B604FA21C495268006EEEC3 /* SnapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FA11C495268006EEEC3 /* SnapKit.framework */; };
+		7B604FA31C4952A4006EEEC3 /* SnapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FA11C495268006EEEC3 /* SnapKit.framework */; };
+		7B604FBB1C495D8A006EEEC3 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FBA1C495D8A006EEEC3 /* XCGLogger.framework */; };
+		7B604FBC1C495E1E006EEEC3 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FBA1C495D8A006EEEC3 /* XCGLogger.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		7B604FBD1C495E31006EEEC3 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FBA1C495D8A006EEEC3 /* XCGLogger.framework */; };
+		7B604FBE1C495E4E006EEEC3 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FBA1C495D8A006EEEC3 /* XCGLogger.framework */; };
+		7B604FBF1C495E60006EEEC3 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FBA1C495D8A006EEEC3 /* XCGLogger.framework */; };
+		7B604FC01C495FD1006EEEC3 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B604FBA1C495D8A006EEEC3 /* XCGLogger.framework */; };
+		7B6050011C49653B006EEEC3 /* AdjustSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B6050001C49653B006EEEC3 /* AdjustSdk.framework */; };
+		7B844E3D1BBDDB9D00E733A2 /* ChevronView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B844E3C1BBDDB9D00E733A2 /* ChevronView.swift */; };
+		7B8A47F61D01D3B400C07734 /* PassKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8A47F51D01D3B400C07734 /* PassKit.framework */; };
+		7B9BF91C1E43472E00CB24F4 /* JSONExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B9BF91B1E43472E00CB24F4 /* JSONExtensions.swift */; };
+		7B9BF9301E449D2500CB24F4 /* MockLogins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3E7DB91B27AB4C00E2E84D /* MockLogins.swift */; };
+		7BA0601B1C0F4DE200DFADB6 /* TabPeekViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA0601A1C0F4DE200DFADB6 /* TabPeekViewController.swift */; };
+		7BA4A9471C4CED900091D032 /* GCDWebServers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA4A9451C4CED780091D032 /* GCDWebServers.framework */; };
+		7BA4A94A1C4CEFC70091D032 /* OnePasswordExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA4A9491C4CEFC70091D032 /* OnePasswordExtension.framework */; };
+		7BA4A94C1C4CF03B0091D032 /* SwiftKeychainWrapper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA4A94B1C4CF03B0091D032 /* SwiftKeychainWrapper.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		7BA4A9641C4CFE840091D032 /* Deferred.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA4A9631C4CFE840091D032 /* Deferred.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		7BA4A9651C4D007B0091D032 /* Deferred.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA4A9631C4CFE840091D032 /* Deferred.framework */; };
+		7BA4A9661C4D008C0091D032 /* Deferred.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA4A9631C4CFE840091D032 /* Deferred.framework */; };
+		7BA8D1C71BA037F500C8AE9E /* OpenInHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA8D1C61BA037F500C8AE9E /* OpenInHelper.swift */; };
+		7BBFEE741BB405D900A305AA /* TabManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBFEE731BB405D900A305AA /* TabManagerTests.swift */; };
+		7BC68D091CC153020043562A /* RoundedToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC68D081CC153020043562A /* RoundedToolbar.swift */; };
+		7BEB64441C7345600092C02E /* L10nSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3632D31C2983F000D12AF9 /* L10nSnapshotTests.swift */; };
+		7BEB64451C7345600092C02E /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B60B0071BDE3AE10090C984 /* SnapshotHelper.swift */; };
+		7BEB64511C7345990092C02E /* MarketingUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B95CD191C3AB2EE00638E31 /* MarketingUITests.swift */; };
+		7BEB64521C7345990092C02E /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B60B0071BDE3AE10090C984 /* SnapshotHelper.swift */; };
+		7BEDD29B1CB7CB24004B51F3 /* JumpAndSpinAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEDD29A1CB7CB24004B51F3 /* JumpAndSpinAnimator.swift */; };
+		7BEDD2B21CB7CC0B004B51F3 /* Animatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEDD2B11CB7CC0B004B51F3 /* Animatable.swift */; };
+		7BEFC6801BFF68C30059C952 /* QuickActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEFC67F1BFF68C30059C952 /* QuickActions.swift */; };
+		7BF5A1EA1B41640500EA9DD8 /* SyncQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BF5A1E91B41640500EA9DD8 /* SyncQueue.swift */; };
+		7BF5A1EE1B429B3100EA9DD8 /* SyncCommandsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BF5A1ED1B429B3100EA9DD8 /* SyncCommandsTests.swift */; };
+		8D8251811F4DE67F00780643 /* AdvanceAccountSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8251721F4DE67E00780643 /* AdvanceAccountSettingViewController.swift */; };
+		8DCD3BCD1ED5B7FA00446D38 /* FxADeepLinkingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DCD3BCC1ED5B7FA00446D38 /* FxADeepLinkingTests.swift */; };
+		A83E5AB71C1D993D0026D912 /* UIPasteboardExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83E5AB61C1D993D0026D912 /* UIPasteboardExtensions.swift */; };
+		A83E5B1A1C1DA8BF0026D912 /* image.gif in Resources */ = {isa = PBXBuildFile; fileRef = A83E5B181C1DA8BF0026D912 /* image.gif */; };
+		A83E5B1B1C1DA8BF0026D912 /* image.png in Resources */ = {isa = PBXBuildFile; fileRef = A83E5B191C1DA8BF0026D912 /* image.png */; };
+		A83E5B1D1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83E5B1C1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift */; };
+		A83E5B1E1C1DAAAA0026D912 /* UIPasteboardExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83E5AB61C1D993D0026D912 /* UIPasteboardExtensions.swift */; };
+		A9072B801D07B34100459960 /* NoImageModeHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9072B7F1D07B34100459960 /* NoImageModeHelper.swift */; };
+		A91528D21D0E637600CD0425 /* NoImageModeHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = A91528D11D0E637600CD0425 /* NoImageModeHelper.js */; };
+		A93067D91D0FE15E00C49C6E /* NightModeHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = A93067D81D0FE15E00C49C6E /* NightModeHelper.js */; };
+		A93067E81D0FE18E00C49C6E /* NightModeHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93067E71D0FE18E00C49C6E /* NightModeHelper.swift */; };
+		C400467C1CF4E43E00B08303 /* BackForwardListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C400467B1CF4E43E00B08303 /* BackForwardListViewController.swift */; };
+		C40046FA1CF8E0B200B08303 /* BackForwardListAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40046F91CF8E0B200B08303 /* BackForwardListAnimator.swift */; };
+		C45F44691D087DB600CB7EF0 /* TopTabsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45F44681D087DB600CB7EF0 /* TopTabsViewController.swift */; };
+		C4E3983D1D21F1E7004E89BA /* TopTabsViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E3983C1D21F1E7004E89BA /* TopTabsViews.swift */; };
+		C4E3984C1D21F2FD004E89BA /* TabTrayButtonExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E3984B1D21F2FD004E89BA /* TabTrayButtonExtensions.swift */; };
+		C4E398601D22C409004E89BA /* TopTabsLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E3985F1D22C409004E89BA /* TopTabsLayout.swift */; };
+		C4EFEECF1CEBB6F2009762A4 /* BackForwardTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EFEECE1CEBB6F2009762A4 /* BackForwardTableViewCell.swift */; };
+		C4F3B29A1CFCF93A00966259 /* ButtonToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F3B2991CFCF93A00966259 /* ButtonToast.swift */; };
+		C817B34D1FC609500086018E /* UIScrollViewSwizzled.swift in Sources */ = {isa = PBXBuildFile; fileRef = C817B34C1FC609500086018E /* UIScrollViewSwizzled.swift */; };
+		C8611C8E1F71904C00C3DE7D /* DiskImageStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BF8CBC1B7472FA0007AFE6 /* DiskImageStoreTests.swift */; };
+		C8611CB01F71AEBA00C3DE7D /* NoImageModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8611CA11F71AEB900C3DE7D /* NoImageModeTests.swift */; };
+		C88601C61F4228AD00BBDE4F /* ContentBlockerSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88601B71F4228AD00BBDE4F /* ContentBlockerSettingViewController.swift */; };
+		C8EB60C41F1FB12500F9B5B3 /* navigationDelegate.html in Resources */ = {isa = PBXBuildFile; fileRef = C8EB60C31F1FB12500F9B5B3 /* navigationDelegate.html */; };
+		C8EB60DC1F1FB9AD00F9B5B3 /* NavigationDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8EB60DB1F1FB9AD00F9B5B3 /* NavigationDelegateTests.swift */; };
+		C8F457A81F1FD75A000CB895 /* BrowserViewController+WKNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F457A71F1FD75A000CB895 /* BrowserViewController+WKNavigationDelegate.swift */; };
+		C8F457AA1F1FDD9B000CB895 /* BrowserViewController+KeyCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F457A91F1FDD9B000CB895 /* BrowserViewController+KeyCommands.swift */; };
+		CE339EE61F2507C0009BE0E6 /* TestBookmarksSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE339ED61F2507A1009BE0E6 /* TestBookmarksSynchronizer.swift */; };
+		CE564D8E1EB7BD7700BEDDDC /* BookmarksRepairRequestor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE564D8D1EB7BD7700BEDDDC /* BookmarksRepairRequestor.swift */; };
+		CE7F11941F3CEEC800ABFC0B /* RemoteDevices.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7F115E1F3CCEF900ABFC0B /* RemoteDevices.swift */; };
+		CEFC984B1EC0DCF5008A3E48 /* TestBookmarksRepairRequestor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFC983B1EC0DC60008A3E48 /* TestBookmarksRepairRequestor.swift */; };
+		D0131B4D1F3CF7D8000CDE86 /* SQLiteFavicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0131B4C1F3CF7D8000CDE86 /* SQLiteFavicons.swift */; };
+		D018F93E1F44A71A0098F8CA /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018F93D1F44A7190098F8CA /* Schema.swift */; };
+		D02816C21ECA5E2A00240CAA /* HistoryStateHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02816C11ECA5E2A00240CAA /* HistoryStateHelper.swift */; };
+		D02816D21ECA60DF00240CAA /* HistoryStateHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = D02816D11ECA60DF00240CAA /* HistoryStateHelper.js */; };
+		D02818611EF056C800240CAA /* SentryIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02818601EF056C800240CAA /* SentryIntegration.swift */; };
+		D09A0CD81FAA23F6009A0273 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		D09A0CD91FAA2413009A0273 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		D09A0CDA1FAA24C2009A0273 /* Storage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* Storage.framework */; };
+		D09A0CDB1FAA24C8009A0273 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		D09A0CDC1FAA24CC009A0273 /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FA435FB1ABB83B4008031D1 /* Account.framework */; };
+		D09A0CDD1FAA24D0009A0273 /* FxA.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28CE83D01A1D1D5100576538 /* FxA.framework */; };
+		D09A0D301FAB8AF3009A0273 /* Sentry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E46175F21EBB73A10021AE8A /* Sentry.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		D0B29EE01F460BDF00C7CEFC /* LoginsSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B29EDF1F460BDF00C7CEFC /* LoginsSchema.swift */; };
+		D301AAEE1A3A55B70078DD1D /* TabTrayController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D301AAED1A3A55B70078DD1D /* TabTrayController.swift */; };
+		D30684F11C84F12A002D8D82 /* SearchPlugins in Resources */ = {isa = PBXBuildFile; fileRef = D30684F01C84F12A002D8D82 /* SearchPlugins */; };
+		D308E4E41A5306F500842685 /* SearchEngines.swift in Sources */ = {isa = PBXBuildFile; fileRef = D308E4E31A5306F500842685 /* SearchEngines.swift */; };
+		D308EE561CBF0BF5006843F2 /* CertError.css in Resources */ = {isa = PBXBuildFile; fileRef = D308EE551CBF0BF5006843F2 /* CertError.css */; };
+		D30B101E1AA7F9C600C01CA3 /* HomePanels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D30B101D1AA7F9C600C01CA3 /* HomePanels.swift */; };
+		D313BE981B2F5096009EF241 /* DomainAutocompleteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D313BE971B2F5096009EF241 /* DomainAutocompleteTests.swift */; };
+		D314E7F71A37B98700426A76 /* TabToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D314E7F51A37B98700426A76 /* TabToolbar.swift */; };
+		D31A0FC71A65D6D000DC8C7E /* SearchSuggestClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31A0FC61A65D6D000DC8C7E /* SearchSuggestClient.swift */; };
+		D31CF65C1CC1959A001D0BD0 /* PrivilegedRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31CF65B1CC1959A001D0BD0 /* PrivilegedRequest.swift */; };
+		D31EC05F1CC57ED80096F4AB /* localhostLoad.html in Resources */ = {isa = PBXBuildFile; fileRef = D31EC05E1CC57ED80096F4AB /* localhostLoad.html */; };
+		D31F95E91AC226CB005C9F3B /* ScreenshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31F95E81AC226CB005C9F3B /* ScreenshotHelper.swift */; };
+		D32A350E1D6530D80066DAE9 /* FxADevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = D32A350D1D6530D80066DAE9 /* FxADevice.swift */; };
+		D32CACED1AE04DA1000658EB /* TestSwiftData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D32CACEC1AE04DA1000658EB /* TestSwiftData.swift */; };
+		D331DFCA1CB6E9EE009B5DA2 /* OldStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D331DFC91CB6E9EE009B5DA2 /* OldStrings.swift */; };
+		D343DCFE1C446BDB00D7EEE8 /* findPage.html in Resources */ = {isa = PBXBuildFile; fileRef = D343DCFD1C446BDB00D7EEE8 /* findPage.html */; };
+		D34510881ACF415700EC27F0 /* SearchLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34510871ACF415700EC27F0 /* SearchLoader.swift */; };
+		D34DC8531A16C40C00D49B7B /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34DC84D1A16C40C00D49B7B /* Profile.swift */; };
+		D34E33031BA793C2006135F0 /* loginForm.html in Resources */ = {isa = PBXBuildFile; fileRef = D34E33021BA793C2006135F0 /* loginForm.html */; };
+		D36998891AD70A0A00650C6C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D36998881AD70A0A00650C6C /* IOKit.framework */; };
+		D37524871C6E8B5A00A5F6C2 /* topdomains.txt in Resources */ = {isa = PBXBuildFile; fileRef = D37524861C6E8B5A00A5F6C2 /* topdomains.txt */; };
+		D375A9201AE71675001B30D5 /* ViewMemoryLeakTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D375A91F1AE71675001B30D5 /* ViewMemoryLeakTests.swift */; };
+		D37DE2831CA2047500A5EC69 /* CertStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D37DE2821CA2047500A5EC69 /* CertStore.swift */; };
+		D37DE2C71CA356D800A5EC69 /* CertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D37DE2C61CA356D800A5EC69 /* CertTests.swift */; };
+		D37DE2CA1CA356F900A5EC69 /* testcert1.pem in Resources */ = {isa = PBXBuildFile; fileRef = D37DE2C81CA356F900A5EC69 /* testcert1.pem */; };
+		D37DE2CB1CA356F900A5EC69 /* testcert2.pem in Resources */ = {isa = PBXBuildFile; fileRef = D37DE2C91CA356F900A5EC69 /* testcert2.pem */; };
+		D38A1BEE1A9FA2CA00F6A386 /* SiteTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D38A1BEC1A9FA2CA00F6A386 /* SiteTableViewController.swift */; };
+		D38A1EE01CB458EC0080C842 /* CertError.html in Resources */ = {isa = PBXBuildFile; fileRef = D38A1EDF1CB458EC0080C842 /* CertError.html */; };
+		D38B2D8A1A8D98D00040E6B5 /* SearchEngines.swift in Sources */ = {isa = PBXBuildFile; fileRef = D308E4E31A5306F500842685 /* SearchEngines.swift */; };
+		D38B2D8B1A8D98D10040E6B5 /* SearchEngines.swift in Sources */ = {isa = PBXBuildFile; fileRef = D308E4E31A5306F500842685 /* SearchEngines.swift */; };
+		D38B2D8C1A8D98D90040E6B5 /* OpenSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3FA77831A43B2CE0010CD32 /* OpenSearch.swift */; };
+		D38B2D8D1A8D98DA0040E6B5 /* OpenSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3FA77831A43B2CE0010CD32 /* OpenSearch.swift */; };
+		D38F02D11C05127100175932 /* Authenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D38F02D01C05127100175932 /* Authenticator.swift */; };
+		D38F03701C06387900175932 /* AuthenticationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D38F036F1C06387900175932 /* AuthenticationTests.swift */; };
+		D3968F251A38FE8500CEFD3B /* TabManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3968F241A38FE8500CEFD3B /* TabManager.swift */; };
+		D3972BF31C22412B00035B87 /* ShareExtensionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3972BF11C22412B00035B87 /* ShareExtensionHelper.swift */; };
+		D3972BF41C22412B00035B87 /* TitleActivityItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3972BF21C22412B00035B87 /* TitleActivityItemProvider.swift */; };
+		D39FA16C1A83E17800EE869C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D39FA16B1A83E17800EE869C /* CoreGraphics.framework */; };
+		D39FA1811A83E84900EE869C /* Global.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39FA1801A83E84900EE869C /* Global.swift */; };
+		D3A14C221CB3145E00253BC6 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35210E01CB2F16600FC5DCB /* Strings.swift */; };
+		D3A9949C1A3686BD008AD1AC /* BrowserViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3A994951A3686BD008AD1AC /* BrowserViewController.swift */; };
+		D3A9949D1A3686BD008AD1AC /* Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3A994961A3686BD008AD1AC /* Tab.swift */; };
+		D3B6923D1B9F9444004B87A4 /* FindInPageBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3B6923C1B9F9444004B87A4 /* FindInPageBar.swift */; };
+		D3B6923F1B9F9A58004B87A4 /* FindInPageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3B6923E1B9F9A58004B87A4 /* FindInPageHelper.swift */; };
+		D3B692411B9F9CC8004B87A4 /* FindInPage.js in Resources */ = {isa = PBXBuildFile; fileRef = D3B692401B9F9CC8004B87A4 /* FindInPage.js */; };
+		D3BA41681BD82F2200DA5457 /* XCTestCaseExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BA41671BD82F2200DA5457 /* XCTestCaseExtensions.swift */; };
+		D3BA7E0C1B0E902A00153782 /* ContextMenu.js in Resources */ = {isa = PBXBuildFile; fileRef = D3BA7E0B1B0E902A00153782 /* ContextMenu.js */; };
+		D3BA7E0E1B0E934F00153782 /* ContextMenuHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BA7E0D1B0E934F00153782 /* ContextMenuHelper.swift */; };
+		D3BE7B261B054D4400641031 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BE7B251B054D4400641031 /* main.swift */; };
+		D3BE7B461B054F8600641031 /* TestAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BE7B451B054F8600641031 /* TestAppDelegate.swift */; };
+		D3BF8CBB1B7425570007AFE6 /* DiskImageStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BF8CBA1B7425570007AFE6 /* DiskImageStore.swift */; };
+		D3C3696E1CC6B78800348A61 /* LocalRequestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C3696D1CC6B78800348A61 /* LocalRequestHelper.swift */; };
+		D3C3EB651B6FF44000388E9A /* SessionRestoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C3EB641B6FF44000388E9A /* SessionRestoreTests.swift */; };
+		D3C744CD1A687D6C004CE85D /* URIFixup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C744CC1A687D6C004CE85D /* URIFixup.swift */; };
+		D3C744CF1A687D6C004CE85D /* URIFixup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C744CC1A687D6C004CE85D /* URIFixup.swift */; };
+		D3C744D01A687D6C004CE85D /* URIFixup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C744CC1A687D6C004CE85D /* URIFixup.swift */; };
+		D3CFD3641CC5605B0064AB4A /* SecurityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3CFD3631CC5605B0064AB4A /* SecurityTests.swift */; };
+		D3D488591ABB54CD00A93597 /* FileAccessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3D488581ABB54CD00A93597 /* FileAccessorTests.swift */; };
+		D3DBE6E51D6516FE00033FFF /* FxADeviceRegistration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3DBE6E41D6516FE00033FFF /* FxADeviceRegistration.swift */; };
+		D3E171C21A841EAD00AB44CD /* KIFHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = D3E171C11A841EAD00AB44CD /* KIFHelper.js */; };
+		D3E8EF101B97BE69001900FB /* ClearPrivateDataTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E8EEE71B97A87A001900FB /* ClearPrivateDataTableViewController.swift */; };
+		D3FA777B1A43B2990010CD32 /* SearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3FA777A1A43B2990010CD32 /* SearchTests.swift */; };
+		D3FEC38D1AC4B42F00494F45 /* AutocompleteTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3FEC38C1AC4B42F00494F45 /* AutocompleteTextField.swift */; };
+		D81127D81F84023B0050841D /* PhotonActionSheetTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81127D71F84023B0050841D /* PhotonActionSheetTest.swift */; };
+		D81E45131F82C56D004EFFBA /* NewTabContentSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81E45121F82C56C004EFFBA /* NewTabContentSettingsViewController.swift */; };
+		D83822001FC7961D00303C12 /* DispatchQueueExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D83821FF1FC7961D00303C12 /* DispatchQueueExtensions.swift */; };
+		D863C8F21F68BFC20058D95F /* GradientProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D863C8E31F68BFC20058D95F /* GradientProgressBar.swift */; };
+		D88FDA9F1F4E2B9200FD9709 /* PhotonActionSheetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88FDA9E1F4E2B9200FD9709 /* PhotonActionSheetProtocol.swift */; };
+		D88FDAAF1F4E2BA000FD9709 /* PhotonActionSheetAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88FDAAE1F4E2BA000FD9709 /* PhotonActionSheetAnimator.swift */; };
+		DD31E0FB1B382B520077078A /* TabPrintPageRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD31E0FA1B382B520077078A /* TabPrintPageRenderer.swift */; };
+		E402000A1E6493C800B45AFF /* LaunchArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075861E37F7AB006961AC /* LaunchArguments.swift */; };
+		E40AFC541DD0E93300DA5651 /* L10nPermissionStringsSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40AFC531DD0E93300DA5651 /* L10nPermissionStringsSnapshotTests.swift */; };
+		E40AFC651DD0F25500DA5651 /* L10nBaseSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40AFC641DD0F25500DA5651 /* L10nBaseSnapshotTests.swift */; };
+		E40AFC6C1DD128DA00DA5651 /* L10nIntroSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40AFC6B1DD128DA00DA5651 /* L10nIntroSnapshotTests.swift */; };
+		E40FAB0C1A7ABB77009CB80D /* WebServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FAB0B1A7ABB77009CB80D /* WebServer.swift */; };
+		E418D0D91A251B3200CAE47A /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34DC84D1A16C40C00D49B7B /* Profile.swift */; };
+		E41A7D4B1A1BE04500245963 /* InitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41A7D4A1A1BE04500245963 /* InitialViewController.swift */; };
+		E41F0D981ADFFB5400FC7387 /* ReadingListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41F0D971ADFFB5400FC7387 /* ReadingListService.swift */; };
+		E41F0D9B1ADFFC5600FC7387 /* ReadingListError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41F0D9A1ADFFC5600FC7387 /* ReadingListError.swift */; };
+		E42736071EA858CF009C428E /* TabsPayloadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E42736061EA858CF009C428E /* TabsPayloadTests.swift */; };
+		E42CCDE81A23A73D00B794D3 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34DC84D1A16C40C00D49B7B /* Profile.swift */; };
+		E4424B3C1AC71FB400F44C38 /* FiraSans-Book.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4424B3B1AC71FB400F44C38 /* FiraSans-Book.ttf */; };
+		E444F7DC1B4B1B7E00FEB19B /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		E444F7DF1B4B1C1200FEB19B /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34DC84D1A16C40C00D49B7B /* Profile.swift */; };
+		E444F7E01B4B1C1A00FEB19B /* NSUserDefaultsPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD19A661A25309B0084FBA7 /* NSUserDefaultsPrefs.swift */; };
+		E444F7E21B4B1C6800FEB19B /* SearchEngines.swift in Sources */ = {isa = PBXBuildFile; fileRef = D308E4E31A5306F500842685 /* SearchEngines.swift */; };
+		E444F7E31B4B1C8000FEB19B /* OpenSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3FA77831A43B2CE0010CD32 /* OpenSearch.swift */; };
+		E444F7E51B4B1CB600FEB19B /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B8E0FF31A932BD500161DC3 /* ImageIO.framework */; };
+		E444F8271B4C1E8800FEB19B /* Sync.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2827315E1ABC9BE600AA1954 /* Sync.framework */; };
+		E4483B5A1ADED63300B485A7 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		E47536ED1C85412C0022CC69 /* PrintHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47536EC1C85412C0022CC69 /* PrintHelper.swift */; };
+		E47536FC1C85415F0022CC69 /* PrintHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = E47536FB1C85415E0022CC69 /* PrintHelper.js */; };
+		E47616C71AB74CA600E7DD25 /* ReaderModeBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47616C61AB74CA600E7DD25 /* ReaderModeBarView.swift */; };
+		E4791B9C1CC035FD00C6D77B /* testcert1.pem in Resources */ = {isa = PBXBuildFile; fileRef = D37DE2C81CA356F900A5EC69 /* testcert1.pem */; };
+		E4791BAA1CC0360200C6D77B /* testcert2.pem in Resources */ = {isa = PBXBuildFile; fileRef = D37DE2C91CA356F900A5EC69 /* testcert2.pem */; };
+		E487B2331AC1C64300F3E86F /* FiraSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7561A793CF20022C5E0 /* FiraSans-Regular.ttf */; };
+		E487B24E1AC1C66400F3E86F /* FiraSans-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7571A793CF20022C5E0 /* FiraSans-SemiBold.ttf */; };
+		E487B24F1AC1CC9200F3E86F /* FiraSans-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4ECCDAD1AB131770005E717 /* FiraSans-Medium.ttf */; };
+		E487B2501AC1CC9800F3E86F /* FiraSans-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7521A793CF20022C5E0 /* FiraSans-Light.ttf */; };
+		E49943F51AE6879C00BF9DE4 /* IntroViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E49943F41AE6879C00BF9DE4 /* IntroViewController.swift */; };
+		E49943F71AE69EDD00BF9DE4 /* Intro.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E49943F61AE69EDD00BF9DE4 /* Intro.xcassets */; };
+		E49BFF591B1F48C3009368CC /* Readability.js in Resources */ = {isa = PBXBuildFile; fileRef = E49BFF581B1F48C3009368CC /* Readability.js */; };
+		E4A888161A95679500CDC337 /* FxA.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28CE83D01A1D1D5100576538 /* FxA.framework */; };
+		E4A960061ABB9C450069AD6F /* ReaderModeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A960051ABB9C450069AD6F /* ReaderModeUtils.swift */; };
+		E4A961181AC041C40069AD6F /* ReadabilityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A961171AC041C40069AD6F /* ReadabilityService.swift */; };
+		E4A961341AC051360069AD6F /* ReadabilityTabHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A961331AC051360069AD6F /* ReadabilityTabHelper.swift */; };
+		E4A961361AC052DE0069AD6F /* ReadabilityTabHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = E4A961351AC052DE0069AD6F /* ReadabilityTabHelper.js */; };
+		E4A961381AC06FA50069AD6F /* ReaderViewLoading.html in Resources */ = {isa = PBXBuildFile; fileRef = E4A961371AC06FA50069AD6F /* ReaderViewLoading.html */; };
+		E4B334881BBF23F3004E2BFF /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4B334871BBF23F3004E2BFF /* iAd.framework */; };
+		E4B3348A1BBF23F9004E2BFF /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4B334891BBF23F9004E2BFF /* AdSupport.framework */; };
+		E4B3348C1BC01D8F004E2BFF /* AdjustIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B3348B1BC01D8F004E2BFF /* AdjustIntegration.swift */; };
+		E4B423BE1AB9FE6A007E66C8 /* ReaderModeCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B423BD1AB9FE6A007E66C8 /* ReaderModeCache.swift */; };
+		E4B423DD1ABA0318007E66C8 /* ReaderModeHandlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B423DC1ABA0318007E66C8 /* ReaderModeHandlers.swift */; };
+		E4B7B7611A793CF20022C5E0 /* CharisSILB.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B73A1A793CF20022C5E0 /* CharisSILB.ttf */; };
+		E4B7B7621A793CF20022C5E0 /* CharisSILBI.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B73B1A793CF20022C5E0 /* CharisSILBI.ttf */; };
+		E4B7B7631A793CF20022C5E0 /* CharisSILI.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B73C1A793CF20022C5E0 /* CharisSILI.ttf */; };
+		E4B7B7641A793CF20022C5E0 /* CharisSILR.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B73D1A793CF20022C5E0 /* CharisSILR.ttf */; };
+		E4B7B7681A793CF20022C5E0 /* FiraSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7411A793CF20022C5E0 /* FiraSans-Bold.ttf */; };
+		E4B7B7781A793CF20022C5E0 /* FiraSans-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7511A793CF20022C5E0 /* FiraSans-Italic.ttf */; };
+		E4B7B7791A793CF20022C5E0 /* FiraSans-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7521A793CF20022C5E0 /* FiraSans-Light.ttf */; };
+		E4B7B77D1A793CF20022C5E0 /* FiraSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7561A793CF20022C5E0 /* FiraSans-Regular.ttf */; };
+		E4B7B77E1A793CF20022C5E0 /* FiraSans-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B7571A793CF20022C5E0 /* FiraSans-SemiBold.ttf */; };
+		E4B7B7861A793CF20022C5E0 /* FiraSans-UltraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4B7B75F1A793CF20022C5E0 /* FiraSans-UltraLight.ttf */; };
+		E4BA8A351B4B0A1700BC2E95 /* ViewLater.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = E4BA8A2B1B4B0A1600BC2E95 /* ViewLater.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+		E4BA8A8A1B4B10F400BC2E95 /* Storage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* Storage.framework */; };
+		E4BA8AA81B4B15EF00BC2E95 /* ActionRequestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BA8AA11B4B15EF00BC2E95 /* ActionRequestHandler.swift */; };
+		E4BA8AAD1B4B15EF00BC2E95 /* ViewLater.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E4BA8AA61B4B15EF00BC2E95 /* ViewLater.xcassets */; };
+		E4BCAAB91B0537E300855D82 /* InstructionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BCAAB81B0537E300855D82 /* InstructionsViewController.swift */; };
+		E4BCAAD91B05380B00855D82 /* ClientPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BCAAD81B05380B00855D82 /* ClientPickerViewController.swift */; };
+		E4C358551AF144BA00299F7E /* FSReadingList.m in Sources */ = {isa = PBXBuildFile; fileRef = E4C358541AF144BA00299F7E /* FSReadingList.m */; };
+		E4CD9E911A6897FB00318571 /* ReaderMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CD9E901A6897FB00318571 /* ReaderMode.swift */; };
+		E4CD9E9A1A68980A00318571 /* ReaderMode.js in Resources */ = {isa = PBXBuildFile; fileRef = E4CD9E991A68980A00318571 /* ReaderMode.js */; };
+		E4CD9F1D1A6D9C2800318571 /* WebServerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CD9F1C1A6D9C2800318571 /* WebServerTests.swift */; };
+		E4CD9F2D1A6DC91200318571 /* TabLocationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CD9F2C1A6DC91200318571 /* TabLocationView.swift */; };
+		E4CD9F541A71506400318571 /* Reader.html in Resources */ = {isa = PBXBuildFile; fileRef = E4CD9F531A71506400318571 /* Reader.html */; };
+		E4CD9F5B1A71506C00318571 /* Reader.css in Resources */ = {isa = PBXBuildFile; fileRef = E4CD9F5A1A71506C00318571 /* Reader.css */; };
+		E4CD9F6D1A77DD2800318571 /* ReaderModeStyleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CD9F6C1A77DD2800318571 /* ReaderModeStyleViewController.swift */; };
+		E4D567231ADECE2700F1EFE7 /* ReadingList.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4D567181ADECE2700F1EFE7 /* ReadingList.framework */; };
+		E4D5672F1ADECE2800F1EFE7 /* ReadingList.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4D567181ADECE2700F1EFE7 /* ReadingList.framework */; };
+		E4D5676A1ADECE8100F1EFE7 /* ReadingListAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567551ADECE8100F1EFE7 /* ReadingListAuthenticator.swift */; };
+		E4D5676C1ADECE8100F1EFE7 /* ReadingListBasicAuthAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567561ADECE8100F1EFE7 /* ReadingListBasicAuthAuthenticator.swift */; };
+		E4D5676E1ADECE8100F1EFE7 /* ReadingListBatchRecordResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567571ADECE8100F1EFE7 /* ReadingListBatchRecordResponse.swift */; };
+		E4D567701ADECE8100F1EFE7 /* ReadingListChangeAccumulator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567581ADECE8100F1EFE7 /* ReadingListChangeAccumulator.swift */; };
+		E4D567721ADECE8100F1EFE7 /* ReadingListClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567591ADECE8100F1EFE7 /* ReadingListClient.swift */; };
+		E4D567741ADECE8100F1EFE7 /* ReadingListClientMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D5675A1ADECE8100F1EFE7 /* ReadingListClientMetadata.swift */; };
+		E4D567761ADECE8100F1EFE7 /* ReadingListClientRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D5675B1ADECE8100F1EFE7 /* ReadingListClientRecord.swift */; };
+		E4D5677A1ADECE8100F1EFE7 /* ReadingListFetchSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D5675D1ADECE8100F1EFE7 /* ReadingListFetchSpec.swift */; };
+		E4D5677C1ADECE8100F1EFE7 /* ReadingListOAuthAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D5675E1ADECE8100F1EFE7 /* ReadingListOAuthAuthenticator.swift */; };
+		E4D5677E1ADECE8100F1EFE7 /* ReadingListRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D5675F1ADECE8100F1EFE7 /* ReadingListRecord.swift */; };
+		E4D567801ADECE8100F1EFE7 /* ReadingListRecordResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567601ADECE8100F1EFE7 /* ReadingListRecordResponse.swift */; };
+		E4D567821ADECE8100F1EFE7 /* ReadingListRecordsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567611ADECE8100F1EFE7 /* ReadingListRecordsResponse.swift */; };
+		E4D567841ADECE8100F1EFE7 /* ReadingListResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567621ADECE8100F1EFE7 /* ReadingListResponse.swift */; };
+		E4D567861ADECE8100F1EFE7 /* ReadingListServerMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567631ADECE8100F1EFE7 /* ReadingListServerMetadata.swift */; };
+		E4D567881ADECE8100F1EFE7 /* ReadingListServerRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567641ADECE8100F1EFE7 /* ReadingListServerRecord.swift */; };
+		E4D5678A1ADECE8100F1EFE7 /* ReadingListSQLStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567651ADECE8100F1EFE7 /* ReadingListSQLStorage.swift */; };
+		E4D5678C1ADECE8100F1EFE7 /* ReadingListStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567661ADECE8100F1EFE7 /* ReadingListStorage.swift */; };
+		E4D5678E1ADECE8100F1EFE7 /* ReadingListSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567671ADECE8100F1EFE7 /* ReadingListSynchronizer.swift */; };
+		E4D567901ADECE8100F1EFE7 /* ReadingListSyncMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567681ADECE8100F1EFE7 /* ReadingListSyncMetadata.swift */; };
+		E4D567921ADECE8100F1EFE7 /* ReadingListUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567691ADECE8100F1EFE7 /* ReadingListUtils.swift */; };
+		E4D5679F1ADECEB800F1EFE7 /* ReadingListClientRecordTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D567951ADECEB800F1EFE7 /* ReadingListClientRecordTestCase.swift */; };
+		E4D567A51ADECEB800F1EFE7 /* ReadingListStorageTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D5679B1ADECEB800F1EFE7 /* ReadingListStorageTestCase.swift */; };
+		E4D6BEB91A0930EC00F538BD /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = E4D6BEB81A0930EC00F538BD /* LaunchScreen.xib */; };
+		E4E25CCB1CA99E7400D0F088 /* HexExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E25CCA1CA99E7400D0F088 /* HexExtensionsTests.swift */; };
+		E4E7EB6D1C4AED5E0094275D /* SupportUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E7EB6C1C4AED5E0094275D /* SupportUtilsTests.swift */; };
+		E4ECCDAE1AB131770005E717 /* FiraSans-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4ECCDAD1AB131770005E717 /* FiraSans-Medium.ttf */; };
+		E4F21AA61A13C4A300B0FAAA /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E4F21AA51A13C4A300B0FAAA /* Images.xcassets */; };
+		E4F2DAC01F620C0300A556CD /* Leanplum.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4F2DABF1F620C0200A556CD /* Leanplum.framework */; };
+		E4F2DAC11F62C73900A556CD /* Leanplum.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = E4F2DABF1F620C0200A556CD /* Leanplum.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E60138651C89EB7600DF9756 /* Shared.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E60138661C89EB7D00DF9756 /* Storage.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* Storage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E60138671C89EB8300DF9756 /* Account.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 2FA435FB1ABB83B4008031D1 /* Account.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E60138681C89EB8800DF9756 /* Sync.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 2827315E1ABC9BE600AA1954 /* Sync.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E60138691C89EB8E00DF9756 /* ReadingList.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = E4D567181ADECE2700F1EFE7 /* ReadingList.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E601386A1C89EB9800DF9756 /* SQLite.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 7B9A62DB1C4002B1005C83DC /* SQLite.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E60222DC1C6E55610061C436 /* FxA.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28CE83D01A1D1D5100576538 /* FxA.framework */; };
+		E60222E31C6E57B20061C436 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B9A62DB1C4002B1005C83DC /* SQLite.framework */; };
+		E60D03181D511398002FE3F6 /* SyncStatusResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E60D03171D511398002FE3F6 /* SyncStatusResolver.swift */; };
+		E60D03261D511554002FE3F6 /* SyncStatusResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E60D03171D511398002FE3F6 /* SyncStatusResolver.swift */; };
+		E60D03271D511554002FE3F6 /* SyncStatusResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E60D03171D511398002FE3F6 /* SyncStatusResolver.swift */; };
+		E60D03281D511555002FE3F6 /* SyncStatusResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E60D03171D511398002FE3F6 /* SyncStatusResolver.swift */; };
+		E60D032A1D5118DB002FE3F6 /* SyncStatusResolverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E60D03291D5118DB002FE3F6 /* SyncStatusResolverTests.swift */; };
+		E6108FF91C84E91C005D25E8 /* BasePasscodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6108FF81C84E91C005D25E8 /* BasePasscodeViewController.swift */; };
+		E610B0191EDC68FC00DC9372 /* EventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E610B0181EDC68FC00DC9372 /* EventTests.swift */; };
+		E61453BE1B750A1700C3F9D7 /* RollingFileLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E61453BD1B750A1700C3F9D7 /* RollingFileLoggerTests.swift */; };
+		E61D11681EAF8F43008A305B /* PanelDataObserversTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E61D11671EAF8F43008A305B /* PanelDataObserversTests.swift */; };
+		E6231C011B90A44F005ABB0D /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6231C001B90A44F005ABB0D /* libz.tbd */; };
+		E6231C031B90A466005ABB0D /* libstdc++.6.0.9.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6231C021B90A466005ABB0D /* libstdc++.6.0.9.tbd */; };
+		E6231C051B90A472005ABB0D /* libxml2.2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6231C041B90A472005ABB0D /* libxml2.2.tbd */; };
+		E6231C071B90A712005ABB0D /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6231C001B90A44F005ABB0D /* libz.tbd */; };
+		E6231C081B90A71E005ABB0D /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6231C001B90A44F005ABB0D /* libz.tbd */; };
+		E62CFB3D1C89EFF700C01324 /* FxA.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 28CE83D01A1D1D5100576538 /* FxA.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E6327A641BF6438E008D12E0 /* DebugSettingsBundleOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6327A631BF6438E008D12E0 /* DebugSettingsBundleOptions.swift */; };
+		E633E2DA1C21EAF8001FFF6C /* LoginDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E633E2D91C21EAF8001FFF6C /* LoginDetailViewController.swift */; };
+		E633E37A1C2204BE001FFF6C /* LoginManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E633E3791C2204BE001FFF6C /* LoginManagerTests.swift */; };
+		E63ED7D81BFCD9990097D08E /* LoginTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E63ED7D71BFCD9990097D08E /* LoginTableViewCell.swift */; };
+		E63ED8E11BFD25580097D08E /* LoginListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E63ED8E01BFD25580097D08E /* LoginListViewController.swift */; };
+		E63F71881DB7FBE200A995C9 /* TestSQLiteMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E63F71871DB7FBE200A995C9 /* TestSQLiteMetadata.swift */; };
+		E640E85E1C73A45A00C5F072 /* PasscodeEntryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E640E85D1C73A45A00C5F072 /* PasscodeEntryViewController.swift */; };
+		E640E86A1C73A47C00C5F072 /* PasscodeViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = E640E8691C73A47C00C5F072 /* PasscodeViews.swift */; };
+		E64ED8FA1BC55AE300DAF864 /* UIAlertControllerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64ED8F91BC55AE300DAF864 /* UIAlertControllerExtensions.swift */; };
+		E650754E1E37F6AE006961AC /* GeometryExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650754D1E37F6AE006961AC /* GeometryExtensions.swift */; };
+		E65075511E37F6D1006961AC /* NSURLExtensionsMailTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650754F1E37F6D1006961AC /* NSURLExtensionsMailTo.swift */; };
+		E65075521E37F6D1006961AC /* UIViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075501E37F6D1006961AC /* UIViewExtensions.swift */; };
+		E65075541E37F6FC006961AC /* DynamicFontHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075531E37F6FC006961AC /* DynamicFontHelper.swift */; };
+		E65075571E37F714006961AC /* FaviconFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075561E37F714006961AC /* FaviconFetcher.swift */; };
+		E650755C1E37F747006961AC /* Swizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = E650755B1E37F747006961AC /* Swizzling.m */; };
+		E650755F1E37F756006961AC /* Try.m in Sources */ = {isa = PBXBuildFile; fileRef = E650755E1E37F756006961AC /* Try.m */; };
+		E65075611E37F77D006961AC /* MenuHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075601E37F77D006961AC /* MenuHelper.swift */; };
+		E65075921E37F7AB006961AC /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075621E37F7AB006961AC /* Accessibility.swift */; };
+		E65075931E37F7AB006961AC /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075631E37F7AB006961AC /* AppConstants.swift */; };
+		E65075941E37F7AB006961AC /* AppInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075641E37F7AB006961AC /* AppInfo.swift */; };
+		E65075951E37F7AB006961AC /* AssertionUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075651E37F7AB006961AC /* AssertionUtils.swift */; };
+		E65075961E37F7AB006961AC /* AsyncReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075661E37F7AB006961AC /* AsyncReducer.swift */; };
+		E65075971E37F7AB006961AC /* AuthenticationKeychainInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075671E37F7AB006961AC /* AuthenticationKeychainInfo.swift */; };
+		E65075981E37F7AB006961AC /* Bytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075681E37F7AB006961AC /* Bytes.swift */; };
+		E65075991E37F7AB006961AC /* Cancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075691E37F7AB006961AC /* Cancellable.swift */; };
+		E650759A1E37F7AB006961AC /* CrashSimulator.h in Headers */ = {isa = PBXBuildFile; fileRef = E650756A1E37F7AB006961AC /* CrashSimulator.h */; };
+		E650759B1E37F7AB006961AC /* CrashSimulator.m in Sources */ = {isa = PBXBuildFile; fileRef = E650756B1E37F7AB006961AC /* CrashSimulator.m */; };
+		E650759C1E37F7AB006961AC /* DeferredUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650756C1E37F7AB006961AC /* DeferredUtils.swift */; };
+		E650759D1E37F7AB006961AC /* DeviceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650756D1E37F7AB006961AC /* DeviceInfo.swift */; };
+		E650759E1E37F7AB006961AC /* effective_tld_names.dat in Resources */ = {isa = PBXBuildFile; fileRef = E650756E1E37F7AB006961AC /* effective_tld_names.dat */; };
+		E65075A01E37F7AB006961AC /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075711E37F7AB006961AC /* ArrayExtensions.swift */; };
+		E65075A11E37F7AB006961AC /* HashExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075721E37F7AB006961AC /* HashExtensions.swift */; };
+		E65075A21E37F7AB006961AC /* HexExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075731E37F7AB006961AC /* HexExtensions.swift */; };
+		E65075A31E37F7AB006961AC /* KeychainWrapperExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075741E37F7AB006961AC /* KeychainWrapperExtensions.swift */; };
+		E65075A41E37F7AB006961AC /* NSCharacterSetExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075751E37F7AB006961AC /* NSCharacterSetExtensions.swift */; };
+		E65075A51E37F7AB006961AC /* NSFileManagerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075761E37F7AB006961AC /* NSFileManagerExtensions.swift */; };
+		E65075A61E37F7AB006961AC /* NSMutableAttributedStringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075771E37F7AB006961AC /* NSMutableAttributedStringExtensions.swift */; };
+		E65075A71E37F7AB006961AC /* NSScannerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075781E37F7AB006961AC /* NSScannerExtensions.swift */; };
+		E65075A81E37F7AB006961AC /* NSStringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075791E37F7AB006961AC /* NSStringExtensions.swift */; };
+		E65075A91E37F7AB006961AC /* NSURLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650757A1E37F7AB006961AC /* NSURLExtensions.swift */; };
+		E65075AA1E37F7AB006961AC /* NSURLProtectionSpaceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650757B1E37F7AB006961AC /* NSURLProtectionSpaceExtensions.swift */; };
+		E65075AB1E37F7AB006961AC /* SetExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650757C1E37F7AB006961AC /* SetExtensions.swift */; };
+		E65075AC1E37F7AB006961AC /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650757D1E37F7AB006961AC /* StringExtensions.swift */; };
+		E65075AD1E37F7AB006961AC /* UIColorExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650757E1E37F7AB006961AC /* UIColorExtensions.swift */; };
+		E65075AE1E37F7AB006961AC /* UIImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650757F1E37F7AB006961AC /* UIImageExtensions.swift */; };
+		E65075B01E37F7AB006961AC /* FSUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = E65075811E37F7AB006961AC /* FSUtils.h */; };
+		E65075B11E37F7AB006961AC /* FSUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E65075821E37F7AB006961AC /* FSUtils.m */; };
+		E65075B21E37F7AB006961AC /* Functions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075831E37F7AB006961AC /* Functions.swift */; };
+		E65075B31E37F7AB006961AC /* KeyboardHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075841E37F7AB006961AC /* KeyboardHelper.swift */; };
+		E65075B41E37F7AB006961AC /* KeychainCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075851E37F7AB006961AC /* KeychainCache.swift */; };
+		E65075B51E37F7AB006961AC /* LaunchArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075861E37F7AB006961AC /* LaunchArguments.swift */; };
+		E65075B61E37F7AB006961AC /* Loader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075871E37F7AB006961AC /* Loader.swift */; };
+		E65075B71E37F7AB006961AC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075881E37F7AB006961AC /* Logger.swift */; };
+		E65075B81E37F7AB006961AC /* NotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075891E37F7AB006961AC /* NotificationConstants.swift */; };
+		E65075BA1E37F7AB006961AC /* Prefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650758B1E37F7AB006961AC /* Prefs.swift */; };
+		E65075BB1E37F7AB006961AC /* RollingFileLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650758C1E37F7AB006961AC /* RollingFileLogger.swift */; };
+		E65075BC1E37F7AB006961AC /* SupportUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650758D1E37F7AB006961AC /* SupportUtils.swift */; };
+		E65075BD1E37F7AB006961AC /* SystemUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650758E1E37F7AB006961AC /* SystemUtils.swift */; };
+		E65075BE1E37F7AB006961AC /* TimeConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E650758F1E37F7AB006961AC /* TimeConstants.swift */; };
+		E65075BF1E37F7AB006961AC /* UserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075901E37F7AB006961AC /* UserAgent.swift */; };
+		E65075C01E37F7AB006961AC /* WeakList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075911E37F7AB006961AC /* WeakList.swift */; };
+		E65075C21E37F956006961AC /* ExtensionUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075C11E37F956006961AC /* ExtensionUtils.swift */; };
+		E653422D1C5944F90039DD9E /* BrowserPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = E653422C1C5944F90039DD9E /* BrowserPrompts.swift */; };
+		E65607611C08B4E200534B02 /* SearchInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65607601C08B4E200534B02 /* SearchInputView.swift */; };
+		E65D89181C8647420006EA35 /* AppAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65D89171C8647420006EA35 /* AppAuthenticator.swift */; };
+		E660BDD91BB06521009AC090 /* TabsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E660BDD81BB06521009AC090 /* TabsButton.swift */; };
+		E660BE061BB0666D009AC090 /* InnerStrokedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E660BE051BB0666D009AC090 /* InnerStrokedView.swift */; };
+		E663D5781BB341C4001EF30E /* ToggleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E663D5771BB341C4001EF30E /* ToggleButton.swift */; };
+		E66C5B481BDA81050051AA93 /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = E66C5B471BDA81050051AA93 /* UIImage+ImageEffects.m */; };
+		E67035EE1E538B500037AB83 /* Mocking.swift in Sources */ = {isa = PBXBuildFile; fileRef = E67035ED1E538B500037AB83 /* Mocking.swift */; };
+		E67422C51CFF2D39009E8373 /* youtube.ico in Resources */ = {isa = PBXBuildFile; fileRef = E67422C41CFF2D39009E8373 /* youtube.ico */; };
+		E677F0451D9423FB00ECF1FB /* SQLiteMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E677F0441D9423FB00ECF1FB /* SQLiteMetadata.swift */; };
+		E677F0541D94247300ECF1FB /* Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E677F0531D94247300ECF1FB /* Metadata.swift */; };
+		E67D57031D527449003917B1 /* BatchingClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E67D57021D527449003917B1 /* BatchingClient.swift */; };
+		E683F0A61E92E0820035D990 /* MockableHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E683F0A51E92E0820035D990 /* MockableHistory.swift */; };
+		E683F0C21E93D4E90035D990 /* DictionaryExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E683F0C11E93D4E90035D990 /* DictionaryExtensions.swift */; };
+		E689C6F81E0C6E72008BAADB /* FxASignIn.js in Resources */ = {isa = PBXBuildFile; fileRef = E689C6F71E0C6E72008BAADB /* FxASignIn.js */; };
+		E689C6FA1E0C6E98008BAADB /* FxAContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E689C6F91E0C6E98008BAADB /* FxAContentViewController.swift */; };
+		E689C7301E0C7617008BAADB /* NSAttributedStringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E689C72F1E0C7617008BAADB /* NSAttributedStringExtensions.swift */; };
+		E68AEDB01B18F81A00133D99 /* SwipeAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68AEDAF1B18F81A00133D99 /* SwipeAnimator.swift */; };
+		E68E39BE1C46F42000B85F42 /* AppSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68E39BD1C46F42000B85F42 /* AppSettingsTableViewController.swift */; };
+		E68E7ACB1CAC1D4500FDCA76 /* PagingPasscodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68E7ACA1CAC1D4500FDCA76 /* PagingPasscodeViewController.swift */; };
+		E68E7ADA1CAC207400FDCA76 /* ChangePasscodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68E7AD91CAC207400FDCA76 /* ChangePasscodeViewController.swift */; };
+		E68E7ADC1CAC208200FDCA76 /* SetupPasscodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68E7ADB1CAC208200FDCA76 /* SetupPasscodeViewController.swift */; };
+		E68E7ADE1CAC208A00FDCA76 /* RemovePasscodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68E7ADD1CAC208A00FDCA76 /* RemovePasscodeViewController.swift */; };
+		E68F36981EA694000048CF44 /* PanelDataObservers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68F36971EA694000048CF44 /* PanelDataObservers.swift */; };
+		E68F36AB1EA698610048CF44 /* PanelDataObservers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68F36971EA694000048CF44 /* PanelDataObservers.swift */; };
+		E68F36AC1EA698610048CF44 /* PanelDataObservers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68F36971EA694000048CF44 /* PanelDataObservers.swift */; };
+		E68F36AD1EA698650048CF44 /* PanelDataObservers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68F36971EA694000048CF44 /* PanelDataObservers.swift */; };
+		E6927EC01C7B6FB800D03F75 /* ErrorToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6927EBF1C7B6FB800D03F75 /* ErrorToast.swift */; };
+		E692E3291C46E62D009D1240 /* AuthenticationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E692E3281C46E62D009D1240 /* AuthenticationSettingsViewController.swift */; };
+		E692E3371C46E86A009D1240 /* AppSettingsOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E692E3361C46E86A009D1240 /* AppSettingsOptions.swift */; };
+		E693F0D91E9D64BD0086DC17 /* OptionalExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E693F0D81E9D64BD0086DC17 /* OptionalExtensions.swift */; };
+		E696FE511C47F86E00EC007C /* AuthenticatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E696FE501C47F86E00EC007C /* AuthenticatorTests.swift */; };
+		E698FFDA1B4AADF40001F623 /* TabScrollController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E698FFD91B4AADF40001F623 /* TabScrollController.swift */; };
+		E69922171B94E3EF007C480D /* Licenses.html in Resources */ = {isa = PBXBuildFile; fileRef = E69922121B94E3EF007C480D /* Licenses.html */; };
+		E69DB07E1E97DEAA008A67E6 /* SyncTelemetry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E69DB0751E97DEA9008A67E6 /* SyncTelemetry.framework */; };
+		E69DB0871E97DEAA008A67E6 /* SyncTelemetry.h in Headers */ = {isa = PBXBuildFile; fileRef = E69DB0771E97DEA9008A67E6 /* SyncTelemetry.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		E69DB08A1E97DEAA008A67E6 /* SyncTelemetry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E69DB0751E97DEA9008A67E6 /* SyncTelemetry.framework */; };
+		E69DB08B1E97DEAA008A67E6 /* SyncTelemetry.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = E69DB0751E97DEA9008A67E6 /* SyncTelemetry.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E69DB0A81E97DF22008A67E6 /* SyncTelemetry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E69DB0751E97DEA9008A67E6 /* SyncTelemetry.framework */; };
+		E69DB0A91E97DF73008A67E6 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		E69DB0B71E97E2AC008A67E6 /* SyncTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69DB0B51E97E2AC008A67E6 /* SyncTelemetry.swift */; };
+		E69DB0BD1E97E301008A67E6 /* ActivityStreamTopics.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69DB0BA1E97E301008A67E6 /* ActivityStreamTopics.swift */; };
+		E69DB0C31E97E320008A67E6 /* BookmarkTelemetryPing.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69DB0C01E97E320008A67E6 /* BookmarkTelemetryPing.swift */; };
+		E69E06BA1C76173D00D0F926 /* RequirePasscodeIntervalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69E06B91C76173D00D0F926 /* RequirePasscodeIntervalViewController.swift */; };
+		E69E06C91C76198000D0F926 /* AuthenticationManagerConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69E06C81C76198000D0F926 /* AuthenticationManagerConstants.swift */; };
+		E6A92ADB1C52A8DA00743291 /* LoginInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A92ADA1C52A8DA00743291 /* LoginInputTests.swift */; };
+		E6B4C3D81C68F55C001F97E8 /* JSPrompt.html in Resources */ = {isa = PBXBuildFile; fileRef = E6B4C3D71C68F55C001F97E8 /* JSPrompt.html */; };
+		E6B4C4031C68F58B001F97E8 /* BrowserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6B4C4021C68F58B001F97E8 /* BrowserTests.swift */; };
+		E6BA20211E52170E00697F9C /* SyncTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6BA20111E52165800697F9C /* SyncTelemetryTests.swift */; };
+		E6BE53CD1D9177B10074909A /* TestSQLiteHistoryRecommendations.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6BE53CC1D9177B10074909A /* TestSQLiteHistoryRecommendations.swift */; };
+		E6C70E821E28314700F8DB57 /* PingCentreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6C70E811E28314700F8DB57 /* PingCentreTests.swift */; };
+		E6C9EB6B1E2FBFC300D5CE80 /* signedInUser.json in Resources */ = {isa = PBXBuildFile; fileRef = E6C9EB6A1E2FBFC300D5CE80 /* signedInUser.json */; };
+		E6CF28E71CB43B7900151AB3 /* SensitiveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6CF28E61CB43B7900151AB3 /* SensitiveViewController.swift */; };
+		E6D7C32B1CF4E86C00E746BA /* TestBookmarkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D7C31C1CF4E68D00E746BA /* TestBookmarkModel.swift */; };
+		E6D8D5E71B569D70009E5A58 /* BrowserTrayAnimators.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D8D5E61B569D70009E5A58 /* BrowserTrayAnimators.swift */; };
+		E6EAC5961B29CB3A00E1DE1E /* scrollablePage.html in Resources */ = {isa = PBXBuildFile; fileRef = E6EAC5951B29CB3A00E1DE1E /* scrollablePage.html */; };
+		E6EC6EED1E53548A0067985D /* EarlGrey.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B21E8051E26CCB7000C8779 /* EarlGrey.framework */; };
+		E6ECF2381C974E0F00B0DC93 /* KIF.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D30EBB6A1C75503800105AE9 /* KIF.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		E6EDE82C1D5244AF007A0732 /* BatchingClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6EDE81D1D524475007A0732 /* BatchingClientTests.swift */; };
+		E6F368291D7F594F008CDD67 /* SQLiteHistoryRecommendations.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F368281D7F594F008CDD67 /* SQLiteHistoryRecommendations.swift */; };
+		E6F6D6A31E9E6B2A0012072B /* DeferredTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */; };
+		E6F6D6A41E9E6B2B0012072B /* DeferredTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */; };
+		E6F6D6A51E9E6B2B0012072B /* DeferredTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */; };
+		E6F6D6A61E9E6B2C0012072B /* DeferredTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */; };
+		E6F6D6A71E9E6B2D0012072B /* DeferredTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */; };
+		E6F6D6AA1E9E6B300012072B /* DeferredTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */; };
+		E6F6D6AB1E9E6B330012072B /* DeferredTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */; };
+		E6F965121B2F1CF20034B023 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
+		E6F9653C1B2F1D5D0034B023 /* NSURLExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F9653B1B2F1D5D0034B023 /* NSURLExtensionsTests.swift */; };
+		E6F965421B2F25110034B023 /* NSMutableAttributedStringExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F965411B2F25110034B023 /* NSMutableAttributedStringExtensionsTests.swift */; };
+		E6FF6ACA1D873CFF0070C294 /* PageMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FF6AC91D873CFF0070C294 /* PageMetadata.swift */; };
+		EB2A63341F3B49A7004EF8B0 /* ContentBlockerHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB2A63251F3B49A7004EF8B0 /* ContentBlockerHelper.swift */; };
+		EB2A633B1F3B513B004EF8B0 /* disconnect-advertising.json in Resources */ = {isa = PBXBuildFile; fileRef = EB2A63381F3B5135004EF8B0 /* disconnect-advertising.json */; };
+		EB2A633C1F3B513E004EF8B0 /* disconnect-analytics.json in Resources */ = {isa = PBXBuildFile; fileRef = EB2A63361F3B5134004EF8B0 /* disconnect-analytics.json */; };
+		EB2A633E1F3B514A004EF8B0 /* disconnect-content.json in Resources */ = {isa = PBXBuildFile; fileRef = EB2A63371F3B5135004EF8B0 /* disconnect-content.json */; };
+		EB2A633F1F3B514B004EF8B0 /* disconnect-social.json in Resources */ = {isa = PBXBuildFile; fileRef = EB2A63391F3B5135004EF8B0 /* disconnect-social.json */; };
+		EBA31D791F7999030055463D /* SyncPingCentre.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBA31D781F7999030055463D /* SyncPingCentre.swift */; };
+		EBA31D7B1F79990C0055463D /* SyncTelemetryEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBA31D7A1F79990C0055463D /* SyncTelemetryEvents.swift */; };
+		EBA31D7D1F79996E0055463D /* SyncTelemetryUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBA31D7C1F79996E0055463D /* SyncTelemetryUtils.swift */; };
+		EBA31D861F799BE20055463D /* Telemetry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBA31D7E1F799BE20055463D /* Telemetry.framework */; };
+		EBF47E701F7979DF00899189 /* UnifiedTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBF47E6F1F7979DF00899189 /* UnifiedTelemetry.swift */; };
+		F35B8D2B1D6380EA008E3D61 /* SessionRestore.html in Resources */ = {isa = PBXBuildFile; fileRef = F35B8D2A1D6380EA008E3D61 /* SessionRestore.html */; };
+		F35B8D2D1D6383E9008E3D61 /* SessionRestoreHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = F35B8D2C1D6383E9008E3D61 /* SessionRestoreHelper.swift */; };
+		F35B8D2F1D638408008E3D61 /* SessionRestoreHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F35B8D2E1D638408008E3D61 /* SessionRestoreHandler.swift */; };
+		F84B21DA1A090F8100AAB793 /* ClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84B21D91A090F8100AAB793 /* ClientTests.swift */; };
+		F84B22041A0910F600AAB793 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84B21E51A0910F600AAB793 /* AppDelegate.swift */; };
+		F84B220B1A0910F600AAB793 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F84B21EF1A0910F600AAB793 /* Images.xcassets */; };
+		F84B22241A09122500AAB793 /* HomePanelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84B22221A09122500AAB793 /* HomePanelViewController.swift */; };
+		F84B22541A0920C600AAB793 /* ShareTo.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = F84B22491A0920C600AAB793 /* ShareTo.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+		F84B22661A09210A00AAB793 /* SendTo.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = F84B225C1A09210A00AAB793 /* SendTo.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+		F8708D2A1A0970B40051AB07 /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8708D201A0970990051AB07 /* ActionViewController.swift */; };
+		F8708D2C1A0970B40051AB07 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F8708D221A0970990051AB07 /* MainInterface.storyboard */; };
+		F8708D2E1A0970B70051AB07 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F8708D251A0970990051AB07 /* Images.xcassets */; };
+		F8708D321A0970B70051AB07 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8708D291A0970990051AB07 /* ShareViewController.swift */; };
+		FA6B2AC21D41F02D00429414 /* Punycode.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA6B2AC11D41F02D00429414 /* Punycode.swift */; };
+		FA6B2AC31D41F02D00429414 /* Punycode.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA6B2AC11D41F02D00429414 /* Punycode.swift */; };
+		FA6B2AC41D41F02D00429414 /* Punycode.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA6B2AC11D41F02D00429414 /* Punycode.swift */; };
+		FA9293D41D6580E100AC8D33 /* QRCodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9293D31D6580E100AC8D33 /* QRCodeViewController.swift */; };
+		FA9294011D6584A200AC8D33 /* QRCode.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA9294001D6584A200AC8D33 /* QRCode.xcassets */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		0B742CCB1B32491400EE9264 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 0B742CC61B32491400EE9264 /* sqlcipher.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = D2AAC046055464E500DB518D;
+			remoteInfo = sqlcipher;
+		};
+		0B742CCD1B32493800EE9264 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 0B742CC61B32491400EE9264 /* sqlcipher.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = D2AAC045055464E500DB518D;
+			remoteInfo = sqlcipher;
+		};
+		2827316A1ABC9BE700AA1954 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2827315D1ABC9BE600AA1954;
+			remoteInfo = Sync;
+		};
+		282731731ABC9BE700AA1954 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2827315D1ABC9BE600AA1954;
+			remoteInfo = Sync;
+		};
+		288A2D9B1AB8B3260023ABC3 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		28CE83CF1A1D1D5100576538 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 28F951FB19D0F9FA00DCE892;
+			remoteInfo = FxA;
+		};
+		28CE83D11A1D1D5100576538 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 28F9520619D0F9FB00DCE892;
+			remoteInfo = FxATests;
+		};
+		28ECD9BE1BA1F12B00D829DA /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		2F11EE4F1ABCAE910083902D /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		2F14E1171ABB88CB00FF98DB /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 28F951FA19D0F9FA00DCE892;
+			remoteInfo = FxA;
+		};
+		2F14E1331ABB88CF00FF98DB /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		2F77F69C1ABCAEFE00484F3A /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 28F951FA19D0F9FA00DCE892;
+			remoteInfo = FxA;
+		};
+		2F77F6B81ABCAF0700484F3A /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FA435FA1ABB83B4008031D1;
+			remoteInfo = Account;
+		};
+		2F9A72311ABB856100F9F05D /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FCAE2191ABB51F800877008;
+			remoteInfo = Storage;
+		};
+		2F9A72331ABB856A00F9F05D /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FCAE2191ABB51F800877008;
+			remoteInfo = Storage;
+		};
+		2FA436101ABB83B4008031D1 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FA435FA1ABB83B4008031D1;
+			remoteInfo = Account;
+		};
+		2FA4361C1ABB83DD008031D1 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		2FA436431ABB84CB008031D1 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 28F951FA19D0F9FA00DCE892;
+			remoteInfo = FxA;
+		};
+		2FC87C3C1BC45E67001BAE77 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FA435FA1ABB83B4008031D1;
+			remoteInfo = Account;
+		};
+		2FCAE2261ABB51F800877008 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FCAE2191ABB51F800877008;
+			remoteInfo = Storage;
+		};
+		2FCAE2281ABB51F800877008 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		2FCAE22F1ABB51F800877008 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FCAE2191ABB51F800877008;
+			remoteInfo = Storage;
+		};
+		2FCAE23B1ABB520700877008 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		390527541C874D35007E0BB7 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 390527491C874D35007E0BB7;
+			remoteInfo = Today;
+		};
+		397848E01ED86605004C0C0B /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 397848DA1ED86605004C0C0B;
+			remoteInfo = NotificationService;
+		};
+		3B43E3D51D95C48D00BBA9DB /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		3BFE4B0C1D342FB900DDF53F /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		7B10AAE51E3A57F90002DD08 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = EE247ADD1C3F04ED00AE3E12;
+			remoteInfo = "SQLiteTests iOS";
+		};
+		7B10AAE71E3A57F90002DD08 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = EE247B451C3F3ED000AE3E12;
+			remoteInfo = "SQLiteTests Mac";
+		};
+		7B10AAE91E3A57F90002DD08 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 03A65E5A1C6BB0F50062603F;
+			remoteInfo = "SQLite tvOS";
+		};
+		7B10AAEB1E3A57F90002DD08 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 03A65E631C6BB0F60062603F;
+			remoteInfo = "SQLiteTests tvOS";
+		};
+		7B10AAED1E3A57F90002DD08 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = A121AC451CA35C79005A31D1;
+			remoteInfo = "SQLite watchOS";
+		};
+		7B10AAEF1E3A58C80002DD08 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		7B9A62DA1C4002B1005C83DC /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = DC2B29E21B26F718001C60EA;
+			remoteInfo = "SQLite iOS";
+		};
+		7B9A62DE1C4002B1005C83DC /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = DC7253AC1B52ADEB009B38B1;
+			remoteInfo = "SQLite Mac";
+		};
+		7B9A62F81C400303005C83DC /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = EE247AD21C3F04ED00AE3E12;
+			remoteInfo = "SQLite iOS";
+		};
+		7B9BF92E1E435DE400CB24F4 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FCAE2231ABB51F800877008;
+			remoteInfo = StorageTests;
+		};
+		7BEB64421C7345600092C02E /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		7BEB645C1C7346100092C02E /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		D09A0CDE1FAA2577009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		D09A0CE01FAA25C5009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		D09A0CE41FAA2C18009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		D09A0CE61FAA2C1B009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FCAE2191ABB51F800877008;
+			remoteInfo = Storage;
+		};
+		D09A0CE81FAA2C1E009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2827315D1ABC9BE600AA1954;
+			remoteInfo = Sync;
+		};
+		D09A0CEA1FAA2C38009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E4D567171ADECE2700F1EFE7;
+			remoteInfo = ReadingList;
+		};
+		D09A0CEC1FAA2C4C009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		D09A0CEE1FAA2C66009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 28F951FA19D0F9FA00DCE892;
+			remoteInfo = FxA;
+		};
+		D09A0CF01FAA2C7E009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		D09A0CF21FAA2C81009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2827315D1ABC9BE600AA1954;
+			remoteInfo = Sync;
+		};
+		D09A0CF41FAA2C99009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E4D567171ADECE2700F1EFE7;
+			remoteInfo = ReadingList;
+		};
+		D09A0CF61FAA2CB2009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 28F951FA19D0F9FA00DCE892;
+			remoteInfo = FxA;
+		};
+		D09A0CF81FAA2CBF009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		D09A0CFA1FAA2CC2009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2827315D1ABC9BE600AA1954;
+			remoteInfo = Sync;
+		};
+		D09A0CFC1FAA2CC5009A0273 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E4D567171ADECE2700F1EFE7;
+			remoteInfo = ReadingList;
+		};
+		D0EA58121FA836CA00D03ED1 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2827315D1ABC9BE600AA1954;
+			remoteInfo = Sync;
+		};
+		D0EA58141FA836CE00D03ED1 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FCAE2191ABB51F800877008;
+			remoteInfo = Storage;
+		};
+		D0EA58161FA836D200D03ED1 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		D30EBB631C75503800105AE9 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = EABD46AA1857A0C700A5F081;
+			remoteInfo = KIF;
+		};
+		D30EBB651C75503800105AE9 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = EB60ECC1177F8C83005A041A;
+			remoteInfo = "Test Host";
+		};
+		D30EBB671C75503800105AE9 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = EABD46CD1857A0F300A5F081;
+			remoteInfo = "KIF Tests";
+		};
+		D30EBB691C75503800105AE9 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 9CC9673B1AD4B1B600576D13;
+			remoteInfo = KIFFramework;
+		};
+		D39FA1651A83E0EC00EE869C /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		E4A888181A95679500CDC337 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 28F951FA19D0F9FA00DCE892;
+			remoteInfo = FxA;
+		};
+		E4BA8A331B4B0A1700BC2E95 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E4BA8A2A1B4B0A1600BC2E95;
+			remoteInfo = ViewLater;
+		};
+		E4D567241ADECE2700F1EFE7 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E4D567171ADECE2700F1EFE7;
+			remoteInfo = ReadingList;
+		};
+		E4D5672D1ADECE2800F1EFE7 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E4D567171ADECE2700F1EFE7;
+			remoteInfo = ReadingList;
+		};
+		E4EE05AF1BA3A0A10021B3A7 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 2FCAE2191ABB51F800877008;
+			remoteInfo = Storage;
+		};
+		E60222E51C6E5A770061C436 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 28F951FA19D0F9FA00DCE892;
+			remoteInfo = FxA;
+		};
+		E63CD1B11B31B66400A63AFF /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 288A2D851AB8B3260023ABC3;
+			remoteInfo = Shared;
+		};
+		E63CD1B21B31B66400A63AFF /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		E69DB07F1E97DEAA008A67E6 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E69DB0741E97DEA9008A67E6;
+			remoteInfo = SyncTelemetry;
+		};
+		E69DB0811E97DEAA008A67E6 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		E69DB0881E97DEAA008A67E6 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E69DB0741E97DEA9008A67E6;
+			remoteInfo = SyncTelemetry;
+		};
+		E69DB0A61E97DEF6008A67E6 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E69DB0741E97DEA9008A67E6;
+			remoteInfo = SyncTelemetry;
+		};
+		E6CB64CB1DA42C2900887098 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = FAB89FFC1CAC546900C6DFC1;
+			remoteInfo = KIFFrameworkConsumer;
+		};
+		E6CB64CD1DA42C2900887098 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = FAB8A0141CAC546A00C6DFC1;
+			remoteInfo = KIFFrameworkConsumerTests;
+		};
+		F84B21D41A090F8100AAB793 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B21BD1A090F8100AAB793;
+			remoteInfo = Client;
+		};
+		F84B22511A0920C600AAB793 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B22481A0920C600AAB793;
+			remoteInfo = ShareToFirefox;
+		};
+		F84B22641A09210A00AAB793 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = F84B21B61A090F8100AAB793 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F84B225B1A09210A00AAB793;
+			remoteInfo = SendToDevice;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		0B21E8011E26C5D3000C8779 /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "$(TEST_HOST)/..";
+			dstSubfolderSpec = 0;
+			files = (
+				0B21E8061E26CCB7000C8779 /* EarlGrey.framework in CopyFiles */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2F3444EC1AB2378200FD9731 /* Copy Files */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 7;
+			files = (
+			);
+			name = "Copy Files";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E6B09CD31C74EEDB00C63FA1 /* Copy Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+				E4F2DAC11F62C73900A556CD /* Leanplum.framework in Copy Frameworks */,
+				E62CFB3D1C89EFF700C01324 /* FxA.framework in Copy Frameworks */,
+				E601386A1C89EB9800DF9756 /* SQLite.framework in Copy Frameworks */,
+				E69DB08B1E97DEAA008A67E6 /* SyncTelemetry.framework in Copy Frameworks */,
+				E60138691C89EB8E00DF9756 /* ReadingList.framework in Copy Frameworks */,
+				E60138681C89EB8800DF9756 /* Sync.framework in Copy Frameworks */,
+				E60138671C89EB8300DF9756 /* Account.framework in Copy Frameworks */,
+				E60138661C89EB7D00DF9756 /* Storage.framework in Copy Frameworks */,
+				E60138651C89EB7600DF9756 /* Shared.framework in Copy Frameworks */,
+			);
+			name = "Copy Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E6ECF2371C974E0600B0DC93 /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+				E6ECF2381C974E0F00B0DC93 /* KIF.framework in CopyFiles */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B22531A0920C600AAB793 /* Embed App Extensions */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 13;
+			files = (
+				390527561C874D35007E0BB7 /* Today.appex in Embed App Extensions */,
+				397848E21ED86605004C0C0B /* NotificationService.appex in Embed App Extensions */,
+				F84B22541A0920C600AAB793 /* ShareTo.appex in Embed App Extensions */,
+				F84B22661A09210A00AAB793 /* SendTo.appex in Embed App Extensions */,
+				E4BA8A351B4B0A1700BC2E95 /* ViewLater.appex in Embed App Extensions */,
+			);
+			name = "Embed App Extensions";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		03CCC9171AF05E7300DBF30D /* RelativeDatesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelativeDatesTests.swift; sourceTree = ""; };
+		0B1C05D51A798B1F004C78B0 /* UIImageViewAligned.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIImageViewAligned.h; sourceTree = ""; };
+		0B1C05D61A798B1F004C78B0 /* UIImageViewAligned.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIImageViewAligned.m; sourceTree = ""; };
+		0B21E8051E26CCB7000C8779 /* EarlGrey.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EarlGrey.framework; path = Carthage/Build/iOS/EarlGrey.framework; sourceTree = ""; };
+		0B305E1A1E3A98A900BE0767 /* BookmarkingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkingTests.swift; sourceTree = ""; };
+		0B3D670D1E09B90B00C1EFC7 /* AuthenticationTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationTest.swift; sourceTree = ""; };
+		0B3E7D931B27A7CE00E2E84D /* AboutHomeHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutHomeHandler.swift; sourceTree = ""; };
+		0B3E7DB91B27AB4C00E2E84D /* MockLogins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MockLogins.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		0B54BD181B698B7C004C822C /* SuggestedSites.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuggestedSites.swift; sourceTree = ""; };
+		0B5A93211B1EB4C8004F47A2 /* ReadingListTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListTest.swift; sourceTree = ""; };
+		0B5A93411B1EB572004F47A2 /* readablePage.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = readablePage.html; sourceTree = ""; };
+		0B62EFD11AD63CD100ACB9CD /* Clearables.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Clearables.swift; sourceTree = ""; };
+		0B6FBAB11AC1F830007EC669 /* numberedPage.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = numberedPage.html; sourceTree = ""; };
+		0B729D361E047D6A008E6859 /* HomePageSettingsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePageSettingsTest.swift; sourceTree = ""; };
+		0B742CC61B32491400EE9264 /* sqlcipher.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = sqlcipher.xcodeproj; path = ThirdParty/sqlcipher/sqlcipher.xcodeproj; sourceTree = ""; };
+		0B7C1E941F6097AD006A8869 /* TrackingProtectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackingProtectionTests.swift; sourceTree = ""; };
+		0B8E0FF31A932BD500161DC3 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };
+		0B9D40781E8D5AC80059E664 /* XCUITests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XCUITests-Bridging-Header.h"; sourceTree = ""; };
+		0BA1E00D1B03FB0B007675AF /* NetError.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = NetError.html; sourceTree = ""; };
+		0BA1E02D1B046F1E007675AF /* ErrorPageHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorPageHelper.swift; sourceTree = ""; };
+		0BA1E02F1B051A07007675AF /* NetError.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = NetError.css; sourceTree = ""; };
+		0BA896491A250E6500C1010C /* ProfileTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileTest.swift; sourceTree = ""; };
+		0BA8964A1A250E6500C1010C /* TestBookmarks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestBookmarks.swift; sourceTree = ""; };
+		0BB5B2861AC0A2B90052877D /* SnackBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnackBar.swift; sourceTree = ""; };
+		0BB5B2871AC0A2B90052877D /* Toolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Toolbar.swift; sourceTree = ""; };
+		0BB5B30A1AC0AD1F0052877D /* LoginsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = LoginsHelper.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		0BC9C9C31F26F54D000E8AB5 /* SiteLoadTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SiteLoadTest.swift; sourceTree = ""; };
+		0BD19A661A25309B0084FBA7 /* NSUserDefaultsPrefs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSUserDefaultsPrefs.swift; sourceTree = ""; };
+		0BDA568A1B26B1BE008C9B96 /* LoginsHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = LoginsHelper.js; sourceTree = ""; };
+		0BDA56AE1B26B1D5008C9B96 /* TestLogins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestLogins.swift; sourceTree = ""; };
+		0BDA56B11B26B1E4008C9B96 /* Logins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Logins.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		0BDA56B31B26B203008C9B96 /* SQLiteLogins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteLogins.swift; sourceTree = ""; };
+		0BEF44621E31165700187C32 /* EarlGrey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EarlGrey.swift; sourceTree = ""; };
+		0BF0DB931A8545800039F300 /* URLBarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLBarView.swift; sourceTree = ""; };
+		0BF1B7E21AC60DEA00A7B407 /* InsetButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsetButton.swift; sourceTree = ""; };
+		0BF42D361A7C0B8E00889E28 /* FaviconManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconManager.swift; sourceTree = ""; };
+		0BF42D381A7C0E8900889E28 /* Favicons.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = Favicons.js; sourceTree = ""; };
+		0BF42D4E1A7CD09600889E28 /* TestFavicons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestFavicons.swift; sourceTree = ""; };
+		0BF8F8D91AEFF1C900E90BC2 /* noTitle.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = noTitle.html; sourceTree = ""; };
+		19DE1F661EC13B6400428B8C /* LeanplumIntegration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeanplumIntegration.swift; sourceTree = ""; };
+		280CB1361C20E0A3005AF147 /* BookmarksSynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BookmarksSynchronizer.swift; path = Sync/Synchronizers/Bookmarks/BookmarksSynchronizer.swift; sourceTree = SOURCE_ROOT; };
+		28126F471C2F948E006466CC /* SQLiteBookmarksHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteBookmarksHelpers.swift; sourceTree = ""; };
+		28126F6D1C2F94F9006466CC /* SQLiteBookmarksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteBookmarksModel.swift; sourceTree = ""; };
+		28126F731C2F96F1006466CC /* SQLiteBookmarksResetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteBookmarksResetting.swift; sourceTree = ""; };
+		28126F761C2F9833006466CC /* SQLiteBookmarksBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteBookmarksBase.swift; sourceTree = ""; };
+		2816EFFF1B33E05400522243 /* UIConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIConstants.swift; sourceTree = ""; };
+		281B02991C037C1F005202C3 /* TestBrowserDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestBrowserDB.swift; sourceTree = ""; };
+		281B2BE91ADF4D90002917DC /* MockProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MockProfile.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		2827315E1ABC9BE600AA1954 /* Sync.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Sync.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		282731611ABC9BE600AA1954 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		282731621ABC9BE600AA1954 /* Sync-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Sync-Bridging-Header.h"; sourceTree = ""; };
+		282731681ABC9BE700AA1954 /* SyncTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SyncTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		282731701ABC9BE700AA1954 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		282915E51AF1A7920006EEB5 /* BrowserSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrowserSchema.swift; sourceTree = ""; };
+		2829D3791C2F0A7F00DCF931 /* BookmarksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BookmarksModel.swift; path = Bookmarks/BookmarksModel.swift; sourceTree = ""; };
+		2829D39F1C2F0AD400DCF931 /* Sharing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sharing.swift; sourceTree = ""; };
+		28302E3F1AF0747800521E2E /* DatabaseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseError.swift; sourceTree = ""; };
+		283586FC1C73F18E00A55435 /* CachingItemSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CachingItemSource.swift; path = Bookmarks/CachingItemSource.swift; sourceTree = ""; };
+		2852B8431C51996B00591EAC /* Trees.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Trees.swift; path = Bookmarks/Trees.swift; sourceTree = ""; };
+		28532CE51C48098D000072D9 /* ThreeWayTreeMerger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreeWayTreeMerger.swift; sourceTree = ""; };
+		28532D311C483E3D000072D9 /* CompletionOps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompletionOps.swift; sourceTree = ""; };
+		2853C5401AD84C6800C4F31D /* TabsPayload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabsPayload.swift; sourceTree = ""; };
+		2855611E1AEFFA1C00D5ED5B /* HistorySynchronizerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = HistorySynchronizerTests.swift; path = SyncTests/HistorySynchronizerTests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		285D3B671B4380B70035FD22 /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Queue.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		285D3B8F1B4386520035FD22 /* SQLiteQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteQueue.swift; sourceTree = ""; };
+		285F2DC01AF80B4600211843 /* SQLiteBookmarksSyncing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteBookmarksSyncing.swift; sourceTree = ""; };
+		28786E541AB0F5FA009EA9EF /* DeferredTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeferredTests.swift; sourceTree = ""; };
+		288501DD1AC0F61D00E7F670 /* RequestExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestExtensions.swift; sourceTree = ""; };
+		2885023E1AC117A500E7F670 /* SyncStateMachine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncStateMachine.swift; sourceTree = ""; };
+		288A2D861AB8B3260023ABC3 /* Shared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Shared.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		288A2DA71AB8B3700023ABC3 /* Box.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Box.swift; path = ThirdParty/Box/Box.swift; sourceTree = ""; };
+		288A2DA81AB8B3700023ABC3 /* BoxType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoxType.swift; path = ThirdParty/Box/BoxType.swift; sourceTree = ""; };
+		288A2DA91AB8B3700023ABC3 /* MutableBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MutableBox.swift; path = ThirdParty/Box/MutableBox.swift; sourceTree = ""; };
+		288A2DB31AB8B38D0023ABC3 /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Error.swift; path = ThirdParty/Result/Error.swift; sourceTree = ""; };
+		288A2DB41AB8B38D0023ABC3 /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Result.swift; path = ThirdParty/Result/Result.swift; sourceTree = ""; };
+		288E67C11B9E730900AE2C6A /* BookmarksDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BookmarksDownloader.swift; path = Sync/Synchronizers/Bookmarks/BookmarksDownloader.swift; sourceTree = SOURCE_ROOT; };
+		2891F2BA1F991185001B105E /* v33.db */ = {isa = PBXFileReference; lastKnownFileType = file; path = v33.db; sourceTree = ""; };
+		28926B191AC0F074009C0B1D /* EncryptedJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EncryptedJSON.swift; sourceTree = ""; };
+		28926B361AC0F0DD009C0B1D /* EnvelopeJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvelopeJSON.swift; sourceTree = ""; };
+		28926B391AC0F128009C0B1D /* CleartextPayloadJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CleartextPayloadJSON.swift; sourceTree = ""; };
+		2894C1421AE89D8900F1F92F /* HistorySynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HistorySynchronizer.swift; path = Synchronizers/HistorySynchronizer.swift; sourceTree = ""; };
+		2894C1651AE89DD200F1F92F /* TabsSynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TabsSynchronizer.swift; path = Synchronizers/TabsSynchronizer.swift; sourceTree = ""; };
+		2894C1681AE89DDC00F1F92F /* ClientsSynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ClientsSynchronizer.swift; path = Synchronizers/ClientsSynchronizer.swift; sourceTree = ""; };
+		2894C16B1AE89FD500F1F92F /* HistoryPayload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryPayload.swift; sourceTree = ""; };
+		289A4C121C4EB90600A460E3 /* StorageTestUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageTestUtils.swift; sourceTree = ""; };
+		28A17B661BEC727500BC14ED /* Downloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Downloader.swift; path = Synchronizers/Downloader.swift; sourceTree = ""; };
+		28A6CE891AC082E200C1A2D4 /* UtilsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilsTests.swift; sourceTree = ""; };
+		28AA941C1B97DCA800703DC6 /* BookmarkPayload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkPayload.swift; sourceTree = ""; };
+		28B62ACD1BC745E7004A585A /* Syncable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Syncable.swift; sourceTree = ""; };
+		28C077971A3B064000834FE5 /* CryptoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CryptoTests.swift; path = SyncTests/CryptoTests.swift; sourceTree = ""; };
+		28C0779D1A3B066000834FE5 /* RecordTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RecordTests.swift; path = SyncTests/RecordTests.swift; sourceTree = ""; };
+		28C28BFC1C51A3B900D5460E /* Merging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Merging.swift; sourceTree = ""; };
+		28C4AB711AD42D4300D9ACE3 /* Clients.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Clients.swift; sourceTree = ""; };
+		28C8B7841C852535006D8318 /* BookmarksPanelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksPanelTests.swift; sourceTree = ""; };
+		28CE83BB1A1D1D3200576538 /* ClientPayload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClientPayload.swift; sourceTree = ""; };
+		28CE83BC1A1D1D3200576538 /* KeyBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBundle.swift; sourceTree = ""; };
+		28CE83BD1A1D1D3200576538 /* KeysPayload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeysPayload.swift; sourceTree = ""; };
+		28CE83BE1A1D1D3200576538 /* Record.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Record.swift; sourceTree = ""; };
+		28CE83BF1A1D1D3200576538 /* SyncMeta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncMeta.swift; sourceTree = ""; };
+		28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = FxA.xcodeproj; path = FxA/FxA.xcodeproj; sourceTree = ""; };
+		28CE83E81A1D206D00576538 /* Client-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Client-Bridging-Header.h"; path = "../../Client-Bridging-Header.h"; sourceTree = ""; };
+		28D158AC1AFD90E500F9C065 /* TestSQLiteBookmarks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSQLiteBookmarks.swift; sourceTree = ""; };
+		28D52E081BCDF44100187A1D /* ResetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResetTests.swift; sourceTree = ""; };
+		28D980221C47149000277055 /* TestBookmarkTreeMerging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestBookmarkTreeMerging.swift; path = SyncTests/TestBookmarkTreeMerging.swift; sourceTree = ""; };
+		28E23C111AC5A5EE00F5AC85 /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; };
+		28E91E741B443AD5009DF274 /* SyncConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncConstants.swift; sourceTree = ""; };
+		28EADE381AFC3898007FB2FB /* UIImageViewExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIImageViewExtensions.swift; path = Extensions/UIImageViewExtensions.swift; sourceTree = ""; };
+		28ECD9791BA1EA2200D829DA /* MockSyncServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MockSyncServer.swift; path = SyncTests/MockSyncServer.swift; sourceTree = ""; };
+		28ECD9A21BA1EBA800D829DA /* SyncTests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SyncTests-Bridging-Header.h"; sourceTree = ""; };
+		28ECD9F31BA1F59800D829DA /* DownloadTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DownloadTests.swift; path = SyncTests/DownloadTests.swift; sourceTree = ""; };
+		28ED02011B26123E003948B2 /* LoginPayload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginPayload.swift; sourceTree = ""; };
+		28ED02251B262B5E003948B2 /* LoginsSynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LoginsSynchronizer.swift; path = Synchronizers/LoginsSynchronizer.swift; sourceTree = ""; };
+		28ED02281B262E0A003948B2 /* IndependentRecordSynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = IndependentRecordSynchronizer.swift; path = Synchronizers/IndependentRecordSynchronizer.swift; sourceTree = ""; };
+		28F596A01ACA13CA0071DDCC /* InfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InfoTests.swift; path = SyncTests/InfoTests.swift; sourceTree = ""; };
+		28FDFF0B1C1F725800840F86 /* SeparatorTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeparatorTableCell.swift; sourceTree = ""; };
+		2C2A5EF31E68469500F02659 /* PrivateBrowsingTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateBrowsingTest.swift; sourceTree = ""; };
+		2C2A91281FA2410D002E36BD /* HistoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryTests.swift; sourceTree = ""; };
+		2C31A7A81E8BFB2200DAC646 /* ReaderViewUITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderViewUITest.swift; sourceTree = ""; };
+		2C31A8461E8D447F00DAC646 /* HomePageSettingsUITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePageSettingsUITest.swift; sourceTree = ""; };
+		2C3406C71E719F00000FD889 /* SettingsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTest.swift; sourceTree = ""; };
+		2C8C07761E7800EA00DC1237 /* FindInPageTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindInPageTest.swift; sourceTree = ""; };
+		2C97EC701E72C80E0092EC18 /* TopTabsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopTabsTest.swift; sourceTree = ""; };
+		2CA16FDD1E5F089100332277 /* SearchTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchTest.swift; sourceTree = ""; };
+		2CB56E3E1E926BFB00AF7586 /* ToolbarTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarTest.swift; sourceTree = ""; };
+		2CC1B3EF1E9B861400814EEC /* DomainAutocompleteTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainAutocompleteTest.swift; sourceTree = ""; };
+		2CEA6F781E93E3A600D4100E /* SearchSettingsUITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchSettingsUITest.swift; sourceTree = ""; };
+		2CF449A41E7BFE2C00FD7595 /* NavigationTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationTest.swift; sourceTree = ""; };
+		2F13E79A1AC0C02700D75081 /* StringExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionsTests.swift; sourceTree = ""; };
+		2F14E1391ABB890800FF98DB /* Account-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Account-Bridging-Header.h"; sourceTree = ""; };
+		2F1A3DE01ABE3C90002F1E15 /* FxALoginStateMachine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = FxALoginStateMachine.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		2F1A3DFD1ABE3C9C002F1E15 /* FxALoginStateMachineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = FxALoginStateMachineTests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		2F3724C41ABF3C01007607FA /* LiveStorageClientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = LiveStorageClientTests.swift; path = SyncTests/LiveStorageClientTests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		2F3724C51ABF3C01007607FA /* StorageClientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StorageClientTests.swift; path = SyncTests/StorageClientTests.swift; sourceTree = ""; };
+		2F3724E21ABF3C19007607FA /* Info.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Info.swift; sourceTree = ""; };
+		2F3724E31ABF3C19007607FA /* StorageClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageClient.swift; sourceTree = ""; };
+		2F3724E41ABF3C19007607FA /* Synchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Synchronizer.swift; path = Synchronizers/Synchronizer.swift; sourceTree = ""; };
+		2F44FA1A1A9D426A00FD20CC /* TestHashExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHashExtensions.swift; sourceTree = ""; };
+		2F44FC711A9E840300FD20CC /* SettingsNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsNavigationController.swift; sourceTree = ""; };
+		2F44FCC41A9E85E900FD20CC /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = ""; };
+		2F44FCC61A9E8CF500FD20CC /* SearchSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchSettingsTableViewController.swift; sourceTree = ""; };
+		2F44FCCA1A9E972E00FD20CC /* SearchEnginePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchEnginePicker.swift; sourceTree = ""; };
+		2F67C5251BB0CB4E00E7B73A /* MetaGlobalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MetaGlobalTests.swift; path = SyncTests/MetaGlobalTests.swift; sourceTree = ""; };
+		2F697F7D1A9FD22D009E03AE /* SearchEnginesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchEnginesTests.swift; sourceTree = ""; };
+		2F8C76561BC32F3C00D5E4E0 /* MockSyncServerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MockSyncServerTests.swift; path = SyncTests/MockSyncServerTests.swift; sourceTree = ""; };
+		2FA435FB1ABB83B4008031D1 /* Account.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Account.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		2FA435FE1ABB83B4008031D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		2FA436051ABB83B4008031D1 /* AccountTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AccountTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		2FA4360D1ABB83B4008031D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		2FA436221ABB8436008031D1 /* FirefoxAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirefoxAccount.swift; sourceTree = ""; };
+		2FA436231ABB8436008031D1 /* FirefoxAccountConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirefoxAccountConfiguration.swift; sourceTree = ""; };
+		2FA436251ABB8436008031D1 /* FxAClient10.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxAClient10.swift; sourceTree = ""; };
+		2FA436271ABB8436008031D1 /* HawkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HawkHelper.swift; sourceTree = ""; };
+		2FA436281ABB8436008031D1 /* TokenServerClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenServerClient.swift; sourceTree = ""; };
+		2FA436371ABB8448008031D1 /* FirefoxAccountTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirefoxAccountTests.swift; sourceTree = ""; };
+		2FA436381ABB8448008031D1 /* FxAClient10Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxAClient10Tests.swift; sourceTree = ""; };
+		2FA4363A1ABB8448008031D1 /* HawkHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HawkHelperTests.swift; sourceTree = ""; };
+		2FA4363B1ABB8448008031D1 /* LiveAccountTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = LiveAccountTest.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		2FA4363C1ABB8448008031D1 /* TokenServerClientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenServerClientTests.swift; sourceTree = ""; };
+		2FCAE21A1ABB51F800877008 /* Storage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Storage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		2FCAE2241ABB51F800877008 /* StorageTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StorageTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		2FCAE22C1ABB51F800877008 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		2FCAE23F1ABB531100877008 /* Bookmarks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bookmarks.swift; path = Bookmarks/Bookmarks.swift; sourceTree = ""; };
+		2FCAE2411ABB531100877008 /* Cursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cursor.swift; sourceTree = ""; };
+		2FCAE2421ABB531100877008 /* Favicons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Favicons.swift; sourceTree = ""; };
+		2FCAE2431ABB531100877008 /* FileAccessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileAccessor.swift; sourceTree = ""; };
+		2FCAE2441ABB531100877008 /* History.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = History.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		2FCAE2471ABB531100877008 /* RemoteTabs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteTabs.swift; sourceTree = ""; };
+		2FCAE2481ABB531100877008 /* Site.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Site.swift; sourceTree = ""; };
+		2FCAE24B1ABB531100877008 /* BrowserDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrowserDB.swift; sourceTree = ""; };
+		2FCAE2551ABB531100877008 /* SQLiteHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteHistory.swift; sourceTree = ""; };
+		2FCAE2581ABB531100877008 /* SQLiteRemoteClientsAndTabs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteRemoteClientsAndTabs.swift; sourceTree = ""; };
+		2FCAE25B1ABB531100877008 /* SwiftData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftData.swift; sourceTree = ""; };
+		2FCAE25C1ABB531100877008 /* Visit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Visit.swift; sourceTree = ""; };
+		2FCAE2791ABB533A00877008 /* MockFiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockFiles.swift; sourceTree = ""; };
+		2FCAE27A1ABB533A00877008 /* TestSQLiteRemoteClientsAndTabs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSQLiteRemoteClientsAndTabs.swift; sourceTree = ""; };
+		2FCAE27D1ABB533A00877008 /* TestSQLiteHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSQLiteHistory.swift; sourceTree = ""; };
+		2FCAE33D1ABB5F1800877008 /* Storage-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Storage-Bridging-Header.h"; sourceTree = ""; };
+		2FDB10921A9FBEC5006CF312 /* PrefsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefsTests.swift; sourceTree = ""; };
+		2FDBCF601ABFC9DE00AFF7F0 /* SyncAuthState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncAuthState.swift; sourceTree = ""; };
+		2FDBCF9A1AC0ADB500AFF7F0 /* SyncAuthStateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncAuthStateTests.swift; sourceTree = ""; };
+		2FDE87FD1ABB3817005317B1 /* RemoteTabsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteTabsPanel.swift; sourceTree = ""; };
+		2FEBABAE1AB3659000DB5728 /* ResultTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultTests.swift; sourceTree = ""; };
+		2FFC4D1A1ABE3C360081D675 /* FxAState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxAState.swift; sourceTree = ""; };
+		2FFC4D371ABE3C420081D675 /* FxAStateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxAStateTests.swift; sourceTree = ""; };
+		318FB6EA1DB5600D0004E40F /* SQLiteHistoryFactories.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteHistoryFactories.swift; sourceTree = ""; };
+		31ADB5D91E58CEC300E87909 /* ClipboardBarDisplayHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClipboardBarDisplayHandler.swift; sourceTree = ""; };
+		3905274A1C874D35007E0BB7 /* Today.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Today.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+		3905274B1C874D35007E0BB7 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; };
+		3905274E1C874D35007E0BB7 /* TodayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewController.swift; sourceTree = ""; };
+		390527531C874D35007E0BB7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		3905B4D41E8E7A6B0027D953 /* FxAPushMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxAPushMessageHandler.swift; sourceTree = ""; };
+		391AEFD11C8F11ED00691F84 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+		39236E711FCC600200A38F1B /* TabEventHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabEventHandlerTests.swift; sourceTree = ""; };
+		392ED6B61D06E85E009D9B62 /* NewTabChoiceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewTabChoiceViewController.swift; sourceTree = ""; };
+		392ED7E31D0AEF56009D9B62 /* NewTabAccessors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NewTabAccessors.swift; path = Accessors/NewTabAccessors.swift; sourceTree = ""; };
+		392ED7E51D0AEFEF009D9B62 /* HomePageAccessors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HomePageAccessors.swift; path = Accessors/HomePageAccessors.swift; sourceTree = ""; };
+		3943A81C1E9807C700D4F6DC /* FxAPushMessageTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxAPushMessageTest.swift; sourceTree = ""; };
+		39455F761FC83F430088A22C /* TabEventHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TabEventHandler.swift; path = Helpers/TabEventHandler.swift; sourceTree = ""; };
+		394CF6CE1BAA493C00906917 /* DefaultSuggestedSites.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultSuggestedSites.swift; sourceTree = ""; };
+		395C8F201E796AD600A68E8C /* PushCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushCrypto.swift; sourceTree = ""; };
+		3964B0991EA8F06F00F2EEF4 /* FeatureSwitch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureSwitch.swift; sourceTree = ""; };
+		3964B09B1EA8F32C00F2EEF4 /* FeatureSwitchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureSwitchTests.swift; sourceTree = ""; };
+		396E38DB1EE0818800CC180F /* ExtensionProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionProfile.swift; sourceTree = ""; };
+		397848DB1ED86605004C0C0B /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+		397848DD1ED86605004C0C0B /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; };
+		397848DF1ED86605004C0C0B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		39A359E31BFCCE94006B9E87 /* UserActivityHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UserActivityHandler.swift; path = Helpers/UserActivityHandler.swift; sourceTree = ""; };
+		39A35AEC1C0662A3006B9E87 /* SpotlightHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = SpotlightHelper.js; sourceTree = ""; };
+		39AC59191CC574AA0042C2F5 /* HomePageSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePageSettingsViewController.swift; sourceTree = ""; };
+		39B0647C1E7ADAC2000BE173 /* PushCryptoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PushCryptoTests.swift; path = PushTests/PushCryptoTests.swift; sourceTree = ""; };
+		39C22C2C1E897B9A000C0E56 /* LivePushClientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LivePushClientTests.swift; path = PushTests/LivePushClientTests.swift; sourceTree = ""; };
+		39DD030C1CD53E1900BC09B3 /* HomePageHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePageHelper.swift; sourceTree = ""; };
+		39E65D261CA5B92000C63CE3 /* AsyncReducerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncReducerTests.swift; sourceTree = ""; };
+		39EB46971E26DDB4006346E8 /* ScreenGraph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenGraph.swift; sourceTree = ""; };
+		39EB46981E26DDB4006346E8 /* FxScreenGraph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxScreenGraph.swift; sourceTree = ""; };
+		39F819C51FD70F5D009E31E4 /* TabEventHandlers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabEventHandlers.swift; sourceTree = ""; };
+		39F99FD91E3A6DE300F353B4 /* PushClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushClient.swift; sourceTree = ""; };
+		39F99FDA1E3A6DE300F353B4 /* PushConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushConfiguration.swift; sourceTree = ""; };
+		39F99FDB1E3A6DE300F353B4 /* PushRegistration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushRegistration.swift; sourceTree = ""; };
+		39F99FED1E3A71F800F353B4 /* FxALoginHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FxALoginHelper.swift; path = Helpers/FxALoginHelper.swift; sourceTree = ""; };
+		3B0943801D6CC4FC004F24E1 /* FilledPageControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FilledPageControl.swift; path = ThirdParty/FilledPageControl.swift; sourceTree = ""; };
+		3B39EDB91E16E18900EF029F /* CustomSearchEnginesTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomSearchEnginesTest.swift; sourceTree = ""; };
+		3B39EDCA1E16E1AA00EF029F /* CustomSearchViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomSearchViewController.swift; sourceTree = ""; };
+		3B4262E21E538EC400CA681C /* MetadataHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = MetadataHelper.js; path = "Metadata Parsing/MetadataHelper.js"; sourceTree = ""; };
+		3B4262E31E538EC400CA681C /* MetadataParserHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MetadataParserHelper.swift; path = "Metadata Parsing/MetadataParserHelper.swift"; sourceTree = ""; };
+		3B4262E41E538EC400CA681C /* page-metadata-parser.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "page-metadata-parser.js"; path = "Metadata Parsing/page-metadata-parser.js"; sourceTree = ""; };
+		3B43E3D01D95C48D00BBA9DB /* StoragePerfTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StoragePerfTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		3B43E3D21D95C48D00BBA9DB /* StoragePerfTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoragePerfTests.swift; sourceTree = ""; };
+		3B43E3D41D95C48D00BBA9DB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		3B4988CD1E42B01800A12FDA /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/iOS/SwiftyJSON.framework; sourceTree = ""; };
+		3B4AA24A1D8B8C4C00A2E008 /* ArrayExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtensionTests.swift; sourceTree = ""; };
+		3B546EBF1D95ECAE00BDBE36 /* ActivityStreamTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityStreamTest.swift; sourceTree = ""; };
+		3B61CD481F2A74EF00D38DE1 /* PocketFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PocketFeed.swift; sourceTree = ""; };
+		3B61CD581F2A750800D38DE1 /* PocketFeedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PocketFeedTests.swift; sourceTree = ""; };
+		3B61CD621F2A769D00D38DE1 /* pocketglobalfeed.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = pocketglobalfeed.json; sourceTree = ""; };
+		3B6889C41D66950E002AC85E /* UIImageColors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIImageColors.swift; path = ThirdParty/UIImageColors.swift; sourceTree = ""; };
+		3B6F40171DC7849C00656CC6 /* ActivityStreamTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityStreamTests.swift; sourceTree = ""; };
+		3BA9A0221D2C208C00BD418C /* Fuzi.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Fuzi.framework; path = Carthage/Build/iOS/Fuzi.framework; sourceTree = ""; };
+		3BB50E101D6274CD004B33DF /* ActivityStreamTopSitesCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityStreamTopSitesCell.swift; sourceTree = ""; };
+		3BB50E1F1D627539004B33DF /* ActivityStreamPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityStreamPanel.swift; sourceTree = ""; };
+		3BB54B301E68EB2B0021DAC4 /* AuthenticationKeychainInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationKeychainInfoTests.swift; sourceTree = ""; };
+		3BC659481E5BA4AE006D560F /* TopSites */ = {isa = PBXFileReference; lastKnownFileType = folder; path = TopSites; sourceTree = ""; };
+		3BC659581E5BA505006D560F /* top_sites.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = top_sites.json; sourceTree = ""; };
+		3BCE6D3B1CEB9E4D0080928C /* ThirdPartySearchAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThirdPartySearchAlerts.swift; sourceTree = ""; };
+		3BE7274D1CCFE8A30099189F /* CustomSearchHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = CustomSearchHelper.js; sourceTree = ""; };
+		3BE7275C1CCFE8B60099189F /* CustomSearchHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomSearchHandler.swift; sourceTree = ""; };
+		3BF4B8E81D38497A00493393 /* BaseTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestCase.swift; sourceTree = ""; };
+		3BF56D261CDBBE1F00AC4D75 /* SimpleToast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleToast.swift; sourceTree = ""; };
+		3BFCBF1F1E04B1C50070C042 /* UIImageViewExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageViewExtensionsTests.swift; sourceTree = ""; };
+		3BFE4B071D342FB800DDF53F /* XCUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XCUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		3BFE4B0B1D342FB900DDF53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		3BFE4B4F1D34673D00DDF53F /* ThirdPartySearchTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThirdPartySearchTest.swift; sourceTree = ""; };
+		3D71C89D1F5703A1008D8646 /* CopiedLinksTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopiedLinksTests.swift; sourceTree = ""; };
+		3D9CA9831EF456A8002434DD /* NightModeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightModeTests.swift; sourceTree = ""; };
+		3D9CA9A71EF84D04002434DD /* NoImageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoImageTests.swift; sourceTree = ""; };
+		3D9CAA1B1EFCD655002434DD /* ClipBoardTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClipBoardTests.swift; sourceTree = ""; };
+		3DEFED071F55EBE300F8620C /* TrackingProtectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackingProtectionTests.swift; sourceTree = ""; };
+		4A59BF410BBD9B3BE71F4C7C /* TestHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHistory.swift; sourceTree = ""; };
+		4F514FD31ACD8F2C0022D7EA /* HistoryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryTests.swift; sourceTree = ""; };
+		4F9757391AFA6F37006ECC24 /* readerContent.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = readerContent.html; sourceTree = ""; };
+		50027345B49B967409DDA348 /* StateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StateTests.swift; path = SyncTests/StateTests.swift; sourceTree = ""; };
+		554867221DC3935A00183DAA /* HomePageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePageTests.swift; sourceTree = ""; };
+		55A747161DC46FC400CE1B57 /* HomePageUITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePageUITest.swift; sourceTree = ""; };
+		59A6825233896FC846499289 /* HistoryPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = HistoryPanel.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		59A6839879D615FC1C0D71CE /* BookmarksPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksPanel.swift; sourceTree = ""; };
+		59A685F4EAD19EDEC854BCA4 /* ReaderPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderPanel.swift; sourceTree = ""; };
+		59A68B1F857A8638598A63A0 /* TwoLineCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwoLineCell.swift; sourceTree = ""; };
+		59A68CCB63E2A565CB03F832 /* SearchViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = ""; };
+		742A56381D80B54A00BDB803 /* PhotonActionSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotonActionSheet.swift; sourceTree = ""; };
+		744B0FFD1B4F172E00100422 /* ToolbarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarTests.swift; sourceTree = ""; };
+		744ED5601DBFEB8D00A2B5BE /* MailtoLinkHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MailtoLinkHandler.swift; sourceTree = ""; };
+		745DAB2F1CDAAFAA00D44181 /* RecentlyClosedTabsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentlyClosedTabsPanel.swift; sourceTree = ""; };
+		745DAB3E1CDAB09E00D44181 /* HistoryBackButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryBackButton.swift; sourceTree = ""; };
+		7479B4ED1C5306A200DF000B /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Reachability.swift; path = ThirdParty/Reachability.swift; sourceTree = ""; };
+		74821F8D1DAD8F1300EEEA72 /* ActivityStreamHighlightCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ActivityStreamHighlightCell.swift; path = ../Widgets/ActivityStreamHighlightCell.swift; sourceTree = ""; };
+		74821FC41DB56A2500EEEA72 /* OpenWithSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenWithSettingsViewController.swift; sourceTree = ""; };
+		74821FFD1DB6D3AC00EEEA72 /* MailSchemes.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = MailSchemes.plist; sourceTree = ""; };
+		7482205B1DBAB56300EEEA72 /* MailProviders.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MailProviders.swift; sourceTree = ""; };
+		74B195431CF503FC007F36EF /* RecentlyClosedTabs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentlyClosedTabs.swift; sourceTree = ""; };
+		74C027441B2A348C001B1E88 /* SessionData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionData.swift; sourceTree = ""; };
+		74E36D771B71323500D69DA1 /* SettingsContentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsContentViewController.swift; sourceTree = ""; };
+		7B10AA9E1E3A15020002DD08 /* DataExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataExtensions.swift; sourceTree = ""; };
+		7B10AABA1E3A1F650002DD08 /* URLRequestExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLRequestExtensions.swift; sourceTree = ""; };
+		7B2142F41E5E03F800CDD3FC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
+		7B2142F71E5E040200CDD3FC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
+		7B2142FD1E5E055000CDD3FC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
+		7B2143021E5F224A00CDD3FC /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = ""; };
+		7B2143031E5F225200CDD3FC /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = ""; };
+		7B24DC9B1B67B3590005766B /* ClearPrivateDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClearPrivateDataTests.swift; sourceTree = ""; };
+		7B3631E91C244FEE00D12AF9 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; };
+		7B3632D31C2983F000D12AF9 /* L10nSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = L10nSnapshotTests.swift; sourceTree = ""; };
+		7B3D9E641E4CBFDB007A50DA /* NSCoderExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSCoderExtensions.swift; sourceTree = ""; };
+		7B42406D1CA04CAC009B5C28 /* Menu.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Menu.xcassets; sourceTree = ""; };
+		7B4980A71CE363ED0017547C /* Settings.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Settings.xcassets; sourceTree = ""; };
+		7B604F851C494983006EEEC3 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = ""; };
+		7B604F981C494F74006EEEC3 /* KIF.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = KIF.framework; path = Carthage/Build/iOS/KIF.framework; sourceTree = ""; };
+		7B604F9A1C4950F2006EEEC3 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/iOS/SDWebImage.framework; sourceTree = ""; };
+		7B604FA11C495268006EEEC3 /* SnapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SnapKit.framework; path = Carthage/Build/iOS/SnapKit.framework; sourceTree = ""; };
+		7B604FBA1C495D8A006EEEC3 /* XCGLogger.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCGLogger.framework; path = Carthage/Build/iOS/XCGLogger.framework; sourceTree = ""; };
+		7B6050001C49653B006EEEC3 /* AdjustSdk.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdjustSdk.framework; path = Carthage/Build/iOS/AdjustSdk.framework; sourceTree = ""; };
+		7B60B0071BDE3AE10090C984 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotHelper.swift; path = fastlane/SnapshotHelper.swift; sourceTree = SOURCE_ROOT; };
+		7B844E3C1BBDDB9D00E733A2 /* ChevronView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChevronView.swift; sourceTree = ""; };
+		7B8A47F51D01D3B400C07734 /* PassKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PassKit.framework; path = System/Library/Frameworks/PassKit.framework; sourceTree = SDKROOT; };
+		7B95CD191C3AB2EE00638E31 /* MarketingUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketingUITests.swift; sourceTree = ""; };
+		7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SQLite.xcodeproj; path = ThirdParty/SQLite.swift/SQLite.xcodeproj; sourceTree = ""; };
+		7B9BF91B1E43472E00CB24F4 /* JSONExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONExtensions.swift; sourceTree = ""; };
+		7BA0601A1C0F4DE200DFADB6 /* TabPeekViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabPeekViewController.swift; sourceTree = ""; };
+		7BA4A9451C4CED780091D032 /* GCDWebServers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GCDWebServers.framework; path = Carthage/Build/iOS/GCDWebServers.framework; sourceTree = ""; };
+		7BA4A9491C4CEFC70091D032 /* OnePasswordExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OnePasswordExtension.framework; path = Carthage/Build/iOS/OnePasswordExtension.framework; sourceTree = ""; };
+		7BA4A94B1C4CF03B0091D032 /* SwiftKeychainWrapper.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftKeychainWrapper.framework; path = Carthage/Build/iOS/SwiftKeychainWrapper.framework; sourceTree = ""; };
+		7BA4A9631C4CFE840091D032 /* Deferred.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Deferred.framework; path = Carthage/Build/iOS/Deferred.framework; sourceTree = ""; };
+		7BA8D1C61BA037F500C8AE9E /* OpenInHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenInHelper.swift; sourceTree = ""; };
+		7BBFEE731BB405D900A305AA /* TabManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabManagerTests.swift; sourceTree = ""; };
+		7BC68D081CC153020043562A /* RoundedToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoundedToolbar.swift; sourceTree = ""; };
+		7BEB644D1C7345600092C02E /* L10nSnapshotTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = L10nSnapshotTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		7BEB644E1C7345600092C02E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = L10nSnapshotTests/Info.plist; sourceTree = SOURCE_ROOT; };
+		7BEB645A1C7345990092C02E /* MarketingUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MarketingUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		7BEB645B1C7345990092C02E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = MarketingUITests/Info.plist; sourceTree = SOURCE_ROOT; };
+		7BEDD29A1CB7CB24004B51F3 /* JumpAndSpinAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JumpAndSpinAnimator.swift; sourceTree = ""; };
+		7BEDD2B11CB7CC0B004B51F3 /* Animatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animatable.swift; sourceTree = ""; };
+		7BEFC67F1BFF68C30059C952 /* QuickActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickActions.swift; sourceTree = ""; };
+		7BF5A1E91B41640500EA9DD8 /* SyncQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncQueue.swift; sourceTree = ""; };
+		7BF5A1ED1B429B3100EA9DD8 /* SyncCommandsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncCommandsTests.swift; sourceTree = ""; };
+		8D8251721F4DE67E00780643 /* AdvanceAccountSettingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvanceAccountSettingViewController.swift; sourceTree = ""; };
+		8DCD3BCC1ED5B7FA00446D38 /* FxADeepLinkingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxADeepLinkingTests.swift; sourceTree = ""; };
+		A83E5AB61C1D993D0026D912 /* UIPasteboardExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIPasteboardExtensions.swift; path = Extensions/UIPasteboardExtensions.swift; sourceTree = ""; };
+		A83E5B181C1DA8BF0026D912 /* image.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = image.gif; sourceTree = ""; };
+		A83E5B191C1DA8BF0026D912 /* image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = image.png; sourceTree = ""; };
+		A83E5B1C1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIPasteboardExtensionsTests.swift; sourceTree = ""; };
+		A9072B7F1D07B34100459960 /* NoImageModeHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoImageModeHelper.swift; sourceTree = ""; };
+		A91528D11D0E637600CD0425 /* NoImageModeHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = NoImageModeHelper.js; sourceTree = ""; };
+		A93067D81D0FE15E00C49C6E /* NightModeHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = NightModeHelper.js; sourceTree = ""; };
+		A93067E71D0FE18E00C49C6E /* NightModeHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightModeHelper.swift; sourceTree = ""; };
+		C400467B1CF4E43E00B08303 /* BackForwardListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackForwardListViewController.swift; sourceTree = ""; };
+		C40046F91CF8E0B200B08303 /* BackForwardListAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackForwardListAnimator.swift; sourceTree = ""; };
+		C45F44681D087DB600CB7EF0 /* TopTabsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopTabsViewController.swift; sourceTree = ""; };
+		C4E3983C1D21F1E7004E89BA /* TopTabsViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopTabsViews.swift; sourceTree = ""; };
+		C4E3984B1D21F2FD004E89BA /* TabTrayButtonExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TabTrayButtonExtensions.swift; path = ../Browser/TabTrayButtonExtensions.swift; sourceTree = ""; };
+		C4E3985F1D22C409004E89BA /* TopTabsLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopTabsLayout.swift; sourceTree = ""; };
+		C4EFEECE1CEBB6F2009762A4 /* BackForwardTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackForwardTableViewCell.swift; sourceTree = ""; };
+		C4F3B2991CFCF93A00966259 /* ButtonToast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonToast.swift; sourceTree = ""; };
+		C817B34C1FC609500086018E /* UIScrollViewSwizzled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollViewSwizzled.swift; sourceTree = ""; };
+		C8611CA11F71AEB900C3DE7D /* NoImageModeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoImageModeTests.swift; sourceTree = ""; };
+		C88601B71F4228AD00BBDE4F /* ContentBlockerSettingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBlockerSettingViewController.swift; sourceTree = ""; };
+		C8EB60C31F1FB12500F9B5B3 /* navigationDelegate.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = navigationDelegate.html; sourceTree = ""; };
+		C8EB60DB1F1FB9AD00F9B5B3 /* NavigationDelegateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationDelegateTests.swift; sourceTree = ""; };
+		C8F457A71F1FD75A000CB895 /* BrowserViewController+WKNavigationDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+WKNavigationDelegate.swift"; sourceTree = ""; };
+		C8F457A91F1FDD9B000CB895 /* BrowserViewController+KeyCommands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+KeyCommands.swift"; sourceTree = ""; };
+		CE339ED61F2507A1009BE0E6 /* TestBookmarksSynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestBookmarksSynchronizer.swift; path = SyncTests/TestBookmarksSynchronizer.swift; sourceTree = ""; };
+		CE564D8D1EB7BD7700BEDDDC /* BookmarksRepairRequestor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksRepairRequestor.swift; sourceTree = ""; };
+		CE7F115E1F3CCEF900ABFC0B /* RemoteDevices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteDevices.swift; sourceTree = ""; };
+		CEFC983B1EC0DC60008A3E48 /* TestBookmarksRepairRequestor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestBookmarksRepairRequestor.swift; path = SyncTests/TestBookmarksRepairRequestor.swift; sourceTree = ""; };
+		D0131B4C1F3CF7D8000CDE86 /* SQLiteFavicons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteFavicons.swift; sourceTree = ""; };
+		D018F93D1F44A7190098F8CA /* Schema.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Schema.swift; sourceTree = ""; };
+		D02816C11ECA5E2A00240CAA /* HistoryStateHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryStateHelper.swift; sourceTree = ""; };
+		D02816D11ECA60DF00240CAA /* HistoryStateHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = HistoryStateHelper.js; sourceTree = ""; };
+		D02818601EF056C800240CAA /* SentryIntegration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SentryIntegration.swift; sourceTree = ""; };
+		D0B29EDF1F460BDF00C7CEFC /* LoginsSchema.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginsSchema.swift; sourceTree = ""; };
+		D301AAED1A3A55B70078DD1D /* TabTrayController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabTrayController.swift; sourceTree = ""; };
+		D30684F01C84F12A002D8D82 /* SearchPlugins */ = {isa = PBXFileReference; lastKnownFileType = folder; name = SearchPlugins; path = Search/SearchPlugins; sourceTree = ""; };
+		D308E4E31A5306F500842685 /* SearchEngines.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchEngines.swift; sourceTree = ""; };
+		D308EE551CBF0BF5006843F2 /* CertError.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = CertError.css; sourceTree = ""; };
+		D30B101D1AA7F9C600C01CA3 /* HomePanels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePanels.swift; sourceTree = ""; };
+		D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KIF.xcodeproj; path = Carthage/Checkouts/KIF/KIF.xcodeproj; sourceTree = ""; };
+		D313BE971B2F5096009EF241 /* DomainAutocompleteTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainAutocompleteTests.swift; sourceTree = ""; };
+		D314E7F51A37B98700426A76 /* TabToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabToolbar.swift; sourceTree = ""; };
+		D31A0FC61A65D6D000DC8C7E /* SearchSuggestClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchSuggestClient.swift; sourceTree = ""; };
+		D31CF65B1CC1959A001D0BD0 /* PrivilegedRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivilegedRequest.swift; sourceTree = ""; };
+		D31EC05E1CC57ED80096F4AB /* localhostLoad.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = localhostLoad.html; sourceTree = ""; };
+		D31F95E81AC226CB005C9F3B /* ScreenshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenshotHelper.swift; sourceTree = ""; };
+		D32A350D1D6530D80066DAE9 /* FxADevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxADevice.swift; sourceTree = ""; };
+		D32CACEC1AE04DA1000658EB /* TestSwiftData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSwiftData.swift; sourceTree = ""; };
+		D331DFC91CB6E9EE009B5DA2 /* OldStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OldStrings.swift; sourceTree = ""; };
+		D343DCFD1C446BDB00D7EEE8 /* findPage.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = findPage.html; sourceTree = ""; };
+		D34510871ACF415700EC27F0 /* SearchLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchLoader.swift; sourceTree = ""; };
+		D34DC84D1A16C40C00D49B7B /* Profile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Profile.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		D34E33021BA793C2006135F0 /* loginForm.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = loginForm.html; sourceTree = ""; };
+		D35210E01CB2F16600FC5DCB /* Strings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Strings.swift; path = ../Client/Frontend/Strings.swift; sourceTree = ""; };
+		D36998881AD70A0A00650C6C /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
+		D37524861C6E8B5A00A5F6C2 /* topdomains.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = topdomains.txt; sourceTree = ""; };
+		D375A91F1AE71675001B30D5 /* ViewMemoryLeakTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewMemoryLeakTests.swift; sourceTree = ""; };
+		D37DE2821CA2047500A5EC69 /* CertStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertStore.swift; sourceTree = ""; };
+		D37DE2C61CA356D800A5EC69 /* CertTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertTests.swift; sourceTree = ""; };
+		D37DE2C81CA356F900A5EC69 /* testcert1.pem */ = {isa = PBXFileReference; lastKnownFileType = file; path = testcert1.pem; sourceTree = ""; };
+		D37DE2C91CA356F900A5EC69 /* testcert2.pem */ = {isa = PBXFileReference; lastKnownFileType = file; path = testcert2.pem; sourceTree = ""; };
+		D38A1BEC1A9FA2CA00F6A386 /* SiteTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SiteTableViewController.swift; sourceTree = ""; };
+		D38A1EDF1CB458EC0080C842 /* CertError.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = CertError.html; sourceTree = ""; };
+		D38F02D01C05127100175932 /* Authenticator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Authenticator.swift; sourceTree = ""; };
+		D38F036F1C06387900175932 /* AuthenticationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationTests.swift; sourceTree = ""; };
+		D3968F241A38FE8500CEFD3B /* TabManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabManager.swift; sourceTree = ""; };
+		D3972BF11C22412B00035B87 /* ShareExtensionHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareExtensionHelper.swift; sourceTree = ""; };
+		D3972BF21C22412B00035B87 /* TitleActivityItemProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleActivityItemProvider.swift; sourceTree = ""; };
+		D39FA15F1A83E0EC00EE869C /* UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		D39FA1621A83E0EC00EE869C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		D39FA16B1A83E17800EE869C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+		D39FA16F1A83E62600EE869C /* UITests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UITests-Bridging-Header.h"; sourceTree = ""; };
+		D39FA1801A83E84900EE869C /* Global.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Global.swift; sourceTree = ""; };
+		D3A994951A3686BD008AD1AC /* BrowserViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrowserViewController.swift; sourceTree = ""; };
+		D3A994961A3686BD008AD1AC /* Tab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tab.swift; sourceTree = ""; };
+		D3B6923C1B9F9444004B87A4 /* FindInPageBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindInPageBar.swift; sourceTree = ""; };
+		D3B6923E1B9F9A58004B87A4 /* FindInPageHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindInPageHelper.swift; sourceTree = ""; };
+		D3B692401B9F9CC8004B87A4 /* FindInPage.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = FindInPage.js; sourceTree = ""; };
+		D3BA41671BD82F2200DA5457 /* XCTestCaseExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTestCaseExtensions.swift; sourceTree = ""; };
+		D3BA7E0B1B0E902A00153782 /* ContextMenu.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ContextMenu.js; sourceTree = ""; };
+		D3BA7E0D1B0E934F00153782 /* ContextMenuHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContextMenuHelper.swift; sourceTree = ""; };
+		D3BE7B251B054D4400641031 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
+		D3BE7B451B054F8600641031 /* TestAppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestAppDelegate.swift; sourceTree = ""; };
+		D3BF8CBA1B7425570007AFE6 /* DiskImageStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiskImageStore.swift; sourceTree = ""; };
+		D3BF8CBC1B7472FA0007AFE6 /* DiskImageStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiskImageStoreTests.swift; sourceTree = ""; };
+		D3C3696D1CC6B78800348A61 /* LocalRequestHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalRequestHelper.swift; sourceTree = ""; };
+		D3C3EB641B6FF44000388E9A /* SessionRestoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionRestoreTests.swift; sourceTree = ""; };
+		D3C744CC1A687D6C004CE85D /* URIFixup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIFixup.swift; sourceTree = ""; };
+		D3CFD3631CC5605B0064AB4A /* SecurityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecurityTests.swift; sourceTree = ""; };
+		D3D488581ABB54CD00A93597 /* FileAccessorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileAccessorTests.swift; sourceTree = ""; };
+		D3DBE6E41D6516FE00033FFF /* FxADeviceRegistration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxADeviceRegistration.swift; sourceTree = ""; };
+		D3E171C11A841EAD00AB44CD /* KIFHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = KIFHelper.js; sourceTree = ""; };
+		D3E8EEE71B97A87A001900FB /* ClearPrivateDataTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClearPrivateDataTableViewController.swift; sourceTree = ""; };
+		D3FA777A1A43B2990010CD32 /* SearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchTests.swift; sourceTree = ""; };
+		D3FA77831A43B2CE0010CD32 /* OpenSearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenSearch.swift; sourceTree = ""; };
+		D3FEC38C1AC4B42F00494F45 /* AutocompleteTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutocompleteTextField.swift; sourceTree = ""; };
+		D81127D71F84023B0050841D /* PhotonActionSheetTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotonActionSheetTest.swift; sourceTree = ""; };
+		D81E45121F82C56C004EFFBA /* NewTabContentSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabContentSettingsViewController.swift; sourceTree = ""; };
+		D83821FF1FC7961D00303C12 /* DispatchQueueExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchQueueExtensions.swift; sourceTree = ""; };
+		D863C8E31F68BFC20058D95F /* GradientProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientProgressBar.swift; sourceTree = ""; };
+		D88FDA9E1F4E2B9200FD9709 /* PhotonActionSheetProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotonActionSheetProtocol.swift; sourceTree = ""; };
+		D88FDAAE1F4E2BA000FD9709 /* PhotonActionSheetAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotonActionSheetAnimator.swift; sourceTree = ""; };
+		DD31E0FA1B382B520077078A /* TabPrintPageRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabPrintPageRenderer.swift; sourceTree = ""; };
+		E40A18F71EDC73D5006B7F28 /* Fennec.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Fennec.entitlements; sourceTree = ""; };
+		E40A18F81EDC73D5006B7F28 /* FennecEnterprise.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = FennecEnterprise.entitlements; sourceTree = ""; };
+		E40A18F91EDC73D5006B7F28 /* Firefox.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Firefox.entitlements; sourceTree = ""; };
+		E40A18FA1EDC73D5006B7F28 /* FirefoxBeta.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = FirefoxBeta.entitlements; sourceTree = ""; };
+		E40AFC531DD0E93300DA5651 /* L10nPermissionStringsSnapshotTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = L10nPermissionStringsSnapshotTests.swift; sourceTree = ""; };
+		E40AFC641DD0F25500DA5651 /* L10nBaseSnapshotTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = L10nBaseSnapshotTests.swift; sourceTree = ""; };
+		E40AFC6B1DD128DA00DA5651 /* L10nIntroSnapshotTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = L10nIntroSnapshotTests.swift; sourceTree = ""; };
+		E40FAB0B1A7ABB77009CB80D /* WebServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebServer.swift; sourceTree = ""; };
+		E41A7D4A1A1BE04500245963 /* InitialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InitialViewController.swift; sourceTree = ""; };
+		E41F0D971ADFFB5400FC7387 /* ReadingListService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ReadingListService.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		E41F0D9A1ADFFC5600FC7387 /* ReadingListError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListError.swift; sourceTree = ""; };
+		E42736061EA858CF009C428E /* TabsPayloadTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TabsPayloadTests.swift; path = SyncTests/TabsPayloadTests.swift; sourceTree = ""; };
+		E4424B3B1AC71FB400F44C38 /* FiraSans-Book.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-Book.ttf"; sourceTree = ""; };
+		E46175F21EBB73A10021AE8A /* Sentry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sentry.framework; path = Carthage/Build/iOS/Sentry.framework; sourceTree = ""; };
+		E47536EC1C85412C0022CC69 /* PrintHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrintHelper.swift; sourceTree = ""; };
+		E47536FB1C85415E0022CC69 /* PrintHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = PrintHelper.js; sourceTree = ""; };
+		E47616C61AB74CA600E7DD25 /* ReaderModeBarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderModeBarView.swift; sourceTree = ""; };
+		E49943F41AE6879C00BF9DE4 /* IntroViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroViewController.swift; sourceTree = ""; };
+		E49943F61AE69EDD00BF9DE4 /* Intro.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Intro.xcassets; sourceTree = ""; };
+		E49BFF581B1F48C3009368CC /* Readability.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Readability.js; path = Carthage/Checkouts/readability/Readability.js; sourceTree = SOURCE_ROOT; };
+		E4A960051ABB9C450069AD6F /* ReaderModeUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderModeUtils.swift; sourceTree = ""; };
+		E4A961171AC041C40069AD6F /* ReadabilityService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadabilityService.swift; sourceTree = ""; };
+		E4A961331AC051360069AD6F /* ReadabilityTabHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadabilityTabHelper.swift; sourceTree = ""; };
+		E4A961351AC052DE0069AD6F /* ReadabilityTabHelper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ReadabilityTabHelper.js; sourceTree = ""; };
+		E4A961371AC06FA50069AD6F /* ReaderViewLoading.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ReaderViewLoading.html; sourceTree = ""; };
+		E4B334871BBF23F3004E2BFF /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; };
+		E4B334891BBF23F9004E2BFF /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; };
+		E4B3348B1BC01D8F004E2BFF /* AdjustIntegration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdjustIntegration.swift; sourceTree = ""; };
+		E4B423BD1AB9FE6A007E66C8 /* ReaderModeCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderModeCache.swift; sourceTree = ""; };
+		E4B423DC1ABA0318007E66C8 /* ReaderModeHandlers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderModeHandlers.swift; sourceTree = ""; };
+		E4B7B73A1A793CF20022C5E0 /* CharisSILB.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = CharisSILB.ttf; sourceTree = ""; };
+		E4B7B73B1A793CF20022C5E0 /* CharisSILBI.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = CharisSILBI.ttf; sourceTree = ""; };
+		E4B7B73C1A793CF20022C5E0 /* CharisSILI.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = CharisSILI.ttf; sourceTree = ""; };
+		E4B7B73D1A793CF20022C5E0 /* CharisSILR.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = CharisSILR.ttf; sourceTree = ""; };
+		E4B7B7411A793CF20022C5E0 /* FiraSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-Bold.ttf"; sourceTree = ""; };
+		E4B7B7421A793CF20022C5E0 /* FiraSans-BoldItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-BoldItalic.ttf"; sourceTree = ""; };
+		E4B7B7511A793CF20022C5E0 /* FiraSans-Italic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-Italic.ttf"; sourceTree = ""; };
+		E4B7B7521A793CF20022C5E0 /* FiraSans-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-Light.ttf"; sourceTree = ""; };
+		E4B7B7561A793CF20022C5E0 /* FiraSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-Regular.ttf"; sourceTree = ""; };
+		E4B7B7571A793CF20022C5E0 /* FiraSans-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-SemiBold.ttf"; sourceTree = ""; };
+		E4B7B75F1A793CF20022C5E0 /* FiraSans-UltraLight.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-UltraLight.ttf"; sourceTree = ""; };
+		E4BA8A2B1B4B0A1600BC2E95 /* ViewLater.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ViewLater.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+		E4BA8AA11B4B15EF00BC2E95 /* ActionRequestHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionRequestHandler.swift; sourceTree = ""; };
+		E4BA8AA61B4B15EF00BC2E95 /* ViewLater.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ViewLater.xcassets; sourceTree = ""; };
+		E4BA8AA71B4B15EF00BC2E95 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		E4BCAAB81B0537E300855D82 /* InstructionsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InstructionsViewController.swift; path = ../../Extensions/SendTo/InstructionsViewController.swift; sourceTree = ""; };
+		E4BCAAD81B05380B00855D82 /* ClientPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ClientPickerViewController.swift; path = ../../Extensions/SendTo/ClientPickerViewController.swift; sourceTree = ""; };
+		E4C358541AF144BA00299F7E /* FSReadingList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSReadingList.m; sourceTree = ""; };
+		E4C358561AF1467A00299F7E /* FSReadingList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSReadingList.h; sourceTree = ""; };
+		E4CD9E901A6897FB00318571 /* ReaderMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderMode.swift; sourceTree = ""; };
+		E4CD9E991A68980A00318571 /* ReaderMode.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ReaderMode.js; sourceTree = ""; };
+		E4CD9F1C1A6D9C2800318571 /* WebServerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebServerTests.swift; sourceTree = ""; };
+		E4CD9F2C1A6DC91200318571 /* TabLocationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabLocationView.swift; sourceTree = ""; };
+		E4CD9F531A71506400318571 /* Reader.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Reader.html; sourceTree = ""; };
+		E4CD9F5A1A71506C00318571 /* Reader.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = Reader.css; sourceTree = ""; };
+		E4CD9F6C1A77DD2800318571 /* ReaderModeStyleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderModeStyleViewController.swift; sourceTree = ""; };
+		E4D567181ADECE2700F1EFE7 /* ReadingList.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReadingList.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		E4D5671B1ADECE2700F1EFE7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		E4D567221ADECE2700F1EFE7 /* ReadingListTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReadingListTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		E4D5672A1ADECE2800F1EFE7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		E4D567551ADECE8100F1EFE7 /* ReadingListAuthenticator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListAuthenticator.swift; sourceTree = ""; };
+		E4D567561ADECE8100F1EFE7 /* ReadingListBasicAuthAuthenticator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListBasicAuthAuthenticator.swift; sourceTree = ""; };
+		E4D567571ADECE8100F1EFE7 /* ReadingListBatchRecordResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListBatchRecordResponse.swift; sourceTree = ""; };
+		E4D567581ADECE8100F1EFE7 /* ReadingListChangeAccumulator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListChangeAccumulator.swift; sourceTree = ""; };
+		E4D567591ADECE8100F1EFE7 /* ReadingListClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListClient.swift; sourceTree = ""; };
+		E4D5675A1ADECE8100F1EFE7 /* ReadingListClientMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListClientMetadata.swift; sourceTree = ""; };
+		E4D5675B1ADECE8100F1EFE7 /* ReadingListClientRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListClientRecord.swift; sourceTree = ""; };
+		E4D5675D1ADECE8100F1EFE7 /* ReadingListFetchSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListFetchSpec.swift; sourceTree = ""; };
+		E4D5675E1ADECE8100F1EFE7 /* ReadingListOAuthAuthenticator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListOAuthAuthenticator.swift; sourceTree = ""; };
+		E4D5675F1ADECE8100F1EFE7 /* ReadingListRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListRecord.swift; sourceTree = ""; };
+		E4D567601ADECE8100F1EFE7 /* ReadingListRecordResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListRecordResponse.swift; sourceTree = ""; };
+		E4D567611ADECE8100F1EFE7 /* ReadingListRecordsResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListRecordsResponse.swift; sourceTree = ""; };
+		E4D567621ADECE8100F1EFE7 /* ReadingListResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListResponse.swift; sourceTree = ""; };
+		E4D567631ADECE8100F1EFE7 /* ReadingListServerMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListServerMetadata.swift; sourceTree = ""; };
+		E4D567641ADECE8100F1EFE7 /* ReadingListServerRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListServerRecord.swift; sourceTree = ""; };
+		E4D567651ADECE8100F1EFE7 /* ReadingListSQLStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ReadingListSQLStorage.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		E4D567661ADECE8100F1EFE7 /* ReadingListStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ReadingListStorage.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		E4D567671ADECE8100F1EFE7 /* ReadingListSynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListSynchronizer.swift; sourceTree = ""; };
+		E4D567681ADECE8100F1EFE7 /* ReadingListSyncMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListSyncMetadata.swift; sourceTree = ""; };
+		E4D567691ADECE8100F1EFE7 /* ReadingListUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListUtils.swift; sourceTree = ""; };
+		E4D567951ADECEB800F1EFE7 /* ReadingListClientRecordTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListClientRecordTestCase.swift; sourceTree = ""; };
+		E4D5679B1ADECEB800F1EFE7 /* ReadingListStorageTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListStorageTestCase.swift; sourceTree = ""; };
+		E4D6BEB81A0930EC00F538BD /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; };
+		E4E0BB151AFBC9E4008D6260 /* Shared-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Shared-Bridging-Header.h"; path = "../Shared-Bridging-Header.h"; sourceTree = ""; };
+		E4E0BB171AFBC9E4008D6260 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		E4E25CCA1CA99E7400D0F088 /* HexExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HexExtensionsTests.swift; sourceTree = ""; };
+		E4E7EB6C1C4AED5E0094275D /* SupportUtilsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SupportUtilsTests.swift; sourceTree = ""; };
+		E4ECCDAD1AB131770005E717 /* FiraSans-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FiraSans-Medium.ttf"; sourceTree = ""; };
+		E4F21AA51A13C4A300B0FAAA /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+		E4F2DABF1F620C0200A556CD /* Leanplum.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Leanplum.framework; path = ThirdParty/Leanplum/Leanplum.framework; sourceTree = ""; };
+		E60961861B62B8A700DD640F /* Fennec.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Fennec.xcconfig; path = Configuration/Fennec.xcconfig; sourceTree = ""; };
+		E60961891B62B8C800DD640F /* Firefox.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Firefox.xcconfig; path = Configuration/Firefox.xcconfig; sourceTree = ""; };
+		E60D03171D511398002FE3F6 /* SyncStatusResolver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncStatusResolver.swift; sourceTree = ""; };
+		E60D03291D5118DB002FE3F6 /* SyncStatusResolverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncStatusResolverTests.swift; sourceTree = ""; };
+		E6108FF81C84E91C005D25E8 /* BasePasscodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasePasscodeViewController.swift; sourceTree = ""; };
+		E610B0181EDC68FC00DC9372 /* EventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventTests.swift; sourceTree = ""; };
+		E61453BD1B750A1700C3F9D7 /* RollingFileLoggerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RollingFileLoggerTests.swift; sourceTree = ""; };
+		E619FB2F1E292BE100882B20 /* signedInUser.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = signedInUser.json; sourceTree = ""; };
+		E61D11671EAF8F43008A305B /* PanelDataObserversTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanelDataObserversTests.swift; sourceTree = ""; };
+		E6231C001B90A44F005ABB0D /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
+		E6231C021B90A466005ABB0D /* libstdc++.6.0.9.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.6.0.9.tbd"; path = "usr/lib/libstdc++.6.0.9.tbd"; sourceTree = SDKROOT; };
+		E6231C041B90A472005ABB0D /* libxml2.2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.2.tbd; path = usr/lib/libxml2.2.tbd; sourceTree = SDKROOT; };
+		E62AC15F1E956AFC00843532 /* FennecEnterpriseApplication.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FennecEnterpriseApplication.entitlements; sourceTree = ""; };
+		E6327A631BF6438E008D12E0 /* DebugSettingsBundleOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugSettingsBundleOptions.swift; sourceTree = ""; };
+		E633E2D91C21EAF8001FFF6C /* LoginDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LoginDetailViewController.swift; path = ../Settings/LoginDetailViewController.swift; sourceTree = ""; };
+		E633E3791C2204BE001FFF6C /* LoginManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginManagerTests.swift; sourceTree = ""; };
+		E63ED7D71BFCD9990097D08E /* LoginTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginTableViewCell.swift; sourceTree = ""; };
+		E63ED8E01BFD25580097D08E /* LoginListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginListViewController.swift; sourceTree = ""; };
+		E63F71871DB7FBE200A995C9 /* TestSQLiteMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSQLiteMetadata.swift; sourceTree = ""; };
+		E640E85D1C73A45A00C5F072 /* PasscodeEntryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeEntryViewController.swift; sourceTree = ""; };
+		E640E8691C73A47C00C5F072 /* PasscodeViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeViews.swift; sourceTree = ""; };
+		E64ED8F91BC55AE300DAF864 /* UIAlertControllerExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIAlertControllerExtensions.swift; path = Extensions/UIAlertControllerExtensions.swift; sourceTree = ""; };
+		E650754D1E37F6AE006961AC /* GeometryExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GeometryExtensions.swift; path = Extensions/GeometryExtensions.swift; sourceTree = ""; };
+		E650754F1E37F6D1006961AC /* NSURLExtensionsMailTo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NSURLExtensionsMailTo.swift; path = Extensions/NSURLExtensionsMailTo.swift; sourceTree = ""; };
+		E65075501E37F6D1006961AC /* UIViewExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIViewExtensions.swift; path = Extensions/UIViewExtensions.swift; sourceTree = ""; };
+		E65075531E37F6FC006961AC /* DynamicFontHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DynamicFontHelper.swift; path = Helpers/DynamicFontHelper.swift; sourceTree = ""; };
+		E65075561E37F714006961AC /* FaviconFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconFetcher.swift; sourceTree = ""; };
+		E650755A1E37F747006961AC /* Swizzling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Swizzling.h; sourceTree = ""; };
+		E650755B1E37F747006961AC /* Swizzling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Swizzling.m; sourceTree = ""; };
+		E650755D1E37F756006961AC /* Try.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Try.h; sourceTree = ""; };
+		E650755E1E37F756006961AC /* Try.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Try.m; sourceTree = ""; };
+		E65075601E37F77D006961AC /* MenuHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MenuHelper.swift; path = Helpers/MenuHelper.swift; sourceTree = ""; };
+		E65075621E37F7AB006961AC /* Accessibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = ""; };
+		E65075631E37F7AB006961AC /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = ""; };
+		E65075641E37F7AB006961AC /* AppInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppInfo.swift; sourceTree = ""; };
+		E65075651E37F7AB006961AC /* AssertionUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssertionUtils.swift; sourceTree = ""; };
+		E65075661E37F7AB006961AC /* AsyncReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncReducer.swift; sourceTree = ""; };
+		E65075671E37F7AB006961AC /* AuthenticationKeychainInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationKeychainInfo.swift; sourceTree = ""; };
+		E65075681E37F7AB006961AC /* Bytes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bytes.swift; sourceTree = ""; };
+		E65075691E37F7AB006961AC /* Cancellable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cancellable.swift; sourceTree = ""; };
+		E650756A1E37F7AB006961AC /* CrashSimulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CrashSimulator.h; sourceTree = ""; };
+		E650756B1E37F7AB006961AC /* CrashSimulator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CrashSimulator.m; sourceTree = ""; };
+		E650756C1E37F7AB006961AC /* DeferredUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeferredUtils.swift; sourceTree = ""; };
+		E650756D1E37F7AB006961AC /* DeviceInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceInfo.swift; sourceTree = ""; };
+		E650756E1E37F7AB006961AC /* effective_tld_names.dat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = effective_tld_names.dat; sourceTree = ""; };
+		E65075711E37F7AB006961AC /* ArrayExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtensions.swift; sourceTree = ""; };
+		E65075721E37F7AB006961AC /* HashExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HashExtensions.swift; sourceTree = ""; };
+		E65075731E37F7AB006961AC /* HexExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HexExtensions.swift; sourceTree = ""; };
+		E65075741E37F7AB006961AC /* KeychainWrapperExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainWrapperExtensions.swift; sourceTree = ""; };
+		E65075751E37F7AB006961AC /* NSCharacterSetExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSCharacterSetExtensions.swift; sourceTree = ""; };
+		E65075761E37F7AB006961AC /* NSFileManagerExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSFileManagerExtensions.swift; sourceTree = ""; };
+		E65075771E37F7AB006961AC /* NSMutableAttributedStringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSMutableAttributedStringExtensions.swift; sourceTree = ""; };
+		E65075781E37F7AB006961AC /* NSScannerExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSScannerExtensions.swift; sourceTree = ""; };
+		E65075791E37F7AB006961AC /* NSStringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSStringExtensions.swift; sourceTree = ""; };
+		E650757A1E37F7AB006961AC /* NSURLExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLExtensions.swift; sourceTree = ""; };
+		E650757B1E37F7AB006961AC /* NSURLProtectionSpaceExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLProtectionSpaceExtensions.swift; sourceTree = ""; };
+		E650757C1E37F7AB006961AC /* SetExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetExtensions.swift; sourceTree = ""; };
+		E650757D1E37F7AB006961AC /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = ""; };
+		E650757E1E37F7AB006961AC /* UIColorExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColorExtensions.swift; sourceTree = ""; };
+		E650757F1E37F7AB006961AC /* UIImageExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtensions.swift; sourceTree = ""; };
+		E65075811E37F7AB006961AC /* FSUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSUtils.h; sourceTree = ""; };
+		E65075821E37F7AB006961AC /* FSUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSUtils.m; sourceTree = ""; };
+		E65075831E37F7AB006961AC /* Functions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Functions.swift; sourceTree = ""; };
+		E65075841E37F7AB006961AC /* KeyboardHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardHelper.swift; sourceTree = ""; };
+		E65075851E37F7AB006961AC /* KeychainCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainCache.swift; sourceTree = ""; };
+		E65075861E37F7AB006961AC /* LaunchArguments.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchArguments.swift; sourceTree = ""; };
+		E65075871E37F7AB006961AC /* Loader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Loader.swift; sourceTree = ""; };
+		E65075881E37F7AB006961AC /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; };
+		E65075891E37F7AB006961AC /* NotificationConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationConstants.swift; sourceTree = ""; };
+		E650758B1E37F7AB006961AC /* Prefs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Prefs.swift; sourceTree = ""; };
+		E650758C1E37F7AB006961AC /* RollingFileLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RollingFileLogger.swift; sourceTree = ""; };
+		E650758D1E37F7AB006961AC /* SupportUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SupportUtils.swift; sourceTree = ""; };
+		E650758E1E37F7AB006961AC /* SystemUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SystemUtils.swift; sourceTree = ""; };
+		E650758F1E37F7AB006961AC /* TimeConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeConstants.swift; sourceTree = ""; };
+		E65075901E37F7AB006961AC /* UserAgent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAgent.swift; sourceTree = ""; };
+		E65075911E37F7AB006961AC /* WeakList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakList.swift; sourceTree = ""; };
+		E65075C11E37F956006961AC /* ExtensionUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionUtils.swift; sourceTree = ""; };
+		E653422C1C5944F90039DD9E /* BrowserPrompts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrowserPrompts.swift; sourceTree = ""; };
+		E65607601C08B4E200534B02 /* SearchInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchInputView.swift; sourceTree = ""; };
+		E659A60A1EB7C1D300D7A6AD /* BuddyBuildSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = BuddyBuildSDK.framework; sourceTree = ""; };
+		E65D89171C8647420006EA35 /* AppAuthenticator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppAuthenticator.swift; sourceTree = ""; };
+		E660BDD81BB06521009AC090 /* TabsButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabsButton.swift; sourceTree = ""; };
+		E660BE051BB0666D009AC090 /* InnerStrokedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InnerStrokedView.swift; sourceTree = ""; };
+		E6639F171BF11E17002D0853 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; };
+		E663D5771BB341C4001EF30E /* ToggleButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToggleButton.swift; sourceTree = ""; };
+		E66C5B461BDA81050051AA93 /* UIImage+ImageEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ImageEffects.h"; sourceTree = ""; };
+		E66C5B471BDA81050051AA93 /* UIImage+ImageEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ImageEffects.m"; sourceTree = ""; };
+		E67035ED1E538B500037AB83 /* Mocking.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mocking.swift; sourceTree = ""; };
+		E67422C41CFF2D39009E8373 /* youtube.ico */ = {isa = PBXFileReference; lastKnownFileType = image.ico; path = youtube.ico; sourceTree = ""; };
+		E677F0441D9423FB00ECF1FB /* SQLiteMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteMetadata.swift; sourceTree = ""; };
+		E677F0531D94247300ECF1FB /* Metadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Metadata.swift; sourceTree = ""; };
+		E67D57021D527449003917B1 /* BatchingClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatchingClient.swift; sourceTree = ""; };
+		E683F0A51E92E0820035D990 /* MockableHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockableHistory.swift; sourceTree = ""; };
+		E683F0C11E93D4E90035D990 /* DictionaryExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryExtensions.swift; sourceTree = ""; };
+		E689C6F71E0C6E72008BAADB /* FxASignIn.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = FxASignIn.js; sourceTree = ""; };
+		E689C6F91E0C6E98008BAADB /* FxAContentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxAContentViewController.swift; sourceTree = ""; };
+		E689C72F1E0C7617008BAADB /* NSAttributedStringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NSAttributedStringExtensions.swift; path = Extensions/NSAttributedStringExtensions.swift; sourceTree = ""; };
+		E68AEDAF1B18F81A00133D99 /* SwipeAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwipeAnimator.swift; sourceTree = ""; };
+		E68E39BD1C46F42000B85F42 /* AppSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppSettingsTableViewController.swift; sourceTree = ""; };
+		E68E7ACA1CAC1D4500FDCA76 /* PagingPasscodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PagingPasscodeViewController.swift; sourceTree = ""; };
+		E68E7AD91CAC207400FDCA76 /* ChangePasscodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangePasscodeViewController.swift; sourceTree = ""; };
+		E68E7ADB1CAC208200FDCA76 /* SetupPasscodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetupPasscodeViewController.swift; sourceTree = ""; };
+		E68E7ADD1CAC208A00FDCA76 /* RemovePasscodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemovePasscodeViewController.swift; sourceTree = ""; };
+		E68F36971EA694000048CF44 /* PanelDataObservers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PanelDataObservers.swift; path = ../Client/Frontend/Home/PanelDataObservers.swift; sourceTree = ""; };
+		E6927EBF1C7B6FB800D03F75 /* ErrorToast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorToast.swift; sourceTree = ""; };
+		E692E3281C46E62D009D1240 /* AuthenticationSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationSettingsViewController.swift; sourceTree = ""; };
+		E692E3361C46E86A009D1240 /* AppSettingsOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppSettingsOptions.swift; sourceTree = ""; };
+		E693F0D81E9D64BD0086DC17 /* OptionalExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalExtensions.swift; sourceTree = ""; };
+		E696FE501C47F86E00EC007C /* AuthenticatorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticatorTests.swift; sourceTree = ""; };
+		E698FFD91B4AADF40001F623 /* TabScrollController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabScrollController.swift; sourceTree = ""; };
+		E69922121B94E3EF007C480D /* Licenses.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Licenses.html; sourceTree = ""; };
+		E69DB0751E97DEA9008A67E6 /* SyncTelemetry.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SyncTelemetry.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		E69DB0771E97DEA9008A67E6 /* SyncTelemetry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SyncTelemetry.h; sourceTree = ""; };
+		E69DB0781E97DEA9008A67E6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		E69DB07D1E97DEA9008A67E6 /* SyncTelemetryTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SyncTelemetryTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		E69DB0861E97DEAA008A67E6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		E69DB0B51E97E2AC008A67E6 /* SyncTelemetry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncTelemetry.swift; sourceTree = ""; };
+		E69DB0BA1E97E301008A67E6 /* ActivityStreamTopics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityStreamTopics.swift; sourceTree = ""; };
+		E69DB0C01E97E320008A67E6 /* BookmarkTelemetryPing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkTelemetryPing.swift; sourceTree = ""; };
+		E69E06B91C76173D00D0F926 /* RequirePasscodeIntervalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequirePasscodeIntervalViewController.swift; sourceTree = ""; };
+		E69E06C81C76198000D0F926 /* AuthenticationManagerConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationManagerConstants.swift; sourceTree = ""; };
+		E6A92ADA1C52A8DA00743291 /* LoginInputTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginInputTests.swift; sourceTree = ""; };
+		E6B4C3D71C68F55C001F97E8 /* JSPrompt.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = JSPrompt.html; sourceTree = ""; };
+		E6B4C4021C68F58B001F97E8 /* BrowserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrowserTests.swift; sourceTree = ""; };
+		E6BA20111E52165800697F9C /* SyncTelemetryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SyncTelemetryTests.swift; path = StorageTests/SyncTelemetryTests.swift; sourceTree = ""; };
+		E6BE53CC1D9177B10074909A /* TestSQLiteHistoryRecommendations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSQLiteHistoryRecommendations.swift; sourceTree = ""; };
+		E6C191D41E38F7B7000A213B /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; };
+		E6C191D51E38F7B7000A213B /* Cartfile.resolved */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile.resolved; sourceTree = ""; };
+		E6C70E811E28314700F8DB57 /* PingCentreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PingCentreTests.swift; sourceTree = ""; };
+		E6C9EB6A1E2FBFC300D5CE80 /* signedInUser.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = signedInUser.json; sourceTree = ""; };
+		E6CF28E61CB43B7900151AB3 /* SensitiveViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensitiveViewController.swift; sourceTree = ""; };
+		E6D7C31C1CF4E68D00E746BA /* TestBookmarkModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestBookmarkModel.swift; path = SyncTests/TestBookmarkModel.swift; sourceTree = ""; };
+		E6D8D5E61B569D70009E5A58 /* BrowserTrayAnimators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrowserTrayAnimators.swift; sourceTree = ""; };
+		E6DCC1ED1DCBB6AA00CEC4B7 /* Fennec.enterprise.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Fennec.enterprise.xcconfig; path = Configuration/Fennec.enterprise.xcconfig; sourceTree = ""; };
+		E6EAC5951B29CB3A00E1DE1E /* scrollablePage.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = scrollablePage.html; sourceTree = ""; };
+		E6EDE81D1D524475007A0732 /* BatchingClientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BatchingClientTests.swift; path = SyncTests/BatchingClientTests.swift; sourceTree = ""; };
+		E6F368281D7F594F008CDD67 /* SQLiteHistoryRecommendations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteHistoryRecommendations.swift; sourceTree = ""; };
+		E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeferredTestUtils.swift; sourceTree = ""; };
+		E6F738741EB7A8D300B50143 /* FennecApplication.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FennecApplication.entitlements; sourceTree = ""; };
+		E6F738751EB7A97100B50143 /* FirefoxBetaApplication.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FirefoxBetaApplication.entitlements; sourceTree = ""; };
+		E6F738761EB7A97500B50143 /* FirefoxApplication.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FirefoxApplication.entitlements; sourceTree = ""; };
+		E6F9650C1B2F1CF20034B023 /* SharedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SharedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		E6F9650F1B2F1CF20034B023 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		E6F9653B1B2F1D5D0034B023 /* NSURLExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLExtensionsTests.swift; sourceTree = ""; };
+		E6F965411B2F25110034B023 /* NSMutableAttributedStringExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSMutableAttributedStringExtensionsTests.swift; sourceTree = ""; };
+		E6FCC43C1C40565200DF6113 /* FirefoxBeta.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = FirefoxBeta.xcconfig; path = Configuration/FirefoxBeta.xcconfig; sourceTree = ""; };
+		E6FF6AC91D873CFF0070C294 /* PageMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageMetadata.swift; sourceTree = ""; };
+		EB2A63251F3B49A7004EF8B0 /* ContentBlockerHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBlockerHelper.swift; sourceTree = ""; };
+		EB2A63361F3B5134004EF8B0 /* disconnect-analytics.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "disconnect-analytics.json"; sourceTree = ""; };
+		EB2A63371F3B5135004EF8B0 /* disconnect-content.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "disconnect-content.json"; sourceTree = ""; };
+		EB2A63381F3B5135004EF8B0 /* disconnect-advertising.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "disconnect-advertising.json"; sourceTree = ""; };
+		EB2A63391F3B5135004EF8B0 /* disconnect-social.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "disconnect-social.json"; sourceTree = ""; };
+		EBA31D781F7999030055463D /* SyncPingCentre.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncPingCentre.swift; sourceTree = ""; };
+		EBA31D7A1F79990C0055463D /* SyncTelemetryEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncTelemetryEvents.swift; sourceTree = ""; };
+		EBA31D7C1F79996E0055463D /* SyncTelemetryUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncTelemetryUtils.swift; sourceTree = ""; };
+		EBA31D7E1F799BE20055463D /* Telemetry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Telemetry.framework; path = Carthage/Build/iOS/Telemetry.framework; sourceTree = ""; };
+		EBF47E6F1F7979DF00899189 /* UnifiedTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedTelemetry.swift; sourceTree = ""; };
+		F35B8D2A1D6380EA008E3D61 /* SessionRestore.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = SessionRestore.html; sourceTree = ""; };
+		F35B8D2C1D6383E9008E3D61 /* SessionRestoreHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionRestoreHelper.swift; sourceTree = ""; };
+		F35B8D2E1D638408008E3D61 /* SessionRestoreHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionRestoreHandler.swift; sourceTree = ""; };
+		F84B21BE1A090F8100AAB793 /* Client.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Client.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		F84B21D31A090F8100AAB793 /* ClientTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ClientTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		F84B21D81A090F8100AAB793 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		F84B21D91A090F8100AAB793 /* ClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientTests.swift; sourceTree = ""; };
+		F84B21E51A0910F600AAB793 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppDelegate.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
+		F84B21EF1A0910F600AAB793 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+		F84B22221A09122500AAB793 /* HomePanelViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomePanelViewController.swift; sourceTree = ""; };
+		F84B22261A09127C00AAB793 /* Home.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Home.xcassets; sourceTree = ""; };
+		F84B22431A09165600AAB793 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		F84B22491A0920C600AAB793 /* ShareTo.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareTo.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+		F84B225C1A09210A00AAB793 /* SendTo.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SendTo.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+		F8708D201A0970990051AB07 /* ActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionViewController.swift; sourceTree = ""; };
+		F8708D211A0970990051AB07 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		F8708D221A0970990051AB07 /* MainInterface.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainInterface.storyboard; sourceTree = ""; };
+		F8708D251A0970990051AB07 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+		F8708D261A0970990051AB07 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+		F8708D291A0970990051AB07 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; };
+		FA6B2AC11D41F02D00429414 /* Punycode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Punycode.swift; sourceTree = ""; };
+		FA9293D31D6580E100AC8D33 /* QRCodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeViewController.swift; sourceTree = ""; };
+		FA9294001D6584A200AC8D33 /* QRCode.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = QRCode.xcassets; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		2827315A1ABC9BE600AA1954 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				D09A0CDC1FAA24CC009A0273 /* Account.framework in Frameworks */,
+				D09A0CDD1FAA24D0009A0273 /* FxA.framework in Frameworks */,
+				D09A0CDB1FAA24C8009A0273 /* Shared.framework in Frameworks */,
+				D09A0CDA1FAA24C2009A0273 /* Storage.framework in Frameworks */,
+				E69DB0A81E97DF22008A67E6 /* SyncTelemetry.framework in Frameworks */,
+				7B604F901C494B0F006EEEC3 /* Alamofire.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		282731651ABC9BE700AA1954 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7B604FC01C495FD1006EEEC3 /* XCGLogger.framework in Frameworks */,
+				28ECD9BF1BA1F19900D829DA /* libz.tbd in Frameworks */,
+				282731691ABC9BE700AA1954 /* Sync.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		288A2D821AB8B3260023ABC3 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7BA4A9641C4CFE840091D032 /* Deferred.framework in Frameworks */,
+				D09A0D301FAB8AF3009A0273 /* Sentry.framework in Frameworks */,
+				7BA4A94C1C4CF03B0091D032 /* SwiftKeychainWrapper.framework in Frameworks */,
+				7B604FBC1C495E1E006EEEC3 /* XCGLogger.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		28CE83DE1A1D1E7C00576538 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6231C031B90A466005ABB0D /* libstdc++.6.0.9.tbd in Frameworks */,
+				E6231C051B90A472005ABB0D /* libxml2.2.tbd in Frameworks */,
+				E6231C011B90A44F005ABB0D /* libz.tbd in Frameworks */,
+				E4A888161A95679500CDC337 /* FxA.framework in Frameworks */,
+				2FA436121ABB83B4008031D1 /* Account.framework in Frameworks */,
+				E4D5672F1ADECE2800F1EFE7 /* ReadingList.framework in Frameworks */,
+				288A2D9D1AB8B3260023ABC3 /* Shared.framework in Frameworks */,
+				2FCAE2311ABB51F800877008 /* Storage.framework in Frameworks */,
+				282731751ABC9BE700AA1954 /* Sync.framework in Frameworks */,
+				E69DB08A1E97DEAA008A67E6 /* SyncTelemetry.framework in Frameworks */,
+				7B6050011C49653B006EEEC3 /* AdjustSdk.framework in Frameworks */,
+				E4B3348A1BBF23F9004E2BFF /* AdSupport.framework in Frameworks */,
+				7B604F861C494983006EEEC3 /* Alamofire.framework in Frameworks */,
+				3BA9A0231D2C208C00BD418C /* Fuzi.framework in Frameworks */,
+				7BA4A9471C4CED900091D032 /* GCDWebServers.framework in Frameworks */,
+				E4B334881BBF23F3004E2BFF /* iAd.framework in Frameworks */,
+				0B8E0FF41A932BD500161DC3 /* ImageIO.framework in Frameworks */,
+				E4F2DAC01F620C0300A556CD /* Leanplum.framework in Frameworks */,
+				7BA4A94A1C4CEFC70091D032 /* OnePasswordExtension.framework in Frameworks */,
+				7B8A47F61D01D3B400C07734 /* PassKit.framework in Frameworks */,
+				7B604F9B1C4950F2006EEEC3 /* SDWebImage.framework in Frameworks */,
+				7B604FA21C495268006EEEC3 /* SnapKit.framework in Frameworks */,
+				3B4988CE1E42B01800A12FDA /* SwiftyJSON.framework in Frameworks */,
+				EBA31D861F799BE20055463D /* Telemetry.framework in Frameworks */,
+				7B604FBB1C495D8A006EEEC3 /* XCGLogger.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FA435F71ABB83B4008031D1 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E60222DC1C6E55610061C436 /* FxA.framework in Frameworks */,
+				D09A0CD91FAA2413009A0273 /* Shared.framework in Frameworks */,
+				7B604F891C4949B1006EEEC3 /* Alamofire.framework in Frameworks */,
+				7B604FBE1C495E4E006EEEC3 /* XCGLogger.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FA436021ABB83B4008031D1 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7B604F8A1C4949C1006EEEC3 /* Alamofire.framework in Frameworks */,
+				2FA436061ABB83B4008031D1 /* Account.framework in Frameworks */,
+				7B604FBF1C495E60006EEEC3 /* XCGLogger.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FCAE2161ABB51F800877008 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				0B742CCF1B32493E00EE9264 /* libsqlcipher.a in Frameworks */,
+				D09A0CD81FAA23F6009A0273 /* Shared.framework in Frameworks */,
+				7B604FBD1C495E31006EEEC3 /* XCGLogger.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FCAE2211ABB51F800877008 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2FCAE2251ABB51F800877008 /* Storage.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		390527471C874D35007E0BB7 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				39409A3F1C90E68300DAE683 /* Shared.framework in Frameworks */,
+				3905274C1C874D35007E0BB7 /* NotificationCenter.framework in Frameworks */,
+				39D9E6851C89E9690071FADA /* SnapKit.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		397848D81ED86605004C0C0B /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				396E38ED1EE0C63500CC180F /* Sync.framework in Frameworks */,
+				396E38E61EE0843500CC180F /* Storage.framework in Frameworks */,
+				396E38E31EE083A400CC180F /* Shared.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		3B43E3CD1D95C48D00BBA9DB /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		3BFE4B041D342FB800DDF53F /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6EC6EED1E53548A0067985D /* EarlGrey.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7BEB64461C7345600092C02E /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7BEB64531C7345990092C02E /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		D39FA15C1A83E0EC00EE869C /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7BA4A9661C4D008C0091D032 /* Deferred.framework in Frameworks */,
+				E6231C071B90A712005ABB0D /* libz.tbd in Frameworks */,
+				7B604F991C494F74006EEEC3 /* KIF.framework in Frameworks */,
+				D36998891AD70A0A00650C6C /* IOKit.framework in Frameworks */,
+				D39FA16C1A83E17800EE869C /* CoreGraphics.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4BA8A281B4B0A1600BC2E95 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2805F5A61B8BCA7A00268FD1 /* ReadingList.framework in Frameworks */,
+				E444F7DC1B4B1B7E00FEB19B /* Shared.framework in Frameworks */,
+				E4BA8A8A1B4B10F400BC2E95 /* Storage.framework in Frameworks */,
+				E444F8271B4C1E8800FEB19B /* Sync.framework in Frameworks */,
+				E444F7E51B4B1CB600FEB19B /* ImageIO.framework in Frameworks */,
+				7B604F9E1C49514A006EEEC3 /* SDWebImage.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4D567141ADECE2700F1EFE7 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E4483B5A1ADED63300B485A7 /* Shared.framework in Frameworks */,
+				E60222E31C6E57B20061C436 /* SQLite.framework in Frameworks */,
+				7B604F911C494B3C006EEEC3 /* Alamofire.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4D5671F1ADECE2700F1EFE7 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E4D567231ADECE2700F1EFE7 /* ReadingList.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E69DB0711E97DEA9008A67E6 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E69DB0A91E97DF73008A67E6 /* Shared.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E69DB07A1E97DEA9008A67E6 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E69DB07E1E97DEAA008A67E6 /* SyncTelemetry.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E6F965091B2F1CF20034B023 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6F965121B2F1CF20034B023 /* Shared.framework in Frameworks */,
+				7BA4A9651C4D007B0091D032 /* Deferred.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B21D01A090F8100AAB793 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6231C081B90A71E005ABB0D /* libz.tbd in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B22461A0920C600AAB793 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2FC244B31A855E05007CE41D /* FxA.framework in Frameworks */,
+				28078A471B1507EF0053B46A /* ReadingList.framework in Frameworks */,
+				28C8D1391AD4CE9100F62011 /* Shared.framework in Frameworks */,
+				28C8D11D1AD4CE8900F62011 /* Storage.framework in Frameworks */,
+				2868FA061ADF7B69000D9B1D /* Sync.framework in Frameworks */,
+				7B604F871C494995006EEEC3 /* Alamofire.framework in Frameworks */,
+				3BA9A0321D2C2C0500BD418C /* Fuzi.framework in Frameworks */,
+				0B75AEA91AC20FB20015E5DC /* ImageIO.framework in Frameworks */,
+				7B604F9D1C495143006EEEC3 /* SDWebImage.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B22591A09210A00AAB793 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2FC244B81A855E0D007CE41D /* FxA.framework in Frameworks */,
+				28293BB51B333EA2004A65EC /* ReadingList.framework in Frameworks */,
+				28C8D13B1AD4CEB100F62011 /* Shared.framework in Frameworks */,
+				28C8D13C1AD4CEB400F62011 /* Storage.framework in Frameworks */,
+				2868FA231ADF7B70000D9B1D /* Sync.framework in Frameworks */,
+				3BA9A0311D2C2C0400BD418C /* Fuzi.framework in Frameworks */,
+				0B75AEAA1AC20FBC0015E5DC /* ImageIO.framework in Frameworks */,
+				7B604F9C1C495135006EEEC3 /* SDWebImage.framework in Frameworks */,
+				7B604FA31C4952A4006EEEC3 /* SnapKit.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		0B1C05D41A798B1F004C78B0 /* UIImageViewAligned */ = {
+			isa = PBXGroup;
+			children = (
+				0B1C05D51A798B1F004C78B0 /* UIImageViewAligned.h */,
+				0B1C05D61A798B1F004C78B0 /* UIImageViewAligned.m */,
+			);
+			name = UIImageViewAligned;
+			path = ThirdParty/UIImageViewAligned/UIImageViewAligned;
+			sourceTree = "";
+		};
+		0B742CC71B32491400EE9264 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				0B742CCC1B32491400EE9264 /* libsqlcipher.a */,
+			);
+			name = Products;
+			sourceTree = "";
+		};
+		282731601ABC9BE600AA1954 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				282731621ABC9BE600AA1954 /* Sync-Bridging-Header.h */,
+				282731611ABC9BE600AA1954 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		2827316F1ABC9BE700AA1954 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				28ECD9A21BA1EBA800D829DA /* SyncTests-Bridging-Header.h */,
+				282731701ABC9BE700AA1954 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			path = SyncTests;
+			sourceTree = "";
+		};
+		284AA38F1AD4C115009041C5 /* Interfaces */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = Interfaces;
+			sourceTree = "";
+		};
+		28532D301C483DEB000072D9 /* Bookmarks */ = {
+			isa = PBXGroup;
+			children = (
+				2FCAE23F1ABB531100877008 /* Bookmarks.swift */,
+				2829D3791C2F0A7F00DCF931 /* BookmarksModel.swift */,
+				283586FC1C73F18E00A55435 /* CachingItemSource.swift */,
+				28532D311C483E3D000072D9 /* CompletionOps.swift */,
+				2852B8431C51996B00591EAC /* Trees.swift */,
+			);
+			name = Bookmarks;
+			sourceTree = "";
+		};
+		288A2D7E1AB8B2AD0023ABC3 /* Result */ = {
+			isa = PBXGroup;
+			children = (
+				288A2DB31AB8B38D0023ABC3 /* Error.swift */,
+				288A2DB41AB8B38D0023ABC3 /* Result.swift */,
+			);
+			name = Result;
+			sourceTree = "";
+		};
+		288A2D7F1AB8B2B20023ABC3 /* Box */ = {
+			isa = PBXGroup;
+			children = (
+				288A2DA71AB8B3700023ABC3 /* Box.swift */,
+				288A2DA81AB8B3700023ABC3 /* BoxType.swift */,
+				288A2DA91AB8B3700023ABC3 /* MutableBox.swift */,
+			);
+			name = Box;
+			sourceTree = "";
+		};
+		2891F2B91F991185001B105E /* fixtures */ = {
+			isa = PBXGroup;
+			children = (
+				2891F2BA1F991185001B105E /* v33.db */,
+			);
+			path = fixtures;
+			sourceTree = "";
+		};
+		28926B3C1AC0F176009C0B1D /* Records */ = {
+			isa = PBXGroup;
+			children = (
+				28926B361AC0F0DD009C0B1D /* EnvelopeJSON.swift */,
+				28926B191AC0F074009C0B1D /* EncryptedJSON.swift */,
+				28926B391AC0F128009C0B1D /* CleartextPayloadJSON.swift */,
+				28CE83BD1A1D1D3200576538 /* KeysPayload.swift */,
+				28AA941C1B97DCA800703DC6 /* BookmarkPayload.swift */,
+				28CE83BB1A1D1D3200576538 /* ClientPayload.swift */,
+				2894C16B1AE89FD500F1F92F /* HistoryPayload.swift */,
+				28ED02011B26123E003948B2 /* LoginPayload.swift */,
+				2853C5401AD84C6800C4F31D /* TabsPayload.swift */,
+				28CE83BE1A1D1D3200576538 /* Record.swift */,
+			);
+			name = Records;
+			sourceTree = "";
+		};
+		28926B3D1AC0F1A6009C0B1D /* Meta */ = {
+			isa = PBXGroup;
+			children = (
+				2F3724E21ABF3C19007607FA /* Info.swift */,
+				28CE83BF1A1D1D3200576538 /* SyncMeta.swift */,
+				28E23C111AC5A5EE00F5AC85 /* State.swift */,
+			);
+			name = Meta;
+			sourceTree = "";
+		};
+		2894C1641AE89DBC00F1F92F /* Synchronizers */ = {
+			isa = PBXGroup;
+			children = (
+				28C28BD81C51A2FA00D5460E /* Bookmarks */,
+				2894C1681AE89DDC00F1F92F /* ClientsSynchronizer.swift */,
+				28A17B661BEC727500BC14ED /* Downloader.swift */,
+				2894C1421AE89D8900F1F92F /* HistorySynchronizer.swift */,
+				28ED02281B262E0A003948B2 /* IndependentRecordSynchronizer.swift */,
+				28ED02251B262B5E003948B2 /* LoginsSynchronizer.swift */,
+				2F3724E41ABF3C19007607FA /* Synchronizer.swift */,
+				2894C1651AE89DD200F1F92F /* TabsSynchronizer.swift */,
+			);
+			name = Synchronizers;
+			sourceTree = "";
+		};
+		28C077911A3B05C200834FE5 /* SyncTests */ = {
+			isa = PBXGroup;
+			children = (
+				2827316F1ABC9BE700AA1954 /* Supporting Files */,
+				CE339ED61F2507A1009BE0E6 /* TestBookmarksSynchronizer.swift */,
+				28D980221C47149000277055 /* TestBookmarkTreeMerging.swift */,
+				E6D7C31C1CF4E68D00E746BA /* TestBookmarkModel.swift */,
+				CEFC983B1EC0DC60008A3E48 /* TestBookmarksRepairRequestor.swift */,
+				28ECD9791BA1EA2200D829DA /* MockSyncServer.swift */,
+				28C077971A3B064000834FE5 /* CryptoTests.swift */,
+				28ECD9F31BA1F59800D829DA /* DownloadTests.swift */,
+				2855611E1AEFFA1C00D5ED5B /* HistorySynchronizerTests.swift */,
+				28F596A01ACA13CA0071DDCC /* InfoTests.swift */,
+				2F3724C41ABF3C01007607FA /* LiveStorageClientTests.swift */,
+				2F67C5251BB0CB4E00E7B73A /* MetaGlobalTests.swift */,
+				2F8C76561BC32F3C00D5E4E0 /* MockSyncServerTests.swift */,
+				E67035ED1E538B500037AB83 /* Mocking.swift */,
+				28C0779D1A3B066000834FE5 /* RecordTests.swift */,
+				50027345B49B967409DDA348 /* StateTests.swift */,
+				E6EDE81D1D524475007A0732 /* BatchingClientTests.swift */,
+				2F3724C51ABF3C01007607FA /* StorageClientTests.swift */,
+				E6BA20111E52165800697F9C /* SyncTelemetryTests.swift */,
+				E42736061EA858CF009C428E /* TabsPayloadTests.swift */,
+			);
+			name = SyncTests;
+			sourceTree = "";
+		};
+		28C28BD81C51A2FA00D5460E /* Bookmarks */ = {
+			isa = PBXGroup;
+			children = (
+				CE564D8D1EB7BD7700BEDDDC /* BookmarksRepairRequestor.swift */,
+				288E67C11B9E730900AE2C6A /* BookmarksDownloader.swift */,
+				280CB1361C20E0A3005AF147 /* BookmarksSynchronizer.swift */,
+				28C28BFC1C51A3B900D5460E /* Merging.swift */,
+				28532CE51C48098D000072D9 /* ThreeWayTreeMerger.swift */,
+			);
+			name = Bookmarks;
+			path = Synchronizers/Bookmarks;
+			sourceTree = "";
+		};
+		28CE83B91A1D1D3200576538 /* Sync */ = {
+			isa = PBXGroup;
+			children = (
+				2894C1641AE89DBC00F1F92F /* Synchronizers */,
+				284AA38F1AD4C115009041C5 /* Interfaces */,
+				282731601ABC9BE600AA1954 /* Supporting Files */,
+				28926B3D1AC0F1A6009C0B1D /* Meta */,
+				28926B3C1AC0F176009C0B1D /* Records */,
+				E69DB0B31E97E0E4008A67E6 /* Telemetry */,
+				E67D57021D527449003917B1 /* BatchingClient.swift */,
+				28CE83BC1A1D1D3200576538 /* KeyBundle.swift */,
+				2F3724E31ABF3C19007607FA /* StorageClient.swift */,
+				28E91E741B443AD5009DF274 /* SyncConstants.swift */,
+				2885023E1AC117A500E7F670 /* SyncStateMachine.swift */,
+				288501DD1AC0F61D00E7F670 /* RequestExtensions.swift */,
+			);
+			path = Sync;
+			sourceTree = "";
+		};
+		28CE83CB1A1D1D5100576538 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				28CE83D01A1D1D5100576538 /* FxA.framework */,
+				28CE83D21A1D1D5100576538 /* FxATests.xctest */,
+			);
+			name = Products;
+			sourceTree = "";
+		};
+		28CE83EF1A1D246900576538 /* Third-Party Source */ = {
+			isa = PBXGroup;
+			children = (
+				E66C5B451BDA81050051AA93 /* Apple */,
+				E659A6091EB7C1D300D7A6AD /* BuddyBuild */,
+				288A2D7F1AB8B2B20023ABC3 /* Box */,
+				28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */,
+				D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */,
+				288A2D7E1AB8B2AD0023ABC3 /* Result */,
+				0B742CC61B32491400EE9264 /* sqlcipher.xcodeproj */,
+				7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */,
+				0B1C05D41A798B1F004C78B0 /* UIImageViewAligned */,
+				3B6889C41D66950E002AC85E /* UIImageColors.swift */,
+				3B0943801D6CC4FC004F24E1 /* FilledPageControl.swift */,
+				7479B4ED1C5306A200DF000B /* Reachability.swift */,
+			);
+			name = "Third-Party Source";
+			sourceTree = "";
+		};
+		28EADE5C1AFC3A6D007FB2FB /* Extensions */ = {
+			isa = PBXGroup;
+			children = (
+				E650754D1E37F6AE006961AC /* GeometryExtensions.swift */,
+				D83821FF1FC7961D00303C12 /* DispatchQueueExtensions.swift */,
+				E689C72F1E0C7617008BAADB /* NSAttributedStringExtensions.swift */,
+				28EADE381AFC3898007FB2FB /* UIImageViewExtensions.swift */,
+				E64ED8F91BC55AE300DAF864 /* UIAlertControllerExtensions.swift */,
+				A83E5AB61C1D993D0026D912 /* UIPasteboardExtensions.swift */,
+				E650754F1E37F6D1006961AC /* NSURLExtensionsMailTo.swift */,
+				E65075501E37F6D1006961AC /* UIViewExtensions.swift */,
+				C817B34C1FC609500086018E /* UIScrollViewSwizzled.swift */,
+			);
+			name = Extensions;
+			sourceTree = "";
+		};
+		2F44FC551A9E83E200FD20CC /* Settings */ = {
+			isa = PBXGroup;
+			children = (
+				8D8251721F4DE67E00780643 /* AdvanceAccountSettingViewController.swift */,
+				3B39EDCA1E16E1AA00EF029F /* CustomSearchViewController.swift */,
+				E692E3361C46E86A009D1240 /* AppSettingsOptions.swift */,
+				E68E39BD1C46F42000B85F42 /* AppSettingsTableViewController.swift */,
+				0B62EFD11AD63CD100ACB9CD /* Clearables.swift */,
+				D3E8EEE71B97A87A001900FB /* ClearPrivateDataTableViewController.swift */,
+				E689C6F91E0C6E98008BAADB /* FxAContentViewController.swift */,
+				39AC59191CC574AA0042C2F5 /* HomePageSettingsViewController.swift */,
+				392ED6B61D06E85E009D9B62 /* NewTabChoiceViewController.swift */,
+				D81E45121F82C56C004EFFBA /* NewTabContentSettingsViewController.swift */,
+				2F44FCCA1A9E972E00FD20CC /* SearchEnginePicker.swift */,
+				2F44FCC61A9E8CF500FD20CC /* SearchSettingsTableViewController.swift */,
+				74E36D771B71323500D69DA1 /* SettingsContentViewController.swift */,
+				2F44FC711A9E840300FD20CC /* SettingsNavigationController.swift */,
+				2F44FCC41A9E85E900FD20CC /* SettingsTableViewController.swift */,
+				7B4980A71CE363ED0017547C /* Settings.xcassets */,
+			);
+			path = Settings;
+			sourceTree = "";
+		};
+		2FA435FC1ABB83B4008031D1 /* Account */ = {
+			isa = PBXGroup;
+			children = (
+				2F14E1391ABB890800FF98DB /* Account-Bridging-Header.h */,
+				2FA436221ABB8436008031D1 /* FirefoxAccount.swift */,
+				2FA436231ABB8436008031D1 /* FirefoxAccountConfiguration.swift */,
+				2FA436251ABB8436008031D1 /* FxAClient10.swift */,
+				D32A350D1D6530D80066DAE9 /* FxADevice.swift */,
+				D3DBE6E41D6516FE00033FFF /* FxADeviceRegistration.swift */,
+				2F1A3DE01ABE3C90002F1E15 /* FxALoginStateMachine.swift */,
+				3905B4D41E8E7A6B0027D953 /* FxAPushMessageHandler.swift */,
+				2FFC4D1A1ABE3C360081D675 /* FxAState.swift */,
+				2FA436271ABB8436008031D1 /* HawkHelper.swift */,
+				2FDBCF601ABFC9DE00AFF7F0 /* SyncAuthState.swift */,
+				2FA436281ABB8436008031D1 /* TokenServerClient.swift */,
+				2FA435FD1ABB83B4008031D1 /* Supporting Files */,
+			);
+			path = Account;
+			sourceTree = "";
+		};
+		2FA435FD1ABB83B4008031D1 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				2FA435FE1ABB83B4008031D1 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		2FA4360B1ABB83B4008031D1 /* AccountTests */ = {
+			isa = PBXGroup;
+			children = (
+				2FA436371ABB8448008031D1 /* FirefoxAccountTests.swift */,
+				2FA436381ABB8448008031D1 /* FxAClient10Tests.swift */,
+				2F1A3DFD1ABE3C9C002F1E15 /* FxALoginStateMachineTests.swift */,
+				2FFC4D371ABE3C420081D675 /* FxAStateTests.swift */,
+				2FA4363A1ABB8448008031D1 /* HawkHelperTests.swift */,
+				2FA4363B1ABB8448008031D1 /* LiveAccountTest.swift */,
+				2FDBCF9A1AC0ADB500AFF7F0 /* SyncAuthStateTests.swift */,
+				2FA4363C1ABB8448008031D1 /* TokenServerClientTests.swift */,
+				E6C9EB6A1E2FBFC300D5CE80 /* signedInUser.json */,
+				2FA4360C1ABB83B4008031D1 /* Supporting Files */,
+			);
+			path = AccountTests;
+			sourceTree = "";
+		};
+		2FA4360C1ABB83B4008031D1 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				E619FB2F1E292BE100882B20 /* signedInUser.json */,
+				2FA4360D1ABB83B4008031D1 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		2FCAE21B1ABB51F800877008 /* Storage */ = {
+			isa = PBXGroup;
+			children = (
+				74B195431CF503FC007F36EF /* RecentlyClosedTabs.swift */,
+				2FCAE33D1ABB5F1800877008 /* Storage-Bridging-Header.h */,
+				D37DE2821CA2047500A5EC69 /* CertStore.swift */,
+				28C4AB711AD42D4300D9ACE3 /* Clients.swift */,
+				2FCAE2411ABB531100877008 /* Cursor.swift */,
+				28302E3F1AF0747800521E2E /* DatabaseError.swift */,
+				394CF6CE1BAA493C00906917 /* DefaultSuggestedSites.swift */,
+				D3BF8CBA1B7425570007AFE6 /* DiskImageStore.swift */,
+				E65075C11E37F956006961AC /* ExtensionUtils.swift */,
+				2FCAE2421ABB531100877008 /* Favicons.swift */,
+				2FCAE2431ABB531100877008 /* FileAccessor.swift */,
+				2FCAE2441ABB531100877008 /* History.swift */,
+				0BDA56B11B26B1E4008C9B96 /* Logins.swift */,
+				E677F0531D94247300ECF1FB /* Metadata.swift */,
+				0B3E7DB91B27AB4C00E2E84D /* MockLogins.swift */,
+				285D3B671B4380B70035FD22 /* Queue.swift */,
+				E6FF6AC91D873CFF0070C294 /* PageMetadata.swift */,
+				2FCAE2471ABB531100877008 /* RemoteTabs.swift */,
+				2829D39F1C2F0AD400DCF931 /* Sharing.swift */,
+				2FCAE2481ABB531100877008 /* Site.swift */,
+				0B54BD181B698B7C004C822C /* SuggestedSites.swift */,
+				28B62ACD1BC745E7004A585A /* Syncable.swift */,
+				7BF5A1E91B41640500EA9DD8 /* SyncQueue.swift */,
+				2FCAE25C1ABB531100877008 /* Visit.swift */,
+				28532D301C483DEB000072D9 /* Bookmarks */,
+				2FCAE2491ABB531100877008 /* SQL */,
+				2FCAE21C1ABB51F800877008 /* Supporting Files */,
+				2FCAE25A1ABB531100877008 /* ThirdParty */,
+			);
+			path = Storage;
+			sourceTree = "";
+		};
+		2FCAE21C1ABB51F800877008 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		2FCAE22A1ABB51F800877008 /* StorageTests */ = {
+			isa = PBXGroup;
+			children = (
+				D37DE2C81CA356F900A5EC69 /* testcert1.pem */,
+				D37DE2C91CA356F900A5EC69 /* testcert2.pem */,
+				D37DE2C61CA356D800A5EC69 /* CertTests.swift */,
+				D3BF8CBC1B7472FA0007AFE6 /* DiskImageStoreTests.swift */,
+				2FCAE2791ABB533A00877008 /* MockFiles.swift */,
+				289A4C121C4EB90600A460E3 /* StorageTestUtils.swift */,
+				7BF5A1ED1B429B3100EA9DD8 /* SyncCommandsTests.swift */,
+				281B02991C037C1F005202C3 /* TestBrowserDB.swift */,
+				0BDA56AE1B26B1D5008C9B96 /* TestLogins.swift */,
+				28D158AC1AFD90E500F9C065 /* TestSQLiteBookmarks.swift */,
+				2FCAE27D1ABB533A00877008 /* TestSQLiteHistory.swift */,
+				E6BE53CC1D9177B10074909A /* TestSQLiteHistoryRecommendations.swift */,
+				E63F71871DB7FBE200A995C9 /* TestSQLiteMetadata.swift */,
+				2FCAE27A1ABB533A00877008 /* TestSQLiteRemoteClientsAndTabs.swift */,
+				D32CACEC1AE04DA1000658EB /* TestSwiftData.swift */,
+				2FCAE22B1ABB51F800877008 /* Supporting Files */,
+			);
+			path = StorageTests;
+			sourceTree = "";
+		};
+		2FCAE22B1ABB51F800877008 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				2891F2B91F991185001B105E /* fixtures */,
+				2FCAE22C1ABB51F800877008 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		2FCAE2491ABB531100877008 /* SQL */ = {
+			isa = PBXGroup;
+			children = (
+				2FCAE24B1ABB531100877008 /* BrowserDB.swift */,
+				282915E51AF1A7920006EEB5 /* BrowserSchema.swift */,
+				D0B29EDF1F460BDF00C7CEFC /* LoginsSchema.swift */,
+				D018F93D1F44A7190098F8CA /* Schema.swift */,
+				28126F761C2F9833006466CC /* SQLiteBookmarksBase.swift */,
+				28126F471C2F948E006466CC /* SQLiteBookmarksHelpers.swift */,
+				28126F6D1C2F94F9006466CC /* SQLiteBookmarksModel.swift */,
+				28126F731C2F96F1006466CC /* SQLiteBookmarksResetting.swift */,
+				285F2DC01AF80B4600211843 /* SQLiteBookmarksSyncing.swift */,
+				D0131B4C1F3CF7D8000CDE86 /* SQLiteFavicons.swift */,
+				2FCAE2551ABB531100877008 /* SQLiteHistory.swift */,
+				318FB6EA1DB5600D0004E40F /* SQLiteHistoryFactories.swift */,
+				E6F368281D7F594F008CDD67 /* SQLiteHistoryRecommendations.swift */,
+				0BDA56B31B26B203008C9B96 /* SQLiteLogins.swift */,
+				E677F0441D9423FB00ECF1FB /* SQLiteMetadata.swift */,
+				285D3B8F1B4386520035FD22 /* SQLiteQueue.swift */,
+				2FCAE2581ABB531100877008 /* SQLiteRemoteClientsAndTabs.swift */,
+			);
+			path = SQL;
+			sourceTree = "";
+		};
+		2FCAE25A1ABB531100877008 /* ThirdParty */ = {
+			isa = PBXGroup;
+			children = (
+				2FCAE25B1ABB531100877008 /* SwiftData.swift */,
+			);
+			path = ThirdParty;
+			sourceTree = "";
+		};
+		3905274D1C874D35007E0BB7 /* Today */ = {
+			isa = PBXGroup;
+			children = (
+				391AEFD11C8F11ED00691F84 /* Images.xcassets */,
+				390527531C874D35007E0BB7 /* Info.plist */,
+				3905274E1C874D35007E0BB7 /* TodayViewController.swift */,
+			);
+			path = Today;
+			sourceTree = "";
+		};
+		392ED7D51D0AEEEE009D9B62 /* Accessors */ = {
+			isa = PBXGroup;
+			children = (
+				392ED7E31D0AEF56009D9B62 /* NewTabAccessors.swift */,
+				392ED7E51D0AEFEF009D9B62 /* HomePageAccessors.swift */,
+			);
+			name = Accessors;
+			sourceTree = "";
+		};
+		397848DC1ED86605004C0C0B /* NotificationService */ = {
+			isa = PBXGroup;
+			children = (
+				397848DF1ED86605004C0C0B /* Info.plist */,
+				397848DD1ED86605004C0C0B /* NotificationService.swift */,
+				396E38DB1EE0818800CC180F /* ExtensionProfile.swift */,
+			);
+			path = NotificationService;
+			sourceTree = "";
+		};
+		39A359BD1BFCCE7B006B9E87 /* Helpers */ = {
+			isa = PBXGroup;
+			children = (
+				E65075531E37F6FC006961AC /* DynamicFontHelper.swift */,
+				E65075601E37F77D006961AC /* MenuHelper.swift */,
+				39F99FED1E3A71F800F353B4 /* FxALoginHelper.swift */,
+				39455F761FC83F430088A22C /* TabEventHandler.swift */,
+				39F819C51FD70F5D009E31E4 /* TabEventHandlers.swift */,
+				39A359E31BFCCE94006B9E87 /* UserActivityHandler.swift */,
+			);
+			name = Helpers;
+			sourceTree = "";
+		};
+		39B0646D1E7ADA4B000BE173 /* PushTests */ = {
+			isa = PBXGroup;
+			children = (
+				39C22C2C1E897B9A000C0E56 /* LivePushClientTests.swift */,
+				39B0647C1E7ADAC2000BE173 /* PushCryptoTests.swift */,
+			);
+			name = PushTests;
+			sourceTree = "";
+		};
+		39F99FC71E3A6DB700F353B4 /* Push */ = {
+			isa = PBXGroup;
+			children = (
+				39F99FD91E3A6DE300F353B4 /* PushClient.swift */,
+				39F99FDA1E3A6DE300F353B4 /* PushConfiguration.swift */,
+				395C8F201E796AD600A68E8C /* PushCrypto.swift */,
+				39F99FDB1E3A6DE300F353B4 /* PushRegistration.swift */,
+			);
+			path = Push;
+			sourceTree = "";
+		};
+		3B4262D31E538EB100CA681C /* Metadata Parsing */ = {
+			isa = PBXGroup;
+			children = (
+				3B4262E21E538EC400CA681C /* MetadataHelper.js */,
+				3B4262E31E538EC400CA681C /* MetadataParserHelper.swift */,
+				3B4262E41E538EC400CA681C /* page-metadata-parser.js */,
+			);
+			name = "Metadata Parsing";
+			sourceTree = "";
+		};
+		3B43E3D11D95C48D00BBA9DB /* StoragePerfTests */ = {
+			isa = PBXGroup;
+			children = (
+				3B43E3D21D95C48D00BBA9DB /* StoragePerfTests.swift */,
+				3B43E3D41D95C48D00BBA9DB /* Info.plist */,
+			);
+			path = StoragePerfTests;
+			sourceTree = "";
+		};
+		3BF4B8DA1D38493300493393 /* Utils */ = {
+			isa = PBXGroup;
+			children = (
+				39EB46971E26DDB4006346E8 /* ScreenGraph.swift */,
+				39EB46981E26DDB4006346E8 /* FxScreenGraph.swift */,
+				3BF4B8E81D38497A00493393 /* BaseTestCase.swift */,
+			);
+			name = Utils;
+			sourceTree = "";
+		};
+		3BFE4B081D342FB900DDF53F /* XCUITests */ = {
+			isa = PBXGroup;
+			children = (
+				0BC9C9C31F26F54D000E8AB5 /* SiteLoadTest.swift */,
+				3D71C89D1F5703A1008D8646 /* CopiedLinksTests.swift */,
+				3DEFED071F55EBE300F8620C /* TrackingProtectionTests.swift */,
+				3D9CA9A71EF84D04002434DD /* NoImageTests.swift */,
+				3D9CAA1B1EFCD655002434DD /* ClipBoardTests.swift */,
+				3D9CA9831EF456A8002434DD /* NightModeTests.swift */,
+				0B305E1A1E3A98A900BE0767 /* BookmarkingTests.swift */,
+				2C3406C71E719F00000FD889 /* SettingsTest.swift */,
+				0B3D670D1E09B90B00C1EFC7 /* AuthenticationTest.swift */,
+				0B729D361E047D6A008E6859 /* HomePageSettingsTest.swift */,
+				3BF4B8DA1D38493300493393 /* Utils */,
+				3BFE4B4F1D34673D00DDF53F /* ThirdPartySearchTest.swift */,
+				3B546EBF1D95ECAE00BDBE36 /* ActivityStreamTest.swift */,
+				3BFE4B0B1D342FB900DDF53F /* Info.plist */,
+				55A747161DC46FC400CE1B57 /* HomePageUITest.swift */,
+				2C2A5EF31E68469500F02659 /* PrivateBrowsingTest.swift */,
+				2CA16FDD1E5F089100332277 /* SearchTest.swift */,
+				2C97EC701E72C80E0092EC18 /* TopTabsTest.swift */,
+				2CF449A41E7BFE2C00FD7595 /* NavigationTest.swift */,
+				2C8C07761E7800EA00DC1237 /* FindInPageTest.swift */,
+				2C31A7A81E8BFB2200DAC646 /* ReaderViewUITest.swift */,
+				2C31A8461E8D447F00DAC646 /* HomePageSettingsUITest.swift */,
+				2CB56E3E1E926BFB00AF7586 /* ToolbarTest.swift */,
+				2CC1B3EF1E9B861400814EEC /* DomainAutocompleteTest.swift */,
+				2CEA6F781E93E3A600D4100E /* SearchSettingsUITest.swift */,
+				0B9D40781E8D5AC80059E664 /* XCUITests-Bridging-Header.h */,
+				D81127D71F84023B0050841D /* PhotonActionSheetTest.swift */,
+				2C2A91281FA2410D002E36BD /* HistoryTests.swift */,
+			);
+			path = XCUITests;
+			sourceTree = "";
+		};
+		7B0B1B9C1C1B69F500DF4AB5 /* Extensions */ = {
+			isa = PBXGroup;
+			children = (
+				E4BCAAD81B05380B00855D82 /* ClientPickerViewController.swift */,
+				E4BCAAB81B0537E300855D82 /* InstructionsViewController.swift */,
+			);
+			name = Extensions;
+			sourceTree = "";
+		};
+		7B3632D21C2983F000D12AF9 /* L10nSnapshotTests */ = {
+			isa = PBXGroup;
+			children = (
+				7BEB644E1C7345600092C02E /* Info.plist */,
+				E40AFC641DD0F25500DA5651 /* L10nBaseSnapshotTests.swift */,
+				E40AFC6B1DD128DA00DA5651 /* L10nIntroSnapshotTests.swift */,
+				E40AFC531DD0E93300DA5651 /* L10nPermissionStringsSnapshotTests.swift */,
+				7B3632D31C2983F000D12AF9 /* L10nSnapshotTests.swift */,
+			);
+			path = L10nSnapshotTests;
+			sourceTree = "";
+		};
+		7B3632E71C29879300D12AF9 /* Snapshot */ = {
+			isa = PBXGroup;
+			children = (
+				7B60B0071BDE3AE10090C984 /* SnapshotHelper.swift */,
+				7B95CD181C3AB2EE00638E31 /* MarketingUITests */,
+				7B3632D21C2983F000D12AF9 /* L10nSnapshotTests */,
+			);
+			name = Snapshot;
+			sourceTree = "";
+		};
+		7B604FC11C496005006EEEC3 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				EBA31D7E1F799BE20055463D /* Telemetry.framework */,
+				E4F2DABF1F620C0200A556CD /* Leanplum.framework */,
+				E46175F21EBB73A10021AE8A /* Sentry.framework */,
+				3B4988CD1E42B01800A12FDA /* SwiftyJSON.framework */,
+				E6231C041B90A472005ABB0D /* libxml2.2.tbd */,
+				E6231C021B90A466005ABB0D /* libstdc++.6.0.9.tbd */,
+				E6231C001B90A44F005ABB0D /* libz.tbd */,
+				0B21E8051E26CCB7000C8779 /* EarlGrey.framework */,
+				D39FA16B1A83E17800EE869C /* CoreGraphics.framework */,
+				0B8E0FF31A932BD500161DC3 /* ImageIO.framework */,
+				D36998881AD70A0A00650C6C /* IOKit.framework */,
+				3BA9A0221D2C208C00BD418C /* Fuzi.framework */,
+				7B8A47F51D01D3B400C07734 /* PassKit.framework */,
+				7BA4A9631C4CFE840091D032 /* Deferred.framework */,
+				7BA4A94B1C4CF03B0091D032 /* SwiftKeychainWrapper.framework */,
+				7BA4A9491C4CEFC70091D032 /* OnePasswordExtension.framework */,
+				7BA4A9451C4CED780091D032 /* GCDWebServers.framework */,
+				7B6050001C49653B006EEEC3 /* AdjustSdk.framework */,
+				7B604FBA1C495D8A006EEEC3 /* XCGLogger.framework */,
+				7B604FA11C495268006EEEC3 /* SnapKit.framework */,
+				7B604F9A1C4950F2006EEEC3 /* SDWebImage.framework */,
+				7B604F981C494F74006EEEC3 /* KIF.framework */,
+				7B604F851C494983006EEEC3 /* Alamofire.framework */,
+				E4B334891BBF23F9004E2BFF /* AdSupport.framework */,
+				E4B334871BBF23F3004E2BFF /* iAd.framework */,
+				3905274B1C874D35007E0BB7 /* NotificationCenter.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "";
+		};
+		7B95CD181C3AB2EE00638E31 /* MarketingUITests */ = {
+			isa = PBXGroup;
+			children = (
+				7B95CD191C3AB2EE00638E31 /* MarketingUITests.swift */,
+				7BEB645B1C7345990092C02E /* Info.plist */,
+			);
+			path = MarketingUITests;
+			sourceTree = "";
+		};
+		7B9A62BA1C4002B1005C83DC /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				7B9A62DB1C4002B1005C83DC /* SQLite.framework */,
+				7B10AAE61E3A57F90002DD08 /* SQLiteTests iOS.xctest */,
+				7B9A62DF1C4002B1005C83DC /* SQLite.framework */,
+				7B10AAE81E3A57F90002DD08 /* SQLiteTests Mac.xctest */,
+				7B10AAEA1E3A57F90002DD08 /* SQLite.framework */,
+				7B10AAEC1E3A57F90002DD08 /* SQLiteTests tvOS.xctest */,
+				7B10AAEE1E3A57F90002DD08 /* SQLite.framework */,
+			);
+			name = Products;
+			sourceTree = "";
+		};
+		7BC7B4571C903A6A0046E9D2 /* Menu */ = {
+			isa = PBXGroup;
+			children = (
+				7B42406D1CA04CAC009B5C28 /* Menu.xcassets */,
+			);
+			path = Menu;
+			sourceTree = "";
+		};
+		7BEDD28C1CB7CB12004B51F3 /* Animators */ = {
+			isa = PBXGroup;
+			children = (
+				7BEDD29A1CB7CB24004B51F3 /* JumpAndSpinAnimator.swift */,
+				7BEDD2B11CB7CC0B004B51F3 /* Animatable.swift */,
+			);
+			path = Animators;
+			sourceTree = "";
+		};
+		C8F457A61F1FD75A000CB895 /* BrowserViewController */ = {
+			isa = PBXGroup;
+			children = (
+				C8F457A71F1FD75A000CB895 /* BrowserViewController+WKNavigationDelegate.swift */,
+				C8F457A91F1FDD9B000CB895 /* BrowserViewController+KeyCommands.swift */,
+			);
+			path = BrowserViewController;
+			sourceTree = "";
+		};
+		D30EBB5B1C75503800105AE9 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				D30EBB641C75503800105AE9 /* libKIF.a */,
+				D30EBB661C75503800105AE9 /* Test Host.app */,
+				D30EBB681C75503800105AE9 /* KIF Tests - XCTest.xctest */,
+				D30EBB6A1C75503800105AE9 /* KIF.framework */,
+				E6CB64CC1DA42C2900887098 /* KIFFrameworkConsumer.app */,
+				E6CB64CE1DA42C2900887098 /* KIFFrameworkConsumerTests.xctest */,
+			);
+			name = Products;
+			sourceTree = "";
+		};
+		D34DC84C1A16C40C00D49B7B /* Providers */ = {
+			isa = PBXGroup;
+			children = (
+				E68F36971EA694000048CF44 /* PanelDataObservers.swift */,
+				3B61CD481F2A74EF00D38DE1 /* PocketFeed.swift */,
+				E60D03171D511398002FE3F6 /* SyncStatusResolver.swift */,
+				D34DC84D1A16C40C00D49B7B /* Profile.swift */,
+				0BD19A661A25309B0084FBA7 /* NSUserDefaultsPrefs.swift */,
+			);
+			path = Providers;
+			sourceTree = "";
+		};
+		D38A1BEB1A9FA2CA00F6A386 /* Widgets */ = {
+			isa = PBXGroup;
+			children = (
+				D3FEC38C1AC4B42F00494F45 /* AutocompleteTextField.swift */,
+				E6927EBF1C7B6FB800D03F75 /* ErrorToast.swift */,
+				E660BE051BB0666D009AC090 /* InnerStrokedView.swift */,
+				0BF1B7E21AC60DEA00A7B407 /* InsetButton.swift */,
+				7BC68D081CC153020043562A /* RoundedToolbar.swift */,
+				28FDFF0B1C1F725800840F86 /* SeparatorTableCell.swift */,
+				D38A1BEC1A9FA2CA00F6A386 /* SiteTableViewController.swift */,
+				0BB5B2861AC0A2B90052877D /* SnackBar.swift */,
+				E660BDD81BB06521009AC090 /* TabsButton.swift */,
+				E663D5771BB341C4001EF30E /* ToggleButton.swift */,
+				7B844E3C1BBDDB9D00E733A2 /* ChevronView.swift */,
+				E65607601C08B4E200534B02 /* SearchInputView.swift */,
+				E63ED7D71BFCD9990097D08E /* LoginTableViewCell.swift */,
+				C4E3984B1D21F2FD004E89BA /* TabTrayButtonExtensions.swift */,
+				7B3631E91C244FEE00D12AF9 /* Theme.swift */,
+				0BB5B2871AC0A2B90052877D /* Toolbar.swift */,
+				59A68B1F857A8638598A63A0 /* TwoLineCell.swift */,
+				745DAB3E1CDAB09E00D44181 /* HistoryBackButton.swift */,
+				742A56381D80B54A00BDB803 /* PhotonActionSheet.swift */,
+				D88FDA9E1F4E2B9200FD9709 /* PhotonActionSheetProtocol.swift */,
+				D88FDAAE1F4E2BA000FD9709 /* PhotonActionSheetAnimator.swift */,
+				D863C8E31F68BFC20058D95F /* GradientProgressBar.swift */,
+			);
+			path = Widgets;
+			sourceTree = "";
+		};
+		D3972BF01C22412B00035B87 /* Share */ = {
+			isa = PBXGroup;
+			children = (
+				D3972BF11C22412B00035B87 /* ShareExtensionHelper.swift */,
+				D3972BF21C22412B00035B87 /* TitleActivityItemProvider.swift */,
+			);
+			path = Share;
+			sourceTree = "";
+		};
+		D39FA1601A83E0EC00EE869C /* UITests */ = {
+			isa = PBXGroup;
+			children = (
+				C8611CA11F71AEB900C3DE7D /* NoImageModeTests.swift */,
+				0B7C1E941F6097AD006A8869 /* TrackingProtectionTests.swift */,
+				0BEF44621E31165700187C32 /* EarlGrey.swift */,
+				D39FA16F1A83E62600EE869C /* UITests-Bridging-Header.h */,
+				D343DCFD1C446BDB00D7EEE8 /* findPage.html */,
+				E6B4C3D71C68F55C001F97E8 /* JSPrompt.html */,
+				D31EC05E1CC57ED80096F4AB /* localhostLoad.html */,
+				D34E33021BA793C2006135F0 /* loginForm.html */,
+				C8EB60C31F1FB12500F9B5B3 /* navigationDelegate.html */,
+				0BF8F8D91AEFF1C900E90BC2 /* noTitle.html */,
+				0B6FBAB11AC1F830007EC669 /* numberedPage.html */,
+				0B5A93411B1EB572004F47A2 /* readablePage.html */,
+				4F9757391AFA6F37006ECC24 /* readerContent.html */,
+				E6EAC5951B29CB3A00E1DE1E /* scrollablePage.html */,
+				E67422C41CFF2D39009E8373 /* youtube.ico */,
+				D3E171C11A841EAD00AB44CD /* KIFHelper.js */,
+				D38F036F1C06387900175932 /* AuthenticationTests.swift */,
+				28C8B7841C852535006D8318 /* BookmarksPanelTests.swift */,
+				E6B4C4021C68F58B001F97E8 /* BrowserTests.swift */,
+				7B24DC9B1B67B3590005766B /* ClearPrivateDataTests.swift */,
+				D313BE971B2F5096009EF241 /* DomainAutocompleteTests.swift */,
+				D39FA1801A83E84900EE869C /* Global.swift */,
+				4F514FD31ACD8F2C0022D7EA /* HistoryTests.swift */,
+				E6A92ADA1C52A8DA00743291 /* LoginInputTests.swift */,
+				E633E3791C2204BE001FFF6C /* LoginManagerTests.swift */,
+				C8EB60DB1F1FB9AD00F9B5B3 /* NavigationDelegateTests.swift */,
+				0B5A93211B1EB4C8004F47A2 /* ReadingListTest.swift */,
+				D3CFD3631CC5605B0064AB4A /* SecurityTests.swift */,
+				D3C3EB641B6FF44000388E9A /* SessionRestoreTests.swift */,
+				744B0FFD1B4F172E00100422 /* ToolbarTests.swift */,
+				D375A91F1AE71675001B30D5 /* ViewMemoryLeakTests.swift */,
+				D39FA1611A83E0EC00EE869C /* Supporting Files */,
+			);
+			path = UITests;
+			sourceTree = "";
+		};
+		D39FA1611A83E0EC00EE869C /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				D39FA1621A83E0EC00EE869C /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		D3A994941A368691008AD1AC /* Browser */ = {
+			isa = PBXGroup;
+			children = (
+				0B3E7D931B27A7CE00E2E84D /* AboutHomeHandler.swift */,
+				D38F02D01C05127100175932 /* Authenticator.swift */,
+				C40046F91CF8E0B200B08303 /* BackForwardListAnimator.swift */,
+				C400467B1CF4E43E00B08303 /* BackForwardListViewController.swift */,
+				C4EFEECE1CEBB6F2009762A4 /* BackForwardTableViewCell.swift */,
+				E653422C1C5944F90039DD9E /* BrowserPrompts.swift */,
+				E6D8D5E61B569D70009E5A58 /* BrowserTrayAnimators.swift */,
+				C8F457A61F1FD75A000CB895 /* BrowserViewController */,
+				D3A994951A3686BD008AD1AC /* BrowserViewController.swift */,
+				C4F3B2991CFCF93A00966259 /* ButtonToast.swift */,
+				31ADB5D91E58CEC300E87909 /* ClipboardBarDisplayHandler.swift */,
+				D3BA7E0D1B0E934F00153782 /* ContextMenuHelper.swift */,
+				3BE7275C1CCFE8B60099189F /* CustomSearchHandler.swift */,
+				0BA1E02D1B046F1E007675AF /* ErrorPageHelper.swift */,
+				0BF42D361A7C0B8E00889E28 /* FaviconManager.swift */,
+				D3B6923C1B9F9444004B87A4 /* FindInPageBar.swift */,
+				D3B6923E1B9F9A58004B87A4 /* FindInPageHelper.swift */,
+				D02816C11ECA5E2A00240CAA /* HistoryStateHelper.swift */,
+				39DD030C1CD53E1900BC09B3 /* HomePageHelper.swift */,
+				D3C3696D1CC6B78800348A61 /* LocalRequestHelper.swift */,
+				0BB5B30A1AC0AD1F0052877D /* LoginsHelper.swift */,
+				7482205B1DBAB56300EEEA72 /* MailProviders.swift */,
+				744ED5601DBFEB8D00A2B5BE /* MailtoLinkHandler.swift */,
+				A93067E71D0FE18E00C49C6E /* NightModeHelper.swift */,
+				A9072B7F1D07B34100459960 /* NoImageModeHelper.swift */,
+				7BA8D1C61BA037F500C8AE9E /* OpenInHelper.swift */,
+				D3FA77831A43B2CE0010CD32 /* OpenSearch.swift */,
+				74821FC41DB56A2500EEEA72 /* OpenWithSettingsViewController.swift */,
+				E47536EC1C85412C0022CC69 /* PrintHelper.swift */,
+				D31CF65B1CC1959A001D0BD0 /* PrivilegedRequest.swift */,
+				FA6B2AC11D41F02D00429414 /* Punycode.swift */,
+				FA9294001D6584A200AC8D33 /* QRCode.xcassets */,
+				FA9293D31D6580E100AC8D33 /* QRCodeViewController.swift */,
+				E47616C61AB74CA600E7DD25 /* ReaderModeBarView.swift */,
+				D31F95E81AC226CB005C9F3B /* ScreenshotHelper.swift */,
+				D308E4E31A5306F500842685 /* SearchEngines.swift */,
+				D34510871ACF415700EC27F0 /* SearchLoader.swift */,
+				D31A0FC61A65D6D000DC8C7E /* SearchSuggestClient.swift */,
+				59A68CCB63E2A565CB03F832 /* SearchViewController.swift */,
+				74C027441B2A348C001B1E88 /* SessionData.swift */,
+				F35B8D2E1D638408008E3D61 /* SessionRestoreHandler.swift */,
+				F35B8D2C1D6383E9008E3D61 /* SessionRestoreHelper.swift */,
+				3BF56D261CDBBE1F00AC4D75 /* SimpleToast.swift */,
+				E68AEDAF1B18F81A00133D99 /* SwipeAnimator.swift */,
+				D3A994961A3686BD008AD1AC /* Tab.swift */,
+				E4CD9F2C1A6DC91200318571 /* TabLocationView.swift */,
+				D3968F241A38FE8500CEFD3B /* TabManager.swift */,
+				7BA0601A1C0F4DE200DFADB6 /* TabPeekViewController.swift */,
+				DD31E0FA1B382B520077078A /* TabPrintPageRenderer.swift */,
+				E698FFD91B4AADF40001F623 /* TabScrollController.swift */,
+				D314E7F51A37B98700426A76 /* TabToolbar.swift */,
+				D301AAED1A3A55B70078DD1D /* TabTrayController.swift */,
+				3BCE6D3B1CEB9E4D0080928C /* ThirdPartySearchAlerts.swift */,
+				C4E3985F1D22C409004E89BA /* TopTabsLayout.swift */,
+				C45F44681D087DB600CB7EF0 /* TopTabsViewController.swift */,
+				C4E3983C1D21F1E7004E89BA /* TopTabsViews.swift */,
+				D3C744CC1A687D6C004CE85D /* URIFixup.swift */,
+				0BF0DB931A8545800039F300 /* URLBarView.swift */,
+			);
+			path = Browser;
+			sourceTree = "";
+		};
+		E40A18F61EDC73D5006B7F28 /* Entitlements */ = {
+			isa = PBXGroup;
+			children = (
+				E40A18F71EDC73D5006B7F28 /* Fennec.entitlements */,
+				E40A18F81EDC73D5006B7F28 /* FennecEnterprise.entitlements */,
+				E40A18F91EDC73D5006B7F28 /* Firefox.entitlements */,
+				E40A18FA1EDC73D5006B7F28 /* FirefoxBeta.entitlements */,
+			);
+			path = Entitlements;
+			sourceTree = "";
+		};
+		E49943F31AE6879C00BF9DE4 /* Intro */ = {
+			isa = PBXGroup;
+			children = (
+				E49943F41AE6879C00BF9DE4 /* IntroViewController.swift */,
+				E49943F61AE69EDD00BF9DE4 /* Intro.xcassets */,
+			);
+			path = Intro;
+			sourceTree = "";
+		};
+		E4BA8AA01B4B15EF00BC2E95 /* ViewLater */ = {
+			isa = PBXGroup;
+			children = (
+				E4BA8AA11B4B15EF00BC2E95 /* ActionRequestHandler.swift */,
+				E4BA8AA71B4B15EF00BC2E95 /* Info.plist */,
+				7B2142F31E5E03F800CDD3FC /* InfoPlist.strings */,
+				E4BA8AA61B4B15EF00BC2E95 /* ViewLater.xcassets */,
+			);
+			path = ViewLater;
+			sourceTree = "";
+		};
+		E4D567191ADECE2700F1EFE7 /* ReadingList */ = {
+			isa = PBXGroup;
+			children = (
+				E4D567551ADECE8100F1EFE7 /* ReadingListAuthenticator.swift */,
+				E4D567561ADECE8100F1EFE7 /* ReadingListBasicAuthAuthenticator.swift */,
+				E4D567571ADECE8100F1EFE7 /* ReadingListBatchRecordResponse.swift */,
+				E4D567581ADECE8100F1EFE7 /* ReadingListChangeAccumulator.swift */,
+				E4D567591ADECE8100F1EFE7 /* ReadingListClient.swift */,
+				E4D5675A1ADECE8100F1EFE7 /* ReadingListClientMetadata.swift */,
+				E4D5675B1ADECE8100F1EFE7 /* ReadingListClientRecord.swift */,
+				E41F0D9A1ADFFC5600FC7387 /* ReadingListError.swift */,
+				E4D5675D1ADECE8100F1EFE7 /* ReadingListFetchSpec.swift */,
+				E4D5675E1ADECE8100F1EFE7 /* ReadingListOAuthAuthenticator.swift */,
+				E4D5675F1ADECE8100F1EFE7 /* ReadingListRecord.swift */,
+				E4D567601ADECE8100F1EFE7 /* ReadingListRecordResponse.swift */,
+				E4D567611ADECE8100F1EFE7 /* ReadingListRecordsResponse.swift */,
+				E4D567621ADECE8100F1EFE7 /* ReadingListResponse.swift */,
+				E4D567631ADECE8100F1EFE7 /* ReadingListServerMetadata.swift */,
+				E4D567641ADECE8100F1EFE7 /* ReadingListServerRecord.swift */,
+				E41F0D971ADFFB5400FC7387 /* ReadingListService.swift */,
+				E4D567651ADECE8100F1EFE7 /* ReadingListSQLStorage.swift */,
+				E4D567661ADECE8100F1EFE7 /* ReadingListStorage.swift */,
+				E4D567671ADECE8100F1EFE7 /* ReadingListSynchronizer.swift */,
+				E4D567681ADECE8100F1EFE7 /* ReadingListSyncMetadata.swift */,
+				E4D567691ADECE8100F1EFE7 /* ReadingListUtils.swift */,
+				E4D5671A1ADECE2700F1EFE7 /* Supporting Files */,
+			);
+			path = ReadingList;
+			sourceTree = "";
+		};
+		E4D5671A1ADECE2700F1EFE7 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				E4D5671B1ADECE2700F1EFE7 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		E4D567281ADECE2800F1EFE7 /* ReadingListTests */ = {
+			isa = PBXGroup;
+			children = (
+				E4D567951ADECEB800F1EFE7 /* ReadingListClientRecordTestCase.swift */,
+				E4D5679B1ADECEB800F1EFE7 /* ReadingListStorageTestCase.swift */,
+				E4D567291ADECE2800F1EFE7 /* Supporting Files */,
+			);
+			path = ReadingListTests;
+			sourceTree = "";
+		};
+		E4D567291ADECE2800F1EFE7 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				E4D5672A1ADECE2800F1EFE7 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		E4E0BB141AFBC9E4008D6260 /* Shared */ = {
+			isa = PBXGroup;
+			children = (
+				D35210E01CB2F16600FC5DCB /* Strings.swift */,
+				E650756F1E37F7AB006961AC /* Extensions */,
+				E4E0BB161AFBC9E4008D6260 /* Supporting Files */,
+				E65075621E37F7AB006961AC /* Accessibility.swift */,
+				E65075631E37F7AB006961AC /* AppConstants.swift */,
+				E65075641E37F7AB006961AC /* AppInfo.swift */,
+				E65075651E37F7AB006961AC /* AssertionUtils.swift */,
+				E65075661E37F7AB006961AC /* AsyncReducer.swift */,
+				E65075671E37F7AB006961AC /* AuthenticationKeychainInfo.swift */,
+				E65075681E37F7AB006961AC /* Bytes.swift */,
+				E65075691E37F7AB006961AC /* Cancellable.swift */,
+				E650756A1E37F7AB006961AC /* CrashSimulator.h */,
+				E650756B1E37F7AB006961AC /* CrashSimulator.m */,
+				E650756C1E37F7AB006961AC /* DeferredUtils.swift */,
+				E650756D1E37F7AB006961AC /* DeviceInfo.swift */,
+				E650756E1E37F7AB006961AC /* effective_tld_names.dat */,
+				3964B0991EA8F06F00F2EEF4 /* FeatureSwitch.swift */,
+				E65075811E37F7AB006961AC /* FSUtils.h */,
+				E65075821E37F7AB006961AC /* FSUtils.m */,
+				E65075831E37F7AB006961AC /* Functions.swift */,
+				E65075841E37F7AB006961AC /* KeyboardHelper.swift */,
+				E65075851E37F7AB006961AC /* KeychainCache.swift */,
+				E65075861E37F7AB006961AC /* LaunchArguments.swift */,
+				E65075871E37F7AB006961AC /* Loader.swift */,
+				E65075881E37F7AB006961AC /* Logger.swift */,
+				E65075891E37F7AB006961AC /* NotificationConstants.swift */,
+				E650758B1E37F7AB006961AC /* Prefs.swift */,
+				CE7F115E1F3CCEF900ABFC0B /* RemoteDevices.swift */,
+				E650758C1E37F7AB006961AC /* RollingFileLogger.swift */,
+				D02818601EF056C800240CAA /* SentryIntegration.swift */,
+				E650758D1E37F7AB006961AC /* SupportUtils.swift */,
+				E650758E1E37F7AB006961AC /* SystemUtils.swift */,
+				E650758F1E37F7AB006961AC /* TimeConstants.swift */,
+				E65075901E37F7AB006961AC /* UserAgent.swift */,
+				E65075911E37F7AB006961AC /* WeakList.swift */,
+			);
+			path = Shared;
+			sourceTree = "";
+		};
+		E4E0BB161AFBC9E4008D6260 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				E4E0BB151AFBC9E4008D6260 /* Shared-Bridging-Header.h */,
+				E4E0BB171AFBC9E4008D6260 /* Info.plist */,
+			);
+			path = "Supporting Files";
+			sourceTree = "";
+		};
+		E60961841B62B7E100DD640F /* Configuration */ = {
+			isa = PBXGroup;
+			children = (
+				E60961861B62B8A700DD640F /* Fennec.xcconfig */,
+				E6DCC1ED1DCBB6AA00CEC4B7 /* Fennec.enterprise.xcconfig */,
+				E6FCC43C1C40565200DF6113 /* FirefoxBeta.xcconfig */,
+				E60961891B62B8C800DD640F /* Firefox.xcconfig */,
+			);
+			name = Configuration;
+			sourceTree = "";
+		};
+		E63ED8DF1BFD254E0097D08E /* Login Management */ = {
+			isa = PBXGroup;
+			children = (
+				E63ED8E01BFD25580097D08E /* LoginListViewController.swift */,
+				E633E2D91C21EAF8001FFF6C /* LoginDetailViewController.swift */,
+			);
+			path = "Login Management";
+			sourceTree = "";
+		};
+		E65075551E37F714006961AC /* Utils */ = {
+			isa = PBXGroup;
+			children = (
+				E650755A1E37F747006961AC /* Swizzling.h */,
+				E650755B1E37F747006961AC /* Swizzling.m */,
+				E65075561E37F714006961AC /* FaviconFetcher.swift */,
+				E650755D1E37F756006961AC /* Try.h */,
+				E650755E1E37F756006961AC /* Try.m */,
+			);
+			path = Utils;
+			sourceTree = "";
+		};
+		E650756F1E37F7AB006961AC /* Extensions */ = {
+			isa = PBXGroup;
+			children = (
+				E65075711E37F7AB006961AC /* ArrayExtensions.swift */,
+				E683F0C11E93D4E90035D990 /* DictionaryExtensions.swift */,
+				E65075721E37F7AB006961AC /* HashExtensions.swift */,
+				E65075731E37F7AB006961AC /* HexExtensions.swift */,
+				E65075741E37F7AB006961AC /* KeychainWrapperExtensions.swift */,
+				E65075751E37F7AB006961AC /* NSCharacterSetExtensions.swift */,
+				E65075761E37F7AB006961AC /* NSFileManagerExtensions.swift */,
+				E65075771E37F7AB006961AC /* NSMutableAttributedStringExtensions.swift */,
+				E65075781E37F7AB006961AC /* NSScannerExtensions.swift */,
+				E65075791E37F7AB006961AC /* NSStringExtensions.swift */,
+				E650757A1E37F7AB006961AC /* NSURLExtensions.swift */,
+				E650757B1E37F7AB006961AC /* NSURLProtectionSpaceExtensions.swift */,
+				E650757C1E37F7AB006961AC /* SetExtensions.swift */,
+				E650757D1E37F7AB006961AC /* StringExtensions.swift */,
+				E650757E1E37F7AB006961AC /* UIColorExtensions.swift */,
+				E650757F1E37F7AB006961AC /* UIImageExtensions.swift */,
+				7B10AA9E1E3A15020002DD08 /* DataExtensions.swift */,
+				7B10AABA1E3A1F650002DD08 /* URLRequestExtensions.swift */,
+				7B9BF91B1E43472E00CB24F4 /* JSONExtensions.swift */,
+				7B3D9E641E4CBFDB007A50DA /* NSCoderExtensions.swift */,
+				E693F0D81E9D64BD0086DC17 /* OptionalExtensions.swift */,
+			);
+			path = Extensions;
+			sourceTree = "";
+		};
+		E652F6F91BF66A79007FFDD6 /* Delegates */ = {
+			isa = PBXGroup;
+			children = (
+				F84B21E51A0910F600AAB793 /* AppDelegate.swift */,
+				D3BE7B451B054F8600641031 /* TestAppDelegate.swift */,
+			);
+			name = Delegates;
+			sourceTree = "";
+		};
+		E659A6091EB7C1D300D7A6AD /* BuddyBuild */ = {
+			isa = PBXGroup;
+			children = (
+				E659A60A1EB7C1D300D7A6AD /* BuddyBuildSDK.framework */,
+			);
+			name = BuddyBuild;
+			path = ThirdParty/BuddyBuild;
+			sourceTree = "";
+		};
+		E66C5B451BDA81050051AA93 /* Apple */ = {
+			isa = PBXGroup;
+			children = (
+				E66C5B461BDA81050051AA93 /* UIImage+ImageEffects.h */,
+				E66C5B471BDA81050051AA93 /* UIImage+ImageEffects.m */,
+			);
+			name = Apple;
+			path = ThirdParty/Apple;
+			sourceTree = SOURCE_ROOT;
+		};
+		E689C6FF1E0C716F008BAADB /* Entitlements */ = {
+			isa = PBXGroup;
+			children = (
+				E6F738761EB7A97500B50143 /* FirefoxApplication.entitlements */,
+				E6F738751EB7A97100B50143 /* FirefoxBetaApplication.entitlements */,
+				E6F738741EB7A8D300B50143 /* FennecApplication.entitlements */,
+				E62AC15F1E956AFC00843532 /* FennecEnterpriseApplication.entitlements */,
+			);
+			path = Entitlements;
+			sourceTree = "";
+		};
+		E68E7ADF1CAC209000FDCA76 /* PasscodeConfiguration */ = {
+			isa = PBXGroup;
+			children = (
+				E640E8691C73A47C00C5F072 /* PasscodeViews.swift */,
+				E6108FF81C84E91C005D25E8 /* BasePasscodeViewController.swift */,
+				E68E7ACA1CAC1D4500FDCA76 /* PagingPasscodeViewController.swift */,
+				E640E85D1C73A45A00C5F072 /* PasscodeEntryViewController.swift */,
+				E69E06B91C76173D00D0F926 /* RequirePasscodeIntervalViewController.swift */,
+				E68E7AD91CAC207400FDCA76 /* ChangePasscodeViewController.swift */,
+				E68E7ADB1CAC208200FDCA76 /* SetupPasscodeViewController.swift */,
+				E68E7ADD1CAC208A00FDCA76 /* RemovePasscodeViewController.swift */,
+			);
+			name = PasscodeConfiguration;
+			sourceTree = "";
+		};
+		E692E3271C46E62D009D1240 /* AuthenticationManager */ = {
+			isa = PBXGroup;
+			children = (
+				E68E7ADF1CAC209000FDCA76 /* PasscodeConfiguration */,
+				E69E06C81C76198000D0F926 /* AuthenticationManagerConstants.swift */,
+				E65D89171C8647420006EA35 /* AppAuthenticator.swift */,
+				E692E3281C46E62D009D1240 /* AuthenticationSettingsViewController.swift */,
+				E6CF28E61CB43B7900151AB3 /* SensitiveViewController.swift */,
+			);
+			path = AuthenticationManager;
+			sourceTree = "";
+		};
+		E699220D1B94E3EF007C480D /* About */ = {
+			isa = PBXGroup;
+			children = (
+				E69922121B94E3EF007C480D /* Licenses.html */,
+			);
+			path = About;
+			sourceTree = "";
+		};
+		E69DB0761E97DEA9008A67E6 /* SyncTelemetry */ = {
+			isa = PBXGroup;
+			children = (
+				EBA31D7A1F79990C0055463D /* SyncTelemetryEvents.swift */,
+				EBA31D781F7999030055463D /* SyncPingCentre.swift */,
+				E69DB0B81E97E2B5008A67E6 /* Supporting Files */,
+				E69DB0B51E97E2AC008A67E6 /* SyncTelemetry.swift */,
+			);
+			path = SyncTelemetry;
+			sourceTree = "";
+		};
+		E69DB0831E97DEAA008A67E6 /* SyncTelemetryTests */ = {
+			isa = PBXGroup;
+			children = (
+				E69DB0861E97DEAA008A67E6 /* Info.plist */,
+				E610B0181EDC68FC00DC9372 /* EventTests.swift */,
+			);
+			path = SyncTelemetryTests;
+			sourceTree = "";
+		};
+		E69DB0B31E97E0E4008A67E6 /* Telemetry */ = {
+			isa = PBXGroup;
+			children = (
+				EBA31D7C1F79996E0055463D /* SyncTelemetryUtils.swift */,
+				E69DB0C01E97E320008A67E6 /* BookmarkTelemetryPing.swift */,
+			);
+			name = Telemetry;
+			sourceTree = "";
+		};
+		E69DB0B81E97E2B5008A67E6 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				E69DB0771E97DEA9008A67E6 /* SyncTelemetry.h */,
+				E69DB0781E97DEA9008A67E6 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		E69DB0B91E97E301008A67E6 /* Telemetry */ = {
+			isa = PBXGroup;
+			children = (
+				E69DB0BA1E97E301008A67E6 /* ActivityStreamTopics.swift */,
+				EBF47E6F1F7979DF00899189 /* UnifiedTelemetry.swift */,
+			);
+			path = Telemetry;
+			sourceTree = "";
+		};
+		E6F6D6921E9E6AC20012072B /* TestUtils */ = {
+			isa = PBXGroup;
+			children = (
+				E6F6D6A11E9E6AF90012072B /* DeferredTestUtils.swift */,
+			);
+			name = TestUtils;
+			sourceTree = "";
+		};
+		E6F9650D1B2F1CF20034B023 /* SharedTests */ = {
+			isa = PBXGroup;
+			children = (
+				E6F9650E1B2F1CF20034B023 /* Supporting Files */,
+				3B4AA24A1D8B8C4C00A2E008 /* ArrayExtensionTests.swift */,
+				39E65D261CA5B92000C63CE3 /* AsyncReducerTests.swift */,
+				28786E541AB0F5FA009EA9EF /* DeferredTests.swift */,
+				3964B09B1EA8F32C00F2EEF4 /* FeatureSwitchTests.swift */,
+				E4E25CCA1CA99E7400D0F088 /* HexExtensionsTests.swift */,
+				E6F965411B2F25110034B023 /* NSMutableAttributedStringExtensionsTests.swift */,
+				E6F9653B1B2F1D5D0034B023 /* NSURLExtensionsTests.swift */,
+				2FEBABAE1AB3659000DB5728 /* ResultTests.swift */,
+				E61453BD1B750A1700C3F9D7 /* RollingFileLoggerTests.swift */,
+				E4E7EB6C1C4AED5E0094275D /* SupportUtilsTests.swift */,
+				28A6CE891AC082E200C1A2D4 /* UtilsTests.swift */,
+				3BB54B301E68EB2B0021DAC4 /* AuthenticationKeychainInfoTests.swift */,
+			);
+			path = SharedTests;
+			sourceTree = "";
+		};
+		E6F9650E1B2F1CF20034B023 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				E6F9650F1B2F1CF20034B023 /* Info.plist */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		EB2A63241F3B49A7004EF8B0 /* ContentBlocker */ = {
+			isa = PBXGroup;
+			children = (
+				EB2A63251F3B49A7004EF8B0 /* ContentBlockerHelper.swift */,
+				C88601B71F4228AD00BBDE4F /* ContentBlockerSettingViewController.swift */,
+				EB2A63381F3B5135004EF8B0 /* disconnect-advertising.json */,
+				EB2A63361F3B5134004EF8B0 /* disconnect-analytics.json */,
+				EB2A63371F3B5135004EF8B0 /* disconnect-content.json */,
+				EB2A63391F3B5135004EF8B0 /* disconnect-social.json */,
+			);
+			path = ContentBlocker;
+			sourceTree = "";
+		};
+		F84B21B51A090F8100AAB793 = {
+			isa = PBXGroup;
+			children = (
+				E6C191D41E38F7B7000A213B /* Cartfile */,
+				E6C191D51E38F7B7000A213B /* Cartfile.resolved */,
+				2FA435FC1ABB83B4008031D1 /* Account */,
+				2FA4360B1ABB83B4008031D1 /* AccountTests */,
+				F84B21C01A090F8100AAB793 /* Client */,
+				F84B21D61A090F8100AAB793 /* ClientTests */,
+				F8708D1E1A0970990051AB07 /* Extensions */,
+				7B604FC11C496005006EEEC3 /* Frameworks */,
+				F84B21BF1A090F8100AAB793 /* Products */,
+				D34DC84C1A16C40C00D49B7B /* Providers */,
+				39F99FC71E3A6DB700F353B4 /* Push */,
+				39B0646D1E7ADA4B000BE173 /* PushTests */,
+				E4D567191ADECE2700F1EFE7 /* ReadingList */,
+				E4D567281ADECE2800F1EFE7 /* ReadingListTests */,
+				E4E0BB141AFBC9E4008D6260 /* Shared */,
+				E6F9650D1B2F1CF20034B023 /* SharedTests */,
+				7B3632E71C29879300D12AF9 /* Snapshot */,
+				2FCAE21B1ABB51F800877008 /* Storage */,
+				3B43E3D11D95C48D00BBA9DB /* StoragePerfTests */,
+				2FCAE22A1ABB51F800877008 /* StorageTests */,
+				28CE83B91A1D1D3200576538 /* Sync */,
+				28C077911A3B05C200834FE5 /* SyncTests */,
+				E6F6D6921E9E6AC20012072B /* TestUtils */,
+				E69DB0761E97DEA9008A67E6 /* SyncTelemetry */,
+				E69DB0831E97DEAA008A67E6 /* SyncTelemetryTests */,
+				28CE83EF1A1D246900576538 /* Third-Party Source */,
+				D39FA1601A83E0EC00EE869C /* UITests */,
+				3BFE4B081D342FB900DDF53F /* XCUITests */,
+			);
+			sourceTree = "";
+		};
+		F84B21BF1A090F8100AAB793 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				F84B21BE1A090F8100AAB793 /* Client.app */,
+				F84B21D31A090F8100AAB793 /* ClientTests.xctest */,
+				F84B22491A0920C600AAB793 /* ShareTo.appex */,
+				F84B225C1A09210A00AAB793 /* SendTo.appex */,
+				D39FA15F1A83E0EC00EE869C /* UITests.xctest */,
+				288A2D861AB8B3260023ABC3 /* Shared.framework */,
+				2FCAE21A1ABB51F800877008 /* Storage.framework */,
+				2FCAE2241ABB51F800877008 /* StorageTests.xctest */,
+				2FA435FB1ABB83B4008031D1 /* Account.framework */,
+				2FA436051ABB83B4008031D1 /* AccountTests.xctest */,
+				2827315E1ABC9BE600AA1954 /* Sync.framework */,
+				282731681ABC9BE700AA1954 /* SyncTests.xctest */,
+				E4D567181ADECE2700F1EFE7 /* ReadingList.framework */,
+				E4D567221ADECE2700F1EFE7 /* ReadingListTests.xctest */,
+				E6F9650C1B2F1CF20034B023 /* SharedTests.xctest */,
+				E4BA8A2B1B4B0A1600BC2E95 /* ViewLater.appex */,
+				7BEB644D1C7345600092C02E /* L10nSnapshotTests.xctest */,
+				7BEB645A1C7345990092C02E /* MarketingUITests.xctest */,
+				3905274A1C874D35007E0BB7 /* Today.appex */,
+				3BFE4B071D342FB800DDF53F /* XCUITests.xctest */,
+				3B43E3D01D95C48D00BBA9DB /* StoragePerfTests.xctest */,
+				E69DB0751E97DEA9008A67E6 /* SyncTelemetry.framework */,
+				E69DB07D1E97DEA9008A67E6 /* SyncTelemetryTests.xctest */,
+				397848DB1ED86605004C0C0B /* NotificationService.appex */,
+			);
+			name = Products;
+			sourceTree = "";
+		};
+		F84B21C01A090F8100AAB793 /* Client */ = {
+			isa = PBXGroup;
+			children = (
+				7B2142FC1E5E055000CDD3FC /* InfoPlist.strings */,
+				F84B22431A09165600AAB793 /* Info.plist */,
+				F84B21EB1A0910F600AAB793 /* Assets */,
+				F84B21E41A0910F600AAB793 /* Application */,
+				E60961841B62B7E100DD640F /* Configuration */,
+				E689C6FF1E0C716F008BAADB /* Entitlements */,
+				28EADE5C1AFC3A6D007FB2FB /* Extensions */,
+				F84B21F11A0910F600AAB793 /* Frontend */,
+				39A359BD1BFCCE7B006B9E87 /* Helpers */,
+				E69DB0B91E97E301008A67E6 /* Telemetry */,
+				E65075551E37F714006961AC /* Utils */,
+				74821FFD1DB6D3AC00EEEA72 /* MailSchemes.plist */,
+			);
+			path = Client;
+			sourceTree = "";
+		};
+		F84B21D61A090F8100AAB793 /* ClientTests */ = {
+			isa = PBXGroup;
+			children = (
+				8DCD3BCC1ED5B7FA00446D38 /* FxADeepLinkingTests.swift */,
+				3B6F40171DC7849C00656CC6 /* ActivityStreamTests.swift */,
+				E696FE501C47F86E00EC007C /* AuthenticatorTests.swift */,
+				F84B21D91A090F8100AAB793 /* ClientTests.swift */,
+				3B39EDB91E16E18900EF029F /* CustomSearchEnginesTest.swift */,
+				D3D488581ABB54CD00A93597 /* FileAccessorTests.swift */,
+				3943A81C1E9807C700D4F6DC /* FxAPushMessageTest.swift */,
+				281B2BE91ADF4D90002917DC /* MockProfile.swift */,
+				E683F0A51E92E0820035D990 /* MockableHistory.swift */,
+				E61D11671EAF8F43008A305B /* PanelDataObserversTests.swift */,
+				E6C70E811E28314700F8DB57 /* PingCentreTests.swift */,
+				3B61CD581F2A750800D38DE1 /* PocketFeedTests.swift */,
+				2FDB10921A9FBEC5006CF312 /* PrefsTests.swift */,
+				0BA896491A250E6500C1010C /* ProfileTest.swift */,
+				03CCC9171AF05E7300DBF30D /* RelativeDatesTests.swift */,
+				28D52E081BCDF44100187A1D /* ResetTests.swift */,
+				2F697F7D1A9FD22D009E03AE /* SearchEnginesTests.swift */,
+				D3FA777A1A43B2990010CD32 /* SearchTests.swift */,
+				2F13E79A1AC0C02700D75081 /* StringExtensionsTests.swift */,
+				E60D03291D5118DB002FE3F6 /* SyncStatusResolverTests.swift */,
+				7BBFEE731BB405D900A305AA /* TabManagerTests.swift */,
+				0BA8964A1A250E6500C1010C /* TestBookmarks.swift */,
+				0BF42D4E1A7CD09600889E28 /* TestFavicons.swift */,
+				2F44FA1A1A9D426A00FD20CC /* TestHashExtensions.swift */,
+				4A59BF410BBD9B3BE71F4C7C /* TestHistory.swift */,
+				A83E5B1C1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift */,
+				3BFCBF1F1E04B1C50070C042 /* UIImageViewExtensionsTests.swift */,
+				E4CD9F1C1A6D9C2800318571 /* WebServerTests.swift */,
+				D3BA41671BD82F2200DA5457 /* XCTestCaseExtensions.swift */,
+				F84B21D71A090F8100AAB793 /* Supporting Files */,
+				554867221DC3935A00183DAA /* HomePageTests.swift */,
+				39236E711FCC600200A38F1B /* TabEventHandlerTests.swift */,
+			);
+			path = ClientTests;
+			sourceTree = "";
+		};
+		F84B21D71A090F8100AAB793 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				A83E5B181C1DA8BF0026D912 /* image.gif */,
+				F84B21D81A090F8100AAB793 /* Info.plist */,
+				A83E5B191C1DA8BF0026D912 /* image.png */,
+				3B61CD621F2A769D00D38DE1 /* pocketglobalfeed.json */,
+			);
+			name = "Supporting Files";
+			sourceTree = "";
+		};
+		F84B21E41A0910F600AAB793 /* Application */ = {
+			isa = PBXGroup;
+			children = (
+				19DE1F661EC13B6400428B8C /* LeanplumIntegration.swift */,
+				E652F6F91BF66A79007FFDD6 /* Delegates */,
+				28CE83E81A1D206D00576538 /* Client-Bridging-Header.h */,
+				E40FAB0B1A7ABB77009CB80D /* WebServer.swift */,
+				E4D6BEB81A0930EC00F538BD /* LaunchScreen.xib */,
+				D3BE7B251B054D4400641031 /* main.swift */,
+				E4B3348B1BC01D8F004E2BFF /* AdjustIntegration.swift */,
+				E6327A631BF6438E008D12E0 /* DebugSettingsBundleOptions.swift */,
+				E6639F171BF11E17002D0853 /* Settings.bundle */,
+				7BEFC67F1BFF68C30059C952 /* QuickActions.swift */,
+			);
+			path = Application;
+			sourceTree = "";
+		};
+		F84B21EB1A0910F600AAB793 /* Assets */ = {
+			isa = PBXGroup;
+			children = (
+				3BC659581E5BA505006D560F /* top_sites.json */,
+				3BC659481E5BA4AE006D560F /* TopSites */,
+				D30684F01C84F12A002D8D82 /* SearchPlugins */,
+				D308EE551CBF0BF5006843F2 /* CertError.css */,
+				0BA1E02F1B051A07007675AF /* NetError.css */,
+				D38A1EDF1CB458EC0080C842 /* CertError.html */,
+				0BA1E00D1B03FB0B007675AF /* NetError.html */,
+				D3BA7E0B1B0E902A00153782 /* ContextMenu.js */,
+				0BF42D381A7C0E8900889E28 /* Favicons.js */,
+				D3B692401B9F9CC8004B87A4 /* FindInPage.js */,
+				E689C6F71E0C6E72008BAADB /* FxASignIn.js */,
+				D02816D11ECA60DF00240CAA /* HistoryStateHelper.js */,
+				0BDA568A1B26B1BE008C9B96 /* LoginsHelper.js */,
+				A91528D11D0E637600CD0425 /* NoImageModeHelper.js */,
+				A93067D81D0FE15E00C49C6E /* NightModeHelper.js */,
+				3BE7274D1CCFE8A30099189F /* CustomSearchHelper.js */,
+				E47536FB1C85415E0022CC69 /* PrintHelper.js */,
+				39A35AEC1C0662A3006B9E87 /* SpotlightHelper.js */,
+				D37524861C6E8B5A00A5F6C2 /* topdomains.txt */,
+				F84B21EF1A0910F600AAB793 /* Images.xcassets */,
+				E699220D1B94E3EF007C480D /* About */,
+				F84B22391A0914A300AAB793 /* Fonts */,
+				F35B8D2A1D6380EA008E3D61 /* SessionRestore.html */,
+			);
+			path = Assets;
+			sourceTree = "";
+		};
+		F84B21F11A0910F600AAB793 /* Frontend */ = {
+			isa = PBXGroup;
+			children = (
+				EB2A63241F3B49A7004EF8B0 /* ContentBlocker */,
+				D331DFC91CB6E9EE009B5DA2 /* OldStrings.swift */,
+				2816EFFF1B33E05400522243 /* UIConstants.swift */,
+				392ED7D51D0AEEEE009D9B62 /* Accessors */,
+				7BEDD28C1CB7CB12004B51F3 /* Animators */,
+				E692E3271C46E62D009D1240 /* AuthenticationManager */,
+				D3A994941A368691008AD1AC /* Browser */,
+				7B0B1B9C1C1B69F500DF4AB5 /* Extensions */,
+				F84B22211A09122500AAB793 /* Home */,
+				E49943F31AE6879C00BF9DE4 /* Intro */,
+				E63ED8DF1BFD254E0097D08E /* Login Management */,
+				3B4262D31E538EB100CA681C /* Metadata Parsing */,
+				7BC7B4571C903A6A0046E9D2 /* Menu */,
+				F84B21F51A0910F600AAB793 /* Reader */,
+				2F44FC551A9E83E200FD20CC /* Settings */,
+				D3972BF01C22412B00035B87 /* Share */,
+				D38A1BEB1A9FA2CA00F6A386 /* Widgets */,
+			);
+			path = Frontend;
+			sourceTree = "";
+		};
+		F84B21F51A0910F600AAB793 /* Reader */ = {
+			isa = PBXGroup;
+			children = (
+				E49BFF581B1F48C3009368CC /* Readability.js */,
+				E4CD9E901A6897FB00318571 /* ReaderMode.swift */,
+				E4A960051ABB9C450069AD6F /* ReaderModeUtils.swift */,
+				E4B423BD1AB9FE6A007E66C8 /* ReaderModeCache.swift */,
+				E4B423DC1ABA0318007E66C8 /* ReaderModeHandlers.swift */,
+				E4CD9E991A68980A00318571 /* ReaderMode.js */,
+				E4CD9F531A71506400318571 /* Reader.html */,
+				E4CD9F5A1A71506C00318571 /* Reader.css */,
+				E4CD9F6C1A77DD2800318571 /* ReaderModeStyleViewController.swift */,
+				E4A961171AC041C40069AD6F /* ReadabilityService.swift */,
+				E4A961331AC051360069AD6F /* ReadabilityTabHelper.swift */,
+				E4A961351AC052DE0069AD6F /* ReadabilityTabHelper.js */,
+				E4A961371AC06FA50069AD6F /* ReaderViewLoading.html */,
+				E4C358541AF144BA00299F7E /* FSReadingList.m */,
+				E4C358561AF1467A00299F7E /* FSReadingList.h */,
+			);
+			path = Reader;
+			sourceTree = "";
+		};
+		F84B22211A09122500AAB793 /* Home */ = {
+			isa = PBXGroup;
+			children = (
+				F84B22261A09127C00AAB793 /* Home.xcassets */,
+				3BB50E1F1D627539004B33DF /* ActivityStreamPanel.swift */,
+				3BB50E101D6274CD004B33DF /* ActivityStreamTopSitesCell.swift */,
+				74821F8D1DAD8F1300EEEA72 /* ActivityStreamHighlightCell.swift */,
+				F84B22221A09122500AAB793 /* HomePanelViewController.swift */,
+				D30B101D1AA7F9C600C01CA3 /* HomePanels.swift */,
+				59A6825233896FC846499289 /* HistoryPanel.swift */,
+				59A6839879D615FC1C0D71CE /* BookmarksPanel.swift */,
+				59A685F4EAD19EDEC854BCA4 /* ReaderPanel.swift */,
+				2FDE87FD1ABB3817005317B1 /* RemoteTabsPanel.swift */,
+				745DAB2F1CDAAFAA00D44181 /* RecentlyClosedTabsPanel.swift */,
+			);
+			path = Home;
+			sourceTree = "";
+		};
+		F84B22391A0914A300AAB793 /* Fonts */ = {
+			isa = PBXGroup;
+			children = (
+				E4B7B73A1A793CF20022C5E0 /* CharisSILB.ttf */,
+				E4B7B73B1A793CF20022C5E0 /* CharisSILBI.ttf */,
+				E4B7B73C1A793CF20022C5E0 /* CharisSILI.ttf */,
+				E4B7B73D1A793CF20022C5E0 /* CharisSILR.ttf */,
+				E4B7B7411A793CF20022C5E0 /* FiraSans-Bold.ttf */,
+				E4B7B7421A793CF20022C5E0 /* FiraSans-BoldItalic.ttf */,
+				E4424B3B1AC71FB400F44C38 /* FiraSans-Book.ttf */,
+				E4B7B7511A793CF20022C5E0 /* FiraSans-Italic.ttf */,
+				E4B7B7521A793CF20022C5E0 /* FiraSans-Light.ttf */,
+				E4ECCDAD1AB131770005E717 /* FiraSans-Medium.ttf */,
+				E4B7B7561A793CF20022C5E0 /* FiraSans-Regular.ttf */,
+				E4B7B7571A793CF20022C5E0 /* FiraSans-SemiBold.ttf */,
+				E4B7B75F1A793CF20022C5E0 /* FiraSans-UltraLight.ttf */,
+			);
+			path = Fonts;
+			sourceTree = "";
+		};
+		F8708D1E1A0970990051AB07 /* Extensions */ = {
+			isa = PBXGroup;
+			children = (
+				E40A18F61EDC73D5006B7F28 /* Entitlements */,
+				397848DC1ED86605004C0C0B /* NotificationService */,
+				3905274D1C874D35007E0BB7 /* Today */,
+				E4BA8AA01B4B15EF00BC2E95 /* ViewLater */,
+				F8708D1F1A0970990051AB07 /* SendTo */,
+				F8708D241A0970990051AB07 /* ShareTo */,
+			);
+			path = Extensions;
+			sourceTree = "";
+		};
+		F8708D1F1A0970990051AB07 /* SendTo */ = {
+			isa = PBXGroup;
+			children = (
+				F8708D201A0970990051AB07 /* ActionViewController.swift */,
+				E4F21AA51A13C4A300B0FAAA /* Images.xcassets */,
+				7B2142F61E5E040200CDD3FC /* InfoPlist.strings */,
+				F8708D211A0970990051AB07 /* Info.plist */,
+				F8708D221A0970990051AB07 /* MainInterface.storyboard */,
+			);
+			path = SendTo;
+			sourceTree = "";
+		};
+		F8708D241A0970990051AB07 /* ShareTo */ = {
+			isa = PBXGroup;
+			children = (
+				F8708D251A0970990051AB07 /* Images.xcassets */,
+				F8708D261A0970990051AB07 /* Info.plist */,
+				E41A7D4A1A1BE04500245963 /* InitialViewController.swift */,
+				F8708D291A0970990051AB07 /* ShareViewController.swift */,
+			);
+			path = ShareTo;
+			sourceTree = "";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		2827315B1ABC9BE600AA1954 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				282731631ABC9BE600AA1954 /* Sync-Bridging-Header.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		288A2D831AB8B3260023ABC3 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E650759A1E37F7AB006961AC /* CrashSimulator.h in Headers */,
+				E65075B01E37F7AB006961AC /* FSUtils.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FA435F81ABB83B4008031D1 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2F14E13A1ABB890800FF98DB /* Account-Bridging-Header.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FCAE2171ABB51F800877008 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2FCAE33E1ABB5F1800877008 /* Storage-Bridging-Header.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4D567151ADECE2700F1EFE7 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E69DB0721E97DEA9008A67E6 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E69DB0871E97DEAA008A67E6 /* SyncTelemetry.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		2827315D1ABC9BE600AA1954 /* Sync */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 282731971ABC9BE800AA1954 /* Build configuration list for PBXNativeTarget "Sync" */;
+			buildPhases = (
+				282731591ABC9BE600AA1954 /* Sources */,
+				2827315A1ABC9BE600AA1954 /* Frameworks */,
+				2827315B1ABC9BE600AA1954 /* Headers */,
+				2827315C1ABC9BE600AA1954 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				2F77F6B91ABCAF0700484F3A /* PBXTargetDependency */,
+				2F77F69D1ABCAEFE00484F3A /* PBXTargetDependency */,
+				2F11EE501ABCAE910083902D /* PBXTargetDependency */,
+				E4EE05B01BA3A0A10021B3A7 /* PBXTargetDependency */,
+				E69DB0A71E97DEF6008A67E6 /* PBXTargetDependency */,
+			);
+			name = Sync;
+			productName = Sync;
+			productReference = 2827315E1ABC9BE600AA1954 /* Sync.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		282731671ABC9BE700AA1954 /* SyncTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 282731981ABC9BE800AA1954 /* Build configuration list for PBXNativeTarget "SyncTests" */;
+			buildPhases = (
+				282731641ABC9BE700AA1954 /* Sources */,
+				282731651ABC9BE700AA1954 /* Frameworks */,
+				282731661ABC9BE700AA1954 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				E60222E61C6E5A770061C436 /* PBXTargetDependency */,
+				2F67C5281BB0D33000E7B73A /* PBXTargetDependency */,
+				28ECD9B11BA1F07000D829DA /* PBXTargetDependency */,
+				2827316B1ABC9BE700AA1954 /* PBXTargetDependency */,
+			);
+			name = SyncTests;
+			productName = SyncTests;
+			productReference = 282731681ABC9BE700AA1954 /* SyncTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		288A2D851AB8B3260023ABC3 /* Shared */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 288A2D9F1AB8B3260023ABC3 /* Build configuration list for PBXNativeTarget "Shared" */;
+			buildPhases = (
+				288A2D811AB8B3260023ABC3 /* Sources */,
+				288A2D821AB8B3260023ABC3 /* Frameworks */,
+				288A2D831AB8B3260023ABC3 /* Headers */,
+				288A2D841AB8B3260023ABC3 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Shared;
+			productName = Shared;
+			productReference = 288A2D861AB8B3260023ABC3 /* Shared.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		2FA435FA1ABB83B4008031D1 /* Account */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 2FA436141ABB83B4008031D1 /* Build configuration list for PBXNativeTarget "Account" */;
+			buildPhases = (
+				2FA435F61ABB83B4008031D1 /* Sources */,
+				2FA435F71ABB83B4008031D1 /* Frameworks */,
+				2FA435F81ABB83B4008031D1 /* Headers */,
+				2FA435F91ABB83B4008031D1 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				2FA436441ABB84CB008031D1 /* PBXTargetDependency */,
+				2FA4361D1ABB83DD008031D1 /* PBXTargetDependency */,
+			);
+			name = Account;
+			productName = Account;
+			productReference = 2FA435FB1ABB83B4008031D1 /* Account.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		2FA436041ABB83B4008031D1 /* AccountTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 2FA436181ABB83B4008031D1 /* Build configuration list for PBXNativeTarget "AccountTests" */;
+			buildPhases = (
+				2FA436011ABB83B4008031D1 /* Sources */,
+				2FA436021ABB83B4008031D1 /* Frameworks */,
+				2FA436031ABB83B4008031D1 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				2F14E1341ABB88CF00FF98DB /* PBXTargetDependency */,
+				2F14E1181ABB88CB00FF98DB /* PBXTargetDependency */,
+			);
+			name = AccountTests;
+			productName = AccountTests;
+			productReference = 2FA436051ABB83B4008031D1 /* AccountTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		2FCAE2191ABB51F800877008 /* Storage */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 2FCAE2331ABB51F900877008 /* Build configuration list for PBXNativeTarget "Storage" */;
+			buildPhases = (
+				2FCAE2151ABB51F800877008 /* Sources */,
+				2FCAE2161ABB51F800877008 /* Frameworks */,
+				2FCAE2171ABB51F800877008 /* Headers */,
+				2FCAE2181ABB51F800877008 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				0B742CCE1B32493800EE9264 /* PBXTargetDependency */,
+				2FCAE23C1ABB520700877008 /* PBXTargetDependency */,
+			);
+			name = Storage;
+			productName = Storage;
+			productReference = 2FCAE21A1ABB51F800877008 /* Storage.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		2FCAE2231ABB51F800877008 /* StorageTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 2FCAE2371ABB51F900877008 /* Build configuration list for PBXNativeTarget "StorageTests" */;
+			buildPhases = (
+				2FCAE2201ABB51F800877008 /* Sources */,
+				2FCAE2211ABB51F800877008 /* Frameworks */,
+				2FCAE2221ABB51F800877008 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				2FCAE2271ABB51F800877008 /* PBXTargetDependency */,
+				2FCAE2291ABB51F800877008 /* PBXTargetDependency */,
+			);
+			name = StorageTests;
+			productName = StorageTests;
+			productReference = 2FCAE2241ABB51F800877008 /* StorageTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		390527491C874D35007E0BB7 /* Today */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 39409A521C90E68300DAE683 /* Build configuration list for PBXNativeTarget "Today" */;
+			buildPhases = (
+				390527461C874D35007E0BB7 /* Sources */,
+				390527471C874D35007E0BB7 /* Frameworks */,
+				390527481C874D35007E0BB7 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				D09A0CED1FAA2C4C009A0273 /* PBXTargetDependency */,
+			);
+			name = Today;
+			productName = Today;
+			productReference = 3905274A1C874D35007E0BB7 /* Today.appex */;
+			productType = "com.apple.product-type.app-extension";
+		};
+		397848DA1ED86605004C0C0B /* NotificationService */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 397848F51ED86605004C0C0B /* Build configuration list for PBXNativeTarget "NotificationService" */;
+			buildPhases = (
+				397848D71ED86605004C0C0B /* Sources */,
+				397848D81ED86605004C0C0B /* Frameworks */,
+				397848D91ED86605004C0C0B /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				D0EA58131FA836CA00D03ED1 /* PBXTargetDependency */,
+				D0EA58151FA836CE00D03ED1 /* PBXTargetDependency */,
+				D0EA58171FA836D200D03ED1 /* PBXTargetDependency */,
+			);
+			name = NotificationService;
+			productName = NotificationService;
+			productReference = 397848DB1ED86605004C0C0B /* NotificationService.appex */;
+			productType = "com.apple.product-type.app-extension";
+		};
+		3B43E3CF1D95C48D00BBA9DB /* StoragePerfTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 3B43E3E91D95C48E00BBA9DB /* Build configuration list for PBXNativeTarget "StoragePerfTests" */;
+			buildPhases = (
+				3B43E3CC1D95C48D00BBA9DB /* Sources */,
+				3B43E3CD1D95C48D00BBA9DB /* Frameworks */,
+				3B43E3CE1D95C48D00BBA9DB /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				3B43E3D61D95C48D00BBA9DB /* PBXTargetDependency */,
+			);
+			name = StoragePerfTests;
+			productName = StoragePerfTests;
+			productReference = 3B43E3D01D95C48D00BBA9DB /* StoragePerfTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		3BFE4B061D342FB800DDF53F /* XCUITests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 3BFE4B201D342FB900DDF53F /* Build configuration list for PBXNativeTarget "XCUITests" */;
+			buildPhases = (
+				E6EC6EFC1E5354E20067985D /* Copy Carthage Frameworks */,
+				3BFE4B031D342FB800DDF53F /* Sources */,
+				3BFE4B041D342FB800DDF53F /* Frameworks */,
+				3BFE4B051D342FB800DDF53F /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				3BFE4B0D1D342FB900DDF53F /* PBXTargetDependency */,
+			);
+			name = XCUITests;
+			productName = XCUITests;
+			productReference = 3BFE4B071D342FB800DDF53F /* XCUITests.xctest */;
+			productType = "com.apple.product-type.bundle.ui-testing";
+		};
+		7BEB64401C7345600092C02E /* L10nSnapshotTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = E60138631C89EAE700DF9756 /* Build configuration list for PBXNativeTarget "L10nSnapshotTests" */;
+			buildPhases = (
+				7BEB64431C7345600092C02E /* Sources */,
+				7BEB64461C7345600092C02E /* Frameworks */,
+				7BEB64471C7345600092C02E /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				7BEB64411C7345600092C02E /* PBXTargetDependency */,
+			);
+			name = L10nSnapshotTests;
+			productName = L10nSnapshotTests;
+			productReference = 7BEB644D1C7345600092C02E /* L10nSnapshotTests.xctest */;
+			productType = "com.apple.product-type.bundle.ui-testing";
+		};
+		7BEB644F1C7345990092C02E /* MarketingUITests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = E60138641C89EAE700DF9756 /* Build configuration list for PBXNativeTarget "MarketingUITests" */;
+			buildPhases = (
+				7BEB64501C7345990092C02E /* Sources */,
+				7BEB64531C7345990092C02E /* Frameworks */,
+				7BEB64541C7345990092C02E /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				7BEB645D1C7346100092C02E /* PBXTargetDependency */,
+			);
+			name = MarketingUITests;
+			productName = MarketingUITests;
+			productReference = 7BEB645A1C7345990092C02E /* MarketingUITests.xctest */;
+			productType = "com.apple.product-type.bundle.ui-testing";
+		};
+		D39FA15E1A83E0EC00EE869C /* UITests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = D39FA1671A83E0EC00EE869C /* Build configuration list for PBXNativeTarget "UITests" */;
+			buildPhases = (
+				D39FA15B1A83E0EC00EE869C /* Sources */,
+				D39FA15C1A83E0EC00EE869C /* Frameworks */,
+				D39FA15D1A83E0EC00EE869C /* Resources */,
+				E6ECF2371C974E0600B0DC93 /* CopyFiles */,
+				0B21E8011E26C5D3000C8779 /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				D39FA1661A83E0EC00EE869C /* PBXTargetDependency */,
+			);
+			name = UITests;
+			productName = UITests;
+			productReference = D39FA15F1A83E0EC00EE869C /* UITests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		E4BA8A2A1B4B0A1600BC2E95 /* ViewLater */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = E4BA8A581B4B0A1700BC2E95 /* Build configuration list for PBXNativeTarget "ViewLater" */;
+			buildPhases = (
+				E4BA8A271B4B0A1600BC2E95 /* Sources */,
+				E4BA8A281B4B0A1600BC2E95 /* Frameworks */,
+				E4BA8A291B4B0A1600BC2E95 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				D09A0CEB1FAA2C38009A0273 /* PBXTargetDependency */,
+				D09A0CE51FAA2C18009A0273 /* PBXTargetDependency */,
+				D09A0CE71FAA2C1B009A0273 /* PBXTargetDependency */,
+				D09A0CE91FAA2C1E009A0273 /* PBXTargetDependency */,
+			);
+			name = ViewLater;
+			productName = ViewLater;
+			productReference = E4BA8A2B1B4B0A1600BC2E95 /* ViewLater.appex */;
+			productType = "com.apple.product-type.app-extension";
+		};
+		E4D567171ADECE2700F1EFE7 /* ReadingList */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = E4D567531ADECE2900F1EFE7 /* Build configuration list for PBXNativeTarget "ReadingList" */;
+			buildPhases = (
+				E4D567131ADECE2700F1EFE7 /* Sources */,
+				E4D567141ADECE2700F1EFE7 /* Frameworks */,
+				E4D567151ADECE2700F1EFE7 /* Headers */,
+				E4D567161ADECE2700F1EFE7 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				D09A0CDF1FAA2577009A0273 /* PBXTargetDependency */,
+				7B9A62F91C400303005C83DC /* PBXTargetDependency */,
+			);
+			name = ReadingList;
+			productName = ReadingList;
+			productReference = E4D567181ADECE2700F1EFE7 /* ReadingList.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		E4D567211ADECE2700F1EFE7 /* ReadingListTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = E4D567541ADECE2900F1EFE7 /* Build configuration list for PBXNativeTarget "ReadingListTests" */;
+			buildPhases = (
+				E4D5671E1ADECE2700F1EFE7 /* Sources */,
+				E4D5671F1ADECE2700F1EFE7 /* Frameworks */,
+				E4D567201ADECE2700F1EFE7 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				7B10AAF01E3A58C80002DD08 /* PBXTargetDependency */,
+				E4D567251ADECE2700F1EFE7 /* PBXTargetDependency */,
+			);
+			name = ReadingListTests;
+			productName = ReadingListTests;
+			productReference = E4D567221ADECE2700F1EFE7 /* ReadingListTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		E69DB0741E97DEA9008A67E6 /* SyncTelemetry */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = E69DB08C1E97DEAA008A67E6 /* Build configuration list for PBXNativeTarget "SyncTelemetry" */;
+			buildPhases = (
+				E69DB0701E97DEA9008A67E6 /* Sources */,
+				E69DB0711E97DEA9008A67E6 /* Frameworks */,
+				E69DB0721E97DEA9008A67E6 /* Headers */,
+				E69DB0731E97DEA9008A67E6 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				D09A0CE11FAA25C5009A0273 /* PBXTargetDependency */,
+			);
+			name = SyncTelemetry;
+			productName = SyncTelemetry;
+			productReference = E69DB0751E97DEA9008A67E6 /* SyncTelemetry.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		E69DB07C1E97DEA9008A67E6 /* SyncTelemetryTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = E69DB0921E97DEAA008A67E6 /* Build configuration list for PBXNativeTarget "SyncTelemetryTests" */;
+			buildPhases = (
+				E69DB0791E97DEA9008A67E6 /* Sources */,
+				E69DB07A1E97DEA9008A67E6 /* Frameworks */,
+				E69DB07B1E97DEA9008A67E6 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				E69DB0801E97DEAA008A67E6 /* PBXTargetDependency */,
+				E69DB0821E97DEAA008A67E6 /* PBXTargetDependency */,
+			);
+			name = SyncTelemetryTests;
+			productName = SyncTelemetryTests;
+			productReference = E69DB07D1E97DEA9008A67E6 /* SyncTelemetryTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		E6F9650B1B2F1CF20034B023 /* SharedTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = E6F965381B2F1CF20034B023 /* Build configuration list for PBXNativeTarget "SharedTests" */;
+			buildPhases = (
+				E6F965081B2F1CF20034B023 /* Sources */,
+				E6F965091B2F1CF20034B023 /* Frameworks */,
+				E6F9650A1B2F1CF20034B023 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				E6F965141B2F1CF20034B023 /* PBXTargetDependency */,
+				E6F9653A1B2F1D330034B023 /* PBXTargetDependency */,
+			);
+			name = SharedTests;
+			productName = SharedTests;
+			productReference = E6F9650C1B2F1CF20034B023 /* SharedTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		F84B21BD1A090F8100AAB793 /* Client */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = F84B21DD1A090F8100AAB793 /* Build configuration list for PBXNativeTarget "Client" */;
+			buildPhases = (
+				7B604F8F1C494AAA006EEEC3 /* Copy Carthage Dependencies */,
+				F84B21BA1A090F8100AAB793 /* Sources */,
+				F84B21BC1A090F8100AAB793 /* Resources */,
+				28CE83DE1A1D1E7C00576538 /* Frameworks */,
+				F84B22531A0920C600AAB793 /* Embed App Extensions */,
+				E6639F191BF11E3A002D0853 /* Conditionally Add Settings Bundle */,
+				E6B09CD31C74EEDB00C63FA1 /* Copy Frameworks */,
+				E4DAA6741F63027B00FA53AF /* Run Script */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				E4A888191A95679500CDC337 /* PBXTargetDependency */,
+				2FA436111ABB83B4008031D1 /* PBXTargetDependency */,
+				E4D5672E1ADECE2800F1EFE7 /* PBXTargetDependency */,
+				288A2D9C1AB8B3260023ABC3 /* PBXTargetDependency */,
+				2FCAE2301ABB51F800877008 /* PBXTargetDependency */,
+				282731741ABC9BE700AA1954 /* PBXTargetDependency */,
+				E69DB0891E97DEAA008A67E6 /* PBXTargetDependency */,
+				397848E11ED86605004C0C0B /* PBXTargetDependency */,
+				F84B22651A09210A00AAB793 /* PBXTargetDependency */,
+				F84B22521A0920C600AAB793 /* PBXTargetDependency */,
+				390527551C874D35007E0BB7 /* PBXTargetDependency */,
+				E4BA8A341B4B0A1700BC2E95 /* PBXTargetDependency */,
+			);
+			name = Client;
+			productName = Client;
+			productReference = F84B21BE1A090F8100AAB793 /* Client.app */;
+			productType = "com.apple.product-type.application";
+		};
+		F84B21D21A090F8100AAB793 /* ClientTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = F84B21E01A090F8100AAB793 /* Build configuration list for PBXNativeTarget "ClientTests" */;
+			buildPhases = (
+				F84B21CF1A090F8100AAB793 /* Sources */,
+				F84B21D01A090F8100AAB793 /* Frameworks */,
+				F84B21D11A090F8100AAB793 /* Resources */,
+				2F3444EC1AB2378200FD9731 /* Copy Files */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				7B9BF92F1E435DE400CB24F4 /* PBXTargetDependency */,
+				F84B21D51A090F8100AAB793 /* PBXTargetDependency */,
+			);
+			name = ClientTests;
+			productName = ClientTests;
+			productReference = F84B21D31A090F8100AAB793 /* ClientTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		F84B22481A0920C600AAB793 /* ShareTo */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = F84B22551A0920C600AAB793 /* Build configuration list for PBXNativeTarget "ShareTo" */;
+			buildPhases = (
+				F84B22451A0920C600AAB793 /* Sources */,
+				F84B22461A0920C600AAB793 /* Frameworks */,
+				F84B22471A0920C600AAB793 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				D09A0CEF1FAA2C66009A0273 /* PBXTargetDependency */,
+				D09A0CF51FAA2C99009A0273 /* PBXTargetDependency */,
+				D09A0CF11FAA2C7E009A0273 /* PBXTargetDependency */,
+				2F9A72321ABB856100F9F05D /* PBXTargetDependency */,
+				D09A0CF31FAA2C81009A0273 /* PBXTargetDependency */,
+			);
+			name = ShareTo;
+			productName = ShareToFirefox;
+			productReference = F84B22491A0920C600AAB793 /* ShareTo.appex */;
+			productType = "com.apple.product-type.app-extension";
+		};
+		F84B225B1A09210A00AAB793 /* SendTo */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = F84B22671A09210A00AAB793 /* Build configuration list for PBXNativeTarget "SendTo" */;
+			buildPhases = (
+				F84B22581A09210A00AAB793 /* Sources */,
+				F84B22591A09210A00AAB793 /* Frameworks */,
+				F84B225A1A09210A00AAB793 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				D09A0CF71FAA2CB2009A0273 /* PBXTargetDependency */,
+				D09A0CFD1FAA2CC5009A0273 /* PBXTargetDependency */,
+				D09A0CF91FAA2CBF009A0273 /* PBXTargetDependency */,
+				2F9A72341ABB856A00F9F05D /* PBXTargetDependency */,
+				D09A0CFB1FAA2CC2009A0273 /* PBXTargetDependency */,
+			);
+			name = SendTo;
+			productName = SendToDevice;
+			productReference = F84B225C1A09210A00AAB793 /* SendTo.appex */;
+			productType = "com.apple.product-type.app-extension";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		F84B21B61A090F8100AAB793 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastSwiftMigration = 0700;
+				LastSwiftUpdateCheck = 0830;
+				LastUpgradeCheck = 0800;
+				ORGANIZATIONNAME = Mozilla;
+				TargetAttributes = {
+					2827315D1ABC9BE600AA1954 = {
+						CreatedOnToolsVersion = 6.2;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+					};
+					282731671ABC9BE700AA1954 = {
+						CreatedOnToolsVersion = 6.2;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					288A2D851AB8B3260023ABC3 = {
+						CreatedOnToolsVersion = 6.2;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+					};
+					2FA435FA1ABB83B4008031D1 = {
+						CreatedOnToolsVersion = 6.2;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+					};
+					2FA436041ABB83B4008031D1 = {
+						CreatedOnToolsVersion = 6.2;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					2FCAE2191ABB51F800877008 = {
+						CreatedOnToolsVersion = 6.2;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+					};
+					2FCAE2231ABB51F800877008 = {
+						CreatedOnToolsVersion = 6.2;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					390527491C874D35007E0BB7 = {
+						CreatedOnToolsVersion = 7.2.1;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						ProvisioningStyle = Manual;
+					};
+					397848DA1ED86605004C0C0B = {
+						CreatedOnToolsVersion = 8.3.2;
+						DevelopmentTeam = 43AQ936H96;
+						ProvisioningStyle = Manual;
+						SystemCapabilities = {
+							com.apple.Push = {
+								enabled = 0;
+							};
+						};
+					};
+					3B43E3CF1D95C48D00BBA9DB = {
+						CreatedOnToolsVersion = 8.0;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						ProvisioningStyle = Automatic;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					3BFE4B061D342FB800DDF53F = {
+						CreatedOnToolsVersion = 7.3.1;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					7BEB64401C7345600092C02E = {
+						DevelopmentTeam = 43AQ936H96;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					7BEB644F1C7345990092C02E = {
+						DevelopmentTeam = 43AQ936H96;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					D39FA15E1A83E0EC00EE869C = {
+						CreatedOnToolsVersion = 6.1.1;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					E4BA8A2A1B4B0A1600BC2E95 = {
+						CreatedOnToolsVersion = 6.4;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						ProvisioningStyle = Manual;
+						SystemCapabilities = {
+							com.apple.ApplicationGroups.iOS = {
+								enabled = 1;
+							};
+						};
+					};
+					E4D567171ADECE2700F1EFE7 = {
+						CreatedOnToolsVersion = 6.3;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+					};
+					E4D567211ADECE2700F1EFE7 = {
+						CreatedOnToolsVersion = 6.3;
+						DevelopmentTeam = 9G8J6YA743;
+						LastSwiftMigration = 0820;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					E69DB0741E97DEA9008A67E6 = {
+						CreatedOnToolsVersion = 8.3;
+						DevelopmentTeam = 43AQ936H96;
+						ProvisioningStyle = Manual;
+					};
+					E69DB07C1E97DEA9008A67E6 = {
+						CreatedOnToolsVersion = 8.3;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0830;
+						ProvisioningStyle = Automatic;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					E6F9650B1B2F1CF20034B023 = {
+						CreatedOnToolsVersion = 6.3.2;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+					};
+					F84B21BD1A090F8100AAB793 = {
+						CreatedOnToolsVersion = 6.1;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						ProvisioningStyle = Manual;
+						SystemCapabilities = {
+							com.apple.ApplicationGroups.iOS = {
+								enabled = 1;
+							};
+							com.apple.BackgroundModes = {
+								enabled = 1;
+							};
+							com.apple.Keychain = {
+								enabled = 1;
+							};
+							com.apple.Push = {
+								enabled = 1;
+							};
+							com.apple.SafariKeychain = {
+								enabled = 1;
+							};
+						};
+					};
+					F84B21D21A090F8100AAB793 = {
+						CreatedOnToolsVersion = 6.1;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						TestTargetID = F84B21BD1A090F8100AAB793;
+					};
+					F84B22481A0920C600AAB793 = {
+						CreatedOnToolsVersion = 6.1;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						ProvisioningStyle = Manual;
+						SystemCapabilities = {
+							com.apple.ApplicationGroups.iOS = {
+								enabled = 1;
+							};
+							com.apple.Keychain = {
+								enabled = 1;
+							};
+							com.apple.Push = {
+								enabled = 0;
+							};
+						};
+					};
+					F84B225B1A09210A00AAB793 = {
+						CreatedOnToolsVersion = 6.1;
+						DevelopmentTeam = 43AQ936H96;
+						LastSwiftMigration = 0820;
+						ProvisioningStyle = Manual;
+						SystemCapabilities = {
+							com.apple.ApplicationGroups.iOS = {
+								enabled = 1;
+							};
+							com.apple.Keychain = {
+								enabled = 1;
+							};
+							com.apple.Push = {
+								enabled = 0;
+							};
+						};
+					};
+				};
+			};
+			buildConfigurationList = F84B21B91A090F8100AAB793 /* Build configuration list for PBXProject "Client" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = F84B21B51A090F8100AAB793;
+			productRefGroup = F84B21BF1A090F8100AAB793 /* Products */;
+			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = 28CE83CB1A1D1D5100576538 /* Products */;
+					ProjectRef = 28CE83CA1A1D1D5100576538 /* FxA.xcodeproj */;
+				},
+				{
+					ProductGroup = D30EBB5B1C75503800105AE9 /* Products */;
+					ProjectRef = D30EBB5A1C75503800105AE9 /* KIF.xcodeproj */;
+				},
+				{
+					ProductGroup = 0B742CC71B32491400EE9264 /* Products */;
+					ProjectRef = 0B742CC61B32491400EE9264 /* sqlcipher.xcodeproj */;
+				},
+				{
+					ProductGroup = 7B9A62BA1C4002B1005C83DC /* Products */;
+					ProjectRef = 7B9A62B91C4002B1005C83DC /* SQLite.xcodeproj */;
+				},
+			);
+			projectRoot = "";
+			targets = (
+				F84B21BD1A090F8100AAB793 /* Client */,
+				397848DA1ED86605004C0C0B /* NotificationService */,
+				F84B225B1A09210A00AAB793 /* SendTo */,
+				F84B22481A0920C600AAB793 /* ShareTo */,
+				390527491C874D35007E0BB7 /* Today */,
+				E4BA8A2A1B4B0A1600BC2E95 /* ViewLater */,
+				288A2D851AB8B3260023ABC3 /* Shared */,
+				2FCAE2191ABB51F800877008 /* Storage */,
+				2FA435FA1ABB83B4008031D1 /* Account */,
+				2827315D1ABC9BE600AA1954 /* Sync */,
+				E4D567171ADECE2700F1EFE7 /* ReadingList */,
+				E69DB0741E97DEA9008A67E6 /* SyncTelemetry */,
+				F84B21D21A090F8100AAB793 /* ClientTests */,
+				D39FA15E1A83E0EC00EE869C /* UITests */,
+				2FCAE2231ABB51F800877008 /* StorageTests */,
+				2FA436041ABB83B4008031D1 /* AccountTests */,
+				282731671ABC9BE700AA1954 /* SyncTests */,
+				E4D567211ADECE2700F1EFE7 /* ReadingListTests */,
+				E6F9650B1B2F1CF20034B023 /* SharedTests */,
+				7BEB64401C7345600092C02E /* L10nSnapshotTests */,
+				7BEB644F1C7345990092C02E /* MarketingUITests */,
+				3BFE4B061D342FB800DDF53F /* XCUITests */,
+				3B43E3CF1D95C48D00BBA9DB /* StoragePerfTests */,
+				E69DB07C1E97DEA9008A67E6 /* SyncTelemetryTests */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+		0B742CCC1B32491400EE9264 /* libsqlcipher.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libsqlcipher.a;
+			remoteRef = 0B742CCB1B32491400EE9264 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		28CE83D01A1D1D5100576538 /* FxA.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = FxA.framework;
+			remoteRef = 28CE83CF1A1D1D5100576538 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		28CE83D21A1D1D5100576538 /* FxATests.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = FxATests.xctest;
+			remoteRef = 28CE83D11A1D1D5100576538 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		7B10AAE61E3A57F90002DD08 /* SQLiteTests iOS.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "SQLiteTests iOS.xctest";
+			remoteRef = 7B10AAE51E3A57F90002DD08 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		7B10AAE81E3A57F90002DD08 /* SQLiteTests Mac.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "SQLiteTests Mac.xctest";
+			remoteRef = 7B10AAE71E3A57F90002DD08 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		7B10AAEA1E3A57F90002DD08 /* SQLite.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = SQLite.framework;
+			remoteRef = 7B10AAE91E3A57F90002DD08 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		7B10AAEC1E3A57F90002DD08 /* SQLiteTests tvOS.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "SQLiteTests tvOS.xctest";
+			remoteRef = 7B10AAEB1E3A57F90002DD08 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		7B10AAEE1E3A57F90002DD08 /* SQLite.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = SQLite.framework;
+			remoteRef = 7B10AAED1E3A57F90002DD08 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		7B9A62DB1C4002B1005C83DC /* SQLite.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = SQLite.framework;
+			remoteRef = 7B9A62DA1C4002B1005C83DC /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		7B9A62DF1C4002B1005C83DC /* SQLite.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = SQLite.framework;
+			remoteRef = 7B9A62DE1C4002B1005C83DC /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		D30EBB641C75503800105AE9 /* libKIF.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libKIF.a;
+			remoteRef = D30EBB631C75503800105AE9 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		D30EBB661C75503800105AE9 /* Test Host.app */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.application;
+			path = "Test Host.app";
+			remoteRef = D30EBB651C75503800105AE9 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		D30EBB681C75503800105AE9 /* KIF Tests - XCTest.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "KIF Tests - XCTest.xctest";
+			remoteRef = D30EBB671C75503800105AE9 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		D30EBB6A1C75503800105AE9 /* KIF.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = KIF.framework;
+			remoteRef = D30EBB691C75503800105AE9 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		E6CB64CC1DA42C2900887098 /* KIFFrameworkConsumer.app */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.application;
+			path = KIFFrameworkConsumer.app;
+			remoteRef = E6CB64CB1DA42C2900887098 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		E6CB64CE1DA42C2900887098 /* KIFFrameworkConsumerTests.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = KIFFrameworkConsumerTests.xctest;
+			remoteRef = E6CB64CD1DA42C2900887098 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+		2827315C1ABC9BE600AA1954 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				D37DE2CA1CA356F900A5EC69 /* testcert1.pem in Resources */,
+				D37DE2CB1CA356F900A5EC69 /* testcert2.pem in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		282731661ABC9BE700AA1954 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		288A2D841AB8B3260023ABC3 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E650759E1E37F7AB006961AC /* effective_tld_names.dat in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FA435F91ABB83B4008031D1 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FA436031ABB83B4008031D1 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6C9EB6B1E2FBFC300D5CE80 /* signedInUser.json in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FCAE2181ABB51F800877008 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FCAE2221ABB51F800877008 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E4791B9C1CC035FD00C6D77B /* testcert1.pem in Resources */,
+				39E65D191CA455A900C63CE3 /* Images.xcassets in Resources */,
+				2891F2CB1F991185001B105E /* v33.db in Resources */,
+				E4791BAA1CC0360200C6D77B /* testcert2.pem in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		390527481C874D35007E0BB7 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				39098DC41CAD5ACB00AE87F3 /* Images.xcassets in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		397848D91ED86605004C0C0B /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		3B43E3CE1D95C48D00BBA9DB /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		3BFE4B051D342FB800DDF53F /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7BEB64471C7345600092C02E /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7BEB64541C7345990092C02E /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		D39FA15D1A83E0EC00EE869C /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6EAC5961B29CB3A00E1DE1E /* scrollablePage.html in Resources */,
+				D34E33031BA793C2006135F0 /* loginForm.html in Resources */,
+				0B6FBAB21AC1F830007EC669 /* numberedPage.html in Resources */,
+				0B5A93421B1EB572004F47A2 /* readablePage.html in Resources */,
+				E6B4C3D81C68F55C001F97E8 /* JSPrompt.html in Resources */,
+				D343DCFE1C446BDB00D7EEE8 /* findPage.html in Resources */,
+				0BF8F8DA1AEFF1C900E90BC2 /* noTitle.html in Resources */,
+				E67422C51CFF2D39009E8373 /* youtube.ico in Resources */,
+				D3E171C21A841EAD00AB44CD /* KIFHelper.js in Resources */,
+				C8EB60C41F1FB12500F9B5B3 /* navigationDelegate.html in Resources */,
+				D31EC05F1CC57ED80096F4AB /* localhostLoad.html in Resources */,
+				4F97573B1AFA6F37006ECC24 /* readerContent.html in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4BA8A291B4B0A1600BC2E95 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E4BA8AAD1B4B15EF00BC2E95 /* ViewLater.xcassets in Resources */,
+				7B2142FF1E5E059900CDD3FC /* InfoPlist.strings in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4D567161ADECE2700F1EFE7 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4D567201ADECE2700F1EFE7 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E69DB0731E97DEA9008A67E6 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E69DB07B1E97DEA9008A67E6 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E6F9650A1B2F1CF20034B023 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B21BC1A090F8100AAB793 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				D38A1EE01CB458EC0080C842 /* CertError.html in Resources */,
+				0BA1E0301B051A07007675AF /* NetError.css in Resources */,
+				3BC659491E5BA4AE006D560F /* TopSites in Resources */,
+				E4B7B77E1A793CF20022C5E0 /* FiraSans-SemiBold.ttf in Resources */,
+				EB2A633C1F3B513E004EF8B0 /* disconnect-analytics.json in Resources */,
+				F84B220B1A0910F600AAB793 /* Images.xcassets in Resources */,
+				F35B8D2B1D6380EA008E3D61 /* SessionRestore.html in Resources */,
+				7B42406E1CA04CAC009B5C28 /* Menu.xcassets in Resources */,
+				E49943F71AE69EDD00BF9DE4 /* Intro.xcassets in Resources */,
+				3BC659591E5BA505006D560F /* top_sites.json in Resources */,
+				D02816D21ECA60DF00240CAA /* HistoryStateHelper.js in Resources */,
+				E4B7B7631A793CF20022C5E0 /* CharisSILI.ttf in Resources */,
+				E4CD9F541A71506400318571 /* Reader.html in Resources */,
+				EB2A633E1F3B514A004EF8B0 /* disconnect-content.json in Resources */,
+				7B2142FE1E5E055000CDD3FC /* InfoPlist.strings in Resources */,
+				E69922171B94E3EF007C480D /* Licenses.html in Resources */,
+				D3B692411B9F9CC8004B87A4 /* FindInPage.js in Resources */,
+				E4CD9F5B1A71506C00318571 /* Reader.css in Resources */,
+				E4B7B7611A793CF20022C5E0 /* CharisSILB.ttf in Resources */,
+				D37524871C6E8B5A00A5F6C2 /* topdomains.txt in Resources */,
+				E4B7B7621A793CF20022C5E0 /* CharisSILBI.ttf in Resources */,
+				7B4980A81CE363ED0017547C /* Settings.xcassets in Resources */,
+				3B4262E71E538EC400CA681C /* page-metadata-parser.js in Resources */,
+				E4A961361AC052DE0069AD6F /* ReadabilityTabHelper.js in Resources */,
+				E4B7B7861A793CF20022C5E0 /* FiraSans-UltraLight.ttf in Resources */,
+				2F44FB2C1A9D5D8500FD20CC /* Home.xcassets in Resources */,
+				E4B7B77D1A793CF20022C5E0 /* FiraSans-Regular.ttf in Resources */,
+				EB2A633B1F3B513B004EF8B0 /* disconnect-advertising.json in Resources */,
+				0BDA568B1B26B1BE008C9B96 /* LoginsHelper.js in Resources */,
+				E4B7B7791A793CF20022C5E0 /* FiraSans-Light.ttf in Resources */,
+				E49BFF591B1F48C3009368CC /* Readability.js in Resources */,
+				E4CD9E9A1A68980A00318571 /* ReaderMode.js in Resources */,
+				D30684F11C84F12A002D8D82 /* SearchPlugins in Resources */,
+				3B4262E51E538EC400CA681C /* MetadataHelper.js in Resources */,
+				E47536FC1C85415F0022CC69 /* PrintHelper.js in Resources */,
+				74821FFE1DB6D3AC00EEEA72 /* MailSchemes.plist in Resources */,
+				FA9294011D6584A200AC8D33 /* QRCode.xcassets in Resources */,
+				D308EE561CBF0BF5006843F2 /* CertError.css in Resources */,
+				E4B7B7641A793CF20022C5E0 /* CharisSILR.ttf in Resources */,
+				D3BA7E0C1B0E902A00153782 /* ContextMenu.js in Resources */,
+				3BE7274E1CCFE8A30099189F /* CustomSearchHelper.js in Resources */,
+				E4B7B7681A793CF20022C5E0 /* FiraSans-Bold.ttf in Resources */,
+				E4B7B7781A793CF20022C5E0 /* FiraSans-Italic.ttf in Resources */,
+				A91528D21D0E637600CD0425 /* NoImageModeHelper.js in Resources */,
+				0BA1E00E1B03FB0B007675AF /* NetError.html in Resources */,
+				E4A961381AC06FA50069AD6F /* ReaderViewLoading.html in Resources */,
+				EB2A633F1F3B514B004EF8B0 /* disconnect-social.json in Resources */,
+				E4ECCDAE1AB131770005E717 /* FiraSans-Medium.ttf in Resources */,
+				E4424B3C1AC71FB400F44C38 /* FiraSans-Book.ttf in Resources */,
+				0BF42D391A7C0E8900889E28 /* Favicons.js in Resources */,
+				39A35AED1C0662A3006B9E87 /* SpotlightHelper.js in Resources */,
+				E689C6F81E0C6E72008BAADB /* FxASignIn.js in Resources */,
+				E4D6BEB91A0930EC00F538BD /* LaunchScreen.xib in Resources */,
+				A93067D91D0FE15E00C49C6E /* NightModeHelper.js in Resources */,
+				2F44FB2D1A9D5D8500FD20CC /* FiraSans-BoldItalic.ttf in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B21D11A090F8100AAB793 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				3B61CD631F2A769D00D38DE1 /* pocketglobalfeed.json in Resources */,
+				A83E5B1A1C1DA8BF0026D912 /* image.gif in Resources */,
+				A83E5B1B1C1DA8BF0026D912 /* image.png in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B22471A0920C600AAB793 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E487B24F1AC1CC9200F3E86F /* FiraSans-Medium.ttf in Resources */,
+				E487B2331AC1C64300F3E86F /* FiraSans-Regular.ttf in Resources */,
+				F8708D2E1A0970B70051AB07 /* Images.xcassets in Resources */,
+				E487B2501AC1CC9800F3E86F /* FiraSans-Light.ttf in Resources */,
+				E487B24E1AC1C66400F3E86F /* FiraSans-SemiBold.ttf in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B225A1A09210A00AAB793 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E4F21AA61A13C4A300B0FAAA /* Images.xcassets in Resources */,
+				7B2143001E5E05A000CDD3FC /* InfoPlist.strings in Resources */,
+				F8708D2C1A0970B40051AB07 /* MainInterface.storyboard in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		7B604F8F1C494AAA006EEEC3 /* Copy Carthage Dependencies */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+				"$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/SDWebImage.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/SnapKit.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/XCGLogger.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/AdjustSdk.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/GCDWebServers.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/OnePasswordExtension.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/Deferred.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/SwiftKeychainWrapper.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/Fuzi.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/JSONSchema.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/SwiftyJSON.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/Sentry.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/SwiftRouter.framework",
+				"$(SRCROOT)/Carthage/Build/iOS/Telemetry.framework",
+			);
+			name = "Copy Carthage Dependencies";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/usr/local/bin/carthage copy-frameworks";
+		};
+		E4DAA6741F63027B00FA53AF /* Run Script */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 8;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Run Script";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+			shellPath = /bin/sh;
+			shellScript = "cd \"${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Leanplum.framework/\"\nlipo -remove i386 -remove x86_64 Leanplum -output Leanplum";
+		};
+		E6639F191BF11E3A002D0853 /* Conditionally Add Settings Bundle */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Conditionally Add Settings Bundle";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "if [ \"${INCLUDE_SETTINGS_BUNDLE}\" = \"YES\" ]\nthen\n    cp -r \"${PROJECT_DIR}/${TARGET_NAME}/Application/Settings.bundle\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app\"\nfi";
+		};
+		E6EC6EFC1E5354E20067985D /* Copy Carthage Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+				"$(SRCROOT)/Carthage/Build/iOS/EarlGrey.framework",
+			);
+			name = "Copy Carthage Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/usr/local/bin/carthage copy-frameworks";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		282731591ABC9BE600AA1954 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2853C5411AD84C6800C4F31D /* TabsPayload.swift in Sources */,
+				28926B3A1AC0F128009C0B1D /* CleartextPayloadJSON.swift in Sources */,
+				280CB1371C20E0A3005AF147 /* BookmarksSynchronizer.swift in Sources */,
+				2827319D1ABC9C2F00AA1954 /* SyncMeta.swift in Sources */,
+				2894C1661AE89DD200F1F92F /* TabsSynchronizer.swift in Sources */,
+				282731991ABC9C2F00AA1954 /* ClientPayload.swift in Sources */,
+				E67D57031D527449003917B1 /* BatchingClient.swift in Sources */,
+				2894C1431AE89D8900F1F92F /* HistorySynchronizer.swift in Sources */,
+				28E23C121AC5A5EE00F5AC85 /* State.swift in Sources */,
+				28ED02291B262E0A003948B2 /* IndependentRecordSynchronizer.swift in Sources */,
+				CE564D8E1EB7BD7700BEDDDC /* BookmarksRepairRequestor.swift in Sources */,
+				28A17B671BEC727500BC14ED /* Downloader.swift in Sources */,
+				2F3724E71ABF3C19007607FA /* StorageClient.swift in Sources */,
+				28926B1A1AC0F074009C0B1D /* EncryptedJSON.swift in Sources */,
+				2894C16C1AE89FD500F1F92F /* HistoryPayload.swift in Sources */,
+				2885023F1AC117A500E7F670 /* SyncStateMachine.swift in Sources */,
+				EBA31D7D1F79996E0055463D /* SyncTelemetryUtils.swift in Sources */,
+				28ED02261B262B5E003948B2 /* LoginsSynchronizer.swift in Sources */,
+				2894C1691AE89DDC00F1F92F /* ClientsSynchronizer.swift in Sources */,
+				288E67C21B9E730900AE2C6A /* BookmarksDownloader.swift in Sources */,
+				28E91E751B443AD5009DF274 /* SyncConstants.swift in Sources */,
+				28532CE61C48098D000072D9 /* ThreeWayTreeMerger.swift in Sources */,
+				28C28BFD1C51A3B900D5460E /* Merging.swift in Sources */,
+				2F3724E91ABF3C19007607FA /* Synchronizer.swift in Sources */,
+				28AA941D1B97DCA800703DC6 /* BookmarkPayload.swift in Sources */,
+				28ED02021B26123E003948B2 /* LoginPayload.swift in Sources */,
+				28926B371AC0F0DD009C0B1D /* EnvelopeJSON.swift in Sources */,
+				2827319A1ABC9C2F00AA1954 /* KeyBundle.swift in Sources */,
+				2F3724E51ABF3C19007607FA /* Info.swift in Sources */,
+				2827319C1ABC9C2F00AA1954 /* Record.swift in Sources */,
+				E69DB0C31E97E320008A67E6 /* BookmarkTelemetryPing.swift in Sources */,
+				2827319B1ABC9C2F00AA1954 /* KeysPayload.swift in Sources */,
+				288501DE1AC0F61D00E7F670 /* RequestExtensions.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		282731641ABC9BE700AA1954 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6BA20211E52170E00697F9C /* SyncTelemetryTests.swift in Sources */,
+				28ECD97A1BA1EA2200D829DA /* MockSyncServer.swift in Sources */,
+				285D37E31ABCA69E000E1CF9 /* CryptoTests.swift in Sources */,
+				28F596A11ACA13CA0071DDCC /* InfoTests.swift in Sources */,
+				2F3724C71ABF3C01007607FA /* StorageClientTests.swift in Sources */,
+				28ECD9F41BA1F59800D829DA /* DownloadTests.swift in Sources */,
+				2F3724C61ABF3C01007607FA /* LiveStorageClientTests.swift in Sources */,
+				E6EDE82C1D5244AF007A0732 /* BatchingClientTests.swift in Sources */,
+				E42736071EA858CF009C428E /* TabsPayloadTests.swift in Sources */,
+				E6F6D6A51E9E6B2B0012072B /* DeferredTestUtils.swift in Sources */,
+				28D980231C47149000277055 /* TestBookmarkTreeMerging.swift in Sources */,
+				CE339EE61F2507C0009BE0E6 /* TestBookmarksSynchronizer.swift in Sources */,
+				E67035EE1E538B500037AB83 /* Mocking.swift in Sources */,
+				289A4C141C4EB90600A460E3 /* StorageTestUtils.swift in Sources */,
+				28532CC11C473977000072D9 /* MockFiles.swift in Sources */,
+				E6D7C32B1CF4E86C00E746BA /* TestBookmarkModel.swift in Sources */,
+				CEFC984B1EC0DCF5008A3E48 /* TestBookmarksRepairRequestor.swift in Sources */,
+				2F8C76571BC32F3C00D5E4E0 /* MockSyncServerTests.swift in Sources */,
+				28F657EA1ABFCA7A00A608BD /* LiveAccountTest.swift in Sources */,
+				2F67C5261BB0CB4E00E7B73A /* MetaGlobalTests.swift in Sources */,
+				2827319E1ABC9C5900AA1954 /* RecordTests.swift in Sources */,
+				2855611F1AEFFA1C00D5ED5B /* HistorySynchronizerTests.swift in Sources */,
+				5002717C41BC7C50F67F1CAD /* StateTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		288A2D811AB8B3260023ABC3 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E65075991E37F7AB006961AC /* Cancellable.swift in Sources */,
+				E65075BE1E37F7AB006961AC /* TimeConstants.swift in Sources */,
+				E65075B21E37F7AB006961AC /* Functions.swift in Sources */,
+				E65075B41E37F7AB006961AC /* KeychainCache.swift in Sources */,
+				E65075BA1E37F7AB006961AC /* Prefs.swift in Sources */,
+				7B10AABB1E3A1F650002DD08 /* URLRequestExtensions.swift in Sources */,
+				D02818611EF056C800240CAA /* SentryIntegration.swift in Sources */,
+				E693F0D91E9D64BD0086DC17 /* OptionalExtensions.swift in Sources */,
+				E65075A01E37F7AB006961AC /* ArrayExtensions.swift in Sources */,
+				288A2DAA1AB8B3700023ABC3 /* Box.swift in Sources */,
+				E65075A31E37F7AB006961AC /* KeychainWrapperExtensions.swift in Sources */,
+				E65075921E37F7AB006961AC /* Accessibility.swift in Sources */,
+				E65075B51E37F7AB006961AC /* LaunchArguments.swift in Sources */,
+				288A2DAB1AB8B3700023ABC3 /* BoxType.swift in Sources */,
+				E65075BB1E37F7AB006961AC /* RollingFileLogger.swift in Sources */,
+				E650759D1E37F7AB006961AC /* DeviceInfo.swift in Sources */,
+				E65075971E37F7AB006961AC /* AuthenticationKeychainInfo.swift in Sources */,
+				E65075A51E37F7AB006961AC /* NSFileManagerExtensions.swift in Sources */,
+				E65075A11E37F7AB006961AC /* HashExtensions.swift in Sources */,
+				3964B09A1EA8F06F00F2EEF4 /* FeatureSwitch.swift in Sources */,
+				E65075981E37F7AB006961AC /* Bytes.swift in Sources */,
+				E65075B11E37F7AB006961AC /* FSUtils.m in Sources */,
+				CE7F11941F3CEEC800ABFC0B /* RemoteDevices.swift in Sources */,
+				D3A14C221CB3145E00253BC6 /* Strings.swift in Sources */,
+				7B10AA9F1E3A15020002DD08 /* DataExtensions.swift in Sources */,
+				7B3D9E651E4CBFDB007A50DA /* NSCoderExtensions.swift in Sources */,
+				E65075931E37F7AB006961AC /* AppConstants.swift in Sources */,
+				E65075B81E37F7AB006961AC /* NotificationConstants.swift in Sources */,
+				E65075AC1E37F7AB006961AC /* StringExtensions.swift in Sources */,
+				E65075951E37F7AB006961AC /* AssertionUtils.swift in Sources */,
+				E683F0C21E93D4E90035D990 /* DictionaryExtensions.swift in Sources */,
+				E650759B1E37F7AB006961AC /* CrashSimulator.m in Sources */,
+				288A2DB51AB8B38D0023ABC3 /* Error.swift in Sources */,
+				E65075A91E37F7AB006961AC /* NSURLExtensions.swift in Sources */,
+				7479B4EF1C5306A200DF000B /* Reachability.swift in Sources */,
+				E65075B31E37F7AB006961AC /* KeyboardHelper.swift in Sources */,
+				E65075AA1E37F7AB006961AC /* NSURLProtectionSpaceExtensions.swift in Sources */,
+				E65075BC1E37F7AB006961AC /* SupportUtils.swift in Sources */,
+				E65075B61E37F7AB006961AC /* Loader.swift in Sources */,
+				E65075BF1E37F7AB006961AC /* UserAgent.swift in Sources */,
+				E65075C01E37F7AB006961AC /* WeakList.swift in Sources */,
+				E65075AE1E37F7AB006961AC /* UIImageExtensions.swift in Sources */,
+				E65075A71E37F7AB006961AC /* NSScannerExtensions.swift in Sources */,
+				E65075A21E37F7AB006961AC /* HexExtensions.swift in Sources */,
+				288A2DB61AB8B38D0023ABC3 /* Result.swift in Sources */,
+				E65075AD1E37F7AB006961AC /* UIColorExtensions.swift in Sources */,
+				E650759C1E37F7AB006961AC /* DeferredUtils.swift in Sources */,
+				E65075941E37F7AB006961AC /* AppInfo.swift in Sources */,
+				288A2DAC1AB8B3700023ABC3 /* MutableBox.swift in Sources */,
+				E65075A41E37F7AB006961AC /* NSCharacterSetExtensions.swift in Sources */,
+				E65075B71E37F7AB006961AC /* Logger.swift in Sources */,
+				E65075961E37F7AB006961AC /* AsyncReducer.swift in Sources */,
+				7B9BF91C1E43472E00CB24F4 /* JSONExtensions.swift in Sources */,
+				E65075A61E37F7AB006961AC /* NSMutableAttributedStringExtensions.swift in Sources */,
+				E65075BD1E37F7AB006961AC /* SystemUtils.swift in Sources */,
+				E65075AB1E37F7AB006961AC /* SetExtensions.swift in Sources */,
+				E65075A81E37F7AB006961AC /* NSStringExtensions.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FA435F61ABB83B4008031D1 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2FA4362B1ABB8436008031D1 /* FirefoxAccountConfiguration.swift in Sources */,
+				39F99FE41E3A6F1700F353B4 /* PushClient.swift in Sources */,
+				39F99FE51E3A6F1700F353B4 /* PushConfiguration.swift in Sources */,
+				D32A350E1D6530D80066DAE9 /* FxADevice.swift in Sources */,
+				39F99FE61E3A6F1700F353B4 /* PushRegistration.swift in Sources */,
+				2F1A3DE11ABE3C90002F1E15 /* FxALoginStateMachine.swift in Sources */,
+				D3DBE6E51D6516FE00033FFF /* FxADeviceRegistration.swift in Sources */,
+				2FA436291ABB8436008031D1 /* FirefoxAccount.swift in Sources */,
+				2FFC4D1B1ABE3C360081D675 /* FxAState.swift in Sources */,
+				2FDBCF611ABFC9DE00AFF7F0 /* SyncAuthState.swift in Sources */,
+				39C22C291E89791C000C0E56 /* PushCrypto.swift in Sources */,
+				2FA436351ABB8436008031D1 /* TokenServerClient.swift in Sources */,
+				2FA436331ABB8436008031D1 /* HawkHelper.swift in Sources */,
+				2FA4362F1ABB8436008031D1 /* FxAClient10.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FA436011ABB83B4008031D1 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6F6D6A41E9E6B2B0012072B /* DeferredTestUtils.swift in Sources */,
+				2FA4363E1ABB8448008031D1 /* FxAClient10Tests.swift in Sources */,
+				2FDBCF9B1AC0ADB500AFF7F0 /* SyncAuthStateTests.swift in Sources */,
+				2FA436421ABB8448008031D1 /* TokenServerClientTests.swift in Sources */,
+				39C22C2A1E897926000C0E56 /* PushCryptoTests.swift in Sources */,
+				39C22C2F1E897BA7000C0E56 /* LivePushClientTests.swift in Sources */,
+				2FFC4D381ABE3C420081D675 /* FxAStateTests.swift in Sources */,
+				2FA436411ABB8448008031D1 /* LiveAccountTest.swift in Sources */,
+				2F1A3DFE1ABE3C9C002F1E15 /* FxALoginStateMachineTests.swift in Sources */,
+				2FA4363D1ABB8448008031D1 /* FirefoxAccountTests.swift in Sources */,
+				2FA436401ABB8448008031D1 /* HawkHelperTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FCAE2151ABB51F800877008 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2FCAE2621ABB531100877008 /* History.swift in Sources */,
+				28126F6E1C2F94F9006466CC /* SQLiteBookmarksModel.swift in Sources */,
+				7B9BF9301E449D2500CB24F4 /* MockLogins.swift in Sources */,
+				0BDA56B21B26B1E4008C9B96 /* Logins.swift in Sources */,
+				0BDA56B41B26B203008C9B96 /* SQLiteLogins.swift in Sources */,
+				E6F368291D7F594F008CDD67 /* SQLiteHistoryRecommendations.swift in Sources */,
+				2829D3A01C2F0AD400DCF931 /* Sharing.swift in Sources */,
+				2FCAE2751ABB531100877008 /* SQLiteRemoteClientsAndTabs.swift in Sources */,
+				285F2DC11AF80B4600211843 /* SQLiteBookmarksSyncing.swift in Sources */,
+				28C4AB721AD42D4300D9ACE3 /* Clients.swift in Sources */,
+				D0131B4D1F3CF7D8000CDE86 /* SQLiteFavicons.swift in Sources */,
+				28126F741C2F96F1006466CC /* SQLiteBookmarksResetting.swift in Sources */,
+				28B62ACE1BC745E7004A585A /* Syncable.swift in Sources */,
+				74B195441CF503FC007F36EF /* RecentlyClosedTabs.swift in Sources */,
+				E65075C21E37F956006961AC /* ExtensionUtils.swift in Sources */,
+				7BF5A1EA1B41640500EA9DD8 /* SyncQueue.swift in Sources */,
+				2852B8441C51996B00591EAC /* Trees.swift in Sources */,
+				E677F0541D94247300ECF1FB /* Metadata.swift in Sources */,
+				28E08C991AF44EF9009BA2FA /* SQLiteHistory.swift in Sources */,
+				285D3B901B4386520035FD22 /* SQLiteQueue.swift in Sources */,
+				28532D321C483E3D000072D9 /* CompletionOps.swift in Sources */,
+				2FCAE25D1ABB531100877008 /* Bookmarks.swift in Sources */,
+				394CF6CF1BAA493C00906917 /* DefaultSuggestedSites.swift in Sources */,
+				2FCAE2781ABB531100877008 /* Visit.swift in Sources */,
+				D3BF8CBB1B7425570007AFE6 /* DiskImageStore.swift in Sources */,
+				E6FF6ACA1D873CFF0070C294 /* PageMetadata.swift in Sources */,
+				2FCAE2611ABB531100877008 /* FileAccessor.swift in Sources */,
+				28126F481C2F948E006466CC /* SQLiteBookmarksHelpers.swift in Sources */,
+				E677F0451D9423FB00ECF1FB /* SQLiteMetadata.swift in Sources */,
+				D37DE2831CA2047500A5EC69 /* CertStore.swift in Sources */,
+				D018F93E1F44A71A0098F8CA /* Schema.swift in Sources */,
+				2829D37A1C2F0A7F00DCF931 /* BookmarksModel.swift in Sources */,
+				2FCAE2661ABB531100877008 /* Site.swift in Sources */,
+				0B54BD191B698B7C004C822C /* SuggestedSites.swift in Sources */,
+				318FB6EB1DB5600D0004E40F /* SQLiteHistoryFactories.swift in Sources */,
+				285D3B681B4380B70035FD22 /* Queue.swift in Sources */,
+				28E08C9A1AF44F00009BA2FA /* BrowserSchema.swift in Sources */,
+				2FCAE2681ABB531100877008 /* BrowserDB.swift in Sources */,
+				283586FD1C73F18E00A55435 /* CachingItemSource.swift in Sources */,
+				D0B29EE01F460BDF00C7CEFC /* LoginsSchema.swift in Sources */,
+				2FCAE2651ABB531100877008 /* RemoteTabs.swift in Sources */,
+				2FCAE2601ABB531100877008 /* Favicons.swift in Sources */,
+				28126F771C2F9833006466CC /* SQLiteBookmarksBase.swift in Sources */,
+				2FCAE2771ABB531100877008 /* SwiftData.swift in Sources */,
+				2FCAE25F1ABB531100877008 /* Cursor.swift in Sources */,
+				28302E401AF0747800521E2E /* DatabaseError.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		2FCAE2201ABB51F800877008 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				28D158AD1AFD90E500F9C065 /* TestSQLiteBookmarks.swift in Sources */,
+				C8611C8E1F71904C00C3DE7D /* DiskImageStoreTests.swift in Sources */,
+				E63F71881DB7FBE200A995C9 /* TestSQLiteMetadata.swift in Sources */,
+				2FCAE2851ABB533A00877008 /* TestSQLiteRemoteClientsAndTabs.swift in Sources */,
+				E6F6D6A31E9E6B2A0012072B /* DeferredTestUtils.swift in Sources */,
+				E6BE53CD1D9177B10074909A /* TestSQLiteHistoryRecommendations.swift in Sources */,
+				289A4C131C4EB90600A460E3 /* StorageTestUtils.swift in Sources */,
+				D37DE2C71CA356D800A5EC69 /* CertTests.swift in Sources */,
+				281B029A1C037C1F005202C3 /* TestBrowserDB.swift in Sources */,
+				D32CACED1AE04DA1000658EB /* TestSwiftData.swift in Sources */,
+				2FCAE2841ABB533A00877008 /* MockFiles.swift in Sources */,
+				7BF5A1EE1B429B3100EA9DD8 /* SyncCommandsTests.swift in Sources */,
+				287AC8661AF4776D00101515 /* TestSQLiteHistory.swift in Sources */,
+				0BDA56B01B26B1D5008C9B96 /* TestLogins.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		390527461C874D35007E0BB7 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				315D05561E58DD60001F349B /* UIPasteboardExtensions.swift in Sources */,
+				3905274F1C874D35007E0BB7 /* TodayViewController.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		397848D71ED86605004C0C0B /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				397848DE1ED86605004C0C0B /* NotificationService.swift in Sources */,
+				396E38EE1EE0C6ED00CC180F /* ExtensionProfile.swift in Sources */,
+				396E38CC1EE0816C00CC180F /* Profile.swift in Sources */,
+				396E38E01EE0821B00CC180F /* NSUserDefaultsPrefs.swift in Sources */,
+				396E38DD1EE081DA00CC180F /* SyncStatusResolver.swift in Sources */,
+				396E38F21EE0C8ED00CC180F /* FxAPushMessageHandler.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		3B43E3CC1D95C48D00BBA9DB /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6F6D6AA1E9E6B300012072B /* DeferredTestUtils.swift in Sources */,
+				3B43E3D31D95C48D00BBA9DB /* StoragePerfTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		3BFE4B031D342FB800DDF53F /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2CA16FDE1E5F089100332277 /* SearchTest.swift in Sources */,
+				0BF0DB4A1E57B05E009172B0 /* LaunchArguments.swift in Sources */,
+				3B546EC01D95ECAE00BDBE36 /* ActivityStreamTest.swift in Sources */,
+				3D9CA9841EF456A8002434DD /* NightModeTests.swift in Sources */,
+				39EB46991E26DDB4006346E8 /* ScreenGraph.swift in Sources */,
+				0B305E1B1E3A98A900BE0767 /* BookmarkingTests.swift in Sources */,
+				D81127D81F84023B0050841D /* PhotonActionSheetTest.swift in Sources */,
+				3BFE4B501D34673D00DDF53F /* ThirdPartySearchTest.swift in Sources */,
+				0BC9C9C41F26F54D000E8AB5 /* SiteLoadTest.swift in Sources */,
+				2C2A5EF41E68469500F02659 /* PrivateBrowsingTest.swift in Sources */,
+				3D71C89E1F5703A1008D8646 /* CopiedLinksTests.swift in Sources */,
+				2CF449A51E7BFE2C00FD7595 /* NavigationTest.swift in Sources */,
+				2C2A91291FA2410D002E36BD /* HistoryTests.swift in Sources */,
+				3BF4B8E91D38497A00493393 /* BaseTestCase.swift in Sources */,
+				3D9CAA1C1EFCD655002434DD /* ClipBoardTests.swift in Sources */,
+				0B3D670E1E09B90B00C1EFC7 /* AuthenticationTest.swift in Sources */,
+				2C97EC711E72C80E0092EC18 /* TopTabsTest.swift in Sources */,
+				39EB469A1E26DDB4006346E8 /* FxScreenGraph.swift in Sources */,
+				2CC1B3F01E9B861400814EEC /* DomainAutocompleteTest.swift in Sources */,
+				0B729D371E047D6A008E6859 /* HomePageSettingsTest.swift in Sources */,
+				3DEFED081F55EBE300F8620C /* TrackingProtectionTests.swift in Sources */,
+				3D9CA9A81EF84D04002434DD /* NoImageTests.swift in Sources */,
+				2C31A8471E8D447F00DAC646 /* HomePageSettingsUITest.swift in Sources */,
+				2CEA6F791E93E3A600D4100E /* SearchSettingsUITest.swift in Sources */,
+				55A747171DC46FC400CE1B57 /* HomePageUITest.swift in Sources */,
+				2C31A7A91E8BFB2200DAC646 /* ReaderViewUITest.swift in Sources */,
+				2C8C07771E7800EA00DC1237 /* FindInPageTest.swift in Sources */,
+				2CB56E3F1E926BFB00AF7586 /* ToolbarTest.swift in Sources */,
+				2C3406C81E719F00000FD889 /* SettingsTest.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7BEB64431C7345600092C02E /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7BEB64441C7345600092C02E /* L10nSnapshotTests.swift in Sources */,
+				7BEB64451C7345600092C02E /* SnapshotHelper.swift in Sources */,
+				E40AFC541DD0E93300DA5651 /* L10nPermissionStringsSnapshotTests.swift in Sources */,
+				E40AFC6C1DD128DA00DA5651 /* L10nIntroSnapshotTests.swift in Sources */,
+				E40AFC651DD0F25500DA5651 /* L10nBaseSnapshotTests.swift in Sources */,
+				E402000A1E6493C800B45AFF /* LaunchArguments.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7BEB64501C7345990092C02E /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7BEB64511C7345990092C02E /* MarketingUITests.swift in Sources */,
+				7BEB64521C7345990092C02E /* SnapshotHelper.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		D39FA15B1A83E0EC00EE869C /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				0B5A93221B1EB4C8004F47A2 /* ReadingListTest.swift in Sources */,
+				D38F03701C06387900175932 /* AuthenticationTests.swift in Sources */,
+				28C8B7851C852535006D8318 /* BookmarksPanelTests.swift in Sources */,
+				C8611CB01F71AEBA00C3DE7D /* NoImageModeTests.swift in Sources */,
+				E6B4C4031C68F58B001F97E8 /* BrowserTests.swift in Sources */,
+				D39FA1811A83E84900EE869C /* Global.swift in Sources */,
+				0B7C1E951F6097AD006A8869 /* TrackingProtectionTests.swift in Sources */,
+				4F514FD41ACD8F2C0022D7EA /* HistoryTests.swift in Sources */,
+				C8EB60DC1F1FB9AD00F9B5B3 /* NavigationDelegateTests.swift in Sources */,
+				E6A92ADB1C52A8DA00743291 /* LoginInputTests.swift in Sources */,
+				D375A9201AE71675001B30D5 /* ViewMemoryLeakTests.swift in Sources */,
+				D313BE981B2F5096009EF241 /* DomainAutocompleteTests.swift in Sources */,
+				D3CFD3641CC5605B0064AB4A /* SecurityTests.swift in Sources */,
+				D3C3EB651B6FF44000388E9A /* SessionRestoreTests.swift in Sources */,
+				7B24DC9C1B67B3590005766B /* ClearPrivateDataTests.swift in Sources */,
+				E633E37A1C2204BE001FFF6C /* LoginManagerTests.swift in Sources */,
+				744B0FFE1B4F172E00100422 /* ToolbarTests.swift in Sources */,
+				0BEF44631E31165700187C32 /* EarlGrey.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4BA8A271B4B0A1600BC2E95 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E444F7E01B4B1C1A00FEB19B /* NSUserDefaultsPrefs.swift in Sources */,
+				E4BA8AA81B4B15EF00BC2E95 /* ActionRequestHandler.swift in Sources */,
+				E60D03281D511555002FE3F6 /* SyncStatusResolver.swift in Sources */,
+				E68F36AB1EA698610048CF44 /* PanelDataObservers.swift in Sources */,
+				E444F7E21B4B1C6800FEB19B /* SearchEngines.swift in Sources */,
+				E444F7DF1B4B1C1200FEB19B /* Profile.swift in Sources */,
+				E444F7E31B4B1C8000FEB19B /* OpenSearch.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4D567131ADECE2700F1EFE7 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E4D5677C1ADECE8100F1EFE7 /* ReadingListOAuthAuthenticator.swift in Sources */,
+				E4D567841ADECE8100F1EFE7 /* ReadingListResponse.swift in Sources */,
+				E4D567921ADECE8100F1EFE7 /* ReadingListUtils.swift in Sources */,
+				E41F0D9B1ADFFC5600FC7387 /* ReadingListError.swift in Sources */,
+				E4D567761ADECE8100F1EFE7 /* ReadingListClientRecord.swift in Sources */,
+				E4D5678E1ADECE8100F1EFE7 /* ReadingListSynchronizer.swift in Sources */,
+				E4D567801ADECE8100F1EFE7 /* ReadingListRecordResponse.swift in Sources */,
+				E41F0D981ADFFB5400FC7387 /* ReadingListService.swift in Sources */,
+				E4D5678A1ADECE8100F1EFE7 /* ReadingListSQLStorage.swift in Sources */,
+				E4D567881ADECE8100F1EFE7 /* ReadingListServerRecord.swift in Sources */,
+				E4D567861ADECE8100F1EFE7 /* ReadingListServerMetadata.swift in Sources */,
+				E4D567901ADECE8100F1EFE7 /* ReadingListSyncMetadata.swift in Sources */,
+				E4D5677A1ADECE8100F1EFE7 /* ReadingListFetchSpec.swift in Sources */,
+				E4D567821ADECE8100F1EFE7 /* ReadingListRecordsResponse.swift in Sources */,
+				E4D567721ADECE8100F1EFE7 /* ReadingListClient.swift in Sources */,
+				E4D5678C1ADECE8100F1EFE7 /* ReadingListStorage.swift in Sources */,
+				E4D5676A1ADECE8100F1EFE7 /* ReadingListAuthenticator.swift in Sources */,
+				E4D567741ADECE8100F1EFE7 /* ReadingListClientMetadata.swift in Sources */,
+				E4D567701ADECE8100F1EFE7 /* ReadingListChangeAccumulator.swift in Sources */,
+				E4D5676E1ADECE8100F1EFE7 /* ReadingListBatchRecordResponse.swift in Sources */,
+				E4D5676C1ADECE8100F1EFE7 /* ReadingListBasicAuthAuthenticator.swift in Sources */,
+				E4D5677E1ADECE8100F1EFE7 /* ReadingListRecord.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E4D5671E1ADECE2700F1EFE7 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E4D567A51ADECEB800F1EFE7 /* ReadingListStorageTestCase.swift in Sources */,
+				E6F6D6A61E9E6B2C0012072B /* DeferredTestUtils.swift in Sources */,
+				E4D5679F1ADECEB800F1EFE7 /* ReadingListClientRecordTestCase.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E69DB0701E97DEA9008A67E6 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E69DB0B71E97E2AC008A67E6 /* SyncTelemetry.swift in Sources */,
+				EBA31D791F7999030055463D /* SyncPingCentre.swift in Sources */,
+				EBA31D7B1F79990C0055463D /* SyncTelemetryEvents.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E69DB0791E97DEA9008A67E6 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E610B0191EDC68FC00DC9372 /* EventTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		E6F965081B2F1CF20034B023 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E6F6D6A71E9E6B2D0012072B /* DeferredTestUtils.swift in Sources */,
+				28532BEB1C472015000072D9 /* UtilsTests.swift in Sources */,
+				28532BEA1C472008000072D9 /* DeferredTests.swift in Sources */,
+				E61453BE1B750A1700C3F9D7 /* RollingFileLoggerTests.swift in Sources */,
+				3BB54B311E68EB2B0021DAC4 /* AuthenticationKeychainInfoTests.swift in Sources */,
+				39E65D271CA5B92000C63CE3 /* AsyncReducerTests.swift in Sources */,
+				E4E7EB6D1C4AED5E0094275D /* SupportUtilsTests.swift in Sources */,
+				3964B09C1EA8F32C00F2EEF4 /* FeatureSwitchTests.swift in Sources */,
+				E4E25CCB1CA99E7400D0F088 /* HexExtensionsTests.swift in Sources */,
+				E6F965421B2F25110034B023 /* NSMutableAttributedStringExtensionsTests.swift in Sources */,
+				28532BE91C471FFB000072D9 /* ResultTests.swift in Sources */,
+				E6F9653C1B2F1D5D0034B023 /* NSURLExtensionsTests.swift in Sources */,
+				3B4AA24B1D8B8C4C00A2E008 /* ArrayExtensionTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B21BA1A090F8100AAB793 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E68E39BE1C46F42000B85F42 /* AppSettingsTableViewController.swift in Sources */,
+				E640E86A1C73A47C00C5F072 /* PasscodeViews.swift in Sources */,
+				E692E3371C46E86A009D1240 /* AppSettingsOptions.swift in Sources */,
+				D38F02D11C05127100175932 /* Authenticator.swift in Sources */,
+				E68E7ADC1CAC208200FDCA76 /* SetupPasscodeViewController.swift in Sources */,
+				7B3631EA1C244FEE00D12AF9 /* Theme.swift in Sources */,
+				3B61CD491F2A74EF00D38DE1 /* PocketFeed.swift in Sources */,
+				396E38F11EE0C8EC00CC180F /* FxAPushMessageHandler.swift in Sources */,
+				E66C5B481BDA81050051AA93 /* UIImage+ImageEffects.m in Sources */,
+				E4CD9F6D1A77DD2800318571 /* ReaderModeStyleViewController.swift in Sources */,
+				E4A960061ABB9C450069AD6F /* ReaderModeUtils.swift in Sources */,
+				EBF47E701F7979DF00899189 /* UnifiedTelemetry.swift in Sources */,
+				E68F36981EA694000048CF44 /* PanelDataObservers.swift in Sources */,
+				31ADB5DA1E58CEC300E87909 /* ClipboardBarDisplayHandler.swift in Sources */,
+				745DAB3F1CDAB09E00D44181 /* HistoryBackButton.swift in Sources */,
+				396E38F31EE0C90D00CC180F /* FxALoginHelper.swift in Sources */,
+				D3B6923F1B9F9A58004B87A4 /* FindInPageHelper.swift in Sources */,
+				D3C3696E1CC6B78800348A61 /* LocalRequestHelper.swift in Sources */,
+				E4B423DD1ABA0318007E66C8 /* ReaderModeHandlers.swift in Sources */,
+				7B0B1B9D1C1B6A3F00DF4AB5 /* InstructionsViewController.swift in Sources */,
+				D308E4E41A5306F500842685 /* SearchEngines.swift in Sources */,
+				3BCE6D3C1CEB9E4D0080928C /* ThirdPartySearchAlerts.swift in Sources */,
+				745DAB301CDAAFAA00D44181 /* RecentlyClosedTabsPanel.swift in Sources */,
+				C45F44691D087DB600CB7EF0 /* TopTabsViewController.swift in Sources */,
+				0BF0DB941A8545800039F300 /* URLBarView.swift in Sources */,
+				C817B34D1FC609500086018E /* UIScrollViewSwizzled.swift in Sources */,
+				39F819C61FD70F5D009E31E4 /* TabEventHandlers.swift in Sources */,
+				E65607611C08B4E200534B02 /* SearchInputView.swift in Sources */,
+				EB2A63341F3B49A7004EF8B0 /* ContentBlockerHelper.swift in Sources */,
+				FA6B2AC21D41F02D00429414 /* Punycode.swift in Sources */,
+				D301AAEE1A3A55B70078DD1D /* TabTrayController.swift in Sources */,
+				0B3E7D951B27A7CE00E2E84D /* AboutHomeHandler.swift in Sources */,
+				D331DFCA1CB6E9EE009B5DA2 /* OldStrings.swift in Sources */,
+				D3BE7B461B054F8600641031 /* TestAppDelegate.swift in Sources */,
+				3BB50E111D6274CD004B33DF /* ActivityStreamTopSitesCell.swift in Sources */,
+				0B62EFD21AD63CD100ACB9CD /* Clearables.swift in Sources */,
+				7482205C1DBAB56300EEEA72 /* MailProviders.swift in Sources */,
+				C40046FA1CF8E0B200B08303 /* BackForwardListAnimator.swift in Sources */,
+				DD31E0FB1B382B520077078A /* TabPrintPageRenderer.swift in Sources */,
+				D81E45131F82C56D004EFFBA /* NewTabContentSettingsViewController.swift in Sources */,
+				E4CD9E911A6897FB00318571 /* ReaderMode.swift in Sources */,
+				E68E7ADE1CAC208A00FDCA76 /* RemovePasscodeViewController.swift in Sources */,
+				74C027451B2A348C001B1E88 /* SessionData.swift in Sources */,
+				D314E7F71A37B98700426A76 /* TabToolbar.swift in Sources */,
+				E60D03181D511398002FE3F6 /* SyncStatusResolver.swift in Sources */,
+				E689C6FA1E0C6E98008BAADB /* FxAContentViewController.swift in Sources */,
+				C4E3983D1D21F1E7004E89BA /* TopTabsViews.swift in Sources */,
+				3B0943811D6CC4FC004F24E1 /* FilledPageControl.swift in Sources */,
+				FA9293D41D6580E100AC8D33 /* QRCodeViewController.swift in Sources */,
+				0BB5B2891AC0A2B90052877D /* Toolbar.swift in Sources */,
+				E6108FF91C84E91C005D25E8 /* BasePasscodeViewController.swift in Sources */,
+				E4CD9F2D1A6DC91200318571 /* TabLocationView.swift in Sources */,
+				0BB5B2881AC0A2B90052877D /* SnackBar.swift in Sources */,
+				7BEFC6801BFF68C30059C952 /* QuickActions.swift in Sources */,
+				0BF1B7E31AC60DEA00A7B407 /* InsetButton.swift in Sources */,
+				D31CF65C1CC1959A001D0BD0 /* PrivilegedRequest.swift in Sources */,
+				E650755C1E37F747006961AC /* Swizzling.m in Sources */,
+				74821FC51DB56A2500EEEA72 /* OpenWithSettingsViewController.swift in Sources */,
+				D3B6923D1B9F9444004B87A4 /* FindInPageBar.swift in Sources */,
+				2F44FC721A9E840300FD20CC /* SettingsNavigationController.swift in Sources */,
+				74821F8E1DAD8F1400EEEA72 /* ActivityStreamHighlightCell.swift in Sources */,
+				E69E06BA1C76173D00D0F926 /* RequirePasscodeIntervalViewController.swift in Sources */,
+				D3BA7E0E1B0E934F00153782 /* ContextMenuHelper.swift in Sources */,
+				E660BE061BB0666D009AC090 /* InnerStrokedView.swift in Sources */,
+				0B1C05D71A798B1F004C78B0 /* UIImageViewAligned.m in Sources */,
+				0BB5B30B1AC0AD1F0052877D /* LoginsHelper.swift in Sources */,
+				E69E06C91C76198000D0F926 /* AuthenticationManagerConstants.swift in Sources */,
+				E47536ED1C85412C0022CC69 /* PrintHelper.swift in Sources */,
+				392ED7E61D0AEFEF009D9B62 /* HomePageAccessors.swift in Sources */,
+				7BA8D1C71BA037F500C8AE9E /* OpenInHelper.swift in Sources */,
+				E4B423BE1AB9FE6A007E66C8 /* ReaderModeCache.swift in Sources */,
+				74E36D781B71323500D69DA1 /* SettingsContentViewController.swift in Sources */,
+				742A56391D80B54A00BDB803 /* PhotonActionSheet.swift in Sources */,
+				C4EFEECF1CEBB6F2009762A4 /* BackForwardTableViewCell.swift in Sources */,
+				E689C7301E0C7617008BAADB /* NSAttributedStringExtensions.swift in Sources */,
+				E64ED8FA1BC55AE300DAF864 /* UIAlertControllerExtensions.swift in Sources */,
+				282DA4731A68C1E700A406E2 /* OpenSearch.swift in Sources */,
+				F35B8D2F1D638408008E3D61 /* SessionRestoreHandler.swift in Sources */,
+				E63ED8E11BFD25580097D08E /* LoginListViewController.swift in Sources */,
+				2F44FCC71A9E8CF500FD20CC /* SearchSettingsTableViewController.swift in Sources */,
+				0BF42D371A7C0B8E00889E28 /* FaviconManager.swift in Sources */,
+				39A359E41BFCCE94006B9E87 /* UserActivityHandler.swift in Sources */,
+				D88FDAAF1F4E2BA000FD9709 /* PhotonActionSheetAnimator.swift in Sources */,
+				E698FFDA1B4AADF40001F623 /* TabScrollController.swift in Sources */,
+				7BEDD29B1CB7CB24004B51F3 /* JumpAndSpinAnimator.swift in Sources */,
+				D34510881ACF415700EC27F0 /* SearchLoader.swift in Sources */,
+				E65075521E37F6D1006961AC /* UIViewExtensions.swift in Sources */,
+				C8F457A81F1FD75A000CB895 /* BrowserViewController+WKNavigationDelegate.swift in Sources */,
+				E6927EC01C7B6FB800D03F75 /* ErrorToast.swift in Sources */,
+				D30B101E1AA7F9C600C01CA3 /* HomePanels.swift in Sources */,
+				F84B22041A0910F600AAB793 /* AppDelegate.swift in Sources */,
+				E653422D1C5944F90039DD9E /* BrowserPrompts.swift in Sources */,
+				2FDE87FE1ABB3817005317B1 /* RemoteTabsPanel.swift in Sources */,
+				39DD030D1CD53E1900BC09B3 /* HomePageHelper.swift in Sources */,
+				C4F3B29A1CFCF93A00966259 /* ButtonToast.swift in Sources */,
+				E4A961341AC051360069AD6F /* ReadabilityTabHelper.swift in Sources */,
+				D31A0FC71A65D6D000DC8C7E /* SearchSuggestClient.swift in Sources */,
+				A83E5AB71C1D993D0026D912 /* UIPasteboardExtensions.swift in Sources */,
+				E650754E1E37F6AE006961AC /* GeometryExtensions.swift in Sources */,
+				D3972BF41C22412B00035B87 /* TitleActivityItemProvider.swift in Sources */,
+				D38A1BEE1A9FA2CA00F6A386 /* SiteTableViewController.swift in Sources */,
+				7BA0601B1C0F4DE200DFADB6 /* TabPeekViewController.swift in Sources */,
+				E6D8D5E71B569D70009E5A58 /* BrowserTrayAnimators.swift in Sources */,
+				E65075611E37F77D006961AC /* MenuHelper.swift in Sources */,
+				E63ED7D81BFCD9990097D08E /* LoginTableViewCell.swift in Sources */,
+				3BB50E201D627539004B33DF /* ActivityStreamPanel.swift in Sources */,
+				F84B22241A09122500AAB793 /* HomePanelViewController.swift in Sources */,
+				39455F771FC83F430088A22C /* TabEventHandler.swift in Sources */,
+				E47616C71AB74CA600E7DD25 /* ReaderModeBarView.swift in Sources */,
+				D88FDA9F1F4E2B9200FD9709 /* PhotonActionSheetProtocol.swift in Sources */,
+				E65075511E37F6D1006961AC /* NSURLExtensionsMailTo.swift in Sources */,
+				D83822001FC7961D00303C12 /* DispatchQueueExtensions.swift in Sources */,
+				2F44FCC51A9E85E900FD20CC /* SettingsTableViewController.swift in Sources */,
+				A9072B801D07B34100459960 /* NoImageModeHelper.swift in Sources */,
+				E660BDD91BB06521009AC090 /* TabsButton.swift in Sources */,
+				2F44FCCB1A9E972E00FD20CC /* SearchEnginePicker.swift in Sources */,
+				D02816C21ECA5E2A00240CAA /* HistoryStateHelper.swift in Sources */,
+				E68E7ACB1CAC1D4500FDCA76 /* PagingPasscodeViewController.swift in Sources */,
+				D34DC8531A16C40C00D49B7B /* Profile.swift in Sources */,
+				392ED6B71D06E85E009D9B62 /* NewTabChoiceViewController.swift in Sources */,
+				E4B3348C1BC01D8F004E2BFF /* AdjustIntegration.swift in Sources */,
+				E65075541E37F6FC006961AC /* DynamicFontHelper.swift in Sources */,
+				C4E3984C1D21F2FD004E89BA /* TabTrayButtonExtensions.swift in Sources */,
+				D3FEC38D1AC4B42F00494F45 /* AutocompleteTextField.swift in Sources */,
+				0BD19A671A25309B0084FBA7 /* NSUserDefaultsPrefs.swift in Sources */,
+				E68AEDB01B18F81A00133D99 /* SwipeAnimator.swift in Sources */,
+				3BF56D271CDBBE1F00AC4D75 /* SimpleToast.swift in Sources */,
+				D31F95E91AC226CB005C9F3B /* ScreenshotHelper.swift in Sources */,
+				28EADE5D1AFC3A78007FB2FB /* UIImageViewExtensions.swift in Sources */,
+				D3968F251A38FE8500CEFD3B /* TabManager.swift in Sources */,
+				C4E398601D22C409004E89BA /* TopTabsLayout.swift in Sources */,
+				2816F0001B33E05400522243 /* UIConstants.swift in Sources */,
+				E650755F1E37F756006961AC /* Try.m in Sources */,
+				3B6889C51D66950E002AC85E /* UIImageColors.swift in Sources */,
+				392ED7E41D0AEF56009D9B62 /* NewTabAccessors.swift in Sources */,
+				D3A9949D1A3686BD008AD1AC /* Tab.swift in Sources */,
+				A93067E81D0FE18E00C49C6E /* NightModeHelper.swift in Sources */,
+				3B39EDCB1E16E1AA00EF029F /* CustomSearchViewController.swift in Sources */,
+				E65075571E37F714006961AC /* FaviconFetcher.swift in Sources */,
+				D863C8F21F68BFC20058D95F /* GradientProgressBar.swift in Sources */,
+				D3C744CD1A687D6C004CE85D /* URIFixup.swift in Sources */,
+				7BC68D091CC153020043562A /* RoundedToolbar.swift in Sources */,
+				39AC591A1CC574AB0042C2F5 /* HomePageSettingsViewController.swift in Sources */,
+				E4A961181AC041C40069AD6F /* ReadabilityService.swift in Sources */,
+				D3BE7B261B054D4400641031 /* main.swift in Sources */,
+				0BA1E02E1B046F1E007675AF /* ErrorPageHelper.swift in Sources */,
+				D3A9949C1A3686BD008AD1AC /* BrowserViewController.swift in Sources */,
+				59A681BDFC95A19F05E07223 /* SearchViewController.swift in Sources */,
+				7BEDD2B21CB7CC0B004B51F3 /* Animatable.swift in Sources */,
+				E6CF28E71CB43B7900151AB3 /* SensitiveViewController.swift in Sources */,
+				E68E7ADA1CAC207400FDCA76 /* ChangePasscodeViewController.swift in Sources */,
+				E640E85E1C73A45A00C5F072 /* PasscodeEntryViewController.swift in Sources */,
+				8D8251811F4DE67F00780643 /* AdvanceAccountSettingViewController.swift in Sources */,
+				E633E2DA1C21EAF8001FFF6C /* LoginDetailViewController.swift in Sources */,
+				59A68B280D62462B85CF57A4 /* HistoryPanel.swift in Sources */,
+				19DE1F671EC13B6400428B8C /* LeanplumIntegration.swift in Sources */,
+				E65D89181C8647420006EA35 /* AppAuthenticator.swift in Sources */,
+				28FDFF0C1C1F725800840F86 /* SeparatorTableCell.swift in Sources */,
+				C400467C1CF4E43E00B08303 /* BackForwardListViewController.swift in Sources */,
+				D3972BF31C22412B00035B87 /* ShareExtensionHelper.swift in Sources */,
+				F35B8D2D1D6383E9008E3D61 /* SessionRestoreHelper.swift in Sources */,
+				744ED5611DBFEB8D00A2B5BE /* MailtoLinkHandler.swift in Sources */,
+				59A68E0B4ABBF55E14819668 /* BookmarksPanel.swift in Sources */,
+				7B0B1B791C1B69C900DF4AB5 /* ClientPickerViewController.swift in Sources */,
+				7B844E3D1BBDDB9D00E733A2 /* ChevronView.swift in Sources */,
+				E4C358551AF144BA00299F7E /* FSReadingList.m in Sources */,
+				3BE7275D1CCFE8B60099189F /* CustomSearchHandler.swift in Sources */,
+				E692E3291C46E62D009D1240 /* AuthenticationSettingsViewController.swift in Sources */,
+				E663D5781BB341C4001EF30E /* ToggleButton.swift in Sources */,
+				C88601C61F4228AD00BBDE4F /* ContentBlockerSettingViewController.swift in Sources */,
+				E6327A641BF6438E008D12E0 /* DebugSettingsBundleOptions.swift in Sources */,
+				D3E8EF101B97BE69001900FB /* ClearPrivateDataTableViewController.swift in Sources */,
+				C8F457AA1F1FDD9B000CB895 /* BrowserViewController+KeyCommands.swift in Sources */,
+				E69DB0BD1E97E301008A67E6 /* ActivityStreamTopics.swift in Sources */,
+				59A68FD5260B8D520F890F4A /* ReaderPanel.swift in Sources */,
+				E40FAB0C1A7ABB77009CB80D /* WebServer.swift in Sources */,
+				59A68D66379CFA85C4EAF00B /* TwoLineCell.swift in Sources */,
+				E49943F51AE6879C00BF9DE4 /* IntroViewController.swift in Sources */,
+				3B4262E61E538EC400CA681C /* MetadataParserHelper.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B21CF1A090F8100AAB793 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E4CD9F1D1A6D9C2800318571 /* WebServerTests.swift in Sources */,
+				D3D488591ABB54CD00A93597 /* FileAccessorTests.swift in Sources */,
+				E6C70E821E28314700F8DB57 /* PingCentreTests.swift in Sources */,
+				0BA8964B1A250E6500C1010C /* ProfileTest.swift in Sources */,
+				03CCC9181AF05E7300DBF30D /* RelativeDatesTests.swift in Sources */,
+				F84B21DA1A090F8100AAB793 /* ClientTests.swift in Sources */,
+				281B2BEA1ADF4D90002917DC /* MockProfile.swift in Sources */,
+				E6F6D6AB1E9E6B330012072B /* DeferredTestUtils.swift in Sources */,
+				2F697F7E1A9FD22D009E03AE /* SearchEnginesTests.swift in Sources */,
+				2F44FA1B1A9D426A00FD20CC /* TestHashExtensions.swift in Sources */,
+				3B39EDBA1E16E18900EF029F /* CustomSearchEnginesTest.swift in Sources */,
+				D3FA777B1A43B2990010CD32 /* SearchTests.swift in Sources */,
+				D3BA41681BD82F2200DA5457 /* XCTestCaseExtensions.swift in Sources */,
+				554867231DC3935A00183DAA /* HomePageTests.swift in Sources */,
+				3BFCBF201E04B1C50070C042 /* UIImageViewExtensionsTests.swift in Sources */,
+				8DCD3BCD1ED5B7FA00446D38 /* FxADeepLinkingTests.swift in Sources */,
+				3943A81D1E9807C700D4F6DC /* FxAPushMessageTest.swift in Sources */,
+				E60D032A1D5118DB002FE3F6 /* SyncStatusResolverTests.swift in Sources */,
+				E683F0A61E92E0820035D990 /* MockableHistory.swift in Sources */,
+				A83E5B1E1C1DAAAA0026D912 /* UIPasteboardExtensions.swift in Sources */,
+				0BF42D4F1A7CD09600889E28 /* TestFavicons.swift in Sources */,
+				7BBFEE741BB405D900A305AA /* TabManagerTests.swift in Sources */,
+				39236E721FCC600200A38F1B /* TabEventHandlerTests.swift in Sources */,
+				0BA8964C1A250E6500C1010C /* TestBookmarks.swift in Sources */,
+				2F13E79B1AC0C02700D75081 /* StringExtensionsTests.swift in Sources */,
+				2FDB10931A9FBEC5006CF312 /* PrefsTests.swift in Sources */,
+				4A59B58AD11B5EE1F80BBDEB /* TestHistory.swift in Sources */,
+				A83E5B1D1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift in Sources */,
+				E61D11681EAF8F43008A305B /* PanelDataObserversTests.swift in Sources */,
+				28D52E2F1BCDF53900187A1D /* ResetTests.swift in Sources */,
+				3B61CD591F2A750800D38DE1 /* PocketFeedTests.swift in Sources */,
+				E696FE511C47F86E00EC007C /* AuthenticatorTests.swift in Sources */,
+				3B6F40181DC7849C00656CC6 /* ActivityStreamTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B22451A0920C600AAB793 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FA6B2AC41D41F02D00429414 /* Punycode.swift in Sources */,
+				D38B2D8A1A8D98D00040E6B5 /* SearchEngines.swift in Sources */,
+				D3C744CF1A687D6C004CE85D /* URIFixup.swift in Sources */,
+				D38B2D8C1A8D98D90040E6B5 /* OpenSearch.swift in Sources */,
+				E418D0D91A251B3200CAE47A /* Profile.swift in Sources */,
+				F8708D321A0970B70051AB07 /* ShareViewController.swift in Sources */,
+				E68F36AD1EA698650048CF44 /* PanelDataObservers.swift in Sources */,
+				28CDA55C1A43C37C005C318C /* NSUserDefaultsPrefs.swift in Sources */,
+				E60D03271D511554002FE3F6 /* SyncStatusResolver.swift in Sources */,
+				E41A7D4B1A1BE04500245963 /* InitialViewController.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F84B22581A09210A00AAB793 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				D38B2D8B1A8D98D10040E6B5 /* SearchEngines.swift in Sources */,
+				D3C744D01A687D6C004CE85D /* URIFixup.swift in Sources */,
+				E60D03261D511554002FE3F6 /* SyncStatusResolver.swift in Sources */,
+				D38B2D8D1A8D98DA0040E6B5 /* OpenSearch.swift in Sources */,
+				E4BCAAB91B0537E300855D82 /* InstructionsViewController.swift in Sources */,
+				E42CCDE81A23A73D00B794D3 /* Profile.swift in Sources */,
+				E68F36AC1EA698610048CF44 /* PanelDataObservers.swift in Sources */,
+				E4BCAAD91B05380B00855D82 /* ClientPickerViewController.swift in Sources */,
+				FA6B2AC31D41F02D00429414 /* Punycode.swift in Sources */,
+				F8708D2A1A0970B40051AB07 /* ActionViewController.swift in Sources */,
+				28CDA5641A43C37D005C318C /* NSUserDefaultsPrefs.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		0B742CCE1B32493800EE9264 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = sqlcipher;
+			targetProxy = 0B742CCD1B32493800EE9264 /* PBXContainerItemProxy */;
+		};
+		2827316B1ABC9BE700AA1954 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2827315D1ABC9BE600AA1954 /* Sync */;
+			targetProxy = 2827316A1ABC9BE700AA1954 /* PBXContainerItemProxy */;
+		};
+		282731741ABC9BE700AA1954 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2827315D1ABC9BE600AA1954 /* Sync */;
+			targetProxy = 282731731ABC9BE700AA1954 /* PBXContainerItemProxy */;
+		};
+		288A2D9C1AB8B3260023ABC3 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = 288A2D9B1AB8B3260023ABC3 /* PBXContainerItemProxy */;
+		};
+		28ECD9B11BA1F07000D829DA /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = 28ECD9BE1BA1F12B00D829DA /* PBXContainerItemProxy */;
+		};
+		2F11EE501ABCAE910083902D /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = 2F11EE4F1ABCAE910083902D /* PBXContainerItemProxy */;
+		};
+		2F14E1181ABB88CB00FF98DB /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = FxA;
+			targetProxy = 2F14E1171ABB88CB00FF98DB /* PBXContainerItemProxy */;
+		};
+		2F14E1341ABB88CF00FF98DB /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = 2F14E1331ABB88CF00FF98DB /* PBXContainerItemProxy */;
+		};
+		2F67C5281BB0D33000E7B73A /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FA435FA1ABB83B4008031D1 /* Account */;
+			targetProxy = 2FC87C3C1BC45E67001BAE77 /* PBXContainerItemProxy */;
+		};
+		2F77F69D1ABCAEFE00484F3A /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = FxA;
+			targetProxy = 2F77F69C1ABCAEFE00484F3A /* PBXContainerItemProxy */;
+		};
+		2F77F6B91ABCAF0700484F3A /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FA435FA1ABB83B4008031D1 /* Account */;
+			targetProxy = 2F77F6B81ABCAF0700484F3A /* PBXContainerItemProxy */;
+		};
+		2F9A72321ABB856100F9F05D /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FCAE2191ABB51F800877008 /* Storage */;
+			targetProxy = 2F9A72311ABB856100F9F05D /* PBXContainerItemProxy */;
+		};
+		2F9A72341ABB856A00F9F05D /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FCAE2191ABB51F800877008 /* Storage */;
+			targetProxy = 2F9A72331ABB856A00F9F05D /* PBXContainerItemProxy */;
+		};
+		2FA436111ABB83B4008031D1 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FA435FA1ABB83B4008031D1 /* Account */;
+			targetProxy = 2FA436101ABB83B4008031D1 /* PBXContainerItemProxy */;
+		};
+		2FA4361D1ABB83DD008031D1 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = 2FA4361C1ABB83DD008031D1 /* PBXContainerItemProxy */;
+		};
+		2FA436441ABB84CB008031D1 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = FxA;
+			targetProxy = 2FA436431ABB84CB008031D1 /* PBXContainerItemProxy */;
+		};
+		2FCAE2271ABB51F800877008 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FCAE2191ABB51F800877008 /* Storage */;
+			targetProxy = 2FCAE2261ABB51F800877008 /* PBXContainerItemProxy */;
+		};
+		2FCAE2291ABB51F800877008 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = 2FCAE2281ABB51F800877008 /* PBXContainerItemProxy */;
+		};
+		2FCAE2301ABB51F800877008 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FCAE2191ABB51F800877008 /* Storage */;
+			targetProxy = 2FCAE22F1ABB51F800877008 /* PBXContainerItemProxy */;
+		};
+		2FCAE23C1ABB520700877008 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = 2FCAE23B1ABB520700877008 /* PBXContainerItemProxy */;
+		};
+		390527551C874D35007E0BB7 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 390527491C874D35007E0BB7 /* Today */;
+			targetProxy = 390527541C874D35007E0BB7 /* PBXContainerItemProxy */;
+		};
+		397848E11ED86605004C0C0B /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 397848DA1ED86605004C0C0B /* NotificationService */;
+			targetProxy = 397848E01ED86605004C0C0B /* PBXContainerItemProxy */;
+		};
+		3B43E3D61D95C48D00BBA9DB /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = 3B43E3D51D95C48D00BBA9DB /* PBXContainerItemProxy */;
+		};
+		3BFE4B0D1D342FB900DDF53F /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = 3BFE4B0C1D342FB900DDF53F /* PBXContainerItemProxy */;
+		};
+		7B10AAF01E3A58C80002DD08 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = 7B10AAEF1E3A58C80002DD08 /* PBXContainerItemProxy */;
+		};
+		7B9A62F91C400303005C83DC /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = "SQLite iOS";
+			targetProxy = 7B9A62F81C400303005C83DC /* PBXContainerItemProxy */;
+		};
+		7B9BF92F1E435DE400CB24F4 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FCAE2231ABB51F800877008 /* StorageTests */;
+			targetProxy = 7B9BF92E1E435DE400CB24F4 /* PBXContainerItemProxy */;
+		};
+		7BEB64411C7345600092C02E /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = 7BEB64421C7345600092C02E /* PBXContainerItemProxy */;
+		};
+		7BEB645D1C7346100092C02E /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = 7BEB645C1C7346100092C02E /* PBXContainerItemProxy */;
+		};
+		D09A0CDF1FAA2577009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = D09A0CDE1FAA2577009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CE11FAA25C5009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = D09A0CE01FAA25C5009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CE51FAA2C18009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = D09A0CE41FAA2C18009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CE71FAA2C1B009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FCAE2191ABB51F800877008 /* Storage */;
+			targetProxy = D09A0CE61FAA2C1B009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CE91FAA2C1E009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2827315D1ABC9BE600AA1954 /* Sync */;
+			targetProxy = D09A0CE81FAA2C1E009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CEB1FAA2C38009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E4D567171ADECE2700F1EFE7 /* ReadingList */;
+			targetProxy = D09A0CEA1FAA2C38009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CED1FAA2C4C009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = D09A0CEC1FAA2C4C009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CEF1FAA2C66009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = FxA;
+			targetProxy = D09A0CEE1FAA2C66009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CF11FAA2C7E009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = D09A0CF01FAA2C7E009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CF31FAA2C81009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2827315D1ABC9BE600AA1954 /* Sync */;
+			targetProxy = D09A0CF21FAA2C81009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CF51FAA2C99009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E4D567171ADECE2700F1EFE7 /* ReadingList */;
+			targetProxy = D09A0CF41FAA2C99009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CF71FAA2CB2009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = FxA;
+			targetProxy = D09A0CF61FAA2CB2009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CF91FAA2CBF009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = D09A0CF81FAA2CBF009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CFB1FAA2CC2009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2827315D1ABC9BE600AA1954 /* Sync */;
+			targetProxy = D09A0CFA1FAA2CC2009A0273 /* PBXContainerItemProxy */;
+		};
+		D09A0CFD1FAA2CC5009A0273 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E4D567171ADECE2700F1EFE7 /* ReadingList */;
+			targetProxy = D09A0CFC1FAA2CC5009A0273 /* PBXContainerItemProxy */;
+		};
+		D0EA58131FA836CA00D03ED1 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2827315D1ABC9BE600AA1954 /* Sync */;
+			targetProxy = D0EA58121FA836CA00D03ED1 /* PBXContainerItemProxy */;
+		};
+		D0EA58151FA836CE00D03ED1 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FCAE2191ABB51F800877008 /* Storage */;
+			targetProxy = D0EA58141FA836CE00D03ED1 /* PBXContainerItemProxy */;
+		};
+		D0EA58171FA836D200D03ED1 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = D0EA58161FA836D200D03ED1 /* PBXContainerItemProxy */;
+		};
+		D39FA1661A83E0EC00EE869C /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = D39FA1651A83E0EC00EE869C /* PBXContainerItemProxy */;
+		};
+		E4A888191A95679500CDC337 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = FxA;
+			targetProxy = E4A888181A95679500CDC337 /* PBXContainerItemProxy */;
+		};
+		E4BA8A341B4B0A1700BC2E95 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E4BA8A2A1B4B0A1600BC2E95 /* ViewLater */;
+			targetProxy = E4BA8A331B4B0A1700BC2E95 /* PBXContainerItemProxy */;
+		};
+		E4D567251ADECE2700F1EFE7 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E4D567171ADECE2700F1EFE7 /* ReadingList */;
+			targetProxy = E4D567241ADECE2700F1EFE7 /* PBXContainerItemProxy */;
+		};
+		E4D5672E1ADECE2800F1EFE7 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E4D567171ADECE2700F1EFE7 /* ReadingList */;
+			targetProxy = E4D5672D1ADECE2800F1EFE7 /* PBXContainerItemProxy */;
+		};
+		E4EE05B01BA3A0A10021B3A7 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 2FCAE2191ABB51F800877008 /* Storage */;
+			targetProxy = E4EE05AF1BA3A0A10021B3A7 /* PBXContainerItemProxy */;
+		};
+		E60222E61C6E5A770061C436 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = FxA;
+			targetProxy = E60222E51C6E5A770061C436 /* PBXContainerItemProxy */;
+		};
+		E69DB0801E97DEAA008A67E6 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E69DB0741E97DEA9008A67E6 /* SyncTelemetry */;
+			targetProxy = E69DB07F1E97DEAA008A67E6 /* PBXContainerItemProxy */;
+		};
+		E69DB0821E97DEAA008A67E6 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = E69DB0811E97DEAA008A67E6 /* PBXContainerItemProxy */;
+		};
+		E69DB0891E97DEAA008A67E6 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E69DB0741E97DEA9008A67E6 /* SyncTelemetry */;
+			targetProxy = E69DB0881E97DEAA008A67E6 /* PBXContainerItemProxy */;
+		};
+		E69DB0A71E97DEF6008A67E6 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = E69DB0741E97DEA9008A67E6 /* SyncTelemetry */;
+			targetProxy = E69DB0A61E97DEF6008A67E6 /* PBXContainerItemProxy */;
+		};
+		E6F965141B2F1CF20034B023 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 288A2D851AB8B3260023ABC3 /* Shared */;
+			targetProxy = E63CD1B11B31B66400A63AFF /* PBXContainerItemProxy */;
+		};
+		E6F9653A1B2F1D330034B023 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = E63CD1B21B31B66400A63AFF /* PBXContainerItemProxy */;
+		};
+		F84B21D51A090F8100AAB793 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B21BD1A090F8100AAB793 /* Client */;
+			targetProxy = F84B21D41A090F8100AAB793 /* PBXContainerItemProxy */;
+		};
+		F84B22521A0920C600AAB793 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B22481A0920C600AAB793 /* ShareTo */;
+			targetProxy = F84B22511A0920C600AAB793 /* PBXContainerItemProxy */;
+		};
+		F84B22651A09210A00AAB793 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F84B225B1A09210A00AAB793 /* SendTo */;
+			targetProxy = F84B22641A09210A00AAB793 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+		7B2142F31E5E03F800CDD3FC /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				7B2142F41E5E03F800CDD3FC /* en */,
+				7B2143021E5F224A00CDD3FC /* Base */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "";
+		};
+		7B2142F61E5E040200CDD3FC /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				7B2142F71E5E040200CDD3FC /* en */,
+				7B2143031E5F225200CDD3FC /* Base */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "";
+		};
+		7B2142FC1E5E055000CDD3FC /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				7B2142FD1E5E055000CDD3FC /* en */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		282731771ABC9BE800AA1954 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Sync/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Sync/Sync-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		2827317A1ABC9BE800AA1954 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = SyncTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/SyncTests/SyncTests-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		288A2DA01AB8B3260023ABC3 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				INFOPLIST_FILE = "Shared/Supporting Files/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		2FA436151ABB83B4008031D1 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				HEADER_SEARCH_PATHS = (
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				INFOPLIST_FILE = Account/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Account/Account-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		2FA436191ABB83B4008031D1 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = AccountTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Account/Account-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		2FCAE2341ABB51F900877008 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				INFOPLIST_FILE = Storage/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				OTHER_CFLAGS = "-DSQLITE_HAS_CODEC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Storage/Storage-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		2FCAE2381ABB51F900877008 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				INFOPLIST_FILE = StorageTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Storage/Storage-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		39409A401C90E68300DAE683 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Fennec.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				INFOPLIST_FILE = Extensions/Today/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_TODAY";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = Today;
+				PROVISIONING_PROFILE_SPECIFIER = "Fennec Today Development";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		39409A411C90E68300DAE683 /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Firefox.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				INFOPLIST_FILE = Extensions/Today/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_RELEASE -DMOZ_TARGET_TODAY";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = Today;
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox Today Development";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		39409A421C90E68300DAE683 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FirefoxBeta.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				INFOPLIST_FILE = Extensions/Today/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_BETA -DMOZ_TARGET_TODAY";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = Today;
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox Beta Today Development";
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		3958DAB01ED98DCB0054AA27 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FennecEnterprise.entitlements";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				DEVELOPMENT_TEAM = 9G8J6YA743;
+				ENABLE_BITCODE = NO;
+				INFOPLIST_FILE = Extensions/NotificationService/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_LDFLAGS = "";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_NOTIFICATIONSERVICE";
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.FennecEnterprise.NotificationService;
+				PRODUCT_NAME = NotificationService;
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		397848E31ED86605004C0C0B /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Fennec.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = Extensions/NotificationService/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				OTHER_LDFLAGS = "";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_NOTIFICATIONSERVICE";
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.Fennec.NotificationService;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "2ca221e2-03db-45b5-ad98-41b0caa46000";
+				PROVISIONING_PROFILE_SPECIFIER = "Fennec NotificationService Development";
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		397848E51ED86605004C0C0B /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Firefox.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = Extensions/NotificationService/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_LDFLAGS = "";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_RELEASE -DMOZ_TARGET_NOTIFICATIONSERVICE";
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.Firefox.NotificationService;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Firefox;
+		};
+		397848E61ED86605004C0C0B /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FirefoxBeta.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = Extensions/NotificationService/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_LDFLAGS = "";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_BETA -DMOZ_TARGET_NOTIFICATIONSERVICE";
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.FirefoxBeta.NotificationService2;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = FirefoxBeta;
+		};
+		3B43E3D71D95C48E00BBA9DB /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVES = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = StoragePerfTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = com.mozilla.StoragePerfTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		3B43E3D81D95C48E00BBA9DB /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVES = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = StoragePerfTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = com.mozilla.StoragePerfTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Firefox;
+		};
+		3B43E3D91D95C48E00BBA9DB /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVES = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = StoragePerfTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = com.mozilla.StoragePerfTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = FirefoxBeta;
+		};
+		3BFE4B0E1D342FB900DDF53F /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = XCUITests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = com.mozilla.XCUITests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/XCUITests/XCUITests-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = Client;
+			};
+			name = Fennec;
+		};
+		3BFE4B0F1D342FB900DDF53F /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = XCUITests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = com.mozilla.XCUITests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = Client;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Firefox;
+		};
+		3BFE4B101D342FB900DDF53F /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = XCUITests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = com.mozilla.XCUITests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = Client;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = FirefoxBeta;
+		};
+		D39FA1681A83E0EC00EE869C /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				INFOPLIST_FILE = UITests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.allizom.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/UITests/UITests-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		D39FA1691A83E0EC00EE869C /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				INFOPLIST_FILE = UITests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.allizom.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Release;
+		};
+		E448FC9D1AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = E60961891B62B8C800DD640F /* Firefox.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				APPLICATION_EXTENSION_API_ONLY = NO;
+				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_ACTIVITY_MODE = "";
+				"DEBUG_ACTIVITY_MODE[sdk=iphonesimulator*]" = disable;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = "$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)";
+				MOZ_INTERNAL_URL_SCHEME = "firefox-internal";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_LDFLAGS = (
+					"-ObjC",
+					"-lxml2",
+				);
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_RELEASE";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
+				SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Storage/modules";
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Firefox;
+		};
+		E448FC9E1AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Client/Entitlements/FirefoxApplication.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(PROJECT_DIR)/ThirdParty/BuddyBuild",
+					"$(PROJECT_DIR)/ThirdParty/Leanplum",
+				);
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Debug$(EFFECTIVE_PLATFORM_NAME)/include/**",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				INFOPLIST_FILE = Client/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				OTHER_LDFLAGS = (
+					"-ObjC",
+					"-lxml2",
+				);
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_RELEASE -DMOZ_TARGET_CLIENT";
+				PRODUCT_MODULE_NAME = Client;
+				PRODUCT_NAME = Client;
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox Development";
+				SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/Client-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E448FC9F1AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+				INFOPLIST_FILE = ClientTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = ClientTests;
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Firefox;
+		};
+		E448FCA01AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Firefox.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/ShareTo/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_RELEASE -DMOZ_TARGET_SHARETO";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox ShareTo Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Firefox;
+		};
+		E448FCA11AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Firefox.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/SendTo/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_RELEASE -DMOZ_TARGET_SENDTO";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox SendTo Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E448FCA21AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.allizom.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = UITests;
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E448FCA31AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = "Shared/Supporting Files/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E448FCA41AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = Storage/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_CFLAGS = "-DSQLITE_HAS_CODEC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Storage/Storage-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E448FCA51AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				INFOPLIST_FILE = StorageTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Storage/Storage-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Firefox;
+		};
+		E448FCA61AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				HEADER_SEARCH_PATHS = (
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				INFOPLIST_FILE = Account/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Account/Account-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E448FCA71AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = AccountTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Account/Account-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Firefox;
+		};
+		E448FCA81AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Sync/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Sync/Sync-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E448FCA91AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = SyncTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/SyncTests/SyncTests-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Firefox;
+		};
+		E448FCAA1AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = ReadingList/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E448FCAB1AEE7A6000869B6C /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				INFOPLIST_FILE = ReadingListTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Firefox;
+		};
+		E4BA8A361B4B0A1700BC2E95 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Fennec.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/ViewLater/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_VIEWLATER";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Fennec View Later Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		E4BA8A381B4B0A1700BC2E95 /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Firefox.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/ViewLater/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_RELEASE -DMOZ_TARGET_VIEWLATER";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox View Later Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+			};
+			name = Firefox;
+		};
+		E4D567311ADECE2900F1EFE7 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = ReadingList/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		E4D567341ADECE2900F1EFE7 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				INFOPLIST_FILE = ReadingListTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		E601384C1C89EAE600DF9756 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = L10nSnapshotTests;
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = Client;
+				USES_XCTRUNNER = YES;
+			};
+			name = Fennec;
+		};
+		E601384D1C89EAE600DF9756 /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = L10nSnapshotTests;
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = Client;
+				USES_XCTRUNNER = YES;
+			};
+			name = Firefox;
+		};
+		E601384E1C89EAE600DF9756 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = L10nSnapshotTests;
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = Client;
+				USES_XCTRUNNER = YES;
+			};
+			name = FirefoxBeta;
+		};
+		E60138511C89EAE600DF9756 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = MarketingUITests;
+			};
+			name = Fennec;
+		};
+		E60138521C89EAE600DF9756 /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = MarketingUITests;
+			};
+			name = Firefox;
+		};
+		E60138531C89EAE600DF9756 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = MarketingUITests;
+			};
+			name = FirefoxBeta;
+		};
+		E69DB08D1E97DEAA008A67E6 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				APPLICATION_EXTENSION_API_ONLY = NO;
+				APP_IDENTIFIER_PREFIX = 9G8J6YA743;
+				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = SyncTelemetry/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.SyncTelemetry;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Fennec;
+		};
+		E69DB08E1E97DEAA008A67E6 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = SyncTelemetry/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.SyncTelemetry;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Fennec_Enterprise;
+		};
+		E69DB08F1E97DEAA008A67E6 /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = SyncTelemetry/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.SyncTelemetry;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Firefox;
+		};
+		E69DB0901E97DEAA008A67E6 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = SyncTelemetry/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.SyncTelemetry;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = FirefoxBeta;
+		};
+		E69DB0931E97DEAA008A67E6 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = SyncTelemetryTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.SyncTelemetryTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		E69DB0941E97DEAA008A67E6 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = SyncTelemetryTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.SyncTelemetryTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Fennec_Enterprise;
+		};
+		E69DB0951E97DEAA008A67E6 /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = SyncTelemetryTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.SyncTelemetryTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Firefox;
+		};
+		E69DB0961E97DEAA008A67E6 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = SyncTelemetryTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = org.mozilla.ios.SyncTelemetryTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = FirefoxBeta;
+		};
+		E6DCC2051DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = E6DCC1ED1DCBB6AA00CEC4B7 /* Fennec.enterprise.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				APPLICATION_EXTENSION_API_ONLY = NO;
+				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_ACTIVITY_MODE = "";
+				"DEBUG_ACTIVITY_MODE[sdk=iphonesimulator*]" = disable;
+				DEVELOPMENT_TEAM = 9G8J6YA743;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = "$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)";
+				MOZ_INTERNAL_URL_SCHEME = fennec;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				OTHER_LDFLAGS = (
+					"-ObjC",
+					"-lxml2",
+				);
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
+				SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Storage/modules";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2061DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon_Developer;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Client/Entitlements/FennecEnterpriseApplication.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(PROJECT_DIR)/ThirdParty/BuddyBuild",
+					"$(PROJECT_DIR)/ThirdParty/Leanplum",
+				);
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Debug$(EFFECTIVE_PLATFORM_NAME)/include/**",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				INFOPLIST_FILE = Client/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				OTHER_LDFLAGS = (
+					"-ObjC",
+					"-lxml2",
+					"-framework",
+					BuddyBuildSDK,
+					"-framework",
+					AssetsLibrary,
+					"-framework",
+					CoreText,
+					"-framework",
+					CoreTelephony,
+					"-framework",
+					SystemConfiguration,
+					"-framework",
+					QuartzCore,
+					"-framework",
+					CoreVideo,
+					"-framework",
+					AVFoundation,
+					"-framework",
+					CoreMedia,
+				);
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_CLIENT";
+				PRODUCT_MODULE_NAME = Client;
+				PRODUCT_NAME = Client;
+				PROVISIONING_PROFILE_SPECIFIER = "FennecEnterprise Development";
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = BUDDYBUILD;
+				SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/Client-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2071DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FennecEnterprise.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/SendTo/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_SENDTO";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "FennecEnterprise SendTo Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2081DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FennecEnterprise.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/ShareTo/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_SHARETO";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "FennecEnterprise Share To Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2091DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FennecEnterprise.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				INFOPLIST_FILE = Extensions/Today/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_TODAY";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = Today;
+				PROVISIONING_PROFILE_SPECIFIER = "FennecEnterprise Today Development";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC20A1DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FennecEnterprise.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/ViewLater/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_VIEWLATER";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "FennecEnterprise ViewLater Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC20B1DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				INFOPLIST_FILE = "Shared/Supporting Files/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC20C1DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				INFOPLIST_FILE = Storage/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				OTHER_CFLAGS = "-DSQLITE_HAS_CODEC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Storage/Storage-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC20D1DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				HEADER_SEARCH_PATHS = (
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				INFOPLIST_FILE = Account/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Account/Account-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC20E1DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Sync/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Sync/Sync-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC20F1DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = ReadingList/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2101DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = ClientTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = ClientTests;
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2111DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				INFOPLIST_FILE = UITests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.allizom.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/UITests/UITests-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2131DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				INFOPLIST_FILE = StorageTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Storage/Storage-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2141DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = AccountTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Account/Account-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2151DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = SyncTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/SyncTests/SyncTests-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2161DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				INFOPLIST_FILE = ReadingListTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2171DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = SharedTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2181DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = L10nSnapshotTests;
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = Client;
+				USES_XCTRUNNER = YES;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC2191DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = MarketingUITests;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC21A1DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = XCUITests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = com.mozilla.XCUITests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/XCUITests/XCUITests-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = Client;
+			};
+			name = Fennec_Enterprise;
+		};
+		E6DCC21B1DCBB6F100CEC4B7 /* Fennec_Enterprise */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVES = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				INFOPLIST_FILE = StoragePerfTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = com.mozilla.StoragePerfTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec_Enterprise;
+		};
+		E6F965151B2F1CF20034B023 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = SharedTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		E6F965171B2F1CF20034B023 /* Firefox */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = SharedTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Firefox;
+		};
+		E6FCC4291C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = E6FCC43C1C40565200DF6113 /* FirefoxBeta.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				APPLICATION_EXTENSION_API_ONLY = NO;
+				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_ACTIVITY_MODE = "";
+				"DEBUG_ACTIVITY_MODE[sdk=iphonesimulator*]" = disable;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = "$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)";
+				MOZ_INTERNAL_URL_SCHEME = "firefox-beta";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_LDFLAGS = (
+					"-ObjC",
+					"-lxml2",
+				);
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_BETA";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
+				SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Storage/modules";
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC42A1C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon_Beta;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Client/Entitlements/FirefoxBetaApplication.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(PROJECT_DIR)/ThirdParty/BuddyBuild",
+					"$(PROJECT_DIR)/ThirdParty/Leanplum",
+				);
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Debug$(EFFECTIVE_PLATFORM_NAME)/include/**",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				INFOPLIST_FILE = Client/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				OTHER_LDFLAGS = (
+					"-ObjC",
+					"-lxml2",
+				);
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_BETA -DMOZ_TARGET_CLIENT";
+				PRODUCT_MODULE_NAME = Client;
+				PRODUCT_NAME = Client;
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox Beta Development";
+				SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/Client-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC42B1C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = ClientTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = ClientTests;
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC42C1C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FirefoxBeta.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/SendTo/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_BETA -DMOZ_TARGET_SENDTO";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox Beta SentTo Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC42D1C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FirefoxBeta.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/ShareTo/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_BETA -DMOZ_TARGET_SHARETO";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox Beta ShareTo Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC42E1C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/FirefoxBeta.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = "";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/ViewLater/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_BETA -DMOZ_TARGET_VIEWLATER";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Firefox Beta ViewLater Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC42F1C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.allizom.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = UITests;
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4311C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = "Shared/Supporting Files/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4321C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = Storage/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_CFLAGS = "-DSQLITE_HAS_CODEC";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Storage/Storage-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4331C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				INFOPLIST_FILE = StorageTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Storage/Storage-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4341C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				HEADER_SEARCH_PATHS = (
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				INFOPLIST_FILE = Account/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Account/Account-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4351C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = AccountTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Account/Account-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4361C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_BITCODE = NO;
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Sync/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Sync/Sync-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4371C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = SyncTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/SyncTests/SyncTests-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4381C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = ReadingList/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_VERSION = 3.0;
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC4391C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				INFOPLIST_FILE = ReadingListTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = FirefoxBeta;
+		};
+		E6FCC43A1C40562400DF6113 /* FirefoxBeta */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = SharedTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = FirefoxBeta;
+		};
+		F84B21DB1A090F8100AAB793 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = E60961861B62B8A700DD640F /* Fennec.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				APPLICATION_EXTENSION_API_ONLY = NO;
+				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_ACTIVITY_MODE = "";
+				"DEBUG_ACTIVITY_MODE[sdk=iphonesimulator*]" = disable;
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				IPHONEOS_DEPLOYMENT_TARGET = 10.3;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = "$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)";
+				MOZ_INTERNAL_URL_SCHEME = fennec;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				OTHER_LDFLAGS = (
+					"-ObjC",
+					"-lxml2",
+				);
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
+				SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Storage/modules";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Fennec;
+		};
+		F84B21DE1A090F8100AAB793 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon_Developer;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Client/Entitlements/FennecApplication.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(PROJECT_DIR)/ThirdParty/BuddyBuild",
+					"$(PROJECT_DIR)/ThirdParty/Leanplum",
+				);
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)",
+					"$(SDKROOT)/usr/include/libxml2",
+					"$(BUILD_DIR)/Debug$(EFFECTIVE_PLATFORM_NAME)/include/**",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)/include/**",
+				);
+				INFOPLIST_FILE = Client/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				OTHER_LDFLAGS = (
+					"-ObjC",
+					"-lxml2",
+					"-framework",
+					BuddyBuildSDK,
+					"-framework",
+					AssetsLibrary,
+					"-framework",
+					CoreText,
+					"-framework",
+					CoreTelephony,
+					"-framework",
+					SystemConfiguration,
+					"-framework",
+					QuartzCore,
+					"-framework",
+					CoreVideo,
+					"-framework",
+					AVFoundation,
+					"-framework",
+					CoreMedia,
+				);
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_CLIENT";
+				PRODUCT_MODULE_NAME = Client;
+				PRODUCT_NAME = Client;
+				PROVISIONING_PROFILE_SPECIFIER = "Fennec Development";
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = BUDDYBUILD;
+				SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/Client-Bridging-Header.h";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+		F84B21E11A090F8100AAB793 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = ClientTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = ClientTests;
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client";
+			};
+			name = Fennec;
+		};
+		F84B22561A0920C600AAB793 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Fennec.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/ShareTo/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_SHARETO";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Fennec ShareTo Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Fennec;
+		};
+		F84B22681A09210A00AAB793 /* Fennec */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				APPLICATION_EXTENSION_API_ONLY = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/Extensions/Entitlements/Fennec.entitlements";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = 43AQ936H96;
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+					"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)",
+				);
+				INFOPLIST_FILE = Extensions/SendTo/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../Frameworks";
+				OTHER_SWIFT_FLAGS = "-DMOZ_CHANNEL_FENNEC -DMOZ_TARGET_SENDTO";
+				PRODUCT_BUNDLE_IDENTIFIER = "$(MOZ_BUNDLE_ID).$(PRODUCT_NAME:rfc1034identifier)";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "Fennec SendTo Development";
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+			};
+			name = Fennec;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		282731971ABC9BE800AA1954 /* Build configuration list for PBXNativeTarget "Sync" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				282731771ABC9BE800AA1954 /* Fennec */,
+				E6DCC20E1DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA81AEE7A6000869B6C /* Firefox */,
+				E6FCC4361C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		282731981ABC9BE800AA1954 /* Build configuration list for PBXNativeTarget "SyncTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2827317A1ABC9BE800AA1954 /* Fennec */,
+				E6DCC2151DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA91AEE7A6000869B6C /* Firefox */,
+				E6FCC4371C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		288A2D9F1AB8B3260023ABC3 /* Build configuration list for PBXNativeTarget "Shared" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				288A2DA01AB8B3260023ABC3 /* Fennec */,
+				E6DCC20B1DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA31AEE7A6000869B6C /* Firefox */,
+				E6FCC4311C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		2FA436141ABB83B4008031D1 /* Build configuration list for PBXNativeTarget "Account" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2FA436151ABB83B4008031D1 /* Fennec */,
+				E6DCC20D1DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA61AEE7A6000869B6C /* Firefox */,
+				E6FCC4341C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		2FA436181ABB83B4008031D1 /* Build configuration list for PBXNativeTarget "AccountTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2FA436191ABB83B4008031D1 /* Fennec */,
+				E6DCC2141DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA71AEE7A6000869B6C /* Firefox */,
+				E6FCC4351C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		2FCAE2331ABB51F900877008 /* Build configuration list for PBXNativeTarget "Storage" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2FCAE2341ABB51F900877008 /* Fennec */,
+				E6DCC20C1DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA41AEE7A6000869B6C /* Firefox */,
+				E6FCC4321C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		2FCAE2371ABB51F900877008 /* Build configuration list for PBXNativeTarget "StorageTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2FCAE2381ABB51F900877008 /* Fennec */,
+				E6DCC2131DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA51AEE7A6000869B6C /* Firefox */,
+				E6FCC4331C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		39409A521C90E68300DAE683 /* Build configuration list for PBXNativeTarget "Today" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				39409A401C90E68300DAE683 /* Fennec */,
+				E6DCC2091DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				39409A411C90E68300DAE683 /* Firefox */,
+				39409A421C90E68300DAE683 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		397848F51ED86605004C0C0B /* Build configuration list for PBXNativeTarget "NotificationService" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				397848E31ED86605004C0C0B /* Fennec */,
+				397848E51ED86605004C0C0B /* Firefox */,
+				397848E61ED86605004C0C0B /* FirefoxBeta */,
+				3958DAB01ED98DCB0054AA27 /* Fennec_Enterprise */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		3B43E3E91D95C48E00BBA9DB /* Build configuration list for PBXNativeTarget "StoragePerfTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				3B43E3D71D95C48E00BBA9DB /* Fennec */,
+				E6DCC21B1DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				3B43E3D81D95C48E00BBA9DB /* Firefox */,
+				3B43E3D91D95C48E00BBA9DB /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		3BFE4B201D342FB900DDF53F /* Build configuration list for PBXNativeTarget "XCUITests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				3BFE4B0E1D342FB900DDF53F /* Fennec */,
+				E6DCC21A1DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				3BFE4B0F1D342FB900DDF53F /* Firefox */,
+				3BFE4B101D342FB900DDF53F /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		D39FA1671A83E0EC00EE869C /* Build configuration list for PBXNativeTarget "UITests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				D39FA1681A83E0EC00EE869C /* Fennec */,
+				E6DCC2111DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				D39FA1691A83E0EC00EE869C /* Release */,
+				E448FCA21AEE7A6000869B6C /* Firefox */,
+				E6FCC42F1C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		E4BA8A581B4B0A1700BC2E95 /* Build configuration list for PBXNativeTarget "ViewLater" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E4BA8A361B4B0A1700BC2E95 /* Fennec */,
+				E6DCC20A1DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E4BA8A381B4B0A1700BC2E95 /* Firefox */,
+				E6FCC42E1C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		E4D567531ADECE2900F1EFE7 /* Build configuration list for PBXNativeTarget "ReadingList" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E4D567311ADECE2900F1EFE7 /* Fennec */,
+				E6DCC20F1DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCAA1AEE7A6000869B6C /* Firefox */,
+				E6FCC4381C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		E4D567541ADECE2900F1EFE7 /* Build configuration list for PBXNativeTarget "ReadingListTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E4D567341ADECE2900F1EFE7 /* Fennec */,
+				E6DCC2161DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCAB1AEE7A6000869B6C /* Firefox */,
+				E6FCC4391C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		E60138631C89EAE700DF9756 /* Build configuration list for PBXNativeTarget "L10nSnapshotTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E601384C1C89EAE600DF9756 /* Fennec */,
+				E6DCC2181DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E601384D1C89EAE600DF9756 /* Firefox */,
+				E601384E1C89EAE600DF9756 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		E60138641C89EAE700DF9756 /* Build configuration list for PBXNativeTarget "MarketingUITests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E60138511C89EAE600DF9756 /* Fennec */,
+				E6DCC2191DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E60138521C89EAE600DF9756 /* Firefox */,
+				E60138531C89EAE600DF9756 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		E69DB08C1E97DEAA008A67E6 /* Build configuration list for PBXNativeTarget "SyncTelemetry" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E69DB08D1E97DEAA008A67E6 /* Fennec */,
+				E69DB08E1E97DEAA008A67E6 /* Fennec_Enterprise */,
+				E69DB08F1E97DEAA008A67E6 /* Firefox */,
+				E69DB0901E97DEAA008A67E6 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		E69DB0921E97DEAA008A67E6 /* Build configuration list for PBXNativeTarget "SyncTelemetryTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E69DB0931E97DEAA008A67E6 /* Fennec */,
+				E69DB0941E97DEAA008A67E6 /* Fennec_Enterprise */,
+				E69DB0951E97DEAA008A67E6 /* Firefox */,
+				E69DB0961E97DEAA008A67E6 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		E6F965381B2F1CF20034B023 /* Build configuration list for PBXNativeTarget "SharedTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E6F965151B2F1CF20034B023 /* Fennec */,
+				E6DCC2171DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E6F965171B2F1CF20034B023 /* Firefox */,
+				E6FCC43A1C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		F84B21B91A090F8100AAB793 /* Build configuration list for PBXProject "Client" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F84B21DB1A090F8100AAB793 /* Fennec */,
+				E6DCC2051DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FC9D1AEE7A6000869B6C /* Firefox */,
+				E6FCC4291C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		F84B21DD1A090F8100AAB793 /* Build configuration list for PBXNativeTarget "Client" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F84B21DE1A090F8100AAB793 /* Fennec */,
+				E6DCC2061DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FC9E1AEE7A6000869B6C /* Firefox */,
+				E6FCC42A1C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		F84B21E01A090F8100AAB793 /* Build configuration list for PBXNativeTarget "ClientTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F84B21E11A090F8100AAB793 /* Fennec */,
+				E6DCC2101DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FC9F1AEE7A6000869B6C /* Firefox */,
+				E6FCC42B1C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		F84B22551A0920C600AAB793 /* Build configuration list for PBXNativeTarget "ShareTo" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F84B22561A0920C600AAB793 /* Fennec */,
+				E6DCC2081DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA01AEE7A6000869B6C /* Firefox */,
+				E6FCC42D1C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+		F84B22671A09210A00AAB793 /* Build configuration list for PBXNativeTarget "SendTo" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F84B22681A09210A00AAB793 /* Fennec */,
+				E6DCC2071DCBB6F100CEC4B7 /* Fennec_Enterprise */,
+				E448FCA11AEE7A6000869B6C /* Firefox */,
+				E6FCC42C1C40562400DF6113 /* FirefoxBeta */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Fennec;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = F84B21B61A090F8100AAB793 /* Project object */;
+}
diff --git a/mobile/ios/Client.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mobile/ios/Client.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..9c19f56bf0
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mobile/ios/Client.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000000..0c67376eba
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/2FCAE2231ABB51F800877008.xcbaseline/FE8885C6-BB1A-48D2-9B90-E9F952C98F6B.plist b/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/2FCAE2231ABB51F800877008.xcbaseline/FE8885C6-BB1A-48D2-9B90-E9F952C98F6B.plist
new file mode 100644
index 0000000000..4ee1dc46e5
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/2FCAE2231ABB51F800877008.xcbaseline/FE8885C6-BB1A-48D2-9B90-E9F952C98F6B.plist
@@ -0,0 +1,22 @@
+
+
+
+
+	classNames
+	
+		TestSQLiteHistoryFrecencyPerf
+		
+			testFrecencyPerf()
+			
+				com.apple.XCTPerformanceMetric_WallClockTime
+				
+					baselineAverage
+					0.16
+					baselineIntegrationDisplayName
+					 30 Jul 2015, Jul 30 07:02:07 
+				
+			
+		
+	
+
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/2FCAE2231ABB51F800877008.xcbaseline/Info.plist b/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/2FCAE2231ABB51F800877008.xcbaseline/Info.plist
new file mode 100644
index 0000000000..e2f0962393
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/2FCAE2231ABB51F800877008.xcbaseline/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+	runDestinationsByUUID
+	
+		FE8885C6-BB1A-48D2-9B90-E9F952C98F6B
+		
+			localComputer
+			
+				busSpeedInMHz
+				100
+				cpuCount
+				1
+				cpuKind
+				Intel Core i7
+				cpuSpeedInMHz
+				3100
+				logicalCPUCoresPerPackage
+				4
+				modelCode
+				MacBookPro12,1
+				physicalCPUCoresPerPackage
+				2
+				platformIdentifier
+				com.apple.platform.macosx
+			
+			targetArchitecture
+			x86_64
+			targetDevice
+			
+				modelCode
+				iPhone7,2
+				platformIdentifier
+				com.apple.platform.iphonesimulator
+			
+		
+	
+
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/E6F9650B1B2F1CF20034B023.xcbaseline/F9839E4F-67D2-4920-8CE8-94CEE3A6C3D7.plist b/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/E6F9650B1B2F1CF20034B023.xcbaseline/F9839E4F-67D2-4920-8CE8-94CEE3A6C3D7.plist
new file mode 100644
index 0000000000..310b1e7a0a
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/E6F9650B1B2F1CF20034B023.xcbaseline/F9839E4F-67D2-4920-8CE8-94CEE3A6C3D7.plist
@@ -0,0 +1,22 @@
+
+
+
+
+	classNames
+	
+		EffectiveTLDUtilsTests
+		
+			testTLDEntriesLoadFromDiskPerformance()
+			
+				com.apple.XCTPerformanceMetric_WallClockTime
+				
+					baselineAverage
+					0.36
+					baselineIntegrationDisplayName
+					Local Baseline
+				
+			
+		
+	
+
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/E6F9650B1B2F1CF20034B023.xcbaseline/Info.plist b/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/E6F9650B1B2F1CF20034B023.xcbaseline/Info.plist
new file mode 100644
index 0000000000..fecefec129
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcbaselines/E6F9650B1B2F1CF20034B023.xcbaseline/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+	runDestinationsByUUID
+	
+		F9839E4F-67D2-4920-8CE8-94CEE3A6C3D7
+		
+			localComputer
+			
+				busSpeedInMHz
+				100
+				cpuCount
+				1
+				cpuKind
+				Intel Core i7
+				cpuSpeedInMHz
+				2800
+				logicalCPUCoresPerPackage
+				8
+				modelCode
+				MacBookPro11,3
+				physicalCPUCoresPerPackage
+				4
+				platformIdentifier
+				com.apple.platform.macosx
+			
+			targetArchitecture
+			x86_64
+			targetDevice
+			
+				modelCode
+				iPhone7,2
+				platformIdentifier
+				com.apple.platform.iphonesimulator
+			
+		
+	
+
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Account.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Account.xcscheme
new file mode 100644
index 0000000000..bc5dd22bd1
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Account.xcscheme
@@ -0,0 +1,104 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+            
+               
+               
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec.xcscheme
new file mode 100644
index 0000000000..51261d4078
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec.xcscheme
@@ -0,0 +1,199 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+         
+            
+            
+            
+               
+               
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+            
+               
+               
+               
+               
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise.xcscheme
new file mode 100644
index 0000000000..6453158497
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise.xcscheme
@@ -0,0 +1,213 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+            
+               
+               
+               
+               
+               
+               
+               
+               
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+            
+               
+               
+               
+               
+            
+         
+         
+            
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_UITests.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_UITests.xcscheme
new file mode 100644
index 0000000000..c89b48a6b7
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_UITests.xcscheme
@@ -0,0 +1,319 @@
+
+
+   
+      
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+         
+            
+            
+            
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+            
+         
+      
+      
+         
+         
+      
+      
+         
+         
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+      
+         
+            
+            
+         
+      
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_XCUITests.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_XCUITests.xcscheme
new file mode 100644
index 0000000000..940a62ba45
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_XCUITests.xcscheme
@@ -0,0 +1,294 @@
+
+
+   
+      
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+         
+            
+            
+         
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+         
+         
+      
+      
+         
+         
+      
+      
+         
+         
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+      
+         
+            
+            
+         
+      
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_XCUITests_iPad.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_XCUITests_iPad.xcscheme
new file mode 100644
index 0000000000..d511ab999a
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Fennec_Enterprise_XCUITests_iPad.xcscheme
@@ -0,0 +1,294 @@
+
+
+   
+      
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+         
+            
+            
+            
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+               
+            
+         
+      
+      
+         
+         
+      
+      
+         
+         
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+      
+         
+            
+            
+         
+      
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Firefox.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Firefox.xcscheme
new file mode 100644
index 0000000000..4432205890
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Firefox.xcscheme
@@ -0,0 +1,201 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+            
+               
+               
+            
+         
+         
+            
+            
+            
+               
+               
+            
+         
+         
+            
+            
+         
+         
+            
+            
+            
+               
+               
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+            
+               
+               
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/FirefoxBeta.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/FirefoxBeta.xcscheme
new file mode 100644
index 0000000000..fe3954f939
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/FirefoxBeta.xcscheme
@@ -0,0 +1,201 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+            
+               
+               
+            
+         
+         
+            
+            
+            
+               
+               
+            
+         
+         
+            
+            
+         
+         
+            
+            
+            
+               
+               
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+         
+         
+            
+            
+            
+               
+               
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/L10nSnapshotTests.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/L10nSnapshotTests.xcscheme
new file mode 100644
index 0000000000..d773100859
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/L10nSnapshotTests.xcscheme
@@ -0,0 +1,93 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/MarketingUITests.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/MarketingUITests.xcscheme
new file mode 100644
index 0000000000..7f195f25a2
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/MarketingUITests.xcscheme
@@ -0,0 +1,93 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ReadingList.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ReadingList.xcscheme
new file mode 100644
index 0000000000..5895c7f40d
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ReadingList.xcscheme
@@ -0,0 +1,113 @@
+
+
+   
+      
+         
+            
+            
+         
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/SendTo.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/SendTo.xcscheme
new file mode 100644
index 0000000000..e12a817e38
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/SendTo.xcscheme
@@ -0,0 +1,99 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ShareTo.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ShareTo.xcscheme
new file mode 100644
index 0000000000..3dbd7d6e72
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ShareTo.xcscheme
@@ -0,0 +1,99 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Shared.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Shared.xcscheme
new file mode 100644
index 0000000000..7b3ef1cb36
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Shared.xcscheme
@@ -0,0 +1,99 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Storage.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Storage.xcscheme
new file mode 100644
index 0000000000..e3ed976da6
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Storage.xcscheme
@@ -0,0 +1,109 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+         
+            
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Sync.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Sync.xcscheme
new file mode 100644
index 0000000000..68b214cb86
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Sync.xcscheme
@@ -0,0 +1,121 @@
+
+
+   
+      
+         
+            
+            
+         
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+            
+               
+               
+               
+               
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Telemetry.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Telemetry.xcscheme
new file mode 100644
index 0000000000..5adf21e183
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Telemetry.xcscheme
@@ -0,0 +1,101 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Today.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Today.xcscheme
new file mode 100644
index 0000000000..4ac66e7ed4
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/Today.xcscheme
@@ -0,0 +1,125 @@
+
+
+   
+      
+         
+            
+            
+         
+         
+            
+            
+         
+      
+   
+   
+      
+         
+            
+            
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ViewLater.xcscheme b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ViewLater.xcscheme
new file mode 100644
index 0000000000..75b9d5efdc
--- /dev/null
+++ b/mobile/ios/Client.xcodeproj/xcshareddata/xcschemes/ViewLater.xcscheme
@@ -0,0 +1,99 @@
+
+
+   
+      
+         
+            
+            
+         
+      
+   
+   
+      
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+      
+         
+         
+      
+      
+      
+   
+   
+      
+         
+         
+      
+   
+   
+   
+   
+   
+
diff --git a/mobile/ios/Client/Application/AdjustIntegration.swift b/mobile/ios/Client/Application/AdjustIntegration.swift
new file mode 100644
index 0000000000..8c7e6ca290
--- /dev/null
+++ b/mobile/ios/Client/Application/AdjustIntegration.swift
@@ -0,0 +1,195 @@
+/* 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/. */
+
+import Foundation
+import Shared
+import AdjustSdk
+
+private let AdjustIntegrationErrorDomain = "org.mozilla.ios.Firefox.AdjustIntegrationErrorDomain"
+
+private let AdjustAttributionFileName = "AdjustAttribution.json"
+
+private let AdjustAppTokenKey = "AdjustAppToken"
+private let AdjustEnvironmentKey = "AdjustEnvironment"
+
+private let AdjustSandboxEnvironment = "sandbox"
+private let AdjustProductionEnvironment = "production"
+
+private enum AdjustEnvironment: String {
+    case Sandbox = "sandbox"
+    case Production = "production"
+}
+
+private struct AdjustSettings {
+    var appToken: String
+    var environment: AdjustEnvironment
+}
+
+/// Simple (singleton) object to contain all code related to Adjust. The idea is to capture all logic
+/// here so that we have one single place where we can see what Adjust is doing. Ideally you only call
+/// functions in this object from other parts of the application.
+
+class AdjustIntegration: NSObject {
+    let profile: Profile
+    
+    init(profile: Profile) {
+        self.profile = profile
+    }
+
+    /// Return an ADJConfig object if Adjust has been enabled. It is determined from the values in
+    /// the Info.plist file if Adjust should be enabled, and if so, what its application token and
+    /// environment are. If those keys are either missing or empty in the Info.plist then it is
+    /// assumed that Adjust is not enabled for this build.
+
+    fileprivate func getConfig() -> ADJConfig? {
+        guard let settings = getSettings() else {
+            return nil
+        }
+
+        let config = ADJConfig(appToken: settings.appToken, environment: settings.environment.rawValue)
+        if settings.environment == .Sandbox {
+            config?.logLevel = ADJLogLevelDebug
+        }
+        config?.delegate = self
+        return config
+    }
+
+    /// Returns the Adjust settings from our Info.plist. If the settings are missing or invalid, such as an unknown
+    /// environment, then it will return nil.
+
+    fileprivate func getSettings() -> AdjustSettings? {
+        let bundle = Bundle.main
+        guard let adjustAppToken = bundle.object(forInfoDictionaryKey: AdjustAppTokenKey) as? String,
+                let adjustEnvironment = bundle.object(forInfoDictionaryKey: AdjustEnvironmentKey) as? String else {
+            return nil
+        }
+        guard !adjustAppToken.isEmpty && !adjustEnvironment.isEmpty else {
+            return nil
+        }
+        guard let environment = AdjustEnvironment(rawValue: adjustEnvironment) else {
+            Logger.browserLogger.error("Adjust - Invalid environment provided: \(adjustEnvironment)")
+            return nil
+        }
+        return AdjustSettings(appToken: adjustAppToken, environment: environment)
+    }
+
+    /// Returns true if the attribution file is present.
+
+    fileprivate func hasAttribution() throws -> Bool {
+        return FileManager.default.fileExists(atPath: try getAttributionPath())
+    }
+
+    /// Save an `ADJAttribution` instance to a JSON file. Throws an error if the file could not be written. The file
+    /// written is a JSON file with a single dictionary in it. We add one extra item to it that contains the current
+    /// timestamp in seconds since the UNIX epoch.
+
+    fileprivate func saveAttribution(_ attribution: ADJAttribution) throws {
+        if let attributionDictionary = attribution.dictionary() {
+            let dictionary = NSMutableDictionary(dictionary: attributionDictionary)
+            dictionary["_timestamp"] = NSNumber(value: Int64(Date().timeIntervalSince1970) as Int64)
+            let data = try JSONSerialization.data(withJSONObject: dictionary, options: [JSONSerialization.WritingOptions.prettyPrinted])
+            try data.write(to: URL(fileURLWithPath: try getAttributionPath()), options: [])
+        }
+    }
+
+    /// Return the path to the `AdjustAttribution.json` file. Throws an `NSError` if we could not build the path.
+
+    fileprivate func getAttributionPath() throws -> String {
+        guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
+            throw NSError(domain: AdjustIntegrationErrorDomain, code: -1,
+                userInfo: [NSLocalizedDescriptionKey: "Could not build \(AdjustAttributionFileName) path"])
+        }
+        
+        return url.appendingPathComponent(AdjustAttributionFileName).path
+    }
+
+    /// Return true if Adjust should be enabled. If the user has disabled the Send Anonymous Usage Data then we immediately
+    /// return false. Otherwise we only do one ping, which means we only enable it if we have not seen the attributiond
+    /// data yet.
+    
+    fileprivate func shouldEnable() throws -> Bool {
+        if profile.prefs.boolForKey(AppConstants.PrefSendUsageData) ?? true {
+            return true
+        }
+        return try hasAttribution() == false
+    }
+    
+    /// Return true if retention (session) tracking should be enabled. This follows the Send Anonymous Usage Data
+    /// setting.
+    
+    fileprivate func shouldTrackRetention() -> Bool {
+        return profile.prefs.boolForKey(AppConstants.PrefSendUsageData) ?? true
+    }
+}
+
+extension AdjustIntegration: AdjustDelegate {
+    /// This is called as part of `UIApplication.didFinishLaunchingWithOptions()`. We always initialize the
+    /// Adjust SDK. We always let it send the initial attribution ping. Session tracking is only enabled if
+    /// the Send Anonymous Usage Data setting is turned on.
+
+    func triggerApplicationDidFinishLaunchingWithOptions(_ launchOptions: [AnyHashable: Any]?) {
+        do {
+            if let config = getConfig() {
+                // Always initialize Adjust - otherwise we cannot enable/disable it later. Their SDK must be
+                // initialized through appDidFinishLaunching otherwise it will be in a bad state.
+                Adjust.appDidLaunch(config)
+
+                // Disable it right now if we have the attribution and if the user has disabled session tracking. If
+                // we do not have attribution yet then we wait until it comes in and at that point make the decision
+                // to disable Adjust again.
+                if try hasAttribution() {
+                    if !shouldTrackRetention() {
+                        Logger.browserLogger.info("Adjust - Disabling because sending of usage data is not allowed")
+                        Adjust.setEnabled(false)
+                    }
+                }
+            } else {
+                Logger.browserLogger.info("Adjust - Skipping because no or invalid config found")
+            }
+        } catch let error {
+            Logger.browserLogger.error("Adjust - Disabling because we failed to configure: \(error)")
+            Adjust.setEnabled(false)
+        }
+    }
+
+    /// This is called when Adjust has figured out the attribution. It will call us with a summary
+    /// of all the things it knows. Like the campaign ID. We simply save this to a local file so
+    /// that we know we have done a single attribution ping to Adjust.
+    ///
+    /// Here we also disable Adjust based on the Send Anonymous Usage Data setting.
+
+    func adjustAttributionChanged(_ attribution: ADJAttribution!) {
+        do {
+            Logger.browserLogger.info("Adjust - Saving attribution info to disk")
+            try saveAttribution(attribution)
+        } catch let error {
+            Logger.browserLogger.error("Adjust - Failed to save attribution: \(error)")
+        }
+        // Keep Adjust enabled only if the user has allowed this
+        if shouldTrackRetention() {
+            Logger.browserLogger.info("Adjust - Enabling because user allows anonymous usage data collection")
+            Adjust.setEnabled(true)
+        } else {
+            Logger.browserLogger.info("Adjust - Disabling because user does not allow anonymous usage data collection")
+            Adjust.setEnabled(false)
+        }
+    }
+
+    /// This is called from the Settings screen. The settings screen will remember the choice in the
+    /// profile and then use this method to disable or enable Adjust.
+    
+    static func setEnabled(_ enabled: Bool) {
+        Adjust.setEnabled(enabled)
+    }
+    
+    /// Store the deeplink url from Adjust SDK. Per Adjust documentation, any interstitial view launched could interfere
+    /// with launching the deeplink. We let the interstial view decide what to do with deeplink.
+    /// Ref: https://github.com/adjust/ios_sdk#deferred-deep-linking-scenario
+    
+    func adjustDeeplinkResponse(_ deeplink: URL!) -> Bool {
+        profile.prefs.setString("\(deeplink)", forKey: "AdjustDeeplinkKey")
+        return true
+    }
+
+}
diff --git a/mobile/ios/Client/Application/AppDelegate.swift b/mobile/ios/Client/Application/AppDelegate.swift
new file mode 100644
index 0000000000..ed26683162
--- /dev/null
+++ b/mobile/ios/Client/Application/AppDelegate.swift
@@ -0,0 +1,884 @@
+/* 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/. */
+
+import Shared
+import Storage
+import AVFoundation
+import XCGLogger
+import MessageUI
+import SDWebImage
+import SwiftKeychainWrapper
+import LocalAuthentication
+import SyncTelemetry
+import SwiftRouter
+import Sync
+import CoreSpotlight
+
+private let log = Logger.browserLogger
+
+let LatestAppVersionProfileKey = "latestAppVersion"
+let AllowThirdPartyKeyboardsKey = "settings.allowThirdPartyKeyboards"
+private let InitialPingSentKey = "initialPingSent"
+
+class AppDelegate: UIResponder, UIApplicationDelegate, UIViewControllerRestoration {
+    public static func viewController(withRestorationIdentifierPath identifierComponents: [Any], coder: NSCoder) -> UIViewController? {
+        return nil
+    }
+
+    var window: UIWindow?
+    var browserViewController: BrowserViewController!
+    var rootViewController: UIViewController!
+    weak var profile: Profile?
+    var tabManager: TabManager!
+    var adjustIntegration: AdjustIntegration?
+    var applicationCleanlyBackgrounded = true
+
+    weak var application: UIApplication?
+    var launchOptions: [AnyHashable: Any]?
+
+    let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
+
+    var openInFirefoxParams: LaunchParams?
+
+    var receivedURLs: [URL]?
+    var unifiedTelemetry: UnifiedTelemetry?
+
+    @discardableResult func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+        //
+        // Determine if the application cleanly exited last time it was used. We default to true in
+        // case we have never done this before. Then check if the "ApplicationCleanlyBackgrounded" user
+        // default exists and whether was properly set to true on app exit.
+        //
+        // Then we always set the user default to false. It will be set to true when we the application
+        // is backgrounded.
+        //
+
+        self.applicationCleanlyBackgrounded = true
+
+        let defaults = UserDefaults()
+        if defaults.object(forKey: "ApplicationCleanlyBackgrounded") != nil {
+            self.applicationCleanlyBackgrounded = defaults.bool(forKey: "ApplicationCleanlyBackgrounded")
+        }
+        defaults.set(false, forKey: "ApplicationCleanlyBackgrounded")
+        defaults.synchronize()
+
+        // Hold references to willFinishLaunching parameters for delayed app launch
+        self.application = application
+        self.launchOptions = launchOptions
+
+        self.window = UIWindow(frame: UIScreen.main.bounds)
+        self.window!.backgroundColor = UIColor.white
+
+        // Short circuit the app if we want to email logs from the debug menu
+        if DebugSettingsBundleOptions.launchIntoEmailComposer {
+            self.window?.rootViewController = UIViewController()
+            presentEmailComposerWithLogs()
+            return true
+        } else {
+            return startApplication(application, withLaunchOptions: launchOptions)
+        }
+    }
+
+    @discardableResult fileprivate func startApplication(_ application: UIApplication, withLaunchOptions launchOptions: [AnyHashable: Any]?) -> Bool {
+        log.info("startApplication begin")
+
+        // Need to get "settings.sendUsageData" this way so that Sentry can be initialized
+        // before getting the Profile.
+        let sendUsageData = NSUserDefaultsPrefs(prefix: "profile").boolForKey(AppConstants.PrefSendUsageData) ?? true
+        Sentry.shared.setup(sendUsageData: sendUsageData)
+        
+        // Set the Firefox UA for browsing.
+        setUserAgent()
+
+        // Start the keyboard helper to monitor and cache keyboard state.
+        KeyboardHelper.defaultHelper.startObserving()
+
+        DynamicFontHelper.defaultHelper.startObserving()
+
+        MenuHelper.defaultHelper.setItems()
+
+        let logDate = Date()
+        // Create a new sync log file on cold app launch. Note that this doesn't roll old logs.
+        Logger.syncLogger.newLogWithDate(logDate)
+
+        Logger.browserLogger.newLogWithDate(logDate)
+
+        let profile = getProfile(application)
+
+        unifiedTelemetry = UnifiedTelemetry(profile: profile)
+
+        if !DebugSettingsBundleOptions.disableLocalWebServer {
+            // Set up a web server that serves us static content. Do this early so that it is ready when the UI is presented.
+            setUpWebServer(profile)
+        }
+
+        do {
+            // for aural progress bar: play even with silent switch on, and do not stop audio from other apps (like music)
+            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: AVAudioSessionCategoryOptions.mixWithOthers)
+        } catch _ {
+            print("Error: Failed to assign AVAudioSession category to allow playing with silent switch on for aural progress bar")
+        }
+
+        let imageStore = DiskImageStore(files: profile.files, namespace: "TabManagerScreenshots", quality: UIConstants.ScreenshotQuality)
+
+        // Temporary fix for Bug 1390871 - NSInvalidArgumentException: -[WKContentView menuHelperFindInPage]: unrecognized selector
+        if #available(iOS 11, *) {
+            if let clazz = NSClassFromString("WKCont" + "ent" + "View"), let swizzledMethod = class_getInstanceMethod(TabWebViewMenuHelper.self, #selector(TabWebViewMenuHelper.swizzledMenuHelperFindInPage)) {
+                class_addMethod(clazz, MenuHelper.SelectorFindInPage, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
+            }
+        }
+
+        self.tabManager = TabManager(prefs: profile.prefs, imageStore: imageStore)
+        self.tabManager.stateDelegate = self
+
+        // Add restoration class, the factory that will return the ViewController we
+        // will restore with.
+
+        browserViewController = BrowserViewController(profile: self.profile!, tabManager: self.tabManager)
+        browserViewController.edgesForExtendedLayout = []
+
+        browserViewController.restorationIdentifier = NSStringFromClass(BrowserViewController.self)
+        browserViewController.restorationClass = AppDelegate.self
+
+        let navigationController = UINavigationController(rootViewController: browserViewController)
+        navigationController.delegate = self
+        navigationController.isNavigationBarHidden = true
+        navigationController.edgesForExtendedLayout = UIRectEdge(rawValue: 0)
+        rootViewController = navigationController
+
+        self.window!.rootViewController = rootViewController
+
+        NotificationCenter.default.addObserver(forName: NSNotification.Name.FSReadingListAddReadingListItem, object: nil, queue: nil) { (notification) -> Void in
+            if let userInfo = notification.userInfo, let url = userInfo["URL"] as? URL {
+                let title = (userInfo["Title"] as? String) ?? ""
+                profile.readingList?.createRecordWithURL(url.absoluteString, title: title, addedBy: UIDevice.current.name)
+            }
+        }
+
+        NotificationCenter.default.addObserver(forName: NotificationFirefoxAccountDeviceRegistrationUpdated, object: nil, queue: nil) { _ in
+            profile.flushAccount()
+        }
+
+        // check to see if we started 'cos someone tapped on a notification.
+        if let localNotification = launchOptions?[UIApplicationLaunchOptionsKey.localNotification] as? UILocalNotification {
+            viewURLInNewTab(localNotification)
+        }
+        
+        adjustIntegration = AdjustIntegration(profile: profile)
+
+        if LeanPlumClient.shouldEnable(profile: profile) {
+            LeanPlumClient.shared.setup(profile: profile)
+            LeanPlumClient.shared.set(enabled: true)
+        }
+
+        self.updateAuthenticationInfo()
+        SystemUtils.onFirstRun()
+
+        let fxaLoginHelper = FxALoginHelper.sharedInstance
+        fxaLoginHelper.application(application, didLoadProfile: profile)
+
+        setUpDeepLinks(application: application)
+
+        log.info("startApplication end")
+        return true
+    }
+
+    func setUpDeepLinks(application: UIApplication) {
+        let router = Router.shared
+        let rootNav = rootViewController as! UINavigationController
+
+        router.map("homepanel/:page", handler: { (params: [String: String]?) -> (Bool) in
+            guard let page = params?["page"] else {
+                return false
+            }
+
+            assert(Thread.isMainThread, "Opening homepanels requires being invoked on the main thread")
+
+            switch page {
+                case "bookmarks":
+                    self.browserViewController.openURLInNewTab(HomePanelType.bookmarks.localhostURL, isPrivileged: true)
+                case "history":
+                    self.browserViewController.openURLInNewTab(HomePanelType.history.localhostURL, isPrivileged: true)
+                case "new-private-tab":
+                    self.browserViewController.openBlankNewTab(focusLocationField: false, isPrivate: true)
+            default:
+                break
+            }
+
+            return true
+        })
+
+        // Route to general settings page like this: "...settings/general"
+        router.map("settings/:page", handler: { (params: [String: String]?) -> (Bool) in
+            guard let page = params?["page"] else {
+                return false
+            }
+
+            assert(Thread.isMainThread, "Opening settings requires being invoked on the main thread")
+
+            let settingsTableViewController = AppSettingsTableViewController()
+            settingsTableViewController.profile = self.profile
+            settingsTableViewController.tabManager = self.tabManager
+            settingsTableViewController.settingsDelegate = self.browserViewController
+
+            let controller = SettingsNavigationController(rootViewController: settingsTableViewController)
+            controller.popoverDelegate = self.browserViewController
+            controller.modalPresentationStyle = UIModalPresentationStyle.formSheet
+
+            rootNav.present(controller, animated: true, completion: nil)
+
+            switch page {
+                case "newtab":
+                    let viewController = NewTabChoiceViewController(prefs: self.getProfile(application).prefs)
+                    controller.pushViewController(viewController, animated: true)
+                case "homepage":
+                    let viewController = HomePageSettingsViewController()
+                    viewController.profile = self.getProfile(application)
+                    viewController.tabManager = self.tabManager
+                    controller.pushViewController(viewController, animated: true)
+                case "mailto":
+                    let viewController = OpenWithSettingsViewController(prefs: self.getProfile(application).prefs)
+                    controller.pushViewController(viewController, animated: true)
+                case "search":
+                    let viewController = SearchSettingsTableViewController()
+                    viewController.model = self.getProfile(application).searchEngines
+                    viewController.profile = self.getProfile(application)
+                    controller.pushViewController(viewController, animated: true)
+                case "clear-private-data":
+                    let viewController = ClearPrivateDataTableViewController()
+                    viewController.profile = self.getProfile(application)
+                    viewController.tabManager = self.tabManager
+                    controller.pushViewController(viewController, animated: true)
+                case "fxa":
+                    self.browserViewController.presentSignInViewController()
+            default:
+                break
+            }
+
+            return true
+        })
+    }
+
+    func applicationWillTerminate(_ application: UIApplication) {
+        // We have only five seconds here, so let's hope this doesn't take too long.
+        self.profile?.shutdown()
+
+        // Allow deinitializers to close our database connections.
+        self.profile = nil
+        self.tabManager = nil
+        self.browserViewController = nil
+        self.rootViewController = nil
+    }
+
+    /**
+     * We maintain a weak reference to the profile so that we can pause timed
+     * syncs when we're backgrounded.
+     *
+     * The long-lasting ref to the profile lives in BrowserViewController,
+     * which we set in application:willFinishLaunchingWithOptions:.
+     *
+     * If that ever disappears, we won't be able to grab the profile to stop
+     * syncing... but in that case the profile's deinit will take care of things.
+     */
+    func getProfile(_ application: UIApplication) -> Profile {
+        if let profile = self.profile {
+            return profile
+        }
+        let p = BrowserProfile(localName: "profile", syncDelegate: application.syncDelegate)
+        self.profile = p
+        return p
+    }
+
+    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+        // Override point for customization after application launch.
+        var shouldPerformAdditionalDelegateHandling = true
+
+        adjustIntegration?.triggerApplicationDidFinishLaunchingWithOptions(launchOptions)
+
+        #if BUDDYBUILD
+            print("Setting up BuddyBuild SDK")
+            BuddyBuildSDK.setup()
+        #endif
+        
+        window!.makeKeyAndVisible()
+
+        // Now roll logs.
+        DispatchQueue.global(qos: DispatchQoS.background.qosClass).async {
+            Logger.syncLogger.deleteOldLogsDownToSizeLimit()
+            Logger.browserLogger.deleteOldLogsDownToSizeLimit()
+        }
+
+        // If a shortcut was launched, display its information and take the appropriate action
+        if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {
+
+            QuickActions.sharedInstance.launchedShortcutItem = shortcutItem
+            // This will block "performActionForShortcutItem:completionHandler" from being called.
+            shouldPerformAdditionalDelegateHandling = false
+        }
+
+        return shouldPerformAdditionalDelegateHandling
+    }
+
+    func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
+        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
+            return false
+        }
+
+        guard let urlTypes = Bundle.main.object(forInfoDictionaryKey: "CFBundleURLTypes") as? [AnyObject],
+                let urlSchemes = urlTypes.first?["CFBundleURLSchemes"] as? [String] else {
+            // Something very strange has happened; org.mozilla.Client should be the zeroeth URL type.
+            log.error("Custom URL schemes not available for validating")
+            return false
+        }
+
+        guard let scheme = components.scheme, urlSchemes.contains(scheme) else {
+            log.warning("Cannot handle \(components.scheme ?? "nil") URL scheme")
+            return false
+        }
+
+        guard let host = url.host else {
+            log.warning("Cannot handle nil URL host")
+            return false
+        }
+
+        let query = url.getQuery()
+
+        switch host {
+        case "open-url":
+            let url = query["url"]?.unescape() ?? ""
+            let isPrivate = NSString(string: query["private"] ?? "false").boolValue
+
+            let params = LaunchParams(url: URL(string: url), isPrivate: isPrivate)
+
+            if application.applicationState == .active {
+                // If we are active then we can ask the BVC to open the new tab right away.
+                // Otherwise, we remember the URL and we open it in applicationDidBecomeActive.
+                launchFromURL(params)
+            } else {
+                openInFirefoxParams = params
+            }
+            return true
+        case "deep-link":
+            guard let url = query["url"], Bundle.main.bundleIdentifier == sourceApplication else {
+                break
+            }
+            Router.shared.routeURL(url)
+            return true
+        case "fxa-signin":
+            if AppConstants.MOZ_FXA_DEEP_LINK_FORM_FILL {
+                // FxA form filling requires a `signin` query param and host = fxa-signin
+                // Ex. firefox://fxa-signin?signin=&someQuery=...
+                guard query["signin"] != nil else {
+                    break
+                }
+                let fxaParams: FxALaunchParams
+                fxaParams = FxALaunchParams(query: query)
+                launchFxAFromURL(fxaParams)
+                return true
+            }
+            break
+        default: ()
+        }
+        return false
+    }
+
+    func launchFxAFromURL(_ params: FxALaunchParams) {
+        self.browserViewController.presentSignInViewController(params)
+    }
+
+    func launchFromURL(_ params: LaunchParams) {
+        let isPrivate = params.isPrivate ?? false
+        if let newURL = params.url {
+            self.browserViewController.switchToTabForURLOrOpen(newURL, isPrivate: isPrivate, isPrivileged: false)
+        } else {
+            self.browserViewController.openBlankNewTab(focusLocationField: true, isPrivate: isPrivate)
+        }
+
+        LeanPlumClient.shared.track(event: .openedNewTab, withParameters: ["Source": "External App or Extension" as AnyObject])
+    }
+
+    // We sync in the foreground only, to avoid the possibility of runaway resource usage.
+    // Eventually we'll sync in response to notifications.
+    func applicationDidBecomeActive(_ application: UIApplication) {
+        guard !DebugSettingsBundleOptions.launchIntoEmailComposer else {
+            return
+        }
+
+        //
+        // We are back in the foreground, so set CleanlyBackgrounded to false so that we can detect that
+        // the application was cleanly backgrounded later.
+        //
+
+        let defaults = UserDefaults()
+        defaults.set(false, forKey: "ApplicationCleanlyBackgrounded")
+        defaults.synchronize()
+
+        if let profile = self.profile {
+            profile.reopen()
+
+            if profile.prefs.boolForKey(PendingAccountDisconnectedKey) ?? false {
+                FxALoginHelper.sharedInstance.applicationDidDisconnect(application)
+            }
+
+            profile.syncManager.applicationDidBecomeActive()
+        }
+
+        // We could load these here, but then we have to futz with the tab counter
+        // and making NSURLRequests.
+        self.browserViewController.loadQueuedTabs(receivedURLs: self.receivedURLs)
+        self.receivedURLs = nil
+        application.applicationIconBadgeNumber = 0
+
+        // handle quick actions is available
+        let quickActions = QuickActions.sharedInstance
+        if let shortcut = quickActions.launchedShortcutItem {
+            // dispatch asynchronously so that BVC is all set up for handling new tabs
+            // when we try and open them
+            quickActions.handleShortCutItem(shortcut, withBrowserViewController: browserViewController)
+            quickActions.launchedShortcutItem = nil
+        }
+
+        // Check if we have a URL from an external app or extension waiting to launch,
+        // then launch it on the main thread.
+        if let params = openInFirefoxParams {
+            openInFirefoxParams = nil
+            DispatchQueue.main.async {
+                self.launchFromURL(params)
+            }
+        }
+
+        UnifiedTelemetry.recordEvent(category: .action, method: .foreground, object: .app)
+    }
+
+    func applicationDidEnterBackground(_ application: UIApplication) {
+        //
+        // At this point we are happy to mark the app as CleanlyBackgrounded. If a crash happens in background
+        // sync then that crash will still be reported. But we won't bother the user with the Restore Tabs
+        // dialog. We don't have to because at this point we already saved the tab state properly.
+        //
+
+        let defaults = UserDefaults()
+        defaults.set(true, forKey: "ApplicationCleanlyBackgrounded")
+        defaults.synchronize()
+
+        syncOnDidEnterBackground(application: application)
+
+        UnifiedTelemetry.recordEvent(category: .action, method: .background, object: .app)
+    }
+
+    fileprivate func syncOnDidEnterBackground(application: UIApplication) {
+        guard let profile = self.profile else {
+            return
+        }
+
+        profile.syncManager.applicationDidEnterBackground()
+
+        var taskId: UIBackgroundTaskIdentifier = 0
+        taskId = application.beginBackgroundTask (expirationHandler: { _ in
+            print("Running out of background time, but we have a profile shutdown pending.")
+            self.shutdownProfileWhenNotActive(application)
+            application.endBackgroundTask(taskId)
+        })
+
+        if profile.hasSyncableAccount() {
+            profile.syncManager.syncEverything(why: .backgrounded).uponQueue(DispatchQueue.main) { _ in
+                self.shutdownProfileWhenNotActive(application)
+                application.endBackgroundTask(taskId)
+            }
+        } else {
+            profile.shutdown()
+            application.endBackgroundTask(taskId)
+        }
+    }
+
+    fileprivate func shutdownProfileWhenNotActive(_ application: UIApplication) {
+        // Only shutdown the profile if we are not in the foreground
+        guard application.applicationState != UIApplicationState.active else {
+            return
+        }
+
+        profile?.shutdown()
+    }
+
+    func applicationWillEnterForeground(_ application: UIApplication) {
+        // The reason we need to call this method here instead of `applicationDidBecomeActive`
+        // is that this method is only invoked whenever the application is entering the foreground where as 
+        // `applicationDidBecomeActive` will get called whenever the Touch ID authentication overlay disappears.
+        self.updateAuthenticationInfo()
+    }
+
+    fileprivate func updateAuthenticationInfo() {
+        if let authInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() {
+            if !LAContext().canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) {
+                authInfo.useTouchID = false
+                KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authInfo)
+            }
+        }
+    }
+
+    fileprivate func setUpWebServer(_ profile: Profile) {
+        let server = WebServer.sharedInstance
+        ReaderModeHandlers.register(server, profile: profile)
+        ErrorPageHelper.register(server, certStore: profile.certStore)
+        AboutHomeHandler.register(server)
+        AboutLicenseHandler.register(server)
+        SessionRestoreHandler.register(server)
+
+        // Bug 1223009 was an issue whereby CGDWebserver crashed when moving to a background task
+        // catching and handling the error seemed to fix things, but we're not sure why.
+        // Either way, not implicitly unwrapping a try is not a great way of doing things
+        // so this is better anyway.
+        do {
+            try server.start()
+        } catch let err as NSError {
+            print("Error: Unable to start WebServer \(err)")
+        }
+    }
+
+    fileprivate func setUserAgent() {
+        let firefoxUA = UserAgent.defaultUserAgent()
+
+        // Set the UA for WKWebView (via defaults), the favicon fetcher, and the image loader.
+        // This only needs to be done once per runtime. Note that we use defaults here that are
+        // readable from extensions, so they can just use the cached identifier.
+        let defaults = UserDefaults(suiteName: AppInfo.sharedContainerIdentifier)!
+        defaults.register(defaults: ["UserAgent": firefoxUA])
+
+        SDWebImageDownloader.shared().setValue(firefoxUA, forHTTPHeaderField: "User-Agent")
+
+        // Record the user agent for use by search suggestion clients.
+        SearchViewController.userAgent = firefoxUA
+
+        // Some sites will only serve HTML that points to .ico files.
+        // The FaviconFetcher is explicitly for getting high-res icons, so use the desktop user agent.
+        FaviconFetcher.userAgent = UserAgent.desktopUserAgent()
+    }
+
+    func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void) {
+        if let actionId = identifier {
+            if let action = SentTabAction(rawValue: actionId) {
+                viewURLInNewTab(notification)
+                switch action {
+                case .bookmark:
+                    addBookmark(notification)
+                    break
+                case .readingList:
+                    addToReadingList(notification)
+                    break
+                default:
+                    break
+                }
+            } else {
+                print("ERROR: Unknown notification action received")
+            }
+        } else {
+            print("ERROR: Unknown notification received")
+        }
+    }
+
+    func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
+        viewURLInNewTab(notification)
+    }
+
+    fileprivate func presentEmailComposerWithLogs() {
+        if let buildNumber = Bundle.main.object(forInfoDictionaryKey: String(kCFBundleVersionKey)) as? NSString {
+            let mailComposeViewController = MFMailComposeViewController()
+            mailComposeViewController.mailComposeDelegate = self
+            mailComposeViewController.setSubject("Debug Info for iOS client version v\(appVersion) (\(buildNumber))")
+
+            if DebugSettingsBundleOptions.attachLogsToDebugEmail {
+                do {
+                    let logNamesAndData = try Logger.diskLogFilenamesAndData()
+                    logNamesAndData.forEach { nameAndData in
+                        if let data = nameAndData.1 {
+                            mailComposeViewController.addAttachmentData(data, mimeType: "text/plain", fileName: nameAndData.0)
+                        }
+                    }
+                } catch _ {
+                    print("Failed to retrieve logs from device")
+                }
+            }
+
+            if DebugSettingsBundleOptions.attachTabStateToDebugEmail {
+                if let tabStateDebugData = TabManager.tabRestorationDebugInfo().data(using: String.Encoding.utf8) {
+                    mailComposeViewController.addAttachmentData(tabStateDebugData, mimeType: "text/plain", fileName: "tabState.txt")
+                }
+
+                if let tabStateData = TabManager.tabArchiveData() {
+                    mailComposeViewController.addAttachmentData(tabStateData as Data, mimeType: "application/octet-stream", fileName: "tabsState.archive")
+                }
+            }
+
+            self.window?.rootViewController?.present(mailComposeViewController, animated: true, completion: nil)
+        }
+    }
+
+    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
+
+        // If the `NSUserActivity` has a `webpageURL`, it is either a deep link or an old history item
+        // reached via a "Spotlight" search before we began indexing visited pages via CoreSpotlight.
+        if let url = userActivity.webpageURL {
+            let query = url.getQuery()
+            
+            // Check for fxa sign-in code and launch the login screen directly
+            if query["signin"] != nil {
+                browserViewController.launchFxAFromDeeplinkURL(url)
+                return true
+            }
+            
+            // Per Adjust documenation, https://docs.adjust.com/en/universal-links/#running-campaigns-through-universal-links,
+            // it is recommended that links contain the `deep_link` query parameter. This link will also
+            // be url encoded.
+            if let deepLink = query["deep_link"]?.removingPercentEncoding, let url = URL(string: deepLink) {
+                browserViewController.switchToTabForURLOrOpen(url, isPrivileged: true)
+                return true
+            }
+
+            browserViewController.switchToTabForURLOrOpen(url, isPrivileged: true)
+            return true
+        }
+
+        // Otherwise, check if the `NSUserActivity` is a CoreSpotlight item and switch to its tab or
+        // open a new one.
+        if userActivity.activityType == CSSearchableItemActionType {
+            if let userInfo = userActivity.userInfo,
+                let urlString = userInfo[CSSearchableItemActivityIdentifier] as? String,
+                let url = URL(string: urlString) {
+                browserViewController.switchToTabForURLOrOpen(url, isPrivileged: true)
+                return true
+            }
+        }
+
+        return false
+    }
+
+    fileprivate func viewURLInNewTab(_ notification: UILocalNotification) {
+        if let alertURL = notification.userInfo?[TabSendURLKey] as? String {
+            if let urlToOpen = URL(string: alertURL) {
+                browserViewController.openURLInNewTab(urlToOpen, isPrivileged: true)
+            }
+        }
+    }
+
+    fileprivate func addBookmark(_ notification: UILocalNotification) {
+        if let alertURL = notification.userInfo?[TabSendURLKey] as? String,
+            let title = notification.userInfo?[TabSendTitleKey] as? String {
+            let tabState = TabState(isPrivate: false, desktopSite: false, isBookmarked: false, url: URL(string: alertURL), title: title, favicon: nil)
+                browserViewController.addBookmark(tabState)
+
+                let userData = [QuickActions.TabURLKey: alertURL,
+                    QuickActions.TabTitleKey: title]
+                QuickActions.sharedInstance.addDynamicApplicationShortcutItemOfType(.openLastBookmark, withUserData: userData, toApplication: UIApplication.shared)
+        }
+    }
+
+    fileprivate func addToReadingList(_ notification: UILocalNotification) {
+        if let alertURL = notification.userInfo?[TabSendURLKey] as? String,
+           let title = notification.userInfo?[TabSendTitleKey] as? String {
+            if let urlToOpen = URL(string: alertURL) {
+                NotificationCenter.default.post(name: NSNotification.Name.FSReadingListAddReadingListItem, object: self, userInfo: ["URL": urlToOpen, "Title": title])
+            }
+        }
+    }
+
+    func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
+        let handledShortCutItem = QuickActions.sharedInstance.handleShortCutItem(shortcutItem, withBrowserViewController: browserViewController)
+
+        completionHandler(handledShortCutItem)
+    }
+}
+
+// MARK: - Root View Controller Animations
+extension AppDelegate: UINavigationControllerDelegate {
+    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
+            if operation == UINavigationControllerOperation.push {
+                return BrowserToTrayAnimator()
+            } else if operation == UINavigationControllerOperation.pop {
+                return TrayToBrowserAnimator()
+            } else {
+                return nil
+            }
+    }
+}
+
+extension AppDelegate: TabManagerStateDelegate {
+    func tabManagerWillStoreTabs(_ tabs: [Tab]) {
+        // It is possible that not all tabs have loaded yet, so we filter out tabs with a nil URL.
+        let storedTabs: [RemoteTab] = tabs.flatMap( Tab.toTab )
+
+        // Don't insert into the DB immediately. We tend to contend with more important
+        // work like querying for top sites.
+        let queue = DispatchQueue.global(qos: DispatchQoS.background.qosClass)
+        queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(ProfileRemoteTabsSyncDelay * Double(NSEC_PER_MSEC))) / Double(NSEC_PER_SEC)) {
+            self.profile?.storeTabs(storedTabs)
+        }
+    }
+}
+
+extension AppDelegate: MFMailComposeViewControllerDelegate {
+    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
+        // Dismiss the view controller and start the app up
+        controller.dismiss(animated: true, completion: nil)
+        startApplication(application!, withLaunchOptions: self.launchOptions)
+    }
+}
+
+extension AppDelegate {
+    func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
+        FxALoginHelper.sharedInstance.application(application, didRegisterUserNotificationSettings: notificationSettings)
+    }
+}
+
+extension AppDelegate {
+    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
+        FxALoginHelper.sharedInstance.apnsRegisterDidSucceed(deviceToken)
+    }
+
+    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
+        print("failed to register. \(error)")
+        FxALoginHelper.sharedInstance.apnsRegisterDidFail()
+    }
+
+    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
+        if Logger.logPII && log.isEnabledFor(level: .info) {
+            NSLog("APNS NOTIFICATION \(userInfo)")
+        }
+
+        // At this point, we know that NotificationService has been run.
+        // We get to this point if the notification was received while the app was in the foreground
+        // OR the app was backgrounded and now the user has tapped on the notification.
+        // Either way, if this method is being run, then the app is foregrounded.
+
+        // Either way, we should zero the badge number.
+        application.applicationIconBadgeNumber = 0
+
+        guard let profile = self.profile else {
+            return completionHandler(.noData)
+        }
+
+        // NotificationService will have decrypted the push message, and done some syncing 
+        // activity. If the `client` collection was synced, and there are `displayURI` commands (i.e. sent tabs)
+        // NotificationService will have collected them for us in the userInfo.
+        if let serializedTabs = userInfo["sentTabs"] as? [[String: String]] {
+            // Let's go ahead and open those.
+            let receivedURLs = serializedTabs.flatMap { item -> URL? in
+                guard let tabURL = item["url"] else {
+                    return nil
+                }
+                return URL(string: tabURL)
+            }
+
+            if receivedURLs.count > 0 {
+                // Remember which URLs we received so we can filter them out later when
+                // loading the queued tabs.
+                self.receivedURLs = receivedURLs
+                
+                // If we're in the foreground, load the queued tabs now.
+                if application.applicationState == UIApplicationState.active {
+                    DispatchQueue.main.async {
+                        self.browserViewController.loadQueuedTabs(receivedURLs: self.receivedURLs)
+                        self.receivedURLs = nil
+                    }
+                }
+
+                return completionHandler(.newData)
+            }
+        }
+
+        // By now, we've dealt with any sent tab notifications.
+        //
+        // The only thing left to do now is to perform actions that can only be performed
+        // while the app is foregrounded.
+        // 
+        // Use the push message handler to re-parse the message,
+        // this time with a BrowserProfile and processing the return
+        // differently than in NotificationService.
+        let handler = FxAPushMessageHandler(with: profile)
+        handler.handle(userInfo: userInfo).upon { res in
+            if let message = res.successValue {
+                switch message {
+                case .accountVerified:
+                    _ = handler.postVerification()
+                case .thisDeviceDisconnected:
+                    FxALoginHelper.sharedInstance.applicationDidDisconnect(application)
+                default:
+                    break
+                }
+            }
+
+            completionHandler(res.isSuccess ? .newData : .failed)
+        }
+    }
+
+    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
+        let completionHandler: (UIBackgroundFetchResult) -> Void = { _ in }
+        self.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)
+    }
+}
+
+struct FxALaunchParams {
+    var query: [String: String]
+}
+
+struct LaunchParams {
+    let url: URL?
+    let isPrivate: Bool?
+}
+
+extension UIApplication {
+    var syncDelegate: SyncDelegate {
+        return AppSyncDelegate(app: self)
+    }
+
+    static var isInPrivateMode: Bool {
+        let appDelegate = UIApplication.shared.delegate as? AppDelegate
+        return appDelegate?.browserViewController.tabManager.selectedTab?.isPrivate ?? false
+    }
+}
+
+class AppSyncDelegate: SyncDelegate {
+    let app: UIApplication
+
+    init(app: UIApplication) {
+        self.app = app
+    }
+
+    open func displaySentTab(for url: URL, title: String, from deviceName: String?) {
+        DispatchQueue.main.sync {
+            if let appDelegate = app.delegate as? AppDelegate, app.applicationState == .active {
+                appDelegate.browserViewController.switchToTabForURLOrOpen(url, isPrivileged: false)
+                return
+            }
+
+            // check to see what the current notification settings are and only try and send a notification if
+            // the user has agreed to them
+            if let currentSettings = app.currentUserNotificationSettings {
+                if currentSettings.types.rawValue & UIUserNotificationType.alert.rawValue != 0 {
+                    if Logger.logPII {
+                        log.info("Displaying notification for URL \(url.absoluteString)")
+                    }
+
+                    let notification = UILocalNotification()
+                    notification.fireDate = Date()
+                    notification.timeZone = NSTimeZone.default
+                    let title: String
+                    if let deviceName = deviceName {
+                        title = String(format: Strings.SentTab_TabArrivingNotification_WithDevice_title, deviceName)
+                    } else {
+                        title = Strings.SentTab_TabArrivingNotification_NoDevice_title
+                    }
+                    notification.alertTitle = title
+                    notification.alertBody = url.absoluteDisplayExternalString
+                    notification.userInfo = [TabSendURLKey: url.absoluteString, TabSendTitleKey: title]
+                    notification.alertAction = nil
+
+                    // Restore this when we fix Bug 1364420.
+                    // notification.category = TabSendCategory
+
+                    app.presentLocalNotificationNow(notification)
+                }
+            }
+        }
+    }
+}
diff --git a/mobile/ios/Client/Application/Crasher.h b/mobile/ios/Client/Application/Crasher.h
new file mode 100644
index 0000000000..a4f782c497
--- /dev/null
+++ b/mobile/ios/Client/Application/Crasher.h
@@ -0,0 +1,13 @@
+//
+//  Crasher.h
+//  Client
+//
+//  Created by Steph Leroux on 2015-10-08.
+//  Copyright © 2015 Mozilla. All rights reserved.
+//
+
+#import 
+
+@interface Crasher : NSObject
+
+@end
diff --git a/mobile/ios/Client/Application/Crasher.m b/mobile/ios/Client/Application/Crasher.m
new file mode 100644
index 0000000000..97c3c687a1
--- /dev/null
+++ b/mobile/ios/Client/Application/Crasher.m
@@ -0,0 +1,13 @@
+//
+//  Crasher.m
+//  Client
+//
+//  Created by Steph Leroux on 2015-10-08.
+//  Copyright © 2015 Mozilla. All rights reserved.
+//
+
+#import "Crasher.h"
+
+@implementation Crasher
+
+@end
diff --git a/mobile/ios/Client/Application/DebugSettingsBundleOptions.swift b/mobile/ios/Client/Application/DebugSettingsBundleOptions.swift
new file mode 100644
index 0000000000..c4f85fe00a
--- /dev/null
+++ b/mobile/ios/Client/Application/DebugSettingsBundleOptions.swift
@@ -0,0 +1,35 @@
+/* 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/. */
+
+import Foundation
+import MessageUI
+
+struct DebugSettingsBundleOptions {
+
+    /// Don't restore tabs on app launch
+    static var skipSessionRestore: Bool {
+        return UserDefaults.standard.bool(forKey: "SettingsBundleSkipSessionRestore")
+    }
+
+    /// Disable the local web server we use for restoration, error pages, etc
+    static var disableLocalWebServer: Bool {
+        return UserDefaults.standard.bool(forKey: "SettingsBundleDisableLocalWebServer")
+    }
+
+    /// When enabled, the app launch will be replaced with the mail compose view appearing with the device
+    /// logs pre-attached. When the mail is sent, the app continues launching normally.
+    static var launchIntoEmailComposer: Bool {
+        return ((attachTabStateToDebugEmail || attachLogsToDebugEmail) &&  MFMailComposeViewController.canSendMail())
+    }
+
+    /// When enabled, the email composer will have the tab state attached.
+    static var attachTabStateToDebugEmail: Bool {
+        return UserDefaults.standard.bool(forKey: "SettingsBundleEmailTabState")
+    }
+
+    /// When enabled, the email composer will have the application logs attached.
+    static var attachLogsToDebugEmail: Bool {
+        return UserDefaults.standard.bool(forKey: "SettingsBundleEmailLogsOnLaunch")
+    }
+}
diff --git a/mobile/ios/Client/Application/LaunchScreen.xib b/mobile/ios/Client/Application/LaunchScreen.xib
new file mode 100644
index 0000000000..702a0a9655
--- /dev/null
+++ b/mobile/ios/Client/Application/LaunchScreen.xib
@@ -0,0 +1,34 @@
+
+
+    
+        
+    
+    
+        
+        
+        
+            
+            
+            
+                
+                    
+                    
+                        
+                        
+                    
+                
+            
+            
+            
+                
+                
+            
+            
+            
+            
+        
+    
+    
+        
+    
+
diff --git a/mobile/ios/Client/Application/LeanplumIntegration.swift b/mobile/ios/Client/Application/LeanplumIntegration.swift
new file mode 100644
index 0000000000..b105773e3c
--- /dev/null
+++ b/mobile/ios/Client/Application/LeanplumIntegration.swift
@@ -0,0 +1,320 @@
+/* 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/. */
+
+import Foundation
+import AdSupport
+import Shared
+import Leanplum
+
+private let LPAppIdKey = "LeanplumAppId"
+private let LPProductionKeyKey = "LeanplumProductionKey"
+private let LPDevelopmentKeyKey = "LeanplumDevelopmentKey"
+private let AppRequestedUserNotificationsPrefKey = "applicationDidRequestUserNotificationPermissionPrefKey"
+
+// FxA Custom Leanplum message template for A/B testing push notifications.
+private struct LPMessage {
+    static let FxAPrePush = "FxA Prepush v1"
+    static let ArgAcceptAction = "Accept action"
+    static let ArgCancelAction = "Cancel action"
+    static let ArgTitleText = "Title.Text"
+    static let ArgTitleColor = "Title.Color"
+    static let ArgMessageText = "Message.Text"
+    static let ArgMessageColor = "Message.Color"
+    static let ArgAcceptButtonText = "Accept button.Text"
+    static let ArgCancelButtonText = "Cancel button.Text"
+    static let ArgCancelButtonTextColor = "Cancel button.Text color"
+    // These defaults are overridden though Leanplum webUI
+    static let DefaultAskToAskTitle = NSLocalizedString("Firefox Sync Requires Push", comment: "Default push to ask title")
+    static let DefaultAskToAskMessage = NSLocalizedString("Firefox will stay in sync faster with Push Notifications enabled.", comment: "Default push to ask message")
+    static let DefaultOkButtonText = NSLocalizedString("Enable Push", comment: "Default push alert ok button text")
+    static let DefaultLaterButtonText = NSLocalizedString("Don't Enable", comment: "Default push alert cancel button text")
+}
+
+private let log = Logger.browserLogger
+
+enum LPEvent: String {
+    case firstRun = "E_First_Run"
+    case secondRun = "E_Second_Run"
+    case openedApp = "E_Opened_App"
+    case dismissedOnboarding = "E_Dismissed_Onboarding"
+    case openedLogins = "Opened Login Manager"
+    case openedBookmark = "E_Opened_Bookmark"
+    case openedNewTab = "E_Opened_New_Tab"
+    case openedPocketStory = "E_Opened_Pocket_Story"
+    case interactWithURLBar = "E_Interact_With_Search_URL_Area"
+    case savedBookmark = "E_Saved_Bookmark"
+    case openedTelephoneLink = "Opened Telephone Link"
+    case openedMailtoLink = "E_Opened_Mailto_Link"
+    case saveImage = "E_Download_Media_Saved_Image"
+    case savedLoginAndPassword = "E_Saved_Login_And_Password"
+    case clearPrivateData = "E_Cleared_Private_Data"
+    case downloadedFocus = "E_User_Downloaded_Focus"
+    case downloadedPocket = "E_User_Downloaded_Pocket"
+    case userSharedWebpage = "E_User_Tapped_Share_Button"
+    case signsInFxa = "E_User_Signed_In_To_FxA"
+    case useReaderView = "E_User_Used_Reader_View"
+    case trackingProtectionSettings = "E_Tracking_Protection_Settings_Changed"
+}
+
+struct LPAttributeKey {
+    static let focusInstalled = "Focus Installed"
+    static let klarInstalled = "Klar Installed"
+    static let signedInSync = "Signed In Sync"
+    static let mailtoIsDefault = "Mailto Is Default"
+    static let pocketInstalled = "Pocket Installed"
+    static let telemetryOptIn = "Telemetry Opt In"
+}
+
+struct MozillaAppSchemes {
+    static let focus = "firefox-focus"
+    static let focusDE = "firefox-klar"
+    static let pocket = "pocket"
+}
+
+private let supportedLocales = ["en_US", "de_DE", "en_GB", "en_CA", "en_AU", "zh_TW", "en_HK", "en_SG",
+                        "fr_FR", "it_IT", "id_ID", "id_ID", "pt_BR", "pl_PL", "ru_RU", "es_ES", "es_MX"]
+
+private struct LPSettings {
+    var appId: String
+    var developmentKey: String
+    var productionKey: String
+}
+
+class LeanPlumClient {
+    static let shared = LeanPlumClient()
+
+    // Setup
+    private weak var profile: Profile?
+    private var prefs: Prefs? { return profile?.prefs }
+    private var enabled: Bool = true
+    
+    // This defines an external Leanplum varible to enable/disable FxA prepush dialogs.
+    // The primary result is having a feature flag controlled by Leanplum, and falling back
+    // to prompting with native push permissions.
+    private var useFxAPrePush: LPVar = LPVar.define("useFxAPrePush", with: false)
+
+    private func isPrivateMode() -> Bool {
+        // Need to be run on main thread since isInPrivateMode requires to be on the main thread.
+        assert(Thread.isMainThread)
+        return UIApplication.isInPrivateMode
+    }
+    
+    func isLPEnabled() -> Bool {
+        return enabled && Leanplum.hasStarted()
+    }
+
+    static func shouldEnable(profile: Profile) -> Bool {
+        return AppConstants.MOZ_ENABLE_LEANPLUM && (profile.prefs.boolForKey(AppConstants.PrefSendUsageData) ?? true)
+    }
+
+    func setup(profile: Profile) {
+        self.profile = profile
+    }
+
+    fileprivate func start() {
+        guard let settings = getSettings(), supportedLocales.contains(Locale.current.identifier), !Leanplum.hasStarted() else {
+            enabled = false
+            log.error("LeanplumIntegration - Could not be started")
+            return
+        }
+
+        if UIDevice.current.name.contains("MozMMADev") {
+            log.info("LeanplumIntegration - Setting up for Development")
+            Leanplum.setDeviceId(UIDevice.current.identifierForVendor?.uuidString)
+            Leanplum.setAppId(settings.appId, withDevelopmentKey: settings.developmentKey)
+        } else {
+            log.info("LeanplumIntegration - Setting up for Production")
+            Leanplum.setAppId(settings.appId, withProductionKey: settings.productionKey)
+        }
+
+        Leanplum.syncResourcesAsync(true)
+
+        let attributes: [AnyHashable: Any] = [
+            LPAttributeKey.mailtoIsDefault: mailtoIsDefault(),
+            LPAttributeKey.focusInstalled: focusInstalled(),
+            LPAttributeKey.klarInstalled: klarInstalled(),
+            LPAttributeKey.pocketInstalled: pocketInstalled(),
+            LPAttributeKey.signedInSync: profile?.hasAccount() ?? false
+        ]
+        
+        self.setupCustomTemplates()
+        
+        Leanplum.start(withUserId: nil, userAttributes: attributes, responseHandler: { _ in
+            self.track(event: .openedApp)
+            
+            // We need to check if the app is a clean install to use for
+            // preventing the What's New URL from appearing.
+            if self.prefs?.intForKey(IntroViewControllerSeenProfileKey) == nil {
+                self.prefs?.setString(AppInfo.appVersion, forKey: LatestAppVersionProfileKey)
+                self.track(event: .firstRun)
+            } else if self.prefs?.boolForKey("SecondRun") == nil {
+                self.prefs?.setBool(true, forKey: "SecondRun")
+                self.track(event: .secondRun)
+            }
+
+            self.checkIfAppWasInstalled(key: PrefsKeys.HasFocusInstalled, isAppInstalled: self.focusInstalled(), lpEvent: .downloadedFocus)
+            self.checkIfAppWasInstalled(key: PrefsKeys.HasPocketInstalled, isAppInstalled: self.pocketInstalled(), lpEvent: .downloadedPocket)
+        })
+    }
+
+    // Events
+    func track(event: LPEvent, withParameters parameters: [String: AnyObject]? = nil) {
+        guard isLPEnabled() else {
+            return
+        }
+        ensureMainThread {
+            guard !self.isPrivateMode() else {
+                return
+            }
+            if let params = parameters {
+                Leanplum.track(event.rawValue, withParameters: params)
+            } else {
+                Leanplum.track(event.rawValue)
+            }
+        }
+    }
+
+    func set(attributes: [AnyHashable: Any]) {
+        guard isLPEnabled() else {
+            return
+        }
+        ensureMainThread {
+            if !self.isPrivateMode() {
+                Leanplum.setUserAttributes(attributes)
+            }
+        }
+    }
+
+    func set(enabled: Bool) {
+        // Setting up Test Mode stops sending things to server.
+        if enabled { start() }
+        self.enabled = enabled
+        Leanplum.setTestModeEnabled(!enabled)
+    }
+    
+    func isFxAPrePushEnabled() -> Bool {
+       return AppConstants.MOZ_FXA_LEANPLUM_AB_PUSH_TEST && useFxAPrePush.boolValue()
+    }
+
+    /*
+     This is used to determine if an app was installed after firefox was installed
+     */
+    private func checkIfAppWasInstalled(key: String, isAppInstalled: Bool, lpEvent: LPEvent) {
+        // if no key is present. create one and set it.
+        // if the app is already installed then the flag will set true and the second block will never run
+        if self.prefs?.boolForKey(key) == nil {
+            self.prefs?.setBool(isAppInstalled, forKey: key)
+        }
+        // on a subsquent launch if the app is installed and the key is false then switch the flag to true
+        if !(self.prefs?.boolForKey(key) ?? false), isAppInstalled {
+            self.prefs?.setBool(isAppInstalled, forKey: key)
+            self.track(event: lpEvent)
+        }
+    }
+
+    private func canOpenApp(scheme: String) -> Bool {
+        return URL(string: "\(scheme)://").flatMap { UIApplication.shared.canOpenURL($0) } ?? false
+    }
+
+    private func focusInstalled() -> Bool {
+        return canOpenApp(scheme: MozillaAppSchemes.focus)
+    }
+
+    private func klarInstalled() -> Bool {
+        return canOpenApp(scheme: MozillaAppSchemes.focusDE)
+    }
+
+    private func pocketInstalled() -> Bool {
+        return canOpenApp(scheme: MozillaAppSchemes.pocket)
+    }
+
+    private func mailtoIsDefault() -> Bool {
+        return (prefs?.stringForKey(PrefsKeys.KeyMailToOption) ?? "mailto:") == "mailto:"
+    }
+
+    private func getSettings() -> LPSettings? {
+        let bundle = Bundle.main
+        guard let appId = bundle.object(forInfoDictionaryKey: LPAppIdKey) as? String,
+              let productionKey = bundle.object(forInfoDictionaryKey: LPProductionKeyKey) as? String,
+              let developmentKey = bundle.object(forInfoDictionaryKey: LPDevelopmentKeyKey) as? String else {
+            return nil
+        }
+        return LPSettings(appId: appId, developmentKey: developmentKey, productionKey: productionKey)
+    }
+    
+    // This must be called before `Leanplum.start` in order to correctly setup
+    // custom message templates.
+    private func setupCustomTemplates() {
+        // These properties are exposed through the Leanplum web interface.
+        // Ref: https://github.com/Leanplum/Leanplum-iOS-Samples/blob/master/iOS_customMessageTemplates/iOS_customMessageTemplates/LPMessageTemplates.m
+        let args: [LPActionArg] = [
+            LPActionArg(named: LPMessage.ArgTitleText, with: LPMessage.DefaultAskToAskTitle),
+            LPActionArg(named: LPMessage.ArgTitleColor, with: UIColor.black),
+            LPActionArg(named: LPMessage.ArgMessageText, with: LPMessage.DefaultAskToAskMessage),
+            LPActionArg(named: LPMessage.ArgMessageColor, with: UIColor.black),
+            LPActionArg(named: LPMessage.ArgAcceptButtonText, with: LPMessage.DefaultOkButtonText),
+            LPActionArg(named: LPMessage.ArgCancelAction, withAction: nil),
+            LPActionArg(named: LPMessage.ArgCancelButtonText, with: LPMessage.DefaultLaterButtonText),
+            LPActionArg(named: LPMessage.ArgCancelButtonTextColor, with: UIColor.gray)
+        ]
+        
+        let responder: LeanplumActionBlock = { (context) -> Bool in
+            // Before proceeding, double check that Leanplum FxA prepush config value has been enabled.
+            if !self.isFxAPrePushEnabled() {
+                return false
+            }
+            
+            guard let context = context else {
+                return false
+            }
+            
+            // Don't display permission screen if they have already allowed/disabled push permissions
+            if self.prefs?.boolForKey(AppRequestedUserNotificationsPrefKey) ?? false {
+                FxALoginHelper.sharedInstance.readyForSyncing()
+                return false
+            }
+            
+            // Present Alert View onto the current top view controller
+            let rootViewController = UIApplication.topViewController()
+            let alert = UIAlertController(title: context.stringNamed(LPMessage.ArgTitleText), message: context.stringNamed(LPMessage.ArgMessageText), preferredStyle: .alert)
+
+            alert.addAction(UIAlertAction(title: context.stringNamed(LPMessage.ArgCancelButtonText), style: .cancel, handler: { (action) -> Void in
+                // Log cancel event and call ready for syncing
+                context.runTrackedActionNamed(LPMessage.ArgCancelAction)
+                FxALoginHelper.sharedInstance.readyForSyncing()
+            }))
+
+            alert.addAction(UIAlertAction(title: context.stringNamed(LPMessage.ArgAcceptButtonText), style: .default, handler: { (action) -> Void in
+                // Log accept event and present push permission modal
+                context.runTrackedActionNamed(LPMessage.ArgAcceptAction)
+                FxALoginHelper.sharedInstance.requestUserNotifications(UIApplication.shared)
+                self.prefs?.setBool(true, forKey: AppRequestedUserNotificationsPrefKey)
+            }))
+            
+            rootViewController?.present(alert, animated: true, completion: nil)
+            return true
+        }
+        
+        // Register or update the custom Leanplum message
+        Leanplum.defineAction(LPMessage.FxAPrePush, of: kLeanplumActionKindMessage, withArguments: args, withOptions: [:], withResponder: responder)
+    }
+}
+
+extension UIApplication {
+    // Extension to get the current top most view controller
+    class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
+        if let nav = base as? UINavigationController {
+            return topViewController(base: nav.visibleViewController)
+        }
+        if let tab = base as? UITabBarController {
+            if let selected = tab.selectedViewController {
+                return topViewController(base: selected)
+            }
+        }
+        if let presented = base?.presentedViewController {
+            return topViewController(base: presented)
+        }
+        return base
+    }
+}
diff --git a/mobile/ios/Client/Application/QuickActions.swift b/mobile/ios/Client/Application/QuickActions.swift
new file mode 100644
index 0000000000..6bb06149a6
--- /dev/null
+++ b/mobile/ios/Client/Application/QuickActions.swift
@@ -0,0 +1,142 @@
+/* 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/. */
+
+import Foundation
+import Storage
+
+import Shared
+import XCGLogger
+
+enum ShortcutType: String {
+    case newTab = "NewTab"
+    case newPrivateTab = "NewPrivateTab"
+    case openLastBookmark = "OpenLastBookmark"
+    case qrCode = "QRCode"
+
+    init?(fullType: String) {
+        guard let last = fullType.components(separatedBy: ".").last else { return nil }
+
+        self.init(rawValue: last)
+    }
+
+    var type: String {
+        return Bundle.main.bundleIdentifier! + ".\(self.rawValue)"
+    }
+}
+
+protocol QuickActionHandlerDelegate {
+    func handleShortCutItemType(_ type: ShortcutType, userData: [String: NSSecureCoding]?)
+}
+
+class QuickActions: NSObject {
+
+    fileprivate let log = Logger.browserLogger
+
+    static let QuickActionsVersion = "1.0"
+    static let QuickActionsVersionKey = "dynamicQuickActionsVersion"
+
+    static let TabURLKey = "url"
+    static let TabTitleKey = "title"
+
+    fileprivate let lastBookmarkTitle = NSLocalizedString("Open Last Bookmark", tableName: "3DTouchActions", comment: "String describing the action of opening the last added bookmark from the home screen Quick Actions via 3D Touch")
+    fileprivate let _lastTabTitle = NSLocalizedString("Open Last Tab", tableName: "3DTouchActions", comment: "String describing the action of opening the last tab sent to Firefox from the home screen Quick Actions via 3D Touch")
+
+    static var sharedInstance = QuickActions()
+
+    var launchedShortcutItem: UIApplicationShortcutItem?
+
+    // MARK: Administering Quick Actions
+    func addDynamicApplicationShortcutItemOfType(_ type: ShortcutType, fromShareItem shareItem: ShareItem, toApplication application: UIApplication) {
+            var userData = [QuickActions.TabURLKey: shareItem.url]
+            if let title = shareItem.title {
+                userData[QuickActions.TabTitleKey] = title
+            }
+            QuickActions.sharedInstance.addDynamicApplicationShortcutItemOfType(type, withUserData: userData, toApplication: application)
+    }
+
+    @discardableResult func addDynamicApplicationShortcutItemOfType(_ type: ShortcutType, withUserData userData: [AnyHashable: Any] = [AnyHashable: Any](), toApplication application: UIApplication) -> Bool {
+        // add the quick actions version so that it is always in the user info
+        var userData: [AnyHashable: Any] = userData
+        userData[QuickActions.QuickActionsVersionKey] = QuickActions.QuickActionsVersion
+        var dynamicShortcutItems = application.shortcutItems ?? [UIApplicationShortcutItem]()
+        switch type {
+        case .openLastBookmark:
+            let openLastBookmarkShortcut = UIMutableApplicationShortcutItem(type: ShortcutType.openLastBookmark.type,
+                localizedTitle: lastBookmarkTitle,
+                localizedSubtitle: userData[QuickActions.TabTitleKey] as? String,
+                icon: UIApplicationShortcutIcon(templateImageName: "quick_action_last_bookmark"),
+                userInfo: userData
+            )
+            if let index = (dynamicShortcutItems.index { $0.type == ShortcutType.openLastBookmark.type }) {
+                dynamicShortcutItems[index] = openLastBookmarkShortcut
+            } else {
+                dynamicShortcutItems.append(openLastBookmarkShortcut)
+            }
+        default:
+            log.warning("Cannot add static shortcut item of type \(type)")
+            return false
+        }
+        application.shortcutItems = dynamicShortcutItems
+        return true
+    }
+
+    func removeDynamicApplicationShortcutItemOfType(_ type: ShortcutType, fromApplication application: UIApplication) {
+        guard var dynamicShortcutItems = application.shortcutItems,
+            let index = (dynamicShortcutItems.index { $0.type == type.type }) else { return }
+
+        dynamicShortcutItems.remove(at: index)
+        application.shortcutItems = dynamicShortcutItems
+    }
+
+    // MARK: Handling Quick Actions
+    @discardableResult func handleShortCutItem(_ shortcutItem: UIApplicationShortcutItem, withBrowserViewController bvc: BrowserViewController ) -> Bool {
+
+        // Verify that the provided `shortcutItem`'s `type` is one handled by the application.
+        guard let shortCutType = ShortcutType(fullType: shortcutItem.type) else { return false }
+
+        DispatchQueue.main.async {
+            self.handleShortCutItemOfType(shortCutType, userData: shortcutItem.userInfo, browserViewController: bvc)
+        }
+
+        return true
+    }
+
+    fileprivate func handleShortCutItemOfType(_ type: ShortcutType, userData: [String: NSSecureCoding]?, browserViewController: BrowserViewController) {
+        switch type {
+        case .newTab:
+            handleOpenNewTab(withBrowserViewController: browserViewController, isPrivate: false)
+        case .newPrivateTab:
+            handleOpenNewTab(withBrowserViewController: browserViewController, isPrivate: true)
+        // even though we're removing OpenLastTab, it's possible that someone will use an existing last tab quick action to open the app
+        // the first time after upgrading, so we should still handle it
+        case .openLastBookmark:
+            if let urlToOpen = (userData?[QuickActions.TabURLKey] as? String)?.asURL {
+                handleOpenURL(withBrowserViewController: browserViewController, urlToOpen: urlToOpen)
+            }
+        case .qrCode:
+            handleQRCode(with: browserViewController)
+        }
+    }
+
+    fileprivate func handleOpenNewTab(withBrowserViewController bvc: BrowserViewController, isPrivate: Bool) {
+        bvc.openBlankNewTab(focusLocationField: true, isPrivate: isPrivate)
+    }
+
+    fileprivate func handleOpenURL(withBrowserViewController bvc: BrowserViewController, urlToOpen: URL) {
+        // open bookmark in a non-private browsing tab
+        bvc.switchToPrivacyMode(isPrivate: false)
+
+        // find out if bookmarked URL is currently open
+        // if so, open to that tab,
+        // otherwise, create a new tab with the bookmarked URL
+        bvc.switchToTabForURLOrOpen(urlToOpen, isPrivileged: true)
+    }
+    
+    fileprivate func handleQRCode(with vc: QRCodeViewControllerDelegate & UIViewController) {
+        let qrCodeViewController = QRCodeViewController()
+        qrCodeViewController.qrCodeDelegate = vc
+        let controller = UINavigationController(rootViewController: qrCodeViewController)
+        vc.present(controller, animated: true, completion: nil)
+    }
+}
diff --git a/mobile/ios/Client/Application/Settings.bundle/Root.plist b/mobile/ios/Client/Application/Settings.bundle/Root.plist
new file mode 100644
index 0000000000..43c451cab2
--- /dev/null
+++ b/mobile/ios/Client/Application/Settings.bundle/Root.plist
@@ -0,0 +1,57 @@
+
+
+
+
+	StringsTable
+	Root
+	PreferenceSpecifiers
+	
+		
+			Type
+			PSGroupSpecifier
+			Title
+			Debug Settings
+		
+		
+			Type
+			PSToggleSwitchSpecifier
+			Title
+			Email Saved Tab State
+			Key
+			SettingsBundleEmailTabState
+			DefaultValue
+			
+		
+		
+			Type
+			PSToggleSwitchSpecifier
+			Title
+			Email Logs On Launch
+			Key
+			SettingsBundleEmailLogsOnLaunch
+			DefaultValue
+			
+		
+		
+			Type
+			PSToggleSwitchSpecifier
+			Title
+			Disable Local Web Server
+			Key
+			SettingsBundleDisableLocalWebServer
+			DefaultValue
+			
+		
+		
+			Type
+			PSToggleSwitchSpecifier
+			Title
+			Skip Session Restore
+			Key
+			SettingsBundleSkipSessionRestore
+			DefaultValue
+			
+		
+	
+
+
diff --git a/mobile/ios/Client/Application/Settings.bundle/en.lproj/Root.strings b/mobile/ios/Client/Application/Settings.bundle/en.lproj/Root.strings
new file mode 100644
index 0000000000..8cd87b9d6b
Binary files /dev/null and b/mobile/ios/Client/Application/Settings.bundle/en.lproj/Root.strings differ
diff --git a/mobile/ios/Client/Application/TestAppDelegate.swift b/mobile/ios/Client/Application/TestAppDelegate.swift
new file mode 100644
index 0000000000..d984514477
--- /dev/null
+++ b/mobile/ios/Client/Application/TestAppDelegate.swift
@@ -0,0 +1,96 @@
+/* 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/. */
+
+import Foundation
+import Shared
+import SDWebImage
+import XCGLogger
+
+private let log = Logger.browserLogger
+
+class TestAppDelegate: AppDelegate {
+    override func getProfile(_ application: UIApplication) -> Profile {
+        if let profile = self.profile {
+            return profile
+        }
+
+        var profile: BrowserProfile
+        let launchArguments = ProcessInfo.processInfo.arguments
+        if launchArguments.contains(LaunchArguments.ClearProfile) {
+            // Use a clean profile for each test session.
+            log.debug("Deleting all files in 'Documents' directory to clear the profile")
+            profile = BrowserProfile(localName: "testProfile", syncDelegate: application.syncDelegate, clear: true)
+        } else {
+            profile = BrowserProfile(localName: "testProfile", syncDelegate: application.syncDelegate)
+        }
+
+        // Don't show the What's New page.
+        if launchArguments.contains(LaunchArguments.SkipWhatsNew) {
+            profile.prefs.setString(AppInfo.appVersion, forKey: LatestAppVersionProfileKey)
+        }
+
+        // Skip the intro when requested by for example tests or automation
+        if launchArguments.contains(LaunchArguments.SkipIntro) {
+            profile.prefs.setInt(1, forKey: IntroViewControllerSeenProfileKey)
+        }
+
+        self.profile = profile
+        return profile
+    }
+
+    override func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+        // If the app is running from a XCUITest reset all settings in the app
+        if ProcessInfo.processInfo.arguments.contains(LaunchArguments.ClearProfile) {
+            resetApplication()
+        }
+
+        return super.application(application, willFinishLaunchingWithOptions: launchOptions)
+    }
+
+    /**
+     Use this to reset the application between tests.
+     **/
+    func resetApplication() {
+        log.debug("Wiping everything for a clean start.")
+
+        // Clear image cache
+        SDImageCache.shared().clearDisk()
+        SDImageCache.shared().clearMemory()
+
+        // Clear the cookie/url cache
+        URLCache.shared.removeAllCachedResponses()
+        let storage = HTTPCookieStorage.shared
+        if let cookies = storage.cookies {
+            for cookie in cookies {
+                storage.deleteCookie(cookie)
+            }
+        }
+
+        // Clear the documents directory
+        var rootPath: String = ""
+        let sharedContainerIdentifier = AppInfo.sharedContainerIdentifier
+        if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: sharedContainerIdentifier) {
+            rootPath = url.path
+        } else {
+            rootPath = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0])
+        }
+        let manager = FileManager.default
+        let documents = URL(fileURLWithPath: rootPath)
+        let docContents = try! manager.contentsOfDirectory(atPath: rootPath)
+        for content in docContents {
+            do {
+                try manager.removeItem(at: documents.appendingPathComponent(content))
+            } catch {
+                log.debug("Couldn't delete some document contents.")
+            }
+        }
+    }
+
+    override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+        // Speed up the animations to 100 times as fast.
+        defer { application.keyWindow?.layer.speed = 100.0 }
+        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+    }
+
+}
diff --git a/mobile/ios/Client/Application/WebServer.swift b/mobile/ios/Client/Application/WebServer.swift
new file mode 100644
index 0000000000..ba9e160b0a
--- /dev/null
+++ b/mobile/ios/Client/Application/WebServer.swift
@@ -0,0 +1,88 @@
+/* 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/. */
+
+import Foundation
+import GCDWebServers
+import Shared
+
+class WebServer {
+    private let log = Logger.browserLogger
+
+    static let WebServerSharedInstance = WebServer()
+
+    class var sharedInstance: WebServer {
+        return WebServerSharedInstance
+    }
+
+    let server: GCDWebServer = GCDWebServer()
+
+    var base: String {
+        return "http://localhost:\(server.port)"
+    }
+
+    /// The private credentials for accessing resources on this Web server.
+    let credentials: URLCredential
+
+    /// A random, transient token used for authenticating requests.
+    /// Other apps are able to make requests to our local Web server,
+    /// so this prevents them from accessing any resources.
+    fileprivate let sessionToken = UUID().uuidString
+
+    init() {
+        credentials = URLCredential(user: sessionToken, password: "", persistence: .forSession)
+    }
+
+    @discardableResult func start() throws -> Bool {
+        if !server.isRunning {
+            try server.start(options: [
+                GCDWebServerOption_Port: 6571,
+                GCDWebServerOption_BindToLocalhost: true,
+                GCDWebServerOption_AutomaticallySuspendInBackground: true,
+                GCDWebServerOption_AuthenticationMethod: GCDWebServerAuthenticationMethod_Basic,
+                GCDWebServerOption_AuthenticationAccounts: [sessionToken: ""]
+            ])
+        }
+        return server.isRunning
+    }
+
+    /// Convenience method to register a dynamic handler. Will be mounted at $base/$module/$resource
+    func registerHandlerForMethod(_ method: String, module: String, resource: String, handler: @escaping (_ request: GCDWebServerRequest?) -> GCDWebServerResponse!) {
+        // Prevent serving content if the requested host isn't a whitelisted local host.
+        let wrappedHandler = {(request: GCDWebServerRequest?) -> GCDWebServerResponse? in
+            guard let request = request, request.url.isLocal else {
+                return GCDWebServerResponse(statusCode: 403)
+            }
+
+            return handler(request)
+        }
+        server.addHandler(forMethod: method, path: "/\(module)/\(resource)", request: GCDWebServerRequest.self, processBlock: wrappedHandler)
+    }
+
+    /// Convenience method to register a resource in the main bundle. Will be mounted at $base/$module/$resource
+    func registerMainBundleResource(_ resource: String, module: String) {
+        if let path = Bundle.main.path(forResource: resource, ofType: nil) {
+            server.addGETHandler(forPath: "/\(module)/\(resource)", filePath: path, isAttachment: false, cacheAge: UInt.max, allowRangeRequests: true)
+        }
+    }
+
+    /// Convenience method to register all resources in the main bundle of a specific type. Will be mounted at $base/$module/$resource
+    func registerMainBundleResourcesOfType(_ type: String, module: String) {
+        for path: String in Bundle.paths(forResourcesOfType: type, inDirectory: Bundle.main.bundlePath) {
+            if let resource = NSURL(string: path)?.lastPathComponent {
+                server.addGETHandler(forPath: "/\(module)/\(resource)", filePath: path as String, isAttachment: false, cacheAge: UInt.max, allowRangeRequests: true)
+            } else {
+                log.warning("Unable to locate resource at path: '\(path)'")
+            }
+        }
+    }
+
+    /// Return a full url, as a string, for a resource in a module. No check is done to find out if the resource actually exist.
+    func URLForResource(_ resource: String, module: String) -> String {
+        return "\(base)/\(module)/\(resource)"
+    }
+
+    func baseReaderModeURL() -> String {
+        return WebServer.sharedInstance.URLForResource("page", module: "reader-mode")
+    }
+}
diff --git a/mobile/ios/Client/Application/main.swift b/mobile/ios/Client/Application/main.swift
new file mode 100644
index 0000000000..86bc5ef193
--- /dev/null
+++ b/mobile/ios/Client/Application/main.swift
@@ -0,0 +1,16 @@
+/* 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/. */
+
+import Shared
+
+private var appDelegate: AppDelegate.Type
+
+if AppConstants.IsRunningTest {
+    appDelegate = TestAppDelegate.self
+} else {
+    appDelegate = AppDelegate.self
+}
+
+private let pointer = UnsafeMutableRawPointer(CommandLine.unsafeArgv).bindMemory(to: UnsafeMutablePointer.self, capacity: Int(CommandLine.argc))
+UIApplicationMain(CommandLine.argc, pointer, NSStringFromClass(UIApplication.self), NSStringFromClass(appDelegate))
diff --git a/mobile/ios/Client/Assets/About/Licenses.html b/mobile/ios/Client/Assets/About/Licenses.html
new file mode 100644
index 0000000000..3dc42de43c
--- /dev/null
+++ b/mobile/ios/Client/Assets/About/Licenses.html
@@ -0,0 +1,674 @@
+
+
+
+
+
+
+
+

Licenses

+ +

Firefox for iOS

+ +
+ + + + +

Mozilla Public License
Version 2.0

+

1. Definitions

+
+
1.1. “Contributor”
+

means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software.

+
+
1.2. “Contributor Version”
+

means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution.

+
+
1.3. “Contribution”
+

means Covered Software of a particular Contributor.

+
+
1.4. “Covered Software”
+

means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof.

+
+
1.5. “Incompatible With Secondary Licenses”
+

means

+
    +
  1. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or

  2. +
  3. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License.

  4. +
+
+
1.6. “Executable Form”
+

means any form of the work other than Source Code Form.

+
+
1.7. “Larger Work”
+

means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software.

+
+
1.8. “License”
+

means this document.

+
+
1.9. “Licensable”
+

means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License.

+
+
1.10. “Modifications”
+

means any of the following:

+
    +
  1. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or

  2. +
  3. any new file in Source Code Form that contains any Covered Software.

  4. +
+
+
1.11. “Patent Claims” of a Contributor
+

means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version.

+
+
1.12. “Secondary License”
+

means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses.

+
+
1.13. “Source Code Form”
+

means the form of the work preferred for making modifications.

+
+
1.14. “You” (or “Your”)
+

means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.

+
+
+

2. License Grants and Conditions

+

2.1. Grants

+

Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:

+
    +
  1. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and

  2. +
  3. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version.

  4. +
+

2.2. Effective Date

+

The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution.

+

2.3. Limitations on Grant Scope

+

The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor:

+
    +
  1. for any code that a Contributor has removed from Covered Software; or

  2. +
  3. for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or

  4. +
  5. under Patent Claims infringed by Covered Software in the absence of its Contributions.

  6. +
+

This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4).

+

2.4. Subsequent Licenses

+

No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3).

+

2.5. Representation

+

Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License.

+

2.6. Fair Use

+

This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents.

+

2.7. Conditions

+

Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1.

+

3. Responsibilities

+

3.1. Distribution of Source Form

+

All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form.

+

3.2. Distribution of Executable Form

+

If You distribute Covered Software in Executable Form then:

+
    +
  1. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and

  2. +
  3. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License.

  4. +
+

3.3. Distribution of a Larger Work

+

You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s).

+

3.4. Notices

+

You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies.

+

3.5. Application of Additional Terms

+

You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction.

+

4. Inability to Comply Due to Statute or Regulation

+

If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it.

+

5. Termination

+

5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice.

+

5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.

+

5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination.

+

6. Disclaimer of Warranty

+

Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer.

+

7. Limitation of Liability

+

Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.

+

8. Litigation

+

Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims.

+

9. Miscellaneous

+

This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor.

+

10. Versions of the License

+

10.1. New Versions

+

Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number.

+

10.2. Effect of New Versions

+

You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward.

+

10.3. Modified Versions

+

If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License).

+

10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses

+

If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached.

+

Exhibit A - Source Code Form License Notice

+
+

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/.

+
+

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

+

You may add additional accurate notices of copyright ownership.

+

Exhibit B - “Incompatible With Secondary Licenses” Notice

+
+

This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.

+
+ + + + + + + +
+ +

-

+ + + +

Alamofire

+ +
+

Copyright (c) 2014 Alamofire (http://alamofire.org/)

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+

-

+ + + +

Base32

+ +
+

The MIT License (MIT)

+ +

Copyright (c) 2015 Norio Nomura

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+

-

+ +

Box

+ +
+

The MIT License (MIT)

+ +

Copyright (c) 2014 Rob Rix

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

+
+

-

+ +

Deferred

+ +
+

Copyright (c) 2014 John Gallagher <jgallagher@bignerdranch.com> + +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +

FilledPageControl

+

Copyright (c) 2016 Kyle Zaragoza

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+ + +

GCDWebServer

+ +
+

Copyright (c) 2012-2014, Pierre-Olivier Latour

+

All rights reserved.

+ +

Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met:

+ +
    +
  • Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer.
  • +
  • Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution.
  • +
  • The name of Pierre-Olivier Latour may not be used to endorse +or promote products derived from this software without specific +prior written permission.
  • +
+ +

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+
+

-

+ + +

KIF

+ +
+

Copyright 2011 Square, Inc.

+

A full list of contributors is available at https://github.com/square/KIF/contributors

+ +

Licensed under the Apache License, Version 2.0 (the "License");

+you may not use this file except in compliance with the License. +You may obtain a copy of the License at

+ +

http://www.apache.org/licenses/LICENSE-2.0

+ +

Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.

+
+ +

Result

+ +
+

Copyright (c) 2014 John Gallagher <jgallagher@bignerdranch.com>

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +

SDWebImage

+ +
+

Copyright (c) 2009 Olivier Poitrey <rs@dailymotion.com>

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+

-

+ + +

SQLite.swift

+ +
+

(The MIT License)

+ +

Copyright (c) 2014-2015 Stephen Celis (<stephen@stephencelis.com>)

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+

-

+ + +

Fuzi

+ +
+

Copyright (c) 2015 Ce Zheng

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+

-

+ + +

Snap

+ +
+

Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+

-

+ + +

XCGLogger

+ +
+

The MIT License (MIT)

+ +

Copyright (c) 2014 Dave Wood, Cerebral Gardens http://www.cerebralgardens.com/

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+

-

+ + +

Readability

+ +
+

Copyright (c) 2010 Arc90 Inc

+ +

Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at

+ +

http://www.apache.org/licenses/LICENSE-2.0

+ +

Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.

+
+

-

+ + +

sqlchipher

+ +
+

Copyright (c) 2008, ZETETIC LLC

+

All rights reserved.

+ +

Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met:

+ +
    +
  • Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer.
  • +
  • Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution.
  • +
  • Neither the name of the ZETETIC LLC nor the +names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission.
  • +
+ +

THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+
+

-

+ + +

SwiftKeychainWrapper

+ +
+

The MIT License (MIT)

+ +

Copyright (c) 2014 Jason

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+

-

+ + +

Swift-JSON

+ +
+

The MIT License (MIT)

+ +

Copyright (c) 2014 Dan Kogai

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+ +
+

UIImageColors

+ + +

Created by Jathu Satkunarajah (@jathu) on 2015-06-11 - Toronto

+

Original Cocoa version by Panic Inc. - Portland

+ +

MIT License

+ +

Copyright (c) 2015 Jathu Satkunarajah

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+ +

UIImageViewAligned

+ +
+

The MIT License (MIT)

+ +

Copyright (c) 2013 Andrei Stanescu

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+
+ + diff --git a/mobile/ios/Client/Assets/CertError.css b/mobile/ios/Client/Assets/CertError.css new file mode 100644 index 0000000000..436541d92b --- /dev/null +++ b/mobile/ios/Client/Assets/CertError.css @@ -0,0 +1,76 @@ +/* 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, +body { + margin: 0; + padding: 0; + height: 100%; +} + +body { + background-color: white; + padding: 0 65px; + color: #333; + font-size: 13px; + font-family: "Helvetica Neue Medium" sans-serif; +} + +h1 { + color: #333; + font-size: 16px; + font-family: "Helvetica Neue Medium" sans-serif; + font-weight: 300; + margin-bottom: 25px; +} + +/* Add a set of stripes at the top of pages */ +#decoration { + background-image: repeating-linear-gradient(-65deg, #ed2, #ed2 10px, + #fe3 10px, #fe3 20px, + #ed2 20px); + position: fixed; + top: 0; + left: 0; + height: 32px; + width: 100%; +} + +a { + color: rgb(76, 158, 255); + text-decoration: none; +} + +button { + width: 100%; + border: none; + padding: 1rem; + font-family: "Helvetica Neue Medium" sans-serif; + background-color: rgb(76, 158, 255); + color: white; + font-size: 16px; + font-weight: 300; + border-radius: 5px; +} + +#errorPageContainer { + max-width: 300px; + margin: 0 auto; + -webkit-transform: translateY(70px); + padding-bottom: 10px; +} + +#certErrorCode { + color: #999; +} + +#advancedButton { + background-color: white; + color: #777; + border: 1px solid #aaa; +} + +#advancedContent { + margin-bottom: 20px; +} diff --git a/mobile/ios/Client/Assets/CertError.html b/mobile/ios/Client/Assets/CertError.html new file mode 100644 index 0000000000..3e576475b9 --- /dev/null +++ b/mobile/ios/Client/Assets/CertError.html @@ -0,0 +1,49 @@ + + + + + %error_title% + + + + + + + +
+

%error_title%

+

%actions%

+

%long_description%

+ + +
+

%cert_error%

+

%warning_advanced1%

+

%warning_advanced2%

+
%warning_actions%
+
+
+ +
+ + + + diff --git a/mobile/ios/Client/Assets/ContextMenu.js b/mobile/ios/Client/Assets/ContextMenu.js new file mode 100644 index 0000000000..91e701c0c0 --- /dev/null +++ b/mobile/ios/Client/Assets/ContextMenu.js @@ -0,0 +1,28 @@ +/* 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/. */ + +window.addEventListener('touchstart', function(evt) { + var target = evt.target; + + var targetLink = target.closest('a'); + var targetImage = target.closest('img'); + + if (!targetLink && !targetImage) { + return; + } + + var data = {}; + + if (targetLink) { + data.link = targetLink.href; + } + + if (targetImage) { + data.image = targetImage.src; + } + + if (data.link || data.image) { + webkit.messageHandlers.contextMenuMessageHandler.postMessage(data); + } +}, true); diff --git a/mobile/ios/Client/Assets/CustomSearchHelper.js b/mobile/ios/Client/Assets/CustomSearchHelper.js new file mode 100644 index 0000000000..5dc8e7dc83 --- /dev/null +++ b/mobile/ios/Client/Assets/CustomSearchHelper.js @@ -0,0 +1,42 @@ +/* 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"; + +if (!window.__firefox__) { + Object.defineProperty(window, '__firefox__', { + enumerable: false, + configurable: false, + writable: false, + value: {} + }); +} + +Object.defineProperty(window.__firefox__, 'searchQueryForField', { + enumerable: false, + configurable: false, + writable: false, + value: function() { + var input = document.activeElement; + if (input.tagName.toLowerCase() !== 'input') return null; + var form = input.form; + if (!form || form.method.toLowerCase() != 'get') return null; + + var inputs = form.getElementsByTagName('input'); + inputs = Array.prototype.slice.call(inputs, 0); + var params = inputs.map(function(element) { + if (element.name == input.name) return [element.name, '{searchTerms}'].join('='); + return [element.name, element.value].map(encodeURIComponent).join('='); + }); + + var selectFields = form.getElementsByTagName('select'); + selectFields = Array.prototype.slice.call(selectFields, 0); + var selectParams = selectFields.map(function(e){ + return [e.name, e.options[e.selectedIndex].value].map(encodeURIComponent).join('='); + }); + params = params.concat(selectParams); + if (!form.action) return null; //an invalid form. + var url = [form.action, params.join('&')].join('?'); + return url; + } +}); diff --git a/mobile/ios/Client/Assets/Favicons.js b/mobile/ios/Client/Assets/Favicons.js new file mode 100644 index 0000000000..bc867b752b --- /dev/null +++ b/mobile/ios/Client/Assets/Favicons.js @@ -0,0 +1,60 @@ +/* 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/. */ + + +if (!window.__firefox__) { + Object.defineProperty(window, '__firefox__', { + enumerable: false, + configurable: false, + writable: false, + value: {} + }); +} + +Object.defineProperty(window.__firefox__, 'favicons', { + enumerable: false, + configurable: false, + writable: false, + value: (function() { + // These integers should be kept in sync with the IconType raw-values + var ICON = 0; + var APPLE = 1; + var APPLE_PRECOMPOSED = 2; + var GUESS = 3; + + var selectors = { + "link[rel~='icon']": ICON, + "link[rel='apple-touch-icon']": APPLE, + "link[rel='apple-touch-icon-precomposed']": APPLE_PRECOMPOSED + }; + + function getAll() { + var favicons = {}; + + for (var selector in selectors) { + var icons = document.querySelectorAll(selector); + for (var i = 0; i < icons.length; i++) { + var href = icons[i].href; + favicons[href] = selectors[selector]; + } + } + + // If we didn't find anything in the page, look to see if a favicon.ico file exists for the domain + if (Object.keys(favicons).length === 0) { + var href = document.location.origin + "/favicon.ico"; + favicons[href] = GUESS; + } + return favicons; + } + + function getFavicons() { + var favicons = getAll(); + webkit.messageHandlers.faviconsMessageHandler.postMessage(favicons); + } + + return { + getFavicons: getFavicons + }; + })() +}); diff --git a/mobile/ios/Client/Assets/FindInPage.js b/mobile/ios/Client/Assets/FindInPage.js new file mode 100644 index 0000000000..51680c8ca4 --- /dev/null +++ b/mobile/ios/Client/Assets/FindInPage.js @@ -0,0 +1,292 @@ +/* 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/. */ + +(function() { +"use strict"; + +var DEBUG_ENABLED = false; +var MATCH_HIGHLIGHT_ACTIVE = "#f19750"; +var MATCH_HIGHLIGHT_INACTIVE = "#ffde49"; +var SCROLL_INTERVAL_INCREMENT = 5; +var SCROLL_INTERVAL_DURATION = 400; +var SCROLL_OFFSET = 60; + +var activeHighlightSpan = null; +var lastSearch; +var scrollInterval; +var activeIndex = 0; +var highlightSpans = []; + +function debug(str) { + if (DEBUG_ENABLED) { + console.log("FindInPage: " + str); + } +} + +function isElementVisible(elem) { + return getComputedStyle(elem).visibility !== "hidden"; +} + +function isRectInViewport(rect) { + var left = rect.left + document.body.scrollLeft; + var right = rect.right + document.body.scrollLeft; + var top = rect.top + document.body.scrollTop; + var bottom = rect.bottom + document.body.scrollTop; + + return rect.width > 0 && + rect.height > 0 && + right >= 0 && + bottom >= 0 && + left <= document.body.scrollWidth && + top <= document.body.scrollHeight; +} + +function findMatches(text) { + // For case-insensitive matching. + var lowerText = text.toLocaleLowerCase(); + var upperText = text.toLocaleUpperCase(); + + var matches = []; + var range = document.createRange(); + var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false); + var textLength = text.length; + var node; + while (node = walker.nextNode()) { + var textContent = node.textContent; + findString: for (var i = 0; i < textContent.length - textLength + 1; ++i) { + for (var j = 0; j < textLength; ++j) { + var nextChar = textContent[i + j]; + if (lowerText[j] !== nextChar && upperText[j] !== nextChar) { + continue findString; + } + } + + // This node is a TextNode, not an Element. Its parent is the nearest Element. + var element = node.parentNode; + + // Find the rect of just the text for this match. + range.setStart(node, i); + range.setEnd(node, i + textLength); + var textRect = range.getBoundingClientRect(); + + // We have a match, but we need to make sure it's visible. The condition + // below checks the following cases: + // * If this element or any of its parents has style visibility hidden. + // The visibility style is inherited, so we need to check only this + // element and not all of its ancestors. + // * If the highlight will be outside of the page's bounds. We determine + // this by comparing the bounds of the text rect. + // * If the element style display is set to none. display:none collapses + // the element's space, so this will again be detected by looking at + // the text's rect: if the element is collapsed, the width and height + // will be zero. + if (isElementVisible(element) && isRectInViewport(textRect)) { + matches.push({ node: node, index: i }); + + // Resume searching after this match to prevent overlapping results. + i += textLength- 1; + } + } + } + + return matches; +} + +function flattenNode(node) { + var parent = node.parentNode; + if (!parent) { + return; + } + + while (node.firstChild) { + parent.insertBefore(node.firstChild, node); + } + + node.remove(); + parent.normalize(); +} + +function clearHighlights() { + if (highlightSpans.length > 0) { + for (var span of highlightSpans) { + flattenNode(span); + } + highlightSpans = []; + } + + activeHighlightSpan = null; +} + +function highlightAllMatches(text) { + debug("Searching: " + text); + + clearHighlights(); + + if (!text.trim()) { + webkit.messageHandlers.findInPageHandler.postMessage({ totalResults: 0 }); + return; + } + + var range = document.createRange(); + var matches = findMatches(text); + var highlightTemplate = document.createElement("span"); + highlightTemplate.style.backgroundColor = MATCH_HIGHLIGHT_INACTIVE; + + // If there are multiple matches in the same node, inserting a highlight span before other matches + // in that node will invalidate other matches since the node itself changes. By iterating through + // results in reverse, we highlight matches last in the node first so earlier matches are unaffected. + for (var i = matches.length - 1; i >= 0; --i) { + var match = matches[i]; + var highlight = highlightTemplate.cloneNode(); + + range.setStart(match.node, match.index); + range.setEnd(match.node, match.index + text.length); + range.surroundContents(highlight); + highlightSpans.unshift(highlight); + } + + debug(matches.length + " highlighted rects created!"); + webkit.messageHandlers.findInPageHandler.postMessage({ totalResults: matches.length }); +} + +function getIDForRect(rect) { + return rect.top + "," + rect.bottom + "," + rect.left + "," + rect.right; +} + +function updateActiveHighlight() { + // Reset the color of the previous highlight. + if (activeHighlightSpan) { + activeHighlightSpan.style.backgroundColor = MATCH_HIGHLIGHT_INACTIVE; + } + + if (!highlightSpans.length) { + return; + } + + activeHighlightSpan = highlightSpans[activeIndex]; + activeHighlightSpan.style.backgroundColor = MATCH_HIGHLIGHT_ACTIVE; + + // Find the position of the element centered on the screen, then scroll to it. + var rect = activeHighlightSpan.getBoundingClientRect(); + var top = SCROLL_OFFSET + rect.top + scrollY - window.innerHeight / 2; + var left = rect.left + scrollX - window.innerWidth / 2; + left = clamp(left, 0, document.body.scrollWidth); + top = clamp(top, 0, document.body.scrollHeight); + scrollToSelection(left, top, SCROLL_INTERVAL_DURATION); + debug("Scrolled to: " + left + ", " + top); +} + +function scrollToSelection(left, top, duration) { + var time = 0; + var startX = scrollX; + var startY = scrollY; + clearInterval(scrollInterval); + scrollInterval = setInterval(function() { + var xStep = easeOutCubic(time, startX, left - startX, duration); + var yStep = easeOutCubic(time, startY, top - startY, duration); + window.scrollTo(xStep, yStep); + time += SCROLL_INTERVAL_INCREMENT; + if (time >= duration) { + clearInterval(scrollInterval); + } + }, SCROLL_INTERVAL_INCREMENT); +} + +function easeOutCubic(currentTime, startValue, changeInValue, duration) { + return changeInValue * (Math.pow(currentTime / duration - 1, 3) + 1) + startValue; +} + +function clamp(number, min, max) { + return Math.max(min, Math.min(number, max)); +} + +function updateSearch(text) { + if (lastSearch == text) { + // The text is the same, so we're either finding either the next or previous result. + var totalResults = highlightSpans.length; + activeIndex = (activeIndex + totalResults) % totalResults; + } else { + // Store the current active rect to decide which new match should be active. + var activeHighlightRect = null; + if (activeHighlightSpan) { + activeHighlightRect = activeHighlightSpan.getBoundingClientRect(); + } + + // The search text changed, so scan the page for new results. + highlightAllMatches(text); + + // If we found a match at or after the last match, use that position + // instead of starting again from the top. + activeIndex = 0; + if (activeHighlightRect) { + for (var i = 0; i < highlightSpans.length; i++) { + var highlight = highlightSpans[i]; + var highlightRect = highlight.getBoundingClientRect(); + if ((highlightRect.top == activeHighlightRect.top && highlightRect.left >= activeHighlightRect.left) || + (highlightRect.top > activeHighlightRect.top)) { + activeIndex = i; + break; + } + } + } + + lastSearch = text; + } + + // Update the UI with the current match index. + var currentResult = highlightSpans.length ? activeIndex + 1 : 0; + webkit.messageHandlers.findInPageHandler.postMessage({ currentResult: currentResult }); + + updateActiveHighlight(); +} + +if (!window.__firefox__) { + Object.defineProperty(window, '__firefox__', { + enumerable: false, + configurable: false, + writable: false, + value: {} + }); +} + +Object.defineProperty(window.__firefox__, 'find', { + enumerable: false, + configurable: false, + writable: false, + value: function(text) { + updateSearch(text); + } +}); + +Object.defineProperty(window.__firefox__, 'findNext', { + enumerable: false, + configurable: false, + writable: false, + value: function(text) { + activeIndex++; + updateSearch(text); + } +}); + +Object.defineProperty(window.__firefox__, 'findPrevious', { + enumerable: false, + configurable: false, + writable: false, + value: function(text) { + activeIndex--; + updateSearch(text); + } +}); + +Object.defineProperty(window.__firefox__, 'findDone', { + enumerable: false, + configurable: false, + writable: false, + value: function() { + clearHighlights(); + lastSearch = null; + } +}); + +})(); diff --git a/mobile/ios/Client/Assets/Fonts/CharisSILB.ttf b/mobile/ios/Client/Assets/Fonts/CharisSILB.ttf new file mode 100644 index 0000000000..379487af39 Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/CharisSILB.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/CharisSILBI.ttf b/mobile/ios/Client/Assets/Fonts/CharisSILBI.ttf new file mode 100644 index 0000000000..917f3692d8 Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/CharisSILBI.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/CharisSILI.ttf b/mobile/ios/Client/Assets/Fonts/CharisSILI.ttf new file mode 100644 index 0000000000..852ae437be Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/CharisSILI.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/CharisSILR.ttf b/mobile/ios/Client/Assets/Fonts/CharisSILR.ttf new file mode 100644 index 0000000000..5b55ec98dd Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/CharisSILR.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-Bold.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-Bold.ttf new file mode 100644 index 0000000000..04830e7e1b Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-Bold.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-BoldItalic.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-BoldItalic.ttf new file mode 100644 index 0000000000..671c3f190b Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-BoldItalic.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-Book.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-Book.ttf new file mode 100644 index 0000000000..4da8f660ec Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-Book.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-Italic.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-Italic.ttf new file mode 100644 index 0000000000..3b7d61bfbe Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-Italic.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-Light.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-Light.ttf new file mode 100644 index 0000000000..314116d14c Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-Light.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-Medium.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-Medium.ttf new file mode 100644 index 0000000000..e6a6637b0a Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-Medium.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-Regular.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-Regular.ttf new file mode 100644 index 0000000000..a4e6563806 Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-Regular.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-SemiBold.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-SemiBold.ttf new file mode 100644 index 0000000000..be24d2b6db Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-SemiBold.ttf differ diff --git a/mobile/ios/Client/Assets/Fonts/FiraSans-UltraLight.ttf b/mobile/ios/Client/Assets/Fonts/FiraSans-UltraLight.ttf new file mode 100644 index 0000000000..b1da1656bb Binary files /dev/null and b/mobile/ios/Client/Assets/Fonts/FiraSans-UltraLight.ttf differ diff --git a/mobile/ios/Client/Assets/FxASignIn.js b/mobile/ios/Client/Assets/FxASignIn.js new file mode 100644 index 0000000000..064b6110f2 --- /dev/null +++ b/mobile/ios/Client/Assets/FxASignIn.js @@ -0,0 +1,15 @@ +/* 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/. */ + +/** + * Transport postMessage events from the fxa-content-server to the embedding + * webview. + */ + +"use strict"; + +function handleAccountsCommand(evt) { + webkit.messageHandlers.accountsCommandHandler.postMessage({ type: evt.type, detail: evt.detail }); +}; +window.addEventListener("FirefoxAccountsCommand", handleAccountsCommand); diff --git a/mobile/ios/Client/Assets/HistoryStateHelper.js b/mobile/ios/Client/Assets/HistoryStateHelper.js new file mode 100644 index 0000000000..0cdb8ff2ad --- /dev/null +++ b/mobile/ios/Client/Assets/HistoryStateHelper.js @@ -0,0 +1,36 @@ +/* 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/. */ + +(function() { + var nativeHistoryPushState = window.history.pushState; + var nativeHistoryReplaceState = window.history.replaceState; + + // We need to catch calls to `history.pushState()` in order to + // notify the BrowserViewController so that history can be + // recorded in single-page web applications that do all rendering + // on the client side. + window.history.pushState = function(state, title, url) { + nativeHistoryPushState.apply(this, arguments); + webkit.messageHandlers.historyStateHelper.postMessage({ + pushState: true, + state: state, + title: title, + url: url + }); + }; + + // We need to catch calls to `history.replaceState()` in order to + // notify the BrowserViewController so that history can be + // recorded in single-page web applications that do all rendering + // on the client side. + window.history.replaceState = function(state, title, url) { + nativeHistoryReplaceState.apply(this, arguments); + webkit.messageHandlers.historyStateHelper.postMessage({ + replaceState: true, + state: state, + title: title, + url: url + }); + }; +})(); diff --git a/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch.png b/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch.png new file mode 100644 index 0000000000..2d1eadbbf9 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch@2x.png new file mode 100644 index 0000000000..ba099d0056 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch@3x.png b/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch@3x.png new file mode 100644 index 0000000000..b4b3454816 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/AddSearch@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/Contents.json new file mode 100644 index 0000000000..140382e425 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/AddSearch.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "AddSearch.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "AddSearch@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "AddSearch@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..ac0824585c --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,150 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-40.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-60.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon-83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "icon-512@2x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/iTunesArtwork@2x-1.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/iTunesArtwork@2x-1.png new file mode 100644 index 0000000000..18b49af615 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/iTunesArtwork@2x-1.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29.png new file mode 100644 index 0000000000..e686b65993 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29@2x.png new file mode 100644 index 0000000000..5ed8287c39 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29@3x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29@3x.png new file mode 100644 index 0000000000..218370a360 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-29@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40.png new file mode 100644 index 0000000000..cc8e1fa4ce Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40@2x.png new file mode 100644 index 0000000000..b41485156b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40@3x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40@3x.png new file mode 100644 index 0000000000..66c0d8c3cb Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-40@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-512@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-512@2x.png new file mode 100644 index 0000000000..e4707a3197 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-512@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60.png new file mode 100644 index 0000000000..c9e15a99c2 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60@2x.png new file mode 100644 index 0000000000..2d343f6583 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60@3x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60@3x.png new file mode 100644 index 0000000000..4efcf6ef42 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-60@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-76.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-76.png new file mode 100644 index 0000000000..c7ff33a5e9 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-76.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-76@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-76@2x.png new file mode 100644 index 0000000000..d63965910e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-76@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-83.5@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-83.5@2x.png new file mode 100644 index 0000000000..677771fef8 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon.appiconset/icon-83.5@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/Contents.json new file mode 100644 index 0000000000..f5925b7973 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/Contents.json @@ -0,0 +1,151 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-40.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-60.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon-83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "icon-512@2x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/iTunesArtwork@2x-1.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/iTunesArtwork@2x-1.png new file mode 100644 index 0000000000..18b49af615 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/iTunesArtwork@2x-1.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29.png new file mode 100644 index 0000000000..ce2ec8ce67 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29@2x.png new file mode 100644 index 0000000000..64985b4fbe Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29@3x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29@3x.png new file mode 100644 index 0000000000..8c3c173d94 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-29@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40.png new file mode 100644 index 0000000000..4cb6e2e52d Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40@2x.png new file mode 100644 index 0000000000..f3dae1ea0d Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40@3x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40@3x.png new file mode 100644 index 0000000000..ddb92c1a75 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-40@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-512@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-512@2x.png new file mode 100644 index 0000000000..b0bcee4f46 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-512@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60.png new file mode 100644 index 0000000000..72b81451df Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60@2x.png new file mode 100644 index 0000000000..db49d15a64 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60@3x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60@3x.png new file mode 100644 index 0000000000..deb57c142e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-60@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-76.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-76.png new file mode 100644 index 0000000000..1d07e4e792 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-76.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-76@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-76@2x.png new file mode 100644 index 0000000000..c6caeed618 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-76@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-83.5@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-83.5@2x.png new file mode 100644 index 0000000000..507f9e0e3f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Beta.appiconset/icon-83.5@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Contents.json new file mode 100644 index 0000000000..7f766f0ae1 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Contents.json @@ -0,0 +1,149 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-60@2x.png", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-Small.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-Small@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-Small-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-Small-40@2x.png", + "scale" : "2x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50.png", + "scale" : "1x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50@2x.png", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-72.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-72@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-iPadPro@2x.png", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-60@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-60@2x.png new file mode 100644 index 0000000000..69afebf0da Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-60@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-60@3x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-60@3x.png new file mode 100644 index 0000000000..180cf0d82c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-60@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-72.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-72.png new file mode 100644 index 0000000000..536b4a6542 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-72.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-72@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-72@2x.png new file mode 100644 index 0000000000..9e9edef349 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-72@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-76.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-76.png new file mode 100644 index 0000000000..0eef6df03a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-76.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-76@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-76@2x.png new file mode 100644 index 0000000000..825494321e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-76@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-40.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-40.png new file mode 100644 index 0000000000..ed4c714c6e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-40.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-40@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-40@2x.png new file mode 100644 index 0000000000..38fc1017b1 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-40@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-50.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-50.png new file mode 100644 index 0000000000..02bb55fee5 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-50.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-50@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-50@2x.png new file mode 100644 index 0000000000..a6272eada9 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small-50@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small.png new file mode 100644 index 0000000000..8f8c3cf8a8 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small@2x.png new file mode 100644 index 0000000000..7d3f3136c5 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-Small@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-iPadPro@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-iPadPro@2x.png new file mode 100644 index 0000000000..68c747d41a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon-iPadPro@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon.png new file mode 100644 index 0000000000..d9d8ee0f56 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon@2x.png b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon@2x.png new file mode 100644 index 0000000000..a744cc6d93 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/AppIcon_Developer.appiconset/Icon@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/Contents.json new file mode 100644 index 0000000000..ce0bef5ead --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "close.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "close@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "close@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close.png new file mode 100644 index 0000000000..bc8f358e63 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close@2x.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close@2x.png new file mode 100644 index 0000000000..b2e3df259e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close@3x.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close@3x.png new file mode 100644 index 0000000000..271f5d22da Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_close.imageset/close@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/Contents.json new file mode 100644 index 0000000000..84d814f3a8 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "down-caret.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "down-caret@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "down-caret@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret.png new file mode 100644 index 0000000000..ca70b1d339 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret@2x.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret@2x.png new file mode 100644 index 0000000000..90dffe4746 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret@3x.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret@3x.png new file mode 100644 index 0000000000..40281ff09c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_next.imageset/down-caret@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/Contents.json new file mode 100644 index 0000000000..50177e45fc --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "up-caret.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "up-caret@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "up-caret@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret.png new file mode 100644 index 0000000000..ad0177faad Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret@2x.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret@2x.png new file mode 100644 index 0000000000..07b96e97e0 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret@3x.png b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret@3x.png new file mode 100644 index 0000000000..885cdcfabf Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/Find In Page/find_previous.imageset/up-caret@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/Contents.json new file mode 100644 index 0000000000..934a827005 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "context-bookmark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "context-bookmark@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "context-bookmark@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark.png new file mode 100644 index 0000000000..e841e66870 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark@2x.png new file mode 100644 index 0000000000..c141cbf11a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark@3x.png new file mode 100644 index 0000000000..3ee251dbc5 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_bookmark.imageset/context-bookmark@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/Contents.json new file mode 100644 index 0000000000..fe685af20f --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "context-open.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "context-open@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "context-open@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open.png new file mode 100644 index 0000000000..97836f00a8 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open@2x.png new file mode 100644 index 0000000000..237e493f79 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open@3x.png new file mode 100644 index 0000000000..ac353e0edf Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_open.imageset/context-open@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/Contents.json new file mode 100644 index 0000000000..d969b7c7cb --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "context-sync.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "context-sync@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "context-sync@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync.png new file mode 100644 index 0000000000..c6d8de4d1d Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync@2x.png new file mode 100644 index 0000000000..3ab46d84a8 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync@3x.png new file mode 100644 index 0000000000..4be467bb33 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_sync.imageset/context-sync@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/Contents.json new file mode 100644 index 0000000000..8d80d53aed --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "context-viewed.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "context-viewed@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "context-viewed@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed.png new file mode 100644 index 0000000000..451d832b79 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed@2x.png new file mode 100644 index 0000000000..2251d042e0 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed@3x.png new file mode 100644 index 0000000000..83f269615f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/context_viewed.imageset/context-viewed@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/Contents.json new file mode 100644 index 0000000000..87ea3dc957 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "defaultTopSiteIcon.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "defaultTopSiteIcon@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "defaultTopSiteIcon@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon.png new file mode 100644 index 0000000000..b9eaee02c2 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon@2x.png new file mode 100644 index 0000000000..377e56b11c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon@3x.png new file mode 100644 index 0000000000..813b775563 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/defaultTopSiteIcon.imageset/defaultTopSiteIcon@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/Contents.json new file mode 100644 index 0000000000..58b6fb9a2b --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "pin-small.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "pin-small@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "pin-small@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small.png new file mode 100644 index 0000000000..e396ad4df7 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small@2x.png new file mode 100644 index 0000000000..84ada8d0b6 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small@3x.png new file mode 100644 index 0000000000..f1c3a4061d Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Activity Stream/pin_small.imageset/pin-small@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/Contents.json new file mode 100644 index 0000000000..634f28fb7f --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "action-bookmark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "action-bookmark@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "action-bookmark@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark.png new file mode 100644 index 0000000000..8855921529 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark@2x.png new file mode 100644 index 0000000000..4a19d302dd Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark@3x.png new file mode 100644 index 0000000000..2d6b48f8fe Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark.imageset/action-bookmark@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/Contents.json new file mode 100644 index 0000000000..f61da3da9f --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "action-bookmark-remove.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "action-bookmark-remove@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "action-bookmark-remove@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove.png new file mode 100644 index 0000000000..8d66b36d99 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove@2x.png new file mode 100644 index 0000000000..bdb615f03e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove@3x.png new file mode 100644 index 0000000000..388cddb0b7 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_bookmark_remove.imageset/action-bookmark-remove@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/Contents.json new file mode 100644 index 0000000000..af874c87b7 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "action-delete.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "action-delete@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "action-delete@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete.png new file mode 100644 index 0000000000..c5558b03fa Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete@2x.png new file mode 100644 index 0000000000..4887e4d800 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete@3x.png new file mode 100644 index 0000000000..7c9b013017 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_delete.imageset/action-delete@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/Contents.json new file mode 100644 index 0000000000..4853fc215e --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "pin-28.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "pin-28@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "pin-28@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28.png new file mode 100644 index 0000000000..aa499fd220 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28@2x.png new file mode 100644 index 0000000000..c6a15d4061 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28@3x.png new file mode 100644 index 0000000000..7f86c43493 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_pin.imageset/pin-28@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/Contents.json new file mode 100644 index 0000000000..83911224ce --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "action-remove.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "action-remove@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "action-remove@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove.png new file mode 100644 index 0000000000..bb734fd300 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove@2x.png new file mode 100644 index 0000000000..f284416a28 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove@3x.png new file mode 100644 index 0000000000..ce55a980f6 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_remove.imageset/action-remove@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/Contents.json new file mode 100644 index 0000000000..d3f5a2b43a --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "action-share.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "action-share@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "action-share@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share.png new file mode 100644 index 0000000000..f6906f3268 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share@2x.png new file mode 100644 index 0000000000..36c42af0cd Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share@3x.png new file mode 100644 index 0000000000..48dd93260c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_share.imageset/action-share@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/Contents.json new file mode 100644 index 0000000000..ecbfadc9b4 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "pinremove.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "pinremove@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "pinremove@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove.png new file mode 100644 index 0000000000..ed7405b12a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove@2x.png new file mode 100644 index 0000000000..7be480e450 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove@3x.png new file mode 100644 index 0000000000..0d318d2df7 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Context menu/action_unpin.imageset/pinremove@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/Contents.json new file mode 100644 index 0000000000..4c1381f4b6 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "UnRead.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "UnRead@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "UnRead@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead.png new file mode 100644 index 0000000000..1fd050cdd6 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead@2x.png new file mode 100644 index 0000000000..102338529b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead@3x.png new file mode 100644 index 0000000000..36e4f55100 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsRead.imageset/UnRead@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Contents.json new file mode 100644 index 0000000000..d5a344b77e --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Read.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Read@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Read@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read.png new file mode 100644 index 0000000000..2c3e6c0675 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read@2x.png new file mode 100644 index 0000000000..80150c9a02 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read@3x.png new file mode 100644 index 0000000000..b019faaff7 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/MarkAsUnread.imageset/Read@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/Contents.json new file mode 100644 index 0000000000..2590c5c946 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reader-active.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "reader-active@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "reader-active@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active.png new file mode 100644 index 0000000000..d52506cf9e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active@2x.png new file mode 100644 index 0000000000..c5f14e2c80 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active@3x.png new file mode 100644 index 0000000000..c06efb3720 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeActive.imageset/reader-active@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/Contents.json new file mode 100644 index 0000000000..c38bff5d49 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "readerOff.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "readerOff@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "readerOff@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff.png new file mode 100644 index 0000000000..64466e2197 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff@2x.png new file mode 100644 index 0000000000..52cb45c219 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff@3x.png new file mode 100644 index 0000000000..d6b183e99c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/ReaderModeAvailable.imageset/readerOff@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira.png new file mode 100644 index 0000000000..dcb18d3343 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira@2x.png new file mode 100644 index 0000000000..161377faab Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira@3x.png new file mode 100644 index 0000000000..289749ccb9 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/AaFira@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/Contents.json new file mode 100644 index 0000000000..8c210bb280 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSansSerif.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "AaFira.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "AaFira@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "AaFira@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis.png new file mode 100644 index 0000000000..76b6706fde Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis@2x.png new file mode 100644 index 0000000000..a28c649f5d Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis@3x.png new file mode 100644 index 0000000000..e9b70c0700 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/AaCharis@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/Contents.json new file mode 100644 index 0000000000..b9bf38976e --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/SettingsSerif.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "AaCharis.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "AaCharis@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "AaCharis@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/Contents.json new file mode 100644 index 0000000000..974ebfa990 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reading-list-add.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "reading-list-add@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "reading-list-add@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add.png new file mode 100644 index 0000000000..c1d899a31f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add@2x.png new file mode 100644 index 0000000000..66ca5a99ec Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add@3x.png new file mode 100644 index 0000000000..998f4a164c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/addToReadingList.imageset/reading-list-add@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/Contents.json new file mode 100644 index 0000000000..f4763c0619 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "brightnessMax.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "brightnessMax@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "brightnessMax@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax.png new file mode 100644 index 0000000000..5cf8fc9846 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax@2x.png new file mode 100644 index 0000000000..4244ba147a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax@3x.png new file mode 100644 index 0000000000..65aef04923 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMax.imageset/brightnessMax@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/Contents.json new file mode 100644 index 0000000000..7d3d89c412 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "brightnessMin.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "brightnessMin@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "brightnessMin@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin.png new file mode 100644 index 0000000000..66c5b4ff73 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin@2x.png new file mode 100644 index 0000000000..f305528294 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin@3x.png new file mode 100644 index 0000000000..9e0aadf5f5 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/brightnessMin.imageset/brightnessMin@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/Contents.json new file mode 100644 index 0000000000..369bcceaf3 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "removeFromList.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "removeFromList@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "removeFromList@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList.png new file mode 100644 index 0000000000..c752f67cd7 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList@2x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList@2x.png new file mode 100644 index 0000000000..9391410930 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList@3x.png b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList@3x.png new file mode 100644 index 0000000000..c233e8f1fa Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/New Tab - Reader/removeFromReadingList.imageset/removeFromList@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/Contents.json new file mode 100644 index 0000000000..7ff94876b9 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "nav-add.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "nav-add@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "nav-add@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add.png new file mode 100644 index 0000000000..f06bd5d50b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add@2x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add@2x.png new file mode 100644 index 0000000000..cc583a213a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add@3x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add@3x.png new file mode 100644 index 0000000000..450497424e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-add.imageset/nav-add@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/Contents.json new file mode 100644 index 0000000000..3bad3d0c6e --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "back.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "back@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "back@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back.png new file mode 100644 index 0000000000..7c59b71627 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back@2x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back@2x.png new file mode 100644 index 0000000000..490cd4472f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back@3x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back@3x.png new file mode 100644 index 0000000000..b6bc96c8ad Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-back.imageset/back@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/Contents.json new file mode 100644 index 0000000000..b92c79b15c --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "forward.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "forward@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "forward@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward.png new file mode 100644 index 0000000000..740d299799 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward@2x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward@2x.png new file mode 100644 index 0000000000..7ff732ad45 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward@3x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward@3x.png new file mode 100644 index 0000000000..d84ee20140 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-forward.imageset/forward@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/Contents.json new file mode 100644 index 0000000000..acf46f4dde --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu.png new file mode 100644 index 0000000000..116d40a453 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu@2x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu@2x.png new file mode 100644 index 0000000000..a25a4468bf Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu@3x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu@3x.png new file mode 100644 index 0000000000..20e730495e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-menu.imageset/menu@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/Contents.json new file mode 100644 index 0000000000..0a91290ed2 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "refresh.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "refresh@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "refresh@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh.png new file mode 100644 index 0000000000..eb35ce7c36 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh@2x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh@2x.png new file mode 100644 index 0000000000..eff3d95d24 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh@3x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh@3x.png new file mode 100644 index 0000000000..f7b06550db Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-refresh.imageset/refresh@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/Contents.json new file mode 100644 index 0000000000..72c2f3ca8c --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "share.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "share@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "share@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share.png new file mode 100644 index 0000000000..f6906f3268 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share@2x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share@2x.png new file mode 100644 index 0000000000..36c42af0cd Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share@3x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share@3x.png new file mode 100644 index 0000000000..48dd93260c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-share.imageset/share@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/Contents.json new file mode 100644 index 0000000000..ca835ece3d --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "stop.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "stop@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "stop@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop.png new file mode 100644 index 0000000000..de43491c35 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop@2x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop@2x.png new file mode 100644 index 0000000000..21c8128bd0 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop@3x.png b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop@3x.png new file mode 100644 index 0000000000..3dfeb19a23 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/TabToolbar/nav-stop.imageset/stop@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/Contents.json new file mode 100644 index 0000000000..190a7b48f1 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bookmark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bookmark@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "bookmark@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark.png b/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark.png new file mode 100644 index 0000000000..968043a85c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark@2x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark@2x.png new file mode 100644 index 0000000000..455992cae9 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark@3x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark@3x.png new file mode 100644 index 0000000000..b8192846fd Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmark.imageset/bookmark@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/Contents.json new file mode 100644 index 0000000000..aad745b808 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon-folder.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icon-folder@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "icon-folder@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder.png new file mode 100644 index 0000000000..1fe7ac72e2 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder@2x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder@2x.png new file mode 100644 index 0000000000..f75db8002a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder@3x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder@3x.png new file mode 100644 index 0000000000..77939b1f9b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarkFolder.imageset/icon-folder@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/Contents.json new file mode 100644 index 0000000000..cced077bda --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bookmarkHighlighted.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bookmarkHighlighted@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "bookmarkHighlighted@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted.png new file mode 100644 index 0000000000..dea20c6d27 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted@2x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted@2x.png new file mode 100644 index 0000000000..fd6dd4e1e5 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted@3x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted@3x.png new file mode 100644 index 0000000000..e2ac2acb52 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarkHighlighted.imageset/bookmarkHighlighted@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/Contents.json new file mode 100644 index 0000000000..24892bd7c6 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bookmarkPressed.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bookmarkPressed@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "bookmarkPressed@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed.png new file mode 100644 index 0000000000..efbc0cccb2 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed@2x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed@2x.png new file mode 100644 index 0000000000..ff7202a0e0 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed@3x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed@3x.png new file mode 100644 index 0000000000..e80eda99f7 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarked.imageset/bookmarkPressed@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/Contents.json new file mode 100644 index 0000000000..968704a015 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "bookmarked_passive.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "bookmarked_passive@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "bookmarked_passive@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive.png new file mode 100644 index 0000000000..a937a5233a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive@2x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive@2x.png new file mode 100644 index 0000000000..358737078c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive@3x.png b/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive@3x.png new file mode 100644 index 0000000000..7a27b727ef Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/bookmarked_passive.imageset/bookmarked_passive@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/Contents.json new file mode 100644 index 0000000000..d421e25e59 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "context_pocket.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "context_pocket@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "context_pocket@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket.png b/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket.png new file mode 100644 index 0000000000..d2ee7afbd6 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket@2x.png b/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket@2x.png new file mode 100644 index 0000000000..f5c8eec3ef Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket@3x.png b/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket@3x.png new file mode 100644 index 0000000000..cefa86453a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/context_pocket.imageset/context_pocket@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/Contents.json new file mode 100644 index 0000000000..46fab86fe2 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "newtab-icon.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "newtab-icon@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "newtab-icon@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon.png b/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon.png new file mode 100644 index 0000000000..e3ba4f3ff4 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon@2x.png b/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon@2x.png new file mode 100644 index 0000000000..32bffde9da Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon@3x.png b/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon@3x.png new file mode 100644 index 0000000000..2f7a93285f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/defaultFavicon.imageset/newtab-icon@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/Contents.json new file mode 100644 index 0000000000..182ea4dc07 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "deviceTypeDesktop.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "deviceTypeDesktop@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "deviceTypeDesktop@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop.png b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop.png new file mode 100644 index 0000000000..0f09177a54 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@2x.png b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@2x.png new file mode 100644 index 0000000000..2fa6c821ef Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@3x.png b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@3x.png new file mode 100644 index 0000000000..feaa8547b4 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/Contents.json new file mode 100644 index 0000000000..68bc633d8b --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "deviceTypeMobile.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "deviceTypeMobile@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "deviceTypeMobile@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile.png b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile.png new file mode 100644 index 0000000000..0228490a3d Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@2x.png b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@2x.png new file mode 100644 index 0000000000..37d63b2109 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@3x.png b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@3x.png new file mode 100644 index 0000000000..e910b3a4f1 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/Contents.json new file mode 100644 index 0000000000..2ae9938182 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "back-panel-home.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "back-panel-home@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "back-panel-home@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home.png b/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home.png new file mode 100644 index 0000000000..a253d0ae9d Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home@2x.png b/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home@2x.png new file mode 100644 index 0000000000..ce4766af7f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home@3x.png b/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home@3x.png new file mode 100644 index 0000000000..22459edbca Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/faviconFox.imageset/back-panel-home@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/Contents.json new file mode 100644 index 0000000000..70eee9725c --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "fxLogo.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "fxLogo@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "fxLogo@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo.png b/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo.png new file mode 100644 index 0000000000..e288c69fb2 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo@2x.png b/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo@2x.png new file mode 100644 index 0000000000..bbf4cac125 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo@3x.png b/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo@3x.png new file mode 100644 index 0000000000..66ea6798a6 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/fxLogo.imageset/fxLogo@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/Contents.json new file mode 100644 index 0000000000..6d765487cb --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "fxa_get_started.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "fxa_get_started@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/fxa_get_started.png b/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/fxa_get_started.png new file mode 100644 index 0000000000..2af9c957a5 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/fxa_get_started.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/fxa_get_started@2x.png b/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/fxa_get_started@2x.png new file mode 100644 index 0000000000..bbe82d9d72 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/fxa_get_started.imageset/fxa_get_started@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/Contents.json new file mode 100644 index 0000000000..5c966d08ce --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "goback.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "goback@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "goback@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback.png b/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback.png new file mode 100644 index 0000000000..ae4f92b6a0 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback@2x.png b/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback@2x.png new file mode 100644 index 0000000000..be1cd00498 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback@3x.png b/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback@3x.png new file mode 100644 index 0000000000..4d9ec58409 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/goBack.imageset/goback@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/key.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/key.imageset/Contents.json new file mode 100644 index 0000000000..562ad20c79 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/key.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "key.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "key@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "key@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key.png b/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key.png new file mode 100644 index 0000000000..34ad21b09b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key@2x.png b/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key@2x.png new file mode 100644 index 0000000000..d1d1c3eb81 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key@3x.png b/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key@3x.png new file mode 100644 index 0000000000..45cc19f1e8 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/key.imageset/key@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/largePrivateMask.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/largePrivateMask.imageset/Contents.json new file mode 100644 index 0000000000..94f6266bb2 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/largePrivateMask.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "largePrivateMask.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/largePrivateMask.imageset/largePrivateMask.pdf b/mobile/ios/Client/Assets/Images.xcassets/largePrivateMask.imageset/largePrivateMask.pdf new file mode 100644 index 0000000000..abfb68f1ed --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/largePrivateMask.imageset/largePrivateMask.pdf @@ -0,0 +1,237 @@ +%PDF-1.5 % +10 0 obj <>/OCGs[14 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 13 0 obj <>stream + + + + + 2015-09-15T14:01:13Z + 2017-11-06T14:39:46-08:00 + 2017-11-06T14:39:46-08:00 + + + + 256 + 128 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAgAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4qlPmTzX5f8t2X1zWb xLWNqiNDVpJCOyItWb6Bt3xV455j/wCckbx2eLy9piRR1ot1eku5HiIkIVT82OKsD1P83PzF1An1 dbmhU1ottxt6A+BiCN+OKsfuvMOv3ZJu9Tu7gt1Ms8j13r+0x74qgXd3Yu7FmPViak/ScVW4qvjl liblE7IxFCVJBp9GKpnZ+bfNNmQbTWL2Cm4EdxKo+4NTtirItN/On8x7AgDVTdRj/ddzHHLX5sVD /wDDYqzTRv8AnJW9UqmtaPHKP2prNzGR/wA85Odf+DGKvRvL35veQtcKxw6itpcv0tr0eg1fDkSY yfkxxVmYIIBBqD0OKuxV2KuxV2KuxV2KuJABJNAOpxVhnmH83vIWhlo5tRW7uU621kPXavhyBEYP zYYq851n/nJW9Ysmi6PHEP2ZrxzIT/zzj4U/4M4qwvUvzp/Me/JB1U2sZ/3XbRxxU+TBS/8Aw2Ks dvPNvmm8JN3rF7PXciS4lYfcWp3xVLJJZZW5SuzsBQFiSafTiqzFVyO6MHRirDowNCPpGKo618w6 /aEG01O7tyvQxTyJTev7LDvirINM/Nz8xdPI9LW5plFKrc8bioHiZQ7fjirPPLn/ADkjeIyReYdM SWOtGurIlHA8TE5KsfkwxV7H5b81+X/Mll9c0a8S6jWgkQVWSMns6NRl+kb9sVTbFUg88+cLHyn5 en1a5AeQfu7S3rQyzNXiny2JPsDir5L8w+YtX8w6pLqeqztPcynav2UWtQka/sqK7DFUtxV2KuxV 2KuxV2KuxV2KuxV2Ksj8s/mH5v8ALbKNL1GRbdf+POX97AR/xjaoX5rQ4q9d8sf85G6VcBIfMdi1 lKdjd2tZYfmYz+8UfLlir1DRPNXlzXY/U0jUYLzapSNx6i/60Zo6/SMVTXFXYqlWt+avLmhR+pq+ owWe1Qkjj1G/1YxV2+gYq8v8z/8AORulW4eHy5YteyjYXd1WKH5iMfvGHz44q8i8zfmH5v8AMjMN U1GRrdv+POL91AB/xjWgb5tU4qxzFXYq7FXYq7FXYq7FXYq7FXYqmXl7zFq/l7VItT0qdoLmI70+ y61qUkX9pTTcYq+tPI3nCx82eXoNWtgEkP7u7t61MUy05J8twR7EYq8M/wCchPMkl/5uj0ZH/wBF 0mJQyDoZ5lEjn6EKj23xV5ZirsVdirsVdirsVdirsVdirsVdirsVdiraO6MHRirKaqwNCD7HFU8t fPfnW0jEdvrt/HGBRU+sylQB4AsQMVddee/Ot3GY7jXb+SMijJ9ZlCkHxAYA4qkbu7sXdizMasxN ST7nFWsVdirsVdirsVdirsVdirsVdirsVdirsVep/wDOPfmSSw83SaM7/wCi6tEwVD0E8KmRD9KB h77YqwXznqDah5t1m9JqJ72dkrvRPUIUfQtBiqTYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FU58mag2n+bdGvQaCC9gZ6bVT1AGH0rUYqlEkjSS NI+7OSzH3JqcVW4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FV0cjRyLImzIQyn3BqMVW4q7FXYq7FXYq7FWc+T/yc84+ZUS5WEafpz0K3d1VeS+M cYHNvY7A+OKvV9D/AOcdvJ9mqtqtxcapN+0OX1eI/JYzz/4fFWX2f5Zfl/aACLQLJgP9/RCc/fLz xVHN5M8nugjfQtPaMUohtICNum3DFUi1f8m/y71JGDaUlpIRQTWjNCV9wqn0/vXFXlXnT/nH3WdM jkvPLsx1W1Spa0cBbpR/k0+GX6KHwBxV5NJHJHI0cilJEJV0YUII2IIPfFVuKuxV2KuxV2KuxVdH HJJIscal5HIVEUVJJ2AAHfFXrXkz/nH3WdSjjvPMUx0q2ejLaIA10wP81fhi+mp8QMVeqaR+Tf5d 6aihdKS7kAoZrtmmLe5Vj6f3Liqer5M8nohjTQtPWM1qgtIAN+u3DFUDefll+X92CJdAslB/3zEI D98XDFWIa5/zjt5PvFZtKuLjS5v2Ry+sRD5rIef/AA+KvKPOH5OecfLSPctCNQ05Klru1q3FfGSM jmvudwPHFWDYq7FXYq7FXYq7FVS5h9G4lhO5jdkqdj8JpiqnirsVdiraI7uqIpZ2ICqBUknYAAYq +iPyt/JSy0uCHWPMsC3OqtR4bFwGit+45Do8n4L898VeuYq7FXYq7FXYq7FXlf5yflVb65Yza9o8 ATW7ZS9xFGKfWY1FTUDrKo+ye/Twoq+bsVdirsVdirsVdir6R/Jv8qrfQ7GHXtYgD63cqHt4pBX6 tGwqKA9JWH2j26eNVXqmKuxV2KuxV2KuxV5H+aX5KWWqQTax5agW21VavNYoAsVx3PEdEk/Bvnvi r53dHR2R1KupIZSKEEbEEHFWsVdirsVVLaH1riKEbGR1So3PxGmKpn5xtTaebdatSKejfXKD5CVg OvtiqUYq7FXYq9F/Iew0e78/QtqLqJbaF5tPifo9wpAFK9SqlmHuK9sVfUGKuxV2KuxV2KuxV2Ku xV8o/nJ5ch0Lz5exW6ena3qrewIBQKJiQ4Ht6itTFWEYq7FXYq7FWb/k35ch13z5ZRXCepa2Stez oRUMISAgPt6jLXFX1dirsVdirsVdirsVdirsVfL/AOfFho9p5+mbTnUy3MKTahEnRLhiQa06FlCs fc174q86xV2KuxVN/J1qbvzbotqBX1r62Q/IyqD09sVZB+dGn/UvzI1YAUS4Mdwnv6kSlv8Ah+WK sIxV2KuxVfFNLDKk0LtHLGwaORCVZWBqCCNwRir2jyJ/zkHNAkdh5sjaeNQFXVIRWQD/AIujH2v9 Zd/Y4q9q0XzDoeuWwudJvob2HuYmBK+zL9pT7MMVTDFXYq7FXYq1JJHGheRgiKKszGgA9ycVYD5s /OzyXoUckdtcDVr9ahbe0IZOX+XNug+ip9sVfOfm/wA2ap5q1yXVtRKiVwI4okqEjjWvFFrU9yfn iqS4q7FXYq7FU68oebNU8q65Fq2nFTKgMcsT1KSRtTkjUoewPzxV9GeU/wA7PJeuxxx3NwNJv2oG t7shU5f5E2yH6aH2xVn0ckciB42DowqrKagj2IxVvFXYq7FXYql+teYdD0O2Nzq19DZQ9jKwBb2V ftMfZRirxXz3/wA5BzTpJYeU42gjYFW1SYUkI/4pjP2f9Zt/YYq8XlmlmleaZ2klkYtJI5LMzE1J JO5JxVZirsVdirN/yW043v5j6SCKx25kuHPh6cTFf+H44qy//nJTSDHrGkauq/DcQPayMP5oX5rX 3IlP3Yq8ZxV2KuxV2KuxVXs769sZ1uLK4ktbhfszQu0bj5MpBxVm+kfnj+YmnBVa+S/jXol3Gr/e 68JD/wAFirIoP+clPMgSk+k2bv3ZGlQfcWf9eKrbj/nJPzS1fq+l2Mfh6nrSb/Q8eKpHqH57/mNd grHeQ2SnqLeBP1yCQj78VYhq/mbzDrDV1XUrm9FahJpXdB/qoTxX6BiqWYq7FXYq7FXYq7FXYq7F Uz0jzN5h0dq6VqVzZCtSkMroh/1kB4t9IxVl+n/nv+Y1oAsl5DeqOguIE/XGIyfvxVPLf/nJPzSt PrGl2Mnj6frR7/S8mKrp/wDnJTzIUpBpNmj9mdpXH3Bk/XirHdX/ADx/MTUQyrfJYRt1S0jVPudu cg/4LFWEXl9e307XF7cSXVw32ppnaRz82Yk4qoYq7FXYq7FXYq9m/wCca9IMmsavq7L8NvAlrGx/ mmfm1PcCIffir0D88PL/AOl/IF3LGvK40xlvo/HjHVZfo9NmP0Yq+WcVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir6m/I/y/+iPIFpLIvG41Nmvp PHjJRYvo9NVP04qzyeGKeGSCZQ8UqlJEPRlYUIPzGKvjfzn5cn8t+Zr/AEeUHjbSn0Hb9uFvijf6 UIr74qkuKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux VOvJnlyfzJ5msNHiB43Mo9d1/YhX4pH+hAae+KvsiCGKCGOCFQkUShI0HRVUUAHyGKr8VeR/85A+ SG1LSIvMllHyu9MXheKo3a1Jry/55Ma/Ik9sVfO2KuxV2KuxV2KuxV2KuxV2KuxV2Ks18lflJ5s8 1cLiKH6jpjb/AF+5BVWH/FSfak+Y+H3xV7T5b/IfyPpSK99E+r3YpWS5JWKvfjChC09mLYqzmz0H Q7KP07PTra2jG3CKGNBt7KBirrzQdDvY/TvNOtrmM7cJYY3G/swOKsF8yfkL5I1VWewR9HujuHty Wir/AJULmlPZSuKvFPOv5U+a/Khee5h+t6YDtqFvVowD09RftR/Tt4E4qw3FXYq7FXYq7FXYq7FX Yq7FXYq7FX0T/wA4/eSG03SJfMl7Hxu9TXhZqw3W1Bry/wCerCvyAPfFXrmKuxVqSOOSNo5FDxuC rowqCDsQQe2Kvlj82vy4n8paybi0Rm0K9YtZydRG3UwufEfs16j5HFWBYq7FXYq7FXYq7FXYq7FU bpGjaprF/Fp+mWz3d5KfgijFTTuSegUdydhir6A/L78iNK0gRah5jCajqYoyWvW2iPuD/eN8/h9u +KvWAAoAAoBsAOgGKuxV2KuxV2KtOiOjI6hkYEMpFQQdiCDirx/8w/yFsdQEmpeVQlnfbtJpxPGC Q9f3f++m9vs/6uKvA9Q06/028lsr+B7a7hbjLDIpVlPyOKofFXYq7FXYq7FXYq7FXYqz38pfy4n8 26yLi7Rl0KyYNeSdBI3UQofE/tU6D5jFX1PHHHHGscahI0AVEUUAA2AAHbFW8VdirsVQesaPpusa bPpupQLcWdwvGWJvwIPUEHcEdMVfMP5j/lRrPlG4e5hVrzQnb9zeqKmOp2SYD7J/yuh/DFWCYq7F XYq7FXYq7FWceQfyl8xebXS54mw0evx38qn4xXcQpsXPv098VfR/lHyT5f8AKlh9U0m34M1PXuno 00pHd3/UBsPDFU+xV2KuxV2KuxV2KuxV2KsZ87fl75d832npajFwu41Itr+Kgmj70r+0tf2T+B3x V82+ePyz8yeUJybyL6xprGkOowgmI1OwfvG3sfoJxViWKuxV2KuxV2KuxVnf5cflRrPm64S5mVrP Qkb99esKGSh3SEH7R/yug/DFX09o+j6bo+mwabpsC29nbrxiiX8ST1JJ3JPXFUZirsVdirsVdiq2 WKOWNopUWSNwVdGAKkHYgg9Rirynzj/zj7oGps91oEv6Ju23NsQXtWPsPtR/RUf5OKvJdc/KD8wd IdvU0qS8hXpPZf6QpHjxT94P9koxViV1ZXto/p3VvJbv04SoyGvyYDFVkMM00gjhjaWRvsogLMfk BirLvL/5SefdbdfR0yS0gbrc3tbdAPGjDmw/1VOKvY/Jn5CeW9HaO71p/wBMX6/EI3HG1Q+0fV/9 nt/k4q9QVVRQqgKqiiqNgAOwxVvFXYq7FXYq7FXYq7FXYq7FXYqsngguIXhnjWWGQFZInAZWU9Qy nYjFXk3nH/nHvRNRZ7ry7P8Aou6apNrJV7Zj7U+OP6KjwGKvItd/Kvz5ort9Z0maaFf+Pi1H1iMj xrHyKj/WAxVissUsTmOVGjcdVYEEfQcVVLWyvbt/TtbeS4fpwiRnNfkoOKst0P8AKD8wdXdfT0qS zhbrPe/6OoHjxf8AeH/YqcVeteTv+cfdA0xkutfl/S12u4tgClqp9x9qT6aD/JxV6tFFHFGsUSLH GgCoigBQBsAAOgxVdirsVdir/9k= + + + + Mac OS X 10.10.5 Quartz PDFContext + 1 + False + False + + 1.388889 + 0.791667 + Inches + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + Black + PROCESS + 100.000000 + RGB + 0 + 0 + 0 + + + + + + + application/pdf + proof:pdf + uuid:b9883ec5-5836-314e-b8d2-97d21cff564b + uuid:88a3fba3-8faa-d24d-9c47-69a3287e942f + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 2 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/Thumb 20 0 R/TrimBox[0.0 0.0 100.0 57.0]/Type/Page>> endobj 16 0 obj <>stream +HTSKn1 hQ(i[*,rAU +$?f$''z/W<\ }~ +NR +e MsF/t;P[z#GWYZt(,c>MtB)%q@,Dًwr-R,m7v: %"ЙqC_9:nT)M{K +;V!N FF5lGiD7z x FvjHw\ ]|ӹXi؟}p{9Qavl(e AQd>stream +8;RZ]$e#Rn]+2bfg=fs@(^:b,?t.'XK=KO:?O+[Q";h+MFW''~> endstream endobj 21 0 obj [/Indexed/DeviceRGB 255 22 0 R] endobj 22 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 14 0 obj <> endobj 23 0 obj [/View/Design] endobj 24 0 obj <>>> endobj 19 0 obj <> endobj 18 0 obj [/ICCBased 25 0 R] endobj 25 0 obj <>stream +HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  + 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 +V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= +x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- +ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 +N')].uJr + wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 +n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! +zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 17 0 obj <> endobj 26 0 obj <> endobj 27 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 22.0.0 %%For: (Bryan Bell) () %%Title: (largePrivateMask.pdf) %%CreationDate: 11/6/17 2:39 PM %%Canvassize: 16383 %%BoundingBox: 0 3 100 54 %%HiResBoundingBox: 0.12500000000091 3.93747167911351 99.8749999999982 53.8125319459614 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 244 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 (Black) %%+ 0 0 0 ([Registration]) %AI3_Cropmarks: 0 0 100 57 %AI3_TemplateBox: 49.5 28.5 49.5 28.5 %AI3_TileBox: -328 -259.5 406 316.5 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 0 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: -29.25 96.75 8 1908 1031 26 0 0 5 44 0 0 0 1 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -29.25 96.75 8 1908 1031 26 0 0 5 44 0 0 0 1 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 7 %%PageOrigin:-670 -692 %AI7_GridSettings: 1 1 1 1 0 0 0.639215707778931 0.639215707778931 0.639215707778931 0.819607853889465 0.819607853889465 0.819607853889465 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 28 0 obj <>stream +%%BoundingBox: 0 3 100 54 %%HiResBoundingBox: 0.12500000000091 3.93747167911351 99.8749999999982 53.8125319459614 %AI7_Thumbnail: 128 64 8 %%BeginData: 14612 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD0EFFA87DA87D7DFD04522752525227FD0452FD047DA8A8FD35FF %A8A87D7D527D52522752525227FD04527D527D7DA8A8FD18FFA87D525227 %2727522752275227522752275227522752275227272752527D7DA8FD2CFF %A87D52522752275227522752275227522752275227522752272727522752 %7DA8FD12FF7D525227522752525227525252275252522752525227525252 %275252522752275227527DA8A8FD25FFA87D525227522752275227525252 %275252522752525227525252275252522752275227527DFD0EFF7D522752 %275227522752275227522752275227522752275227522752275227522752 %27522752275252A8A8FD1FFF7D7D27272752275227522752275227522752 %27522752275227522752275227522752275227522727277DFD0BFF525227 %522752525227525252275252522752525227525252275252522752525227 %52525227525252275227527DFD1BFFA87D52522752525227525252275252 %522752525227525252275252522752525227525252275252522752525227 %7DFD09FF5227275227522752275227522752275227522752275227522752 %2752275227522752275227522752275227522727277D7DFD15FFA8A85252 %275227522752275227522752275227522752275227522752275227522752 %27522752275227522752275227522752FD07FFFD04522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %5252275252522752527DA8FD11FF7D522752275227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %27525252277DFD05FF7D2727522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %52275252A8A8FD09FFA8FF7D522727275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227A8FD04FF5227525252275252522752525227525252275252 %522752525227525252275252522752525227525252275252522752525227 %52525227522752527D7DFD05A87D7D525227525252275252522752525227 %525252275252522752525227525252275252522752525227525252275252 %522752525227525252275252FFFFFFA82752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522727275227272752275227522752 %275227522752275227522752275227522752275227522752275227522752 %27522752275227522752275227522752275227527DFFFFFD045227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %5252275252522752525227525252275252522752525227525252277DFFA8 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227FFA827525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %2752525227525252275252522752A87D2727522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %52275227522752275227522752275227522752275227A87D275227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %7D5252275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752522752275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %27525252275252522752525227FD04522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752522752525227 %525252275252522752525227525252275252522752525227525252275252 %522752525227525252275252522752525227525252275252522752525227 %525252275252522752525227525252275252522752525227525252275252 %522752525227525252275252522752525227525252275252522752525227 %525227522752275227522752275227522752275227522752275227522752 %27522752FD0B275227522752275227522752275227522752275227522752 %2752275227522752275227522752275227522752FD092752275227522752 %275227522752275227522752275227522752275227522752275252275252 %522752525227525252275252522752525227525252275252522752527D52 %A87DA8A8A87D7D5252275227525252275252522752525227525252275252 %522752525227525252275252522752525227522752527D7DA87DA87DA87D %7D5252275227522752525227525252275252522752525227525252275252 %522752522752275227522752275227522752275227522752275227522752 %2752527D7DFD0BFFA8A87D52275227522752275227522752275227522752 %275227522752275227522752275227522727277DA8FD0BFFA8A87D522727 %27522752275227522752275227522752275227522752275227FD04522752 %5252275252522752525227525252275252522752277DA8FD11FFA87D2752 %525227525252275252522752525227525252275252522752525227525252 %27527DFD12FFA87D52275252522752525227525252275252522752525227 %5252522727522752275227522752275227522752275227522752272752A8 %FD15FFA85227275227522752275227522752275227522752275227522752 %275227522752A8FD15FFA852275227522752275227522752275227522752 %2752275227FD045227525252275252522752525227525252275227527DFD %19FF52522752525227525252275252522752525227525252275252522752 %277DFD19FFA8525227525252275252522752525227525252275252522727 %522752275227522752275227522752275227522752A8FD1BFF5227275227 %522752275227522752275227522752275227522752277DFD1CFF52272752 %275227522752275227522752275227522752522752525227525252275252 %522752525227522752FD1EFF525227525252275252522752525227525252 %2752525227522752FD1EFF52522752525227525252275252522752525227 %FD0452275227522752275227522752275227522752A8FD1EFFA827522752 %2752275227522752275227522752275227522752A8FD1FFF522727522752 %27522752275227522752275227527D275252522752525227525252275252 %522752A8FD20FF7D27525252275252522752525227525252275252522752 %7DFD20FFA8275252522752525227525252275252522752527D2727522752 %27522752275227522752272752FD21FFA852275227522752275227522752 %275227522752275227FD22FF7D2752275227522752275227522752275227 %7DA82752275252522752525227525252275227A8FD22FF52522752525227 %52525227525252275252522752277DFD22FFA85227525252275252522752 %5252275252527D7D272752275227522752275227522752275252FD22FF7D %27522752275227522752275227522752275227277DFD21FFA85227522752 %27522752275227522752275227A8A8275227525252275252522752525227 %FD0452FD21FF7D52275252522752525227525252275252522752277DFD20 %FFA87D275227525252275252522752525227525252A8A852275227522752 %27522752275227522752272727A8FD1EFF7D522752275227522752275227 %522752275227522752277DFD1EFF7D522752275227522752275227522752 %2752275227FFFFFD045227525252275252522752525227525252277DA8FD %1AFFA8525227525252275252522752525227525252275252522752277DA8 %FD1AFFA852522752275252522752525227525252275252522752FFFF5227 %52275227522752275227522752275227522752275252A8A8FD15FF7D5227 %52275227522752275227522752275227522752275227522752272752A8A8 %FD15FF7D7D2727275227522752275227522752275227522752272752FFFF %7D525252275252522752525227525252275252522752525227527DA8FD0E %FFA8A87D7D52522752525227525252275252522752525227525252275252 %52275252522752275252A8A8FD0FFFA87D52522752275252522752525227 %525252275252522752525227A8FFFFA82752275227522752275227522752 %2752275227522752275227522752527D7DFD05A87DA87D7D525227272752 %275227522752275227522752275227522752275227522752275227522752 %2752275227522752527D7DA87DA8A8A87DA87D5227522752275227522752 %2752275227522752275227522752275227277DFFFFA85227525252275252 %522752525227525252275252522752525227522752275227522752275227 %522752275252522752525227525252275252522752525227525252275252 %522752525227525252275252522752275227522752275227522752275227 %5252522752525227525252275252522752525227525252275252FD04FF52 %272752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752FD04FF7D2752525227525252275252522752525227525252275252 %522752525227525252275252522752525227525252275252522752525227 %525252275252522752525227525252275252522752525227525252275252 %522752525227525252275252522752525227525252275252522752525227 %5252522752525227527DFD04FFA852275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %52275227522752275227522752275227A8FD05FF52522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %52522752525227525252275252522752525227522752FD06FF7D27522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %27522752275227522752275227522752275227522752275227277DFD06FF %A85227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275252522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %27FD08FF5227275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %2752277DFD08FFA827522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227522752275227522752525227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %5252275252527DFD08FFA852275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522727275227522752272727522752275227522752275227522752 %275227522752275227522752275227522752275227522752275227522752 %275227522752275252FD0AFF7D5227525252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %52522752275252A8A8FFA8FFA8A87D7D5252275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %525227525252275227A8FD0BFF5252275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %52272752A8A8FD0BFF7D5227522752275227522752275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %52FD0CFFA827522752525227525252275252522752525227525252275252 %522752525227525252275252522752525227525252277DA8FD10FFA85252 %275227525252275252522752525227525252275252522752525227525252 %27525252275252522752525227525252A8FD0DFF7D275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %522752272752A8FD14FF7D52275227522752275227522752275227522752 %275227522752275227522752275227522752275227522752272752FD0FFF %522752525227525252275252522752525227525252275252522752525227 %525252275252522752525227527DFD18FF7D275252522752525227525252 %275252522752525227525252275252522752525227525252275252522752 %52FD10FF7D27275227522752275227522752275227522752275227522752 %27522752275227522752275227522752A8FD1AFFA8275227522752275227 %522752275227522752275227522752275227522752275227522752275227 %5227A8FD11FF7D5227525252275252522752525227525252275252522752 %525227525252275252522752525227A8FD1EFF5252275227525252275252 %522752525227525252275252522752525227525252275252522752277DFD %13FF52272752275227522752275227522752275227522752275227522752 %275227522752272752A8FD20FF7D52275227522752275227522752275227 %52275227522752275227522752275227522752277DFD15FFFD0452275252 %5227525252275252522752525227525252275252522752525227527DFD23 %FFA852275252522752525227525252275252522752525227525252275252 %5227525252277DFD17FF5227275227522752275227522752275227522752 %2752275227522752275227527DFD26FF7D27522752275227522752275227 %5227522752275227522752275227522752277DFD19FF7D52275227525252 %2752525227525252275252522752525227525252277DFD29FFA852522752 %275252522752525227525252275252522752525227525252277DFD1BFF7D %5227522752275227522752275227522752275227522752272727A8FD2CFF %525227522752275227522752275227522752275227522752272727A8FD1D %FFA87D275252522752525227525252275252522752525227527DFD2FFFA8 %7D2752525227525252275252522752525227525252275252FD21FFA85252 %27522752275227522752275227522752277DA8FD32FFA852522752275227 %52275227522752275227522752A8FD24FFA87D5252275227522752525227 %5227527DFD37FFA87D52522752525227525252275227527DA8FD29FFA87D %525227522752275252A8A8FD3BFF7D7D525227522752527D7DA8A8FD14FF %FF %%EndData endstream endobj 29 0 obj <>stream +%AI12_CompressedDatax}z}ށwf%!@ tBP3?γ_ӇiswvŒlY%YXNMv:9CNӣz}:IV뉰RȀn؞n|_í>=]z> q0ToK@;PG1_\N8#bO0#Q5mO"D4#A$ ZPS~`7TxT`$`J 8`ws??)P<Xȧ-{Eo"^i_v:%1'|T}m.vEp`pTOD_:;z1]M }s[s`5mu >,0 Ę@).7Rx)82z9'r,F=i#ZOʁ"zy,Tئ,r {Nh)GfT}c1ObgZ6XA%[yÊRou{==/ݟ[EzĮ7SKM!42+\'zԎ4/ĥ#s#K/cp9T_S򿗑z/59P'ols/[@#³tcr !>(xGN2^Rh)x'PGOn]LL6;kt<,'3f6$iR*mtq=>[8le@z]0Jd:LsLM G& h~J "p(0t@4~g?4Г`A +hAQ.fB8@dfHH݉^b^v :odXB!WBMBѰQdBT4 P  '8x +h0O @ `vWM|Ir_M&Bo;p7}V zV) +郪Jem67׊;sTza|O-%*vt5vF}Wo?cHP8k-:|l (Vr Aq./6Eÿ%!>}t8ې{r4R@6QB7 +|nHNXrLMJAaS@ yhusWP.v%+zKPp$4vt 훸#\_v4+$Oڬبrt:N/|^bS5|4k0o{p60cH +RZFv?]Q`hSP(GF. -mYp$yӣbmGavG2#cN7 $9~vt6pԥ[ ]dy(''U"=BXz:kJky=AYߩRT_p㐇q:qJIusi#_G8> (Nr~8s`$,7Ȃᢆa859[p(@PEJ!3]3@a2p̮83vf #O褛ѩ֜@jL,Z0)Y-;p7hBJoToK_Jz͈ +:n=^7ԃ=hx`Z%rG\G &)9nE^=;Z +zʶG~#<GP0A8Q5$*_C,VoӕD ל#db^^v pL;㪽)s{]4H@nx(jmkP~N`s<#Hoe| + KgP'؄fa@cXiji;_G4y a>Fe*f z8Vj4vC^FnϧE`iN*Ԝ^#ɭ={ ^^h1q8:`NKY ;Q %T m)bԏPb I?BGBL>Wk\:.F *åZ|!dТߌ=&DD=̷;n-0nAb H /w'T*>=OPPCD&m|ŊGnD61U؝syv#1\ B[FfN!rRa܏WvM;v S`ϙ ~LgAkN Y</(gۣgޓvJj&jhIF# pfl3%ThIf'ZqNC. +\vᢓѐTZo[l-㽓։@bTN7DB4_"꯽GK9B`R,z#䜟j9Б %PC7P`qqc-ػ~ro! fS4Z +D1 `+4i;[`9Tv^|2Җ"je:'l-OãLGXѩ>?|* x) Itew;J:,0ʊhM 6k ~u6aDibDh,QгPpýgfB"7jCO뮥s>vmάEsB$C̈Δ[%ŗ5}6QD&Cb&j _XX$Yc|Z aNK$Sq%KY,a`9 i$V4?Ruo^ܧVӎ,6J-FZxO?s`n]ب]o`ބ&2 ʂM;bGhJÓOW b--3 ?Q̆Oy Ӑ Ik, C%`(KkCX5T'~Zv`4agϰlo"%hmi2ZO }9ݍPH{cw#wcj,6Y=kocmVc?7!iGg6n뙅`IMdue&Waa/? ژ_Se2Yj*SnS ãLv4?L´>LccGl龖ΓL14?Z4>k h77žg8v_կy 5~6X0`&oe†%V#>,eʦ3[ +]m-MVY2`Om㱜r踭k k-iMR1>OҶ~,sZ7z\%&1gBP9rxVR6,6yޗm4/5=۽g.^5jb>g:b_&w :_c0:BX9~f 1Z?eq >vEvgh9ʮJt 8zXgvƴ˗/ܻW_?ڌVa\So٩W}g YFkOrX֌x{7d+j ( +څ}Ĉm)%v%uaoh۳?3N?QSSGNיcx|[=!uitCйrN,d2`[9u9!#P>m 4Z֡hv|B}Yn'|9‡ [*NXG^2@=,_?Qc5/hGr{s,{oXހT}l|qzd +x6k=ě~9><[!ymC2|-ƥa;{~t?2 :\m9O +/d1;'^_f?_-Onwfx%O}4̻O~Mzo2[ KN6} +R2μ3KXa6=NczO:sgRr"83Q5uOlz>W=lHeߕFkI,sÞk}bұ孝C>]DU+?,f,ݑB +q봓E<)fk]ōc=//Rn)>ƙO@>O|n4E{xU?/_`D\˶+?|iܰEb'v%Lg*WIDZWgxxMruz*x5[YkX+=}j NoV:m^ym=7SKQG} fЬl8㶱xɷٌG]Y$*%ӱZ!g\7TtN[;_U=)[^ydž{lQ~zobM^ fNj1%>c3c^~>Xt~56!W{}-Îj% =P:}g8JS'kT{ڨ=iFcTG^my8Ki8 ?1NN64tgxVtO,}Ҽڰ [߶Eͻi/+\>[+ܾK?Og?/=dΦ«~~ȽEֽ1&l|nsVs;;Ws=bxq_k ;'3FNih 1gJ&=69p y{㝰RV>'@?`'MqpY<Dž`m{/ 9gG]+0T3tȍ"i;=^g|Z//OEawTICj̲]: +c% n$G<WwÝ}SeѼ։h`.rXPG1i{OYDC$mlў tBUn<#'gY8J7P7S+H2~x'Z@EЂDڟHC/&~0"B{5m7҃+CZLmTg>kuՊ$R`FdKR +)P6Ѵ%!=XASik" {O4RQ!?O2Dj?S[&i`!XY- kVi0b۔Ay慏B]CZ4mOiX`\L" -cO6e):A2Oaiy,Rc57Qs5&ϲH- B +hx.Mn^y 4/ka৑6Q\c}OR:FZ\駀RMEHm!«jCّH?4Z.^2H?x԰ =GC +3m?.e6ޅ&@Ak۰'ɱvm,N7!]/) ki6I"t[[e~>NJZu&%~6Yޗ!_@`$ R٢NCa ~2Dl4U!B +TAxC">kV45glwAJ M#ͽq "QhMjسP*\+zDHӷNm@?Buw(Oċ[|nRS\#/sCHϟn>c:$s2jm#z[zKbn-k z-[<0q1ogr9Y`%L}&@{,3ᕀ#i#юF\Z*<|̦V蝭v+QS4vk"C2wb' + ;)`7}FK머";ẽ/)TgjRc{K45fGH}?0 \ xH'Cz-H c-B +q}XH G)dr}X҂)$Z"HY j$C9uyח%Hp\?#Úo >s 5֋3;R!"зjڻ'Ri,{I#Ibßf3'Mp 4MRMFw1͚'qH>d-S>ș?NKާ:?(vHZ k~Uy$^D$)':3f9\j|~S6>NΠ͠aC>F j?|3mK,G,%`U"f$\P{tPFtי/,\2EB>ɉE;z !{.R@@B3y,RvNKWdbi'yR|SEZlˬJʛwh==*@o! +Z/z%=u< s: e ,YtfQڥ6i+^fCH{J`U74h1E9˺f;f.1CKAt C>Ogܑ?|`I|zly5eeXb|<YAHc5-LG'/ږ_țU䨼-Ȟ%/.SbJsb9|.GKT:K:fjTS4_hA%b̠"@ ϑi`+II1ݓb[(Fo4h/0\E|bn֎}'7(9&oJHY[p~ULjH+KvRYE6eE/\@,_P_ +Jˬx#/6Hyn7ibpTJ21ҙ9 ]> 6+@ v~9}L0! -ey:B]V:tYxTEE ^ESd] eGvJybH[L7ʕnRde_<^LǼ6 +?SBp)Pz9}dd |SR1n .ڻKF٬7 +|zA6ʅӘ+ *IӛWO]àN;F/gV4&5IgdϜV׏O'aFm|i.)g>Zv}s@')sqJ6YMG$Plύ6f$Tvy(Y$$Lvs!1Qd m^{ίEgb!Xs%bW5伔{EI +)#߯h ee= Y6MTQr)N\xbFՕ?Ӛ]$"<0ȸ6K<0QM^Z5*s-7Jל\(`j?<> ݂ o"CkUsf.W~7)^N1:/z4(Ib[)Tn{eK?*;_GSѢvcOZ+JZ (Ӟ9#r38( meS־$1DYirq} NNsRDd\|B=R󧤖+43e9t{G[zdƐ\͈憐fV >Vн#fJuAN٣$=WK=2Jl##+5yhSetqZetzd+Y-OGo$#v.R<_9+r a9h#CYih*g:ih[=2:3$LH'9Y[yv>42W2O¼a_D. ߸FM '˥i SN]ܒW%XWwa}Geafת:A!uW^J$NRlt،{Éc.ʇSNppߺFޖ3n*[|8Qo⌸{É|Wkxp[x{]^kqup秾b[o%G!/=&!&R'"lLdKSLonNBȩ1ROx)8\e"V> Q!:eb` +oh2.^ޞMQ2<{eؾ(4-B!GmoZ"(j#8/3땂s2DPliw 8s  Vt% +L*\.{T qqF*aДD-#0n6]I7evڹKFjN;ev_@ #DPt 4"rr^8]^DNjkjY*ȫ^?N{x ʒT|nnk6YXMvC}ȷgq]fEUtR~*tRtR=eI)܄dIIޫpS6h$̽餺f)hJw̦RNtR^al:)PeIRȯ2NbwΦTCe#NEr$jޘM'K'}g-tµMҩW^M'@>>l:E^?^tR*ڿ:N@ T-4V!qtS+#,q *MbPo˩.vv!A20W'%s* +:eNTF&T+41XhSEy4/g. 4[y1+ ;U|^,2LR?㗹:2w4'˩ϗ#JBw7կTKNp&rXeΥZ5eDEBwg̝"'k +R{^Ĺs4SWV +[jP_oR[1%TQk<$u +MuT>w -NPKk"i5s-]UZ5|i$ R`<.k_qkxej jݐtDe7W2k](_^)|"Jy/Cq[*ipGPᎫ*]Z.z .%5{Ga9{G!k?2kBpnf!(`o7N:pK>%T.vA4LP<28143RlZ3n ^<ؽ68b{ٕ`.ZT$&C51i쒘#^+r\ݞ[fHڤ-utZQˎܻ#_\)E=c66JKc<ī)D&(/ywbUmIWk+W>f5Sz.h>ݲrR  p$Oyrws~c0?Mݬrue j9_LjIE]z٬Yx[P\0CCWRl伔3X6` 0N>f-U^eǮJz 8UDN雷dG)}_3E{* X]TXDKǧgٸqum\%'.(WQӕgVwv0FcԪȂ#vs0(VO"M%dv(+JC"zwUkɗUԓ-5gjTbu$sE5glg9Y6Yl/sEYZs52o9toظHb)q|r[O|:m֢|lZQ>{CwVWQ>qſSOZIԯ(K[3`Q]?&.wC0NwC v7Wh[u4ֲQwP u~Utr"qwc]?e]AtC]?dU?qk)3;Swߒ<* + Z)aC]?~+U)Gso8[/c覺~~WfS/@uY]?E=*fuR.w{uxP$]ZWS*g䚺~ +]&VOB,JcYbJuI5uakIx.֬4mü)t$Mu8jKӚ๺$;Ա +)CQ^POC YU?Z2]⬴3$3'߯Yt]۴quTRO߅y]JAnԹ8 WXO2~˱K)9c%Y[]zm]?~nZ+=꧓=,I5S'偿rU?]슺~UTҞXՏw/Mu4-o';7O^Kj]?eʱ{SV yg|7;#ȕuOlDٵWSe^]Oba]YOy7ɧ&.%.~Ax1˺UԎ6t?cW>cH9^2|ַy-664<$GO% +sߊ7f9:5\4Ct061<9v7kTu,L S/x}Wވ[xcuh.x{l;O,ޯ^%v×$_VR"OO,ByäcǒhjHWFuD)x-j=2%Y_fjAɗp|Qkwx#s5a/^9fـgu$ ةOCCۍ>7ԧz0C }ҙ̓h]Z EQ#ݛf@>ejm ^YoC.m[>:ctNjp?@yOԧ糓qG|3'M}S\ggC3 ^8~Ȓ7-aْ~8oU@^)Tvh mJZf1S6's aEk$/.Bmle]: Bsbmxz+#hmLNF}$\Goa*R[׆mpJ fPZli +/ +CJ4гKIj\)bf}"Q|ӑE z]&}@뽦\{<OsʵKͧp/U }+EƮºLx{/j˝©s͘C ?pvT-¿z97Z=a"g3"C+R9dXnLl\$)o*[,H3Xv \?J߯8Y0 ㎿Bqjf rpacb̃Ϛ0dejO2gc1~'\iOl%QғEh Ϙ?O ̧33.sk.+e|˝ WgV0`4y%ɧەcv $!fTcW3?}./9ӾkPDto(-*O`X)cfoӺe%խ#{mьCjߏdfɶ^~*SC&`u>`}kw#) + s;Jn}U.;2`[vfDvݒB%2QDG)wtf{7=,Km an}v{m:#3GP޾{w-q7͐KZIQ^^4fʧt]s|2-DGW,pf}# 6J}uXp(Í 7=4fecY$ku]-#] n/R.[MF2~$Ֆv +׹"/x.+cVbJ?2h*?f%1s X!VaWy*?Xz3kX$O0pqՖYbvsLj z;>Sϗ&F |8gI 1R_&H>#s6\>ꇹ*ݜU]*U+}}n_JcWͯpw.\iTVAo[QNݭ =O@r,Ŕ? D{8^zfft<<5 xX6UvN{0T[˻7z*xV̡@ "?21РŠagga^ ?yg^l`/=H 6ϻhJoZlO0axAOۆ= 0*!KGEaJyI_L1Ck;@1cc%TQz߉xW+0W #3 Dy|1DD2'oƒOU&&" R:ŠϗcDpvE2FN>aRD"V*N[@,@͋jq2:(wQmoƂR.f5vWɧ-ۉ0s d٨H)`,J px2;a$dmq#SV'YT:NJ-i㤁p b7L,xb1QFWH!,{ IљZay=8 R^hpK jw@`h"uE}X8BqGmW +.\0-s>RQJ(ͿEȼ Oy(ˈ $ڎj |pl]T@*? X^&"O?SisF.:1+t٬;"s%xiDK ॔%2n^& +8K^~Q|b~S%K/<:xɚ<̅P]_@oQ${3(iMrU xkU/J߄ _x"M*yV+?u`DtvbǏ㧀gی2e(7^ +|'f4+t W>}HY0K$T&&!;jyQ'F| Լї/-~$ГTMxM27OzW8%f9{TwLe ]]\ݘfN |̧I$D_ :y_ȿ%HyW'.fW) fs#>O)Y%VuT Z.ON_n|LG}LM52R$w2Mfk-!:+Jggªh?38_|Yu*s-̃9ON)y')ڼ?pǏOD pOV8oX%\E[*U /Z652gN5NNLP^3C{|xNzx>j\rJ?ՙ6B5M8WaXŰuef\<:Gh"Gz|"lp t +QZ4GY+X$Jgf~8n`/u^%=Ns̾p_| >3g_ҿP;zul#61L$zNt8QtJйOu{4wBOua16c&(i0v?BfS  +ZB$}oO84gHƳr58ęgiT<5L"i4q/mflvtcEh&U1;f_OPz%DL}C(q#/zm P;pP'ss+Y7!#fNHα DA[W]5*xV)ޥ+@X{i=EʁwY:ٕfE{hIxD}w9ǐ9$< .3$z| +i!8#`3$Hy$FBDx9"xиR9} iNGfv-eERɠ&B 8Ǯ$:For^ Dm[iiF9๼Nkzob*Rtf >l]kUa zt&ak) B#G@[tጔ-­rJ=IvL}Sm?O~X;Xb#9f>X'RKsO!"vMJܛjg׆qFd:~҄QTJn~7J_ͯR]7Jn%tqJ1m'K 46r[=%u¿᨞E`| §Ά Ht7Eqɿ1[)JY}LO`~@h ^ts)_Oa;Qs,\P/Q?'Ѡ C|( D#PG \{Ȋ(80EKˣ(0ȡI(hGC1y:y }zjޫ;_?r;v񬝜|\ҤtFZ~]kS) 1=jS3$Y߾,f\4kf͢TRk]gA8 ޹nU-Zg&͂'Yyp p"h%> Wrx>N+b85Zʞ ͓%"UEqnRPRS\ѯ't*P'ě75#Wdo*;ECSh3xFY@-LWT[c^ ӧ -RJܡ;Y~Ġ}Wk Ņhʘ3lG CxA9ѠGQlk}FoЂzDYf UhL$p +VCL[4 +$bC΁`Ho&DD!Cv `Jу&`1`Rm03׆]YF׽!*`GPš;>PѹʘdXAS:j 41ؔc/&B<Έ 3g`E;;Y t0 TgqQ6 [fl 3K`; +H5)vuCۈu{I`1nG DOEvT|⦃t.I|=hq|IuPbI0!z]1GD~Ibcwݎ^tP~D!7˺~s;prx\N)wǧsy|]~'p endstream endobj 15 0 obj [14 0 R] endobj 30 0 obj <> endobj xref 0 31 0000000000 65535 f +0000000000 00000 f +0000012937 00000 n +0000012865 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000016 00000 n +0000000000 00000 f +0000000000 00000 f +0000000149 00000 n +0000014522 00000 n +0000058196 00000 n +0000013314 00000 n +0000017505 00000 n +0000014822 00000 n +0000014709 00000 n +0000013771 00000 n +0000013961 00000 n +0000014009 00000 n +0000014593 00000 n +0000014624 00000 n +0000014857 00000 n +0000017579 00000 n +0000017759 00000 n +0000019061 00000 n +0000033903 00000 n +0000058221 00000 n +trailer <<94763EDBEEB34E7F913256011A8A4B43>]>> startxref 58352 %%EOF \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/Contents.json new file mode 100644 index 0000000000..2757a67080 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "lock-small.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "lock-small@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "lock-small@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small.png b/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small.png new file mode 100644 index 0000000000..38c781c84c Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small@2x.png b/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small@2x.png new file mode 100644 index 0000000000..a604594c5f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small@3x.png b/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small@3x.png new file mode 100644 index 0000000000..763c383528 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/lock_verified.imageset/lock-small@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/Contents.json new file mode 100644 index 0000000000..b1df1ed205 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "loginSelected.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "loginSelected@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "loginSelected@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected.png b/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected.png new file mode 100644 index 0000000000..b8ac7da808 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected@2x.png b/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected@2x.png new file mode 100644 index 0000000000..f990c0ff34 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected@3x.png b/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected@3x.png new file mode 100644 index 0000000000..a37f7e95b2 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/loginSelected.imageset/loginSelected@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/Contents.json new file mode 100644 index 0000000000..196abc64c8 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "loginUnselected.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "loginUnselected@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "loginUnselected@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected.png b/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected.png new file mode 100644 index 0000000000..07ae5fc48a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected@2x.png b/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected@2x.png new file mode 100644 index 0000000000..20c677eafb Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected@3x.png b/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected@3x.png new file mode 100644 index 0000000000..f1db95d6de Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/loginUnselected.imageset/loginUnselected@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/Contents.json new file mode 100644 index 0000000000..57af6143c9 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "quick-search.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "quick-search@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "quick-search@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search.png b/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search.png new file mode 100644 index 0000000000..3f93adb554 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search@2x.png b/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search@2x.png new file mode 100644 index 0000000000..f65607d044 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search@3x.png b/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search@3x.png new file mode 100644 index 0000000000..0bcf025b15 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quickSearch.imageset/quick-search@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/Contents.json new file mode 100644 index 0000000000..fe5f062330 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "go-to-copied.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "go-to-copied2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "go-to-copied@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied.png new file mode 100644 index 0000000000..c574fb22fc Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied2x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied2x.png new file mode 100644 index 0000000000..aec91e18d3 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied@3x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied@3x.png new file mode 100644 index 0000000000..384e965951 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_go_to_copied.imageset/go-to-copied@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/Contents.json new file mode 100644 index 0000000000..260654cbbb --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "last-bookmark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "last-bookmark@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "last-bookmark@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark.png new file mode 100644 index 0000000000..ecffed2bfd Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark@2x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark@2x.png new file mode 100644 index 0000000000..fb4fc6a511 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark@3x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark@3x.png new file mode 100644 index 0000000000..a1ea2d78e5 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_bookmark.imageset/last-bookmark@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/Contents.json new file mode 100644 index 0000000000..7b153e8204 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "open-tab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "open-tab2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "open-tab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab.png new file mode 100644 index 0000000000..67c6253d2d Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab2x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab2x.png new file mode 100644 index 0000000000..aab81ec4c4 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab@3x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab@3x.png new file mode 100644 index 0000000000..b59b3621ae Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_last_tab.imageset/open-tab@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/Contents.json new file mode 100644 index 0000000000..da3489bf6a --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "new-private-tab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "new-private-tab@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "new-private-tab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab.png new file mode 100644 index 0000000000..642ead018f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab@2x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab@2x.png new file mode 100644 index 0000000000..138e7c232b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab@3x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab@3x.png new file mode 100644 index 0000000000..64f917fb17 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_private_tab.imageset/new-private-tab@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/Contents.json new file mode 100644 index 0000000000..a5a5041271 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "new-tab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "new-tab@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "new-tab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab.png new file mode 100644 index 0000000000..7f5ef797b0 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab@2x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab@2x.png new file mode 100644 index 0000000000..c4996d9b2e Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab@3x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab@3x.png new file mode 100644 index 0000000000..6d40497957 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_new_tab.imageset/new-tab@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/Contents.json new file mode 100644 index 0000000000..3fa08d35cf --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reading-list.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "reading-list2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "reading-list@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list.png new file mode 100644 index 0000000000..c9a538a83b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list2x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list2x.png new file mode 100644 index 0000000000..c59bcaede3 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list@3x.png b/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list@3x.png new file mode 100644 index 0000000000..fa02e16368 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/quick_action_reading_list.imageset/reading-list@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/Contents.json new file mode 100644 index 0000000000..0b33e17a84 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "readermode.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "readermode@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "readermode@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode.png b/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode.png new file mode 100644 index 0000000000..53a0cde354 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode@2x.png b/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode@2x.png new file mode 100644 index 0000000000..12013f58a7 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode@3x.png b/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode@3x.png new file mode 100644 index 0000000000..5b6790ebd8 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/reader.imageset/readermode@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/Contents.json new file mode 100644 index 0000000000..4e7ad4d5ad --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "closedRecently.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "closedRecently@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "closedRecently@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently.png b/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently.png new file mode 100644 index 0000000000..ef0a8b07d3 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently@2x.png b/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently@2x.png new file mode 100644 index 0000000000..3f187384c3 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently@3x.png b/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently@3x.png new file mode 100644 index 0000000000..5a425f0742 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/recently_closed.imageset/closedRecently@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/search.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/search.imageset/Contents.json new file mode 100644 index 0000000000..b5c88ada0d --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/search.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "search-suggestion-magnifying-glass.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "search-suggestion-magnifying-glass@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "search-suggestion-magnifying-glass@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass.png b/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass.png new file mode 100644 index 0000000000..d8b4b1a402 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass@2x.png b/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass@2x.png new file mode 100644 index 0000000000..d9b07b3099 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass@3x.png b/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass@3x.png new file mode 100644 index 0000000000..6e68778951 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/search.imageset/search-suggestion-magnifying-glass@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Contents.json new file mode 100644 index 0000000000..80578099fa --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Settings-cog.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Settings-cog@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Settings-cog@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog.png b/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog.png new file mode 100644 index 0000000000..ce922b5e77 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog@2x.png b/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog@2x.png new file mode 100644 index 0000000000..33f3a1faeb Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog@3x.png b/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog@3x.png new file mode 100644 index 0000000000..dcd226d7d0 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/settings.imageset/Settings-cog@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/Contents.json new file mode 100644 index 0000000000..13301f1ef2 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "RDS.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "RDS@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "RDS@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS.png b/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS.png new file mode 100644 index 0000000000..d4c7ce8935 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS@2x.png b/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS@2x.png new file mode 100644 index 0000000000..038a8678b8 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS@3x.png b/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS@3x.png new file mode 100644 index 0000000000..e25b19da0b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/shareRequestDesktopSite.imageset/RDS@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/Contents.json new file mode 100644 index 0000000000..0adc6482ae --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "RMS.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "RMS@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "RMS@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS.png b/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS.png new file mode 100644 index 0000000000..6b80f26814 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS@2x.png b/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS@2x.png new file mode 100644 index 0000000000..2462e5f291 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS@3x.png b/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS@3x.png new file mode 100644 index 0000000000..188adce0a6 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/shareRequestMobileSite.imageset/RMS@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/Contents.json new file mode 100644 index 0000000000..da3489bf6a --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "new-private-tab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "new-private-tab@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "new-private-tab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab.png b/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab.png new file mode 100644 index 0000000000..642ead018f Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab@2x.png b/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab@2x.png new file mode 100644 index 0000000000..138e7c232b Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab@3x.png b/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab@3x.png new file mode 100644 index 0000000000..64f917fb17 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/smallPrivateMask.imageset/new-private-tab@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/Contents.json new file mode 100644 index 0000000000..5b0a67688c --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "splash.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "splash@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "splash@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash.png b/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash.png new file mode 100644 index 0000000000..9db6904ce1 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash@2x.png b/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash@2x.png new file mode 100644 index 0000000000..c12fa29e41 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash@3x.png b/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash@3x.png new file mode 100644 index 0000000000..5459357835 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/splash.imageset/splash@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Contents.json new file mode 100644 index 0000000000..977698d614 --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Synced Panel.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Synced Panel@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Synced Panel@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel.png b/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel.png new file mode 100644 index 0000000000..c889e158cb Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel@2x.png b/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel@2x.png new file mode 100644 index 0000000000..7b47639594 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel@3x.png b/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel@3x.png new file mode 100644 index 0000000000..25e4001a66 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/synced_devices.imageset/Synced Panel@3x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/Contents.json b/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/Contents.json new file mode 100644 index 0000000000..5519b4b26a --- /dev/null +++ b/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "closeTab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "closeTab@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "closeTab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab.png b/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab.png new file mode 100644 index 0000000000..c41ba45c9a Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab@2x.png b/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab@2x.png new file mode 100644 index 0000000000..be2c23aca7 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab@2x.png differ diff --git a/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab@3x.png b/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab@3x.png new file mode 100644 index 0000000000..75eddea608 Binary files /dev/null and b/mobile/ios/Client/Assets/Images.xcassets/topTabs-closeTabs.imageset/closeTab@3x.png differ diff --git a/mobile/ios/Client/Assets/LoginsHelper.js b/mobile/ios/Client/Assets/LoginsHelper.js new file mode 100644 index 0000000000..ece8ae8781 --- /dev/null +++ b/mobile/ios/Client/Assets/LoginsHelper.js @@ -0,0 +1,713 @@ +/* vim: set ts=2 sts=2 sw=2 et tw=80: */ +/* 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/. */ + +(function() { +"use strict"; + +var gEnabled = true; +var gStoreWhenAutocompleteOff = true; +var gAutofillForms = true; +var gDebug = false; + +var KEYCODE_ARROW_DOWN = 40; + +function log(pieces) { + if (!gDebug) + return; + alert(pieces); +} + +var LoginManagerContent = { + _getRandomId: function() { + return Math.round(Math.random() * (Number.MAX_VALUE - Number.MIN_VALUE) + Number.MIN_VALUE).toString() + }, + + _messages: [ "RemoteLogins:loginsFound" ], + + // Map from form login requests to information about that request. + _requests: { }, + + _takeRequest: function(msg) { + var data = msg; + var request = this._requests[data.requestId]; + this._requests[data.requestId] = undefined; + return request; + }, + + _sendRequest: function(requestData, messageData) { + var requestId = this._getRandomId(); + messageData.requestId = requestId; + webkit.messageHandlers.loginsManagerMessageHandler.postMessage(messageData); + + var self = this; + return new Promise(function(resolve, reject) { + requestData.promise = { resolve: resolve, reject: reject }; + self._requests[requestId] = requestData; + }); + }, + + receiveMessage: function (msg) { + var request = this._takeRequest(msg); + switch (msg.name) { + case "RemoteLogins:loginsFound": { + request.promise.resolve({ form: request.form, + loginsFound: msg.logins }); + break; + } + + case "RemoteLogins:loginsAutoCompleted": { + request.promise.resolve(msg.logins); + break; + } + } + }, + + _asyncFindLogins : function (form, options) { + // XXX - Unlike desktop, I want to avoid doing a lookup if there is no username/password in this form + var fields = this._getFormFields(form, false); + if (!fields[0] || !fields[1]) { + return Promise.reject("No logins found"); + } + + fields[0].addEventListener("blur", onBlur) + + var formOrigin = LoginUtils._getPasswordOrigin(); + var actionOrigin = LoginUtils._getActionOrigin(form); + if (actionOrigin == null) { + return Promise.reject("Action origin is null") + } + + // XXX - Allowing the page to set origin information in this message is a security problem. Right now its just ignored... + // TODO: We need to designate what type of message we're sending here... + var requestData = { form: form }; + var messageData = { type: "request", formOrigin: formOrigin, actionOrigin: actionOrigin }; + return this._sendRequest(requestData, messageData); + }, + + loginsFound : function (form, loginsFound) { + var autofillForm = gAutofillForms; // && !PrivateBrowsingUtils.isContentWindowPrivate(doc.defaultView); + this._fillForm(form, autofillForm, false, false, false, loginsFound); + }, + + /* + * onUsernameInput + * + * Listens for DOMAutoComplete and blur events on an input field. + */ + onUsernameInput : function(event) { + if (!gEnabled) + return; + + var acInputField = event.target; + + // This is probably a bit over-conservatative. + if (!(acInputField.ownerDocument instanceof HTMLDocument)) + return; + + if (!this._isUsernameFieldType(acInputField)) + return; + + var acForm = acInputField.form; + if (!acForm) + return; + + // If the username is blank, bail out now -- we don't want + // fillForm() to try filling in a login without a username + // to filter on (bug 471906). + if (!acInputField.value) + return; + + log("onUsernameInput from", event.type); + + // Make sure the username field fillForm will use is the + // same field as the autocomplete was activated on. + var [usernameField, passwordField, ignored] = + this._getFormFields(acForm, false); + if (usernameField == acInputField && passwordField) { + var self = this; + this._asyncFindLogins(acForm, { showMasterPassword: false }) + .then(function(res) { + self._fillForm(res.form, true, true, true, true, res.loginsFound); + }).then(null, log); + } else { + // Ignore the event, it's for some input we don't care about. + } + }, + + /* + * _getPasswordFields + * + * Returns an array of password field elements for the specified form. + * If no pw fields are found, or if more than 3 are found, then null + * is returned. + * + * skipEmptyFields can be set to ignore password fields with no value. + */ + _getPasswordFields : function (form, skipEmptyFields) { + // Locate the password fields in the form. + var pwFields = []; + for (var i = 0; i < form.elements.length; i++) { + var element = form.elements[i]; + if (!(element instanceof HTMLInputElement) || + element.type != "password") + continue; + + if (skipEmptyFields && !element.value) + continue; + + pwFields[pwFields.length] = { index : i, + element : element }; + } + + // If too few or too many fields, bail out. + if (pwFields.length == 0) { + log("(form ignored -- no password fields.)"); + return null; + } else if (pwFields.length > 3) { + log("(form ignored -- too many password fields. [ got ", + pwFields.length, "])"); + return null; + } + return pwFields; + }, + + _isUsernameFieldType: function(element) { + if (!(element instanceof HTMLInputElement)) + return false; + + var fieldType = (element.hasAttribute("type") ? + element.getAttribute("type").toLowerCase() : + element.type); + if (fieldType == "text" || + fieldType == "email" || + fieldType == "url" || + fieldType == "tel" || + fieldType == "number") { + return true; + } + return false; + }, + + /* + * _getFormFields + * + * Returns the username and password fields found in the form. + * Can handle complex forms by trying to figure out what the + * relevant fields are. + * + * Returns: [usernameField, newPasswordField, oldPasswordField] + * + * usernameField may be null. + * newPasswordField will always be non-null. + * oldPasswordField may be null. If null, newPasswordField is just + * "theLoginField". If not null, the form is apparently a + * change-password field, with oldPasswordField containing the password + * that is being changed. + */ + _getFormFields : function (form, isSubmission) { + var usernameField = null; + + // Locate the password field(s) in the form. Up to 3 supported. + // If there's no password field, there's nothing for us to do. + var pwFields = this._getPasswordFields(form, isSubmission); + if (!pwFields) + return [null, null, null]; + + // Locate the username field in the form by searching backwards + // from the first passwordfield, assume the first text field is the + // username. We might not find a username field if the user is + // already logged in to the site. + for (var i = pwFields[0].index - 1; i >= 0; i--) { + var element = form.elements[i]; + if (this._isUsernameFieldType(element)) { + usernameField = element; + break; + } + } + + if (!usernameField) + log("(form -- no username field found)"); + + + // If we're not submitting a form (it's a page load), there are no + // password field values for us to use for identifying fields. So, + // just assume the first password field is the one to be filled in. + if (!isSubmission || pwFields.length == 1) + return [usernameField, pwFields[0].element, null]; + + + // Try to figure out WTF is in the form based on the password values. + var oldPasswordField, newPasswordField; + var pw1 = pwFields[0].element.value; + var pw2 = pwFields[1].element.value; + var pw3 = (pwFields[2] ? pwFields[2].element.value : null); + + if (pwFields.length == 3) { + // Look for two identical passwords, that's the new password + + if (pw1 == pw2 && pw2 == pw3) { + // All 3 passwords the same? Weird! Treat as if 1 pw field. + newPasswordField = pwFields[0].element; + oldPasswordField = null; + } else if (pw1 == pw2) { + newPasswordField = pwFields[0].element; + oldPasswordField = pwFields[2].element; + } else if (pw2 == pw3) { + oldPasswordField = pwFields[0].element; + newPasswordField = pwFields[2].element; + } else if (pw1 == pw3) { + // A bit odd, but could make sense with the right page layout. + newPasswordField = pwFields[0].element; + oldPasswordField = pwFields[1].element; + } else { + // We can't tell which of the 3 passwords should be saved. + log("(form ignored -- all 3 pw fields differ)"); + return [null, null, null]; + } + } else { // pwFields.length == 2 + if (pw1 == pw2) { + // Treat as if 1 pw field + newPasswordField = pwFields[0].element; + oldPasswordField = null; + } else { + // Just assume that the 2nd password is the new password + oldPasswordField = pwFields[0].element; + newPasswordField = pwFields[1].element; + } + } + + return [usernameField, newPasswordField, oldPasswordField]; + }, + + /* + * _isAutoCompleteDisabled + * + * Returns true if the page requests autocomplete be disabled for the + * specified form input. + */ + _isAutocompleteDisabled : function (element) { + if (element && element.hasAttribute("autocomplete") && + element.getAttribute("autocomplete").toLowerCase() == "off") + return true; + + return false; + }, + + /* + * _onFormSubmit + * + * Called by the our observer when notified of a form submission. + * [Note that this happens before any DOM onsubmit handlers are invoked.] + * Looks for a password change in the submitted form, so we can update + * our stored password. + */ + _onFormSubmit : function (form) { + var doc = form.ownerDocument; + var win = doc.defaultView; + + // XXX - We'll handle private mode in Swift + // if (PrivateBrowsingUtils.isContentWindowPrivate(win)) { + // We won't do anything in private browsing mode anyway, + // so there's no need to perform further checks. + // log("(form submission ignored in private browsing mode)"); + // return; + // } + + // If password saving is disabled (globally or for host), bail out now. + if (!gEnabled) + return; + + var hostname = LoginUtils._getPasswordOrigin(doc.documentURI); + if (!hostname) { + log("(form submission ignored -- invalid hostname)"); + return; + } + + var formSubmitURL = LoginUtils._getActionOrigin(form); + + // Get the appropriate fields from the form. + // [usernameField, newPasswordField, oldPasswordField] + var fields = this._getFormFields(form, true); + var usernameField = fields[0]; + var newPasswordField = fields[1]; + var oldPasswordField = fields[2]; + + // Need at least 1 valid password field to do anything. + if (newPasswordField == null) + return; + + // Check for autocomplete=off attribute. We don't use it to prevent + // autofilling (for existing logins), but won't save logins when it's + // present and the storeWhenAutocompleteOff pref is false. + // XXX spin out a bug that we don't update timeLastUsed in this case? + if ((this._isAutocompleteDisabled(form) || + this._isAutocompleteDisabled(usernameField) || + this._isAutocompleteDisabled(newPasswordField) || + this._isAutocompleteDisabled(oldPasswordField)) && !gStoreWhenAutocompleteOff) { + log("(form submission ignored -- autocomplete=off found)"); + return; + } + + // Don't try to send DOM nodes over IPC. + var mockUsername = usernameField ? { name: usernameField.name, + value: usernameField.value } : + null; + var mockPassword = { name: newPasswordField.name, + value: newPasswordField.value }; + var mockOldPassword = oldPasswordField ? + { name: oldPasswordField.name, + value: oldPasswordField.value } : + null; + + // Make sure to pass the opener's top in case it was in a frame. + var opener = win.opener ? win.opener.top : null; + + webkit.messageHandlers.loginsManagerMessageHandler.postMessage({ + type: "submit", + hostname: hostname, + username: mockUsername.value, + usernameField: mockUsername.name, + password: mockPassword.value, + passwordField: mockPassword.name, + formSubmitURL: formSubmitURL + }); + }, + + /* + * _fillform + * + * Fill the form with login information if we can find it. This will find + * an array of logins if not given any, otherwise it will use the logins + * passed in. The logins are returned so they can be reused for + * optimization. Success of action is also returned in format + * [success, foundLogins]. + * + * - autofillForm denotes if we should fill the form in automatically + * - ignoreAutocomplete denotes if we should ignore autocomplete=off + * attributes + * - userTriggered is an indication of whether this filling was triggered by + * the user + * - foundLogins is an array of nsILoginInfo for optimization + */ + _fillForm : function (form, autofillForm, ignoreAutocomplete, + clobberPassword, userTriggered, foundLogins) { + // Heuristically determine what the user/pass fields are + // We do this before checking to see if logins are stored, + // so that the user isn't prompted for a master password + // without need. + var fields = this._getFormFields(form, false); + var usernameField = fields[0]; + var passwordField = fields[1]; + + // Need a valid password field to do anything. + if (passwordField == null) + return [false, foundLogins]; + + // If the password field is disabled or read-only, there's nothing to do. + if (passwordField.disabled || passwordField.readOnly) { + log("not filling form, password field disabled or read-only"); + return [false, foundLogins]; + } + + // Discard logins which have username/password values that don't + // fit into the fields (as specified by the maxlength attribute). + // The user couldn't enter these values anyway, and it helps + // with sites that have an extra PIN to be entered (bug 391514) + var maxUsernameLen = Number.MAX_VALUE; + var maxPasswordLen = Number.MAX_VALUE; + + // If attribute wasn't set, default is -1. + if (usernameField && usernameField.maxLength >= 0) + maxUsernameLen = usernameField.maxLength; + if (passwordField.maxLength >= 0) + maxPasswordLen = passwordField.maxLength; + + var createLogin = function(login) { + return { + hostname: login.hostname, + formSubmitURL: login.formSubmitURL, + httpReal : login.httpRealm, + username: login.username, + password: login.password, + usernameField: login.usernameField, + passwordField: login.passwordField + } + } + foundLogins = map(foundLogins, createLogin); + var logins = foundLogins.filter(function (l) { + var fit = (l.username.length <= maxUsernameLen && + l.password.length <= maxPasswordLen); + if (!fit) + log("Ignored", l.username, "login: won't fit"); + + return fit; + }, this); + + + // Nothing to do if we have no matching logins available. + if (logins.length == 0) + return [false, foundLogins]; + + // The reason we didn't end up filling the form, if any. We include + // this in the formInfo object we send with the passwordmgr-found-logins + // notification. See the _notifyFoundLogins docs for possible values. + var didntFillReason = null; + + // Attach autocomplete stuff to the username field, if we have + // one. This is normally used to select from multiple accounts, + // but even with one account we should refill if the user edits. + // if (usernameField) + // formFillService.markAsLoginManagerField(usernameField); + + // Don't clobber an existing password. + if (passwordField.value && !clobberPassword) { + didntFillReason = "existingPassword"; + return [false, foundLogins]; + } + + // If the form has an autocomplete=off attribute in play, don't + // fill in the login automatically. We check this after attaching + // the autocomplete stuff to the username field, so the user can + // still manually select a login to be filled in. + var isFormDisabled = false; + if (!ignoreAutocomplete && + (this._isAutocompleteDisabled(form) || + this._isAutocompleteDisabled(usernameField) || + this._isAutocompleteDisabled(passwordField))) { + + isFormDisabled = true; + log("form not filled, has autocomplete=off"); + } + + // Variable such that we reduce code duplication and can be sure we + // should be firing notifications if and only if we can fill the form. + var selectedLogin = null; + + if (usernameField && (usernameField.value || usernameField.disabled || usernameField.readOnly)) { + // If username was specified in the field, it's disabled or it's readOnly, only fill in the + // password if we find a matching login. + var username = usernameField.value.toLowerCase(); + + var matchingLogins = logins.filter(function(l) { return l.username.toLowerCase() == username }); + if (matchingLogins.length) { + // If there are multiple, and one matches case, use it + for (var i = 0; i < matchingLogins.length; i++) { + var l = matchingLogins[i]; + if (l.username == usernameField.value) { + selectedLogin = l; + } + } + // Otherwise just use the first + if (!selectedLogin) { + selectedLogin = matchingLogins[0]; + } + } else { + didntFillReason = "existingUsername"; + log("Password not filled. None of the stored logins match the username already present."); + } + } else if (logins.length == 1) { + selectedLogin = logins[0]; + } else { + // We have multiple logins. Handle a special case here, for sites + // which have a normal user+pass login *and* a password-only login + // (eg, a PIN). Prefer the login that matches the type of the form + // (user+pass or pass-only) when there's exactly one that matches. + var matchingLogins; + if (usernameField) + matchingLogins = logins.filter(function(l) { return l.username }); + else + matchingLogins = logins.filter(function(l) { return !l.username }); + + // We really don't want to type on phones, so we always autofill with something... + //if (matchingLogins.length == 1) { + selectedLogin = matchingLogins[0]; + //} else { + //didntFillReason = "multipleLogins"; + //log("Multiple logins for form, so not filling any."); + //} + } + + var didFillForm = false; + if (selectedLogin && autofillForm && !isFormDisabled) { + // Fill the form + if (usernameField) { + // Don't modify the username field if it's disabled or readOnly so we preserve its case. + var disabledOrReadOnly = usernameField.disabled || usernameField.readOnly; + + var userNameDiffers = selectedLogin.username != usernameField.value; + // Don't replace the username if it differs only in case, and the user triggered + // this autocomplete. We assume that if it was user-triggered the entered text + // is desired. + var userEnteredDifferentCase = userTriggered && userNameDiffers && usernameField.value.toLowerCase() == selectedLogin.username.toLowerCase(); + + if (!disabledOrReadOnly && !userEnteredDifferentCase && userNameDiffers) { + usernameField.value = selectedLogin.username; + dispatchKeyboardEvent(usernameField, 'keydown', KEYCODE_ARROW_DOWN); + dispatchKeyboardEvent(usernameField, 'keyup', KEYCODE_ARROW_DOWN); + } + } + if (passwordField.value != selectedLogin.password) { + passwordField.value = selectedLogin.password; + dispatchKeyboardEvent(passwordField, 'keydown', KEYCODE_ARROW_DOWN); + dispatchKeyboardEvent(passwordField, 'keyup', KEYCODE_ARROW_DOWN); + } + didFillForm = true; + } else if (selectedLogin && !autofillForm) { + // For when autofillForm is false, but we still have the information + // to fill a form, we notify observers. + didntFillReason = "noAutofillForms"; + // Services.obs.notifyObservers(form, "passwordmgr-found-form", didntFillReason); + log("autofillForms=false but form can be filled; notified observers"); + } else if (selectedLogin && isFormDisabled) { + // For when autocomplete is off, but we still have the information + // to fill a form, we notify observers. + didntFillReason = "autocompleteOff"; + // Services.obs.notifyObservers(form, "passwordmgr-found-form", didntFillReason); + log("autocomplete=off but form can be filled; notified observers"); + } + + // this._notifyFoundLogins(didntFillReason, usernameField, passwordField, foundLogins, selectedLogin); + return [didFillForm, foundLogins]; + }, +} + +var LoginUtils = { + /* + * _getPasswordOrigin + * + * Get the parts of the URL we want for identification. + */ + _getPasswordOrigin : function (uriString, allowJS) { + // All of this logic is moved to swift (so that we don't need a uri parser here) + return uriString; + }, + + _getActionOrigin : function(form) { + var uriString = form.action; + + // A blank or missing action submits to where it came from. + if (uriString == "") + uriString = form.baseURI; // ala bug 297761 + + return this._getPasswordOrigin(uriString, true); + }, +} + +function onBlur(event) { + LoginManagerContent.onUsernameInput(event) +} + +var documentBody = document.body +var observer = new MutationObserver(function(mutations) { + for(var idx = 0; idx < mutations.length; ++idx){ + findForms(mutations[idx].addedNodes); + } +}); + +function findForms(nodes) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (node.nodeName === "FORM") { + findLogins(node); + } else if(node.hasChildNodes()) { + findForms(node.childNodes); + } + + } + return false; +} + +observer.observe(documentBody, { attributes: false, childList: true, characterData: false, subtree: true }); + +function findLogins(form) { + try { + LoginManagerContent._asyncFindLogins(form, { }) + .then(function(res) { + LoginManagerContent.loginsFound(res.form, res.loginsFound); + }).then(null, log); + } catch(ex) { + // Eat errors to avoid leaking them to the page + log(ex); + } + } + +window.addEventListener("load", function(event) { + for (var i = 0; i < document.forms.length; i++) { + findLogins(document.forms[i]); + } +}); + +window.addEventListener("submit", function(event) { + try { + LoginManagerContent._onFormSubmit(event.target); + } catch(ex) { + // Eat errors to avoid leaking them to the page + log(ex); + } +}); + +if (!window.__firefox__) { + Object.defineProperty(window, '__firefox__', { + enumerable: false, + configurable: false, + writable: false, + value: {} + }); +} + +function LoginInjector() { + this.inject = function(msg) { + try { + LoginManagerContent.receiveMessage(msg); + } catch(ex) { + // Eat errors to avoid leaking them to the page + // alert(ex); + } + }; +} + +Object.defineProperty(window.__firefox__, 'logins', { + enumerable: false, + configurable: false, + writable: false, + value: Object.freeze(new LoginInjector()) +}); + +function map(array, callback) { + var T, A, k; + + if (array == null) { + throw new TypeError(' array is null or not defined'); + } + + var O = Object(array); + var len = O.length >>> 0; + if (typeof callback !== 'function') { + throw new TypeError(callback + ' is not a function'); + } + if (arguments.length > 1) { + T = array; + } + A = new Array(len); + k = 0; + while (k < len) { + var kValue, mappedValue; + if (k in O) { + kValue = O[k]; + mappedValue = callback.call(T, kValue, k, O); + A[k] = mappedValue; + } + k++; + } + return A; +}; + +function dispatchKeyboardEvent(element, eventName, keyCode) { + var event = document.createEvent('KeyboardEvent'); + event.initKeyboardEvent(eventName, true, true, window, 0, 0, 0, 0, 0, keyCode); + element.dispatchEvent(event); +} + +})(); diff --git a/mobile/ios/Client/Assets/NetError.css b/mobile/ios/Client/Assets/NetError.css new file mode 100644 index 0000000000..7035c4a7c9 --- /dev/null +++ b/mobile/ios/Client/Assets/NetError.css @@ -0,0 +1,110 @@ +/* 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, +body { + margin: 0; + padding: 0; + height: 100%; +} + +body { + background-color: white; + padding: 0 65px; + color: #333; + font-size: 16px; + -webkit-text-size-adjust: none; + font: -apple-system-body; +} + +h1 { + color: #333; + font-size: 16px; + -webkit-text-size-adjust: none; + font: -apple-system-body; + font-weight: 300; +} + +/* Add a set of stripes at the top of pages */ +#decoration { + background-image: repeating-linear-gradient(-65deg, #eee, #eee 10px, + white 10px, white 20px, + #eee 20px); + position: fixed; + top: 0; + left: 0; + height: 32px; + width: 100%; +} + +a { + color: rgb(76, 158, 255); + text-decoration: none; +} + +#errorShortDesc { + /* Margins between the li and buttons below it won't be collapsed. Remove the bottom margin here. */ + margin: 20px 0 0; +} + +button { + /* Force buttons to display: block here to try and enfoce collapsing margins */ + display: block; + width: 100%; + border: none; + padding: 1rem; + font: -apple-system-body; + background-color: rgb(76, 158, 255); + color: white; + font-size: 16px; + font-weight: 300; + border-radius: 5px; + background-image: none; + margin: 10px 0 0; + position: -webkit-sticky; + bottom: 5px; +} + +#errorPageContainer { + /* If the page is greater than 550px center the content. + * This number should be kept in sync with the media query for tablets below */ + max-width: 550px; + margin: 0 auto; + -webkit-transform: translateY(127px); + padding-bottom: 10px; + + min-height: calc(100% - 127px - 10px); + display: flex; + flex-direction: column; +} + +/* On large screen devices (hopefully a 7+ inch tablet, we already center content (see #errorPageContainer above). + Apply tablet specific styles here */ +@media (min-width: 550px) { + #errorTitle, + #errorShortDescText { + width: 50%; + } + + button { + position: absolute; + top: -0.5em; + right: 0px; + bottom: auto; + padding-left: 5%; + padding-right: 5%; + min-width: 40%; + width: auto; + } +} + +#errorLongContent { + font: -apple-system-body; + color: #ccc; + font-size: 12px; +} + +#errorLongDesc { + margin-bottom: 78px; +} diff --git a/mobile/ios/Client/Assets/NetError.html b/mobile/ios/Client/Assets/NetError.html new file mode 100644 index 0000000000..cd88482cdd --- /dev/null +++ b/mobile/ios/Client/Assets/NetError.html @@ -0,0 +1,50 @@ + + + + + %error_title% + + + + + + + + + +
+ + +
+

%error_title%

+
+ + +
+ + +
+

%short_description%

+
+ + +
%actions%
+
+ +
+ +
+ + + diff --git a/mobile/ios/Client/Assets/NightModeHelper.js b/mobile/ios/Client/Assets/NightModeHelper.js new file mode 100644 index 0000000000..ac83b1f6ce --- /dev/null +++ b/mobile/ios/Client/Assets/NightModeHelper.js @@ -0,0 +1,132 @@ +/* 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/. */ + +(function() { +"use strict"; + +if (!window.__firefox__) { + Object.defineProperty(window, '__firefox__', { + enumerable: false, + configurable: false, + writable: false, + value: {} + }); +} + +Object.defineProperty(window.__firefox__, 'NightMode', { + enumerable: false, + configurable: false, + writable: false, + value: { enabled: false } +}); + +const NIGHT_MODE_INVERT_FILTER_CSS = 'brightness(80%) invert(100%) hue-rotate(180deg)'; + +const NIGHT_MODE_STYLESHEET = `html { + -webkit-filter: hue-rotate(180deg) invert(100%) !important; +} +img,video { + -webkit-filter: ${NIGHT_MODE_INVERT_FILTER_CSS} !important; +}`; + +var styleElement; + +function getStyleElement() { + if (styleElement) { + return styleElement; + } + + styleElement = document.createElement('style'); + styleElement.type = 'text/css'; + styleElement.appendChild(document.createTextNode(NIGHT_MODE_STYLESHEET)); + + return styleElement; +} + +function applyInvertFilterToChildBackgroundImageElements(parentNode) { + parentNode.querySelectorAll('[style*="background"]').forEach(function(el) { + if ((el.style.backgroundImage || '').startsWith('url')) { + applyInvertFilterToElement(el); + } + }); +} + +function applyInvertFilterToElement(el) { + invertedBackgroundImageElements.push(el); + el.__firefox__NightMode_originalFilter = el.style.webkitFilter; + el.style.webkitFilter = NIGHT_MODE_INVERT_FILTER_CSS; +} + +function removeInvertFilterFromElement(el) { + el.style.webkitFilter = el.__firefox__NightMode_originalFilter; + delete el.__firefox__NightMode_originalFilter; +} + +var invertedBackgroundImageElements = null; + +// Create a `MutationObserver` that checks for new elements +// added that have a `background-image` in their `style` +// property/attribute. +var observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + mutation.addedNodes.forEach(function(node) { + if (node.nodeType === Node.ELEMENT_NODE) { + applyInvertFilterToChildBackgroundImageElements(node); + } + }); + }); +}); + +Object.defineProperty(window.__firefox__.NightMode, 'setEnabled', { + enumerable: false, + configurable: false, + writable: false, + value: function(enabled) { + if (enabled === window.__firefox__.NightMode.enabled) { + return; + } + + window.__firefox__.NightMode.enabled = enabled; + + var styleElement = getStyleElement(); + + if (enabled) { + invertedBackgroundImageElements = []; + + // Apply the NightMode CSS to the document. + document.documentElement.appendChild(styleElement); + + // Add the "invert" CSS class name to all elements with a + // `background-image` in their `style` property/attribute. + applyInvertFilterToChildBackgroundImageElements(document); + + // Observe for future elements in the document containing + // `background-image` in their `style` property/attribute + // so that we can also apply the "invert" CSS class name + // to them as they are added. + observer.observe(document.documentElement, { + childList: true, + subtree: true + }); + return; + } + + // Stop observing for future elements in the document. + observer.disconnect(); + + // Remove the "invert" CSS class name from all elements + // it was previously applied to. + invertedBackgroundImageElements.forEach(removeInvertFilterFromElement); + + // Remove the NightMode CSS from the document. + var styleElementParentNode = styleElement.parentNode; + if (styleElementParentNode) { + styleElementParentNode.removeChild(styleElement); + } + + invertedBackgroundImageElements = null; + } +}); + +})(); diff --git a/mobile/ios/Client/Assets/NoImageModeHelper.js b/mobile/ios/Client/Assets/NoImageModeHelper.js new file mode 100644 index 0000000000..de241bace0 --- /dev/null +++ b/mobile/ios/Client/Assets/NoImageModeHelper.js @@ -0,0 +1,94 @@ +/* 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/. */ + +(function() { +"use strict"; + +if (!window.__firefox__) { + Object.defineProperty(window, '__firefox__', { + enumerable: false, + configurable: false, + writable: false, + value: {} + }); +} + +Object.defineProperty(window.__firefox__, 'NoImageMode', { + enumerable: false, + configurable: false, + writable: false, + value: { enabled: false } +}); + +var className = "__firefox__NoImageMode"; + +function initializeStyleSheet () { + var noImageCSS = "*{background-image:none !important;}img,iframe{visibility:hidden !important;}"; + var newCss = document.getElementById(className); + if (!newCss) { + var cssStyle = document.createElement("style"); + cssStyle.type = "text/css"; + cssStyle.id = className; + cssStyle.appendChild(document.createTextNode(noImageCSS)); + document.documentElement.appendChild(cssStyle); + } else { + newCss.innerHTML = noImageCSS; + } +} + +Object.defineProperty(window.__firefox__.NoImageMode, 'setEnabled', { + enumerable: false, + configurable: false, + writable: false, + value: function(enabled) { + if (enabled === window.__firefox__.NoImageMode.enabled) { + return; + } + window.__firefox__.NoImageMode.enabled = enabled; + if (enabled) { + initializeStyleSheet(); + return; + } + + // Disable no image mode // + + // It would be useful to also revert the changes we've made, rather than just to prevent any more images from being loaded + var style = document.getElementById(className); + if (style) { + style.remove(); + } + + [].slice.apply(document.getElementsByTagName('img')).forEach(function(el) { + var src = el.src; + el.src = ''; + el.src = src; + }); + + [].slice.apply(document.querySelectorAll('[style*="background"]')).forEach(function(el) { + var backgroundImage = el.style.backgroundImage; + el.style.backgroundImage = 'none'; + el.style.backgroundImage = backgroundImage; + }); + + [].slice.apply(document.styleSheets).forEach(function(styleSheet) { + [].slice.apply(styleSheet.rules || []).forEach(function(rules) { + var style = rules.style; + if (!style) { + return; + } + + var backgroundImage = style.backgroundImage; + style.backgroundImage = 'none'; + style.backgroundImage = backgroundImage; + }); + }); + } +}); + +window.addEventListener("DOMContentLoaded", function (event) { + window.__firefox__.NoImageMode.setEnabled(window.__firefox__.NoImageMode.enabled); +}); + +})(); + diff --git a/mobile/ios/Client/Assets/PrintHelper.js b/mobile/ios/Client/Assets/PrintHelper.js new file mode 100644 index 0000000000..02c849781e --- /dev/null +++ b/mobile/ios/Client/Assets/PrintHelper.js @@ -0,0 +1,10 @@ +/* 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/. */ + +(function() { + "use strict"; + window.print = function() { + webkit.messageHandlers.printHandler.postMessage({}) + }; +}) (); \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/README.md b/mobile/ios/Client/Assets/Search/README.md new file mode 100644 index 0000000000..e37ecced43 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/README.md @@ -0,0 +1,57 @@ +# Search Plugins + +Locale-based search engines are imported from the Android l10n repos. To import the latest set of plugins, execute the `./scrape_plugins.py` script. + +*Do not make changes to any files in `SearchPlugins` -- these changes will be overwritten on the next import!* If you need to make changes to search plugins, you have the following options (in preferred order): + +1. Update the plugin directly in the Android l10n repos. This is preferred if your changes apply to both platforms. Since the iOS engines are imported from Android, any changes to the Android l10n repos will be picked up here when the import script is run. +2. Define an overlay. Overlays allow local, iOS-specific modifications to be applied after the files are imported. + +## Import process +The Android search engines are scraped from the Mercurial web frontend to the l10n repos. + +1. The list of all plugins is scraped from the Aurora l10n repo. +2. We only import search engines under supported locales on iOS. The list of supported locales is determined by running the `./get_supported_locales.swift` script from the scraping script. +3. We then scrape the `searchplugins` directory to get the list of plugins for each locale. +4. Each file found in step 3 is downloaded into `SearchPlugins/`. +5. Any search overlays are applied to the downloaded file. Note that search overlays are not applied to overridden files. +6. We also scrape the default search engine for each locale from the `region.properties` prefs file. The default is found by parsing the `browser.search.defaultenginename` preference, and the default engine name is written to `SearchPlugins//default.txt`. + +## Overlays + +### Background +For the most part, the engines are the same on both platforms. There are, however, certain iOS-specific changes that we want to make to some of the engines. Previously, we would modify the engine XML files directly, but this made it difficult to re-import the engines from Android without losing our local changes. + +To address this, we've added support for search engine overlays. These are XML files located in the `SearchOverlays` directory that contain document transformations to be applied after each import. + +#### Usage +To add an overlay, append the overlay definition to the corresponding XML file (or create it if it doesn't exist) in the search engine in the `SearchOverlays` directory. The overlay file name is based on the plugin file name used in `SearchPlugins`; for example, to create a Yahoo overlay, we would add an overlay to `SearchOverlays/yahoo.xml`. + +Overlay files have the following structure: +``` + + + + + + + + +``` + +The root node of an overlay document must be a `SearchOverlay` element. It can have any number of `` or `` nodes, which will perform those respective actions on the engine matching this file. + +### API + +##### append +* Node name: `append` +* Required attribute: `parent` - The value for `parent` is an XPath expression identifying elements in the search plugin XML. Note that all nodes must be prefixed by the `search` namespace. +* Children: `append` must have exactly one child element; the element may have any number of children. This element will be appended to any elements matching the `parent` XPath expression. + +##### replace +* Node name: `replace` +* Required attribute: `target` - The value for `target` is an XPath expression identifying elements in the search plugin XML. Note that all nodes must be prefixed by the `search` namespace. +* Children: `replace` must have exactly one child element; the element may have any number of children. This element will replace any elements matching the `target` XPath expression. + +### Tests +Execute `./run_tests.py` to run tests. This uses test files in the `Tests` directory to check overlay behavior. diff --git a/mobile/ios/Client/Assets/Search/SearchOverlays/baidu.xml b/mobile/ios/Client/Assets/Search/SearchOverlays/baidu.xml new file mode 100644 index 0000000000..98934a1620 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchOverlays/baidu.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchOverlays/bing.xml b/mobile/ios/Client/Assets/Search/SearchOverlays/bing.xml new file mode 100644 index 0000000000..f71110ea14 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchOverlays/bing.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchOverlays/duckduckgo.xml b/mobile/ios/Client/Assets/Search/SearchOverlays/duckduckgo.xml new file mode 100644 index 0000000000..ada0acfd35 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchOverlays/duckduckgo.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchOverlays/qwant.xml b/mobile/ios/Client/Assets/Search/SearchOverlays/qwant.xml new file mode 100644 index 0000000000..233ad0b72d --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchOverlays/qwant.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchOverlays/yahoo.xml b/mobile/ios/Client/Assets/Search/SearchOverlays/yahoo.xml new file mode 100644 index 0000000000..ced2af9f84 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchOverlays/yahoo.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ar/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ar/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ar/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ar/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ar/list.txt new file mode 100644 index 0000000000..3c6483de88 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ar/list.txt @@ -0,0 +1,3 @@ +google +wikipedia-ar +twitter diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ar/wikipedia-ar.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ar/wikipedia-ar.xml new file mode 100644 index 0000000000..b7d1f01566 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ar/wikipedia-ar.xml @@ -0,0 +1,23 @@ + + + +ويكيبيديا (ar) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ar.wikipedia.org/wiki/خاص:بحث + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/as/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/as/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/as/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/as/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/as/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/as/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/as/eBay-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/as/eBay-in.xml new file mode 100644 index 0000000000..8d27d340f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/as/eBay-in.xml @@ -0,0 +1,17 @@ + + + +eBay India +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/as/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/as/list.txt new file mode 100644 index 0000000000..42dc76c624 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/as/list.txt @@ -0,0 +1,6 @@ +amazon-in +bing +eBay-in +google +wikipedia-as +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/as/wikipedia-as.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/as/wikipedia-as.xml new file mode 100644 index 0000000000..11fa0e3307 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/as/wikipedia-as.xml @@ -0,0 +1,23 @@ + + + +অসমীয়া ৱিকিপিডিয়া (as) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://as.wikipedia.org/wiki/বিশেষ:সন্ধান + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/as/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/as/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/as/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/az/azerdict.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/az/azerdict.xml new file mode 100644 index 0000000000..c839cb042d --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/az/azerdict.xml @@ -0,0 +1,17 @@ + + + +Azerdict +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzJCNDY4NTI2REMxMUU1ODVCMkNGRkY2RTc3OUJCRiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzJCNDY4NDI2REMxMUU1ODVCMkNGRkY2RTc3OUJCRiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4VHErkAAAJOElEQVR42uxcaWxU1xX+3jrjsTO2x7vHBgUHbMCWsQMBGiiKAkqbhQg1aoQqVWqloqRI7Y+oUaNGlapu6o9KDYqUilSpGqWqiKBLQCGUNjQSTZO2SSgGQ21D8L7WM/YM9sxbe+7zOKEUQlF5b+aae6xre0Zjv5nznfOd7b4rmRM1yIlOaw+tx2htzj0WcuvEoPUXWgdp7c89hpQDIE7rCK11Qk+ByClaD9MalnOWflQoP1BZl9O5Ludop03oJHBhOt/DAHhc6CJv8jiLAVkRcPMXmGWh/LyKFwOE5FEEAAIAAYAQAYAAQIgAQAAgJA+iBnkxSaIFl33zxHW9Z3M/BQC+Kl7RbVwabEPvBQWJRBqhkIqqyiLE6zKorx6CFp4FbBmOLcFxJAHArVR+xqjGT1/qxNlzBjJZCZZVSc9L0DQZuu4grNcgHi9B+1oVbS0Xsby+i/7Q9QCxnaXtIawZ5/qp/MRMJX70wlYMDCbp8Sdfilm+RR4QCkewtrkca1um0Nr0PmLlKQIKCGkmVMUgEpOuoDABwPX/uRzBt3/8AHp6k1CUm7sMU65NHmDRisVKEKe3Ga8dQW31DOprw2ioT6O+6kPiNoteuEBbPFKXbwCoRC0HX38UB36ThiL//5fw/oMreUE7FFKgazbCIQPNq6rQ2mKirfk9VFYOerTlEiA2J2D4BoAsK9j7rU1IJDVfPwDzFMdlcUVGWVmU4kgRgTGI5hXvozjiEnXRUrPkgTa9VvKQdJc6AMz2Eqk6PPP9VUhdDtYSF+OI62pEV8WI12e9LKuuOksZVwgNdVMUUwYWXux5ipzXWOJLFsQ+j04BU/aoJ1gA2DV177pZ8r4sphPA6bMxokGWcRF9aWWIlq6iAF+GttXTWEtBvqg4uRBH2HKlpUFBasjCN75zPwaHC5OLF4M884BljVUEiI27W8/gzoYBREsy9AqLcwBUB2/9bTv27Qc0+r2QZTGOmKaMmpoK7Njaj0e291DKm/CdnnzrBbGg+On1b2LlXXUFn697lTrRVjhkYyY5gYOHi/HKb7eQd/g/Lve1GWfbwNNfeQ0VFVHOiiYHR96Yx5nee3NxjFMAmJSWzuKbX30Hm9fLVJhFkTUULgqmEMWwF39ZD1kt5bcSvtLFDTOEVFpD3+BqnOpehbPnHQwNTVB8cClHd7zXFJqwdPZ7z1aiufFV8mZ/3mAg3VBGPxoVQ7GyLDbF/opPdbxLpOsim6lAd986nKI08XzPLKWNFgxDJbAYfdleQptPYBTihw/7S9Gy3PXSVG4BuLpQ8iiIsjxVTqKj5QQ61joeG04nl2NkvBzDIyaGRyMYnYxjaEzH2NgsZMn0+kl+c/LVFY1l+6siNZ8uzjyDuTlsxXscjQygdMUA1jS55AEaeUK35w3z8zr+2d+J830NVFQZGBufohTR8cDw00OYoTQ3ZeH6GLMCiQG3hg5I2cz6KWakZptwtq8d53uL8Y+uUaQvS0RdMgzyKodRl+Tekvq7trYRP/nuYViZpADgv/J28gAwQFwNU9MrMDwWJdrKYng8ipGJevpdxuTkDAFnedR1o1nE1aLr5Xj2qXk0xY8uNPEEAJ8MiPeTONt2QsiaRF+GhNRcGbovdFLGVY2u7mmkUkmirhvHEUnS8fUnIli/5jCrZvhPQ/MGDAvtSo66FAkTEx1UXK0kMGz0XZhCJsvijEJVu+ONSHUN3mh075eIfmKHvGqe215QIQqzfM/62XTOLcPYRCPGJiOU/tpEOSoaG2QsqzsNx5oLrFi8rQC4HnV9PKIJfgOAittYPlZ2/qo9sTMu37QoVCAAuK0l2L2hubTwfwuQAUdDl82DEXirPDAAVM2BbUdx/lIHTEtd2KR7vR4MOWZ2Xg9w/4gETbdQFRtFQ+3pQPenBpKGJlNV+PWxB3D0+CQU2SxID2BXY4qvqq7BF3b1Y2P7OwvtDp4BYGX/uYsb8PxLdZiYTN/09sR8iWkp2LpJxZ7dJ6hAM/gMwqzinEx24AfPxTD1rxQ3ymeiqTb+/K6BXxx6CGrI5hUADc/9bBlM0yjIceONhBnM8T/Noutcp6/G4wsATOG9/e0YGpnjOkXUdRsHD9dA0hzePMAl5buwLP7vdBmfuIy5dJQ/CnLZ1xJo87mkIttSeQNAQkV5CKrKvwcUFSm4o2SGLwCY5a9ZOYiSiM218lkxdt+WErIn7mIApXLKIHY/VkUfgs92E5sDV1dH8eiOI7BMmT8A2Dhvy4Zf4XOPFMF2ItxZfmVFGM/sPU38z3krwnF1vP3BNux/WSNLmg94Y9XNUye7Z2DVXZX42pdPorJ8hO9WxJUtiXlzGd58ezMVNhlkMmbBZUisdqkgq99yzww6Wn8PO6MG0gsMbCbs7eVRc3t5CjU5Ypqw5IXdegGJGqR7+xnMeBWhEQGAAECIAOD2lcAPbCrkOsBxlvDOODaUN41y9Ay0eyO/xaG8K+mUmV7jPAmJne2QCSj7lKCrJhpqR1FS3AOHUtElNZRPzNThwOs78IcTo1SUXaNBd80BvBToqRrsUuxGvJbmRnz+4TNoXfkBeavNNwDsbvkzPRvx/M9rMT2dLmj6+Y92hKPiM/cr+OKu4/Se/d0Z4etQfjyxAT/cV45EIsWF8hfjlKpYOPZHA6/8bidUndehvKJh34txcmt+h/KH30ih52I7p0P5S+swPMr3UD5E1v/qa42QVB6H8qM2TJP/keTQSBqZuRhnHsAyCsvBUrj1hk305rMRvgBgeXU5G8or/HsAuyE8WjzFGQBk+qubRlAUNrhWPpsL33N3GRQtwxcATCJFA9j5YIVvp4wEUQ8URcLYvfM4bFPhDwA2fHnovkN4cEcYpqVzp/zi4iI8/eRF6Oq8r/0h31sRlhPG8ZPb8PIBxzvxpNBrAnbga0XsDjz1xDncGe/luxXxUSDTHEwm2nDsrVacPTeNdDpNVlVYOZIsswP7yrGxE9h+7xE4FgI5wjKwobx3l3rBD+XZOUZSIEcUfGScweXTEhxDgZCAgrAQAYAAQIgAQAAgRAAgABAiABAACLk+AIZQQ94kzQB4T+ghb9LFADgg9JA3OcC6oWxa8ndabUIfwVo/rfWLMeCzuSeEBKd8pnNDsqY6F59knvAkrV20tgkd+SInaR2k9cJi8vNvAQYAfkWvrJCRv8MAAAAASUVORK5CYII= + + + + + + + +http://azerdict.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/az/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/az/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/az/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/az/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/az/list.txt new file mode 100644 index 0000000000..6ebff05141 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/az/list.txt @@ -0,0 +1,6 @@ +amazondotcom +azerdict +bing +duckduckgo +google +wikipedia-az diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/az/wikipedia-az.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/az/wikipedia-az.xml new file mode 100644 index 0000000000..48dc338cd7 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/az/wikipedia-az.xml @@ -0,0 +1,23 @@ + + + +Vikipediya (az) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://az.wikipedia.org/wiki/Xüsusi:Axtar + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/be/be.wikipedia.org.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/be/be.wikipedia.org.xml new file mode 100644 index 0000000000..b8d586ea78 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/be/be.wikipedia.org.xml @@ -0,0 +1,23 @@ + + + +Вікіпедыя (be) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://be.wikipedia.org/wiki/Адмысловае:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/be/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/be/default.txt new file mode 100644 index 0000000000..daaaf0e061 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/be/default.txt @@ -0,0 +1 @@ +Яндекс \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/be/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/be/list.txt new file mode 100644 index 0000000000..ba637d0f1d --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/be/list.txt @@ -0,0 +1,7 @@ +be.wikipedia.org +bing +google:hidden +google-nocodes +tut.by +yahoo +yandex.by diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/be/tut.by.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/be/tut.by.xml new file mode 100644 index 0000000000..82addfc5ff --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/be/tut.by.xml @@ -0,0 +1,18 @@ + + + +TUT.BY +Пошук TUT.BY +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAB4xJREFUeNrsnE9MHFUcxx9Is6EFBLVpQkmLJiZdPRQPtl6MJBRjoomQ9uKFopeaFEM92ITGxjYam9RES0IPvdiFQ/WgKSb1YtukvUk9tFyK0UShKVhC//BHQJSC7/uYJcvuzM5v3ryZN7PzfsmELdAd5vd5v7/v97bst2d3rTIj2qTcqMAAMACMGAAGgBEDwAAwYgAYAEYMAAPASHhSEYU/IvXCLlb5yh6WSqfZpobtrHLvy7a/tzw+wf67O86Wbo+wxaEbbOHnG2xldi7WAMp0NeOg9Np3D7LNXPEV2+ul32dp5Fc2fX6A/f3TlVjCCB0AVvrT3V2Oq1xWVubmOISr7GFvn7ASA8BmxW89fky54u3kYe9Z9uh8fywsIhQAW4/3cHfTEeqDIV7c+6iHLfI4kdgsCAF1x48XQ1e+yC54XGm40C/cXSIBwOVA+an0Lq0P+FT3Ybbti1PJAgDlN3wzwMqrqyPxkDX72yILoSKKys/m+wUZlI8ADgiQSR4XShZAeU21tPJnvx9k85evuBZX2aKtjtcQXusHQFiZnWVTn0bHGpRmQV59PnL36a8HpFNG2Zrir/e7RM1QUgCgCAQ8qsxfvipWooqiqer1FuHjqZYH8HfebI9EwaYkCCPd9KL8qc9OsYlDXcoUgNX856stoi1BemgOCrVJyWRB1AwDK2/y6DHhdlQLXBhWNWIJRba0tggXFnsAeAiqD4bLmf3uYqAPhCxncegXstuMPYA6YpULt2OnfLivmgPtQhnw5Spk4tBhkcq6Lh6+cHRbga80FMqDKbsJVqSd27EL3HBTiA9+ejhwR4Cw45K7tdXsb9faL/JlAVuIK9au+HHKmhAg68/1iXzfjyzdXtsnoNQGqF9iCQCrh1Jg5Wc7eODa9zqKZinYrPErD3r7hEW5p7H74gcASqQUXdggKaxm0645u4p4AFdEKbgq9+6JH4DNhOCFvFw211fVyJvmVbaKZ4kcAGygu7sf+yC4TIBCLaooscAtI0JPSVcckAdACJJO2QWswi1XpwRQqiwQshy4xZjFgBrS6iuWqzutcgRulQXbcoQ36SvkARQ3WTezR4C8+06HKMKqWvdZ35tlj/jKV52XL42MuMcBHoh11APSANwyIErwBQQUaEH0hnLlcYSnI8xoYlwBuLkYndVlIgC4uRjd0xD5/l1FnIidC0KzLhKrjGCNuuKENABKxhCFDQ/q34GJ63i5oHH3LKeqtUW78mGFbu4QDbuVUrQA7BXoDsaUjm0s9wMQhCm7TnUK2sq+ABxwB7AwFNMNGRyKcBP0/XVZAe5NGd6a1zgj5AuAU7dzww2qq7VsfgM65b5oCuqcD/IFAM02StsY4+lhZ0T1586S9hQoiyjSdQC1baxin5cqGLqijMoghgU9JhM4ADwAJRhjNWJwN2gICLrUAyEPbLZLY1kJ3yOOfAcNASt/2+nPae6Tu07dq18ZAOTRGLalQsC8TrGpCJliC2C9HIWKyjkBZb0gWAFlBGR9tX7cI8bZ/QTnbKYj3sfjiHqt5vokK0rPB4hzYZe8m7XXw9bZQ94YXfEzPYGtT92WoPyYKoIg1Q87wRCTDHZHlPBxBlz5Ks+e6YYQyDlhvxDCFp0QAtkPQHaBcwBxEZ2nKAPbkAEEnMXyEpiTCCHQHTHMZeLUiqopt1KEAAAzQd4AjS5AwAGNsKwBDbY7b7VLucGQIcw88UHdM2/wF41B3+mfm8Ns5sK3PM35l6VeTLOyVEr5PdASmTzaw+6f/pI9nrq/PhfqdWcOmdamhgZycelDhpAFZfiLUKsSFFDIlGQOWztlMehqOu1syWZlIWRH/QBwhL/4SpffFceceEGF0REMyFKAwMV4/diyiEL4EACa+IubUQqGTu0JFGd+Nk8iCOGlstXVVfb7c+lp/o8nWQIkQhBmnv9jpDabhg6yhIhskRhAdjSYWwckBkCEIAidCxcESZIbioA7Eu4nvxLOsISJH0ugzBsVkYxdK+IMS6DIQ/AF4EwBAG4SoygMDARiqiz/8Wn9lq4LLABygiVUvELw0dfaoOMNACwyJw0Ed5Ec6D2Zu/rtLCDrn8YMhOIiMVM0ZhdnCwBwQkhHO1mCxQ0CflbsDLSDdFq63SDrdUC+8LoAvuqTJINAoxCzRtlT9GgAYnpDoh8F12MbXx0BWBCu8S+vMSN+5DpXfrPTD922JPFxs8NGh9IybOnQUYpagGUFKJlv8Wun0afnoNtk5/e9WEA2KLclOTOSVH6bm/JJFpBnCYgJu41+Xd1OM0X5JAvIswQEk+tGx84B14vyPVlAnjWgoOg2+t4gvVzxR7z+JykAFgTEhQxL2B6CjcxYRZbUppb0ZJx1w0Z+/ZBg5ePZG2WV78sC8qyh2bKGpKSqY9aqv+b3jZQAyAHRydbarTtLWPEnuOIzqt5QKYASBqFc8YECyHNNgHEwporHDmFGhavRAiCviGuzrrdjEFgRVAe95PORBmADoznn0l1ZD1sVvrjCULpWAA5AmiwYTVZquztAZY+yteYiFH4rbIVHDgABDLPg5EojKzzTMGpduZL13doVHTsASRHzwa2a5X8BBgBnvaAfQW8DmwAAAABJRU5ErkJggg== + + + + + + + +http://search.tut.by/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/be/yandex.by.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/be/yandex.by.xml new file mode 100644 index 0000000000..48483b25c4 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/be/yandex.by.xml @@ -0,0 +1,22 @@ + + + +Яндекс +Пошук з дапамогаю Яндекс +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAD8GlDQ1BJQ0MgUHJvZmlsZQAAOI2NVd1v21QUP4lvXKQWP6Cxjg4Vi69VU1u5GxqtxgZJk6XpQhq5zdgqpMl1bhpT1za2021Vn/YCbwz4A4CyBx6QeEIaDMT2su0BtElTQRXVJKQ9dNpAaJP2gqpwrq9Tu13GuJGvfznndz7v0TVAx1ea45hJGWDe8l01n5GPn5iWO1YhCc9BJ/RAp6Z7TrpcLgIuxoVH1sNfIcHeNwfa6/9zdVappwMknkJsVz19HvFpgJSpO64PIN5G+fAp30Hc8TziHS4miFhheJbjLMMzHB8POFPqKGKWi6TXtSriJcT9MzH5bAzzHIK1I08t6hq6zHpRdu2aYdJYuk9Q/881bzZa8Xrx6fLmJo/iu4/VXnfH1BB/rmu5ScQvI77m+BkmfxXxvcZcJY14L0DymZp7pML5yTcW61PvIN6JuGr4halQvmjNlCa4bXJ5zj6qhpxrujeKPYMXEd+q00KR5yNAlWZzrF+Ie+uNsdC/MO4tTOZafhbroyXuR3Df08bLiHsQf+ja6gTPWVimZl7l/oUrjl8OcxDWLbNU5D6JRL2gxkDu16fGuC054OMhclsyXTOOFEL+kmMGs4i5kfNuQ62EnBuam8tzP+Q+tSqhz9SuqpZlvR1EfBiOJTSgYMMM7jpYsAEyqJCHDL4dcFFTAwNMlFDUUpQYiadhDmXteeWAw3HEmA2s15k1RmnP4RHuhBybdBOF7MfnICmSQ2SYjIBM3iRvkcMki9IRcnDTthyLz2Ld2fTzPjTQK+Mdg8y5nkZfFO+se9LQr3/09xZr+5GcaSufeAfAww60mAPx+q8u/bAr8rFCLrx7s+vqEkw8qb+p26n11Aruq6m1iJH6PbWGv1VIY25mkNE8PkaQhxfLIF7DZXx80HD/A3l2jLclYs061xNpWCfoB6WHJTjbH0mV35Q/lRXlC+W8cndbl9t2SfhU+Fb4UfhO+F74GWThknBZ+Em4InwjXIyd1ePnY/Psg3pb1TJNu15TMKWMtFt6ScpKL0ivSMXIn9QtDUlj0h7U7N48t3i8eC0GnMC91dX2sTivgloDTgUVeEGHLTizbf5Da9JLhkhh29QOs1luMcScmBXTIIt7xRFxSBxnuJWfuAd1I7jntkyd/pgKaIwVr3MgmDo2q8x6IdB5QH162mcX7ajtnHGN2bov71OU1+U0fqqoXLD0wX5ZM005UHmySz3qLtDqILDvIL+iH6jB9y2x83ok898GOPQX3lk3Itl0A+BrD6D7tUjWh3fis58BXDigN9yF8M5PJH4B8Gr79/F/XRm8m241mw/wvur4BGDj42bzn+Vmc+NL9L8GcMn8F1kAcXgSteGGAAAG7ElEQVR4Ae2de2wURRzHvzN71xaplMcp9CGP+PinRjGiKFETfMYKakCCiIKgQEFbUAmi8RXxgSJqDaCIkBhE5A8hEnzFgAaMBgOxKBWDIBbaAnI8W6X0bnecKdqSdqbhZO92djLzR9n9fWdndj7ffdzN/XYh+LdUVVVl9S4qmERARjOwYkJI7n+a/ffMCTDGGjjbKs522e6auoXFxcVNolUi/sTj8cKcqLMGhPQX67akmQBjlY0Jd0gsFqsl4sjvU1Sw0cJPM/S2zXMTqmvqBpL6o4fL+OXmrba6XU8/AX5ZKqfimp/+rmwPMgKCvTgD6u0NV4Yn/TFxY6YWfvpBq3oQ7KlKtPHMELAGZIazshdrgBJNZgRrQGY4K3uxBijRZEawBmSGs7IXa4ASTWYEa0BmOCt7sQYo0WRGsAZkhrOyF2uAEk1mhEhmuvGpl4a/QL9YC7r+e5Ctv4Ds2g3UN4A0Nf+41GEnrF9vNG3Z0GGdIMRwGFC9B5G5C0BXrAQ53vj/OAmzNCx6G5BIwJk7H86ceSB82cSirwHxg4jeWwr63Q8mcm8Zk54G/HkA0ZK7QbfvaNlRUxf0M4Bf46PD71fCZ9EovJF3wh02FKz/xUD3bgBt/TBH330f0enPhMYv7QyIcHh0y1YpQO/yS5FcVAF2QT+pHsagVgaQr7+Fs3SFlKN3w3VILF8E5ORI9bAGW8/doEfAGCJPzpLuhceP+MTSd4yDLwarjQF0zZegVb9KDUjOexXI7SzVwh7UxgBn8QdSlu7Ng8EGXSnVTAjqYcC+/RDXf1nxJo6VhY2JaWEA/eobEH4PaFtYtzx411/bNmzUuh4GqI7+a64GIlp9UPPdfC0MIJU/SwfGrjA/Wz54A/g3X7Jjl9yAiy6Uxk0KBm4Aqd178ikRCVVWlC+JmhUK3ADU7VUSZbEeSs0UIXADSMPfapadOqk1Q5TADcDx42qUTvC7p945f5TgR9gR5BMn/Bmlxq0EbgDr0kWJhxw+otRMEQI3AHlqA1C7zxTOynEEbgDr10e9c9u2KzVThMANQPeuYEUFUp5k04/SuEnB4A3gNL3LLpEypet4IlUyKdVMCephwNBbpDzJocMQM6UmFz0MKLkJLCtLytmpWCiNmxLUwgB0ORve6LukTEViFl31qVQzIaiHAZxkcka58iyITH0C+L3aBN7txqCNASjMh/volHY7KALkyFFkDR0Fsn2nVA9zUB8DOEX38XJ4AwdIeZI9tYgOvh0i8w0GJeqShmNH2v8YK0WQoWDdPmTdOuJk7r+iS5bfE+5wnpp41QCw/F5AN/5dgjS/ewrOilWIzH6z3ZZikE3H9LuM6WeAQMd/pMm6bSSIj9d9XQ3Q6hLUctjy+0HTutVwS25sCZm6oKcBgjafokh+tBiJipfBzomZyl+f1EQVYW/cPWj6aQPcCWNUVUIdD0fSTeezgP0HpKBZTjbYqXNJ/IE9unmLtK6OwVAYQDZuhrP6cyk/t3Q83Odntmr842p28aDWdc2X9L0HnAIu8tSLp6y1LjKeMe1OndQaCOGS9gZQfuRTfgbIils6DujBH1EKcdHbAPGY6rOzpXgZn8BzyyZKtTAFtTaALlkGuvMPKU/3oQf4N+A8qRamoL4GHKvnUwoVUpasax7cKdwAA4q2BjhvvA1y8JAUsVs2AR1mU0i30jOopwF8Qs6Z/56UGOPfkN3J46VaGINaGhCZNQekUZ4V504rNeqBPe0MIFu3gX74sfRgFtnS7oSxUi2sQe0MiDz9kvR5MQHYfWQyIKYlDCpaGUB4HhBdu16Kl/U8F+6D90m1MAf1McDzoJpyEICTj/HfizuZ9ZoCMS5tDKDLV4Ly67+ssIJeENPSJhY9DGhsROSF15R8k9MfBrKzlXqYBS0McBYsgXhYT1bYeYXwxoyUSUbEgjeAf9t1Xl+ghJmcUQYo0haVG4VICNwAMd9D+LyPrLC+vXnK4giZZEwsWAP4TCdVvCVFEBbpivZVBWk81iLPvQKiyP/3zu8Lb9SwNPauR9OBnQFkUyWcTz5TUnBnTgMcR6mbIgRnwG87W9IJ28L0+AuavBF3tA2f3npuLkSmRLuiaW6RnqmJ7eiZGwjsDDAXaWojswakxsv32tYA35Gm1qA1IDVevte2BviONLUGrQGp8fK9tjXAd6SpNWgNSI2X77WtAb4jTa1Ba0BqvHyvbQ3wHWlqDVLxH8untomt7RcBwZ4SkCq/GrTtpEZAsKcMbFlqm9nafhEQ7OnumrqFYKzSr0ZtO6dJgDMX7JtfsBCPxwtzos4aENL/NDe31c6EAIffmHCHxGKx2uZPQWKhuqZuIL8p8Jf2YKO9MZ8JXfm2zUxPsi0XrAVzUfMf8/fTP37wylMAAAAASUVORK5CYII= + + + + + + + + + + + +https://www.yandex.by/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/eBay-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/eBay-in.xml new file mode 100644 index 0000000000..8d27d340f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/eBay-in.xml @@ -0,0 +1,17 @@ + + + +eBay India +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/list.txt new file mode 100644 index 0000000000..fe09799927 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/list.txt @@ -0,0 +1,7 @@ +amazondotcom +bing +eBay-in +google +rediff +wikipedia-bn +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/rediff.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/rediff.xml new file mode 100644 index 0000000000..7905815b3e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/rediff.xml @@ -0,0 +1,14 @@ + + + +Rediff +windows-1252 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCNjU0MTA3MEUyQzcxMUU1QTJGRTgwNUQ3ODM3MDA4NyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCNjU0MTA2RkUyQzcxMUU1QTJGRTgwNUQ3ODM3MDA4NyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMTkwMEE4NjY0REI0QThFNzkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7xsnzEAAAGrElEQVR42uxdTYgcVRCu6p4dN7vJJosuG9QgnkQxsocQ9OQPCqsIeojk5iWSgwrmpBe9BQSvESLqJf4cgosYCXjyICxIUENAUDAiRggS9BCym/2ZzLyy6r3q2Z6dienO9nTPzFYNb3qnp3+mv69e/bx63Yt/wIOgUud2lNshbo/pZ5PipMHte24L3D7Uz4BKwD3cznKbM5xKkQvcnud2OVJN/8bAL1XmFPN6pGZnv2FSugjmR4WAw4ZFZXJYCDhoOFQmByOLdioV7wNMKhQjwAgwAkyMACPAxAgwAkyMACOgZCFdYurvrIKp1q/fhqNNACFfILe8MLapQuJjgG959qbkGHJuxJ7byPqwnRtdAlCRCABGmWloE+bRZ7AoTw9CiDCA78/d85wYXuj4V/Hvwug2emg2qVUIP19Sk9sSAxixnpHqZh51dgFQmOT3eiaQBHBHTX92AbdFq3yUZtd2LZIjj0OMO/j3uZsQNcQEEDSgdt8+mH77VVHiACZl0zSvvKjaz8urx0/CjUt/MURjtyB8ld8bEI3PANZl2xswfex1iPft5dNTxwnk8NdPfQ0ri4u8Yrxv3qDCHnADarMzsOuVQ1s+0rWPvgC49DsDPNZhpoJZc/xa4+Ua7Hj0cbjj4fth1xtHoLZvlvljE7Nn6qbgrp//FdzitxDDhPa2ETNB0AoXRbz0Gp3DzqKak0gMektcJbK5QA8U+Z7U8r1M2vjcI7DnnddgYv5JwInxthP2x+BeRETdPibiYzQa+ql/jrhCAoqmE9WUCS1Nhp+Bf2g/7HnrCOx8+YV29ORcq5TwchsSkOjqqof6rvffhd1HXgIcrwOJfRdNRxwo8EeKAPK2/ipMPjMPd773JozNPaDmTYD3IQ2o3zYCCtN5TZbEVrdwHaaenofZL08A7pzwdIDDjWTDmyhnPaA4gyPYKrATdbj7zOcw+dwTAHHstd5nskS6KXbsZwQUNk5D3qTMLpyA2r2zAWJHmjS5QcR7sIYitt4RwjiSgE8S3biQsVLkNKs2AvrUATRnII3PnQsXouvRdYwYDbQMpwnC7nEjb3aQepgq6wF9dcQ9QcbhuQqriBkB21tqI3+FKAWY7DbJOWcEZEzDYKOWTDctL8q31059lRrZ7F2ClOJQPDMLO198KoVOTY8QhrWNgE1pmA9DOfLBKPbr18//wji1YOmzs7C2uAgxTgA0CVYu/AAyPB326jUaKgA3+X0Klg/M+YFsOUvrz7/5GFPyl5Y9jYCucBQxgqvHP4DGxYuw9IncZ7gulQEI+XCL9Tbm16THWKJUR929STqO129Oq6//eC5VzInZfNU9+AT9GcauDSnuHgtS9JY/PQMrv51juPYyYJPt0FS+jn3RX8qdDCaFwmS3OYukUuw/RL76Fda0kmIN5p56MdpRUACeNszCrinWpN16MeQJQl8C0MyYal67HVJPc0Za3BeS/OCS7ylhnf9uFIvyRTgCX5KETVpN6eleibdw6jP+x6l0FCrD3th2wN09x/IAS8RMjAAjYKtmnBK3WUBmUOTe5Y3mVeuEOYanjusNM9KyEBciHExGG7ZEAupQdlsRiEqjoFICUKcooA8RNXTMMRyBm6KW2ycglDZD+diFWRQUjT4B7SAxknCSOnpClr0doVbCijJgEvVHoUeA2w4mKFx6lOr+mFGTnZiJSCnE4lQiZM7lVdIqNkEBOUk6KacdD/M61WcUhhcGRaBtQkCvMCTrbIZc1qrEiMryAMsDTIyAIZKKfYDeiYjphCiDlSb1FUneVLAfKOcG1YEIQ91GNBOFLCxbABJCn5BHx4X6TUqy8ZIioWoJUNUV8ElrhtlmMIShiPaAARbZJ3FjyuOo+wDaNIyQN/9J0jcsMg/AbTQtJakySaE8olCTdS4jmqTVqkItEOl4FPatAjaQUVCk92/luWQ/B6h4C9ShGBaG5jZllgeYGAFGgIkRYASYGAFGgIkRYASYGAFGgIkRMLhS4XA0AcR680Mcpe58zC7trWMEGtIhuQoJGIPmlX9g6eOFLT+20l359xaPrBxckX9lWNETLVIPbvXV3XIe3Go9IGWC5HZShOlwd2J7ZnTWmXHJs50pNZkWjYBcFGhRCwlyAZh+eLdOLu/bjdQjTUByfwDdrvMlHOJa2AAQ0PnMn7xQEoyCWB5gBBgBJkaAEWBiBBgBJkaAEWBSAQENg6EyWRYCfjIcKpOfhYDThkNlcloIOClMGBbla79gn/iAZ42E0sEXzBtJFHSZ2wFux7h9Z/j0TRYV4wOKOfwnwACUUUOD1EeLIgAAAABJRU5ErkJggg== + + + + +http://search.rediff.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/wikipedia-bn.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/wikipedia-bn.xml new file mode 100644 index 0000000000..49f8e8afdf --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/wikipedia-bn.xml @@ -0,0 +1,23 @@ + + + +উইকিপিডিয়া (bn) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://bn.wikipedia.org/wiki/বিশেষ:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/bn-IN/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/br/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/br/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/br/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/br/eBay-france.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/br/eBay-france.xml new file mode 100644 index 0000000000..5d1a2db0b8 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/br/eBay-france.xml @@ -0,0 +1,13 @@ + + + +eBay France +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + +http://search.ebay.fr/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/br/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/br/list.txt new file mode 100644 index 0000000000..822a78a50d --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/br/list.txt @@ -0,0 +1,6 @@ +bing +eBay-france +google +twitter +wikipedia-br +yahoo-france diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/br/wikipedia-br.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/br/wikipedia-br.xml new file mode 100644 index 0000000000..14d8184f11 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/br/wikipedia-br.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (br) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://br.wikipedia.org/wiki/Dibar:Klask + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/br/yahoo-france.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/br/yahoo-france.xml new file mode 100644 index 0000000000..5bdc936c24 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/br/yahoo-france.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://fr.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ca/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ca/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ca/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ca/diec2.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ca/diec2.xml new file mode 100644 index 0000000000..fd74d61d22 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ca/diec2.xml @@ -0,0 +1,13 @@ + + +DIEC2 +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCOTA4RjFFQTJENDYxMUU1QTQ4NkU3NUVFNEYzMjg2MSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCOTA4RjFFOTJENDYxMUU1QTQ4NkU3NUVFNEYzMjg2MSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RkI3RjExNzQwNzIwNjgxMTgwQkE5RTFBODgxMUZCMzUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6n8NEIAAADFklEQVR42uydvUsbYRjAn8R4Jn7ix1bI4ObglqKlf0EpFJyKk9Chqwgubv4hWigO0qng6K4EanUQuukQujiooKIkfqTP02Tq3XvNe1zult8PnpjLm3u5e373fsTlKbSrVZFGQ5RAY0Xjg8br7jGkR0vjh8aextfusYgJaIu80jjRaBOZxEk351JQAYGOgCN9P89DmimnGrWivnwm+blgOV8xAR/JRW4s2RTU1CkovOBWKiLlMilKg2ZT5P4+quWi5NztrK+LrK2RvDTY2RFZXY1qCUrOk0ZHRSYnSV4ajI05m4rOludnEpcWMbkskp18QUDOlBINp5sbv3MCXedHRsKf229C6+vlpfe+BgZExsej225vRZ6eeu+rUBCZmOj8/RfbtdjuxXeuL5X6LOD8XGRhwXO3uySyvR29PVtc1M3YRe99zc2JHBxEty0vixwe9t6XbTSOj0VmZsJtm5siW1t+97m/r79ta30WYE/Y9bXfOa4RYyPg8tKvv6srd5v149PXw0PnGlyjyfc+Hx8zWAOihmsv04bzEfB8BuK+79vX4GCya04xNyzC7IIQAAhAACAAAYAABAACEAAIQAAgAAGAAAQAAhAACEAAIAABgAAEAAIQAAhAACAAAYAABAACEAAIQAAgAAGAAAQAAhAACEAAIAABgAAEAAIQAAhAACAAAYAABAACEAAIQAAgAAGAAAQggBQgAAFeuIrexBFXlc+n7NT/vu/bV1zRnSSVBBPkxr+KkhXK8a0x6ar7ZUVvpqf9Ejc15W6z6/K5Nitj5Sq8YzXBfO8zrihQagJmZ0XOzvzOCRzl6YeGROp1/0JuLnZ3kxVyi8LqiG1s+N1nTNHO9ARYAtKqshqXgCQkSICT4eFOsAizCEMuApJUkgPvXLrXgLs7/1qKEI3VpXQtg+1qtSmNRnibUqmIlMskLw2saqyVxw3z20bAT403oSarNGoB/eSXrQHfyENufLcpKNAp6EgP5slHppxq1GwEtDTedT+A7JJvOW/ZCBAdAX//YaDxSeO9xlty1BfqGnsaX7oPvvwRYACUNV/GZTKtGgAAAABJRU5ErkJggg== + + + + +http://mdlc.iec.cat + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ca/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ca/list.txt new file mode 100644 index 0000000000..2e0a625f6e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ca/list.txt @@ -0,0 +1,4 @@ +google +twitter +wikipedia-ca +diec2 diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ca/wikipedia-ca.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ca/wikipedia-ca.xml new file mode 100644 index 0000000000..78ac873e38 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ca/wikipedia-ca.xml @@ -0,0 +1,23 @@ + + + +Viquipèdia (ca) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ca.wikipedia.org/wiki/Especial:Cerca + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cs/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cs/heureka-cz.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/heureka-cz.xml new file mode 100644 index 0000000000..b01fcfc8a4 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/heureka-cz.xml @@ -0,0 +1,17 @@ + + + +Heuréka +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABlBJREFUeNrsXDtTG1cUXq0WwYwK0yUVuEoqk7iIK5EZCtIQz7hwGuwyDUl+AK48rswvCE2KFDZNUjDj0NiFZwKV03igcipDFXei0AQhCXK/i5aRld1z793de/d1zsyOZDCLON95fOdxN/DG0uv1boqXx+K6J655j8WGdMW1K64n7Xb7Pb7QGCv/S/HymhXvFIgVAcJbf2z5rHy3Al2/hu79cdhh5ecDwmN/HPNZ8pF7Plt/vl7gsw7yFQaAAWAAWBgABoCFAWAAWBgABoCFAWAAWBxKUKYP2zg98fzuyUdfu/jklnc5d4MBsKHs5rs9r3m87/kfjuS/KQEQ8lpc9kafrZUGlEav17sszIc5O/WahztecPhcKj2NAITR5996w6V1BkBH8cFf217w5mf5Pku5vLHgDb5+VFggcgcgEBY/82ozc8VHAXF+d9sbLXYYgNDqZ39f9/zjA6e/d3hnwztf3ao3AIjvs8/WrFs9lbD7D/cKkaj9uil/8jOkTfSl84AkykfsRtwGvcT7Sd4f1gUNcV9JV08OzO4t7nP2/YG8b+UBMFX+hVD64M4Pkk6aJnWwKV3rzjscOQEASp/7paMspq4Vv/woNVtp/r3ntV5uav/OMwFCZXNA68WGliLATqCILKjixYK4R1/P28DEZva3qgkALBGXKhYjDIAiZiUz+0+N8sHMn0+1jKRUAEABCAM6ys+yQGoKiw7ebBv/3OyLjWoBgPaCyqrO7+/IRJiloLJOpAwBXNNxYWgXAMFGKEGPJuvWAGJ5Gn6P0FUJAEAHqRgMqx8sb2b6O+FtKtD73+2QlBNe4DIXWATgOW39FvoxknYSoEuPE3XFUNQXpBcoQCw8AFAC1WQD78469KjYFqrd4VdXSRavlBdgEFRqAFS0c6CwQBts6/ybrWul43VEzAcQglyFISsA+B8OSdpJtRfwh7cEi5l7tiZfdRQhOT/x/+R0bOp3DpceKKmsCwnsAHBEV6ia/SJJC0UyR50QR1XxMxTnB+Cw/igSgO/F5YxSe0CDAuDTpfgkGjEZk4Ob39ZjFdVSFE/oK8V1OyljQHe11Ek4kQfEuL0MSxGKhuWT3iasnGpvUMZQmV6QiZDMRCT2yVADUFRFE2bAiY2oW9IQlCZ2qvg5QlRo8SrOD8tXtTio75c2B6SZLqEyVikN+QBVtorzI/anCZW1DEE6rYK4fBDH+ZN664Wj9RXnAKhcO9zfSSpRnD/eA7rV9AAqDFFF2qQSkwxn4jh/onrF0aDeDgDzC8ZU839hZHXLeE5Acf6o+E99lsv5xfICMFpcJq1Ol2Go8oEJ54+iteT9FkqcA1QfHixGN5Tp5gPTvNF894fCiDpl9oAOabkmW9DIB+jj0/XDhlG4kmcPCA8w3UUqJAsiO57jdXSj+iDGIgG0Duf/qKBTtK5xrqD0AKiqWukFBtVm//5OZIJF6DHZalMObhTt8tIAcHVcqEN6AapaE4qJPU7JjsR9EXb+/enISFlycKMo4mA4LtcUra4mYqiB/j75By+tpyq8TJSv2oiWIP945BQAq5Xw1VazmhG1LC9E6Sg/D+t30oroa8ToEAQbzTHkGR3l21iTKQQAsjOpsYICELI+NIFki61snXu6CIO5ABDGeZ1TilAUFKa7TU3lHgz1qVHmtPKzXo8sRBKeFl1rnKwlhl88kJW1KozJM8aYmuGMscFGAzwUbCovcQqAbjKMpbXYZJhqkvn/HF4dVUoRulwxsdwBuAYhh+OpRQXB+UBGcu2MD2NkIS7ocCEAuE58ghmZtJurCkKuM2EkWVSeRfIG1yDkPpSXY0ThDWAiiMNZekT4oA7c24RmugShUI+rmaSTGJioplZxgIaPqpls1CVhYC4Sc+EAiCqqsGvqnx7HKm80cYqeXLYqIAiFB6AItYhNEGr30L7wWKxpTrB1kLuWT01MBIKlc2O1fWylKQgIXTba5bV+bqgpCDaKxto/uFUXBFvtan5yriYIg1VOwk5AmB4cob5Az8rWplzt6gDdhIs6AaDYnpQFrO6YdkZVD2iwMAAMAAsDwACwMAAMAAsDwAAwACwMAAPAkisAXVZDbtIFALush9xkFwA8YS/Ix/qhe7/dbr8Xb1YYBOfKX4HuZRIWb96Kl9vi+pWBsK546Pj2WOfefwIMAKwdcNS3Bx6dAAAAAElFTkSuQmCC + + + + + + + +http://www.heureka.cz/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cs/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/list.txt new file mode 100644 index 0000000000..776e62a0eb --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/list.txt @@ -0,0 +1,7 @@ +duckduckgo +google +heureka-cz +mapy-cz +seznam-cz +twitter +wikipedia-cz diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cs/mapy-cz.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/mapy-cz.xml new file mode 100644 index 0000000000..5916844661 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/mapy-cz.xml @@ -0,0 +1,14 @@ + + + +Mapy.cz +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABHNCSVQICAgIfAhkiAAAAGJ6VFh0UmF3IHByb2ZpbGUgdHlwZSBBUFAxAAB4nFXIsQ2AMAwAwd5TeIR3HBwyDkIBRUKAsn9BAQ1XnuztbKOveo9r60cTVVVVz5JrrmkBZl4GbhgJKF8t/ExEDQ8rHgYgD0i2FMl6UPBzAAAI+klEQVR4nO2de1QU1x3Hv3dmgV0eKoggEBDYWFd8NkaNGrXxEU+j6bEJcHzFPDRRYx60PTmnSZq06WnT5JzUPE7amlMTmmAeJsQTWo2agDYaq2iraBTQ8lBA5C2yAss+5vYPAhVl987szsxVmM9f7M7vzu/Hfpg7d+beHQh6oCC23KA1IGQtgDQCEgED1aCgdgDFoHRLabrrXRBQACAAkPYpRkokeCshZD7XKgcJlNICgTpXFWeiTgAFMT58fSGEzJdI8FZQENE2IehRQoSneRc12CCEpEYXCzUCQNbwLmbQQshaAUAa7zoGMWmCMdrhBwGJEHgXMdgxBHDGEMAZQwBnDAGcMQRwxhDAGUMAZwwBnDEEcMYQwBlDAGcMAZwx8UxuFkPx4OincHfCUqRE/AAAQaX9DPbUbMdHFZtxxdXGszxdIGNzQyiPxBZTGHLm5iNt2A/73V7feQFPH16Gky1Hda5MX7h1QRnJj3j98AEg1pKA7Nm7MSFqqo5V6Q83AUnhVmaMxRSG16d/iFBTuA4V8YGbALurVVZcfGgSNo59XuNq+MFNQJtTngAAWGHdgJGWWzSpg/fRxU1Au+eK7NgQ0YyNab9SvYbwoCH4dkk1Xpj8JmItCarvXw7cBHS45AsAgKWjVuGWsGRVa7grbjHMogXLreuwe9FpPDPxFYSZ9F2jwO8IcNsVxYvEhAdHq7t+bKX18d6fQ0QzHh6dhZ2LTmJ+/E9UzeMLbgIkKiluc3/yQ4gMGa5K/lmxCzCxnyFujDkOb83YhvW2Z1XJw+KmuhVhFi1YZd0Y8H5EIuIX43/vdTsBwVPjfo2MlEcCzsXiphIAACus6wMeuSxLfQy2YZOYcc9O+qNmo68euAkIES1+tRsaHIWfjlrtd9640ERkjf+trFizaMGaMT/3O5ccuAkIFoL9bvvArRshEOWli0TEy7dvUTTSmREzT3EeJXA8Asx+t00Kt+JHcYsVt1tn+yWmj5irqE10SKziPErgJiAyJDqg9qtvfVJR/OyRi7Bh7HOK84QFaXtdwE3A8JCYgNpPGzEH4yJvkxU7PnIKXpv2AUQiKs7T6e5Q3EYJHAWMCHgfD4/OYsakRtiweVYeIoKG+pXDTd1+tZMLNwHxKtxWWJiwFCPMI71uTwq34r05uxAVQHfX5rzkd1s5cBMwSsZ8AIsgIRjpXi6WksNH429z9iDGHBdQjlZnS0DtWXAREGaKYJ4D3JILDY6LzH1lpqyFSPpObVuHjMUHc/NVuYhq7moIeB++4CIgdYiNGXO06QDWHLgHDk+nz7hYSzzmxS/pfT0pahpy5hYg2qzO8LHZMQAFjBk6nhlT2noC5W0l2FzyB2bs/ckPAeg+J2TP2Y1hwVGBlthLfecF1fbVH5wETGTGnLn8HQDg/bK3UNtR5TN2VuwCPD95E96442OYxVBVauyh3jEABdgUCOjyOPDGqRd9xorEhJXWx0G6n7zApK6zRlYcANR31sqO9QfdBYjEhHGR3pejAIBLcqLcXtr7+suaT1HWVqxK/kMNe7Hkq8lwSU5Z8Q0DTcCYoROY3UR5Wwnckqv3tUQlvFP6asC599ftxsZ/paPDfQU17edktWlwDDAB46OmMGNKv+9+rmZXzWeotJ/1O29uZTaeOJQBh6f71sKlriZmG6fUhUtdzX7nlIPuAm6PvpMZc/rSsevek6iED8v/rDifRCW89t1zePHYhj5HlZw56UZHneJ8StFdwNToOcyY4tbrBQDAP6o+6f0LlkOH+wqyDi/He2c3XbdNAntOuslRLzuXv+gqIDEsFbGWeJ8xHurptwsCulfT7a7ZLitXhf0MMvfeifzavH63dzEu8ADtT8CAzgJmxNzFjKm0n0Gnu93r9h1VHzP3safmc2TunYWKq0ZS1+KUMQqScyskUHQVMDN2ATPmP00HfW4/3LjP68nY4enAS8efxM8KV6LDrWzhV38MqHOASERZ86tHmw743C5RCS8df6LPCRUATrYcxX3507Gt4q8B1Xk1TToI0O0bMrdFz5Q1KfLvRt8CAOBI436s3r8AmSmPwiU5cbD+a+TX5ila7OVws88BlzWeCwB0FDAv7l5mTKX9rOx+t6i5EEXNhX7X46YuZkybS3sBunVB8+LZAv5Z96UOlXQj5zpAyRJ6f9FFwMSoqUgMS2HG5V/4QodqupEz2d6p4JrDX3QRcG/ScmZMbUdVQF2KUuyuy8wYuTfsAkFzAQIRcHfCfcy4ndXbQKHfFzblDDGdni7N69BcwOThd/hcudBD3vmtWpfSh4uMSR6g+2ac1mguYGnSA8yYY82HUGE/o3UpfShrK/HrOwpqo6mAUFM4fpyYzoz7/Fy2lmX0S7vbjv+2ndY977VoKmBxYiZzJfJlZwt2VX+mZRle8XajDuieCpVzog4UTQWssK5nxmw/9z5z6YlW5J3f6rUbqm6v0KUGzQRMHTGbufrBJTmRU/YnrUpgUtN+Dkcav+l3W2nrCV1q0EzA8tR1zJgd1dsUrVDQgv4mawDgSNN+XfJrIiDGHIeFCUt9xkhU8vrL68nB+nyUtBb1ec8lOVFQ+3dd8msiYJn1sevWa17Lvos7UN5WokV6RVBQ/K4oq89FYG5ltuaT8T2oLiBICEZGiu//CeGhHrx5+jdqp/ab482H8cqJZ+DwdOBA3R5sOqX+YxG8ofrt6HsSM5grnz8q/4tqC63UIqfsbeSUva17XtWPgBWpvoeehxr24vVTL6id9qZF1SNgQtRUr0+4qm6vwDulr+KL8zk3xC2AGwVVBfQsE++hw30F+y7uxI6qT3Cgfo/xwfeDqgKmDJ+JwsZvcKKlEN/WfYWilsLrJs8N+sLtqYkG3dx0D+sYaBgCOGMI4IwhgDOGAM4YAjhjCOCMIYAzhgDOGAI4YwjgjCGAM4YAzhgCOCNQUGWPMTdQDQpqFwDcWLPjg4tiAZRu4V3FoIXSLQQUxJYb/DUhZD7vegYTlNKC0nTnQgEEVKDOVZTSAt5FDRYopQUCda4CAf3/M74oiC03aA0IWQsgjYDo+89UBjjfD3aKQemW0nTXuyDdayH/Bz381BDxtkZ9AAAAAElFTkSuQmCC + + + + +http://www.mapy.cz/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cs/seznam-cz.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/seznam-cz.xml new file mode 100644 index 0000000000..d14eb2c469 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/seznam-cz.xml @@ -0,0 +1,17 @@ + + + +Seznam +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAACXBIWXMAAAsTAAALEwEAmpwYAAA58mlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMwMTQgNzkuMTU2Nzk3LCAyMDE0LzA4LzIwLTA5OjUzOjAyICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8eG1wOkNyZWF0ZURhdGU+MjAxNS0wOC0xMFQxMjo1NDo0MSswMjowMDwveG1wOkNyZWF0ZURhdGU+CiAgICAgICAgIDx4bXA6TW9kaWZ5RGF0ZT4yMDE1LTA4LTEwVDE0OjQyOjE0KzAyOjAwPC94bXA6TW9kaWZ5RGF0ZT4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxNS0wOC0xMFQxNDo0MjoxNCswMjowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9wbmc8L2RjOmZvcm1hdD4KICAgICAgICAgPHBob3Rvc2hvcDpDb2xvck1vZGU+MzwvcGhvdG9zaG9wOkNvbG9yTW9kZT4KICAgICAgICAgPHhtcE1NOkluc3RhbmNlSUQ+eG1wLmlpZDo5NzIxNWU1OC05MWNjLTRkZmEtOGM4Zi1lMGMwZjNjMzg5ZGE8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPmFkb2JlOmRvY2lkOnBob3Rvc2hvcDphMDBkMDRhZS03ZmU5LTExNzgtOTk0Yi1kYzk1ZTg5ZDQ3NTU8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+eG1wLmRpZDplMTVmZjczMi0yMjQyLTQzMWMtYTQ0Yy02ODYwMDVkOTc5OTg8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkhpc3Rvcnk+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jcmVhdGVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6ZTE1ZmY3MzItMjI0Mi00MzFjLWE0NGMtNjg2MDA1ZDk3OTk4PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE1LTA4LTEwVDEyOjU0OjQxKzAyOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6OTcyMTVlNTgtOTFjYy00ZGZhLThjOGYtZTBjMGYzYzM4OWRhPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE1LTA4LTEwVDE0OjQyOjE0KzAyOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+OTY8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+OTY8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PqvEAjkAAAAgY0hSTQAAbXUAAHOgAAD83QAAg2QAAHDoAADsaAAAMD4AABCQ5OyZ6gAAB5ZJREFUeNrsnW1MW9Ufxz/3QktbWsrTHliU8TSHE1h9GCMsODaCYZqgU3QLIzjnXBY1McaYGLMlf5NlL3xjsvhGw7bMABqBjGyJGhQ3lWTAlmzE8CDMQec2mAPa0ZZCC60v6NR/4nja7QP0fJP7hlzOvff7Ofec3znnd26lS/wtCXgd2A9sAAwIKSkb0AVUAccBL4DkA7AaqAaKhE8BUTNQAQzJvpovzA+sinyeS7KvyRHmBwfC67Kv3RcKjvbLvg5XKDjaIItoJ6gyyMKD4EoAEAAEACEBQAAQEgAEACEBQAAQEgAEACEBQFlps7NJ+eILTKOjRG/eHFL3Jl3yrU0uO9Mfe4zYF14gdudOdE88AZIEgHtwkO6nnsJ965YAoNhDqFRoc3KIzs1Fv2UL+q1bUT/00H3Pt7e00FtYiHd6WgBYcJup16PLyUFrMqEzmdA9/jja7GykqKgFlXPr8GEGjxwRAGZ3W0ablYV+yxaiN28mOi8Pzbp1ID941+V1uejOzcXZ0SEA/FuRCQnE7txJzDPPYNi2jcjERL9dy/7LL/z29NMCgKRSEfviiyTu3YuhqAhJpQrYtX/buhX7zz8Hr8IF13mJhMpK1nz0Eeq1a4NyC3EvvRSeANTJyaRWV6MvKAhqHdA9+WRwm9xgXNRQWEhafT2RCQnBj0LU6vACYHzuOdLq65E1mpDo9Cd6esJnKiJ60ybSvv46ZMz3ut3c+fTT8AAg63Sk1tYi63QhYb57cJCrzz6Lo709PJqg1R98QFRGRtCNd3Z2MnLiBHc+/xyP3R4eI2FZryfn5k0iYmIC38b39uJobcVx4QJjzc1M9vWF1GA/IG+APj8/IOZPWyw42ttnjrY2HO3tTN25QygrIAD8NZ3g7OzE1tz8t+mhVrtDBsDk778rVpZnfJw/jx1juKpK0XKXdR+ALJN97Zoi0w3XXn4ZS309y0WBCUM9Hm5++KEyRU1MsJwUsHHAaG0tIydPPnA5a6uqMBQVCQCLkfnAAUZrax+oDNWqVTzS1ERqTQ1R6elLHkDEAfhfwK7m8WA9fRqv04mhsBBpsStbkoQ2O5sVBw8SlZGBy2zGPTQkOuGFjg2SP/sMbVaWIuU52toYPnECS10d0xaLADCvi6vVrHrvPZIOH0bWahUp0+tyMdbUhKWhgbtnzzI1MiIAzCX1ww+TdOgQCfv2IUUqNzTxTk1hO38ea0MD1jNnQiYXKOQA3FNUejpJhw4RX16u/EKJx4O9tRVrQwOW+npc168LAPeNdJKSWPn22yQePEhkfLxfggF7SwvDJ09iqa8P6qxoSOcFydHRJO7bx8p33vFbyDlttTJ8/Dh/HjsWlLdiaWTGyTKxzz9P4v79GEtKFEnM+q/Oe+TUKQaPHAkoiCWXmqhOTibh1VeJLy9Hk5mpfOvkdDJ09ChDH3+M1+USAGaTduNG4nfvJq6sTPHVtvHLl+kvL/f7ov2ySU/XmUzElpURV1aGZv16ZfoHm43+Xbu4++23AsCC3oycHOLuwXj00QfrG9xu+vfswVJXJwAsFkb8nj0kVFSgWrNm0RD6ioux/fSTALDoB1WpiC0tZdX77y9qm5Lrjz/oXL8ej9OpbIBHmMjrdmNpaKAnL4++HTuYvHp1wdMlCXv3Kh9hE4Ya++47OrOyGK2pWdD/xZWViSZI2aeXWPfNN8SUlMw7KrqicHpNeO8T9nq5/uabeKem5nV6hEH5z+uF/Ubtyf5+HG1t8zp3anhYAPALhHl2yI4LFwQAf2i++Uojp04JAIoP1LKyMMxjp6Tj4kUsp08LAEoqwmgk9csv55zenhoeZqCyEjweAUCxZic5mUd+/HHOrAzXjRv0FRf7bVY07ABIkZGseOstNnR0zHzEY5YQdbS6mm6TifErV/x2P5HhYnyE0UhCZSUr332XqNTUWY23nj3L0NGj8w5PBYBZRrr6ggISX3uNuFdemXV/msduZ/Srr7j9ySdMdHUF7BaXJQCdyUTcrl3E796NOiXl/pV9epqxpiZGa2qwNjbicTgCfq/LAoCs0RCdn09saSnG0tJZmxiv243t3DksdXVYGxv9MroNCwBRGRkYS0qI2bEDQ2HhnM3L2A8/YG1sxHrmTEjlji4ZAKrVqzFs3z5zbNtGVFrarLXc0daG7dw5bOfPY29pCUiGw7ICoEpKQl9QgL6ggJjt29FsuP8vrbgGBrC3tjLu2x05fvmy4itXyxqApFajM5lmvoqVm0t0fv5/1nCvy4Wzqwvnr7/OHB0dODs6cN++vWT7r8ADkCQ0mZkzRm/ahC43F93Gjf+XjDt99y6OixeZ6O5moqeHyd5enF1dTPb1zXvufslEyv5eEYtcsYLovLx/anduLhFGI1PDw7jMZlxmM5NmM5O9vUz09jLR3Y17cDB8RuZKA4hKT0dnMqHJzESdkoKs1eK6ceMfswcGcJnNQYm5w/INEJpjDCMsEAAEACEBQAAQEgAEACEBQAAQEgAEACEBIKwA2IQNQZNNBrqED0FTlwxUCR+CpirpEkjA90CR8COgagaKZWYWZCp8fxAKnPkVgPdeFDQEFANvAG2iY/ZPh+vz9g2f10MAfw0AplOyxDyGHKYAAAAASUVORK5CYII= + + + + + + + +http://search.seznam.cz/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cs/wikipedia-cz.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/wikipedia-cz.xml new file mode 100644 index 0000000000..36b15cde86 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cs/wikipedia-cz.xml @@ -0,0 +1,23 @@ + + + +Wikipedie (cs) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://cs.wikipedia.org/wiki/Speciální:Hledání + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cy/amazon-en-GB.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/amazon-en-GB.xml new file mode 100644 index 0000000000..a63eb0caa3 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/amazon-en-GB.xml @@ -0,0 +1,12 @@ + +Amazon.co.uk +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.co.uk/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cy/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cy/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/list.txt new file mode 100644 index 0000000000..84e480939f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/list.txt @@ -0,0 +1,6 @@ +amazon-en-GB +bing +duckduckgo +google +wikipedia-cy +yahoo-en-GB diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cy/wikipedia-cy.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/wikipedia-cy.xml new file mode 100644 index 0000000000..6a4da7037f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/wikipedia-cy.xml @@ -0,0 +1,23 @@ + + + +Wicipedia (cy) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://cy.wikipedia.org/wiki/Arbennig:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/cy/yahoo-en-GB.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/yahoo-en-GB.xml new file mode 100644 index 0000000000..91713ad634 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/cy/yahoo-en-GB.xml @@ -0,0 +1,22 @@ + + + +Yahoo.co.uk +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://uk.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/da/amazon-co-uk.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/da/amazon-co-uk.xml new file mode 100644 index 0000000000..3a3fbabb19 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/da/amazon-co-uk.xml @@ -0,0 +1,16 @@ + + + +Amazon.co.uk +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.co.uk/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/da/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/da/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/da/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/da/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/da/list.txt new file mode 100644 index 0000000000..3108316eb0 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/da/list.txt @@ -0,0 +1,4 @@ +amazon-co-uk +google +twitter +wikipedia-da diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/da/wikipedia-da.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/da/wikipedia-da.xml new file mode 100644 index 0000000000..a6c740de48 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/da/wikipedia-da.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (da) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://da.wikipedia.org/wiki/Speciel:Søgning + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/de/amazon-de.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/de/amazon-de.xml new file mode 100644 index 0000000000..1253945732 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/de/amazon-de.xml @@ -0,0 +1,12 @@ + +Amazon.de +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.de/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/de/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/de/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/de/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/de/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/de/list.txt new file mode 100644 index 0000000000..01536d292d --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/de/list.txt @@ -0,0 +1,8 @@ +amazon-de +bing +duckduckgo +google +qwant +twitter +wikipedia-de +yahoo-de diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/de/wikipedia-de.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/de/wikipedia-de.xml new file mode 100644 index 0000000000..d576b753ac --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/de/wikipedia-de.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (de) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://de.wikipedia.org/wiki/Spezial:Suche + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/de/yahoo-de.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/de/yahoo-de.xml new file mode 100644 index 0000000000..04b36eea83 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/de/yahoo-de.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://de.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/amazon-de.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/amazon-de.xml new file mode 100644 index 0000000000..d19cc3133a --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/amazon-de.xml @@ -0,0 +1,16 @@ + + + +Amazon.de +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.de/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/list.txt new file mode 100644 index 0000000000..0ed2c032aa --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/list.txt @@ -0,0 +1,6 @@ +amazon-de +bing +google +twitter +wikipedia-dsb +yahoo-de diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/wikipedia-dsb.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/wikipedia-dsb.xml new file mode 100644 index 0000000000..a4a8a16f20 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/wikipedia-dsb.xml @@ -0,0 +1,23 @@ + + + +Wikipedija (dsb) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://dsb.wikipedia.org/wiki/Specialne:Pytaś + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/yahoo-de.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/yahoo-de.xml new file mode 100644 index 0000000000..04b36eea83 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/dsb/yahoo-de.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://de.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/el/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/el/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/el/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/el/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/el/list.txt new file mode 100644 index 0000000000..3da7e54726 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/el/list.txt @@ -0,0 +1,4 @@ +google +twitter +wikipedia-el +skroutz diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/el/skroutz.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/el/skroutz.xml new file mode 100644 index 0000000000..7fa892102a --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/el/skroutz.xml @@ -0,0 +1,15 @@ + + + +Skroutz +Ενσωματωμένη Αναζήτηση στο www.skroutz.gr +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozOTM2Q0Q2NjNDREQxMUU1Qjk0RUFGQzRBMEY2MzVFQyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozOTM2Q0Q2NTNDREQxMUU1Qjk0RUFGQzRBMEY2MzVFQyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDM4MDExNzQwNzIwNjgxMUI0NTZBNEVEM0I1NUYwMzUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5F3cluAAAN2klEQVR42uxdCWxc1RU97/8/i8dL7GxkxaRJSEhrlLAEQiBtxd5SoGUJlNJFIFqkiqJSVFEkWqqqqkpbNaCWlgqqQlGhJSqtEAEEAhHCEhIIAdKEJYtJwHZsk8TrzF9e733/jzP2zNgz9v+zeZ7yMrbnz1/Oefe8e+9bRvTevQheCUPgBnq9nOoq9TsXof6XVG36f5Bqgv4mMbKIMX4v/cJ3HKJaQ1VPe9dRVQgp1c/q8ehnR9fco1MRkSmvmndmwk1Y8hX67GP06310qgRfTfSuW8QHzKVDnqC6fEwQZQ5Alx/4+d03YUBgcpOExi+6GE6Z9I6h/6QmkgS4n1HkiW2OZV+EqH7AUC1dYgO9tqTdhMx+A0PHZSJElin4edw3AyscsgD6jEbAOppIO58UYoiM1HMTLcs1XdtAXJxi0G830MEtY4I+miXkQtpEW6ScYKvN53nGc5+mJ2BD52JmxNB5lXSlSBP9axGEPVvA2lEvLgK++YmeV/pItpjAhy3SI0NPsyiRIkkZ7nWtQQesHM8DSj+0tJSKzJPM4ZICkhTVT8PrnJOEqh9TW//wspIlKDwe4EQxLCJoDvJ5/nRJob8N95qOvi0yOo70TtjISddz1f8yL0L6YTEyzVkRo8iIMeFWXKFkjFocmRM+QmYgSw7HyhjmUhbTkyiHeEB6+i7HAECmMOBkwUV3e2mjKj05NqSRwMscPifHvoimUgsyg7alVZlZA+UkkR0hRidL5qkKUnXUjkF61uflgcaf05mMJCQbpMgRE5GSQXCQlKY+w/sxd3AnS0c7VhmKcmX+qQwxpB4JY8L6OJkIkRMw/SyHGiN91rw7WjlZTUDmf0iGj2hVcIub1kiPhEUOJIjJ3uj9a5lGUNY3qaVnXH0AMofKpY8HB0g2VSelSpWhFCoRw0OGYRJbvSR5MnwjWhTggRhoxySMLXp1CFsC1TAgIk1AtA4iXEMRTT393kigRwBrELK/DU53K9Df7RJhRCYAqP+mbxTbMkc/JwFuUaBOoCuwo1OgNXwGouk4aDOWQUxdCK1xDkTdbCDSQMDXUkPQ0yxEdu+Gvft5mNsegux8HwjVlozuir67FnbS67TSaOYcFtpuyyUpETUE+PQl0OaeBH3eSogZS4mAedRswuPjs78LicdvhL1vE5EQKy747im7jLw+EBT+rON2HNKKQ8SaoB+3Gvqic6E1r4JGrVzpuB+tLTYNoXPvhP3gV+h6duH7hawSJPMAym/gzX51A9oxy6Av+yr0JRdAm7Y4uAzCjBNUdfa/QVZQUwIEFMulTPSpaRvc2o0V18JYfF7BABGNzZCtm0vC0TMKezmh9B1OguRlNUKnfZek5vyCu7xCD5WMF104Alhu4ochpi1EaPUPYLRcQXpgFOWhpZK9SUMANW87oTpZY8U1CH3hNnIbjylu7DbYQ/26NhkIYMkZUNoevuCXMJZfUwKRM0XKA93p8ULlEUDgmwR+bAoil95Lne2a0rB56n+keaRkci3BEcCyE61D5LL7oc8/vXRSR+wE2KZvsUVpEqASZCbCF95TUuCrYiXcIKxESiDNQCZ6YJx4FYwTLkbJFQafq6hUCXIsiFoK+c+4aQxP5DDsHf+BtWsDRHQKwuf8FKJ+dgH6AC91XaluKGusseR8lbHMqgLvPAbzpd/BOfieGwuwX05WE7nyocC1WUqbqqxgCaKH05vXZH2PgeeMpPy0lVp+I0S4DiI2A/YHz6mUcUECwkAzi0UlQJJ7bWQNtKTVD2vb3+iqPDASTfFY3cn05ub7/E/4ZXKPS2gdVSAWwKNWGR89FIOx7HLXFRxZwjE4ezfC3vtisPBrOvGtVaoECTVc6LS/nfV948xbKChbRZrfO0IGhBpmNDf/JdjWyX2OVrEEcIQfgbXzCXJFMye8BLX08IW/BWqnqvzQsBKqhbPnBditrwb3xLpHgKxUCTIicDp2wdr0++wXnbEE4bPvhORoORUI6gukZcJ6/f7gnjgUVQP5ldsHqFZeC/PVP5C7uT47Ty1XILT8asj44WFSxJ+1P3wWzidvBdMHKAJiFWwBbk+nso2JDbdSp7oxe2P84h3KGlTGNOWzLF/W1r8G1AuTlxabyS5ZBROgtDZCAVYC8f9+nwKuXZmxiDWRFN2hZkCktkhBfQFHyLJrdzAPXTeTnAWnwglgjeUx3p52Cry+B9l3MDNPi89H6HOXUatPSRGTpyL7u2G+9XAwRlA/N7c+QLnUtpe+kOVGgEdCuB5229tIPPkjNw2cSYrW3Aqtfpabwk4GdESeteNxIq7TfwIaZo8OujlAfVMPJ02ASBQiUsMZRm8GR1kR4IEZbYRNrqm58TeZAWk8FsZpN0KafSmmEYb8dB+s/z3uPwFNzdRFhYdbAQPPsYkThzbvZCWN0a+vR811zyF6/XOIXPUI9OPPIxJ6/XUaCyZ2kQaYL98DbVYL9KUXpd/ISd9SXpPs2Dk0PUWQS2tv/xdCK77pzuv0i4ApzXQ/dQRm3J2cxSN3QpIcngfj1OsoUDwzbchSr5sN/djTEV9/PexdT5Fl15aLBQxFaK5n9PTtcLp3Z3Rdw6tvHu6dGFE4JF+jeVLjeuiGWSplzpInBw+pSWGRyx5A5MoHoS/4fPbxYvp76Mwfug3Ep5R2YWNyBrSnDYmnfpyxP9CXfhnagjUkt30pqQ0b1vZHfA7GYsoKJEXi4bNuQeQb/yZ5uSA3wMht1qY2Z+3PSpsA7g8i1Cl/+DzMV+7JGD+EVt3krUCUnksag73nRcjuvf62hWWXIHr1I+40GZajnN1rksLYLHfmdvkRkJSbeuoP7s6Y89EXnAVj4dlHO2TSaNnXRZ3xen8JOHEt9EXnjM+zswfg13hCcdKCDKqVQOKZn3ju3ghwyCNSSbOkFZB0cWAGK170wEkOHIY8st+3WX1Fy8uytDifbM/omurNZ8DgzjDpd1NULdt3wt6/pegEOAe2EgFtbgMpZwKSUmRteYC8nJfSSTjhUm98WLpZUsckl/RRevhPXKspUjLN2vqAGxn7JEGi79f5rJAJoFArFxQbhM/9BcUA76gsqNP1AWT/IcjethH2T65ftIGspx4i1qCmmfMCDm3mUogZy6BNmUfMBTfz2XztT0g8+zPlMvtEQFfxCVB2bbmtXI2SadTwDVdj08CUR6eVOLaa4aCmwfCxNU3QmBBezsQra+acDNEwxyfhlyq9br7wK7qvkJ8ra0qEgORivORy0wz7VQoOjvjBGWwV1KVu75JMmplqkIfHfEXdTBV1a3NOoroC2vTFbhIun+FI6vTt1pdhbv4zHHKd1TiCv8uaikwAg24PQpCssJTwXCJBMiKiTW5L40iVs6QDXXCOtAN9HSqrKvs7VSDE83tU61frgI10qyIAJUXWvCBDkIWIxgVU50NrOpbIILniaTGcaKPIlpN/ygrjvdTPdMBpJylsfc0d3+YtynxKPYwkoEgrJBw1fVGbtgihlitUFKrWhY2l3wx6XycB1Aqnc48LUscuCtLeo793u8tZheGuBeaWSqAlt76W8X7Ij9+EPPC6Z2U6kedtK6ysSfP28nFUVas0mVidiDGCm0NUYAvwlijRgxsrb0CI/H1euThhPo8cgHNwJ7mIW+B8vJ1I2UGEdLhyxANDanG2GFXjh99mwSZtFdICeL1AH0TtdIS/dJcaiPHtzA1zoXOlCFrhOUjBEhFif/Qq7D0b4bS9401JzwJsESfqFi4OsAZI3+cgsvbvvoKf+VqDashRRKcqz0jpO0pnQu6wqL8wbqatZCB88R/JMzkxmG6FgjMe9OFRNKf9XaD/U69P0N30cYksSSoKAZxYC53ybejzVwZwcglr28MwX7+PtH+nCzhrfihKoleDUi/BE8CuohGG/tmv+W9YB3fBfPYOld5mV1REGlBuJXgCWAYa5qvdTfwsNklN/JnbIXs7yxL4AlqArVxNHojxLS2w8S6YL61TyToXfFklIDtg/rl5cqAbiaduU4P3nEl10wLlvX9a8AR4I1qcaJuIFXCWNP7kLRRobVPTXCqlBB8H6CHIw/sIuDfG79a/+RDi/1gL2faumyeqmCLYArJ9V5Xw7SJ8Op4TxLte5bMljXPgDZib1sF6/2ly46NAuO7oOSukGFlB87Pw8OPelzH4z2sRWn0zEXFq1s3zZE8b7I82qyWs9p4XgES/q/cVWgqXCwrXwtn3CuL7t0CbthBi+vHuCBYv1rPjcHraIQ/tVasnJf3sTu6NpbT6SiUgyH1CRzoo3sIIp+N9oG0HrJS5NWrhnPBGwVJ3NSy2kxPYPnkeJCN34xU+4p3xXOySKvmJ5HUtWQB8Mu7SLH06T7Y2meuD+vVAQRtZqZ5fjipBokzRKWcJ8vAxKgaoMjUxrYp98XiVyT5AlmnrKXsJCtwNrZax3dCKaq1laMVGoDvnVCVoTHiUBEkx9jVlad172RlA2g5FwyRo5LcUCn/uoiJUTQZ7GiYgXPDwrypByaLzgEwNqqVYpVZDwbewr5aUEjIkf51tUoZkBpsTuX5lX4UGEtm+tlwc1SjBs6m1sZ9fOHLkcb0a9bhbVa8rRWYQk++NViddFJfy7E7yG67GwMgRmY57my3gUfrzqqoajNdCpLuYUI7ruEfFoZ8vZvnh9Z8tVTQLWnhryVM4EuY+4EKqG6okFBR8xjyRTMYdYDaofofqJVR5pYPuiTsvTx9ANVs0ngiCZxTwuqvkysNNVHnPhXvhNnz8X4ABANRAb02iBx5JAAAAAElFTkSuQmCC +http://www.skroutz.gr/ + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/el/wikipedia-el.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/el/wikipedia-el.xml new file mode 100644 index 0000000000..64fcb3caec --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/el/wikipedia-el.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (el) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://el.wikipedia.org/wiki/Ειδικό:Αναζήτηση + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/amazon-en-GB.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/amazon-en-GB.xml new file mode 100644 index 0000000000..3a3fbabb19 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/amazon-en-GB.xml @@ -0,0 +1,16 @@ + + + +Amazon.co.uk +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.co.uk/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/list.txt new file mode 100644 index 0000000000..28c00428fb --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/list.txt @@ -0,0 +1,8 @@ +amazon-en-GB +bing +duckduckgo +google +qwant +twitter +wikipedia +yahoo-en-GB diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/yahoo-en-GB.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/yahoo-en-GB.xml new file mode 100644 index 0000000000..91713ad634 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en-GB/yahoo-en-GB.xml @@ -0,0 +1,22 @@ + + + +Yahoo.co.uk +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://uk.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en-ZA/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/en-ZA/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en-ZA/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en-ZA/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/en-ZA/list.txt new file mode 100644 index 0000000000..517b81ae99 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en-ZA/list.txt @@ -0,0 +1,3 @@ +google +twitter +wikipedia diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/amazondotcom.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/amazondotcom.xml new file mode 100644 index 0000000000..84b1c7e76b --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/amazondotcom.xml @@ -0,0 +1,16 @@ + + + +Amazon.com +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/bing.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/bing.xml new file mode 100644 index 0000000000..48e15c62b1 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/bing.xml @@ -0,0 +1,20 @@ + + + +Bing +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAABl5JREFUeAHtnXtQVFUcx793AcEEtEEkyywfgFASk+GjIjKE7CG9p7HBMZXMqUbUIZx0YCL7QxOaxmaqUUz/oMaZTBxLwsEVM8skRVE0HiEhRhEhxkNQgdvvXGcnBWt3Ze+ec9bzm4Fl7z17fr/z/ZzfvXfPOfeiwWa6rmFV2gJ6mwINkdD1ANsu9eoCBTStDTpOUk25yMjeCE3TWa2aUfV7b96Crt48QI833qtfJiugWeFnSUb62j8s1NM1Jb7Jevernjo66/CkvRe8O16hnp/ar4zaYLYCY7Gv6AzLAHbcV8ZHgRSLccLl41x5pYsdlgHqaodXVyDtLbx8K7+XFVAAOPcEBUAB4KwAZ/cqAxQAzgpwdq8yQAHgrABn9yoDFADOCnB2rzJAAeCsAGf3KgMUAM4KcHavMuBGBXBsYRqW3z8dowOHcZaAr3sN7ywzlke4Oww9I8dwqes69tfX4rPjh/HFyTKc7ep0dyhc/XEHcGXrL/X0oLCmgmCUYkdVOTq7u6/c7ZF/e4vUKh8vL8wKu8v4ab94AfkVx7Gy+BvUt54TKUyXxiLsSdh/kC/mRN2HyOEhLm2waJUJC0A0ocyKRwEwS1kH61UAHBTKrGIKgFnKOlivAuCgUGYVUwDMUtbBehUAB4Uyq5gCYJayDtarADgolFnFFACzlHWwXgXAQaHMKqYAmKWsg/UKNRpqL+b0adPR3duLLSeOoKG91V5xKfZLlQElDaeRk5iE+iUZsCYvwvzoyRjq6yeF0P8VpFQA9tbVoKr5T1g0Cx4ZE4qNs15E47IsfPn8XDw3YSJ8aT5BNpMKABN3Q+nBqzT29fbGsxFR2PrCywaMTwlK/J2hYHcfymDSAdhc9hMu9lx7qnKo32DMo8PS7jmLcGZJJt5PSMKkkaOE5iAdgL86O4ypSnuqjgwIxNKpcTiUshSVry1HZmwCxt8cZO9jbt8vHQCm0PrSH50SKixoBLIenonqN1bg4PxUpE6ORcgQf6fqMKuwVJehNhGKf/0F1c1NCA0Ktm1y+HXybaPBfnLo8GStrcbn5aXYRpP/bbQIgIdJmQFsIdOGI85lQV9xvSwWJI4Lx+anZhsn77773fVeSgBMnP87GTsr3mAfH2c/4rLy0gJoOt+B7RXlLhOCV0XSAmCCZX5biILqn3lp5xK/UgOopBPxE1tyEb0+G1vKj6CHxolkM6kB2MQua/wds/PzEP7RarpEPYALEq0p9QgANhA1Lc14dedWjPnwXeysZs/HE988CgCTe/jgIXg77lE8Nn6C+OpThFJ+EbuWst40Qvp6zAOG+MNoTEgW8wgAiWPD8EHi04gIlm8ltdQAxtHgGhvxTAq/W5YO3y9OKQH4+wzCytgZWDolDmw+YKDWq/O7fB149ANtvROfZ1MsyRMnYU38k2DDza6w/adPYfGu7a6o6rrqkAZAzMjbsW7mM5g66o7ramjfD9X/3YJ069c0wX+07y63vhceAOvpm2iace49MfS864FPM3Z1X8LaH4qx+vs9OE9/8zbhAbA5XlcIz4TeSrfBpu3+CnXU+0Ux4QG4QvxjjQ1IpeM8W1UhmgkPYCCCNdOQdcbeQmN8qIduCBfRPBJAd28PPjl8AJkkfovgd957HABrbZVxuDnR1Chih+8Xk8cAOEUjoWlFO5BfKdcsGbfR0Je25aHu3Nl+PcLZDR20mmHlngJEfrxGOvFZW7k9rIM59/PyxpIpD+GtB+MR6OQiW/aUFfZQj+X0ZUrmldJcATAIzIJvGoIsGsNfeO80sOUi9uxQQz0WF+bjwG919ooKv18IADaVIoaPQPaMJDweGmHbdNVrY3sbVhQXYNPREvqPUJ5hQgGwSTqDlp6zlWtRIbcam9hi3HUl32HVviK0clrBZovN1a9CAmCNZMvL50XHIIEmWzL37kLV2SZXt12I+oQFIIQ6bgjC/hnPDUHcyC4UAM70FQAFgLMCnN2rDFAAOCvA2b3KAAWAswKc3asMUAA4K8DZvcoABYCzApzdqwxQADgrwNm9ygDuADStjXMMN6570t5Ck6ty3E7oiZhIe3YIyvXEtknSplwNuq5hVVoRoMdLErSHhKlZkZGdQHPfmg4/SzKt0bJ6SMskaAZpzTQn7f+95eRyJiyg6FNoQUIkZUaABC2RJ0R2sXP5fJtLPX+j0fEp+n8Aqe+mBAmGWdQAAAAASUVORK5CYII= + + + + + + + + + + + +http://www.bing.com + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/en/default.txt new file mode 100644 index 0000000000..b3259247ac --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/default.txt @@ -0,0 +1 @@ +Google diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/duckduckgo.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/duckduckgo.xml new file mode 100644 index 0000000000..464cb0fdf3 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/duckduckgo.xml @@ -0,0 +1,23 @@ + + + +DuckDuckGo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAGKVJREFUeAHtXQm4HFWV/qv37e15W/KSvCwQSUIgJIEIArIIRD4UFDWCKBDCMIJsH6g4KKB+CjIKOmjAIaAQMjIwH8oMMCiKAoFIFoFsQHaSvLyt3+t+3a/79T7nVKf63a7XXV1V3R1CJuf7uuvWXc6995yqu5xz7ikJByCTyUi7L5m/JJPBkgwwm6J9StqRawUoIEkhKZPZJElYPnnl2uWSJBGZAYn/dl6+oC0TyzyOTOZsvj8CVaaAJL0kOaXLpvxmTbeFn/wjxK8ywdXo6UFnmjPtpV1fnndVOoN/V+c5cl99ClgkLLXQQHRV9as6UkMhCvB8S0MQZhVKPBJXfQrwYsdC1RxZ7VSf1sVq8NmKpRxS8VYb7C0TYGvtgMXjg8XlgUQ/i9OFdGwEmZEI0vyLhJHs2YtE7z4glTykulCsMYckAxyTj4Zr1gK4PjYXjo4psBHxJWKCXsgQ8ZPEhPjenRh59x8Y2bQG8d3v6y1+UPNJOxbPkzcEB7VWdWUWK9zHfRy+Uz8N9+wTYa2pV+co+z4VCiC68U2EX30e0bffANKpsnFWAsGHygD7+E7UnH0xfKecC2ttQyX6owtHamgQ4VUvIvTS00h07dJVplqZPhQGODpnoP6zV8Bz4pmQLLwOKA7JgT6ZSIn9u+VraihA4/0wMlEa8+MjsDhckNw0H7i8xMR6MFPt7ZPlq62xuThiSsmk04i8+RcE/vAo4rve08xbrcSDygBbSweavnozPPNOK9qfVMCPyIbVGNm4BtFNa5HydxfNWyrB2tQG96z5cM1eAM+xC2GtbypaJLLuFfgf+xnNHXuL5qlGwkFhgGR3oO4zl9NTfzk4rAZ+kiNr/4bwK88h+s5qfjTVWcq/lyxwz1kI32nnwzP/dPnNUSPNJOL0NvwGwWd/Aw4fDKg6A5zTZ6P5uh/CTktINfDEOPTC7zD04u/kJaQ6vVr3vJStPXcxahctLjjhJ2gp2/fA7Yht21itJuTwVpUBted/BY2Lr4Nky19C8no98MxyDP3paWRi0VxjDnZAcrpR+6mLUXfhlbB6a/KqzySTGPjdAxh6bkVefKVvqsIAye1FCz31nhNOHdNeXgb6n7gf6eDAmLQPK8JS14jGS29Azannj2kCzw29v/wuTfrDY9IqEVFxBnBn2r79b3DSSkeEJE2mfb+6EyOb14rRh1TYdcw8NH/9LtjGteW1K0YrpO67v1GVh6aiDOBVTtt3Hhgz3kfWv4a+ZXcgHQ7KHUt4ablIc4K7rl5e//MegEUK6aEBpOjNSHTtpqs/jwgH68birZWZoH57eV7o/tF1FV8lVYwBTPz2ux6GrX5cjlakcMDgk79EkFYWOSCdXGjC0QjNWIDOmcdi/Imn0RxhzyUrgfg+EiNsXofI+ldp5/o6rYwO7oa97oKvoeHLNH9RexVIBvqx/46rKsoE6w2zx9+pVGD2ysNO+/cegl14dVke07/sLoT+9NQYtM4hP2p2voPEnu1I0AbK23l0Xke5AL8Vzmkz4fvEIvp9GqANW3zvDiCZGIOvGhGx999GonsPzWP0gBzYLLIQ0HPCJxB+448VWzyU/QbwhNv+vV/njfk8nPTe983sk1uAOqlp9ORfvJTW5SdR56wFchSOSg72w//I3bRn+GvhDFWI5b1Dy83/KkteFfQ8J+z//tUVmZjLfgNab/oJ3MecoLQN/OT3/uzWosRPeOoQOedSpEkMMLBzKwL0i+7bjVhvF0BLUpuvliSfhZliIZGD7+RzYJ/Qiehbqw6KyJnF2/Edm+H9+Dm5N4GHWUfHNAy//mKu32YDZb0BvM5v+sqNubp5zO9fdidJHJ/LxakDCV8DIuMmwpKMQSImZGiPkLHakXR6kKTJOeWtQ01LG9omTUbjrBNgpU1TIYhuWY+ee66noWCkUHLF47ynnIfma3+QN1T6V9xf9j7B9BvAO1xe6yvjI/c48NSDtKt9UrPzVhI7uAI94HnAERqAM9gPJ927+/fCu38b6sN+1FlSsJGyBSRoczS1FsRnb26XRdcZmhOSg33IEN5qQmLPNqojDvexJ+Wqcc+cjyjJrVIDvbk4owFTbwDLcybc+595y83IW6/LT6TRBnB+C8n/a8/+PLynLIKDhhejwFJNHiZ4Zy2/fVVcMbXeel/eBpOXp/tu/aJp2ZGpN6D+oiXwnnhGjk4sMu7+8XWGn8KMzQEvDWPtNMl5SCHD4mQzwEtFW2MLvAs+SU/oQnl+YDVlNYCVOb6Tz5VVo4zfSnNWJpXCyJZ1pqrTFsYXQMnrfZZqitD/4F1Ik2DNCMQa2zHu5nvResk3SJbvNlJUM6/r6Dnyqow3VNWA9PAQ7ejvyEPN9GC6mAHDDGB5vihSHl79kjwOGql8pGk8Wpd8C7VzTzFSTHdee/sktN7yU3o884WAuhGUyMhPe0hYaDA9mC5mwBADWJMlKlPYEsH/GHXUAKRpYrWedykaaENTTWCFPg+V1YKBJ36O1HAoh57pwvQxCoYYwGpEEYLPPoYUrUCMQM/8RZiy8HQjRUzn5fY6Jh1lurxWQZbmBn//SF4WNX3yEovc6GYA61pZh6sAy/RZkWIEEjWN8B01K09kYaS8nry7tu7Fk4+/gueefh3DwzE0XfFNPcVM5eFVFyuVFGD6MJ2MgG4GsPWCuObnypkJRmDgYwvRWl83pkigqxsvrPwznnz4RWxY9faYdL0Rr//5LSxbsQG7Pgjg3fd68d0fvIjtYbds8qIXh5F8rExijZ4CTB+mkxHQN0uRvIZNRxRgbVHwhZXKre4rS0FrWtrz8r+w4o94em0U8ydaMWd6LQZ7A9j29lZMP8740DGxzYt77lqUwy9LYz/YA+8XrsnaAuVSKhfgUaDuwstzOmam08CK+3TbHeliABtNiXY7LB42qtHi4Yd/dsEyYeeq1Xh1lwX33nISGjvylSBmSDRxVj7TeH/QOHmSjMoxbRbi2zeZQatZhkeByJq/0gN6npyP6cT0iv7jNc1ySqKuIYgt1kRgtaJRiNVlbXSsHm+uaG8wgRsvm10R4ueQFgmw7rdaoKaHml5a9epigCj/kDm+/hUtnAXTEiRkYxBtPOeePg8tk8t/8gtWqIr0LvxU3v5FlVzWLZvSsD2TAiK9lLhi15IMYENZq2904oySlsqMzUzKkd3t8t5BAYfXowQrfn35qf/Br+95GJvXbZRxsyU1G/xWBciOiY3JFGB6Md30QEkGqBttVqlOJwTl9qRKWBf09QXAv3Lgvtt+hhue2Irla4aw7rX1ePn5V2V0aj1vOXWoy7IlnwhquolpYrg0A46ZK+YnU2+TVg0HrJFjg6Ovqog4EU/in6/5Kc5a+qj8u+kb94HjjEI6HsN/vZu1aqtzWTFzajOeeCb7dDqPOtYoOt352YxSBJeKbmKaGC7JAMeEKbn86ZEo4h9szd0bCdiHsxYRI8HBgsUeuf9xrOrONuc7ZzfjjuvPw6M/f7xgXq1INgJzS1nGdYfTuGL5u3A7sho2uS8GVKBa9ajT2IaVpcIKiHRT4gpdtRlAwiw+HKFAovsDJWj4ag9nCR8eHi5Ydsv2nlz8slX9uOX+l7B522hcLrFEgHXMNy6aAjuy9v/1ljiuu+Z8uRQLzcT+lEBlOFk0dZfr0SEM1NwH8LEgcdWS2G+eAc5QdugJxBIFOzajoxZ/6YnJaYPRDN7cl8S1C8zpB85feinmn7UL29/biTmnzIevtiZXJ+uVdQNbpPAvra8Em9C7yRKbgenG9OM4LdBkAJ/JEiFZxhtgIZWhfTgA/4HlqIiXw0tu+ireuvaneCOYleOfXB/CFTf+kzqb7vvWqZ3gnxokksZqgdWXhPeYIXiPDcLRSmpOYkA6YkOsy43w22RQ8N4oM9V4xDeA05h+ZTGArYhFEAVPYrzesMvfhRAp3uP93XAINkRc3uHz4cFHv4uud96ROz3+2Dl5sie9dZTKxwqVPCACO8ePwD0lBNe0YTgnjDUWtniScE8Pyb+elZMwsmt0Myni4sMjIqjpJ6YpYc03gA2RROBJuBxwDexHaNJMRLr3jmEA42Vh1oTjjy+nCs2yGVqJ8TzmaCHDgM4IXJOH4ZoUheTUd14sGXAg3ussWgef3BFBTT8xTQlrMoCNrkQoV8/qHiDbH4KhwCDMje5ia3SE00SQFM098Z1AdD1S3c9j4vWbSQWqj+C5GlJkTvlWPQJ/a6bjUdkVVS5NCPCxKRHU9BPTlLAmAyyOfG5naI1dDjj798nFByIxZEVk5WBTlSUCZwYfByK05k/sJcIHyZw0n9Dykk97CshDmolbEHq7HqE3G5EM2vPSCt3wSR8R1PQT05SwJgN4UyOCxLY6ZYAtFoEtHEC/SeuHglXHyV6n+3vIBP9QMNlMZLzbhfBbDQhvJIsHYoJe4AODIrCJZinQZID6UIKeMa1UhR4ahoZ8hSfiUmXHpPsfQGb/7fSkF17ajsmvEZEetiG8qRbDG+vADDADfFpTBD1DtiYDRMEZI9YzpokNKBTmldAQTcTh/XvQqFoJFcpfLC7TfRsyfb8olqwrPhOzILK1BsNE+OhOWvHpXO8XQ85HZUVQ009MU8LaDFCpHEWljILA6NVFJogMPBE3Gi2s5B96VpP4PF4n+lywuJOw1SToIB6JJnhDRcArmZEPPPJ6PrqDCEYTbKVAbVimR2WryQC2DBbBPn6yeGsqrKyEBqIJdJrCQGc1wi8XLRnd4UPvUxOJsEIWorGFlpppHs/TlSO4UIMcVCvk1fRT5+d7zRmGvY6wubkC9vZOJWj6yjtiBxnm9qcs8kl1U4gs+RtEEUdwFR3GFonPiSQJl5ePVSQ+V8Mn9BVgusleW5SIIldNBrDLF/Y6ooB81rcC0kSXfx+SpB+I94ziVurQc5XqPls0m3CiqGieaiWIb4BMN+HhLVanNgOoFJ/VUoBFvXxsqFxwEwMYwiYZAPd8SHWfKdiM+jN6aWdrfjaV7BnaHUdQc0IAdQv9ZPSr78Q8n6wUfVOwqxw9oDkHMIKRLf+Ad/4nc7hY0xPbuiF3bybgOrAhCwSCoAHDFEgdD9GMSucCht/IK8+ynAlLdyC4ugmRd2uQCmt0kaYDOxGYRROOjihcHZGsAE54LB3tUfQ9ky+UzKvwwI1aA8Z+ivSARuuyxdnZkQhuYoDaJE9M1xN2D3bTuJxGfyyDaXoKFMpjIalp5/MI/Gomaub2kdnM6FxlrU2g8Zxu+ZcaohXRgIOOwfKcQxSn+cDqSckrI1tdnE5oUkQR4GVqcPW4Iqn50UwXEdR0E9PEcEkGsKepFJ3vVRTzrhnH0X7ARwfUwiIeQ2EpGadTMn0YaGyTFfyitbURRKlBss9cVY/g6/VwTw3DO3sIHpJaikMQM4N/RiHyvg+Df2rTJYIgKaLsCESpg6XGej10lWQAI41u+Dt8dEiNgYnlXXg2wi//Xr43++fy78VIQyuiXbvhmXyUKTQ58S89xNHtPvkHcsTp7iQp51T6TaQhpS0r09dTQcLvoP0B7YZpY5boy5eDaZWXDdfoqK4CTC+9oIsBbHikMIAR15DLl3IZ4KZ5IDB9HkK93aYZUPCIKw0zvBfgH4PkSGcZ0UHjfGMMtoYE7QlouKJxPj1sRWLQKYseeFNmhOgy8gN/7AJHhPBrL4i3mmFdDOBjOezmS9kJO2ccL2t79Gw0itXOS1GGwFAIrcUylYiXVNLaQtlZmJZ7OwplKDPOQl5WPPNOz2FhOsk+6XIx2gFhvtfISIoM9rGmANtc1l3wVeXW1NU52AMplUBfovgkWAqxtcgJylLlKplee95iMswdHa5kOhlwCKiPAdRidnDHpxEVqDn9AlgbmpVbw1eJVkGugW4M0ZCRUsmc9CLjjpfTBr31FMvHvktrz/tyLpnpw3QyAroZwApndnCnADvYYIcW5YCyIYvo3LQUqsvMsaBCeMzE1Z7zRfmUpFKW6aNWzCtpxa66GcAI2LugCGxxbBcMt8Q0PWFX314521B/r57sBfPwqcgPA6zkrkB9WlRNHz3tMsQAdu3IHqQUYNFE05XfUm4NX90D2Yl4MJyvSzWCyCX4qdBTrqvFjhGHoW4XRNt42U25s8KcgelixvWl4Zawa0fROpqP68vuZAo2UzuSpaIWOubTmzTcjBxi51FzyB1l6d3q5qlOPPSFevz2M7V4bV7WUjuHxGDARe4K+LC2Aqy6ZbqYAcM9Z7+a7NpRBD4IZ/agMusHRkhbkvDnmyHuCr2Pn6y7Gcs33YO/d/8FsVRhkxg2ZREPD4rt4rC/3ooVF9ThD2f6MFCXtWjYNsmhzqb7nt0qNF9zZ17+4LO/Ne3EyTADuGb2q8k+EhRgA6SWG35s6mC0q2+PjCbc9YGCTr5uD2zCNvox8ZkJt7y6GI9tuQ97wzvy8vEN78xT9DmKIS/JbmqscjhDYp/Vc9x45KJ67GnN3+4M1liQtFIGE8AuOEWpJ9OB6WEW8lumEwsPQexXs/2Oh3MuKZ1Tj0HT126RHSrpRCNnU1ZCwQE/GoSCKZVJSSw1gte6/lf+zWw8AYs6F6PDNw0rNi/DlsG1iFw5Kgpo7U/CQZvdPW3FuxckJjQF1JoboQEFgvWfvxoecuCkAB9WZDqIQ7KSpvdavIUlMLBTU/arKfoL4lVRkly3GJGWekhJz+CPxNEph7J/fMKxGGweWI+1+9chRrvchpqx+XrGle5WxEUMGKM6K1YjfeXijAvRcPHVeRm4/+U6dzU1BCmtYKem4qqI4xu/9HW5sUqeUldrNAR7JAh/hhw3CRokm0WbiENk9CaVYcYQc+gfgjykDxl31W15XeF+V8Kpa1kM4BaxU1P2oSYCN5afGL3gpv0AS/Njgvm73aI9UfIbQlJg08BzhB7wLDgDLdf/iOrKTuBchvvL/a4ElNGFbPVsvMVOTcVJmRvbfPXtqFP5lijWYEUwF+7ODkecz2XTsVQcO/oUq2JMvHJmbUyCEFFDTqRabrwn73Ql95P7qzZaE4oZCpbNAK6ND23LTk3Jr6YIjYuvpY3at0uujlg0zTAYCOSKu21ZcXIuQhXgKYK+f2YanFqqXnq1Gr50LcYtuU222FYqYb+h3E+jh9SV8oWuFWEAI+b9ATs1Fd8EjueJefz3H9U8GiS/AUTR/vjoqqTWIa6JGFM+sPVDmE7SiOf4UiQrjJCa87Q3Izjr7xG0+EfVlPmlaVIdHhUsimnWhnFou30Z6i+8QoyW+1Vpp61cQcUYwMiYCV13XDlmTuAl6oQfPwEvOWEtBBZSUTqDfRikiTh94Bhro6ulUFY5jsXhx7XNRDIpYW9vGju6sr+RcDM+N/UanBmbgRM3RLHkmSCWPh3AqesiaPOPMtdFTGoIjd4rFXkWfBIT7v4PuGfOU6LkK4/53K9qfNzBlNO+vNYVuGEb0hZy8Sg6d1KyRcl5t3/53WOkhvtPvgiBaXNx2tGT4Zs+S85+0ysXYzgRUorK19lNC3DR9CswkfYA/qgfPeEe2Og8VrOnGQ2u7FvDFgn771qaV45veOnZ00SnKGMptPWPMoAP1DVdfis8cz8xtgytdqrpPd2U074xrVRHkCtJdmrKxqksKxLd3Nibx6PmrM/JnhL5yKtiQZx01yDcMQONtOGqmThVxrhz6F10D++Bhcbk45o/jq/NvJk2YF9CnSO76fLYPWj2NqPJ3QS3MGnbxrXT+nyD/E0xsWn2ZPbJ90Wyk4eFHGvUf26p7Kzb0ZGtU8kvfz9g5S8w8Nt76dU2rtRX8JS6VuUNECvV+oIG+/wM/fVZBP/7cYSTaew8/xp0WhOYeW7W8q1/pBtbBzfgGNr51juNWRDFdmxB179cJjYlF2YjKnY6W3PmhTk3M7lECvA8dlh8QUPpFFtSaH1Dhtf0PGxsi5E8p6cLp5ybr+RW8Bi99pAL5cial+Vi/LUM70lnyd8qc6neSgUvixQOu2/IKJ3jKx/bbLpM+ytKaSICf0cAtJewkqmHuAEScekJ85McIvMZHgadHzu+4NOu4OGd7WH7FSWlk8rVyHfE2CkqHy3lp5PHZclqoY2Rk4yv6PthdJXjE7HslZXhNLxLDodsSCYeMlfqFq//774jJnaew2xNfORLeofatyRJ26SYQaoZVs49m1eyxRobmR35lmQJSua+pkouX9jrCK/TSw0nIkqWqspfU+XPoJB195GvqYrUMRM+4Pgi73vCtNljuyDWx7JgjPccfCaLrfWOfE/YDJG1ytATzU4vSjm+0EJxqKZVVBZ0qHbyUG4XM8C8of+h3LOPQtskKWQhweKmj0JbD8c2klJoExlz4OHDsXMfhT7Rw7+cmJCRdl6ygL5Mljn7o9Dow6aNkvTSlJVrzqEhSMpITuky+j7TS4dN5w71jhCtmeYy7ZW28puw+5L5S0iUchUJJ1kjoq2UVQoeueqlQJiG+4087ExeuXY5E58L/h92t1mNYWFeRQAAAABJRU5ErkJggg== + + + + + + + + + + + + + +https://duckduckgo.com + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/google-2018.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/google-2018.xml new file mode 100644 index 0000000000..82f70f41f4 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/google-2018.xml @@ -0,0 +1,17 @@ + + + +Google +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAHqklEQVR4Ae2dVXgbSRaFe5lelnnfluFlmCnMzMzMzMwMCjPMKOsxM7MVh5kTc0AMJePDWd+dT172WupuVXVc+b4zwZF0/9N1763qVpUS+AHgSzU1NWOrq6vPN8rr9/shihhj6v8fziKmxJYYE2sACon+Q/pp419mGAi4oQ0h1sQ8YMCXeMMnOPzfk4sJX1Iah8Q4AYNvFYZQOlIoL/EPtHWaQOwVfgVXitgrrfVqFyUGRcLnG4uix4cVH744cSl8A5NSZLrhG7Mi4fONXZHwuZjAvwZIiW+ANECmHf3ZKKLDZ3YbvJZ8uE8cgmP5PDhmjoN9zADY+nWCtdN7sLZ/C7Yen8A2oDMc4weD/o3rwE54kuPAykuFN0EREb7v3h249u+EfXR/WNu+AWub10OWbXB3OLeuhfeihb8JItcAZrXCE3EW9olDCZwuolFCI4lZX8gi3CS3C+4zx2Dr2YYghUddPoDLtI1M528At9TDGDyxn9NVSVC4yNa7HdxRZq6piIsBvopyOGZNIAhCyLloBqUl/gaEA74nJwO2Xm0pcKFkG9IDvlvXw26CEk74LtN2ClZYUVvriY/SwwTORZgxuDavpiDFV8d34Htw7yXqgnw+ONcsNgx8b17Wy9WGOlfOl/B5GeA6fkDCD9YArYovBRRYRtBatu4fwz6sF+xTR8E+ZSR1MLB1/VBc+M2wVfSAzx4/ogUyzYBT2+ratAqepFiaQ/zv933xHJ60RLg2roCtX0chr3xirHsKcsyeqAl4+8h+X8xUXc6Qir8nLpJGBwf4HGuANz1Jg7Wa9+H+7CT8WoxInxeeyM+ox+cPX3cDnE7YBnZRBZ9yOit9onmgNMu1DekuFHySomX+98TtVwXfsWwOrY7qFizVCN+lYqHunGk3Anx2NOT8BP7orrC2C777cW1cqSblyJvytU9MaMj4Gkh12W/APuSjFsOnok25Wt6UV6H6or8Q/CbV5/wK7iX/vx7YhvZUuxQsDaixFhL0/1Tmt8FO9GjWAG9RXmt9gkI7A2rvLyXg/1O1qZ/A2uOd/4DvXLVQPhekSfqxvEqgm1Vdzh/gnNL+Hwa0exOstEQaoPpFXI8JcMuU9T14dnyRkhxLZ9P/Lw1Q2/9XV0YT3KBUHdsF3vMFkE/SMfUjoPbBWoIanHJ+BL9fm55/zCHGRXfLtTGBviWp6gXqrg0K2oC6yz00u4o+Wce4KP26IDWgzvJG0AbUPtpieANO5zExDKgv+H3wNaAyyvAGbE8QxICG3J8HbUDNi3zDG7Au2i+IAZnfCX4EOO8Y3oBlf+U6AqQB889yHQEyBS38TBZhrgasiuRqgGxDN8VxTUFyIrYvlb8BHJci+BsQVWzgxbhjueNQWH5RkwBMqerVfVvwBlju8VqMU7Ec7c76MWanT8dr5j6YlbNeiBXJ5w4/2q4P3oDS5wa7IXM353X0jBsHgk9641w/lNjLuRuQdDn4NNZnp3bvH5ZbkvG5A/FuxKAA/CYtyN/K3YAlZn6zYJISyEV63JSvyfgONmRNI9j/U3llF7jBv1ESWgE+V6RN/tf1sZTK7N9geNIUgtysesRPxgu3jYsB8z8NrYt68kzEB7NKTE3wi/I6om3UCALcIk3IWA4v84UVftzF0K7+SUe1Sz+6PJp4KHc8FVgCG5RWFO0G87OwwL/y2I8OG0MzwFwo8MO5EbfOEsyQNSd3A1w+t67wr5f8vYsJCX7nzYzaVjEfziU5vS50jh2vyoSRqQvxRKf2NPWqH502hT773ZVsgG0rkx7lEkhVei9iME7cjNIsJVU6n2GtZT9Gny0OGX77DQzlVoN8S5KKKoFUq76J02G+k0AjK6TPUeKogOnqGXzw+RB6Pbxu7ouJcZ+FZIBJo8W3sHxJ76GtFB9HDtfEBFKbqBFYadmDuAcZKHdUNZsCiyuv0eihi4CA/9fXG5awBl23W1sMf8BuBodb1y/paW9CVoklAEBzfRQ5DD3jJ2Nk2kKMTluM/kkz0DFmLN4MovvqEjMRQ47eaZEB2bf0/5qqLjpw7TMKVljR8siEyJTmC28SM/ZWBfPzNgttAmlc4l502OT+D/hTjjP4mN/YBviYD4sLtgtvQt/4uehjKmuCP3w/Q5XtJdkzjtrJVZa9wpvwceQIjP7UgiEmhgrtW07+GzZtu3RMeBOGp85HmdXNa8Mm/U3IeFKINlEjhYS/sfggvMyrP3zem/ZRLz8+Y5kw4D+MHIaUx3mtZ9fEQF2IuJuMzjHjuMKfnLWSJo58t63kKVr9PHojAp9EjQgr+BnZa3G56pbcOTcgq9uGM7djMTRlrm7QaWZO85Kbz+7xj1nkzbvvvHiIHZeO0xIDQVM926U0Y76biArnU/E37xZt+3qbx4H8sos4eM2MubmbMDZ9SaMxM2nth+DizXP9qYiiQ/QYMgzTs9dgffEBnL0dh6tVt+lWp/jb14tugjzAQUqeISMNEDAdyWOs5EFu8ihDrvBlDZBFWB5nKw90lgc6yyPNVYjjof5SxJ4MOG/8K8qYn43YKzU1NWOFDLQVfCZirwD4UqMTGfyDb10XATEn9mQA6adhM0EqAP+nxJ7gB/QlGhKUl0QrzIwxw6c5YkpsiTGxDnD/GwMDxywT49owAAAAAElFTkSuQmCC + + + + + + + +https://www.google.com + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/google-nocodes.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/google-nocodes.xml new file mode 100644 index 0000000000..7ed636ae91 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/google-nocodes.xml @@ -0,0 +1,16 @@ + + + +Google +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAHqklEQVR4Ae2dVXgbSRaFe5lelnnfluFlmCnMzMzMzMwMCjPMKOsxM7MVh5kTc0AMJePDWd+dT172WupuVXVc+b4zwZF0/9N1763qVpUS+AHgSzU1NWOrq6vPN8rr9/shihhj6v8fziKmxJYYE2sACon+Q/pp419mGAi4oQ0h1sQ8YMCXeMMnOPzfk4sJX1Iah8Q4AYNvFYZQOlIoL/EPtHWaQOwVfgVXitgrrfVqFyUGRcLnG4uix4cVH744cSl8A5NSZLrhG7Mi4fONXZHwuZjAvwZIiW+ANECmHf3ZKKLDZ3YbvJZ8uE8cgmP5PDhmjoN9zADY+nWCtdN7sLZ/C7Yen8A2oDMc4weD/o3rwE54kuPAykuFN0EREb7v3h249u+EfXR/WNu+AWub10OWbXB3OLeuhfeihb8JItcAZrXCE3EW9olDCZwuolFCI4lZX8gi3CS3C+4zx2Dr2YYghUddPoDLtI1M528At9TDGDyxn9NVSVC4yNa7HdxRZq6piIsBvopyOGZNIAhCyLloBqUl/gaEA74nJwO2Xm0pcKFkG9IDvlvXw26CEk74LtN2ClZYUVvriY/SwwTORZgxuDavpiDFV8d34Htw7yXqgnw+ONcsNgx8b17Wy9WGOlfOl/B5GeA6fkDCD9YArYovBRRYRtBatu4fwz6sF+xTR8E+ZSR1MLB1/VBc+M2wVfSAzx4/ogUyzYBT2+ratAqepFiaQ/zv933xHJ60RLg2roCtX0chr3xirHsKcsyeqAl4+8h+X8xUXc6Qir8nLpJGBwf4HGuANz1Jg7Wa9+H+7CT8WoxInxeeyM+ox+cPX3cDnE7YBnZRBZ9yOit9onmgNMu1DekuFHySomX+98TtVwXfsWwOrY7qFizVCN+lYqHunGk3Anx2NOT8BP7orrC2C777cW1cqSblyJvytU9MaMj4Gkh12W/APuSjFsOnok25Wt6UV6H6or8Q/CbV5/wK7iX/vx7YhvZUuxQsDaixFhL0/1Tmt8FO9GjWAG9RXmt9gkI7A2rvLyXg/1O1qZ/A2uOd/4DvXLVQPhekSfqxvEqgm1Vdzh/gnNL+Hwa0exOstEQaoPpFXI8JcMuU9T14dnyRkhxLZ9P/Lw1Q2/9XV0YT3KBUHdsF3vMFkE/SMfUjoPbBWoIanHJ+BL9fm55/zCHGRXfLtTGBviWp6gXqrg0K2oC6yz00u4o+Wce4KP26IDWgzvJG0AbUPtpieANO5zExDKgv+H3wNaAyyvAGbE8QxICG3J8HbUDNi3zDG7Au2i+IAZnfCX4EOO8Y3oBlf+U6AqQB889yHQEyBS38TBZhrgasiuRqgGxDN8VxTUFyIrYvlb8BHJci+BsQVWzgxbhjueNQWH5RkwBMqerVfVvwBlju8VqMU7Ec7c76MWanT8dr5j6YlbNeiBXJ5w4/2q4P3oDS5wa7IXM353X0jBsHgk9641w/lNjLuRuQdDn4NNZnp3bvH5ZbkvG5A/FuxKAA/CYtyN/K3YAlZn6zYJISyEV63JSvyfgONmRNI9j/U3llF7jBv1ESWgE+V6RN/tf1sZTK7N9geNIUgtysesRPxgu3jYsB8z8NrYt68kzEB7NKTE3wi/I6om3UCALcIk3IWA4v84UVftzF0K7+SUe1Sz+6PJp4KHc8FVgCG5RWFO0G87OwwL/y2I8OG0MzwFwo8MO5EbfOEsyQNSd3A1w+t67wr5f8vYsJCX7nzYzaVjEfziU5vS50jh2vyoSRqQvxRKf2NPWqH502hT773ZVsgG0rkx7lEkhVei9iME7cjNIsJVU6n2GtZT9Gny0OGX77DQzlVoN8S5KKKoFUq76J02G+k0AjK6TPUeKogOnqGXzw+RB6Pbxu7ouJcZ+FZIBJo8W3sHxJ76GtFB9HDtfEBFKbqBFYadmDuAcZKHdUNZsCiyuv0eihi4CA/9fXG5awBl23W1sMf8BuBodb1y/paW9CVoklAEBzfRQ5DD3jJ2Nk2kKMTluM/kkz0DFmLN4MovvqEjMRQ47eaZEB2bf0/5qqLjpw7TMKVljR8siEyJTmC28SM/ZWBfPzNgttAmlc4l502OT+D/hTjjP4mN/YBviYD4sLtgtvQt/4uehjKmuCP3w/Q5XtJdkzjtrJVZa9wpvwceQIjP7UgiEmhgrtW07+GzZtu3RMeBOGp85HmdXNa8Mm/U3IeFKINlEjhYS/sfggvMyrP3zem/ZRLz8+Y5kw4D+MHIaUx3mtZ9fEQF2IuJuMzjHjuMKfnLWSJo58t63kKVr9PHojAp9EjQgr+BnZa3G56pbcOTcgq9uGM7djMTRlrm7QaWZO85Kbz+7xj1nkzbvvvHiIHZeO0xIDQVM926U0Y76biArnU/E37xZt+3qbx4H8sos4eM2MubmbMDZ9SaMxM2nth+DizXP9qYiiQ/QYMgzTs9dgffEBnL0dh6tVt+lWp/jb14tugjzAQUqeISMNEDAdyWOs5EFu8ihDrvBlDZBFWB5nKw90lgc6yyPNVYjjof5SxJ4MOG/8K8qYn43YKzU1NWOFDLQVfCZirwD4UqMTGfyDb10XATEn9mQA6adhM0EqAP+nxJ7gB/QlGhKUl0QrzIwxw6c5YkpsiTGxDnD/GwMDxywT49owAAAAAElFTkSuQmCC + + + + + + +https://www.google.com + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/google.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/google.xml new file mode 100644 index 0000000000..2a264c27cb --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/google.xml @@ -0,0 +1,17 @@ + + + +Google +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAHqklEQVR4Ae2dVXgbSRaFe5lelnnfluFlmCnMzMzMzMwMCjPMKOsxM7MVh5kTc0AMJePDWd+dT172WupuVXVc+b4zwZF0/9N1763qVpUS+AHgSzU1NWOrq6vPN8rr9/shihhj6v8fziKmxJYYE2sACon+Q/pp419mGAi4oQ0h1sQ8YMCXeMMnOPzfk4sJX1Iah8Q4AYNvFYZQOlIoL/EPtHWaQOwVfgVXitgrrfVqFyUGRcLnG4uix4cVH744cSl8A5NSZLrhG7Mi4fONXZHwuZjAvwZIiW+ANECmHf3ZKKLDZ3YbvJZ8uE8cgmP5PDhmjoN9zADY+nWCtdN7sLZ/C7Yen8A2oDMc4weD/o3rwE54kuPAykuFN0EREb7v3h249u+EfXR/WNu+AWub10OWbXB3OLeuhfeihb8JItcAZrXCE3EW9olDCZwuolFCI4lZX8gi3CS3C+4zx2Dr2YYghUddPoDLtI1M528At9TDGDyxn9NVSVC4yNa7HdxRZq6piIsBvopyOGZNIAhCyLloBqUl/gaEA74nJwO2Xm0pcKFkG9IDvlvXw26CEk74LtN2ClZYUVvriY/SwwTORZgxuDavpiDFV8d34Htw7yXqgnw+ONcsNgx8b17Wy9WGOlfOl/B5GeA6fkDCD9YArYovBRRYRtBatu4fwz6sF+xTR8E+ZSR1MLB1/VBc+M2wVfSAzx4/ogUyzYBT2+ratAqepFiaQ/zv933xHJ60RLg2roCtX0chr3xirHsKcsyeqAl4+8h+X8xUXc6Qir8nLpJGBwf4HGuANz1Jg7Wa9+H+7CT8WoxInxeeyM+ox+cPX3cDnE7YBnZRBZ9yOit9onmgNMu1DekuFHySomX+98TtVwXfsWwOrY7qFizVCN+lYqHunGk3Anx2NOT8BP7orrC2C777cW1cqSblyJvytU9MaMj4Gkh12W/APuSjFsOnok25Wt6UV6H6or8Q/CbV5/wK7iX/vx7YhvZUuxQsDaixFhL0/1Tmt8FO9GjWAG9RXmt9gkI7A2rvLyXg/1O1qZ/A2uOd/4DvXLVQPhekSfqxvEqgm1Vdzh/gnNL+Hwa0exOstEQaoPpFXI8JcMuU9T14dnyRkhxLZ9P/Lw1Q2/9XV0YT3KBUHdsF3vMFkE/SMfUjoPbBWoIanHJ+BL9fm55/zCHGRXfLtTGBviWp6gXqrg0K2oC6yz00u4o+Wce4KP26IDWgzvJG0AbUPtpieANO5zExDKgv+H3wNaAyyvAGbE8QxICG3J8HbUDNi3zDG7Au2i+IAZnfCX4EOO8Y3oBlf+U6AqQB889yHQEyBS38TBZhrgasiuRqgGxDN8VxTUFyIrYvlb8BHJci+BsQVWzgxbhjueNQWH5RkwBMqerVfVvwBlju8VqMU7Ec7c76MWanT8dr5j6YlbNeiBXJ5w4/2q4P3oDS5wa7IXM353X0jBsHgk9641w/lNjLuRuQdDn4NNZnp3bvH5ZbkvG5A/FuxKAA/CYtyN/K3YAlZn6zYJISyEV63JSvyfgONmRNI9j/U3llF7jBv1ESWgE+V6RN/tf1sZTK7N9geNIUgtysesRPxgu3jYsB8z8NrYt68kzEB7NKTE3wi/I6om3UCALcIk3IWA4v84UVftzF0K7+SUe1Sz+6PJp4KHc8FVgCG5RWFO0G87OwwL/y2I8OG0MzwFwo8MO5EbfOEsyQNSd3A1w+t67wr5f8vYsJCX7nzYzaVjEfziU5vS50jh2vyoSRqQvxRKf2NPWqH502hT773ZVsgG0rkx7lEkhVei9iME7cjNIsJVU6n2GtZT9Gny0OGX77DQzlVoN8S5KKKoFUq76J02G+k0AjK6TPUeKogOnqGXzw+RB6Pbxu7ouJcZ+FZIBJo8W3sHxJ76GtFB9HDtfEBFKbqBFYadmDuAcZKHdUNZsCiyuv0eihi4CA/9fXG5awBl23W1sMf8BuBodb1y/paW9CVoklAEBzfRQ5DD3jJ2Nk2kKMTluM/kkz0DFmLN4MovvqEjMRQ47eaZEB2bf0/5qqLjpw7TMKVljR8siEyJTmC28SM/ZWBfPzNgttAmlc4l502OT+D/hTjjP4mN/YBviYD4sLtgtvQt/4uehjKmuCP3w/Q5XtJdkzjtrJVZa9wpvwceQIjP7UgiEmhgrtW07+GzZtu3RMeBOGp85HmdXNa8Mm/U3IeFKINlEjhYS/sfggvMyrP3zem/ZRLz8+Y5kw4D+MHIaUx3mtZ9fEQF2IuJuMzjHjuMKfnLWSJo58t63kKVr9PHojAp9EjQgr+BnZa3G56pbcOTcgq9uGM7djMTRlrm7QaWZO85Kbz+7xj1nkzbvvvHiIHZeO0xIDQVM926U0Y76biArnU/E37xZt+3qbx4H8sos4eM2MubmbMDZ9SaMxM2nth+DizXP9qYiiQ/QYMgzTs9dgffEBnL0dh6tVt+lWp/jb14tugjzAQUqeISMNEDAdyWOs5EFu8ihDrvBlDZBFWB5nKw90lgc6yyPNVYjjof5SxJ4MOG/8K8qYn43YKzU1NWOFDLQVfCZirwD4UqMTGfyDb10XATEn9mQA6adhM0EqAP+nxJ7gB/QlGhKUl0QrzIwxw6c5YkpsiTGxDnD/GwMDxywT49owAAAAAElFTkSuQmCC + + + + + + + +https://www.google.com + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/en/list.txt new file mode 100644 index 0000000000..55b4d7effc --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/list.txt @@ -0,0 +1,9 @@ +amazondotcom +google:hidden +google-nocodes:hidden +google-2018 +twitter +wikipedia +yahoo +bing +duckduckgo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/qwant.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/qwant.xml new file mode 100644 index 0000000000..a80b2dbcac --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/qwant.xml @@ -0,0 +1,18 @@ + + + +Qwant +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAFjhJREFUeAHtXQmQHNV5/vqac+/VnjpWKwkQQsjIYIEpYzuhAmWEITgcRWETDFQlTpVjEoMPSJmAq+xylV0OFCZlBwwV21UBhxDkgCHkMmBsQAJiQCAt6EDS3vfc3dPd+f6e6dnZA7zS9uxsivlVvX3M6/f+9/3H+9/VUvA+lE6n17iueymT7FQUZSPPXbyvf59XPvA/EackQegnTu/w/DjvH4vFYkffCxhloR9SqVQ3n9/Blz/PjLSF0tSeLQ4BYmgTwweY+vZ4PN4/9615AiD4l/Cln/GlurmJa/cnjgAxTRDTz1IIu8pzUctv6HL+kgn/tQZ+OSrBXBPTesFWMC7PsWQBRc0X8EvPyhPWroNBgEIgxO4f+5bggS0+nz/s4w81txMMzu+bC7EWd7RZ2gTfBd1RA/99MQv0R2ItkeQdkqkioSbPh/iwFu0IIstEtAKbRa3XCbzE+TXwlwl4v5iiwl8qLmin/7B2XnYEdqo0Benh1qgKCAj2YgHS661RdRDoVumLaqFndcCHYO+HoVVioVZsTQBV1oGaAGoCqDICVS5er3L5iyzehqKMM+0wzyM8T0DV9kHXnoGV3wq45/BZExu1VXDcdp5bocBYZN7VTaZwIM6tLgsLl64I2Op+Av0qQd/HRINQ1SQ0VbymjCG6BN+Bocu1PHMlqkDSiiOV74KhbIKObdDcLfy1nb+vTFpRAnDdHLT8c9CsX0CxX4YeM4FYlHgbsDlaIiPlnrYQ6IVIRDFtGzAVDSFd9QRimTEKYxt09+M8tlN04YVerdqzlSEAN0/Qn4KW+ym19k3wD2zLheNQq0XbqfWuoVMOBC8UhqLRvXiWQNzKhCFiGTdDsMumNFRVQSikwHb4Y74HIfciGBSGoqwMQVRdAKr1MozsD6jfezwtzBN4wdzDUM5y490XtN5VeKNpFEbIE4iihSgM3vO5zSRjuVDBSrzcZv8xDFVehWNtQMi+kpaxY3aCKtxVTwBuBkbmH6DnfgJFt2CbPsBEwQO8eC4JwL8vnKFQNEznIUqLsJUQ0ogjq0SgyfvMrpAj08yhUEilddHQnD9A2P0c24imOSmW77YqAlDy7yKUuoMNKrU+R1fD+vpeo6T5Aq4AWRSAtLMCuIAq6XP8k84DSTYTCeaRtvisrgnhaASNdFf1IbYDdFPyDj3ZPJLnkagGJ9eFqP3nTMdoqgq07GGokn0VkcytjHD64Wbo4wmEYDyXBCAPPP4gAGYJtICcEMB5TnE6w+LhYcs/bjzGdiKElGlTKDb0jIK4oaExpKOOZ4NtgaQtNRm8sdImzNAonrcfRZcdxWna8g8ML6sA1MQLCB37MpRVSbji630qgu0LIk9gzRwB55ES4HlkqPE80dXwoDXI/J0nJD5zdR1OLOah6z9ziPR0Lu8dBn1SHa1ChBHTRRhsj10Vr9s9eCW5CdNqA8LqczBtE9u1U32uluW8bC5ITeyBceiL0JxpuI10DXUFtRfttulKTKKbzSrIEPQsNdwk4Dx5YDsEzCHgAr5c27wmfiW3lW9ohEPtn1Hv2dj5mi/CiVIYihbBS/q5GFO7+I5N70ZHRwvR2EL/ETt1Z+ibZ2dQwbtlsQAl8zZCh26Gak974SUS7ETlFFgZ+m0CbhJpMQibDatNIARsAUsjyGIVEnEqBl0IO105CU1dnZBFeKiwwwxJCb6mWtDZuIqLkUjKkZCoSMzCy09uTba+B9l47EqN4ZzuFoTFepjU5R9bcfCf6ouI0R2drPUU367sqeICUOwphN75KsEfgcNIRxHNPawhw7MVJlACMg8BWdoD7xDseK0TcIP4Zu04wpFtiNadyYZzM591Mn0dD+mgOXCUDIEdZQ/4ABL5NzCN1+GGJykMCroYXfkwSnEuO2ojqUm82L8fO1afjLAmQqBg2VnIc678SfwazW4D2pRm/7WKnSvsglwYb98KI/kLOFmiKqpIP6K+FUWqxUam0SaAfERUPNfCs03Vp4JDC9NC9B7UtV2GWOP5MMKyeGNxZLkTmLBexJD5BFLOXiJOq8iLVClUWtnebAw/HO2m1tvoYOS0o/skhIpC8NJEDLSbTbg6dBFCFR5TEoWoGGkj/wZjYhccRjsCgpAySf+SUxmGsh3gM889yA/yO48Ie62a3ox451+he/NP0dj+p8cFvmRlUHPbQxdia/x72Bj5GhvYNQxPC1WV8iw2IOJ2ZFxpKCmW0McGOE83Jb9SWGyERiJTeI6dxEpT5QRgjkA//H2qNGvqOVmeea2MyzCCyzCRvVKLDSJrKIIQRqLUeiW2Ay2n/hjxjmvZWC5ttlRRdLSFzsfWur9DMy6EznZEXJ3pFMeUWKYvhJf630bellHXohAyFl5W3sIxZ7iiMqiYAIyj93MkcojdfvJPgL0jSe1Ps0jWUZYlGXJNkjqHBJzWq9Cw+W7o0V7veVB/DKURm2JfxrrQFwi4jrxIoYxECIPJCbw00Ic83ZIIQdoPcYW/yr8krUxZ6mAvZ3MSUN5q5iD0wUfgit8X8IV/nj3tL6tLKFlwQ2E2tkrHdYht+Dob6coNknVHPoPeyF/D4kCcqjkEWo6CdogQBhIT2C2WUBSCuKKj2jDeto8EhMz8bCoiAO0Ix3eUtITYJfCRJdhiAX6J1Hqdz+plmLntckR6vzSfuwo8aWbbcKr2RaQmNyGV6EAuW8+QlX0IEvtoGEiNYM/gfnpLjtAKj5qL3far1J8yzQmQr+DD0OwA1MEnvLja45mVEFKmWFSeN74A5BkDfVc5C6FNN3tm7yVchj8Xt5+L54/G8OC7h6DkM7QG9iH0LPsRaTb4aSSnkrCywzh19XqMpurxdJ4urCGFHZHgd2cFLgBtiOP6SgIOe7deC+tZOF3MNIsqCsPDmIJwDTay22+j24ksA+wzRUibc9uHTsMLY4N4M5ln51Bl5408ZDgqKh0RuqWxfovh6lrY7GWroRAemhqriADK9HGGwRO+os/RKQAI+L7v56XnekwWVS4Aan/+9GvhNPWccHFLebFON/CNbWfQAQqDjM689oBtgiqNMM8MVW2Oh+i8Vq0cnklPY9SWiCJYClQASuoA1Om9HGijv5QxATnYDijTDD3Lic7Vja9B/rQ/KX+67Nef7OzE+as4Xyzd7XnEKMgqmjGHLyY4xfnbdGJeqqU+CFQA6tiL1CCL/p9sySFWwIYWWerZLO1nL3fzZXRB8aXyv+T3/+ykkzkPTWbL+SvmWhBA8YZjKM+udAFo47sLwPvgk3clSe0SQfjEirpKHeyNF/hPqnr+SHsbTjc48c/+wWyilYoFiBWT3Hwer+ZSMD3tmp1yKXfBWYCdY6TzVsH/C0fiXBNsfNNzGl+astN9Jl1Q21L4Duxdg0PQn1q9BkpOfGVZtqIoMjFRFADYSz6aN3HMklmJ4Cg4ATBsU3i40rGhq1T+g4PF95HRPt5LxcoqZ6/9aHA1CCCn89auhjaZpvLMdkWeAGQYRYiCyDFwOMQGOUiaa3cnnLeaG6AFsBKc5lX3kOkJZqWzQgd5cOwFG3lIaRwNddq2nHA5lXjxpNYmdEQi6Od8p9vk98TJLy3AZQOscNWFR5w7CFoAgVmAsm8IygMFzeeAPCOLIlSiVUMUyF4ejOLcWDPcus7ijyvjVMcoqKeRnSyZFZI5ULFWHgK+uB7GpSVGB+iGgqTgBHB4sqD1AryfK+vjLV8QBZrgzRsM7ZwWuKHqRz9zQVzTUE9NZ5uVpJbIfKhgTvfjuSE/Md3QGBvjIMmHasl5qvs58TGjKIX85F7Wj4ggpCR+R8Q9xt4vZ6RWGrVyOYun6QRdmaafJ9vi911ZeuHXi/VIewNcwXEfmAD0xx/1GJ7HmghAKiMkpYUY8q1AinJGzCMBm8taFHFFpFJnrHDneSnvMqA/gQnA6emd0RSfOamMTAWWRxcc6l2JxG/KzLAlfMuKL4am5S6I9kBjKEs388YJXwUmAHvnZQUTnsuKzIj5E+O8VHKMlFYgJWRdTDm2ck1X5OYsGnDBhJvUeqwzWgLlPrAw1G18j/WVUhFxQ/X0+yKASW60kFVXXOW8kmggmSI7ZRKgFSjSEZtIo4U991V6A5c8tqCDEzlBUmAW4LasmsX/LCallyl1k05a/yiUUdntsnIoz3Dz8HSiEHaWsSXecpXWhg1GF+qUqFeFpoDjh+AE0NnNRnaB7MSf+pEQL5URToAcPFhWzepfiva/O8Xuu8T9QsIz18qo3G3Tvr63sGZI4OfvHTJtFiAtgNiJ5e62d3DJ4QJuSCojHRxpjKX95US8+jK7yyuIXhkaYXhJ/vyG2NRgJ7iWlAN1dW2NJctwOQ7UxbGsICmw3AR8d916ao8gPoekIZZIiGs/ZTm69pvnKZTgJzfmlLro26feOVzi281x2WOGmz/4r+OkdaxOASIZjqinFXTJyt4AKbjcCLy9ZVvBfOcyKJYtvUv5oCM7OuqBA9B+97u5qapyP0j389/vHvXCTQEeOYMa7yLW3ICm1e2csBezZbU4DrSOew7q2VsOkoITALlyzjr7vRtiWR0ngUaRf/2Rfw6yHiec18Nv9WFKxqhk3oKuR0jGgNo3roUuC3+LpHDYemsksKDRz7Y0alN6sJQL5/TtcFsXGOfnFGR+OONtyPAEwApqzz4L9bXXllLckt8dyWTw4Mv74UwTeFmgSuWQBVmheASrerl21NvZx2Jo3QpD5w9HZwSy5MKLGQRqAS5XENjnfIzRUFHNybhUKDE0iZG+AaRGxmYiJXZ8jL+/tzDaGFRtjjOfu557DYMT5FXaqCIJ6K3ruhCpj3u8y2OVE/g9lFEPd9oETYEKQJizP3VJgUcKweIWl/GDI0gMc3yafjUxMgIzyYZABETBaHv2QH/on4Ku06Lye7rvKH7yymGO9cwOBlTupGnftLYEvmSmMPQ8Lx7iColFZX1ciYIXwBlnwT5lK8yRaYwdHEaOQvD5FmuYOtbP9aIc0pVoScz9Rz9a9rD0jaEJ3PzEbpjS0/W6VwXMHGp/Y2cr6ts4Z1HsE0j0E6f7+RgFUAkKXABcYob0xVciOcANEtR6H3xhXq4tup7pgcGZutAPh2+/HerbfTPPKni1b2QKNzzyHIZlA9qsgUHhlR0tCT3LOpRqOIxPEvwWWadYAQpeAGRSvfjTyG/fzs0N80mqkZ6aQnqMwxFSUVqBMjyM8C23cOMGd8lXkF45NorPPfwrHJ5iOJanALj+s7CAlW2Vyk8atK5HYzc7lEXBSOQTM7PYWb9QTYJhtGI7ZPJPPgnziivY/3LKjHyGadGy1vXrYci3ICgEcUluczPMr3wF9h+eP5MwoKtfvnkQN/9yN8bZEZTJaVdnt0pn59HgNiQOtLkaG91IFK1bdZzSPMk9xpwTiMRxVdjB5Y2crKkQVUwAAmrm+uuhPfwwuBdvHgkMIU6Et/Su5+JYsQQ+kHaBghm5/OsIf54bKlqWXnGTQyDfe2EA97wyxH0BBJpDygI2F3yyPN8BsHBRAt46mxpQX5fHltYkPhQ2cXt7HSLCV4XI5yD47Ml0+JvfhLl6dWl+vrwQqZKZzSIxOMSrYgU53Ze1mzD281EcuWEXJh96A/Zktvy1476WzRaJbCsXA+yAzY0fbojj+QK+SFymF71Duuq8l146G+aEZeC1qWZsorAqCb5URrvtttv+Vi4qQUpDA5QNG+A8yunKBVyRLwSd20wNb6N1HsdwNibdDk6O52D+dgCT/84NEwNJxuIcxGNjqB5nb1SM6/xeHfZUFv/LT2XbGvdV8tmCOk0BcEc3lLjGbxEBv0kZiLFhPquOzytElXNBZQxnv/MdKHfeCTZ7C7YHKhu7Vb3rkI904U33Mla5qKFMr9FNGNzrZbHBVFujMNY2wOiqg94c5WZvRidXnQaV58XQXc+YuGe3ikzERo770TwplGMrAuhkm9RF1ydGIf6Bfa8vtVm4dbVV6l8upqzFplkWAYj2Z266Cdr99y/YHog2RmIakr3XYVD5MPfwze4c+ZWhDXgC0ehWNF6nuBB4479cBaOTKy0WSfc+b+GuX3P/MBeNZWLsLHJvmswTeSQCaOFMXQ8/eyACEBLmKN9rG/P41jqTOy69p4H9CTi79+CLDWv0u99F/uqradKFOkm9pHB6Xa5kXIM3059AX387u9Kmtz5noZxkblYsIcudfxmH6cJUT8noOOgvzjVwy8f5ESfu1qmfchBPMtoh7oWPhjAzGbX1wZd8RTg03X/kBpMvHAwjId9LCJCCH957L+a4yyR2773IRqMI//hBLp5rxDg28jiZ3/npYJ350SXOv2bT/eyNtiBaz6+fSO0FgIDpxrMNftLMwrf/R+GXW2wY/KhHJq7yyylUCZm3EEsojmd5xcsfhnK7+IWQsb4Q7uk1sZa7/IOg5ROAcEshRO6+G6Orz8G+b73O5TdR0WkqMXeheNtq6BJyJsYODyHeUo+G9mZoHACTHnXQdO2ZBj9RYOHO/6IVEfT4tE326JYa2GDLfmb2fEUG0ojLLKTMw8j3QI6wvRqmFXC0KBCWllcAwjL9d+tXr8HJW/binVuegH00QQufsXmZiRJKjk8jl8qgsYPW0MBOUgWs4aozxBLy+MbT9DKMekLynaFRbtjjrvlwCz8AQj5ECGS50EUhWn/TZOLM2Ay/HrNL+CNueNlJKtR+yRZsf/pGtFy5ldrPSMer7gwrIgiLa3LG3h3GBIcQHMbnsnYzaLqMPd9vX6ggxtkul6vjFFqbdiRLwZS8kNdHk4b4uriFneykBUlVEYBfgci6Jmx54Aqc/vNrEP+IdNj4MSUePswla5iYxvCBAaQnU9REUUc/h2DOF28xcNenVTRHWSLXK1kDOXYA2UkroqMyMr2AlnJj08LR2VK4qKoAfMZXXbQZ25+6Aac8eDkazuvh0ITGr3uKKLi5m4lEEHl+VGj8yDDGj45wW2nw1vCJDRp++BkNqxvo7Lhx2zyULbgeRqXb6CK/tsryNm77PAd1Xp5+wHFwKw3u9ItHMPrYXow+vR/pvlEYssGbJMN68n0gjZMmTYyUIp0N6H3ochgdi+8H/D5WDow7uOkxC325MOouiGENo50ftGfRbQTT6M4tf8UJoJxBJ5tH6q1hJPYcQ+LVfqQoDHMwAWuK88v8LdbZiG1PXo9QgAKQ8oeTLoVg4tAaflfooy5OZ3RUKVrRAlio0jY/I+Pw84lydrljMdzVwHEiiVeCpfG0i74xF2evrayX/n8ngGBhrn5ulRVv9eu34jmoCaDKIqoJoCaAKiNQ5eLlf9KTJbM1qgICgr24oP4qlF0rsoBAv/xPeu/U0KgOAoK9WMDj1Sm+VqpgX/sPnaukB/T/sjB1vRqLxY7SFB6oEh8f2GIFc8HeG2bk/yXWTYns48PghhU/sND+/ooT6wSx3hyPx7lSiSQXfHANf6jMmOvv5+kDk0IwJn1WMJdKl3rCfLCL9zfVhFA5XShie1MRa6+geZN7dEeXMOHPKKWaOwpQFsRU3I5ovih6iUoW4D+RBEx4Cu/v40vSUtdoCQgUMbyPmIrPnwW+ZDvPAsrLSqfTa/jipXy2kxlt5Lmb9zXLKAdpzjVxkqEdaVOlg/s47x+TaGdOstLt/wFBXnCCUaUiKAAAAABJRU5ErkJggg== + + + + + + + + +https://www.qwant.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/twitter.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/twitter.xml new file mode 100644 index 0000000000..1334c4726f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/twitter.xml @@ -0,0 +1,13 @@ + + + + Twitter + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACW5JREFUeAHtXGmMFEUUft07x87sAS6ngILKYkTDoaLiFeSIKP4wGggmxoSsaOIRE3+q0R8aNeKtMUZB/WEMh5JIFGMEMYiCyC2Xigi4wCKw7DJ7zOwx7ft6aZ0duuesqt7Beklv73R1V736vjpevX7VBp0Ry7KMucub65JW8n4yaCxZVOWk6bMABAyKMaa7TcNcuPiufosMw7CQq4E/s79sGUrtnR8TWdPwW4tsBIzVFAneu2xWZYOJlq/Blw14ev7c0LnBA3tjzvKm+VYy+V76Lfq3fAR4OJpvMvh18ovSJbghgPnWtCdct1R9TT4CbOyY2tqRj7NnCWxpmp6JOkEJApoAJTB7F6IJ8MZGSYomQAnM3oVoAryxUZKiCVACs3chmgBvbJSkaAKUwOxdiCbAGxslKZoAJTB7F6IJ8MZGSYomQAnM3oVoAryxUZKiCVACs3chmgBvbJSkaAKUwOxdSMA76dxICXDcx/DqMjqv3KDqsEmxjiQ1tlt0NNZN/K/vcs4SMGFIgKaMDNOEoUGKBs/GOdFFtLWhk9b91UEbj3SefYPLlZqIQV1M2umEHdLjckf+l6QRgLHNjwZ2Ibf2eRMidPmgzFULc/J1I4L28XtjN324rY32nep2RXBw1KQ7Ly2ncUzqY1+fdr2n0IuZtSww1xru7g9eVUELfmyhLnGNJas2k4cH6eFJFRQqy3prrxtqa8rouVuqaOHWNlr1Z4edVhUyaMKQIF09LEjX8FHGLeqTnXHqFlwfKQRMvzhME4cG6CEG482Nrb0qK+vHtFEhJj1acPYmzxUPXBmlKwYFaVCFSZecV0a45sih5iR98Vvc+SnsLJwAKD39orCt4I0XBKmlI0IfbGsXprBbRpcNDFDdxMLBT83zetY5XeI8X7z9c6uU3izcDB3Crac/D0GOzLwkTI9OilLZf5ecJCHnINfgUe5pAeE16VGvg6eFF39ooQPNPfND/zCGJnHtVlxOZ+AEAely04Uh2wR8ZX0Lxd3nufRHcv592+gwDYzKYbehJUlvccuHxTSVh7jJI0L20PTUd7Gc9ct2o3ACBle4z4DjudW8MLWaXuc54eCZ1pRNuWzpgP2O2vJstxWc3s1m3DM3V/07qVs8Ab+0vpWOxMTZd2c314LV7Xkw01AzvNqk59nauJUnaREC6yV1uBORZ2oe0DfVolqyO06bj+a2ZkjNJ9P/wgk43pa5dQS5g9RNjNDTN1XSiCID82AmqhC0/I9/aafle8VbQcIJ+Ls1MwEOYFcMDtCC6dU0b3yEKoKFjeEDXeYbJ39RZ0zCr//USit+S4jKslc+wueAIy3dbHpaVMkLmWyCxQ0m0VtGhWn1nwlauS9B2XpQap415cLbT2r29uT73LoY/XpSsOWQUorwGsBXsvZgz2oypZyM/5ZzM5hVG6a3ZlbT49dW0CReecK8zCYoS6Y0J5JSwYfuwnsAMl3Frfl2BjRfwSLO8c9g8YMJDw6zfY1ddIRNwnQ50X72tfR7ivltGtl7cTH541kpBNSzmbZqfwdNvzhUsH7oFTfwqhQHBMPaH+wsO8ZENMbhUk5SFL5miRJX4MiSQgAw+WhHG41lj+SwIi0dB1/MKVhL0BDnivyzCgJyGGnzq6hj0cB6eHVDKzXFBbsP81OnqLvbOuXrLpwA+M2x2JoyMmQPFU+sidFfp+WO1UWhnOHhXE3qDFlkTRI+BMFyGM0r1NE1Pd7JGL89ahL4BilrjQTe0NAqz/x01BROwGF+15oqVew9xFGKItLn41V/4UPQ7uNd9ntTrwJL6TrMX9kinIAEdwDRDivZILjlD1e0iqFTOAGozOe/indauYEk89reE/JbP/SXQgCiC9YdEuu2lQm2W96bBLud3crANSkEIOOFHOZxok2+HY2yRAvcINvYBaJCpBGARcyz38foFEehlZpsYfBVRc1JIwCgH+WJ7Jm1MTrQ1Ns07euErNovx/fvVm+pBKBAWBNYDeNtErp2X5d6XrXvZFNalQhfiLkpDr/94l1x+uL3BCGA6qrzQzRmQO/AJ7fn/Li2cp9aC046AdW8Cn7k6gp2yiXtSDNETSB0pS+ujeH7+e5Afi+Tim0k0glAJDGCpqZwy+/rspSjHhS8AugFg/Q5AKWhYn1dYCh8f0ht6wcmSgjYe7LLfkPWV0lAANa7m9v442HqRQkBqBYWZhvq1Sxu8oVxBUc97/fJVFZGQJKb1xsclrgpx90o+YJY6P0Yepbt8W+IVEYAAMLmhlc5yOkrjv8BIX4LXhYt4FhP2eEtmeqplAAogsp+uL2dnuTF2cbDnb4RgQbwGjeGfALBMgFZaJox+9NGX9sigmvHDQ4SAm0HREzeWdOzHajQCuXyHMB/Z1MbrfXB6knXT3kPSFcAURMA4kteJUc5RhThijIFgbbvbekb4KOe0hdi2cDEihjxofdcHiHsXJQpMDff54143ype7Waqk+QqexeNuHvs472dwRcVvOVdGlErR9bBAPjlb3WOtkz6OGlKCUBrH9mvjK7j7aQzeJOGqmgJeDhf3tAidGeLA2CxZ2EE9GOnW4LtTLicsUsGTjh8GgDXh1aW8fbPAGFPQC5h68VWynkeky08sEt2tVMnDz99UYQRgAl0Pm8Vxcbm1P21flUaC6xFvPqWGdsvom7CzdAxbE7eNy5q+/tFKJhvHngBBOcfvgFRCiKcAKfSiGTGzpdJ5/NmC/eNk86tQs57OIwEIfE/1ncI/5yAEAU9MhE2BKXnv/1YF+FAtPSNF4Ts9wHY/i9SEPS7lcNH1hxM0GGBW0dF6pgtL2k9wK1gfACjtiZAGKbGDAhwAG+AsBEjF4EZCZDrOfYUQVM7jnVy9LWvi/hc1M56T47Vz5pPTjfEGESEfOCAwCytYFJgGYGcqpBp/4/Vaju/mrIPDm/BbhgVYYK2Uor/KCUgvW5ov9h6hKPBTiyt8JX0+hTyW7LnpRCV/l/PaAJ85lsToAnwGQGfi9c9QBPgMwI+F697gCbAZwR8Ll73AE2Azwj4XLzuAZoAnxHwuXjdAzQBPiPgc/G6B2gCfEbA5+KxW07ch5B9rkzJFc/Ym7wvZ3fJKX6uKMzYm6ZhLjxX6lNq9QD2hmVZxpzPmr4hsqaVWgVKW19j9dK7+8/gb5MaFkWC93KMwurSrlApac9YM+bAHpEhtqAnzF3eXJe0kvfzxDyW54YqJ02fBSAAYwdjPg87i+/qt8hu+JztP8DF2aE2lt4MAAAAAElFTkSuQmCC + + + + UTF-8 + https://mobile.twitter.com/search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/wikipedia.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/wikipedia.xml new file mode 100644 index 0000000000..2043036e6b --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/wikipedia.xml @@ -0,0 +1,23 @@ + + + +Wikipedia +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://en.wikipedia.org/wiki/Special:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/en/yahoo.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/en/yahoo.xml new file mode 100644 index 0000000000..fbc69d2a4c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/en/yahoo.xml @@ -0,0 +1,29 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eo/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/eo/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eo/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eo/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/eo/list.txt new file mode 100644 index 0000000000..0b9dd166db --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eo/list.txt @@ -0,0 +1,7 @@ +bing +duckduckgo +google +reta-vortaro +twitter +wikipedia-eo +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eo/reta-vortaro.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/eo/reta-vortaro.xml new file mode 100644 index 0000000000..3b0b28dce3 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eo/reta-vortaro.xml @@ -0,0 +1,15 @@ + + + +Revoserĉo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpBOTM4NEVGNDU4NzAxMUU2OEYzNEY5MEFEOEYxNTI2NCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpBOTM4NEVGMzU4NzAxMUU2OEYzNEY5MEFEOEYxNTI2NCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4MDExNzQwNzIwNjgxMTg4QzZFMzlDMjAxOTVDNkMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4GgtFjAAAjd0lEQVR42txd2XIcV3LNqq7esTZ2gCAJgAA3iZyhTHlsjz0xER47JsIRDj/41Q/+Ev/B/IEf/AGO8JtjvEQ4RpbH4hDSSCRFEiBAAAQIoLEvvXeX8+StW13dqKpurBTdVAlkA6i6N9eTeTOzrV/96leE1+PHjzsODg7+cWdn5xfb29s9tVqNQl8G/2cYZJh8RQyKxCIUTUYp1hmjRE+CEr18dSco1hGjSDxCZsSkWrVG1WKVSkclKuwXqLDL116BSoclKufLVCvV5Gfsmk22bRPZdGkvWbep1m0lLVlrsi8pF9YfTUXJtHjNlRqVc2VZZ347LxfWXslXqFqqqrXWWi/UNE3q6+vby2Qy/9bV1fX3T548OcL7Fv736NGjz+bn53+zu7ubPNXioxEhLjYQTUcp3hEXBoDouPC+ED9qCrOwCLyidtTdPDYKBhSPilQ+LquNMZOqFd5ctb3NtU91tXYIgxA+4ay7K66ubrV+CBK+D8HCz0MQIBCyZt4Pfqd44Ky3oBihBSdIaCDQ2Wy2h6+/7e3t/Sum+Z/Ozs4+Nb744ouOubm57N7eXqLl+g1H2qOK6ELozlid6OmYbAqLxAYgQbjwe9i83gikChcWDmJjE6Vj1oKjMhUPi8IQaIkwo+wwwrbPTfiI5RC9Q2lqvDMuFwhqpSyy4s7aLYf4vG48F8+HQMhaixWq5CpCfL1WfMXahRmVaigj9Kunp6cwPT09YMHstCS+dwMgvDYzfEFysCFZvEN0vXjRFBDfuQcWZZB6Hz+HzdopxRBIHzYnTGDpgspr8ySMaHNjftqKZ2HdILaYRqy72yG8Q3RoBdYtWmrWBU7WHHHW62hsrUuZ0mQxqRixX18v1o71Yk9h2guag/YW2/u/bEV8UVleJKQ82ct2MpOUjYD4YmaidTOjfYNL9KZ7uZrk/IwdsZVGQTLLUdEi1yTwJXZ3Ny8agU1D1dtigqHsbiQREcJjzWLj+auYx4RVNzNYi5foTVovr4i6H4x2pBYRxsWqMap2VJX/4Pvmd/Lq4jVDK6qFqpieoPWC9hY73a5Qk2MZYhMhMan+lFwgvjhXLfFa0o3TmQXvBg3b0Yyo6TpGSCgkDn/PbeVE0uCs7UoLkwR68rrwuyBMejCt1s2SD1Mj63YkvZngrUywZgY0GcIjmsFMxn1BEwgNvh5vHgsz4MChDX5MAO2tILQjTjOqNgGCYxO4ZBNJR3rOQvhWqMqomygxHSxp2q8Is3cNtalyzZcJet0gQmogRR0jHUJ80Va+F+5xWsKHMsTRDNE2qw5KNADJbeZEe/3WC9pbocRnCYTadgx3UHogrexmMupK/YUQPowRcYVYoIWaIfh3bjsntrd5U7LumCkmJz2Ups7RTiE+fFaDubnoJXsYEY1EXX8hppnXC22AbwDMbmaC5UsAmB2W/FSfkiBIPogPrgpBjEsifvM64PwM3pQZlc15nXrOzglygjkS9YbZYaGBpENgOscc4sNURiMXJvUtUaLVqMXC9Ih6LkwoUJ3XHFl+DhdSLmZnuNHssOWlql07EzY/4dya3hfi+nBVNsJ/jKRBjF/kFwXKOrgb5ghfsUkQG+sF8fEVDl0T4SpfAtX5j5Hm5w6qPQqU5gvO2esTrObNwm5B2qHC2uzAyYDw23u7tLO/R9Vq5Uwi7cI6fo4VYVtpseOKsoOPMTyMqytiwkE2mgoxd1gsoKQdl43oWAKMgCmC0KQGU67Z0ZGsJn7NEZyabV8JE7AHmCUIgTxXr5UvQG1Bc14GYMNwIuK8eANC/J662cnlc/Tk29/Tb7+ZpVwuH/hgaIkRYp+wMMtkQsYZ0iaT1JVOU29PDw309dNgb4b6enupu7OLkokERbS582GCBHKApfwVARC0FKYHjlebHU18rClfKND7jQ3KFwtXoQMsWDEaGRykdFzBXjAB5kev2c6rKN/yqg02B5yvIVs0EXVtfrVapaNcjja3d+g4d3y2yNSRfnw14TCBGtjGW1GlCWlmyPjIKN2dmqLpiSka7OtjRsXlZ73mCOuye2wJ3CD9YICGyF6br18I4t5vbtI///pfaT2b9cfmjsywovBz6uv1ypLdKj1murpOfZle+utf/AXd5n1Eo5Yr2AjSJFDjdYMhlmt6eNFACzrIEsm3vMGVumQhZ1Vjo/67VRsSweqIf5SK8t7+wQFt7ezS29V3tPz+PT26/wnNTExSIhEXZ+wiHSeyhZCIajO6SGRUYAj0ccLh8t8rlQodHB6xAG1TEPRuRlRB32vH10Fwy2XHVPN6sC6sD0wALJXkY7VWZ4DekDfIujSoGfCqMmFgIkrZEhUKRSFUKpmi8dFR9g8xZdp0WiSmzCWkFBvR0W0Y1DyNAJ1VyCRpZzQCCg1TEYeAxkCXgKWIlC0t/cD8OrdzVuJHGCqm2aan4glf34DFVeGEymUqlktU4q9+GwUjDo+PaGFpifrZL3R2dNAQmyPtBzQTsCFtKtx8jnG1iCeQETX7ZIwCzeWIWfJRuwkqHZQcBsQjbu6lwfScsB/aMPq/0iytP/3sMT28c5cRToT08yHJQB+lUomO2Zln2QwssplZWlmm/aMjIXjzq8I+J7u7QwvvVuiTmRmqZTJes17fkGEp32IZDXbfx/2o9QRAaNwPfqiTBSjC6Mywz6gFhvIBvb3d4ogbEYgyRTqZiVSFBanRmUJkNQU9BEh/q+UARQ3199HE+HVGOIkGtdRXuVKmfL5AM5sb9OzVS5p9/pw22DFWmzwcfrZQLNL+/j5rSkXZbYauDU5TsgqmQl7m+aJcaO/10TH68z/5ExrI9AmzzmyG+E88FqPh/kGB2g1CYzr07lapcAuhuyS9nJSyjuSCyW+HIX1xloCPlpdYnlcsxng9kaQOlrSoFaUVdrZbLOlwyH72tMyaULWD81VBWUx/FQg/sYL5nBy/QUMDA+diJtatYxmz+T6mElTQHJpgSaYTJ1npWD1LGOjhnTucCyGrMB0S0plm2MhfgzZrMhPjzDDLDLHtjsq3RicOTIR2VwOYYGgBipwk3EWmKyLKf8l5hD7RAoKQTKFBl4p8EJHCESOwW9/MckyR841OYRI6UykazPQzAkr8YJzrRTFBgA9S7XAG+uA8PFtoOE7VDrV95WpFHK3d9HOSv2EHWGTMD7y/tLpKz16/lsAIQV7zK8q2c6h/gG5PTnJk3HluiWzphAUsVClXynPAeXzmggDQTwIvdsCBazYVaFCpdi/ub7HJViQoMsp5vbAgkSecj3ZiYAaIX+ZgKF/I0y47VkSm61tZxvuFhsBIo5F+Rj13JqckEAMyuWwNqPCaN7e26cvf/Y6f1+ErQO04Xyti0fWRMbp765akU8J8DvyvheM0F3qGYn+9pOCFFBm1fPPyBb1ceKPD3gbOwfyA2BWUpzAzADX1xkBgMA2B17XhIYaet+mT6RkaYPyP9y+bATXe1+b2Fv3myVfKD9onpa5VpQ5+Deby8YMHjATHAxmgwYOcsbt1O1brIKaVEwaer3IEiyj2tGqb5IWPDg3S1I2bLPm3+Ot1MT1R1gbjApySodcf4IQhCBUn33VeTYIlsNvYszhjb93Oh3RKKY4bkIjTxO/t6lblIfSROV+j/T1LNH/RJ1x+2NeLcvxsKd7bY8f8+++/p6PjYw7ACmxDp6mvp0cg4VUJh7v2czzPlONUs+3nWUhkyXGf3ZoJinbBhhABWKa7h+FjWhZhO39gmioczYKwuXyeik05IK3+uwf7goy29/aowGr8o3v3aKA3I0w4d26mjVQE0uHDHIRFdQqhVf7Z5xlwwshbRS2rrYDNwgGBLCBmtFB3/d3gn+lgwv/s85/Qj+7fZ5selwXBJgLpAPmsrq/TwrtliX73+N/lppM1LAjZ0NWNdfrf2VmOBQz6/OGPJBlnGualSj8c/c1r45LDx6HQeSxQkiN9MLMV8eVABrlpDsUkk2ibdoi6t0ZBOE7s6uygYcbvKWcBInQs3ZDwu9O3RLpnnz2jr58/p3fra5IRbX7hvXcb7+nF3LzEAnDMQBTmJZoiQ9IkMcp09bAE95/L7LXzu7rk0UKlry6IcgMx4+ypCMM5+3WPEvEbLF2QMJz5ppNpSidSgnr+66sSvd/aEkjabJLyDGmXVlfomxddckQ5NjQsJ2iXhYJcojgbvUy/I3utqZM6EyXiUvZXqp6vALZtVY9QpreH7k1P02f3P6VBpJl98k+IF7ZYW16+eSOagjPdqzpQv4qXpOhL7H+lANapuzx3FfIpmDA6NEQP2VdcGx4WzfA7AsQx4s7uLj1nx/yWtaHsY64uPFFWRxsntaONq82oT+qZcKZtSSk4KpALqqJXDrRtf1/bCgWdJiOKtDR8xczEFO2wpL9dW2OkVD6xaQRGL+fnJUcPMwR0EZaxPSsKwrvlcon2jw8oumud3L99CluHEzpeZwf7QRQcNAMIORksV6WmycLhMDQAVWZSA4T6eDNy6VoAJqRTKbp36xYjpD3aYknfb/IFEl0zFNw7PKSF5WU5G749OSW/5zpk2ymFOafNBlBYeb9O//LrX0vJzFkDI2E0mxfEMH/GiPD62Bh5yamdr5TiHzMDYId0cwTexPkAqn6vIviBKRpkxDF1/SYtrqxQsVhi/F84YQFKLJnLa6v07fcvWBMyChFFIq4zE9d5ztJDOYc+OqTnb+akVMYvF9TKxBgeoRgc6KeHd++xrR9pPMlznC+ID8sjgRjqVHSXh5TzRcOiYzM0G2ifIo8LLYD9vz42Sg/u3OUo+IhWNzfkvKCZOAjS5pfe0uSNG9TV0UndfOH33X4Bi0KZ0A4KkrNpBI0X4EuQYrd9/IgkI0Hv/aLQ3JKKLTTOodXmoNhQFdG8GRwzpphgNZ/8PXYIaGmKvrXPBNhzRLt3p27R8uoq2/y8nAX73R/fQ7ob6p28MUlRwxKt1VUR4r8iwVE8UuJUuyIkVXM0xqs1kP6SojXgPwTeEodQcToXGRG5VdBWoxbggOHG6BjlP/2USmyrjRNVYzYlU0kaHRyUcPxUBxjskEcYFf3Bg4dskjKUKxR53TW1dsMb5kck1WFFokJIoCRsBs/G8Z7RoQ69T2qBOqPFQUkimbjcDkyQzFZn3zjV03kl3RuH/jLpDuULwMcSJwanwP8QBnSp3ilhQNxwzwhwhvvJ7ds0PTHhv3bnIBr5cCsaPfW6Eboj94ODDF+8j/eQvHJq8I2aIXYUvQIo80NFn3TFmFHVweJhAionkNr+8b1P6NrI6KXnVyEQvd3dktJAfkzecxwvJB9rlsKsilOaKGbIUQ30N8lZZUwV5XpbTJFeSCWTlyA0itFwrmGnSHqtkCRZ625eOlA0hMZadVeN1xQhwu9jM/fzn/yRpETosgEGCwsIj5yQLk0H7ATRc9mc0Bh+oKE4VzjEb2JT0mKTUCUq0hxBZr0q7UO+nDJEQGdoKzYDaRIG8Pu6PVaKzaheHQ0GI36IshZc+ZIdzA+BQZ+bdMt4egSshh90fAF+0HtKBo24kq6YNoiPekogiOPssWrcQ+sPaopqdUcsZS+d8QB/cLXEB8xHwIW1Hq0fSTUc9qCbXKxm9QYiwgbdJmsHDUErdIf8lW/EGQcADYUNhRTB9EjLT1FtppQrkbFpuP2+WKdkeT9Ah4y2KGIqOcaCph6uHsqapcHQc7hsBak4uhG9xa5oihB0ROaVaoPYfEfyYXZA/ON1pwXUKfHWHfjQXnxfC4ndb6uKD7qaHjEv8XWqAes5XDuUr9It2dSyavmpOhJFojbbuYbDAzBBmjYus0vSuw6H+CB0cU+ZHRBfuiRz5XqDnhYeNkUwSa7WOLMmdNlNMzq6DJOjiS82H5LvEN81lU0Azwq0XWieAMyzc6q3yenJQmeKNDtHL6nt064zHMhMzA4kP6vMjtv87NN3q20uTJOYgKrqQrmsPuHm/L7gfIaagnYcmx/WJxzIAC8TpBVUS5MjUUn+Y6RUu9CFSpVnmIdE5/zswg4Tf+tYpKmdTnmNOgRpOONxwETdagtA0dBFY1ycsEAwBCDATLbRKR/KAJezDJslc8c3csezoLepVm+OoAujv9qMaB+gJhP/aOPIJb70hLUzK8JW0oj1uh2V1Xp7rW5E1yMHLmS9mCm0q9Z7vHHsRrqt1tvqfFHMjFRQd6lJI95C3vPW5Ifm1PUGPS2pZ5mW0iyt7WQ1z2KC9GibU2eEw3I0zTMX0LrawIALRkNuyZ5TOQyGQ7pcBhzZgba0mYEnhnUMpNxJWG6y8ZyLl993ul7wwrP0QCg8/8wm6EPNXJBnO+gKrUfezeCZYTMXwgTn0pywUfcjcm/PJK52hnX4M+AjnbnwIQXn4oZ1OKr7Mc5c+H8xrEM4mAqfuXDVL5mYwn9CZy58xIJjeW0vhnLAkQTNXPhQL5cJATMXdMLwoxMclwGOBIntHEgHzlz40EyAVDXPXIBUwc5+jILjngfoUQXYBDYQOHPhQ798Zi5ILRO/d1bBqUkkW1MH8rYaZ2OfKImw6wdHhm4/Nd1W1DAaBQlOfViHoVplZLKgMzVW+oUjxg+uM/HEzAUWFhl4wf+G+WlHcHTqoFKryplyPp+n4wJf/LWQL1CpWlYzQh2G2BpdwURHLIpZlpzaoZUqnUzICSHOwKWPwTT8q7jDhnVo24+gBxqARFs77Uofkgl65gJG60iFcUKNHg4THOlP4w2jfWj/4JB2DvZoe3dXqvIwhAoNIgeHh1KDim5+Obp0Am/TUD3LUSY0yu67urqop7ubMvw109PDVy/19fTKubNMdkEDnocRocM6YD+hHrpd1WAoV6ogerN9ayS1yZKGZky3ihgX1kYkzRxIoFXVvE0d4vtwQZ4LfC8a7ETOfoKja3HQGIKO/Hfr72lxeUVqTVEqD4aA4FVkMqsVVbpinExX6GlfMtphPSIVDyg+iEdjwoSbY2PSX4DqvcFMn2iG90QucFiHqEanmpsMSYJavl1bkcpk/N04URmm2kgzLAFDA4PUw1y/qFMyFN9uZLdoY3tLGrgl92N4S71UC1GKTcBw/xD1d/WKWuvxNc12H1KPASEg9Pzbt/Tdq5e0sLxEh0fHVCgVlZQH5I18E5P8gnC4fc0FNX0LpZVgLFqsJsfH6dM7d+nWzZsy6QU9B24Zpd+wDhBdBlajFIWlP1cq0PP5OfrmxXNRyeYqNYF8bAdR8/izz/+Q7k3PSHXbeV9wfvv8vK++/Yaf/YL/fqCe7cm2Sg9xLCr1ST959JlIXjwadTsOvdKP+0HqF1eW6Wvey3cvX6rWp2LxwpNxYGSFBQbPg3lbXlujT2/foYf37tHUjRviL0ztvJuHdcj08M56ngTnqDfHrtHSu3fSUuRXpYYboel6cvy6/Cw04iwVy17TA+nP7uzQ/NKSSJPvc/kP+oZR2zMivVz1SukG4rPJQbPf67eL9NuvZ6W6eg8MDRlSiwaSZCwuRWLKqdbtuB6vABNVLpUpD+3xKSSWxhIW4PfZTcWMo0MqFcs0MzUhzd96Wm/DsA5diCWjCgxVqznBtuztyopcKJj16xrHAxZWlqQS7v7MbUEGZ3Xc2Fx2Z5tevXlDWTY/2KTfC1XLqJybZvXGkD8woPk8oub0mb1hRv7n/3xJc8wEMWcB8yhiVoydagczdFC0eqSfzSo7VwwUjFmqwAzFwXDOYCJGKyyvvqM1JjJGoOF7zYyVWlb+2W9ffi90gt+4PTVZ1wTvsA7JEqZUJk/m78DGplIyO+fmtWvCbdykeQN4MOY9oG7/BmuBX5NFu7l0SD+07QWbvl1GIzUfI4yyRNSQ3rpxU54Zt6JNc+Ecc8D3evtulZ4++461eCWQ+DCj6EVGpR/MBTQZzYBgMjTA8rTH6i5OaAAEEtoF0/Yt+xT4FhQOwyI07wvQdpFpNPv8OzGdGLsQd6bDuMM6xPk68E2/YmLjR+nu7jStbW5Kl2O1uW6fuQzohoJaqBzm/yTO0EgHcwHbD7MjYyULBX+CsZkbHxmR/uHuzo76eo1Gp4uGjvnFBXo+95oO2B77poCZuMOsuajI/vzBQxpDl04sIeNsdLB1Qlv4d2J2VDQdPWuYijjKv/dV7+/Z+b6QtTc7dWEC7+3Zq9cCVceGhkRr5SxCD+uQVG080gCZoA1wcJh3MNjfLxz2c16wg7DbL+bmqIvR0LXhEWnIO430A42g7PzN8jId5YNNRVeqQ2w/rgRK/pqgL8xkkU3XOgvDu411mTlX8enzlXt1dNKP796nP2ZHPjI02PY4BHcYHwMuwMwbbLIAQzmYot/k8iyQ+yfMEdZwmDuiNV4ThBnlitAyPazDjKVi4hS8EA4PgRoiuMDEkpH+Ad8JWLpu//s382JCYJZO0x8AmHnIdnRuYVGcvl/LqsyR4M1Osd2HScRIAz8tw73yLP3LbH42trakgtvvXphrN3X9hozBgXBhatdZ4hhV7hiVe9y+NSVop4NNt5/2yPw7XhNMNsySiu6UMzb1nCC/YAtSfXdqWmY4AM/6vRDIYMoIOlgw8xON2e1KPyR+5f2a9AQHDYON8Ia6OtJ0hzcJvxSLRAOxO7rr4Rx3ZbzyyXWAcehjhhPHVNtYNHrufmCZa8SAYPrmhGiW6cNMrAVOGSN6MK7H1SYZTh4QuutGusF+hn3sDzLssILa72GeFpaWxZQUCu3hbDitza0s2+o52mAEVPYhmBrigfE1o3SdL4FyETMQykKDDo4OA/2I4QCM0aFhseOGef5UL+4hfcwYU5xO+a5P4CmvCbFN2RnT4B7ahLWmAgcj6pwYG6eZyUlRfz9mYeOQ5PmlRRVA1cIPzpW9LolNfL34hp3lge80W2BzDNDDKONMb6/0lIU79Ko0ePthdK/EdjHaaYhQz5OgdYJDWAsZU+lnHlE2KcOqCgK5bW9eSxq0q8HEAhGuMfoAhOru7FZTwf04zNh7bX1Dmu2Aj8MYgJG+kP63DBORDCtX/LuyANnG2bFj/nJ3GymPmtNbHNjQ7aSRLbbdFzn2QOZZO/c0A/1dTXxBzQMMZLqilE1Ua4Htv7oxY2x4iG0wzECnar3xgZPILj6ff02bO1nBzEHSD5M1x/gZUW+u6D/cCYkuJLXGGWn0ZTIKvrVwliCAty3Ih0Oqcq5WoZYfVHeqNEpNEnpgfC3EVAHI6Mhdp8VN+dilQsXNPvq9sCng2PvTMxL5RgIQEUJvRKCr75HCKDVw2w1o2Ekj/fuGAxnBzgFoBU3OQCqIyiXIawOpoEFQWqQCxttIyoMJdXh0JFpnX0CjmLpnReIP6eQPoKHFa0MqW84NqF7Ia+qSvzAzJARJpWVqCRBRUNpBz/zBWGKMnGlGROD4AfsIZCTXNzdkfnRQoIQeK0S90vTXxpAOPa0Q9h2zq/20FE/K5QuSTkCisVY9vxbgHgfMUCAcQMygEZzJRFwibZwpNAzrEA3IVULNkCSrQJSuLomQhwcUhPN7If27yFowt7ioUhgeKcMpFDb/3atXMj/aLx1sOoHSTXb8I4NDEgOEzgry7BeZUXzmQDevM2gACFAS0BpihcB09CkzoYDhuCfu7WfasJZuRpGIvnXKxh3WoT8TUTpNQgZOqFRwTEzCHWdcQJAWrG9nafHdinzkicAuUmetQAHQDMnRHAfnaDDIAwO7Mz3doVlW75AMOGhAVuSl0H3v1yorscfRseRv5hix7ezvBvqqdom/w3tEwg8CB9Pmr9EWDWR66Tpbj3RKRfF6WIc4YdSqSOVxJVwloeJD/f0SSSJK9osLBHKVyrQBiLmwwJvcV6UYzIglNk0LjJIwMd0vTSBRL5u3ayPDNMnPENwf5FBl8Aa5BbsYuQbpGmPUhJwL2l79zBBmTyAowtDw/376lCP4DYGupxmFU3PmGSH6/3J2lp4+eyb39Et3RxwQMzowpHJOGO2PonOngybyy1/+8h/cQxl8iqgVCYR7Mpybb6hVGYcPmIR+Il0NqFlVbZhgWG93D+VY+p8++1YORvYO930lJQENGx+nB3fu8ddrgdG3e9QITO34LglqTDX3GesrlgqSWfVLb+D7yJICtamEHTnj9h0L0PSRjGgaB3Fxr5yMX9ujVyxcX/7uCX394plMfy8HpFEwdBbpesyNAAMgtJB+fHos6kYtxAHQADhjHGzjgD6su9AwVaIOiAgfBwKnW2W7fyIuYMYsra3RO5YSpJGR8VxeXXM+hclf+pFRnWHzNnENxI+Hm56q7X62pDt0PKKyptBQaOHOPjt8Rlt+kTGIuZndUrmo5bc0xhKK8wD4N8QcKTYVUceMwUwd5/KyByT7kNNZ21yXOXiopAjUZpb2MY7gP/v0AQOKCfm0KN9hHajUQhuQWxXhbCYIayOjB1uL7CcCL2y2WQsgMZghDXuLXAgc8vrWpjhpv5ceV4xTtn7G/5FIiOPVMxcwaIpVGcUE0qQt1QhqDM6tiQkpLoBZgo0+8LHPMEcoScmvF2hre4des1/Az0NKoUl6bE+1ps6BATcRw0C4/A5ivMQHGkN+CEMHZ/irJOoc7TsxrEOPKUBXhxQ2WeFaAOJgkzfZXMhBSnGOVTPvk6gryqkZTruweES9vnYShy1M/NuTtyT4ioWkh3ULE+wnDrW9wzq04AjqYCSFfD8I2sW+BOcDONEq+YzMrDqRfEE+TEh9EJff7FNDPoYlHAoDiQGFYQ4SRiNAowHhZShi1T45rEMcQsVpo9/OUaxLnQ+gzDqs/wtEgqnY2tmh5fdrQuwTR3PVmhyEwxaTc6rkZ/tx9DfMJuD+9C0xb2FJMj1zQfdi4e+w/9J44REcCAns752pKYkpUC6CKB3p6oPcsdjsqs8BivZifk45iPaYLxSNx2TcPuIkzL2emZygob4BtzwleFiHEyDJmILtvPtpRH4zF5qxbQ9jW6QnECxh5LufrW0o4whYPNQVEG1saMT5yCojkPh65oJ0TWZzIlG6tqlZcFQ2VX02Gaas3Lg2xhB4VdAYZpfCf0EjIICIUWr8tUY1Ck4lGZJuxvRGRLZAOMhXoVALp3U41kTKHJNfIPWWVT/YDx3WoZvaYJMgVd6Pq/XOXPDLLKJKAVKGLCg2ddrgBqdDOMzAvGg4vqCgy3fmwr7qhNSl6X6Cg/vF2D9Y7FjTMk5niGbYP+AkT6ri+IJpwvEqcDyytGCK0gC7oR4JTjkuEW2aejpQHdcljEWmFtMfAc2TUqrY+Ekk7Q3rQPVuoSp2td2ZC/g+FnD31gwtr72nDUS3+XzbxJdPyXCcFSJfXYXga/d9Zi5AhfG9dgQHe4iZMcnuplk6cSaArCyAAgiPXA6gaalSkjHLyGNVdAl5xPm8YDAgGhOt6kinZO2QdMRHcNjeUpZQwfEb1qHxsWyS8Wk7Mxf0FBKE/zBFKww78RkC1TYyjfqoEeYB9hkb8ot6W85cgA87heBIVXNE5ZtgPhCwYa6PpAaQkHRaT5tRnTqsJ5mJre8LMxTWKXrqYR3aFJ1m5oKkqzl6hRnZ3tthqSlLlNg6c2nKUR7iCSAf39RBmzMXTis4DYfsTg3/Rb/ONqxDM+GUMxeg1nCiUENINLByWPpY5W5Mmf12Y/SaOmzxEOnUMxfOIDiX+TrVsA6dWvBTnXZnLuAeiGKnrl+XbKnq22r9eTRgnC4vlATVOWYufIzDOjhqt63e3t7D7e3tziDU0TxzQRqeUYufsuopANNxcrGYqP2ZFl5TZeQyoCPnwLVsru2ZC2cRnIsk/FkEh+HrkdXX1/fvzIC/Cco4StR5pDYPBuBmaDBwxxbErcYe3DY+2c5dSM0jNRXFYIkSdxVWBlyDAMBp+X4GcAhcbVdwzvuJeUL4MwoOaG91d3f/XU9PT3Zvby8RyISqairTQzTAYTQYyKevdsedIlPVGa6zkt7NeecoeBetJ3TpMb6QXGwADJCDonylPiPidOeEP3jBYZoXQHvryZMnR48ePfrpwsLCF4FM0HFCuepOr0J3BziMzcgHgeLzKFOKESi5k7S2g0Y0A7RdxqJhKrxTWGRwrDO9VyayVKrnHs7xQxUcEH9ycvKnoL2goNnZ2aePHz8e2N/f/6fd3d2fZ7PZnqBNSUhdUwTSk6xyiZycJciMhITlTi905845G9FDN6CusgEmNC7cB//G++5YmQvqofghCU5/f/9BJpP5D0g+iI/3/k+AAQBbD0Ba7u2UwwAAAABJRU5ErkJggg== + + + + + +http://www.reta-vortaro.de/revo/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eo/wikipedia-eo.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/eo/wikipedia-eo.xml new file mode 100644 index 0000000000..35d80add4c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eo/wikipedia-eo.xml @@ -0,0 +1,23 @@ + + + +Vikipedio (eo) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://eo.wikipedia.org/wiki/Specialaĵo:Serĉi + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/list.txt new file mode 100644 index 0000000000..91eb653833 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/list.txt @@ -0,0 +1,4 @@ +google +mercadolibre-ar +twitter +wikipedia-es diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/mercadolibre-ar.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/mercadolibre-ar.xml new file mode 100644 index 0000000000..52155ee68c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/mercadolibre-ar.xml @@ -0,0 +1,14 @@ + + + +MercadoLibre Argentina +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozRjI2NzFGMDJGQUQxMUU1QTU0MzhDNzBBMTQ4RTJDRiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozRjI2NzFFRjJGQUQxMUU1QTU0MzhDNzBBMTQ4RTJDRiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMThBNkRBMkY5QTdDQzAwNzYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4XdLjhAAAcAklEQVR42uxcB3xUVfb+pmYyk2TSeyG9kISQ0CF0aYKgKAusIisIiIor6LLq2oVdFcUKilixgCIIhCpNekgghPRG+iSZTPpMkqnvf96bUAIoqeD+d84v9zclb95793znnnO+c+99PEaByyKgtojaQ9SGwiK9IeXUtlL7D7VK9gteGwAu1HZYFH/bpJbabGq/sgCwln+U2giLXm6rqKkNYAH4C73ZbNHHHZGdLAAJ9OZuiy7uiBhZAPLoTZBFF3dGWACK6dXXogoLABYALGIBwAKARSwAWACwiAUACwAWsQBgAcAiFgAsAFjEAoAFAIv8DwHAgAeDyQ2V1Q7IKxRCb3JFqyEQZQoBShR8tLbyUFHFQKkC+Hye+TcMA1sbHvypFxIJA28PEzzdTbCxyoeQX4UAX/rOvYZ7z6MrWAC4RoyMFBXVnlA1BOJ8hh+OnBTQZwfUNwphMOhJuRo4yevh7KCj1gqRyAS5rQ4yKfs/MwA8emnV8lFbL4Fez4eqToKaejHqGu1gYmwh4IvgYG+Ah0sdRg83Iq5vMZzlBfRZAQGv+X8PAJ1BjsLyICSlR2Pnr07IL5FB3ViH4D5sa4S/twoh/ir08SLFO2pgLdHDSmyASGwks6cTiGFeRHOtmKhpza96nQBanZBAEaK6xgZF5fbIL3ZEYZkL8ovskH3JEbZ2Dgj01WDaXbWIDrmIYJ9CSCU1/38BMBjFUNZHYs9vUdhzxAPpWQx8PJToH1GFYXHFiItUwNVRDWt7PSBkf9CmVOYmDde8tuvNNe3yZ35bazunlkZWpcoWKRmeOJ3iQ6POgwByRUgAMHVcFaaOTYO7QzpEQu3/DwD0RgecyxqBz7f4kHuRw8ezGqMGFWLyqHxEBldA5qxrQ4j1R9covVd62waGoK3R5+YaMbIK3LDvWBCOJvqjqMwN8UMasGhOKeLCT0AkqPvvBIBVfHLWaKz+KBQ5+VpSeglmTkrnrN3OtdWsbENbu5MibGsEiIbASEzxxU97o3DkjB/8/ayxbH4+xg05DLGg5r8DAKNJhOTMeKxeNxRZuWpMG5eHBfefRzi5Gp6ITFvXC0rnX+eeuiqCtvhCozA3yxXf7ozGz/vDEOgnx7OLEzE0+jiEAu2fF4BaTT+s+jge2/ZIMG1sDpY+eBZh4VVtkbeHXIvwGhdyWfGtbd+L2j5fdmWX40hXxMp8jaJcJ3zwzWDsPBiOSWN0eHnZCbjIU/5cABhNYuw/OQ4vv9cP7k7lWLnoJEYMv2T+Z08ZjMjcWupEKCx1QmqWB3IKndDYZEXppgTWVgbiAjq4OWsQFVqF8MAquLs1QmhjujrqumIAYnOsOHvWD//+NB45l3yw5sVcTB6+l75uvvMANGs98P6mGdj4vRTTyd288uwB2HmSSTZcY4nddS9kjcoyW2zdG42EI8HIyJWDL5BAKrOh9FQEa2sBGQHdi0ZPRK0FLS0a2BBPiI2sxtihhZgUnwMvv3pzENZ18Z6s6acaITZtjcW67wZixhQ+lj34M+QyxZ0DoEwZiOfX3EVWIYOOcm8wjRg+oBIjBxZRuwQ310bwpGxEvsYCmVtkKbxr0kZqBg0fW36JxcffDqA8Xo6+ES64a2wo4mL94OfrAicnG8jlUiJgRlRXN0GhqMWlwiokJRfj+KkiKCoaicCpcfeYQsyZegGRYYob7+n6tJZ33f2I20a6moeUTG+8sW48LmRI0T9Sj/WrEiltTb39AFTUjcTcJ/oiMNADb7w6F5k5WuxISMGR34pQW9cIR7maLFCFEbElGBxTjFB/JcQyo7kzhus6z7/qv00tPFRW26K43IkYrQwHTwXjx91BCAtxxtLFIzF1SixZvLhjMam2CceOZ+PHbedw8nQppZQaDO5Po2JIAYbQPQX3qYaYJXeiNsD5l32qGSCTnodGtYTcnScSU31x+JQ/sgvkkFhbY/rUIDQ11OLkmRLs/voivJ2O3j4AylTDMH5uLMaN9sXaNY9AbOV05X+VlfU4diKHgMjB6cRSqGqaIRFr4O/ThAFRlYgJr0BogJJYbi1sZVowpPTqOhtk5LkTKfJG0kV3Yq1O5FKkaG4RkEvR44H7IvHCc/fC2cm2a/UlukhScgG2bT+HX4/kQ6nUQGKlgbe7GsH+9fBxb4KLE/udnjP52nprKGtkKCiRo6BYjtoGKdmGDEEBcowbE4K7J0ejX7QfMe56vPrad/h5RxYObs6El+OR3gegXBWCuctGICoyFO+ueZSU7/C7nVbVqJF4tgCnzuQj9aICOXm10Gp1RPlZH91KHWY4AFhFN6htSOkSREa4kluxQnJyPgwGE5YsGounl00Cn8//AwWb60EdkWpVIwXUSzh/oQRZOVUoKq4nQNTQsRbfNiKF5E1lUiH8/Bzg50NuL9wDgwcHkPvzhvT60ce04J/Pf4ZfD+Vgx8aj8HbJ7D0AdEZ3LPjnDJh4rvh8wxM0FF06fCHWksvKapGWUYps6jjrm5vUrZzFOdhLqHPuGDkiFBKJCM/96wecISW9+NwMzJ836qbna2xsQcKeFJw8lYn8AiVEIgEGxAVi2tQ4xPX371h5xGBEU1MrGYAO9fUa7j1bYXVxsYNUKoadrTXdj/iW4Op1dXjs8XWoUZVgy4cJRNoUvQPA2q8fxJYEV2z/cQk8PIN7nBVqNK1Y/PhGsqYMrHp1FhY+Muamxx06nIY1a3fjfEoxbGwlxFhdaGTpkX+piizXCg8/GI9lT0ym4Gx92wh1fX0Z7r3/fUwa1YSVCz/vONtkAaDG3Kplnp7I+AU9xhw5fJTpDSHlM4uXbmDcvJcwb76986bHqOmY1f/ZzvgEPM6ERC5nXlu1lcnMKmUaGpqZ2jo1c+hIGvPAnPcYV6/FzIyZa5i8PAVzO+XM6RNMQOjjzLkjk5iO6JRtHQKguciZuf/+xcw/Vq6ly+h7/MaNRhPz7D+/ZRzdHmVeeGnzTY8pKVUxc+d9yDh5LGJm/fUDJi295KbHtWr1zIfr9jD+IcuYuMHPMQcOXryNEJiYl15ax0y5ewGjK/PoOQAO75zGRMc+yZQUZfTKbf+8/Szj5vMY8/yLmxmjwXjD/4/8lsEMHfky4+m3lHl99TamuVl7y3OSm2JiBz3HBIQ8xXz2xaHbBoGyqpCu+zSza8vcDgHAv2WgMsnx6XeeuPeecPj4RfSK/2xobKZAZuACcFV1A0jBIHeD3LwKvPzaVsxf8Clamlvx0Xvz8S9KRzvCA8aOicSmr5YiJNgNL7z0E155fSsXdHtbXFz7YM6sKHz+vQ1a9U7dD8LFynEYPSsMu7ctQETf/r1y03V1avzrlR+RsPsCESMB/P3dQCMBhUVVxLBNmDghCiufuYeU6dHpc6so7Vz5wmbs2HUOD8wchNWvz6asS9arIBQX5WLSPeuw84ssBHsd+OMC7Csr8DS9ym+aOurk+D5hCOXH7pSPTwWPb9UrN8xa9ITx0Rg8KBBu7g4Qi4RwcbbD8GFhePLxiXhy6UQuNeyKSCkrmjA+CppmHb7ffApnkwowaEAAHB1teg0AewI4JSUdlUo9YiOKIRa2/mFx9/fTQq0PTiQKMXBwMPgC2161GjaPHzE8jGu9AfDq12bBy0OOt97ZhXkL1uG9NfMwaGBvbQ6VYPDAUOzdcwmN9/lAJqnr2gjIKhqIbfv8QGkeci81orVFy+XZMpkVkRMe/tuEVbifrzP27LuInQnJnKsLDnLv0WuwpC43X4nsrGwkJjchOsIAf6+crsWATbtm4P0vw4ksqCk4CskFSch/ShEe5oQBsb7oF+2LmH5+nLv4b5LTZ/Lw92e+QZWyCS8+Px0L5o/p8rnYwJ6XX4ULqUVIPleI5POlUFS2wKA3kK4YLJqdjSWzt3fNBaVl8WEyGvHZql+IaQpxNs0bF7PdkZbjguMn8yCgmODqaofYfm6UdYRh6JAQzsL+7DJ0SDC+//oJLFv+JV56dSuUVfV4Zvk0coPCDv2ezdDS0ktx8lQujp3IJQAaiQmrKYEwIcBXjcnxSnh7NOKHhDjkFjK3nOD7/fqN1lxU8/JugLtPI4aNLOTKxbUqKQpKnXHqvB+S0jxx6owLdu3J4gLlgFgP3HN3P8THh8OpFwNddyUw0A1fbXwMK1Z+i/c+2k8BsxGvvTwLcrubly/YUsfFtBIcOpyOA4dyUFhMLpkU5OGixZCYKgzuV45B0cUI8lNxiw4qq+3ww644GiH8rgPAFiDZpYJGLc8876pnv2Pg7KaBs6cGg4cVw6jhQ1FhhxPnA3DwRACSkpTYvS8PAf72uHdaFB64fxD8+7j+KUFwcZFj/YcLiGv8jK83HUc1uaQ1b/4Vnp5XK7xFxdXYtz8VCXvTkZZZDV2rDiEBjZg5sQLjhhYgJrwM7p6N4EnaJnnaVnswLebJHD4PXQcAjAlGIw9VKlt4+TaYvzO1NX1bFOebiKDVY07gecyekYLSYnvsPx6GX34Nxbsf1OKrb5Px0NxYLFk8DgUUnDZ+eRgKRR2lalIiLEMxeVJ/yvUNKKKcX6/Xw8lJDnd3hx5XdsqFImRklmM2XVMovGqVMpkEb66ew7nS9z7Yi4cXrsdbq+ZAS/f0zXenyMUUU6xQc65l9pQSTIzPRWzfMti7tVydvGHrbur288gNjRLS3S157h8DYCMj6zcKUVZpj1h+2c0PMrXNs+rYmjwD3z51eDT4NObNTMKhE6H4dPNAfLhezQ3dSvK1AgEfQYHuxHKrsOTJrzBj2kXU1KiRdC6fA8DBwQ6TJkTjqScmk1LkPQaAlZWQUtAd5EaK8MarfyF/fbXr7D39Y8U0eFKayo6GhxZ8QrGP9KrXYmA/JWY9nY6hsYVw9WrTMqvwlj+exy6rdICBAOALTF0nYoqaMBxN9IabUx1GxV8yK/pW0jadJxSZEBxejb9MTIW1lQDb9zmiX5QH+d0lWLxwHGbeNwhl5TXY8lMidKT42bOGY8b0QZwytvyYSFlFMfrH+BFLbuZq9WwuLxQKuuFu7BDZ1xtvvr0LF9NLMHZ0BIEiandMdJQfQkM8cPBwNpHBVnz86m4sX3IMYeFKyKx15hUeHVnqQu5ox95IJF0MxKTRSgyKyu7aCPDzNsJWZkRKlhda64WQWBnMCkYHgWgmY5AxCA2q5JS3ZNE49PEzT+Kw5YBHHh5FrkeFd99+kOs4Kw/NHYGBcQFcDWjK9LegVmshkRAZjA3Es8vvxqBBXSdP8SPC8dknC7HwsY1YuGQD3n9nPjw87NsdM2lCDAoLVVj15j4CXW9ef9SZ1Sdk/SY1D+fTvej3QHiQ4VaH/75EhVTA30eNrDwXpOd4mievOytkLTU1MvJPghuKaBHh3vhg7bwryr8skyfGcFnKtCmx2LBuIZY9PgkFhZV4dOlGnEu51C1XNHpUX2wkEFJohC1YvAGFRcobjgkJceeWuyuqusBvSEe5l1xxIdMTfl5NBEBt1wEQ8UsQE6GGplmIXw5EtV953AkAIkMqKaDrkLA7lUtruWk8IiqqmiYEBrjd8BO2TrPug0fw1r/n4p6psVj+1BR888VjFI9M+OqbYx2boSL2fjox/6YV0NEj+2LDxwtxiZT/0N/WU05f0i7dZCfvbchmAnxqOr+GiEbM9gPRaFSLERmqho1VQddjgFhIvlfWBz8lyFCpcsHYQflwdGnuuBtqA8DVWY3qWkd8vUWArOxi1NY2YtN3J3H0WCamTIq5oazBfmY5BBsPLgsbkLOyFcjJrcR9Mwa2C6I3E3ZJyqKlGyjO1GEkcZLrr8GmxhHhnti56xz2HkilBKGRAnQZ3nn/APYdLMLf7k/HnOnnO7eOlQZ4eYkcq9ffRVmQCSuXKhHic7brALBia8Pgl4PhqFZJ0NxihQmjcrpkFcNii2jw8HHomJY6nEuBsAy+Po6YPi3uylajW8mp07k4m1xAqaOIA4cF5fdqUra21vD3d8Xq//yC4mIVxo2NvOE6LAhs+XvfgXScO19EhDIbJoMSTz6chBULj9A1mI73tW0B17ufjsHxZH84Oxqx/G+nIbVSdg8AK5EKyvoYpGYyKCjxRKCPirIb1RUe0NFRICKaPmJIIf4yKQP3T85FXaMjzpy3w4TxIZT737rSqidXwubplVUN3Lqjn34+S6lsObcCwsbm5uyVVbCPjzPeeW83KipqKPPp225UcZmeoh77f83GsvlJWLXiCBbNPouRIwogoJS6UyNdChw/GYC3N4wn+qTFzLtbMSV+H261IPWWALDSx0+KTT9ToOSJkJrljTED82Dv3Nq54cmYgZDIDHD0aoarXIMfE4KQmlpB6aYPt+iqnAhaIvltVnHXW7bRYGaAC/82BnPnDKeALsLmLWeQmVVKcWIAt0zl+Mls+Hg7tVNyeKgn7OUyvP/hfpRX1HLuSNxW86mtU+PNd/aiuroKLz11GEERKkhEhs6vqibLryy3xdOvz0RNvZQGgw7/XpnB7UO7pXPoCAB2UgWqG/ohg7xPfZMdcijKTxyRA7G1sfPuqI24sczayVZH8UWOH7dlUYBOI5Z8FOdT8vHA/UO4+YF2N0pK7RfdhyzaiQiTAwXSCHKPEnzx1TEumwoIcMXDCz7GpcJqsuDwdpyhf0wfmIhZffHlMQq4xZT/iylA5+HFV3YiMbkSf38kCVPuyjSXWzrbH3bFdqsIK16fgfOZPhAKmjF5rBZzpuwGn6fvGQB4dFfhIVbYtN0DLHcpKHFBebk9xo3MhUDcyaF6DU+IjlJgdFwJxzg1mioa9hqUKCToG+bCsWXuMMp8KirrKCu5cQ6CrbzuP3ARLS3NuJdIXGRfXyJaCZSyVmHMqIh2ILIV0MSkfPLzhdi2IxOHjuTCwUaB55ecxMK5p8EzovPL14XshkMBXlozBXt+60tkTcstEv7otTQyrryOnqJj4uFwAisf88Xr77sROeMj4WhfbmHrKyv2Qmaj6/w+ALaz9JvofuWIjivnYopCIcecZXPx5PKdmPfXEowaGYqjRzPJWsnn//B3rm7TfupPCgdHGZqbzUxp2JAQrP/wESJan6GpsRVr1zx4ZepR06xFXYMJnm56vPP8LtjZtMLbox6Obs1Xdld2Ssjt6PSk/Lem4Ke9/clAWCPSYsXiFgR4HO14ftKREXCFOAVWESsOQKlCROwUuEDxIDPHA8NjCyFz1HUuMF9XumAVYOuoxYjYYhSX2mDXPhU2bU7nJjrYjg0dHMj592slPaMMn2w4iMmTBpDyzSv1AijzCQxwwedfHeXWf8rJ/19ILcGLr7IlCCX+SRZ/z4x0uLk0wZpdjNuVnTsU8+trrPHsqunYeSSSK1OwdayIEAb/eXY7BPymDp+q04tzVU0DMPnheGhahOTv+GRZYoQFKrFqeQJiBpSb/Wh3Vn+QZRn1PGTluFNAM+87eObNCfDrE4SP3p0NX19zabusrAbLn/0Bv50s4jKpRx8ZifAwT85Vsez2yac3IS+/jlu1y27o9nJTY9m8s5g7M7nru2X4ZuVnXPDAv9ZOQWq2F2ykWs5NCvl67P/uHNztj3fqlF1anp6vGIfpC6Kpb0IuOLa0Cskt6bBkzgnMm5UEK6nBDERX94TxcHXNPrnxn7fGYOWb42Fj64j4Ef7UWT6OHi9AS3M18QslzmU4QVVrAw83G8jJLRUX13H7fJf+9RTiIkug1QsREVwFN6+mrt0Xez9WZBhaPr7fHocPvxlJabQ1VysysVtzeAZsWpuF/iH7Ot/Vrm7QOJs5GQueDaXsQsTV19mZH3Z3+tD+hfjHo4cRFaMwjwQduidtYJw+24eSgP44l+bMrudDv/B6zL/vPIYPuYS8PBccTwpAZr4z+WVi0Q46TBqZg8EDi69GOW0XR6bYbAhZaW5Y++VoHD4TTGmskQA2cZbPKn/9qlzEx+zuWve6s0XpQt5EPLoyAmqN4ErGwaZk7MaLeydcxMIHTsOjT6N5yOu7OSLadtboW83XEVoZWVpiBlhkHilXwL68g1LbxWteMwIriuT45peB+HFvDBqbyOoluivZmVBowCerszE0am/X7au7m/RKVSOx8B+DUFRqulJfN5r43HMaXJ3UmDkhFbOmpMDXv+6qUkzdAIJ3TRbF3OT/6CbQbWvPFMVyfLcrDtsP9OMebcA+r4Kd/btcSHR14eGTVSkI9zvUvQHeE9tUG5pDsHr9aOw4YMcF5ss1F4NRwAHh4qDGuGG5mD4+DbGRZRDZGK9Oa3Z3FyV6xsWx1m7S8JCS7o2dhyNx4EQYqmpsuTkQocDsu9hKbkuLDuNGaPDGilNwkWd0//I9tVFbb7TFL4fGYu3GQNTW89pVK9m50RatiEv7+oZUYOyQPMQPuITwoErwrRmzEi7vWrwdcu2mbhqReYUuOHXeH3uPhSM91wPNLWJKs/Wk+KvWwZa12S1VLzzVgKnxPxEhbegZ/Hv6UQVVddEUrAZj1wFbckXtgTDRZz0xR5bA2Nu1cIW94XGFiAkvJzDMG6uv7FZsqx116wEe1+6o5109X7XSBjmFrkjJ8MZJUnxesQvq6qXcNKqY/Dq78uOKYRGzNZkYjI9vwPIFyQj0utCzA7A3HtZhNAlxIWcwPt86FIcpLeYLeJxraneMkce5KJbKi8jS3F0b4E0ARIYoEOxXDX/vWspmNHCy18DGTgs+W/JgOjAhdPkYGk1N9VZQ1dugpk6Gkgp7ZBe4ISPPA+VKO1RWyylro2sLzRmN4LrJcx35ebYAODCGh2cW5yI68BD1oaXnPWBvPq7GxEhxIXcovvzJD7+ddqJ4YORS1usn19lJMhYM1lWxo8ZEr2yObW/XzJUMWKbp4qiGnN6zoLDbSS8/LevqJA5D5xdxyq5XW6O2Tgo1kcQGylzqm9gtryJOyQKybjaYCknp7G/aG4WJczXsPY4aZsLD9+Wgf+gJGhUNvReCbscDm/QGMUqrwnE4cQB2HXRGZo6OI3BscY3t7M0mVVgFs9kUO1LY96YrO9p5t+rRFdLKY5UtMCv8emVfAd5grsKxW2ID/cWYNl6FMYOTEeKb2ysWf0cAuFaatc4orOiPgye8iDx5ICffyG1hZddlMoyJA+aP9gR3a0SaWPLEcFka69uFxF3CgoUYEFlJii+Dn3sq7KTK25uE3cmH9rUQGOVKV5SronDwuASFZW4oUYhQV6fntimxrkogEHCgcJbKY/94v7tvl+HChDlWsL81K9zE5e3W1lZwsBfB21OPAK9KcjF6eDlfRB8vJWSS6juXBf+ZHltpZORQVDkQ8bEmltsX+UVS5BfyqJkogXEkfy6lwMlwT0a86dwIZTFWYh7kts3kgmoR4CeAvx+DkIBmMLp0eLi2wIt9hA2/Fn8W+RM/uJUPrV6KJrUVmjR8yGz7oEUnR0ODCE3NghtGAWv9tlIj5HI9rMUN0DQVc4vKbGTsExc17BJj/BnF8uRcCwAWACwAWACwAGABwAKABQCLWACwAGARCwAWACxiAeB/CwB2GW+QRRV3Rti6bqZFDXdMuL3031v0cMdkJ+uCWGEfbHaXRR+3VdiZ/gGXAXCkto3aKItebouwU3LTqZ24DAAr7FqR+dTmtgEhsOipxyWfGvv4rLepcRPR/yfAALBQYw6aQOGaAAAAAElFTkSuQmCC + + + + +http://www.mercadolibre.com.ar/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/wikipedia-es.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/wikipedia-es.xml new file mode 100644 index 0000000000..b22d159ede --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-AR/wikipedia-es.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (es) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://es.wikipedia.org/wiki/Especial:Buscar + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/drae.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/drae.xml new file mode 100644 index 0000000000..26f6e04ee1 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/drae.xml @@ -0,0 +1,12 @@ + + + +Diccionario RAE +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozMkI5RjZGMEUxRDUxMUU1QjNGQjhCMkJCNTFGN0VBNiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozMkI5RjZFRkUxRDUxMUU1QjNGQjhCMkJCNTFGN0VBNiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDQ4MDExNzQwNzIwNjgxMUEyRThFMzA3QjczODA3QjMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7RHLvSAAAn10lEQVR42uydBXAcxtKEx8zMzMzMDJKZGWVmiBlkZoY4ZpSZWWaSmZmZmRn/+UY6xcnL+6tST7ZPiTelshSdTne7Oz3dPbOrAO/evROfEVQ/GulHRf3I4fP1z+F3471+7NGPxfoxyedrCeCzALH0Y7V+pP85T99lHNWPkvpxK6DPTvf0T5P/+fMXGT9/s1y7/dC/LkB6nzkPGtAHdtL4p1dfu/MEaTtotvQcu8Q/RwFz3ogFqOLfXnnRXN77JWGcqP4diqqwAFn926sOFjSIBAoYUG4/eCqfPn/2zwuQNaB/ZDseK3fKdo/ucuPOIxk2ba1/XoCggf3Dq3z15p1cvH5Pnr14LcNneMrT569kw64TcuveEwkUKKB9L2CAAPJUvx87WkR5/uqNJI4bzV+sgFMvAJO868h5aVq1kLTq7yFNqhSUc1fu2AKEDhlcCmRLIfPX7pEL1+7Kk2evJFyYkJIiUUy59/CZtKtbXN6+/yBxY0Ry6gVAB3xxthe1//gluXHvsSSIFUVcGg6WPJmSyYePnyRc6JDi6XVMOjUoJdEjh5OAAQPI1CXb5c3b95I0fnR5++6DPHjyQhpWzC8rtx6W1EliSwP9PFqkcBJAI+RnBPzFOHbuusSMEt5ghsnLkjqhbNxzUvafuCyZUyUwaKlVOreUK5xZnujOj1OglaRPHteXCS3ZcEDyZU4uvVqUt68fP3spvcctkyxpEopr7nQSv3BbaVy5oIzqUlO6jVoktcvmlrsPnkn+rCl+RgAjdenOCi2FJGiQwNJqwCxpVLmAjOlaW/YcvSA1O42XEysGScjgQcXr0DkZ7bFeDp26Ilc2jjQhxsKs3XFU2gz0UJgqLNc1KQcJHEja1HaVAycuyYQFWyR82JASVSMgmD7/7iMXJHG8aBJG4Wv6gEb/7gjoN2G5PHzyUro2Ki0L1u0zrOYjcdzo0ue3ZXL49FX5tXsdg5K6XSZKmFDB5cWrt5I9XWL7+cgRwsjt+08kiv77WPH/y5cvFhX9J6yQuWt2S2XXbNKiRlGpUiybzFi2Q/pNXCFD21eTGcu9JG2yuLbY8WJGtlzxr1yAyq7ZpVHPqboIL6RNLRdNqCllk0LP2Dkbpa3u4GJ500neWv0M25eNbSP7jl2Sl2/eyq/6/Wcv38jsVbskvCZdknI6nVAwfqdGSdFcqWXSoq2SIHZU2bLvlBxXiLul+SRD8ngGY3z8MniOMajm1Yr8OyGo9QAPuXH3keL+ezl/9Y7tahIpNHLvsYtSrUQOCR4siExfukPiRI8kERRGHHT00o37poBZJPLHnFW7ZXin6vb9Q6eualLeJikTxTLYql4ypyzU6CJSEG/RNHFvmtpZJusC7VaIixcjsm/u+FEj4I/4pTV0YjKmTGA4HzFcKDl7+basV8r5Wie4UPZUsmzTQbl666EM7VDNFur4+Rv2weQzXuvCYcRFjRjWoIifn7Vip+w6fN6+37x6YVkx7hcTbC9fv9WvixiEXbx2T4Knd5Plmw9J2UKZjLb+KyMANxMKuXbHMekxdrEmylDyViMA6hk7agS5fvexZFUW8+79R9l+4IxkVmYUNnQIWb/zuNQpm8d+nskdopjeqmZRSVCkrdxV7t+mtotC02558Pi5DGhbWYrkSC25a/aR9x8+2UIRGURTBF10tALPSw7610XAhAWbJYlrewkVIqglwvWTO8rOOT1k9uCmpmpjKFTkSJ/E6GbbOq7SvUkZKac7NrCq3om96vmKqygRw9i/zzUntKxRRAa2rWIsiLH9wFljPFE0SpIniKFwE0liRYtgcHfn/lNJFCfaD5/8HxYBlxVKPn76LPOUrSRLGFOyp00kg6asll/qFJOYGgH1uk2SYR2ry5jZ622ycqsQ262K+OSFm1KmYCZZvf2IiS44v5IfGedeV2HloCXxUV1qyea9p0wdHzl9zSIhrMLP1v1nTMSVzJ/BFiyvagcU9r9aBzBR7mMWG1MBj/Fx1k/pJKuUerIQ5AMmeuv+0zJYF2i/cnvgJ2yoEBI/VmS5cuuB0c/USeJY8iZxLxzRUnHf2ztigXhuJtwld1pbJM+JHVUXhDV4C+YEVtgPXQDsBRYgWfwYslN3+JIN+6VDvRLSrXEZo5v4PGB33JiRVBEHNOsZdhMiWFD7HOo6dfE2WbLxwH88NzAVKXxoVc+vbaeTP5rov6ULZPzpBf3VwMEMrlSxYY8psnLLESlVIIO46q6Fep64cEMSKq+/ockZhsTCFdLJB4pI4EwqVPO+Jl/YE587RvkimWXu0OZOa8YFdJYXAqxgR5QrnMV2PV7OFOX0cPZYUSMa++nfupJNbmGFphkDGxvUpEocW0Z0qiHzh7eQLdO7ilu5vN4WR5LY9m/JfBl+2tF/Z8DPj565Jh2GzjN1S16Ax99/9EyWHzhkYuro2WtS0G2APf79h49mayC0wHksDIRaGs0L128/kirFs/+0o//uQAGPmOmpjCW9jJy5zhYF3QCfp9DCAmBBJIkXXa7cfGBizXdHKVWFYZnfpBHT3q34zwX4uwNoSVmqo3xUrK9ZKpd9fffhU3n49KVi/AONhuf2OJJxoEAB7Pt/NeqVzye/9aj7E4L+dmLS3V6teA6jibCh12/f/75jFJYQW8lUXGVMGd+i4Ne5G+Xh4xd/KNCTM1g0IiRB7Cg/F+DvDJIxxhwlSSYfWCmUI7WkSxbHlK1LLsX6M1fNCyJHJFcxR3J2H73Y2JRDY9xU1pQ2ady/NNzIHTxm/c4Tcu7qHXmhWoHqWV2fJP6PXABEVPfRi+Tq7QcmtPDiY0QJ/58vSid8ZOeaMmKGp6llFuPug6eaWGObRcHEvXn33or0iKtgQYLIZxVk/AeDIoKIjHChQ6jCXiVxYkSU+hXy23Nv3Xfa8sv5q3d9ypwhpGbpXFYla9J7uqRLHk8ypIj3z8wBDdynyJzVu+XkykHKUB7KjOU7pFGlgpIrY9I/7EycTqAGu3nSwq26WOGN609cuEW27T9j8JQxVXzz9PH6UdHQTrQCRZmlGw/ac/M89A8BRYl1Qb7oBjhw8rKJvWxpE0mapHHMi5q53MsWdNOeU9bqsmFqZ1uYf9QCsLuoTOH3RFSFygSA4R2HzTfLYFr/hpZUaTmk3Bg7ekSLjgMnLtuOzJclhXVI8JgNUzr94blhSktVDQNFlCXJBQd1orExUMTpdVcfUWoLW8qqv3eURhc2Rp3OE6yYg2l3WXNFQs0Ve45etOfw8nA3LfKPEGKlmg23yS+WJ53Bw6vXb3WCrhjdrOya1dQtE42lwOQzapfOLZHChbbPL12/L2u2H7XHuOZJ+x/PX6ZgRusPwqJ+9PSFQp23ZcG4p/rBATeMFLpILGTzPjMkgj5/IE3oGHrxNRLotjjvOUxmDmwi1TqMs6jw1xGAjZC3Vl+DBpQrk3Lm8m3LAw0qFrByY6aK3SVrmkTyTqGnfOHMVqIcNn2t8X2zpjUK8PdjabId515HCmsy/m+DBarvPtkmHAYFW/ozRSUaSLZ4UDQAECXAHjnnkIq4k+dvGHMid8Ceds3paUUjf5eEqWDlqt7bbN85Q5sZs2FQFAF6yrcaZSIpU6oEZhHvO37RhBbRYJb1zfuWG+hgQP3yMxTfe/26VBPuZ2VA4cz9BG5gQ1TTjp69LhHChpYKRbKYR3Tm8i3rhPh6YFO/e//B8soWTcgZU8S3qGKReb38zs4aCW+PTpchU9dIIVXc22Z1/2Y54ZtAEDCStXIPKwPmzJBE2g+dq8Kqk9WCGeBsBJ2gMbM36C4NbAn3wIkrVh2j7JgtbWLrYCDZYq6RJKcs3mZJlaiBir5QGIOiPnvxRjoNn687f4qMnbNBEsWN6kslHZOPkr65dYwtOFEJ7aRof0EjJbpG2Ja9p6Vxr2lSQ0VfKd0MwGSJJsNsAYnYci1H+h8IoneHCeHN9mlZ0d4MA4+mdPMR9jkw07N5ebnz4IlsVuYBhaS1MIVGB4vGBIfQ3f1IlS9JG1t5uuYQ2lKSaMJ01VxCNQzuT1mTmnD1Ejmt2QrG08B9qhVnyDl0VDjo5+TFW40K45qSg4AeouW6Jmde0+B2VaVJr+lWtmzvVsKYFjDUbvBc60s6urS/RZ3TLgATlKBIGysNNqxU4D++Tx02SbH29sZJdOt3HZe5SkuJhoaV8lskFM2ZRhas22v0M1SIYLorc5rwQjcQATyedpOvsR1Yo5MCi4KkGypkMGs5gZqSvMFzrG4igZ9jwdjZeEqM6JHD6yKHkra62BTu+fkWNYrIMqWz9CV1qF9SRqomQWPQYee0OWDx+v3Gq5l8YKPXuKXWBEVCLaY4y84mObIAw6avsTfLYJcBNbSQEEEkRh7brm4xTdzB5OyV29Ky/yzb8RRX5gxpZqwHZsOikjxpT+FxDJIrE9y451TNEV80wdYwATdvzR5ZseWwCrNIllMK50hlCZ+cgHtKdY3iDyXTCNka23NRDqU9sq2+FiLbqZPw/pOXbKcyqFaFVjiB7j3S8AYCTl+6Za0mTBaWwZoJ7S1HtBsy18qQwBI0Ma0KJLrb2L3AEGyG3Vy1WHazmukbff32neTJlFx3a3DrHWrnVsxKmPD9Cq1HWwQdWzbAPCPHyJE+sZUuKUlCO6/d8XZRP3z8aHSUXiGSOayMQdG+R7NyvvnkpUa4X5cy/TQJJ4gV1brWGAgg8JWd2rq2qyz/ta1NFJ3O1HPphECJTlu63aCF4nmXhqUMJpjk7k3KytR+Da1h9+OnT2YtwMuBBBYFqILWUvMNGzq4MaBRs9YZbN3f9Zt1T7TSpM+COEb8WFGkb+uK1i19//EL6yNCKQNLc1btsmjiPUBnEYKOBWLQyggE+XUd2c+TMGyEEG5WrbAqVE/rfCtVIKPtcKpTQMuG3ScsGSKaoJYkTyBocLsq1vXAAJ8b9phqC8kksQDkA/DeMaCk0Mqyqh8quWS1CBuseM9zDu9Yw6Isd40+MqGnmy8zosM6izI0jLpEutAVimYxJQ2cMenko1wZktrXbAwWl7pyLI3sSb3r+5IKp6WhU/s2MD9m6NTV5lTWLJVbCmRNqbsnrJlq+DsUU3izR5b0l9OrBpu/A/46Jh8qWrXdODuEQWLHzeQwBs1XXw8iAwF3RieehchU0V2FVnxZOqaNUUd8ohcHp0jnEQtMJTNOX7xlyRpm9VLhprxGKY+B/7MoJ1S/EDWzVnjZArWsUdQWl9YXv578b6YDgJL9C/vIwpEtLdkRvphcvAHeuMN0A/vRB2D+ubVD7f9jsFVuO8ag6r0mRxQqEVCxzRibHAZFGdoL2aXQ2zIKW9BIfB2YFTnjqOL/iBnrZIHnXjnnOcySOAoX/cDvptOOtngMQljS5mldrAmMgSjkuaG+wCaLy/P4CyGGkh0+4/eDc+wiWA2KFbp3U3clA5uB3n46nCNFCOP7eCYf9UwvT6tarpIqcSyzmffN722P7Thsnh3AgNGQH6h6DZu2xp7PY3ATS9QkShZhar8GJv4On7oiKzQHcb4YWLF6g8LKeY1EzhjQwJWiZEfJnyWFiUAGUEmxH0gFojbvPek/FgBrmJMowAwD7Mbfd0ALAoiRNXVCw25cztCaOFmg/hNXSGqNBsQYkENvPyN5gpg2oau2HZEHmjwfK47zePpHE2hCJ0K66u+s1n6c7DtxSSc4kCXUmh3HS0pdwNpdJlr3RN1yeWxBiLg4CoFXdTEcxIBFces22fISI6oKPdoYaZ/EgSXJOwiGUy8ADIXRvN9MbwV85qpvkRzMJuGCt/TpY/9CJ8H6Op0n2uRm1x1IX1All2yWzBmoXaglzIfJZ0APgRDsgxEKU+N71LWJoie0g0ZJ0z7TjV6O7lJLc0Jrsxryay7CYsasY8Jpib9+56H1DmHycSDEUf7EtuYMQoYU8WWHR3fryD598abzL8AxZS+IJTg5hpunTh47jEGSIxe4K8VkNwUNEsT+H97M4g37pXTBjHLk7FVxb1ZWYuVvKa0HehjWg9NYGxRz2PXACdDmKD/iVmLoDfqlisHUMd2tJ87ftII8OQgxR1/paI914jGoiW0EFgFbAeWMdkEp83XrWi62OBh8nD+joRe6zKHAbbq4Tr8AeOvsxE4q39m5qFzayBm8GeyGu/qmSYSENzYzpUWMN2rAUZQtoR/AZqKFxqwujUoZdS2gX9O2yBiiLKvHmD/eFUFkIZ44nkpntdeh81bsWaQKm4UDRqCUKHUWD7i8ccc7J0WKENo2DMoYqsuCcb6Mf0nKRXKmNirq9AuAJzNXE+TSTQdMvWJLb9x90iZ0wfAWhu90MJCYmSjYC9YAFjNwhEqlMDO5T305qbuYc79QUcQSdJRki+UAJNDmDoNxDOxjKHAtpb6BNWfw2NoKbfSdujctJy2qFzE6ikpnRNAFYNev23ncqDLdeeQTBhPPQNhdvfXIKmgc9nD6BUDF4kjOWOZlkh7zbNW2w7rjP0jJpsPtGOp7xWYiAcxH3fL/iBz8GuzgAZqMgaTgwYNI/JhRrEl33rDmvk4qO99xDmD11iO+/3/dzmNSpsVISZYgugk4Oh2Am4GqsrGxObjH12cu3bYdTVJHlXsdPGeRyvcolbLosKUQqrSBo+cvX5tW4WwZFNgvRyB3d/deflkBc2kwWCcuqHFuFClsBSaECYYK7aH4DjRwaAIaGlGVJwILE69VTRfbcSTC6Uu2Wx6hMEMR3dHbw6S0GzJHTmpCpFrGz5JA3bpONp0AtmM34ym91sWl85rijdfBszJLd/+xczcknk46kYjFDAsjBxFRJHaem40DRF6+ft+wf++xS6aQqRVjndMC6ZQRkKt6H0mfIp6cWjnIdg1Q8UkZ0ClVnwx28WndfdBEdhJUkQlHzbIgiB08mZwaCXlUC2BPPFZWBbbD7RnAAHUDBF1qpZYfPnySriMXGk7zOCaUwxzepl5cuabPsVp3OpO8SqMFEw5TLXCgQDapRCivZ/z8TQaJJ1YMlEXr9xk5IE/AhF7ov71bVLAFJ085JQShaplwNxVGwAsVJwZvgm6E0V1rGdaTEMHbgZNXGdULom8eOGHhiudNZ4vhXSkLJA+Vk3dSVc1wVKXoCUIwuZXLZ0YfP4dNTWKFGbnkTqPKOLPlDW/T7bk9jhoFCZocgeVMZGJHswFgN1WVBOAtHVTRdtdrnHVuOEZFl6yyXSOICCVnYJk7FQQx8XQoE7ojVAVDBS9cu+erejGxoIO0nEAVOw1fYBj9XCcJFpRM8Rnujz+E73L28h3DYDqeaTcHKji8jT0Aja2M2tWcQu9o5tQJlIaGtp89rvDC4nKsiYmC/uLrABtgORMJpTxy+qotAJB5VgUjfs+ImWuNreGucpiD333WR0yygAU1cdevkM8cVn6ubtk8zlEPIInivYP5Z1YPseLIlMXezVS8aPAypNJNGAvnvqgs8QYomnDRBsUaaCiCqHjjodbRzOPh7rl9GrYQUXvm9ZLf5m0ymMIfooh+xqeyRZeDdzOXWLIFckKHCG4RAZ+Hiu47fkmWbT5oiR8HlMUEUsB1zo7FjRFZKrUZY6Yb+YbcAiGIq5Dl0DE5qvUykgH88XN+cRPL/wxBJNcdGp54MNC5OwoHYDitKEw+yY4iPBdygNWcakHBYqLh9yD9QyoMrJnQQYZ1qG4FE9xKbGAwnSoZ7ChtMm+LApbCQDhxhPWOtSzGMchBRFGAIXHny5Lcm9/rZHGyBhiEUS0e1cpKnNBMbAgGr58IoqHXrdsk6Th8vl2JkzFVAqtBkyc41Ul1r0Te9BYlfDhFBMDpgQVeXFJlO4ivB0+e20Tc0sWAksJOSIxgaLnCmWTc3E3mMJIDsKhpR0HNUoel4EG7CLsXv2bjbu/Ll+artmBn4+nQ0BU2TAjTBkzEI93hTDCJ2qXhEDs77LhPjituKH0SjbAph3IOHDig0U76hMgFMCQ2BYdBsECGTFtjLTFEFrmL1hVyFIcFgVYiD/X9wyOAN8GVALAVLGN2ME7jovX7zZdhp9EJxxEi8Jf+y1s+uQHF/PHj711slC1ZQG9bIKgl8+zpkhiFTJ/CuxcUikoUHfMpqGMrL/TcZzCIWobyOnqQTGzpZEdTceeoH5PEgQ9+L8KLXLFDc8zq8e0tajxW7LS8QS8qLS5MPpUwNhGXhgCtAfQ/3qOT5IAPVsKDN2N0kWwpYuO7c98PhRaSGVcJ3NFoAO9507xB1Cos5JlS1lSlOllCraj4vFkXwtH+gR2NWYfNTY0Bk42+T+rF3hWu12Z/VyyaVWYPaSq1Oo23WrTDeyIv8DW1XoSU1+Fz9nxMKheCUAIFCpv3nSHzhjaXnqoF6GviZ1HrKHhc1Plr9kqf8cusHk0CR7c4xQKQDGluIrE17jnNdi9CJ7pSQNgLVjS7nu+TINnhCLRyRTLb3T83dVfz/3NmSGpyn9BmUegLQt1uU5xnYoGWeEofd8zqbhqCRSVycF8pxAA5zfvOtMiDszPwdXjuyOHDGByyQQpmT2m6hEiF6kJhYT/klrJKdSlH4tRiiRAhLBSlTtrg3yvEAV9E2P3Hz5xjAcBd8P3S9XsmfjhSit/SqHJB21ksTju34gZV2BNcpEGSRbFyW4r3IYo45v2wmLSg84bZYdSN2bXkgq0zukr2qr1MCMH5KZjQhMtkLNXoAObQGBh5M1d4mafDQuHMwu3xhdjdFOYZtJgAj7x+8hSEAbsa93Xn4fP23CwaiR+GRDInZ8GQzl/d+l+PRX33BUiZKKZOXDJ7syQpejK52wevHQyNHS2SMR0mmh7RTApR2MtMrnctIJi9Geq2LBJuKNgPu8Gh5IB2vtr9rVeTzon2Kvi4LxRI8XZUg9l5Yn5mtcISKvnCtTuWeJl0hBiwBx0F+2+rRiASvvh04yEEwXQGBIAiEN9DO6DiA+pCEsUYir3HLZVI4RL4llSdYgHYgTAeWkgoE8K1d8x2t4mmKoayhR193dLH4jx+/tImAN2A/YsYwq6Gk0NngYBHT16asqXJK1nxDnaZBzmhnCrdP7eHEHVsgiyaR6Yv2258H3ZDiyIFIagxg+OtHeuX0B0dxiaRHIEtvUAT+QLPPUYM+N38ywVRjjNm9AXB+6Gr3rb7F+dYAFgHoQxL4IVC3a4oD1+wdo/C0U3r8YeBYMQx0RTs2aWXbtwzDOZ6GnwZxBJ+DZQTv4YjQ7cfPLGfIbLIHTRroXrBXweH9+2v0ZkEr7FA+B6Rx8+SvHmN9JIy4VS/6Fkl4sgPnJjJX6e/TShwBS0mrxBlT/Q18bMsNpUxFH6/CSvMQ/KrJPw/01B2BKwCk4wXxY6jFku4N6xYwArb43u6WU8lHgyd0kwkCdbufdM3CksB+1HCCK9kCWMYHEE7mURwGg7Pc7IQFPfZmahrxwAuiEYEHDuVnMLCk2tYtDCaUBFc2MqQA14zF/kt3XDARN6EXvXsUhBEF4tGwR6yMHvlLhObbBYWY/bgJr5K2CkigB1Ljz8GGvQMnu5WPq+M7+FmImbzvlN2iI6JwTKAWVCOhFND93hT2BBENEkOkcPjuemQpMxjiQwWl8nEsWQy+F0sVo2SuSxRIsaAPBaHEiNwxOOBR3Ywj2fn83gMQvLCYeX7JGXyQ/46/cy2pixKtIL7sCciC5LArsfLWjGurWRLl9i3HuEUnXFYwUUbDLaWDqxbdiNQwGQF1RcKZSTZWtLUndereXlvZTp0nvX0w8XxW1ChDLeuk0wbwEpQv+xcFo6Jo6gyy+q6nyVuwdZWeiSp1imTx7warrmkADR29kZdzEdS0SWb5QVKj/QMcYeow+KgHoyAo+sC+KQbj4V6+/aDaRTa1GneombBIRFUOJCF7tk7v5fR3x8eAY48QC8PapheHXYMHXBAQURNrDCVsKFDKsdOYrsL04vd7jmxg1nOwAkwQbLFeOOEChPB/RC8Wfr26bzmzQMdDKyMojlTm02MdQH3x1KmksbE4tCyu9kMLBY6gSoYr4/fg9Imd7F4VVyzGzRSS8DlxAYJqlEDE6ONhX/pxuB3lsiX3iLbr07M+Ek9gMkjQQEXqF+K3yQ01CnhnSpJbIOEAZNWmisJnaRcmLxER7uemKoTPgx9/xTiuTsOkcYk4bZyN6iXMitHVxyDMmJShZdf6haz6ILm7lSVi9Xg6D1CPwAV5JFKrlmNSgJXUGAuDGTjMKFMPvBEwzC0lUYwPCJeE++ra+Mycm3TKGudnLxomzEkh55wigiwdsRGpe1YD0KGhIvj+edBgR5fn11FsywRwtfgbbcmZY0OcnCDI604pPj9qFIudsVvsmK5T28O4om8ULtMbtuRXFeJwuUDuGKgvrEOEF1sCCxtJh4xF1k1BjoBW4OSJtQUqsljOaLK5NNSw2FCh+qFUNBR7RcmnJ9XxNhluJkMznOhPh0D5oJNADTRKEUDFF7OSVXNYD8QYTdhBQ9id0PAkNAOMCE8eygiTAjLABUNA0Hw0WtKkoTTY2E4BrmCNheiAlZDKwt3xnEpOBGIuHr64o1RZnx/oIkqF14P+YgTOs36zNAFzGoEASXMgCqj9skjTlkT5uoBkhldB/RrMumYcPw/qB0tJD1/XWKTRTMuJ9pJdogrbN6YUSKY08lNusAUk0yLCv5Sm0EeZjOTDHtr1FBzxo6wCX/5+g+1WgxBXFD0Ba0s7HKghEVgBwMvHBrhYDdRh1Jn58N6OCTC/REwOdgX+QloQx8QEbA8hJrTtqVwCh0aCPUDYuhi4BbEMoW872qDa9NsRQ3h6LL+NiEpEsay3UXvKIyEHACUcZaL3n52OdY2u7S3ThCFezqXHX+kge85WgrppOA8As9FfykJ/Z5GDbv2lMIXljgFGxgafpHd4Pjxs8EQxRfOMxAFbCIOl5PMaWnn/DBwxlVqTtmWAvZSa8XUggHxBsDpTg1KKrPIax4ONVuSMlDFafWqxXKYKCI3MGnj5m6U8orbo2etM2++s6pmkigGnzJmK8og5uiWgJmgE7iumGsKWAxuUCeifpu30RaCLohgwYKYiOM+aRgYvaTweaAPm4TfXShHKoMtfCIgidcBZea90GTAc59XBsSxVkqmTtkVQYiXazVKCtcfZN3Ojlutkrq2t6oVLijJ8pGqS66Xf/7yrUl+XFOqWY7dvM7ruFQrkVOGTFntazGQHHs0LSutahVVKnrFOu6ACKgqRRgwHHFExJBcEYHkIH7fKlWx1AtQwA0q5Jdq7cbZ82IU0jVBFMDieK2oeNpQKG26NytnC7BDo4tzxGNVaH6Le4f8LAKoTPGCpy7eLi0Vq1GU2MOvFBrg3ex+kmYinWh2H5YvO5IbsYAW4ArWgwXM+V7Mu+HT11opkFou/6I1eBwcnTow+gIcj+XjJ7GYtEYCMyWVXobR1wTTgX6y6PM995jShi6jAYrrY+D3EcOGVkj6aDyfSOQeUq4ywJwjmrOkSWTGITnIr+inn9NQBhpgULsq0mXEQqOij/dOtNMxqE2YjaNIjmtKMxTMBobD5LGbaVOZ0qeBzFu7R5LGj2F5IV/tfnJr21jf34FO4IPJ6jthuS0KeeLPgwQdNHBgu+aMkzpEFCYgR6V4DdBfBtHEhbBAI50URAFtKahlyALRQI4g0fO7nL43lILI4tGtpIeyHU6kcDCPvqDwPjeVAxMUcDDOgAA8fCKB3Yy6pE+Ix7NrC2VPbd5N0mIdfJtlHYMJJIGSKB23qn89oJH8sYYZ/RsZLebQYIzI4U1N06CFhoCi4jsdOXNVc9IFywN0V+BDQT3Z7SR4kjb0+Vv8HZpvckYMPKd0yNkt4Ad85TQMgzcDHYQ2xorqfRMKsEIyJdxhRUQDyZtLl0iQOJs1Ov5mitUxIvsca0KVckiPQQ0XhzRblZ7GxKb3b2j3TzNv/F2a7goryX3ODcNmKL5TknRc6sTwviohjDUEY0fThcfkOyivX4/vdmETzifeDmENxWTAhrADiAT8F46PAgl477Af6sHvfA7q5c6YzBqzMOasJTF5XGNeePpcQ49nRBkR1xKIAcKAMsQYVLJ747J2JpnO6Q71StrGwAik+QoviWYxR4EJWBzbrfZ3uT/OT7uj/79BuJ/wgZELPlcUsOOxofF6kPewkYvX71uos5vxafbbxH6xy1w5P0a3HAmfgg2JmRZC6CFFfDQEixkubEjz8Nnd3HiSN1Ny6yH1WOllCZaBmiYC+Ds2+ElcWzOuR10rutNR3eU7XW3/3RYAXs/uwjYmwaE2aWkhmWL50kWBi8li5FBKCSZzbgA+z9EkrjSw27Z87GHKlyRHii58DruCOcFW6Hi4duehirCSZjfEV/p4TqMAawH9YN0WCoPkniZVC1pFGFdWdDNw2r5KseyyQqOU1hoW41uO73Z3NMmOWi6Q80I1ADscuGDSwP0dB88Z/tIvykLRBYF4quSazfo1gR6uLkM/7D1+UVImjm1WMgUX8gvPS8MXeYNFpUkXe5mCP6qb38ViHj59xaKRxI1ap1ODWxTfvHmvUXPIkjXXIWCbJPoOf631u0UAsMLfBeMDAXZoSV+rpOGxIJhQxFBGeDtfUz1D4WIpM3HcB8SOZDKBMOxqHFcmqYcm13rdJtvCYbxxzwSuKQtCdwO5gUS/bNMh+1s1RA1Qg8OaTTk+hSQWsruKPXIOlsX0AY3NPPzm8/K9ry4eOm2NLN900C5doiqGunQfu8T8na8HhhlsaN2kjpZUmTRsawcVjFOwtbWyYxEndm1npx9p4sVZZYfjQUF30RYsEs3B2Ny/1zBC2VUKRAI1aSxsDDz+Kh9nyTD9vsf47jfn4stwP0Or/rPsYDZlPSIBB5MkzJktcgMLgkdPq7rD4vb+Q2/RjDLG92kAwG3Fymby+Zw+H6CETgoiguchl3AtJlUxtAMUlSIOPhA/FyNKONMZS0a1+mZ002ki4OuBFuAas91ze9oCOAbeD/07qGkaarnuhjoBcMRtVhw94iDffM+93jUB/e/V4anGaqCaTD5tibS702lhyVbhqnGVgmYxoAWo0p3SSedGXSKjtOoCR036e47vlgP+asBcqHzRowMtxJSjZYU6guMAHjVa8gI7FLZDRxw6gEmFKZFsKVuibPkYNHmV1aaBE6pkCDUYDuYcuiF3pqT2s3ceeJ9V7jZ6kS0+JckfMZzi+noYDhCDSHPciIKvlD19YjPdULdYzXTN0RVBE280hYpmfWdYEYhIwnjDxMPqIKEjwMghf9VCCNRBi81AzJXWmrV+1HC6vx+AAVeny0Tzguhwox4LW+EgSAbdqZQU4fceK3eZFd2/dWVbIGq9+FA4nbS0UJh3tA/alTm1XKw9kUnHdY381Q0tP3KwAGhwp/u78vyhT5Iq7IRT9PQZ0bGAp4+QA9vh8dx23qdFBasxYy38wSLXn0XdwpacdLxkAXbrJzmc8dUVqjfQ9+9DMmBBiCsacbnQm14gDmy8eftB5g9vbvqCK2twVumm4OC1k/9J8z0sQGv9ZJRTbg9VsTmr97IWQ8eOplOC+i9wQ3KmSFJOP0/s8ouxGKAHJcwV+f5gtGEBgB8ubE7jjK8QobRyy2HTB5hz2AR8jYji2nluzHI8jgv7cE25h4gTN9/ijjc/HLRxZA7gnQKEqwg9nXUR/oGDyS+mH7ccCyA+ibipfnBTab6fc/RNBlc3LtaP8fphfTT/J8AA3ocG+Pfx1msAAAAASUVORK5CYII= + + + +http://dle.rae.es + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/list.txt new file mode 100644 index 0000000000..7d1f454896 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/list.txt @@ -0,0 +1,7 @@ +bing +drae +google +mercadolibre-cl +twitter +wikipedia-es +yahoo-cl diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/mercadolibre-cl.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/mercadolibre-cl.xml new file mode 100644 index 0000000000..65f1303f38 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/mercadolibre-cl.xml @@ -0,0 +1,14 @@ + + + +MercadoLibre Chile +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozRjI2NzFGMDJGQUQxMUU1QTU0MzhDNzBBMTQ4RTJDRiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozRjI2NzFFRjJGQUQxMUU1QTU0MzhDNzBBMTQ4RTJDRiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMThBNkRBMkY5QTdDQzAwNzYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4XdLjhAAAcAklEQVR42uxcB3xUVfb+pmYyk2TSeyG9kISQ0CF0aYKgKAusIisIiIor6LLq2oVdFcUKilixgCIIhCpNekgghPRG+iSZTPpMkqnvf96bUAIoqeD+d84v9zclb95793znnnO+c+99PEaByyKgtojaQ9SGwiK9IeXUtlL7D7VK9gteGwAu1HZYFH/bpJbabGq/sgCwln+U2giLXm6rqKkNYAH4C73ZbNHHHZGdLAAJ9OZuiy7uiBhZAPLoTZBFF3dGWACK6dXXogoLABYALGIBwAKARSwAWACwiAUACwAWsQBgAcAiFgAsAFjEAoAFAIv8DwHAgAeDyQ2V1Q7IKxRCb3JFqyEQZQoBShR8tLbyUFHFQKkC+Hye+TcMA1sbHvypFxIJA28PEzzdTbCxyoeQX4UAX/rOvYZ7z6MrWAC4RoyMFBXVnlA1BOJ8hh+OnBTQZwfUNwphMOhJuRo4yevh7KCj1gqRyAS5rQ4yKfs/MwA8emnV8lFbL4Fez4eqToKaejHqGu1gYmwh4IvgYG+Ah0sdRg83Iq5vMZzlBfRZAQGv+X8PAJ1BjsLyICSlR2Pnr07IL5FB3ViH4D5sa4S/twoh/ir08SLFO2pgLdHDSmyASGwks6cTiGFeRHOtmKhpza96nQBanZBAEaK6xgZF5fbIL3ZEYZkL8ovskH3JEbZ2Dgj01WDaXbWIDrmIYJ9CSCU1/38BMBjFUNZHYs9vUdhzxAPpWQx8PJToH1GFYXHFiItUwNVRDWt7PSBkf9CmVOYmDde8tuvNNe3yZ35bazunlkZWpcoWKRmeOJ3iQ6POgwByRUgAMHVcFaaOTYO7QzpEQu3/DwD0RgecyxqBz7f4kHuRw8ezGqMGFWLyqHxEBldA5qxrQ4j1R9covVd62waGoK3R5+YaMbIK3LDvWBCOJvqjqMwN8UMasGhOKeLCT0AkqPvvBIBVfHLWaKz+KBQ5+VpSeglmTkrnrN3OtdWsbENbu5MibGsEiIbASEzxxU97o3DkjB/8/ayxbH4+xg05DLGg5r8DAKNJhOTMeKxeNxRZuWpMG5eHBfefRzi5Gp6ITFvXC0rnX+eeuiqCtvhCozA3yxXf7ozGz/vDEOgnx7OLEzE0+jiEAu2fF4BaTT+s+jge2/ZIMG1sDpY+eBZh4VVtkbeHXIvwGhdyWfGtbd+L2j5fdmWX40hXxMp8jaJcJ3zwzWDsPBiOSWN0eHnZCbjIU/5cABhNYuw/OQ4vv9cP7k7lWLnoJEYMv2T+Z08ZjMjcWupEKCx1QmqWB3IKndDYZEXppgTWVgbiAjq4OWsQFVqF8MAquLs1QmhjujrqumIAYnOsOHvWD//+NB45l3yw5sVcTB6+l75uvvMANGs98P6mGdj4vRTTyd288uwB2HmSSTZcY4nddS9kjcoyW2zdG42EI8HIyJWDL5BAKrOh9FQEa2sBGQHdi0ZPRK0FLS0a2BBPiI2sxtihhZgUnwMvv3pzENZ18Z6s6acaITZtjcW67wZixhQ+lj34M+QyxZ0DoEwZiOfX3EVWIYOOcm8wjRg+oBIjBxZRuwQ310bwpGxEvsYCmVtkKbxr0kZqBg0fW36JxcffDqA8Xo6+ES64a2wo4mL94OfrAicnG8jlUiJgRlRXN0GhqMWlwiokJRfj+KkiKCoaicCpcfeYQsyZegGRYYob7+n6tJZ33f2I20a6moeUTG+8sW48LmRI0T9Sj/WrEiltTb39AFTUjcTcJ/oiMNADb7w6F5k5WuxISMGR34pQW9cIR7maLFCFEbElGBxTjFB/JcQyo7kzhus6z7/qv00tPFRW26K43IkYrQwHTwXjx91BCAtxxtLFIzF1SixZvLhjMam2CceOZ+PHbedw8nQppZQaDO5Po2JIAYbQPQX3qYaYJXeiNsD5l32qGSCTnodGtYTcnScSU31x+JQ/sgvkkFhbY/rUIDQ11OLkmRLs/voivJ2O3j4AylTDMH5uLMaN9sXaNY9AbOV05X+VlfU4diKHgMjB6cRSqGqaIRFr4O/ThAFRlYgJr0BogJJYbi1sZVowpPTqOhtk5LkTKfJG0kV3Yq1O5FKkaG4RkEvR44H7IvHCc/fC2cm2a/UlukhScgG2bT+HX4/kQ6nUQGKlgbe7GsH+9fBxb4KLE/udnjP52nprKGtkKCiRo6BYjtoGKdmGDEEBcowbE4K7J0ejX7QfMe56vPrad/h5RxYObs6El+OR3gegXBWCuctGICoyFO+ueZSU7/C7nVbVqJF4tgCnzuQj9aICOXm10Gp1RPlZH91KHWY4AFhFN6htSOkSREa4kluxQnJyPgwGE5YsGounl00Cn8//AwWb60EdkWpVIwXUSzh/oQRZOVUoKq4nQNTQsRbfNiKF5E1lUiH8/Bzg50NuL9wDgwcHkPvzhvT60ce04J/Pf4ZfD+Vgx8aj8HbJ7D0AdEZ3LPjnDJh4rvh8wxM0FF06fCHWksvKapGWUYps6jjrm5vUrZzFOdhLqHPuGDkiFBKJCM/96wecISW9+NwMzJ836qbna2xsQcKeFJw8lYn8AiVEIgEGxAVi2tQ4xPX371h5xGBEU1MrGYAO9fUa7j1bYXVxsYNUKoadrTXdj/iW4Op1dXjs8XWoUZVgy4cJRNoUvQPA2q8fxJYEV2z/cQk8PIN7nBVqNK1Y/PhGsqYMrHp1FhY+Muamxx06nIY1a3fjfEoxbGwlxFhdaGTpkX+piizXCg8/GI9lT0ym4Gx92wh1fX0Z7r3/fUwa1YSVCz/vONtkAaDG3Kplnp7I+AU9xhw5fJTpDSHlM4uXbmDcvJcwb76986bHqOmY1f/ZzvgEPM6ERC5nXlu1lcnMKmUaGpqZ2jo1c+hIGvPAnPcYV6/FzIyZa5i8PAVzO+XM6RNMQOjjzLkjk5iO6JRtHQKguciZuf/+xcw/Vq6ly+h7/MaNRhPz7D+/ZRzdHmVeeGnzTY8pKVUxc+d9yDh5LGJm/fUDJi295KbHtWr1zIfr9jD+IcuYuMHPMQcOXryNEJiYl15ax0y5ewGjK/PoOQAO75zGRMc+yZQUZfTKbf+8/Szj5vMY8/yLmxmjwXjD/4/8lsEMHfky4+m3lHl99TamuVl7y3OSm2JiBz3HBIQ8xXz2xaHbBoGyqpCu+zSza8vcDgHAv2WgMsnx6XeeuPeecPj4RfSK/2xobKZAZuACcFV1A0jBIHeD3LwKvPzaVsxf8Clamlvx0Xvz8S9KRzvCA8aOicSmr5YiJNgNL7z0E155fSsXdHtbXFz7YM6sKHz+vQ1a9U7dD8LFynEYPSsMu7ctQETf/r1y03V1avzrlR+RsPsCESMB/P3dQCMBhUVVxLBNmDghCiufuYeU6dHpc6so7Vz5wmbs2HUOD8wchNWvz6asS9arIBQX5WLSPeuw84ssBHsd+OMC7Csr8DS9ym+aOurk+D5hCOXH7pSPTwWPb9UrN8xa9ITx0Rg8KBBu7g4Qi4RwcbbD8GFhePLxiXhy6UQuNeyKSCkrmjA+CppmHb7ffApnkwowaEAAHB1teg0AewI4JSUdlUo9YiOKIRa2/mFx9/fTQq0PTiQKMXBwMPgC2161GjaPHzE8jGu9AfDq12bBy0OOt97ZhXkL1uG9NfMwaGBvbQ6VYPDAUOzdcwmN9/lAJqnr2gjIKhqIbfv8QGkeci81orVFy+XZMpkVkRMe/tuEVbifrzP27LuInQnJnKsLDnLv0WuwpC43X4nsrGwkJjchOsIAf6+crsWATbtm4P0vw4ksqCk4CskFSch/ShEe5oQBsb7oF+2LmH5+nLv4b5LTZ/Lw92e+QZWyCS8+Px0L5o/p8rnYwJ6XX4ULqUVIPleI5POlUFS2wKA3kK4YLJqdjSWzt3fNBaVl8WEyGvHZql+IaQpxNs0bF7PdkZbjguMn8yCgmODqaofYfm6UdYRh6JAQzsL+7DJ0SDC+//oJLFv+JV56dSuUVfV4Zvk0coPCDv2ezdDS0ktx8lQujp3IJQAaiQmrKYEwIcBXjcnxSnh7NOKHhDjkFjK3nOD7/fqN1lxU8/JugLtPI4aNLOTKxbUqKQpKnXHqvB+S0jxx6owLdu3J4gLlgFgP3HN3P8THh8OpFwNddyUw0A1fbXwMK1Z+i/c+2k8BsxGvvTwLcrubly/YUsfFtBIcOpyOA4dyUFhMLpkU5OGixZCYKgzuV45B0cUI8lNxiw4qq+3ww644GiH8rgPAFiDZpYJGLc8876pnv2Pg7KaBs6cGg4cVw6jhQ1FhhxPnA3DwRACSkpTYvS8PAf72uHdaFB64fxD8+7j+KUFwcZFj/YcLiGv8jK83HUc1uaQ1b/4Vnp5XK7xFxdXYtz8VCXvTkZZZDV2rDiEBjZg5sQLjhhYgJrwM7p6N4EnaJnnaVnswLebJHD4PXQcAjAlGIw9VKlt4+TaYvzO1NX1bFOebiKDVY07gecyekYLSYnvsPx6GX34Nxbsf1OKrb5Px0NxYLFk8DgUUnDZ+eRgKRR2lalIiLEMxeVJ/yvUNKKKcX6/Xw8lJDnd3hx5XdsqFImRklmM2XVMovGqVMpkEb66ew7nS9z7Yi4cXrsdbq+ZAS/f0zXenyMUUU6xQc65l9pQSTIzPRWzfMti7tVydvGHrbur288gNjRLS3S157h8DYCMj6zcKUVZpj1h+2c0PMrXNs+rYmjwD3z51eDT4NObNTMKhE6H4dPNAfLhezQ3dSvK1AgEfQYHuxHKrsOTJrzBj2kXU1KiRdC6fA8DBwQ6TJkTjqScmk1LkPQaAlZWQUtAd5EaK8MarfyF/fbXr7D39Y8U0eFKayo6GhxZ8QrGP9KrXYmA/JWY9nY6hsYVw9WrTMqvwlj+exy6rdICBAOALTF0nYoqaMBxN9IabUx1GxV8yK/pW0jadJxSZEBxejb9MTIW1lQDb9zmiX5QH+d0lWLxwHGbeNwhl5TXY8lMidKT42bOGY8b0QZwytvyYSFlFMfrH+BFLbuZq9WwuLxQKuuFu7BDZ1xtvvr0LF9NLMHZ0BIEiandMdJQfQkM8cPBwNpHBVnz86m4sX3IMYeFKyKx15hUeHVnqQu5ox95IJF0MxKTRSgyKyu7aCPDzNsJWZkRKlhda64WQWBnMCkYHgWgmY5AxCA2q5JS3ZNE49PEzT+Kw5YBHHh5FrkeFd99+kOs4Kw/NHYGBcQFcDWjK9LegVmshkRAZjA3Es8vvxqBBXSdP8SPC8dknC7HwsY1YuGQD3n9nPjw87NsdM2lCDAoLVVj15j4CXW9ef9SZ1Sdk/SY1D+fTvej3QHiQ4VaH/75EhVTA30eNrDwXpOd4mievOytkLTU1MvJPghuKaBHh3vhg7bwryr8skyfGcFnKtCmx2LBuIZY9PgkFhZV4dOlGnEu51C1XNHpUX2wkEFJohC1YvAGFRcobjgkJceeWuyuqusBvSEe5l1xxIdMTfl5NBEBt1wEQ8UsQE6GGplmIXw5EtV953AkAIkMqKaDrkLA7lUtruWk8IiqqmiYEBrjd8BO2TrPug0fw1r/n4p6psVj+1BR888VjFI9M+OqbYx2boSL2fjox/6YV0NEj+2LDxwtxiZT/0N/WU05f0i7dZCfvbchmAnxqOr+GiEbM9gPRaFSLERmqho1VQddjgFhIvlfWBz8lyFCpcsHYQflwdGnuuBtqA8DVWY3qWkd8vUWArOxi1NY2YtN3J3H0WCamTIq5oazBfmY5BBsPLgsbkLOyFcjJrcR9Mwa2C6I3E3ZJyqKlGyjO1GEkcZLrr8GmxhHhnti56xz2HkilBKGRAnQZ3nn/APYdLMLf7k/HnOnnO7eOlQZ4eYkcq9ffRVmQCSuXKhHic7brALBia8Pgl4PhqFZJ0NxihQmjcrpkFcNii2jw8HHomJY6nEuBsAy+Po6YPi3uylajW8mp07k4m1xAqaOIA4cF5fdqUra21vD3d8Xq//yC4mIVxo2NvOE6LAhs+XvfgXScO19EhDIbJoMSTz6chBULj9A1mI73tW0B17ufjsHxZH84Oxqx/G+nIbVSdg8AK5EKyvoYpGYyKCjxRKCPirIb1RUe0NFRICKaPmJIIf4yKQP3T85FXaMjzpy3w4TxIZT737rSqidXwubplVUN3Lqjn34+S6lsObcCwsbm5uyVVbCPjzPeeW83KipqKPPp225UcZmeoh77f83GsvlJWLXiCBbNPouRIwogoJS6UyNdChw/GYC3N4wn+qTFzLtbMSV+H261IPWWALDSx0+KTT9ToOSJkJrljTED82Dv3Nq54cmYgZDIDHD0aoarXIMfE4KQmlpB6aYPt+iqnAhaIvltVnHXW7bRYGaAC/82BnPnDKeALsLmLWeQmVVKcWIAt0zl+Mls+Hg7tVNyeKgn7OUyvP/hfpRX1HLuSNxW86mtU+PNd/aiuroKLz11GEERKkhEhs6vqibLryy3xdOvz0RNvZQGgw7/XpnB7UO7pXPoCAB2UgWqG/ohg7xPfZMdcijKTxyRA7G1sfPuqI24sczayVZH8UWOH7dlUYBOI5Z8FOdT8vHA/UO4+YF2N0pK7RfdhyzaiQiTAwXSCHKPEnzx1TEumwoIcMXDCz7GpcJqsuDwdpyhf0wfmIhZffHlMQq4xZT/iylA5+HFV3YiMbkSf38kCVPuyjSXWzrbH3bFdqsIK16fgfOZPhAKmjF5rBZzpuwGn6fvGQB4dFfhIVbYtN0DLHcpKHFBebk9xo3MhUDcyaF6DU+IjlJgdFwJxzg1mioa9hqUKCToG+bCsWXuMMp8KirrKCu5cQ6CrbzuP3ARLS3NuJdIXGRfXyJaCZSyVmHMqIh2ILIV0MSkfPLzhdi2IxOHjuTCwUaB55ecxMK5p8EzovPL14XshkMBXlozBXt+60tkTcstEv7otTQyrryOnqJj4uFwAisf88Xr77sROeMj4WhfbmHrKyv2Qmaj6/w+ALaz9JvofuWIjivnYopCIcecZXPx5PKdmPfXEowaGYqjRzPJWsnn//B3rm7TfupPCgdHGZqbzUxp2JAQrP/wESJan6GpsRVr1zx4ZepR06xFXYMJnm56vPP8LtjZtMLbox6Obs1Xdld2Ssjt6PSk/Lem4Ke9/clAWCPSYsXiFgR4HO14ftKREXCFOAVWESsOQKlCROwUuEDxIDPHA8NjCyFz1HUuMF9XumAVYOuoxYjYYhSX2mDXPhU2bU7nJjrYjg0dHMj592slPaMMn2w4iMmTBpDyzSv1AijzCQxwwedfHeXWf8rJ/19ILcGLr7IlCCX+SRZ/z4x0uLk0wZpdjNuVnTsU8+trrPHsqunYeSSSK1OwdayIEAb/eXY7BPymDp+q04tzVU0DMPnheGhahOTv+GRZYoQFKrFqeQJiBpSb/Wh3Vn+QZRn1PGTluFNAM+87eObNCfDrE4SP3p0NX19zabusrAbLn/0Bv50s4jKpRx8ZifAwT85Vsez2yac3IS+/jlu1y27o9nJTY9m8s5g7M7nru2X4ZuVnXPDAv9ZOQWq2F2ykWs5NCvl67P/uHNztj3fqlF1anp6vGIfpC6Kpb0IuOLa0Cskt6bBkzgnMm5UEK6nBDERX94TxcHXNPrnxn7fGYOWb42Fj64j4Ef7UWT6OHi9AS3M18QslzmU4QVVrAw83G8jJLRUX13H7fJf+9RTiIkug1QsREVwFN6+mrt0Xez9WZBhaPr7fHocPvxlJabQ1VysysVtzeAZsWpuF/iH7Ot/Vrm7QOJs5GQueDaXsQsTV19mZH3Z3+tD+hfjHo4cRFaMwjwQduidtYJw+24eSgP44l+bMrudDv/B6zL/vPIYPuYS8PBccTwpAZr4z+WVi0Q46TBqZg8EDi69GOW0XR6bYbAhZaW5Y++VoHD4TTGmskQA2cZbPKn/9qlzEx+zuWve6s0XpQt5EPLoyAmqN4ErGwaZk7MaLeydcxMIHTsOjT6N5yOu7OSLadtboW83XEVoZWVpiBlhkHilXwL68g1LbxWteMwIriuT45peB+HFvDBqbyOoluivZmVBowCerszE0am/X7au7m/RKVSOx8B+DUFRqulJfN5r43HMaXJ3UmDkhFbOmpMDXv+6qUkzdAIJ3TRbF3OT/6CbQbWvPFMVyfLcrDtsP9OMebcA+r4Kd/btcSHR14eGTVSkI9zvUvQHeE9tUG5pDsHr9aOw4YMcF5ss1F4NRwAHh4qDGuGG5mD4+DbGRZRDZGK9Oa3Z3FyV6xsWx1m7S8JCS7o2dhyNx4EQYqmpsuTkQocDsu9hKbkuLDuNGaPDGilNwkWd0//I9tVFbb7TFL4fGYu3GQNTW89pVK9m50RatiEv7+oZUYOyQPMQPuITwoErwrRmzEi7vWrwdcu2mbhqReYUuOHXeH3uPhSM91wPNLWJKs/Wk+KvWwZa12S1VLzzVgKnxPxEhbegZ/Hv6UQVVddEUrAZj1wFbckXtgTDRZz0xR5bA2Nu1cIW94XGFiAkvJzDMG6uv7FZsqx116wEe1+6o5109X7XSBjmFrkjJ8MZJUnxesQvq6qXcNKqY/Dq78uOKYRGzNZkYjI9vwPIFyQj0utCzA7A3HtZhNAlxIWcwPt86FIcpLeYLeJxraneMkce5KJbKi8jS3F0b4E0ARIYoEOxXDX/vWspmNHCy18DGTgs+W/JgOjAhdPkYGk1N9VZQ1dugpk6Gkgp7ZBe4ISPPA+VKO1RWyylro2sLzRmN4LrJcx35ebYAODCGh2cW5yI68BD1oaXnPWBvPq7GxEhxIXcovvzJD7+ddqJ4YORS1usn19lJMhYM1lWxo8ZEr2yObW/XzJUMWKbp4qiGnN6zoLDbSS8/LevqJA5D5xdxyq5XW6O2Tgo1kcQGylzqm9gtryJOyQKybjaYCknp7G/aG4WJczXsPY4aZsLD9+Wgf+gJGhUNvReCbscDm/QGMUqrwnE4cQB2HXRGZo6OI3BscY3t7M0mVVgFs9kUO1LY96YrO9p5t+rRFdLKY5UtMCv8emVfAd5grsKxW2ID/cWYNl6FMYOTEeKb2ysWf0cAuFaatc4orOiPgye8iDx5ICffyG1hZddlMoyJA+aP9gR3a0SaWPLEcFka69uFxF3CgoUYEFlJii+Dn3sq7KTK25uE3cmH9rUQGOVKV5SronDwuASFZW4oUYhQV6fntimxrkogEHCgcJbKY/94v7tvl+HChDlWsL81K9zE5e3W1lZwsBfB21OPAK9KcjF6eDlfRB8vJWSS6juXBf+ZHltpZORQVDkQ8bEmltsX+UVS5BfyqJkogXEkfy6lwMlwT0a86dwIZTFWYh7kts3kgmoR4CeAvx+DkIBmMLp0eLi2wIt9hA2/Fn8W+RM/uJUPrV6KJrUVmjR8yGz7oEUnR0ODCE3NghtGAWv9tlIj5HI9rMUN0DQVc4vKbGTsExc17BJj/BnF8uRcCwAWACwAWACwAGABwAKABQCLWACwAGARCwAWACxiAeB/CwB2GW+QRRV3Rti6bqZFDXdMuL3031v0cMdkJ+uCWGEfbHaXRR+3VdiZ/gGXAXCkto3aKItebouwU3LTqZ24DAAr7FqR+dTmtgEhsOipxyWfGvv4rLepcRPR/yfAALBQYw6aQOGaAAAAAElFTkSuQmCC + + + + +http://www.mercadolibre.cl/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/wikipedia-es.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/wikipedia-es.xml new file mode 100644 index 0000000000..b22d159ede --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/wikipedia-es.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (es) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://es.wikipedia.org/wiki/Especial:Buscar + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/yahoo-cl.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/yahoo-cl.xml new file mode 100644 index 0000000000..4464f93e3e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-CL/yahoo-cl.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://cl.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/list.txt new file mode 100644 index 0000000000..14fe1af92e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/list.txt @@ -0,0 +1,6 @@ +bing +duckduckgo +google +twitter +wikipedia-es +yahoo-es diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/wikipedia-es.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/wikipedia-es.xml new file mode 100644 index 0000000000..b22d159ede --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/wikipedia-es.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (es) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://es.wikipedia.org/wiki/Especial:Buscar + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/yahoo-es.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/yahoo-es.xml new file mode 100644 index 0000000000..a9b50bc07e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-ES/yahoo-es.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://es.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/list.txt new file mode 100644 index 0000000000..757a33489c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/list.txt @@ -0,0 +1,8 @@ +amazondotcom +bing +duckduckgo +google +mercadolibre-mx +twitter +wikipedia-es +yahoo-mx diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/mercadolibre-mx.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/mercadolibre-mx.xml new file mode 100644 index 0000000000..b536695fe6 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/mercadolibre-mx.xml @@ -0,0 +1,14 @@ + + + +MercadoLibre Mexico +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozRjI2NzFGMDJGQUQxMUU1QTU0MzhDNzBBMTQ4RTJDRiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozRjI2NzFFRjJGQUQxMUU1QTU0MzhDNzBBMTQ4RTJDRiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMThBNkRBMkY5QTdDQzAwNzYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4XdLjhAAAcAklEQVR42uxcB3xUVfb+pmYyk2TSeyG9kISQ0CF0aYKgKAusIisIiIor6LLq2oVdFcUKilixgCIIhCpNekgghPRG+iSZTPpMkqnvf96bUAIoqeD+d84v9zclb95793znnnO+c+99PEaByyKgtojaQ9SGwiK9IeXUtlL7D7VK9gteGwAu1HZYFH/bpJbabGq/sgCwln+U2giLXm6rqKkNYAH4C73ZbNHHHZGdLAAJ9OZuiy7uiBhZAPLoTZBFF3dGWACK6dXXogoLABYALGIBwAKARSwAWACwiAUACwAWsQBgAcAiFgAsAFjEAoAFAIv8DwHAgAeDyQ2V1Q7IKxRCb3JFqyEQZQoBShR8tLbyUFHFQKkC+Hye+TcMA1sbHvypFxIJA28PEzzdTbCxyoeQX4UAX/rOvYZ7z6MrWAC4RoyMFBXVnlA1BOJ8hh+OnBTQZwfUNwphMOhJuRo4yevh7KCj1gqRyAS5rQ4yKfs/MwA8emnV8lFbL4Fez4eqToKaejHqGu1gYmwh4IvgYG+Ah0sdRg83Iq5vMZzlBfRZAQGv+X8PAJ1BjsLyICSlR2Pnr07IL5FB3ViH4D5sa4S/twoh/ir08SLFO2pgLdHDSmyASGwks6cTiGFeRHOtmKhpza96nQBanZBAEaK6xgZF5fbIL3ZEYZkL8ovskH3JEbZ2Dgj01WDaXbWIDrmIYJ9CSCU1/38BMBjFUNZHYs9vUdhzxAPpWQx8PJToH1GFYXHFiItUwNVRDWt7PSBkf9CmVOYmDde8tuvNNe3yZ35bazunlkZWpcoWKRmeOJ3iQ6POgwByRUgAMHVcFaaOTYO7QzpEQu3/DwD0RgecyxqBz7f4kHuRw8ezGqMGFWLyqHxEBldA5qxrQ4j1R9covVd62waGoK3R5+YaMbIK3LDvWBCOJvqjqMwN8UMasGhOKeLCT0AkqPvvBIBVfHLWaKz+KBQ5+VpSeglmTkrnrN3OtdWsbENbu5MibGsEiIbASEzxxU97o3DkjB/8/ayxbH4+xg05DLGg5r8DAKNJhOTMeKxeNxRZuWpMG5eHBfefRzi5Gp6ITFvXC0rnX+eeuiqCtvhCozA3yxXf7ozGz/vDEOgnx7OLEzE0+jiEAu2fF4BaTT+s+jge2/ZIMG1sDpY+eBZh4VVtkbeHXIvwGhdyWfGtbd+L2j5fdmWX40hXxMp8jaJcJ3zwzWDsPBiOSWN0eHnZCbjIU/5cABhNYuw/OQ4vv9cP7k7lWLnoJEYMv2T+Z08ZjMjcWupEKCx1QmqWB3IKndDYZEXppgTWVgbiAjq4OWsQFVqF8MAquLs1QmhjujrqumIAYnOsOHvWD//+NB45l3yw5sVcTB6+l75uvvMANGs98P6mGdj4vRTTyd288uwB2HmSSTZcY4nddS9kjcoyW2zdG42EI8HIyJWDL5BAKrOh9FQEa2sBGQHdi0ZPRK0FLS0a2BBPiI2sxtihhZgUnwMvv3pzENZ18Z6s6acaITZtjcW67wZixhQ+lj34M+QyxZ0DoEwZiOfX3EVWIYOOcm8wjRg+oBIjBxZRuwQ310bwpGxEvsYCmVtkKbxr0kZqBg0fW36JxcffDqA8Xo6+ES64a2wo4mL94OfrAicnG8jlUiJgRlRXN0GhqMWlwiokJRfj+KkiKCoaicCpcfeYQsyZegGRYYob7+n6tJZ33f2I20a6moeUTG+8sW48LmRI0T9Sj/WrEiltTb39AFTUjcTcJ/oiMNADb7w6F5k5WuxISMGR34pQW9cIR7maLFCFEbElGBxTjFB/JcQyo7kzhus6z7/qv00tPFRW26K43IkYrQwHTwXjx91BCAtxxtLFIzF1SixZvLhjMam2CceOZ+PHbedw8nQppZQaDO5Po2JIAYbQPQX3qYaYJXeiNsD5l32qGSCTnodGtYTcnScSU31x+JQ/sgvkkFhbY/rUIDQ11OLkmRLs/voivJ2O3j4AylTDMH5uLMaN9sXaNY9AbOV05X+VlfU4diKHgMjB6cRSqGqaIRFr4O/ThAFRlYgJr0BogJJYbi1sZVowpPTqOhtk5LkTKfJG0kV3Yq1O5FKkaG4RkEvR44H7IvHCc/fC2cm2a/UlukhScgG2bT+HX4/kQ6nUQGKlgbe7GsH+9fBxb4KLE/udnjP52nprKGtkKCiRo6BYjtoGKdmGDEEBcowbE4K7J0ejX7QfMe56vPrad/h5RxYObs6El+OR3gegXBWCuctGICoyFO+ueZSU7/C7nVbVqJF4tgCnzuQj9aICOXm10Gp1RPlZH91KHWY4AFhFN6htSOkSREa4kluxQnJyPgwGE5YsGounl00Cn8//AwWb60EdkWpVIwXUSzh/oQRZOVUoKq4nQNTQsRbfNiKF5E1lUiH8/Bzg50NuL9wDgwcHkPvzhvT60ce04J/Pf4ZfD+Vgx8aj8HbJ7D0AdEZ3LPjnDJh4rvh8wxM0FF06fCHWksvKapGWUYps6jjrm5vUrZzFOdhLqHPuGDkiFBKJCM/96wecISW9+NwMzJ836qbna2xsQcKeFJw8lYn8AiVEIgEGxAVi2tQ4xPX371h5xGBEU1MrGYAO9fUa7j1bYXVxsYNUKoadrTXdj/iW4Op1dXjs8XWoUZVgy4cJRNoUvQPA2q8fxJYEV2z/cQk8PIN7nBVqNK1Y/PhGsqYMrHp1FhY+Muamxx06nIY1a3fjfEoxbGwlxFhdaGTpkX+piizXCg8/GI9lT0ym4Gx92wh1fX0Z7r3/fUwa1YSVCz/vONtkAaDG3Kplnp7I+AU9xhw5fJTpDSHlM4uXbmDcvJcwb76986bHqOmY1f/ZzvgEPM6ERC5nXlu1lcnMKmUaGpqZ2jo1c+hIGvPAnPcYV6/FzIyZa5i8PAVzO+XM6RNMQOjjzLkjk5iO6JRtHQKguciZuf/+xcw/Vq6ly+h7/MaNRhPz7D+/ZRzdHmVeeGnzTY8pKVUxc+d9yDh5LGJm/fUDJi295KbHtWr1zIfr9jD+IcuYuMHPMQcOXryNEJiYl15ax0y5ewGjK/PoOQAO75zGRMc+yZQUZfTKbf+8/Szj5vMY8/yLmxmjwXjD/4/8lsEMHfky4+m3lHl99TamuVl7y3OSm2JiBz3HBIQ8xXz2xaHbBoGyqpCu+zSza8vcDgHAv2WgMsnx6XeeuPeecPj4RfSK/2xobKZAZuACcFV1A0jBIHeD3LwKvPzaVsxf8Clamlvx0Xvz8S9KRzvCA8aOicSmr5YiJNgNL7z0E155fSsXdHtbXFz7YM6sKHz+vQ1a9U7dD8LFynEYPSsMu7ctQETf/r1y03V1avzrlR+RsPsCESMB/P3dQCMBhUVVxLBNmDghCiufuYeU6dHpc6so7Vz5wmbs2HUOD8wchNWvz6asS9arIBQX5WLSPeuw84ssBHsd+OMC7Csr8DS9ym+aOurk+D5hCOXH7pSPTwWPb9UrN8xa9ITx0Rg8KBBu7g4Qi4RwcbbD8GFhePLxiXhy6UQuNeyKSCkrmjA+CppmHb7ffApnkwowaEAAHB1teg0AewI4JSUdlUo9YiOKIRa2/mFx9/fTQq0PTiQKMXBwMPgC2161GjaPHzE8jGu9AfDq12bBy0OOt97ZhXkL1uG9NfMwaGBvbQ6VYPDAUOzdcwmN9/lAJqnr2gjIKhqIbfv8QGkeci81orVFy+XZMpkVkRMe/tuEVbifrzP27LuInQnJnKsLDnLv0WuwpC43X4nsrGwkJjchOsIAf6+crsWATbtm4P0vw4ksqCk4CskFSch/ShEe5oQBsb7oF+2LmH5+nLv4b5LTZ/Lw92e+QZWyCS8+Px0L5o/p8rnYwJ6XX4ULqUVIPleI5POlUFS2wKA3kK4YLJqdjSWzt3fNBaVl8WEyGvHZql+IaQpxNs0bF7PdkZbjguMn8yCgmODqaofYfm6UdYRh6JAQzsL+7DJ0SDC+//oJLFv+JV56dSuUVfV4Zvk0coPCDv2ezdDS0ktx8lQujp3IJQAaiQmrKYEwIcBXjcnxSnh7NOKHhDjkFjK3nOD7/fqN1lxU8/JugLtPI4aNLOTKxbUqKQpKnXHqvB+S0jxx6owLdu3J4gLlgFgP3HN3P8THh8OpFwNddyUw0A1fbXwMK1Z+i/c+2k8BsxGvvTwLcrubly/YUsfFtBIcOpyOA4dyUFhMLpkU5OGixZCYKgzuV45B0cUI8lNxiw4qq+3ww644GiH8rgPAFiDZpYJGLc8876pnv2Pg7KaBs6cGg4cVw6jhQ1FhhxPnA3DwRACSkpTYvS8PAf72uHdaFB64fxD8+7j+KUFwcZFj/YcLiGv8jK83HUc1uaQ1b/4Vnp5XK7xFxdXYtz8VCXvTkZZZDV2rDiEBjZg5sQLjhhYgJrwM7p6N4EnaJnnaVnswLebJHD4PXQcAjAlGIw9VKlt4+TaYvzO1NX1bFOebiKDVY07gecyekYLSYnvsPx6GX34Nxbsf1OKrb5Px0NxYLFk8DgUUnDZ+eRgKRR2lalIiLEMxeVJ/yvUNKKKcX6/Xw8lJDnd3hx5XdsqFImRklmM2XVMovGqVMpkEb66ew7nS9z7Yi4cXrsdbq+ZAS/f0zXenyMUUU6xQc65l9pQSTIzPRWzfMti7tVydvGHrbur288gNjRLS3S157h8DYCMj6zcKUVZpj1h+2c0PMrXNs+rYmjwD3z51eDT4NObNTMKhE6H4dPNAfLhezQ3dSvK1AgEfQYHuxHKrsOTJrzBj2kXU1KiRdC6fA8DBwQ6TJkTjqScmk1LkPQaAlZWQUtAd5EaK8MarfyF/fbXr7D39Y8U0eFKayo6GhxZ8QrGP9KrXYmA/JWY9nY6hsYVw9WrTMqvwlj+exy6rdICBAOALTF0nYoqaMBxN9IabUx1GxV8yK/pW0jadJxSZEBxejb9MTIW1lQDb9zmiX5QH+d0lWLxwHGbeNwhl5TXY8lMidKT42bOGY8b0QZwytvyYSFlFMfrH+BFLbuZq9WwuLxQKuuFu7BDZ1xtvvr0LF9NLMHZ0BIEiandMdJQfQkM8cPBwNpHBVnz86m4sX3IMYeFKyKx15hUeHVnqQu5ox95IJF0MxKTRSgyKyu7aCPDzNsJWZkRKlhda64WQWBnMCkYHgWgmY5AxCA2q5JS3ZNE49PEzT+Kw5YBHHh5FrkeFd99+kOs4Kw/NHYGBcQFcDWjK9LegVmshkRAZjA3Es8vvxqBBXSdP8SPC8dknC7HwsY1YuGQD3n9nPjw87NsdM2lCDAoLVVj15j4CXW9ef9SZ1Sdk/SY1D+fTvej3QHiQ4VaH/75EhVTA30eNrDwXpOd4mievOytkLTU1MvJPghuKaBHh3vhg7bwryr8skyfGcFnKtCmx2LBuIZY9PgkFhZV4dOlGnEu51C1XNHpUX2wkEFJohC1YvAGFRcobjgkJceeWuyuqusBvSEe5l1xxIdMTfl5NBEBt1wEQ8UsQE6GGplmIXw5EtV953AkAIkMqKaDrkLA7lUtruWk8IiqqmiYEBrjd8BO2TrPug0fw1r/n4p6psVj+1BR888VjFI9M+OqbYx2boSL2fjox/6YV0NEj+2LDxwtxiZT/0N/WU05f0i7dZCfvbchmAnxqOr+GiEbM9gPRaFSLERmqho1VQddjgFhIvlfWBz8lyFCpcsHYQflwdGnuuBtqA8DVWY3qWkd8vUWArOxi1NY2YtN3J3H0WCamTIq5oazBfmY5BBsPLgsbkLOyFcjJrcR9Mwa2C6I3E3ZJyqKlGyjO1GEkcZLrr8GmxhHhnti56xz2HkilBKGRAnQZ3nn/APYdLMLf7k/HnOnnO7eOlQZ4eYkcq9ffRVmQCSuXKhHic7brALBia8Pgl4PhqFZJ0NxihQmjcrpkFcNii2jw8HHomJY6nEuBsAy+Po6YPi3uylajW8mp07k4m1xAqaOIA4cF5fdqUra21vD3d8Xq//yC4mIVxo2NvOE6LAhs+XvfgXScO19EhDIbJoMSTz6chBULj9A1mI73tW0B17ufjsHxZH84Oxqx/G+nIbVSdg8AK5EKyvoYpGYyKCjxRKCPirIb1RUe0NFRICKaPmJIIf4yKQP3T85FXaMjzpy3w4TxIZT737rSqidXwubplVUN3Lqjn34+S6lsObcCwsbm5uyVVbCPjzPeeW83KipqKPPp225UcZmeoh77f83GsvlJWLXiCBbNPouRIwogoJS6UyNdChw/GYC3N4wn+qTFzLtbMSV+H261IPWWALDSx0+KTT9ToOSJkJrljTED82Dv3Nq54cmYgZDIDHD0aoarXIMfE4KQmlpB6aYPt+iqnAhaIvltVnHXW7bRYGaAC/82BnPnDKeALsLmLWeQmVVKcWIAt0zl+Mls+Hg7tVNyeKgn7OUyvP/hfpRX1HLuSNxW86mtU+PNd/aiuroKLz11GEERKkhEhs6vqibLryy3xdOvz0RNvZQGgw7/XpnB7UO7pXPoCAB2UgWqG/ohg7xPfZMdcijKTxyRA7G1sfPuqI24sczayVZH8UWOH7dlUYBOI5Z8FOdT8vHA/UO4+YF2N0pK7RfdhyzaiQiTAwXSCHKPEnzx1TEumwoIcMXDCz7GpcJqsuDwdpyhf0wfmIhZffHlMQq4xZT/iylA5+HFV3YiMbkSf38kCVPuyjSXWzrbH3bFdqsIK16fgfOZPhAKmjF5rBZzpuwGn6fvGQB4dFfhIVbYtN0DLHcpKHFBebk9xo3MhUDcyaF6DU+IjlJgdFwJxzg1mioa9hqUKCToG+bCsWXuMMp8KirrKCu5cQ6CrbzuP3ARLS3NuJdIXGRfXyJaCZSyVmHMqIh2ILIV0MSkfPLzhdi2IxOHjuTCwUaB55ecxMK5p8EzovPL14XshkMBXlozBXt+60tkTcstEv7otTQyrryOnqJj4uFwAisf88Xr77sROeMj4WhfbmHrKyv2Qmaj6/w+ALaz9JvofuWIjivnYopCIcecZXPx5PKdmPfXEowaGYqjRzPJWsnn//B3rm7TfupPCgdHGZqbzUxp2JAQrP/wESJan6GpsRVr1zx4ZepR06xFXYMJnm56vPP8LtjZtMLbox6Obs1Xdld2Ssjt6PSk/Lem4Ke9/clAWCPSYsXiFgR4HO14ftKREXCFOAVWESsOQKlCROwUuEDxIDPHA8NjCyFz1HUuMF9XumAVYOuoxYjYYhSX2mDXPhU2bU7nJjrYjg0dHMj592slPaMMn2w4iMmTBpDyzSv1AijzCQxwwedfHeXWf8rJ/19ILcGLr7IlCCX+SRZ/z4x0uLk0wZpdjNuVnTsU8+trrPHsqunYeSSSK1OwdayIEAb/eXY7BPymDp+q04tzVU0DMPnheGhahOTv+GRZYoQFKrFqeQJiBpSb/Wh3Vn+QZRn1PGTluFNAM+87eObNCfDrE4SP3p0NX19zabusrAbLn/0Bv50s4jKpRx8ZifAwT85Vsez2yac3IS+/jlu1y27o9nJTY9m8s5g7M7nru2X4ZuVnXPDAv9ZOQWq2F2ykWs5NCvl67P/uHNztj3fqlF1anp6vGIfpC6Kpb0IuOLa0Cskt6bBkzgnMm5UEK6nBDERX94TxcHXNPrnxn7fGYOWb42Fj64j4Ef7UWT6OHi9AS3M18QslzmU4QVVrAw83G8jJLRUX13H7fJf+9RTiIkug1QsREVwFN6+mrt0Xez9WZBhaPr7fHocPvxlJabQ1VysysVtzeAZsWpuF/iH7Ot/Vrm7QOJs5GQueDaXsQsTV19mZH3Z3+tD+hfjHo4cRFaMwjwQduidtYJw+24eSgP44l+bMrudDv/B6zL/vPIYPuYS8PBccTwpAZr4z+WVi0Q46TBqZg8EDi69GOW0XR6bYbAhZaW5Y++VoHD4TTGmskQA2cZbPKn/9qlzEx+zuWve6s0XpQt5EPLoyAmqN4ErGwaZk7MaLeydcxMIHTsOjT6N5yOu7OSLadtboW83XEVoZWVpiBlhkHilXwL68g1LbxWteMwIriuT45peB+HFvDBqbyOoluivZmVBowCerszE0am/X7au7m/RKVSOx8B+DUFRqulJfN5r43HMaXJ3UmDkhFbOmpMDXv+6qUkzdAIJ3TRbF3OT/6CbQbWvPFMVyfLcrDtsP9OMebcA+r4Kd/btcSHR14eGTVSkI9zvUvQHeE9tUG5pDsHr9aOw4YMcF5ss1F4NRwAHh4qDGuGG5mD4+DbGRZRDZGK9Oa3Z3FyV6xsWx1m7S8JCS7o2dhyNx4EQYqmpsuTkQocDsu9hKbkuLDuNGaPDGilNwkWd0//I9tVFbb7TFL4fGYu3GQNTW89pVK9m50RatiEv7+oZUYOyQPMQPuITwoErwrRmzEi7vWrwdcu2mbhqReYUuOHXeH3uPhSM91wPNLWJKs/Wk+KvWwZa12S1VLzzVgKnxPxEhbegZ/Hv6UQVVddEUrAZj1wFbckXtgTDRZz0xR5bA2Nu1cIW94XGFiAkvJzDMG6uv7FZsqx116wEe1+6o5109X7XSBjmFrkjJ8MZJUnxesQvq6qXcNKqY/Dq78uOKYRGzNZkYjI9vwPIFyQj0utCzA7A3HtZhNAlxIWcwPt86FIcpLeYLeJxraneMkce5KJbKi8jS3F0b4E0ARIYoEOxXDX/vWspmNHCy18DGTgs+W/JgOjAhdPkYGk1N9VZQ1dugpk6Gkgp7ZBe4ISPPA+VKO1RWyylro2sLzRmN4LrJcx35ebYAODCGh2cW5yI68BD1oaXnPWBvPq7GxEhxIXcovvzJD7+ddqJ4YORS1usn19lJMhYM1lWxo8ZEr2yObW/XzJUMWKbp4qiGnN6zoLDbSS8/LevqJA5D5xdxyq5XW6O2Tgo1kcQGylzqm9gtryJOyQKybjaYCknp7G/aG4WJczXsPY4aZsLD9+Wgf+gJGhUNvReCbscDm/QGMUqrwnE4cQB2HXRGZo6OI3BscY3t7M0mVVgFs9kUO1LY96YrO9p5t+rRFdLKY5UtMCv8emVfAd5grsKxW2ID/cWYNl6FMYOTEeKb2ysWf0cAuFaatc4orOiPgye8iDx5ICffyG1hZddlMoyJA+aP9gR3a0SaWPLEcFka69uFxF3CgoUYEFlJii+Dn3sq7KTK25uE3cmH9rUQGOVKV5SronDwuASFZW4oUYhQV6fntimxrkogEHCgcJbKY/94v7tvl+HChDlWsL81K9zE5e3W1lZwsBfB21OPAK9KcjF6eDlfRB8vJWSS6juXBf+ZHltpZORQVDkQ8bEmltsX+UVS5BfyqJkogXEkfy6lwMlwT0a86dwIZTFWYh7kts3kgmoR4CeAvx+DkIBmMLp0eLi2wIt9hA2/Fn8W+RM/uJUPrV6KJrUVmjR8yGz7oEUnR0ODCE3NghtGAWv9tlIj5HI9rMUN0DQVc4vKbGTsExc17BJj/BnF8uRcCwAWACwAWACwAGABwAKABQCLWACwAGARCwAWACxiAeB/CwB2GW+QRRV3Rti6bqZFDXdMuL3031v0cMdkJ+uCWGEfbHaXRR+3VdiZ/gGXAXCkto3aKItebouwU3LTqZ24DAAr7FqR+dTmtgEhsOipxyWfGvv4rLepcRPR/yfAALBQYw6aQOGaAAAAAElFTkSuQmCC + + + + +http://www.mercadolibre.com.mx/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/wikipedia-es.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/wikipedia-es.xml new file mode 100644 index 0000000000..b22d159ede --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/wikipedia-es.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (es) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://es.wikipedia.org/wiki/Especial:Buscar + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/yahoo-mx.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/yahoo-mx.xml new file mode 100644 index 0000000000..67fc1d3a5d --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/es-MX/yahoo-mx.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://mx.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/et/amazon-co-uk.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/et/amazon-co-uk.xml new file mode 100644 index 0000000000..3a3fbabb19 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/et/amazon-co-uk.xml @@ -0,0 +1,16 @@ + + + +Amazon.co.uk +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.co.uk/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/et/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/et/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/et/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/et/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/et/list.txt new file mode 100644 index 0000000000..0a860d5b5f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/et/list.txt @@ -0,0 +1,4 @@ +amazon-co-uk +google +twitter +wikipedia-et diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/et/wikipedia-et.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/et/wikipedia-et.xml new file mode 100644 index 0000000000..b5b71ebc18 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/et/wikipedia-et.xml @@ -0,0 +1,23 @@ + + + +Vikipeedia (et) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://et.wikipedia.org/wiki/Eri:Otsimine + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eu/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eu/eBay-es.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/eBay-es.xml new file mode 100644 index 0000000000..63ffe34d09 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/eBay-es.xml @@ -0,0 +1,17 @@ + + + +eBay +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.es/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eu/elebila.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/elebila.xml new file mode 100644 index 0000000000..7ea497c643 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/elebila.xml @@ -0,0 +1,15 @@ + + + + Elebila + UTF-8 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOEVGQjlGNDQzNDAxMUU1QjMxRUUxQjk0MEM4ODg5MSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOEVGQjlGMzQzNDAxMUU1QjMxRUUxQjk0MEM4ODg5MSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDM4MDExNzQwNzIwNjgxMTkyQjBGRkQ2MzQ3QjE4OUUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5ISaQBAAADRUlEQVR42uxcMWsUQRTezD1SpZO0kkLQKtU1koBCEAQTELRIEbEJBwH/g9iJ/gD/gZWCmkYMhgT0D1hYpUiKgI2BQKoDwffgFo4jYWdndue9mXwfvCQsu7nve9/svJl3tzc3Ho+rCQYcI45nHHcroA+ccnzgeM3xRw7MTQxY5PiMxCfDGccmx54YICP/gGMVeUmKC46h4x9PkXwVLHC8cZM5H9DBIzHgNvKghoEYMI886MEhBTAABgAwAAYAMAAGADAABgAw4FqBLJLaXXnVeM7Gz5dFGCDvB5zw75uWkv9w6X7jeV+PD4owwVkb+T7JF8h5PncKDABgAAzwhMzpMrdjFaRswuzc7lsXYECHJoQWZ0xBAAyAAQAMuBZFuO1O1HrrQEMPxZBsuzKZvtaKGdp6qO0LxiwHp6+tyWsaYUGPS0X2MvKaDTUrepwG2VniqU2wpMdpktUwwZqeTloRPg20nFoJKfVQzGipifoUnnpEXPX/6lHTZ1G2qIdiRkmbZNXnWm2saekJ3gmHjlS57t3fT+YM0NLjQkdLSdDUg16QMmCAMoKKcOy6fWfpsakkaOqhGNIlQUsPpiDUABiQ5UYoh6Wtjx7SJhm7EbK6n/DVQ7EvpLH7tLoRC9FDXb3YxpPl6t7arcbrDr8fVbsff5lvRaTSgyKMIgwDOoHchnI75jj9aOpxqUjnlPyUeqgP0lLALjueI/rWQ32RLgl96gmagkp5QM6CHoolff78RrU1euE/mmaEWtmMaelpfE7Y95MEbYS27ZlcxSGkf2RBT6c1ILaPnuLjKJb1NNaA0p5ctKbH5Ui6JBOcNmmt9wGs6KG2pJs+kudL0sIqyIIeCiE9vfzy/WYTi0tPC3qoK+K+51uuCxp6qCviJRVok0UYgAEwAIABMMASSmiL4w5QBuUuwPcusLpcphJGkc/u1VLLO7spqOQv88umBpRqQlZFuEQTzH13tA/atpAtP3uQpQGzRuS6AsreANQAAAbAAAAGwAAABsAAAAbAACDIgDHSoGvAb6RBDf/EgPfIgxq+SDNO/vjG8QD5SIpzjmFdhDc5DpGTZDjjWOc4clMH1ji2OfZlbkKOeoE8dv+W4w7HDznwX4ABAMgHwgM+bKkgAAAAAElFTkSuQmCC + + + + + + http://elebila.elhuyar.eus + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eu/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/list.txt new file mode 100644 index 0000000000..f93efb7403 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/list.txt @@ -0,0 +1,6 @@ +bing +eBay-es +elebila +google +wikipedia-eu +yahoo-es diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eu/wikipedia-eu.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/wikipedia-eu.xml new file mode 100644 index 0000000000..2482d1cf57 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/wikipedia-eu.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (eu) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://eu.wikipedia.org/wiki/Berezi:Bilatu + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/eu/yahoo-es.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/yahoo-es.xml new file mode 100644 index 0000000000..a9b50bc07e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/eu/yahoo-es.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://es.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fa/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/fa/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fa/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fa/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/fa/list.txt new file mode 100644 index 0000000000..21721d9d13 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fa/list.txt @@ -0,0 +1,3 @@ +google +wikipedia-fa +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fa/wikipedia-fa.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/fa/wikipedia-fa.xml new file mode 100644 index 0000000000..dd66c88f72 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fa/wikipedia-fa.xml @@ -0,0 +1,23 @@ + + + +ویکی‌پدیا (fa) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://fa.wikipedia.org/wiki/ویژه:جستجو + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ff/amazon-france.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/amazon-france.xml new file mode 100644 index 0000000000..b93c2752fb --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/amazon-france.xml @@ -0,0 +1,17 @@ + + + +Amazon.fr +Recherche Amazon.fr +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.fr/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ff/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ff/eBay-france.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/eBay-france.xml new file mode 100644 index 0000000000..0db6faa349 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/eBay-france.xml @@ -0,0 +1,14 @@ + + + +eBay France +Recherche intégrée eBay +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + +http://search.ebay.fr/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ff/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/list.txt new file mode 100644 index 0000000000..0a2dad5ef7 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/list.txt @@ -0,0 +1,6 @@ +amazon-france +bing +eBay-france +google +wikipedia-fr +yahoo-france diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ff/wikipedia-fr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/wikipedia-fr.xml new file mode 100644 index 0000000000..c600f076e1 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/wikipedia-fr.xml @@ -0,0 +1,23 @@ + + + +Wikipédia (fr) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://fr.wikipedia.org/wiki/Spécial:Recherche + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ff/yahoo-france.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/yahoo-france.xml new file mode 100644 index 0000000000..5bdc936c24 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ff/yahoo-france.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://fr.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fi/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/fi/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fi/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fi/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/fi/list.txt new file mode 100644 index 0000000000..586e5b8594 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fi/list.txt @@ -0,0 +1,5 @@ +google +twitter +wikipedia-fi +yahoo-fi +amazondotcom diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fi/wikipedia-fi.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/fi/wikipedia-fi.xml new file mode 100644 index 0000000000..c82bee0195 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fi/wikipedia-fi.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (fi) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://fi.wikipedia.org/wiki/Toiminnot:Haku + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fi/yahoo-fi.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/fi/yahoo-fi.xml new file mode 100644 index 0000000000..be75dc4319 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fi/yahoo-fi.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://fi.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fr/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fr/eBay-france.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/eBay-france.xml new file mode 100644 index 0000000000..0db6faa349 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/eBay-france.xml @@ -0,0 +1,14 @@ + + + +eBay France +Recherche intégrée eBay +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + +http://search.ebay.fr/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fr/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/list.txt new file mode 100644 index 0000000000..94b850738a --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/list.txt @@ -0,0 +1,8 @@ +bing +duckduckgo +eBay-france +google +qwant +twitter +wikipedia-fr +yahoo-france diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fr/wikipedia-fr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/wikipedia-fr.xml new file mode 100644 index 0000000000..c600f076e1 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/wikipedia-fr.xml @@ -0,0 +1,23 @@ + + + +Wikipédia (fr) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://fr.wikipedia.org/wiki/Spécial:Recherche + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fr/yahoo-france.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/yahoo-france.xml new file mode 100644 index 0000000000..5bdc936c24 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fr/yahoo-france.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://fr.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/bolcom-fy-NL.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/bolcom-fy-NL.xml new file mode 100644 index 0000000000..7e93a46a54 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/bolcom-fy-NL.xml @@ -0,0 +1,12 @@ + + + +bol.com +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3wkXERE19+wneQAAEVtJREFUeNrtnXl0VGWaxn93qT1FqLAECARNIGxGxCiRiEhjABtb8MCAOno86umBbkfHg8rocdxmeo4NZxxxt6HPaUTl9AguRAWjos3ayL7EkLAYIQRiwJC19qp7549bVUlBlkqlUinaev7Kqbqpuvd9vu/9nnf5vhJ4r55WeAJYAIwDzCQRSziAUmAt8FLwRSFAwPDAGxOTdooLdgcG+ikx8ELS+PHFxIDNEQNuJ2n83iHhCTEwFZLoHSwQAwtuEr2DcWJS7fQqzGLSBr2LJAFJApIEJJEk4JcL+XK9cYsskCJDP4NArVulzqPiUZIE9Agm9ZeYM0yHTS+QlSJSOLjt267zqOyr9VPeqFDlUNhU7WPfBX9CP5vAe/VqIhr8tgwdUwfJjE0VsemFsPcr7QoNHpWKZgWXH4wSZFpEhphF0o3h11Y7VUrq/BRX+/i/kx6qnWqSgEumoQDjbRJ3DNNxW4bMhDQpZOjv6xU2nPFyuE6hwatSUt/5iB6bKjLEJJJrk5g7TCbbKjHYpBGz/ZyPD055KT7r40STkiRAEuCvk83MH64DwKNA0WkvfyhxR2TsSDE/U8fiMQYmDZBCrz22z8XyMvcvk4B0o8AzuUbuvkJHP4PApmofy0rdHKjzU+vuuVsaYhK5cYDE0glGsqwiFc0Kbx718Eq5G0X9BRAgCvBQjp4lYw1kWkQOXPDzv0fcrDnpjeuDGyVYPMbAb0foyUoROVKvsGS/k00/+eKqpuJKgE0v8MMcKzaDgN2n8theFytPeHrdD7+cZ2TxGAMAK497WLTL+Y9HwOSBMqsmmRhhFVle5mZZqZsaV+IokrGpIq9eZ6JwsMzGMz5mb7bjV/8BCJAFuGWwzOoCM2YJnj/s5vVyN76EE78a3i0wc/cVOirtCndtd7CntmfjiB5PRTwyykDxNAspEszd4mB5WeIaH+C+vztYvNdJllVk969TKBwkX74EvHStkZevM1LRpDCxuJlNP/ki/t8JNolVk0yXBFbxwFvHPUzfZKfGpbJ+qpk5Q3WXlwsSgBlDZD6fauG7n33c+q0De4TDPscq8vhYAw9m65FFsHtV8ovtlDbEP6WQ21fi60IL6UaBguJmdv7svzxmwLVpEsXTLLj9Kv+0NXLj33OljqNzrCwcqRkfwKITuPMKXa+4o5J6Pwu2OgB4/0YzknAZuKAcq8inU7Uy86y/OSJSOhZZYO1NZt4pCC9PH6lXuPkrO3/8vvei1e3nfSz6zkmmReSrWyyJTYAowDsFZmwGgXt3ONh6rnOfn2kRWX+zloqQAyOszqPywiEXeV80sfWcD6e/91ZtRYWVJzy8/6OHaYNkVuSbMEoxVImxvNm3J5qYNEBieZmbNT9GFtn+bbqFrJSWcVBS5+fqDc0Jp44e2OlkqFlk4Ug9n5/x8lmVL7FmwIQ0iYUj9ew87+fZQ527jPz+Ej/cYQ0z/lMHXNz0lT1hJeq/7tYi5FfyTIhCgs2AxwOh/HOHXJ0uuvn9JYqmWkISs86j8sDfnRRV9Xw+yKoTyLGKZFpEMswCFlmgxqVyoknheKO/wzXrWJPCY/tcvJxn5MlxhpisTTGRoYWDZL4utFDRpJBd1NTp9afnWhkaaEmye1Wu3tBMRbPSpgycNUTGZhBCaeruVLhev97Ew6P0HV6zYKuDdZUdD4Sy2Vb0ImSvb0oMArbMsDC+r8SoT5s6HEGZFvESn3/thmYO1LUYNZimvmOYHCKpNWpcKltrfCwvc0ekyzMtIm9cb2TaIBmLHJnf+KzKy93bne3O5MfHGHgpz8jyMjeP7XP1LgET0iR235rCukov/7zd0e51qTqBD6eYQ/Xc8y6VOZvtYUacl6njzYmRR79ztzj45HTbo9Uowe0ZOt7ON9HPEP55VQ6FU3aVvT/72HPBz+E6bfZdbROZN0zHlHSZBo/KDcXNnG+jNmGUYN+vrYztKzKqqIlj3aisdZuAC/P7YDMIDPqwscPRvyLfxMKRLdP/3h2OMKW0dILmV1ujzqOy7Hs3G8/6QtUxiywwP1PHqgITdq9KdlHbs+7i7wti0S4nK493nAIf3UekbLa1w9T0rCEyG6ZZeOqAi2Wl0a8F3VJBo/uI2AwCH5z0dmj8dKPA3a2i2WcOusKM/3yuIcz4O8/7mb7JzrCPm1h2JLw0afepvFPhIW1tI9UulaUTjJcEddtmWMKMf9ahcO92B30/aOzU+ADljQqLvnPyYLaeHGvbJgpmSe/L0veeDA0Wzz863f6iZZTgk5stWHVCyLivlLcYYWq6zAvjNSPWulWePuCi4EstcdeRmqrzqBSf9VEwQA7z94dvS2HywJbXik57uXZjM2tOemnwRj7ZV57w4FPhtnYScefdKkWnvYxNFRmbKvYOAXcGCuklde0vhhP7yaFCeJ1HpeDL5jDDvnZdywie+Y2dP3ZhOtt9Kjl9Wh7h86lmslqN2GWlbu7Y4oi68CMKWotMe/hDibvbsyDqOCBVJ1A4WKaiSemwvaO1K7jYV87P1DGmr0StW+VXX9u73AVx6xAZl79lDcm1acZy+eG3Ox3dqjNnpYjoRToUBPsu+Km0K2EzLm4zYM4wHRZZYHkH1S2jBL/J0G6u0q7wankLAXpR0+WyAH865umy8ecM1THeJnHWqZFf0aTgC4yDx/c5u13kfzbXENF139crjO4jRh0ZR03d7KEydp/KG0fbX9Qm2CRSA11t/3PEHRqtAEPNIukmAbtX7ZLbCQZo6wMZ1/IGJeSzbQYBm17grWPdK/QPNYvcn60PxR0doajKy6wMmXnDdJ0GcDElYIBB4LSj45u7odUCue+i2mqqXqCkzs/6Kl/E9YKLjQ/wboXnEheXlSJi96lR+/7ftXKbn5/pOOm2JxDH5PWT4kvAQJOIvRNVkdLq00/Zw6891qiw8ayPdaciv+m8NIm1U8yhSPqTSi8ftPp/iyzw7FUGZg/T0exTmfxlc5d7fCYPlHl8rOZ+Gjya0ukIwRRKXpoUXxekF+FcF0auX1UvUTBPHYg8jA/mm1rj3/a6LgmOnrxKM97yMndUDVarC1ry/a8d9XQqXYPvR0tA1IuwRRbaDNNb40hD91vMLLLAqkmmMLdT0ayQvb6JKkf4599zpSaLPzjp5emDXcvRZKWIYelxu1flzaORrU0ldX5sBgEhngSkGwVONnds4E3VvlCf58X5mEg+/3cj9dTMs3J/tj6USCtvULhjs6PN7KkkaNe8Wh6+4HeGSf0lvpjWkiRs8qpM/8Ye8RpyJtDyPjCKDo6oCAjeaCTT89E9Wi5lXGrkU3R+po6y2Vbezjdh0QlhC/l1XzS3K1m/rPaGAr5IsXCEns0zUsICuif2u7rUAeEOlEwv3sfQ4wRUNHfuYj4+7WPlcQ9/vsHE0muM7aaEs1JElk4wUna7lbVTzGEPc6xR4a5tjkui6IvxaaBMeH2/zsmel6lj/6wUVtxgQt/KCg/sdPKXLvarHq7X7KCLIhiIahEOGiGS/LrTr7Jol5Mmr8rDo/U8eZWBzTU+GlqN0jGpUtgIDOJks8LnZ3w8c9AVUR6n0q65pzWTTdwwQOaTSm/YQny1TWSCTdt9k24Kv/fSej//cdAdVVUuqPaiWfGiIiA4PbvStfbEfherK7xsmW5hanrHX1vnVlmwzdFmJ9392XpWTTKxrNTNc4dclyidoiovi3bBiokmHsrpPEfT0Xd11SP87FLiQ0BQI4+0dk16ldT7SVvXSG5fidF9tC1ERhGC9739nI9Ku0J546UP0s8g8PZEE3OGaUrnyXEGUnUCv999ab5+zY9eNlX7yEuTmDlER5ZVZLhZGyzNPjjn0mbWgQt+Sur93d4PMNCoEdDoVeNHgN2n0jfKJGBJvfbgkUaOQ0wiqwtMYbsja1wqG8+2P2qD73d0TayQYdZq1k4/8SOg0adlROOBbTPD68jBOCBRkGkR2VQdHdFid1xQV7V9NL714t6hTdU+CooTp3ErWDGLRBHGlIBGrxqqcvUE0o0CK/JNIeN7FFh3ytutAkuPDJIAARdH5T1OwP4LfjItYtQ5kM7w/o3mMJ//5lE3C7Y5upQ5jQeCVcGlURbmoyYgmAb+r/HGmD6QLGjGn9ZqZ8oLh1z8+34XiYjxNonSej/eKJVU1AQcaVA4cMHPrAyZATFcC+6+Qsc9V+oQhUBn8nEPy44k5rYmiywwJlUKRcJxJQAI5eJHWGPT45uVIvLujS1Zz8+qvCza5exSYi2eeDhHj1HSsq+9QsD2QP//7THaQ/XmRFPo7z21/rju1+0qjBI8eZWBBo/arSi6WwSUNyp4FC2x1d1NC3lpUihF4VHgvh2JpXYuxqg+Eja9wEeV3m4Jg24RUOtWWV7mJqeP2O0OsbU3mUMk3rvd0WY6IpEQzDN9VNm97otuO++nD7qocigsGWuI+jNGWMWQnj5wwR9VcTuemJouc1+WnpI6P9/W+HqXAEWFVSe8jLCKLB4dHQmt+y/f+cFDomPJWAN+VeWeHd0XCDGRL88ddlHjVHn5OmNY2iBSBDva7F6V144mNgFZKSKzMmS21Phjcp5RzPaILd6nKZbOdqC0F3wBcT+yJhrd/3WhBZcfHt0bG4UWMwI2nvFR5VD4fY6BKV3slQxO41h0UfQkHsjWkZUisvK4O2bHnUVMQGexboNXJWt9E6IAayabunQTwV77WGVXJ/WXGGoWoyqSt4fCQTKvX68914sx3DgeMQGRKF2vAo/u0fbTls22RlyyLKn3U+NUmZcZfUD3UI6ebwotNN/Vh28KLeyYaYl4T1ikEXqNS2VMJ/vguux+Yz1N/3TcwxUpIk+OM/DiNUYW7XJ2msep82h9ODtvtbC6wMR/Hna3m1+3yALpRoGhZpEJaRK/SpdCZcrWOFnrD+t2iBbpRoGvb7Fg0wv8y3exj0965LQUUYDdt6aQ10/q0k7ChSP1rMjXpnlFkxIWDwTT3lPS5U4N+8huJ28ci42aWn+zmTnDdDy218Xy8tifWdFjJ2ZZZIEdMy2MsIq8cdTDMwddEWU0x9skXrrWyNR0OXRiSqR5qT+f8PLtT76oiyNtRefzh+soOq1tW+2JMyt69Miy3L4Sf51sYlxfiZXHPTx3yBWx/8ztK/GbDJlpg2TSTUJY05NfUal1qxyuVyip81NU5Y2pX86xinw4xUyuTeKTSi9ztzp6TFn1+JlxNr3mQ/P6SZQ3Koz5NHGK6e0Rv3OmBYtOYNn3bp462LOFIDG2bLa9wE4sbmZZqZvRfbQie35/KSGNv3Cknm0zLPhUmL3ZznOHe74KF1MC1A7yRU8dcPHIbk2ibp6ewvO5hl45D669Ub+6wMSKfBO1Hu2Ur8+q4nOAa9xPztWJcHpun5DxY6lYohEKL+cZQzs5K5oUCr5sjmsdIuYECBEEbak6gfnDdfz3eCPpJoFDdX7eOubhL4HN0fHA0muM3JOlY6hZZOd5Py8cdvFVtS/ug6BXT0+XBHjxGiP3XqljSMAQ6yq9bK3xcaxJockbu1uz6QXG2yRmDJZ5MFtPukmgvFFheZmbdys8vVZ3TojfD7jYFQTxxlFNunZlw0VbeaFnco3MypB7LFi77AloHfaPC+j/eZk6Mi2aRjjZrHDGqeL0ab8Vc6xRodajcs6lUONUSTcJDDFpv56RaRHpZ9BOwsowC6Ezh3ae97PhjJfNNT4O1ikJ0+CVkD9hEsTkgTJ3DteRlyaFNmEbRUKbv9tSW+fdKnafisuv9esXn/Xx8WkvRxO0xpzQBHSEwkEy6UaBUakSW2t8HGnwc9Z5+T1Kj51MLQig9qA9WnpxvFzO6LnDu1WS6E0Ckvbv7RmQRJKAJAFJJAm4HAhwJM3Qa3CIQGnSDr2GUhFYm7RDr2GtwHv1ALuAiUl7xBW7gfzgIrwg8EIS8TP+gtYq6BSQDywB9iQX5p5ZcAO2XRKw9SmA/wcG81lzqFAbMgAAAABJRU5ErkJggg== +http://www.bol.com/ + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/list.txt new file mode 100644 index 0000000000..b7fdb1e9be --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/list.txt @@ -0,0 +1,3 @@ +google +wikipedia-fy-NL +bolcom-fy-NL diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/wikipedia-fy-NL.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/wikipedia-fy-NL.xml new file mode 100644 index 0000000000..4260d9993b --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/fy-NL/wikipedia-fy-NL.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (fy) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://fy.wikipedia.org/wiki/Wiki:Sykje + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/amazon-en-GB.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/amazon-en-GB.xml new file mode 100644 index 0000000000..1ee5021e2c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/amazon-en-GB.xml @@ -0,0 +1,17 @@ + + + +Amazon.co.uk +Amazon.co.uk: Cuardach Comhtháite +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.co.uk/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/list.txt new file mode 100644 index 0000000000..2be6aca20f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/list.txt @@ -0,0 +1,5 @@ +amazon-en-GB +google +tearma +twitter +wikipedia-ga-IE diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/tearma.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/tearma.xml new file mode 100644 index 0000000000..e9f9d21117 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/tearma.xml @@ -0,0 +1,16 @@ + + + +tearma.ie +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoyNkIzMUU3MTM3OEQxMUU1QTUxRjhDODRGRkUxMDlBRCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyNkIzMUU3MDM3OEQxMUU1QTUxRjhDODRGRkUxMDlBRCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Rjc3RjExNzQwNzIwNjgxMThBNkQ5OEE0NTNEODRERTgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4c62kpAAAMJklEQVR42uxde4xUVxn/fXdmdl6wuyylgLTbgGVLjH/YaP+oJbap78BflcStEWtTIrEhmkatsfUZbajQqsGkEWOt4gtMLSmJ0YrBNDZqbGzSNGnsbpEiLEsD7PLYx+zOzv08d+7rO3funZ3dnZnd4vngMGfPnDl37vf7zvc8d6GhoSF4lFLtM6ptV+1WGGoFOcx+WrVHVTvrDJAHwCrVnjWMbxuNqNav2lHLk/xnDPPbSj0ez29yANim2mbDk7bTMtX2WJ7ON7Q4tMUB4CbDh0WjlANAh+HD4pFlWGAAMAAYMgAYAAwZAAwAhgwABgBDBgADgCEDgAHAkAHAAGDIAGAAMGQAuKopvRS+BBGBLQsVJQ8z3FqZyJCNFNuAasz8/wvATKoDg1MZ/GXUwuAE4+I0o+IzxAGEqy/Bq0NyzJvmjTNI/YGcz9W/3nwOgHZBAHo6CO/pBG7ttHF9ZhpUmVkc4RsaGjqpXnvbI+kWTtk5PHkmhRMTNuwGPlNl4pz/ndtns+oDt3Rb6L+2jC67dPUB4EjeEOew540URsrssUZwCZ7ISlH33/bf8vrkiTV7Ih6Me2sF8705Dc/3dtDbCxa+dP00CvbU1QGAncpg33AOL12yA+n02UsBrzlgmMcKTfXUbAkIMde3Sr1t1Nh8b7x/LWFL54QyFXZLAWipxbtAeewa7Kgy3+Eo+bpY9h3m+zxlaOPQ94qry8llECNmEwGaYQ16lLAOktf5zTDjyyeLKKc63poADFYK+OKghbGKK85MQuSrDHEtJgO6tSUx3wOHWUis84M3wEFf3xn+eBVEMYel9guA8gblOt7EockKPj+YwbiVe2sBMDBTxHf+Q6jY/o1RVdlyVfm6fapRIx4IPlLeq4sLhwaBvL3hrEH+egIBMc6B/ifPLviST2LLELRtFQiHu44jQJ8bSLUMhKYDcAZ5PHLClcKoMvAlkgOpE4x3TWYokVJkWazju5yBdEvmIzIeGvBgHX8OsT5fW19fZ1oJ0gODqZaoo6YC4HzBbxy3XAaT53d7wiUdRBICSAj1ujtOYj5CiadQb/v9wEqQcGu0ccFsosh4ZD4Jq0+165QUCA+f6ABZqaUJAKlI9psns5iy5baW290HQ/4cqiRdH4n32Q+gKFBBECoiVEFCvcl1KVQvFL2enK9FcTHrqLGzU4zDF/NLMxJ+qZTHqUlb+JfQnG32pTrqhJMrcauzFjZ3M3qzjEyLXIPJCmFwEvjrKDA+I2SD4/r69/P7h99k3NmdQ2eTArbmxAGpNO57LYtyYETFl0bkZkT0k7EId68F7uicRrpSbmvuaYw68Mz5NP58QXdFG6HrchZ29441JZfUFFk7diWHctVmuZLOwqFh4rDve5Fq7F1dFn7cN40PFMfbynw/DiiqSHd7zzh+2DeDlRmqiQniYj+/f7pUwTnOLQ0b4Oj+g8N6UCVsadVjEba42r/rWsIX1kwgZbeX8XHUyVP4/oYSNhZJT4FwAgSeW71/OL00ADhdySkPAWF6koXvXxPzM27uSuOubhXis40lQ/YMvnZdqWqHAJlpZS8YDMNmP6M6MGajksq0zggTUUPK8XfHx2FfrDR0seXqavesL4bJr5o4rD35+dh7syu4Z8UUHhuYRKXBr/HPcxm8t4cauGDyvSUa4f1P/B5PH3o+lN2YvDxikmYsXPPEvsjny/HVa1bgU/d+GB/8yLsxd9M4OxeO/vFfOPDUc3jz7Kj4vqGE6325b5PGRbzipWr9dKIfQ5Aa/1j/7dh5/5a57YDhoQteKlfPFFcjRQrDdqoVZBFkJfQpfr7DmL27D+Kpn/wBT/7iQeTzmaawfnKyjPu278H5c5fixTPoUbIIxyRhKWZEz+S6zHN4OS8b4HourG+hao6FAw9Tphz8PvuJMl8OglQDIq9ijvjp/LmL+PQnHq2TX56b5DtrOWsyR4xqTBojzOmxWEFPq3CNlxQmD93Uusy60vyNMAW6WtT5PBBIpAEouLDva7pRZNUt9YsjLCJWz2WtftKfEyTj3DkjF67gyOG/L5j9zhqjI1eC8mQ0TY1IypoSXE9KKCNwkOfSsliB4DbJC5Kbk2M2LcVu02hCQk4g4W3Eb3Dglz/7U+B1zNfYOmvItTlyNxSR9bg7phjFI98jP9Xhz+RwfDa/wprVemu4up6+VBz6Tva2n58+1rK+HGsPELENJPpjY5Ow7fkbY+ezzhpSjVD0e2tCwmE5QLs3XTXpRVUOpZ2hR/xCHS1gB5BWxCD2g60w5UuyYuJ8WSaZ3Q3VmVgnkgGO6TPqhqcNhbyyxkJaX16GI3Pc2xBzQDXrhHEZBSkXvd5DNXPnnoxjEb5yxH3x9Uh0nBI2bHQO16qj6Px8PgsrRfOOD5zPOmuUr0zUfPWm9OVtcc0tNiRAVgPyj1ARhSLFgZVnvUwoJ3i5oHCzhJJfHYf/HoeehNhw2z5++4KCM+ezzhoU8V24thJcM861SiZmPM6gR9amBdqAwNSQMEZBaj+S15dGmYQBo9BnJjkevEehAfMu29lZRP8n71ywF+SssXx5AQk8141knX4cfykCT9QLakR0rEZ0aIPDsTcUd4OccOP+WFf3Mvz84FfCWvCC0g6MA4ceQveK5TX5nCAtMc++7gUxQhFkbXxeAKy8pltgytq/hFBtaMVXkcQKynxSPjQviEMPwxvvXlHEjp1b8dvDX0ex2Lz6q7OWs6azdpe6hn50JU7xcIwK4gQF5qtPGQl4HPICMZeXcyzIEM3uwzq099VpvHypsWRcZ5rw7XcWsDJvJ0hr6xNy9e7rlVHgsdcaT8bt2JDFHautBq6ZfF/pegasIR27qQuvHI8ms2QFLBSKMdU5OJ7BrsLl2PXbkQxNzEpaKfxqLA9eWYAlzyBFPTjh8dz2tjJQmW7gmi2sB/SmpxCk0TlISgjlJRvhHyMzODpWWFCE23RSzN93NoehEuuhD4lzSFLRquHegoVMA8xveUGG7Qq2rfFPFEQrYhypjrn9A2eA/eeULk4t/uMJk1YWXz2Zw4uX6ntB0f5n1zXnOHtTasIf6pxC2tLzRbHuDofuzgsjNnYOZPFiaXGAmE514MjlIu4fSOO/pQaDKq+/OktYR0vpVISiv5WW4UenWGQHRVFCJHQJkVPQ3s7YWCBsXsFYm2EUU7PnUOZKFXaPGb5RIjx3gXCxPH+D84M+Gz082ZTv1TTRu60wgWdzBQyXwoOwvh/P4khmmCJ3c0b+nIFxVJ+Ucedb3ok5qlOxWkjfnvdnP7rKUswfb575aZp3Ydv41g1ldASn2RCcRanZzhwpMWjzKVIxi6aFuU66mBPTyPPr60X5azoId/dMNNf+N3OxnD2FhzeED1u4/KQgUKl6R37VLDg7RF4QEz1HRAn2j2rcSS1ZHPd8QEwOJ84tjb+W9xiT4tTu9eVq8X7JAuDQemsCu3rD4gQFYbnXJ7dapntHrJUPwiINJ3gjLHxFceormq7UTlVTNGiPzI+cnhZzVPyI795oI9uCx5Zacgrzluw4HuiNLF7v2BknjVOCN0L6CWtxrrOe91JzKIC5/pqK8uomHt/YPKPbFgAculmB8MiNjJwlcoYcbvuwQBIp6rMe8CSqDiHBnJCrjy+x6zkCrjN/ldL5+zbOtIz5LQXAoXU0gSf6yuhbZoU10iCDyKJPMf04w4hZ+9FM5exz4udvXUV4fMNkS9ROS+KA2RJgAzN5fO8kYbwSEWOapS/FPfp+vScm5zl/jQqyHrphBt3cnueF2/ugtmXh39N5/PSM+7CDrT3WHjwEHB7+quf2Jkq1XnqPO90WVVNpda1Nywj3rqlgtYpw2/krDNoKgNwRJasDL0+kcWyUcHqScXkmkn30n6YUBRT9SKQPEjcwR+87ercrQ3iHYvr7um30ZaeRqizOSe1FASBuZ1QohbKKgMuK61N2CzKlask82VWXMuP8WhDbXhIntJfEb0txomgLys92Ah64/7lK8y+C2t+QsATI/L4gA4ABwJABwABgyABgADBkADAAGDIAGAAMGQAMAIYMAAYAQwYAA4AhA8DVD8C0YcPiAvCqYcOiUcUB4NeGD4tGRxwADql21PCi7eQ8lfagb4T7VXve8KRtNKLaVtVet8TA+1XbodoxRzcZHrWEXldtr2qbVHvBGfifAAMAMyE2VNhTrbkAAAAASUVORK5CYII= + + + + + + +http://m.tearma.ie/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/wikipedia-ga-IE.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/wikipedia-ga-IE.xml new file mode 100644 index 0000000000..67d3bfb863 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ga-IE/wikipedia-ga-IE.xml @@ -0,0 +1,23 @@ + + + +Vicipéid (ga) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ga.wikipedia.org/wiki/Speisialta:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gd/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gd/faclair-beag.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/faclair-beag.xml new file mode 100644 index 0000000000..e57d903c4a --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/faclair-beag.xml @@ -0,0 +1,13 @@ + + + +Am Faclair Beag +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAIAAABt+uBvAAAAB3RJTUUH3wcCAAIzunMTVQAAAAlwSFlzAAAK8AAACvABQqw0mAAAAARnQU1BAACxjwv8YQUAABx2SURBVHja5Z15lNXz/8c/fYUUGVK0RzVtWqcy7SVpFe1xmrTgdFA5FTqOcxDOIZLCJBOSVmnTXkrrtDFttO+0CIWirP0ev/ucec17PnPndu+dqb6+3n+M2+d+7vv9ej9f2/P1fr8/H7nOnTvnZWxcyZUrl/3lCh+8f2Y7F2iaQnSzSIVAcJx3sBxHyvoMv3NXfxdBklzC2L47derU8ePHv/zyy99+++2qq67Kly9fsWLFYmNjL4QR/f333//5z3+CSum2X3755a+//rriiivy5Mnj++rIkSMpKSknTpwoXLhw7ty5+Sd/T58+jdh58+ZlCnz+448/6JOxZETnnMbN1157bZkyZSpWrEjnZmuuGLnd8bi6du3aMWPGfPXVVz/99BNdI9bll19eoECBChUqFCxYkB5r1ap18803I9aNN94IdldeeSVdnz17tnz58kxj5syZkydP/uGHH5CMiyVLlrzssst+//13OuED02jZsmXx4sXpuXbt2j50JMC33367bNmyLVu2MG06371793fffcf9zLZq1aqDBg2Ki4s7efLktm3bpk+fvnHjxuuvv75s2bJNmjThtvfee2/FihVgwYh0zjz//PNPQZM5kkhDfNWrV6+XX35Zo3PFh1HqL/ft2zdx4sStW7ceOHBg+/bt2JGvL2YIOldffTWTRNwzZ87weyYAgqirUaNGderUmT17NsDt3Lnz119/Vbfoh4kJaH4CpkWKFAE7rsfHxzPh/Pnz33TTTddccw0zQYbVq1fTw7Fjx7AaOuE28JLE9HPDDTeAOHOgK74FQS7GxMSgsNKlS3/zzTd79uw5evRopIaMf3To0KFGjRrorESJEn47krElJSUhaBRuIpiYKqYBUj4HMRvRdddksDsmDNxMDxPAzvlMV+79AITEaAXr8/08s/KiEF6NzpEcAYYMGYLVg8bfgZYa4PWfoUOHEnGiAwi5EdHmloMN0QklQuciNDB6++23sUFhJGTSNRydHOpLMSLHJSao4Ur8vTgA4aGjR4/+9NNPsSMLW6kAYcZBw9i/rZGd5s2bR+z/8ccfU8OFDImkUKlSpUst3n9FI2V36tQJpDK4GPESb7/Usl3KRiQtVKgQaQGOsmTJEksIqcGf3KxkDIO41KJe7EbwJTzXq1cPgvbxxx9DAKEdJNYMAGE+5F2+wKi446LFxUveSPBt27bt3LkzGCUnJzNx/IsroJaBB1FbwJUhHXC5i5ZWL3mjEhgwYADUFFzWrFnTuHHj1q1bCxCuZOBB77//Ppz9uuuu++cW7hE1iBvUPzEx8eDBg/Dy9evXd+3albjTvHnzVatWke/T6zX9AEYPkYHgZ2dU6Cx0HGZMyOczSsAYv//+e8yTQulSY5LeqC3q1q1LeUHcgd/s2rVrxIgRlJB8tXDhQoqtF154gdoldVL6D66YTc+ilG3atGn9+vUpagSQivXjx4/PmDFjwYIFhw8f/vnnny9hEqBUwEWoiu655x5ERUjEO3LkCMX5hAkTvEAgZhaIDUb2q1SAADI7zsVgCQkJvXv3xqu9tHUMkWyGJHcCHDUwJBVjBiYVzRetET3Kly9frlw54myDBg34IGs4efLkqFGjRo4cqduQmYKJKHzHHXf4AQK8rErB0A1nrlix4p133tmzZ094hAwErP8KNC0g4HdFixa97bbb4KLLli3bsWMHVJXi+yJAkz9/fsTDXpgzXkOaZppaA6GIobB45ZVXbD3k9OnTuFvlypWrVavmBwgLigIgjLZRo0ZPPPEEmnFXCby04k6fkQCZ+ABG8fHx+/fvx6Tx+SiWJiLSHIbTpUuXli1bVq9eHQuwslFLVHjWsGHDfKtF6BgT85ylu1SA6CvSFQMwJeYPHDgQu9D8BfH/0/OAfxk6tqqrD7gh5oZZJSUlkS9yHBomgsvHxcUx1bvvvhsfl0VrEQPZwOjdd9/FdlRgu0UoOIIdKiTVpPam/5C/NMkwGx3dfvvtjz322K233soPGVULmgoukkN42XKnu35epEgRbJ56Z+/evTlYJAMNYRiFEYZBB2YswSSSCTNp0qThw4fjUJl7IJvzLWg8++yzGQCKKLlQkZAm+/TpU6VKFcZTwpIcGLYs2UszGVmQbSqYuLgnus0paGjEl5o1a7Zq1Qq+R8hDSGnFVQ81+qJFi4jKQWmH1i2JjzExMXzQClcqQGS7MC0IB4Y+9O/fH2ls1d3dVDGLcK3GCzigjFxrbHgo08ASs0m+1Igd7du37969e8mSJYHGcqhr2rjz9OnTp06d6mZxt6Fp1AY0fKDeos90gMjEYQZpCGjfvn0xYC2JYzISwszEApBvT83CntkUcjCZbAJECYmqYH0ERKbkRlzbqiHoQC+oFlasWEGxnlVXyryIB702c0kFCKOCK8ILQktDGsJ2sGHsSETZ1KX6Rand7hdeipGeY1PKJhFFvaAKh5RSWJJJMRxjKr59G2jXrFmziCwQelJ7iA6R6uzZs4gK6MwrA0AUBLfccsuxY8dCCA3XevDBB4nNmjDS0AtDUsvQtdKqlxZ6VOyZGpkMpkvnuQNN92jDIzp0qKvvu+8+Ig7shmAh/3UVQ2O2FFYzZ85cvnw5lOK8SxToG2iwaHf5OL0Wo4UguKVKlQIdBGJ6zJO+MLfk5GQkAFZ6hICiSUysQIECKlwQUXBLpeaJXtpeCHdC5IJmk9ANKtyvXz8qbyKDa7AMoXEJxvgU0KxcuRJoQCqcbpm+JX4EywAQrIRERu9BMWLyvXr16tixIzPnBm5D82vXrn3++echxDJLLGj27NlEARgE7KNNmzZIL6Wlrl0GNj8srTDcqVOnIq05+GHDhg2hURgyc1DU9wIWijkjFdlm8+bNROINGzYATURbCZKNOcIP/C4GFSaAa5fWR0y4QkiGj8K+mJUyAuXCxIkTt23bZreBBUhp25qyC3sEI+0I2+62aRuIuXPNmjURVfn4+F133dWiRQtJi3kqxmnlAFZFrbdu3ToAojCOLsDBFYiwVCeKsOkA4cnkSKh3ZolhdD169CBCgY5+hlNQUs2bNy+rYUioI0aMIF9069aN8Ok5CcUL0ChGmTNnztKlS8NcusQwMRnQqVWrlqpwBUGgwSpJyUQZahfcCgvKDvNE99gdtm9rG+nLHdTiKGHBggUEbBsDygsrpYCSTLpI9NmyZUvo+IqBMH+0QfByjwyADrrlqw8//PDEiRPhCA1ZT0hIoB6mRuHnCv9XBBr5AU//5JNPUBhmG2asCdGY1L59+1zGkwoQQ6IZRFmyZImrgdjYWC4iiu2l0fAvLPm8g6EKjAg4+LlcDG1jhpCRsWPHwjXO2wOZG4ciohH+MSKgUX6gH4IL6vzss8/QKOEmdP4OvymewmD9AKkxtjsSQFatWlXx225A7Qh06NCh8w6GoXGzjnYAkIyWtEIdRPoL/Vt+Urly5Xbt2jVr1oyoT8SRDKRhgIYKQ20wHILgeblbRE0VOC0DQEariERwGXKkvqPwIxySjEX/tIJBUt+0aVM4gzElAJInahVm9erVb7zxBswgxK8YhUExHLIVpIFwoOUbhgYmFLN48eL58+cTdHIWGrWmTZsOHjw4JSUlA0CWXHAoILTvoBtAhjJVHAgmxCIQhjkeJICIrhVYYH3nnXdwihD3oxJCHgQnLi4OxQhloEEqIjHuP2XKFAAiSuY4NGqEToKau/qcwcVQlxuAqlWrRg5SNvUyHlILczySPXEUiEEnKSmJ2JzVnXJnbJvER8b8K63p4BcxGJKFT+3fv/8CQaMG8yBu2lqHHyBClDE31A5AQGZLGSIdlwVamOPRoRYQXnvtNaJGVosqGAgOBRel7MSIuE3KgG0TE8Fl5MiRsJsLCo3EgBLbqlYQgHbt2mUBiLRau3Zt0VO7wRblwhySRDZ9+nS6XbhwYVbMDSPFrYjHoOMFfEqnBxkFuoRPEdR1zuxCN1shgfQEB0jnEr3AHg78EBJktYIBhEWEn1PxCJSfFRvEPCF+0D8SOaoTNCp3GGX37t1z58598803KccvAjpeYFkVgSFuCBYcIJSpc2Y4FxGa2KHiwzDS+qEbyEO3ED5F+CeFU98xkGp9L207BMPBoSZMmEDpEPVqEUNYmFe38lkUQA1IoMlcBhLvsJ0SJUrYyQU/QERHihE+wEGgP+7RWd3AZ+aDR4A05haF3PA9hq9RowalA+bDHHA9qwFxcKgNIRn6R00XRf9gHRMTg5DVq1dnOlKtVgjxHWbHZyo1iBgDwUJcx8cgMBEqVcSAtaeu6rm9Q8BwHwagLNSJTDt8aTSa4E14go8QXCxghW5aZ4EWV6pUCYJTt27dMmXKEIzFjCUH4Zw+IQHE8i+++CKKDVj8glnBKsmGxAfGwl4Uy7TPo/Si/S/4DoUbnJ6/wCQLQAaCJiq0FX6/BakshoNgQYRnM0LXjhgPEyDj0B2UhL+M567g2WetbwAovYEIyqlXrx6Fi0UZ3S8+CQ8AcQwnoojDQCgSb8LeYZVNmjShfy11i53Y0p1qSRE6tFWnTh1yAqmTEaGd5FndhiQ4h7vGlAEg7b2iBFuIMiNyt7e8QLSiuIXyUiLSOz6CTBIIG6QT5NY59qaBpjpT6Q9EbHcIOFRSEY937twZPjTyF7DAXlAAf6tUqYJVaotFccdutl0WBQ0lDXrA03FGfp6YmAg115lv4EOvfoCkdlIJU8J13TOdtkPgOcu99IKuAAib3LNnD6EU4VSUUovgpORBhqEfLNZWi+38sWCCkS9atIiyHowidSisuFWrVvHx8bgS6DOWEJGZeGmszdKisTlTMybGzegS/SEM7BwNMRGt5/gB0o/Hjx9PANOCqbo2RHRFmdiqc2ACTdzHdUOt1Lh2Z03/5K8q3pkzZ1I9hNhmCNqYEgEY+6UiUUox03Dn4jkbc17Gx37OZWzayEpISBg2bBilhh5SCW5B69atIwUSerlJRmSDSRte2qa78r0+2x68bebYZ9sLk5Tq5ODBgx8FGjkh0iVXqBmkCXKA4TAN28I1jMxwDBTfYqZFUvcGAiW+htUzdzNGvwVhV0jMX9RiBaoNJqPAZDRb9WK7Ou4eoVuyuZ6lfUsIztixY0lVUazVExx79uzZvn37woULW7mTuTD0pQurtM3MLeEYfLYCh4ugYPr3A0SDfYjaEGXd7VoD2+AwIXwbyu7ei2lVPWiliWKVgn716tVRZHGS1EMPPUSe0n6DZiiYbAfV2KxhZEcNXRxtaqZIbtPqrRcoQomnQQAiAOnMjm3RuHqwD9a8jCvNQbVnV8id5KkZM2aQziNFB3GJx/feey+hh/how1npJJhcv3BrI3NwZTdCmIAwpbohkm+hr+4U0gH6+uuvxU3gTqiLFChHs/Dh29iyrn0nN9xgqe0d4vG4ceOIx9SckW42QEop1giiSlVegKy5Fi2pEFLFhDZRLDm4fqBFft+2jaFM9CDs8tmShp8o2jNiVECYGRFLz8gZ2fUyPRFoPuUKoXbmzBkC3po1a6DFa9euxXAirTmJOEBDWRMbG2sPWrmgwFEJmqRdWBhp8eTJkyCIAyIzQyMYmEJ6LdNpUdzyrBRsi6U6xMM/cSM72pEBIB1P0+NqU6dO5XOfPn0gO9pKtRMHBq1vu10+LA1QRgEK7AZcGE9BLXxomBjQQHPxKfSUvgOTO7f2LOmQgnbVqlXw4L179/IVMoOX2YhCj5a0SE+YoRt3XfnVmCBA7969Wyc46coPkO18ystIMVOmTKE4QlB4VKlSpfiBETA7UGIhnMYPdwQaXIEwjNyYTKQOhZHjTZ06dYIBUj3YoDolQW90C7fcsmULhIWxYAwhdtaYKnOmH1AjiunogOdQNstlCI/7o0t4crt27YIsd6ABrBSWYTvZYESptWvXLtyEkETxYgsgOuanPRx6Bwh6nzdvHlaDxPDjKFI4DXtBH1T5uDYRQS6gww7IBjQER4oS/oJOOMu+Wh5AGMg6nWgv38iq3cZE4NBkWK63bNmyb9++TIeiwg8QHTFVn0KYMLYHRkimR4O5B4D0LK9YA7UFuvr888+jWwDxApVd27ZtSeF4hPSswMko9IlJrly5kv63bdvGWJF2jt2lpKRgm6i/du3aZpVGXzRNbdVgldTMCOO3IJHaoMsXDMC3uBvBW+sGoucWGrC4qE+xgG/9+vVJ4Tiywo28UusKxLKFCxfOmTNHT2FHN4RQwO4AGttkFJclav1Mz1ZzkREnTZrUrVs3P0BexqCVuQFfjpyV86FDBXT//fdr7cbqTG23Y7MoE+PN6rSwdtBJXuG4G1FGz/4aERFAXMQwifcoBisjP8ip/QCZ4V20xogPPPDAI488omMRskEZJnb+SaCF2KGsW7dumzZttm/fTnwJZzgCAoC6FFEZhsCCDoieXsBEMAJb7shAFIlSF/MZMThOjx49evXqVahQIcKfNMl1fJx4MW3aNNAJ4VNkjAEDBjRo0OCDDz7wnS3Lqml9w3eRQVEGoUMcEElgy5UrV9a3GYiiHqILc7DsNJ2Q7tChQ6NGjSjHtUGi9QCiwMyZM/V+gxBBDXQGDx5MRJfAWCITO++4OhJpJYXVUvgXpEH3IE/RokXhNO4PUwEqXry4Puh05oWAhpIKdkM8hpIUKFBA71bQygnQEB2XL18OQUWHITqpUKEC9BUq4AXCIhGXbsMBSFzXS2O2OhKHWeisl829dOnSZLogAJUpUyYmJgaJgVZvH8hBaCgUYFJwHFiGIg6RVeGGEdEhhItKjUQe2n7hGY8++mjjxo21K83P8VAocjhnBVAJ1oGN2CoVH2AwjG6TBWidtwwCEEGBKhY+RukUjkLCbNqBwR3at28v3wYRlZSoAWPR8ScS1nlLfFTYs2dPAjMmwxzkI3nz5nVZb4hGzYR12EMB8i8iryoVa8Rs38mI9HzWuXNnSgTUmCPQYDVA06JFCxwKzRMptFYvBSIHmpgxYwY0J5znoogADz/8cMeOHYGDaCJ0tEes3cHQDVwIeaRwOyenrUoAckfH6fTkVhCAMDMCZ1JSUphbXSEaWBDnSDH4FEGH8pop2XkEPlDNYjjjx49PTk4Ox1oxE2p63BN0tF1heZor2P55n2YHmpo1a2LOttQFQES9zZs3uw6FUeP7qv79AGlICGV2oNFzSMRRHIr5oA3UpWPmudKeWMPn586dSxW+b9++MCNd8+bNKV8pjrTVZdsB/BPsqE7gRGJ6WSkMkewpUS8QjKktJk+ejMf4btZxlCAAeYEj+1FDg3ESGmrUqIGs2I6O6dr+lx7RwpgpxHErn95CNwIH5TWh3UXHmp7KQhOQA9iTThi61qSXBnTv3l1nSWU+jA46cCjfKQxFfTsh7QeIkBlFSaVHtEhSXbp0wYwpNdGYrciYtrVWT8SJdJOHpFu2bFktdOmKu1kgjBhXvkbChjEsW7ZMryZBSXyLLaM5Pkse5gifIDNkPqOilTafJaYDZFt6YTZEBA7sheAFebOzxbZeJ/Phn8TjxMREErmquVxZvDArq1EsJJ8LPLfje4JGmqcKxdb4FmqzdOlS6lLmiUhxcXF6OkJuzp1koeHDh2d1MoJ7cMbgAPGb8M8ZMzbQEDvr1avH8O7Oh61jIiIpE3E/+ugjLMjicURqIGrqhV+2pOvbI7ClTtWiVFKKgIrEMmcNCjrQwhEjRlB8ZTUc98D1gwOE8YfJoUuWLEnGJXDywa2Pc6U9fUk/QIPJYO1Ic/z4cXv4J9KGaygoqAeVbO5TjO4+imxWa1WSR8e7tVZLWsB2QpyT9ALrzr7TT+kA4b1axwtBZxmpSpUq1JmtW7cmf9u+oL61p1Rw8ilTpmDM9JlN2im/8O155Up71tIe79EV83HP2UGV6R04cODVV1+dM2dOaELAb7FZK7wyAAQ6emaGIB9U29wAkSUjkFltY9q4nzjY0aNHZ8+ejU+RzrP/YICXdvTd5T7uirjB5Nt9MjSFEfTl9ddfpxI+71ow8sMeMYIgAME19ZI/uss8N+wWw+ndu3eJEiVEKNy9Vu24Q/9wK/5S4+RUxYt76hyYu1ngZdradXfBPOcVlrgkwgwdOhS1hbNSzjThk+6VdICwi+eee27MmDGHDh3KDBBV+KBBg8Tr3d16RGEOnwbapk2bdDA6R6BRI5ZB0BRH3DNKZraec3LDHt9XotBDV9gO1DQcdLgfVtWsWbMgADE2lAHG5a7+mkK6du365JNP6s0TJhmNO+F+DI/pUVJfiBeXwM4mTJjAWBAivb3HeIrvgXMDTi5JrICavvjii7NmzQqTA/PDrVu3omb31RTpR0BwLjire7hKjYQFamiANAePOnXqFHQGs8eVnnrqKUjahX75GejAZagTd+3ahUEhBnbxQ6CRBPisi98FGh+0w0W2wuojfTkkfAoO6Z4eSt/nxlGpA3Sf2U7btm2ffvpp4o42G9EeAjH8ihUryN8bNmwAqQu9VoulrF+/Hg0hOvogUTANL7AO7zu5oZQHbxo3btzUqVNhdhHtXObLl69q1ap+fdsY9rYKa5TjkGDsBRNFPsjesGHDEhISKLjCWWS4EI2SFeL+zDPP4DjkY6gz4unVrvq7d+/el156ybb9Imrgy5T379/vWlCqpQAERbNbKDVt2hQHJuERWQAI8o5OMJwotu5yvGHLsbGxcDFcT69lwYoxbUIBVkNlH/V7ZYh0K1euFDXNsKtB166n1KpV6/HHH9erOYhb06dPnz9//o4dOy41MqkN50Iq5MH3Vejo3KOd4Im6waSxBsqx9HMsMqTRo0fb2iWpjsREhkInUD58/kK8yPa/s2ETkyZNIhGlRzf956233lINQnlFLCQkU7kMGTLE3nX2L2kYI4R58eLFGbKYFyiyRA6pgymycCiMaPLkydGd0/iHNrnqxo0bqSXsNWapABUsWLBLly56J3xiYiIcJ5zHdv/HGpEELqpXG9rFVIDq1KlDAB81ahS+lv11+39oAxoiDGzIXWxMJYoUGURvoMmREvwf2siAsET4d7ly5exi6gt3vMAb9eLj4yGpmasNL2B+2SwpLtBr3XOwQTshCqBTr149W+S6TE/4Ku2XLVsWA4ObQlJ9RXnDhg3r168Pk8QOzcqYM+TANTpblNCBTrvOryAXNWrUwMm5v3jx4vAXnaWlB62o+07GZdXy5MkjoCM9ZyF6nXljAtmIvEwcfsjnUqVKYSi50h5SSd8X04vXevbsCTedNm3ali1bYGLGuxo0aNC5c2emBxOnZNMDPBgdZUdycjIf4E2q5iFs1P3MnFygY0uMxJRw4caNG8fFxVHKtWjRQucPmS1sC0pBtUVaQIEwdc1fpyW1oEH/ej4cZlihQgUmc+DAAbQFYdm+fbu9ecALPETEzfRw+PBh7rdX2vC3X79+s2fPJv/opGXRokW5zijwGxRGIaEnFO0guf+ctK3LMY1ixYpR9ROzIazgqv/XSaVKlQYOHLhgwQIQgSwgBzL1798/JSUFvKih+QnxH1LOt0WKFEEa0CT804PWmLAa/dNd98WOKlasCB310rbGMWHmQD9Iz836v5343igP7wd9MFq4cCGw0rkeUgI4sg1fwf4p7hmOb+mTnhGJsYghROKdO3dSVMbExIwdO5au9LpMvdXNy/i/jPHvwNh3e/bsoVjX1ii9Q6+pdMO3Z72YUe+TQFw60Va6yhxXgqxOqYdo4d+pxujIYKfFtYyrg0UEEzRtr6jJ3G2QLSp7qCD09czdhSN3pHOLrmU1hSgEi2AP79/Z/g+h7MLZpF/GpQAAAABJRU5ErkJggg== + + + +http://www.faclair.com/m + \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gd/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/list.txt new file mode 100644 index 0000000000..8402ab420e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/list.txt @@ -0,0 +1,6 @@ +bing +duckduckgo +faclair-beag +google +wikipedia-gd +yahoo-en-GB diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gd/wikipedia-gd.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/wikipedia-gd.xml new file mode 100644 index 0000000000..4358141999 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/wikipedia-gd.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (gd) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://gd.wikipedia.org/wiki/Sònraichte:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gd/yahoo-en-GB.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/yahoo-en-GB.xml new file mode 100644 index 0000000000..91713ad634 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gd/yahoo-en-GB.xml @@ -0,0 +1,22 @@ + + + +Yahoo.co.uk +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://uk.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gl/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/gl/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gl/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gl/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/gl/list.txt new file mode 100644 index 0000000000..5d0d1f3591 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gl/list.txt @@ -0,0 +1,6 @@ +amazondotcom +bing +google +twitter +wikipedia-gl +yahoo-es diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gl/wikipedia-gl.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gl/wikipedia-gl.xml new file mode 100644 index 0000000000..815f8113e9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gl/wikipedia-gl.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (gl) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://gl.wikipedia.org/wiki/Especial:Procurar + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gl/yahoo-es.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gl/yahoo-es.xml new file mode 100644 index 0000000000..a9b50bc07e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gl/yahoo-es.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://es.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/eBay-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/eBay-in.xml new file mode 100644 index 0000000000..8d27d340f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/eBay-in.xml @@ -0,0 +1,17 @@ + + + +eBay India +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/list.txt new file mode 100644 index 0000000000..19a819dccf --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/list.txt @@ -0,0 +1,6 @@ +amazon-in +bing +eBay-in +google +wikipedia-gu +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/wikipedia-gu.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/wikipedia-gu.xml new file mode 100644 index 0000000000..f47992634f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/wikipedia-gu.xml @@ -0,0 +1,23 @@ + + + +વિકિપીડિયા (gu) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://gu.wikipedia.org/wiki/વિશેષ:શોધ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/gu-IN/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/he/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/he/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/he/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/he/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/he/list.txt new file mode 100644 index 0000000000..7d3db56d89 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/he/list.txt @@ -0,0 +1,3 @@ +google +twitter +wikipedia-he diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/he/wikipedia-he.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/he/wikipedia-he.xml new file mode 100644 index 0000000000..886ed724ed --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/he/wikipedia-he.xml @@ -0,0 +1,23 @@ + + + +ויקיפדיה +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://he.wikipedia.org/wiki/מיוחד:חיפוש + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/list.txt new file mode 100644 index 0000000000..b299ab348f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/list.txt @@ -0,0 +1,6 @@ +amazon-in +bing +google +twitter +wikipedia-hi +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/wikipedia-hi.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/wikipedia-hi.xml new file mode 100644 index 0000000000..bb7d00de5e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/wikipedia-hi.xml @@ -0,0 +1,23 @@ + + + +विकिपीडिया (hi) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://hi.wikipedia.org/wiki/विशेष:खोज + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hi-IN/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hr/amazon-en-GB.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hr/amazon-en-GB.xml new file mode 100644 index 0000000000..3a3fbabb19 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hr/amazon-en-GB.xml @@ -0,0 +1,16 @@ + + + +Amazon.co.uk +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.co.uk/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hr/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hr/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hr/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hr/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hr/list.txt new file mode 100644 index 0000000000..e4faa0be43 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hr/list.txt @@ -0,0 +1,7 @@ +amazon-en-GB +bing +duckduckgo +google +twitter +wikipedia-hr +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hr/wikipedia-hr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hr/wikipedia-hr.xml new file mode 100644 index 0000000000..138f852710 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hr/wikipedia-hr.xml @@ -0,0 +1,23 @@ + + + +Wikipedija (hr) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://hr.wikipedia.org/wiki/Posebno:Traži + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/amazon-de.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/amazon-de.xml new file mode 100644 index 0000000000..d19cc3133a --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/amazon-de.xml @@ -0,0 +1,16 @@ + + + +Amazon.de +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.de/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/list.txt new file mode 100644 index 0000000000..bc281cb69f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/list.txt @@ -0,0 +1,6 @@ +amazon-de +bing +google +twitter +wikipedia-hsb +yahoo-de diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/wikipedia-hsb.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/wikipedia-hsb.xml new file mode 100644 index 0000000000..fd20d12a23 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/wikipedia-hsb.xml @@ -0,0 +1,23 @@ + + + +Wikipedija (hsb) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://hsb.wikipedia.org/wiki/Specialnje:Pytać + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/yahoo-de.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/yahoo-de.xml new file mode 100644 index 0000000000..04b36eea83 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hsb/yahoo-de.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://de.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hu/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hu/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/list.txt new file mode 100644 index 0000000000..67c96f2e7d --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/list.txt @@ -0,0 +1,5 @@ +google +sztaki-en-hu +vatera +twitter +wikipedia-hu diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hu/sztaki-en-hu.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/sztaki-en-hu.xml new file mode 100644 index 0000000000..ac761c4c95 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/sztaki-en-hu.xml @@ -0,0 +1,20 @@ + + + + SZTAKI angol-magyar + UTF-8 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAABWASURBVHja7F0JeJTltX7/WTJb9n2DkIQlBBAMyCK7tVrUehGqUFoQqKJV2lrbe3uvvb3PbR/FulIqYBWVgvWKxR1FihYkbIkkgBggZIVAlskkmSSz7/ecbxIFAaHMZCa0c3x+JyHL/895z3m/95zz/X+kqVOnDgNgWLFixbQBAwbcr1Qqp9LnWkQs6Obz+drtdvuWw4cPP//xxx/XzJw5M0VasmRJ4urVq79HX3+KjtiIm0JiNXQspuO4VFFR8W+5ubmb6BN1xC8htWOSJP1AlpSUtDzi/LBYIVHSPJlCoZgW8UXY7Fsy+l9UxA9hs2xZxAdhNUUEgPCaNwJAmC0CQASACAARiwAQASBiEQD+RQsBn8kMaPtv99nndAF2B3xWG3wWq/+VP3c44XW7IVMqoRs/BrJoHRwON2rqDYiKkiMmRg2tWgEVfdyvAXDb7P3P6T6JnKiA5PHCUlYGR20DfDYbvHStwvkEis/tos8dwvG6EcMgj4uFw+XE+9tPoLXdgtgkHVIStchI0SEnMw4DM2IRF6PqfwB4JalfXIjb7YW+3YrmFhOGD02DTqeB12mFZX85rAcryOkU8WYLvBT5PhcB4PEIQBSJ8Uj+0Xwo6XdwBuwvO4lGvQm65GjEaKMQG62CVhOF1CQthuUmYfyoTOQNiEc/edtQSPLwLgNOlwdNrRZUn+pE/al2mDptyEyPQ0pStKAZ894DsJQegkyjoqj3cHp8Vcf3ZoPL7QeRMqbuVAdO1LdDGa+BmrIougeEhDgNKqpasa24FkWF6bhhYg6GD06GIszvXyGPjQnbyc/ozag6aUQVOayhqQsnqvXoNJgx68YCPxVRlHuMXfAS70tKxTnO/2YK8wlgnU4PTBYnZZZFrAUxOhWSCJiWNjN2lzVg4pgs3DZzCAryksIHgMPlRaghMFlcOF7XjqPVBtSdNtJrK6pPtkPf3AWdTBKRHLz1xAePxwerzQub3Q1jlw06ApmBaOu0ovRII26Zlo87ZxWKbAk5AGaLA8lJoY368go9RX6boIQvTuiJgkyw2Ijj7S5o+tAJvZnh6raL8xnptbOlGy/VGNBGNHjfousQqwstCCQ1QnMiD0X18Tojyr5oQiVRTtkXjYJ6ukz2oEb8ZQFB/znNDhgJ+EGjB+CBZZNx15xx0LkJmIZGyLIzQghACMzr9eFoVTt276/HEYr6shMtaGjpgs3mFlEZEpOE50kq0YJtdSIrKx7Lf3kz7l40CRlxUTC9/QFqN74Ne1UNEh5YgoSl8/45AJBI72m1aowuzERjczfe2XYMtYfPwMUFkiZE6c6a00EFncmBtPRYLFgyGQ///NvIjlfAsWMPqh9fAxOpLVm0FvLoaLQ9too1LRLuX4i+1quKvna+SqWCTCaDRiPD3NtGYcyoDLy48TNseKMMeuJfxKr9g7m+SgTKPnRbEU0ydME9k3H/0im4tiAV1uJ9qFu9HsYPd3ARIhzv6TRRZR2FxB/MQeK3p0MRFQUX1RxXLQC9zj/b8nOS8cRvbsHd88bijy/uxYa3DsJutAKk1YO2HnHUUmEHkqAypRxzZ1+Lhx+6ERNHpAFV1Ti5+DEY39sGb7cFkk7rL+rsdiTccQvSHr4XuglFZ61d9DWv9+oDwFvXACdFkCp3AGl45XlfL6Rq909Pz8Hd88fi6bXF+Ojvx2EjIHwZSpE5V8zzbF1WSNEaTJ8yGL986Fu4dWo+0NiEpl89itZXNsHd1UWFnYarIFFhR0+diPSfL0PcLTec9yvlcjnVE04oFIqrBwBPYwusH++G9fOjwvmJd30Xsd++8PajSeNy8NYrC/HhJ5VYtWYX9pWdFC2FK21nmInnxxYNxEPE8XfdMRpRbW3Q//45tL70Ohx1p0TPSEaZ6TNboJ0wFqkPLELCnbfTv114PVLS9e87UI2crESkpsT2AQBB5l5uH9iLS+GorYf1yFHYjh5F+4Y3EHfbjUh76B5ETxwHKer8N3srVb/Tr8/D1k+OIyP1ykpDnUaJJ3/7XcyYkoeMGBkMz6xFy9qNsNdVU1apKerV8JhMUA8fgrTlS4TjuZd0IXO5PThGNcrqV/Zi05vlmHldKjZtvD/4AMhkwV3l1bExkE+bCEdlNYHhgjo3XzTQzCWfwbrsGJLn3YHU5fdCkZJ43s9yJXrX7aOv+NzcP/r+7NGw79qDqidXw1pBGehRQD3Y39rgKE9cMBspyxZCkZx40d9jJpn60qulWL9hP4ztFsQlxuBQbQfeeKcU8+6YEFwAuFEVPNkjE5wpH5KLrBX/hZT7Fvl5WXC6BB+pDS/PH/q0reqBLyUFAx7/H8h00XRaf4r7aCFlpaNMT7mMotGHqRPzcNPMoSQk/LWq1WqDobWJahc7KbrgbaVVyIPYDVSfxaPM/arBgwLDkxbJy9Hh4vu+ekfQFA4L6Lw8Nxg7Ouu8f2/QedHS0ozc3NxgrgHBWQRYJUgUZSzpfEGQbRJlE1OX1NM8+MYCt6cl7fN6vhbJHpSUlmLT5s2ora39Uslw9f2PKi3+fhdlsJbU04oVKzAwJyc4pNFYXeOLzwy892HfXgz36UbYjtfApTdw/yGwCyMq48GL9VAFLZyWc6P8qx6HaFNrikZCTnTDFPdVvwc4aTXh1aY6nKG1JS4zXTjvXMdL/0ChKwng2trbMESlwxOvvxoM/+sVYuYaoDmOHIPl032wV9bAcuAwPF2mIDTM/OzD84qLzgKoyOMhjenve8Xr2c49RT+yMoEcPGQQRo0ahWuvvRYZGRkiC1jXd3Z2oovqATsVYJwpl5sF/HNf7N6L7pZWxKanBqMbGrgKchz4nKjHS5FqhkTrgPwi0u4Ke8jfPIih62dtf7a1Sl6sVtuhHpqHMWPGYOLEiQKE1NRU4fDysjIYNr2DDL0RagpAOYN3FvBn13TnUBplpR1exLscOLW3BKPm3h7+QoxVjZsKL3eHEe5245fjwdD2l78CqINUz0qlFbIh+ZgwYQKmTZuGwsJCJCUlicg/SM5vf3INZlbUXVGLw+3zQuZ1Qb+jOCgABCyBHBWV8Fqswvn8Gk6zUvyuVdpgJ9oZN24cZs6cibFjxyIzM1P0cw4cOAD9089j1JU4vwdoOeVGNAmEltJy2No7wg+A60QdvFa7mN36+rhz+I3yn44XlHbo87JQVFSEGTNm4JprrkFCQgIcDgcOHjyIuieew5gjNQF3eDUEgP1MEwzHT4QZAIoqph+OfOZ/n9cXFufzErpBYUdVTipGjx6N6dOnC+5PTEwU7eSKigocenIVig5XBeV8SsoCGRVkTccqw7sGeM3k+G4TvDab6Cp+2QruI36/mL2tcKAkOwFFFPHsfM6A5ORkQTtVVVXY+cRKzCg9BnkwRp+ChqjopPfZEoQMCKgQ441SbuJBV2sb3IZ2sU8nqI6nN8k737gmuOB10te3yezYlhGDa0aOFAvu+PHjkZ6eLr5cV1eHj55ehSn7K6B0e4J2aXI6r5qyoKuxGS4KPGXUlU/2FFIgfW6qVFUDsiCRHudGl88TvDcJGfeOvHCePA2fjYC9QMtkr+TAm8lqDCeVw85nuckLLvP06dOn8dHz6zDx03JobI6gJiUvxCo6mg0Gsb4EBIA8JvqKf1g1IBMZ//2Q3/FBnhpxK8Jt7ETdggdgPXxUFGRnZ8FhmRt/TlAgd3gBJk+ejEmTJiE7O1sUWs3Nzfjbxr9g5Ae7EGMKvjKTetYBe1c3nBSEgWysUiCAdjQ33OSaPrzJvqeL+vVWUJ3Mg5difMgePgxTpkwRx6BBgxBFkWigqNz+zrvIfmMrkjq6++ayRBYQARAFcwYEtAZ4A1AuPLmyOG2kNDzo7LYjJVGHhHjNpdcOuxMeKuml3nkxOdpLXMo7n6OyM0U1LZYBlrVf4/5GqnJXaV2IGzZMUA47Pz8/X8yfjUYjdmz5EPHrNiGzub3P1ZfL6aDiLkAAus12xMVd2aht684qvP7OEbTquzB5Uj5+/uPpSLiEbDW+uw2ta9aLRZt7PGKfv9UKZWYq0u9bCNXCi+/HaWPnqx1QDx0sqtypU6di6NCh0Gg0MJvN2LOrGHjxNQxs0KNPBTGlABOu28dj0MAqfwUPH67UzB0WingdFi+4DjdNHwqtRnlRRWPaXQr9yhfR/bdd9CldPveOXCbItXFI+t53Mei/HoQ7Nxc799UhLycROVnn9pNI6GI1VbmeIXmYdN11X7YYoqOjYSMZXFJSAsPjqzDiwDE4+7rzQQg4YILDHh3w7wpoa+LUqflYuGgyopQXr+cspQdheOFVdL61FR4qXuQxup6mnQqp3/8h0h9cDPX4IpR83oSVP3kTO3Yex1uvLj0HACddI7cYOvIHYAJpfNb63FyLjY31N9fKy9G4+T1MH1IAaUhBn1OPlwKo02iAxtwBpTIqQAACsEGDki/qfPuJGrT+8WV0bN4Cd0enfxsISUluW8TfPAMD//NBKCdPQE2zGc/+6m389d3P0d7YiYT0WOLzc3v/G6K9qM3JxDiqbtn5XO1yi6G3ym04dQo/fO4ZMQ4NhXGB13XoMGK2fQRVgCIkaNtSeqdMztONaFv3Ggwvb4Jb3wqZVguuNXykFnQTi5D98H2Inj0LZzrsWPfUJ1i7fg/aWk2ATgUk6SCPkp+z7v7FpEd5bhrG9lS53NfnFgP38LnKPXToEBYuXAiFKnS3H7npvZhtViEioqLCmAFn7xjzdBjRvmGzoBt7VZ3o0UtajWhXaItGIW353UhcOAcdDhme+tNurFu/D9U1rf6tiaSexKrpdJ8jOV97czM+UfswcuQowfnXEfenpaUJsHnEWFxcLJzPi3AojaUnD2Y441QBAq8INOpZxRjf3oqWZ1+AjQomkLIRPE8aWZ2TjcxHlyDx7rvgjovHK5sP4rkXduPw4TP0fTIR8T2r2nm2ZcsWPPfySygoHC7UDktOnmhxljU0NGDXrl2YP3++WAdCbbzudHR0QEvZrVaHkYK4Am7+w0toW7tejCEltUp0RmVZ6Uj76VJk/vv9cMYm4INdNXhy5SbsLqkTY0TEqf2thYv0oQ6Vl2DjKyuFvmedf/311yMrK0tEXFNTE3bs2IFbb71VDFlCbRx0LHlbW1sxcODA8/a+hnYN4JksN8x0OrhooZVrdUhZOg8ZP14ERcFQbC+uxZp17+H9v1f6dynHqi/Z5ZR5DHj1z8+JaOcWw9erXHY+D1q47RAO44W/ra1NHHx9gcvQAHv4qpHDqGL1IHn+bGT/bCnk14xEeWUbnrr3NXzwt6OwWJ1+xyvluNS5lOiCzrcfSYlZorfD1JOXl/dllbtz507R5+fMCJcx/Zw5c0aMNzkDAgZApwtsEVGPvQYFm5+Hsmg0KhtNWPPI+1j/xgFYum1+ZZOo9XP8JZwv91mRJJVgaH7ql1Xu4MGDxQJrMpmwZ88e5OTkiClXuIzph3dS1NfXC/pLSUkJHAC1KkAWiotBty4Of3xqO9Zt3I3mRiMQQxEfy9zoInl06TGlzGdHoqcUhYPjhdJhxVNQUCCqXKvVin379omPeSEOp3HUc/SzAps1a1ZQfmdQ6oAPP9iJNc/8GpBcSNRwg0QiWrqMLYWcGvRtMRoJuTlJYpLFzh8xYgTi4uJEupeVlQne/c53vhNW53P0d3d3o7KyUgQFD/v7DQCzbhqPZzJVSKbqNCYmxi9P6bjUnSUsKVnZsJRjPuUIZ9rhnr5er8eRI0eE3LvzzjsRbuOmW2Njo6i8OVDi4+P7DwA6Krge/e0j2Lp1q4helmaXA0AvCHwTBEc8H6x0WOIxAMz/c+fODVmL4VLRz85nGbx48eKg/W6F1xmcrSSs1dlxTBcsGXu3CX7Tbai938OvXF3yJIsPBo45vzcbQnYr6zdwPy+8vK+I+1CszIIGgOQLziixN1q5NayjuoBpJRiR25c3yF1u9HNglZaWigV42bJlV34P24UAUATxYU1MJc3tBrRZuhETG3PBuySvJmPnWywWlJV/hk93F+Omm28O6r0BQe2G9lKJTe7BsjeehVnuEo+YkcnlVy0AXp8HzpYumMqqMVybjjlz5gT9HEG/S7IgdSDmXzsD//Hhi/BplVSpKQkEGe/Ev6qc72Hq66JislKP6FNmPLL2KRIb2v4PANs9k27DwYYavF5RLLqeXqIm6SqiIjEy5b1EDV2Q1Rnx65/9ClPGTeiTc/UJAFFyBX5/+72ob21Eid6/GdZHmSC2mUj9nncACzm/rg042ox75nwfD/xgaZ+drs/CMjk6Dn9a8AsUaFOBDgtFlLPnZourwPn17UBFI2ZPuxGP/eIRvpPx6gOAbUhqNjYs+TWGqpIBg9n/5phbff3U+SY7UGMAPj+NW8ZPw6rfPAatum+nbX1OzCOz8/Da/f+LMTFZAD8dpdsu7uXtNyDwdfD1cJYebwYONWDu9Jvx8uN/QHJC3w98QrIyFmbl4vWfPIqbs0cBZ4xAu9n//B5vmCmJKZGvo6mLov4M5Edb8NMf/gjrVqxEbHRonqQnGQwGnzZET8412Sz4/ZuvYM32zXDFq3mh8D+mhp8XFMoHefZGPVMOB0SVHqkyLX6z/BdY+r0FoQwBfUgB6LX3S3bid689j+OdTUBKjH9XBNcMvNhJfex43sltIUHQZvYrnZNtuHHydPyOpObo4SNCnYPhAYDN0NWBZ//6Z/zfrg/RJjn8QPDGXu1ZGSEFkWpctPhbHX7Hn6aob+hAXloWHlz4IxH1UUplOEgwfAD0WnnVUazf8le8u38njDKKzCSipQSNf5zJ07re50VI/2Cks9OZZvjZQ+Yexzd1Cr7Py8jG/NvuwMLZd2FgZlY4JUD4Aei1L2pP4K1PtuKtndtQ36mHjx+0Ha/1jzd5028vGHw/A29pEYD0PApRUIvXv6j3Op03A3AroZ3UjcEEhdWNMYUjMe/W2bht5k3hdnz/A6DXOk3d+LRsP7bv+RSfVXyO5u52dDqtfhC4mo5S+HdY9ILQ63zeVdfreOJ4iWqOlNgE4ejJYydg1rQbMGHM2HBRzdUDwNnWZe7G0eoTqD1Zj+O1VTjT3Ig2Ywe6CCSbeMaDu2esyQ/p1iI+Ng5JCYnIGzAIBflDMDgnF8MHD4Mqqt/+scD+DcB5xarXKxxvd9jFjLZ3WMMzB45slUotnohyFZlecTVdLTuaW8I67T/P35uO/A2ZCAARACIWASACQMQiAEQAiFgEgH89/0cACK85GICuiB/CZjUyp9O5JeKHsNl7ssbGxrX0QX3EFyG3LZIkbZG1trbyk+cW0fFFxCchsw/oWC6Xy42S1WotoA9avV5vts/n44f13ECv/Ghw7pR6I74Kmtp0UMQfp9etMpnsPfJ5F/k59f8FGAAhm1s5PDK1cgAAAABJRU5ErkJggg== + + + + + + + + + + + http://szotar.sztaki.hu/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hu/vatera.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/vatera.xml new file mode 100644 index 0000000000..b7f5a29808 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/vatera.xml @@ -0,0 +1,15 @@ + + + + Vatera.hu + hu + ISO-8859-2 + ISO-8859-2 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpBNjZGQkZGMERGOTkxMUU1QkZFRUI4NzU3Q0YwODM1NiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpBNjZGQkZFRkRGOTkxMUU1QkZFRUI4NzU3Q0YwODM1NiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDM4MDExNzQwNzIwNjgxMTkyQjA4NjY3OTk1Qjk5MEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4WPh3KAAANK0lEQVR42uxdWXNVxxHumXu1RLYRhMXGGJAMEggkNssO2BgvbLErFb+44n/gVPyU9zynkqf8gDyk8uqqPOKqYJwY8IJjQwLIkljFKlaxWYDQcmfSPcs95xYE3zt9llvhTvmULOCcMzPd/U13fz1zxOTkJLjWjNeHeL2P1yb3e6Ml16bwOoDX3/D6s/sdhBPAIrx24bWuMU+ZtMN4/QKvURIAafpBvPoa85JpG8CrXzrYaUx+9o3m/EMSwAeNucitfUAQNNlYcPNbmGVj8nNtzcWa/rlWeGn0nUTY68y9Mvz+tBtnfHSf8StrG1+x9sljDFDEBkrPqrfJ54wv8L5i9ZPv3jA9ydPgYrMdKMeS0mheIWYmw2eTxlNoSlgATjPErVEo/PU3IK6dwbta8S9UbR2jVpoBvWIzzLz/e4C29vqwBNcHefgTKOz6I8DkvUhBah3f9ANQWz+C0raPqh7bjwtAlVCq+KBrIyCHdgNIN/chSkJKf3sYCu0LofTe75wV5Dj5NDZZMMpV/MuvcQKvowUEjo3mBPVSHPkEgARAD6nCymW1pqlf6AW9YKXrIL5JNdV2lVDW8icmAyIP78Lfp83gjVTy1H4azlFUrAma/GbrFNY6NrpEC8ADfOSad92zS1VB7I9bAE0SdfSpOaC7N4MYO4YdnbbaU2ubtveIi9+DOH8EdGc/CoIsrJjD5KPgpX2vHPqn1XrqS8i4zOKNc1JsA9XzZtnaq2myalOlH73brQWoEmMBpc5OgRz8Rx1gvwBx5wqIk1/XtKQ9UgCopwoVSr+wOlLcxATgHqa7XgU9Z7F5WdDi6V1Zun3ICYC0X+t8LID6ceJrFMIoaj/w+kGQ37stUtgqFVRW/XTq36wFKITXwgXgbZPWvrP/AXHpWIWFZQs/Vqnk959ZICY40ipM+zXCwkwR1Kq3Q/CgSjfLw9Can1tzDYUhGqTC+6Z/AHF8X67wA/fvoAV8wYcfkt3SdaCXrK10S5OzgFjfu9ECWufjnSochgh2pNM+D0M5eEPy7CEQV09E61pI4OX6rVa9ZYNMXZuPLmt7GT5/7hJQ3Zt4MESdJAM6dQDEjQsOhlR2M+/GIkgBKHA10WuIAgjrbqIDpFdvr7Su5AUgTSRrpb3Vmi39HgxDGF3fv44eyFf55HymJ637qRiLr0k94O3P96AH9FJlSiMtCDJj6HkDNWcW3q3DYYgWQQNDe2KLWQYw5CxNnEMn4MKA834Y1kdGsBLno/Vpty6mKQDvjpLEl26wMBSaS/AwdGw/wPhYBZ5mgv/Dn2P/yYILgd6Pc0wodluzsyKyTk8A5qUWhnRfGOY9JIBb50GOfJuRO6rLUXcUCIZmPm3wped2gFr2s5qCLx4EOSVVq3Ed0C3hmTkPQ/ifGNgdhJ81t5JLhYwOgcA4xMBPqNV5AaxA+Hl6roNPkYEAPAy90Gd8XxPEBE+cMOOXBEOUBpYFHh5X6f3I4b2oN3fxXZIPP0wkkEEvp5ehKavV23jpZA9Dl4ZBnjkUjKNVv8spjxj8zPbbCDzAAmjdwDhIP7PQZgY4axEnj2JgaNqF4kFWoO1gijrKDaUFQz73M3YW5Kl/8b2fgs+NPc/qt+SYsl663mb/EkjOyaHPLUcgZKowZDKfD8ZMHBIMPxR8KZcdBkY8FCwAcDDU0mYTUBylJSyl/p8/AuLiYIW2ppN822P7Gww/lE7H+1p+iv7/Fr47HGwBTnu0gSEIhyGzeNFK/gAX473puZ/U7XGMvI9/wYQfG/2qZf2gFywLdj+ZFhD5z2rZRuzIcgdDjGoC+nH002hASVqBiy/EyQMYd1wIF0Bc8Xpd8GVgU+QgAO8ytrWjL7zFyUOETxBxBGcOgrhyMnlvyK8zBD8FjoCFjXvkUxH1yKwqkElolurbYbVKhS5G2vrk03dADO9NVgDe/ZwYt/DDMSx6DuX+O14yRQpc+OELIE5Vti/ie0OCUgSeI2hKBoacIOXZf5t4g0U9ujIaFUA9piMAT1W2P2sKrthUJa3Hp78BcftSMlYQ56AH99jcf3DyjUc9piOAOFXZt5NJVVquWIxfAXHiq4TcUSeAmSmbfuAm3zz1uHhNhfOQowXEhkohees87JQKd0eJGKcofyBGVXKE4KPfCwMgzh221GOwVTn4IeqxqaVm6jE9AfioeH4HqK6NzOScdTLEif0Ad28mthgb7ZfTNt4Ihp+SqeoLpR5TFIAsw5Cm5BwLhlxUPDaCi+bBxKJfg/8cyHgU9ZhQUWsyEOSTc+QbNz3DgCFtvZ+iI8w5k+brPi8fBzly0LnJDMKH4KcnRj0y3c9kBRCnKju4VKX1hgxhPjURnpzzAqAk38y4jTNCgoBY7l/37kg8SExGAHGq0mMkaB5VeXEQBPru1rRUmCXRACnNLSCc9I9Tj8s3JhJ8peIFlalKClJ0s8VzCBSA4QiUnTwO/Ny8COLUN67yjUs9bmFRj+kLIE5VLkmIqiQYcuxbTWZfLrz9EsS9aw7/udTjzkS9n+QFEKcqe5lUpY+K0Xc3tTu1wJCOVT7QQm6Sb4Glj6RAnnrsfhXSaMnyfxVUpeBxBIYwnwB5fH9t3pC3lLs3bOEtp9LFw8/yTaBn86jHbARQpio32GwhJznnfXhfOVdjxYQ8/S2IG2dd8q0UBoPkWCiX7aXGoB6zEQC46rYWt1WH83TnDcnT34G4NlJ9bsiTO4Ou7j80qyo99TgnEeoxOwvwUTER1lyqkkxo8qbN41ftQeG7pu672h9OQs9Rj50vJ0I9ZmQBUQBG5XosqtKnkk0Bb5VUpS+8PXMIxOggn3oknsjDj5pJZWN58gIoU5WzQXdt5lGVPigz+7iuVB2FmrrPog7P/Zepxzab/WSEETlYQJRzUWv9dqYZXlT8wyVDqD9WAD5ewHfb+IEheJ/7N7see1ODn/QE4Dd3d6H7NmsR3xsyHMGnj58IDz8XjpoaI1b0652gBKnHfATQ/lwCVKVLK5FPf+92Rfr7Ud6PHKaNfw8YhbeOeiw1JUo9ZiyAGFVJGcQkqMqrJ2McgX4YfuKFt9Us2I9bwwh+Fq9JlHrMVgDxuVnxuqUqJYOqpMWUjmMY+B/bmXzu5+opkCPf8b0f4aL5BKnH7AXgo+J5Sy1VyYIhv49gnzkSxj7nYe028cLUbRs/qMDot0w9bk0l+ZahAKJdlYaq1MDb3D3jyPXzRyuj4njhLcGPZAja534WrcI45pVUcj+ZQ5BZB8wm5nZexQQR6sUZ62I+Ivkmbl+25SyswltX+UC7HpvbgnY91pcAPEewcCWojvU8qtLNjwmyvNbTTy8AnHwxftkeg8DZdjRD0W/4rsf6EkCcquzdDqyQ0gdldLzApaHIP/fwM+Dq/kWBRz3O64zgJ6XgK1sIiu+qVC3uJKnA7Uzk26t7djeN+SP3rHu3YoduMKnHnjdSoR7zE4CHIfKrO9eHU5XxOs9yyYrTfiprv346PPtJlkoOA1GPCRde5S8A71ujIIwVcKlKQh309Wmznacey4duBFe+UbpDO+rxNciyZXNmZJmq3MajKinfo/H+iTEQw+6soYlxu7WJu14S/HRvBj17YSbuZ7YCKFOV69DH7mMEZS7FXIgO+aC8vzh3hBn9JrfrsT4F4HdVNlN+/U3+W0vW7aRTbiVtO23RvMJboh5b56ZKPeZvAS5dbBgmFlVZKnME8uhuU/vDI0sc9fjiy6Dnd2bmfmZsAREMqRdfAf1sF4+qdCt54e9/AkEnrXCOHCtTj8nseqxfAcR3VXZv4XtDuBiL0wfQEq7bhTn0yDFKjxRiux4zPss627eVT17cEZWLc75FQGkHIcIrHxzbZuBn0aonQABJHQBbYQnMLUwiliZJkXqsDwEkegAstyuOelTNmVCP9SGAOFW59h0eVZmEAIruxJfFfRWOwv+xBcSsn2CojXEALNsj0xH1aMoX8/mYRA5vdBUTc5fkCEP+wFUZwY9WTwAE+cH7A2D9rsoMQ/+yBZBXvLgXNHpAeXg/uUOQUTryvVvmhB8Ay9QDRduOmlozoR7rSwDeHX2ui38AbNDMO+px3buRO/tEeEEV3pCjKql+VENmBIhZg8j7WbAcVEd/rvCTLwR5qrLnLftxH1DZWIEreTelMvQpLdBPqADKuyp77cd8ihlooqEepw38lM97VgrybPkJwAdl+NN8lcP8WSH6FmMaF/n7ZtN1Z3Tec86tLj7oqDa8hxOEMFSYjPI7aVylKfuZsA2/dJUP+X/JL9+3uyJb8oZKv/oDuoRzwBMkiV/muIIi6CWvg9r5W7cO5f89S/qgs861B7FJoKMF4MZ5EOaQDlH595yvXNC9xSbQrbNAL+rB/2+pmy+65i8AP8lZJsPq6HO6xbrohdfSLL4nZhbk+vmWcbFuemImpgBPWiNVmIJGy6vdJQEcasxDbm2ABPBxYx5yax+TF0RfMabth32N+chW+/Hq92vAO+4PGi27yac5n/L+2ChJAy8KEfc15ie19qWb43435/BfAQYAlp4hgks4HMEAAAAASUVORK5CYII= + + + + http://m.vatera.hu/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hu/wikipedia-hu.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/wikipedia-hu.xml new file mode 100644 index 0000000000..368e603f37 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hu/wikipedia-hu.xml @@ -0,0 +1,23 @@ + + + +Wikipédia (hu) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://hu.wikipedia.org/wiki/Speciális:Keresés + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/list-am.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/list-am.xml new file mode 100644 index 0000000000..e5b7cd94d5 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/list-am.xml @@ -0,0 +1,13 @@ + + + +List.am +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1MjY4MTNGMEUyMDMxMUU1QjEwMEEwMkZCOUU1N0Y5MCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1MjY4MTNFRkUyMDMxMUU1QjEwMEEwMkZCOUU1N0Y5MCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMThBNkRDRjQ4QkY4NDdGOTUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6wgdxSAAABj0lEQVR42uzbPUoDURSA0STGcQGWFq4gYJHGJQiWwewgtetxB5GUbkAQbCIIWYFFSjubGX/vg5dWm7wZSc4HF4yIxHsyMwEz/bque7kqZhYziTnPj7W9mpjHmEXMTX7c62eAk5i7mDN7aqXnmMuYdQJIr/RlzMheWm0VMx7k047lt1/a+SwBTO2is6bpFFS74HZ3YR5YfqdVAzvoNgAAAAgAAAEAIAAABACAAOxPw23/ws/To6JP+OCldgQIAAABACAAAAQAgAAAEAAAAgBAAAAIAAABACAAAPR76TbVb2twBAAQAAACAEAA9qqt3x9wfHVY9Am/3r7/+TNfi3L3KAwm9f8GSDUfZf74arh7R4BTEAAAAgBAAAAIAAABACAAAAQAgAAAEAAAAgBAhSryOYNd/PRCqdwf4BQEQAAACAAAAQAgAAAEAIAA7A9AYw2d9ZYAnuyhs1YJYG4PnTVP/5Cp4otlzMg+2n31x4w314CL/A21t/y082bzLmidNGKuY+7tp1gPecfjvPPejwADAF1kP7+yQzo3AAAAAElFTkSuQmCC +http://www.list.am/category?q= + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/list.txt new file mode 100644 index 0000000000..e73b45ffc3 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/list.txt @@ -0,0 +1,6 @@ +amazondotcom +bing +google +list-am +wikipedia-hy-AM +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/wikipedia-hy-AM.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/wikipedia-hy-AM.xml new file mode 100644 index 0000000000..098b620bd3 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/hy-AM/wikipedia-hy-AM.xml @@ -0,0 +1,23 @@ + + + +Վիքիպեդիա (hy) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://hy.wikipedia.org/wiki/Սպասարկող:Որոնել + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/is/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/is/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/is/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/is/leit-is.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/is/leit-is.xml new file mode 100644 index 0000000000..80b395d5d9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/is/leit-is.xml @@ -0,0 +1,14 @@ + + + +leit.is +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoyRDEyM0RFNzNDRjExMUU1ODU5M0Q0QjRFMkEzNzU5NSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyRDEyM0RFNjNDRjExMUU1ODU5M0Q0QjRFMkEzNzU5NSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDY4MDExNzQwNzIwNjgxMTg3MUZBMEU2Mzg4RjI3OTgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6t43m4AAAGtElEQVR42uydW2skRRSAT1X39FwzMdkEFpIHkX1yXVifxB8gou6DCKv4B/bRVxEFH8Q/4Iug+AdkFx980AffBUHwkkR3QRdZxUjMdZKemb5UeU539WSyuZhJpqtvVeEwSSaQ6vP1uVTVmdNsc/kaqOGg3EF5FeV5lBClicLAjMsMiXKAUkf5FuUeyqcoHr3JFIAllC9R6IcZo7PUxw8ot1D+4urO/wrlplG+tnFT6dyxldu5YXSifZDO75AFvG50kdl4gwA8Z/SQnRUkMcCMbIYgAAOjh8xGlyf5qBmZDMbVQsGMjBZptj7WZyyoZXXvAVuX8qWHni4Mjyve4sBqmAdwXkkQmgBwkL19ANc9aglSAHfqULuyAEHNAhEEldt4Sh+AECD7PWi8eRusZ3EF7geHXOo18P78Gwb37kJjfR2C2Xn8c1EpCOkDkDEA5/Zr4Lz4wrG3vYd/wG/ffA1X72/B8twi9BCAgOpswWoLwnJ4crbLfR+VLmELk7EZEUIHY4FbIQhc238aDk+eAAbmJir8AAGs+B7s4fcthMAqkh/rA3BKGirVJOjkx8UsaM0bRhDaFYHA8zCJQwgMDhDCagQhrAQEnpeJJEpuoqW4EQTljli5IfA8TmoEwR9CTxIEVtqAzPM6sQiCiAMzQWgyZgBkAaGPbmgF3RHFhjJC4HmfILmfPir/ZwzM+/jaKBmE3AOQj0E4KBkEXoRJJhCGJYTAizJRqWLCgCD4Xmkg8CJNliC0CQIG5rJYAi/ahIVyRwPljtyCQ+BFnLQ8AUKSokoDIIvsyItSVIJQtCqDwgIYD8x9XCmv+LROoBVzsfaOCg3g6Io53sCL9o4KtItaCgAJBMqKVjAm9Ap0nlAaAOPbFslWdqcA7qhUABJLcNEN0aHOroLAVfpqAOh2RxiYt9XJGqfiMANAz2Ajd4SW4HuwE4YwQylqDiGUEoBUECglHUQQ0BLCAN1R/iCUEsDjEKLAjJawRRDoonMEobQAToOwTSmqunBpAOh2R3Fg3iEI6qBfGgB6IMTrBAUhUNlRDvaOKgHg6GINIeCiYDXwonVCK2NLqBQAObZiJghkCbsyWwiVswAJY+cJIj7e3BPZFX9VDsA4CHJHHh1v+nEtaiuDk7XKAjgCQR5agu7ir0oDoCEUhKjkxR9qh1B5AAmEtrIEWifQeYKug34D4DFLiNwRpqj7miAYACdBiAKzp6UW1QA4wxJWNdQdGQCnQtBTd2QA/A+EtOuODIBzQUiv7sgAONdiLb26IwNgAghuCnVHBsAEEJoqJqwkdUdTgGAATDhG1Raq7igqebkEBAPgAuPww+TDUW+Li0IwAC7gihgc/0T/RWOCAXBpCALWqPjrgu7IAJgCBNq4W1MxYVJ3ZABMAUKSoq55k/c7MgCm7Y4m7HdkAEwJQpKiTtrvyABIYZ0wSb8jAyAlSzhvvyMDIAUIo72jc/Q7MgBSBNFSbRXO6ndkAGiAcFa/IwMg5RGXvJze78gA0AhhqM4TxiHkDADLoUwPQuuEfkd29reHgBCDFD1ZIBz2QYowV7eEVW/EXX+n8GwDMcqO4n5HN5x69gCk70No2+DPzUHIfJCWzI814s1gQR31z1H/cqqW4KqYkDmAxlNPwjMffgD+xr9gz8zihebjM+0MlRS6fbj/zrsQbO+A1W5P3R2RG8ocgN3twuLLL+U2gD547310jUOwOp2pPmIlCcwmCzpj+BsbkdKZZaWWHekDUMQH9JSlOlriF5+fK5z+awsL8ROgRHpxydZxF1m1OvR/fwh7VxbAIZOGYnSzkmEQpclpuaBIPZvL13bwdTbVXBqVPnAceDBTBxdV3ypIM/ooRd7ci91nOu4o1JIFhVYtekzV0qM+/IJ31Tqmmh11dJ1rS0ClNxeuRhaQlhvSAkCKAOTiIizhgqYt4jIO2pxqF6DXJ63Mix0D1I5KiBfhYuLVRaU/jXcUdS7ZF8WAkHYWxHRBoPuINqNmUenXa05cU6PSU1ZN/TOt/ewSCH2UyBIQAh1aVxiCRwB2tSJPLIFSL84RQi2CcFBNCHuZPFF73B09gRCuI4Sk02HFIOwSgI1MnJ8KvJQNdSMIzqjiuEIQHhGAzyHDvqZCQZhVEBrVgUAX+QUB+BjlJxQ/S0twEwg2QYib7MnyQqAnm/6I8kkSA26h/ErpeuYQrDgmNFR/txKuDyj/+A7lFdK99XZ3nn7ZQ/kMZUstzsgz0KOvG3BY7JWqqFNXif9UYkyQHc7kthDSk1LajEld80hByLP8o16/R/kI5S0U2oOD/wQYAJnNCEnEIM75AAAAAElFTkSuQmCC + + + + +http://leit.is/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/is/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/is/list.txt new file mode 100644 index 0000000000..283d194f60 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/is/list.txt @@ -0,0 +1,6 @@ +amazondotcom +bing +google +leit-is +wikipedia-is +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/is/wikipedia-is.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/is/wikipedia-is.xml new file mode 100644 index 0000000000..7e31731196 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/is/wikipedia-is.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (is) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://is.wikipedia.org/wiki/Kerfissíða:Leit + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/it/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/it/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/it/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/it/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/it/list.txt new file mode 100644 index 0000000000..c0ec68b395 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/it/list.txt @@ -0,0 +1,3 @@ +google +twitter +wikipedia-it diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/it/wikipedia-it.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/it/wikipedia-it.xml new file mode 100644 index 0000000000..c30a83d631 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/it/wikipedia-it.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (it) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://it.wikipedia.org/wiki/Speciale:Ricerca + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ja/amazon-jp.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/amazon-jp.xml new file mode 100644 index 0000000000..9dd84c2844 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/amazon-jp.xml @@ -0,0 +1,30 @@ + + + +Amazon.co.jp +検索エンジン - Amazon.co.jp 検索 +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + + + +https://www.amazon.co.jp/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ja/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ja/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/list.txt new file mode 100644 index 0000000000..d6504a9ca0 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/list.txt @@ -0,0 +1,6 @@ +amazon-jp +bing +google +twitter-ja +wikipedia-ja +yahoo-jp diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ja/twitter-ja.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/twitter-ja.xml new file mode 100644 index 0000000000..37c0fff880 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/twitter-ja.xml @@ -0,0 +1,15 @@ + + + + Twitter + 検索エンジン - リアルタイム Twitter 検索 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACW5JREFUeAHtXGmMFEUUft07x87sAS6ngILKYkTDoaLiFeSIKP4wGggmxoSsaOIRE3+q0R8aNeKtMUZB/WEMh5JIFGMEMYiCyC2Xigi4wCKw7DJ7zOwx7ft6aZ0duuesqt7Beklv73R1V736vjpevX7VBp0Ry7KMucub65JW8n4yaCxZVOWk6bMABAyKMaa7TcNcuPiufosMw7CQq4E/s79sGUrtnR8TWdPwW4tsBIzVFAneu2xWZYOJlq/Blw14ev7c0LnBA3tjzvKm+VYy+V76Lfq3fAR4OJpvMvh18ovSJbghgPnWtCdct1R9TT4CbOyY2tqRj7NnCWxpmp6JOkEJApoAJTB7F6IJ8MZGSYomQAnM3oVoAryxUZKiCVACs3chmgBvbJSkaAKUwOxdiCbAGxslKZoAJTB7F6IJ8MZGSYomQAnM3oVoAryxUZKiCVACs3chmgBvbJSkaAKUwOxdSMA76dxICXDcx/DqMjqv3KDqsEmxjiQ1tlt0NNZN/K/vcs4SMGFIgKaMDNOEoUGKBs/GOdFFtLWhk9b91UEbj3SefYPLlZqIQV1M2umEHdLjckf+l6QRgLHNjwZ2Ibf2eRMidPmgzFULc/J1I4L28XtjN324rY32nep2RXBw1KQ7Ly2ncUzqY1+fdr2n0IuZtSww1xru7g9eVUELfmyhLnGNJas2k4cH6eFJFRQqy3prrxtqa8rouVuqaOHWNlr1Z4edVhUyaMKQIF09LEjX8FHGLeqTnXHqFlwfKQRMvzhME4cG6CEG482Nrb0qK+vHtFEhJj1acPYmzxUPXBmlKwYFaVCFSZecV0a45sih5iR98Vvc+SnsLJwAKD39orCt4I0XBKmlI0IfbGsXprBbRpcNDFDdxMLBT83zetY5XeI8X7z9c6uU3izcDB3Crac/D0GOzLwkTI9OilLZf5ecJCHnINfgUe5pAeE16VGvg6eFF39ooQPNPfND/zCGJnHtVlxOZ+AEAely04Uh2wR8ZX0Lxd3nufRHcv592+gwDYzKYbehJUlvccuHxTSVh7jJI0L20PTUd7Gc9ct2o3ACBle4z4DjudW8MLWaXuc54eCZ1pRNuWzpgP2O2vJstxWc3s1m3DM3V/07qVs8Ab+0vpWOxMTZd2c314LV7Xkw01AzvNqk59nauJUnaREC6yV1uBORZ2oe0DfVolqyO06bj+a2ZkjNJ9P/wgk43pa5dQS5g9RNjNDTN1XSiCID82AmqhC0/I9/aafle8VbQcIJ+Ls1MwEOYFcMDtCC6dU0b3yEKoKFjeEDXeYbJ39RZ0zCr//USit+S4jKslc+wueAIy3dbHpaVMkLmWyCxQ0m0VtGhWn1nwlauS9B2XpQap415cLbT2r29uT73LoY/XpSsOWQUorwGsBXsvZgz2oypZyM/5ZzM5hVG6a3ZlbT49dW0CReecK8zCYoS6Y0J5JSwYfuwnsAMl3Frfl2BjRfwSLO8c9g8YMJDw6zfY1ddIRNwnQ50X72tfR7ivltGtl7cTH541kpBNSzmbZqfwdNvzhUsH7oFTfwqhQHBMPaH+wsO8ZENMbhUk5SFL5miRJX4MiSQgAw+WhHG41lj+SwIi0dB1/MKVhL0BDnivyzCgJyGGnzq6hj0cB6eHVDKzXFBbsP81OnqLvbOuXrLpwA+M2x2JoyMmQPFU+sidFfp+WO1UWhnOHhXE3qDFlkTRI+BMFyGM0r1NE1Pd7JGL89ahL4BilrjQTe0NAqz/x01BROwGF+15oqVew9xFGKItLn41V/4UPQ7uNd9ntTrwJL6TrMX9kinIAEdwDRDivZILjlD1e0iqFTOAGozOe/indauYEk89reE/JbP/SXQgCiC9YdEuu2lQm2W96bBLud3crANSkEIOOFHOZxok2+HY2yRAvcINvYBaJCpBGARcyz38foFEehlZpsYfBVRc1JIwCgH+WJ7Jm1MTrQ1Ns07euErNovx/fvVm+pBKBAWBNYDeNtErp2X5d6XrXvZFNalQhfiLkpDr/94l1x+uL3BCGA6qrzQzRmQO/AJ7fn/Li2cp9aC046AdW8Cn7k6gp2yiXtSDNETSB0pS+ujeH7+e5Afi+Tim0k0glAJDGCpqZwy+/rspSjHhS8AugFg/Q5AKWhYn1dYCh8f0ht6wcmSgjYe7LLfkPWV0lAANa7m9v442HqRQkBqBYWZhvq1Sxu8oVxBUc97/fJVFZGQJKb1xsclrgpx90o+YJY6P0Yepbt8W+IVEYAAMLmhlc5yOkrjv8BIX4LXhYt4FhP2eEtmeqplAAogsp+uL2dnuTF2cbDnb4RgQbwGjeGfALBMgFZaJox+9NGX9sigmvHDQ4SAm0HREzeWdOzHajQCuXyHMB/Z1MbrfXB6knXT3kPSFcAURMA4kteJUc5RhThijIFgbbvbekb4KOe0hdi2cDEihjxofdcHiHsXJQpMDff54143ype7Waqk+QqexeNuHvs472dwRcVvOVdGlErR9bBAPjlb3WOtkz6OGlKCUBrH9mvjK7j7aQzeJOGqmgJeDhf3tAidGeLA2CxZ2EE9GOnW4LtTLicsUsGTjh8GgDXh1aW8fbPAGFPQC5h68VWynkeky08sEt2tVMnDz99UYQRgAl0Pm8Vxcbm1P21flUaC6xFvPqWGdsvom7CzdAxbE7eNy5q+/tFKJhvHngBBOcfvgFRCiKcAKfSiGTGzpdJ5/NmC/eNk86tQs57OIwEIfE/1ncI/5yAEAU9MhE2BKXnv/1YF+FAtPSNF4Ts9wHY/i9SEPS7lcNH1hxM0GGBW0dF6pgtL2k9wK1gfACjtiZAGKbGDAhwAG+AsBEjF4EZCZDrOfYUQVM7jnVy9LWvi/hc1M56T47Vz5pPTjfEGESEfOCAwCytYFJgGYGcqpBp/4/Vaju/mrIPDm/BbhgVYYK2Uor/KCUgvW5ov9h6hKPBTiyt8JX0+hTyW7LnpRCV/l/PaAJ85lsToAnwGQGfi9c9QBPgMwI+F697gCbAZwR8Ll73AE2Azwj4XLzuAZoAnxHwuXjdAzQBPiPgc/G6B2gCfEbA5+KxW07ch5B9rkzJFc/Ym7wvZ3fJKX6uKMzYm6ZhLjxX6lNq9QD2hmVZxpzPmr4hsqaVWgVKW19j9dK7+8/gb5MaFkWC93KMwurSrlApac9YM+bAHpEhtqAnzF3eXJe0kvfzxDyW54YqJ02fBSAAYwdjPg87i+/qt8hu+JztP8DF2aE2lt4MAAAAAElFTkSuQmCC + + + + + UTF-8 + https://mobile.twitter.com/search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ja/wikipedia-ja.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/wikipedia-ja.xml new file mode 100644 index 0000000000..65979ed1e7 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/wikipedia-ja.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (ja) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ja.wikipedia.org/wiki/特別:検索 + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ja/yahoo-jp.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/yahoo-jp.xml new file mode 100644 index 0000000000..1cd56a5fed --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ja/yahoo-jp.xml @@ -0,0 +1,17 @@ + + + +Yahoo! JAPAN +検索エンジン - Yahoo!検索 +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAASdJREFUWAntVNEOgjAQ4wxG//9rNZpMatKkGXfHhhBftpeNrdf2ysBKKdM/x+Wf4tAeBkYC9ppu3Z/BXB521OXd9QrMrNt0ZNjwHyDhkoaLu07P1f5SZ2+7NxlhYsTzGaRfA8pOkO5hrUU8i7A854wGvObAuTKAoojYM5Glp8l5BqDlGug1URtWYbyqiA+48BJ63XpEkTiEM3FwYYQGcLhlIhNHfTaYUmoABFsmKEJCds39bAZ20wAIIhMkz8TrlFBDPNZNBgCMBslaO6/xzQayFFrF2YTimw2w+JeZ3SvHrA9nrJEcf1bg1+7xfJoBvXy1KIQ5wj8hAErCgmzWe6K1iD4ycegd0Kgzo3qWJgBgL6l2qrW632VAwWesD30FewwOAyOBkcAH7E+nC5+hXw8AAAAASUVORK5CYII= + + + + + + +http://search.yahoo.co.jp/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ka/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ka/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ka/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ka/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ka/list.txt new file mode 100644 index 0000000000..73cae8e2d9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ka/list.txt @@ -0,0 +1,6 @@ +amazondotcom +bing +duckduckgo +google +wikipedia-ka +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ka/wikipedia-ka.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ka/wikipedia-ka.xml new file mode 100644 index 0000000000..3c3062138c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ka/wikipedia-ka.xml @@ -0,0 +1,23 @@ + + + +ვიკიპედია (ka) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ka.wikipedia.org/wiki/სპეციალური:ძიება + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kk/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/kk/default.txt new file mode 100644 index 0000000000..daaaf0e061 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kk/default.txt @@ -0,0 +1 @@ +Яндекс \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kk/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/kk/list.txt new file mode 100644 index 0000000000..03bd02f058 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kk/list.txt @@ -0,0 +1,7 @@ +bing +google:hidden +google-nocodes +twitter +wikipedia-kk +yahoo +yandex diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kk/wikipedia-kk.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/kk/wikipedia-kk.xml new file mode 100644 index 0000000000..2b88c036f2 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kk/wikipedia-kk.xml @@ -0,0 +1,23 @@ + + + +Уикипедия (kk) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://kk.wikipedia.org/wiki/Арнайы:Іздеу + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kk/yandex.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/kk/yandex.xml new file mode 100644 index 0000000000..0013363ef2 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kk/yandex.xml @@ -0,0 +1,21 @@ + + + +Яндекс +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAD8GlDQ1BJQ0MgUHJvZmlsZQAAOI2NVd1v21QUP4lvXKQWP6Cxjg4Vi69VU1u5GxqtxgZJk6XpQhq5zdgqpMl1bhpT1za2021Vn/YCbwz4A4CyBx6QeEIaDMT2su0BtElTQRXVJKQ9dNpAaJP2gqpwrq9Tu13GuJGvfznndz7v0TVAx1ea45hJGWDe8l01n5GPn5iWO1YhCc9BJ/RAp6Z7TrpcLgIuxoVH1sNfIcHeNwfa6/9zdVappwMknkJsVz19HvFpgJSpO64PIN5G+fAp30Hc8TziHS4miFhheJbjLMMzHB8POFPqKGKWi6TXtSriJcT9MzH5bAzzHIK1I08t6hq6zHpRdu2aYdJYuk9Q/881bzZa8Xrx6fLmJo/iu4/VXnfH1BB/rmu5ScQvI77m+BkmfxXxvcZcJY14L0DymZp7pML5yTcW61PvIN6JuGr4halQvmjNlCa4bXJ5zj6qhpxrujeKPYMXEd+q00KR5yNAlWZzrF+Ie+uNsdC/MO4tTOZafhbroyXuR3Df08bLiHsQf+ja6gTPWVimZl7l/oUrjl8OcxDWLbNU5D6JRL2gxkDu16fGuC054OMhclsyXTOOFEL+kmMGs4i5kfNuQ62EnBuam8tzP+Q+tSqhz9SuqpZlvR1EfBiOJTSgYMMM7jpYsAEyqJCHDL4dcFFTAwNMlFDUUpQYiadhDmXteeWAw3HEmA2s15k1RmnP4RHuhBybdBOF7MfnICmSQ2SYjIBM3iRvkcMki9IRcnDTthyLz2Ld2fTzPjTQK+Mdg8y5nkZfFO+se9LQr3/09xZr+5GcaSufeAfAww60mAPx+q8u/bAr8rFCLrx7s+vqEkw8qb+p26n11Aruq6m1iJH6PbWGv1VIY25mkNE8PkaQhxfLIF7DZXx80HD/A3l2jLclYs061xNpWCfoB6WHJTjbH0mV35Q/lRXlC+W8cndbl9t2SfhU+Fb4UfhO+F74GWThknBZ+Em4InwjXIyd1ePnY/Psg3pb1TJNu15TMKWMtFt6ScpKL0ivSMXIn9QtDUlj0h7U7N48t3i8eC0GnMC91dX2sTivgloDTgUVeEGHLTizbf5Da9JLhkhh29QOs1luMcScmBXTIIt7xRFxSBxnuJWfuAd1I7jntkyd/pgKaIwVr3MgmDo2q8x6IdB5QH162mcX7ajtnHGN2bov71OU1+U0fqqoXLD0wX5ZM005UHmySz3qLtDqILDvIL+iH6jB9y2x83ok898GOPQX3lk3Itl0A+BrD6D7tUjWh3fis58BXDigN9yF8M5PJH4B8Gr79/F/XRm8m241mw/wvur4BGDj42bzn+Vmc+NL9L8GcMn8F1kAcXgSteGGAAAG7ElEQVR4Ae2de2wURRzHvzN71xaplMcp9CGP+PinRjGiKFETfMYKakCCiIKgQEFbUAmi8RXxgSJqDaCIkBhE5A8hEnzFgAaMBgOxKBWDIBbaAnI8W6X0bnecKdqSdqbhZO92djLzR9n9fWdndj7ffdzN/XYh+LdUVVVl9S4qmERARjOwYkJI7n+a/ffMCTDGGjjbKs522e6auoXFxcVNolUi/sTj8cKcqLMGhPQX67akmQBjlY0Jd0gsFqsl4sjvU1Sw0cJPM/S2zXMTqmvqBpL6o4fL+OXmrba6XU8/AX5ZKqfimp/+rmwPMgKCvTgD6u0NV4Yn/TFxY6YWfvpBq3oQ7KlKtPHMELAGZIazshdrgBJNZgRrQGY4K3uxBijRZEawBmSGs7IXa4ASTWYEa0BmOCt7sQYo0WRGsAZkhrOyF2uAEk1mhEhmuvGpl4a/QL9YC7r+e5Ctv4Ds2g3UN4A0Nf+41GEnrF9vNG3Z0GGdIMRwGFC9B5G5C0BXrAQ53vj/OAmzNCx6G5BIwJk7H86ceSB82cSirwHxg4jeWwr63Q8mcm8Zk54G/HkA0ZK7QbfvaNlRUxf0M4Bf46PD71fCZ9EovJF3wh02FKz/xUD3bgBt/TBH330f0enPhMYv7QyIcHh0y1YpQO/yS5FcVAF2QT+pHsagVgaQr7+Fs3SFlKN3w3VILF8E5ORI9bAGW8/doEfAGCJPzpLuhceP+MTSd4yDLwarjQF0zZegVb9KDUjOexXI7SzVwh7UxgBn8QdSlu7Ng8EGXSnVTAjqYcC+/RDXf1nxJo6VhY2JaWEA/eobEH4PaFtYtzx411/bNmzUuh4GqI7+a64GIlp9UPPdfC0MIJU/SwfGrjA/Wz54A/g3X7Jjl9yAiy6Uxk0KBm4Aqd178ikRCVVWlC+JmhUK3ADU7VUSZbEeSs0UIXADSMPfapadOqk1Q5TADcDx42qUTvC7p945f5TgR9gR5BMn/Bmlxq0EbgDr0kWJhxw+otRMEQI3AHlqA1C7zxTOynEEbgDr10e9c9u2KzVThMANQPeuYEUFUp5k04/SuEnB4A3gNL3LLpEypet4IlUyKdVMCephwNBbpDzJocMQM6UmFz0MKLkJLCtLytmpWCiNmxLUwgB0ORve6LukTEViFl31qVQzIaiHAZxkcka58iyITH0C+L3aBN7txqCNASjMh/volHY7KALkyFFkDR0Fsn2nVA9zUB8DOEX38XJ4AwdIeZI9tYgOvh0i8w0GJeqShmNH2v8YK0WQoWDdPmTdOuJk7r+iS5bfE+5wnpp41QCw/F5AN/5dgjS/ewrOilWIzH6z3ZZikE3H9LuM6WeAQMd/pMm6bSSIj9d9XQ3Q6hLUctjy+0HTutVwS25sCZm6oKcBgjafokh+tBiJipfBzomZyl+f1EQVYW/cPWj6aQPcCWNUVUIdD0fSTeezgP0HpKBZTjbYqXNJ/IE9unmLtK6OwVAYQDZuhrP6cyk/t3Q83Odntmr842p28aDWdc2X9L0HnAIu8tSLp6y1LjKeMe1OndQaCOGS9gZQfuRTfgbIils6DujBH1EKcdHbAPGY6rOzpXgZn8BzyyZKtTAFtTaALlkGuvMPKU/3oQf4N+A8qRamoL4GHKvnUwoVUpasax7cKdwAA4q2BjhvvA1y8JAUsVs2AR1mU0i30jOopwF8Qs6Z/56UGOPfkN3J46VaGINaGhCZNQekUZ4V504rNeqBPe0MIFu3gX74sfRgFtnS7oSxUi2sQe0MiDz9kvR5MQHYfWQyIKYlDCpaGUB4HhBdu16Kl/U8F+6D90m1MAf1McDzoJpyEICTj/HfizuZ9ZoCMS5tDKDLV4Ly67+ssIJeENPSJhY9DGhsROSF15R8k9MfBrKzlXqYBS0McBYsgXhYT1bYeYXwxoyUSUbEgjeAf9t1Xl+ghJmcUQYo0haVG4VICNwAMd9D+LyPrLC+vXnK4giZZEwsWAP4TCdVvCVFEBbpivZVBWk81iLPvQKiyP/3zu8Lb9SwNPauR9OBnQFkUyWcTz5TUnBnTgMcR6mbIgRnwG87W9IJ28L0+AuavBF3tA2f3npuLkSmRLuiaW6RnqmJ7eiZGwjsDDAXaWojswakxsv32tYA35Gm1qA1IDVevte2BviONLUGrQGp8fK9tjXAd6SpNWgNSI2X77WtAb4jTa1Ba0BqvHyvbQ3wHWlqDVLxH8untomt7RcBwZ4SkCq/GrTtpEZAsKcMbFlqm9nafhEQ7OnumrqFYKzSr0ZtO6dJgDMX7JtfsBCPxwtzos4aENL/NDe31c6EAIffmHCHxGKx2uZPQWKhuqZuIL8p8Jf2YKO9MZ8JXfm2zUxPsi0XrAVzUfMf8/fTP37wylMAAAAASUVORK5CYII= + + + + + + + + + + + +https://www.yandex.kz/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kn/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kn/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kn/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/list.txt new file mode 100644 index 0000000000..a9ef4bc0de --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/list.txt @@ -0,0 +1,7 @@ +amazon-in +bing +google +twitter +wikipedia-kn +wiktionary-kn +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kn/wikipedia-kn.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/wikipedia-kn.xml new file mode 100644 index 0000000000..fd0ed3ddc1 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/wikipedia-kn.xml @@ -0,0 +1,23 @@ + + + +ವಿಕಿಪೀಡಿಯ (kn) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://kn.wikipedia.org/wiki/ವಿಶೇಷ:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kn/wiktionary-kn.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/wiktionary-kn.xml new file mode 100644 index 0000000000..9b2353b526 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/wiktionary-kn.xml @@ -0,0 +1,18 @@ + + + +ವಿಕ್ಷನರಿ (kn) +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpGRTdGMTE3NDA3MjA2ODExOTJCMEU1MkZGMDQ2RkQ0QyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNURGRTgzRTMwMzMxMUU1OTlBMUM2MDY0MDI4RjgwMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNURGRTgzRDMwMzMxMUU1OTlBMUM2MDY0MDI4RjgwMSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDA4MDExNzQwNzIwNjgxMTkyQjBFNTJGRjA0NkZENEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RkU3RjExNzQwNzIwNjgxMTkyQjBFNTJGRjA0NkZENEMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6qmdYgAAAHWElEQVR42uxdWU8USxgtYASFEMXtYnBFEESNKy4YV3ADjNG/IDfxxVwT/wE++OCr3sTkGt94IL4gqKAsKi4YlUACRIxGXEBBXBhcQZxbp50uq3p6enoQpoeZ7yQl00sVM9+p/vZBxn4jho8SPpr4cPPhoTGmw+2VbYlX1gpS+aglIYVs1HplLnY+Cd8ZEmLi+D9/8/EPI4Qa6Xy8AgH/8jGX5OEI/orxGodkkoUjGIzx6iOCQ4glERABRACBCCACCEQAEUAgAogAAhFABBCIACKAQAQQAQQigAggjC9cdm88fPhwwHuuXbvGXrx44XN+z549bO7cX2Xnvr4+VllZOWEFtmHDBrZ8+XLLewYGBtiFCxdsr2mrjcIODh06ZDq3sbFR3NPW1jah20nOnDkTUA49PT221xtTFTQ8PGx6/vPnz+L1p0+fJrTK+PbtW8B7BgcHnbEBcXFxEa+zJ02a5IwNkPHhwwd29OhR5na7WUzMrzbH2NhY1tTUFPEEnD17ltXX17OfP39qx/i5atUqduLEiVGvGbQN6O7u9iQkJNjWc9XV1WIuJyni2gw3bdqkyKezs3N8bQB2fVJSEvmQXkyZMoXiAArECEQAEUAgAiI2FzSeWLBgAUtOTtZ8anhY379/Z0+ePAnKC0lPT//lU3s8Wkzy+vVr9u7dO9trpKamspkzZ2rvAfPfvHnD+vv7Q/L5g44DkOuYPn26bV+3pqZGzL13757P9ZMnT3qGhoY8XPDaeP/+vYeTYnv9I0eOiLkYWOv8+fNB+fI8uBLvYXh42LN7927bc3fu3BnaOCBYxMfHi9c8gPO5fuPGDS3Ex30YKSkpbPPmzbbX379/v5iLgbW2bNnCJk+ebGv+4sWLtd+nvwfsfL5RIkcFlZaWsnPnzmmv375963MdHxbnZ82aJc4VFBSwsrKygGtjzsaNG33OL1q0iGVnZ7OWlpaAa/DdrmwSpNWRUo4YAhoaGgLmlkBCcXGxOIcdiacF9sAKeXl5jKtDX++C63GsYYcAPEEyLl68GH1eUF1dnXKckZHBcnJyAs7bt2+f32vbt28POH/OnDkaiTq4/dFUYtQRcP36dTYyMqLs4G3btlnOwROyY8cOv9dzc3MD5qwwf+rUqeL45s2bpmoy4gno6OjwcT3z8/Mt56xcuZJlZmYqxhzqTMf8+fPZsmXLglI/oS6Xhg0B3AVkt27dUs6tX7/eVL/r2LVrl6hHAKdOnWKPHz8Wx7gGb8gfpk2bpqgpVO5qa2ujNxKG9yFj9uzZbO3atZbeiw4ETpj/8OFD5R4rNQbdjwBM9sbMmgqihoA7d+4o9WOABzmm90K9rFu3Thzj6cFT1NjYqNyHe2Qdb6V+qqqqojsX9PLlSx+3EUZSVjPyzk5MTBTHV65cEbv469evipezYsUK0/QFVJgONBRUV1dTMg71VhkQHnJFVu4nBK7HGl1dXaytrU25d+vWrT7z8WQgAtYB4js7O4kAIwHY5bKfDiBxJwu1ubmZPXv2TCTjjGrIzA4UFRUpx5cuXRKF9qgmAMLs6emxtAPYvWlpaeK4pqbGMvJevXo1mzFjxu/w3+VSniAI/vLly4583rAjAK0ud+/eVc7BlZSTeHv37lWEZyTgwYMH7OPHj0q+CK0jOhAbyPEBVI+dlEVUEAAYfXGkJZYuXaq9RvOXbDyfPn3qIzy4pMZzssrC7pebyGB8/XX1RSUBSAfIApHTEkuWLFGaY2Ez4H6areGPAKP+d8L9DGsCoBIePXpkmpaAPZDbA/3pbqMdQNoCke+8efOU+OH58+eOdvSFJQFIyhl3MBJr8Ijk/BBKjrdv3zZdAyqot7dXHKPIA72PJ0ku1CAL++XLFyIgkB1AyuDAgQNszZo14hyE76/uCyN8//59n9xRYWGhci6UuX9/GPea8GgGF7iHC1H5ve3t7VrdVgdqwVZrHD9+XJnPYwVPf3+/OO7r6xuTzxH2NeHRAJ6MMbGGAo2u/1EpMxZxzAyxHFwtXLhQiQeQvkYBxkmEdV+QMSqW0draGrB1hT8xltnNcFA/YU8AUgtmuHr1qt9rOmBcjUGdHPBZEUwEeHc53EQz2M1c+msIADHd3d1EwGh2MNQKckZ24M9NdTL4kuFiYY6KigotG6oX7GGEy8vLlZy/FVCiRKUMETTW0Fsfncj9Tyg3VB7x8fEeLnhtBPPVKOHqxcaKNfDT5XKN6fv7Ezc07J8AwCzXEwzgiv7pGmFlA+B9BPNd2EiHsY497jYAzU7Hjh3TfrH8NVX01KAkGMlAuyM6NXSbhM2YlZUVWhvgDwcPHoz4//ni9OnTAeXgWCrix48fEa9u7NgSsy6OkMQBUEORDjt/jiGYP2dA/4EDRcJEAIEIIAIIRAARQCACiAACEUAEEIgAIoBABBABBCKACCAQAUQAYZwJoAYf5zAIAjpIDo6hAwT8R3JwDJrs0RmBb8R5aIR01HplryGVSAi58FONjwPYKOED31p2k5DGfLi9si2Rd/7/AgwA1G383MiEhakAAAAASUVORK5CYII= + + + + + + + + + +https://kn.wiktionary.org/wiki/ವಿಶೇಷ:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/kn/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/kn/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ko/danawa-kr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/danawa-kr.xml new file mode 100644 index 0000000000..6be182a830 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/danawa-kr.xml @@ -0,0 +1,15 @@ + + + +다나와 +다나와 쇼핑 검색 +EUC-KR +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAAGVn0euAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QkM3MTNGRUVFRkU5MTFFNTlDMURCODFDN0ZGRUYzQ0UiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QkM3MTNGRUZFRkU5MTFFNTlDMURCODFDN0ZGRUYzQ0UiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpCQzcxM0ZFQ0VGRTkxMUU1OUMxREI4MUM3RkZFRjNDRSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpCQzcxM0ZFREVGRTkxMUU1OUMxREI4MUM3RkZFRjNDRSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PhSI93wAACAdSURBVHjajFE7TsNAEH3jGFtECkEQCAqcgS5CkZDdQRdFXABxE+5AQc0FEBIVoiG00EJDAVWIUyBMImOwd4fdjXEwP2VGqxnNvPnsG2pc1CAhGVOIDQe2BjPENHgkeIX1V9KNJ6lgfYjhamT8Xwv6/jOu202M4gRX7Q0M1rax/FDJ1voiFcfFXSsw/tLbGUbaCYF6twpSWphwv9nLwSvdeTQuF0B7Y1DghwgGYVag+VFvtlTOJ1kO0POeUN+t5rFb78bgLFZNmIusKuZwcn6McsktxDXO5pTx/Qj91ouxHexMpqrOLLRVBTKV2DrwTYIOCVEUgY7UN/cJYTze3XtsGhwtns6x5Oxwqos1Qz9oFu8SGUmwKbUhZILPvUTy/7U/BBCjxAGh2UA6hVCyANrNwMzAYsAofoCfqIQH9zwO4xheSf6Ac694WiOlWDTAxsLE8Mj6HcPnbacYuL2nMnxifcsg8FsRKHMUYhayk17Yv2eABwcUMK9gYhCV5EO14T84vXwACyhdFmX49eEfw58/fxleOH5g+BvxD56+4GmJlZ0ZbsKvz/8Ynti+ZXhs+5ph283NSOkCgllAyej/339I6eUfWELlhBTDQ5vXKOkI7CRgNAM5iMB6av0eTCMrBmuAJgamf8C09OsLJHrbrjQxsPWzACWBpv1hYDh8az8iBQPTETgtCW7mBidXkI3MrExY4wSclkBMIJvlH5DzH+qpf7//EYxpgAACpyVgMZPCQCPARExCJQa8NP3E8EnuGyhHoRWWRAJQQL5S+MTwUseb4Q/TXwapTxIMjJ8WMcge4wca+p/hD080wzvOtwycP1gZVPYdRAkinCUx2NAnnxj+R0PSBP98XoZP8l8Z/jshwp7pGQcD+8r/DD/UfjNIcvAx/GMh4AOwoQ+Ahsaj5tqGVTUMxTwFDPK/lFELPClgriyEsBWPizJ8//UbI5LhPmBhY2Z4YvkWwycyx4UZ/gGD5Zk5JH8xrmZkEBfjB9cI6OD2q1sMttfNkCIZ6FBGKGZgxBH+oCSJlCLLhQvBYt9/fMdQ++f/H7AcDEOyGrSAZPqDvTB7dvUdg5SKIIP0fiGwI559fc/w3xdPwYdUGzOBsuE/GP6FmnHaTjQxMMYzMrCdZwFWY08Ynti/ZXi2FWi4938GxgBGhkO3DjB8/P4RRc/kSxMZ/oGrDoiZjMLb+IEFx1+kQgGYx7ewMnyY+YHkvMC4l5FB6Ac3qpjQBl5ggfUXnPX/I5dt1ACgsoXxL6vBv39/LqCYTUULAALQXjWhTURB+HvZ3XTTpImhmjRGTTzaIlgVaTxIsfQQUcGDCCJ48uDBo1rPXgJaMEdB0YOI9eKpN/FQEAoKHouobSCKSZs0P7VNsr++3Y3Z3WRTUxsffITs7nsz85iZ7xstTft5pMEj4DQ9ommPEZbWgNrvBicZdRXWHHfhP6++GchN3gBbY3dngBUJ1kICBmr2bXoXwE98T54FX2f+zQDP0T41fQmZ0QgyySk8vTuG1bAAViLIna5i1VtEZk8J+bi4Mz7Q2kgx9wvSFRklHKWGToAIr3H+E0Fp/BwGqcfrPhENRsbhxbcI5wK9G/C4OawkTPofXlmG+mHJ0BjjKvg5NxoHRPjnPdi4TtMmE+gsBSe5pnNClnLCtd4yOL44jHpD7jJftK0hjsdSIktLnGs9S79Ko8wUIEoSbifuIRD32/ZkJoogLwlCUX9L8DtGkK9UoF60ez27kMIDNUUNMnrpS4qMoX08vozmHHhDRWQh2D2LHsUedmwq8UZXfRx5pos+jcWqa3WQN53sRKhyUt1y2xVZHJYpGzmkkQ6OcbceFZQKIiOB7VLPHgH5S7czbJhkFPXuRUGqbvOtCZfOt2qTeB3MEGK8O8gdgiRIIDMEjU0BnrK3O11aSNll/nEO4/6pFNw0o6a/nkHsfQjRZBDlQg2VCxvoJQTWOtcpXUbn7GSh536lqQ+Xhdpduqpo4vm3J7aPy1sl/MhndeInNymmKG5RXCbg7wyAXCVIf5y17eEUzjhPVZvTptKMi951Jbbe5o4G+mJMG6EpfBRHKLTuEaR79tPfQTPquXcvIApSG+nP+1Qrh26FN1E7puyYKU7OHMfyxGcQ27BKzAmk5TE9WIuKcfduQRFN8daegaw+/2jsrxjnG9dCW0Jd3jXLqboBxchz5U/FyejfIk1tao2u37rotwDMWm1oU1cYfs7NjUma5st2bUotfmTT+dFhV2QqSJmufjuZtQ5EkA3mmGPINgRx/tmf/Rhlc2WicyAbW53YonYO5v4ojsEYVjZEsSqtjV3S1hhpkpvdfNx7ricnaY1t0t64tvaEy01yT85933PPed7ned9wXjQZ1GWKWqsw0aRuilujMN0sKg7PwEBtZBS7mnTeOCGNrYWu1Q+g2XaiZ/0arLxkhyEmPhsHDIqA1UwwvnjTirv1a9Hz2hrsaanCwCthiHExw2VHJLcSBJW/ORAxBBEoknCsaQl867dgYFlkzESL7nzuuNxYMMHrv48fVn6HXVW7cY/Mhq3mdYiectjaOkDutOPlg6W42rqZ9Y4iZlRw6N2b+LHBD6skonPrOvhtARQljUiwiFgpPQ8SOoKyKw4QcZIcMDIq8G/gAb6ubcb7cz4Y/j6clEDNr8JJFzHPGJmXTw5f6wj+hWV9y1F1zIVbR+pggYuBOlPeBgpBsSGGJCzdp+G5WwJJVMaEmadywMBe/sGH2D//Q3y+8IucfWRVRtFPRcx44HZ9J15wLMjZ76y/Ddv+aMTcinIkEIeqZoIi0RkK9DogsBH7pEFsd7+B1tozk7JvvuxqwkfX9qOypIRna/63Aym+dD8RxnJbLf5c0TH2QIx7zfusDImoOiLeq5DYcgpdUlDaPROB5qAuw/bd2Ivm7qOosLt49aBgB0TBgIbiBnxVc3zcm31y5QC+V75lnFvlj36VaxXmmjzwxXvR5v2ZLQ0FFTZmCGNEVrOZZ5rkT+O6HLncfxE7u7ZDVag+5TdMWFgcmU08einJMEdPFWfesb6HtfM28mst1ZmY723Bx737EJVjsGzSMNDfj3K3e9yxy4gbCkky2DXkWdpaDq1TaIQYPy+OrZWN8ClBPr6ZWvFP9O+CSFvevZnLfn7QwjYgF14kfVbo6B+bjppQSh183D7vINZ5NhQ29ghxN3SI+fRkuuagj+fFaIzFAwGKqrC1Cmzu3AKNTTApYbLH7ULSR1G22A4LU9feGwFoe7WnmB1tdA6UjJD2KQkyNHmp5CzVicVNKw6jCYfx0uUliGkhuOxOwA7u0CK5GtsW7sBbs95Od64rnB9xqZpnjsVMXSrLuSEBQtlsFhbgrtVdn/DYwIuZGVmda0sIXA7S7CP9tJJRigMXD+VXEj2nEJbDIO0EwYdBOE87YDlphhyXQS4QPhY5TvAcI2fCBcKlXipHJZwgqPrFjS7fHV7XiMQjOH+vPe99qr9ZCiKLabtyHKT0V8fjOECeRJRUpkKa+R/OSeexsX7TlDLrkC8E51UnXAYrT2txVFQz6KhlSUpejaDKY/u13DBpchjR3zsI/M7eG42ZrNHEtngiAdQAFUudiAWSuqCcV9lVqj6ZWCP6sH06NBFqKpYp+g3OhqqpbjmeuggqSGzDFeuBs9FA/Aw0ZzYUpWA0qco2dj7FPryZt/N0bJm/HzwSgHorgY2yiMLf/Pvv8ffGHtADajkUWyuCICgISACVaEQU5WhRoySiBo0mKhq5PWJMPIgJSgyJRs54JN6KEQMYG1QkWhBo2iJtt7tddrfd7Xbvcebfo3tf0rqdzaTb3dn535t57807vgnUy6aw/i18Jaisa0Q2PqKMRfE3nmddKxKNXCbYx/65byQmhZSQiDBSife3XQJGdnt4pDOQXZk5Hk/orrJCZRejcDbxD7JsUkp2qH49ayYc5V4s/aEJVUeL4FJ6R1BulK36iVorak/ngEqPoOMmc1jJatgZ4GUZpUuArsYKHpOLnsRyQdlq17fnIs+lQvuoFrg1jdBe3Z84Jh6qg6enzorPHp+GJ3aNg7NmGQ6tvg7mEid0ky3QcPRDDKK66ixY0lwNBVOAXIcIk1qHhjeqITrJ8DHAc6Xd5l7kveXF5HMFWHGgB6ZCihyrAtYpDXCPuRcFVuLLUrsVMhKD70yuUY28v0W4SL8fj0VQ4ijF/rntUbCzIWGAR3YKFiboDWbQOyl6N3jR6zqGKtoJp+kE9JZTIMb3uN+L79ZMBdU8iN3P1KLkogp2tQerviqF5Ya7YZE8MqpAyYLyhqlHUTGqmMXmdGgZUAtK6Hv68Fr123As88NKiAcKXAUdqWVEa3GDswNncAqav/Zh26Q2WdAmtKpwuHEGdHPmY93+KhhyfOADFYuqjgpmfPx5DwbsiTN4aWN0I1ddUov4p80I78rwaaT7lRj44DH27jio5yiIMCjHOd+z2LncgT03TsdKC0/dDTAxsTGe2drTMiyZ9wV+/MiKgrMCiJDQF8qcAZGI6DRdxNa6LXhx4sbolfmJ18hZ/4ZF3Ks8EIRwSg7pDmHRiUXMD2ZjfiEo+EsNZ64H9mVOTNCVwWJzJCQ+wICYyarnqTRobdUH8Z+xmkorwjnAJN6OKOJ5Wzh6IeitFMr9IsaMy4O3mPiAve0SrCQ58RnpAEeG6y19WJC7JCHxcoC+wiUTSB9OPM51nxuby19HV4+ZmU8x5cJGWjrABxRoJLSc6Yan0Q2BKIbi+ICwl6C6pgQ2hzMK35SxCAnspR0w4RppGs6t0cYdN2AewPYvt0GtUvgTr5TpiRozS2di0ZzFcro+WeOGYPPZF7Hl9HZUFhUz6+X+bzuQr2Sr3tINe4OdmUp13El2frkDj1atR6VYHHEiExlh3NlpAj4BtOs7MWZyRWqi8SHB+IllsDodcfeC70BcHcgVVdAb+0HX0ITE87auaz1KDYVwGdxwGpjsG6ncvRe98OgpRouFGL28CNWKKmze/0JqxqKRYiy9AiqlIjMlbu3uQe/tfakJbwGCdVyjw4q1FY/grpK7UagoRLfejFyVWs7CFl3Ix5byl8MStYna4RuPoKPdmGE80J9+uob7L+4uLzYtfins67rDE0HVXticLlSrSnHdvnr8virFTLbbJ4o0TppHiOlKetNMC9GQ38QQ2Ob5LWhr9UHXHA4X/uhvzmzuGKWw6BpZplnDJFZP0qjkAjmfnypHYEwsA/1pasym5dIEH4Dw1Hsmmb5Ev3VYmVVnLrLAfARRJVySuX3g0RDRpaHiQNLXgXiXQlbtugeXzyzz+UhKJW6rXJg+9XEgtGL4hyGFgXR0wQsf9Xwu1+CDzOd7MfvdGehY0Q61QSNP/49Bj/N3fpumfoVUTGk4d2L4JzTm26TN5a8rswdVTy4BOSDXP1F4uYj8uwqhMUiyGXSKDjw36cn0ZdMbRyJI1A5k1qaNvwLdSj0TdMaL04OKMj8OvA8yPoJffDVdcOHTxQextOKeS2fhaIQVClbD0zwHfpt3Bs+Xb2dxrAZ5iny5a4iEStVY3F68FOfmaEEfoJkRTyMq9RGdlB4qiElqT1tfUl9+WHJd7xOUjfPdvovOgEgxlJhnozzInub24Zb4S4hUB8aUQOggGJxfJ5ULyHzEqCQrM5Fg3M5y+XZZ4SsFPgj5QwTKp0SQOwh2HH8T5AXmxTxLZIB65Y5SkI0EHdoLqHpnjDzm5r2zQapJ0pOK+lEeoYYocG1A8MbxMcZWFGPTdxviT9wIzLl6LnAHcO30eh+MZqEaZTcVMeKAmpIajF5QJHdpgQaz6+eiZEE+JIWEWVNm8bvYmDHpeqAh/iPOtpxGcX1OkNigfoZ0gQQVggzuhIfCZnZga/Or8Wc/BRwz/MQMO3BS/6f8kb3TAb3WBHoeaLO1QcfiXJ3WjIELdvysPwJDjwU2uw1NhiaAjfnVxP6eif+IK9+tBQxClObSkE6Kvw5B+EdUMVUsqOnabQTdM/zKrFiuQMUTo2Drc4R7bSEnM1diIQBuCoA8Ap2Llp3575VrLwNZT9B0pGlYCDf+bQZZw3TmaU68fZAgj78H7rn4RYhc9kU+DfgNlMY+RGQEZJUL5j1OKPoJRFF5yQn3eJizp/RCWk0gdeeCijTpWcR3wHeHI8INCjv9aAi6gGu9KKScdErrvOJXPNyBa8IpnA/En1YJ3g0J5YDGjBh9fpt7iA+JFNXNh9FjzpyXhuC1aJw5shF1QPygP0rTJJD+D9wQPxwyFK1CI+MBblMjw4BsWfkgYjGcICpQ/y2jZPRmqQgxunRiIiJptjLhDy+Z83AL1wFR9vloti95FHkHXR7byX8FaO9agKOqzvB39959P7NJliQmJEgEeQYE5VFMARUVRJAKVZkqoBal6rRIVYZ2SlvtYEUcrZ1xUMqU8Y06Q3kpjqUtTxFEQBSEADGvzXvf73tvz7m7WTbJZrOb7C4wwxnOhL1799xz///8z/P//6HOXUlyk/4OruzIlSupfUD6Qiq/ZQzYirDVcBX4WWwU1iGiSFRQnWbvVXhcsvY/igDdVThcsmaQXYVBL/KSui5DjBRRk9BD2Md2FQEJtS0GbRYfbtmfi4pvDVLNr8ZBbujtcikKTmSuIiCzTh2BQagkAMtJFtt/Mw2idjECgxZAbWPQMNkBBFkpGrA/iJBd2Su0M7AkViFFS6VHVxcjBscgq1ZSFK3aetQZmnHsoUkQVY+h6AyH2ik26AhF9BUJaU1FzwbEaWK3LCRDzWR7eGtSMuAZaE6rUdioRqspAPsIN0SFAKZOjoGn9RDkPAIKsfcaO7GPIhB16wW4892oGjodZT4TGnROcAIT/k4RQKm9BEfMVRhfsweWgybICF9KBRF9ijS7lE3Fc6ge4oThJAdR/yC5QoNnaKFLXqpNRFPwlVJgk0ZS7gJsO96dUY3lq86gfaxDQkD+IT00bgWCqhAEtofAC3Kf0q6AdVITXrpnFAF+MWqMtVAHw74b6kfTBhSoMl3AuLaR2DIihDknD6DoSxN4JrUIh8seATTUqspthdgEmAcY8OqADZjNTIAHi+FEE1jDcOTWvovAjiNovX8+FOoJyPd4UTnzC4xt0uK1ndOwaGd5ZDQlTpbU4pVF1Xjv53XwlPkJ76KFFwnEbVx4Q81MSEwnQFsjh8t4rxT4fIEAXxcBPhXMPjaEIo8Ked5y5Dy3EbZVPpQfzIVDFkxZSbosWZAEdA8Beh0wevBwfDnpCFSsKvo9396MRnMleVk/9IufAAaYYVvzFFlN42DCOXgdJ/Cc9jWs3/p7YBIB+zYWXy2rxCj/9RDZWvxgdOG6Nj2hFD3CHklCOwR4VHjIeSUZV0mu2VCd44HOJ5dWPAW8X8ZDJYjI9ZRjg/4AHjl3FHmtOVDVCgj2YSlL0bqXAwLECNDP+6wQ6oGBJcX4fsopaNj4FcgCp2zwDhtBADMKXnkQoswMxrcTmjGPwXi0cxE4XuTxi6ML8J7rEzIwec7bCmz+y3jc7i2XQCAybajXuxAGMUPUSyaacN0R2RAkgqfUTrdqLViv34ul+4+BtWhQdlwNJ6GGvu6RXFIE0JfTcSrUBRvhryG8uTAHVVOroef0CX936zs34wvDXuTX5qFiB4slh65FZcsFLFs1Cp/86bOEEalBMYi7vrodu1p3h8ud+RiotrO4e0cBpn6XiwktJlwfNBGuFIYo5ecnFDZsHWTF2mVn4X+AR0GzGco6EV4icKWQ335oXFlHgBQqzqlhDTbBUyPCaDGgeno1jHJT0mPM3XcntlR9iqEjCqWijGwOhzP2Bhhb9LDd4UjaUvULflQemIxD578GQyhjWH4xmhknWpWUoiIp4QKHfK8cSrccgjeEAE2sT6MlnBUEdAC9RWiBo5qH3qzD2elnYVH1PVPWy3sw58hcHG4/hCJtIT6/aRcKFSX9Gu+G/RU4de4smGuAwdoCOGg1gwy4HrKCABqzQIFuJypi648BaAwafPPTo7hOP+SyV3VdIReG/ncw6uuIhlUMlKkK4Ax6M4KHtCJAyv8hmooXbjTVuKFSK7F36h6MM914xVrajpAdpbtLYbPaoS5hUCi3EAT50oaMfiOgA+h+mRfWGqcUwrrz5u2Ynn9bnye1bvNL+O2WZyEUi+EYsXjhhrIIa6ARqTT2xhs2inVKHabnTMPqm59HxcTRaUVGe6AdZV+UwtHihK6MgUVGkeFNKjEm7QigRy4YVXKcsTaBC7LYPOVDzC2c168X9NE6VX8gE1pEyN5VALfL0ylTLrE1w0j30pAf1iCHX+2C9aAH2AK8PPdFLL/vmbQio8ZzAcN3j4TL6UZJqRlCgNYREbKDAJYovY28DVw7sRTnusHJ0mNMP7lnKV6vWY/isjwEg8HONoKCGGZtVimBLrrgKBUoiJGlZJCroKojC7940RKlx7Zo1Gq0F7bB/nwQJ359HCNHjUo7myrYZUJT0I4ivVmKxE8VASmbELRCL98g4oXyP6cN+LQZlTnh4r4xvhRK3jSbt+q0FS2TWyD+jDC9eZE+l/SZItqnuvH2sA+lyldNTXYoFCxhRzIwHAMv4dfKcxqUrsjBqF2jsXnfB2lHwJ4xByHaiHEoD/SJHaVuw0V4r4zPgF4Qj4rZcJeiSeM0GjI7Le9W1E9rh3gvrW3vRWPQBjkTziGgf0JN5O8EYNHZhyDw6S0iJFXm5lPUVjtVQu+xJF6cHjN3kUlzNaTYfJLY53UEgia5OJpmNgNtgBMOyW1Mx+EJkAoURniCfnz54770IoCJiQMVkoRjDBKuoA2Z5Kaq5JRSiVwHH5Tk1UWnUFhmNIaar8C3yrKPiEmaP3VvLa0t8LT4kKfRkpUvRClDOhaN/CvVDczIvIWEc+8FAUwKXCgbQX9RSmYubnwnUySUZjeUvVkK2RiikvoVEnuQcvqImtrodCHfosfYgvEZmXOH20JIEZayblmqsdhg4mCH78ACk36w87GQjxTjFMPXVQpVwl9v+OBNyH4ng2EeB4vbCJ4XouPwHLHW6oB/37gvM74dCYhi57lHy8Si55KuYryqrmICqmdib0ivEKbFtMPjC9GxpdUfJEAdqsSibQuhrNUAWgEBgYe1vQk+3g+RHsMyDigaa0BxUR789X4InCD5o1QyBdpZJ1zHedQ9WIMibXEWGGgiAIrdPnPdACwkMX4GeNGKkSux7sTrcDNuaEVt1LKkBpUyqERgtB/Bcf6odmTmNUT3V0nfS0f51FGDOAiFTA4Fx+K8gwjbGmDpxCV44/EN2YF7H2DC9ZRv2yOjYzIjCAoNRQj9MoQBOy2oryN6pCmstUSf5YwzF8qyQohmKjPkfp1OhxWFK7By8krIZYrsaA2R9Cmml2Ctjr0EMSb5nhPFFFNMhEwwoA43B4uWma244poQy6IT+dC6f+birvLe2BCtD8dwuNoIHGTyCFcQY5QTIUbJFHtjQXF4SoLaxtIJtYSyv2092acJ1zbXYtOOTVixcAUOnzqM7898L51MseSuJdh7bC9aHW1YMH0BNu3cKJWYuG/GQmzbuxV2mx0O0Y0n5iyDta0Bn3z2MQqKCiRXAJ2n1+eDjAUWzngQ+4/vw8mzJ2HKMZDx2rFo5mJ8duBT5BnyMHbYDfjnto2E2uSYMPImDB88Ams2rsHD9zyMotyilN+nyv5DtMpWR152srYLvZfJ32WK7w3tgRLoKdFOnRN+otE5l7mg0WlSmvBHde9j/pb7YV9sx5NnlmKT932AcJ2WSc2Y/8M8HHMcQ+stdqg/D1eZaKtsx9ADg1BjbgRznrD92QK2N2zF7MNzUFRuAu8XJERZGRtUdUp47vBh4dH5eNf9EQoG6GCtcqFlQjPGn6rABMNEvGBZg/Kvh0gy5lnzcqy6djUM6w3Yfu+/MLNwdsr8X/t3DTyDvSjgjAileKKBlCzcSXrH4oG/KGCYmCRiGoOmcxuAieQdnjemXP5e2kRpjhgtLjJgY+Qz9SW6yPj2yGTayF97JJzQIYTvaw3/TnIEks98Cy91gXQauAVbZFxP+P4guU5/Q4lcIGOJLppgT9gCvZeO54nMqZlWpkl9U8r0ohEesxfXqM0ICqFOaeSdO7r8P/ag3a5kwyd03oUJi5j1uS49QvcHwT3F4eO5H2LejPlJTfrG/IlYPeuPUHEqLC1/HJOKK+Ej7EOr1eKZYSvR7GuSgPi3m14Np5Rzcrxc8SraWHoctF26VpE7Fusq16HAlC9Zv9QN7GI8kHnDFfAfG/IkfnLNdJi1OjRYWolmpMXaildgkVuQbyzAusnrIJfLMZFQBJ3H6rtXY2xu8hayrcGGnGdzoFzKoNBlhs8b6EUCi/H5O2VBeZ/Syvx8fK4jRNzBQs+mv8agRr2sBeIbwNOTnsbaX63NaCTBpWw7duzArH/MAh4ASorz4GrwEtWX6bNaLmXL5243JpABvahEEQ7BkxEULAfZQAbWQ3Yp68ygMeD3U1bhzmGzUFZUBoVREd6wuJyREwFk0BOEtcGK/1Ttxto9f8V3DaeB0YTl3KaAqlkDnzsAhk12uzTOwo9qUAQBedsMIs/wySn2yRz5ECmEy2oI6ehEwhv9cLj9EHx9dBdeAiRQg06rl0MtVwJuFrybl6gdaS5+KZXdSSS4E59C0QM2qDXIihC8ghStQGdtgCZ5BF4OjUZaBKi+cNEv1U29T17VT6iGRixhJu6DeoqdlzgWK15c0V2ByidHTHxExIjIHn5kPTyj23XxImy7zZVP7V3jsqSoIdaxbIUEQOgjkHtjt12HzdZeQ7LXhQRz7a+c6fD2cozAEn00FB8IUdQzCXdEMr5yuy7Bnsint3t6I8EsNKarO5rp2ECIh4COOme9HEmc8fl3XYJCD+TDpLBsRVwSmdTVIqAy4C3SH+n1F2J2J9efm7tofmnxoDOZIYe3qAx4lMyOlkyZ3+M7iukAJ5NmkCT/ZDHbiyM51H1EFv6jHAc1FQYLIhfHkL6c9NvJIy2ZRX8G3paJw2L6M2bXNdO/Rj1QtHYtPeD4m7AdoML/ASsCGebepEA3AAAAAElFTkSuQmCC + + + + +http://m.danawa.com + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ko/daum-kr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/daum-kr.xml new file mode 100644 index 0000000000..f257c6b0fc --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/daum-kr.xml @@ -0,0 +1,20 @@ + + + +다음지도 +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoyQzA1RkZCOUUyMDYxMUU1QjEwMEEwMkZCOUU1N0Y5MCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyQzA1RkZCOEUyMDYxMUU1QjEwMEEwMkZCOUU1N0Y5MCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDg4MDExNzQwNzIwNjgxMThBNkRDRjQ4QkY4NDdGOTUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6jtHwKAAACFElEQVR42uydsUrDUBhGbxrTdndw0EVQcalV6CK4OgiOBd+gs88gPoVvUHB0EhdBcKkgFB20aysW3FzaksT/4o0oRqx4mxvac+ADe2tD+50kf6Gk9QaDgTIUJQ1JXbJtboM9hpJryankxNxWnhGwKDmTbNJTJtxK9iVdLUDv6S1JhV4ypS2pFcxph/KzR3fe0AIO6MIZB/oUNGDguhvMWkBMD+4oUAECEAAIQAAgAAGAAAQAAhAACEAAIAABgAAEwGSZqx77uX6Co5GvgiBUW9V1VS53/r29o76d1+td1GfrCLBRPqcgQEDuZsBPd4SxUrHE+7Tmj6krjNLXf3t82uP0WjCLAnzdvPd1LRhzfgUW57pfCt+HXrSi4kJn+gXoPU7vqavz+Xp3tFuxU/7S8pqV7UT3C3/6/6feMzOAIQwIQAAgAAGAAAQAAhAACEAAAgABCAAEIAAQgABAAAIAAQgABCAAEIAAQAACAAEIAAQgABCAALDNt2vEkisZH1/CXD3R8zs729npP1jZjtfbmIyAhLTLVF2gv6qgXApn5wj4OBJSLlN1QTTlJ0lmAAIQAA7hFzQ4AhAACEAAIAABgAAEAAIQAAhAACAAAYAABAACpl/AkBqc8aoF3NCDM9paQJMenNHUH8oX5Y+WpEIf2e79kloyA/bMAmRXvu58mLwL6mobkkPJJf1MjCvTcc10rt4EGABiRGNcL0JtwgAAAABJRU5ErkJggg== + + + + + + + + + + +http://m.map.daum.net + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ko/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ko/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/list.txt new file mode 100644 index 0000000000..a77260fab0 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/list.txt @@ -0,0 +1,5 @@ +google +danawa-kr +twitter +daum-kr +naver-kr diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ko/naver-kr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/naver-kr.xml new file mode 100644 index 0000000000..db1bd2c0ca --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ko/naver-kr.xml @@ -0,0 +1,21 @@ + + + +네이버 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1MjY4MTNGNEUyMDMxMUU1QjEwMEEwMkZCOUU1N0Y5MCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1MjY4MTNGM0UyMDMxMUU1QjEwMEEwMkZCOUU1N0Y5MCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4MDExNzQwNzIwNjgxMThBNkRDRjQ4QkY4NDdGOTUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6ugdXHAAAFXElEQVR42uydbWhbVRjH/zdJ0ySte4u0o23a1fSFlA0G1uLY2BcVX3CIOjdwuCHKUD/o1FIdWlndxGmZE0Gc+2AFnbAXfGHOgcJQcZujiKK027q2Wbe+zNZWW9smuc2Lz7m9xS+Czb25Obvp829O2ny4J+c8v3P+5+Tk3FMFZ9ZCl5vSdkobKa3RX7MyJ5XSWUrHKB3UX0PRAZRS+pLSao5TVvQLpXspDTj0ln6Sg59VrdZj7nbotrOKY5J1iZhvFwA2cyykabMA0MBxkKYGB892pEobA1gSxQAYAANgMQAGwGIADIDFABgAiwEwABYDYAAsBsAAWFmQy9rsU/RImctCccgtg6KIJ7sBUGYDF/udKq+aCADl4/QA7iLKI57+tSL4sWH6lZj920jwlXwgv0jPwy4ARGHjE3ixcgduKQwhmlQNhF6BS3GidfATtI+cBHxV6UFIRslg3dhf+xrKCKCamkm7DB66/txkB97sO0ANoTADvfG/6nlmbSrzAKiy6hgu3noKNZ6AqaxG4+MoOrseyWRMb4nJ+V0Yn6TmVYDUmtOm3r8jEsbKH2+bfW8l8+3VYZ0FOdEXu2Y6J79rMT4I7SOgf1CrTqMV6601HBsy9f5XhI1qgbdmHLDFLGjbjbfjzsCjwNQlDSxPQyXoSHUL8n1BIDpoiRczgP/RIqcPH9eRFdGYAG1QVxhAtrVx6To8UPGkbkUOBiBDh4IvobCwjqyoPyfGA9sBEHPzo3X7yYqmgUTE9lZky3581+J6bK18Bpi2vxXZtvRtwRfgJxCI9Nnaihz2LbiCT0NkRck4WdGUba3I1v13/Q0r8VSwiWZFPfqqJQPIut5d8TRKl62j8SBsSyvKicn0F6G3Zgfj+ITtrCgnANxcUI2mqmYakMO2GwpyZlHljcDjCPrvoPGg15JlYwYwDx0XVuT0AjNjtrGinAIQ8gbwak0LWdFVGPoKkgGYV3PJFqwq3kBW1G2LWVFObks5HmoF8pYA6igc1/lSRU4CqHAX4+XaPUBsAAmLdjMsCACXolcxpA2o6Wt36VY0LN+EzunLDMCoeqKDuP/CTsPXf1b7uuldGQsaQJ13Bc5dO4qd/W2Gri9x+1HjZQCG5RTF85Rhb1czwhnY4sIA0lSSfhx5fm2NZ8P5RgYgRWI7oq8KHcMnsGvgIwYgTd5ytHTtQof4BowBZL0b0AerpeRJMbKi5xiANCsquAnh0VNovHKQAciBQD2Bpqb7uvegfeoiA5BiRa5F2krzfZ3PMwA5DBLUCyox9OdpPHH5bQYgB0KSxoMg3u9pxbd//8oApFiRs0C7BenBzmeRmO9dMwwg01ZUjrGJn7Gtdy8DkGZF9Cn5UPgdfDXezgDkWJFXuxlvE1lRxMDdmAwgE1bkKcPUZCce7tnNAOTNimrwed8BHBn7ngFIsSKaEcG1BI+cb8S4tluaAWS/F3hKoEZ68VDXKwxA2njgq8Y3/R+ibeTrhQwgpQWjIn+5qVwC+cX/tu551yhPO9zjsQuNGJn5y3RNykUZtDMqrNlpZ9EuVic9fGgbPmH4sA634sKQOjpbbUca/+JAwKKgpaa7cQ9BaCrZgjg1hpSBAM4d1gFXoWVt1ZrDOjJyXI2eh9aLlPRboNghrQ4Diajx1mvb42p0C4Lbn4HDkmAsgMI28pZRDU2uE4kyWLi7zuKN9Ir8e7d4byiLATAAFgNgACwGwABYDIABsBgAA2AxAAbAYgAMgMUArgMAKodBmiYFgJ84DtL0mwBwmOMgTYcFgPcECY5F9lu/iP3cGHA3Q8h68EXM1blZ0ACleko7KH3H8bFMP+gxrtdjjn8EGABZZoZg4pPHIQAAAABJRU5ErkJggg== + + + + + + + + + + + + +http://m.naver.com + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lo/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/lo/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lo/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lo/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/lo/list.txt new file mode 100644 index 0000000000..211f4dc3dc --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lo/list.txt @@ -0,0 +1,5 @@ +bing +google +twitter +wikipedia-lo +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lo/wikipedia-lo.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/lo/wikipedia-lo.xml new file mode 100644 index 0000000000..ff637f53e4 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lo/wikipedia-lo.xml @@ -0,0 +1,23 @@ + + + +ວິກິພີເດຍ (lo) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://lo.wikipedia.org/wiki/ພິເສດ:ຊອກຫາ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lt/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/lt/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lt/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lt/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/lt/list.txt new file mode 100644 index 0000000000..2ff63a596c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lt/list.txt @@ -0,0 +1,3 @@ +google +twitter +wikipedia-lt diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lt/wikipedia-lt.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/lt/wikipedia-lt.xml new file mode 100644 index 0000000000..930947eaae --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lt/wikipedia-lt.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (lt) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://lt.wikipedia.org/wiki/Specialus:Paieška + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lv/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lv/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/list.txt new file mode 100644 index 0000000000..c26a6314a1 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/list.txt @@ -0,0 +1,5 @@ +google +salidzinilv +sslv +twitter +wikipedia-lv diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lv/salidzinilv.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/salidzinilv.xml new file mode 100644 index 0000000000..7558f54416 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/salidzinilv.xml @@ -0,0 +1,18 @@ + + + +Salidzini.lv +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2ODNBMDBFNkUyMjQxMUU1QjE0QUUxNkJFNEIwNTQwQiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2ODNBMDBFNUUyMjQxMUU1QjE0QUUxNkJFNEIwNTQwQiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDg4MDExNzQwNzIwNjgxMThBNkRDRjQ4QkY4NDdGOTUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz77QEj5AAAfkUlEQVR42uxdCXxU5bX/32XWhGyQgAlbJOwgiAiiAlK3goBQxQXcfm6/19q+UpciWtDa1q3aZ5+71lr3HZ+oBRWUNQFEZBEUXIBAWBKWrLPfe98533fvZDIEtToJk5YbPiZz587NnXPO9z//s3x3lHA4DHtz07iWxvk0RtjPj26p2yI0ymi8TuMJ+zkUWwFFNN6hMfionFplW0tjPI0K1bb0eW1J+HV1dZgzZw4ikUhbVcBgW+Zu1YadgW3p6nfv3o3S0lJUVVW15VnAMr+WFXBhW7rqgwcP4s4778SDDz6ISy+9FDt37mzLSriQfUC4rTjc/fv3Y/HixbjmmmtQX18v9v30pz8VyujatWubdMysACvdrzIWi6G2thbPPfcc/v73v+OLL75o8jorYebMmTjppJPanAbSVgGWJS9rw4YNWLduHebPn48FCxaiuvqg2D9imBtV+0x89U0MqqrirLPOwhNPPIGOHTseVcCPFXxNTQ0+/fRTrFq1CvPmzcOaNZ8iHA6J17MygbPHeHDTzExs3W7irrvqsXZ9VLx29tln47HHHkNhYeFRBfyQbd++ffjggw9sa18gnjtbu3Ya+vbWMHmCG7+4yo+sIp0vH6+9HMBtt9Xi8y2GOG7UqFF46qmn2oxPOOIKMAxDWPsnn3yCZ599FqtXr27yelGhjm5dvRg3LhNTz9NR3M+kvSaMWkB1KVB8Kl55oQE3z6zFth2meM/o0aPx/PPPo6Cg4KgCvovVMMbfe++9WLjwQwYgsT8jQ0Wvnm4MGeLDOefkYtSpGchrH4OimLCiQZhRIm6mIo7VfAosXcWclxtww4w6bN8hZ8Jpp50mlJCfn39UAYeLZh9++GExKisrxb7cHA3HDczE2WNzcO7EHHTt5kZmJl8eCdUiHxBTYMZICVYQlhGGQi/xUDMpnFEVvPV6ADfeXEuOuRGOXnjhhbSeCUdEAaZp4oEHHsDdd98tHK6L4HzYsHa4/NKu5Eg7oOMxOjxejY5koTeQwEmgsZCUNlQxUwwrACUaEZOG54JKswY6KWFOELfeWouNX8TE3zr55JOFEtLVMR8RBaxduxbnnXeeiGJ9HgWXXJSHGbf0Q/ceHaBpzHZIeFaU/kXisGSxwC0nc6tIP2AGoZjEgAx5jOYlOHKrmPtmELf8rhabPpdKGDp0qIghjj322LRTgNrafzAQCOD++++PpxCmnp+LW2b1QY9e7Un4UVu4NBRysLpu/67SUx8sMdxxpWiqn/5zw1IVcZgRssiiDEyc5MMff5+FXiW6OI4dO6ctKioqjirgyy+/xPLly8XvHTupuPzazmT5RO4RjguWsEQOVbOVQOxGod9Vj9hvKR5bUQz9Xtrvku9kJdCkUchPjD/Xi7v+mIUe3bW4Eq644oom1PY/TgHsbB955BHs2rVLPJ82tQADB2VLAYv6hNk4A+CSg5VAVg4RGbMS3OKy5UxQ5bEq4z/vk0oxgxZctGvCeV7cd08WSorlTFiyZAmuvPLKQ6jukdz01oxw2foWLlwofs/NVzDtolzksPyNkC18mgWqj2TqaXp5KmG5RgowjbjlszLk71H63y0ctKXRcYYpzm82mHBlKJh0gU/oZyb5hC++NPDee++JOgLHHOnAjlptBnAamSNczuWzQCaPy0XPXi7BdCx2uCw4dqhWRNLOuLPVxUxQNDqWR5wykMAVVoKb/INOH8QjYEr4AxqCvNbT/zELE8/34f6/ZOOUk1zinR999BHOP/98kdRzck7/9grgjCbndfjR79dx3gQ3Mpi/k1VbRtSWq24rIWjPiMSJyvDDPoGt3RVnQpbC0MNQxUpwi0dWgqVrYhghQVIxepQbx3Rq/LgrV67E5Zdfjk2bNv37K0AhbP7qq6+wfv168bw3sZN+g9wE7yR8wRRNYfmWZQoLt9iTWqEEn2DFlcA+QdV9dE6aFYo7/jEs4S/onARf7JRlcKAQoqmoqowRK6rF/A8iPEnQIU/hlwQd/tWvfoXy8vJ/bwVwzYd5OAddHpLNhHEeFBa5BfZbZojg26ARFdxfCNuUSuDXGpUA2zHrwukqOvsKPQ5H0ie4hGIkHNFMoPcq5DsO7jfx5jsmwhELt8/OxMOP5mLwIAlHzMiuvvrqI1ZZa5VAjFnHOeecg+rqapT00PDCMwUYdgoJMGLZOR0WlldAiRA1Mx1LEeYhqKegn2qCIqIiWLOMmEhJICFAU3gW8Wt0jEkK1PUYDh5QMOftiMghTbnAj5wOOv75VgNm31aHT9bJYG3kyJGi2NPaWdQWnwGc7Xz88ceF8Nn5nnWmC70HkCAtdrpmnDpKS48KwQlHzGkHcpBSwM5MaBonsGOWtNSV5JjpNRoawVEs5kJWDnDlVT5c/fMc5GTRRUQMjJvowx1/yMKwofK9S5cuxWWXXSZ8Qms6ZrWlhf+Pf/wDr776qnh+bHcVUy/OQDZRT5OooClgh4Qm4MOwUw2GYEWSDUmrlj4hMVBz4EgTOC8UIfyBYitBMid21iopyDLJGQcNGAEDsbCMmEGxwrgJPsye1Q4nDJZQVlZWhmuvvRafffZZ24YgTjd8/fXXIgnGgwMwFs0v/4ui0z/nIsNPeg+ZNqKYpAhyqpxWkGpLECBbskukIliwis7Y7o0n5Gx+RQqjGWJw/igmWRScpF1M+hY6p2kSs4pFm1qfXU94580Abr6lLp7A49wRX3f37t3bpgI44rzvvvtE0MObx6Ng/Fgf/vd/MlDYXYdJ/Nwym0RphBoUMOl+KTyGJ1aCZStBdcXxXyrBl8COZDBG4a8QPsNa3JkLJfDMkrGFwQGfSUzIsuLn4wQet0e9838B3DSDgjW7snbKKacI4lBUVNT2ICgnJwdutxter1c893qIh4/2k/BlDkdQz2S1GwHa32CbBbEcOkhxnK1j1XGfkBwnuEQEzYpSKA5ojBOshLQFxQmaTwRzlpLwZwmKOHoeP8mPv9ybjX69tTg7mjJlCrZu3dqiCtBmzZp1e6pxv0OHDujTp4/g/t988w05QmDXTgPHdHRR9KtyAlMSGSUeKNh+OGbL3xV3zIqT8CfhcyAmnlDwJlBJ0ZqmJsROfo+TUY0lvKaIcyn8HuHgE9Ia7PN1BT37udCjWMOmjVHs2WuKqJ2d86mnnor27duLeCbtFcCWw+0hnPo9cOCAUIJBFran0sDKVWEUtAf6HueCrihSBo1oaAe3yUqwpJgUyZykABX5yCkL8ajGYwFnv1SBkiBoPk9M7lN4Fpg2ZbX/StQSwVlJXze6d9HwxaYodu0xsXfvXgGpw4cPFy0vqVZCSn0AXxzjJjMJTdPE80g4wrwkfkyXIg1/vjsLF0zz0h+3wIiC5M/Egia4UFx+Owuq2iloJyPqabR2nk7CMWuNkMMO1ww0whD7FMJ/JZ7ylvtFQceINMIhPWp0asujYf47QeGY138mHXf//v1Fjblfv37pPQO43Pj222+LqJfhSLBFbyNVr622KDCLovAYVcwEjaa+FU3IvdmSUDXFhhzNtl7TjnxljVhR7MCMo2ibcsrXLJGc45nARXzGd+FT6FxS9LF4ylvlaJmzqKZhzzI5YXgmFPdyoStd4/r1UezbbxGTq8KaNWtwxhlnEI3OTl8FcJca929u374d4IaES5l/0jiHXutPH3qvhoPfmFi1IkpTWkHfAQRH3NmQWG20p7nk/7aVCyVYtuXb/kHR4tRVFGziClLi0KSoZnwWcXDGQVajElSZQVVkqjuuf85+k2H06K2jTy8vyitUbNsWEXWMFStWiAawrKys9GRBuq4T7bTz+czgLqdxMY1LSA430+NDZN0jdPpQBmbRFH/puQCi/IHbqbLmnlA/YMu0zDCxo4CtFMMu3EiYYkopjZ72m/U2/VQTlOC2awv2iZkhaf4EOGNlaGQ0BHe6KxGJRD1Bdys4Y6wLUya547WJjz/+GBMmTEhZa3zKFcBFFw7CJB+l0S1BqF7C3dPJch8iaxunYOtOE7ffVo+Xng+KlJDobEhkl3YAxvhtxYJyVzxNoMhuCTMcV4hlJCvBZkCcwtZ0G7o4evaL3FOjc2YlkL9hJTD+6GQMbvna2tUhzHmzXkIgn418Gxf3XS5X+lXE2OlysYO5M7MNtbsKI9c4lKoOoQ/zAB2fQ0p40cDsWbWiNeXiS/1koAqFBFajaVh2eiEakFSUgjWOEWS0zKBEQuXgi63bMoQSFC2j0Scw/rOwlagNa1F6PzlqsnpLBONhe2apQgmmEiI/ZkDzMe5bePyJGBYulkrm1pa77roLp59+uoh10k4B3ELOvZ3siJU8squhZFlutQkLim896cP/kdCYhLb9JRO3zqiDiwz1/At90MgKjTpLTABpicz9LVE9k+rwi5kgCjHMesRMUKUP4CiPUxNxeopGhqTaNh+L2jOBlGBxBjVkU1dN1BOgRsVYsSyEN+fKmcexzZNPPokzzzwzpck6PZXWzw21y5Ytk5bWlwQ00kIG/ZhNcCVhKya5/d5EID+ArY8YuH56LbgV6KJLSAmctVQtm/+zfOgxJuvG/Lcs+GQ8peiNBR0uxpAQLZPbGENJeSM9Drose05lCw1bmq1I6X0VwkLF68P+vSrmzauhOCAi/Nq5556LMWPGpDxTmjIFcKnx3XffFbVfceLhOly9uTii2pHpYS6gpw7zDhNGexM77ovi1hvrEKWgaNrlGdhFbOnJB+uRk6/iqmv8yO6giSQe83xLEB1vwsdQpD/g9LTIXIft3c0owQmghRJ0myWhMa+kGFiyNIh5H0jo6datG2644QaB/yknLakS/ocffijop/h8/TRkTMiA2+NuHn6StozsDGgzNIQywtg6uxZ/IJ9QXWHim3oDf30qgJJuXkw+z0R2AVs3ucMow4ntlLkxS3HS0zYz4hQ0C9WI2NkKL5q2u0h4s0RvqSqP5YSdxTVnlSC0BmUrDqB8R0TMtrFjx6KkpKRF6gQpUQBzf7Z+p7bqPduLzOGZwvq/jwJkypQU8Rt6R76OrbfU4te310G9yo/ez+bjmqiKDuSwraAlhWB3wjE9FYV6JSITdQRBlpP9ZCy3k3eK6JTwJFi5y1aeIhJ9iqnbuT4OHHVs3qBR0CUztl27dhEKaKkiTUoUwG3mvIxInLC9hsxTMuH3+Q+P/YfVJPmMy/Lgy/Lh4KYaokWdMLHYhxuwWzhZo85sGjFzRwQJWxX5IVOUNznzycV9wW6EEhSpBNFK7U2qLxPmqxac7LTswgNKV1pYs9aKpyC4XNlSW0oU8Prrr2PjZxvF774RfmQNySGDdoui+L/szFk0k7LQflI2qg+Y+OjJ/Xg10oALrsuCRnGC0WA2pnNEEo1zTW6RzRSO15kJosMibLcz2krg5i5RS2jqEyRhkoFZoCGEstI68mVREVByJjQeWKajAtj6OTyvrasVi131sRnwF2eA3a/5AxQAO4vJXT5WdRifzQti+vv1iBKdvfjqTBExi5mQoAQzGpXrBEQ3SsiOZt3CJ4iuC1YCQ0wsLBTV1DE3xgvsnZcu3Y9FSw6IfZx442aCltx+tALeeustbNm8RZ6svxf5J3RAOwp8QogIH/CD6wpMNIs86HJ7J3xZH8XNFCcwabnoSnLupASz3rQbcu1ALRaRzlhTRbwgBSxzQxZXweweIpEV1RQ7ReFcn+wzjYQDmDNnP0XysXhVrFevXumtgEWLFmHPnj0y8zAgEx26Z5NNuYQAv41+fq+ZQDLqdJwX7f7mw+fTy/HbGXsRqo7hsl9nweulmRAym9QSTK75Rgn/XVwdk1U0yfH5algJiTPB8Qk2LyXIeufdCsyfL7un2fp5/XFLUM+UKoDbOOpq6yT+F/jgbs/go1GY5PvRF+egTPuuHgz5W0+svcXELX+qEn26V9yYDc2jyA4HJcmJWI2cXkbMbpmmiPsEiBkj4y9V5Mu/+SqIJx/fR9TTWeg3SqQcWnr70QqIRqMi9SDsiHi02/RwQP/96ef33HLzsjHszuOwLncLbvnzLhJsDS67MQt6O5m2aGRHqoAZUTXT/DKdbYXsog4ka9Lt1nZiTaFIDBurK/HZ5lPhqmtPe+fw2hvs27dfxDdc207rmjCXIKsqq1BXXwdvXw9yT8uF1+eNO9NU/bCIfT4P2g/LQX07DxY8sA85oQgGDvfART7BCllNZ4DllDbtWoLK0CRX3VhhE8FgDF9vMPDiuho86K1DYewcTNt5ETZv+wzloXIBq9y+fvzxx6e3ArjjjdPPFbsqCPlN5Iwgq+zsJ4Yd40aQlP7wGd0eHdknZGB/Ox2LHqxGZgMpYagL7mzC6rDVWNDhzCnBjuoyZUKPgrFo0Is9WyNY/GENXvqEICcQw0qK2isKVfxk1Wj87MA4HNQOYlH5ItQH6gX+T5w4UeSC0lYBnCfh3k9e72tU0ZTt46VYIIOEFRVKSPVPiAMszUTeiRko76ChlOKErJooBg/zQPfTTIhYdnJQlcGvh1NECtYva8ArL9XgocVBzMnQsbaPH1UDfVB7asgp1zF+/lnoE+uL/NwCrNm5Btvrt6OhoQGdO3cWwVja+oC8vDwxTefOnStuIbOvjKyyMhueAs8PjgO+0+/Y/KrnpTnY7OqC2/+yCx61FlfNzBHBmhkxoZIyjGoDC16uxwcrDSzzulHVz4eGkzLhGeJHh3w3/IT4e80q5K0uRmFNZxB/RklWCc4sOhNLdy+NlyAvvPDC9E5FXHzxxXjttdfEzTXql9TiYNlB5J2bJ2CjpTan763rRVnY7rXwh2d3Q7v/AK74dQ4JX8O6Dxvw+JMNWGq5sO/UPISGuNHh5HYo4nS1gLMgKHRE5f4qTNx4LnpEegCZMi47seuJKNlcgi/rvhQlSO4P6tSpU/oqgJuWhgwZIhQQqzRQTbNAH68LDE01GzoEQ2kudJpE2J7fHn96oRb1D4XQkQT8tyURvN/Fg+yLstF+VBayxXwMos6OT/i6AvTjKfPg1IpTkefNk2lsIkwjC0fipGNOEgr4YvMXeP/990XndEtsKakJMw0dP358vLe+fn49albUEFqH6fO07E+AhBpFA9qf4sLu67Jx164oZnwQwOJTvMi5Iwe5o1xk7fV0VICuJtjkvftq92Hwh4Mx0Boo69cNcviz/RhWNAx+orG1NbV44403BCVNSyfspKO5k5jbujkrau0lK8tVoI3UEHOlng0lMyPJuKLwFlioPoZm4FAdWVMoKMwyKf6N2oTAiPMyPj5MQVlwcRjXLf4FxuSOgSvLJZcqK9Jxuw031u5Zi/KGcsH0Bg8ejB49eqQnBIkTEVXjvDnnhrgpK7I6gsDWAMX0aNXNPUgh+ekk+BAih0n0sRIiFJAVLe+CEZknw+f3yfSRU7Oh3wd0GoCxxWOxbO8y0enB96UbMWIEMjMz0w+ChFMklsC3DXNy59HNUQRWBloFhhJ/ggJsAt9+jBVEZGcEo/acjG6+rs5SgsZVUOQLdKKqI7uMxLEZ8v4SzIZ4bTFDUSoZUUo74zhvzg257LSsOgtmHvGNc2jiqz8SaKI0NtFYb4g2F8P3485nxSy4Frkw49MZOCHnBGgeTTpgE7JDxb5DTr4vH0aMqOzOBWKhITcc8CJvpt7cnpiKAC2ljVlsGdy2EU/hbqdPUpOCE9eTY7zVg8LLC+Hd4v3x5yMr77qvK4a2GwpXzCXhx2ZAwhFzXy9dt9/0Y1qPabiizxXQXJoIzO655x6xtJWXuKYVBCUGZvHbwlTT2GpbVRTO4sZ/bbA17gdOqxmBu3vfheHqcCms5OP43BF7JP6ePPhaKAAo2FaATCtTPq+3RywhyJBFCXTO7YxpvabB5ZV1ZG445r5X9nNp5YSdjYOW+KoSbp98g8bmZj5c8u8K0GzIQJ/btUfHiPwxmNpnGrZ9tQ1lW8oQ4QYiRTpV0XDLi7LtFhjm+CqnIhQ1jte8X1M0mG6KkmtVFGwugNqR7C8jQfiJK2FVbkUy8MmuT3DvmnsRCUiX3rdvX0FLU7WcNaUKYOtgtvD555/LHTsgWhDjrfsJTESxiyjJRZtDijgKs0IvogNNaP01DJ97EvIX5qMqWoVivZhe8whc92f4keXLgpt+mOFku7KR5cmCaS/C4CJRnkbRuWVAV3WcmH8i2rnbAc5qJ/VQxa+sWInry67Hyt0rxa6ePXsKR5xKOqqnEv83b96MLVu2CAfFwRkzhmAw2OS4Dp4OuKD7Bch154oPmaPmiDoCv9/n8aGdpx1dlA7DNJDpzkSeP0+cqyC7QEap+SOx4CcLEDWjyMrIEg7U0iwRi6hK4wxga9cUrYliNchWdMVShOI8EQ8OyZYooj6D0opSzFw5E6v2rIoLn2+zNmDAgJQiRkpXyDBD4CVJnJRjjOQEHa8+F1EkfbAuGV1w27DbMLn/5HjPEFumY/VCaNznYwtR54UWmuJ0kjeajLMk2Olwc+rryZDm+B0lyes5uB9pxiOSTpbvWo7flf4OiyoWid3clMX3OeI4INUFmpRCEF8c11JZ4Lw2+JlnnpGrZHjFSUEx7jjuDlw44EK4uBYYaya7ZsK5O02TZUMON3fKt3G4MBIEn1yWjNkCTlaKw3Yi9rmQcF7626U7SnHzipuxbJfsceXFhrw0iVPSPMvSNhJOrhMzXeMZwNDCmDu+aDwuGXSJFEANmlkXZlu2hUOV47zuLAUzm4GNJs7ItvxkxfDzsP2almT5JImy7WWYvmI6Pq78WOxmuHnllVfEDGiprUXWCTMUca04/g0XJLBPKz7F0u1LYXGbuW7/ZTWBebBw/UmCSRSw5zCvHZIZRNO7nyUqKGi/lvyp6dzLypfhl8t/GRc+sx2+zUJLCj/lPiC5VPnSSy/hoYceEn6Bt5/1+BkeG/sY8r35chY4Fuq2FaA0Q1NVxO9S862Z7cQVTM0dF2zGH0AqvXRbKW4qvQmllaVx2OGV/hxUtvSW8kV6zsar5HkK862DOWpkp1wZqERJZgkGdh4onasjXDearipKFL77OyzfccKxBNhJxvxAAs9PYjtLypdgdtlsLK1cGrd8vqEst6S0BOa3CgQ5m8/nw6RJk3DdddeJ5/vD+/HMpmdQUV0B0TbktaHlcJb/fWAnmhD9mt9SOrNvrhJ34rqEndvLbsdHez8Shx533HF49NFHheW3ZCG+VSAocQuFQuLbLThAy3Hl4KnTnsLkQZPtlezNCMyBpe+CHdiMxkhIJeNQ2lkfqsc7W95BeW05phw7BcV5xSjdXorflv4Wy6vkPUz5DilMmXv37t2q6fMWg6DkWgEvdHjvg/cQjAWhx3Sc0f0MeTMPqxlI+b7CdzKYVpLwDRty7BlR2VCJ2R/PxhMbnkBNtAbuiBuzVs9CaZXEfC62PP300wL7W3trtXtHc1Fj2LBh4h4SJd4SzD13Lvp269soRCRg/ncBo/ItmA8b8yONsyJgBPDytpdx76f3YvOBzYR8XlEXcDCf723B13Yktla7bSWvq+VFbiyQ8nA5Fu5eiIgakdisJuC0+h2CV5J4fnMON5pAb+kYv8ePK/tfiam9psKtu+PC792nt7h9PsPPkdpaTQFcyuP7dGZnZYtk2etbX8eB0AHpiJ2hf4fwYVt++DCZ1Oaopn0b6pV7VmLJziWIGDI24cj2uWefE76pNdjOEVcAt6gwy+CkFm+lu0uxqmKV+EKGRGv99nTrt1h+c8K3GdTy7cvxm49+I3M79N4BAweI2vWgQYNavP08bRTgOGO+zwLT02gsiqfXPY0d1Tu+v8MNJ0W4SBB+5NB8kKmYWLxjMa5dfC3KqspEKpqF/vbct9GlSxekw9aqCvD7/SIucIoZ//zqn6LgYd8p4LuFj2aSbiEcWkyBdOYMOdctvw6bquXtiTlR+PLLL6fVt2m0qgIYa7nFj5u4+PeIGcFfS/+KjXs2yjyQmkQnYwnW3Vy84ES4SUqx/BYWli/EjWU3YuPBjXG2w98xlm7fonFEvsKEm17HjRsnAjMuvowvGY8Zo2dgSLchoqIV5/Zhe6iHSSnHmjEncuYLty0U+fwVlSviuR2mmieccEKrRbhprQDe+JaWfGszZ33ZoKJBmNp3KiZ3n4zCToXI8GRIpxpMgCHH8kPNZDXlneyxaNsi3LT8JqzeJ7+kgTH/xRdfFGXElrjpXptVABdquH/o+uuvF3dW5C3DnYFBHQdhaJehmHjsRIwoHAE/38fHmRFGAttRkyyfYohFWxfhv0v/GxsObBC7uWGY79qbLg43rRQgjNmyxF3LZ8yYgTlvzGnspCZD7ZXXC4PyB2FM0RiM6jIK/Tv2l4JuSJgVjkH7gPe/fh/Tl07H5zWftxnhH3EFOBvXkLnV48033xRfcZL4VeXcNt4nvw+O73w8pnSfgtFFo6Xga21YIqRasHUBblx+I9btWxeHHb63Dz+m+5Y2X+bJnQ9cxOF1x7wogh/5LoWJGN8/tz/O7HImpvWZhqH5Q8WMeO+b90Q+f1XVqrjlcxGIH9MR89NWAc7G1s/K4BYXvgUOf3e8s0pFwr2KUYWjMH3QdHg1L+5cfSeW7FkiXuOuBbZ8LiO2BeGnpQIS/QM7ar47ITMmvhcRD+fL2Hrn9Bb9RIz57Dta847n/xEKSN64H5O/8pa/hS/5e8D4Szv5G1lbek1vSykgLBl0+m88I3gFDn8toVPoZ6xnnl9cXIw2uNUzsfukrVwtZy7ZyrnGnJubK1LJ/O3ZbVT4vG1gBbzSpqYsOVf+ilrGei7w8ELxNry9whDE8MOgOhBHt1a1fhpDFekCxF2e5x1VQqsKfyyNCkcBsB3xz2lMpjH6qIxaZOOO39dpPAq7N/v/BRgAzzYY6JMe+WgAAAAASUVORK5CYII= + + + + + + + + +http://salidzini.lv + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lv/sslv.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/sslv.xml new file mode 100644 index 0000000000..2108963235 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/sslv.xml @@ -0,0 +1,14 @@ + + + +SS.lv +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2ODNBMDBFQUUyMjQxMUU1QjE0QUUxNkJFNEIwNTQwQiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2ODNBMDBFOUUyMjQxMUU1QjE0QUUxNkJFNEIwNTQwQiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Rjk3RjExNzQwNzIwNjgxMUI2MEJEOTMwMkE4QTkwQjMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7PU8A4AAAQFklEQVR42uxde1iUZRY/c2FmuA4MIAgKiFcEgbxWGpbmJa/hPpmlubVpq9Zua2272tM+u7nWs+tWrva4XcysHu2mYhSVeUnDG4qAiHdCUEBQuV8GGBhmz3lnBr/55psL6cQfvmeeNxlnvvd73/M7l9857yfJIl9NAIuocCzEMQvHKMt7xyLDYRL8eSdK93RgwJGN42scn1jeg9LyYSSODBzJbt/UesM7VfkgoQPXQMy0jGdxzMBRLrdY+vdOlS+zjDtd4e4CInP5zWSLzlVyS9gZ5rbFc7ldQJDOF1IISnWoeG7xtw6Ecz2mkgcM58rvMW8YrpRkO1zxngHBXlgOkLZ+Lp6hrSKRSyZcLp7PCXYAcOX3CAhyHvd7NifIuTZ6VjgAPZyQOQA9HIbknHb2rBfIefLtWS/gHsA94E73AC6chnIAuHAAOABcOAAcAC4cAA4AFw4AB4ALB4ADwIUDwAHgwgHgAHDxqCi78+WOzg5oaW8FE77kcgUoZObD/U78T6fRyI7Y1Ao1qJQqt046WzvawNBhAJlcDgq5jF3D5jLhHTo78R5y0CjVoJQru70xWmOHscPu7xW4brlM2u6MJiMY8b6yblwj1o/JZH/EqFR4OdSHWzvrxEU1GpogMjACpseMgTF974Lo4CgI0PiyG9bpG+FybSkUVJ6F3LICuHjjZ7YYXy8ftnihkJpb2lugHTeb2HsoTByYAkm94yHUXwdqpRc0GVqhHucrri6BnPJTkF2aBxUN11ABMjafTCZzS/lKmRKCA0JsHgOka/VtzTj0dvPQPgI0WvBWaZgBCK9paGkAQ3ub03t3mjpB6xMIGi+NAATz8571+jqmD5kEDE4BoAvISpUKJayY8Dw8PWY+hPuHOd283qCHnLJ82F6QAd+e3YPvm22sp76tAYahwldOfB4eHDieWbgzudZ0A7IuZ8MXJ9Ph4KUsNAajSxAMxnboo4uEjN9tBbWXmgFijrdyePOnDbA2813wV/vZXNOI61wwci68MvEF6MTXzRgth38feBvWHXwPtGp/acBR4XTFh3PXQWJ4HP5s6tIfGc+MTY8xTxcbo0sADEYD+Hv7wyac+IH+Y7usy5n4qHzgvth72EiJvRsWf7kcfLy82WLq2xphZvwU2JC6BgK9tS7no2vC/EJhdvw0NhZtWw7b8tPBX+Xr0gsIpCC0SDIeodhaqCDMoJEU11wBf42f3WcjI5MYEM5CTwh6W1JEPPiJ1na68hzUtNQ5NDSHs1pRfWfOf5jyTZaXVTGOXsLvBWq0XfNR2BkemQgbH/kvU74781kBsn7PG4GUUp4zxYjnoFAhJSqM0xerCqEZPUF8Tf+QGNCo1A7v3Y736a+L6VK+8NqcslNo/e2S4cepBzS362H60EkwZfADNlZqVXJWyQn4ubqYbTLMNxSGhA2EfrootLybmBoxXHQpA2P+C/cvY94gnu9GUxUcLcmGSgw3KoUK+mojIC58EEQEhNss3JHybgsbwfBwvbEaSmpKIT58iM1nMbiv3v7hcLW+ggFlBzQm++TeCZIenV2Wy7yr2yyI0J4ZN8UuJOgNLbA07UVIP72LJWf2cBHeQItW3T84GlLQW+bET4fEiKFosRq2oHaMyRHa3jAuZrTdfDnl+bDg02VQVltuVjWGDoqVIT46SIiIgxlxk2HW0CkQ6hfC2JDJQw8ykeE0tjWxkCEGgPJFVFAkXEFwpACgNQ9DQiHeWxvG/cIbxeAldY0zAGiTdFEftESxlNWXw86C75glC+mhod0A+eVn4PiVPHjvyEcwO2EqDAyOZRZtRC8J9+uFIAXYzffjzwfhfOV5di+hakkZBwoPwZ4LB1jiXDBiLtxorgYvuZfnSDkaXV75aXg0OdVGF6TM4RGJsB/XI8V+KG8kigAgKcGccqW2DHWp/AUe4MDlY4NjYNGYBfDe0U+Q86uYlcuY1crBW65h7+m6z/PSUPlq9p3WTiMLR0TvFKJQ+EjibEhDQPORvvqpfRhg1pCgxIROUt1UA//atw588b0v8yrPCBlddlke837ak9DbkiMSsC6RSeQZI0QHhkG0ro/dZ6cqzjJDClD7da8SJsTbMXFcxrBgx6/R6t+atRq2PP4OjIhKhjZjGzS0NmKYuVn0UEjyU/kx5OkaBV5T0XQdavW1dvPFBPWFXYs+h79N/jP0xpjfgAtuwkQoBJ8UQ5ugWOrJJykpvFzGMFPReM3us6G9B2Mo8rczSqKX8WHxyHI0dtccvpwNrv7pkcPsQGj/cHFvFyBCpZGkDpsOe57ZBulPbYEnRz8OQb5BUI9AUN0gBNJqzZXIhzNLjkmGO60mAFZinXHwuQzY/OjbMAkTP1XHNJ+5gPl1hHJPVXMNFKDliiU6sA9EasNtDM1aPd8VaZuAad/k8flXT3d5dLcB8MUYv/tiJmReOiqpNJPlX5uN7TcG1j/8Ohx89ht4a/ZqxoYasNgiZiAEjrxhfeb7oEc6KqZk1vkC0MJ+kzgDtj2xCcHdAX9KWcLqEKofukM/b0Wo0DvKLNd2fWrk8QlYZFFtJCQq9Pcj+iTZzUOxv6jqknTSdgcAYgXUj1mS9hJrMQi5uVhx9Ar1DYbFmBv2/T4N1s56HXwwnrd03FS2N7pofnkBLNvxly4QHM3HXD5sEPxz6grYv+QreGr0fNDjXJ6koUJDOXI5pyv5CmVM1AibNdDPwb46GNxroN08J8ryoa6lwWUPyemnVL1dq78GqZt/C1tyt9sUTY68giyCWhY7n/wYQpA6tgkshuhcWsE3MOvDBXCiNM/hfEJgiR2tm/0arJ76srkR6GFPoJBReKMI2d5Vu89G9U1GIuDbtQba2yBUPhmfXfwvOX7r7WhSANHNRozFS3e8BDNRcT9c+JEh7wqIJGQNazFZU5UoZBNadQDkluYjCPPhDztXIlM44xJYkmfHPg3zhs9hCdrTeaAG80AOrlEsg0MHYD0TxvbEKmCsb0b1TbKL/9SLyi7NZQzwls8DrDWBFq33EOaDeVsWw4PvPwIfHNsCVxsq7VoHQnloyEQYhzmiFS3XBlSVN1vqx9mfwdSNc2He1mfg6zO7GGVz5BEkz497BnzVvh4PRXS/A0WHJftcSZGJWGC1WcKVCu6Ludvue0XVxayv5Cr+uwTAzN1vbtbMw72Rs5+C5emvwH0bZsKi7S/AQQeJmmTSoPHoqu02vRkrVQ3Q+DOWtuvcXnjis6WQ8r+Z8Pfda1hrWwrQQWiB8WGDbRKhJ4TONLKu5DBGJ+xJkdwbPQqZj8ncgvEPtauASbJKcjBqNLnVOnfajAv00bLbUotZWCVQsaVF5TWjxX6ZmwbTNz0Ga/avk7TeAVgNW6tXHcbKJpyLXFdmUzP4gj/WDeV1FfDG/rdh4rtzsCItsJuLzgQitZF4vdG2aSjlESaQzBfu5BCy3KKqYjhbecHus7Exo9Bw/Fg+igsbACGYhMW0O7P4qNP+j1sANKOipsdNhi8WfgDJGOfqMA8QexFugIoyAsIL//z05Fc2Fm4Vb0zKpDh9RyusmfkPeH3ayxDgHQA1LfUMCPHGdd5BrITPOL9bOkYrFEy75oOdVqyyDSxENuPaqPdiNQIqkAyi+VnYcKOfRJbb2t4mGYYGhMRCrC6a3Xt8rH2LnopSasCpXZxzuPYAMFtWSr97YPfibbBx7loYgSyAEhAVSKxibWtmPzciWPfH3s0SmHhzFY3X8Zp2dNtO1mpYdu/TsG/JTlh+/zLGkgjo+tYGFv9pUO+c+vjk6lLSYKF21K0dFT0Cti/cDPuXpmMBtx5idH2R+rayddQZ6ln9IJY4pLfEXkiBBBiFGRr0nvZDfxKAREf3Fx2yoaP0MxnJsIghbE8psffazZ9bng9X6yqd9n/cPpCxKpMq2ceSU2Fe0sOQd7UAcjEHUJ+jtrUagrx1MA4T0cMJ0yTnOIzVr9UqOyzt6ajASFg9ZQW8iIVWHs5FR49F1SVgQHCjMcTQXHS4IQazWl+LNck5MyNB+vfFgo3MA809qmim3GkbHzWD2tIIpbXl7F5CmTx4AqyY8EfW6KPzZzqvpW6mxssLevkFYrjtQLKRxSj4Sdwr5aOYoCibOWYPfQjBamK1ilj2YvHKqmU3e4ZKV65oQ7HwPR2q0HAGmDUe0nlBxtkfWOLWo9VZixLr94K8A2HCwBQ2nM1lla1Yi1BPnjyTWiGkfCH9I5o4LvYeSD/9HWuV/3TpMFbqo0UVrQpWTVkJxknmBqFCpiD9s4cMSI6XnYS9hZngh2umQupw8XEbAGiOqUMeZENMP0nxPyEhoXu4K04zBZ3kCDm6ycVL+N261np4Lm0FsoFmc2jC3EFxWZisXM0lnO9w8TF448AGBiZjKg5iLCV8uhdZ8I6Cb+1aH9b5aU309AblFLngrFan0UKAhepSIt19YX/X8brYOMRGcubaebhwo9At/u+6F4SUM+Psbljx7So4d/2iy6NIIQPKQStK/ehJOIrVIM1jYslYBSszVsE7Rzazvr7MzRcl6o9PfA7zP10CLYYWFg5pg3uwIBQXcJWN1zDkZTGWRsqlinb9oY2ShZ4j0IlaBvkEMe8gEI8iHaX1gsQ+xe/3oefQgZU79LOLVAQ80OuvpB+p8EOs5hBa3pf56ZjZ81lspUNuSkRkOeS+lFyJppY3VEBm0RFmpauQy5djqCBqad0YfbcWmc/35/fCjtMZcP56IePzxGBoPup+yizlfT26PllSGlrwy9+/BpuObWWfkeJNln7NpZoSKK2/CkMwFxAby684jR63EgqrLnV5B33vEIaQBkzGcb0GsVaIK+Oh8LHzVAaGukoGYpW+BkYi+Rgi0e8Ry+q9b7KnILwUbh8atcgiX00geHVOO4SkZHRlK5MJ8Q2FQIy/pBA6621A9lCNVlKnr2MboUrXWROKOqXEVmjPWnT5EL9gjLk+7FCnFcMUMavq5ioEtpWBQxYtJdSWIMakxVxC7e52vFZ85kyHQPS98IAwlrviqHfjo2MGxo4NEfDqllpW09Qg8JWoeAKR9kt7ICOMCuwDsSH9MLR1OsyVdH6SjZ5vpC6w+x5Q4xYA4kKGFkWgsJoAb0Y8n6xQLuv+k440D7Ej2pzJ4tYUeylGu7MRa7VO93f2fVozgdtpfVBA9LtR2dN+6KUsxFlql5u9HemaQgwCdXy7E34IgG4/80c36IaLuU5CqGyV4pc/okpA0cv1Uw9KrLh/2SOOtN/bueduNeO4eFY4ABwADgAXDgAHgAsHgAPAhQPAAeDCAeAAcOEAcAC4cAA4AFx+FQD4r6/vOeG/vr6Hhf8PHLgHcA/gWug56+csqIetnwPA6wAucqm4xMXzsV8aABMHwePKN7kKQZyWejzxigEwuHITLrc/9FikmQDId4gUB+L2KV46spwlAHY6dRkOwm2N+SLZSQBsxlHAQfjVlU8632zNAQ+5BIHnh+7FedfKJ50brP9igX432UgcT+GYjmOsSzBkAu8wcSt3k0Fm4fjaEnUY+fm/AAMAWLYzeILBGhQAAAAASUVORK5CYII= + + + + +https://www.ss.lv + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/lv/wikipedia-lv.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/wikipedia-lv.xml new file mode 100644 index 0000000000..b0d82664cb --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/lv/wikipedia-lv.xml @@ -0,0 +1,23 @@ + + + +Vikipēdija (lv) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://lv.wikipedia.org/wiki/Special:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ml/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ml/eBay-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/eBay-in.xml new file mode 100644 index 0000000000..8d27d340f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/eBay-in.xml @@ -0,0 +1,17 @@ + + + +eBay India +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ml/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/list.txt new file mode 100644 index 0000000000..9d7b7a0d25 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/list.txt @@ -0,0 +1,7 @@ +bing +duckduckgo +eBay-in +google +twitter +wikipedia-ml +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ml/wikipedia-ml.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/wikipedia-ml.xml new file mode 100644 index 0000000000..746f5e0864 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/wikipedia-ml.xml @@ -0,0 +1,23 @@ + + + +വിക്കിപീഡിയ (ml) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ml.wikipedia.org/wiki/പ്രത്യേകം:അന്വേഷണം + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ml/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ml/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/mr/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/mr/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/mr/eBay-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/eBay-in.xml new file mode 100644 index 0000000000..8d27d340f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/eBay-in.xml @@ -0,0 +1,17 @@ + + + +eBay India +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/mr/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/list.txt new file mode 100644 index 0000000000..0e0551ee52 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/list.txt @@ -0,0 +1,7 @@ +amazon-in +bing +eBay-in +google +rediff +wikipedia-mr +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/mr/rediff.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/rediff.xml new file mode 100644 index 0000000000..7905815b3e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/rediff.xml @@ -0,0 +1,14 @@ + + + +Rediff +windows-1252 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCNjU0MTA3MEUyQzcxMUU1QTJGRTgwNUQ3ODM3MDA4NyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCNjU0MTA2RkUyQzcxMUU1QTJGRTgwNUQ3ODM3MDA4NyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMTkwMEE4NjY0REI0QThFNzkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7xsnzEAAAGrElEQVR42uxdTYgcVRCu6p4dN7vJJosuG9QgnkQxsocQ9OQPCqsIeojk5iWSgwrmpBe9BQSvESLqJf4cgosYCXjyICxIUENAUDAiRggS9BCym/2ZzLyy6r3q2Z6dienO9nTPzFYNb3qnp3+mv69e/bx63Yt/wIOgUud2lNshbo/pZ5PipMHte24L3D7Uz4BKwD3cznKbM5xKkQvcnud2OVJN/8bAL1XmFPN6pGZnv2FSugjmR4WAw4ZFZXJYCDhoOFQmByOLdioV7wNMKhQjwAgwAkyMACPAxAgwAkyMACOgZCFdYurvrIKp1q/fhqNNACFfILe8MLapQuJjgG959qbkGHJuxJ7byPqwnRtdAlCRCABGmWloE+bRZ7AoTw9CiDCA78/d85wYXuj4V/Hvwug2emg2qVUIP19Sk9sSAxixnpHqZh51dgFQmOT3eiaQBHBHTX92AbdFq3yUZtd2LZIjj0OMO/j3uZsQNcQEEDSgdt8+mH77VVHiACZl0zSvvKjaz8urx0/CjUt/MURjtyB8ld8bEI3PANZl2xswfex1iPft5dNTxwnk8NdPfQ0ri4u8Yrxv3qDCHnADarMzsOuVQ1s+0rWPvgC49DsDPNZhpoJZc/xa4+Ua7Hj0cbjj4fth1xtHoLZvlvljE7Nn6qbgrp//FdzitxDDhPa2ETNB0AoXRbz0Gp3DzqKak0gMektcJbK5QA8U+Z7U8r1M2vjcI7DnnddgYv5JwInxthP2x+BeRETdPibiYzQa+ql/jrhCAoqmE9WUCS1Nhp+Bf2g/7HnrCOx8+YV29ORcq5TwchsSkOjqqof6rvffhd1HXgIcrwOJfRdNRxwo8EeKAPK2/ipMPjMPd773JozNPaDmTYD3IQ2o3zYCCtN5TZbEVrdwHaaenofZL08A7pzwdIDDjWTDmyhnPaA4gyPYKrATdbj7zOcw+dwTAHHstd5nskS6KXbsZwQUNk5D3qTMLpyA2r2zAWJHmjS5QcR7sIYitt4RwjiSgE8S3biQsVLkNKs2AvrUATRnII3PnQsXouvRdYwYDbQMpwnC7nEjb3aQepgq6wF9dcQ9QcbhuQqriBkB21tqI3+FKAWY7DbJOWcEZEzDYKOWTDctL8q31059lRrZ7F2ClOJQPDMLO198KoVOTY8QhrWNgE1pmA9DOfLBKPbr18//wji1YOmzs7C2uAgxTgA0CVYu/AAyPB326jUaKgA3+X0Klg/M+YFsOUvrz7/5GFPyl5Y9jYCucBQxgqvHP4DGxYuw9IncZ7gulQEI+XCL9Tbm16THWKJUR929STqO129Oq6//eC5VzInZfNU9+AT9GcauDSnuHgtS9JY/PQMrv51juPYyYJPt0FS+jn3RX8qdDCaFwmS3OYukUuw/RL76Fda0kmIN5p56MdpRUACeNszCrinWpN16MeQJQl8C0MyYal67HVJPc0Za3BeS/OCS7ylhnf9uFIvyRTgCX5KETVpN6eleibdw6jP+x6l0FCrD3th2wN09x/IAS8RMjAAjYKtmnBK3WUBmUOTe5Y3mVeuEOYanjusNM9KyEBciHExGG7ZEAupQdlsRiEqjoFICUKcooA8RNXTMMRyBm6KW2ycglDZD+diFWRQUjT4B7SAxknCSOnpClr0doVbCijJgEvVHoUeA2w4mKFx6lOr+mFGTnZiJSCnE4lQiZM7lVdIqNkEBOUk6KacdD/M61WcUhhcGRaBtQkCvMCTrbIZc1qrEiMryAMsDTIyAIZKKfYDeiYjphCiDlSb1FUneVLAfKOcG1YEIQ91GNBOFLCxbABJCn5BHx4X6TUqy8ZIioWoJUNUV8ElrhtlmMIShiPaAARbZJ3FjyuOo+wDaNIyQN/9J0jcsMg/AbTQtJakySaE8olCTdS4jmqTVqkItEOl4FPatAjaQUVCk92/luWQ/B6h4C9ShGBaG5jZllgeYGAFGgIkRYASYGAFGgIkRYASYGAFGgIkRMLhS4XA0AcR680Mcpe58zC7trWMEGtIhuQoJGIPmlX9g6eOFLT+20l359xaPrBxckX9lWNETLVIPbvXV3XIe3Go9IGWC5HZShOlwd2J7ZnTWmXHJs50pNZkWjYBcFGhRCwlyAZh+eLdOLu/bjdQjTUByfwDdrvMlHOJa2AAQ0PnMn7xQEoyCWB5gBBgBJkaAEWBiBBgBJkaAEWBSAQENg6EyWRYCfjIcKpOfhYDThkNlcloIOClMGBbla79gn/iAZ42E0sEXzBtJFHSZ2wFux7h9Z/j0TRYV4wOKOfwnwACUUUOD1EeLIgAAAABJRU5ErkJggg== + + + + +http://search.rediff.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/mr/wikipedia-mr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/wikipedia-mr.xml new file mode 100644 index 0000000000..2ef18440a5 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/wikipedia-mr.xml @@ -0,0 +1,23 @@ + + + +विकिपीडिया (mr) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://mr.wikipedia.org/wiki/विशेष:शोधा + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/mr/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/mr/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ms/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ms/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ms/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ms/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ms/list.txt new file mode 100644 index 0000000000..84d2fb5bf3 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ms/list.txt @@ -0,0 +1,6 @@ +amazondotcom +bing +google +twitter +wikipedia-ms +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ms/wikipedia-ms.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ms/wikipedia-ms.xml new file mode 100644 index 0000000000..8b1f554755 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ms/wikipedia-ms.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (ms) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ms.wikipedia.org/wiki/Khas:Gelintar + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/my/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/my/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/my/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/my/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/my/list.txt new file mode 100644 index 0000000000..13bc570250 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/my/list.txt @@ -0,0 +1,6 @@ +amazondotcom +bing +google +twitter +wikipedia-my +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/my/wikipedia-my.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/my/wikipedia-my.xml new file mode 100644 index 0000000000..8b03d391b6 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/my/wikipedia-my.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (my) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://my.wikipedia.org/wiki/Special:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/gulesider-mobile-NO.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/gulesider-mobile-NO.xml new file mode 100644 index 0000000000..bac0801df6 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/gulesider-mobile-NO.xml @@ -0,0 +1,16 @@ + + + +Gule sider mobil +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGQ0JFNjNCODNBODcxMUU1OTA4RkJFMkNCMTYxQzY3MCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGQ0JFNjNCNzNBODcxMUU1OTA4RkJFMkNCMTYxQzY3MCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Rjg3RjExNzQwNzIwNjgxMThDMTQ5NzZBOENCMzZGNDciIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz46qzHsAAACjUlEQVR42uydzWsTQRiH391N4weRSjH1CyIIpUpvjRfBS/GoCBWRXvRUevIk6t8gKl4F/4CCUANtjwVBW/Ai4kGk1CIopBS3RFNEMUld3ykreN3dzs6WPk/4EViYzOR9dnfCTEK86E1dYgLNlOaG5ryADZqaGc19zbo54MUCqppZCp8bLc2EZsGPz/wGxc+Vgbjmw0bANc0FapI7Fc0DP77ngxsuGQHD1MEZgRFQpg7u8CkBAhAACEAAIAABgAAEAAIQAAhAACAAAYAABIBdSrY7uHL7ozS/dhO3O1ktS+PRaSn5Xqb+e38iuXrnkzTDTvIxDPbJ3OOh3S1g/tVmqnZvl3/JWtiT2rFsO6ZrYVfmF9upx8AtiDkAEIAAQAACAAEIAAQgABCAANg1Asp9Xup2/ZUgc//mNbKMwTbWV0NXGiOy8X0rcbuB/mDHBCw/H5FWO/kYjhwOrAswP1P9rM81az1EkfaS/kx6t/JTnsyEqdpOjVelfvags7EX4grIytPGxnbSEPieCqgV+v0xCSMAAYAABAACEAAIQAAgAAGAAAQUhiDDt6MD3yu8gMKvht69eVQO7Pek/SPZer7ZB7h1fbDwAgq/H7ATfFnvSPitl7id2ZA5dXzf3r4CsmKunKHx99LpRonbmi3J369HmYSzCkhTfEPadgjgUxAgAAGAAAQAAhAACEAAIGCvCoiosVsBnj62l6Qd5US1JGP1Q6nGPnauYl2A/f0AYA5AACAAAYAABAACEAAIQAAgAAGAAAQAAhCAAHAtoEMZ3Ar4QBmcsWUETFMHZ8wZAc80C9Qid8wf29z7NwlPaF5Sk9xoaS5rVv3/DlzUTGpemHsTNbLCquah5oxmyRz4K8AAibe+3Px7Wu8AAAAASUVORK5CYII= + + + + + + +http://m.gulesider.no/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/list.txt new file mode 100644 index 0000000000..66c0699ba4 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/list.txt @@ -0,0 +1,5 @@ +duckduckgo +google +gulesider-mobile-NO +twitter +wikipedia-NO diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/wikipedia-NO.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/wikipedia-NO.xml new file mode 100644 index 0000000000..52180b96d5 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nb-NO/wikipedia-NO.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (no) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://no.wikipedia.org/wiki/Spesial:Søk + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nl/bolcom-nl.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/nl/bolcom-nl.xml new file mode 100644 index 0000000000..7e93a46a54 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nl/bolcom-nl.xml @@ -0,0 +1,12 @@ + + + +bol.com +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3wkXERE19+wneQAAEVtJREFUeNrtnXl0VGWaxn93qT1FqLAECARNIGxGxCiRiEhjABtb8MCAOno86umBbkfHg8rocdxmeo4NZxxxt6HPaUTl9AguRAWjos3ayL7EkLAYIQRiwJC19qp7549bVUlBlkqlUinaev7Kqbqpuvd9vu/9nnf5vhJ4r55WeAJYAIwDzCQRSziAUmAt8FLwRSFAwPDAGxOTdooLdgcG+ikx8ELS+PHFxIDNEQNuJ2n83iHhCTEwFZLoHSwQAwtuEr2DcWJS7fQqzGLSBr2LJAFJApIEJJEk4JcL+XK9cYsskCJDP4NArVulzqPiUZIE9Agm9ZeYM0yHTS+QlSJSOLjt267zqOyr9VPeqFDlUNhU7WPfBX9CP5vAe/VqIhr8tgwdUwfJjE0VsemFsPcr7QoNHpWKZgWXH4wSZFpEhphF0o3h11Y7VUrq/BRX+/i/kx6qnWqSgEumoQDjbRJ3DNNxW4bMhDQpZOjv6xU2nPFyuE6hwatSUt/5iB6bKjLEJJJrk5g7TCbbKjHYpBGz/ZyPD055KT7r40STkiRAEuCvk83MH64DwKNA0WkvfyhxR2TsSDE/U8fiMQYmDZBCrz22z8XyMvcvk4B0o8AzuUbuvkJHP4PApmofy0rdHKjzU+vuuVsaYhK5cYDE0glGsqwiFc0Kbx718Eq5G0X9BRAgCvBQjp4lYw1kWkQOXPDzv0fcrDnpjeuDGyVYPMbAb0foyUoROVKvsGS/k00/+eKqpuJKgE0v8MMcKzaDgN2n8theFytPeHrdD7+cZ2TxGAMAK497WLTL+Y9HwOSBMqsmmRhhFVle5mZZqZsaV+IokrGpIq9eZ6JwsMzGMz5mb7bjV/8BCJAFuGWwzOoCM2YJnj/s5vVyN76EE78a3i0wc/cVOirtCndtd7CntmfjiB5PRTwyykDxNAspEszd4mB5WeIaH+C+vztYvNdJllVk969TKBwkX74EvHStkZevM1LRpDCxuJlNP/ki/t8JNolVk0yXBFbxwFvHPUzfZKfGpbJ+qpk5Q3WXlwsSgBlDZD6fauG7n33c+q0De4TDPscq8vhYAw9m65FFsHtV8ovtlDbEP6WQ21fi60IL6UaBguJmdv7svzxmwLVpEsXTLLj9Kv+0NXLj33OljqNzrCwcqRkfwKITuPMKXa+4o5J6Pwu2OgB4/0YzknAZuKAcq8inU7Uy86y/OSJSOhZZYO1NZt4pCC9PH6lXuPkrO3/8vvei1e3nfSz6zkmmReSrWyyJTYAowDsFZmwGgXt3ONh6rnOfn2kRWX+zloqQAyOszqPywiEXeV80sfWcD6e/91ZtRYWVJzy8/6OHaYNkVuSbMEoxVImxvNm3J5qYNEBieZmbNT9GFtn+bbqFrJSWcVBS5+fqDc0Jp44e2OlkqFlk4Ug9n5/x8lmVL7FmwIQ0iYUj9ew87+fZQ527jPz+Ej/cYQ0z/lMHXNz0lT1hJeq/7tYi5FfyTIhCgs2AxwOh/HOHXJ0uuvn9JYqmWkISs86j8sDfnRRV9Xw+yKoTyLGKZFpEMswCFlmgxqVyoknheKO/wzXrWJPCY/tcvJxn5MlxhpisTTGRoYWDZL4utFDRpJBd1NTp9afnWhkaaEmye1Wu3tBMRbPSpgycNUTGZhBCaeruVLhev97Ew6P0HV6zYKuDdZUdD4Sy2Vb0ImSvb0oMArbMsDC+r8SoT5s6HEGZFvESn3/thmYO1LUYNZimvmOYHCKpNWpcKltrfCwvc0ekyzMtIm9cb2TaIBmLHJnf+KzKy93bne3O5MfHGHgpz8jyMjeP7XP1LgET0iR235rCukov/7zd0e51qTqBD6eYQ/Xc8y6VOZvtYUacl6njzYmRR79ztzj45HTbo9Uowe0ZOt7ON9HPEP55VQ6FU3aVvT/72HPBz+E6bfZdbROZN0zHlHSZBo/KDcXNnG+jNmGUYN+vrYztKzKqqIlj3aisdZuAC/P7YDMIDPqwscPRvyLfxMKRLdP/3h2OMKW0dILmV1ujzqOy7Hs3G8/6QtUxiywwP1PHqgITdq9KdlHbs+7i7wti0S4nK493nAIf3UekbLa1w9T0rCEyG6ZZeOqAi2Wl0a8F3VJBo/uI2AwCH5z0dmj8dKPA3a2i2WcOusKM/3yuIcz4O8/7mb7JzrCPm1h2JLw0afepvFPhIW1tI9UulaUTjJcEddtmWMKMf9ahcO92B30/aOzU+ADljQqLvnPyYLaeHGvbJgpmSe/L0veeDA0Wzz863f6iZZTgk5stWHVCyLivlLcYYWq6zAvjNSPWulWePuCi4EstcdeRmqrzqBSf9VEwQA7z94dvS2HywJbXik57uXZjM2tOemnwRj7ZV57w4FPhtnYScefdKkWnvYxNFRmbKvYOAXcGCuklde0vhhP7yaFCeJ1HpeDL5jDDvnZdywie+Y2dP3ZhOtt9Kjl9Wh7h86lmslqN2GWlbu7Y4oi68CMKWotMe/hDibvbsyDqOCBVJ1A4WKaiSemwvaO1K7jYV87P1DGmr0StW+VXX9u73AVx6xAZl79lDcm1acZy+eG3Ox3dqjNnpYjoRToUBPsu+Km0K2EzLm4zYM4wHRZZYHkH1S2jBL/J0G6u0q7wankLAXpR0+WyAH865umy8ecM1THeJnHWqZFf0aTgC4yDx/c5u13kfzbXENF139crjO4jRh0ZR03d7KEydp/KG0fbX9Qm2CRSA11t/3PEHRqtAEPNIukmAbtX7ZLbCQZo6wMZ1/IGJeSzbQYBm17grWPdK/QPNYvcn60PxR0doajKy6wMmXnDdJ0GcDElYIBB4LSj45u7odUCue+i2mqqXqCkzs/6Kl/E9YKLjQ/wboXnEheXlSJi96lR+/7ftXKbn5/pOOm2JxDH5PWT4kvAQJOIvRNVkdLq00/Zw6891qiw8ayPdaciv+m8NIm1U8yhSPqTSi8ftPp/iyzw7FUGZg/T0exTmfxlc5d7fCYPlHl8rOZ+Gjya0ukIwRRKXpoUXxekF+FcF0auX1UvUTBPHYg8jA/mm1rj3/a6LgmOnrxKM97yMndUDVarC1ry/a8d9XQqXYPvR0tA1IuwRRbaDNNb40hD91vMLLLAqkmmMLdT0ayQvb6JKkf4599zpSaLPzjp5emDXcvRZKWIYelxu1flzaORrU0ldX5sBgEhngSkGwVONnds4E3VvlCf58X5mEg+/3cj9dTMs3J/tj6USCtvULhjs6PN7KkkaNe8Wh6+4HeGSf0lvpjWkiRs8qpM/8Ye8RpyJtDyPjCKDo6oCAjeaCTT89E9Wi5lXGrkU3R+po6y2Vbezjdh0QlhC/l1XzS3K1m/rPaGAr5IsXCEns0zUsICuif2u7rUAeEOlEwv3sfQ4wRUNHfuYj4+7WPlcQ9/vsHE0muM7aaEs1JElk4wUna7lbVTzGEPc6xR4a5tjkui6IvxaaBMeH2/zsmel6lj/6wUVtxgQt/KCg/sdPKXLvarHq7X7KCLIhiIahEOGiGS/LrTr7Jol5Mmr8rDo/U8eZWBzTU+GlqN0jGpUtgIDOJks8LnZ3w8c9AVUR6n0q65pzWTTdwwQOaTSm/YQny1TWSCTdt9k24Kv/fSej//cdAdVVUuqPaiWfGiIiA4PbvStfbEfherK7xsmW5hanrHX1vnVlmwzdFmJ9392XpWTTKxrNTNc4dclyidoiovi3bBiokmHsrpPEfT0Xd11SP87FLiQ0BQI4+0dk16ldT7SVvXSG5fidF9tC1ERhGC9739nI9Ku0J546UP0s8g8PZEE3OGaUrnyXEGUnUCv999ab5+zY9eNlX7yEuTmDlER5ZVZLhZGyzNPjjn0mbWgQt+Sur93d4PMNCoEdDoVeNHgN2n0jfKJGBJvfbgkUaOQ0wiqwtMYbsja1wqG8+2P2qD73d0TayQYdZq1k4/8SOg0adlROOBbTPD68jBOCBRkGkR2VQdHdFid1xQV7V9NL714t6hTdU+CooTp3ErWDGLRBHGlIBGrxqqcvUE0o0CK/JNIeN7FFh3ytutAkuPDJIAARdH5T1OwP4LfjItYtQ5kM7w/o3mMJ//5lE3C7Y5upQ5jQeCVcGlURbmoyYgmAb+r/HGmD6QLGjGn9ZqZ8oLh1z8+34XiYjxNonSej/eKJVU1AQcaVA4cMHPrAyZATFcC+6+Qsc9V+oQhUBn8nEPy44k5rYmiywwJlUKRcJxJQAI5eJHWGPT45uVIvLujS1Zz8+qvCza5exSYi2eeDhHj1HSsq+9QsD2QP//7THaQ/XmRFPo7z21/rju1+0qjBI8eZWBBo/arSi6WwSUNyp4FC2x1d1NC3lpUihF4VHgvh2JpXYuxqg+Eja9wEeV3m4Jg24RUOtWWV7mJqeP2O0OsbU3mUMk3rvd0WY6IpEQzDN9VNm97otuO++nD7qocigsGWuI+jNGWMWQnj5wwR9VcTuemJouc1+WnpI6P9/W+HqXAEWFVSe8jLCKLB4dHQmt+y/f+cFDomPJWAN+VeWeHd0XCDGRL88ddlHjVHn5OmNY2iBSBDva7F6V144mNgFZKSKzMmS21Phjcp5RzPaILd6nKZbOdqC0F3wBcT+yJhrd/3WhBZcfHt0bG4UWMwI2nvFR5VD4fY6BKV3slQxO41h0UfQkHsjWkZUisvK4O2bHnUVMQGexboNXJWt9E6IAayabunQTwV77WGVXJ/WXGGoWoyqSt4fCQTKvX68914sx3DgeMQGRKF2vAo/u0fbTls22RlyyLKn3U+NUmZcZfUD3UI6ebwotNN/Vh28KLeyYaYl4T1ikEXqNS2VMJ/vguux+Yz1N/3TcwxUpIk+OM/DiNUYW7XJ2msep82h9ODtvtbC6wMR/Hna3m1+3yALpRoGhZpEJaRK/SpdCZcrWOFnrD+t2iBbpRoGvb7Fg0wv8y3exj0965LQUUYDdt6aQ10/q0k7ChSP1rMjXpnlFkxIWDwTT3lPS5U4N+8huJ28ci42aWn+zmTnDdDy218Xy8tifWdFjJ2ZZZIEdMy2MsIq8cdTDMwddEWU0x9skXrrWyNR0OXRiSqR5qT+f8PLtT76oiyNtRefzh+soOq1tW+2JMyt69Miy3L4Sf51sYlxfiZXHPTx3yBWx/8ztK/GbDJlpg2TSTUJY05NfUal1qxyuVyip81NU5Y2pX86xinw4xUyuTeKTSi9ztzp6TFn1+JlxNr3mQ/P6SZQ3Koz5NHGK6e0Rv3OmBYtOYNn3bp462LOFIDG2bLa9wE4sbmZZqZvRfbQie35/KSGNv3Cknm0zLPhUmL3ZznOHe74KF1MC1A7yRU8dcPHIbk2ibp6ewvO5hl45D669Ub+6wMSKfBO1Hu2Ur8+q4nOAa9xPztWJcHpun5DxY6lYohEKL+cZQzs5K5oUCr5sjmsdIuYECBEEbak6gfnDdfz3eCPpJoFDdX7eOubhL4HN0fHA0muM3JOlY6hZZOd5Py8cdvFVtS/ug6BXT0+XBHjxGiP3XqljSMAQ6yq9bK3xcaxJockbu1uz6QXG2yRmDJZ5MFtPukmgvFFheZmbdys8vVZ3TojfD7jYFQTxxlFNunZlw0VbeaFnco3MypB7LFi77AloHfaPC+j/eZk6Mi2aRjjZrHDGqeL0ab8Vc6xRodajcs6lUONUSTcJDDFpv56RaRHpZ9BOwsowC6Ezh3ae97PhjJfNNT4O1ikJ0+CVkD9hEsTkgTJ3DteRlyaFNmEbRUKbv9tSW+fdKnafisuv9esXn/Xx8WkvRxO0xpzQBHSEwkEy6UaBUakSW2t8HGnwc9Z5+T1Kj51MLQig9qA9WnpxvFzO6LnDu1WS6E0Ckvbv7RmQRJKAJAFJJAm4HAhwJM3Qa3CIQGnSDr2GUhFYm7RDr2GtwHv1ALuAiUl7xBW7gfzgIrwg8EIS8TP+gtYq6BSQDywB9iQX5p5ZcAO2XRKw9SmA/wcG81lzqFAbMgAAAABJRU5ErkJggg== +http://www.bol.com/ + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nl/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/nl/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nl/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nl/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/nl/list.txt new file mode 100644 index 0000000000..1c4b14278f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nl/list.txt @@ -0,0 +1,3 @@ +google +wikipedia-nl +bolcom-nl \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nl/wikipedia-nl.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/nl/wikipedia-nl.xml new file mode 100644 index 0000000000..6c53270a65 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nl/wikipedia-nl.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (nl) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://nl.wikipedia.org/wiki/Speciaal:Zoeken + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/gulesider-mobile-NO.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/gulesider-mobile-NO.xml new file mode 100644 index 0000000000..bac0801df6 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/gulesider-mobile-NO.xml @@ -0,0 +1,16 @@ + + + +Gule sider mobil +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGQ0JFNjNCODNBODcxMUU1OTA4RkJFMkNCMTYxQzY3MCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGQ0JFNjNCNzNBODcxMUU1OTA4RkJFMkNCMTYxQzY3MCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Rjg3RjExNzQwNzIwNjgxMThDMTQ5NzZBOENCMzZGNDciIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz46qzHsAAACjUlEQVR42uydzWsTQRiH391N4weRSjH1CyIIpUpvjRfBS/GoCBWRXvRUevIk6t8gKl4F/4CCUANtjwVBW/Ai4kGk1CIopBS3RFNEMUld3ykreN3dzs6WPk/4EViYzOR9dnfCTEK86E1dYgLNlOaG5ryADZqaGc19zbo54MUCqppZCp8bLc2EZsGPz/wGxc+Vgbjmw0bANc0FapI7Fc0DP77ngxsuGQHD1MEZgRFQpg7u8CkBAhAACEAAIAABgAAEAAIQAAhAACAAAYAABIBdSrY7uHL7ozS/dhO3O1ktS+PRaSn5Xqb+e38iuXrnkzTDTvIxDPbJ3OOh3S1g/tVmqnZvl3/JWtiT2rFsO6ZrYVfmF9upx8AtiDkAEIAAQAACAAEIAAQgABCAANg1Asp9Xup2/ZUgc//mNbKMwTbWV0NXGiOy8X0rcbuB/mDHBCw/H5FWO/kYjhwOrAswP1P9rM81az1EkfaS/kx6t/JTnsyEqdpOjVelfvags7EX4grIytPGxnbSEPieCqgV+v0xCSMAAYAABAACEAAIQAAgAAGAAAQUhiDDt6MD3yu8gMKvht69eVQO7Pek/SPZer7ZB7h1fbDwAgq/H7ATfFnvSPitl7id2ZA5dXzf3r4CsmKunKHx99LpRonbmi3J369HmYSzCkhTfEPadgjgUxAgAAGAAAQAAhAACEAAIGCvCoiosVsBnj62l6Qd5US1JGP1Q6nGPnauYl2A/f0AYA5AACAAAYAABAACEAAIQAAgAAGAAAQAAhCAAHAtoEMZ3Ar4QBmcsWUETFMHZ8wZAc80C9Qid8wf29z7NwlPaF5Sk9xoaS5rVv3/DlzUTGpemHsTNbLCquah5oxmyRz4K8AAibe+3Px7Wu8AAAAASUVORK5CYII= + + + + + + +http://m.gulesider.no/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/list.txt new file mode 100644 index 0000000000..77033aeaa7 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/list.txt @@ -0,0 +1,5 @@ +duckduckgo +google +gulesider-mobile-NO +twitter +wikipedia-NN diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/wikipedia-NN.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/wikipedia-NN.xml new file mode 100644 index 0000000000..fc7de5e432 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/nn-NO/wikipedia-NN.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (nn) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://nn.wikipedia.org/wiki/Spesial:Søk + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/or/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/or/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/or/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/or/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/or/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/or/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/or/eBay-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/or/eBay-in.xml new file mode 100644 index 0000000000..8d27d340f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/or/eBay-in.xml @@ -0,0 +1,17 @@ + + + +eBay India +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/or/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/or/list.txt new file mode 100644 index 0000000000..065d0ca721 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/or/list.txt @@ -0,0 +1,7 @@ +amazon-in +bing +eBay-in +google +wikipedia-or +wiktionary-or +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/or/wikipedia-or.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/or/wikipedia-or.xml new file mode 100644 index 0000000000..e8d50ff8aa --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/or/wikipedia-or.xml @@ -0,0 +1,23 @@ + + + +ଉଇକିପିଡ଼ିଆ (or) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://or.wikipedia.org/wiki/ବିଶେଷ:ଖୋଜନ୍ତୁ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/or/wiktionary-or.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/or/wiktionary-or.xml new file mode 100644 index 0000000000..1425b54b47 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/or/wiktionary-or.xml @@ -0,0 +1,17 @@ + + + +Wiktionary (or) +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpGRTdGMTE3NDA3MjA2ODExOTJCMEU1MkZGMDQ2RkQ0QyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNURGRTgzRTMwMzMxMUU1OTlBMUM2MDY0MDI4RjgwMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNURGRTgzRDMwMzMxMUU1OTlBMUM2MDY0MDI4RjgwMSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDA4MDExNzQwNzIwNjgxMTkyQjBFNTJGRjA0NkZENEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RkU3RjExNzQwNzIwNjgxMTkyQjBFNTJGRjA0NkZENEMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6qmdYgAAAHWElEQVR42uxdWU8USxgtYASFEMXtYnBFEESNKy4YV3ADjNG/IDfxxVwT/wE++OCr3sTkGt94IL4gqKAsKi4YlUACRIxGXEBBXBhcQZxbp50uq3p6enoQpoeZ7yQl00sVM9+p/vZBxn4jho8SPpr4cPPhoTGmw+2VbYlX1gpS+aglIYVs1HplLnY+Cd8ZEmLi+D9/8/EPI4Qa6Xy8AgH/8jGX5OEI/orxGodkkoUjGIzx6iOCQ4glERABRACBCCACCEQAEUAgAogAAhFABBCIACKAQAQQAQQigAggjC9cdm88fPhwwHuuXbvGXrx44XN+z549bO7cX2Xnvr4+VllZOWEFtmHDBrZ8+XLLewYGBtiFCxdsr2mrjcIODh06ZDq3sbFR3NPW1jah20nOnDkTUA49PT221xtTFTQ8PGx6/vPnz+L1p0+fJrTK+PbtW8B7BgcHnbEBcXFxEa+zJ02a5IwNkPHhwwd29OhR5na7WUzMrzbH2NhY1tTUFPEEnD17ltXX17OfP39qx/i5atUqduLEiVGvGbQN6O7u9iQkJNjWc9XV1WIuJyni2gw3bdqkyKezs3N8bQB2fVJSEvmQXkyZMoXiAArECEQAEUAgAiI2FzSeWLBgAUtOTtZ8anhY379/Z0+ePAnKC0lPT//lU3s8Wkzy+vVr9u7dO9trpKamspkzZ2rvAfPfvHnD+vv7Q/L5g44DkOuYPn26bV+3pqZGzL13757P9ZMnT3qGhoY8XPDaeP/+vYeTYnv9I0eOiLkYWOv8+fNB+fI8uBLvYXh42LN7927bc3fu3BnaOCBYxMfHi9c8gPO5fuPGDS3Ex30YKSkpbPPmzbbX379/v5iLgbW2bNnCJk+ebGv+4sWLtd+nvwfsfL5RIkcFlZaWsnPnzmmv375963MdHxbnZ82aJc4VFBSwsrKygGtjzsaNG33OL1q0iGVnZ7OWlpaAa/DdrmwSpNWRUo4YAhoaGgLmlkBCcXGxOIcdiacF9sAKeXl5jKtDX++C63GsYYcAPEEyLl68GH1eUF1dnXKckZHBcnJyAs7bt2+f32vbt28POH/OnDkaiTq4/dFUYtQRcP36dTYyMqLs4G3btlnOwROyY8cOv9dzc3MD5qwwf+rUqeL45s2bpmoy4gno6OjwcT3z8/Mt56xcuZJlZmYqxhzqTMf8+fPZsmXLglI/oS6Xhg0B3AVkt27dUs6tX7/eVL/r2LVrl6hHAKdOnWKPHz8Wx7gGb8gfpk2bpqgpVO5qa2ujNxKG9yFj9uzZbO3atZbeiw4ETpj/8OFD5R4rNQbdjwBM9sbMmgqihoA7d+4o9WOABzmm90K9rFu3Thzj6cFT1NjYqNyHe2Qdb6V+qqqqojsX9PLlSx+3EUZSVjPyzk5MTBTHV65cEbv469evipezYsUK0/QFVJgONBRUV1dTMg71VhkQHnJFVu4nBK7HGl1dXaytrU25d+vWrT7z8WQgAtYB4js7O4kAIwHY5bKfDiBxJwu1ubmZPXv2TCTjjGrIzA4UFRUpx5cuXRKF9qgmAMLs6emxtAPYvWlpaeK4pqbGMvJevXo1mzFjxu/w3+VSniAI/vLly4583rAjAK0ud+/eVc7BlZSTeHv37lWEZyTgwYMH7OPHj0q+CK0jOhAbyPEBVI+dlEVUEAAYfXGkJZYuXaq9RvOXbDyfPn3qIzy4pMZzssrC7pebyGB8/XX1RSUBSAfIApHTEkuWLFGaY2Ez4H6areGPAKP+d8L9DGsCoBIePXpkmpaAPZDbA/3pbqMdQNoCke+8efOU+OH58+eOdvSFJQFIyhl3MBJr8Ijk/BBKjrdv3zZdAyqot7dXHKPIA72PJ0ku1CAL++XLFyIgkB1AyuDAgQNszZo14hyE76/uCyN8//59n9xRYWGhci6UuX9/GPea8GgGF7iHC1H5ve3t7VrdVgdqwVZrHD9+XJnPYwVPf3+/OO7r6xuTzxH2NeHRAJ6MMbGGAo2u/1EpMxZxzAyxHFwtXLhQiQeQvkYBxkmEdV+QMSqW0draGrB1hT8xltnNcFA/YU8AUgtmuHr1qt9rOmBcjUGdHPBZEUwEeHc53EQz2M1c+msIADHd3d1EwGh2MNQKckZ24M9NdTL4kuFiYY6KigotG6oX7GGEy8vLlZy/FVCiRKUMETTW0Fsfncj9Tyg3VB7x8fEeLnhtBPPVKOHqxcaKNfDT5XKN6fv7Ezc07J8AwCzXEwzgiv7pGmFlA+B9BPNd2EiHsY497jYAzU7Hjh3TfrH8NVX01KAkGMlAuyM6NXSbhM2YlZUVWhvgDwcPHoz4//ni9OnTAeXgWCrix48fEa9u7NgSsy6OkMQBUEORDjt/jiGYP2dA/4EDRcJEAIEIIAIIRAARQCACiAACEUAEEIgAIoBABBABBCKACCAQAUQAYZwJoAYf5zAIAjpIDo6hAwT8R3JwDJrs0RmBb8R5aIR01HplryGVSAi58FONjwPYKOED31p2k5DGfLi9si2Rd/7/AgwA1G383MiEhakAAAAASUVORK5CYII= + + + + + + + + +https://or.wiktionary.org/wiki/ବିଶେଷ:ଖୋଜନ୍ତୁ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/or/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/or/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/or/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pl/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/pl/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pl/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pl/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/pl/list.txt new file mode 100644 index 0000000000..f6c2e98a62 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pl/list.txt @@ -0,0 +1,5 @@ +bing +duckduckgo +google +twitter +wikipedia-pl diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pl/wikipedia-pl.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/pl/wikipedia-pl.xml new file mode 100644 index 0000000000..eb10ef3ea1 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pl/wikipedia-pl.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (pl) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://pl.wikipedia.org/wiki/Specjalna:Szukaj + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/list.txt new file mode 100644 index 0000000000..543d604025 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/list.txt @@ -0,0 +1,5 @@ +bing +google +twitter +wikipedia-br +yahoo-br diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/wikipedia-br.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/wikipedia-br.xml new file mode 100644 index 0000000000..70ead749f0 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/wikipedia-br.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (pt) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://pt.wikipedia.org/wiki/Especial:Busca + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/yahoo-br.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/yahoo-br.xml new file mode 100644 index 0000000000..fe94c7ac56 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-BR/yahoo-br.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://br.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/list.txt new file mode 100644 index 0000000000..32dcd4bfea --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/list.txt @@ -0,0 +1,2 @@ +google +wikipedia-ptpt diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/wikipedia-ptpt.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/wikipedia-ptpt.xml new file mode 100644 index 0000000000..8896a4257e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/pt-PT/wikipedia-ptpt.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (pt) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://pt.wikipedia.org/wiki/Especial:Pesquisar + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/rm/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/rm/leo_ende_de.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/leo_ende_de.xml new file mode 100644 index 0000000000..29d6917208 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/leo_ende_de.xml @@ -0,0 +1,15 @@ + + + +LEO Eng-Tud +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFMzIyRTc3MEI2Q0IxMUU1QkU5RkY4OTVGNjNGQUYyMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFMzIyRTc2RkI2Q0IxMUU1QkU5RkY4OTVGNjNGQUYyMyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4MDExNzQwNzIwNjgxMTg3MUY5RTZERjU2QUVFQ0EiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7eMFtWAAAeiklEQVR42uxdBXhU1/M98Ww8wd1aHFokWKHBJbgUKBbciluAUoIVKQQr7lIciksIxV2KBShSCg1aKHG3/z13s5vdbBI2yUZ+/zLf977dbJK37925d+bMmZn7jEJCQhAv5uLoL44O4qgZ//MnMZxEiuOSOHaLY1X8zzCKV0ABcRwSx5efxilT5JY4WojjJRXAmX5dHBU+jUumyl1xVKUChog3P38ajyyRoVTAOfGmtiHP+uzJRRz8dSmOe1/AvYd+cHQwR04nS+RwskbePE7o0LEPatXr82n4gfNUQIQhHe5fj8+jjksz+AXEpvh3jb7Og71HnsDIyPg/7ZipgDhDnS048C3q1imPB09CkTuHMUa4WaL856YoUdgYlhZG+O1SFI6di8TRM1EIi4jDqkV90bXvov/0EjCoArasGY7+w9egeCETnN9mDyd7oyT/ruPwIBw4GYmu7Uti1aab/2kFGHT9nz59Rr7OHGWV7OBTShUzSfW5/d4/w93f9+PK2Q34+8/LOr8/d2IF3DqVR/MGRTBxRD388/pBmu/j9rXdaNmoKCqWcULZko7YuWlchinA1JAnu3D1uXytXSXl05bUUwFxcbE4tm82Nm7chGOnfBEVnfC7wvnNUalCHhTInwu+vm9x8MTLhIlw+T227K6ORfNGoE3naam6ByqyY9exCAxO8GG9By+V19LJbV72VoCNtZkM8IJDgZyOCZ9Hxwj/EBoHB1sjvVcAZ+HIUcNw5feAJH//96tIcfiKd74J329lhPo1zPD8VSxu/xGNrn08MfLqBUz39NbL2XOVtes8BqFhcahUxhTtmpjjoDCVV+9EY+Dw5ShUuIzB0ZtBTVCxQg7y9eXbGK3PJy8KReNegVorwEjo4uHj1zrnCA8LgPswF9Su76Ye/GZfm2PdTBuc+cUeL8464upue3RrbSF9TZ2qZhja3RJHVtvh1Xkn7Fxki4s77DF7jBWsFUZYsPIyunUohwA/349e/5plo+TgU5EHVthibB8FTm+2x+jeCkRGAV16jBQQ+1L2dcKTRjWQN7xmho0cIArRjpPzB+TNZYzHxx1hGj/5q7bzx/0/Y/Dk4VXkyV9Ofnbnxl706d0f9wWKolT/wlT6k68qm6Xpev4WK2HEzBAcORMJW2tj9O1eHUNGLUTeAuV1/jY05F+UL1scb99HY8IABTyGWGmYQjEJ+gXi9JUo1HF2wrHTvtlzBVSrXke+PnqWsALCI5Q3EBgUh3f/JtjVr53NECt+HDqwDWJiIrFwVie4NOgmB59Kmj7CSs6+tA6+0k8Y49cltvBaaye+zxQLV15CqTLV0blNaXjtnyO/Vz15xrSSg29vY4RhPRTas1Ss1lXTbIQSjXDu2gfpJ7LlCnj35iGKlqiMogWMcf+II4yFekPD4/BZIz988I+Dq4u5HBDKvhOR6DwySL4vUsAcz18qB6OIGLTNc21RraJB3ZOUJ89jsHRLODbti0CIMDUF8pihpnNB+PmH4OSFf+REmTbcCuP6KuB9IQpnr0VhslgJZvGX8tOaMGlO69fKhYPez7KfAigVyzrhz+cR2DbfFm0bKQPsWw+i5U2rbpAziQop8PUH+ZlKOgint3SKjZyFSQlREJ3i8QuRePhXjFBaLHYssIVzMsr6EBCHp74xqFLOVM5ilfzrFwePn0Oxbk+4XIUUc7HQfhprjYHfWspr7f9DsPz8oZejnBSSN7gRhYY9A4WPMMbbd0HZDwVRvqpWTCjgDwyYHCwiYDtULGWKL8soD01xcjCSBweDMnectXSmSQlR1KwVoVi9KwL/xJsxEzEmDWuZwTgFQLVoYxjmrA6TUXnTOmbSmfN/cjgaYclka/TraIELv0cjh7iOL0qbonRxEzwTSh08RTn43za3EKskwUqXL6m8h8io2OwJQyk1atTApl1/CBwdhya9AzG4i6WcVbmcdN2NrZVSARyU5AY/QJznW2GqTl6OEtDWGIPEuepWN5PoJ6VgjzKwsyXeifNv2qs0OzwszI0wupclxvVTyEHnoSlXbkfh86Im6C5AxMieCq2Vs+tohDSrRkZG2dMHUH6/tB11GvbRme3X9zggf25tJTwWNvmcsLNtG1vA0S7pm6rTNQDXBA6vJwZ9j/AfVpapv/m372MFEorCwVPCfJ2PlCuqxpem0snrsGNRSnOkZcqEuRwkVsX+35R+qm/XCli06nL2VMBDH29Urt5Gvq9ZyVTa6Vf/xKJjMwts+skmVee6djcadboEyMDtzBZ7dSCXLrb2RQxmrgjD0bNRMqZISWKEpVmzMxxTl4RKf0Jp2bAA1m29BCvrHNnTBFnbOKpt9IqpNggTKMhjcahQQOoZ7+2HIySi2rfMVg7+KYHDN/waASOJnIzxeRETdHS10JmxieXNu1hsPhCBF29iUaygMX4YbCXii5T/h6ax+YBACSBUSM3j+z7o2OMng1LoBl8B3oc80abTZNSuYoYTG+zSdS4ilMioONy8HyNNwB9PY4QNN4WZwIXhEcKURMeipLDXB1faqZFKYlktZvC4uaFyIqhEIczYPHcr9OmQtN+hGWraNwAXhYN2cjDG+JFt0G/oCphbWGdvNpSydOnSePrALP0XJ67uzfs4tP0uUPiLWHh4TMK79x8QFByGly9fo3Gj+jLoI70dkwQwue4TjVGzQtGgQQOcPn0aT548wdWrV1GqVHkMmRYiEFBUkt+75JcwOfg5HU3g43Mf343ZnCGDb3AF+Nw8gBPn3krz08nVwiDnXLwpDP4iih42bASmTJkOW1tlIJc7d24c8zqBFi1cJfF29Xa01v+RAuk5PgwuLnWx/4CXeHVBiRIl4OzsjIuXrsifh0yP1mJYVUIERylexBr2joX+N/IBvn9dRYdv3GRg1VTg7YJ5DXNqwk+Kh4eHrv0UcHDuXE+xUoxkpk1Tzl+PFpFvJDznLxS/174WhUIh/m+ezNxxtieWLi0t5Oq7dS8Qr3xvZ38FvH5xF67NmsL3daR0jPMnGG65BoiYyN7eXh5JRsdRUcJXxIkoNVoHzxcskA8VK1ZMOmIXn9vZ2QnFxejmK4RfIR1BX7Bo7rDsrQDyP82b1RMhf4SkBEgZJ+cQ0yJBQgH58+fX+fzw4cOoXLkyXF1dlaRfpHZIfFlM3Bw5c+vS3eHhWL58OcaMGYPAwEA8f5U0tCUbSrp7657fZTImoyRdMJQJjBaudfDwaZiMTncvtpVcukFhrThfYgXECTvXrVs3+Pv7ayAm7ZlsaspB0wV4PXr0wK5du9Q/58mZ9BDQlPL44B+Le7cOoXylVtlvBXw/rgN8HoagRGET7FuqO/i/7I9Aj3HBaiydFsnpEIeQ4EDtCPrxY63Bl3+XKKYqW8IYsTHhiWBtLLy8vLQ+K/95TJLfu/VghAza5KoJC85+JujFs+tieSoT3z+NtZJlJ1pLWARffScFY7dXhMwJpFU+Ez7lzp1bAvMnKPHatWs6f/dNU23UVe4zE9x/8FjA1YRcsY+PjzQ7mtKukS5cJoU+ebEyKdSve0VUrdUl+ylg/cofJIQrK260eV3tKJe8OVlIFSFG3iWtMsJNgdCwKEwYN0D9mUZFtxQqv3VD7Wto38QcFUqawq17B/XfMw7QlFxOJnCppquAZVvDJX1C3n/hikvISEnzyBibKJ1evlzaOmRwM/Vn5ewh/zNrtFW6LpB8UhsxuPMWrMObV49gbV8Sp06fV/+e5NzW+bo5BCplq6c1anS8isKF8qJ+gyZ4+vQvjZVljp0LrdQpUs0YYP465eRpUL8GMlrSrIA8efLJ14hIbXaz29hgGZUykT1jhBUMwdxuX2ArM1TTll3G9bvnpXPkeYsVNMHGOTZwrpD0bRDFnN5sJ+353hMH8N6PJTNWqFo+DhMGKpJM/Jy7HqUm3h49fpLhCkgzF3Tx1Fo0aqHEyN+Lm+FS7jwqSFK3HPwfR1plyAXT7JFcI8XNqgdDy3u/WLFqAiRxx4j+pNcq4QO6Zj8FUFRVEJri1tYCK6fZ4H9ZWFdUr3uA9AOlS1jh/OVHUFg5Zj8FsKqgRaPPcPbKv+rP7hx0kJHk/7qQX2rgFigLylzr58e2vT4itrAw+PekKw4wMTHHXM8lajtPGiLx4NOpqWyqvsJ6Hr/AuCxVAFOVTCDRDB05+QqDe9fIkIg43ZwBI8RWjZWMYaniCYMfHhGHKQINsSTl3uPUBWLMATi395dVCFkpLKOZ667ktbbseYRNK4dkTzLOrWdv+cqECWf80bORqP5NAGavCkNUVEI1gb5C9MLzNO4dKNOB0TFZpwQWFagSN5Nn/CLpl6Tk33d/ikg7OmsUYGqiDGZY+JT3qw9o+12QrNshxl4+zTrZhHuyFyWuynO8tcyIzVoZhvo9AmS5SFbJXHcraV7f+8Vg4pj26s/ZkLLm536oWSUPChetiLIlc+H6xS2Z54RVcuTXH/FN95lan9kJjE0b2rRO2rufBnoEyxyw6nxThlphgIisTbKgq4mVGXUFMmKMw6oIGZ/svSectPbEYA3q8aObULFK28xTQNtmxXH87Fu1+eCy7dHGQg5aeiQiMg4jZ4Vi3e4EUq1CSRMsmGgtc86ZLdOEOZy5UjuBw/LGPt1d8Nz3JbxOPoaFuTFmTR+G1p2mZrwCnj48i+FDeuDkxXeyLn9IN0s54431nKGEeEOnh6DGF6ZyZicnLKgaNiNEOnaVdHZV0hz5cmfecqAvqtDCX82S2tkY457PbTjlKp41cUDtanlw816wLOFbPzt1wde7D7FoMzgIN+5Fy/K/P0+kHOiQ0mYxr6YvYI3p8fV2spkiM4SorFGvQHU9q0xbXjuMEqXrZj4KYusQB18SX5ap+19WqrHgioNPR8260I8Ja0sv7XSQpo3vWabIutOiBUx0VlVGCM/bb1KIVjExQcIiT/esiYRdauTF9bsJFcJsyFj0vbVe/AxrfNbviZAB3LpZNnIFGULYiNF1dDDmjLVC/06WaToHC7KYx2A+YYYGnzX8xxCs3B4ur7mzuF6SwdsORsic26l08EVpWgFeB37SGnwKs19ftPLHr8cj9UIUlNG9FDqDT9az6+ggWZufejhsJMtR6C/GzQ1JslYoJSGby1pUxjGWiWpQdx1TojGu1vVi0rALqG9HS7kKBg4agciIkMxZAW9e+qBOndp49TYK5T83kYW1l29FyYFTyZyx1hjeI/kZWLKJn6Qb2EtctbxpktCTUJOJnnrCubOK2sLCCAqhKwcRUzjYGcuyl6RqRXu6B2P7EeVgsaCXPQoOesQhwWIYJi1U1oCyWnvPz7aykppCs9NzfLB8pa9TwWCuFt4Lmz32bp+Kxi3HZKwCIsKD0KR+SVy7HYiW9cyxea6NOhW52ysSo2eHSPuuEJ/d2GsvIWlSQnqCdC/hJMvNNeXSzWg07x8o04IpCb9jdB8FJg1S6NjqFgMCxaRIWx6aZe9s0FNY6AehC7n4SUCR1q7/VJmg4QNc5OBzVm2db6uVB2Z3y+0DSidJM0AqN1kfED/o388PlY1vmsIM2OFVdrLExTQFUpXfsVbEB5r9aBTZ4bjcLtmumRTjGXFf+5cnDD67a5havfckeS4kJN7pO9dsmbEmaM6UNpg211uanYs7HFKsSCZkLPe5qbq3KqnBK9PMXyZW6NR6trPAjyOsZZJFU7gK+DcsTQwQh39gnIwFqHg2Z3wlgrHklMTGDte+gRJp6SMTByjww3faGbx568IwaYEyvcpapxZi1ZMlZZ8DzQ5X2YINysBs1uTWqP11KxETFEGOXEVha5/PcApg3+6StdflgF7Ybi/hX7pD+7vRsg/rwZ/K2cUBHd/fSjg2izQ1YSQlpLQ7jUjZoXPAl3nYoFd7XSRGc0hzxsFONX80rT0Gj96UfhNEhm/tlhvyPXuoDDH4cslWMMWVXQ7ShnPJ0/kRuXze2E+yqMxKpVdIAh5fZ4cNc2ySjZgXCj+U1OCrzKHPIQfZrmSWytuOi4sz3Aro0q409nv5JtvWk/KF4KOJeaKJ5dvCsGxbuMwpq4RYnMueaIhoyTgdrAMhZqXW/lrUtns/BaYO0y93TUj76m2siMRjZDT+7EUMfB7HqNuWWMLSp08P2DvkFCaokGHJOFUCnnb/0Eo72WT9MaFzZX3QRbGMSRkwSU8HnZLQ5hOCsrsx8Qpgk1/zumbo3d4yzT3E5J3YsKGiMR57O6ar7Ul1voJ5zXD5yi045iyacU64nWsJeJ15IzHw0O4KuRdDUkLEMNEzBF7nde3u0TV2EpvrQ3qxH3iHwPPHzkVpkXAq88UuR0Lh1AgnRdO+yso4ximMV9Iq9CtN+gTK1X1kryfqNByYsSjo8f3fBNRqpW5o0GxgphB2Mnu1WUTEquZnVs2Rq3n5Vrl7CRHU6V/sU1XAy8wYSTB2yDwWkJOdjow1eOMLJigbq/UVxirdxigjePavEX2lRQh96/UIkKZz8thGcJ+yL3O4IG5g9OffyiiTfb0qEo2lfMT0YfEzldQ0O+JVUS6hZOV2/tK+87P9y+xks3RahMpsNyRIKlRCRXdrSYPrI5wgs+L5fF4HOy9Tm9zxfR0rB5+B5KTR9TFh2sHMIeP27/BA977z1PwKZ+AwoQRCPfL1Kii5+AcbGZTp/L9wVoSEFKb32PnIquq0MpNu7sE4fFrpANkOxdWQOI7QFHJU3cdq95Lx/yYNVsjr0QdMMPBjXMC4ZMbE5hj5/c50IzW9FMCUY9feM9G6gbmkgjnjORM1hfzJ6uk2KSZIvhcX7xlfd8lgih3rY/oq9A77teExZNUFgyW+54qqK8BBWREA5nYykp/Fxtf4M4ibtTJUdrwwk8bZv3BjQmaLTp0Iz9zUSAINMzMjcYhX8TN3f1Sa0BjceRidKoxvEAWwFiZ3Ljt5Qx+uOkkoyOqHL1v7qzmZmaOtZBW0PnWgh4QNH+gRIksAVREmtwRgv+/Hth5ILknSa0KwNA0fE/qkk5uUDd+MNabEFxHrPVji8hbO6oK+Q1cbLM/wUQWQgCtdsqAYsGi8vuAkC1q55QuJN6YfF0+ylvvypEa44Yb7vFBpFpj3pXDmsQ5HhfnZHa8v7iftMO6nENx9GCNAQpwECspD+Z5q5eZPzFdw4w41vP49WuYQTlyKEr4tBmxBiI6JkygscRzFa1k+vze69TPsJsN6maB1Swdg6LhfpAkiDUwFcIAu7bTXoQ3ocBduDMcwAfPyfyRfS6fMDva1u3RJNeJ0RqLN45ViqK7L1Jg4rvTKbZUrfZlnT7gNXGrw79FLAawBreVcULYjqWTSYCsdKpjkVMuBgQgSp9ziaYv2jc1TZUrW7GQZecKq0BQqf9WM5PcSyghhYoY1TqMG1cL0ed4Z8h16o6Db1/bApWEPdRxwcIUdGn1lphWANXQLkKiIXS3JBWofE3JCJOp8X8dIu07cfz+eDma70s6FttKWZ7QQLVXv4I9iRfJi6977wgSZZq0CNClpiYfPOKr3AGJ2q258OXe/jpb4+QfD9QlT4fPXh0n8zoiYQRybMhK3RaUkNIuLNoVL2KxvGcti8fc/rgjD7VvXkStvqQxTdKoMaxe3ier3f8ejDpYjuvYPlIPPDnM6ZUMKWUiSZld22cuOGMYA3wwPkgOkj/LI11do6S9fa30bIFfXx4R1P0RI40e2zNDBT/UKYB3k8PFblVFxKVPUrW4qyTPSBezjot1PbWTJWW0q8LapHlaFqT/aZG7CQaEJdGtriRZ1zbSyc0QxB0TgN21pqHSkFCZSGD0zz0v6mVuYEfVw5xRWcuTJaSQVTGFe+twN4MatlzAzV2S9AqKjIzDzh9aYv+yczuYWhGejBI73GGqVas6cG3iPmhUiB+/mPge9/p+MKaseWIWhEjrmOs7K5D0DKO+LUXgdnxIlvGXHDqPeifNDtQKwpOKEVvXNsUiguLFDG8B96v4M9zV6KWDGRFfMWnRG53M2Y9Dk1K2e+jrN5dvCMXKmElWxhie1pouVD8Omh6h3NtGxrWJi1PzSDB5DFFr0ORnRFdvDZUCYUtn7vh3T0KjF6OyhgFIlHPDiTZRMpo/vr5AhOoOcPDnThs25F3MDgZi4mhjMcS+4lEwXByopE8VUIeMHmhlujcZIlTOeVXM0MUltFKgSQmWiKzaPcAdfJldIMauY3G3rxqJVpylZrwBGwjly5pWz/dZ+B4O0nZJNZL61VmVTWcGQEj3NwW09KBCrptsk2VRtSNkjIvNe44MkZ/RNi2LYsMMnwxXw0Sn88vlNGZaTsDLE4NOGc5ax7M97/cdzAyT+mB3buC8iwweDgSMnBKPw3Yf/EqtgZNYrIF+hCnL5J95fU8XB/J3K5DmpC25pM6a3Qi/EpKq4u/sw7Rt+kOfRN8lPf8aKa5qxvkNXYYp746xVAPtjy5W00XooD2cwKxjy1PwgS/MGTw3JsAu0iQ+o0+pvKOyUL9PMD+Pn6cd+stydHfbcsXHukguYN7191gZizpWLqavDaI66jNYOhNjBcicdM/RjM5Kmr1d7yzSfo0FNZdRMCMouF32EyaJTm+wloegx+xg2rvguCxVQrZoITJTYmoEXdz4vUcQCc6a0lftpUuau0cXXTNvRsf2djhofpj3ZvJEaYi+x0Nkz50Bhi1HiKJpQlgUADPS0zK8YfG4OzuBt2LgNuHllp8EVoBcM/eOuF6rUaCeXJsP0z4rZYN/By7IMg0+maNqwKnweBcvaUM30HuvsGTAx0jy12c5gRV1p5ZQmeIZguXDqzJTdPeggyT2VSSWXRVjKXb8SxzVMRX4nzCy3Lbhw5QksFfaZqwBWxxUu6Cj9APfSvHjxDAoUrqTBlO5Grbpusu6HcFEl5G3YL0wnyKTNxe320rllpdx8EI2dRyJlSQtXhibcrdLWX852PuNAUwlkRos38JPVGCMH1sQMzxOZa4JIxbZvUQ6OdsbYuHam1uBLnsW5A5rWy4dthyK0UoOEmNOHW6kZ09Gzk7e/fMgbyxKZONdHmMxJSxMHVzGb+zQHn8KyywJ5jSVMZtXFcY26JqI1l/ho+sGDv7KGDZ3peRDXrl1E3SZJt+tPmDhVLvN567R9AUk6VfUDu0zYwJ1YWMTFm5YlH3rQGqy+rtAqeVRDZpYNgCUa+kmuSV9RZd2USgjElgMJsYdFvAuytVVkjQKsbXMhX8Hkn3jLHqk61XNg/Z5wrVVATsbVxUxta2cn6rOl42P0ySwYK94+hnZIJzfrGyiLokb1ViQZN/ABQdzIldUMDWrqHz0/9Y3Voj/ow9iZya6bLQeVyqhZ0zlrFKCPDBsyQIbxpIE1RbNzccfRCMkFqWTEjyEyC0ZFLZpknWK0reqeYdaNuYfE9Ufc7Yq5AtXuLOx20TdxQ5it6leY7dFGthzxYXFEfCT+OHm4kXf3fvOyrwKatZ2AksUUsjxRtXwZLXPgNIM49luRSGOWak98Ux8zaZXLJo+SzlyNkrX6hIwsKVz7o42Oc20/NEirjlQ+gM0jWK+tb4iO5Ov83hg6bovs9zp56hyqV1YiHoKPVUsmGOy5AalCQakRblbRuPkAOZP6d7LA7mOR6nYl8v7cZpirhNwSzQkDO3Ivj447JrupB80Kd0gPi09JPjvlqMUhkRGt3yNQ1hrRYTp/6YBKFYvhr+dv4HX6tXyIDx/0ltzWCURp7PCsUdlJ/L32M8KYCzn/22qU+6JRhmTHDI4J6QsO7JmPPDnNZMDDwacy+OTU+z5XxHFZBm+cnaraGyZCkht8lh92GBakrjtNXCvElUSzxMEf3KsyXvg+wm/nXmLe0vPYc+gJtq4dKzNhrQYFytWYlCzYEC5t/nh33S5H7pJF4JFRqckMAeW16/fHlWv30bl1CdR2doL3ocXysbV8Yh4d+fHj3ihWKKEyObktzvZ6K581xu2L3TqVkY8P4eoZJMyKKpnCCJxOnzB4zuJTsHMooHUOcvorFg7EldvRchMoFmMlJhQZBdeq4oh6zYZnelxicBOkr3Dn3Zpf1ZN7M9Oms1xcU+j4+kwIRsF85nK74ULFqqlNXKt2AxEcEotcOYyl42zTtDBWrj8NG7s8ydt4Tze4T9kt37OaunMLC8QIJbLCj6vx3Mn1qFSt439HAZRDu6ejk9tsSVXcO+wgnzdJYbU1nWfRAhY46uWNgkWq6PiZHyZNgK2NBVq2aIru/fUrF5TPHO7jLh9ZqCk0XXOXnMuSMchSBUgYKkL71ZvvyOaN4+vthdOOkPsy5MtthpO/HVfPfEMJt9vftnEqTp6+jKfP/fFth68wfur+LHu2PRVAvGieVQrg42ubNSyNq7cCJbJRPnfYGN5eO1D2C1f8P5dgqv1GVl4BmcUj3vfRzrWIpDKqVrTFoQNr/wuDT7nLFUDXvxCfJEssMBVA83NdHBU+jUfmzn6GTTRB5AKaxX/wSTJv8DnmkUYaD0PgShgkDrZ4u3waowwRPviAwcjy+ImP/xNgAAn4CqFRfcuPAAAAAElFTkSuQmCC + + + + + +http://dict.leo.org + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/rm/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/list.txt new file mode 100644 index 0000000000..07dedc32ef --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/list.txt @@ -0,0 +1,7 @@ +bing +duckduckgo +google +leo_ende_de +pledarigrond +wikipedia-rm +yahoo-ch diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/rm/pledarigrond.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/pledarigrond.xml new file mode 100644 index 0000000000..eef1b941be --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/pledarigrond.xml @@ -0,0 +1,11 @@ + + + +Pledari Grond +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2QjU0QkNFNkI2Q0IxMUU1QTYzQUIxQzY5MzE4QzQ4OCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2QjU0QkNFNUI2Q0IxMUU1QTYzQUIxQzY5MzE4QzQ4OCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMTkyQjBDOTk3OUU1NzBCODIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4cMlNGAAAbzElEQVR42uxde8xlV1Vfa5/zfdOZKUOhZfqmQ1Wgj5FiKgJRicQYa6xBRRpfqfhCQ4zAX8T0D2NMNCIa1MQEMcYHGgiKL6ygCL5iUnlIx9JS0sq0nTKU6WPKtJ35vrv3cq/H3mef1z3nft8300fmtne+e88995y9195rrd/6rbX3xV/8X4LjC+DHOhH8bPz7RoDwGiS3TghnHzvwQAIgDBsA7r/i2w8hwnvj343n1wD1V58K8KiHSyt0fx8PXqdfcWeltuMPtx7/eZ09f8pT+N6NCo64unbrUfi3NsLnRwBHZ0W2Y6InlWnxuI5lzrJ30cqw2TlIrCaUpH5WA07DMMi/LGMT80GWPR+9iUcn2qX4xKwBeuJZNdjuo5GjagDLWMUs72+KbgBexaMjJ0V94D+ITgbsrA/eAQccpc1ghjDJlmVPKuMo+1rRD2VvLUIntVsB4awv2OYjyZDne5ItQTL3uF7rKJHYKB6drtUJZ9VghzUCbCh0SGq1RtEuNc5BVcZGa6fUsLSJQ58N+Zvye8ts7KQJSBreudeq1x86nz8fu67Yf5FlbEP8L05x8KR/idQ01d2Gyl+TPJ+AOzAIZSO7g7FMgDsBAsprdK+36vXHzp97XTnesTJ1eqMKoY4CsprsnAN4tiKqKTZgtQnayFQ0I8qkbtn7IgIgG4TTTUekcRmyBhk1PIsHqJnE2JGp2vm68Mh5EAo12BGn0xVkV+il80/H5irMM1+xMCOfUhap3WaCXGfM3I7FANmx07zPuuc9F2JBwuH+ejAnTF2bhjtp/c8+lA0dfu8CdsLm02hzx1BPF6k81ymQUsY1hoT/u3h8HgpCC7GH7DciTAp8pyDitmz0LCe69e8TNIFVE5fo9+puyNy/IM52gsP2+9keSuMOW4H2JKsDFti00I0mZN4+FyK2juYdXwZFhzStS5+MnbsKFC7f+wFEN/Z6qF0847mPvri+I8yTs1ZvbFAJ2yTcjvBAhcdfptnde5UDkz6jjpDR2kjQHwDAeXHEIOLG1bR9Dprr9pWsPzkSBmtI6mw4QwruRwbEw7grKjkrmICtT7c/J5v9GgtglnNDRaQ+YBsiKW09HREQLlfhsZCdsH986NjUd86EALumZaUo3SZJYhl00qiQiUwDSq+c+Wr7dphpYqZmH418j6aOrfL56fLBWJiqodcT8kmxVbAvImGWjyuN3umOA561uH3S9s+D2qUmB1BZ1ySevsH+VUHKBZzmu6sJEzXlyKdQUEBYqXNDSoPCvYsFLtrbxD8BtR983eB0WlezYTgtHYSUkmQZOyqcbfIBg9GqNGr84uV7P2UQaKYT3mocNPGoQ2F3McT7VdnJVYiGNhA8D1CcdeR1goVs42lbE0yYteRUoZ/mrctyFAQchGfbySidLkqjjMSXDrBLMmTpukw7sgnYtASJE9DOgxEEdHBKyosmhB3pY/KjnlDSv55v60oNIJcnmzcYJG0KCG0fASPvn77odLINzkpCUJ0fSeyg6SdJDYKqiAipcqIxwTLoxFLaLh7HYEOKLSjHsuWBqEMP4rmMr58LDhlDgitmh6X0xrFcRCQeTCssT66zUwdGkrNYbbMFDkrTnyA/lvmAkLCnJY+TjZwyPWeCMFuW0J/rhHn2JcYl0CLOPhftv4varlTZgp2uc2L/NRgNQsu44MR5z23fJAMaiuyYgABsnHCa9Tm4LMzNuOnBmSLYOtm13UEmMadx7lMlryuso30nRXrxH9aIECWPG1HYVTweRwVjeMrmKuAMrnNW+9A40XbozhO/boQcshNOUV5IvmBJpDtNxuI2yVxcisunHhfGHn77Cyq47oUBLlxHOLAbYfcaQ8MgXuCOxxma1nD7owR3PYHw0UfioETPvRk7txYNVIBqW/MLsUCSmTtJNl58Domgk61KHQ4DlXFDka7vnPOf39qFAFryCB0IfGzDw0MnHRw+gXBXFMIHH46CsOulQXfmAUORMpV7sQFPwMHpW+msMYh8jat2e7j50gquPx9gj3hWJVXIaZSDJpRr9vHk8/CyfRohvGNBcOsRhD896uGYr/KtXDRPvlY/sUrVYMMwq3xDNH36fW0/3ngb0cOn2vSwl4Bl3k26tHJ3AMr0TiizzW32Ax45GeDDDzp439F472B0SRJWaDQudHxTui8Jhl/E02t4x6UAbzwABZni9O7kGi3ucH2YW6c3e2rh4O+OEPz2A6SOHBfAOsGOwpsQy6KvpYPgmnaWTPP+ml+bwFMqMF3QW6TIf5c9G8aPRoMypDSPEag1MAG0Lg/g/F0OfvrKAL/7DQAXVCB2mgVW9m9BpfnTToWgldyL2Imr9lTwgVcA/NCBHOvKyFAewADH4mS74zjB3Y8B3Pk4ZeHrQGv9Got6dxTOm65A+OArCS5Y41Gv5T4+oqKKtcyp3DifsvzZMKKlTJOc665FDkUiYZ6TXG7NP/+4jTLDPe4A+5V41wO7CXbVKIopcw91cL75AoDf2RM7/1kUwRFCq0hAKAUJatWtMVbnzr32PA+/9nKEc9b0ZMRg9WUIdx8H+IejDj4eBX9ss6FQpC1xFL/7BQDf8vz4vADhheeEKBSXScnL9yD8xtUAN98eHTgPtKl7OZlWARlGx5k5gtIHYJt+p9VZgKEh+MnPmV8xp8fSU4fk4JrdADdEG33j5VFwdSrIC3DFXgfvuIzg3fejgQFtLGKTTfIFINgfLcMtL3V6jezjXPQzAO/5IsHHooNl6IkVwoI7HS90Mn5xDdX+3/pIHZ8BwmEHb78M4Q2XEOxZS97Qwb8/pPcPcUZUEpwpqgkrB0rYDEL2cwMjtFUKZug7QQgplmtEFtxsUTElXW5/iuBd90eTcRvA/U9GxEFKF7BFeNMBghethZbdxAXkOm+e9Zt2x9+MM/SF69hCHF+Is/3NnwH4x0dQzAr/zxEuX5LbsBafjP9DNC08mGzXYRGizUd4yyGE+06ok/yDLwbxS3xDpio5VpD5E3BLeYlQTBzJQAazqwFLG6Wd8OnEiWdj3wYqnEmjykWEEWuMrc0ehwpl0QLbyQg44C3/g3DKAiF2vqwtN1/k5Pwy5cdfX6Da/l2x0W97McHL9yWgpVH8XRFZ/djtAEd4wJCdps+MwiZ6mxhBtcmpEJSTc+LI7zoB8HOHogbehfDeL/PE0XmxEDClWrSI0t90NCmbRDgmzi39DVjkAxpkgT11Cbj8OYXoWSCb7Ajj7JFAMDrYDeFCnEA7MVDx+ENxGn74iPoDJEUtL9nXYU2dTZQoPDb150WT8wOXNWrN/zz2FMDbD6lzrGUSVbDmXba5FCp1njHyDZkMjXM7kDhWig6K2/OVKOX3H0MBA7VX+bhKG+JIV7w4j5Py8YPMaRPcOsgRsvLWwZzAAtszr5uIoAJWBRO0R+xlk3nWYDCeJUWgpM40VNoRnp9sT2/9akNaMQL6ur0+axhfQ8/T6ejj+x+PcPMc8ZdBYWT86rvvVUernVdGcwOxpfbanJCNJvfVW6zCny+qopww3nzTKVYTDXQL6y+1ZDH2DHbOwmKCUDC0VKIgKlKRWChDgDZeh+77QK1q3+6jSkwvGjGWSjaCcu7SFqeY7s4nWEEW0iw+5wXrVW7cQrCDy8t8QjRT33epmjE01PKJaKs/8kgK49Uspu/wwgg+s+ocn/KjVTxhM3A87IyaqLWbmwpFt1K5QyZobkftC14i6UgRLGcMPerXHRYLoPqPhdM7YoK4kNaiFUEZ22CnM4TANS2I036TSTFEm3EWLsVjPxqjmHM7LMHfHDWVNMTiJMNCNkj6XQ6K5HWwqHsqYcQmCBjqekh5MjGQTv0OzaCrySh+SuQKNiXqLs9yaq8FSM6ZcOIZir9DldZk1zYHhPbkgfHiyBL9gQJL0XAyi+vRk4peZFmPqa9kq+Lflz4vzV41KF+KjvNfv0Zi+8lmOAvcVyiDASWP5ZP5nIYxPPinxABVORrXrNmcdF6/okOyjcVysDoL2ti6XGZCNGudWDtmwMF0ELnG4ycEgEExfajML8TOfM9+ygPIPP0XT2jj2ClvOBsEnS3wjfsaofB3Dh3XSYPmX7yYG1TeP2qC9hOFARXfE99XnibhdghoGkA5wQKcI0iVDnMAO5WReTOJAuV8gHbbp/xlt6hlVoAxfN4iwr6KnC4ERAugmBYmMaPgFjoI+3fFAOgyS4REgUXMBPc84ZTMQpIoWqGxEwr58uclfkf1584T6igT7+fMzUpnnWogm7yFkHe6MH2B0zsCiFwM9bDwXVDSTiiQguOZk5Z0VgCQVmBIXVAr/0vYGoxKDAHOKrxyrbxB4cRAhc8NXZBygpwM35Bc7EJg30Uxkn3fQYK9NWXWkE3IHz2gJgUskAvRg7ITvXYtDgPz+0Wi5VPHzbTJykNNPy6iwLjsI/hm1qHleck03E1OLRJTSUKluJyyZa1gbZxTvumgRExKfyQEmVGQL2a+t6/5CR5+aeFVcV1GC+sBJBjbFYdkgyVRebh2vYYbL1Isz+RXysRhNLJ/8aUKHlw0TkgdnpPZeGBvZacagxkFfcdTStyhkHY6MM6oaQ7GOLXIZk5o4HjejecD/PrBefF9ggsHP8HmVJ06C3+zUuZ2zhWoJCKNE5PqaG+pMbBCoTSTlfRCLSZYomZoxVyhIJ3LecVsYlJ/1ikpRoqtv2RfBfvYIKNr+Ro2QQ+cqOBXDuty/sTbs1D5zEVOcac1bQoRy4rkMrungKIyKKz+h7WiJixqnoKYtqpse4biTXHmAlMBQ2xHYmNnmR9sUXFS9FDGAVREaAGaokea4QIIsVdsVD6ueT52PgsZKmptRmgKAeLjtmMO3vkFpSKYItAZLCoTHXHQOh8eSNPSKouAZNKQ4HX5N86ySsSp2F9pkSrRw83GDXodKoSP6WhYaqS2ni1tEGfNkCiYzQxlwt1mGQ7UwzfptqY4K8HEXoPz2ITGrTmrGiODjFHAXz3l4K8Oe/itB1GdNs/6Sge3CpVoBtt9Vv3jG1Y6A1o6wtT01bsRDp1U5652VqmPzVSDg7ZS3VrxqOe8QKMpMgl4+jmlzbn315znOua08XfLhqaUlRkR8z/Yy5bV3IEcBbdmvCuKdEc0oTg3jLJ/yYK6Fh44dgrhoVME9zxewR0Rv//xUcUGBM3uIqjwQ64hIYtX5fnYE+xV67TrhUREL90D8LkntbSwIjAHqSCRI3BmStls8ERntf/kYwgf/4yHNdaseOFadCm2lDbjICgXcfd3LC+0CnNoYTJKpHPYNWUphQ+AYrV8ejcy84nGEo/tx9X/gq3aU0nMAJnpMpNnlQtC99p9U4lkHeW+ydu7uKC4jDUnYsn7Iuy84twmufHy50Vf8LAiLW9BJSOnTIJZgMOBlU81rdExbwbININuJbAWB4ks8m7jpLJOtrWofckKHUXRFo0X3/eFdhTCwfbiB2iItvLZP4ajPmADlSTDlJ4zYiukKjyedwVLqTSLNpi/d0o8lbKpIJyM4vq7T1CGknzn170oCtG7rOatRdFg9C8mgKGUshXFCYnouV4IFbKGTBW4nu0OhXDDgHy6x/o+ttEckmA0NAdTUBYK5m5OPqD8Xr8yzQnTuUibRlGzqMMJ0V7pZ85bglr9kQ9kFQhBGiosaDSXG2ZL//th1N2nJBjzog0H9wUTQtBAKeeR1cYGX3D0iTqRvxwb1MA8J/uLyltE3elRWUU4lQNoM8iN1pTy8tBdJzxAMayaCaPu12ymJeIwBK+0gCVlQj4F1VbyjAxWQija01RFUKYHCP7wKwBPeKWtwWb2Wy938pnQ1QZhkYpQyKXUohJpue9MdQQl3ThLJnmBgIkq6yEfmkjXDlH3gYaF5qBgPYnaAizfjz1DcYPExWCnLCirJhqE7HSCLEHTJC3MVICWD/q0xiftZeeUVv2nByGnOxlJvT4Gdd+5T7NVKcuX7lPyboyaNnnW50V+Xk1bZ2GiFu6ma6gmqgbrjPA4Uz6FLIJ9EMynuJwmw/aIeQvM5qTc+hkfGJ05g7NpQG3Ta7SwQQbRYw5qGCD9yRHVAp1G7Eg93HIVwRWV1lyyGfJONSYkTocsiHJOnPGmjE4lJJ1PRSpERlVryhytoCCk9ETQUhe3mJeSLHZK7KEnR4CD9T7lQKR8b/ksj7fywZ1B8OYAmxRd893yfUIh5aKQModaVmuHoIn+zz4B8JeHUzZjIWHZ5ec6+OWXgaAbjqSVLrc6T/Yn5rXZBwRbp8tmh0m6atGkYZPNMK7W4Gxsq1fNYQDhq3b7y2fZl2DcU7eflI1cNy1E2BupsVxwgnhhJDmR10MN7AHR3SOiHKTmXlZclU0YaULfrnfL/xHc9zWXk3vcnNdftID3XQtwyZpGKE0iPFjAyXCUjCBUck4SNDUph+pRzFyxsEWEz6lNqpyQfImZLttfPnNf0r07W0EkktNlNQnYwk7Z/KTFBR0smo6HIpEzlN5rXZfPDTh4rLxmvq41WnK23OSgmTGyFKW3lS03fTrC1c1SwWv4rgsB3v9KgB88v2kHE3ILi8I9oz+nc9DbzAmGwH7mEoBPvdaiFNtAz7u04j0oKYh6f25n+Uz9y/0sIX06L5lRTklSsaVigGIrlWCh/tjS0K6nX5IcLR0uQj9QgZFNAskqmKQYweoxWRvYBEk5iV33cPQDb/2sh9/7pgp2184oOgdXxODs3a908ObHAvztAw4+cgzhS5skxVUy160GieJ3fvgCgldfAPBt+xH27wpWfGX1n3G4n2R7o7lOMX8VDRdm9YyJmQmCIR+AvFcE5ICmKWMtOQ8aLUQl1zCKY4mJMnrMuedicUNeSThybSFMrWxxAcof6fug9TxOK5g/eryCm24DeE80PQf2pbVgarquPU+fvxTf3PtkgCc3KiOyAfbvAXjRegTAKcuV1xRoYpSPHT5Rw9sOpVRkJRopiTEXbN3XcP9T3zQDSLlf+TUqKwvlhh0ZBmIThgQrRXBdtNNymGUKo6CCuysNsT0/XGkXsQ+myRZQcDJEMlvxv7VoMkKckZJRI03acBdue4rgRz6D8JbLAH7i603EIjVbfBtn/pV74+u9YPXfSUiVlba4vGEhvz920sGf3wfwrsNeinIZ/fpKS90Zti4ShWNFbCXH09Z+alhjolwE2qyUh/YKyVTR3D0+DDNTNXXjsXCwPr7Plwxds2uqQtBZl5w8z6gFCw/TokJb1WhZt/sXAO+8F+CvjyL8wpUAr95fwd5aTVdeB5eRTQL2FWBe+U7w+UcRPvEQwa8+kMajKtCRa3IDA/3LG3FQs4CFiqX15Q4sEjNd929ED57s1srPrw/NJUHU3l9CRLLiAret0OsKwoJSfGl1o9lRFvSLI2p5Q3TIrzqP4OK9CC+JJmfPWmNu74lQ9mQcNC5XfyDK4c+OBji8cELICUgnN7vNOHJsSKb8/qJd8fqv+CTRlzeG1/527feyhHOzoCNAw2tubRv8VdYBN9ULQRbapShTAZIme5LfEbtOTSpT2l3GFxR1y9USI9ROyySFkhhYKLjV9cPlZrgXr0PaurgsTi9vhJNlF7UVrHpIpSzqABkheEMLfROEs4RfToKxQUmfY6VJcoQGZ/Nar2BVFtkgs2BDk/kiK7RV+11LXV5lgZoEcmgZ3dQGbPK8GUTQ8v4FAw9Nts2SUWl9gDpdnR2h4E1oxq5Zm+n8FDNg2iPNcrVD+y0vtSnYc2JpocVQsK1VbsHK1DSAwtYWMZqiZPUUVMcaigsRNsQZz+XpfI01slU5iyAJGa2qAENdzfZr3V2yiPoLNbDnS4vF7/YdKHfO9alMGkvMPm/vyoCqxjn7b8W2mmfdma1llm7CZDR16oPEBsWaMl/knLXItxJzqTmKOrdv02pXqyrCzGCoJS3bpdXywUPt68ZDuTq69OIUtrZKYwFGXoEuv9cUYLOKZcp/dJ8rLXio2E57iQmkhj+ZMXudcr3p2t7a1ZRTatsFD7kg5BwLv7JM1nYeoSPKMmETrGSn2arACmhLoXuYv1BZ0m5CF1R5txGArW21oFu8D9vT7vY5Qh84w/RBP/NWHS3VbwB5SatLFWmWE0h1qGlVJq8ZkJJFrmGqwQrTxgEJURtm5IKvznmemn0KsLMWoy45n8F6xslJUBJ31WoYdsk1y7QddheCUHshIQ2u6m9T2zompqGtArR+daU3GOtb/Riq/OvsKEZ90+1z6Y75g6I2tPX7AdnphgThmter2GeYUaqxxOdO3gtx+7u0rHQdN21nprbVLM172pky3bpumQlqk2U4x4TMFODYHq5zFIy6r3FFJcORxSUIvei/R6jRvGsjDrjO5TVrOr6+sx412cdWXnjgKQ7sDO1tOfeXK7Z9H9z6Fj1E05nA9KMNwTRC6Gg+mmydVWA3dS9zSt/DNExdquE0bbqAcLgqj3DSjAScZ27cFn+8aI6M0oSWtQmoaxTSiNS90cLVG7EtqDZ3780Zx8v9GFb1U1vt69imggkgDO0AXK4VdqFMpyH0ePtuqq37PJPmp5svHhLG1C6L3bzz6TKRfUolmZ+iD9ipjm7R/Lj1my/LEPUmMW2vs1NcFdJyYrE1ONvYmXdsEFKVXZIppggby+3rUxK+hJ252nmbdmh7u1r2cH7/OM66fsOjYeu7rS2IC/Cxyg8IdWFtqywyWIVpk49p9bkozh22l2M/qrPqj+1sOSSb2LGLaP73u30c+2GhofNHBTzBCWHLEfcnUJ0WCyCtDq/ODASdScpt4/tTWxOPvZ517pJ8QGOCtmi/t2ovV73Hdu7ftf2997j8/G1rMPWFTkUwaOuEu+tlsVB3GiXFVuYStogwlm6bOXV/bC+Og6KSPhGQyxz0UOVGeax7XvfztCUoWVjc3Z24ho5jau3y1/us7/xOvylavm0mrfxTgtBzwm1njAPXx4E+D583dO3SEJVrsTObGrCczM1WZWEgO/Wc+GG1M+7XsDehtHob+yio5WSWNG6nLM/UzxyOsYxz2zDnemPCH/uxIMT5MDWVyVfFQJQ/4VinWb4oxsoVHEpYAa9vaW64/oIOogkqArc4+UaOYcsvDEBYHJzIs6BvVdAPmWHGZpVM3WVOG+5C99l8uszBs9kktdYCSH45Fe60NQfFCRNsxOd6GgWfF7a5nMFZpu5nCAydkUFA3DkTmjUBsSXL1hriACfqOMk/HcfoNWQAVVBQroEpfl171ITg6OdzyK6p3WenfpJ8zk+az+JxcmJltcI0AuqviSvMtsPmN9qaKvBU9wqH6jgKH4i3eU1OvlK3RnQe1zJmgHEWF4QT6rzsByQmBDwjaYQwvFIRZ23OOiGfUPo1ym9sm7UP4MX/TOtHT8Kn4icHy8gNiuqtZ6LqP1seWuxWVOc15unQhbvgere5CLzzwg3x2KFWmIz4jPgFjbHdGp8pDnzqIQro2tRHbPeh6JxvYNnXl+91cM4pOBIPXh8//3l09P3xrNfx0GHo/5AbbiHbNMVWPp3IaFlsMacdYz8mmr6vu0JC+kG3/4jy/FA85/fju40LdyH8vwADAHLXOpBXgClQAAAAAElFTkSuQmCC + +http://www.pledarigrond.ch/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/rm/wikipedia-rm.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/wikipedia-rm.xml new file mode 100644 index 0000000000..64377a395b --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/wikipedia-rm.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (rm) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://rm.wikipedia.org/wiki/Spezial:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/rm/yahoo-ch.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/yahoo-ch.xml new file mode 100644 index 0000000000..479089b989 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/rm/yahoo-ch.xml @@ -0,0 +1,21 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + +https://ch.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ro/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ro/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ro/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ro/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ro/list.txt new file mode 100644 index 0000000000..116691e2b6 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ro/list.txt @@ -0,0 +1,3 @@ +google +twitter +wikipedia-ro diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ro/wikipedia-ro.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ro/wikipedia-ro.xml new file mode 100644 index 0000000000..2e1f73079e --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ro/wikipedia-ro.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (ro) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ro.wikipedia.org/wiki/Special:Căutare + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ru/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ru/default.txt new file mode 100644 index 0000000000..daaaf0e061 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ru/default.txt @@ -0,0 +1 @@ +Яндекс \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ru/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ru/list.txt new file mode 100644 index 0000000000..6ce1a87b51 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ru/list.txt @@ -0,0 +1,5 @@ +google:hidden +google-nocodes +twitter +wikipedia-ru +yandex-ru diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ru/wikipedia-ru.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ru/wikipedia-ru.xml new file mode 100644 index 0000000000..4988bdd954 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ru/wikipedia-ru.xml @@ -0,0 +1,23 @@ + + + +Википедия (ru) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ru.wikipedia.org/wiki/Служебная:Поиск + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ru/yandex-ru.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ru/yandex-ru.xml new file mode 100644 index 0000000000..bab34585e4 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ru/yandex-ru.xml @@ -0,0 +1,21 @@ + + + +Яндекс +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAD8GlDQ1BJQ0MgUHJvZmlsZQAAOI2NVd1v21QUP4lvXKQWP6Cxjg4Vi69VU1u5GxqtxgZJk6XpQhq5zdgqpMl1bhpT1za2021Vn/YCbwz4A4CyBx6QeEIaDMT2su0BtElTQRXVJKQ9dNpAaJP2gqpwrq9Tu13GuJGvfznndz7v0TVAx1ea45hJGWDe8l01n5GPn5iWO1YhCc9BJ/RAp6Z7TrpcLgIuxoVH1sNfIcHeNwfa6/9zdVappwMknkJsVz19HvFpgJSpO64PIN5G+fAp30Hc8TziHS4miFhheJbjLMMzHB8POFPqKGKWi6TXtSriJcT9MzH5bAzzHIK1I08t6hq6zHpRdu2aYdJYuk9Q/881bzZa8Xrx6fLmJo/iu4/VXnfH1BB/rmu5ScQvI77m+BkmfxXxvcZcJY14L0DymZp7pML5yTcW61PvIN6JuGr4halQvmjNlCa4bXJ5zj6qhpxrujeKPYMXEd+q00KR5yNAlWZzrF+Ie+uNsdC/MO4tTOZafhbroyXuR3Df08bLiHsQf+ja6gTPWVimZl7l/oUrjl8OcxDWLbNU5D6JRL2gxkDu16fGuC054OMhclsyXTOOFEL+kmMGs4i5kfNuQ62EnBuam8tzP+Q+tSqhz9SuqpZlvR1EfBiOJTSgYMMM7jpYsAEyqJCHDL4dcFFTAwNMlFDUUpQYiadhDmXteeWAw3HEmA2s15k1RmnP4RHuhBybdBOF7MfnICmSQ2SYjIBM3iRvkcMki9IRcnDTthyLz2Ld2fTzPjTQK+Mdg8y5nkZfFO+se9LQr3/09xZr+5GcaSufeAfAww60mAPx+q8u/bAr8rFCLrx7s+vqEkw8qb+p26n11Aruq6m1iJH6PbWGv1VIY25mkNE8PkaQhxfLIF7DZXx80HD/A3l2jLclYs061xNpWCfoB6WHJTjbH0mV35Q/lRXlC+W8cndbl9t2SfhU+Fb4UfhO+F74GWThknBZ+Em4InwjXIyd1ePnY/Psg3pb1TJNu15TMKWMtFt6ScpKL0ivSMXIn9QtDUlj0h7U7N48t3i8eC0GnMC91dX2sTivgloDTgUVeEGHLTizbf5Da9JLhkhh29QOs1luMcScmBXTIIt7xRFxSBxnuJWfuAd1I7jntkyd/pgKaIwVr3MgmDo2q8x6IdB5QH162mcX7ajtnHGN2bov71OU1+U0fqqoXLD0wX5ZM005UHmySz3qLtDqILDvIL+iH6jB9y2x83ok898GOPQX3lk3Itl0A+BrD6D7tUjWh3fis58BXDigN9yF8M5PJH4B8Gr79/F/XRm8m241mw/wvur4BGDj42bzn+Vmc+NL9L8GcMn8F1kAcXgSteGGAAAG7ElEQVR4Ae2de2wURRzHvzN71xaplMcp9CGP+PinRjGiKFETfMYKakCCiIKgQEFbUAmi8RXxgSJqDaCIkBhE5A8hEnzFgAaMBgOxKBWDIBbaAnI8W6X0bnecKdqSdqbhZO92djLzR9n9fWdndj7ffdzN/XYh+LdUVVVl9S4qmERARjOwYkJI7n+a/ffMCTDGGjjbKs522e6auoXFxcVNolUi/sTj8cKcqLMGhPQX67akmQBjlY0Jd0gsFqsl4sjvU1Sw0cJPM/S2zXMTqmvqBpL6o4fL+OXmrba6XU8/AX5ZKqfimp/+rmwPMgKCvTgD6u0NV4Yn/TFxY6YWfvpBq3oQ7KlKtPHMELAGZIazshdrgBJNZgRrQGY4K3uxBijRZEawBmSGs7IXa4ASTWYEa0BmOCt7sQYo0WRGsAZkhrOyF2uAEk1mhEhmuvGpl4a/QL9YC7r+e5Ctv4Ds2g3UN4A0Nf+41GEnrF9vNG3Z0GGdIMRwGFC9B5G5C0BXrAQ53vj/OAmzNCx6G5BIwJk7H86ceSB82cSirwHxg4jeWwr63Q8mcm8Zk54G/HkA0ZK7QbfvaNlRUxf0M4Bf46PD71fCZ9EovJF3wh02FKz/xUD3bgBt/TBH330f0enPhMYv7QyIcHh0y1YpQO/yS5FcVAF2QT+pHsagVgaQr7+Fs3SFlKN3w3VILF8E5ORI9bAGW8/doEfAGCJPzpLuhceP+MTSd4yDLwarjQF0zZegVb9KDUjOexXI7SzVwh7UxgBn8QdSlu7Ng8EGXSnVTAjqYcC+/RDXf1nxJo6VhY2JaWEA/eobEH4PaFtYtzx411/bNmzUuh4GqI7+a64GIlp9UPPdfC0MIJU/SwfGrjA/Wz54A/g3X7Jjl9yAiy6Uxk0KBm4Aqd178ikRCVVWlC+JmhUK3ADU7VUSZbEeSs0UIXADSMPfapadOqk1Q5TADcDx42qUTvC7p945f5TgR9gR5BMn/Bmlxq0EbgDr0kWJhxw+otRMEQI3AHlqA1C7zxTOynEEbgDr10e9c9u2KzVThMANQPeuYEUFUp5k04/SuEnB4A3gNL3LLpEypet4IlUyKdVMCephwNBbpDzJocMQM6UmFz0MKLkJLCtLytmpWCiNmxLUwgB0ORve6LukTEViFl31qVQzIaiHAZxkcka58iyITH0C+L3aBN7txqCNASjMh/volHY7KALkyFFkDR0Fsn2nVA9zUB8DOEX38XJ4AwdIeZI9tYgOvh0i8w0GJeqShmNH2v8YK0WQoWDdPmTdOuJk7r+iS5bfE+5wnpp41QCw/F5AN/5dgjS/ewrOilWIzH6z3ZZikE3H9LuM6WeAQMd/pMm6bSSIj9d9XQ3Q6hLUctjy+0HTutVwS25sCZm6oKcBgjafokh+tBiJipfBzomZyl+f1EQVYW/cPWj6aQPcCWNUVUIdD0fSTeezgP0HpKBZTjbYqXNJ/IE9unmLtK6OwVAYQDZuhrP6cyk/t3Q83Odntmr842p28aDWdc2X9L0HnAIu8tSLp6y1LjKeMe1OndQaCOGS9gZQfuRTfgbIils6DujBH1EKcdHbAPGY6rOzpXgZn8BzyyZKtTAFtTaALlkGuvMPKU/3oQf4N+A8qRamoL4GHKvnUwoVUpasax7cKdwAA4q2BjhvvA1y8JAUsVs2AR1mU0i30jOopwF8Qs6Z/56UGOPfkN3J46VaGINaGhCZNQekUZ4V504rNeqBPe0MIFu3gX74sfRgFtnS7oSxUi2sQe0MiDz9kvR5MQHYfWQyIKYlDCpaGUB4HhBdu16Kl/U8F+6D90m1MAf1McDzoJpyEICTj/HfizuZ9ZoCMS5tDKDLV4Ly67+ssIJeENPSJhY9DGhsROSF15R8k9MfBrKzlXqYBS0McBYsgXhYT1bYeYXwxoyUSUbEgjeAf9t1Xl+ghJmcUQYo0haVG4VICNwAMd9D+LyPrLC+vXnK4giZZEwsWAP4TCdVvCVFEBbpivZVBWk81iLPvQKiyP/3zu8Lb9SwNPauR9OBnQFkUyWcTz5TUnBnTgMcR6mbIgRnwG87W9IJ28L0+AuavBF3tA2f3npuLkSmRLuiaW6RnqmJ7eiZGwjsDDAXaWojswakxsv32tYA35Gm1qA1IDVevte2BviONLUGrQGp8fK9tjXAd6SpNWgNSI2X77WtAb4jTa1Ba0BqvHyvbQ3wHWlqDVLxH8untomt7RcBwZ4SkCq/GrTtpEZAsKcMbFlqm9nafhEQ7OnumrqFYKzSr0ZtO6dJgDMX7JtfsBCPxwtzos4aENL/NDe31c6EAIffmHCHxGKx2uZPQWKhuqZuIL8p8Jf2YKO9MZ8JXfm2zUxPsi0XrAVzUfMf8/fTP37wylMAAAAASUVORK5CYII= + + + + + + + + + + + +https://www.yandex.ru/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sk/azet-sk.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/azet-sk.xml new file mode 100644 index 0000000000..bf83bc2ba5 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/azet-sk.xml @@ -0,0 +1,14 @@ + + + +Azet.sk - firmy +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1MDc5QUNFRkUyMkIxMUU1QjE0QUUxNkJFNEIwNTQwQiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1MDc5QUNFRUUyMkIxMUU1QjE0QUUxNkJFNEIwNTQwQiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RkI3RjExNzQwNzIwNjgxMUI2MEJEOTMwMkE4QTkwQjMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4DIsEHAAAbGElEQVR42uxdeXRcV3n/3TdvVu2yR4slS7Ic2U4cOzZ2TByTxUncQhICJcmhpYVzaDmc/gXtoQcOLYU/+IOlpQcIS+gBSg4F2rRhiwMJTUyClwRiJ97iTbZsSbZ2W7s023u3313emzeylpnRyJGCn8/1LJp5c9+3f7/vu/exeDwOfQRofJTGIzS269fXj8IdCRov0/hfGv+uX4NpBtTR2E1j03U6XZPjMI0HaVwSDBCSfpDGhut0uabHMRpbDW12rhP/2h+C5h816b/3L+ZZcvrH6J844tYkxpPDGIh143KsR/61LLAcNZFGlAYqYRp+9R1O32FsjhPbZIAN9Xy0C+j8HXjnAWC4HRijcxtEmvImMs7bwVbdCyxbqz/PheUu1OW9X5ig+OJ1uOpibW6hdfgIDvbtwemh1xBPTUgCc64+E/aVYGP0dmyJ7kRjybqrGDcj8W0LvJVc39EfACOd6j15Uq4+J1/bYKFS8Jb3gt38ASCyvJBMSAgG8MVM/MnUGJ7vfBL7up8GM4msNtdSrmmk6WCYBkwrjPtWPorbax6A3whMzwSH+FYc/ODjwPEfIuBjsOiEtqa9QxCmz2/Qfz6TIR7dBrbjH4GSFZkaNI9jUTLAMSETyTH8vO1xHBvdDytpS+IzGFq+00Ry5JERkeyUjZ31j+BPGz4AHzOnSKvn+eHvwTz8OGw6pwUt+czDWYe73HnkCIYMxGvvBnZ8BixYUhAmGIvS5kvzwknqf4njRPxU3CJzASnNJKea/Fx/Om0yeJLDIGl+6dLPcKjvt9NxVj10vwp+9An5UhHf1qLPp/k8138nHxSzEOjYA1x4IVP93koMcI6L4+ewv/sZWCTRivDcI/fTM44z+rtN5iJIGU/PrzEw2SUl3mWSkNYUubzzexA0YkjZSNv7bEwifV+6hTO/IEfdrc5NfuQtwwDHZovHU4MHETfGyU/mZiFtktZkzEZ3og0XRk9dJf2YvAx26RUyaTzz/exsI+L0veCV48CVVq0E7K2nAePJEbQOvgZupRmSk2Oj4fMZ6Bw7jSQ52wxHPN4DThGPzfN3fcyg8w22eSIlvrgZwHl6zOV8xWHxFMX6PZKSPC9NgjRdAxPdmLTG1XtaUvl4P/y+PKXWmQ/Nk08OyEjK5Xieh7mgRNd+aqqW2jp+N2ZQX2FGYpR0CfFgyI8J4kjSP8HMzJMn3bnNI3ikufkLEoYuiAYIAqv4OTMAdCTc0LE1n4G4Bl1YyBea9zwsIratI5irbFSeqQnT32elKxUT5qkCBdcArgksjsvjSZy9HMOp/gkMTaTgp2SpsTyIDTURRIsDCPsNzTClDY5DM5kf0XA9xsdP5Gz/vROZzeTlq1liinGLyFbRrMg+z1zALDTxxaSGYyn84vgAfnioD2cGJincs10pEf9XREzsXF2Bv9i8HNsbyyTxbZl8qfNEzBK0lG9Ge+ykcAh5OWJHKBljhbtAOlcgQBlx9W1AWUNBTmkU1OzQY/tQHB/7+Vl8+rlOnLicQEoacp/rDLjhw5UYx09PDuOvn2zF4y93EYOUBijbbEui3VS5FUErIhOrhUjVcz8niQFJezxJ17H6XWChysWTCQviC7PTO5bEp3afwwsdSQl0sRSRX4BZthhcDvFaDKQSGElwfP6FTjy275K2/YIJSmJri1Zhx4oHJQOYuvw3NzYW0h8icjW/E2zljsWTCTs2P05h31d/dwn7LibAEhMQSamgpTAt4tEZtgS9tDPmlpSgr+/twjMnr7iWQzhOQfCt1fci6m+AL1B44ud0RppjwOCIsQoYax4C/BENTywGBmhdfrFtGD8+3AtOqb4AzTibm3FSc4gJScOUWtA1ktA4kLL5lcFqvKP23aQs9uzw8jUwQSL5MloeBK/dkk7A3mwf4Eh/gqR/37lhWCbZbMxN/KvyBTJHx/oT+J8j/fI9n8Fcxm5ctgM3V25HgBx3IR0qy0H6gwHS8NIWQEi/E/kU6DAKIf19FG6e6JuQhMx1bjJy4uqi/uPVHhztHndcnjRFIWLqtppdMBNhoS4oVDWKZ8kmA8LxGmBr3kORT2PB6gAFYoC6jLG4hYvDsfwlQxp+CwOU2X/nlW4ZFcmgSRP7xoqt2By9m3yBoZh1DR2vn34TK7YBLQ8WzPEWzgfouSQoVp9I2nmDBtyJgIgJz5Iz/r8zg24M72SyW6vuQQVq4aNIxChEJSoL0gR9HHGjDOymRwvqeAvHAE3vEGW4ZUFzXpOTiZhF6s5MfPtAl0zmFBOkV0F98Wpsq94lizMiV8BChqVSyrU2r7xDjfmibgvBAEcbKyM+3BANU741/8SaWym83jUms2j3kjWjt5AWNJdtgBny0cTZnOaRTYs3MFiWYCFdOiWF7hBa5Q4fgn7KeCN1YDf/pQcIWmQMcNDM5UUB3NZY6laM8iY+nc4n5N0XxI9e68Xp/gmX00ILiv1l2F79TvgSQYhyL/OEW8JfCNNkEPHEvAyfActOEaGn+CU7gUCJiWARmZigqPOCHmmEmHr0i2FTZEcMXPcIULE639T52uQBlu5SuGd1OW4gHnAzBNOYnykSuUTnqIXvvtLtUXz1/6boHVhXuVVB1SI2FzCHID5JrBmmhKmYmBBk0lQVmaXwyb975L+oBrGiDYiXbEa8fBOFlxsRK12PWPFaxItaSOobye5XgNftAF/73gWVfjmfQnRFcD2/nx8fwD/sbkOMm/DZSRnN5KdZdE6fH6V+jq89tBq71lS4YJ2Q9M7RVjxx5guImcMy6ROdEBGUoSIURZG/HGX+ZagM16Au0oym0nXwG8HZm7VERp6iKC45CR4bIqKMAEVVQGn9wgdahWSAuMgfv96Hzz/fiTEeAEtOQDVW5f4TPhEB+UPY2RDEt9/XguKgz4WtxfFcx49wZGAfoqE61JWsJid9A1ZEmlAejGIpHQXrC/KmSL8+PYhv7u/C4d645A4TVSgbqmshy0hCYkmkCiZ9/LO7GvA322ozGDCeHMWVWA+qIispXAxNG57xmUC8mQSCTb0gtngZoJKwdJjhtAo6c+4ciuPJo/3kTPvQFyfXmoxLVNRxttkcwpdYZhirS2x86+EWrK8uymBC2m/YulLFtLlm08xzBoLz6cWJsWuDvhq5mhq3bVJWsJxH1UjlNJYJ07+yPIhP3FmP7z26Bh++pRQRSmoorZTFcSHdbI5qlSByihyocMgt0QjCps/9XUUiLn+Ty9qyIfMFyVld3HE759x5TjMww/vOb3C45+L8zdaAXGAY0XFGM/bpaChJcfeB9hF89/fd2NM24jbGGlpC+VQrIN7wB8m+2/j4HfV4z/plqAibGRqWAeZpiV1omXV/C6xg1mlOBkyNHsYGY+g+N4CetkFMDE3CHzJRFi1C3dooqpsqVM+MJiLXOatPf//KRBLPtw7iO6/04JQAfgTJKFY3WFrC5ANFQJtrg/jsvU3Y1lCc4egziZGuP3vlJEkZdf9YEh1DMWkKO4cSGBhLIEaqGUvamEjYUihEd4poUQmQowlQ3lBOTK4qCaCqyC9r1k0VQdSTJpuMTdvZwdj8c+NZGeC96NHLE3jtN2fxxt7zGB+Jw0qQY7XUDHymAT9Nvm7Ncmx7YB0a1lfJRMgL2HFP4tY9qqDnJw72oGdCS5TjqE0TdzcW4Qv3N6OBCODkGj4Ppae+nkxaROw4DlwYxaGLozjZNyGZnSIix1ICzbRhSWoZ8oKYftRNPjRHW9sbSxJbMMSk+YfosYoYsb4mTP6nGLeuLMENy8OI+I0MRswj7cnOBLWf6MOeHxxCX9uwi82Inn1l95UPEAmRkHczZGDd2xtw67vXoaqxPEOTZG+zZ7Ineick+vl86xCGkwp7/5PmCL70QDOiJIU2z1T3qQ744nAcL54bxtNvXMbRnnGSbAsp8gPM1O0i5PRd4mpQj7l+hKehfbcBzOsItF+RaUKSGMMl5rWuKoKH1ldSblKJhvJgRlCVj1makQGO6elqHcDub76Cke4Ypedx/SNM9ig7cmC73lwCAvIzodIAtryzBRvubpYmKj1RnqEN4jjQPoyv7euSSdW/PXQD6ssCV0mWV+ovkrT/jJK+Hx/uQ8dgPI3liISKiG4weDopmFpT4DVfUxwam2LDlBlNd2PIfJJp7AhKU+ro+j74tio8vDGKFaWBnN3krAxwiD9ONnT3YwfQeXyQbGZMYZB8LoBORUQKkzGwjGz4lvvXYs3WOkTKQlrqVNXMK93jZJcTlkXO1j8NPJGuO+8+eQXfIGa1DiZd6RbdCtKiZEhzASMVlzHqN7jksE9e68aqAD65swF3ry6b1lflpwGalYeebcWe7x9Gwk64yVG2KKnDLJ9hSoas2lyNzbta0LSxBoGQqS0El9LGZsWGFPGFU/3KSxfxn4d6VTibSqTnwxYMK5s+R9CJjBQiM4giI4V/3tWIvyKNmC5wmTXXmUn6J4ZjaHu9SycLzHWmWUMTmhEpnpKE6jgygLbDPdhw1yrcsnMVVq6vhmHo8zI2rR11iN9Jtv7Tz7ThxfZJKX2GlcwpoSu0Pji/K/MVK4FxbuKfnj0vr+GDW6pyMkTmTJHPGJmfgY5BDenyvMKtNCMoqaIoR4jpqb2XcO71S9I3bNy5GsvrS6eVGIf4PRQ+fnJ3G/Z2kq1PJlT1kuUhtWCZ+Qy/2gHwnM+q8x0SCMsM4Iu/bacENEDmqHzajD27TFiLYmIygaG+8Zwkf7ZcQgybVCFlxxEbSeHg06146ssvoeONXs+KR2+0o2z+v754URKfpeI5Sz3zmE13UZP4Ldmhpx89f2M5mNkMSF4QkkzisBWQUZ2o5hlTrilnKMJKcUpSAvk3x84AsKlFcZbULJFbxCeSmfmCR3KeOjaA/z7cL3GkbHqNrgLzxPkonmd0HYwya+YPyUhGqH3AUOGmsOHifUYSzH2mZEw+TBAaK+b5cvsonj5xJWuNMqeLYuQfAj6SWEtFKgVlgzqCZhgtt1Vj1S21UzAeZSxEYvX4y92yLiBsvp0joyUhKQAoNm3c2VyCLfUlWFUZQlnQp8JZpkJbkRmLlsrW/gnsvTCCYz0TMhkUbZU59TcxyFwh5S/C3vPDeP+mKPwGmzMqMmeCZCOlQVQ1laOXki/pSAulBXrJp1g6VN1cKRnNdTTEPbH/0ycu49xQiqiUzFnLuGFIYrxvQzk+vLUaTRUhlIZmr1eLzo6PTKaw7/yQjLbaBWRlpXISPFn3IFN0ui+F45QYbl5RPGdHnzETKF5RTRKzqVaGkb5C98IwEyXRMGqbKjOY7lzswHhCVtfgIKy5EN/nk+0kn75nJb5MGfXG2mKX+ELiRZXOkmAh9HMuGS8Wa1cX+/Hwhii+9WctWFVmyk7uXMyRzBFIYC4OJ3D+cmzW0sOMDJAxvM4c193WgKLlplrwbBSoI02oquFHOTF4GUVA8BRNmAtRTOJ070R+uDx9/iPbavG321dIEyCILu2zRmdFjUGAcD4G/Zy5sJClqbWprhifuKueNMCS2pQtE8S1CaAmxoJk1hJZ+YFpnbChzUH1qgrsePhmkpQUyHKqVnE2X+lXS5DKlkdkZuzUSxxbKYj1+45RBZ5x292aIJsSJoJhbKkJ4UNbapTEa6IbbO6FGkyfw2kyuHNVGdZURXJuQ5Qrfcihi8w+G3zImDX9puNmSpzu+dBmEheKilhQdi4LRoirMvTwFjIyH9MFG7lmzK0PxFFKDMhES9VjPGXhaPeYilCcTFkXcGYbDvh2OxGunmJxiR3lIS3OHIvIN91aX6xmlivsTPOJJe2rcaasnPCUcp2Ald/+0I3klEN49ZlT6GuPIWgUyTKguwCOZVvTUdUroVHh4uAUCUkXb84OTFLo6CfmJFQKOKf5IzNDny/zW7hlRXFGVJUH0iCn4jcZasoCc9Uup/EDXAN42X3enEsvnSx1w92rJM5/5tWL6G8fwmDvqGoTJCaInCGb3xOXYVk2ghE/KmqKp1Ta1BOxLYRIbER2GQ4Y7oqZ2c0+x0QiiaaqYjRqos3bVGotcCe+QN2Q5twXlw5RBKx86/1rFXo5FEN8PKEqUIlURjF8puxZNtuShJh+AyXaBDkVNOfawn6Gz93XKLNg4SSzkSMmw0gb1SVBNFWGslJ9zGF7xT4S/aPJTEwlm6/nGKyYOU3MUxMtKg/JUbAsWTOvmKTugRsrrznE5nRP2NpxD8eS+O25ITdG4/lwsaAMcApGnqDdlXSWn52dyU5beXbUqcpcdoTO7AFKh7s+CRxyWSA6ORBzlvUv2JF/OzObh6Ob42u+eeYc6dA2c1snNpNz9rx3sHNUAmrPnr4iA/v8YBh+DRiwSA6nVYTztAawaRdps6tIJBg0ErNw7sokEX4ML50dxMn+SfRN6iqIyEPYAkjYUmeAXGGplzHJxAdXB+oSZtDQgxiDEyl0j8bRNZLEpeE4Lg3FcX5Qta2MJSyMUPhlGQEBJOUFff9RaIAXUnDMlLhUsUZtkhKfocmURFHbSKK7hhLoHqNBxO6ix7FYSi7MENGNxIJkxGKqQjs3ZDhtaMLbrKBbUy59BrgLu3V6LULOHgoR20mCj3SNyXG8ZwJdo2qVpuXgGt4+ILH0g3vKL3K1fpIy35Sy8ra30pY/8RV08hYyQd52lIHxFN7oHcfetmE8R06yjaQ8vWOVRHN0Vm5rOlsKqjC8ZE23qYhubYvPRvPcNWHh8oA3wbnKrju6IGGjf3N6EE8dHcCLbUOygiVgX+UMLBXhuITO7AMSRM7Mpr1JFZvRhaqyBZvHus8lzABva76QeLHW4JdvXAb8OvFLxjIW78HZi4JPJfBs5oQDU2BwiX0ZahNXsfWiYLKMhP6YfIBX6V9oHcLnn2/H2VFDddOlYpkyxrI/K5ta9XGIbyiNkSVMnwnbDMilSnc1hBEJFuFXp/SaZc4XhBHmYjM7juSLLupPPnNeLu4wEuMyAsqpLpyhIR5TYhhyML0klRsKcAvbk2iJBnFjNIy3N1bjzuZyvHh2CL86PaxLXbkwfIk7YdG0+7nnLqAvZsAgabRyDEycrXJUVqaIzQShyV+UBTnqSgKoKwvK/s4V5UHU0utoUQBVJX6spPedrdQmknY+NF2aGuA0MsUpLJFFcVGTobg8124I6Q98hrsIpKnUxJaVpdhUV4SW5WGUhUyUBH00DBQHTdnxPN1cHP7NIyBaWgxweoH2kOkRKKTclAQ5FuRlJGqiyMexa005Ht0Ylf38JQEDZeGZL9Xi3n6kGTrasiQ+t/nSi4Ic4RIx/38d7kdcwAF29i0hTMMGoormdCvf3lgqF1pMJXTaIXO3Rcbn2dyUz7PhdGnmAZoDFwbjsh7M5JYDzO1SmPOipeQHsLU2iK+8uxmrl4VdU8I9S4lUjZhlivQsiG7K9iJ3b1En7G3MfbVjBKOizGlnDwKrVfXkREMcf39nvSS+s6rRyGcRF3O0hdNcUtMkb285E5S+MrHBq1jvJcPDXGqwFOHcujKMu5rLMhgzn0M0B4idwPIzQdn/+KLaPf3ScEL21DBb3wsgC8crtp0JWHHZ++lq1HwhEKi2krP9MaRLkguTDxuLSAEwOCmk39S9OVl0QxgqsRKh5IoSpxuiMLGigLYFDJI+Zy7n5UtTA2Ipy7N8NHsOirA/7y3pp0i/Y7r2XRjBiNi1K4fuvKWpAZ4j9042FUaKzmYhsYUIxsQhCjw/eb1P5hRifwvO/kgYEPb7lMSx7CIJWWChfGGMaP+GKuRmdaOImTNx9fyp4wM4JrbPdHeBzDOUWhIM8BCrqtgv94xzFmhn81UfVDPsHzpG5UILx4LxrEwOd7dSdrLffedH8Nj+S7BELsJ5nnVh7slR2NLRgMbKEMXFlq5yZSm5Ij5JTOJ47wS+vu+iK8nMlWy4LerOUK+57qJgLvF/c2YIn3qmDd1jSrPsPPZBdfyFu1sYX+R5gFdANtZEJBI5mhILY5NZmRLuwYGe+EOvbGn82I46ucmG4TRqTZVCz2tBKLHy/olDfXjySD9klVOuypnPtvlcrbFAeiexmTRhUWFBb6srRmXYxNgYz6khUOJAwlkStX9y5Ar2t41g55pySszKcQNlxmK7MwOqidfmCmIQm3kI2Hs/RTv724fRPZJSBXzLmufCb/XlpFWI7uhrfCwr8uPeNRX4/sE+CZzlgoYqJgibbaNjzMITB/vxw4O9MClPEHfsKA35ZJQlNEQ0Yw3rNhUFXas9IMR9DQrSkkISH9M7tSi4my1uBjg7bQktfWTDcvz02ADIKpBpSeV2nzWmSofMtpRzJeInuIHeCRu943bmjSflxq1cb+5hy4DHZt4IxntXj+n0dbaLsWUOIcJZyQC2FJywnqRYYPHnm6ISU7F57gunnZtEyIKKcMjEREPczYOiK2eI1+K+BfLOHtpRe6MdteqGySWycqFeDiEm1z1HAlQcT1jpcHmxM4Ah3YAlFthtWxECC4RVb1WefsXmTvSj7+IB71084L6XQRCmb/pm+nHjMj9uigbpdY5kIuYOUmI4HLPmZNqiCkMdlRebNX1uVyNayuha/BGF5/PcMJZc2eWUIAW4xwIh3NdchH95sFkirM6e2NkIglqqaklgsW8smdaKpcAA7yFMkSDAxmXElEBE23e9YK+ARHfNjXjHDIJ8NT76tnJ86cHV2ERzqCwKqOhId187sNxMQ0IqdDaxce2lkfjS0oB03Kyeb60vwTfe14KH16odt+Q+QXrZkpNAOQyZDa/0/t39no7zxTpg+P2yprCjPoxv0u995r4GuWhbHKKQL+8daaS3w8wcLPO5Y9bofGflPdTU5oAzuYFF2ZbiJC/iSTNlx1+8fxV2ri6Tm/z94WJSgmTuKkTDex9yPoNjTpchuQMt615GEym8oyEitx67g8yNMH/iSBLhxELvhvIAaiMc3ZMBCZNkl52rZO6lc0M4fUsU62vUhrPTgY1ixyyhJ4HFaooym3MTeLVjDM+eGcTv2oYomUq5QFpG061rYtLdcHLLN+1jgibDuuoi3NFUijtWlcqN+Coifhe6cPb0k/smUSTz3OlBtJI05wJ5CwGyiBPvvXk51kbDM+0fNCYYcICebMciPhzcxpm+2B1RRBltV2IStRQ3/ukYjMlFFirJSsoQRyxzLSajHiXiio31hDbdRNJ4IxFcAH9iDwnTs86Az7AFJUfu69YYc4THwCx8e1kw4OP05Ku4frwZx98JBgjzc5DGhuv0uKbHMRFniChIbOvxLv3G9ePaEV/QPOGEoeJumluFStB46Tp9FuzYp2m8VdMc/y/AAGhuCPhqDHheAAAAAElFTkSuQmCC + + + + +http://www.azet.sk/katalog/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sk/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sk/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/list.txt new file mode 100644 index 0000000000..97d5f9dfeb --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/list.txt @@ -0,0 +1,5 @@ +azet-sk +google +slovnik-sk +twitter +wikipedia-sk diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sk/slovnik-sk.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/slovnik-sk.xml new file mode 100644 index 0000000000..a923c7570b --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/slovnik-sk.xml @@ -0,0 +1,15 @@ + + + +Slovnik.sk +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1MDc5QUNGM0UyMkIxMUU1QjE0QUUxNkJFNEIwNTQwQiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1MDc5QUNGMkUyMkIxMUU1QjE0QUUxNkJFNEIwNTQwQiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RkM3RjExNzQwNzIwNjgxMUI2MEJEOTMwMkE4QTkwQjMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6h3RNCAAARi0lEQVR42uxda3Bc9XX//e+9+15Ju3ralmU9/BC2bANWDIEQY4ZAGjupm6SBMm0z6ZB+oPmSmX7qtP3Spu2k03zppKSdSZomk0kmFMKj4AkxhJeNMZjYGFsPG0dvW9KuLGnfj/voOf+7KwsCxiv7riTnnpm/7mpfuvf8zvuc/5UoFAooUZjWD2jdRysKl5ygWVqHaD1MK8VPiBIAvbReoxVweVQVytL6NK23GQCW/Bgtv8uXqlKOVpNSMjsu86tPzPMfsAawXYq4/FgWmmMALJcPy0eKywIXABcAl1wAXABccgFwAXDJBcAFwCUXABcAl1wAXABcqg5pq+lkxVW+z3IBuEZGi8vMFiWGmpaFvCHoCOim+FAwFGFBJZ3m5VHe/3kJjLXywFlRAGiKzfyCDqSLwHRaw2QaGJqzcCEpMJ0CZrMWLft9i8kwgVo/0BQSaA4B0QDQGQFaa4CGgEG/WxIUj2ojopsrA4wV0ZCR0kqMmcsIDM4IvDWhoH8GuDBPK0lSLWxwFMV2WuIjbBFLuMnaQj+MEpPDXqCDgNhQB3Q1CGxvNOmxhYawrQ66vrxALCsACjFSJR1M5hQcmxA4eE7BqUkTybxtOnz0mld9vxmpxF8wULoBMl1ATrelv9YHdDcJ7G038YlWBsaUqBXN3zMAlJIUvzam4pkBgRMXLWTI7PhUm/GixPXrcXKi9IPNVNGwmc3f31VvA7F/C7A2bEqwrN8HANicJIsqfvIO8OQAawAQ8JR8gMNRzGWnbmsFU0cU+LOdAvd1GtKRG9YNDACbgfGEgu8dF3hpyLb/bGaWixiIrG6fx5e3CfzFLQb5DUv6jxsOAGb+dFrBPx9W8PqoJR2kKrDsxKfApilPTP98t8A3bzPIDFoSnBsmE+bYPKcL/OiUiqPE/JoVwvxy4qaRcATJDB4ctPD0oAqB6pycUk0pe5ainKf6THmhK4X5HzxHFpSfn7ZwblaRj28IADjiGZqznS4/Znt7rdptURhjCeV9C9dBajkQiFGid2zckufqtJxo1QLg4DmBWNqS0r8k5jOTJeN5UXJm6FAsc5EZUWBQUsFAyByAQ02rck9aLoNMkq8q6FzasGSCt2oBYObHMgqOX7CWbHZMSoEVkxxjYQbBuX54k0Pw5GeIUcZCYGkJDwzFi2JoPXJ13UjXdMJUfUsCQhDHU6ks5Q0aAaCsbg1gO9ofF5hI2Oq9FOb78rOIjB9EcOoonXABmllAIBiEx+Ml6bQWPGkhl0Zu5jiK8CAd2Y70hs8iVdsNUzCAVwcCw2nSz1w2A1MPQHj8cFIFnDdBdEXj85zlCgQq/GtsTjQjh4bB/0Y0cQLrO7vR3rUZLS1rEa2PwqN5FgAgHSCmZRGLxTA8dB7n+09h9uS7CHbsw6XW+1HUQlCMjweh/G21SgZeoRIYAUdTQ0cBYHvKghfLCLu0ICpDzqLQMDT5BjYFZ3HP5x/Gtu07UFdXR5LvueInk8kUxsbH8OqLz+PUO0+SyRpGvOsBZAOtH6sJDLpXn8VacxiKuuuyhq1KADjBoZRyPm2QXfVUhgAhxjliVMvhTx58AN09O+XThmGgWCxe4WMC4XAI27ZuRfuGdrz55lEcevYpqH2PIr7pq0iRf1AkBuaHMp/ZvS7+MjZ0eqD6wnT++uoNQ5kZum4gnU6Ru6wstWHJ0ykK6ereQczogmXajDc/ToLl53T53kDAj71778VXv/5X2Fgv0Hzmu4hOHYalGBQxKeSkFelj5JJBv47GsefQnj6K7m3bZRPI8bqY41lmqQ0lKtYeCxqFMKPmWiQp2AkQ00SF1UrWFvqJLd3d+NrXH8EvHn8Mp/t+DN/8IHKNvcgHWqCTH9GKOrzZCwhNH0PN3AnsPfBHWLeurfT5VVwLUikGzWTz+NahDA7HG2TFsxIySl0rrs98aauJznr7CavUcKlEQDVNQyKRxK9+eRCvvnxIBgXwhilC8kE1cxDFJMJegbvv24fP7f+CDD+tKmiAowAodBGFbBr/9EIaL8WaCYDKKyxcEMuTGW6PArevs3DrOmBbk0DEZ0JV7RYYg3E1hTN23myeTp48gTOnTmBq8qJ02MFgAK3rN+DmXbvR09MjTadpVqcc6igAggAQ+QS+80Icz0y2w+/1SNNSuRkDcoYt+WEf0BYR2N5kYXODhfW1Am11Fur9BoEgsCgt+NCGDguFqqrIUpyfTmelr9A0FaFwGMFAQJqdajHfcR/AKqz5/GgPZeHR07C80SUBwCEs5xD8SdaGgZiF/mlO7ATqKUxvqRFYG9awMSqwowXoqNNl6durXE7+rJKWMHN5eb0++P0BKe18nvzclaKr1emE+aq1ANb6SM1zF5ANRa8pp2HzxYz1lCScv342B8QzwOkp4BXFglfjRryKTfVAT7OCzeQ3WmtMCVTIK+sMUpP0EhDLTY5HQSaJXVtzHTbofejTt5L6X5+mY7npXq6ulokbK5eywOtjwEtDpuwvt0dUdBH2veQ/tkQNqTHRoK0SRWN5AXC8I8YqzsnM9/7r+3hB34Ncy06oVer3iVK6xb3fbAEIkgY0BAmEBoFPtVnYRU69LUI2XxdV7QNXPQ/w+Xy4a/fN6H/qIEbru6Cr4asujl3T3y6BENTsbhdLeywNTCYtvDUBrK9TcG8nsG8z0Bg0Zdmk2jhUpSFjUmSx/ZZbsWONgob3/peYYsrss1pU9hfskEMeO5JiGp618MOTAt/8pcBz76koWsqSKrYrHgDWAr8/iP1fOIDO4ik0Dv5IRkWc/tudLFQVDNYKZrSfNINSE4zNA/92GPj2EQUXU0I6enEjAWA7Y8pkN27B/gNfRvOlI2g8812EkiMgoYOuKbLFuCxOsBTianR8/pyFf3xVRV9MUG5wgzjhDyZBTMeOHcP/Pf5TXEgCha59SDT0Ihtoke1G1VhaK/F6UbpgD2r93R6TMm7no6SqD2aVM9Ezff14/rmnMDgwCNS1I9WwC8loDzKhTWSa6H2GbTCEVf3wJJHnkFXgH+4x0BBwdkhrWUYTOTRlEObm5nD8rTdx5OUXEYtPo+BrgB5qRa6mC6noLuQDa8hEeWCWzJOwsAgQ506bQ9IsJcUP7RT4xm5T1kCcGtJa1uloBoH5OTc/i7eOvYG+06dxYWIEqUyetMCPoq8ZuYadyNd0oOhtpN8jKHpCC5MPssy9AMr1vQzOHaJBgW/dY2LnWi5T3IAAfFAj0ukMRkeGcH5oCGf7+xCbmkQmnUQxn0Pe3wwzuAbFcBvy4U7kQ20ESJjC2QDlFV7bvFllUK7dZjCmSWL6n+5U8EivDtWhod1lA6BcSli8bagMBB/TqRTi8TjeO/9bTIyPYiYew8z0BGYvzaAIH0wtBNPPJmstcrVbUOCjvxUFb2iRdizdh/B38Lj8hqjAv37GwPpaZxxy1QGQI+jkZC05py/gVayF2f3FdrbsrMvWPjGfQHwmjumpKYyPDmNk+LeYiU0hl00jm8mhqIVhRTaiUNuBbHgjMjWbUPDUyTBXNSo3UQwAl8A5i/72/WSGmp1xxlUDQEimCpy/JHBySsgQlId1o34TbXUCvWRnm0Nkaw3xkSZKlJxxvlBAijQknUrLpsr42CgmL05gfOQ90pBLMDy1EDXrkKq9SYa4mVBXxREV/6UCCQi3iv9+D7Cn3ZCFRWs1AsAXw9LzeL+GJ/stTKYuJ0HMEz5urgf+stfCnW3m72jDh4WyvBgQbqAYlOTlcznMzMwQEBdxdrAPA31nJEB54Ues80HMNd8JxaxME2Qhr2DikdsEHuwxHdk8UhUAuFz8WJ+G/3jTnrNc2JCxaBsSRx0NFHX89Z0m7u4gEAxcdehX1ozykacZkokETr97CsePHsZgTMfI5m9ADzRV5KBJZ5AkR/C1m4t4eLdHavD1Tkucnw0l5o+nFDw9YKuvT/td9WC2cZFsPmfhO68r0tnd02mBgtSrijwWpuMWcae2thZ77t6L3t5P4IknnsDEbAzFYJMMWysKFMhZqUauxKrrXy5xvBbENvTIKDA8Z7cIr1Qk4w16vA/4X14TeKKPbb6y5IFeBoNbjNzr/ey9e9BYF0SxwhkriyRegQ6tkHBsPtTx0UR2qmMJBVczHMSXyBVKDv/+87glR84f6CFNMJceg5tGEYVgK4Wr9OeTlTlh9lteTaA+aMnNe05sIXR2Mo7TerqKdM5Y2JZ6NcTNE2b4o+Qz/v2YilTRLhErFWoDv1+hMPfIhAfjaQ/5osqYxz6Iw2Ru1qjCGSVwfDTRIAlMJ+ckQyvhH5srZuDP37Xwt79W8c6kIhni0WynLneviMsbKsqPZY9Ytd/H45DPDNo7c2RSVsEJWKWaUF1hAg1++qyiOVJ/cnYshRjgQR4hkZOMsSp0Y5y0aV7ITdx/Q/nDvi0q7qIwtaPOvi/Egn8Q5XTaHsGOkx8ZmRX41ZCK58+Z0h9UuhWW602KoaOlOIRITQ8hS6wy9dUGAJsAFWvMcYok6mF5gkuq03A2mikAPzkJPDugYFsLsCYs0BS0GRv1235jPs+lZAVDsxYG4kAyX9oQuIQ9aSZn0MkR9ESTqKutcWxQ11kAKEHSfDVYr00hMD+IQuDWJWkxf4QZzaaFywNHRrh0YUmHbZsc+zY2ObIZBfI5/L6AZt+oYymFa9mdI9PZMncMN+9ei2BNhCIoZzozzrckKRFo39CGjsRLUAupJTfjrUVJXZ0PctCKcwre38tg8MRdSLOfr/XiGprrBCahGrjwBnpDI9jWs51MmHAsDHUcAJ1i8c039eDmtRqaRx6XOxuvdSKiXFCQd1spOV1VuXwbm2thlUFf6E+Mon3mED55+22I1DdB150bWaxKU55Hwz9z3/1Yn30HDed/CtUqyA0SK4uEPCd/NoaW9/4Ht21bj9vv/LTjewSqMxdEvmDT5m4c+OKX0BJ/BY1930cgF4ehKVWdD/poh6vQuQiEk8NoPPMotjZZ2PeHX5SC4/T8aNVuWcYXcgdJVLGg4xeP/RjeU2NIbfwKEpEdKGoeWbNfjgY8Sz3nZ9HpNxA99zO0N/rwlYceQXNTU1Wmpas+lsJ1/ZMnfoOnH/8ZJuIJFJtuwXzTHUhGtsOgWFs1nG+6yw1QPJZOyhdIjaH+4osITr6GTZ0d+OOH/hwdHR1VG1VflrEUXly35+1Cp35zDBnTi0ztZiQbP4lMdAdJZWDBNJWrl0ufhhALQ1+WuFzh9GUmUTf1CgLxEwgYc7jjU3fhD/YfQH00InfRWFXSxuW7ZRnbXXJwZ8+exeFXX8bZgT6ksgXovnrk6neiEL0JuUArit46FDmBW4jRsTAN8b4LsUqvLX7fotcUswhffgb+9Bgx/W14L51GgDL09o4u3HPvfbj11l0LprKqrn+5pyJ43xare39/P9499Q4GB/qRuDSFbDaPnK8ZiHTACLciT2DoHgLDW0PHgLw3RLn0YCpeGU8IMy8Hf5lUIw2tkJGl5GBmBEp2Gsqls/CkJ1BTE8a6ti7s2r0bu3b1IhKJLMvumBUBQLloxxEH7ymenJzE2NgohoeGcHF8CNMTo0gm5qFz012lDEzliYggTG8t8VyVd1HRPRF5VAvzJO0FuT1fpShLGFlaRSjFJHweDWvaOtDetQXdN23Fxo0b5a57lvhqbEdd0QB80EnL6ISYMp9IYGYmjnhsBhNjw5idmUZsegqpVFKWue07RNi78S2LSxDqwvyp1+dFY1Mz6usbsKFrM5roMa8o2XgGu7yhe9mFbyX+Jz3WCF7lxjtTPp8nM8E74AuyCc9zQ7bZsJAiDSkUDfs+El6vNGt8NxUvHZnZ/kCAsubLm/FWwt6wFQ3AlUARi4r6iyOV8nRF+b2LX+ejZa3My1w1d0+/GiZaq/C/Yrr/P8AFwAXAJRcAFwCXXABcAFxyAXABcKnK+SUDkHD5sGyUZAAOuXxYNjrExbgwPYjR8rv8qCrxro8m1gDesXVX6QmXqsd85nmq7ITfZjRoPUFr1uWPYzRX4nFTief4fwEGAHBg1fZNXOIsAAAAAElFTkSuQmCC + + + + + +http://slovnik.azet.sk/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sk/wikipedia-sk.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/wikipedia-sk.xml new file mode 100644 index 0000000000..2877773a9d --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sk/wikipedia-sk.xml @@ -0,0 +1,23 @@ + + + +Wikipédia (sk) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://sk.wikipedia.org/wiki/Špeciálne:Hľadanie + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sl/ceneje.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/ceneje.xml new file mode 100644 index 0000000000..d1ef5e30a2 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/ceneje.xml @@ -0,0 +1,15 @@ + + + +m.Ceneje.si +Mobilni iskalnik Ceneje.si +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABJ9JREFUeNrsnb9rFEEUx9/M7p3BSEyh+AsxhTZRNEEttJGAhVqJoP4FgqWgtb8aGwvtBBFsRZR0ChZiYyGiEfyB2EQEEbS4qBE1tzO+2dsLuejtnLgzs7d+H7zs3eXgbr+ffW/fmx9JTJn9vLl6hA9n2A+yDxPMhTXYJ9nP1Q9/mDYviEz8MT7ch/BeQUwwhCmRXflPIX4QCOMySzsQ378Zzc/ILOfDwthBias/bBRIaBDWAAAAAAAGAAAAAwAAgAEAAMAAAABgAAAAMAAAABgAAAAMAKptse8PTOprKBlYS0KIzKl1pPRB+pxaz2jBD382N0O68aKaAMTwZvq+9Rp9+SGpFscU12oURRHF7JLdPJZSznsbkveL5PEJUtM3qpWCjPjxnttE9eWlTwvRjkskR45WB8C8+LWhvsnNviBIiB8WgoT4YSFIiB8WgoT4YSFIiB8WQuF9gE38WM1S/fOTtOaPYnZT82f1v2An41z761aHlh59dgKz8QZqisHub9h4lgY+TVH09XVJGzHLlT+YvKUlr47nvkdnHsJmR6/Q3ND2/FOUyyjq16GI0o/NcDTqOF+WIrtzAFic5wEgrEnZGpsCgGARwMWANQIIANxFQFaN5QEgRIBTANqSgggpyC0AskQAIQW5s/QGawGgkYJ6EHJwPYm1+0jUlpP+9q7nGa50Fs4CQBXYKFYSgGTho52XO7pyufEYNR8cIpr7bAdgy/EFpqDqrYpg0ReLn2o2vJmisfO9hMCCBQN/9iIJVA6AGN7SdTxKbrCPZPpeAoB1QaHTZeXOiG+4XauXjw+rD0BrbXG3J6RnueJ5c/X3X/DNN3l2unQAYhcA8mto9yP9Rmg984Jz/pHWZ35rQfG54q28AJSfqRZT9/ta3VYqAEopGyHceUMCEFqRgO4OASRJPgAGFEF3dwASSwRIAHAMoJkfATpRVIPu7gA0k2b+B6oEqruNgHwAIgEApwDmbACaAOAUQGxZURANjVA0esrbCbY777RB1J1DJYpLYtMYmtK57QPRShqwXmUz5QWw4t2FdBFrd1vFvtXrVdYxFqVU6gmnQuOmbG4a58g1LuRgLgCzf6zIIY3CB+NM+2++ZBXNxeY9J8PRVYTgaueks/mAKkFwuW3V6YRMFSC43jPsfEasnyH42LDtZUqyHyF0E99sUYoPPEq9iHLa27qg9snkl6jlFl+s3N3x/cXoydb7X14sP4A2BN14TlQL8OcK9HxLRkKbE9cUZY1ZPW3STGPGr6mvpLrs/5IM4Hcou/ojAuZ1KMG8rFh07Pm7/6ED1paVdqW4B1TF0gheuOyFxVf/kH6CREBfGwvevLeX5Lr96eo7/f5uugwGADxDKLI0RQoqsqbfdIziPbf+ajc9IqAo8Vn0aFtr9XVkqqWfM6Q4RSECfFVWS9d3PjertJGCfJbXzzsrph4XApt/5omlakVFAace06yp93d67ncAIPS9AxIAAADAAAAAYAAAADAAAAAYAPx3ABqQIZg1DIBJ6BDMJg2Ac4iCMFe/0V7WD3+Y5gcTgOBd/AmjfXoT5gdTfBhnvw4QzoU3Go9nmtMvAQYANBXJumEWXjoAAAAASUVORK5CYII= + + + + +http://ceneje.si + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sl/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sl/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/list.txt new file mode 100644 index 0000000000..f29ffff33a --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/list.txt @@ -0,0 +1,5 @@ +ceneje +google +odpiralni +twitter +wikipedia-sl diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sl/odpiralni.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/odpiralni.xml new file mode 100644 index 0000000000..094bccaea5 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/odpiralni.xml @@ -0,0 +1,15 @@ + + + +Odpiralni Časi +Odpiralni Časi v Sloveniji +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDozNmQ4NzgxNS1jY2RiLTQyOGMtOTk0MC1jNTg0YzA3OGMxN2IiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NkI2QTREN0EyQTA1MTFFNTg4NzM5RjgxODBENTVDNTYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NkI2QTRENzkyQTA1MTFFNTg4NzM5RjgxODBENTVDNTYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDozNmQ4NzgxNS1jY2RiLTQyOGMtOTk0MC1jNTg0YzA3OGMxN2IiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzZkODc4MTUtY2NkYi00MjhjLTk5NDAtYzU4NGMwNzhjMTdiIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+61WF3wAALH5JREFUeNrEfXmQHFeZ5+9lHd1dVX0faqkl67BkyWAj+TYGjE9s8ADjWXMTMNjm2AFmFsdsxMRubMRG7Pw3A+ZYYGCWw1weYAcM2APGhMPGNsdYsiXZli3Jsq5uqe+ruu6qfPu9l9d7L19Wt8xubCtSXZ2VWZX5nb/vesnOvvABoDMDxpDlHJ8A8D7aLqKtwGgnp53RD6NN/XutP6/2vHP8Fu16/+9/J308ff6r/twV2p6nT7mfzv8nel1HtQF2dvJu8dFj9N+DtO3xPpzJM7xX0d/Rj+0mmfKe7SIZoH2W+bm278E5HMv9vWyV89DmGmzfqdKDK5+/2jW1/ez99N+f0fsTaZTqWZ7LPEjs3RO/UHgSFX4n98QgfA39dSh9PBCX6HixTz3H+J7Y39q56vn+56rfoR6lXod8341em5+l8UI9R3kv+C7/PW6eq36/+TfMewi/S9D6IVZuXJWmQz7OheTzNmrF+bm9Vv9O2r+WH9ux7b7zXK5vtetey7Wv5d6S73c3vfmxNEn4+7khiUlWjrUxMH+KF2AJ+sAshiPFxNaSppGx6B1hm1tyc+Aq35Z0zavdw5/iQdZsmIn2afp1acQo/zDVytBNipuTmhkcx0yt5f5rpmmxp33cvwAG9XuYoprcIiwp+sxcuo6sU4XDXEnwhuug2sqg6mbQbGTQaHjnpIgrmWwTHak6CukGsqmmtNUuXXeDZ1FudqHJmW5lYFo7xdZbzDc3rCq3WBfV/3Ou0zK4T+O8S4QJynLDbsW1kK9RM3kb62PYauVNDkcSuZMIl0+X6HULlWYWJyYKOHWyGytFB8USx9ICx+ISR7XC0WxyuC4PCZpOd6CjsxPdBYa+fobeboauPDC6voEd20sYyFSk9pSbOZRbWakpCEGGKoCrW5Mk62qjxypWqSPNfd8eV5Ikw4BzOK6NeffP7SKp7U6vSAmdXSrgyQPDOH6MYXHBxeRUC8VijSRZENsnNFHRERvT8YDY3BZHi45ruVy+J47p7HIwMlzA4EAvNmwkw7u7ivPGVtDh1FFp5bFC2qHjPqwBOZ0LHdqjQ3bq6Ac48llVftucyBJgmgf/VF8S/R0/R5i03kyJpH0ZUyuDePaZHA48C0xOuphbaErTks0wdHY6yGS8zxEa02q15NZstogprnYjDhOMSSGTThGT0pI74p9gSLXiot7w0ExfXwrDgw5ee3EKu19XxraNC/RZGczXu+m3p4n0aTHArF5/e5Hj/r3rNNLp4+1zyk3BgPdz7jPAxK866tTtts12Jh0XqZ0g/ArZ9mW8dHIUv/9dJ154vonpORecpLeLpLWjw5EX2iAuVGs1IriLlOOQiUnT+x0o5PIk1V3IZrNyv7S3JPH1egO1WpVMVQnlcgWNVlMyy4FgZAcxMiOPr9c5ysQQYb2Emdq5M4MrLm/g8j3T9K0ZLNR7JCMiB98epCX5g9XP9RlwUjAgl/mTI0cLJNdkopCu0LaMoxND+M3DXTh0qIX5hRbyOQf5fEpKdIkIV6vX0UHEzedyWD86ivM2bUJ3by96eroxNDyCwaFBdNF76UxWSr1gtji3RVpRqZQxPzeHuZlZLC4uorRSxMT4BMYnJlBcKUmGpklDCrkuctxpYpiL5WKLGMSw/fwMrr22iasvnSTH3YVF0oi10qPdvbc9r9wQDHjfn8iAOOSLuExmweEY7pjBQrmAB37aj6f3NbG85KKnO0WEdIgIDSwtF6VEryPibt6yBRdffDFGN2zA+rEx9PT1o+mS6WnUUa9W0SAGSRNE+zQT5KSIqGSy6HOy5IxTxKAMEblcLmHqzATOTpzB4UOH8PKxY5iamZEM6S7kkevqJG0Tzr1J5zp4zc40bntHFRdumcJSo5+cdgcxmr8qKV8N0EoGnDgSMCCCh6oXj/6OpxECiGoL4QVw7CE735Uq4tEnN+FXvyQbP9Wkm04hR4SvVGtYXlkhM9BN0nc+9uy5BJdeeQX6hoboM12UiSnVcpmITQ6BOWGeRwvEY6+ZgcZIzcnsdHblkCsUSGs6sbI0j0PPPYd9e/fi8JEjkhkF0qhCPhcyIpd38Pqr03jXHVPkrFuYqQ36ehzct03iTdopUEO5djWXxIQJOnHkvSEDeELgkux6k3k90jlHUp/Hd+7rx/79delUe3rS0sQsFYnwRJA9u3fjDde+CRdfcjnBwhYWZ2dQJzPhXawTQxzRTUSESMwiMMTOFZ+XTmfQO9CPAjHlyJHDeOq3T2Dfvn2YnJ4hs9clt0rFM02bN2fw7ndXsXvXJOZqw6i7aTiGK0WbLNlqWSGpAcclA9LaYa/WGAnnlXUaGOqYxt7nx3D//VlMk9QPDKTJPIAQzpJ0hpddsge3vPWtuPC1F5FDLEmbrUqQjZBJ+814xQMAzMfgOqN0DE9mkHzLQP8AxsfH8fBD/4bf/eH30hwO9PXS9aYwN9+QZultt6Zw+23HUWz2odjIUTzhtiXtWunHynWwVw6/h1BQOoF3a8lKeucI4udSFTI7i/jZw1vx0IMtiWz6BzIkUVVpbrZv3Yp33n47rnnDG8gGr5DDnA1VNAyJQilHjHBxdMUt7/M12GTvhADe9vT0kJAM4qWXXsIDP/4xnjl4kDSWNKW3mxx5EyslF5dfkcXdd47Td6QIKfX5cHW1rGd7WM9KLcGAd/kMYFoka3c49hts8RQFU8LeL+O++7fjt4/VyKamCN04UuqFNN10ww141wc/QDfWgcmJ0zKKDQjKGFsl6NHtv0tRmUAx/eQvOju75N8LZL6EwxXfFSaNw+xrZIKEaRPS75k4hPvFr8HhIQIGBfzqFz/Dz3/+CywsLmGwv08GgXOzDZy/swOf/tQ0Cp1VzNWHRJSxJhiqvx/dGyuRDzh2+A7ukgliCVl+u/xEQYWQ/J6MiCzL+Oo3zse+P9TQP5imgAiE7+exfmQEH/zQh3D161+PqekpVMixCsdok9jE/Irh9aRjJaTzPEnq8VdekRJ85euvlqmICkFZx2FedO8Hax7RI4abzlxNGwiYunHjJpw8dRJf+/JX8OKRoxjq75W+Y3amgXUbMvhPn5nHUO8ypqsjEiEJyMHXlCsQTHcjfRFO+OhLd1AknPITbmuz/MGxgviFdBmdhHS+/PUd2P90jbB6WkrY7MIiLtq1E5++5x5iyBAm6IakeXFY7DJ1+64SKu5Mxc/QuhE8+JOf4of/+1/lnhoFbVfs2Y1PfeYzksEiAEty4DZ/YuJ5AXGHKQZxSMu+8eUv4/GnnpIoKUcBoGDCAN3jPffMYqivSAhpRGZn10ozNSh1Kk3BEq6oobrB2KJ94liRaewkm9+VWsTXvnmBJP7wSIZC/6Yk/jUEKf/L//h7KZWnT7zipQYcppgDBY6xiADMWsCAEtLTKyLM8ePHpekZHhwgKFvAtMD2y0sENdMJzlkntFrGDLYwE0tmbHZqiqDwMj5NTL3j9j8nP1YjX1DC8HAG8zNNfOHzQ1gu5zCYnaV7ZgaddPq5SkJT1zjuMSC5OuUGSVQ1oerBOdZAb2YG3/vxLuz9fZUkn4jfamB+cRk3vPla/O3f/R1KSwuEcKalJDEz5R3LjqpSznSY6aOW8KqaTXQRYzPptCfZIqlHf4tgLCCAnh7xt/CzofgeHqIilTnCzK0QUDhz5gze+4EP4oMfeD/q9aYM4EZI0GbONvClL42iQdQtZIohkY3ksxI/2DeHt3mTh5XQ6F+wfzA7gYce3YXHHyGbTzCTk0MSxL/xumvxqb/5G5LIaYp4l6SzZKGW2SFktC9KYgVSFDAiQEoMyVVMpvzPoWoVYqlnHrM/TkwIHJk7qhFMPY23v/OdkgkijlkpVTBETDhxrI5vfGsbuhyC104dXKMdT/jbDf/2vYJOYJFXkenfwCwFJ0gJcdGk3QPZSex/maDmT4n73SnC9sDsPJmdq67EJ//aI3655CESKNFjFK0yewUwgIcWCJqYg2EmLzxzo+f5WYzpzKgRM+h+SE1xCJ9y+vRp/Nk73kHR8R3EgDIxguKdoTT2/3sNDzx8IdHkjGSqyyOaBfRTGeHyiBHiPceTNDfcItMT7OPhfoL15HSLWK7n8ePv5SXIEFBzem4BF1+4C5/+2/9MwcucJL6Qnjj2tceOgWlgWqWMhSZCJUwAimDU5lerPqj+S0VDsWJMLJDzjheOeWJiHHe8+924+cYbsEDaLZxqd08KjzzYxL4Xz8dgxxmP3BpN4/SN9sMzQa7PJa5wjBt7xDEOmZmu1Bx+9C+bMHW2hT4yPXMLyxgdGZYIpFopS7MjpCZytuoNcsOnwGpWAsLH7TnTmizA2hGfxfIwcaZbkJByfQy6xjYaTandf/nxv8LrXvMazMwvIJdLyTv42Y/zWKEoOUeI0FVoxlf550hpt3BMmCIemB75t0Nqdha/278L+//YILufkhGuyLF/6MMfJmYMSYfrmZ14biapNBfUjTnXHX3wnmkqOJI7SsxyZyTxjhZxQ4m4Vf9jq+2aaKlEjrlWWcFf/fWnMTI0KIM1IYhnx5v46U+2IZ+ej0y2QldX0YJIGwITFJN3HqmKb9G6UisoNgt45OcdFJQwmdtZLq7glptvwlVXX40zp0+Ekm9KeWhfbVLHESeOht/hR67M2jqU1CGnmRqtBq1nNDVfYzGTIUT370vmiCigHBlZh/e9931oimJQrYaevhT2PtXAwZe3oy8z7WMfE7wY/7hEQZHT9TYPt3Lof+dTM3j44W2YPNNCTy9dBGH9Hdu24j+8/32YpgtKMgOMRbCHmfVQ7X65UrLkBjGjfSqqQWIhhOlFcW50PMSQF1PgYvvWRxknEPw9ffoUrr3+eryRIvD5pSLFO4ycNSN/0E1MEea6HjpcHholHtI22OdEXWJK5AA3sr8kffn0Es4sjuGZp1zpdGu1OmHwDG4nRJDJdKBETjeSKot4J3UbcFPSo5JmYLv1FIKOY5lpJiwdF6oZCz6LGzaGKd0LYbxhaKaJqkSpdGFxAe9673vJBw6hWCyhrz+F40ea+OOzF6CfUJHreuVS34r7XRyuArGFBsgD/CPgETzYZI5DSv8knnh0HZYWXFmsWCI7eMXll0rTM0nIQJgeewdevNFMizq1Yo/Z5eDGpM9MH5idjtwCMSOmwrD51kAk/B6N4ZwbaXDv85YWF7F+/Xpcf/0NKFdrEhWlyDz/8TESymYemVQ99KFeDsh7zV2Pzr4J8u2TzwjJHdfruRG/OynKOzmzDS/sJ0YUHFTpi0Qx5Za33SZTzJ591gnFuU5stWnLptZxs6AHYJxzvVnA5atkzrkSTTMN2tqiVe/jXQ1tRekLbi8+MS9Qm5yaxI23vAXbztuERTJFApaOn2zhmf1b0J2e9FMRAX19uvpMEK+deA4jMD2B7Z/EM0+vw/yMK2u4i+R4L7nkEuzcdSEW5mZ9hBG/cJMp6g2ZpsmW97dlLiM3bnfEzNItrTdI6fmYID0RmSlu7dwz70f9zmqlgoG+frzx2jdRnOT6MRRw4A+iG09YBjfUIK4kiAIz6ISwSPHM3I/m0uka5msbcPg5v4BOYXhfT7csI5bKJVu/Wyh5Kvbn3F7AjFICTKtk2ZLhUT4HXseVrRbCIjZFzpe37WaIAwOmpSMC7Y0Yx4zKHCMtmMIb3nQtxkbXy1xRodvBxGmOIye2IpeZD+mp0dgPdB3pFrjiKHzJF00HufQcXj48gplJ3/aT9O/Yvh0X7b4U87MznvQrBQ2ziSlOd6ZJoG4euIbZ1VhA7TmVL13epiyp6KPW02SvFSdn8bklZWHrmyLBrFbQNziEyy69BI1miwQXKBU5ntvbi6yzKDPHrnTCvnuVLoDJ23BcF5GdUk2Q49mqF54toNX0nGI2k8Ull14qC+hJ4T64SUhoJsTaG5ow1aLGBszSjpbci8OteSdTyuPTP0jsX1VBgO7UvWNWlpdw2ZVXoqeQl3mizi6GiZMMC9VRYkg9NDsajT0TFNklN7T/XJ60XB/C1ARDljBumWzd6PAQ9lx2GRYp4tXtuu/sYrn2uAkJLlyz6ywhQ6nkYzRGOGzVjjWumB+VkTzBLHGLQdWjdG7knXRoLGoRm7ZuxXayEKLBrCvHMHMWOHxoA5mhuZDoaszloSAemR21gNCRWsTLh4ZkR3JnB0OVsP95mzejd3AQdfIF1pwwQ0K6l7Ulls3RqSgmnlBrl462pTDUyhvThEHtZAUSsrVRPjsRqYm4INfZhQt2XiDTDmK/6DOaGu+gYKsse1TN4pawPl4k7LoSEnm/vc1BBcePFsi+iSt1Zbvg63bvVgIkaI7JJHQs3WtNnPEEiTKlVS/QSAmJf6U+Z8BVwrtarl//TouNN3A/S2zFV2sWDEtLC9h6/vkY6O1FvSFaWhjGj6dRrA3ASTVDCOr5gzAXFIehoICi7oouMiYDC+FYRE103egoSjINy0KbqNrBKM/CtFqsLrUsVgGzB2PccsN6NtQkjpYE1NAUMwRAj9r1cqvBVG67FvW6FT9AIOX8HRdg08aNqFSr6CDLMT8LTE0NIZsthcQPkp7SCXMFowYXkclWKagYopPJ/hMXxYeNEvHXbxyT7YKmmbD1gqmOxsw2qk7O3k1tohZuwfa2VHKSNtr8iq1IY5QFDACga048uhZSLdog+/p6pdCK3KSw1ksLnUixqqXOHjphV2dAagWnT/RjeVEwA2iSATtv83no6e2n181Yfl/F86okq6VEe/CV1A/EYhCUJwS/th5NM9CCVhNWnauaFIyaw6Lz42hKG7vicYAhftZvGEM65aVnGsSAmclOMunVCCWGPp17DAgdsC8dDISAFrMQ3R0iv5FOOejt6ZUcNnMyKrJJDKASgqrwPFWVE2CmtVuC2X1ArA4c8tlNBgYhfNaFJB7fWBqClWRheaWIbTu2o6e74DUW08/UmSyZ9Iy0+RECcmXqx1EJL/MVfpRWq7IwPhATJ93d3eTV63FcDlhVy7zaOMNYYhYnlDwW1xyeEBMkVcPU8qaa2o5Mn5mpZcnX1ub+gu8TQyKDFJQV8nlphoQPLa9QsNbIgznNEFgEQp8OCK832ZLdL6XktYmCtJhMGV43EnYux5NpPLH8p9+khaDGzDOLTWjq9pclZP7tqQ5umfDhMSSk+ir1XqCkr5mvVrpZ0v2VtCZkrkUDsghaRR2ZjAeEIjSqWfIJLTompZk4JwoQgi930eBpCqW9nvxms0ncLKB/YBAN4q5q2+0NVTyEgPHJQ25UvtgapNcMpJI7pHUm6/4pIG58lkDp7TcSc6aQhZ+jfQfTEJEguhwSyWak9RAxo2RAQzSMtUI6cy0QcxUzQZi/XsmiWnGkF2+SBoiWvK5cl5xM0VWQxboKmIIN41lOHYVELSRoW8QxnStznCigivFOJZwT1xVzyQJEmsGsHRLccL7MUjnjGsLKEPFF76r0mQ6kL63XUpK2CIMwHqEgafX9AExwqUncata9UVBxlFCpDKmULNzYOr+MaNXM6djiAD2EZZaCjM2EeRKWIwkTLY9m0cZmmMy8DzOSaXowydukNXSGqmZE1SpvKiflX58nYCKXVq+LgcJW1DvEeeCEA8ertBK1nLB9nPttesHryPTYZ0CS8z9MU/e49piFnHj1SxD8vM1b8dzBg9i/f78c5JOpIZIUoaluqxVep2om4vkne10ifv3caCjDqultSS85LpvWkFSzoTRmKfQO44AoEeRqTXW6avNYd4EdF/JYTRWWiXSzK0GHs3ppUEi+IP5Lh17A5++9VzZGCdMoPr9cqcrryuXy0gkmhrVKiiOqPccdt5rM49a0iFIrboPoVH55VUgdKipOGFCdMfEL3oiWL0cuj8axGWvTi2OzjfH+f+t6EZxb68hBLmfzlm2S+P/4D/8oWwP7e3u9LGSpJGHy2267DR3EEAGVk+rTccFQCy88FiQGGV572ptbmwyY/1leizxCqyEmalxX7ZrjfkHGaJ2TGTpHQCmPGeJkMTTdos1xmFEo4bEqkdZlrBVXeEJ9gBlBD9dwvvBLQvJfeP45Iv4/oFwuY6CvT74tatJiPvgjH/kw3nLrrVicn9PTHxwWopqzAWaLvGNE6qYZ4pr9V/1AYABahBxr9ZrX8ycXExF+tEH3wox2xbAkGcGiVpMhlXGR7XBl1UbYs2q1KsdKg643NTw3I0cVkjEDVsazkKxtC0lLIf69n/2snIAf6O+TxwniC1R2551/KYkv+nRiSTMWT5rFNcAGZ5npGSxVPqb5lnDAULSsEO6sklkU8xByNRdyB6lMk/Y7MOntBP0q0vy4fobO4ejKezkfkdMQgwlLiwsS32oXYym76tlMbs2ABk4oaT4g0KTNW4j4zx3UiK9K/l13fgQ333IrTp065SM4s3JlL7BzRZLNjo0IlMThpg4Q/C4KQ5O8lvaGrJmItk3XZ4CTaviZUK51SUQoyFV/M8L9DW8Qg7y5qIbNTE4h29mlO9A20E+t7eoDy/77CkIx16QI0M7zBw/gc5/9XIz4zZD4t+CUlHw31toYR2tMK77Euy+gOWZzliCuRUxfzs1/4VDo2yRzLRoY5GyaK1L6oqWRzHuLhc1aYUVMLUcidMQiDe3ZfMf3AUtLi0iTBsRSA8zsvUzG0zaYGsfkAdQ8gHs/9zlUiPn9qs0n53b3XXfiJiK+NDt+gtCsdsXXOIraHrliOtUINz4c7l2wXvuAMt2pIz/xI+IlUZ4UQiMG/tymWDKniTSZddG6qCIgyQAXemeil/9h6MxXZCQstEH0OpZWCG04KU0D1JYSta7LVdhptInbiiuRY/SIf/DAfnxeEJ98j2rzBfHvuusu3PSWt4RmRyeGDVryGK5PFor4rCOzILlQc41ZSPHdue4evPLyMSwXi3LWWLzbP1QmWnKpDVztBPXigHgms15NYWjdAvIFVzplseSLmCYvl1bCDujkMSOj14YnrRqlh+8B2jl44Fl8gYgvOvD6eyPJF/j+bkH8m2+WxFdnfc2gLl7zNTMQ3Fo75tyMkrmlnSZpts2fnSODL66v3qjL7n9RT+kfLlKg6Cg19+jzHNdl/o5oa9QcFPoa6B1oyoKCWG9HMGDq7Bm5Vo+tvYTHImFmxA3x2Vy1HLqFHO7B/c+Q5N8rGwD6JM7nvuS7JPl34kYi/mnF5puFf1sbixppx/2NieeZFZHZG7dgDN95e+r1quwZFYIqVvBKE5wvFMoytRPRGOFrB3qRxhtQcoXndiUSaraYzOyJgGeaHLFYdcQm0QxxoqqpgFhHmsIYQfxn9u2lCPfzck2f/r5eeYz4TqEZH7v7Lkn8U6dOhmZHBwHcyE0hFmmbtenofGZck72725xxi+KfKD+Uy+UwQdI/ceYMukhoBdG7e1voGahIoXa5MW8qNMC7GL/4IrTB9ZeAJJUZGZsnOya6er3lZQ49/4J0MnrZkcXqv7YOY91BRgHJli1biPj78MUvfFG2vYsgSxwjbGhgdq6/6Sbf5kcr11rnOYwatdoYbO2MY/EUha2DT9dYFb1xqEvjiO64Iy++iOnZOXR2dMg09PCGMjryYpk1x0Jn6QM8RXK5olD0X62cwobz5lDoEcuHMenRX375KFaWF+XYvr21BEZwxYwcf3SOHLIeHcXep58m4n9BwjYh+TK9sFKUqOxukvwbBPFVqMmYFUUlJcv0qpitNYVbujC4BlHt6wOpc8we48U9vXLsWJg1Fvi/f2hZ+tHAyriaI2ZeIMa1nsUge8ck53oH62hUIZf5mpyZwYukBb0DA4lj/ma20+yhCS66lyT92OHD+KevftUzO35uZ4kkXxz3sY/e7RH/5EkfajoxUxJvLbENBdqK/vYUth1B6YUa67p5dESeTLNYjuEluqcc0UqUdHsHW9iweQ7VUgpBB7ylK0LZoSdF5fVuOn9GwlExcC0mx/eRxBbIEXOjwJ28Yog9VV3oIQYcPYqZ+Xn09fQoxOf4KBH/uhtu9MyOVrxJrteqUFg1d/qUJbdM5KsAwT7IzdQYwkBvgRD09g9iP5lSMbolQEudGDA4UkWuRwAZx6Ot6m91BjDrViPOjW5aQHdfC7UK0E1cfpE4fOTIEbnYURyaMUPiubURVrycn5nCNde+CRfu2IFxcu5np2c8yf/YR4n4N8RwfiISYbr0M9j6QmFJf/NYSj2xa9tcLs0omwroWa2U5DJocqZYAJcujo3bJskRB5rL/DhA+a36gNhG/zVqTHJwbEtRqpRY4G6KCPWHJ5+UK00F0zHmMsW2DKdZgBcJvmy2A5/45Cfxptdfje1bt+ATn/g43njdDQrOZzHElDRr0N6xcqNj2h6bxNrdLc1d+kyBZ/eH12/A3t//HsfJXIqFAKtlhoHhBtafV0RlJaVLPVQNYKIror2prJcdnLfjLF55qRd1YohoUfx3MkM33noLunt6sVJcjuYEmLmWKNeSWFFdVhSrHSzMz0lf8Kl77iE1rUnsPH7yuFbssFeseExibc43PqBtDwiD03ms9hsNWDLYB75FrkysEPP4Y49R8NVEj8ge03Gbd8zI6DdY8ReutQWVAjGuT59wRD5AvFclNDS4vkpaUEKlJBjQReZiGr/+t19iUDpjntA7iYSnb0SOTfoVsvvzM9Mo0e+Fubmw/JmMouwO3kQn0URkvIaraicz+l3MyFZNTmulVDkpSU52bBN+99jjcmGn/r4eSaOB4SY2XzCDSjkVm+7h/vCLUpL0JzfEFEfLJ3xLb1WvVRxsf+0pCsxcTwso4HiCzNDRo0cwODziOWQWJK70Vg99/orr7PclVeB7Ee2qkE5HIe2GJpx4ZYvr04wqoZmV0GZJ1OZjDL8hxnfzBYLMy/jVL38pk5Yp0mCB/bfumiEf4EoTHtDTlWta+9lQBDRXnHDQ8OD5hMgRi58amaGB0Tqp1TJx1ZFaIKbk//WHP0JXLi/VMEpc2Zt1oZkhszIVlzb9XDfBBPFYqpjF2hWZBeFEnOBJLeraGJK9dX5kZAQP/fQBHDtxAn1igb8iMLS+ga0XTqO8nNLpGfaosvB2vfkAJTGkJonMTfQJ7br0FHr6mygLNSN123fgAH790INyjbWW6L0ICzUsqTYNfS0gvYHXLMjrkTMS0IodAETtntzqbJmxrE2S9unBpkc5ca8jG8Zw6IXn8fAjj6A7n5fIRxyya884nAwFr3VmbdcM6Bzk35wkgptbjTx7Z6GFna+bJNUSlZ80OjIZ/OyBB+QCd8PrRsNCNIM9yWVOw8R7LeOzAsycuFNsvD3i5lpcYlvcNanAzoyhC/N4z1y6KHT3SK38zre+LRcsEYu9looMm3aUMLZ9UZF+fXNtgRgUh2uOKmkn0geWllLY8poZjG0tY2VZdEx3Y35xCV//ylfhkBkSF+a6bqJDTEIkEZFc68QMMx8QFKsxJxT5YxKd1FXKjObcuKYGwZlYomF4aAj3/fP/wpFXjhMQ6fPASW8LF13xCupkKeRQI+JjX2E6IlhHTkVBQfc298cpQ24h9DloNSDzGq+75hiF3mSKViAv4NDhI/jmV74iL0xg+2i9hXhbn8rYdmVDs7rGYgV2FutDiuXrFR/BwCxL5zCj8w0x1GUyeWzjRvyCtP7Rxx/HQG+PpIdQ/NdeOY7Oblf6S2XFTB/5sKg3SF0NAgED1DyFMWsVMsPfX1lh6OpxcfHV4/KLWw0Hg/29eOyJJ/HDH/wAGzZskPBSb2SNI6N4HyiPrw0UriEd76AwE2jm9AqMjjwea0FJGuJOeCyDaBLYvAVPPfEE7hfgw38mQbnoYNtrFrBxB5keshByDRQ3aMTyEm48mMPmEeHF1nIDFKQWZVxvC1Om6uYfU1p0sIFs3c49s6R+IhTPygDtJyQZD/785+SUN0o87yrqFZ/1Ypa4wY316kS2nidX4Jit7KmnjqOab4R+uDJnpjt8HQUJsypqFs8++yy+/vWvS18hHO/KkoN1myq46KrTqJYcKZAh/Vpe5rPVgk5LDoWeRLtAwh0nMEM+igmWb4xFiR6urZAP2HXZBErLWZw62ovuvi45nvm97/9AYuK3vf3tmJiY8DvVHGv0afbu25/QgYTFPGzLX/J4o2YsELS0qzCutZeYq3gFxP/S578gpx8HSOOLiyBEWMel1x3xup8r3sWG9OIsMkWqIw/CCF+m0lHXsY7Eg8mellJ5Uuc4RKlStGDsufYEatXtmDqdpwsiqeAl3Pfd78oOtjve8x65xppY5kuYJQT9QNp6nTxhNRMWDmjYhuTUEM02axxPBOoTMSoj1WWUg/OE9mYyaYyNbcSTZHb+mSRfEr+vV06PiradK248ikyHACfME2Bu0MuFRku5z48HghUXUn/xFxv/e9NhYRcfa9vdqf8065AjOBu2LWBxugeLsxlCQl6x5pkDBzE/PY1r3ny97JcXjxNh8kEMiE0iJvWbRsRy9I47pi+gZGqPLUcUH7YzE23RfgGnC93dcjL0Zz/5Cb59332yJiEKRivLYuWABq68+SgKfU1JfDA9txpPjsT3yY452ZhlUDkWPBiLaam1A/HJlaL39xV0QcNjZVJNihc6utDXncevH30Uf//f/iuq5RK2bt2mJch0+80TUYdZ8rTVd9Ub0BnCjWXvOWzL5kTdFF6lbpR8WI4g9le++EV8//5/kdXAPkI8xSWgU0r+MXQPNDziGyVpbkkt2/YF56VuJw1oOa/q4Sghe0VgJhZvHds+T74hj7kpMaJDcUGhEydOj2PvH/+IHDlp8ZgSYYTEGjsh3lZsotknpOZv1LySuT/Wo6fNgjFri2R8pRVXtrcLk/PiCy/gf37uXux9dr9cnqezo5OI75CJ9cxOoZ8kf5HZ3EvyxJTlR0DQ1J/fvmnNDGj3PYIJ4pGCG7YvkJPuwMyZTtISh9S2CwtLy9j79D6MnzqFnRdeiE2bNqFaq8qOOzDb4w/VITsF66trjDKWPJittIWbps30J0Li5ZL1mzbLVWB+RFD6+7TNzMxSXNNPB6Ql1Bweq+DyG46iI+cS8Y0I2WY+/YtgljHd4D3RFce+/d2reSPNoqfDJhFceTRi7JmMikqls6SmBWD86CBe2rcO9Voa+W4u12BeLBaxbngI1735Otz81luJOf2YnDyLWq1mtBfGJxHNmWH1mPi0PW8zJhVNPook4vDoeiI8x5O/+Q0e+fWvcezESQmp5bNkykz29mzZtYydl52S+Z7qStBLguQH6SB5TVNV2DL02ezb37mKN1KOXcTX+jRDZV8gxbk+oDiXxuF92zB7tkOihY5OLleUqhDBt5AWXHPNNXjT9dfL5wuI9XaWaYsK8HGEEzIIMFY3sQVSzDJM4Z2ZL+TR2z9E6K0kq3tP/Pa3OHz0Zalffb0F2UZepYg219PABXvOYP3WJcL5npY7bBVzsNpzrZVjMk2612/d52vAOf60e2xH4KjzPUzOaBx7fj3Gj/TRTaXRmRedwi0sLq9I9R8jpCHWoNt92aXYtuMCWfAXy0GKQo3rcku+yLasTbzvX1vslY4RTVO9A94jsk6dOI4Dz+zDM3v34cSp0xJe9pOTFfn8MgVUYkBldHMJ23cflw8ELS15kNFhq9PEVnNIolO6Qdf4zW9dzesZlsysVZ4S1+7h5dIkkXPu6gaWZlM4+eJmTE90odVIESNcuaCd0AgxUS5WmhLPEzt/xw5sp+38nTvl82HEjxj/r1Wrck7MdV29CqcInShzithEjLGKB8N1EZR0WIYkuorxkyfx0guH5CNPXjpyBPMLizJg7C7kZIwi6rgCt/eN1LB55yTWnVeUEl8r83N7rhHW/uzibINM0De+9eo04Fw0RWy5bgepDMfsRB7jL49ifqpTqnq2g8s2SOGQi+WKlFDRI7Rxwxj6+/uwfsMGYsp2DA4Ne+Oy2YwcFBEPhZArtIsYRjzks9mSkyliMEL05y8SgU8QsUWBX/RqinbBmbk5Kcm5zk50dYqx25RsNhAX2DtUx+iWeYppZmVQVV7m56z55/qTaXKvKO+aayi70XjXag8wtg7E+TGCqj3lopdq7h8tYWD9McydyWHq1DosTJOzE2rPOtHfnaXv5dIkiPaXBhFWTOj0UEyRJ4jY0dEhxz+7yEyJQWixhLD4ejGiKpy8mCWo1+ryfBGJi0UGRZeyMC0iedYvW2mYLBWKpGKms4WBdQ2MbJqlbUH6KUF4uUhJIL1OfBDPLEMkPehZTUPYaOevFWFfgELtu1ptBfQk1bQ9+Lm05I3v949WiBHHUVxwMDO+DsX5Ar3OoF5JyWd15bs65GSJ+KAGSfbc/II0Py1/lZFYVU10sKYc/wGfjv/Qzhy9LsjclXSs5Egd0rbu/jpFsVUMbZim6/BWvK2sgN7naiYmRoekxGnbBz2vQrs0T8jIcqbg6XaAgxndxvFSsIHNPY0rLXmPc+rocrHt4rMyr75IAVxxqZ/e6yJmiO7ilNzvtjrlohfptL5aoW09IR40GDQhVzYXE4qCkd0DJQqgagSJl8nOL5MPYmjVSROKrpR4hxnm3HiyR6LZMRKVGh2S6MMVH6mmFRCvZ0S71N4Wc9ETFjEtaJCIwVOL+sphkAqXXXfieVw9QzUMjE1JiS0tiv051KtpYkiBpLOTbHvKT+uKAErPsArTJYYLhckQKKujq0YwsoyuQp18RgX53haZHI8xtTJB5Hl9tfS1P6bc7l1jj2IJs5zJNHT9bGhdPFe+zfoTbbO+sWNtHn8NdQ9xMRUyAcxHHekOUYMuy2QfY4RI6CpbDR4ufioZ4AbS5xFfBEjiceci8Zrt8MRAlAdbTbHGv+hxco3nBaxWhlkNYZzbexbTtJKmG3+G3rj6VX/R/wPUJL6vSQRv1pUvZ96aENIEiWbhNDcW12NhkrBR5V5+Hufgs/4//BDtnxcm6H7BgKQgGKsEx+1K3nyNeSXWpmTOlVxLy+XtukLXnA9LClZZgsK3+45EzK+mbpLTO/eLroiv0XbA7MjTMqc8Dp+s9QIzBbuaNtlMFo9/Lm9j+tR2yoTnqCWuWZdkhmLoDUZ6fjVrzKGjKW55n+Mg/fqaU0+xGgnWbbRjv6s4DDfhIXpcaakIyplhp5fSfuEmPR9OKfaHMI9HDXBaIwCPujRU5KD219i+G2ofpnqMqx9r3oOrLGCuXo96TtK9mw8igXFtxj0eoH1vaxDt07kqBTFpZ4IYdhW9/x/psA/S6wvpd36tPsjeS5YcwSe9Z3ta8WpPreYJv9tdX9L38ASTyhK+F2v4HGW/WO//Rdq+R39/lf6ui2Tc/xFgAOJvtb2CZnneAAAAAElFTkSuQmCC +http://www.odpiralnicasi.com/opensearch/description.xml + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sl/wikipedia-sl.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/wikipedia-sl.xml new file mode 100644 index 0000000000..6fbbdd4ebb --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sl/wikipedia-sl.xml @@ -0,0 +1,23 @@ + + + +Wikipedija (sl) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://sl.wikipedia.org/wiki/Posebno:Iskanje + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sq/amazon-en-GB.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sq/amazon-en-GB.xml new file mode 100644 index 0000000000..3a3fbabb19 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sq/amazon-en-GB.xml @@ -0,0 +1,16 @@ + + + +Amazon.co.uk +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + + +https://www.amazon.co.uk/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sq/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sq/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sq/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sq/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sq/list.txt new file mode 100644 index 0000000000..56a92fd0b0 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sq/list.txt @@ -0,0 +1,6 @@ +amazon-en-GB +bing +google +twitter +wikipedia-sq +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sq/wikipedia-sq.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sq/wikipedia-sq.xml new file mode 100644 index 0000000000..b0d228cc15 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sq/wikipedia-sq.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (sq) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://sq.wikipedia.org/wiki/Speciale:Kërkim + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sr/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sr/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sr/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sr/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sr/list.txt new file mode 100644 index 0000000000..53ad1108e0 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sr/list.txt @@ -0,0 +1,6 @@ +bing +duckduckgo +google +twitter +wikipedia-sr +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sr/wikipedia-sr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sr/wikipedia-sr.xml new file mode 100644 index 0000000000..f6fd5f22e2 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sr/wikipedia-sr.xml @@ -0,0 +1,23 @@ + + + +Википедија (sr) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://sr.wikipedia.org/wiki/Посебно:Претражи + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/list.txt new file mode 100644 index 0000000000..eb0a30f8dd --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/list.txt @@ -0,0 +1,4 @@ +google +prisjakt-sv-SE +twitter +wikipedia-sv-SE diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/prisjakt-sv-SE.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/prisjakt-sv-SE.xml new file mode 100644 index 0000000000..06f5e65312 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/prisjakt-sv-SE.xml @@ -0,0 +1,12 @@ + + + +Prisjakt +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABHNCSVQICAgIfAhkiAAAAGJ6VFh0UmF3IHByb2ZpbGUgdHlwZSBBUFAxAAB4nFXIsQ2AMAwAwd5TeIR3HBwyDkIBRUKAsn9BAQ1XnuztbKOveo9r60cTVVVVz5JrrmkBZl4GbhgJKF8t/ExEDQ8rHgYgD0i2FMl6UPBzAAAdGElEQVR4nO2dd5Dcx3XnP92/NHFzwiIHIiwAJhAgCYJJzJRIJZuUJVqBlM62kmXp5DvV0bIln80618mWLVNnMSlYJ5nSUZbMLJCiQYIIJCGCIDKwAIig3cXu7M6GCb/Y98dvFnEnbMKyivxWTQ1q8Zvu1+91v9Sv+ycYhlLipvufukfApxG0CUSSdzFhUKhBFDsVPPTs5259GCEUgAC49f4nWwLEjwVcN7VkvjOg4HmJuuupz723U6KUeJf55xYCrgsQP0Ypod3SdOlnBPzpVBP1ToOAefNf2XdUKqXumWpi3qkQ8GmJoG2qCXnHQtAm3/V2pg4CkZRTTcQ7He8KYIqhTzUBxRBXLi061A6kaDx6iBlOhmjHUWKpbqID/Rh2HukHAARS4kYs8skasnUN5KZN56gVp3v6bPqqG+n0YEiaUzyikfG2EkBDYDPfTnPe3jeZ/tZ+6vbtJqoUUoDyXDRdR0iJkhKEAG34lwHks5Adgo7D+G+8wnLdACCrBOn553Fs1nz2nrec9lgt3XpsysZ4JsQt9z+lppKAhCZY5A7QtmU9523fQlXPcXQVIDUJho5CMFYCReGD5xH4PgGSwdo69rVdyI6VV7E7UsegP3FjGRONUyWAahlwceowK158hml7dhARCqHrKE0bM8PLQQAiCFCuh60UXfMXs2XNDWxpnkcfxiT1WhrnXAUlDMkl3QdZ/cxjNB1qx9Q1iJgEMGmMH4aCUH1ZJhYw+9BeWvfv4vLWmWy48YO8On0RA94kE3EGzukKOD/Xw00vPsn01zdjmgZK1yed6eUgAOF5OI5H57ILeXbNLbxRO4PgHBF2TgRQJwOue2Mdl/36P4gELljWlDP+TAgA28EWktdvfD9rV91AZ37yDcSkC2CpP8Btv/pXpu/dgRaNEAgxmd2NG1Ip/FyezhmzeeJDn+KNWNOk9jdpAtAE3JDv4tr7/xcJ3xn/rPcFygcVCEKDIThpNQQIFX5pCqEB2th7E4BwHDJC56VP/ylP18zBnaRpOikCsITi/ftf5dJHv080ahFoWvkfnYkAlCNRPggdtKSPVuehNbjotR4y7iPNMBBTrsTPaPhpHa9Hx+818Ackyg1jBWkqkKMfpgwC7Gye1267g18su5KcmHifZcJbjCqf33/1WVasfQIjHg1VjgJly3CGmkFB4Y4M5QiUI9GSPtbyLNHzM0Tacpgz82i1PiIShFSfcPIpuDeADyov8dMazlELe1eU3LY49t4Ifr+OMFTp/lUodFRIZyAlZjzKZU/+P8zuLn5+zYcZkhPrrk6oAKL43LnxcVa8uBaZiIaawhMoR1D3h92ImCL1QFM4c89YFCovUQFY8/PErx4gccUA5mwbIoAPuISqxwWcIgQIEFqA3hSgT3eJXT5ErdONc8QiuynJ0AvV2HsjKAHSOkMQCoKMRu1He5BVPr0PN4WrxgQZi3Dxqy8R0TV+et2dpN1gwng2YQKISPi9Tc+w4sVfI2NRlAhnMwKavtJB1Yd6gVBV93yvGRnxQQdlC5QriCzNUfOhFPHVg4iqIGSyAwyOgojhlTAsKAAB5kwbc4FN9QdSZF9Jkv73enKvxxAaCCsImT+kUXtnD/V/0gkGGM0O3X/fSpAXEFHIaIS2jeu4PZvj5zd/jNyZM2iM0M5778f+atyNSMEH973CZY8/ih6Phcy3BdJSNN97jOSt6ZCRLkRWZpFGQOaVKlReYrQ6NPxJF42f68RcnEcECvKEs36i4AMOCAnmeTZV16UxZzu4hyy8ThPlSGru7KHh852h0HNgLrWJLMyR3VRFkNXAUEhdp/XIIZKJCHumL8CfAOs5IQK4Od/FlQ/8PZFEnECEKkdaiuavHyF+9SAMFB5UgAeRS7IIFEazS8tfHCW6IhsO3GZyw2HFiZVhLrZJXttPkNWILMvS+MUC84cFb4MxzyXaliXz8kkhaIZB05tbMZe1sTtaO26Sxu0FLddtPnrfV6k2JIHUUJ5AAC1fP0rs2oGTzD+tV8AofJ+qLs4lVIEGjRMTg5FUexXkXonTce8slCMQhkIGAYO2x0//7JtsNccnhHFtyNSZkvf95LtUERBILfQiXEHD5zuKMx9OzkSH0TNfFKge6TOaGE8QMn2YhmJ2dQCiqzI0feUYFGKQQEqSmuC2H/8zrbHxeUVjFoAAbtr2Ii3794BlAaGrWfexbqo+3FfeeA4bzEo6OpXJihN6OsiEH3KFvwWMXiCV0DEAiZsHaPgvXSg3dFOVadDU1cH1636JLsce3Y/ZC7pQ5rjolz/FiMdOTB4lQOW1cGZphN9jxTDjfSAHXYNJDg7O4lBmJh35FtJuDXYQRtcRaVOt9zMt0sWcxBHmJt6iOTmAiBboGG+qtSB45XEi/lCAFo+y/NdPcPml1/AS8TE1PSYBJEyN9/zi/xLXxGm5Hc0M6PlZPYOOYs6XO8M/jlYIw4x3ob/XZHPXxaxPXc7OzBJ63AYcZaIAgTojDhMIBaZ0qDdSLI7v5sq6jaxq+i11tflQ349FEBKIwVsPNJB6uJnaZHCiiQCIWwZX/ORf2Pbxr9LvjD4+GJMALu0/xvQ3XkMk46eNRwgIoj6HHq3HU7Dgy50nItSKUJhpgz06Tx99D08cv5UDuXkESAzpoguXmHDDjgQIwq1JUZgECoVSkPIbeSE9jXV9VzP76CHe1/Q0t8x4npp6J+yjUj4JIAZHHmrg4ANNmLEAn5N2G0JV1HJgP6uP7ebpxoUVNnwSo3ZDa0yND/zbd6m3swTydBOiAEOCYSk6X4vj9unUrx6qbNZJIA8bDi7nvj1f4fGe2xjwq4loNoZ00ISP1DSkYaAZJtKwwm/dQBpG+K0ZaLqOYWhYhsLQFL1+PRvSl7Kl+wJq3ePMiXeCRXmaBGDCWw82cvDBJsy4ot4EQ5z9U12T1BxsZ8eqq8mOchGM2ghfMvA7mg61o/SRF48CEjrU6gI/K1HlDFRB5dhpwb+8eQf/Y+9fsTu3mLiWwZL5kEjNQLdi6JEYmhlBaMaJWR92qsLPKawRQiJ1g1hUUpOAA2o5f3ngG3xn28fIpmRlRlqCO6AjA0G9qbBGYD6A0jTqjnewqnNvmQZH7KJyJEydC59+LNzNKvGcbwtqZzuc94UuhFLFZ1uB+f09Jn/95pf4QccnAYjKbPjfmoYeiaJZEYRWELiqxG0ZxrBgIG75WDGLf+u/h29u/2+kuqKnJ/RG+CkuzPmjLlqX2hiOVlRzKcCImFz07K+otUaXohiVABb7g7Ts2QFm6Rob5Upq7upGa/FK+/kS0t0W39z+X1nbdyMJbQhN+IBAMyx0K3aS8eMMkZVSSAKqLJv1zi389Z57SXXGSgvBA706oOETx/H80gtG6Tp1h9o5306Piq6KBSAELN+6kYhQJVmh8pLI0izJ69OQKfGgBvm05Fs7P8v6/itJaoOEeWCBHokih4WsJjg3oRRJbYgt7lX87wNfJZPSSnM2A1VXDiBWDOLnirNLAZah0bbx+VHFBRULoFGH2ZvWoRWCrqKEBFDzwRQipop7GxLIwQ/2/h5r+24gqReYLyV6JBrO+olm/BlIyEHWZ2/g+wc/hcpQnBMKhAH1H06RCVRJhknLonXzemZEKlcsFT85P9dHdarnLM/nNFodgTUvT3z1YBidjoRC/mfD4TYe7bqTqJYjHKUMVY7UKma+Oi0aGD1i2hC/7P8I646uCl3lYk3loHZlFhZnyeZEcbMhBMlshgW9v6uYhooFsLB9Ozpl1I8jSVw9gKgOivv+EgbTJo8c/iSuMk7ofN2KIKQsy3w7sMh4cXJ+FF/p+Eoj70fJeHHsoPTqPJuUgEBIftj1GfpSseICCEBEFY039NOXFwSM/KgidEkX7HydSrVQRYFYXCqm7diKZhjFYxgFMuETXz1QcscKD545cjU7skuJaxlQCs20yqodO7BQSrCwah8r6l9jUXIv9WYKgaLXqWPv0EJeS61gz8AiUGBpdiVDwxJ52p1FPNlxC3fVPBZGzCORYUP95UMcqnPpy2s0WCM/Jk2Dhje3UHv5e0nZ5SPQigTQGtWpObAfjOIulrIl0WVZzDl2cc9HQn+vxePH34suPEAhNB1pmCWZn/HiLEi28/F5P2J14wZMrSDhU4oirhQv8Ym5P2Rz6lJ+dODj7OpfTFwv5QWchCEdnknfzs3pZ2loHhp59bpgtbpUt+XofjmJqSuqtBHMnKZR09VFCw6pCnbNKlJBVV1HiRHquGJQniByfgaiFDe+Abxy/AIO5OZhSRsQaKZJKTck48W5ftpz/NPKL3LNtP/ExAnzSx4ho/zCv13Q8bii6WX+ceWXeN+MJ8l48ZJtD8MUDke92Wzsvixsq5h+MaDm4ixCCQZ8RV6dzUAFWAJqOw6X7RcqFMD0wV7wvZL6X+iKyJJcSd2v8vBSajVBIekjNB0hdYr5+BkvzvUtz3Hv8r8hoQ2FK6ukESLccRM5/nzp33HbjMcLQqgML/dfhZejOFc8qFqSQyvsI6c9ha/O2ttHeS5zBvsq6rMiATR3d5QuEvdBq/IxZ+WLqx8BPYMJdg4twZAuIELVU2SC2oHFgmQ7X277B6QKKk+gQfhsAF9Y/M8srdlB3o+U/YkhHPbZS+gYrC/+kAvR6TZmnQe+wFWQHmHCSU2j+tihikitSADRzmNoJYqrlC/Coqk6rzijFBwcnEXKbUDHQ0iJLOL1KARKCe6e/wgJY2h0zB9GABEtzz3zH0SKoKy7qguPdFBH++D8kipUq/axGj2UL8JwJlAM+aczUuoa0e6uisisTAC9PYgyAtDrXESkSPBV8P0PDs3EVhaCIPR6itgUJzBZVLWXyxo2ja86wocVda+zNLkVpwIX1UPnUHZecTsQgDDBanJQBboEhPYgOMlMISWx3lRFJFYkgPhAOqyrLwYFWq1X2qfyoSPfEioyIZAlBOoFBpfUv4que+NLAamwVnRl3SZcX1YUsnU600oHZRqYdf5pC1cBaV+d+JkSAiszVBGJFQnAyNtFZ2tIgUDGC9mqkRgmAB/SXs3JcYniQZcUPgur9k1MiYqCRVX70VS+pBcXkhnQ79fgl1l1euL0BwSE9sArECwEul/ZVmBlkXA5igBhluaWUmD7Zpg8kPL0fP6pzyEwpEuDmZowAdSbfRgqh1LlBBAaf7+UzRHhWMUZbUkgGxDaAwGVnvCYonPCpXLABUxgMk4IwixhZU+PvR/OtgflUNlzWpnHBOCWmV0CLOmEG+qFPd2Rm1J4gUGfWzceXpxGW59Tje0bFZ23NKVderiqUMEtzm5rWAOnPYVb4UGUigTgWlaZGaTwM2FhVtEoUoMaIx26g2Vo85Vk79B5EyaAPQPz8JQ5fElVUQRIqrU05Y4zeJnibBOAGyiGRGU7YxUJIJusCbcWS7Tip/XSJSgaTIt0Ek6h0v3p0uO1nkvw/TKbJeVQcH83d12MpqmKUtfNZufpZQ9nIgCnVy/pkwilcGKVHQavTAD1DagSlklIhZfSw1LukVpUYU9z4kewhBPapxICNaXDzoElbEmtOOscwaigwRuppWxNLSNmlHdpNTzmxA6E7vSIqc5Q/djdBqIU54IAp76hIhIrEkC+uRXfKz69hQZ+r0GQ1ou3KGBu1WEajB68oHS3orBKHmm/m7wXHZurIMENDB7YdRc+BlIfrmscGZ7SqJZ9LEi0F+9Pgt8vsY8bCL14W8r3sRubKyWzPI43tpRevprCH9BwjlgUPXCuoCE5RFt8F05goMp4JREtz87+Nr6z+3Mnaz0rhQQ0+O72T7ClezmJaEDpKQuuslgQ2UNrVXfxh3TIdZi4vTqixCFA5ftkps+qmNSyOJqsCzOXJZ5RnsDeVWK2BiAjsKZhA1J5qECVDu6AmJ7h8WO38XfbvoQdmCdL2kvBAE/o/OO2z/Do/ttJRlyEbpR1axWC1VUvoZdKpxswuCuKn5dF6VCArhu8laysbL2iDZnBlplkFSQpbsiEpshti1Pr9ITnkIro0Eub3mDukYMc9hYSK9O7QBHXszz+uw/QPjCbu8/7EauatiKkOr2q+ZRC3i3d5/P9XX/Aa93LSVoOuhUpq/tdZdKqH+GKhg0hR0aKOwu7ef2vx0qeuAztviLdOqei0vuKBHAs55OeO4+qwwegSEWcMAPsfVHcwybGLHvkbckAqmtsbmt6kn84spCYVUmwpUiaWfZmz+e/v/Y/WVr1Bquaf8uS6v3UW70IoNepZXf/fF7puoitqTY8ZVAd95B6+TQ0gKMsbqh5gqbageKzXwenU6d/eyw89loEwvfJNzbSKS0qSeNWJICMknQuuYDW9j2IIgJAgj+okdmYpOa8IgJQYY83z1zHs903st+9gLjplQ16lYKIZqM0yfbMSn67+xJ08pgiLF10AhM30NGlImIGxAwJsrzaAbCVxWyjndunPQkmxXkWgd7NSZweHS1enLGB6zJ4wQpSFVZKV2QDFLB73hICipdkAAgjYPCFatRgEXcUIICqOoe7Z/0Q6WXxVeXWVaCIGi41CY94XEdGEkgrTiymU5OEREJDt8ySib7TxxXuO3y86UEa6gdLl1DacHxtVUm3WBEe7j649KKKL/uoePRHGmaQTtYggxLxgKmw90fIbk5CsTikEC1fMXs7dzT8lCHHKmuMz2qiMDhNgqaJsJxl2MsZRQ4p4yd5X/VjXDfz5dLBVxT6X4/Tvy0WbkcWgVAKLxalvXFmxTRULIBjWZe3Ll2D7xSrORmmAvr/vR7s0quAKHxy4c+5Nv4UQ16iYoInCkNBklXxl/jM3AeRCYqrnkKC5+jP6lBemTSK7ZC+9AoO25VPgooFoBRsX7EGp/RNA8hIQPaNGEO/qSq+CgB8iNYGfGXRP7Eq8huGgnN3fWkmSHJ+ZAt/Pvc+quqd0rYyDn0bEvRuTKBFy+h132PvFdfhjuIA8ahizN1WLV3zFiLc0v6V0BW9P24k6NVKm/kAahtt7l34t1wdf5YhP0kwQSfQR+5OMuQnWRldz9fnf53mloHT3dkzoUGQERx6uDHcSyg18zwPZ+YstkZKbOqPgFEJYMD22HrzB3HybmljbCqcgxFSDzaHurVUDb6C2iabexf/LR+rf5ggkORVZe7jaOAoCzcw+WDNT/jGor+gubkM8yE8IfNwEwNvxtAiZWZ/3qb99t+nd5TnxEZ9RuzVhtmsmjGLaanOoqdkhgcl9BIV0qc+qyBSE/DHi37AsmNv8oPOT7PXXoohXUxRWYlhMbjKxFYWc419fLz5Ya6f8TLEqazSIiBUOxJUIMIAcCT4Pl5dHa/OXgaZMjbyDIz6jFjOh+jcmczbsA7NGuGghgovvqi5o4eGL3aGKerK4i0wYVZtB1cl11KrujnutNDjN+IpK9zKFJUklAWe0rFVBFeZTNOPcUfdv/KFud9m2YwD4fmwSidpANWXZdEMRd/GBKJIIYfKZtl792fZbIz+1PyYTklubJzP+YuWMvfQPpR5SvZNhVe+1NyRCplvM/qCKgE1DQ4fqf4VN6afZVPPZWxIX8WefBu9fgNeIdsnOHmj6HCZulJgCI8arZcFkV2srlrP6oYNNNYMhUGWGiU9CsjCzLt7wrqm7zUho5y2sSM8D3vWbNZNXwJjOKY65rsiVut5PvDNPyMxfCkTYYFuzYdT1H++c/w3npyS3wly0DlUw4HB+RzMzaHLaSXt1mIXbIUpbKr1NC1mB7Ojh5iXbKc1kUKLEk6xiTionYCj36/n4ANNJ1IRCpCZLBvuvY/faGO7M2LMJ+U3B1EW3PohVj79C2Q8Fo5PgYwGJwc9HihO1OfIOLTG07Q2bWGNvyW8GcvnRPWCJincE1f4DKf+h9sYLworUwyXrheCSZnLceza61lv1lO6lKI4xlwV4QeKtatvpWvaTEQhOBNWQPePGun+RQ1UlWmggsII4KTaGJ7FGmCBiIGeCD8iFv7tRDTrM7pZX46OKuh5NsmB+5tDIQjA87Cra/jNTXfijJH5MM6ylI6sy+N/+HkGgzAHIgW4mmL3t6bR+0KiuBAKh6CxKL79VwynCuTMz2jb0QivRDMozokkDLwaY+9900GoQipcgeuy6Ytf463c+JbYuOuC3tCq2PBHXyGfCc96xSxFHMHOb0wnvSF+thAkEIfDjzSy/1vT8PIaJCeCklFAAAkIfMnB7zbT/u1p4YQ4UyEnYXBblJ33zsDPyRO6X2az7PnUH/NS2WVeHhNyY9aBeC21VTFad25DMwwiJjg5Sce6KhJz80QXO2F6usD8Iw83cvCBRga2x+jblMCs9onNP+WCvomryTodkvAAiQ69LyfY8zfTOb62moHtUfwhjbo1hXrOAKgOZ/6ur83CTeuhbVMh8/df+R5+ddF1b58rywIF7S2zqfezTHvrIFLXiJlg5wQdL1QRqfVIXJAHEw4/1MDB7zVhxAP0qCKfMuj+TRUD22MYiYDIdBcxnJubiMsJBaGKiREeqtiSoP3bzRz+fhN2t44eD5Cmov/1ON6ARt2VQ5CAnmeq2PWXM/AGtRPMJ5Oh78pr+MVNHyUzEdxnAm9NzCrJz9Z8AN1xueD1TciISUMcUjnB7vtaT1QSHHygCSMa0GgKPAUpK0Ao6Hs1Tvq1OMm2LE03DlB/2SDWdDdkXuEI0gk9XypvP+y+GoXReWB3GvRtTnB8bTX926IoT4QRrjj5Oy3hc/Rn9QhTYTZ4HPo/TaGbOcz8oQx9qy7jsfd9gnR2dNFuKUz4zblxz+Yj63/FhZvXoUUtFIJeVzGUC8vDNSugwRRYhcGnPRgKChGugsCWKA+Mep+qJTmqL85Q1ZYjOt1Grw7CIuBi+boAlAP+gEbumMnA7ij9r8cZ2BENa3k0FebzS+SmglMubhUSUAqZt0mtuZrH3nsXXdmJveBuUq4ujiqPD2/7T1Y8+RiRWIRAkwx4kPUVdUbI/FPP2va4CludcdbKFwSOCE/fRAKMWh+rycVqdDHrPPSEHxpFERZLeRmJ06tjdxvYXQZOn46fFwgB0lIly0iKIgiQeZv2Ndfw1E0fIT0JF0hP2uXdhoBbew9w5SPfIaY8lGXiq7M3niRhbX23pwhUkcmpQoEoT6ACwtSwUuEGqQClwhIXIRRChklAoRVrrEJ4HtIP2PmJz/DEjGXYk5Qmn/Tr6y8c6uT2xx6hqeMYMmYRjMCV4dr6Xm88Fw9MEJRCOg5OdRUbP/81XpwAV7MUzskLHKZFJDesf5ILnnuCqKGhjLPvG5KEJw4H/dIXYkwmhOchfJ+jV13Hc9e+nyPe5G0OnejzXL3CRBdwmRpgzaMP03poP7ppjPjCnh5X4YxTe4wavo/I29hz5vLqH9zDBqsep8xpmonCOX+LUrUMWPXWDlY/9x/UH+9AN7QT75IRgFewB5N8W00Iz0f6Hm5dPTvefyfrWxee87cpTdlrrOoCm0uO7mHlhudoPHwQQxPhUVgpyQTQNwn2QBGWjuA4SKXIz5zFzqtuYOuSlRzLT9yV9KPBlL/IrVoGtA12sWzTC8zbtY14ZggNxZCm01/wPMYqiOFVJXwf5bpIIQgiEVKXXsGOiy7nzXgj6Sl+meCUC2AYEsUME+b2HKFt/07qd2xFHDmK1DQ8N7zaQOjhClFCnL03qFQ4u4MA5YUJJd0w8X2PfEsLg8suZN+CNg40zOSoMvDeFqN+GwngTNQol5lRjcSB3cwa6qempxPzeCdWqgczM4RwvZNVcEKgdB03niBfV4/b1EJ/QxNvxasZmr+Eo/mAtGaes3eDjQZvq5d5noq0MEjngdY2NgKM/lLaEMNZ2Lch82HKzgm/i2G8K4AphlSo0bwm511MIBRqUKLYOdWEvGOh2CkVPDTVdLxToeAhgVLi5u8+vVbAdVNN0DsJCp5/5rO33CARQknUXQqen2qi3ilQ8LxE3YU49dIbpcRN9z91j4BPI2gTiHN3YuIdAIUaRLFTwUPPfu7Wh4cLTP8/Vkzz/TMMxxEAAAAASUVORK5CYII= + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/wikipedia-sv-SE.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/wikipedia-sv-SE.xml new file mode 100644 index 0000000000..83df4fa315 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/sv-SE/wikipedia-sv-SE.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (sv) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://sv.wikipedia.org/wiki/Special:Sök + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ta/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ta/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ta/eBay-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/eBay-in.xml new file mode 100644 index 0000000000..8d27d340f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/eBay-in.xml @@ -0,0 +1,17 @@ + + + +eBay India +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ta/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/list.txt new file mode 100644 index 0000000000..5c8c024bee --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/list.txt @@ -0,0 +1,8 @@ +amazon-in +bing +duckduckgo +eBay-in +google +wikipedia-ta +wiktionary-ta +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ta/wikipedia-ta.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/wikipedia-ta.xml new file mode 100644 index 0000000000..fde6a35718 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/wikipedia-ta.xml @@ -0,0 +1,23 @@ + + + +விக்கிப்பீடியா (ta) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ta.wikipedia.org/wiki/சிறப்பு:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ta/wiktionary-ta.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/wiktionary-ta.xml new file mode 100644 index 0000000000..01d859dec0 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/wiktionary-ta.xml @@ -0,0 +1,17 @@ + + + +விக்சனரி (ta) +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpGRTdGMTE3NDA3MjA2ODExOTJCMEU1MkZGMDQ2RkQ0QyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNURGRTgzRTMwMzMxMUU1OTlBMUM2MDY0MDI4RjgwMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNURGRTgzRDMwMzMxMUU1OTlBMUM2MDY0MDI4RjgwMSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDA4MDExNzQwNzIwNjgxMTkyQjBFNTJGRjA0NkZENEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RkU3RjExNzQwNzIwNjgxMTkyQjBFNTJGRjA0NkZENEMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6qmdYgAAAHWElEQVR42uxdWU8USxgtYASFEMXtYnBFEESNKy4YV3ADjNG/IDfxxVwT/wE++OCr3sTkGt94IL4gqKAsKi4YlUACRIxGXEBBXBhcQZxbp50uq3p6enoQpoeZ7yQl00sVM9+p/vZBxn4jho8SPpr4cPPhoTGmw+2VbYlX1gpS+aglIYVs1HplLnY+Cd8ZEmLi+D9/8/EPI4Qa6Xy8AgH/8jGX5OEI/orxGodkkoUjGIzx6iOCQ4glERABRACBCCACCEQAEUAgAogAAhFABBCIACKAQAQQAQQigAggjC9cdm88fPhwwHuuXbvGXrx44XN+z549bO7cX2Xnvr4+VllZOWEFtmHDBrZ8+XLLewYGBtiFCxdsr2mrjcIODh06ZDq3sbFR3NPW1jah20nOnDkTUA49PT221xtTFTQ8PGx6/vPnz+L1p0+fJrTK+PbtW8B7BgcHnbEBcXFxEa+zJ02a5IwNkPHhwwd29OhR5na7WUzMrzbH2NhY1tTUFPEEnD17ltXX17OfP39qx/i5atUqduLEiVGvGbQN6O7u9iQkJNjWc9XV1WIuJyni2gw3bdqkyKezs3N8bQB2fVJSEvmQXkyZMoXiAArECEQAEUAgAiI2FzSeWLBgAUtOTtZ8anhY379/Z0+ePAnKC0lPT//lU3s8Wkzy+vVr9u7dO9trpKamspkzZ2rvAfPfvHnD+vv7Q/L5g44DkOuYPn26bV+3pqZGzL13757P9ZMnT3qGhoY8XPDaeP/+vYeTYnv9I0eOiLkYWOv8+fNB+fI8uBLvYXh42LN7927bc3fu3BnaOCBYxMfHi9c8gPO5fuPGDS3Ex30YKSkpbPPmzbbX379/v5iLgbW2bNnCJk+ebGv+4sWLtd+nvwfsfL5RIkcFlZaWsnPnzmmv375963MdHxbnZ82aJc4VFBSwsrKygGtjzsaNG33OL1q0iGVnZ7OWlpaAa/DdrmwSpNWRUo4YAhoaGgLmlkBCcXGxOIcdiacF9sAKeXl5jKtDX++C63GsYYcAPEEyLl68GH1eUF1dnXKckZHBcnJyAs7bt2+f32vbt28POH/OnDkaiTq4/dFUYtQRcP36dTYyMqLs4G3btlnOwROyY8cOv9dzc3MD5qwwf+rUqeL45s2bpmoy4gno6OjwcT3z8/Mt56xcuZJlZmYqxhzqTMf8+fPZsmXLglI/oS6Xhg0B3AVkt27dUs6tX7/eVL/r2LVrl6hHAKdOnWKPHz8Wx7gGb8gfpk2bpqgpVO5qa2ujNxKG9yFj9uzZbO3atZbeiw4ETpj/8OFD5R4rNQbdjwBM9sbMmgqihoA7d+4o9WOABzmm90K9rFu3Thzj6cFT1NjYqNyHe2Qdb6V+qqqqojsX9PLlSx+3EUZSVjPyzk5MTBTHV65cEbv469evipezYsUK0/QFVJgONBRUV1dTMg71VhkQHnJFVu4nBK7HGl1dXaytrU25d+vWrT7z8WQgAtYB4js7O4kAIwHY5bKfDiBxJwu1ubmZPXv2TCTjjGrIzA4UFRUpx5cuXRKF9qgmAMLs6emxtAPYvWlpaeK4pqbGMvJevXo1mzFjxu/w3+VSniAI/vLly4583rAjAK0ud+/eVc7BlZSTeHv37lWEZyTgwYMH7OPHj0q+CK0jOhAbyPEBVI+dlEVUEAAYfXGkJZYuXaq9RvOXbDyfPn3qIzy4pMZzssrC7pebyGB8/XX1RSUBSAfIApHTEkuWLFGaY2Ez4H6areGPAKP+d8L9DGsCoBIePXpkmpaAPZDbA/3pbqMdQNoCke+8efOU+OH58+eOdvSFJQFIyhl3MBJr8Ijk/BBKjrdv3zZdAyqot7dXHKPIA72PJ0ku1CAL++XLFyIgkB1AyuDAgQNszZo14hyE76/uCyN8//59n9xRYWGhci6UuX9/GPea8GgGF7iHC1H5ve3t7VrdVgdqwVZrHD9+XJnPYwVPf3+/OO7r6xuTzxH2NeHRAJ6MMbGGAo2u/1EpMxZxzAyxHFwtXLhQiQeQvkYBxkmEdV+QMSqW0draGrB1hT8xltnNcFA/YU8AUgtmuHr1qt9rOmBcjUGdHPBZEUwEeHc53EQz2M1c+msIADHd3d1EwGh2MNQKckZ24M9NdTL4kuFiYY6KigotG6oX7GGEy8vLlZy/FVCiRKUMETTW0Fsfncj9Tyg3VB7x8fEeLnhtBPPVKOHqxcaKNfDT5XKN6fv7Ezc07J8AwCzXEwzgiv7pGmFlA+B9BPNd2EiHsY497jYAzU7Hjh3TfrH8NVX01KAkGMlAuyM6NXSbhM2YlZUVWhvgDwcPHoz4//ni9OnTAeXgWCrix48fEa9u7NgSsy6OkMQBUEORDjt/jiGYP2dA/4EDRcJEAIEIIAIIRAARQCACiAACEUAEEIgAIoBABBABBCKACCAQAUQAYZwJoAYf5zAIAjpIDo6hAwT8R3JwDJrs0RmBb8R5aIR01HplryGVSAi58FONjwPYKOED31p2k5DGfLi9si2Rd/7/AgwA1G383MiEhakAAAAASUVORK5CYII= + + + + + + + + +https://ta.wiktionary.org/wiki/சிறப்பு:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ta/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ta/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/te/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/te/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/te/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/te/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/te/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/te/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/te/eBay-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/te/eBay-in.xml new file mode 100644 index 0000000000..8d27d340f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/te/eBay-in.xml @@ -0,0 +1,17 @@ + + + +eBay India +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAEWklEQVRYw8WXfUxVdRjHP79z7guXBBTEEBXEraktCydjWi7RZW82lr340kZNXaX+41p/tF42Xakw3ZqNyeZMnZVYtjnLNLXMzJFLA1FrgiIioveCIvcyLvdyzz3n6Q+7FxIM5YJ8/jovv/2e7/Oc5+X8FICIbCKCiCyTLmgArcUbmb2ugirP3u4rlIjkA3P+3aFIiYjQBa21eCMARv2XFB5Mo9sKRORZ+R80IMv0NAJQ7Q4CYDYdJmwGehZ+O0pEXEA7d0B1i0UnbUqpd7urvg2NXtAAQhWnmF5Ug9tnQDiIZYUBCBo+NPf0WQTLfqc1aDEyyU77kWyCB9Kpa/6NOHsS3Mm9tQcejLoZk0gzEgehb2zp9VP0Ro8S522qv2sJGkDLR6uwmpvBsvA8n8+3f/oA+Oakly3HbhI6swKA9u9dFB5MA6DKs5drvtO3Noh/4Tm8a9fRunUbzkmTGJGgs3ZfIx/sbiT/YQPTdxbjUgnKkcL7z3goPJjG0PhM0pMeo19iYBIrIvJaH4x3iIgeyYNUYAWQepc2jyqlSiPWX+mr/wAqhiwEWKPFGL6sWDfoXm1Ltjf0bYNQ+SnEMPB4b7WLX6vbOmu2uQyrrZqg4Ys+izRGDaBxzlwcUybjXbkaEYuSIzfIGz8E9eZZQudWoidPQ+mJ/F25nNrrRwBY/3MWADYAfXgyrcUb0UeOQNpDLJ85HIAnH4rHrP8CQ9nQEibyiH0In1Ys5KXsLSyadqhL1ztfgy1rHP5du8HpJOu9Kjb8dJ3aGyHE9KMSJhA6XwhiMT/na3ZXLiEt8dFoGt8TJy5vFrfvTOR2R6yJVNr/eXCPhJSINN1DFd7O5EggvX0oxg97aipeGXjCIrJaRByRduACGoBk7j85GlAwSMYBVmiAzuChawwydyVgzmd1TC+qGRABtsiF5fXSsmoNofIKbBPGI01NWIEAQws/AZJpCVjMWHeRKy0GLodGlbuDd55KYf2r6VjXD9Nxcj44UtDiM7C8FcgDmWxTJgnOUbwxdX+XarPYXJZHYtwoFuTsRInIMqDEnfc09swxOPPyOgdBXS3tPxxg8YubONfmoK5oAkp1qs/++AJpiXZ+XJ5IuGEXVls1yriBWCFMz3600QvZ7j+Hy5bI61P3IWLxedlMklzpzJuyE6A0GgHb2AyU3UHCooKogY7ySvSx49B8Q7jW4Oe8J8j4kXEA1N80uNDYweKJlQT2L8D5+CHs45be8jLgJnBtD0op3nriKFuPz2bHyZcxwn4SnGkR40T6wDKgBMC8epXgsTLCl6+AaeLIzcE1K499f/nRFIxJtvPVcS++YJjMFAdvz0hhWLyO+C8Sqi1Ggo3orrHoGQVI4DKixWFLnYlpGWz4ZSKjh+Uyf0rpf6ZBzD93vWFZYfnij3zZc3ppT6932Aa6zJTSKcj9bsDGWb/0gUuDaL8mMgnnyv2nMHpc7TKSU4FcIBvI6GdvbwLlwAmlVPQU9g9eOPBg6mUX4QAAAABJRU5ErkJggg== + + + + + + + +http://search.ebay.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/te/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/te/list.txt new file mode 100644 index 0000000000..ca3fc758d5 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/te/list.txt @@ -0,0 +1,7 @@ +amazon-in +bing +eBay-in +google +wikipedia-te +wiktionary-te +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/te/wikipedia-te.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/te/wikipedia-te.xml new file mode 100644 index 0000000000..241b698ed6 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/te/wikipedia-te.xml @@ -0,0 +1,23 @@ + + + +వికీపీడియా (te) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://te.wikipedia.org/wiki/ప్రత్యేక:అన్వేషణ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/te/wiktionary-te.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/te/wiktionary-te.xml new file mode 100644 index 0000000000..e556ec7344 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/te/wiktionary-te.xml @@ -0,0 +1,17 @@ + + + +విక్షనరీ (te) +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpGRTdGMTE3NDA3MjA2ODExOTJCMEU1MkZGMDQ2RkQ0QyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNURGRTgzRTMwMzMxMUU1OTlBMUM2MDY0MDI4RjgwMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNURGRTgzRDMwMzMxMUU1OTlBMUM2MDY0MDI4RjgwMSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDA4MDExNzQwNzIwNjgxMTkyQjBFNTJGRjA0NkZENEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RkU3RjExNzQwNzIwNjgxMTkyQjBFNTJGRjA0NkZENEMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6qmdYgAAAHWElEQVR42uxdWU8USxgtYASFEMXtYnBFEESNKy4YV3ADjNG/IDfxxVwT/wE++OCr3sTkGt94IL4gqKAsKi4YlUACRIxGXEBBXBhcQZxbp50uq3p6enoQpoeZ7yQl00sVM9+p/vZBxn4jho8SPpr4cPPhoTGmw+2VbYlX1gpS+aglIYVs1HplLnY+Cd8ZEmLi+D9/8/EPI4Qa6Xy8AgH/8jGX5OEI/orxGodkkoUjGIzx6iOCQ4glERABRACBCCACCEQAEUAgAogAAhFABBCIACKAQAQQAQQigAggjC9cdm88fPhwwHuuXbvGXrx44XN+z549bO7cX2Xnvr4+VllZOWEFtmHDBrZ8+XLLewYGBtiFCxdsr2mrjcIODh06ZDq3sbFR3NPW1jah20nOnDkTUA49PT221xtTFTQ8PGx6/vPnz+L1p0+fJrTK+PbtW8B7BgcHnbEBcXFxEa+zJ02a5IwNkPHhwwd29OhR5na7WUzMrzbH2NhY1tTUFPEEnD17ltXX17OfP39qx/i5atUqduLEiVGvGbQN6O7u9iQkJNjWc9XV1WIuJyni2gw3bdqkyKezs3N8bQB2fVJSEvmQXkyZMoXiAArECEQAEUAgAiI2FzSeWLBgAUtOTtZ8anhY379/Z0+ePAnKC0lPT//lU3s8Wkzy+vVr9u7dO9trpKamspkzZ2rvAfPfvHnD+vv7Q/L5g44DkOuYPn26bV+3pqZGzL13757P9ZMnT3qGhoY8XPDaeP/+vYeTYnv9I0eOiLkYWOv8+fNB+fI8uBLvYXh42LN7927bc3fu3BnaOCBYxMfHi9c8gPO5fuPGDS3Ex30YKSkpbPPmzbbX379/v5iLgbW2bNnCJk+ebGv+4sWLtd+nvwfsfL5RIkcFlZaWsnPnzmmv375963MdHxbnZ82aJc4VFBSwsrKygGtjzsaNG33OL1q0iGVnZ7OWlpaAa/DdrmwSpNWRUo4YAhoaGgLmlkBCcXGxOIcdiacF9sAKeXl5jKtDX++C63GsYYcAPEEyLl68GH1eUF1dnXKckZHBcnJyAs7bt2+f32vbt28POH/OnDkaiTq4/dFUYtQRcP36dTYyMqLs4G3btlnOwROyY8cOv9dzc3MD5qwwf+rUqeL45s2bpmoy4gno6OjwcT3z8/Mt56xcuZJlZmYqxhzqTMf8+fPZsmXLglI/oS6Xhg0B3AVkt27dUs6tX7/eVL/r2LVrl6hHAKdOnWKPHz8Wx7gGb8gfpk2bpqgpVO5qa2ujNxKG9yFj9uzZbO3atZbeiw4ETpj/8OFD5R4rNQbdjwBM9sbMmgqihoA7d+4o9WOABzmm90K9rFu3Thzj6cFT1NjYqNyHe2Qdb6V+qqqqojsX9PLlSx+3EUZSVjPyzk5MTBTHV65cEbv469evipezYsUK0/QFVJgONBRUV1dTMg71VhkQHnJFVu4nBK7HGl1dXaytrU25d+vWrT7z8WQgAtYB4js7O4kAIwHY5bKfDiBxJwu1ubmZPXv2TCTjjGrIzA4UFRUpx5cuXRKF9qgmAMLs6emxtAPYvWlpaeK4pqbGMvJevXo1mzFjxu/w3+VSniAI/vLly4583rAjAK0ud+/eVc7BlZSTeHv37lWEZyTgwYMH7OPHj0q+CK0jOhAbyPEBVI+dlEVUEAAYfXGkJZYuXaq9RvOXbDyfPn3qIzy4pMZzssrC7pebyGB8/XX1RSUBSAfIApHTEkuWLFGaY2Ez4H6areGPAKP+d8L9DGsCoBIePXpkmpaAPZDbA/3pbqMdQNoCke+8efOU+OH58+eOdvSFJQFIyhl3MBJr8Ijk/BBKjrdv3zZdAyqot7dXHKPIA72PJ0ku1CAL++XLFyIgkB1AyuDAgQNszZo14hyE76/uCyN8//59n9xRYWGhci6UuX9/GPea8GgGF7iHC1H5ve3t7VrdVgdqwVZrHD9+XJnPYwVPf3+/OO7r6xuTzxH2NeHRAJ6MMbGGAo2u/1EpMxZxzAyxHFwtXLhQiQeQvkYBxkmEdV+QMSqW0draGrB1hT8xltnNcFA/YU8AUgtmuHr1qt9rOmBcjUGdHPBZEUwEeHc53EQz2M1c+msIADHd3d1EwGh2MNQKckZ24M9NdTL4kuFiYY6KigotG6oX7GGEy8vLlZy/FVCiRKUMETTW0Fsfncj9Tyg3VB7x8fEeLnhtBPPVKOHqxcaKNfDT5XKN6fv7Ezc07J8AwCzXEwzgiv7pGmFlA+B9BPNd2EiHsY497jYAzU7Hjh3TfrH8NVX01KAkGMlAuyM6NXSbhM2YlZUVWhvgDwcPHoz4//ni9OnTAeXgWCrix48fEa9u7NgSsy6OkMQBUEORDjt/jiGYP2dA/4EDRcJEAIEIIAIIRAARQCACiAACEUAEEIgAIoBABBABBCKACCAQAUQAYZwJoAYf5zAIAjpIDo6hAwT8R3JwDJrs0RmBb8R5aIR01HplryGVSAi58FONjwPYKOED31p2k5DGfLi9si2Rd/7/AgwA1G383MiEhakAAAAASUVORK5CYII= + + + + + + + + +https://te.wiktionary.org/wiki/ప్రత్యేక:అన్వేషణ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/te/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/te/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/te/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/th/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/th/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/th/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/th/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/th/list.txt new file mode 100644 index 0000000000..ecbd34be3c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/th/list.txt @@ -0,0 +1,3 @@ +google +twitter +wikipedia-th diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/th/wikipedia-th.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/th/wikipedia-th.xml new file mode 100644 index 0000000000..fa0cabb0f9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/th/wikipedia-th.xml @@ -0,0 +1,23 @@ + + + +วิกิพีเดีย +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://th.wikipedia.org/wiki/พิเศษ:ค้นหา + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/tr/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/tr/default.txt new file mode 100644 index 0000000000..c4735ea8a6 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/tr/default.txt @@ -0,0 +1 @@ +Yandex \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/tr/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/tr/list.txt new file mode 100644 index 0000000000..a222fe9cf4 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/tr/list.txt @@ -0,0 +1,5 @@ +google:hidden +google-nocodes +yandex-tr +twitter +wikipedia-tr diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/tr/wikipedia-tr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/tr/wikipedia-tr.xml new file mode 100644 index 0000000000..6db21a8eb0 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/tr/wikipedia-tr.xml @@ -0,0 +1,23 @@ + + + +Wikipedia (tr) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://tr.wikipedia.org/wiki/Özel:Ara + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/tr/yandex-tr.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/tr/yandex-tr.xml new file mode 100644 index 0000000000..1fd00bcb7f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/tr/yandex-tr.xml @@ -0,0 +1,22 @@ + + + +Yandex +Yandex Türkiye arama motoru +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAD8GlDQ1BJQ0MgUHJvZmlsZQAAOI2NVd1v21QUP4lvXKQWP6Cxjg4Vi69VU1u5GxqtxgZJk6XpQhq5zdgqpMl1bhpT1za2021Vn/YCbwz4A4CyBx6QeEIaDMT2su0BtElTQRXVJKQ9dNpAaJP2gqpwrq9Tu13GuJGvfznndz7v0TVAx1ea45hJGWDe8l01n5GPn5iWO1YhCc9BJ/RAp6Z7TrpcLgIuxoVH1sNfIcHeNwfa6/9zdVappwMknkJsVz19HvFpgJSpO64PIN5G+fAp30Hc8TziHS4miFhheJbjLMMzHB8POFPqKGKWi6TXtSriJcT9MzH5bAzzHIK1I08t6hq6zHpRdu2aYdJYuk9Q/881bzZa8Xrx6fLmJo/iu4/VXnfH1BB/rmu5ScQvI77m+BkmfxXxvcZcJY14L0DymZp7pML5yTcW61PvIN6JuGr4halQvmjNlCa4bXJ5zj6qhpxrujeKPYMXEd+q00KR5yNAlWZzrF+Ie+uNsdC/MO4tTOZafhbroyXuR3Df08bLiHsQf+ja6gTPWVimZl7l/oUrjl8OcxDWLbNU5D6JRL2gxkDu16fGuC054OMhclsyXTOOFEL+kmMGs4i5kfNuQ62EnBuam8tzP+Q+tSqhz9SuqpZlvR1EfBiOJTSgYMMM7jpYsAEyqJCHDL4dcFFTAwNMlFDUUpQYiadhDmXteeWAw3HEmA2s15k1RmnP4RHuhBybdBOF7MfnICmSQ2SYjIBM3iRvkcMki9IRcnDTthyLz2Ld2fTzPjTQK+Mdg8y5nkZfFO+se9LQr3/09xZr+5GcaSufeAfAww60mAPx+q8u/bAr8rFCLrx7s+vqEkw8qb+p26n11Aruq6m1iJH6PbWGv1VIY25mkNE8PkaQhxfLIF7DZXx80HD/A3l2jLclYs061xNpWCfoB6WHJTjbH0mV35Q/lRXlC+W8cndbl9t2SfhU+Fb4UfhO+F74GWThknBZ+Em4InwjXIyd1ePnY/Psg3pb1TJNu15TMKWMtFt6ScpKL0ivSMXIn9QtDUlj0h7U7N48t3i8eC0GnMC91dX2sTivgloDTgUVeEGHLTizbf5Da9JLhkhh29QOs1luMcScmBXTIIt7xRFxSBxnuJWfuAd1I7jntkyd/pgKaIwVr3MgmDo2q8x6IdB5QH162mcX7ajtnHGN2bov71OU1+U0fqqoXLD0wX5ZM005UHmySz3qLtDqILDvIL+iH6jB9y2x83ok898GOPQX3lk3Itl0A+BrD6D7tUjWh3fis58BXDigN9yF8M5PJH4B8Gr79/F/XRm8m241mw/wvur4BGDj42bzn+Vmc+NL9L8GcMn8F1kAcXgSteGGAAAGrElEQVR4Ae1d228VRRj/ZpbesEWRE4G2tsQIiTQGSKWgXNSQoEC5tKUXW999sm8+kGji36APhj+AiGkpAkXAAmkFEUjAGj2oMYa09qLhRC4tprTdGWcW2pyzM3tyjvbsN9vOPPTs/GZ2v29+v51vdmbnnBJ4kuLxeH5Feel7BEgbB15FCCmeKbOf/58Bzvm44DYuuD0yODRyuKqqalJelcg/iUSirDDP6QZC1su8TTlmgPP+iSm3NhaLDRN551eWl16z5OeYdP/lhQgDQyObyNj9u++LcPOJv9zmc8+ACEvtVMb83JuyFnQMSO5lDxizA66OntxjcmCmlvzcEx1kQXJPgwotHg4DVoBweA60YgUIpCacAitAODwHWrECBFITToEVIByeA61YAQKpCafAChAOz4FWrACB1IRTYAUIh+dAK1aAQGrCKVgUjhlcK6TvEuQ1tAKZ9F5CzTrDly2Dydu3ZvMYBwuiBzhHOxTyJdmsphqD8xSb818A1wV65uuURs9kWPPBmUO0z3kvAPn2OyB/31UI5iXFwHa/peBhA/NeAOfUV1pO2f5agMJCbVmYIPog7Hz4MZDRv1LbXFgA0x8dAlixPBXPNsc50AABXAPCj2wOugAyPtPffleo5eVl4B76QMGzAcjNfiAjo8opvHQl8G1bFBwDQA9BrLVZ2256/JQWzwakJ09rq7uNdQAUvemeb+heyFDAibc/LIUs+suvQG79nIJlm6HdAfG/pTHbS+WsProAIEINf32btoG080stnglIhIC60MbWviQ2Xq7N5BKh1MEXQDTTbW3SNtY5dlyLZwIGDb6sBf/ZP9l/IwRg+/YAL34q2S/vmNweAHLjewXPBNDFfxnq3Mb6TE4PrY4RAsDixcAO7NU2mnb+h14w+AfQH35Urse3vgZQVqrgmIAZAggG3ICnIafrhFi0YVlxFDT5cg0LP7JRxgjAt7wKvOJ5hWgy+ieQK1cVPB2gDT8FBcD263tZumvluswYAcT2eHDfCRiMO7IIQ3fuALl6XeGN7doJsKREwbEBcwQQTAQJQE+ISdn0dEZc0dNngYglCH8yYeXT75PMGyUAvLAK2OYaxU+5mkkv9Cq4DtA9fvJnlwLbuUNXHR0zSwBBh9sWsDSRyZzgwRjQ3ksKqaxuH0BenoKbABgnAKvbD1yzTEy7zwBMTKTljJ7rATI1pdRxm81ZevA7Z5wAcqBktbv8fgIZfwj0bI+CJwPa8FNZAXzzxuRqRh2bJ4Cgx21r0ZKUdlL26BHQngvKeW5Tg4KZBBgpAH9zO/CVKxSe6LnzAGPjCi4BerEPyMN/lDJTn35mHDVSALlWr3tjReRdLscCTdLhbMM64Gte1NQ2BzJTAMEPezcgDHVplqjFUoVu5wMzPPzI28BYAfia1cCqNyi3qjcfuHc/BSfXbwBJJFIwLnvRQfHmy/BkrACSN91gTMSMmJ7sTqGVnr+YkpcZOY7A8ucU3DTAaAFYwwHg+fkKZ87RzhSM9n6TkpcZt8msFy+Kg08AowWApc8A2/O24ju5fAVgaPgxLma//pc2vKgI2N7dynkmAmYLIBhjmjmBfIXvdHR5fFIhBhHbD5OTJ5rmDVtyHVOOzRdgxxvANRu06BfHPA7lzmd/Mv3ZP9lf4wUAxwFXs42Eii0r5Kc40L7Lye0BueWcCdGikswXQDAZNCdwPv1M2TvE6sXK5yL0DX8Z6x8JAbw5wcZqpVHO52Lfvw/VzaB9VYzKRkIAyZgbMDNOZpOvqgRe80oyZPxxZARg9WJOoHlPkMyw6Sufyb7OHEdGAHh6idjVIPb0p0msyaxNV2lcnS2KjgDC5XRhiK17Wax8rp5tWFQOIiUA374VZJzXpSisfOr8jpQA3t4hzdKEbJgbkaUHvwjREkB6HzQQl5i36cpPti4fPQF0rYgwZgVAFs8KYAVAZgDZvO0BVgBkBpDN2x5gBUBmANm87QFWAGQGkM3bHmAFQGYA2bztAVYAZAaQzdseYAVAZgDZvO0BVgBkBpDNR68HiC3r/sTFz91AEf5PUPr9yiRPxh/cU39YIZMzbZ05YSB6PWBOmm3ORawAyFpYAawAyAwgm7c9wAqAzACyedsDrADIDCCbtz3ACoDMALJ52wOwBZD/WB7ZhwVrXnJPCZD4gmUAueGSe8qBH0H2Y8Gal9zTwaGRw8B5/4JlAavhgnPJvfdN/0QiUVaY53SLL8Gtx/JnQdkV5E9MubWxWGzYewqSBwNDI5vEoNAOHK7ZgXnubweP08fctkuuJefSyr/6yLCF22FZTQAAAABJRU5ErkJggg== + + + + + + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/uk/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/uk/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/uk/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/uk/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/uk/list.txt new file mode 100644 index 0000000000..ade00315aa --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/uk/list.txt @@ -0,0 +1,5 @@ +google:hidden +google-nocodes +twitter +wikipedia-uk +yandex-market diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/uk/wikipedia-uk.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/uk/wikipedia-uk.xml new file mode 100644 index 0000000000..631bb644b3 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/uk/wikipedia-uk.xml @@ -0,0 +1,23 @@ + + + +Вікіпедія +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://uk.wikipedia.org/wiki/Спеціальна:Пошук + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/uk/yandex-market.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/uk/yandex-market.xml new file mode 100644 index 0000000000..aac55155d4 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/uk/yandex-market.xml @@ -0,0 +1,20 @@ + + + +Яндекс.Маркет +Вибір моделей та пошук товарів. +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAD8GlDQ1BJQ0MgUHJvZmlsZQAAOI2NVd1v21QUP4lvXKQWP6Cxjg4Vi69VU1u5GxqtxgZJk6XpQhq5zdgqpMl1bhpT1za2021Vn/YCbwz4A4CyBx6QeEIaDMT2su0BtElTQRXVJKQ9dNpAaJP2gqpwrq9Tu13GuJGvfznndz7v0TVAx1ea45hJGWDe8l01n5GPn5iWO1YhCc9BJ/RAp6Z7TrpcLgIuxoVH1sNfIcHeNwfa6/9zdVappwMknkJsVz19HvFpgJSpO64PIN5G+fAp30Hc8TziHS4miFhheJbjLMMzHB8POFPqKGKWi6TXtSriJcT9MzH5bAzzHIK1I08t6hq6zHpRdu2aYdJYuk9Q/881bzZa8Xrx6fLmJo/iu4/VXnfH1BB/rmu5ScQvI77m+BkmfxXxvcZcJY14L0DymZp7pML5yTcW61PvIN6JuGr4halQvmjNlCa4bXJ5zj6qhpxrujeKPYMXEd+q00KR5yNAlWZzrF+Ie+uNsdC/MO4tTOZafhbroyXuR3Df08bLiHsQf+ja6gTPWVimZl7l/oUrjl8OcxDWLbNU5D6JRL2gxkDu16fGuC054OMhclsyXTOOFEL+kmMGs4i5kfNuQ62EnBuam8tzP+Q+tSqhz9SuqpZlvR1EfBiOJTSgYMMM7jpYsAEyqJCHDL4dcFFTAwNMlFDUUpQYiadhDmXteeWAw3HEmA2s15k1RmnP4RHuhBybdBOF7MfnICmSQ2SYjIBM3iRvkcMki9IRcnDTthyLz2Ld2fTzPjTQK+Mdg8y5nkZfFO+se9LQr3/09xZr+5GcaSufeAfAww60mAPx+q8u/bAr8rFCLrx7s+vqEkw8qb+p26n11Aruq6m1iJH6PbWGv1VIY25mkNE8PkaQhxfLIF7DZXx80HD/A3l2jLclYs061xNpWCfoB6WHJTjbH0mV35Q/lRXlC+W8cndbl9t2SfhU+Fb4UfhO+F74GWThknBZ+Em4InwjXIyd1ePnY/Psg3pb1TJNu15TMKWMtFt6ScpKL0ivSMXIn9QtDUlj0h7U7N48t3i8eC0GnMC91dX2sTivgloDTgUVeEGHLTizbf5Da9JLhkhh29QOs1luMcScmBXTIIt7xRFxSBxnuJWfuAd1I7jntkyd/pgKaIwVr3MgmDo2q8x6IdB5QH162mcX7ajtnHGN2bov71OU1+U0fqqoXLD0wX5ZM005UHmySz3qLtDqILDvIL+iH6jB9y2x83ok898GOPQX3lk3Itl0A+BrD6D7tUjWh3fis58BXDigN9yF8M5PJH4B8Gr79/F/XRm8m241mw/wvur4BGDj42bzn+Vmc+NL9L8GcMn8F1kAcXgSteGGAAAGzUlEQVR4Ae2dX0wcRRzHf3vcX+AuHBxaCpYWy4lyKEX+NfVPAxbTlhdtjFFjjUJbX+Sx6JtpU1sTo0nf+uhD09QYH2zVGP++GMFK0wjXEhIpnBSoHgUKwbMI6/wOzjvoDbuUnZm9u9kEbnd/c/P7zec7OzM7OwsKLG/BYNC+pWTzEQWUV1RQKxVFyY3Z5OfGCaiqOkvYBgnbs6GR0TOVlZV3MFcFf4XD4WKnLesiKEo1HsuNMQFVvRKZX2j1+Xw3FKz5pSWbuyV8xtBXZ09EGB4ZbVBmpiffIs3N6dV2ecyeAGmWOizY5rN3JT0kI4Ds8QqYkR1uMjzsz2HHbJHw2YOmeUD2FppRnudDQArAhzPVixSAioaPQQrAhzPVixSAioaPQQrAhzPVixSAioaPQQrAhzPVixSAioaPQQrAhzPVi5Vq0WnY3XFZZ8p4ssI8G5x/NwAWMhWY6ZuQK+CvqXm41H8709lHyy9EAPT8xc8TUgBCQJgAP/VOwdTMfMaLIEyAhUWAry/dkgKIJCCbIYANj4Jeeub+NTUcCM1Bz8BM0jShmxHoG5yFQFnmroBRZm9PqUnpGHTy+tjf8PrJa9Tc9jYWQOfLpVR7uhuY9wHbilxQXuKicvzh8iTM/bNAtae7gbkACLClroDKMXJnEb7vmaTa093ARYDmx72w1k3vl13hdOdMLd+GO2FqzgmGfI8N6h72QPfV5He/V4fm4NueW5DvtiV8y5y7NX63oYEx74Rj0X5HAB//eCh2mLKfP56uMTR2Lk0QRvxEVR64HNzcGQqJZWbciDjsFthd7WVZlpTMm5sASKelLj8lIbEMmqsA1eW5gM8C5BYnwFUAshYS9tTKqyCOX8B0tGyGEvELEGArmZrwP5C9MooMPuLaBMU4y6sgRkLAFYCum2q8kCVE+njBzbInBANOTdRWeMzCQGgcQgTAEstmaEl3YQLg1ES2U5h7obU+0bkwAjg18fRjcmpCmABYC1rq5U2ZUAGqt+fCfd7UmZpY66FSYrOynn2hAqTa1ERervHPr4QKEG2GUmiGtHKb8ctnhAtQuil1pib21Bk/aBAuQKpcBfgs+CkGozZTCICrJsw8NYGDhWNtZevpW3WnNb5X0e06ntBLVkPg1ARt1UQ8Jb89J7lP2UEeIDWT5xdNO8iyGhZDIFIcUwiAWJ8l9wSiBdhe7Ioun6knlSFQlgM2K/sGwjQC7AosTU3MRci6dU6b122F2oc8BLob6gh0vBJ5b6YRIDo1QVZNfNXF7s0Za5YSrdlYw3GhGNZ4vBcRuZlGAISAM6RGC1BS6IB6AhuBY2fqcmSJ5H2Xb1MJEJua+HPy3l9dyiEzrDV+zzJ0N2zKd9xVaDOdMJUAsamJs9/c1M0IW5CKLdnRGo7t+CNbc8iQVmyzojt4ktBUAmDg2AxpCYBrixA2/tRWuMGdbbpi6NbAdJHHpiYG/pj7vxB2m0Lab3cUNnaguLIiXTbTCYBg8Z5g/t/FaA3HDrTqwVxw2NiPyUWIym15uojCpYLP9KxWqUB+OUYpgGCxpABSAMEEBLuXV4BgAYQOQ/v6gtDf3w+KxQKPVgWgvLycCw5RfpMVTogAvw8OQmfnO/Bbb++KmBobGuD9U+9BUVHRivNGHaDfo0ffht6+vhVZ7mxshFMnTzDzu8LZqgPu9wGhUAgOvPAiTE9Prwpl6RDhf/bpJ1BQQH+7PukXNU6K8qsRFv8/2HTs+AkqfAx2bGwMPvjwI624120X5VcrUK5XwMTEBOzc9aRWTOB0OuHXX7rAbrdrptWTQJRfPbFxHQUNDQ/riQkikQiMj4/rSqsn0fWhIT3JDPerxylXAVykZuvdXC7jZjyz15GXkX71lJWrAH6/Hzwe7TdjSktLobCwUE/8utLg8FaEXz3BcRXAarXCofY2zbjePHJYM816EthsNmhve0PzK0b71XRIEnAVAANCAVr376PGdvDgq3Dg+eeo9ns1HD7UDvv37aV+nZVfqsNlA9dRUCwY8u+b4PMLF+DcufNwjdwJW8idcFUgAK8R+M3NTbFkhn+K8rtWQYQIsFZAmWbj3gRlGmCt8koBtAgxtksBGAPWyl4KoEWIsV0KwBiwVvZSAC1CjO1SAMaAtbKXAmgRYmyXAjAGrJW9FECLEGO7FIAxYK3spQBahBjbLfiP5Rn7kNlTCCB78jKPEqTY5WnGBJC9RQX1LGM/MnsKAWRvCY2MngFVvUJJI0+zIkCYI/vo64ThcLjYacu6SN5armblT+abQIDAj8wvtPp8vhvRURDuDI+MNpBOoQNU6JYdcwIsg3ajTJfYdiBrZI5Z/weGHZt6DygPGQAAAABJRU5ErkJggg== + + + + + + + + + +http://m.market.yandex.ua + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ur/amazon-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/amazon-in.xml new file mode 100644 index 0000000000..05c5311e31 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/amazon-in.xml @@ -0,0 +1,15 @@ + + + +Amazon.in +utf-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACixJREFUeAHtXQ1MldcZfuRXlIr4A1MoYAf+xKBswlKmdTJ1Q7RZdc5kM7XWsXaGWk2WTDPc0qlzOmZqnHGZoxrntuiydB1UXZSRqS1h03WTVdDa+osov/I3qAicve93ufTC/eHc673f+ejOmxzu933n/c77nuc5/+fcC/CJjKDLXArlFFopCB38igFjytgyxoz1APkM3ZVQ0KCbgwFjzZgbwmxo8M0B3rGAM+YjgunPdyhspKDFXASeInPVTMABCvHm2tbW+hCI5eaHO4cnNCRKEGhjArhd0qIIgSBFdrXZPgQ0AYqLgiZAE6AYAcXmdQ3QBChGQLF5XQM0AYoRUGxe1wBNgGIEFJvXNUAToBgBxeZ1DdAEKEZAsfkQxfZ9Nh8SEoKwsDD09PTg4cOHPqej+sVhQcC4ceOwdOlSZGRkICUlxQhJSUkIDuYNPaCpqQm3bt3CzZs3UVlZiVOnTqG8vNwgRzXAMvYdN4otdT1//nxBYIpHjx4Jb6W2tlbk5+eLqKgoS+WJCBnsj9ODwQqm38fHx4uSkhJvMXep39zcLNauXWt6HlwA7c4HaxGwZMkS0dDQ4BLMx3m4b98+dwCofm4dAhYuXOhTcyNLzObNm1WD7cq+NQiYNm2a4OYikNLZ2SmSk5NdgaDymTUIOHnyZCCx70/70KFDKsF2sm2JYyk02sHZs2dlRmyoqanB4cOHcfnyZbS2tmLq1KlYs2YN0tLSpN5vbGxEbGyspYaoTqx40YP75d2jR4/2l1BPFzt37hQjR450shkUFCR27drl6dUBcenp6U5pmJ1nB3tqmyAGr76+fgBArm4KCgqGBI0mX65edXq2YsWKIdNyACigusoX41JTUzFhwgTKr3uhzhnbtm1zr9AXc+TIkSF1WIHmGVJ6ZigpJ+DatWtG+9/d3e02v8eOHUNbW5vbeHtERUWF/dLjJy9tWEWUrwV1dHRgwYIFxrpOXFwcEhMTMWXKFCPwek9oaCi2b98uhVd7e7uUHi/kWUUs4wmvat6+fdsI58+f9wkfT7XIMUHqdxxvlV5bxxM/wEC9rVQqsnpSiT2mkmVqgEw+uDnicf/MmTMxY8YMozOdPHkyOEyaNAkTJ06UScZSOpYnIDMzEzk5OcjOzjYmW1Zqv/3BpCUJCA8Px+rVq7Fp0ybwMPXTLJYjYN68eSgsLAQtzn2ace/Pm6U64S1btuDcuXP/N+AzC5apAVu3bpUe77PjPJLh/V9enKOlDNAmjjFnWL9+PUd7FCuNgtjRgK51yKS/aNEiwkRO6urqxMaNG0VMTIyT39OnT5dKZMeOHU7vyvgZCB3lNSAiIgIHDx6kvA0tpaWlWL58ubEM7UrbfkrCVZxVnyknYOXKlcayw1AAXbhwAcuWLQPtarlVHY4EKO+E161b5xZQxwg6YuIRfNYdjnMEpQSMHj0avBs2lNy5cwdnzpwZSm1YzoSVEsCTLJmFMdllZj41JyPR0dEyaqboKCUgISFBKpOe2n3HBPj4oozwsrdVRCkBtL8rhYNMieWZ8+LFi6XSmzNnDkaM4PMI6kUpAXTmUwoB2kQ3JlmelGnDvv+wric9juMtSVmyhkrLH/HKJiVZWVlSEydW2rBhg1s/aQlDOh274qVLlwQtb7tNk4A1K840Q04Zos140dvba8fE42dXV5egFVJBTUd/OrQPIPbu3evxPU+Re/bs6U/LRMAH21RHAGeaRjieMHKKq6qqErRJL06fPi3oixlO8d4+sMAZIbUEcNOiUmjkNLhEmn2vloDIyEhx7949v3Fw8eJFo4bIJLh7926zwXZlTy0B3AzRdqN0X+AJ2OLiYkGza8GkXr161a0qnZ4QtGztCgwVz9QTwCTk5uYKBsZX2b9/v6DFuH4A6UyRqK6udkqODngJCzQ7/X5S3q1BAPvB+wJXrlxxAs3Tg7KyMsHfJXOVDzo5MeDcKa0pidmzZ7vUdXyfjg2J1DiI59IgXsmCePXLEHn0mZMKkTDOv3jxdJAd8lqSY4DrDUBvr9evenyBj56sWrXKCPSNGfCCnaPQsBXUvIAPbxUVFeHEiROO0U7XPOs9cOCAsXOWl5dnfDop9T1IiQW+/xXga3TSfWKkOy3gj+8B3/iV+3hvYnwm4P3XbL9Anf8W8Na/vTHpnS4f3OXzPnzssKWlxTgjSjXCu0QktHetAL5HKxkhEmsDnTSBH/WKRKISKj4TkDge+BNtv37uSeDvN4D8PwN/rZKwaFGVl2lVvPVj4E4Tfe+4A2im0Eb3wUTIdPqZ7Re/CLz0jM35FtoTGrvJPxnxmQA2HxEGvLEG+GaGzZmKu8AvSoHf/QPo7PKPg1ZJZewo4MHrNm/OXQO+9HP/eCZR4dwbYpC/VQhsfpP6AmoVZtEq76+fB+7uBn72dSDJ87F/9wkrjmG/f5ADHH8JGN/XF0QTAXZ59yP71eN/PlYNcDSfReeo3ngBmEJNk12YlGI6sv8b+rcFpyuBdqrSVpXYMcCqdFttznzK5iX7n7ETeO828PzTlI8Xbc+X7gdO/sc/OfEbAezOKGqSfvIcQMM2BHHKDtLVA5z9AHibCHmbnL9e7xCp6DKaBljL0wj0LwBcgIIdfL7RCLz8W+AMFRyWQmpqvz0XuEnPU34IdFN+/CF+JcDu0NNUgn65Gkjz8E2gqvs2Mt75EPgnlbC7D+xvB+6TxvCYmwzMozD3swCN9Z0KSncv8HoJ8Fox0NHXj4XSb4LcK6DmiAh79bitn/OXlwEhgJ3jDSeu0j9+FphG4+uhpLaNiLhlq+4f1gFcAm80ADXNQA+B4o3EUHOSNJ5KaozNNo9iuFA86WErmFobFF0CflQEVFQPtEYTMmPEV9NCaW79hJiBWr7dBYwAuzs8jHshkzrqbGAqAeKtcDvc9F+gjgh60GHLvL1kcjMXFgJEhtM/QKDdzbER9I9ZougZlVhZ6aH0j18AfvoX4H0axbkSHm7TLNgY+ZRfd6Xh+7OAE2B3jWsEt7PfnQ9wieJqrVLutwJ/uAjsKwU+qnfvCfcT9wuAvN9TP/COez1fY0wjwNFBHnFwx/fsLOAZao/NIqORatKb/wKOUYn/Gw0IZJZRRoYCcxKBd6mvCoQoIcAxI1HUbHx1JpBNIZ0yOmOS3HKAYxrurhvagTJqMspo3M4Alt/w3+jFnU1vnysnYLDDXOJmxQOfT7B1oHFjgTjqPGOfAMYQWWOorQ+ndp/7ho8f0XIB/VxcIwFdT4E7bW5OOHCH/kHt4NStd285AmQg4o7d25GRTLoqdIYlASqACpRNKktaVCKgCVCJPtnWBGgCFCOg2LyuAZoAxQgoNq9rgCZAMQKKzesaoAlQjIBi87oGaAIUI6DYvK4BmgDFCCg2zzWAtru1KEKgjQmoVGRcmyXsmYBCjYQyBAzseVeshALtsupgIgaMOWNvCJ0d0yQQBmYVQgafMR8gzEYuhXIKdGzJNGfMyrRqO4wpY8sY95f8/wEKvBLprcz3zwAAAABJRU5ErkJggg== + + + + + +https://www.amazon.in/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ur/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ur/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/list.txt new file mode 100644 index 0000000000..1d848c8110 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/list.txt @@ -0,0 +1,7 @@ +amazon-in +bing +duckduckgo +google +twitter +wikipedia-ur +yahoo-in diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ur/wikipedia-ur.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/wikipedia-ur.xml new file mode 100644 index 0000000000..9eb978609f --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/wikipedia-ur.xml @@ -0,0 +1,23 @@ + + + +ویکیپیڈیا (ur) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://ur.wikipedia.org/wiki/خاص:تلاش + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/ur/yahoo-in.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/yahoo-in.xml new file mode 100644 index 0000000000..67e95519df --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/ur/yahoo-in.xml @@ -0,0 +1,22 @@ + + + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAACJ5JREFUeAHtXWlsVFUUPm9mOt2gLWKXIFtLKRZIGoIS/CEJa7ASEExdECPYVhYjiAlq0CAgIJBIABUFWkqKEaGiEKRAoAIKBEGBmNJCW2ihQGnL0oW2dJmO9wyly3DPw/bN2+SehPS9c+bee873vbvf95CgSZzglOIgPZ7dJjgB+rO/nR/YxF+PIFApAWSxnJLSIDZZAonBDMB0AHFwKMwJNd8zEkbivRB1EWDgZ0jgOyUNht+w4JMvwFcXcPfc8UFvwlySXob0RADnBvcfiXv1EWDNT6JFAie2+0L0QSCBNUGuDlef4h/zUhF7C8NAjHb0exA6IwFCdERAEKAj+Fi0IEAQoDMCOhcvaoAgQGcEdC5e1ABBgM4I6Fy8qAGCAJ0R0Ll4UQN0JsCmdvmDYoMh8tlAuH6hCipK61xbQE9084GQcF8IjfCDAxsK4cKxO2q7wc1/8LgQwH/Fl6qhtKAaHA1OsNkt4O1vheCevvBPxk3I/l1d31Qn4OKpcpidGgOdu9q5IPSOCYAPBx+FRgfXrJrS5m2B+K/6Q0hvP24ZJYyQX1Zc5No8qVS9CcKnPnXeedJnJGBUYk/SrpZh7Lu9SPCxzOTZWVBX3ahW8c35qk4AlnQo5SpkHr7VXKj7xWufR4F/F9UrY3OxASF2iFsQ2XzvfnFyVzH8vbvEXa3KvSYEoOfrp2dCfS2/nQl40g6vLIxSJUBepm980Q/8A714JqitdsCm2ee4NjWUmhFQlFMFO5bRberYWT2he/9OasTYJs/IIYEwYlr3NrrWN2mLc+HmlXutVapea0YARrFz+UW4dv4uNyCrzQLTVkdzbZ5SSizahK8HgCS5TuM8lG1hViXsXpX/kF5NhaYENNQ5Yf2MTDKemNHB8Mz4ENKu1DDi7R5sSBxEZrNhZiY46l3npcjfeNqgKQHofNaR23BkyzUyjqmrogGHiJ4W7OSx7afkcOpV1cf8vLI9HymvFDdd6rxsqCqvd9Pevw3r4w8T5oVzbUqUk5f1A+zseXL3Tr3sUJmXxlM6XQgoL66DrZ/kkDFMmh8Jwb19SXt7Ddjxjn6Hnmv8MP8CVJSwWboOogsBGOf+by/DpdPl3JC9fa2sQ8bzwcoFO97EdQPBwo6g8ST3ZBlbDrnCM2mi040AJ5tkbpyVCU4nv9MbMiEUcB1JqYyZ0RP6DA7kZuNwOAE7XvRFL9GNAAw4989yOJhUSMYev7Y/ePl03MWAYDtMXkp3vPvXXYb80xVk+VoYOh6dh7zDvqC6gu6QX/ooosMlTVnBZrxB/Blvxc06+HEB3Q91uNB2JtSdAFys+2lJHun2xI/7QEhE+zvkqOeCYPhUesa79dMLUF3WQJarlUF3AjDQ9DUFUJRXxY3Z7mOF+LUDuDZKabGyGe839Iw3/2wFHNxIN31UvmroDUEAzpA3f5BNxjf4xRAYMjGUtLsbxszsBRGD+B0v/nbTnHO6dryt/TUEAegQLv+e2Vfa2rc219gh+3Rij/YjJCjMDq8voVdWj20v0mXGS7ltGALQwZT3s6Chnj8m7NrdF15d1JeKo1n/1pfR9FJzjQO2sFm4kcRQBOC+cfraAhKf2Dnh0CuGfp1h4Iiu8Pzkp8j0u1Ze0nSpmXSklcFQBKBfaYvzoKy4tpWLLZdWqwTTvxvY9G5nix6vrF6Sa6m5rbbl7mZhDexcSe9HtPxS2yvDEVBT0QC4NkNJ1NAu3OHluLnh0D2a3tDBfWkt9ngpvym94QhAR39je8h5p8oon13Lyn6BLXvIXXv4yO7xZv1xG45vKyLz09NgSAKALQ/hqQRKgkK94c2VTzebceHOx7+FkGYDu2hsdELKHDqv1r/V49qYBDAkck+UwYmfb5CYjErsAdHDurgW7IZOCiN/l5FcCPln9F3vIZ1jBvai9h7+cqRcKo1suASxJmsYeHnzx//Xc+6yztcCoeH8w1W46fNe3yP3T+Rp5HN7izFsDcBASi7VwK+rC8iYukV1IsHHRGmLcg0NPvpoaALQwR1L6WEp2inB2rH368uU2TB6wxNwr9IhOyylkMS1Ja1POFC+yOkNTwA6f2jzVXL7khfc2f2lcHoPva7ES6OXzhQE4Jbhpv84lHQ0NELKXOMOO92JNgUB6PT5o3fgeNqjJ1P71l2Ba9n8vQX34I1wbxoCEKxtn+W4JlYUcJW36mD7Qv23GSn/eHpTEYBP9il2dJwSPPxbdUf/bUbKP57eVARgAJmH6PcMSvKreTEaWmc6Aupr+Rs2iLKFLVebTUxHAHXCDYG32gQBqj+AeNSQEkEAhYwH9RJxxhOLsIga4EGkiaxsbOuREnzLxmxiOo99OvM3XhB4PJBlNjEdAXLtvKgBGjx+ckNN0QfoTIBc7dDAtQ4V8b9qguRqR4fQ0SCR6QiQA5l620YDHDtchOkIwBNwlIhOmELGg3rq/A8WYbPT5HjQBY9mZboagB9TosTGjqiYTUznsUXGY7nmyajEyIRjTJeJt1pdzuIhLbOJ6TyWW4wTfYAGj5/cMFT0ARoQILsaKjNE1cC1DhVhuibIzr4jQYnoAyhkPKi3+9EE4Dc/zSam89hL5mNOcs2TUYkxHQFyK55mnAfQ20tGfWSa/MJPzdRWNbhe0MBagaclzDgKMh0By8f/BfeqHFDJvnbS/J0ftgQUFOYN3jL9g1GfJ9MRUJJf8zCW7CWrsiL+u8UP/9hYGtP1AcaCT7k3ggDlGCrKQRCgCD7liQUByjFUlIMgQBF8yhMLApRjqCgHQYAi+JQnFgQox1BRDoIARfApTywIUI6hohyQgEpFOYjEShCoxPdNzPNauZJQDZgWsccakGRA3x4Xl5IkJzilONh7gP0d+bhEbYQ4JZAy0uCF0awJkpwS+E5BhREcexx8QKybMGfYN8n9mpAez24T2PI6/vcV9BdSHyQSf9uDQGVTf5uUBrHJ+OBj4n8BJ5EPp7ErQgIAAAAASUVORK5CYII= + + + + + + + + + + + + +https://in.search.yahoo.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/uz/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/uz/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/uz/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/uz/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/uz/list.txt new file mode 100644 index 0000000000..c4a0ab5085 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/uz/list.txt @@ -0,0 +1,6 @@ +amazondotcom +bing +google +twitter +wikipedia-uz +yahoo diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/uz/wikipedia-uz.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/uz/wikipedia-uz.xml new file mode 100644 index 0000000000..217879fa32 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/uz/wikipedia-uz.xml @@ -0,0 +1,23 @@ + + + +Vikipediya (uz) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://uz.wikipedia.org/wiki/Maxsus:Search + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/baidu.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/baidu.xml new file mode 100644 index 0000000000..eb806c6b5b --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/baidu.xml @@ -0,0 +1,28 @@ + + + + 百度 + UTF-8 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozQTZEQkQzRTNBODUxMUU1OUE0RDhCNjkxRkYwMTQwNCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozQTZEQkQzRDNBODUxMUU1OUE0RDhCNjkxRkYwMTQwNCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Rjc3RjExNzQwNzIwNjgxMTk0RkZFQURGMTU5RDlDM0MiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4A3vL4AAAWzklEQVR42uxdCXgUVZ7/VfWdzkFCEshBwn3fIkc8OBREnUFFYRxFPJblW89RcWf8Vtcdx93VGWZHHWccb0bxVhDBCxXCYRDCGQgQyEUCSSck6dx9d9W+V91JuuvoK6cx7/seabqqXlX9f+9/vv//NeNwOOBtKtLXkn4H6fMw0LqjVZD+KenPkV5Fv2C8ACSR/vkA4XusmUm/lfTvKAB05u8i/fIBuvRoayF9Fkv+uWWA+L3Sokn/E+uV+QOtd9r1FIBxA3TotaaiAGgH6NB7Td2XHuZEaSV2FtSgvLYVOhWPacOTsWjCECTFx/ZbAKgVVEb+ZvSqcVxjxhOf5eHTIhYOjvE+Gek8j1QDh8cvH4S1i6eDZZkBALq6HT97Dis/KkNJM7GGXXbvt7wXAfqHSEm1FneNc+Pvq7OgUUfOtEdPF+H7EivON3MYHs9i6ehBmDhq2M8XgPNVNVjy5lkU17sBzilzBgGCZzxYaKNw/2QOz6+6LOz7lFVW44ltZ7G5hGDspvfiQNgJOrUGK4er8PRNY5A+ZPDPD4CVf8vGlvMawGFvn/BiBvD7rDbgg6Ua3Lzo0pDvkX28BHd/UopKu86Hw3yaRoOMKB7vLE9D1pTRPU4DtrdY74ucYg/xnSLiS6aIz2fCJf9zwAKL1RbSPbYfKcYtH55HpVUlT3yKrtOB8mYI5+07UfTzAeAf+y+Q9+c6ZrnvX6XmdiG/QYNNP5wIOv4xIu/v3lKFZge5B+f2uQEvQpd0zoVaO4s1W02oIGKx3wNAzc1dFwkhXE752c4E4Aa3Ex+dsgQcv7mlFfduvYBaq1feiwmuAG5RI4unthb0fwB2nqyEk2P96cJLpYPsZzKbc00unK82K46/fusRHDZrBbBC14aku2zYWMxiz9HT/RuA/cV1HvMyGEFkG48GtxbHiytkj54qOoeXT5OxnTbF65UbL/geb+6v7L8AOJ0ulLSofOSyAsH5AMdYNc5UNcqO/+qeCjQ5RLKeD3Aj8THCNTsqVDDV1vdPACw2O6pbnMoyhvelE6/IHRV1LZKvqwnRtpyjusUhM5bPF37giu5BdMZFomLyKpv6JwB2qOFQGUSWCaMwQZXt02ar1KzMLTLBRBWvYF3xCpfzCvfgO46pWBRV1vUIPXo+GEeJw/M+mjey+A4jc93xRr1gzQQ2o0JTOo0WV//kAB3jhp6zkjurpCKID6AwRcfiovWSsSurqgT9EFDJhtii9ar+CYDRYMCQWH0IokFENNGxtEHSMVqd4RFZsRHxODotuX8CoFarMCqWF4JhfuzPMwpigZHSlIiZcSlxClCFLmbkT2EQp+ExJdnQf/2Ay9K1/rcWB9/kLKI2y5L4DwkaJ6aOSpeMa1BHul7A+5m4lybxyEhJ/GkBwBPFyvGhsf/C2ZOhZ90eZSzWw0yHQ+TnIbdFEYjumDeUQWqyNHycNjRJiOtEotLbm0qDWybH9ZxE6MzFrTYntuScwJfFNpTWWcExKqTGG7Aghcctc8ciLTlB9rrxKfG4KtWNL89rPfGgNmKLg0G8105vWxMQDqlw29Ro2XEnxpCxGPJKvEvBy2XkpZBwf0bgrhFRTiybO6XvA3DwVDHu21aHvDqHZ9bxKuElj15sJYDo8MeD+XhsthEPXTcdapXUorh/zmB8WdFKXtop750ycrOTxSWDOCzLmir7TDMzBiFWW008YcZr6opmOaMs9z3U0OD+GVokxkX37VDEvrwz+OW75cirsXji7NSp4t0dNr7LhlpiRz++14bbX9mD5larZIyr50zF7SPJtRpdB7F4BV3p/T+risJ/LkiETis/b0YMS8GCDNbDBWFTQo0sIvvXLpnWo/owbABM1Wbc83kdzE5yqdsdSCkIQHxWrsXqt47B7pBGJp+7eQqmRJPzNPrgRorOiN9NdeG6rAkBn++hOYmCpdU+q0NSASwSYw148Zdp0Ot0fRuAZ77IQ0kLJa5Luozoa7G0NYeNyHoeT358QDLWkMTB+OjOCZgcRzhBpVOwgFQCQA+Nt+H3v84K+nxXzpyIx6bDM15IFFAhWqfGW9dEYdq4kT1uEYYFwPGiOrxbpBFmtjSoFcDAIOe/dILB94dOSQ6PzkjEt/ddgnunMYjSqwUrBCqtRzQRsTAqxo23rx+EP9+5gEzq0Gb107/KwrqZGu8YGgXHjry6xoBMwoFbbkvH0jmTFcdzczysTg42Fwee71oAwlqUf+ydnfhrvlZ+fTVQWIcXPDBcNgTYue5KRUKW1bZg97FClBExR+X81BFDccXkkTDqNRG93I7jZXh+RzFyTMRiczNCeovQXA6kGIFVo1x4+MYsJMUZJdc2Er312Y+nsf20GUXOWCE2pCZGQJKBwfToFtwwZzTmTxpG7AK2ZwBottgwe/0+FDcxHoUbilfpBwovZDVsXxmPhbMm9iibl1XXI/98DSov1oPmdmUOScDMscOQEK2XPf/bg6fwm6+qUGzReZY03Q4v43g9eMqhxOBYlOLA+uWTMWX40O4HYM+Jc7j67XPShZSQ2YA0rR4PjrXj/+5ZhL7atv5wDKu+tsJmd3hzlRhl84yIy0F6Fm9fG41rs6Z3rw7IPXvBI58DrugxgbEhM+l4na7PEr+4rAIPZlPi27weNSNyw8XKwYkGqwt3fGPB/uNnuxeAkxdtHjs/0lgXPUaUWZ2bg9PN9UkAXsgugalZnEkRPHLaREB45ItytIaYrxQRAOfcCUISkyS1xneG8wFmP+9BgYYv7E53nyN+RXUNNpfwHnmvEKeTfMd3cMLhBgPe2lPQfQBcbLb7z2Y+AAcEOGZ39U0O2FtYhxoL5++V8yG8U9v3RGT985AZVpu9ewBgGJEoZAKInwDHVMQM6Ytp5gfKWvy9ZybAO8l9JgCcaNbj4Mki4qOGzuEhB02SjFqchSVM41+aaxKt00CviWy5r6bBgryiMhRYjKhucgiR0uQYPcYbrZgxKgWJg2IiBqDARNNQOlks5HYjp6wZSYkXMSEzpWsBGKmpR45aL3LCwtTIjIo4Mi7o1OEBcOB4AV47WIfvznGosnLSmD/xmFP05/GLTAb3LRyLSaPTwxqfmpwmi1wENQIgL1pQYjKHDEDIImjOMGN4AS65RszYCdGhs2cFcZzufm0PFm6sxsYCN6osTvkFF/Kdycri9UIdLnuzFE99kBOWLKa5Sq1utgsA4NHi4NFkC31RKGQAFk4fg2jWgUjTSNoipFmjE0I6NfvoGVz5t6N4r5DxFFW4nYEJRE1klw0WhxPPHQOWvZKLyhpzSPdyEaPA5XZHTHS/uUBMbS4MMzZkAMakJWJhMiPEdCLzuVkka51YMG1U0FO3/HgaN31Sg/MW1msW8mGBTPNCd1cC1796DGWm4OnmbkIwLuLJL9Vz4TBSWJGkh+ZnkAvUQQx+JfGjxopxRFYPHhQ45HG0BGu2mWGxO4Ks7wZ5BpcDJxs1uHXjKdTWB04zZIloZbrIMKPBOU0YOi4sAObPHIm7xnNCGDcsV5g8VJpRjXVLAi+m1JgbcO83lWhyOH2y58J1u32+J9xzuE6NBzYeC3hfSjCNqmsSsWL1GsRG6bsHANr+95bpmJVIQFDroJzE75vmoYJBr8fLS+KCFsI9szUPhQ2MzMznQ+MyuUbE0eZKFV767EfFU4wGPWI0fOeNDKKH0gdHY2gQLu8UAAmx0fjkzkm4LMnhAYFh5L0TYcFDS2Y+j0+XxeDaeYFD0N/knsDrp1hPzVhYXl4ISpKA8PRhFkdPl8ieodNqhOf0ByACMUsm28TBKmQmGrsPANpouskXD2ThD/MGIT1a41l1omDQODkxNRkickbEMnh8hhE/PjwLi2dPDjheZXUNHvu2XlCGkhfkO8sMnsy6JrsN939ehqaWVtmzZqTFiopGwkzwJeAZiBSbPiyOTNLQAeh0mWpDq4O438UoqqqDXR2LeLUDY1PjMXX0MBj1wT1LWrDx61f3YWsZLY6wd87MDcYJxJFcPYbDG/96peTo7rwiLN54Ich6R2AfZ2GyDdv/fUl4NlRvV8r/9p3deOEkLVe19swNdUY8e6kT65ZfIbHfr/lzDnbXctLiwVAaMUzevS4KK+eHtzDTa2WqtK3feggv5KuUie8kxLC6OjrN2W8LZUcgooVjdgue3M/jkz35IkONwe8XD0aU2rvsGKh0VnyMcNayTBdWXBl+TlGvccBfvzqCx7JbvZWMvDT0S7zT5TNTMHvEILTaXUJmArXXc0rqkX26lrw0K433KVXYiz8TYscYjPh0eQIWzhzj91wfZ5di7bcXCNa8t9iDVx7Pu49FVjKHD++aSqyf8HNKe2W7mr9sO4zH91r8Fz/Eho6bxw1Tk7F6TprftS/tLkN2fo3nyUM1lsSfiY/RbLPiri0XsMmgxqwJI9oPr1w4AqOGMvjvHeewoxywMXpPzZmwtRLTUVxOZn0cY8U94x34j5tnIy7aGBEtehyA//pgL549ynQU0kl4u6MewCkTH/BkYPMK0z6MRpStyarGyo/KsWWVWjAa2tolE4Zj8/hMnDlfjR/PmHDKrIeprgE0FqglhkVKjA4zEjgsmDYZGSlJnaJHjwFAQ76/ef8INpziAxRQM6GZ+nwoHnEIjTzHhRYNVrxfik23M5jsU3NAc5fGZwwVene2HlHCNeYmrHh5FzacdnfI/AjCXF1Bc8lAnBOlzTxueq8UxwrLe1wcdzsAF0y1uPnVE9huMgSoXg/foOmUPyAGgUyKsiYON7xbggPEp+k3AOw4WowFr+Rhv5nzyHy5mUvlPF2k9+0u2t1E33UHBAq1aHRRp5XBjYQTdh7tOU7oNh3wl60H8NQ+OxwutcfD9a2AoXSl9jz5qzdqEGeQPkarw40oXZAIpdMLWLt14zExoQ1wHb2vm5diQmsOCAh1DjVu/qQCrzXWYcWCGT89AOjq0qMbsvFKocGTws6LglwuT+rHnLGDcScxMReOSUByjNbrCvDtBdiURNGBACBEnEuunZIaI1ynJoQ3EN+gvN6GTXnVitJn4cQkZCYYyGN4QKC+RQvxM746WQMbBYdYR612K1Z/7Ua1JRcPXDf7pwOAw+nE2o2n8f4ZDSGQjHdLZvWQeD3+tHw8Vl2aKrx8xGKcALkmKx3/Ms9/AX53kRmbjlW1B8j8riHA//bqEVg60d90NDXaMbM0B1X1ZMKoPIvzbqcDj+5hUVa7G8/edrmn6KOv64CHN+wixG+QNzMJ8cenxWDnw3OwenZaO/F5Xtnn54Os7clVZbo5ufBph+8gp1Y4ocJT8i15ZitezGex8h+HUFPf1LcBWL95P94ojaHhTRm5xGFogh6frp2JiUP9C+AYRnmbLEYCkhigUJUuE4Ht6j2fGA9fXHBgyd9zUXiutm+KoN2H8vH0QSI/7QqFG6SvXz4Bk7zEbyNoG4GzC834Kv8iYRK+XWo4iC554MpMATB6Hr2mHSzGX8L4HVO0djphURFxdLJJi+XvluLrNUD60MS+AwDNv3liZw2xdlTyL0kU26JJSbhtVqpkZlvJsUc2F+DVXWUe68SXiHY3rhmf1M4xjFie++RRhVa65DGTIobB5cSZZgYPfpyPzQ/OD7lcqttF0Ac5Z5FLc/6Fgmv50M6/XT4Mcumg6yjxvyn2mI4GorhpjRjtOs9fFRtYETMRrE6GzQm8Pyd8WWnA29uP9A0d4CRm5hsHqzuUrjiTmGi2pHgD5o+RLsbnljXi9b3E4YnSeADgw4w4BMok5EUKwq/AhQlwjcz/xe/kJIr5SAusdkfvA5BbUI5DNR4HRjb8S+Q43VYmwSgtsvvudC1cRMzIsgYThFiQWpnS68W7cEn3UvFT7nLZ0HLvxLtxslGN7Qfyex+APWdrRBsvSWegUcMKTpK4HatsltGT4o2b+MiCcTzkC0Z4fy0g0StKG0aJLWXirG0729r7AORVtEBRdjCBQ8u0rEeajy++hoksSqdkeTLyW53Jzng/c0v0OByHwyYHMTzcvQcATUCtauUDE4M8cDMRM3IVMSmxWgRMyAyqK/kwjzNhO3qBxjZZgOq6xt4DgGYTW51BsgcYFpUNdqGSUNyEcECQHXP5IOjK0U92wUzhv4qmZLBaN55DK6eBuaml9wBQEdmvDZZPSWR/bZMdJ03SB71xajLmjUmgzoD8iwYTFwpKWENjOZTjOF+zk0f7wn84jBWg1o1yT+Qp7V0BADHSE6ND2H6YyMltxMsVsz0tU3rjjqmYMGIQhMVWWtRg93aHW/i/y5tnT6/hJWYlLwvP7Mw4LKdOHwWBOnc0+ups624h/0dWBPEyYopRZiFa66bXajoNQKc84XGJemEnFKUZ3LYJ6oeHTFi3aARS43R+bE+93L2PzMU/D1RgV6GZKDWufVbbCMFS4vTyosIruuQqUSiw7981DT9ckYGqZjtUPvEk+liXZMQqiyBezrtjJPelojWGdSAhLqZ3AZg7Nh04XKLApl6WVxM9UGPB41sK8M6d0sSlwcRHWLdouNDDjZV9mV+DRxeNkBzSkXteNW5w2OMpb5spttZYpEW5MKQLft2pU2bonIwYJEWpFHZCZzpmk1aFjTkX8Oim052wPERNq8bOglpsoD8EEUysK0ZT+RCRkXqAM1L0XVJu2ykAUpIH46pUh3QPCTkLUMvi+e3FWP7GUZwzd0EeqFccPPjhKbx3qDKIx8wE/T4sUrJqXDW8a/YV7XQwbhVVeDSXMlgKP31ZMmu35Fbikj/m4Hefn8Hximaio/kw6e4zOBE1dO34jrfy8KsNx7CvpEEIY0dm2Yf6ACxS9U4sEKU0RjyPuiI3dNmLu/BNRdsP5YQwl9weq0QXpcHk9BhkxOt9bHpGkRwaotALqltw4nyzZ+nQl3rEelLr1BifFo0EMi7HK+8yIEoTFRT+0QtNcFKLKViIVaPHmjE2vLzmqr4DQO6Js1j64UW0WB0+QXqFKeb3q0h8+yK9/L48MhvR0Ri1mlUer80HUHoGpe80rDzx/TZ6Z2A0GrDn7mGYMjK9SwDokhWx2VPG4pmKFjySTVPNLaEH0IKlkISpG4Xx2oKD4WRO+5mYAQAjs//ecY4uI36X6IC2dv/SmXhqBuEArS7478MAgRdH+GCEZ0S7hzDBAQqULR3KBiRaPZakOfHUirnoytalWRFP3jofry9ORryO81hGYJSJK473+y6iMB0KT/g9ALYjF506VtE6FvF6NeINKsTqVf7hbta76yLDioAMVHsWKPjDCPVv16U68c7dl3b5vqLdUqBRWG7C+u9LsbnI6flBHaZNLHDyKtGXY7wlqqxag2StA6NjOExO1mHS8BSMTDYiibUItWdtP+pJt4ZptdlRz0ehvNGJwjIT8isakNegwQWrFzhhR1+uI7c/FPnGejZ/jddyeHS2EQ9fO12opuzq1q0VMmUVVdhZaEZuSS0qzc1oduthhaY9xkOryvWMC9GwIJ4ot0SjGsOSEzAy0YhhUU4MS0tBInH3I3F4zI3NOFZqwi7irB2osKHAzKHayoBr/4UN3gs84xfnpyBp4caEBAbLJsRh9bxMZHayBqDXAJANY5MZ6/ZWItKIandlnIk93joCSHkTh3MV1Sgzt6KqwSb8zKHNScxXMhEMKh5D4vQYnT4Uk1JjMDo5pltmfK8D0NvNYneipqEV5hYbWiwW2B0OgRMNhNg0uJaSGIcYvabHnocCUEj+jsZA65VGheCpATL0WqPbROH9ATr0WttKRRD98C3piwfo0aONrujPajPAbyV99wBNeqzRvdR+QXoR6/MFDe+tIX0nlU0DNOqWRn8zfT3p40n/gX7x/wIMABlSS4pAgk9AAAAAAElFTkSuQmCC + + + + + + + + + + + + + + + + https://m.baidu.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/default.txt new file mode 100644 index 0000000000..1ff2bf5542 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/default.txt @@ -0,0 +1 @@ +百度 \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/list.txt new file mode 100644 index 0000000000..bd8014fbd3 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/list.txt @@ -0,0 +1,6 @@ +baidu +bing +google:hidden +google-nocodes +taobao +wikipedia-zh-CN diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/taobao.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/taobao.xml new file mode 100644 index 0000000000..a43e873a85 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/taobao.xml @@ -0,0 +1,23 @@ + + + +淘宝 +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEE2REI2ODhGMkQ2RTdCRSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo0QkUwRjAxREQ4NkIxMUU1ODBCNDk3NEYxRTREODQyOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0QkUwRjAxQ0Q4NkIxMUU1ODBCNDk3NEYxRTREODQyOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMUIxREJDMDZDRDM1QUE2REEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMThBNkRCNjg4RjJENkU3QkUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4OfK++AAAKb0lEQVR42uxdC3QU5RW+s9mdfSYh2YS22KZiqcCxHBARbOHwigaCgKKkgIIVSQM+ooAVU6UNKNgghVSiQBBRREpSUCympEAlPmitD16NPX1QaouliLB57e7szia72/knu9TIzsw/793N3HMmj7Pz+Od+/39f/713Cb/fDzEimaOMOWYyx3dj/xukHIWY4z3m2MMcW2L/AxED4ArmaGCOYQafNKETzDGVOc6aYjO90WC+pjQsxnPSFBM7QwyeaE6I52UIgFkGL3SjWQiAkQYfdKORJsPa0ZVYHWCQjmSWZdhuewXoo8eg61+fQpenBSAaBXOeG8wDB0Dm+p+pMuALoyaC0Kxxv384vQHwP7wcqCN/6MGI+N+Rix4IMYeHYVSEIMAxfiw4qyoVG3C6LVnR73NxzCQIfon5nDdnVkSw6W24OHaKIWuUAAAtf6KzU/RDCDrIXiuX0MoTpOzs9ATg4vhiWcsfXdtSOE3WYAMfHhM8x8ron7QDILR5GxABWvbDoj6/rOvRShIiy6Cr0w+AwIdHFXugd+FDkq7rKC3HOs96/w/TzwyN/Oe/ij0wfP5zSdd1Nv8Z6zyPArpG2lTOAMvVV4GNsfrI+XcquwJMCio2IjdX/Oy/d2nyT+VIGDr/egq8m1+ACzcUQnBtjXIAWK8frtg4bdeJj3p3HjuRWnKdMb/9e/ZC263CKwFtyESxlvboIoCuLnlK2GKBvCMHRF3TOmUmRJCXnaJEOB2Qe7hBvhnq/v1B2YMRy3zf4oqUZj476fwUeIpmKOOIZc6fK008gvj4TKj2RaDf+yA93N32dmi7Y4F8AMhF97CMzPh6P+xrMgoKIF9CcMy7bUdahRzCpz9hJ5VkHZCIqOWrgD5+kg3A9bhpnhts118HjhUVku6LE/EESJ6oJ7WiCgKNGCLabL5MlMsKRztWLQeHwi+Dy3zn7dNTbxkwRkxg1VqwL39EmghSk9DAPJjMJxmz2LZscUqKIqrxkHIrQClqLfkBRM58ihdqGDUCXBueTl1l8CVTXlcAvIsegtDxZmxLKmtOCVgX35tWyjkhAK23zIGozweuO2cBec9cVR7cMmEaRCm86Chy4PJF+hApCwAylSKfne+eobXbgHiljteTU82BYZge3/xBv3GCbKm0F8yphL07dl3uyTEvj1aFJmQxg3P2TNFec1qsAOT6Q2fieA9aFQgI8tohkLn5GUUZbu5/JZCDB4H9MXlRz/a7FgJBZKjCqKztG9UHAMf1R0rTM6YI3EfkxYZym95Q3sD426nUFUHUyir8q5hVglaDd9ES1QYWenFnrxBBlwBwVFawSsyU58Zn0vGT4Cm6VR0l3N7RuwCIU85vdoNr7iw2qQpP8HawO0BKU7ilpXcCwHqb5Qsh/49vgmU43u4V2gFCIimw/lnFBhZpbet9VtBlmn/T+m7H7OaSyyKeCeMc9a8xPwI9gk1SyVWzFlwizk9VPwErGCdGLFFvNEJg9c/BIAUB+KJYIq8dKgzCvv0Qen67wV0lAYhT5ubq7qVs5o/jtW81AFAFgEvyVGCTXolcUAMAIbE0cgS/Le/zMw7eGoPLagHgqhHeGPE3HjS4LNUMxbrBt/pD1+lPeH2EwJNPg/0nyxJ+HlxXA/5f7dXkZZXIG7WN+R44161KjhWAyF44XngVHGwyprpaAJAL5gmeQ4Rog9NqAWBQigCQKCvMIA2zIiIUlXgG9OkDGf36ybp3NBK+tI/NKwrz88Fkscibsfnu1ASAIElOHYKjR5SwcHIb6nuvCCLMZjBIRwDIhfMNbuspgqQSvekFCH9+gd2HjjLmLEFagch0gv1RefvR/srVED77GUTpbhPZ5LQD4XCyqff2pQ+kDgD+ipWKDwrtJ1D7D/KWRFGvdWdVoJRFK+bOXXvp/dDV/BfB89iNpS/cO74xlZQAhP7UrOiAUC8KMe0QkAzFLeLDYX6ie6OU+XyVdtNk6wAla7ik9qLQQlGqVX8sCwB6wybFBoKqMJPdLW+ZqHxRiCwRRP32TbwTBQq92TYEGCWwSCaT/Qsgo29fCFP+7igsFRQ1ZpT067hxQo/yKVRUjXSOULZ21O9LLgBwxQ955Td4P8dpQ2CbMI6z8VOgqhqohkbOvNY4cRV32B4pZw9f+TKgP/iIX5HPK4PsHVv0F0GoQA+XLAOukjVIW/FNvF237BVL2FxVxy1TE2ZuoGw/tI8tVFnDbjBlZ/EbHadOJ4cO8P8OP8bPV88VWFPN70E7XeBc8WOs56DsapS5YSq4Ira+zeC6aw6bVoNLjsJx/AyLRvUXQfTGrcoNpCvMz9TJ4q2PnN3Sa4yRgxf3MZI2FOF7Hb9iJiL0wo//iP9zjash0RZp8seCRGQuy5X/9C82acoQ+uTH/JaQ1aYvAC03l4hToEO/IwzSEO5zAm+9oykAQkUetqHX6AtAFCNJF1cBxylr6wbOz8LnzmvGfNRyQIhQ0rBuAIid/aKsgYHf5vaSb9KmLYFQDlNU5m6abADEzn7zNwuwz81+uZbHVfZJbvaHrda+f7cgM1wzpuoHgGfSDPEO1LjR4kzAKUXcDtCJZvBVrFBH9KxcA13/PiPoj9geLtcHANQ3FNraRd9cbAtJVKdmyudu6kc3vQP+RysVZ0Jg/wFBUzr38D79zFDvzjrRN0a7S1Iop2EPr+8QfOtd8D24TDEG4LRUzpo3Wz8/gC1fDYlv1mcbPUryoIQ2P+j3P4LWEvmZFKi4UIgBthvHgfWBMv0A8O+Xlt2MmjnJIcfUyfxi4cxZtp+1nJkvFE6xjR8NztWVoCbxAtB2R6kkV1kJbxFlU6MQNK+YC9AsI+lnt4hnvtDMH8swf82T+oYiwqf/KW32ThyryOBQCNo+qVDwBXw76oD66WoMa6cKqyuX47Zp4FyrPvNZU53rA7S8CaniQ2KzvoT3euJxyPjqV8C3/ZcccQwzVt+KjtIHobP5Y8HzMhctENX7WZUVgDZbJLer76P8FyhY7yvtLgzM6lk5jHrH4TC/dfJtwswnzewz1GY+8icEV0DgkPQUDNe0YtUG7z60DwJPrYfg8ZOQs1u4CpN+7nnoeHmXoMhBSbta5Y2avtaXH4C22+W1KFPTZGOV82NLwY4TWphXBl1//4cg81HdMyq91YpsI4ZzAxCsfg7CMr4rgBym/1dSBqs3grf+VUETEzl72fPnst2AtSTbkvu4AfDWvSorNyez9hldmR/vaSH0DiZGT7kP7NV8fI7pU7itoPbZd8v7kh7GUtGLUJ/+8LlzeCJyzA3gWveU5mM0XzM44fbrJQCy6176v/KqqYVIIADRDh/zm+LPt3E4wGQ2y/Z85VCf13dCy/TZEOX5epQoaYW8dxt1GZ+9uIjTNE9oBaHGHKlGufvqOO19y+BBkPXSRs3HhKPg065sJb69icIT1KEmyPn1LtWfSWSYWL1CuN1ADhzAhtWxr5XTvt4glWNBBhkAGAAYZACQ9gCEDDboRj4EwFGDD7pRMwKg3uCDblSPAEDpx80GL7Sf/Yj3cR1QbICgOfMRz0NxK+gsc6AWiCiV+W2DP6rRkRiPR8R4Dv8TYADus3KHk3OpIQAAAABJRU5ErkJggg== + + + + + + + + + + + + + +http://r.m.taobao.com/ + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/wikipedia-zh-CN.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/wikipedia-zh-CN.xml new file mode 100644 index 0000000000..2f3eead054 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-CN/wikipedia-zh-CN.xml @@ -0,0 +1,23 @@ + + + +维基百科 +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + +https://zh.wikipedia.org/wiki/Special:搜索 + diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/default.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/default.txt new file mode 100644 index 0000000000..ced95a5cb9 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/default.txt @@ -0,0 +1 @@ +Google \ No newline at end of file diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/list.txt b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/list.txt new file mode 100644 index 0000000000..088c61428c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/list.txt @@ -0,0 +1,5 @@ +bing +duckduckgo +google-nocodes:hidden +google +wikipedia-zh-TW diff --git a/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/wikipedia-zh-TW.xml b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/wikipedia-zh-TW.xml new file mode 100644 index 0000000000..589ab4ad63 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/SearchPlugins/zh-TW/wikipedia-zh-TW.xml @@ -0,0 +1,25 @@ + + + +Wikipedia (zh) +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAAEXElEQVR4Ae3cA4xs2QJG4b9aj41n27Zt27Zt27Zt27Zt+2KM5lXP924qOzs56VPjKSRnrfhv7NUsp08v98+PsxwT4nJ+nPunl8KZ8/WYQL+eMydJrx5/EhN603lAHpVJ5bzZNp035uyZXM7Uy3LmM7ms9CITzVRGQRfQBXQBXUAX0AV0AV1AF9AFdAFdQBfQBXQBXcBMjgU7M5+1vqtZyXqmc/IsZDEL+53LP3KRPCCv62+rWd7vnpx6v/M5Vd935OF5R+6RtRyeQ3NYNjKTxZw2p8tiduR8uWfemY3+dkjWM5fFLPU/8q9yrRwbHLP39WkHamPD5z1WnNMb/dpW/uAdbipu413+qcl2H3N3cXFv9DNNtvmg68uxMY6dPfewTZNvOauouqEdULlTY532IgqHua+ZxnoHm4ANj63biRNQPZedVPY5nTR1BXsVbNuyTlsDqy4tW/wK4NYiJ01AXMlm+wGrL1cDnWbLejC4m7T4DvAOOSkD4v0qztGyLzpUweOk4UXAp6XV72DNmU7qgPPao+DJ0uLTFPzXXGN5I9acU1o8vb14jZzUAfFeBdvMtuwLDlfwIKme2248T1p9MvY59zACLqcy4Kf5eQr+ZbYRfrAFaXHaf/FRGUZAfE/Bzwf8OKwpuJ/0vYRNPEpavT248rACbqfimtLiqxT8w4yIz+Of5qTV7+LHMqyAaf9R8Clp8ex2K7iXuAa4q7R6aXCH4QXE4xVsOq+0+DYFfzXth/ilnrT6Tvzb9DADlqwqDPjTd377FHwI3EBaPb0NPFaGGRBvoLBiUVr8EFS+KgN8KpYtDjvgQo6i8Hhp8ZJUjnIZaXXGNrxKhh0QX6TwHzPS4uco/FtPWr0T9jnPKAJuOOiCc/UqVG4jrf4AH5dRBPT8UWHg3/BvUfhl635ZcNXRBMSDqFxFWvwklVu07O/BT2RUAad0GIWPtexXgMpPt+xntAt3Gl1AvJjCPufasn4d/6NyY2n4DPzXzCgDzmEvhVdIw+tj02X8nsIPGvus7Xi8jDIgPkLhSPON5ad4t7gbletJ9S71n+BIA65C5dGal1g3nENM+weF70j1R3iNjDogfkrhn6br5dU/4UXS94EtF7+vUC8IjjzgrlRuJ33v27j2dTLbKXxd+r4Pn5RRB9RfxsL3y4H/i0dI9TFUrirOZDeuPh4B8TQqVyjH/ZtZqZ7KIRS+JJ6Fn8k4BNRL9IUPmncwbr/1b37lanbiLuMTEG+nsNfb8cOWq0DLFA7E/8yMU8AlNLnaoP/alSfKOAXEN6h8Qlo8k3UKq5bGLeAWFPa6oLT6Ogqvk3ELmPJ3wOtlgOe0B2w6//gFxCPBsjPIQN8JPi3jGDDvSDxVDPaCNnFNOdGczrNzIrEnRyR5XPZlMIdmKofnpTnx6B783QV0ARNOF9AFdAFdQBfQBXQBXUAX0AV0AV3A6OgCVjLJrEzlj5lk/jiVt2eSefvEvzTJxL84zMS/PM//Af1pBRpQAkXBAAAAAElFTkSuQmCC + + + + + + + + + + + + + + + +https://zh.wikipedia.org/wiki/Special:搜索 + diff --git a/mobile/ios/Client/Assets/Search/Tests/Base/testplugin.xml b/mobile/ios/Client/Assets/Search/Tests/Base/testplugin.xml new file mode 100644 index 0000000000..b0fd8f057b --- /dev/null +++ b/mobile/ios/Client/Assets/Search/Tests/Base/testplugin.xml @@ -0,0 +1,17 @@ + + + + TestPlugin + Test Plugin + UTF-8 + + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/Tests/Expected/append.xml b/mobile/ios/Client/Assets/Search/Tests/Expected/append.xml new file mode 100644 index 0000000000..ab7f87a2e8 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/Tests/Expected/append.xml @@ -0,0 +1,19 @@ + + + TestPlugin + Test Plugin + UTF-8 + + + + + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/Tests/Expected/replace.xml b/mobile/ios/Client/Assets/Search/Tests/Expected/replace.xml new file mode 100644 index 0000000000..f5a53b992c --- /dev/null +++ b/mobile/ios/Client/Assets/Search/Tests/Expected/replace.xml @@ -0,0 +1,15 @@ + + + TestPlugin + Test Plugin + UTF-8 + + + + + + Child of replaced element. + + diff --git a/mobile/ios/Client/Assets/Search/Tests/Overlays/append.xml b/mobile/ios/Client/Assets/Search/Tests/Overlays/append.xml new file mode 100644 index 0000000000..5bc874342a --- /dev/null +++ b/mobile/ios/Client/Assets/Search/Tests/Overlays/append.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/mobile/ios/Client/Assets/Search/Tests/Overlays/replace.xml b/mobile/ios/Client/Assets/Search/Tests/Overlays/replace.xml new file mode 100644 index 0000000000..42c7998130 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/Tests/Overlays/replace.xml @@ -0,0 +1,7 @@ + + + + Child of replaced element. + + + diff --git a/mobile/ios/Client/Assets/Search/get_supported_locales.swift b/mobile/ios/Client/Assets/Search/get_supported_locales.swift new file mode 100644 index 0000000000..dc643f8736 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/get_supported_locales.swift @@ -0,0 +1,13 @@ +#!/usr/bin/env swift + +import Foundation + +var allLocales = NSLocale.availableLocaleIdentifiers() + +// iOS doesn't directly support zh-CN/zh-TW; instead, it supports zh-Hans-CN and zh-Hant-TW, respectively. +// These transformations are done in SearchEngines.swift. Add them to the list of supported engines so +// that we download them. +allLocales.append("zh_CN") +allLocales.append("zh_TW") + +print(allLocales) diff --git a/mobile/ios/Client/Assets/Search/run_tests.py b/mobile/ios/Client/Assets/Search/run_tests.py new file mode 100644 index 0000000000..63a59d41ed --- /dev/null +++ b/mobile/ios/Client/Assets/Search/run_tests.py @@ -0,0 +1,34 @@ +#!/usr/bin/env 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/. + +from lxml import etree +import sys +import unittest + +from scrape_plugins import Overlay + +class TestOverlays(unittest.TestCase): + def setUp(self): + self.plugin = etree.parse("Tests/Base/testplugin.xml") + + def testAppend(self): + overlay = Overlay("Tests/Overlays/append.xml") + overlay.apply(self.plugin) + self.assertEqualsExpectedXML(plugin=self.plugin, expectedPath="Tests/Expected/append.xml") + + def testReplace(self): + overlay = Overlay("Tests/Overlays/replace.xml") + overlay.apply(self.plugin) + self.assertEqualsExpectedXML(plugin=self.plugin, expectedPath="Tests/Expected/replace.xml") + + def assertEqualsExpectedXML(self, plugin, expectedPath): + actual = etree.tostring(plugin, pretty_print=True) + with open(expectedPath, "r") as file: + expected = file.read() + self.assertEqual(actual, expected, "\nExpected:\n%s\n\nActual:\n%s" % (expected, actual)) + +if __name__ == '__main__': + unittest.main() diff --git a/mobile/ios/Client/Assets/Search/scrape_plugins.py b/mobile/ios/Client/Assets/Search/scrape_plugins.py new file mode 100644 index 0000000000..30d0cd8d96 --- /dev/null +++ b/mobile/ios/Client/Assets/Search/scrape_plugins.py @@ -0,0 +1,214 @@ +#!/usr/bin/env 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/. + +from lxml import html +from lxml import etree +import copy +import json +import os +import requests +import shutil +import subprocess +import urllib + +# Paths for en-US plugins included in the core Android repo. +EN_PLUGINS_DIR_URL = "https://hg.mozilla.org/releases/mozilla-aurora/file/default/mobile/locales/en-US/searchplugins" +EN_PLUGINS_FILE_URL = "https://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/mobile/locales/en-US/searchplugins/%s" +EN_PREFS_URL = "https://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/mobile/locales/en-US/chrome/region.properties" + +# Paths for plugins in the l10n repos. +L10N_LOCALE_LIST_URL = "https://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/mobile/android/locales/all-locales" +L10N_PLUGINS_DIR_URL = "https://hg.mozilla.org/releases/l10n/mozilla-aurora/%s/file/default/mobile/searchplugins" +L10N_PLUGINS_FILE_URL = "https://hg.mozilla.org/releases/l10n/mozilla-aurora/%s/raw-file/default/mobile/searchplugins/%%s" +L10N_PREFS_URL = "https://hg.mozilla.org/releases/l10n/mozilla-aurora/%s/raw-file/default/mobile/chrome/region.properties" + +MOZ_HEADER = """\ + + +""" + +ns = { "search": "http://www.mozilla.org/2006/browser/search/" } + +def main(): + # Remove and recreate the SearchPlugins directory. + if os.path.exists("SearchPlugins"): + shutil.rmtree("SearchPlugins") + os.makedirs("SearchPlugins") + + # Import en-US engines from the core repo. + downloadLocale("en", EnScraper()) + + # Import engines from the l10n repos. + response = requests.get(L10N_LOCALE_LIST_URL) + locales = response.text.strip().split("\n") + supportedLocales = getSupportedLocales() + for locale in locales: + if (locale not in supportedLocales): + print("skipping unsupported locale: %s" % locale) + continue + + downloadLocale(locale, L10nScraper(locale)) + + verifyEngines() + +def downloadLocale(locale, scraper): + print("scraping: %s..." % locale) + files = scraper.getFileList() + if files == None: + print("no files for locale: %s" % locale) + return + + print(" found search plugins") + + directory = os.path.join("SearchPlugins", locale) + if not os.path.exists(directory): + os.makedirs(directory) + + # Get the default search engine for this locale. + default = scraper.getDefault() + print(" default: %s" % default) + saveDefault(locale, default) + + for file in files: + path = os.path.join(directory, file) + print(" downloading: %s..." % file) + downloadedFile = scraper.getFile(file) + name, extension = os.path.splitext(file) + + # Apply iOS-specific overlays for this engine if they are defined. + if extension == ".xml": + engine = name.split("-")[0] + overlay = overlayForEngine(engine) + if overlay: + plugin = etree.parse(downloadedFile) + overlay.apply(plugin) + contents = MOZ_HEADER + etree.tostring(plugin.getroot(), encoding="utf-8", pretty_print=True) + with open(path, "w") as outfile: + outfile.write(contents) + continue + + # Otherwise, just use the downloaded file as is. + shutil.move(downloadedFile, path) + +def verifyEngines(): + print("verifying engines...") + enDir = os.path.join("SearchPlugins", "en") + for locale in os.listdir("SearchPlugins"): + if locale.startswith("."): continue + localeDir = os.path.join("SearchPlugins", locale) + with open(os.path.join(localeDir, "list.txt")) as f: + engineList = f.read().splitlines() + + for engine in engineList: + if engine.endswith(":hidden"): continue + path = os.path.join(localeDir, engine + ".xml") + enPath = os.path.join(enDir, engine + ".xml") + if not os.path.exists(path) and not os.path.exists(enPath): + print(" ERROR: missing engine %s for locale %s" % (engine, locale)) + +def getSupportedLocales(): + supportedLocales = subprocess.Popen("./get_supported_locales.swift", stdout=subprocess.PIPE).communicate()[0] + return json.loads(supportedLocales.replace("_", "-")) + +def overlayForEngine(engine): + path = os.path.join("SearchOverlays", "%s.xml" % engine) + if not os.path.exists(path): + return None + return Overlay(path) + +def saveDefault(locale, default): + directory = os.path.join("SearchPlugins", locale, "default.txt") + file = open(directory, "w") + file.write(default.encode("UTF-8")) + + +class Scraper: + def pluginsDirURL(self): pass + def pluginsFileURL(self): pass + def prefsURL(self): pass + def defaultPrefName(self): pass + + def getFileList(self): + response = requests.get(self.pluginsDirURL) + if not response.ok: + raise Exception("error: could not read plugins directory") + + tree = html.fromstring(response.content) + return tree.xpath('//a[@class="list"]/text()') + + def getFile(self, file): + result = urllib.urlretrieve(self.pluginsFileURL % file) + return result[0] + + def getDefault(self): + response = requests.get(self.prefsURL) + if not response.ok: + raise Exception("error: could not read prefs file") + + lines = response.text.strip().split("\n") + for line in lines: + values = line.strip().split("=") + if len(values) == 2 and values[0].strip() == self.defaultPrefName: + default = values[1].strip() + return default + + raise Exception("error: no default pref found") + + +class L10nScraper(Scraper): + def __init__(self, locale): + self.pluginsDirURL = L10N_PLUGINS_DIR_URL % locale + self.pluginsFileURL = L10N_PLUGINS_FILE_URL % locale + self.prefsURL = L10N_PREFS_URL % locale + self.defaultPrefName = "browser.search.defaultenginename" + + +class EnScraper(Scraper): + def __init__(self): + self.pluginsDirURL = EN_PLUGINS_DIR_URL + self.pluginsFileURL = EN_PLUGINS_FILE_URL + self.prefsURL = EN_PREFS_URL + self.defaultPrefName = "browser.search.defaultenginename.US" + +class Overlay: + def __init__(self, path): + overlay = etree.parse(path) + self.actions = overlay.getroot().getchildren() + + def apply(self, doc): + for action in self.actions: + if action.tag == "replace": + self.replace(target=action.get("target"), replacement=action[0], doc=doc) + elif action.tag == "append": + self.append(parent=action.get("parent"), child=action[0], doc=doc) + + def replace(self, target, replacement, doc): + for element in doc.xpath(target, namespaces=ns): + replacementCopy = copy.deepcopy(replacement) + element.getparent().replace(element, replacementCopy) + + # Try to preserve indentation. + replacementCopy.tail = element.tail + + def append(self, parent, child, doc): + for element in doc.xpath(parent, namespaces=ns): + childCopy = copy.deepcopy(child) + element.append(childCopy) + + # Try to preserve indentation. + childCopy.tail = "\n" + previous = childCopy.getprevious() + if previous is not None: + childCopy.tail = previous.tail + prevPrevious = previous.getprevious() + if prevPrevious is not None: + previous.tail = prevPrevious.tail + + +if __name__ == "__main__": + main() diff --git a/mobile/ios/Client/Assets/SessionRestore.html b/mobile/ios/Client/Assets/SessionRestore.html new file mode 100644 index 0000000000..19f4de7376 --- /dev/null +++ b/mobile/ios/Client/Assets/SessionRestore.html @@ -0,0 +1,52 @@ + + + + + + + + + + diff --git a/mobile/ios/Client/Assets/SpotlightHelper.js b/mobile/ios/Client/Assets/SpotlightHelper.js new file mode 100644 index 0000000000..4ce8923c41 --- /dev/null +++ b/mobile/ios/Client/Assets/SpotlightHelper.js @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +(function() { +"use strict"; + +var selectors = { + title: "title", + description: "meta[name='description'], body p", +}; + +function collectText(selector) { + var el = document.querySelector(selector); + return el ? el.getAttribute("content") || el.innerText || "" : ""; +} + +function assemblePayload(selectors) { + var payload = {}; + for (var key in selectors) { + payload[key] = collectText(selectors[key]); + } + return payload; +} + +window.addEventListener("load", function() { + var payload = assemblePayload(selectors); + webkit.messageHandlers.spotlightMessageHandler.postMessage(payload); +}); + +})(); diff --git a/mobile/ios/Client/Assets/TopSites/aa-com.png b/mobile/ios/Client/Assets/TopSites/aa-com.png new file mode 100644 index 0000000000..c96e95fd43 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/aa-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/abcnews-go-com.png b/mobile/ios/Client/Assets/TopSites/abcnews-go-com.png new file mode 100644 index 0000000000..62b5b1b3d1 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/abcnews-go-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/about-com.png b/mobile/ios/Client/Assets/TopSites/about-com.png new file mode 100644 index 0000000000..d61a22fff5 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/about-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/accuweather-com.png b/mobile/ios/Client/Assets/TopSites/accuweather-com.png new file mode 100644 index 0000000000..0f14e31a26 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/accuweather-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/adobe-com.png b/mobile/ios/Client/Assets/TopSites/adobe-com.png new file mode 100644 index 0000000000..ca8cde6ec9 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/adobe-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/adp-com.png b/mobile/ios/Client/Assets/TopSites/adp-com.png new file mode 100644 index 0000000000..f5bf112321 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/adp-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/airbnb-com.png b/mobile/ios/Client/Assets/TopSites/airbnb-com.png new file mode 100644 index 0000000000..5e775cafbd Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/airbnb-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/allrecipes-com.png b/mobile/ios/Client/Assets/TopSites/allrecipes-com.png new file mode 100644 index 0000000000..ef1f12d154 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/allrecipes-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/amazon-com.png b/mobile/ios/Client/Assets/TopSites/amazon-com.png new file mode 100644 index 0000000000..9bba9e5c54 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/amazon-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/amazonaws-com.png b/mobile/ios/Client/Assets/TopSites/amazonaws-com.png new file mode 100644 index 0000000000..8086e5e227 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/amazonaws-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/americanexpress-com.png b/mobile/ios/Client/Assets/TopSites/americanexpress-com.png new file mode 100644 index 0000000000..344120b49c Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/americanexpress-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ancestry-com.png b/mobile/ios/Client/Assets/TopSites/ancestry-com.png new file mode 100644 index 0000000000..5fe61b2547 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ancestry-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/answers-com.png b/mobile/ios/Client/Assets/TopSites/answers-com.png new file mode 100644 index 0000000000..5ed923423b Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/answers-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/aol-com.png b/mobile/ios/Client/Assets/TopSites/aol-com.png new file mode 100644 index 0000000000..5e7a26cf00 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/aol-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/apple-com.png b/mobile/ios/Client/Assets/TopSites/apple-com.png new file mode 100644 index 0000000000..e688081c26 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/apple-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ask-com.png b/mobile/ios/Client/Assets/TopSites/ask-com.png new file mode 100644 index 0000000000..2f9ab71007 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ask-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/att-com.png b/mobile/ios/Client/Assets/TopSites/att-com.png new file mode 100644 index 0000000000..7fa9febd08 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/att-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/baidu-com.png b/mobile/ios/Client/Assets/TopSites/baidu-com.png new file mode 100644 index 0000000000..a72237ae8e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/baidu-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/bankofamerica-com.png b/mobile/ios/Client/Assets/TopSites/bankofamerica-com.png new file mode 100644 index 0000000000..ddb7ef5019 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/bankofamerica-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/bbc-com.png b/mobile/ios/Client/Assets/TopSites/bbc-com.png new file mode 100644 index 0000000000..b90feff3fe Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/bbc-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/bestbuy-com.png b/mobile/ios/Client/Assets/TopSites/bestbuy-com.png new file mode 100644 index 0000000000..d72238386d Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/bestbuy-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/bing-com.png b/mobile/ios/Client/Assets/TopSites/bing-com.png new file mode 100644 index 0000000000..6c09543646 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/bing-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/blackboard-com.png b/mobile/ios/Client/Assets/TopSites/blackboard-com.png new file mode 100644 index 0000000000..3692d392e6 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/blackboard-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/bleacherreport-com.png b/mobile/ios/Client/Assets/TopSites/bleacherreport-com.png new file mode 100644 index 0000000000..088a242322 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/bleacherreport-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/blogger-com.png b/mobile/ios/Client/Assets/TopSites/blogger-com.png new file mode 100644 index 0000000000..33947ead81 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/blogger-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/box-com.png b/mobile/ios/Client/Assets/TopSites/box-com.png new file mode 100644 index 0000000000..7f5d62bdb8 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/box-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/businessinsider-com.png b/mobile/ios/Client/Assets/TopSites/businessinsider-com.png new file mode 100644 index 0000000000..f1c960031a Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/businessinsider-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/buzzfeed-com.png b/mobile/ios/Client/Assets/TopSites/buzzfeed-com.png new file mode 100644 index 0000000000..a0af65eefe Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/buzzfeed-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/buzzlie-com.png b/mobile/ios/Client/Assets/TopSites/buzzlie-com.png new file mode 100644 index 0000000000..cf1a880577 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/buzzlie-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ca-gov.png b/mobile/ios/Client/Assets/TopSites/ca-gov.png new file mode 100644 index 0000000000..10479e67e3 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ca-gov.png differ diff --git a/mobile/ios/Client/Assets/TopSites/capitalone-com.png b/mobile/ios/Client/Assets/TopSites/capitalone-com.png new file mode 100644 index 0000000000..bbae9002bb Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/capitalone-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/cbsnews-com.png b/mobile/ios/Client/Assets/TopSites/cbsnews-com.png new file mode 100644 index 0000000000..60afaf6ea3 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/cbsnews-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/cbssports-com.png b/mobile/ios/Client/Assets/TopSites/cbssports-com.png new file mode 100644 index 0000000000..c11b56b252 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/cbssports-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/chase-com.png b/mobile/ios/Client/Assets/TopSites/chase-com.png new file mode 100644 index 0000000000..61a7e9d21f Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/chase-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/citi-com.png b/mobile/ios/Client/Assets/TopSites/citi-com.png new file mode 100644 index 0000000000..415b8f8190 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/citi-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/cnet-com.png b/mobile/ios/Client/Assets/TopSites/cnet-com.png new file mode 100644 index 0000000000..8dd8438b19 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/cnet-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/cnn-com.png b/mobile/ios/Client/Assets/TopSites/cnn-com.png new file mode 100644 index 0000000000..64fff1a8e2 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/cnn-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/conservativetribune-com.png b/mobile/ios/Client/Assets/TopSites/conservativetribune-com.png new file mode 100644 index 0000000000..b808aeeb7c Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/conservativetribune-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/costco-com.png b/mobile/ios/Client/Assets/TopSites/costco-com.png new file mode 100644 index 0000000000..42827a58b1 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/costco-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/craigslist-org.png b/mobile/ios/Client/Assets/TopSites/craigslist-org.png new file mode 100644 index 0000000000..e1825ae0e2 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/craigslist-org.png differ diff --git a/mobile/ios/Client/Assets/TopSites/dailybeast-com.png b/mobile/ios/Client/Assets/TopSites/dailybeast-com.png new file mode 100644 index 0000000000..5102bef549 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/dailybeast-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/dailymail-co-uk.png b/mobile/ios/Client/Assets/TopSites/dailymail-co-uk.png new file mode 100644 index 0000000000..9c3374d77c Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/dailymail-co-uk.png differ diff --git a/mobile/ios/Client/Assets/TopSites/delta-com.png b/mobile/ios/Client/Assets/TopSites/delta-com.png new file mode 100644 index 0000000000..eea4df5e0e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/delta-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/deviantart-com.png b/mobile/ios/Client/Assets/TopSites/deviantart-com.png new file mode 100644 index 0000000000..41347d31ad Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/deviantart-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/digg-com.png b/mobile/ios/Client/Assets/TopSites/digg-com.png new file mode 100644 index 0000000000..cd547b82e3 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/digg-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/diply-com.png b/mobile/ios/Client/Assets/TopSites/diply-com.png new file mode 100644 index 0000000000..349407a691 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/diply-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/discovercard-com.png b/mobile/ios/Client/Assets/TopSites/discovercard-com.png new file mode 100644 index 0000000000..b9feba07c0 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/discovercard-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/dropbox-com.png b/mobile/ios/Client/Assets/TopSites/dropbox-com.png new file mode 100644 index 0000000000..22fd13b491 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/dropbox-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/drudgereport-com.png b/mobile/ios/Client/Assets/TopSites/drudgereport-com.png new file mode 100644 index 0000000000..fbdd4ef0f1 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/drudgereport-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ebates-com.png b/mobile/ios/Client/Assets/TopSites/ebates-com.png new file mode 100644 index 0000000000..4fe8c7ead5 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ebates-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ebay-com.png b/mobile/ios/Client/Assets/TopSites/ebay-com.png new file mode 100644 index 0000000000..d6f8e6acb2 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ebay-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/espn-go-com.png b/mobile/ios/Client/Assets/TopSites/espn-go-com.png new file mode 100644 index 0000000000..0322d3d134 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/espn-go-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/etsy-com.png b/mobile/ios/Client/Assets/TopSites/etsy-com.png new file mode 100644 index 0000000000..a8cfe2daa4 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/etsy-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/eventbrite-com.png b/mobile/ios/Client/Assets/TopSites/eventbrite-com.png new file mode 100644 index 0000000000..01b74c3202 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/eventbrite-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/expedia-com.png b/mobile/ios/Client/Assets/TopSites/expedia-com.png new file mode 100644 index 0000000000..48125f8985 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/expedia-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/facebook-com.png b/mobile/ios/Client/Assets/TopSites/facebook-com.png new file mode 100644 index 0000000000..a820630ea8 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/facebook-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/faithtap-com.png b/mobile/ios/Client/Assets/TopSites/faithtap-com.png new file mode 100644 index 0000000000..7ade921c99 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/faithtap-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/fedex-com.png b/mobile/ios/Client/Assets/TopSites/fedex-com.png new file mode 100644 index 0000000000..4711a9ace7 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/fedex-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/feedly-com.png b/mobile/ios/Client/Assets/TopSites/feedly-com.png new file mode 100644 index 0000000000..87beb5cb8e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/feedly-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/fitbit-com.png b/mobile/ios/Client/Assets/TopSites/fitbit-com.png new file mode 100644 index 0000000000..9ea8afa9d1 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/fitbit-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/flickr-com.png b/mobile/ios/Client/Assets/TopSites/flickr-com.png new file mode 100644 index 0000000000..41db127f9e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/flickr-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/foodnetwork-com.png b/mobile/ios/Client/Assets/TopSites/foodnetwork-com.png new file mode 100644 index 0000000000..ba3cee06dd Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/foodnetwork-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/forbes-com.png b/mobile/ios/Client/Assets/TopSites/forbes-com.png new file mode 100644 index 0000000000..e813d38800 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/forbes-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/foxnews-com.png b/mobile/ios/Client/Assets/TopSites/foxnews-com.png new file mode 100644 index 0000000000..0c1cfc983f Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/foxnews-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/gap-com.png b/mobile/ios/Client/Assets/TopSites/gap-com.png new file mode 100644 index 0000000000..11f24e1268 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/gap-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/gawker-com.png b/mobile/ios/Client/Assets/TopSites/gawker-com.png new file mode 100644 index 0000000000..cb2ba8a90d Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/gawker-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/gfycat-com.png b/mobile/ios/Client/Assets/TopSites/gfycat-com.png new file mode 100644 index 0000000000..7305cdee70 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/gfycat-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/github-com.png b/mobile/ios/Client/Assets/TopSites/github-com.png new file mode 100644 index 0000000000..369315c603 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/github-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/gizmodo-com.png b/mobile/ios/Client/Assets/TopSites/gizmodo-com.png new file mode 100644 index 0000000000..e332f8194b Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/gizmodo-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/glassdoor-com.png b/mobile/ios/Client/Assets/TopSites/glassdoor-com.png new file mode 100644 index 0000000000..c92b84b5ed Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/glassdoor-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/go-com.png b/mobile/ios/Client/Assets/TopSites/go-com.png new file mode 100644 index 0000000000..86b97210d8 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/go-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/goodreads-com.png b/mobile/ios/Client/Assets/TopSites/goodreads-com.png new file mode 100644 index 0000000000..a07b21073a Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/goodreads-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-admin.png b/mobile/ios/Client/Assets/TopSites/google-admin.png new file mode 100644 index 0000000000..666a1ca647 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-admin.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-calendar.png b/mobile/ios/Client/Assets/TopSites/google-calendar.png new file mode 100644 index 0000000000..cde34eff31 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-calendar.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-com.png b/mobile/ios/Client/Assets/TopSites/google-com.png new file mode 100644 index 0000000000..6b3c2b2e01 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-contacts.png b/mobile/ios/Client/Assets/TopSites/google-contacts.png new file mode 100644 index 0000000000..968c7e0e51 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-contacts.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-docs.png b/mobile/ios/Client/Assets/TopSites/google-docs.png new file mode 100644 index 0000000000..f75ce6b7b8 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-docs.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-drive.png b/mobile/ios/Client/Assets/TopSites/google-drive.png new file mode 100644 index 0000000000..6f43fc7dc5 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-drive.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-forms.png b/mobile/ios/Client/Assets/TopSites/google-forms.png new file mode 100644 index 0000000000..daf8fe6e5d Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-forms.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-gmail.png b/mobile/ios/Client/Assets/TopSites/google-gmail.png new file mode 100644 index 0000000000..fd9cec2c57 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-gmail.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-groups.png b/mobile/ios/Client/Assets/TopSites/google-groups.png new file mode 100644 index 0000000000..8691079905 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-groups.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-hangouts.png b/mobile/ios/Client/Assets/TopSites/google-hangouts.png new file mode 100644 index 0000000000..de2e88bdae Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-hangouts.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-photos.png b/mobile/ios/Client/Assets/TopSites/google-photos.png new file mode 100644 index 0000000000..367751a8d2 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-photos.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-plus.png b/mobile/ios/Client/Assets/TopSites/google-plus.png new file mode 100644 index 0000000000..ea8e8d030f Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-plus.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-sheets.png b/mobile/ios/Client/Assets/TopSites/google-sheets.png new file mode 100644 index 0000000000..69f1e23f27 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-sheets.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-sites.png b/mobile/ios/Client/Assets/TopSites/google-sites.png new file mode 100644 index 0000000000..bb6ead5d8d Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-sites.png differ diff --git a/mobile/ios/Client/Assets/TopSites/google-slides.png b/mobile/ios/Client/Assets/TopSites/google-slides.png new file mode 100644 index 0000000000..508375aa4f Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/google-slides.png differ diff --git a/mobile/ios/Client/Assets/TopSites/groupon-com.png b/mobile/ios/Client/Assets/TopSites/groupon-com.png new file mode 100644 index 0000000000..10e04e5d81 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/groupon-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/homedepot-com.png b/mobile/ios/Client/Assets/TopSites/homedepot-com.png new file mode 100644 index 0000000000..273fee4216 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/homedepot-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/houzz-com.png b/mobile/ios/Client/Assets/TopSites/houzz-com.png new file mode 100644 index 0000000000..aff94af116 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/houzz-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/huffingtonpost-com.png b/mobile/ios/Client/Assets/TopSites/huffingtonpost-com.png new file mode 100644 index 0000000000..38a2153826 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/huffingtonpost-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/hulu-com.png b/mobile/ios/Client/Assets/TopSites/hulu-com.png new file mode 100644 index 0000000000..593d18d8fb Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/hulu-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ign-com.png b/mobile/ios/Client/Assets/TopSites/ign-com.png new file mode 100644 index 0000000000..2cbc573762 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ign-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ikea-com.png b/mobile/ios/Client/Assets/TopSites/ikea-com.png new file mode 100644 index 0000000000..08a5c017c9 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ikea-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/images-google-com.png b/mobile/ios/Client/Assets/TopSites/images-google-com.png new file mode 100644 index 0000000000..ef4c566931 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/images-google-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/imdb-com.png b/mobile/ios/Client/Assets/TopSites/imdb-com.png new file mode 100644 index 0000000000..8c06de0eb3 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/imdb-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/imgur-com.png b/mobile/ios/Client/Assets/TopSites/imgur-com.png new file mode 100644 index 0000000000..ec963f908d Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/imgur-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/instagram-com.png b/mobile/ios/Client/Assets/TopSites/instagram-com.png new file mode 100644 index 0000000000..7197f1c59b Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/instagram-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/instructure-com.png b/mobile/ios/Client/Assets/TopSites/instructure-com.png new file mode 100644 index 0000000000..e874d6c5da Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/instructure-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/intuit-com.png b/mobile/ios/Client/Assets/TopSites/intuit-com.png new file mode 100644 index 0000000000..45599f9f03 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/intuit-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/invision-com.png b/mobile/ios/Client/Assets/TopSites/invision-com.png new file mode 100644 index 0000000000..3ff2b533d9 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/invision-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/irs-gov.png b/mobile/ios/Client/Assets/TopSites/irs-gov.png new file mode 100644 index 0000000000..2c8986235a Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/irs-gov.png differ diff --git a/mobile/ios/Client/Assets/TopSites/jcpenney-com.png b/mobile/ios/Client/Assets/TopSites/jcpenney-com.png new file mode 100644 index 0000000000..5ccf7c86f0 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/jcpenney-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/jd-com.png b/mobile/ios/Client/Assets/TopSites/jd-com.png new file mode 100644 index 0000000000..6169213af4 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/jd-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/kayak-com.png b/mobile/ios/Client/Assets/TopSites/kayak-com.png new file mode 100644 index 0000000000..c0c7938b6b Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/kayak-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/kohls-com.png b/mobile/ios/Client/Assets/TopSites/kohls-com.png new file mode 100644 index 0000000000..ad486a5541 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/kohls-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/latimes-com.png b/mobile/ios/Client/Assets/TopSites/latimes-com.png new file mode 100644 index 0000000000..4c3e94b2d7 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/latimes-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/lifehacker-com.png b/mobile/ios/Client/Assets/TopSites/lifehacker-com.png new file mode 100644 index 0000000000..d06b35d0e2 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/lifehacker-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/linkedin-com.png b/mobile/ios/Client/Assets/TopSites/linkedin-com.png new file mode 100644 index 0000000000..5f005fddc8 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/linkedin-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/live-com.png b/mobile/ios/Client/Assets/TopSites/live-com.png new file mode 100644 index 0000000000..8255e40097 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/live-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/lowes-com.png b/mobile/ios/Client/Assets/TopSites/lowes-com.png new file mode 100644 index 0000000000..503534a388 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/lowes-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/macys-com.png b/mobile/ios/Client/Assets/TopSites/macys-com.png new file mode 100644 index 0000000000..a75ef3e4b6 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/macys-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/mapquest-com.png b/mobile/ios/Client/Assets/TopSites/mapquest-com.png new file mode 100644 index 0000000000..84185b3712 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/mapquest-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/mashable-com.png b/mobile/ios/Client/Assets/TopSites/mashable-com.png new file mode 100644 index 0000000000..42d62dc371 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/mashable-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/microsoft-com.png b/mobile/ios/Client/Assets/TopSites/microsoft-com.png new file mode 100644 index 0000000000..32db2a40c8 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/microsoft-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/microsoftonline-com.png b/mobile/ios/Client/Assets/TopSites/microsoftonline-com.png new file mode 100644 index 0000000000..f50d1986bb Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/microsoftonline-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/mlb-com.png b/mobile/ios/Client/Assets/TopSites/mlb-com.png new file mode 100644 index 0000000000..a3e9c96658 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/mlb-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/mozilla-com.png b/mobile/ios/Client/Assets/TopSites/mozilla-com.png new file mode 100644 index 0000000000..41bb981cdb Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/mozilla-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/msn-com.png b/mobile/ios/Client/Assets/TopSites/msn-com.png new file mode 100644 index 0000000000..5bb3403bff Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/msn-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/nbcnews-com.png b/mobile/ios/Client/Assets/TopSites/nbcnews-com.png new file mode 100644 index 0000000000..4f7c467cdb Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/nbcnews-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/netflix-com.png b/mobile/ios/Client/Assets/TopSites/netflix-com.png new file mode 100644 index 0000000000..708f2102fc Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/netflix-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/newegg-com.png b/mobile/ios/Client/Assets/TopSites/newegg-com.png new file mode 100644 index 0000000000..a98d2fae0f Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/newegg-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/news-ycombinator-com.png b/mobile/ios/Client/Assets/TopSites/news-ycombinator-com.png new file mode 100644 index 0000000000..8ede606794 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/news-ycombinator-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/nih-gov.png b/mobile/ios/Client/Assets/TopSites/nih-gov.png new file mode 100644 index 0000000000..237b1038c6 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/nih-gov.png differ diff --git a/mobile/ios/Client/Assets/TopSites/nordstrom-com.png b/mobile/ios/Client/Assets/TopSites/nordstrom-com.png new file mode 100644 index 0000000000..247be3953e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/nordstrom-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/npr-org.png b/mobile/ios/Client/Assets/TopSites/npr-org.png new file mode 100644 index 0000000000..8944be7270 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/npr-org.png differ diff --git a/mobile/ios/Client/Assets/TopSites/nypost-com.png b/mobile/ios/Client/Assets/TopSites/nypost-com.png new file mode 100644 index 0000000000..d9ca6fd43e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/nypost-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/nytimes-com.png b/mobile/ios/Client/Assets/TopSites/nytimes-com.png new file mode 100644 index 0000000000..3d316e1743 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/nytimes-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/office-com.png b/mobile/ios/Client/Assets/TopSites/office-com.png new file mode 100644 index 0000000000..d7ad7649a5 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/office-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/overstock-com.png b/mobile/ios/Client/Assets/TopSites/overstock-com.png new file mode 100644 index 0000000000..469659b8e8 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/overstock-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/pandora-com.png b/mobile/ios/Client/Assets/TopSites/pandora-com.png new file mode 100644 index 0000000000..20d2d13c77 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/pandora-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/patch-com.png b/mobile/ios/Client/Assets/TopSites/patch-com.png new file mode 100644 index 0000000000..bdf24ac327 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/patch-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/paypal-com.png b/mobile/ios/Client/Assets/TopSites/paypal-com.png new file mode 100644 index 0000000000..4783328a1b Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/paypal-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/people-com.png b/mobile/ios/Client/Assets/TopSites/people-com.png new file mode 100644 index 0000000000..51bc55c432 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/people-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/pinterest-com.png b/mobile/ios/Client/Assets/TopSites/pinterest-com.png new file mode 100644 index 0000000000..5b4a427ff7 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/pinterest-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/politico-com.png b/mobile/ios/Client/Assets/TopSites/politico-com.png new file mode 100644 index 0000000000..561ca25390 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/politico-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/qq-com.png b/mobile/ios/Client/Assets/TopSites/qq-com.png new file mode 100644 index 0000000000..764c93cfb2 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/qq-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/quora-com.png b/mobile/ios/Client/Assets/TopSites/quora-com.png new file mode 100644 index 0000000000..99b8364016 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/quora-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/realtor-com.png b/mobile/ios/Client/Assets/TopSites/realtor-com.png new file mode 100644 index 0000000000..4c4948cd57 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/realtor-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/reddit-com.png b/mobile/ios/Client/Assets/TopSites/reddit-com.png new file mode 100644 index 0000000000..782b44561f Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/reddit-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/salesforce-com.png b/mobile/ios/Client/Assets/TopSites/salesforce-com.png new file mode 100644 index 0000000000..86819ac168 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/salesforce-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/sears-com.png b/mobile/ios/Client/Assets/TopSites/sears-com.png new file mode 100644 index 0000000000..03faa333bd Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/sears-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/sina-com.png b/mobile/ios/Client/Assets/TopSites/sina-com.png new file mode 100644 index 0000000000..dd0177b1d7 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/sina-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/slate-com.png b/mobile/ios/Client/Assets/TopSites/slate-com.png new file mode 100644 index 0000000000..0688958e42 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/slate-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/slickdeals-net.png b/mobile/ios/Client/Assets/TopSites/slickdeals-net.png new file mode 100644 index 0000000000..2683ca9adc Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/slickdeals-net.png differ diff --git a/mobile/ios/Client/Assets/TopSites/soundcloud-com.png b/mobile/ios/Client/Assets/TopSites/soundcloud-com.png new file mode 100644 index 0000000000..d12f24f56c Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/soundcloud-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/southwest-com.png b/mobile/ios/Client/Assets/TopSites/southwest-com.png new file mode 100644 index 0000000000..ef14ad7682 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/southwest-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/spotify-com.png b/mobile/ios/Client/Assets/TopSites/spotify-com.png new file mode 100644 index 0000000000..b1d0b364de Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/spotify-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/stackexchange-com.png b/mobile/ios/Client/Assets/TopSites/stackexchange-com.png new file mode 100644 index 0000000000..b5c50b5069 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/stackexchange-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/stackoverflow-com.png b/mobile/ios/Client/Assets/TopSites/stackoverflow-com.png new file mode 100644 index 0000000000..8b97dba3d0 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/stackoverflow-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/staples-com.png b/mobile/ios/Client/Assets/TopSites/staples-com.png new file mode 100644 index 0000000000..2571d42cc3 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/staples-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/strava-com.png b/mobile/ios/Client/Assets/TopSites/strava-com.png new file mode 100644 index 0000000000..76bf338339 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/strava-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/surveymonkey-com.png b/mobile/ios/Client/Assets/TopSites/surveymonkey-com.png new file mode 100644 index 0000000000..4d48bf62ca Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/surveymonkey-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/swagbucks-com.png b/mobile/ios/Client/Assets/TopSites/swagbucks-com.png new file mode 100644 index 0000000000..3e1fc6df7e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/swagbucks-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/t-mobile-com.png b/mobile/ios/Client/Assets/TopSites/t-mobile-com.png new file mode 100644 index 0000000000..221e66c359 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/t-mobile-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/taboola-com.png b/mobile/ios/Client/Assets/TopSites/taboola-com.png new file mode 100644 index 0000000000..f485c184c4 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/taboola-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/talkingpointsmemo-com.png b/mobile/ios/Client/Assets/TopSites/talkingpointsmemo-com.png new file mode 100644 index 0000000000..781ab88f8c Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/talkingpointsmemo-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/taobao-com.png b/mobile/ios/Client/Assets/TopSites/taobao-com.png new file mode 100644 index 0000000000..2fb36ef86f Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/taobao-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/target-com.png b/mobile/ios/Client/Assets/TopSites/target-com.png new file mode 100644 index 0000000000..60db330959 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/target-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/thedailybeast-com.png b/mobile/ios/Client/Assets/TopSites/thedailybeast-com.png new file mode 100644 index 0000000000..eac04ef598 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/thedailybeast-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/theguardian-com.png b/mobile/ios/Client/Assets/TopSites/theguardian-com.png new file mode 100644 index 0000000000..8712caf44d Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/theguardian-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/thesaurus-com.png b/mobile/ios/Client/Assets/TopSites/thesaurus-com.png new file mode 100644 index 0000000000..e204efc44c Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/thesaurus-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ticketmaster-com.png b/mobile/ios/Client/Assets/TopSites/ticketmaster-com.png new file mode 100644 index 0000000000..8924d6e2f8 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ticketmaster-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/tripadvisor-com.png b/mobile/ios/Client/Assets/TopSites/tripadvisor-com.png new file mode 100644 index 0000000000..edcfae006d Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/tripadvisor-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/trulia-com.png b/mobile/ios/Client/Assets/TopSites/trulia-com.png new file mode 100644 index 0000000000..386dce7102 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/trulia-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/tumblr-com.png b/mobile/ios/Client/Assets/TopSites/tumblr-com.png new file mode 100644 index 0000000000..01b2e8daa1 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/tumblr-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/twitch-tv.png b/mobile/ios/Client/Assets/TopSites/twitch-tv.png new file mode 100644 index 0000000000..2021463da9 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/twitch-tv.png differ diff --git a/mobile/ios/Client/Assets/TopSites/twitter-com.png b/mobile/ios/Client/Assets/TopSites/twitter-com.png new file mode 100644 index 0000000000..de2f9eb1de Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/twitter-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/ups-com.png b/mobile/ios/Client/Assets/TopSites/ups-com.png new file mode 100644 index 0000000000..62b0ff38b5 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/ups-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/usaa-com.png b/mobile/ios/Client/Assets/TopSites/usaa-com.png new file mode 100644 index 0000000000..3f175e6946 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/usaa-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/usatoday-com.png b/mobile/ios/Client/Assets/TopSites/usatoday-com.png new file mode 100644 index 0000000000..090a26ed7e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/usatoday-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/usbank-com.png b/mobile/ios/Client/Assets/TopSites/usbank-com.png new file mode 100644 index 0000000000..f1f254d3bf Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/usbank-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/usps-com.png b/mobile/ios/Client/Assets/TopSites/usps-com.png new file mode 100644 index 0000000000..d709c6e72f Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/usps-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/verizon-com.png b/mobile/ios/Client/Assets/TopSites/verizon-com.png new file mode 100644 index 0000000000..001bc86f03 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/verizon-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/verizonwireless-com.png b/mobile/ios/Client/Assets/TopSites/verizonwireless-com.png new file mode 100644 index 0000000000..2bc56995c1 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/verizonwireless-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/vice-com.png b/mobile/ios/Client/Assets/TopSites/vice-com.png new file mode 100644 index 0000000000..c281d1afc6 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/vice-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/vimeo-com.png b/mobile/ios/Client/Assets/TopSites/vimeo-com.png new file mode 100644 index 0000000000..52eb2cd427 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/vimeo-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/walmart-com.png b/mobile/ios/Client/Assets/TopSites/walmart-com.png new file mode 100644 index 0000000000..ac9400b1f7 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/walmart-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/washingtonpost-com.png b/mobile/ios/Client/Assets/TopSites/washingtonpost-com.png new file mode 100644 index 0000000000..bc14e4cbe5 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/washingtonpost-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wayfair-com.png b/mobile/ios/Client/Assets/TopSites/wayfair-com.png new file mode 100644 index 0000000000..1c467d0be6 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wayfair-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/weather-com.png b/mobile/ios/Client/Assets/TopSites/weather-com.png new file mode 100644 index 0000000000..866138a42a Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/weather-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/webmd-com.png b/mobile/ios/Client/Assets/TopSites/webmd-com.png new file mode 100644 index 0000000000..db3f46094c Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/webmd-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wellsfargo-com.png b/mobile/ios/Client/Assets/TopSites/wellsfargo-com.png new file mode 100644 index 0000000000..3675c67901 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wellsfargo-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wikia-com.png b/mobile/ios/Client/Assets/TopSites/wikia-com.png new file mode 100644 index 0000000000..7630eeb187 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wikia-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wikihow-com.png b/mobile/ios/Client/Assets/TopSites/wikihow-com.png new file mode 100644 index 0000000000..7560695b3c Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wikihow-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wikipedia-org.png b/mobile/ios/Client/Assets/TopSites/wikipedia-org.png new file mode 100644 index 0000000000..de6627270e Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wikipedia-org.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wired-com.png b/mobile/ios/Client/Assets/TopSites/wired-com.png new file mode 100644 index 0000000000..63fb545a1a Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wired-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wittyfeed-com.png b/mobile/ios/Client/Assets/TopSites/wittyfeed-com.png new file mode 100644 index 0000000000..6f3a98183d Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wittyfeed-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wordpress-com.png b/mobile/ios/Client/Assets/TopSites/wordpress-com.png new file mode 100644 index 0000000000..5403f48a70 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wordpress-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wsj-com.png b/mobile/ios/Client/Assets/TopSites/wsj-com.png new file mode 100644 index 0000000000..a53adcfd40 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wsj-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/wunderground-com.png b/mobile/ios/Client/Assets/TopSites/wunderground-com.png new file mode 100644 index 0000000000..d444c58b90 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/wunderground-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/xfinity-com.png b/mobile/ios/Client/Assets/TopSites/xfinity-com.png new file mode 100644 index 0000000000..1b8c732868 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/xfinity-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/yahoo-com.png b/mobile/ios/Client/Assets/TopSites/yahoo-com.png new file mode 100644 index 0000000000..50320c7a16 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/yahoo-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/yelp-com.png b/mobile/ios/Client/Assets/TopSites/yelp-com.png new file mode 100644 index 0000000000..74214d9832 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/yelp-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/youtube-com.png b/mobile/ios/Client/Assets/TopSites/youtube-com.png new file mode 100644 index 0000000000..9e54c0a698 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/youtube-com.png differ diff --git a/mobile/ios/Client/Assets/TopSites/zillow-com.png b/mobile/ios/Client/Assets/TopSites/zillow-com.png new file mode 100644 index 0000000000..930abb4bc7 Binary files /dev/null and b/mobile/ios/Client/Assets/TopSites/zillow-com.png differ diff --git a/mobile/ios/Client/Assets/top_sites.json b/mobile/ios/Client/Assets/top_sites.json new file mode 100644 index 0000000000..fd4f2c3ee4 --- /dev/null +++ b/mobile/ios/Client/Assets/top_sites.json @@ -0,0 +1,1384 @@ +[ + { + "title": "aa", + "url": "https://www.aa.com/", + "image_url": "aa-com.png", + "background_color": "#FAFAFA", + "domain": "aa.com" + }, + { + "title": "abcnews.go", + "url": "http://abcnews.go.com/", + "image_url": "abcnews-go-com.png", + "background_color": "#FFF", + "domain": "abcnews.go.com" + }, + { + "title": "about", + "url": "http://www.about.com/", + "image_url": "about-com.png", + "background_color": "#FFF", + "domain": "about.com" + }, + { + "title": "accuweather", + "url": "http://www.accuweather.com/", + "image_url": "accuweather-com.png", + "background_color": "#f56b17", + "domain": "accuweather.com" + }, + { + "title": "adobe", + "url": "http://www.adobe.com/", + "image_url": "adobe-com.png", + "background_color": "#e22919", + "domain": "adobe.com" + }, + { + "title": "adp", + "url": "http://www.adp.com/", + "image_url": "adp-com.png", + "background_color": "#f02311", + "domain": "adp.com" + }, + { + "title": "airbnb", + "url": "https://www.airbnb.com/", + "image_url": "airbnb-com.png", + "background_color": "#ff585a", + "domain": "airbnb.com" + }, + { + "title": "allrecipes", + "url": "http://allrecipes.com/", + "image_url": "allrecipes-com.png", + "background_color": "#ffb333", + "domain": "allrecipes.com" + }, + { + "title": "amazon", + "url": "http://www.amazon.com/", + "image_url": "amazon-com.png", + "background_color": "#FFF", + "is_multi_region_domain": "true", + "domain": "amazon" + }, + { + "title": "americanexpress", + "url": "https://www.americanexpress.com", + "image_url": "americanexpress-com.png", + "background_color": "#e0e0e0", + "domain": "americanexpress.com" + }, + { + "title": "ancestry", + "url": "http://www.ancestry.com/", + "image_url": "ancestry-com.png", + "background_color": "#9bbf2f", + "domain": "ancestry.com" + }, + { + "title": "answers", + "url": "http://www.answers.com", + "image_url": "answers-com.png", + "background_color": "#3c67d5", + "domain": "answers.com" + }, + { + "title": "aol", + "url": "http://www.aol.com/", + "image_url": "aol-com.png", + "background_color": "#e0e0e0", + "domain": "aol.com" + }, + { + "title": "apple", + "url": "http://www.apple.com/", + "image_url": "apple-com.png", + "background_color": "#6d6e71", + "domain": "apple.com" + }, + { + "title": "ask.com", + "url": "http://www.ask.com", + "image_url": "ask-com.png", + "background_color": "#cf0000", + "domain": "ask.com" + }, + { + "title": "att", + "url": "https://www.att.com/", + "image_url": "att-com.png", + "background_color": "#5ba1ca", + "domain": "att.com" + }, + { + "title": "aws.amazon", + "url": "https://aws.amazon.com/", + "image_url": "amazonaws-com.png", + "background_color": "#FFF", + "domain": "aws.amazon.com" + }, + { + "title": "baidu", + "url": "http://baidu.com/", + "image_url": "baidu-com.png", + "background_color": "#c33302", + "domain": "baidu.com" + }, + { + "title": "bankofamerica", + "url": "https://www.bankofamerica.com", + "image_url": "bankofamerica-com.png", + "background_color": "#eb3146", + "domain": "bankofamerica.com" + }, + { + "title": "bbc", + "url": "http://www.bbc.com/", + "image_url": "bbc-com.png", + "background_color": "#000000", + "domain": "bbc.com" + }, + { + "title": "bestbuy", + "url": "http://www.bestbuy.com", + "image_url": "bestbuy-com.png", + "background_color": "#003a65", + "domain": "bestbuy.com" + }, + { + "title": "bing", + "url": "http://www.bing.com/", + "image_url": "bing-com.png", + "background_color": "#138484", + "domain": "bing.com" + }, + { + "title": "blackboard", + "url": "http://www.blackboard.com/", + "image_url": "blackboard-com.png", + "background_color": "#e6e6e6", + "domain": "blackboard.com" + }, + { + "title": "bleacherreport", + "url": "http://bleacherreport.com/", + "image_url": "bleacherreport-com.png", + "background_color": "#ec412e", + "domain": "bleacherreport.com" + }, + { + "title": "blogger", + "url": "https://www.blogger.com/home", + "image_url": "blogger-com.png", + "background_color": "#ff8822", + "domain": "blogger.com" + }, + { + "title": "box", + "url": "https://www.box.com/", + "image_url": "box-com.png", + "background_color": "#4daee8", + "domain": "box.com" + }, + { + "title": "businessinsider", + "url": "http://www.businessinsider.com", + "image_url": "businessinsider-com.png", + "background_color": "#1d5b7d", + "domain": "businessinsider.com" + }, + { + "title": "buzzfeed", + "url": "http://www.buzzfeed.com/index", + "image_url": "buzzfeed-com.png", + "background_color": "#ee3322", + "domain": "buzzfeed.com" + }, + { + "title": "buzzlie", + "url": "http://buzzlie.com/", + "image_url": "buzzlie-com.png", + "background_color": "#ff68b6", + "domain": "buzzlie.com" + }, + { + "title": "California", + "url": "http://ca.gov/", + "image_url": "ca-gov.png", + "background_color": "#000201", + "domain": "ca.gov" + }, + { + "title": "capitalone", + "url": "https://www.capitalone.com/", + "image_url": "capitalone-com.png", + "background_color": "#303e4f", + "domain": "capitalone.com" + }, + { + "title": "cbsnews", + "url": "http://www.cbsnews.com/", + "image_url": "cbsnews-com.png", + "background_color": "#000", + "domain": "cbsnews.com" + }, + { + "title": "cbssports", + "url": "http://www.cbssports.com/", + "image_url": "cbssports-com.png", + "background_color": "#014a8f", + "domain": "cbssports.com" + }, + { + "title": "chase", + "url": "https://www.chase.com", + "image_url": "chase-com.png", + "background_color": "#0d68c1", + "domain": "chase.com" + }, + { + "title": "cnet", + "url": "http://www.cnet.com/", + "image_url": "cnet-com.png", + "background_color": "#FFF", + "domain": "cnet.com" + }, + { + "title": "cnn", + "url": "http://www.cnn.com", + "image_url": "cnn-com.png", + "background_color": "#d41c1e", + "domain": "cnn.com" + }, + { + "title": "comcast", + "urls": ["http://www.comcast.net/", "http://www.xfinity.com/"], + "image_url": "xfinity-com.png", + "background_color": "#000", + "domain": "comcast.net" + }, + { + "title": "conservativetribune", + "url": "http://conservativetribune.com/", + "image_url": "conservativetribune-com.png", + "background_color": "#ae0001", + "domain": "conservativetribune.com" + }, + { + "title": "costco", + "url": "http://www.costco.com/", + "image_url": "costco-com.png", + "background_color": "#005bad", + "domain": "costco.com" + }, + { + "title": "craigslist", + "url": "http://craigslist.org/", + "image_url": "craigslist-org.png", + "background_color": "#652892", + "is_multi_region_domain": "true", + "domain": "craigslist" + }, + { + "title": "dailymail", + "url": "http://www.dailymail.co.uk/", + "image_url": "dailymail-co-uk.png", + "background_color": "#0064c1", + "domain": "dailymail.co.uk" + }, + { + "title": "dailybeast", + "url": "https://www.thedailybeast.com/", + "image_url": "dailybeast-com.png", + "background_color": "#f12c15", + "domain": "dailybeast.com" + }, + { + "title": "delta", + "url": "https://www.delta.com/", + "image_url": "delta-com.png", + "background_color": "#1d649e", + "domain": "delta.com" + }, + { + "title": "deviantart", + "url": "http://www.deviantart.com/", + "image_url": "deviantart-com.png", + "background_color": "#00ce3e", + "domain": "deviantart.com" + }, + { + "title": "digg", + "url": "http://digg.com/", + "image_url": "digg-com.png", + "background_color": "#000", + "domain": "digg.com" + }, + { + "title": "diply", + "url": "http://diply.com/", + "image_url": "diply-com.png", + "background_color": "#2168b3", + "domain": "diply.com" + }, + { + "title": "discover", + "urls": ["https://www.discover.com/", "https://www.discovercard.com/"], + "image_url": "discovercard-com.png", + "background_color": "#d6d6d6", + "domain": "discover.com" + }, + { + "title": "dropbox", + "url": "https://www.dropbox.com/", + "image_url": "dropbox-com.png", + "background_color": "#007fe2", + "domain": "dropbox.com" + }, + { + "title": "drudgereport", + "url": "http://drudgereport.com/", + "image_url": "drudgereport-com.png", + "background_color": "#FFF", + "domain": "drudgereport.com" + }, + { + "title": "ebates", + "url": "http://www.ebates.com/", + "image_url": "ebates-com.png", + "background_color": "#14af44", + "domain": "ebates.com" + }, + { + "title": "ebay", + "url": "http://www.ebay.com", + "image_url": "ebay-com.png", + "background_color": "#ededed", + "domain": "ebay.com" + }, + { + "title": "espn.go", + "url": "http://espn.go.com", + "image_url": "espn-go-com.png", + "background_color": "#4b4b4b", + "domain": "espn.go.com" + }, + { + "title": "etsy", + "url": "https://www.etsy.com/", + "image_url": "etsy-com.png", + "background_color": "#f76300", + "domain": "etsy.com" + }, + { + "title": "eventbrite", + "url": "https://www.eventbrite.com/", + "image_url": "eventbrite-com.png", + "background_color": "#ff8000", + "domain": "eventbrite.com" + }, + { + "title": "expedia", + "url": "https://www.expedia.com/", + "image_url": "expedia-com.png", + "background_color": "#003460", + "domain": "expedia.com" + }, + { + "title": "facebook", + "url": "https://www.facebook.com/", + "image_url": "facebook-com.png", + "background_color": "#3b5998", + "domain": "facebook.com" + }, + { + "title": "faithtap", + "url": "http://faithtap.com/", + "image_url": "faithtap-com.png", + "background_color": "#4c286f", + "domain": "faithtap.com" + }, + { + "title": "fedex", + "url": "http://www.fedex.com/", + "image_url": "fedex-com.png", + "background_color": "#391675", + "domain": "fedex.com" + }, + { + "title": "feedly", + "url": "http://feedly.com/", + "image_url": "feedly-com.png", + "background_color": "#20b447", + "domain": "feedly.com" + }, + { + "title": "fitbit", + "url": "https://www.fitbit.com/", + "image_url": "fitbit-com.png", + "background_color": "#00b0ba", + "domain": "fitbit.com" + }, + { + "title": "flickr", + "url": "https://www.flickr.com", + "image_url": "flickr-com.png", + "background_color": "#dcdcdc", + "domain": "flickr.com" + }, + { + "title": "foodnetwork", + "url": "http://www.foodnetwork.com/", + "image_url": "foodnetwork-com.png", + "background_color": "#f50024", + "domain": "foodnetwork.com" + }, + { + "title": "forbes", + "url": "http://www.forbes.com/", + "image_url": "forbes-com.png", + "background_color": "#4177ab", + "domain": "forbes.com" + }, + { + "title": "foxnews", + "url": "http://www.foxnews.com", + "image_url": "foxnews-com.png", + "background_color": "#9e0b0f", + "domain": "foxnews.com" + }, + { + "title": "gap", + "url": "http://www.gap.com/", + "image_url": "gap-com.png", + "background_color": "#002861", + "domain": "gap.com" + }, + { + "title": "gawker", + "url": "http://gawker.com/", + "image_url": "gawker-com.png", + "background_color": "#d75343", + "domain": "gawker.com" + }, + { + "title": "gfycat", + "url": "http://gfycat.com/", + "image_url": "gfycat-com.png", + "background_color": "#eaeaea", + "domain": "gfycat.com" + }, + { + "title": "GitHub", + "url": "https://github.com/", + "image_url": "github-com.png", + "background_color": "#000", + "domain": "github.com" + }, + { + "title": "gizmodo", + "url": "http://gizmodo.com/", + "image_url": "gizmodo-com.png", + "background_color": "#000", + "domain": "gizmodo.com" + }, + { + "title": "glassdoor", + "url": "https://www.glassdoor.com/", + "image_url": "glassdoor-com.png", + "background_color": "#7aad28", + "domain": "glassdoor.com" + }, + { + "title": "go", + "url": "http://go.com", + "image_url": "go-com.png", + "background_color": "#000", + "domain": "go.com" + }, + { + "title": "goodreads", + "url": "http://www.goodreads.com/", + "image_url": "goodreads-com.png", + "background_color": "#382110", + "domain": "goodreads.com" + }, + { + "title": "google", + "url": "https://www.google.com/", + "image_url": "google-com.png", + "background_color": "#FFF", + "is_multi_region_domain": "true", + "domain": "google" + }, + { + "title": "admin.google", + "url": "https://admin.google.com/", + "image_url": "google-admin.png", + "background_color": "#FFF", + "domain": "admin.google.com" + }, + { + "title": "calendar.google", + "url": "https://calendar.google.com/", + "image_url": "google-calendar.png", + "background_color": "#FFF", + "domain": "calendar.google.com" + }, + { + "title": "contacts.google", + "url": "https://contacts.google.com/", + "image_url": "google-contacts.png", + "background_color": "#FFF", + "domain": "contacts.google.com" + }, + { + "title": "docs.google", + "url": "https://docs.google.com/", + "image_url": "google-docs.png", + "background_color": "#FFF", + "domain": "docs.google.com" + }, + { + "title": "drive.google", + "url": "https://drive.google.com/", + "image_url": "google-drive.png", + "background_color": "#FFF", + "domain": "drive.google.com" + }, + { + "title": "forms.google", + "url": "https://forms.google.com/", + "image_url": "google-forms.png", + "background_color": "#FFF", + "domain": "forms.google.com" + }, + { + "title": "gmail", + "urls": ["https://mail.google.com/", "https://gmail.com"], + "image_url": "google-gmail.png", + "background_color": "#FFF", + "domain": "mail.google.com" + }, + { + "title": "groups.google", + "url": "https://groups.google.com/", + "image_url": "google-groups.png", + "background_color": "#FFF", + "domain": "groups.google.com" + }, + { + "title": "hangouts.google", + "url": "https://hangouts.google.com/", + "image_url": "google-hangouts.png", + "background_color": "#FFF", + "domain": "hangouts.google.com" + }, + { + "title": "plus.google", + "url": "https://plus.google.com/", + "image_url": "google-plus.png", + "background_color": "#FFF", + "domain": "plus.google.com" + }, + { + "title": "sheets.google", + "url": "https://sheets.google.com/", + "image_url": "google-sheets.png", + "background_color": "#FFF", + "domain": "sheets.google.com" + }, + { + "title": "sites.google", + "url": "https://sites.google.com/", + "image_url": "google-sites.png", + "background_color": "#FFF", + "domain": "sites.google.com" + }, + { + "title": "slides.google", + "url": "https://slides.google.com/", + "image_url": "google-slides.png", + "background_color": "#FFF", + "domain": "slides.google.com" + }, + { + "title": "photos.google", + "url": "https://photos.google.com/", + "image_url": "google-photos.png", + "background_color": "#FFF", + "domain": "photos.google.com" + }, + { + "title": "images.google", + "url": "https://images.google.com/", + "image_url": "images-google-com.png", + "background_color": "#FFF", + "domain": "images.google.com" + }, + { + "title": "groupon", + "url": "https://www.groupon.com/", + "image_url": "groupon-com.png", + "background_color": "#53a318", + "domain": "groupon.com" + }, + { + "title": "homedepot", + "url": "http://www.homedepot.com/", + "image_url": "homedepot-com.png", + "background_color": "#f7d5a4", + "domain": "homedepot.com" + }, + { + "title": "houzz", + "url": "https://www.houzz.com/", + "image_url": "houzz-com.png", + "background_color": "#52a02a", + "domain": "houzz.com" + }, + { + "title": "huffingtonpost", + "url": "http://www.huffingtonpost.com/", + "image_url": "huffingtonpost-com.png", + "background_color": "#7dbdb8", + "domain": "huffingtonpost.com" + }, + { + "title": "hulu", + "url": "http://www.hulu.com/", + "image_url": "hulu-com.png", + "background_color": "#97c64f", + "domain": "hulu.com" + }, + { + "title": "ign", + "url": "http://www.ign.com/", + "image_url": "ign-com.png", + "background_color": "#ff0000", + "domain": "ign.com" + }, + { + "title": "ikea", + "url": "http://www.ikea.com/", + "image_url": "ikea-com.png", + "background_color": "#00329c", + "domain": "ikea.com" + }, + { + "title": "imdb", + "url": "http://www.imdb.com/", + "image_url": "imdb-com.png", + "background_color": "#ffd100", + "domain": "imdb.com" + }, + { + "title": "imgur", + "url": "http://imgur.com/", + "image_url": "imgur-com.png", + "background_color": "#2a2c25", + "domain": "imgur.com" + }, + { + "title": "instagram", + "url": "https://www.instagram.com/", + "image_url": "instagram-com.png", + "background_color": "#0b558a", + "domain": "instagram.com" + }, + { + "title": "instructure", + "url": "https://www.instructure.com/", + "image_url": "instructure-com.png", + "background_color": "#efefef", + "domain": "instructure.com" + }, + { + "title": "intuit", + "url": "http://www.intuit.com/", + "image_url": "intuit-com.png", + "background_color": "#f6f6f6", + "domain": "intuit.com" + }, + { + "title": "irs", + "url": "https://www.irs.gov/", + "image_url": "irs-gov.png", + "background_color": "#efefef", + "domain": "irs.gov" + }, + { + "title": "invision", + "urls": ["https://www.invisionapp.com/", "https://mozilla.invisionapp.com/"], + "image_url": "invision-com.png", + "background_color": "#ff2e63", + "domain": "invisionapp.com" + }, + { + "title": "jcpenney", + "url": "http://www.jcpenney.com/", + "image_url": "jcpenney-com.png", + "background_color": "#fa0026", + "domain": "jcpenney.com" + }, + { + "title": "jd", + "url": "http://www.jd.com/", + "image_url": "jd-com.png", + "background_color": "#e50000", + "domain": "jd.com" + }, + { + "title": "kayak", + "url": "https://www.kayak.com/", + "image_url": "kayak-com.png", + "background_color": "#fff", + "domain": "kayak.com" + }, + { + "title": "kohl's", + "url": "http://www.kohls.com", + "image_url": "kohls-com.png", + "background_color": "#000", + "domain": "kohls.com" + }, + { + "title": "latimes", + "url": "http://www.latimes.com/", + "image_url": "latimes-com.png", + "background_color": "#FFF", + "domain": "latimes.com" + }, + { + "title": "lifehacker", + "url": "http://lifehacker.com/", + "image_url": "lifehacker-com.png", + "background_color": "#94b330", + "domain": "lifehacker.com" + }, + { + "title": "linkedin", + "url": "https://www.linkedin.com/", + "image_url": "linkedin-com.png", + "background_color": "#00659b", + "domain": "linkedin.com" + }, + { + "title": "lowes", + "url": "http://www.lowes.com/", + "image_url": "lowes-com.png", + "background_color": "#004793", + "domain": "lowes.com" + }, + { + "title": "macys", + "url": "http://www.macys.com/", + "image_url": "macys-com.png", + "background_color": "#ea0000", + "domain": "macys.com" + }, + { + "title": "login.microsoftonline", + "url": "https://login.microsoftonline.com/", + "image_url": "microsoftonline-com.png", + "background_color": "#ce4f00", + "domain": "login.microsoftonline.com" + }, + { + "title": "mail.live", + "url": "https://mail.live.com", + "image_url": "live-com.png", + "background_color": "#0070c9", + "domain": "mail.live.com" + }, + { + "title": "mapquest", + "url": "http://www.mapquest.com/", + "image_url": "mapquest-com.png", + "background_color": "#373737", + "domain": "mapquest.com" + }, + { + "title": "mashable", + "url": "http://mashable.com/stories/", + "image_url": "mashable-com.png", + "background_color": "#00aef0", + "domain": "mashable.com" + }, + { + "title": "microsoft", + "url": "http://www.microsoft.com/", + "image_url": "microsoft-com.png", + "background_color": "#FFF", + "domain": "microsoft.com" + }, + { + "title": "mlb", + "url": "http://mlb.mlb.com/", + "image_url": "mlb-com.png", + "background_color": "#ffffff", + "domain": "mlb.com" + }, + { + "title": "msn", + "url": "http://www.msn.com/", + "image_url": "msn-com.png", + "background_color": "#000", + "domain": "msn.com" + }, + { + "title": "mozilla", + "url": "http://www.mozilla.com.cn/", + "image_url": "mozilla-com.png", + "background_color": "#000", + "domain": "mozilla.com.cn" + }, + { + "title": "nbcnews", + "url": "http://www.nbcnews.com/", + "image_url": "nbcnews-com.png", + "background_color": "#003a51", + "domain": "nbcnews.com" + }, + { + "title": "netflix", + "url": "https://www.netflix.com/", + "image_url": "netflix-com.png", + "background_color": "#000", + "domain": "netflix.com" + }, + { + "title": "newegg", + "url": "http://www.newegg.com/", + "image_url": "newegg-com.png", + "background_color": "#cecece", + "domain": "newegg.com" + }, + { + "title": "news.ycombinator", + "url": "https://news.ycombinator.com/", + "image_url": "news-ycombinator-com.png", + "background_color": "#D46D1D", + "domain": "news.ycombinator.com" + }, + { + "title": "nih", + "url": "http://www.nih.gov/", + "image_url": "nih-gov.png", + "background_color": "#efefef", + "domain": "nih.gov" + }, + { + "title": "nordstrom", + "url": "http://shop.nordstrom.com/", + "image_url": "nordstrom-com.png", + "background_color": "#7f7d7a", + "domain": "nordstrom.com" + }, + { + "title": "npr", + "url": "http://www.npr.org/", + "image_url": "npr-org.png", + "background_color": "#FFF", + "domain": "npr.org" + }, + { + "title": "nypost", + "url": "http://nypost.com/", + "image_url": "nypost-com.png", + "background_color": "#FFF", + "domain": "nypost.com" + }, + { + "title": "nytimes", + "url": "http://www.nytimes.com", + "image_url": "nytimes-com.png", + "background_color": "#FFF", + "domain": "nytimes.com" + }, + { + "title": "office", + "url": "https://www.office.com/", + "image_url": "office-com.png", + "background_color": "#000", + "domain": "office.com" + }, + { + "title": "online.citi", + "url": "https://online.citi.com/", + "image_url": "citi-com.png", + "background_color": "#FFF", + "domain": "online.citi.com" + }, + { + "title": "overstock", + "url": "http://www.overstock.com/", + "image_url": "overstock-com.png", + "background_color": "#fff", + "domain": "overstock.com" + }, + { + "title": "pandora", + "url": "http://www.pandora.com/", + "image_url": "pandora-com.png", + "background_color": "#efefef", + "domain": "pandora.com" + }, + { + "title": "Patch", + "url": "http://patch.com", + "image_url": "patch-com.png", + "background_color": "#519442", + "domain": "patch.com" + }, + { + "title": "paypal", + "url": "https://www.paypal.com/home", + "image_url": "paypal-com.png", + "background_color": "#009cde", + "domain": "paypal.com" + }, + { + "title": "people.com", + "url": "http://www.people.com/", + "image_url": "people-com.png", + "background_color": "#27c4ff", + "domain": "people.com" + }, + { + "title": "pinterest", + "url": "https://www.pinterest.com/", + "image_url": "pinterest-com.png", + "background_color": "#ba212b", + "domain": "pinterest.com" + }, + { + "title": "politico", + "url": "http://www.politico.com/", + "image_url": "politico-com.png", + "background_color": "#9f0000", + "domain": "politico.com" + }, + { + "title": "quora", + "url": "https://www.quora.com/", + "image_url": "quora-com.png", + "background_color": "#bb2920", + "domain": "quora.com" + }, + { + "title": "qq", + "url": "https://www.qq.com/", + "image_url": "qq-com.png", + "background_color": "#2d91da", + "domain": "qq.com" + }, + { + "title": "realtor", + "url": "http://www.realtor.com/", + "image_url": "realtor-com.png", + "background_color": "#fcfcfc", + "domain": "realtor.com" + }, + { + "title": "reddit", + "url": "https://www.reddit.com/", + "image_url": "reddit-com.png", + "background_color": "#cee3f8", + "domain": "reddit.com" + }, + { + "title": "salesforce", + "url": "http://www.salesforce.com/", + "image_url": "salesforce-com.png", + "background_color": "#efefef", + "domain": "salesforce.com" + }, + { + "title": "sears", + "url": "http://www.sears.com/", + "image_url": "sears-com.png", + "background_color": "#00265a", + "domain": "sears.com" + }, + { + "title": "sina", + "url": "http://www.sina.cn/", + "image_url": "sina-com.png", + "background_color": "#ff0000", + "domain": "sina.cn" + }, + { + "title": "sina", + "url": "http://www.sina.com/", + "image_url": "sina-com.png", + "background_color": "#ff0000", + "domain": "sina.com" + }, + { + "title": "slate", + "url": "http://www.slate.com/", + "image_url": "slate-com.png", + "background_color": "#670033", + "domain": "slate.com" + }, + { + "title": "slickdeals", + "url": "http://slickdeals.net", + "image_url": "slickdeals-net.png", + "background_color": "#0072bd", + "domain": "slickdeals.net" + }, + { + "title": "soundcloud", + "url": "https://soundcloud.com/", + "image_url": "soundcloud-com.png", + "background_color": "#F95300", + "domain": "soundcloud.com" + }, + { + "title": "southwest", + "url": "https://www.southwest.com/", + "image_url": "southwest-com.png", + "background_color": "#3452c1", + "domain": "southwest.com" + }, + { + "title": "spotify", + "url": "https://www.spotify.com/", + "image_url": "spotify-com.png", + "background_color": "#dd08a7", + "domain": "spotify.com" + }, + { + "title": "stackexchange", + "url": "http://stackexchange.com/", + "image_url": "stackexchange-com.png", + "background_color": "#fff", + "domain": "stackexchange.com" + }, + { + "title": "stackoverflow", + "url": "http://stackoverflow.com/", + "image_url": "stackoverflow-com.png", + "background_color": "#f48024", + "domain": "stackoverflow.com" + }, + { + "title": "staples", + "url": "http://www.staples.com/", + "image_url": "staples-com.png", + "background_color": "#F3F1F3", + "domain": "staples.com" + }, + { + "title": "strava", + "url": "http://www.strava.com/", + "image_url": "strava-com.png", + "background_color": "#ff4b00", + "domain": "strava.com" + }, + { + "title": "surveymonkey", + "url": "https://www.surveymonkey.com/", + "image_url": "surveymonkey-com.png", + "background_color": "#a6c32f", + "domain": "surveymonkey.com" + }, + { + "title": "swagbucks", + "url": "http://www.swagbucks.com/", + "image_url": "swagbucks-com.png", + "background_color": "#5fb5d6", + "domain": "swagbucks.com" + }, + { + "title": "talkingpointsmemo", + "url": "http://talkingpointsmemo.com/", + "image_url": "talkingpointsmemo-com.png", + "background_color": "#FFF", + "domain": "talkingpointsmemo.com" + }, + { + "title": "t-mobile", + "url": "http://www.t-mobile.com/", + "image_url": "t-mobile-com.png", + "background_color": "#f32f9d", + "domain": "t-mobile.com" + }, + { + "title": "taboola", + "url": "https://www.taboola.com/", + "image_url": "taboola-com.png", + "background_color": "#1761a8", + "domain": "taboola.com" + }, + { + "title": "taobao", + "url": "https://www.taobao.com/", + "image_url": "taobao-com.png", + "background_color": "#ff8300", + "domain": "taobao.com" + }, + { + "title": "target", + "url": "http://www.target.com", + "image_url": "target-com.png", + "background_color": "#e81530", + "domain": "target.com" + }, + { + "title": "thedailybeast", + "url": "http://www.thedailybeast.com/", + "image_url": "thedailybeast-com.png", + "background_color": "#f12c15", + "domain": "thedailybeast.com" + }, + { + "title": "theguardian", + "url": "http://www.theguardian.com/", + "image_url": "theguardian-com.png", + "background_color": "#005E91", + "domain": "theguardian.com" + }, + { + "title": "thesaurus", + "url": "http://www.thesaurus.com/", + "image_url": "thesaurus-com.png", + "background_color": "#ffce80", + "domain": "thesaurus.com" + }, + { + "title": "ticketmaster", + "url": "http://www.ticketmaster.com/", + "image_url": "ticketmaster-com.png", + "background_color": "#fff", + "domain": "ticketmaster.com" + }, + { + "title": "tripadvisor", + "url": "https://www.tripadvisor.com/", + "image_url": "tripadvisor-com.png", + "background_color": "#5ba443", + "domain": "tripadvisor.com" + }, + { + "title": "trulia", + "url": "http://www.trulia.com/", + "image_url": "trulia-com.png", + "background_color": "#62be06", + "domain": "trulia.com" + }, + { + "title": "tumblr", + "url": "https://www.tumblr.com/", + "image_url": "tumblr-com.png", + "background_color": "#4ebd89", + "domain": "tumblr.com" + }, + { + "title": "twitch", + "url": "https://www.twitch.tv/", + "image_url": "twitch-tv.png", + "background_color": "#5A43A9", + "domain": "twitch.tv" + }, + { + "title": "twitter", + "url": "https://twitter.com/", + "image_url": "twitter-com.png", + "background_color": "#049ff5", + "domain": "twitter.com" + }, + { + "title": "ups", + "url": "https://www.ups.com/", + "image_url": "ups-com.png", + "background_color": "#281704", + "domain": "ups.com" + }, + { + "title": "usaa", + "url": "https://www.usaa.com/", + "image_url": "usaa-com.png", + "background_color": "#002a41", + "domain": "usaa.com" + }, + { + "title": "usatoday", + "url": "http://www.usatoday.com/", + "image_url": "usatoday-com.png", + "background_color": "#000", + "domain": "usatoday.com" + }, + { + "title": "usbank", + "url": "https://www.usbank.com/", + "image_url": "usbank-com.png", + "background_color": "#ff0022", + "domain": "usbank.com" + }, + { + "title": "usps", + "url": "https://www.usps.com/", + "image_url": "usps-com.png", + "background_color": "#f5f5f5", + "domain": "usps.com" + }, + { + "title": "verizon", + "url": "http://www.verizon.com/", + "image_url": "verizon-com.png", + "background_color": "#f00000", + "domain": "verizon.com" + }, + { + "title": "verizonwireless", + "url": "http://www.verizonwireless.com/", + "image_url": "verizonwireless-com.png", + "background_color": "#fff", + "domain": "verizonwireless.com" + }, + { + "title": "vice", + "url": "http://www.vice.com/", + "image_url": "vice-com.png", + "background_color": "#000", + "domain": "vice.com" + }, + { + "title": "vimeo", + "url": "https://vimeo.com/", + "image_url": "vimeo-com.png", + "background_color": "#00b1f2", + "domain": "vimeo.com" + }, + { + "title": "walmart", + "url": "http://www.walmart.com/", + "image_url": "walmart-com.png", + "background_color": "#fff", + "domain": "walmart.com" + }, + { + "title": "washingtonpost", + "url": "https://www.washingtonpost.com/regional/", + "image_url": "washingtonpost-com.png", + "background_color": "#fff", + "domain": "washingtonpost.com" + }, + { + "title": "wayfair", + "url": "http://www.wayfair.com/", + "image_url": "wayfair-com.png", + "background_color": "#ffffff", + "domain": "wayfair.com" + }, + { + "title": "weather", + "url": "https://weather.com/", + "image_url": "weather-com.png", + "background_color": "#2147a8", + "domain": "weather.com" + }, + { + "title": "webmd", + "url": "http://www.webmd.com/default.htm", + "image_url": "webmd-com.png", + "background_color": "#00639a", + "domain": "webmd.com" + }, + { + "title": "wellsfargo", + "url": "https://www.wellsfargo.com", + "image_url": "wellsfargo-com.png", + "background_color": "#ba1613", + "domain": "wellsfargo.com" + }, + { + "title": "wikia", + "url": "http://www.wikia.com/fandom", + "image_url": "wikia-com.png", + "background_color": "#f1f1f1", + "domain": "wikia.com" + }, + { + "title": "wikihow", + "url": "http://www.wikihow.com/", + "image_url": "wikihow-com.png", + "background_color": "#455046", + "domain": "wikihow.com" + }, + { + "title": "wikipedia", + "url": "https://www.wikipedia.org/", + "image_url": "wikipedia-org.png", + "background_color": "#fff", + "domain": "wikipedia.org" + }, + { + "title": "wired", + "url": "https://www.wired.com/", + "image_url": "wired-com.png", + "background_color": "#000", + "domain": "wired.com" + }, + { + "title": "wittyfeed", + "url": "http://www.wittyfeed.com", + "image_url": "wittyfeed-com.png", + "background_color": "#d83633", + "domain": "wittyfeed.com" + }, + { + "title": "wordpress", + "url": "https://wordpress.com", + "image_url": "wordpress-com.png", + "background_color": "#00739c", + "domain": "wordpress.com" + }, + { + "title": "wsj", + "url": "http://www.wsj.com/", + "image_url": "wsj-com.png", + "background_color": "#000000", + "domain": "wsj.com" + }, + { + "title": "wunderground", + "url": "https://www.wunderground.com/", + "image_url": "wunderground-com.png", + "background_color": "#000000", + "domain": "wunderground.com" + }, + { + "title": "yahoo", + "url": "https://www.yahoo.com/", + "image_url": "yahoo-com.png", + "background_color": "#5009a7", + "domain": "yahoo.com" + }, + { + "title": "yelp", + "url": "http://yelp.com/", + "image_url": "yelp-com.png", + "background_color": "#d83633", + "domain": "yelp.com" + }, + { + "title": "youtube", + "url": "https://www.youtube.com/", + "image_url": "youtube-com.png", + "background_color": "#db4338", + "domain": "youtube.com" + }, + { + "title": "zillow", + "url": "http://www.zillow.com/", + "image_url": "zillow-com.png", + "background_color": "#98c554", + "domain": "zillow.com" + } +] diff --git a/mobile/ios/Client/Assets/topdomains.txt b/mobile/ios/Client/Assets/topdomains.txt new file mode 100644 index 0000000000..de1c19f4b3 --- /dev/null +++ b/mobile/ios/Client/Assets/topdomains.txt @@ -0,0 +1,455 @@ +google.com +facebook.com +amazon.com +youtube.com +yahoo.com +ebay.com +wikipedia.org +twitter.com +reddit.com +go.com +craigslist.org +live.com +netflix.com +pinterest.com +bing.com +linkedin.com +imgur.com +espn.go.com +walmart.com +tumblr.com +target.com +paypal.com +cnn.com +chase.com +instagram.com +bestbuy.com +blogspot.com +nytimes.com +msn.com +imdb.com +apple.com +bankofamerica.com +diply.com +huffingtonpost.com +yelp.com +wellsfargo.com +etsy.com +weather.com +wordpress.com +buzzfeed.com +zillow.com +kohls.com +aol.com +homedepot.com +foxnews.com +microsoft.com +comcast.net +wikia.com +groupon.com +macys.com +washingtonpost.com +outbrain.com +microsoftonline.com +xfinity.com +usps.com +hulu.com +americanexpress.com +slickdeals.net +pandora.com +office.com +cnet.com +indeed.com +capitalone.com +nfl.com +ups.com +ask.com +verizonwireless.com +newegg.com +usatoday.com +forbes.com +dailymail.co.uk +dropbox.com +att.com +costco.com +gfycat.com +lowes.com +gap.com +about.com +tripadvisor.com +fedex.com +baidu.com +vice.com +nordstrom.com +adobe.com +bbc.com +twitch.tv +allrecipes.com +retailmenot.com +stackoverflow.com +citi.com +sears.com +jcpenney.com +webmd.com +ijreview.com +nih.gov +answers.com +foodnetwork.com +discovercard.com +cbssports.com +overstock.com +businessinsider.com +office365.com +theguardian.com +staples.com +bleacherreport.com +toysrus.com +verizon.com +github.com +wayfair.com +salesforce.com +zulily.com +wsj.com +flickr.com +goodreads.com +realtor.com +nbcnews.com +ebates.com +ancestry.com +wunderground.com +instructure.com +people.com +stackexchange.com +drudgereport.com +fidelity.com +southwest.com +deviantart.com +thesaurus.com +intuit.com +woot.com +pch.com +soundcloud.com +force.com +samsclub.com +ign.com +qvc.com +npr.org +patch.com +dell.com +accuweather.com +vimeo.com +expedia.com +trulia.com +ca.gov +swagbucks.com +spotify.com +bedbathandbeyond.com +nypost.com +aliexpress.com +blackboard.com +ticketmaster.com +ikea.com +feedly.com +usaa.com +tmz.com +quora.com +lifehacker.com +kayak.com +reference.com +zappos.com +gizmodo.com +slate.com +faithtap.com +adp.com +abcnews.go.com +sephora.com +cbs.com +latimes.com +shutterfly.com +t-mobile.com +littlethings.com +glassdoor.com +bloomberg.com +cbsnews.com +wikihow.com +walgreens.com +usbank.com +blogger.com +weebly.com +gamestop.com +food.com +time.com +kickstarter.com +okcupid.com +aa.com +weather.gov +nametests.com +fandango.com +engadget.com +steamcommunity.com +thekitchn.com +nba.com +mashable.com +hp.com +gamefaqs.com +delta.com +breitbart.com +coupons.com +eonline.com +surveymonkey.com +kmart.com +barnesandnoble.com +meetup.com +bhphotovideo.com +fanduel.com +quizlet.com +nydailynews.com +sbnation.com +nbcsports.com +likes.com +bbc.co.uk +ew.com +nike.com +rottentomatoes.com +steampowered.com +reuters.com +qq.com +today.com +mapquest.com +audible.com +priceline.com +whitepages.com +united.com +myfitnesspal.com +icloud.com +forever21.com +theatlantic.com +microsoftstore.com +theverge.com +gawker.com +houzz.com +mayoclinic.org +rei.com +sfgate.com +lifebuzz.com +discover.com +pnc.com +pof.com +iflscience.com +popsugar.com +creditkarma.com +telegraph.co.uk +airbnb.com +buzzlie.com +cnbc.com +deadspin.com +sina.com.cn +legacy.com +thedailybeast.com +samsung.com +nextdoor.com +evite.com +shopify.com +yellowpages.com +pcmag.com +redfin.com +emgn.com +weibo.com +alibaba.com +cabelas.com +battle.net +foxsports.com +taobao.com +eventbrite.com +victoriassecret.com +theblaze.com +dealnews.com +cbslocal.com +cvs.com +dailymotion.com +ecollege.com +gofundme.com +fitbit.com +instructables.com +godaddy.com +babycenter.com +squarespace.com +llbean.com +dickssportinggoods.com +6pm.com +myway.com +hsn.com +wired.com +officedepot.com +ozztube.com +usmagazine.com +match.com +cracked.com +evernote.com +box.com +starbucks.com +kbb.com +mlb.com +marriott.com +si.com +jezebel.com +pbs.org +consumerreports.org +roblox.com +urbandictionary.com +kotaku.com +xbox.com +marketwatch.com +refinery29.com +wikimedia.org +tvguide.com +politico.com +barclaycardus.com +abc.go.com +mint.com +topix.com +theblackfriday.com +aarp.org +hotnewhiphop.com +yourdailydish.com +sprint.com +vox.com +cafemom.com +nbc.com +dailykos.com +azlyrics.com +autotrader.com +hilton.com +irs.gov +monster.com +fatwallet.com +mailchimp.com +webex.com +landsend.com +wix.com +usnews.com +jcrew.com +jet.com +capitalone360.com +sharepoint.com +schwab.com +ulta.com +vistaprint.com +rollingstone.com +biblegateway.com +gamespot.com +io9.com +opentable.com +hm.com +duckduckgo.com +chron.com +photobucket.com +shareasale.com +directv.com +avg.com +oracle.com +hotels.com +timewarnercable.com +chicagotribune.com +ehow.com +primewire.ag +abs-cbnnews.com +salon.com +greatergood.com +epicurious.com +fool.com +patheos.com +custhelp.com +purdue.edu +tickld.com +frys.com +indiatimes.com +amazon.co.uk +zendesk.com +tigerdirect.com +stubhub.com +healthcare.gov +archive.org +qualtrics.com +ravelry.com +cars.com +redbox.com +jalopnik.com +speedtest.net +harvard.edu +slideshare.net +kinja.com +nesn.com +michaels.com +mit.edu +bodybuilding.com +edmunds.com +nhl.com +zergnet.com +terraclicks.com +techcrunch.com +regnok.com +pogo.com +backpage.com +mozilla.org +naver.com +giphy.com +bankrate.com +msnbc.com +digitaltrends.com +fanfiction.net +skype.com +disney.go.com +norton.com +androidcentral.com +tomshardware.com +thefreedictionary.com +liveleak.com +247sports.com +merriam-webster.com +wnd.com +earthlink.net +conservativetribune.com +independent.co.uk +drugs.com +rotoworld.com +nationalgeographic.com +ae.com +noaa.gov +arstechnica.com +thinkgeek.com +stanford.edu +bizjournals.com +hootsuite.com +genius.com +goodhousekeeping.com +vanguard.com +ny.gov +citibankonline.com +booking.com +mic.com +orbitz.com +dominos.com +medium.com +wow.com +urbanoutfitters.com +douban.com +timeanddate.com +draftkings.com +livestrong.com +livingsocial.com +cox.net +theonion.com +marthastewart.com +comenity.net +worldlifestyle.com +disney.com +realsimple.com +vrbo.com +playstation.com +potterybarn.com +zazzle.com +ksl.com +tdbank.com +sourceforge.net +careerbuilder.com diff --git a/mobile/ios/Client/Configuration/Fennec.enterprise.xcconfig b/mobile/ios/Client/Configuration/Fennec.enterprise.xcconfig new file mode 100644 index 0000000000..dcf262bfa3 --- /dev/null +++ b/mobile/ios/Client/Configuration/Fennec.enterprise.xcconfig @@ -0,0 +1,20 @@ +// 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/. + +MOZ_BUNDLE_DISPLAY_NAME = Fennec + +// Bundle Identifier +MOZ_BUNDLE_ID = org.mozilla.ios.FennecEnterprise + +// Flag to indicate if we want to include the debug settings bundle or not +INCLUDE_SETTINGS_BUNDLE = YES + +// Adjust SDK Variables +ADJUST_ENVIRONMENT = +ADJUST_APP_TOKEN = + +// Leanplum SDK Variables +LEANPLUM_ENVIRONMENT = +LEANPLUM_APP_ID = +LEANPLUM_KEY = diff --git a/mobile/ios/Client/Configuration/Fennec.xcconfig b/mobile/ios/Client/Configuration/Fennec.xcconfig new file mode 100644 index 0000000000..5cfd3171b9 --- /dev/null +++ b/mobile/ios/Client/Configuration/Fennec.xcconfig @@ -0,0 +1,20 @@ +// 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/. + +MOZ_BUNDLE_DISPLAY_NAME = Fennec ($(USER)) + +// Bundle Identifier +MOZ_BUNDLE_ID = org.mozilla.ios.Fennec + +// Flag to indicate if we want to include the debug settings bundle or not +INCLUDE_SETTINGS_BUNDLE = YES + +// Adjust SDK Variables +ADJUST_ENVIRONMENT = +ADJUST_APP_TOKEN = + +// Leanplum SDK Variables +LEANPLUM_ENVIRONMENT = development +LEANPLUM_APP_ID = +LEANPLUM_KEY = diff --git a/mobile/ios/Client/Configuration/Firefox.xcconfig b/mobile/ios/Client/Configuration/Firefox.xcconfig new file mode 100644 index 0000000000..8fcd7900e1 --- /dev/null +++ b/mobile/ios/Client/Configuration/Firefox.xcconfig @@ -0,0 +1,20 @@ +// 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/. + +MOZ_BUNDLE_DISPLAY_NAME = Firefox + +// Bundle Identifier +MOZ_BUNDLE_ID = org.mozilla.ios.Firefox + +// Flag to indicate if we want to include the debug settings bundle or not +INCLUDE_SETTINGS_BUNDLE = NO + +// Adjust SDK Variables +ADJUST_ENVIRONMENT = +ADJUST_APP_TOKEN = + +// Leanplum SDK Variables +LEANPLUM_ENVIRONMENT = +LEANPLUM_APP_ID = +LEANPLUM_KEY = diff --git a/mobile/ios/Client/Configuration/FirefoxBeta.xcconfig b/mobile/ios/Client/Configuration/FirefoxBeta.xcconfig new file mode 100644 index 0000000000..6911d23c45 --- /dev/null +++ b/mobile/ios/Client/Configuration/FirefoxBeta.xcconfig @@ -0,0 +1,20 @@ +// 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/. + +MOZ_BUNDLE_DISPLAY_NAME = Firefox Beta + +// Bundle Identifier +MOZ_BUNDLE_ID = org.mozilla.ios.FirefoxBeta + +// Flag to indicate if we want to include the debug settings bundle or not +INCLUDE_SETTINGS_BUNDLE = NO + +// Adjust SDK Variables +ADJUST_ENVIRONMENT = +ADJUST_APP_TOKEN = + +// Leanplum SDK Variables +LEANPLUM_ENVIRONMENT = +LEANPLUM_APP_ID = +LEANPLUM_KEY = diff --git a/mobile/ios/Client/DispatchQueueExtensions.swift b/mobile/ios/Client/DispatchQueueExtensions.swift new file mode 100644 index 0000000000..9f1b73a6a1 --- /dev/null +++ b/mobile/ios/Client/DispatchQueueExtensions.swift @@ -0,0 +1,18 @@ +/* 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/. */ + +import Foundation + + +// Only push the task async if we are not already on the main thread. +// Unless you want another event to fire before your work happens. This is better than using DispatchQueue.main.async to ensure main thread +public func ensureMainThread(execute work: @escaping @convention(block) () -> Swift.Void) { + if Thread.isMainThread { + work() + } else { + DispatchQueue.main.async { + work() + } + } +} diff --git a/mobile/ios/Client/Entitlements/FennecApplication.entitlements b/mobile/ios/Client/Entitlements/FennecApplication.entitlements new file mode 100644 index 0000000000..6d3ba2781e --- /dev/null +++ b/mobile/ios/Client/Entitlements/FennecApplication.entitlements @@ -0,0 +1,25 @@ + + + + + aps-environment + development + com.apple.developer.associated-domains + + applinks:accounts.firefox.com + applinks:accounts.stage.mozaws.net + applinks:latest.dev.lcip.org + applinks:nightly.dev.lcip.org + applinks:rzte.adj.st + applinks:nn8g.adj.st + + com.apple.security.application-groups + + group.org.mozilla.ios.Fennec + + keychain-access-groups + + $(AppIdentifierPrefix)org.mozilla.ios.Fennec + + + diff --git a/mobile/ios/Client/Entitlements/FennecEnterpriseApplication.entitlements b/mobile/ios/Client/Entitlements/FennecEnterpriseApplication.entitlements new file mode 100644 index 0000000000..1d9670e369 --- /dev/null +++ b/mobile/ios/Client/Entitlements/FennecEnterpriseApplication.entitlements @@ -0,0 +1,16 @@ + + + + + aps-environment + production + com.apple.security.application-groups + + group.org.mozilla.ios.Fennec.enterprise + + keychain-access-groups + + $(AppIdentifierPrefix)org.mozilla.ios.Fennec.enterprise + + + diff --git a/mobile/ios/Client/Entitlements/FirefoxApplication.entitlements b/mobile/ios/Client/Entitlements/FirefoxApplication.entitlements new file mode 100644 index 0000000000..1f7a3e1ca6 --- /dev/null +++ b/mobile/ios/Client/Entitlements/FirefoxApplication.entitlements @@ -0,0 +1,25 @@ + + + + + com.apple.developer.associated-domains + + applinks:accounts.firefox.com + applinks:accounts.stage.mozaws.net + applinks:latest.dev.lcip.org + applinks:nightly.dev.lcip.org + applinks:rzte.adj.st + applinks:nn8g.adj.st + + aps-environment + production + com.apple.security.application-groups + + group.org.mozilla.ios.Firefox + + keychain-access-groups + + $(AppIdentifierPrefix)org.mozilla.ios.Firefox + + + diff --git a/mobile/ios/Client/Entitlements/FirefoxBetaApplication.entitlements b/mobile/ios/Client/Entitlements/FirefoxBetaApplication.entitlements new file mode 100644 index 0000000000..a9055bfd0d --- /dev/null +++ b/mobile/ios/Client/Entitlements/FirefoxBetaApplication.entitlements @@ -0,0 +1,25 @@ + + + + + com.apple.developer.associated-domains + + applinks:accounts.firefox.com + applinks:accounts.stage.mozaws.net + applinks:latest.dev.lcip.org + applinks:nightly.dev.lcip.org + applinks:rzte.adj.st + applinks:nn8g.adj.st + + aps-environment + production + com.apple.security.application-groups + + group.org.mozilla.ios.FirefoxBeta + + keychain-access-groups + + $(AppIdentifierPrefix)org.mozilla.ios.FirefoxBeta + + + diff --git a/mobile/ios/Client/Extensions/GeometryExtensions.swift b/mobile/ios/Client/Extensions/GeometryExtensions.swift new file mode 100644 index 0000000000..85ba16d50b --- /dev/null +++ b/mobile/ios/Client/Extensions/GeometryExtensions.swift @@ -0,0 +1,42 @@ +/* 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/. */ + +import UIKit + +extension CGRect { + var center: CGPoint { + get { + return CGPoint(x: size.width / 2, y: size.height / 2) + } + set { + self.origin = CGPoint(x: newValue.x - size.width / 2, y: newValue.y - size.height / 2) + } + } +} + +extension UIEdgeInsets { + init(equalInset inset: CGFloat) { + top = inset + left = inset + right = inset + bottom = inset + } +} + +/** +Generates the affine transform for transforming the first CGRect into the second one + +- parameter frame: CGRect to transform from +- parameter toFrame: CGRect to transform to + +- returns: CGAffineTransform that transforms the first CGRect into the second +*/ +func CGAffineTransformMakeRectToRect(_ frame: CGRect, toFrame: CGRect) -> CGAffineTransform { + let scale = toFrame.size.width / frame.size.width + let tx = toFrame.origin.x + toFrame.width / 2 - (frame.origin.x + frame.width / 2) + let ty = toFrame.origin.y - frame.origin.y * scale * 2 + let translation = CGAffineTransform(translationX: tx, y: ty) + let scaledAndTranslated = translation.scaledBy(x: scale, y: scale) + return scaledAndTranslated +} diff --git a/mobile/ios/Client/Extensions/NSAttributedStringExtensions.swift b/mobile/ios/Client/Extensions/NSAttributedStringExtensions.swift new file mode 100644 index 0000000000..ae9eccb0b7 --- /dev/null +++ b/mobile/ios/Client/Extensions/NSAttributedStringExtensions.swift @@ -0,0 +1,13 @@ +/* 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/. */ + +import Foundation + +// MARK: - Common UITableView text styling +extension NSAttributedString { + static func tableRowTitle(_ string: String, enabled: Bool) -> NSAttributedString { + let color = enabled ? [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor] : [NSForegroundColorAttributeName: UIConstants.TableViewDisabledRowTextColor] + return NSAttributedString(string: string, attributes: color) + } +} diff --git a/mobile/ios/Client/Extensions/NSURLExtensionsMailTo.swift b/mobile/ios/Client/Extensions/NSURLExtensionsMailTo.swift new file mode 100644 index 0000000000..2e36998fa9 --- /dev/null +++ b/mobile/ios/Client/Extensions/NSURLExtensionsMailTo.swift @@ -0,0 +1,55 @@ +/* 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/. */ + +import Foundation + +/** + * Data structure containing metadata associated with a mailto: link. For additional details, + * see RFC 2368 https://tools.ietf.org/html/rfc2368 + */ +public struct MailToMetadata { + public let to: String + public let headers: [String: String] +} + +public extension URL { + + /** + Extracts the metadata associated with a mailto: URL according to RFC 2368 + https://tools.ietf.org/html/rfc2368 + */ + func mailToMetadata() -> MailToMetadata? { + guard scheme == "mailto" else { + return nil + } + let urlString = absoluteString + + // Extract 'to' value + let toStart = urlString.characters.index(urlString.startIndex, offsetBy: "mailto:".characters.count) + let toEnd = urlString.characters.index(of: "?") ?? urlString.endIndex + + let to = urlString.substring(with: toStart.. UIAlertController { + let alert = UIAlertController( + title: NSLocalizedString("Well, this is embarrassing.", comment: "Restore Tabs Prompt Title"), + message: NSLocalizedString("Looks like Firefox crashed previously. Would you like to restore your tabs?", comment: "Restore Tabs Prompt Description"), + preferredStyle: UIAlertControllerStyle.alert + ) + + let noOption = UIAlertAction( + title: NSLocalizedString("No", comment: "Restore Tabs Negative Action"), + style: UIAlertActionStyle.cancel, + handler: noCallback + ) + + let okayOption = UIAlertAction( + title: NSLocalizedString("Okay", comment: "Restore Tabs Affirmative Action"), + style: UIAlertActionStyle.default, + handler: okayCallback + ) + + alert.addAction(okayOption) + alert.addAction(noOption) + return alert + } + + class func clearPrivateDataAlert(okayCallback: @escaping (UIAlertAction) -> Void) -> UIAlertController { + let alert = UIAlertController( + title: "", + message: NSLocalizedString("This action will clear all of your private data. It cannot be undone.", tableName: "ClearPrivateDataConfirm", comment: "Description of the confirmation dialog shown when a user tries to clear their private data."), + preferredStyle: UIAlertControllerStyle.alert + ) + + let noOption = UIAlertAction( + title: NSLocalizedString("Cancel", tableName: "ClearPrivateDataConfirm", comment: "The cancel button when confirming clear private data."), + style: UIAlertActionStyle.cancel, + handler: nil + ) + + let okayOption = UIAlertAction( + title: NSLocalizedString("OK", tableName: "ClearPrivateDataConfirm", comment: "The button that clears private data."), + style: UIAlertActionStyle.destructive, + handler: okayCallback + ) + + alert.addAction(okayOption) + alert.addAction(noOption) + return alert + } + + /** + Builds the Alert view that asks if the users wants to also delete history stored on their other devices. + + - parameter okayCallback: Okay option handler. + + - returns: UIAlertController for asking the user to restore tabs after a crash + */ + + class func clearSyncedHistoryAlert(okayCallback: @escaping (UIAlertAction) -> Void) -> UIAlertController { + let alert = UIAlertController( + title: "", + message: NSLocalizedString("This action will clear all of your private data, including history from your synced devices.", tableName: "ClearHistoryConfirm", comment: "Description of the confirmation dialog shown when a user tries to clear history that's synced to another device."), + preferredStyle: UIAlertControllerStyle.alert + ) + + let noOption = UIAlertAction( + title: NSLocalizedString("Cancel", tableName: "ClearHistoryConfirm", comment: "The cancel button when confirming clear history."), + style: UIAlertActionStyle.cancel, + handler: nil + ) + + let okayOption = UIAlertAction( + title: NSLocalizedString("OK", tableName: "ClearHistoryConfirm", comment: "The confirmation button that clears history even when Sync is connected."), + style: UIAlertActionStyle.destructive, + handler: okayCallback + ) + + alert.addAction(okayOption) + alert.addAction(noOption) + return alert + } + + /** + Creates an alert view to warn the user that their logins will either be completely deleted in the + case of local-only logins or deleted across synced devices in synced account logins. + + - parameter deleteCallback: Block to run when delete is tapped. + - parameter hasSyncedLogins: Boolean indicating the user has logins that have been synced. + + - returns: UIAlertController instance + */ + class func deleteLoginAlertWithDeleteCallback( + _ deleteCallback: @escaping UIAlertActionCallback, + hasSyncedLogins: Bool) -> UIAlertController { + + let areYouSureTitle = NSLocalizedString("Are you sure?", + tableName: "LoginManager", + comment: "Prompt title when deleting logins") + let deleteLocalMessage = NSLocalizedString("Logins will be permanently removed.", + tableName: "LoginManager", + comment: "Prompt message warning the user that deleting non-synced logins will permanently remove them") + let deleteSyncedDevicesMessage = NSLocalizedString("Logins will be removed from all connected devices.", + tableName: "LoginManager", + comment: "Prompt message warning the user that deleted logins will remove logins from all connected devices") + let cancelActionTitle = NSLocalizedString("Cancel", + tableName: "LoginManager", + comment: "Prompt option for cancelling out of deletion") + let deleteActionTitle = NSLocalizedString("Delete", + tableName: "LoginManager", + comment: "Label for the button used to delete the current login.") + + let deleteAlert: UIAlertController + if hasSyncedLogins { + deleteAlert = UIAlertController(title: areYouSureTitle, message: deleteSyncedDevicesMessage, preferredStyle: .alert) + } else { + deleteAlert = UIAlertController(title: areYouSureTitle, message: deleteLocalMessage, preferredStyle: .alert) + } + + let cancelAction = UIAlertAction(title: cancelActionTitle, style: .cancel, handler: nil) + let deleteAction = UIAlertAction(title: deleteActionTitle, style: .destructive, handler: deleteCallback) + + deleteAlert.addAction(cancelAction) + deleteAlert.addAction(deleteAction) + + return deleteAlert + } +} diff --git a/mobile/ios/Client/Extensions/UIImageViewExtensions.swift b/mobile/ios/Client/Extensions/UIImageViewExtensions.swift new file mode 100644 index 0000000000..68c8d5759d --- /dev/null +++ b/mobile/ios/Client/Extensions/UIImageViewExtensions.swift @@ -0,0 +1,87 @@ +/* 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/. */ + +import UIKit +import Storage +import SDWebImage +import Shared + +public extension UIImageView { + + public func setIcon(_ icon: Favicon?, forURL url: URL?, completed completionBlock: ((UIColor, URL?) -> Void)? = nil ) { + if let url = url, let defaultIcon = FaviconFetcher.getDefaultIconForURL(url: url) { + self.image = UIImage(contentsOfFile: defaultIcon.url) + self.backgroundColor = defaultIcon.color + completionBlock?(defaultIcon.color, url) + } else { + let imageURL = URL(string: icon?.url ?? "") + let defaults = defaultFavicon(url) + self.sd_setImage(with: imageURL, placeholderImage: defaults.image, options: []) {(img, err, _, _) in + guard let image = img, let dUrl = url, err == nil else { + self.backgroundColor = defaults.color + completionBlock?(defaults.color, url) + return + } + self.color(forImage: image, andURL: dUrl, completed: completionBlock) + } + } + } + + /* + * Fetch a background color for a specfic favicon UIImage. It uses the URL to store the UIColor in memory for subsequent requests. + */ + private func color(forImage image: UIImage, andURL url: URL, completed completionBlock: ((UIColor, URL?) -> Void)? = nil) { + guard let domain = url.baseDomain else { + self.backgroundColor = .gray + completionBlock?(UIColor.gray, url) + return + } + + if let color = FaviconFetcher.colors[domain] { + self.backgroundColor = color + completionBlock?(color, url) + } else { + image.getColors(scaleDownSize: CGSize(width: 25, height: 25)) {colors in + let isSame = [colors.primary, colors.secondary, colors.detail].every { $0 == colors.primary } + if isSame { + completionBlock?(UIColor.white, url) + FaviconFetcher.colors[domain] = UIColor.white + } else { + completionBlock?(colors.background, url) + FaviconFetcher.colors[domain] = colors.background + } + } + } + } + + public func setFavicon(forSite site: Site, onCompletion completionBlock: ((UIColor, URL?) -> Void)? = nil ) { + self.setIcon(site.icon, forURL: site.tileURL, completed: completionBlock) + } + + private func defaultFavicon(_ url: URL?) -> (image: UIImage, color: UIColor) { + if let url = url { + return (FaviconFetcher.getDefaultFavicon(url), FaviconFetcher.getDefaultColor(url)) + } else { + return (FaviconFetcher.defaultFavicon, .white) + } + } +} + +open class ImageOperation: NSObject, SDWebImageOperation { + open var cacheOperation: Operation? + + var cancelled: Bool { + if let cacheOperation = cacheOperation { + return cacheOperation.isCancelled + } + return false + } + + @objc open func cancel() { + if let cacheOperation = cacheOperation { + cacheOperation.cancel() + } + } +} + diff --git a/mobile/ios/Client/Extensions/UIPasteboardExtensions.swift b/mobile/ios/Client/Extensions/UIPasteboardExtensions.swift new file mode 100644 index 0000000000..0cc815124c --- /dev/null +++ b/mobile/ios/Client/Extensions/UIPasteboardExtensions.swift @@ -0,0 +1,63 @@ +/* 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/. */ + +import Deferred +import Foundation +import MobileCoreServices +import Shared +import UIKit + +extension UIPasteboard { + func addImageWithData(_ data: Data, forURL url: URL) { + let isGIF = UIImage.dataIsGIF(data) + + // Setting pasteboard.items allows us to set multiple representations for the same item. + items = [[ + kUTTypeURL as String: url, + imageTypeKey(isGIF): data + ]] + } + + fileprivate func imageTypeKey(_ isGIF: Bool) -> String { + return (isGIF ? kUTTypeGIF : kUTTypePNG) as String + } + + private var syncURL: URL? { + if let string = UIPasteboard.general.string, + let url = URL(string: string), url.isWebPage() { + return url + } else { + return nil + } + } + + /// Preferred method to get strings out of the clipboard. + /// When iCloud pasteboards are enabled, the usually fast, synchronous calls + /// become slow and synchronous causing very slow start up times. + func asyncString() -> Deferred> { + return fetchAsync() { + return UIPasteboard.general.string + } + } + + /// Preferred method to get URLs out of the clipboard. + /// We use Deferred> to fit in to the rest of the Deferred tools + /// we already use; but use optionals instead of errorTypes, because not having a URL + /// on the clipboard isn't an error. + func asyncURL() -> Deferred> { + return fetchAsync() { + return self.syncURL + } + } + + // Converts the potentially long running synchronous operation into an asynchronous one. + private func fetchAsync(getter: @escaping () -> T) -> Deferred> { + let deferred = Deferred>() + DispatchQueue.global().async { + let value = getter() + deferred.fill(Maybe(success: value)) + } + return deferred + } +} diff --git a/mobile/ios/Client/Extensions/UIViewExtensions.swift b/mobile/ios/Client/Extensions/UIViewExtensions.swift new file mode 100644 index 0000000000..a7b87ed526 --- /dev/null +++ b/mobile/ios/Client/Extensions/UIViewExtensions.swift @@ -0,0 +1,94 @@ +/* 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/. */ + +import Foundation + +extension UIView { + /** + * Takes a screenshot of the view with the given size. + */ + func screenshot(_ size: CGSize, offset: CGPoint? = nil, quality: CGFloat = 1) -> UIImage? { + assert(0...1 ~= quality) + + let offset = offset ?? CGPoint(x: 0, y: 0) + + UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale * quality) + drawHierarchy(in: CGRect(origin: offset, size: frame.size), afterScreenUpdates: false) + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return image + } + + /** + * Takes a screenshot of the view with the given aspect ratio. + * An aspect ratio of 0 means capture the entire view. + */ + func screenshot(_ aspectRatio: CGFloat = 0, offset: CGPoint? = nil, quality: CGFloat = 1) -> UIImage? { + assert(aspectRatio >= 0) + + var size: CGSize + if aspectRatio > 0 { + size = CGSize() + let viewAspectRatio = frame.width / frame.height + if viewAspectRatio > aspectRatio { + size.height = frame.height + size.width = size.height * aspectRatio + } else { + size.width = frame.width + size.height = size.width / aspectRatio + } + } else { + size = frame.size + } + + return screenshot(size, offset: offset, quality: quality) + } + + /* + * Performs a deep copy of the view. Does not copy constraints. + */ + func clone() -> UIView { + let data = NSKeyedArchiver.archivedData(withRootObject: self) + return NSKeyedUnarchiver.unarchiveObject(with: data) as! UIView + } + + /** + * rounds the requested corners of a view with the provided radius + */ + func addRoundedCorners(_ cornersToRound: UIRectCorner, cornerRadius: CGSize, color: UIColor) { + let rect = bounds + let maskPath = UIBezierPath(roundedRect: rect, byRoundingCorners: cornersToRound, cornerRadii: cornerRadius) + + // Create the shape layer and set its path + let maskLayer = CAShapeLayer() + maskLayer.frame = rect + maskLayer.path = maskPath.cgPath + + let roundedLayer = CALayer() + roundedLayer.backgroundColor = color.cgColor + roundedLayer.frame = rect + roundedLayer.mask = maskLayer + + layer.insertSublayer(roundedLayer, at: 0) + backgroundColor = UIColor.clear + } + + /** + This allows us to find the view in a current view hierarchy that is currently the first responder + */ + static func findSubViewWithFirstResponder(_ view: UIView) -> UIView? { + let subviews = view.subviews + if subviews.count == 0 { + return nil + } + for subview: UIView in subviews { + if subview.isFirstResponder { + return subview + } + return findSubViewWithFirstResponder(subview) + } + return nil + } +} diff --git a/mobile/ios/Client/Frontend/Accessors/HomePageAccessors.swift b/mobile/ios/Client/Frontend/Accessors/HomePageAccessors.swift new file mode 100644 index 0000000000..23d8227701 --- /dev/null +++ b/mobile/ios/Client/Frontend/Accessors/HomePageAccessors.swift @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +import Shared +import XCGLogger + +/// Accessors for homepage details from the app state. +/// These are pure functions, so it's quite ok to have them +/// as static. +class HomePageAccessors { + + static func getHomePage(_ prefs: Prefs) -> URL? { + let string = prefs.stringForKey(HomePageConstants.HomePageURLPrefKey) ?? getDefaultHomePageString(prefs) + guard let urlString = string else { + return nil + } + return NSURL(string: urlString) as URL? + } + + static func getDefaultHomePageString(_ prefs: Prefs) -> String? { + return prefs.stringForKey(HomePageConstants.DefaultHomePageURLPrefKey) + } +} diff --git a/mobile/ios/Client/Frontend/Accessors/NewTabAccessors.swift b/mobile/ios/Client/Frontend/Accessors/NewTabAccessors.swift new file mode 100644 index 0000000000..42912713f0 --- /dev/null +++ b/mobile/ios/Client/Frontend/Accessors/NewTabAccessors.swift @@ -0,0 +1,77 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger + +/// Accessors to find what a new tab should do when created without a URL. +struct NewTabAccessors { + static let PrefKey = PrefsKeys.KeyNewTab + static let Default = NewTabPage.topSites + + static func getNewTabPage(_ prefs: Prefs) -> NewTabPage { + guard let raw = prefs.stringForKey(PrefKey) else { + return Default + } + let option = NewTabPage(rawValue: raw) ?? Default + // Check if the user has chosen to open a homepage, but no homepage is set, + // then use the default. + if option == .homePage && HomePageAccessors.getHomePage(prefs) == nil { + return Default + } + return option + } +} + +/// Enum to encode what should happen when the user opens a new tab without a URL. +enum NewTabPage: String { + case blankPage = "Blank" + case homePage = "HomePage" + case topSites = "TopSites" + case bookmarks = "Bookmarks" + case history = "History" + case readingList = "ReadingList" + + var settingTitle: String { + switch self { + case .blankPage: + return Strings.SettingsNewTabBlankPage + case .homePage: + return Strings.SettingsNewTabHomePage + case .topSites: + return Strings.SettingsNewTabTopSites + case .bookmarks: + return Strings.SettingsNewTabBookmarks + case .history: + return Strings.SettingsNewTabHistory + case .readingList: + return Strings.SettingsNewTabReadingList + } + } + + var homePanelType: HomePanelType? { + switch self { + case .topSites: + return HomePanelType.topSites + case .bookmarks: + return HomePanelType.bookmarks + case .history: + return HomePanelType.history + case .readingList: + return HomePanelType.readingList + default: + return nil + } + } + + var url: URL? { + guard let homePanel = self.homePanelType else { + return nil + } + return homePanel.localhostURL as URL + } + + static let allValues = [blankPage, topSites, bookmarks, history, readingList, homePage] +} diff --git a/mobile/ios/Client/Frontend/Animators/Animatable.swift b/mobile/ios/Client/Frontend/Animators/Animatable.swift new file mode 100644 index 0000000000..642c35ac54 --- /dev/null +++ b/mobile/ios/Client/Frontend/Animators/Animatable.swift @@ -0,0 +1,9 @@ +/* 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/. */ + +import UIKit + +protocol Animatable { + func animateFromView(_ view: UIView, offset: CGFloat?, completion: ((Bool) -> Void)?) +} diff --git a/mobile/ios/Client/Frontend/Animators/JumpAndSpinAnimator.swift b/mobile/ios/Client/Frontend/Animators/JumpAndSpinAnimator.swift new file mode 100644 index 0000000000..3026dcd010 --- /dev/null +++ b/mobile/ios/Client/Frontend/Animators/JumpAndSpinAnimator.swift @@ -0,0 +1,35 @@ +/* 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/. */ + +import UIKit + +class JumpAndSpinAnimator: Animatable { + fileprivate let AnimationDuration: Double = 0.5 + fileprivate let AnimationOffset: CGFloat = -80 + + static func animateFromView(_ view: UIView, offset: CGFloat, completion: ((Bool) -> Void)?) { + let animator = JumpAndSpinAnimator() + animator.animateFromView(view, offset: offset, completion: completion) + } + + func animateFromView(_ viewToAnimate: UIView, offset: CGFloat? = nil, completion: ((Bool) -> Void)?) { + let offset = offset ?? AnimationOffset + let offToolbar = CGAffineTransform(translationX: 0, y: offset) + + UIView.animate(withDuration: AnimationDuration, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 2.0, options: [], animations: { () -> Void in + viewToAnimate.transform = offToolbar + let rotation = CABasicAnimation(keyPath: "transform.rotation") + rotation.toValue = CGFloat(2.0 * Double.pi) + rotation.isCumulative = true + rotation.duration = self.AnimationDuration + 0.075 + rotation.repeatCount = 1.0 + rotation.timingFunction = CAMediaTimingFunction(controlPoints: 0.32, 0.70, 0.18, 1.00) + viewToAnimate.layer.add(rotation, forKey: "rotateStar") + }, completion: { finished in + UIView.animate(withDuration: self.AnimationDuration, delay: 0.15, usingSpringWithDamping: 0.7, initialSpringVelocity: 0, options: [], animations: { () -> Void in + viewToAnimate.transform = CGAffineTransform.identity + }, completion: completion) + }) + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/AppAuthenticator.swift b/mobile/ios/Client/Frontend/AuthenticationManager/AppAuthenticator.swift new file mode 100644 index 0000000000..ac4ea06684 --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/AppAuthenticator.swift @@ -0,0 +1,55 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftKeychainWrapper +import LocalAuthentication + +class AppAuthenticator { + static func presentAuthenticationUsingInfo(_ authenticationInfo: AuthenticationKeychainInfo, touchIDReason: String, success: (() -> Void)?, cancel: (() -> Void)?, fallback: (() -> Void)?) { + if authenticationInfo.useTouchID { + let localAuthContext = LAContext() + localAuthContext.localizedFallbackTitle = AuthenticationStrings.enterPasscode + localAuthContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: touchIDReason) { didSucceed, error in + if didSucceed { + // Update our authentication info's last validation timestamp so we don't ask again based + // on the set required interval + authenticationInfo.recordValidation() + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authenticationInfo) + DispatchQueue.main.async { + success?() + } + return + } + + guard let authError = error, + let code = LAError.Code(rawValue: authError._code) else { + return + } + + DispatchQueue.main.async { + switch code { + case .userFallback, .touchIDNotEnrolled, .touchIDNotAvailable, .touchIDLockout: + fallback?() + case .userCancel: + cancel?() + default: + cancel?() + } + } + } + } else { + fallback?() + } + } + + static func presentPasscodeAuthentication(_ presentingNavController: UINavigationController?, delegate: PasscodeEntryDelegate?) { + let passcodeVC = PasscodeEntryViewController() + passcodeVC.delegate = delegate + let navController = UINavigationController(rootViewController: passcodeVC) + navController.modalPresentationStyle = .formSheet + presentingNavController?.present(navController, animated: true, completion: nil) + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/AuthenticationManagerConstants.swift b/mobile/ios/Client/Frontend/AuthenticationManager/AuthenticationManagerConstants.swift new file mode 100644 index 0000000000..1fd79ece2a --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/AuthenticationManagerConstants.swift @@ -0,0 +1,107 @@ +/* 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/. */ + +import Foundation +import Shared + +// Strings for the passcode intervals. +extension PasscodeInterval { + var settingTitle: String { + switch self { + case .immediately: return AuthenticationStrings.immediately + case .oneMinute: return AuthenticationStrings.oneMinute + case .fiveMinutes: return AuthenticationStrings.fiveMinutes + case .tenMinutes: return AuthenticationStrings.tenMinutes + case .fifteenMinutes: return AuthenticationStrings.fifteenMinutes + case .oneHour: return AuthenticationStrings.oneHour + } + } +} + +// Strings used in multiple areas within the Authentication Manager +struct AuthenticationStrings { + static let passcode = + NSLocalizedString("Passcode For Logins", tableName: "AuthenticationManager", comment: "Label for the Passcode item in Settings") + + static let touchIDPasscodeSetting = + NSLocalizedString("Touch ID & Passcode", tableName: "AuthenticationManager", comment: "Label for the Touch ID/Passcode item in Settings") + + static let faceIDPasscodeSetting = + NSLocalizedString("Face ID & Passcode", tableName: "AuthenticationManager", comment: "Label for the Face ID/Passcode item in Settings") + + static let requirePasscode = + NSLocalizedString("Require Passcode", tableName: "AuthenticationManager", comment: "Text displayed in the 'Interval' section, followed by the current interval setting, e.g. 'Immediately'") + + static let enterAPasscode = + NSLocalizedString("Enter a passcode", tableName: "AuthenticationManager", comment: "Text displayed above the input field when entering a new passcode") + + static let enterPasscodeTitle = + NSLocalizedString("Enter Passcode", tableName: "AuthenticationManager", comment: "Title of the dialog used to request the passcode") + + static let enterPasscode = + NSLocalizedString("Enter passcode", tableName: "AuthenticationManager", comment: "Text displayed above the input field when changing the existing passcode") + + static let reenterPasscode = + NSLocalizedString("Re-enter passcode", tableName: "AuthenticationManager", comment: "Text displayed above the input field when confirming a passcode") + + static let setPasscode = + NSLocalizedString("Set Passcode", tableName: "AuthenticationManager", comment: "Title of the dialog used to set a passcode") + + static let turnOffPasscode = + NSLocalizedString("Turn Passcode Off", tableName: "AuthenticationManager", comment: "Label used as a setting item to turn off passcode") + + static let turnOnPasscode = + NSLocalizedString("Turn Passcode On", tableName: "AuthenticationManager", comment: "Label used as a setting item to turn on passcode") + + static let changePasscode = + NSLocalizedString("Change Passcode", tableName: "AuthenticationManager", comment: "Label used as a setting item and title of the following screen to change the current passcode") + + static let enterNewPasscode = + NSLocalizedString("Enter a new passcode", tableName: "AuthenticationManager", comment: "Text displayed above the input field when changing the existing passcode") + + static let immediately = + NSLocalizedString("Immediately", tableName: "AuthenticationManager", comment: "'Immediately' interval item for selecting when to require passcode") + + static let oneMinute = + NSLocalizedString("After 1 minute", tableName: "AuthenticationManager", comment: "'After 1 minute' interval item for selecting when to require passcode") + + static let fiveMinutes = + NSLocalizedString("After 5 minutes", tableName: "AuthenticationManager", comment: "'After 5 minutes' interval item for selecting when to require passcode") + + static let tenMinutes = + NSLocalizedString("After 10 minutes", tableName: "AuthenticationManager", comment: "'After 10 minutes' interval item for selecting when to require passcode") + + static let fifteenMinutes = + NSLocalizedString("After 15 minutes", tableName: "AuthenticationManager", comment: "'After 15 minutes' interval item for selecting when to require passcode") + + static let oneHour = + NSLocalizedString("After 1 hour", tableName: "AuthenticationManager", comment: "'After 1 hour' interval item for selecting when to require passcode") + + static let loginsTouchReason = + NSLocalizedString("Use your fingerprint to access Logins now.", tableName: "AuthenticationManager", comment: "Touch ID prompt subtitle when accessing logins") + + static let requirePasscodeTouchReason = + NSLocalizedString("touchid.require.passcode.reason.label", + tableName: "AuthenticationManager", + value: "Use your fingerprint to access configuring your required passcode interval.", + comment: "Touch ID prompt subtitle when accessing the require passcode setting") + + static let disableTouchReason = + NSLocalizedString("touchid.disable.reason.label", + tableName: "AuthenticationManager", + value: "Use your fingerprint to disable Touch ID.", + comment: "Touch ID prompt subtitle when disabling Touch ID") + + static let wrongPasscodeError = + NSLocalizedString("Incorrect passcode. Try again.", tableName: "AuthenticationManager", comment: "Error message displayed when user enters incorrect passcode when trying to enter a protected section of the app") + + static let incorrectAttemptsRemaining = + NSLocalizedString("Incorrect passcode. Try again (Attempts remaining: %d).", tableName: "AuthenticationManager", comment: "Error message displayed when user enters incorrect passcode when trying to enter a protected section of the app with attempts remaining") + + static let maximumAttemptsReached = + NSLocalizedString("Maximum attempts reached. Please try again in an hour.", tableName: "AuthenticationManager", comment: "Error message displayed when user enters incorrect passcode and has reached the maximum number of attempts.") + + static let maximumAttemptsReachedNoTime = + NSLocalizedString("Maximum attempts reached. Please try again later.", tableName: "AuthenticationManager", comment: "Error message displayed when user enters incorrect passcode and has reached the maximum number of attempts.") +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/AuthenticationSettingsViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/AuthenticationSettingsViewController.swift new file mode 100644 index 0000000000..7c49cee4d0 --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/AuthenticationSettingsViewController.swift @@ -0,0 +1,351 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared +import SwiftKeychainWrapper +import LocalAuthentication + +private let logger = Logger.browserLogger + +private func presentNavAsFormSheet(_ presented: UINavigationController, presenter: UINavigationController?, settings: AuthenticationSettingsViewController?) { + presented.modalPresentationStyle = .formSheet + presenter?.present(presented, animated: true, completion: { + if let selectedRow = settings?.tableView.indexPathForSelectedRow { + settings?.tableView.deselectRow(at: selectedRow, animated: false) + } + }) +} + +class TurnPasscodeOnSetting: Setting { + weak var settings: AuthenticationSettingsViewController? + + init(settings: SettingsTableViewController, delegate: SettingsDelegate? = nil) { + self.settings = settings as? AuthenticationSettingsViewController + super.init(title: NSAttributedString.tableRowTitle(AuthenticationStrings.turnOnPasscode, enabled: true), + delegate: delegate) + } + + override func onClick(_ navigationController: UINavigationController?) { + presentNavAsFormSheet(UINavigationController(rootViewController: SetupPasscodeViewController()), + presenter: navigationController, + settings: settings) + } +} + +class TurnPasscodeOffSetting: Setting { + weak var settings: AuthenticationSettingsViewController? + + init(settings: SettingsTableViewController, delegate: SettingsDelegate? = nil) { + self.settings = settings as? AuthenticationSettingsViewController + super.init(title: NSAttributedString.tableRowTitle(AuthenticationStrings.turnOffPasscode, enabled: true), + delegate: delegate) + } + + override func onClick(_ navigationController: UINavigationController?) { + presentNavAsFormSheet(UINavigationController(rootViewController: RemovePasscodeViewController()), + presenter: navigationController, + settings: settings) + } +} + +class ChangePasscodeSetting: Setting { + weak var settings: AuthenticationSettingsViewController? + + init(settings: SettingsTableViewController, delegate: SettingsDelegate? = nil, enabled: Bool) { + self.settings = settings as? AuthenticationSettingsViewController + + let attributedTitle: NSAttributedString = NSAttributedString.tableRowTitle(AuthenticationStrings.changePasscode, enabled: enabled) + + super.init(title: attributedTitle, + delegate: delegate, + enabled: enabled) + } + + override func onClick(_ navigationController: UINavigationController?) { + presentNavAsFormSheet(UINavigationController(rootViewController: ChangePasscodeViewController()), + presenter: navigationController, + settings: settings) + } +} + +class RequirePasscodeSetting: Setting { + weak var settings: AuthenticationSettingsViewController? + + fileprivate weak var navigationController: UINavigationController? + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var style: UITableViewCellStyle { return .value1 } + + override var status: NSAttributedString { + // Only show the interval if we are enabled and have an interval set. + let authenticationInterval = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() + if let interval = authenticationInterval?.requiredPasscodeInterval, enabled { + return NSAttributedString.tableRowTitle(interval.settingTitle, enabled: false) + } + return NSAttributedString(string: "") + } + + init(settings: SettingsTableViewController, delegate: SettingsDelegate? = nil, enabled: Bool? = nil) { + self.navigationController = settings.navigationController + self.settings = settings as? AuthenticationSettingsViewController + + let title = AuthenticationStrings.requirePasscode + let attributedTitle = NSAttributedString.tableRowTitle(title, enabled: enabled ?? true) + super.init(title: attributedTitle, + delegate: delegate, + enabled: enabled) + } + + func deselectRow () { + if let selectedRow = self.settings?.tableView.indexPathForSelectedRow { + self.settings?.tableView.deselectRow(at: selectedRow, animated: true) + } + } + + override func onClick(_: UINavigationController?) { + guard let authInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() else { + navigateToRequireInterval() + return + } + + if authInfo.requiresValidation() { + AppAuthenticator.presentAuthenticationUsingInfo(authInfo, + touchIDReason: AuthenticationStrings.requirePasscodeTouchReason, + success: { + self.navigateToRequireInterval() + }, + cancel: nil, + fallback: { + AppAuthenticator.presentPasscodeAuthentication(self.navigationController, delegate: self) + self.deselectRow() + }) + } else { + self.navigateToRequireInterval() + } + } + + fileprivate func navigateToRequireInterval() { + navigationController?.pushViewController(RequirePasscodeIntervalViewController(), animated: true) + } +} + +extension RequirePasscodeSetting: PasscodeEntryDelegate { + @objc func passcodeValidationDidSucceed() { + navigationController?.dismiss(animated: true) { + self.navigateToRequireInterval() + } + } +} + +class TouchIDSetting: Setting { + fileprivate let authInfo: AuthenticationKeychainInfo? + + fileprivate weak var navigationController: UINavigationController? + fileprivate weak var switchControl: UISwitch? + + fileprivate var touchIDSuccess: (() -> Void)? + fileprivate var touchIDFallback: (() -> Void)? + + init( + title: NSAttributedString?, + navigationController: UINavigationController? = nil, + delegate: SettingsDelegate? = nil, + enabled: Bool? = nil, + touchIDSuccess: (() -> Void)? = nil, + touchIDFallback: (() -> Void)? = nil) { + self.touchIDSuccess = touchIDSuccess + self.touchIDFallback = touchIDFallback + self.navigationController = navigationController + self.authInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() + super.init(title: title, delegate: delegate, enabled: enabled) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + cell.selectionStyle = .none + + // In order for us to recognize a tap gesture without toggling the switch, + // the switch is wrapped in a UIView which has a tap gesture recognizer. This way + // we can disable interaction of the switch and still handle tap events. + let control = UISwitch() + control.onTintColor = UIConstants.ControlTintColor + control.isOn = authInfo?.useTouchID ?? false + control.isUserInteractionEnabled = false + switchControl = control + + let accessoryContainer = UIView(frame: control.frame) + accessoryContainer.addSubview(control) + + let gesture = UITapGestureRecognizer(target: self, action: #selector(TouchIDSetting.switchTapped)) + accessoryContainer.addGestureRecognizer(gesture) + + cell.accessoryView = accessoryContainer + } + + @objc fileprivate func switchTapped() { + guard let authInfo = authInfo else { + logger.error("Authentication info should always be present when modifying Touch ID preference.") + return + } + + if authInfo.useTouchID { + AppAuthenticator.presentAuthenticationUsingInfo( + authInfo, + touchIDReason: AuthenticationStrings.disableTouchReason, + success: self.touchIDSuccess, + cancel: nil, + fallback: self.touchIDFallback + ) + } else { + toggleTouchID(true) + } + } + + func toggleTouchID(_ enabled: Bool) { + authInfo?.useTouchID = enabled + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authInfo) + switchControl?.setOn(enabled, animated: true) + } +} + +class AuthenticationSettingsViewController: SettingsTableViewController { + override func viewDidLoad() { + super.viewDidLoad() + updateTitleForTouchIDState() + + let notificationCenter = NotificationCenter.default + notificationCenter.addObserver(self, selector: #selector(AuthenticationSettingsViewController.refreshSettings(_:)), name: NSNotification.Name(rawValue: NotificationPasscodeDidRemove), object: nil) + notificationCenter.addObserver(self, selector: #selector(AuthenticationSettingsViewController.refreshSettings(_:)), name: NSNotification.Name(rawValue: NotificationPasscodeDidCreate), object: nil) + notificationCenter.addObserver(self, selector: #selector(AuthenticationSettingsViewController.refreshSettings(_:)), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + + tableView.accessibilityIdentifier = "AuthenticationManager.settingsTableView" + } + + deinit { + let notificationCenter = NotificationCenter.default + notificationCenter.removeObserver(self, name: NSNotification.Name(rawValue: NotificationPasscodeDidRemove), object: nil) + notificationCenter.removeObserver(self, name: NSNotification.Name(rawValue: NotificationPasscodeDidCreate), object: nil) + notificationCenter.removeObserver(self, name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + } + + override func generateSettings() -> [SettingSection] { + if let _ = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() { + return passcodeEnabledSettings() + } else { + return passcodeDisabledSettings() + } + } + + fileprivate func updateTitleForTouchIDState() { + let localAuthContext = LAContext() + if localAuthContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) { + let title: String + if #available(iOS 11.0, *), localAuthContext.biometryType == .faceID { + title = AuthenticationStrings.faceIDPasscodeSetting + } else { + title = AuthenticationStrings.touchIDPasscodeSetting + } + navigationItem.title = title + } else { + navigationItem.title = AuthenticationStrings.passcode + } + } + + fileprivate func passcodeEnabledSettings() -> [SettingSection] { + var settings = [SettingSection]() + + let passcodeSectionTitle = NSAttributedString(string: AuthenticationStrings.passcode) + let passcodeSection = SettingSection(title: passcodeSectionTitle, children: [ + TurnPasscodeOffSetting(settings: self), + ChangePasscodeSetting(settings: self, delegate: nil, enabled: true) + ]) + + var requirePasscodeSectionChildren: [Setting] = [RequirePasscodeSetting(settings: self)] + let localAuthContext = LAContext() + if localAuthContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) { + let title: String + if #available(iOS 11.0, *), localAuthContext.biometryType == .faceID { + title = Strings.UseFaceID + } else { + title = Strings.UseTouchID + } + requirePasscodeSectionChildren.append( + TouchIDSetting( + title: NSAttributedString.tableRowTitle(title, enabled: true), + navigationController: self.navigationController, + delegate: nil, + enabled: true, + touchIDSuccess: { [unowned self] in + self.touchIDAuthenticationSucceeded() + }, + touchIDFallback: { [unowned self] in + self.fallbackOnTouchIDFailure() + } + ) + ) + } + + let requirePasscodeSection = SettingSection(title: nil, children: requirePasscodeSectionChildren) + settings += [ + passcodeSection, + requirePasscodeSection, + ] + + return settings + } + + fileprivate func passcodeDisabledSettings() -> [SettingSection] { + var settings = [SettingSection]() + + let passcodeSectionTitle = NSAttributedString(string: AuthenticationStrings.passcode) + let passcodeSection = SettingSection(title: passcodeSectionTitle, children: [ + TurnPasscodeOnSetting(settings: self), + ChangePasscodeSetting(settings: self, delegate: nil, enabled: false) + ]) + + let requirePasscodeSection = SettingSection(title: nil, children: [ + RequirePasscodeSetting(settings: self, delegate: nil, enabled: false), + ]) + + settings += [ + passcodeSection, + requirePasscodeSection, + ] + + return settings + } +} + +extension AuthenticationSettingsViewController { + func refreshSettings(_ notification: Notification) { + updateTitleForTouchIDState() + settings = generateSettings() + tableView.reloadData() + } +} + +extension AuthenticationSettingsViewController: PasscodeEntryDelegate { + fileprivate func getTouchIDSetting() -> TouchIDSetting? { + guard settings.count >= 2 && settings[1].count >= 2 else { + return nil + } + return settings[1][1] as? TouchIDSetting + } + + func touchIDAuthenticationSucceeded() { + getTouchIDSetting()?.toggleTouchID(false) + } + + func fallbackOnTouchIDFailure() { + AppAuthenticator.presentPasscodeAuthentication(self.navigationController, delegate: self) + } + + @objc func passcodeValidationDidSucceed() { + getTouchIDSetting()?.toggleTouchID(false) + navigationController?.dismiss(animated: true, completion: nil) + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/BasePasscodeViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/BasePasscodeViewController.swift new file mode 100644 index 0000000000..62dd46e8a0 --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/BasePasscodeViewController.swift @@ -0,0 +1,92 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftKeychainWrapper + +/// Base UIViewController subclass containing methods for displaying common error messaging +/// for the various Passcode configuration screens. +class BasePasscodeViewController: UIViewController { + var authenticationInfo: AuthenticationKeychainInfo? + + var errorToast: ErrorToast? + let errorPadding: CGFloat = 10 + + init() { + self.authenticationInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(self.dismissAnimated)) + automaticallyAdjustsScrollViewInsets = false + } + + func dismissAnimated() { + self.dismiss(animated: true, completion: nil) + } +} + +// MARK: - Error Helpers +extension BasePasscodeViewController { + fileprivate func displayError(_ text: String) { + errorToast?.removeFromSuperview() + errorToast = { + let toast = ErrorToast() + toast.textLabel.text = text + view.addSubview(toast) + toast.snp.makeConstraints { make in + make.center.equalTo(self.view) + make.left.greaterThanOrEqualTo(self.view).offset(errorPadding) + make.right.lessThanOrEqualTo(self.view).offset(-errorPadding) + } + return toast + }() + } + + func displayLockoutError() { + displayError(AuthenticationStrings.maximumAttemptsReachedNoTime) + } + + func failMismatchPasscode() { + let mismatchPasscodeError + = NSLocalizedString("Passcodes didn’t match. Try again.", + tableName: "AuthenticationManager", + comment: "Error message displayed to user when their confirming passcode doesn't match the first code.") + displayError(mismatchPasscodeError) + } + + func failMustBeDifferent() { + let useNewPasscodeError + = NSLocalizedString("New passcode must be different than existing code.", + tableName: "AuthenticationManager", + comment: "Error message displayed when user tries to enter the same passcode as their existing code when changing it.") + displayError(useNewPasscodeError) + } + + func failIncorrectPasscode(_ inputView: PasscodeInputView) { + authenticationInfo?.recordFailedAttempt() + let numberOfAttempts = authenticationInfo?.failedAttempts ?? 0 + if numberOfAttempts == AllowedPasscodeFailedAttempts { + authenticationInfo?.lockOutUser() + displayError(AuthenticationStrings.maximumAttemptsReachedNoTime) + inputView.isUserInteractionEnabled = false + resignFirstResponder() + } else { + displayError(String(format: AuthenticationStrings.incorrectAttemptsRemaining, (AllowedPasscodeFailedAttempts - numberOfAttempts))) + } + + inputView.resetCode() + + // Store mutations on authentication info object + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authenticationInfo) + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/ChangePasscodeViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/ChangePasscodeViewController.swift new file mode 100644 index 0000000000..486ed2c34f --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/ChangePasscodeViewController.swift @@ -0,0 +1,93 @@ +/* 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/. */ + +import Foundation +import SwiftKeychainWrapper +import Shared + +let NotificationPasscodeDidChange = "NotificationPasscodeDidChange" + +/// Displayed to the user when changing an existing passcode. +class ChangePasscodeViewController: PagingPasscodeViewController, PasscodeInputViewDelegate { + fileprivate var newPasscode: String? + fileprivate var oldPasscode: String? + + override init() { + super.init() + self.title = AuthenticationStrings.changePasscode + self.panes = [ + PasscodePane(title: AuthenticationStrings.enterPasscode, passcodeSize: authenticationInfo?.passcode?.count ?? 6), + PasscodePane(title: AuthenticationStrings.enterNewPasscode, passcodeSize: 6), + PasscodePane(title: AuthenticationStrings.reenterPasscode, passcodeSize: 6), + ] + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + panes.forEach { $0.codeInputView.delegate = self } + + // Don't show the keyboard or allow typing if we're locked out. Also display the error. + if authenticationInfo?.isLocked() ?? false { + displayLockoutError() + panes.first?.codeInputView.isUserInteractionEnabled = false + } else { + panes.first?.codeInputView.becomeFirstResponder() + } + } + + func passcodeInputView(_ inputView: PasscodeInputView, didFinishEnteringCode code: String) { + switch currentPaneIndex { + case 0: + // Constraint: We need to make sure that the first passcode they've entered matches the one stored in the keychain + if code != authenticationInfo?.passcode { + panes[currentPaneIndex].shakePasscode() + failIncorrectPasscode(inputView) + return + } + oldPasscode = code + authenticationInfo?.recordValidation() + + // Clear out any previous errors if we are allowed to proceed + errorToast?.removeFromSuperview() + scrollToNextAndSelect() + case 1: + // Constraint: The new passcode cannot match their old passcode. + if oldPasscode == code { + failMustBeDifferent() + + // Scroll back and reset the input fields + resetAllInputFields() + return + } + newPasscode = code + errorToast?.removeFromSuperview() + scrollToNextAndSelect() + case 2: + if newPasscode != code { + failMismatchPasscode() + + // Scroll back and reset input fields + resetAllInputFields() + scrollToPreviousAndSelect() + newPasscode = nil + return + } + changePasscodeToCode(code) + dismissAnimated() + default: + break + } + } + + fileprivate func changePasscodeToCode(_ code: String) { + authenticationInfo?.updatePasscode(code) + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authenticationInfo) + let notificationCenter = NotificationCenter.default + notificationCenter.post(name: Notification.Name(rawValue: NotificationPasscodeDidChange), object: nil) + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/PagingPasscodeViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/PagingPasscodeViewController.swift new file mode 100644 index 0000000000..5016ac6427 --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/PagingPasscodeViewController.swift @@ -0,0 +1,89 @@ +/* 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/. */ + +import Foundation +private let PaneSwipeDuration: TimeInterval = 0.3 + +/// Base class for implementing a Passcode configuration screen with multiple 'panes'. +class PagingPasscodeViewController: BasePasscodeViewController { + fileprivate lazy var pager: UIScrollView = { + let scrollView = UIScrollView() + scrollView.isPagingEnabled = true + scrollView.isUserInteractionEnabled = false + scrollView.showsHorizontalScrollIndicator = false + scrollView.showsVerticalScrollIndicator = false + return scrollView + }() + + var panes = [PasscodePane]() + var currentPaneIndex: Int = 0 + + override func viewDidLoad() { + super.viewDidLoad() + view.addSubview(pager) + panes.forEach { pager.addSubview($0) } + pager.snp.makeConstraints { make in + make.bottom.left.right.equalTo(self.view) + make.top.equalTo(self.topLayoutGuide.snp.bottom) + } + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + panes.enumerated().forEach { index, pane in + pane.frame = CGRect(origin: CGPoint(x: CGFloat(index) * pager.frame.width, y: 0), size: pager.frame.size) + } + pager.contentSize = CGSize(width: CGFloat(panes.count) * pager.frame.width, height: pager.frame.height) + scrollToPaneAtIndex(currentPaneIndex) + if self.authenticationInfo?.isLocked() ?? false { + return + } + panes[currentPaneIndex].codeInputView.becomeFirstResponder() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + self.view.endEditing(true) + } +} + +extension PagingPasscodeViewController { + @discardableResult func scrollToNextAndSelect() -> PasscodePane { + scrollToNextPane() + panes[currentPaneIndex].codeInputView.becomeFirstResponder() + return panes[currentPaneIndex] + } + + @discardableResult func scrollToPreviousAndSelect() -> PasscodePane { + scrollToPreviousPane() + panes[currentPaneIndex].codeInputView.becomeFirstResponder() + return panes[currentPaneIndex] + } + + func resetAllInputFields() { + panes.forEach { $0.codeInputView.resetCode() } + } + + func scrollToNextPane() { + guard (currentPaneIndex + 1) < panes.count else { + return + } + currentPaneIndex += 1 + scrollToPaneAtIndex(currentPaneIndex) + } + + func scrollToPreviousPane() { + guard (currentPaneIndex - 1) >= 0 else { + return + } + currentPaneIndex -= 1 + scrollToPaneAtIndex(currentPaneIndex) + } + + func scrollToPaneAtIndex(_ index: Int) { + UIView.animate(withDuration: PaneSwipeDuration, delay: 0, options: UIViewAnimationOptions(), animations: { + self.pager.contentOffset = CGPoint(x: CGFloat(self.currentPaneIndex) * self.pager.frame.width, y: 0) + }, completion: nil) + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/PasscodeEntryViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/PasscodeEntryViewController.swift new file mode 100644 index 0000000000..c9a8b009dd --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/PasscodeEntryViewController.swift @@ -0,0 +1,92 @@ +/* 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/. */ + +import Foundation +import SnapKit +import Shared +import SwiftKeychainWrapper + +/// Delegate available for PasscodeEntryViewController consumers to be notified of the validation of a passcode. +@objc protocol PasscodeEntryDelegate: class { + func passcodeValidationDidSucceed() + @objc optional func userDidCancelValidation() +} + +/// Presented to the to user when asking for their passcode to validate entry into a part of the app. +class PasscodeEntryViewController: BasePasscodeViewController { + weak var delegate: PasscodeEntryDelegate? + fileprivate var passcodePane: PasscodePane + + override init() { + let authInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() + passcodePane = PasscodePane(title:nil, passcodeSize:authInfo?.passcode?.count ?? 6) + + super.init() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + title = AuthenticationStrings.enterPasscodeTitle + view.addSubview(passcodePane) + passcodePane.snp.makeConstraints { make in + make.bottom.left.right.equalTo(self.view) + make.top.equalTo(self.topLayoutGuide.snp.bottom) + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + passcodePane.codeInputView.delegate = self + + // Don't show the keyboard or allow typing if we're locked out. Also display the error. + if authenticationInfo?.isLocked() ?? false { + displayLockoutError() + passcodePane.codeInputView.isUserInteractionEnabled = false + } else { + passcodePane.codeInputView.becomeFirstResponder() + } + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if authenticationInfo?.isLocked() ?? false { + passcodePane.codeInputView.isUserInteractionEnabled = false + passcodePane.codeInputView.resignFirstResponder() + } else { + passcodePane.codeInputView.becomeFirstResponder() + } + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + self.view.endEditing(true) + } + + override func dismissAnimated() { + delegate?.userDidCancelValidation?() + super.dismissAnimated() + } +} + +extension PasscodeEntryViewController: PasscodeInputViewDelegate { + func passcodeInputView(_ inputView: PasscodeInputView, didFinishEnteringCode code: String) { + if let passcode = authenticationInfo?.passcode, passcode == code { + authenticationInfo?.recordValidation() + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authenticationInfo) + delegate?.passcodeValidationDidSucceed() + } else { + passcodePane.shakePasscode() + failIncorrectPasscode(inputView) + passcodePane.codeInputView.resetCode() + + // Store mutations on authentication info object + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authenticationInfo) + } + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/PasscodeViews.swift b/mobile/ios/Client/Frontend/AuthenticationManager/PasscodeViews.swift new file mode 100644 index 0000000000..2283fd7da7 --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/PasscodeViews.swift @@ -0,0 +1,206 @@ +/* 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/. */ + +import Foundation +import SnapKit + +private struct PasscodeUX { + static let TitleVerticalSpacing: CGFloat = 32 + static let DigitSize: CGFloat = 30 + static let TopMargin: CGFloat = 80 + static let PasscodeFieldSize: CGSize = CGSize(width: 160, height: 32) +} + +@objc protocol PasscodeInputViewDelegate: class { + func passcodeInputView(_ inputView: PasscodeInputView, didFinishEnteringCode code: String) +} + +/// A custom, keyboard-able view that displays the blank/filled digits when entrering a passcode. +class PasscodeInputView: UIView, UIKeyInput { + weak var delegate: PasscodeInputViewDelegate? + + var digitFont: UIFont = UIConstants.PasscodeEntryFont + + let blankCharacter: Character = "-" + + let filledCharacter: Character = "•" + + fileprivate let passcodeSize: Int + + fileprivate var inputtedCode: String = "" + + fileprivate var blankDigitString: NSAttributedString { + return NSAttributedString(string: "\(blankCharacter)", attributes: [NSFontAttributeName: digitFont]) + } + + fileprivate var filledDigitString: NSAttributedString { + return NSAttributedString(string: "\(filledCharacter)", attributes: [NSFontAttributeName: digitFont]) + } + + @objc var keyboardType: UIKeyboardType = .numberPad + + init(frame: CGRect, passcodeSize: Int) { + self.passcodeSize = passcodeSize + super.init(frame: frame) + isOpaque = false + } + + convenience init(passcodeSize: Int) { + self.init(frame: CGRect.zero, passcodeSize: passcodeSize) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var canBecomeFirstResponder: Bool { + return true + } + + func resetCode() { + inputtedCode = "" + setNeedsDisplay() + } + + @objc var hasText: Bool { + return inputtedCode.characters.count > 0 + } + + @objc func insertText(_ text: String) { + guard inputtedCode.characters.count < passcodeSize else { + return + } + + inputtedCode += text + setNeedsDisplay() + if inputtedCode.characters.count == passcodeSize { + delegate?.passcodeInputView(self, didFinishEnteringCode: inputtedCode) + } + } + + // Required for implementing UIKeyInput + @objc func deleteBackward() { + guard inputtedCode.characters.count > 0 else { + return + } + + inputtedCode.remove(at: inputtedCode.characters.index(before: inputtedCode.endIndex)) + setNeedsDisplay() + } + + override func draw(_ rect: CGRect) { + let circleSize = CGSize(width: 14, height: 14) + + guard let context = UIGraphicsGetCurrentContext() else { return } + + context.setLineWidth(1) + context.setStrokeColor(UIConstants.PasscodeDotColor.cgColor) + context.setFillColor(UIConstants.PasscodeDotColor.cgColor) + + (0.. Int { + return 1 + } + + override func accessibilityElement(at index: Int) -> Any? { + switch index { + case 0: return titleLabel + default: return nil + } + } + + init(title: String? = nil, passcodeSize: Int = 4) { + codeInputView = PasscodeInputView(passcodeSize: passcodeSize) + super.init(frame: CGRect.zero) + backgroundColor = UIConstants.TableViewHeaderBackgroundColor + + titleLabel.text = title + centerContainer.addSubview(titleLabel) + centerContainer.addSubview(codeInputView) + addSubview(centerContainer) + + centerContainer.snp.makeConstraints { make in + make.centerX.equalTo(self) + containerCenterConstraint = make.centerY.equalTo(self).constraint + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalTo(centerContainer) + make.top.equalTo(centerContainer) + make.bottom.equalTo(codeInputView.snp.top).offset(-PasscodeUX.TitleVerticalSpacing) + } + + codeInputView.snp.makeConstraints { make in + codeViewCenterConstraint = make.centerX.equalTo(centerContainer).constraint + make.bottom.equalTo(centerContainer) + make.size.equalTo(PasscodeUX.PasscodeFieldSize) + } + layoutIfNeeded() + NotificationCenter.default.addObserver(self, selector: #selector(PasscodePane.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(PasscodePane.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) + } + + func shakePasscode() { + UIView.animate(withDuration: 0.1, animations: { + self.codeViewCenterConstraint?.update(offset: -10) + self.layoutIfNeeded() + }, completion: { complete in + UIView.animate(withDuration: 0.1, animations: { + self.codeViewCenterConstraint?.update(offset: 0) + self.layoutIfNeeded() + }) + }) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func keyboardWillShow(_ sender: Notification) { + guard let keyboardFrame = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as AnyObject).cgRectValue else { + return + } + + UIView.animate(withDuration: 0.1, animations: { + self.containerCenterConstraint?.update(offset: -keyboardFrame.height/2) + self.layoutIfNeeded() + }) + } + + func keyboardWillHide(_ sender: Notification) { + UIView.animate(withDuration: 0.1, animations: { + self.containerCenterConstraint?.update(offset: 0) + self.layoutIfNeeded() + }) + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/RemovePasscodeViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/RemovePasscodeViewController.swift new file mode 100644 index 0000000000..6141a0aaa5 --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/RemovePasscodeViewController.swift @@ -0,0 +1,56 @@ +/* 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/. */ + +import Foundation +import SwiftKeychainWrapper +import Shared + +let NotificationPasscodeDidRemove = "NotificationPasscodeDidRemove" + +/// Displayed to the user when removing a passcode. +class RemovePasscodeViewController: PagingPasscodeViewController, PasscodeInputViewDelegate { + override init() { + super.init() + self.title = AuthenticationStrings.turnOffPasscode + self.panes = [ + PasscodePane(title: AuthenticationStrings.enterPasscode, passcodeSize: authenticationInfo?.passcode?.count ?? 6), + ] + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + panes.forEach { $0.codeInputView.delegate = self } + + // Don't show the keyboard or allow typing if we're locked out. Also display the error. + if authenticationInfo?.isLocked() ?? false { + displayLockoutError() + panes.first?.codeInputView.isUserInteractionEnabled = false + } else { + panes.first?.codeInputView.becomeFirstResponder() + } + } + + func passcodeInputView(_ inputView: PasscodeInputView, didFinishEnteringCode code: String) { + if code != authenticationInfo?.passcode { + panes[currentPaneIndex].shakePasscode() + failIncorrectPasscode(inputView) + return + } + + authenticationInfo?.recordValidation() + errorToast?.removeFromSuperview() + removePasscode() + dismissAnimated() + } + + fileprivate func removePasscode() { + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(nil) + let notificationCenter = NotificationCenter.default + notificationCenter.post(name: Notification.Name(rawValue: NotificationPasscodeDidRemove), object: nil) + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/RequirePasscodeIntervalViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/RequirePasscodeIntervalViewController.swift new file mode 100644 index 0000000000..182dcc496c --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/RequirePasscodeIntervalViewController.swift @@ -0,0 +1,77 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftKeychainWrapper + +/// Screen presented to the user when selecting the time interval before requiring a passcode +class RequirePasscodeIntervalViewController: UITableViewController { + let intervalOptions: [PasscodeInterval] = [ + .immediately, + .oneMinute, + .fiveMinutes, + .tenMinutes, + .fifteenMinutes, + .oneHour + ] + + fileprivate let BasicCheckmarkCell = "BasicCheckmarkCell" + fileprivate var authenticationInfo: AuthenticationKeychainInfo? + + init() { + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + title = AuthenticationStrings.requirePasscode + + tableView.accessibilityIdentifier = "AuthenticationManager.passcodeIntervalTableView" + + tableView.register(UITableViewCell.self, forCellReuseIdentifier: BasicCheckmarkCell) + tableView.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + + let headerFooterFrame = CGRect(origin: CGPoint.zero, size: CGSize(width: self.view.frame.width, height: UIConstants.TableViewHeaderFooterHeight)) + let headerView = SettingsTableSectionHeaderFooterView(frame: headerFooterFrame) + headerView.showTopBorder = false + headerView.showBottomBorder = true + + let footerView = SettingsTableSectionHeaderFooterView(frame: headerFooterFrame) + footerView.showTopBorder = true + footerView.showBottomBorder = false + + tableView.tableHeaderView = headerView + tableView.tableFooterView = footerView + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.authenticationInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() + tableView.reloadData() + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: BasicCheckmarkCell, for: indexPath) + let option = intervalOptions[indexPath.row] + let intervalTitle = NSAttributedString.tableRowTitle(option.settingTitle, enabled: true) + cell.textLabel?.attributedText = intervalTitle + cell.accessoryType = authenticationInfo?.requiredPasscodeInterval == option ? .checkmark : .none + return cell + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return intervalOptions.count + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + authenticationInfo?.updateRequiredPasscodeInterval(intervalOptions[indexPath.row]) + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authenticationInfo) + tableView.reloadData() + } +} diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/SensitiveViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/SensitiveViewController.swift new file mode 100644 index 0000000000..1f33ade48c --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/SensitiveViewController.swift @@ -0,0 +1,115 @@ +/* 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/. */ + +import Foundation +import SnapKit +import SwiftKeychainWrapper + +enum AuthenticationState { + case notAuthenticating + case presenting +} + +class SensitiveViewController: UIViewController { + var promptingForTouchID: Bool = false + var backgroundedBlur: UIImageView? + var authState: AuthenticationState = .notAuthenticating + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + let notificationCenter = NotificationCenter.default + notificationCenter.addObserver(self, selector: #selector(SensitiveViewController.checkIfUserRequiresValidation), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil) + notificationCenter.addObserver(self, selector: #selector(SensitiveViewController.checkIfUserRequiresValidation), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + notificationCenter.addObserver(self, selector: #selector(SensitiveViewController.blurContents), name: NSNotification.Name.UIApplicationWillResignActive, object: nil) + notificationCenter.addObserver(self, selector: #selector(SensitiveViewController.hideLogins), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) + + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + let notificationCenter = NotificationCenter.default + notificationCenter.removeObserver(self, name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil) + notificationCenter.removeObserver(self, name: NSNotification.Name.UIApplicationWillResignActive, object: nil) + notificationCenter.removeObserver(self, name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + notificationCenter.removeObserver(self, name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) + } + + func checkIfUserRequiresValidation() { + guard authState != .presenting else { + return + } + + presentedViewController?.dismiss(animated: false, completion: nil) + guard let authInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo(), authInfo.requiresValidation() else { + removeBackgroundedBlur() + return + } + + promptingForTouchID = true + AppAuthenticator.presentAuthenticationUsingInfo(authInfo, + touchIDReason: AuthenticationStrings.loginsTouchReason, + success: { + self.promptingForTouchID = false + self.authState = .notAuthenticating + self.removeBackgroundedBlur() + }, + cancel: { + self.promptingForTouchID = false + self.authState = .notAuthenticating + _ = self.navigationController?.popToRootViewController(animated: true) + }, + fallback: { + self.promptingForTouchID = false + AppAuthenticator.presentPasscodeAuthentication(self.navigationController, delegate: self) + } + ) + authState = .presenting + } + + func hideLogins() { + _ = self.navigationController?.popToRootViewController(animated: true) + } + + func blurContents() { + if backgroundedBlur == nil { + backgroundedBlur = addBlurredContent() + } + } + + func removeBackgroundedBlur() { + if !promptingForTouchID { + backgroundedBlur?.removeFromSuperview() + backgroundedBlur = nil + } + } + + fileprivate func addBlurredContent() -> UIImageView? { + guard let snapshot = view.screenshot() else { + return nil + } + + let blurredSnapshot = snapshot.applyBlur(withRadius: 10, blurType: BOXFILTER, tintColor: UIColor(white: 1, alpha: 0.3), saturationDeltaFactor: 1.8, maskImage: nil) + let blurView = UIImageView(image: blurredSnapshot) + view.addSubview(blurView) + blurView.snp.makeConstraints { $0.edges.equalTo(self.view) } + view.layoutIfNeeded() + + return blurView + } +} + +// MARK: - PasscodeEntryDelegate +extension SensitiveViewController: PasscodeEntryDelegate { + func passcodeValidationDidSucceed() { + removeBackgroundedBlur() + self.navigationController?.dismiss(animated: true, completion: nil) + self.authState = .notAuthenticating + } + + func userDidCancelValidation() { + _ = self.navigationController?.popToRootViewController(animated: false) + self.authState = .notAuthenticating + } +} + diff --git a/mobile/ios/Client/Frontend/AuthenticationManager/SetupPasscodeViewController.swift b/mobile/ios/Client/Frontend/AuthenticationManager/SetupPasscodeViewController.swift new file mode 100644 index 0000000000..1b08a1dea1 --- /dev/null +++ b/mobile/ios/Client/Frontend/AuthenticationManager/SetupPasscodeViewController.swift @@ -0,0 +1,68 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftKeychainWrapper + +let NotificationPasscodeDidCreate = "NotificationPasscodeDidCreate" + +/// Displayed to the user when setting up a passcode. +class SetupPasscodeViewController: PagingPasscodeViewController, PasscodeInputViewDelegate { + fileprivate var confirmCode: String? + + override init() { + super.init() + self.title = AuthenticationStrings.setPasscode + self.panes = [ + PasscodePane(title: AuthenticationStrings.enterAPasscode, passcodeSize: 6), + PasscodePane(title: AuthenticationStrings.reenterPasscode, passcodeSize: 6), + ] + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + panes.forEach { $0.codeInputView.delegate = self } + + // Don't show the keyboard or allow typing if we're locked out. Also display the error. + if authenticationInfo?.isLocked() ?? false { + displayLockoutError() + panes.first?.codeInputView.isUserInteractionEnabled = false + } else { + panes.first?.codeInputView.becomeFirstResponder() + } + } + + func passcodeInputView(_ inputView: PasscodeInputView, didFinishEnteringCode code: String) { + switch currentPaneIndex { + case 0: + confirmCode = code + scrollToNextAndSelect() + case 1: + // Constraint: The first and confirmation codes must match. + if confirmCode != code { + failMismatchPasscode() + resetAllInputFields() + scrollToPreviousAndSelect() + confirmCode = nil + return + } + + createPasscodeWithCode(code) + dismissAnimated() + default: + break + } + } + + fileprivate func createPasscodeWithCode(_ code: String) { + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(AuthenticationKeychainInfo(passcode: code)) + let notificationCenter = NotificationCenter.default + notificationCenter.post(name: Notification.Name(rawValue: NotificationPasscodeDidCreate), object: nil) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/AboutHomeHandler.swift b/mobile/ios/Client/Frontend/Browser/AboutHomeHandler.swift new file mode 100644 index 0000000000..463530a70f --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/AboutHomeHandler.swift @@ -0,0 +1,38 @@ +/* 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/. */ + +/** + * Handles the page request to about/home/ so that the page loads and does not throw an error (404) on initialization + */ +import GCDWebServers + +struct AboutHomeHandler { + static func register(_ webServer: WebServer) { + webServer.registerHandlerForMethod("GET", module: "about", resource: "home") { (request: GCDWebServerRequest?) -> GCDWebServerResponse! in + return GCDWebServerResponse(statusCode: 200) + } + } +} + +struct AboutLicenseHandler { + static func register(_ webServer: WebServer) { + webServer.registerHandlerForMethod("GET", module: "about", resource: "license") { (request: GCDWebServerRequest?) -> GCDWebServerResponse! in + let path = Bundle.main.path(forResource: "Licenses", ofType: "html") + do { + let html = try NSString(contentsOfFile: path!, encoding: String.Encoding.utf8.rawValue) as String + return GCDWebServerDataResponse(html: html) + } catch { + print("Unable to register webserver \(error)") + } + return GCDWebServerResponse(statusCode: 200) + } + } +} + +extension GCDWebServerDataResponse { + convenience init(XHTML: String) { + let data = XHTML.data(using: String.Encoding.utf8, allowLossyConversion: false) + self.init(data: data, contentType: "application/xhtml+xml; charset=utf-8") + } +} diff --git a/mobile/ios/Client/Frontend/Browser/Authenticator.swift b/mobile/ios/Client/Frontend/Browser/Authenticator.swift new file mode 100644 index 0000000000..28c4db7ead --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/Authenticator.swift @@ -0,0 +1,153 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import Deferred + +private let CancelButtonTitle = NSLocalizedString("Cancel", comment: "Label for Cancel button") +private let LogInButtonTitle = NSLocalizedString("Log in", comment: "Authentication prompt log in button") +private let log = Logger.browserLogger + +class Authenticator { + fileprivate static let MaxAuthenticationAttempts = 3 + + static func handleAuthRequest(_ viewController: UIViewController, challenge: URLAuthenticationChallenge, loginsHelper: LoginsHelper?) -> Deferred> { + // If there have already been too many login attempts, we'll just fail. + if challenge.previousFailureCount >= Authenticator.MaxAuthenticationAttempts { + return deferMaybe(LoginDataError(description: "Too many attempts to open site")) + } + + var credential = challenge.proposedCredential + + // If we were passed an initial set of credentials from iOS, try and use them. + if let proposed = credential { + if !(proposed.user?.isEmpty ?? true) { + if challenge.previousFailureCount == 0 { + return deferMaybe(Login.createWithCredential(credential!, protectionSpace: challenge.protectionSpace)) + } + } else { + credential = nil + } + } + + // If we have some credentials, we'll show a prompt with them. + if let credential = credential { + return promptForUsernamePassword(viewController, credentials: credential, protectionSpace: challenge.protectionSpace, loginsHelper: loginsHelper) + } + + // Otherwise, try to look them up and show the prompt. + if let loginsHelper = loginsHelper { + return findMatchingCredentialsForChallenge(challenge, fromLoginsProvider: loginsHelper.logins).bindQueue(DispatchQueue.main) { result in + guard let credentials = result.successValue else { + return deferMaybe(result.failureValue ?? LoginDataError(description: "Unknown error when finding credentials")) + } + return self.promptForUsernamePassword(viewController, credentials: credentials, protectionSpace: challenge.protectionSpace, loginsHelper: loginsHelper) + } + } + + // No credentials, so show an empty prompt. + return self.promptForUsernamePassword(viewController, credentials: nil, protectionSpace: challenge.protectionSpace, loginsHelper: nil) + } + + static func findMatchingCredentialsForChallenge(_ challenge: URLAuthenticationChallenge, fromLoginsProvider loginsProvider: BrowserLogins) -> Deferred> { + return loginsProvider.getLoginsForProtectionSpace(challenge.protectionSpace) >>== { cursor in + guard cursor.count >= 1 else { + return deferMaybe(nil) + } + + let logins = cursor.asArray() + var credentials: URLCredential? = nil + + // It is possible that we might have duplicate entries since we match against host and scheme://host. + // This is a side effect of https://bugzilla.mozilla.org/show_bug.cgi?id=1238103. + if logins.count > 1 { + credentials = (logins.find { login in + (login.protectionSpace.`protocol` == challenge.protectionSpace.`protocol`) && !login.hasMalformedHostname + })?.credentials + + let malformedGUIDs: [GUID] = logins.flatMap { login in + if login.hasMalformedHostname { + return login.guid + } + return nil + } + loginsProvider.removeLoginsWithGUIDs(malformedGUIDs).upon { log.debug("Removed malformed logins. Success :\($0.isSuccess)") } + } + + // Found a single entry but the schemes don't match. This is a result of a schemeless entry that we + // saved in a previous iteration of the app so we need to migrate it. We only care about the + // the username/password so we can rewrite the scheme to be correct. + else if logins.count == 1 && logins[0].protectionSpace.`protocol` != challenge.protectionSpace.`protocol` { + let login = logins[0] + credentials = login.credentials + let new = Login(credential: login.credentials, protectionSpace: challenge.protectionSpace) + return loginsProvider.updateLoginByGUID(login.guid, new: new, significant: true) + >>> { deferMaybe(credentials) } + } + + // Found a single entry that matches the scheme and host - good to go. + else { + credentials = logins[0].credentials + } + + return deferMaybe(credentials) + } + } + + fileprivate static func promptForUsernamePassword(_ viewController: UIViewController, credentials: URLCredential?, protectionSpace: URLProtectionSpace, loginsHelper: LoginsHelper?) -> Deferred> { + if protectionSpace.host.isEmpty { + print("Unable to show a password prompt without a hostname") + return deferMaybe(LoginDataError(description: "Unable to show a password prompt without a hostname")) + } + + let deferred = Deferred>() + let alert: UIAlertController + let title = NSLocalizedString("Authentication required", comment: "Authentication prompt title") + if !(protectionSpace.realm?.isEmpty ?? true) { + let msg = NSLocalizedString("A username and password are being requested by %@. The site says: %@", comment: "Authentication prompt message with a realm. First parameter is the hostname. Second is the realm string") + let formatted = NSString(format: msg as NSString, protectionSpace.host, protectionSpace.realm ?? "") as String + alert = UIAlertController(title: title, message: formatted, preferredStyle: UIAlertControllerStyle.alert) + } else { + let msg = NSLocalizedString("A username and password are being requested by %@.", comment: "Authentication prompt message with no realm. Parameter is the hostname of the site") + let formatted = NSString(format: msg as NSString, protectionSpace.host) as String + alert = UIAlertController(title: title, message: formatted, preferredStyle: UIAlertControllerStyle.alert) + } + + // Add a button to log in. + let action = UIAlertAction(title: LogInButtonTitle, + style: UIAlertActionStyle.default) { (action) -> Void in + guard let user = alert.textFields?[0].text, let pass = alert.textFields?[1].text else { deferred.fill(Maybe(failure: LoginDataError(description: "Username and Password required"))); return } + + let login = Login.createWithCredential(URLCredential(user: user, password: pass, persistence: .forSession), protectionSpace: protectionSpace) + deferred.fill(Maybe(success: login)) + loginsHelper?.setCredentials(login) + } + alert.addAction(action) + + // Add a cancel button. + let cancel = UIAlertAction(title: CancelButtonTitle, style: UIAlertActionStyle.cancel) { (action) -> Void in + deferred.fill(Maybe(failure: LoginDataError(description: "Save password cancelled"))) + } + alert.addAction(cancel) + + // Add a username textfield. + alert.addTextField { (textfield) -> Void in + textfield.placeholder = NSLocalizedString("Username", comment: "Username textbox in Authentication prompt") + textfield.text = credentials?.user + } + + // Add a password textfield. + alert.addTextField { (textfield) -> Void in + textfield.placeholder = NSLocalizedString("Password", comment: "Password textbox in Authentication prompt") + textfield.isSecureTextEntry = true + textfield.text = credentials?.password + } + + viewController.present(alert, animated: true) { () -> Void in } + return deferred + } + +} diff --git a/mobile/ios/Client/Frontend/Browser/BackForwardListAnimator.swift b/mobile/ios/Client/Frontend/Browser/BackForwardListAnimator.swift new file mode 100644 index 0000000000..d7c1672a0c --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/BackForwardListAnimator.swift @@ -0,0 +1,83 @@ +/* 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/. */ + +import UIKit + +class BackForwardListAnimator: NSObject, UIViewControllerAnimatedTransitioning { + + var presenting: Bool = false + let animationDuration = 0.4 + + func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let screens = (from: transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!, to: transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!) + + guard let backForwardViewController = !self.presenting ? screens.from as? BackForwardListViewController : screens.to as? BackForwardListViewController else { + return + } + + var bottomViewController = !self.presenting ? screens.to as UIViewController : screens.from as UIViewController + + if let navController = bottomViewController as? UINavigationController { + bottomViewController = navController.viewControllers.last ?? bottomViewController + } + + if let browserViewController = bottomViewController as? BrowserViewController { + animateWithBackForward(backForwardViewController, browserViewController: browserViewController, transitionContext: transitionContext) + } + } + + func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return animationDuration + } +} + +extension BackForwardListAnimator: UIViewControllerTransitioningDelegate { + func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + self.presenting = true + return self + } + + func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + self.presenting = false + return self + } +} + +extension BackForwardListAnimator { + fileprivate func animateWithBackForward(_ backForward: BackForwardListViewController, browserViewController bvc: BrowserViewController, transitionContext: UIViewControllerContextTransitioning) { + let containerView = transitionContext.containerView + + if presenting { + backForward.view.frame = bvc.view.frame + backForward.view.alpha = 0 + containerView.addSubview(backForward.view) + backForward.view.snp.updateConstraints { make in + make.edges.equalTo(containerView) + } + backForward.view.layoutIfNeeded() + + UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.3, options: [], animations: { () -> Void in + backForward.view.alpha = 1 + backForward.tableView.snp.updateConstraints { make in + make.height.equalTo(backForward.tableHeight) + } + backForward.view.layoutIfNeeded() + }, completion: { (completed) -> Void in + transitionContext.completeTransition(completed) + }) + + } else { + UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 1.2, initialSpringVelocity: 0.0, options: [], animations: { () -> Void in + backForward.view.alpha = 0 + backForward.tableView.snp.updateConstraints { make in + make.height.equalTo(0) + } + backForward.view.layoutIfNeeded() + }, completion: { (completed) -> Void in + backForward.view.removeFromSuperview() + transitionContext.completeTransition(completed) + }) + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/BackForwardListViewController.swift b/mobile/ios/Client/Frontend/Browser/BackForwardListViewController.swift new file mode 100644 index 0000000000..00a70b7ab8 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/BackForwardListViewController.swift @@ -0,0 +1,249 @@ +/* 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/. */ + +import UIKit +import Shared +import WebKit +import Storage +import SnapKit + +struct BackForwardViewUX { + static let RowHeight: CGFloat = 50 + static let BackgroundColor = UIColor(rgb: 0xf9f9fa).withAlphaComponent(0.4) +} + +class BackForwardListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UIGestureRecognizerDelegate { + + fileprivate let BackForwardListCellIdentifier = "BackForwardListViewController" + fileprivate var profile: Profile + fileprivate lazy var sites = [String: Site]() + fileprivate var dismissing = false + fileprivate var currentRow = 0 + fileprivate var verticalConstraints: [Constraint] = [] + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.separatorStyle = .none + tableView.dataSource = self + tableView.delegate = self + tableView.alwaysBounceVertical = false + tableView.register(BackForwardTableViewCell.self, forCellReuseIdentifier: self.BackForwardListCellIdentifier) + tableView.backgroundColor = BackForwardViewUX.BackgroundColor + let blurEffect = UIBlurEffect(style: .extraLight) + let blurEffectView = UIVisualEffectView(effect: blurEffect) + tableView.backgroundView = blurEffectView + + return tableView + }() + + lazy var shadow: UIView = { + let shadow = UIView() + shadow.backgroundColor = UIColor(white: 0, alpha: 0.2) + return shadow + }() + + var tabManager: TabManager! + weak var bvc: BrowserViewController? + var currentItem: WKBackForwardListItem? + var listData = [WKBackForwardListItem]() + + var tableHeight: CGFloat { + get { + assert(Thread.isMainThread, "tableHeight interacts with UIKit components - cannot call from background thread.") + return min(BackForwardViewUX.RowHeight * CGFloat(listData.count), self.view.frame.height/2) + } + } + + var backForwardTransitionDelegate: UIViewControllerTransitioningDelegate? { + didSet { + self.transitioningDelegate = backForwardTransitionDelegate + } + } + + var snappedToBottom: Bool = true + + init(profile: Profile, backForwardList: WKBackForwardList) { + self.profile = profile + super.init(nibName: nil, bundle: nil) + + loadSites(backForwardList) + loadSitesFromProfile() + } + + override func viewDidLoad() { + super.viewDidLoad() + view.addSubview(shadow) + view.addSubview(tableView) + snappedToBottom = bvc?.toolbar != nil + tableView.snp.makeConstraints { make in + make.height.equalTo(0) + make.left.right.equalTo(self.view) + } + shadow.snp.makeConstraints { make in + make.left.right.equalTo(self.view) + } + remakeVerticalConstraints() + view.layoutIfNeeded() + scrollTableViewToIndex(currentRow) + setupDismissTap() + } + + func loadSitesFromProfile() { + let sql = profile.favicons as! SQLiteHistory + let urls = listData.flatMap {$0.url.isLocal ? $0.url.getQuery()["url"]?.unescape() : $0.url.absoluteString} + + sql.getSitesForURLs(urls).uponQueue(.main) { result in + guard let results = result.successValue else { + return + } + // Add all results into the sites dictionary + results.flatMap({$0}).forEach({site in + if let url = site?.url { + self.sites[url] = site + } + }) + self.tableView.reloadData() + } + } + + func homeAndNormalPagesOnly(_ bfList: WKBackForwardList) { + let items = bfList.forwardList.reversed() + [bfList.currentItem].flatMap({$0}) + bfList.backList.reversed() + + //error url's are OK as they are used to populate history on session restore. + listData = items.filter({return !($0.url.isLocal && ($0.url.originalURLFromErrorURL?.isLocal ?? true)) || $0.url.isAboutHomeURL}) + } + + func loadSites(_ bfList: WKBackForwardList) { + currentItem = bfList.currentItem + + homeAndNormalPagesOnly(bfList) + } + + func scrollTableViewToIndex(_ index: Int) { + guard index > 1 else { + return + } + let moveToIndexPath = IndexPath(row: index-2, section: 0) + tableView.reloadRows(at: [moveToIndexPath], with: .none) + tableView.scrollToRow(at: moveToIndexPath, at: UITableViewScrollPosition.middle, animated: false) + } + + override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { + super.willTransition(to: newCollection, with: coordinator) + guard let bvc = self.bvc else { + return + } + if bvc.shouldShowFooterForTraitCollection(newCollection) != snappedToBottom { + tableView.snp.updateConstraints { make in + if snappedToBottom { + make.bottom.equalTo(self.view).offset(0) + } else { + make.top.equalTo(self.view).offset(0) + } + make.height.equalTo(0) + } + snappedToBottom = !snappedToBottom + } + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + let correctHeight = { + self.tableView.snp.updateConstraints { make in + make.height.equalTo(min(BackForwardViewUX.RowHeight * CGFloat(self.listData.count), size.height / 2)) + } + } + coordinator.animate(alongsideTransition: nil) { _ in + self.remakeVerticalConstraints() + correctHeight() + } + } + + func remakeVerticalConstraints() { + guard let bvc = self.bvc else { + return + } + for constraint in self.verticalConstraints { + constraint.deactivate() + } + self.verticalConstraints = [] + tableView.snp.makeConstraints { make in + if snappedToBottom { + verticalConstraints += [make.bottom.equalTo(self.view).offset(-bvc.footer.frame.height).constraint] + } else { + verticalConstraints += [make.top.equalTo(self.view).offset(bvc.header.frame.height + UIApplication.shared.statusBarFrame.size.height).constraint] + } + } + shadow.snp.makeConstraints() { make in + if snappedToBottom { + verticalConstraints += [ + make.bottom.equalTo(tableView.snp.top).constraint, + make.top.equalTo(self.view).constraint + ] + + } else { + verticalConstraints += [ + make.top.equalTo(tableView.snp.bottom).constraint, + make.bottom.equalTo(self.view).constraint + ] + } + } + } + + func setupDismissTap() { + let tap = UITapGestureRecognizer(target: self, action: #selector(BackForwardListViewController.handleTap)) + tap.cancelsTouchesInView = false + tap.delegate = self + view.addGestureRecognizer(tap) + } + + func handleTap() { + dismiss(animated: true, completion: nil) + } + + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { + if touch.view?.isDescendant(of: tableView) ?? true { + return false + } + return true + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Table view + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return listData.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = self.tableView.dequeueReusableCell(withIdentifier: BackForwardListCellIdentifier, for: indexPath) as! BackForwardTableViewCell + let item = listData[indexPath.item] + let urlString = item.url.isLocal ? item.url.getQuery()["url"]?.unescape() : item.url.absoluteString + + cell.isCurrentTab = listData[indexPath.item] == self.currentItem + cell.connectingBackwards = indexPath.item != listData.count-1 + cell.connectingForwards = indexPath.item != 0 + + guard let url = urlString, !item.url.isAboutHomeURL else { + cell.site = Site(url: item.url.absoluteString, title: Strings.FirefoxHomePage) + return cell + } + + cell.site = sites[url] ?? Site(url: url, title: item.title ?? "") + cell.setNeedsDisplay() + + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tabManager.selectedTab?.goToBackForwardListItem(listData[indexPath.item]) + dismiss(animated: true, completion: nil) + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return BackForwardViewUX.RowHeight + } +} diff --git a/mobile/ios/Client/Frontend/Browser/BackForwardTableViewCell.swift b/mobile/ios/Client/Frontend/Browser/BackForwardTableViewCell.swift new file mode 100644 index 0000000000..f18d2f903e --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/BackForwardTableViewCell.swift @@ -0,0 +1,142 @@ +/* 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/. */ + +import UIKit +import Storage + +class BackForwardTableViewCell: UITableViewCell { + + struct BackForwardViewCellUX { + static let bgColor = UIColor.gray + static let faviconWidth = 29 + static let faviconPadding: CGFloat = 20 + static let labelPadding = 20 + static let borderSmall = 2 + static let borderBold = 5 + static let IconSize = 23 + static let fontSize: CGFloat = 12.0 + } + + lazy var faviconView: UIImageView = { + let faviconView = UIImageView(image: FaviconFetcher.defaultFavicon) + faviconView.backgroundColor = UIColor.white + faviconView.layer.cornerRadius = 6 + faviconView.layer.borderWidth = 0.5 + faviconView.layer.borderColor = UIColor(white: 0, alpha: 0.1).cgColor + faviconView.layer.masksToBounds = true + faviconView.contentMode = .center + return faviconView + }() + + lazy var label: UILabel = { + let label = UILabel() + label.text = " " + label.font = label.font.withSize(BackForwardViewCellUX.fontSize) + label.textColor = UIColor(rgb: 0x272727) + return label + }() + + var connectingForwards = true + var connectingBackwards = true + + var isCurrentTab = false { + didSet { + if isCurrentTab { + label.font = UIFont(name: "HelveticaNeue-Bold", size: BackForwardViewCellUX.fontSize) + } + } + } + + var site: Site? { + didSet { + if let s = site { + faviconView.setFavicon(forSite: s, onCompletion: { [weak self] (color, url) in + if s.tileURL.isLocal { + self?.faviconView.image = UIImage(named: "faviconFox") + self?.faviconView.image = self?.faviconView.image?.createScaled(CGSize(width: BackForwardViewCellUX.IconSize, height: BackForwardViewCellUX.IconSize)) + self?.faviconView.backgroundColor = UIColor.white + return + } + + self?.faviconView.image = self?.faviconView.image?.createScaled(CGSize(width: BackForwardViewCellUX.IconSize, height: BackForwardViewCellUX.IconSize)) + self?.faviconView.backgroundColor = color == .clear ? .white : color + }) + var title = s.title + if title.isEmpty { + title = s.url + } + label.text = title + setNeedsLayout() + } + } + } + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + backgroundColor = UIColor.clear + selectionStyle = .none + + contentView.addSubview(faviconView) + contentView.addSubview(label) + + faviconView.snp.makeConstraints { make in + make.height.equalTo(BackForwardViewCellUX.faviconWidth) + make.width.equalTo(BackForwardViewCellUX.faviconWidth) + make.centerY.equalTo(self) + make.leading.equalTo(self.snp.leading).offset(BackForwardViewCellUX.faviconPadding) + } + + label.snp.makeConstraints { make in + make.centerY.equalTo(self) + make.leading.equalTo(faviconView.snp.trailing).offset(BackForwardViewCellUX.labelPadding) + make.trailing.equalTo(self.snp.trailing).offset(-BackForwardViewCellUX.labelPadding) + } + + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ rect: CGRect) { + super.draw(rect) + guard let context = UIGraphicsGetCurrentContext() else { return } + + var startPoint = CGPoint(x: rect.origin.x + BackForwardViewCellUX.faviconPadding + CGFloat(Double(BackForwardViewCellUX.faviconWidth)*0.5), + y: rect.origin.y + (connectingForwards ? 0 : rect.size.height/2)) + var endPoint = CGPoint(x: rect.origin.x + BackForwardViewCellUX.faviconPadding + CGFloat(Double(BackForwardViewCellUX.faviconWidth)*0.5), + y: rect.origin.y + rect.size.height - (connectingBackwards ? 0 : rect.size.height/2)) + + // flip the x component if RTL + if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft { + startPoint.x = rect.origin.x - startPoint.x + rect.size.width + endPoint.x = rect.origin.x - endPoint.x + rect.size.width + } + + context.saveGState() + context.setLineCap(CGLineCap.square) + context.setStrokeColor(BackForwardViewCellUX.bgColor.cgColor) + context.setLineWidth(1.0) + context.move(to: CGPoint(x: startPoint.x, y: startPoint.y)) + context.addLine(to: CGPoint(x: endPoint.x, y: endPoint.y)) + context.strokePath() + context.restoreGState() + } + + override func setHighlighted(_ highlighted: Bool, animated: Bool) { + if highlighted { + self.backgroundColor = UIColor(white: 0, alpha: 0.1) + } else { + self.backgroundColor = UIColor.clear + } + } + + override func prepareForReuse() { + super.prepareForReuse() + connectingForwards = true + connectingBackwards = true + isCurrentTab = false + label.font = UIFont(name: "HelveticaNeue", size: BackForwardViewCellUX.fontSize) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/BrowserPrompts.swift b/mobile/ios/Client/Frontend/Browser/BrowserPrompts.swift new file mode 100644 index 0000000000..a627e812b5 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/BrowserPrompts.swift @@ -0,0 +1,135 @@ +/* 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/. */ + +import Foundation +import WebKit + +@objc protocol JSPromptAlertControllerDelegate: class { + func promptAlertControllerDidDismiss(_ alertController: JSPromptAlertController) +} + +/// A simple version of UIAlertController that attaches a delegate to the viewDidDisappear method +/// to allow forwarding the event. The reason this is needed for prompts from Javascript is we +/// need to invoke the completionHandler passed to us from the WKWebView delegate or else +/// a runtime exception is thrown. +class JSPromptAlertController: UIAlertController { + var alertInfo: JSAlertInfo? + + weak var delegate: JSPromptAlertControllerDelegate? + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + delegate?.promptAlertControllerDidDismiss(self) + } +} + +/** + * An JSAlertInfo is used to store information about an alert we want to show either immediately or later. + * Since alerts are generated by web pages and have no upper limit it would be unwise to allocate a + * UIAlertController instance for each generated prompt which could potentially be queued in the background. + * Instead, the JSAlertInfo structure retains the relevant data needed for the prompt along with a copy + * of the provided completionHandler to let us generate the UIAlertController when needed. + */ +protocol JSAlertInfo { + func alertController() -> JSPromptAlertController + func cancel() +} + +struct MessageAlert: JSAlertInfo { + let message: String + let frame: WKFrameInfo + let completionHandler: () -> Void + + func alertController() -> JSPromptAlertController { + let alertController = JSPromptAlertController(title: titleForJavaScriptPanelInitiatedByFrame(frame), + message: message, + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction(UIAlertAction(title: UIConstants.OKString, style: UIAlertActionStyle.default) { _ in + self.completionHandler() + }) + alertController.alertInfo = self + return alertController + } + + func cancel() { + completionHandler() + } +} + +struct ConfirmPanelAlert: JSAlertInfo { + let message: String + let frame: WKFrameInfo + let completionHandler: (Bool) -> Void + + init(message: String, frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { + self.message = message + self.frame = frame + self.completionHandler = completionHandler + } + + func alertController() -> JSPromptAlertController { + // Show JavaScript confirm dialogs. + let alertController = JSPromptAlertController(title: titleForJavaScriptPanelInitiatedByFrame(frame), message: message, preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction(UIAlertAction(title: UIConstants.OKString, style: UIAlertActionStyle.default) { _ in + self.completionHandler(true) + }) + alertController.addAction(UIAlertAction(title: UIConstants.CancelString, style: UIAlertActionStyle.cancel) { _ in + self.cancel() + }) + alertController.alertInfo = self + return alertController + } + + func cancel() { + completionHandler(false) + } +} + +struct TextInputAlert: JSAlertInfo { + let message: String + let frame: WKFrameInfo + let completionHandler: (String?) -> Void + let defaultText: String? + + var input: UITextField! + + init(message: String, frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void, defaultText: String?) { + self.message = message + self.frame = frame + self.completionHandler = completionHandler + self.defaultText = defaultText + } + + func alertController() -> JSPromptAlertController { + let alertController = JSPromptAlertController(title: titleForJavaScriptPanelInitiatedByFrame(frame), message: message, preferredStyle: UIAlertControllerStyle.alert) + var input: UITextField! + alertController.addTextField(configurationHandler: { (textField: UITextField) in + input = textField + input.text = self.defaultText + }) + alertController.addAction(UIAlertAction(title: UIConstants.OKString, style: UIAlertActionStyle.default) { _ in + self.completionHandler(input.text) + }) + alertController.addAction(UIAlertAction(title: UIConstants.CancelString, style: UIAlertActionStyle.cancel) { _ in + self.cancel() + }) + alertController.alertInfo = self + return alertController + } + + func cancel() { + completionHandler(nil) + } +} + +/// Show a title for a JavaScript Panel (alert) based on the WKFrameInfo. On iOS9 we will use the new securityOrigin +/// and on iOS 8 we will fall back to the request URL. If the request URL is nil, which happens for JavaScript pages, +/// we fall back to "JavaScript" as a title. +private func titleForJavaScriptPanelInitiatedByFrame(_ frame: WKFrameInfo) -> String { + var title = "\(frame.securityOrigin.`protocol`)://\(frame.securityOrigin.host)" + if frame.securityOrigin.port != 0 { + title += ":\(frame.securityOrigin.port)" + } + return title +} diff --git a/mobile/ios/Client/Frontend/Browser/BrowserTrayAnimators.swift b/mobile/ios/Client/Frontend/Browser/BrowserTrayAnimators.swift new file mode 100644 index 0000000000..6c22a2228e --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/BrowserTrayAnimators.swift @@ -0,0 +1,322 @@ +/* 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/. */ + +import UIKit +import Shared + +class TrayToBrowserAnimator: NSObject, UIViewControllerAnimatedTransitioning { + func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + if let bvc = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as? BrowserViewController, + let tabTray = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as? TabTrayController { + transitionFromTray(tabTray, toBrowser: bvc, usingContext: transitionContext) + } + } + + func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return 0.4 + } +} + +private extension TrayToBrowserAnimator { + func transitionFromTray(_ tabTray: TabTrayController, toBrowser bvc: BrowserViewController, usingContext transitionContext: UIViewControllerContextTransitioning) { + let container = transitionContext.containerView + guard let selectedTab = bvc.tabManager.selectedTab else { return } + + let tabManager = bvc.tabManager + let displayedTabs = selectedTab.isPrivate ? tabManager.privateTabs : tabManager.normalTabs + guard let expandFromIndex = displayedTabs.index(of: selectedTab) else { return } + + bvc.view.frame = transitionContext.finalFrame(for: bvc) + + // Hide browser components + bvc.toggleSnackBarVisibility(show: false) + toggleWebViewVisibility(false, usingTabManager: bvc.tabManager) + bvc.homePanelController?.view.isHidden = true + bvc.webViewContainerBackdrop.isHidden = true + bvc.statusBarOverlay.isHidden = false + if let url = selectedTab.url, !url.isReaderModeURL { + bvc.hideReaderModeBar(animated: false) + } + + // Take a snapshot of the collection view that we can scale/fade out. We don't need to wait for screen updates since it's already rendered on the screen + let tabCollectionViewSnapshot = tabTray.collectionView.snapshotView(afterScreenUpdates: false)! + tabTray.collectionView.alpha = 0 + tabCollectionViewSnapshot.frame = tabTray.collectionView.frame + container.insertSubview(tabCollectionViewSnapshot, at: 0) + + // Create a fake cell to use for the upscaling animation + let startingFrame = calculateCollapsedCellFrameUsingCollectionView(tabTray.collectionView, atIndex: expandFromIndex) + let cell = createTransitionCellFromTab(bvc.tabManager.selectedTab, withFrame: startingFrame) + cell.backgroundHolder.layer.cornerRadius = 0 + + container.insertSubview(bvc.view, aboveSubview: tabCollectionViewSnapshot) + container.insertSubview(cell, aboveSubview: bvc.view) + + // Flush any pending layout/animation code in preperation of the animation call + container.layoutIfNeeded() + + let finalFrame = calculateExpandedCellFrameFromBVC(bvc) + bvc.footer.alpha = shouldDisplayFooterForBVC(bvc) ? 1 : 0 + bvc.urlBar.isTransitioning = true + + // Re-calculate the starting transforms for header/footer views in case we switch orientation + resetTransformsForViews([bvc.header, bvc.readerModeBar, bvc.footer]) + transformHeaderFooterForBVC(bvc, toFrame: startingFrame, container: container) + + UIView.animate(withDuration: self.transitionDuration(using: transitionContext), + delay: 0, usingSpringWithDamping: 1, + initialSpringVelocity: 0, + options: UIViewAnimationOptions(), + animations: { + // Scale up the cell and reset the transforms for the header/footers + cell.frame = finalFrame + container.layoutIfNeeded() + cell.title.transform = CGAffineTransform(translationX: 0, y: -cell.title.frame.height) + + bvc.tabTrayDidDismiss(tabTray) + UIApplication.shared.windows.first?.backgroundColor = UIConstants.AppBackgroundColor + tabTray.navigationController?.setNeedsStatusBarAppearanceUpdate() + tabTray.toolbar.transform = CGAffineTransform(translationX: 0, y: UIConstants.BottomToolbarHeight) + tabCollectionViewSnapshot.transform = CGAffineTransform(scaleX: 0.9, y: 0.9) + tabCollectionViewSnapshot.alpha = 0 + }, completion: { finished in + // Remove any of the views we used for the animation + cell.removeFromSuperview() + tabCollectionViewSnapshot.removeFromSuperview() + bvc.footer.alpha = 1 + bvc.toggleSnackBarVisibility(show: true) + toggleWebViewVisibility(true, usingTabManager: bvc.tabManager) + bvc.webViewContainerBackdrop.isHidden = false + bvc.homePanelController?.view.isHidden = false + bvc.urlBar.isTransitioning = false + transitionContext.completeTransition(true) + }) + } +} + +class BrowserToTrayAnimator: NSObject, UIViewControllerAnimatedTransitioning { + func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + if let bvc = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as? BrowserViewController, + let tabTray = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as? TabTrayController { + transitionFromBrowser(bvc, toTabTray: tabTray, usingContext: transitionContext) + } + } + + func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return 0.4 + } +} + +private extension BrowserToTrayAnimator { + func transitionFromBrowser(_ bvc: BrowserViewController, toTabTray tabTray: TabTrayController, usingContext transitionContext: UIViewControllerContextTransitioning) { + + let container = transitionContext.containerView + guard let selectedTab = bvc.tabManager.selectedTab else { return } + + let tabManager = bvc.tabManager + let displayedTabs = selectedTab.isPrivate ? tabManager.privateTabs : tabManager.normalTabs + guard let scrollToIndex = displayedTabs.index(of: selectedTab) else { return } + + tabTray.view.frame = transitionContext.finalFrame(for: tabTray) + + // Insert tab tray below the browser and force a layout so the collection view can get it's frame right + container.insertSubview(tabTray.view, belowSubview: bvc.view) + + // Force subview layout on the collection view so we can calculate the correct end frame for the animation + tabTray.view.layoutSubviews() + + tabTray.collectionView.scrollToItem(at: IndexPath(item: scrollToIndex, section: 0), at: .centeredVertically, animated: false) + + // Build a tab cell that we will use to animate the scaling of the browser to the tab + let expandedFrame = calculateExpandedCellFrameFromBVC(bvc) + let cell = createTransitionCellFromTab(bvc.tabManager.selectedTab, withFrame: expandedFrame) + cell.backgroundHolder.layer.cornerRadius = TabTrayControllerUX.CornerRadius + + // Take a snapshot of the collection view to perform the scaling/alpha effect + let tabCollectionViewSnapshot = tabTray.collectionView.snapshotView(afterScreenUpdates: true)! + tabCollectionViewSnapshot.frame = tabTray.collectionView.frame + tabCollectionViewSnapshot.transform = CGAffineTransform(scaleX: 0.9, y: 0.9) + tabCollectionViewSnapshot.alpha = 0 + tabTray.view.insertSubview(tabCollectionViewSnapshot, belowSubview: tabTray.toolbar) + + if let toast = bvc.clipboardBarDisplayHandler?.clipboardToast { + toast.removeFromSuperview() + } + + container.addSubview(cell) + cell.layoutIfNeeded() + cell.title.transform = CGAffineTransform(translationX: 0, y: -cell.title.frame.size.height) + + // Hide views we don't want to show during the animation in the BVC + bvc.homePanelController?.view.isHidden = true + bvc.statusBarOverlay.isHidden = true + bvc.toggleSnackBarVisibility(show: false) + toggleWebViewVisibility(false, usingTabManager: bvc.tabManager) + bvc.urlBar.isTransitioning = true + + // Since we are hiding the collection view and the snapshot API takes the snapshot after the next screen update, + // the screenshot ends up being blank unless we set the collection view hidden after the screen update happens. + // To work around this, we dispatch the setting of collection view to hidden after the screen update is completed. + + DispatchQueue.main.async { + tabTray.collectionView.isHidden = true + let finalFrame = calculateCollapsedCellFrameUsingCollectionView(tabTray.collectionView, + atIndex: scrollToIndex) + tabTray.toolbar.transform = CGAffineTransform(translationX: 0, y: UIConstants.BottomToolbarHeight) + + UIView.animate(withDuration: self.transitionDuration(using: transitionContext), + delay: 0, usingSpringWithDamping: 1, + initialSpringVelocity: 0, + options: UIViewAnimationOptions(), + animations: { + cell.frame = finalFrame + cell.title.transform = CGAffineTransform.identity + cell.layoutIfNeeded() + + UIApplication.shared.windows.first?.backgroundColor = TabTrayControllerUX.BackgroundColor + tabTray.navigationController?.setNeedsStatusBarAppearanceUpdate() + + transformHeaderFooterForBVC(bvc, toFrame: finalFrame, container: container) + + bvc.urlBar.updateAlphaForSubviews(0) + bvc.footer.alpha = 0 + tabCollectionViewSnapshot.alpha = 1 + + tabTray.toolbar.transform = CGAffineTransform.identity + resetTransformsForViews([tabCollectionViewSnapshot]) + }, completion: { finished in + // Remove any of the views we used for the animation + cell.removeFromSuperview() + tabCollectionViewSnapshot.removeFromSuperview() + tabTray.collectionView.isHidden = false + + bvc.toggleSnackBarVisibility(show: true) + toggleWebViewVisibility(true, usingTabManager: bvc.tabManager) + bvc.homePanelController?.view.isHidden = false + + bvc.urlBar.isTransitioning = false + transitionContext.completeTransition(true) + }) + } + } +} + +private func transformHeaderFooterForBVC(_ bvc: BrowserViewController, toFrame finalFrame: CGRect, container: UIView) { + let footerForTransform = footerTransform(bvc.footer.frame, toFrame: finalFrame, container: container) + let headerForTransform = headerTransform(bvc.header.frame, toFrame: finalFrame, container: container) + + bvc.footer.transform = footerForTransform + bvc.header.transform = headerForTransform + bvc.readerModeBar?.transform = headerForTransform +} + +private func footerTransform( _ frame: CGRect, toFrame finalFrame: CGRect, container: UIView) -> CGAffineTransform { + let frame = container.convert(frame, to: container) + let endY = finalFrame.maxY - (frame.size.height / 2) + let endX = finalFrame.midX + let translation = CGPoint(x: endX - frame.midX, y: endY - frame.midY) + + let scaleX = finalFrame.width / frame.width + + var transform = CGAffineTransform.identity + transform = transform.translatedBy(x: translation.x, y: translation.y) + transform = transform.scaledBy(x: scaleX, y: scaleX) + return transform +} + +private func headerTransform(_ frame: CGRect, toFrame finalFrame: CGRect, container: UIView) -> CGAffineTransform { + let frame = container.convert(frame, to: container) + let endY = finalFrame.minY + (frame.size.height / 2) + let endX = finalFrame.midX + let translation = CGPoint(x: endX - frame.midX, y: endY - frame.midY) + + let scaleX = finalFrame.width / frame.width + + var transform = CGAffineTransform.identity + transform = transform.translatedBy(x: translation.x, y: translation.y) + transform = transform.scaledBy(x: scaleX, y: scaleX) + return transform +} + +//MARK: Private Helper Methods +private func calculateCollapsedCellFrameUsingCollectionView(_ collectionView: UICollectionView, atIndex index: Int) -> CGRect { + if let attr = collectionView.collectionViewLayout.layoutAttributesForItem(at: IndexPath(item: index, section: 0)) { + return collectionView.convert(attr.frame, to: collectionView.superview) + } else { + return CGRect.zero + } +} + +private func calculateExpandedCellFrameFromBVC(_ bvc: BrowserViewController) -> CGRect { + var frame = bvc.webViewContainer.frame + + // If we're navigating to a home panel and we were expecting to show the toolbar, add more height to end frame since + // there is no toolbar for home panels + if !bvc.shouldShowFooterForTraitCollection(bvc.traitCollection) { + return frame + } else if let url = bvc.tabManager.selectedTab?.url, url.isAboutURL && bvc.toolbar == nil { + frame.size.height += UIConstants.BottomToolbarHeight + } + + return frame +} + +private func shouldDisplayFooterForBVC(_ bvc: BrowserViewController) -> Bool { + if bvc.shouldShowFooterForTraitCollection(bvc.traitCollection) { + if let url = bvc.tabManager.selectedTab?.url { + return !url.isAboutURL + } + } + return false +} + +private func toggleWebViewVisibility(_ show: Bool, usingTabManager tabManager: TabManager) { + for i in 0.. TabCell { + let cell = TabCell(frame: frame) + cell.screenshotView.image = tab?.screenshot + cell.titleText.text = tab?.displayTitle + + if let tab = tab, tab.isPrivate { + cell.style = .dark + } + + if let favIcon = tab?.displayFavicon { + cell.favicon.sd_setImage(with: URL(string: favIcon.url)!) + } else { + let defaultFavicon = UIImage(named: "defaultFavicon") + if tab?.isPrivate ?? false { + cell.favicon.image = defaultFavicon + cell.favicon.tintColor = (tab?.isPrivate ?? false) ? UIColor.white : UIColor.darkGray + } else { + cell.favicon.image = defaultFavicon + } + } + return cell +} diff --git a/mobile/ios/Client/Frontend/Browser/BrowserViewController.swift b/mobile/ios/Client/Frontend/Browser/BrowserViewController.swift new file mode 100644 index 0000000000..4f041003e2 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/BrowserViewController.swift @@ -0,0 +1,2986 @@ +/* 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/. */ + +import Foundation +import Photos +import UIKit +import WebKit +import Shared +import Storage +import SnapKit +import XCGLogger +import Alamofire +import Account +import ReadingList +import MobileCoreServices +import SDWebImage +import SwiftyJSON +import Telemetry +import Sentry + +private let KVOs: [KVOConstants] = [ + .estimatedProgress, + .loading, + .canGoBack, + .canGoForward, + .URL, + .title, +] + +private let ActionSheetTitleMaxLength = 120 + +private struct BrowserViewControllerUX { + fileprivate static let BackgroundColor = UIConstants.AppBackgroundColor + fileprivate static let ShowHeaderTapAreaHeight: CGFloat = 32 + fileprivate static let BookmarkStarAnimationDuration: Double = 0.5 + fileprivate static let BookmarkStarAnimationOffset: CGFloat = 80 +} + +class BrowserViewController: UIViewController { + var homePanelController: HomePanelViewController? + var webViewContainer: UIView! + var urlBar: URLBarView! + var clipboardBarDisplayHandler: ClipboardBarDisplayHandler? + var readerModeBar: ReaderModeBarView? + var readerModeCache: ReaderModeCache + let webViewContainerToolbar = UIView() + var statusBarOverlay: UIView! + fileprivate(set) var toolbar: TabToolbar? + fileprivate var searchController: SearchViewController? + fileprivate var screenshotHelper: ScreenshotHelper! + fileprivate var homePanelIsInline = false + fileprivate var searchLoader: SearchLoader? + fileprivate let snackBars = UIView() + fileprivate var findInPageBar: FindInPageBar? + fileprivate let findInPageContainer = UIView() + + lazy var mailtoLinkHandler: MailtoLinkHandler = MailtoLinkHandler() + + lazy fileprivate var customSearchEngineButton: UIButton = { + let searchButton = UIButton() + searchButton.setImage(UIImage(named: "AddSearch")?.withRenderingMode(.alwaysTemplate), for: UIControlState()) + searchButton.addTarget(self, action: #selector(BrowserViewController.addCustomSearchEngineForFocusedElement), for: .touchUpInside) + searchButton.accessibilityIdentifier = "BrowserViewController.customSearchEngineButton" + return searchButton + }() + + fileprivate var customSearchBarButton: UIBarButtonItem? + + // popover rotation handling + fileprivate var displayedPopoverController: UIViewController? + fileprivate var updateDisplayedPopoverProperties: (() -> Void)? + + var openInHelper: OpenInHelper? + + // location label actions + fileprivate var pasteGoAction: AccessibleAction! + fileprivate var pasteAction: AccessibleAction! + fileprivate var copyAddressAction: AccessibleAction! + + fileprivate weak var tabTrayController: TabTrayController! + let profile: Profile + let tabManager: TabManager + + // These views wrap the urlbar and toolbar to provide background effects on them + var header: UIView! + var footer: UIView! + fileprivate var topTouchArea: UIButton! + let urlBarTopTabsContainer = UIView(frame: CGRect.zero) + var topTabsVisible: Bool { + return topTabsViewController != nil + } + // Backdrop used for displaying greyed background for private tabs + var webViewContainerBackdrop: UIView! + + var scrollController = TabScrollingController() + + fileprivate var keyboardState: KeyboardState? + + var didRemoveAllTabs: Bool = false + var pendingToast: ButtonToast? // A toast that might be waiting for BVC to appear before displaying + + let WhiteListedUrls = ["\\/\\/itunes\\.apple\\.com\\/"] + + // Tracking navigation items to record history types. + // TODO: weak references? + var ignoredNavigation = Set() + var typedNavigation = [WKNavigation: VisitType]() + var navigationToolbar: TabToolbarProtocol { + return toolbar ?? urlBar + } + + var topTabsViewController: TopTabsViewController? + let topTabsContainer = UIView(frame: CGRect.zero) + + init(profile: Profile, tabManager: TabManager) { + self.profile = profile + self.tabManager = tabManager + self.readerModeCache = DiskReaderModeCache.sharedInstance + super.init(nibName: nil, bundle: nil) + didInit() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + if UIDevice.current.userInterfaceIdiom == .phone { + return UIInterfaceOrientationMask.allButUpsideDown + } else { + return UIInterfaceOrientationMask.all + } + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + + displayedPopoverController?.dismiss(animated: true) { + self.displayedPopoverController = nil + } + + if let _ = self.presentedViewController as? PhotonActionSheet { + self.presentedViewController?.dismiss(animated: true, completion: nil) + } + + coordinator.animate(alongsideTransition: { context in + self.scrollController.updateMinimumZoom() + self.topTabsViewController?.scrollToCurrentTab(false, centerCell: false) + if let popover = self.displayedPopoverController { + self.updateDisplayedPopoverProperties?() + self.present(popover, animated: true, completion: nil) + } + }, completion: { _ in + self.scrollController.setMinimumZoom() + }) + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + } + + fileprivate func didInit() { + screenshotHelper = ScreenshotHelper(controller: self) + tabManager.addDelegate(self) + tabManager.addNavigationDelegate(self) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + let isPrivate = tabManager.selectedTab?.isPrivate ?? false + let isIpad = shouldShowTopTabsForTraitCollection(traitCollection) + return (isPrivate || isIpad) ? UIStatusBarStyle.lightContent : UIStatusBarStyle.default + } + + func shouldShowFooterForTraitCollection(_ previousTraitCollection: UITraitCollection) -> Bool { + return previousTraitCollection.verticalSizeClass != .compact && previousTraitCollection.horizontalSizeClass != .regular + } + + func shouldShowTopTabsForTraitCollection(_ newTraitCollection: UITraitCollection) -> Bool { + return newTraitCollection.verticalSizeClass == .regular && newTraitCollection.horizontalSizeClass == .regular + } + + func toggleSnackBarVisibility(show: Bool) { + if show { + UIView.animate(withDuration: 0.1, animations: { self.snackBars.isHidden = false }) + } else { + snackBars.isHidden = true + } + } + + fileprivate func updateToolbarStateForTraitCollection(_ newCollection: UITraitCollection, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator? = nil) { + let showToolbar = shouldShowFooterForTraitCollection(newCollection) + let showTopTabs = shouldShowTopTabsForTraitCollection(newCollection) + + urlBar.topTabsIsShowing = showTopTabs + urlBar.setShowToolbar(!showToolbar) + toolbar?.removeFromSuperview() + toolbar?.tabToolbarDelegate = nil + toolbar = nil + + if showToolbar { + toolbar = TabToolbar() + footer.addSubview(toolbar!) + toolbar?.tabToolbarDelegate = self + let theme = (tabManager.selectedTab?.isPrivate ?? false) ? Theme.PrivateMode : Theme.NormalMode + toolbar?.applyTheme(theme) + updateTabCountUsingTabManager(self.tabManager) + } + + if showTopTabs { + if topTabsViewController == nil { + let topTabsViewController = TopTabsViewController(tabManager: tabManager) + topTabsViewController.delegate = self + addChildViewController(topTabsViewController) + topTabsViewController.view.frame = topTabsContainer.frame + topTabsContainer.addSubview(topTabsViewController.view) + topTabsViewController.view.snp.makeConstraints { make in + make.edges.equalTo(topTabsContainer) + make.height.equalTo(TopTabsUX.TopTabsViewHeight) + } + self.topTabsViewController = topTabsViewController + } + topTabsContainer.snp.updateConstraints { make in + make.height.equalTo(TopTabsUX.TopTabsViewHeight) + } + } else { + topTabsContainer.snp.updateConstraints { make in + make.height.equalTo(0) + } + topTabsViewController?.view.removeFromSuperview() + topTabsViewController?.removeFromParentViewController() + topTabsViewController = nil + } + + view.setNeedsUpdateConstraints() + if let home = homePanelController { + home.view.setNeedsUpdateConstraints() + } + + if let tab = tabManager.selectedTab, + let webView = tab.webView { + updateURLBarDisplayURL(tab) + navigationToolbar.updateBackStatus(webView.canGoBack) + navigationToolbar.updateForwardStatus(webView.canGoForward) + navigationToolbar.updateReloadStatus(tab.loading) + } + } + + override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { + super.willTransition(to: newCollection, with: coordinator) + + // During split screen launching on iPad, this callback gets fired before viewDidLoad gets a chance to + // set things up. Make sure to only update the toolbar state if the view is ready for it. + if isViewLoaded { + updateToolbarStateForTraitCollection(newCollection, withTransitionCoordinator: coordinator) + } + + displayedPopoverController?.dismiss(animated: true, completion: nil) + coordinator.animate(alongsideTransition: { context in + self.scrollController.showToolbars(animated: false) + if self.isViewLoaded { + self.statusBarOverlay.backgroundColor = self.shouldShowTopTabsForTraitCollection(self.traitCollection) ? UIColor(rgb: 0x272727) : self.urlBar.backgroundColor + self.setNeedsStatusBarAppearanceUpdate() + } + }, completion: nil) + } + + func SELappDidEnterBackgroundNotification() { + displayedPopoverController?.dismiss(animated: false) { + self.displayedPopoverController = nil + } + } + + func SELtappedTopArea() { + scrollController.showToolbars(animated: true) + } + + func SELappWillResignActiveNotification() { + // Dismiss any popovers that might be visible + displayedPopoverController?.dismiss(animated: false) { + self.displayedPopoverController = nil + } + + // If we are displying a private tab, hide any elements in the tab that we wouldn't want shown + // when the app is in the home switcher + guard let privateTab = tabManager.selectedTab, privateTab.isPrivate else { + return + } + + webViewContainerBackdrop.alpha = 1 + webViewContainer.alpha = 0 + urlBar.locationContainer.alpha = 0 + topTabsViewController?.switchForegroundStatus(isInForeground: false) + presentedViewController?.popoverPresentationController?.containerView?.alpha = 0 + presentedViewController?.view.alpha = 0 + } + + func SELappDidBecomeActiveNotification() { + // Re-show any components that might have been hidden because they were being displayed + // as part of a private mode tab + UIView.animate(withDuration: 0.2, delay: 0, options: UIViewAnimationOptions(), animations: { + self.webViewContainer.alpha = 1 + self.urlBar.locationContainer.alpha = 1 + self.topTabsViewController?.switchForegroundStatus(isInForeground: true) + self.presentedViewController?.popoverPresentationController?.containerView?.alpha = 1 + self.presentedViewController?.view.alpha = 1 + self.view.backgroundColor = UIColor.clear + }, completion: { _ in + self.webViewContainerBackdrop.alpha = 0 + }) + + // Re-show toolbar which might have been hidden during scrolling (prior to app moving into the background) + scrollController.showToolbars(animated: false) + } + + override func viewDidLoad() { + super.viewDidLoad() + NotificationCenter.default.addObserver(self, selector: #selector(BrowserViewController.SELBookmarkStatusDidChange(_:)), name: NSNotification.Name(rawValue: BookmarkStatusChangedNotification), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(BrowserViewController.SELappWillResignActiveNotification), name: NSNotification.Name.UIApplicationWillResignActive, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(BrowserViewController.SELappDidBecomeActiveNotification), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(BrowserViewController.SELappDidEnterBackgroundNotification), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) + KeyboardHelper.defaultHelper.addDelegate(self) + + webViewContainerBackdrop = UIView() + webViewContainerBackdrop.backgroundColor = UIColor.gray + webViewContainerBackdrop.alpha = 0 + view.addSubview(webViewContainerBackdrop) + + webViewContainer = UIView() + webViewContainer.addSubview(webViewContainerToolbar) + view.addSubview(webViewContainer) + + // Temporary work around for covering the non-clipped web view content + statusBarOverlay = UIView() + view.addSubview(statusBarOverlay) + + topTouchArea = UIButton() + topTouchArea.isAccessibilityElement = false + topTouchArea.addTarget(self, action: #selector(BrowserViewController.SELtappedTopArea), for: UIControlEvents.touchUpInside) + view.addSubview(topTouchArea) + + // Setup the URL bar, wrapped in a view to get transparency effect + urlBar = URLBarView() + urlBar.translatesAutoresizingMaskIntoConstraints = false + urlBar.delegate = self + urlBar.tabToolbarDelegate = self + header = urlBarTopTabsContainer + urlBarTopTabsContainer.addSubview(urlBar) + urlBarTopTabsContainer.addSubview(topTabsContainer) + view.addSubview(header) + + // UIAccessibilityCustomAction subclass holding an AccessibleAction instance does not work, thus unable to generate AccessibleActions and UIAccessibilityCustomActions "on-demand" and need to make them "persistent" e.g. by being stored in BVC + pasteGoAction = AccessibleAction(name: NSLocalizedString("Paste & Go", comment: "Paste the URL into the location bar and visit"), handler: { () -> Bool in + if let pasteboardContents = UIPasteboard.general.string { + self.urlBar(self.urlBar, didSubmitText: pasteboardContents) + return true + } + return false + }) + pasteAction = AccessibleAction(name: NSLocalizedString("Paste", comment: "Paste the URL into the location bar"), handler: { () -> Bool in + if let pasteboardContents = UIPasteboard.general.string { + // Enter overlay mode and make the search controller appear. + self.urlBar.enterOverlayMode(pasteboardContents, pasted: true, search: true) + + return true + } + return false + }) + copyAddressAction = AccessibleAction(name: NSLocalizedString("Copy Address", comment: "Copy the URL from the location bar"), handler: { () -> Bool in + if let url = self.urlBar.currentURL { + UIPasteboard.general.url = url as URL + } + return true + }) + + searchLoader = SearchLoader(profile: profile, urlBar: urlBar) + + footer = UIView() + self.view.addSubview(footer) + self.view.addSubview(snackBars) + snackBars.backgroundColor = UIColor.clear + self.view.addSubview(findInPageContainer) + + if AppConstants.MOZ_CLIPBOARD_BAR { + clipboardBarDisplayHandler = ClipboardBarDisplayHandler(prefs: profile.prefs, tabManager: tabManager) + clipboardBarDisplayHandler?.delegate = self + } + + scrollController.urlBar = urlBar + scrollController.header = header + scrollController.footer = footer + scrollController.snackBars = snackBars + scrollController.webViewContainerToolbar = webViewContainerToolbar + + self.updateToolbarStateForTraitCollection(self.traitCollection) + + setupConstraints() + } + + fileprivate func setupConstraints() { + topTabsContainer.snp.makeConstraints { make in + make.leading.trailing.equalTo(self.header) + make.top.equalTo(urlBarTopTabsContainer) + } + + urlBar.snp.makeConstraints { make in + make.leading.trailing.bottom.equalTo(urlBarTopTabsContainer) + make.height.equalTo(UIConstants.TopToolbarHeight) + make.top.equalTo(topTabsContainer.snp.bottom) + } + + header.snp.makeConstraints { make in + scrollController.headerTopConstraint = make.top.equalTo(self.topLayoutGuide.snp.bottom).constraint + make.left.right.equalTo(self.view) + } + + webViewContainerBackdrop.snp.makeConstraints { make in + make.edges.equalTo(webViewContainer) + } + + webViewContainerToolbar.snp.makeConstraints { make in + make.left.right.top.equalTo(webViewContainer) + make.height.equalTo(0) + } + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + statusBarOverlay.snp.remakeConstraints { make in + make.top.left.right.equalTo(self.view) + make.height.equalTo(self.topLayoutGuide.length) + } + } + + override var canBecomeFirstResponder: Bool { + return true + } + + override func becomeFirstResponder() -> Bool { + // Make the web view the first responder so that it can show the selection menu. + return tabManager.selectedTab?.webView?.becomeFirstResponder() ?? false + } + + func loadQueuedTabs(receivedURLs: [URL]? = nil) { + // Chain off of a trivial deferred in order to run on the background queue. + succeed().upon() { res in + self.dequeueQueuedTabs(receivedURLs: receivedURLs ?? []) + } + } + + fileprivate func dequeueQueuedTabs(receivedURLs: [URL]) { + assert(!Thread.current.isMainThread, "This must be called in the background.") + self.profile.queue.getQueuedTabs() >>== { cursor in + + // This assumes that the DB returns rows in some kind of sane order. + // It does in practice, so WFM. + if cursor.count > 0 { + + // Filter out any tabs received by a push notification to prevent dupes. + let urls = cursor.flatMap { $0?.url.asURL }.filter { !receivedURLs.contains($0) } + if !urls.isEmpty { + DispatchQueue.main.async { + self.tabManager.addTabsForURLs(urls, zombie: false) + } + } + + // Clear *after* making an attempt to open. We're making a bet that + // it's better to run the risk of perhaps opening twice on a crash, + // rather than losing data. + self.profile.queue.clearQueuedTabs() + } + + // Then, open any received URLs from push notifications. + if !receivedURLs.isEmpty { + DispatchQueue.main.async { + let unopenedReceivedURLs = receivedURLs.filter { self.tabManager.getTabForURL($0) == nil } + + self.tabManager.addTabsForURLs(unopenedReceivedURLs, zombie: false) + + if let lastURL = receivedURLs.last, let tab = self.tabManager.getTabForURL(lastURL) { + self.tabManager.selectTab(tab) + } + } + } + } + } + + // Because crashedLastLaunch is sticky, it does not get reset, we need to remember its + // value so that we do not keep asking the user to restore their tabs. + var displayedRestoreTabsAlert = false + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + // On iPhone, if we are about to show the On-Boarding, blank out the tab so that it does + // not flash before we present. This change of alpha also participates in the animation when + // the intro view is dismissed. + if UIDevice.current.userInterfaceIdiom == .phone { + self.view.alpha = (profile.prefs.intForKey(IntroViewControllerSeenProfileKey) != nil) ? 1.0 : 0.0 + } + + if !displayedRestoreTabsAlert && !cleanlyBackgrounded() && crashedLastLaunch() { + displayedRestoreTabsAlert = true + showRestoreTabsAlert() + } else { + tabManager.restoreTabs() + } + + updateTabCountUsingTabManager(tabManager, animated: false) + clipboardBarDisplayHandler?.checkIfShouldDisplayBar() + } + + fileprivate func crashedLastLaunch() -> Bool { + return Sentry.crashedLastLaunch + } + + fileprivate func cleanlyBackgrounded() -> Bool { + guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { + return false + } + return appDelegate.applicationCleanlyBackgrounded + } + + fileprivate func showRestoreTabsAlert() { + if !canRestoreTabs() { + self.tabManager.addTabAndSelect() + return + } + + let alert = UIAlertController.restoreTabsAlert( + okayCallback: { _ in + self.tabManager.restoreTabs() + self.updateTabCountUsingTabManager(self.tabManager, animated: false) + }, + noCallback: { _ in + self.tabManager.addTabAndSelect() + self.updateTabCountUsingTabManager(self.tabManager, animated: false) + } + ) + + self.present(alert, animated: true, completion: nil) + } + + fileprivate func canRestoreTabs() -> Bool { + guard let tabsToRestore = TabManager.tabsToRestore() else { return false } + return tabsToRestore.count > 0 + } + + override func viewDidAppear(_ animated: Bool) { + presentIntroViewController() + self.webViewContainerToolbar.isHidden = false + + screenshotHelper.viewIsVisible = true + screenshotHelper.takePendingScreenshots(tabManager.tabs) + + super.viewDidAppear(animated) + + if shouldShowWhatsNewTab() { + // Only display if the SUMO topic has been configured in the Info.plist (present and not empty) + if let whatsNewTopic = AppInfo.whatsNewTopic, whatsNewTopic != "" { + if let whatsNewURL = SupportUtils.URLForTopic(whatsNewTopic) { + self.openURLInNewTab(whatsNewURL, isPrivileged: false) + profile.prefs.setString(AppInfo.appVersion, forKey: LatestAppVersionProfileKey) + } + } + } + + if let toast = self.pendingToast { + self.pendingToast = nil + show(buttonToast: toast, afterWaiting: ButtonToastUX.ToastDelay) + } + showQueuedAlertIfAvailable() + } + + // THe logic for shouldShowWhatsNewTab is as follows: If we do not have the LatestAppVersionProfileKey in + // the profile, that means that this is a fresh install and we do not show the What's New. If we do have + // that value, we compare it to the major version of the running app. If it is different then this is an + // upgrade, downgrades are not possible, so we can show the What's New page. + + fileprivate func shouldShowWhatsNewTab() -> Bool { + guard let latestMajorAppVersion = profile.prefs.stringForKey(LatestAppVersionProfileKey)?.components(separatedBy: ".").first else { + return false // Clean install, never show What's New + } + + return latestMajorAppVersion != AppInfo.majorAppVersion && DeviceInfo.hasConnectivity() + } + + fileprivate func showQueuedAlertIfAvailable() { + if let queuedAlertInfo = tabManager.selectedTab?.dequeueJavascriptAlertPrompt() { + let alertController = queuedAlertInfo.alertController() + alertController.delegate = self + present(alertController, animated: true, completion: nil) + } + } + + override func viewWillDisappear(_ animated: Bool) { + screenshotHelper.viewIsVisible = false + super.viewWillDisappear(animated) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + } + + func resetBrowserChrome() { + // animate and reset transform for tab chrome + urlBar.updateAlphaForSubviews(1) + footer.alpha = 1 + + [header, footer, readerModeBar].forEach { view in + view?.transform = CGAffineTransform.identity + } + statusBarOverlay.isHidden = false + } + + override func updateViewConstraints() { + super.updateViewConstraints() + + topTouchArea.snp.remakeConstraints { make in + make.top.left.right.equalTo(self.view) + make.height.equalTo(BrowserViewControllerUX.ShowHeaderTapAreaHeight) + } + + readerModeBar?.snp.remakeConstraints { make in + make.top.equalTo(self.header.snp.bottom) + make.height.equalTo(UIConstants.ToolbarHeight) + make.leading.trailing.equalTo(self.view) + } + + webViewContainer.snp.remakeConstraints { make in + make.left.right.equalTo(self.view) + + if let readerModeBarBottom = readerModeBar?.snp.bottom { + make.top.equalTo(readerModeBarBottom) + } else { + make.top.equalTo(self.header.snp.bottom) + } + + let findInPageHeight = (findInPageBar == nil) ? 0 : UIConstants.ToolbarHeight + if let toolbar = self.toolbar { + make.bottom.equalTo(toolbar.snp.top).offset(-findInPageHeight) + } else { + make.bottom.equalTo(self.view).offset(-findInPageHeight) + } + } + + // Setup the bottom toolbar + toolbar?.snp.remakeConstraints { make in + make.edges.equalTo(self.footer) + make.height.equalTo(UIConstants.BottomToolbarHeight) + } + + footer.snp.remakeConstraints { make in + scrollController.footerBottomConstraint = make.bottom.equalTo(self.view.snp.bottom).constraint + make.leading.trailing.equalTo(self.view) + } + + updateSnackBarConstraints() + urlBar.setNeedsUpdateConstraints() + + // Remake constraints even if we're already showing the home controller. + // The home controller may change sizes if we tap the URL bar while on about:home. + homePanelController?.view.snp.remakeConstraints { make in + make.top.equalTo(self.urlBar.snp.bottom) + make.left.right.equalTo(self.view) + if self.homePanelIsInline { + make.bottom.equalTo(self.toolbar?.snp.top ?? self.view.snp.bottom) + } else { + make.bottom.equalTo(self.view.snp.bottom) + } + } + + findInPageContainer.snp.remakeConstraints { make in + make.left.right.equalTo(self.view) + + if let keyboardHeight = keyboardState?.intersectionHeightForView(self.view), keyboardHeight > 0 { + make.bottom.equalTo(self.view).offset(-keyboardHeight) + } else if let toolbar = self.toolbar { + make.bottom.equalTo(toolbar.snp.top) + } else { + make.bottom.equalTo(self.view) + } + } + } + + fileprivate func showHomePanelController(inline: Bool) { + homePanelIsInline = inline + + if homePanelController == nil { + let homePanelController = HomePanelViewController() + homePanelController.profile = profile + homePanelController.delegate = self + homePanelController.url = tabManager.selectedTab?.url?.displayURL + homePanelController.view.alpha = 0 + self.homePanelController = homePanelController + + addChildViewController(homePanelController) + view.addSubview(homePanelController.view) + homePanelController.didMove(toParentViewController: self) + } + guard let homePanelController = self.homePanelController else { + assertionFailure("homePanelController is still nil after assignment.") + return + } + let isPrivate = tabManager.selectedTab?.isPrivate ?? false + homePanelController.applyTheme(isPrivate ? Theme.PrivateMode : Theme.NormalMode) + let panelNumber = tabManager.selectedTab?.url?.fragment + + // splitting this out to see if we can get better crash reports when this has a problem + var newSelectedButtonIndex = 0 + if let numberArray = panelNumber?.components(separatedBy: "=") { + if let last = numberArray.last, let lastInt = Int(last) { + newSelectedButtonIndex = lastInt + } + } + homePanelController.selectedPanel = HomePanelType(rawValue: newSelectedButtonIndex) + + // We have to run this animation, even if the view is already showing because there may be a hide animation running + // and we want to be sure to override its results. + UIView.animate(withDuration: 0.2, animations: { () -> Void in + homePanelController.view.alpha = 1 + }, completion: { finished in + if finished { + self.webViewContainer.accessibilityElementsHidden = true + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil) + } + }) + view.setNeedsUpdateConstraints() + } + + fileprivate func hideHomePanelController() { + if let controller = homePanelController { + self.homePanelController = nil + UIView.animate(withDuration: 0.2, delay: 0, options: .beginFromCurrentState, animations: { () -> Void in + controller.view.alpha = 0 + }, completion: { _ in + controller.willMove(toParentViewController: nil) + controller.view.removeFromSuperview() + controller.removeFromParentViewController() + self.webViewContainer.accessibilityElementsHidden = false + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil) + + // Refresh the reading view toolbar since the article record may have changed + if let readerMode = self.tabManager.selectedTab?.getContentScript(name: ReaderMode.name()) as? ReaderMode, readerMode.state == .active { + self.showReaderModeBar(animated: false) + } + }) + } + } + + fileprivate func updateInContentHomePanel(_ url: URL?) { + if !urlBar.inOverlayMode { + guard let url = url else { + hideHomePanelController() + return + } + if url.isAboutHomeURL { + showHomePanelController(inline: true) + } else if !url.isLocalUtility || url.isReaderModeURL { + hideHomePanelController() + } + } + } + + fileprivate func showSearchController() { + if searchController != nil { + return + } + + let isPrivate = tabManager.selectedTab?.isPrivate ?? false + searchController = SearchViewController(isPrivate: isPrivate) + searchController!.searchEngines = profile.searchEngines + searchController!.searchDelegate = self + searchController!.profile = self.profile + + searchLoader = SearchLoader(profile: profile, urlBar: urlBar) + searchLoader?.addListener(searchController!) + + addChildViewController(searchController!) + view.addSubview(searchController!.view) + searchController!.view.snp.makeConstraints { make in + make.top.equalTo(self.urlBar.snp.bottom) + make.left.right.bottom.equalTo(self.view) + return + } + + homePanelController?.view?.isHidden = true + + searchController!.didMove(toParentViewController: self) + } + + fileprivate func hideSearchController() { + if let searchController = searchController { + searchController.willMove(toParentViewController: nil) + searchController.view.removeFromSuperview() + searchController.removeFromParentViewController() + self.searchController = nil + homePanelController?.view?.isHidden = false + searchLoader = nil + } + } + + fileprivate func finishEditingAndSubmit(_ url: URL, visitType: VisitType) { + urlBar.currentURL = url + urlBar.leaveOverlayMode() + + guard let tab = tabManager.selectedTab else { + return + } + + if let webView = tab.webView { + resetSpoofedUserAgentIfRequired(webView, newURL: url) + } + + if let nav = tab.loadRequest(PrivilegedRequest(url: url) as URLRequest) { + self.recordNavigationInTab(tab, navigation: nav, visitType: visitType) + } + } + + func addBookmark(_ tabState: TabState) { + guard let url = tabState.url else { return } + let absoluteString = url.absoluteString + let shareItem = ShareItem(url: absoluteString, title: tabState.title, favicon: tabState.favicon) + _ = profile.bookmarks.shareItem(shareItem) + var userData = [QuickActions.TabURLKey: shareItem.url] + if let title = shareItem.title { + userData[QuickActions.TabTitleKey] = title + } + QuickActions.sharedInstance.addDynamicApplicationShortcutItemOfType(.openLastBookmark, + withUserData: userData, + toApplication: UIApplication.shared) + if let tab = tabManager.getTabForURL(url) { + tab.isBookmarked = true + } + } + + func SELBookmarkStatusDidChange(_ notification: Notification) { + if let bookmark = notification.object as? BookmarkItem { + if bookmark.url == urlBar.currentURL?.absoluteString { + if let userInfo = notification.userInfo as? Dictionary { + if userInfo["added"] != nil { + if let tab = self.tabManager.getTabForURL(urlBar.currentURL!) { + tab.isBookmarked = false + } + } + } + } + } + } + + override func accessibilityPerformEscape() -> Bool { + if urlBar.inOverlayMode { + urlBar.SELdidClickCancel() + return true + } else if let selectedTab = tabManager.selectedTab, selectedTab.canGoBack { + selectedTab.goBack() + return true + } + return false + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { + let webView = object as! WKWebView + guard let kp = keyPath, let path = KVOConstants(rawValue: kp) else { + assertionFailure("Unhandled KVO key: \(keyPath ?? "nil")") + return + } + + switch path { + case .estimatedProgress: + guard webView == tabManager.selectedTab?.webView, + let progress = change?[NSKeyValueChangeKey.newKey] as? Float else { break } + if !(webView.url?.isLocalUtility ?? false) { + urlBar.updateProgressBar(progress) + } else { + urlBar.hideProgressBar() + } + case .loading: + guard let loading = change?[NSKeyValueChangeKey.newKey] as? Bool else { break } + + if webView == tabManager.selectedTab?.webView { + navigationToolbar.updateReloadStatus(loading) + } + + if !loading { + runScriptsOnWebView(webView) + } + case .URL: + guard let tab = tabManager[webView] else { break } + + // To prevent spoofing, only change the URL immediately if the new URL is on + // the same origin as the current URL. Otherwise, do nothing and wait for + // didCommitNavigation to confirm the page load. + if tab.url?.origin == webView.url?.origin { + tab.url = webView.url + + if tab === tabManager.selectedTab && !tab.restoring { + updateUIForReaderHomeStateForTab(tab) + } + } + case .title: + guard let tab = tabManager[webView] else { break } + + // Ensure that the tab title *actually* changed to prevent repeated calls + // to navigateInTab(tab:). + guard let title = tab.title else { break } + if !title.isEmpty && title != tab.lastTitle { + navigateInTab(tab: tab) + } + case .canGoBack: + guard webView == tabManager.selectedTab?.webView, + let canGoBack = change?[NSKeyValueChangeKey.newKey] as? Bool else { break } + + navigationToolbar.updateBackStatus(canGoBack) + case .canGoForward: + guard webView == tabManager.selectedTab?.webView, + let canGoForward = change?[NSKeyValueChangeKey.newKey] as? Bool else { break } + + navigationToolbar.updateForwardStatus(canGoForward) + default: + assertionFailure("Unhandled KVO key: \(keyPath ?? "nil")") + } + } + + fileprivate func runScriptsOnWebView(_ webView: WKWebView) { + guard let url = webView.url, url.isWebPage(), !url.isLocal else { + return + } + webView.evaluateJavaScript("__firefox__.favicons.getFavicons()", completionHandler: nil) + webView.evaluateJavaScript("__firefox__.metadata.extractMetadata()", completionHandler: nil) + + if #available(iOS 11, *) { + if NoImageModeHelper.isActivated(profile.prefs) { + webView.evaluateJavaScript("__firefox__.NoImageMode.setEnabled(true)", completionHandler: nil) + } + } + } + + func updateUIForReaderHomeStateForTab(_ tab: Tab) { + updateURLBarDisplayURL(tab) + scrollController.showToolbars(animated: false) + + if let url = tab.url { + if url.isReaderModeURL { + showReaderModeBar(animated: false) + NotificationCenter.default.addObserver(self, selector: #selector(BrowserViewController.SELDynamicFontChanged(_:)), name: NotificationDynamicFontChanged, object: nil) + } else { + hideReaderModeBar(animated: false) + NotificationCenter.default.removeObserver(self, name: NotificationDynamicFontChanged, object: nil) + } + + updateInContentHomePanel(url as URL) + } + } + + fileprivate func isWhitelistedUrl(_ url: URL) -> Bool { + for entry in WhiteListedUrls { + if let _ = url.absoluteString.range(of: entry, options: .regularExpression) { + return UIApplication.shared.canOpenURL(url) + } + } + return false + } + + /// Updates the URL bar text and button states. + /// Call this whenever the page URL changes. + fileprivate func updateURLBarDisplayURL(_ tab: Tab) { + urlBar.currentURL = tab.url?.displayURL + + let isPage = tab.url?.displayURL?.isWebPage() ?? false + navigationToolbar.updatePageStatus(isPage) + + guard let url = tab.url?.displayURL?.absoluteString else { + return + } + + profile.bookmarks.modelFactory >>== { + $0.isBookmarked(url).uponQueue(DispatchQueue.main) { [weak tab] result in + guard let bookmarked = result.successValue else { + print("Error getting bookmark status: \(result.failureValue ??? "nil").") + return + } + tab?.isBookmarked = bookmarked + } + } + } + + // MARK: Opening New Tabs + + func switchToPrivacyMode(isPrivate: Bool ) { +// applyTheme(isPrivate ? Theme.PrivateMode : Theme.NormalMode) + + let tabTrayController = self.tabTrayController ?? TabTrayController(tabManager: tabManager, profile: profile, tabTrayDelegate: self) + if tabTrayController.privateMode != isPrivate { + tabTrayController.changePrivacyMode(isPrivate) + } + self.tabTrayController = tabTrayController + } + + func switchToTabForURLOrOpen(_ url: URL, isPrivate: Bool = false, isPrivileged: Bool) { + popToBVC() + if let tab = tabManager.getTabForURL(url) { + tabManager.selectTab(tab) + } else { + openURLInNewTab(url, isPrivate: isPrivate, isPrivileged: isPrivileged) + } + } + + func openURLInNewTab(_ url: URL?, isPrivate: Bool = false, isPrivileged: Bool) { + if let selectedTab = tabManager.selectedTab { + screenshotHelper.takeScreenshot(selectedTab) + } + let request: URLRequest? + if let url = url { + request = isPrivileged ? PrivilegedRequest(url: url) as URLRequest : URLRequest(url: url) + } else { + request = nil + } + + switchToPrivacyMode(isPrivate: isPrivate) + _ = tabManager.addTabAndSelect(request, isPrivate: isPrivate) + if url == nil && NewTabAccessors.getNewTabPage(profile.prefs) == .blankPage { + urlBar.tabLocationViewDidTapLocation(urlBar.locationView) + } + } + + func openBlankNewTab(focusLocationField: Bool, isPrivate: Bool = false) { + popToBVC() + openURLInNewTab(nil, isPrivate: isPrivate, isPrivileged: true) + + if focusLocationField { + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) { + // Without a delay, the text field fails to become first responder + self.urlBar.tabLocationViewDidTapLocation(self.urlBar.locationView) + } + } + } + + fileprivate func popToBVC() { + guard let currentViewController = navigationController?.topViewController else { + return + } + currentViewController.dismiss(animated: true, completion: nil) + if currentViewController != self { + _ = self.navigationController?.popViewController(animated: true) + } else if urlBar.inOverlayMode { + urlBar.SELdidClickCancel() + } + } + + // MARK: User Agent Spoofing + + func resetSpoofedUserAgentIfRequired(_ webView: WKWebView, newURL: URL) { + // Reset the UA when a different domain is being loaded + if webView.url?.host != newURL.host { + webView.customUserAgent = nil + } + } + + func restoreSpoofedUserAgentIfRequired(_ webView: WKWebView, newRequest: URLRequest) { + // Restore any non-default UA from the request's header + let ua = newRequest.value(forHTTPHeaderField: "User-Agent") + webView.customUserAgent = ua != UserAgent.defaultUserAgent() ? ua : nil + } + + fileprivate func presentActivityViewController(_ url: URL, tab: Tab? = nil, sourceView: UIView?, sourceRect: CGRect, arrowDirection: UIPopoverArrowDirection) { + let helper = ShareExtensionHelper(url: url, tab: tab) + + let controller = helper.createActivityViewController({ [unowned self] completed, _ in + // After dismissing, check to see if there were any prompts we queued up + self.showQueuedAlertIfAvailable() + + // Usually the popover delegate would handle nil'ing out the references we have to it + // on the BVC when displaying as a popover but the delegate method doesn't seem to be + // invoked on iOS 10. See Bug 1297768 for additional details. + self.displayedPopoverController = nil + self.updateDisplayedPopoverProperties = nil + }) + + if let popoverPresentationController = controller.popoverPresentationController { + popoverPresentationController.sourceView = sourceView + popoverPresentationController.sourceRect = sourceRect + popoverPresentationController.permittedArrowDirections = arrowDirection + popoverPresentationController.delegate = self + } + + present(controller, animated: true, completion: nil) + LeanPlumClient.shared.track(event: .userSharedWebpage) + } + + func updateFindInPageVisibility(visible: Bool) { + if visible { + if findInPageBar == nil { + let findInPageBar = FindInPageBar() + self.findInPageBar = findInPageBar + findInPageBar.delegate = self + findInPageContainer.addSubview(findInPageBar) + + findInPageBar.snp.makeConstraints { make in + make.edges.equalTo(findInPageContainer) + make.height.equalTo(UIConstants.ToolbarHeight) + } + + updateViewConstraints() + + // We make the find-in-page bar the first responder below, causing the keyboard delegates + // to fire. This, in turn, will animate the Find in Page container since we use the same + // delegate to slide the bar up and down with the keyboard. We don't want to animate the + // constraints added above, however, so force a layout now to prevent these constraints + // from being lumped in with the keyboard animation. + findInPageBar.layoutIfNeeded() + } + + self.findInPageBar?.becomeFirstResponder() + } else if let findInPageBar = self.findInPageBar { + findInPageBar.endEditing(true) + guard let webView = tabManager.selectedTab?.webView else { return } + webView.evaluateJavaScript("__firefox__.findDone()", completionHandler: nil) + findInPageBar.removeFromSuperview() + self.findInPageBar = nil + updateViewConstraints() + } + } + + @objc fileprivate func openSettings() { + assert(Thread.isMainThread, "Opening settings requires being invoked on the main thread") + + let settingsTableViewController = AppSettingsTableViewController() + settingsTableViewController.profile = profile + settingsTableViewController.tabManager = tabManager + settingsTableViewController.settingsDelegate = self + + let controller = SettingsNavigationController(rootViewController: settingsTableViewController) + controller.popoverDelegate = self + controller.modalPresentationStyle = UIModalPresentationStyle.formSheet + self.present(controller, animated: true, completion: nil) + } + + fileprivate func postLocationChangeNotificationForTab(_ tab: Tab, navigation: WKNavigation?) { + let notificationCenter = NotificationCenter.default + var info = [AnyHashable: Any]() + info["url"] = tab.url?.displayURL + info["title"] = tab.title + if let visitType = self.getVisitTypeForTab(tab, navigation: navigation)?.rawValue { + info["visitType"] = visitType + } + info["isPrivate"] = tab.isPrivate + notificationCenter.post(name: NotificationOnLocationChange, object: self, userInfo: info) + } + + func navigateInTab(tab: Tab, to navigation: WKNavigation? = nil) { + tabManager.expireSnackbars() + + guard let webView = tab.webView else { + print("Cannot navigate in tab without a webView") + return + } + + if let url = webView.url, !url.isErrorPageURL && !url.isAboutHomeURL { + tab.lastExecutedTime = Date.now() + + postLocationChangeNotificationForTab(tab, navigation: navigation) + + // Fire the readability check. This is here and not in the pageShow event handler in ReaderMode.js anymore + // because that event wil not always fire due to unreliable page caching. This will either let us know that + // the currently loaded page can be turned into reading mode or if the page already is in reading mode. We + // ignore the result because we are being called back asynchronous when the readermode status changes. + webView.evaluateJavaScript("\(ReaderModeNamespace).checkReadability()", completionHandler: nil) + + // Re-run additional scripts in webView to extract updated favicons and metadata. + runScriptsOnWebView(webView) + } + + if tab === tabManager.selectedTab { + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil) + // must be followed by LayoutChanged, as ScreenChanged will make VoiceOver + // cursor land on the correct initial element, but if not followed by LayoutChanged, + // VoiceOver will sometimes be stuck on the element, not allowing user to move + // forward/backward. Strange, but LayoutChanged fixes that. + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil) + } else { + // To Screenshot a tab that is hidden we must add the webView, + // then wait enough time for the webview to render. + if let webView = tab.webView { + view.insertSubview(webView, at: 0) + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { + self.screenshotHelper.takeScreenshot(tab) + if webView.superview == self.view { + webView.removeFromSuperview() + } + } + } + } + + // Remember whether or not a desktop site was requested + tab.desktopSite = webView.customUserAgent?.isEmpty == false + } + + // MARK: open in helper utils + func addViewForOpenInHelper(_ openInHelper: OpenInHelper) { + guard let view = openInHelper.openInView else { return } + webViewContainerToolbar.addSubview(view) + webViewContainerToolbar.snp.updateConstraints { make in + make.height.equalTo(OpenInViewUX.ViewHeight) + } + view.snp.makeConstraints { make in + make.edges.equalTo(webViewContainerToolbar) + } + + self.openInHelper = openInHelper + } + + func removeOpenInView() { + guard let _ = self.openInHelper else { return } + webViewContainerToolbar.subviews.forEach { $0.removeFromSuperview() } + + webViewContainerToolbar.snp.updateConstraints { make in + make.height.equalTo(0) + } + + self.openInHelper = nil + } +} + +extension BrowserViewController: ClipboardBarDisplayHandlerDelegate { + func shouldDisplay(clipboardBar bar: ButtonToast) { + show(buttonToast: bar, duration: ClipboardBarToastUX.ToastDelay) + } +} + +extension BrowserViewController: QRCodeViewControllerDelegate { + func didScanQRCodeWithURL(_ url: URL) { + openBlankNewTab(focusLocationField: false) + finishEditingAndSubmit(url, visitType: VisitType.typed) + UnifiedTelemetry.recordEvent(category: .action, method: .scan, object: .qrCodeURL) + } + + func didScanQRCodeWithText(_ text: String) { + openBlankNewTab(focusLocationField: false) + submitSearchText(text) + UnifiedTelemetry.recordEvent(category: .action, method: .scan, object: .qrCodeText) + } +} + +extension BrowserViewController: SettingsDelegate { + func settingsOpenURLInNewTab(_ url: URL) { + self.openURLInNewTab(url, isPrivileged: false) + } +} + +extension BrowserViewController: PresentingModalViewControllerDelegate { + func dismissPresentedModalViewController(_ modalViewController: UIViewController, animated: Bool) { + self.dismiss(animated: animated, completion: nil) + } +} + +/** + * History visit management. + * TODO: this should be expanded to track various visit types; see Bug 1166084. + */ +extension BrowserViewController { + func ignoreNavigationInTab(_ tab: Tab, navigation: WKNavigation) { + self.ignoredNavigation.insert(navigation) + } + + func recordNavigationInTab(_ tab: Tab, navigation: WKNavigation, visitType: VisitType) { + self.typedNavigation[navigation] = visitType + } + + /** + * Untrack and do the right thing. + */ + func getVisitTypeForTab(_ tab: Tab, navigation: WKNavigation?) -> VisitType? { + guard let navigation = navigation else { + // See https://github.com/WebKit/webkit/blob/master/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm#L390 + return VisitType.link + } + + if let _ = self.ignoredNavigation.remove(navigation) { + return nil + } + + return self.typedNavigation.removeValue(forKey: navigation) ?? VisitType.link + } +} + +extension BrowserViewController: URLBarDelegate { + + func showTabTray() { + webViewContainerToolbar.isHidden = true + updateFindInPageVisibility(visible: false) + + let tabTrayController = TabTrayController(tabManager: tabManager, profile: profile, tabTrayDelegate: self) + + if let tab = tabManager.selectedTab { + screenshotHelper.takeScreenshot(tab) + } + + navigationController?.pushViewController(tabTrayController, animated: true) + self.tabTrayController = tabTrayController + } + + func urlBarDidPressReload(_ urlBar: URLBarView) { + tabManager.selectedTab?.reload() + } + + func urlBarDidPressQRButton(_ urlBar: URLBarView) { + let qrCodeViewController = QRCodeViewController() + qrCodeViewController.qrCodeDelegate = self + let controller = QRCodeNavigationController(rootViewController: qrCodeViewController) + self.present(controller, animated: true, completion: nil) + } + + func urlBarDidPressPageOptions(_ urlBar: URLBarView, from button: UIButton) { + + let actionMenuPresenter: (URL, Tab, UIView, UIPopoverArrowDirection) -> Void = { (url, tab, view, _) in + self.presentActivityViewController(url, tab: tab, sourceView: view, sourceRect: view.bounds, arrowDirection: .up) + } + + let findInPageAction = { + self.updateFindInPageVisibility(visible: true) + } + + let successCallback: (String) -> Void = { (successMessage) in + SimpleToast().showAlertWithText(successMessage, bottomContainer: self.webViewContainer) + } + + guard let tab = tabManager.selectedTab, tab.url != nil else { return } + + // The logic of which actions appear when isnt final. + let pageActions = getTabActions(tab: tab, buttonView: button, presentShareMenu: actionMenuPresenter, + findInPage: findInPageAction, presentableVC: self, success: successCallback) + + presentSheetWith(actions: pageActions, on: self, from: button) + } + + func urlBarDidLongPressPageOptions(_ urlBar: URLBarView, from button: UIButton) { + guard let tab = tabManager.selectedTab else { return } + guard let url = tab.canonicalURL?.displayURL else { return } + presentActivityViewController(url, tab: tab, sourceView: button, sourceRect: button.bounds, arrowDirection: .up) + } + + func urlBarDidPressStop(_ urlBar: URLBarView) { + tabManager.selectedTab?.stop() + } + + func urlBarDidPressTabs(_ urlBar: URLBarView) { + showTabTray() + } + + func urlBarDidPressReaderMode(_ urlBar: URLBarView) { + if let tab = tabManager.selectedTab { + if let readerMode = tab.getContentScript(name: "ReaderMode") as? ReaderMode { + switch readerMode.state { + case .available: + enableReaderMode() + UnifiedTelemetry.recordEvent(category: .action, method: .tap, object: .readerModeOpenButton) + LeanPlumClient.shared.track(event: .useReaderView) + case .active: + disableReaderMode() + UnifiedTelemetry.recordEvent(category: .action, method: .tap, object: .readerModeCloseButton) + case .unavailable: + break + } + } + } + } + + func urlBarDidLongPressReaderMode(_ urlBar: URLBarView) -> Bool { + guard let tab = tabManager.selectedTab, + let url = tab.url?.displayURL, + let result = profile.readingList?.createRecordWithURL(url.absoluteString, title: tab.title ?? "", addedBy: UIDevice.current.name) + else { + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, NSLocalizedString("Could not add page to Reading list", comment: "Accessibility message e.g. spoken by VoiceOver after adding current webpage to the Reading List failed.")) + return false + } + + switch result { + case .success: + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, NSLocalizedString("Added page to Reading List", comment: "Accessibility message e.g. spoken by VoiceOver after the current page gets added to the Reading List using the Reader View button, e.g. by long-pressing it or by its accessibility custom action.")) + // TODO: https://bugzilla.mozilla.org/show_bug.cgi?id=1158503 provide some form of 'this has been added' visual feedback? + case .failure(let error): + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, NSLocalizedString("Could not add page to Reading List. Maybe it’s already there?", comment: "Accessibility message e.g. spoken by VoiceOver after the user wanted to add current page to the Reading List and this was not done, likely because it already was in the Reading List, but perhaps also because of real failures.")) + print("readingList.createRecordWithURL(url: \"\(url.absoluteString)\", ...) failed with error: \(error)") + } + return true + } + + func locationActionsForURLBar(_ urlBar: URLBarView) -> [AccessibleAction] { + if UIPasteboard.general.string != nil { + return [pasteGoAction, pasteAction, copyAddressAction] + } else { + return [copyAddressAction] + } + } + + func urlBarDisplayTextForURL(_ url: URL?) -> (String?, Bool) { + // use the initial value for the URL so we can do proper pattern matching with search URLs + var searchURL = self.tabManager.selectedTab?.currentInitialURL + if searchURL?.isErrorPageURL ?? true { + searchURL = url + } + if let query = profile.searchEngines.queryForSearchURL(searchURL as URL?) { + return (query, true) + } else { + return (url?.absoluteString, false) + } + } + + func urlBarDidLongPressLocation(_ urlBar: URLBarView) { + let longPressAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + + for action in locationActionsForURLBar(urlBar) { + longPressAlertController.addAction(action.alertAction(style: .default)) + } + + let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: "Label for Cancel button"), style: .cancel, handler: { (alert: UIAlertAction) -> Void in + }) + longPressAlertController.addAction(cancelAction) + + let setupPopover = { [unowned self] in + if let popoverPresentationController = longPressAlertController.popoverPresentationController { + popoverPresentationController.sourceView = urlBar + popoverPresentationController.sourceRect = urlBar.frame + popoverPresentationController.permittedArrowDirections = .any + popoverPresentationController.delegate = self + } + } + + setupPopover() + + if longPressAlertController.popoverPresentationController != nil { + displayedPopoverController = longPressAlertController + updateDisplayedPopoverProperties = setupPopover + } + + self.present(longPressAlertController, animated: true, completion: nil) + } + + func urlBarDidPressScrollToTop(_ urlBar: URLBarView) { + if let selectedTab = tabManager.selectedTab { + // Only scroll to top if we are not showing the home view controller + if homePanelController == nil { + selectedTab.webView?.scrollView.setContentOffset(CGPoint.zero, animated: true) + } + } + } + + func urlBarLocationAccessibilityActions(_ urlBar: URLBarView) -> [UIAccessibilityCustomAction]? { + return locationActionsForURLBar(urlBar).map { $0.accessibilityCustomAction } + } + + func urlBar(_ urlBar: URLBarView, didEnterText text: String) { + if text.isEmpty { + hideSearchController() + } else { + showSearchController() + searchController?.searchQuery = text + searchLoader?.query = text + } + } + + func urlBar(_ urlBar: URLBarView, didSubmitText text: String) { + if let fixupURL = URIFixup.getURL(text) { + // The user entered a URL, so use it. + finishEditingAndSubmit(fixupURL, visitType: VisitType.typed) + return + } + + // We couldn't build a URL, so check for a matching search keyword. + let trimmedText = text.trimmingCharacters(in: CharacterSet.whitespaces) + guard let possibleKeywordQuerySeparatorSpace = trimmedText.characters.index(of: " ") else { + submitSearchText(text) + return + } + + let possibleKeyword = trimmedText.substring(to: possibleKeywordQuerySeparatorSpace) + let possibleQuery = trimmedText.substring(from: trimmedText.index(after: possibleKeywordQuerySeparatorSpace)) + + profile.bookmarks.getURLForKeywordSearch(possibleKeyword).uponQueue(DispatchQueue.main) { result in + if var urlString = result.successValue, + let escapedQuery = possibleQuery.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed), + let range = urlString.range(of: "%s") { + urlString.replaceSubrange(range, with: escapedQuery) + + if let url = URL(string: urlString) { + self.finishEditingAndSubmit(url, visitType: VisitType.typed) + return + } + } + + self.submitSearchText(text) + } + } + + fileprivate func submitSearchText(_ text: String) { + let engine = profile.searchEngines.defaultEngine + + if let searchURL = engine.searchURLForQuery(text) { + // We couldn't find a matching search keyword, so do a search query. + Telemetry.default.recordSearch(location: .actionBar, searchEngine: engine.engineID ?? "other") + finishEditingAndSubmit(searchURL, visitType: VisitType.typed) + } else { + // We still don't have a valid URL, so something is broken. Give up. + print("Error handling URL entry: \"\(text)\".") + assertionFailure("Couldn't generate search URL: \(text)") + } + } + + func urlBarDidEnterOverlayMode(_ urlBar: URLBarView) { + guard let profile = profile as? BrowserProfile else { + return + } + + if .blankPage == NewTabAccessors.getNewTabPage(profile.prefs) { + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil) + } else { + if let toast = clipboardBarDisplayHandler?.clipboardToast { + toast.removeFromSuperview() + } + showHomePanelController(inline: false) + } + + LeanPlumClient.shared.track(event: .interactWithURLBar) + } + + func urlBarDidLeaveOverlayMode(_ urlBar: URLBarView) { + hideSearchController() + updateInContentHomePanel(tabManager.selectedTab?.url as URL?) + } +} + +extension BrowserViewController: TabToolbarDelegate, PhotonActionSheetProtocol { + func tabToolbarDidPressBack(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + tabManager.selectedTab?.goBack() + } + + func tabToolbarDidLongPressBack(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + showBackForwardList() + } + + func tabToolbarDidPressReload(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + tabManager.selectedTab?.reload() + } + + func tabToolbarDidLongPressReload(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + guard let tab = tabManager.selectedTab, tab.webView?.url != nil && (tab.getContentScript(name: ReaderMode.name()) as? ReaderMode)?.state != .active else { + return + } + + let toggleActionTitle: String + if tab.desktopSite { + toggleActionTitle = NSLocalizedString("Request Mobile Site", comment: "Action Sheet Button for Requesting the Mobile Site") + } else { + toggleActionTitle = NSLocalizedString("Request Desktop Site", comment: "Action Sheet Button for Requesting the Desktop Site") + } + + let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + controller.addAction(UIAlertAction(title: toggleActionTitle, style: .default, handler: { _ in tab.toggleDesktopSite() })) + controller.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "Label for Cancel button"), style: .cancel, handler: nil)) + controller.popoverPresentationController?.sourceView = toolbar ?? urlBar + controller.popoverPresentationController?.sourceRect = button.frame + present(controller, animated: true, completion: nil) + } + + func tabToolbarDidPressStop(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + tabManager.selectedTab?.stop() + } + + func tabToolbarDidPressForward(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + tabManager.selectedTab?.goForward() + } + + func tabToolbarDidLongPressForward(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + showBackForwardList() + } + + func tabToolbarDidPressMenu(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + // ensure that any keyboards or spinners are dismissed before presenting the menu + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + var actions: [[PhotonActionSheetItem]] = [] + + actions.append(getHomePanelActions()) + actions.append(getOtherPanelActions(vcDelegate: self)) + // force a modal if the menu is being displayed in compact split screen + let shouldSupress = !topTabsVisible && UIDevice.current.userInterfaceIdiom == .pad + presentSheetWith(actions: actions, on: self, from: button, supressPopover: shouldSupress) + } + + func tabToolbarDidPressTabs(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + showTabTray() + } + + func tabToolbarDidLongPressTabs(_ tabToolbar: TabToolbarProtocol, button: UIButton) { + let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + controller.addAction(UIAlertAction(title: Strings.NewTabTitle, style: .default, handler: { _ in + self.tabManager.addTabAndSelect(isPrivate: false) + })) + controller.addAction(UIAlertAction(title: Strings.NewPrivateTabTitle, style: .default, handler: { _ in + self.tabManager.addTabAndSelect(isPrivate: true) + })) + controller.addAction(UIAlertAction(title: Strings.CloseTabTitle, style: .destructive, handler: { _ in + if let tab = self.tabManager.selectedTab { + self.tabManager.removeTab(tab) + } + })) + controller.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "Label for Cancel button"), style: .cancel, handler: nil)) + controller.popoverPresentationController?.sourceView = toolbar ?? urlBar + controller.popoverPresentationController?.sourceRect = button.frame + present(controller, animated: true, completion: nil) + } + + func showBackForwardList() { + if let backForwardList = tabManager.selectedTab?.webView?.backForwardList { + let backForwardViewController = BackForwardListViewController(profile: profile, backForwardList: backForwardList) + backForwardViewController.tabManager = tabManager + backForwardViewController.bvc = self + backForwardViewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext + backForwardViewController.backForwardTransitionDelegate = BackForwardListAnimator() + self.present(backForwardViewController, animated: true, completion: nil) + } + } +} + +extension BrowserViewController: TabDelegate { + + func tab(_ tab: Tab, didCreateWebView webView: WKWebView) { + webView.frame = webViewContainer.frame + // Observers that live as long as the tab. Make sure these are all cleared in willDeleteWebView below! + KVOs.forEach { webView.addObserver(self, forKeyPath: $0.rawValue, options: .new, context: nil) } + webView.scrollView.addObserver(self.scrollController, forKeyPath: KVOConstants.contentSize.rawValue, options: .new, context: nil) + + webView.uiDelegate = self + + let readerMode = ReaderMode(tab: tab) + readerMode.delegate = self + tab.addContentScript(readerMode, name: ReaderMode.name()) + + let favicons = FaviconManager(tab: tab, profile: profile) + tab.addContentScript(favicons, name: FaviconManager.name()) + + // only add the logins helper if the tab is not a private browsing tab + if !tab.isPrivate { + let logins = LoginsHelper(tab: tab, profile: profile) + tab.addContentScript(logins, name: LoginsHelper.name()) + } + + let contextMenuHelper = ContextMenuHelper(tab: tab) + contextMenuHelper.delegate = self + tab.addContentScript(contextMenuHelper, name: ContextMenuHelper.name()) + + let errorHelper = ErrorPageHelper() + tab.addContentScript(errorHelper, name: ErrorPageHelper.name()) + + let sessionRestoreHelper = SessionRestoreHelper(tab: tab) + sessionRestoreHelper.delegate = self + tab.addContentScript(sessionRestoreHelper, name: SessionRestoreHelper.name()) + + let findInPageHelper = FindInPageHelper(tab: tab) + findInPageHelper.delegate = self + tab.addContentScript(findInPageHelper, name: FindInPageHelper.name()) + + let noImageModeHelper = NoImageModeHelper(tab: tab) + tab.addContentScript(noImageModeHelper, name: NoImageModeHelper.name()) + + let printHelper = PrintHelper(tab: tab) + tab.addContentScript(printHelper, name: PrintHelper.name()) + + let customSearchHelper = CustomSearchHelper(tab: tab) + tab.addContentScript(customSearchHelper, name: CustomSearchHelper.name()) + + let nightModeHelper = NightModeHelper(tab: tab) + tab.addContentScript(nightModeHelper, name: NightModeHelper.name()) + + // XXX: Bug 1390200 - Disable NSUserActivity/CoreSpotlight temporarily + // let spotlightHelper = SpotlightHelper(tab: tab) + // tab.addHelper(spotlightHelper, name: SpotlightHelper.name()) + + tab.addContentScript(LocalRequestHelper(), name: LocalRequestHelper.name()) + + let historyStateHelper = HistoryStateHelper(tab: tab) + historyStateHelper.delegate = self + tab.addContentScript(historyStateHelper, name: HistoryStateHelper.name()) + + if #available(iOS 11, *) { + (tab.contentBlocker as? ContentBlockerHelper)?.setupForWebView() + } + + let metadataHelper = MetadataParserHelper(tab: tab, profile: profile) + tab.addContentScript(metadataHelper, name: MetadataParserHelper.name()) + } + + func tab(_ tab: Tab, willDeleteWebView webView: WKWebView) { + tab.cancelQueuedAlerts() + KVOs.forEach { webView.removeObserver(self, forKeyPath: $0.rawValue) } + webView.scrollView.removeObserver(self.scrollController, forKeyPath: KVOConstants.contentSize.rawValue) + webView.uiDelegate = nil + webView.scrollView.delegate = nil + webView.removeFromSuperview() + } + + fileprivate func findSnackbar(_ barToFind: SnackBar) -> Int? { + let bars = snackBars.subviews + for (index, bar) in bars.enumerated() where bar === barToFind { + return index + } + return nil + } + + fileprivate func updateSnackBarConstraints() { + snackBars.snp.remakeConstraints { make in + make.bottom.equalTo(findInPageContainer.snp.top) + + let bars = self.snackBars.subviews + if bars.count > 0 { + let view = bars[bars.count-1] + make.top.equalTo(view.snp.top) + } else { + make.height.equalTo(0) + } + + if traitCollection.horizontalSizeClass != .regular { + make.leading.trailing.equalTo(self.view) + self.snackBars.layer.borderWidth = 0 + } else { + make.centerX.equalTo(self.view) + make.width.equalTo(SnackBarUX.MaxWidth) + self.snackBars.layer.borderColor = UIConstants.BorderColor.cgColor + self.snackBars.layer.borderWidth = 1 + } + } + } + + // This removes the bar from its superview and updates constraints appropriately + fileprivate func finishRemovingBar(_ bar: SnackBar) { + // If there was a bar above this one, we need to remake its constraints. + if let index = findSnackbar(bar) { + // If the bar being removed isn't on the top of the list + let bars = snackBars.subviews + if index < bars.count-1 { + // Move the bar above this one + let nextbar = bars[index+1] as! SnackBar + nextbar.snp.makeConstraints { make in + // If this wasn't the bottom bar, attach to the bar below it + if index > 0 { + let bar = bars[index-1] as! SnackBar + nextbar.bottom = make.bottom.equalTo(bar.snp.top).constraint + } else { + // Otherwise, we attach it to the bottom of the snackbars + nextbar.bottom = make.bottom.equalTo(self.snackBars.snp.bottom).constraint + } + } + } + } + + // Really remove the bar + bar.removeFromSuperview() + } + + fileprivate func finishAddingBar(_ bar: SnackBar) { + snackBars.addSubview(bar) + bar.snp.makeConstraints { make in + // If there are already bars showing, add this on top of them + let bars = self.snackBars.subviews + + // Add the bar on top of the stack + // We're the new top bar in the stack, so make sure we ignore ourself + if bars.count > 1 { + let view = bars[bars.count - 2] + bar.bottom = make.bottom.equalTo(view.snp.top).offset(0).constraint + } else { + bar.bottom = make.bottom.equalTo(self.snackBars.snp.bottom).offset(0).constraint + } + make.leading.trailing.equalTo(self.snackBars) + } + } + + func showBar(_ bar: SnackBar, animated: Bool) { + finishAddingBar(bar) + updateSnackBarConstraints() + + bar.hide() + view.layoutIfNeeded() + UIView.animate(withDuration: animated ? 0.25 : 0, animations: { () -> Void in + bar.show() + self.view.layoutIfNeeded() + }) + } + + func removeBar(_ bar: SnackBar, animated: Bool) { + if let _ = findSnackbar(bar) { + UIView.animate(withDuration: animated ? 0.25 : 0, animations: { () -> Void in + bar.hide() + self.view.layoutIfNeeded() + }, completion: { success in + // Really remove the bar + self.finishRemovingBar(bar) + self.updateSnackBarConstraints() + }) + } + } + + func removeAllBars() { + let bars = snackBars.subviews + for bar in bars { + if let bar = bar as? SnackBar { + bar.removeFromSuperview() + } + } + self.updateSnackBarConstraints() + } + + func tab(_ tab: Tab, didAddSnackbar bar: SnackBar) { + showBar(bar, animated: true) + } + + func tab(_ tab: Tab, didRemoveSnackbar bar: SnackBar) { + removeBar(bar, animated: true) + } + + func tab(_ tab: Tab, didSelectFindInPageForSelection selection: String) { + updateFindInPageVisibility(visible: true) + findInPageBar?.text = selection + } +} + +extension BrowserViewController: HomePanelViewControllerDelegate { + func homePanelViewController(_ homePanelViewController: HomePanelViewController, didSelectURL url: URL, visitType: VisitType) { + finishEditingAndSubmit(url, visitType: visitType) + } + + func homePanelViewController(_ homePanelViewController: HomePanelViewController, didSelectPanel panel: Int) { + if let url = tabManager.selectedTab?.url, url.isAboutHomeURL { + tabManager.selectedTab?.webView?.evaluateJavaScript("history.replaceState({}, '', '#panel=\(panel)')", completionHandler: nil) + } + } + + func homePanelViewControllerDidRequestToCreateAccount(_ homePanelViewController: HomePanelViewController) { + presentSignInViewController() // TODO UX Right now the flow for sign in and create account is the same + } + + func homePanelViewControllerDidRequestToSignIn(_ homePanelViewController: HomePanelViewController) { + presentSignInViewController() // TODO UX Right now the flow for sign in and create account is the same + } + + func homePanelViewControllerDidRequestToOpenInNewTab(_ url: URL, isPrivate: Bool) { + let tab = self.tabManager.addTab(PrivilegedRequest(url: url) as URLRequest, afterTab: self.tabManager.selectedTab, isPrivate: isPrivate) + // If we are showing toptabs a user can just use the top tab bar + // If in overlay mode switching doesnt correctly dismiss the homepanels + guard !topTabsVisible, !self.urlBar.inOverlayMode else { + return + } + // We're not showing the top tabs; show a toast to quick switch to the fresh new tab. + let toast = ButtonToast(labelText: Strings.ContextMenuButtonToastNewTabOpenedLabelText, buttonText: Strings.ContextMenuButtonToastNewTabOpenedButtonText, completion: { buttonPressed in + if buttonPressed { + self.tabManager.selectTab(tab) + } + }) + self.show(buttonToast: toast) + } +} + +extension BrowserViewController: SearchViewControllerDelegate { + func searchViewController(_ searchViewController: SearchViewController, didSelectURL url: URL) { + finishEditingAndSubmit(url, visitType: VisitType.typed) + } + + func searchViewController(_ searchViewController: SearchViewController, didLongPressSuggestion suggestion: String) { + self.urlBar.setLocation(suggestion, search: true) + } + + func presentSearchSettingsController() { + let settingsNavigationController = SearchSettingsTableViewController() + settingsNavigationController.model = self.profile.searchEngines + settingsNavigationController.profile = self.profile + let navController = ModalSettingsNavigationController(rootViewController: settingsNavigationController) + + self.present(navController, animated: true, completion: nil) + } +} + +extension BrowserViewController: TabManagerDelegate { + + func tabManager(_ tabManager: TabManager, didSelectedTabChange selected: Tab?, previous: Tab?) { + // Remove the old accessibilityLabel. Since this webview shouldn't be visible, it doesn't need it + // and having multiple views with the same label confuses tests. + if let wv = previous?.webView { + removeOpenInView() + wv.endEditing(true) + wv.accessibilityLabel = nil + wv.accessibilityElementsHidden = true + wv.accessibilityIdentifier = nil + wv.removeFromSuperview() + } + + if let tab = selected, let webView = tab.webView { + updateURLBarDisplayURL(tab) + if tab.isPrivate != previous?.isPrivate { + applyTheme(tab.isPrivate ? Theme.PrivateMode : Theme.NormalMode) + } + if tab.isPrivate { + readerModeCache = MemoryReaderModeCache.sharedInstance + + } else { + readerModeCache = DiskReaderModeCache.sharedInstance + } + if let privateModeButton = topTabsViewController?.privateModeButton, previous != nil && previous?.isPrivate != tab.isPrivate { + privateModeButton.setSelected(tab.isPrivate, animated: true) + } + ReaderModeHandlers.readerModeCache = readerModeCache + + scrollController.tab = selected + webViewContainer.addSubview(webView) + webView.snp.makeConstraints { make in + make.top.equalTo(webViewContainerToolbar.snp.bottom) + make.left.right.bottom.equalTo(self.webViewContainer) + } + webView.accessibilityLabel = NSLocalizedString("Web content", comment: "Accessibility label for the main web content view") + webView.accessibilityIdentifier = "contentView" + webView.accessibilityElementsHidden = false + + if let url = webView.url { + let absoluteString = url.absoluteString + // Don't bother fetching bookmark state for about/sessionrestore and about/home. + if url.isAboutURL { + // Indeed, because we don't show the toolbar at all, don't even blank the star. + } else { + profile.bookmarks.modelFactory >>== { [weak tab] in + $0.isBookmarked(absoluteString) + .uponQueue(DispatchQueue.main) { + guard let isBookmarked = $0.successValue else { + print("Error getting bookmark status: \($0.failureValue ??? "nil").") + return + } + + tab?.isBookmarked = isBookmarked + } + } + } + } else { + // The web view can go gray if it was zombified due to memory pressure. + // When this happens, the URL is nil, so try restoring the page upon selection. + tab.reload() + } + } + + if let selected = selected, let previous = previous, selected.isPrivate != previous.isPrivate { + updateTabCountUsingTabManager(tabManager) + } + + removeAllBars() + if let bars = selected?.bars { + for bar in bars { + showBar(bar, animated: true) + } + } + + updateFindInPageVisibility(visible: false) + + navigationToolbar.updateReloadStatus(selected?.loading ?? false) + navigationToolbar.updateBackStatus(selected?.canGoBack ?? false) + navigationToolbar.updateForwardStatus(selected?.canGoForward ?? false) + if !(selected?.webView?.url?.isLocalUtility ?? false) { + self.urlBar.updateProgressBar(Float(selected?.estimatedProgress ?? 0)) + } + + if let readerMode = selected?.getContentScript(name: ReaderMode.name()) as? ReaderMode { + urlBar.updateReaderModeState(readerMode.state) + if readerMode.state == .active { + showReaderModeBar(animated: false) + } else { + hideReaderModeBar(animated: false) + } + } else { + urlBar.updateReaderModeState(ReaderModeState.unavailable) + } + + updateInContentHomePanel(selected?.url as URL?) + } + + func tabManager(_ tabManager: TabManager, willAddTab tab: Tab) { + } + + func tabManager(_ tabManager: TabManager, didAddTab tab: Tab) { + // If we are restoring tabs then we update the count once at the end + if !tabManager.isRestoring { + updateTabCountUsingTabManager(tabManager) + } + tab.tabDelegate = self + } + + func tabManager(_ tabManager: TabManager, willRemoveTab tab: Tab) { + } + + func tabManager(_ tabManager: TabManager, didRemoveTab tab: Tab) { + updateTabCountUsingTabManager(tabManager) + // tabDelegate is a weak ref (and the tab's webView may not be destroyed yet) + // so we don't expcitly unset it. + + if let url = tab.url, !url.isAboutURL && !tab.isPrivate { + profile.recentlyClosedTabs.addTab(url as URL, title: tab.title, faviconURL: tab.displayFavicon?.url) + } + } + + func tabManagerDidAddTabs(_ tabManager: TabManager) { + updateTabCountUsingTabManager(tabManager) + } + + func tabManagerDidRestoreTabs(_ tabManager: TabManager) { + updateTabCountUsingTabManager(tabManager) + } + + func show(buttonToast: ButtonToast, afterWaiting delay: DispatchTimeInterval = SimpleToastUX.ToastDelayBefore, duration: DispatchTimeInterval = SimpleToastUX.ToastDismissAfter) { + // If BVC isnt visible hold on to this toast until viewDidAppear + if self.view.window == nil { + self.pendingToast = buttonToast + return + } + + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + self.view.addSubview(buttonToast) + buttonToast.snp.makeConstraints { make in + make.left.right.equalTo(self.view) + make.bottom.equalTo(self.webViewContainer) + } + buttonToast.showToast(duration: duration) + } + } + + func tabManagerDidRemoveAllTabs(_ tabManager: TabManager, toast: ButtonToast?) { + guard let toast = toast, !tabTrayController.privateMode else { + return + } + show(buttonToast: toast, afterWaiting: ButtonToastUX.ToastDelay) + } + + fileprivate func updateTabCountUsingTabManager(_ tabManager: TabManager, animated: Bool = true) { + if let selectedTab = tabManager.selectedTab { + let count = selectedTab.isPrivate ? tabManager.privateTabs.count : tabManager.normalTabs.count + toolbar?.updateTabCount(count, animated: animated) + urlBar.updateTabCount(count, animated: !urlBar.inOverlayMode) + topTabsViewController?.updateTabCount(count, animated: animated) + } + } +} + +/// List of schemes that are allowed to open a popup window +private let SchemesAllowedToOpenPopups = ["http", "https", "javascript", "data"] + +extension BrowserViewController: WKUIDelegate { + func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { + guard let parentTab = tabManager[webView] else { return nil } + + if !navigationAction.isAllowed { + print("Denying unprivileged request: \(navigationAction.request)") + return nil + } + + if let currentTab = tabManager.selectedTab { + screenshotHelper.takeScreenshot(currentTab) + } + + // If the page uses window.open() or target="_blank", open the page in a new tab. + let newTab = tabManager.addTab(navigationAction.request, configuration: configuration, afterTab: parentTab, isPrivate: parentTab.isPrivate) + tabManager.selectTab(newTab) + + // If the page we just opened has a bad scheme, we return nil here so that JavaScript does not + // get a reference to it which it can return from window.open() - this will end up as a + // CFErrorHTTPBadURL being presented. + guard let scheme = (navigationAction.request as NSURLRequest).url?.scheme?.lowercased(), SchemesAllowedToOpenPopups.contains(scheme) else { + return nil + } + + return newTab.webView + } + + fileprivate func canDisplayJSAlertForWebView(_ webView: WKWebView) -> Bool { + // Only display a JS Alert if we are selected and there isn't anything being shown + return ((tabManager.selectedTab == nil ? false : tabManager.selectedTab!.webView == webView)) && (self.presentedViewController == nil) + } + + func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { + let messageAlert = MessageAlert(message: message, frame: frame, completionHandler: completionHandler) + if canDisplayJSAlertForWebView(webView) { + present(messageAlert.alertController(), animated: true, completion: nil) + } else if let promptingTab = tabManager[webView] { + promptingTab.queueJavascriptAlertPrompt(messageAlert) + } else { + // This should never happen since an alert needs to come from a web view but just in case call the handler + // since not calling it will result in a runtime exception. + completionHandler() + } + } + + func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { + let confirmAlert = ConfirmPanelAlert(message: message, frame: frame, completionHandler: completionHandler) + if canDisplayJSAlertForWebView(webView) { + present(confirmAlert.alertController(), animated: true, completion: nil) + } else if let promptingTab = tabManager[webView] { + promptingTab.queueJavascriptAlertPrompt(confirmAlert) + } else { + completionHandler(false) + } + } + + func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { + let textInputAlert = TextInputAlert(message: prompt, frame: frame, completionHandler: completionHandler, defaultText: defaultText) + if canDisplayJSAlertForWebView(webView) { + present(textInputAlert.alertController(), animated: true, completion: nil) + } else if let promptingTab = tabManager[webView] { + promptingTab.queueJavascriptAlertPrompt(textInputAlert) + } else { + completionHandler(nil) + } + } + + /// Invoked when an error occurs while starting to load data for the main frame. + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + // Ignore the "Frame load interrupted" error that is triggered when we cancel a request + // to open an external application and hand it over to UIApplication.openURL(). The result + // will be that we switch to the external app, for example the app store, while keeping the + // original web page in the tab instead of replacing it with an error page. + let error = error as NSError + if error.domain == "WebKitErrorDomain" && error.code == 102 { + return + } + + if checkIfWebContentProcessHasCrashed(webView, error: error as NSError) { + return + } + + if error.code == Int(CFNetworkErrors.cfurlErrorCancelled.rawValue) { + if let tab = tabManager[webView], tab === tabManager.selectedTab { + urlBar.currentURL = tab.url?.displayURL + } + return + } + + if let url = error.userInfo[NSURLErrorFailingURLErrorKey] as? URL { + ErrorPageHelper().showPage(error, forUrl: url, inWebView: webView) + + // If the local web server isn't working for some reason (Firefox cellular data is + // disabled in settings, for example), we'll fail to load the session restore URL. + // We rely on loading that page to get the restore callback to reset the restoring + // flag, so if we fail to load that page, reset it here. + if url.aboutComponent == "sessionrestore" { + tabManager.tabs.filter { $0.webView == webView }.first?.restoring = false + } + } + } + + fileprivate func checkIfWebContentProcessHasCrashed(_ webView: WKWebView, error: NSError) -> Bool { + if error.code == WKError.webContentProcessTerminated.rawValue && error.domain == "WebKitErrorDomain" { + print("WebContent process has crashed. Trying to reloadFromOrigin to restart it.") + webView.reloadFromOrigin() + return true + } + + return false + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { + let helperForURL = OpenIn.helperForResponse(navigationResponse.response) + if navigationResponse.canShowMIMEType { + if let openInHelper = helperForURL { + addViewForOpenInHelper(openInHelper) + } + decisionHandler(WKNavigationResponsePolicy.allow) + return + } + + guard var openInHelper = helperForURL else { + let error = NSError(domain: ErrorPageHelper.MozDomain, code: Int(ErrorPageHelper.MozErrorDownloadsNotEnabled), userInfo: [NSLocalizedDescriptionKey: Strings.UnableToDownloadError]) + ErrorPageHelper().showPage(error, forUrl: navigationResponse.response.url!, inWebView: webView) + return decisionHandler(WKNavigationResponsePolicy.allow) + } + + if openInHelper.openInView == nil { + openInHelper.openInView = navigationToolbar.menuButton + } + + openInHelper.open() + decisionHandler(WKNavigationResponsePolicy.cancel) + } + + func webViewDidClose(_ webView: WKWebView) { + if let tab = tabManager[webView] { + self.tabManager.removeTab(tab) + } + } +} + +extension BrowserViewController: ReaderModeDelegate { + func readerMode(_ readerMode: ReaderMode, didChangeReaderModeState state: ReaderModeState, forTab tab: Tab) { + // If this reader mode availability state change is for the tab that we currently show, then update + // the button. Otherwise do nothing and the button will be updated when the tab is made active. + if tabManager.selectedTab === tab { + urlBar.updateReaderModeState(state) + } + } + + func readerMode(_ readerMode: ReaderMode, didDisplayReaderizedContentForTab tab: Tab) { + self.showReaderModeBar(animated: true) + tab.showContent(true) + } +} + +// MARK: - UIPopoverPresentationControllerDelegate + +extension BrowserViewController: UIPopoverPresentationControllerDelegate { + func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) { + displayedPopoverController = nil + updateDisplayedPopoverProperties = nil + } +} + +extension BrowserViewController: UIAdaptivePresentationControllerDelegate { + // Returning None here makes sure that the Popover is actually presented as a Popover and + // not as a full-screen modal, which is the default on compact device classes. + func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { + return UIModalPresentationStyle.none + } +} + +// MARK: - ReaderModeStyleViewControllerDelegate + +extension BrowserViewController: ReaderModeStyleViewControllerDelegate { + func readerModeStyleViewController(_ readerModeStyleViewController: ReaderModeStyleViewController, didConfigureStyle style: ReaderModeStyle) { + // Persist the new style to the profile + let encodedStyle: [String: Any] = style.encodeAsDictionary() + profile.prefs.setObject(encodedStyle, forKey: ReaderModeProfileKeyStyle) + // Change the reader mode style on all tabs that have reader mode active + for tabIndex in 0.. 1 && backList.last?.url == readerModeURL { + webView.go(to: backList.last!) + } else if forwardList.count > 0 && forwardList.first?.url == readerModeURL { + webView.go(to: forwardList.first!) + } else { + // Store the readability result in the cache and load it. This will later move to the ReadabilityHelper. + webView.evaluateJavaScript("\(ReaderModeNamespace).readerize()", completionHandler: { (object, error) -> Void in + if let readabilityResult = ReadabilityResult(object: object as AnyObject?) { + do { + try self.readerModeCache.put(currentURL, readabilityResult) + } catch _ { + } + if let nav = webView.load(PrivilegedRequest(url: readerModeURL) as URLRequest) { + self.ignoreNavigationInTab(tab, navigation: nav) + } + } + }) + } + } + + /// Disabling reader mode can mean two things. In the simplest case we were opened from the reading list, which + /// means that there is nothing in the BackForwardList except the internal url for the reader mode page. In that + /// case we simply open a new page with the original url. In the more complicated page, the non-readerized version + /// of the page is either to the left or right in the BackForwardList. If that is the case, we navigate there. + + func disableReaderMode() { + if let tab = tabManager.selectedTab, + let webView = tab.webView { + let backList = webView.backForwardList.backList + let forwardList = webView.backForwardList.forwardList + + if let currentURL = webView.backForwardList.currentItem?.url { + if let originalURL = currentURL.decodeReaderModeURL { + if backList.count > 1 && backList.last?.url == originalURL { + webView.go(to: backList.last!) + } else if forwardList.count > 0 && forwardList.first?.url == originalURL { + webView.go(to: forwardList.first!) + } else { + if let nav = webView.load(URLRequest(url: originalURL)) { + self.ignoreNavigationInTab(tab, navigation: nav) + } + } + } + } + } + } + + func SELDynamicFontChanged(_ notification: Notification) { + guard notification.name == NotificationDynamicFontChanged else { return } + + var readerModeStyle = DefaultReaderModeStyle + if let dict = profile.prefs.dictionaryForKey(ReaderModeProfileKeyStyle) { + if let style = ReaderModeStyle(dict: dict as [String: AnyObject]) { + readerModeStyle = style + } + } + readerModeStyle.fontSize = ReaderModeFontSize.defaultSize + self.readerModeStyleViewController(ReaderModeStyleViewController(), didConfigureStyle: readerModeStyle) + } +} + +extension BrowserViewController: ReaderModeBarViewDelegate { + func readerModeBar(_ readerModeBar: ReaderModeBarView, didSelectButton buttonType: ReaderModeBarButtonType) { + switch buttonType { + case .settings: + if let readerMode = tabManager.selectedTab?.getContentScript(name: "ReaderMode") as? ReaderMode, readerMode.state == ReaderModeState.active { + var readerModeStyle = DefaultReaderModeStyle + if let dict = profile.prefs.dictionaryForKey(ReaderModeProfileKeyStyle) { + if let style = ReaderModeStyle(dict: dict as [String: AnyObject]) { + readerModeStyle = style + } + } + + let readerModeStyleViewController = ReaderModeStyleViewController() + readerModeStyleViewController.delegate = self + readerModeStyleViewController.readerModeStyle = readerModeStyle + readerModeStyleViewController.modalPresentationStyle = UIModalPresentationStyle.popover + + let setupPopover = { [unowned self] in + if let popoverPresentationController = readerModeStyleViewController.popoverPresentationController { + popoverPresentationController.backgroundColor = UIColor.white + popoverPresentationController.delegate = self + popoverPresentationController.sourceView = readerModeBar + popoverPresentationController.sourceRect = CGRect(x: readerModeBar.frame.width/2, y: UIConstants.ToolbarHeight, width: 1, height: 1) + popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirection.up + } + } + + setupPopover() + + if readerModeStyleViewController.popoverPresentationController != nil { + displayedPopoverController = readerModeStyleViewController + updateDisplayedPopoverProperties = setupPopover + } + + self.present(readerModeStyleViewController, animated: true, completion: nil) + } + + case .markAsRead: + if let url = self.tabManager.selectedTab?.url?.displayURL?.absoluteString, let result = profile.readingList?.getRecordWithURL(url) { + if let successValue = result.successValue, let record = successValue { + profile.readingList?.updateRecord(record, unread: false) // TODO Check result, can this fail? + readerModeBar.unread = false + } + } + + case .markAsUnread: + if let url = self.tabManager.selectedTab?.url?.displayURL?.absoluteString, let result = profile.readingList?.getRecordWithURL(url) { + if let successValue = result.successValue, let record = successValue { + profile.readingList?.updateRecord(record, unread: true) // TODO Check result, can this fail? + readerModeBar.unread = true + } + } + + case .addToReadingList: + if let tab = tabManager.selectedTab, + let rawURL = tab.url, rawURL.isReaderModeURL, + let url = rawURL.decodeReaderModeURL { + profile.readingList?.createRecordWithURL(url.absoluteString, title: tab.title ?? "", addedBy: UIDevice.current.name) // TODO Check result, can this fail? + readerModeBar.added = true + readerModeBar.unread = true + } + + case .removeFromReadingList: + if let url = self.tabManager.selectedTab?.url?.displayURL?.absoluteString, + let result = profile.readingList?.getRecordWithURL(url), + let successValue = result.successValue, + let record = successValue { + profile.readingList?.deleteRecord(record) // TODO Check result, can this fail? + readerModeBar.added = false + readerModeBar.unread = false + } + } + } +} + +extension BrowserViewController: IntroViewControllerDelegate { + @discardableResult func presentIntroViewController(_ force: Bool = false, animated: Bool = true) -> Bool { + if let deeplink = self.profile.prefs.stringForKey("AdjustDeeplinkKey"), let url = URL(string: deeplink) { + self.launchFxAFromDeeplinkURL(url) + return true + } + + if force || profile.prefs.intForKey(IntroViewControllerSeenProfileKey) == nil { + let introViewController = IntroViewController() + introViewController.delegate = self + // On iPad we present it modally in a controller + if topTabsVisible { + introViewController.preferredContentSize = CGSize(width: IntroViewControllerUX.Width, height: IntroViewControllerUX.Height) + introViewController.modalPresentationStyle = UIModalPresentationStyle.formSheet + } + present(introViewController, animated: animated) { + // On first run (and forced) open up the homepage in the background. + if let homePageURL = HomePageAccessors.getHomePage(self.profile.prefs), let tab = self.tabManager.selectedTab, DeviceInfo.hasConnectivity() { + tab.loadRequest(URLRequest(url: homePageURL)) + } + } + + return true + } + + return false + } + + func launchFxAFromDeeplinkURL(_ url: URL) { + self.profile.prefs.removeObjectForKey("AdjustDeeplinkKey") + var query = url.getQuery() + query["entrypoint"] = "adjust_deepklink_ios" + let fxaParams: FxALaunchParams + fxaParams = FxALaunchParams(query: query) + self.presentSignInViewController(fxaParams) + } + + func introViewControllerDidFinish(_ introViewController: IntroViewController, requestToLogin: Bool) { + self.profile.prefs.setInt(1, forKey: IntroViewControllerSeenProfileKey) + introViewController.dismiss(animated: true) { finished in + if self.navigationController?.viewControllers.count ?? 0 > 1 { + _ = self.navigationController?.popToRootViewController(animated: true) + } + + if requestToLogin { + self.presentSignInViewController() + } + } + } + + func presentSignInViewController(_ fxaOptions: FxALaunchParams? = nil) { + // Show the settings page if we have already signed in. If we haven't then show the signin page + let vcToPresent: UIViewController + if profile.hasAccount() { + let settingsTableViewController = AppSettingsTableViewController() + settingsTableViewController.profile = profile + settingsTableViewController.tabManager = tabManager + vcToPresent = settingsTableViewController + } else { + let signInVC = FxAContentViewController(profile: profile, fxaOptions: fxaOptions) + signInVC.delegate = self + signInVC.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: #selector(BrowserViewController.dismissSignInViewController)) + vcToPresent = signInVC + } + + let settingsNavigationController = SettingsNavigationController(rootViewController: vcToPresent) + settingsNavigationController.modalPresentationStyle = .formSheet + settingsNavigationController.navigationBar.isTranslucent = false + self.present(settingsNavigationController, animated: true, completion: nil) + } + + func dismissSignInViewController() { + self.dismiss(animated: true, completion: nil) + } + +} + +extension BrowserViewController: FxAContentViewControllerDelegate { + func contentViewControllerDidSignIn(_ viewController: FxAContentViewController, withFlags flags: FxALoginFlags) { + if flags.verified { + self.dismiss(animated: true, completion: nil) + } + } + + func contentViewControllerDidCancel(_ viewController: FxAContentViewController) { + self.dismiss(animated: true, completion: nil) + } +} + +extension BrowserViewController: ContextMenuHelperDelegate { + func contextMenuHelper(_ contextMenuHelper: ContextMenuHelper, didLongPressElements elements: ContextMenuHelper.Elements, gestureRecognizer: UIGestureRecognizer) { + // locationInView can return (0, 0) when the long press is triggered in an invalid page + // state (e.g., long pressing a link before the document changes, then releasing after a + // different page loads). + let touchPoint = gestureRecognizer.location(in: view) + guard touchPoint != CGPoint.zero else { return } + + let touchSize = CGSize(width: 0, height: 16) + + let actionSheetController = UIAlertController(title: nil, message: nil, preferredStyle: UIAlertControllerStyle.actionSheet) + var dialogTitle: String? + + if let url = elements.link, let currentTab = tabManager.selectedTab { + dialogTitle = url.absoluteString + let isPrivate = currentTab.isPrivate + + let addTab = { (rURL: URL, isPrivate: Bool) in + let tab = self.tabManager.addTab(URLRequest(url: rURL as URL), afterTab: currentTab, isPrivate: isPrivate) + LeanPlumClient.shared.track(event: .openedNewTab, withParameters: ["Source": "Long Press Context Menu" as AnyObject]) + guard !self.topTabsVisible else { + return + } + // We're not showing the top tabs; show a toast to quick switch to the fresh new tab. + let toast = ButtonToast(labelText: Strings.ContextMenuButtonToastNewTabOpenedLabelText, buttonText: Strings.ContextMenuButtonToastNewTabOpenedButtonText, completion: { buttonPressed in + if buttonPressed { + self.tabManager.selectTab(tab) + } + }) + self.show(buttonToast: toast) + } + + if !isPrivate { + let newTabTitle = NSLocalizedString("Open in New Tab", comment: "Context menu item for opening a link in a new tab") + let openNewTabAction = UIAlertAction(title: newTabTitle, style: UIAlertActionStyle.default) { (action: UIAlertAction) in + addTab(url, false) + } + actionSheetController.addAction(openNewTabAction) + } + + let openNewPrivateTabTitle = NSLocalizedString("Open in New Private Tab", tableName: "PrivateBrowsing", comment: "Context menu option for opening a link in a new private tab") + let openNewPrivateTabAction = UIAlertAction(title: openNewPrivateTabTitle, style: UIAlertActionStyle.default) { (action: UIAlertAction) in + addTab(url, true) + } + actionSheetController.addAction(openNewPrivateTabAction) + + let copyTitle = NSLocalizedString("Copy Link", comment: "Context menu item for copying a link URL to the clipboard") + let copyAction = UIAlertAction(title: copyTitle, style: UIAlertActionStyle.default) { (action: UIAlertAction) -> Void in + UIPasteboard.general.url = url as URL + } + actionSheetController.addAction(copyAction) + + let shareTitle = NSLocalizedString("Share Link", comment: "Context menu item for sharing a link URL") + let shareAction = UIAlertAction(title: shareTitle, style: UIAlertActionStyle.default) { _ in + self.presentActivityViewController(url as URL, sourceView: self.view, sourceRect: CGRect(origin: touchPoint, size: touchSize), arrowDirection: .any) + } + actionSheetController.addAction(shareAction) + } + + if let url = elements.image { + if dialogTitle == nil { + dialogTitle = url.absoluteString + } + + let photoAuthorizeStatus = PHPhotoLibrary.authorizationStatus() + let saveImageTitle = NSLocalizedString("Save Image", comment: "Context menu item for saving an image") + let saveImageAction = UIAlertAction(title: saveImageTitle, style: UIAlertActionStyle.default) { (action: UIAlertAction) -> Void in + if photoAuthorizeStatus == PHAuthorizationStatus.authorized || photoAuthorizeStatus == PHAuthorizationStatus.notDetermined { + self.getImage(url as URL) { + UIImageWriteToSavedPhotosAlbum($0, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil) + } + } else { + let accessDenied = UIAlertController(title: NSLocalizedString("Firefox would like to access your Photos", comment: "See http://mzl.la/1G7uHo7"), message: NSLocalizedString("This allows you to save the image to your Camera Roll.", comment: "See http://mzl.la/1G7uHo7"), preferredStyle: UIAlertControllerStyle.alert) + let dismissAction = UIAlertAction(title: UIConstants.CancelString, style: UIAlertActionStyle.default, handler: nil) + accessDenied.addAction(dismissAction) + let settingsAction = UIAlertAction(title: NSLocalizedString("Open Settings", comment: "See http://mzl.la/1G7uHo7"), style: UIAlertActionStyle.default ) { (action: UIAlertAction!) -> Void in + UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!) + } + accessDenied.addAction(settingsAction) + self.present(accessDenied, animated: true, completion: nil) + } + } + actionSheetController.addAction(saveImageAction) + + let copyImageTitle = NSLocalizedString("Copy Image", comment: "Context menu item for copying an image to the clipboard") + let copyAction = UIAlertAction(title: copyImageTitle, style: UIAlertActionStyle.default) { (action: UIAlertAction) -> Void in + // put the actual image on the clipboard + // do this asynchronously just in case we're in a low bandwidth situation + let pasteboard = UIPasteboard.general + pasteboard.url = url as URL + let changeCount = pasteboard.changeCount + let application = UIApplication.shared + var taskId: UIBackgroundTaskIdentifier = 0 + taskId = application.beginBackgroundTask (expirationHandler: { _ in + application.endBackgroundTask(taskId) + }) + + Alamofire.request(url) + .validate(statusCode: 200..<300) + .response { response in + // Only set the image onto the pasteboard if the pasteboard hasn't changed since + // fetching the image; otherwise, in low-bandwidth situations, + // we might be overwriting something that the user has subsequently added. + if changeCount == pasteboard.changeCount, let imageData = response.data, response.error == nil { + pasteboard.addImageWithData(imageData, forURL: url) + } + + application.endBackgroundTask(taskId) + } + } + actionSheetController.addAction(copyAction) + } + + // If we're showing an arrow popup, set the anchor to the long press location. + if let popoverPresentationController = actionSheetController.popoverPresentationController { + popoverPresentationController.sourceView = view + popoverPresentationController.sourceRect = CGRect(origin: touchPoint, size: touchSize) + popoverPresentationController.permittedArrowDirections = .any + popoverPresentationController.delegate = self + } + + if actionSheetController.popoverPresentationController != nil { + displayedPopoverController = actionSheetController + } + + actionSheetController.title = dialogTitle?.ellipsize(maxLength: ActionSheetTitleMaxLength) + let cancelAction = UIAlertAction(title: UIConstants.CancelString, style: UIAlertActionStyle.cancel, handler: nil) + actionSheetController.addAction(cancelAction) + self.present(actionSheetController, animated: true, completion: nil) + } + + fileprivate func getImage(_ url: URL, success: @escaping (UIImage) -> Void) { + Alamofire.request(url) + .validate(statusCode: 200..<300) + .response { response in + if let data = response.data, + let image = UIImage.dataIsGIF(data) ? UIImage.imageFromGIFDataThreadSafe(data) : UIImage.imageFromDataThreadSafe(data) { + success(image) + } + } + } + + func contextMenuHelper(_ contextMenuHelper: ContextMenuHelper, didCancelGestureRecognizer: UIGestureRecognizer) { + displayedPopoverController?.dismiss(animated: true) { + self.displayedPopoverController = nil + } + } +} + +extension BrowserViewController { + func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) { + if error == nil { + LeanPlumClient.shared.track(event: .saveImage) + } + } +} + +extension BrowserViewController: HistoryStateHelperDelegate { + func historyStateHelper(_ historyStateHelper: HistoryStateHelper, didPushOrReplaceStateInTab tab: Tab) { + navigateInTab(tab: tab) + tabManager.storeChanges() + } +} + +/** + A third party search engine Browser extension +**/ +extension BrowserViewController { + + func addCustomSearchButtonToWebView(_ webView: WKWebView) { + //check if the search engine has already been added. + let domain = webView.url?.domainURL.host + let matches = self.profile.searchEngines.orderedEngines.filter {$0.shortName == domain} + if !matches.isEmpty { + self.customSearchEngineButton.tintColor = UIColor.gray + self.customSearchEngineButton.isUserInteractionEnabled = false + } else { + self.customSearchEngineButton.tintColor = UIConstants.SystemBlueColor + self.customSearchEngineButton.isUserInteractionEnabled = true + } + + /* + This is how we access hidden views in the WKContentView + Using the public headers we can find the keyboard accessoryView which is not usually available. + Specific values here are from the WKContentView headers. + https://github.com/JaviSoto/iOS9-Runtime-Headers/blob/master/Frameworks/WebKit.framework/WKContentView.h + */ + guard let webContentView = UIView.findSubViewWithFirstResponder(webView) else { + /* + In some cases the URL bar can trigger the keyboard notification. In that case the webview isnt the first responder + and a search button should not be added. + */ + return + } + + guard let input = webContentView.perform(#selector(getter: UIResponder.inputAccessoryView)), + let inputView = input.takeUnretainedValue() as? UIInputView, + let nextButton = inputView.value(forKey: "_nextItem") as? UIBarButtonItem, + let nextButtonView = nextButton.value(forKey: "view") as? UIView else { + //failed to find the inputView instead lets use the inputAssistant + addCustomSearchButtonToInputAssistant(webContentView) + return + } + inputView.addSubview(self.customSearchEngineButton) + self.customSearchEngineButton.snp.remakeConstraints { make in + make.leading.equalTo(nextButtonView.snp.trailing).offset(20) + make.width.equalTo(inputView.snp.height) + make.top.equalTo(nextButtonView.snp.top) + make.height.equalTo(inputView.snp.height) + } + } + + /** + This adds the customSearchButton to the inputAssistant + for cases where the inputAccessoryView could not be found for example + on the iPad where it does not exist. However this only works on iOS9 + **/ + func addCustomSearchButtonToInputAssistant(_ webContentView: UIView) { + guard customSearchBarButton == nil else { + return //The searchButton is already on the keyboard + } + let inputAssistant = webContentView.inputAssistantItem + let item = UIBarButtonItem(customView: customSearchEngineButton) + customSearchBarButton = item + _ = Try(withTry: { + inputAssistant.trailingBarButtonGroups.last?.barButtonItems.append(item) + }) { (exception) in + Sentry.shared.send(message: "Failed adding custom search button to input assistant", tag: .general, severity: .error, description: "\(exception ??? "nil")") + } + } + + func addCustomSearchEngineForFocusedElement() { + guard let webView = tabManager.selectedTab?.webView else { + return + } + webView.evaluateJavaScript("__firefox__.searchQueryForField()") { (result, _) in + guard let searchQuery = result as? String, let favicon = self.tabManager.selectedTab!.displayFavicon else { + //Javascript responded with an incorrectly formatted message. Show an error. + let alert = ThirdPartySearchAlerts.failedToAddThirdPartySearch() + self.present(alert, animated: true, completion: nil) + return + } + self.addSearchEngine(searchQuery, favicon: favicon) + self.customSearchEngineButton.tintColor = UIColor.gray + self.customSearchEngineButton.isUserInteractionEnabled = false + } + } + + func addSearchEngine(_ searchQuery: String, favicon: Favicon) { + guard searchQuery != "", + let iconURL = URL(string: favicon.url), + let url = URL(string: searchQuery.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlFragmentAllowed)!), + let shortName = url.domainURL.host else { + let alert = ThirdPartySearchAlerts.failedToAddThirdPartySearch() + self.present(alert, animated: true, completion: nil) + return + } + + let alert = ThirdPartySearchAlerts.addThirdPartySearchEngine { alert in + self.customSearchEngineButton.tintColor = UIColor.gray + self.customSearchEngineButton.isUserInteractionEnabled = false + SDWebImageManager.shared().loadImage(with: iconURL, options: .continueInBackground, progress: nil) { (image, _, _, _, _, _) in + guard let image = image else { + let alert = ThirdPartySearchAlerts.failedToAddThirdPartySearch() + self.present(alert, animated: true, completion: nil) + return + } + + self.profile.searchEngines.addSearchEngine(OpenSearchEngine(engineID: nil, shortName: shortName, image: image, searchTemplate: searchQuery, suggestTemplate: nil, isCustomEngine: true)) + let Toast = SimpleToast() + Toast.showAlertWithText(Strings.ThirdPartySearchEngineAdded, bottomContainer: self.webViewContainer) + } + } + + self.present(alert, animated: true, completion: {}) + } +} + +extension BrowserViewController: KeyboardHelperDelegate { + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillShowWithState state: KeyboardState) { + keyboardState = state + updateViewConstraints() + + UIView.animate(withDuration: state.animationDuration) { + UIView.setAnimationCurve(state.animationCurve) + self.findInPageContainer.layoutIfNeeded() + self.snackBars.layoutIfNeeded() + } + + if let webView = tabManager.selectedTab?.webView { + webView.evaluateJavaScript("__firefox__.searchQueryForField()") { (result, _) in + guard let _ = result as? String else { + return + } + self.addCustomSearchButtonToWebView(webView) + } + } + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardDidShowWithState state: KeyboardState) { + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillHideWithState state: KeyboardState) { + keyboardState = nil + updateViewConstraints() + //If the searchEngineButton exists remove it form the keyboard + if let buttonGroup = customSearchBarButton?.buttonGroup { + buttonGroup.barButtonItems = buttonGroup.barButtonItems.filter { $0 != customSearchBarButton } + customSearchBarButton = nil + } + + if self.customSearchEngineButton.superview != nil { + self.customSearchEngineButton.removeFromSuperview() + } + + UIView.animate(withDuration: state.animationDuration) { + UIView.setAnimationCurve(state.animationCurve) + self.findInPageContainer.layoutIfNeeded() + self.snackBars.layoutIfNeeded() + } + } +} + +extension BrowserViewController: SessionRestoreHelperDelegate { + func sessionRestoreHelper(_ helper: SessionRestoreHelper, didRestoreSessionForTab tab: Tab) { + tab.restoring = false + + if let tab = tabManager.selectedTab, tab.webView === tab.webView { + updateUIForReaderHomeStateForTab(tab) + } + } +} + +extension BrowserViewController: TabTrayDelegate { + // This function animates and resets the tab chrome transforms when + // the tab tray dismisses. + func tabTrayDidDismiss(_ tabTray: TabTrayController) { + resetBrowserChrome() + } + + func tabTrayDidAddBookmark(_ tab: Tab) { + guard let url = tab.url?.absoluteString, url.characters.count > 0 else { return } + self.addBookmark(tab.tabState) + } + + func tabTrayDidAddToReadingList(_ tab: Tab) -> ReadingListClientRecord? { + guard let url = tab.url?.absoluteString, url.characters.count > 0 else { return nil } + return profile.readingList?.createRecordWithURL(url, title: tab.title ?? url, addedBy: UIDevice.current.name).successValue + } + + func tabTrayRequestsPresentationOf(_ viewController: UIViewController) { + self.present(viewController, animated: false, completion: nil) + } +} + +// MARK: Browser Chrome Theming +extension BrowserViewController: Themeable { + + func applyTheme(_ themeName: String) { + let ui: [Themeable?] = [urlBar, toolbar, readerModeBar, topTabsViewController] + ui.forEach { $0?.applyTheme(themeName) } + statusBarOverlay.backgroundColor = shouldShowTopTabsForTraitCollection(traitCollection) ? UIColor(rgb: 0x272727) : urlBar.backgroundColor + setNeedsStatusBarAppearanceUpdate() + } +} + +protocol Themeable { + func applyTheme(_ themeName: String) +} + +extension BrowserViewController: FindInPageBarDelegate, FindInPageHelperDelegate { + func findInPage(_ findInPage: FindInPageBar, didTextChange text: String) { + find(text, function: "find") + } + + func findInPage(_ findInPage: FindInPageBar, didFindNextWithText text: String) { + findInPageBar?.endEditing(true) + find(text, function: "findNext") + } + + func findInPage(_ findInPage: FindInPageBar, didFindPreviousWithText text: String) { + findInPageBar?.endEditing(true) + find(text, function: "findPrevious") + } + + func findInPageDidPressClose(_ findInPage: FindInPageBar) { + updateFindInPageVisibility(visible: false) + } + + fileprivate func find(_ text: String, function: String) { + guard let webView = tabManager.selectedTab?.webView else { return } + + let escaped = text.replacingOccurrences(of: "\\", with: "\\\\") + .replacingOccurrences(of: "\"", with: "\\\"") + + webView.evaluateJavaScript("__firefox__.\(function)(\"\(escaped)\")", completionHandler: nil) + } + + func findInPageHelper(_ findInPageHelper: FindInPageHelper, didUpdateCurrentResult currentResult: Int) { + findInPageBar?.currentResult = currentResult + } + + func findInPageHelper(_ findInPageHelper: FindInPageHelper, didUpdateTotalResults totalResults: Int) { + findInPageBar?.totalResults = totalResults + } +} + +extension BrowserViewController: JSPromptAlertControllerDelegate { + func promptAlertControllerDidDismiss(_ alertController: JSPromptAlertController) { + showQueuedAlertIfAvailable() + } +} + +extension BrowserViewController: TopTabsDelegate { + func topTabsDidPressTabs() { + urlBar.leaveOverlayMode(didCancel: true) + self.urlBarDidPressTabs(urlBar) + } + + func topTabsDidPressNewTab(_ isPrivate: Bool) { + openBlankNewTab(focusLocationField: false, isPrivate: isPrivate) + } + + func topTabsDidTogglePrivateMode() { + guard let selectedTab = tabManager.selectedTab else { + return + } + urlBar.leaveOverlayMode() + } + + func topTabsDidChangeTab() { + urlBar.leaveOverlayMode(didCancel: true) + } +} + +extension BrowserViewController: ClientPickerViewControllerDelegate, InstructionsViewControllerDelegate { + func instructionsViewControllerDidClose(_ instructionsViewController: InstructionsViewController) { + self.popToBVC() + } + + func clientPickerViewControllerDidCancel(_ clientPickerViewController: ClientPickerViewController) { + self.popToBVC() + } + + func clientPickerViewController(_ clientPickerViewController: ClientPickerViewController, didPickClients clients: [RemoteClient]) { + guard let tab = tabManager.selectedTab, + let url = tab.canonicalURL?.displayURL?.absoluteString else { return } + let shareItem = ShareItem(url: url, title: tab.title, favicon: tab.displayFavicon) + guard shareItem.isShareable else { + let alert = UIAlertController(title: Strings.SendToErrorTitle, message: Strings.SendToErrorMessage, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: Strings.SendToErrorOKButton, style: .default) { _ in self.popToBVC()}) + present(alert, animated: true, completion: nil) + return + } + profile.sendItems([shareItem], toClients: clients).uponQueue(DispatchQueue.main) { _ in + self.popToBVC() + } + } +} + diff --git a/mobile/ios/Client/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift b/mobile/ios/Client/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift new file mode 100644 index 0000000000..e13d08f434 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift @@ -0,0 +1,100 @@ +/* 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/. */ + +import Shared + +// Naming functions: use the suffix 'KeyCommand' for an additional level of namespacing (bug 1415830) + +extension BrowserViewController { + + @objc private func reloadTabKeyCommand() { + if homePanelController == nil { + tabManager.selectedTab?.reload() + } + } + + @objc private func goBackKeyCommand() { + if tabManager.selectedTab?.canGoBack == true && homePanelController == nil { + tabManager.selectedTab?.goBack() + } + } + + @objc private func goForwardKeyCommand() { + if tabManager.selectedTab?.canGoForward == true && homePanelController == nil { + tabManager.selectedTab?.goForward() + } + } + + @objc private func findOnPageKeyCommand() { + if homePanelController == nil { + tab( (tabManager.selectedTab)!, didSelectFindInPageForSelection: "") + } + } + + @objc private func selectLocationBarKeyCommand() { + scrollController.showToolbars(animated: true) + urlBar.tabLocationViewDidTapLocation(urlBar.locationView) + } + + @objc private func newTabKeyCommand() { + openBlankNewTab(focusLocationField: false, isPrivate: false) + } + + @objc private func newPrivateTabKeyCommand() { + openBlankNewTab(focusLocationField: false, isPrivate: true) + } + + @objc private func closeTabKeyCommand() { + guard let currentTab = tabManager.selectedTab else { + return + } + tabManager.removeTab(currentTab) + } + + @objc private func nextTabKeyCommand() { + guard let currentTab = tabManager.selectedTab else { + return + } + + let tabs = currentTab.isPrivate ? tabManager.privateTabs : tabManager.normalTabs + if let index = tabs.index(of: currentTab), index + 1 < tabs.count { + tabManager.selectTab(tabs[index + 1]) + } else if let firstTab = tabs.first { + tabManager.selectTab(firstTab) + } + } + + @objc private func previousTabKeyCommand() { + guard let currentTab = tabManager.selectedTab else { + return + } + + let tabs = currentTab.isPrivate ? tabManager.privateTabs : tabManager.normalTabs + if let index = tabs.index(of: currentTab), index - 1 < tabs.count && index != 0 { + tabManager.selectTab(tabs[index - 1]) + } else if let lastTab = tabs.last { + tabManager.selectTab(lastTab) + } + } + + override var keyCommands: [UIKeyCommand]? { + return [ + UIKeyCommand(input: "r", modifierFlags: .command, action: #selector(BrowserViewController.reloadTabKeyCommand), discoverabilityTitle: Strings.ReloadPageTitle), + UIKeyCommand(input: "[", modifierFlags: .command, action: #selector(BrowserViewController.goBackKeyCommand), discoverabilityTitle: Strings.BackTitle), + UIKeyCommand(input: UIKeyInputLeftArrow, modifierFlags: .command, action: #selector(BrowserViewController.goBackKeyCommand), discoverabilityTitle: Strings.BackTitle), + UIKeyCommand(input: "]", modifierFlags: .command, action: #selector(BrowserViewController.goForwardKeyCommand), discoverabilityTitle: Strings.ForwardTitle), + UIKeyCommand(input: UIKeyInputRightArrow, modifierFlags: .command, action: #selector(BrowserViewController.goForwardKeyCommand), discoverabilityTitle: Strings.ForwardTitle), + + UIKeyCommand(input: "f", modifierFlags: .command, action: #selector(BrowserViewController.findOnPageKeyCommand), discoverabilityTitle: Strings.FindTitle), + UIKeyCommand(input: "l", modifierFlags: .command, action: #selector(BrowserViewController.selectLocationBarKeyCommand), discoverabilityTitle: Strings.SelectLocationBarTitle), + UIKeyCommand(input: "t", modifierFlags: .command, action: #selector(BrowserViewController.newTabKeyCommand), discoverabilityTitle: Strings.NewTabTitle), + UIKeyCommand(input: "p", modifierFlags: [.command, .shift], action: #selector(BrowserViewController.newPrivateTabKeyCommand), discoverabilityTitle: Strings.NewPrivateTabTitle), + UIKeyCommand(input: "w", modifierFlags: .command, action: #selector(BrowserViewController.closeTabKeyCommand), discoverabilityTitle: Strings.CloseTabTitle), + UIKeyCommand(input: "\t", modifierFlags: .control, action: #selector(BrowserViewController.nextTabKeyCommand), discoverabilityTitle: Strings.ShowNextTabTitle), + UIKeyCommand(input: UIKeyInputRightArrow, modifierFlags: [.command, .shift], action: #selector(BrowserViewController.nextTabKeyCommand), discoverabilityTitle: Strings.ShowNextTabTitle), + UIKeyCommand(input: "\t", modifierFlags: [.control, .shift], action: #selector(BrowserViewController.previousTabKeyCommand), discoverabilityTitle: Strings.ShowPreviousTabTitle), + UIKeyCommand(input: UIKeyInputLeftArrow, modifierFlags: [.command, .shift], action: #selector(BrowserViewController.previousTabKeyCommand), discoverabilityTitle: Strings.ShowPreviousTabTitle), + ] + } +} diff --git a/mobile/ios/Client/Frontend/Browser/BrowserViewController/BrowserViewController+WKNavigationDelegate.swift b/mobile/ios/Client/Frontend/Browser/BrowserViewController/BrowserViewController+WKNavigationDelegate.swift new file mode 100644 index 0000000000..aaeb4e5978 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/BrowserViewController/BrowserViewController+WKNavigationDelegate.swift @@ -0,0 +1,212 @@ +/* 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/. */ + +import Foundation +import WebKit +import Shared + +private let log = Logger.browserLogger + +extension WKNavigationAction { + /// Allow local requests only if the request is privileged. + var isAllowed: Bool { + guard let url = request.url else { + return true + } + + return !url.isWebPage(includeDataURIs: false) || !url.isLocal || request.isPrivileged + } +} + +extension BrowserViewController: WKNavigationDelegate { + func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { + if tabManager.selectedTab?.webView !== webView { + return + } + + updateFindInPageVisibility(visible: false) + + // If we are going to navigate to a new page, hide the reader mode button. Unless we + // are going to a about:reader page. Then we keep it on screen: it will change status + // (orange color) as soon as the page has loaded. + if let url = webView.url { + if !url.isReaderModeURL { + urlBar.updateReaderModeState(ReaderModeState.unavailable) + hideReaderModeBar(animated: false) + } + + // remove the open in overlay view if it is present + removeOpenInView() + } + } + + // Recognize an Apple Maps URL. This will trigger the native app. But only if a search query is present. Otherwise + // it could just be a visit to a regular page on maps.apple.com. + fileprivate func isAppleMapsURL(_ url: URL) -> Bool { + if url.scheme == "http" || url.scheme == "https" { + if url.host == "maps.apple.com" && url.query != nil { + return true + } + } + return false + } + + // Recognize a iTunes Store URL. These all trigger the native apps. Note that appstore.com and phobos.apple.com + // used to be in this list. I have removed them because they now redirect to itunes.apple.com. If we special case + // them then iOS will actually first open Safari, which then redirects to the app store. This works but it will + // leave a 'Back to Safari' button in the status bar, which we do not want. + fileprivate func isStoreURL(_ url: URL) -> Bool { + if url.scheme == "http" || url.scheme == "https" { + if url.host == "itunes.apple.com" { + return true + } + } + return false + } + + // This is the place where we decide what to do with a new navigation action. There are a number of special schemes + // and http(s) urls that need to be handled in a different way. All the logic for that is inside this delegate + // method. + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + guard let url = navigationAction.request.url else { + decisionHandler(WKNavigationActionPolicy.cancel) + return + } + + if url.scheme == "about" { + decisionHandler(WKNavigationActionPolicy.allow) + return + } + + if !navigationAction.isAllowed && navigationAction.navigationType != .backForward { + log.warning("Denying unprivileged request: \(navigationAction.request)") + decisionHandler(WKNavigationActionPolicy.cancel) + return + } + + // First special case are some schemes that are about Calling. We prompt the user to confirm this action. This + // gives us the exact same behaviour as Safari. + if url.scheme == "tel" || url.scheme == "facetime" || url.scheme == "facetime-audio" { + UIApplication.shared.openURL(url) + decisionHandler(WKNavigationActionPolicy.cancel) + return + } + + // Second special case are a set of URLs that look like regular http links, but should be handed over to iOS + // instead of being loaded in the webview. Note that there is no point in calling canOpenURL() here, because + // iOS will always say yes. TODO Is this the same as isWhitelisted? + + if isAppleMapsURL(url) { + UIApplication.shared.openURL(url) + decisionHandler(WKNavigationActionPolicy.cancel) + return + } + + if let tab = tabManager.selectedTab, isStoreURL(url) { + decisionHandler(WKNavigationActionPolicy.cancel) + + let alreadyShowingSnackbarOnThisTab = tab.bars.count > 0 + if !alreadyShowingSnackbarOnThisTab { + TimerSnackBar.showAppStoreConfirmationBar(forTab: tab, appStoreURL: url) + } + + return + } + + // Handles custom mailto URL schemes. + if url.scheme == "mailto" { + if let mailToMetadata = url.mailToMetadata(), let mailScheme = self.profile.prefs.stringForKey(PrefsKeys.KeyMailToOption), mailScheme != "mailto" { + self.mailtoLinkHandler.launchMailClientForScheme(mailScheme, metadata: mailToMetadata, defaultMailtoURL: url) + } else { + UIApplication.shared.openURL(url) + } + + LeanPlumClient.shared.track(event: .openedMailtoLink) + decisionHandler(WKNavigationActionPolicy.cancel) + return + } + + // This is the normal case, opening a http or https url, which we handle by loading them in this WKWebView. We + // always allow this. Additionally, data URIs are also handled just like normal web pages. + + if url.scheme == "http" || url.scheme == "https" || url.scheme == "data" || url.scheme == "blob" { + if navigationAction.navigationType == .linkActivated { + resetSpoofedUserAgentIfRequired(webView, newURL: url) + } else if navigationAction.navigationType == .backForward { + restoreSpoofedUserAgentIfRequired(webView, newRequest: navigationAction.request) + } + decisionHandler(WKNavigationActionPolicy.allow) + return + } + + // Ignore JS navigated links, the intention is to match Safari and native WKWebView behaviour. + if navigationAction.navigationType == .linkActivated { + UIApplication.shared.open(url, options: [:]) { openedURL in + if !openedURL { + let alert = UIAlertController(title: Strings.UnableToOpenURLErrorTitle, message: Strings.UnableToOpenURLError, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: UIConstants.OKString, style: UIAlertActionStyle.default, handler: nil)) + self.present(alert, animated: true, completion: nil) + } + } + } + decisionHandler(WKNavigationActionPolicy.cancel) + } + + func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + + // If this is a certificate challenge, see if the certificate has previously been + // accepted by the user. + let origin = "\(challenge.protectionSpace.host):\(challenge.protectionSpace.port)" + if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, + let trust = challenge.protectionSpace.serverTrust, + let cert = SecTrustGetCertificateAtIndex(trust, 0), profile.certStore.containsCertificate(cert, forOrigin: origin) { + completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: trust)) + return + } + + guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic || + challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPDigest || + challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM, + let tab = tabManager[webView] else { + completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil) + return + } + + // If this is a request to our local web server, use our private credentials. + if challenge.protectionSpace.host == "localhost" && challenge.protectionSpace.port == Int(WebServer.sharedInstance.server.port) { + completionHandler(.useCredential, WebServer.sharedInstance.credentials) + return + } + + // The challenge may come from a background tab, so ensure it's the one visible. + tabManager.selectTab(tab) + + let loginsHelper = tab.getContentScript(name: LoginsHelper.name()) as? LoginsHelper + Authenticator.handleAuthRequest(self, challenge: challenge, loginsHelper: loginsHelper).uponQueue(DispatchQueue.main) { res in + if let credentials = res.successValue { + completionHandler(.useCredential, credentials.credentials) + } else { + completionHandler(URLSession.AuthChallengeDisposition.rejectProtectionSpace, nil) + } + } + } + + func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { + guard let tab = tabManager[webView] else { return } + + tab.url = webView.url + self.scrollController.resetZoomState() + + if tabManager.selectedTab === tab { + updateUIForReaderHomeStateForTab(tab) + } + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + if let tab = tabManager[webView] { + navigateInTab(tab: tab, to: navigation) + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/ButtonToast.swift b/mobile/ios/Client/Frontend/Browser/ButtonToast.swift new file mode 100644 index 0000000000..2d6b9f90e3 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/ButtonToast.swift @@ -0,0 +1,181 @@ +/* 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/. */ + +import Foundation +import Shared +import SnapKit + +struct ButtonToastUX { + static let ToastPadding = 15.0 + static let TitleSpacing = 2.0 + static let ToastButtonPadding: CGFloat = 10.0 + static let TitleButtonPadding: CGFloat = 5.0 + static let ToastDelay = DispatchTimeInterval.milliseconds(900) + static let ToastButtonBorderRadius: CGFloat = 5 + static let ToastButtonBorderWidth: CGFloat = 1 +} + +private class HighlightableButton: UIButton { + override var isHighlighted: Bool { + didSet { + if isHighlighted { + self.backgroundColor = UIColor.white + } else { + self.backgroundColor = UIColor.clear + } + } + } +} + +class ButtonToast: UIView { + + fileprivate var dismissed = false + fileprivate var completionHandler: ((Bool) -> Void)? + fileprivate lazy var toast: UIView = { + let toast = UIView() + toast.backgroundColor = SimpleToastUX.ToastDefaultColor + return toast + }() + fileprivate var animationConstraint: Constraint? + fileprivate lazy var gestureRecognizer: UITapGestureRecognizer = { + let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ButtonToast.handleTap(_:))) + gestureRecognizer.cancelsTouchesInView = false + return gestureRecognizer + }() + + init(labelText: String, descriptionText: String? = nil, buttonText: String, completion:@escaping (_ buttonPressed: Bool) -> Void) { + super.init(frame: CGRect.zero) + completionHandler = completion + + self.clipsToBounds = true + self.addSubview(createView(labelText, descriptionText: descriptionText, buttonText: buttonText)) + + toast.snp.makeConstraints { make in + make.left.right.height.equalTo(self) + animationConstraint = make.top.equalTo(self).offset(SimpleToastUX.ToastHeight).constraint + } + self.snp.makeConstraints { make in + make.height.equalTo(SimpleToastUX.ToastHeight) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + fileprivate func createView(_ labelText: String, descriptionText: String?, buttonText: String) -> UIView { + let label = UILabel() + label.textColor = UIColor.white + label.font = SimpleToastUX.ToastFont + label.text = labelText + label.lineBreakMode = .byWordWrapping + label.numberOfLines = 0 + toast.addSubview(label) + + let button = HighlightableButton() + button.layer.cornerRadius = ButtonToastUX.ToastButtonBorderRadius + button.layer.borderWidth = ButtonToastUX.ToastButtonBorderWidth + button.layer.borderColor = UIColor.white.cgColor + button.setTitle(buttonText, for: UIControlState()) + button.setTitleColor(self.toast.backgroundColor, for: .highlighted) + button.titleLabel?.font = SimpleToastUX.ToastFont + button.titleLabel?.numberOfLines = 1 + button.titleLabel?.lineBreakMode = .byClipping + button.titleLabel?.adjustsFontSizeToFitWidth = true + button.titleLabel?.minimumScaleFactor = 0.1 + + let recognizer = UITapGestureRecognizer(target: self, action: #selector(ButtonToast.buttonPressed(_:))) + button.addGestureRecognizer(recognizer) + toast.addSubview(button) + var descriptionLabel: UILabel? + + if let text = descriptionText { + let textLabel = UILabel() + textLabel.textColor = UIColor.white + textLabel.font = SimpleToastUX.ToastFont + textLabel.text = text + textLabel.lineBreakMode = .byTruncatingTail + toast.addSubview(textLabel) + descriptionLabel = textLabel + } + + if let description = descriptionLabel { + label.numberOfLines = 1 // if showing a description we cant wrap to the second line + label.lineBreakMode = .byClipping + label.adjustsFontSizeToFitWidth = true + label.snp.makeConstraints { (make) in + make.leading.equalTo(toast).offset(ButtonToastUX.ToastPadding) + make.top.equalTo(toast).offset(ButtonToastUX.TitleButtonPadding) + make.trailing.equalTo(button.snp.leading).offset(-ButtonToastUX.TitleButtonPadding) + } + description.snp.makeConstraints { (make) in + make.leading.equalTo(toast).offset(ButtonToastUX.ToastPadding) + make.top.equalTo(label.snp.bottom).offset(ButtonToastUX.TitleSpacing) + make.trailing.equalTo(button.snp.leading).offset(-ButtonToastUX.TitleButtonPadding) + } + } else { + label.snp.makeConstraints { (make) in + make.leading.equalTo(toast).offset(ButtonToastUX.ToastPadding) + make.centerY.equalTo(toast) + make.trailing.equalTo(button.snp.leading).offset(-ButtonToastUX.TitleButtonPadding) + } + } + + button.snp.makeConstraints { (make) in + make.trailing.equalTo(toast).offset(-ButtonToastUX.ToastPadding) + make.centerY.equalTo(toast) + make.width.equalTo(button.titleLabel!.intrinsicContentSize.width + 2*ButtonToastUX.ToastButtonPadding) + } + + return toast + } + + fileprivate func dismiss(_ buttonPressed: Bool) { + guard dismissed == false else { + return + } + dismissed = true + superview?.removeGestureRecognizer(gestureRecognizer) + + UIView.animate(withDuration: SimpleToastUX.ToastAnimationDuration, animations: { + self.animationConstraint?.update(offset: SimpleToastUX.ToastHeight) + self.layoutIfNeeded() + }, + completion: { finished in + self.removeFromSuperview() + if !buttonPressed { + self.completionHandler?(false) + } + } + ) + } + + func showToast(duration: DispatchTimeInterval = SimpleToastUX.ToastDismissAfter) { + layoutIfNeeded() + UIView.animate(withDuration: SimpleToastUX.ToastAnimationDuration, animations: { + self.animationConstraint?.update(offset: 0) + self.layoutIfNeeded() + }, + completion: { finished in + DispatchQueue.main.asyncAfter(deadline: .now() + duration) { + self.dismiss(false) + } + } + ) + } + + @objc func buttonPressed(_ gestureRecognizer: UIGestureRecognizer) { + self.completionHandler?(true) + self.dismiss(true) + } + + override func didMoveToSuperview() { + super.didMoveToSuperview() + superview?.addGestureRecognizer(gestureRecognizer) + } + + func handleTap(_ gestureRecognizer: UIGestureRecognizer) { + dismiss(false) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/ClipboardBarDisplayHandler.swift b/mobile/ios/Client/Frontend/Browser/ClipboardBarDisplayHandler.swift new file mode 100644 index 0000000000..794b27f828 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/ClipboardBarDisplayHandler.swift @@ -0,0 +1,162 @@ +/* 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/. */ + +import Foundation +import Shared + +public struct ClipboardBarToastUX { + static let ToastDelay = DispatchTimeInterval.milliseconds(4000) +} + +protocol ClipboardBarDisplayHandlerDelegate: class { + func shouldDisplay(clipboardBar bar: ButtonToast) +} + +class ClipboardBarDisplayHandler: NSObject, URLChangeDelegate { + weak var delegate: (ClipboardBarDisplayHandlerDelegate & SettingsDelegate)? + weak var settingsDelegate: SettingsDelegate? + weak var tabManager: TabManager? + private var sessionStarted = true + private var sessionRestored = false + private var firstTabLoaded = false + private var prefs: Prefs + private var lastDisplayedURL: String? + private weak var firstTab: Tab? + var clipboardToast: ButtonToast? + + init(prefs: Prefs, tabManager: TabManager) { + self.prefs = prefs + self.tabManager = tabManager + + super.init() + + NotificationCenter.default.addObserver(self, selector: #selector(SELUIPasteboardChanged), name: NSNotification.Name.UIPasteboardChanged, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(SELAppWillEnterForegroundNotification), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(SELDidRestoreSession), name: NotificationDidRestoreSession, object: nil) + } + + @objc private func SELUIPasteboardChanged() { + // UIPasteboardChanged gets triggered when calling UIPasteboard.general. + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIPasteboardChanged, object: nil) + + UIPasteboard.general.asyncURL().uponQueue(.main) { res in + defer { + NotificationCenter.default.addObserver(self, selector: #selector(self.SELUIPasteboardChanged), name: NSNotification.Name.UIPasteboardChanged, object: nil) + } + + guard let copiedURL: URL? = res.successValue, + let url = copiedURL else { + return + } + self.lastDisplayedURL = url.absoluteString + } + } + + @objc private func SELAppWillEnterForegroundNotification() { + sessionStarted = true + checkIfShouldDisplayBar() + } + + private func observeURLForFirstTab(firstTab: Tab) { + if firstTab.webView == nil { + // Nothing to do; bail out. + firstTabLoaded = true + return + } + self.firstTab = firstTab + firstTab.observeURLChanges(delegate: self) + } + + @objc private func SELDidRestoreSession() { + DispatchQueue.main.sync { + if let tabManager = self.tabManager, + let firstTab = tabManager.selectedTab { + self.observeURLForFirstTab(firstTab: firstTab) + } else { + firstTabLoaded = true + } + + NotificationCenter.default.removeObserver(self, name: NotificationDidRestoreSession, object: nil) + + sessionRestored = true + checkIfShouldDisplayBar() + } + } + + func tab(_ tab: Tab, urlDidChangeTo url: URL) { + // Ugly hack to ensure we wait until we're finished restoring the session on the first tab + // before checking if we should display the clipboard bar. + guard sessionRestored, + !url.absoluteString.startsWith("\(WebServer.sharedInstance.base)/about/sessionrestore?history=") else { + return + } + + tab.removeURLChangeObserver(delegate: self) + firstTabLoaded = true + checkIfShouldDisplayBar() + } + + private func shouldDisplayBar(_ copiedURL: String) -> Bool { + if !sessionStarted || + !sessionRestored || + !firstTabLoaded || + isClipboardURLAlreadyDisplayed(copiedURL) || + self.prefs.intForKey(IntroViewControllerSeenProfileKey) == nil { + return false + } + sessionStarted = false + return true + } + + // If we already displayed this URL on the previous session, or in an already open + // tab, we shouldn't display it again + private func isClipboardURLAlreadyDisplayed(_ clipboardURL: String) -> Bool { + if lastDisplayedURL == clipboardURL { + return true + } + + if let url = URL(string: clipboardURL), + let _ = tabManager?.getTabFor(url) { + return true + } + return false + } + + func checkIfShouldDisplayBar() { + guard self.prefs.boolForKey("showClipboardBar") ?? false else { + // There's no point in doing any of this work unless the + // user has asked for it in settings. + return + } + UIPasteboard.general.asyncURL().uponQueue(.main) { res in + guard let copiedURL: URL? = res.successValue, + let url = copiedURL else { + return + } + + let absoluteString = url.absoluteString + + guard self.shouldDisplayBar(absoluteString) else { + return + } + + self.lastDisplayedURL = absoluteString + + self.clipboardToast = + ButtonToast( + labelText: Strings.GoToCopiedLink, + descriptionText: url.absoluteDisplayString, + buttonText: Strings.GoButtonTittle, + completion: { buttonPressed in + if buttonPressed { + self.delegate?.settingsOpenURLInNewTab(url) + } + }) + + if let toast = self.clipboardToast { + self.delegate?.shouldDisplay(clipboardBar: toast) + } + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/ContextMenuHelper.swift b/mobile/ios/Client/Frontend/Browser/ContextMenuHelper.swift new file mode 100644 index 0000000000..b3873facf9 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/ContextMenuHelper.swift @@ -0,0 +1,108 @@ +/* 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/. */ + +import WebKit + +protocol ContextMenuHelperDelegate: class { + func contextMenuHelper(_ contextMenuHelper: ContextMenuHelper, didLongPressElements elements: ContextMenuHelper.Elements, gestureRecognizer: UIGestureRecognizer) + func contextMenuHelper(_ contextMenuHelper: ContextMenuHelper, didCancelGestureRecognizer: UIGestureRecognizer) +} + +class ContextMenuHelper: NSObject { + struct Elements { + let link: URL? + let image: URL? + } + + fileprivate weak var tab: Tab? + + weak var delegate: ContextMenuHelperDelegate? + + fileprivate var nativeHighlightLongPressRecognizer: UILongPressGestureRecognizer? + fileprivate var elements: Elements? + + required init(tab: Tab) { + super.init() + + self.tab = tab + + guard let path = Bundle.main.path(forResource: "ContextMenu", ofType: "js"), + let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String, + let webView = tab.webView else { + return + } + + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false) + webView.configuration.userContentController.addUserScript(userScript) + + nativeHighlightLongPressRecognizer = gestureRecognizerWithDescriptionFragment("action=_highlightLongPressRecognized:") as? UILongPressGestureRecognizer + + if let nativeLongPressRecognizer = gestureRecognizerWithDescriptionFragment("action=_longPressRecognized:") as? UILongPressGestureRecognizer { + nativeLongPressRecognizer.removeTarget(nil, action: nil) + nativeLongPressRecognizer.addTarget(self, action: #selector(longPressGestureDetected(_:))) + } + } + + func gestureRecognizerWithDescriptionFragment(_ descriptionFragment: String) -> UIGestureRecognizer? { + return tab?.webView?.scrollView.subviews.flatMap({ $0.gestureRecognizers }).joined().first(where: { $0.description.contains(descriptionFragment) }) + } + + func longPressGestureDetected(_ sender: UIGestureRecognizer) { + if sender.state == .cancelled { + delegate?.contextMenuHelper(self, didCancelGestureRecognizer: sender) + return + } + + guard sender.state == .began, let elements = self.elements else { + return + } + + delegate?.contextMenuHelper(self, didLongPressElements: elements, gestureRecognizer: sender) + + // To prevent the tapped link from proceeding with navigation, "cancel" the native WKWebView + // `_highlightLongPressRecognizer`. This preserves the original behavior as seen here: + // https://github.com/WebKit/webkit/blob/d591647baf54b4b300ca5501c21a68455429e182/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm#L1600-L1614 + if let nativeHighlightLongPressRecognizer = self.nativeHighlightLongPressRecognizer, + nativeHighlightLongPressRecognizer.isEnabled { + nativeHighlightLongPressRecognizer.isEnabled = false + nativeHighlightLongPressRecognizer.isEnabled = true + } + + self.elements = nil + } +} + +extension ContextMenuHelper: TabContentScript { + class func name() -> String { + return "ContextMenuHelper" + } + + func scriptMessageHandlerName() -> String? { + return "contextMenuMessageHandler" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + guard let data = message.body as? [String: AnyObject] else { + return + } + + var linkURL: URL? + if let urlString = data["link"] as? String, + let escapedURLString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.URLAllowedCharacterSet()) { + linkURL = URL(string: escapedURLString) + } + + var imageURL: URL? + if let urlString = data["image"] as? String, + let escapedURLString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.URLAllowedCharacterSet()) { + imageURL = URL(string: escapedURLString) + } + + if linkURL != nil || imageURL != nil { + elements = Elements(link: linkURL, image: imageURL) + } else { + elements = nil + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/CustomSearchHandler.swift b/mobile/ios/Client/Frontend/Browser/CustomSearchHandler.swift new file mode 100644 index 0000000000..b2de348309 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/CustomSearchHandler.swift @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +import WebKit + +class CustomSearchHelper: TabContentScript { + fileprivate weak var tab: Tab? + + required init(tab: Tab) { + self.tab = tab + if let path = Bundle.main.path(forResource: "CustomSearchHelper", ofType: "js") { + if let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + } + + func scriptMessageHandlerName() -> String? { + return "customSearchHelper" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + //We don't listen to messages because the BVC calls the searchHelper script by itself. + } + + class func name() -> String { + return "CustomSearchHelper" + } +} diff --git a/mobile/ios/Client/Frontend/Browser/ErrorPageHelper.swift b/mobile/ios/Client/Frontend/Browser/ErrorPageHelper.swift new file mode 100644 index 0000000000..9dfbe936b0 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/ErrorPageHelper.swift @@ -0,0 +1,298 @@ +/* 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/. */ + +import Foundation +import WebKit +import GCDWebServers +import Shared +import Storage + +class ErrorPageHelper { + static let MozDomain = "mozilla" + static let MozErrorDownloadsNotEnabled = 100 + + fileprivate static let MessageOpenInSafari = "openInSafari" + fileprivate static let MessageCertVisitOnce = "certVisitOnce" + + // When an error page is intentionally loaded, its added to this set. If its in the set, we show + // it as an error page. If its not, we assume someone is trying to reload this page somehow, and + // we'll instead redirect back to the original URL. + fileprivate static var redirecting = [URL]() + + fileprivate static weak var certStore: CertStore? + + // Regardless of cause, NSURLErrorServerCertificateUntrusted is currently returned in all cases. + // Check the other cases in case this gets fixed in the future. + fileprivate static let CertErrors = [ + NSURLErrorServerCertificateUntrusted, + NSURLErrorServerCertificateHasBadDate, + NSURLErrorServerCertificateHasUnknownRoot, + NSURLErrorServerCertificateNotYetValid + ] + + // Error codes copied from Gecko. The ints corresponding to these codes were determined + // by inspecting the NSError in each of these cases. + fileprivate static let CertErrorCodes = [ + -9813: "SEC_ERROR_UNKNOWN_ISSUER", + -9814: "SEC_ERROR_EXPIRED_CERTIFICATE", + -9843: "SSL_ERROR_BAD_CERT_DOMAIN", + ] + + class func cfErrorToName(_ err: CFNetworkErrors) -> String { + switch err { + case .cfHostErrorHostNotFound: return "CFHostErrorHostNotFound" + case .cfHostErrorUnknown: return "CFHostErrorUnknown" + case .cfsocksErrorUnknownClientVersion: return "CFSOCKSErrorUnknownClientVersion" + case .cfsocksErrorUnsupportedServerVersion: return "CFSOCKSErrorUnsupportedServerVersion" + case .cfsocks4ErrorRequestFailed: return "CFSOCKS4ErrorRequestFailed" + case .cfsocks4ErrorIdentdFailed: return "CFSOCKS4ErrorIdentdFailed" + case .cfsocks4ErrorIdConflict: return "CFSOCKS4ErrorIdConflict" + case .cfsocks4ErrorUnknownStatusCode: return "CFSOCKS4ErrorUnknownStatusCode" + case .cfsocks5ErrorBadState: return "CFSOCKS5ErrorBadState" + case .cfsocks5ErrorBadResponseAddr: return "CFSOCKS5ErrorBadResponseAddr" + case .cfsocks5ErrorBadCredentials: return "CFSOCKS5ErrorBadCredentials" + case .cfsocks5ErrorUnsupportedNegotiationMethod: return "CFSOCKS5ErrorUnsupportedNegotiationMethod" + case .cfsocks5ErrorNoAcceptableMethod: return "CFSOCKS5ErrorNoAcceptableMethod" + case .cfftpErrorUnexpectedStatusCode: return "CFFTPErrorUnexpectedStatusCode" + case .cfErrorHTTPAuthenticationTypeUnsupported: return "CFErrorHTTPAuthenticationTypeUnsupported" + case .cfErrorHTTPBadCredentials: return "CFErrorHTTPBadCredentials" + case .cfErrorHTTPConnectionLost: return "CFErrorHTTPConnectionLost" + case .cfErrorHTTPParseFailure: return "CFErrorHTTPParseFailure" + case .cfErrorHTTPRedirectionLoopDetected: return "CFErrorHTTPRedirectionLoopDetected" + case .cfErrorHTTPBadURL: return "CFErrorHTTPBadURL" + case .cfErrorHTTPProxyConnectionFailure: return "CFErrorHTTPProxyConnectionFailure" + case .cfErrorHTTPBadProxyCredentials: return "CFErrorHTTPBadProxyCredentials" + case .cfErrorPACFileError: return "CFErrorPACFileError" + case .cfErrorPACFileAuth: return "CFErrorPACFileAuth" + case .cfErrorHTTPSProxyConnectionFailure: return "CFErrorHTTPSProxyConnectionFailure" + case .cfStreamErrorHTTPSProxyFailureUnexpectedResponseToCONNECTMethod: return "CFStreamErrorHTTPSProxyFailureUnexpectedResponseToCONNECTMethod" + + case .cfurlErrorBackgroundSessionInUseByAnotherProcess: return "CFURLErrorBackgroundSessionInUseByAnotherProcess" + case .cfurlErrorBackgroundSessionWasDisconnected: return "CFURLErrorBackgroundSessionWasDisconnected" + case .cfurlErrorUnknown: return "CFURLErrorUnknown" + case .cfurlErrorCancelled: return "CFURLErrorCancelled" + case .cfurlErrorBadURL: return "CFURLErrorBadURL" + case .cfurlErrorTimedOut: return "CFURLErrorTimedOut" + case .cfurlErrorUnsupportedURL: return "CFURLErrorUnsupportedURL" + case .cfurlErrorCannotFindHost: return "CFURLErrorCannotFindHost" + case .cfurlErrorCannotConnectToHost: return "CFURLErrorCannotConnectToHost" + case .cfurlErrorNetworkConnectionLost: return "CFURLErrorNetworkConnectionLost" + case .cfurlErrorDNSLookupFailed: return "CFURLErrorDNSLookupFailed" + case .cfurlErrorHTTPTooManyRedirects: return "CFURLErrorHTTPTooManyRedirects" + case .cfurlErrorResourceUnavailable: return "CFURLErrorResourceUnavailable" + case .cfurlErrorNotConnectedToInternet: return "CFURLErrorNotConnectedToInternet" + case .cfurlErrorRedirectToNonExistentLocation: return "CFURLErrorRedirectToNonExistentLocation" + case .cfurlErrorBadServerResponse: return "CFURLErrorBadServerResponse" + case .cfurlErrorUserCancelledAuthentication: return "CFURLErrorUserCancelledAuthentication" + case .cfurlErrorUserAuthenticationRequired: return "CFURLErrorUserAuthenticationRequired" + case .cfurlErrorZeroByteResource: return "CFURLErrorZeroByteResource" + case .cfurlErrorCannotDecodeRawData: return "CFURLErrorCannotDecodeRawData" + case .cfurlErrorCannotDecodeContentData: return "CFURLErrorCannotDecodeContentData" + case .cfurlErrorCannotParseResponse: return "CFURLErrorCannotParseResponse" + case .cfurlErrorInternationalRoamingOff: return "CFURLErrorInternationalRoamingOff" + case .cfurlErrorCallIsActive: return "CFURLErrorCallIsActive" + case .cfurlErrorDataNotAllowed: return "CFURLErrorDataNotAllowed" + case .cfurlErrorRequestBodyStreamExhausted: return "CFURLErrorRequestBodyStreamExhausted" + case .cfurlErrorFileDoesNotExist: return "CFURLErrorFileDoesNotExist" + case .cfurlErrorFileIsDirectory: return "CFURLErrorFileIsDirectory" + case .cfurlErrorNoPermissionsToReadFile: return "CFURLErrorNoPermissionsToReadFile" + case .cfurlErrorDataLengthExceedsMaximum: return "CFURLErrorDataLengthExceedsMaximum" + case .cfurlErrorSecureConnectionFailed: return "CFURLErrorSecureConnectionFailed" + case .cfurlErrorServerCertificateHasBadDate: return "CFURLErrorServerCertificateHasBadDate" + case .cfurlErrorServerCertificateUntrusted: return "CFURLErrorServerCertificateUntrusted" + case .cfurlErrorServerCertificateHasUnknownRoot: return "CFURLErrorServerCertificateHasUnknownRoot" + case .cfurlErrorServerCertificateNotYetValid: return "CFURLErrorServerCertificateNotYetValid" + case .cfurlErrorClientCertificateRejected: return "CFURLErrorClientCertificateRejected" + case .cfurlErrorClientCertificateRequired: return "CFURLErrorClientCertificateRequired" + case .cfurlErrorCannotLoadFromNetwork: return "CFURLErrorCannotLoadFromNetwork" + case .cfurlErrorCannotCreateFile: return "CFURLErrorCannotCreateFile" + case .cfurlErrorCannotOpenFile: return "CFURLErrorCannotOpenFile" + case .cfurlErrorCannotCloseFile: return "CFURLErrorCannotCloseFile" + case .cfurlErrorCannotWriteToFile: return "CFURLErrorCannotWriteToFile" + case .cfurlErrorCannotRemoveFile: return "CFURLErrorCannotRemoveFile" + case .cfurlErrorCannotMoveFile: return "CFURLErrorCannotMoveFile" + case .cfurlErrorDownloadDecodingFailedMidStream: return "CFURLErrorDownloadDecodingFailedMidStream" + case .cfurlErrorDownloadDecodingFailedToComplete: return "CFURLErrorDownloadDecodingFailedToComplete" + + case .cfhttpCookieCannotParseCookieFile: return "CFHTTPCookieCannotParseCookieFile" + case .cfNetServiceErrorUnknown: return "CFNetServiceErrorUnknown" + case .cfNetServiceErrorCollision: return "CFNetServiceErrorCollision" + case .cfNetServiceErrorNotFound: return "CFNetServiceErrorNotFound" + case .cfNetServiceErrorInProgress: return "CFNetServiceErrorInProgress" + case .cfNetServiceErrorBadArgument: return "CFNetServiceErrorBadArgument" + case .cfNetServiceErrorCancel: return "CFNetServiceErrorCancel" + case .cfNetServiceErrorInvalid: return "CFNetServiceErrorInvalid" + case .cfNetServiceErrorTimeout: return "CFNetServiceErrorTimeout" + case .cfNetServiceErrorDNSServiceFailure: return "CFNetServiceErrorDNSServiceFailure" + default: return "Unknown" + } + } + + class func register(_ server: WebServer, certStore: CertStore?) { + self.certStore = certStore + + server.registerHandlerForMethod("GET", module: "errors", resource: "error.html", handler: { (request) -> GCDWebServerResponse! in + guard let url = request?.url.originalURLFromErrorURL else { + return GCDWebServerResponse(statusCode: 404) + } + + guard let index = self.redirecting.index(of: url) else { + return GCDWebServerDataResponse(redirect: url, permanent: false) + } + + self.redirecting.remove(at: index) + + guard let code = request?.query["code"] as? String, + let errCode = Int(code), + let errDescription = request?.query["description"] as? String, + let errURLString = request?.query["url"] as? String, + let errURLDomain = URL(string: errURLString)?.host, + var errDomain = request?.query["domain"] as? String else { + return GCDWebServerResponse(statusCode: 404) + } + + var asset = Bundle.main.path(forResource: "NetError", ofType: "html") + var variables = [ + "error_code": "\(errCode)", + "error_title": errDescription, + "short_description": errDomain, + ] + + let tryAgain = NSLocalizedString("Try again", tableName: "ErrorPages", comment: "Shown in error pages on a button that will try to load the page again") + var actions = "" + + if errDomain == kCFErrorDomainCFNetwork as String { + if let code = CFNetworkErrors(rawValue: Int32(errCode)) { + errDomain = self.cfErrorToName(code) + } + } else if errDomain == ErrorPageHelper.MozDomain { + if errCode == ErrorPageHelper.MozErrorDownloadsNotEnabled { + let downloadInSafari = NSLocalizedString("Open in Safari", tableName: "ErrorPages", comment: "Shown in error pages for files that can't be shown and need to be downloaded.") + + // Overwrite the normal try-again action. + actions = "" + } + errDomain = "" + } else if CertErrors.contains(errCode) { + guard let certError = request?.query["certerror"] as? String else { + return GCDWebServerResponse(statusCode: 404) + } + + asset = Bundle.main.path(forResource: "CertError", ofType: "html") + actions = "" + variables["error_title"] = Strings.ErrorPagesCertWarningTitle + variables["cert_error"] = certError + variables["long_description"] = String(format: Strings.ErrorPagesCertWarningDescription, "\(errURLDomain)") + variables["advanced_button"] = Strings.ErrorPagesAdvancedButton + variables["warning_description"] = Strings.ErrorPagesCertWarningDescription + variables["warning_advanced1"] = Strings.ErrorPagesAdvancedWarning1 + variables["warning_advanced2"] = Strings.ErrorPagesAdvancedWarning2 + variables["warning_actions"] = + "

\(Strings.ErrorPagesVisitOnceButton)

" + } + + variables["actions"] = actions + + let response = GCDWebServerDataResponse(htmlTemplate: asset, variables: variables) + response?.setValue("no cache", forAdditionalHeader: "Pragma") + response?.setValue("no-cache,must-revalidate", forAdditionalHeader: "Cache-Control") + response?.setValue(Date().description, forAdditionalHeader: "Expires") + return response + }) + + server.registerHandlerForMethod("GET", module: "errors", resource: "NetError.css", handler: { (request) -> GCDWebServerResponse! in + let path = Bundle(for: self).path(forResource: "NetError", ofType: "css")! + return GCDWebServerDataResponse(data: try? Data(contentsOf: URL(fileURLWithPath: path)), contentType: "text/css") + }) + + server.registerHandlerForMethod("GET", module: "errors", resource: "CertError.css", handler: { (request) -> GCDWebServerResponse! in + let path = Bundle(for: self).path(forResource: "CertError", ofType: "css")! + return GCDWebServerDataResponse(data: try? Data(contentsOf: URL(fileURLWithPath: path)), contentType: "text/css") + }) + } + + func showPage(_ error: NSError, forUrl url: URL, inWebView webView: WKWebView) { + // Don't show error pages for error pages. + if url.isErrorPageURL { + if let previousURL = url.originalURLFromErrorURL, + let index = ErrorPageHelper.redirecting.index(of: previousURL) { + ErrorPageHelper.redirecting.remove(at: index) + } + return + } + + // Add this page to the redirecting list. This will cause the server to actually show the error page + // (instead of redirecting to the original URL). + ErrorPageHelper.redirecting.append(url) + + var components = URLComponents(string: WebServer.sharedInstance.base + "/errors/error.html")! + var queryItems = [ + URLQueryItem(name: "url", value: url.absoluteString), + URLQueryItem(name: "code", value: String(error.code)), + URLQueryItem(name: "domain", value: error.domain), + URLQueryItem(name: "description", value: error.localizedDescription) + ] + + // If this is an invalid certificate, show a certificate error allowing the + // user to go back or continue. The certificate itself is encoded and added as + // a query parameter to the error page URL; we then read the certificate from + // the URL if the user wants to continue. + if ErrorPageHelper.CertErrors.contains(error.code), + let certChain = error.userInfo["NSErrorPeerCertificateChainKey"] as? [SecCertificate], + let cert = certChain.first, + let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError, + let certErrorCode = underlyingError.userInfo["_kCFStreamErrorCodeKey"] as? Int { + let encodedCert = (SecCertificateCopyData(cert) as Data).base64EncodedString + queryItems.append(URLQueryItem(name: "badcert", value: encodedCert)) + + let certError = ErrorPageHelper.CertErrorCodes[certErrorCode] ?? "" + queryItems.append(URLQueryItem(name: "certerror", value: String(certError))) + } + + components.queryItems = queryItems + webView.load(PrivilegedRequest(url: components.url!) as URLRequest) + } +} + +extension ErrorPageHelper: TabContentScript { + static func name() -> String { + return "ErrorPageHelper" + } + + func scriptMessageHandlerName() -> String? { + return "errorPageHelperMessageManager" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + if let errorURL = message.frameInfo.request.url, errorURL.isErrorPageURL, + let res = message.body as? [String: String], + let originalURL = errorURL.originalURLFromErrorURL, + let type = res["type"] { + + switch type { + case ErrorPageHelper.MessageOpenInSafari: + UIApplication.shared.openURL(originalURL) + case ErrorPageHelper.MessageCertVisitOnce: + if let cert = certFromErrorURL(errorURL), + let host = originalURL.host { + let origin = "\(host):\(originalURL.port ?? 443)" + ErrorPageHelper.certStore?.addCertificate(cert, forOrigin: origin) + _ = message.webView?.reload() + } + default: + assertionFailure("Unknown error message") + } + } + } + + fileprivate func certFromErrorURL(_ url: URL) -> SecCertificate? { + let components = URLComponents(url: url, resolvingAgainstBaseURL: false) + if let encodedCert = components?.queryItems?.filter({ $0.name == "badcert" }).first?.value, + let certData = Data(base64Encoded: encodedCert, options: []) { + return SecCertificateCreateWithData(nil, certData as CFData) + } + + return nil + } +} diff --git a/mobile/ios/Client/Frontend/Browser/FaviconManager.swift b/mobile/ios/Client/Frontend/Browser/FaviconManager.swift new file mode 100644 index 0000000000..edbff93413 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/FaviconManager.swift @@ -0,0 +1,145 @@ +/* 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/. */ + +import Foundation +import WebKit +import Shared +import Storage +import SDWebImage +import Deferred +import Sync + +class FaviconManager: TabContentScript { + static let FaviconDidLoad = "FaviconManagerFaviconDidLoad" + + let profile: Profile! + weak var tab: Tab? + + static let maximumFaviconSize = 1 * 1024 * 1024 // 1 MiB file size limit + + init(tab: Tab, profile: Profile) { + self.profile = profile + self.tab = tab + + if let path = Bundle.main.path(forResource: "Favicons", ofType: "js") { + if let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + } + + class func name() -> String { + return "FaviconsManager" + } + + func scriptMessageHandlerName() -> String? { + return "faviconsMessageHandler" + } + + fileprivate func loadFavicons(_ tab: Tab, profile: Profile, favicons: [Favicon]) -> Deferred<[Maybe]> { + var deferreds: [() -> Deferred>] + deferreds = favicons.map { favicon in + return { [weak tab] () -> Deferred> in + if let tab = tab, + let url = URL(string: favicon.url), + let currentURL = tab.url { + return self.getFavicon(tab, iconUrl: url, currentURL: currentURL, icon: favicon, profile: profile) + } else { + return deferMaybe(FaviconError()) + } + } + } + return all(deferreds.map({$0()})) + } + + func getFavicon(_ tab: Tab, iconUrl: URL, currentURL: URL, icon: Favicon, profile: Profile) -> Deferred> { + let deferred = Deferred>() + let manager = SDWebImageManager.shared() + let options: [SDWebImageOptions] = tab.isPrivate ? [.lowPriority, .cacheMemoryOnly] : [.lowPriority] + let url = currentURL.absoluteString + let site = Site(url: url, title: "") + + weak var tab = tab + + func loadImageCompleted(_ img: UIImage?, _ url: URL?) { + guard let tab = tab, let img = img, let urlString = url?.absoluteString else { + deferred.fill(Maybe(failure: FaviconError())) + return + } + + let fav = Favicon(url: urlString, date: Date(), type: icon.type) + fav.width = Int(img.size.width) + fav.height = Int(img.size.height) + + if !tab.isPrivate { + if tab.favicons.isEmpty { + self.makeFaviconAvailable(tab, atURL: currentURL, favicon: fav, withImage: img) + } + tab.favicons.append(fav) + self.profile.favicons.addFavicon(fav, forSite: site).upon { _ in + deferred.fill(Maybe(success: fav)) + } + } else { + tab.favicons.append(fav) + deferred.fill(Maybe(success: fav)) + } + } + + var fetch: SDWebImageOperation? = nil + fetch = manager.loadImage(with: iconUrl, options: SDWebImageOptions(options), + progress: { (receivedSize, expectedSize, _) in + if receivedSize > FaviconManager.maximumFaviconSize || expectedSize > FaviconManager.maximumFaviconSize { + fetch?.cancel() + } + }, + completed: { (img, _, _, _, _, url) in + loadImageCompleted(img, url) + }) + return deferred + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + self.tab?.favicons.removeAll(keepingCapacity: false) + if let tab = self.tab, let currentURL = tab.url { + var favicons = [Favicon]() + if let icons = message.body as? [String: Int] { + for icon in icons { + if let _ = URL(string: icon.0), let iconType = IconType(rawValue: icon.1) { + let favicon = Favicon(url: icon.0, date: Date(), type: iconType) + favicons.append(favicon) + } + } + } + loadFavicons(tab, profile: profile, favicons: favicons).uponQueue(DispatchQueue.main) { result in + let results = result.flatMap({ $0.successValue }) + let faviconsReadOnly = favicons + if results.count == 1 && faviconsReadOnly[0].type == .guess { + // No favicon is indicated in the HTML + self.noFaviconAvailable(tab, atURL: currentURL as URL) + } + + NotificationCenter.default.post(name: NSNotification.Name(rawValue: FaviconManager.FaviconDidLoad), object: tab) + } + } + } + + func makeFaviconAvailable(_ tab: Tab, atURL url: URL, favicon: Favicon, withImage image: UIImage) { + // XXX: Bug 1390200 - Disable NSUserActivity/CoreSpotlight temporarily + // let helper = tab.getHelper(name: "SpotlightHelper") as? SpotlightHelper + // helper?.updateImage(image, forURL: url) + } + + func noFaviconAvailable(_ tab: Tab, atURL url: URL) { + // XXX: Bug 1390200 - Disable NSUserActivity/CoreSpotlight temporarily + // let helper = tab.getHelper(name: "SpotlightHelper") as? SpotlightHelper + // helper?.updateImage(forURL: url) + } +} + +class FaviconError: MaybeErrorType { + internal var description: String { + return "No Image Loaded" + } +} diff --git a/mobile/ios/Client/Frontend/Browser/FindInPageBar.swift b/mobile/ios/Client/Frontend/Browser/FindInPageBar.swift new file mode 100644 index 0000000000..8edf49516a --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/FindInPageBar.swift @@ -0,0 +1,167 @@ +/* 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/. */ + +import Foundation +import UIKit + +protocol FindInPageBarDelegate: class { + func findInPage(_ findInPage: FindInPageBar, didTextChange text: String) + func findInPage(_ findInPage: FindInPageBar, didFindPreviousWithText text: String) + func findInPage(_ findInPage: FindInPageBar, didFindNextWithText text: String) + func findInPageDidPressClose(_ findInPage: FindInPageBar) +} + +private struct FindInPageUX { + static let ButtonColor = UIColor.black + static let MatchCountColor = UIColor.lightGray + static let MatchCountFont = UIConstants.DefaultChromeFont + static let SearchTextColor = UIColor(rgb: 0xe66000) + static let SearchTextFont = UIConstants.DefaultChromeFont + static let TopBorderColor = UIColor(rgb: 0xEEEEEE) +} + +class FindInPageBar: UIView { + weak var delegate: FindInPageBarDelegate? + fileprivate let searchText = UITextField() + fileprivate let matchCountView = UILabel() + fileprivate let previousButton = UIButton() + fileprivate let nextButton = UIButton() + + var currentResult = 0 { + didSet { + matchCountView.text = "\(currentResult)/\(totalResults)" + } + } + + var totalResults = 0 { + didSet { + matchCountView.text = "\(currentResult)/\(totalResults)" + previousButton.isEnabled = totalResults > 1 + nextButton.isEnabled = previousButton.isEnabled + } + } + + var text: String? { + get { + return searchText.text + } + + set { + searchText.text = newValue + SELdidTextChange(searchText) + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + backgroundColor = UIColor.white + + searchText.addTarget(self, action: #selector(FindInPageBar.SELdidTextChange(_:)), for: UIControlEvents.editingChanged) + searchText.textColor = FindInPageUX.SearchTextColor + searchText.font = FindInPageUX.SearchTextFont + searchText.autocapitalizationType = UITextAutocapitalizationType.none + searchText.autocorrectionType = UITextAutocorrectionType.no + searchText.inputAssistantItem.leadingBarButtonGroups = [] + searchText.inputAssistantItem.trailingBarButtonGroups = [] + searchText.enablesReturnKeyAutomatically = true + searchText.returnKeyType = .search + searchText.accessibilityIdentifier = "FindInPage.searchField" + addSubview(searchText) + + matchCountView.textColor = FindInPageUX.MatchCountColor + matchCountView.font = FindInPageUX.MatchCountFont + matchCountView.isHidden = true + matchCountView.accessibilityIdentifier = "FindInPage.matchCount" + addSubview(matchCountView) + + previousButton.setImage(UIImage(named: "find_previous"), for: UIControlState()) + previousButton.setTitleColor(FindInPageUX.ButtonColor, for: UIControlState()) + previousButton.accessibilityLabel = NSLocalizedString("Previous in-page result", tableName: "FindInPage", comment: "Accessibility label for previous result button in Find in Page Toolbar.") + previousButton.addTarget(self, action: #selector(FindInPageBar.SELdidFindPrevious(_:)), for: UIControlEvents.touchUpInside) + previousButton.accessibilityIdentifier = "FindInPage.find_previous" + addSubview(previousButton) + + nextButton.setImage(UIImage(named: "find_next"), for: UIControlState()) + nextButton.setTitleColor(FindInPageUX.ButtonColor, for: UIControlState()) + nextButton.accessibilityLabel = NSLocalizedString("Next in-page result", tableName: "FindInPage", comment: "Accessibility label for next result button in Find in Page Toolbar.") + nextButton.addTarget(self, action: #selector(FindInPageBar.SELdidFindNext(_:)), for: UIControlEvents.touchUpInside) + nextButton.accessibilityIdentifier = "FindInPage.find_next" + addSubview(nextButton) + + let closeButton = UIButton() + closeButton.setImage(UIImage(named: "find_close"), for: UIControlState()) + closeButton.setTitleColor(FindInPageUX.ButtonColor, for: UIControlState()) + closeButton.accessibilityLabel = NSLocalizedString("Done", tableName: "FindInPage", comment: "Done button in Find in Page Toolbar.") + closeButton.addTarget(self, action: #selector(FindInPageBar.SELdidPressClose(_:)), for: UIControlEvents.touchUpInside) + closeButton.accessibilityIdentifier = "FindInPage.close" + addSubview(closeButton) + + let topBorder = UIView() + topBorder.backgroundColor = FindInPageUX.TopBorderColor + addSubview(topBorder) + + searchText.snp.makeConstraints { make in + make.leading.top.bottom.equalTo(self).inset(UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0)) + } + searchText.setContentHuggingPriority(UILayoutPriorityDefaultLow, for: UILayoutConstraintAxis.horizontal) + searchText.setContentCompressionResistancePriority(UILayoutPriorityDefaultLow, for: UILayoutConstraintAxis.horizontal) + + matchCountView.snp.makeConstraints { make in + make.leading.equalTo(searchText.snp.trailing) + make.centerY.equalTo(self) + } + matchCountView.setContentHuggingPriority(UILayoutPriorityDefaultHigh, for: UILayoutConstraintAxis.horizontal) + matchCountView.setContentCompressionResistancePriority(UILayoutPriorityDefaultHigh, for: UILayoutConstraintAxis.horizontal) + + previousButton.snp.makeConstraints { make in + make.leading.equalTo(matchCountView.snp.trailing) + make.size.equalTo(self.snp.height) + make.centerY.equalTo(self) + } + + nextButton.snp.makeConstraints { make in + make.leading.equalTo(previousButton.snp.trailing) + make.size.equalTo(self.snp.height) + make.centerY.equalTo(self) + } + + closeButton.snp.makeConstraints { make in + make.leading.equalTo(nextButton.snp.trailing) + make.size.equalTo(self.snp.height) + make.trailing.centerY.equalTo(self) + } + + topBorder.snp.makeConstraints { make in + make.height.equalTo(1) + make.left.right.top.equalTo(self) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @discardableResult override func becomeFirstResponder() -> Bool { + searchText.becomeFirstResponder() + return super.becomeFirstResponder() + } + + @objc fileprivate func SELdidFindPrevious(_ sender: UIButton) { + delegate?.findInPage(self, didFindPreviousWithText: searchText.text ?? "") + } + + @objc fileprivate func SELdidFindNext(_ sender: UIButton) { + delegate?.findInPage(self, didFindNextWithText: searchText.text ?? "") + } + + @objc fileprivate func SELdidTextChange(_ sender: UITextField) { + matchCountView.isHidden = searchText.text?.isEmpty ?? true + delegate?.findInPage(self, didTextChange: searchText.text ?? "") + } + + @objc fileprivate func SELdidPressClose(_ sender: UIButton) { + delegate?.findInPageDidPressClose(self) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/FindInPageHelper.swift b/mobile/ios/Client/Frontend/Browser/FindInPageHelper.swift new file mode 100644 index 0000000000..db7d7a63f2 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/FindInPageHelper.swift @@ -0,0 +1,46 @@ +/* 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/. */ + +import Foundation +import Shared +import WebKit + +protocol FindInPageHelperDelegate: class { + func findInPageHelper(_ findInPageHelper: FindInPageHelper, didUpdateCurrentResult currentResult: Int) + func findInPageHelper(_ findInPageHelper: FindInPageHelper, didUpdateTotalResults totalResults: Int) +} + +class FindInPageHelper: TabContentScript { + weak var delegate: FindInPageHelperDelegate? + fileprivate weak var tab: Tab? + + class func name() -> String { + return "FindInPage" + } + + required init(tab: Tab) { + self.tab = tab + + if let path = Bundle.main.path(forResource: "FindInPage", ofType: "js"), let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + + func scriptMessageHandlerName() -> String? { + return "findInPageHandler" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + let data = message.body as! [String: Int] + + if let currentResult = data["currentResult"] { + delegate?.findInPageHelper(self, didUpdateCurrentResult: currentResult) + } + + if let totalResults = data["totalResults"] { + delegate?.findInPageHelper(self, didUpdateTotalResults: totalResults) + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/HistoryStateHelper.swift b/mobile/ios/Client/Frontend/Browser/HistoryStateHelper.swift new file mode 100644 index 0000000000..931247bbeb --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/HistoryStateHelper.swift @@ -0,0 +1,45 @@ +/* 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/. */ + +import Foundation +import WebKit + +protocol HistoryStateHelperDelegate: class { + func historyStateHelper(_ historyStateHelper: HistoryStateHelper, didPushOrReplaceStateInTab tab: Tab) +} + +// This tab helper is needed for injecting a user script into the +// WKWebView that intercepts calls to `history.pushState()` and +// `history.replaceState()` so that the BrowserViewController is +// notified when the user navigates a single-page web application. +class HistoryStateHelper: TabContentScript { + weak var delegate: HistoryStateHelperDelegate? + fileprivate weak var tab: Tab? + + required init(tab: Tab) { + self.tab = tab + if let path = Bundle.main.path(forResource: "HistoryStateHelper", ofType: "js") { + if let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + } + + func scriptMessageHandlerName() -> String? { + return "historyStateHelper" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + if let tab = tab { + DispatchQueue.main.async { + self.delegate?.historyStateHelper(self, didPushOrReplaceStateInTab: tab) + } + } + } + + class func name() -> String { + return "HistoryStateHelper" + } +} diff --git a/mobile/ios/Client/Frontend/Browser/HomePageHelper.swift b/mobile/ios/Client/Frontend/Browser/HomePageHelper.swift new file mode 100644 index 0000000000..8940c20807 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/HomePageHelper.swift @@ -0,0 +1,71 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger + +private let log = Logger.browserLogger + +struct HomePageConstants { + static let HomePageURLPrefKey = "HomePageURLPref" + static let DefaultHomePageURLPrefKey = PrefsKeys.KeyDefaultHomePageURL +} + +class HomePageHelper { + + let prefs: Prefs + + var currentURL: URL? { + get { + return HomePageAccessors.getHomePage(prefs) + } + set { + if let url = newValue, url.isWebPage(includeDataURIs: false) && !url.isLocal { + prefs.setString(url.absoluteString, forKey: HomePageConstants.HomePageURLPrefKey) + } else { + prefs.removeObjectForKey(HomePageConstants.HomePageURLPrefKey) + } + } + } + + var defaultURLString: String? { + return HomePageAccessors.getDefaultHomePageString(prefs) + } + + var isHomePageAvailable: Bool { return currentURL != nil } + + init(prefs: Prefs) { + self.prefs = prefs + } + + func openHomePage(_ tab: Tab) { + guard let url = currentURL else { + // this should probably never happen. + log.error("User requested a homepage that wasn't a valid URL") + return + } + tab.loadRequest(URLRequest(url: url)) + } + + func openHomePage(inTab tab: Tab, presentAlertOn viewController: UIViewController?) { + if isHomePageAvailable { + openHomePage(tab) + } else { + setHomePage(toTab: tab, presentAlertOn: viewController) + } + } + + func setHomePage(toTab tab: Tab, presentAlertOn viewController: UIViewController?) { + let alertController = UIAlertController( + title: Strings.SetHomePageDialogTitle, + message: Strings.SetHomePageDialogMessage, + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction(UIAlertAction(title: Strings.SetHomePageDialogNo, style: .cancel, handler: nil)) + alertController.addAction(UIAlertAction(title: Strings.SetHomePageDialogYes, style: .default) { _ in + self.currentURL = tab.url as URL? + }) + viewController?.present(alertController, animated: true, completion: nil) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/LocalRequestHelper.swift b/mobile/ios/Client/Frontend/Browser/LocalRequestHelper.swift new file mode 100644 index 0000000000..b01fefd6ae --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/LocalRequestHelper.swift @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +import WebKit + +class LocalRequestHelper: TabContentScript { + func scriptMessageHandlerName() -> String? { + return "localRequestHelper" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + guard message.frameInfo.request.url?.isLocal ?? false else { return } + + let params = message.body as! [String: String] + + if params["type"] == "load", + let urlString = params["url"], + let url = URL(string: urlString) { + _ = message.webView?.load(PrivilegedRequest(url: url) as URLRequest) + } else if params["type"] == "reload" { + _ = message.webView?.reload() + } else { + assertionFailure("Invalid message: \(message.body)") + } + } + + class func name() -> String { + return "LocalRequestHelper" + } +} diff --git a/mobile/ios/Client/Frontend/Browser/LoginsHelper.swift b/mobile/ios/Client/Frontend/Browser/LoginsHelper.swift new file mode 100644 index 0000000000..6605e3a138 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/LoginsHelper.swift @@ -0,0 +1,234 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import WebKit +import Deferred +import SwiftyJSON + +private let log = Logger.browserLogger + +class LoginsHelper: TabContentScript { + fileprivate weak var tab: Tab? + fileprivate let profile: Profile + fileprivate var snackBar: SnackBar? + + // Exposed for mocking purposes + var logins: BrowserLogins { + return profile.logins + } + + class func name() -> String { + return "LoginsHelper" + } + + required init(tab: Tab, profile: Profile) { + self.tab = tab + self.profile = profile + + if let path = Bundle.main.path(forResource: "LoginsHelper", ofType: "js"), let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + + func scriptMessageHandlerName() -> String? { + return "loginsManagerMessageHandler" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + guard var res = message.body as? [String: AnyObject] else { return } + guard let type = res["type"] as? String else { return } + + // Check to see that we're in the foreground before trying to check the logins. We want to + // make sure we don't try accessing the logins database while we're backgrounded to avoid + // the system from terminating our app due to background disk access. + // + // See https://bugzilla.mozilla.org/show_bug.cgi?id=1307822 for details. + guard UIApplication.shared.applicationState == .active && !profile.isShutdown else { + return + } + + // We don't use the WKWebView's URL since the page can spoof the URL by using document.location + // right before requesting login data. See bug 1194567 for more context. + if let url = message.frameInfo.request.url { + // Since responses go to the main frame, make sure we only listen for main frame requests + // to avoid XSS attacks. + if message.frameInfo.isMainFrame && type == "request" { + res["username"] = "" as AnyObject? + res["password"] = "" as AnyObject? + if let login = Login.fromScript(url, script: res), + let requestId = res["requestId"] as? String { + requestLogins(login, requestId: requestId) + } + } else if type == "submit" { + if self.profile.prefs.boolForKey("saveLogins") ?? true { + if let login = Login.fromScript(url, script: res) { + setCredentials(login) + } + } + } + } + } + + class func replace(_ base: String, keys: [String], replacements: [String]) -> NSMutableAttributedString { + var ranges = [NSRange]() + var string = base + for (index, key) in keys.enumerated() { + let replace = replacements[index] + let range = string.range(of: key, + options: NSString.CompareOptions.literal, + range: nil, + locale: nil)! + string.replaceSubrange(range, with: replace) + let nsRange = NSRange(location: string.characters.distance(from: string.startIndex, to: range.lowerBound), + length: replace.characters.count) + ranges.append(nsRange) + } + + var attributes = [String: AnyObject]() + attributes[NSFontAttributeName] = UIFont.systemFont(ofSize: 13, weight: UIFontWeightRegular) + attributes[NSForegroundColorAttributeName] = UIColor.darkGray + let attr = NSMutableAttributedString(string: string, attributes: attributes) + let font: UIFont = UIFont.systemFont(ofSize: 13, weight: UIFontWeightMedium) + for range in ranges { + attr.addAttribute(NSFontAttributeName, value: font, range: range) + } + return attr + } + + func getLoginsForProtectionSpace(_ protectionSpace: URLProtectionSpace) -> Deferred>> { + return profile.logins.getLoginsForProtectionSpace(protectionSpace) + } + + func updateLoginByGUID(_ guid: GUID, new: LoginData, significant: Bool) -> Success { + return profile.logins.updateLoginByGUID(guid, new: new, significant: significant) + } + + func setCredentials(_ login: LoginData) { + if login.password.isEmpty { + log.debug("Empty password") + return + } + + profile.logins + .getLoginsForProtectionSpace(login.protectionSpace, withUsername: login.username) + .uponQueue(DispatchQueue.main) { res in + if let data = res.successValue { + log.debug("Found \(data.count) logins.") + for saved in data { + if let saved = saved { + if saved.password == login.password { + self.profile.logins.addUseOfLoginByGUID(saved.guid) + return + } + + self.promptUpdateFromLogin(login: saved, toLogin: login) + return + } + } + } + + self.promptSave(login) + } + } + + fileprivate func promptSave(_ login: LoginData) { + guard login.isValid.isSuccess else { + return + } + + let promptMessage: NSAttributedString + if let username = login.username { + let promptStringFormat = NSLocalizedString("LoginsHelper.PromptSaveLogin.Title", value: "Save login %@ for %@?", comment: "Prompt for saving a login. The first parameter is the username being saved. The second parameter is the hostname of the site.") + promptMessage = NSAttributedString(string: String(format: promptStringFormat, username, login.hostname)) + } else { + let promptStringFormat = NSLocalizedString("LoginsHelper.PromptSavePassword.Title", value: "Save password for %@?", comment: "Prompt for saving a password with no username. The parameter is the hostname of the site.") + promptMessage = NSAttributedString(string: String(format: promptStringFormat, login.hostname)) + } + + if snackBar != nil { + tab?.removeSnackbar(snackBar!) + } + + snackBar = TimerSnackBar(attrText: promptMessage, + img: UIImage(named: "key"), + buttons: [ + SnackButton(title: Strings.LoginsHelperDontSaveButtonTitle, accessibilityIdentifier: "SaveLoginPrompt.dontSaveButton", callback: { (bar: SnackBar) -> Void in + self.tab?.removeSnackbar(bar) + self.snackBar = nil + return + }), + + SnackButton(title: Strings.LoginsHelperSaveLoginButtonTitle, accessibilityIdentifier: "SaveLoginPrompt.saveLoginButton", callback: { (bar: SnackBar) -> Void in + self.tab?.removeSnackbar(bar) + self.snackBar = nil + self.profile.logins.addLogin(login) + + LeanPlumClient.shared.track(event: .savedLoginAndPassword) + }) + ]) + tab?.addSnackbar(snackBar!) + } + + fileprivate func promptUpdateFromLogin(login old: LoginData, toLogin new: LoginData) { + guard new.isValid.isSuccess else { + return + } + + let guid = old.guid + + let formatted: String + if let username = new.username { + let promptStringFormat = NSLocalizedString("LoginsHelper.PromptUpdateLogin.Title", value: "Update login %@ for %@?", comment: "Prompt for updating a login. The first parameter is the username for which the password will be updated for. The second parameter is the hostname of the site.") + formatted = String(format: promptStringFormat, username, new.hostname) + } else { + let promptStringFormat = NSLocalizedString("LoginsHelper.PromptUpdatePassword.Title", value: "Update password for %@?", comment: "Prompt for updating a password with no username. The parameter is the hostname of the site.") + formatted = String(format: promptStringFormat, new.hostname) + } + let promptMessage = NSAttributedString(string: formatted) + + if snackBar != nil { + tab?.removeSnackbar(snackBar!) + } + + snackBar = TimerSnackBar(attrText: promptMessage, + img: UIImage(named: "key"), + buttons: [ + SnackButton(title: Strings.LoginsHelperDontSaveButtonTitle, accessibilityIdentifier: "UpdateLoginPrompt.dontSaveButton", callback: { (bar: SnackBar) -> Void in + self.tab?.removeSnackbar(bar) + self.snackBar = nil + return + }), + + SnackButton(title: Strings.LoginsHelperUpdateButtonTitle, accessibilityIdentifier: "UpdateLoginPrompt.updateButton", callback: { (bar: SnackBar) -> Void in + self.tab?.removeSnackbar(bar) + self.snackBar = nil + self.profile.logins.updateLoginByGUID(guid, new: new, + significant: new.isSignificantlyDifferentFrom(old)) + }) + ]) + tab?.addSnackbar(snackBar!) + } + + fileprivate func requestLogins(_ login: LoginData, requestId: String) { + profile.logins.getLoginsForProtectionSpace(login.protectionSpace).uponQueue(DispatchQueue.main) { res in + var jsonObj = [String: Any]() + if let cursor = res.successValue { + log.debug("Found \(cursor.count) logins.") + jsonObj["requestId"] = requestId + jsonObj["name"] = "RemoteLogins:loginsFound" + jsonObj["logins"] = cursor.map { $0!.toDict() } + } + + let json = JSON(jsonObj) + let src = "window.__firefox__.logins.inject(\(json.stringValue()!))" + self.tab?.webView?.evaluateJavaScript(src, completionHandler: { (obj, err) -> Void in + }) + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/MailProviders.swift b/mobile/ios/Client/Frontend/Browser/MailProviders.swift new file mode 100644 index 0000000000..c140182ab8 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/MailProviders.swift @@ -0,0 +1,156 @@ +/* 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/. */ + +import Foundation +import Shared + +// mailto headers: subject, body, cc, bcc + +protocol MailProvider { + var beginningScheme: String {get set} + var supportedHeaders: [String] {get set} + func newEmailURLFromMetadata(_ metadata: MailToMetadata) -> URL? +} + +private func constructEmailURLString(_ beginningURLString: String, metadata: MailToMetadata, supportedHeaders: [String], bodyHName: String = "body", toHName: String = "to") -> String { + var lowercasedHeaders = [String: String]() + metadata.headers.forEach { (hname, hvalue) in + lowercasedHeaders[hname.lowercased()] = hvalue + } + + var toParam: String + if let toHValue = lowercasedHeaders["to"] { + let value = metadata.to.isEmpty ? toHValue : [metadata.to, toHValue].joined(separator: "%2C%20") + lowercasedHeaders.removeValue(forKey: "to") + toParam = "\(toHName)=\(value)" + } else { + toParam = "\(toHName)=\(metadata.to)" + } + + var queryParams: [String] = [] + lowercasedHeaders.forEach({ (hname, hvalue) in + if supportedHeaders.contains(hname) { + queryParams.append("\(hname)=\(hvalue)") + } else if hname == "body" { + queryParams.append("\(bodyHName)=\(hvalue)") + } + }) + let stringParams = queryParams.joined(separator: "&") + let finalURLString = beginningURLString + (stringParams.isEmpty ? toParam : [toParam, stringParams].joined(separator: "&")) + return finalURLString +} + +class ReaddleSparkIntegration: MailProvider { + var beginningScheme = "readdle-spark://compose?" + var supportedHeaders = [ + "subject", + "recipient", + "textbody", + "html", + "cc", + "bcc" + ] + + func newEmailURLFromMetadata(_ metadata: MailToMetadata) -> URL? { + return constructEmailURLString(beginningScheme, metadata: metadata, supportedHeaders: supportedHeaders, bodyHName: "textbody", toHName: "recipient").asURL + } +} + +class AirmailIntegration: MailProvider { + var beginningScheme = "airmail://compose?" + var supportedHeaders = [ + "subject", + "from", + "to", + "cc", + "bcc", + "plainBody", + "htmlBody" + ] + + func newEmailURLFromMetadata(_ metadata: MailToMetadata) -> URL? { + return constructEmailURLString(beginningScheme, metadata: metadata, supportedHeaders: supportedHeaders, bodyHName: "htmlBody").asURL + } +} + +class MyMailIntegration: MailProvider { + var beginningScheme = "mymail-mailto://?" + var supportedHeaders = [ + "to", + "subject", + "body", + "cc", + "bcc" + ] + + func newEmailURLFromMetadata(_ metadata: MailToMetadata) -> URL? { + return constructEmailURLString(beginningScheme, metadata: metadata, supportedHeaders: supportedHeaders).asURL + } +} + +class MailRuIntegration: MyMailIntegration { + override init() { + super.init() + self.beginningScheme = "mailru-mailto://?" + } +} + +class MSOutlookIntegration: MailProvider { + var beginningScheme = "ms-outlook://emails/new?" + var supportedHeaders = [ + "to", + "cc", + "bcc", + "subject", + "body" + ] + + func newEmailURLFromMetadata(_ metadata: MailToMetadata) -> URL? { + return constructEmailURLString(beginningScheme, metadata: metadata, supportedHeaders: supportedHeaders).asURL + } +} + +class YMailIntegration: MailProvider { + var beginningScheme = "ymail://mail/any/compose?" + var supportedHeaders = [ + "to", + "cc", + "subject", + "body" + ] + + func newEmailURLFromMetadata(_ metadata: MailToMetadata) -> URL? { + return constructEmailURLString(beginningScheme, metadata: metadata, supportedHeaders: supportedHeaders).asURL + } +} + +class GoogleGmailIntegration: MailProvider { + var beginningScheme = "googlegmail:///co?" + var supportedHeaders = [ + "to", + "cc", + "bcc", + "subject", + "body" + ] + + func newEmailURLFromMetadata(_ metadata: MailToMetadata) -> URL? { + return constructEmailURLString(beginningScheme, metadata: metadata, supportedHeaders: supportedHeaders).asURL + } +} + +class GoogleInboxIntegration: MailProvider { + var beginningScheme = "inbox-gmail://co?" + var supportedHeaders = [ + "to", + "cc", + "bcc", + "subject", + "body" + ] + + func newEmailURLFromMetadata(_ metadata: MailToMetadata) -> URL? { + return constructEmailURLString(beginningScheme, metadata: metadata, supportedHeaders: supportedHeaders).asURL + } +} diff --git a/mobile/ios/Client/Frontend/Browser/MailtoLinkHandler.swift b/mobile/ios/Client/Frontend/Browser/MailtoLinkHandler.swift new file mode 100644 index 0000000000..cd9097b14b --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/MailtoLinkHandler.swift @@ -0,0 +1,52 @@ +/* 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/. */ + +import Foundation +import UIKit + +open class MailtoLinkHandler { + + lazy var mailSchemeProviders: [String: MailProvider] = self.fetchMailSchemeProviders() + + func launchMailClientForScheme(_ scheme: String, metadata: MailToMetadata, defaultMailtoURL: URL) { + guard let provider = mailSchemeProviders[scheme], let mailURL = provider.newEmailURLFromMetadata(metadata) else { + UIApplication.shared.openURL(defaultMailtoURL) + return + } + + if UIApplication.shared.canOpenURL(mailURL) { + UIApplication.shared.openURL(mailURL) + } else { + UIApplication.shared.openURL(defaultMailtoURL) + } + } + + func fetchMailSchemeProviders() -> [String: MailProvider] { + var providerDict = [String: MailProvider]() + if let path = Bundle.main.path(forResource: "MailSchemes", ofType: "plist"), let dictRoot = NSArray(contentsOfFile: path) { + dictRoot.forEach({ dict in + if let schemeDict = dict as? [String: Any], let scheme = schemeDict["scheme"] as? String { + if scheme == "readdle-spark://" { + providerDict[scheme] = ReaddleSparkIntegration() + } else if scheme == "mymail-mailto://" { + providerDict[scheme] = MyMailIntegration() + } else if scheme == "mailru-mailto://" { + providerDict[scheme] = MailRuIntegration() + } else if scheme == "airmail://" { + providerDict[scheme] = AirmailIntegration() + } else if scheme == "ms-outlook://" { + providerDict[scheme] = MSOutlookIntegration() + } else if scheme == "ymail://" { + providerDict[scheme] = YMailIntegration() + } else if scheme == "googlegmail://" { + providerDict[scheme] = GoogleGmailIntegration() + } else if scheme == "inbox-gmail://" { + providerDict[scheme] = GoogleInboxIntegration() + } + } + }) + } + return providerDict + } +} diff --git a/mobile/ios/Client/Frontend/Browser/NightModeHelper.swift b/mobile/ios/Client/Frontend/Browser/NightModeHelper.swift new file mode 100644 index 0000000000..4ed325561f --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/NightModeHelper.swift @@ -0,0 +1,58 @@ +/* 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/. */ + +import Foundation +import WebKit +import Shared + +struct NightModePrefsKey { + static let NightModeButtonIsInMenu = PrefsKeys.KeyNightModeButtonIsInMenu + static let NightModeStatus = PrefsKeys.KeyNightModeStatus +} + +class NightModeHelper: TabContentScript { + fileprivate weak var tab: Tab? + + required init(tab: Tab) { + self.tab = tab + if let path = Bundle.main.path(forResource: "NightModeHelper", ofType: "js"), let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + + static func name() -> String { + return "NightMode" + } + + func scriptMessageHandlerName() -> String? { + return "NightMode" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + // Do nothing. + } + + static func toggle(_ prefs: Prefs, tabManager: TabManager) { + let isActive = prefs.boolForKey(NightModePrefsKey.NightModeStatus) ?? false + setNightMode(prefs, tabManager: tabManager, enabled: !isActive) + } + + static func setNightMode(_ prefs: Prefs, tabManager: TabManager, enabled: Bool) { + prefs.setBool(enabled, forKey: NightModePrefsKey.NightModeStatus) + for tab in tabManager.tabs { + tab.setNightMode(enabled) + } + } + + static func isActivated(_ prefs: Prefs) -> Bool { + return prefs.boolForKey(NightModePrefsKey.NightModeStatus) ?? false + } +} + +class NightModeAccessors { + static func isNightMode(_ prefs: Prefs) -> Bool { + return prefs.boolForKey(NightModePrefsKey.NightModeStatus) ?? false + } +} diff --git a/mobile/ios/Client/Frontend/Browser/NoImageModeHelper.swift b/mobile/ios/Client/Frontend/Browser/NoImageModeHelper.swift new file mode 100644 index 0000000000..8c20f36b78 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/NoImageModeHelper.swift @@ -0,0 +1,47 @@ +/* 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/. */ + +import Foundation +import WebKit +import Shared + +struct NoImageModePrefsKey { + static let NoImageModeStatus = PrefsKeys.KeyNoImageModeStatus +} + +class NoImageModeHelper: TabContentScript { + fileprivate weak var tab: Tab? + + required init(tab: Tab) { + self.tab = tab + if let path = Bundle.main.path(forResource: "NoImageModeHelper", ofType: "js"), let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + + static func name() -> String { + return "NoImageMode" + } + + func scriptMessageHandlerName() -> String? { + return "NoImageMode" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + // Do nothing. + } + + static func isActivated(_ prefs: Prefs) -> Bool { + return prefs.boolForKey(NoImageModePrefsKey.NoImageModeStatus) ?? false + } + + static func toggle(profile: Profile, tabManager: TabManager) { + if #available(iOS 11, *) { + let enabled = !isActivated(profile.prefs) + profile.prefs.setBool(enabled, forKey: PrefsKeys.KeyNoImageModeStatus) + tabManager.tabs.forEach { $0.noImageMode = enabled } + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/OpenInHelper.swift b/mobile/ios/Client/Frontend/Browser/OpenInHelper.swift new file mode 100644 index 0000000000..3b1fe73e83 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/OpenInHelper.swift @@ -0,0 +1,232 @@ +/* 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/. */ + +import Foundation +import PassKit +import WebKit +import SnapKit + +import Shared + +import XCGLogger + +private let log = Logger.browserLogger + +struct OpenInViewUX { + static let ViewHeight: CGFloat = 40.0 + static let TextFont = UIFont.systemFont(ofSize: 16) + static let TextColor = UIColor(red: 74.0/255.0, green: 144.0/255.0, blue: 226.0/255.0, alpha: 1.0) + static let TextOffset = -15 + static let OpenInString = NSLocalizedString("Open in…", comment: "String indicating that the file can be opened in another application on the device") +} + +enum MimeType: String { + case PDF = "application/pdf" + case PASS = "application/vnd.apple.pkpass" +} + +protocol OpenInHelper { + init?(response: URLResponse) + var openInView: UIView? { get set } + func open() +} + +struct OpenIn { + static let helpers: [OpenInHelper.Type] = [OpenPdfInHelper.self, OpenPassBookHelper.self, ShareFileHelper.self] + + static func helperForResponse(_ response: URLResponse) -> OpenInHelper? { + return helpers.flatMap { $0.init(response: response) }.first + } +} + +class ShareFileHelper: NSObject, OpenInHelper { + var openInView: UIView? + + fileprivate var url: URL + var pathExtension: String? + + required init?(response: URLResponse) { + guard let MIMEType = response.mimeType, !(MIMEType == MimeType.PASS.rawValue || MIMEType == MimeType.PDF.rawValue), + let responseURL = response.url else { return nil } + url = (responseURL as NSURL) as URL + super.init() + } + + func open() { + let alertController = UIAlertController( + title: Strings.OpenInDownloadHelperAlertTitle, + message: Strings.OpenInDownloadHelperAlertMessage, + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction( UIAlertAction(title: Strings.OpenInDownloadHelperAlertCancel, style: .cancel, handler: nil)) + alertController.addAction(UIAlertAction(title: Strings.OpenInDownloadHelperAlertConfirm, style: .default) { (action) in + let objectsToShare = [self.url] + let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil) + if let sourceView = self.openInView, let popoverController = activityVC.popoverPresentationController { + popoverController.sourceView = sourceView + popoverController.sourceRect = CGRect(origin: CGPoint(x: sourceView.bounds.midX, y: sourceView.bounds.maxY), size: .zero) + popoverController.permittedArrowDirections = .up + } + UIApplication.shared.keyWindow?.rootViewController?.present(activityVC, animated: true, completion: nil) + }) + UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil) + } +} + +class OpenPassBookHelper: NSObject, OpenInHelper { + var openInView: UIView? + + fileprivate var url: URL + + required init?(response: URLResponse) { + guard let MIMEType = response.mimeType, MIMEType == MimeType.PASS.rawValue && PKAddPassesViewController.canAddPasses(), + let responseURL = response.url else { return nil } + url = responseURL + super.init() + } + + func open() { + guard let passData = try? Data(contentsOf: url) else { return } + var error: NSError? = nil + let pass = PKPass(data: passData, error: &error) + if let _ = error { + // display an error + let alertController = UIAlertController( + title: Strings.UnableToAddPassErrorTitle, + message: Strings.UnableToAddPassErrorMessage, + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction( + UIAlertAction(title: Strings.UnableToAddPassErrorDismiss, style: .cancel) { (action) in + // Do nothing. + }) + UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil) + return + } + let passLibrary = PKPassLibrary() + if passLibrary.containsPass(pass) { + UIApplication.shared.openURL(pass.passURL!) + } else { + let addController = PKAddPassesViewController(pass: pass) + UIApplication.shared.keyWindow?.rootViewController?.present(addController, animated: true, completion: nil) + } + + } +} + +class OpenPdfInHelper: NSObject, OpenInHelper, UIDocumentInteractionControllerDelegate { + fileprivate var url: URL + fileprivate var docController: UIDocumentInteractionController? + fileprivate var openInURL: URL? + + lazy var openInView: UIView? = getOpenInView(self)() + + lazy var documentDirectory: URL = { + return URL(string: NSTemporaryDirectory())!.appendingPathComponent("pdfs") + }() + + fileprivate var filepath: URL? + + required init?(response: URLResponse) { + guard let MIMEType = response.mimeType, MIMEType == MimeType.PDF.rawValue && UIApplication.shared.canOpenURL(URL(string: "itms-books:")!), + let responseURL = response.url else { return nil } + url = responseURL + super.init() + setFilePath(response.suggestedFilename ?? url.lastPathComponent ) + } + + fileprivate func setFilePath(_ suggestedFilename: String) { + var filename = suggestedFilename + let pathExtension = filename.asURL?.pathExtension + if pathExtension == nil { + filename.append(".pdf") + } + filepath = documentDirectory.appendingPathComponent(filename) + } + + deinit { + guard let url = openInURL else { return } + let fileManager = FileManager.default + do { + try fileManager.removeItem(at: url) + } catch { + log.error("failed to delete file at \(url): \(error)") + } + } + + func getOpenInView() -> OpenInView { + let overlayView = OpenInView() + + overlayView.openInButton.addTarget(self, action: #selector(OpenPdfInHelper.open), for: .touchUpInside) + return overlayView + } + + func createDocumentControllerForURL(url: URL) { + docController = UIDocumentInteractionController(url: url) + docController?.delegate = self + self.openInURL = url + } + + func createLocalCopyOfPDF() { + guard let filePath = filepath else { + log.error("failed to create proper URL") + return + } + if docController == nil { + // if we already have a URL but no document controller, just create the document controller + if let url = openInURL { + createDocumentControllerForURL(url: url) + return + } + let contentsOfFile = try? Data(contentsOf: url) + let fileManager = FileManager.default + do { + try fileManager.createDirectory(atPath: documentDirectory.absoluteString, withIntermediateDirectories: true, attributes: nil) + if fileManager.createFile(atPath: filePath.absoluteString, contents: contentsOfFile, attributes: nil) { + let openInURL = URL(fileURLWithPath: filePath.absoluteString) + createDocumentControllerForURL(url: openInURL) + } else { + log.error("Unable to create local version of PDF file at \(filePath)") + } + } catch { + log.error("Error on creating directory at \(self.documentDirectory)") + } + } + } + + func open() { + createLocalCopyOfPDF() + guard let _parentView = self.openInView!.superview, let docController = self.docController else { log.error("view doesn't have a superview so can't open anything"); return } + // iBooks should be installed by default on all devices we care about, so regardless of whether or not there are other pdf-capable + // apps on this device, if we can open in iBooks we can open this PDF + // simulators do not have iBooks so the open in view will not work on the simulator + if UIApplication.shared.canOpenURL(URL(string: "itms-books:")!) { + log.info("iBooks installed: attempting to open pdf") + docController.presentOpenInMenu(from: .zero, in: _parentView, animated: true) + } else { + log.info("iBooks is not installed") + } + } +} + +class OpenInView: UIView { + let openInButton = UIButton() + + init() { + super.init(frame: .zero) + openInButton.setTitleColor(OpenInViewUX.TextColor, for: UIControlState.normal) + openInButton.setTitle(OpenInViewUX.OpenInString, for: UIControlState.normal) + openInButton.titleLabel?.font = OpenInViewUX.TextFont + openInButton.sizeToFit() + self.addSubview(openInButton) + openInButton.snp.makeConstraints { make in + make.centerY.equalTo(self) + make.height.equalTo(self) + make.trailing.equalTo(self).offset(OpenInViewUX.TextOffset) + } + self.backgroundColor = UIColor.white + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/mobile/ios/Client/Frontend/Browser/OpenSearch.swift b/mobile/ios/Client/Frontend/Browser/OpenSearch.swift new file mode 100644 index 0000000000..1af3593a83 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/OpenSearch.swift @@ -0,0 +1,281 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared +import Fuzi + +private let TypeSearch = "text/html" +private let TypeSuggest = "application/x-suggestions+json" + +class OpenSearchEngine: NSObject, NSCoding { + static let PreferredIconSize = 30 + + let shortName: String + let engineID: String? + let image: UIImage + let isCustomEngine: Bool + let searchTemplate: String + fileprivate let suggestTemplate: String? + + fileprivate let SearchTermComponent = "{searchTerms}" + fileprivate let LocaleTermComponent = "{moz:locale}" + + fileprivate lazy var searchQueryComponentKey: String? = self.getQueryArgFromTemplate() + + init(engineID: String?, shortName: String, image: UIImage, searchTemplate: String, suggestTemplate: String?, isCustomEngine: Bool) { + self.shortName = shortName + self.image = image + self.searchTemplate = searchTemplate + self.suggestTemplate = suggestTemplate + self.isCustomEngine = isCustomEngine + self.engineID = engineID + } + + required init?(coder aDecoder: NSCoder) { + // this catches the cases where bool encoded in Swift 2 needs to be decoded with decodeObject, but a Bool encoded in swift 3 needs + // to be decoded using decodeBool. This catches the upgrade case to ensure that we are always able to fetch a keyed valye for isCustomEngine + // http://stackoverflow.com/a/40034694 + let isCustomEngine = aDecoder.decodeAsBool(forKey: "isCustomEngine") + guard let searchTemplate = aDecoder.decodeObject(forKey: "searchTemplate") as? String, + let shortName = aDecoder.decodeObject(forKey: "shortName") as? String, + let image = aDecoder.decodeObject(forKey: "image") as? UIImage else { + assertionFailure() + return nil + } + + self.searchTemplate = searchTemplate + self.shortName = shortName + self.isCustomEngine = isCustomEngine + self.image = image + self.engineID = aDecoder.decodeObject(forKey: "engineID") as? String + self.suggestTemplate = nil + } + + func encode(with aCoder: NSCoder) { + aCoder.encode(searchTemplate, forKey: "searchTemplate") + aCoder.encode(shortName, forKey: "shortName") + aCoder.encode(isCustomEngine, forKey: "isCustomEngine") + aCoder.encode(image, forKey: "image") + aCoder.encode(engineID, forKey: "engineID") + } + + /** + * Returns the search URL for the given query. + */ + func searchURLForQuery(_ query: String) -> URL? { + return getURLFromTemplate(searchTemplate, query: query) + } + + /** + * Return the arg that we use for searching for this engine + * Problem: the search terms may not be a query arg, they may be part of the URL - how to deal with this? + **/ + fileprivate func getQueryArgFromTemplate() -> String? { + // we have the replace the templates SearchTermComponent in order to make the template + // a valid URL, otherwise we cannot do the conversion to NSURLComponents + // and have to do flaky pattern matching instead. + let placeholder = "PLACEHOLDER" + let template = searchTemplate.replacingOccurrences(of: SearchTermComponent, with: placeholder) + let components = URLComponents(string: template) + let searchTerm = components?.queryItems?.filter { item in + return item.value == placeholder + } + guard let term = searchTerm, !term.isEmpty else { return nil } + return term[0].name + } + + /** + * check that the URL host contains the name of the search engine somewhere inside it + **/ + fileprivate func isSearchURLForEngine(_ url: URL?) -> Bool { + guard let urlHost = url?.hostSLD, + let queryEndIndex = searchTemplate.range(of: "?")?.lowerBound, + let templateURL = URL(string: searchTemplate.substring(to: queryEndIndex)) else { return false } + return urlHost == templateURL.hostSLD + } + + /** + * Returns the query that was used to construct a given search URL + **/ + func queryForSearchURL(_ url: URL?) -> String? { + if isSearchURLForEngine(url) { + if let key = searchQueryComponentKey, + let value = url?.getQuery()[key] { + return value.replacingOccurrences(of: "+", with: " ").removingPercentEncoding + } + } + return nil + } + + /** + * Returns the search suggestion URL for the given query. + */ + func suggestURLForQuery(_ query: String) -> URL? { + if let suggestTemplate = suggestTemplate { + return getURLFromTemplate(suggestTemplate, query: query) + } + return nil + } + + fileprivate func getURLFromTemplate(_ searchTemplate: String, query: String) -> URL? { + if let escapedQuery = query.addingPercentEncoding(withAllowedCharacters: CharacterSet.SearchTermsAllowedCharacterSet()) { + // Escape the search template as well in case it contains not-safe characters like symbols + let templateAllowedSet = NSMutableCharacterSet() + templateAllowedSet.formUnion(with: CharacterSet.URLAllowedCharacterSet()) + + // Allow brackets since we use them in our template as our insertion point + templateAllowedSet.formUnion(with: CharacterSet(charactersIn: "{}")) + + if let encodedSearchTemplate = searchTemplate.addingPercentEncoding(withAllowedCharacters: templateAllowedSet as CharacterSet) { + let localeString = Locale.current.identifier + let urlString = encodedSearchTemplate + .replacingOccurrences(of: SearchTermComponent, with: escapedQuery, options: String.CompareOptions.literal, range: nil) + .replacingOccurrences(of: LocaleTermComponent, with: localeString, options: String.CompareOptions.literal, range: nil) + return URL(string: urlString) + } + } + + return nil + } +} + +/** + * OpenSearch XML parser. + * + * This parser accepts standards-compliant OpenSearch 1.1 XML documents in addition to + * the Firefox-specific search plugin format. + * + * OpenSearch spec: http://www.opensearch.org/Specifications/OpenSearch/1.1 + */ +class OpenSearchParser { + fileprivate let pluginMode: Bool + + init(pluginMode: Bool) { + self.pluginMode = pluginMode + } + + func parse(_ file: String, engineID: String) -> OpenSearchEngine? { + guard let data = try? Data(contentsOf: URL(fileURLWithPath: file)) else { + print("Invalid search file") + return nil + } + + guard let indexer = try? XMLDocument(data: data), + let docIndexer = indexer.root else { + print("Invalid XML document") + return nil + } + + let shortNameIndexer = docIndexer.children(tag: "ShortName") + if shortNameIndexer.count != 1 { + print("ShortName must appear exactly once") + return nil + } + + let shortName = shortNameIndexer[0].stringValue + if shortName == "" { + print("ShortName must contain text") + return nil + } + + let urlIndexers = docIndexer.children(tag: "Url") + if urlIndexers.isEmpty { + print("Url must appear at least once") + return nil + } + + var searchTemplate: String! + var suggestTemplate: String? + for urlIndexer in urlIndexers { + let type = urlIndexer.attributes["type"] + if type == nil { + print("Url element requires a type attribute", terminator: "\n") + return nil + } + + if type != TypeSearch && type != TypeSuggest { + // Not a supported search type. + continue + } + + var template = urlIndexer.attributes["template"] + if template == nil { + print("Url element requires a template attribute", terminator: "\n") + return nil + } + + if pluginMode { + let paramIndexers = urlIndexer.children(tag: "Param") + + if !paramIndexers.isEmpty { + template! += "?" + var firstAdded = false + for paramIndexer in paramIndexers { + if firstAdded { + template! += "&" + } else { + firstAdded = true + } + + let name = paramIndexer.attributes["name"] + let value = paramIndexer.attributes["value"] + if name == nil || value == nil { + print("Param element must have name and value attributes", terminator: "\n") + return nil + } + template! += name! + "=" + value! + } + } + } + + if type == TypeSearch { + searchTemplate = template + } else { + suggestTemplate = template + } + } + + if searchTemplate == nil { + print("Search engine must have a text/html type") + return nil + } + + let imageIndexers = docIndexer.children(tag: "Image") + var largestImage = 0 + var largestImageElement: XMLElement? + + // TODO: For now, just use the largest icon. + for imageIndexer in imageIndexers { + let imageWidth = Int(imageIndexer.attributes["width"] ?? "") + let imageHeight = Int(imageIndexer.attributes["height"] ?? "") + + // Only accept square images. + if imageWidth != imageHeight { + continue + } + + if let imageWidth = imageWidth { + if imageWidth > largestImage { + largestImage = imageWidth + largestImageElement = imageIndexer + } + } + } + + let uiImage: UIImage + if let imageElement = largestImageElement, + let imageURL = URL(string: imageElement.stringValue), + let imageData = try? Data(contentsOf: imageURL), + let image = UIImage.imageFromDataThreadSafe(imageData) { + uiImage = image + } else { + print("Error: Invalid search image data") + return nil + } + + return OpenSearchEngine(engineID: engineID, shortName: shortName, image: uiImage, searchTemplate: searchTemplate, suggestTemplate: suggestTemplate, isCustomEngine: false) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/OpenWithSettingsViewController.swift b/mobile/ios/Client/Frontend/Browser/OpenWithSettingsViewController.swift new file mode 100644 index 0000000000..e9de532ccd --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/OpenWithSettingsViewController.swift @@ -0,0 +1,123 @@ +/* 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/. */ + +import Foundation +import Shared + +class OpenWithSettingsViewController: UITableViewController { + typealias MailtoProviderEntry = (name: String, scheme: String, enabled: Bool) + var mailProviderSource = [MailtoProviderEntry]() + + fileprivate let prefs: Prefs + fileprivate var currentChoice: String = "mailto" + + fileprivate let BasicCheckmarkCell = "BasicCheckmarkCell" + + init(prefs: Prefs) { + self.prefs = prefs + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + title = Strings.SettingsOpenWithSectionName + + tableView.accessibilityIdentifier = "OpenWithPage.Setting.Options" + + tableView.register(UITableViewCell.self, forCellReuseIdentifier: BasicCheckmarkCell) + tableView.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + + let headerFooterFrame = CGRect(origin: CGPoint.zero, size: CGSize(width: self.view.frame.width, height: UIConstants.TableViewHeaderFooterHeight)) + let headerView = SettingsTableSectionHeaderFooterView(frame: headerFooterFrame) + headerView.titleLabel.text = Strings.SettingsOpenWithPageTitle.uppercased() + headerView.showTopBorder = false + headerView.showBottomBorder = true + + let footerView = SettingsTableSectionHeaderFooterView(frame: headerFooterFrame) + footerView.showTopBorder = true + footerView.showBottomBorder = false + + tableView.tableHeaderView = headerView + tableView.tableFooterView = footerView + + NotificationCenter.default.addObserver(self, selector: #selector(OpenWithSettingsViewController.appDidBecomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + appDidBecomeActive() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + self.prefs.setString(currentChoice, forKey: PrefsKeys.KeyMailToOption) + } + + func appDidBecomeActive() { + reloadMailProviderSource() + updateCurrentChoice() + tableView.reloadData() + } + + func updateCurrentChoice() { + var previousChoiceAvailable: Bool = false + if let prefMailtoScheme = self.prefs.stringForKey(PrefsKeys.KeyMailToOption) { + mailProviderSource.forEach({ (name, scheme, enabled) in + if scheme == prefMailtoScheme { + previousChoiceAvailable = enabled + } + }) + } + + if !previousChoiceAvailable { + self.prefs.setString(mailProviderSource[0].scheme, forKey: PrefsKeys.KeyMailToOption) + } + + if let updatedMailToClient = self.prefs.stringForKey(PrefsKeys.KeyMailToOption) { + self.currentChoice = updatedMailToClient + } + } + + func reloadMailProviderSource() { + if let path = Bundle.main.path(forResource: "MailSchemes", ofType: "plist"), let dictRoot = NSArray(contentsOfFile: path) { + mailProviderSource = dictRoot.map { dict in + let nsDict = dict as! NSDictionary + return (name: nsDict["name"] as! String, scheme: nsDict["scheme"] as! String, + enabled: canOpenMailScheme(nsDict["scheme"] as! String)) + } + } + } + + func canOpenMailScheme(_ scheme: String) -> Bool { + if let url = URL(string: scheme) { + return UIApplication.shared.canOpenURL(url) + } + return false + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: BasicCheckmarkCell, for: indexPath) + + let option = mailProviderSource[indexPath.row] + + cell.textLabel?.attributedText = NSAttributedString.tableRowTitle(option.name, enabled: option.enabled) + cell.accessoryType = (currentChoice == option.scheme && option.enabled) ? .checkmark : .none + cell.isUserInteractionEnabled = option.enabled + + return cell + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return mailProviderSource.count + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + self.currentChoice = mailProviderSource[indexPath.row].scheme + tableView.reloadData() + } +} diff --git a/mobile/ios/Client/Frontend/Browser/PrintHelper.swift b/mobile/ios/Client/Frontend/Browser/PrintHelper.swift new file mode 100644 index 0000000000..d56f0a377e --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/PrintHelper.swift @@ -0,0 +1,35 @@ +/* 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/. */ + +import Foundation +import Shared +import WebKit + +class PrintHelper: TabContentScript { + fileprivate weak var tab: Tab? + + class func name() -> String { + return "PrintHelper" + } + + required init(tab: Tab) { + self.tab = tab + if let path = Bundle.main.path(forResource: "PrintHelper", ofType: "js"), let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + + func scriptMessageHandlerName() -> String? { + return "printHandler" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + if let tab = tab, let webView = tab.webView { + let printController = UIPrintInteractionController.shared + printController.printFormatter = webView.viewPrintFormatter() + printController.present(animated: true, completionHandler: nil) + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/PrivilegedRequest.swift b/mobile/ios/Client/Frontend/Browser/PrivilegedRequest.swift new file mode 100644 index 0000000000..128b4ea8e4 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/PrivilegedRequest.swift @@ -0,0 +1,41 @@ +/* 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/. */ + +import Foundation + +private let REQUEST_KEY_PRIVILEGED = "privileged" + +/** + Request that is allowed to load local resources. + + Pages running on the local server have same origin access all resources + on the server, so we need to prevent arbitrary web pages from accessing + these resources. We do so by explicitly requiring "privileged" requests + in our navigation policy when loading local resources. + + Be careful: creating a privileged request for an arbitrary URL provided + by the page will break this model. Only use a privileged request when + needed, and when you are sure the URL is from a trustworthy source! + **/ +class PrivilegedRequest: NSMutableURLRequest { + override init(url URL: URL, cachePolicy: NSURLRequest.CachePolicy, timeoutInterval: TimeInterval) { + super.init(url: URL, cachePolicy: cachePolicy, timeoutInterval: timeoutInterval) + setPrivileged() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setPrivileged() + } + + fileprivate func setPrivileged() { + URLProtocol.setProperty(true, forKey: REQUEST_KEY_PRIVILEGED, in: self) + } +} + +extension URLRequest { + var isPrivileged: Bool { + return URLProtocol.property(forKey: REQUEST_KEY_PRIVILEGED, in: self) != nil + } +} diff --git a/mobile/ios/Client/Frontend/Browser/Punycode.swift b/mobile/ios/Client/Frontend/Browser/Punycode.swift new file mode 100644 index 0000000000..517019c198 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/Punycode.swift @@ -0,0 +1,198 @@ +/* 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/. */ + +import Foundation + +private let base = 36 +private let tMin = 1 +private let tMax = 26 +private let initialBias = 72 +private let initialN: Int = 128 // 0x80 +private let delimiter: Character = "-"; // '\x2D' +private let prefixPunycode = "xn--" +private let asciiPunycode = [Character]("abcdefghijklmnopqrstuvwxyz0123456789".characters) + +extension String { + fileprivate func toValue(_ index: Int) -> Character { + return asciiPunycode[index] + } + + fileprivate func toIndex(_ value: Character) -> Int { + return asciiPunycode.index(of: value)! + } + + fileprivate func adapt(_ delta: Int, numPoints: Int, firstTime: Bool) -> Int { + let skew = 38 + let damp = firstTime ? 700 : 2 + var delta = delta + delta = delta / damp + delta += delta / numPoints + var k = 0 + while delta > ((base - tMin) * tMax) / 2 { + delta /= (base - tMin) + k += base + } + return k + ((base - tMin + 1) * delta) / (delta + skew) + } + + fileprivate func encode(_ input: String) -> String { + var output = "" + var d: Int = 0 + var extendedChars = [Int]() + for c in input.unicodeScalars { + if Int(c.value) < initialN { + d += 1 + output.append(String(c)) + } else { + extendedChars.append(Int(c.value)) + } + } + if extendedChars.count == 0 { + return output + } + if d > 0 { + output.append(delimiter) + } + + var n = initialN + var delta = 0 + var bias = initialBias + var h: Int = 0 + var b: Int = 0 + + if d > 0 { + h = output.unicodeScalars.count - 1 + b = output.unicodeScalars.count - 1 + } else { + h = output.unicodeScalars.count + b = output.unicodeScalars.count + } + + while h < input.unicodeScalars.count { + var char = Int(0x7fffffff) + for c in input.unicodeScalars { + let ci = Int(c.value) + if char > ci && ci >= n { + char = ci + } + } + delta = delta + (char - n) * (h + 1) + if delta < 0 { + print("error: invalid char:") + output = "" + return output + } + n = char + for c in input.unicodeScalars { + let ci = Int(c.value) + if ci < n || ci < initialN { + delta += 1 + continue + } + if ci > n { + continue + } + var q = delta + var k = base + while true { + let t = max(min(k - bias, tMax), tMin) + if q < t { + break + } + let code = t + ((q - t) % (base - t)) + output.append(toValue(code)) + q = (q - t) / (base - t) + k += base + } + output.append(toValue(q)) + bias = self.adapt(delta, numPoints: h + 1, firstTime: h == b) + delta = 0 + h += 1 + } + delta += 1 + n += 1 + } + return output + } + + fileprivate func decode(_ punycode: String) -> String { + var input = [Character](punycode.characters) + var output = [Character]() + var i = 0 + var n = initialN + var bias = initialBias + var pos = 0 + if let ipos = input.index(of: delimiter) { + pos = ipos + output.append(contentsOf: input[0 ..< pos]) + pos += 1 + } + var outputLength = output.count + let inputLength = input.count + while pos < inputLength { + let oldi = i + var w = 1 + var k = base + while true { + let digit = toIndex(input[pos]) + pos += 1 + i += digit * w + let t = max(min(k - bias, tMax), tMin) + if digit < t { + break + } + w = w * (base - t) + k += base + } + outputLength += 1 + bias = adapt(i - oldi, numPoints: outputLength, firstTime: (oldi == 0)) + n = n + i / outputLength + i = i % outputLength + output.insert(Character(UnicodeScalar(n)!), at: i) + i += 1 + } + return String(output) + } + + fileprivate func isValidUnicodeScala(_ s: String) -> Bool { + for c in s.unicodeScalars { + let ci = Int(c.value) + if ci >= initialN { + return false + } + } + return true + } + + fileprivate func isValidPunycodeScala(_ s: String) -> Bool { + return s.hasPrefix(prefixPunycode) + } + + public func utf8HostToAscii() -> String { + if isValidUnicodeScala(self) { + return self + } + var labels = self.components(separatedBy: ".") + for (i, part) in labels.enumerated() { + if !isValidUnicodeScala(part) { + let a = encode(part) + labels[i] = prefixPunycode + a + } + } + let resultString = labels.joined(separator: ".") + return resultString + } + + public func asciiHostToUTF8() -> String { + var labels = self.components(separatedBy: ".") + for (index, part) in labels.enumerated() { + if isValidPunycodeScala(part) { + let changeStr = part.substring(from: part.characters.index(part.startIndex, offsetBy: 4)) + labels[index] = decode(changeStr) + } + } + let resultString = labels.joined(separator: ".") + return resultString + } +} diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/Contents.json b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/Contents.json b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/Contents.json new file mode 100644 index 0000000000..acc9878d2e --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "qrcode-goBack.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "qrcode-goBack@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "qrcode-goBack@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack.png new file mode 100644 index 0000000000..8ee322cf77 Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack@2x.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack@2x.png new file mode 100644 index 0000000000..36b8c21eca Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack@2x.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack@3x.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack@3x.png new file mode 100644 index 0000000000..88ec112fd5 Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-goBack.imageset/qrcode-goBack@3x.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/Contents.json b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/Contents.json new file mode 100644 index 0000000000..77e2fb8723 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "qrcode-isLighting.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "qrcode-isLighting@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "qrcode-isLighting@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting.png new file mode 100644 index 0000000000..a3ea881dc3 Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting@2x.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting@2x.png new file mode 100644 index 0000000000..0c49495b64 Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting@2x.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting@3x.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting@3x.png new file mode 100644 index 0000000000..2ca1265d6f Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-isLighting.imageset/qrcode-isLighting@3x.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/Contents.json b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/Contents.json new file mode 100644 index 0000000000..923eee6e64 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "qrcode-light.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "qrcode-light@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "qrcode-light@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light.png new file mode 100644 index 0000000000..7da9401738 Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light@2x.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light@2x.png new file mode 100644 index 0000000000..9da67c1888 Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light@2x.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light@3x.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light@3x.png new file mode 100644 index 0000000000..094ba8f7be Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-light.imageset/qrcode-light@3x.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanBorder.imageset/Contents.json b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanBorder.imageset/Contents.json new file mode 100644 index 0000000000..31465003e5 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanBorder.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "qrcode-scanBorder.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanBorder.imageset/qrcode-scanBorder.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanBorder.imageset/qrcode-scanBorder.png new file mode 100644 index 0000000000..2a61593d44 Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanBorder.imageset/qrcode-scanBorder.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanLine.imageset/Contents.json b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanLine.imageset/Contents.json new file mode 100644 index 0000000000..7ede851e8a --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanLine.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "qrcode-scanLine.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanLine.imageset/qrcode-scanLine.png b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanLine.imageset/qrcode-scanLine.png new file mode 100644 index 0000000000..8e990f29a1 Binary files /dev/null and b/mobile/ios/Client/Frontend/Browser/QRCode.xcassets/qrcode-scanLine.imageset/qrcode-scanLine.png differ diff --git a/mobile/ios/Client/Frontend/Browser/QRCodeViewController.swift b/mobile/ios/Client/Frontend/Browser/QRCodeViewController.swift new file mode 100644 index 0000000000..bf0a2c7eab --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/QRCodeViewController.swift @@ -0,0 +1,291 @@ +/* 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/. */ + +import Foundation +import AVFoundation +import SnapKit +import Shared + +private struct QRCodeViewControllerUX { + static let navigationBarBackgroundColor = UIColor.black + static let navigationBarTitleColor = UIColor.white + static let maskViewBackgroungColor = UIColor(colorLiteralRed: 0, green: 0, blue: 0, alpha: 0.5) + static let isLightingNavigationItemColor = UIColor(colorLiteralRed: 0.45, green: 0.67, blue: 0.84, alpha: 1) +} + +protocol QRCodeViewControllerDelegate { + func didScanQRCodeWithURL(_ url: URL) + func didScanQRCodeWithText(_ text: String) +} + +class QRCodeViewController: UIViewController { + var qrCodeDelegate: QRCodeViewControllerDelegate? + + fileprivate lazy var captureSession: AVCaptureSession = { + let session = AVCaptureSession() + session.sessionPreset = AVCaptureSessionPresetHigh + return session + }() + + private lazy var captureDevice: AVCaptureDevice? = { + return AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) + }() + + private var videoPreviewLayer: AVCaptureVideoPreviewLayer? + private let scanLine: UIImageView = UIImageView(image: UIImage(named: "qrcode-scanLine")) + private let scanBorder: UIImageView = UIImageView(image: UIImage(named: "qrcode-scanBorder")) + private lazy var instructionsLabel: UILabel = { + let label = UILabel() + label.text = Strings.ScanQRCodeInstructionsLabel + label.textColor = UIColor.white + label.textAlignment = NSTextAlignment.center + label.numberOfLines = 0 + return label + }() + private var maskView: UIView = UIView() + private var isAnimationing: Bool = false + private var isLightOn: Bool = false + private var shapeLayer: CAShapeLayer = CAShapeLayer() + + private var scanRange: CGRect { + let size = UIDevice.current.userInterfaceIdiom == .pad ? + CGSize(width: view.frame.width / 2, height: view.frame.width / 2) : + CGSize(width: view.frame.width / 3 * 2, height: view.frame.width / 3 * 2) + var rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) + rect.center = UIScreen.main.bounds.center + return rect + } + + private var scanBorderHeight: CGFloat { + return UIDevice.current.userInterfaceIdiom == .pad ? + view.frame.width / 2 : view.frame.width / 3 * 2 + } + + override func viewDidLoad() { + super.viewDidLoad() + + guard let captureDevice = self.captureDevice else { + dismiss(animated: false) + return + } + + self.navigationItem.title = Strings.ScanQRCodeViewTitle + + // Setup the NavigationBar + self.navigationController?.navigationBar.barTintColor = QRCodeViewControllerUX.navigationBarBackgroundColor + self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: QRCodeViewControllerUX.navigationBarTitleColor] + + // Setup the NavigationItem + self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "qrcode-goBack"), style: UIBarButtonItemStyle.plain, target: self, action: #selector(goBack)) + self.navigationItem.leftBarButtonItem?.tintColor = UIColor.white + + self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "qrcode-light"), style: .plain, target: self, action: #selector(openLight)) + if captureDevice.hasTorch { + self.navigationItem.rightBarButtonItem?.tintColor = UIColor.white + } else { + self.navigationItem.rightBarButtonItem?.tintColor = UIColor.gray + self.navigationItem.rightBarButtonItem?.isEnabled = false + } + + let getAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) + if getAuthorizationStatus != AVAuthorizationStatus.denied { + setupCamera() + } else { + let alert = UIAlertController(title: "", message: Strings.ScanQRCodePermissionErrorMessage, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: Strings.ScanQRCodeErrorOKButton, style: .default, handler: nil)) + self.present(alert, animated: true, completion: nil) + } + + maskView.backgroundColor = QRCodeViewControllerUX.maskViewBackgroungColor + self.view.addSubview(maskView) + self.view.addSubview(scanBorder) + self.view.addSubview(scanLine) + self.view.addSubview(instructionsLabel) + + setupConstraints() + let rectPath = UIBezierPath(rect: UIScreen.main.bounds) + rectPath.append(UIBezierPath(rect: scanRange).reversing()) + shapeLayer.path = rectPath.cgPath + maskView.layer.mask = shapeLayer + + isAnimationing = true + startScanLineAnimation() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + self.captureSession.stopRunning() + stopScanLineAnimation() + } + + private func setupConstraints() { + maskView.snp.makeConstraints { (make) in + make.edges.equalTo(self.view) + } + if UIDevice.current.userInterfaceIdiom == .pad { + scanBorder.snp.makeConstraints { (make) in + make.center.equalTo(self.view) + make.width.height.equalTo(view.frame.width / 2) + } + } else { + scanBorder.snp.makeConstraints { (make) in + make.center.equalTo(self.view) + make.width.height.equalTo(view.frame.width / 3 * 2) + } + } + scanLine.snp.makeConstraints { (make) in + make.left.equalTo(scanBorder.snp.left) + make.top.equalTo(scanBorder.snp.top).offset(6) + make.width.equalTo(scanBorder.snp.width) + make.height.equalTo(6) + } + + instructionsLabel.snp.makeConstraints { (make) in + make.left.right.equalTo(self.view.layoutMarginsGuide) + make.top.equalTo(scanBorder.snp.bottom).offset(30) + } + } + + func startScanLineAnimation() { + if !isAnimationing { + return + } + self.view.layoutIfNeeded() + self.view.setNeedsLayout() + UIView.animate(withDuration: 2.4, animations: { + self.scanLine.snp.updateConstraints({ (make) in + make.top.equalTo(self.scanBorder.snp.top).offset(self.scanBorderHeight - 6) + }) + self.view.layoutIfNeeded() + }) { (value: Bool) in + self.scanLine.snp.updateConstraints({ (make) in + make.top.equalTo(self.scanBorder.snp.top).offset(6) + }) + self.perform(#selector(self.startScanLineAnimation), with: nil, afterDelay: 0) + } + } + + func stopScanLineAnimation() { + isAnimationing = false + } + + func goBack() { + self.dismiss(animated: true, completion: nil) + } + + func openLight() { + guard let captureDevice = self.captureDevice else { + return + } + + if isLightOn { + do { + try captureDevice.lockForConfiguration() + captureDevice.torchMode = AVCaptureTorchMode.off + captureDevice.unlockForConfiguration() + navigationItem.rightBarButtonItem?.image = UIImage(named: "qrcode-light") + navigationItem.rightBarButtonItem?.tintColor = UIColor.white + } catch { + print(error) + } + } else { + do { + try captureDevice.lockForConfiguration() + captureDevice.torchMode = AVCaptureTorchMode.on + captureDevice.unlockForConfiguration() + navigationItem.rightBarButtonItem?.image = UIImage(named: "qrcode-isLighting") + navigationItem.rightBarButtonItem?.tintColor = QRCodeViewControllerUX.isLightingNavigationItemColor + } catch { + print(error) + } + } + isLightOn = !isLightOn + } + + func setupCamera() { + guard let captureDevice = self.captureDevice else { + dismiss(animated: false) + return + } + + do { + let input = try AVCaptureDeviceInput(device: captureDevice) + captureSession.addInput(input) + } catch { + print(error) + } + let output = AVCaptureMetadataOutput() + if captureSession.canAddOutput(output) { + captureSession.addOutput(output) + output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) + output.metadataObjectTypes = [AVMetadataObjectTypeQRCode] + } + if let videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) { + videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill + videoPreviewLayer.frame = UIScreen.main.bounds + view.layer.addSublayer(videoPreviewLayer) + self.videoPreviewLayer = videoPreviewLayer + captureSession.startRunning() + } + } + + override func willAnimateRotation(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { + shapeLayer.removeFromSuperlayer() + let rectPath = UIBezierPath(rect: UIScreen.main.bounds) + rectPath.append(UIBezierPath(rect: scanRange).reversing()) + shapeLayer.path = rectPath.cgPath + maskView.layer.mask = shapeLayer + + guard let videoPreviewLayer = self.videoPreviewLayer else { + return + } + videoPreviewLayer.frame = UIScreen.main.bounds + switch toInterfaceOrientation { + case .portrait: + videoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait + case .landscapeLeft: + videoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientation.landscapeLeft + case .landscapeRight: + videoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientation.landscapeRight + case .portraitUpsideDown: + videoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown + default: + videoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait + } + } +} + +extension QRCodeViewController: AVCaptureMetadataOutputObjectsDelegate { + func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { + if metadataObjects == nil || metadataObjects.count == 0 { + self.captureSession.stopRunning() + let alert = UIAlertController(title: "", message: Strings.ScanQRCodeInvalidDataErrorMessage, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: Strings.ScanQRCodeErrorOKButton, style: .default, handler: { (UIAlertAction) in + self.captureSession.startRunning() + })) + self.present(alert, animated: true, completion: nil) + } else { + self.captureSession.stopRunning() + stopScanLineAnimation() + self.dismiss(animated: true, completion: { + guard let metaData = metadataObjects.first as? AVMetadataMachineReadableCodeObject, let qrCodeDelegate = self.qrCodeDelegate, let text = metaData.stringValue else { + Sentry.shared.sendWithStacktrace(message: "Unable to scan QR code", tag: .general) + return + } + + if let url = URIFixup.getURL(text) { + qrCodeDelegate.didScanQRCodeWithURL(url) + } else { + qrCodeDelegate.didScanQRCodeWithText(text) + } + }) + } + } +} + +class QRCodeNavigationController: UINavigationController { + override open var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } +} diff --git a/mobile/ios/Client/Frontend/Browser/ReaderModeBarView.swift b/mobile/ios/Client/Frontend/Browser/ReaderModeBarView.swift new file mode 100644 index 0000000000..07153f0de7 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/ReaderModeBarView.swift @@ -0,0 +1,172 @@ +/* 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/. */ + +import Foundation +import UIKit +import SnapKit +import Shared +import XCGLogger + +private let log = Logger.browserLogger + +enum ReaderModeBarButtonType { + case markAsRead, markAsUnread, settings, addToReadingList, removeFromReadingList + + fileprivate var localizedDescription: String { + switch self { + case .markAsRead: return NSLocalizedString("Mark as Read", comment: "Name for Mark as read button in reader mode") + case .markAsUnread: return NSLocalizedString("Mark as Unread", comment: "Name for Mark as unread button in reader mode") + case .settings: return NSLocalizedString("Display Settings", comment: "Name for display settings button in reader mode. Display in the meaning of presentation, not monitor.") + case .addToReadingList: return NSLocalizedString("Add to Reading List", comment: "Name for button adding current article to reading list in reader mode") + case .removeFromReadingList: return NSLocalizedString("Remove from Reading List", comment: "Name for button removing current article from reading list in reader mode") + } + } + + fileprivate var imageName: String { + switch self { + case .markAsRead: return "MarkAsRead" + case .markAsUnread: return "MarkAsUnread" + case .settings: return "SettingsSerif" + case .addToReadingList: return "addToReadingList" + case .removeFromReadingList: return "removeFromReadingList" + } + } + + fileprivate var image: UIImage? { + let image = UIImage(named: imageName) + image?.accessibilityLabel = localizedDescription + return image + } +} + +protocol ReaderModeBarViewDelegate { + func readerModeBar(_ readerModeBar: ReaderModeBarView, didSelectButton buttonType: ReaderModeBarButtonType) +} + +struct ReaderModeBarViewUX { + + static let Themes: [String: Theme] = { + var themes = [String: Theme]() + var theme = Theme() + theme.backgroundColor = UIColor(rgb: 0x38383D) + theme.buttonTintColor = UIColor(rgb: 0xf9f9fA) + themes[Theme.PrivateMode] = theme + + theme = Theme() + theme.backgroundColor = UIColor(rgb: 0xf9f9fA) + theme.buttonTintColor = UIColor(rgb: 0x272727) + themes[Theme.NormalMode] = theme + + return themes + }() +} + +class ReaderModeBarView: UIView { + var delegate: ReaderModeBarViewDelegate? + + var readStatusButton: UIButton! + var settingsButton: UIButton! + var listStatusButton: UIButton! + + dynamic var buttonTintColor: UIColor = UIColor.clear { + didSet { + readStatusButton.tintColor = self.buttonTintColor + settingsButton.tintColor = self.buttonTintColor + listStatusButton.tintColor = self.buttonTintColor + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + readStatusButton = createButton(.markAsRead, action: #selector(ReaderModeBarView.SELtappedReadStatusButton(_:))) + readStatusButton.accessibilityIdentifier = "ReaderModeBarView.readStatusButton" + readStatusButton.snp.makeConstraints { (make) -> Void in + make.left.equalTo(self) + make.height.centerY.equalTo(self) + make.width.equalTo(80) + } + + settingsButton = createButton(.settings, action: #selector(ReaderModeBarView.SELtappedSettingsButton(_:))) + settingsButton.accessibilityIdentifier = "ReaderModeBarView.settingsButton" + settingsButton.snp.makeConstraints { (make) -> Void in + make.height.centerX.centerY.equalTo(self) + make.width.equalTo(80) + } + + listStatusButton = createButton(.addToReadingList, action: #selector(ReaderModeBarView.SELtappedListStatusButton(_:))) + listStatusButton.accessibilityIdentifier = "ReaderModeBarView.listStatusButton" + listStatusButton.snp.makeConstraints { (make) -> Void in + make.right.equalTo(self) + make.height.centerY.equalTo(self) + make.width.equalTo(80) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ rect: CGRect) { + super.draw(rect) + guard let context = UIGraphicsGetCurrentContext() else { return } + context.setLineWidth(0.5) + context.setStrokeColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1.0) + context.setStrokeColor(UIColor.gray.cgColor) + context.beginPath() + context.move(to: CGPoint(x: 0, y: frame.height)) + context.addLine(to: CGPoint(x: frame.width, y: frame.height)) + context.strokePath() + } + + fileprivate func createButton(_ type: ReaderModeBarButtonType, action: Selector) -> UIButton { + let button = UIButton() + addSubview(button) + button.setImage(type.image, for: UIControlState()) + button.addTarget(self, action: action, for: .touchUpInside) + return button + } + + func SELtappedReadStatusButton(_ sender: UIButton!) { + UnifiedTelemetry.recordEvent(category: .action, method: .tap, object: .readingListItem, value: unread ? .markAsRead : .markAsUnread, extras: [ "from": "reader-mode-toolbar" ]) + delegate?.readerModeBar(self, didSelectButton: unread ? .markAsRead : .markAsUnread) + } + + func SELtappedSettingsButton(_ sender: UIButton!) { + delegate?.readerModeBar(self, didSelectButton: .settings) + } + + func SELtappedListStatusButton(_ sender: UIButton!) { + UnifiedTelemetry.recordEvent(category: .action, method: added ? .delete : .add, object: .readingListItem, value: .readerModeToolbar) + delegate?.readerModeBar(self, didSelectButton: added ? .removeFromReadingList : .addToReadingList) + } + + var unread: Bool = true { + didSet { + let buttonType: ReaderModeBarButtonType = unread && added ? .markAsRead : .markAsUnread + readStatusButton.setImage(buttonType.image, for: UIControlState()) + readStatusButton.isEnabled = added + readStatusButton.alpha = added ? 1.0 : 0.6 + } + } + + var added: Bool = false { + didSet { + let buttonType: ReaderModeBarButtonType = added ? .removeFromReadingList : .addToReadingList + listStatusButton.setImage(buttonType.image, for: UIControlState()) + } + } +} + +extension ReaderModeBarView: Themeable { + func applyTheme(_ themeName: String) { + guard let theme = ReaderModeBarViewUX.Themes[themeName] else { + log.error("Unable to apply unknown theme \(themeName)") + return + } + + backgroundColor = theme.backgroundColor + buttonTintColor = theme.buttonTintColor! + } +} diff --git a/mobile/ios/Client/Frontend/Browser/ScreenshotHelper.swift b/mobile/ios/Client/Frontend/Browser/ScreenshotHelper.swift new file mode 100644 index 0000000000..83370dba8e --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/ScreenshotHelper.swift @@ -0,0 +1,59 @@ +/* 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/. */ + +import Foundation + +/** + * Handles screenshots for a given tab, including pages with non-webview content. + */ +class ScreenshotHelper { + var viewIsVisible = false + + fileprivate weak var controller: BrowserViewController? + + init(controller: BrowserViewController) { + self.controller = controller + } + + func takeScreenshot(_ tab: Tab) { + var screenshot: UIImage? + + if let url = tab.url { + if url.isAboutHomeURL { + if let homePanel = controller?.homePanelController { + screenshot = homePanel.view.screenshot(quality: UIConstants.ActiveScreenshotQuality) + } + } else { + let offset = CGPoint(x: 0, y: -(tab.webView?.scrollView.contentInset.top ?? 0)) + screenshot = tab.webView?.screenshot(offset: offset, quality: UIConstants.ActiveScreenshotQuality) + } + } + + tab.setScreenshot(screenshot) + } + + /// Takes a screenshot after a small delay. + /// Trying to take a screenshot immediately after didFinishNavigation results in a screenshot + /// of the previous page, presumably due to an iOS bug. Adding a brief delay fixes this. + func takeDelayedScreenshot(_ tab: Tab) { + let time = DispatchTime.now() + Double(Int64(100 * NSEC_PER_MSEC)) / Double(NSEC_PER_SEC) + DispatchQueue.main.asyncAfter(deadline: time) { + // If the view controller isn't visible, the screenshot will be blank. + // Wait until the view controller is visible again to take the screenshot. + guard self.viewIsVisible else { + tab.pendingScreenshot = true + return + } + + self.takeScreenshot(tab) + } + } + + func takePendingScreenshots(_ tabs: [Tab]) { + for tab in tabs where tab.pendingScreenshot { + tab.pendingScreenshot = false + takeDelayedScreenshot(tab) + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SearchEngines.swift b/mobile/ios/Client/Frontend/Browser/SearchEngines.swift new file mode 100644 index 0000000000..6482f4d8ad --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SearchEngines.swift @@ -0,0 +1,291 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger + +private let log = Logger.browserLogger + +private let OrderedEngineNames = "search.orderedEngineNames" +private let DisabledEngineNames = "search.disabledEngineNames" +private let ShowSearchSuggestionsOptIn = "search.suggestions.showOptIn" +private let ShowSearchSuggestions = "search.suggestions.show" +private let customSearchEnginesFileName = "customEngines.plist" + +/** + * Manage a set of Open Search engines. + * + * The search engines are ordered. Individual search engines can be enabled and disabled. The + * first search engine is distinguished and labeled the "default" search engine; it can never be + * disabled. Search suggestions should always be sourced from the default search engine. + * + * Two additional bits of information are maintained: whether the user should be shown "opt-in to + * search suggestions" UI, and whether search suggestions are enabled. + * + * Consumers will almost always use `defaultEngine` if they want a single search engine, and + * `quickSearchEngines()` if they want a list of enabled quick search engines (possibly empty, + * since the default engine is never included in the list of enabled quick search engines, and + * it is possible to disable every non-default quick search engine). + * + * The search engines are backed by a write-through cache into a ProfilePrefs instance. This class + * is not thread-safe -- you should only access it on a single thread (usually, the main thread)! + */ +class SearchEngines { + fileprivate let prefs: Prefs + fileprivate let fileAccessor: FileAccessor + + init(prefs: Prefs, files: FileAccessor) { + self.prefs = prefs + // By default, show search suggestions + self.shouldShowSearchSuggestions = prefs.boolForKey(ShowSearchSuggestions) ?? true + self.fileAccessor = files + self.disabledEngineNames = getDisabledEngineNames() + self.orderedEngines = getOrderedEngines() + } + + var defaultEngine: OpenSearchEngine { + get { + return self.orderedEngines[0] + } + + set(defaultEngine) { + // The default engine is always enabled. + self.enableEngine(defaultEngine) + // The default engine is always first in the list. + var orderedEngines = self.orderedEngines.filter { engine in engine.shortName != defaultEngine.shortName } + orderedEngines.insert(defaultEngine, at: 0) + self.orderedEngines = orderedEngines + } + } + + func isEngineDefault(_ engine: OpenSearchEngine) -> Bool { + return defaultEngine.shortName == engine.shortName + } + + // The keys of this dictionary are used as a set. + fileprivate var disabledEngineNames: [String: Bool]! { + didSet { + self.prefs.setObject(Array(self.disabledEngineNames.keys), forKey: DisabledEngineNames) + } + } + + var orderedEngines: [OpenSearchEngine]! { + didSet { + self.prefs.setObject(self.orderedEngines.map { $0.shortName }, forKey: OrderedEngineNames) + } + } + + var quickSearchEngines: [OpenSearchEngine]! { + get { + return self.orderedEngines.filter({ (engine) in !self.isEngineDefault(engine) && self.isEngineEnabled(engine) }) + } + } + + var shouldShowSearchSuggestions: Bool { + didSet { + self.prefs.setObject(shouldShowSearchSuggestions, forKey: ShowSearchSuggestions) + } + } + + func isEngineEnabled(_ engine: OpenSearchEngine) -> Bool { + return disabledEngineNames.index(forKey: engine.shortName) == nil + } + + func enableEngine(_ engine: OpenSearchEngine) { + disabledEngineNames.removeValue(forKey: engine.shortName) + } + + func disableEngine(_ engine: OpenSearchEngine) { + if isEngineDefault(engine) { + // Can't disable default engine. + return + } + disabledEngineNames[engine.shortName] = true + } + + func deleteCustomEngine(_ engine: OpenSearchEngine) { + // We can't delete a preinstalled engine or an engine that is currently the default. + if !engine.isCustomEngine || isEngineDefault(engine) { + return + } + + customEngines.remove(at: customEngines.index(of: engine)!) + saveCustomEngines() + orderedEngines = getOrderedEngines() + } + + /// Adds an engine to the front of the search engines list. + func addSearchEngine(_ engine: OpenSearchEngine) { + customEngines.append(engine) + orderedEngines.insert(engine, at: 1) + saveCustomEngines() + } + + func queryForSearchURL(_ url: URL?) -> String? { + for engine in orderedEngines { + guard let searchTerm = engine.queryForSearchURL(url) else { continue } + return searchTerm + } + return nil + } + + fileprivate func getDisabledEngineNames() -> [String: Bool] { + if let disabledEngineNames = self.prefs.stringArrayForKey(DisabledEngineNames) { + var disabledEngineDict = [String: Bool]() + for engineName in disabledEngineNames { + disabledEngineDict[engineName] = true + } + return disabledEngineDict + } else { + return [String: Bool]() + } + } + + fileprivate func customEngineFilePath() -> String { + let profilePath = try! self.fileAccessor.getAndEnsureDirectory() as NSString + return profilePath.appendingPathComponent(customSearchEnginesFileName) + } + + fileprivate lazy var customEngines: [OpenSearchEngine] = { + return NSKeyedUnarchiver.unarchiveObject(withFile: self.customEngineFilePath()) as? [OpenSearchEngine] ?? [] + }() + + fileprivate func saveCustomEngines() { + NSKeyedArchiver.archiveRootObject(customEngines, toFile: self.customEngineFilePath()) + } + + /// Return all possible paths for a language identifier in the order of most specific to least specific. + /// For example, zh-Hans-CN with a default of en will return [zh-Hans-CN, zh-CN, zh, en]. The fallback + /// identifier must be a known one that is guaranteed to exist in the SearchPlugins directory. + class func directoriesForLanguageIdentifier(_ languageIdentifier: String, basePath: NSString, fallbackIdentifier: String) -> [String] { + var directories = [String]() + let components = languageIdentifier.components(separatedBy: "-") + if components.count == 1 { + // zh + directories.append(languageIdentifier) + } else if components.count == 2 { + // zh-CN + directories.append(languageIdentifier) + directories.append(components[0]) + } else if components.count == 3 { + directories.append(languageIdentifier) + directories.append(components[0] + "-" + components[2]) + directories.append(components[0]) + } + if !directories.contains(fallbackIdentifier) { + directories.append(fallbackIdentifier) + } + + return directories.map { (path) -> String in + return basePath.appendingPathComponent(path) + } + } + + // Return the language identifier to be used for the search engine selection. This returns the first + // identifier from preferredLanguages and takes into account that on iOS 8, zh-Hans-CN is returned as + // zh-Hans. In that case it returns the longer form zh-Hans-CN. Same for traditional Chinese. + // + // These exceptions can go away when we drop iOS 8 or when we start using a better mechanism for search + // engine selection that is not based on language identifier. + class func languageIdentifierForSearchEngines() -> String { + let languageIdentifier = Locale.preferredLanguages.first! + switch languageIdentifier { + case "zh-Hans": + return "zh-Hans-CN" + case "zh-Hant": + return "zh-Hant-TW" + default: + return languageIdentifier + } + } + + /// Get all bundled (not custom) search engines, with the default search engine first, + /// but the others in no particular order. + class func getUnorderedBundledEngines() -> [OpenSearchEngine] { + let pluginBasePath: NSString = (Bundle.main.resourcePath! as NSString).appendingPathComponent("SearchPlugins") as NSString + let languageIdentifier = languageIdentifierForSearchEngines() + let fallbackDirectory: NSString = pluginBasePath.appendingPathComponent("en") as NSString + + var directory: String? + for path in directoriesForLanguageIdentifier(languageIdentifier, basePath: pluginBasePath, fallbackIdentifier: "en") { + if FileManager.default.fileExists(atPath: path) { + directory = path + break + } + } + + // This cannot happen if we include the fallback, but if it does we return no engines at all + guard let searchDirectory = directory else { + return [] + } + + let index = (searchDirectory as NSString).appendingPathComponent("list.txt") + let listFile = try? String(contentsOfFile: index, encoding: String.Encoding.utf8) + assert(listFile != nil, "Read the list of search engines") + + let engineNames = listFile! + .trimmingCharacters(in: CharacterSet.newlines) + .components(separatedBy: CharacterSet.newlines) + + var engines = [OpenSearchEngine]() + let parser = OpenSearchParser(pluginMode: true) + for engineName in engineNames { + // Ignore hidden engines in list.txt + if engineName.endsWith(":hidden") { + continue + } + + // Search the current localized search plugins directory for the search engine. + // If it doesn't exist, fall back to English. + var fullPath = (searchDirectory as NSString).appendingPathComponent("\(engineName).xml") + if !FileManager.default.fileExists(atPath: fullPath) { + fullPath = fallbackDirectory.appendingPathComponent("\(engineName).xml") + } + assert(FileManager.default.fileExists(atPath: fullPath), "\(fullPath) exists") + + guard let engine = parser.parse(fullPath, engineID: engineName) else { + log.error("Failed to parse search engine ID \(engineName) at \(fullPath)") + continue + } + engines.append(engine) + } + + let defaultEngineFile = (searchDirectory as NSString).appendingPathComponent("default.txt") + let defaultEngineName = try? String(contentsOfFile: defaultEngineFile, encoding: String.Encoding.utf8).trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + + return engines.sorted { e, _ in e.shortName == defaultEngineName } + } + + /// Get all known search engines, possibly as ordered by the user. + fileprivate func getOrderedEngines() -> [OpenSearchEngine] { + let unorderedEngines = customEngines + SearchEngines.getUnorderedBundledEngines() + + guard let orderedEngineNames = prefs.stringArrayForKey(OrderedEngineNames) else { + // We haven't persisted the engine order, so return whatever order we got from disk. + return unorderedEngines + } + + // We have a persisted order of engines, so try to use that order. + // We may have found engines that weren't persisted in the ordered list + // (if the user changed locales or added a new engine); these engines + // will be appended to the end of the list. + return unorderedEngines.sorted { engine1, engine2 in + let index1 = orderedEngineNames.index(of: engine1.shortName) + let index2 = orderedEngineNames.index(of: engine2.shortName) + + if index1 == nil && index2 == nil { + return engine1.shortName < engine2.shortName + } + + // nil < N for all non-nil values of N. + if index1 == nil || index2 == nil { + return index1 ?? -1 > index2 ?? -1 + } + + return index1! < index2! + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SearchLoader.swift b/mobile/ios/Client/Frontend/Browser/SearchLoader.swift new file mode 100644 index 0000000000..ffae17d23f --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SearchLoader.swift @@ -0,0 +1,135 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger + +private let log = Logger.browserLogger + +private let URLBeforePathRegex = try! NSRegularExpression(pattern: "^https?://([^/]+)/", options: []) + +// TODO: Swift currently requires that classes extending generic classes must also be generic. +// This is a workaround until that requirement is fixed. +typealias SearchLoader = _SearchLoader + +/** + * Shared data source for the SearchViewController and the URLBar domain completion. + * Since both of these use the same SQL query, we can perform the query once and dispatch the results. + */ +class _SearchLoader: Loader, SearchViewController> { + fileprivate let profile: Profile + fileprivate let urlBar: URLBarView + fileprivate let frecentHistory: FrecentHistory + + init(profile: Profile, urlBar: URLBarView) { + self.profile = profile + self.urlBar = urlBar + frecentHistory = profile.history.getFrecentHistory() + + super.init() + } + + fileprivate lazy var topDomains: [String] = { + let filePath = Bundle.main.path(forResource: "topdomains", ofType: "txt") + return try! String(contentsOfFile: filePath!).components(separatedBy: "\n") + }() + + // `weak` usage here allows deferred queue to be the owner. The deferred is always filled and this set to nil, + // this is defensive against any changes to queue (or cancellation) behaviour in future. + private weak var currentDbQuery: Cancellable? + + var query: String = "" { + didSet { + guard let profile = self.profile as? BrowserProfile else { + assertionFailure("nil profile") + return + } + + if query.isEmpty { + load(Cursor(status: .success, msg: "Empty query")) + return + } + + if let currentDbQuery = currentDbQuery { + profile.db.cancel(databaseOperation: WeakRef(currentDbQuery)) + } + + let deferred = frecentHistory.getSites(whereURLContains: query, historyLimit: 100, bookmarksLimit: 5) + currentDbQuery = deferred as? Cancellable + + deferred.uponQueue(DispatchQueue.main) { result in + defer { + self.currentDbQuery = nil + } + + guard let deferred = deferred as? Cancellable, !deferred.cancelled else { + return + } + + // Failed cursors are excluded in .get(). + if let cursor = result.successValue { + // First, see if the query matches any URLs from the user's search history. + self.load(cursor) + for site in cursor { + if let url = site?.url, + let completion = self.completionForURL(url) { + self.urlBar.setAutocompleteSuggestion(completion) + return + } + } + + // If there are no search history matches, try matching one of the Alexa top domains. + for domain in self.topDomains { + if let completion = self.completionForDomain(domain) { + self.urlBar.setAutocompleteSuggestion(completion) + return + } + } + } + } + } + } + + fileprivate func completionForURL(_ url: String) -> String? { + // Extract the pre-path substring from the URL. This should be more efficient than parsing via + // NSURL since we need to only look at the beginning of the string. + // Note that we won't match non-HTTP(S) URLs. + guard let match = URLBeforePathRegex.firstMatch(in: url, options: NSRegularExpression.MatchingOptions(), range: NSRange(location: 0, length: url.characters.count)) else { + return nil + } + + // If the pre-path component (including the scheme) starts with the query, just use it as is. + var prePathURL = (url as NSString).substring(with: match.rangeAt(0)) + if prePathURL.startsWith(query) { + // Trailing slashes in the autocompleteTextField cause issues with Swype keyboard. Bug 1194714 + if prePathURL.endsWith("/") { + prePathURL.remove(at: prePathURL.index(before: prePathURL.endIndex)) + } + return prePathURL + } + + // Otherwise, find and use any matching domain. + // To simplify the search, prepend a ".", and search the string for ".query". + // For example, for http://en.m.wikipedia.org, domainWithDotPrefix will be ".en.m.wikipedia.org". + // This allows us to use the "." as a separator, so we can match "en", "m", "wikipedia", and "org", + let domain = (url as NSString).substring(with: match.rangeAt(1)) + return completionForDomain(domain) + } + + fileprivate func completionForDomain(_ domain: String) -> String? { + let domainWithDotPrefix: String = ".\(domain)" + if let range = domainWithDotPrefix.range(of: ".\(query)", options: NSString.CompareOptions.caseInsensitive, range: nil, locale: nil) { + // We don't actually want to match the top-level domain ("com", "org", etc.) by itself, so + // so make sure the result includes at least one ".". + let matchedDomain: String = domainWithDotPrefix.substring(from: domainWithDotPrefix.index(range.lowerBound, offsetBy: 1)) + if matchedDomain.contains(".") { + return matchedDomain + } + } + + return nil + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SearchSuggestClient.swift b/mobile/ios/Client/Frontend/Browser/SearchSuggestClient.swift new file mode 100644 index 0000000000..21f05120fa --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SearchSuggestClient.swift @@ -0,0 +1,78 @@ +/* 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/. */ + +import Alamofire +import Foundation +import Shared + +let SearchSuggestClientErrorDomain = "org.mozilla.firefox.SearchSuggestClient" +let SearchSuggestClientErrorInvalidEngine = 0 +let SearchSuggestClientErrorInvalidResponse = 1 + +/* + * Clients of SearchSuggestionClient should retain the object during the + * lifetime of the search suggestion query, as requests are canceled during destruction. + * + * Query callbacks that must run even if they are cancelled should wrap their contents in `withExtendendLifetime`. + */ +class SearchSuggestClient { + fileprivate let searchEngine: OpenSearchEngine + fileprivate weak var request: Request? + fileprivate let userAgent: String + + lazy fileprivate var alamofire: SessionManager = { + let configuration = URLSessionConfiguration.ephemeral + var defaultHeaders = SessionManager.default.session.configuration.httpAdditionalHeaders ?? [:] + defaultHeaders["User-Agent"] = self.userAgent + configuration.httpAdditionalHeaders = defaultHeaders + return SessionManager(configuration: configuration) + }() + + init(searchEngine: OpenSearchEngine, userAgent: String) { + self.searchEngine = searchEngine + self.userAgent = userAgent + } + + func query(_ query: String, callback: @escaping (_ response: [String]?, _ error: NSError?) -> Void) { + let url = searchEngine.suggestURLForQuery(query) + if url == nil { + let error = NSError(domain: SearchSuggestClientErrorDomain, code: SearchSuggestClientErrorInvalidEngine, userInfo: nil) + callback(nil, error) + return + } + + request = alamofire.request(url!) + .validate(statusCode: 200..<300) + .responseJSON { response in + if let error = response.result.error { + callback(nil, error as NSError?) + return + } + + // The response will be of the following format: + // ["foobar",["foobar","foobar2000 mac","foobar skins",...]] + // That is, an array of at least two elements: the search term and an array of suggestions. + let array = response.result.value as? NSArray + if array?.count ?? 0 < 2 { + let error = NSError(domain: SearchSuggestClientErrorDomain, code: SearchSuggestClientErrorInvalidResponse, userInfo: nil) + callback(nil, error) + return + } + + let suggestions = array?[1] as? [String] + if suggestions == nil { + let error = NSError(domain: SearchSuggestClientErrorDomain, code: SearchSuggestClientErrorInvalidResponse, userInfo: nil) + callback(nil, error) + return + } + + callback(suggestions!, nil) + } + + } + + func cancelPendingRequest() { + request?.cancel() + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SearchViewController.swift b/mobile/ios/Client/Frontend/Browser/SearchViewController.swift new file mode 100644 index 0000000000..65b1c0daf3 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SearchViewController.swift @@ -0,0 +1,635 @@ +/* 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/. */ + +import UIKit +import Shared +import Storage +import Telemetry + +private enum SearchListSection: Int { + case searchSuggestions + case bookmarksAndHistory + static let Count = 2 +} + +private struct SearchViewControllerUX { + static let SearchEngineScrollViewBackgroundColor = UIColor.white.withAlphaComponent(0.8).cgColor + static let SearchEngineScrollViewBorderColor = UIColor.black.withAlphaComponent(0.2).cgColor + + // TODO: This should use ToolbarHeight in BVC. Fix this when we create a shared theming file. + static let EngineButtonHeight: Float = 44 + static let EngineButtonWidth = EngineButtonHeight * 1.4 + static let EngineButtonBackgroundColor = UIColor.clear.cgColor + + static let SearchImage = "search" + static let SearchEngineTopBorderWidth = 0.5 + static let SearchImageHeight: Float = 44 + static let SearchImageWidth: Float = 24 + + static let SuggestionBackgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.8) + static let SuggestionBorderColor = UIConstants.HighlightBlue + static let SuggestionBorderWidth: CGFloat = 1 + static let SuggestionCornerRadius: CGFloat = 4 + static let SuggestionInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) + static let SuggestionMargin: CGFloat = 8 + static let SuggestionCellVerticalPadding: CGFloat = 10 + static let SuggestionCellMaxRows = 2 + + static let IconSize: CGFloat = 23 + static let FaviconSize: CGFloat = 29 + static let IconBorderColor = UIColor(white: 0, alpha: 0.1) + static let IconBorderWidth: CGFloat = 0.5 +} + +protocol SearchViewControllerDelegate: class { + func searchViewController(_ searchViewController: SearchViewController, didSelectURL url: URL) + func searchViewController(_ searchViewController: SearchViewController, didLongPressSuggestion suggestion: String) + func presentSearchSettingsController() +} + +class SearchViewController: SiteTableViewController, KeyboardHelperDelegate, LoaderListener { + var searchDelegate: SearchViewControllerDelegate? + + fileprivate let isPrivate: Bool + fileprivate var suggestClient: SearchSuggestClient? + + // Views for displaying the bottom scrollable search engine list. searchEngineScrollView is the + // scrollable container; searchEngineScrollViewContent contains the actual set of search engine buttons. + fileprivate let searchEngineScrollView = ButtonScrollView() + fileprivate let searchEngineScrollViewContent = UIView() + + fileprivate lazy var bookmarkedBadge: UIImage = { + return UIImage(named: "bookmarked_passive")! + }() + + // Cell for the suggestion flow layout. Since heightForHeaderInSection is called *before* + // cellForRowAtIndexPath, we create the cell to find its height before it's added to the table. + fileprivate let suggestionCell = SuggestionCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) + + static var userAgent: String? + + init(isPrivate: Bool) { + self.isPrivate = isPrivate + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + view.backgroundColor = UIConstants.PanelBackgroundColor + let blur = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light)) + view.addSubview(blur) + + super.viewDidLoad() + + KeyboardHelper.defaultHelper.addDelegate(self) + + searchEngineScrollView.layer.backgroundColor = SearchViewControllerUX.SearchEngineScrollViewBackgroundColor + searchEngineScrollView.layer.shadowRadius = 0 + searchEngineScrollView.layer.shadowOpacity = 100 + searchEngineScrollView.layer.shadowOffset = CGSize(width: 0, height: -SearchViewControllerUX.SearchEngineTopBorderWidth) + searchEngineScrollView.layer.shadowColor = SearchViewControllerUX.SearchEngineScrollViewBorderColor + searchEngineScrollView.clipsToBounds = false + + searchEngineScrollView.decelerationRate = UIScrollViewDecelerationRateFast + view.addSubview(searchEngineScrollView) + + searchEngineScrollViewContent.layer.backgroundColor = UIColor.clear.cgColor + searchEngineScrollView.addSubview(searchEngineScrollViewContent) + + layoutTable() + layoutSearchEngineScrollView() + + searchEngineScrollViewContent.snp.makeConstraints { make in + make.center.equalTo(self.searchEngineScrollView).priority(10) + //left-align the engines on iphones, center on ipad + if UIScreen.main.traitCollection.horizontalSizeClass == .compact { + make.left.equalTo(self.searchEngineScrollView).priority(1000) + } else { + make.left.greaterThanOrEqualTo(self.searchEngineScrollView).priority(1000) + } + make.right.lessThanOrEqualTo(self.searchEngineScrollView).priority(1000) + make.top.equalTo(self.searchEngineScrollView) + make.bottom.equalTo(self.searchEngineScrollView) + } + + blur.snp.makeConstraints { make in + make.edges.equalTo(self.view) + } + + suggestionCell.delegate = self + + NotificationCenter.default.addObserver(self, selector: #selector(SearchViewController.SELDynamicFontChanged(_:)), name: NotificationDynamicFontChanged, object: nil) + } + + func SELDynamicFontChanged(_ notification: Notification) { + guard notification.name == NotificationDynamicFontChanged else { return } + + reloadData() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + reloadSearchEngines() + reloadData() + } + + fileprivate func layoutSearchEngineScrollView() { + let keyboardHeight = KeyboardHelper.defaultHelper.currentState?.intersectionHeightForView(self.view) ?? 0 + searchEngineScrollView.snp.remakeConstraints { make in + make.left.right.equalTo(self.view) + make.bottom.equalTo(self.view).offset(-keyboardHeight) + } + } + + var searchEngines: SearchEngines! { + didSet { + suggestClient?.cancelPendingRequest() + + // Query and reload the table with new search suggestions. + querySuggestClient() + + // Show the default search engine first. + if !isPrivate { + let ua = SearchViewController.userAgent as String! ?? "FxSearch" + suggestClient = SearchSuggestClient(searchEngine: searchEngines.defaultEngine, userAgent: ua) + } + + // Reload the footer list of search engines. + reloadSearchEngines() + } + } + + fileprivate var quickSearchEngines: [OpenSearchEngine] { + var engines = searchEngines.quickSearchEngines + + // If we're not showing search suggestions, the default search engine won't be visible + // at the top of the table. Show it with the others in the bottom search bar. + if isPrivate || !searchEngines.shouldShowSearchSuggestions { + engines?.insert(searchEngines.defaultEngine, at: 0) + } + + return engines! + } + + var searchQuery: String = "" { + didSet { + // Reload the tableView to show the updated text in each engine. + reloadData() + } + } + + override func reloadData() { + querySuggestClient() + } + + fileprivate func layoutTable() { + tableView.snp.remakeConstraints { make in + make.top.equalTo(self.view.snp.top) + make.leading.trailing.equalTo(self.view) + make.bottom.equalTo(self.searchEngineScrollView.snp.top) + } + } + + fileprivate func reloadSearchEngines() { + searchEngineScrollViewContent.subviews.forEach { $0.removeFromSuperview() } + var leftEdge = searchEngineScrollViewContent.snp.left + + //search settings icon + let searchButton = UIButton() + searchButton.setImage(UIImage(named: "quickSearch"), for: UIControlState()) + searchButton.imageView?.contentMode = UIViewContentMode.center + searchButton.layer.backgroundColor = SearchViewControllerUX.EngineButtonBackgroundColor + searchButton.addTarget(self, action: #selector(SearchViewController.SELdidClickSearchButton), for: UIControlEvents.touchUpInside) + searchButton.accessibilityLabel = String(format: NSLocalizedString("Search Settings", tableName: "Search", comment: "Label for search settings button.")) + + searchButton.imageView?.snp.makeConstraints { make in + make.width.height.equalTo(SearchViewControllerUX.SearchImageWidth) + return + } + + searchEngineScrollViewContent.addSubview(searchButton) + searchButton.snp.makeConstraints { make in + make.size.equalTo(SearchViewControllerUX.FaviconSize) + //offset the left edge to align with search results + make.left.equalTo(leftEdge).offset(SearchViewControllerUX.SuggestionMargin * 2) + make.top.equalTo(self.searchEngineScrollViewContent).offset(SearchViewControllerUX.SuggestionMargin) + make.bottom.equalTo(self.searchEngineScrollViewContent).offset(-SearchViewControllerUX.SuggestionMargin) + } + + //search engines + leftEdge = searchButton.snp.right + for engine in quickSearchEngines { + let engineButton = UIButton() + engineButton.setImage(engine.image, for: UIControlState()) + engineButton.imageView?.contentMode = UIViewContentMode.scaleAspectFit + engineButton.layer.backgroundColor = SearchViewControllerUX.EngineButtonBackgroundColor + engineButton.addTarget(self, action: #selector(SearchViewController.SELdidSelectEngine(_:)), for: UIControlEvents.touchUpInside) + engineButton.accessibilityLabel = String(format: NSLocalizedString("%@ search", tableName: "Search", comment: "Label for search engine buttons. The argument corresponds to the name of the search engine."), engine.shortName) + + engineButton.imageView?.snp.makeConstraints { make in + make.width.height.equalTo(SearchViewControllerUX.FaviconSize) + return + } + + searchEngineScrollViewContent.addSubview(engineButton) + engineButton.snp.makeConstraints { make in + make.width.equalTo(SearchViewControllerUX.EngineButtonWidth) + make.height.equalTo(SearchViewControllerUX.EngineButtonHeight) + make.left.equalTo(leftEdge) + make.top.equalTo(self.searchEngineScrollViewContent) + make.bottom.equalTo(self.searchEngineScrollViewContent) + if engine === self.searchEngines.quickSearchEngines.last { + make.right.equalTo(self.searchEngineScrollViewContent) + } + } + leftEdge = engineButton.snp.right + } + } + + func SELdidSelectEngine(_ sender: UIButton) { + // The UIButtons are the same cardinality and order as the array of quick search engines. + // Subtract 1 from index to account for magnifying glass accessory. + guard let index = searchEngineScrollViewContent.subviews.index(of: sender) else { + assertionFailure() + return + } + + let engine = quickSearchEngines[index - 1] + + guard let url = engine.searchURLForQuery(searchQuery) else { + assertionFailure() + return + } + + Telemetry.default.recordSearch(location: .quickSearch, searchEngine: engine.engineID ?? "other") + + searchDelegate?.searchViewController(self, didSelectURL: url) + } + + func SELdidClickSearchButton() { + self.searchDelegate?.presentSearchSettingsController() + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillShowWithState state: KeyboardState) { + animateSearchEnginesWithKeyboard(state) + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardDidShowWithState state: KeyboardState) { + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillHideWithState state: KeyboardState) { + animateSearchEnginesWithKeyboard(state) + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + // The height of the suggestions row may change, so call reloadData() to recalculate cell heights. + coordinator.animate(alongsideTransition: { _ in + self.tableView.reloadData() + }, completion: nil) + } + + fileprivate func animateSearchEnginesWithKeyboard(_ keyboardState: KeyboardState) { + layoutSearchEngineScrollView() + + UIView.animate(withDuration: keyboardState.animationDuration, animations: { + UIView.setAnimationCurve(keyboardState.animationCurve) + self.view.layoutIfNeeded() + }) + } + + fileprivate func querySuggestClient() { + suggestClient?.cancelPendingRequest() + + if searchQuery.isEmpty || !searchEngines.shouldShowSearchSuggestions || searchQuery.looksLikeAURL() { + suggestionCell.suggestions = [] + tableView.reloadData() + return + } + + suggestClient?.query(searchQuery, callback: { suggestions, error in + if let error = error { + let isSuggestClientError = error.domain == SearchSuggestClientErrorDomain + + switch error.code { + case NSURLErrorCancelled where error.domain == NSURLErrorDomain: + // Request was cancelled. Do nothing. + break + case SearchSuggestClientErrorInvalidEngine where isSuggestClientError: + // Engine does not support search suggestions. Do nothing. + break + case SearchSuggestClientErrorInvalidResponse where isSuggestClientError: + print("Error: Invalid search suggestion data") + default: + print("Error: \(error.description)") + } + } else { + self.suggestionCell.suggestions = suggestions! + } + + // If there are no suggestions, just use whatever the user typed. + if suggestions?.isEmpty ?? true { + self.suggestionCell.suggestions = [self.searchQuery] + } + + // Reload the tableView to show the new list of search suggestions. + self.tableView.reloadData() + }) + } + + func loader(dataLoaded data: Cursor) { + self.data = data + tableView.reloadData() + } + + func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) { + let section = SearchListSection(rawValue: indexPath.section)! + if section == SearchListSection.bookmarksAndHistory { + if let site = data[indexPath.row] { + if let url = URL(string: site.url) { + searchDelegate?.searchViewController(self, didSelectURL: url) + UnifiedTelemetry.recordEvent(category: .action, method: .open, object: .bookmark, value: .awesomebarResults) + } + } + } + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + if let currentSection = SearchListSection(rawValue: indexPath.section) { + switch currentSection { + case .searchSuggestions: + // heightForRowAtIndexPath is called *before* the cell is created, so to get the height, + // force a layout pass first. + suggestionCell.layoutIfNeeded() + return suggestionCell.frame.height + default: + return super.tableView(tableView, heightForRowAt: indexPath) + } + } + + return 0 + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 0 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + switch SearchListSection(rawValue: indexPath.section)! { + case .searchSuggestions: + suggestionCell.imageView?.image = searchEngines.defaultEngine.image + suggestionCell.imageView?.isAccessibilityElement = true + suggestionCell.imageView?.accessibilityLabel = String(format: NSLocalizedString("Search suggestions from %@", tableName: "Search", comment: "Accessibility label for image of default search engine displayed left to the actual search suggestions from the engine. The parameter substituted for \"%@\" is the name of the search engine. E.g.: Search suggestions from Google"), searchEngines.defaultEngine.shortName) + return suggestionCell + + case .bookmarksAndHistory: + let cell = super.tableView(tableView, cellForRowAt: indexPath) + if let site = data[indexPath.row] { + if let cell = cell as? TwoLineTableViewCell { + let isBookmark = site.bookmarked ?? false + cell.setLines(site.title, detailText: site.url) + cell.setRightBadge(isBookmark ? self.bookmarkedBadge : nil) + cell.imageView!.layer.borderColor = SearchViewControllerUX.IconBorderColor.cgColor + cell.imageView!.layer.borderWidth = SearchViewControllerUX.IconBorderWidth + cell.imageView?.setIcon(site.icon, forURL: site.tileURL, completed: { (color, url) in + if site.tileURL == url { + cell.imageView?.image = cell.imageView?.image?.createScaled(CGSize(width: SearchViewControllerUX.IconSize, height: SearchViewControllerUX.IconSize)) + cell.imageView?.contentMode = .center + cell.imageView?.backgroundColor = color + } + }) + } + } + return cell + } + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + switch SearchListSection(rawValue: section)! { + case .searchSuggestions: + return searchEngines.shouldShowSearchSuggestions && !searchQuery.looksLikeAURL() && !isPrivate ? 1 : 0 + case .bookmarksAndHistory: + return data.count + } + } + + func numberOfSectionsInTableView(_ tableView: UITableView) -> Int { + return SearchListSection.Count + } +} + +extension SearchViewController: SuggestionCellDelegate { + fileprivate func suggestionCell(_ suggestionCell: SuggestionCell, didSelectSuggestion suggestion: String) { + // Assume that only the default search engine can provide search suggestions. + let engine = searchEngines.defaultEngine + + var url = URIFixup.getURL(suggestion) + if url == nil { + url = engine.searchURLForQuery(suggestion) + } + + Telemetry.default.recordSearch(location: .suggestion, searchEngine: engine.engineID ?? "other") + + if let url = url { + searchDelegate?.searchViewController(self, didSelectURL: url) + } + } + + fileprivate func suggestionCell(_ suggestionCell: SuggestionCell, didLongPressSuggestion suggestion: String) { + searchDelegate?.searchViewController(self, didLongPressSuggestion: suggestion) + } +} + +/** + * Private extension containing string operations specific to this view controller + */ +fileprivate extension String { + func looksLikeAURL() -> Bool { + // The assumption here is that if the user is typing in a forward slash and there are no spaces + // involved, it's going to be a URL. If we type a space, any url would be invalid. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=1192155 for additional details. + return self.contains("/") && !self.contains(" ") + } +} + +/** + * UIScrollView that prevents buttons from interfering with scroll. + */ +fileprivate class ButtonScrollView: UIScrollView { + fileprivate override func touchesShouldCancel(in view: UIView) -> Bool { + return true + } +} + +fileprivate protocol SuggestionCellDelegate: class { + func suggestionCell(_ suggestionCell: SuggestionCell, didSelectSuggestion suggestion: String) + func suggestionCell(_ suggestionCell: SuggestionCell, didLongPressSuggestion suggestion: String) +} + +/** + * Cell that wraps a list of search suggestion buttons. + */ +fileprivate class SuggestionCell: UITableViewCell { + weak var delegate: SuggestionCellDelegate? + let container = UIView() + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + isAccessibilityElement = false + accessibilityLabel = nil + layoutMargins = UIEdgeInsets.zero + separatorInset = UIEdgeInsets.zero + selectionStyle = UITableViewCellSelectionStyle.none + + container.backgroundColor = UIColor.clear + contentView.backgroundColor = UIColor.clear + backgroundColor = UIColor.clear + contentView.addSubview(container) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var suggestions: [String] = [] { + didSet { + for view in container.subviews { + view.removeFromSuperview() + } + + for suggestion in suggestions { + let button = SuggestionButton() + button.setTitle(suggestion, for: UIControlState()) + button.addTarget(self, action: #selector(SuggestionCell.SELdidSelectSuggestion(_:)), for: UIControlEvents.touchUpInside) + button.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(SuggestionCell.SELdidLongPressSuggestion(_:)))) + + // If this is the first image, add the search icon. + if container.subviews.isEmpty { + let image = UIImage(named: SearchViewControllerUX.SearchImage) + button.setImage(image, for: UIControlState()) + button.titleEdgeInsets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0) + } + + container.addSubview(button) + } + + setNeedsLayout() + } + } + + @objc + func SELdidSelectSuggestion(_ sender: UIButton) { + delegate?.suggestionCell(self, didSelectSuggestion: sender.titleLabel!.text!) + } + + @objc + func SELdidLongPressSuggestion(_ recognizer: UILongPressGestureRecognizer) { + if recognizer.state == UIGestureRecognizerState.began { + if let button = recognizer.view as! UIButton? { + delegate?.suggestionCell(self, didLongPressSuggestion: button.titleLabel!.text!) + } + } + } + + fileprivate override func layoutSubviews() { + super.layoutSubviews() + + // The left bounds of the suggestions, aligned with where text would be displayed. + let textLeft: CGFloat = 61 + + // The maximum width of the container, after which suggestions will wrap to the next line. + let maxWidth = contentView.frame.width + + let imageSize = CGFloat(SearchViewControllerUX.FaviconSize) + + // The height of the suggestions container (minus margins), used to determine the frame. + // We set it to imageSize.height as a minimum since we don't want the cell to be shorter than the icon + var height: CGFloat = imageSize + + var currentLeft = textLeft + var currentTop = SearchViewControllerUX.SuggestionCellVerticalPadding + var currentRow = 0 + + for view in container.subviews { + let button = view as! UIButton + var buttonSize = button.intrinsicContentSize + + // Update our base frame height by the max size of either the image or the button so we never + // make the cell smaller than any of the two + if height == imageSize { + height = max(buttonSize.height, imageSize) + } + + var width = currentLeft + buttonSize.width + SearchViewControllerUX.SuggestionMargin + if width > maxWidth { + // Only move to the next row if there's already a suggestion on this row. + // Otherwise, the suggestion is too big to fit and will be resized below. + if currentLeft > textLeft { + currentRow += 1 + if currentRow >= SearchViewControllerUX.SuggestionCellMaxRows { + // Don't draw this button if it doesn't fit on the row. + button.frame = CGRect.zero + continue + } + + currentLeft = textLeft + currentTop += buttonSize.height + SearchViewControllerUX.SuggestionMargin + height += buttonSize.height + SearchViewControllerUX.SuggestionMargin + width = currentLeft + buttonSize.width + SearchViewControllerUX.SuggestionMargin + } + + // If the suggestion is too wide to fit on its own row, shrink it. + if width > maxWidth { + buttonSize.width = maxWidth - currentLeft - SearchViewControllerUX.SuggestionMargin + } + } + + button.frame = CGRect(x: currentLeft, y: currentTop, width: buttonSize.width, height: buttonSize.height) + currentLeft += buttonSize.width + SearchViewControllerUX.SuggestionMargin + } + + frame.size.height = height + 2 * SearchViewControllerUX.SuggestionCellVerticalPadding + contentView.frame = bounds + container.frame = bounds + + let imageX = (textLeft - imageSize) / 2 + let imageY = (frame.size.height - imageSize) / 2 + imageView!.frame = CGRect(x: imageX, y: imageY, width: imageSize, height: imageSize) + } +} + +/** + * Rounded search suggestion button that highlights when selected. + */ +fileprivate class SuggestionButton: InsetButton { + override init(frame: CGRect) { + super.init(frame: frame) + + setTitleColor(UIConstants.HighlightBlue, for: UIControlState()) + setTitleColor(UIColor.white, for: UIControlState.highlighted) + titleLabel?.font = DynamicFontHelper.defaultHelper.DefaultMediumFont + backgroundColor = SearchViewControllerUX.SuggestionBackgroundColor + layer.borderColor = SearchViewControllerUX.SuggestionBorderColor.cgColor + layer.borderWidth = SearchViewControllerUX.SuggestionBorderWidth + layer.cornerRadius = SearchViewControllerUX.SuggestionCornerRadius + contentEdgeInsets = SearchViewControllerUX.SuggestionInsets + + accessibilityHint = NSLocalizedString("Searches for the suggestion", comment: "Accessibility hint describing the action performed when a search suggestion is clicked") + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc + override var isHighlighted: Bool { + didSet { + backgroundColor = isHighlighted ? UIConstants.HighlightBlue : SearchViewControllerUX.SuggestionBackgroundColor + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SessionData.swift b/mobile/ios/Client/Frontend/Browser/SessionData.swift new file mode 100644 index 0000000000..b2919e76b6 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SessionData.swift @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation + +import Shared + +class SessionData: NSObject, NSCoding { + let currentPage: Int + let urls: [URL] + let lastUsedTime: Timestamp + + var jsonDictionary: [String: Any] { + return [ + "currentPage": String(self.currentPage), + "lastUsedTime": String(self.lastUsedTime), + "urls": urls.map { $0.absoluteString } + ] + } + + /** + Creates a new SessionData object representing a serialized tab. + + - parameter currentPage: The active page index. Must be in the range of (-N, 0], + where 1-N is the first page in history, and 0 is the last. + - parameter urls: The sequence of URLs in this tab's session history. + - parameter lastUsedTime: The last time this tab was modified. + **/ + init(currentPage: Int, urls: [URL], lastUsedTime: Timestamp) { + self.currentPage = currentPage + self.urls = urls + self.lastUsedTime = lastUsedTime + + assert(urls.count > 0, "Session has at least one entry") + assert(currentPage > -urls.count && currentPage <= 0, "Session index is valid") + } + + required init?(coder: NSCoder) { + self.currentPage = coder.decodeAsInt(forKey: "currentPage") + self.urls = coder.decodeObject(forKey: "urls") as? [URL] ?? [] + self.lastUsedTime = coder.decodeAsUInt64(forKey: "lastUsedTime") + } + + func encode(with coder: NSCoder) { + coder.encode(currentPage, forKey: "currentPage") + coder.encode(urls, forKey: "urls") + coder.encode(Int64(lastUsedTime), forKey: "lastUsedTime") + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SessionRestoreHandler.swift b/mobile/ios/Client/Frontend/Browser/SessionRestoreHandler.swift new file mode 100644 index 0000000000..554ced8447 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SessionRestoreHandler.swift @@ -0,0 +1,30 @@ +/* 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/. */ + +import Foundation +import WebKit +import GCDWebServers +import Shared + +/// Handles requests to /about/sessionrestore to restore session history. +struct SessionRestoreHandler { + static func register(_ webServer: WebServer) { + // Register the handler that accepts /about/sessionrestore?history=...¤tpage=... requests. + webServer.registerHandlerForMethod("GET", module: "about", resource: "sessionrestore") { _ in + if let sessionRestorePath = Bundle.main.path(forResource: "SessionRestore", ofType: "html") { + do { + let sessionRestoreString = try String(contentsOfFile: sessionRestorePath) + + defer { + NotificationCenter.default.post(name: NotificationDidRestoreSession, object: self) + } + + return GCDWebServerDataResponse(html: sessionRestoreString) + } catch _ {} + } + + return GCDWebServerResponse(statusCode: 404) + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SessionRestoreHelper.swift b/mobile/ios/Client/Frontend/Browser/SessionRestoreHelper.swift new file mode 100644 index 0000000000..de8b6213ce --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SessionRestoreHelper.swift @@ -0,0 +1,37 @@ +/* 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/. */ + +import Foundation +import WebKit + +protocol SessionRestoreHelperDelegate: class { + func sessionRestoreHelper(_ helper: SessionRestoreHelper, didRestoreSessionForTab tab: Tab) +} + +class SessionRestoreHelper: TabContentScript { + weak var delegate: SessionRestoreHelperDelegate? + fileprivate weak var tab: Tab? + + required init(tab: Tab) { + self.tab = tab + } + + func scriptMessageHandlerName() -> String? { + return "sessionRestoreHelper" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + if let tab = tab, let params = message.body as? [String: AnyObject] { + if params["name"] as! String == "didRestoreSession" { + DispatchQueue.main.async { + self.delegate?.sessionRestoreHelper(self, didRestoreSessionForTab: tab) + } + } + } + } + + class func name() -> String { + return "SessionRestoreHelper" + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SimpleToast.swift b/mobile/ios/Client/Frontend/Browser/SimpleToast.swift new file mode 100644 index 0000000000..cec47002dc --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SimpleToast.swift @@ -0,0 +1,73 @@ +/* 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/. */ + +import Foundation +import Shared + +struct SimpleToastUX { + static let ToastHeight = BottomToolbarHeight + static let ToastAnimationDuration = 0.5 + static let ToastDefaultColor = UIColor(red: 10 / 255, green: 132 / 255, blue: 255.0 / 255, alpha: 1) + static let ToastFont = UIFont.systemFont(ofSize: 15) + static let ToastDismissAfter = DispatchTimeInterval.milliseconds(4500) // 4.5 seconds. + static let ToastDelayBefore = DispatchTimeInterval.milliseconds(0) // 0 seconds + static let BottomToolbarHeight = CGFloat(45) +} + +struct SimpleToast { + + func showAlertWithText(_ text: String, bottomContainer: UIView) { + let toast = self.createView() + toast.text = text + bottomContainer.addSubview(toast) + toast.snp.makeConstraints { (make) in + make.width.equalTo(bottomContainer) + make.left.equalTo(bottomContainer) + make.height.equalTo(SimpleToastUX.ToastHeight) + make.bottom.equalTo(bottomContainer) + } + animate(toast) + } + + fileprivate func createView() -> UILabel { + let toast = UILabel() + toast.textColor = UIColor.white + toast.backgroundColor = SimpleToastUX.ToastDefaultColor + toast.font = SimpleToastUX.ToastFont + toast.textAlignment = .center + return toast + } + + fileprivate func dismiss(_ toast: UIView) { + UIView.animate(withDuration: SimpleToastUX.ToastAnimationDuration, + animations: { + var frame = toast.frame + frame.origin.y = frame.origin.y + SimpleToastUX.ToastHeight + frame.size.height = 0 + toast.frame = frame + }, + completion: { finished in + toast.removeFromSuperview() + } + ) + } + + fileprivate func animate(_ toast: UIView) { + UIView.animate(withDuration: SimpleToastUX.ToastAnimationDuration, + animations: { + var frame = toast.frame + frame.origin.y = frame.origin.y - SimpleToastUX.ToastHeight + frame.size.height = SimpleToastUX.ToastHeight + toast.frame = frame + }, + completion: { finished in + let dispatchTime = DispatchTime.now() + SimpleToastUX.ToastDismissAfter + + DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: { + self.dismiss(toast) + }) + } + ) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/SwipeAnimator.swift b/mobile/ios/Client/Frontend/Browser/SwipeAnimator.swift new file mode 100644 index 0000000000..fec61058ea --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/SwipeAnimator.swift @@ -0,0 +1,156 @@ +/* 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/. */ + +import Foundation + +struct SwipeAnimationParameters { + let totalRotationInDegrees: Double + let deleteThreshold: CGFloat + let totalScale: CGFloat + let totalAlpha: CGFloat + let minExitVelocity: CGFloat + let recenterAnimationDuration: TimeInterval +} + +private let DefaultParameters = + SwipeAnimationParameters( + totalRotationInDegrees: 10, + deleteThreshold: 80, + totalScale: 0.9, + totalAlpha: 0, + minExitVelocity: 800, + recenterAnimationDuration: 0.15) + +protocol SwipeAnimatorDelegate: class { + func swipeAnimator(_ animator: SwipeAnimator, viewWillExitContainerBounds: UIView) +} + +class SwipeAnimator: NSObject { + weak var delegate: SwipeAnimatorDelegate? + weak var animatingView: UIView? + + fileprivate var prevOffset: CGPoint? + fileprivate let params: SwipeAnimationParameters + + fileprivate var panGestureRecogniser: UIPanGestureRecognizer! + + var containerCenter: CGPoint { + guard let animatingView = self.animatingView else { + return CGPoint.zero + } + return CGPoint(x: animatingView.frame.width / 2, y: animatingView.frame.height / 2) + } + + init(animatingView: UIView, params: SwipeAnimationParameters = DefaultParameters) { + self.animatingView = animatingView + self.params = params + + super.init() + + self.panGestureRecogniser = UIPanGestureRecognizer(target: self, action: #selector(SwipeAnimator.didPan(_:))) + animatingView.addGestureRecognizer(self.panGestureRecogniser) + self.panGestureRecogniser.delegate = self + } + + func cancelExistingGestures() { + self.panGestureRecogniser.isEnabled = false + self.panGestureRecogniser.isEnabled = true + } +} + +//MARK: Private Helpers +extension SwipeAnimator { + fileprivate func animateBackToCenter() { + UIView.animate(withDuration: params.recenterAnimationDuration, animations: { + self.animatingView?.transform = CGAffineTransform.identity + self.animatingView?.alpha = 1 + }) + } + + fileprivate func animateAwayWithVelocity(_ velocity: CGPoint, speed: CGFloat) { + guard let animatingView = self.animatingView else { + return + } + + // Calculate the edge to calculate distance from + let translation = velocity.x >= 0 ? animatingView.frame.width : -animatingView.frame.width + let timeStep = TimeInterval(abs(translation) / speed) + self.delegate?.swipeAnimator(self, viewWillExitContainerBounds: animatingView) + UIView.animate(withDuration: timeStep, animations: { + animatingView.transform = self.transformForTranslation(translation) + animatingView.alpha = self.alphaForDistanceFromCenter(abs(translation)) + }, completion: { finished in + if finished { + animatingView.alpha = 0 + } + }) + } + + fileprivate func transformForTranslation(_ translation: CGFloat) -> CGAffineTransform { + let swipeWidth = animatingView?.frame.size.width ?? 1 + let totalRotationInRadians = CGFloat(params.totalRotationInDegrees / 180.0 * Double.pi) + + // Determine rotation / scaling amounts by the distance to the edge + let rotation = (translation / swipeWidth) * totalRotationInRadians + let scale = 1 - (abs(translation) / swipeWidth) * (1 - params.totalScale) + + let rotationTransform = CGAffineTransform(rotationAngle: rotation) + let scaleTransform = CGAffineTransform(scaleX: scale, y: scale) + let translateTransform = CGAffineTransform(translationX: translation, y: 0) + return rotationTransform.concatenating(scaleTransform).concatenating(translateTransform) + } + + fileprivate func alphaForDistanceFromCenter(_ distance: CGFloat) -> CGFloat { + let swipeWidth = animatingView?.frame.size.width ?? 1 + return 1 - (distance / swipeWidth) * (1 - params.totalAlpha) + } +} + +//MARK: Selectors +extension SwipeAnimator { + @objc func didPan(_ recognizer: UIPanGestureRecognizer!) { + let translation = recognizer.translation(in: animatingView) + + switch recognizer.state { + case .began: + prevOffset = containerCenter + case .changed: + animatingView?.transform = transformForTranslation(translation.x) + animatingView?.alpha = alphaForDistanceFromCenter(abs(translation.x)) + prevOffset = CGPoint(x: translation.x, y: 0) + case .cancelled: + animateBackToCenter() + case .ended: + let velocity = recognizer.velocity(in: animatingView) + // Bounce back if the velocity is too low or if we have not reached the threshold yet + let speed = max(abs(velocity.x), params.minExitVelocity) + if speed < params.minExitVelocity || abs(prevOffset?.x ?? 0) < params.deleteThreshold { + animateBackToCenter() + } else { + animateAwayWithVelocity(velocity, speed: speed) + } + default: + break + } + } + + func close(right: Bool) { + let direction = CGFloat(right ? -1 : 1) + animateAwayWithVelocity(CGPoint(x: -direction * params.minExitVelocity, y: 0), speed: direction * params.minExitVelocity) + } + + @discardableResult @objc func closeWithoutGesture() -> Bool { + close(right: false) + return true + } +} + +extension SwipeAnimator: UIGestureRecognizerDelegate { + @objc func gestureRecognizerShouldBegin(_ recognizer: UIGestureRecognizer) -> Bool { + let cellView = recognizer.view as UIView! + let panGesture = recognizer as! UIPanGestureRecognizer + let translation = panGesture.translation(in: cellView?.superview) + return fabs(translation.x) > fabs(translation.y) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/Tab.swift b/mobile/ios/Client/Frontend/Browser/Tab.swift new file mode 100644 index 0000000000..1ddf5616cf --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/Tab.swift @@ -0,0 +1,598 @@ +/* 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/. */ + +import Foundation +import WebKit +import Storage +import Shared +import SwiftyJSON +import XCGLogger + +protocol TabContentScript { + static func name() -> String + func scriptMessageHandlerName() -> String? + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) +} + +@objc +protocol TabDelegate { + func tab(_ tab: Tab, didAddSnackbar bar: SnackBar) + func tab(_ tab: Tab, didRemoveSnackbar bar: SnackBar) + func tab(_ tab: Tab, didSelectFindInPageForSelection selection: String) + @objc optional func tab(_ tab: Tab, didCreateWebView webView: WKWebView) + @objc optional func tab(_ tab: Tab, willDeleteWebView webView: WKWebView) +} + +@objc +protocol URLChangeDelegate { + func tab(_ tab: Tab, urlDidChangeTo url: URL) +} + +struct TabState { + var isPrivate: Bool = false + var desktopSite: Bool = false + var isBookmarked: Bool = false + var url: URL? + var title: String? + var favicon: Favicon? +} + +class Tab: NSObject { + fileprivate var _isPrivate: Bool = false + internal fileprivate(set) var isPrivate: Bool { + get { + return _isPrivate + } + set { + if _isPrivate != newValue { + _isPrivate = newValue + } + } + } + + var tabState: TabState { + return TabState(isPrivate: _isPrivate, desktopSite: desktopSite, isBookmarked: isBookmarked, url: url, title: displayTitle, favicon: displayFavicon) + } + + // PageMetadata is derived from the page content itself, and as such lags behind the + // rest of the tab. + var pageMetadata: PageMetadata? + + var canonicalURL: URL? { + if let string = pageMetadata?.siteURL, + let siteURL = URL(string: string) { + return siteURL + } + return self.url + } + + var userActivity: NSUserActivity? = nil + + var webView: WKWebView? + var tabDelegate: TabDelegate? + weak var urlDidChangeDelegate: URLChangeDelegate? // TODO: generalize this. + var bars = [SnackBar]() + var favicons = [Favicon]() + var lastExecutedTime: Timestamp? + var sessionData: SessionData? + fileprivate var lastRequest: URLRequest? + var restoring: Bool = false + var pendingScreenshot = false + var url: URL? + var mimeType: String? + + fileprivate var _noImageMode = false + + /// Returns true if this tab's URL is known, and it's longer than we want to store. + var urlIsTooLong: Bool { + guard let url = self.url else { + return false + } + return url.absoluteString.lengthOfBytes(using: String.Encoding.utf8) > AppConstants.DB_URL_LENGTH_MAX + } + + // Use computed property so @available can be used to guard `noImageMode`. + @available(iOS 11, *) + var noImageMode: Bool { + get { return _noImageMode } + set { + if newValue == _noImageMode { + return + } + _noImageMode = newValue + let helper = (contentBlocker as? ContentBlockerHelper) + helper?.noImageMode(enabled: _noImageMode) + } + } + + // There is no 'available macro' on props, we currently just need to store ownership. + var contentBlocker: AnyObject? + + /// The last title shown by this tab. Used by the tab tray to show titles for zombie tabs. + var lastTitle: String? + + /// Whether or not the desktop site was requested with the last request, reload or navigation. Note that this property needs to + /// be managed by the web view's navigation delegate. + var desktopSite: Bool = false + var isBookmarked: Bool = false + + var readerModeAvailableOrActive: Bool { + if let readerMode = self.getContentScript(name: "ReaderMode") as? ReaderMode { + return readerMode.state != .unavailable + } + return false + } + + fileprivate(set) var screenshot: UIImage? + var screenshotUUID: UUID? + + // If this tab has been opened from another, its parent will point to the tab from which it was opened + var parent: Tab? + + fileprivate var contentScriptManager = TabContentScriptManager() + + fileprivate var configuration: WKWebViewConfiguration? + + /// Any time a tab tries to make requests to display a Javascript Alert and we are not the active + /// tab instance, queue it for later until we become foregrounded. + fileprivate var alertQueue = [JSAlertInfo]() + + init(configuration: WKWebViewConfiguration, isPrivate: Bool = false) { + self.configuration = configuration + super.init() + self.isPrivate = isPrivate + + if #available(iOS 11, *) { + if let appDelegate = UIApplication.shared.delegate as? AppDelegate, let profile = appDelegate.profile { + contentBlocker = ContentBlockerHelper(tab: self, profile: profile) + } + } + } + + class func toTab(_ tab: Tab) -> RemoteTab? { + if let displayURL = tab.url?.displayURL, RemoteTab.shouldIncludeURL(displayURL) { + let history = Array(tab.historyList.filter(RemoteTab.shouldIncludeURL).reversed()) + return RemoteTab(clientGUID: nil, + URL: displayURL, + title: tab.displayTitle, + history: history, + lastUsed: Date.now(), + icon: nil) + } else if let sessionData = tab.sessionData, !sessionData.urls.isEmpty { + let history = Array(sessionData.urls.filter(RemoteTab.shouldIncludeURL).reversed()) + if let displayURL = history.first { + return RemoteTab(clientGUID: nil, + URL: displayURL, + title: tab.displayTitle, + history: history, + lastUsed: sessionData.lastUsedTime, + icon: nil) + } + } + + return nil + } + + weak var navigationDelegate: WKNavigationDelegate? { + didSet { + if let webView = webView { + webView.navigationDelegate = navigationDelegate + } + } + } + + func createWebview() { + if webView == nil { + assert(configuration != nil, "Create webview can only be called once") + configuration!.userContentController = WKUserContentController() + configuration!.preferences = WKPreferences() + configuration!.preferences.javaScriptCanOpenWindowsAutomatically = false + configuration!.allowsInlineMediaPlayback = true + let webView = TabWebView(frame: CGRect.zero, configuration: configuration!) + webView.delegate = self + configuration = nil + + webView.accessibilityLabel = NSLocalizedString("Web content", comment: "Accessibility label for the main web content view") + webView.allowsBackForwardNavigationGestures = true + webView.allowsLinkPreview = false + + // Night mode enables this by toggling WKWebView.isOpaque, otherwise this has no effect. + webView.backgroundColor = .black + + // Turning off masking allows the web content to flow outside of the scrollView's frame + // which allows the content appear beneath the toolbars in the BrowserViewController + webView.scrollView.layer.masksToBounds = false + webView.navigationDelegate = navigationDelegate + + restore(webView) + + self.webView = webView + self.webView?.addObserver(self, forKeyPath: KVOConstants.URL.rawValue, options: .new, context: nil) + tabDelegate?.tab?(self, didCreateWebView: webView) + } + } + + func restore(_ webView: WKWebView) { + // Pulls restored session data from a previous SavedTab to load into the Tab. If it's nil, a session restore + // has already been triggered via custom URL, so we use the last request to trigger it again; otherwise, + // we extract the information needed to restore the tabs and create a NSURLRequest with the custom session restore URL + // to trigger the session restore via custom handlers + if let sessionData = self.sessionData { + restoring = true + + var urls = [String]() + for url in sessionData.urls { + urls.append(url.absoluteString) + } + + let currentPage = sessionData.currentPage + self.sessionData = nil + var jsonDict = [String: AnyObject]() + jsonDict["history"] = urls as AnyObject? + jsonDict["currentPage"] = currentPage as AnyObject? + guard let json = JSON(jsonDict).stringValue() else { + return + } + let escapedJSON = json.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! + let restoreURL = URL(string: "\(WebServer.sharedInstance.base)/about/sessionrestore?history=\(escapedJSON)") + lastRequest = PrivilegedRequest(url: restoreURL!) as URLRequest + webView.load(lastRequest!) + } else if let request = lastRequest { + webView.load(request) + } else { + print("creating webview with no lastRequest and no session data: \(self.url?.description ?? "nil")") + } + } + + deinit { + if let webView = webView { + webView.removeObserver(self, forKeyPath: KVOConstants.URL.rawValue) + tabDelegate?.tab?(self, willDeleteWebView: webView) + } + } + + var loading: Bool { + return webView?.isLoading ?? false + } + + var estimatedProgress: Double { + return webView?.estimatedProgress ?? 0 + } + + var backList: [WKBackForwardListItem]? { + return webView?.backForwardList.backList + } + + var forwardList: [WKBackForwardListItem]? { + return webView?.backForwardList.forwardList + } + + var historyList: [URL] { + func listToUrl(_ item: WKBackForwardListItem) -> URL { return item.url } + var tabs = self.backList?.map(listToUrl) ?? [URL]() + tabs.append(self.url!) + return tabs + } + + var title: String? { + return webView?.title + } + + var displayTitle: String { + if let title = webView?.title { + if !title.isEmpty { + return title + } + } + + // When picking a display title. Tabs with sessionData are pending a restore so show their old title. + // To prevent flickering of the display title. If a tab is restoring make sure to use its lastTitle. + if let url = self.url, url.isAboutHomeURL, sessionData == nil, !restoring { + return "" + } + + guard let lastTitle = lastTitle, !lastTitle.isEmpty else { + return self.url?.displayURL?.absoluteString ?? "" + } + + return lastTitle + } + + var currentInitialURL: URL? { + get { + let initalURL = self.webView?.backForwardList.currentItem?.initialURL + return initalURL + } + } + + var displayFavicon: Favicon? { + var width = 0 + var largest: Favicon? + for icon in favicons where icon.width! > width { + width = icon.width! + largest = icon + } + return largest + } + + var canGoBack: Bool { + return webView?.canGoBack ?? false + } + + var canGoForward: Bool { + return webView?.canGoForward ?? false + } + + func goBack() { + _ = webView?.goBack() + } + + func goForward() { + _ = webView?.goForward() + } + + func goToBackForwardListItem(_ item: WKBackForwardListItem) { + _ = webView?.go(to: item) + } + + @discardableResult func loadRequest(_ request: URLRequest) -> WKNavigation? { + if let webView = webView { + lastRequest = request + return webView.load(request) + } + return nil + } + + func stop() { + webView?.stopLoading() + } + + func reload() { + let userAgent: String? = desktopSite ? UserAgent.desktopUserAgent() : nil + if (userAgent ?? "") != webView?.customUserAgent, + let currentItem = webView?.backForwardList.currentItem { + webView?.customUserAgent = userAgent + + // Reload the initial URL to avoid UA specific redirection + loadRequest(PrivilegedRequest(url: currentItem.initialURL, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60) as URLRequest) + return + } + + if let _ = webView?.reloadFromOrigin() { + print("reloaded zombified tab from origin") + return + } + + if let webView = self.webView { + print("restoring webView from scratch") + restore(webView) + } + } + + func addContentScript(_ helper: TabContentScript, name: String) { + contentScriptManager.addContentScript(helper, name: name, forTab: self) + } + + func getContentScript(name: String) -> TabContentScript? { + return contentScriptManager.getContentScript(name) + } + + func hideContent(_ animated: Bool = false) { + webView?.isUserInteractionEnabled = false + if animated { + UIView.animate(withDuration: 0.25, animations: { () -> Void in + self.webView?.alpha = 0.0 + }) + } else { + webView?.alpha = 0.0 + } + } + + func showContent(_ animated: Bool = false) { + webView?.isUserInteractionEnabled = true + if animated { + UIView.animate(withDuration: 0.25, animations: { () -> Void in + self.webView?.alpha = 1.0 + }) + } else { + webView?.alpha = 1.0 + } + } + + func addSnackbar(_ bar: SnackBar) { + bars.append(bar) + tabDelegate?.tab(self, didAddSnackbar: bar) + } + + func removeSnackbar(_ bar: SnackBar) { + if let index = bars.index(of: bar) { + bars.remove(at: index) + tabDelegate?.tab(self, didRemoveSnackbar: bar) + } + } + + func removeAllSnackbars() { + // Enumerate backwards here because we'll remove items from the list as we go. + for i in (0.. JSAlertInfo? { + guard !alertQueue.isEmpty else { + return nil + } + return alertQueue.removeFirst() + } + + func cancelQueuedAlerts() { + alertQueue.forEach { alert in + alert.cancel() + } + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { + guard let webView = object as? WKWebView, webView == self.webView, + let path = keyPath, path == KVOConstants.URL.rawValue else { + return assertionFailure("Unhandled KVO key: \(keyPath ?? "nil")") + } + guard let url = self.webView?.url else { + return + } + + self.urlDidChangeDelegate?.tab(self, urlDidChangeTo: url) + TabEvent.post(.didChangeURL(url), for: self) + } + + func isDescendentOf(_ ancestor: Tab) -> Bool { + var tab = parent + while tab != nil { + if tab! == ancestor { + return true + } + tab = tab?.parent + } + return false + } + + func setNightMode(_ enabled: Bool) { + webView?.evaluateJavaScript("window.__firefox__.NightMode.setEnabled(\(enabled))", completionHandler: nil) + // For WKWebView background color to take effect, isOpaque must be false, which is counter-intuitive. Default is true. + // The color is previously set to black in the webview init + webView?.isOpaque = !enabled + } + + func injectUserScriptWith(fileName: String, type: String = "js", injectionTime: WKUserScriptInjectionTime = .atDocumentEnd, mainFrameOnly: Bool = true) { + guard let webView = self.webView else { + return + } + if let path = Bundle.main.path(forResource: fileName, ofType: type), + let source = try? String(contentsOfFile: path) { + let userScript = WKUserScript(source: source, injectionTime: injectionTime, forMainFrameOnly: mainFrameOnly) + webView.configuration.userContentController.addUserScript(userScript) + } + } + + func observeURLChanges(delegate: URLChangeDelegate) { + self.urlDidChangeDelegate = delegate + } + + func removeURLChangeObserver(delegate: URLChangeDelegate) { + if let existing = self.urlDidChangeDelegate, existing === delegate { + self.urlDidChangeDelegate = nil + } + } +} + +extension Tab: TabWebViewDelegate { + fileprivate func tabWebView(_ tabWebView: TabWebView, didSelectFindInPageForSelection selection: String) { + tabDelegate?.tab(self, didSelectFindInPageForSelection: selection) + } +} + +private class TabContentScriptManager: NSObject, WKScriptMessageHandler { + fileprivate var helpers = [String: TabContentScript]() + + @objc func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + for helper in helpers.values { + if let scriptMessageHandlerName = helper.scriptMessageHandlerName() { + if scriptMessageHandlerName == message.name { + helper.userContentController(userContentController, didReceiveScriptMessage: message) + return + } + } + } + } + + func addContentScript(_ helper: TabContentScript, name: String, forTab tab: Tab) { + if let _ = helpers[name] { + assertionFailure("Duplicate helper added: \(name)") + } + + helpers[name] = helper + + // If this helper handles script messages, then get the handler name and register it. The Browser + // receives all messages and then dispatches them to the right TabHelper. + if let scriptMessageHandlerName = helper.scriptMessageHandlerName() { + tab.webView?.configuration.userContentController.add(self, name: scriptMessageHandlerName) + } + } + + func getContentScript(_ name: String) -> TabContentScript? { + return helpers[name] + } +} + +private protocol TabWebViewDelegate: class { + func tabWebView(_ tabWebView: TabWebView, didSelectFindInPageForSelection selection: String) +} + +private class TabWebView: WKWebView, MenuHelperInterface { + fileprivate weak var delegate: TabWebViewDelegate? + + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + return super.canPerformAction(action, withSender: sender) || action == MenuHelper.SelectorFindInPage + } + + @objc func menuHelperFindInPage() { + evaluateJavaScript("getSelection().toString()") { result, _ in + let selection = result as? String ?? "" + self.delegate?.tabWebView(self, didSelectFindInPageForSelection: selection) + } + } + + fileprivate override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + // The find-in-page selection menu only appears if the webview is the first responder. + becomeFirstResponder() + + return super.hitTest(point, with: event) + } +} + +/// +// Temporary fix for Bug 1390871 - NSInvalidArgumentException: -[WKContentView menuHelperFindInPage]: unrecognized selector +// +// This class only exists to contain the swizzledMenuHelperFindInPage. This class is actually never +// instantiated. It only serves as a placeholder for the method. When the method is called, self is +// actually pointing to a WKContentView. Which is not public, but that is fine, we only need to know +// that it is a UIView subclass to access its superview. +// + +class TabWebViewMenuHelper: UIView { + @objc func swizzledMenuHelperFindInPage() { + if let tabWebView = superview?.superview as? TabWebView { + tabWebView.evaluateJavaScript("getSelection().toString()") { result, _ in + let selection = result as? String ?? "" + tabWebView.delegate?.tabWebView(tabWebView, didSelectFindInPageForSelection: selection) + } + } + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TabLocationView.swift b/mobile/ios/Client/Frontend/Browser/TabLocationView.swift new file mode 100644 index 0000000000..c426a7a1c5 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TabLocationView.swift @@ -0,0 +1,399 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared +import SnapKit +import XCGLogger + +private let log = Logger.browserLogger + +protocol TabLocationViewDelegate { + func tabLocationViewDidTapLocation(_ tabLocationView: TabLocationView) + func tabLocationViewDidLongPressLocation(_ tabLocationView: TabLocationView) + func tabLocationViewDidTapReaderMode(_ tabLocationView: TabLocationView) + func tabLocationViewDidTapPageOptions(_ tabLocationView: TabLocationView, from button: UIButton) + func tabLocationViewDidLongPressPageOptions(_ tabLocationVIew: TabLocationView) + + /// - returns: whether the long-press was handled by the delegate; i.e. return `false` when the conditions for even starting handling long-press were not satisfied + @discardableResult func tabLocationViewDidLongPressReaderMode(_ tabLocationView: TabLocationView) -> Bool + func tabLocationViewLocationAccessibilityActions(_ tabLocationView: TabLocationView) -> [UIAccessibilityCustomAction]? +} + +struct TabLocationViewUX { + static let HostFontColor = UIColor.black + static let BaseURLFontColor = UIColor.gray + static let LocationContentInset = 8 + static let URLBarPadding = 4 + + static let Themes: [String: Theme] = { + var themes = [String: Theme]() + var theme = Theme() + theme.URLFontColor = UIColor.lightGray + theme.textColor = UIColor(rgb: 0xf9f9fa) + theme.highlightButtonColor = UIConstants.PrivateModePurple + theme.buttonTintColor = UIColor(rgb: 0xADADb0) + theme.backgroundColor = UIColor(rgb: 0x636369) + themes[Theme.PrivateMode] = theme + + theme = Theme() + theme.textColor = UIColor(rgb: 0x27) + theme.highlightButtonColor = UIColor(rgb: 0x00A2FE) + theme.buttonTintColor = UIColor(rgb: 0x737373) + theme.backgroundColor = .white + themes[Theme.NormalMode] = theme + + return themes + }() +} + +class TabLocationView: UIView { + var delegate: TabLocationViewDelegate? + var longPressRecognizer: UILongPressGestureRecognizer! + var tapRecognizer: UITapGestureRecognizer! + + dynamic var baseURLFontColor: UIColor = TabLocationViewUX.BaseURLFontColor { + didSet { updateTextWithURL() } + } + + var url: URL? { + didSet { + let wasHidden = lockImageView.isHidden + lockImageView.isHidden = url?.scheme != "https" + if wasHidden != lockImageView.isHidden { + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil) + } + updateTextWithURL() + pageOptionsButton.isHidden = (url == nil) + setNeedsUpdateConstraints() + } + } + + var readerModeState: ReaderModeState { + get { + return readerModeButton.readerModeState + } + set (newReaderModeState) { + if newReaderModeState != self.readerModeButton.readerModeState { + let wasHidden = readerModeButton.isHidden + self.readerModeButton.readerModeState = newReaderModeState + readerModeButton.isHidden = (newReaderModeState == ReaderModeState.unavailable) + separatorLine.isHidden = readerModeButton.isHidden + if wasHidden != readerModeButton.isHidden { + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil) + if !readerModeButton.isHidden { + // Delay the Reader Mode accessibility announcement briefly to prevent interruptions. + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, Strings.ReaderModeAvailableVoiceOverAnnouncement) + } + } + } + UIView.animate(withDuration: 0.1, animations: { () -> Void in + if newReaderModeState == ReaderModeState.unavailable { + self.readerModeButton.alpha = 0.0 + } else { + self.readerModeButton.alpha = 1.0 + } + self.setNeedsUpdateConstraints() + self.layoutIfNeeded() + }) + } + } + } + + lazy var placeholder: NSAttributedString = { + let placeholderText = NSLocalizedString("Search or enter address", comment: "The text shown in the URL bar on about:home") + return NSAttributedString(string: placeholderText, attributes: [NSForegroundColorAttributeName: UIColor.gray]) + }() + + lazy var urlTextField: UITextField = { + let urlTextField = DisplayTextField() + + self.longPressRecognizer.delegate = self + urlTextField.addGestureRecognizer(self.longPressRecognizer) + self.tapRecognizer.delegate = self + urlTextField.addGestureRecognizer(self.tapRecognizer) + + // Prevent the field from compressing the toolbar buttons on the 4S in landscape. + urlTextField.setContentCompressionResistancePriority(250, for: UILayoutConstraintAxis.horizontal) + urlTextField.attributedPlaceholder = self.placeholder + urlTextField.accessibilityIdentifier = "url" + urlTextField.accessibilityActionsSource = self + urlTextField.font = UIConstants.DefaultChromeFont + urlTextField.backgroundColor = .clear + return urlTextField + }() + + fileprivate lazy var lockImageView: UIImageView = { + let lockImageView = UIImageView(image: UIImage.templateImageNamed("lock_verified")) + lockImageView.isHidden = true + lockImageView.tintColor = UIColor(rgb: 0x16DA00) + lockImageView.isAccessibilityElement = true + lockImageView.contentMode = UIViewContentMode.center + lockImageView.accessibilityLabel = NSLocalizedString("Secure connection", comment: "Accessibility label for the lock icon, which is only present if the connection is secure") + return lockImageView + }() + + fileprivate lazy var readerModeButton: ReaderModeButton = { + let readerModeButton = ReaderModeButton(frame: CGRect.zero) + readerModeButton.isHidden = true + readerModeButton.addTarget(self, action: #selector(TabLocationView.SELtapReaderModeButton), for: .touchUpInside) + readerModeButton.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(TabLocationView.SELlongPressReaderModeButton(_:)))) + readerModeButton.isAccessibilityElement = true + readerModeButton.imageView?.contentMode = UIViewContentMode.scaleAspectFit + readerModeButton.accessibilityLabel = NSLocalizedString("Reader View", comment: "Accessibility label for the Reader View button") + readerModeButton.accessibilityIdentifier = "TabLocationView.readerModeButton" + readerModeButton.accessibilityCustomActions = [UIAccessibilityCustomAction(name: NSLocalizedString("Add to Reading List", comment: "Accessibility label for action adding current page to reading list."), target: self, selector: #selector(TabLocationView.SELreaderModeCustomAction))] + return readerModeButton + }() + + lazy var pageOptionsButton: ToolbarButton = { + let pageOptionsButton = ToolbarButton(frame: CGRect.zero) + pageOptionsButton.setImage(UIImage.templateImageNamed("menu-More-Options"), for: .normal) + pageOptionsButton.isHidden = true + pageOptionsButton.addTarget(self, action: #selector(TabLocationView.SELDidPressPageOptionsButton), for: .touchUpInside) + pageOptionsButton.isAccessibilityElement = true + pageOptionsButton.imageView?.contentMode = .center + pageOptionsButton.accessibilityLabel = NSLocalizedString("Page Options Menu", comment: "Accessibility label for the Page Options menu button") + pageOptionsButton.accessibilityIdentifier = "TabLocationView.pageOptionsButton" + let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(TabLocationView.SELDidLongPressPageOptionsButton)) + pageOptionsButton.addGestureRecognizer(longPressGesture) + return pageOptionsButton + }() + + lazy var separatorLine: UIView = { + let line = UIView() + line.layer.cornerRadius = 2 + line.backgroundColor = UIColor(rgb: 0xE5E5E5) + line.isHidden = true + return line + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(TabLocationView.SELlongPressLocation(_:))) + tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(TabLocationView.SELtapLocation(_:))) + + addSubview(urlTextField) + addSubview(lockImageView) + addSubview(readerModeButton) + addSubview(pageOptionsButton) + addSubview(separatorLine) + + lockImageView.snp.makeConstraints { make in + make.size.equalTo(24) + make.centerY.equalTo(self) + make.leading.equalTo(self).offset(9) + } + + pageOptionsButton.snp.makeConstraints { make in + make.centerY.equalTo(self) + make.trailing.equalTo(self) + make.width.equalTo(44) + make.height.equalTo(self) + } + + separatorLine.snp.makeConstraints { make in + make.width.equalTo(1) + make.height.equalTo(26) + make.trailing.equalTo(pageOptionsButton.snp.leading) + make.centerY.equalTo(self) + } + + readerModeButton.snp.makeConstraints { make in + make.centerY.equalTo(self) + make.trailing.equalTo(separatorLine.snp.leading).offset(-9) + make.size.equalTo(24) + } + } + + override var accessibilityElements: [Any]? { + get { + return [lockImageView, urlTextField, readerModeButton, pageOptionsButton].filter { !$0.isHidden } + } + set { + super.accessibilityElements = newValue + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func updateConstraints() { + urlTextField.snp.remakeConstraints { make in + make.top.bottom.equalTo(self) + + if lockImageView.isHidden { + make.leading.equalTo(self).offset(TabLocationViewUX.LocationContentInset) + } else { + make.leading.equalTo(self.lockImageView.snp.trailing).offset(TabLocationViewUX.URLBarPadding) + } + + if readerModeButton.isHidden { + make.trailing.equalTo(self.pageOptionsButton.snp.leading).offset(-TabLocationViewUX.URLBarPadding) + } else { + make.trailing.equalTo(self.readerModeButton.snp.leading).offset(-TabLocationViewUX.URLBarPadding) + } + } + + super.updateConstraints() + } + + func SELtapReaderModeButton() { + delegate?.tabLocationViewDidTapReaderMode(self) + } + + func SELlongPressReaderModeButton(_ recognizer: UILongPressGestureRecognizer) { + if recognizer.state == UIGestureRecognizerState.began { + delegate?.tabLocationViewDidLongPressReaderMode(self) + } + } + + func SELDidPressPageOptionsButton(_ button: UIButton) { + delegate?.tabLocationViewDidTapPageOptions(self, from: button) + } + + func SELDidLongPressPageOptionsButton(_ recognizer: UILongPressGestureRecognizer) { + delegate?.tabLocationViewDidLongPressPageOptions(self) + } + + func SELlongPressLocation(_ recognizer: UITapGestureRecognizer) { + if recognizer.state == UIGestureRecognizerState.began { + delegate?.tabLocationViewDidLongPressLocation(self) + } + } + + func SELtapLocation(_ recognizer: UITapGestureRecognizer) { + delegate?.tabLocationViewDidTapLocation(self) + } + + func SELreaderModeCustomAction() -> Bool { + return delegate?.tabLocationViewDidLongPressReaderMode(self) ?? false + } + + fileprivate func updateTextWithURL() { + if let host = url?.host, AppConstants.MOZ_PUNYCODE { + urlTextField.text = url?.absoluteString.replacingOccurrences(of: host, with: host.asciiHostToUTF8()) + } else { + urlTextField.text = url?.absoluteString + } + // remove https:// (the scheme) from the url when displaying + if let scheme = url?.scheme, let range = url?.absoluteString.range(of: "\(scheme)://") { + urlTextField.text = url?.absoluteString.replacingCharacters(in: range, with: "") + } + } +} + +extension TabLocationView: UIGestureRecognizerDelegate { + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + return true + } + + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool { + // If the longPressRecognizer is active, fail all other recognizers to avoid conflicts. + return gestureRecognizer == longPressRecognizer + } +} + +extension TabLocationView: AccessibilityActionsSource { + func accessibilityCustomActionsForView(_ view: UIView) -> [UIAccessibilityCustomAction]? { + if view === urlTextField { + return delegate?.tabLocationViewLocationAccessibilityActions(self) + } + return nil + } +} + +extension TabLocationView: Themeable { + func applyTheme(_ themeName: String) { + guard let theme = TabLocationViewUX.Themes[themeName] else { + log.error("Unable to apply unknown theme \(themeName)") + return + } + let isPrivate = themeName == Theme.PrivateMode + backgroundColor = theme.backgroundColor + urlTextField.textColor = theme.textColor + readerModeButton.selectedTintColor = theme.highlightButtonColor + readerModeButton.unselectedTintColor = theme.buttonTintColor + pageOptionsButton.selectedTintColor = theme.highlightButtonColor + + pageOptionsButton.unselectedTintColor = isPrivate ? UIColor(rgb: 0xD2d2d4) : UIColor(rgb: 0x272727) + pageOptionsButton.tintColor = pageOptionsButton.unselectedTintColor + separatorLine.backgroundColor = isPrivate ? UIColor(rgb: 0x3f3f43) : UIColor(rgb: 0xE5E5E5) + } +} + +class ReaderModeButton: UIButton { + var selectedTintColor: UIColor? + var unselectedTintColor: UIColor? + override init(frame: CGRect) { + super.init(frame: frame) + adjustsImageWhenHighlighted = false + setImage(UIImage.templateImageNamed("reader"), for: .normal) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var isSelected: Bool { + didSet { + self.tintColor = (isHighlighted || isSelected) ? selectedTintColor : unselectedTintColor + } + } + + override open var isHighlighted: Bool { + didSet { + self.tintColor = (isHighlighted || isSelected) ? selectedTintColor : unselectedTintColor + } + } + + override var tintColor: UIColor! { + didSet { + self.imageView?.tintColor = self.tintColor + } + } + + var _readerModeState: ReaderModeState = ReaderModeState.unavailable + + var readerModeState: ReaderModeState { + get { + return _readerModeState + } + set (newReaderModeState) { + _readerModeState = newReaderModeState + switch _readerModeState { + case .available: + self.isEnabled = true + self.isSelected = false + case .unavailable: + self.isEnabled = false + self.isSelected = false + case .active: + self.isEnabled = true + self.isSelected = true + } + } + } +} + +private class DisplayTextField: UITextField { + weak var accessibilityActionsSource: AccessibilityActionsSource? + + override var accessibilityCustomActions: [UIAccessibilityCustomAction]? { + get { + return accessibilityActionsSource?.accessibilityCustomActionsForView(self) + } + set { + super.accessibilityCustomActions = newValue + } + } + + fileprivate override var canBecomeFirstResponder: Bool { + return false + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TabManager.swift b/mobile/ios/Client/Frontend/Browser/TabManager.swift new file mode 100644 index 0000000000..643bfbf5e1 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TabManager.swift @@ -0,0 +1,988 @@ +/* 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/. */ + +import Foundation +import WebKit +import Storage +import Shared + +protocol TabManagerDelegate: class { + func tabManager(_ tabManager: TabManager, didSelectedTabChange selected: Tab?, previous: Tab?) + func tabManager(_ tabManager: TabManager, willAddTab tab: Tab) + func tabManager(_ tabManager: TabManager, didAddTab tab: Tab) + func tabManager(_ tabManager: TabManager, willRemoveTab tab: Tab) + func tabManager(_ tabManager: TabManager, didRemoveTab tab: Tab) + + func tabManagerDidRestoreTabs(_ tabManager: TabManager) + func tabManagerDidAddTabs(_ tabManager: TabManager) + func tabManagerDidRemoveAllTabs(_ tabManager: TabManager, toast: ButtonToast?) +} + +protocol TabManagerStateDelegate: class { + func tabManagerWillStoreTabs(_ tabs: [Tab]) +} + +// We can't use a WeakList here because this is a protocol. +class WeakTabManagerDelegate { + weak var value: TabManagerDelegate? + + init (value: TabManagerDelegate) { + self.value = value + } + + func get() -> TabManagerDelegate? { + return value + } +} + +// TabManager must extend NSObjectProtocol in order to implement WKNavigationDelegate +class TabManager: NSObject { + fileprivate var delegates = [WeakTabManagerDelegate]() + fileprivate var tabEventHandlers = TabEventHandlers.default.handlers + weak var stateDelegate: TabManagerStateDelegate? + + func addDelegate(_ delegate: TabManagerDelegate) { + assert(Thread.isMainThread) + delegates.append(WeakTabManagerDelegate(value: delegate)) + } + + func removeDelegate(_ delegate: TabManagerDelegate) { + assert(Thread.isMainThread) + for i in 0 ..< delegates.count { + let del = delegates[i] + if delegate === del.get() || del.get() == nil { + delegates.remove(at: i) + return + } + } + } + + fileprivate(set) var tabs = [Tab]() + fileprivate var _selectedIndex = -1 + fileprivate let navDelegate: TabManagerNavDelegate + fileprivate(set) var isRestoring = false + + // A WKWebViewConfiguration used for normal tabs + lazy fileprivate var configuration: WKWebViewConfiguration = { + let configuration = WKWebViewConfiguration() + configuration.processPool = WKProcessPool() + configuration.preferences.javaScriptCanOpenWindowsAutomatically = !(self.prefs.boolForKey("blockPopups") ?? true) + return configuration + }() + + // A WKWebViewConfiguration used for private mode tabs + lazy fileprivate var privateConfiguration: WKWebViewConfiguration = { + let configuration = WKWebViewConfiguration() + configuration.processPool = WKProcessPool() + configuration.preferences.javaScriptCanOpenWindowsAutomatically = !(self.prefs.boolForKey("blockPopups") ?? true) + configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() + return configuration + }() + + fileprivate let imageStore: DiskImageStore? + + fileprivate let prefs: Prefs + var selectedIndex: Int { return _selectedIndex } + var tempTabs: [Tab]? + + var normalTabs: [Tab] { + assert(Thread.isMainThread) + + return tabs.filter { !$0.isPrivate } + } + + var privateTabs: [Tab] { + assert(Thread.isMainThread) + return tabs.filter { $0.isPrivate } + } + + init(prefs: Prefs, imageStore: DiskImageStore?) { + assert(Thread.isMainThread) + + self.prefs = prefs + self.navDelegate = TabManagerNavDelegate() + self.imageStore = imageStore + super.init() + + addNavigationDelegate(self) + + NotificationCenter.default.addObserver(self, selector: #selector(TabManager.prefsDidChange), name: UserDefaults.didChangeNotification, object: nil) + } + + func addNavigationDelegate(_ delegate: WKNavigationDelegate) { + assert(Thread.isMainThread) + + self.navDelegate.insert(delegate) + } + + var count: Int { + assert(Thread.isMainThread) + + return tabs.count + } + + var selectedTab: Tab? { + assert(Thread.isMainThread) + if !(0.. Tab? { + assert(Thread.isMainThread) + + if index >= tabs.count { + return nil + } + return tabs[index] + } + + subscript(webView: WKWebView) -> Tab? { + assert(Thread.isMainThread) + + for tab in tabs where tab.webView === webView { + return tab + } + + return nil + } + + func getTabFor(_ url: URL) -> Tab? { + assert(Thread.isMainThread) + + for tab in tabs { + if tab.webView?.url == url { + return tab + } + + // Also look for tabs that haven't been restored yet. + if let sessionData = tab.sessionData, + 0.. Bool { + return prefs.boolForKey("settings.closePrivateTabs") ?? false + } + + //Called by other classes to signal that they are entering/exiting private mode + //This is called by TabTrayVC when the private mode button is pressed and BEFORE we've switched to the new mode + func willSwitchTabMode() { + if shouldClearPrivateTabs() && (selectedTab?.isPrivate ?? false) { + removeAllPrivateTabs() + } + } + + func expireSnackbars() { + assert(Thread.isMainThread) + + for tab in tabs { + tab.expireSnackbars() + } + } + + @discardableResult func addTab(_ request: URLRequest! = nil, configuration: WKWebViewConfiguration! = nil, afterTab: Tab? = nil, isPrivate: Bool) -> Tab { + return self.addTab(request, configuration: configuration, afterTab: afterTab, flushToDisk: true, zombie: false, isPrivate: isPrivate) + } + + func addTabAndSelect(_ request: URLRequest! = nil, configuration: WKWebViewConfiguration! = nil, afterTab: Tab? = nil, isPrivate: Bool) -> Tab { + let tab = addTab(request, configuration: configuration, afterTab: afterTab, isPrivate: isPrivate) + selectTab(tab) + return tab + } + + @discardableResult func addTabAndSelect(_ request: URLRequest! = nil, configuration: WKWebViewConfiguration! = nil, afterTab: Tab? = nil) -> Tab { + let tab = addTab(request, configuration: configuration, afterTab: afterTab) + selectTab(tab) + return tab + } + + // This method is duplicated to hide the flushToDisk option from consumers. + @discardableResult func addTab(_ request: URLRequest! = nil, configuration: WKWebViewConfiguration! = nil, afterTab: Tab? = nil) -> Tab { + return self.addTab(request, configuration: configuration, afterTab: afterTab, flushToDisk: true, zombie: false) + } + + func addTabsForURLs(_ urls: [URL], zombie: Bool) { + assert(Thread.isMainThread) + + if urls.isEmpty { + return + } + // When bulk adding tabs don't notify delegates until we are done + self.isRestoring = true + var tab: Tab! + for url in urls { + tab = self.addTab(URLRequest(url: url), flushToDisk: false, zombie: zombie) + } + // Flush. + storeChanges() + // Select the most recent. + self.selectTab(tab) + self.isRestoring = false + // Okay now notify that we bulk-loaded so we can adjust counts and animate changes. + delegates.forEach { $0.get()?.tabManagerDidAddTabs(self) } + } + + fileprivate func addTab(_ request: URLRequest? = nil, configuration: WKWebViewConfiguration? = nil, afterTab: Tab? = nil, flushToDisk: Bool, zombie: Bool, isPrivate: Bool) -> Tab { + assert(Thread.isMainThread) + + // Take the given configuration. Or if it was nil, take our default configuration for the current browsing mode. + let configuration: WKWebViewConfiguration = configuration ?? (isPrivate ? privateConfiguration : self.configuration) + + let tab = Tab(configuration: configuration, isPrivate: isPrivate) + configureTab(tab, request: request, afterTab: afterTab, flushToDisk: flushToDisk, zombie: zombie) + return tab + } + + fileprivate func addTab(_ request: URLRequest? = nil, configuration: WKWebViewConfiguration? = nil, afterTab: Tab? = nil, flushToDisk: Bool, zombie: Bool) -> Tab { + assert(Thread.isMainThread) + + let tab = Tab(configuration: configuration ?? self.configuration) + configureTab(tab, request: request, afterTab: afterTab, flushToDisk: flushToDisk, zombie: zombie) + return tab + } + + func moveTab(isPrivate privateMode: Bool, fromIndex visibleFromIndex: Int, toIndex visibleToIndex: Int) { + assert(Thread.isMainThread) + + let currentTabs = privateMode ? privateTabs : normalTabs + let fromIndex = tabs.index(of: currentTabs[visibleFromIndex]) ?? tabs.count - 1 + let toIndex = tabs.index(of: currentTabs[visibleToIndex]) ?? tabs.count - 1 + + let previouslySelectedTab = selectedTab + + tabs.insert(tabs.remove(at: fromIndex), at: toIndex) + + if let previouslySelectedTab = previouslySelectedTab, let previousSelectedIndex = tabs.index(of: previouslySelectedTab) { + _selectedIndex = previousSelectedIndex + } + + storeChanges() + } + + func configureTab(_ tab: Tab, request: URLRequest?, afterTab parent: Tab? = nil, flushToDisk: Bool, zombie: Bool) { + assert(Thread.isMainThread) + + delegates.forEach { $0.get()?.tabManager(self, willAddTab: tab) } + + if parent == nil || parent?.isPrivate != tab.isPrivate { + tabs.append(tab) + } else if let parent = parent, var insertIndex = tabs.index(of: parent) { + insertIndex += 1 + while insertIndex < tabs.count && tabs[insertIndex].isDescendentOf(parent) { + insertIndex += 1 + } + tab.parent = parent + tabs.insert(tab, at: insertIndex) + } + + delegates.forEach { $0.get()?.tabManager(self, didAddTab: tab) } + + if !zombie { + tab.createWebview() + } + tab.navigationDelegate = self.navDelegate + + if let request = request { + tab.loadRequest(request) + } else { + let newTabChoice = NewTabAccessors.getNewTabPage(prefs) + switch newTabChoice { + case .homePage: + // We definitely have a homepage if we've got here + // (so we can safely dereference it). + let url = HomePageAccessors.getHomePage(prefs)! + tab.loadRequest(URLRequest(url: url)) + case .blankPage: + // Do nothing: we're already seeing a blank page. + break + default: + // The common case, where the NewTabPage enum defines + // one of the about:home pages. + if let url = newTabChoice.url { + tab.loadRequest(PrivilegedRequest(url: url) as URLRequest) + tab.url = url + } + } + } + if flushToDisk { + storeChanges() + } + } + + // This method is duplicated to hide the flushToDisk option from consumers. + func removeTab(_ tab: Tab) { + self.removeTab(tab, flushToDisk: true, notify: true) + hideNetworkActivitySpinner() + } + + /// - Parameter notify: if set to true, will call the delegate after the tab + /// is removed. + fileprivate func removeTab(_ tab: Tab, flushToDisk: Bool, notify: Bool) { + assert(Thread.isMainThread) + + guard let removalIndex = tabs.index(where: { $0 === tab }) else { + Sentry.shared.sendWithStacktrace(message: "Could not find index of tab to remove", tag: .tabManager, severity: .fatal, description: "Tab count: \(count)") + return + } + + if tab.isPrivate { + removeAllBrowsingDataForTab(tab) + } + + let oldSelectedTab = selectedTab + + if notify { + delegates.forEach { $0.get()?.tabManager(self, willRemoveTab: tab) } + } + + // The index of the tab in its respective tab grouping. Used to figure out which tab is next + var tabIndex: Int = -1 + if let oldTab = oldSelectedTab { + tabIndex = (tab.isPrivate ? privateTabs.index(of: oldTab) : normalTabs.index(of: oldTab)) ?? -1 + } + + let prevCount = count + tabs.remove(at: removalIndex) + + let viableTabs: [Tab] = tab.isPrivate ? privateTabs : normalTabs + + // Let's select the tab to be selected next. + if let oldTab = oldSelectedTab, tab !== oldTab { + // If it wasn't the selected tab we removed, then keep it like that. + // It might have changed index, so we look it up again. + _selectedIndex = tabs.index(of: oldTab) ?? -1 + } else if let newTab = viableTabs.reduce(viableTabs.first, { currentBestTab, tab2 in + if let tab1 = currentBestTab, let time1 = tab1.lastExecutedTime { + if let time2 = tab2.lastExecutedTime { + return time1 <= time2 ? tab2 : tab1 + } + return tab1 + } else { + return tab2 + } + }), tab !== newTab, newTab.lastExecutedTime != nil { + // Next we look for the most recently loaded one. It might not exist, of course. + _selectedIndex = tabs.index(of: newTab) ?? -1 + } else { + // By now, we've just removed the selected one, and no previously loaded + // tabs. So let's load the final one in the tab tray. + if tabIndex == viableTabs.count { + tabIndex -= 1 + } + if tabIndex < viableTabs.count && !viableTabs.isEmpty { + _selectedIndex = tabs.index(of: viableTabs[tabIndex]) ?? -1 + } else { + _selectedIndex = -1 + } + } + + assert(count == prevCount - 1, "Make sure the tab count was actually removed") + + // There's still some time between this and the webView being destroyed. We don't want to pick up any stray events. + tab.webView?.navigationDelegate = nil + + if notify { + delegates.forEach { $0.get()?.tabManager(self, didRemoveTab: tab) } + TabEvent.post(.didClose, for: tab) + } + + if !tab.isPrivate && viableTabs.isEmpty { + addTab() + } + + // If the removed tab was selected, find the new tab to select. + if selectedTab != nil { + selectTab(selectedTab, previous: oldSelectedTab) + } else { + selectTab(tabs.last, previous: oldSelectedTab) + } + + if flushToDisk { + storeChanges() + } + } + + /// Removes all private tabs from the manager without notifying delegates. + private func removeAllPrivateTabs() { + // reset the selectedTabIndex if we are on a private tab because we will be removing it. + if selectedTab?.isPrivate ?? false { + _selectedIndex = -1 + } + tabs.forEach { tab in + if tab.isPrivate { + removeAllBrowsingDataForTab(tab) + } + } + + tabs = tabs.filter { !$0.isPrivate } + } + + func removeAllBrowsingDataForTab(_ tab: Tab, completionHandler: @escaping () -> Void = {}) { + let dataTypes = Set([WKWebsiteDataTypeCookies, + WKWebsiteDataTypeLocalStorage, + WKWebsiteDataTypeSessionStorage, + WKWebsiteDataTypeWebSQLDatabases, + WKWebsiteDataTypeIndexedDBDatabases]) + tab.webView?.configuration.websiteDataStore.removeData(ofTypes: dataTypes, + modifiedSince: Date.distantPast, + completionHandler: completionHandler) + } + + func removeTabsWithUndoToast(_ tabs: [Tab]) { + tempTabs = tabs + var tabsCopy = tabs + + // Remove the current tab last to prevent switching tabs while removing tabs + if let selectedTab = selectedTab { + if let selectedIndex = tabsCopy.index(of: selectedTab) { + let removed = tabsCopy.remove(at: selectedIndex) + removeTabs(tabsCopy) + removeTab(removed) + } else { + removeTabs(tabsCopy) + } + } + for tab in tabs { + tab.hideContent() + } + var toast: ButtonToast? + if let numberOfTabs = tempTabs?.count, numberOfTabs > 0 { + toast = ButtonToast(labelText: String.localizedStringWithFormat(Strings.TabsDeleteAllUndoTitle, numberOfTabs), buttonText: Strings.TabsDeleteAllUndoAction, completion: { buttonPressed in + if buttonPressed { + self.undoCloseTabs() + self.storeChanges() + for delegate in self.delegates { + delegate.get()?.tabManagerDidAddTabs(self) + } + } + self.eraseUndoCache() + }) + } + + delegates.forEach { $0.get()?.tabManagerDidRemoveAllTabs(self, toast: toast) } + } + + func undoCloseTabs() { + guard let tempTabs = self.tempTabs, tempTabs.count > 0 else { + return + } + let tabsCopy = normalTabs + restoreTabs(tempTabs) + self.isRestoring = true + for tab in tempTabs { + tab.showContent(true) + } + if !tempTabs[0].isPrivate { + removeTabs(tabsCopy) + } + selectTab(tempTabs.first) + self.isRestoring = false + delegates.forEach { $0.get()?.tabManagerDidRestoreTabs(self) } + self.tempTabs?.removeAll() + tabs.first?.createWebview() + } + + func eraseUndoCache() { + tempTabs?.removeAll() + } + + func removeTabs(_ tabs: [Tab]) { + for tab in tabs { + self.removeTab(tab, flushToDisk: false, notify: true) + } + storeChanges() + } + + func removeAll() { + removeTabs(self.tabs) + } + + func getIndex(_ tab: Tab) -> Int? { + assert(Thread.isMainThread) + + for i in 0.. Tab? { + assert(Thread.isMainThread) + + return tabs.filter { $0.webView?.url == url } .first + } + + func storeChanges() { + stateDelegate?.tabManagerWillStoreTabs(normalTabs) + + // Also save (full) tab state to disk. + preserveTabs() + } + + func prefsDidChange() { + DispatchQueue.main.async { + let allowPopups = !(self.prefs.boolForKey("blockPopups") ?? true) + // Each tab may have its own configuration, so we should tell each of them in turn. + for tab in self.tabs { + tab.webView?.configuration.preferences.javaScriptCanOpenWindowsAutomatically = allowPopups + } + // The default tab configurations also need to change. + self.configuration.preferences.javaScriptCanOpenWindowsAutomatically = allowPopups + self.privateConfiguration.preferences.javaScriptCanOpenWindowsAutomatically = allowPopups + } + } + + func resetProcessPool() { + assert(Thread.isMainThread) + + configuration.processPool = WKProcessPool() + } +} + +class SavedTab: NSObject, NSCoding { + let isSelected: Bool + let title: String? + let isPrivate: Bool + var sessionData: SessionData? + var screenshotUUID: UUID? + var faviconURL: String? + + var jsonDictionary: [String: AnyObject] { + let title: String = self.title ?? "null" + let faviconURL: String = self.faviconURL ?? "null" + let uuid: String = self.screenshotUUID?.uuidString ?? "null" + + var json: [String: AnyObject] = [ + "title": title as AnyObject, + "isPrivate": String(self.isPrivate) as AnyObject, + "isSelected": String(self.isSelected) as AnyObject, + "faviconURL": faviconURL as AnyObject, + "screenshotUUID": uuid as AnyObject + ] + + if let sessionDataInfo = self.sessionData?.jsonDictionary { + json["sessionData"] = sessionDataInfo as AnyObject? + } + + return json + } + + init?(tab: Tab, isSelected: Bool) { + assert(Thread.isMainThread) + + self.screenshotUUID = tab.screenshotUUID as UUID? + self.isSelected = isSelected + self.title = tab.displayTitle + self.isPrivate = tab.isPrivate + self.faviconURL = tab.displayFavicon?.url + super.init() + + if tab.sessionData == nil { + let currentItem: WKBackForwardListItem! = tab.webView?.backForwardList.currentItem + + // Freshly created web views won't have any history entries at all. + // If we have no history, abort. + if currentItem == nil { + return nil + } + + let backList = tab.webView?.backForwardList.backList ?? [] + let forwardList = tab.webView?.backForwardList.forwardList ?? [] + let urls = (backList + [currentItem] + forwardList).map { $0.url } + let currentPage = -forwardList.count + self.sessionData = SessionData(currentPage: currentPage, urls: urls, lastUsedTime: tab.lastExecutedTime ?? Date.now()) + } else { + self.sessionData = tab.sessionData + } + } + + required init?(coder: NSCoder) { + self.sessionData = coder.decodeObject(forKey: "sessionData") as? SessionData + self.screenshotUUID = coder.decodeObject(forKey: "screenshotUUID") as? UUID + self.isSelected = coder.decodeBool(forKey: "isSelected") + self.title = coder.decodeObject(forKey: "title") as? String + self.isPrivate = coder.decodeBool(forKey: "isPrivate") + self.faviconURL = coder.decodeObject(forKey: "faviconURL") as? String + } + + func encode(with coder: NSCoder) { + coder.encode(sessionData, forKey: "sessionData") + coder.encode(screenshotUUID, forKey: "screenshotUUID") + coder.encode(isSelected, forKey: "isSelected") + coder.encode(title, forKey: "title") + coder.encode(isPrivate, forKey: "isPrivate") + coder.encode(faviconURL, forKey: "faviconURL") + } +} + +extension TabManager { + + static fileprivate func tabsStateArchivePath() -> String { + let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + return URL(fileURLWithPath: documentsPath).appendingPathComponent("tabsState.archive").path + } + + static func tabArchiveData() -> Data? { + let tabStateArchivePath = tabsStateArchivePath() + if FileManager.default.fileExists(atPath: tabStateArchivePath) { + return (try? Data(contentsOf: URL(fileURLWithPath: tabStateArchivePath))) + } else { + return nil + } + } + + static func tabsToRestore() -> [SavedTab]? { + if let tabData = tabArchiveData() { + let unarchiver = NSKeyedUnarchiver(forReadingWith: tabData) + unarchiver.decodingFailurePolicy = .setErrorAndReturn + guard let tabs = unarchiver.decodeObject(forKey: "tabs") as? [SavedTab] else { + Sentry.shared.send(message: "Failed to restore tabs", tag: SentryTag.tabManager, severity: .error, description: "\(unarchiver.error ??? "nil")") + return nil + } + return tabs + } else { + return nil + } + } + + fileprivate func preserveTabsInternal() { + assert(Thread.isMainThread) + + guard !isRestoring else { return } + + let path = TabManager.tabsStateArchivePath() + var savedTabs = [SavedTab]() + var savedUUIDs = Set() + for (tabIndex, tab) in tabs.enumerated() { + if let savedTab = SavedTab(tab: tab, isSelected: tabIndex == selectedIndex) { + savedTabs.append(savedTab) + + if let screenshot = tab.screenshot, + let screenshotUUID = tab.screenshotUUID { + savedUUIDs.insert(screenshotUUID.uuidString) + imageStore?.put(screenshotUUID.uuidString, image: screenshot) + } + } + } + + // Clean up any screenshots that are no longer associated with a tab. + _ = imageStore?.clearExcluding(savedUUIDs) + + let tabStateData = NSMutableData() + let archiver = NSKeyedArchiver(forWritingWith: tabStateData) + archiver.encode(savedTabs, forKey: "tabs") + archiver.finishEncoding() + tabStateData.write(toFile: path, atomically: true) + } + + func preserveTabs() { + // This is wrapped in an Objective-C @try/@catch handler because NSKeyedArchiver may throw exceptions which Swift cannot handle + _ = Try(withTry: { () -> Void in + self.preserveTabsInternal() + }) { (exception) -> Void in + Sentry.shared.send(message: "Failed to preserve tabs", tag: SentryTag.tabManager, severity: .error, description: "\(exception ??? "nil")") + } + } + + fileprivate func restoreTabsInternal() { + guard var savedTabs = TabManager.tabsToRestore() else { + return + } + + // Make sure to wipe the private tabs if the user has the pref turned on + if shouldClearPrivateTabs() { + savedTabs = savedTabs.filter { !$0.isPrivate } + } + + var tabToSelect: Tab? + for savedTab in savedTabs { + // Provide an empty request to prevent a new tab from loading the home screen + let tab = self.addTab(nil, configuration: nil, afterTab: nil, flushToDisk: false, zombie: true, isPrivate: savedTab.isPrivate) + + // Since this is a restored tab, reset the URL to be loaded as that will be handled by the SessionRestoreHandler + tab.url = nil + + if let faviconURL = savedTab.faviconURL { + let icon = Favicon(url: faviconURL, date: Date(), type: IconType.noneFound) + icon.width = 1 + tab.favicons.append(icon) + } + + // Set the UUID for the tab, asynchronously fetch the UIImage, then store + // the screenshot in the tab as long as long as a newer one hasn't been taken. + if let screenshotUUID = savedTab.screenshotUUID, + let imageStore = self.imageStore { + tab.screenshotUUID = screenshotUUID + imageStore.get(screenshotUUID.uuidString) >>== { screenshot in + if tab.screenshotUUID == screenshotUUID { + tab.setScreenshot(screenshot, revUUID: false) + } + } + } + + if savedTab.isSelected { + tabToSelect = tab + } + + tab.sessionData = savedTab.sessionData + tab.lastTitle = savedTab.title + } + + if tabToSelect == nil { + tabToSelect = tabs.first + } + + // Only tell our delegates that we restored tabs if we actually restored a tab(s) + if savedTabs.count > 0 { + for delegate in delegates { + delegate.get()?.tabManagerDidRestoreTabs(self) + } + } + + if let tab = tabToSelect { + selectTab(tab) + tab.createWebview() + } + } + + func restoreTabs() { + isRestoring = true + + if count == 0 && !AppConstants.IsRunningTest && !DebugSettingsBundleOptions.skipSessionRestore { + // This is wrapped in an Objective-C @try/@catch handler because NSKeyedUnarchiver may throw exceptions which Swift cannot handle + _ = Try( + withTry: { () -> Void in + self.restoreTabsInternal() + }, + catch: { exception in + Sentry.shared.send(message: "Failed to restore tabs: ", tag: SentryTag.tabManager, severity: .error, description: "\(exception ??? "nil")") + } + ) + } + isRestoring = false + + // Always make sure there is a single normal tab. + if normalTabs.isEmpty { + let tab = addTab() + if selectedTab == nil { + selectTab(tab) + } + } + } + + func restoreTabs(_ savedTabs: [Tab]) { + isRestoring = true + for tab in savedTabs { + tabs.append(tab) + tab.navigationDelegate = self.navDelegate + for delegate in delegates { + delegate.get()?.tabManager(self, didAddTab: tab) + } + } + isRestoring = false + } +} + +extension TabManager: WKNavigationDelegate { + func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { + UIApplication.shared.isNetworkActivityIndicatorVisible = true + } + + func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { + let tab = self[webView] + let isNightMode = NightModeAccessors.isNightMode(self.prefs) + tab?.setNightMode(isNightMode) + + if #available(iOS 11, *) { + let isNoImageMode = self.prefs.boolForKey(PrefsKeys.KeyNoImageModeStatus) ?? false + tab?.noImageMode = isNoImageMode + } + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + hideNetworkActivitySpinner() + // only store changes if this is not an error page + // as we current handle tab restore as error page redirects then this ensures that we don't + // call storeChanges unnecessarily on startup + if let url = webView.url { + if !url.isErrorPageURL { + storeChanges() + } + } + } + + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + hideNetworkActivitySpinner() + } + + func hideNetworkActivitySpinner() { + for tab in tabs { + if let tabWebView = tab.webView { + // If we find one tab loading, we don't hide the spinner + if tabWebView.isLoading { + return + } + } + } + UIApplication.shared.isNetworkActivityIndicatorVisible = false + } + + /// Called when the WKWebView's content process has gone away. If this happens for the currently selected tab + /// then we immediately reload it. + + func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { + if let tab = selectedTab, tab.webView == webView { + webView.reload() + } + } +} + +extension TabManager { + class func tabRestorationDebugInfo() -> String { + assert(Thread.isMainThread) + + let tabs = TabManager.tabsToRestore()?.map { $0.jsonDictionary } ?? [] + do { + let jsonData = try JSONSerialization.data(withJSONObject: tabs, options: [.prettyPrinted]) + return String(data: jsonData, encoding: String.Encoding.utf8) ?? "" + } catch _ { + return "" + } + } +} + +// WKNavigationDelegates must implement NSObjectProtocol +class TabManagerNavDelegate: NSObject, WKNavigationDelegate { + fileprivate var delegates = WeakList() + + func insert(_ delegate: WKNavigationDelegate) { + delegates.insert(delegate) + } + + func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { + for delegate in delegates { + delegate.webView?(webView, didCommit: navigation) + } + } + + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + for delegate in delegates { + delegate.webView?(webView, didFail: navigation, withError: error) + } + } + + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + for delegate in delegates { + delegate.webView?(webView, didFailProvisionalNavigation: navigation, withError: error) + } + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + for delegate in delegates { + delegate.webView?(webView, didFinish: navigation) + } + } + + func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + let authenticatingDelegates = delegates.filter { wv in + return wv.responds(to: #selector(WKNavigationDelegate.webView(_:didReceive:completionHandler:))) + } + + guard let firstAuthenticatingDelegate = authenticatingDelegates.first else { + return completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil) + } + + firstAuthenticatingDelegate.webView?(webView, didReceive: challenge) { (disposition, credential) in + completionHandler(disposition, credential) + } + } + + func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { + for delegate in delegates { + delegate.webView?(webView, didReceiveServerRedirectForProvisionalNavigation: navigation) + } + } + + func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { + for delegate in delegates { + delegate.webView?(webView, didStartProvisionalNavigation: navigation) + } + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + var res = WKNavigationActionPolicy.allow + for delegate in delegates { + delegate.webView?(webView, decidePolicyFor: navigationAction, decisionHandler: { policy in + if policy == .cancel { + res = policy + } + }) + } + + decisionHandler(res) + } + + func webView(_ webView: WKWebView, + decidePolicyFor navigationResponse: WKNavigationResponse, + decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { + var res = WKNavigationResponsePolicy.allow + for delegate in delegates { + delegate.webView?(webView, decidePolicyFor: navigationResponse, decisionHandler: { policy in + if policy == .cancel { + res = policy + } + }) + } + + if res == .allow, let appDelegate = UIApplication.shared.delegate as? AppDelegate { + let tab = appDelegate.browserViewController.tabManager[webView] + tab?.mimeType = navigationResponse.response.mimeType + } + + decisionHandler(res) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TabPeekViewController.swift b/mobile/ios/Client/Frontend/Browser/TabPeekViewController.swift new file mode 100644 index 0000000000..fcde0e0ad8 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TabPeekViewController.swift @@ -0,0 +1,174 @@ +/* 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/. */ + +import UIKit +import Shared +import Storage +import ReadingList +import WebKit + +protocol TabPeekDelegate: class { + func tabPeekDidAddBookmark(_ tab: Tab) + @discardableResult func tabPeekDidAddToReadingList(_ tab: Tab) -> ReadingListClientRecord? + func tabPeekRequestsPresentationOf(_ viewController: UIViewController) + func tabPeekDidCloseTab(_ tab: Tab) +} + +class TabPeekViewController: UIViewController, WKNavigationDelegate { + + fileprivate static let PreviewActionAddToBookmarks = NSLocalizedString("Add to Bookmarks", tableName: "3DTouchActions", comment: "Label for preview action on Tab Tray Tab to add current tab to Bookmarks") + fileprivate static let PreviewActionAddToReadingList = NSLocalizedString("Add to Reading List", tableName: "3DTouchActions", comment: "Label for preview action on Tab Tray Tab to add current tab to Reading List") + fileprivate static let PreviewActionCopyURL = NSLocalizedString("Copy URL", tableName: "3DTouchActions", comment: "Label for preview action on Tab Tray Tab to copy the URL of the current tab to clipboard") + fileprivate static let PreviewActionCloseTab = NSLocalizedString("Close Tab", tableName: "3DTouchActions", comment: "Label for preview action on Tab Tray Tab to close the current tab") + + weak var tab: Tab? + + fileprivate weak var delegate: TabPeekDelegate? + fileprivate var clientPicker: UINavigationController? + fileprivate var isBookmarked: Bool = false + fileprivate var isInReadingList: Bool = false + fileprivate var hasRemoteClients: Bool = false + fileprivate var ignoreURL: Bool = false + + fileprivate var screenShot: UIImageView? + fileprivate var previewAccessibilityLabel: String! + + // Preview action items. + lazy var previewActions: [UIPreviewActionItem] = { + var actions = [UIPreviewActionItem]() + + let urlIsTooLongToSave = self.tab?.urlIsTooLong ?? false + if !self.ignoreURL && !urlIsTooLongToSave { + if !self.isInReadingList { + actions.append(UIPreviewAction(title: TabPeekViewController.PreviewActionAddToReadingList, style: .default) { previewAction, viewController in + guard let tab = self.tab else { return } + _ = self.delegate?.tabPeekDidAddToReadingList(tab) + }) + } + + if !self.isBookmarked { + actions.append(UIPreviewAction(title: TabPeekViewController.PreviewActionAddToBookmarks, style: .default) { previewAction, viewController in + guard let tab = self.tab else { return } + self.delegate?.tabPeekDidAddBookmark(tab) + }) + } + if self.hasRemoteClients { + actions.append(UIPreviewAction(title: Strings.SendToDeviceTitle, style: .default) { previewAction, viewController in + guard let clientPicker = self.clientPicker else { return } + self.delegate?.tabPeekRequestsPresentationOf(clientPicker) + }) + } + // only add the copy URL action if we don't already have 3 items in our list + // as we are only allowed 4 in total and we always want to display close tab + if actions.count < 3 { + actions.append(UIPreviewAction(title: TabPeekViewController.PreviewActionCopyURL, style: .default) { previewAction, viewController in + guard let url = self.tab?.canonicalURL else { return } + UIPasteboard.general.url = url + SimpleToast().showAlertWithText(Strings.AppMenuCopyURLConfirmMessage, bottomContainer: self.view) + }) + } + } + actions.append(UIPreviewAction(title: TabPeekViewController.PreviewActionCloseTab, style: .destructive) { previewAction, viewController in + guard let tab = self.tab else { return } + self.delegate?.tabPeekDidCloseTab(tab) + }) + + return actions + }() + + init(tab: Tab, delegate: TabPeekDelegate?) { + self.tab = tab + self.delegate = delegate + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + if let webViewAccessibilityLabel = tab?.webView?.accessibilityLabel { + previewAccessibilityLabel = String(format: NSLocalizedString("Preview of %@", tableName: "3DTouchActions", comment: "Accessibility label, associated to the 3D Touch action on the current tab in the tab tray, used to display a larger preview of the tab."), webViewAccessibilityLabel) + } + // if there is no screenshot, load the URL in a web page + // otherwise just show the screenshot + setupWebView(tab?.webView) + guard let screenshot = tab?.screenshot else { return } + setupWithScreenshot(screenshot) + } + + fileprivate func setupWithScreenshot(_ screenshot: UIImage) { + let imageView = UIImageView(image: screenshot) + self.view.addSubview(imageView) + + imageView.snp.makeConstraints { make in + make.edges.equalTo(self.view) + } + + screenShot = imageView + screenShot?.accessibilityLabel = previewAccessibilityLabel + } + + fileprivate func setupWebView(_ webView: WKWebView?) { + guard let webView = webView, let url = webView.url, !isIgnoredURL(url) else { return } + let clonedWebView = WKWebView(frame: webView.frame, configuration: webView.configuration) + clonedWebView.allowsLinkPreview = false + webView.accessibilityLabel = previewAccessibilityLabel + self.view.addSubview(clonedWebView) + + clonedWebView.snp.makeConstraints { make in + make.edges.equalTo(self.view) + } + + clonedWebView.navigationDelegate = self + + clonedWebView.load(URLRequest(url: url)) + } + + func setState(withProfile browserProfile: BrowserProfile, clientPickerDelegate: ClientPickerViewControllerDelegate) { + assert(Thread.current.isMainThread) + + guard let tab = self.tab else { + return + } + + guard let displayURL = tab.url?.absoluteString, displayURL.characters.count > 0 else { + return + } + + let mainQueue = DispatchQueue.main + browserProfile.bookmarks.modelFactory >>== { + $0.isBookmarked(displayURL).uponQueue(mainQueue) { + self.isBookmarked = $0.successValue ?? false + } + } + + browserProfile.remoteClientsAndTabs.getClientGUIDs().uponQueue(mainQueue) { + guard let clientGUIDs = $0.successValue else { + return + } + + self.hasRemoteClients = !clientGUIDs.isEmpty + let clientPickerController = ClientPickerViewController() + clientPickerController.clientPickerDelegate = clientPickerDelegate + clientPickerController.profile = browserProfile + if let url = tab.url?.absoluteString { + clientPickerController.shareItem = ShareItem(url: url, title: tab.title, favicon: nil) + } + + self.clientPicker = UINavigationController(rootViewController: clientPickerController) + } + + let result = browserProfile.readingList?.getRecordWithURL(displayURL).successValue! + + self.isInReadingList = (result?.url.characters.count ?? 0) > 0 + self.ignoreURL = isIgnoredURL(displayURL) + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + screenShot?.removeFromSuperview() + screenShot = nil + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TabPrintPageRenderer.swift b/mobile/ios/Client/Frontend/Browser/TabPrintPageRenderer.swift new file mode 100644 index 0000000000..bd30759b9d --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TabPrintPageRenderer.swift @@ -0,0 +1,73 @@ +/* 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/. */ + +import Foundation + +private struct PrintedPageUX { + static let PageInsets = CGFloat(36.0) + static let PageTextFont = DynamicFontHelper.defaultHelper.DefaultSmallFont + static let PageMarginScale = CGFloat(0.5) +} + +class TabPrintPageRenderer: UIPrintPageRenderer { + fileprivate weak var tab: Tab? + let textAttributes = [NSFontAttributeName: PrintedPageUX.PageTextFont] + let dateString: String + + required init(tab: Tab) { + self.tab = tab + let dateFormatter = DateFormatter() + dateFormatter.dateStyle = .short + dateFormatter.timeStyle = .short + self.dateString = dateFormatter.string(from: Date()) + + super.init() + + self.footerHeight = PrintedPageUX.PageMarginScale * PrintedPageUX.PageInsets + self.headerHeight = PrintedPageUX.PageMarginScale * PrintedPageUX.PageInsets + + if let tab = self.tab { + let formatter = tab.webView!.viewPrintFormatter() + formatter.perPageContentInsets = UIEdgeInsets(top: PrintedPageUX.PageInsets, left: PrintedPageUX.PageInsets, bottom: PrintedPageUX.PageInsets, right: PrintedPageUX.PageInsets) + addPrintFormatter(formatter, startingAtPageAt: 0) + } + } + + override func drawFooterForPage(at pageIndex: Int, in headerRect: CGRect) { + let headerInsets = UIEdgeInsets(top: headerRect.minY, left: PrintedPageUX.PageInsets, bottom: paperRect.maxY - headerRect.maxY, right: PrintedPageUX.PageInsets) + let headerRect = UIEdgeInsetsInsetRect(paperRect, headerInsets) + + // url on left + self.drawTextAtPoint(tab!.url?.displayURL?.absoluteString ?? "", rect: headerRect, onLeft: true) + + // page number on right + let pageNumberString = "\(pageIndex + 1)" + self.drawTextAtPoint(pageNumberString, rect: headerRect, onLeft: false) + } + + override func drawHeaderForPage(at pageIndex: Int, in headerRect: CGRect) { + let headerInsets = UIEdgeInsets(top: headerRect.minY, left: PrintedPageUX.PageInsets, bottom: paperRect.maxY - headerRect.maxY, right: PrintedPageUX.PageInsets) + let headerRect = UIEdgeInsetsInsetRect(paperRect, headerInsets) + + // page title on left + self.drawTextAtPoint(tab!.displayTitle, rect: headerRect, onLeft: true) + + // date on right + self.drawTextAtPoint(dateString, rect: headerRect, onLeft: false) + } + + func drawTextAtPoint(_ text: String, rect: CGRect, onLeft: Bool) { + let size = text.size(attributes: textAttributes) + let x, y: CGFloat + if onLeft { + x = rect.minX + y = rect.midY - size.height / 2 + } else { + x = rect.maxX - size.width + y = rect.midY - size.height / 2 + } + text.draw(at: CGPoint(x: x, y: y), withAttributes: textAttributes) + } + +} diff --git a/mobile/ios/Client/Frontend/Browser/TabScrollController.swift b/mobile/ios/Client/Frontend/Browser/TabScrollController.swift new file mode 100644 index 0000000000..9f7f7f8bc9 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TabScrollController.swift @@ -0,0 +1,344 @@ +/* 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/. */ + +import UIKit +import SnapKit + +private let ToolbarBaseAnimationDuration: CGFloat = 0.2 + +class TabScrollingController: NSObject { + enum ScrollDirection { + case up + case down + } + + enum ToolbarState { + case collapsed + case visible + case animating + } + + weak var tab: Tab? { + willSet { + self.scrollView?.delegate = nil + self.scrollView?.removeGestureRecognizer(panGesture) + } + + didSet { + self.scrollView?.addGestureRecognizer(panGesture) + scrollView?.delegate = self + } + } + + // Constraint-based animation is causing PDF docs to flicker. This is used to bypass this animation. + var isTabShowingPDF: Bool { + return (tab?.mimeType ?? "") == MimeType.PDF.rawValue + } + + weak var header: UIView? + weak var footer: UIView? + weak var urlBar: URLBarView? + weak var snackBars: UIView? + weak var webViewContainerToolbar: UIView? + + var footerBottomConstraint: Constraint? + var headerTopConstraint: Constraint? + var toolbarsShowing: Bool { return headerTopOffset == 0 } + + fileprivate var isZoomedOut: Bool = false + fileprivate var lastZoomedScale: CGFloat = 0 + fileprivate var isUserZoom: Bool = false + + fileprivate var headerTopOffset: CGFloat = 0 { + didSet { + headerTopConstraint?.update(offset: headerTopOffset) + header?.superview?.setNeedsLayout() + } + } + + fileprivate var footerBottomOffset: CGFloat = 0 { + didSet { + footerBottomConstraint?.update(offset: footerBottomOffset) + footer?.superview?.setNeedsLayout() + } + } + + fileprivate lazy var panGesture: UIPanGestureRecognizer = { + let panGesture = UIPanGestureRecognizer(target: self, action: #selector(TabScrollingController.handlePan(_:))) + panGesture.maximumNumberOfTouches = 1 + panGesture.delegate = self + return panGesture + }() + + fileprivate var scrollView: UIScrollView? { return tab?.webView?.scrollView } + fileprivate var contentOffset: CGPoint { return scrollView?.contentOffset ?? CGPoint.zero } + fileprivate var contentSize: CGSize { return scrollView?.contentSize ?? CGSize.zero } + fileprivate var scrollViewHeight: CGFloat { return scrollView?.frame.height ?? 0 } + fileprivate var topScrollHeight: CGFloat { return header?.frame.height ?? 0 } + fileprivate var bottomScrollHeight: CGFloat { return footer?.frame.height ?? 0 } + fileprivate var snackBarsFrame: CGRect { return snackBars?.frame ?? CGRect.zero } + + fileprivate var lastContentOffset: CGFloat = 0 + fileprivate var scrollDirection: ScrollDirection = .down + fileprivate var toolbarState: ToolbarState = .visible + + override init() { + super.init() + } + + func showToolbars(animated: Bool, completion: ((_ finished: Bool) -> Void)? = nil) { + if toolbarState == .visible { + completion?(true) + return + } + toolbarState = .visible + let durationRatio = abs(headerTopOffset / topScrollHeight) + let actualDuration = TimeInterval(ToolbarBaseAnimationDuration * durationRatio) + self.animateToolbarsWithOffsets( + animated, + duration: actualDuration, + headerOffset: 0, + footerOffset: 0, + alpha: 1, + completion: completion) + } + + func hideToolbars(animated: Bool, completion: ((_ finished: Bool) -> Void)? = nil) { + if toolbarState == .collapsed { + completion?(true) + return + } + toolbarState = .collapsed + let durationRatio = abs((topScrollHeight + headerTopOffset) / topScrollHeight) + let actualDuration = TimeInterval(ToolbarBaseAnimationDuration * durationRatio) + self.animateToolbarsWithOffsets( + animated, + duration: actualDuration, + headerOffset: -topScrollHeight, + footerOffset: bottomScrollHeight, + alpha: 0, + completion: completion) + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { + if keyPath == "contentSize" { + if !checkScrollHeightIsLargeEnoughForScrolling() && !toolbarsShowing { + showToolbars(animated: true, completion: nil) + } + } + } + + func updateMinimumZoom() { + guard let scrollView = scrollView else { + return + } + self.isZoomedOut = roundNum(scrollView.zoomScale) == roundNum(scrollView.minimumZoomScale) + self.lastZoomedScale = self.isZoomedOut ? 0 : scrollView.zoomScale + } + + func setMinimumZoom() { + guard let scrollView = scrollView else { + return + } + if self.isZoomedOut && roundNum(scrollView.zoomScale) != roundNum(scrollView.minimumZoomScale) { + scrollView.zoomScale = scrollView.minimumZoomScale + } + } + + func resetZoomState() { + self.isZoomedOut = false + self.lastZoomedScale = 0 + } + + fileprivate func roundNum(_ num: CGFloat) -> CGFloat { + return round(100 * num) / 100 + } + +} + +private extension TabScrollingController { + func tabIsLoading() -> Bool { + return tab?.loading ?? true + } + + func isBouncingAtBottom() -> Bool { + guard let scrollView = scrollView else { return false } + return scrollView.contentOffset.y > (scrollView.contentSize.height - scrollView.frame.size.height) && scrollView.contentSize.height > scrollView.frame.size.height + } + + @objc func handlePan(_ gesture: UIPanGestureRecognizer) { + if tabIsLoading() { + return + } + + if let containerView = scrollView?.superview { + let translation = gesture.translation(in: containerView) + let delta = lastContentOffset - translation.y + + if delta > 0 { + scrollDirection = .down + } else if delta < 0 { + scrollDirection = .up + } + + lastContentOffset = translation.y + if checkRubberbandingForDelta(delta) && checkScrollHeightIsLargeEnoughForScrolling() { + let bottomIsNotRubberbanding = contentOffset.y + scrollViewHeight < contentSize.height + let topIsRubberbanding = contentOffset.y <= 0 + if isTabShowingPDF || ((toolbarState != .collapsed || topIsRubberbanding) && bottomIsNotRubberbanding) { + scrollWithDelta(delta) + } + + if headerTopOffset == -topScrollHeight && footerBottomOffset == bottomScrollHeight { + toolbarState = .collapsed + } else if headerTopOffset == 0 { + toolbarState = .visible + } else { + toolbarState = .animating + } + } + + if gesture.state == .ended || gesture.state == .cancelled { + lastContentOffset = 0 + } + + showOrHideWebViewContainerToolbar() + } + } + + func checkRubberbandingForDelta(_ delta: CGFloat) -> Bool { + return !((delta < 0 && contentOffset.y + scrollViewHeight > contentSize.height && + scrollViewHeight < contentSize.height) || + contentOffset.y < delta) + } + + func scrollWithDelta(_ delta: CGFloat) { + if scrollViewHeight >= contentSize.height { + return + } + + var updatedOffset = headerTopOffset - delta + headerTopOffset = clamp(updatedOffset, min: -topScrollHeight, max: 0) + if isHeaderDisplayedForGivenOffset(updatedOffset) { + scrollView?.contentOffset = CGPoint(x: contentOffset.x, y: contentOffset.y - delta) + } + + updatedOffset = footerBottomOffset + delta + footerBottomOffset = clamp(updatedOffset, min: 0, max: bottomScrollHeight) + + let alpha = 1 - abs(headerTopOffset / topScrollHeight) + urlBar?.updateAlphaForSubviews(alpha) + } + + func isHeaderDisplayedForGivenOffset(_ offset: CGFloat) -> Bool { + return offset > -topScrollHeight && offset < 0 + } + + func clamp(_ y: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat { + if y >= max { + return max + } else if y <= min { + return min + } + return y + } + + func animateToolbarsWithOffsets(_ animated: Bool, duration: TimeInterval, headerOffset: CGFloat, footerOffset: CGFloat, alpha: CGFloat, completion: ((_ finished: Bool) -> Void)?) { + guard let scrollView = scrollView else { return } + let initialContentOffset = scrollView.contentOffset + + // If this function is used to fully animate the toolbar from hidden to shown, keep the page from scrolling by adjusting contentOffset, + // Otherwise when the toolbar is hidden and a link navigated, showing the toolbar will scroll the page and + // produce a ~50px page jumping effect in response to tap navigations. + let isShownFromHidden = headerTopOffset == -topScrollHeight && headerOffset == 0 + + let animation: () -> Void = { + if isShownFromHidden { + scrollView.contentOffset = CGPoint(x: initialContentOffset.x, y: initialContentOffset.y + self.topScrollHeight) + } + self.headerTopOffset = headerOffset + self.footerBottomOffset = footerOffset + self.urlBar?.updateAlphaForSubviews(alpha) + self.header?.superview?.layoutIfNeeded() + } + + if animated { + UIView.animate(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: animation, completion: completion) + } else { + animation() + completion?(true) + } + } + + func checkScrollHeightIsLargeEnoughForScrolling() -> Bool { + return (UIScreen.main.bounds.size.height + 2 * UIConstants.ToolbarHeight) < scrollView?.contentSize.height ?? 0 + } + + func showOrHideWebViewContainerToolbar() { + if contentOffset.y >= webViewContainerToolbar?.frame.height ?? 0 { + webViewContainerToolbar?.isHidden = true + } else { + webViewContainerToolbar?.isHidden = false + } + } +} + +extension TabScrollingController: UIGestureRecognizerDelegate { + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, + shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + return true + } +} + +extension TabScrollingController: UIScrollViewDelegate { + func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { + if tabIsLoading() || isBouncingAtBottom() { + return + } + + if (decelerate || (toolbarState == .animating && !decelerate)) && checkScrollHeightIsLargeEnoughForScrolling() { + if scrollDirection == .up { + showToolbars(animated: !isTabShowingPDF) + } else if scrollDirection == .down { + hideToolbars(animated: !isTabShowingPDF) + } + } + } + + func scrollViewDidZoom(_ scrollView: UIScrollView) { + // Only mess with the zoom level if the user did not initate the zoom via a zoom gesture + if self.isUserZoom { + return + } + + //scrollViewDidZoom will be called multiple times when a rotation happens. + // In that case ALWAYS reset to the minimum zoom level if the previous state was zoomed out (isZoomedOut=true) + if isZoomedOut { + scrollView.zoomScale = scrollView.minimumZoomScale + } else if roundNum(scrollView.zoomScale) > roundNum(self.lastZoomedScale) && self.lastZoomedScale != 0 { + //When we have manually zoomed in we want to preserve that scale. + //But sometimes when we rotate a larger zoomScale is appled. In that case apply the lastZoomedScale + scrollView.zoomScale = self.lastZoomedScale + } + } + + func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) { + self.isUserZoom = true + } + + func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) { + self.isUserZoom = false + showOrHideWebViewContainerToolbar() + } + + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + showOrHideWebViewContainerToolbar() + } + + func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { + showToolbars(animated: true) + webViewContainerToolbar?.isHidden = false + return true + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TabToolbar.swift b/mobile/ios/Client/Frontend/Browser/TabToolbar.swift new file mode 100644 index 0000000000..0372245411 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TabToolbar.swift @@ -0,0 +1,315 @@ +/* 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/. */ + +import Foundation +import UIKit +import SnapKit +import Shared +import XCGLogger + +private let log = Logger.browserLogger + +protocol TabToolbarProtocol: class { + weak var tabToolbarDelegate: TabToolbarDelegate? { get set } + var tabsButton: TabsButton { get } + var menuButton: ToolbarButton { get } + var forwardButton: ToolbarButton { get } + var backButton: ToolbarButton { get } + var stopReloadButton: ToolbarButton { get } + var actionButtons: [Themeable & UIButton] { get } + + func updateBackStatus(_ canGoBack: Bool) + func updateForwardStatus(_ canGoForward: Bool) + func updateReloadStatus(_ isLoading: Bool) + func updatePageStatus(_ isWebPage: Bool) + func updateTabCount(_ count: Int, animated: Bool) +} + +protocol TabToolbarDelegate: class { + func tabToolbarDidPressBack(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidPressForward(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidLongPressBack(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidLongPressForward(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidPressReload(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidLongPressReload(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidPressStop(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidPressMenu(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidPressTabs(_ tabToolbar: TabToolbarProtocol, button: UIButton) + func tabToolbarDidLongPressTabs(_ tabToolbar: TabToolbarProtocol, button: UIButton) +} + +@objc +open class TabToolbarHelper: NSObject { + let toolbar: TabToolbarProtocol + + let ImageReload = UIImage.templateImageNamed("nav-refresh") + let ImageStop = UIImage.templateImageNamed("nav-stop") + + var loading: Bool = false { + didSet { + if loading { + toolbar.stopReloadButton.setImage(ImageStop, for: .normal) + toolbar.stopReloadButton.accessibilityLabel = NSLocalizedString("Stop", comment: "Accessibility Label for the tab toolbar Stop button") + } else { + toolbar.stopReloadButton.setImage(ImageReload, for: .normal) + toolbar.stopReloadButton.accessibilityLabel = NSLocalizedString("Reload", comment: "Accessibility Label for the tab toolbar Reload button") + } + } + } + + fileprivate func setTheme(theme: String, forButtons buttons: [Themeable]) { + buttons.forEach { $0.applyTheme(theme) } + } + + init(toolbar: TabToolbarProtocol) { + self.toolbar = toolbar + super.init() + + toolbar.backButton.setImage(UIImage.templateImageNamed("nav-back"), for: .normal) + toolbar.backButton.accessibilityLabel = NSLocalizedString("Back", comment: "Accessibility label for the Back button in the tab toolbar.") + let longPressGestureBackButton = UILongPressGestureRecognizer(target: self, action: #selector(TabToolbarHelper.SELdidLongPressBack(_:))) + toolbar.backButton.addGestureRecognizer(longPressGestureBackButton) + toolbar.backButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickBack), for: UIControlEvents.touchUpInside) + + toolbar.forwardButton.setImage(UIImage.templateImageNamed("nav-forward"), for: .normal) + toolbar.forwardButton.accessibilityLabel = NSLocalizedString("Forward", comment: "Accessibility Label for the tab toolbar Forward button") + let longPressGestureForwardButton = UILongPressGestureRecognizer(target: self, action: #selector(TabToolbarHelper.SELdidLongPressForward(_:))) + toolbar.forwardButton.addGestureRecognizer(longPressGestureForwardButton) + toolbar.forwardButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickForward), for: UIControlEvents.touchUpInside) + + toolbar.stopReloadButton.setImage(UIImage.templateImageNamed("nav-refresh"), for: .normal) + toolbar.stopReloadButton.accessibilityLabel = NSLocalizedString("Reload", comment: "Accessibility Label for the tab toolbar Reload button") + let longPressGestureStopReloadButton = UILongPressGestureRecognizer(target: self, action: #selector(TabToolbarHelper.SELdidLongPressStopReload(_:))) + toolbar.stopReloadButton.addGestureRecognizer(longPressGestureStopReloadButton) + toolbar.stopReloadButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickStopReload), for: UIControlEvents.touchUpInside) + + toolbar.tabsButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickTabs), for: .touchUpInside) + let longPressGestureTabsButton = UILongPressGestureRecognizer(target: self, action: #selector(TabToolbarHelper.SELdidLongPressTabs(_:))) + toolbar.tabsButton.addGestureRecognizer(longPressGestureTabsButton) + + toolbar.menuButton.contentMode = UIViewContentMode.center + toolbar.menuButton.setImage(UIImage.templateImageNamed("nav-menu"), for: .normal) + toolbar.menuButton.accessibilityLabel = Strings.AppMenuButtonAccessibilityLabel + toolbar.menuButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickMenu), for: UIControlEvents.touchUpInside) + toolbar.menuButton.accessibilityIdentifier = "TabToolbar.menuButton" + setTheme(theme: Theme.NormalMode, forButtons: toolbar.actionButtons) + } + + func SELdidClickBack() { + toolbar.tabToolbarDelegate?.tabToolbarDidPressBack(toolbar, button: toolbar.backButton) + } + + func SELdidLongPressBack(_ recognizer: UILongPressGestureRecognizer) { + if recognizer.state == UIGestureRecognizerState.began { + toolbar.tabToolbarDelegate?.tabToolbarDidLongPressBack(toolbar, button: toolbar.backButton) + } + } + + func SELdidClickTabs() { + toolbar.tabToolbarDelegate?.tabToolbarDidPressTabs(toolbar, button: toolbar.tabsButton) + } + + func SELdidLongPressTabs(_ recognizer: UILongPressGestureRecognizer) { + toolbar.tabToolbarDelegate?.tabToolbarDidLongPressTabs(toolbar, button: toolbar.tabsButton) + } + + func SELdidClickForward() { + toolbar.tabToolbarDelegate?.tabToolbarDidPressForward(toolbar, button: toolbar.forwardButton) + } + + func SELdidLongPressForward(_ recognizer: UILongPressGestureRecognizer) { + if recognizer.state == UIGestureRecognizerState.began { + toolbar.tabToolbarDelegate?.tabToolbarDidLongPressForward(toolbar, button: toolbar.forwardButton) + } + } + + func SELdidClickMenu() { + toolbar.tabToolbarDelegate?.tabToolbarDidPressMenu(toolbar, button: toolbar.menuButton) + } + + func SELdidClickStopReload() { + if loading { + toolbar.tabToolbarDelegate?.tabToolbarDidPressStop(toolbar, button: toolbar.stopReloadButton) + } else { + toolbar.tabToolbarDelegate?.tabToolbarDidPressReload(toolbar, button: toolbar.stopReloadButton) + } + } + + func SELdidLongPressStopReload(_ recognizer: UILongPressGestureRecognizer) { + if recognizer.state == UIGestureRecognizerState.began && !loading { + toolbar.tabToolbarDelegate?.tabToolbarDidLongPressReload(toolbar, button: toolbar.stopReloadButton) + } + } + + func updateReloadStatus(_ isLoading: Bool) { + loading = isLoading + } +} + +class ToolbarButton: UIButton { + static let Themes: [String: Theme] = { + var themes = [String: Theme]() + var theme = Theme() + theme.buttonTintColor = UIColor(rgb: 0xd2d2d4) + theme.highlightButtonColor = UIColor(rgb: 0xAC39FF) + theme.disabledButtonColor = UIColor.gray + themes[Theme.PrivateMode] = theme + + theme = Theme() + theme.buttonTintColor = UIColor(rgb: 0x272727) + theme.highlightButtonColor = UIColor(rgb: 0x00A2FE) + theme.disabledButtonColor = UIColor.lightGray + themes[Theme.NormalMode] = theme + + return themes + }() + + var selectedTintColor: UIColor! + var unselectedTintColor: UIColor! + var disabledTintColor: UIColor! + + override init(frame: CGRect) { + super.init(frame: frame) + adjustsImageWhenHighlighted = false + selectedTintColor = tintColor + unselectedTintColor = tintColor + disabledTintColor = UIColor.gray + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open var isHighlighted: Bool { + didSet { + self.tintColor = isHighlighted ? selectedTintColor : unselectedTintColor + } + } + + override open var isEnabled: Bool { + didSet { + self.tintColor = isEnabled ? unselectedTintColor : disabledTintColor + } + } + + override var tintColor: UIColor! { + didSet { + self.imageView?.tintColor = self.tintColor + } + } + +} + +extension ToolbarButton: Themeable { + func applyTheme(_ themeName: String) { + guard let theme = ToolbarButton.Themes[themeName] else { + log.error("Unable to apply unknown theme \(themeName)") + return + } + selectedTintColor = theme.highlightButtonColor + disabledTintColor = theme.disabledButtonColor + unselectedTintColor = theme.buttonTintColor + tintColor = isEnabled ? unselectedTintColor : disabledTintColor + imageView?.tintColor = tintColor + } +} + +class TabToolbar: Toolbar, TabToolbarProtocol { + weak var tabToolbarDelegate: TabToolbarDelegate? + + let tabsButton: TabsButton + let menuButton: ToolbarButton + let forwardButton: ToolbarButton + let backButton: ToolbarButton + let stopReloadButton: ToolbarButton + let actionButtons: [Themeable & UIButton] + + var helper: TabToolbarHelper? + + static let Themes: [String: Theme] = { + var themes = [String: Theme]() + var theme = Theme() + theme.backgroundColor = UIColor(rgb: 0x38383D) + themes[Theme.PrivateMode] = theme + + theme = Theme() + theme.backgroundColor = UIConstants.AppBackgroundColor + themes[Theme.NormalMode] = theme + + return themes + }() + + // This has to be here since init() calls it + fileprivate override init(frame: CGRect) { + // And these have to be initialized in here or the compiler will get angry + backButton = ToolbarButton() + backButton.accessibilityIdentifier = "TabToolbar.backButton" + forwardButton = ToolbarButton() + forwardButton.accessibilityIdentifier = "TabToolbar.forwardButton" + stopReloadButton = ToolbarButton() + stopReloadButton.accessibilityIdentifier = "TabToolbar.stopReloadButton" + tabsButton = TabsButton() + tabsButton.accessibilityIdentifier = "TabToolbar.tabsButton" + menuButton = ToolbarButton() + menuButton.accessibilityIdentifier = "TabToolbar.menuButton" + actionButtons = [backButton, forwardButton, stopReloadButton, tabsButton, menuButton] + + super.init(frame: frame) + + helper = TabToolbarHelper(toolbar: self) + addButtons(actionButtons) + + accessibilityNavigationStyle = .combined + accessibilityLabel = NSLocalizedString("Navigation Toolbar", comment: "Accessibility label for the navigation toolbar displayed at the bottom of the screen.") + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func updateBackStatus(_ canGoBack: Bool) { + backButton.isEnabled = canGoBack + } + + func updateForwardStatus(_ canGoForward: Bool) { + forwardButton.isEnabled = canGoForward + } + + func updateReloadStatus(_ isLoading: Bool) { + helper?.updateReloadStatus(isLoading) + } + + func updatePageStatus(_ isWebPage: Bool) { + stopReloadButton.isEnabled = isWebPage + } + + func updateTabCount(_ count: Int, animated: Bool) { + tabsButton.updateTabCount(count, animated: animated) + } + + override func draw(_ rect: CGRect) { + if let context = UIGraphicsGetCurrentContext() { + drawLine(context, start: CGPoint(x: 0, y: 0), end: CGPoint(x: frame.width, y: 0)) + } + } + + fileprivate func drawLine(_ context: CGContext, start: CGPoint, end: CGPoint) { + context.setStrokeColor(UIColor.black.withAlphaComponent(0.05).cgColor) + context.setLineWidth(2) + context.move(to: CGPoint(x: start.x, y: start.y)) + context.addLine(to: CGPoint(x: end.x, y: end.y)) + context.strokePath() + } +} + +extension TabToolbar: Themeable { + func applyTheme(_ themeName: String) { + guard let theme = TabToolbar.Themes[themeName] else { + log.error("Unable to apply unknown theme \(themeName)") + return + } + backgroundColor = theme.backgroundColor! + helper?.setTheme(theme: themeName, forButtons: actionButtons) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TabTrayButtonExtensions.swift b/mobile/ios/Client/Frontend/Browser/TabTrayButtonExtensions.swift new file mode 100644 index 0000000000..6960eb210c --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TabTrayButtonExtensions.swift @@ -0,0 +1,46 @@ +/* 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/. */ + +import UIKit + +class PrivateModeButton: ToggleButton { + var light: Bool = false + + override init(frame: CGRect) { + super.init(frame: frame) + self.accessibilityLabel = PrivateModeStrings.toggleAccessibilityLabel + self.accessibilityHint = PrivateModeStrings.toggleAccessibilityHint + let maskImage = UIImage(named: "smallPrivateMask")?.withRenderingMode(.alwaysTemplate) + self.setImage(maskImage, for: UIControlState()) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func styleForMode(privateMode isPrivate: Bool) { + self.tintColor = isPrivate ? UIColor(rgb: 0xf9f9fa) : UIColor(rgb: 0x272727) + self.imageView?.tintColor = self.tintColor + self.isSelected = isPrivate + self.accessibilityValue = isPrivate ? PrivateModeStrings.toggleAccessibilityValueOn : PrivateModeStrings.toggleAccessibilityValueOff + } +} + +extension UIButton { + static func newTabButton() -> UIButton { + let newTab = UIButton() + newTab.setImage(UIImage.templateImageNamed("quick_action_new_tab"), for: .normal) + newTab.accessibilityLabel = NSLocalizedString("New Tab", comment: "Accessibility label for the New Tab button in the tab toolbar.") + return newTab + } +} + +extension TabsButton { + static func tabTrayButton() -> TabsButton { + let tabsButton = TabsButton() + tabsButton.countLabel.text = "0" + tabsButton.accessibilityLabel = NSLocalizedString("Show Tabs", comment: "Accessibility Label for the tabs button in the tab toolbar") + return tabsButton + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TabTrayController.swift b/mobile/ios/Client/Frontend/Browser/TabTrayController.swift new file mode 100644 index 0000000000..10d32be686 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TabTrayController.swift @@ -0,0 +1,1061 @@ +/* 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/. */ + +import Foundation +import UIKit +import SnapKit +import Storage +import ReadingList +import Shared + +struct TabTrayControllerUX { + static let CornerRadius = CGFloat(6.0) + static let BackgroundColor = UIConstants.TabTrayBG + static let CellBackgroundColor = UIConstants.TabTrayBG + static let TextBoxHeight = CGFloat(32.0) + static let FaviconSize = CGFloat(20) + static let Margin = CGFloat(15) + static let ToolbarBarTintColor = UIColor.black + static let ToolbarButtonOffset = CGFloat(10.0) + static let CloseButtonSize = CGFloat(18.0) + static let CloseButtonMargin = CGFloat(6.0) + static let CloseButtonEdgeInset = CGFloat(10) + + static let NumberOfColumnsThin = 1 + static let NumberOfColumnsWide = 3 + static let CompactNumberOfColumnsThin = 2 + + static let MenuFixedWidth: CGFloat = 320 +} + +struct LightTabCellUX { + static let TabTitleTextColor = UIColor.black +} + +struct DarkTabCellUX { + static let TabTitleTextColor = UIColor.white +} + +protocol TabCellDelegate: class { + func tabCellDidClose(_ cell: TabCell) +} + +class TabCell: UICollectionViewCell { + enum Style { + case light + case dark + } + + static let Identifier = "TabCellIdentifier" + static let BorderWidth: CGFloat = 3 + + var style: Style = .light { + didSet { + applyStyle(style) + } + } + + let backgroundHolder = UIView() + let screenshotView = UIImageViewAligned() + let titleText: UILabel + let favicon: UIImageView = UIImageView() + let closeButton: UIButton + + var title: UIVisualEffectView! + var animator: SwipeAnimator! + + weak var delegate: TabCellDelegate? + + // Changes depending on whether we're full-screen or not. + var margin = CGFloat(0) + + override init(frame: CGRect) { + self.backgroundHolder.backgroundColor = UIColor.white + self.backgroundHolder.layer.cornerRadius = TabTrayControllerUX.CornerRadius + self.backgroundHolder.clipsToBounds = true + self.backgroundHolder.backgroundColor = TabTrayControllerUX.CellBackgroundColor + + self.screenshotView.contentMode = UIViewContentMode.scaleAspectFill + self.screenshotView.clipsToBounds = true + self.screenshotView.isUserInteractionEnabled = false + self.screenshotView.alignLeft = true + self.screenshotView.alignTop = true + screenshotView.backgroundColor = UIConstants.AppBackgroundColor + + self.favicon.backgroundColor = UIColor.clear + self.favicon.layer.cornerRadius = 2.0 + self.favicon.layer.masksToBounds = true + + self.titleText = UILabel() + self.titleText.textAlignment = NSTextAlignment.left + self.titleText.isUserInteractionEnabled = false + self.titleText.numberOfLines = 1 + self.titleText.font = DynamicFontHelper.defaultHelper.DefaultSmallFontBold + + self.closeButton = UIButton() + self.closeButton.setImage(UIImage.templateImageNamed("nav-stop"), for: UIControlState()) + self.closeButton.tintColor = UIColor.lightGray + self.closeButton.imageEdgeInsets = UIEdgeInsets(equalInset: TabTrayControllerUX.CloseButtonEdgeInset) + + super.init(frame: frame) + + self.animator = SwipeAnimator(animatingView: self) + self.closeButton.addTarget(self, action: #selector(TabCell.close), for: UIControlEvents.touchUpInside) + + contentView.addSubview(backgroundHolder) + backgroundHolder.addSubview(self.screenshotView) + + // Default style is light + applyStyle(style) + + self.accessibilityCustomActions = [ + UIAccessibilityCustomAction(name: NSLocalizedString("Close", comment: "Accessibility label for action denoting closing a tab in tab list (tray)"), target: self.animator, selector: #selector(SwipeAnimator.closeWithoutGesture)) + ] + } + + fileprivate func applyStyle(_ style: Style) { + self.title?.removeFromSuperview() + + let title: UIVisualEffectView + switch style { + case .light: + title = UIVisualEffectView(effect: UIBlurEffect(style: .extraLight)) + self.titleText.textColor = LightTabCellUX.TabTitleTextColor + case .dark: + title = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) + self.titleText.textColor = DarkTabCellUX.TabTitleTextColor + } + + titleText.backgroundColor = UIColor.clear + + title.contentView.addSubview(self.closeButton) + title.contentView.addSubview(self.titleText) + title.contentView.addSubview(self.favicon) + + backgroundHolder.addSubview(title) + self.title = title + } + + func setTabSelected(_ isPrivate: Bool) { + // This creates a border around a tabcell. Using the shadow craetes a border _outside_ of the tab frame. + layer.shadowColor = (isPrivate ? UIConstants.PrivateModePurple : UIConstants.SystemBlueColor).cgColor + layer.shadowOpacity = 1 + layer.shadowRadius = 0 // A 0 radius creates a solid border instead of a gradient blur + layer.masksToBounds = false + // create a frame that is "BorderWidth" size bigger than the cell + layer.shadowOffset = CGSize(width: -TabCell.BorderWidth, height: -TabCell.BorderWidth) + let shadowPath = CGRect(x: 0, y: 0, width: layer.frame.width + (TabCell.BorderWidth * 2), height: layer.frame.height + (TabCell.BorderWidth * 2)) + layer.shadowPath = UIBezierPath(roundedRect: shadowPath, cornerRadius: TabTrayControllerUX.CornerRadius+TabCell.BorderWidth).cgPath + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + let w = frame.width + let h = frame.height + backgroundHolder.frame = CGRect(x: margin, + y: margin, + width: w, + height: h) + screenshotView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: backgroundHolder.frame.size) + + title.frame = CGRect(x: 0, + y: 0, + width: backgroundHolder.frame.width, + height: TabTrayControllerUX.TextBoxHeight) + + favicon.frame = CGRect(x: 6, + y: (TabTrayControllerUX.TextBoxHeight - TabTrayControllerUX.FaviconSize)/2, + width: TabTrayControllerUX.FaviconSize, + height: TabTrayControllerUX.FaviconSize) + + let titleTextLeft = favicon.frame.origin.x + favicon.frame.width + 6 + titleText.frame = CGRect(x: titleTextLeft, + y: 0, + width: title.frame.width - titleTextLeft - margin - TabTrayControllerUX.CloseButtonSize - TabTrayControllerUX.CloseButtonMargin * 2, + height: title.frame.height) + + closeButton.snp.makeConstraints { make in + make.size.equalTo(title.snp.height) + make.trailing.centerY.equalTo(title) + } + + let top = (TabTrayControllerUX.TextBoxHeight - titleText.bounds.height) / 2.0 + titleText.frame.origin = CGPoint(x: titleText.frame.origin.x, y: max(0, top)) + let shadowPath = CGRect(x: 0, y: 0, width: layer.frame.width + (TabCell.BorderWidth * 2), height: layer.frame.height + (TabCell.BorderWidth * 2)) + layer.shadowPath = UIBezierPath(roundedRect: shadowPath, cornerRadius: TabTrayControllerUX.CornerRadius+TabCell.BorderWidth).cgPath + } + + override func prepareForReuse() { + // Reset any close animations. + backgroundHolder.transform = CGAffineTransform.identity + backgroundHolder.alpha = 1 + self.titleText.font = DynamicFontHelper.defaultHelper.DefaultSmallFontBold + layer.shadowOffset = CGSize.zero + layer.shadowPath = nil + layer.shadowOpacity = 0 + } + + override func accessibilityScroll(_ direction: UIAccessibilityScrollDirection) -> Bool { + var right: Bool + switch direction { + case .left: + right = false + case .right: + right = true + default: + return false + } + animator.close(right: right) + return true + } + + @objc + func close() { + self.animator.closeWithoutGesture() + } +} + +struct PrivateModeStrings { + static let toggleAccessibilityLabel = NSLocalizedString("Private Mode", tableName: "PrivateBrowsing", comment: "Accessibility label for toggling on/off private mode") + static let toggleAccessibilityHint = NSLocalizedString("Turns private mode on or off", tableName: "PrivateBrowsing", comment: "Accessiblity hint for toggling on/off private mode") + static let toggleAccessibilityValueOn = NSLocalizedString("On", tableName: "PrivateBrowsing", comment: "Toggled ON accessibility value") + static let toggleAccessibilityValueOff = NSLocalizedString("Off", tableName: "PrivateBrowsing", comment: "Toggled OFF accessibility value") +} + +protocol TabTrayDelegate: class { + func tabTrayDidDismiss(_ tabTray: TabTrayController) + func tabTrayDidAddBookmark(_ tab: Tab) + func tabTrayDidAddToReadingList(_ tab: Tab) -> ReadingListClientRecord? + func tabTrayRequestsPresentationOf(_ viewController: UIViewController) +} + +class TabTrayController: UIViewController { + let tabManager: TabManager + let profile: Profile + weak var delegate: TabTrayDelegate? + + var collectionView: UICollectionView! + var draggedCell: TabCell? + var dragOffset: CGPoint = CGPoint.zero + lazy var toolbar: TrayToolbar = { + let toolbar = TrayToolbar() + toolbar.addTabButton.addTarget(self, action: #selector(TabTrayController.didClickAddTab), for: .touchUpInside) + toolbar.maskButton.addTarget(self, action: #selector(TabTrayController.didTogglePrivateMode), for: .touchUpInside) + toolbar.deleteButton.addTarget(self, action: #selector(TabTrayController.didTapDelete(_:)), for: .touchUpInside) + return toolbar + }() + + fileprivate(set) internal var privateMode: Bool = false { + didSet { + tabDataSource.tabs = tabsToDisplay + toolbar.styleToolbar(privateMode) + collectionView?.reloadData() + } + } + + fileprivate var tabsToDisplay: [Tab] { + return self.privateMode ? tabManager.privateTabs : tabManager.normalTabs + } + + fileprivate lazy var emptyPrivateTabsView: EmptyPrivateTabsView = { + let emptyView = EmptyPrivateTabsView() + emptyView.learnMoreButton.addTarget(self, action: #selector(TabTrayController.didTapLearnMore), for: UIControlEvents.touchUpInside) + return emptyView + }() + + fileprivate lazy var tabDataSource: TabManagerDataSource = { + return TabManagerDataSource(tabs: self.tabsToDisplay, cellDelegate: self, tabManager: self.tabManager) + }() + + fileprivate lazy var tabLayoutDelegate: TabLayoutDelegate = { + let delegate = TabLayoutDelegate(profile: self.profile, traitCollection: self.traitCollection) + delegate.tabSelectionDelegate = self + return delegate + }() + + init(tabManager: TabManager, profile: Profile) { + self.tabManager = tabManager + self.profile = profile + super.init(nibName: nil, bundle: nil) + + tabManager.addDelegate(self) + } + + convenience init(tabManager: TabManager, profile: Profile, tabTrayDelegate: TabTrayDelegate) { + self.init(tabManager: tabManager, profile: profile) + self.delegate = tabTrayDelegate + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + self.tabManager.removeDelegate(self) + } + + func dynamicFontChanged(_ notification: Notification) { + guard notification.name == NotificationDynamicFontChanged else { return } + + self.collectionView.reloadData() + } + +// MARK: View Controller Callbacks + override func viewDidLoad() { + super.viewDidLoad() + + view.accessibilityLabel = NSLocalizedString("Tabs Tray", comment: "Accessibility label for the Tabs Tray view.") + + collectionView = UICollectionView(frame: view.frame, collectionViewLayout: UICollectionViewFlowLayout()) + + collectionView.dataSource = tabDataSource + collectionView.delegate = tabLayoutDelegate + collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: UIConstants.BottomToolbarHeight, right: 0) + collectionView.register(TabCell.self, forCellWithReuseIdentifier: TabCell.Identifier) + collectionView.backgroundColor = TabTrayControllerUX.BackgroundColor + + view.addSubview(collectionView) + view.addSubview(toolbar) + + makeConstraints() + + view.insertSubview(emptyPrivateTabsView, aboveSubview: collectionView) + emptyPrivateTabsView.snp.makeConstraints { make in + make.top.left.right.equalTo(self.collectionView) + make.bottom.equalTo(self.toolbar.snp.top) + } + + if let tab = tabManager.selectedTab, tab.isPrivate { + privateMode = true + } + + // register for previewing delegate to enable peek and pop if force touch feature available + if traitCollection.forceTouchCapability == .available { + registerForPreviewing(with: self, sourceView: view) + } + + emptyPrivateTabsView.isHidden = !privateTabsAreEmpty() + + NotificationCenter.default.addObserver(self, selector: #selector(TabTrayController.appWillResignActiveNotification), name: NSNotification.Name.UIApplicationWillResignActive, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(TabTrayController.appDidBecomeActiveNotification), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(TabTrayController.dynamicFontChanged(_:)), name: NotificationDynamicFontChanged, object: nil) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + // Update the trait collection we reference in our layout delegate + tabLayoutDelegate.traitCollection = traitCollection + self.collectionView.collectionViewLayout.invalidateLayout() + } + + fileprivate func cancelExistingGestures() { + if let visibleCells = self.collectionView.visibleCells as? [TabCell] { + for cell in visibleCells { + cell.animator.cancelExistingGestures() + } + } + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + coordinator.animate(alongsideTransition: { _ in + self.collectionView.collectionViewLayout.invalidateLayout() + }, completion: nil) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return UIStatusBarStyle.lightContent //this will need to be fixed + } + + fileprivate func makeConstraints() { + collectionView.snp.makeConstraints { make in + make.left.bottom.right.equalTo(view) + make.top.equalTo(self.topLayoutGuide.snp.bottom) + } + + toolbar.snp.makeConstraints { make in + make.left.right.bottom.equalTo(view) + make.height.equalTo(UIConstants.BottomToolbarHeight) + } + } + +// MARK: Selectors + func didClickDone() { + presentingViewController!.dismiss(animated: true, completion: nil) + } + + func didClickSettingsItem() { + assert(Thread.isMainThread, "Opening settings requires being invoked on the main thread") + + let settingsTableViewController = AppSettingsTableViewController() + settingsTableViewController.profile = profile + settingsTableViewController.tabManager = tabManager + settingsTableViewController.settingsDelegate = self + + let controller = SettingsNavigationController(rootViewController: settingsTableViewController) + controller.popoverDelegate = self + controller.modalPresentationStyle = UIModalPresentationStyle.formSheet + present(controller, animated: true, completion: nil) + } + + func didClickAddTab() { + openNewTab() + LeanPlumClient.shared.track(event: .openedNewTab, withParameters: ["Source": "Tab Tray" as AnyObject]) + } + + func didTapLearnMore() { + let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String + if let langID = Locale.preferredLanguages.first { + let learnMoreRequest = URLRequest(url: "https://support.mozilla.org/1/mobile/\(appVersion)/iOS/\(langID)/private-browsing-ios".asURL!) + openNewTab(learnMoreRequest) + } + } + + func didTogglePrivateMode() { + let scaleDownTransform = CGAffineTransform(scaleX: 0.9, y: 0.9) + + let fromView: UIView + if !privateTabsAreEmpty(), let snapshot = collectionView.snapshotView(afterScreenUpdates: false) { + snapshot.frame = collectionView.frame + view.insertSubview(snapshot, aboveSubview: collectionView) + fromView = snapshot + } else { + fromView = emptyPrivateTabsView + } + + tabManager.willSwitchTabMode() + privateMode = !privateMode + // If we are exiting private mode and we have the close private tabs option selected, make sure + // we clear out all of the private tabs + let exitingPrivateMode = !privateMode && tabManager.shouldClearPrivateTabs() + + toolbar.maskButton.setSelected(privateMode, animated: true) + collectionView.layoutSubviews() + + let toView: UIView + if !privateTabsAreEmpty(), let newSnapshot = collectionView.snapshotView(afterScreenUpdates: !exitingPrivateMode) { + emptyPrivateTabsView.isHidden = true + //when exiting private mode don't screenshot the collectionview (causes the UI to hang) + newSnapshot.frame = collectionView.frame + view.insertSubview(newSnapshot, aboveSubview: fromView) + collectionView.alpha = 0 + toView = newSnapshot + } else { + emptyPrivateTabsView.isHidden = false + toView = emptyPrivateTabsView + } + toView.alpha = 0 + toView.transform = scaleDownTransform + + UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: { () -> Void in + fromView.transform = scaleDownTransform + fromView.alpha = 0 + toView.transform = CGAffineTransform.identity + toView.alpha = 1 + }) { finished in + if fromView != self.emptyPrivateTabsView { + fromView.removeFromSuperview() + } + if toView != self.emptyPrivateTabsView { + toView.removeFromSuperview() + } + self.collectionView.alpha = 1 + } + } + + fileprivate func privateTabsAreEmpty() -> Bool { + return privateMode && tabManager.privateTabs.count == 0 + } + + func changePrivacyMode(_ isPrivate: Bool) { + if isPrivate != privateMode { + guard let _ = collectionView else { + privateMode = isPrivate + return + } + didTogglePrivateMode() + } + } + + fileprivate func openNewTab(_ request: URLRequest? = nil) { + toolbar.isUserInteractionEnabled = false + + // We're only doing one update here, but using a batch update lets us delay selecting the tab + // until after its insert animation finishes. + self.collectionView.performBatchUpdates({ _ in + _ = self.tabManager.addTab(request, isPrivate: self.privateMode) + }, completion: { finished in + // The addTab delegate method will pop to the BVC no need to do anything here. + self.toolbar.isUserInteractionEnabled = true + if finished { + if request == nil && NewTabAccessors.getNewTabPage(self.profile.prefs) == .blankPage { + if let bvc = self.navigationController?.topViewController as? BrowserViewController { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { + bvc.urlBar.tabLocationViewDidTapLocation(bvc.urlBar.locationView) + } + } + } + } + }) + } + + fileprivate func closeTabsForCurrentTray() { + tabManager.removeTabsWithUndoToast(tabsToDisplay) + self.collectionView.reloadData() + } +} + +// MARK: - App Notifications +extension TabTrayController { + func appWillResignActiveNotification() { + if privateMode { + collectionView.alpha = 0 + } + } + + func appDidBecomeActiveNotification() { + // Re-show any components that might have been hidden because they were being displayed + // as part of a private mode tab + UIView.animate(withDuration: 0.2, delay: 0, options: UIViewAnimationOptions(), animations: { + self.collectionView.alpha = 1 + }, + completion: nil) + } +} + +extension TabTrayController: TabSelectionDelegate { + func didSelectTabAtIndex(_ index: Int) { + let tab = tabsToDisplay[index] + tabManager.selectTab(tab) + _ = self.navigationController?.popViewController(animated: true) + } +} + +extension TabTrayController: PresentingModalViewControllerDelegate { + func dismissPresentedModalViewController(_ modalViewController: UIViewController, animated: Bool) { + dismiss(animated: animated, completion: { self.collectionView.reloadData() }) + } +} + +extension TabTrayController: TabManagerDelegate { + func tabManager(_ tabManager: TabManager, didSelectedTabChange selected: Tab?, previous: Tab?) { + } + + func tabManager(_ tabManager: TabManager, willAddTab tab: Tab) { + } + + func tabManager(_ tabManager: TabManager, willRemoveTab tab: Tab) { + } + + func tabManager(_ tabManager: TabManager, didAddTab tab: Tab) { + // Get the index of the added tab from it's set (private or normal) + guard let index = tabsToDisplay.index(of: tab) else { return } + if !privateTabsAreEmpty() { + emptyPrivateTabsView.isHidden = true + } + + tabDataSource.addTab(tab) + self.collectionView?.performBatchUpdates({ _ in + self.collectionView.insertItems(at: [IndexPath(item: index, section: 0)]) + }, completion: { finished in + if finished { + tabManager.selectTab(tab) + // don't pop the tab tray view controller if it is not in the foreground + if self.presentedViewController == nil { + _ = self.navigationController?.popViewController(animated: true) + } + } + }) + } + + func tabManager(_ tabManager: TabManager, didRemoveTab tab: Tab) { + // it is possible that we are removing a tab that we are not currently displaying + // through the Close All Tabs feature (which will close tabs that are not in our current privacy mode) + // check this before removing the item from the collection + let removedIndex = tabDataSource.removeTab(tab) + if removedIndex > -1 { + self.collectionView.performBatchUpdates({ + self.collectionView.deleteItems(at: [IndexPath(item: removedIndex, section: 0)]) + }, completion: { finished in + guard finished && self.privateTabsAreEmpty() else { return } + self.emptyPrivateTabsView.isHidden = false + }) + } + } + + func tabManagerDidAddTabs(_ tabManager: TabManager) { + } + + func tabManagerDidRestoreTabs(_ tabManager: TabManager) { + } + + func tabManagerDidRemoveAllTabs(_ tabManager: TabManager, toast: ButtonToast?) { + guard privateMode else { + return + } + + if let toast = toast { + view.addSubview(toast) + toast.snp.makeConstraints { make in + make.left.right.equalTo(view) + make.bottom.equalTo(toolbar.snp.top) + } + toast.showToast() + } + } +} + +extension TabTrayController: UIScrollViewAccessibilityDelegate { + func accessibilityScrollStatus(for scrollView: UIScrollView) -> String? { + var visibleCells = collectionView.visibleCells as! [TabCell] + var bounds = collectionView.bounds + bounds = bounds.offsetBy(dx: collectionView.contentInset.left, dy: collectionView.contentInset.top) + bounds.size.width -= collectionView.contentInset.left + collectionView.contentInset.right + bounds.size.height -= collectionView.contentInset.top + collectionView.contentInset.bottom + // visible cells do sometimes return also not visible cells when attempting to go past the last cell with VoiceOver right-flick gesture; so make sure we have only visible cells (yeah...) + visibleCells = visibleCells.filter { !$0.frame.intersection(bounds).isEmpty } + + let cells = visibleCells.map { self.collectionView.indexPath(for: $0)! } + let indexPaths = cells.sorted { (a: IndexPath, b: IndexPath) -> Bool in + return a.section < b.section || (a.section == b.section && a.row < b.row) + } + + if indexPaths.count == 0 { + return NSLocalizedString("No tabs", comment: "Message spoken by VoiceOver to indicate that there are no tabs in the Tabs Tray") + } + + let firstTab = indexPaths.first!.row + 1 + let lastTab = indexPaths.last!.row + 1 + let tabCount = collectionView.numberOfItems(inSection: 0) + + if firstTab == lastTab { + let format = NSLocalizedString("Tab %@ of %@", comment: "Message spoken by VoiceOver saying the position of the single currently visible tab in Tabs Tray, along with the total number of tabs. E.g. \"Tab 2 of 5\" says that tab 2 is visible (and is the only visible tab), out of 5 tabs total.") + return String(format: format, NSNumber(value: firstTab as Int), NSNumber(value: tabCount as Int)) + } else { + let format = NSLocalizedString("Tabs %@ to %@ of %@", comment: "Message spoken by VoiceOver saying the range of tabs that are currently visible in Tabs Tray, along with the total number of tabs. E.g. \"Tabs 8 to 10 of 15\" says tabs 8, 9 and 10 are visible, out of 15 tabs total.") + return String(format: format, NSNumber(value: firstTab as Int), NSNumber(value: lastTab as Int), NSNumber(value: tabCount as Int)) + } + } +} + +extension TabTrayController: SwipeAnimatorDelegate { + func swipeAnimator(_ animator: SwipeAnimator, viewWillExitContainerBounds: UIView) { + let tabCell = animator.animatingView as! TabCell + if let indexPath = collectionView.indexPath(for: tabCell) { + let tab = tabsToDisplay[indexPath.item] + tabManager.removeTab(tab) + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, NSLocalizedString("Closing tab", comment: "Accessibility label (used by assistive technology) notifying the user that the tab is being closed.")) + } + } +} + +extension TabTrayController: TabCellDelegate { + func tabCellDidClose(_ cell: TabCell) { + let indexPath = collectionView.indexPath(for: cell)! + let tab = tabsToDisplay[indexPath.item] + tabManager.removeTab(tab) + } +} + +extension TabTrayController: SettingsDelegate { + func settingsOpenURLInNewTab(_ url: URL) { + let request = URLRequest(url: url) + openNewTab(request) + } +} + +extension TabTrayController: PhotonActionSheetProtocol { + func didTapDelete(_ sender: UIButton) { + let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + controller.addAction(UIAlertAction(title: Strings.AppMenuCloseAllTabsTitleString, style: .default, handler: { _ in self.closeTabsForCurrentTray() })) + controller.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "Label for Cancel button"), style: .cancel, handler: nil)) + controller.popoverPresentationController?.sourceView = sender + controller.popoverPresentationController?.sourceRect = sender.bounds + present(controller, animated: true, completion: nil) + } +} + +fileprivate class TabManagerDataSource: NSObject, UICollectionViewDataSource { + unowned var cellDelegate: TabCellDelegate & SwipeAnimatorDelegate + fileprivate var tabs: [Tab] + fileprivate var tabManager: TabManager + + init(tabs: [Tab], cellDelegate: TabCellDelegate & SwipeAnimatorDelegate, tabManager: TabManager) { + self.cellDelegate = cellDelegate + self.tabs = tabs + self.tabManager = tabManager + super.init() + } + + /** + Removes the given tab from the data source + + - parameter tab: Tab to remove + + - returns: The index of the removed tab, -1 if tab did not exist + */ + func removeTab(_ tabToRemove: Tab) -> Int { + var index: Int = -1 + for (i, tab) in tabs.enumerated() where tabToRemove === tab { + index = i + tabs.remove(at: index) + break + } + return index + } + + /** + Adds the given tab to the data source + + - parameter tab: Tab to add + */ + func addTab(_ tab: Tab) { + tabs.append(tab) + } + + @objc func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let tabCell = collectionView.dequeueReusableCell(withReuseIdentifier: TabCell.Identifier, for: indexPath) as! TabCell + tabCell.animator.delegate = cellDelegate + tabCell.delegate = cellDelegate + + let tab = tabs[indexPath.item] + tabCell.style = tab.isPrivate ? .dark : .light + tabCell.titleText.text = tab.displayTitle + tabCell.closeButton.tintColor = tab.isPrivate ? UIColor.white : UIColor.gray + + if !tab.displayTitle.isEmpty { + tabCell.accessibilityLabel = tab.displayTitle + } else { + tabCell.accessibilityLabel = tab.url?.aboutComponent ?? "" // If there is no title we are most likely on a home panel. + } + tabCell.isAccessibilityElement = true + tabCell.accessibilityHint = NSLocalizedString("Swipe right or left with three fingers to close the tab.", comment: "Accessibility hint for tab tray's displayed tab.") + + if let favIcon = tab.displayFavicon { + tabCell.favicon.sd_setImage(with: URL(string: favIcon.url)!) + } else { + let defaultFavicon = UIImage(named: "defaultFavicon") + if tab.isPrivate { + tabCell.favicon.image = defaultFavicon + tabCell.favicon.tintColor = UIColor.white + } else { + tabCell.favicon.image = defaultFavicon + } + } + if tab == tabManager.selectedTab { + tabCell.setTabSelected(tab.isPrivate) + } + tabCell.screenshotView.image = tab.screenshot + return tabCell + } + + @objc func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return tabs.count + } + + @objc fileprivate func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { + let fromIndex = sourceIndexPath.item + let toIndex = destinationIndexPath.item + tabs.insert(tabs.remove(at: fromIndex), at: toIndex < fromIndex ? toIndex : toIndex - 1) + tabManager.moveTab(isPrivate: tabs[fromIndex].isPrivate, fromIndex: fromIndex, toIndex: toIndex) + } +} + +@objc protocol TabSelectionDelegate: class { + func didSelectTabAtIndex(_ index: Int) +} + +fileprivate class TabLayoutDelegate: NSObject, UICollectionViewDelegateFlowLayout { + weak var tabSelectionDelegate: TabSelectionDelegate? + + fileprivate var traitCollection: UITraitCollection + fileprivate var profile: Profile + fileprivate var numberOfColumns: Int { + // iPhone 4-6+ portrait + if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular { + return TabTrayControllerUX.CompactNumberOfColumnsThin + } else { + return TabTrayControllerUX.NumberOfColumnsWide + } + } + + init(profile: Profile, traitCollection: UITraitCollection) { + self.profile = profile + self.traitCollection = traitCollection + super.init() + } + + fileprivate func cellHeightForCurrentDevice() -> CGFloat { + let shortHeight = TabTrayControllerUX.TextBoxHeight * 6 + + if self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClass.compact { + return shortHeight + } else if self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.compact { + return shortHeight + } else { + return TabTrayControllerUX.TextBoxHeight * 8 + } + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return TabTrayControllerUX.Margin + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let cellWidth = floor((collectionView.bounds.width - TabTrayControllerUX.Margin * CGFloat(numberOfColumns + 1)) / CGFloat(numberOfColumns)) + return CGSize(width: cellWidth, height: self.cellHeightForCurrentDevice()) + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + return UIEdgeInsets(equalInset: TabTrayControllerUX.Margin) + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return TabTrayControllerUX.Margin + } + + @objc func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + tabSelectionDelegate?.didSelectTabAtIndex(indexPath.row) + } +} + +struct EmptyPrivateTabsViewUX { + static let TitleColor = UIColor.white + static let TitleFont = UIFont.systemFont(ofSize: 22, weight: UIFontWeightMedium) + static let DescriptionColor = UIColor.white + static let DescriptionFont = UIFont.systemFont(ofSize: 17) + static let LearnMoreFont = UIFont.systemFont(ofSize: 15, weight: UIFontWeightMedium) + static let TextMargin: CGFloat = 18 + static let LearnMoreMargin: CGFloat = 30 + static let MaxDescriptionWidth: CGFloat = 250 + static let MinBottomMargin: CGFloat = 10 +} + +// View we display when there are no private tabs created +fileprivate class EmptyPrivateTabsView: UIView { + fileprivate lazy var titleLabel: UILabel = { + let label = UILabel() + label.textColor = EmptyPrivateTabsViewUX.TitleColor + label.font = EmptyPrivateTabsViewUX.TitleFont + label.textAlignment = NSTextAlignment.center + return label + }() + + fileprivate var descriptionLabel: UILabel = { + let label = UILabel() + label.textColor = EmptyPrivateTabsViewUX.DescriptionColor + label.font = EmptyPrivateTabsViewUX.DescriptionFont + label.textAlignment = NSTextAlignment.center + label.numberOfLines = 0 + label.preferredMaxLayoutWidth = EmptyPrivateTabsViewUX.MaxDescriptionWidth + return label + }() + + fileprivate var learnMoreButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle( + NSLocalizedString("Learn More", tableName: "PrivateBrowsing", comment: "Text button displayed when there are no tabs open while in private mode"), + for: UIControlState()) + button.setTitleColor(UIConstants.PrivateModeTextHighlightColor, for: UIControlState()) + button.titleLabel?.font = EmptyPrivateTabsViewUX.LearnMoreFont + return button + }() + + fileprivate var iconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "largePrivateMask")) + return imageView + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + titleLabel.text = NSLocalizedString("Private Browsing", + tableName: "PrivateBrowsing", comment: "Title displayed for when there are no open tabs while in private mode") + descriptionLabel.text = NSLocalizedString("Firefox won’t remember any of your history or cookies, but new bookmarks will be saved.", + tableName: "PrivateBrowsing", comment: "Description text displayed when there are no open tabs while in private mode") + + addSubview(titleLabel) + addSubview(descriptionLabel) + addSubview(iconImageView) + addSubview(learnMoreButton) + + titleLabel.snp.makeConstraints { make in + make.center.equalTo(self) + } + + iconImageView.snp.makeConstraints { make in + make.bottom.equalTo(titleLabel.snp.top).offset(-EmptyPrivateTabsViewUX.TextMargin) + make.centerX.equalTo(self) + } + + descriptionLabel.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(EmptyPrivateTabsViewUX.TextMargin) + make.centerX.equalTo(self) + } + + learnMoreButton.snp.makeConstraints { (make) -> Void in + make.top.equalTo(descriptionLabel.snp.bottom).offset(EmptyPrivateTabsViewUX.LearnMoreMargin).priority(10) + make.bottom.lessThanOrEqualTo(self).offset(-EmptyPrivateTabsViewUX.MinBottomMargin).priority(1000) + make.centerX.equalTo(self) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension TabTrayController: TabPeekDelegate { + + func tabPeekDidAddBookmark(_ tab: Tab) { + delegate?.tabTrayDidAddBookmark(tab) + } + + func tabPeekDidAddToReadingList(_ tab: Tab) -> ReadingListClientRecord? { + return delegate?.tabTrayDidAddToReadingList(tab) + } + + func tabPeekDidCloseTab(_ tab: Tab) { + if let index = self.tabDataSource.tabs.index(of: tab), + let cell = self.collectionView?.cellForItem(at: IndexPath(item: index, section: 0)) as? TabCell { + cell.close() + } + } + + func tabPeekRequestsPresentationOf(_ viewController: UIViewController) { + delegate?.tabTrayRequestsPresentationOf(viewController) + } +} + +extension TabTrayController: UIViewControllerPreviewingDelegate { + + func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? { + + guard let collectionView = collectionView else { return nil } + let convertedLocation = self.view.convert(location, to: collectionView) + + guard let indexPath = collectionView.indexPathForItem(at: convertedLocation), + let cell = collectionView.cellForItem(at: indexPath) else { return nil } + + let tab = tabDataSource.tabs[indexPath.row] + let tabVC = TabPeekViewController(tab: tab, delegate: self) + if let browserProfile = profile as? BrowserProfile { + tabVC.setState(withProfile: browserProfile, clientPickerDelegate: self) + } + previewingContext.sourceRect = self.view.convert(cell.frame, from: collectionView) + + return tabVC + } + + func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) { + guard let tpvc = viewControllerToCommit as? TabPeekViewController else { return } + tabManager.selectTab(tpvc.tab) + navigationController?.popViewController(animated: true) + delegate?.tabTrayDidDismiss(self) + } +} + +extension TabTrayController: ClientPickerViewControllerDelegate { + + func clientPickerViewController(_ clientPickerViewController: ClientPickerViewController, didPickClients clients: [RemoteClient]) { + if let item = clientPickerViewController.shareItem { + _ = self.profile.sendItems([item], toClients: clients) + } + clientPickerViewController.dismiss(animated: true, completion: nil) + } + + func clientPickerViewControllerDidCancel(_ clientPickerViewController: ClientPickerViewController) { + clientPickerViewController.dismiss(animated: true, completion: nil) + } +} + +extension TabTrayController: UIAdaptivePresentationControllerDelegate, UIPopoverPresentationControllerDelegate { + // Returning None here makes sure that the Popover is actually presented as a Popover and + // not as a full-screen modal, which is the default on compact device classes. + func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { + return UIModalPresentationStyle.none + } +} + +// MARK: - Toolbar +class TrayToolbar: UIView { + fileprivate let toolbarButtonSize = CGSize(width: 44, height: 44) + + lazy var addTabButton: UIButton = { + let button = UIButton() + button.setImage(UIImage.templateImageNamed("nav-add"), for: .normal) + button.accessibilityLabel = NSLocalizedString("Add Tab", comment: "Accessibility label for the Add Tab button in the Tab Tray.") + button.accessibilityIdentifier = "TabTrayController.addTabButton" + return button + }() + + lazy var deleteButton: UIButton = { + let button = UIButton() + button.setImage(UIImage.templateImageNamed("action_delete"), for: .normal) + button.accessibilityLabel = Strings.TabTrayDeleteMenuButtonAccessibilityLabel + button.accessibilityIdentifier = "TabTrayController.removeTabsButton" + return button + }() + + lazy var maskButton: PrivateModeButton = PrivateModeButton() + fileprivate let sideOffset: CGFloat = 32 + + fileprivate override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = .white + addSubview(addTabButton) + + var buttonToCenter: UIButton? + addSubview(deleteButton) + buttonToCenter = deleteButton + + maskButton.accessibilityIdentifier = "TabTrayController.maskButton" + + buttonToCenter?.snp.makeConstraints { make in + make.centerX.equalTo(self) + make.top.equalTo(self) + make.size.equalTo(toolbarButtonSize) + } + + addTabButton.snp.makeConstraints { make in + make.top.equalTo(self) + make.right.equalTo(self).offset(-sideOffset) + make.size.equalTo(toolbarButtonSize) + } + + addSubview(maskButton) + maskButton.snp.makeConstraints { make in + make.top.equalTo(self) + make.left.equalTo(self).offset(sideOffset) + make.size.equalTo(toolbarButtonSize) + } + + styleToolbar(false) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + fileprivate func styleToolbar(_ isPrivate: Bool) { + addTabButton.tintColor = isPrivate ? UIColor(rgb: 0xf9f9fa) : UIColor(rgb: 0x272727) + deleteButton.tintColor = isPrivate ? UIColor(rgb: 0xf9f9fa) : UIColor(rgb: 0x272727) + backgroundColor = isPrivate ? UIConstants.PrivateModeToolbarTintColor : UIColor(rgb: 0xf9f9fa) + maskButton.styleForMode(privateMode: isPrivate) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/ThirdPartySearchAlerts.swift b/mobile/ios/Client/Frontend/Browser/ThirdPartySearchAlerts.swift new file mode 100644 index 0000000000..1ebcce473d --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/ThirdPartySearchAlerts.swift @@ -0,0 +1,88 @@ +/* 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/. */ + +import Foundation +import Shared + +class ThirdPartySearchAlerts: UIAlertController { + + /** + Allows the keyboard to pop back up after an alertview. + **/ + override var canBecomeFirstResponder: Bool { + return false + } + + /** + Builds the Alert view that asks if the users wants to add a third party search engine. + + - parameter okayCallback: Okay option handler. + + - returns: UIAlertController for asking the user to add a search engine + **/ + + static func addThirdPartySearchEngine(_ okayCallback: @escaping (UIAlertAction) -> Void) -> UIAlertController { + let alert = ThirdPartySearchAlerts( + title: Strings.ThirdPartySearchAddTitle, + message: Strings.ThirdPartySearchAddMessage, + preferredStyle: UIAlertControllerStyle.alert + ) + + let noOption = UIAlertAction( + title: Strings.ThirdPartySearchCancelButton, + style: UIAlertActionStyle.cancel, + handler: nil + ) + + let okayOption = UIAlertAction( + title: Strings.ThirdPartySearchOkayButton, + style: UIAlertActionStyle.default, + handler: okayCallback + ) + + alert.addAction(okayOption) + alert.addAction(noOption) + + return alert + } + + /** + Builds the Alert view that shows the user an error in case a search engine could not be added. + + - returns: UIAlertController with an error dialog + **/ + + static func failedToAddThirdPartySearch() -> UIAlertController { + return searchAlertWithOK(title: Strings.ThirdPartySearchFailedTitle, + message: Strings.ThirdPartySearchFailedMessage) + } + + static func incorrectCustomEngineForm() -> UIAlertController { + return searchAlertWithOK(title: Strings.CustomEngineFormErrorTitle, + message: Strings.CustomEngineFormErrorMessage) + } + + static func duplicateCustomEngine() -> UIAlertController { + return searchAlertWithOK(title: Strings.CustomEngineDuplicateErrorTitle, + message: Strings.CustomEngineDuplicateErrorMessage) + } + + private static func searchAlertWithOK(title: String, message: String) -> UIAlertController { + let alert = ThirdPartySearchAlerts( + title: title, + message: message, + preferredStyle: UIAlertControllerStyle.alert + ) + + let okayOption = UIAlertAction( + title: Strings.ThirdPartySearchOkayButton, + style: UIAlertActionStyle.default, + handler: nil + ) + + alert.addAction(okayOption) + return alert + } + +} diff --git a/mobile/ios/Client/Frontend/Browser/TopTabsLayout.swift b/mobile/ios/Client/Frontend/Browser/TopTabsLayout.swift new file mode 100644 index 0000000000..595022ea9e --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TopTabsLayout.swift @@ -0,0 +1,113 @@ +/* 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/. */ +import Foundation + +class TopTabsLayoutDelegate: NSObject, UICollectionViewDelegateFlowLayout { + weak var tabSelectionDelegate: TabSelectionDelegate? + let HeaderFooterWidth = TopTabsUX.SeparatorWidth + TopTabsUX.FaderPading + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return TopTabsUX.SeparatorWidth + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: TopTabsUX.TabWidth, height: collectionView.frame.height) + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + return UIEdgeInsets.zero + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return TopTabsUX.SeparatorWidth + } + + @objc func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + tabSelectionDelegate?.didSelectTabAtIndex(indexPath.row) + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + return CGSize(width: HeaderFooterWidth, height: 0) + } + + @objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { + return CGSize(width: HeaderFooterWidth, height: 0) + } + +} + +class TopTabsViewLayout: UICollectionViewFlowLayout { + var decorationAttributeArr: [Int: UICollectionViewLayoutAttributes?] = [:] + let separatorYOffset = TopTabsUX.SeparatorYOffset + let separatorSize = TopTabsUX.SeparatorHeight + let SeparatorZIndex = -2 ///Prevent the header/footer from appearing above the Tabs + + override var collectionViewContentSize: CGSize { + let tabsWidth = ((CGFloat(collectionView!.numberOfItems(inSection: 0))) * (TopTabsUX.TabWidth + TopTabsUX.SeparatorWidth)) - TopTabsUX.SeparatorWidth + return CGSize(width: tabsWidth + (TopTabsUX.TopTabsBackgroundShadowWidth * 2), height: collectionView!.bounds.height) + } + + override func prepare() { + super.prepare() + self.minimumLineSpacing = TopTabsUX.SeparatorWidth + scrollDirection = UICollectionViewScrollDirection.horizontal + register(TopTabsSeparator.self, forDecorationViewOfKind: TopTabsSeparatorUX.Identifier) + } + + override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { + decorationAttributeArr = [:] + return true + } + + // MARK: layoutAttributesForElementsInRect + override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + guard indexPath.row < self.collectionView!.numberOfItems(inSection: 0) else { + let separatorAttr = UICollectionViewLayoutAttributes(forDecorationViewOfKind: TopTabsSeparatorUX.Identifier, with: indexPath) + separatorAttr.frame = CGRect.zero + separatorAttr.zIndex = SeparatorZIndex + return separatorAttr + } + + if let attr = self.decorationAttributeArr[indexPath.item] { + return attr + } else { + // Compute the separator if it does not exist in the cache + let separatorAttr = UICollectionViewLayoutAttributes(forDecorationViewOfKind: TopTabsSeparatorUX.Identifier, with: indexPath) + let x = TopTabsUX.TopTabsBackgroundShadowWidth + ((CGFloat(indexPath.row) * (TopTabsUX.TabWidth + TopTabsUX.SeparatorWidth)) - TopTabsUX.SeparatorWidth) + separatorAttr.frame = CGRect(x: x, y: separatorYOffset, width: TopTabsUX.SeparatorWidth, height: separatorSize) + separatorAttr.zIndex = SeparatorZIndex + return separatorAttr + } + } + + override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + let attributes = super.layoutAttributesForSupplementaryView(ofKind: elementKind, at: indexPath) + attributes?.zIndex = SeparatorZIndex + return attributes + } + + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + var attributes = super.layoutAttributesForElements(in: rect)! + + // Create attributes for the Tab Separator. + for i in attributes { + guard i.representedElementKind != UICollectionElementKindSectionHeader && i.representedElementKind != UICollectionElementKindSectionFooter else { + i.zIndex = SeparatorZIndex + continue + } + let sep = UICollectionViewLayoutAttributes(forDecorationViewOfKind: TopTabsSeparatorUX.Identifier, with: i.indexPath) + sep.frame = CGRect(x: i.frame.origin.x - TopTabsUX.SeparatorWidth, y: separatorYOffset, width: TopTabsUX.SeparatorWidth, height: separatorSize) + sep.zIndex = SeparatorZIndex + i.zIndex = 10 + + // Only add the seperator if it will be shown. + if i.indexPath.row != 0 && i.indexPath.row < self.collectionView!.numberOfItems(inSection: 0) { + attributes.append(sep) + decorationAttributeArr[i.indexPath.item] = sep + } + } + + return attributes + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TopTabsViewController.swift b/mobile/ios/Client/Frontend/Browser/TopTabsViewController.swift new file mode 100644 index 0000000000..82e172aa3e --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TopTabsViewController.swift @@ -0,0 +1,560 @@ +/* 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/. */ + +import Foundation +import Shared +import WebKit + +struct TopTabsUX { + static let TopTabsViewHeight: CGFloat = 44 + static let TopTabsBackgroundColor = UIColor(rgb: 0x2a2a2e) + static let TopTabsBackgroundPadding: CGFloat = 35 + static let TopTabsBackgroundShadowWidth: CGFloat = 12 + static let TabWidth: CGFloat = 190 + static let CollectionViewPadding: CGFloat = 15 + static let FaderPading: CGFloat = 8 + static let SeparatorWidth: CGFloat = 1 + static let HighlightLineWidth: CGFloat = 3 + static let TabNudge: CGFloat = 1 // Nudge the favicon and close button by 1px + static let TabTitleWidth: CGFloat = 110 + static let TabTitlePadding: CGFloat = 10 + static let AnimationSpeed: TimeInterval = 0.1 + static let SeparatorYOffset: CGFloat = 7 + static let SeparatorHeight: CGFloat = 32 +} + +protocol TopTabsDelegate: class { + func topTabsDidPressTabs() + func topTabsDidPressNewTab(_ isPrivate: Bool) + + func topTabsDidTogglePrivateMode() + func topTabsDidChangeTab() +} + +protocol TopTabCellDelegate: class { + func tabCellDidClose(_ cell: TopTabCell) +} + +class TopTabsViewController: UIViewController { + let tabManager: TabManager + weak var delegate: TopTabsDelegate? + fileprivate var isPrivate = false + let faviconNotification = NSNotification.Name(rawValue: FaviconManager.FaviconDidLoad) + + lazy var collectionView: UICollectionView = { + let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: TopTabsViewLayout()) + collectionView.register(TopTabCell.self, forCellWithReuseIdentifier: TopTabCell.Identifier) + collectionView.showsVerticalScrollIndicator = false + collectionView.showsHorizontalScrollIndicator = false + collectionView.bounces = false + collectionView.clipsToBounds = false + collectionView.accessibilityIdentifier = "Top Tabs View" + return collectionView + }() + + fileprivate lazy var tabsButton: TabsButton = { + let tabsButton = TabsButton.tabTrayButton() + tabsButton.addTarget(self, action: #selector(TopTabsViewController.tabsTrayTapped), for: UIControlEvents.touchUpInside) + tabsButton.accessibilityIdentifier = "TopTabsViewController.tabsButton" + return tabsButton + }() + + fileprivate lazy var newTab: UIButton = { + let newTab = UIButton.newTabButton() + newTab.addTarget(self, action: #selector(TopTabsViewController.newTabTapped), for: UIControlEvents.touchUpInside) + return newTab + }() + + lazy var privateModeButton: PrivateModeButton = { + let privateModeButton = PrivateModeButton() + privateModeButton.light = true + privateModeButton.addTarget(self, action: #selector(TopTabsViewController.togglePrivateModeTapped), for: UIControlEvents.touchUpInside) + return privateModeButton + }() + + fileprivate lazy var tabLayoutDelegate: TopTabsLayoutDelegate = { + let delegate = TopTabsLayoutDelegate() + delegate.tabSelectionDelegate = self + return delegate + }() + + fileprivate var tabsToDisplay: [Tab] { + return self.isPrivate ? tabManager.privateTabs : tabManager.normalTabs + } + + // Handle animations. + fileprivate var tabStore: [Tab] = [] //the actual datastore + fileprivate var pendingUpdatesToTabs: [Tab] = [] //the datastore we are transitioning to + fileprivate var needReloads: [Tab?] = [] // Tabs that need to be reloaded + fileprivate var isUpdating = false + fileprivate var pendingReloadData = false + fileprivate var oldTabs: [Tab]? // The last state of the tabs before an animation + fileprivate weak var oldSelectedTab: Tab? // Used to select the right tab when transitioning between private/normal tabs + + init(tabManager: TabManager) { + self.tabManager = tabManager + super.init(nibName: nil, bundle: nil) + collectionView.dataSource = self + collectionView.delegate = tabLayoutDelegate + [UICollectionElementKindSectionHeader, UICollectionElementKindSectionFooter].forEach { + collectionView.register(TopTabsHeaderFooter.self, forSupplementaryViewOfKind: $0, withReuseIdentifier: "HeaderFooter") + } + NotificationCenter.default.addObserver(self, selector: #selector(TopTabsViewController.reloadFavicons(_:)), name: faviconNotification, object: nil) + } + + deinit { + self.tabManager.removeDelegate(self) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + if self.tabsToDisplay != self.tabStore { + self.reloadData() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + tabManager.addDelegate(self) + self.tabStore = self.tabsToDisplay + + let topTabFader = TopTabFader() + + view.addSubview(topTabFader) + topTabFader.addSubview(collectionView) + view.addSubview(tabsButton) + view.addSubview(newTab) + view.addSubview(privateModeButton) + + newTab.snp.makeConstraints { make in + make.centerY.equalTo(view) + make.trailing.equalTo(tabsButton.snp.leading).offset(-10) + make.size.equalTo(view.snp.height) + } + tabsButton.snp.makeConstraints { make in + make.centerY.equalTo(view) + make.trailing.equalTo(view).offset(-10) + make.size.equalTo(view.snp.height) + } + privateModeButton.snp.makeConstraints { make in + make.centerY.equalTo(view) + make.leading.equalTo(view).offset(10) + make.size.equalTo(view.snp.height) + } + topTabFader.snp.makeConstraints { make in + make.top.bottom.equalTo(view) + make.leading.equalTo(privateModeButton.snp.trailing) + make.trailing.equalTo(newTab.snp.leading) + } + collectionView.snp.makeConstraints { make in + make.edges.equalTo(topTabFader) + } + + view.backgroundColor = UIColor(rgb: 0x272727) + tabsButton.applyTheme(Theme.NormalMode) + if let currentTab = tabManager.selectedTab { + applyTheme(currentTab.isPrivate ? Theme.PrivateMode : Theme.NormalMode) + } + updateTabCount(tabStore.count, animated: false) + } + + func switchForegroundStatus(isInForeground reveal: Bool) { + // Called when the app leaves the foreground to make sure no information is inadvertently revealed + if let cells = self.collectionView.visibleCells as? [TopTabCell] { + let alpha: CGFloat = reveal ? 1 : 0 + for cell in cells { + cell.titleText.alpha = alpha + cell.favicon.alpha = alpha + } + } + } + + func updateTabCount(_ count: Int, animated: Bool = true) { + self.tabsButton.updateTabCount(count, animated: animated) + } + + func tabsTrayTapped() { + delegate?.topTabsDidPressTabs() + } + + func newTabTapped() { + if pendingReloadData { + return + } + self.delegate?.topTabsDidPressNewTab(self.isPrivate) + LeanPlumClient.shared.track(event: .openedNewTab, withParameters: ["Source": "Add tab button in the URL Bar on iPad" as AnyObject]) + } + + func togglePrivateModeTapped() { + if isUpdating || pendingReloadData { + return + } + let isPrivate = self.isPrivate + delegate?.topTabsDidTogglePrivateMode() + self.pendingReloadData = true // Stops animations from happening + let oldSelectedTab = self.oldSelectedTab + self.oldSelectedTab = tabManager.selectedTab + self.privateModeButton.setSelected(!isPrivate, animated: true) + + //if private tabs is empty and we are transitioning to it add a tab + if tabManager.privateTabs.isEmpty && !isPrivate { + tabManager.addTab(isPrivate: true) + } + + //get the tabs from which we will select which one to nominate for tribute (selection) + //the isPrivate boolean still hasnt been flipped. (It'll be flipped in the BVC didSelectedTabChange method) + let tabs = !isPrivate ? tabManager.privateTabs : tabManager.normalTabs + if let tab = oldSelectedTab, tabs.index(of: tab) != nil { + tabManager.selectTab(tab) + } else { + tabManager.selectTab(tabs.last) + } + } + + func reloadFavicons(_ notification: Notification) { + // Notifications might be called from a different thread. Make sure animations only happen on the main thread. + DispatchQueue.main.async { + if let tab = notification.object as? Tab, self.tabStore.index(of: tab) != nil { + self.needReloads.append(tab) + self.performTabUpdates() + } + } + } + + func scrollToCurrentTab(_ animated: Bool = true, centerCell: Bool = false) { + assertIsMainThread("Only animate on the main thread") + + guard let currentTab = tabManager.selectedTab, let index = tabStore.index(of: currentTab), !collectionView.frame.isEmpty else { + return + } + if let frame = collectionView.layoutAttributesForItem(at: IndexPath(row: index, section: 0))?.frame { + if centerCell { + collectionView.scrollToItem(at: IndexPath(item: index, section: 0), at: .centeredHorizontally, animated: false) + } else { + // Padding is added to ensure the tab is completely visible (none of the tab is under the fader) + let padFrame = frame.insetBy(dx: -(TopTabsUX.TopTabsBackgroundShadowWidth+TopTabsUX.FaderPading), dy: 0) + if animated { + UIView.animate(withDuration: TopTabsUX.AnimationSpeed, animations: { + self.collectionView.scrollRectToVisible(padFrame, animated: true) + }) + } else { + collectionView.scrollRectToVisible(padFrame, animated: false) + } + } + } + } +} + +extension TopTabsViewController: Themeable { + func applyTheme(_ themeName: String) { + tabsButton.applyTheme(themeName) + tabsButton.titleBackgroundColor = view.backgroundColor ?? UIColor(rgb: 0x272727) + tabsButton.textColor = UIColor(rgb: 0xb1b1b3) + isPrivate = (themeName == Theme.PrivateMode) + privateModeButton.styleForMode(privateMode: isPrivate) + privateModeButton.tintColor = isPrivate ? UIColor(rgb: 0xf9f9fa) : UIColor(rgb: 0xb1b1b3) + privateModeButton.imageView?.tintColor = privateModeButton.tintColor + newTab.tintColor = UIColor(rgb: 0xb1b1b3) + collectionView.backgroundColor = view.backgroundColor + } +} + +extension TopTabsViewController: TopTabCellDelegate { + func tabCellDidClose(_ cell: TopTabCell) { + // Trying to remove tabs while animating can lead to crashes as indexes change. If updates are happening don't allow tabs to be removed. + guard let index = collectionView.indexPath(for: cell)?.item else { + return + } + let tab = tabStore[index] + if tabsToDisplay.index(of: tab) != nil { + tabManager.removeTab(tab) + } + } +} + +extension TopTabsViewController: UICollectionViewDataSource { + @objc func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let index = indexPath.item + let tabCell = collectionView.dequeueReusableCell(withReuseIdentifier: TopTabCell.Identifier, for: indexPath) as! TopTabCell + tabCell.delegate = self + + let tab = tabStore[index] + tabCell.style = tab.isPrivate ? .dark : .light + tabCell.titleText.text = tab.displayTitle + + if tab.displayTitle.isEmpty { + if tab.webView?.url?.baseDomain?.contains("localhost") ?? true { + tabCell.titleText.text = Strings.AppMenuNewTabTitleString + } else { + tabCell.titleText.text = tab.webView?.url?.absoluteDisplayString + } + tabCell.accessibilityLabel = tab.url?.aboutComponent ?? "" + tabCell.closeButton.accessibilityLabel = String(format: Strings.TopSitesRemoveButtonAccessibilityLabel, tabCell.titleText.text ?? "") + } else { + tabCell.accessibilityLabel = tab.displayTitle + tabCell.closeButton.accessibilityLabel = String(format: Strings.TopSitesRemoveButtonAccessibilityLabel, tab.displayTitle) + } + + tabCell.selectedTab = (tab == tabManager.selectedTab) + if let siteURL = tab.url?.displayURL { + tabCell.favicon.setIcon(tab.displayFavicon, forURL: siteURL, completed: { (color, url) in + if siteURL == url { + tabCell.favicon.image = tabCell.favicon.image?.createScaled(CGSize(width: 15, height: 15)) + tabCell.favicon.backgroundColor = color == .clear ? .white : color + tabCell.favicon.contentMode = .center + } + }) + } else { + tabCell.favicon.image = UIImage(named: "defaultFavicon") + tabCell.favicon.contentMode = .scaleAspectFit + tabCell.favicon.backgroundColor = .clear + } + + return tabCell + } + + @objc func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return tabStore.count + } + + @objc func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeaderFooter", for: indexPath) as! TopTabsHeaderFooter + view.arrangeLine(kind) + return view + } + +} + +extension TopTabsViewController: TabSelectionDelegate { + func didSelectTabAtIndex(_ index: Int) { + let tab = tabStore[index] + if tabsToDisplay.index(of: tab) != nil { + tabManager.selectTab(tab) + } + } +} + +// Collection Diff (animations) +extension TopTabsViewController { + + struct TopTabChangeSet { + let reloads: Set + let inserts: Set + let deletes: Set + + init(reloadArr: [IndexPath], insertArr: [IndexPath], deleteArr: [IndexPath]) { + reloads = Set(reloadArr) + inserts = Set(insertArr) + deletes = Set(deleteArr) + } + + var all: [Set] { + return [inserts, reloads, deletes] + } + + } + + // create a TopTabChangeSet which is a snapshot of updates to perfrom on a collectionView + func calculateDiffWith(_ oldTabs: [Tab], to newTabs: [Tab], and reloadTabs: [Tab?]) -> TopTabChangeSet { + let inserts: [IndexPath] = newTabs.enumerated().flatMap { index, tab in + if oldTabs.index(of: tab) == nil { + return IndexPath(row: index, section: 0) + } + return nil + } + + let deletes: [IndexPath] = oldTabs.enumerated().flatMap { index, tab in + if newTabs.index(of: tab) == nil { + return IndexPath(row: index, section: 0) + } + return nil + } + + // Create based on what is visibile but filter out tabs we are about to insert/delete. + let reloads: [IndexPath] = reloadTabs.flatMap { tab in + guard let tab = tab, newTabs.index(of: tab) != nil else { + return nil + } + return IndexPath(row: newTabs.index(of: tab)!, section: 0) + }.filter { return inserts.index(of: $0) == nil && deletes.index(of: $0) == nil } + + return TopTabChangeSet(reloadArr: reloads, insertArr: inserts, deleteArr: deletes) + } + + func updateTabsFrom(_ oldTabs: [Tab]?, to newTabs: [Tab], on completion: (() -> Void)? = nil) { + assertIsMainThread("Updates can only be performed from the main thread") + guard let oldTabs = oldTabs, !self.isUpdating, !self.pendingReloadData else { + return + } + + // Lets create our change set + let update = self.calculateDiffWith(oldTabs, to: newTabs, and: needReloads) + flushPendingChanges() + + // If there are no changes. We have nothing to do + if update.all.every({ $0.isEmpty }) { + completion?() + return + } + + // The actual update block. We update the dataStore right before we do the UI updates. + let updateBlock = { + self.tabStore = newTabs + self.collectionView.deleteItems(at: Array(update.deletes)) + self.collectionView.insertItems(at: Array(update.inserts)) + self.collectionView.reloadItems(at: Array(update.reloads)) + } + + //Lets lock any other updates from happening. + self.isUpdating = true + self.pendingUpdatesToTabs = newTabs // This var helps other mutations that might happen while updating. + + // The actual update + UIView.animate(withDuration: TopTabsUX.AnimationSpeed, animations: { + self.collectionView.performBatchUpdates(updateBlock) + }) { (_) in + self.isUpdating = false + self.pendingUpdatesToTabs = [] + // Sometimes there might be a pending reload. Lets do that. + if self.pendingReloadData { + return self.reloadData() + } + + // There can be pending animations. Run update again to clear them. + let tabs = self.oldTabs ?? self.tabStore + self.updateTabsFrom(tabs, to: self.tabsToDisplay, on: { + if !update.inserts.isEmpty || !update.reloads.isEmpty { + self.scrollToCurrentTab() + } + }) + } + } + + fileprivate func flushPendingChanges() { + oldTabs = nil + needReloads.removeAll() + } + + fileprivate func reloadData() { + assertIsMainThread("reloadData must only be called from main thread") + + if self.isUpdating || self.collectionView.frame == CGRect.zero { + self.pendingReloadData = true + return + } + + isUpdating = true + self.tabStore = self.tabsToDisplay + self.newTab.isUserInteractionEnabled = false + self.flushPendingChanges() + UIView.animate(withDuration: TopTabsUX.AnimationSpeed, animations: { + self.collectionView.reloadData() + self.collectionView.collectionViewLayout.invalidateLayout() + self.collectionView.layoutIfNeeded() + self.scrollToCurrentTab(true, centerCell: true) + }, completion: { (_) in + self.isUpdating = false + self.pendingReloadData = false + self.performTabUpdates() + self.newTab.isUserInteractionEnabled = true + }) + } +} + +extension TopTabsViewController: TabManagerDelegate { + + // Because we don't know when we are about to transition to private mode + // check to make sure that the tab we are trying to add is being added to the right tab group + fileprivate func tabsMatchDisplayGroup(_ a: Tab?, b: Tab?) -> Bool { + if let a = a, let b = b, a.isPrivate == b.isPrivate { + return true + } + return false + } + + func performTabUpdates() { + guard !isUpdating else { + return + } + + let fromTabs = !self.pendingUpdatesToTabs.isEmpty ? self.pendingUpdatesToTabs : self.oldTabs + self.oldTabs = fromTabs ?? self.tabStore + if self.pendingReloadData && !isUpdating { + self.reloadData() + } else { + self.updateTabsFrom(self.oldTabs, to: self.tabsToDisplay) + } + } + + // This helps make sure animations don't happen before the view is loaded. + fileprivate var isRestoring: Bool { + return self.tabManager.isRestoring || self.collectionView.frame == CGRect.zero + } + + func tabManager(_ tabManager: TabManager, didSelectedTabChange selected: Tab?, previous: Tab?) { + if isRestoring { + return + } + if !tabsMatchDisplayGroup(selected, b: previous) { + self.reloadData() + } else { + self.needReloads.append(selected) + self.needReloads.append(previous) + performTabUpdates() + delegate?.topTabsDidChangeTab() + } + } + + func tabManager(_ tabManager: TabManager, willAddTab tab: Tab) { + // We need to store the earliest oldTabs. So if one already exists use that. + self.oldTabs = self.oldTabs ?? tabStore + } + + func tabManager(_ tabManager: TabManager, didAddTab tab: Tab) { + if isRestoring || (tabManager.selectedTab != nil && !tabsMatchDisplayGroup(tab, b: tabManager.selectedTab)) { + return + } + performTabUpdates() + } + + func tabManager(_ tabManager: TabManager, willRemoveTab tab: Tab) { + // We need to store the earliest oldTabs. So if one already exists use that. + self.oldTabs = self.oldTabs ?? tabStore + } + + func tabManager(_ tabManager: TabManager, didRemoveTab tab: Tab) { + if isRestoring { + return + } + // If we deleted the last private tab. We'll be switching back to normal browsing. Pause updates till then + if self.tabsToDisplay.isEmpty { + self.pendingReloadData = true + return + } + + // dont want to hold a ref to a deleted tab + if tab === oldSelectedTab { + oldSelectedTab = nil + } + + performTabUpdates() + } + + func tabManagerDidRestoreTabs(_ tabManager: TabManager) { + self.reloadData() + } + + func tabManagerDidAddTabs(_ tabManager: TabManager) { + self.reloadData() + } + + func tabManagerDidRemoveAllTabs(_ tabManager: TabManager, toast: ButtonToast?) { + self.reloadData() + } +} diff --git a/mobile/ios/Client/Frontend/Browser/TopTabsViews.swift b/mobile/ios/Client/Frontend/Browser/TopTabsViews.swift new file mode 100644 index 0000000000..898ed32b60 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/TopTabsViews.swift @@ -0,0 +1,258 @@ +/* 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/. */ + +import Foundation + +struct TopTabsSeparatorUX { + static let Identifier = "Separator" + static let Color = UIColor(rgb: 0x3c3c3d) + static let Width: CGFloat = 1 +} + +class TopTabsSeparator: UICollectionReusableView { + override init(frame: CGRect) { + super.init(frame: frame) + self.backgroundColor = TopTabsSeparatorUX.Color + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +class TopTabsHeaderFooter: UICollectionReusableView { + let line = UIView() + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(line) + line.backgroundColor = TopTabsSeparatorUX.Color + } + + func arrangeLine(_ kind: String) { + line.snp.removeConstraints() + switch kind { + case UICollectionElementKindSectionHeader: + line.snp.makeConstraints { make in + make.trailing.equalTo(self) + } + case UICollectionElementKindSectionFooter: + line.snp.makeConstraints { make in + make.leading.equalTo(self) + } + default: + break + } + line.snp.makeConstraints { make in + make.height.equalTo(TopTabsUX.SeparatorHeight) + make.width.equalTo(TopTabsUX.SeparatorWidth) + make.top.equalTo(self).offset(TopTabsUX.SeparatorYOffset) + } + } + + override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { + layer.zPosition = CGFloat(layoutAttributes.zIndex) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +class TopTabCell: UICollectionViewCell { + enum Style { + case light + case dark + } + + static let Identifier = "TopTabCellIdentifier" + static let ShadowOffsetSize: CGFloat = 2 //The shadow is used to hide the tab separator + + var style: Style = .light { + didSet { + if style != oldValue { + applyStyle(style) + } + } + } + + var selectedTab = false { + didSet { + backgroundColor = selectedTab ? UIColor(rgb: 0xf9f9fa) : UIColor(rgb: 0x272727) + titleText.textColor = selectedTab ? UIColor(rgb: 0x0c0c0d) : UIColor(rgb: 0xb1b1b3) + highlightLine.isHidden = !selectedTab + closeButton.tintColor = selectedTab ? UIColor(rgb: 0x272727) : UIColor(rgb: 0xb1b1b3) + // restyle if we are in PBM + if style == .dark && selectedTab { + backgroundColor = UIColor(rgb: 0x38383D) + titleText.textColor = UIColor(rgb: 0xf9f9fa) + closeButton.tintColor = UIColor(rgb: 0xf9f9fa) + } + closeButton.backgroundColor = backgroundColor + closeButton.layer.shadowColor = backgroundColor?.cgColor + if selectedTab { + drawShadow() + } + } + } + + let titleText: UILabel = { + let titleText = UILabel() + titleText.textAlignment = NSTextAlignment.left + titleText.isUserInteractionEnabled = false + titleText.numberOfLines = 1 + titleText.lineBreakMode = .byCharWrapping + titleText.font = DynamicFontHelper.defaultHelper.DefaultSmallFont + return titleText + }() + + let favicon: UIImageView = { + let favicon = UIImageView() + favicon.layer.cornerRadius = 2.0 + favicon.layer.masksToBounds = true + return favicon + }() + + let closeButton: UIButton = { + let closeButton = UIButton() + closeButton.setImage(UIImage.templateImageNamed("menu-CloseTabs"), for: UIControlState()) + closeButton.tintColor = UIColor(rgb: 0xb1b1b3) + closeButton.imageEdgeInsets = UIEdgeInsets(top: 15, left: TopTabsUX.TabTitlePadding, bottom: 15, right: TopTabsUX.TabTitlePadding) + closeButton.layer.shadowOpacity = 0.8 + closeButton.layer.masksToBounds = false + closeButton.layer.shadowOffset = CGSize(width: -TopTabsUX.TabTitlePadding, height: 0) + return closeButton + }() + + let highlightLine: UIView = { + let line = UIView() + line.backgroundColor = UIColor(rgb: 0x0066DC) + line.isHidden = true + return line + }() + + weak var delegate: TopTabCellDelegate? + + override init(frame: CGRect) { + super.init(frame: frame) + + closeButton.addTarget(self, action: #selector(TopTabCell.closeTab), for: UIControlEvents.touchUpInside) + + contentView.addSubview(titleText) + contentView.addSubview(closeButton) + contentView.addSubview(favicon) + contentView.addSubview(highlightLine) + + favicon.snp.makeConstraints { make in + make.centerY.equalTo(self).offset(TopTabsUX.TabNudge) + make.size.equalTo(TabTrayControllerUX.FaviconSize) + make.leading.equalTo(self).offset(TopTabsUX.TabTitlePadding) + } + titleText.snp.makeConstraints { make in + make.centerY.equalTo(self) + make.height.equalTo(self) + make.trailing.equalTo(closeButton.snp.leading).offset(TopTabsUX.TabTitlePadding) + make.leading.equalTo(favicon.snp.trailing).offset(TopTabsUX.TabTitlePadding) + } + closeButton.snp.makeConstraints { make in + make.centerY.equalTo(self).offset(TopTabsUX.TabNudge) + make.height.equalTo(self) + make.width.equalTo(self.snp.height).offset(-TopTabsUX.TabTitlePadding) + make.trailing.equalTo(self.snp.trailing) + } + highlightLine.snp.makeConstraints { make in + make.top.equalTo(self) + make.leading.equalTo(self).offset(-TopTabCell.ShadowOffsetSize) + make.trailing.equalTo(self).offset(TopTabCell.ShadowOffsetSize) + make.height.equalTo(TopTabsUX.HighlightLineWidth) + } + + self.clipsToBounds = false + + applyStyle(style) + } + + fileprivate func applyStyle(_ style: Style) { + switch style { + case Style.light: + titleText.textColor = UIColor.darkText + backgroundColor = UIConstants.AppBackgroundColor + highlightLine.backgroundColor = UIColor(rgb: 0x0066DC) + case Style.dark: + titleText.textColor = UIColor.lightText + backgroundColor = UIColor(rgb: 0x38383D) + highlightLine.backgroundColor = UIColor(rgb: 0x9400ff) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + super.prepareForReuse() + self.layer.shadowOpacity = 0 + } + + func closeTab() { + delegate?.tabCellDidClose(self) + } + + // When a tab is selected the shadow prevents the tab separators from showing. + func drawShadow() { + self.layer.masksToBounds = false + self.layer.shadowColor = backgroundColor?.cgColor + self.layer.shadowOpacity = 1 + self.layer.shadowRadius = 0 + + self.layer.shadowPath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: self.frame.size.width + (TopTabCell.ShadowOffsetSize * 2), height: self.frame.size.height), cornerRadius: 0).cgPath + self.layer.shadowOffset = CGSize(width: -TopTabCell.ShadowOffsetSize, height: 0) + } + + override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { + layer.zPosition = CGFloat(layoutAttributes.zIndex) + } +} + +class TopTabFader: UIView { + lazy var hMaskLayer: CAGradientLayer = { + let innerColor: CGColor = UIColor(white: 1, alpha: 1.0).cgColor + let outerColor: CGColor = UIColor(white: 1, alpha: 0.0).cgColor + let hMaskLayer = CAGradientLayer() + hMaskLayer.colors = [outerColor, innerColor, innerColor, outerColor] + hMaskLayer.locations = [0.00, 0.005, 0.995, 1.0] + hMaskLayer.startPoint = CGPoint(x: 0, y: 0.5) + hMaskLayer.endPoint = CGPoint(x: 1.0, y: 0.5) + hMaskLayer.anchorPoint = CGPoint.zero + return hMaskLayer + }() + + init() { + super.init(frame: CGRect.zero) + layer.mask = hMaskLayer + } + + internal override func layoutSubviews() { + super.layoutSubviews() + + let widthA = NSNumber(value: Float(CGFloat(8) / frame.width)) + let widthB = NSNumber(value: Float(1 - CGFloat(8) / frame.width)) + + hMaskLayer.locations = [0.00, widthA, widthB, 1.0] + hMaskLayer.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +class TopTabsViewLayoutAttributes: UICollectionViewLayoutAttributes { + + override func isEqual(_ object: Any?) -> Bool { + guard let object = object as? TopTabsViewLayoutAttributes else { + return false + } + return super.isEqual(object) + } +} diff --git a/mobile/ios/Client/Frontend/Browser/URIFixup.swift b/mobile/ios/Client/Frontend/Browser/URIFixup.swift new file mode 100644 index 0000000000..df7e027aa4 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/URIFixup.swift @@ -0,0 +1,53 @@ +/* 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/. */ + +import Foundation +import Shared + +class URIFixup { + static func getURL(_ entry: String) -> URL? { + let trimmed = entry.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + guard let escaped = trimmed.addingPercentEncoding(withAllowedCharacters: CharacterSet.URLAllowedCharacterSet()) else { + return nil + } + + // Then check if the URL includes a scheme. This will handle + // all valid requests starting with "http://", "about:", etc. + // However, we ensure that the scheme is one that is listed in + // the official URI scheme list, so that other such search phrases + // like "filetype:" are recognised as searches rather than URLs. + if let url = punycodedURL(escaped), url.schemeIsValid { + return url + } + + // If there's no scheme, we're going to prepend "http://". First, + // make sure there's at least one "." in the host. This means + // we'll allow single-word searches (e.g., "foo") at the expense + // of breaking single-word hosts without a scheme (e.g., "localhost"). + if trimmed.range(of: ".") == nil { + return nil + } + + if trimmed.range(of: " ") != nil { + return nil + } + + // If there is a ".", prepend "http://" and try again. Since this + // is strictly an "http://" URL, we also require a host. + if let url = punycodedURL("http://\(escaped)"), url.host != nil { + return url + } + + return nil + } + + static func punycodedURL(_ string: String) -> URL? { + var components = URLComponents(string: string) + if AppConstants.MOZ_PUNYCODE { + let host = components?.host?.utf8HostToAscii() + components?.host = host + } + return components?.url + } +} diff --git a/mobile/ios/Client/Frontend/Browser/URLBarView.swift b/mobile/ios/Client/Frontend/Browser/URLBarView.swift new file mode 100644 index 0000000000..86e9f8cf17 --- /dev/null +++ b/mobile/ios/Client/Frontend/Browser/URLBarView.swift @@ -0,0 +1,825 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared +import SnapKit +import XCGLogger + +private let log = Logger.browserLogger + +struct URLBarViewUX { + static let TextFieldBorderColor = UIColor(rgb: 0xBBBBBB) + static let TextFieldActiveBorderColor = UIColor(rgb: 0xB0D5FB) + static let LocationLeftPadding: CGFloat = 8 + static let Padding: CGFloat = 10 + static let LocationHeight: CGFloat = 40 + static let ButtonHeight: CGFloat = 44 + static let LocationContentOffset: CGFloat = 8 + static let TextFieldCornerRadius: CGFloat = 8 + static let TextFieldBorderWidth: CGFloat = 1 + static let TextFieldBorderWidthSelected: CGFloat = 4 + // offset from edge of tabs button + static let ProgressTintColor = UIColor(rgb: 0x00dcfc) + static let ProgressBarHeight: CGFloat = 3 + + static let TabsButtonRotationOffset: CGFloat = 1.5 + static let TabsButtonHeight: CGFloat = 18.0 + static let ToolbarButtonInsets = UIEdgeInsets(top: Padding, left: Padding, bottom: Padding, right: Padding) + + static let Themes: [String: Theme] = { + var themes = [String: Theme]() + var theme = Theme() + theme.borderColor = UIColor(rgb: 0x2D2D31) + theme.backgroundColor = UIColor(rgb: 0x38383D) + theme.activeBorderColor = UIColor(rgb: 0x4a4a4f) + theme.tintColor = UIColor(rgb: 0xf9f9fa) + theme.textColor = UIColor(rgb: 0xf9f9fa) + theme.buttonTintColor = UIColor(rgb: 0xD2d2d4) + theme.disabledButtonColor = UIColor.gray + theme.highlightButtonColor = UIColor(rgb: 0xAC39FF) + themes[Theme.PrivateMode] = theme + + theme = Theme() + theme.borderColor = UIColor(rgb: 0x737373).withAlphaComponent(0.3) + theme.activeBorderColor = TextFieldActiveBorderColor + theme.disabledButtonColor = UIColor.lightGray + theme.highlightButtonColor = UIColor(rgb: 0x00A2FE) + theme.tintColor = ProgressTintColor + theme.textColor = UIColor(rgb: 0x272727) + theme.backgroundColor = UIConstants.AppBackgroundColor + theme.buttonTintColor = UIColor(rgb: 0x272727) + themes[Theme.NormalMode] = theme + + return themes + }() +} + +protocol URLBarDelegate: class { + func urlBarDidPressTabs(_ urlBar: URLBarView) + func urlBarDidPressReaderMode(_ urlBar: URLBarView) + /// - returns: whether the long-press was handled by the delegate; i.e. return `false` when the conditions for even starting handling long-press were not satisfied + func urlBarDidLongPressReaderMode(_ urlBar: URLBarView) -> Bool + func urlBarDidPressStop(_ urlBar: URLBarView) + func urlBarDidPressReload(_ urlBar: URLBarView) + func urlBarDidEnterOverlayMode(_ urlBar: URLBarView) + func urlBarDidLeaveOverlayMode(_ urlBar: URLBarView) + func urlBarDidLongPressLocation(_ urlBar: URLBarView) + func urlBarDidPressQRButton(_ urlBar: URLBarView) + func urlBarDidPressPageOptions(_ urlBar: URLBarView, from button: UIButton) + func urlBarLocationAccessibilityActions(_ urlBar: URLBarView) -> [UIAccessibilityCustomAction]? + func urlBarDidPressScrollToTop(_ urlBar: URLBarView) + func urlBar(_ urlBar: URLBarView, didEnterText text: String) + func urlBar(_ urlBar: URLBarView, didSubmitText text: String) + // Returns either (search query, true) or (url, false). + func urlBarDisplayTextForURL(_ url: URL?) -> (String?, Bool) + func urlBarDidLongPressPageOptions(_ urlBar: URLBarView, from button: UIButton) +} + +class URLBarView: UIView { + // Additional UIAppearance-configurable properties + dynamic var locationBorderColor: UIColor = URLBarViewUX.TextFieldBorderColor { + didSet { + if !inOverlayMode { + locationContainer.layer.borderColor = locationBorderColor.cgColor + } + } + } + dynamic var locationActiveBorderColor: UIColor = URLBarViewUX.TextFieldActiveBorderColor { + didSet { + if inOverlayMode { + locationContainer.layer.borderColor = locationActiveBorderColor.cgColor + } + } + } + + weak var delegate: URLBarDelegate? + weak var tabToolbarDelegate: TabToolbarDelegate? + var helper: TabToolbarHelper? + var isTransitioning: Bool = false { + didSet { + if isTransitioning { + // Cancel any pending/in-progress animations related to the progress bar + self.progressBar.setProgress(1, animated: false) + self.progressBar.alpha = 0.0 + } + } + } + + fileprivate var currentTheme: String = Theme.NormalMode + + var toolbarIsShowing = false + var topTabsIsShowing = false + + fileprivate var locationTextField: ToolbarTextField? + + /// Overlay mode is the state where the lock/reader icons are hidden, the home panels are shown, + /// and the Cancel button is visible (allowing the user to leave overlay mode). Overlay mode + /// is *not* tied to the location text field's editing state; for instance, when selecting + /// a panel, the first responder will be resigned, yet the overlay mode UI is still active. + var inOverlayMode = false + + lazy var locationView: TabLocationView = { + let locationView = TabLocationView() + locationView.translatesAutoresizingMaskIntoConstraints = false + locationView.readerModeState = ReaderModeState.unavailable + locationView.delegate = self + return locationView + }() + + lazy var locationContainer: UIView = { + let locationContainer = TabLocationContainerView() + locationContainer.translatesAutoresizingMaskIntoConstraints = false + locationContainer.layer.shadowColor = self.locationBorderColor.cgColor + locationContainer.layer.borderWidth = URLBarViewUX.TextFieldBorderWidth + locationContainer.layer.borderColor = self.locationBorderColor.cgColor + locationContainer.backgroundColor = .clear + return locationContainer + }() + + let line = UIView() + + lazy var tabsButton: TabsButton = { + let tabsButton = TabsButton.tabTrayButton() + tabsButton.accessibilityIdentifier = "URLBarView.tabsButton" + return tabsButton + }() + + fileprivate lazy var progressBar: GradientProgressBar = { + let progressBar = GradientProgressBar() + progressBar.clipsToBounds = false + return progressBar + }() + + fileprivate lazy var cancelButton: UIButton = { + let cancelButton = InsetButton() + cancelButton.setImage(UIImage.templateImageNamed("goBack"), for: .normal) + cancelButton.addTarget(self, action: #selector(URLBarView.SELdidClickCancel), for: .touchUpInside) + cancelButton.alpha = 0 + return cancelButton + }() + + fileprivate lazy var showQRScannerButton: InsetButton = { + let button = InsetButton() + button.setImage(UIImage.templateImageNamed("menu-ScanQRCode"), for: .normal) + button.clipsToBounds = false + button.addTarget(self, action: #selector(URLBarView.showQRScanner), for: .touchUpInside) + button.setContentHuggingPriority(1000, for: UILayoutConstraintAxis.horizontal) + button.setContentCompressionResistancePriority(1000, for: UILayoutConstraintAxis.horizontal) + return button + }() + + fileprivate lazy var scrollToTopButton: UIButton = { + let button = UIButton() + button.addTarget(self, action: #selector(URLBarView.SELtappedScrollToTopArea), for: .touchUpInside) + return button + }() + + var menuButton = ToolbarButton() + var bookmarkButton = ToolbarButton() + var forwardButton = ToolbarButton() + var stopReloadButton = ToolbarButton() + + var backButton: ToolbarButton = { + let backButton = ToolbarButton() + backButton.accessibilityIdentifier = "URLBarView.backButton" + return backButton + }() + + lazy var actionButtons: [Themeable & UIButton] = [self.tabsButton, self.menuButton, self.forwardButton, self.backButton, self.stopReloadButton] + + var currentURL: URL? { + get { + return locationView.url as URL? + } + + set(newURL) { + locationView.url = newURL + line.isHidden = newURL?.isAboutHomeURL ?? true + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + commonInit() + } + + fileprivate func commonInit() { + locationContainer.addSubview(locationView) + + [scrollToTopButton, line, tabsButton, progressBar, cancelButton, showQRScannerButton].forEach { addSubview($0) } + [menuButton, forwardButton, backButton, stopReloadButton, locationContainer].forEach { addSubview($0) } + + helper = TabToolbarHelper(toolbar: self) + setupConstraints() + + // Make sure we hide any views that shouldn't be showing in non-overlay mode. + updateViewsForOverlayModeAndToolbarChanges() + } + + fileprivate func setupConstraints() { + + line.snp.makeConstraints { make in + make.bottom.leading.trailing.equalTo(self) + make.height.equalTo(1) + } + + scrollToTopButton.snp.makeConstraints { make in + make.top.equalTo(self) + make.left.right.equalTo(self.locationContainer) + } + + progressBar.snp.makeConstraints { make in + make.top.equalTo(self.snp.bottom).inset(URLBarViewUX.ProgressBarHeight / 2) + make.height.equalTo(URLBarViewUX.ProgressBarHeight) + make.left.right.equalTo(self) + } + + locationView.snp.makeConstraints { make in + make.edges.equalTo(self.locationContainer) + } + + cancelButton.snp.makeConstraints { make in + make.centerY.equalTo(self.locationContainer) + make.size.equalTo(URLBarViewUX.ButtonHeight) + make.leading.equalTo(self) + } + + backButton.snp.makeConstraints { make in + make.centerY.equalTo(self) + make.leading.equalTo(self).offset(URLBarViewUX.Padding) + make.size.equalTo(URLBarViewUX.ButtonHeight) + } + + forwardButton.snp.makeConstraints { make in + make.left.equalTo(self.backButton.snp.right) + make.centerY.equalTo(self) + make.size.equalTo(URLBarViewUX.ButtonHeight) + } + + stopReloadButton.snp.makeConstraints { make in + make.left.equalTo(self.forwardButton.snp.right) + make.centerY.equalTo(self) + make.size.equalTo(URLBarViewUX.ButtonHeight) + } + + menuButton.snp.makeConstraints { make in + make.trailing.equalTo(self.snp.trailing).offset(-URLBarViewUX.Padding) + make.centerY.equalTo(self) + make.size.equalTo(URLBarViewUX.ButtonHeight) + } + + tabsButton.snp.makeConstraints { make in + make.trailing.equalTo(self.menuButton.snp.leading) + make.centerY.equalTo(self) + make.size.equalTo(URLBarViewUX.ButtonHeight) + } + + showQRScannerButton.snp.makeConstraints { make in + make.centerY.equalTo(self.locationContainer) + make.trailing.equalTo(self) + make.size.equalTo(URLBarViewUX.ButtonHeight) + } + } + + override func updateConstraints() { + super.updateConstraints() + if inOverlayMode { + // In overlay mode, we always show the location view full width + self.locationContainer.layer.borderWidth = URLBarViewUX.TextFieldBorderWidthSelected + self.locationContainer.snp.remakeConstraints { make in + let height = URLBarViewUX.LocationHeight + (URLBarViewUX.TextFieldBorderWidthSelected * 2) + make.height.equalTo(height) + make.trailing.equalTo(self.showQRScannerButton.snp.leading) + make.leading.equalTo(self.cancelButton.snp.trailing) + make.centerY.equalTo(self) + } + self.locationView.snp.remakeConstraints { make in + make.edges.equalTo(self.locationContainer).inset(UIEdgeInsets(equalInset: URLBarViewUX.TextFieldBorderWidthSelected)) + } + self.locationTextField?.snp.remakeConstraints { make in + make.edges.equalTo(self.locationView).inset(UIEdgeInsets(top: 0, left: URLBarViewUX.LocationLeftPadding, bottom: 0, right: URLBarViewUX.LocationLeftPadding)) + } + } else { + self.locationContainer.snp.remakeConstraints { make in + if self.toolbarIsShowing { + // If we are showing a toolbar, show the text field next to the forward button + make.leading.equalTo(self.stopReloadButton.snp.trailing).offset(URLBarViewUX.Padding) + if self.topTabsIsShowing { + make.trailing.equalTo(self.menuButton.snp.leading).offset(-URLBarViewUX.Padding) + } else { + make.trailing.equalTo(self.tabsButton.snp.leading).offset(-URLBarViewUX.Padding) + } + + } else { + // Otherwise, left align the location view + make.leading.trailing.equalTo(self).inset(UIEdgeInsets(top: 0, left: URLBarViewUX.LocationLeftPadding-1, bottom: 0, right: URLBarViewUX.LocationLeftPadding-1)) + } + + make.height.equalTo(URLBarViewUX.LocationHeight+2) + make.centerY.equalTo(self) + } + self.locationContainer.layer.borderWidth = URLBarViewUX.TextFieldBorderWidth + self.locationView.snp.remakeConstraints { make in + make.edges.equalTo(self.locationContainer).inset(UIEdgeInsets(equalInset: URLBarViewUX.TextFieldBorderWidth)) + } + } + + } + + func showQRScanner() { + self.delegate?.urlBarDidPressQRButton(self) + } + + func createLocationTextField() { + guard locationTextField == nil else { return } + + locationTextField = ToolbarTextField() + + guard let locationTextField = locationTextField else { return } + + locationTextField.translatesAutoresizingMaskIntoConstraints = false + locationTextField.autocompleteDelegate = self + locationTextField.keyboardType = UIKeyboardType.webSearch + locationTextField.autocorrectionType = UITextAutocorrectionType.no + locationTextField.autocapitalizationType = UITextAutocapitalizationType.none + locationTextField.returnKeyType = UIReturnKeyType.go + locationTextField.clearButtonMode = UITextFieldViewMode.whileEditing + locationTextField.font = UIConstants.DefaultChromeFont + locationTextField.accessibilityIdentifier = "address" + locationTextField.accessibilityLabel = NSLocalizedString("Address and Search", comment: "Accessibility label for address and search field, both words (Address, Search) are therefore nouns.") + locationTextField.attributedPlaceholder = self.locationView.placeholder + locationContainer.addSubview(locationTextField) + locationTextField.snp.remakeConstraints { make in + make.edges.equalTo(self.locationView) + } + + locationTextField.applyTheme(currentTheme) + } + + func removeLocationTextField() { + locationTextField?.removeFromSuperview() + locationTextField = nil + } + + // Ideally we'd split this implementation in two, one URLBarView with a toolbar and one without + // However, switching views dynamically at runtime is a difficult. For now, we just use one view + // that can show in either mode. + func setShowToolbar(_ shouldShow: Bool) { + toolbarIsShowing = shouldShow + setNeedsUpdateConstraints() + // when we transition from portrait to landscape, calling this here causes + // the constraints to be calculated too early and there are constraint errors + if !toolbarIsShowing { + updateConstraintsIfNeeded() + } + updateViewsForOverlayModeAndToolbarChanges() + } + + func updateAlphaForSubviews(_ alpha: CGFloat) { + self.locationContainer.alpha = alpha + self.alpha = alpha + } + + func updateProgressBar(_ progress: Float) { + progressBar.alpha = 1 + progressBar.isHidden = false + progressBar.setProgress(progress, animated: !isTransitioning) + } + + func hideProgressBar() { + progressBar.isHidden = true + progressBar.setProgress(0, animated: false) + } + + func updateReaderModeState(_ state: ReaderModeState) { + locationView.readerModeState = state + } + + func setAutocompleteSuggestion(_ suggestion: String?) { + locationTextField?.setAutocompleteSuggestion(suggestion) + } + + func setLocation(_ location: String?, search: Bool) { + locationTextField?.text = location + if search, let location = location, !location.isEmpty { + // Not notifying when empty agrees with AutocompleteTextField.textDidChange. + delegate?.urlBar(self, didEnterText: location) + } + } + + func enterOverlayMode(_ locationText: String?, pasted: Bool, search: Bool) { + createLocationTextField() + + // Show the overlay mode UI, which includes hiding the locationView and replacing it + // with the editable locationTextField. + animateToOverlayState(overlayMode: true) + + delegate?.urlBarDidEnterOverlayMode(self) + + // Bug 1193755 Workaround - Calling becomeFirstResponder before the animation happens + // won't take the initial frame of the label into consideration, which makes the label + // look squished at the start of the animation and expand to be correct. As a workaround, + // we becomeFirstResponder as the next event on UI thread, so the animation starts before we + // set a first responder. + if pasted { + // Clear any existing text, focus the field, then set the actual pasted text. + // This avoids highlighting all of the text. + self.locationTextField?.text = "" + DispatchQueue.main.async { + self.locationTextField?.becomeFirstResponder() + self.setLocation(locationText, search: search) + } + } else { + // Copy the current URL to the editable text field, then activate it. + self.setLocation(locationText, search: search) + DispatchQueue.main.async { + self.locationTextField?.becomeFirstResponder() + } + } + } + + func leaveOverlayMode(didCancel cancel: Bool = false) { + locationTextField?.resignFirstResponder() + animateToOverlayState(overlayMode: false, didCancel: cancel) + delegate?.urlBarDidLeaveOverlayMode(self) + } + + func prepareOverlayAnimation() { + // Make sure everything is showing during the transition (we'll hide it afterwards). + self.bringSubview(toFront: self.locationContainer) + self.cancelButton.isHidden = false + self.showQRScannerButton.isHidden = false + self.progressBar.isHidden = false + self.menuButton.isHidden = !self.toolbarIsShowing + self.forwardButton.isHidden = !self.toolbarIsShowing + self.backButton.isHidden = !self.toolbarIsShowing + self.tabsButton.isHidden = !self.toolbarIsShowing || topTabsIsShowing + self.stopReloadButton.isHidden = !self.toolbarIsShowing + } + + func transitionToOverlay(_ didCancel: Bool = false) { + self.cancelButton.alpha = inOverlayMode ? 1 : 0 + self.showQRScannerButton.alpha = inOverlayMode ? 1 : 0 + self.progressBar.alpha = inOverlayMode || didCancel ? 0 : 1 + self.tabsButton.alpha = inOverlayMode ? 0 : 1 + self.menuButton.alpha = inOverlayMode ? 0 : 1 + self.forwardButton.alpha = inOverlayMode ? 0 : 1 + self.backButton.alpha = inOverlayMode ? 0 : 1 + self.stopReloadButton.alpha = inOverlayMode ? 0 : 1 + + let borderColor = inOverlayMode ? locationActiveBorderColor : locationBorderColor + locationContainer.layer.borderColor = borderColor.cgColor + + if inOverlayMode { + self.line.isHidden = inOverlayMode + // Make the editable text field span the entire URL bar, covering the lock and reader icons. + self.locationTextField?.snp.remakeConstraints { make in + make.edges.equalTo(self.locationView) + } + } else { + // Shrink the editable text field back to the size of the location view before hiding it. + self.locationTextField?.snp.remakeConstraints { make in + make.edges.equalTo(self.locationView.urlTextField) + } + } + } + + func updateViewsForOverlayModeAndToolbarChanges() { + self.cancelButton.isHidden = !inOverlayMode + self.showQRScannerButton.isHidden = !inOverlayMode + self.progressBar.isHidden = inOverlayMode + self.menuButton.isHidden = !self.toolbarIsShowing || inOverlayMode + self.forwardButton.isHidden = !self.toolbarIsShowing || inOverlayMode + self.backButton.isHidden = !self.toolbarIsShowing || inOverlayMode + self.tabsButton.isHidden = !self.toolbarIsShowing || inOverlayMode || topTabsIsShowing + self.stopReloadButton.isHidden = !self.toolbarIsShowing || inOverlayMode + } + + func animateToOverlayState(overlayMode overlay: Bool, didCancel cancel: Bool = false) { + prepareOverlayAnimation() + layoutIfNeeded() + + inOverlayMode = overlay + + if !overlay { + removeLocationTextField() + } + + UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 0.85, initialSpringVelocity: 0.0, options: [], animations: { _ in + self.transitionToOverlay(cancel) + self.setNeedsUpdateConstraints() + self.layoutIfNeeded() + }, completion: { _ in + self.updateViewsForOverlayModeAndToolbarChanges() + }) + } + + func SELdidClickAddTab() { + delegate?.urlBarDidPressTabs(self) + } + + func SELdidClickCancel() { + leaveOverlayMode(didCancel: true) + } + + func SELtappedScrollToTopArea() { + delegate?.urlBarDidPressScrollToTop(self) + } +} + +extension URLBarView: TabToolbarProtocol { + + func updateBackStatus(_ canGoBack: Bool) { + backButton.isEnabled = canGoBack + } + + func updateForwardStatus(_ canGoForward: Bool) { + forwardButton.isEnabled = canGoForward + } + + func updateTabCount(_ count: Int, animated: Bool = true) { + self.tabsButton.updateTabCount(count, animated: animated) + } + + func updateReloadStatus(_ isLoading: Bool) { + helper?.updateReloadStatus(isLoading) + if isLoading { + stopReloadButton.setImage(helper?.ImageStop, for: .normal) + } else { + stopReloadButton.setImage(helper?.ImageReload, for: .normal) + } + } + + func updatePageStatus(_ isWebPage: Bool) { + stopReloadButton.isEnabled = isWebPage + } + + var access: [Any]? { + get { + if inOverlayMode { + guard let locationTextField = locationTextField else { return nil } + return [locationTextField, cancelButton] + } else { + if toolbarIsShowing { + return [backButton, forwardButton, stopReloadButton, locationView, tabsButton, menuButton, progressBar] + } else { + return [locationView, progressBar] + } + } + } + set { + super.accessibilityElements = newValue + } + } +} + +extension URLBarView: TabLocationViewDelegate { + func tabLocationViewDidLongPressReaderMode(_ tabLocationView: TabLocationView) -> Bool { + return delegate?.urlBarDidLongPressReaderMode(self) ?? false + } + + func tabLocationViewDidTapLocation(_ tabLocationView: TabLocationView) { + guard let (locationText, isSearchQuery) = delegate?.urlBarDisplayTextForURL(locationView.url as URL?) else { return } + + var overlayText = locationText + // Make sure to use the result from urlBarDisplayTextForURL as it is responsible for extracting out search terms when on a search page + if let text = locationText, let url = URL(string: text), let host = url.host, AppConstants.MOZ_PUNYCODE { + overlayText = url.absoluteString.replacingOccurrences(of: host, with: host.asciiHostToUTF8()) + } + enterOverlayMode(overlayText, pasted: false, search: isSearchQuery) + } + + func tabLocationViewDidLongPressLocation(_ tabLocationView: TabLocationView) { + delegate?.urlBarDidLongPressLocation(self) + } + + func tabLocationViewDidTapReload(_ tabLocationView: TabLocationView) { + delegate?.urlBarDidPressReload(self) + } + + func tabLocationViewDidTapStop(_ tabLocationView: TabLocationView) { + delegate?.urlBarDidPressStop(self) + } + + func tabLocationViewDidTapReaderMode(_ tabLocationView: TabLocationView) { + delegate?.urlBarDidPressReaderMode(self) + } + + func tabLocationViewDidTapPageOptions(_ tabLocationView: TabLocationView, from button: UIButton) { + delegate?.urlBarDidPressPageOptions(self, from: tabLocationView.pageOptionsButton) + } + + func tabLocationViewDidLongPressPageOptions(_ tabLocationView: TabLocationView) { + delegate?.urlBarDidLongPressPageOptions(self, from: tabLocationView.pageOptionsButton) + } + + func tabLocationViewLocationAccessibilityActions(_ tabLocationView: TabLocationView) -> [UIAccessibilityCustomAction]? { + return delegate?.urlBarLocationAccessibilityActions(self) + } +} + +extension URLBarView: AutocompleteTextFieldDelegate { + func autocompleteTextFieldShouldReturn(_ autocompleteTextField: AutocompleteTextField) -> Bool { + guard let text = locationTextField?.text else { return true } + if !text.trimmingCharacters(in: .whitespaces).isEmpty { + delegate?.urlBar(self, didSubmitText: text) + return true + } else { + return false + } + } + + func autocompleteTextField(_ autocompleteTextField: AutocompleteTextField, didEnterText text: String) { + delegate?.urlBar(self, didEnterText: text) + } + + func autocompleteTextFieldDidBeginEditing(_ autocompleteTextField: AutocompleteTextField) { + autocompleteTextField.highlightAll() + } + + func autocompleteTextFieldShouldClear(_ autocompleteTextField: AutocompleteTextField) -> Bool { + delegate?.urlBar(self, didEnterText: "") + return true + } +} + +// MARK: UIAppearance +extension URLBarView { + + dynamic var cancelTintColor: UIColor? { + get { return cancelButton.tintColor } + set { return cancelButton.tintColor = newValue } + } + + dynamic var showQRButtonTintColor: UIColor? { + get { return showQRScannerButton.tintColor } + set { return showQRScannerButton.tintColor = newValue } + } + +} + +extension URLBarView: Themeable { + + func applyTheme(_ themeName: String) { + locationView.applyTheme(themeName) + locationTextField?.applyTheme(themeName) + + guard let theme = URLBarViewUX.Themes[themeName] else { + fatalError("Theme not found") + } + + let isPrivate = themeName == Theme.PrivateMode + + progressBar.setGradientColors(startColor: UIConstants.LoadingStartColor.color(isPBM: isPrivate), endColor: UIConstants.LoadingEndColor.color(isPBM: isPrivate)) + currentTheme = themeName + locationBorderColor = theme.borderColor! + locationActiveBorderColor = theme.activeBorderColor! + cancelTintColor = theme.buttonTintColor + showQRButtonTintColor = theme.buttonTintColor + backgroundColor = theme.backgroundColor + self.actionButtons.forEach { $0.applyTheme(themeName) } + tabsButton.applyTheme(themeName) + line.backgroundColor = UIConstants.URLBarDivider.color(isPBM: isPrivate) + locationContainer.layer.shadowColor = self.locationBorderColor.cgColor + } +} + +// We need a subclass so we can setup the shadows correctly +// This subclass creates a strong shadow on the URLBar +class TabLocationContainerView: UIView { + + struct LocationContainerUX { + static let CornerRadius: CGFloat = 4 + static let ShadowRadius: CGFloat = 2 + static let ShadowOpacity: Float = 1 + } + + override init(frame: CGRect) { + super.init(frame: frame) + let layer = self.layer + layer.cornerRadius = LocationContainerUX.CornerRadius + layer.shadowRadius = LocationContainerUX.ShadowRadius + layer.shadowOpacity = LocationContainerUX.ShadowOpacity + layer.masksToBounds = false + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + let layer = self.layer + + layer.shadowOffset = CGSize(width: 0, height: 1) + // the shadow appears 2px off from the view rect + let shadowLength: CGFloat = 2 + let shadowPath = CGRect(x: shadowLength, y: shadowLength, width: layer.frame.width - (shadowLength * 2), height: layer.frame.height - (shadowLength * 2)) + layer.shadowPath = UIBezierPath(roundedRect: shadowPath, cornerRadius: layer.cornerRadius).cgPath + super.layoutSubviews() + } +} + +class ToolbarTextField: AutocompleteTextField { + static let Themes: [String: Theme] = { + var themes = [String: Theme]() + var theme = Theme() + theme.backgroundColor = UIColor(rgb: 0x636369) + theme.textColor = UIColor.white + theme.buttonTintColor = UIColor.white + theme.highlightColor = UIConstants.PrivateModeInputHighlightColor + themes[Theme.PrivateMode] = theme + + theme = Theme() + theme.backgroundColor = .white + theme.textColor = UIColor(rgb: 0x272727) + theme.highlightColor = AutocompleteTextFieldUX.HighlightColor + themes[Theme.NormalMode] = theme + + return themes + }() + + dynamic var clearButtonTintColor: UIColor? { + didSet { + // Clear previous tinted image that's cache and ask for a relayout + tintedClearImage = nil + setNeedsLayout() + } + } + + fileprivate var tintedClearImage: UIImage? + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + // Since we're unable to change the tint color of the clear image, we need to iterate through the + // subviews, find the clear button, and tint it ourselves. Thanks to Mikael Hellman for the tip: + // http://stackoverflow.com/questions/27944781/how-to-change-the-tint-color-of-the-clear-button-on-a-uitextfield + for view in subviews as [UIView] { + if let button = view as? UIButton { + if let image = button.image(for: UIControlState()) { + if tintedClearImage == nil { + tintedClearImage = tintImage(image, color: clearButtonTintColor) + } + + if button.imageView?.image != tintedClearImage { + button.setImage(tintedClearImage, for: UIControlState()) + } + } + } + } + } + + fileprivate func tintImage(_ image: UIImage, color: UIColor?) -> UIImage { + guard let color = color else { return image } + + let size = image.size + + UIGraphicsBeginImageContextWithOptions(size, false, 2) + let context = UIGraphicsGetCurrentContext()! + image.draw(at: CGPoint.zero, blendMode: CGBlendMode.normal, alpha: 1.0) + + context.setFillColor(color.cgColor) + context.setBlendMode(CGBlendMode.sourceIn) + context.setAlpha(1.0) + + let rect = CGRect( + x: CGPoint.zero.x, + y: CGPoint.zero.y, + width: image.size.width, + height: image.size.height) + context.fill(rect) + let tintedImage = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + + return tintedImage + } +} + +extension ToolbarTextField: Themeable { + func applyTheme(_ themeName: String) { + guard let theme = ToolbarTextField.Themes[themeName] else { + fatalError("Theme not found") + } + + backgroundColor = theme.backgroundColor + textColor = theme.textColor + clearButtonTintColor = theme.buttonTintColor + highlightColor = theme.highlightColor! + } +} diff --git a/mobile/ios/Client/Frontend/ContentBlocker/ContentBlockerHelper.swift b/mobile/ios/Client/Frontend/ContentBlocker/ContentBlockerHelper.swift new file mode 100644 index 0000000000..46c50e96f9 --- /dev/null +++ b/mobile/ios/Client/Frontend/ContentBlocker/ContentBlockerHelper.swift @@ -0,0 +1,310 @@ +/* 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/. */ + +import WebKit +import Shared +import Deferred + +fileprivate let NotificationContentBlockerReloadNeeded = "NotificationContentBlockerReloadNeeded" + +@available(iOS 11.0, *) +class ContentBlockerHelper { + static let PrefKeyEnabledState = "prefkey.trackingprotection.enabled" + static let PrefKeyStrength = "prefkey.trackingprotection.strength" + fileprivate let blocklistBasic = ["disconnect-advertising", "disconnect-analytics", "disconnect-social"] + fileprivate let blocklistStrict = ["disconnect-content"] + fileprivate let ruleStore: WKContentRuleListStore + fileprivate weak var tab: Tab? + fileprivate weak var profile: Profile? + + static var blockImagesRule: WKContentRuleList? + + // Raw values are stored to prefs, be careful changing them. + enum EnabledState: String { + case on + case onInPrivateBrowsing + case off + + var settingTitle: String { + switch self { + case .on: + return Strings.TrackingProtectionOptionAlwaysOn + case .onInPrivateBrowsing: + return Strings.TrackingProtectionOptionOnInPrivateBrowsing + case .off: + return Strings.TrackingProtectionOptionAlwaysOff + } + } + + static let allOptions: [EnabledState] = [.on, .onInPrivateBrowsing, .off] + } + + // Raw values are stored to prefs, be careful changing them. + enum BlockingStrength: String { + case basic + case strict + + var settingTitle: String { + switch self { + case .basic: + return Strings.TrackingProtectionOptionBlockListTypeBasic + case .strict: + return Strings.TrackingProtectionOptionBlockListTypeStrict + } + } + + var subtitle: String { + switch self { + case .basic: + return Strings.TrackingProtectionOptionBlockListTypeBasicDescription + case .strict: + return Strings.TrackingProtectionOptionBlockListTypeStrictDescription + } + } + + static let allOptions: [BlockingStrength] = [.basic, .strict] + } + + static func prefsChanged() { + NotificationCenter.default.post(name: Notification.Name(rawValue: NotificationContentBlockerReloadNeeded), object: nil) + } + + class func name() -> String { + return "ContentBlockerHelper" + } + + private static var heavyInitHasRunOnce = false + + init(tab: Tab, profile: Profile) { + self.ruleStore = WKContentRuleListStore.default() + self.tab = tab + self.profile = profile + + if ContentBlockerHelper.heavyInitHasRunOnce { + return + } + ContentBlockerHelper.heavyInitHasRunOnce = true + + removeOldListsByDateFromStore() { + self.removeOldListsByNameFromStore() { + self.compileListsNotInStore(completion: {}) + } + } + + let blockImages = "[{'trigger':{'url-filter':'.*','resource-type':['image']},'action':{'type':'block'}}]".replacingOccurrences(of: "'", with: "\"") + ruleStore.compileContentRuleList(forIdentifier: "images", encodedContentRuleList: blockImages) { + rule, error in + assert(rule != nil && error == nil) + ContentBlockerHelper.blockImagesRule = rule + } + } + + func setupForWebView() { + NotificationCenter.default.addObserver(self, selector: #selector(ContentBlockerHelper.reloadTab), name: NSNotification.Name(rawValue: NotificationContentBlockerReloadNeeded), object: nil) + addActiveRulesToTab() + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + @objc func reloadTab() { + addActiveRulesToTab() + } + + fileprivate var blockingStrengthPref: BlockingStrength { + let pref = profile?.prefs.stringForKey(ContentBlockerHelper.PrefKeyStrength) ?? "" + return BlockingStrength(rawValue: pref) ?? .basic + } + + fileprivate var enabledStatePref: EnabledState { + let pref = profile?.prefs.stringForKey(ContentBlockerHelper.PrefKeyEnabledState) ?? "" + return EnabledState(rawValue: pref) ?? .onInPrivateBrowsing + } + + fileprivate func addActiveRulesToTab() { + guard let tab = tab else { return } + removeTrackingProtectionFromTab() + + switch enabledStatePref { + case .off: + return + case .on: + break + case .onInPrivateBrowsing: + if !tab.isPrivate { + return + } + } + + let rules = blocklistBasic + (blockingStrengthPref == .strict ? blocklistStrict : []) + for name in rules { + ruleStore.lookUpContentRuleList(forIdentifier: name) { rule, error in + guard let rule = rule else { + let msg = "lookUpContentRuleList for \(name): \(error?.localizedDescription ?? "empty rules")" + Sentry.shared.send(message: "Content blocker error", tag: .general, description: msg) + return + } + self.addToTab(contentRuleList: rule) + } + } + } + + func removeTrackingProtectionFromTab() { + guard let tab = tab else { return } + tab.webView?.configuration.userContentController.removeAllContentRuleLists() + + if let rule = ContentBlockerHelper.blockImagesRule, tab.noImageMode { + addToTab(contentRuleList: rule) + } + } + + fileprivate func addToTab(contentRuleList: WKContentRuleList) { + tab?.webView?.configuration.userContentController.add(contentRuleList) + } + + func noImageMode(enabled: Bool) { + guard let rule = ContentBlockerHelper.blockImagesRule else { return } + + if enabled { + addToTab(contentRuleList: rule) + } else { + tab?.webView?.configuration.userContentController.remove(rule) + } + + // Async required here to ensure remove() call is processed. + DispatchQueue.main.async() { + self.tab?.webView?.evaluateJavaScript("window.__firefox__.NoImageMode.setEnabled(\(enabled))", completionHandler: nil) + } + } +} + +// MARK: Private initialization code +// The rule store can compile JSON rule files into a private format which is cached on disk. +// On app boot, we need to check if the ruleStore's data is out-of-date, or if the names of the rule files +// no longer match. Finally, any JSON rule files that aren't in the ruleStore need to be compiled and stored in the +// ruleStore. +@available(iOS 11, *) +extension ContentBlockerHelper { + fileprivate func loadJsonFromBundle(forResource file: String, completion: @escaping (_ jsonString: String) -> Void) { + DispatchQueue.global().async { + guard let path = Bundle.main.path(forResource: file, ofType: "json"), + let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String else { + return + } + DispatchQueue.main.async { + completion(source) + } + } + } + + fileprivate func lastModifiedSince1970(forFileAtPath path: String) -> Timestamp? { + do { + let url = URL(fileURLWithPath: path) + let attr = try FileManager.default.attributesOfItem(atPath: url.path) + guard let date = attr[FileAttributeKey.modificationDate] as? Date else { return nil } + return UInt64(1000.0 * date.timeIntervalSince1970) + } catch { + return nil + } + } + + fileprivate func dateOfMostRecentBlockerFile() -> Timestamp { + let blocklists = blocklistBasic + blocklistStrict + return blocklists.reduce(Timestamp(0)) { result, filename in + guard let path = Bundle.main.path(forResource: filename, ofType: "json") else { return result } + let date = lastModifiedSince1970(forFileAtPath: path) ?? 0 + return date > result ? date : result + } + } + + fileprivate func removeAllRulesInStore(completion: @escaping () -> Void) { + ruleStore.getAvailableContentRuleListIdentifiers { available in + guard let available = available else { + completion() + return + } + let deferreds: [Deferred] = available.map { filename in + let result = Deferred() + self.ruleStore.removeContentRuleList(forIdentifier: filename) { _ in + result.fill() + } + return result + } + all(deferreds).uponQueue(.main) { _ in + completion() + } + } + } + + // If any blocker files are newer than the date saved in prefs, + // remove all the content blockers and reload them. + fileprivate func removeOldListsByDateFromStore(completion: @escaping () -> Void) { + let fileDate = self.dateOfMostRecentBlockerFile() + let prefsNewestDate = profile?.prefs.longForKey("blocker-file-date") ?? 0 + if prefsNewestDate < 1 || fileDate <= prefsNewestDate { + completion() + return + } + + profile?.prefs.setTimestamp(fileDate, forKey: "blocker-file-date") + self.removeAllRulesInStore() { + completion() + } + } + + fileprivate func removeOldListsByNameFromStore(completion: @escaping () -> Void) { + var noMatchingIdentifierFoundForRule = false + + ruleStore.getAvailableContentRuleListIdentifiers { available in + guard let available = available else { + completion() + return + } + + let blocklists = self.blocklistBasic + self.blocklistStrict + for contentRuleIdentifier in available { + if !blocklists.contains(where: { $0 == contentRuleIdentifier }) { + noMatchingIdentifierFoundForRule = true + break + } + } + + let fileDate = self.dateOfMostRecentBlockerFile() + let prefsNewestDate = self.profile?.prefs.timestampForKey("blocker-file-date") ?? 0 + if prefsNewestDate > 0 && fileDate <= prefsNewestDate && !noMatchingIdentifierFoundForRule { + completion() + return + } + self.profile?.prefs.setTimestamp(fileDate, forKey: "blocker-file-date") + + self.removeAllRulesInStore { + completion() + } + } + } + + fileprivate func compileListsNotInStore(completion: @escaping () -> Void) { + let blocklists = blocklistBasic + blocklistStrict + let deferreds: [Deferred] = blocklists.map { filename in + let result = Deferred() + ruleStore.lookUpContentRuleList(forIdentifier: filename) { contentRuleList, error in + if contentRuleList != nil { + result.fill() + return + } + self.loadJsonFromBundle(forResource: filename) { jsonString in + self.ruleStore.compileContentRuleList(forIdentifier: filename, encodedContentRuleList: jsonString) { _, _ in + result.fill() + } + } + } + return result + } + + all(deferreds).uponQueue(.main) { _ in + completion() + } + } +} diff --git a/mobile/ios/Client/Frontend/ContentBlocker/ContentBlockerSettingViewController.swift b/mobile/ios/Client/Frontend/ContentBlocker/ContentBlockerSettingViewController.swift new file mode 100644 index 0000000000..f497a36f0a --- /dev/null +++ b/mobile/ios/Client/Frontend/ContentBlocker/ContentBlockerSettingViewController.swift @@ -0,0 +1,99 @@ +/* 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/. */ + +import Foundation +import Shared + +@available(iOS 11.0, *) +class ContentBlockerSettingsTableView: SettingsTableViewController { + // The first section header gets a More Info link + override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + if section == 0 { + return super.tableView(tableView, viewForFooterInSection: section) + } + + // TODO: Get a dedicated string for this. + let title = NSLocalizedString("More Info…", tableName: "SendAnonymousUsageData", comment: "Re-using more info label from 'anonymous usage data' item for showing a 'More Info' link on the Tracking Protection settings screen.") + + var attributes = [String: AnyObject]() + attributes[NSFontAttributeName] = UIFont.systemFont(ofSize: 12, weight: UIFontWeightRegular) + attributes[NSForegroundColorAttributeName] = UIConstants.HighlightBlue + + let button = UIButton() + button.setAttributedTitle(NSAttributedString(string: title, attributes: attributes), for: .normal) + button.contentHorizontalAlignment = .left + // Top and left insets are needed to match the table row style. + button.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 0, right: 0) + button.addTarget(self, action: #selector(ContentBlockerSettingsTableView.moreInfoTapped), for: .touchUpInside) + return button + } + + func moreInfoTapped() { + let viewController = SettingsContentViewController() + viewController.url = SupportUtils.URLForTopic("tracking-protection-ios") + navigationController?.pushViewController(viewController, animated: true) + } +} + +@available(iOS 11.0, *) +class ContentBlockerSettingViewController: ContentBlockerSettingsTableView { + let prefs: Prefs + let EnabledStates = ContentBlockerHelper.EnabledState.allOptions + let BlockingStrengths = ContentBlockerHelper.BlockingStrength.allOptions + var currentEnabledState: ContentBlockerHelper.EnabledState + var currentBlockingStrength: ContentBlockerHelper.BlockingStrength + + init(prefs: Prefs) { + self.prefs = prefs + currentEnabledState = ContentBlockerHelper.EnabledState(rawValue: prefs.stringForKey(ContentBlockerHelper.PrefKeyEnabledState) ?? "") ?? .onInPrivateBrowsing + currentBlockingStrength = ContentBlockerHelper.BlockingStrength(rawValue: prefs.stringForKey(ContentBlockerHelper.PrefKeyStrength) ?? "") ?? .basic + + super.init(style: .grouped) + + self.title = Strings.SettingsTrackingProtectionSectionName + hasSectionSeparatorLine = false + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func generateSettings() -> [SettingSection] { + let enabledSetting: [CheckmarkSetting] = EnabledStates.map { option in + return CheckmarkSetting(title: NSAttributedString(string: option.settingTitle), subtitle: nil, isEnabled: { + return option == self.currentEnabledState + }, onChanged: { + self.currentEnabledState = option + self.prefs.setString(self.currentEnabledState.rawValue, forKey: ContentBlockerHelper.PrefKeyEnabledState) + self.tableView.reloadData() + ContentBlockerHelper.prefsChanged() + + LeanPlumClient.shared.track(event: .trackingProtectionSettings, withParameters: ["Enabled option": option.rawValue as AnyObject]) + UnifiedTelemetry.recordEvent(category: .action, method: .change, object: .setting, value: ContentBlockerHelper.PrefKeyEnabledState, extras: ["to": option.rawValue]) + }) + } + + let strengthSetting: [CheckmarkSetting] = BlockingStrengths.map { option in + return CheckmarkSetting(title: NSAttributedString(string: option.settingTitle), subtitle: NSAttributedString(string: option.subtitle), isEnabled: { + return option == self.currentBlockingStrength + }, onChanged: { + self.currentBlockingStrength = option + self.prefs.setString(self.currentBlockingStrength.rawValue, forKey: ContentBlockerHelper.PrefKeyStrength) + self.tableView.reloadData() + ContentBlockerHelper.prefsChanged() + + LeanPlumClient.shared.track(event: .trackingProtectionSettings, withParameters: ["Strength option": option.rawValue as AnyObject]) + UnifiedTelemetry.recordEvent(category: .action, method: .change, object: .setting, value: ContentBlockerHelper.PrefKeyStrength, extras: ["to": option.rawValue]) + }) + } + + let firstSection = SettingSection(title: NSAttributedString(string: Strings.TrackingProtectionOptionOnOffHeader), footerTitle: NSAttributedString(string: Strings.TrackingProtectionOptionOnOffFooter), children: enabledSetting) + + // The bottom of the block lists section has a More Info button, implemented as a custom footer view, + // SettingSection needs footerTitle set to create a footer, which we then override the view for. + let blockListsTitle = Strings.TrackingProtectionOptionBlockListsTitle + let secondSection = SettingSection(title: NSAttributedString(string: blockListsTitle), footerTitle: NSAttributedString(string: "placeholder replaced with UIButton"), children: strengthSetting) + return [firstSection, secondSection] + } +} diff --git a/mobile/ios/Client/Frontend/ContentBlocker/disconnect-advertising.json b/mobile/ios/Client/Frontend/ContentBlocker/disconnect-advertising.json new file mode 100644 index 0000000000..13520936c9 --- /dev/null +++ b/mobile/ios/Client/Frontend/ContentBlocker/disconnect-advertising.json @@ -0,0 +1 @@ +[{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?2leep\\.com","load-type":["third-party"],"unless-domain":["*2leep.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?33across\\.com","load-type":["third-party"],"unless-domain":["*33across.com","*tynt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?4info\\.com","load-type":["third-party"],"unless-domain":["*4info.com","*adhaven.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adhaven\\.com","load-type":["third-party"],"unless-domain":["*4info.com","*adhaven.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?4mads\\.com","load-type":["third-party"],"unless-domain":["*4mads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adeurope\\.com","load-type":["third-party"],"unless-domain":["*adeurope.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ad2onegroup\\.com","load-type":["third-party"],"unless-domain":["*ad2onegroup.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adition\\.com","load-type":["third-party"],"unless-domain":["*adition.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admission\\.net","load-type":["third-party"],"unless-domain":["*adpdealerservices.com","*admission.net","*cobalt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adpdealerservices\\.com","load-type":["third-party"],"unless-domain":["*adpdealerservices.com","*admission.net","*cobalt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cobalt\\.com","load-type":["third-party"],"unless-domain":["*adpdealerservices.com","*admission.net","*cobalt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtech\\.com","load-type":["third-party"],"unless-domain":["*adtech.com","*adtech.de","*adtechus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtech\\.de","load-type":["third-party"],"unless-domain":["*adtech.com","*adtech.de","*adtechus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtechus\\.com","load-type":["third-party"],"unless-domain":["*adtech.com","*adtech.de","*adtechus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtelligence\\.de","load-type":["third-party"],"unless-domain":["*adtelligence.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adzcentral\\.com","load-type":["third-party"],"unless-domain":["*adzcentral.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aerifymedia\\.com","load-type":["third-party"],"unless-domain":["*aerifymedia.com","*anonymous-media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?anonymous-media\\.com","load-type":["third-party"],"unless-domain":["*aerifymedia.com","*anonymous-media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aggregateknowledge\\.com","load-type":["third-party"],"unless-domain":["*aggregateknowledge.com","*agkn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?agkn\\.com","load-type":["third-party"],"unless-domain":["*aggregateknowledge.com","*agkn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsonar\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advertising\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?atwola\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?leadback\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tacoda\\.net","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hit-parade\\.com","load-type":["third-party"],"unless-domain":["*atinternet.com","*hit-parade.com","*xiti.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?att\\.com","load-type":["third-party"],"unless-domain":["*att.com","*yp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yp\\.com","load-type":["third-party"],"unless-domain":["*att.com","*yp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?affiliatetracking\\.com","load-type":["third-party"],"unless-domain":["*affiliatetracking.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?am\\.ua","load-type":["third-party"],"unless-domain":["*autocentre.ua","*am.ua"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?autocentre\\.ua","load-type":["third-party"],"unless-domain":["*autocentre.ua","*am.ua"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aweber\\.com","load-type":["third-party"],"unless-domain":["*aweber.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?abaxinteractive\\.com","load-type":["third-party"],"unless-domain":["*abaxinteractive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?accelia\\.net","load-type":["third-party"],"unless-domain":["*accelia.net","*durasite.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?durasite\\.net","load-type":["third-party"],"unless-domain":["*accelia.net","*durasite.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?accordantmedia\\.com","load-type":["third-party"],"unless-domain":["*accordantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?acquisio\\.com","load-type":["third-party"],"unless-domain":["*acquisio.com","*clickequations.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickequations\\.net","load-type":["third-party"],"unless-domain":["*acquisio.com","*clickequations.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?act-on\\.com","load-type":["third-party"],"unless-domain":["*act-on.com","*actonsoftware.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?actonsoftware\\.com","load-type":["third-party"],"unless-domain":["*act-on.com","*actonsoftware.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?actisens\\.com","load-type":["third-party"],"unless-domain":["*actisens.com","*gestionpub.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gestionpub\\.com","load-type":["third-party"],"unless-domain":["*actisens.com","*gestionpub.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?activeconversion\\.com","load-type":["third-party"],"unless-domain":["*activeconversion.com","*activemeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?activemeter\\.com","load-type":["third-party"],"unless-domain":["*activeconversion.com","*activemeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?acuity\\.com","load-type":["third-party"],"unless-domain":["*acuity.com","*acuityads.com","*acuityplatform.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?acuityads\\.com","load-type":["third-party"],"unless-domain":["*acuity.com","*acuityads.com","*acuityplatform.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?acuityplatform\\.com","load-type":["third-party"],"unless-domain":["*acuity.com","*acuityads.com","*acuityplatform.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?a2dfp\\.net","load-type":["third-party"],"unless-domain":["*addecisive.com","*a2dfp.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addecisive\\.com","load-type":["third-party"],"unless-domain":["*addecisive.com","*a2dfp.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addynamo\\.com","load-type":["third-party"],"unless-domain":["*addynamo.com","*addynamo.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addynamo\\.net","load-type":["third-party"],"unless-domain":["*addynamo.com","*addynamo.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adknife\\.com","load-type":["third-party"],"unless-domain":["*adknife.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admagnet\\.com","load-type":["third-party"],"unless-domain":["*admagnet.com","*admagnet.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admagnet\\.net","load-type":["third-party"],"unless-domain":["*admagnet.com","*admagnet.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ad4game\\.com","load-type":["third-party"],"unless-domain":["*ad4game.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbrain\\.com","load-type":["third-party"],"unless-domain":["*adbrain.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbrn\\.com","load-type":["third-party"],"unless-domain":["*adbrain.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adcirrus\\.com","load-type":["third-party"],"unless-domain":["*adcirrus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adengage\\.com","load-type":["third-party"],"unless-domain":["*adengage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adextent\\.com","load-type":["third-party"],"unless-domain":["*adextent.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adf\\.ly","load-type":["third-party"],"unless-domain":["*adf.ly"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adfox\\.ru","load-type":["third-party"],"unless-domain":["*adfox.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adfrontiers\\.com","load-type":["third-party"],"unless-domain":["*adfrontiers.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adgentdigital\\.com","load-type":["third-party"],"unless-domain":["*adgentdigital.com","*shorttailmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shorttailmedia\\.com","load-type":["third-party"],"unless-domain":["*adgentdigital.com","*shorttailmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adgibbon\\.com","load-type":["third-party"],"unless-domain":["*adgibbon.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adiquity\\.com","load-type":["third-party"],"unless-domain":["*adiquity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adinsight\\.com","load-type":["third-party"],"unless-domain":["*adinsight.com","*adinsight.eu"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adinsight\\.eu","load-type":["third-party"],"unless-domain":["*adinsight.com","*adinsight.eu"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adjug\\.com","load-type":["third-party"],"unless-domain":["*adjug.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adjuggler\\.com","load-type":["third-party"],"unless-domain":["*adjuggler.com","*adjuggler.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adjuggler\\.net","load-type":["third-party"],"unless-domain":["*adjuggler.com","*adjuggler.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adkeeper\\.com","load-type":["third-party"],"unless-domain":["*adkeeper.com","*akncdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?akncdn\\.com","load-type":["third-party"],"unless-domain":["*adkeeper.com","*akncdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adimg\\.net","load-type":["third-party"],"unless-domain":["*www.adlantis.jp","*adimg.net","*adlantis.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adlantis\\.jp","load-type":["third-party"],"unless-domain":["*www.adlantis.jp","*adimg.net","*adlantis.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adleave\\.com","load-type":["third-party"],"unless-domain":["*adleave.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admarvel\\.com","load-type":["third-party"],"unless-domain":["*admarvel.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admaximizer\\.com","load-type":["third-party"],"unless-domain":["*admaximizer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admedia\\.com","load-type":["third-party"],"unless-domain":["*admedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adnetwork\\.net","load-type":["third-party"],"unless-domain":["*adnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adocean-global\\.com","load-type":["third-party"],"unless-domain":["*adocean-global.com","*adocean.pl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adocean\\.pl","load-type":["third-party"],"unless-domain":["*adocean-global.com","*adocean.pl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adonnetwork\\.com","load-type":["third-party"],"unless-domain":["*adonnetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dashboardad\\.net","load-type":["third-party"],"unless-domain":["*adonnetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adonion\\.com","load-type":["third-party"],"unless-domain":["*adonion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adperfect\\.com","load-type":["third-party"],"unless-domain":["*adperfect.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adpredictive\\.com","load-type":["third-party"],"unless-domain":["*adpredictive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adreactor\\.com","load-type":["third-party"],"unless-domain":["*adreactor.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adready\\.com","load-type":["third-party"],"unless-domain":["*adready.com","*adreadytractions.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adreadytractions\\.com","load-type":["third-party"],"unless-domain":["*adready.com","*adreadytractions.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adrevolution\\.com","load-type":["third-party"],"unless-domain":["*adrevolution.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adriver\\.ru","load-type":["third-party"],"unless-domain":["*adriver.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adroll\\.com","load-type":["third-party"],"unless-domain":["*adroll.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsafemedia\\.com","load-type":["third-party"],"unless-domain":["*adsafemedia.com","*adsafeprotected.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsafeprotected\\.com","load-type":["third-party"],"unless-domain":["*adsafemedia.com","*adsafeprotected.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adserverpub\\.com","load-type":["third-party"],"unless-domain":["*adserverpub.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adshuffle\\.com","load-type":["third-party"],"unless-domain":["*adshuffle.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adside\\.com","load-type":["third-party"],"unless-domain":["*adside.com","*doclix.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?doclix\\.com","load-type":["third-party"],"unless-domain":["*adside.com","*doclix.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsmart\\.com","load-type":["third-party"],"unless-domain":["*adsmart.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adspeed\\.com","load-type":["third-party"],"unless-domain":["*adspeed.com","*adspeed.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adspeed\\.net","load-type":["third-party"],"unless-domain":["*adspeed.com","*adspeed.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adspirit\\.com","load-type":["third-party"],"unless-domain":["*adspirit.de","*adspirit.com","*adspirit.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adspirit\\.de","load-type":["third-party"],"unless-domain":["*adspirit.de","*adspirit.com","*adspirit.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adspirit\\.net","load-type":["third-party"],"unless-domain":["*adspirit.de","*adspirit.com","*adspirit.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtiger\\.de","load-type":["third-party"],"unless-domain":["*adtiger.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtruth\\.com","load-type":["third-party"],"unless-domain":["*adtruth.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adxpansion\\.com","load-type":["third-party"],"unless-domain":["*adxpansion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adaptiveads\\.com","load-type":["third-party"],"unless-domain":["*adaptiveads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adaptly\\.com","load-type":["third-party"],"unless-domain":["*adaptly.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adaramedia\\.com","load-type":["third-party"],"unless-domain":["*adaramedia.com","*opinmind.com","*yieldoptimizer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?opinmind\\.com","load-type":["third-party"],"unless-domain":["*adaramedia.com","*opinmind.com","*yieldoptimizer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yieldoptimizer\\.com","load-type":["third-party"],"unless-domain":["*adaramedia.com","*opinmind.com","*yieldoptimizer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adatus\\.com","load-type":["third-party"],"unless-domain":["*adatus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbroker\\.de","load-type":["third-party"],"unless-domain":["*adbroker.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adchemy\\.com","load-type":["third-party"],"unless-domain":["*adchemy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adconion\\.com","load-type":["third-party"],"unless-domain":["*adconion.com","*amgdgt.com","*euroclick.com","*smartclip.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amgdgt\\.com","load-type":["third-party"],"unless-domain":["*adconion.com","*amgdgt.com","*euroclick.com","*smartclip.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?euroclick\\.com","load-type":["third-party"],"unless-domain":["*adconion.com","*amgdgt.com","*euroclick.com","*smartclip.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?smartclip\\.com","load-type":["third-party"],"unless-domain":["*adconion.com","*amgdgt.com","*euroclick.com","*smartclip.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addvantagemedia\\.com","load-type":["third-party"],"unless-domain":["*addvantagemedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adfonic\\.com","load-type":["third-party"],"unless-domain":["*adfonic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adform\\.com","load-type":["third-party"],"unless-domain":["*adform.com","*adform.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adform\\.net","load-type":["third-party"],"unless-domain":["*adform.com","*adform.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adfunky\\.com","load-type":["third-party"],"unless-domain":["*adfunky.com","*adfunkyserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adfunkyserver\\.com","load-type":["third-party"],"unless-domain":["*adfunky.com","*adfunkyserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adfusion\\.com","load-type":["third-party"],"unless-domain":["*adfusion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adblade\\.com","load-type":["third-party"],"unless-domain":["*adiant.com","*adblade.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adiant\\.com","load-type":["third-party"],"unless-domain":["*adiant.com","*adblade.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adknowledge\\.com","load-type":["third-party"],"unless-domain":["*adknowledge.com","*adparlor.com","*bidsystem.com","*cubics.com","*lookery.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adparlor\\.com","load-type":["third-party"],"unless-domain":["*adknowledge.com","*adparlor.com","*bidsystem.com","*cubics.com","*lookery.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bidsystem\\.com","load-type":["third-party"],"unless-domain":["*adknowledge.com","*adparlor.com","*bidsystem.com","*cubics.com","*lookery.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cubics\\.com","load-type":["third-party"],"unless-domain":["*adknowledge.com","*adparlor.com","*bidsystem.com","*cubics.com","*lookery.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lookery\\.com","load-type":["third-party"],"unless-domain":["*adknowledge.com","*adparlor.com","*bidsystem.com","*cubics.com","*lookery.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adlibrium\\.com","load-type":["third-party"],"unless-domain":["*adlibrium.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admeta\\.com","load-type":["third-party"],"unless-domain":["*admeta.com","*atemda.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?atemda\\.com","load-type":["third-party"],"unless-domain":["*admeta.com","*atemda.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admicro\\.vn","load-type":["third-party"],"unless-domain":["*admicro.vn","*vcmedia.vn"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vcmedia\\.vn","load-type":["third-party"],"unless-domain":["*admicro.vn","*vcmedia.vn"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admobile\\.com","load-type":["third-party"],"unless-domain":["*admobile.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admotion\\.com","load-type":["third-party"],"unless-domain":["*admotion.com","*nspmotion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nspmotion\\.com","load-type":["third-party"],"unless-domain":["*admotion.com","*nspmotion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adnetik\\.com","load-type":["third-party"],"unless-domain":["*adnetik.com","*wtp101.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wtp101\\.com","load-type":["third-party"],"unless-domain":["*adnetik.com","*wtp101.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?2o7\\.net","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?auditude\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?demdex\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?demdex\\.net","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dmtracker\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?efrontier\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?everestads\\.net","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?everestjs\\.net","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?everesttech\\.net","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hitbox\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?omniture\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?omtrdc\\.net","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?touchclarity\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adometry\\.com","load-type":["third-party"],"unless-domain":["*adometry.com","*dmtry.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dmtry\\.com","load-type":["third-party"],"unless-domain":["*adometry.com","*dmtry.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickotmedia\\.com","load-type":["third-party"],"unless-domain":["*clickotmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adperium\\.com","load-type":["third-party"],"unless-domain":["*adperium.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adpersia\\.com","load-type":["third-party"],"unless-domain":["*adpersia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adstours\\.com","load-type":["third-party"],"unless-domain":["*adstours.com","*clickintext.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickintext\\.net","load-type":["third-party"],"unless-domain":["*adstours.com","*clickintext.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsnative\\.com","load-type":["third-party"],"unless-domain":["*adsnative.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsrevenue\\.net","load-type":["third-party"],"unless-domain":["*adsrevenue.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtegrity\\.com","load-type":["third-party"],"unless-domain":["*adtegrity.com","*adtegrity.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtegrity\\.net","load-type":["third-party"],"unless-domain":["*adtegrity.com","*adtegrity.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adultadworld\\.com","load-type":["third-party"],"unless-domain":["*adultadworld.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adultmoda\\.com","load-type":["third-party"],"unless-domain":["*adultmoda.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adnext\\.fr","load-type":["third-party"],"unless-domain":["*adverline.com","*adnext.fr"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adverline\\.com","load-type":["third-party"],"unless-domain":["*adverline.com","*adnext.fr"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adversal\\.com","load-type":["third-party"],"unless-domain":["*adversal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adv-adserver\\.com","load-type":["third-party"],"unless-domain":["*adversal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advertstream\\.com","load-type":["third-party"],"unless-domain":["*advertstream.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adverticum\\.com","load-type":["third-party"],"unless-domain":["*adverticum.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adverticum\\.net","load-type":["third-party"],"unless-domain":["*adverticum.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advertise\\.com","load-type":["third-party"],"unless-domain":["*advertise.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advertisespace\\.com","load-type":["third-party"],"unless-domain":["*advertisespace.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advisormedia\\.cz","load-type":["third-party"],"unless-domain":["*advisormedia.cz"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adworx\\.at","load-type":["third-party"],"unless-domain":["*adworx.at"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adworx\\.be","load-type":["third-party"],"unless-domain":["*adworx.at"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adworx\\.nl","load-type":["third-party"],"unless-domain":["*adworx.at"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adxvalue\\.com","load-type":["third-party"],"unless-domain":["*adxvalue.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adxvalue\\.de","load-type":["third-party"],"unless-domain":["*adxvalue.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adzerk\\.com","load-type":["third-party"],"unless-domain":["*adzerk.com","*adzerk.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adzerk\\.net","load-type":["third-party"],"unless-domain":["*adzerk.com","*adzerk.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aemedia\\.com","load-type":["third-party"],"unless-domain":["*aemedia.com","*bluestreak.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bluestreak\\.com","load-type":["third-party"],"unless-domain":["*aemedia.com","*bluestreak.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?affectv\\.co\\.uk","load-type":["third-party"],"unless-domain":["*affectv.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?affine\\.tv","load-type":["third-party"],"unless-domain":["*affine.tv","*affinesystems.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?affinesystems\\.com","load-type":["third-party"],"unless-domain":["*affine.tv","*affinesystems.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?afdads\\.com","load-type":["third-party"],"unless-domain":["*afterdownload.com","*afdads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?afterdownload\\.com","load-type":["third-party"],"unless-domain":["*afterdownload.com","*afdads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aim4media\\.com","load-type":["third-party"],"unless-domain":["*aim4media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?airpush\\.com","load-type":["third-party"],"unless-domain":["*airpush.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?imiclk\\.com","load-type":["third-party"],"unless-domain":["*akamai.com","*imiclk.com","*abmr.net","*edgesuite.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?allstarmediagroup\\.com","load-type":["third-party"],"unless-domain":["*allstarmediagroup.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ad\\.aloodo\\.com","load-type":["third-party"],"unless-domain":["*ad.aloodo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon-adsystem\\.com","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon\\.ca","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon\\.co\\.jp","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon\\.co\\.uk","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon\\.de","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon\\.es","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon\\.fr","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon\\.it","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?assoc-amazon\\.com","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adnetwork\\.vn","load-type":["third-party"],"unless-domain":["*ambientdigital.com.vn","*adnetwork.vn"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ambientdigital\\.com\\.vn","load-type":["third-party"],"unless-domain":["*ambientdigital.com.vn","*adnetwork.vn"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amobee\\.com","load-type":["third-party"],"unless-domain":["*amobee.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appflood\\.com","load-type":["third-party"],"unless-domain":["*appflood.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adlantic\\.nl","load-type":["third-party"],"unless-domain":["*appnexus.com","*adlantic.nl","*adnxs.com","*adrdgt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adnxs\\.com","load-type":["third-party"],"unless-domain":["*appnexus.com","*adlantic.nl","*adnxs.com","*adrdgt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adrdgt\\.com","load-type":["third-party"],"unless-domain":["*appnexus.com","*adlantic.nl","*adnxs.com","*adrdgt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appnexus\\.com","load-type":["third-party"],"unless-domain":["*appnexus.com","*adlantic.nl","*adnxs.com","*adrdgt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?alenty\\.com","load-type":["third-party"],"unless-domain":["*appnexus.com","*adlantic.nl","*adnxs.com","*adrdgt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appenda\\.com","load-type":["third-party"],"unless-domain":["*appenda.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appier\\.com","load-type":["third-party"],"unless-domain":["*appier.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?applifier\\.com","load-type":["third-party"],"unless-domain":["*applifier.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?applovin\\.com","load-type":["third-party"],"unless-domain":["*applovin.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?arkwrightshomebrew\\.com","load-type":["third-party"],"unless-domain":["*arkwrightshomebrew.com","*ctasnet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ctasnet\\.com","load-type":["third-party"],"unless-domain":["*arkwrightshomebrew.com","*ctasnet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?atoomic\\.com","load-type":["third-party"],"unless-domain":["*atoomic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?atrinsic\\.com","load-type":["third-party"],"unless-domain":["*atrinsic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?audienceadnetwork\\.com","load-type":["third-party"],"unless-domain":["*audienceadnetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?audience2media\\.com","load-type":["third-party"],"unless-domain":["*audience2media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?audiencescience\\.com","load-type":["third-party"],"unless-domain":["*audiencescience.com","*revsci.net","*targetingmarketplace.com","*wunderloop.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?revsci\\.net","load-type":["third-party"],"unless-domain":["*audiencescience.com","*revsci.net","*targetingmarketplace.com","*wunderloop.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?targetingmarketplace\\.com","load-type":["third-party"],"unless-domain":["*audiencescience.com","*revsci.net","*targetingmarketplace.com","*wunderloop.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wunderloop\\.net","load-type":["third-party"],"unless-domain":["*audiencescience.com","*revsci.net","*targetingmarketplace.com","*wunderloop.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?augme\\.com","load-type":["third-party"],"unless-domain":["*augme.com","*hipcricket.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hipcricket\\.com","load-type":["third-party"],"unless-domain":["*augme.com","*hipcricket.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?augur\\.io","load-type":["third-party"],"unless-domain":["*augur.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?avalanchers\\.com","load-type":["third-party"],"unless-domain":["*avalanchers.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?avantlink\\.com","load-type":["third-party"],"unless-domain":["*avantlink.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?avsads\\.com","load-type":["third-party"],"unless-domain":["*avsads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adgear\\.com","load-type":["third-party"],"unless-domain":["*bloom-hq.com","*adgear.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bloom-hq\\.com","load-type":["third-party"],"unless-domain":["*bloom-hq.com","*adgear.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adgrx\\.com","load-type":["third-party"],"unless-domain":["*bloom-hq.com","*adgear.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buzzcity\\.com","load-type":["third-party"],"unless-domain":["*buzzcity.com","*bvmedia.ca","*networldmedia.com","*networldmedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bvmedia\\.ca","load-type":["third-party"],"unless-domain":["*buzzcity.com","*bvmedia.ca","*networldmedia.com","*networldmedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?networldmedia\\.com","load-type":["third-party"],"unless-domain":["*buzzcity.com","*bvmedia.ca","*networldmedia.com","*networldmedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?networldmedia\\.net","load-type":["third-party"],"unless-domain":["*buzzcity.com","*bvmedia.ca","*networldmedia.com","*networldmedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?backbeatmedia\\.com","load-type":["third-party"],"unless-domain":["*backbeatmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bannerconnect\\.net","load-type":["third-party"],"unless-domain":["*bannerconnect.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?barilliance\\.com","load-type":["third-party"],"unless-domain":["*barilliance.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?baronsoffers\\.com","load-type":["third-party"],"unless-domain":["*baronsoffers.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?batanga\\.com","load-type":["third-party"],"unless-domain":["*batanganetwork.com","*batanga.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?batanganetwork\\.com","load-type":["third-party"],"unless-domain":["*batanganetwork.com","*batanga.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?beanstockmedia\\.com","load-type":["third-party"],"unless-domain":["*beanstockmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?begun\\.ru","load-type":["third-party"],"unless-domain":["*begun.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?betgenius\\.com","load-type":["third-party"],"unless-domain":["*betgenius.com","*connextra.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?connextra\\.com","load-type":["third-party"],"unless-domain":["*betgenius.com","*connextra.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bidvertiser\\.com","load-type":["third-party"],"unless-domain":["*bidvertiser.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bidswitch\\.net","load-type":["third-party"],"unless-domain":["*bidswitch.net","*bidswitch.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bidswitch\\.com","load-type":["third-party"],"unless-domain":["*bidswitch.net","*bidswitch.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?binlayer\\.com","load-type":["third-party"],"unless-domain":["*binlayer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bitcoinplus\\.com","load-type":["third-party"],"unless-domain":["*bitcoinplus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bittads\\.com","load-type":["third-party"],"unless-domain":["*bittads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bizo\\.com","load-type":["third-party"],"unless-domain":["*bizo.com","*bizographics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bizographics\\.com","load-type":["third-party"],"unless-domain":["*bizo.com","*bizographics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blacklabelads\\.com","load-type":["third-party"],"unless-domain":["*blacklabelads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blogcatalog\\.com","load-type":["third-party"],"unless-domain":["*blogcatalog.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?theblogfrog\\.com","load-type":["third-party"],"unless-domain":["*theblogfrog.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blogher\\.com","load-type":["third-party"],"unless-domain":["*blogher.com","*blogherads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blogherads\\.com","load-type":["third-party"],"unless-domain":["*blogher.com","*blogherads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blogrollr\\.com","load-type":["third-party"],"unless-domain":["*blogrollr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bloomreach\\.com","load-type":["third-party"],"unless-domain":["*bloomreach.com","*brcdn.com","*brsrvr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brcdn\\.com","load-type":["third-party"],"unless-domain":["*bloomreach.com","*brcdn.com","*brsrvr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brsrvr\\.com","load-type":["third-party"],"unless-domain":["*bloomreach.com","*brcdn.com","*brsrvr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blutrumpet\\.com","load-type":["third-party"],"unless-domain":["*blutrumpet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bluecava\\.com","load-type":["third-party"],"unless-domain":["*bluecava.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bkrtx\\.com","load-type":["third-party"],"unless-domain":["*bluekai.com","*bkrtx.com","*tracksimple.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bluekai\\.com","load-type":["third-party"],"unless-domain":["*bluekai.com","*bkrtx.com","*tracksimple.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tracksimple\\.com","load-type":["third-party"],"unless-domain":["*bluekai.com","*bkrtx.com","*tracksimple.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brainient\\.com","load-type":["third-party"],"unless-domain":["*brainient.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brandaffinity\\.net","load-type":["third-party"],"unless-domain":["*brandaffinity.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brand\\.net","load-type":["third-party"],"unless-domain":["*brand.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brandscreen\\.com","load-type":["third-party"],"unless-domain":["*brandscreen.com","*rtbidder.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rtbidder\\.net","load-type":["third-party"],"unless-domain":["*brandscreen.com","*rtbidder.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brightroll\\.com","load-type":["third-party"],"unless-domain":["*brightroll.com","*btrll.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?btrll\\.com","load-type":["third-party"],"unless-domain":["*brightroll.com","*btrll.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brighttag\\.com","load-type":["third-party"],"unless-domain":["*brighttag.com","*btstatic.com","*thebrighttag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?btstatic\\.com","load-type":["third-party"],"unless-domain":["*brighttag.com","*btstatic.com","*thebrighttag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thebrighttag\\.com","load-type":["third-party"],"unless-domain":["*brighttag.com","*btstatic.com","*thebrighttag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brilig\\.com","load-type":["third-party"],"unless-domain":["*brilig.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?burstbeacon\\.com","load-type":["third-party"],"unless-domain":["*burstmedia.com","*burstbeacon.com","*burstdirectads.com","*burstnet.com","*giantrealm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?burstdirectads\\.com","load-type":["third-party"],"unless-domain":["*burstmedia.com","*burstbeacon.com","*burstdirectads.com","*burstnet.com","*giantrealm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?burstmedia\\.com","load-type":["third-party"],"unless-domain":["*burstmedia.com","*burstbeacon.com","*burstdirectads.com","*burstnet.com","*giantrealm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?burstnet\\.com","load-type":["third-party"],"unless-domain":["*burstmedia.com","*burstbeacon.com","*burstdirectads.com","*burstnet.com","*giantrealm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?giantrealm\\.com","load-type":["third-party"],"unless-domain":["*burstmedia.com","*burstbeacon.com","*burstdirectads.com","*burstnet.com","*giantrealm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?burstly\\.com","load-type":["third-party"],"unless-domain":["*burstly.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?businessol\\.com","load-type":["third-party"],"unless-domain":["*businessol.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?beaconads\\.com","load-type":["third-party"],"unless-domain":["*buysellads.com","*beaconads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buysellads\\.com","load-type":["third-party"],"unless-domain":["*buysellads.com","*beaconads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buysight\\.com","load-type":["third-party"],"unless-domain":["*buysight.com","*permuto.com","*pulsemgr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?permuto\\.com","load-type":["third-party"],"unless-domain":["*buysight.com","*permuto.com","*pulsemgr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pulsemgr\\.com","load-type":["third-party"],"unless-domain":["*buysight.com","*permuto.com","*pulsemgr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buzzcity\\.com","load-type":["third-party"],"unless-domain":["*buzzcity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buzzparadise\\.com","load-type":["third-party"],"unless-domain":["*buzzparadise.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?capitaldata\\.fr","load-type":["third-party"],"unless-domain":["*capitaldata.fr"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cbproads\\.com","load-type":["third-party"],"unless-domain":["*cbproads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?contaxe\\.com","load-type":["third-party"],"unless-domain":["*contaxe.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?contextweb\\.com","load-type":["third-party"],"unless-domain":["*contextweb.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admailtiser\\.com","load-type":["third-party"],"unless-domain":["*contextin.com","*admailtiser.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?contextin\\.com","load-type":["third-party"],"unless-domain":["*contextin.com","*admailtiser.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cpmstar\\.com","load-type":["third-party"],"unless-domain":["*cpmstar.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cpxadroit\\.com","load-type":["third-party"],"unless-domain":["*cpxinteractive.com","*cpxadroit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cpxinteractive\\.com","load-type":["third-party"],"unless-domain":["*cpxinteractive.com","*cpxadroit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cadreon\\.com","load-type":["third-party"],"unless-domain":["*cadreon.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?campaigngrid\\.com","load-type":["third-party"],"unless-domain":["*campaigngrid.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?caraytech\\.com\\.ar","load-type":["third-party"],"unless-domain":["*www.caraytech.com.ar","*caraytech.com.ar","*e-planning.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?e-planning\\.net","load-type":["third-party"],"unless-domain":["*www.caraytech.com.ar","*caraytech.com.ar","*e-planning.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cart\\.ro","load-type":["third-party"],"unless-domain":["*cart.ro","*statistics.ro"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?statistics\\.ro","load-type":["third-party"],"unless-domain":["*cart.ro","*statistics.ro"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?casalemedia\\.com","load-type":["third-party"],"unless-domain":["*casalemedia.com","*medianet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?medianet\\.com","load-type":["third-party"],"unless-domain":["*casalemedia.com","*medianet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chango\\.ca","load-type":["third-party"],"unless-domain":["*chango.com","*chango.ca"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chango\\.com","load-type":["third-party"],"unless-domain":["*chango.com","*chango.ca"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?channelintelligence\\.com","load-type":["third-party"],"unless-domain":["*channelintelligence.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?channeladvisor\\.com","load-type":["third-party"],"unless-domain":["*channeladvisor.com","*searchmarketing.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?searchmarketing\\.com","load-type":["third-party"],"unless-domain":["*channeladvisor.com","*searchmarketing.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chartboost\\.com","load-type":["third-party"],"unless-domain":["*chartboost.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?checkm8\\.com","load-type":["third-party"],"unless-domain":["*checkm8.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chitika\\.com","load-type":["third-party"],"unless-domain":["*chitika.com","*chitika.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chitika\\.net","load-type":["third-party"],"unless-domain":["*chitika.com","*chitika.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?choicestream\\.com","load-type":["third-party"],"unless-domain":["*choicestream.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clearsaleing\\.com","load-type":["third-party"],"unless-domain":["*clearsaleing.com","*csdata1.com","*csdata2.com","*csdata3.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?csdata1\\.com","load-type":["third-party"],"unless-domain":["*clearsaleing.com","*csdata1.com","*csdata2.com","*csdata3.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?csdata2\\.com","load-type":["third-party"],"unless-domain":["*clearsaleing.com","*csdata1.com","*csdata2.com","*csdata3.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?csdata3\\.com","load-type":["third-party"],"unless-domain":["*clearsaleing.com","*csdata1.com","*csdata2.com","*csdata3.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clearsightinteractive\\.com","load-type":["third-party"],"unless-domain":["*clearsightinteractive.com","*csi-tracking.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?csi-tracking\\.com","load-type":["third-party"],"unless-domain":["*clearsightinteractive.com","*csi-tracking.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clearsearchmedia\\.com","load-type":["third-party"],"unless-domain":["*clearsearchmedia.com","*csm-secure.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?csm-secure\\.com","load-type":["third-party"],"unless-domain":["*clearsearchmedia.com","*csm-secure.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clicmanager\\.fr","load-type":["third-party"],"unless-domain":["*clicmanager.fr"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickaider\\.com","load-type":["third-party"],"unless-domain":["*clickaider.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickdimensions\\.com","load-type":["third-party"],"unless-domain":["*clickdimensions.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickdistrict\\.com","load-type":["third-party"],"unless-domain":["*clickdistrict.com","*creative-serving.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?creative-serving\\.com","load-type":["third-party"],"unless-domain":["*clickdistrict.com","*creative-serving.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?conversiondashboard\\.com","load-type":["third-party"],"unless-domain":["*clickfuel.com","*conversiondashboard.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickinc\\.com","load-type":["third-party"],"unless-domain":["*clickinc.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickbooth\\.com","load-type":["third-party"],"unless-domain":["*clickbooth.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtoll\\.com","load-type":["third-party"],"unless-domain":["*clickbooth.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clicksor\\.com","load-type":["third-party"],"unless-domain":["*clicksor.com","*clicksor.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clicksor\\.net","load-type":["third-party"],"unless-domain":["*clicksor.com","*clicksor.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickwinks\\.com","load-type":["third-party"],"unless-domain":["*clickwinks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clovenetwork\\.com","load-type":["third-party"],"unless-domain":["*clovenetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cmads\\.com\\.tw","load-type":["third-party"],"unless-domain":["*cognitivematch.com","*cmads.com.tw","*cmadsasia.com","*cmadseu.com","*cmmeglobal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cmadsasia\\.com","load-type":["third-party"],"unless-domain":["*cognitivematch.com","*cmads.com.tw","*cmadsasia.com","*cmadseu.com","*cmmeglobal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cmadseu\\.com","load-type":["third-party"],"unless-domain":["*cognitivematch.com","*cmads.com.tw","*cmadsasia.com","*cmadseu.com","*cmmeglobal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cmmeglobal\\.com","load-type":["third-party"],"unless-domain":["*cognitivematch.com","*cmads.com.tw","*cmadsasia.com","*cmadseu.com","*cmmeglobal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cognitivematch\\.com","load-type":["third-party"],"unless-domain":["*cognitivematch.com","*cmads.com.tw","*cmadsasia.com","*cmadseu.com","*cmmeglobal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?collective-media\\.net","load-type":["third-party"],"unless-domain":["*collective.com","*collective-media.net","*oggifinogi.com","*tumri.com","*tumri.net","*yt1187.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?collective\\.com","load-type":["third-party"],"unless-domain":["*collective.com","*collective-media.net","*oggifinogi.com","*tumri.com","*tumri.net","*yt1187.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oggifinogi\\.com","load-type":["third-party"],"unless-domain":["*collective.com","*collective-media.net","*oggifinogi.com","*tumri.com","*tumri.net","*yt1187.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tumri\\.com","load-type":["third-party"],"unless-domain":["*collective.com","*collective-media.net","*oggifinogi.com","*tumri.com","*tumri.net","*yt1187.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tumri\\.net","load-type":["third-party"],"unless-domain":["*collective.com","*collective-media.net","*oggifinogi.com","*tumri.com","*tumri.net","*yt1187.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yt1187\\.net","load-type":["third-party"],"unless-domain":["*collective.com","*collective-media.net","*oggifinogi.com","*tumri.com","*tumri.net","*yt1187.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?apmebf\\.com","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?awltovhc\\.com","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cj\\.com","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ftjcfx\\.com","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kcdwa\\.com","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?qksz\\.com","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?qksz\\.net","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tqlkg\\.com","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yceml\\.net","load-type":["third-party"],"unless-domain":["*cj.com","*apmebf.com","*awltovhc.com","*ftjcfx.com","*kcdwa.com","*qksz.com","*qksz.net","*tqlkg.com","*yceml.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?communicatorcorp\\.com","load-type":["third-party"],"unless-domain":["*communicatorcorp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?compasslabs\\.com","load-type":["third-party"],"unless-domain":["*compasslabs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?complex\\.com","load-type":["third-party"],"unless-domain":["*complexmedianetwork.com","*complex.com","*collider.com","*solecollector.com","*pigeonsandplanes.com","*theridechannel.com","*firstwefeast.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?complexmedianetwork\\.com","load-type":["third-party"],"unless-domain":["*complexmedianetwork.com","*complex.com","*collider.com","*solecollector.com","*pigeonsandplanes.com","*theridechannel.com","*firstwefeast.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?consiliummedia\\.com","load-type":["third-party"],"unless-domain":["*consiliummedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?agencytradingdesk\\.net","load-type":["third-party"],"unless-domain":["*contextuads.com","*agencytradingdesk.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?contextuads\\.com","load-type":["third-party"],"unless-domain":["*contextuads.com","*agencytradingdesk.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?convergedirect\\.com","load-type":["third-party"],"unless-domain":["*convergedirect.com","*convergetrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?convergetrack\\.com","load-type":["third-party"],"unless-domain":["*convergedirect.com","*convergetrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?conversionruler\\.com","load-type":["third-party"],"unless-domain":["*conversionruler.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?conversive\\.nl","load-type":["third-party"],"unless-domain":["*conversive.nl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?coremotives\\.com","load-type":["third-party"],"unless-domain":["*coremotives.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adify\\.com","load-type":["third-party"],"unless-domain":["*coxdigitalsolutions.com","*adify.com","*afy11.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?afy11\\.net","load-type":["third-party"],"unless-domain":["*coxdigitalsolutions.com","*adify.com","*afy11.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?coxdigitalsolutions\\.com","load-type":["third-party"],"unless-domain":["*coxdigitalsolutions.com","*adify.com","*afy11.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?creafi\\.com","load-type":["third-party"],"unless-domain":["*creafi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crimtan\\.com","load-type":["third-party"],"unless-domain":["*crimtan.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crispmedia\\.com","load-type":["third-party"],"unless-domain":["*crispmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?criteo\\.com","load-type":["third-party"],"unless-domain":["*criteo.com","*criteo.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?criteo\\.net","load-type":["third-party"],"unless-domain":["*criteo.com","*criteo.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crosspixel\\.net","load-type":["third-party"],"unless-domain":["*crosspixel.net","*crosspixelmedia.com","*crsspxl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crosspixelmedia\\.com","load-type":["third-party"],"unless-domain":["*crosspixel.net","*crosspixelmedia.com","*crsspxl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crsspxl\\.com","load-type":["third-party"],"unless-domain":["*crosspixel.net","*crosspixelmedia.com","*crsspxl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cyberplex\\.com","load-type":["third-party"],"unless-domain":["*cyberplex.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dc-storm\\.com","load-type":["third-party"],"unless-domain":["*dc-storm.com","*stormiq.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?stormiq\\.com","load-type":["third-party"],"unless-domain":["*dc-storm.com","*stormiq.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dgit\\.com","load-type":["third-party"],"unless-domain":["*dgit.com","*eyeblaster.com","*eyewonder.com","*mdadx.com","*serving-sys.com","*unicast.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eyeblaster\\.com","load-type":["third-party"],"unless-domain":["*dgit.com","*eyeblaster.com","*eyewonder.com","*mdadx.com","*serving-sys.com","*unicast.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eyewonder\\.com","load-type":["third-party"],"unless-domain":["*dgit.com","*eyeblaster.com","*eyewonder.com","*mdadx.com","*serving-sys.com","*unicast.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mdadx\\.com","load-type":["third-party"],"unless-domain":["*dgit.com","*eyeblaster.com","*eyewonder.com","*mdadx.com","*serving-sys.com","*unicast.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?serving-sys\\.com","load-type":["third-party"],"unless-domain":["*dgit.com","*eyeblaster.com","*eyewonder.com","*mdadx.com","*serving-sys.com","*unicast.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?unicast\\.com","load-type":["third-party"],"unless-domain":["*dgit.com","*eyeblaster.com","*eyewonder.com","*mdadx.com","*serving-sys.com","*unicast.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ds-iq\\.com","load-type":["third-party"],"unless-domain":["*ds-iq.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dsnrgroup\\.com","load-type":["third-party"],"unless-domain":["*dsnrmg.com","*dsnrgroup.com","*traffiliate.com","*z5x.com","*z5x.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dsnrmg\\.com","load-type":["third-party"],"unless-domain":["*dsnrmg.com","*dsnrgroup.com","*traffiliate.com","*z5x.com","*z5x.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?traffiliate\\.com","load-type":["third-party"],"unless-domain":["*dsnrmg.com","*dsnrgroup.com","*traffiliate.com","*z5x.com","*z5x.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?z5x\\.com","load-type":["third-party"],"unless-domain":["*dsnrmg.com","*dsnrgroup.com","*traffiliate.com","*z5x.com","*z5x.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?z5x\\.net","load-type":["third-party"],"unless-domain":["*dsnrmg.com","*dsnrgroup.com","*traffiliate.com","*z5x.com","*z5x.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dada\\.pro","load-type":["third-party"],"unless-domain":["*dada.pro","*simply.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?simply\\.com","load-type":["third-party"],"unless-domain":["*dada.pro","*simply.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dataxu\\.com","load-type":["third-party"],"unless-domain":["*dataxu.com","*dataxu.net","*mexad.com","*w55c.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dataxu\\.net","load-type":["third-party"],"unless-domain":["*dataxu.com","*dataxu.net","*mexad.com","*w55c.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mexad\\.com","load-type":["third-party"],"unless-domain":["*dataxu.com","*dataxu.net","*mexad.com","*w55c.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?w55c\\.net","load-type":["third-party"],"unless-domain":["*dataxu.com","*dataxu.net","*mexad.com","*w55c.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nexac\\.com","load-type":["third-party"],"unless-domain":["*datalogix.com","*nexac.com","*nextaction.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nextaction\\.net","load-type":["third-party"],"unless-domain":["*datalogix.com","*nexac.com","*nextaction.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?datonics\\.com","load-type":["third-party"],"unless-domain":["*datonics.com","*pro-market.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pro-market\\.net","load-type":["third-party"],"unless-domain":["*datonics.com","*pro-market.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?datranmedia\\.com","load-type":["third-party"],"unless-domain":["*datranmedia.com","*displaymarketplace.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?displaymarketplace\\.com","load-type":["third-party"],"unless-domain":["*datranmedia.com","*displaymarketplace.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?datvantage\\.com","load-type":["third-party"],"unless-domain":["*datvantage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dedicatedmedia\\.com","load-type":["third-party"],"unless-domain":["*dedicatedmedia.com","*dedicatednetworks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dedicatednetworks\\.com","load-type":["third-party"],"unless-domain":["*dedicatedmedia.com","*dedicatednetworks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?delivr\\.com","load-type":["third-party"],"unless-domain":["*delivr.com","*percentmobile.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?percentmobile\\.com","load-type":["third-party"],"unless-domain":["*delivr.com","*percentmobile.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adaction\\.se","load-type":["third-party"],"unless-domain":["*deltaprojects.se","*adaction.se","*de17a.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?de17a\\.com","load-type":["third-party"],"unless-domain":["*deltaprojects.se","*adaction.se","*de17a.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?deltaprojects\\.se","load-type":["third-party"],"unless-domain":["*deltaprojects.se","*adaction.se","*de17a.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?demandmedia\\.com","load-type":["third-party"],"unless-domain":["*demandmedia.com","*indieclick.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?indieclick\\.com","load-type":["third-party"],"unless-domain":["*demandmedia.com","*indieclick.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adcloud\\.com","load-type":["third-party"],"unless-domain":["*dp-dhl.com","*adcloud.com","*adcloud.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adcloud\\.net","load-type":["third-party"],"unless-domain":["*dp-dhl.com","*adcloud.com","*adcloud.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dp-dhl\\.com","load-type":["third-party"],"unless-domain":["*dp-dhl.com","*adcloud.com","*adcloud.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?developermedia\\.com","load-type":["third-party"],"unless-domain":["*developermedia.com","*lqcdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lqcdn\\.com","load-type":["third-party"],"unless-domain":["*developermedia.com","*lqcdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?did-it\\.com","load-type":["third-party"],"unless-domain":["*didit.com","*did-it.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?didit\\.com","load-type":["third-party"],"unless-domain":["*didit.com","*did-it.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?digitalriver\\.com","load-type":["third-party"],"unless-domain":["*digitalriver.com","*keywordmax.com","*netflame.cc"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?keywordmax\\.com","load-type":["third-party"],"unless-domain":["*digitalriver.com","*keywordmax.com","*netflame.cc"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netflame\\.cc","load-type":["third-party"],"unless-domain":["*digitalriver.com","*keywordmax.com","*netflame.cc"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?digitalwindow\\.com","load-type":["third-party"],"unless-domain":["*digitalwindow.com","*perfiliate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?perfiliate\\.com","load-type":["third-party"],"unless-domain":["*digitalwindow.com","*perfiliate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?digitize\\.ie","load-type":["third-party"],"unless-domain":["*digitize.ie"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?directresponsegroup\\.com","load-type":["third-party"],"unless-domain":["*directresponsegroup.com","*ppctracking.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ppctracking\\.net","load-type":["third-party"],"unless-domain":["*directresponsegroup.com","*ppctracking.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?directtrack\\.com","load-type":["third-party"],"unless-domain":["*directtrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?doublepimp\\.com","load-type":["third-party"],"unless-domain":["*doublepimp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bid-tag\\.com","load-type":["third-party"],"unless-domain":["*doublepositive.com","*bid-tag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?doublepositive\\.com","load-type":["third-party"],"unless-domain":["*doublepositive.com","*bid-tag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?doubleverify\\.com","load-type":["third-party"],"unless-domain":["*doubleverify.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsymptotic\\.com","load-type":["third-party"],"unless-domain":["*drawbrid.ge","*adsymptotic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?drawbrid\\.ge","load-type":["third-party"],"unless-domain":["*drawbrid.ge","*adsymptotic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dynamicoxygen\\.com","load-type":["third-party"],"unless-domain":["*dynamicoxygen.com","*exitjunction.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?exitjunction\\.com","load-type":["third-party"],"unless-domain":["*dynamicoxygen.com","*exitjunction.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eqads\\.com","load-type":["third-party"],"unless-domain":["*eqads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?extensions\\.ru","load-type":["third-party"],"unless-domain":["*extensions.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?earnify\\.com","load-type":["third-party"],"unless-domain":["*earnify.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?effectivemeasure\\.com","load-type":["third-party"],"unless-domain":["*effectivemeasure.com","*effectivemeasure.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?effectivemeasure\\.net","load-type":["third-party"],"unless-domain":["*effectivemeasure.com","*effectivemeasure.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eleavers\\.com","load-type":["third-party"],"unless-domain":["*eleavers.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?emediate\\.biz","load-type":["third-party"],"unless-domain":["*emediate.com","*emediate.biz","*emediate.dk","*emediate.eu"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?emediate\\.com","load-type":["third-party"],"unless-domain":["*emediate.com","*emediate.biz","*emediate.dk","*emediate.eu"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?emediate\\.dk","load-type":["third-party"],"unless-domain":["*emediate.com","*emediate.biz","*emediate.dk","*emediate.eu"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?emediate\\.eu","load-type":["third-party"],"unless-domain":["*emediate.com","*emediate.biz","*emediate.dk","*emediate.eu"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?usemax\\.de","load-type":["third-party"],"unless-domain":["*usemax.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?enecto\\.com","load-type":["third-party"],"unless-domain":["*enecto.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appmetrx\\.com","load-type":["third-party"],"unless-domain":["*engago.com","*appmetrx.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?engago\\.com","load-type":["third-party"],"unless-domain":["*engago.com","*appmetrx.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?enginenetwork\\.com","load-type":["third-party"],"unless-domain":["*enginenetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ensighten\\.com","load-type":["third-party"],"unless-domain":["*ensighten.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?entireweb\\.com","load-type":["third-party"],"unless-domain":["*entireweb.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?epicadvertising\\.com","load-type":["third-party"],"unless-domain":["*theepicmediagroup.com","*epicadvertising.com","*epicmarketplace.com","*epicmobileads.com","*trafficmp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?epicmarketplace\\.com","load-type":["third-party"],"unless-domain":["*theepicmediagroup.com","*epicadvertising.com","*epicmarketplace.com","*epicmobileads.com","*trafficmp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?epicmobileads\\.com","load-type":["third-party"],"unless-domain":["*theepicmediagroup.com","*epicadvertising.com","*epicmarketplace.com","*epicmobileads.com","*trafficmp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?theepicmediagroup\\.com","load-type":["third-party"],"unless-domain":["*theepicmediagroup.com","*epicadvertising.com","*epicmarketplace.com","*epicmobileads.com","*trafficmp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trafficmp\\.com","load-type":["third-party"],"unless-domain":["*theepicmediagroup.com","*epicadvertising.com","*epicmarketplace.com","*epicmobileads.com","*trafficmp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?epsilon\\.com","load-type":["third-party"],"unless-domain":["*epsilon.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ero-advertising\\.com","load-type":["third-party"],"unless-domain":["*ero-advertising.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?etargetnet\\.com","load-type":["third-party"],"unless-domain":["*etargetnet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?etarget\\.eu","load-type":["third-party"],"unless-domain":["*etargetnet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adwitserver\\.com","load-type":["third-party"],"unless-domain":["*etineria.com","*adwitserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?etineria\\.com","load-type":["third-party"],"unless-domain":["*etineria.com","*adwitserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?everydayhealth\\.com","load-type":["third-party"],"unless-domain":["*everydayhealth.com","*waterfrontmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?waterfrontmedia\\.com","load-type":["third-party"],"unless-domain":["*everydayhealth.com","*waterfrontmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?betrad\\.com","load-type":["third-party"],"unless-domain":["*evidon.com","*betrad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?evidon\\.com","load-type":["third-party"],"unless-domain":["*evidon.com","*betrad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?engineseeker\\.com","load-type":["third-party"],"unless-domain":["*evisionsmarketing.com","*engineseeker.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?evisionsmarketing\\.com","load-type":["third-party"],"unless-domain":["*evisionsmarketing.com","*engineseeker.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?evolvemediacorp\\.com","load-type":["third-party"],"unless-domain":["*evolvemediacorp.com","*evolvemediametrics.com","*gorillanation.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?evolvemediametrics\\.com","load-type":["third-party"],"unless-domain":["*evolvemediacorp.com","*evolvemediametrics.com","*gorillanation.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gorillanation\\.com","load-type":["third-party"],"unless-domain":["*evolvemediacorp.com","*evolvemediametrics.com","*gorillanation.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?exoclick\\.com","load-type":["third-party"],"unless-domain":["*exoclick.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?audienceiq\\.com","load-type":["third-party"],"unless-domain":["*experian.com","*audienceiq.com","*pricegrabber.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?experian\\.com","load-type":["third-party"],"unless-domain":["*experian.com","*audienceiq.com","*pricegrabber.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pricegrabber\\.com","load-type":["third-party"],"unless-domain":["*experian.com","*audienceiq.com","*pricegrabber.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adotube\\.com","load-type":["third-party"],"unless-domain":["*exponential.com","*adotube.com","*fulltango.com","*tribalfusion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?exponential\\.com","load-type":["third-party"],"unless-domain":["*exponential.com","*adotube.com","*fulltango.com","*tribalfusion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fulltango\\.com","load-type":["third-party"],"unless-domain":["*exponential.com","*adotube.com","*fulltango.com","*tribalfusion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tribalfusion\\.com","load-type":["third-party"],"unless-domain":["*exponential.com","*adotube.com","*fulltango.com","*tribalfusion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?extensionfactory\\.com","load-type":["third-party"],"unless-domain":["*extensionfactory.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eyeconomy\\.co\\.uk","load-type":["third-party"],"unless-domain":["*www.eyeconomy.co.uk","*eyeconomy.co.uk","*eyeconomy.com","*sublimemedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eyeconomy\\.com","load-type":["third-party"],"unless-domain":["*www.eyeconomy.co.uk","*eyeconomy.co.uk","*eyeconomy.com","*sublimemedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sublimemedia\\.net","load-type":["third-party"],"unless-domain":["*www.eyeconomy.co.uk","*eyeconomy.co.uk","*eyeconomy.com","*sublimemedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eyeviewdigital\\.com","load-type":["third-party"],"unless-domain":["*eyeviewdigital.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eyeviewads\\.com","load-type":["third-party"],"unless-domain":["*eyeviewdigital.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsfac\\.eu","load-type":["third-party"],"unless-domain":["*facilitatedigital.com","*adsfac.eu","*adsfac.info","*adsfac.net","*adsfac.sg","*adsfac.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsfac\\.info","load-type":["third-party"],"unless-domain":["*facilitatedigital.com","*adsfac.eu","*adsfac.info","*adsfac.net","*adsfac.sg","*adsfac.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsfac\\.net","load-type":["third-party"],"unless-domain":["*facilitatedigital.com","*adsfac.eu","*adsfac.info","*adsfac.net","*adsfac.sg","*adsfac.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsfac\\.sg","load-type":["third-party"],"unless-domain":["*facilitatedigital.com","*adsfac.eu","*adsfac.info","*adsfac.net","*adsfac.sg","*adsfac.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsfac\\.us","load-type":["third-party"],"unless-domain":["*facilitatedigital.com","*adsfac.eu","*adsfac.info","*adsfac.net","*adsfac.sg","*adsfac.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?facilitatedigital\\.com","load-type":["third-party"],"unless-domain":["*facilitatedigital.com","*adsfac.eu","*adsfac.info","*adsfac.net","*adsfac.sg","*adsfac.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fairfax\\.com\\.au","load-type":["third-party"],"unless-domain":["*www.fxj.com.au","*fairfax.com.au","*fxj.com.au"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fxj\\.com\\.au","load-type":["third-party"],"unless-domain":["*www.fxj.com.au","*fairfax.com.au","*fxj.com.au"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fathomdelivers\\.com","load-type":["third-party"],"unless-domain":["*fathomdelivers.com","*fathomseo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fathomseo\\.com","load-type":["third-party"],"unless-domain":["*fathomdelivers.com","*fathomseo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?federatedmedia\\.net","load-type":["third-party"],"unless-domain":["*federatedmedia.net","*fmpub.net","*lijit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fmpub\\.net","load-type":["third-party"],"unless-domain":["*federatedmedia.net","*fmpub.net","*lijit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lijit\\.com","load-type":["third-party"],"unless-domain":["*federatedmedia.net","*fmpub.net","*lijit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fetchback\\.com","load-type":["third-party"],"unless-domain":["*fetchback.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fiksu\\.com","load-type":["third-party"],"unless-domain":["*fiksu.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?financialcontent\\.com","load-type":["third-party"],"unless-domain":["*financialcontent.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fizzbuzzmedia\\.com","load-type":["third-party"],"unless-domain":["*fizzbuzzmedia.com","*fizzbuzzmedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fizzbuzzmedia\\.net","load-type":["third-party"],"unless-domain":["*fizzbuzzmedia.com","*fizzbuzzmedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?flashtalking\\.com","load-type":["third-party"],"unless-domain":["*flashtalking.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?flite\\.com","load-type":["third-party"],"unless-domain":["*flite.com","*widgetserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?widgetserver\\.com","load-type":["third-party"],"unless-domain":["*flite.com","*widgetserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?flurry\\.com","load-type":["third-party"],"unless-domain":["*flurry.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?flytxt\\.com","load-type":["third-party"],"unless-domain":["*flytxt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brandsideplatform\\.com","load-type":["third-party"],"unless-domain":["*forbes.com","*brandsideplatform.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?forbes\\.com","load-type":["third-party"],"unless-domain":["*forbes.com","*brandsideplatform.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fimserve\\.com","load-type":["third-party"],"unless-domain":["*foxonestop.com","*fimserve.com","*foxnetworks.com","*mobsmith.com","*myads.com","*othersonline.com","*rubiconproject.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?foxnetworks\\.com","load-type":["third-party"],"unless-domain":["*foxonestop.com","*fimserve.com","*foxnetworks.com","*mobsmith.com","*myads.com","*othersonline.com","*rubiconproject.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?foxonestop\\.com","load-type":["third-party"],"unless-domain":["*foxonestop.com","*fimserve.com","*foxnetworks.com","*mobsmith.com","*myads.com","*othersonline.com","*rubiconproject.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mobsmith\\.com","load-type":["third-party"],"unless-domain":["*foxonestop.com","*fimserve.com","*foxnetworks.com","*mobsmith.com","*myads.com","*othersonline.com","*rubiconproject.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?myads\\.com","load-type":["third-party"],"unless-domain":["*foxonestop.com","*fimserve.com","*foxnetworks.com","*mobsmith.com","*myads.com","*othersonline.com","*rubiconproject.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?othersonline\\.com","load-type":["third-party"],"unless-domain":["*foxonestop.com","*fimserve.com","*foxnetworks.com","*mobsmith.com","*myads.com","*othersonline.com","*rubiconproject.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rubiconproject\\.com","load-type":["third-party"],"unless-domain":["*foxonestop.com","*fimserve.com","*foxnetworks.com","*mobsmith.com","*myads.com","*othersonline.com","*rubiconproject.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fout\\.jp","load-type":["third-party"],"unless-domain":["*fout.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?freedom\\.com","load-type":["third-party"],"unless-domain":["*freedom.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adultfriendfinder\\.com","load-type":["third-party"],"unless-domain":["*ffn.com","*adultfriendfinder.com","*pop6.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ffn\\.com","load-type":["third-party"],"unless-domain":["*ffn.com","*adultfriendfinder.com","*pop6.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pop6\\.com","load-type":["third-party"],"unless-domain":["*ffn.com","*adultfriendfinder.com","*pop6.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?double-check\\.com","load-type":["third-party"],"unless-domain":["*frogsex.com","*double-check.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?frogsex\\.com","load-type":["third-party"],"unless-domain":["*frogsex.com","*double-check.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?futureads\\.com","load-type":["third-party"],"unless-domain":["*futureads.com","*resultlinks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?resultlinks\\.com","load-type":["third-party"],"unless-domain":["*futureads.com","*resultlinks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gb-world\\.net","load-type":["third-party"],"unless-domain":["*gb-world.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?geniegroupltd\\.co\\.uk","load-type":["third-party"],"unless-domain":["*www.geniegroupltd.co.uk","*geniegroupltd.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gismads\\.jp","load-type":["third-party"],"unless-domain":["*www.gismads.jp","*gismads.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gsicommerce\\.com","load-type":["third-party"],"unless-domain":["*gsicommerce.com","*gsimedia.net","*pepperjam.com","*pjatr.com","*pjtra.com","*pntra.com","*pntrac.com","*pntrs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gsimedia\\.net","load-type":["third-party"],"unless-domain":["*gsicommerce.com","*gsimedia.net","*pepperjam.com","*pjatr.com","*pjtra.com","*pntra.com","*pntrac.com","*pntrs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pepperjam\\.com","load-type":["third-party"],"unless-domain":["*gsicommerce.com","*gsimedia.net","*pepperjam.com","*pjatr.com","*pjtra.com","*pntra.com","*pntrac.com","*pntrs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pjatr\\.com","load-type":["third-party"],"unless-domain":["*gsicommerce.com","*gsimedia.net","*pepperjam.com","*pjatr.com","*pjtra.com","*pntra.com","*pntrac.com","*pntrs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pjtra\\.com","load-type":["third-party"],"unless-domain":["*gsicommerce.com","*gsimedia.net","*pepperjam.com","*pjatr.com","*pjtra.com","*pntra.com","*pntrac.com","*pntrs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pntra\\.com","load-type":["third-party"],"unless-domain":["*gsicommerce.com","*gsimedia.net","*pepperjam.com","*pjatr.com","*pjtra.com","*pntra.com","*pntrac.com","*pntrs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pntrac\\.com","load-type":["third-party"],"unless-domain":["*gsicommerce.com","*gsimedia.net","*pepperjam.com","*pjatr.com","*pjtra.com","*pntra.com","*pntrac.com","*pntrs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pntrs\\.com","load-type":["third-party"],"unless-domain":["*gsicommerce.com","*gsimedia.net","*pepperjam.com","*pjatr.com","*pjtra.com","*pntra.com","*pntrac.com","*pntrs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?game-advertising-online\\.com","load-type":["third-party"],"unless-domain":["*game-advertising-online.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?games2win\\.com","load-type":["third-party"],"unless-domain":["*games2win.com","*inviziads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inviziads\\.com","load-type":["third-party"],"unless-domain":["*games2win.com","*inviziads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gamned\\.com","load-type":["third-party"],"unless-domain":["*gamned.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gannett\\.com","load-type":["third-party"],"unless-domain":["*gannett.com","*pointroll.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pointroll\\.com","load-type":["third-party"],"unless-domain":["*gannett.com","*pointroll.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gemius\\.com","load-type":["third-party"],"unless-domain":["*gemius.com","*gemius.pl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gemius\\.pl","load-type":["third-party"],"unless-domain":["*gemius.com","*gemius.pl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?geoads\\.com","load-type":["third-party"],"unless-domain":["*geoads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?getglue\\.com","load-type":["third-party"],"unless-domain":["*getglue.com","*smrtlnks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?smrtlnks\\.com","load-type":["third-party"],"unless-domain":["*getglue.com","*smrtlnks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?glam\\.com","load-type":["third-party"],"unless-domain":["*glammedia.com","*glam.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?glammedia\\.com","load-type":["third-party"],"unless-domain":["*glammedia.com","*glam.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?globe7\\.com","load-type":["third-party"],"unless-domain":["*globe7.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?godatafeed\\.com","load-type":["third-party"],"unless-domain":["*godatafeed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?goldspotmedia\\.com","load-type":["third-party"],"unless-domain":["*goldspotmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?2mdn\\.net","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admeld\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admob\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cc-dt\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?destinationurl\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?doubleclick\\.net","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adwords\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?googleadservices\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?googlesyndication\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?googletagservices\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?invitemedia\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?smtad\\.net","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?teracent\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?teracent\\.net","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ytsa\\.net","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?grapeshot\\.co\\.uk","load-type":["third-party"],"unless-domain":["*www.grapeshot.co.uk","*grapeshot.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?groceryshopping\\.net","load-type":["third-party"],"unless-domain":["*groceryshopping.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?groovinads\\.com","load-type":["third-party"],"unless-domain":["*groovinads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?guj\\.de","load-type":["third-party"],"unless-domain":["*guj.de","*ligatus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ligatus\\.com","load-type":["third-party"],"unless-domain":["*guj.de","*ligatus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gumgum\\.com","load-type":["third-party"],"unless-domain":["*gumgum.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gunggo\\.com","load-type":["third-party"],"unless-domain":["*gunggo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hotwords\\.com","load-type":["third-party"],"unless-domain":["*hotwords.com","*hotwords.es"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hotwords\\.es","load-type":["third-party"],"unless-domain":["*hotwords.com","*hotwords.es"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hp\\.com","load-type":["third-party"],"unless-domain":["*hp.com","*optimost.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?optimost\\.com","load-type":["third-party"],"unless-domain":["*hp.com","*optimost.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?huntmads\\.com","load-type":["third-party"],"unless-domain":["*huntmads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hands\\.com\\.br","load-type":["third-party"],"unless-domain":["*www.hands.com.br","*hands.com.br"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?harrenmedia\\.com","load-type":["third-party"],"unless-domain":["*harrenmedia.com","*harrenmedianetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?harrenmedianetwork\\.com","load-type":["third-party"],"unless-domain":["*harrenmedia.com","*harrenmedianetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adacado\\.com","load-type":["third-party"],"unless-domain":["*healthpricer.com","*adacado.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?healthpricer\\.com","load-type":["third-party"],"unless-domain":["*healthpricer.com","*adacado.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hearst\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ic-live\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iclive\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?icrossing\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sptag\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sptag1\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sptag2\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sptag3\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?comclick\\.com","load-type":["third-party"],"unless-domain":["*hi-media.com","*comclick.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hi-media\\.com","load-type":["third-party"],"unless-domain":["*hi-media.com","*comclick.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hlserve\\.com","load-type":["third-party"],"unless-domain":["*hooklogic.com","*hlserve.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hooklogic\\.com","load-type":["third-party"],"unless-domain":["*hooklogic.com","*hlserve.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?horyzon-media\\.com","load-type":["third-party"],"unless-domain":["*horyzon-media.com","*meetic-partners.com","*smartadserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?meetic-partners\\.com","load-type":["third-party"],"unless-domain":["*horyzon-media.com","*meetic-partners.com","*smartadserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?smartadserver\\.com","load-type":["third-party"],"unless-domain":["*horyzon-media.com","*meetic-partners.com","*smartadserver.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?httpool\\.com","load-type":["third-party"],"unless-domain":["*httpool.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hurra\\.com","load-type":["third-party"],"unless-domain":["*hurra.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?i-behavior\\.com","load-type":["third-party"],"unless-domain":["*i-behavior.com","*ib-ibi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ib-ibi\\.com","load-type":["third-party"],"unless-domain":["*i-behavior.com","*ib-ibi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?i\\.ua","load-type":["third-party"],"unless-domain":["*i.ua"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iac\\.com","load-type":["third-party"],"unless-domain":["*iac.com","*iacadvertising.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iacadvertising\\.com","load-type":["third-party"],"unless-domain":["*iac.com","*iacadvertising.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?unica\\.com","load-type":["third-party"],"unless-domain":["*ibm.com","*unica.com","*cmcore.com","*coremetrics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?idg\\.com","load-type":["third-party"],"unless-domain":["*idg.com","*idgtechnetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?idgtechnetwork\\.com","load-type":["third-party"],"unless-domain":["*idg.com","*idgtechnetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adversalservers\\.com","load-type":["third-party"],"unless-domain":["*digbro.com","*adversalservers.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?digbro\\.com","load-type":["third-party"],"unless-domain":["*digbro.com","*adversalservers.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ignitad\\.com","load-type":["third-party"],"unless-domain":["*ignitad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ignitionone\\.com","load-type":["third-party"],"unless-domain":["*ignitionone.com","*ignitionone.net","*searchignite.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ignitionone\\.net","load-type":["third-party"],"unless-domain":["*ignitionone.com","*ignitionone.net","*searchignite.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?searchignite\\.com","load-type":["third-party"],"unless-domain":["*ignitionone.com","*ignitionone.net","*searchignite.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?360yield\\.com","load-type":["third-party"],"unless-domain":["*improvedigital.com","*360yield.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?improvedigital\\.com","load-type":["third-party"],"unless-domain":["*improvedigital.com","*360yield.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inmobi\\.com","load-type":["third-party"],"unless-domain":["*inmobi.com","*sproutinc.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sproutinc\\.com","load-type":["third-party"],"unless-domain":["*inmobi.com","*sproutinc.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inskinmedia\\.com","load-type":["third-party"],"unless-domain":["*inskinmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?anadcoads\\.com","load-type":["third-party"],"unless-domain":["*inadco.com","*anadcoads.com","*inadcoads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inadco\\.com","load-type":["third-party"],"unless-domain":["*inadco.com","*anadcoads.com","*inadcoads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inadcoads\\.com","load-type":["third-party"],"unless-domain":["*inadco.com","*anadcoads.com","*inadcoads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?impressiondesk\\.com","load-type":["third-party"],"unless-domain":["*infectiousmedia.com","*impressiondesk.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?infectiousmedia\\.com","load-type":["third-party"],"unless-domain":["*infectiousmedia.com","*impressiondesk.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inflectionpointmedia\\.com","load-type":["third-party"],"unless-domain":["*inflectionpointmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?infogroup\\.com","load-type":["third-party"],"unless-domain":["*infogroup.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?infolinks\\.com","load-type":["third-party"],"unless-domain":["*infolinks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?infra-ad\\.com","load-type":["third-party"],"unless-domain":["*infra-ad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?innity\\.com","load-type":["third-party"],"unless-domain":["*innity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?insightexpress\\.com","load-type":["third-party"],"unless-domain":["*insightexpress.com","*insightexpressai.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?insightexpressai\\.com","load-type":["third-party"],"unless-domain":["*insightexpress.com","*insightexpressai.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intentmedia\\.com","load-type":["third-party"],"unless-domain":["*intentmedia.com","*intentmedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intentmedia\\.net","load-type":["third-party"],"unless-domain":["*intentmedia.com","*intentmedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intergi\\.com","load-type":["third-party"],"unless-domain":["*intergi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intermarkets\\.net","load-type":["third-party"],"unless-domain":["*intermarkets.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intermundomedia\\.com","load-type":["third-party"],"unless-domain":["*intermundomedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ibpxl\\.com","load-type":["third-party"],"unless-domain":["*internetbrands.com","*ibpxl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?internetbrands\\.com","load-type":["third-party"],"unless-domain":["*internetbrands.com","*ibpxl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?interpolls\\.com","load-type":["third-party"],"unless-domain":["*interpolls.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inuvo\\.com","load-type":["third-party"],"unless-domain":["*inuvo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?investingchannel\\.com","load-type":["third-party"],"unless-domain":["*investingchannel.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jaroop\\.com","load-type":["third-party"],"unless-domain":["*jaroop.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jasperlabs\\.com","load-type":["third-party"],"unless-domain":["*jasperlabs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jemmgroup\\.com","load-type":["third-party"],"unless-domain":["*jemmgroup.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jink\\.de","load-type":["third-party"],"unless-domain":["*jink.de","*jinkads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jinkads\\.com","load-type":["third-party"],"unless-domain":["*jink.de","*jinkads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adcolony\\.com","load-type":["third-party"],"unless-domain":["*jirbo.com","*adcolony.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jirbo\\.com","load-type":["third-party"],"unless-domain":["*jirbo.com","*adcolony.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jivox\\.com","load-type":["third-party"],"unless-domain":["*jivox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jobthread\\.com","load-type":["third-party"],"unless-domain":["*jobthread.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?juicyads\\.com","load-type":["third-party"],"unless-domain":["*juicyads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?jumptap\\.com","load-type":["third-party"],"unless-domain":["*jumptap.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?keewurd\\.com","load-type":["third-party"],"unless-domain":["*kitd.com","*keewurd.com","*peerset.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kitd\\.com","load-type":["third-party"],"unless-domain":["*kitd.com","*keewurd.com","*peerset.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?peerset\\.com","load-type":["third-party"],"unless-domain":["*kitd.com","*keewurd.com","*peerset.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kenshoo\\.com","load-type":["third-party"],"unless-domain":["*kenshoo.com","*xg4ken.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xg4ken\\.com","load-type":["third-party"],"unless-domain":["*kenshoo.com","*xg4ken.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?keyade\\.com","load-type":["third-party"],"unless-domain":["*keyade.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kissmyads\\.com","load-type":["third-party"],"unless-domain":["*kissmyads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?103092804\\.com","load-type":["third-party"],"unless-domain":["*kitaramedia.com","*103092804.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kitaramedia\\.com","load-type":["third-party"],"unless-domain":["*kitaramedia.com","*103092804.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admost\\.com","load-type":["third-party"],"unless-domain":["*kokteyl.com","*admost.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kokteyl\\.com","load-type":["third-party"],"unless-domain":["*kokteyl.com","*admost.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?komli\\.com","load-type":["third-party"],"unless-domain":["*komli.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kontera\\.com","load-type":["third-party"],"unless-domain":["*kontera.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsummos\\.com","load-type":["third-party"],"unless-domain":["*korrelate.com","*adsummos.com","*adsummos.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsummos\\.net","load-type":["third-party"],"unless-domain":["*korrelate.com","*adsummos.com","*adsummos.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?korrelate\\.com","load-type":["third-party"],"unless-domain":["*korrelate.com","*adsummos.com","*adsummos.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?krux\\.com","load-type":["third-party"],"unless-domain":["*krux.com","*kruxdigital.com","*krxd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kruxdigital\\.com","load-type":["third-party"],"unless-domain":["*krux.com","*kruxdigital.com","*krxd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?krxd\\.net","load-type":["third-party"],"unless-domain":["*krux.com","*kruxdigital.com","*krxd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lakana\\.com","load-type":["third-party"],"unless-domain":["*lakana.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ibsys\\.com","load-type":["third-party"],"unless-domain":["*lakana.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?layer-ads\\.net","load-type":["third-party"],"unless-domain":["*layer-ads.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?layer-ad\\.org","load-type":["third-party"],"unless-domain":["*layer-ad.org"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?leadbolt\\.com","load-type":["third-party"],"unless-domain":["*leadbolt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?leadformix\\.com","load-type":["third-party"],"unless-domain":["*leadformix.com","*leadforce1.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?leadforce1\\.com","load-type":["third-party"],"unless-domain":["*leadformix.com","*leadforce1.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?leadlander\\.com","load-type":["third-party"],"unless-domain":["*leadlander.com","*trackalyzer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trackalyzer\\.com","load-type":["third-party"],"unless-domain":["*leadlander.com","*trackalyzer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?legolas-media\\.com","load-type":["third-party"],"unless-domain":["*legolas-media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?levexis\\.com","load-type":["third-party"],"unless-domain":["*levexis.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbull\\.com","load-type":["third-party"],"unless-domain":["*lexosmedia.com","*adbull.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lexosmedia\\.com","load-type":["third-party"],"unless-domain":["*lexosmedia.com","*adbull.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lfstmedia\\.com","load-type":["third-party"],"unless-domain":["*lifestreetmedia.com","*lfstmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lifestreetmedia\\.com","load-type":["third-party"],"unless-domain":["*lifestreetmedia.com","*lfstmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?linkconnector\\.com","load-type":["third-party"],"unless-domain":["*linkconnector.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?linkshare\\.com","load-type":["third-party"],"unless-domain":["*linkshare.com","*linksynergy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?linksynergy\\.com","load-type":["third-party"],"unless-domain":["*linkshare.com","*linksynergy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?linkz\\.net","load-type":["third-party"],"unless-domain":["*linkz.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?listrak\\.com","load-type":["third-party"],"unless-domain":["*listrak.com","*listrakbi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?listrakbi\\.com","load-type":["third-party"],"unless-domain":["*listrak.com","*listrakbi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?liadm\\.com","load-type":["third-party"],"unless-domain":["*liveintent.com","*liadm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?liveintent\\.com","load-type":["third-party"],"unless-domain":["*liveintent.com","*liadm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?liveinternet\\.ru","load-type":["third-party"],"unless-domain":["*liveinternet.ru","*yadro.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yadro\\.ru","load-type":["third-party"],"unless-domain":["*liveinternet.ru","*yadro.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?localyokelmedia\\.com","load-type":["third-party"],"unless-domain":["*localyokelmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?longboardmedia\\.com","load-type":["third-party"],"unless-domain":["*longboardmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?loomia\\.com","load-type":["third-party"],"unless-domain":["*loomia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lfov\\.net","load-type":["third-party"],"unless-domain":["*loopfuse.net","*lfov.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?loopfuse\\.net","load-type":["third-party"],"unless-domain":["*loopfuse.net","*lfov.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lucidmedia\\.com","load-type":["third-party"],"unless-domain":["*lucidmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cpalead\\.com","load-type":["third-party"],"unless-domain":["*cpalead.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mundomedia\\.com","load-type":["third-party"],"unless-domain":["*mundomedia.com","*silver-path.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?silver-path\\.com","load-type":["third-party"],"unless-domain":["*mundomedia.com","*silver-path.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?madhouse\\.cn","load-type":["third-party"],"unless-domain":["*madhouse.cn"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dinclinx\\.com","load-type":["third-party"],"unless-domain":["*madisonlogic.com","*dinclinx.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?madisonlogic\\.com","load-type":["third-party"],"unless-domain":["*madisonlogic.com","*dinclinx.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?domdex\\.com","load-type":["third-party"],"unless-domain":["*magnetic.com","*domdex.com","*domdex.net","*qjex.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?domdex\\.net","load-type":["third-party"],"unless-domain":["*magnetic.com","*domdex.com","*domdex.net","*qjex.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?magnetic\\.com","load-type":["third-party"],"unless-domain":["*magnetic.com","*domdex.com","*domdex.net","*qjex.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?qjex\\.net","load-type":["third-party"],"unless-domain":["*magnetic.com","*domdex.com","*domdex.net","*qjex.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dialogmgr\\.com","load-type":["third-party"],"unless-domain":["*magnify360.com","*dialogmgr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?magnify360\\.com","load-type":["third-party"],"unless-domain":["*magnify360.com","*dialogmgr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?campaign-archive1\\.com","load-type":["third-party"],"unless-domain":["*mailchimp.com","*campaign-archive1.com","*list-manage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?list-manage\\.com","load-type":["third-party"],"unless-domain":["*mailchimp.com","*campaign-archive1.com","*list-manage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mailchimp\\.com","load-type":["third-party"],"unless-domain":["*mailchimp.com","*campaign-archive1.com","*list-manage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bannerbank\\.ru","load-type":["third-party"],"unless-domain":["*manifest.ru","*bannerbank.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?manifest\\.ru","load-type":["third-party"],"unless-domain":["*manifest.ru","*bannerbank.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?industrybrains\\.com","load-type":["third-party"],"unless-domain":["*marchex.com","*industrybrains.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marchex\\.com","load-type":["third-party"],"unless-domain":["*marchex.com","*industrybrains.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marimedia\\.net","load-type":["third-party"],"unless-domain":["*marimedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dt00\\.net","load-type":["third-party"],"unless-domain":["*marketgid.com","*dt00.net","*dt07.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dt07\\.net","load-type":["third-party"],"unless-domain":["*marketgid.com","*dt00.net","*dt07.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marketgid\\.com","load-type":["third-party"],"unless-domain":["*marketgid.com","*dt00.net","*dt07.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marketo\\.com","load-type":["third-party"],"unless-domain":["*marketo.com","*marketo.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marketo\\.net","load-type":["third-party"],"unless-domain":["*marketo.com","*marketo.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?martiniadnetwork\\.com","load-type":["third-party"],"unless-domain":["*martinimedianetwork.com","*martiniadnetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?martinimedianetwork\\.com","load-type":["third-party"],"unless-domain":["*martinimedianetwork.com","*martiniadnetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chemistry\\.com","load-type":["third-party"],"unless-domain":["*match.com","*chemistry.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?match\\.com","load-type":["third-party"],"unless-domain":["*match.com","*chemistry.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?matomy\\.com","load-type":["third-party"],"unless-domain":["*matomy.com","*matomymarket.com","*matomymedia.com","*xtendmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?matomymarket\\.com","load-type":["third-party"],"unless-domain":["*matomy.com","*matomymarket.com","*matomymedia.com","*xtendmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?matomymedia\\.com","load-type":["third-party"],"unless-domain":["*matomy.com","*matomymarket.com","*matomymedia.com","*xtendmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xtendmedia\\.com","load-type":["third-party"],"unless-domain":["*matomy.com","*matomymarket.com","*matomymedia.com","*xtendmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsmarket\\.com","load-type":["third-party"],"unless-domain":["*matomy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?matomy\\.com","load-type":["third-party"],"unless-domain":["*matomy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?maxbounty\\.com","load-type":["third-party"],"unless-domain":["*maxbounty.com","*mb01.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mb01\\.com","load-type":["third-party"],"unless-domain":["*maxbounty.com","*mb01.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?maxpointinteractive\\.com","load-type":["third-party"],"unless-domain":["*maxpointinteractive.com","*maxusglobal.com","*mxptint.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?maxusglobal\\.com","load-type":["third-party"],"unless-domain":["*maxpointinteractive.com","*maxusglobal.com","*mxptint.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mxptint\\.net","load-type":["third-party"],"unless-domain":["*maxpointinteractive.com","*maxusglobal.com","*mxptint.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mdotm\\.com","load-type":["third-party"],"unless-domain":["*mdotm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediabrix\\.com","load-type":["third-party"],"unless-domain":["*mediabrix.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediacom\\.com","load-type":["third-party"],"unless-domain":["*mediacom.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adroitinteractive\\.com","load-type":["third-party"],"unless-domain":["*mediamath.com","*adroitinteractive.com","*designbloxlive.com","*mathtag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?designbloxlive\\.com","load-type":["third-party"],"unless-domain":["*mediamath.com","*adroitinteractive.com","*designbloxlive.com","*mathtag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mathtag\\.com","load-type":["third-party"],"unless-domain":["*mediamath.com","*adroitinteractive.com","*designbloxlive.com","*mathtag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediamath\\.com","load-type":["third-party"],"unless-domain":["*mediamath.com","*adroitinteractive.com","*designbloxlive.com","*mathtag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?media-servers\\.net","load-type":["third-party"],"unless-domain":["*mediashakers.com","*media-servers.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediashakers\\.com","load-type":["third-party"],"unless-domain":["*mediashakers.com","*media-servers.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediatrust\\.com","load-type":["third-party"],"unless-domain":["*mediatrust.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adnetinteractive\\.com","load-type":["third-party"],"unless-domain":["*mediawhiz.com","*adnetinteractive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediawhiz\\.com","load-type":["third-party"],"unless-domain":["*mediawhiz.com","*adnetinteractive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?medialets\\.com","load-type":["third-party"],"unless-domain":["*medialets.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbuyer\\.com","load-type":["third-party"],"unless-domain":["*mediaocean.com","*adbuyer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediaocean\\.com","load-type":["third-party"],"unless-domain":["*mediaocean.com","*adbuyer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?medicxmedia\\.com","load-type":["third-party"],"unless-domain":["*medicxmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?megaindex\\.ru","load-type":["third-party"],"unless-domain":["*megaindex.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mercent\\.com","load-type":["third-party"],"unless-domain":["*mercent.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?merchantadvantage\\.com","load-type":["third-party"],"unless-domain":["*merchantadvantage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?merchenta\\.com","load-type":["third-party"],"unless-domain":["*merchenta.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metanetwork\\.com","load-type":["third-party"],"unless-domain":["*metanetwork.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?meteorsolutions\\.com","load-type":["third-party"],"unless-domain":["*meteorsolutions.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?microad\\.jp","load-type":["third-party"],"unless-domain":["*www.microad.jp","*microad.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbureau\\.net","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adecn\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aquantive\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?atdmt\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?msads\\.net","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netconversions\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?roiservice\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?decktrade\\.com","load-type":["third-party"],"unless-domain":["*millennialmedia.com","*decktrade.com","*mydas.mobi"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?millennialmedia\\.com","load-type":["third-party"],"unless-domain":["*millennialmedia.com","*decktrade.com","*mydas.mobi"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mydas\\.mobi","load-type":["third-party"],"unless-domain":["*millennialmedia.com","*decktrade.com","*mydas.mobi"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mindset-media\\.com","load-type":["third-party"],"unless-domain":["*mindset-media.com","*mmismm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mmismm\\.com","load-type":["third-party"],"unless-domain":["*mindset-media.com","*mmismm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mirando\\.de","load-type":["third-party"],"unless-domain":["*mirando.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mixpo\\.com","load-type":["third-party"],"unless-domain":["*mixpo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mopub\\.com","load-type":["third-party"],"unless-domain":["*mopub.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?moat\\.com","load-type":["third-party"],"unless-domain":["*moat.com","*moatads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?moatads\\.com","load-type":["third-party"],"unless-domain":["*moat.com","*moatads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mobfox\\.com","load-type":["third-party"],"unless-domain":["*mobfox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admoda\\.com","load-type":["third-party"],"unless-domain":["*mobvision.com","*admoda.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mobvision\\.com","load-type":["third-party"],"unless-domain":["*mobvision.com","*admoda.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mobilemeteor\\.com","load-type":["third-party"],"unless-domain":["*mobilemeteor.com","*showmeinn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?showmeinn\\.com","load-type":["third-party"],"unless-domain":["*mobilemeteor.com","*showmeinn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mobilestorm\\.com","load-type":["third-party"],"unless-domain":["*mobilestorm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?moceanmobile\\.com","load-type":["third-party"],"unless-domain":["*moceanmobile.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mochila\\.com","load-type":["third-party"],"unless-domain":["*mochila.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mojiva\\.com","load-type":["third-party"],"unless-domain":["*mojiva.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?monetate\\.com","load-type":["third-party"],"unless-domain":["*monetate.com","*monetate.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?monetate\\.net","load-type":["third-party"],"unless-domain":["*monetate.com","*monetate.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?monetizemore\\.com","load-type":["third-party"],"unless-domain":["*monetizemore.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?monoloop\\.com","load-type":["third-party"],"unless-domain":["*monoloop.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?monster\\.com","load-type":["third-party"],"unless-domain":["*monster.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?moolah-media\\.com","load-type":["third-party"],"unless-domain":["*moolahmedia.com","*moolah-media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?moolahmedia\\.com","load-type":["third-party"],"unless-domain":["*moolahmedia.com","*moolah-media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?affbuzzads\\.com","load-type":["third-party"],"unless-domain":["*movielush.com","*affbuzzads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?movielush\\.com","load-type":["third-party"],"unless-domain":["*movielush.com","*affbuzzads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adclickmedia\\.com","load-type":["third-party"],"unless-domain":["*multiplestreammktg.com","*adclickmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?multiplestreammktg\\.com","load-type":["third-party"],"unless-domain":["*multiplestreammktg.com","*adclickmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mybuys\\.com","load-type":["third-party"],"unless-domain":["*mybuys.com","*veruta.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?veruta\\.com","load-type":["third-party"],"unless-domain":["*mybuys.com","*veruta.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mycounter\\.com\\.ua","load-type":["third-party"],"unless-domain":["*mycounter.com.ua"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mywebgrocer\\.com","load-type":["third-party"],"unless-domain":["*mywebgrocer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nanigans\\.com","load-type":["third-party"],"unless-domain":["*nanigans.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?navdmp\\.com","load-type":["third-party"],"unless-domain":["*navegg.com","*navdmp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?navegg\\.com","load-type":["third-party"],"unless-domain":["*navegg.com","*navdmp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cdnma\\.com","load-type":["third-party"],"unless-domain":["*net-results.com","*cdnma.com","*nr7.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?net-results\\.com","load-type":["third-party"],"unless-domain":["*net-results.com","*cdnma.com","*nr7.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nr7\\.us","load-type":["third-party"],"unless-domain":["*net-results.com","*cdnma.com","*nr7.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netaffiliation\\.com","load-type":["third-party"],"unless-domain":["*netaffiliation.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netbina\\.com","load-type":["third-party"],"unless-domain":["*netbina.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adelixir\\.com","load-type":["third-party"],"unless-domain":["*netelixir.com","*adelixir.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netelixir\\.com","load-type":["third-party"],"unless-domain":["*netelixir.com","*adelixir.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netseer\\.com","load-type":["third-party"],"unless-domain":["*netseer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netshelter\\.com","load-type":["third-party"],"unless-domain":["*netshelter.com","*netshelter.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netshelter\\.net","load-type":["third-party"],"unless-domain":["*netshelter.com","*netshelter.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netmining\\.com","load-type":["third-party"],"unless-domain":["*netmining.com","*netmng.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netmng\\.com","load-type":["third-party"],"unless-domain":["*netmining.com","*netmng.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adadvisor\\.net","load-type":["third-party"],"unless-domain":["*neustar.biz","*adadvisor.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?neustar\\.biz","load-type":["third-party"],"unless-domain":["*neustar.biz","*adadvisor.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nexage\\.com","load-type":["third-party"],"unless-domain":["*nexage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nextperformance\\.com","load-type":["third-party"],"unless-domain":["*nextperformance.com","*nxtck.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nxtck\\.com","load-type":["third-party"],"unless-domain":["*nextperformance.com","*nxtck.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nextag\\.com","load-type":["third-party"],"unless-domain":["*nextag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?imrworldwide\\.com","load-type":["third-party"],"unless-domain":["*nielsen.com","*imrworldwide.com","*imrworldwide.net","*glanceguide.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?imrworldwide\\.net","load-type":["third-party"],"unless-domain":["*nielsen.com","*imrworldwide.com","*imrworldwide.net","*glanceguide.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?networkedblogs\\.com","load-type":["third-party"],"unless-domain":["*ninua.com","*networkedblogs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ninua\\.com","load-type":["third-party"],"unless-domain":["*ninua.com","*networkedblogs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?noktamedya\\.com","load-type":["third-party"],"unless-domain":["*noktamedya.com","*virgul.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?virgul\\.com","load-type":["third-party"],"unless-domain":["*noktamedya.com","*virgul.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nowspots\\.com","load-type":["third-party"],"unless-domain":["*nowspots.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nuffnang\\.com","load-type":["third-party"],"unless-domain":["*www.nuffnang.com.my","*nuffnang.com","*nuffnang.com.my"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nuffnang\\.com\\.my","load-type":["third-party"],"unless-domain":["*www.nuffnang.com.my","*nuffnang.com","*nuffnang.com.my"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advg\\.jp","load-type":["third-party"],"unless-domain":["*www.opt.ne.jp","*advg.jp","*opt.ne.jp","*p-advg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?opt\\.ne\\.jp","load-type":["third-party"],"unless-domain":["*www.opt.ne.jp","*advg.jp","*opt.ne.jp","*p-advg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?p-advg\\.com","load-type":["third-party"],"unless-domain":["*www.opt.ne.jp","*advg.jp","*opt.ne.jp","*p-advg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adohana\\.com","load-type":["third-party"],"unless-domain":["*ohana-media.com","*adohana.com","*ohanaqb.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ohana-media\\.com","load-type":["third-party"],"unless-domain":["*ohana-media.com","*adohana.com","*ohanaqb.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ohanaqb\\.com","load-type":["third-party"],"unless-domain":["*ohana-media.com","*adohana.com","*ohanaqb.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?accuenmedia\\.com","load-type":["third-party"],"unless-domain":["*omnicomgroup.com","*accuenmedia.com","*p-td.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?omnicomgroup\\.com","load-type":["third-party"],"unless-domain":["*omnicomgroup.com","*accuenmedia.com","*p-td.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?p-td\\.com","load-type":["third-party"],"unless-domain":["*omnicomgroup.com","*accuenmedia.com","*p-td.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?itsoneiota\\.com","load-type":["third-party"],"unless-domain":["*itsoneiota.com","*oneiota.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oneiota\\.co\\.uk","load-type":["third-party"],"unless-domain":["*itsoneiota.com","*oneiota.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oneupweb\\.com","load-type":["third-party"],"unless-domain":["*oneupweb.com","*sodoit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sodoit\\.com","load-type":["third-party"],"unless-domain":["*oneupweb.com","*sodoit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?onm\\.de","load-type":["third-party"],"unless-domain":["*onm.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?liftdna\\.com","load-type":["third-party"],"unless-domain":["*openx.com","*openx.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?openx\\.com","load-type":["third-party"],"unless-domain":["*openx.com","*openx.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?openx\\.net","load-type":["third-party"],"unless-domain":["*openx.com","*openx.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?openx\\.org","load-type":["third-party"],"unless-domain":["*openx.com","*openx.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?openxenterprise\\.com","load-type":["third-party"],"unless-domain":["*openx.com","*openx.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?servedbyopenx\\.com","load-type":["third-party"],"unless-domain":["*openx.com","*openx.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mobiletheory\\.com","load-type":["third-party"],"unless-domain":["*opera.com","*mobiletheory.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?operamediaworks\\.com","load-type":["third-party"],"unless-domain":["*opera.com","*mobiletheory.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?operasoftware\\.com","load-type":["third-party"],"unless-domain":["*opera.com","*mobiletheory.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?opera\\.com","load-type":["third-party"],"unless-domain":["*opera.com","*mobiletheory.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?optmd\\.com","load-type":["third-party"],"unless-domain":["*optmd.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?optify\\.net","load-type":["third-party"],"unless-domain":["*optify.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cpmadvisors\\.com","load-type":["third-party"],"unless-domain":["*bn.co"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cpmatic\\.com","load-type":["third-party"],"unless-domain":["*bn.co"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nprove\\.com","load-type":["third-party"],"unless-domain":["*bn.co"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?optim\\.al","load-type":["third-party"],"unless-domain":["*bn.co"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?orbengine\\.com","load-type":["third-party"],"unless-domain":["*bn.co"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xa\\.net","load-type":["third-party"],"unless-domain":["*bn.co"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?optimumresponse\\.com","load-type":["third-party"],"unless-domain":["*optimumresponse.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?estara\\.com","load-type":["third-party"],"unless-domain":["*oracle.com","*estara.com","*atgsvcs.com","*instantservice.com","*istrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?orangesoda\\.com","load-type":["third-party"],"unless-domain":["*orangesoda.com","*otracking.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?otracking\\.com","load-type":["third-party"],"unless-domain":["*orangesoda.com","*otracking.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?out-there-media\\.com","load-type":["third-party"],"unless-domain":["*out-there-media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?outbrain\\.com","load-type":["third-party"],"unless-domain":["*outbrain.com","*sphere.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sphere\\.com","load-type":["third-party"],"unless-domain":["*outbrain.com","*sphere.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dsnextgen\\.com","load-type":["third-party"],"unless-domain":["*oversee.net","*dsnextgen.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oversee\\.net","load-type":["third-party"],"unless-domain":["*oversee.net","*dsnextgen.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?owneriq\\.com","load-type":["third-party"],"unless-domain":["*owneriq.com","*owneriq.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?owneriq\\.net","load-type":["third-party"],"unless-domain":["*owneriq.com","*owneriq.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adconnexa\\.com","load-type":["third-party"],"unless-domain":["*oxamedia.com","*adconnexa.com","*adsbwm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsbwm\\.com","load-type":["third-party"],"unless-domain":["*oxamedia.com","*adconnexa.com","*adsbwm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oxamedia\\.com","load-type":["third-party"],"unless-domain":["*oxamedia.com","*adconnexa.com","*adsbwm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?platform-one\\.co\\.jp","load-type":["third-party"],"unless-domain":["*www.platform-one.co.jp","*platform-one.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?paid-to-promote\\.net","load-type":["third-party"],"unless-domain":["*paid-to-promote.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pardot\\.com","load-type":["third-party"],"unless-domain":["*pardot.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?payhit\\.com","load-type":["third-party"],"unless-domain":["*payhit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lzjl\\.com","load-type":["third-party"],"unless-domain":["*paypopup.com","*lzjl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?paypopup\\.com","load-type":["third-party"],"unless-domain":["*paypopup.com","*lzjl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?peer39\\.com","load-type":["third-party"],"unless-domain":["*peer39.com","*peer39.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?peer39\\.net","load-type":["third-party"],"unless-domain":["*peer39.com","*peer39.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?peerfly\\.com","load-type":["third-party"],"unless-domain":["*peerfly.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?performancing\\.com","load-type":["third-party"],"unless-domain":["*performancing.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pheedo\\.com","load-type":["third-party"],"unless-domain":["*pheedo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pictela\\.com","load-type":["third-party"],"unless-domain":["*pictela.com","*pictela.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pictela\\.net","load-type":["third-party"],"unless-domain":["*pictela.com","*pictela.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pixel\\.sg","load-type":["third-party"],"unless-domain":["*pixel.sg"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?piximedia\\.com","load-type":["third-party"],"unless-domain":["*piximedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?po\\.st","load-type":["third-party"],"unless-domain":["*po.st"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pocketcents\\.com","load-type":["third-party"],"unless-domain":["*pocketcents.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?politads\\.com","load-type":["third-party"],"unless-domain":["*politads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pontiflex\\.com","load-type":["third-party"],"unless-domain":["*pontiflex.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?popads\\.net","load-type":["third-party"],"unless-domain":["*popads.net","*popadscdn.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?popadscdn\\.net","load-type":["third-party"],"unless-domain":["*popads.net","*popadscdn.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gocampaignlive\\.com","load-type":["third-party"],"unless-domain":["*poprule.com","*gocampaignlive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?poprule\\.com","load-type":["third-party"],"unless-domain":["*poprule.com","*gocampaignlive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?popunder\\.ru","load-type":["third-party"],"unless-domain":["*popunder.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?precisionclick\\.com","load-type":["third-party"],"unless-domain":["*precisionclick.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?predictad\\.com","load-type":["third-party"],"unless-domain":["*predictad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blogads\\.com","load-type":["third-party"],"unless-domain":["*pressflex.com","*blogads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pressflex\\.com","load-type":["third-party"],"unless-domain":["*pressflex.com","*blogads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adcde\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addlvr\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adonnetwork\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adonnetwork\\.net","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtrgt\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bannertgt\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cptgt\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cpvfeed\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cpvtgt\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?popcde\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?primevisibility\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sdfje\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?urtbk\\.com","load-type":["third-party"],"unless-domain":["*primevisibility.com","*adonnetwork.com","*adonnetwork.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?proclivitymedia\\.com","load-type":["third-party"],"unless-domain":["*proclivitymedia.com","*proclivitysystems.com","*pswec.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?proclivitysystems\\.com","load-type":["third-party"],"unless-domain":["*proclivitymedia.com","*proclivitysystems.com","*pswec.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pswec\\.com","load-type":["third-party"],"unless-domain":["*proclivitymedia.com","*proclivitysystems.com","*pswec.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?projectwonderful\\.com","load-type":["third-party"],"unless-domain":["*projectwonderful.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?propellerads\\.com","load-type":["third-party"],"unless-domain":["*propellerads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?prosperent\\.com","load-type":["third-party"],"unless-domain":["*prosperent.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?proxilinks\\.com","load-type":["third-party"],"unless-domain":["*proximic.com","*proxilinks.com","*proximic.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?proximic\\.com","load-type":["third-party"],"unless-domain":["*proximic.com","*proxilinks.com","*proximic.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?proximic\\.net","load-type":["third-party"],"unless-domain":["*proximic.com","*proxilinks.com","*proximic.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pubmatic\\.com","load-type":["third-party"],"unless-domain":["*pubmatic.com","*revinet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?revinet\\.com","load-type":["third-party"],"unless-domain":["*pubmatic.com","*revinet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?publicidees\\.com","load-type":["third-party"],"unless-domain":["*publicidees.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pch\\.com","load-type":["third-party"],"unless-domain":["*pch.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?i-behavior\\.com","load-type":["third-party"],"unless-domain":["*iaded.com","*quisma.com","*quismatch.com","*xmladed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iaded\\.com","load-type":["third-party"],"unless-domain":["*iaded.com","*quisma.com","*quismatch.com","*xmladed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quisma\\.com","load-type":["third-party"],"unless-domain":["*iaded.com","*quisma.com","*quismatch.com","*xmladed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quismatch\\.com","load-type":["third-party"],"unless-domain":["*iaded.com","*quisma.com","*quismatch.com","*xmladed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xaded\\.com","load-type":["third-party"],"unless-domain":["*iaded.com","*quisma.com","*quismatch.com","*xmladed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xmladed\\.com","load-type":["third-party"],"unless-domain":["*iaded.com","*quisma.com","*quismatch.com","*xmladed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quakemarketing\\.com","load-type":["third-party"],"unless-domain":["*quakemarketing.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quantcast\\.com","load-type":["third-party"],"unless-domain":["*quantcast.com","*quantserve.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quantserve\\.com","load-type":["third-party"],"unless-domain":["*quantcast.com","*quantserve.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?qnsr\\.com","load-type":["third-party"],"unless-domain":["*quinstreet.com","*thecounter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?qsstats\\.com","load-type":["third-party"],"unless-domain":["*quinstreet.com","*thecounter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quinstreet\\.com","load-type":["third-party"],"unless-domain":["*quinstreet.com","*thecounter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rmbn\\.net","load-type":["third-party"],"unless-domain":["*rmbn.net","*rmbn.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rmbn\\.ru","load-type":["third-party"],"unless-domain":["*rmbn.net","*rmbn.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rmmonline\\.com","load-type":["third-party"],"unless-domain":["*rmmonline.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?matchbin\\.com","load-type":["third-party"],"unless-domain":["*radiatemedia.com","*matchbin.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?radiatemedia\\.com","load-type":["third-party"],"unless-domain":["*radiatemedia.com","*matchbin.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gwallet\\.com","load-type":["third-party"],"unless-domain":["*radiumone.com","*gwallet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?radiumone\\.com","load-type":["third-party"],"unless-domain":["*radiumone.com","*gwallet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?radiusmarketing\\.com","load-type":["third-party"],"unless-domain":["*radiusmarketing.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rambler\\.ru","load-type":["third-party"],"unless-domain":["*rambler.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?liveramp\\.com","load-type":["third-party"],"unless-domain":["*rapleaf.com","*liveramp.com","*rlcdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rapleaf\\.com","load-type":["third-party"],"unless-domain":["*rapleaf.com","*liveramp.com","*rlcdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rlcdn\\.com","load-type":["third-party"],"unless-domain":["*rapleaf.com","*liveramp.com","*rlcdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?retargeter\\.com","load-type":["third-party"],"unless-domain":["*retargeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reachlocal\\.com","load-type":["third-party"],"unless-domain":["*reachlocal.com","*rlcdn.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rlcdn\\.net","load-type":["third-party"],"unless-domain":["*reachlocal.com","*rlcdn.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?react2media\\.com","load-type":["third-party"],"unless-domain":["*react2media.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reduxmedia\\.com","load-type":["third-party"],"unless-domain":["*reduxmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?convertglobal\\.com","load-type":["third-party"],"unless-domain":["*rekko.com","*convertglobal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rekko\\.com","load-type":["third-party"],"unless-domain":["*rekko.com","*convertglobal.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reklamstore\\.com","load-type":["third-party"],"unless-domain":["*reklamstore.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reklamport\\.com","load-type":["third-party"],"unless-domain":["*reklamport.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reklamz\\.com","load-type":["third-party"],"unless-domain":["*reklamz.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?relestar\\.com","load-type":["third-party"],"unless-domain":["*relevad.com","*relestar.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?relevad\\.com","load-type":["third-party"],"unless-domain":["*relevad.com","*relestar.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advertserve\\.com","load-type":["third-party"],"unless-domain":["*renegadeinternet.com","*advertserve.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?renegadeinternet\\.com","load-type":["third-party"],"unless-domain":["*renegadeinternet.com","*advertserve.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?resolutionmedia\\.com","load-type":["third-party"],"unless-domain":["*resolutionmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?resonateinsights\\.com","load-type":["third-party"],"unless-domain":["*resonateinsights.com","*resonatenetworks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?resonatenetworks\\.com","load-type":["third-party"],"unless-domain":["*resonateinsights.com","*resonatenetworks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?responsys\\.com","load-type":["third-party"],"unless-domain":["*responsys.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blvdstatus\\.com","load-type":["third-party"],"unless-domain":["*retirement-living.com","*blvdstatus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?retirement-living\\.com","load-type":["third-party"],"unless-domain":["*retirement-living.com","*blvdstatus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?revcontent\\.com","load-type":["third-party"],"unless-domain":["*revcontent.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?revenuemax\\.de","load-type":["third-party"],"unless-domain":["*revenuemax.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rhythmnewmedia\\.com","load-type":["third-party"],"unless-domain":["*rhythmnewmedia.com","*rnmd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rnmd\\.net","load-type":["third-party"],"unless-domain":["*rhythmnewmedia.com","*rnmd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rhythmxchange\\.com","load-type":["third-party"],"unless-domain":["*rhythmnewmedia.com","*rnmd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?1rx\\.io","load-type":["third-party"],"unless-domain":["*rhythmnewmedia.com","*rnmd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?richrelevance\\.com","load-type":["third-party"],"unless-domain":["*richrelevance.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rightaction\\.com","load-type":["third-party"],"unless-domain":["*rightaction.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rfihub\\.com","load-type":["third-party"],"unless-domain":["*rocketfuel.com","*rfihub.com","*rfihub.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rfihub\\.net","load-type":["third-party"],"unless-domain":["*rocketfuel.com","*rfihub.com","*rfihub.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rocketfuel\\.com","load-type":["third-party"],"unless-domain":["*rocketfuel.com","*rfihub.com","*rfihub.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rovion\\.com","load-type":["third-party"],"unless-domain":["*rovion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rutarget\\.ru","load-type":["third-party"],"unless-domain":["*rutarget.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aimatch\\.com","load-type":["third-party"],"unless-domain":["*sas.com","*aimatch.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sas\\.com","load-type":["third-party"],"unless-domain":["*sas.com","*aimatch.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reztrack\\.com","load-type":["third-party"],"unless-domain":["*sabre.com","*reztrack.com","*sabrehospitality.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sabre\\.com","load-type":["third-party"],"unless-domain":["*sabre.com","*reztrack.com","*sabrehospitality.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sabrehospitality\\.com","load-type":["third-party"],"unless-domain":["*sabre.com","*reztrack.com","*sabrehospitality.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?salesforce\\.com","load-type":["third-party"],"unless-domain":["*salesforce.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?samurai-factory\\.jp","load-type":["third-party"],"unless-domain":["*samurai-factory.jp","*shinobi.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shinobi\\.jp","load-type":["third-party"],"unless-domain":["*samurai-factory.jp","*shinobi.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bridgetrack\\.com","load-type":["third-party"],"unless-domain":["*sapient.com","*bridgetrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sapient\\.com","load-type":["third-party"],"unless-domain":["*sapient.com","*bridgetrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?scandinavianadnetworks\\.com","load-type":["third-party"],"unless-domain":["*scandinavianadnetworks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?scribol\\.com","load-type":["third-party"],"unless-domain":["*scribol.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?searchforce\\.com","load-type":["third-party"],"unless-domain":["*searchforce.com","*searchforce.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?searchforce\\.net","load-type":["third-party"],"unless-domain":["*searchforce.com","*searchforce.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kanoodle\\.com","load-type":["third-party"],"unless-domain":["*seevast.com","*kanoodle.com","*pulse360.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pulse360\\.com","load-type":["third-party"],"unless-domain":["*seevast.com","*kanoodle.com","*pulse360.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?seevast\\.com","load-type":["third-party"],"unless-domain":["*seevast.com","*kanoodle.com","*pulse360.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?syndigonetworks\\.com","load-type":["third-party"],"unless-domain":["*seevast.com","*kanoodle.com","*pulse360.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nabbr\\.com","load-type":["third-party"],"unless-domain":["*selectablemedia.com","*nabbr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?selectablemedia\\.com","load-type":["third-party"],"unless-domain":["*selectablemedia.com","*nabbr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sevenads\\.net","load-type":["third-party"],"unless-domain":["*sevenads.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sexinyourcity\\.com","load-type":["third-party"],"unless-domain":["*sexinyourcity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shareasale\\.com","load-type":["third-party"],"unless-domain":["*shareasale.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shopzilla\\.com","load-type":["third-party"],"unless-domain":["*shopzilla.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mkt51\\.net","load-type":["third-party"],"unless-domain":["*silverpop.com","*mkt51.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pages05\\.net","load-type":["third-party"],"unless-domain":["*silverpop.com","*mkt51.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?silverpop\\.com","load-type":["third-party"],"unless-domain":["*silverpop.com","*mkt51.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vtrenz\\.net","load-type":["third-party"],"unless-domain":["*silverpop.com","*mkt51.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?simpli\\.fi","load-type":["third-party"],"unless-domain":["*simpli.fi"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sitescout\\.com","load-type":["third-party"],"unless-domain":["*sitescout.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?skimlinks\\.com","load-type":["third-party"],"unless-domain":["*skimlinks.com","*skimresources.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?skimresources\\.com","load-type":["third-party"],"unless-domain":["*skimlinks.com","*skimresources.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adcentriconline\\.com","load-type":["third-party"],"unless-domain":["*skupenet.com","*adcentriconline.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?skupenet\\.com","load-type":["third-party"],"unless-domain":["*skupenet.com","*adcentriconline.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?smaato\\.com","load-type":["third-party"],"unless-domain":["*smaato.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?smileymedia\\.com","load-type":["third-party"],"unless-domain":["*smileymedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?smowtion\\.com","load-type":["third-party"],"unless-domain":["*smowtion.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?snap\\.com","load-type":["third-party"],"unless-domain":["*snap.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?halogenmediagroup\\.com","load-type":["third-party"],"unless-domain":["*socialchorus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?halogennetwork\\.com","load-type":["third-party"],"unless-domain":["*socialchorus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?socialchorus\\.com","load-type":["third-party"],"unless-domain":["*socialchorus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ratevoice\\.com","load-type":["third-party"],"unless-domain":["*socialinterface.com","*ratevoice.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?socialinterface\\.com","load-type":["third-party"],"unless-domain":["*socialinterface.com","*ratevoice.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?socialtwist\\.com","load-type":["third-party"],"unless-domain":["*socialtwist.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spacechimpmedia\\.com","load-type":["third-party"],"unless-domain":["*spacechimpmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sparkstudios\\.com","load-type":["third-party"],"unless-domain":["*sparkstudios.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbutler\\.com","load-type":["third-party"],"unless-domain":["*sparklit.com","*adbutler.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sparklit\\.com","load-type":["third-party"],"unless-domain":["*sparklit.com","*adbutler.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adviva\\.co\\.uk","load-type":["third-party"],"unless-domain":["*specificmedia.com","*sitemeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adviva\\.net","load-type":["third-party"],"unless-domain":["*specificmedia.com","*sitemeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sitemeter\\.com","load-type":["third-party"],"unless-domain":["*specificmedia.com","*sitemeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?specificclick\\.net","load-type":["third-party"],"unless-domain":["*specificmedia.com","*sitemeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?specificmedia\\.com","load-type":["third-party"],"unless-domain":["*specificmedia.com","*sitemeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?specificmedia\\.co\\.uk","load-type":["third-party"],"unless-domain":["*specificmedia.com","*sitemeter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spectate\\.com","load-type":["third-party"],"unless-domain":["*spectate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spongegroup\\.com","load-type":["third-party"],"unless-domain":["*spongegroup.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spongecell\\.com","load-type":["third-party"],"unless-domain":["*spongecell.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sponsorads\\.de","load-type":["third-party"],"unless-domain":["*sponsorads.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spot200\\.com","load-type":["third-party"],"unless-domain":["*spot200.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spotxchange\\.com","load-type":["third-party"],"unless-domain":["*spotxchange.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spotxcdn\\.com","load-type":["third-party"],"unless-domain":["*spotxchange.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?stargamesaffiliate\\.com","load-type":["third-party"],"unless-domain":["*stargames.net","*stargamesaffiliate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?steelhouse\\.com","load-type":["third-party"],"unless-domain":["*steelhouse.com","*steelhousemedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?steelhousemedia\\.com","load-type":["third-party"],"unless-domain":["*steelhouse.com","*steelhousemedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cams\\.com","load-type":["third-party"],"unless-domain":["*streamray.com","*cams.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?streamray\\.com","load-type":["third-party"],"unless-domain":["*streamray.com","*cams.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?strikead\\.com","load-type":["third-party"],"unless-domain":["*strikead.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?popularmedia\\.com","load-type":["third-party"],"unless-domain":["*strongmail.com","*popularmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?struq\\.com","load-type":["third-party"],"unless-domain":["*struq.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?suite66\\.com","load-type":["third-party"],"unless-domain":["*suite66.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?summitmedia\\.co\\.uk","load-type":["third-party"],"unless-domain":["*www.summit.co.uk","*summitmedia.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?supersonicads\\.com","load-type":["third-party"],"unless-domain":["*supersonicads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?switchadhub\\.com","load-type":["third-party"],"unless-domain":["*switchconcepts.com","*switchadhub.com","*switchconcepts.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?switchconcepts\\.co\\.uk","load-type":["third-party"],"unless-domain":["*switchconcepts.com","*switchadhub.com","*switchconcepts.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?switchconcepts\\.com","load-type":["third-party"],"unless-domain":["*switchconcepts.com","*switchadhub.com","*switchconcepts.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ethicalads\\.net","load-type":["third-party"],"unless-domain":["*switchconcepts.com","*switchadhub.com","*switchconcepts.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?switchads\\.com","load-type":["third-party"],"unless-domain":["*switchconcepts.com","*switchadhub.com","*switchconcepts.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?swoop\\.com","load-type":["third-party"],"unless-domain":["*swoop.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?factortg\\.com","load-type":["third-party"],"unless-domain":["*factortg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickable\\.net","load-type":["third-party"],"unless-domain":["*syncapse.com","*clickable.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?syncapse\\.com","load-type":["third-party"],"unless-domain":["*syncapse.com","*clickable.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tlvmedia\\.com","load-type":["third-party"],"unless-domain":["*tlvmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?taboola\\.com","load-type":["third-party"],"unless-domain":["*taboola.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tailsweep\\.com","load-type":["third-party"],"unless-domain":["*tailsweep.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tap\\.me","load-type":["third-party"],"unless-domain":["*tap.me"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tapit\\.com","load-type":["third-party"],"unless-domain":["*tapit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tapad\\.com","load-type":["third-party"],"unless-domain":["*tapad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bizmey\\.com","load-type":["third-party"],"unless-domain":["*tapgage.com","*bizmey.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tapgage\\.com","load-type":["third-party"],"unless-domain":["*tapgage.com","*bizmey.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?targetix\\.net","load-type":["third-party"],"unless-domain":["*targetix.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quicknoodles\\.com","load-type":["third-party"],"unless-domain":["*tattomedia.com","*quicknoodles.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tattomedia\\.com","load-type":["third-party"],"unless-domain":["*tattomedia.com","*quicknoodles.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?teadma\\.com","load-type":["third-party"],"unless-domain":["*teadma.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?teads\\.tv","load-type":["third-party"],"unless-domain":["*teads.tv"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ebuzzing\\.com","load-type":["third-party"],"unless-domain":["*teads.tv"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?technorati\\.com","load-type":["third-party"],"unless-domain":["*technorati.com","*technoratimedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?technoratimedia\\.com","load-type":["third-party"],"unless-domain":["*technorati.com","*technoratimedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tellapart\\.com","load-type":["third-party"],"unless-domain":["*tellapart.com","*tellapt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tellapt\\.com","load-type":["third-party"],"unless-domain":["*tellapart.com","*tellapt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sensis\\.com\\.au","load-type":["third-party"],"unless-domain":["*telstra.com.au","*sensis.com.au","*sensisdata.com.au","*sensisdigitalmedia.com.au"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sensisdata\\.com\\.au","load-type":["third-party"],"unless-domain":["*telstra.com.au","*sensis.com.au","*sensisdata.com.au","*sensisdigitalmedia.com.au"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sensisdigitalmedia\\.com\\.au","load-type":["third-party"],"unless-domain":["*telstra.com.au","*sensis.com.au","*sensisdata.com.au","*sensisdigitalmedia.com.au"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?telstra\\.com\\.au","load-type":["third-party"],"unless-domain":["*telstra.com.au","*sensis.com.au","*sensisdata.com.au","*sensisdigitalmedia.com.au"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eztargetmedia\\.com","load-type":["third-party"],"unless-domain":["*www.terra.com.br","*eztargetmedia.com","*terra.com.br"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?terra\\.com\\.br","load-type":["third-party"],"unless-domain":["*www.terra.com.br","*eztargetmedia.com","*terra.com.br"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hittail\\.com","load-type":["third-party"],"unless-domain":["*thenumagroup.com","*hittail.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thenumagroup\\.com","load-type":["third-party"],"unless-domain":["*thenumagroup.com","*hittail.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rimmkaufman\\.com","load-type":["third-party"],"unless-domain":["*rimmkaufman.com","*rkdms.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rkdms\\.com","load-type":["third-party"],"unless-domain":["*rimmkaufman.com","*rkdms.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thesearchagency\\.com","load-type":["third-party"],"unless-domain":["*thesearchagency.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thesearchagency\\.net","load-type":["third-party"],"unless-domain":["*thesearchagency.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsrvr\\.org","load-type":["third-party"],"unless-domain":["*thetradedesk.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thetradedesk\\.com","load-type":["third-party"],"unless-domain":["*thetradedesk.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?echosearch\\.com","load-type":["third-party"],"unless-domain":["*thinkrealtime.com","*echosearch.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?esm1\\.net","load-type":["third-party"],"unless-domain":["*thinkrealtime.com","*echosearch.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thinkrealtime\\.com","load-type":["third-party"],"unless-domain":["*thinkrealtime.com","*echosearch.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?carbonads\\.com","load-type":["third-party"],"unless-domain":["*tinder.com","*carbonads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tinder\\.com","load-type":["third-party"],"unless-domain":["*tinder.com","*carbonads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tiqiq\\.com","load-type":["third-party"],"unless-domain":["*tiqiq.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?todacell\\.com","load-type":["third-party"],"unless-domain":["*todacell.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tonefuse\\.com","load-type":["third-party"],"unless-domain":["*tonefuse.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickfuse\\.com","load-type":["third-party"],"unless-domain":["*tonemedia.com","*clickfuse.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tonemedia\\.com","load-type":["third-party"],"unless-domain":["*tonemedia.com","*clickfuse.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inq\\.com","load-type":["third-party"],"unless-domain":["*touchcommerce.com","*inq.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?touchcommerce\\.com","load-type":["third-party"],"unless-domain":["*touchcommerce.com","*inq.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trackingsoft\\.com","load-type":["third-party"],"unless-domain":["*trackingsoft.com","*roia.biz"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tradetracker\\.com","load-type":["third-party"],"unless-domain":["*tradetracker.com","*tradetracker.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tradetracker\\.net","load-type":["third-party"],"unless-domain":["*tradetracker.com","*tradetracker.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tradedoubler\\.com","load-type":["third-party"],"unless-domain":["*tradedoubler.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?traffichaus\\.com","load-type":["third-party"],"unless-domain":["*traffichaus.com","*traffichouse.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?traffichouse\\.com","load-type":["third-party"],"unless-domain":["*traffichaus.com","*traffichouse.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trafficrevenue\\.net","load-type":["third-party"],"unless-domain":["*trafficrevenue.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?traffiq\\.com","load-type":["third-party"],"unless-domain":["*traffiq.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?traveladnetwork\\.com","load-type":["third-party"],"unless-domain":["*travoramedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?traveladvertising\\.com","load-type":["third-party"],"unless-domain":["*travoramedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?travoramedia\\.com","load-type":["third-party"],"unless-domain":["*travoramedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?scanscout\\.com","load-type":["third-party"],"unless-domain":["*tremorvideo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tmnetads\\.com","load-type":["third-party"],"unless-domain":["*tremorvideo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tremormedia\\.com","load-type":["third-party"],"unless-domain":["*tremorvideo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tremorvideo\\.com","load-type":["third-party"],"unless-domain":["*tremorvideo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?triggit\\.com","load-type":["third-party"],"unless-domain":["*triggit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adlegend\\.com","load-type":["third-party"],"unless-domain":["*trueffect.com","*adlegend.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trueffect\\.com","load-type":["third-party"],"unless-domain":["*trueffect.com","*adlegend.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tmogul\\.com","load-type":["third-party"],"unless-domain":["*tubemogul.com","*tmogul.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tubemogul\\.com","load-type":["third-party"],"unless-domain":["*tubemogul.com","*tmogul.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buzzlogic\\.com","load-type":["third-party"],"unless-domain":["*twelvefold.com","*buzzlogic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?twelvefold\\.com","load-type":["third-party"],"unless-domain":["*twelvefold.com","*buzzlogic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tyroo\\.com","load-type":["third-party"],"unless-domain":["*tyroo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?upsellit\\.com","load-type":["third-party"],"unless-domain":["*usitechnologies.com","*upsellit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?usitechnologies\\.com","load-type":["third-party"],"unless-domain":["*usitechnologies.com","*upsellit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?unanimis\\.co\\.uk","load-type":["third-party"],"unless-domain":["*www.unanimis.co.uk","*unanimis.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?udmserve\\.net","load-type":["third-party"],"unless-domain":["*underdogmedia.com","*udmserve.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?underdogmedia\\.com","load-type":["third-party"],"unless-domain":["*underdogmedia.com","*udmserve.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?undertone\\.com","load-type":["third-party"],"unless-domain":["*undertone.com","*undertonenetworks.com","*undertonevideo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?undertonenetworks\\.com","load-type":["third-party"],"unless-domain":["*undertone.com","*undertonenetworks.com","*undertonevideo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?undertonevideo\\.com","load-type":["third-party"],"unless-domain":["*undertone.com","*undertonenetworks.com","*undertonevideo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?51network\\.com","load-type":["third-party"],"unless-domain":["*uniqlick.com","*51network.com","*wanmo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?uniqlick\\.com","load-type":["third-party"],"unless-domain":["*uniqlick.com","*51network.com","*wanmo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wanmo\\.com","load-type":["third-party"],"unless-domain":["*uniqlick.com","*51network.com","*wanmo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?unrulymedia\\.com","load-type":["third-party"],"unless-domain":["*unrulymedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?valuead\\.com","load-type":["third-party"],"unless-domain":["*valuead.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adserver\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dotomi\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dtmpub\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?emjcd\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fastclick\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fastclick\\.net","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?greystripe\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lduhtrp\\.net","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediaplex\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?valueclick\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?valueclick\\.net","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?valueclickmedia\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amigos\\.com","load-type":["third-party"],"unless-domain":["*various.com","*amigos.com","*getiton.com","*medley.com","*nostringsattached.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?getiton\\.com","load-type":["third-party"],"unless-domain":["*various.com","*amigos.com","*getiton.com","*medley.com","*nostringsattached.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?medley\\.com","load-type":["third-party"],"unless-domain":["*various.com","*amigos.com","*getiton.com","*medley.com","*nostringsattached.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nostringsattached\\.com","load-type":["third-party"],"unless-domain":["*various.com","*amigos.com","*getiton.com","*medley.com","*nostringsattached.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?various\\.com","load-type":["third-party"],"unless-domain":["*various.com","*amigos.com","*getiton.com","*medley.com","*nostringsattached.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vcmedia\\.vn","load-type":["third-party"],"unless-domain":["*vcmedia.vn"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ivdopia\\.com","load-type":["third-party"],"unless-domain":["*vdopia.com","*ivdopia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vdopia\\.com","load-type":["third-party"],"unless-domain":["*vdopia.com","*ivdopia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsvelocity\\.com","load-type":["third-party"],"unless-domain":["*adsvelocity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mobclix\\.com","load-type":["third-party"],"unless-domain":["*velti.com","*mobclix.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?velti\\.com","load-type":["third-party"],"unless-domain":["*velti.com","*mobclix.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vemba\\.com","load-type":["third-party"],"unless-domain":["*vemba.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?singlefeed\\.com","load-type":["third-party"],"unless-domain":["*vendio.com","*singlefeed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vendio\\.com","load-type":["third-party"],"unless-domain":["*vendio.com","*singlefeed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?veoxa\\.com","load-type":["third-party"],"unless-domain":["*veoxa.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?veremedia\\.com","load-type":["third-party"],"unless-domain":["*veremedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?verticalresponse\\.com","load-type":["third-party"],"unless-domain":["*verticalresponse.com","*vresp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vresp\\.com","load-type":["third-party"],"unless-domain":["*verticalresponse.com","*vresp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intellitxt\\.com","load-type":["third-party"],"unless-domain":["*vibrantmedia.com","*intellitxt.com","*picadmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?picadmedia\\.com","load-type":["third-party"],"unless-domain":["*vibrantmedia.com","*intellitxt.com","*picadmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vibrantmedia\\.com","load-type":["third-party"],"unless-domain":["*vibrantmedia.com","*intellitxt.com","*picadmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?viglink\\.com","load-type":["third-party"],"unless-domain":["*viglink.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?viewablemedia\\.net","load-type":["third-party"],"unless-domain":["*visiblemeasures.com","*viewablemedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visiblemeasures\\.com","load-type":["third-party"],"unless-domain":["*visiblemeasures.com","*viewablemedia.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visbrands\\.com","load-type":["third-party"],"unless-domain":["*visbrands.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vdna-assets\\.com","load-type":["third-party"],"unless-domain":["*visualdna.com","*vdna-assets.com","*visualdna-stats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visualdna-stats\\.com","load-type":["third-party"],"unless-domain":["*visualdna.com","*vdna-assets.com","*visualdna-stats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visualdna\\.com","load-type":["third-party"],"unless-domain":["*visualdna.com","*vdna-assets.com","*visualdna-stats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vizu\\.com","load-type":["third-party"],"unless-domain":["*vizu.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vizury\\.com","load-type":["third-party"],"unless-domain":["*vizury.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vserv\\.com","load-type":["third-party"],"unless-domain":["*vserv.com","*vserv.mobi"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vserv\\.mobi","load-type":["third-party"],"unless-domain":["*vserv.com","*vserv.mobi"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?247realmedia\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?accelerator-media\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?acceleratorusa\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?decdna\\.net","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?decideinteractive\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gmads\\.net","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?groupm\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kantarmedia\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mecglobal\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mindshare\\.nl","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mookie1\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pm14\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?realmedia\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?targ\\.ad","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?themig\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wpp\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xaxis\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?contentwidgets\\.net","load-type":["third-party"],"unless-domain":["*wahoha.com","*contentwidgets.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wahoha\\.com","load-type":["third-party"],"unless-domain":["*wahoha.com","*contentwidgets.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?feedperfect\\.com","load-type":["third-party"],"unless-domain":["*web.com","*feedperfect.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?web\\.com","load-type":["third-party"],"unless-domain":["*web.com","*feedperfect.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webads\\.co\\.uk","load-type":["third-party"],"unless-domain":["*www.webads.co.uk","*webads.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webgozar\\.com","load-type":["third-party"],"unless-domain":["*webgozar.com","*webgozar.ir"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webgozar\\.ir","load-type":["third-party"],"unless-domain":["*webgozar.com","*webgozar.ir"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dsmmadvantage\\.com","load-type":["third-party"],"unless-domain":["*webmetro.com","*dsmmadvantage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webmetro\\.com","load-type":["third-party"],"unless-domain":["*webmetro.com","*dsmmadvantage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?weborama\\.com","load-type":["third-party"],"unless-domain":["*weborama.com","*weborama.fr"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?weborama\\.fr","load-type":["third-party"],"unless-domain":["*weborama.com","*weborama.fr"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webtraffic\\.no","load-type":["third-party"],"unless-domain":["*webtraffic.se","*webtraffic.no"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webtraffic\\.se","load-type":["third-party"],"unless-domain":["*webtraffic.se","*webtraffic.no"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wiredminds\\.com","load-type":["third-party"],"unless-domain":["*wiredminds.com","*wiredminds.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wiredminds\\.de","load-type":["third-party"],"unless-domain":["*wiredminds.com","*wiredminds.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adtotal\\.pl","load-type":["third-party"],"unless-domain":["*wp.pl","*adtotal.pl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wp\\.pl","load-type":["third-party"],"unless-domain":["*wp.pl","*adtotal.pl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wordstream\\.com","load-type":["third-party"],"unless-domain":["*wordstream.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admanager-xertive\\.com","load-type":["third-party"],"unless-domain":["*xertivemedia.com","*admanager-xertive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xertivemedia\\.com","load-type":["third-party"],"unless-domain":["*xertivemedia.com","*admanager-xertive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adplan-ds\\.com","load-type":["third-party"],"unless-domain":["*adplan-ds.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ydworld\\.com","load-type":["third-party"],"unless-domain":["*ydworld.com","*yieldivision.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yieldivision\\.com","load-type":["third-party"],"unless-domain":["*ydworld.com","*yieldivision.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yoc\\.com","load-type":["third-party"],"unless-domain":["*yoc.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yoc-performance\\.com","load-type":["third-party"],"unless-domain":["*yoc.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yabuka\\.com","load-type":["third-party"],"unless-domain":["*yabuka.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adinterax\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adrevolver\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bluelithium\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dapper\\.net","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?interclick\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?overture\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rightmedia\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rmxads\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?secure-adserver\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adserver\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advertising\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marketingsolutions\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thewheelof\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yieldmanager\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yieldmanager\\.net","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yldmgrimg\\.net","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metrica\\.yandex\\.com\\.tr","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metrika\\.yandex\\.kz","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metrika\\.yandex\\.by","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metrika\\.yandex\\.ua","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metrika\\.yandex\\.ru","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metrica\\.yandex\\.com","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advertising\\.yandex\\.ru","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?advertising\\.yandex\\.com","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?direct\\.yandex\\.ru","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?direct\\.yandex\\.com","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appmetrika\\.yandex\\.ru","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appmetrica\\.yandex\\.com","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appmetrica\\.yandex\\.com\\.tr","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?api-metrika\\.yandex\\.com","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?api-metrika\\.yandex\\.ru","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addynamix\\.com","load-type":["third-party"],"unless-domain":["*ybrantdigital.com","*addynamix.com","*adserverplus.com","*oridian.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adserverplus\\.com","load-type":["third-party"],"unless-domain":["*ybrantdigital.com","*addynamix.com","*adserverplus.com","*oridian.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oridian\\.com","load-type":["third-party"],"unless-domain":["*ybrantdigital.com","*addynamix.com","*adserverplus.com","*oridian.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ybrantdigital\\.com","load-type":["third-party"],"unless-domain":["*ybrantdigital.com","*addynamix.com","*adserverplus.com","*oridian.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?attracto\\.com","load-type":["third-party"],"unless-domain":["*yhmg.com","*attracto.com","*clickhype.com","*yellowhammermg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickhype\\.com","load-type":["third-party"],"unless-domain":["*yhmg.com","*attracto.com","*clickhype.com","*yellowhammermg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yellowhammermg\\.com","load-type":["third-party"],"unless-domain":["*yhmg.com","*attracto.com","*clickhype.com","*yellowhammermg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yhmg\\.com","load-type":["third-party"],"unless-domain":["*yhmg.com","*attracto.com","*clickhype.com","*yellowhammermg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yesads\\.com","load-type":["third-party"],"unless-domain":["*yesads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yieldads\\.com","load-type":["third-party"],"unless-domain":["*yieldads.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yieldbuild\\.com","load-type":["third-party"],"unless-domain":["*yieldbuild.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yieldlab\\.de","load-type":["third-party"],"unless-domain":["*yieldlab.de","*yieldlab.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yieldlab\\.net","load-type":["third-party"],"unless-domain":["*yieldlab.de","*yieldlab.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yoggrt\\.com","load-type":["third-party"],"unless-domain":["*yoggrt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yume\\.com","load-type":["third-party"],"unless-domain":["*yume.com","*yumenetworks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yumenetworks\\.com","load-type":["third-party"],"unless-domain":["*yume.com","*yumenetworks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zedo\\.com","load-type":["third-party"],"unless-domain":["*zedo.com","*zincx.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zincx\\.com","load-type":["third-party"],"unless-domain":["*zedo.com","*zincx.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metricsdirect\\.com","load-type":["third-party"],"unless-domain":["*zango.com","*metricsdirect.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zango\\.com","load-type":["third-party"],"unless-domain":["*zango.com","*metricsdirect.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zemanta\\.com","load-type":["third-party"],"unless-domain":["*zemanta.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zestad\\.com","load-type":["third-party"],"unless-domain":["*zestad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?insightgrit\\.com","load-type":["third-party"],"unless-domain":["*zetaemailsolutions.com","*insightgrit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zetaemailsolutions\\.com","load-type":["third-party"],"unless-domain":["*zetaemailsolutions.com","*insightgrit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zumobi\\.com","load-type":["third-party"],"unless-domain":["*zumobi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ru4\\.com","load-type":["third-party"],"unless-domain":["*xplusone.com","*ru4.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xplusone\\.com","load-type":["third-party"],"unless-domain":["*xplusone.com","*ru4.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adpepper\\.com","load-type":["third-party"],"unless-domain":["*adpepper.us","*adpepper.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adpepper\\.us","load-type":["third-party"],"unless-domain":["*adpepper.us","*adpepper.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ad6media\\.fr","load-type":["third-party"],"unless-domain":["*ad6media.fr"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbrite\\.com","load-type":["third-party"],"unless-domain":["*adbrite.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?admarketplace\\.com","load-type":["third-party"],"unless-domain":["*admarketplace.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adprs\\.net","load-type":["third-party"],"unless-domain":["*adprecision.net","*adprs.net","*aprecision.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aprecision\\.net","load-type":["third-party"],"unless-domain":["*adprecision.net","*adprs.net","*aprecision.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addgloo\\.com","load-type":["third-party"],"unless-domain":["*addgloo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adhood\\.com","load-type":["third-party"],"unless-domain":["*adhood.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adnologies\\.com","load-type":["third-party"],"unless-domain":["*adnologies.com","*heias.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?heias\\.com","load-type":["third-party"],"unless-domain":["*adnologies.com","*heias.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adrolays\\.com","load-type":["third-party"],"unless-domain":["*adrolays.com","*adrolays.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adrolays\\.de","load-type":["third-party"],"unless-domain":["*adrolays.com","*adrolays.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adscale\\.de","load-type":["third-party"],"unless-domain":["*adscale.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adyard\\.de","load-type":["third-party"],"unless-domain":["*adyard.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adzly\\.com","load-type":["third-party"],"unless-domain":["*adzly.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?affili\\.net","load-type":["third-party"],"unless-domain":["*affili.net","*affilinet-inside.de","*banner-rotation.com","*successfultogether.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?affilinet-inside\\.de","load-type":["third-party"],"unless-domain":["*affili.net","*affilinet-inside.de","*banner-rotation.com","*successfultogether.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?banner-rotation\\.com","load-type":["third-party"],"unless-domain":["*affili.net","*affilinet-inside.de","*banner-rotation.com","*successfultogether.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?successfultogether\\.co\\.uk","load-type":["third-party"],"unless-domain":["*affili.net","*affilinet-inside.de","*banner-rotation.com","*successfultogether.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appssavvy\\.com","load-type":["third-party"],"unless-domain":["*appssavvy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?beencounter\\.com","load-type":["third-party"],"unless-domain":["*beencounter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adbutler\\.de","load-type":["third-party"],"unless-domain":["*belboon.com","*adbutler.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?belboon\\.com","load-type":["third-party"],"unless-domain":["*belboon.com","*adbutler.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bigmir\\.net","load-type":["third-party"],"unless-domain":["*bigmir.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cxense\\.com","load-type":["third-party"],"unless-domain":["*cxense.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adxpose\\.com","load-type":["third-party"],"unless-domain":["*comscore.com","*adxpose.com","*certifica.com","*scorecardresearch.com","*sitestat.com","*voicefive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dianomi\\.com","load-type":["third-party"],"unless-domain":["*dianomi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ebay\\.com","load-type":["third-party"],"unless-domain":["*ebay.com","*ebay.at","*ebay.ba","*ebay.be","*ebay.com.au","*ebay.ca","*ebay.ch","*ebay.cn","*ebay.de","*ebay.es","*ebay.fr","*ebay.com.hk","*ebay.ie","*ebay.in","*ebay.it","*ebay.co.jp","*ebay.co.kr","*ebay.com.my","*ebay.nl","*ebay.com.ph","*ebay.pl","*ebay.com.sg","*ebay.com.tw","*ebay.co.uk","*gopjn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gopjn\\.com","load-type":["third-party"],"unless-domain":["*ebay.com","*ebay.at","*ebay.ba","*ebay.be","*ebay.com.au","*ebay.ca","*ebay.ch","*ebay.cn","*ebay.de","*ebay.es","*ebay.fr","*ebay.com.hk","*ebay.ie","*ebay.in","*ebay.it","*ebay.co.jp","*ebay.co.kr","*ebay.com.my","*ebay.nl","*ebay.com.ph","*ebay.pl","*ebay.com.sg","*ebay.com.tw","*ebay.co.uk","*gopjn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?etrigue\\.com","load-type":["third-party"],"unless-domain":["*etrigue.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ewaydirect\\.com","load-type":["third-party"],"unless-domain":["*ewaydirect.com","*ixs1.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ixs1\\.net","load-type":["third-party"],"unless-domain":["*ewaydirect.com","*ixs1.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?exelate\\.com","load-type":["third-party"],"unless-domain":["*exelate.com","*exelator.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?exelator\\.com","load-type":["third-party"],"unless-domain":["*exelate.com","*exelator.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?e-kolay\\.net","load-type":["third-party"],"unless-domain":["*ekolay.net","*e-kolay.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ekolay\\.net","load-type":["third-party"],"unless-domain":["*ekolay.net","*e-kolay.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bnmla\\.com","load-type":["third-party"],"unless-domain":["*engagebdr.com","*bnmla.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?engagebdr\\.com","load-type":["third-party"],"unless-domain":["*engagebdr.com","*bnmla.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?777seo\\.com","load-type":["third-party"],"unless-domain":["*ewebse.com","*777seo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ewebse\\.com","load-type":["third-party"],"unless-domain":["*ewebse.com","*777seo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?excitad\\.com","load-type":["third-party"],"unless-domain":["*excitad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?expo-max\\.com","load-type":["third-party"],"unless-domain":["*expo-max.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eyereturn\\.com","load-type":["third-party"],"unless-domain":["*eyereturnmarketing.com","*eyereturn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eyereturnmarketing\\.com","load-type":["third-party"],"unless-domain":["*eyereturnmarketing.com","*eyereturn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?faithadnet\\.com","load-type":["third-party"],"unless-domain":["*faithadnet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?600z\\.com","load-type":["third-party"],"unless-domain":["*ientry.com","*600z.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ientry\\.com","load-type":["third-party"],"unless-domain":["*ientry.com","*600z.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?centraliprom\\.com","load-type":["third-party"],"unless-domain":["*iprom.si","*centraliprom.com","*iprom.net","*mediaiprom.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iprom\\.net","load-type":["third-party"],"unless-domain":["*iprom.si","*centraliprom.com","*iprom.net","*mediaiprom.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iprom\\.si","load-type":["third-party"],"unless-domain":["*iprom.si","*centraliprom.com","*iprom.net","*mediaiprom.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediaiprom\\.com","load-type":["third-party"],"unless-domain":["*iprom.si","*centraliprom.com","*iprom.net","*mediaiprom.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ipromote\\.com","load-type":["third-party"],"unless-domain":["*ipromote.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iprospect\\.com","load-type":["third-party"],"unless-domain":["*iprospect.com","*clickmanage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickmanage\\.com","load-type":["third-party"],"unless-domain":["*iprospect.com","*clickmanage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inner-active\\.com","load-type":["third-party"],"unless-domain":["*inner-active.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adsbyisocket\\.com","load-type":["third-party"],"unless-domain":["*isocket.com","*adsbyisocket.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?isocket\\.com","load-type":["third-party"],"unless-domain":["*isocket.com","*adsbyisocket.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?m6d\\.com","load-type":["third-party"],"unless-domain":["*m6d.com","*media6degrees.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?media6degrees\\.com","load-type":["third-party"],"unless-domain":["*m6d.com","*media6degrees.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?madvertise\\.com","load-type":["third-party"],"unless-domain":["*madvertise.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mashero\\.com","load-type":["third-party"],"unless-domain":["*mashero.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?media\\.net","load-type":["third-party"],"unless-domain":["*media.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediaforge\\.com","load-type":["third-party"],"unless-domain":["*mediaforge.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mythings\\.com","load-type":["third-party"],"unless-domain":["*mythings.com","*mythingsmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mythingsmedia\\.com","load-type":["third-party"],"unless-domain":["*mythings.com","*mythingsmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?newtention\\.de","load-type":["third-party"],"unless-domain":["*newtention.de","*newtention.net","*newtentionassets.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?newtention\\.net","load-type":["third-party"],"unless-domain":["*newtention.de","*newtention.net","*newtentionassets.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?newtentionassets\\.net","load-type":["third-party"],"unless-domain":["*newtention.de","*newtention.net","*newtentionassets.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nrelate\\.com","load-type":["third-party"],"unless-domain":["*nrelate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nugg\\.ad","load-type":["third-party"],"unless-domain":["*nugg.ad","*nuggad.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nuggad\\.net","load-type":["third-party"],"unless-domain":["*nugg.ad","*nuggad.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?onad\\.eu","load-type":["third-party"],"unless-domain":["*onad.eu"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?plista\\.com","load-type":["third-party"],"unless-domain":["*plista.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quadrantone\\.com","load-type":["third-party"],"unless-domain":["*quadrantone.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sociomantic\\.com","load-type":["third-party"],"unless-domain":["*sociomantic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sophus3\\.co\\.uk","load-type":["third-party"],"unless-domain":["*sophus3.com","*sophus3.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sophus3\\.com","load-type":["third-party"],"unless-domain":["*sophus3.com","*sophus3.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?twyn\\.com","load-type":["third-party"],"unless-domain":["*twyn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ucoz\\.ae","load-type":["third-party"],"unless-domain":["*ucoz.com","*ucoz.ae","*ucoz.fr","*ucoz.net","*ucoz.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ucoz\\.br","load-type":["third-party"],"unless-domain":["*ucoz.com","*ucoz.ae","*ucoz.fr","*ucoz.net","*ucoz.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ucoz\\.com","load-type":["third-party"],"unless-domain":["*ucoz.com","*ucoz.ae","*ucoz.fr","*ucoz.net","*ucoz.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ucoz\\.du","load-type":["third-party"],"unless-domain":["*ucoz.com","*ucoz.ae","*ucoz.fr","*ucoz.net","*ucoz.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ucoz\\.fr","load-type":["third-party"],"unless-domain":["*ucoz.com","*ucoz.ae","*ucoz.fr","*ucoz.net","*ucoz.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ucoz\\.net","load-type":["third-party"],"unless-domain":["*ucoz.com","*ucoz.ae","*ucoz.fr","*ucoz.net","*ucoz.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ucoz\\.ru","load-type":["third-party"],"unless-domain":["*ucoz.com","*ucoz.ae","*ucoz.fr","*ucoz.net","*ucoz.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?up-value\\.de","load-type":["third-party"],"unless-domain":["*up-value.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xad\\.com","load-type":["third-party"],"unless-domain":["*xad.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xplosion\\.de","load-type":["third-party"],"unless-domain":["*xplosion.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?youknowbest\\.com","load-type":["third-party"],"unless-domain":["*youknowbest.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buy\\.at","load-type":["third-party"],"unless-domain":["*zanox.com","*buy.at","*zanox-affiliate.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zanox-affiliate\\.de","load-type":["third-party"],"unless-domain":["*zanox.com","*buy.at","*zanox-affiliate.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zanox\\.com","load-type":["third-party"],"unless-domain":["*zanox.com","*buy.at","*zanox-affiliate.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zaparena\\.com","load-type":["third-party"],"unless-domain":["*zapunited.com","*zaparena.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zapunited\\.com","load-type":["third-party"],"unless-domain":["*zapunited.com","*zaparena.com"]}}] \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/ContentBlocker/disconnect-analytics.json b/mobile/ios/Client/Frontend/ContentBlocker/disconnect-analytics.json new file mode 100644 index 0000000000..c8b365397a --- /dev/null +++ b/mobile/ios/Client/Frontend/ContentBlocker/disconnect-analytics.json @@ -0,0 +1 @@ +[{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?63squares\\.com","load-type":["third-party"],"unless-domain":["*63squares.com","*i-stats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?i-stats\\.com","load-type":["third-party"],"unless-domain":["*63squares.com","*i-stats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?atinternet\\.com","load-type":["third-party"],"unless-domain":["*atinternet.com","*hit-parade.com","*xiti.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xiti\\.com","load-type":["third-party"],"unless-domain":["*atinternet.com","*hit-parade.com","*xiti.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?acxiom\\.com","load-type":["third-party"],"unless-domain":["*acxiom.com","*mm7.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mm7\\.net","load-type":["third-party"],"unless-domain":["*acxiom.com","*mm7.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?3dstats\\.com","load-type":["third-party"],"unless-domain":["*addfreestats.com","*3dstats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addfreestats\\.com","load-type":["third-party"],"unless-domain":["*addfreestats.com","*3dstats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amadesa\\.com","load-type":["third-party"],"unless-domain":["*amadesa.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazingcounters\\.com","load-type":["third-party"],"unless-domain":["*amazingcounters.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?alexa\\.com","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?alexametrics\\.com","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?attracta\\.com","load-type":["third-party"],"unless-domain":["*attracta.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?polldaddy\\.com","load-type":["third-party"],"unless-domain":["*automattic.com","*polldaddy.com","*gravatar.com","*intensedebate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?awio\\.com","load-type":["third-party"],"unless-domain":["*awio.com","*w3counter.com","*w3roi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?w3counter\\.com","load-type":["third-party"],"unless-domain":["*awio.com","*w3counter.com","*w3roi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?w3roi\\.com","load-type":["third-party"],"unless-domain":["*awio.com","*w3counter.com","*w3roi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?belstat\\.be","load-type":["third-party"],"unless-domain":["*belstat.com","*belstat.be","*belstat.de","*belstat.fr","*belstat.nl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?belstat\\.com","load-type":["third-party"],"unless-domain":["*belstat.com","*belstat.be","*belstat.de","*belstat.fr","*belstat.nl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?belstat\\.de","load-type":["third-party"],"unless-domain":["*belstat.com","*belstat.be","*belstat.de","*belstat.fr","*belstat.nl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?belstat\\.fr","load-type":["third-party"],"unless-domain":["*belstat.com","*belstat.be","*belstat.de","*belstat.fr","*belstat.nl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?belstat\\.nl","load-type":["third-party"],"unless-domain":["*belstat.com","*belstat.be","*belstat.de","*belstat.fr","*belstat.nl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blogcounter\\.de","load-type":["third-party"],"unless-domain":["*blogcounter.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bluemetrix\\.com","load-type":["third-party"],"unless-domain":["*bluemetrix.com","*bmmetrix.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bmmetrix\\.com","load-type":["third-party"],"unless-domain":["*bluemetrix.com","*bmmetrix.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?branica\\.com","load-type":["third-party"],"unless-domain":["*branica.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brightedge\\.com","load-type":["third-party"],"unless-domain":["*brightedge.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bubblestat\\.com","load-type":["third-party"],"unless-domain":["*bubblestat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?attributionmodel\\.com","load-type":["third-party"],"unless-domain":["*c3metrics.com","*attributionmodel.com","*c3tag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?c3metrics\\.com","load-type":["third-party"],"unless-domain":["*c3metrics.com","*attributionmodel.com","*c3tag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?c3tag\\.com","load-type":["third-party"],"unless-domain":["*c3metrics.com","*attributionmodel.com","*c3tag.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cnzz\\.com","load-type":["third-party"],"unless-domain":["*cnzz.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chartbeat\\.com","load-type":["third-party"],"unless-domain":["*chartbeat.com","*chartbeat.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chartbeat\\.net","load-type":["third-party"],"unless-domain":["*chartbeat.com","*chartbeat.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clicktale\\.com","load-type":["third-party"],"unless-domain":["*clicktale.com","*clicktale.net","*pantherssl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clicktale\\.net","load-type":["third-party"],"unless-domain":["*clicktale.com","*clicktale.net","*pantherssl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pantherssl\\.com","load-type":["third-party"],"unless-domain":["*clicktale.com","*clicktale.net","*pantherssl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickdensity\\.com","load-type":["third-party"],"unless-domain":["*clickdensity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clixmetrix\\.com","load-type":["third-party"],"unless-domain":["*clixmetrix.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clixpy\\.com","load-type":["third-party"],"unless-domain":["*clixpy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clustrmaps\\.com","load-type":["third-party"],"unless-domain":["*clustrmaps.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?axf8\\.net","load-type":["third-party"],"unless-domain":["*compuware.com","*axf8.net","*gomez.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?compuware\\.com","load-type":["third-party"],"unless-domain":["*compuware.com","*axf8.net","*gomez.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gomez\\.com","load-type":["third-party"],"unless-domain":["*compuware.com","*axf8.net","*gomez.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?connexity\\.com","load-type":["third-party"],"unless-domain":["*connexity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zmedia\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?conversantmedia\\.com","load-type":["third-party"],"unless-domain":["*conversantmedia.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?convert\\.com","load-type":["third-party"],"unless-domain":["*convert.com","*reedge.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reedge\\.com","load-type":["third-party"],"unless-domain":["*convert.com","*reedge.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?convertro\\.com","load-type":["third-party"],"unless-domain":["*convertro.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cetrk\\.com","load-type":["third-party"],"unless-domain":["*crazyegg.com","*cetrk.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crazyegg\\.com","load-type":["third-party"],"unless-domain":["*crazyegg.com","*cetrk.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crowdscience\\.com","load-type":["third-party"],"unless-domain":["*crowdscience.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cya2\\.net","load-type":["third-party"],"unless-domain":["*cya2.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?collserve\\.com","load-type":["third-party"],"unless-domain":["*dataium.com","*collserve.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dataium\\.com","load-type":["third-party"],"unless-domain":["*dataium.com","*collserve.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?demandbase\\.com","load-type":["third-party"],"unless-domain":["*demandbase.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ipcounter\\.de","load-type":["third-party"],"unless-domain":["*directcorp.de","*ipcounter.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trackersimulator\\.org","load-type":["third-party"],"unless-domain":["*eff.org"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eviltracker\\.net","load-type":["third-party"],"unless-domain":["*eff.org"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?do-not-tracker\\.org","load-type":["third-party"],"unless-domain":["*eff.org"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eloqua\\.com","load-type":["third-party"],"unless-domain":["*eloqua.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?encoremetrics\\.com","load-type":["third-party"],"unless-domain":["*encoremetrics.com","*sitecompass.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sitecompass\\.com","load-type":["third-party"],"unless-domain":["*encoremetrics.com","*sitecompass.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eulerian\\.com","load-type":["third-party"],"unless-domain":["*eulerian.com","*eulerian.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eulerian\\.net","load-type":["third-party"],"unless-domain":["*eulerian.com","*eulerian.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?feedjit\\.com","load-type":["third-party"],"unless-domain":["*feedjit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?footprintlive\\.com","load-type":["third-party"],"unless-domain":["*footprintlive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?freeonlineusers\\.com","load-type":["third-party"],"unless-domain":["*freeonlineusers.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?free-pagerank\\.com","load-type":["third-party"],"unless-domain":["*free-pagerank.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gtop\\.ro","load-type":["third-party"],"unless-domain":["*gtop.ro","*gtopstats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gtopstats\\.com","load-type":["third-party"],"unless-domain":["*gtop.ro","*gtopstats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?daphnecm\\.com","load-type":["third-party"],"unless-domain":["*gfk.com","*daphnecm.com","*gfkdaphne.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gfk\\.com","load-type":["third-party"],"unless-domain":["*gfk.com","*daphnecm.com","*gfkdaphne.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gfkdaphne\\.com","load-type":["third-party"],"unless-domain":["*gfk.com","*daphnecm.com","*gfkdaphne.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gaug\\.es","load-type":["third-party"],"unless-domain":["*github.com","*gaug.es"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?godaddy\\.com","load-type":["third-party"],"unless-domain":["*godaddy.com","*trafficfacts.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trafficfacts\\.com","load-type":["third-party"],"unless-domain":["*godaddy.com","*trafficfacts.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gosquared\\.com","load-type":["third-party"],"unless-domain":["*gosquared.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gostats\\.com","load-type":["third-party"],"unless-domain":["*gostats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google-analytics\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?postrank\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?raasnet\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?redaril\\.com","load-type":["third-party"],"unless-domain":["*hearst.com","*ic-live.com","*iclive.com","*icrossing.com","*sptag.com","*sptag1.com","*sptag2.com","*sptag3.com","*raasnet.com","*redaril.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?histats\\.com","load-type":["third-party"],"unless-domain":["*histats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hitsniffer\\.com","load-type":["third-party"],"unless-domain":["*hitsniffer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hitslink\\.com","load-type":["third-party"],"unless-domain":["*hitslink.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cmcore\\.com","load-type":["third-party"],"unless-domain":["*ibm.com","*unica.com","*cmcore.com","*coremetrics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?coremetrics\\.com","load-type":["third-party"],"unless-domain":["*ibm.com","*unica.com","*cmcore.com","*coremetrics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ibm\\.com","load-type":["third-party"],"unless-domain":["*ibm.com","*unica.com","*cmcore.com","*coremetrics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?infonline\\.de","load-type":["third-party"],"unless-domain":["*infonline.de","*ioam.de","*ivwbox.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ioam\\.de","load-type":["third-party"],"unless-domain":["*infonline.de","*ioam.de","*ivwbox.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ivwbox\\.de","load-type":["third-party"],"unless-domain":["*infonline.de","*ioam.de","*ivwbox.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?enquisite\\.com","load-type":["third-party"],"unless-domain":["*inboundwriter.com","*enquisite.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inboundwriter\\.com","load-type":["third-party"],"unless-domain":["*inboundwriter.com","*enquisite.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hotlog\\.ru","load-type":["third-party"],"unless-domain":["*infostars.ru","*hotlog.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?infostars\\.ru","load-type":["third-party"],"unless-domain":["*infostars.ru","*hotlog.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inspectlet\\.com","load-type":["third-party"],"unless-domain":["*inspectlet.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?domodomain\\.com","load-type":["third-party"],"unless-domain":["*intelligencefocus.com","*domodomain.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intelligencefocus\\.com","load-type":["third-party"],"unless-domain":["*intelligencefocus.com","*domodomain.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intercom\\.io","load-type":["third-party"],"unless-domain":["*intercom.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kissmetrics\\.com","load-type":["third-party"],"unless-domain":["*kissmetrics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?keymetric\\.net","load-type":["third-party"],"unless-domain":["*keymetric.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?src\\.kitcode\\.net","load-type":["third-party"],"unless-domain":["*src.kitcode.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?linezing\\.com","load-type":["third-party"],"unless-domain":["*linezing.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?liveperson\\.com","load-type":["third-party"],"unless-domain":["*liveperson.com","*nuconomy.com","*liveperson.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nuconomy\\.com","load-type":["third-party"],"unless-domain":["*liveperson.com","*nuconomy.com","*liveperson.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?logdy\\.com","load-type":["third-party"],"unless-domain":["*logdy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crwdcntrl\\.net","load-type":["third-party"],"unless-domain":["*lotame.com","*crwdcntrl.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lotame\\.com","load-type":["third-party"],"unless-domain":["*lotame.com","*crwdcntrl.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lynchpin\\.com","load-type":["third-party"],"unless-domain":["*lynchpin.com","*lypn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lypn\\.com","load-type":["third-party"],"unless-domain":["*lynchpin.com","*lypn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clicktracks\\.com","load-type":["third-party"],"unless-domain":["*lyris.com","*clicktracks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lyris\\.com","load-type":["third-party"],"unless-domain":["*lyris.com","*clicktracks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lytiks\\.com","load-type":["third-party"],"unless-domain":["*lytiks.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marktest\\.com","load-type":["third-party"],"unless-domain":["*marktest.com","*marktest.pt"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marktest\\.pt","load-type":["third-party"],"unless-domain":["*marktest.com","*marktest.pt"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?maxymiser\\.com","load-type":["third-party"],"unless-domain":["*maxymiser.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?meetrics\\.de","load-type":["third-party"],"unless-domain":["*meetrics.de","*meetrics.net","*de.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?meetrics\\.net","load-type":["third-party"],"unless-domain":["*meetrics.de","*meetrics.net","*de.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?research\\.de\\.com","load-type":["third-party"],"unless-domain":["*meetrics.de","*meetrics.net","*de.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crm-metrix\\.com","load-type":["third-party"],"unless-domain":["*metrixlab.com","*crm-metrix.com","*customerconversio.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?customerconversio\\.com","load-type":["third-party"],"unless-domain":["*metrixlab.com","*crm-metrix.com","*customerconversio.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?metrixlab\\.com","load-type":["third-party"],"unless-domain":["*metrixlab.com","*crm-metrix.com","*customerconversio.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mixpanel\\.com","load-type":["third-party"],"unless-domain":["*mixpanel.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mongoosemetrics\\.com","load-type":["third-party"],"unless-domain":["*mongoosemetrics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?monitus\\.net","load-type":["third-party"],"unless-domain":["*monitus.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mouseflow\\.com","load-type":["third-party"],"unless-domain":["*mouseflow.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mypagerank\\.net","load-type":["third-party"],"unless-domain":["*mypagerank.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?estat\\.com","load-type":["third-party"],"unless-domain":["*mediametrie-estat.com","*estat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mediametrie-estat\\.com","load-type":["third-party"],"unless-domain":["*mediametrie-estat.com","*estat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hitsprocessor\\.com","load-type":["third-party"],"unless-domain":["*netapplications.com","*hitsprocessor.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?netapplications\\.com","load-type":["third-party"],"unless-domain":["*netapplications.com","*hitsprocessor.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?newrelic\\.com","load-type":["third-party"],"unless-domain":["*newrelic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nr-data\\.net","load-type":["third-party"],"unless-domain":["*newrelic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?apnewsregistry\\.com","load-type":["third-party"],"unless-domain":["*newsright.com","*apnewsregistry.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nextstat\\.com","load-type":["third-party"],"unless-domain":["*nextstat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?glanceguide\\.com","load-type":["third-party"],"unless-domain":["*nielsen.com","*imrworldwide.com","*imrworldwide.net","*glanceguide.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nielsen\\.com","load-type":["third-party"],"unless-domain":["*nielsen.com","*imrworldwide.com","*imrworldwide.net","*glanceguide.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?observerapp\\.com","load-type":["third-party"],"unless-domain":["*observerapp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?onestat\\.com","load-type":["third-party"],"unless-domain":["*onestat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?openstat\\.ru","load-type":["third-party"],"unless-domain":["*openstat.ru","*spylog.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spylog\\.com","load-type":["third-party"],"unless-domain":["*openstat.ru","*spylog.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?opentracker\\.net","load-type":["third-party"],"unless-domain":["*opentracker.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?persianstat\\.com","load-type":["third-party"],"unless-domain":["*persianstat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?phonalytics\\.com","load-type":["third-party"],"unless-domain":["*phonalytics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?piwik\\.org","load-type":["third-party"],"unless-domain":["*piwik.org"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pronunciator\\.com","load-type":["third-party"],"unless-domain":["*pronunciator.com","*visitorville.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visitorville\\.com","load-type":["third-party"],"unless-domain":["*pronunciator.com","*visitorville.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kissinsights\\.com","load-type":["third-party"],"unless-domain":["*qualaroo.com","*kissinsights.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?qualaroo\\.com","load-type":["third-party"],"unless-domain":["*qualaroo.com","*kissinsights.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thecounter\\.com","load-type":["third-party"],"unless-domain":["*quinstreet.com","*thecounter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?quintelligence\\.com","load-type":["third-party"],"unless-domain":["*quintelligence.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?radarurl\\.com","load-type":["third-party"],"unless-domain":["*radarurl.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?researchnow\\.com","load-type":["third-party"],"unless-domain":["*researchnow.com","*valuedopinions.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?valuedopinions\\.co\\.uk","load-type":["third-party"],"unless-domain":["*researchnow.com","*valuedopinions.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?revtrax\\.com","load-type":["third-party"],"unless-domain":["*revtrax.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ringier\\.cz","load-type":["third-party"],"unless-domain":["*ringier.cz"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?getclicky\\.com","load-type":["third-party"],"unless-domain":["*roxr.net","*getclicky.com","*staticstuff.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?roxr\\.net","load-type":["third-party"],"unless-domain":["*roxr.net","*getclicky.com","*staticstuff.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?staticstuff\\.net","load-type":["third-party"],"unless-domain":["*roxr.net","*getclicky.com","*staticstuff.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?statsit\\.com","load-type":["third-party"],"unless-domain":["*statsit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dl-rms\\.com","load-type":["third-party"],"unless-domain":["*safecount.net","*dl-rms.com","*dlqm.net","*questionmarket.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dlqm\\.net","load-type":["third-party"],"unless-domain":["*safecount.net","*dl-rms.com","*dlqm.net","*questionmarket.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?questionmarket\\.com","load-type":["third-party"],"unless-domain":["*safecount.net","*dl-rms.com","*dlqm.net","*questionmarket.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?safecount\\.net","load-type":["third-party"],"unless-domain":["*safecount.net","*dl-rms.com","*dlqm.net","*questionmarket.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sageanalyst\\.net","load-type":["third-party"],"unless-domain":["*sagemetrics.com","*sageanalyst.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sagemetrics\\.com","load-type":["third-party"],"unless-domain":["*sagemetrics.com","*sageanalyst.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?seevolution\\.com","load-type":["third-party"],"unless-domain":["*seevolution.com","*svlu.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?svlu\\.net","load-type":["third-party"],"unless-domain":["*seevolution.com","*svlu.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?segment\\.io","load-type":["third-party"],"unless-domain":["*segment.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shinystat\\.com","load-type":["third-party"],"unless-domain":["*shinystat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shorte\\.st","load-type":["third-party"],"unless-domain":["*shorte.st"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?snoobi\\.com","load-type":["third-party"],"unless-domain":["*snoobi.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?statcounter\\.com","load-type":["third-party"],"unless-domain":["*statcounter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?statisfy\\.net","load-type":["third-party"],"unless-domain":["*statisfy.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?stratigent\\.com","load-type":["third-party"],"unless-domain":["*stratigent.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tensquare\\.com","load-type":["third-party"],"unless-domain":["*tensquare.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sesamestats\\.com","load-type":["third-party"],"unless-domain":["*tnsglobal.com","*sesamestats.com","*statistik-gallup.net","*tns-counter.ru","*tns-cs.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?statistik-gallup\\.net","load-type":["third-party"],"unless-domain":["*tnsglobal.com","*sesamestats.com","*statistik-gallup.net","*tns-counter.ru","*tns-cs.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tns-counter\\.ru","load-type":["third-party"],"unless-domain":["*tnsglobal.com","*sesamestats.com","*statistik-gallup.net","*tns-counter.ru","*tns-cs.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tns-cs\\.net","load-type":["third-party"],"unless-domain":["*tnsglobal.com","*sesamestats.com","*statistik-gallup.net","*tns-counter.ru","*tns-cs.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tnsglobal\\.com","load-type":["third-party"],"unless-domain":["*tnsglobal.com","*sesamestats.com","*statistik-gallup.net","*tns-counter.ru","*tns-cs.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tealium\\.com","load-type":["third-party"],"unless-domain":["*tealium.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tiqcdn\\.com","load-type":["third-party"],"unless-domain":["*tealium.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?heronpartners\\.com\\.au","load-type":["third-party"],"unless-domain":["*www.heronpartners.com.au","*heronpartners.com.au","*marinsm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?marinsm\\.com","load-type":["third-party"],"unless-domain":["*www.heronpartners.com.au","*heronpartners.com.au","*marinsm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?roia\\.biz","load-type":["third-party"],"unless-domain":["*trackingsoft.com","*roia.biz"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trackingsoft\\.com","load-type":["third-party"],"unless-domain":["*trackingsoft.com","*roia.biz"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?umbel\\.com","load-type":["third-party"],"unless-domain":["*umbel.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nakanohito\\.jp","load-type":["third-party"],"unless-domain":["*nakanohito.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vertster\\.com","load-type":["third-party"],"unless-domain":["*vertster.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sa-as\\.com","load-type":["third-party"],"unless-domain":["*visistat.com","*sa-as.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visistat\\.com","load-type":["third-party"],"unless-domain":["*visistat.com","*sa-as.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visitstreamer\\.com","load-type":["third-party"],"unless-domain":["*visitstreamer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vizisense\\.com","load-type":["third-party"],"unless-domain":["*vizisense.com","*vizisense.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vizisense\\.net","load-type":["third-party"],"unless-domain":["*vizisense.com","*vizisense.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wowanalytics\\.co\\.uk","load-type":["third-party"],"unless-domain":["*wowanalytics.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?compete\\.com","load-type":["third-party"],"unless-domain":["*wpp.com","*247realmedia.com","*accelerator-media.com","*acceleratorusa.com","*decdna.net","*decideinteractive.com","*gmads.net","*groupm.com","*kantarmedia.com","*mecglobal.com","*mindshare.nl","*mookie1.com","*pm14.com","*realmedia.com","*targ.ad","*themig.com","*xaxis.com","*compete.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?onlinewebstats\\.com","load-type":["third-party"],"unless-domain":["*onlinewebstats.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?web-stat\\.com","load-type":["third-party"],"unless-domain":["*webtrackingservices.com","*web-stat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webtrackingservices\\.com","load-type":["third-party"],"unless-domain":["*webtrackingservices.com","*web-stat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webtraxs\\.com","load-type":["third-party"],"unless-domain":["*webtraxs.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webclicktracker\\.com","load-type":["third-party"],"unless-domain":["*webclicktracker.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webtrekk\\.com","load-type":["third-party"],"unless-domain":["*webtrekk.com","*webtrekk.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webtrekk\\.net","load-type":["third-party"],"unless-domain":["*webtrekk.com","*webtrekk.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reinvigorate\\.net","load-type":["third-party"],"unless-domain":["*webtrends.com","*reinvigorate.net","*webtrendslive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webtrends\\.com","load-type":["third-party"],"unless-domain":["*webtrends.com","*reinvigorate.net","*webtrendslive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webtrendslive\\.com","load-type":["third-party"],"unless-domain":["*webtrends.com","*reinvigorate.net","*webtrendslive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?woopra-ns\\.com","load-type":["third-party"],"unless-domain":["*woopra.com","*woopra-ns.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?woopra\\.com","load-type":["third-party"],"unless-domain":["*woopra.com","*woopra-ns.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wysistat\\.com","load-type":["third-party"],"unless-domain":["*wysistat.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?analytics\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yellowtracker\\.com","load-type":["third-party"],"unless-domain":["*yellowtracker.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?anormal-media\\.de","load-type":["third-party"],"unless-domain":["*anormal-media.de","*anormal-tracker.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?anormal-tracker\\.de","load-type":["third-party"],"unless-domain":["*anormal-media.de","*anormal-tracker.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?certifica\\.com","load-type":["third-party"],"unless-domain":["*comscore.com","*adxpose.com","*certifica.com","*scorecardresearch.com","*sitestat.com","*voicefive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?comscore\\.com","load-type":["third-party"],"unless-domain":["*comscore.com","*adxpose.com","*certifica.com","*scorecardresearch.com","*sitestat.com","*voicefive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?scorecardresearch\\.com","load-type":["third-party"],"unless-domain":["*comscore.com","*adxpose.com","*certifica.com","*scorecardresearch.com","*sitestat.com","*voicefive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sitestat\\.com","load-type":["third-party"],"unless-domain":["*comscore.com","*adxpose.com","*certifica.com","*scorecardresearch.com","*sitestat.com","*voicefive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?voicefive\\.com","load-type":["third-party"],"unless-domain":["*comscore.com","*adxpose.com","*certifica.com","*scorecardresearch.com","*sitestat.com","*voicefive.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dwstat\\.cn","load-type":["third-party"],"unless-domain":["*dwstat.cn"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?eproof\\.com","load-type":["third-party"],"unless-domain":["*eproof.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?extreme-dm\\.com","load-type":["third-party"],"unless-domain":["*extremetracking.com","*extreme-dm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?extremetracking\\.com","load-type":["third-party"],"unless-domain":["*extremetracking.com","*extreme-dm.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?etracker\\.com","load-type":["third-party"],"unless-domain":["*etracker.com","*etracker.de","*sedotracker.com","*sedotracker.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?etracker\\.de","load-type":["third-party"],"unless-domain":["*etracker.com","*etracker.de","*sedotracker.com","*sedotracker.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sedotracker\\.com","load-type":["third-party"],"unless-domain":["*etracker.com","*etracker.de","*sedotracker.com","*sedotracker.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sedotracker\\.de","load-type":["third-party"],"unless-domain":["*etracker.com","*etracker.de","*sedotracker.com","*sedotracker.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iperceptions\\.com","load-type":["third-party"],"unless-domain":["*iperceptions.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?motigo\\.com","load-type":["third-party"],"unless-domain":["*motigo.com","*nedstatbasic.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nedstatbasic\\.net","load-type":["third-party"],"unless-domain":["*motigo.com","*nedstatbasic.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nurago\\.com","load-type":["third-party"],"unless-domain":["*nurago.com","*nurago.de","*sensic.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nurago\\.de","load-type":["third-party"],"unless-domain":["*nurago.com","*nurago.de","*sensic.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sensic\\.net","load-type":["third-party"],"unless-domain":["*nurago.com","*nurago.de","*sensic.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?phpmyvisites\\.us","load-type":["third-party"],"unless-domain":["*phpmyvisites.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?4u\\.pl","load-type":["third-party"],"unless-domain":["*4u.pl"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vistrac\\.com","load-type":["third-party"],"unless-domain":["*vistrac.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amung\\.us","load-type":["third-party"],"unless-domain":["*amung.us"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oewa\\.at","load-type":["third-party"],"unless-domain":["*oewa.at","*oewabox.at"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oewabox\\.at","load-type":["third-party"],"unless-domain":["*oewa.at","*oewabox.at"]}}] \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/ContentBlocker/disconnect-content.json b/mobile/ios/Client/Frontend/ContentBlocker/disconnect-content.json new file mode 100644 index 0000000000..927a0c7a5d --- /dev/null +++ b/mobile/ios/Client/Frontend/ContentBlocker/disconnect-content.json @@ -0,0 +1 @@ +[{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tynt\\.com","load-type":["third-party"],"unless-domain":["*33across.com","*tynt.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?activengage\\.com","load-type":["third-party"],"unless-domain":["*activengage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adap\\.tv","load-type":["third-party"],"unless-domain":["*adap.tv"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?adobe\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?typekit\\.com","load-type":["third-party"],"unless-domain":["*adobe.com","*2o7.net","*auditude.com","*demdex.com","*demdex.net","*dmtracker.com","*efrontier.com","*everestads.net","*everestjs.net","*everesttech.net","*hitbox.com","*omniture.com","*omtrdc.net","*touchclarity.com","*typekit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?abmr\\.net","load-type":["third-party"],"unless-domain":["*akamai.com","*imiclk.com","*abmr.net","*edgesuite.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?akamai\\.com","load-type":["third-party"],"unless-domain":["*akamai.com","*imiclk.com","*abmr.net","*edgesuite.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?edgesuite\\.net","load-type":["third-party"],"unless-domain":["*akamai.com","*imiclk.com","*abmr.net","*edgesuite.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?akqa\\.com","load-type":["third-party"],"unless-domain":["*akqa.com","*srtk.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?srtk\\.net","load-type":["third-party"],"unless-domain":["*akqa.com","*srtk.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazon\\.com","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cloudfront\\.net","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?amazonaws\\.com","load-type":["third-party"],"unless-domain":["*amazon.com","*amazon-adsystem.com","*amazon.ca","*amazon.co.jp","*amazon.co.uk","*amazon.de","*amazon.es","*amazon.fr","*amazon.it","*assoc-amazon.com","*alexa.com","*alexametrics.com","*cloudfront.net","*amazonaws.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?5min\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aim\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aol\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aolanswers\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aolcdn\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aoltechguru\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?autoblog\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cambio\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dailyfinance\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?editions\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?engadget\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?games\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?homesessive\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?huffingtonpost\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?joystiq\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kitchendaily\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?makers\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mandatory\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mapquest\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?moviefone\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?noisecreep\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?patch\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pawnation\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shortcuts\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shoutcast\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?spinner\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?stylelist\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?stylemepretty\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?surphace\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?techcrunch\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?theboombox\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?theboot\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tuaw\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?userplane\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?winamp\\.com","load-type":["third-party"],"unless-domain":["*aol.com","*adsonar.com","*advertising.com","*atwola.com","*leadback.com","*tacoda.net","*5min.com","*aim.com","*aolcdn.com","*aoltechguru.com","*autoblog.com","*cambio.com","*dailyfinance.com","*editions.com","*engadget.com","*games.com","*homesessive.com","*huffingtonpost.com","*joystiq.com","*kitchendaily.com","*makers.com","*mandatory.com","*mapquest.com","*moviefone.com","*noisecreep.com","*patch.com","*pawnation.com","*shortcuts.com","*shoutcast.com","*spinner.com","*stylelist.com","*stylemepretty.com","*surphace.com","*techcrunch.com","*theboombox.com","*theboot.com","*tuaw.com","*userplane.com","*winamp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?automattic\\.com","load-type":["third-party"],"unless-domain":["*automattic.com","*polldaddy.com","*gravatar.com","*intensedebate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gravatar\\.com","load-type":["third-party"],"unless-domain":["*automattic.com","*polldaddy.com","*gravatar.com","*intensedebate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?intensedebate\\.com","load-type":["third-party"],"unless-domain":["*automattic.com","*polldaddy.com","*gravatar.com","*intensedebate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?baynote\\.com","load-type":["third-party"],"unless-domain":["*baynote.com","*baynote.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?baynote\\.net","load-type":["third-party"],"unless-domain":["*baynote.com","*baynote.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bazaarvoice\\.com","load-type":["third-party"],"unless-domain":["*bazaarvoice.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bigdoor\\.com","load-type":["third-party"],"unless-domain":["*bigdoor.com","*onetruefan.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?onetruefan\\.com","load-type":["third-party"],"unless-domain":["*bigdoor.com","*onetruefan.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?brightcove\\.com","load-type":["third-party"],"unless-domain":["*brightcove.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?browser-update\\.org","load-type":["third-party"],"unless-domain":["*browser-update.org"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?btbuckets\\.com","load-type":["third-party"],"unless-domain":["*btbuckets.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bufferapp\\.com","load-type":["third-party"],"unless-domain":["*bufferapp.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bunchball\\.com","load-type":["third-party"],"unless-domain":["*bunchball.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buysafe\\.com","load-type":["third-party"],"unless-domain":["*buysafe.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buzzfed\\.com","load-type":["third-party"],"unless-domain":["*buzzfeed.com","*buzzfed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buzzfeed\\.com","load-type":["third-party"],"unless-domain":["*buzzfeed.com","*buzzfed.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cbox\\.ws","load-type":["third-party"],"unless-domain":["*cbox.ws"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cbsinteractive\\.com","load-type":["third-party"],"unless-domain":["*cbsinteractive.com","*com.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?com\\.com","load-type":["third-party"],"unless-domain":["*cbsinteractive.com","*com.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cedexis\\.com","load-type":["third-party"],"unless-domain":["*cedexis.com","*cedexis.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?cedexis\\.net","load-type":["third-party"],"unless-domain":["*cedexis.com","*cedexis.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?certona\\.com","load-type":["third-party"],"unless-domain":["*certona.com","*res-x.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?res-x\\.com","load-type":["third-party"],"unless-domain":["*certona.com","*res-x.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clipsyndicate\\.com","load-type":["third-party"],"unless-domain":["*clipsyndicate.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?collarity\\.com","load-type":["third-party"],"unless-domain":["*collarity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?conduit-banners\\.com","load-type":["third-party"],"unless-domain":["*conduit.com","*conduit-banners.com","*conduit-services.com","*wibiya.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?conduit-services\\.com","load-type":["third-party"],"unless-domain":["*conduit.com","*conduit-banners.com","*conduit-services.com","*wibiya.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?conduit\\.com","load-type":["third-party"],"unless-domain":["*conduit.com","*conduit-banners.com","*conduit-services.com","*wibiya.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wibiya\\.com","load-type":["third-party"],"unless-domain":["*conduit.com","*conduit-banners.com","*conduit-services.com","*wibiya.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?congoo\\.com","load-type":["third-party"],"unless-domain":["*congoo.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?contactatonce\\.com","load-type":["third-party"],"unless-domain":["*contactatonce.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?conviva\\.com","load-type":["third-party"],"unless-domain":["*conviva.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?dailyme\\.com","load-type":["third-party"],"unless-domain":["*dailyme.com","*newstogram.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?newstogram\\.com","load-type":["third-party"],"unless-domain":["*dailyme.com","*newstogram.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?datasift\\.com","load-type":["third-party"],"unless-domain":["*datasift.com","*tweetmeme.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tweetmeme\\.com","load-type":["third-party"],"unless-domain":["*datasift.com","*tweetmeme.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?disqus\\.com","load-type":["third-party"],"unless-domain":["*disqus.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?aboutecho\\.com","load-type":["third-party"],"unless-domain":["*aboutecho.com","*haloscan.com","*js-kit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?haloscan\\.com","load-type":["third-party"],"unless-domain":["*aboutecho.com","*haloscan.com","*js-kit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?js-kit\\.com","load-type":["third-party"],"unless-domain":["*aboutecho.com","*haloscan.com","*js-kit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?akamaihd\\.net","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?instagram\\.com","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fbcdn\\.net","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?flattr\\.com","load-type":["third-party"],"unless-domain":["*flattr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?freewheel\\.tv","load-type":["third-party"],"unless-domain":["*freewheel.tv","*fwmrm.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fwmrm\\.net","load-type":["third-party"],"unless-domain":["*freewheel.tv","*fwmrm.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?genius\\.com","load-type":["third-party"],"unless-domain":["*genius.com","*rsvpgenius.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?getsatisfaction\\.com","load-type":["third-party"],"unless-domain":["*getsatisfaction.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gigcount\\.com","load-type":["third-party"],"unless-domain":["*gigya.com","*gigcount.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gigya\\.com","load-type":["third-party"],"unless-domain":["*gigya.com","*gigcount.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?globaltakeoff\\.com","load-type":["third-party"],"unless-domain":["*globaltakeoff.com","*globaltakeoff.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?globaltakeoff\\.net","load-type":["third-party"],"unless-domain":["*globaltakeoff.com","*globaltakeoff.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?formalyzer\\.com","load-type":["third-party"],"unless-domain":["*gogrid.com","*formalyzer.com","*komli.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gogrid\\.com","load-type":["third-party"],"unless-domain":["*gogrid.com","*formalyzer.com","*komli.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?komli\\.net","load-type":["third-party"],"unless-domain":["*gogrid.com","*formalyzer.com","*komli.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?apture\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blogger\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?feedburner\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ggpht\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gmodules\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google-melange\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ad","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ae","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.af","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ag","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ai","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.al","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.am","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.ao","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ar","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.as","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.at","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.au","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.az","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ba","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.bd","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.be","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.bf","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.bg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.bh","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.bi","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.bj","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.bn","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.bo","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.br","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.bs","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.bt","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.bw","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.by","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.bz","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ca","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cd","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cf","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ch","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ci","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.ck","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cl","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cn","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.co","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?accounts\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?apis\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?appengine\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?books\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?checkout\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?chrome\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?code\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?codesearch\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?docs\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?drive\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?earth\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?encrypted\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?feedburner\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?feedproxy\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?finance\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?groups\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?health\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?images\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?investor\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?knol\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?maps\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?music\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?news\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?picasa\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?picasaweb\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?play\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?script\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shopping\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sites\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sketchup\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?support\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?talk\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?talkgadget\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?toolbar\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?translate\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trends\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?video\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?videos\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wallet\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?www\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.cr","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.cu","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cv","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.cy","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cz","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.de","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.dj","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.dk","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.dm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.do","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.dz","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ec","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ee","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.eg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.es","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.et","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.fi","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.fj","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.fm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.fr","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ga","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ge","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.gg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.gh","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.gi","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.gl","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.gm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.gp","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.gr","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.gt","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.gy","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.hk","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.hn","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.hr","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ht","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.hu","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.id","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ie","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.il","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.im","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.in","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.iq","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.is","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.it","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.je","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.jm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.jo","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.jp","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.ke","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.kh","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ki","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.kg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.kr","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.kw","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.kz","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.la","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.lb","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.li","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.lk","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.ls","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.lt","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.lu","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.lv","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ly","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.ma","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.md","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.me","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.mg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.mk","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ml","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.mm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.mn","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ms","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.mt","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.mu","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.mv","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.mw","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.mx","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.my","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.mz","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.na","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.nf","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ng","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ni","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ne","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.nl","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.no","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.np","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.nr","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.nu","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.nz","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.om","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.pa","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.pe","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.pg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ph","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.pk","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.pl","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.pn","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.pr","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ps","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.pt","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.py","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.qa","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ro","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ru","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.rw","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.sa","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.sb","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.sc","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.se","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.sg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.sh","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.si","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.sk","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.sl","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.sn","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.so","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.sm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.st","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.sv","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.td","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.tg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.th","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.tj","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.tk","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.tl","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.tm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.tn","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.to","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.tr","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.tt","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.tw","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.tz","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.ua","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.ug","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.uk","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.uy","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.uz","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.vc","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.ve","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.vg","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.vi","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.com\\.vn","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.vu","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.ws","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.rs","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.za","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.zm","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.co\\.zw","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?google\\.cat","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?googleapis\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?googleartproject\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?googleusercontent\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gstatic\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?panoramio\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?postini\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?recaptcha\\.net","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?youtube\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gravity\\.com","load-type":["third-party"],"unless-domain":["*gravity.com","*grvcdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?grvcdn\\.com","load-type":["third-party"],"unless-domain":["*gravity.com","*grvcdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?heyzap\\.com","load-type":["third-party"],"unless-domain":["*heyzap.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hubspot\\.com","load-type":["third-party"],"unless-domain":["*hubspot.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iesnare\\.com","load-type":["third-party"],"unless-domain":["*iovation.com","*iesnare.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iovation\\.com","load-type":["third-party"],"unless-domain":["*iovation.com","*iesnare.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kaltura\\.com","load-type":["third-party"],"unless-domain":["*kaltura.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?kikin\\.com","load-type":["third-party"],"unless-domain":["*kikin.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clickability\\.com","load-type":["third-party"],"unless-domain":["*limelight.com","*clickability.com","*llnwd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?limelight\\.com","load-type":["third-party"],"unless-domain":["*limelight.com","*clickability.com","*llnwd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?llnwd\\.net","load-type":["third-party"],"unless-domain":["*limelight.com","*clickability.com","*llnwd.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fyre\\.co","load-type":["third-party"],"unless-domain":["*livefyre.com","*fyre.co"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?livefyre\\.com","load-type":["third-party"],"unless-domain":["*livefyre.com","*fyre.co"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?liveperson\\.net","load-type":["third-party"],"unless-domain":["*liveperson.com","*nuconomy.com","*liveperson.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?liverail\\.com","load-type":["third-party"],"unless-domain":["*liverail.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?longtailvideo\\.com","load-type":["third-party"],"unless-domain":["*longtailvideo.com","*ltassrv.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ltassrv\\.com","load-type":["third-party"],"unless-domain":["*longtailvideo.com","*ltassrv.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?luminate\\.com","load-type":["third-party"],"unless-domain":["*luminate.com","*pixazza.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pixazza\\.com","load-type":["third-party"],"unless-domain":["*luminate.com","*pixazza.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?markit\\.com","load-type":["third-party"],"unless-domain":["*markit.com","*wsod.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wsod\\.com","load-type":["third-party"],"unless-domain":["*markit.com","*wsod.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mashlogic\\.com","load-type":["third-party"],"unless-domain":["*mashlogic.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mcafee\\.com","load-type":["third-party"],"unless-domain":["*mcafee.com","*scanalert.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?scanalert\\.com","load-type":["third-party"],"unless-domain":["*mcafee.com","*scanalert.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?bing\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gamesforwindows\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?getgamesmart\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?healthvault\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ieaddons\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?iegallery\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?live\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?microsoft\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?microsoftalumni\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?microsoftalumni\\.org","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?microsoftstore\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?msn\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?msnbc\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?msndirect\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?nbcnews\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?office\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?officelive\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?outlook\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?s-msn\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?skype\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?windowsphone\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?worldwidetelescope\\.org","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xbox\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zune\\.com","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zune\\.net","load-type":["third-party"],"unless-domain":["*microsoft.com","*adbureau.net","*adecn.com","*aquantive.com","*atdmt.com","*msads.net","*netconversions.com","*roiservice.com","*bing.com","*gamesforwindows.com","*getgamesmart.com","*healthvault.com","*ieaddons.com","*iegallery.com","*live.com","*microsoftalumni.com","*microsoftalumni.org","*microsoftstore.com","*msn.com","*msnbc.com","*nbcnews.com","*office.com","*officelive.com","*outlook.com","*s-msn.com","*skype.com","*windowsphone.com","*worldwidetelescope.org","*xbox.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?newsinc\\.com","load-type":["third-party"],"unless-domain":["*newsinc.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?blaze\\.com","load-type":["third-party"],"unless-domain":["*oberon-media.com","*blaze.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oberon-media\\.com","load-type":["third-party"],"unless-domain":["*oberon-media.com","*blaze.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?olark\\.com","load-type":["third-party"],"unless-domain":["*olark.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oo4\\.com","load-type":["third-party"],"unless-domain":["*ooyala.com","*oo4.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ooyala\\.com","load-type":["third-party"],"unless-domain":["*ooyala.com","*oo4.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?optimizely\\.com","load-type":["third-party"],"unless-domain":["*optimizely.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?atgsvcs\\.com","load-type":["third-party"],"unless-domain":["*oracle.com","*estara.com","*atgsvcs.com","*instantservice.com","*istrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?instantservice\\.com","load-type":["third-party"],"unless-domain":["*oracle.com","*estara.com","*atgsvcs.com","*instantservice.com","*istrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?istrack\\.com","load-type":["third-party"],"unless-domain":["*oracle.com","*estara.com","*atgsvcs.com","*instantservice.com","*istrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?oracle\\.com","load-type":["third-party"],"unless-domain":["*oracle.com","*estara.com","*atgsvcs.com","*instantservice.com","*istrack.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?parsely\\.com","load-type":["third-party"],"unless-domain":["*parsely.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?peerius\\.com","load-type":["third-party"],"unless-domain":["*peerius.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pinterest\\.com","load-type":["third-party"],"unless-domain":["*pinterest.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?punchtab\\.com","load-type":["third-party"],"unless-domain":["*punchtab.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rim\\.com","load-type":["third-party"],"unless-domain":["*rim.com","*scoreloop.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?scoreloop\\.com","load-type":["third-party"],"unless-domain":["*rim.com","*scoreloop.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?saymedia\\.com","load-type":["third-party"],"unless-domain":["*saymedia.com","*typepad.com","*videoegg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?typepad\\.com","load-type":["third-party"],"unless-domain":["*saymedia.com","*typepad.com","*videoegg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?videoegg\\.com","load-type":["third-party"],"unless-domain":["*saymedia.com","*typepad.com","*videoegg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?scribefire\\.com","load-type":["third-party"],"unless-domain":["*scribefire.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sixapart\\.com","load-type":["third-party"],"unless-domain":["*sixapart.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?skribit\\.com","load-type":["third-party"],"unless-domain":["*skribit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?snapengage\\.com","load-type":["third-party"],"unless-domain":["*snapengage.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?springmetrics\\.com","load-type":["third-party"],"unless-domain":["*springmetrics.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?superfish\\.com","load-type":["third-party"],"unless-domain":["*superfish.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?synacor\\.com","load-type":["third-party"],"unless-domain":["*synacor.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thinglink\\.com","load-type":["third-party"],"unless-domain":["*thinglink.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thismoment\\.com","load-type":["third-party"],"unless-domain":["*thismoment.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?thummit\\.com","load-type":["third-party"],"unless-domain":["*thummit.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?topsy\\.com","load-type":["third-party"],"unless-domain":["*topsy.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tracemyip\\.org","load-type":["third-party"],"unless-domain":["*tracemyip.org"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trackset\\.com","load-type":["third-party"],"unless-domain":["*trackset.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trovus\\.co\\.uk","load-type":["third-party"],"unless-domain":["*www.trovus.co.uk","*trovus.co.uk"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?trumba\\.com","load-type":["third-party"],"unless-domain":["*trumba.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tumblr\\.com","load-type":["third-party"],"unless-domain":["*tumblr.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?turn\\.com","load-type":["third-party"],"unless-domain":["*turn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?turnto\\.com","load-type":["third-party"],"unless-domain":["*turntonetworks.com","*turnto.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?turntonetworks\\.com","load-type":["third-party"],"unless-domain":["*turntonetworks.com","*turnto.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tweetboard\\.com","load-type":["third-party"],"unless-domain":["*tweetboard.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?truste\\.com","load-type":["third-party"],"unless-domain":["*truste.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?twittercounter\\.com","load-type":["third-party"],"unless-domain":["*twittercounter.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ubermedia\\.com","load-type":["third-party"],"unless-domain":["*ubermedia.com","*tweetup.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tweetup\\.com","load-type":["third-party"],"unless-domain":["*ubermedia.com","*tweetup.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ubertags\\.com","load-type":["third-party"],"unless-domain":["*ubertags.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?unbounce\\.com","load-type":["third-party"],"unless-domain":["*unbounce.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?uptrends\\.com","load-type":["third-party"],"unless-domain":["*uptrends.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?usabilitysciences\\.com","load-type":["third-party"],"unless-domain":["*usabilitysciences.com","*webiqonline.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webiqonline\\.com","load-type":["third-party"],"unless-domain":["*usabilitysciences.com","*webiqonline.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?uservoice\\.com","load-type":["third-party"],"unless-domain":["*uservoice.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?verticalacuity\\.com","load-type":["third-party"],"unless-domain":["*verticalacuity.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vgwort\\.de","load-type":["third-party"],"unless-domain":["*vgwort.de"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tidaltv\\.com","load-type":["third-party"],"unless-domain":["*videologygroup.com","*tidaltv.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?videologygroup\\.com","load-type":["third-party"],"unless-domain":["*videologygroup.com","*tidaltv.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?qoof\\.com","load-type":["third-party"],"unless-domain":["*viewbix.com","*qoof.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?viewbix\\.com","load-type":["third-party"],"unless-domain":["*viewbix.com","*qoof.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vimeo\\.com","load-type":["third-party"],"unless-domain":["*vimeo.com","*vimeocdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vimeocdn\\.com","load-type":["third-party"],"unless-domain":["*vimeo.com","*vimeocdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vindicogroup\\.com","load-type":["third-party"],"unless-domain":["*vindicogroup.com","*vindicosuite.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vindicosuite\\.com","load-type":["third-party"],"unless-domain":["*vindicogroup.com","*vindicosuite.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visualrevenue\\.com","load-type":["third-party"],"unless-domain":["*visualrevenue.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?voice2page\\.com","load-type":["third-party"],"unless-domain":["*voice2page.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive0\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive1\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive2\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive3\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive4\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive5\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive6\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive7\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive8\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?websitealive9\\.com","load-type":["third-party"],"unless-domain":["*websitealive.com","*websitealive0.com","*websitealive1.com","*websitealive2.com","*websitealive3.com","*websitealive4.com","*websitealive5.com","*websitealive6.com","*websitealive7.com","*websitealive8.com","*websitealive9.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?visualwebsiteoptimizer\\.com","load-type":["third-party"],"unless-domain":["*wingify.com","*visualwebsiteoptimizer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wingify\\.com","load-type":["third-party"],"unless-domain":["*wingify.com","*visualwebsiteoptimizer.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xtify\\.com","load-type":["third-party"],"unless-domain":["*xtify.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?flickr\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?staticflickr\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?answers\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?apps\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?autos\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?biz\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?developer\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?everything\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?finance\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?games\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?groups\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?help\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?hotjobs\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?info\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?local\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?messages\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?movies\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?msg\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?news\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?omg\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pipes\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?realestate\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?search\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shine\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?smallbusiness\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sports\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?suggestions\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?travel\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?upcoming\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webhosting\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?widgets\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?www\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yahooapis\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yahoofs\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yimg\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ypolicyblog\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yuilibrary\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zenfs\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yandex\\.com","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?web-visor\\.com","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?moikrug\\.ru","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yandex\\.ru","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yandex\\.st","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yandex\\.ua","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yandex\\.com\\.tr","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?yandex\\.by","load-type":["third-party"],"unless-domain":["*yandex.com","*web-visor.com","*moikrug.ru","*yandex.ru","*yandex.st","*yandex.ua","*yandex.com.tr","*yandex.by"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zendesk\\.com","load-type":["third-party"],"unless-domain":["*zendesk.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?zopim\\.com","load-type":["third-party"],"unless-domain":["*zopim.com"]}}] \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/ContentBlocker/disconnect-social.json b/mobile/ios/Client/Frontend/ContentBlocker/disconnect-social.json new file mode 100644 index 0000000000..ce332270bd --- /dev/null +++ b/mobile/ios/Client/Frontend/ContentBlocker/disconnect-social.json @@ -0,0 +1 @@ +[{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addthis\\.com","load-type":["third-party"],"unless-domain":["*addthis.com","*addthiscdn.com","*addthisedge.com","*clearspring.com","*connectedads.net","*xgraph.com","*xgraph.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addthiscdn\\.com","load-type":["third-party"],"unless-domain":["*addthis.com","*addthiscdn.com","*addthisedge.com","*clearspring.com","*connectedads.net","*xgraph.com","*xgraph.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addthisedge\\.com","load-type":["third-party"],"unless-domain":["*addthis.com","*addthiscdn.com","*addthisedge.com","*clearspring.com","*connectedads.net","*xgraph.com","*xgraph.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?clearspring\\.com","load-type":["third-party"],"unless-domain":["*addthis.com","*addthiscdn.com","*addthisedge.com","*clearspring.com","*connectedads.net","*xgraph.com","*xgraph.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?connectedads\\.net","load-type":["third-party"],"unless-domain":["*addthis.com","*addthiscdn.com","*addthisedge.com","*clearspring.com","*connectedads.net","*xgraph.com","*xgraph.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xgraph\\.com","load-type":["third-party"],"unless-domain":["*addthis.com","*addthiscdn.com","*addthisedge.com","*clearspring.com","*connectedads.net","*xgraph.com","*xgraph.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?xgraph\\.net","load-type":["third-party"],"unless-domain":["*addthis.com","*addthiscdn.com","*addthisedge.com","*clearspring.com","*connectedads.net","*xgraph.com","*xgraph.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?causes\\.com","load-type":["third-party"],"unless-domain":["*causes.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?digg\\.com","load-type":["third-party"],"unless-domain":["*digg.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?facebook\\.com","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?facebook\\.de","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?facebook\\.fr","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?facebook\\.net","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?fb\\.com","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?atlassolutions\\.com","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?friendfeed\\.com","load-type":["third-party"],"unless-domain":["*facebook.com","*facebook.de","*facebook.fr","*facebook.net","*fb.com","*fb.me","*friendfeed.com","*instagram.com","*fbcdn.net","*messenger.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?developers\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?gmail\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mail\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?inbox\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?orkut\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?plus\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?plusone\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?voice\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?wave\\.google\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?googlemail\\.com","load-type":["third-party"],"unless-domain":["*abc.xyz","*google.com","*ingress.com","*admeld.com","*blogger.com","*google-melange.com","*google.ad","*google.ae","*google.com.af","*google.com.ag","*google.com.ai","*google.al","*google.am","*google.co.ao","*google.com.ar","*google.as","*google.at","*google.com.au","*google.az","*google.ba","*google.com.bd","*google.be","*google.bf","*google.bg","*google.com.bh","*google.bi","*google.bj","*google.com.bn","*google.com.bo","*google.com.br","*google.bs","*google.bt","*google.co.bw","*google.by","*google.com.bz","*google.ca","*google.cd","*google.cf","*google.cg","*google.ch","*google.ci","*google.co.ck","*google.cl","*google.cm","*google.cn","*google.com.co","*google.co.cr","*google.com.cu","*google.cv","*google.com.cy","*google.cz","*google.de","*google.dj","*google.dk","*google.dm","*google.com.do","*google.dz","*google.com.ec","*google.ee","*google.com.eg","*google.es","*google.com.et","*google.fi","*google.com.fj","*google.fm","*google.fr","*google.ga","*google.ge","*google.gg","*google.com.gh","*google.com.gi","*google.gl","*google.gm","*google.gp","*google.gr","*google.com.gt","*google.gy","*google.com.hk","*google.hn","*google.hr","*google.ht","*google.hu","*google.co.id","*google.ie","*google.co.il","*google.im","*google.co.in","*google.iq","*google.is","*google.it","*google.je","*google.com.jm","*google.jo","*google.co.jp","*google.co.ke","*google.com.kh","*google.ki","*google.kg","*google.co.kr","*google.com.kw","*google.kz","*google.la","*google.com.lb","*google.li","*google.lk","*google.co.ls","*google.lt","*google.lu","*google.lv","*google.com.ly","*google.co.ma","*google.md","*google.me","*google.mg","*google.mk","*google.ml","*google.com.mm","*google.mn","*google.ms","*google.com.mt","*google.mu","*google.mv","*google.mw","*google.com.mx","*google.com.my","*google.co.mz","*google.com.na","*google.com.nf","*google.com.ng","*google.com.ni","*google.ne","*google.nl","*google.no","*google.com.np","*google.nr","*google.nu","*google.co.nz","*google.com.om","*google.com.pa","*google.com.pe","*google.com.pg","*google.com.ph","*google.com.pk","*google.pl","*google.pn","*google.com.pr","*google.ps","*google.pt","*google.com.py","*google.com.qa","*google.ro","*google.ru","*google.rw","*google.com.sa","*google.com.sb","*google.sc","*google.se","*google.com.sg","*google.sh","*google.si","*google.sk","*google.com.sl","*google.sn","*google.so","*google.sm","*google.st","*google.com.sv","*google.td","*google.tg","*google.co.th","*google.com.tj","*google.tk","*google.tl","*google.tm","*google.tn","*google.to","*google.com.tr","*google.tt","*google.com.tw","*google.co.tz","*google.com.ua","*google.co.ug","*google.co.uk","*google.com.uy","*google.co.uz","*google.com.vc","*google.co.ve","*google.vg","*google.co.vi","*google.com.vn","*google.vu","*google.ws","*google.rs","*google.co.za","*google.co.zm","*google.co.zw","*google.cat","*panoramio.com","*youtube.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?licdn\\.com","load-type":["third-party"],"unless-domain":["*linkedin.com","*licdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?linkedin\\.com","load-type":["third-party"],"unless-domain":["*linkedin.com","*licdn.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?addtoany\\.com","load-type":["third-party"],"unless-domain":["*lockerz.com","*addtoany.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?lockerz\\.com","load-type":["third-party"],"unless-domain":["*lockerz.com","*addtoany.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?list\\.ru","load-type":["third-party"],"unless-domain":["*mail.ru","*list.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mail\\.ru","load-type":["third-party"],"unless-domain":["*mail.ru","*list.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?meebo\\.com","load-type":["third-party"],"unless-domain":["*meebo.com","*meebocdn.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?meebocdn\\.net","load-type":["third-party"],"unless-domain":["*meebo.com","*meebocdn.net"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?papayamobile\\.com","load-type":["third-party"],"unless-domain":["*papayamobile.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?sharethis\\.com","load-type":["third-party"],"unless-domain":["*sharethis.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buzzster\\.com","load-type":["third-party"],"unless-domain":["*shareaholic.com","*buzzster.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?shareaholic\\.com","load-type":["third-party"],"unless-domain":["*shareaholic.com","*buzzster.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?stumble-upon\\.com","load-type":["third-party"],"unless-domain":["*stumbleupon.com","*stumble-upon.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?stumbleupon\\.com","load-type":["third-party"],"unless-domain":["*stumbleupon.com","*stumble-upon.com"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?backtype\\.com","load-type":["third-party"],"unless-domain":["*twitter.com","*backtype.com","*crashlytics.com","*tweetdeck.com","*twimg.com","*twitter.jp","*digits.com","*fabric.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?crashlytics\\.com","load-type":["third-party"],"unless-domain":["*twitter.com","*backtype.com","*crashlytics.com","*tweetdeck.com","*twimg.com","*twitter.jp","*digits.com","*fabric.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?tweetdeck\\.com","load-type":["third-party"],"unless-domain":["*twitter.com","*backtype.com","*crashlytics.com","*tweetdeck.com","*twimg.com","*twitter.jp","*digits.com","*fabric.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?twimg\\.com","load-type":["third-party"],"unless-domain":["*twitter.com","*backtype.com","*crashlytics.com","*tweetdeck.com","*twimg.com","*twitter.jp","*digits.com","*fabric.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?twitter\\.com","load-type":["third-party"],"unless-domain":["*twitter.com","*backtype.com","*crashlytics.com","*tweetdeck.com","*twimg.com","*twitter.jp","*digits.com","*fabric.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?twitter\\.jp","load-type":["third-party"],"unless-domain":["*twitter.com","*backtype.com","*crashlytics.com","*tweetdeck.com","*twimg.com","*twitter.jp","*digits.com","*fabric.io"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?userapi\\.com","load-type":["third-party"],"unless-domain":["*vk.com","*userapi.com","*vkontakte.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vk\\.com","load-type":["third-party"],"unless-domain":["*vk.com","*userapi.com","*vkontakte.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?vkontakte\\.ru","load-type":["third-party"],"unless-domain":["*vk.com","*userapi.com","*vkontakte.ru"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mybloglog\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?rocketmail\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?address\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?alerts\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?avatars\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?buzz\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?calendar\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?edit\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?legalredirect\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?login\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?mail\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?my\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?notepad\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?pulse\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?webmessenger\\.yahoo\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?ymail\\.com","load-type":["third-party"],"unless-domain":["*flickr.com","*yuilibrary.com","*tumblr.com","*yahoo.com","*yahoostudios.com","*yahoo.co.jp"]}},{"action":{"type":"block"},"trigger":{"url-filter":"^https?://([^/]+\\.)?reddit\\.com","load-type":["third-party"],"unless-domain":["*reddit.com"]}}] \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/ActivityStreamPanel.swift b/mobile/ios/Client/Frontend/Home/ActivityStreamPanel.swift new file mode 100644 index 0000000000..974fe1545f --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/ActivityStreamPanel.swift @@ -0,0 +1,1073 @@ +/* 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/. */ + +import Shared +import UIKit +import Deferred +import Storage +import SDWebImage +import XCGLogger +import SyncTelemetry +import SnapKit + +private let log = Logger.browserLogger +private let DefaultSuggestedSitesKey = "topSites.deletedSuggestedSites" + +// MARK: - Lifecycle +struct ASPanelUX { + static let backgroundColor = UIConstants.AppBackgroundColor + static let rowSpacing: CGFloat = UIDevice.current.userInterfaceIdiom == .pad ? 30 : 20 + static let highlightCellHeight: CGFloat = UIDevice.current.userInterfaceIdiom == .pad ? 250 : 200 + static let sectionInsetsForSizeClass = UXSizeClasses(compact: 0, regular: 101, other: 14) + static let numberOfItemsPerRowForSizeClassIpad = UXSizeClasses(compact: 3, regular: 4, other: 2) + static let SectionInsetsForIpad: CGFloat = 101 + static let SectionInsetsForIphone: CGFloat = 14 + static let MinimumInsets: CGFloat = 14 + static let BookmarkHighlights = 2 + +} +/* + Size classes are the way Apple requires us to specify our UI. + Split view on iPad can make a landscape app appear with the demensions of an iPhone app + Use UXSizeClasses to specify things like offsets/itemsizes with respect to size classes + For a primer on size classes https://useyourloaf.com/blog/size-classes/ + */ +struct UXSizeClasses { + var compact: CGFloat + var regular: CGFloat + var unspecified: CGFloat + + init(compact: CGFloat, regular: CGFloat, other: CGFloat) { + self.compact = compact + self.regular = regular + self.unspecified = other + } + + subscript(sizeClass: UIUserInterfaceSizeClass) -> CGFloat { + switch sizeClass { + case .compact: + return self.compact + case .regular: + return self.regular + case .unspecified: + return self.unspecified + } + + } +} + +class ActivityStreamPanel: UICollectionViewController, HomePanel { + weak var homePanelDelegate: HomePanelDelegate? + fileprivate let profile: Profile + fileprivate let telemetry: ActivityStreamTracker + fileprivate let pocketAPI = Pocket() + fileprivate let flowLayout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() + + fileprivate let topSitesManager = ASHorizontalScrollCellManager() + fileprivate var showHighlightIntro = false + fileprivate var sessionStart: Timestamp? + + fileprivate lazy var longPressRecognizer: UILongPressGestureRecognizer = { + return UILongPressGestureRecognizer(target: self, action: #selector(ActivityStreamPanel.longPress(_:))) + }() + + // Not used for displaying. Only used for calculating layout. + lazy var topSiteCell: ASHorizontalScrollCell = { + let customCell = ASHorizontalScrollCell(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 0)) + customCell.delegate = self.topSitesManager + return customCell + }() + + var highlights: [Site] = [] + var pocketStories: [PocketStory] = [] + + init(profile: Profile, telemetry: ActivityStreamTracker? = nil) { + self.profile = profile + self.telemetry = telemetry ?? ActivityStreamTracker(eventsTracker: PingCentre.clientForTopic(.ActivityStreamEvents, clientID: profile.clientID), sessionsTracker: PingCentre.clientForTopic(.ActivityStreamSessions, clientID: profile.clientID)) + + super.init(collectionViewLayout: flowLayout) + self.collectionView?.delegate = self + self.collectionView?.dataSource = self + + collectionView?.addGestureRecognizer(longPressRecognizer) + + NotificationCenter.default.addObserver(self, + selector: #selector(didChangeFontSize(notification:)), + name: NotificationDynamicFontChanged, + object: nil) + + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + Section.allValues.forEach { self.collectionView?.register(Section($0.rawValue).cellType, forCellWithReuseIdentifier: Section($0.rawValue).cellIdentifier) } + self.collectionView?.register(ASHeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "Header") + self.collectionView?.register(ASFooterView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "Footer") + collectionView?.backgroundColor = ASPanelUX.backgroundColor + collectionView?.keyboardDismissMode = .onDrag + + self.profile.panelDataObservers.activityStream.delegate = self + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + sessionStart = Date.now() + reloadAll() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + telemetry.reportSessionStop(Date.now() - (sessionStart ?? 0)) + sessionStart = nil + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + coordinator.animate(alongsideTransition: {context in + //The AS context menu does not behave correctly. Dismiss it when rotating. + if let _ = self.presentedViewController as? PhotonActionSheet { + self.presentedViewController?.dismiss(animated: true, completion: nil) + } + self.collectionViewLayout.invalidateLayout() + self.collectionView?.reloadData() + }, completion: nil) + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + self.topSitesManager.currentTraits = self.traitCollection + } + + func didChangeFontSize(notification: Notification) { + // Don't need to invalidate the data for a font change. Just reload the UI. + reloadAll() + } +} + +// MARK: - Section management +extension ActivityStreamPanel { + enum Section: Int { + case topSites + case pocket + case highlights + case highlightIntro + + static let count = 4 + static let allValues = [topSites, pocket, highlights, highlightIntro] + + var title: String? { + switch self { + case .highlights: return Strings.ASHighlightsTitle + case .pocket: return Strings.ASPocketTitle + case .topSites: return nil + case .highlightIntro: return nil + } + } + + var headerHeight: CGSize { + switch self { + case .highlights, .pocket: return CGSize(width: 50, height: 40) + case .topSites: return CGSize(width: 0, height: 0) + case .highlightIntro: return CGSize(width: 50, height: 2) + } + } + + var footerHeight: CGSize { + switch self { + case .highlights, .highlightIntro, .pocket: return CGSize.zero + case .topSites: return CGSize(width: 50, height: 5) + } + } + + func cellHeight(_ traits: UITraitCollection, width: CGFloat) -> CGFloat { + switch self { + case .highlights, .pocket: return ASPanelUX.highlightCellHeight + case .topSites: return 0 //calculated dynamically + case .highlightIntro: return 200 + } + } + + /* + There are edge cases to handle when calculating section insets + - An iPhone 7+ is considered regular width when in landscape + - An iPad in 66% split view is still considered regular width + */ + func sectionInsets(_ traits: UITraitCollection, frameWidth: CGFloat) -> CGFloat { + var currentTraits = traits + if (traits.horizontalSizeClass == .regular && UIScreen.main.bounds.size.width != frameWidth) || UIDevice.current.userInterfaceIdiom == .phone { + currentTraits = UITraitCollection(horizontalSizeClass: .compact) + } + switch self { + case .highlights, .pocket: + var insets = ASPanelUX.sectionInsetsForSizeClass[currentTraits.horizontalSizeClass] + insets = insets + ASPanelUX.MinimumInsets + return insets + case .topSites: + return ASPanelUX.sectionInsetsForSizeClass[currentTraits.horizontalSizeClass] + case .highlightIntro: + return ASPanelUX.sectionInsetsForSizeClass[currentTraits.horizontalSizeClass] + } + } + + func numberOfItemsForRow(_ traits: UITraitCollection) -> CGFloat { + switch self { + case .highlights, .pocket: + var numItems: CGFloat = ASPanelUX.numberOfItemsPerRowForSizeClassIpad[traits.horizontalSizeClass] + if UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation) { + numItems = numItems - 1 + } + if traits.horizontalSizeClass == .compact && UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation) { + numItems = numItems - 1 + } + return numItems + case .topSites, .highlightIntro: + return 1 + } + } + + func cellSize(for traits: UITraitCollection, frameWidth: CGFloat) -> CGSize { + let height = cellHeight(traits, width: frameWidth) + let inset = sectionInsets(traits, frameWidth: frameWidth) * 2 + + switch self { + case .highlights, .pocket: + let numItems = numberOfItemsForRow(traits) + return CGSize(width: floor(((frameWidth - inset) - (ASPanelUX.MinimumInsets * (numItems - 1))) / numItems), height: height) + case .topSites: + return CGSize(width: frameWidth - inset, height: height) + case .highlightIntro: + return CGSize(width: frameWidth - inset - (ASPanelUX.MinimumInsets * 2), height: height) + } + } + + var headerView: UIView? { + switch self { + case .highlights, .highlightIntro, .pocket: + let view = ASHeaderView() + view.title = title + return view + case .topSites: + return nil + } + } + + var cellIdentifier: String { + switch self { + case .topSites: return "TopSiteCell" + case .highlights: return "HistoryCell" + case .pocket: return "PocketCell" + case .highlightIntro: return "HighlightIntroCell" + } + } + + var cellType: UICollectionViewCell.Type { + switch self { + case .topSites: return ASHorizontalScrollCell.self + case .highlights, .pocket: return ActivityStreamHighlightCell.self + case .highlightIntro: return HighlightIntroCell.self + } + } + + init(at indexPath: IndexPath) { + self.init(rawValue: indexPath.section)! + } + + init(_ section: Int) { + self.init(rawValue: section)! + } + } +} + +// MARK: - Tableview Delegate +extension ActivityStreamPanel: UICollectionViewDelegateFlowLayout { + + override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + switch kind { + case UICollectionElementKindSectionHeader: + let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "Header", for: indexPath) as! ASHeaderView + let title = Section(indexPath.section).title + switch Section(indexPath.section) { + case .highlights, .highlightIntro: + view.title = title + return view + case .pocket: + view.title = title + view.moreButton.isHidden = false + view.moreButton.addTarget(self, action: #selector(ActivityStreamPanel.showMorePocketStories), for: .touchUpInside) + return view + case .topSites: + return UICollectionReusableView() + } + case UICollectionElementKindSectionFooter: + let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "Footer", for: indexPath) as! ASFooterView + switch Section(indexPath.section) { + case .highlights, .highlightIntro: + return UICollectionReusableView() + case .topSites, .pocket: + return view + } + default: + return UICollectionReusableView() + } + } + + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + self.longPressRecognizer.isEnabled = false + selectItemAtIndex(indexPath.item, inSection: Section(indexPath.section)) + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let cellSize = Section(indexPath.section).cellSize(for: self.traitCollection, frameWidth: self.view.frame.width) + + switch Section(indexPath.section) { + case .highlights: + if highlights.isEmpty { + return CGSize.zero + } + return cellSize + case .topSites: + // Create a temporary cell so we can calculate the height. + let layout = topSiteCell.collectionView.collectionViewLayout as! HorizontalFlowLayout + let estimatedLayout = layout.calculateLayout(for: CGSize(width: cellSize.width, height: 0)) + return CGSize(width: cellSize.width, height: estimatedLayout.size.height) + case .highlightIntro, .pocket: + return cellSize + } + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + switch Section(section) { + case .highlights: + return highlights.isEmpty ? CGSize.zero : CGSize(width: self.view.frame.size.width, height: Section(section).headerHeight.height) + case .highlightIntro: + return !highlights.isEmpty ? CGSize.zero : CGSize(width: self.view.frame.size.width, height: Section(section).headerHeight.height) + case .pocket: + return pocketStories.isEmpty ? CGSize.zero : Section(section).headerHeight + case .topSites: + return Section(section).headerHeight + } + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { + switch Section(section) { + case .highlights, .highlightIntro, .pocket: + return CGSize.zero + case .topSites: + return Section(section).footerHeight + } + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return 0 + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return ASPanelUX.rowSpacing + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + let insets = Section(section).sectionInsets(self.traitCollection, frameWidth: self.view.frame.width) + return UIEdgeInsets(top: 0, left: insets, bottom: 0, right: insets) + } + + fileprivate func showSiteWithURLHandler(_ url: URL) { + let visitType = VisitType.bookmark + homePanelDelegate?.homePanel(self, didSelectURL: url, visitType: visitType) + } +} + +// MARK: - Tableview Data Source +extension ActivityStreamPanel { + + override func numberOfSections(in collectionView: UICollectionView) -> Int { + return 4 + } + + override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + var numItems: CGFloat = ASPanelUX.numberOfItemsPerRowForSizeClassIpad[self.traitCollection.horizontalSizeClass] + if UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation) { + numItems = numItems - 1 + } + if self.traitCollection.horizontalSizeClass == .compact && UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation) { + numItems = numItems - 1 + } + switch Section(section) { + case .topSites: + return topSitesManager.content.isEmpty ? 0 : 1 + case .highlights: + return self.highlights.count + case .pocket: + return pocketStories.isEmpty ? 0 : Int(numItems) + case .highlightIntro: + return self.highlights.isEmpty && showHighlightIntro && isHighlightsEnabled() ? 1 : 0 + } + } + + override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let identifier = Section(indexPath.section).cellIdentifier + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) + + switch Section(indexPath.section) { + case .topSites: + return configureTopSitesCell(cell, forIndexPath: indexPath) + case .highlights: + return configureHistoryItemCell(cell, forIndexPath: indexPath) + case .pocket: + return configurePocketItemCell(cell, forIndexPath: indexPath) + case .highlightIntro: + return configureHighlightIntroCell(cell, forIndexPath: indexPath) + } + } + + //should all be collectionview + func configureTopSitesCell(_ cell: UICollectionViewCell, forIndexPath indexPath: IndexPath) -> UICollectionViewCell { + let topSiteCell = cell as! ASHorizontalScrollCell + topSiteCell.delegate = self.topSitesManager + topSiteCell.setNeedsLayout() + topSiteCell.collectionView.reloadData() + return cell + } + + func configureHistoryItemCell(_ cell: UICollectionViewCell, forIndexPath indexPath: IndexPath) -> UICollectionViewCell { + let site = highlights[indexPath.row] + let simpleHighlightCell = cell as! ActivityStreamHighlightCell + simpleHighlightCell.configureWithSite(site) + return simpleHighlightCell + } + + func configurePocketItemCell(_ cell: UICollectionViewCell, forIndexPath indexPath: IndexPath) -> UICollectionViewCell { + let pocketStory = pocketStories[indexPath.row] + let pocketItemCell = cell as! ActivityStreamHighlightCell + pocketItemCell.configureWithPocketStory(pocketStory) + return pocketItemCell + } + + func configureHighlightIntroCell(_ cell: UICollectionViewCell, forIndexPath indexPath: IndexPath) -> UICollectionViewCell { + let introCell = cell as! HighlightIntroCell + //The cell is configured on creation. No need to configure. But leave this here in case we need it. + return introCell + } +} + +// MARK: - Data Management +extension ActivityStreamPanel: DataObserverDelegate { + fileprivate func reportMissingData(sites: [Site], source: ASPingSource) { + let missingImagePings: [[String: Any]] = sites.flatMap { site in + if site.metadata?.mediaURL == nil { + return self.telemetry.pingFor(badState: .MissingMetadataImage, source: source) + } + return nil + } + + let missingFaviconPings: [[String: Any]] = sites.flatMap { site in + if site.icon == nil { + return self.telemetry.pingFor(badState: .MissingFavicon, source: source) + } + return nil + } + + let badPings = missingImagePings + missingFaviconPings + self.telemetry.eventsTracker.sendBatch(badPings, validate: true) + } + + // Reloads both highlights and top sites data from their respective caches. Does not invalidate the cache. + // See ActivityStreamDataObserver for invalidation logic. + func reloadAll() { + // If the pocket stories are not availible for the Locale the PocketAPI will return nil + // So it is okay if the default here is true + self.getPocketSites().uponQueue(.main) { _ in + if !self.pocketStories.isEmpty { + self.collectionView?.reloadData() + } + } + + accumulate([self.getHighlights, self.getTopSites]).uponQueue(.main) { _ in + // If there is no pending cache update and highlights are empty. Show the onboarding screen + self.showHighlightIntro = self.highlights.isEmpty + self.collectionView?.reloadData() + + // Refresh the AS data in the background so we'll have fresh data next time we show. + self.profile.panelDataObservers.activityStream.refreshIfNeeded(forceHighlights: false, forceTopSites: false) + } + } + + func getBookmarksForHighlights() -> Deferred>> { + let count = ASPanelUX.BookmarkHighlights // Fetch 2 bookmarks + return self.profile.recommendations.getRecentBookmarks(count) + } + + // Used to check if the entire section is turned off + // when it is we shouldnt show the emtpy state + func isHighlightsEnabled() -> Bool { + let bookmarks = profile.prefs.boolForKey(PrefsKeys.ASBookmarkHighlightsVisible) ?? false + let history = profile.prefs.boolForKey(PrefsKeys.ASRecentHighlightsVisible) ?? false + return history && bookmarks + } + + func getHighlights() -> Success { + var queries: [() -> Deferred>>] = [] + if profile.prefs.boolForKey(PrefsKeys.ASBookmarkHighlightsVisible) ?? true { + queries.append(getBookmarksForHighlights) + } + + if profile.prefs.boolForKey(PrefsKeys.ASRecentHighlightsVisible) ?? true { + queries.append(self.profile.recommendations.getHighlights) + } + + guard !queries.isEmpty else { + self.highlights = [] + return succeed() + } + + return accumulate(queries).bindQueue(.main) { result in + guard let resultArr = result.successValue else { + return succeed() + } + let sites = resultArr.reduce([]) { $0 + $1.asArray() } + + // Scan through the fetched highlights and report on anything that might be missing. + self.reportMissingData(sites: sites, source: .Highlights) + self.highlights = sites + return succeed() + } + } + + func getPocketSites() -> Success { + let showPocket = (profile.prefs.boolForKey(PrefsKeys.ASPocketStoriesVisible) ?? Pocket.IslocaleSupported(Locale.current.identifier)) && AppConstants.MOZ_POCKET_STORIES + guard showPocket else { + self.pocketStories = [] + return succeed() + } + + return pocketAPI.globalFeed(items: 4).bindQueue(.main) { pStory in + self.pocketStories = pStory + return succeed() + } + } + + @objc func showMorePocketStories() { + showSiteWithURLHandler(Pocket.MoreStoriesURL) + } + + func getTopSites() -> Success { + return self.profile.history.getTopSitesWithLimit(16).both(self.profile.history.getPinnedTopSites()).bindQueue(.main) { (topsites, pinnedSites) in + guard let mySites = topsites.successValue?.asArray(), let pinned = pinnedSites.successValue?.asArray() else { + return succeed() + } + + // How sites are merged together. We compare against the urls second level domain. example m.youtube.com is compared against `youtube` + let unionOnURL = { (site: Site) -> String in + return URL(string: site.url)?.hostSLD ?? "" + } + + // Fetch the default sites + let defaultSites = self.defaultTopSites() + // create PinnedSite objects. used by the view layer to tell topsites apart + let pinnedSites: [Site] = pinned.map({ PinnedSite(site: $0) }) + + // Merge default topsites with a user's topsites. + let mergedSites = mySites.union(defaultSites, f: unionOnURL) + // Merge pinnedSites with sites from the previous step + let allSites = pinnedSites.union(mergedSites, f: unionOnURL) + + // Favour topsites from defaultSites as they have better favicons. But keep PinnedSites + let newSites = allSites.map { site -> Site in + if let _ = site as? PinnedSite { + return site + } + let domain = URL(string: site.url)?.hostSLD + return defaultSites.find { $0.title.lowercased() == domain } ?? site + } + + // Don't report bad states for default sites we provide + self.reportMissingData(sites: mySites, source: .TopSites) + + self.topSitesManager.currentTraits = self.view.traitCollection + + if newSites.count > Int(ActivityStreamTopSiteCacheSize) { + self.topSitesManager.content = Array(newSites[0.. [Site] { + let suggested = SuggestedSites.asArray() + let deleted = profile.prefs.arrayForKey(DefaultSuggestedSitesKey) as? [String] ?? [] + return suggested.filter({deleted.index(of: $0.url) == .none}) + } + + @objc fileprivate func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) { + guard longPressGestureRecognizer.state == UIGestureRecognizerState.began else { return } + + let point = longPressGestureRecognizer.location(in: self.collectionView) + guard let indexPath = self.collectionView?.indexPathForItem(at: point) else { return } + + switch Section(indexPath.section) { + case .highlights, .pocket: + presentContextMenu(for: indexPath) + case .topSites: + let topSiteCell = self.collectionView?.cellForItem(at: indexPath) as! ASHorizontalScrollCell + let pointInTopSite = longPressGestureRecognizer.location(in: topSiteCell.collectionView) + guard let topSiteIndexPath = topSiteCell.collectionView.indexPathForItem(at: pointInTopSite) else { return } + presentContextMenu(for: topSiteIndexPath) + case .highlightIntro: + break + } + } + + fileprivate func fetchBookmarkStatus(for site: Site, with indexPath: IndexPath, forSection section: Section, completionHandler: @escaping () -> Void) { + profile.bookmarks.modelFactory >>== { + $0.isBookmarked(site.url).uponQueue(.main) { result in + guard let isBookmarked = result.successValue else { + log.error("Error getting bookmark status: \(result.failureValue ??? "nil").") + return + } + site.setBookmarked(isBookmarked) + completionHandler() + } + } + } + + func selectItemAtIndex(_ index: Int, inSection section: Section) { + let site: Site? + switch section { + case .highlights: + site = self.highlights[index] + telemetry.reportEvent(.Click, source: .Highlights, position: index) + case .pocket: + site = Site(url: pocketStories[index].url.absoluteString, title: pocketStories[index].title) + telemetry.reportEvent(.Click, source: .Pocket, position: index) + LeanPlumClient.shared.track(event: .openedPocketStory, withParameters: ["Source": "Activity Stream" as AnyObject]) + case .topSites, .highlightIntro: + return + } + if let site = site { + showSiteWithURLHandler(URL(string: site.url)!) + } + } +} + +extension ActivityStreamPanel: HomePanelContextMenu { + func presentContextMenu(for site: Site, with indexPath: IndexPath, completionHandler: @escaping () -> PhotonActionSheet?) { + + fetchBookmarkStatus(for: site, with: indexPath, forSection: Section(indexPath.section)) { + guard let contextMenu = completionHandler() else { return } + self.present(contextMenu, animated: true, completion: nil) + } + } + + func getSiteDetails(for indexPath: IndexPath) -> Site? { + let site: Site + + switch Section(indexPath.section) { + case .highlights: + site = highlights[indexPath.row] + case .pocket: + site = Site(url: pocketStories[indexPath.row].dedupeURL.absoluteString, title: pocketStories[indexPath.row].title) + case .topSites: + site = topSitesManager.content[indexPath.item] + case .highlightIntro: + return nil + } + + return site + } + + func getContextMenuActions(for site: Site, with indexPath: IndexPath) -> [PhotonActionSheetItem]? { + guard let siteURL = URL(string: site.url) else { return nil } + + let pingSource: ASPingSource + let index: Int + var sourceView: UIView? + + switch Section(indexPath.section) { + case .topSites: + pingSource = .TopSites + index = indexPath.item + if let topSiteCell = self.collectionView?.cellForItem(at: IndexPath(row: 0, section: 0)) as? ASHorizontalScrollCell { + sourceView = topSiteCell.collectionView.cellForItem(at: indexPath) + } + case .highlights: + pingSource = .Highlights + index = indexPath.row + sourceView = self.collectionView?.cellForItem(at: indexPath) + case .pocket: + pingSource = .Pocket + index = indexPath.item + sourceView = self.collectionView?.cellForItem(at: indexPath) + case .highlightIntro: + return nil + } + + let openInNewTabAction = PhotonActionSheetItem(title: Strings.OpenInNewTabContextMenuTitle, iconString: "quick_action_new_tab") { action in + self.homePanelDelegate?.homePanelDidRequestToOpenInNewTab(siteURL, isPrivate: false) + self.telemetry.reportEvent(.NewTab, source: pingSource, position: index) + let source = ["Source": "Activity Stream Long Press Context Menu" as AnyObject] + LeanPlumClient.shared.track(event: .openedNewTab, withParameters: source) + if Section(indexPath.section) == .pocket { + LeanPlumClient.shared.track(event: .openedPocketStory, withParameters: source) + } + } + + let openInNewPrivateTabAction = PhotonActionSheetItem(title: Strings.OpenInNewPrivateTabContextMenuTitle, iconString: "quick_action_new_private_tab") { action in + self.homePanelDelegate?.homePanelDidRequestToOpenInNewTab(siteURL, isPrivate: true) + } + + let bookmarkAction: PhotonActionSheetItem + if site.bookmarked ?? false { + bookmarkAction = PhotonActionSheetItem(title: Strings.RemoveBookmarkContextMenuTitle, iconString: "action_bookmark_remove", handler: { action in + self.profile.bookmarks.modelFactory >>== { + $0.removeByURL(siteURL.absoluteString).uponQueue(.main) {_ in + self.profile.panelDataObservers.activityStream.refreshIfNeeded(forceHighlights: true, forceTopSites: false) + } + site.setBookmarked(false) + } + self.telemetry.reportEvent(.RemoveBookmark, source: pingSource, position: index) + UnifiedTelemetry.recordEvent(category: .action, method: .delete, object: .bookmark, value: .activityStream) + }) + } else { + bookmarkAction = PhotonActionSheetItem(title: Strings.BookmarkContextMenuTitle, iconString: "action_bookmark", handler: { action in + let shareItem = ShareItem(url: site.url, title: site.title, favicon: site.icon) + _ = self.profile.bookmarks.shareItem(shareItem) + var userData = [QuickActions.TabURLKey: shareItem.url] + if let title = shareItem.title { + userData[QuickActions.TabTitleKey] = title + } + QuickActions.sharedInstance.addDynamicApplicationShortcutItemOfType(.openLastBookmark, + withUserData: userData, + toApplication: UIApplication.shared) + site.setBookmarked(true) + self.profile.panelDataObservers.activityStream.refreshIfNeeded(forceHighlights: true, forceTopSites: true) + self.telemetry.reportEvent(.AddBookmark, source: pingSource, position: index) + LeanPlumClient.shared.track(event: .savedBookmark) + UnifiedTelemetry.recordEvent(category: .action, method: .add, object: .bookmark, value: .activityStream) + }) + } + + let deleteFromHistoryAction = PhotonActionSheetItem(title: Strings.DeleteFromHistoryContextMenuTitle, iconString: "action_delete", handler: { action in + self.telemetry.reportEvent(.Delete, source: pingSource, position: index) + self.profile.history.removeHistoryForURL(site.url).uponQueue(.main) { result in + guard result.isSuccess else { return } + self.profile.panelDataObservers.activityStream.refreshIfNeeded(forceHighlights: true, forceTopSites: true) + } + }) + + let shareAction = PhotonActionSheetItem(title: Strings.ShareContextMenuTitle, iconString: "action_share", handler: { action in + let helper = ShareExtensionHelper(url: siteURL, tab: nil) + let controller = helper.createActivityViewController { completed, activityType in + self.telemetry.reportEvent(.Share, source: pingSource, position: index, shareProvider: activityType) + } + if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad, let popoverController = controller.popoverPresentationController { + let cellRect = sourceView?.frame ?? CGRect.zero + let cellFrameInSuperview = self.collectionView?.convert(cellRect, to: self.collectionView) ?? CGRect.zero + + popoverController.sourceView = sourceView + popoverController.sourceRect = CGRect(origin: CGPoint(x: cellFrameInSuperview.size.width/2, y: cellFrameInSuperview.height/2), size: .zero) + popoverController.permittedArrowDirections = [.up, .down, .left] + popoverController.delegate = self + } + self.present(controller, animated: true, completion: nil) + }) + + let removeTopSiteAction = PhotonActionSheetItem(title: Strings.RemoveContextMenuTitle, iconString: "action_remove", handler: { action in + self.telemetry.reportEvent(.Remove, source: pingSource, position: index) + self.hideURLFromTopSites(site) + }) + + let dismissHighlightAction = PhotonActionSheetItem(title: Strings.RemoveContextMenuTitle, iconString: "action_remove", handler: { action in + self.telemetry.reportEvent(.Dismiss, source: pingSource, position: index) + self.hideFromHighlights(site) + }) + + let pinTopSite = PhotonActionSheetItem(title: Strings.PinTopsiteActionTitle, iconString: "action_pin", handler: { action in + self.pinTopSite(site) + }) + + let removePinTopSite = PhotonActionSheetItem(title: Strings.RemovePinTopsiteActionTitle, iconString: "action_unpin", handler: { action in + self.removePinTopSite(site) + }) + + let topSiteActions: [PhotonActionSheetItem] + if let _ = site as? PinnedSite { + topSiteActions = [removePinTopSite] + } else { + topSiteActions = [pinTopSite, removeTopSiteAction] + } + + var actions = [openInNewTabAction, openInNewPrivateTabAction, bookmarkAction, shareAction] + + switch Section(indexPath.section) { + case .highlights: actions.append(contentsOf: [dismissHighlightAction, deleteFromHistoryAction]) + case .pocket: break + case .topSites: actions.append(contentsOf: topSiteActions) + case .highlightIntro: break + } + return actions + } +} + +extension ActivityStreamPanel: UIPopoverPresentationControllerDelegate { + + // Dismiss the popover if the device is being rotated. + // This is used by the Share UIActivityViewController action sheet on iPad + func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer, in view: AutoreleasingUnsafeMutablePointer) { + popoverPresentationController.presentedViewController.dismiss(animated: false, completion: nil) + } +} + +// MARK: Telemetry + +enum ASPingEvent: String { + case Click = "CLICK" + case Delete = "DELETE" + case Dismiss = "DISMISS" + case Share = "SHARE" + case NewTab = "NEW_TAB" + case AddBookmark = "ADD_BOOKMARK" + case RemoveBookmark = "REMOVE_BOOKMARK" + case Remove = "REMOVE" +} + +enum ASPingBadStateEvent: String { + case MissingMetadataImage = "MISSING_METADATA_IMAGE" + case MissingFavicon = "MISSING_FAVICON" +} + +enum ASPingSource: String { + case Highlights = "HIGHLIGHTS" + case TopSites = "TOP_SITES" + case HighlightsIntro = "HIGHLIGHTS_INTRO" + case Pocket = "POCKET" +} + +struct ActivityStreamTracker { + let eventsTracker: PingCentreClient + let sessionsTracker: PingCentreClient + + private var baseASPing: [String: Any] { + return [ + "app_version": AppInfo.appVersion, + "build": AppInfo.buildNumber, + "locale": Locale.current.identifier, + "release_channel": AppConstants.BuildChannel.rawValue + ] + } + + func pingFor(badState: ASPingBadStateEvent, source: ASPingSource) -> [String: Any] { + var eventPing: [String: Any] = [ + "event": badState.rawValue, + "page": "NEW_TAB", + "source": source.rawValue, + ] + eventPing.merge(with: baseASPing) + return eventPing + } + + func reportEvent(_ event: ASPingEvent, source: ASPingSource, position: Int, shareProvider: String? = nil) { + var eventPing: [String: Any] = [ + "event": event.rawValue, + "page": "NEW_TAB", + "source": source.rawValue, + "action_position": position, + ] + + if let provider = shareProvider { + eventPing["share_provider"] = provider + } + + eventPing.merge(with: baseASPing) + eventsTracker.sendPing(eventPing as [String : AnyObject], validate: true) + } + + func reportSessionStop(_ duration: UInt64) { + sessionsTracker.sendPing([ + "session_duration": NSNumber(value: duration), + "app_version": AppInfo.appVersion, + "build": AppInfo.buildNumber, + "locale": Locale.current.identifier, + "release_channel": AppConstants.BuildChannel.rawValue + ] as [String: Any], validate: true) + } +} + +// MARK: - Section Header View +struct ASHeaderViewUX { + static let SeperatorColor = UIColor(rgb: 0xedecea) + static let TextFont = DynamicFontHelper.defaultHelper.MediumSizeBoldFontAS + static let SeperatorHeight = 1 + static let Insets: CGFloat = UIDevice.current.userInterfaceIdiom == .pad ? ASPanelUX.SectionInsetsForIpad + ASPanelUX.MinimumInsets : ASPanelUX.MinimumInsets + static let TitleTopInset: CGFloat = 5 +} + +class ASFooterView: UICollectionReusableView { + + override init(frame: CGRect) { + super.init(frame: frame) + + let seperatorLine = UIView() + seperatorLine.backgroundColor = ASHeaderViewUX.SeperatorColor + self.backgroundColor = UIColor.clear + addSubview(seperatorLine) + seperatorLine.snp.makeConstraints { make in + make.height.equalTo(ASHeaderViewUX.SeperatorHeight) + make.leading.equalTo(self.snp.leading) + make.trailing.equalTo(self.snp.trailing) + make.top.equalTo(self.snp.top) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +class ASHeaderView: UICollectionReusableView { + lazy fileprivate var titleLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.text = self.title + titleLabel.textColor = UIColor.gray + titleLabel.font = ASHeaderViewUX.TextFont + titleLabel.minimumScaleFactor = 0.6 + titleLabel.numberOfLines = 1 + titleLabel.adjustsFontSizeToFitWidth = true + return titleLabel + }() + + lazy var moreButton: UIButton = { + let button = UIButton() + button.setTitle("More", for: .normal) + button.isHidden = true + button.titleLabel?.font = ASHeaderViewUX.TextFont + button.contentHorizontalAlignment = .right + button.setTitleColor(UIConstants.SystemBlueColor, for: .normal) + button.setTitleColor(.gray, for: UIControlState.highlighted) + return button + }() + + var title: String? { + willSet(newTitle) { + titleLabel.text = newTitle + } + } + + var leftConstraint: Constraint? + var rightConstraint: Constraint? + + var titleInsets: CGFloat { + get { + return UIScreen.main.bounds.size.width == self.frame.size.width && UIDevice.current.userInterfaceIdiom == .pad ? ASHeaderViewUX.Insets : ASPanelUX.MinimumInsets + } + } + + override func prepareForReuse() { + super.prepareForReuse() + moreButton.isHidden = true + moreButton.removeTarget(nil, action: nil, for: .allEvents) + } + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(titleLabel) + addSubview(moreButton) + moreButton.snp.makeConstraints { make in + make.top.equalTo(self).inset(ASHeaderViewUX.TitleTopInset) + make.bottom.equalTo(self) + self.rightConstraint = make.trailing.equalTo(self).inset(-titleInsets).constraint + } + moreButton.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: UILayoutConstraintAxis.horizontal) + titleLabel.snp.makeConstraints { make in + self.leftConstraint = make.leading.equalTo(self).inset(titleInsets).constraint + make.trailing.equalTo(moreButton.snp.leading).inset(-ASHeaderViewUX.TitleTopInset) + make.top.equalTo(self).inset(ASHeaderViewUX.TitleTopInset) + make.bottom.equalTo(self) + } + } + + override func layoutSubviews() { + super.layoutSubviews() + leftConstraint?.update(offset: titleInsets) + rightConstraint?.update(offset: -titleInsets) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +open class PinnedSite: Site { + let isPinnedSite = true + + init(site: Site) { + super.init(url: site.url, title: site.title, bookmarked: site.bookmarked) + self.icon = site.icon + self.metadata = site.metadata + } + +} diff --git a/mobile/ios/Client/Frontend/Home/ActivityStreamTopSitesCell.swift b/mobile/ios/Client/Frontend/Home/ActivityStreamTopSitesCell.swift new file mode 100644 index 0000000000..91cabbca6d --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/ActivityStreamTopSitesCell.swift @@ -0,0 +1,558 @@ +/* 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/. */ + +import Foundation +import Shared +import SDWebImage +import Storage + +struct TopSiteCellUX { + static let TitleHeight: CGFloat = 20 + static let TitleBackgroundColor = UIColor(colorLiteralRed: 1, green: 1, blue: 1, alpha: 0.7) + static let TitleTextColor = UIColor.black + static let TitleFont = DynamicFontHelper.defaultHelper.SmallSizeRegularWeightAS + static let SelectedOverlayColor = UIColor(white: 0.0, alpha: 0.25) + static let CellCornerRadius: CGFloat = 4 + static let TitleOffset: CGFloat = 5 + static let OverlayColor = UIColor(white: 0.0, alpha: 0.25) + static let IconSizePercent: CGFloat = 0.8 + static let BorderColor = UIColor(white: 0, alpha: 0.1) + static let BorderWidth: CGFloat = 0.5 + static let PinIconSize: CGFloat = 12 + static let PinColor = UIColor(rgb: 0x272727) +} + +/* + * The TopSite cell that appears in the ASHorizontalScrollView. + */ +class TopSiteItemCell: UICollectionViewCell { + + var url: URL? + + lazy var imageView: UIImageView = { + let imageView = UIImageView() + imageView.layer.masksToBounds = true + return imageView + }() + + lazy var pinImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage.templateImageNamed("pin_small") + imageView.tintColor = TopSiteCellUX.PinColor + return imageView + }() + + lazy fileprivate var titleLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.layer.masksToBounds = true + titleLabel.textAlignment = .center + titleLabel.font = TopSiteCellUX.TitleFont + titleLabel.textColor = TopSiteCellUX.TitleTextColor + titleLabel.backgroundColor = UIColor.clear + return titleLabel + }() + + lazy private var faviconBG: UIView = { + let view = UIView() + view.layer.cornerRadius = TopSiteCellUX.CellCornerRadius + view.layer.masksToBounds = true + view.layer.borderWidth = TopSiteCellUX.BorderWidth + view.layer.borderColor = TopSiteCellUX.BorderColor.cgColor + return view + }() + + lazy var selectedOverlay: UIView = { + let selectedOverlay = UIView() + selectedOverlay.backgroundColor = TopSiteCellUX.OverlayColor + selectedOverlay.isHidden = true + return selectedOverlay + }() + + lazy var titleBorder: CALayer = { + let border = CALayer() + border.backgroundColor = TopSiteCellUX.BorderColor.cgColor + return border + }() + + override var isSelected: Bool { + didSet { + self.selectedOverlay.isHidden = !isSelected + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + isAccessibilityElement = true + accessibilityIdentifier = "TopSite" + + contentView.addSubview(titleLabel) + contentView.addSubview(faviconBG) + contentView.addSubview(imageView) + contentView.addSubview(selectedOverlay) + + titleLabel.snp.makeConstraints { make in + make.left.equalTo(self).offset(TopSiteCellUX.TitleOffset) + make.right.equalTo(self).offset(-TopSiteCellUX.TitleOffset) + make.height.equalTo(TopSiteCellUX.TitleHeight) + make.bottom.equalTo(self) + } + + imageView.snp.makeConstraints { make in + make.size.equalTo(floor(frame.width * TopSiteCellUX.IconSizePercent)) + make.centerX.equalTo(self) + make.centerY.equalTo(self).inset(-TopSiteCellUX.TitleHeight/2) + } + + selectedOverlay.snp.makeConstraints { make in + make.edges.equalTo(contentView) + } + + faviconBG.snp.makeConstraints { make in + make.top.left.right.equalTo(self) + make.bottom.equalTo(self).inset(TopSiteCellUX.TitleHeight) + } + } + + override func layoutSubviews() { + super.layoutSubviews() + titleBorder.frame = CGRect(x: 0, y: frame.height - TopSiteCellUX.TitleHeight - TopSiteCellUX.BorderWidth, width: frame.width, height: TopSiteCellUX.BorderWidth) + + imageView.snp.remakeConstraints { make in + make.size.equalTo(floor(self.frame.width * TopSiteCellUX.IconSizePercent)) + make.centerX.equalTo(self) + make.centerY.equalTo(self).inset(-TopSiteCellUX.TitleHeight/2) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + super.prepareForReuse() + contentView.backgroundColor = UIColor.clear + imageView.image = nil + imageView.backgroundColor = UIColor.clear + faviconBG.backgroundColor = UIColor.clear + pinImageView.removeFromSuperview() + imageView.sd_cancelCurrentImageLoad() + titleLabel.text = "" + titleLabel.snp.updateConstraints { make in + make.left.equalTo(self).offset(TopSiteCellUX.TitleOffset) + } + } + + func configureWithTopSiteItem(_ site: Site) { + url = site.tileURL + + if let provider = site.metadata?.providerName { + titleLabel.text = provider.lowercased() + } else { + titleLabel.text = site.tileURL.hostSLD + } + + // If its a pinned site add a bullet point to the front + if let _ = site as? PinnedSite { + contentView.addSubview(pinImageView) + pinImageView.snp.makeConstraints { make in + make.right.equalTo(self.titleLabel.snp.left) + make.size.equalTo(TopSiteCellUX.PinIconSize) + make.centerY.equalTo(self.titleLabel.snp.centerY) + } + titleLabel.snp.updateConstraints { make in + make.left.equalTo(self).offset(TopSiteCellUX.PinIconSize) + } + } + + accessibilityLabel = titleLabel.text + imageView.setFavicon(forSite: site, onCompletion: { [weak self] (color, url) in + if let url = url, url == self?.url { + self?.faviconBG.backgroundColor = color + self?.imageView.backgroundColor = color + } + }) + } + +} + +// An empty cell to show when a row is incomplete +class EmptyTopsiteDecorationCell: UICollectionReusableView { + + override init(frame: CGRect) { + super.init(frame: frame) + self.layer.cornerRadius = TopSiteCellUX.CellCornerRadius + self.layer.borderWidth = TopSiteCellUX.BorderWidth + self.layer.borderColor = TopSiteCellUX.BorderColor.cgColor + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +struct ASHorizontalScrollCellUX { + static let TopSiteCellIdentifier = "TopSiteItemCell" + static let TopSiteEmptyCellIdentifier = "TopSiteItemEmptyCell" + + static let TopSiteItemSize = CGSize(width: 75, height: 75) + static let BackgroundColor = UIColor.white + static let PageControlRadius: CGFloat = 3 + static let PageControlSize = CGSize(width: 30, height: 15) + static let PageControlOffset: CGFloat = 12 + static let MinimumInsets: CGFloat = 14 +} + +/* + The View that describes the topSite cell that appears in the tableView. + */ +class ASHorizontalScrollCell: UICollectionViewCell { + + lazy var collectionView: UICollectionView = { + let layout = HorizontalFlowLayout() + layout.itemSize = ASHorizontalScrollCellUX.TopSiteItemSize + let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout) + collectionView.register(TopSiteItemCell.self, forCellWithReuseIdentifier: ASHorizontalScrollCellUX.TopSiteCellIdentifier) + collectionView.backgroundColor = UIColor.clear + collectionView.showsHorizontalScrollIndicator = false + collectionView.isPagingEnabled = true + return collectionView + }() + + lazy fileprivate var pageControl: FilledPageControl = { + let pageControl = FilledPageControl() + pageControl.tintColor = UIColor.gray + pageControl.indicatorRadius = ASHorizontalScrollCellUX.PageControlRadius + pageControl.isUserInteractionEnabled = true + pageControl.isAccessibilityElement = true + pageControl.accessibilityIdentifier = "pageControl" + pageControl.accessibilityLabel = Strings.ASPageControlButton + pageControl.accessibilityTraits = UIAccessibilityTraitButton + return pageControl + }() + + lazy fileprivate var pageControlPress: UITapGestureRecognizer = { + let press = UITapGestureRecognizer(target: self, action: #selector(ASHorizontalScrollCell.handlePageTap(_:))) + // press.delegate = self + return press + }() + + weak var delegate: ASHorizontalScrollCellManager? { + didSet { + collectionView.delegate = delegate + collectionView.dataSource = delegate + delegate?.pageChangedHandler = { [weak self] progress in + self?.currentPageChanged(progress) + } + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + isAccessibilityElement = false + accessibilityIdentifier = "TopSitesCell" + backgroundColor = UIColor.clear + contentView.addSubview(collectionView) + contentView.addSubview(pageControl) + + pageControl.addGestureRecognizer(self.pageControlPress) + + collectionView.snp.makeConstraints { make in + make.edges.equalTo(contentView) + } + + pageControl.snp.makeConstraints { make in + make.size.equalTo(ASHorizontalScrollCellUX.PageControlSize) + make.top.equalTo(collectionView.snp.bottom).inset(ASHorizontalScrollCellUX.PageControlOffset) + make.centerX.equalTo(self.snp.centerX) + } + } + + override func layoutSubviews() { + super.layoutSubviews() + let layout = collectionView.collectionViewLayout as! HorizontalFlowLayout + + pageControl.pageCount = layout.numberOfPages(with: self.frame.size) + pageControl.isHidden = pageControl.pageCount <= 1 + } + + func currentPageChanged(_ currentPage: CGFloat) { + pageControl.progress = currentPage + if currentPage == floor(currentPage) { + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil) + self.setNeedsLayout() + } + } + + func handlePageTap(_ gesture: UITapGestureRecognizer) { + guard pageControl.pageCount > 1 else { + return + } + + if pageControl.pageCount > pageControl.currentPage + 1 { + pageControl.progress = CGFloat(pageControl.currentPage + 1) + } else { + pageControl.progress = CGFloat(pageControl.currentPage - 1) + } + let swipeCoordinate = CGFloat(pageControl.currentPage) * self.collectionView.frame.size.width + self.collectionView.setContentOffset(CGPoint(x: swipeCoordinate, y: 0), animated: true) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} +/* + A custom layout used to show a horizontal scrolling list with paging. Similar to iOS springboard. + A modified version of http://stackoverflow.com/a/34167915 + */ + +class HorizontalFlowLayout: UICollectionViewLayout { + fileprivate var cellCount: Int { + if let collectionView = collectionView, let dataSource = collectionView.dataSource { + return dataSource.collectionView(collectionView, numberOfItemsInSection: 0) + } + return 0 + } + var boundsSize = CGSize.zero + private var insets = UIEdgeInsets(equalInset: ASHorizontalScrollCellUX.MinimumInsets) + private var sectionInsets: CGFloat = 0 + var itemSize = CGSize.zero + var cachedAttributes: [UICollectionViewLayoutAttributes]? + + override func prepare() { + super.prepare() + if boundsSize != self.collectionView?.frame.size { + self.collectionView?.setContentOffset(CGPoint.zero, animated: false) + } + boundsSize = self.collectionView?.frame.size ?? CGSize.zero + cachedAttributes = nil + register(EmptyTopsiteDecorationCell.self, forDecorationViewOfKind: ASHorizontalScrollCellUX.TopSiteEmptyCellIdentifier) + } + + func numberOfPages(with bounds: CGSize) -> Int { + let itemsPerPage = maxVerticalItemsCount(height: bounds.height) * maxHorizontalItemsCount(width: bounds.width) + // Sometimes itemsPerPage is 0. In this case just return 0. We dont want to try dividing by 0. + return itemsPerPage == 0 ? 0 : Int(ceil(Double(cellCount) / Double(itemsPerPage))) + } + + func calculateLayout(for size: CGSize) -> (size: CGSize, cellSize: CGSize, cellInsets: UIEdgeInsets) { + let width = size.width + let height = size.height + guard width != 0 else { + return (size: CGSize.zero, cellSize: self.itemSize, cellInsets: self.insets) + } + + let horizontalItemsCount = maxHorizontalItemsCount(width: width) + var verticalItemsCount = maxVerticalItemsCount(height: height) + if cellCount <= horizontalItemsCount { + // If we have only a few items don't provide space for multiple rows. + verticalItemsCount = 1 + } + + // Take the number of cells and subtract its space in the view from the height. The left over space is the white space. + // The left over space is then devided evenly into (n + 1) parts to figure out how much space should be inbetween a cell + var verticalInsets = floor((height - (CGFloat(verticalItemsCount) * itemSize.height)) / CGFloat(verticalItemsCount + 1)) + var horizontalInsets = floor((width - (CGFloat(horizontalItemsCount) * itemSize.width)) / CGFloat(horizontalItemsCount + 1)) + + // We want a minimum inset to make things not look crowded. We also don't want uneven spacing. + // If we dont have this. Set a minimum inset and recalculate the size of a cell + var estimatedItemSize = itemSize + if horizontalInsets != ASHorizontalScrollCellUX.MinimumInsets { + verticalInsets = ASHorizontalScrollCellUX.MinimumInsets + horizontalInsets = ASHorizontalScrollCellUX.MinimumInsets + estimatedItemSize.width = floor((width - (CGFloat(horizontalItemsCount + 1) * horizontalInsets)) / CGFloat(horizontalItemsCount)) + estimatedItemSize.height = estimatedItemSize.width + TopSiteCellUX.TitleHeight + } + + //calculate our estimates. + let estimatedHeight = floor(estimatedItemSize.height * CGFloat(verticalItemsCount)) + (verticalInsets * (CGFloat(verticalItemsCount) + 1)) + let estimatedSize = CGSize(width: CGFloat(numberOfPages(with: boundsSize)) * width, height: estimatedHeight) + + let estimatedInsets = UIEdgeInsets(top: verticalInsets, left: horizontalInsets, bottom: verticalInsets, right: horizontalInsets) + return (size: estimatedSize, cellSize: estimatedItemSize, cellInsets: estimatedInsets) + } + + override var collectionViewContentSize: CGSize { + let estimatedLayout = calculateLayout(for: boundsSize) + insets = estimatedLayout.cellInsets + itemSize = estimatedLayout.cellSize + boundsSize.height = estimatedLayout.size.height + return estimatedLayout.size + } + + func maxVerticalItemsCount(height: CGFloat) -> Int { + let verticalItemsCount = Int(floor(height / (ASHorizontalScrollCellUX.TopSiteItemSize.height + insets.top))) + if let delegate = self.collectionView?.delegate as? ASHorizontalLayoutDelegate { + return delegate.numberOfVerticalItems() + } else { + return verticalItemsCount + } + } + + func maxHorizontalItemsCount(width: CGFloat) -> Int { + let horizontalItemsCount = Int(floor(width / (ASHorizontalScrollCellUX.TopSiteItemSize.width + insets.left))) + if let delegate = self.collectionView?.delegate as? ASHorizontalLayoutDelegate { + return delegate.numberOfHorizontalItems() + } else { + return horizontalItemsCount + } + } + + override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + let decorationAttr = UICollectionViewLayoutAttributes(forDecorationViewOfKind: elementKind, with: indexPath) + let cellAttr = self.computeLayoutAttributesForCellAtIndexPath(indexPath) + decorationAttr.frame = cellAttr.frame + + decorationAttr.frame.size.height -= TopSiteCellUX.TitleHeight + decorationAttr.zIndex = -1 + return decorationAttr + } + + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + if cachedAttributes != nil { + return cachedAttributes + } + var allAttributes = [UICollectionViewLayoutAttributes]() + for i in 0 ..< cellCount { + let indexPath = IndexPath(row: i, section: 0) + let attr = self.computeLayoutAttributesForCellAtIndexPath(indexPath) + allAttributes.append(attr) + } + + //create decoration attributes + let horizontalItemsCount = maxHorizontalItemsCount(width: boundsSize.width) + var numberOfCells = cellCount + while numberOfCells % horizontalItemsCount != 0 { + //we need some empty cells dawg. + + let attr = self.layoutAttributesForDecorationView(ofKind: ASHorizontalScrollCellUX.TopSiteEmptyCellIdentifier, at: IndexPath(item: numberOfCells, section: 0)) + allAttributes.append(attr!) + numberOfCells += 1 + } + cachedAttributes = allAttributes + return allAttributes + } + + override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + return self.computeLayoutAttributesForCellAtIndexPath(indexPath) + } + + override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { + cachedAttributes = nil + // Sometimes when the topsiteCell isnt on the screen the newbounds that it tries to layout in is 0 + // Resulting in incorrect layouts. Only layout when a valid width is given + return newBounds.width > 0 + } + + func computeLayoutAttributesForCellAtIndexPath(_ indexPath: IndexPath) -> UICollectionViewLayoutAttributes { + let row = indexPath.row + let bounds = self.collectionView!.bounds + + let verticalItemsCount = maxVerticalItemsCount(height: bounds.size.height) + let horizontalItemsCount = maxHorizontalItemsCount(width: bounds.size.width) + + let itemsPerPage = verticalItemsCount * horizontalItemsCount + + let columnPosition = row % horizontalItemsCount + let rowPosition = (row / horizontalItemsCount) % verticalItemsCount + let itemPage = Int(floor(Double(row)/Double(itemsPerPage))) + + let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath) + var frame = CGRect.zero + frame.origin.x = CGFloat(itemPage) * bounds.size.width + CGFloat(columnPosition) * (itemSize.width + insets.left) + insets.left + frame.origin.y = CGFloat(rowPosition) * (itemSize.height + insets.top) + insets.top + frame.size = itemSize + attr.frame = frame + + return attr + } +} + +/* + Defines the number of items to show in topsites for different size classes. +*/ +struct ASTopSiteSourceUX { + static let verticalItemsForTraitSizes = [UIUserInterfaceSizeClass.compact: 1, UIUserInterfaceSizeClass.regular: 2, UIUserInterfaceSizeClass.unspecified: 0] + static let maxNumberOfPages = 2 + static let CellIdentifier = "TopSiteItemCell" +} + +protocol ASHorizontalLayoutDelegate { + func numberOfVerticalItems() -> Int + func numberOfHorizontalItems() -> Int +} + +/* + This Delegate/DataSource is used to manage the ASHorizontalScrollCell's UICollectionView. + This is left generic enough for it to be re used for other parts of Activity Stream. + */ + +class ASHorizontalScrollCellManager: NSObject, UICollectionViewDelegate, UICollectionViewDataSource, ASHorizontalLayoutDelegate { + + var content: [Site] = [] + + var urlPressedHandler: ((URL, IndexPath) -> Void)? + var pageChangedHandler: ((CGFloat) -> Void)? + + // The current traits that define the parent ViewController. Used to determine how many rows/columns should be created. + var currentTraits: UITraitCollection? + + // Size classes define how many items to show per row/column. + func numberOfVerticalItems() -> Int { + guard let traits = currentTraits else { + return 0 + } + return ASTopSiteSourceUX.verticalItemsForTraitSizes[traits.verticalSizeClass]! + } + + func numberOfHorizontalItems() -> Int { + guard let traits = currentTraits else { + return 0 + } + let isLandscape = UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation) + if UIDevice.current.userInterfaceIdiom == .phone { + if isLandscape { + return 8 + } else { + return 4 + } + } + // On iPad + // The number of items in a row is equal to the number of highlights in a row * 2 + var numItems: Int = Int(ASPanelUX.numberOfItemsPerRowForSizeClassIpad[traits.horizontalSizeClass]) + if UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation) || (traits.horizontalSizeClass == .compact && isLandscape) { + numItems = numItems - 1 + } + return numItems * 2 + } + + func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return self.content.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ASTopSiteSourceUX.CellIdentifier, for: indexPath) as! TopSiteItemCell + let contentItem = content[indexPath.row] + cell.configureWithTopSiteItem(contentItem) + return cell + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let contentItem = content[indexPath.row] + guard let url = contentItem.url.asURL else { + return + } + urlPressedHandler?(url, indexPath) + } + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + let pageWidth = scrollView.frame.width + pageChangedHandler?(scrollView.contentOffset.x / pageWidth) + } + +} diff --git a/mobile/ios/Client/Frontend/Home/BookmarksPanel.swift b/mobile/ios/Client/Frontend/Home/BookmarksPanel.swift new file mode 100644 index 0000000000..12e2d059d4 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/BookmarksPanel.swift @@ -0,0 +1,593 @@ +/* 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/. */ + +import UIKit +import Storage +import Shared +import XCGLogger + +private let log = Logger.browserLogger + +let BookmarkStatusChangedNotification = "BookmarkStatusChangedNotification" + +// MARK: - Placeholder strings for Bug 1232810. + +let deleteWarningTitle = NSLocalizedString("This folder isn’t empty.", tableName: "BookmarkPanelDeleteConfirm", comment: "Title of the confirmation alert when the user tries to delete a folder that still contains bookmarks and/or folders.") +let deleteWarningDescription = NSLocalizedString("Are you sure you want to delete it and its contents?", tableName: "BookmarkPanelDeleteConfirm", comment: "Main body of the confirmation alert when the user tries to delete a folder that still contains bookmarks and/or folders.") +let deleteCancelButtonLabel = NSLocalizedString("Cancel", tableName: "BookmarkPanelDeleteConfirm", comment: "Button label to cancel deletion when the user tried to delete a non-empty folder.") +let deleteDeleteButtonLabel = NSLocalizedString("Delete", tableName: "BookmarkPanelDeleteConfirm", comment: "Button label for the button that deletes a folder and all of its children.") + +// Placeholder strings for Bug 1248034 +let emptyBookmarksText = NSLocalizedString("Bookmarks you save will show up here.", comment: "Status label for the empty Bookmarks state.") + +// MARK: - UX constants. + +struct BookmarksPanelUX { + static let BookmarkFolderHeaderViewChevronInset: CGFloat = 10 + static let BookmarkFolderChevronSize: CGFloat = 20 + static let BookmarkFolderChevronLineWidth: CGFloat = 2.0 + static let BookmarkFolderTextColor = UIColor(red: 92/255, green: 92/255, blue: 92/255, alpha: 1.0) + static let BookmarkFolderBGColor = UIColor(rgb: 0xf7f8f7).withAlphaComponent(0.3) + static let WelcomeScreenPadding: CGFloat = 15 + static let WelcomeScreenItemTextColor = UIColor.gray + static let WelcomeScreenItemWidth = 170 + static let SeparatorRowHeight: CGFloat = 0.5 + static let IconSize: CGFloat = 23 + static let IconBorderColor = UIColor(white: 0, alpha: 0.1) + static let IconBorderWidth: CGFloat = 0.5 +} + +class BookmarksPanel: SiteTableViewController, HomePanel { + weak var homePanelDelegate: HomePanelDelegate? + var source: BookmarksModel? + var parentFolders = [BookmarkFolder]() + var bookmarkFolder: BookmarkFolder? + var refreshControl: UIRefreshControl? + + fileprivate lazy var longPressRecognizer: UILongPressGestureRecognizer = { + return UILongPressGestureRecognizer(target: self, action: #selector(BookmarksPanel.longPress(_:))) + }() + fileprivate lazy var emptyStateOverlayView: UIView = self.createEmptyStateOverlayView() + + fileprivate let BookmarkFolderCellIdentifier = "BookmarkFolderIdentifier" + fileprivate let BookmarkSeparatorCellIdentifier = "BookmarkSeparatorIdentifier" + fileprivate let BookmarkFolderHeaderViewIdentifier = "BookmarkFolderHeaderIdentifier" + + init() { + super.init(nibName: nil, bundle: nil) + NotificationCenter.default.addObserver(self, selector: #selector(BookmarksPanel.notificationReceived(_:)), name: NotificationFirefoxAccountChanged, object: nil) + + self.tableView.register(SeparatorTableCell.self, forCellReuseIdentifier: BookmarkSeparatorCellIdentifier) + self.tableView.register(BookmarkFolderTableViewCell.self, forCellReuseIdentifier: BookmarkFolderCellIdentifier) + self.tableView.register(BookmarkFolderTableViewHeader.self, forHeaderFooterViewReuseIdentifier: BookmarkFolderHeaderViewIdentifier) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + tableView.addGestureRecognizer(longPressRecognizer) + + self.tableView.accessibilityIdentifier = "Bookmarks List" + + self.refreshControl = UIRefreshControl() + self.tableView.addSubview(refreshControl!) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + refreshControl?.addTarget(self, action: #selector(BookmarksPanel.refreshBookmarks), for: .valueChanged) + + loadData() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + refreshControl?.removeTarget(self, action: #selector(BookmarksPanel.refreshBookmarks), for: .valueChanged) + } + + func loadData() { + // If we've not already set a source for this panel, fetch a new model from + // the root; otherwise, just use the existing source to select a folder. + guard let source = self.source else { + // Get all the bookmarks split by folders + if let bookmarkFolder = bookmarkFolder { + profile.bookmarks.modelFactory >>== { $0.modelForFolder(bookmarkFolder).upon(self.onModelFetched) } + } else { + profile.bookmarks.modelFactory >>== { $0.modelForRoot().upon(self.onModelFetched) } + } + return + } + + if let bookmarkFolder = bookmarkFolder { + source.selectFolder(bookmarkFolder).upon(onModelFetched) + } else { + source.selectFolder(BookmarkRoots.MobileFolderGUID).upon(onModelFetched) + } + } + + func notificationReceived(_ notification: Notification) { + switch notification.name { + case NotificationFirefoxAccountChanged: + self.reloadData() + break + default: + // no need to do anything at all + log.warning("Received unexpected notification \(notification.name)") + break + } + } + + @objc fileprivate func refreshBookmarks() { + profile.syncManager.mirrorBookmarks().upon { (_) in + DispatchQueue.main.async { + self.loadData() + self.refreshControl?.endRefreshing() + } + } + } + + fileprivate func createEmptyStateOverlayView() -> UIView { + let overlayView = UIView() + overlayView.backgroundColor = UIColor.white + + let logoImageView = UIImageView(image: UIImage(named: "emptyBookmarks")) + overlayView.addSubview(logoImageView) + logoImageView.snp.makeConstraints { make in + make.centerX.equalTo(overlayView) + + // Sets proper top constraint for iPhone 6 in portait and for iPad. + make.centerY.equalTo(overlayView).offset(HomePanelUX.EmptyTabContentOffset).priority(100) + + // Sets proper top constraint for iPhone 4, 5 in portrait. + make.top.greaterThanOrEqualTo(overlayView).offset(50) + } + + let welcomeLabel = UILabel() + overlayView.addSubview(welcomeLabel) + welcomeLabel.text = emptyBookmarksText + welcomeLabel.textAlignment = NSTextAlignment.center + welcomeLabel.font = DynamicFontHelper.defaultHelper.DeviceFontLight + welcomeLabel.textColor = BookmarksPanelUX.WelcomeScreenItemTextColor + welcomeLabel.numberOfLines = 0 + welcomeLabel.adjustsFontSizeToFitWidth = true + + welcomeLabel.snp.makeConstraints { make in + make.centerX.equalTo(overlayView) + make.top.equalTo(logoImageView.snp.bottom).offset(BookmarksPanelUX.WelcomeScreenPadding) + make.width.equalTo(BookmarksPanelUX.WelcomeScreenItemWidth) + } + + return overlayView + } + + fileprivate func updateEmptyPanelState() { + if source?.current.count == 0 && source?.current.guid == BookmarkRoots.MobileFolderGUID { + if self.emptyStateOverlayView.superview == nil { + self.view.addSubview(self.emptyStateOverlayView) + self.view.bringSubview(toFront: self.emptyStateOverlayView) + self.emptyStateOverlayView.snp.makeConstraints { make -> Void in + make.edges.equalTo(self.tableView) + } + } + } else { + self.emptyStateOverlayView.removeFromSuperview() + } + } + + fileprivate func onModelFetched(_ result: Maybe) { + guard let model = result.successValue else { + self.onModelFailure(result.failureValue as Any) + return + } + self.onNewModel(model) + } + + fileprivate func onNewModel(_ model: BookmarksModel) { + if Thread.current.isMainThread { + self.source = model + self.tableView.reloadData() + return + } + + DispatchQueue.main.async { + self.source = model + self.tableView.reloadData() + self.updateEmptyPanelState() + } + } + + fileprivate func onModelFailure(_ e: Any) { + log.error("Error: failed to get data: \(e)") + } + + override func reloadData() { + self.source?.reloadData().upon(onModelFetched) + } + + @objc fileprivate func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) { + guard longPressGestureRecognizer.state == UIGestureRecognizerState.began else { return } + let touchPoint = longPressGestureRecognizer.location(in: tableView) + guard let indexPath = tableView.indexPathForRow(at: touchPoint) else { return } + presentContextMenu(for: indexPath) + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return source?.current.count ?? 0 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let source = source, let bookmark = source.current[indexPath.row] else { return super.tableView(tableView, cellForRowAt: indexPath) } + switch bookmark { + case let item as BookmarkItem: + let cell = super.tableView(tableView, cellForRowAt: indexPath) + if item.title.isEmpty { + cell.textLabel?.text = item.url + } else { + cell.textLabel?.text = item.title + } + if let url = bookmark.favicon?.url.asURL, url.scheme == "asset" { + cell.imageView?.image = UIImage(named: url.host!) + } else { + cell.imageView?.layer.borderColor = BookmarksPanelUX.IconBorderColor.cgColor + cell.imageView?.layer.borderWidth = BookmarksPanelUX.IconBorderWidth + let bookmarkURL = URL(string: item.url) + cell.imageView?.setIcon(bookmark.favicon, forURL: bookmarkURL, completed: { (color, url) in + if bookmarkURL == url { + cell.imageView?.image = cell.imageView?.image?.createScaled(CGSize(width: BookmarksPanelUX.IconSize, height: BookmarksPanelUX.IconSize)) + cell.imageView?.backgroundColor = color + cell.imageView?.contentMode = .center + } + }) + } + return cell + case is BookmarkSeparator: + return tableView.dequeueReusableCell(withIdentifier: BookmarkSeparatorCellIdentifier, for: indexPath) + case let bookmark as BookmarkFolder: + let cell = tableView.dequeueReusableCell(withIdentifier: BookmarkFolderCellIdentifier, for: indexPath) + cell.textLabel?.text = bookmark.title + return cell + default: + // This should never happen. + return super.tableView(tableView, cellForRowAt: indexPath) + } + } + + func tableView(_ tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: IndexPath) { + if let cell = cell as? BookmarkFolderTableViewCell { + cell.textLabel?.font = DynamicFontHelper.defaultHelper.DeviceFontHistoryPanel + } + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + // Don't show a header for the root + if source == nil || parentFolders.isEmpty { + return nil + } + guard let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: BookmarkFolderHeaderViewIdentifier) as? BookmarkFolderTableViewHeader else { return nil } + + // register as delegate to ensure we get notified when the user interacts with this header + if header.delegate == nil { + header.delegate = self + } + + if parentFolders.count == 1 { + header.textLabel?.text = NSLocalizedString("Bookmarks", comment: "Panel accessibility label") + } else if let parentFolder = parentFolders.last { + header.textLabel?.text = parentFolder.title + } + + return header + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + if let it = self.source?.current[indexPath.row], it is BookmarkSeparator { + return BookmarksPanelUX.SeparatorRowHeight + } + + return super.tableView(tableView, heightForRowAt: indexPath) + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + // Don't show a header for the root. If there's no root (i.e. source == nil), we'll also show no header. + if source == nil || parentFolders.isEmpty { + return 0 + } + + return SiteTableViewControllerUX.RowHeight + } + + func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { + if let header = view as? BookmarkFolderTableViewHeader { + // for some reason specifying the font in header view init is being ignored, so setting it here + header.textLabel?.font = DynamicFontHelper.defaultHelper.DeviceFontHistoryPanel + } + } + + override func tableView(_ tableView: UITableView, hasFullWidthSeparatorForRowAtIndexPath indexPath: IndexPath) -> Bool { + // Show a full-width border for cells above separators, so they don't have a weird step. + // Separators themselves already have a full-width border, but let's force the issue + // just in case. + let this = self.source?.current[indexPath.row] + if (indexPath.row + 1) < (self.source?.current.count)! { + let below = self.source?.current[indexPath.row + 1] + if this is BookmarkSeparator || below is BookmarkSeparator { + return true + } + } + return super.tableView(tableView, hasFullWidthSeparatorForRowAtIndexPath: indexPath) + } + + func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: false) + guard let source = source else { + return + } + + let bookmark = source.current[indexPath.row] + + switch bookmark { + case let item as BookmarkItem: + homePanelDelegate?.homePanel(self, didSelectURLString: item.url, visitType: VisitType.bookmark) + LeanPlumClient.shared.track(event: .openedBookmark) + UnifiedTelemetry.recordEvent(category: .action, method: .open, object: .bookmark, value: .bookmarksPanel) + break + + case let folder as BookmarkFolder: + log.debug("Selected \(folder.guid)") + let nextController = BookmarksPanel() + nextController.parentFolders = parentFolders + [source.current] + nextController.bookmarkFolder = folder + nextController.homePanelDelegate = self.homePanelDelegate + nextController.profile = self.profile + source.modelFactory.uponQueue(DispatchQueue.main) { maybe in + guard let factory = maybe.successValue else { + // Nothing we can do. + return + } + let specificFactory = factory.factoryForIndex(indexPath.row, inFolder: source.current) + nextController.source = BookmarksModel(modelFactory: specificFactory, root: folder) + self.navigationController?.pushViewController(nextController, animated: true) + } + break + + default: + // You can't do anything with separators. + break + } + } + + func tableView(_ tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: IndexPath) { + // Intentionally blank. Required to use UITableViewRowActions + } + + private func editingStyleforRow(atIndexPath indexPath: IndexPath) -> UITableViewCellEditingStyle { + guard let source = source else { + return .none + } + + if source.current[indexPath.row] is BookmarkSeparator { + // Because the deletion block is too big. + return .none + } + + if source.current.itemIsEditableAtIndex(indexPath.row) { + return .delete + } + + return .none + } + + func tableView(_ tableView: UITableView, editingStyleForRowAtIndexPath indexPath: IndexPath) -> UITableViewCellEditingStyle { + return editingStyleforRow(atIndexPath: indexPath) + } + + func tableView(_ tableView: UITableView, editActionsForRowAtIndexPath indexPath: IndexPath) -> [AnyObject]? { + let editingStyle = editingStyleforRow(atIndexPath: indexPath) + guard let source = self.source, editingStyle == .delete else { + return nil + } + + let title = NSLocalizedString("Delete", tableName: "BookmarkPanel", comment: "Action button for deleting bookmarks in the bookmarks panel.") + + let delete = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: title, handler: { (action, indexPath) in + self.deleteBookmark(indexPath: indexPath, source: source) + UnifiedTelemetry.recordEvent(category: .action, method: .delete, object: .bookmark, value: .bookmarksPanel, extras: ["gesture": "swipe"]) + }) + + return [delete] + } + + func pinTopSite(_ site: Site) { + _ = profile.history.addPinnedTopSite(site).value + } + + func deleteBookmark(indexPath: IndexPath, source: BookmarksModel) { + guard let bookmark = source.current[indexPath.row] else { + return + } + + assert(!(bookmark is BookmarkFolder)) + if bookmark is BookmarkFolder { + // TODO: check whether the folder is empty (excluding separators). If it isn't + // then we must ask the user to confirm. Bug 1232810. + log.debug("Not deleting folder.") + return + } + + log.debug("Removing rows \(indexPath).") + + // Block to do this -- this is UI code. + guard let factory = source.modelFactory.value.successValue else { + log.error("Couldn't get model factory. This is unexpected.") + self.onModelFailure(DatabaseError(description: "Unable to get factory.")) + return + } + + let specificFactory = factory.factoryForIndex(indexPath.row, inFolder: source.current) + if let err = specificFactory.removeByGUID(bookmark.guid).value.failureValue { + log.debug("Failed to remove \(bookmark.guid).") + self.onModelFailure(err) + return + } + + self.tableView.beginUpdates() + self.source = source.removeGUIDFromCurrent(bookmark.guid) + self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.left) + self.tableView.endUpdates() + self.updateEmptyPanelState() + + NotificationCenter.default.post(name: NSNotification.Name(rawValue: BookmarkStatusChangedNotification), object: bookmark, userInfo: ["added": false] + ) + } +} + +extension BookmarksPanel: HomePanelContextMenu { + func presentContextMenu(for site: Site, with indexPath: IndexPath, completionHandler: @escaping () -> PhotonActionSheet?) { + guard let contextMenu = completionHandler() else { return } + self.present(contextMenu, animated: true, completion: nil) + } + + func getSiteDetails(for indexPath: IndexPath) -> Site? { + guard let bookmarkItem = source?.current[indexPath.row] as? BookmarkItem else { return nil } + let site = Site(url: bookmarkItem.url, title: bookmarkItem.title, bookmarked: true, guid: bookmarkItem.guid) + site.icon = bookmarkItem.favicon + return site + } + + func getContextMenuActions(for site: Site, with indexPath: IndexPath) -> [PhotonActionSheetItem]? { + guard var actions = getDefaultContextMenuActions(for: site, homePanelDelegate: homePanelDelegate) else { return nil } + + let pinTopSite = PhotonActionSheetItem(title: Strings.PinTopsiteActionTitle, iconString: "action_pin", handler: { action in + self.pinTopSite(site) + }) + + actions.append(pinTopSite) + + // Only local bookmarks can be removed + guard let source = source else { return nil } + if source.current.itemIsEditableAtIndex(indexPath.row) { + let removeAction = PhotonActionSheetItem(title: Strings.RemoveBookmarkContextMenuTitle, iconString: "action_bookmark_remove", handler: { action in + self.deleteBookmark(indexPath: indexPath, source: source) + UnifiedTelemetry.recordEvent(category: .action, method: .delete, object: .bookmark, value: .bookmarksPanel, extras: ["gesture": "long-press"]) + }) + actions.append(removeAction) + } + return actions + } +} + +private protocol BookmarkFolderTableViewHeaderDelegate { + func didSelectHeader() +} + +extension BookmarksPanel: BookmarkFolderTableViewHeaderDelegate { + fileprivate func didSelectHeader() { + _ = self.navigationController?.popViewController(animated: true) + } +} + +class BookmarkFolderTableViewCell: TwoLineTableViewCell { + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.backgroundColor = BookmarksPanelUX.BookmarkFolderBGColor + textLabel?.backgroundColor = UIColor.clear + textLabel?.tintColor = BookmarksPanelUX.BookmarkFolderTextColor + + imageView?.image = UIImage(named: "bookmarkFolder") + accessoryType = UITableViewCellAccessoryType.disclosureIndicator + separatorInset = UIEdgeInsets.zero + } + + override func layoutSubviews() { + super.layoutSubviews() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +fileprivate class BookmarkFolderTableViewHeader: UITableViewHeaderFooterView { + var delegate: BookmarkFolderTableViewHeaderDelegate? + + lazy var titleLabel: UILabel = { + let label = UILabel() + label.textColor = UIConstants.HighlightBlue + return label + }() + + lazy var chevron: ChevronView = { + let chevron = ChevronView(direction: .left) + chevron.tintColor = UIConstants.HighlightBlue + chevron.lineWidth = BookmarksPanelUX.BookmarkFolderChevronLineWidth + return chevron + }() + + lazy var topBorder: UIView = { + let view = UIView() + view.backgroundColor = SiteTableViewControllerUX.HeaderBorderColor + return view + }() + + lazy var bottomBorder: UIView = { + let view = UIView() + view.backgroundColor = SiteTableViewControllerUX.HeaderBorderColor + return view + }() + + override var textLabel: UILabel? { + return titleLabel + } + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + + isUserInteractionEnabled = true + + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(BookmarkFolderTableViewHeader.viewWasTapped(_:))) + tapGestureRecognizer.numberOfTapsRequired = 1 + addGestureRecognizer(tapGestureRecognizer) + + addSubview(topBorder) + addSubview(bottomBorder) + contentView.addSubview(chevron) + contentView.addSubview(titleLabel) + + chevron.snp.makeConstraints { make in + make.left.equalTo(contentView).offset(BookmarksPanelUX.BookmarkFolderHeaderViewChevronInset) + make.centerY.equalTo(contentView) + make.size.equalTo(BookmarksPanelUX.BookmarkFolderChevronSize) + } + + titleLabel.snp.makeConstraints { make in + make.left.equalTo(chevron.snp.right).offset(BookmarksPanelUX.BookmarkFolderHeaderViewChevronInset) + make.right.greaterThanOrEqualTo(contentView).offset(-BookmarksPanelUX.BookmarkFolderHeaderViewChevronInset) + make.centerY.equalTo(contentView) + } + + topBorder.snp.makeConstraints { make in + make.left.right.equalTo(self) + make.top.equalTo(self).offset(-0.5) + make.height.equalTo(0.5) + } + + bottomBorder.snp.makeConstraints { make in + make.left.right.bottom.equalTo(self) + make.height.equalTo(0.5) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc fileprivate func viewWasTapped(_ gestureRecognizer: UITapGestureRecognizer) { + delegate?.didSelectHeader() + } +} diff --git a/mobile/ios/Client/Frontend/Home/HistoryPanel.swift b/mobile/ios/Client/Frontend/Home/HistoryPanel.swift new file mode 100644 index 0000000000..1ba5499263 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/HistoryPanel.swift @@ -0,0 +1,574 @@ +/* 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/. */ + +import UIKit + +import Shared +import Storage +import XCGLogger +import Deferred + +private typealias SectionNumber = Int +private typealias CategoryNumber = Int +private typealias CategorySpec = (section: SectionNumber?, rows: Int, offset: Int) + +private struct HistoryPanelUX { + static let WelcomeScreenItemTextColor = UIColor.gray + static let WelcomeScreenItemWidth = 170 + static let IconSize = 23 + static let IconBorderColor = UIColor(white: 0, alpha: 0.1) + static let IconBorderWidth: CGFloat = 0.5 +} + +private func getDate(_ dayOffset: Int) -> Date { + let calendar = Calendar(identifier: Calendar.Identifier.gregorian) + let nowComponents = (calendar as NSCalendar).components([.year, .month, .day], from: Date()) + let today = calendar.date(from: nowComponents)! + return (calendar as NSCalendar).date(byAdding: NSCalendar.Unit.day, value: dayOffset, to: today, options: [])! +} + +class HistoryPanel: SiteTableViewController, HomePanel { + weak var homePanelDelegate: HomePanelDelegate? + private var currentSyncedDevicesCount: Int? + + var events = [NotificationFirefoxAccountChanged, NotificationPrivateDataClearedHistory, NotificationDynamicFontChanged] + var refreshControl: UIRefreshControl? + + fileprivate lazy var longPressRecognizer: UILongPressGestureRecognizer = { + return UILongPressGestureRecognizer(target: self, action: #selector(HistoryPanel.longPress(_:))) + }() + + private lazy var emptyStateOverlayView: UIView = self.createEmptyStateOverlayView() + private let QueryLimit = 100 + private let NumSections = 5 + private let Today = getDate(0) + private let Yesterday = getDate(-1) + private let ThisWeek = getDate(-7) + private var categories: [CategorySpec] = [CategorySpec]() // Category number (index) -> (UI section, row count, cursor offset). + private var sectionLookup = [SectionNumber: CategoryNumber]() // Reverse lookup from UI section to data category. + + var syncDetailText = "" + var hasRecentlyClosed: Bool { + return self.profile.recentlyClosedTabs.tabs.count > 0 + } + + // MARK: - Lifecycle + init() { + super.init(nibName: nil, bundle: nil) + events.forEach { NotificationCenter.default.addObserver(self, selector: #selector(HistoryPanel.notificationReceived(_:)), name: $0, object: nil) } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + tableView.addGestureRecognizer(longPressRecognizer) + tableView.accessibilityIdentifier = "History List" + updateSyncedDevicesCount().uponQueue(DispatchQueue.main) { result in + self.updateNumberOfSyncedDevices(self.currentSyncedDevicesCount) + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + // Add a refresh control if the user is logged in and the control was not added before. If the user is not + // logged in, remove any existing control but only when it is not currently refreshing. Otherwise, wait for + // the refresh to finish before removing the control. + if profile.hasSyncableAccount() && refreshControl == nil { + addRefreshControl() + } else if refreshControl?.isRefreshing == false { + removeRefreshControl() + } + + if profile.hasSyncableAccount() { + syncDetailText = " " + updateSyncedDevicesCount().uponQueue(DispatchQueue.main) { result in + self.updateNumberOfSyncedDevices(self.currentSyncedDevicesCount) + } + } else { + syncDetailText = "" + } + } + + @objc fileprivate func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) { + guard longPressGestureRecognizer.state == UIGestureRecognizerState.began else { return } + let touchPoint = longPressGestureRecognizer.location(in: tableView) + guard let indexPath = tableView.indexPathForRow(at: touchPoint) else { return } + + if indexPath.section != 0 { + presentContextMenu(for: indexPath) + } + } + + // MARK: - History Data Store + func updateNumberOfSyncedDevices(_ count: Int?) { + if let count = count, count > 0 { + syncDetailText = String.localizedStringWithFormat(Strings.SyncedTabsTableViewCellDescription, count) + } else { + syncDetailText = "" + } + self.tableView.reloadRows(at: [IndexPath(row: 1, section: 0)], with: .automatic) + } + + func updateSyncedDevicesCount() -> Success { + return chainDeferred(self.profile.getCachedClientsAndTabs()) { tabsAndClients in + self.currentSyncedDevicesCount = tabsAndClients.count + return succeed() + } + } + + func notificationReceived(_ notification: Notification) { + reloadData() + + switch notification.name { + case NotificationFirefoxAccountChanged, NotificationPrivateDataClearedHistory: + if self.profile.hasSyncableAccount() { + resyncHistory() + } + break + case NotificationDynamicFontChanged: + if emptyStateOverlayView.superview != nil { + emptyStateOverlayView.removeFromSuperview() + } + emptyStateOverlayView = createEmptyStateOverlayView() + resyncHistory() + break + default: + // no need to do anything at all + print("Error: Received unexpected notification \(notification.name)") + break + } + } + + private func fetchData() -> Deferred>> { + return profile.history.getSitesByLastVisit(QueryLimit) + } + + private func setData(_ data: Cursor) { + self.data = data + self.computeSectionOffsets() + } + + func resyncHistory() { + profile.syncManager.syncHistory().uponQueue(DispatchQueue.main) { result in + if result.isSuccess { + self.reloadData() + } else { + self.endRefreshing() + } + + self.updateSyncedDevicesCount().uponQueue(DispatchQueue.main) { result in + self.updateNumberOfSyncedDevices(self.currentSyncedDevicesCount) + } + } + } + + // MARK: - Refreshing TableView + func addRefreshControl() { + let refresh = UIRefreshControl() + refresh.addTarget(self, action: #selector(HistoryPanel.refresh), for: UIControlEvents.valueChanged) + self.refreshControl = refresh + self.tableView.refreshControl = refresh + } + + func removeRefreshControl() { + self.tableView.refreshControl = nil + self.refreshControl = nil + } + + func endRefreshing() { + // Always end refreshing, even if we failed! + self.refreshControl?.endRefreshing() + + // Remove the refresh control if the user has logged out in the meantime + if !self.profile.hasSyncableAccount() { + self.removeRefreshControl() + } + } + + @objc func refresh() { + self.refreshControl?.beginRefreshing() + resyncHistory() + } + + override func reloadData() { + self.fetchData().uponQueue(DispatchQueue.main) { result in + if let data = result.successValue { + self.setData(data) + self.tableView.reloadData() + self.updateEmptyPanelState() + } + self.endRefreshing() + } + } + + // MARK: - Empty State + private func updateEmptyPanelState() { + if data.count == 0 { + if self.emptyStateOverlayView.superview == nil { + self.tableView.addSubview(self.emptyStateOverlayView) + self.emptyStateOverlayView.snp.makeConstraints { make -> Void in + make.left.right.bottom.equalTo(self.view) + make.top.equalTo(self.view).offset(100) + } + } + } else { + self.tableView.alwaysBounceVertical = true + self.emptyStateOverlayView.removeFromSuperview() + } + } + + private func createEmptyStateOverlayView() -> UIView { + let overlayView = UIView() + overlayView.backgroundColor = UIColor.white + + let welcomeLabel = UILabel() + overlayView.addSubview(welcomeLabel) + welcomeLabel.text = Strings.HistoryPanelEmptyStateTitle + welcomeLabel.textAlignment = NSTextAlignment.center + welcomeLabel.font = DynamicFontHelper.defaultHelper.DeviceFontLight + welcomeLabel.textColor = HistoryPanelUX.WelcomeScreenItemTextColor + welcomeLabel.numberOfLines = 0 + welcomeLabel.adjustsFontSizeToFitWidth = true + + welcomeLabel.snp.makeConstraints { make in + make.centerX.equalTo(overlayView) + // Sets proper top constraint for iPhone 6 in portait and for iPad. + make.centerY.equalTo(overlayView).offset(HomePanelUX.EmptyTabContentOffset).priority(100) + // Sets proper top constraint for iPhone 4, 5 in portrait. + make.top.greaterThanOrEqualTo(overlayView).offset(50) + make.width.equalTo(HistoryPanelUX.WelcomeScreenItemWidth) + } + return overlayView + } + + // MARK: - TableView Row Helpers + func computeSectionOffsets() { + var counts = [Int](repeating: 0, count: NumSections) + + // Loop over all the data. Record the start of each "section" of our list. + for i in 0.. 0 { + self.categories.append((section: section, rows: count, offset: offset)) + sectionLookup[section] = i + offset += count + section += 1 + } else { + self.categories.append((section: nil, rows: 0, offset: offset)) + } + } + } + + fileprivate func siteForIndexPath(_ indexPath: IndexPath) -> Site? { + let offset = self.categories[sectionLookup[indexPath.section]!].offset + return data[indexPath.row + offset] + } + + private func categoryForDate(_ date: MicrosecondTimestamp) -> Int { + let date = Double(date) + if date > (1000000 * Today.timeIntervalSince1970) { + return 0 + } + if date > (1000000 * Yesterday.timeIntervalSince1970) { + return 1 + } + if date > (1000000 * ThisWeek.timeIntervalSince1970) { + return 2 + } + return 3 + } + + private func isInCategory(_ date: MicrosecondTimestamp, category: Int) -> Bool { + return self.categoryForDate(date) == category + } + + // UI sections disappear as categories empty. We need to translate back and forth. + private func uiSectionToCategory(_ section: SectionNumber) -> CategoryNumber { + for i in 0.. SectionNumber? { + return self.categories[category].section + } + + // MARK: - TableView Delegate / DataSource + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = super.tableView(tableView, cellForRowAt: indexPath) + cell.accessoryType = UITableViewCellAccessoryType.none + + if indexPath.section == 0 { + cell.imageView!.layer.borderWidth = 0 + return indexPath.row == 0 ? configureRecentlyClosed(cell, for: indexPath) : configureSyncedTabs(cell, for: indexPath) + } else { + return configureSite(cell, for: indexPath) + } + } + + func configureRecentlyClosed(_ cell: UITableViewCell, for indexPath: IndexPath) -> UITableViewCell { + cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator + cell.textLabel!.text = Strings.RecentlyClosedTabsButtonTitle + cell.detailTextLabel!.text = "" + cell.imageView!.image = UIImage(named: "recently_closed") + cell.imageView?.backgroundColor = UIColor.white + if !hasRecentlyClosed { + cell.textLabel?.alpha = 0.5 + cell.imageView!.alpha = 0.5 + cell.selectionStyle = .none + } + cell.accessibilityIdentifier = "HistoryPanel.recentlyClosedCell" + return cell + } + + func configureSyncedTabs(_ cell: UITableViewCell, for indexPath: IndexPath) -> UITableViewCell { + cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator + cell.textLabel!.text = Strings.SyncedTabsTableViewCellTitle + cell.detailTextLabel!.text = self.syncDetailText + cell.imageView!.image = UIImage(named: "synced_devices") + cell.imageView?.backgroundColor = UIColor.white + cell.accessibilityIdentifier = "HistoryPanel.syncedDevicesCell" + return cell + } + + func configureSite(_ cell: UITableViewCell, for indexPath: IndexPath) -> UITableViewCell { + if let site = siteForIndexPath(indexPath), let cell = cell as? TwoLineTableViewCell { + cell.setLines(site.title, detailText: site.url) + + cell.imageView!.layer.borderColor = HistoryPanelUX.IconBorderColor.cgColor + cell.imageView!.layer.borderWidth = HistoryPanelUX.IconBorderWidth + cell.imageView?.setIcon(site.icon, forURL: site.tileURL, completed: { (color, url) in + if site.tileURL == url { + cell.imageView?.image = cell.imageView?.image?.createScaled(CGSize(width: HistoryPanelUX.IconSize, height: HistoryPanelUX.IconSize)) + cell.imageView?.backgroundColor = color + cell.imageView?.contentMode = .center + } + }) + } + return cell + } + + func numberOfSectionsInTableView(_ tableView: UITableView) -> Int { + var count = 1 + for category in self.categories where category.rows > 0 { + count += 1 + } + return count + } + + func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) { + if indexPath.section == 0 { + self.tableView.deselectRow(at: indexPath, animated: true) + return indexPath.row == 0 ? self.showRecentlyClosed() : self.showSyncedTabs() + } + if let site = self.siteForIndexPath(indexPath), let url = URL(string: site.url) { + let visitType = VisitType.typed // Means History, too. + if let homePanelDelegate = homePanelDelegate { + homePanelDelegate.homePanel(self, didSelectURL: url, visitType: visitType) + } + return + } + print("Error: No site or no URL when selecting row.") + } + + func pinTopSite(_ site: Site) { + _ = profile.history.addPinnedTopSite(site).value + } + + func showSyncedTabs() { + let nextController = RemoteTabsPanel() + nextController.homePanelDelegate = self.homePanelDelegate + nextController.profile = self.profile + self.refreshControl?.endRefreshing() + self.navigationController?.pushViewController(nextController, animated: true) + } + + func showRecentlyClosed() { + guard hasRecentlyClosed else { + return + } + let nextController = RecentlyClosedTabsPanel() + nextController.homePanelDelegate = self.homePanelDelegate + nextController.profile = self.profile + self.refreshControl?.endRefreshing() + self.navigationController?.pushViewController(nextController, animated: true) + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + var title = String() + switch sectionLookup[section]! { + case 0: return nil + case 1: title = NSLocalizedString("Today", comment: "History tableview section header") + case 2: title = NSLocalizedString("Yesterday", comment: "History tableview section header") + case 3: title = NSLocalizedString("Last week", comment: "History tableview section header") + case 4: title = NSLocalizedString("Last month", comment: "History tableview section header") + default: + assertionFailure("Invalid history section \(section)") + } + return title + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + if section == 0 { + return nil + } + return super.tableView(tableView, viewForHeaderInSection: section) + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + if section == 0 { + return 0 + } + return super.tableView(tableView, heightForHeaderInSection: section) + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == 0 { + return 2 + } + return self.categories[uiSectionToCategory(section)].rows + } + + func tableView(_ tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: IndexPath) { + // Intentionally blank. Required to use UITableViewRowActions + } + + fileprivate func removeHistoryForURLAtIndexPath(indexPath: IndexPath) { + if let site = self.siteForIndexPath(indexPath) { + // Why the dispatches? Because we call success and failure on the DB + // queue, and so calling anything else that calls through to the DB will + // deadlock. This problem will go away when the history API switches to + // Deferred instead of using callbacks. + self.profile.history.removeHistoryForURL(site.url) + .upon { res in + self.fetchData().uponQueue(DispatchQueue.main) { result in + // If a section will be empty after removal, we must remove the section itself. + if let data = result.successValue { + + let oldCategories = self.categories + self.data = data + self.computeSectionOffsets() + + let sectionsToDelete = NSMutableIndexSet() + var rowsToDelete = [IndexPath]() + let sectionsToAdd = NSMutableIndexSet() + var rowsToAdd = [IndexPath]() + + for (index, category) in self.categories.enumerated() { + let oldCategory = oldCategories[index] + + // don't bother if we're not displaying this category + if oldCategory.section == nil && category.section == nil { + continue + } + + // 1. add a new section if the section didn't previously exist + if oldCategory.section == nil && category.section != oldCategory.section { + sectionsToAdd.add(category.section!) + } + + // 2. add a new row if there are more rows now than there were before + if oldCategory.rows < category.rows { + rowsToAdd.append(IndexPath(row: category.rows-1, section: category.section!)) + } + + // if we're dealing with the section where the row was deleted: + // 1. if the category no longer has a section, then we need to delete the entire section + // 2. delete a row if the number of rows has been reduced + // 3. delete the selected row and add a new one on the bottom of the section if the number of rows has stayed the same + if oldCategory.section == indexPath.section { + if category.section == nil { + sectionsToDelete.add(indexPath.section) + } else if oldCategory.section == category.section { + if oldCategory.rows > category.rows { + rowsToDelete.append(indexPath) + } else if category.rows == oldCategory.rows { + rowsToDelete.append(indexPath) + rowsToAdd.append(IndexPath(row: category.rows-1, section: indexPath.section)) + } + } + } + } + + self.tableView.beginUpdates() + if sectionsToAdd.count > 0 { + self.tableView.insertSections(sectionsToAdd as IndexSet, with: UITableViewRowAnimation.left) + } + if sectionsToDelete.count > 0 { + self.tableView.deleteSections(sectionsToDelete as IndexSet, with: UITableViewRowAnimation.right) + } + if !rowsToDelete.isEmpty { + self.tableView.deleteRows(at: rowsToDelete, with: UITableViewRowAnimation.right) + } + + if !rowsToAdd.isEmpty { + self.tableView.insertRows(at: rowsToAdd, with: UITableViewRowAnimation.right) + } + + self.tableView.endUpdates() + self.updateEmptyPanelState() + } + } + } + } + } + + func tableView(_ tableView: UITableView, editActionsForRowAtIndexPath indexPath: IndexPath) -> [AnyObject]? { + if indexPath.section == 0 { + return [] + } + let title = NSLocalizedString("Delete", tableName: "HistoryPanel", comment: "Action button for deleting history entries in the history panel.") + + let delete = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: title, handler: { (action, indexPath) in + self.removeHistoryForURLAtIndexPath(indexPath: indexPath) + }) + return [delete] + } +} + +extension HistoryPanel: HomePanelContextMenu { + func presentContextMenu(for site: Site, with indexPath: IndexPath, completionHandler: @escaping () -> PhotonActionSheet?) { + guard let contextMenu = completionHandler() else { return } + self.present(contextMenu, animated: true, completion: nil) + } + + func getSiteDetails(for indexPath: IndexPath) -> Site? { + return siteForIndexPath(indexPath) + } + + func getContextMenuActions(for site: Site, with indexPath: IndexPath) -> [PhotonActionSheetItem]? { + guard var actions = getDefaultContextMenuActions(for: site, homePanelDelegate: homePanelDelegate) else { return nil } + + let removeAction = PhotonActionSheetItem(title: Strings.DeleteFromHistoryContextMenuTitle, iconString: "action_delete", handler: { action in + self.removeHistoryForURLAtIndexPath(indexPath: indexPath) + }) + + let pinTopSite = PhotonActionSheetItem(title: Strings.PinTopsiteActionTitle, iconString: "action_pin", handler: { action in + self.pinTopSite(site) + }) + actions.append(pinTopSite) + actions.append(removeAction) + return actions + } +} diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/Contents.json new file mode 100644 index 0000000000..d7def16a3e --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reading list add circle.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "reading list add circle@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "reading list add circle@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle.png new file mode 100644 index 0000000000..76724fc007 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle@2x.png new file mode 100644 index 0000000000..73a6405add Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle@3x.png new file mode 100644 index 0000000000..41ff52928f Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/AddToReadingListCircle.imageset/reading list add circle@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/Contents.json new file mode 100644 index 0000000000..a37eb57cfe --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reader view circle.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "reader view circle@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "reader view circle@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle.png new file mode 100644 index 0000000000..97e8d25092 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle@2x.png new file mode 100644 index 0000000000..725797ea1e Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle@3x.png new file mode 100644 index 0000000000..ff2654b020 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/ReaderModeCircle.imageset/reader view circle@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/Contents.json new file mode 100644 index 0000000000..5ede011af1 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "clear.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "clear@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "clear@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear.png new file mode 100644 index 0000000000..b0ebd2762d Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear@2x.png new file mode 100644 index 0000000000..ecaf5fa679 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear@3x.png new file mode 100644 index 0000000000..965e526caf Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/clear.imageset/clear@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel.png new file mode 100644 index 0000000000..65d0e9ca90 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel@2x.png new file mode 100644 index 0000000000..7b2cc29342 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel@3x.png new file mode 100644 index 0000000000..119433323f Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/BookmarksEmptyPanel@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/Contents.json new file mode 100644 index 0000000000..69ddbc0672 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyBookmarks.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "BookmarksEmptyPanel.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "BookmarksEmptyPanel@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "BookmarksEmptyPanel@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/Contents.json new file mode 100644 index 0000000000..86f95699c8 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "historyEmptyPanel.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "historyEmptyPanel@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "historyEmptyPanel@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel.png new file mode 100644 index 0000000000..857a25f237 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel@2x.png new file mode 100644 index 0000000000..c56355d858 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel@3x.png new file mode 100644 index 0000000000..b9c6bb719f Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyHistory.imageset/historyEmptyPanel@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/Contents.json new file mode 100644 index 0000000000..ccd23408e7 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "sync-devices.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "sync-devices@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "sync-devices@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices.png new file mode 100644 index 0000000000..d6d3a57745 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices@2x.png new file mode 100644 index 0000000000..4c3aab5fb0 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices@3x.png new file mode 100644 index 0000000000..38dc8cf449 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptySync.imageset/sync-devices@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/Contents.json new file mode 100644 index 0000000000..d1f7e65ce4 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "topSitesEmptyPanel.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "topSitesEmptyPanel@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "topSitesEmptyPanel@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel.png new file mode 100644 index 0000000000..43b5513c7f Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel@2x.png new file mode 100644 index 0000000000..7cdd5340ba Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel@3x.png new file mode 100644 index 0000000000..4b6ff1ccc2 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/emptyTopSites.imageset/topSitesEmptyPanel@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/Contents.json new file mode 100644 index 0000000000..554eb04b28 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bookmark-Outline.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bookmark-Outline@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "bookmark-Outline@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline.png new file mode 100644 index 0000000000..03fe478950 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline@2x.png new file mode 100644 index 0000000000..fca7ac6cc5 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline@3x.png new file mode 100644 index 0000000000..c29ed85a61 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconBookmarks.imageset/bookmark-Outline@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/Contents.json new file mode 100644 index 0000000000..e972e4e90c --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "history.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "history@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "history@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history.png new file mode 100644 index 0000000000..55a38daf73 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history@2x.png new file mode 100644 index 0000000000..f4b829241e Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history@3x.png new file mode 100644 index 0000000000..700bb3084a Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconHistory.imageset/history@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/Contents.json new file mode 100644 index 0000000000..c2dfe5e38a --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reading-list.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "reading-list@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "reading-list@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list.png new file mode 100644 index 0000000000..05f93e98cc Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list@2x.png new file mode 100644 index 0000000000..05e1576f58 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list@3x.png new file mode 100644 index 0000000000..0038a91124 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconReadingList.imageset/reading-list@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Contents.json new file mode 100644 index 0000000000..977698d614 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Synced Panel.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Synced Panel@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Synced Panel@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel.png new file mode 100644 index 0000000000..c889e158cb Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel@2x.png new file mode 100644 index 0000000000..7b47639594 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel@3x.png new file mode 100644 index 0000000000..25e4001a66 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconSyncedTabs.imageset/Synced Panel@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/Contents.json b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/Contents.json new file mode 100644 index 0000000000..d0b4f6a6ab --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "topsites.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "topsites@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "topsites@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites.png new file mode 100644 index 0000000000..67fc5a0c6c Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites@2x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites@2x.png new file mode 100644 index 0000000000..16d6bc8a43 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites@2x.png differ diff --git a/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites@3x.png b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites@3x.png new file mode 100644 index 0000000000..11c0270b78 Binary files /dev/null and b/mobile/ios/Client/Frontend/Home/Home.xcassets/panelIconTopSites.imageset/topsites@3x.png differ diff --git a/mobile/ios/Client/Frontend/Home/HomePanelViewController.swift b/mobile/ios/Client/Frontend/Home/HomePanelViewController.swift new file mode 100644 index 0000000000..89455f3e67 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/HomePanelViewController.swift @@ -0,0 +1,364 @@ +/* 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/. */ + +import Foundation +import Shared +import SnapKit +import UIKit +import Storage + +private struct HomePanelViewControllerUX { + // Height of the top panel switcher button toolbar. + static let ButtonContainerHeight: CGFloat = 40 + static let ButtonContainerBorderColor = UIColor.black.withAlphaComponent(0.1) + static let BackgroundColorPrivateMode = UIConstants.PrivateModeAssistantToolbarBackgroundColor + static let ToolbarButtonDeselectedColorNormalMode = UIColor(white: 0.2, alpha: 0.5) + static let ToolbarButtonDeselectedColorPrivateMode = UIColor(white: 0.9, alpha: 1) + static let ButtonHighlightLineHeight: CGFloat = 2 + static let ButtonSelectionAnimationDuration = 0.2 +} + +protocol HomePanelViewControllerDelegate: class { + func homePanelViewController(_ homePanelViewController: HomePanelViewController, didSelectURL url: URL, visitType: VisitType) + func homePanelViewController(_ HomePanelViewController: HomePanelViewController, didSelectPanel panel: Int) + func homePanelViewControllerDidRequestToSignIn(_ homePanelViewController: HomePanelViewController) + func homePanelViewControllerDidRequestToCreateAccount(_ homePanelViewController: HomePanelViewController) + func homePanelViewControllerDidRequestToOpenInNewTab(_ url: URL, isPrivate: Bool) +} + +protocol HomePanel: class { + weak var homePanelDelegate: HomePanelDelegate? { get set } +} + +struct HomePanelUX { + static let EmptyTabContentOffset = -180 +} + +protocol HomePanelDelegate: class { + func homePanelDidRequestToSignIn(_ homePanel: HomePanel) + func homePanelDidRequestToCreateAccount(_ homePanel: HomePanel) + func homePanelDidRequestToOpenInNewTab(_ url: URL, isPrivate: Bool) + func homePanel(_ homePanel: HomePanel, didSelectURL url: URL, visitType: VisitType) + func homePanel(_ homePanel: HomePanel, didSelectURLString url: String, visitType: VisitType) +} + +struct HomePanelState { + var selectedIndex: Int = 0 +} + +enum HomePanelType: Int { + case topSites = 0 + case bookmarks = 1 + case history = 2 + case readingList = 3 + + var localhostURL: URL { + return URL(string: "#panel=\(self.rawValue)", relativeTo: UIConstants.AboutHomePage as URL)! + } +} + +class HomePanelViewController: UIViewController, UITextFieldDelegate, HomePanelDelegate { + static let Themes: [String: Theme] = { + var themes = [String: Theme]() + var theme = Theme() + theme.backgroundColor = UIConstants.AppBackgroundColor + theme.buttonTintColor = UIColor(rgb: 0x7e7e7f) + theme.highlightButtonColor = UIConstants.HighlightBlue + themes[Theme.PrivateMode] = theme + + theme = Theme() + theme.backgroundColor = UIConstants.AppBackgroundColor + theme.buttonTintColor = UIColor(rgb: 0x7e7e7f) + theme.highlightButtonColor = UIConstants.HighlightBlue + themes[Theme.NormalMode] = theme + + return themes + }() + + var profile: Profile! + var notificationToken: NSObjectProtocol! + var panels: [HomePanelDescriptor]! + var url: URL? + weak var delegate: HomePanelViewControllerDelegate? + + fileprivate var buttonContainerView = UIStackView() + fileprivate var buttonContainerBottomBorderView: UIView! + fileprivate var controllerContainerView: UIView! + fileprivate var buttons: [UIButton] = [] + fileprivate var highlightLine = UIView() //The line underneath a panel button that shows which one is selected + + fileprivate var buttonTintColor: UIColor? + fileprivate var buttonSelectedTintColor: UIColor? + + var homePanelState: HomePanelState { + return HomePanelState(selectedIndex: selectedPanel?.rawValue ?? 0) + } + + override func viewDidLoad() { + view.backgroundColor = UIConstants.AppBackgroundColor + + buttonContainerView.axis = .horizontal + buttonContainerView.alignment = .fill + buttonContainerView.distribution = .fillEqually + buttonContainerView.spacing = 14 + buttonContainerView.clipsToBounds = true + buttonContainerView.accessibilityNavigationStyle = .combined + buttonContainerView.accessibilityLabel = NSLocalizedString("Panel Chooser", comment: "Accessibility label for the Home panel's top toolbar containing list of the home panels (top sites, bookmarsk, history, remote tabs, reading list).") + view.addSubview(buttonContainerView) + buttonContainerView.addSubview(highlightLine) + + self.buttonContainerBottomBorderView = UIView() + self.view.addSubview(buttonContainerBottomBorderView) + buttonContainerBottomBorderView.backgroundColor = HomePanelViewControllerUX.ButtonContainerBorderColor + + controllerContainerView = UIView() + view.addSubview(controllerContainerView) + + buttonContainerView.snp.makeConstraints { make in + make.top.equalTo(self.view) + make.leading.trailing.equalTo(self.view).inset(14) + make.height.equalTo(HomePanelViewControllerUX.ButtonContainerHeight) + } + + buttonContainerBottomBorderView.snp.makeConstraints { make in + make.top.equalTo(self.buttonContainerView.snp.bottom).offset(-1) + make.bottom.equalTo(self.buttonContainerView) + make.leading.trailing.equalToSuperview() + } + + controllerContainerView.snp.makeConstraints { make in + make.top.equalTo(self.buttonContainerView.snp.bottom) + make.left.right.bottom.equalTo(self.view) + } + + self.panels = HomePanels().enabledPanels + updateButtons() + + // Gesture recognizer to dismiss the keyboard in the URLBarView when the buttonContainerView is tapped + let dismissKeyboardGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(HomePanelViewController.dismissKeyboard(_:))) + dismissKeyboardGestureRecognizer.cancelsTouchesInView = false + buttonContainerView.addGestureRecognizer(dismissKeyboardGestureRecognizer) + } + + func dismissKeyboard(_ gestureRecognizer: UITapGestureRecognizer) { + view.window?.rootViewController?.view.endEditing(true) + } + + var selectedPanel: HomePanelType? = nil { + didSet { + if oldValue == selectedPanel { + // Prevent flicker, allocations, and disk access: avoid duplicate view controllers. + return + } + + if let index = oldValue?.rawValue { + if index < buttons.count { + let currentButton = buttons[index] + currentButton.isSelected = false + currentButton.isUserInteractionEnabled = true + } + } + + hideCurrentPanel() + + if let index = selectedPanel?.rawValue { + if index < buttons.count { + let newButton = buttons[index] + newButton.isSelected = true + newButton.isUserInteractionEnabled = false + } + + if index < panels.count { + let panel = self.panels[index].makeViewController(profile) + let accessibilityLabel = self.panels[index].accessibilityLabel + if let panelController = panel as? UINavigationController, + let rootPanel = panelController.viewControllers.first { + setupHomePanel(rootPanel, accessibilityLabel: accessibilityLabel) + self.showPanel(panelController) + } else { + setupHomePanel(panel, accessibilityLabel: accessibilityLabel) + self.showPanel(panel) + } + } + } + self.updateButtonTints() + } + } + + func setupHomePanel(_ panel: UIViewController, accessibilityLabel: String) { + (panel as? HomePanel)?.homePanelDelegate = self + panel.view.accessibilityNavigationStyle = .combined + panel.view.accessibilityLabel = accessibilityLabel + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return UIStatusBarStyle.lightContent + } + + fileprivate func hideCurrentPanel() { + if let panel = childViewControllers.first { + panel.willMove(toParentViewController: nil) + panel.beginAppearanceTransition(false, animated: false) + panel.view.removeFromSuperview() + panel.endAppearanceTransition() + panel.removeFromParentViewController() + } + } + + fileprivate func showPanel(_ panel: UIViewController) { + addChildViewController(panel) + panel.beginAppearanceTransition(true, animated: false) + controllerContainerView.addSubview(panel.view) + panel.endAppearanceTransition() + panel.view.snp.makeConstraints { make in + make.top.equalTo(self.buttonContainerView.snp.bottom) + make.left.right.bottom.equalTo(self.view) + } + panel.didMove(toParentViewController: self) + } + + func tappedButton(_ sender: UIButton!) { + for (index, button) in buttons.enumerated() where button == sender { + selectedPanel = HomePanelType(rawValue: index) + delegate?.homePanelViewController(self, didSelectPanel: index) + if selectedPanel == .bookmarks { + UnifiedTelemetry.recordEvent(category: .action, method: .view, object: .bookmarksPanel, value: .homePanelTabButton) + } + break + } + } + + fileprivate func updateButtons() { + for panel in panels { + let button = UIButton() + button.addTarget(self, action: #selector(HomePanelViewController.tappedButton(_:)), for: .touchUpInside) + if let image = UIImage.templateImageNamed("panelIcon\(panel.imageName)") { + button.setImage(image, for: UIControlState.normal) + } + button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 4, right: 0) + button.accessibilityLabel = panel.accessibilityLabel + button.accessibilityIdentifier = panel.accessibilityIdentifier + buttons.append(button) + self.buttonContainerView.addArrangedSubview(button) + } + } + + func updateButtonTints() { + var selectedbutton: UIView? + for (index, button) in self.buttons.enumerated() { + if index == self.selectedPanel?.rawValue { + button.tintColor = self.buttonSelectedTintColor + selectedbutton = button + } else { + button.tintColor = self.buttonTintColor + } + } + guard let button = selectedbutton else { + return + } + + // Calling this before makes sure that only the highlightline animates and not the homepanels + self.view.setNeedsUpdateConstraints() + self.view.layoutIfNeeded() + UIView.animate(withDuration: HomePanelViewControllerUX.ButtonSelectionAnimationDuration, delay: 0.0, usingSpringWithDamping: 0.85, initialSpringVelocity: 0.0, options: [], animations: { _ in + self.highlightLine.snp.remakeConstraints { make in + make.leading.equalTo(button.snp.leading) + make.trailing.equalTo(button.snp.trailing) + make.bottom.equalToSuperview() + make.height.equalTo(HomePanelViewControllerUX.ButtonHighlightLineHeight) + } + self.view.setNeedsUpdateConstraints() + self.view.layoutIfNeeded() + }, completion: nil) + } + + func homePanel(_ homePanel: HomePanel, didSelectURLString url: String, visitType: VisitType) { + // If we can't get a real URL out of what should be a URL, we let the user's + // default search engine give it a shot. + // Typically we'll be in this state if the user has tapped a bookmarked search template + // (e.g., "http://foo.com/bar/?query=%s"), and this will get them the same behavior as if + // they'd copied and pasted into the URL bar. + // See BrowserViewController.urlBar:didSubmitText:. + guard let url = URIFixup.getURL(url) ?? profile.searchEngines.defaultEngine.searchURLForQuery(url) else { + Logger.browserLogger.warning("Invalid URL, and couldn't generate a search URL for it.") + return + } + + return self.homePanel(homePanel, didSelectURL: url, visitType: visitType) + } + + func homePanel(_ homePanel: HomePanel, didSelectURL url: URL, visitType: VisitType) { + delegate?.homePanelViewController(self, didSelectURL: url, visitType: visitType) + dismiss(animated: true, completion: nil) + } + + func homePanelDidRequestToCreateAccount(_ homePanel: HomePanel) { + delegate?.homePanelViewControllerDidRequestToCreateAccount(self) + } + + func homePanelDidRequestToSignIn(_ homePanel: HomePanel) { + delegate?.homePanelViewControllerDidRequestToSignIn(self) + } + + func homePanelDidRequestToOpenInNewTab(_ url: URL, isPrivate: Bool) { + delegate?.homePanelViewControllerDidRequestToOpenInNewTab(url, isPrivate: isPrivate) + } +} + +// MARK: UIAppearance +extension HomePanelViewController: Themeable { + func applyTheme(_ themeName: String) { + guard let theme = HomePanelViewController.Themes[themeName] else { + fatalError("Theme not found") + } + + highlightLine.backgroundColor = theme.highlightButtonColor + buttonContainerView.backgroundColor = theme.backgroundColor + self.view.backgroundColor = theme.backgroundColor + buttonTintColor = theme.buttonTintColor + buttonSelectedTintColor = theme.highlightButtonColor + updateButtonTints() + } +} + +protocol HomePanelContextMenu { + func getSiteDetails(for indexPath: IndexPath) -> Site? + func getContextMenuActions(for site: Site, with indexPath: IndexPath) -> [PhotonActionSheetItem]? + func presentContextMenu(for indexPath: IndexPath) + func presentContextMenu(for site: Site, with indexPath: IndexPath, completionHandler: @escaping () -> PhotonActionSheet?) +} + +extension HomePanelContextMenu { + func presentContextMenu(for indexPath: IndexPath) { + guard let site = getSiteDetails(for: indexPath) else { return } + + presentContextMenu(for: site, with: indexPath, completionHandler: { + return self.contextMenu(for: site, with: indexPath) + }) + } + + func contextMenu(for site: Site, with indexPath: IndexPath) -> PhotonActionSheet? { + guard let actions = self.getContextMenuActions(for: site, with: indexPath) else { return nil } + + let contextMenu = PhotonActionSheet(site: site, actions: actions) + contextMenu.modalPresentationStyle = .overFullScreen + contextMenu.modalTransitionStyle = .crossDissolve + + return contextMenu + } + + func getDefaultContextMenuActions(for site: Site, homePanelDelegate: HomePanelDelegate?) -> [PhotonActionSheetItem]? { + guard let siteURL = URL(string: site.url) else { return nil } + + let openInNewTabAction = PhotonActionSheetItem(title: Strings.OpenInNewTabContextMenuTitle, iconString: "quick_action_new_tab") { action in + homePanelDelegate?.homePanelDidRequestToOpenInNewTab(siteURL, isPrivate: false) + } + + let openInNewPrivateTabAction = PhotonActionSheetItem(title: Strings.OpenInNewPrivateTabContextMenuTitle, iconString: "quick_action_new_private_tab") { action in + homePanelDelegate?.homePanelDidRequestToOpenInNewTab(siteURL, isPrivate: true) + } + + return [openInNewTabAction, openInNewPrivateTabAction] + } +} diff --git a/mobile/ios/Client/Frontend/Home/HomePanels.swift b/mobile/ios/Client/Frontend/Home/HomePanels.swift new file mode 100644 index 0000000000..bb131c392f --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/HomePanels.swift @@ -0,0 +1,69 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared + +/** + * Data for identifying and constructing a HomePanel. + */ +struct HomePanelDescriptor { + let makeViewController: (_ profile: Profile) -> UIViewController + let imageName: String + let accessibilityLabel: String + let accessibilityIdentifier: String +} + +class HomePanels { + let enabledPanels = [ + HomePanelDescriptor( + makeViewController: { profile in + return ActivityStreamPanel(profile: profile) + }, + imageName: "TopSites", + accessibilityLabel: NSLocalizedString("Top sites", comment: "Panel accessibility label"), + accessibilityIdentifier: "HomePanels.TopSites"), + + HomePanelDescriptor( + makeViewController: { profile in + let bookmarks = BookmarksPanel() + bookmarks.profile = profile + let controller = UINavigationController(rootViewController: bookmarks) + controller.setNavigationBarHidden(true, animated: false) + // this re-enables the native swipe to pop gesture on UINavigationController for embedded, navigation bar-less UINavigationControllers + // don't ask me why it works though, I've tried to find an answer but can't. + // found here, along with many other places: + // http://luugiathuy.com/2013/11/ios7-interactivepopgesturerecognizer-for-uinavigationcontroller-with-hidden-navigation-bar/ + controller.interactivePopGestureRecognizer?.delegate = nil + return controller + }, + imageName: "Bookmarks", + accessibilityLabel: NSLocalizedString("Bookmarks", comment: "Panel accessibility label"), + accessibilityIdentifier: "HomePanels.Bookmarks"), + + HomePanelDescriptor( + makeViewController: { profile in + let history = HistoryPanel() + history.profile = profile + let controller = UINavigationController(rootViewController: history) + controller.setNavigationBarHidden(true, animated: false) + controller.interactivePopGestureRecognizer?.delegate = nil + return controller + }, + imageName: "History", + accessibilityLabel: NSLocalizedString("History", comment: "Panel accessibility label"), + accessibilityIdentifier: "HomePanels.History"), + + HomePanelDescriptor( + makeViewController: { profile in + let controller = ReadingListPanel() + controller.profile = profile + return controller + }, + imageName: "ReadingList", + accessibilityLabel: NSLocalizedString("Reading list", comment: "Panel accessibility label"), + accessibilityIdentifier: "HomePanels.ReadingList"), + ] +} diff --git a/mobile/ios/Client/Frontend/Home/PanelDataObservers.swift b/mobile/ios/Client/Frontend/Home/PanelDataObservers.swift new file mode 100644 index 0000000000..cea62a6cb5 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/PanelDataObservers.swift @@ -0,0 +1,97 @@ +/* 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/. */ + +import Foundation +import Deferred +import Shared + +public let ActivityStreamTopSiteCacheSize: Int32 = 16 + +private let log = Logger.browserLogger + +protocol DataObserver { + var profile: Profile { get } + weak var delegate: DataObserverDelegate? { get set } + + func refreshIfNeeded(forceHighlights highlights: Bool, forceTopSites topSites: Bool) +} + +protocol DataObserverDelegate: class { + func didInvalidateDataSources(refresh forced: Bool, highlightsRefreshed: Bool, topSitesRefreshed: Bool) + func willInvalidateDataSources(forceHighlights highlights: Bool, forceTopSites topSites: Bool) +} + +// Make these delegate methods optional by providing default implementations +extension DataObserverDelegate { + func didInvalidateDataSources(refresh forced: Bool, highlightsRefreshed: Bool, topSitesRefreshed: Bool) {} + func willInvalidateDataSources(forceHighlights highlights: Bool, forceTopSites topSites: Bool) {} +} + +open class PanelDataObservers { + var activityStream: DataObserver + + init(profile: Profile) { + self.activityStream = ActivityStreamDataObserver(profile: profile) + } +} + +class ActivityStreamDataObserver: DataObserver { + let profile: Profile + weak var delegate: DataObserverDelegate? + private var invalidationTime = OneMinuteInMilliseconds * 15 + + fileprivate let events = [NotificationFirefoxAccountChanged, NotificationProfileDidFinishSyncing, NotificationPrivateDataClearedHistory] + + init(profile: Profile) { + self.profile = profile + self.profile.history.setTopSitesCacheSize(ActivityStreamTopSiteCacheSize) + events.forEach { NotificationCenter.default.addObserver(self, selector: #selector(self.notificationReceived(_:)), name: $0, object: nil) } + } + + /* + refreshIfNeeded will refresh the underlying caches for both TopSites and Highlights. + By default this will only refresh the highlights if the last fetch is older than 15 mins + By default this will only refresh topSites if KeyTopSitesCacheIsValid is false + */ + func refreshIfNeeded(forceHighlights highlights: Bool, forceTopSites topSites: Bool) { + guard !profile.isShutdown else { + return + } + + // Highlights are cached for 15 mins + let userEnabledHighlights = profile.prefs.boolForKey(PrefsKeys.ASRecentHighlightsVisible) ?? true + let lastInvalidationTime = profile.prefs.unsignedLongForKey(PrefsKeys.ASLastInvalidation) ?? 0 + let shouldInvalidateHighlights = (highlights || (Date.now() - lastInvalidationTime > invalidationTime)) && userEnabledHighlights + + // KeyTopSitesCacheIsValid is false when we want to invalidate. Thats why this logic is so backwards + let shouldInvalidateTopSites = topSites || !(profile.prefs.boolForKey(PrefsKeys.KeyTopSitesCacheIsValid) ?? false) + if !shouldInvalidateTopSites && !shouldInvalidateHighlights { + // There is nothing to refresh. Bye + return + } + + self.delegate?.willInvalidateDataSources(forceHighlights: highlights, forceTopSites: topSites) + self.profile.recommendations.repopulate(invalidateTopSites: shouldInvalidateTopSites, invalidateHighlights: shouldInvalidateHighlights).uponQueue(DispatchQueue.main) { _ in + if shouldInvalidateTopSites { + self.profile.prefs.setBool(true, forKey: PrefsKeys.KeyTopSitesCacheIsValid) + } + + if shouldInvalidateHighlights { + let newInvalidationTime = shouldInvalidateHighlights ? Date.now() : lastInvalidationTime + self.profile.prefs.setLong(newInvalidationTime, forKey: PrefsKeys.ASLastInvalidation) + } + + self.delegate?.didInvalidateDataSources(refresh: highlights || topSites, highlightsRefreshed: shouldInvalidateHighlights, topSitesRefreshed: shouldInvalidateTopSites) + } + } + + @objc func notificationReceived(_ notification: Notification) { + switch notification.name { + case NotificationProfileDidFinishSyncing, NotificationFirefoxAccountChanged, NotificationPrivateDataClearedHistory: + refreshIfNeeded(forceHighlights: true, forceTopSites: true) + default: + log.warning("Received unexpected notification \(notification.name)") + } + } +} diff --git a/mobile/ios/Client/Frontend/Home/ReaderPanel.swift b/mobile/ios/Client/Frontend/Home/ReaderPanel.swift new file mode 100644 index 0000000000..8b804f0804 --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/ReaderPanel.swift @@ -0,0 +1,456 @@ +/* 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/. */ + +import UIKit +import SnapKit +import Storage +import ReadingList +import Shared +import XCGLogger + +private let log = Logger.browserLogger + +private struct ReadingListTableViewCellUX { + static let RowHeight: CGFloat = 86 + + static let ActiveTextColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0) + static let DimmedTextColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 0.44) + + static let ReadIndicatorWidth: CGFloat = 12 // image width + static let ReadIndicatorHeight: CGFloat = 12 // image height + static let ReadIndicatorLeftOffset: CGFloat = 18 + static let ReadAccessibilitySpeechPitch: Float = 0.7 // 1.0 default, 0.0 lowest, 2.0 highest + + static let TitleLabelTopOffset: CGFloat = 14 - 4 + static let TitleLabelLeftOffset: CGFloat = 16 + 16 + 16 + static let TitleLabelRightOffset: CGFloat = -40 + + static let HostnameLabelBottomOffset: CGFloat = 11 + + static let DeleteButtonBackgroundColor = UIColor(rgb: 0xef4035) + static let DeleteButtonTitleColor = UIColor.white + static let DeleteButtonTitleEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4) + + static let MarkAsReadButtonBackgroundColor = UIColor(rgb: 0x2193d1) + static let MarkAsReadButtonTitleColor = UIColor.white + static let MarkAsReadButtonTitleEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4) + + // Localizable strings + static let DeleteButtonTitleText = NSLocalizedString("Remove", comment: "Title for the button that removes a reading list item") + static let MarkAsReadButtonTitleText = NSLocalizedString("Mark as Read", comment: "Title for the button that marks a reading list item as read") + static let MarkAsUnreadButtonTitleText = NSLocalizedString("Mark as Unread", comment: "Title for the button that marks a reading list item as unread") +} + +private struct ReadingListPanelUX { + // Welcome Screen + static let WelcomeScreenTopPadding: CGFloat = 16 + static let WelcomeScreenPadding: CGFloat = 15 + static let WelcomeScreenHeaderTextColor = UIColor.darkGray + + static let WelcomeScreenItemTextColor = UIColor.gray + static let WelcomeScreenItemWidth = 220 + static let WelcomeScreenItemOffset = -20 + + static let WelcomeScreenCircleWidth = 40 + static let WelcomeScreenCircleOffset = 20 + static let WelcomeScreenCircleSpacer = 10 +} + +class ReadingListTableViewCell: UITableViewCell { + var title: String = "Example" { + didSet { + titleLabel.text = title + updateAccessibilityLabel() + } + } + + var url: URL = URL(string: "http://www.example.com")! { + didSet { + hostnameLabel.text = simplifiedHostnameFromURL(url) + updateAccessibilityLabel() + } + } + + var unread: Bool = true { + didSet { + readStatusImageView.image = UIImage(named: unread ? "MarkAsRead" : "MarkAsUnread") + titleLabel.textColor = unread ? ReadingListTableViewCellUX.ActiveTextColor : ReadingListTableViewCellUX.DimmedTextColor + hostnameLabel.textColor = unread ? ReadingListTableViewCellUX.ActiveTextColor : ReadingListTableViewCellUX.DimmedTextColor + updateAccessibilityLabel() + } + } + + let readStatusImageView: UIImageView! + let titleLabel: UILabel! + let hostnameLabel: UILabel! + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + readStatusImageView = UIImageView() + titleLabel = UILabel() + hostnameLabel = UILabel() + + super.init(style: style, reuseIdentifier: reuseIdentifier) + + backgroundColor = UIColor.clear + + separatorInset = UIEdgeInsets(top: 0, left: 48, bottom: 0, right: 0) + layoutMargins = UIEdgeInsets.zero + preservesSuperviewLayoutMargins = false + + contentView.addSubview(readStatusImageView) + readStatusImageView.contentMode = UIViewContentMode.scaleAspectFit + readStatusImageView.snp.makeConstraints { (make) -> Void in + make.width.equalTo(ReadingListTableViewCellUX.ReadIndicatorWidth) + make.height.equalTo(ReadingListTableViewCellUX.ReadIndicatorHeight) + make.centerY.equalTo(self.contentView) + make.leading.equalTo(self.contentView).offset(ReadingListTableViewCellUX.ReadIndicatorLeftOffset) + } + + contentView.addSubview(titleLabel) + contentView.addSubview(hostnameLabel) + + titleLabel.textColor = ReadingListTableViewCellUX.ActiveTextColor + titleLabel.numberOfLines = 2 + titleLabel.snp.makeConstraints { (make) -> Void in + make.top.equalTo(self.contentView).offset(ReadingListTableViewCellUX.TitleLabelTopOffset) + make.leading.equalTo(self.contentView).offset(ReadingListTableViewCellUX.TitleLabelLeftOffset) + make.trailing.equalTo(self.contentView).offset(ReadingListTableViewCellUX.TitleLabelRightOffset) // TODO Not clear from ux spec + make.bottom.lessThanOrEqualTo(hostnameLabel.snp.top).priority(1000) + } + + hostnameLabel.textColor = ReadingListTableViewCellUX.ActiveTextColor + hostnameLabel.numberOfLines = 1 + hostnameLabel.snp.makeConstraints { (make) -> Void in + make.bottom.equalTo(self.contentView).offset(-ReadingListTableViewCellUX.HostnameLabelBottomOffset) + make.leading.trailing.equalTo(self.titleLabel) + } + + setupDynamicFonts() + } + + func setupDynamicFonts() { + titleLabel.font = DynamicFontHelper.defaultHelper.DeviceFont + hostnameLabel.font = DynamicFontHelper.defaultHelper.DeviceFontSmallLight + } + + override func prepareForReuse() { + super.prepareForReuse() + setupDynamicFonts() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + let prefixesToSimplify = ["www.", "mobile.", "m.", "blog."] + + fileprivate func simplifiedHostnameFromURL(_ url: URL) -> String { + let hostname = url.host ?? "" + for prefix in prefixesToSimplify { + if hostname.hasPrefix(prefix) { + return hostname.substring(from: hostname.characters.index(hostname.startIndex, offsetBy: prefix.characters.count)) + } + } + return hostname + } + + fileprivate func updateAccessibilityLabel() { + if let hostname = hostnameLabel.text, + let title = titleLabel.text { + let unreadStatus = unread ? NSLocalizedString("unread", comment: "Accessibility label for unread article in reading list. It's a past participle - functions as an adjective.") : NSLocalizedString("read", comment: "Accessibility label for read article in reading list. It's a past participle - functions as an adjective.") + let string = "\(title), \(unreadStatus), \(hostname)" + var label: AnyObject + if !unread { + // mimic light gray visual dimming by "dimming" the speech by reducing pitch + let lowerPitchString = NSMutableAttributedString(string: string as String) + lowerPitchString.addAttribute(UIAccessibilitySpeechAttributePitch, value: NSNumber(value: ReadingListTableViewCellUX.ReadAccessibilitySpeechPitch as Float), range: NSRange(location: 0, length: lowerPitchString.length)) + label = NSAttributedString(attributedString: lowerPitchString) + } else { + label = string as AnyObject + } + // need to use KVC as accessibilityLabel is of type String! and cannot be set to NSAttributedString other way than this + // see bottom of page 121 of the PDF slides of WWDC 2012 "Accessibility for iOS" session for indication that this is OK by Apple + // also this combined with Swift's strictness is why we cannot simply override accessibilityLabel and return the label directly... + setValue(label, forKey: "accessibilityLabel") + } + } +} + +class ReadingListPanel: UITableViewController, HomePanel { + weak var homePanelDelegate: HomePanelDelegate? + var profile: Profile! + + fileprivate lazy var longPressRecognizer: UILongPressGestureRecognizer = { + return UILongPressGestureRecognizer(target: self, action: #selector(ReadingListPanel.longPress(_:))) + }() + + fileprivate lazy var emptyStateOverlayView: UIView = self.createEmptyStateOverview() + + fileprivate var records: [ReadingListClientRecord]? + + init() { + super.init(nibName: nil, bundle: nil) + NotificationCenter.default.addObserver(self, selector: #selector(ReadingListPanel.notificationReceived(_:)), name: NotificationFirefoxAccountChanged, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(ReadingListPanel.notificationReceived(_:)), name: NotificationDynamicFontChanged, object: nil) + } + + required init!(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.addGestureRecognizer(longPressRecognizer) + tableView.accessibilityIdentifier = "ReadingTable" + tableView.estimatedRowHeight = ReadingListTableViewCellUX.RowHeight + tableView.rowHeight = UITableViewAutomaticDimension + tableView.cellLayoutMarginsFollowReadableWidth = false + tableView.separatorInset = UIEdgeInsets.zero + tableView.layoutMargins = UIEdgeInsets.zero + tableView.separatorColor = UIConstants.SeparatorColor + tableView.register(ReadingListTableViewCell.self, forCellReuseIdentifier: "ReadingListTableViewCell") + + // Set an empty footer to prevent empty cells from appearing in the list. + tableView.tableFooterView = UIView() + + view.backgroundColor = UIConstants.PanelBackgroundColor + + if let result = profile.readingList?.getAvailableRecords(), result.isSuccess { + records = result.successValue + + // If no records have been added yet, we display the empty state + if records?.count == 0 { + tableView.isScrollEnabled = false + view.addSubview(emptyStateOverlayView) + + } + } + } + + func notificationReceived(_ notification: Notification) { + switch notification.name { + case NotificationFirefoxAccountChanged: + refreshReadingList() + break + case NotificationDynamicFontChanged: + if emptyStateOverlayView.superview != nil { + emptyStateOverlayView.removeFromSuperview() + } + emptyStateOverlayView = createEmptyStateOverview() + refreshReadingList() + break + default: + // no need to do anything at all + log.warning("Received unexpected notification \(notification.name)") + break + } + } + + func refreshReadingList() { + let prevNumberOfRecords = records?.count + if let result = profile.readingList?.getAvailableRecords(), result.isSuccess { + records = result.successValue + + if records?.count == 0 { + tableView.isScrollEnabled = false + if emptyStateOverlayView.superview == nil { + view.addSubview(emptyStateOverlayView) + } + } else { + if prevNumberOfRecords == 0 { + tableView.isScrollEnabled = true + emptyStateOverlayView.removeFromSuperview() + } + } + self.tableView.reloadData() + } + } + + fileprivate func createEmptyStateOverview() -> UIView { + let overlayView = UIScrollView(frame: tableView.bounds) + overlayView.backgroundColor = UIColor.white + // Unknown why this does not work with autolayout + overlayView.autoresizingMask = [UIViewAutoresizing.flexibleHeight, UIViewAutoresizing.flexibleWidth] + + let containerView = UIView() + overlayView.addSubview(containerView) + + let welcomeLabel = UILabel() + containerView.addSubview(welcomeLabel) + welcomeLabel.text = NSLocalizedString("Welcome to your Reading List", comment: "See http://mzl.la/1LXbDOL") + welcomeLabel.textAlignment = NSTextAlignment.center + welcomeLabel.font = DynamicFontHelper.defaultHelper.DeviceFontSmallBold + welcomeLabel.textColor = ReadingListPanelUX.WelcomeScreenHeaderTextColor + welcomeLabel.adjustsFontSizeToFitWidth = true + welcomeLabel.snp.makeConstraints { make in + make.centerX.equalTo(containerView) + make.width.equalTo(ReadingListPanelUX.WelcomeScreenItemWidth + ReadingListPanelUX.WelcomeScreenCircleSpacer + ReadingListPanelUX.WelcomeScreenCircleWidth) + make.top.equalTo(containerView) + // Sets proper center constraint for iPhones in landscape. + make.centerY.lessThanOrEqualTo(overlayView.snp.centerY).offset(-40).priority(1000) + } + + let readerModeLabel = UILabel() + containerView.addSubview(readerModeLabel) + readerModeLabel.text = NSLocalizedString("Open articles in Reader View by tapping the book icon when it appears in the title bar.", comment: "See http://mzl.la/1LXbDOL") + readerModeLabel.font = DynamicFontHelper.defaultHelper.DeviceFontSmallLight + readerModeLabel.textColor = ReadingListPanelUX.WelcomeScreenItemTextColor + readerModeLabel.numberOfLines = 0 + readerModeLabel.snp.makeConstraints { make in + make.top.equalTo(welcomeLabel.snp.bottom).offset(ReadingListPanelUX.WelcomeScreenPadding) + make.leading.equalTo(welcomeLabel.snp.leading) + make.width.equalTo(ReadingListPanelUX.WelcomeScreenItemWidth) + } + + let readerModeImageView = UIImageView(image: UIImage(named: "ReaderModeCircle")) + containerView.addSubview(readerModeImageView) + readerModeImageView.snp.makeConstraints { make in + make.centerY.equalTo(readerModeLabel) + make.trailing.equalTo(welcomeLabel.snp.trailing) + } + + let readingListLabel = UILabel() + containerView.addSubview(readingListLabel) + readingListLabel.text = NSLocalizedString("Save pages to your Reading List by tapping the book plus icon in the Reader View controls.", comment: "See http://mzl.la/1LXbDOL") + readingListLabel.font = DynamicFontHelper.defaultHelper.DeviceFontSmallLight + readingListLabel.textColor = ReadingListPanelUX.WelcomeScreenItemTextColor + readingListLabel.numberOfLines = 0 + readingListLabel.snp.makeConstraints { make in + make.top.equalTo(readerModeLabel.snp.bottom).offset(ReadingListPanelUX.WelcomeScreenPadding) + make.leading.equalTo(welcomeLabel.snp.leading) + make.width.equalTo(ReadingListPanelUX.WelcomeScreenItemWidth) + make.bottom.equalTo(overlayView).offset(-20) // making AutoLayout compute the overlayView's contentSize + } + + let readingListImageView = UIImageView(image: UIImage(named: "AddToReadingListCircle")) + containerView.addSubview(readingListImageView) + readingListImageView.snp.makeConstraints { make in + make.centerY.equalTo(readingListLabel) + make.trailing.equalTo(welcomeLabel.snp.trailing) + } + + containerView.snp.makeConstraints { make in + // Let the container wrap around the content + make.left.equalTo(welcomeLabel).offset(ReadingListPanelUX.WelcomeScreenItemOffset) + make.right.equalTo(welcomeLabel).offset(ReadingListPanelUX.WelcomeScreenCircleOffset) + + // And then center it in the overlay view that sits on top of the UITableView + make.centerX.equalTo(overlayView) + } + + return overlayView + } + + @objc fileprivate func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) { + guard longPressGestureRecognizer.state == UIGestureRecognizerState.began else { return } + let touchPoint = longPressGestureRecognizer.location(in: tableView) + guard let indexPath = tableView.indexPathForRow(at: touchPoint) else { return } + presentContextMenu(for: indexPath) + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return records?.count ?? 0 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "ReadingListTableViewCell", for: indexPath) as! ReadingListTableViewCell + if let record = records?[indexPath.row] { + cell.title = record.title + cell.url = URL(string: record.url)! + cell.unread = record.unread + } + return cell + } + + override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { + guard let record = records?[indexPath.row] else { + return [] + } + + let delete = UITableViewRowAction(style: .normal, title: ReadingListTableViewCellUX.DeleteButtonTitleText) { [weak self] action, index in + self?.deleteItem(atIndex: index) + } + delete.backgroundColor = ReadingListTableViewCellUX.DeleteButtonBackgroundColor + + let toggleText = record.unread ? ReadingListTableViewCellUX.MarkAsReadButtonTitleText : ReadingListTableViewCellUX.MarkAsUnreadButtonTitleText + let unreadToggle = UITableViewRowAction(style: .normal, title: toggleText.stringSplitWithNewline()) { [weak self] (action, index) in + self?.toggleItem(atIndex: index) + } + unreadToggle.backgroundColor = ReadingListTableViewCellUX.MarkAsReadButtonBackgroundColor + + return [unreadToggle, delete] + } + + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + // the cells you would like the actions to appear needs to be editable + return true + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: false) + if let record = records?[indexPath.row], let url = URL(string: record.url), let encodedURL = url.encodeReaderModeURL(WebServer.sharedInstance.baseReaderModeURL()) { + // Mark the item as read + profile.readingList?.updateRecord(record, unread: false) + // Reading list items are closest in concept to bookmarks. + let visitType = VisitType.bookmark + homePanelDelegate?.homePanel(self, didSelectURL: encodedURL, visitType: visitType) + UnifiedTelemetry.recordEvent(category: .action, method: .open, object: .readingListItem) + } + } + + fileprivate func deleteItem(atIndex indexPath: IndexPath) { + if let record = records?[indexPath.row] { + UnifiedTelemetry.recordEvent(category: .action, method: .delete, object: .readingListItem, value: .readingListPanel) + if let result = profile.readingList?.deleteRecord(record), result.isSuccess { + records?.remove(at: indexPath.row) + tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic) + // reshow empty state if no records left + if records?.count == 0 { + view.addSubview(emptyStateOverlayView) + } + } + } + } + + fileprivate func toggleItem(atIndex indexPath: IndexPath) { + if let record = records?[indexPath.row] { + UnifiedTelemetry.recordEvent(category: .action, method: .tap, object: .readingListItem, value: !record.unread ? .markAsUnread : .markAsRead, extras: [ "from": "reading-list-panel" ]) + if let result = profile.readingList?.updateRecord(record, unread: !record.unread), result.isSuccess { + // TODO This is a bit odd because the success value of the update is an optional optional Record + if let successValue = result.successValue, let updatedRecord = successValue { + records?[indexPath.row] = updatedRecord + tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic) + } + } + } + } +} + +extension ReadingListPanel: HomePanelContextMenu { + func presentContextMenu(for site: Site, with indexPath: IndexPath, completionHandler: @escaping () -> PhotonActionSheet?) { + guard let contextMenu = completionHandler() else { return } + self.present(contextMenu, animated: true, completion: nil) + } + + func getSiteDetails(for indexPath: IndexPath) -> Site? { + guard let record = records?[indexPath.row] else { return nil } + return Site(url: record.url, title: record.title) + } + + func getContextMenuActions(for site: Site, with indexPath: IndexPath) -> [PhotonActionSheetItem]? { + guard var actions = getDefaultContextMenuActions(for: site, homePanelDelegate: homePanelDelegate) else { return nil } + + let removeAction: PhotonActionSheetItem = PhotonActionSheetItem(title: Strings.RemoveContextMenuTitle, iconString: "action_remove", handler: { action in + self.deleteItem(atIndex: indexPath) + }) + + actions.append(removeAction) + return actions + } +} diff --git a/mobile/ios/Client/Frontend/Home/RecentlyClosedTabsPanel.swift b/mobile/ios/Client/Frontend/Home/RecentlyClosedTabsPanel.swift new file mode 100644 index 0000000000..9dd027d60c --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/RecentlyClosedTabsPanel.swift @@ -0,0 +1,178 @@ +/* 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/. */ + +import UIKit + +import Shared +import Storage +import XCGLogger +import Deferred + +private let log = Logger.browserLogger + +struct RecentlyClosedPanelUX { + static let IconSize = CGSize(width: 23, height: 23) + static let IconBorderColor = UIColor(white: 0, alpha: 0.1) + static let IconBorderWidth: CGFloat = 0.5 +} + +class RecentlyClosedTabsPanel: UIViewController, HomePanel { + weak var homePanelDelegate: HomePanelDelegate? + var profile: Profile! + + fileprivate lazy var recentlyClosedHeader: UILabel = { + let headerLabel = UILabel() + headerLabel.text = Strings.RecentlyClosedTabsPanelTitle + headerLabel.font = DynamicFontHelper.defaultHelper.DeviceFontHistoryPanel + headerLabel.textAlignment = .center + headerLabel.backgroundColor = .white + return headerLabel + }() + + fileprivate var tableViewController = RecentlyClosedTabsPanelSiteTableViewController() + + fileprivate lazy var historyBackButton: HistoryBackButton = { + let button = HistoryBackButton() + button.addTarget(self, action: #selector(RecentlyClosedTabsPanel.historyBackButtonWasTapped), for: .touchUpInside) + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .white + + tableViewController.profile = self.profile + tableViewController.homePanelDelegate = homePanelDelegate + tableViewController.recentlyClosedTabsPanel = self + + self.addChildViewController(tableViewController) + self.view.addSubview(tableViewController.view) + self.view.addSubview(historyBackButton) + self.view.addSubview(recentlyClosedHeader) + + historyBackButton.snp.makeConstraints { make in + make.top.left.right.equalTo(self.view) + make.height.equalTo(50) + make.bottom.equalTo(recentlyClosedHeader.snp.top) + } + + recentlyClosedHeader.snp.makeConstraints { make in + make.top.equalTo(historyBackButton.snp.bottom) + make.height.equalTo(20) + make.bottom.equalTo(tableViewController.view.snp.top).offset(-10) + make.left.right.equalTo(self.view) + } + + tableViewController.view.snp.makeConstraints { make in + make.left.right.bottom.equalTo(self.view) + } + + tableViewController.didMove(toParentViewController: self) + } + + @objc fileprivate func historyBackButtonWasTapped(_ gestureRecognizer: UITapGestureRecognizer) { + _ = self.navigationController?.popViewController(animated: true) + } + +} + +class RecentlyClosedTabsPanelSiteTableViewController: SiteTableViewController { + weak var homePanelDelegate: HomePanelDelegate? + var recentlyClosedTabs: [ClosedTab] = [] + weak var recentlyClosedTabsPanel: RecentlyClosedTabsPanel? + + fileprivate lazy var longPressRecognizer: UILongPressGestureRecognizer = { + return UILongPressGestureRecognizer(target: self, action: #selector(RecentlyClosedTabsPanelSiteTableViewController.longPress(_:))) + }() + + init() { + super.init(nibName: nil, bundle: nil) + } + + override func viewDidLoad() { + super.viewDidLoad() + tableView.addGestureRecognizer(longPressRecognizer) + tableView.accessibilityIdentifier = "Recently Closed Tabs List" + self.recentlyClosedTabs = profile.recentlyClosedTabs.tabs + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc fileprivate func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) { + guard longPressGestureRecognizer.state == UIGestureRecognizerState.began else { return } + let touchPoint = longPressGestureRecognizer.location(in: tableView) + guard let indexPath = tableView.indexPathForRow(at: touchPoint) else { return } + presentContextMenu(for: indexPath) + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = super.tableView(tableView, cellForRowAt: indexPath) + guard let twoLineCell = cell as? TwoLineTableViewCell else { + return cell + } + let tab = recentlyClosedTabs[indexPath.row] + let displayURL = tab.url.displayURL ?? tab.url + twoLineCell.setLines(tab.title, detailText: displayURL.absoluteDisplayString) + let site: Favicon? = (tab.faviconURL != nil) ? Favicon(url: tab.faviconURL!, type: .guess) : nil + cell.imageView!.layer.borderColor = RecentlyClosedPanelUX.IconBorderColor.cgColor + cell.imageView!.layer.borderWidth = RecentlyClosedPanelUX.IconBorderWidth + cell.imageView?.setIcon(site, forURL: displayURL, completed: { (color, url) in + if url == displayURL { + cell.imageView?.image = cell.imageView?.image?.createScaled(RecentlyClosedPanelUX.IconSize) + cell.imageView?.contentMode = .center + cell.imageView?.backgroundColor = color + } + }) + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) { + guard let homePanelDelegate = homePanelDelegate, + let recentlyClosedTabsPanel = recentlyClosedTabsPanel else { + log.warning("No site or no URL when selecting row.") + return + } + let visitType = VisitType.typed // Means History, too. + homePanelDelegate.homePanel(recentlyClosedTabsPanel, didSelectURL: recentlyClosedTabs[indexPath.row].url, visitType: visitType) + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 0 + } + + // Functions that deal with showing header rows. + func numberOfSectionsInTableView(_ tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return profile.recentlyClosedTabs.tabs.count + } + +} + +extension RecentlyClosedTabsPanelSiteTableViewController: HomePanelContextMenu { + func presentContextMenu(for site: Site, with indexPath: IndexPath, completionHandler: @escaping () -> PhotonActionSheet?) { + guard let contextMenu = completionHandler() else { return } + self.present(contextMenu, animated: true, completion: nil) + } + + func getSiteDetails(for indexPath: IndexPath) -> Site? { + let closedTab = recentlyClosedTabs[indexPath.row] + let site: Site + if let title = closedTab.title { + site = Site(url: String(describing: closedTab.url), title: title) + } else { + site = Site(url: String(describing: closedTab.url), title: "") + } + return site + } + + func getContextMenuActions(for site: Site, with indexPath: IndexPath) -> [PhotonActionSheetItem]? { + return getDefaultContextMenuActions(for: site, homePanelDelegate: homePanelDelegate) + } +} diff --git a/mobile/ios/Client/Frontend/Home/RemoteTabsPanel.swift b/mobile/ios/Client/Frontend/Home/RemoteTabsPanel.swift new file mode 100644 index 0000000000..da37a4fa8b --- /dev/null +++ b/mobile/ios/Client/Frontend/Home/RemoteTabsPanel.swift @@ -0,0 +1,610 @@ +/* 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/. */ + +import UIKit +import Account +import Shared +import SnapKit +import Storage +import Sync +import XCGLogger + +private let log = Logger.browserLogger + +private struct RemoteTabsPanelUX { + static let HeaderHeight = SiteTableViewControllerUX.RowHeight // Not HeaderHeight! + static let RowHeight = SiteTableViewControllerUX.RowHeight + static let HeaderBackgroundColor = UIColor(rgb: 0xf8f8f8) + + static let EmptyStateTitleTextColor = UIColor.darkGray + + static let EmptyStateInstructionsTextColor = UIColor.gray + static let EmptyStateInstructionsWidth = 170 + static let EmptyStateTopPaddingInBetweenItems: CGFloat = 15 // UX TODO I set this to 8 so that it all fits on landscape + static let EmptyStateSignInButtonColor = UIColor(red: 0.3, green: 0.62, blue: 1, alpha: 1) + static let EmptyStateSignInButtonTitleColor = UIColor.white + static let EmptyStateSignInButtonCornerRadius: CGFloat = 4 + static let EmptyStateSignInButtonHeight = 44 + static let EmptyStateSignInButtonWidth = 200 + + // Backup and active strings added in Bug 1205294. + static let EmptyStateInstructionsSyncTabsPasswordsBookmarksString = NSLocalizedString("Sync your tabs, bookmarks, passwords and more.", comment: "Text displayed when the Sync home panel is empty, describing the features provided by Sync to invite the user to log in.") + + static let EmptyStateInstructionsSyncTabsPasswordsString = NSLocalizedString("Sync your tabs, passwords and more.", comment: "Text displayed when the Sync home panel is empty, describing the features provided by Sync to invite the user to log in.") + + static let EmptyStateInstructionsGetTabsBookmarksPasswordsString = NSLocalizedString("Get your open tabs, bookmarks, and passwords from your other devices.", comment: "A re-worded offer about Sync, displayed when the Sync home panel is empty, that emphasizes one-way data transfer, not syncing.") + + static let HistoryTableViewHeaderChevronInset: CGFloat = 10 + static let HistoryTableViewHeaderChevronSize: CGFloat = 20 + static let HistoryTableViewHeaderChevronLineWidth: CGFloat = 3.0 +} + +private let RemoteClientIdentifier = "RemoteClient" +private let RemoteTabIdentifier = "RemoteTab" + +class RemoteTabsPanel: UIViewController, HomePanel { + weak var homePanelDelegate: HomePanelDelegate? + fileprivate lazy var tableViewController: RemoteTabsTableViewController = RemoteTabsTableViewController() + fileprivate lazy var historyBackButton: HistoryBackButton = { + let button = HistoryBackButton() + button.addTarget(self, action: #selector(RemoteTabsPanel.historyBackButtonWasTapped), for: .touchUpInside) + return button + }() + var profile: Profile! + + init() { + super.init(nibName: nil, bundle: nil) + NotificationCenter.default.addObserver(self, selector: #selector(RemoteTabsPanel.notificationReceived(_:)), name: NotificationFirefoxAccountChanged, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(RemoteTabsPanel.notificationReceived(_:)), name: NotificationProfileDidFinishSyncing, object: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + tableViewController.profile = profile + tableViewController.remoteTabsPanel = self + + view.backgroundColor = UIConstants.PanelBackgroundColor + + addChildViewController(tableViewController) + self.view.addSubview(tableViewController.view) + self.view.addSubview(historyBackButton) + + historyBackButton.snp.makeConstraints { make in + make.top.left.right.equalTo(self.view) + make.height.equalTo(50) + make.bottom.equalTo(tableViewController.view.snp.top) + } + + tableViewController.view.snp.makeConstraints { make in + make.top.equalTo(historyBackButton.snp.bottom) + make.left.right.bottom.equalTo(self.view) + } + + tableViewController.didMove(toParentViewController: self) + } + + func notificationReceived(_ notification: Notification) { + switch notification.name { + case NotificationFirefoxAccountChanged, NotificationProfileDidFinishSyncing: + DispatchQueue.main.async { + print(notification.name) + self.tableViewController.refreshTabs() + } + break + default: + // no need to do anything at all + log.warning("Received unexpected notification \(notification.name)") + break + } + } + + @objc fileprivate func historyBackButtonWasTapped(_ gestureRecognizer: UITapGestureRecognizer) { + _ = self.navigationController?.popViewController(animated: true) + } +} + +enum RemoteTabsError { + case notLoggedIn + case noClients + case noTabs + case failedToSync + + func localizedString() -> String { + switch self { + case .notLoggedIn: + return "" // This does not have a localized string because we have a whole specific screen for it. + case .noClients: + return Strings.EmptySyncedTabsPanelNullStateDescription + case .noTabs: + return NSLocalizedString("You don’t have any tabs open in Firefox on your other devices.", comment: "Error message in the remote tabs panel") + case .failedToSync: + return NSLocalizedString("There was a problem accessing tabs from your other devices. Try again in a few moments.", comment: "Error message in the remote tabs panel") + } + } +} + +protocol RemoteTabsPanelDataSource: UITableViewDataSource, UITableViewDelegate { +} + +class RemoteTabsPanelClientAndTabsDataSource: NSObject, RemoteTabsPanelDataSource { + weak var homePanel: HomePanel? + fileprivate var clientAndTabs: [ClientAndTabs] + + init(homePanel: HomePanel, clientAndTabs: [ClientAndTabs]) { + self.homePanel = homePanel + self.clientAndTabs = clientAndTabs + } + + func numberOfSections(in tableView: UITableView) -> Int { + return self.clientAndTabs.count + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return self.clientAndTabs[section].tabs.count + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return RemoteTabsPanelUX.HeaderHeight + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let clientTabs = self.clientAndTabs[section] + let client = clientTabs.client + let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: RemoteClientIdentifier) as! TwoLineHeaderFooterView + view.frame = CGRect(x: 0, y: 0, width: tableView.frame.width, height: RemoteTabsPanelUX.HeaderHeight) + view.textLabel?.text = client.name + view.contentView.backgroundColor = RemoteTabsPanelUX.HeaderBackgroundColor + + /* + * A note on timestamps. + * We have access to two timestamps here: the timestamp of the remote client record, + * and the set of timestamps of the client's tabs. + * Neither is "last synced". The client record timestamp changes whenever the remote + * client uploads its record (i.e., infrequently), but also whenever another device + * sends a command to that client -- which can be much later than when that client + * last synced. + * The client's tabs haven't necessarily changed, but it can still have synced. + * Ideally, we should save and use the modified time of the tabs record itself. + * This will be the real time that the other client uploaded tabs. + */ + + let timestamp = clientTabs.approximateLastSyncTime() + let label = NSLocalizedString("Last synced: %@", comment: "Remote tabs last synced time. Argument is the relative date string.") + view.detailTextLabel?.text = String(format: label, Date.fromTimestamp(timestamp).toRelativeTimeString()) + + let image: UIImage? + if client.type == "desktop" { + image = UIImage(named: "deviceTypeDesktop") + image?.accessibilityLabel = NSLocalizedString("computer", comment: "Accessibility label for Desktop Computer (PC) image in remote tabs list") + } else { + image = UIImage(named: "deviceTypeMobile") + image?.accessibilityLabel = NSLocalizedString("mobile device", comment: "Accessibility label for Mobile Device image in remote tabs list") + } + view.imageView.image = image + + view.mergeAccessibilityLabels() + return view + } + + fileprivate func tabAtIndexPath(_ indexPath: IndexPath) -> RemoteTab { + return clientAndTabs[indexPath.section].tabs[indexPath.item] + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: RemoteTabIdentifier, for: indexPath) as! TwoLineTableViewCell + let tab = tabAtIndexPath(indexPath) + cell.setLines(tab.title, detailText: tab.URL.absoluteString) + // TODO: Bug 1144765 - Populate image with cached favicons. + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: false) + let tab = tabAtIndexPath(indexPath) + if let homePanel = self.homePanel { + // It's not a bookmark, so let's call it Typed (which means History, too). + homePanel.homePanelDelegate?.homePanel(homePanel, didSelectURL: tab.URL, visitType: VisitType.typed) + } + } +} + +// MARK: - + +class RemoteTabsPanelErrorDataSource: NSObject, RemoteTabsPanelDataSource { + weak var homePanel: HomePanel? + var error: RemoteTabsError + var notLoggedCell: UITableViewCell? + + init(homePanel: HomePanel, error: RemoteTabsError) { + self.homePanel = homePanel + self.error = error + self.notLoggedCell = nil + } + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + if let cell = self.notLoggedCell { + cell.updateConstraints() + } + return tableView.bounds.height + } + + func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + // Making the footer height as small as possible because it will disable button tappability if too high. + return 1 + } + + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + return UIView() + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + switch error { + case .notLoggedIn: + let cell = RemoteTabsNotLoggedInCell(homePanel: homePanel) + self.notLoggedCell = cell + return cell + default: + let cell = RemoteTabsErrorCell(error: self.error) + self.notLoggedCell = nil + return cell + } + } + +} + +// MARK: - + +class RemoteTabsErrorCell: UITableViewCell { + static let Identifier = "RemoteTabsErrorCell" + + init(error: RemoteTabsError) { + super.init(style: .default, reuseIdentifier: RemoteTabsErrorCell.Identifier) + + separatorInset = UIEdgeInsets(top: 0, left: 1000, bottom: 0, right: 0) + + let containerView = UIView() + contentView.addSubview(containerView) + + let imageView = UIImageView() + imageView.image = UIImage(named: "emptySync") + containerView.addSubview(imageView) + imageView.snp.makeConstraints { (make) -> Void in + make.top.equalTo(containerView) + make.centerX.equalTo(containerView) + } + + let titleLabel = UILabel() + titleLabel.font = DynamicFontHelper.defaultHelper.DeviceFont + titleLabel.text = Strings.EmptySyncedTabsPanelStateTitle + titleLabel.textAlignment = NSTextAlignment.center + titleLabel.textColor = RemoteTabsPanelUX.EmptyStateTitleTextColor + containerView.addSubview(titleLabel) + + let instructionsLabel = UILabel() + instructionsLabel.font = DynamicFontHelper.defaultHelper.DeviceFontSmallLight + instructionsLabel.text = error.localizedString() + instructionsLabel.textAlignment = NSTextAlignment.center + instructionsLabel.textColor = RemoteTabsPanelUX.EmptyStateInstructionsTextColor + instructionsLabel.numberOfLines = 0 + containerView.addSubview(instructionsLabel) + + titleLabel.snp.makeConstraints { make in + make.top.equalTo(imageView.snp.bottom).offset(RemoteTabsPanelUX.EmptyStateTopPaddingInBetweenItems) + make.centerX.equalTo(imageView) + } + + instructionsLabel.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(RemoteTabsPanelUX.EmptyStateTopPaddingInBetweenItems / 2) + make.centerX.equalTo(containerView) + make.width.equalTo(RemoteTabsPanelUX.EmptyStateInstructionsWidth) + } + + containerView.snp.makeConstraints { make in + // Let the container wrap around the content + make.top.equalTo(imageView.snp.top) + make.left.bottom.right.equalTo(instructionsLabel) + // And then center it in the overlay view that sits on top of the UITableView + make.centerX.equalTo(contentView) + + // Sets proper top constraint for iPhone 6 in portait and for iPad. + make.centerY.equalTo(contentView.snp.centerY).offset(HomePanelUX.EmptyTabContentOffset).priority(100) + + // Sets proper top constraint for iPhone 4, 5 in portrait. + make.top.greaterThanOrEqualTo(contentView.snp.top).offset(20).priority(1000) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - + +class RemoteTabsNotLoggedInCell: UITableViewCell { + static let Identifier = "RemoteTabsNotLoggedInCell" + var homePanel: HomePanel? + var instructionsLabel: UILabel + var signInButton: UIButton + var titleLabel: UILabel + var emptyStateImageView: UIImageView + + init(homePanel: HomePanel?) { + let titleLabel = UILabel() + let instructionsLabel = UILabel() + let signInButton = UIButton() + let imageView = UIImageView() + + self.instructionsLabel = instructionsLabel + self.signInButton = signInButton + self.titleLabel = titleLabel + self.emptyStateImageView = imageView + + super.init(style: .default, reuseIdentifier: RemoteTabsErrorCell.Identifier) + + self.homePanel = homePanel + let createAnAccountButton = UIButton(type: .system) + + imageView.image = UIImage(named: "emptySync") + contentView.addSubview(imageView) + + titleLabel.font = DynamicFontHelper.defaultHelper.DeviceFont + titleLabel.text = Strings.EmptySyncedTabsPanelStateTitle + titleLabel.textAlignment = NSTextAlignment.center + titleLabel.textColor = RemoteTabsPanelUX.EmptyStateTitleTextColor + contentView.addSubview(titleLabel) + + instructionsLabel.font = DynamicFontHelper.defaultHelper.DeviceFontSmallLight + instructionsLabel.text = Strings.EmptySyncedTabsPanelStateDescription + instructionsLabel.textAlignment = NSTextAlignment.center + instructionsLabel.textColor = RemoteTabsPanelUX.EmptyStateInstructionsTextColor + instructionsLabel.numberOfLines = 0 + contentView.addSubview(instructionsLabel) + + signInButton.backgroundColor = RemoteTabsPanelUX.EmptyStateSignInButtonColor + signInButton.setTitle(NSLocalizedString("Sign in", comment: "See http://mzl.la/1Qtkf0j"), for: UIControlState()) + signInButton.setTitleColor(RemoteTabsPanelUX.EmptyStateSignInButtonTitleColor, for: UIControlState()) + signInButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.subheadline) + signInButton.layer.cornerRadius = RemoteTabsPanelUX.EmptyStateSignInButtonCornerRadius + signInButton.clipsToBounds = true + signInButton.addTarget(self, action: #selector(RemoteTabsNotLoggedInCell.SELsignIn), for: UIControlEvents.touchUpInside) + contentView.addSubview(signInButton) + + createAnAccountButton.setTitle(NSLocalizedString("Create an account", comment: "See http://mzl.la/1Qtkf0j"), for: UIControlState()) + createAnAccountButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.caption1) + createAnAccountButton.addTarget(self, action: #selector(RemoteTabsNotLoggedInCell.SELcreateAnAccount), for: UIControlEvents.touchUpInside) + contentView.addSubview(createAnAccountButton) + + imageView.snp.makeConstraints { (make) -> Void in + make.centerX.equalTo(instructionsLabel) + + // Sets proper top constraint for iPhone 6 in portait and for iPad. + make.centerY.equalTo(contentView).offset(HomePanelUX.EmptyTabContentOffset + 30).priority(100) + + // Sets proper top constraint for iPhone 4, 5 in portrait. + make.top.greaterThanOrEqualTo(contentView.snp.top).priority(1000) + } + + titleLabel.snp.makeConstraints { make in + make.top.equalTo(imageView.snp.bottom).offset(RemoteTabsPanelUX.EmptyStateTopPaddingInBetweenItems) + make.centerX.equalTo(imageView) + } + + createAnAccountButton.snp.makeConstraints { (make) -> Void in + make.centerX.equalTo(signInButton) + make.top.equalTo(signInButton.snp.bottom).offset(RemoteTabsPanelUX.EmptyStateTopPaddingInBetweenItems) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc fileprivate func SELsignIn() { + if let homePanel = self.homePanel { + homePanel.homePanelDelegate?.homePanelDidRequestToSignIn(homePanel) + } + } + + @objc fileprivate func SELcreateAnAccount() { + if let homePanel = self.homePanel { + homePanel.homePanelDelegate?.homePanelDidRequestToCreateAccount(homePanel) + } + } + + override func updateConstraints() { + if UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation) && !(DeviceInfo.deviceModel().range(of: "iPad") != nil) { + instructionsLabel.snp.remakeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(RemoteTabsPanelUX.EmptyStateTopPaddingInBetweenItems) + make.width.equalTo(RemoteTabsPanelUX.EmptyStateInstructionsWidth) + + // Sets proper landscape layout for bigger phones: iPhone 6 and on. + make.left.lessThanOrEqualTo(contentView.snp.left).offset(80).priority(100) + + // Sets proper landscape layout for smaller phones: iPhone 4 & 5. + make.right.lessThanOrEqualTo(contentView.snp.centerX).offset(-30).priority(1000) + } + + signInButton.snp.remakeConstraints { make in + make.height.equalTo(RemoteTabsPanelUX.EmptyStateSignInButtonHeight) + make.width.equalTo(RemoteTabsPanelUX.EmptyStateSignInButtonWidth) + make.centerY.equalTo(emptyStateImageView).offset(2*RemoteTabsPanelUX.EmptyStateTopPaddingInBetweenItems) + + // Sets proper landscape layout for bigger phones: iPhone 6 and on. + make.right.greaterThanOrEqualTo(contentView.snp.right).offset(-70).priority(100) + + // Sets proper landscape layout for smaller phones: iPhone 4 & 5. + make.left.greaterThanOrEqualTo(contentView.snp.centerX).offset(10).priority(1000) + } + } else { + instructionsLabel.snp.remakeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(RemoteTabsPanelUX.EmptyStateTopPaddingInBetweenItems) + make.centerX.equalTo(contentView) + make.width.equalTo(RemoteTabsPanelUX.EmptyStateInstructionsWidth) + } + + signInButton.snp.remakeConstraints { make in + make.centerX.equalTo(contentView) + make.top.equalTo(instructionsLabel.snp.bottom).offset(RemoteTabsPanelUX.EmptyStateTopPaddingInBetweenItems) + make.height.equalTo(RemoteTabsPanelUX.EmptyStateSignInButtonHeight) + make.width.equalTo(RemoteTabsPanelUX.EmptyStateSignInButtonWidth) + } + } + super.updateConstraints() + } +} + +fileprivate class RemoteTabsTableViewController: UITableViewController { + weak var remoteTabsPanel: RemoteTabsPanel? + var profile: Profile! + var tableViewDelegate: RemoteTabsPanelDataSource? { + didSet { + tableView.dataSource = tableViewDelegate + tableView.delegate = tableViewDelegate + } + } + + fileprivate lazy var longPressRecognizer: UILongPressGestureRecognizer = { + return UILongPressGestureRecognizer(target: self, action: #selector(RemoteTabsTableViewController.longPress(_:))) + }() + + override func viewDidLoad() { + super.viewDidLoad() + tableView.addGestureRecognizer(longPressRecognizer) + tableView.register(TwoLineHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: RemoteClientIdentifier) + tableView.register(TwoLineTableViewCell.self, forCellReuseIdentifier: RemoteTabIdentifier) + + tableView.rowHeight = RemoteTabsPanelUX.RowHeight + tableView.separatorInset = UIEdgeInsets.zero + + tableView.delegate = nil + tableView.dataSource = nil + + refreshControl = UIRefreshControl() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + refreshControl?.addTarget(self, action: #selector(RemoteTabsTableViewController.refreshTabs), for: .valueChanged) + refreshTabs() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + refreshControl?.removeTarget(self, action: #selector(RemoteTabsTableViewController.refreshTabs), for: .valueChanged) + } + + fileprivate func startRefreshing() { + if let refreshControl = self.refreshControl { + let height = -refreshControl.bounds.size.height + tableView.setContentOffset(CGPoint(x: 0, y: height), animated: true) + refreshControl.beginRefreshing() + } + } + + func endRefreshing() { + if self.refreshControl?.isRefreshing ?? false { + self.refreshControl?.endRefreshing() + } + + self.tableView.isScrollEnabled = true + self.tableView.reloadData() + } + + func updateDelegateClientAndTabData(_ clientAndTabs: [ClientAndTabs]) { + guard let remoteTabsPanel = remoteTabsPanel else { return } + if clientAndTabs.count == 0 { + self.tableViewDelegate = RemoteTabsPanelErrorDataSource(homePanel: remoteTabsPanel, error: .noClients) + } else { + let nonEmptyClientAndTabs = clientAndTabs.filter { $0.tabs.count > 0 } + if nonEmptyClientAndTabs.count == 0 { + self.tableViewDelegate = RemoteTabsPanelErrorDataSource(homePanel: remoteTabsPanel, error: .noTabs) + } else { + self.tableViewDelegate = RemoteTabsPanelClientAndTabsDataSource(homePanel: remoteTabsPanel, clientAndTabs: nonEmptyClientAndTabs) + tableView.allowsSelection = true + } + } + } + + @objc fileprivate func refreshTabs() { + guard let remoteTabsPanel = remoteTabsPanel else { return } + + assert(Thread.isMainThread) + + tableView.isScrollEnabled = false + tableView.allowsSelection = false + tableView.tableFooterView = UIView(frame: CGRect.zero) + + // Short circuit if the user is not logged in + if !profile.hasSyncableAccount() { + self.tableViewDelegate = RemoteTabsPanelErrorDataSource(homePanel: remoteTabsPanel, error: .notLoggedIn) + self.endRefreshing() + return + } + + self.profile.getCachedClientsAndTabs().uponQueue(DispatchQueue.main) { result in + if let clientAndTabs = result.successValue { + self.updateDelegateClientAndTabData(clientAndTabs) + } + + // Fetch the tabs from the cloud if it has been more than 5 seconds since the last sync. + let lastSyncTime = self.profile.prefs.timestampForKey(PrefsKeys.KeyLastRemoteTabSyncTime) ?? 0 + if Date.now() > lastSyncTime && Date.now() - lastSyncTime > OneSecondInMilliseconds * 5 { + self.startRefreshing() + self.profile.getClientsAndTabs().uponQueue(DispatchQueue.main) { result in + // We set the last sync time to now, regardless of whether the sync was successful, to avoid trying to sync over + // and over again in cases whether the client is unable to sync (e.g. when there is no network connectivity). + self.profile.prefs.setTimestamp(Date.now(), forKey: PrefsKeys.KeyLastRemoteTabSyncTime) + if let clientAndTabs = result.successValue { + self.updateDelegateClientAndTabData(clientAndTabs) + } + self.endRefreshing() + } + } else { + // If we failed before and didn't sync, show the failure delegate + if let _ = result.failureValue { + self.tableViewDelegate = RemoteTabsPanelErrorDataSource(homePanel: remoteTabsPanel, error: .failedToSync) + } + + self.endRefreshing() + } + } + } + + @objc fileprivate func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) { + guard longPressGestureRecognizer.state == UIGestureRecognizerState.began else { return } + let touchPoint = longPressGestureRecognizer.location(in: tableView) + guard let indexPath = tableView.indexPathForRow(at: touchPoint) else { return } + presentContextMenu(for: indexPath) + } +} + +extension RemoteTabsTableViewController: HomePanelContextMenu { + func presentContextMenu(for site: Site, with indexPath: IndexPath, completionHandler: @escaping () -> PhotonActionSheet?) { + guard let contextMenu = completionHandler() else { return } + self.present(contextMenu, animated: true, completion: nil) + } + + func getSiteDetails(for indexPath: IndexPath) -> Site? { + guard let tab = (tableViewDelegate as? RemoteTabsPanelClientAndTabsDataSource)?.tabAtIndexPath(indexPath) else { return nil } + return Site(url: String(describing: tab.URL), title: tab.title) + } + + func getContextMenuActions(for site: Site, with indexPath: IndexPath) -> [PhotonActionSheetItem]? { + return getDefaultContextMenuActions(for: site, homePanelDelegate: remoteTabsPanel?.homePanelDelegate) + } +} diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/Contents.json b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/Contents.json b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/Contents.json new file mode 100644 index 0000000000..a60ac59d12 --- /dev/null +++ b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tour-Mail.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "tour-Mail@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "tour-Mail@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail.png new file mode 100644 index 0000000000..8acb0bd09d Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail@2x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail@2x.png new file mode 100644 index 0000000000..4e2c4a07a8 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail@2x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail@3x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail@3x.png new file mode 100644 index 0000000000..f70c072e49 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Mail.imageset/tour-Mail@3x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/Contents.json b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/Contents.json new file mode 100644 index 0000000000..4515371a3e --- /dev/null +++ b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tour-Private.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "tour-Private@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "tour-Private@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private.png new file mode 100644 index 0000000000..f69229e433 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private@2x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private@2x.png new file mode 100644 index 0000000000..866cfb568e Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private@2x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private@3x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private@3x.png new file mode 100644 index 0000000000..f1eb654812 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Private.imageset/tour-Private@3x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/Contents.json b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/Contents.json new file mode 100644 index 0000000000..13d08e5fa9 --- /dev/null +++ b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tour-Search.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "tour-Search@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "tour-Search@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search.png new file mode 100644 index 0000000000..00d93b48d8 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search@2x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search@2x.png new file mode 100644 index 0000000000..c6408bfea9 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search@2x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search@3x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search@3x.png new file mode 100644 index 0000000000..c68fb44788 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Search.imageset/tour-Search@3x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/Contents.json b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/Contents.json new file mode 100644 index 0000000000..195cc0030f --- /dev/null +++ b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tour-Sync.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "tour-Sync@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "tour-Sync@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync.png new file mode 100644 index 0000000000..9dade46278 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync@2x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync@2x.png new file mode 100644 index 0000000000..44a69fa456 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync@2x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync@3x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync@3x.png new file mode 100644 index 0000000000..4853bd12e1 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Sync.imageset/tour-Sync@3x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/Contents.json b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/Contents.json new file mode 100644 index 0000000000..cb2f3b376d --- /dev/null +++ b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tour-Welcome.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "tour-Welcome@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "tour-Welcome@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome.png new file mode 100644 index 0000000000..ca86833f8f Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome@2x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome@2x.png new file mode 100644 index 0000000000..276af880a2 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome@2x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome@3x.png b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome@3x.png new file mode 100644 index 0000000000..5c3d37dcb6 Binary files /dev/null and b/mobile/ios/Client/Frontend/Intro/Intro.xcassets/tour-Welcome.imageset/tour-Welcome@3x.png differ diff --git a/mobile/ios/Client/Frontend/Intro/IntroViewController.swift b/mobile/ios/Client/Frontend/Intro/IntroViewController.swift new file mode 100644 index 0000000000..631638c6d3 --- /dev/null +++ b/mobile/ios/Client/Frontend/Intro/IntroViewController.swift @@ -0,0 +1,437 @@ +/* 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/. */ + +import UIKit +import SnapKit + +struct IntroViewControllerUX { + static let Width = 375 + static let Height = 667 + static let SyncButtonTopPadding = 5 + static let MinimumFontScale: CGFloat = 0.5 + + static let CardSlides = ["tour-Welcome", "tour-Search", "tour-Private", "tour-Mail", "tour-Sync"] + static let NumberOfCards = CardSlides.count + + static let PagerCenterOffsetFromScrollViewBottom = UIScreen.main.bounds.width <= 320 ? 20 : 30 + + static let StartBrowsingButtonTitle = NSLocalizedString("Start Browsing", tableName: "Intro", comment: "See http://mzl.la/1T8gxwo") + static let StartBrowsingButtonColor = UIColor(rgb: 0x4990E2) + static let StartBrowsingButtonHeight = 56 + static let SignInButtonTitle = NSLocalizedString("Sign in to Firefox", tableName: "Intro", comment: "See http://mzl.la/1T8gxwo") + static let SignInButtonColor = UIColor(rgb: 0x45A1FF) + static let SignInButtonHeight = 60 + static let SignInButtonWidth = 290 + + static let CardTextLineHeight = UIScreen.main.bounds.width <= 320 ? CGFloat(2) : CGFloat(6) + static let CardTextWidth = UIScreen.main.bounds.width <= 320 ? 240 : 280 + static let CardTitleHeight = 50 + + static let CardTitleWelcome = NSLocalizedString("Intro.Slides.Welcome.Title", tableName: "Intro", value: "Thanks for choosing Firefox!", comment: "Title for the first panel 'Welcome' in the First Run tour.") + static let CardTitleSearch = NSLocalizedString("Intro.Slides.Search.Title", tableName: "Intro", value: "Your search, your way", comment: "Title for the second panel 'Search' in the First Run tour.") + static let CardTitlePrivate = NSLocalizedString("Intro.Slides.Private.Title", tableName: "Intro", value: "Browse like no one’s watching", comment: "Title for the third panel 'Private Browsing' in the First Run tour.") + static let CardTitleMail = NSLocalizedString("Intro.Slides.Mail.Title", tableName: "Intro", value: "You’ve got mail… options", comment: "Title for the fourth panel 'Mail' in the First Run tour.") + static let CardTitleSync = NSLocalizedString("Intro.Slides.Sync.Title", tableName: "Intro", value: "Pick up where you left off", comment: "Title for the fifth panel 'Sync' in the First Run tour.") + + static let CardTextWelcome = NSLocalizedString("Intro.Slides.Welcome.Description", tableName: "Intro", value: "A modern mobile browser from Mozilla, the non-profit committed to a free and open web.", comment: "Description for the 'Welcome' panel in the First Run tour.") + static let CardTextSearch = NSLocalizedString("Intro.Slides.Search.Description", tableName: "Intro", value: "Searching for something different? Choose another default search engine (or add your own) in Settings.", comment: "Description for the 'Favorite Search Engine' panel in the First Run tour.") + static let CardTextPrivate = NSLocalizedString("Intro.Slides.Private.Description", tableName: "Intro", value: "Tap the mask icon to slip into Private Browsing mode.", comment: "Description for the 'Private Browsing' panel in the First Run tour.") + static let CardTextMail = NSLocalizedString("Intro.Slides.Mail.Description", tableName: "Intro", value: "Use any email app — not just Mail — with Firefox.", comment: "Description for the 'Mail' panel in the First Run tour.") + static let CardTextSync = NSLocalizedString("Intro.Slides.Sync.Description", tableName: "Intro", value: "Use Sync to find the bookmarks, passwords, and other things you save to Firefox on all your devices.", comment: "Description for the 'Sync' panel in the First Run tour.") + + static let FadeDuration = 0.25 +} + +let IntroViewControllerSeenProfileKey = "IntroViewControllerSeen" + +protocol IntroViewControllerDelegate: class { + func introViewControllerDidFinish(_ introViewController: IntroViewController, requestToLogin: Bool) +} + +class IntroViewController: UIViewController, UIScrollViewDelegate { + weak var delegate: IntroViewControllerDelegate? + + var slides = [UIImage]() + var cards = [UIImageView]() + var introViews = [UIView]() + var titleLabels = [UILabel]() + var textLabels = [UILabel]() + + var startBrowsingButton: UIButton! + var introView: UIView? + var slideContainer: UIView! + var pageControl: UIPageControl! + var backButton: UIButton! + var forwardButton: UIButton! + var signInButton: UIButton! + + fileprivate var scrollView: IntroOverlayScrollView! + + var slideVerticalScaleFactor: CGFloat = 1.0 + + override func viewDidLoad() { + view.backgroundColor = UIColor.white + + // scale the slides down for iPhone 4S + if view.frame.height <= 480 { + slideVerticalScaleFactor = 1.33 + slideVerticalScaleFactor = 1.33 //4S + } else if view.frame.height <= 568 { + slideVerticalScaleFactor = 1.15 //SE + } + + for slideName in IntroViewControllerUX.CardSlides { + slides.append(UIImage(named: slideName)!) + } + + startBrowsingButton = UIButton() + startBrowsingButton.backgroundColor = UIColor.clear + startBrowsingButton.setTitle(IntroViewControllerUX.StartBrowsingButtonTitle, for: UIControlState()) + startBrowsingButton.setTitleColor(IntroViewControllerUX.StartBrowsingButtonColor, for: UIControlState()) + startBrowsingButton.addTarget(self, action: #selector(IntroViewController.SELstartBrowsing), for: UIControlEvents.touchUpInside) + startBrowsingButton.accessibilityIdentifier = "IntroViewController.startBrowsingButton" + + view.addSubview(startBrowsingButton) + startBrowsingButton.snp.makeConstraints { (make) -> Void in + if #available(iOS 11.0, *) { + make.left.right.bottom.equalTo(self.view.safeAreaLayoutGuide) + } else { + make.left.right.bottom.equalTo(self.view) + } + make.height.equalTo(IntroViewControllerUX.StartBrowsingButtonHeight) + } + + scrollView = IntroOverlayScrollView() + scrollView.backgroundColor = UIColor.clear + scrollView.accessibilityLabel = NSLocalizedString("Intro Tour Carousel", comment: "Accessibility label for the introduction tour carousel") + scrollView.delegate = self + scrollView.bounces = false + scrollView.isPagingEnabled = true + scrollView.showsHorizontalScrollIndicator = false + scrollView.contentSize = CGSize(width: scaledWidthOfSlide * CGFloat(IntroViewControllerUX.NumberOfCards), height: scaledHeightOfSlide) + scrollView.accessibilityIdentifier = "IntroViewController.scrollView" + view.addSubview(scrollView) + + slideContainer = UIView() + for i in 0.. Void in + make.left.right.top.equalTo(self.view) + make.bottom.equalTo(startBrowsingButton.snp.top) + } + self.view.layoutIfNeeded() + self.scrollView.layoutIfNeeded() + + pageControl = UIPageControl() + pageControl.pageIndicatorTintColor = UIColor.black.withAlphaComponent(0.3) + pageControl.currentPageIndicatorTintColor = UIColor.black + pageControl.numberOfPages = IntroViewControllerUX.NumberOfCards + pageControl.accessibilityIdentifier = "IntroViewController.pageControl" + pageControl.addTarget(self, action: #selector(IntroViewController.changePage), for: UIControlEvents.valueChanged) + + view.addSubview(pageControl) + pageControl.snp.makeConstraints { (make) -> Void in + make.centerX.equalTo(self.scrollView) + make.centerY.equalTo(self.startBrowsingButton.snp.top).offset(-IntroViewControllerUX.PagerCenterOffsetFromScrollViewBottom) + } + + func addCard(title: String, text: String, introView: UIView) { + self.introViews.append(introView) + + let titleLabel = UILabel() + titleLabel.numberOfLines = 2 + titleLabel.adjustsFontSizeToFitWidth = true + titleLabel.minimumScaleFactor = IntroViewControllerUX.MinimumFontScale + titleLabel.textAlignment = NSTextAlignment.center + titleLabel.text = title + titleLabels.append(titleLabel) + introView.addSubview(titleLabel) + titleLabel.snp.makeConstraints { (make ) -> Void in + make.top.equalTo(introView).offset(20) + make.centerX.equalTo(introView) + make.height.equalTo(IntroViewControllerUX.CardTitleHeight) + make.width.equalTo(IntroViewControllerUX.CardTextWidth) + } + + let textLabel = UILabel() + textLabel.numberOfLines = 5 + textLabel.attributedText = attributedStringForLabel(text) + textLabel.adjustsFontSizeToFitWidth = true + textLabel.minimumScaleFactor = IntroViewControllerUX.MinimumFontScale + textLabel.lineBreakMode = .byTruncatingTail + textLabels.append(textLabel) + introView.addSubview(textLabel) + textLabel.snp.makeConstraints({ (make) -> Void in + make.top.equalTo(titleLabel.snp.bottom).offset(20) + make.centerX.equalTo(introView) + make.width.equalTo(IntroViewControllerUX.CardTextWidth) + }) + } + addCard(title: IntroViewControllerUX.CardTitleWelcome, text: IntroViewControllerUX.CardTextWelcome, introView: UIView()) + addCard(title: IntroViewControllerUX.CardTitleSearch, text: IntroViewControllerUX.CardTextSearch, introView: UIView()) + addCard(title: IntroViewControllerUX.CardTitlePrivate, text: IntroViewControllerUX.CardTextPrivate, introView: UIView()) + addCard(title: IntroViewControllerUX.CardTitleMail, text: IntroViewControllerUX.CardTextMail, introView: UIView()) + + // Sync card, with sign in to sync button. + signInButton = UIButton() + signInButton.backgroundColor = IntroViewControllerUX.SignInButtonColor + signInButton.setTitle(IntroViewControllerUX.SignInButtonTitle, for: UIControlState()) + signInButton.setTitleColor(UIColor.white, for: UIControlState()) + signInButton.clipsToBounds = true + signInButton.addTarget(self, action: #selector(IntroViewController.SELlogin), for: UIControlEvents.touchUpInside) + signInButton.snp.makeConstraints { (make) -> Void in + make.height.equalTo(IntroViewControllerUX.SignInButtonHeight) + } + + let syncCardView = UIView() + // introViews.append(syncCardView) + addCard(title: IntroViewControllerUX.CardTitleSync, text: IntroViewControllerUX.CardTextSync, introView: syncCardView) + + syncCardView.addSubview(signInButton) + syncCardView.bringSubview(toFront: signInButton) + signInButton.snp.makeConstraints { (make) -> Void in + make.centerX.equalTo(syncCardView) + make.width.equalTo(IntroViewControllerUX.CardTextWidth) // TODO Talk to UX about small screen sizes + make.bottom.equalTo(syncCardView) + } + + // We need a reference to the sync pages textlabel so we can adjust the constraints + if let index = introViews.index(of: syncCardView), index < textLabels.count { + let syncTextLabel = textLabels[index] + syncTextLabel.snp.makeConstraints { make in + make.bottom.equalTo(signInButton.snp.top).offset(-IntroViewControllerUX.SyncButtonTopPadding) + } + } + // Add all the cards to the view, make them invisible with zero alpha + for introView in introViews { + introView.alpha = 0 + self.view.addSubview(introView) + introView.snp.makeConstraints { (make) -> Void in + make.top.equalTo(self.slideContainer.snp.bottom) + make.bottom.equalTo(self.startBrowsingButton.snp.top) + make.left.right.equalTo(self.view) + } + } + + // Make whole screen scrollable by bringing the scrollview to the top + view.bringSubview(toFront: scrollView) + view.sendSubview(toBack: pageControl) + scrollView?.bringSubview(toFront: syncCardView) + signInButton.superview?.bringSubview(toFront: signInButton) + + // Activate the first card + setActiveIntroView(introViews[0], forPage: 0) + setupDynamicFonts() + } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + NotificationCenter.default.addObserver(self, selector: #selector(SELDynamicFontChanged(_:)), name: NotificationDynamicFontChanged, object: nil) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + NotificationCenter.default.removeObserver(self, name: NotificationDynamicFontChanged, object: nil) + } + + func SELDynamicFontChanged(_ notification: Notification) { + guard notification.name == NotificationDynamicFontChanged else { return } + setupDynamicFonts() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + scrollView.snp.remakeConstraints { (make) -> Void in + make.left.right.top.equalTo(self.view) + make.bottom.equalTo(self.startBrowsingButton.snp.top) + } + + for i in 0.. 1.0 ? 1.0 : percentageOfScroll + let whiteComponent = UIColor.white.components + let grayComponent = UIColor(rgb: 0xF2F2F2).components + + let page = Int(scrollView.contentOffset.x / scrollView.frame.size.width) + pageControl.currentPage = page + + let newRed = (1.0 - percentageOfScroll) * whiteComponent.red + percentageOfScroll * grayComponent.red + let newGreen = (1.0 - percentageOfScroll) * whiteComponent.green + percentageOfScroll * grayComponent.green + let newBlue = (1.0 - percentageOfScroll) * whiteComponent.blue + percentageOfScroll * grayComponent.blue + let newColor = UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: 1.0) + slideContainer.backgroundColor = newColor + } + + fileprivate func setActiveIntroView(_ newIntroView: UIView, forPage page: Int) { + if introView != newIntroView { + UIView.animate(withDuration: IntroViewControllerUX.FadeDuration, animations: { () -> Void in + self.introView?.alpha = 0 + self.introView = newIntroView + newIntroView.alpha = 1.0 + if page == 0 { + self.startBrowsingButton.alpha = 0 + } else { + self.startBrowsingButton.alpha = 1 + } + }, completion: { _ in + if page == (IntroViewControllerUX.NumberOfCards - 1) { + self.scrollView.signinButton = self.signInButton + } else { + self.scrollView.signinButton = nil + } + }) + } + } + + fileprivate var scaledWidthOfSlide: CGFloat { + return view.frame.width + } + + fileprivate var scaledHeightOfSlide: CGFloat { + return (view.frame.width / slides[0].size.width) * slides[0].size.height / slideVerticalScaleFactor + } + + fileprivate func attributedStringForLabel(_ text: String) -> NSMutableAttributedString { + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineSpacing = IntroViewControllerUX.CardTextLineHeight + paragraphStyle.alignment = .center + + let string = NSMutableAttributedString(string: text) + string.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: string.length)) + return string + } + + fileprivate func setupDynamicFonts() { + startBrowsingButton.titleLabel?.font = UIFont(name: "FiraSans-Regular", size: DynamicFontHelper.defaultHelper.IntroStandardFontSize) + signInButton.titleLabel?.font = UIFont(name: "FiraSans-Regular", size: DynamicFontHelper.defaultHelper.IntroBigFontSize) + + for titleLabel in titleLabels { + titleLabel.font = UIFont(name: "FiraSans-Medium", size: DynamicFontHelper.defaultHelper.IntroBigFontSize) + } + + for label in textLabels { + label.font = UIFont(name: "FiraSans-UltraLight", size: DynamicFontHelper.defaultHelper.IntroStandardFontSize) + } + } +} + +fileprivate class IntroOverlayScrollView: UIScrollView { + weak var signinButton: UIButton? + + fileprivate override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + if let signinFrame = signinButton?.frame { + let convertedFrame = convert(signinFrame, from: signinButton?.superview) + if convertedFrame.contains(point) { + return false + } + } + + return CGRect(origin: self.frame.origin, size: CGSize(width: self.contentSize.width, height: self.frame.size.height)).contains(point) + } +} + +extension UIColor { + var components:(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + var r: CGFloat = 0 + var g: CGFloat = 0 + var b: CGFloat = 0 + var a: CGFloat = 0 + getRed(&r, green: &g, blue: &b, alpha: &a) + return (r, g, b, a) + } +} diff --git a/mobile/ios/Client/Frontend/Login Management/LoginListViewController.swift b/mobile/ios/Client/Frontend/Login Management/LoginListViewController.swift new file mode 100644 index 0000000000..a68fc8211a --- /dev/null +++ b/mobile/ios/Client/Frontend/Login Management/LoginListViewController.swift @@ -0,0 +1,639 @@ +/* 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/. */ + +import Foundation +import UIKit +import SnapKit +import Storage +import Shared +import SwiftKeychainWrapper +import Deferred + +private struct LoginListUX { + static let RowHeight: CGFloat = 58 + static let SearchHeight: CGFloat = 58 + static let selectionButtonFont = UIFont.systemFont(ofSize: 16) + static let selectionButtonTextColor = UIColor.white + static let selectionButtonBackground = UIConstants.HighlightBlue + static let NoResultsFont: UIFont = UIFont.systemFont(ofSize: 16) + static let NoResultsTextColor: UIColor = UIColor.lightGray +} + +private extension UITableView { + var allIndexPaths: [IndexPath] { + return (0..>? + + fileprivate let loadingStateView = LoadingLoginsView() + + fileprivate var deleteAlert: UIAlertController? + + // Titles for selection/deselect/delete buttons + fileprivate let deselectAllTitle = NSLocalizedString("Deselect All", tableName: "LoginManager", comment: "Label for the button used to deselect all logins.") + fileprivate let selectAllTitle = NSLocalizedString("Select All", tableName: "LoginManager", comment: "Label for the button used to select all logins.") + fileprivate let deleteLoginTitle = NSLocalizedString("Delete", tableName: "LoginManager", comment: "Label for the button used to delete the current login.") + + fileprivate lazy var selectionButton: UIButton = { + let button = UIButton() + button.titleLabel?.font = LoginListUX.selectionButtonFont + button.setTitle(self.selectAllTitle, for: UIControlState()) + button.setTitleColor(LoginListUX.selectionButtonTextColor, for: UIControlState()) + button.backgroundColor = LoginListUX.selectionButtonBackground + button.addTarget(self, action: #selector(LoginListViewController.tappedSelectionButton), for: .touchUpInside) + return button + }() + + fileprivate var selectionButtonHeightConstraint: Constraint? + fileprivate var selectedIndexPaths = [IndexPath]() + + fileprivate let tableView = UITableView() + + weak var settingsDelegate: SettingsDelegate? + + init(profile: Profile) { + self.profile = profile + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + let notificationCenter = NotificationCenter.default + notificationCenter.addObserver(self, selector: #selector(LoginListViewController.remoteLoginsDidChange), name: NotificationDataRemoteLoginChangesWereApplied, object: nil) + notificationCenter.addObserver(self, selector: #selector(LoginListViewController.dismissAlertController), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) + + automaticallyAdjustsScrollViewInsets = false + self.view.backgroundColor = UIColor.white + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(LoginListViewController.beginEditing)) + + self.title = NSLocalizedString("Logins", tableName: "LoginManager", comment: "Title for Logins List View screen.") + + searchView.delegate = self + tableView.register(LoginTableViewCell.self, forCellReuseIdentifier: LoginCellIdentifier) + + view.addSubview(searchView) + view.addSubview(tableView) + view.addSubview(loadingStateView) + view.addSubview(selectionButton) + + loadingStateView.isHidden = true + + searchView.snp.makeConstraints { make in + make.top.equalTo(self.topLayoutGuide.snp.bottom) + make.left.right.equalTo(self.view) + make.height.equalTo(LoginListUX.SearchHeight) + } + + tableView.snp.makeConstraints { make in + make.top.equalTo(searchView.snp.bottom) + make.left.right.equalTo(self.view) + make.bottom.equalTo(self.selectionButton.snp.top) + } + + selectionButton.snp.makeConstraints { make in + make.left.right.bottom.equalTo(self.view) + make.top.equalTo(self.tableView.snp.bottom) + make.bottom.equalTo(self.view) + selectionButtonHeightConstraint = make.height.equalTo(0).constraint + } + + loadingStateView.snp.makeConstraints { make in + make.edges.equalTo(tableView) + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + tableView.accessibilityIdentifier = "Login List" + tableView.dataSource = loginDataSource + tableView.allowsMultipleSelectionDuringEditing = true + tableView.delegate = self + tableView.tableFooterView = UIView() + + KeyboardHelper.defaultHelper.addDelegate(self) + + searchView.isEditing ? loadLogins(searchView.inputField.text) : loadLogins() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + self.loginDataSource.emptyStateView.searchBarHeight = searchView.frame.height + self.loadingStateView.searchBarHeight = searchView.frame.height + } + + deinit { + let notificationCenter = NotificationCenter.default + notificationCenter.removeObserver(self, name: NotificationProfileDidFinishSyncing, object: nil) + notificationCenter.removeObserver(self, name: NotificationDataLoginDidChange, object: nil) + notificationCenter.removeObserver(self, name: NotificationDataRemoteLoginChangesWereApplied, object: nil) + notificationCenter.removeObserver(self, name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) + } + + fileprivate func toggleDeleteBarButton() { + // Show delete bar button item if we have selected any items + if loginSelectionController.selectedCount > 0 { + if navigationItem.rightBarButtonItem == nil { + navigationItem.rightBarButtonItem = UIBarButtonItem(title: deleteLoginTitle, style: .plain, target: self, action: #selector(LoginListViewController.tappedDelete)) + navigationItem.rightBarButtonItem?.tintColor = UIColor.red + } + } else { + navigationItem.rightBarButtonItem = nil + } + } + + fileprivate func toggleSelectionTitle() { + if loginSelectionController.selectedCount == loginDataSource.count { + selectionButton.setTitle(deselectAllTitle, for: UIControlState()) + } else { + selectionButton.setTitle(selectAllTitle, for: UIControlState()) + } + } + + // Wrap the SQLiteLogins method to allow us to cancel it from our end. + fileprivate func queryLogins(_ query: String) -> Deferred> { + let deferred = Deferred>() + profile.logins.searchLoginsWithQuery(query) >>== { logins in + deferred.fillIfUnfilled(Maybe(success: logins.asArray())) + succeed() + } + return deferred + } +} + +// MARK: - Selectors +private extension LoginListViewController { + @objc func remoteLoginsDidChange() { + DispatchQueue.main.async { + self.loadLogins() + } + } + + @objc func dismissAlertController() { + self.deleteAlert?.dismiss(animated: false, completion: nil) + } + + func loadLogins(_ query: String? = nil) { + loadingStateView.isHidden = false + + // Fill in an in-flight query and re-query + activeLoginQuery?.fillIfUnfilled(Maybe(success: [])) + activeLoginQuery = queryLogins(query ?? "") + activeLoginQuery! >>== self.loginDataSource.setLogins + } + + @objc func beginEditing() { + navigationItem.rightBarButtonItem = nil + navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(LoginListViewController.cancelSelection)) + selectionButtonHeightConstraint?.update(offset: UIConstants.ToolbarHeight) + self.view.layoutIfNeeded() + tableView.setEditing(true, animated: true) + } + + @objc func cancelSelection() { + // Update selection and select all button + loginSelectionController.deselectAll() + toggleSelectionTitle() + selectionButtonHeightConstraint?.update(offset: 0) + self.view.layoutIfNeeded() + + tableView.setEditing(false, animated: true) + navigationItem.leftBarButtonItem = nil + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(LoginListViewController.beginEditing)) + } + + @objc func tappedDelete() { + profile.logins.hasSyncedLogins().uponQueue(DispatchQueue.main) { yes in + self.deleteAlert = UIAlertController.deleteLoginAlertWithDeleteCallback({ [unowned self] _ in + // Delete here + let guidsToDelete = self.loginSelectionController.selectedIndexPaths.map { indexPath in + self.loginDataSource.loginAtIndexPath(indexPath)!.guid + } + + self.profile.logins.removeLoginsWithGUIDs(guidsToDelete).uponQueue(DispatchQueue.main) { _ in + self.cancelSelection() + self.loadLogins() + } + }, hasSyncedLogins: yes.successValue ?? true) + + self.present(self.deleteAlert!, animated: true, completion: nil) + } + } + + @objc func tappedSelectionButton() { + // If we haven't selected everything yet, select all + if loginSelectionController.selectedCount < loginDataSource.count { + // Find all unselected indexPaths + let unselectedPaths = tableView.allIndexPaths.filter { indexPath in + return !loginSelectionController.indexPathIsSelected(indexPath) + } + loginSelectionController.selectIndexPaths(unselectedPaths) + unselectedPaths.forEach { indexPath in + self.tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none) + } + } + + // If everything has been selected, deselect all + else { + loginSelectionController.deselectAll() + tableView.allIndexPaths.forEach { indexPath in + self.tableView.deselectRow(at: indexPath, animated: true) + } + } + + toggleSelectionTitle() + toggleDeleteBarButton() + } +} + +// MARK: - LoginDataSourceObserver +extension LoginListViewController: LoginDataSourceObserver { + func loginSectionsDidUpdate() { + loadingStateView.isHidden = true + tableView.reloadData() + activeLoginQuery = nil + navigationItem.rightBarButtonItem?.isEnabled = loginDataSource.count > 0 + restoreSelectedRows() + } + + func restoreSelectedRows() { + for path in self.loginSelectionController.selectedIndexPaths { + tableView.selectRow(at: path, animated: false, scrollPosition: .none) + } + } +} + +// MARK: - UITableViewDelegate +extension LoginListViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + // Force the headers to be hidden + return 0 + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return LoginListUX.RowHeight + } + + func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle { + return .none + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if tableView.isEditing { + loginSelectionController.selectIndexPath(indexPath) + toggleSelectionTitle() + toggleDeleteBarButton() + } else { + tableView.deselectRow(at: indexPath, animated: true) + let login = loginDataSource.loginAtIndexPath(indexPath)! + let detailViewController = LoginDetailViewController(profile: profile, login: login) + detailViewController.settingsDelegate = settingsDelegate + navigationController?.pushViewController(detailViewController, animated: true) + } + } + + func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { + if tableView.isEditing { + loginSelectionController.deselectIndexPath(indexPath) + toggleSelectionTitle() + toggleDeleteBarButton() + } + } +} + +// MARK: - KeyboardHelperDelegate +extension LoginListViewController: KeyboardHelperDelegate { + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillShowWithState state: KeyboardState) { + let coveredHeight = state.intersectionHeightForView(tableView) + tableView.contentInset.bottom = coveredHeight + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardDidShowWithState state: KeyboardState) { + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillHideWithState state: KeyboardState) { + tableView.contentInset.bottom = 0 + } +} + +// MARK: - SearchInputViewDelegate +extension LoginListViewController: SearchInputViewDelegate { + + @objc func searchInputView(_ searchView: SearchInputView, didChangeTextTo text: String) { + loadLogins(text) + } + + @objc func searchInputViewBeganEditing(_ searchView: SearchInputView) { + // Trigger a cancel for editing + cancelSelection() + + // Hide the edit button while we're searching + navigationItem.rightBarButtonItem = nil + loadLogins() + } + + @objc func searchInputViewFinishedEditing(_ searchView: SearchInputView) { + // Show the edit after we're done with the search + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(LoginListViewController.beginEditing)) + loadLogins() + } +} + +/// Controller that keeps track of selected indexes +fileprivate class ListSelectionController: NSObject { + + fileprivate unowned let tableView: UITableView + + fileprivate(set) var selectedIndexPaths = [IndexPath]() + + var selectedCount: Int { + return selectedIndexPaths.count + } + + init(tableView: UITableView) { + self.tableView = tableView + super.init() + } + + func selectIndexPath(_ indexPath: IndexPath) { + selectedIndexPaths.append(indexPath) + } + + func indexPathIsSelected(_ indexPath: IndexPath) -> Bool { + return selectedIndexPaths.contains(indexPath) { path1, path2 in + return path1.row == path2.row && path1.section == path2.section + } + } + + func deselectIndexPath(_ indexPath: IndexPath) { + guard let foundSelectedPath = (selectedIndexPaths.filter { $0.row == indexPath.row && $0.section == indexPath.section }).first, + let indexToRemove = selectedIndexPaths.index(of: foundSelectedPath) else { + return + } + + selectedIndexPaths.remove(at: indexToRemove) + } + + func deselectAll() { + selectedIndexPaths.removeAll() + } + + func selectIndexPaths(_ indexPaths: [IndexPath]) { + selectedIndexPaths += indexPaths + } +} + +protocol LoginDataSourceObserver: class { + func loginSectionsDidUpdate() +} + +/// Data source for handling LoginData objects from a Cursor +class LoginDataSource: NSObject, UITableViewDataSource { + + var count: Int = 0 + + weak var dataObserver: LoginDataSourceObserver? + + fileprivate let emptyStateView = NoLoginsView() + + fileprivate var sections = [Character: [Login]]() { + didSet { + assert(Thread.isMainThread, "Must be assigned to from the main thread or else data will be out of sync with reloadData.") + self.dataObserver?.loginSectionsDidUpdate() + } + } + + fileprivate var titles = [Character]() + + fileprivate func loginsForSection(_ section: Int) -> [Login]? { + let titleForSectionIndex = titles[section] + return sections[titleForSectionIndex] + } + + func loginAtIndexPath(_ indexPath: IndexPath) -> Login? { + let titleForSectionIndex = titles[indexPath.section] + return sections[titleForSectionIndex]?[indexPath.row] + } + + @objc func numberOfSections(in tableView: UITableView) -> Int { + let numOfSections = sections.count + if numOfSections == 0 { + tableView.backgroundView = emptyStateView + tableView.separatorStyle = .none + } else { + tableView.backgroundView = nil + tableView.separatorStyle = .singleLine + } + return numOfSections + } + + @objc func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return loginsForSection(section)?.count ?? 0 + } + + @objc func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: LoginCellIdentifier, for: indexPath) as! LoginTableViewCell + let login = loginAtIndexPath(indexPath)! + cell.style = .noIconAndBothLabels + cell.updateCellWithLogin(login) + return cell + } + + @objc func sectionIndexTitles(for tableView: UITableView) -> [String]? { + return titles.map { String($0) } + } + + @objc func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { + return titles.index(of: Character(title)) ?? 0 + } + + @objc func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return String(titles[section]) + } + + func setLogins(_ logins: [Login]) { + // NB: Make sure we call the callback on the main thread so it can be synced up with a reloadData to + // prevent race conditions between data/UI indexing. + return computeSectionsFromLogins(logins).uponQueue(DispatchQueue.main) { result in + guard let (titles, sections) = result.successValue else { + self.count = 0 + self.titles = [] + self.sections = [:] + return + } + + self.count = logins.count + self.titles = titles + self.sections = sections + } + } + + fileprivate func computeSectionsFromLogins(_ logins: [Login]) -> Deferred> { + guard logins.count > 0 else { + return deferMaybe( ([Character](), [Character: [Login]]()) ) + } + + var domainLookup = [GUID: (baseDomain: String?, host: String?, hostname: String)]() + var sections = [Character: [Login]]() + var titleSet = Set() + + // Small helper method for using the precomputed base domain to determine the title/section of the + // given login. + func titleForLogin(_ login: Login) -> Character { + // Fallback to hostname if we can't extract a base domain. + let titleString = domainLookup[login.guid]?.baseDomain?.uppercased() ?? login.hostname + return titleString.characters.first ?? Character("") + } + + // Rules for sorting login URLS: + // 1. Compare base domains + // 2. If bases are equal, compare hosts + // 3. If login URL was invalid, revert to full hostname + func sortByDomain(_ loginA: Login, loginB: Login) -> Bool { + guard let domainsA = domainLookup[loginA.guid], + let domainsB = domainLookup[loginB.guid] else { + return false + } + + guard let baseDomainA = domainsA.baseDomain, + let baseDomainB = domainsB.baseDomain, + let hostA = domainsA.host, + let hostB = domainsB.host else { + return domainsA.hostname < domainsB.hostname + } + + if baseDomainA == baseDomainB { + return hostA < hostB + } else { + return baseDomainA < baseDomainB + } + } + + return deferDispatchAsync(DispatchQueue.global(qos: DispatchQoS.userInteractive.qosClass)) { + // Precompute the baseDomain, host, and hostname values for sorting later on. At the moment + // baseDomain() is a costly call because of the ETLD lookup tables. + logins.forEach { login in + domainLookup[login.guid] = ( + login.hostname.asURL?.baseDomain, + login.hostname.asURL?.host, + login.hostname + ) + } + + // 1. Temporarily insert titles into a Set to get duplicate removal for 'free'. + logins.forEach { titleSet.insert(titleForLogin($0)) } + + // 2. Setup an empty list for each title found. + titleSet.forEach { sections[$0] = [Login]() } + + // 3. Go through our logins and put them in the right section. + logins.forEach { sections[titleForLogin($0)]?.append($0) } + + // 4. Go through each section and sort. + sections.forEach { sections[$0] = $1.sorted(by: sortByDomain) } + + return deferMaybe( (Array(titleSet).sorted(), sections) ) + } + } +} + +/// Empty state view when there is no logins to display. +fileprivate class NoLoginsView: UIView { + + // We use the search bar height to maintain visual balance with the whitespace on this screen. The + // title label is centered visually using the empty view + search bar height as the size to center with. + var searchBarHeight: CGFloat = 0 { + didSet { + setNeedsUpdateConstraints() + } + } + + lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = LoginListUX.NoResultsFont + label.textColor = LoginListUX.NoResultsTextColor + label.text = NSLocalizedString("No logins found", tableName: "LoginManager", comment: "Label displayed when no logins are found after searching.") + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(titleLabel) + } + + fileprivate override func updateConstraints() { + super.updateConstraints() + titleLabel.snp.remakeConstraints { make in + make.centerX.equalTo(self) + make.centerY.equalTo(self).offset(-(searchBarHeight / 2)) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +/// View to display to the user while we are loading the logins +fileprivate class LoadingLoginsView: UIView { + + var searchBarHeight: CGFloat = 0 { + didSet { + setNeedsUpdateConstraints() + } + } + + lazy var indicator: UIActivityIndicatorView = { + let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) + indicator.hidesWhenStopped = false + return indicator + }() + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(indicator) + backgroundColor = UIColor.white + indicator.startAnimating() + } + + fileprivate override func updateConstraints() { + super.updateConstraints() + indicator.snp.remakeConstraints { make in + make.centerX.equalTo(self) + make.centerY.equalTo(self).offset(-(searchBarHeight / 2)) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/mobile/ios/Client/Frontend/Login/LoginViewController.swift b/mobile/ios/Client/Frontend/Login/LoginViewController.swift new file mode 100644 index 0000000000..e67949e690 --- /dev/null +++ b/mobile/ios/Client/Frontend/Login/LoginViewController.swift @@ -0,0 +1,35 @@ +/* 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/. */ + +import UIKit +import Snap + +class LoginViewController: UIViewController { + var accountManager: AccountProfileManager! + + override func loadView() { + view = LoginView() + } + + override func viewDidLoad() { + super.viewDidLoad() + + let loginView = view as LoginView + + loginView.didClickLogin = { [unowned self] in + self.accountManager.login(loginView.username, password: loginView.password, { err in + switch err { + case .badAuth: + println("Invalid username and/or password") + default: + println("Connection error") + } + }) + } + } + + override func prefersStatusBarHidden() -> Bool { + return true + } +} diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/Contents.json new file mode 100644 index 0000000000..fc91820b86 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bookmark-remove.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bookmark-remove@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "bookmark-remove@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove.png new file mode 100644 index 0000000000..8d66b36d99 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove@2x.png new file mode 100644 index 0000000000..bdb615f03e Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove@3x.png new file mode 100644 index 0000000000..388cddb0b7 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark-Remove.imageset/bookmark-remove@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/Contents.json new file mode 100644 index 0000000000..e7fc60dd35 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-Bookmark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-Bookmark@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-Bookmark@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark.png new file mode 100644 index 0000000000..214afcb29e Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark@2x.png new file mode 100644 index 0000000000..028721ac4b Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark@3x.png new file mode 100644 index 0000000000..d4d18ab6c6 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Bookmark.imageset/menu-Bookmark@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/Contents.json new file mode 100644 index 0000000000..b79aa0cff0 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-CloseTabs.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-CloseTabs@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-CloseTabs@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs.png new file mode 100644 index 0000000000..fa1588c857 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs@2x.png new file mode 100644 index 0000000000..89941db856 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs@3x.png new file mode 100644 index 0000000000..6423d6c5ad Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-CloseTabs.imageset/menu-CloseTabs@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/Contents.json new file mode 100644 index 0000000000..6deda9a625 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "link.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "link@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "link@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link.png new file mode 100644 index 0000000000..87263b50da Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link@2x.png new file mode 100644 index 0000000000..b12aa6a1ba Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link@3x.png new file mode 100644 index 0000000000..36a280869b Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Copy-Link.imageset/link@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/Contents.json new file mode 100644 index 0000000000..216ea4a88f --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "search.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "search@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "search@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search.png new file mode 100644 index 0000000000..17732b06f6 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search@2x.png new file mode 100644 index 0000000000..47e4d1c0fa Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search@3x.png new file mode 100644 index 0000000000..bcc8e6e96e Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-FindInPage.imageset/search@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/Contents.json new file mode 100644 index 0000000000..47bcb3b1a1 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bottomNav-Home.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bottomNav-Home@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "bottomNav-Home@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home.png new file mode 100644 index 0000000000..db2543ba83 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home@2x.png new file mode 100644 index 0000000000..86076fe209 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home@3x.png new file mode 100644 index 0000000000..bd27a9895b Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Home.imageset/bottomNav-Home@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/Contents.json new file mode 100644 index 0000000000..cc7787d280 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "action.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "action@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "action@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action.png new file mode 100644 index 0000000000..600de87ec3 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action@2x.png new file mode 100644 index 0000000000..7e71c9c059 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action@3x.png new file mode 100644 index 0000000000..e1ad99e304 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-More-Options.imageset/action@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/Contents.json new file mode 100644 index 0000000000..da3489bf6a --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "new-private-tab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "new-private-tab@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "new-private-tab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab.png new file mode 100644 index 0000000000..642ead018f Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab@2x.png new file mode 100644 index 0000000000..138e7c232b Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab@3x.png new file mode 100644 index 0000000000..64f917fb17 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewPrivateTab.imageset/new-private-tab@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/Contents.json new file mode 100644 index 0000000000..99dafff517 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-NewTab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-NewTab@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-NewTab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab.png new file mode 100644 index 0000000000..523b0b0f60 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab@2x.png new file mode 100644 index 0000000000..3a0458caa4 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab@3x.png new file mode 100644 index 0000000000..dc27e70819 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NewTab.imageset/menu-NewTab@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/Contents.json new file mode 100644 index 0000000000..68d6cc2c43 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-NightMode.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-NightMode@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-NightMode@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode.png new file mode 100644 index 0000000000..9e57f24a9f Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode@2x.png new file mode 100644 index 0000000000..10266d165c Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode@3x.png new file mode 100644 index 0000000000..dbf016df46 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NightMode.imageset/menu-NightMode@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/Contents.json new file mode 100644 index 0000000000..2976d3f86b --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-NoImageMode.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-NoImageMode@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-NoImageMode@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode.png new file mode 100644 index 0000000000..9dd70569c0 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode@2x.png new file mode 100644 index 0000000000..030e03915d Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode@3x.png new file mode 100644 index 0000000000..3189391554 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-NoImageMode.imageset/menu-NoImageMode@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/Contents.json new file mode 100644 index 0000000000..9485891d1e --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-RequestDesktopSite.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-RequestDesktopSite@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-RequestDesktopSite@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite.png new file mode 100644 index 0000000000..2759d5b19d Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite@2x.png new file mode 100644 index 0000000000..8798268a5c Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite@3x.png new file mode 100644 index 0000000000..661c56625c Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-RequestDesktopSite.imageset/menu-RequestDesktopSite@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/Contents.json new file mode 100644 index 0000000000..5b775b8303 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "qrscan.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "qrscan@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "qrscan@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan.png new file mode 100644 index 0000000000..87c6dca468 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan@2x.png new file mode 100644 index 0000000000..ca37a13800 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan@3x.png new file mode 100644 index 0000000000..742e243be0 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ScanQRCode.imageset/qrscan@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/Contents.json new file mode 100644 index 0000000000..b507a7807b --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "sendtodevice.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "sendtodevice@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "sendtodevice@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice.png new file mode 100644 index 0000000000..5430ffbe38 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice@2x.png new file mode 100644 index 0000000000..11bfea7fb5 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice@3x.png new file mode 100644 index 0000000000..665fb857aa Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send-to-Device.imageset/sendtodevice@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/Contents.json new file mode 100644 index 0000000000..432bea0a81 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "sendMenu.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "sendMenu@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "sendMenu@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu.png new file mode 100644 index 0000000000..d2b170d967 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu@2x.png new file mode 100644 index 0000000000..66878a3752 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu@3x.png new file mode 100644 index 0000000000..8a88d79989 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Send.imageset/sendMenu@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/Contents.json new file mode 100644 index 0000000000..2622c41053 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-Settings.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-Settings@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-Settings@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings.png new file mode 100644 index 0000000000..a48cdc780c Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings@2x.png new file mode 100644 index 0000000000..89be79c697 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings@3x.png new file mode 100644 index 0000000000..071bd1e0a2 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Settings.imageset/menu-Settings@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/Contents.json new file mode 100644 index 0000000000..980051f93d --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "showtabs.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "showtabs@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "showtabs@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs.png new file mode 100644 index 0000000000..2842180043 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs@2x.png new file mode 100644 index 0000000000..cc4d4409ce Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs@3x.png new file mode 100644 index 0000000000..78da39ad85 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-Show-Tabs.imageset/showtabs@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/Contents.json new file mode 100644 index 0000000000..f8738ba83e --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "trackingprotection.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "trackingprotection@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "trackingprotection@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection.png new file mode 100644 index 0000000000..96ce77c44f Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection@2x.png new file mode 100644 index 0000000000..77888df088 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection@3x.png new file mode 100644 index 0000000000..2b8521064f Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-TrackingProtection.imageset/trackingprotection@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/Contents.json new file mode 100644 index 0000000000..4da5077fa8 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-ViewMobile.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-ViewMobile@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-ViewMobile@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile.png new file mode 100644 index 0000000000..0892f0b459 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile@2x.png new file mode 100644 index 0000000000..2098daf05a Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile@3x.png new file mode 100644 index 0000000000..3bb68fd2f0 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-ViewMobile.imageset/menu-ViewMobile@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/Contents.json new file mode 100644 index 0000000000..43fd6f1765 --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bookmark-filled.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bookmark-filled@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "bookmark-filled@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled.png new file mode 100644 index 0000000000..4a3fa09981 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled@2x.png new file mode 100644 index 0000000000..c7fda8e906 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled@3x.png new file mode 100644 index 0000000000..f05b80bcc1 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-Bookmarks.imageset/bookmark-filled@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/Contents.json new file mode 100644 index 0000000000..e972e4e90c --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "history.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "history@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "history@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history.png new file mode 100644 index 0000000000..1f3e68ab2b Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history@2x.png new file mode 100644 index 0000000000..8650cba5a9 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history@3x.png new file mode 100644 index 0000000000..2b626ad30a Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-History.imageset/history@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/Contents.json new file mode 100644 index 0000000000..c2dfe5e38a --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reading-list.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "reading-list@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "reading-list@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list.png new file mode 100644 index 0000000000..05f93e98cc Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list@2x.png new file mode 100644 index 0000000000..05e1576f58 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list@3x.png new file mode 100644 index 0000000000..0038a91124 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-ReadingList.imageset/reading-list@3x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/Contents.json b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/Contents.json new file mode 100644 index 0000000000..d0b4f6a6ab --- /dev/null +++ b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "topsites.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "topsites@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "topsites@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites.png new file mode 100644 index 0000000000..aed2cf5bd9 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites@2x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites@2x.png new file mode 100644 index 0000000000..06ad523d13 Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites@2x.png differ diff --git a/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites@3x.png b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites@3x.png new file mode 100644 index 0000000000..5f1d13a29e Binary files /dev/null and b/mobile/ios/Client/Frontend/Menu/Menu.xcassets/menu-panel-TopSites.imageset/topsites@3x.png differ diff --git a/mobile/ios/Client/Frontend/Metadata Parsing/MetadataHelper.js b/mobile/ios/Client/Frontend/Metadata Parsing/MetadataHelper.js new file mode 100644 index 0000000000..e01bec44b3 --- /dev/null +++ b/mobile/ios/Client/Frontend/Metadata Parsing/MetadataHelper.js @@ -0,0 +1,76 @@ +/* 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/. */ + +(function() { +"use strict"; + +if (!window.__firefox__) { + Object.defineProperty(window, '__firefox__', { + enumerable: false, + configurable: false, + writable: false, + value: {} + }); +} + +function MetadataWrapper(metadataparser) { + var dataURIRegex = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i; + + function isDataURI(s) { + return !!s.match(dataURIRegex); + } + + function getDataUri(url, callback) { + var image = new Image(); + image.onload = function() { + try { + var canvas = document.createElement('canvas'); + canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size + canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size + canvas.getContext('2d').drawImage(this, 0, 0); + var dataURI = canvas.toDataURL(); + callback(dataURI); + } catch (exception) { + callback(false); + } + }; + + image.src = url; + } + + function metadataCallback(metadata) { + window.__firefox__.pageMetadata = metadata; + webkit.messageHandlers.metadataMessageHandler.postMessage(metadata); + } + + this.extractMetadata = function() { + var metadata = metadataparser.getMetadata(window.document, document.URL); + var imageURL = metadata["image"]; + if (imageURL) { + if (isDataURI(imageURL)) { + metadata["image_data_uri"] = imageURL; + metadataCallback(metadata); + } else { + getDataUri(imageURL, function(dataURI) { + if (dataURI) { + metadata["image_data_uri"] = dataURI; + } + metadataCallback(metadata); + }); + } + } else { + metadataCallback(metadata); + } + }; +} + +Object.defineProperty(window.__firefox__, 'metadata', { + enumerable: false, + configurable: false, + writable: false, + value: Object.freeze(new MetadataWrapper(metadataparser)) +}); +metadataparser = undefined; + +})(); diff --git a/mobile/ios/Client/Frontend/Metadata Parsing/MetadataParserHelper.swift b/mobile/ios/Client/Frontend/Metadata Parsing/MetadataParserHelper.swift new file mode 100644 index 0000000000..ad258e0785 --- /dev/null +++ b/mobile/ios/Client/Frontend/Metadata Parsing/MetadataParserHelper.swift @@ -0,0 +1,55 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import WebKit + +private let log = Logger.browserLogger + +class MetadataParserHelper: TabContentScript { + private weak var tab: Tab? + private let profile: Profile + + class func name() -> String { + return "MetadataParserHelper" + } + + required init(tab: Tab, profile: Profile) { + self.tab = tab + self.profile = profile + + tab.injectUserScriptWith(fileName: "page-metadata-parser") + tab.injectUserScriptWith(fileName: "MetadataHelper") + } + + func scriptMessageHandlerName() -> String? { + return "metadataMessageHandler" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + // Get the metadata out of the page-metadata-parser, and into a type safe struct as soon + // as possible. + guard let dict = message.body as? [String: Any], + let tab = self.tab, + let pageURL = tab.url?.displayURL, + let pageMetadata = PageMetadata.fromDictionary(dict) else { + log.debug("Page contains no metadata!") + return + } + + let userInfo: [String: Any] = [ + "isPrivate": self.tab?.isPrivate ?? true, + "pageMetadata": pageMetadata, + "tabURL": pageURL + ] + + tab.pageMetadata = pageMetadata + + TabEvent.post(.didLoadPageMetadata(pageMetadata), for: tab) + NotificationCenter.default.post(name: NotificationOnPageMetadataFetched, object: nil, userInfo: userInfo) + } +} diff --git a/mobile/ios/Client/Frontend/Metadata Parsing/page-metadata-parser.js b/mobile/ios/Client/Frontend/Metadata Parsing/page-metadata-parser.js new file mode 100644 index 0000000000..78b10d3e29 --- /dev/null +++ b/mobile/ios/Client/Frontend/Metadata Parsing/page-metadata-parser.js @@ -0,0 +1 @@ +var metadataparser=function(t){function r(e){if(n[e])return n[e].exports;var o=n[e]={exports:{},id:e,loaded:!1};return t[e].call(o.exports,o,o.exports,r),o.loaded=!0,o.exports}var n={};return r.m=t,r.c=n,r.p="",r(0)}([function(t,r,n){t.exports=n(1)},function(t,r,n){"use strict";function e(t){return t&&t.__esModule?t:{default:t}}function o(t){return t.replace(/www[a-zA-Z0-9]*\./,"").replace(".co.",".").split(".").slice(0,-1).join(" ")}function u(t){return function(r,n){for(var e=0,o=void 0,u=0;ue&&(e=x,o=f(m))}}catch(t){v=!0,y=t}finally{try{!l&&g.return&&g.return()}finally{if(v)throw y}}}}if(!o&&t.defaultValue&&(o=t.defaultValue(n)),o){if(t.processors){var j=!0,k=!1,M=void 0;try{for(var T,P=(0,s.default)(t.processors);!(j=(T=P.next()).done);j=!0){var E=T.value;o=E(o,n)}}catch(t){k=!0,M=t}finally{try{!j&&P.return&&P.return()}finally{if(k)throw M}}}return o.trim&&(o=o.trim()),o}}}function i(t,r,n){var e={},o={url:r},i=n||m;return(0,f.default)(i).map(function(r){var n=i[r],c=u(n);e[r]=c(t,o)}),e}var c=n(2),f=e(c),a=n(37),s=e(a),l=n(59),p=e(l),v=n(66),d=e(v),y=n(70),h=y.makeUrlAbsolute,g=y.parseUrl,m={description:{rules:[['meta[property="og:description"]',function(t){return t.getAttribute("content")}],['meta[name="description"]',function(t){return t.getAttribute("content")}]]},icon:{rules:[['link[rel="apple-touch-icon"]',function(t){return t.getAttribute("href")}],['link[rel="apple-touch-icon-precomposed"]',function(t){return t.getAttribute("href")}],['link[rel="icon"]',function(t){return t.getAttribute("href")}],['link[rel="fluid-icon"]',function(t){return t.getAttribute("href")}],['link[rel="shortcut icon"]',function(t){return t.getAttribute("href")}],['link[rel="Shortcut Icon"]',function(t){return t.getAttribute("href")}],['link[rel="mask-icon"]',function(t){return t.getAttribute("href")}]],scorers:[function(t,r){var n=t.getAttribute("sizes");if(n){var e=n.match(/\d+/g);if(e)return e.reduce(function(t,r){return t*r})}}],defaultValue:function(t){return"favicon.ico"},processors:[function(t,r){return h(r.url,t)}]},image:{rules:[['meta[property="og:image:secure_url"]',function(t){return t.getAttribute("content")}],['meta[property="og:image:url"]',function(t){return t.getAttribute("content")}],['meta[property="og:image"]',function(t){return t.getAttribute("content")}],['meta[name="twitter:image"]',function(t){return t.getAttribute("content")}],['meta[property="twitter:image"]',function(t){return t.getAttribute("content")}],['meta[name="thumbnail"]',function(t){return t.getAttribute("content")}]],processors:[function(t,r){return h(r.url,t)}]},keywords:{rules:[['meta[name="keywords"]',function(t){return t.getAttribute("content")}]],processors:[function(t,r){return t.split(",").map(function(t){return t.trim()})}]},title:{rules:[['meta[property="og:title"]',function(t){return t.getAttribute("content")}],['meta[name="twitter:title"]',function(t){return t.getAttribute("content")}],['meta[property="twitter:title"]',function(t){return t.getAttribute("content")}],['meta[name="hdl"]',function(t){return t.getAttribute("content")}],["title",function(t){return t.text}]]},type:{rules:[['meta[property="og:type"]',function(t){return t.getAttribute("content")}]]},url:{rules:[["a.amp-canurl",function(t){return t.getAttribute("href")}],['meta[property="og:url"]',function(t){return t.getAttribute("content")}],['link[rel="canonical"]',function(t){return t.getAttribute("href")}]],defaultValue:function(t){return t.url},processors:[function(t,r){return h(r.url,t)}]},provider:{rules:[['meta[property="og:site_name"]',function(t){return t.getAttribute("content")}]],defaultValue:function(t){return o(g(t.url))}}};t.exports={buildRuleSet:u,getMetadata:i,getProvider:o,metadataRuleSets:m}},function(t,r,n){t.exports={default:n(3),__esModule:!0}},function(t,r,n){n(4),t.exports=n(24).Object.keys},function(t,r,n){var e=n(5),o=n(7);n(22)("keys",function(){return function(t){return o(e(t))}})},function(t,r,n){var e=n(6);t.exports=function(t){return Object(e(t))}},function(t,r){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},function(t,r,n){var e=n(8),o=n(21);t.exports=Object.keys||function(t){return e(t,o)}},function(t,r,n){var e=n(9),o=n(10),u=n(13)(!1),i=n(17)("IE_PROTO");t.exports=function(t,r){var n,c=o(t),f=0,a=[];for(n in c)n!=i&&e(c,n)&&a.push(n);for(;r.length>f;)e(c,n=r[f++])&&(~u(a,n)||a.push(n));return a}},function(t,r){var n={}.hasOwnProperty;t.exports=function(t,r){return n.call(t,r)}},function(t,r,n){var e=n(11),o=n(6);t.exports=function(t){return e(o(t))}},function(t,r,n){var e=n(12);t.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==e(t)?t.split(""):Object(t)}},function(t,r){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,r,n){var e=n(10),o=n(14),u=n(16);t.exports=function(t){return function(r,n,i){var c,f=e(r),a=o(f.length),s=u(i,a);if(t&&n!=n){for(;a>s;)if(c=f[s++],c!=c)return!0}else for(;a>s;s++)if((t||s in f)&&f[s]===n)return t||s||0;return!t&&-1}}},function(t,r,n){var e=n(15),o=Math.min;t.exports=function(t){return t>0?o(e(t),9007199254740991):0}},function(t,r){var n=Math.ceil,e=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?e:n)(t)}},function(t,r,n){var e=n(15),o=Math.max,u=Math.min;t.exports=function(t,r){return t=e(t),t<0?o(t+r,0):u(t,r)}},function(t,r,n){var e=n(18)("keys"),o=n(20);t.exports=function(t){return e[t]||(e[t]=o(t))}},function(t,r,n){var e=n(19),o="__core-js_shared__",u=e[o]||(e[o]={});t.exports=function(t){return u[t]||(u[t]={})}},function(t,r){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(t,r){var n=0,e=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+e).toString(36))}},function(t,r){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(t,r,n){var e=n(23),o=n(24),u=n(33);t.exports=function(t,r){var n=(o.Object||{})[t]||Object[t],i={};i[t]=r(n),e(e.S+e.F*u(function(){n(1)}),"Object",i)}},function(t,r,n){var e=n(19),o=n(24),u=n(25),i=n(27),c="prototype",f=function(t,r,n){var a,s,l,p=t&f.F,v=t&f.G,d=t&f.S,y=t&f.P,h=t&f.B,g=t&f.W,m=v?o:o[r]||(o[r]={}),x=m[c],b=v?e:d?e[r]:(e[r]||{})[c];v&&(n=r);for(a in n)s=!p&&b&&void 0!==b[a],s&&a in m||(l=s?b[a]:n[a],m[a]=v&&"function"!=typeof b[a]?n[a]:h&&s?u(l,e):g&&b[a]==l?function(t){var r=function(r,n,e){if(this instanceof t){switch(arguments.length){case 0:return new t;case 1:return new t(r);case 2:return new t(r,n)}return new t(r,n,e)}return t.apply(this,arguments)};return r[c]=t[c],r}(l):y&&"function"==typeof l?u(Function.call,l):l,y&&((m.virtual||(m.virtual={}))[a]=l,t&f.R&&x&&!x[a]&&i(x,a,l)))};f.F=1,f.G=2,f.S=4,f.P=8,f.B=16,f.W=32,f.U=64,f.R=128,t.exports=f},function(t,r){var n=t.exports={version:"2.5.1"};"number"==typeof __e&&(__e=n)},function(t,r,n){var e=n(26);t.exports=function(t,r,n){if(e(t),void 0===r)return t;switch(n){case 1:return function(n){return t.call(r,n)};case 2:return function(n,e){return t.call(r,n,e)};case 3:return function(n,e,o){return t.call(r,n,e,o)}}return function(){return t.apply(r,arguments)}}},function(t,r){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},function(t,r,n){var e=n(28),o=n(36);t.exports=n(32)?function(t,r,n){return e.f(t,r,o(1,n))}:function(t,r,n){return t[r]=n,t}},function(t,r,n){var e=n(29),o=n(31),u=n(35),i=Object.defineProperty;r.f=n(32)?Object.defineProperty:function(t,r,n){if(e(t),r=u(r,!0),e(n),o)try{return i(t,r,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(t[r]=n.value),t}},function(t,r,n){var e=n(30);t.exports=function(t){if(!e(t))throw TypeError(t+" is not an object!");return t}},function(t,r){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,r,n){t.exports=!n(32)&&!n(33)(function(){return 7!=Object.defineProperty(n(34)("div"),"a",{get:function(){return 7}}).a})},function(t,r,n){t.exports=!n(33)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(t,r){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,r,n){var e=n(30),o=n(19).document,u=e(o)&&e(o.createElement);t.exports=function(t){return u?o.createElement(t):{}}},function(t,r,n){var e=n(30);t.exports=function(t,r){if(!e(t))return t;var n,o;if(r&&"function"==typeof(n=t.toString)&&!e(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!e(o=n.call(t)))return o;if(!r&&"function"==typeof(n=t.toString)&&!e(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,r){t.exports=function(t,r){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:r}}},function(t,r,n){t.exports={default:n(38),__esModule:!0}},function(t,r,n){n(39),n(54),t.exports=n(56)},function(t,r,n){n(40);for(var e=n(19),o=n(27),u=n(43),i=n(52)("toStringTag"),c="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),f=0;f=t.length?(this._t=void 0,o(1)):"keys"==r?o(0,n):"values"==r?o(0,t[n]):o(0,[n,t[n]])},"values"),u.Arguments=u.Array,e("keys"),e("values"),e("entries")},function(t,r){t.exports=function(){}},function(t,r){t.exports=function(t,r){return{value:r,done:!!t}}},function(t,r){t.exports={}},function(t,r,n){"use strict";var e=n(45),o=n(23),u=n(46),i=n(27),c=n(9),f=n(43),a=n(47),s=n(51),l=n(53),p=n(52)("iterator"),v=!([].keys&&"next"in[].keys()),d="@@iterator",y="keys",h="values",g=function(){return this};t.exports=function(t,r,n,m,x,b,A){a(n,r,m);var w,S,_,O=function(t){if(!v&&t in M)return M[t];switch(t){case y:return function(){return new n(this,t)};case h:return function(){return new n(this,t)}}return function(){return new n(this,t)}},L=r+" Iterator",j=x==h,k=!1,M=t.prototype,T=M[p]||M[d]||x&&M[x],P=T||O(x),E=x?j?O("entries"):P:void 0,R="Array"==r?M.entries||T:T;if(R&&(_=l(R.call(new t)),_!==Object.prototype&&_.next&&(s(_,L,!0),e||c(_,p)||i(_,p,g))),j&&T&&T.name!==h&&(k=!0,P=function(){return T.call(this)}),e&&!A||!v&&!k&&M[p]||i(M,p,P),f[r]=P,f[L]=g,x)if(w={values:j?P:O(h),keys:b?P:O(y),entries:E},A)for(S in w)S in M||u(M,S,w[S]);else o(o.P+o.F*(v||k),r,w);return w}},function(t,r){t.exports=!0},function(t,r,n){t.exports=n(27)},function(t,r,n){"use strict";var e=n(48),o=n(36),u=n(51),i={};n(27)(i,n(52)("iterator"),function(){return this}),t.exports=function(t,r,n){t.prototype=e(i,{next:o(1,n)}),u(t,r+" Iterator")}},function(t,r,n){var e=n(29),o=n(49),u=n(21),i=n(17)("IE_PROTO"),c=function(){},f="prototype",a=function(){var t,r=n(34)("iframe"),e=u.length,o="<",i=">";for(r.style.display="none",n(50).appendChild(r),r.src="javascript:",t=r.contentWindow.document,t.open(),t.write(o+"script"+i+"document.F=Object"+o+"/script"+i),t.close(),a=t.F;e--;)delete a[f][u[e]];return a()};t.exports=Object.create||function(t,r){var n;return null!==t?(c[f]=e(t),n=new c,c[f]=null,n[i]=t):n=a(),void 0===r?n:o(n,r)}},function(t,r,n){var e=n(28),o=n(29),u=n(7);t.exports=n(32)?Object.defineProperties:function(t,r){o(t);for(var n,i=u(r),c=i.length,f=0;c>f;)e.f(t,n=i[f++],r[n]);return t}},function(t,r,n){var e=n(19).document;t.exports=e&&e.documentElement},function(t,r,n){var e=n(28).f,o=n(9),u=n(52)("toStringTag");t.exports=function(t,r,n){t&&!o(t=n?t:t.prototype,u)&&e(t,u,{configurable:!0,value:r})}},function(t,r,n){var e=n(18)("wks"),o=n(20),u=n(19).Symbol,i="function"==typeof u,c=t.exports=function(t){return e[t]||(e[t]=i&&u[t]||(i?u:o)("Symbol."+t))};c.store=e},function(t,r,n){var e=n(9),o=n(5),u=n(17)("IE_PROTO"),i=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=o(t),e(t,u)?t[u]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?i:null}},function(t,r,n){"use strict";var e=n(55)(!0);n(44)(String,"String",function(t){this._t=String(t),this._i=0},function(){var t,r=this._t,n=this._i;return n>=r.length?{value:void 0,done:!0}:(t=e(r,n),this._i+=t.length,{value:t,done:!1})})},function(t,r,n){var e=n(15),o=n(6);t.exports=function(t){return function(r,n){var u,i,c=String(o(r)),f=e(n),a=c.length;return f<0||f>=a?t?"":void 0:(u=c.charCodeAt(f),u<55296||u>56319||f+1===a||(i=c.charCodeAt(f+1))<56320||i>57343?t?c.charAt(f):u:t?c.slice(f,f+2):(u-55296<<10)+(i-56320)+65536)}}},function(t,r,n){var e=n(29),o=n(57);t.exports=n(24).getIterator=function(t){var r=o(t);if("function"!=typeof r)throw TypeError(t+" is not iterable!");return e(r.call(t))}},function(t,r,n){var e=n(58),o=n(52)("iterator"),u=n(43);t.exports=n(24).getIteratorMethod=function(t){if(void 0!=t)return t[o]||t["@@iterator"]||u[e(t)]}},function(t,r,n){var e=n(12),o=n(52)("toStringTag"),u="Arguments"==e(function(){return arguments}()),i=function(t,r){try{return t[r]}catch(t){}};t.exports=function(t){var r,n,c;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=i(r=Object(t),o))?n:u?e(r):"Object"==(c=e(r))&&"function"==typeof r.callee?"Arguments":c}},function(t,r,n){t.exports={default:n(60),__esModule:!0}},function(t,r,n){n(54),n(61),t.exports=n(24).Array.from},function(t,r,n){"use strict";var e=n(25),o=n(23),u=n(5),i=n(62),c=n(63),f=n(14),a=n(64),s=n(57);o(o.S+o.F*!n(65)(function(t){Array.from(t)}),"Array",{from:function(t){var r,n,o,l,p=u(t),v="function"==typeof this?this:Array,d=arguments.length,y=d>1?arguments[1]:void 0,h=void 0!==y,g=0,m=s(p);if(h&&(y=e(y,d>2?arguments[2]:void 0,2)),void 0==m||v==Array&&c(m))for(r=f(p.length),n=new v(r);r>g;g++)a(n,g,h?y(p[g],g):p[g]);else for(l=m.call(p),n=new v;!(o=l.next()).done;g++)a(n,g,h?i(l,y,[o.value,g],!0):o.value);return n.length=g,n}})},function(t,r,n){var e=n(29);t.exports=function(t,r,n,o){try{return o?r(e(n)[0],n[1]):r(n)}catch(r){var u=t.return;throw void 0!==u&&e(u.call(t)),r}}},function(t,r,n){var e=n(43),o=n(52)("iterator"),u=Array.prototype;t.exports=function(t){return void 0!==t&&(e.Array===t||u[o]===t)}},function(t,r,n){"use strict";var e=n(28),o=n(36);t.exports=function(t,r,n){r in t?e.f(t,r,o(0,n)):t[r]=n}},function(t,r,n){var e=n(52)("iterator"),o=!1;try{var u=[7][e]();u.return=function(){o=!0},Array.from(u,function(){throw 2})}catch(t){}t.exports=function(t,r){if(!r&&!o)return!1;var n=!1;try{var u=[7],i=u[e]();i.next=function(){return{done:n=!0}},u[e]=function(){return i},t(u)}catch(t){}return n}},function(t,r,n){"use strict";function e(t){return t&&t.__esModule?t:{default:t}}r.__esModule=!0;var o=n(67),u=e(o),i=n(37),c=e(i);r.default=function(){function t(t,r){var n=[],e=!0,o=!1,u=void 0;try{for(var i,f=(0,c.default)(t);!(e=(i=f.next()).done)&&(n.push(i.value),!r||n.length!==r);e=!0);}catch(t){o=!0,u=t}finally{try{!e&&f.return&&f.return()}finally{if(o)throw u}}return n}return function(r,n){if(Array.isArray(r))return r;if((0,u.default)(Object(r)))return t(r,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}()},function(t,r,n){t.exports={default:n(68),__esModule:!0}},function(t,r,n){n(39),n(54),t.exports=n(69)},function(t,r,n){var e=n(58),o=n(52)("iterator"),u=n(43);t.exports=n(24).isIterable=function(t){var r=Object(t);return void 0!==r[o]||"@@iterator"in r||u.hasOwnProperty(e(r))}},function(t,r,n){(function(r){"use strict";if(void 0!==r.URL)t.exports={makeUrlAbsolute:function(t,r){return new URL(r,t).href},parseUrl:function(t){return new URL(t).host}};else{var e=n(71);t.exports={makeUrlAbsolute:function(t,r){var n=e.parse(r);return null===n.host?e.resolve(t,r):r},parseUrl:function(t){return e.parse(t).hostname}}}}).call(r,function(){return this}())},function(t,r){t.exports=window}]); \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/OldStrings.swift b/mobile/ios/Client/Frontend/OldStrings.swift new file mode 100644 index 0000000000..6169ebe2cb --- /dev/null +++ b/mobile/ios/Client/Frontend/OldStrings.swift @@ -0,0 +1,65 @@ +/* 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/. */ + +import Foundation + +/// These were supposed to be strings for prelanded features, but they've been sitting here for awhile. +/// We should audit and remove them (bug 1262956). +/// NOTE: DO NOT LAND NEW STRINGS HERE! Land them in Shared/Strings.swift instead. +private func prelandedStrings() { + // Bug 1182303 - Checkbox to block alert spam. + _ = NSLocalizedString("Disable additional page dialogs", comment: "Pending feature; currently unused string! Checkbox label shown after multiple alerts are shown") + + // Bug 1186013 - Prompt for going to clipboard URL + _ = NSLocalizedString("Go to copied URL?", comment: "Pending feature; currently unused string! Prompt message shown when browser is opened with URL on the clipboard") + _ = NSLocalizedString("Go", comment: "Pending feature; currently unused string! Button to browse to URL on the clipboard when browser is opened") + + // strings for lightweight themes + _ = NSLocalizedString("Theme", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Settings row to enter theme settings") + _ = NSLocalizedString("Themes", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! sub header for theme options in theme chooser") + _ = NSLocalizedString("Photos", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Sub header for photo options in theme chooser") + _ = NSLocalizedString("Preview", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Button to show preview of selected theme") + _ = NSLocalizedString("Set", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Button to set selected theme as current theme") + _ = NSLocalizedString("Allow Firefox to use my Photos", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Button shown when user wishes to view photos for theme but has not given Firefox permission to do so yet.") + _ = NSLocalizedString("Choose", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Back button shown to return back to theme settings from photo picker") + + // accessibility strings for lightweight themes + _ = NSLocalizedString("Choose Theme", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Accessibility label for settings row to enter theme settings") + _ = NSLocalizedString("Default Themes", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Accessibility label for themes subheader") + _ = NSLocalizedString("My Photos", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Accessibility label for photo viewer") + _ = NSLocalizedString("Preview Theme", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Accessibility label for theme preview button") + _ = NSLocalizedString("Set Theme", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Accessibility label for set theme button") + _ = NSLocalizedString("Back to Themes", tableName: "LightweightThemes", comment: "Pending feature; currently unused string! Accessibility label for back button to theme chooser") + + // Bug 1198418 - Touch ID Passcode Strings + _ = NSLocalizedString("Turn off your passcode.", tableName: "AuthenticationManager", comment: "Touch ID prompt subtitle when turning off passcode") + _ = NSLocalizedString("Use your fingerprint to access Private Browsing now.", tableName: "AuthenticationManager", comment: "Touch ID prompt subtitle when accessing private browsing") +} + +/// Old strings that will be removed in a future version. We keep these around for l10n backwards compatibility. +private func obsoleteStrings() { + // v1.0 + _ = NSLocalizedString("Browse multiple Web pages at the same time with tabs.", tableName: "Intro", comment: "See http://mzl.la/1T8gxwo") + _ = NSLocalizedString("Personalize your Firefox just the way you like in Settings.", tableName: "Intro", comment: "See http://mzl.la/1T8gxwo") + _ = NSLocalizedString("Connect Firefox everywhere you use it.", tableName: "Intro", comment: "See http://mzl.la/1T8gxwo") + _ = NSLocalizedString("Show search suggestions", comment: "Label for show search suggestions setting.") + _ = NSLocalizedString("Sign in", comment: "Text message / button in the settings table view") + + // v3.0 + _ = NSLocalizedString("History will be removed from all your connected devices. This cannot be undone.", tableName: "ClearHistoryConfirm", comment: "Description of the confirmation dialog shown when a user tries to clear history that's synced to another device.") + _ = NSLocalizedString("Remove history from your Firefox Account?", tableName: "ClearHistoryConfirm", comment: "Title of the confirmation dialog shown when a user tries to clear history that's synced to another device.") + _ = NSLocalizedString("Clear", tableName: "ClearHistoryConfirm", comment: "The button that clears history even when Sync is connected.") + _ = NSLocalizedString("Clear Private Data", comment: "Label used as an item in Settings. When touched it will open a dialog prompting the user to make sure they want to clear all of their private data.") + _ = NSLocalizedString("Clear Private Data", tableName: "ClearPrivateData", comment: "Navigation title in settings.") + _ = NSLocalizedString("Clear Private Data", tableName: "ClearPrivateData", comment: "Button in settings that clears private data for the selected items.") + _ = NSLocalizedString("Opening %@", comment: "Opening an external URL") + _ = NSLocalizedString("This will open in another application", comment: "Opening an external app") + _ = NSLocalizedString("Not now", comment: "Button to not save the user's password") + _ = NSLocalizedString("Update", comment: "Button to update the user's password") + _ = NSLocalizedString("Yes", comment: "Button to save the user's password") + _ = NSLocalizedString("Do you want to save the password for %@ on %@?", comment: "Prompt for saving a password. The first parameter is the username being saved. The second parameter is the hostname of the site.") + _ = NSLocalizedString("Do you want to save the password on %@?", comment: "Prompt for saving a password with no username. The parameter is the hostname of the site.") + _ = NSLocalizedString("Do you want to update the password for %@ on %@?", comment: "Prompt for updating a password. The first parameter is the username being saved. The second parameter is the hostname of the site.") + _ = NSLocalizedString("Do you want to update the password on %@?", comment: "Prompt for updating a password with on username. The parameter is the hostname of the site.") +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Reader/FSReadingList.h b/mobile/ios/Client/Frontend/Reader/FSReadingList.h new file mode 100644 index 0000000000..1df191d029 --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/FSReadingList.h @@ -0,0 +1,7 @@ +/* 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/. */ + +#pragma once + +extern NSString* const FSReadingListAddReadingListItemNotification; diff --git a/mobile/ios/Client/Frontend/Reader/FSReadingList.m b/mobile/ios/Client/Frontend/Reader/FSReadingList.m new file mode 100644 index 0000000000..719c9ce214 --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/FSReadingList.m @@ -0,0 +1,60 @@ +/* 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/. */ + +#import +#import + +#import "Swizzling.h" + +NSString* const FSReadingListAddReadingListItemNotification = @"FSReadingListAddReadingListItemNotification"; + +@interface FSReadingList: NSObject ++ (id) sharedInstance; ++ (BOOL)supportsURL:(NSURL *)URL; +- (BOOL)addReadingListItemWithURL:(NSURL *)URL title:(NSString *)title previewText:(NSString *)previewText error:(NSError **)error; +@end + +@implementation FSReadingList ++ (id) sharedInstance { + static FSReadingList *sharedFSReadingList = nil; + @synchronized (self) { + if (sharedFSReadingList == nil) { + sharedFSReadingList = [FSReadingList new]; + } + } + return sharedFSReadingList; +} + ++ (BOOL)supportsURL:(NSURL *)URL { + return [[URL scheme] isEqualToString: @"http"] || [[URL scheme] isEqualToString: @"https"]; +} + +- (BOOL)addReadingListItemWithURL:(NSURL *)URL title:(NSString *)title previewText:(NSString *)previewText error:(NSError **)error { + if (error != NULL) { + *error = nil; + } + // To keep this as simple as possible and have as little as possible coupling between this Objective-C + // singleton and our Swift world, we simply send out a notification that our AppDelegate (which has access + // to the browser profile and reading list service) can respond to. + [[NSNotificationCenter defaultCenter] postNotificationName: FSReadingListAddReadingListItemNotification + object:self userInfo: @{@"URL": URL, @"Title": title}]; + return YES; +} +@end + +// This class extension on SSReadingList implements an initialize method that will be called when the class +// is instantiated. It swizzles defaultReadingList to our own implementation which returns a shared instance +// of the FSReadingList. ("FirefoxServices" Reading List) + +@implementation SSReadingList (Firefox) ++ (void) initialize { + if ([SSReadingList class] == self) { + SwizzleClassMethods([SSReadingList class], @selector(defaultReadingList), @selector(defaultFSReadingList)); + } +} + ++ (id) defaultFSReadingList { + return [FSReadingList sharedInstance]; +} +@end diff --git a/mobile/ios/Client/Frontend/Reader/ReadabilityService.swift b/mobile/ios/Client/Frontend/Reader/ReadabilityService.swift new file mode 100644 index 0000000000..70b394c543 --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReadabilityService.swift @@ -0,0 +1,112 @@ +/* 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/. */ + +import Foundation +import WebKit + +private let ReadabilityServiceSharedInstance = ReadabilityService() + +private let ReadabilityTaskDefaultTimeout = 15 +private let ReadabilityServiceDefaultConcurrency = 1 + +enum ReadabilityOperationResult { + case success(ReadabilityResult) + case error(NSError) + case timeout +} + +class ReadabilityOperation: Operation, WKNavigationDelegate, ReadabilityTabHelperDelegate { + var url: URL + var semaphore: DispatchSemaphore + var result: ReadabilityOperationResult? + var tab: Tab! + var readerModeCache: ReaderModeCache + + init(url: URL, readerModeCache: ReaderModeCache) { + self.url = url + self.semaphore = DispatchSemaphore(value: 0) + self.readerModeCache = readerModeCache + } + + override func main() { + if self.isCancelled { + return + } + + // Setup a tab, attach a Readability helper. Kick all this off on the main thread since UIKit + // and WebKit are not safe from other threads. + + DispatchQueue.main.async(execute: { () -> Void in + let configuration = WKWebViewConfiguration() + self.tab = Tab(configuration: configuration) + self.tab.createWebview() + self.tab.navigationDelegate = self + + if let readabilityTabHelper = ReadabilityTabHelper(tab: self.tab) { + readabilityTabHelper.delegate = self + self.tab.addContentScript(readabilityTabHelper, name: ReadabilityTabHelper.name()) + } + + // Load the page in the webview. This either fails with a navigation error, or we get a readability + // callback. Or it takes too long, in which case the semaphore times out. + self.tab.loadRequest(URLRequest(url: self.url)) + }) + let timeout = DispatchTime.now() + Double(Int64(Double(16) * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + if semaphore.wait(timeout: timeout) == .timedOut { + result = ReadabilityOperationResult.timeout + } + + // Maybe this is where we should store stuff in the cache / run a callback? + + if let result = self.result { + switch result { + case .timeout: + // Don't do anything on timeout + break + case .success(let readabilityResult): + do { + try readerModeCache.put(url, readabilityResult) + } catch let error as NSError { + print("Failed to store readability results in the cache: \(error.localizedDescription)") + // TODO Fail + } + case .error(_): + // TODO Not entitely sure what to do on error. Needs UX discussion and followup bug. + break + } + } + } + + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + result = ReadabilityOperationResult.error(error as NSError) + semaphore.signal() + } + + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + result = ReadabilityOperationResult.error(error as NSError) + semaphore.signal() + } + + func readabilityTabHelper(_ readabilityTabHelper: ReadabilityTabHelper, didFinishWithReadabilityResult readabilityResult: ReadabilityResult) { + result = ReadabilityOperationResult.success(readabilityResult) + semaphore.signal() + } +} + +class ReadabilityService { + class var sharedInstance: ReadabilityService { + return ReadabilityServiceSharedInstance + } + + var queue: OperationQueue + + init() { + queue = OperationQueue() + queue.maxConcurrentOperationCount = ReadabilityServiceDefaultConcurrency + } + + func process(_ url: URL, cache: ReaderModeCache) { + queue.addOperation(ReadabilityOperation(url: url, readerModeCache: cache)) + } +} diff --git a/mobile/ios/Client/Frontend/Reader/ReadabilityTabHelper.js b/mobile/ios/Client/Frontend/Reader/ReadabilityTabHelper.js new file mode 100644 index 0000000000..3509fa3756 --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReadabilityTabHelper.js @@ -0,0 +1,30 @@ +/* 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/. */ + +(function() { + // To keep this file readable and Readability.js separate, since we import it from an external + // repository, we merge it in this file programatically. We do not include it as a user script + // because that means pages can mess with it; by including it below, it is part of an anonymous + // function that only exists once. + + %READABILITYJS% + + var uri = { + spec: document.location.href, + host: document.location.host, + prePath: document.location.protocol + "//" + document.location.host, // TODO This is incomplete, needs username/password and port + scheme: document.location.protocol.substr(0, document.location.protocol.indexOf(":")), + pathBase: document.location.protocol + "//" + document.location.host + location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1) + } + + // document.cloneNode() can cause the webview to break (bug 1128774). + // Serialize and then parse the document instead. + var docStr = new XMLSerializer().serializeToString(document); + var doc = new DOMParser().parseFromString(docStr, "text/html"); + + var readability = new Readability(uri, doc); + var readabilityResult = readability.parse(); + + webkit.messageHandlers.readabilityMessageHandler.postMessage(readabilityResult); +})(); diff --git a/mobile/ios/Client/Frontend/Reader/ReadabilityTabHelper.swift b/mobile/ios/Client/Frontend/Reader/ReadabilityTabHelper.swift new file mode 100644 index 0000000000..d649affbdb --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReadabilityTabHelper.swift @@ -0,0 +1,39 @@ +/* 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/. */ + +import Foundation +import WebKit + +protocol ReadabilityTabHelperDelegate { + func readabilityTabHelper(_ readabilityTabHelper: ReadabilityTabHelper, didFinishWithReadabilityResult result: ReadabilityResult) +} + +class ReadabilityTabHelper: TabContentScript { + var delegate: ReadabilityTabHelperDelegate? + + class func name() -> String { + return "ReadabilityTabHelper" + } + + init?(tab: Tab) { + if let readabilityPath = Bundle.main.path(forResource: "Readability", ofType: "js"), + let readabilitySource = try? NSMutableString(contentsOfFile: readabilityPath, encoding: String.Encoding.utf8.rawValue), + let readabilityTabHelperPath = Bundle.main.path(forResource: ReadabilityTabHelper.name(), ofType: "js"), + let readabilityTabHelperSource = try? NSMutableString(contentsOfFile: readabilityTabHelperPath, encoding: String.Encoding.utf8.rawValue) { + readabilityTabHelperSource.replaceOccurrences(of: "%READABILITYJS%", with: readabilitySource as String, options: NSString.CompareOptions.literal, range: NSRange(location: 0, length: readabilityTabHelperSource.length)) + let userScript = WKUserScript(source: readabilityTabHelperSource as String, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + + func scriptMessageHandlerName() -> String? { + return "readabilityMessageHandler" + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + if let readabilityResult = ReadabilityResult(object: message.body as AnyObject?) { + delegate?.readabilityTabHelper(self, didFinishWithReadabilityResult: readabilityResult) + } + } +} diff --git a/mobile/ios/Client/Frontend/Reader/Reader.css b/mobile/ios/Client/Frontend/Reader/Reader.css new file mode 100644 index 0000000000..a70fdda48f --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/Reader.css @@ -0,0 +1,787 @@ +/* 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/. */ + +@font-face { + font-family: sans-serif; + src: url('/reader-mode/fonts/FiraSans-Regular.ttf'); +} + +@font-face { + font-family: sans-serif; + src: url('/reader-mode/fonts/FiraSans-Book.ttf'); + font-weight: medium; + } + +@font-face { + font-family: sans-serif; + src: url('/reader-mode/fonts/FiraSans-Bold.ttf'); + font-weight: bold; +} + +@font-face { + font-family: sans-serif; + src: url('/reader-mode/fonts/FiraSans-Italic.ttf'); + font-style: italic; +} + +@font-face { + font-family: sans-serif; + src: url('/reader-mode/fonts/FiraSans-BoldItalic.ttf'); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: serif; + src: url('/reader-mode/fonts/CharisSILR.ttf'); +} + +@font-face { + font-family: serif; + src: url('/reader-mode/fonts/CharisSILB.ttf'); + font-weight: bold; +} + +@font-face { + font-family: serif; + src: url('/reader-mode/fonts/CharisSILI.ttf'); + font-style: italic; +} + +@font-face { + font-family: serif; + src: url('/reader-mode/fonts/CharisSILBI.ttf'); + font-weight: bold; + font-style: italic; +} + +html { + -moz-text-size-adjust: none; + -webkit-text-size-adjust: none; +} + +body { + padding: 2vw; + transition-property: background-color, color; + transition-duration: 0.4s; + margin-left: auto; + margin-right: auto; +} + +.light { + background-color: #ffffff; + color: #222222; +} + +.dark { + background-color: #333333; + color: #eeeeee; +} + +.sepia { + background-color: #F0E6DC; + color: #333333; +} + +.sans-serif { + font-family: sans-serif; +} + +.serif { + font-family: serif; +} + +.message { + margin-top: 40px; + display: none; + text-align: center; + width: 100%; + font-size: 16px; +} + +#reader-header { + text-align: start; + display: none; +} + +.domain, +.credits { + font-family: sans-serif; +} + +.domain { + margin-top: 10px; + padding-bottom: 10px; + color: #00acff !important; + text-decoration: none; +} + +.domain-border { + margin-top: 15px; + border-bottom: 1.5px solid #777777; + width: 50%; +} + +.header > h1 { + font-size: 1.5em; + font-weight: 700; + line-height: 1.1em; + width: 100%; + margin: 0px; + margin-top: 0px; + margin-bottom: 16px; + padding: 0px; +} + +.header > .credits { + padding: 0px; + margin: 0px; + margin-bottom: 24px; + font-style: italic; +} + +.light > .header > .domain { + color: #ee7600; + border-bottom-color: #d0d0d0; +} + +.light > .header > h1 { + color: #222222; +} + +.light > .header > .credits { + color: #333333; +} + +.dark > .header > .domain { + color: #ff9400; + border-bottom-color: #777777; +} + +.dark > .header > h1 { + color: #eeeeee; +} + +.dark > .header > .credits { + color: #aaaaaa; +} + +.font-size1 > .header > h1 { + font-size: 24px; +} + +.font-size2 > .header > h1 { + font-size: 28px; +} + +.font-size3 > .header > h1 { + font-size: 32px; +} + +.font-size4 > .header > h1 { + font-size: 36px; +} + +.font-size5 > .header > h1 { + font-size: 40px; +} + +.font-size6 > .header > h1 { + font-size: 44px; +} + +.font-size7 > .header > h1 { + font-size: 48px; +} + +.font-size8 > .header > h1 { + font-size: 52px; +} + +.font-size9 > .header > h1 { + font-size: 56px; +} + +.font-size10 > .header > h1 { + font-size: 60px; +} + +.font-size11 > .header > h1 { + font-size: 64px; +} + +.font-size12 > .header > h1 { + font-size: 68px; +} + +.font-size13 > .header > h1 { + font-size: 72px; +} + +/* This covers caption, domain, and credits + texts in the reader UI */ + +.font-size1 > .content .wp-caption-text, +.font-size1 > .content figcaption, +.font-size1 > .header > .domain, +.font-size1 > .header > .credits { + font-size: 12px; +} + +.font-size2 > .content .wp-caption-text, +.font-size2 > .content figcaption, +.font-size2 > .header > .domain, +.font-size2 > .header > .credits { + font-size: 14px; +} + +.font-size3 > .content .wp-caption-text, +.font-size3 > .content figcaption, +.font-size3 > .header > .domain, +.font-size3 > .header > .credits { + font-size: 16px; +} + +.font-size4 > .content .wp-caption-text, +.font-size4 > .content figcaption, +.font-size4 > .header > .domain, +.font-size4 > .header > .credits { + font-size: 18px; +} + +.font-size5 > .content .wp-caption-text, +.font-size5 > .content figcaption, +.font-size5 > .header > .domain, +.font-size5 > .header > .credits { + font-size: 20px; +} + +.font-size6 > .content .wp-caption-text, +.font-size6 > .content figcaption, +.font-size6 > .header > .domain, +.font-size6 > .header > .credits { + font-size: 22px; +} + +.font-size7 > .content .wp-caption-text, +.font-size7 > .content figcaption, +.font-size7 > .header > .domain, +.font-size7 > .header > .credits { + font-size: 25px; +} + +.font-size8 > .content .wp-caption-text, +.font-size8 > .content figcaption, +.font-size8 > .header > .domain, +.font-size8 > .header > .credits { + font-size: 28px; +} + +.font-size9 > .content .wp-caption-text, +.font-size9 > .content figcaption, +.font-size9 > .header > .domain, +.font-size9 > .header > .credits { + font-size: 31px; +} + +.font-size10 > .content .wp-caption-text, +.font-size10 > .content figcaption, +.font-size10 > .header > .domain, +.font-size10 > .header > .credits { + font-size: 35px; +} + +.font-size11 > .content .wp-caption-text, +.font-size11 > .content figcaption, +.font-size11 > .header > .domain, +.font-size11 > .header > .credits { + font-size: 40px; +} + +.font-size12 > .content .wp-caption-text, +.font-size12 > .content figcaption, +.font-size12 > .header > .domain, +.font-size12 > .header > .credits { + font-size: 45px; +} + +.font-size13 > .content .wp-caption-text, +.font-size13 > .content figcaption, +.font-size13 > .header > .domain, +.font-size13 > .header > .credits { + font-size: 50px; +} + +#reader-content { + display: none; +} + +.content a { + text-decoration: none !important; + font-weight: normal; +} + +.light > .content a, +.light > .content a:visited, +.light > .content a:hover, +.light > .content a:active { + color: #00acff !important; +} + +.dark > .content a, +.dark > .content a:visited, +.dark > .content a:hover, +.dark > .content a:active { + color: #00acff !important; +} + +.sepia > .content a, +.sepia > .content a:visited, +.sepia > .content a:hover, +.sepia > .content a:active { + color: #00acff !important; +} + +.content * { + max-width: 100% !important; + height: auto !important; +} + +.content p { + line-height: 1.4em !important; + margin: 0px !important; + margin-bottom: 20px !important; +} + +/* Covers all images showing edge-to-edge using a + an optional caption text */ +.content .wp-caption, +.content figure { + display: block !important; + width: 100% !important; + margin: 0px !important; + margin-bottom: 32px !important; +} + +/* Images marked to be shown edge-to-edge with an + optional captio ntext */ +.content p > img:only-child, +.content p > a:only-child > img:only-child, +.content .wp-caption img, +.content figure img { + max-width: none !important; + height: auto !important; + display: block !important; + margin-top: 0px !important; + margin-bottom: 32px !important; +} + +/* If image is place inside one of these blocks + there's no need to add margin at the bottom */ +.content .wp-caption img, +.content figure img { + margin-bottom: 0px !important; +} + +/* Image caption text */ +.content .caption, +.content .wp-caption-text, +.content figcaption { + font-family: sans-serif; + margin: 0px !important; + padding-top: 4px !important; +} + +.light > .content .caption, +.light > .content .wp-caption-text, +.light > .content figcaption { + color: #898989; +} + +.dark > .content .caption, +.dark > .content .wp-caption-text, +.dark > .content figcaption { + color: #aaaaaa; +} + +/* Ensure all pre-formatted code inside the reader content + are properly wrapped inside content width */ +.content code, +.content pre { + white-space: pre-wrap !important; + margin-bottom: 20px !important; + word-break: break-all; +} + +.content blockquote { + margin: 0px !important; + margin-bottom: 20px !important; + padding: 0px !important; + -moz-padding-start: 16px !important; + -webkit-padding-start: 16px !important; + border: 0px !important; + border-left: 2px solid !important; +} + +.light > .content blockquote { + color: #898989 !important; + border-left-color: #d0d0d0 !important; +} + +.dark > .content blockquote { + color: #aaaaaa !important; + border-left-color: #777777 !important; +} + +.content ul, +.content ol { + margin: 0px !important; + margin-bottom: 20px !important; + padding: 0px !important; + line-height: 1.5em; +} + +.content ul { + -moz-padding-start: 30px !important; + -webkit-padding-start: 30px !important; + list-style: disk !important; +} + +.content ol { + -moz-padding-start: 35px !important; + -webkit-padding-start: 35px !important; + list-style: decimal !important; +} + +.font-size1-sample, +.font-size1 > .content { + font-size: 10px !important; +} + +.font-size2-sample, +.font-size2 > .content { + font-size: 11px !important; +} + +.font-size3-sample, +.font-size3 > .content { + font-size: 12px !important; +} + +.font-size4-sample, +.font-size4 > .content { + font-size: 14px !important; +} + +.font-size5-sample, +.font-size5 > .content { + font-size: 16px !important; +} + +.font-size6-sample, +.font-size6 > .content { + font-size: 18px !important; +} + +.font-size7-sample, +.font-size7 > .content { + font-size: 21px !important; +} + +.font-size8-sample, +.font-size8 > .content { + font-size: 24px !important; +} + +.font-size9-sample, +.font-size9 > .content { + font-size: 28px !important; +} + +.font-size10-sample, +.font-size10 > .content { + font-size: 32px !important; +} + +.font-size11-sample, +.font-size11 > .content { + font-size: 37px !important; +} + +.font-size12-sample, +.font-size12 > .content { + font-size: 42px !important; +} + +.font-size13-sample, +.font-size13 > .content { + font-size: 48px !important; +} + +.toolbar { + font-family: "Clear Sans",sans-serif; + transition-property: visibility, opacity; + transition-duration: 0.7s; + visibility: visible; + opacity: 1.0; + position: fixed; + width: 100%; + bottom: 0px; + left: 0px; + margin: 0; + padding: 0; + list-style: none; + background-color: #EBEBF0; + -moz-user-select: none; +} + +.toolbar-hidden { + transition-property: visibility, opacity; + transition-duration: 0.7s; + visibility: hidden; + opacity: 0.0; +} + +.toolbar > * { + float: right; + width: 33%; +} + +.button { + color: white; + display: block; + background-position: center; + background-size: 30px 24px; + background-repeat: no-repeat; +} + +.dropdown { + text-align: center; + display: inline-block; + list-style: none; + margin: 0px; + padding: 0px; +} + +.dropdown li { + margin: 0px; + padding: 0px; +} + +.dropdown-toggle { + margin: 0px; + padding: 0px; +} + +.dropdown-popup { + text-align: start; + position: absolute; + left: 0px; + z-index: 1000; + float: left; + background: #EBEBF0; + margin-top: 12px; + margin-bottom: 10px; + padding-top: 4px; + padding-bottom: 8px; + font-size: 14px; + box-shadow: 0px -1px 12px #333; + border-radius: 3px; + visibility: hidden; +} + +.dropdown-popup > hr { + width: 100%; + height: 0px; + border: 0px; + border-top: 1px solid #B5B5B5; + margin: 0; +} + +.open > .dropdown-popup { + margin-top: 0px; + margin-bottom: 6px; + bottom: 100%; + visibility: visible; +} + +.dropdown-arrow { + position: absolute; + width: 40px; + height: 18px; + bottom: -18px; + background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-mdpi.png'); + background-size: 40px 18px; + background-position: center; + display: block; +} + +#font-type-buttons, +.segmented-button { + display: flex; + flex-direction: row; + list-style: none; + padding: 10px 5px; + white-space: nowrap; +} + +#font-type-buttons > li, +.segmented-button > li { + width: 50px; /* combined with flex, this acts as a minimum width */ + flex: 1 0 auto; + text-align: center; + line-height: 20px; +} + +#font-type-buttons > li { + padding: 10px 0; +} + +.segmented-button > li { + border-left: 1px solid #B5B5B5; +} + +.segmented-button > li:first-child { + border-left: 0px; +} + +#font-type-buttons > li > a, +.segmented-button > li > a { + vertical-align: middle; + text-decoration: none; + color: black; +} + +#font-type-buttons > li > a { + display: inline-block; + font-size: 48px; + line-height: 50px; + margin-bottom: 5px; + border-bottom: 3px solid transparent; +} + +.segmented-button > li > a { + display: block; + padding: 5px 0; + font-family: "Clear Sans",sans-serif; + font-weight: lighter; +} + +#font-type-buttons > li > a:active, +#font-type-buttons > li.selected > a { + border-color: #ff9400; +} + +.segmented-button > li > a:active, +.segmented-button > li.selected > a { + font-weight: bold; +} + +#font-type-buttons > li > .sans-serif { + font-weight: lighter; +} + +#font-type-buttons > li > div { + color: #666; + font-size: 12px; +} + +.toggle-button.on { + background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-mdpi.png'); +} + +.toggle-button { + background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-mdpi.png'); +} + +.share-button { + background-image: url('chrome://browser/skin/images/reader-share-icon-mdpi.png'); +} + +.style-button { + background-image: url('chrome://browser/skin/images/reader-style-icon-mdpi.png'); +} + +@media screen and (min-resolution: 1.25dppx) { + .dropdown-arrow { + background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-hdpi.png'); + } + + .step-control > .plus-button { + background-image: url('chrome://browser/skin/images/reader-plus-icon-hdpi.png'); + } + + .step-control > .minus-button { + background-image: url('chrome://browser/skin/images/reader-minus-icon-hdpi.png'); + } + + .toggle-button.on { + background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-hdpi.png'); + } + + .toggle-button { + background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-hdpi.png'); + } + + .share-button { + background-image: url('chrome://browser/skin/images/reader-share-icon-hdpi.png'); + } + + .style-button { + background-image: url('chrome://browser/skin/images/reader-style-icon-hdpi.png'); + } +} + +@media screen and (min-resolution: 2dppx) { + .dropdown-arrow { + background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-xhdpi.png'); + } + + .step-control > .plus-button { + background-image: url('chrome://browser/skin/images/reader-plus-icon-xhdpi.png'); + } + + .step-control > .minus-button { + background-image: url('chrome://browser/skin/images/reader-minus-icon-xhdpi.png'); + } + + .toggle-button.on { + background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xhdpi.png'); + } + + .toggle-button { + background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xhdpi.png'); + } + + .share-button { + background-image: url('chrome://browser/skin/images/reader-share-icon-xhdpi.png'); + } + + .style-button { + background-image: url('chrome://browser/skin/images/reader-style-icon-xhdpi.png'); + } +} + +@media screen and (orientation: portrait) { + .button { + height: 48px; + } +} + +@media screen and (orientation: landscape) { + .button { + height: 40px; + } +} + +@media screen and (min-width: 960px) { + .button { + width: 56px; + height: 56px; + } + + .toolbar > * { + width: 56px; + } +} diff --git a/mobile/ios/Client/Frontend/Reader/Reader.html b/mobile/ios/Client/Frontend/Reader/Reader.html new file mode 100644 index 0000000000..4685716703 --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/Reader.html @@ -0,0 +1,46 @@ + + + + + + + + + + %READER-TITLE% + + + +
+

%READER-TITLE%

+
%READER-CREDITS%
+
+ +
+ %READER-CONTENT% +
+ +
+ %READER-MESSAGE% +
+ +
    +
  • + +
  • +
+ + + + diff --git a/mobile/ios/Client/Frontend/Reader/ReaderMode.js b/mobile/ios/Client/Frontend/Reader/ReaderMode.js new file mode 100644 index 0000000000..dae82781cf --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReaderMode.js @@ -0,0 +1,222 @@ +/* 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/. */ + +(function() { + "use strict"; + + if (!window.__firefox__) { + Object.defineProperty(window, '__firefox__', { + enumerable: false, + configurable: false, + writable: false, + value: {} + }); + } + + var readabilityResult = null; + var currentStyle = null; + + var readerModeURL = /^http:\/\/localhost:\d+\/reader-mode\/page/; + + var BLOCK_IMAGES_SELECTOR = ".content p > img:only-child, " + + ".content p > a:only-child > img:only-child, " + + ".content .wp-caption img, " + + ".content figure img"; + + function debug(s) { + if (!window.__firefox__.reader.DEBUG) { + return; + } + console.log(s); + } + + function checkReadability() { + if (document.location.href.match(readerModeURL)) { + debug({Type: "ReaderModeStateChange", Value: "Active"}); + webkit.messageHandlers.readerModeMessageHandler.postMessage({Type: "ReaderModeStateChange", Value: "Active"}); + return; + } + + if ((document.location.protocol === "http:" || document.location.protocol === "https:") && document.location.pathname !== "/") { + // Short circuit in case we already ran Readability. This mostly happens when going + // back/forward: the page will be cached and the result will still be there. + if (readabilityResult && readabilityResult.content) { + debug({Type: "ReaderModeStateChange", Value: "Available"}); + webkit.messageHandlers.readerModeMessageHandler.postMessage({Type: "ReaderModeStateChange", Value: "Available"}); + return; + } + + var uri = { + spec: document.location.href, + host: document.location.host, + prePath: document.location.protocol + "//" + document.location.host, // TODO This is incomplete, needs username/password and port + scheme: document.location.protocol.substr(0, document.location.protocol.indexOf(":")), + pathBase: document.location.protocol + "//" + document.location.host + location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1) + } + + // document.cloneNode() can cause the webview to break (bug 1128774). + // Serialize and then parse the document instead. + var docStr = new XMLSerializer().serializeToString(document); + var doc = new DOMParser().parseFromString(docStr, "text/html"); + var readability = new Readability(uri, doc); + readabilityResult = readability.parse(); + + debug({Type: "ReaderModeStateChange", Value: readabilityResult !== null ? "Available" : "Unavailable"}); + webkit.messageHandlers.readerModeMessageHandler.postMessage({Type: "ReaderModeStateChange", Value: readabilityResult !== null ? "Available" : "Unavailable"}); + + return; + } + + debug({Type: "ReaderModeStateChange", Value: "Unavailable"}); + webkit.messageHandlers.readerModeMessageHandler.postMessage({Type: "ReaderModeStateChange", Value: "Unavailable"}); + } + + // Readerize the document. Since we did the actual readerization already in checkReadability, we + // can simply return the results we already have. + function readerize() { + return readabilityResult; + } + + // TODO The following code only makes sense in about:reader context. It may be a good idea to move + // it out of this file and into for example a Reader.js. + + function setStyle(style) { + // Configure the theme (light, dark) + if (currentStyle != null) { + document.body.classList.remove(currentStyle.theme); + } + document.body.classList.add(style.theme); + + // Configure the font size (1-5) + if (currentStyle != null) { + document.body.classList.remove("font-size" + currentStyle.fontSize); + } + document.body.classList.add("font-size" + style.fontSize); + + // Configure the font type + if (currentStyle != null) { + document.body.classList.remove(currentStyle.fontType); + } + document.body.classList.add(style.fontType); + + // Remember the style + currentStyle = style; + } + + function updateImageMargins() { + var contentElement = document.getElementById('reader-content'); + + var windowWidth = window.innerWidth; + var contentWidth = contentElement.offsetWidth; + var maxWidthStyle = windowWidth + "px !important"; + + var setImageMargins = function(img) { + if (!img._originalWidth) { + img._originalWidth = img.offsetWidth; + } + + var imgWidth = img._originalWidth; + + // If the image is taking more than half of the screen, just make + // it fill edge-to-edge. + if (imgWidth < contentWidth && imgWidth > windowWidth * 0.55) { + imgWidth = windowWidth; + } + + var sideMargin = Math.max((contentWidth - windowWidth) / 2, (contentWidth - imgWidth) / 2); + + var imageStyle = sideMargin + "px !important"; + var widthStyle = imgWidth + "px !important"; + + var cssText = "max-width: " + maxWidthStyle + ";" + + "width: " + widthStyle + ";" + + "margin-left: " + imageStyle + ";" + + "margin-right: " + imageStyle + ";"; + + img.style.cssText = cssText; + } + + var imgs = document.querySelectorAll(BLOCK_IMAGES_SELECTOR); + for (var i = imgs.length; --i >= 0;) { + var img = imgs[i]; + if (img.width > 0) { + setImageMargins(img); + } else { + img.onload = function() { + setImageMargins(img); + } + } + } + } + + function showContent() { + // Make the reader visible + var messageElement = document.getElementById('reader-message'); + messageElement.style.display = "none"; + var headerElement = document.getElementById('reader-header'); + headerElement.style.display = "block" + var contentElement = document.getElementById('reader-content'); + contentElement.style.display = "block"; + } + + function configureReader() { + // Configure the reader with the initial style that was injected in the page. + var style = JSON.parse(document.body.getAttribute("data-readerStyle")); + setStyle(style); + + // The order here is important. Because updateImageMargins depends on contentElement.offsetWidth which + // will not be set until contentElement is visible. If this leads to annoying content reflowing then we + // need to look at an alternative way to do + showContent(); + updateImageMargins(); + } + + Object.defineProperty(window.__firefox__, 'reader', { + enumerable: false, + configurable: false, + writable: false, + value: { + // If this is http or https content, and not an index page, then try to run Readability. If anything + // fails, the app will never be notified and we don't show the button. That is ok for now since there + // is no error feedback possible anyway. + DEBUG: false + } + }); + + Object.defineProperty(window.__firefox__.reader, 'checkReadability', { + enumerable: false, + configurable: false, + writable: false, + value: checkReadability + }); + + Object.defineProperty(window.__firefox__.reader, 'readerize', { + enumerable: false, + configurable: false, + writable: false, + value: readerize + }); + + Object.defineProperty(window.__firefox__.reader, 'setStyle', { + enumerable: false, + configurable: false, + writable: false, + value: setStyle + }); + + window.addEventListener('load', function(event) { + // If this is an about:reader page that we are loading, apply the initial style to the page. + if (document.location.href.match(readerModeURL)) { + configureReader(); + } + }); + + + window.addEventListener('pageshow', function(event) { + // If this is an about:reader page that we are showing, fire an event to the native code + if (document.location.href.match(readerModeURL)) { + webkit.messageHandlers.readerModeMessageHandler.postMessage({Type: "ReaderPageEvent", Value: "PageShow"}); + } + }); +})(); diff --git a/mobile/ios/Client/Frontend/Reader/ReaderMode.swift b/mobile/ios/Client/Frontend/Reader/ReaderMode.swift new file mode 100644 index 0000000000..5efa3a71a2 --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReaderMode.swift @@ -0,0 +1,296 @@ +/* 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/. */ + +import Foundation +import Shared +import WebKit +import SwiftyJSON + +let ReaderModeProfileKeyStyle = "readermode.style" + +enum ReaderModeMessageType: String { + case stateChange = "ReaderModeStateChange" + case pageEvent = "ReaderPageEvent" +} + +enum ReaderPageEvent: String { + case pageShow = "PageShow" +} + +enum ReaderModeState: String { + case available = "Available" + case unavailable = "Unavailable" + case active = "Active" +} + +enum ReaderModeTheme: String { + case light = "light" + case dark = "dark" + case sepia = "sepia" +} + +enum ReaderModeFontType: String { + case serif = "serif" + case sansSerif = "sans-serif" +} + +enum ReaderModeFontSize: Int { + case size1 = 1 + case size2 = 2 + case size3 = 3 + case size4 = 4 + case size5 = 5 + case size6 = 6 + case size7 = 7 + case size8 = 8 + case size9 = 9 + case size10 = 10 + case size11 = 11 + case size12 = 12 + case size13 = 13 + + func isSmallest() -> Bool { + return self == ReaderModeFontSize.size1 + } + + func smaller() -> ReaderModeFontSize { + if isSmallest() { + return self + } else { + return ReaderModeFontSize(rawValue: self.rawValue - 1)! + } + } + + func isLargest() -> Bool { + return self == ReaderModeFontSize.size13 + } + + static var defaultSize: ReaderModeFontSize { + switch UIApplication.shared.preferredContentSizeCategory { + case UIContentSizeCategory.extraSmall: + return .size1 + case UIContentSizeCategory.small: + return .size2 + case UIContentSizeCategory.medium: + return .size3 + case UIContentSizeCategory.large: + return .size5 + case UIContentSizeCategory.extraLarge: + return .size7 + case UIContentSizeCategory.extraExtraLarge: + return .size9 + case UIContentSizeCategory.extraExtraExtraLarge: + return .size12 + default: + return .size5 + } + } + + func bigger() -> ReaderModeFontSize { + if isLargest() { + return self + } else { + return ReaderModeFontSize(rawValue: self.rawValue + 1)! + } + } +} + +struct ReaderModeStyle { + var theme: ReaderModeTheme + var fontType: ReaderModeFontType + var fontSize: ReaderModeFontSize + + /// Encode the style to a JSON dictionary that can be passed to ReaderMode.js + func encode() -> String { + return JSON(["theme": theme.rawValue, "fontType": fontType.rawValue, "fontSize": fontSize.rawValue]).stringValue() ?? "" + } + + /// Encode the style to a dictionary that can be stored in the profile + func encodeAsDictionary() -> [String: Any] { + return ["theme": theme.rawValue, "fontType": fontType.rawValue, "fontSize": fontSize.rawValue] + } + + init(theme: ReaderModeTheme, fontType: ReaderModeFontType, fontSize: ReaderModeFontSize) { + self.theme = theme + self.fontType = fontType + self.fontSize = fontSize + } + + /// Initialize the style from a dictionary, taken from the profile. Returns nil if the object cannot be decoded. + init?(dict: [String: Any]) { + let themeRawValue = dict["theme"] as? String + let fontTypeRawValue = dict["fontType"] as? String + let fontSizeRawValue = dict["fontSize"] as? Int + if themeRawValue == nil || fontTypeRawValue == nil || fontSizeRawValue == nil { + return nil + } + + let theme = ReaderModeTheme(rawValue: themeRawValue!) + let fontType = ReaderModeFontType(rawValue: fontTypeRawValue!) + let fontSize = ReaderModeFontSize(rawValue: fontSizeRawValue!) + if theme == nil || fontType == nil || fontSize == nil { + return nil + } + + self.theme = theme! + self.fontType = fontType! + self.fontSize = fontSize! + } +} + +let DefaultReaderModeStyle = ReaderModeStyle(theme: .light, fontType: .sansSerif, fontSize: ReaderModeFontSize.defaultSize) + +/// This struct captures the response from the Readability.js code. +struct ReadabilityResult { + var domain = "" + var url = "" + var content = "" + var title = "" + var credits = "" + + init?(object: AnyObject?) { + if let dict = object as? NSDictionary { + if let uri = dict["uri"] as? NSDictionary { + if let url = uri["spec"] as? String { + self.url = url + } + if let host = uri["host"] as? String { + self.domain = host + } + } + if let content = dict["content"] as? String { + self.content = content + } + if let title = dict["title"] as? String { + self.title = title + } + if let credits = dict["byline"] as? String { + self.credits = credits + } + } else { + return nil + } + } + + /// Initialize from a JSON encoded string + init?(string: String) { + let object = JSON(parseJSON: string) + let domain = object["domain"].string + let url = object["url"].string + let content = object["content"].string + let title = object["title"].string + let credits = object["credits"].string + + if domain == nil || url == nil || content == nil || title == nil || credits == nil { + return nil + } + + self.domain = domain! + self.url = url! + self.content = content! + self.title = title! + self.credits = credits! + } + + /// Encode to a dictionary, which can then for example be json encoded + func encode() -> [String: Any] { + return ["domain": domain, "url": url, "content": content, "title": title, "credits": credits] + } + + /// Encode to a JSON encoded string + func encode() -> String { + let dict: [String: Any] = self.encode() + return JSON(object: dict).stringValue()! + } +} + +/// Delegate that contains callbacks that we have added on top of the built-in WKWebViewDelegate +protocol ReaderModeDelegate { + func readerMode(_ readerMode: ReaderMode, didChangeReaderModeState state: ReaderModeState, forTab tab: Tab) + func readerMode(_ readerMode: ReaderMode, didDisplayReaderizedContentForTab tab: Tab) +} + +let ReaderModeNamespace = "window.__firefox__.reader" + +class ReaderMode: TabContentScript { + var delegate: ReaderModeDelegate? + + fileprivate weak var tab: Tab? + var state: ReaderModeState = ReaderModeState.unavailable + fileprivate var originalURL: URL? + + class func name() -> String { + return "ReaderMode" + } + + required init(tab: Tab) { + self.tab = tab + + // This is a WKUserScript at the moment because webView.evaluateJavaScript() fails with an unspecified error. Possibly script size related. + if let path = Bundle.main.path(forResource: "Readability", ofType: "js") { + if let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + + // This is executed after a page has been loaded. It executes Readability and then fires a script message to let us know if the page is compatible with reader mode. + if let path = Bundle.main.path(forResource: "ReaderMode", ofType: "js") { + if let source = try? NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true) + tab.webView!.configuration.userContentController.addUserScript(userScript) + } + } + } + + func scriptMessageHandlerName() -> String? { + return "readerModeMessageHandler" + } + + fileprivate func handleReaderPageEvent(_ readerPageEvent: ReaderPageEvent) { + switch readerPageEvent { + case .pageShow: + if let tab = tab { + delegate?.readerMode(self, didDisplayReaderizedContentForTab: tab) + } + } + } + + fileprivate func handleReaderModeStateChange(_ state: ReaderModeState) { + self.state = state + guard let tab = tab else { + return + } + delegate?.readerMode(self, didChangeReaderModeState: state, forTab: tab) + } + + func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { + if let msg = message.body as? Dictionary { + if let messageType = ReaderModeMessageType(rawValue: msg["Type"] ?? "") { + switch messageType { + case .pageEvent: + if let readerPageEvent = ReaderPageEvent(rawValue: msg["Value"] ?? "Invalid") { + handleReaderPageEvent(readerPageEvent) + } + break + case .stateChange: + if let readerModeState = ReaderModeState(rawValue: msg["Value"] ?? "Invalid") { + handleReaderModeStateChange(readerModeState) + } + break + } + } + } + } + + var style: ReaderModeStyle = DefaultReaderModeStyle { + didSet { + if state == ReaderModeState.active { + tab?.webView?.evaluateJavaScript("\(ReaderModeNamespace).setStyle(\(style.encode()))", completionHandler: { (object, error) -> Void in + return + }) + } + } + } +} diff --git a/mobile/ios/Client/Frontend/Reader/ReaderModeCache.swift b/mobile/ios/Client/Frontend/Reader/ReaderModeCache.swift new file mode 100644 index 0000000000..f1285537ca --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReaderModeCache.swift @@ -0,0 +1,142 @@ +/* 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/. */ + +import Foundation + +private let DiskReaderModeCacheSharedInstance = DiskReaderModeCache() +private let MemoryReaderModeCacheSharedInstance = MemoryReaderModeCache() + +let ReaderModeCacheErrorDomain = "com.mozilla.client.readermodecache." +enum ReaderModeCacheErrorCode: Int { + case noPathsFound = 0 +} + +// NSObject wrapper around ReadabilityResult Swift struct for adding into the NSCache +private class ReadabilityResultWrapper: NSObject { + let result: ReadabilityResult + + init(readabilityResult: ReadabilityResult) { + self.result = readabilityResult + super.init() + } +} + +protocol ReaderModeCache { + func put(_ url: URL, _ readabilityResult: ReadabilityResult) throws + + func get(_ url: URL) throws -> ReadabilityResult + + func delete(_ url: URL, error: NSErrorPointer) + + func contains(_ url: URL) -> Bool +} + +/// A non-persistent cache for readerized content for times when you don't want to write reader data to disk. +/// For example, when the user is in a private tab, we want to make sure that we leave no trace on the file system +class MemoryReaderModeCache: ReaderModeCache { + var cache: NSCache + + init(cache: NSCache = NSCache()) { + self.cache = cache + } + + class var sharedInstance: ReaderModeCache { + return MemoryReaderModeCacheSharedInstance + } + + func put(_ url: URL, _ readabilityResult: ReadabilityResult) throws { + cache.setObject(ReadabilityResultWrapper(readabilityResult: readabilityResult), forKey: url as AnyObject) + } + + func get(_ url: URL) throws -> ReadabilityResult { + guard let resultWrapper = cache.object(forKey: url as AnyObject) as? ReadabilityResultWrapper else { + throw NSError(domain: ReaderModeCacheErrorDomain, code: ReaderModeCacheErrorCode.noPathsFound.rawValue, userInfo: nil) + } + return resultWrapper.result + } + + func delete(_ url: URL, error: NSErrorPointer) { + cache.removeObject(forKey: url as AnyObject) + } + + func contains(_ url: URL) -> Bool { + return cache.object(forKey: url as AnyObject) != nil + } +} + +/// Really basic persistent cache to store readerized content. Has a simple hashed structure +/// to avoid storing many items in the same directory. +/// +/// This currently lives in ~/Library/Caches so that the data can be pruned in case the OS needs +/// more space. Whether that is a good idea or not is not sure. We have a bug on file to investigate +/// and improve at a later time. +class DiskReaderModeCache: ReaderModeCache { + class var sharedInstance: ReaderModeCache { + return DiskReaderModeCacheSharedInstance + } + + func put(_ url: URL, _ readabilityResult: ReadabilityResult) throws { + guard let (cacheDirectoryPath, contentFilePath) = cachePathsForURL(url) else { + throw NSError(domain: ReaderModeCacheErrorDomain, code: ReaderModeCacheErrorCode.noPathsFound.rawValue, userInfo: nil) + } + + try FileManager.default.createDirectory(atPath: cacheDirectoryPath, withIntermediateDirectories: true, attributes: nil) + let string: String = readabilityResult.encode() + try string.write(toFile: contentFilePath, atomically: true, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) + return + } + + func get(_ url: URL) throws -> ReadabilityResult { + if let (_, contentFilePath) = cachePathsForURL(url), FileManager.default.fileExists(atPath: contentFilePath) { + let string = try NSString(contentsOfFile: contentFilePath, encoding: String.Encoding.utf8.rawValue) + if let value = ReadabilityResult(string: string as String) { + return value + } + } + + throw NSError(domain: ReaderModeCacheErrorDomain, code: ReaderModeCacheErrorCode.noPathsFound.rawValue, userInfo: nil) + } + + func delete(_ url: URL, error: NSErrorPointer) { + guard let (cacheDirectoryPath, _) = cachePathsForURL(url) else { return } + + if FileManager.default.fileExists(atPath: cacheDirectoryPath) { + do { + try FileManager.default.removeItem(atPath: cacheDirectoryPath) + } catch let error1 as NSError { + error?.pointee = error1 + } + } + } + + func contains(_ url: URL) -> Bool { + if let (_, contentFilePath) = cachePathsForURL(url), FileManager.default.fileExists(atPath: contentFilePath) { + return true + } + + return false + } + + fileprivate func cachePathsForURL(_ url: URL) -> (cacheDirectoryPath: String, contentFilePath: String)? { + let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) + if !paths.isEmpty, let hashedPath = hashedPathForURL(url) { + let cacheDirectoryURL = URL(fileURLWithPath: NSString.path(withComponents: [paths[0], "ReaderView", hashedPath])) + return (cacheDirectoryURL.path, cacheDirectoryURL.appendingPathComponent("content.json").path) + } + + return nil + } + + fileprivate func hashedPathForURL(_ url: URL) -> String? { + guard let hash = hashForURL(url) else { return nil } + + return NSString.path(withComponents: [hash.substring(with: NSRange(location: 0, length: 2)), hash.substring(with: NSRange(location: 2, length: 2)), hash.substring(from: 4)]) as String + } + + fileprivate func hashForURL(_ url: URL) -> NSString? { + guard let data = url.absoluteString.data(using: String.Encoding.utf8) else { return nil } + + return data.sha1.hexEncodedString as NSString? + } +} diff --git a/mobile/ios/Client/Frontend/Reader/ReaderModeHandlers.swift b/mobile/ios/Client/Frontend/Reader/ReaderModeHandlers.swift new file mode 100644 index 0000000000..e756aa1e1a --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReaderModeHandlers.swift @@ -0,0 +1,81 @@ +/* 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/. */ + +import Foundation +import GCDWebServers + +struct ReaderModeHandlers { + static var readerModeCache: ReaderModeCache = DiskReaderModeCache.sharedInstance + + static func register(_ webServer: WebServer, profile: Profile) { + // Register our fonts and css, which we want to expose to web content that we present in the WebView + webServer.registerMainBundleResourcesOfType("ttf", module: "reader-mode/fonts") + webServer.registerMainBundleResource("Reader.css", module: "reader-mode/styles") + + // Register a handler that simply lets us know if a document is in the cache or not. This is called from the + // reader view interstitial page to find out when it can stop showing the 'Loading...' page and instead load + // the readerized content. + webServer.registerHandlerForMethod("GET", module: "reader-mode", resource: "page-exists") { (request: GCDWebServerRequest?) -> GCDWebServerResponse! in + guard let stringURL = request?.query["url"] as? String, + let url = URL(string: stringURL) else { + return GCDWebServerResponse(statusCode: 500) + } + + let status = readerModeCache.contains(url) ? 200 : 404 + return GCDWebServerResponse(statusCode: status) + } + + // Register the handler that accepts /reader-mode/page?url=http://www.example.com requests. + webServer.registerHandlerForMethod("GET", module: "reader-mode", resource: "page") { (request: GCDWebServerRequest?) -> GCDWebServerResponse! in + if let url = request?.query["url"] as? String { + if let url = URL(string: url), url.isWebPage() { + do { + let readabilityResult = try readerModeCache.get(url) + // We have this page in our cache, so we can display it. Just grab the correct style from the + // profile and then generate HTML from the Readability results. + var readerModeStyle = DefaultReaderModeStyle + if let dict = profile.prefs.dictionaryForKey(ReaderModeProfileKeyStyle) { + if let style = ReaderModeStyle(dict: dict) { + readerModeStyle = style + } + } + if let html = ReaderModeUtils.generateReaderContent(readabilityResult, initialStyle: readerModeStyle), + let response = GCDWebServerDataResponse(html: html) { + // Apply a Content Security Policy that disallows everything except images from anywhere and fonts and css from our internal server + response.setValue("default-src 'none'; img-src *; style-src http://localhost:*; font-src http://localhost:*", forAdditionalHeader: "Content-Security-Policy") + return response + } + } catch _ { + // This page has not been converted to reader mode yet. This happens when you for example add an + // item via the app extension and the application has not yet had a change to readerize that + // page in the background. + // + // What we do is simply queue the page in the ReadabilityService and then show our loading + // screen, which will periodically call page-exists to see if the readerized content has + // become available. + ReadabilityService.sharedInstance.process(url, cache: readerModeCache) + if let readerViewLoadingPath = Bundle.main.path(forResource: "ReaderViewLoading", ofType: "html") { + do { + let readerViewLoading = try NSMutableString(contentsOfFile: readerViewLoadingPath, encoding: String.Encoding.utf8.rawValue) + readerViewLoading.replaceOccurrences(of: "%ORIGINAL-URL%", with: url.absoluteString, + options: NSString.CompareOptions.literal, range: NSRange(location: 0, length: readerViewLoading.length)) + readerViewLoading.replaceOccurrences(of: "%LOADING-TEXT%", with: NSLocalizedString("Loading content…", comment: "Message displayed when the reader mode page is loading. This message will appear only when sharing to Firefox reader mode from another app."), + options: NSString.CompareOptions.literal, range: NSRange(location: 0, length: readerViewLoading.length)) + readerViewLoading.replaceOccurrences(of: "%LOADING-FAILED-TEXT%", with: NSLocalizedString("The page could not be displayed in Reader View.", comment: "Message displayed when the reader mode page could not be loaded. This message will appear only when sharing to Firefox reader mode from another app."), + options: NSString.CompareOptions.literal, range: NSRange(location: 0, length: readerViewLoading.length)) + readerViewLoading.replaceOccurrences(of: "%LOAD-ORIGINAL-TEXT%", with: NSLocalizedString("Load original page", comment: "Link for going to the non-reader page when the reader view could not be loaded. This message will appear only when sharing to Firefox reader mode from another app."), + options: NSString.CompareOptions.literal, range: NSRange(location: 0, length: readerViewLoading.length)) + return GCDWebServerDataResponse(html: readerViewLoading as String) + } catch _ { + } + } + } + } + } + + let errorString = NSLocalizedString("There was an error converting the page", comment: "Error displayed when reader mode cannot be enabled") + return GCDWebServerDataResponse(html: errorString) // TODO Needs a proper error page + } + } +} diff --git a/mobile/ios/Client/Frontend/Reader/ReaderModeStyleViewController.swift b/mobile/ios/Client/Frontend/Reader/ReaderModeStyleViewController.swift new file mode 100644 index 0000000000..bd169c9b17 --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReaderModeStyleViewController.swift @@ -0,0 +1,379 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared + +private struct ReaderModeStyleViewControllerUX { + static let RowHeight = 50 + + static let Width = 270 + static let Height = 4 * RowHeight + + static let FontTypeRowBackground = UIColor(rgb: 0xfbfbfb) + + static let FontTypeTitleSelectedColor = UIColor(rgb: 0x333333) + static let FontTypeTitleNormalColor = UIColor.lightGray // TODO THis needs to be 44% of 0x333333 + + static let FontSizeRowBackground = UIColor(rgb: 0xf4f4f4) + static let FontSizeLabelColor = UIColor(rgb: 0x333333) + static let FontSizeButtonTextColorEnabled = UIColor(rgb: 0x333333) + static let FontSizeButtonTextColorDisabled = UIColor.lightGray // TODO THis needs to be 44% of 0x333333 + + static let ThemeRowBackgroundColor = UIColor.white + static let ThemeTitleColorLight = UIColor(rgb: 0x333333) + static let ThemeTitleColorDark = UIColor.white + static let ThemeTitleColorSepia = UIColor(rgb: 0x333333) + static let ThemeBackgroundColorLight = UIColor.white + static let ThemeBackgroundColorDark = UIColor(rgb: 0x333333) + static let ThemeBackgroundColorSepia = UIColor(rgb: 0xF0E6DC) + + static let BrightnessRowBackground = UIColor(rgb: 0xf4f4f4) + static let BrightnessSliderTintColor = UIColor(rgb: 0xe66000) + static let BrightnessSliderWidth = 140 + static let BrightnessIconOffset = 10 +} + +// MARK: - + +protocol ReaderModeStyleViewControllerDelegate { + func readerModeStyleViewController(_ readerModeStyleViewController: ReaderModeStyleViewController, didConfigureStyle style: ReaderModeStyle) +} + +// MARK: - + +class ReaderModeStyleViewController: UIViewController { + var delegate: ReaderModeStyleViewControllerDelegate? + var readerModeStyle: ReaderModeStyle = DefaultReaderModeStyle + + fileprivate var fontTypeButtons: [FontTypeButton]! + fileprivate var fontSizeLabel: FontSizeLabel! + fileprivate var fontSizeButtons: [FontSizeButton]! + fileprivate var themeButtons: [ThemeButton]! + + override func viewDidLoad() { + // Our preferred content size has a fixed width and height based on the rows + padding + + preferredContentSize = CGSize(width: ReaderModeStyleViewControllerUX.Width, height: ReaderModeStyleViewControllerUX.Height) + + popoverPresentationController?.backgroundColor = ReaderModeStyleViewControllerUX.FontTypeRowBackground + + // Font type row + + let fontTypeRow = UIView() + view.addSubview(fontTypeRow) + fontTypeRow.backgroundColor = ReaderModeStyleViewControllerUX.FontTypeRowBackground + + fontTypeRow.snp.makeConstraints { (make) -> Void in + make.top.equalTo(self.view) + make.left.right.equalTo(self.view) + make.height.equalTo(ReaderModeStyleViewControllerUX.RowHeight) + } + + fontTypeButtons = [ + FontTypeButton(fontType: ReaderModeFontType.sansSerif), + FontTypeButton(fontType: ReaderModeFontType.serif) + ] + + setupButtons(fontTypeButtons, inRow: fontTypeRow, action: #selector(ReaderModeStyleViewController.SELchangeFontType(_:))) + + // Font size row + + let fontSizeRow = UIView() + view.addSubview(fontSizeRow) + fontSizeRow.backgroundColor = ReaderModeStyleViewControllerUX.FontSizeRowBackground + + fontSizeRow.snp.makeConstraints { (make) -> Void in + make.top.equalTo(fontTypeRow.snp.bottom) + make.left.right.equalTo(self.view) + make.height.equalTo(ReaderModeStyleViewControllerUX.RowHeight) + } + + fontSizeLabel = FontSizeLabel() + fontSizeRow.addSubview(fontSizeLabel) + + fontSizeLabel.snp.makeConstraints { (make) -> Void in + make.center.equalTo(fontSizeRow) + return + } + + fontSizeButtons = [ + FontSizeButton(fontSizeAction: FontSizeAction.smaller), + FontSizeButton(fontSizeAction: FontSizeAction.reset), + FontSizeButton(fontSizeAction: FontSizeAction.bigger) + ] + + setupButtons(fontSizeButtons, inRow: fontSizeRow, action: #selector(ReaderModeStyleViewController.SELchangeFontSize(_:))) + + // Theme row + + let themeRow = UIView() + view.addSubview(themeRow) + + themeRow.snp.makeConstraints { (make) -> Void in + make.top.equalTo(fontSizeRow.snp.bottom) + make.left.right.equalTo(self.view) + make.height.equalTo(ReaderModeStyleViewControllerUX.RowHeight) + } + + themeButtons = [ + ThemeButton(theme: ReaderModeTheme.light), + ThemeButton(theme: ReaderModeTheme.dark), + ThemeButton(theme: ReaderModeTheme.sepia) + ] + + setupButtons(themeButtons, inRow: themeRow, action: #selector(ReaderModeStyleViewController.SELchangeTheme(_:))) + + // Brightness row + + let brightnessRow = UIView() + view.addSubview(brightnessRow) + brightnessRow.backgroundColor = ReaderModeStyleViewControllerUX.BrightnessRowBackground + + brightnessRow.snp.makeConstraints { (make) -> Void in + make.top.equalTo(themeRow.snp.bottom) + make.left.right.equalTo(self.view) + make.height.equalTo(ReaderModeStyleViewControllerUX.RowHeight) + } + + let slider = UISlider() + brightnessRow.addSubview(slider) + slider.accessibilityLabel = NSLocalizedString("Brightness", comment: "Accessibility label for brightness adjustment slider in Reader Mode display settings") + slider.tintColor = ReaderModeStyleViewControllerUX.BrightnessSliderTintColor + slider.addTarget(self, action: #selector(ReaderModeStyleViewController.SELchangeBrightness(_:)), for: UIControlEvents.valueChanged) + + slider.snp.makeConstraints { make in + make.center.equalTo(brightnessRow) + make.width.equalTo(ReaderModeStyleViewControllerUX.BrightnessSliderWidth) + } + + let brightnessMinImageView = UIImageView(image: UIImage(named: "brightnessMin")) + brightnessRow.addSubview(brightnessMinImageView) + + brightnessMinImageView.snp.makeConstraints { (make) -> Void in + make.centerY.equalTo(slider) + make.right.equalTo(slider.snp.left).offset(-ReaderModeStyleViewControllerUX.BrightnessIconOffset) + } + + let brightnessMaxImageView = UIImageView(image: UIImage(named: "brightnessMax")) + brightnessRow.addSubview(brightnessMaxImageView) + + brightnessMaxImageView.snp.makeConstraints { (make) -> Void in + make.centerY.equalTo(slider) + make.left.equalTo(slider.snp.right).offset(ReaderModeStyleViewControllerUX.BrightnessIconOffset) + } + + selectFontType(readerModeStyle.fontType) + updateFontSizeButtons() + selectTheme(readerModeStyle.theme) + slider.value = Float(UIScreen.main.brightness) + } + + /// Setup constraints for a row of buttons. Left to right. They are all given the same width. + fileprivate func setupButtons(_ buttons: [UIButton], inRow row: UIView, action: Selector) { + for (idx, button) in buttons.enumerated() { + row.addSubview(button) + button.addTarget(self, action: action, for: UIControlEvents.touchUpInside) + button.snp.makeConstraints { make in + make.top.equalTo(row.snp.top) + if idx == 0 { + make.left.equalTo(row.snp.left) + } else { + make.left.equalTo(buttons[idx - 1].snp.right) + } + make.bottom.equalTo(row.snp.bottom) + make.width.equalTo(self.preferredContentSize.width / CGFloat(buttons.count)) + } + } + } + + func SELchangeFontType(_ button: FontTypeButton) { + selectFontType(button.fontType) + delegate?.readerModeStyleViewController(self, didConfigureStyle: readerModeStyle) + } + + fileprivate func selectFontType(_ fontType: ReaderModeFontType) { + readerModeStyle.fontType = fontType + for button in fontTypeButtons { + button.isSelected = (button.fontType == fontType) + } + for button in themeButtons { + button.fontType = fontType + } + fontSizeLabel.fontType = fontType + } + + func SELchangeFontSize(_ button: FontSizeButton) { + switch button.fontSizeAction { + case .smaller: + readerModeStyle.fontSize = readerModeStyle.fontSize.smaller() + case .bigger: + readerModeStyle.fontSize = readerModeStyle.fontSize.bigger() + case .reset: + readerModeStyle.fontSize = ReaderModeFontSize.defaultSize + } + updateFontSizeButtons() + delegate?.readerModeStyleViewController(self, didConfigureStyle: readerModeStyle) + } + + fileprivate func updateFontSizeButtons() { + for button in fontSizeButtons { + switch button.fontSizeAction { + case .bigger: + button.isEnabled = !readerModeStyle.fontSize.isLargest() + break + case .smaller: + button.isEnabled = !readerModeStyle.fontSize.isSmallest() + break + case .reset: + break + } + } + } + + func SELchangeTheme(_ button: ThemeButton) { + selectTheme(button.theme) + delegate?.readerModeStyleViewController(self, didConfigureStyle: readerModeStyle) + } + + fileprivate func selectTheme(_ theme: ReaderModeTheme) { + readerModeStyle.theme = theme + } + + func SELchangeBrightness(_ slider: UISlider) { + UIScreen.main.brightness = CGFloat(slider.value) + } +} + +// MARK: - + +class FontTypeButton: UIButton { + var fontType: ReaderModeFontType = .sansSerif + + convenience init(fontType: ReaderModeFontType) { + self.init(frame: CGRect.zero) + self.fontType = fontType + setTitleColor(ReaderModeStyleViewControllerUX.FontTypeTitleSelectedColor, for: UIControlState.selected) + setTitleColor(ReaderModeStyleViewControllerUX.FontTypeTitleNormalColor, for: UIControlState()) + backgroundColor = ReaderModeStyleViewControllerUX.FontTypeRowBackground + accessibilityHint = NSLocalizedString("Changes font type.", comment: "Accessibility hint for the font type buttons in reader mode display settings") + switch fontType { + case .sansSerif: + setTitle(NSLocalizedString("Sans-serif", comment: "Font type setting in the reading view settings"), for: UIControlState()) + let f = UIFont(name: "FiraSans-Book", size: DynamicFontHelper.defaultHelper.ReaderStandardFontSize) + titleLabel?.font = f + case .serif: + setTitle(NSLocalizedString("Serif", comment: "Font type setting in the reading view settings"), for: UIControlState()) + let f = UIFont(name: "Charis SIL", size: DynamicFontHelper.defaultHelper.ReaderStandardFontSize) + titleLabel?.font = f + } + } +} + +// MARK: - + +enum FontSizeAction { + case smaller + case reset + case bigger +} + +class FontSizeButton: UIButton { + var fontSizeAction: FontSizeAction = .bigger + + convenience init(fontSizeAction: FontSizeAction) { + self.init(frame: CGRect.zero) + self.fontSizeAction = fontSizeAction + + setTitleColor(ReaderModeStyleViewControllerUX.FontSizeButtonTextColorEnabled, for: UIControlState.normal) + setTitleColor(ReaderModeStyleViewControllerUX.FontSizeButtonTextColorDisabled, for: UIControlState.disabled) + + switch fontSizeAction { + case .smaller: + let smallerFontLabel = NSLocalizedString("-", comment: "Button for smaller reader font size. Keep this extremely short! This is shown in the reader mode toolbar.") + let smallerFontAccessibilityLabel = NSLocalizedString("Decrease text size", comment: "Accessibility label for button decreasing font size in display settings of reader mode") + setTitle(smallerFontLabel, for: UIControlState()) + accessibilityLabel = smallerFontAccessibilityLabel + case .bigger: + let largerFontLabel = NSLocalizedString("+", comment: "Button for larger reader font size. Keep this extremely short! This is shown in the reader mode toolbar.") + let largerFontAccessibilityLabel = NSLocalizedString("Increase text size", comment: "Accessibility label for button increasing font size in display settings of reader mode") + setTitle(largerFontLabel, for: UIControlState()) + accessibilityLabel = largerFontAccessibilityLabel + case .reset: + accessibilityLabel = Strings.ReaderModeResetFontSizeAccessibilityLabel + } + + // TODO Does this need to change with the selected font type? Not sure if makes sense for just +/- + titleLabel?.font = UIFont(name: "FiraSans-Light", size: DynamicFontHelper.defaultHelper.ReaderBigFontSize) + } +} + +// MARK: - + +class FontSizeLabel: UILabel { + override init(frame: CGRect) { + super.init(frame: frame) + let fontSizeLabel = NSLocalizedString("Aa", comment: "Button for reader mode font size. Keep this extremely short! This is shown in the reader mode toolbar.") + text = fontSizeLabel + isAccessibilityElement = false + } + + required init?(coder aDecoder: NSCoder) { + // TODO + fatalError("init(coder:) has not been implemented") + } + + var fontType: ReaderModeFontType = .sansSerif { + didSet { + switch fontType { + case .sansSerif: + font = UIFont(name: "FiraSans-Book", size: DynamicFontHelper.defaultHelper.ReaderBigFontSize) + case .serif: + font = UIFont(name: "Charis SIL", size: DynamicFontHelper.defaultHelper.ReaderBigFontSize) + } + } + } +} + +// MARK: - + +class ThemeButton: UIButton { + var theme: ReaderModeTheme! + + convenience init(theme: ReaderModeTheme) { + self.init(frame: CGRect.zero) + self.theme = theme + + setTitle(theme.rawValue, for: UIControlState()) + + accessibilityHint = NSLocalizedString("Changes color theme.", comment: "Accessibility hint for the color theme setting buttons in reader mode display settings") + + switch theme { + case .light: + setTitle(NSLocalizedString("Light", comment: "Light theme setting in Reading View settings"), for: UIControlState()) + setTitleColor(ReaderModeStyleViewControllerUX.ThemeTitleColorLight, for: UIControlState.normal) + backgroundColor = ReaderModeStyleViewControllerUX.ThemeBackgroundColorLight + case .dark: + setTitle(NSLocalizedString("Dark", comment: "Dark theme setting in Reading View settings"), for: UIControlState()) + setTitleColor(ReaderModeStyleViewControllerUX.ThemeTitleColorDark, for: UIControlState()) + backgroundColor = ReaderModeStyleViewControllerUX.ThemeBackgroundColorDark + case .sepia: + setTitle(NSLocalizedString("Sepia", comment: "Sepia theme setting in Reading View settings"), for: UIControlState()) + setTitleColor(ReaderModeStyleViewControllerUX.ThemeTitleColorSepia, for: UIControlState.normal) + backgroundColor = ReaderModeStyleViewControllerUX.ThemeBackgroundColorSepia + } + } + + var fontType: ReaderModeFontType = .sansSerif { + didSet { + switch fontType { + case .sansSerif: + titleLabel?.font = UIFont(name: "FiraSans-Book", size: DynamicFontHelper.defaultHelper.ReaderStandardFontSize) + case .serif: + titleLabel?.font = UIFont(name: "Charis SIL", size: DynamicFontHelper.defaultHelper.ReaderStandardFontSize) + } + } + } +} diff --git a/mobile/ios/Client/Frontend/Reader/ReaderModeUtils.swift b/mobile/ios/Client/Frontend/Reader/ReaderModeUtils.swift new file mode 100644 index 0000000000..ebf8419b47 --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReaderModeUtils.swift @@ -0,0 +1,57 @@ +/* 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/. */ + +import Foundation + +struct ReaderModeUtils { + + static let DomainPrefixesToSimplify = ["www.", "mobile.", "m.", "blog."] + + static func simplifyDomain(_ domain: String) -> String { + for prefix in DomainPrefixesToSimplify { + if domain.hasPrefix(prefix) { + return domain.substring(from: domain.characters.index(domain.startIndex, offsetBy: prefix.characters.count)) + } + } + return domain + } + + static func generateReaderContent(_ readabilityResult: ReadabilityResult, initialStyle: ReaderModeStyle) -> String? { + if let stylePath = Bundle.main.path(forResource: "Reader", ofType: "css") { + do { + let css = try NSString(contentsOfFile: stylePath, encoding: String.Encoding.utf8.rawValue) + if let tmplPath = Bundle.main.path(forResource: "Reader", ofType: "html") { + do { + let tmpl = try NSMutableString(contentsOfFile: tmplPath, encoding: String.Encoding.utf8.rawValue) + tmpl.replaceOccurrences(of: "%READER-CSS%", with: css as String, + options: NSString.CompareOptions(), range: NSRange(location: 0, length: tmpl.length)) + + tmpl.replaceOccurrences(of: "%READER-STYLE%", with: initialStyle.encode(), + options: NSString.CompareOptions(), range: NSRange(location: 0, length: tmpl.length)) + + tmpl.replaceOccurrences(of: "%READER-DOMAIN%", with: simplifyDomain(readabilityResult.domain), + options: NSString.CompareOptions(), range: NSRange(location: 0, length: tmpl.length)) + + tmpl.replaceOccurrences(of: "%READER-URL%", with: readabilityResult.url, + options: NSString.CompareOptions(), range: NSRange(location: 0, length: tmpl.length)) + + tmpl.replaceOccurrences(of: "%READER-TITLE%", with: readabilityResult.title, + options: NSString.CompareOptions(), range: NSRange(location: 0, length: tmpl.length)) + + tmpl.replaceOccurrences(of: "%READER-CREDITS%", with: readabilityResult.credits, + options: NSString.CompareOptions(), range: NSRange(location: 0, length: tmpl.length)) + + tmpl.replaceOccurrences(of: "%READER-CONTENT%", with: readabilityResult.content, + options: NSString.CompareOptions(), range: NSRange(location: 0, length: tmpl.length)) + + return tmpl as String + } catch _ { + } + } + } catch _ { + } + } + return nil + } +} diff --git a/mobile/ios/Client/Frontend/Reader/ReaderViewLoading.html b/mobile/ios/Client/Frontend/Reader/ReaderViewLoading.html new file mode 100644 index 0000000000..c1e5879cbf --- /dev/null +++ b/mobile/ios/Client/Frontend/Reader/ReaderViewLoading.html @@ -0,0 +1,86 @@ + + + + + + + + + +
+

%LOADING-TEXT%

+ +
+ + + + diff --git a/mobile/ios/Client/Frontend/Settings/AdvanceAccountSettingViewController.swift b/mobile/ios/Client/Frontend/Settings/AdvanceAccountSettingViewController.swift new file mode 100644 index 0000000000..8fac12bc88 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/AdvanceAccountSettingViewController.swift @@ -0,0 +1,183 @@ +/* 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/. */ + +import UIKit +import Shared +import SnapKit +import Foundation +import FxA +import Account + +class AdvanceAccountSettingViewController: SettingsTableViewController { + fileprivate let SectionHeaderIdentifier = "SectionHeaderIdentifier" + + fileprivate var customSyncUrl: String? + + override func viewDidLoad() { + super.viewDidLoad() + title = Strings.SettingsAdvanceAccountSectionName + self.customSyncUrl = self.profile.prefs.stringForKey(PrefsKeys.KeyCustomSyncWeb) + } + + func clearCustomAccountPrefs() { + self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService) + self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncToken) + self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncProfile) + self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncOauth) + self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncAuth) + self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncWeb) + + // To help prevent the account being in a strange state, we force it to + // log out when user clears their custom server preferences. + self.profile.removeAccount() + } + + func setCustomAccountPrefs(_ data: Data, url: URL) { + guard let settings = (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)) as? [String:Any], + let customSyncToken = settings["sync_tokenserver_base_url"] as? String, + let customSyncProfile = settings["profile_server_base_url"] as? String, + let customSyncOauth = settings["oauth_server_base_url"] as? String, + let customSyncAuth = settings["auth_server_base_url"] as? String else { + return + } + + self.profile.prefs.setBool(true, forKey: PrefsKeys.KeyUseCustomSyncService) + self.profile.prefs.setString(customSyncToken, forKey: PrefsKeys.KeyCustomSyncToken) + self.profile.prefs.setString(customSyncProfile, forKey: PrefsKeys.KeyCustomSyncProfile) + self.profile.prefs.setString(customSyncOauth, forKey: PrefsKeys.KeyCustomSyncOauth) + self.profile.prefs.setString(customSyncAuth, forKey: PrefsKeys.KeyCustomSyncAuth) + self.profile.prefs.setString(url.absoluteString, forKey: PrefsKeys.KeyCustomSyncWeb) + self.profile.removeAccount() + self.displaySuccessAlert() + } + + func setCustomAccountPrefs() { + guard let urlString = self.customSyncUrl, let url = URL(string: urlString) else { + // If the user attempts to set a nil url, clear all the custom service perferences + // and use default FxA servers. + self.displayNoServiceSetAlert() + return + } + + // FxA stores its server configuation under a well-known path. This attempts to download the configuration + // and save it into the users preferences. + let syncConfigureString = urlString + "/.well-known/fxa-client-configuration" + guard let syncConfigureURL = URL(string: syncConfigureString) else { + return + } + + URLSession.shared.dataTask(with: syncConfigureURL, completionHandler: {(data, response, error) in + guard let data = data, error == nil else { + // Something went wrong while downloading or parsing the configuration. + self.displayErrorAlert() + return + } + self.setCustomAccountPrefs(data, url: url) + }).resume() + } + + func displaySuccessAlert() { + let alertController = UIAlertController(title: "", message: Strings.SettingsAdvanceAccountUrlUpdatedAlertMessage, preferredStyle: .alert) + let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlUpdatedAlertOk, style: .default, handler: nil) + alertController.addAction(defaultAction) + self.present(alertController, animated: true) + } + + func displayErrorAlert() { + self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService) + DispatchQueue.main.async { + self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic) + } + let alertController = UIAlertController(title: Strings.SettingsAdvanceAccountUrlErrorAlertTitle, message: Strings.SettingsAdvanceAccountUrlErrorAlertMessage, preferredStyle: .alert) + let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlErrorAlertOk, style: .default, handler: nil) + alertController.addAction(defaultAction) + self.present(alertController, animated: true) + } + + func displayNoServiceSetAlert() { + self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService) + DispatchQueue.main.async { + self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic) + } + let alertController = UIAlertController(title: Strings.SettingsAdvanceAccountUrlErrorAlertTitle, message: Strings.SettingsAdvanceAccountEmptyUrlErrorAlertMessage, preferredStyle: .alert) + let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlUpdatedAlertOk, style: .default, handler: nil) + alertController.addAction(defaultAction) + self.present(alertController, animated: true) + } + + override func generateSettings() -> [SettingSection] { + let prefs = profile.prefs + let customSyncSetting = CustomSyncWebPageSetting(prefs: prefs, + prefKey: PrefsKeys.KeyCustomSyncWeb, + placeholder: Strings.SettingsAdvanceAccountUrlPlaceholder, + accessibilityIdentifier: "CustomSyncSetting", + settingDidChange: { fieldText in + self.customSyncUrl = fieldText + if let customSyncUrl = self.customSyncUrl, customSyncUrl.isEmpty { + self.clearCustomAccountPrefs() + return + } + }) + + var basicSettings: [Setting] = [] + basicSettings += [ + CustomSyncEnableSetting( + prefs: prefs, + settingDidChange: { result in + if result == true { + // Reload the table data to ensure that the updated custom url is set + self.tableView?.reloadData() + self.setCustomAccountPrefs() + } + }), + customSyncSetting + ] + + let settings: [SettingSection] = [ + SettingSection(title: NSAttributedString(string: ""), children: basicSettings), + SettingSection(title: NSAttributedString(string: Strings.SettingsAdvanceAccountSectionFooter), children: []) + ] + + return settings + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: SectionHeaderIdentifier) as! SettingsTableSectionHeaderFooterView + let sectionSetting = settings[section] + headerView.titleLabel.text = sectionSetting.title?.string + + switch section { + // Hide the bottom border for the FxA custom server notes. + case 1: + headerView.titleAlignment = .top + headerView.titleLabel.numberOfLines = 0 + headerView.showBottomBorder = false + default: + return super.tableView(tableView, viewForHeaderInSection: section) + } + return headerView + } +} + +class CustomSyncEnableSetting: BoolSetting { + init(prefs: Prefs, settingDidChange: ((Bool?) -> Void)? = nil) { + super.init( + prefs: prefs, prefKey: PrefsKeys.KeyUseCustomSyncService, defaultValue: false, + attributedTitleText: NSAttributedString(string: Strings.SettingsAdvanceAccountUseCustomAccountsServiceTitle), + settingDidChange: settingDidChange + ) + } +} + +class CustomSyncWebPageSetting: WebPageSetting { + override init(prefs: Prefs, prefKey: String, defaultValue: String? = nil, placeholder: String, accessibilityIdentifier: String, settingDidChange: ((String?) -> Void)? = nil) { + super.init(prefs: prefs, + prefKey: prefKey, + defaultValue: defaultValue, + placeholder: placeholder, + accessibilityIdentifier: accessibilityIdentifier, + settingDidChange: settingDidChange) + textField.clearButtonMode = UITextFieldViewMode.always + } +} diff --git a/mobile/ios/Client/Frontend/Settings/AppSettingsOptions.swift b/mobile/ios/Client/Frontend/Settings/AppSettingsOptions.swift new file mode 100644 index 0000000000..fe90023f33 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/AppSettingsOptions.swift @@ -0,0 +1,1092 @@ +/* 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/. */ + +import Foundation +import Shared +import Account +import SwiftKeychainWrapper +import LocalAuthentication + +// This file contains all of the settings available in the main settings screen of the app. + +private var ShowDebugSettings: Bool = false +private var DebugSettingsClickCount: Int = 0 + +// For great debugging! +class HiddenSetting: Setting { + unowned let settings: SettingsTableViewController + + init(settings: SettingsTableViewController) { + self.settings = settings + super.init(title: nil) + } + + override var hidden: Bool { + return !ShowDebugSettings + } +} + +// Sync setting for connecting a Firefox Account. Shown when we don't have an account. +class ConnectSetting: WithoutAccountSetting { + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var title: NSAttributedString? { + return NSAttributedString(string: Strings.FxASignIntoSync, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override var accessibilityIdentifier: String? { return "SignInToSync" } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = FxAContentViewController(profile: profile) + viewController.delegate = self + viewController.url = settings.profile.accountConfiguration.signInURL + navigationController?.pushViewController(viewController, animated: true) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + + if AppConstants.MOZ_SHOW_FXA_AVATAR { + let image = UIImage(named: "FxA-Default") + cell.imageView?.image = image?.createScaled(CGSize(width: 30, height: 30)) + cell.imageView?.layer.cornerRadius = (cell.imageView?.frame.size.width)! / 2 + cell.imageView?.layer.masksToBounds = true + } + } +} + +// Sync setting for disconnecting a Firefox Account. Shown when we have an account. +class DisconnectSetting: WithAccountSetting { + override var accessoryType: UITableViewCellAccessoryType { return .none } + override var textAlignment: NSTextAlignment { return .center } + + override var title: NSAttributedString? { + return NSAttributedString(string: Strings.SettingsDisconnectSyncButton, attributes: [NSForegroundColorAttributeName: UIConstants.DestructiveRed]) + } + + override var accessibilityIdentifier: String? { return "SignOut" } + + override func onClick(_ navigationController: UINavigationController?) { + let alertController = UIAlertController( + title: Strings.SettingsDisconnectSyncAlertTitle, + message: NSLocalizedString("Firefox will stop syncing with your account, but won’t delete any of your browsing data on this device.", comment: "Text of the 'sign out firefox account' alert"), + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction( + UIAlertAction(title: NSLocalizedString("Cancel", comment: "Label for Cancel button"), style: .cancel) { (action) in + // Do nothing. + }) + alertController.addAction( + UIAlertAction(title: Strings.SettingsDisconnectDestructiveAction, style: .destructive) { (action) in + FxALoginHelper.sharedInstance.applicationDidDisconnect(UIApplication.shared) + self.settings.settings = self.settings.generateSettings() + self.settings.SELfirefoxAccountDidChange() + LeanPlumClient.shared.set(attributes: [LPAttributeKey.signedInSync: self.profile.hasAccount()]) + }) + navigationController?.present(alertController, animated: true, completion: nil) + } +} + +class SyncNowSetting: WithAccountSetting { + static let NotificationUserInitiatedSyncManually = "NotificationUserInitiatedSyncManually" + let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) + let syncIconWrapper = UIImage.createWithColor(CGSize(width: 30, height: 30), color: UIColor.clear) + let syncBlueIcon = UIImage(named: "FxA-Sync-Blue")?.createScaled(CGSize(width: 20, height: 20)) + let syncIcon = UIImage(named: "FxA-Sync")?.createScaled(CGSize(width: 20, height: 20)) + + // Animation used to rotate the Sync icon 360 degrees while syncing is in progress. + let continuousRotateAnimation = CABasicAnimation(keyPath: "transform.rotation") + + override init(settings: SettingsTableViewController) { + super.init(settings: settings) + NotificationCenter.default.addObserver(self, selector: #selector(SyncNowSetting.stopRotateSyncIcon), name: NotificationProfileDidFinishSyncing, object: nil) + } + + fileprivate lazy var timestampFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + return formatter + }() + + fileprivate var syncNowTitle: NSAttributedString { + if !DeviceInfo.hasConnectivity() { + return NSAttributedString( + string: Strings.FxANoInternetConnection, + attributes: [ + NSForegroundColorAttributeName: UIColor.red, + NSFontAttributeName: DynamicFontHelper.defaultHelper.DefaultMediumFont + ] + ) + } + + return NSAttributedString( + string: NSLocalizedString("Sync Now", comment: "Sync Firefox Account"), + attributes: [ + NSForegroundColorAttributeName: self.enabled ? UIConstants.TableViewRowSyncTextColor : UIColor.gray, + NSFontAttributeName: DynamicFontHelper.defaultHelper.DefaultStandardFont + ] + ) + } + + fileprivate let syncingTitle = NSAttributedString(string: Strings.SyncingMessageWithEllipsis, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowSyncTextColor, NSFontAttributeName: UIFont.systemFont(ofSize: DynamicFontHelper.defaultHelper.DefaultStandardFontSize, weight: UIFontWeightRegular)]) + + func startRotateSyncIcon() { + DispatchQueue.main.async { + self.imageView.layer.add(self.continuousRotateAnimation, forKey: "rotateKey") + } + } + + func stopRotateSyncIcon() { + DispatchQueue.main.async { + self.imageView.layer.removeAllAnimations() + } + } + + override var accessoryType: UITableViewCellAccessoryType { return .none } + + override var style: UITableViewCellStyle { return .value1 } + + override var image: UIImage? { + if !AppConstants.MOZ_SHOW_FXA_AVATAR { + return nil + } + + guard let syncStatus = profile.syncManager.syncDisplayState else { + return syncIcon + } + + switch syncStatus { + case .inProgress: + return syncBlueIcon + default: + return syncIcon + } + } + + override var title: NSAttributedString? { + guard let syncStatus = profile.syncManager.syncDisplayState else { + return syncNowTitle + } + + switch syncStatus { + case .bad(let message): + guard let message = message else { return syncNowTitle } + return NSAttributedString(string: message, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowErrorTextColor, NSFontAttributeName: DynamicFontHelper.defaultHelper.DefaultStandardFont]) + case .warning(let message): + return NSAttributedString(string: message, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowWarningTextColor, NSFontAttributeName: DynamicFontHelper.defaultHelper.DefaultStandardFont]) + case .inProgress: + return syncingTitle + default: + return syncNowTitle + } + } + + override var status: NSAttributedString? { + guard let timestamp = profile.syncManager.lastSyncFinishTime else { + return nil + } + + let formattedLabel = timestampFormatter.string(from: Date.fromTimestamp(timestamp)) + let attributedString = NSMutableAttributedString(string: formattedLabel) + let attributes = [NSForegroundColorAttributeName: UIColor.gray, NSFontAttributeName: UIFont.systemFont(ofSize: 12, weight: UIFontWeightRegular)] + let range = NSRange(location: 0, length: attributedString.length) + attributedString.setAttributes(attributes, range: range) + return attributedString + } + + override var enabled: Bool { + if !DeviceInfo.hasConnectivity() { + return false + } + + return profile.hasSyncableAccount() + } + + fileprivate lazy var troubleshootButton: UIButton = { + let troubleshootButton = UIButton(type: UIButtonType.roundedRect) + troubleshootButton.setTitle(Strings.FirefoxSyncTroubleshootTitle, for: .normal) + troubleshootButton.addTarget(self, action: #selector(self.troubleshoot), for: .touchUpInside) + troubleshootButton.tintColor = UIConstants.TableViewRowActionAccessoryColor + troubleshootButton.titleLabel?.font = DynamicFontHelper.defaultHelper.DefaultSmallFont + troubleshootButton.sizeToFit() + return troubleshootButton + }() + + fileprivate lazy var warningIcon: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "AmberCaution")) + imageView.sizeToFit() + return imageView + }() + + fileprivate lazy var errorIcon: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "RedCaution")) + imageView.sizeToFit() + return imageView + }() + + fileprivate let syncSUMOURL = SupportUtils.URLForTopic("sync-status-ios") + + @objc fileprivate func troubleshoot() { + let viewController = SettingsContentViewController() + viewController.url = syncSUMOURL + settings.navigationController?.pushViewController(viewController, animated: true) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + cell.textLabel?.attributedText = title + cell.textLabel?.numberOfLines = 0 + cell.textLabel?.lineBreakMode = .byWordWrapping + if let syncStatus = profile.syncManager.syncDisplayState { + switch syncStatus { + case .bad(let message): + if let _ = message { + // add the red warning symbol + // add a link to the MANA page + cell.detailTextLabel?.attributedText = nil + cell.accessoryView = troubleshootButton + addIcon(errorIcon, toCell: cell) + } else { + cell.detailTextLabel?.attributedText = status + cell.accessoryView = nil + } + case .warning(_): + // add the amber warning symbol + // add a link to the MANA page + cell.detailTextLabel?.attributedText = nil + cell.accessoryView = troubleshootButton + addIcon(warningIcon, toCell: cell) + case .good: + cell.detailTextLabel?.attributedText = status + fallthrough + default: + cell.accessoryView = nil + } + } else { + cell.accessoryView = nil + } + cell.accessoryType = accessoryType + cell.isUserInteractionEnabled = !profile.syncManager.isSyncing && DeviceInfo.hasConnectivity() + + if AppConstants.MOZ_SHOW_FXA_AVATAR { + // Animation that loops continously until stopped + continuousRotateAnimation.fromValue = 0.0 + continuousRotateAnimation.toValue = CGFloat(Double.pi) + continuousRotateAnimation.isRemovedOnCompletion = true + continuousRotateAnimation.duration = 0.5 + continuousRotateAnimation.repeatCount = Float.infinity + + // To ensure sync icon is aligned properly with user's avatar, an image is created with proper + // dimensions and color, then the scaled sync icon is added as a subview. + imageView.contentMode = .center + imageView.image = image + + cell.imageView?.subviews.forEach({ $0.removeFromSuperview() }) + cell.imageView?.image = syncIconWrapper + cell.imageView?.addSubview(imageView) + + if let syncStatus = profile.syncManager.syncDisplayState { + switch syncStatus { + case .inProgress: + self.startRotateSyncIcon() + default: + self.stopRotateSyncIcon() + } + } + } + } + + fileprivate func addIcon(_ image: UIImageView, toCell cell: UITableViewCell) { + cell.contentView.addSubview(image) + + cell.textLabel?.snp.updateConstraints { make in + make.leading.equalTo(image.snp.trailing).offset(5) + make.trailing.lessThanOrEqualTo(cell.contentView) + make.centerY.equalTo(cell.contentView) + } + + image.snp.makeConstraints { make in + make.leading.equalTo(cell.contentView).offset(17) + make.top.equalTo(cell.textLabel!).offset(2) + } + } + + override func onClick(_ navigationController: UINavigationController?) { + if !DeviceInfo.hasConnectivity() { + return + } + + NotificationCenter.default.post(name: Notification.Name(rawValue: SyncNowSetting.NotificationUserInitiatedSyncManually), object: nil) + profile.syncManager.syncEverything(why: .syncNow) + } +} + +// Sync setting that shows the current Firefox Account status. +class AccountStatusSetting: WithAccountSetting { + override init(settings: SettingsTableViewController) { + super.init(settings: settings) + NotificationCenter.default.addObserver(self, selector: #selector(AccountStatusSetting.updateAccount(notification:)), name: NotificationFirefoxAccountProfileChanged, object: nil) + } + + func updateAccount(notification: Notification) { + DispatchQueue.main.async { + self.settings.tableView.reloadData() + } + } + + override var image: UIImage? { + if !AppConstants.MOZ_SHOW_FXA_AVATAR { + return nil + } + + if let image = profile.getAccount()?.fxaProfile?.avatar.image { + return image.createScaled(CGSize(width: 30, height: 30)) + } + + let image = UIImage(named: "placeholder-avatar") + return image?.createScaled(CGSize(width: 30, height: 30)) + } + + override var accessoryType: UITableViewCellAccessoryType { + if let account = profile.getAccount() { + switch account.actionNeeded { + case .needsVerification: + // We link to the resend verification email page. + return .disclosureIndicator + case .needsPassword: + // We link to the re-enter password page. + return .disclosureIndicator + case .none: + // We link to FxA web /settings. + return .disclosureIndicator + case .needsUpgrade: + // In future, we'll want to link to an upgrade page. + return .none + } + } + return .disclosureIndicator + } + + override var title: NSAttributedString? { + if let account = profile.getAccount() { + + if let displayName = account.fxaProfile?.displayName { + return NSAttributedString(string: displayName, attributes: [NSFontAttributeName: DynamicFontHelper.defaultHelper.DefaultStandardFontBold, NSForegroundColorAttributeName: UIConstants.TableViewRowSyncTextColor]) + } + + if let email = account.fxaProfile?.email { + return NSAttributedString(string: email, attributes: [NSFontAttributeName: DynamicFontHelper.defaultHelper.DefaultStandardFontBold, NSForegroundColorAttributeName: UIConstants.TableViewRowSyncTextColor]) + } + + return NSAttributedString(string: account.email, attributes: [NSFontAttributeName: DynamicFontHelper.defaultHelper.DefaultStandardFontBold, NSForegroundColorAttributeName: UIConstants.TableViewRowSyncTextColor]) + } + return nil + } + + override var status: NSAttributedString? { + if let account = profile.getAccount() { + var string: String + + switch account.actionNeeded { + case .none: + return nil + case .needsVerification: + string = NSLocalizedString("Verify your email address.", comment: "Text message in the settings table view") + break + case .needsPassword: + string = NSLocalizedString("Enter your password to connect.", comment: "Text message in the settings table view") + break + case .needsUpgrade: + string = NSLocalizedString("Upgrade Firefox to connect.", comment: "Text message in the settings table view") + break + } + + let orange = UIColor(red: 255.0 / 255, green: 149.0 / 255, blue: 0.0 / 255, alpha: 1) + let range = NSRange(location: 0, length: string.characters.count) + let attrs = [NSForegroundColorAttributeName: orange] + let res = NSMutableAttributedString(string: string) + res.setAttributes(attrs, range: range) + return res + } + return nil + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = FxAContentViewController(profile: profile) + viewController.delegate = self + + if let account = profile.getAccount() { + switch account.actionNeeded { + case .none, .needsVerification: + var cs = URLComponents(url: account.configuration.settingsURL, resolvingAgainstBaseURL: false) + cs?.queryItems?.append(URLQueryItem(name: "email", value: account.email)) + if let url = try? cs?.asURL() { + viewController.url = url + } + case .needsPassword: + var cs = URLComponents(url: account.configuration.forceAuthURL, resolvingAgainstBaseURL: false) + cs?.queryItems?.append(URLQueryItem(name: "email", value: account.email)) + if let url = try? cs?.asURL() { + viewController.url = url + } + case .needsUpgrade: + // In future, we'll want to link to an upgrade page. + return + } + } + navigationController?.pushViewController(viewController, animated: true) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + + if AppConstants.MOZ_SHOW_FXA_AVATAR { + cell.imageView?.subviews.forEach({ $0.removeFromSuperview() }) + cell.imageView?.frame = CGRect(x: 0, y: 0, width: 30, height: 30) + cell.imageView?.layer.cornerRadius = (cell.imageView?.frame.height)! / 2 + cell.imageView?.layer.masksToBounds = true + cell.imageView?.image = image + } + } +} + +// For great debugging! +class RequirePasswordDebugSetting: WithAccountSetting { + override var hidden: Bool { + if !ShowDebugSettings { + return true + } + if let account = profile.getAccount(), account.actionNeeded != FxAActionNeeded.needsPassword { + return false + } + return true + } + + override var title: NSAttributedString? { + return NSAttributedString(string: NSLocalizedString("Debug: require password", comment: "Debug option"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override func onClick(_ navigationController: UINavigationController?) { + profile.getAccount()?.makeSeparated() + settings.tableView.reloadData() + } +} + +// For great debugging! +class RequireUpgradeDebugSetting: WithAccountSetting { + override var hidden: Bool { + if !ShowDebugSettings { + return true + } + if let account = profile.getAccount(), account.actionNeeded != FxAActionNeeded.needsUpgrade { + return false + } + return true + } + + override var title: NSAttributedString? { + return NSAttributedString(string: NSLocalizedString("Debug: require upgrade", comment: "Debug option"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override func onClick(_ navigationController: UINavigationController?) { + profile.getAccount()?.makeDoghouse() + settings.tableView.reloadData() + } +} + +// For great debugging! +class ForgetSyncAuthStateDebugSetting: WithAccountSetting { + override var hidden: Bool { + if !ShowDebugSettings { + return true + } + if let _ = profile.getAccount() { + return false + } + return true + } + + override var title: NSAttributedString? { + return NSAttributedString(string: NSLocalizedString("Debug: forget Sync auth state", comment: "Debug option"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override func onClick(_ navigationController: UINavigationController?) { + profile.getAccount()?.syncAuthState.invalidate() + settings.tableView.reloadData() + } +} + +class DeleteExportedDataSetting: HiddenSetting { + override var title: NSAttributedString? { + // Not localized for now. + return NSAttributedString(string: "Debug: delete exported databases", attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override func onClick(_ navigationController: UINavigationController?) { + let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + let fileManager = FileManager.default + do { + let files = try fileManager.contentsOfDirectory(atPath: documentsPath) + for file in files { + if file.startsWith("browser.") || file.startsWith("logins.") { + try fileManager.removeItemInDirectory(documentsPath, named: file) + } + } + } catch { + print("Couldn't delete exported data: \(error).") + } + } +} + +class ExportBrowserDataSetting: HiddenSetting { + override var title: NSAttributedString? { + // Not localized for now. + return NSAttributedString(string: "Debug: copy databases to app container", attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override func onClick(_ navigationController: UINavigationController?) { + let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + do { + let log = Logger.syncLogger + try self.settings.profile.files.copyMatching(fromRelativeDirectory: "", toAbsoluteDirectory: documentsPath) { file in + log.debug("Matcher: \(file)") + return file.startsWith("browser.") || file.startsWith("logins.") || file.startsWith("metadata.") + } + } catch { + print("Couldn't export browser data: \(error).") + } + } +} + +/* + FeatureSwitchSetting is a boolean switch for features that are enabled via a FeatureSwitch. + These are usually features behind a partial release and not features released to the entire population. + */ +class FeatureSwitchSetting: BoolSetting { + let featureSwitch: FeatureSwitch + let prefs: Prefs + + init(prefs: Prefs, featureSwitch: FeatureSwitch, with title: NSAttributedString) { + self.featureSwitch = featureSwitch + self.prefs = prefs + super.init(prefs: prefs, defaultValue: featureSwitch.isMember(prefs), attributedTitleText: title) + } + + override var hidden: Bool { + return !ShowDebugSettings + } + + override func displayBool(_ control: UISwitch) { + control.isOn = featureSwitch.isMember(prefs) + } + + override func writeBool(_ control: UISwitch) { + self.featureSwitch.setMembership(control.isOn, for: self.prefs) + } + +} + +class EnableBookmarkMergingSetting: HiddenSetting { + override var title: NSAttributedString? { + // Not localized for now. + return NSAttributedString(string: "Enable Bidirectional Bookmark Sync ", attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override func onClick(_ navigationController: UINavigationController?) { + AppConstants.shouldMergeBookmarks = true + } +} + +class ForceCrashSetting: HiddenSetting { + override var title: NSAttributedString? { + return NSAttributedString(string: "Debug: Force Crash", attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override func onClick(_ navigationController: UINavigationController?) { + Sentry.shared.crash() + } +} + +// Show the current version of Firefox +class VersionSetting: Setting { + unowned let settings: SettingsTableViewController + + init(settings: SettingsTableViewController) { + self.settings = settings + super.init(title: nil) + } + + override var title: NSAttributedString? { + let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String + let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String + return NSAttributedString(string: String(format: NSLocalizedString("Version %@ (%@)", comment: "Version number of Firefox shown in settings"), appVersion, buildNumber), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + cell.selectionStyle = .none + } + + override func onClick(_ navigationController: UINavigationController?) { + DebugSettingsClickCount += 1 + if DebugSettingsClickCount >= 5 { + DebugSettingsClickCount = 0 + ShowDebugSettings = !ShowDebugSettings + settings.tableView.reloadData() + } + } +} + +// Opens the the license page in a new tab +class LicenseAndAcknowledgementsSetting: Setting { + override var title: NSAttributedString? { + return NSAttributedString(string: NSLocalizedString("Licenses", comment: "Settings item that opens a tab containing the licenses. See http://mzl.la/1NSAWCG"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override var url: URL? { + return URL(string: WebServer.sharedInstance.URLForResource("license", module: "about")) + } + + override func onClick(_ navigationController: UINavigationController?) { + setUpAndPushSettingsContentViewController(navigationController) + } +} + +// Opens about:rights page in the content view controller +class YourRightsSetting: Setting { + override var title: NSAttributedString? { + return NSAttributedString(string: NSLocalizedString("Your Rights", comment: "Your Rights settings section title"), attributes: + [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override var url: URL? { + return URL(string: "https://www.mozilla.org/about/legal/terms/firefox/") + } + + override func onClick(_ navigationController: UINavigationController?) { + setUpAndPushSettingsContentViewController(navigationController) + } +} + +// Opens the on-boarding screen again +class ShowIntroductionSetting: Setting { + let profile: Profile + + override var accessibilityIdentifier: String? { return "ShowTour" } + + init(settings: SettingsTableViewController) { + self.profile = settings.profile + super.init(title: NSAttributedString(string: NSLocalizedString("Show Tour", comment: "Show the on-boarding screen again from the settings"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor])) + } + + override func onClick(_ navigationController: UINavigationController?) { + navigationController?.dismiss(animated: true, completion: { + if let appDelegate = UIApplication.shared.delegate as? AppDelegate { + appDelegate.browserViewController.presentIntroViewController(true) + } + }) + } +} + +class SendFeedbackSetting: Setting { + override var title: NSAttributedString? { + return NSAttributedString(string: NSLocalizedString("Send Feedback", comment: "Menu item in settings used to open input.mozilla.org where people can submit feedback"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override var url: URL? { + let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String + return URL(string: "https://input.mozilla.org/feedback/fxios/\(appVersion)") + } + + override func onClick(_ navigationController: UINavigationController?) { + setUpAndPushSettingsContentViewController(navigationController) + } +} + +class SendAnonymousUsageDataSetting: BoolSetting { + init(prefs: Prefs, delegate: SettingsDelegate?) { + super.init( + prefs: prefs, prefKey: AppConstants.PrefSendUsageData, defaultValue: true, + attributedTitleText: NSAttributedString(string: Strings.SendUsageSettingTitle), + attributedStatusText: createStatusText(), + settingDidChange: { + AdjustIntegration.setEnabled($0) + LeanPlumClient.shared.set(attributes: [LPAttributeKey.telemetryOptIn: $0]) + LeanPlumClient.shared.set(enabled: $0) + } + ) + } + + private func createStatusText() -> NSAttributedString { + let statusText = NSMutableAttributedString() + statusText.append(NSAttributedString(string: Strings.SendUsageSettingMessage, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewHeaderTextColor])) + statusText.append(NSAttributedString(string: " ")) + statusText.append(NSAttributedString(string: Strings.SendUsageSettingLink, attributes: [NSForegroundColorAttributeName: UIConstants.HighlightBlue])) + return statusText + } + + override var url: URL? { + return SupportUtils.URLForTopic("adjust") + } + + override func onClick(_ navigationController: UINavigationController?) { + setUpAndPushSettingsContentViewController(navigationController) + } +} + +// Opens the the SUMO page in a new tab +class OpenSupportPageSetting: Setting { + init(delegate: SettingsDelegate?) { + super.init(title: NSAttributedString(string: NSLocalizedString("Help", comment: "Show the SUMO support page from the Support section in the settings. see http://mzl.la/1dmM8tZ"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]), + delegate: delegate) + } + + override func onClick(_ navigationController: UINavigationController?) { + navigationController?.dismiss(animated: true) { + if let url = URL(string: "https://support.mozilla.org/products/ios") { + self.delegate?.settingsOpenURLInNewTab(url) + } + } + } +} + +// Opens the search settings pane +class SearchSetting: Setting { + let profile: Profile + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var style: UITableViewCellStyle { return .value1 } + + override var status: NSAttributedString { return NSAttributedString(string: profile.searchEngines.defaultEngine.shortName) } + + override var accessibilityIdentifier: String? { return "Search" } + + init(settings: SettingsTableViewController) { + self.profile = settings.profile + super.init(title: NSAttributedString(string: NSLocalizedString("Search", comment: "Open search section of settings"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor])) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = SearchSettingsTableViewController() + viewController.model = profile.searchEngines + viewController.profile = profile + navigationController?.pushViewController(viewController, animated: true) + } +} + +class LoginsSetting: Setting { + let profile: Profile + var tabManager: TabManager! + weak var navigationController: UINavigationController? + weak var settings: AppSettingsTableViewController? + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var accessibilityIdentifier: String? { return "Logins" } + + init(settings: SettingsTableViewController, delegate: SettingsDelegate?) { + self.profile = settings.profile + self.tabManager = settings.tabManager + self.navigationController = settings.navigationController + self.settings = settings as? AppSettingsTableViewController + + let loginsTitle = NSLocalizedString("Logins", comment: "Label used as an item in Settings. When touched, the user will be navigated to the Logins/Password manager.") + super.init(title: NSAttributedString(string: loginsTitle, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]), + delegate: delegate) + } + + func deselectRow () { + if let selectedRow = self.settings?.tableView.indexPathForSelectedRow { + self.settings?.tableView.deselectRow(at: selectedRow, animated: true) + } + } + + override func onClick(_: UINavigationController?) { + guard let authInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo() else { + settings?.navigateToLoginsList() + LeanPlumClient.shared.track(event: .openedLogins) + return + } + + if authInfo.requiresValidation() { + AppAuthenticator.presentAuthenticationUsingInfo(authInfo, + touchIDReason: AuthenticationStrings.loginsTouchReason, + success: { + self.settings?.navigateToLoginsList() + LeanPlumClient.shared.track(event: .openedLogins) + }, + cancel: { + self.deselectRow() + }, + fallback: { + AppAuthenticator.presentPasscodeAuthentication(self.navigationController, delegate: self.settings) + self.deselectRow() + }) + } else { + settings?.navigateToLoginsList() + LeanPlumClient.shared.track(event: .openedLogins) + } + } +} + +class TouchIDPasscodeSetting: Setting { + let profile: Profile + var tabManager: TabManager! + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var accessibilityIdentifier: String? { return "TouchIDPasscode" } + + init(settings: SettingsTableViewController, delegate: SettingsDelegate? = nil) { + self.profile = settings.profile + self.tabManager = settings.tabManager + let localAuthContext = LAContext() + + let title: String + if localAuthContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) { + if #available(iOS 11.0, *), localAuthContext.biometryType == .faceID { + title = AuthenticationStrings.faceIDPasscodeSetting + } else { + title = AuthenticationStrings.touchIDPasscodeSetting + } + } else { + title = AuthenticationStrings.passcode + } + super.init(title: NSAttributedString(string: title, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]), + delegate: delegate) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = AuthenticationSettingsViewController() + viewController.profile = profile + navigationController?.pushViewController(viewController, animated: true) + } +} + +@available(iOS 11, *) +class ContentBlockerSetting: Setting { + let profile: Profile + var tabManager: TabManager! + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + override var accessibilityIdentifier: String? { return "TrackingProtection" } + + init(settings: SettingsTableViewController) { + self.profile = settings.profile + self.tabManager = settings.tabManager + super.init(title: NSAttributedString(string: Strings.SettingsTrackingProtectionSectionName, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor])) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = ContentBlockerSettingViewController(prefs: profile.prefs) + viewController.profile = profile + viewController.tabManager = tabManager + navigationController?.pushViewController(viewController, animated: true) + } +} + +class ClearPrivateDataSetting: Setting { + let profile: Profile + var tabManager: TabManager! + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var accessibilityIdentifier: String? { return "ClearPrivateData" } + + init(settings: SettingsTableViewController) { + self.profile = settings.profile + self.tabManager = settings.tabManager + + let clearTitle = Strings.SettingsClearPrivateDataSectionName + super.init(title: NSAttributedString(string: clearTitle, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor])) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = ClearPrivateDataTableViewController() + viewController.profile = profile + viewController.tabManager = tabManager + navigationController?.pushViewController(viewController, animated: true) + } +} + +class PrivacyPolicySetting: Setting { + override var title: NSAttributedString? { + return NSAttributedString(string: NSLocalizedString("Privacy Policy", comment: "Show Firefox Browser Privacy Policy page from the Privacy section in the settings. See https://www.mozilla.org/privacy/firefox/"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override var url: URL? { + return URL(string: "https://www.mozilla.org/privacy/firefox/") + } + + override func onClick(_ navigationController: UINavigationController?) { + setUpAndPushSettingsContentViewController(navigationController) + } +} + +class ChinaSyncServiceSetting: WithoutAccountSetting { + override var accessoryType: UITableViewCellAccessoryType { return .none } + var prefs: Prefs { return settings.profile.prefs } + let prefKey = "useChinaSyncService" + + override var title: NSAttributedString? { + return NSAttributedString(string: "本地同步服务", attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override var status: NSAttributedString? { + return NSAttributedString(string: "禁用后使用全球服务同步数据", attributes: [NSForegroundColorAttributeName: UIConstants.TableViewHeaderTextColor]) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + let control = UISwitch() + control.onTintColor = UIConstants.ControlTintColor + control.addTarget(self, action: #selector(ChinaSyncServiceSetting.switchValueChanged(_:)), for: UIControlEvents.valueChanged) + control.isOn = prefs.boolForKey(prefKey) ?? self.profile.isChinaEdition + cell.accessoryView = control + cell.selectionStyle = .none + } + + @objc func switchValueChanged(_ toggle: UISwitch) { + prefs.setObject(toggle.isOn, forKey: prefKey) + } +} + +class StageSyncServiceDebugSetting: WithoutAccountSetting { + override var accessoryType: UITableViewCellAccessoryType { return .none } + var prefs: Prefs { return settings.profile.prefs } + + var prefKey: String = "useStageSyncService" + + override var hidden: Bool { + if !ShowDebugSettings { + return true + } + if let _ = profile.getAccount() { + return true + } + return false + } + + override var title: NSAttributedString? { + return NSAttributedString(string: NSLocalizedString("Debug: use stage servers", comment: "Debug option"), attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override var status: NSAttributedString? { + // Derive the configuration we display from the profile. Currently, this could be either a custom + // FxA server or FxA stage servers. + let isOn = prefs.boolForKey(prefKey) ?? false + let isCustomSync = prefs.boolForKey(PrefsKeys.KeyUseCustomSyncService) ?? false + + var configurationURL = ProductionFirefoxAccountConfiguration().authEndpointURL + if isCustomSync { + configurationURL = CustomFirefoxAccountConfiguration(prefs: profile.prefs).authEndpointURL + } else if isOn { + configurationURL = StageFirefoxAccountConfiguration().authEndpointURL + } + + return NSAttributedString(string: configurationURL.absoluteString, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewHeaderTextColor]) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + let control = UISwitch() + control.onTintColor = UIConstants.ControlTintColor + control.addTarget(self, action: #selector(StageSyncServiceDebugSetting.switchValueChanged(_:)), for: UIControlEvents.valueChanged) + control.isOn = prefs.boolForKey(prefKey) ?? false + cell.accessoryView = control + cell.selectionStyle = .none + } + + @objc func switchValueChanged(_ toggle: UISwitch) { + prefs.setObject(toggle.isOn, forKey: prefKey) + settings.tableView.reloadData() + } +} + +class HomePageSetting: Setting { + let profile: Profile + var tabManager: TabManager! + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var accessibilityIdentifier: String? { return "Homepage" } + + init(settings: SettingsTableViewController) { + self.profile = settings.profile + self.tabManager = settings.tabManager + + super.init(title: NSAttributedString(string: Strings.SettingsHomePageSectionName, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor])) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = HomePageSettingsViewController() + viewController.profile = profile + viewController.tabManager = tabManager + navigationController?.pushViewController(viewController, animated: true) + } +} + +class NewTabPageSetting: Setting { + let profile: Profile + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var accessibilityIdentifier: String? { return "NewTab" } + + init(settings: SettingsTableViewController) { + self.profile = settings.profile + + super.init(title: NSAttributedString(string: Strings.SettingsNewTabSectionName, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor])) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = NewTabContentSettingsViewController() + viewController.profile = profile + navigationController?.pushViewController(viewController, animated: true) + } +} + +class OpenWithSetting: Setting { + let profile: Profile + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var accessibilityIdentifier: String? { return "OpenWith.Setting" } + + init(settings: SettingsTableViewController) { + self.profile = settings.profile + + super.init(title: NSAttributedString(string: Strings.SettingsOpenWithSectionName, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor])) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = OpenWithSettingsViewController(prefs: profile.prefs) + navigationController?.pushViewController(viewController, animated: true) + } +} + +class AdvanceAccountSetting: HiddenSetting { + let profile: Profile + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var accessibilityIdentifier: String? { return "AdvanceAccount.Setting" } + + override var title: NSAttributedString? { + return NSAttributedString(string: Strings.SettingsAdvanceAccountTitle, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + } + + override init(settings: SettingsTableViewController) { + self.profile = settings.profile + super.init(settings: settings) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = AdvanceAccountSettingViewController() + viewController.profile = profile + navigationController?.pushViewController(viewController, animated: true) + } + + override var hidden: Bool { + return !ShowDebugSettings || profile.hasAccount() + } +} diff --git a/mobile/ios/Client/Frontend/Settings/AppSettingsTableViewController.swift b/mobile/ios/Client/Frontend/Settings/AppSettingsTableViewController.swift new file mode 100644 index 0000000000..98873d8dc0 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/AppSettingsTableViewController.swift @@ -0,0 +1,172 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared +import Account + +/// App Settings Screen (triggered by tapping the 'Gear' in the Tab Tray Controller) +class AppSettingsTableViewController: SettingsTableViewController { + fileprivate let SectionHeaderIdentifier = "SectionHeaderIdentifier" + + override func viewDidLoad() { + super.viewDidLoad() + + navigationItem.title = NSLocalizedString("Settings", comment: "Title in the settings view controller title bar") + navigationItem.leftBarButtonItem = UIBarButtonItem( + title: NSLocalizedString("Done", comment: "Done button on left side of the Settings view controller title bar"), + style: UIBarButtonItemStyle.done, + target: navigationController, action: #selector((navigationController as! SettingsNavigationController).SELdone)) + navigationItem.leftBarButtonItem?.accessibilityIdentifier = "AppSettingsTableViewController.navigationItem.leftBarButtonItem" + + tableView.accessibilityIdentifier = "AppSettingsTableViewController.tableView" + + // Refresh the user's FxA profile upon viewing settings. This will update their avatar, + // display name, etc. + if AppConstants.MOZ_SHOW_FXA_AVATAR { + profile.getAccount()?.updateProfile() + } + } + + override func generateSettings() -> [SettingSection] { + var settings = [SettingSection]() + + let privacyTitle = NSLocalizedString("Privacy", comment: "Privacy section title") + let accountDebugSettings = [ + // Debug settings: + RequirePasswordDebugSetting(settings: self), + RequireUpgradeDebugSetting(settings: self), + ForgetSyncAuthStateDebugSetting(settings: self), + StageSyncServiceDebugSetting(settings: self), + ] + + let prefs = profile.prefs + var generalSettings: [Setting] = [ + SearchSetting(settings: self), + NewTabPageSetting(settings: self), + HomePageSetting(settings: self), + OpenWithSetting(settings: self), + BoolSetting(prefs: prefs, prefKey: "blockPopups", defaultValue: true, + titleText: NSLocalizedString("Block Pop-up Windows", comment: "Block pop-up windows setting")), + BoolSetting(prefs: prefs, prefKey: "saveLogins", defaultValue: true, + titleText: NSLocalizedString("Save Logins", comment: "Setting to enable the built-in password manager")), + ] + + let accountChinaSyncSetting: [Setting] + if !profile.isChinaEdition { + accountChinaSyncSetting = [] + } else { + accountChinaSyncSetting = [ + // Show China sync service setting: + ChinaSyncServiceSetting(settings: self) + ] + } + // There is nothing to show in the Customize section if we don't include the compact tab layout + // setting on iPad. When more options are added that work on both device types, this logic can + // be changed. + + if AppConstants.MOZ_CLIPBOARD_BAR { + generalSettings += [ + BoolSetting(prefs: prefs, prefKey: "showClipboardBar", defaultValue: false, + titleText: Strings.SettingsOfferClipboardBarTitle, + statusText: Strings.SettingsOfferClipboardBarStatus) + ] + } + + var accountSectionTitle: NSAttributedString? + if AppConstants.MOZ_SHOW_FXA_AVATAR { + accountSectionTitle = NSAttributedString(string: Strings.FxAFirefoxAccount) + } + + let footerText = !profile.hasAccount() ? NSAttributedString(string: Strings.FxASyncUsageDetails) : nil + settings += [ + SettingSection(title: accountSectionTitle, footerTitle: footerText, children: [ + // Without a Firefox Account: + ConnectSetting(settings: self), + AdvanceAccountSetting(settings: self), + // With a Firefox Account: + AccountStatusSetting(settings: self), + SyncNowSetting(settings: self) + ] + accountChinaSyncSetting + accountDebugSettings)] + + settings += [ SettingSection(title: NSAttributedString(string: NSLocalizedString("General", comment: "General settings section title")), children: generalSettings)] + + var privacySettings = [Setting]() + privacySettings.append(LoginsSetting(settings: self, delegate: settingsDelegate)) + privacySettings.append(TouchIDPasscodeSetting(settings: self)) + + privacySettings.append(ClearPrivateDataSetting(settings: self)) + + privacySettings += [ + BoolSetting(prefs: prefs, + prefKey: "settings.closePrivateTabs", + defaultValue: false, + titleText: NSLocalizedString("Close Private Tabs", tableName: "PrivateBrowsing", comment: "Setting for closing private tabs"), + statusText: NSLocalizedString("When Leaving Private Browsing", tableName: "PrivateBrowsing", comment: "Will be displayed in Settings under 'Close Private Tabs'")) + ] + + if #available(iOS 11, *) { + privacySettings.append(ContentBlockerSetting(settings: self)) + } + + privacySettings += [ + PrivacyPolicySetting() + ] + + settings += [ + SettingSection(title: NSAttributedString(string: privacyTitle), children: privacySettings), + SettingSection(title: NSAttributedString(string: NSLocalizedString("Support", comment: "Support section title")), children: [ + ShowIntroductionSetting(settings: self), + SendFeedbackSetting(), + SendAnonymousUsageDataSetting(prefs: prefs, delegate: settingsDelegate), + OpenSupportPageSetting(delegate: settingsDelegate), + ]), + SettingSection(title: NSAttributedString(string: NSLocalizedString("About", comment: "About settings section title")), children: [ + VersionSetting(settings: self), + LicenseAndAcknowledgementsSetting(), + YourRightsSetting(), + ExportBrowserDataSetting(settings: self), + DeleteExportedDataSetting(settings: self), + EnableBookmarkMergingSetting(settings: self), + ForceCrashSetting(settings: self) + ])] + + if profile.hasAccount() { + settings += [SettingSection(title: nil, footerTitle: NSAttributedString(string: ""), children: [DisconnectSetting(settings: self)])] + } + + return settings + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView = super.tableView(tableView, viewForHeaderInSection: section) as! SettingsTableSectionHeaderFooterView + // Prevent the top border from showing for the General section. + if !profile.hasAccount() { + switch section { + case 1: + headerView.showTopBorder = false + default: + break + } + } + return headerView + } +} + +extension AppSettingsTableViewController { + func navigateToLoginsList() { + let viewController = LoginListViewController(profile: profile) + viewController.settingsDelegate = settingsDelegate + navigationController?.pushViewController(viewController, animated: true) + } +} + +extension AppSettingsTableViewController: PasscodeEntryDelegate { + @objc func passcodeValidationDidSucceed() { + navigationController?.dismiss(animated: true) { + self.navigateToLoginsList() + } + } +} diff --git a/mobile/ios/Client/Frontend/Settings/ClearPrivateDataTableViewController.swift b/mobile/ios/Client/Frontend/Settings/ClearPrivateDataTableViewController.swift new file mode 100644 index 0000000000..338b100b0a --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/ClearPrivateDataTableViewController.swift @@ -0,0 +1,176 @@ +/* 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/. */ + +import UIKit +import Shared + +private let SectionToggles = 0 +private let SectionButton = 1 +private let NumberOfSections = 2 +private let SectionHeaderFooterIdentifier = "SectionHeaderFooterIdentifier" +private let TogglesPrefKey = "clearprivatedata.toggles" + +private let log = Logger.browserLogger + +private let HistoryClearableIndex = 0 + +class ClearPrivateDataTableViewController: UITableViewController { + fileprivate var clearButton: UITableViewCell? + + var profile: Profile! + var tabManager: TabManager! + + fileprivate typealias DefaultCheckedState = Bool + + fileprivate lazy var clearables: [(clearable: Clearable, checked: DefaultCheckedState)] = { + return [ + (HistoryClearable(profile: self.profile), true), + (CacheClearable(tabManager: self.tabManager), true), + (CookiesClearable(tabManager: self.tabManager), true), + (SiteDataClearable(tabManager: self.tabManager), true), + ] + }() + + fileprivate lazy var toggles: [Bool] = { + if let savedToggles = self.profile.prefs.arrayForKey(TogglesPrefKey) as? [Bool] { + return savedToggles + } + + return self.clearables.map { $0.checked } + }() + + fileprivate var clearButtonEnabled = true { + didSet { + clearButton?.textLabel?.textColor = clearButtonEnabled ? UIConstants.DestructiveRed : UIColor.lightGray + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + title = Strings.SettingsClearPrivateDataTitle + + tableView.register(SettingsTableSectionHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: SectionHeaderFooterIdentifier) + + tableView.separatorColor = UIConstants.TableViewSeparatorColor + tableView.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + let footer = SettingsTableSectionHeaderFooterView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: UIConstants.TableViewHeaderFooterHeight)) + footer.showBottomBorder = false + tableView.tableFooterView = footer + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) + + if indexPath.section == SectionToggles { + cell.textLabel?.text = clearables[indexPath.item].clearable.label + let control = UISwitch() + control.onTintColor = UIConstants.ControlTintColor + control.addTarget(self, action: #selector(ClearPrivateDataTableViewController.switchValueChanged(_:)), for: UIControlEvents.valueChanged) + control.isOn = toggles[indexPath.item] + cell.accessoryView = control + cell.selectionStyle = .none + control.tag = indexPath.item + } else { + assert(indexPath.section == SectionButton) + cell.textLabel?.text = Strings.SettingsClearPrivateDataClearButton + cell.textLabel?.textAlignment = NSTextAlignment.center + cell.textLabel?.textColor = UIConstants.DestructiveRed + cell.accessibilityTraits = UIAccessibilityTraitButton + cell.accessibilityIdentifier = "ClearPrivateData" + clearButton = cell + } + + return cell + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return NumberOfSections + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == SectionToggles { + return clearables.count + } + + assert(section == SectionButton) + return 1 + } + + override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { + guard indexPath.section == SectionButton else { return false } + + // Highlight the button only if it's enabled. + return clearButtonEnabled + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + guard indexPath.section == SectionButton else { return } + + func clearPrivateData(_ action: UIAlertAction) { + let toggles = self.toggles + self.clearables + .enumerated() + .flatMap { (i, pair) in + guard toggles[i] else { + return nil + } + log.debug("Clearing \(pair.clearable).") + return pair.clearable.clear() + } + .allSucceed() + .upon { result in + assert(result.isSuccess, "Private data cleared successfully") + + LeanPlumClient.shared.track(event: .clearPrivateData) + + self.profile.prefs.setObject(self.toggles, forKey: TogglesPrefKey) + + DispatchQueue.main.async { + // Disable the Clear Private Data button after it's clicked. + self.clearButtonEnabled = false + self.tableView.deselectRow(at: indexPath, animated: true) + } + } + } + + // We have been asked to clear history and we have an account. + // (Whether or not it's in a good state is irrelevant.) + if self.toggles[HistoryClearableIndex] && profile.hasAccount() { + profile.syncManager.hasSyncedHistory().uponQueue(DispatchQueue.main) { yes in + // Err on the side of warning, but this shouldn't fail. + let alert: UIAlertController + if yes.successValue ?? true { + // Our local database contains some history items that have been synced. + // Warn the user before clearing. + alert = UIAlertController.clearSyncedHistoryAlert(okayCallback: clearPrivateData) + } else { + alert = UIAlertController.clearPrivateDataAlert(okayCallback: clearPrivateData) + } + self.present(alert, animated: true, completion: nil) + return + } + } else { + let alert = UIAlertController.clearPrivateDataAlert(okayCallback: clearPrivateData) + self.present(alert, animated: true, completion: nil) + } + + tableView.deselectRow(at: indexPath, animated: false) + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + return tableView.dequeueReusableHeaderFooterView(withIdentifier: SectionHeaderFooterIdentifier) as! SettingsTableSectionHeaderFooterView + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return UIConstants.TableViewHeaderFooterHeight + } + + @objc func switchValueChanged(_ toggle: UISwitch) { + toggles[toggle.tag] = toggle.isOn + + // Dim the clear button if no clearables are selected. + clearButtonEnabled = toggles.contains(true) + } +} diff --git a/mobile/ios/Client/Frontend/Settings/Clearables.swift b/mobile/ios/Client/Frontend/Settings/Clearables.swift new file mode 100644 index 0000000000..1e0fbfb553 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/Clearables.swift @@ -0,0 +1,149 @@ +/* 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/. */ + +import Foundation +import Shared +import WebKit +import Deferred +import SDWebImage +import CoreSpotlight + +private let log = Logger.browserLogger + +// Removed Clearables as part of Bug 1226654, but keeping the string around. +private let removedSavedLoginsLabel = NSLocalizedString("Saved Logins", tableName: "ClearPrivateData", comment: "Settings item for clearing passwords and login data") + +// A base protocol for something that can be cleared. +protocol Clearable { + func clear() -> Success + var label: String { get } +} + +class ClearableError: MaybeErrorType { + fileprivate let msg: String + init(msg: String) { + self.msg = msg + } + + var description: String { return msg } +} + +// Clears our browsing history, including favicons and thumbnails. +class HistoryClearable: Clearable { + let profile: Profile + init(profile: Profile) { + self.profile = profile + } + + var label: String { + return NSLocalizedString("Browsing History", tableName: "ClearPrivateData", comment: "Settings item for clearing browsing history") + } + + func clear() -> Success { + return profile.history.clearHistory().bindQueue(.main) { success in + SDImageCache.shared().clearDisk() + SDImageCache.shared().clearMemory() + self.profile.recentlyClosedTabs.clearTabs() + CSSearchableIndex.default().deleteAllSearchableItems() + NotificationCenter.default.post(name: NotificationPrivateDataClearedHistory, object: nil) + log.debug("HistoryClearable succeeded: \(success).") + return Deferred(value: success) + } + } +} + +struct ClearableErrorType: MaybeErrorType { + let err: Error + + init(err: Error) { + self.err = err + } + + var description: String { + return "Couldn't clear: \(err)." + } +} + +// Clear the web cache. Note, this has to close all open tabs in order to ensure the data +// cached in them isn't flushed to disk. +class CacheClearable: Clearable { + let tabManager: TabManager + init(tabManager: TabManager) { + self.tabManager = tabManager + } + + var label: String { + return NSLocalizedString("Cache", tableName: "ClearPrivateData", comment: "Settings item for clearing the cache") + } + + func clear() -> Success { + let dataTypes = Set([WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache]) + WKWebsiteDataStore.default().removeData(ofTypes: dataTypes, modifiedSince: Date.distantPast, completionHandler: {}) + + log.debug("CacheClearable succeeded.") + return succeed() + } +} + +private func deleteLibraryFolderContents(_ folder: String) throws { + let manager = FileManager.default + let library = manager.urls(for: FileManager.SearchPathDirectory.libraryDirectory, in: .userDomainMask)[0] + let dir = library.appendingPathComponent(folder) + let contents = try manager.contentsOfDirectory(atPath: dir.path) + for content in contents { + do { + try manager.removeItem(at: dir.appendingPathComponent(content)) + } catch where ((error as NSError).userInfo[NSUnderlyingErrorKey] as? NSError)?.code == Int(EPERM) { + // "Not permitted". We ignore this. + log.debug("Couldn't delete some library contents.") + } + } +} + +private func deleteLibraryFolder(_ folder: String) throws { + let manager = FileManager.default + let library = manager.urls(for: FileManager.SearchPathDirectory.libraryDirectory, in: .userDomainMask)[0] + let dir = library.appendingPathComponent(folder) + try manager.removeItem(at: dir) +} + +// Removes all app cache storage. +class SiteDataClearable: Clearable { + let tabManager: TabManager + init(tabManager: TabManager) { + self.tabManager = tabManager + } + + var label: String { + return NSLocalizedString("Offline Website Data", tableName: "ClearPrivateData", comment: "Settings item for clearing website data") + } + + func clear() -> Success { + let dataTypes = Set([WKWebsiteDataTypeOfflineWebApplicationCache]) + WKWebsiteDataStore.default().removeData(ofTypes: dataTypes, modifiedSince: Date.distantPast, completionHandler: {}) + + log.debug("SiteDataClearable succeeded.") + return succeed() + } +} + +// Remove all cookies stored by the site. This includes localStorage, sessionStorage, and WebSQL/IndexedDB. +class CookiesClearable: Clearable { + let tabManager: TabManager + init(tabManager: TabManager) { + self.tabManager = tabManager + } + + var label: String { + return NSLocalizedString("Cookies", tableName: "ClearPrivateData", comment: "Settings item for clearing cookies") + } + + func clear() -> Success { + let dataTypes = Set([WKWebsiteDataTypeCookies, WKWebsiteDataTypeLocalStorage, WKWebsiteDataTypeSessionStorage, WKWebsiteDataTypeWebSQLDatabases, WKWebsiteDataTypeIndexedDBDatabases]) + WKWebsiteDataStore.default().removeData(ofTypes: dataTypes, modifiedSince: Date.distantPast, completionHandler: {}) + + log.debug("CookiesClearable succeeded.") + return succeed() + } +} diff --git a/mobile/ios/Client/Frontend/Settings/CustomSearchViewController.swift b/mobile/ios/Client/Frontend/Settings/CustomSearchViewController.swift new file mode 100644 index 0000000000..dfcdf071bd --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/CustomSearchViewController.swift @@ -0,0 +1,252 @@ +/* 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/. */ + +import UIKit +import Shared +import SnapKit +import Storage +import SDWebImage +import Deferred + +private let log = Logger.browserLogger + +class CustomSearchError: MaybeErrorType { + + enum Reason { + case DuplicateEngine, FormInput + } + + var reason: Reason! + + internal var description: String { + return "Search Engine Not Added" + } + + init(_ reason: Reason) { + self.reason = reason + } +} + +class CustomSearchViewController: SettingsTableViewController { + + fileprivate var urlString: String? + fileprivate var engineTitle = "" + fileprivate lazy var spinnerView: UIActivityIndicatorView = { + let spinner = UIActivityIndicatorView(activityIndicatorStyle: .gray) + spinner.hidesWhenStopped = true + return spinner + }() + + override func viewDidLoad() { + super.viewDidLoad() + title = Strings.SettingsAddCustomEngineTitle + view.addSubview(spinnerView) + spinnerView.snp.makeConstraints { make in + make.center.equalTo(self.view.snp.center) + } + } + + var successCallback: (() -> Void)? + + fileprivate func addSearchEngine(_ searchQuery: String, title: String) { + spinnerView.startAnimating() + + let trimmedQuery = searchQuery.trimmingCharacters(in: .whitespacesAndNewlines) + let trimmedTitle = title.trimmingCharacters(in: .whitespacesAndNewlines) + + createEngine(forQuery: trimmedQuery, andName: trimmedTitle).uponQueue(DispatchQueue.main) { result in + self.spinnerView.stopAnimating() + guard let engine = result.successValue else { + let alert: UIAlertController + let error = result.failureValue as? CustomSearchError + + alert = (error?.reason == .DuplicateEngine) ? + ThirdPartySearchAlerts.duplicateCustomEngine() : ThirdPartySearchAlerts.incorrectCustomEngineForm() + + self.navigationItem.rightBarButtonItem?.isEnabled = true + self.present(alert, animated: true, completion: nil) + return + } + self.profile.searchEngines.addSearchEngine(engine) + + CATransaction.begin() // Use transaction to call callback after animation has been completed + CATransaction.setCompletionBlock(self.successCallback) + _ = self.navigationController?.popViewController(animated: true) + CATransaction.commit() + } + } + + func createEngine(forQuery query: String, andName name: String) -> Deferred> { + let deferred = Deferred>() + guard let template = getSearchTemplate(withString: query), + let url = URL(string: template.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlFragmentAllowed)!), url.isWebPage() else { + deferred.fill(Maybe(failure: CustomSearchError(.FormInput))) + return deferred + } + + // ensure we haven't already stored this template + guard engineExists(name: name, template: template) == false else { + deferred.fill(Maybe(failure: CustomSearchError(.DuplicateEngine))) + return deferred + } + + FaviconFetcher.fetchFavImageForURL(forURL: url, profile: profile).uponQueue(DispatchQueue.main) { result in + let image = result.successValue ?? FaviconFetcher.getDefaultFavicon(url) + let engine = OpenSearchEngine(engineID: nil, shortName: name, image: image, searchTemplate: template, suggestTemplate: nil, isCustomEngine: true) + + //Make sure a valid scheme is used + let url = engine.searchURLForQuery("test") + let maybe = (url == nil) ? Maybe(failure: CustomSearchError(.FormInput)) : Maybe(success: engine) + deferred.fill(maybe) + } + return deferred + } + + private func engineExists(name: String, template: String) -> Bool { + return profile.searchEngines.orderedEngines.contains { (engine) -> Bool in + return engine.shortName == name || engine.searchTemplate == template + } + } + + func getSearchTemplate(withString query: String) -> String? { + let SearchTermComponent = "%s" //Placeholder in User Entered String + let placeholder = "{searchTerms}" //Placeholder looked for when using Custom Search Engine in OpenSearch.swift + + if query.contains(SearchTermComponent) { + return query.replacingOccurrences(of: SearchTermComponent, with: placeholder) + } + return nil + } + + override func generateSettings() -> [SettingSection] { + + func URLFromString(_ string: String?) -> URL? { + guard let string = string else { + return nil + } + return URL(string: string) + } + + let titleField = CustomSearchEngineTextView(placeholder: Strings.SettingsAddCustomEngineTitlePlaceholder, settingIsValid: { text in + return text != nil && text != "" + }, settingDidChange: {fieldText in + guard let title = fieldText else { + return + } + self.engineTitle = title + }) + titleField.textField.accessibilityIdentifier = "customEngineTitle" + + let urlField = CustomSearchEngineTextView(placeholder: Strings.SettingsAddCustomEngineURLPlaceholder, height: 133, settingIsValid: { text in + //Can check url text text validity here. + return true + }, settingDidChange: {fieldText in + self.urlString = fieldText + }) + + urlField.textField.autocapitalizationType = .none + urlField.textField.accessibilityIdentifier = "customEngineUrl" + + let settings: [SettingSection] = [ + SettingSection(title: NSAttributedString(string: Strings.SettingsAddCustomEngineTitleLabel), children: [titleField]), + SettingSection(title: NSAttributedString(string: Strings.SettingsAddCustomEngineURLLabel), footerTitle: NSAttributedString(string: "http://youtube.com/search?q=%s"), children: [urlField]) + ] + + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(self.addCustomSearchEngine(_:))) + self.navigationItem.rightBarButtonItem?.accessibilityIdentifier = "customEngineSaveButton" + + return settings + } + + func addCustomSearchEngine(_ nav: UINavigationController?) { + self.view.endEditing(true) + navigationItem.rightBarButtonItem?.isEnabled = false + if let url = self.urlString { + self.addSearchEngine(url, title: self.engineTitle) + } + } +} + +class CustomSearchEngineTextView: Setting, UITextViewDelegate { + + fileprivate let Padding: CGFloat = 8 + fileprivate let TextLabelHeight: CGFloat = 44 + fileprivate var TextFieldHeight: CGFloat = 44 + + fileprivate let defaultValue: String? + fileprivate let placeholder: String + fileprivate let settingDidChange: ((String?) -> Void)? + fileprivate let settingIsValid: ((String?) -> Bool)? + + let textField = UITextView() + let placeholderLabel = UILabel() + + init(defaultValue: String? = nil, placeholder: String, height: CGFloat = 44, settingIsValid isValueValid: ((String?) -> Bool)? = nil, settingDidChange: ((String?) -> Void)? = nil) { + self.defaultValue = defaultValue + self.TextFieldHeight = height + self.settingDidChange = settingDidChange + self.settingIsValid = isValueValid + self.placeholder = placeholder + textField.addSubview(placeholderLabel) + super.init(cellHeight: TextFieldHeight) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + if let id = accessibilityIdentifier { + textField.accessibilityIdentifier = id + "TextField" + } + + placeholderLabel.adjustsFontSizeToFitWidth = true + placeholderLabel.textColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22) + placeholderLabel.text = placeholder + placeholderLabel.frame = CGRect(x: 0, y: 0, width: textField.frame.width, height: TextLabelHeight) + textField.font = placeholderLabel.font + + textField.textContainer.lineFragmentPadding = 0 + textField.keyboardType = .URL + textField.autocorrectionType = .no + textField.delegate = self + cell.isUserInteractionEnabled = true + cell.accessibilityTraits = UIAccessibilityTraitNone + cell.contentView.addSubview(textField) + cell.selectionStyle = .none + + textField.snp.makeConstraints { make in + make.height.equalTo(TextFieldHeight) + make.left.right.equalTo(cell.contentView).inset(Padding) + } + } + + override func onClick(_ navigationController: UINavigationController?) { + textField.becomeFirstResponder() + } + + fileprivate func isValid(_ value: String?) -> Bool { + guard let test = settingIsValid else { + return true + } + return test(prepareValidValue(userInput: value)) + } + + func prepareValidValue(userInput value: String?) -> String? { + return value + } + + func textViewDidBeginEditing(_ textView: UITextView) { + placeholderLabel.isHidden = textField.text != "" + } + + func textViewDidChange(_ textView: UITextView) { + placeholderLabel.isHidden = textField.text != "" + settingDidChange?(textView.text) + let color = isValid(textField.text) ? UIConstants.TableViewRowTextColor : UIConstants.DestructiveRed + textField.textColor = color + } + + func textViewDidEndEditing(_ textView: UITextView) { + placeholderLabel.isHidden = textField.text != "" + settingDidChange?(textView.text) + } +} diff --git a/mobile/ios/Client/Frontend/Settings/FxAContentViewController.swift b/mobile/ios/Client/Frontend/Settings/FxAContentViewController.swift new file mode 100644 index 0000000000..0884e28b39 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/FxAContentViewController.swift @@ -0,0 +1,278 @@ +/* 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/. */ + +import Foundation +import Shared +import SnapKit +import UIKit +import WebKit +import SwiftyJSON + +protocol FxAContentViewControllerDelegate: class { + func contentViewControllerDidSignIn(_ viewController: FxAContentViewController, withFlags: FxALoginFlags) + func contentViewControllerDidCancel(_ viewController: FxAContentViewController) +} + +/** + * A controller that manages a single web view connected to the Firefox + * Accounts (Desktop) Sync postMessage interface. + * + * The postMessage interface is not really documented, but it is simple + * enough. I reverse engineered it from the Desktop Firefox code and the + * fxa-content-server git repository. + */ +class FxAContentViewController: SettingsContentViewController, WKScriptMessageHandler { + fileprivate enum RemoteCommand: String { + case canLinkAccount = "can_link_account" + case loaded = "loaded" + case login = "login" + case sessionStatus = "session_status" + case signOut = "sign_out" + } + + weak var delegate: FxAContentViewControllerDelegate? + + let profile: Profile + + init(profile: Profile, fxaOptions: FxALaunchParams? = nil) { + self.profile = profile + + super.init(backgroundColor: UIColor(red: 242 / 255.0, green: 242 / 255.0, blue: 242 / 255.0, alpha: 1.0), title: NSAttributedString(string: "Firefox Accounts")) + + if AppConstants.MOZ_FXA_DEEP_LINK_FORM_FILL { + self.url = self.createFxAURLWith(fxaOptions, profile: profile) + } else { + self.url = profile.accountConfiguration.signInURL + } + + NotificationCenter.default.addObserver(self, selector: #selector(FxAContentViewController.userDidVerify(_:)), name: NotificationFirefoxAccountVerified, object: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + if AppConstants.MOZ_SHOW_FXA_AVATAR { + profile.getAccount()?.updateProfile() + } + + // If the FxAContentViewController was launched from a FxA deferred link + // onboarding might not have been shown. Check to see if it needs to be + // displayed and don't animate. + if let appDelegate = UIApplication.shared.delegate as? AppDelegate { + appDelegate.browserViewController.presentIntroViewController(false, animated: false) + } + } + + override func makeWebView() -> WKWebView { + // Inject our setup code after the page loads. + let source = getJS() + let userScript = WKUserScript( + source: source, + injectionTime: WKUserScriptInjectionTime.atDocumentEnd, + forMainFrameOnly: true + ) + + // Handle messages from the content server (via our user script). + let contentController = WKUserContentController() + contentController.addUserScript(userScript) + contentController.add(LeakAvoider(delegate: self), name: "accountsCommandHandler") + + let config = WKWebViewConfiguration() + config.userContentController = contentController + + let webView = WKWebView( + frame: CGRect(x: 0, y: 0, width: 1, height: 1), + configuration: config + ) + webView.allowsLinkPreview = false + webView.navigationDelegate = self + webView.accessibilityLabel = NSLocalizedString("Web content", comment: "Accessibility label for the main web content view") + + // Don't allow overscrolling. + webView.scrollView.bounces = false + return webView + } + + // Send a message to the content server. + func injectData(_ type: String, content: [String: Any]) { + let data = [ + "type": type, + "content": content, + ] as [String: Any] + let json = JSON(data).stringValue() ?? "" + let script = "window.postMessage(\(json), '\(self.url.absoluteString)');" + webView.evaluateJavaScript(script, completionHandler: nil) + } + + fileprivate func onCanLinkAccount(_ data: JSON) { + // // We need to confirm a relink - see shouldAllowRelink for more + // let ok = shouldAllowRelink(accountData.email); + let ok = true + injectData("message", content: ["status": "can_link_account", "data": ["ok": ok]]) + } + + // We're not signed in to a Firefox Account at this time, which we signal by returning an error. + fileprivate func onSessionStatus(_ data: JSON) { + injectData("message", content: ["status": "error"]) + } + + // We're not signed in to a Firefox Account at this time. We should never get a sign out message! + fileprivate func onSignOut(_ data: JSON) { + injectData("message", content: ["status": "error"]) + } + + // The user has signed in to a Firefox Account. We're done! + fileprivate func onLogin(_ data: JSON) { + injectData("message", content: ["status": "login"]) + + let app = UIApplication.shared + let helper = FxALoginHelper.sharedInstance + helper.delegate = self + helper.application(app, didReceiveAccountJSON: data) + + if profile.hasAccount() { + LeanPlumClient.shared.set(attributes: [LPAttributeKey.signedInSync: true]) + } + + LeanPlumClient.shared.track(event: .signsInFxa) + } + + @objc fileprivate func userDidVerify(_ notification: Notification) { + guard let account = profile.getAccount() else { + return + } + // We can't verify against the actionNeeded of the account, + // because of potential race conditions. + // However, we restrict visibility of this method, and make sure + // we only Notify via the FxALoginStateMachine. + let flags = FxALoginFlags(pushEnabled: account.pushRegistration != nil, + verified: true) + LeanPlumClient.shared.set(attributes: [LPAttributeKey.signedInSync: true]) + DispatchQueue.main.async { + self.delegate?.contentViewControllerDidSignIn(self, withFlags: flags) + } + } + + // The content server page is ready to be shown. + fileprivate func onLoaded() { + self.timer?.invalidate() + self.timer = nil + self.isLoaded = true + } + + // Handle a message coming from the content server. + func handleRemoteCommand(_ rawValue: String, data: JSON) { + if let command = RemoteCommand(rawValue: rawValue) { + if !isLoaded && command != .loaded { + // Work around https://github.com/mozilla/fxa-content-server/issues/2137 + onLoaded() + } + + switch command { + case .loaded: + onLoaded() + case .login: + onLogin(data) + case .canLinkAccount: + onCanLinkAccount(data) + case .sessionStatus: + onSessionStatus(data) + case .signOut: + onSignOut(data) + } + } + } + + // Dispatch webkit messages originating from our child webview. + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + // Make sure we're communicating with a trusted page. That is, ensure the origin of the + // message is the same as the origin of the URL we initially loaded in this web view. + // Note that this exploit wouldn't be possible if we were using WebChannels; see + // https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/WebChannel.jsm + let origin = message.frameInfo.securityOrigin + guard origin.`protocol` == url.scheme && origin.host == url.host && origin.port == (url.port ?? 0) else { + print("Ignoring message - \(origin) does not match expected origin: \(url.origin ?? "nil")") + return + } + + if message.name == "accountsCommandHandler" { + let body = JSON(message.body) + let detail = body["detail"] + handleRemoteCommand(detail["command"].stringValue, data: detail["data"]) + } + } + + // Configure the FxA signin url based on any passed options. + public func createFxAURLWith(_ fxaOptions: FxALaunchParams?, profile: Profile) -> URL { + let profileUrl = profile.accountConfiguration.signInURL + + guard let launchParams = fxaOptions else { + return profileUrl + } + + // Only append `signin`, `entrypoint` and `utm_*` parameters. Note that you can't + // override the service and context params. + var params = launchParams.query + params.removeValue(forKey: "service") + params.removeValue(forKey: "context") + let queryURL = params.filter { $0.key == "signin" || $0.key == "entrypoint" || $0.key.range(of: "utm_") != nil }.map({ + return "\($0.key)=\($0.value)" + }).joined(separator: "&") + + return URL(string: "\(profileUrl)&\(queryURL)") ?? profileUrl + } + + fileprivate func getJS() -> String { + let fileRoot = Bundle.main.path(forResource: "FxASignIn", ofType: "js") + return (try! NSString(contentsOfFile: fileRoot!, encoding: String.Encoding.utf8.rawValue)) as String + } + + override func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + // Ignore for now. + } + + override func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + // Ignore for now. + } +} + +extension FxAContentViewController: FxAPushLoginDelegate { + func accountLoginDidSucceed(withFlags flags: FxALoginFlags) { + DispatchQueue.main.async { + self.delegate?.contentViewControllerDidSignIn(self, withFlags: flags) + } + } + + func accountLoginDidFail() { + DispatchQueue.main.async { + self.delegate?.contentViewControllerDidCancel(self) + } + } +} + +/* +LeakAvoider prevents leaks with WKUserContentController +http://stackoverflow.com/questions/26383031/wkwebview-causes-my-view-controller-to-leak +*/ + +class LeakAvoider: NSObject, WKScriptMessageHandler { + weak var delegate: WKScriptMessageHandler? + + init(delegate: WKScriptMessageHandler) { + self.delegate = delegate + super.init() + } + + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + self.delegate?.userContentController(userContentController, didReceive: message) + } +} diff --git a/mobile/ios/Client/Frontend/Settings/HomePageSettingsViewController.swift b/mobile/ios/Client/Frontend/Settings/HomePageSettingsViewController.swift new file mode 100644 index 0000000000..02ff37fdfd --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/HomePageSettingsViewController.swift @@ -0,0 +1,98 @@ +/* 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/. */ + +import UIKit +import Shared +import SnapKit + +private let log = Logger.browserLogger + +class HomePageSettingsViewController: SettingsTableViewController { + + override func viewDidLoad() { + super.viewDidLoad() + title = Strings.SettingsHomePageTitle + } + + override func generateSettings() -> [SettingSection] { + let prefs = profile.prefs + let helper = HomePageHelper(prefs: prefs) + func setHomePage(_ url: URL?) -> ((UINavigationController?) -> Void) { + weak var tableView: UITableView? = self.tableView + return { nav in + helper.currentURL = url + tableView?.reloadData() + } + } + + func isHomePage(_ url: URL?) -> (() -> Bool) { + return { + return url?.isWebPage() ?? false + } + } + + func URLFromString(_ string: String?) -> URL? { + guard let string = string else { + return nil + } + return URL(string: string) + } + + let currentTabURL = self.tabManager.selectedTab?.url?.displayURL + let clipboardURL = URLFromString(UIPasteboard.general.string) + + var basicSettings: [Setting] = [ + WebPageSetting(prefs: prefs, + prefKey: HomePageConstants.HomePageURLPrefKey, + placeholder: helper.defaultURLString ?? Strings.SettingsHomePagePlaceholder, + accessibilityIdentifier: "HomePageSetting"), + ButtonSetting(title: NSAttributedString(string: Strings.SettingsHomePageUseCurrentPage), + accessibilityIdentifier: "UseCurrentTab", + isEnabled: isHomePage(currentTabURL), + onClick: setHomePage(currentTabURL)), + ButtonSetting(title: NSAttributedString(string: Strings.SettingsHomePageUseCopiedLink), + accessibilityIdentifier: "UseCopiedLink", + isEnabled: isHomePage(clipboardURL), + onClick: setHomePage(clipboardURL)), + ] + + basicSettings += [ + ButtonSetting(title: NSAttributedString(string: Strings.SettingsHomePageClear), + destructive: true, + accessibilityIdentifier: "ClearHomePage", + onClick: setHomePage(nil)), + ] + + return [SettingSection(title: NSAttributedString(string: Strings.SettingsHomePageURLSectionTitle), children: basicSettings)] + } +} + +class WebPageSetting: StringSetting { + init(prefs: Prefs, prefKey: String, defaultValue: String? = nil, placeholder: String, accessibilityIdentifier: String, settingDidChange: ((String?) -> Void)? = nil) { + super.init(prefs: prefs, + prefKey: prefKey, + defaultValue: defaultValue, + placeholder: placeholder, + accessibilityIdentifier: accessibilityIdentifier, + settingIsValid: WebPageSetting.isURLOrEmpty, + settingDidChange: settingDidChange) + textField.keyboardType = .URL + textField.autocapitalizationType = .none + textField.autocorrectionType = .no + } + + override func prepareValidValue(userInput value: String?) -> String? { + guard let value = value else { + return nil + } + return URIFixup.getURL(value)?.absoluteString + } + + static func isURLOrEmpty(_ string: String?) -> Bool { + guard let string = string, !string.isEmpty else { + return true + } + return URL(string: string)?.isWebPage() ?? false + } +} diff --git a/mobile/ios/Client/Frontend/Settings/LoginDetailViewController.swift b/mobile/ios/Client/Frontend/Settings/LoginDetailViewController.swift new file mode 100644 index 0000000000..92badff5f2 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/LoginDetailViewController.swift @@ -0,0 +1,376 @@ +/* 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/. */ + +import Foundation +import Storage +import Shared +import SwiftKeychainWrapper + +enum InfoItem: Int { + case websiteItem = 0 + case usernameItem = 1 + case passwordItem = 2 + case lastModifiedSeparator = 3 + case deleteItem = 4 + + var indexPath: IndexPath { + return IndexPath(row: rawValue, section: 0) + } +} + +private struct LoginDetailUX { + static let InfoRowHeight: CGFloat = 58 + static let DeleteRowHeight: CGFloat = 44 + static let SeparatorHeight: CGFloat = 44 +} + +class LoginDetailViewController: SensitiveViewController { + + fileprivate let profile: Profile + + fileprivate let tableView = UITableView() + + fileprivate var login: Login { + didSet { + tableView.reloadData() + } + } + + fileprivate var editingInfo: Bool = false { + didSet { + if editingInfo != oldValue { + tableView.reloadData() + } + } + } + + fileprivate let LoginCellIdentifier = "LoginCell" + fileprivate let DefaultCellIdentifier = "DefaultCellIdentifier" + fileprivate let SeparatorIdentifier = "SeparatorIdentifier" + + // Used to temporarily store a reference to the cell the user is showing the menu controller for + fileprivate var menuControllerCell: LoginTableViewCell? + + fileprivate weak var websiteField: UITextField? + fileprivate weak var usernameField: UITextField? + fileprivate weak var passwordField: UITextField? + + fileprivate var deleteAlert: UIAlertController? + + weak var settingsDelegate: SettingsDelegate? + + init(profile: Profile, login: Login) { + self.login = login + self.profile = profile + super.init(nibName: nil, bundle: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(LoginDetailViewController.dismissAlertController), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(LoginDetailViewController.SELedit)) + + tableView.register(LoginTableViewCell.self, forCellReuseIdentifier: LoginCellIdentifier) + tableView.register(UITableViewCell.self, forCellReuseIdentifier: DefaultCellIdentifier) + tableView.register(SettingsTableSectionHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: SeparatorIdentifier) + + view.addSubview(tableView) + tableView.snp.makeConstraints { make in + make.edges.equalTo(self.view) + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + tableView.separatorColor = UIConstants.TableViewSeparatorColor + tableView.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + tableView.accessibilityIdentifier = "Login Detail List" + tableView.delegate = self + tableView.dataSource = self + + // Add empty footer view to prevent seperators from being drawn past the last item. + tableView.tableFooterView = UIView() + + // Add a line on top of the table view so when the user pulls down it looks 'correct'. + let topLine = UIView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: tableView.frame.width, height: 0.5))) + topLine.backgroundColor = UIConstants.TableViewSeparatorColor + tableView.tableHeaderView = topLine + + // Normally UITableViewControllers handle responding to content inset changes from keyboard events when editing + // but since we don't use the tableView's editing flag for editing we handle this ourselves. + KeyboardHelper.defaultHelper.addDelegate(self) + } + + deinit { + let notificationCenter = NotificationCenter.default + notificationCenter.removeObserver(self, name: NotificationProfileDidFinishSyncing, object: nil) + notificationCenter.removeObserver(self, name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + // The following hacks are to prevent the default cell seperators from displaying. We want to + // hide the default seperator for the website/last modified cells since the last modified cell + // draws its own separators. The last item in the list draws its seperator full width. + + // Prevent seperators from showing by pushing them off screen by the width of the cell + let itemsToHideSeperators: [InfoItem] = [.passwordItem, .lastModifiedSeparator] + itemsToHideSeperators.forEach { item in + let cell = tableView.cellForRow(at: IndexPath(row: item.rawValue, section: 0)) + cell?.separatorInset = UIEdgeInsets(top: 0, left: cell?.bounds.width ?? 0, bottom: 0, right: 0) + } + + // Rows to display full width seperator + let itemsToShowFullWidthSeperator: [InfoItem] = [.deleteItem] + itemsToShowFullWidthSeperator.forEach { item in + let cell = tableView.cellForRow(at: IndexPath(row: item.rawValue, section: 0)) + cell?.separatorInset = UIEdgeInsets.zero + cell?.layoutMargins = UIEdgeInsets.zero + cell?.preservesSuperviewLayoutMargins = false + } + } +} + +// MARK: - UITableViewDataSource +extension LoginDetailViewController: UITableViewDataSource { + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + switch InfoItem(rawValue: indexPath.row)! { + case .usernameItem: + let loginCell = dequeueLoginCellForIndexPath(indexPath) + loginCell.style = .noIconAndBothLabels + loginCell.highlightedLabelTitle = NSLocalizedString("username", tableName: "LoginManager", comment: "Label displayed above the username row in Login Detail View.") + loginCell.descriptionLabel.text = login.username + loginCell.descriptionLabel.keyboardType = .emailAddress + loginCell.descriptionLabel.returnKeyType = .next + loginCell.editingDescription = editingInfo + usernameField = loginCell.descriptionLabel + usernameField?.accessibilityIdentifier = "usernameField" + return loginCell + + case .passwordItem: + let loginCell = dequeueLoginCellForIndexPath(indexPath) + loginCell.style = .noIconAndBothLabels + loginCell.highlightedLabelTitle = NSLocalizedString("password", tableName: "LoginManager", comment: "Label displayed above the password row in Login Detail View.") + loginCell.descriptionLabel.text = login.password + loginCell.descriptionLabel.returnKeyType = .default + loginCell.displayDescriptionAsPassword = true + loginCell.editingDescription = editingInfo + passwordField = loginCell.descriptionLabel + passwordField?.accessibilityIdentifier = "passwordField" + return loginCell + + case .websiteItem: + let loginCell = dequeueLoginCellForIndexPath(indexPath) + loginCell.style = .noIconAndBothLabels + loginCell.highlightedLabelTitle = NSLocalizedString("website", tableName: "LoginManager", comment: "Label displayed above the website row in Login Detail View.") + loginCell.descriptionLabel.text = login.hostname + websiteField = loginCell.descriptionLabel + websiteField?.accessibilityIdentifier = "websiteField" + return loginCell + + case .lastModifiedSeparator: + let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: SeparatorIdentifier) as! SettingsTableSectionHeaderFooterView + footer.titleAlignment = .top + let lastModified = NSLocalizedString("Last modified %@", tableName: "LoginManager", comment: "Footer label describing when the current login was last modified with the timestamp as the parameter.") + let formattedLabel = String(format: lastModified, Date.fromMicrosecondTimestamp(login.timePasswordChanged).toRelativeTimeString()) + footer.titleLabel.text = formattedLabel + let cell = wrapFooter(footer, withCellFromTableView: tableView, atIndexPath: indexPath) + return cell + + case .deleteItem: + let deleteCell = tableView.dequeueReusableCell(withIdentifier: DefaultCellIdentifier, for: indexPath) + deleteCell.textLabel?.text = NSLocalizedString("Delete", tableName: "LoginManager", comment: "Label for the button used to delete the current login.") + deleteCell.textLabel?.textAlignment = NSTextAlignment.center + deleteCell.textLabel?.textColor = UIConstants.DestructiveRed + deleteCell.accessibilityTraits = UIAccessibilityTraitButton + return deleteCell + } + } + + fileprivate func dequeueLoginCellForIndexPath(_ indexPath: IndexPath) -> LoginTableViewCell { + let loginCell = tableView.dequeueReusableCell(withIdentifier: LoginCellIdentifier, for: indexPath) as! LoginTableViewCell + loginCell.selectionStyle = .none + loginCell.delegate = self + return loginCell + } + + fileprivate func wrapFooter(_ footer: UITableViewHeaderFooterView, withCellFromTableView tableView: UITableView, atIndexPath indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: DefaultCellIdentifier, for: indexPath) + cell.selectionStyle = .none + cell.addSubview(footer) + footer.snp.makeConstraints { make in + make.edges.equalTo(cell) + } + return cell + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 5 + } +} + +// MARK: - UITableViewDelegate +extension LoginDetailViewController: UITableViewDelegate { + private func showMenuOnSingleTap(forIndexPath indexPath: IndexPath) { + guard let item = InfoItem(rawValue: indexPath.row) else { return } + if ![InfoItem.passwordItem, InfoItem.websiteItem, InfoItem.usernameItem].contains(item) { + return + } + + guard let cell = tableView.cellForRow(at: indexPath) as? LoginTableViewCell else { return } + + cell.becomeFirstResponder() + + let menu = UIMenuController.shared + menu.setTargetRect(cell.frame, in: self.tableView) + menu.setMenuVisible(true, animated: true) + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if indexPath == InfoItem.deleteItem.indexPath { + deleteLogin() + } else if !editingInfo { + showMenuOnSingleTap(forIndexPath: indexPath) + } + tableView.deselectRow(at: indexPath, animated: true) + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + switch InfoItem(rawValue: indexPath.row)! { + case .usernameItem, .passwordItem, .websiteItem: + return LoginDetailUX.InfoRowHeight + case .lastModifiedSeparator: + return LoginDetailUX.SeparatorHeight + case .deleteItem: + return LoginDetailUX.DeleteRowHeight + } + } +} + +// MARK: - KeyboardHelperDelegate +extension LoginDetailViewController: KeyboardHelperDelegate { + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillShowWithState state: KeyboardState) { + let coveredHeight = state.intersectionHeightForView(tableView) + tableView.contentInset.bottom = coveredHeight + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardDidShowWithState state: KeyboardState) { + } + + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillHideWithState state: KeyboardState) { + tableView.contentInset.bottom = 0 + } +} + +// MARK: - Selectors +extension LoginDetailViewController { + + @objc func dismissAlertController() { + self.deleteAlert?.dismiss(animated: false, completion: nil) + } + + func deleteLogin() { + profile.logins.hasSyncedLogins().uponQueue(DispatchQueue.main) { yes in + self.deleteAlert = UIAlertController.deleteLoginAlertWithDeleteCallback({ [unowned self] _ in + self.profile.logins.removeLoginByGUID(self.login.guid).uponQueue(DispatchQueue.main) { _ in + _ = self.navigationController?.popViewController(animated: true) + } + }, hasSyncedLogins: yes.successValue ?? true) + + self.present(self.deleteAlert!, animated: true, completion: nil) + } + } + + func SELonProfileDidFinishSyncing() { + // Reload details after syncing. + profile.logins.getLoginDataForGUID(login.guid).uponQueue(DispatchQueue.main) { result in + if let syncedLogin = result.successValue { + self.login = syncedLogin + } + } + } + + func SELedit() { + editingInfo = true + + let cell = tableView.cellForRow(at: InfoItem.usernameItem.indexPath) as! LoginTableViewCell + cell.descriptionLabel.becomeFirstResponder() + + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(LoginDetailViewController.SELdoneEditing)) + } + + func SELdoneEditing() { + editingInfo = false + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(LoginDetailViewController.SELedit)) + + defer { + // Required to get UI to reload with changed state + tableView.reloadData() + } + + // We only care to update if we changed something + guard let username = usernameField?.text, + let password = passwordField?.text, username != login.username || password != login.password else { + return + } + + // Keep a copy of the old data in case we fail and need to revert back + let oldPassword = login.password + let oldUsername = login.username + login.update(password: password, username: username) + + if login.isValid.isSuccess { + profile.logins.updateLoginByGUID(login.guid, new: login, significant: true) + } else if let oldUsername = oldUsername { + login.update(password: oldPassword, username: oldUsername) + } + } +} + +// MARK: - Cell Delegate +extension LoginDetailViewController: LoginTableViewCellDelegate { + + fileprivate func cellForItem(_ item: InfoItem) -> LoginTableViewCell? { + return tableView.cellForRow(at: item.indexPath) as? LoginTableViewCell + } + + func didSelectOpenAndFillForCell(_ cell: LoginTableViewCell) { + guard let url = (self.login.formSubmitURL?.asURL ?? self.login.hostname.asURL) else { + return + } + + navigationController?.dismiss(animated: true, completion: { + self.settingsDelegate?.settingsOpenURLInNewTab(url) + }) + } + + func shouldReturnAfterEditingDescription(_ cell: LoginTableViewCell) -> Bool { + let usernameCell = cellForItem(.usernameItem) + let passwordCell = cellForItem(.passwordItem) + + if cell == usernameCell { + passwordCell?.descriptionLabel.becomeFirstResponder() + } + + return false + } + + func infoItemForCell(_ cell: LoginTableViewCell) -> InfoItem? { + if let index = tableView.indexPath(for: cell), + let item = InfoItem(rawValue: index.row) { + return item + } + return nil + } +} diff --git a/mobile/ios/Client/Frontend/Settings/NewTabChoiceViewController.swift b/mobile/ios/Client/Frontend/Settings/NewTabChoiceViewController.swift new file mode 100644 index 0000000000..bbe671a3fc --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/NewTabChoiceViewController.swift @@ -0,0 +1,84 @@ +/* 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/. */ + +import Foundation +import Shared + +/// Screen presented to the user when selecting the page that is displayed when the user goes to a new tab. +class NewTabChoiceViewController: UITableViewController { + + let newTabOptions: [NewTabPage] = [.blankPage, .topSites, .bookmarks, .history, .homePage] + + let prefs: Prefs + var currentChoice: NewTabPage! + var hasHomePage: Bool! + + fileprivate let BasicCheckmarkCell = "BasicCheckmarkCell" + fileprivate var authenticationInfo: AuthenticationKeychainInfo? + + init(prefs: Prefs) { + self.prefs = prefs + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + title = Strings.SettingsNewTabTitle + + tableView.accessibilityIdentifier = "NewTabPage.Setting.Options" + + tableView.register(UITableViewCell.self, forCellReuseIdentifier: BasicCheckmarkCell) + tableView.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + + let headerFooterFrame = CGRect(origin: CGPoint.zero, size: CGSize(width: self.view.frame.width, height: UIConstants.TableViewHeaderFooterHeight)) + let headerView = SettingsTableSectionHeaderFooterView(frame: headerFooterFrame) + headerView.showTopBorder = false + headerView.showBottomBorder = true + + let footerView = SettingsTableSectionHeaderFooterView(frame: headerFooterFrame) + footerView.showTopBorder = true + footerView.showBottomBorder = false + + tableView.tableHeaderView = headerView + tableView.tableFooterView = footerView + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.currentChoice = NewTabAccessors.getNewTabPage(prefs) + self.hasHomePage = HomePageAccessors.getHomePage(prefs) != nil + tableView.reloadData() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + self.prefs.setString(currentChoice.rawValue, forKey: NewTabAccessors.PrefKey) + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: BasicCheckmarkCell, for: indexPath) + + let option = newTabOptions[indexPath.row] + let enabled = (option != .homePage) || hasHomePage + + cell.accessoryType = (currentChoice == option) ? .checkmark : .none + cell.textLabel?.attributedText = NSAttributedString.tableRowTitle(option.settingTitle, enabled: enabled) + cell.isUserInteractionEnabled = enabled + + return cell + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return newTabOptions.count + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + currentChoice = newTabOptions[indexPath.row] + tableView.reloadData() + } +} diff --git a/mobile/ios/Client/Frontend/Settings/NewTabContentSettingsViewController.swift b/mobile/ios/Client/Frontend/Settings/NewTabContentSettingsViewController.swift new file mode 100644 index 0000000000..1e97d23389 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/NewTabContentSettingsViewController.swift @@ -0,0 +1,55 @@ +/* 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/. */ + +import Foundation +import Shared + +class CurrentTabSetting: Setting { + let profile: Profile + + override var accessoryType: UITableViewCellAccessoryType { return .disclosureIndicator } + + override var style: UITableViewCellStyle { return .value1 } + + override var accessibilityIdentifier: String? { return "NewTabOption" } + + init(profile: Profile) { + self.profile = profile + super.init(title: NSAttributedString(string: NewTabAccessors.getNewTabPage(profile.prefs).settingTitle, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor])) + } + + override func onClick(_ navigationController: UINavigationController?) { + let viewController = NewTabChoiceViewController(prefs: profile.prefs) + navigationController?.pushViewController(viewController, animated: true) + } +} + +class NewTabContentSettingsViewController: SettingsTableViewController { + + init() { + super.init(style: .grouped) + + self.title = Strings.SettingsNewTabTitle + hasSectionSeparatorLine = false + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func generateSettings() -> [SettingSection] { + let tabSetting = CurrentTabSetting(profile: profile) + let firstSection = SettingSection(title: NSAttributedString(string: Strings.SettingsNewTabSectionName), footerTitle: nil, children: [tabSetting]) + + let isPocketEnabledDefault = Pocket.IslocaleSupported(Locale.current.identifier) + let pocketSetting = BoolSetting(prefs: profile.prefs, prefKey: PrefsKeys.ASPocketStoriesVisible, defaultValue: isPocketEnabledDefault, attributedTitleText: NSAttributedString(string: Strings.SettingsNewTabPocket)) + let bookmarks = BoolSetting(prefs: profile.prefs, prefKey: PrefsKeys.ASBookmarkHighlightsVisible, defaultValue: true, attributedTitleText: NSAttributedString(string: Strings.SettingsNewTabHighlightsBookmarks)) + let history = BoolSetting(prefs: profile.prefs, prefKey: PrefsKeys.ASRecentHighlightsVisible, defaultValue: true, attributedTitleText: NSAttributedString(string: Strings.SettingsNewTabHiglightsHistory)) + let options = AppConstants.MOZ_POCKET_STORIES ? [pocketSetting, bookmarks, history] : [bookmarks, history] + let secondSection = SettingSection(title: NSAttributedString(string: Strings.SettingsNewTabASTitle), footerTitle: nil, children: options) + + return [firstSection, secondSection] + } +} + diff --git a/mobile/ios/Client/Frontend/Settings/SearchEnginePicker.swift b/mobile/ios/Client/Frontend/Settings/SearchEnginePicker.swift new file mode 100644 index 0000000000..602b3475ee --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/SearchEnginePicker.swift @@ -0,0 +1,47 @@ +/* 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/. */ + +import UIKit + +class SearchEnginePicker: UITableViewController { + weak var delegate: SearchEnginePickerDelegate? + var engines: [OpenSearchEngine]! + var selectedSearchEngineName: String? + + override func viewDidLoad() { + super.viewDidLoad() + + navigationItem.title = NSLocalizedString("Default Search Engine", comment: "Title for default search engine picker.") + navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("Cancel", comment: "Label for Cancel button"), style: .plain, target: self, action: #selector(SearchEnginePicker.cancel)) + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return engines.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let engine = engines[indexPath.item] + let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) + cell.textLabel?.text = engine.shortName + cell.imageView?.image = engine.image.createScaled(CGSize(width: OpenSearchEngine.PreferredIconSize, height: OpenSearchEngine.PreferredIconSize)) + if engine.shortName == selectedSearchEngineName { + cell.accessoryType = UITableViewCellAccessoryType.checkmark + } + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let engine = engines[indexPath.item] + delegate?.searchEnginePicker(self, didSelectSearchEngine: engine) + tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark + } + + override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { + tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none + } + + func cancel() { + delegate?.searchEnginePicker(self, didSelectSearchEngine: nil) + } +} diff --git a/mobile/ios/Client/Frontend/Settings/SearchSettingsTableViewController.swift b/mobile/ios/Client/Frontend/Settings/SearchSettingsTableViewController.swift new file mode 100644 index 0000000000..26356e1d00 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/SearchSettingsTableViewController.swift @@ -0,0 +1,331 @@ +/* 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/. */ + +import UIKit +import SDWebImage +import Shared + +protocol SearchEnginePickerDelegate: class { + func searchEnginePicker(_ searchEnginePicker: SearchEnginePicker?, didSelectSearchEngine engine: OpenSearchEngine?) +} + +class SearchSettingsTableViewController: UITableViewController { + fileprivate let SectionDefault = 0 + fileprivate let ItemDefaultEngine = 0 + fileprivate let ItemDefaultSuggestions = 1 + fileprivate let ItemAddCustomSearch = 2 + fileprivate let NumberOfItemsInSectionDefault = 2 + fileprivate let SectionOrder = 1 + fileprivate let NumberOfSections = 2 + fileprivate let IconSize = CGSize(width: OpenSearchEngine.PreferredIconSize, height: OpenSearchEngine.PreferredIconSize) + fileprivate let SectionHeaderIdentifier = "SectionHeaderIdentifier" + + fileprivate var showDeletion = false + + var profile: Profile? + var tabManager: TabManager? + + fileprivate var isEditable: Bool { + // If the default engine is a custom one, make sure we have more than one since we can't edit the default. + // Otherwise, enable editing if we have at least one custom engine. + let customEngineCount = model.orderedEngines.filter({$0.isCustomEngine}).count + return model.defaultEngine.isCustomEngine ? customEngineCount > 1 : customEngineCount > 0 + } + + var model: SearchEngines! + + override func viewDidLoad() { + super.viewDidLoad() + + navigationItem.title = NSLocalizedString("Search", comment: "Navigation title for search settings.") + + // To allow re-ordering the list of search engines at all times. + tableView.isEditing = true + // So that we push the default search engine controller on selection. + tableView.allowsSelectionDuringEditing = true + + tableView.register(SettingsTableSectionHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: SectionHeaderIdentifier) + + // Insert Done button if being presented outside of the Settings Nav stack + if !(self.navigationController is SettingsNavigationController) { + self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: Strings.SettingsSearchDoneButton, style: .done, target: self, action: #selector(self.dismissAnimated)) + } + + let footer = SettingsTableSectionHeaderFooterView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 44)) + footer.showBottomBorder = false + tableView.tableFooterView = footer + + tableView.separatorColor = UIConstants.TableViewSeparatorColor + tableView.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + + navigationItem.rightBarButtonItem = UIBarButtonItem(title: Strings.SettingsSearchEditButton, style: .plain, target: self, + action: #selector(SearchSettingsTableViewController.beginEditing)) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + // Only show the Edit button if custom search engines are in the list. + // Otherwise, there is nothing to delete. + navigationItem.rightBarButtonItem?.isEnabled = isEditable + tableView.reloadData() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + setEditing(false, animated: false) + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + var cell: UITableViewCell! + var engine: OpenSearchEngine! + + if indexPath.section == SectionDefault { + switch indexPath.item { + case ItemDefaultEngine: + engine = model.defaultEngine + cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) + cell.editingAccessoryType = UITableViewCellAccessoryType.disclosureIndicator + cell.accessibilityLabel = NSLocalizedString("Default Search Engine", comment: "Accessibility label for default search engine setting.") + cell.accessibilityValue = engine.shortName + cell.textLabel?.text = engine.shortName + cell.imageView?.image = engine.image.createScaled(IconSize) + cell.imageView?.layer.cornerRadius = 4 + cell.imageView?.layer.masksToBounds = true + case ItemDefaultSuggestions: + cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) + cell.textLabel?.text = NSLocalizedString("Show Search Suggestions", comment: "Label for show search suggestions setting.") + let toggle = UISwitch() + toggle.onTintColor = UIConstants.ControlTintColor + toggle.addTarget(self, action: #selector(SearchSettingsTableViewController.didToggleSearchSuggestions(_:)), for: UIControlEvents.valueChanged) + toggle.isOn = model.shouldShowSearchSuggestions + cell.editingAccessoryView = toggle + cell.selectionStyle = .none + default: + // Should not happen. + break + } + } else { + // The default engine is not a quick search engine. + let index = indexPath.item + 1 + if index < model.orderedEngines.count { + engine = model.orderedEngines[index] + + cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) + cell.showsReorderControl = true + + let toggle = UISwitch() + toggle.onTintColor = UIConstants.ControlTintColor + // This is an easy way to get from the toggle control to the corresponding index. + toggle.tag = index + toggle.addTarget(self, action: #selector(SearchSettingsTableViewController.didToggleEngine(_:)), for: UIControlEvents.valueChanged) + toggle.isOn = model.isEngineEnabled(engine) + + cell.editingAccessoryView = toggle + cell.textLabel?.text = engine.shortName + cell.textLabel?.adjustsFontSizeToFitWidth = true + cell.textLabel?.minimumScaleFactor = 0.5 + cell.imageView?.image = engine.image.createScaled(IconSize) + cell.imageView?.layer.cornerRadius = 4 + cell.imageView?.layer.masksToBounds = true + cell.selectionStyle = .none + } else { + cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) + cell.editingAccessoryType = UITableViewCellAccessoryType.disclosureIndicator + cell.accessibilityLabel = Strings.SettingsAddCustomEngineTitle + cell.accessibilityIdentifier = "customEngineViewButton" + cell.textLabel?.text = Strings.SettingsAddCustomEngine + } + } + + // So that the seperator line goes all the way to the left edge. + cell.separatorInset = UIEdgeInsets.zero + + return cell + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return NumberOfSections + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == SectionDefault { + return NumberOfItemsInSectionDefault + } else { + // The first engine -- the default engine -- is not shown in the quick search engine list. + // But the option to add Custom Engine is. + return AppConstants.MOZ_CUSTOM_SEARCH_ENGINE ? model.orderedEngines.count : model.orderedEngines.count - 1 + } + } + + override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { + if indexPath.section == SectionDefault && indexPath.item == ItemDefaultEngine { + let searchEnginePicker = SearchEnginePicker() + // Order alphabetically, so that picker is always consistently ordered. + // Every engine is a valid choice for the default engine, even the current default engine. + searchEnginePicker.engines = model.orderedEngines.sorted { e, f in e.shortName < f.shortName } + searchEnginePicker.delegate = self + searchEnginePicker.selectedSearchEngineName = model.defaultEngine.shortName + navigationController?.pushViewController(searchEnginePicker, animated: true) + } else if indexPath.item + 1 == model.orderedEngines.count { + let customSearchEngineForm = CustomSearchViewController() + customSearchEngineForm.profile = self.profile + customSearchEngineForm.successCallback = { + guard let window = self.view.window else { return } + SimpleToast().showAlertWithText(Strings.ThirdPartySearchEngineAdded, bottomContainer: window) + } + navigationController?.pushViewController(customSearchEngineForm, animated: true) + } + return nil + } + + // Don't show delete button on the left. + override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle { + if indexPath.section == SectionDefault || indexPath.item + 1 == model.orderedEngines.count { + return UITableViewCellEditingStyle.none + } + + let index = indexPath.item + 1 + let engine = model.orderedEngines[index] + return (self.showDeletion && engine.isCustomEngine) ? .delete : .none + } + + // Don't reserve space for the delete button on the left. + override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool { + return false + } + + // Hide a thin vertical line that iOS renders between the accessoryView and the reordering control. + override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + if cell.isEditing { + for v in cell.subviews where v.frame.width == 1.0 { + v.backgroundColor = UIColor.clear + } + } + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 44 + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: SectionHeaderIdentifier) as! SettingsTableSectionHeaderFooterView + var sectionTitle: String + if section == SectionDefault { + sectionTitle = NSLocalizedString("Default Search Engine", comment: "Title for default search engine settings section.") + } else { + sectionTitle = NSLocalizedString("Quick-Search Engines", comment: "Title for quick-search engines settings section.") + } + headerView.titleLabel.text = sectionTitle + + return headerView + } + + override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { + if indexPath.section == SectionDefault || indexPath.item + 1 == model.orderedEngines.count { + return false + } else { + return true + } + } + + override func tableView(_ tableView: UITableView, moveRowAt indexPath: IndexPath, to newIndexPath: IndexPath) { + // The first engine (default engine) is not shown in the list, so the indices are off-by-1. + let index = indexPath.item + 1 + let newIndex = newIndexPath.item + 1 + let engine = model.orderedEngines.remove(at: index) + model.orderedEngines.insert(engine, at: newIndex) + tableView.reloadData() + } + + // Snap to first or last row of the list of engines. + override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath { + // You can't drag or drop on the default engine. + if sourceIndexPath.section == SectionDefault || proposedDestinationIndexPath.section == SectionDefault { + return sourceIndexPath + } + + //Can't drag/drop over "Add Custom Engine button" + if sourceIndexPath.item + 1 == model.orderedEngines.count || proposedDestinationIndexPath.item + 1 == model.orderedEngines.count { + return sourceIndexPath + } + + if sourceIndexPath.section != proposedDestinationIndexPath.section { + var row = 0 + if sourceIndexPath.section < proposedDestinationIndexPath.section { + row = tableView.numberOfRows(inSection: sourceIndexPath.section) - 1 + } + return IndexPath(row: row, section: sourceIndexPath.section) + } + return proposedDestinationIndexPath + } + + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + let index = indexPath.item + 1 + let engine = model.orderedEngines[index] + model.deleteCustomEngine(engine) + tableView.deleteRows(at: [indexPath], with: .right) + + // End editing if we are no longer edit since we've deleted all editable cells. + if !isEditable { + finishEditing() + } + } + } + + override func setEditing(_ editing: Bool, animated: Bool) { + showDeletion = editing + UIView.performWithoutAnimation { + self.navigationItem.rightBarButtonItem?.title = editing ? Strings.SettingsSearchDoneButton : Strings.SettingsSearchEditButton + } + navigationItem.rightBarButtonItem?.isEnabled = isEditable + navigationItem.rightBarButtonItem?.action = editing ? + #selector(SearchSettingsTableViewController.finishEditing) : #selector(SearchSettingsTableViewController.beginEditing) + tableView.reloadData() + } +} + +// MARK: - Selectors +extension SearchSettingsTableViewController { + func didToggleEngine(_ toggle: UISwitch) { + let engine = model.orderedEngines[toggle.tag] // The tag is 1-based. + if toggle.isOn { + model.enableEngine(engine) + } else { + model.disableEngine(engine) + } + } + + func didToggleSearchSuggestions(_ toggle: UISwitch) { + // Setting the value in settings dismisses any opt-in. + model.shouldShowSearchSuggestions = toggle.isOn + } + + func cancel() { + _ = navigationController?.popViewController(animated: true) + } + + func dismissAnimated() { + self.dismiss(animated: true, completion: nil) + } + + func beginEditing() { + setEditing(true, animated: false) + } + + func finishEditing() { + setEditing(false, animated: false) + } +} + +extension SearchSettingsTableViewController: SearchEnginePickerDelegate { + func searchEnginePicker(_ searchEnginePicker: SearchEnginePicker?, didSelectSearchEngine searchEngine: OpenSearchEngine?) { + if let engine = searchEngine { + model.defaultEngine = engine + self.tableView.reloadData() + UnifiedTelemetry.recordEvent(category: .action, method: .change, object: .setting, value: "defaultSearchEngine", extras: ["to": engine.engineID ?? "custom"]) + } + _ = navigationController?.popViewController(animated: true) + } +} diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution.png new file mode 100644 index 0000000000..db432a6afd Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution@2x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution@2x.png new file mode 100644 index 0000000000..12c8b7d7b5 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution@2x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution@3x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution@3x.png new file mode 100644 index 0000000000..3ad7311520 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/AmberCaution@3x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/Contents.json b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/Contents.json new file mode 100644 index 0000000000..113bee3719 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/AmberCaution.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "AmberCaution.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "AmberCaution@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "AmberCaution@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/Contents.json b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/Contents.json b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/Contents.json new file mode 100644 index 0000000000..2f661f8eee --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "FxA-Default.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "FxA-Default@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "FxA-Default@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default.png new file mode 100644 index 0000000000..39b92bca05 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default@2x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default@2x.png new file mode 100644 index 0000000000..afde6016ab Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default@2x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default@3x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default@3x.png new file mode 100644 index 0000000000..6e403c6b21 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Default.imageset/FxA-Default@3x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/Contents.json b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/Contents.json new file mode 100644 index 0000000000..5581f58e3d --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "FxA-Sync-Blue.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "FxA-Sync-Blue@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "FxA-Sync-Blue@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue.png new file mode 100644 index 0000000000..f467f4e311 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue@2x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue@2x.png new file mode 100644 index 0000000000..cb37121e15 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue@2x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue@3x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue@3x.png new file mode 100644 index 0000000000..9340efa913 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync-Blue.imageset/FxA-Sync-Blue@3x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/Contents.json b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/Contents.json new file mode 100644 index 0000000000..471da4f80c --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "FxA-Sync.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "FxA-Sync@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "FxA-Sync@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync.png new file mode 100644 index 0000000000..bc6494247e Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync@2x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync@2x.png new file mode 100644 index 0000000000..5df878d331 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync@2x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync@3x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync@3x.png new file mode 100644 index 0000000000..2b57e082f2 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/FxA-Sync.imageset/FxA-Sync@3x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/Contents.json b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/Contents.json new file mode 100644 index 0000000000..808d9ef9ca --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "RedCaution.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "RedCaution@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "RedCaution@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution.png new file mode 100644 index 0000000000..212b345f0d Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution@2x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution@2x.png new file mode 100644 index 0000000000..54d324f2a6 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution@2x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution@3x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution@3x.png new file mode 100644 index 0000000000..e8a1056c52 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/RedCaution.imageset/RedCaution@3x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/Contents.json b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/Contents.json new file mode 100644 index 0000000000..7d5c7a1a3f --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "placeholder-avatar.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "placeholder-avatar@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "placeholder-avatar@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar.png new file mode 100644 index 0000000000..67b66e1eb1 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar@2x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar@2x.png new file mode 100644 index 0000000000..b57a44f6c8 Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar@2x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar@3x.png b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar@3x.png new file mode 100644 index 0000000000..ce2ea04dab Binary files /dev/null and b/mobile/ios/Client/Frontend/Settings/Settings.xcassets/placeholder-avatar.imageset/placeholder-avatar@3x.png differ diff --git a/mobile/ios/Client/Frontend/Settings/SettingsContentViewController.swift b/mobile/ios/Client/Frontend/Settings/SettingsContentViewController.swift new file mode 100644 index 0000000000..db2b15d2f6 --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/SettingsContentViewController.swift @@ -0,0 +1,182 @@ +/* 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/. */ + +import Foundation +import Shared +import SnapKit +import UIKit +import WebKit + +let DefaultTimeoutTimeInterval = 10.0 // Seconds. We'll want some telemetry on load times in the wild. +private var TODOPageLoadErrorString = NSLocalizedString("Could not load page.", comment: "Error message that is shown in settings when there was a problem loading") + +/** + * A controller that manages a single web view and provides a way for + * the user to navigate back to Settings. + */ +class SettingsContentViewController: UIViewController, WKNavigationDelegate { + let interstitialBackgroundColor: UIColor + var settingsTitle: NSAttributedString? + var url: URL! + var timer: Timer? + + var isLoaded: Bool = false { + didSet { + if isLoaded { + UIView.transition(from: interstitialView, to: webView, + duration: 0.5, + options: UIViewAnimationOptions.transitionCrossDissolve, + completion: { finished in + self.interstitialView.removeFromSuperview() + self.interstitialSpinnerView.stopAnimating() + }) + } + } + } + + fileprivate var isError: Bool = false { + didSet { + if isError { + interstitialErrorView.isHidden = false + UIView.transition(from: interstitialSpinnerView, to: interstitialErrorView, + duration: 0.5, + options: UIViewAnimationOptions.transitionCrossDissolve, + completion: { finished in + self.interstitialSpinnerView.removeFromSuperview() + self.interstitialSpinnerView.stopAnimating() + }) + } + } + } + + // The view shown while the content is loading in the background web view. + fileprivate var interstitialView: UIView! + fileprivate var interstitialSpinnerView: UIActivityIndicatorView! + fileprivate var interstitialErrorView: UILabel! + + // The web view that displays content. + var webView: WKWebView! + + fileprivate func startLoading(_ timeout: Double = DefaultTimeoutTimeInterval) { + if self.isLoaded { + return + } + if timeout > 0 { + self.timer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(SettingsContentViewController.SELdidTimeOut), userInfo: nil, repeats: false) + } else { + self.timer = nil + } + self.webView.load(URLRequest(url: url)) + self.interstitialSpinnerView.startAnimating() + } + + init(backgroundColor: UIColor = UIColor.white, title: NSAttributedString? = nil) { + interstitialBackgroundColor = backgroundColor + settingsTitle = title + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + // This background agrees with the web page background. + // Keeping the background constant prevents a pop of mismatched color. + view.backgroundColor = interstitialBackgroundColor + + self.webView = makeWebView() + view.addSubview(webView) + self.webView.snp.remakeConstraints { make in + make.edges.equalTo(self.view) + } + + // Destructuring let causes problems. + let ret = makeInterstitialViews() + self.interstitialView = ret.0 + self.interstitialSpinnerView = ret.1 + self.interstitialErrorView = ret.2 + view.addSubview(interstitialView) + self.interstitialView.snp.remakeConstraints { make in + make.edges.equalTo(self.view) + } + + startLoading() + } + + func makeWebView() -> WKWebView { + let config = WKWebViewConfiguration() + let webView = WKWebView( + frame: CGRect(x: 0, y: 0, width: 1, height: 1), + configuration: config + ) + webView.allowsLinkPreview = false + webView.navigationDelegate = self + return webView + } + + fileprivate func makeInterstitialViews() -> (UIView, UIActivityIndicatorView, UILabel) { + let view = UIView() + + // Keeping the background constant prevents a pop of mismatched color. + view.backgroundColor = interstitialBackgroundColor + + let spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray) + view.addSubview(spinner) + + let error = UILabel() + if let _ = settingsTitle { + error.text = TODOPageLoadErrorString + error.textColor = UIColor.red // Firefox Orange! + error.textAlignment = NSTextAlignment.center + } + error.isHidden = true + view.addSubview(error) + + spinner.snp.makeConstraints { make in + make.center.equalTo(view) + return + } + + error.snp.makeConstraints { make in + make.center.equalTo(view) + make.left.equalTo(view.snp.left).offset(20) + make.right.equalTo(view.snp.right).offset(-20) + make.height.equalTo(44) + return + } + + return (view, spinner, error) + } + + func SELdidTimeOut() { + self.timer = nil + self.isError = true + } + + func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + // If this is a request to our local web server, use our private credentials. + if challenge.protectionSpace.host == "localhost" && challenge.protectionSpace.port == Int(WebServer.sharedInstance.server.port) { + completionHandler(.useCredential, WebServer.sharedInstance.credentials) + return + } + completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil) + } + + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + SELdidTimeOut() + } + + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + SELdidTimeOut() + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + self.timer?.invalidate() + self.timer = nil + self.isLoaded = true + } +} diff --git a/mobile/ios/Client/Frontend/Settings/SettingsNavigationController.swift b/mobile/ios/Client/Frontend/Settings/SettingsNavigationController.swift new file mode 100644 index 0000000000..c62036b34a --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/SettingsNavigationController.swift @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import UIKit + +class SettingsNavigationController: UINavigationController { + var popoverDelegate: PresentingModalViewControllerDelegate? + + func SELdone() { + if let delegate = popoverDelegate { + delegate.dismissPresentedModalViewController(self, animated: true) + } else { + self.dismiss(animated: true, completion: nil) + } + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return UIStatusBarStyle.default + } +} + +protocol PresentingModalViewControllerDelegate { + func dismissPresentedModalViewController(_ modalViewController: UIViewController, animated: Bool) +} + +class ModalSettingsNavigationController: UINavigationController { + override var preferredStatusBarStyle: UIStatusBarStyle { + return UIStatusBarStyle.default + } +} diff --git a/mobile/ios/Client/Frontend/Settings/SettingsTableViewController.swift b/mobile/ios/Client/Frontend/Settings/SettingsTableViewController.swift new file mode 100644 index 0000000000..fee3289e5b --- /dev/null +++ b/mobile/ios/Client/Frontend/Settings/SettingsTableViewController.swift @@ -0,0 +1,738 @@ +/* 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/. */ + +import Account +import Shared +import UIKit + +// A base setting class that shows a title. You probably want to subclass this, not use it directly. +class Setting: NSObject { + fileprivate var _title: NSAttributedString? + fileprivate var _footerTitle: NSAttributedString? + fileprivate var _cellHeight: CGFloat? + fileprivate var _image: UIImage? + + weak var delegate: SettingsDelegate? + + // The url the SettingsContentViewController will show, e.g. Licenses and Privacy Policy. + var url: URL? { return nil } + + // The title shown on the pref. + var title: NSAttributedString? { return _title } + var footerTitle: NSAttributedString? { return _footerTitle } + var cellHeight: CGFloat? { return _cellHeight} + fileprivate(set) var accessibilityIdentifier: String? + + // An optional second line of text shown on the pref. + var status: NSAttributedString? { return nil } + + // Whether or not to show this pref. + var hidden: Bool { return false } + + var style: UITableViewCellStyle { return .subtitle } + + var accessoryType: UITableViewCellAccessoryType { return .none } + + var textAlignment: NSTextAlignment { return .natural } + + var image: UIImage? { return _image } + + fileprivate(set) var enabled: Bool = true + + // Called when the cell is setup. Call if you need the default behaviour. + func onConfigureCell(_ cell: UITableViewCell) { + cell.detailTextLabel?.attributedText = status + cell.detailTextLabel?.numberOfLines = 0 + cell.textLabel?.attributedText = title + cell.textLabel?.textAlignment = textAlignment + cell.textLabel?.numberOfLines = 1 + cell.textLabel?.lineBreakMode = .byTruncatingTail + cell.accessoryType = accessoryType + cell.accessoryView = nil + cell.selectionStyle = enabled ? .default : .none + cell.accessibilityIdentifier = accessibilityIdentifier + cell.imageView?.image = _image + if let title = title?.string { + if let detailText = cell.detailTextLabel?.text { + cell.accessibilityLabel = "\(title), \(detailText)" + } else if let status = status?.string { + cell.accessibilityLabel = "\(title), \(status)" + } else { + cell.accessibilityLabel = title + } + } + cell.accessibilityTraits = UIAccessibilityTraitButton + cell.indentationWidth = 0 + cell.layoutMargins = UIEdgeInsets.zero + // So that the separator line goes all the way to the left edge. + cell.separatorInset = UIEdgeInsets.zero + } + + // Called when the pref is tapped. + func onClick(_ navigationController: UINavigationController?) { return } + + // Helper method to set up and push a SettingsContentViewController + func setUpAndPushSettingsContentViewController(_ navigationController: UINavigationController?) { + if let url = self.url { + let viewController = SettingsContentViewController() + viewController.settingsTitle = self.title + viewController.url = url + navigationController?.pushViewController(viewController, animated: true) + } + } + + init(title: NSAttributedString? = nil, footerTitle: NSAttributedString? = nil, cellHeight: CGFloat? = nil, delegate: SettingsDelegate? = nil, enabled: Bool? = nil) { + self._title = title + self._footerTitle = footerTitle + self._cellHeight = cellHeight + self.delegate = delegate + self.enabled = enabled ?? true + } +} + +// A setting in the sections panel. Contains a sublist of Settings +class SettingSection: Setting { + fileprivate let children: [Setting] + + init(title: NSAttributedString? = nil, footerTitle: NSAttributedString? = nil, cellHeight: CGFloat? = nil, children: [Setting]) { + self.children = children + super.init(title: title, footerTitle: footerTitle, cellHeight: cellHeight) + } + + var count: Int { + var count = 0 + for setting in children where !setting.hidden { + count += 1 + } + return count + } + + subscript(val: Int) -> Setting? { + var i = 0 + for setting in children where !setting.hidden { + if i == val { + return setting + } + i += 1 + } + return nil + } +} + +private class PaddedSwitch: UIView { + fileprivate static let Padding: CGFloat = 8 + + init(switchView: UISwitch) { + super.init(frame: CGRect.zero) + + addSubview(switchView) + + frame.size = CGSize(width: switchView.frame.width + PaddedSwitch.Padding, height: switchView.frame.height) + switchView.frame.origin = CGPoint(x: PaddedSwitch.Padding, y: 0) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// A helper class for settings with a UISwitch. +// Takes and optional settingsDidChange callback and status text. +class BoolSetting: Setting { + let prefKey: String? // Sometimes a subclass will manage its own pref setting. In that case the prefkey will be nil + + fileprivate let prefs: Prefs + fileprivate let defaultValue: Bool + fileprivate let settingDidChange: ((Bool) -> Void)? + fileprivate let statusText: NSAttributedString? + + init(prefs: Prefs, prefKey: String? = nil, defaultValue: Bool, attributedTitleText: NSAttributedString, attributedStatusText: NSAttributedString? = nil, settingDidChange: ((Bool) -> Void)? = nil) { + self.prefs = prefs + self.prefKey = prefKey + self.defaultValue = defaultValue + self.settingDidChange = settingDidChange + self.statusText = attributedStatusText + super.init(title: attributedTitleText) + } + + convenience init(prefs: Prefs, prefKey: String? = nil, defaultValue: Bool, titleText: String, statusText: String? = nil, settingDidChange: ((Bool) -> Void)? = nil) { + var statusTextAttributedString: NSAttributedString? + if let statusTextString = statusText { + statusTextAttributedString = NSAttributedString(string: statusTextString, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewHeaderTextColor]) + } + self.init(prefs: prefs, prefKey: prefKey, defaultValue: defaultValue, attributedTitleText: NSAttributedString(string: titleText, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]), attributedStatusText: statusTextAttributedString, settingDidChange: settingDidChange) + } + + override var status: NSAttributedString? { + return statusText + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + + let control = UISwitch() + control.onTintColor = UIConstants.SystemBlueColor + control.addTarget(self, action: #selector(BoolSetting.switchValueChanged(_:)), for: UIControlEvents.valueChanged) + displayBool(control) + if let title = title { + if let status = status { + control.accessibilityLabel = "\(title.string), \(status.string)" + } else { + control.accessibilityLabel = title.string + } + cell.accessibilityLabel = nil + } + cell.accessoryView = PaddedSwitch(switchView: control) + cell.selectionStyle = .none + } + + @objc func switchValueChanged(_ control: UISwitch) { + writeBool(control) + settingDidChange?(control.isOn) + UnifiedTelemetry.recordEvent(category: .action, method: .change, object: .setting, value: self.prefKey, extras: ["to": control.isOn]) + } + + // These methods allow a subclass to control how the pref is saved + func displayBool(_ control: UISwitch) { + guard let key = prefKey else { + return + } + control.isOn = prefs.boolForKey(key) ?? defaultValue + } + + func writeBool(_ control: UISwitch) { + guard let key = prefKey else { + return + } + prefs.setBool(control.isOn, forKey: key) + } +} + +/// A helper class for a setting backed by a UITextField. +/// This takes an optional settingIsValid and settingDidChange callback +/// If settingIsValid returns false, the Setting will not change and the text remains red. +class StringSetting: Setting, UITextFieldDelegate { + + let prefKey: String + fileprivate let Padding: CGFloat = 8 + + fileprivate let prefs: Prefs + fileprivate let defaultValue: String? + fileprivate let placeholder: String + fileprivate let settingDidChange: ((String?) -> Void)? + fileprivate let settingIsValid: ((String?) -> Bool)? + + let textField = UITextField() + + init(prefs: Prefs, prefKey: String, defaultValue: String? = nil, placeholder: String, accessibilityIdentifier: String, settingIsValid isValueValid: ((String?) -> Bool)? = nil, settingDidChange: ((String?) -> Void)? = nil) { + self.prefs = prefs + self.prefKey = prefKey + self.defaultValue = defaultValue + self.settingDidChange = settingDidChange + self.settingIsValid = isValueValid + self.placeholder = placeholder + + super.init() + self.accessibilityIdentifier = accessibilityIdentifier + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + if let id = accessibilityIdentifier { + textField.accessibilityIdentifier = id + "TextField" + } + textField.placeholder = placeholder + textField.textAlignment = .center + textField.delegate = self + textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged) + cell.isUserInteractionEnabled = true + cell.accessibilityTraits = UIAccessibilityTraitNone + cell.contentView.addSubview(textField) + + textField.snp.makeConstraints { make in + make.height.equalTo(44) + make.trailing.equalTo(cell.contentView).offset(-Padding) + make.leading.equalTo(cell.contentView).offset(Padding) + } + textField.text = prefs.stringForKey(prefKey) ?? defaultValue + textFieldDidChange(textField) + } + + override func onClick(_ navigationController: UINavigationController?) { + textField.becomeFirstResponder() + } + + fileprivate func isValid(_ value: String?) -> Bool { + guard let test = settingIsValid else { + return true + } + return test(prepareValidValue(userInput: value)) + } + + /// This gives subclasses an opportunity to treat the user input string + /// before it is saved or tested. + /// Default implementation does nothing. + func prepareValidValue(userInput value: String?) -> String? { + return value + } + + @objc func textFieldDidChange(_ textField: UITextField) { + let color = isValid(textField.text) ? UIConstants.TableViewRowTextColor : UIConstants.DestructiveRed + textField.textColor = color + } + + @objc func textFieldShouldReturn(_ textField: UITextField) -> Bool { + return isValid(textField.text) + } + + @objc func textFieldDidEndEditing(_ textField: UITextField) { + let text = textField.text + if !isValid(text) { + return + } + if let text = prepareValidValue(userInput: text) { + prefs.setString(text, forKey: prefKey) + } else { + prefs.removeObjectForKey(prefKey) + } + // Call settingDidChange with text or nil. + settingDidChange?(text) + } +} + +class CheckmarkSetting: Setting { + let onChanged: () -> Void + let isEnabled: () -> Bool + private let subtitle: NSAttributedString? + + override var status: NSAttributedString? { + return subtitle + } + + init(title: NSAttributedString, subtitle: NSAttributedString?, accessibilityIdentifier: String? = nil, isEnabled: @escaping () -> Bool, onChanged: @escaping () -> Void) { + self.subtitle = subtitle + self.onChanged = onChanged + self.isEnabled = isEnabled + super.init(title: title) + self.accessibilityIdentifier = accessibilityIdentifier + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + cell.accessoryType = isEnabled() ? .checkmark : .none + cell.selectionStyle = .none + } + + override func onClick(_ navigationController: UINavigationController?) { + // Force editing to end for any focused text fields so they can finish up validation first. + navigationController?.view.endEditing(true) + if !isEnabled() { + onChanged() + } + } +} + +/// A helper class for a setting backed by a UITextField. +/// This takes an optional isEnabled and mandatory onClick callback +/// isEnabled is called on each tableview.reloadData. If it returns +/// false then the 'button' appears disabled. +class ButtonSetting: Setting { + let onButtonClick: (UINavigationController?) -> Void + let destructive: Bool + let isEnabled: (() -> Bool)? + + init(title: NSAttributedString?, destructive: Bool = false, accessibilityIdentifier: String, isEnabled: (() -> Bool)? = nil, onClick: @escaping (UINavigationController?) -> Void) { + self.onButtonClick = onClick + self.destructive = destructive + self.isEnabled = isEnabled + super.init(title: title) + self.accessibilityIdentifier = accessibilityIdentifier + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + + if isEnabled?() ?? true { + cell.textLabel?.textColor = destructive ? UIConstants.DestructiveRed : UIConstants.HighlightBlue + } else { + cell.textLabel?.textColor = UIConstants.TableViewDisabledRowTextColor + } + cell.textLabel?.textAlignment = NSTextAlignment.center + cell.accessibilityTraits = UIAccessibilityTraitButton + cell.selectionStyle = .none + } + + override func onClick(_ navigationController: UINavigationController?) { + // Force editing to end for any focused text fields so they can finish up validation first. + navigationController?.view.endEditing(true) + if isEnabled?() ?? true { + onButtonClick(navigationController) + } + } +} + +// A helper class for prefs that deal with sync. Handles reloading the tableView data if changes to +// the fxAccount happen. +class AccountSetting: Setting, FxAContentViewControllerDelegate { + unowned var settings: SettingsTableViewController + + var profile: Profile { + return settings.profile + } + + override var title: NSAttributedString? { return nil } + + init(settings: SettingsTableViewController) { + self.settings = settings + super.init(title: nil) + } + + override func onConfigureCell(_ cell: UITableViewCell) { + super.onConfigureCell(cell) + if settings.profile.getAccount() != nil { + cell.selectionStyle = .none + } + } + + override var accessoryType: UITableViewCellAccessoryType { return .none } + + func contentViewControllerDidSignIn(_ viewController: FxAContentViewController, withFlags flags: FxALoginFlags) { + // This method will get called twice: once when the user signs in, and once + // when the account is verified by email – on this device or another. + // If the user hasn't dismissed the fxa content view controller, + // then we should only do that (thus finishing the sign in/verification process) + // once the account is verified. + // By the time we get to here, we should be syncing or just about to sync in the + // background, most likely from FxALoginHelper. + if flags.verified { + _ = settings.navigationController?.popToRootViewController(animated: true) + // Reload the data to reflect the new Account immediately. + settings.tableView.reloadData() + // And start advancing the Account state in the background as well. + settings.SELrefresh() + } + } + + func contentViewControllerDidCancel(_ viewController: FxAContentViewController) { + NSLog("didCancel") + _ = settings.navigationController?.popToRootViewController(animated: true) + } +} + +class WithAccountSetting: AccountSetting { + override var hidden: Bool { return !profile.hasAccount() } +} + +class WithoutAccountSetting: AccountSetting { + override var hidden: Bool { return profile.hasAccount() } +} + +@objc +protocol SettingsDelegate: class { + func settingsOpenURLInNewTab(_ url: URL) +} + +// The base settings view controller. +class SettingsTableViewController: UITableViewController { + + typealias SettingsGenerator = (SettingsTableViewController, SettingsDelegate?) -> [SettingSection] + + fileprivate let Identifier = "CellIdentifier" + fileprivate let SectionHeaderIdentifier = "SectionHeaderIdentifier" + var settings = [SettingSection]() + + weak var settingsDelegate: SettingsDelegate? + + var profile: Profile! + var tabManager: TabManager! + + var hasSectionSeparatorLine = true + + /// Used to calculate cell heights. + fileprivate lazy var dummyToggleCell: UITableViewCell = { + let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "dummyCell") + cell.accessoryView = UISwitch() + return cell + }() + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.register(UITableViewCell.self, forCellReuseIdentifier: Identifier) + tableView.register(SettingsTableSectionHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: SectionHeaderIdentifier) + tableView.separatorColor = UIConstants.TableViewSeparatorColor + tableView.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 30)) + tableView.estimatedRowHeight = 44 + tableView.estimatedSectionHeaderHeight = 44 + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + settings = generateSettings() + + NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.SELsyncDidChangeState), name: NotificationProfileDidStartSyncing, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.SELsyncDidChangeState), name: NotificationProfileDidFinishSyncing, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.SELfirefoxAccountDidChange), name: NotificationFirefoxAccountChanged, object: nil) + + tableView.reloadData() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + SELrefresh() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + NotificationCenter.default.removeObserver(self, name: NotificationProfileDidStartSyncing, object: nil) + NotificationCenter.default.removeObserver(self, name: NotificationProfileDidFinishSyncing, object: nil) + NotificationCenter.default.removeObserver(self, name: NotificationFirefoxAccountChanged, object: nil) + } + + // Override to provide settings in subclasses + func generateSettings() -> [SettingSection] { + return [] + } + + @objc fileprivate func SELsyncDidChangeState() { + DispatchQueue.main.async { + self.tableView.reloadData() + } + } + + @objc fileprivate func SELrefresh() { + // Through-out, be aware that modifying the control while a refresh is in progress is /not/ supported and will likely crash the app. + if let account = self.profile.getAccount() { + account.advance().upon { state in + DispatchQueue.main.async { () -> Void in + self.tableView.reloadData() + } + } + } else { + self.tableView.reloadData() + } + } + + @objc func SELfirefoxAccountDidChange() { + self.tableView.reloadData() + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let section = settings[indexPath.section] + if let setting = section[indexPath.row] { + var cell: UITableViewCell! + if let _ = setting.status { + // Work around http://stackoverflow.com/a/9999821 and http://stackoverflow.com/a/25901083 by using a new cell. + // I could not make any setNeedsLayout solution work in the case where we disconnect and then connect a new account. + // Be aware that dequeing and then ignoring a cell appears to cause issues; only deque a cell if you're going to return it. + cell = UITableViewCell(style: setting.style, reuseIdentifier: nil) + } else { + cell = tableView.dequeueReusableCell(withIdentifier: Identifier, for: indexPath) + } + setting.onConfigureCell(cell) + return cell + } + return tableView.dequeueReusableCell(withIdentifier: Identifier, for: indexPath) + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return settings.count + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + let section = settings[section] + return section.count + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: SectionHeaderIdentifier) as! SettingsTableSectionHeaderFooterView + let sectionSetting = settings[section] + if let sectionTitle = sectionSetting.title?.string { + headerView.titleLabel.text = sectionTitle.uppercased() + } + // Hide the top border for the top section to avoid having a double line at the top + if section == 0 || !hasSectionSeparatorLine { + headerView.showTopBorder = false + } else { + headerView.showTopBorder = true + } + + return headerView + } + + override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + let sectionSetting = settings[section] + guard let sectionFooter = sectionSetting.footerTitle?.string else { + return nil + } + let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: SectionHeaderIdentifier) as! SettingsTableSectionHeaderFooterView + footerView.titleLabel.text = sectionFooter + footerView.titleAlignment = .top + footerView.showBottomBorder = false + return footerView + } + + // To hide a footer dynamically requires returning nil from viewForFooterInSection + // and setting the height to zero. + // However, we also want the height dynamically calculated, there is a magic constant + // for that: `UITableViewAutomaticDimension`. + override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + let sectionSetting = settings[section] + if let _ = sectionSetting.footerTitle?.string { + return UITableViewAutomaticDimension + } + return 0 + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + let section = settings[indexPath.section] + // Workaround for calculating the height of default UITableViewCell cells with a subtitle under + // the title text label. + if let setting = section[indexPath.row], setting is BoolSetting && setting.status != nil { + return calculateStatusCellHeightForSetting(setting) + } + if let setting = section[indexPath.row], let height = setting.cellHeight { + return height + } + + return UITableViewAutomaticDimension + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let section = settings[indexPath.section] + if let setting = section[indexPath.row], setting.enabled { + setting.onClick(navigationController) + } + } + + fileprivate func calculateStatusCellHeightForSetting(_ setting: Setting) -> CGFloat { + dummyToggleCell.layoutSubviews() + + let topBottomMargin: CGFloat = 10 + let width = dummyToggleCell.contentView.frame.width - 2 * dummyToggleCell.separatorInset.left + + return + heightForLabel(dummyToggleCell.textLabel!, width: width, text: setting.title?.string) + + heightForLabel(dummyToggleCell.detailTextLabel!, width: width, text: setting.status?.string) + + 2 * topBottomMargin + } + + fileprivate func heightForLabel(_ label: UILabel, width: CGFloat, text: String?) -> CGFloat { + guard let text = text else { return 0 } + + let size = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) + let attrs = [NSFontAttributeName: label.font as Any] + let boundingRect = NSString(string: text).boundingRect(with: size, + options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attrs, context: nil) + return boundingRect.height + } +} + +struct SettingsTableSectionHeaderFooterViewUX { + static let titleHorizontalPadding: CGFloat = 15 + static let titleVerticalPadding: CGFloat = 6 + static let titleVerticalLongPadding: CGFloat = 20 +} + +class SettingsTableSectionHeaderFooterView: UITableViewHeaderFooterView { + + enum TitleAlignment { + case top + case bottom + } + + var titleAlignment: TitleAlignment = .bottom { + didSet { + remakeTitleAlignmentConstraints() + } + } + + var showTopBorder: Bool = true { + didSet { + topBorder.isHidden = !showTopBorder + } + } + + var showBottomBorder: Bool = true { + didSet { + bottomBorder.isHidden = !showBottomBorder + } + } + + lazy var titleLabel: UILabel = { + var headerLabel = UILabel() + headerLabel.textColor = UIConstants.TableViewHeaderTextColor + headerLabel.font = UIFont.systemFont(ofSize: 12.0, weight: UIFontWeightRegular) + headerLabel.numberOfLines = 0 + return headerLabel + }() + + fileprivate lazy var topBorder: UIView = { + let topBorder = UIView() + topBorder.backgroundColor = UIConstants.SeparatorColor + return topBorder + }() + + fileprivate lazy var bottomBorder: UIView = { + let bottomBorder = UIView() + bottomBorder.backgroundColor = UIConstants.SeparatorColor + return bottomBorder + }() + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + contentView.backgroundColor = UIConstants.TableViewHeaderBackgroundColor + addSubview(titleLabel) + addSubview(topBorder) + addSubview(bottomBorder) + + setupInitialConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setupInitialConstraints() { + bottomBorder.snp.makeConstraints { make in + make.bottom.left.right.equalTo(self) + make.height.equalTo(0.5) + } + + topBorder.snp.makeConstraints { make in + make.top.left.right.equalTo(self) + make.height.equalTo(0.5) + } + + remakeTitleAlignmentConstraints() + } + + override func prepareForReuse() { + super.prepareForReuse() + showTopBorder = true + showBottomBorder = true + titleLabel.text = nil + titleAlignment = .bottom + } + + fileprivate func remakeTitleAlignmentConstraints() { + switch titleAlignment { + case .top: + titleLabel.snp.remakeConstraints { make in + make.left.right.equalTo(self).inset(SettingsTableSectionHeaderFooterViewUX.titleHorizontalPadding) + make.top.equalTo(self).offset(SettingsTableSectionHeaderFooterViewUX.titleVerticalPadding) + make.bottom.equalTo(self).offset(-SettingsTableSectionHeaderFooterViewUX.titleVerticalLongPadding) + } + case .bottom: + titleLabel.snp.remakeConstraints { make in + make.left.right.equalTo(self).inset(SettingsTableSectionHeaderFooterViewUX.titleHorizontalPadding) + make.bottom.equalTo(self).offset(-SettingsTableSectionHeaderFooterViewUX.titleVerticalPadding) + make.top.equalTo(self).offset(SettingsTableSectionHeaderFooterViewUX.titleVerticalLongPadding) + } + } + } +} + diff --git a/mobile/ios/Client/Frontend/Share/ShareExtensionHelper.swift b/mobile/ios/Client/Frontend/Share/ShareExtensionHelper.swift new file mode 100644 index 0000000000..442cb6beae --- /dev/null +++ b/mobile/ios/Client/Frontend/Share/ShareExtensionHelper.swift @@ -0,0 +1,148 @@ +/* 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/. */ + +import Foundation +import Shared +import OnePasswordExtension + +private let log = Logger.browserLogger + +class ShareExtensionHelper: NSObject { + fileprivate weak var selectedTab: Tab? + + fileprivate let selectedURL: URL + fileprivate var onePasswordExtensionItem: NSExtensionItem! + fileprivate let browserFillIdentifier = "org.appextension.fill-browser-action" + + init(url: URL, tab: Tab?) { + self.selectedURL = tab?.canonicalURL?.displayURL ?? url + self.selectedTab = tab + } + + func createActivityViewController(_ completionHandler: @escaping (_ completed: Bool, _ activityType: String?) -> Void) -> UIActivityViewController { + var activityItems = [AnyObject]() + + let printInfo = UIPrintInfo(dictionary: nil) + + let absoluteString = selectedTab?.url?.absoluteString ?? selectedURL.absoluteString + printInfo.jobName = absoluteString + printInfo.outputType = .general + activityItems.append(printInfo) + + if let tab = selectedTab { + activityItems.append(TabPrintPageRenderer(tab: tab)) + } + + if let title = selectedTab?.title { + activityItems.append(TitleActivityItemProvider(title: title)) + } + activityItems.append(self) + + let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) + + // Hide 'Add to Reading List' which currently uses Safari. + // We would also hide View Later, if possible, but the exclusion list doesn't currently support + // third-party activity types (rdar://19430419). + activityViewController.excludedActivityTypes = [ + UIActivityType.addToReadingList, + ] + + // This needs to be ready by the time the share menu has been displayed and + // activityViewController(activityViewController:, activityType:) is called, + // which is after the user taps the button. So a million cycles away. + findLoginExtensionItem() + + activityViewController.completionWithItemsHandler = { activityType, completed, returnedItems, activityError in + if !completed { + completionHandler(completed, activityType.map { $0.rawValue }) + return + } + // Bug 1392418 - When copying a url using the share extension there are 2 urls in the pasteboard. + // Make sure the pasteboard only has one url. + if let url = UIPasteboard.general.urls?.first { + UIPasteboard.general.urls = [url] + } + + if self.isPasswordManagerActivityType(activityType.map { $0.rawValue }) { + if let logins = returnedItems { + self.fillPasswords(logins as [AnyObject]) + } + } + + completionHandler(completed, activityType.map { $0.rawValue }) + } + return activityViewController + } +} + +extension ShareExtensionHelper: UIActivityItemSource { + func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { + return selectedURL + } + + // IMPORTANT: This method needs Swift compiler optimization DISABLED to prevent a nasty + // crash from happening in release builds. It seems as though the check for `nil` may + // get removed by the optimizer which leads to a crash when that happens. + @_semantics("optimize.sil.never") func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? { + // activityType actually is nil sometimes (in the simulator at least) + if activityType != nil && isPasswordManagerActivityType(activityType.rawValue) { + return onePasswordExtensionItem + } else { + // Return the URL for the selected tab. If we are in reader view then decode + // it so that we copy the original and not the internal localhost one. + return selectedURL.isReaderModeURL ? selectedURL.decodeReaderModeURL : selectedURL + } + } + + func activityViewController(_ activityViewController: UIActivityViewController, dataTypeIdentifierForActivityType activityType: UIActivityType?) -> String { + if let type = activityType, isPasswordManagerActivityType(type.rawValue) { + return browserFillIdentifier + } + return activityType == nil ? browserFillIdentifier : kUTTypeURL as String + } +} + +private extension ShareExtensionHelper { + + func isPasswordManagerActivityType(_ activityType: String?) -> Bool { + // A 'password' substring covers the most cases, such as pwsafe and 1Password. + // com.agilebits.onepassword-ios.extension + // com.app77.ios.pwsafe2.find-login-action-password-actionExtension + // If your extension's bundle identifier does not contain "password", simply submit a pull request by adding your bundle identifier. + return (activityType?.range(of: "password") != nil) + || (activityType == "com.lastpass.ilastpass.LastPassExt") + || (activityType == "in.sinew.Walletx.WalletxExt") + || (activityType == "com.8bit.bitwarden.find-login-action-extension") + + } + + func findLoginExtensionItem() { + guard let selectedWebView = selectedTab?.webView else { + return + } + + // Add 1Password to share sheet + OnePasswordExtension.shared().createExtensionItem(forWebView: selectedWebView, completion: {(extensionItem, error) -> Void in + if extensionItem == nil { + log.error("Failed to create the password manager extension item: \(error.debugDescription).") + return + } + + // Set the 1Password extension item property + self.onePasswordExtensionItem = extensionItem + }) + } + + func fillPasswords(_ returnedItems: [AnyObject]) { + guard let selectedWebView = selectedTab?.webView else { + return + } + + OnePasswordExtension.shared().fillReturnedItems(returnedItems, intoWebView: selectedWebView, completion: { (success, returnedItemsError) -> Void in + if !success { + log.error("Failed to fill item into webview: \(returnedItemsError ??? "nil").") + } + }) + } +} diff --git a/mobile/ios/Client/Frontend/Share/TitleActivityItemProvider.swift b/mobile/ios/Client/Frontend/Share/TitleActivityItemProvider.swift new file mode 100644 index 0000000000..1e58531d36 --- /dev/null +++ b/mobile/ios/Client/Frontend/Share/TitleActivityItemProvider.swift @@ -0,0 +1,33 @@ +/* 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/. */ + +import Foundation + +/// This Activity Item Provider subclass does two things that are non-standard behaviour: +/// +/// * We return NSNull if the calling activity is not supposed to see the title. For example the Copy action, which should only paste the URL. We also include Message and Mail to have parity with what Safari exposes. +/// * We set the subject of the item to the title, this means it will correctly be used when sharing to for example Mail. Again parity with Safari. +/// +/// Note that not all applications use the Subject. For example OmniFocus ignores it, so we need to do both. + +class TitleActivityItemProvider: UIActivityItemProvider { + static let activityTypesToIgnore = [UIActivityType.copyToPasteboard, UIActivityType.message, UIActivityType.mail] + + init(title: String) { + super.init(placeholderItem: title) + } + + override var item: Any { + if let activityType = activityType { + if TitleActivityItemProvider.activityTypesToIgnore.contains(activityType) { + return NSNull() + } + } + return placeholderItem! as AnyObject + } + + override func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivityType?) -> String { + return placeholderItem as! String + } +} diff --git a/mobile/ios/Client/Frontend/Strings.swift b/mobile/ios/Client/Frontend/Strings.swift new file mode 100644 index 0000000000..3590c9f1f8 --- /dev/null +++ b/mobile/ios/Client/Frontend/Strings.swift @@ -0,0 +1,462 @@ +/* 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/. */ + +import Foundation + +public struct Strings {} + +/// Return the main application bundle. Even if called from an extension. If for some reason we cannot find the +/// application bundle, the current bundle is returned, which will then result in an English base language string. +private func applicationBundle() -> Bundle { + let bundle = Bundle.main + guard bundle.bundleURL.pathExtension == "appex", let applicationBundleURL = (bundle.bundleURL as NSURL).deletingLastPathComponent?.deletingLastPathComponent() else { + return bundle + } + return Bundle(url: applicationBundleURL) ?? bundle +} + +// SendTo extension. +extension Strings { + public static let SendToCancelButton = NSLocalizedString("SendTo.Cancel.Button", bundle: applicationBundle(), value: "Cancel", comment: "Button title for cancelling SendTo screen") + public static let SendToErrorOKButton = NSLocalizedString("SendTo.Error.OK.Button", bundle: applicationBundle(), value: "OK", comment: "OK button to dismiss the error prompt.") + public static let SendToErrorTitle = NSLocalizedString("SendTo.Error.Title", bundle: applicationBundle(), value: "The link you are trying to share cannot be shared.", comment: "Title of error prompt displayed when an invalid URL is shared.") + public static let SendToErrorMessage = NSLocalizedString("SendTo.Error.Message", bundle: applicationBundle(), value: "Only HTTP and HTTPS links can be shared.", comment: "Message in error prompt explaining why the URL is invalid.") +} + +// ShareTo extension. +extension Strings { + public static let ShareToCancelButton = NSLocalizedString("ShareTo.Cancel.Button", bundle: applicationBundle(), value: "Cancel", comment: "Button title for cancelling Share screen") +} + +// Top Sites. +extension Strings { + public static let TopSitesEmptyStateDescription = NSLocalizedString("TopSites.EmptyState.Description", value: "Your most visited sites will show up here.", comment: "Description label for the empty Top Sites state.") + public static let TopSitesEmptyStateTitle = NSLocalizedString("TopSites.EmptyState.Title", value: "Welcome to Top Sites", comment: "The title for the empty Top Sites state") + public static let TopSitesRemoveButtonAccessibilityLabel = NSLocalizedString("TopSites.RemovePage.Button", value: "Remove page — %@", comment: "Button shown in editing mode to remove this site from the top sites panel.") +} + +// Activity Stream. +extension Strings { + public static let HighlightIntroTitle = NSLocalizedString("ActivityStream.HighlightIntro.Title", value: "Be on the Lookout", comment: "The title that appears for the introduction to highlights in AS.") + public static let HighlightIntroDescription = NSLocalizedString("ActivityStream.HighlightIntro.Description", value: "Firefox will place things here that you’ve discovered on the web so you can find your way back to the great articles, videos, bookmarks and other pages", comment: "The detailed text that explains what highlights are in AS.") + public static let ASPageControlButton = NSLocalizedString("ActivityStream.PageControl.Button", value: "Next Page", comment: "The page control button that lets you switch between pages in top sites") + public static let ASHighlightsTitle = NSLocalizedString("ActivityStream.Highlights.Title", value: "Highlights", comment: "Section title label for the Highlights section") + public static let ASPocketTitle = NSLocalizedString("ActivityStream.Pocket.SectionTitle", value: "Recommended by Pocket", comment: "Section title label for Recommended by Pocket section") + public static let ASTopSitesTitle = NSLocalizedString("ActivityStream.TopSites.SectionTitle", value: "Top Sites", comment: "Section title label for Top Sites") + public static let HighlightVistedText = NSLocalizedString("ActivityStream.Highlights.Visited", value: "Visited", comment: "The description of a highlight if it is a site the user has visited") + public static let HighlightBookmarkText = NSLocalizedString("ActivityStream.Highlights.Bookmark", value: "Bookmarked", comment: "The description of a highlight if it is a site the user has bookmarked") + public static let PocketTrendingText = NSLocalizedString("ActivityStream.Pocket.Trending", value: "Trending", comment: "The description of a Pocket Story") +} + +// Home Panel Context Menu. +extension Strings { + public static let OpenInNewTabContextMenuTitle = NSLocalizedString("HomePanel.ContextMenu.OpenInNewTab", value: "Open in New Tab", comment: "The title for the Open in New Tab context menu action for sites in Home Panels") + public static let OpenInNewPrivateTabContextMenuTitle = NSLocalizedString("HomePanel.ContextMenu.OpenInNewPrivateTab", value: "Open in New Private Tab", comment: "The title for the Open in New Private Tab context menu action for sites in Home Panels") + public static let BookmarkContextMenuTitle = NSLocalizedString("HomePanel.ContextMenu.Bookmark", value: "Bookmark", comment: "The title for the Bookmark context menu action for sites in Home Panels") + public static let RemoveBookmarkContextMenuTitle = NSLocalizedString("HomePanel.ContextMenu.RemoveBookmark", value: "Remove Bookmark", comment: "The title for the Remove Bookmark context menu action for sites in Home Panels") + public static let DeleteFromHistoryContextMenuTitle = NSLocalizedString("HomePanel.ContextMenu.DeleteFromHistory", value: "Delete from History", comment: "The title for the Delete from History context menu action for sites in Home Panels") + public static let ShareContextMenuTitle = NSLocalizedString("HomePanel.ContextMenu.Share", value: "Share", comment: "The title for the Share context menu action for sites in Home Panels") + public static let RemoveContextMenuTitle = NSLocalizedString("HomePanel.ContextMenu.Remove", value: "Remove", comment: "The title for the Remove context menu action for sites in Home Panels") + public static let PinTopsiteActionTitle = NSLocalizedString("ActivityStream.ContextMenu.PinTopsite", value: "Pin to Top Sites", comment: "The title for the pinning a topsite action") + public static let RemovePinTopsiteActionTitle = NSLocalizedString("ActivityStream.ContextMenu.RemovePinTopsite", value: "Remove Pinned Site", comment: "The title for removing a pinned topsite action") +} + +// PhotonActionSheet Strings +extension Strings { + public static let CancelButtonTitle = NSLocalizedString("PhotonMenu.cancel", value: "Cancel", comment: "Button for closing the menu action sheet") + +} + +// Settings. +extension Strings { + public static let SettingsClearPrivateDataClearButton = NSLocalizedString("Settings.ClearPrivateData.Clear.Button", value: "Clear Private Data", comment: "Button in settings that clears private data for the selected items.") + public static let SettingsClearPrivateDataSectionName = NSLocalizedString("Settings.ClearPrivateData.SectionName", value: "Clear Private Data", comment: "Label used as an item in Settings. When touched it will open a dialog prompting the user to make sure they want to clear all of their private data.") + public static let SettingsClearPrivateDataTitle = NSLocalizedString("Settings.ClearPrivateData.Title", value: "Clear Private Data", comment: "Title displayed in header of the setting panel.") + public static let SettingsDisconnectSyncAlertTitle = NSLocalizedString("Settings.Disconnect.Title", value: "Disconnect Sync?", comment: "Title of the alert when prompting the user asking to disconnect.") + public static let SettingsDisconnectSyncButton = NSLocalizedString("Settings.Disconnect.Button", value: "Disconnect Sync", comment: "Button displayed at the bottom of settings page allowing users to Disconnect from FxA") + public static let SettingsDisconnectDestructiveAction = NSLocalizedString("Settings.Disconnect.DestructiveButton", value: "Disconnect", comment: "Destructive action button in alert when user is prompted for disconnect") + public static let SettingsSearchDoneButton = NSLocalizedString("Settings.Search.Done.Button", value: "Done", comment: "Button displayed at the top of the search settings.") + public static let SettingsSearchEditButton = NSLocalizedString("Settings.Search.Edit.Button", value: "Edit", comment: "Button displayed at the top of the search settings.") + public static let UseTouchID = NSLocalizedString("Use Touch ID", tableName: "AuthenticationManager", comment: "List section title for when to use Touch ID") + public static let UseFaceID = NSLocalizedString("Use Face ID", tableName: "AuthenticationManager", comment: "List section title for when to use Face ID") +} + +// Error pages. +extension Strings { + public static let ErrorPagesAdvancedButton = NSLocalizedString("ErrorPages.Advanced.Button", value: "Advanced", comment: "Label for button to perform advanced actions on the error page") + public static let ErrorPagesAdvancedWarning1 = NSLocalizedString("ErrorPages.AdvancedWarning1.Text", value: "Warning: we can’t confirm your connection to this website is secure.", comment: "Warning text when clicking the Advanced button on error pages") + public static let ErrorPagesAdvancedWarning2 = NSLocalizedString("ErrorPages.AdvancedWarning2.Text", value: "It may be a misconfiguration or tampering by an attacker. Proceed if you accept the potential risk.", comment: "Additional warning text when clicking the Advanced button on error pages") + public static let ErrorPagesCertWarningDescription = NSLocalizedString("ErrorPages.CertWarning.Description", value: "The owner of %@ has configured their website improperly. To protect your information from being stolen, Firefox has not connected to this website.", comment: "Warning text on the certificate error page") + public static let ErrorPagesCertWarningTitle = NSLocalizedString("ErrorPages.CertWarning.Title", value: "This Connection is Untrusted", comment: "Title on the certificate error page") + public static let ErrorPagesGoBackButton = NSLocalizedString("ErrorPages.GoBack.Button", value: "Go Back", comment: "Label for button to go back from the error page") + public static let ErrorPagesVisitOnceButton = NSLocalizedString("ErrorPages.VisitOnce.Button", value: "Visit site anyway", comment: "Button label to temporarily continue to the site from the certificate error page") +} + +// Logins Helper. +extension Strings { + public static let LoginsHelperSaveLoginButtonTitle = NSLocalizedString("LoginsHelper.SaveLogin.Button", value: "Save Login", comment: "Button to save the user's password") + public static let LoginsHelperDontSaveButtonTitle = NSLocalizedString("LoginsHelper.DontSave.Button", value: "Don’t Save", comment: "Button to not save the user's password") + public static let LoginsHelperUpdateButtonTitle = NSLocalizedString("LoginsHelper.Update.Button", value: "Update", comment: "Button to update the user's password") +} + +// History Panel +extension Strings { + public static let SyncedTabsTableViewCellTitle = NSLocalizedString("HistoryPanel.SyncedTabsCell.Title", value: "Synced Devices", comment: "Title for the Synced Tabs Cell in the History Panel") + public static let HistoryBackButtonTitle = NSLocalizedString("HistoryPanel.HistoryBackButton.Title", value: "History", comment: "Title for the Back to History button in the History Panel") + public static let EmptySyncedTabsPanelStateTitle = NSLocalizedString("HistoryPanel.EmptySyncedTabsState.Title", value: "Firefox Sync", comment: "Title for the empty synced tabs state in the History Panel") + public static let EmptySyncedTabsPanelStateDescription = NSLocalizedString("HistoryPanel.EmptySyncedTabsState.Description", value: "Sign in to view open tabs on your other devices.", comment: "Description for the empty synced tabs state in the History Panel") + public static let EmptySyncedTabsPanelNullStateDescription = NSLocalizedString("HistoryPanel.EmptySyncedTabsNullState.Description", value: "Your tabs from other devices show up here.", comment: "Description for the empty synced tabs null state in the History Panel") + public static let SyncedTabsTableViewCellDescription = NSLocalizedString("HistoryPanel.SyncedTabsCell.Description.Pluralized", value: "%d device(s) connected", comment: "Description that corresponds with a number of devices connected for the Synced Tabs Cell in the History Panel") + public static let HistoryPanelEmptyStateTitle = NSLocalizedString("HistoryPanel.EmptyState.Title", value: "Websites you’ve visited recently will show up here.", comment: "Title for the History Panel empty state.") + public static let RecentlyClosedTabsButtonTitle = NSLocalizedString("HistoryPanel.RecentlyClosedTabsButton.Title", value: "Recently Closed", comment: "Title for the Recently Closed button in the History Panel") + public static let RecentlyClosedTabsPanelTitle = NSLocalizedString("RecentlyClosedTabsPanel.Title", value: "Recently Closed", comment: "Title for the Recently Closed Tabs Panel") + public static let FirefoxHomePage = NSLocalizedString("Firefox.HomePage.Title", value: "Firefox Home Page", comment: "Title for firefox about:home page in tab history list") +} + +// Syncing +extension Strings { + public static let SyncingMessageWithEllipsis = NSLocalizedString("Sync.SyncingEllipsis.Label", value: "Syncing…", comment: "Message displayed when the user's account is syncing with ellipsis at the end") + public static let SyncingMessageWithoutEllipsis = NSLocalizedString("Sync.Syncing.Label", value: "Syncing", comment: "Message displayed when the user's account is syncing with no ellipsis") + + public static let FirstTimeSyncLongTime = NSLocalizedString("Sync.FirstTimeMessage.Label", value: "Your first sync may take a while", comment: "Message displayed when the user syncs for the first time") + + public static let FirefoxSyncOfflineTitle = NSLocalizedString("SyncState.Offline.Title", value: "Sync is offline", comment: "Title for Sync status message when Sync failed due to being offline") + public static let FirefoxSyncNotStartedTitle = NSLocalizedString("SyncState.NotStarted.Title", value: "Sync is unavailable", comment: "Title for Sync status message when Sync failed to start.") + public static let FirefoxSyncPartialTitle = NSLocalizedString("SyncState.Partial.Title", value: "Sync is experiencing issues syncing %@", comment: "Title for Sync status message when a component of Sync failed to complete, where %@ represents the name of the component, i.e. Sync is experiencing issues syncing Bookmarks") + public static let FirefoxSyncFailedTitle = NSLocalizedString("SyncState.Failed.Title", value: "Syncing has failed", comment: "Title for Sync status message when synchronization failed to complete") + public static let FirefoxSyncTroubleshootTitle = NSLocalizedString("Settings.TroubleShootSync.Title", value: "Troubleshoot", comment: "Title of link to help page to find out how to solve Sync issues") + + public static func localizedStringForSyncComponent(_ componentName: String) -> String? { + switch componentName { + case "bookmarks": + return NSLocalizedString("SyncState.Bookmark.Title", value: "Bookmarks", comment: "The Bookmark sync component, used in SyncState.Partial.Title") + case "clients": + return NSLocalizedString("SyncState.Clients.Title", value: "Remote Clients", comment: "The Remote Clients sync component, used in SyncState.Partial.Title") + case "tabs": + return NSLocalizedString("SyncState.Tabs.Title", value: "Tabs", comment: "The Tabs sync component, used in SyncState.Partial.Title") + case "logins": + return NSLocalizedString("SyncState.Logins.Title", value: "Logins", comment: "The Logins sync component, used in SyncState.Partial.Title") + case "history": + return NSLocalizedString("SyncState.History.Title", value: "History", comment: "The History sync component, used in SyncState.Partial.Title") + default: return nil + } + } +} + +// Firefox Account +extension Strings { + // Settings strings + public static let FxAFirefoxAccount = NSLocalizedString("FxA.FirefoxAccount", value: "Firefox Account", comment: "Settings section title for Firefox Account") + public static let FxASignIntoSync = NSLocalizedString("FxA.SignIntoSync", value: "Sign in to Sync", comment: "Button label to sign into Sync") + public static let FxATakeYourWebWithYou = NSLocalizedString("FxA.TakeYourWebWithYou", value: "Take Your Web With You", comment: "Call to action for sign into sync button") + public static let FxASyncUsageDetails = NSLocalizedString("FxA.SyncExplain", value: "Get your tabs, bookmarks, and passwords from your other devices.", comment: "Label explaining what sync does") + public static let FxAAccountVerificationRequired = NSLocalizedString("FxA.AccountVerificationRequired", value: "Account Verification Required", comment: "Label stating your account is not verified") + public static let FxAAccountVerificationDetails = NSLocalizedString("FxA.AccountVerificationDetails", value: "Wrong email? Disconnect below to start over.", comment: "Label stating how to disconnect account") + public static let FxAManageAccount = NSLocalizedString("FxA.ManageAccount", value: "Manage Account", comment: "Button label to goto Firefox Account settings") + public static let FxASyncNow = NSLocalizedString("FxA.SyncNow", value: "Sync Now", comment: "Button label to Sync your Firefox Account") + public static let FxANoInternetConnection = NSLocalizedString("FxA.NoInternetConnection", value: "No Internet Connection", comment: "Label when no internet is present") + + // Surface error strings + public static let FxAAccountVerificationRequiredSurface = NSLocalizedString("FxA.AccountVerificationRequiredSurface", value: "You need to verify %@. Check your email for the verification link from Firefox.", comment: "Message explaining that user needs to check email for Firefox Account verfication link.") + public static let FxAResendEmail = NSLocalizedString("FxA.ResendEmail", value: "Resend Email", comment: "Button label to resend email") +} + +//Hotkey Titles +extension Strings { + public static let ReloadPageTitle = NSLocalizedString("Hotkeys.Reload.DiscoveryTitle", value: "Reload Page", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let BackTitle = NSLocalizedString("Hotkeys.Back.DiscoveryTitle", value: "Back", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let ForwardTitle = NSLocalizedString("Hotkeys.Forward.DiscoveryTitle", value: "Forward", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + + public static let FindTitle = NSLocalizedString("Hotkeys.Find.DiscoveryTitle", value: "Find", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let SelectLocationBarTitle = NSLocalizedString("Hotkeys.SelectLocationBar.DiscoveryTitle", value: "Select Location Bar", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let NewTabTitle = NSLocalizedString("Hotkeys.NewTab.DiscoveryTitle", value: "New Tab", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let NewPrivateTabTitle = NSLocalizedString("Hotkeys.NewPrivateTab.DiscoveryTitle", value: "New Private Tab", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let CloseTabTitle = NSLocalizedString("Hotkeys.CloseTab.DiscoveryTitle", value: "Close Tab", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let ShowNextTabTitle = NSLocalizedString("Hotkeys.ShowNextTab.DiscoveryTitle", value: "Show Next Tab", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let ShowPreviousTabTitle = NSLocalizedString("Hotkeys.ShowPreviousTab.DiscoveryTitle", value: "Show Previous Tab", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") +} + +// Home page. +extension Strings { + public static let SettingsHomePageSectionName = NSLocalizedString("Settings.HomePage.SectionName", value: "Homepage", comment: "Label used as an item in Settings. When touched it will open a dialog to configure the home page and its uses.") + public static let SettingsHomePageTitle = NSLocalizedString("Settings.HomePage.Title", value: "Homepage Settings", comment: "Title displayed in header of the setting panel.") + public static let SettingsHomePageURLSectionTitle = NSLocalizedString("Settings.HomePage.URL.Title", value: "Current Homepage", comment: "Title of the setting section containing the URL of the current home page.") + public static let SettingsHomePageUseCurrentPage = NSLocalizedString("Settings.HomePage.UseCurrent.Button", value: "Use Current Page", comment: "Button in settings to use the current page as home page.") + public static let SettingsHomePagePlaceholder = NSLocalizedString("Settings.HomePage.URL.Placeholder", value: "Enter a webpage", comment: "Placeholder text in the homepage setting when no homepage has been set.") + public static let SettingsHomePageUseCopiedLink = NSLocalizedString("Settings.HomePage.UseCopiedLink.Button", value: "Use Copied Link", comment: "Button in settings to use the current link on the clipboard as home page.") + public static let SettingsHomePageUseDefault = NSLocalizedString("Settings.HomePage.UseDefault.Button", value: "Use Default", comment: "Button in settings to use the default home page. If no default is set, then this button isn't shown.") + public static let SettingsHomePageClear = NSLocalizedString("Settings.HomePage.Clear.Button", value: "Clear", comment: "Button in settings to clear the home page.") + public static let SetHomePageDialogTitle = NSLocalizedString("HomePage.Set.Dialog.Title", value: "Do you want to use this web page as your home page?", comment: "Alert dialog title when the user opens the home page for the first time.") + public static let SetHomePageDialogMessage = NSLocalizedString("HomePage.Set.Dialog.Message", value: "You can change this at any time in Settings", comment: "Alert dialog body when the user opens the home page for the first time.") + public static let SetHomePageDialogYes = NSLocalizedString("HomePage.Set.Dialog.OK", value: "Set Homepage", comment: "Button accepting changes setting the home page for the first time.") + public static let SetHomePageDialogNo = NSLocalizedString("HomePage.Set.Dialog.Cancel", value: "Cancel", comment: "Button cancelling changes setting the home page for the first time.") +} + +// New tab choice settings +extension Strings { + public static let SettingsNewTabSectionName = NSLocalizedString("Settings.NewTab.SectionName", value: "New Tab", comment: "Label used as an item in Settings. When touched it will open a dialog to configure the new tab behaviour.") + public static let SettingsNewTabTitle = NSLocalizedString("Settings.NewTab.Title", value: "New Tab Settings", comment: "Title displayed in header of the setting panel.") + public static let SettingsNewTabTopSites = NSLocalizedString("Settings.NewTab.Option.TopSites", value: "Show your Top Sites", comment: "Option in settings to show top sites when you open a new tab") + public static let SettingsNewTabBookmarks = NSLocalizedString("Settings.NewTab.Option.Bookmarks", value: "Show your Bookmarks", comment: "Option in settings to show bookmarks when you open a new tab") + public static let SettingsNewTabHistory = NSLocalizedString("Settings.NewTab.Option.History", value: "Show your History", comment: "Option in settings to show history when you open a new tab") + public static let SettingsNewTabReadingList = NSLocalizedString("Settings.NewTab.Option.ReadingList", value: "Show your Reading List", comment: "Option in settings to show reading list when you open a new tab") + public static let SettingsNewTabBlankPage = NSLocalizedString("Settings.NewTab.Option.BlankPage", value: "Show a Blank Page", comment: "Option in settings to show a blank page when you open a new tab") + public static let SettingsNewTabHomePage = NSLocalizedString("Settings.NewTab.Option.HomePage", value: "Show your Homepage", comment: "Option in settings to show your homepage when you open a new tab") + public static let SettingsNewTabDescription = NSLocalizedString("Settings.NewTab.Description", value: "When you open a New Tab:", comment: "A description in settings of what the new tab choice means") + // AS Panel settings + public static let SettingsNewTabASTitle = NSLocalizedString("Settings.NewTab.Option.ASTitle", value: "Additional Content", comment: "The title of the section in newtab that lets you modify the topsites panel") + public static let SettingsNewTabPocket = NSLocalizedString("Settings.NewTab.Option.Pocket", value: "Recommended by Pocket", comment: "Option in settings to turn on off pocket recommendations") + public static let SettingsNewTabHiglightsHistory = NSLocalizedString("Settings.NewTab.Option.HighlightsHistory", value: "Visited", comment: "Option in settings to turn off history in the highlights section") + public static let SettingsNewTabHighlightsBookmarks = NSLocalizedString("Settings.NewTab.Option.HighlightsBookmarks", value: "Recent Bookmarks", comment: "Option in the settings to turn off recent bookmarks in the Highlights section") +} + +// Custom account settings - These strings did not make it for the v10 l10n deadline so we have turned them into regular strings. These strings will come back localized in a next version. + +extension Strings { + // Settings.AdvanceAccount.SectionName + // Label used as an item in Settings. When touched it will open a dialog to setup advance Firefox account settings. + public static let SettingsAdvanceAccountSectionName = "Account Settings" + + // Settings.AdvanceAccount.SectionFooter + // Details for using custom Firefox Account service. + public static let SettingsAdvanceAccountSectionFooter = "To use a custom Firefox Account and sync servers, specify the root Url of the Firefox Account site. This will download the configuration and setup this device to use the new service. After the new service has been set, you will need to create a new Firefox Account or login with an existing one." + + // Settings.AdvanceAccount.SectionName + // Title displayed in header of the setting panel. + public static let SettingsAdvanceAccountTitle = "Advance Account Settings" + + // Settings.AdvanceAccount.UrlPlaceholder + // Title displayed in header of the setting panel. + public static let SettingsAdvanceAccountUrlPlaceholder = "Custom Account Url" + + // Settings.AdvanceAccount.UpdatedAlertMessage + // Messaged displayed when sync service has been successfully set. + public static let SettingsAdvanceAccountUrlUpdatedAlertMessage = "Firefox account service updated. To begin using custom server, please log out and re-login." + + // Settings.AdvanceAccount.UpdatedAlertOk + // Ok button on custom sync service updated alert + public static let SettingsAdvanceAccountUrlUpdatedAlertOk = "OK" + + // Settings.AdvanceAccount.ErrorAlertTitle + // Error alert message title. + public static let SettingsAdvanceAccountUrlErrorAlertTitle = "Error" + + // Settings.AdvanceAccount.ErrorAlertMessage + // Messaged displayed when sync service has an error setting a custom sync url. + public static let SettingsAdvanceAccountUrlErrorAlertMessage = "There was an error while attempting to parse the url. Please make sure that it is a valid Firefox Account root url." + + // Settings.AdvanceAccount.ErrorAlertOk + // Ok button on custom sync service error alert. + public static let SettingsAdvanceAccountUrlErrorAlertOk = "OK" + + // Settings.AdvanceAccount.UseCustomAccountsServiceTitle + // Toggle switch to use custom FxA server + public static let SettingsAdvanceAccountUseCustomAccountsServiceTitle = "Use Custom Account Service" + + // Settings.AdvanceAccount.UrlEmptyErrorAlertMessage + // No custom service set. + public static let SettingsAdvanceAccountEmptyUrlErrorAlertMessage = "Please enter a custom account url before enabling." +} + +// Open With Settings +extension Strings { + public static let SettingsOpenWithSectionName = NSLocalizedString("Settings.OpenWith.SectionName", value: "Mail App", comment: "Label used as an item in Settings. When touched it will open a dialog to configure the open with (mail links) behaviour.") + public static let SettingsOpenWithPageTitle = NSLocalizedString("Settings.OpenWith.PageTitle", value: "Open mail links with", comment: "Title for Open With Settings") +} + +// Third Party Search Engines +extension Strings { + public static let ThirdPartySearchEngineAdded = NSLocalizedString("Search.ThirdPartyEngines.AddSuccess", value: "Added Search engine!", comment: "The success message that appears after a user sucessfully adds a new search engine") + public static let ThirdPartySearchAddTitle = NSLocalizedString("Search.ThirdPartyEngines.AddTitle", value: "Add Search Provider?", comment: "The title that asks the user to Add the search provider") + public static let ThirdPartySearchAddMessage = NSLocalizedString("Search.ThirdPartyEngines.AddMessage", value: "The new search engine will appear in the quick search bar.", comment: "The message that asks the user to Add the search provider explaining where the search engine will appear") + public static let ThirdPartySearchCancelButton = NSLocalizedString("Search.ThirdPartyEngines.Cancel", value: "Cancel", comment: "The cancel button if you do not want to add a search engine.") + public static let ThirdPartySearchOkayButton = NSLocalizedString("Search.ThirdPartyEngines.OK", value: "OK", comment: "The confirmation button") + public static let ThirdPartySearchFailedTitle = NSLocalizedString("Search.ThirdPartyEngines.FailedTitle", value: "Failed", comment: "A title explaining that we failed to add a search engine") + public static let ThirdPartySearchFailedMessage = NSLocalizedString("Search.ThirdPartyEngines.FailedMessage", value: "The search provider could not be added.", comment: "A title explaining that we failed to add a search engine") + public static let CustomEngineFormErrorTitle = NSLocalizedString("Search.ThirdPartyEngines.FormErrorTitle", value: "Failed", comment: "A title stating that we failed to add custom search engine.") + public static let CustomEngineFormErrorMessage = NSLocalizedString("Search.ThirdPartyEngines.FormErrorMessage", value: "Please fill all fields correctly.", comment: "A message explaining fault in custom search engine form.") + public static let CustomEngineDuplicateErrorTitle = NSLocalizedString("Search.ThirdPartyEngines.DuplicateErrorTitle", value: "Failed", comment: "A title stating that we failed to add custom search engine.") + public static let CustomEngineDuplicateErrorMessage = NSLocalizedString("Search.ThirdPartyEngines.DuplicateErrorMessage", value: "A search engine with this title or URL has already been added.", comment: "A message explaining fault in custom search engine form.") +} + +// Bookmark Management +extension Strings { + public static let BookmarksTitle = NSLocalizedString("Bookmarks.Title.Label", value: "Title", comment: "The label for the title of a bookmark") + public static let BookmarksURL = NSLocalizedString("Bookmarks.URL.Label", value: "URL", comment: "The label for the URL of a bookmark") + public static let BookmarksFolder = NSLocalizedString("Bookmarks.Folder.Label", value: "Folder", comment: "The label to show the location of the folder where the bookmark is located") + public static let BookmarksNewFolder = NSLocalizedString("Bookmarks.NewFolder.Label", value: "New Folder", comment: "The button to create a new folder") + public static let BookmarksFolderName = NSLocalizedString("Bookmarks.FolderName.Label", value: "Folder Name", comment: "The label for the title of the new folder") + public static let BookmarksFolderLocation = NSLocalizedString("Bookmarks.FolderLocation.Label", value: "Location", comment: "The label for the location of the new folder") +} + +// Tabs Delete All Undo Toast +extension Strings { + public static let TabsDeleteAllUndoTitle = NSLocalizedString("Tabs.DeleteAllUndo.Title", value: "%d tab(s) closed", comment: "The label indicating that all the tabs were closed") + public static let TabsDeleteAllUndoAction = NSLocalizedString("Tabs.DeleteAllUndo.Button", value: "Undo", comment: "The button to undo the delete all tabs") +} + +//Clipboard Toast +extension Strings { + public static let GoToCopiedLink = NSLocalizedString("ClipboardToast.GoToCopiedLink.Title", value: "Go to copied link?", comment: "Message displayed when the user has a copied link on the clipboard") + public static let GoButtonTittle = NSLocalizedString("ClipboardToast.GoToCopiedLink.Button", value: "Go", comment: "The button to open a new tab with the copied link") + + public static let SettingsOfferClipboardBarTitle = NSLocalizedString("Settings.OfferClipboardBar.Title", value: "Offer to Open Copied Links", comment: "Title of setting to enable the Go to Copied URL feature. See https://bug1223660.bmoattachments.org/attachment.cgi?id=8898349") + public static let SettingsOfferClipboardBarStatus = NSLocalizedString("Settings.OfferClipboardBar.Status", value: "When Opening Firefox", comment: "Description displayed under the ”Offer to Open Copied Link” option. See https://bug1223660.bmoattachments.org/attachment.cgi?id=8898349") +} + +// errors +extension Strings { + public static let UnableToDownloadError = NSLocalizedString("Downloads.Error.Message", value: "Downloads aren’t supported in Firefox yet.", comment: "The message displayed to a user when they try and perform the download of an asset that Firefox cannot currently handle.") + public static let UnableToAddPassErrorTitle = NSLocalizedString("AddPass.Error.Title", value: "Failed to Add Pass", comment: "Title of the 'Add Pass Failed' alert. See https://support.apple.com/HT204003 for context on Wallet.") + public static let UnableToAddPassErrorMessage = NSLocalizedString("AddPass.Error.Message", value: "An error occured while adding the pass to Wallet. Please try again later.", comment: "Text of the 'Add Pass Failed' alert. See https://support.apple.com/HT204003 for context on Wallet.") + public static let UnableToAddPassErrorDismiss = NSLocalizedString("AddPass.Error.Dismiss", value: "OK", comment: "Button to dismiss the 'Add Pass Failed' alert. See https://support.apple.com/HT204003 for context on Wallet.") + public static let UnableToOpenURLError = NSLocalizedString("OpenURL.Error.Message", value: "Firefox cannot open the page because it has an invalid address.", comment: "The message displayed to a user when they try to open a URL that cannot be handled by Firefox, or any external app.") + public static let UnableToOpenURLErrorTitle = NSLocalizedString("OpenURL.Error.Title", value: "Cannot Open Page", comment: "Title of the message shown when the user attempts to navigate to an invalid link.") +} + +// open in +extension Strings { + public static let OpenInDownloadHelperAlertTitle = NSLocalizedString("Downloads.Alert.Title", value: "Firefox Downloads", comment: "The title of the alert box asking the user if they want to use another app to open a file.") + public static let OpenInDownloadHelperAlertMessage = NSLocalizedString("Downloads.Alert.Message", value: "Firefox is unable to download or display this file. Would you like to open it in another app?", comment: "The message of the alert box asking the user if they want to use another app to open a file.") + public static let OpenInDownloadHelperAlertConfirm = NSLocalizedString("Downloads.Alert.Confirm", value: "Yes", comment: "The label of the button the user will press to be presented with a list of other apps to open a file in") + public static let OpenInDownloadHelperAlertCancel = NSLocalizedString("Downloads.Alert.Cancel", value: "No", comment: "The label of the button the user will press to reject the option to open a file in another application") +} + +// Add Custom Search Engine +extension Strings { + public static let SettingsAddCustomEngine = NSLocalizedString("Settings.AddCustomEngine", value: "Add Search Engine", comment: "The button text in Search Settings that opens the Custom Search Engine view.") + public static let SettingsAddCustomEngineTitle = NSLocalizedString("Settings.AddCustomEngine.Title", value: "Add Search Engine", comment: "The title of the Custom Search Engine view.") + public static let SettingsAddCustomEngineTitleLabel = NSLocalizedString("Settings.AddCustomEngine.TitleLabel", value: "Title", comment: "The title for the field which sets the title for a custom search engine.") + public static let SettingsAddCustomEngineURLLabel = NSLocalizedString("Settings.AddCustomEngine.URLLabel", value: "URL", comment: "The title for URL Field") + public static let SettingsAddCustomEngineTitlePlaceholder = NSLocalizedString("Settings.AddCustomEngine.TitlePlaceholder", value: "Search Engine", comment: "The placeholder for Title Field when saving a custom search engine.") + public static let SettingsAddCustomEngineURLPlaceholder = NSLocalizedString("Settings.AddCustomEngine.URLPlaceholder", value: "URL (Replace Query with %s)", comment: "The placeholder for URL Field when saving a custom search engine") + public static let SettingsAddCustomEngineSaveButtonText = NSLocalizedString("Settings.AddCustomEngine.SaveButtonText", value: "Save", comment: "The text on the Save button when saving a custom search engine") +} + +// Context menu ButtonToast instances. +extension Strings { + public static let ContextMenuButtonToastNewTabOpenedLabelText = NSLocalizedString("ContextMenu.ButtonToast.NewTabOpened.LabelText", value: "New Tab opened", comment: "The label text in the Button Toast for switching to a fresh New Tab.") + public static let ContextMenuButtonToastNewTabOpenedButtonText = NSLocalizedString("ContextMenu.ButtonToast.NewTabOpened.ButtonText", value: "Switch", comment: "The button text in the Button Toast for switching to a fresh New Tab.") + public static let ContextMenuButtonToastNewPrivateTabOpenedLabelText = NSLocalizedString("ContextMenu.ButtonToast.NewPrivateTabOpened.LabelText", value: "New Private Tab opened", comment: "The label text in the Button Toast for switching to a fresh New Private Tab.") + public static let ContextMenuButtonToastNewPrivateTabOpenedButtonText = NSLocalizedString("ContextMenu.ButtonToast.NewPrivateTabOpened.ButtonText", value: "Switch", comment: "The button text in the Button Toast for switching to a fresh New Private Tab.") +} + +// Sent tabs notifications. These are displayed when the app is backgrounded or the device is locked. +extension Strings { + // zero tabs + public static let SentTab_NoTabArrivingNotification_title = NSLocalizedString("SentTab.NoTabArrivingNotification.title", value: "Firefox Sync", comment: "Title of notification received after a spurious message from FxA has been received.") + public static let SentTab_NoTabArrivingNotification_body = + NSLocalizedString("SentTab.NoTabArrivingNotification.body", value: "Tap to begin", comment: "Body of notification received after a spurious message from FxA has been received.") + + // one or more tabs + public static let SentTab_TabArrivingNotification_NoDevice_title = NSLocalizedString("SentTab_TabArrivingNotification_NoDevice_title", value: "Tab received", comment: "Title of notification shown when the device is sent one or more tabs from an unnamed device.") + public static let SentTab_TabArrivingNotification_NoDevice_body = NSLocalizedString("SentTab_TabArrivingNotification_NoDevice_body", value: "New tab arrived from another device.", comment: "Body of notification shown when the device is sent one or more tabs from an unnamed device.") + public static let SentTab_TabArrivingNotification_WithDevice_title = NSLocalizedString("SentTab_TabArrivingNotification_WithDevice_title", value: "Tab received from %@", comment: "Title of notification shown when the device is sent one or more tabs from the named device. %@ is the placeholder for the device name. This device name will be localized by that device.") + public static let SentTab_TabArrivingNotification_WithDevice_body = NSLocalizedString("SentTab_TabArrivingNotification_WithDevice_body", value: "New tab arrived in %@", comment: "Body of notification shown when the device is sent one or more tabs from the named device. %@ is the placeholder for the app name.") +} + +// Additional messages sent via Push from FxA +extension Strings { + public static let FxAPush_DeviceDisconnected_ThisDevice_title = NSLocalizedString("FxAPush_DeviceDisconnected_ThisDevice_title", value: "Sync Disconnected", comment: "Title of a notification displayed when this device has been disconnected by another device.") + public static let FxAPush_DeviceDisconnected_ThisDevice_body = NSLocalizedString("FxAPush_DeviceDisconnected_ThisDevice_body", value: "This device has been successfully disconnected from Firefox Sync.", comment: "Body of a notification displayed when this device has been disconnected from FxA by another device.") + public static let FxAPush_DeviceDisconnected_title = NSLocalizedString("FxAPush_DeviceDisconnected_title", value: "Sync Disconnected", comment: "Title of a notification displayed when named device has been disconnected from FxA.") + public static let FxAPush_DeviceDisconnected_body = NSLocalizedString("FxAPush_DeviceDisconnected_body", value: "%@ has been successfully disconnected.", comment: "Body of a notification displayed when named device has been disconnected from FxA. %@ refers to the name of the disconnected device.") + + public static let FxAPush_DeviceDisconnected_UnknownDevice_body = NSLocalizedString("FxAPush_DeviceDisconnected_UnknownDevice_body", value: "A device has disconnected from Firefox Sync", comment: "Body of a notification displayed when unnamed device has been disconnected from FxA.") + + public static let FxAPush_DeviceConnected_title = NSLocalizedString("FxAPush_DeviceConnected_title", value: "Sync Connected", comment: "Title of a notification displayed when another device has connected to FxA.") + public static let FxAPush_DeviceConnected_body = NSLocalizedString("FxAPush_DeviceConnected_body", value: "Firefox Sync has connected to %@", comment: "Title of a notification displayed when another device has connected to FxA. %@ refers to the name of the newly connected device.") +} + +// Reader Mode. +extension Strings { + public static let ReaderModeAvailableVoiceOverAnnouncement = NSLocalizedString("ReaderMode.Available.VoiceOverAnnouncement", value: "Reader Mode available", comment: "Accessibility message e.g. spoken by VoiceOver when Reader Mode becomes available.") + public static let ReaderModeResetFontSizeAccessibilityLabel = NSLocalizedString("Reset text size", comment: "Accessibility label for button resetting font size in display settings of reader mode") +} + +// QR Code scanner. +extension Strings { + public static let ScanQRCodeViewTitle = NSLocalizedString("ScanQRCode.View.Title", value: "Scan QR Code", comment: "Title for the QR code scanner view.") + public static let ScanQRCodeInstructionsLabel = NSLocalizedString("ScanQRCode.Instructions.Label", value: "Align QR code within frame to scan", comment: "Text for the instructions label, displayed in the QR scanner view") + public static let ScanQRCodeInvalidDataErrorMessage = NSLocalizedString("ScanQRCode.InvalidDataError.Message", value: "The data is invalid", comment: "Text of the prompt user the data is invalid") + public static let ScanQRCodePermissionErrorMessage = NSLocalizedString("ScanQRCode.PermissionError.Message", value: "Please allow Firefox to access your device’s camera in ‘Settings’ -> ‘Privacy’ -> ‘Camera’.", comment: "Text of the prompt user to setup the camera authorization.") + public static let ScanQRCodeErrorOKButton = NSLocalizedString("ScanQRCode.Error.OK.Button", value: "OK", comment: "OK button to dismiss the error prompt.") +} + +// App menu. +extension Strings { + public static let AppMenuAddToReadingListTitleString = NSLocalizedString("Menu.AddToReadingList.Title", tableName: "Menu", value: "Add to Reading List", comment: "Label for the button, displayed in the menu, used to add a page to the reading list.") + public static let AppMenuShowTabsTitleString = NSLocalizedString("Menu.ShowTabs.Title", tableName: "Menu", value: "Show Tabs", comment: "Label for the button, displayed in the menu, used to open the tabs tray") + public static let AppMenuSharePageTitleString = NSLocalizedString("Menu.SharePageAction.Title", tableName: "Menu", value: "Share Page With…", comment: "Label for the button, displayed in the menu, used to open the share dialog.") + public static let AppMenuCopyURLTitleString = NSLocalizedString("Menu.CopyURL.Title", tableName: "Menu", value: "Copy URL", comment: "Label for the button, displayed in the menu, used to copy the page url to the clipboard.") + public static let AppMenuNewTabTitleString = NSLocalizedString("Menu.NewTabAction.Title", tableName: "Menu", value: "Open New Tab", comment: "Label for the button, displayed in the menu, used to open a new tab") + public static let AppMenuNewPrivateTabTitleString = NSLocalizedString("Menu.NewPrivateTabAction.Title", tableName: "Menu", value: "Open New Private Tab", comment: "Label for the button, displayed in the menu, used to open a new private tab.") + public static let AppMenuAddBookmarkTitleString = NSLocalizedString("Menu.AddBookmarkAction.Title", tableName: "Menu", value: "Bookmark This Page", comment: "Label for the button, displayed in the menu, used to create a bookmark for the current website.") + public static let AppMenuRemoveBookmarkTitleString = NSLocalizedString("Menu.RemoveBookmarkAction.Title", tableName: "Menu", value: "Remove Bookmark", comment: "Label for the button, displayed in the menu, used to delete an existing bookmark for the current website.") + public static let AppMenuFindInPageTitleString = NSLocalizedString("Menu.FindInPageAction.Title", tableName: "Menu", value: "Find in Page", comment: "Label for the button, displayed in the menu, used to open the toolbar to search for text within the current page.") + public static let AppMenuViewDesktopSiteTitleString = NSLocalizedString("Menu.ViewDekstopSiteAction.Title", tableName: "Menu", value: "Request Desktop Site", comment: "Label for the button, displayed in the menu, used to request the desktop version of the current website.") + public static let AppMenuViewMobileSiteTitleString = NSLocalizedString("Menu.ViewMobileSiteAction.Title", tableName: "Menu", value: "Request Mobile Site", comment: "Label for the button, displayed in the menu, used to request the mobile version of the current website.") + public static let AppMenuScanQRCodeTitleString = NSLocalizedString("Menu.ScanQRCodeAction.Title", tableName: "Menu", value: "Scan QR Code", comment: "Label for the button, displayed in the menu, used to open the QR code scanner.") + public static let AppMenuSettingsTitleString = NSLocalizedString("Menu.OpenSettingsAction.Title", tableName: "Menu", value: "Settings", comment: "Label for the button, displayed in the menu, used to open the Settings menu.") + public static let AppMenuCloseAllTabsTitleString = NSLocalizedString("Menu.CloseAllTabsAction.Title", tableName: "Menu", value: "Close All Tabs", comment: "Label for the button, displayed in the menu, used to close all tabs currently open.") + public static let AppMenuOpenHomePageTitleString = NSLocalizedString("Menu.OpenHomePageAction.Title", tableName: "Menu", value: "Open Homepage", comment: "Label for the button, displayed in the menu, used to navigate to the home page.") + public static let AppMenuTopSitesTitleString = NSLocalizedString("Menu.OpenTopSitesAction.AccessibilityLabel", tableName: "Menu", value: "Top Sites", comment: "Accessibility label for the button, displayed in the menu, used to open the Top Sites home panel.") + public static let AppMenuBookmarksTitleString = NSLocalizedString("Menu.OpenBookmarksAction.AccessibilityLabel", tableName: "Menu", value: "Bookmarks", comment: "Accessibility label for the button, displayed in the menu, used to open the Bbookmarks home panel.") + public static let AppMenuHistoryTitleString = NSLocalizedString("Menu.OpenHistoryAction.AccessibilityLabel", tableName: "Menu", value: "History", comment: "Accessibility label for the button, displayed in the menu, used to open the History home panel.") + public static let AppMenuReadingListTitleString = NSLocalizedString("Menu.OpenReadingListAction.AccessibilityLabel", tableName: "Menu", value: "Reading List", comment: "Accessibility label for the button, displayed in the menu, used to open the Reading list home panel.") + public static let AppMenuButtonAccessibilityLabel = NSLocalizedString("Toolbar.Menu.AccessibilityLabel", value: "Menu", comment: "Accessibility label for the Menu button.") + public static let TabTrayDeleteMenuButtonAccessibilityLabel = NSLocalizedString("Toolbar.Menu.CloseAllTabs", value: "Close All Tabs", comment: "Accessibility label for the Close All Tabs menu button.") + public static let AppMenuNightModeEnable = NSLocalizedString("Menu.NightModeTurnOn.Label", value: "Enable Night Mode", comment: "Label for the button, displayed in the menu, turns on night mode.") + public static let AppMenuNightModeDisable = NSLocalizedString("Menu.NightModeTurnOff.Label", value: "Disable Night Mode", comment: "Label for the button, displayed in the menu, turns off night mode") + public static let AppMenuNoImageModeEnable = NSLocalizedString("Menu.NoImageModeHideImages.Label", value: "Hide Images", comment: "Label for the button, displayed in the menu, hides images on the webpage when pressed.") + public static let AppMenuNoImageModeDisable = NSLocalizedString("Menu.NoImageModeShowImages.Label", value: "Show Images", comment: "Label for the button, displayed in the menu, shows images on the webpage when pressed") + public static let AppMenuCopyURLConfirmMessage = NSLocalizedString("Menu.CopyURL.Confirm", value: "URL Copied To Clipboard", comment: "Toast displayed to user after copy url pressed.") + public static let AppMenuAddBookmarkConfirmMessage = NSLocalizedString("Menu.AddBookmark.Confirm", value: "Bookmark Added", comment: "Toast displayed to the user after a bookmark has been added.") + public static let AppMenuRemoveBookmarkConfirmMessage = NSLocalizedString("Menu.RemoveBookmark.Confirm", value: "Bookmark Removed", comment: "Toast displayed to the user after a bookmark has been removed.") + public static let AppMenuAddToReadingListConfirmMessage = NSLocalizedString("Menu.AddToReadingList.Confirm", value: "Added To Reading List", comment: "Toast displayed to the user after adding the item to their reading list.") + public static let SendToDeviceTitle = NSLocalizedString("Send to Device", tableName: "3DTouchActions", comment: "Label for preview action on Tab Tray Tab to send the current tab to another device") +} + +// Snackbar shown when tapping app store link +extension Strings { + public static let ExternalLinkAppStoreConfirmationTitle = NSLocalizedString("ExternalLink.AppStore.ConfirmationTitle", value: "Open this link in the App Store app?", comment: "Question shown to user when tapping a link that opens the App Store app") +} + +// ContentBlocker/TrackingProtection strings +extension Strings { + public static let SettingsTrackingProtectionSectionName = NSLocalizedString("Settings.TrackingProtection.SectionName", value: "Tracking Protection", comment: "Row in top-level of settings that gets tapped to show the tracking protection settings detail view.") + + public static let TrackingProtectionOptionAlwaysOn = NSLocalizedString("Settings.TrackingProtectionOption.OnLabel", value: "Always On", comment: "Settings option to specify that Tracking Protection is always on.") + public static let TrackingProtectionOptionAlwaysOff = NSLocalizedString("Settings.TrackingProtectionOption.OffLabel", value: "Never", comment: "Settings option to specify that Tracking Protection is always off.") + public static let TrackingProtectionOptionOnInPrivateBrowsing = NSLocalizedString("Settings.TrackingProtectionOption.OnInPrivateBrowsingLabel", value: "Private Browsing Mode Only", comment: "Settings option to specify that Tracking Protection is on only in Private Browsing mode.") + + public static let TrackingProtectionOptionOnOffHeader = NSLocalizedString("Settings.TrackingProtectionOption.EnabledStateHeaderLabel", value: "Use Tracking Protection to Block Known Trackers", comment: "Description label shown at the top of tracking protection options screen.") + public static let TrackingProtectionOptionOnOffFooter = NSLocalizedString("Settings.TrackingProtectionOption.EnabledStateFooterLabel", value: "Tracking is the collection of your browsing data across multiple websites. Tracking can be used to build a profile and display content based on your browsing and personal information.", comment: "Description label shown on tracking protection options screen.") + public static let TrackingProtectionOptionBlockListsTitle = NSLocalizedString("Settings.TrackingProtection.BlockListsTitle", value: "Block Lists", comment: "Title for tracking protection options section where Basic/Strict block list can be selected") + public static let TrackingProtectionOptionBlockListsHeader = NSLocalizedString("Settings.TrackingProtection.BlockListsHeader", value: "You can choose which list Firefox will use to block Web elements that may track your browsing activity.", comment: "Header description for tracking protection options section where Basic/Strict block list can be selected") + + public static let TrackingProtectionOptionBlockListTypeBasic = NSLocalizedString("Settings.TrackingProtectionOption.BlockListBasic", value: "Basic (Recommended)", comment: "Tracking protection settings option for using the basic blocklist.") + public static let TrackingProtectionOptionBlockListTypeBasicDescription = NSLocalizedString("Settings.TrackingProtectionOption.BlockListBasicDescription", value: "Allows some trackers so websites function properly.", comment: "Tracking protection settings option description for using the basic blocklist.") + public static let TrackingProtectionOptionBlockListTypeStrict = NSLocalizedString("Settings.TrackingProtectionOption.BlockListStrict", value: "Strict", comment: "Tracking protection settings option for using the strict blocklist.") + public static let TrackingProtectionOptionBlockListTypeStrictDescription = NSLocalizedString("Settings.TrackingProtectionOption.BlockListStrictDescription", value: "Blocks known trackers. Some websites may not function properly.", comment: "Tracking protection settings option description for using the strict blocklist.") +} + +// Settings Home +extension Strings { + public static let SendUsageSettingTitle = NSLocalizedString("Settings.SendUsage.Title", value: "Send Usage Data", comment: "The title for the setting to send usage data.") + public static let SendUsageSettingLink = NSLocalizedString("Settings.SendUsage.Link", value: "Learn More.", comment: "title for a link that explains how mozilla collects telemetry") + public static let SendUsageSettingMessage = NSLocalizedString("Settings.SendUsage.Message", value: "Mozilla strives to only collect what we need to provide and improve Firefox for everyone.", comment: "A short description that explains why mozilla collects usage data.") +} + +// Do not track +extension Strings { + public static let SettingsDoNotTrackTitle = NSLocalizedString("Settings.DNT.Title", value: "Send websites a Do Not Track signal that you don’t want to be tracked", comment: "DNT Settings title") + public static let SettingsDoNotTrackOptionOnWithTP = NSLocalizedString("Settings.DNT.OptionOnWithTP", value: "Only when using Tracking Protection", comment: "DNT Settings option for only turning on when Tracking Protection is also on") + public static let SettingsDoNotTrackOptionAlwaysOn = NSLocalizedString("Settings.DNT.OptionAlwaysOn", value: "Always", comment: "DNT Settings option for always on") +} + +// MARK: Deprecated Strings (to be removed in next version) +private let logOut = NSLocalizedString("Log Out", comment: "Button in settings screen to disconnect from your account") +private let logOutQuestion = NSLocalizedString("Log Out?", comment: "Title of the 'log out firefox account' alert") +private let logOutDestructive = NSLocalizedString("Log Out", comment: "Disconnect button in the 'log out firefox account' alert") diff --git a/mobile/ios/Client/Frontend/UIConstants.swift b/mobile/ios/Client/Frontend/UIConstants.swift new file mode 100644 index 0000000000..4cc806f598 --- /dev/null +++ b/mobile/ios/Client/Frontend/UIConstants.swift @@ -0,0 +1,127 @@ +/* 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/. */ + +import Foundation +import Shared + +// A browser color represents the color of UI in both Private browsing mode and normal mode +struct BrowserColor { + let normalColor: Int + let PBMColor: Int + init(normal: Int, pbm: Int) { + self.normalColor = normal + self.PBMColor = pbm + } + func color(isPBM: Bool) -> UIColor { + return UIColor(rgb: isPBM ? PBMColor : normalColor) + } +} + +public struct UIConstants { + static let AboutHomePage = URL(string: "\(WebServer.sharedInstance.base)/about/home/")! + + // Photon Colors. Remove old colors once we've completly transitioned + static let BrowserUI = BrowserColor(normal: 0xf9f9fa, pbm: 0x38383D) + static let TextColor = BrowserColor(normal: 0xffffff, pbm: 0x414146) + static let URLBarDivider = BrowserColor(normal: 0xE4E4E4, pbm: 0x414146) + static let TabTrayBG = UIColor(rgb: 0x272727) + static let locationBarBG = UIColor(rgb: 0xD7D7DB) + static let LoadingStartColor = BrowserColor(normal: 0x00DCFC, pbm: 0x9400ff) + static let LoadingEndColor = BrowserColor(normal: 0x0A84FF, pbm: 0xff1ad9) + + //Photon UI sizes + static let TopToolbarHeight: CGFloat = 56 + // The loading bar starts with one color and then animates to the second one + static let LoadingBarStart = BrowserColor(normal: 0x00DCFC, pbm: 0x9f00ff) + static let LoadingBarEnd = BrowserColor(normal: 0x0A84FF, pbm: 0xff1ad9) + + static let TextSelectionBG = UIColor(rgb: 0xE4E4E4) + + static let TopTabsBG = TabTrayBG + + static let AppBackgroundColor = UIColor(rgb: 0xf9f9fa) + static let SystemBlueColor = UIColor(rgb: 0x0297F8) + static let PrivateModePurple = UIColor(red: 207 / 255, green: 104 / 255, blue: 255 / 255, alpha: 1) + static let PrivateModeLocationBackgroundColor = UIColor(red: 31 / 255, green: 31 / 255, blue: 31 / 255, alpha: 1) + static let PrivateModeLocationBorderColor = UIColor(red: 255, green: 255, blue: 255, alpha: 0.15) + static let PrivateModeActionButtonTintColor = UIColor(red: 255, green: 255, blue: 255, alpha: 0.8) + static let PrivateModeTextHighlightColor = UIColor(red: 207 / 255, green: 104 / 255, blue: 255 / 255, alpha: 1) + static let PrivateModeInputHighlightColor = UIColor(red: 120 / 255, green: 120 / 255, blue: 165 / 255, alpha: 1) + static let PrivateModeAssistantToolbarBackgroundColor = UIColor(red: 89 / 255, green: 89 / 255, blue: 89 / 255, alpha: 1) + static let PrivateModeToolbarTintColor = UIColor(red: 74 / 255, green: 74 / 255, blue: 74 / 255, alpha: 1) + + static var ToolbarHeight: CGFloat = 46 + static var BottomToolbarHeight: CGFloat { + get { + var bottomInset: CGFloat = 0.0 + if #available(iOS 11, *) { + if let window = UIApplication.shared.keyWindow { + bottomInset = window.safeAreaInsets.bottom + } + } + return ToolbarHeight + bottomInset + } + } + static let DefaultRowHeight: CGFloat = 58 + static let DefaultPadding: CGFloat = 10 + static let SnackbarButtonHeight: CGFloat = 48 + + // Static fonts + static let DefaultChromeSize: CGFloat = 16 + static let DefaultChromeSmallSize: CGFloat = 11 + static let PasscodeEntryFontSize: CGFloat = 36 + static let DefaultChromeFont: UIFont = UIFont.systemFont(ofSize: DefaultChromeSize, weight: UIFontWeightRegular) + static let DefaultChromeBoldFont = UIFont.systemFont(ofSize: DefaultChromeSize, weight: UIFontWeightHeavy) + static let DefaultChromeSmallFontBold = UIFont.boldSystemFont(ofSize: DefaultChromeSmallSize) + static let PasscodeEntryFont = UIFont.systemFont(ofSize: PasscodeEntryFontSize, weight: UIFontWeightBold) + + // These highlight colors are currently only used on Snackbar buttons when they're pressed + static let HighlightColor = UIColor(red: 205/255, green: 223/255, blue: 243/255, alpha: 0.9) + static let HighlightText = UIColor(red: 42/255, green: 121/255, blue: 213/255, alpha: 1.0) + + static let PanelBackgroundColor = UIColor.white + static let SeparatorColor = UIColor(rgb: 0xcccccc) + static let HighlightBlue = UIColor(red: 76/255, green: 158/255, blue: 255/255, alpha: 1) + static let DestructiveRed = UIColor(red: 255/255, green: 64/255, blue: 0/255, alpha: 1.0) + static let BorderColor = UIColor.darkGray + static let BackgroundColor = AppBackgroundColor + + // These colours are used on the Menu + static let MenuToolbarBackgroundColorNormal = AppBackgroundColor + static let MenuToolbarBackgroundColorPrivate = UIColor(red: 74/255, green: 74/255, blue: 74/255, alpha: 1.0) + static let MenuToolbarTintColorNormal = BackgroundColor + static let MenuToolbarTintColorPrivate = UIColor.white + static let MenuBackgroundColorNormal = UIColor(red: 223/255, green: 223/255, blue: 223/255, alpha: 1.0) + static let MenuBackgroundColorPrivate = UIColor(red: 59/255, green: 59/255, blue: 59/255, alpha: 1.0) + static let MenuSelectedItemTintColor = UIColor(red: 0.30, green: 0.62, blue: 1.0, alpha: 1.0) + static let MenuDisabledItemTintColor = UIColor.lightGray + + // settings + static let TableViewHeaderBackgroundColor = AppBackgroundColor + static let TableViewHeaderTextColor = UIColor(rgb: 0x737373) + static let TableViewRowTextColor = UIColor(rgb: 0x0c0c0d) + static let TableViewDisabledRowTextColor = UIColor.lightGray + static let TableViewSeparatorColor = UIColor(rgb: 0xD1D1D4) + static let TableViewHeaderFooterHeight = CGFloat(44) + static let TableViewRowErrorTextColor = UIColor(red: 255/255, green: 0/255, blue: 26/255, alpha: 1.0) + static let TableViewRowWarningTextColor = UIColor(red: 245/255, green: 166/255, blue: 35/255, alpha: 1.0) + static let TableViewRowActionAccessoryColor = UIColor(red: 0.29, green: 0.56, blue: 0.89, alpha: 1.0) + static let TableViewRowSyncTextColor = UIColor(red: 51/255, green: 51/255, blue: 51/255, alpha: 1.0) + + // Firefox Orange + static let ControlTintColor = SystemBlueColor + + // List of Default colors to use for Favicon backgrounds + static let DefaultColorStrings = ["2e761a", "399320", "40a624", "57bd35", "70cf5b", "90e07f", "b1eea5", "881606", "aa1b08", "c21f09", "d92215", "ee4b36", "f67964", "ffa792", "025295", "0568ba", "0675d3", "0996f8", "2ea3ff", "61b4ff", "95cdff", "00736f", "01908b", "01a39d", "01bdad", "27d9d2", "58e7e6", "89f4f5", "c84510", "e35b0f", "f77100", "ff9216", "ffad2e", "ffc446", "ffdf81", "911a2e", "b7223b", "cf2743", "ea385e", "fa526e", "ff7a8d", "ffa7b3" ] + + // Passcode dot gray + static let PasscodeDotColor = UIColor(rgb: 0x4A4A4A) + + /// JPEG compression quality for persisted screenshots. Must be between 0-1. + static let ScreenshotQuality: Float = 0.3 + static let ActiveScreenshotQuality: CGFloat = 0.5 + + static let OKString = NSLocalizedString("OK", comment: "OK button") + static let CancelString = NSLocalizedString("Cancel", comment: "Label for Cancel button") +} diff --git a/mobile/ios/Client/Frontend/Widgets/ActivityStreamHighlightCell.swift b/mobile/ios/Client/Frontend/Widgets/ActivityStreamHighlightCell.swift new file mode 100644 index 0000000000..c42392b13e --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/ActivityStreamHighlightCell.swift @@ -0,0 +1,237 @@ +/* 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/. */ + +import UIKit +import Shared +import Storage + +struct ActivityStreamHighlightCellUX { + static let LabelColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.black : UIColor(rgb: 0x353535) + static let BorderWidth: CGFloat = 0.5 + static let CellSideOffset = 20 + static let TitleLabelOffset = 2 + static let CellTopBottomOffset = 12 + static let SiteImageViewSize: CGSize = UIDevice.current.userInterfaceIdiom == .pad ? CGSize(width: 99, height: 120) : CGSize(width: 99, height: 90) + static let StatusIconSize = 12 + static let FaviconSize = CGSize(width: 45, height: 45) + static let DescriptionLabelColor = UIColor(rgb: 0x919191) + static let SelectedOverlayColor = UIColor(white: 0.0, alpha: 0.25) + static let CornerRadius: CGFloat = 3 + static let BorderColor = UIColor(white: 0, alpha: 0.1) +} + +class ActivityStreamHighlightCell: UICollectionViewCell { + + fileprivate lazy var titleLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.font = DynamicFontHelper.defaultHelper.MediumSizeHeavyWeightAS + titleLabel.textColor = ActivityStreamHighlightCellUX.LabelColor + titleLabel.textAlignment = .left + titleLabel.numberOfLines = 3 + return titleLabel + }() + + fileprivate lazy var descriptionLabel: UILabel = { + let descriptionLabel = UILabel() + descriptionLabel.font = DynamicFontHelper.defaultHelper.SmallSizeRegularWeightAS + descriptionLabel.textColor = ActivityStreamHighlightCellUX.DescriptionLabelColor + descriptionLabel.textAlignment = .left + descriptionLabel.numberOfLines = 1 + return descriptionLabel + }() + + fileprivate lazy var domainLabel: UILabel = { + let descriptionLabel = UILabel() + descriptionLabel.font = DynamicFontHelper.defaultHelper.SmallSizeRegularWeightAS + descriptionLabel.textColor = ActivityStreamHighlightCellUX.DescriptionLabelColor + descriptionLabel.textAlignment = .left + descriptionLabel.numberOfLines = 1 + descriptionLabel.setContentCompressionResistancePriority(1000, for: UILayoutConstraintAxis.vertical) + return descriptionLabel + }() + + lazy var siteImageView: UIImageView = { + let siteImageView = UIImageView() + siteImageView.contentMode = UIViewContentMode.scaleAspectFit + siteImageView.clipsToBounds = true + siteImageView.contentMode = UIViewContentMode.center + siteImageView.layer.cornerRadius = ActivityStreamHighlightCellUX.CornerRadius + siteImageView.layer.borderColor = ActivityStreamHighlightCellUX.BorderColor.cgColor + siteImageView.layer.borderWidth = ActivityStreamHighlightCellUX.BorderWidth + siteImageView.layer.masksToBounds = true + return siteImageView + }() + + fileprivate lazy var statusIcon: UIImageView = { + let statusIcon = UIImageView() + statusIcon.contentMode = UIViewContentMode.scaleAspectFit + statusIcon.clipsToBounds = true + statusIcon.layer.cornerRadius = ActivityStreamHighlightCellUX.CornerRadius + return statusIcon + }() + + fileprivate lazy var selectedOverlay: UIView = { + let selectedOverlay = UIView() + selectedOverlay.backgroundColor = ActivityStreamHighlightCellUX.SelectedOverlayColor + selectedOverlay.isHidden = true + return selectedOverlay + }() + + override var isSelected: Bool { + didSet { + self.selectedOverlay.isHidden = !isSelected + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + layer.shouldRasterize = true + layer.rasterizationScale = UIScreen.main.scale + + isAccessibilityElement = true + + contentView.addSubview(siteImageView) + contentView.addSubview(descriptionLabel) + contentView.addSubview(selectedOverlay) + contentView.addSubview(titleLabel) + contentView.addSubview(statusIcon) + contentView.addSubview(domainLabel) + + siteImageView.snp.makeConstraints { make in + make.top.equalTo(contentView) + make.leading.trailing.equalTo(contentView) + make.centerX.equalTo(contentView) + make.height.equalTo(ActivityStreamHighlightCellUX.SiteImageViewSize) + } + + selectedOverlay.snp.makeConstraints { make in + make.edges.equalTo(contentView) + } + + domainLabel.snp.makeConstraints { make in + make.leading.equalTo(siteImageView) + make.trailing.equalTo(contentView) + make.top.equalTo(siteImageView.snp.bottom).offset(5) + } + + titleLabel.snp.makeConstraints { make in + make.leading.equalTo(siteImageView) + make.trailing.equalTo(contentView) + make.top.equalTo(domainLabel.snp.bottom).offset(5) + } + + descriptionLabel.snp.makeConstraints { make in + make.leading.equalTo(statusIcon.snp.trailing).offset(ActivityStreamHighlightCellUX.TitleLabelOffset) + make.bottom.equalTo(contentView) + } + + statusIcon.snp.makeConstraints { make in + make.size.equalTo(ActivityStreamHighlightCellUX.StatusIconSize) + make.centerY.equalTo(descriptionLabel.snp.centerY) + make.leading.equalTo(siteImageView) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + super.prepareForReuse() + self.siteImageView.image = nil + contentView.backgroundColor = UIColor.clear + siteImageView.backgroundColor = UIColor.clear + } + + func configureWithSite(_ site: Site) { + if let mediaURLStr = site.metadata?.mediaURL, + let mediaURL = URL(string: mediaURLStr) { + self.siteImageView.sd_setImage(with: mediaURL) + self.siteImageView.contentMode = .scaleAspectFill + } else { + let itemURL = site.tileURL + self.siteImageView.setFavicon(forSite: site, onCompletion: { [weak self] (color, url) in + if itemURL == url { + self?.siteImageView.image = self?.siteImageView.image?.createScaled(ActivityStreamHighlightCellUX.FaviconSize) + self?.siteImageView.backgroundColor = color + } + }) + self.siteImageView.contentMode = .center + } + + self.domainLabel.text = site.tileURL.hostSLD + self.titleLabel.text = site.title.characters.count <= 1 ? site.url : site.title + + if let bookmarked = site.bookmarked, bookmarked { + self.descriptionLabel.text = Strings.HighlightBookmarkText + self.statusIcon.image = UIImage(named: "context_bookmark") + } else { + self.descriptionLabel.text = Strings.HighlightVistedText + self.statusIcon.image = UIImage(named: "context_viewed") + } + } + + func configureWithPocketStory(_ pocketStory: PocketStory) { + self.siteImageView.sd_setImage(with: pocketStory.imageURL) + self.siteImageView.contentMode = .scaleAspectFill + + self.domainLabel.text = pocketStory.domain + self.titleLabel.text = pocketStory.title + + self.descriptionLabel.text = Strings.PocketTrendingText + self.statusIcon.image = UIImage(named: "context_pocket") + } +} + +struct HighlightIntroCellUX { + static let margin: CGFloat = 20 + static let foxImageWidth: CGFloat = 168 +} + +class HighlightIntroCell: UICollectionViewCell { + + lazy var titleLabel: UILabel = { + let textLabel = UILabel() + textLabel.font = DynamicFontHelper.defaultHelper.MediumSizeBoldFontAS + textLabel.textColor = UIColor.black + textLabel.numberOfLines = 1 + textLabel.adjustsFontSizeToFitWidth = true + textLabel.minimumScaleFactor = 0.8 + return textLabel + }() + + lazy var descriptionLabel: UILabel = { + let label = UILabel() + label.font = DynamicFontHelper.defaultHelper.MediumSizeRegularWeightAS + label.textColor = UIColor.darkGray + label.numberOfLines = 0 + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + contentView.addSubview(titleLabel) + contentView.addSubview(descriptionLabel) + + titleLabel.text = Strings.HighlightIntroTitle + descriptionLabel.text = Strings.HighlightIntroDescription + + let titleInsets = UIEdgeInsets(top: HighlightIntroCellUX.margin, left: 0, bottom: 0, right: 0) + titleLabel.snp.makeConstraints { make in + make.leading.top.trailing.equalTo(self.contentView).inset(titleInsets) + } + + descriptionLabel.snp.makeConstraints { make in + make.leading.trailing.equalTo(titleLabel) + make.top.equalTo(titleLabel.snp.bottom).offset(HighlightIntroCellUX.margin/2) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/mobile/ios/Client/Frontend/Widgets/AutocompleteTextField.swift b/mobile/ios/Client/Frontend/Widgets/AutocompleteTextField.swift new file mode 100644 index 0000000000..ce6b4b9fd0 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/AutocompleteTextField.swift @@ -0,0 +1,280 @@ +/* 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 code is loosely based on https://github.com/Antol/APAutocompleteTextField + +import UIKit +import Shared + +/// Delegate for the text field events. Since AutocompleteTextField owns the UITextFieldDelegate, +/// callers must use this instead. +protocol AutocompleteTextFieldDelegate: class { + func autocompleteTextField(_ autocompleteTextField: AutocompleteTextField, didEnterText text: String) + func autocompleteTextFieldShouldReturn(_ autocompleteTextField: AutocompleteTextField) -> Bool + func autocompleteTextFieldShouldClear(_ autocompleteTextField: AutocompleteTextField) -> Bool + func autocompleteTextFieldDidBeginEditing(_ autocompleteTextField: AutocompleteTextField) +} + +struct AutocompleteTextFieldUX { + static let HighlightColor = UIColor(rgb: 0xccdded) +} + +class AutocompleteTextField: UITextField, UITextFieldDelegate { + var autocompleteDelegate: AutocompleteTextFieldDelegate? + + // AutocompleteTextLabel repersents the actual autocomplete text. + // The textfields "text" property only contains the entered text, while this label holds the autocomplete text + // This makes sure that the autocomplete doesnt mess with keyboard suggestions provided by third party keyboards. + private var autocompleteTextLabel: UILabel? + private var hideCursor: Bool = false + + var isSelectionActive: Bool { + return autocompleteTextLabel != nil + } + + // This variable is a solution to get the right behavior for refocusing + // the AutocompleteTextField. The initial transition into Overlay Mode + // doesn't involve the user interacting with AutocompleteTextField. + // Thus, we update shouldApplyCompletion in touchesBegin() to reflect whether + // the highlight is active and then the text field is updated accordingly + // in touchesEnd() (eg. applyCompletion() is called or not) + fileprivate var notifyTextChanged: (() -> Void)? + private var lastReplacement: String? + + var highlightColor = AutocompleteTextFieldUX.HighlightColor + + override var text: String? { + didSet { + super.text = text + self.textDidChange(self) + } + } + + override var accessibilityValue: String? { + get { + return (self.text ?? "") + (self.autocompleteTextLabel?.text ?? "") + } + set(value) { + super.accessibilityValue = value + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + commonInit() + } + + fileprivate func commonInit() { + super.delegate = self + super.addTarget(self, action: #selector(AutocompleteTextField.textDidChange(_:)), for: UIControlEvents.editingChanged) + notifyTextChanged = debounce(0.1, action: { + if self.isEditing { + self.autocompleteDelegate?.autocompleteTextField(self, didEnterText: self.normalizeString(self.text ?? "")) + } + }) + } + + override var keyCommands: [UIKeyCommand]? { + return [ + UIKeyCommand(input: UIKeyInputLeftArrow, modifierFlags: .init(rawValue: 0), action: #selector(self.handleKeyCommand(sender:))), + UIKeyCommand(input: UIKeyInputRightArrow, modifierFlags: .init(rawValue: 0), action: #selector(self.handleKeyCommand(sender:))) + ] + } + + func handleKeyCommand(sender: UIKeyCommand) { + switch sender.input { + case UIKeyInputLeftArrow: + if isSelectionActive { + applyCompletion() + + // Set the current position to the beginning of the text. + selectedTextRange = textRange(from: beginningOfDocument, to: beginningOfDocument) + } else if let range = selectedTextRange { + if range.start == beginningOfDocument { + return + } + + guard let cursorPosition = position(from: range.start, offset: -1) else { + return + } + + selectedTextRange = textRange(from: cursorPosition, to: cursorPosition) + } + return + case UIKeyInputRightArrow: + if isSelectionActive { + applyCompletion() + + // Set the current position to the end of the text. + selectedTextRange = textRange(from: endOfDocument, to: endOfDocument) + } else if let range = selectedTextRange { + if range.end == endOfDocument { + return + } + + guard let cursorPosition = position(from: range.end, offset: 1) else { + return + } + + selectedTextRange = textRange(from: cursorPosition, to: cursorPosition) + } + return + default: + return + } + } + + func highlightAll() { + let text = self.text + self.text = "" + setAutocompleteSuggestion(text ?? "") + selectedTextRange = textRange(from: endOfDocument, to: endOfDocument) + } + + fileprivate func normalizeString(_ string: String) -> String { + return string.lowercased().stringByTrimmingLeadingCharactersInSet(CharacterSet.whitespaces) + } + + /// Commits the completion by setting the text and removing the highlight. + fileprivate func applyCompletion() { + + // Clear the current completion, then set the text without the attributed style. + let text = (self.text ?? "") + (self.autocompleteTextLabel?.text ?? "") + removeCompletion() + self.text = text + hideCursor = false + // Move the cursor to the end of the completion. + selectedTextRange = textRange(from: endOfDocument, to: endOfDocument) + } + + /// Removes the autocomplete-highlighted + fileprivate func removeCompletion() { + autocompleteTextLabel?.removeFromSuperview() + autocompleteTextLabel = nil + } + + // `shouldChangeCharactersInRange` is called before the text changes, and textDidChange is called after. + // Since the text has changed, remove the completion here, and textDidChange will fire the callback to + // get the new autocompletion. + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + lastReplacement = string + return true + } + + func setAutocompleteSuggestion(_ suggestion: String?) { + let text = self.text ?? "" + + guard let suggestion = suggestion, isEditing && markedTextRange == nil else { + hideCursor = false + return + } + + let normalized = normalizeString(text) + guard suggestion.startsWith(normalized) && normalized.characters.count < suggestion.characters.count else { + hideCursor = false + return + } + + let suggestionText = suggestion.substring(from: suggestion.characters.index(suggestion.startIndex, offsetBy: normalized.characters.count)) + let autocompleteText = NSMutableAttributedString(string: suggestionText) + autocompleteText.addAttribute(NSBackgroundColorAttributeName, value: highlightColor, range: NSRange(location: 0, length: suggestionText.characters.count)) + autocompleteTextLabel?.removeFromSuperview() // should be nil. But just in case + autocompleteTextLabel = createAutocompleteLabelWith(autocompleteText) + if let l = autocompleteTextLabel { + addSubview(l) + hideCursor = true + forceResetCursor() + } + } + + override func caretRect(for position: UITextPosition) -> CGRect { + return hideCursor ? CGRect.zero : super.caretRect(for: position) + } + + private func createAutocompleteLabelWith(_ autocompleteText: NSAttributedString) -> UILabel { + let label = UILabel() + var frame = self.bounds + label.attributedText = autocompleteText + label.font = self.font + label.accessibilityIdentifier = "autocomplete" + label.backgroundColor = self.backgroundColor + label.textColor = self.textColor + + let enteredTextSize = self.attributedText?.boundingRect(with: self.frame.size, options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil) + frame.origin.x = (enteredTextSize?.width.rounded() ?? 0) + frame.size.width = self.frame.size.width - frame.origin.x + frame.size.height = self.frame.size.height - 1 + label.frame = frame + return label + } + + func textFieldDidBeginEditing(_ textField: UITextField) { + autocompleteDelegate?.autocompleteTextFieldDidBeginEditing(self) + } + + func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { + applyCompletion() + return true + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + applyCompletion() + return autocompleteDelegate?.autocompleteTextFieldShouldReturn(self) ?? true + } + + func textFieldShouldClear(_ textField: UITextField) -> Bool { + removeCompletion() + return autocompleteDelegate?.autocompleteTextFieldShouldClear(self) ?? true + } + + override func setMarkedText(_ markedText: String?, selectedRange: NSRange) { + // Clear the autocompletion if any provisionally inserted text has been + // entered (e.g., a partial composition from a Japanese keyboard). + removeCompletion() + super.setMarkedText(markedText, selectedRange: selectedRange) + } + + func textDidChange(_ textField: UITextField) { + hideCursor = autocompleteTextLabel != nil + removeCompletion() + + let isAtEnd = selectedTextRange?.start == endOfDocument + let isEmpty = lastReplacement?.isEmpty ?? true + if !isEmpty, isAtEnd, markedTextRange == nil { + notifyTextChanged?() + } else { + hideCursor = false + } + } + + // Reset the cursor to the end of the text field. + // This forces `caretRect(for position: UITextPosition)` to be called which will decide if we should show the cursor + // This exists because ` caretRect(for position: UITextPosition)` is not called after we apply an autocompletion. + private func forceResetCursor() { + selectedTextRange = nil + selectedTextRange = textRange(from: endOfDocument, to: endOfDocument) + } + + override func deleteBackward() { + lastReplacement = nil + hideCursor = false + if isSelectionActive { + removeCompletion() + forceResetCursor() + } else { + super.deleteBackward() + } + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + applyCompletion() + super.touchesBegan(touches, with: event) + } + +} diff --git a/mobile/ios/Client/Frontend/Widgets/ChevronView.swift b/mobile/ios/Client/Frontend/Widgets/ChevronView.swift new file mode 100644 index 0000000000..6892073159 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/ChevronView.swift @@ -0,0 +1,123 @@ +/* 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/. */ + +import Foundation + +enum ChevronDirection { + case left + case up + case right + case down +} + +enum ChevronStyle { + case angular + case rounded +} + +class ChevronView: UIView { + fileprivate let Padding: CGFloat = 2.5 + fileprivate var direction = ChevronDirection.right + fileprivate var lineCapStyle = CGLineCap.round + fileprivate var lineJoinStyle = CGLineJoin.round + + var lineWidth: CGFloat = 3.0 + + var style: ChevronStyle = .rounded { + didSet { + switch style { + case .rounded: + lineCapStyle = CGLineCap.round + lineJoinStyle = CGLineJoin.round + case .angular: + lineCapStyle = CGLineCap.butt + lineJoinStyle = CGLineJoin.miter + + } + } + } + + init(direction: ChevronDirection) { + super.init(frame: CGRect.zero) + + self.direction = direction + if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft { + if direction == .left { + self.direction = .right + } else if direction == .right { + self.direction = .left + } + } + self.backgroundColor = UIColor.clear + self.contentMode = UIViewContentMode.redraw + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ rect: CGRect) { + super.draw(rect) + + let strokeLength = (rect.size.height / 2) - Padding + + let path: UIBezierPath + + switch direction { + case .left: + path = drawLeftChevronAt(CGPoint(x: rect.size.width - (strokeLength + Padding), y: strokeLength + Padding), strokeLength: strokeLength) + case .up: + path = drawUpChevronAt(CGPoint(x: (rect.size.width - Padding) - strokeLength, y: (strokeLength / 2) + Padding), strokeLength: strokeLength) + case .right: + path = drawRightChevronAt(CGPoint(x: rect.size.width - Padding, y: strokeLength + Padding), strokeLength: strokeLength) + case .down: + path = drawDownChevronAt(CGPoint(x: (rect.size.width - Padding) - strokeLength, y: (strokeLength * 1.5) + Padding), strokeLength: strokeLength) + } + + tintColor.set() + + // The line thickness needs to be proportional to the distance from the arrow head to the tips. Making it half seems about right. + path.lineCapStyle = lineCapStyle + path.lineJoinStyle = lineJoinStyle + path.lineWidth = lineWidth + path.stroke() + } + + fileprivate func drawUpChevronAt(_ origin: CGPoint, strokeLength: CGFloat) -> UIBezierPath { + return drawChevron(CGPoint(x: origin.x-strokeLength, y: origin.y+strokeLength), + head: CGPoint(x: origin.x, y: origin.y), + rightTip: CGPoint(x: origin.x+strokeLength, y: origin.y+strokeLength)) + } + + fileprivate func drawDownChevronAt(_ origin: CGPoint, strokeLength: CGFloat) -> UIBezierPath { + return drawChevron(CGPoint(x: origin.x-strokeLength, y: origin.y-strokeLength), + head: CGPoint(x: origin.x, y: origin.y), + rightTip: CGPoint(x: origin.x+strokeLength, y: origin.y-strokeLength)) + } + + fileprivate func drawLeftChevronAt(_ origin: CGPoint, strokeLength: CGFloat) -> UIBezierPath { + return drawChevron(CGPoint(x: origin.x+strokeLength, y: origin.y-strokeLength), + head: CGPoint(x: origin.x, y: origin.y), + rightTip: CGPoint(x: origin.x+strokeLength, y: origin.y+strokeLength)) + } + + fileprivate func drawRightChevronAt(_ origin: CGPoint, strokeLength: CGFloat) -> UIBezierPath { + return drawChevron(CGPoint(x: origin.x-strokeLength, y: origin.y+strokeLength), + head: CGPoint(x: origin.x, y: origin.y), + rightTip: CGPoint(x: origin.x-strokeLength, y: origin.y-strokeLength)) + } + + fileprivate func drawChevron(_ leftTip: CGPoint, head: CGPoint, rightTip: CGPoint) -> UIBezierPath { + let path = UIBezierPath() + + // Left tip + path.move(to: leftTip) + // Arrow head + path.addLine(to: head) + // Right tip + path.addLine(to: rightTip) + + return path + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/ErrorToast.swift b/mobile/ios/Client/Frontend/Widgets/ErrorToast.swift new file mode 100644 index 0000000000..e3808aa216 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/ErrorToast.swift @@ -0,0 +1,55 @@ +/* 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/. */ + +import Foundation +import SnapKit + +private struct ErrorToastDefaultUX { + static let cornerRadius: CGFloat = 40 + static let fillColor = UIColor(red: 186/255, green: 32/255, blue: 36/255, alpha: 1) + static let margins = UIEdgeInsets(top: 10, left: 12, bottom: 10, right: 12) + static let textColor = UIColor.white +} + +class ErrorToast: UIView { + lazy var textLabel: UILabel = { + let label = UILabel() + label.textColor = ErrorToastDefaultUX.textColor + label.textAlignment = .center + label.numberOfLines = 0 + return label + }() + + var cornerRadius: CGFloat = ErrorToastDefaultUX.cornerRadius { + didSet { + setNeedsDisplay() + } + } + + var fillColor: UIColor = ErrorToastDefaultUX.fillColor { + didSet { + setNeedsDisplay() + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + isOpaque = false + addSubview(textLabel) + textLabel.snp.makeConstraints { make in + make.edges.equalTo(self).inset(ErrorToastDefaultUX.margins) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ rect: CGRect) { + super.draw(rect) + fillColor.setFill() + let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius) + path.fill() + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/GradientProgressBar.swift b/mobile/ios/Client/Frontend/Widgets/GradientProgressBar.swift new file mode 100644 index 0000000000..1f9cbe432f --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/GradientProgressBar.swift @@ -0,0 +1,187 @@ +/* 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/. */ + +// ADAPTED FROM: +// +// GradientProgressBar.swift +// GradientProgressBar +// +// Created by Felix Mau on 01.03.17. +// Copyright © 2017 Felix Mau. All rights reserved. +// + +import Foundation +import UIKit + +open class GradientProgressBar: UIProgressView { + + private struct DefaultValues { + static let backgroundColor = UIColor.clear + static let animationDuration = 0.2 // CALayer default animation duration + } + + var gradientColors: [CGColor] = [] + // Alpha mask for visible part of gradient. + private var alphaMaskLayer: CALayer = CALayer() + + // Gradient layer. + open var gradientLayer: CAGradientLayer = CAGradientLayer() + + // Duration for "setProgress(animated: true)" + open var animationDuration = DefaultValues.animationDuration + + // Workaround to handle orientation change, as "layoutSubviews()" gets triggered each time + // the progress value is changed. + override open var bounds: CGRect { + didSet { + updateAlphaMaskLayerWidth() + } + } + + // Update layer mask on direct changes to progress value. + override open var progress: Float { + didSet { + updateAlphaMaskLayerWidth() + } + } + + func setGradientColors(startColor: UIColor, endColor: UIColor) { + gradientColors = [startColor, endColor, startColor, endColor, startColor, endColor, startColor].map { $0.cgColor } + gradientLayer.colors = gradientColors + } + + func commonInit() { + setupProgressViewColors() + setupAlphaMaskLayer() + setupGradientLayer() + + layer.insertSublayer(gradientLayer, at: 0) + updateAlphaMaskLayerWidth() + } + + override public init(frame: CGRect) { + gradientColors = [] + super.init(frame: frame) + commonInit() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + commonInit() + } + + // MARK: - Setup UIProgressView + + private func setupProgressViewColors() { + backgroundColor = DefaultValues.backgroundColor + trackTintColor = .clear + progressTintColor = .clear + } + + // MARK: - Setup layers + + private func setupAlphaMaskLayer() { + alphaMaskLayer.frame = bounds + alphaMaskLayer.cornerRadius = 3 + + alphaMaskLayer.anchorPoint = CGPoint(x: 0, y: 0) + alphaMaskLayer.position = CGPoint(x: 0, y: 0) + + alphaMaskLayer.backgroundColor = UIColor.white.cgColor + } + + private func setupGradientLayer() { + // Apply "alphaMaskLayer" as a mask to the gradient layer in order to show only parts of the current "progress" + gradientLayer.mask = alphaMaskLayer + + gradientLayer.frame = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width * 2, height: bounds.size.height) + gradientLayer.colors = gradientColors + gradientLayer.locations = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.0] + gradientLayer.startPoint = CGPoint(x: 0, y: 0) + gradientLayer.endPoint = CGPoint(x: 1, y: 0) + gradientLayer.drawsAsynchronously = true + } + + func hideProgressBar() { + guard progress == 1 else { + return + } + + CATransaction.begin() + let moveAnimation = CABasicAnimation(keyPath: "position") + moveAnimation.duration = DefaultValues.animationDuration + moveAnimation.fromValue = gradientLayer.position + moveAnimation.toValue = CGPoint(x: gradientLayer.frame.width, y: gradientLayer.position.y) + moveAnimation.fillMode = kCAFillModeForwards + moveAnimation.isRemovedOnCompletion = false + + CATransaction.setCompletionBlock { + self.resetProgressBar() + } + + gradientLayer.add(moveAnimation, forKey: "position") + + CATransaction.commit() + } + + func resetProgressBar() { + // Call on super instead so no animation layers are created + super.setProgress(0, animated: false) + isHidden = true // The URLBar will unhide the view before starting the next animation. + } + + override open func layoutSubviews() { + super.layoutSubviews() + self.gradientLayer.frame = CGRect(x: bounds.origin.x - 4, y: bounds.origin.y, width: bounds.size.width * 2, height: bounds.size.height) + } + + func animateGradient() { + let gradientChangeAnimation = CABasicAnimation(keyPath: "locations") + gradientChangeAnimation.duration = DefaultValues.animationDuration * 4 + gradientChangeAnimation.toValue = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.0] + gradientChangeAnimation.fromValue = [0.0, 0.0, 0.0, 0.2, 0.4, 0.6, 0.8] + gradientChangeAnimation.fillMode = kCAFillModeForwards + gradientChangeAnimation.isRemovedOnCompletion = false + gradientChangeAnimation.repeatCount = .infinity + gradientLayer.add(gradientChangeAnimation, forKey: "colorChange") + } + + // MARK: - Update gradient + + open func updateAlphaMaskLayerWidth(animated: Bool = false) { + CATransaction.begin() + // Workaround for non animated progress change + // Source: https://stackoverflow.com/a/16381287/3532505 + CATransaction.setAnimationDuration(animated ? DefaultValues.animationDuration : 0.0) + alphaMaskLayer.frame = bounds.updateWidth(byPercentage: CGFloat(progress)) + if progress == 1 { + // Delay calling hide until the last animation has completed + CATransaction.setCompletionBlock({ + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DefaultValues.animationDuration, execute: { + self.hideProgressBar() + }) + }) + } + CATransaction.commit() + } + + override open func setProgress(_ progress: Float, animated: Bool) { + if progress < self.progress && self.progress != 1 { + return + } + // Setup animations + gradientLayer.removeAnimation(forKey: "position") + if gradientLayer.animation(forKey: "colorChange") == nil { + animateGradient() + } + super.setProgress(progress, animated: animated) + updateAlphaMaskLayerWidth(animated: animated) + } +} + +extension CGRect { + func updateWidth(byPercentage percentage: CGFloat) -> CGRect { + return CGRect(x: origin.x, y: origin.y, width: size.width * percentage, height: size.height) + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/HistoryBackButton.swift b/mobile/ios/Client/Frontend/Widgets/HistoryBackButton.swift new file mode 100644 index 0000000000..867c0bf320 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/HistoryBackButton.swift @@ -0,0 +1,70 @@ +/* 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/. */ + +import SnapKit +import Shared + +private struct HistoryBackButtonUX { + static let HistoryHistoryBackButtonHeaderChevronInset: CGFloat = 10 + static let HistoryHistoryBackButtonHeaderChevronSize: CGFloat = 20 + static let HistoryHistoryBackButtonHeaderChevronLineWidth: CGFloat = 3.0 +} + +class HistoryBackButton: UIButton { + lazy var title: UILabel = { + let label = UILabel() + label.textColor = UIConstants.HighlightBlue + label.text = Strings.HistoryBackButtonTitle + return label + }() + + lazy var chevron: ChevronView = { + let chevron = ChevronView(direction: .left) + chevron.tintColor = UIConstants.HighlightBlue + chevron.lineWidth = HistoryBackButtonUX.HistoryHistoryBackButtonHeaderChevronLineWidth + return chevron + }() + + lazy var topBorder: UIView = self.createBorderView() + lazy var bottomBorder: UIView = self.createBorderView() + + override init(frame: CGRect) { + super.init(frame: frame) + isUserInteractionEnabled = true + + addSubview(topBorder) + addSubview(chevron) + addSubview(title) + + backgroundColor = UIColor.white + + chevron.snp.makeConstraints { make in + make.leading.equalTo(self).offset(HistoryBackButtonUX.HistoryHistoryBackButtonHeaderChevronInset) + make.centerY.equalTo(self) + make.size.equalTo(HistoryBackButtonUX.HistoryHistoryBackButtonHeaderChevronSize) + } + + title.snp.makeConstraints { make in + make.leading.equalTo(chevron.snp.trailing).offset(HistoryBackButtonUX.HistoryHistoryBackButtonHeaderChevronInset) + make.trailing.greaterThanOrEqualTo(self).offset(-HistoryBackButtonUX.HistoryHistoryBackButtonHeaderChevronInset) + make.centerY.equalTo(self) + } + + topBorder.snp.makeConstraints { make in + make.leading.trailing.equalTo(self) + make.top.equalTo(self).offset(-0.5) + make.height.equalTo(0.5) + } + } + + fileprivate func createBorderView() -> UIView { + let view = UIView() + view.backgroundColor = SiteTableViewControllerUX.HeaderBorderColor + return view + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/InnerStrokedView.swift b/mobile/ios/Client/Frontend/Widgets/InnerStrokedView.swift new file mode 100644 index 0000000000..aeb88b51ed --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/InnerStrokedView.swift @@ -0,0 +1,49 @@ +/* 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/. */ + +import UIKit + +/// A transparent view with a rectangular border with rounded corners, stroked +/// with a semi-transparent white border. +class InnerStrokedView: UIView { + var color = UIColor.white.withAlphaComponent(0.2) { + didSet { + setNeedsDisplay() + } + } + + var strokeWidth: CGFloat = 1.0 { + didSet { + setNeedsDisplay() + } + } + + var cornerRadius: CGFloat = 4 { + didSet { + setNeedsDisplay() + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = UIColor.clear + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ rect: CGRect) { + let halfWidth = strokeWidth / 2 as CGFloat + + let path = UIBezierPath(roundedRect: CGRect(x: halfWidth, + y: halfWidth, + width: rect.width - strokeWidth, + height: rect.height - strokeWidth), + cornerRadius: cornerRadius) + color.setStroke() + path.lineWidth = strokeWidth + path.stroke() + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/InsetButton.swift b/mobile/ios/Client/Frontend/Widgets/InsetButton.swift new file mode 100644 index 0000000000..a567c92ebc --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/InsetButton.swift @@ -0,0 +1,14 @@ +/* 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/. */ + +/** + * Button whose insets are included in its intrinsic size. + */ +class InsetButton: UIButton { + override var intrinsicContentSize: CGSize { + let size = super.intrinsicContentSize + return CGSize(width: size.width + titleEdgeInsets.left + titleEdgeInsets.right, + height: size.height + titleEdgeInsets.top + titleEdgeInsets.bottom) + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/LoginTableViewCell.swift b/mobile/ios/Client/Frontend/Widgets/LoginTableViewCell.swift new file mode 100644 index 0000000000..9b29468e6e --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/LoginTableViewCell.swift @@ -0,0 +1,387 @@ +/* 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/. */ + +import Foundation +import UIKit +import SnapKit +import Storage + +protocol LoginTableViewCellDelegate: class { + func didSelectOpenAndFillForCell(_ cell: LoginTableViewCell) + func shouldReturnAfterEditingDescription(_ cell: LoginTableViewCell) -> Bool + func infoItemForCell(_ cell: LoginTableViewCell) -> InfoItem? +} + +private struct LoginTableViewCellUX { + static let highlightedLabelFont = UIFont.systemFont(ofSize: 12) + static let highlightedLabelTextColor = UIConstants.SystemBlueColor + static let highlightedLabelEditingTextColor = UIConstants.TableViewHeaderTextColor + + static let descriptionLabelFont = UIFont.systemFont(ofSize: 16) + static let descriptionLabelTextColor = UIColor.black + + static let HorizontalMargin: CGFloat = 14 + static let IconImageSize: CGFloat = 34 + + static let indentWidth: CGFloat = 44 + static let IndentAnimationDuration: TimeInterval = 0.2 + + static let editingDescriptionIndent: CGFloat = IconImageSize + HorizontalMargin +} + +enum LoginTableViewCellStyle { + case iconAndBothLabels + case noIconAndBothLabels + case iconAndDescriptionLabel +} + +class LoginTableViewCell: UITableViewCell { + + fileprivate let labelContainer = UIView() + + weak var delegate: LoginTableViewCellDelegate? + + // In order for context menu handling, this is required + override var canBecomeFirstResponder: Bool { + return true + } + + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + guard let item = delegate?.infoItemForCell(self) else { + return false + } + + // Menu actions for password + if item == .passwordItem { + let showRevealOption = self.descriptionLabel.isSecureTextEntry ? (action == MenuHelper.SelectorReveal) : (action == MenuHelper.SelectorHide) + return action == MenuHelper.SelectorCopy || showRevealOption + } + + // Menu actions for Website + if item == .websiteItem { + return action == MenuHelper.SelectorCopy || action == MenuHelper.SelectorOpenAndFill + } + + // Menu actions for Username + if item == .usernameItem { + return action == MenuHelper.SelectorCopy + } + + return false + } + + lazy var descriptionLabel: UITextField = { + let label = UITextField() + label.font = LoginTableViewCellUX.descriptionLabelFont + label.textColor = LoginTableViewCellUX.descriptionLabelTextColor + label.textAlignment = .left + label.backgroundColor = UIColor.white + label.isUserInteractionEnabled = false + label.autocapitalizationType = .none + label.autocorrectionType = .no + label.accessibilityElementsHidden = true + label.adjustsFontSizeToFitWidth = false + label.delegate = self + label.isAccessibilityElement = true + return label + }() + + // Exposing this label as internal/public causes the Xcode 7.2.1 compiler optimizer to + // produce a EX_BAD_ACCESS error when dequeuing the cell. For now, this label is made private + // and the text property is exposed using a get/set property below. + fileprivate lazy var highlightedLabel: UILabel = { + let label = UILabel() + label.font = LoginTableViewCellUX.highlightedLabelFont + label.textColor = LoginTableViewCellUX.highlightedLabelTextColor + label.textAlignment = .left + label.backgroundColor = UIColor.white + label.numberOfLines = 1 + return label + }() + + fileprivate lazy var iconImageView: UIImageView = { + let imageView = UIImageView() + imageView.backgroundColor = UIColor.white + imageView.contentMode = .scaleAspectFit + return imageView + }() + + fileprivate var showingIndent: Bool = false + + fileprivate var customIndentView = UIView() + + fileprivate var customCheckmarkIcon = UIImageView(image: UIImage(named: "loginUnselected")) + + /// Override the default accessibility label since it won't include the description by default + /// since it's a UITextField acting as a label. + override var accessibilityLabel: String? { + get { + if descriptionLabel.isSecureTextEntry { + return highlightedLabel.text ?? "" + } else { + return "\(highlightedLabel.text ?? ""), \(descriptionLabel.text ?? "")" + } + } + set { + // Ignore sets + } + } + + var style: LoginTableViewCellStyle = .iconAndBothLabels { + didSet { + if style != oldValue { + configureLayoutForStyle(style) + } + } + } + + var descriptionTextSize: CGSize? { + guard let descriptionText = descriptionLabel.text else { + return nil + } + + let attributes = [ + NSFontAttributeName: LoginTableViewCellUX.descriptionLabelFont + ] + + return descriptionText.size(attributes: attributes) + } + + var displayDescriptionAsPassword: Bool = false { + didSet { + descriptionLabel.isSecureTextEntry = displayDescriptionAsPassword + } + } + + var editingDescription: Bool = false { + didSet { + if editingDescription != oldValue { + descriptionLabel.isUserInteractionEnabled = editingDescription + + highlightedLabel.textColor = editingDescription ? + LoginTableViewCellUX.highlightedLabelEditingTextColor : LoginTableViewCellUX.highlightedLabelTextColor + + // Trigger a layout configuration if we changed to editing/not editing the description. + configureLayoutForStyle(self.style) + } + } + } + + var highlightedLabelTitle: String? { + get { + return highlightedLabel.text + } + set(newTitle) { + highlightedLabel.text = newTitle + } + } + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + indentationWidth = 0 + selectionStyle = .none + + contentView.backgroundColor = UIColor.white + labelContainer.backgroundColor = UIColor.white + + labelContainer.addSubview(highlightedLabel) + labelContainer.addSubview(descriptionLabel) + + contentView.addSubview(iconImageView) + contentView.addSubview(labelContainer) + + customIndentView.addSubview(customCheckmarkIcon) + addSubview(customIndentView) + + configureLayoutForStyle(self.style) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + super.prepareForReuse() + delegate = nil + descriptionLabel.isSecureTextEntry = false + descriptionLabel.keyboardType = .default + descriptionLabel.returnKeyType = .default + descriptionLabel.isUserInteractionEnabled = false + } + + override func layoutSubviews() { + super.layoutSubviews() + + // Adjust indent frame + var indentFrame = CGRect( + origin: CGPoint.zero, + size: CGSize(width: LoginTableViewCellUX.indentWidth, height: frame.height)) + + if !showingIndent { + indentFrame.origin.x = -LoginTableViewCellUX.indentWidth + } + + customIndentView.frame = indentFrame + customCheckmarkIcon.frame.center = CGPoint(x: indentFrame.width / 2, y: indentFrame.height / 2) + + // Adjust content view frame based on indent + var contentFrame = self.contentView.frame + contentFrame.origin.x += showingIndent ? LoginTableViewCellUX.indentWidth : 0 + contentView.frame = contentFrame + } + + fileprivate func configureLayoutForStyle(_ style: LoginTableViewCellStyle) { + switch style { + case .iconAndBothLabels: + iconImageView.snp.remakeConstraints { make in + make.centerY.equalTo(contentView) + make.left.equalTo(contentView).offset(LoginTableViewCellUX.HorizontalMargin) + make.height.width.equalTo(LoginTableViewCellUX.IconImageSize) + } + + labelContainer.snp.remakeConstraints { make in + make.centerY.equalTo(contentView) + make.right.equalTo(contentView).offset(-LoginTableViewCellUX.HorizontalMargin) + make.left.equalTo(iconImageView.snp.right).offset(LoginTableViewCellUX.HorizontalMargin) + } + + highlightedLabel.snp.remakeConstraints { make in + make.left.top.equalTo(labelContainer) + make.bottom.equalTo(descriptionLabel.snp.top) + make.width.equalTo(labelContainer) + } + + descriptionLabel.snp.remakeConstraints { make in + make.left.bottom.equalTo(labelContainer) + make.top.equalTo(highlightedLabel.snp.bottom) + make.width.equalTo(labelContainer) + } + case .iconAndDescriptionLabel: + iconImageView.snp.remakeConstraints { make in + make.centerY.equalTo(contentView) + make.left.equalTo(contentView).offset(LoginTableViewCellUX.HorizontalMargin) + make.height.width.equalTo(LoginTableViewCellUX.IconImageSize) + } + + labelContainer.snp.remakeConstraints { make in + make.centerY.equalTo(contentView) + make.right.equalTo(contentView).offset(-LoginTableViewCellUX.HorizontalMargin) + make.left.equalTo(iconImageView.snp.right).offset(LoginTableViewCellUX.HorizontalMargin) + } + + highlightedLabel.snp.remakeConstraints { make in + make.height.width.equalTo(0) + } + + descriptionLabel.snp.remakeConstraints { make in + make.top.left.bottom.equalTo(labelContainer) + make.width.equalTo(labelContainer) + } + case .noIconAndBothLabels: + // Currently we only support modifying the description for this layout which is why + // we factor in the editingOffset when calculating the constraints. + let editingOffset = editingDescription ? LoginTableViewCellUX.editingDescriptionIndent : 0 + + iconImageView.snp.remakeConstraints { make in + make.centerY.equalTo(contentView) + make.left.equalTo(contentView).offset(LoginTableViewCellUX.HorizontalMargin) + make.height.width.equalTo(0) + } + + labelContainer.snp.remakeConstraints { make in + make.centerY.equalTo(contentView) + make.right.equalTo(contentView).offset(-LoginTableViewCellUX.HorizontalMargin) + make.left.equalTo(iconImageView.snp.right).offset(editingOffset) + } + + highlightedLabel.snp.remakeConstraints { make in + make.left.top.equalTo(labelContainer) + make.bottom.equalTo(descriptionLabel.snp.top) + make.width.equalTo(labelContainer) + } + + descriptionLabel.snp.remakeConstraints { make in + make.left.bottom.equalTo(labelContainer) + make.top.equalTo(highlightedLabel.snp.bottom) + make.width.equalTo(labelContainer) + } + } + + setNeedsUpdateConstraints() + } + + override func setEditing(_ editing: Bool, animated: Bool) { + showingIndent = editing + + let adjustConstraints = { [unowned self] in + + // Shift over content view + var contentFrame = self.contentView.frame + contentFrame.origin.x += editing ? LoginTableViewCellUX.indentWidth : -LoginTableViewCellUX.indentWidth + self.contentView.frame = contentFrame + + // Shift over custom indent view + var indentFrame = self.customIndentView.frame + indentFrame.origin.x += editing ? LoginTableViewCellUX.indentWidth : -LoginTableViewCellUX.indentWidth + self.customIndentView.frame = indentFrame + } + + animated ? UIView.animate(withDuration: LoginTableViewCellUX.IndentAnimationDuration, animations: adjustConstraints) : adjustConstraints() + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + customCheckmarkIcon.image = UIImage(named: selected ? "loginSelected" : "loginUnselected") + } +} + +// MARK: - Menu Selectors +extension LoginTableViewCell: MenuHelperInterface { + + func menuHelperReveal() { + displayDescriptionAsPassword = false + } + + func menuHelperSecure() { + displayDescriptionAsPassword = true + } + + func menuHelperCopy() { + // Copy description text to clipboard + UIPasteboard.general.string = descriptionLabel.text + } + + func menuHelperOpenAndFill() { + delegate?.didSelectOpenAndFillForCell(self) + } +} + +// MARK: - Cell Decorators +extension LoginTableViewCell { + func updateCellWithLogin(_ login: LoginData) { + descriptionLabel.text = login.hostname + highlightedLabel.text = login.username + iconImageView.image = UIImage(named: "faviconFox") + } +} + +extension LoginTableViewCell: UITextFieldDelegate { + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + return self.delegate?.shouldReturnAfterEditingDescription(self) ?? true + } + + func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { + if descriptionLabel.isSecureTextEntry { + displayDescriptionAsPassword = false + } + return true + } + + func textFieldDidEndEditing(_ textField: UITextField) { + if descriptionLabel.isSecureTextEntry { + displayDescriptionAsPassword = true + } + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/PhotonActionSheet.swift b/mobile/ios/Client/Frontend/Widgets/PhotonActionSheet.swift new file mode 100644 index 0000000000..cfcf610bcf --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/PhotonActionSheet.swift @@ -0,0 +1,496 @@ +/* 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/. */ + +import Foundation +import Storage +import SnapKit +import Shared + +private struct PhotonActionSheetUX { + static let MaxWidth: CGFloat = 414 + static let Padding: CGFloat = 10 + static let SectionVerticalPadding: CGFloat = 13 + static let HeaderHeight: CGFloat = 80 + static let RowHeight: CGFloat = 44 + static let LabelColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.black : UIColor(rgb: 0x353535) + static let DescriptionLabelColor = UIColor(rgb: 0x919191) + static let PlaceholderImage = UIImage(named: "defaultTopSiteIcon") + static let BorderWidth: CGFloat = 0.5 + static let BorderColor = UIColor(white: 0, alpha: 0.1) + static let CornerRadius: CGFloat = 10 + static let SiteImageViewSize = 52 + static let IconSize = CGSize(width: 24, height: 24) + static let HeaderName = "PhotonActionSheetHeaderView" + static let CellName = "PhotonActionSheetCell" + static let CancelButtonHeight: CGFloat = 56 + static let TablePadding: CGFloat = 6 +} + +public struct PhotonActionSheetItem { + public fileprivate(set) var title: String + public fileprivate(set) var iconString: String + public fileprivate(set) var isEnabled: Bool // Used by toggles like nightmode to switch tint color + public fileprivate(set) var handler: ((PhotonActionSheetItem) -> Void)? + + init(title: String, iconString: String, isEnabled: Bool = false, handler: ((PhotonActionSheetItem) -> Void)?) { + self.title = title + self.iconString = iconString + self.isEnabled = isEnabled + self.handler = handler + } +} + +private enum PresentationStyle { + case centered // used in the home panels + case bottom // used to display the menu +} + +class PhotonActionSheet: UIViewController, UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate { + fileprivate(set) var actions: [[PhotonActionSheetItem]] + + private var site: Site? + private let style: PresentationStyle + private lazy var showCancelButton: Bool = { + return self.style == .bottom && self.modalPresentationStyle != .popover + }() + var tableView = UITableView(frame: CGRect.zero, style: .grouped) + private var tintColor = UIColor(rgb: 0x272727) + private var outerScrollView = UIScrollView() + + lazy var tapRecognizer: UITapGestureRecognizer = { + let tapRecognizer = UITapGestureRecognizer() + tapRecognizer.addTarget(self, action: #selector(PhotonActionSheet.dismiss(_:))) + tapRecognizer.numberOfTapsRequired = 1 + tapRecognizer.cancelsTouchesInView = false + tapRecognizer.delegate = self + return tapRecognizer + }() + + lazy var cancelButton: UIButton = { + let button = UIButton() + button.setTitle(Strings.CancelButtonTitle, for: .normal) + button.backgroundColor = UIConstants.AppBackgroundColor + button.setTitleColor(UIConstants.SystemBlueColor, for: .normal) + button.layer.cornerRadius = PhotonActionSheetUX.CornerRadius + button.titleLabel?.font = DynamicFontHelper.defaultHelper.DeviceFontExtraLargeBold + button.addTarget(self, action: #selector(PhotonActionSheet.dismiss(_:)), for: .touchUpInside) + button.accessibilityIdentifier = "PhotonMenu.cancel" + return button + }() + + init(site: Site, actions: [PhotonActionSheetItem]) { + self.site = site + self.actions = [actions] + self.style = .centered + super.init(nibName: nil, bundle: nil) + } + + init(actions: [[PhotonActionSheetItem]]) { + self.actions = actions + self.style = .bottom + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var photonTransitionDelegate: UIViewControllerTransitioningDelegate? { + didSet { + self.transitioningDelegate = photonTransitionDelegate + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + if style == .centered { + applyBackgroundBlur() + self.tintColor = UIConstants.SystemBlueColor + } + view.addGestureRecognizer(tapRecognizer) + view.addSubview(tableView) + + view.accessibilityIdentifier = "Action Sheet" + tableView.bounces = false + tableView.delegate = self + tableView.dataSource = self + tableView.sectionFooterHeight = 0 + tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag + tableView.register(PhotonActionSheetCell.self, forCellReuseIdentifier: PhotonActionSheetUX.CellName) + tableView.register(PhotonActionSheetHeaderView.self, forHeaderFooterViewReuseIdentifier: PhotonActionSheetUX.HeaderName) + tableView.register(PhotonActionSheetSeparator.self, forHeaderFooterViewReuseIdentifier: "SeparatorSectionHeader") + tableView.isScrollEnabled = true + tableView.showsVerticalScrollIndicator = false + tableView.layer.cornerRadius = PhotonActionSheetUX.CornerRadius + tableView.separatorStyle = .none + tableView.cellLayoutMarginsFollowReadableWidth = false + tableView.accessibilityIdentifier = "Context Menu" + let footer = UIView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: tableView.frame.width, height: PhotonActionSheetUX.TablePadding))) + tableView.tableFooterView = footer + tableView.tableHeaderView = footer.clone() + + // In a popover the popover provides the blur background + // Not using a background color allows the view to style correctly with the popover arrow + if self.popoverPresentationController == nil { + tableView.backgroundColor = UIConstants.AppBackgroundColor.withAlphaComponent(0.7) + let blurEffect = UIBlurEffect(style: .light) + let blurEffectView = UIVisualEffectView(effect: blurEffect) + tableView.backgroundView = blurEffectView + } else { + tableView.backgroundColor = .clear + } + + let width = min(self.view.frame.size.width, PhotonActionSheetUX.MaxWidth) - (PhotonActionSheetUX.Padding * 2) + let height = actionSheetHeight() + + if self.modalPresentationStyle == .popover { + self.preferredContentSize = CGSize(width: width, height: height) + } + + if self.showCancelButton { + self.view.addSubview(cancelButton) + cancelButton.snp.makeConstraints { make in + make.centerX.equalTo(self.view.snp.centerX) + make.width.equalTo(width) + make.height.equalTo(PhotonActionSheetUX.CancelButtonHeight) + if #available(iOS 11, *) { + let bottomPad: CGFloat + if let window = UIApplication.shared.keyWindow, window.safeAreaInsets.bottom != 0 { + // for iPhone X and similar + bottomPad = 0 + } else { + bottomPad = PhotonActionSheetUX.Padding + } + make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom).offset(-bottomPad) + } else { + make.bottom.equalTo(self.view.snp.bottom).offset(-PhotonActionSheetUX.Padding) + } + } + } + + if style == .bottom && self.modalPresentationStyle == .popover { + // We are showing the menu in a popOver + self.actions = actions.map({ $0.reversed() }).reversed() + tableView.frame = CGRect(origin: CGPoint.zero, size: self.preferredContentSize) + return + } + + tableView.snp.makeConstraints { make in + make.centerX.equalTo(self.view.snp.centerX) + switch style { + case .bottom: + make.bottom.equalTo(cancelButton.snp.top).offset(-PhotonActionSheetUX.Padding) + case .centered: + make.centerY.equalTo(self.view.snp.centerY) + } + make.width.equalTo(width) + make.height.equalTo(min(height, view.bounds.height - PhotonActionSheetUX.CancelButtonHeight - (PhotonActionSheetUX.Padding * 6))) + } + } + + private func applyBackgroundBlur() { + let appDelegate = UIApplication.shared.delegate as! AppDelegate + if let screenshot = appDelegate.window?.screenshot() { + let blurredImage = screenshot.applyBlur(withRadius: 5, + blurType: BOXFILTER, + tintColor: UIColor.black.withAlphaComponent(0.2), + saturationDeltaFactor: 1.8, + maskImage: nil) + let imageView = UIImageView(image: blurredImage) + view.addSubview(imageView) + } + } + + fileprivate func actionSheetHeight() -> CGFloat { + let count = actions.reduce(0) { $1.count + $0 } + let headerHeight = (style == .centered) ? PhotonActionSheetUX.HeaderHeight : 0 + let separatorHeight = actions.count > 1 ? (actions.count - 1) * Int(PhotonActionSheetUX.SectionVerticalPadding) : 0 + return CGFloat(separatorHeight) + headerHeight + ( PhotonActionSheetUX.TablePadding * 2) + CGFloat(count) * PhotonActionSheetUX.RowHeight + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + } + + func dismiss(_ gestureRecognizer: UIGestureRecognizer?) { + self.dismiss(animated: true, completion: nil) + } + + deinit { + tableView.dataSource = nil + tableView.delegate = nil + } + + override func updateViewConstraints() { + if !self.showCancelButton { + tableView.frame = CGRect(origin: CGPoint.zero, size: self.preferredContentSize) + } + super.updateViewConstraints() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + if self.traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass + || self.traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass { + updateViewConstraints() + } + } + + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { + if tableView.frame.contains(touch.location(in: self.view)) { + return false + } + return true + } + + func numberOfSections(in tableView: UITableView) -> Int { + return actions.count + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return actions[section].count + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let action = actions[indexPath.section][indexPath.row] + guard let handler = action.handler else { + self.dismiss(nil) + return + } + self.dismiss(nil) + return handler(action) + } + + func tableView(_ tableView: UITableView, hasFullWidthSeparatorForRowAtIndexPath indexPath: IndexPath) -> Bool { + return false + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return PhotonActionSheetUX.RowHeight + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + // If we have multiple sections show a separator for each one except the first. + if section > 0 { + return PhotonActionSheetUX.SectionVerticalPadding + } + return self.site != nil ? PhotonActionSheetUX.HeaderHeight : 0 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: PhotonActionSheetUX.CellName, for: indexPath) as! PhotonActionSheetCell + let action = actions[indexPath.section][indexPath.row] + + cell.tintColor = action.isEnabled ? UIConstants.SystemBlueColor : self.tintColor + cell.configureCell(action.title, imageString: action.iconString) + return cell + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + // If we have multiple sections show a separator for each one except the first. + if section > 0 { + return tableView.dequeueReusableHeaderFooterView(withIdentifier: "SeparatorSectionHeader") + } + guard let site = site else { + return nil + } + let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: PhotonActionSheetUX.HeaderName) as! PhotonActionSheetHeaderView + header.tintColor = self.tintColor + header.configureWithSite(site) + return header + } +} + +private class PhotonActionSheetHeaderView: UITableViewHeaderFooterView { + static let Padding: CGFloat = 12 + static let VerticalPadding: CGFloat = 2 + + lazy var titleLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.font = DynamicFontHelper.defaultHelper.MediumSizeBoldFontAS + titleLabel.textAlignment = .left + titleLabel.numberOfLines = 2 + return titleLabel + }() + + lazy var descriptionLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.font = DynamicFontHelper.defaultHelper.MediumSizeRegularWeightAS + titleLabel.textAlignment = .left + titleLabel.numberOfLines = 1 + return titleLabel + }() + + lazy var siteImageView: UIImageView = { + let siteImageView = UIImageView() + siteImageView.contentMode = UIViewContentMode.center + siteImageView.clipsToBounds = true + siteImageView.layer.cornerRadius = PhotonActionSheetUX.CornerRadius + siteImageView.layer.borderColor = PhotonActionSheetUX.BorderColor.cgColor + siteImageView.layer.borderWidth = PhotonActionSheetUX.BorderWidth + return siteImageView + }() + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + + self.backgroundView = UIView() + self.backgroundView?.backgroundColor = .clear + contentView.addSubview(siteImageView) + + siteImageView.snp.remakeConstraints { make in + make.centerY.equalTo(contentView) + make.leading.equalTo(contentView).offset(PhotonActionSheetHeaderView.Padding) + make.size.equalTo(PhotonActionSheetUX.SiteImageViewSize) + } + + let stackView = UIStackView(arrangedSubviews: [titleLabel, descriptionLabel]) + stackView.spacing = PhotonActionSheetHeaderView.VerticalPadding + stackView.alignment = .leading + stackView.axis = .vertical + + contentView.addSubview(stackView) + + stackView.snp.makeConstraints { make in + make.leading.equalTo(siteImageView.snp.trailing).offset(PhotonActionSheetHeaderView.Padding) + make.trailing.equalTo(contentView).inset(PhotonActionSheetHeaderView.Padding) + make.centerY.equalTo(siteImageView.snp.centerY) + } + + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + self.siteImageView.image = nil + self.siteImageView.backgroundColor = UIColor.clear + } + + func configureWithSite(_ site: Site) { + self.siteImageView.setFavicon(forSite: site) { (color, url) in + self.siteImageView.backgroundColor = color + self.siteImageView.image = self.siteImageView.image?.createScaled(PhotonActionSheetUX.IconSize) + } + self.titleLabel.text = site.title.characters.count <= 1 ? site.url : site.title + self.descriptionLabel.text = site.tileURL.baseDomain + } +} + +private struct PhotonActionSheetCellUX { + static let LabelColor = UIConstants.SystemBlueColor + static let BorderWidth: CGFloat = CGFloat(0.5) + static let CellSideOffset = 20 + static let TitleLabelOffset = 10 + static let CellTopBottomOffset = 12 + static let StatusIconSize = 24 + static let SelectedOverlayColor = UIColor(white: 0.0, alpha: 0.25) + static let CornerRadius: CGFloat = 3 +} + +private class PhotonActionSheetSeparator: UITableViewHeaderFooterView { + + let separatorLineView = UIView() + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + self.backgroundView = UIView() + self.backgroundView?.backgroundColor = .clear + separatorLineView.backgroundColor = UIColor.lightGray + self.contentView.addSubview(separatorLineView) + separatorLineView.snp.makeConstraints { make in + make.leading.trailing.equalTo(self) + make.centerY.equalTo(self) + make.height.equalTo(0.5) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private class PhotonActionSheetCell: UITableViewCell { + lazy var titleLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.font = DynamicFontHelper.defaultHelper.LargeSizeRegularWeightAS + titleLabel.minimumScaleFactor = 0.75 // Scale the font if we run out of space + titleLabel.textColor = PhotonActionSheetCellUX.LabelColor + titleLabel.textAlignment = .left + titleLabel.numberOfLines = 1 + titleLabel.adjustsFontSizeToFitWidth = true + return titleLabel + }() + + lazy var statusIcon: UIImageView = { + let siteImageView = UIImageView() + siteImageView.contentMode = UIViewContentMode.scaleAspectFit + siteImageView.clipsToBounds = true + siteImageView.layer.cornerRadius = PhotonActionSheetCellUX.CornerRadius + return siteImageView + }() + + lazy var selectedOverlay: UIView = { + let selectedOverlay = UIView() + selectedOverlay.backgroundColor = PhotonActionSheetCellUX.SelectedOverlayColor + selectedOverlay.isHidden = true + return selectedOverlay + }() + + override var isSelected: Bool { + didSet { + self.selectedOverlay.isHidden = !isSelected + } + } + + override func prepareForReuse() { + self.statusIcon.image = nil + } + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + isAccessibilityElement = true + + contentView.addSubview(selectedOverlay) + contentView.addSubview(titleLabel) + contentView.addSubview(statusIcon) + backgroundColor = .clear + + selectedOverlay.snp.makeConstraints { make in + make.edges.equalTo(contentView) + } + + titleLabel.snp.makeConstraints { make in + make.leading.equalTo(statusIcon.snp.trailing).offset(16) + make.trailing.equalTo(contentView) + make.centerY.equalTo(contentView) + } + + statusIcon.snp.makeConstraints { make in + make.size.equalTo(PhotonActionSheetCellUX.StatusIconSize) + make.leading.equalTo(contentView).offset(16) + make.centerY.equalTo(contentView) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configureCell(_ label: String, imageString: String) { + titleLabel.text = label + titleLabel.textColor = self.tintColor + accessibilityIdentifier = imageString + accessibilityLabel = label + if let image = UIImage(named: imageString)?.withRenderingMode(.alwaysTemplate) { + statusIcon.image = image + statusIcon.tintColor = self.tintColor + } + } +} + diff --git a/mobile/ios/Client/Frontend/Widgets/PhotonActionSheetAnimator.swift b/mobile/ios/Client/Frontend/Widgets/PhotonActionSheetAnimator.swift new file mode 100644 index 0000000000..10e730e0c5 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/PhotonActionSheetAnimator.swift @@ -0,0 +1,79 @@ +/* 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/. */ + +import UIKit + +class PhotonActionSheetAnimator: NSObject, UIViewControllerAnimatedTransitioning { + + var presenting: Bool = false + let animationDuration = 0.4 + + lazy var shadow: UIView = { + let shadow = UIView() + shadow.backgroundColor = UIColor(white: 0, alpha: 0.5) + return shadow + }() + + func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let screens = (from: transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!, to: transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!) + + guard let actionSheet = (self.presenting ? screens.to : screens.from) as? PhotonActionSheet else { + return + } + + let bottomViewController = (self.presenting ? screens.from : screens.to) as UIViewController + animateWitVC(actionSheet, presentingVC: bottomViewController, transitionContext: transitionContext) + } + + func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return animationDuration + } +} + +extension PhotonActionSheetAnimator: UIViewControllerTransitioningDelegate { + func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + self.presenting = true + return self + } + + func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + self.presenting = false + return self + } +} + +extension PhotonActionSheetAnimator { + fileprivate func animateWitVC(_ actionSheet: PhotonActionSheet, presentingVC viewController: UIViewController, transitionContext: UIViewControllerContextTransitioning) { + let containerView = transitionContext.containerView + + if presenting { + shadow.frame = containerView.bounds + containerView.addSubview(shadow) + actionSheet.view.frame = CGRect(origin: CGPoint(x: 0, y: containerView.frame.size.height), size: containerView.frame.size) + self.shadow.alpha = 0 + containerView.addSubview(actionSheet.view) + actionSheet.view.layoutIfNeeded() + + UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.3, options: [], animations: { () -> Void in + self.shadow.alpha = 1 + actionSheet.view.frame = containerView.bounds + actionSheet.view.layoutIfNeeded() + }, completion: { (completed) -> Void in + transitionContext.completeTransition(completed) + }) + + } else { + UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 1.2, initialSpringVelocity: 0.0, options: [], animations: { () -> Void in + self.shadow.alpha = 0 + actionSheet.view.frame = CGRect(origin: CGPoint(x: 0, y: containerView.frame.size.height), size: containerView.frame.size) + actionSheet.view.layoutIfNeeded() + }, completion: { (completed) -> Void in + actionSheet.view.removeFromSuperview() + self.shadow.removeFromSuperview() + transitionContext.completeTransition(completed) + }) + } + } +} + diff --git a/mobile/ios/Client/Frontend/Widgets/PhotonActionSheetProtocol.swift b/mobile/ios/Client/Frontend/Widgets/PhotonActionSheetProtocol.swift new file mode 100644 index 0000000000..7ffaa6f609 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/PhotonActionSheetProtocol.swift @@ -0,0 +1,232 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage + +protocol PhotonActionSheetProtocol { + var tabManager: TabManager { get } + var profile: Profile { get } +} + +private let log = Logger.browserLogger + +extension PhotonActionSheetProtocol { + typealias PresentableVC = UIViewController & UIPopoverPresentationControllerDelegate + typealias MenuAction = () -> Void + typealias IsPrivateTab = Bool + typealias URLOpenAction = (URL?, IsPrivateTab) -> Void + + func presentSheetWith(actions: [[PhotonActionSheetItem]], on viewController: PresentableVC, from view: UIView, supressPopover: Bool = false) { + let sheet = PhotonActionSheet(actions: actions) + sheet.modalPresentationStyle = (UIDevice.current.userInterfaceIdiom == .pad && !supressPopover) ? .popover : .overCurrentContext + sheet.photonTransitionDelegate = PhotonActionSheetAnimator() + + if let popoverVC = sheet.popoverPresentationController, sheet.modalPresentationStyle == .popover { + popoverVC.delegate = viewController + popoverVC.sourceView = view + popoverVC.sourceRect = CGRect(x: view.frame.width/2, y: view.frame.size.height * 0.75, width: 1, height: 1) + popoverVC.permittedArrowDirections = UIPopoverArrowDirection.up + popoverVC.backgroundColor = UIConstants.AppBackgroundColor.withAlphaComponent(0.7) + } + viewController.present(sheet, animated: true, completion: nil) + } + + //Returns a list of actions which is used to build a menu + //OpenURL is a closure that can open a given URL in some view controller. It is up to the class using the menu to know how to open it + func getHomePanelActions() -> [PhotonActionSheetItem] { + guard let tab = self.tabManager.selectedTab else { return [] } + + let openTopSites = PhotonActionSheetItem(title: Strings.AppMenuTopSitesTitleString, iconString: "menu-panel-TopSites") { action in + tab.loadRequest(PrivilegedRequest(url: HomePanelType.topSites.localhostURL) as URLRequest) + } + + let openBookmarks = PhotonActionSheetItem(title: Strings.AppMenuBookmarksTitleString, iconString: "menu-panel-Bookmarks") { action in + tab.loadRequest(PrivilegedRequest(url: HomePanelType.bookmarks.localhostURL) as URLRequest) + UnifiedTelemetry.recordEvent(category: .action, method: .view, object: .bookmarksPanel, value: .appMenu) + } + + let openHistory = PhotonActionSheetItem(title: Strings.AppMenuHistoryTitleString, iconString: "menu-panel-History") { action in + tab.loadRequest(PrivilegedRequest(url: HomePanelType.history.localhostURL) as URLRequest) + } + + let openReadingList = PhotonActionSheetItem(title: Strings.AppMenuReadingListTitleString, iconString: "menu-panel-ReadingList") { action in + tab.loadRequest(PrivilegedRequest(url: HomePanelType.readingList.localhostURL) as URLRequest) + } + + let openHomePage = PhotonActionSheetItem(title: Strings.AppMenuOpenHomePageTitleString, iconString: "menu-Home") { _ in + HomePageHelper(prefs: self.profile.prefs).openHomePage(tab) + } + + var actions = [openTopSites, openBookmarks, openReadingList, openHistory] + if HomePageHelper(prefs: self.profile.prefs).isHomePageAvailable { + actions.insert(openHomePage, at: 0) + } + + return actions + } + + /* + Returns a list of actions which is used to build the general browser menu + These items repersent global options that are presented in the menu + TODO: These icons should all have the icons and use Strings.swift + */ + + typealias PageOptionsVC = QRCodeViewControllerDelegate & SettingsDelegate & PresentingModalViewControllerDelegate & UIViewController + + func getOtherPanelActions(vcDelegate: PageOptionsVC) -> [PhotonActionSheetItem] { + var noImageMode: PhotonActionSheetItem? = nil + if #available(iOS 11, *) { + let noImageEnabled = NoImageModeHelper.isActivated(profile.prefs) + let noImageText = noImageEnabled ? Strings.AppMenuNoImageModeDisable : Strings.AppMenuNoImageModeEnable + noImageMode = PhotonActionSheetItem(title: noImageText, iconString: "menu-NoImageMode", isEnabled: noImageEnabled) { action in + NoImageModeHelper.toggle(profile: self.profile, tabManager: self.tabManager) + } + } + + let nightModeEnabled = NightModeHelper.isActivated(profile.prefs) + let nightModeText = nightModeEnabled ? Strings.AppMenuNightModeDisable : Strings.AppMenuNightModeEnable + let nightMode = PhotonActionSheetItem(title: nightModeText, iconString: "menu-NightMode", isEnabled: nightModeEnabled) { action in + NightModeHelper.toggle(self.profile.prefs, tabManager: self.tabManager) + } + + let openSettings = PhotonActionSheetItem(title: Strings.AppMenuSettingsTitleString, iconString: "menu-Settings") { action in + let settingsTableViewController = AppSettingsTableViewController() + settingsTableViewController.profile = self.profile + settingsTableViewController.tabManager = self.tabManager + settingsTableViewController.settingsDelegate = vcDelegate + + let controller = SettingsNavigationController(rootViewController: settingsTableViewController) + controller.popoverDelegate = vcDelegate + controller.modalPresentationStyle = UIModalPresentationStyle.formSheet + vcDelegate.present(controller, animated: true, completion: nil) + } + + if let noImageMode = noImageMode { + return [noImageMode, nightMode, openSettings] + } + return [nightMode, openSettings] + } + + func getTabActions(tab: Tab, buttonView: UIView, + presentShareMenu: @escaping (URL, Tab, UIView, UIPopoverArrowDirection) -> Void, + findInPage: @escaping () -> Void, + presentableVC: PresentableVC, + success: @escaping (String) -> Void) -> Array<[PhotonActionSheetItem]> { + + let toggleActionTitle = tab.desktopSite ? Strings.AppMenuViewMobileSiteTitleString : Strings.AppMenuViewDesktopSiteTitleString + let toggleDesktopSite = PhotonActionSheetItem(title: toggleActionTitle, iconString: "menu-RequestDesktopSite") { action in + tab.toggleDesktopSite() + } + + let addReadingList = PhotonActionSheetItem(title: Strings.AppMenuAddToReadingListTitleString, iconString: "addToReadingList") { action in + guard let url = tab.url?.displayURL else { return } + + self.profile.readingList?.createRecordWithURL(url.absoluteString, title: tab.title ?? "", addedBy: UIDevice.current.name) + UnifiedTelemetry.recordEvent(category: .action, method: .add, object: .readingListItem, value: .pageActionMenu) + success(Strings.AppMenuAddToReadingListConfirmMessage) + } + + let findInPageAction = PhotonActionSheetItem(title: Strings.AppMenuFindInPageTitleString, iconString: "menu-FindInPage") { action in + findInPage() + } + + let bookmarkPage = PhotonActionSheetItem(title: Strings.AppMenuAddBookmarkTitleString, iconString: "menu-Bookmark") { action in + //TODO: can all this logic go somewhere else? + guard let url = tab.canonicalURL?.displayURL else { return } + let absoluteString = url.absoluteString + let shareItem = ShareItem(url: absoluteString, title: tab.title, favicon: tab.displayFavicon) + _ = self.profile.bookmarks.shareItem(shareItem) + var userData = [QuickActions.TabURLKey: shareItem.url] + if let title = shareItem.title { + userData[QuickActions.TabTitleKey] = title + } + QuickActions.sharedInstance.addDynamicApplicationShortcutItemOfType(.openLastBookmark, + withUserData: userData, + toApplication: UIApplication.shared) + tab.isBookmarked = true + UnifiedTelemetry.recordEvent(category: .action, method: .add, object: .bookmark, value: .pageActionMenu) + success(Strings.AppMenuAddBookmarkConfirmMessage) + } + + let removeBookmark = PhotonActionSheetItem(title: Strings.AppMenuRemoveBookmarkTitleString, iconString: "menu-Bookmark-Remove") { action in + //TODO: can all this logic go somewhere else? + guard let url = tab.url?.displayURL else { return } + let absoluteString = url.absoluteString + self.profile.bookmarks.modelFactory >>== { + $0.removeByURL(absoluteString).uponQueue(.main) { res in + if res.isSuccess { + tab.isBookmarked = false + UnifiedTelemetry.recordEvent(category: .action, method: .delete, object: .bookmark, value: .pageActionMenu) + success(Strings.AppMenuRemoveBookmarkConfirmMessage) + } + } + } + } + + let pinToTopSites = PhotonActionSheetItem(title: Strings.PinTopsiteActionTitle, iconString: "action_pin") { action in + guard let url = tab.url?.displayURL, + let sql = self.profile.history as? SQLiteHistory else { return } + let absoluteString = url.absoluteString + + sql.getSitesForURLs([absoluteString]) >>== { result in + guard let siteOp = result.asArray().first, let site = siteOp else { + log.warning("Could not get site for \(absoluteString)") + return + } + + _ = self.profile.history.addPinnedTopSite(site).value + } + } + + let sendToDevice = PhotonActionSheetItem(title: Strings.SendToDeviceTitle, iconString: "menu-Send-to-Device") { action in + guard let bvc = presentableVC as? PresentableVC & InstructionsViewControllerDelegate & ClientPickerViewControllerDelegate else { return } + if !self.profile.hasAccount() { + let instructionsViewController = InstructionsViewController() + instructionsViewController.delegate = bvc + let navigationController = UINavigationController(rootViewController: instructionsViewController) + navigationController.modalPresentationStyle = .formSheet + bvc.present(navigationController, animated: true, completion: nil) + return + } + + let clientPickerViewController = ClientPickerViewController() + clientPickerViewController.clientPickerDelegate = bvc + clientPickerViewController.profile = self.profile + clientPickerViewController.profileNeedsShutdown = false + let navigationController = UINavigationController(rootViewController: clientPickerViewController) + navigationController.modalPresentationStyle = .formSheet + bvc.present(navigationController, animated: true, completion: nil) + } + + let share = PhotonActionSheetItem(title: Strings.AppMenuSharePageTitleString, iconString: "action_share") { action in + guard let url = tab.canonicalURL?.displayURL else { return } + presentShareMenu(url, tab, buttonView, .up) + } + + let closeTab = PhotonActionSheetItem(title: Strings.CloseTabTitle, iconString: "action_remove") { action in + self.tabManager.removeTab(tab) + } + + let copyURL = PhotonActionSheetItem(title: Strings.AppMenuCopyURLTitleString, iconString: "menu-Copy-Link") { _ in + UIPasteboard.general.url = tab.canonicalURL?.displayURL + success(Strings.AppMenuCopyURLConfirmMessage) + } + + var topActions: [PhotonActionSheetItem] = [] + + // Disable bookmarking and reading list if the URL is too long. + if !tab.urlIsTooLong { + topActions.append(tab.isBookmarked ? removeBookmark : bookmarkPage) + + if tab.readerModeAvailableOrActive { + topActions.append(addReadingList) + } + } + + return [topActions, [copyURL, findInPageAction, toggleDesktopSite, pinToTopSites, sendToDevice, closeTab], [share]] + } +} + diff --git a/mobile/ios/Client/Frontend/Widgets/RoundedToolbar.swift b/mobile/ios/Client/Frontend/Widgets/RoundedToolbar.swift new file mode 100644 index 0000000000..ea56aace36 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/RoundedToolbar.swift @@ -0,0 +1,33 @@ +/* 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/. */ + +import UIKit + +class RoundedToolbar: UIToolbar { + + fileprivate var layerBackgroundColor: UIColor? + + override var backgroundColor: UIColor? { + get { return layerBackgroundColor } + + set { + layerBackgroundColor = newValue + } + } + + var cornerRadius: CGSize = CGSize.zero + + var cornersToRound: UIRectCorner = [.allCorners] + + /** + * The toolbar on the menu requires rounded corners on the top and bottom so we need a custom + * view to do this + */ + override func draw(_ rect: CGRect) { + super.draw(rect) + layer.sublayers?.filter { $0.mask != nil } .forEach { $0.removeFromSuperlayer() } + addRoundedCorners(cornersToRound, cornerRadius: cornerRadius, color: layerBackgroundColor ?? UIColor.white) + } + +} diff --git a/mobile/ios/Client/Frontend/Widgets/SearchInputView.swift b/mobile/ios/Client/Frontend/Widgets/SearchInputView.swift new file mode 100644 index 0000000000..95e63b895a --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/SearchInputView.swift @@ -0,0 +1,205 @@ +/* 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/. */ + +import Foundation +import SnapKit + +private struct SearchInputViewUX { + + static let horizontalSpacing: CGFloat = 16 + static let titleFont: UIFont = UIFont.systemFont(ofSize: 16) + static let titleColor: UIColor = UIColor.lightGray + static let inputColor: UIColor = UIConstants.HighlightBlue + static let borderColor: UIColor = UIConstants.SeparatorColor + static let borderLineWidth: CGFloat = 0.5 + static let closeButtonSize: CGFloat = 36 +} + +@objc protocol SearchInputViewDelegate: class { + + func searchInputView(_ searchView: SearchInputView, didChangeTextTo text: String) + + func searchInputViewBeganEditing(_ searchView: SearchInputView) + + func searchInputViewFinishedEditing(_ searchView: SearchInputView) +} + +class SearchInputView: UIView { + + weak var delegate: SearchInputViewDelegate? + + var showBottomBorder: Bool = true { + didSet { + bottomBorder.isHidden = !showBottomBorder + } + } + + lazy var inputField: UITextField = { + let textField = UITextField() + textField.delegate = self + textField.textColor = SearchInputViewUX.inputColor + textField.tintColor = SearchInputViewUX.inputColor + textField.addTarget(self, action: #selector(SearchInputView.inputTextDidChange(_:)), for: .editingChanged) + textField.accessibilityLabel = NSLocalizedString("Search Input Field", tableName: "LoginManager", comment: "Accessibility label for the search input field in the Logins list") + textField.autocorrectionType = .no + textField.autocapitalizationType = .none + return textField + }() + + lazy var titleLabel: UILabel = { + let label = UILabel() + label.text = NSLocalizedString("Search", tableName: "LoginManager", comment: "Title for the search field at the top of the Logins list screen") + label.font = SearchInputViewUX.titleFont + label.textColor = SearchInputViewUX.titleColor + return label + }() + + lazy var searchIcon: UIImageView = { + return UIImageView(image: UIImage(named: "quickSearch")) + }() + + fileprivate lazy var closeButton: UIButton = { + let button = UIButton() + button.addTarget(self, action: #selector(SearchInputView.tappedClose), for: .touchUpInside) + button.setImage(UIImage(named: "clear"), for: UIControlState()) + button.accessibilityLabel = NSLocalizedString("Clear Search", tableName: "LoginManager", + comment: "Accessibility message e.g. spoken by VoiceOver after the user taps the close button in the search field to clear the search and exit search mode") + return button + }() + + fileprivate var centerContainer = UIView() + + fileprivate lazy var bottomBorder: UIView = { + let border = UIView() + border.backgroundColor = SearchInputViewUX.borderColor + return border + }() + + fileprivate lazy var overlay: UIView = { + let view = UIView() + view.backgroundColor = UIColor.white + view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(SearchInputView.tappedSearch))) + + view.isAccessibilityElement = true + view.accessibilityLabel = NSLocalizedString("Enter Search Mode", tableName: "LoginManager", comment: "Accessibility label for entering search mode for logins") + return view + }() + + fileprivate(set) var isEditing = false { + didSet { + if isEditing { + overlay.isHidden = true + inputField.isHidden = false + inputField.accessibilityElementsHidden = false + closeButton.isHidden = false + closeButton.accessibilityElementsHidden = false + } else { + overlay.isHidden = false + inputField.isHidden = true + inputField.accessibilityElementsHidden = true + closeButton.isHidden = true + closeButton.accessibilityElementsHidden = true + } + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + backgroundColor = UIColor.white + isUserInteractionEnabled = true + + addSubview(inputField) + addSubview(closeButton) + + centerContainer.addSubview(searchIcon) + centerContainer.addSubview(titleLabel) + overlay.addSubview(centerContainer) + addSubview(overlay) + addSubview(bottomBorder) + + setupConstraints() + + setEditing(false) + } + + fileprivate func setupConstraints() { + centerContainer.snp.makeConstraints { make in + make.center.equalTo(overlay) + } + + overlay.snp.makeConstraints { make in + make.edges.equalTo(self) + } + + searchIcon.snp.makeConstraints { make in + make.right.equalTo(titleLabel.snp.left).offset(-SearchInputViewUX.horizontalSpacing) + make.centerY.equalTo(centerContainer) + } + + titleLabel.snp.makeConstraints { make in + make.center.equalTo(centerContainer) + } + + inputField.snp.makeConstraints { make in + make.left.equalTo(self).offset(SearchInputViewUX.horizontalSpacing) + make.centerY.equalTo(self) + make.right.equalTo(closeButton.snp.left).offset(-SearchInputViewUX.horizontalSpacing) + } + + closeButton.snp.makeConstraints { make in + make.right.equalTo(self).offset(-SearchInputViewUX.horizontalSpacing) + make.centerY.equalTo(self) + make.size.equalTo(SearchInputViewUX.closeButtonSize) + } + + bottomBorder.snp.makeConstraints { make in + make.left.right.bottom.equalTo(self) + make.height.equalTo(SearchInputViewUX.borderLineWidth) + } + } + + // didSet callbacks don't trigger when a property is being set in the init() call + // but calling a method that does works fine. + fileprivate func setEditing(_ editing: Bool) { + isEditing = editing + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - Selectors +extension SearchInputView { + + func tappedSearch() { + isEditing = true + inputField.becomeFirstResponder() + delegate?.searchInputViewBeganEditing(self) + } + + func tappedClose() { + isEditing = false + delegate?.searchInputViewFinishedEditing(self) + inputField.text = nil + inputField.resignFirstResponder() + } + + func inputTextDidChange(_ textField: UITextField) { + delegate?.searchInputView(self, didChangeTextTo: textField.text ?? "") + } +} + +// MARK: - UITextFieldDelegate +extension SearchInputView: UITextFieldDelegate { + + func textFieldDidEndEditing(_ textField: UITextField) { + // If there is no text, go back to showing the title view + if (textField.text?.characters.count ?? 0) == 0 { + isEditing = false + delegate?.searchInputViewFinishedEditing(self) + } + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/SeparatorTableCell.swift b/mobile/ios/Client/Frontend/Widgets/SeparatorTableCell.swift new file mode 100644 index 0000000000..2ffad23255 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/SeparatorTableCell.swift @@ -0,0 +1,29 @@ +/* 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/. */ + +import UIKit + +class SeparatorTableCell: UITableViewCell { + override var textLabel: UILabel? { + return nil + } + + override var detailTextLabel: UILabel? { + return nil + } + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + self.selectionStyle = UITableViewCellSelectionStyle.none + self.indentationWidth = 0 + self.separatorInset = UIEdgeInsets.zero + self.layoutMargins = UIEdgeInsets.zero + self.backgroundColor = UIConstants.PanelBackgroundColor // So we get a gentle white and grey stripe. + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/SiteTableViewController.swift b/mobile/ios/Client/Frontend/Widgets/SiteTableViewController.swift new file mode 100644 index 0000000000..db9de263f9 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/SiteTableViewController.swift @@ -0,0 +1,160 @@ +/* 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/. */ + +import UIKit +import Storage + +struct SiteTableViewControllerUX { + static let HeaderHeight = CGFloat(32) + static let RowHeight = CGFloat(44) + static let HeaderBorderColor = UIColor(rgb: 0xCFD5D9).withAlphaComponent(0.8) + static let HeaderTextColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.black : UIColor(rgb: 0x232323) + static let HeaderBackgroundColor = UIColor(rgb: 0xf7f8f7) + static let HeaderFont = UIFont.systemFont(ofSize: 12, weight: UIFontWeightMedium) + static let HeaderTextMargin = CGFloat(16) +} + +class SiteTableViewHeader: UITableViewHeaderFooterView { + // I can't get drawRect to play nicely with the glass background. As a fallback + // we just use views for the top and bottom borders. + let topBorder = UIView() + let bottomBorder = UIView() + let titleLabel = UILabel() + + override var textLabel: UILabel? { + return titleLabel + } + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + + topBorder.backgroundColor = SiteTableViewControllerUX.HeaderBorderColor + bottomBorder.backgroundColor = SiteTableViewControllerUX.HeaderBorderColor + contentView.backgroundColor = SiteTableViewControllerUX.HeaderBackgroundColor + + titleLabel.font = DynamicFontHelper.defaultHelper.DeviceFontMediumBold + titleLabel.textColor = SiteTableViewControllerUX.HeaderTextColor + titleLabel.textAlignment = .left + + addSubview(topBorder) + addSubview(bottomBorder) + contentView.addSubview(titleLabel) + + topBorder.snp.makeConstraints { make in + make.left.right.equalTo(self) + make.top.equalTo(self).offset(-0.5) + make.height.equalTo(0.5) + } + + bottomBorder.snp.makeConstraints { make in + make.left.right.bottom.equalTo(self) + make.height.equalTo(0.5) + } + + // A table view will initialize the header with CGSizeZero before applying the actual size. Hence, the label's constraints + // must not impose a minimum width on the content view. + titleLabel.snp.makeConstraints { make in + make.left.equalTo(contentView).offset(SiteTableViewControllerUX.HeaderTextMargin).priority(1000) + make.right.equalTo(contentView).offset(-SiteTableViewControllerUX.HeaderTextMargin).priority(1000) + make.left.greaterThanOrEqualTo(contentView) // Fallback for when the left space constraint breaks + make.right.lessThanOrEqualTo(contentView) // Fallback for when the right space constraint breaks + make.centerY.equalTo(contentView) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +/** + * Provides base shared functionality for site rows and headers. + */ +class SiteTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { + fileprivate let CellIdentifier = "CellIdentifier" + fileprivate let HeaderIdentifier = "HeaderIdentifier" + var profile: Profile! { + didSet { + reloadData() + } + } + var data: Cursor = Cursor(status: .success, msg: "No data set") + var tableView = UITableView() + + override func viewDidLoad() { + super.viewDidLoad() + + view.addSubview(tableView) + tableView.snp.makeConstraints { make in + make.edges.equalTo(self.view) + return + } + + tableView.delegate = self + tableView.dataSource = self + tableView.register(SiteTableViewCell.self, forCellReuseIdentifier: CellIdentifier) + tableView.register(SiteTableViewHeader.self, forHeaderFooterViewReuseIdentifier: HeaderIdentifier) + tableView.layoutMargins = UIEdgeInsets.zero + tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag + tableView.backgroundColor = UIConstants.PanelBackgroundColor + tableView.separatorColor = UIConstants.SeparatorColor + tableView.accessibilityIdentifier = "SiteTable" + tableView.cellLayoutMarginsFollowReadableWidth = false + + // Set an empty footer to prevent empty cells from appearing in the list. + tableView.tableFooterView = UIView() + } + + deinit { + // The view might outlive this view controller thanks to animations; + // explicitly nil out its references to us to avoid crashes. Bug 1218826. + tableView.dataSource = nil + tableView.delegate = nil + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + coordinator.animate(alongsideTransition: { context in + //The AS context menu does not behave correctly. Dismiss it when rotating. + if let _ = self.presentedViewController as? PhotonActionSheet { + self.presentedViewController?.dismiss(animated: true, completion: nil) + } + }, completion: nil) + } + + func reloadData() { + if data.status != .success { + print("Err: \(data.statusMessage)", terminator: "\n") + } else { + self.tableView.reloadData() + } + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return data.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier, for: indexPath) + if self.tableView(tableView, hasFullWidthSeparatorForRowAtIndexPath: indexPath) { + cell.separatorInset = UIEdgeInsets.zero + } + return cell + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + return tableView.dequeueReusableHeaderFooterView(withIdentifier: HeaderIdentifier) + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return SiteTableViewControllerUX.HeaderHeight + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return SiteTableViewControllerUX.RowHeight + } + + func tableView(_ tableView: UITableView, hasFullWidthSeparatorForRowAtIndexPath indexPath: IndexPath) -> Bool { + return false + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/SnackBar.swift b/mobile/ios/Client/Frontend/Widgets/SnackBar.swift new file mode 100644 index 0000000000..5f9609522c --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/SnackBar.swift @@ -0,0 +1,319 @@ +/* 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/. */ + +import Foundation +import SnapKit +import Shared + +class SnackBarUX { + static var MaxWidth: CGFloat = 400 +} + +/** + * A specialized version of UIButton for use in SnackBars. These are displayed evenly + * spaced in the bottom of the bar. The main convenience of these is that you can pass + * in a callback in the constructor (although these also style themselves appropriately). + * + *``SnackButton(title: "OK", { _ in print("OK", terminator: "\n") })`` + */ +class SnackButton: UIButton { + let callback: (_ bar: SnackBar) -> Void + fileprivate var bar: SnackBar! + + /** + * An image to show as the background when a button is pressed. This is currently a 1x1 pixel blue color + */ + lazy var highlightImg: UIImage = { + let size = CGSize(width: 1, height: 1) + return UIImage.createWithColor(size, color: UIConstants.HighlightColor) + }() + + init(title: String, accessibilityIdentifier: String, callback: @escaping (_ bar: SnackBar) -> Void) { + self.callback = callback + + super.init(frame: CGRect.zero) + + setTitle(title, for: UIControlState()) + titleLabel?.font = DynamicFontHelper.defaultHelper.DefaultMediumFont + setBackgroundImage(highlightImg, for: .highlighted) + setTitleColor(UIConstants.HighlightText, for: .highlighted) + + addTarget(self, action: #selector(SnackButton.onClick), for: .touchUpInside) + + self.accessibilityIdentifier = accessibilityIdentifier + } + + override init(frame: CGRect) { + self.callback = { bar in } + super.init(frame: frame) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func onClick() { + callback(bar) + } + +} + +/** + * Presents some information to the user. Can optionally include some buttons and an image. Usage: + * + * ``let bar = SnackBar(text: "This is some text in the snackbar.", + * img: UIImage(named: "bookmark"), + * buttons: [ + * SnackButton(title: "OK", { _ in print("OK", terminator: "\n") }), + * SnackButton(title: "Cancel", { _ in print("Cancel", terminator: "\n") }), + * SnackButton(title: "Maybe", { _ in print("Maybe", terminator: "\n") }) + * ] + * )`` + */ +class SnackBar: UIView { + let imageView: UIImageView + let textLabel: UILabel + let contentView: UIView + let backgroundView: UIView + let buttonsView: Toolbar + fileprivate var buttons = [SnackButton]() + // The Constraint for the bottom of this snackbar. We use this to transition it + var bottom: Constraint? + + convenience init(text: String, img: UIImage?, buttons: [SnackButton]?) { + var attributes = [String: AnyObject]() + attributes[NSFontAttributeName] = DynamicFontHelper.defaultHelper.DefaultMediumFont + attributes[NSBackgroundColorAttributeName] = UIColor.clear + let attrText = NSAttributedString(string: text, attributes: attributes) + self.init(attrText: attrText, img: img, buttons: buttons) + } + + init(attrText: NSAttributedString, img: UIImage?, buttons: [SnackButton]?) { + imageView = UIImageView() + textLabel = UILabel() + contentView = UIView() + buttonsView = Toolbar() + backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.extraLight)) + + super.init(frame: CGRect.zero) + + imageView.image = img + textLabel.attributedText = attrText + if let buttons = buttons { + for button in buttons { + addButton(button) + } + } + setup() + } + + fileprivate override init(frame: CGRect) { + imageView = UIImageView() + textLabel = UILabel() + contentView = UIView() + buttonsView = Toolbar() + backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.extraLight)) + + super.init(frame: frame) + } + + fileprivate func setup() { + textLabel.backgroundColor = nil + + addSubview(backgroundView) + addSubview(contentView) + contentView.addSubview(imageView) + contentView.addSubview(textLabel) + addSubview(buttonsView) + + self.backgroundColor = UIColor.clear + buttonsView.drawTopBorder = true + buttonsView.drawBottomBorder = false + buttonsView.drawSeperators = true + + imageView.contentMode = UIViewContentMode.left + + textLabel.font = DynamicFontHelper.defaultHelper.DefaultMediumFont + textLabel.lineBreakMode = NSLineBreakMode.byWordWrapping + textLabel.numberOfLines = 0 + textLabel.backgroundColor = UIColor.clear + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + let imageWidth: CGFloat + if let img = imageView.image { + imageWidth = img.size.width + UIConstants.DefaultPadding * 2 + } else { + imageWidth = 0 + } + self.textLabel.preferredMaxLayoutWidth = contentView.frame.width - (imageWidth + UIConstants.DefaultPadding) + super.layoutSubviews() + } + + fileprivate func drawLine(_ context: CGContext, start: CGPoint, end: CGPoint) { + context.setStrokeColor(UIConstants.BorderColor.cgColor) + context.setLineWidth(1) + context.move(to: CGPoint(x: start.x, y: start.y)) + context.addLine(to: CGPoint(x: end.x, y: end.y)) + context.strokePath() + } + + override func draw(_ rect: CGRect) { + let context = UIGraphicsGetCurrentContext() + drawLine(context!, start: CGPoint(x: 0, y: 1), end: CGPoint(x: frame.size.width, y: 1)) + } + + /** + * Called to check if the snackbar should be removed or not. By default, Snackbars persist forever. + * Override this class or use a class like CountdownSnackbar if you want things expire + * - returns: true if the snackbar should be kept alive + */ + func shouldPersist(_ tab: Tab) -> Bool { + return true + } + + override func updateConstraints() { + super.updateConstraints() + + backgroundView.snp.remakeConstraints { make in + make.bottom.left.right.equalTo(self) + // Offset it by the width of the top border line so we can see the line from the super view + make.top.equalTo(self).offset(1) + } + + contentView.snp.remakeConstraints { make in + make.top.left.right.equalTo(self).inset(UIEdgeInsets(equalInset: UIConstants.DefaultPadding)) + } + + if let img = imageView.image { + imageView.snp.remakeConstraints { make in + make.left.centerY.equalTo(contentView) + // To avoid doubling the padding, the textview doesn't have an inset on its left side. + // Instead, it relies on the imageView to tell it where its left side should be. + make.width.equalTo(img.size.width + UIConstants.DefaultPadding) + make.height.equalTo(img.size.height + UIConstants.DefaultPadding) + } + } else { + imageView.snp.remakeConstraints { make in + make.width.height.equalTo(0) + make.top.left.equalTo(self) + make.bottom.lessThanOrEqualTo(contentView.snp.bottom) + } + } + + textLabel.snp.remakeConstraints { make in + make.top.equalTo(contentView) + make.left.equalTo(self.imageView.snp.right) + make.trailing.equalTo(contentView) + make.bottom.lessThanOrEqualTo(contentView.snp.bottom) + } + + buttonsView.snp.remakeConstraints { make in + make.top.equalTo(contentView.snp.bottom).offset(UIConstants.DefaultPadding) + make.bottom.equalTo(self.snp.bottom) + make.left.right.equalTo(self) + if self.buttonsView.subviews.count > 0 { + make.height.equalTo(UIConstants.SnackbarButtonHeight) + } else { + make.height.equalTo(0) + } + } + } + + var showing: Bool { + return alpha != 0 && self.superview != nil + } + + /** + * Helper for animating the Snackbar showing on screen. + */ + func show() { + alpha = 1 + bottom?.update(offset: 0) + } + + /** + * Helper for animating the Snackbar leaving the screen. + */ + func hide() { + alpha = 0 + var h = frame.height + if h == 0 { + h = UIConstants.ToolbarHeight + } + bottom?.update(offset: h) + } + + fileprivate func addButton(_ snackButton: SnackButton) { + snackButton.bar = self + buttonsView.addButtons([snackButton]) + buttonsView.setNeedsUpdateConstraints() + } +} + +/** + * A special version of a snackbar that persists for at least a timeout. After that + * it will dismiss itself on the next page load where this tab isn't showing. As long as + * you stay on the current tab though, it will persist until you interact with it. + */ +class TimerSnackBar: SnackBar { + fileprivate var prevURL: URL? + fileprivate var timer: Timer? + fileprivate var timeout: TimeInterval + + init(timeout: TimeInterval = 10, attrText: NSAttributedString, img: UIImage?, buttons: [SnackButton]?) { + self.timeout = timeout + super.init(attrText: attrText, img: img, buttons: buttons) + } + + override init(frame: CGRect) { + self.timeout = 0 + super.init(frame: frame) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + static func showAppStoreConfirmationBar(forTab tab: Tab, appStoreURL: URL) { + let msg = NSAttributedString(string: Strings.ExternalLinkAppStoreConfirmationTitle, attributes: [NSForegroundColorAttributeName: UIConstants.TableViewRowTextColor]) + let bar = TimerSnackBar(attrText: msg, + img: UIImage(named: "defaultFavicon"), + buttons: [ + SnackButton(title: UIConstants.OKString, accessibilityIdentifier: "ConfirmOpenInAppStore", callback: { bar in + tab.removeSnackbar(bar) + UIApplication.shared.openURL(appStoreURL) + }), + SnackButton(title: UIConstants.CancelString, accessibilityIdentifier: "CancelOpenInAppStore", callback: { bar in + tab.removeSnackbar(bar) + }) + ]) + + tab.addSnackbar(bar) + } + + override func show() { + self.timer = Timer(timeInterval: timeout, target: self, selector: #selector(TimerSnackBar.SELTimerDone), userInfo: nil, repeats: false) + RunLoop.current.add(self.timer!, forMode: RunLoopMode.defaultRunLoopMode) + super.show() + } + + @objc + func SELTimerDone() { + self.timer = nil + } + + override func shouldPersist(_ tab: Tab) -> Bool { + if !showing { + return timer != nil + } + + return super.shouldPersist(tab) + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/TabsButton.swift b/mobile/ios/Client/Frontend/Widgets/TabsButton.swift new file mode 100644 index 0000000000..1641626ed4 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/TabsButton.swift @@ -0,0 +1,255 @@ +/* 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/. */ + +import Foundation +import SnapKit +import Shared +import XCGLogger + +private let log = Logger.browserLogger + +struct TabsButtonUX { + static let TitleColor: UIColor = UIColor(rgb: 0x272727) + static let TitleBackgroundColor: UIColor = UIColor.white + static let CornerRadius: CGFloat = 2 + static let TitleFont: UIFont = UIConstants.DefaultChromeSmallFontBold + static let BorderStrokeWidth: CGFloat = 3 + static let BorderColor: UIColor = UIColor.darkGray + static let TitleInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) + + static let Themes: [String: Theme] = { + var themes = [String: Theme]() + var theme = Theme() + theme.borderColor = UIColor(rgb: 0xD2D2D4) + theme.backgroundColor = UIColor(rgb: 0x38383D) + theme.textColor = UIColor(rgb: 0xD2D2D4) + theme.highlightButtonColor = UIConstants.PrivateModePurple + theme.highlightTextColor = TabsButtonUX.TitleColor + theme.highlightBorderColor = UIConstants.PrivateModePurple + themes[Theme.PrivateMode] = theme + + theme = Theme() + theme.borderColor = UIColor(rgb: 0x272727) + theme.backgroundColor = UIConstants.AppBackgroundColor + theme.textColor = UIColor(rgb: 0x272727) + theme.highlightButtonColor = TabsButtonUX.TitleColor + theme.highlightTextColor = TabsButtonUX.TitleBackgroundColor + theme.highlightBorderColor = TabsButtonUX.TitleColor + themes[Theme.NormalMode] = theme + + return themes + }() +} + +class TabsButton: UIButton { + + var textColor = UIColor.white { + didSet { + countLabel.textColor = textColor + borderView.color = textColor + } + } + var titleBackgroundColor = UIColor.white { + didSet { + labelBackground.backgroundColor = titleBackgroundColor + } + } + var highlightTextColor: UIColor? + var highlightBackgroundColor: UIColor? + + override var isHighlighted: Bool { + didSet { + if isHighlighted { + countLabel.textColor = textColor + borderView.color = titleBackgroundColor + labelBackground.backgroundColor = titleBackgroundColor + } else { + countLabel.textColor = textColor + borderView.color = textColor + labelBackground.backgroundColor = titleBackgroundColor + } + } + } + + override var transform: CGAffineTransform { + didSet { + clonedTabsButton?.transform = transform + } + } + + lazy var countLabel: UILabel = { + let label = UILabel() + label.font = TabsButtonUX.TitleFont + label.layer.cornerRadius = TabsButtonUX.CornerRadius + label.textAlignment = NSTextAlignment.center + label.isUserInteractionEnabled = false + return label + }() + + lazy var insideButton: UIView = { + let view = UIView() + view.clipsToBounds = false + view.isUserInteractionEnabled = false + return view + }() + + fileprivate lazy var labelBackground: UIView = { + let background = UIView() + background.layer.cornerRadius = TabsButtonUX.CornerRadius + background.isUserInteractionEnabled = false + return background + }() + + fileprivate lazy var borderView: InnerStrokedView = { + let border = InnerStrokedView() + border.strokeWidth = TabsButtonUX.BorderStrokeWidth + border.cornerRadius = TabsButtonUX.CornerRadius + border.isUserInteractionEnabled = false + return border + }() + + // Used to temporarily store the cloned button so we can respond to layout changes during animation + fileprivate weak var clonedTabsButton: TabsButton? + + override init(frame: CGRect) { + super.init(frame: frame) + insideButton.addSubview(labelBackground) + insideButton.addSubview(borderView) + insideButton.addSubview(countLabel) + addSubview(insideButton) + isAccessibilityElement = true + accessibilityTraits |= UIAccessibilityTraitButton + } + + override func updateConstraints() { + super.updateConstraints() + labelBackground.snp.remakeConstraints { (make) -> Void in + make.edges.equalTo(insideButton) + } + borderView.snp.remakeConstraints { (make) -> Void in + make.edges.equalTo(insideButton) + } + countLabel.snp.remakeConstraints { (make) -> Void in + make.edges.equalTo(insideButton) + } + insideButton.snp.remakeConstraints { (make) -> Void in + make.size.equalTo(24) + make.center.equalTo(self) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func clone() -> UIView { + let button = TabsButton() + + button.accessibilityLabel = accessibilityLabel + button.countLabel.text = countLabel.text + + // Copy all of the styable properties over to the new TabsButton + button.countLabel.font = countLabel.font + button.countLabel.textColor = countLabel.textColor + button.countLabel.layer.cornerRadius = countLabel.layer.cornerRadius + + button.labelBackground.backgroundColor = labelBackground.backgroundColor + button.labelBackground.layer.cornerRadius = labelBackground.layer.cornerRadius + + button.borderView.strokeWidth = borderView.strokeWidth + button.borderView.color = borderView.color + button.borderView.cornerRadius = borderView.cornerRadius + + return button + } + + func updateTabCount(_ count: Int, animated: Bool = true) { + let count = max(count, 1) + let currentCount = self.countLabel.text + let infinity = "\u{221E}" + let countToBe = (count < 100) ? count.description : infinity + + // only animate a tab count change if the tab count has actually changed + if currentCount != count.description || (clonedTabsButton?.countLabel.text ?? count.description) != count.description { + if let _ = self.clonedTabsButton { + self.clonedTabsButton?.layer.removeAllAnimations() + self.clonedTabsButton?.removeFromSuperview() + insideButton.layer.removeAllAnimations() + } + + // make a 'clone' of the tabs button + let newTabsButton = clone() as! TabsButton + + self.clonedTabsButton = newTabsButton + newTabsButton.frame = self.bounds + newTabsButton.addTarget(self, action: #selector(TabsButton.cloneDidClickTabs), for: UIControlEvents.touchUpInside) + newTabsButton.countLabel.text = countToBe + newTabsButton.accessibilityValue = countToBe + newTabsButton.insideButton.frame = self.insideButton.frame + newTabsButton.snp.removeConstraints() + self.addSubview(newTabsButton) + newTabsButton.snp.makeConstraints { make in + make.center.equalTo(self) + } + + // Instead of changing the anchorPoint of the CALayer, lets alter the rotation matrix math to be + // a rotation around a non-origin point + let frame = self.insideButton.frame + let halfTitleHeight = frame.height / 2 + var newFlipTransform = CATransform3DIdentity + newFlipTransform = CATransform3DTranslate(newFlipTransform, 0, halfTitleHeight, 0) + newFlipTransform.m34 = -1.0 / 200.0 // add some perspective + newFlipTransform = CATransform3DRotate(newFlipTransform, CGFloat(-(Double.pi / 2)), 1.0, 0.0, 0.0) + newTabsButton.insideButton.layer.transform = newFlipTransform + + var oldFlipTransform = CATransform3DIdentity + oldFlipTransform = CATransform3DTranslate(oldFlipTransform, 0, halfTitleHeight, 0) + oldFlipTransform.m34 = -1.0 / 200.0 // add some perspective + oldFlipTransform = CATransform3DRotate(oldFlipTransform, CGFloat(-(Double.pi / 2)), 1.0, 0.0, 0.0) + + let animate = { + newTabsButton.insideButton.layer.transform = CATransform3DIdentity + self.insideButton.layer.transform = oldFlipTransform + self.insideButton.layer.opacity = 0 + } + + let completion: (Bool) -> Void = { completed in + let noActiveAnimations = self.insideButton.layer.animationKeys()?.isEmpty ?? true + if completed || noActiveAnimations { + newTabsButton.removeFromSuperview() + self.insideButton.layer.opacity = 1 + self.insideButton.layer.transform = CATransform3DIdentity + } + self.accessibilityLabel = NSLocalizedString("Show Tabs", comment: "Accessibility label for the tabs button in the (top) tab toolbar") + self.countLabel.text = countToBe + self.accessibilityValue = countToBe + } + + if animated { + UIView.animate(withDuration: 1.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: UIViewAnimationOptions(), animations: animate, completion: completion) + } else { + completion(true) + } + } + } + func cloneDidClickTabs() { + sendActions(for: UIControlEvents.touchUpInside) + } +} + +extension TabsButton: Themeable { + func applyTheme(_ themeName: String) { + guard let theme = TabsButtonUX.Themes[themeName] else { + fatalError("Theme not found") + } + titleBackgroundColor = theme.backgroundColor! + textColor = theme.textColor! + + countLabel.textColor = textColor + borderView.color = textColor + labelBackground.backgroundColor = titleBackgroundColor + + } +} + diff --git a/mobile/ios/Client/Frontend/Widgets/Theme.swift b/mobile/ios/Client/Frontend/Widgets/Theme.swift new file mode 100644 index 0000000000..1fe0ae4916 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/Theme.swift @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import Foundation + +struct Theme { + var URLFontColor: UIColor? + var hostFontColor: UIColor? + var backgroundColor: UIColor? + var textColor: UIColor? + var highlightColor: UIColor? + var tintColor: UIColor? + var buttonTintColor: UIColor? + var activeBorderColor: UIColor? + var borderColor: UIColor? + var highlightButtonColor: UIColor? + var highlightBorderColor: UIColor? + var highlightTextColor: UIColor? + var disabledButtonColor: UIColor? + + static let PrivateMode = "Private" + static let NormalMode = "Normal" +} diff --git a/mobile/ios/Client/Frontend/Widgets/ToggleButton.swift b/mobile/ios/Client/Frontend/Widgets/ToggleButton.swift new file mode 100644 index 0000000000..1e61b08ab2 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/ToggleButton.swift @@ -0,0 +1,126 @@ +/* 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/. */ + +import UIKit + +private struct UX { + static let TopColor = UIColor(red: 179 / 255, green: 83 / 255, blue: 253 / 255, alpha: 1) + static let BottomColor = UIColor(red: 146 / 255, green: 16 / 255, blue: 253, alpha: 1) + + // The amount of pixels the toggle button will expand over the normal size. This results in the larger -> contract animation. + static let ExpandDelta: CGFloat = 5 + static let ShowDuration: TimeInterval = 0.4 + static let HideDuration: TimeInterval = 0.2 + + static let BackgroundSize = CGSize(width: 32, height: 32) +} + +class ToggleButton: UIButton { + func setSelected(_ selected: Bool, animated: Bool = true) { + self.isSelected = selected + if animated { + animateSelection(selected) + } + } + + fileprivate func updateMaskPathForSelectedState(_ selected: Bool) { + let path = CGMutablePath() + if selected { + var rect = CGRect(origin: CGPoint.zero, size: UX.BackgroundSize) + rect.center = maskShapeLayer.position + path.addEllipse(in: rect) + } else { + path.addEllipse(in: CGRect(origin: maskShapeLayer.position, size: CGSize.zero)) + } + self.maskShapeLayer.path = path + } + + fileprivate func animateSelection(_ selected: Bool) { + var endFrame = CGRect(origin: CGPoint.zero, size: UX.BackgroundSize) + endFrame.center = maskShapeLayer.position + + if selected { + let animation = CAKeyframeAnimation(keyPath: "path") + + let startPath = CGMutablePath() + startPath.addEllipse(in: CGRect(origin: maskShapeLayer.position, size: CGSize.zero)) + + let largerPath = CGMutablePath() + let largerBounds = endFrame.insetBy(dx: -UX.ExpandDelta, dy: -UX.ExpandDelta) + largerPath.addEllipse(in: largerBounds) + + let endPath = CGMutablePath() + endPath.addEllipse(in: endFrame) + + animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) + animation.values = [ + startPath, + largerPath, + endPath + ] + animation.duration = UX.ShowDuration + self.maskShapeLayer.path = endPath + self.maskShapeLayer.add(animation, forKey: "grow") + } else { + let animation = CABasicAnimation(keyPath: "path") + animation.duration = UX.HideDuration + animation.fillMode = kCAFillModeForwards + + let fromPath = CGMutablePath() + fromPath.addEllipse(in: endFrame) + animation.fromValue = fromPath + animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) + + let toPath = CGMutablePath() + toPath.addEllipse(in: CGRect(origin: self.maskShapeLayer.bounds.center, size: CGSize.zero)) + + self.maskShapeLayer.path = toPath + self.maskShapeLayer.add(animation, forKey: "shrink") + } + } + + lazy fileprivate var backgroundView: UIView = { + let view = UIView() + view.isUserInteractionEnabled = false + view.layer.addSublayer(self.gradientLayer) + return view + }() + + lazy fileprivate var maskShapeLayer: CAShapeLayer = { + let circle = CAShapeLayer() + return circle + }() + + lazy fileprivate var gradientLayer: CAGradientLayer = { + let gradientLayer = CAGradientLayer() + gradientLayer.colors = [UX.TopColor.cgColor, UX.BottomColor.cgColor] + gradientLayer.mask = self.maskShapeLayer + return gradientLayer + }() + + override init(frame: CGRect) { + super.init(frame: frame) + contentMode = UIViewContentMode.redraw + insertSubview(backgroundView, belowSubview: imageView!) + } + + override func layoutSubviews() { + super.layoutSubviews() + let zeroFrame = CGRect(origin: CGPoint.zero, size: frame.size) + backgroundView.frame = zeroFrame + + // Make the gradient larger than normal to allow the mask transition to show when it blows up + // a little larger than the resting size + gradientLayer.bounds = backgroundView.frame.insetBy(dx: -UX.ExpandDelta, dy: -UX.ExpandDelta) + maskShapeLayer.bounds = backgroundView.frame + gradientLayer.position = CGPoint(x: zeroFrame.midX, y: zeroFrame.midY) + maskShapeLayer.position = CGPoint(x: zeroFrame.midX, y: zeroFrame.midY) + + updateMaskPathForSelectedState(isSelected) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/Toolbar.swift b/mobile/ios/Client/Frontend/Widgets/Toolbar.swift new file mode 100644 index 0000000000..3799baaa93 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/Toolbar.swift @@ -0,0 +1,93 @@ +/* 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/. */ + +import Foundation +import SnapKit + +class Toolbar: UIView { + var drawTopBorder = false + var drawBottomBorder = false + var drawSeperators = false + + override init(frame: CGRect) { + super.init(frame: frame) + self.backgroundColor = UIColor.clear + + // Allow the view to redraw itself on rotation changes + contentMode = UIViewContentMode.redraw + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + fileprivate func drawLine(_ context: CGContext, width: CGFloat, start: CGPoint, end: CGPoint) { + context.setStrokeColor(UIConstants.BorderColor.cgColor) + context.setLineWidth(width * (1 / UIScreen.main.scale) ) + context.move(to: CGPoint(x: start.x, y: start.y)) + context.addLine(to: CGPoint(x: end.x, y: end.y)) + context.strokePath() + } + + override func draw(_ rect: CGRect) { + if let context = UIGraphicsGetCurrentContext() { + if drawTopBorder { + drawLine(context, width: 1, start: CGPoint(x: 0, y: 0), end: CGPoint(x: frame.width, y: 0)) + } + + if drawBottomBorder { + drawLine(context, width: 1, start: CGPoint(x: 0, y: frame.height), end: CGPoint(x: frame.width, y: frame.height)) + } + + if drawSeperators { + var skippedFirst = false + for view in subviews { + if skippedFirst { + let frame = view.frame + drawLine(context, + width: 0.5, + start: CGPoint(x: floor(frame.origin.x), y: 0), + end: CGPoint(x: floor(frame.origin.x), y: self.frame.height)) + } else { + skippedFirst = true + } + } + } + } + } + + func addButtons(_ buttons: [UIButton]) { + for button in buttons { + button.setTitleColor(UIColor.black, for: UIControlState()) + button.setTitleColor(UIColor.gray, for: UIControlState.disabled) + button.imageView?.contentMode = UIViewContentMode.scaleAspectFit + addSubview(button) + } + } + + override func updateConstraints() { + var prev: UIView? = nil + for view in self.subviews { + view.snp.remakeConstraints { make in + if let prev = prev { + make.left.equalTo(prev.snp.right) + } else { + make.left.equalTo(self) + } + prev = view + + var bottomInset: CGFloat = 0.0 + if #available(iOS 11, *) { + if let window = UIApplication.shared.keyWindow { + bottomInset = window.safeAreaInsets.bottom + } + } + make.top.equalTo(self) + make.height.equalTo(UIConstants.BottomToolbarHeight - bottomInset) + make.width.equalTo(self).dividedBy(self.subviews.count) + } + } + super.updateConstraints() + } +} diff --git a/mobile/ios/Client/Frontend/Widgets/TwoLineCell.swift b/mobile/ios/Client/Frontend/Widgets/TwoLineCell.swift new file mode 100644 index 0000000000..0654ef31d2 --- /dev/null +++ b/mobile/ios/Client/Frontend/Widgets/TwoLineCell.swift @@ -0,0 +1,263 @@ +/* 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/. */ + +import UIKit + +struct TwoLineCellUX { + static let ImageSize: CGFloat = 29 + static let ImageCornerRadius: CGFloat = 8 + static let BorderViewMargin: CGFloat = 16 + static let BadgeSize: CGFloat = 16 + static let BadgeMargin: CGFloat = 16 + static let BorderFrameSize: CGFloat = 32 + static let TextColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.black : UIColor(rgb: 0x333333) + static let DetailTextColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.darkGray : UIColor.gray + static let DetailTextTopMargin: CGFloat = 0 +} + +class TwoLineTableViewCell: UITableViewCell { + fileprivate let twoLineHelper = TwoLineCellHelper() + + let _textLabel = UILabel() + let _detailTextLabel = UILabel() + + // Override the default labels with our own to disable default UITableViewCell label behaviours like dynamic type + override var textLabel: UILabel? { + return _textLabel + } + + override var detailTextLabel: UILabel? { + return _detailTextLabel + } + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: UITableViewCellStyle.subtitle, reuseIdentifier: reuseIdentifier) + + contentView.addSubview(_textLabel) + contentView.addSubview(_detailTextLabel) + + twoLineHelper.setUpViews(self, textLabel: textLabel!, detailTextLabel: detailTextLabel!, imageView: imageView!) + + indentationWidth = 0 + layoutMargins = UIEdgeInsets.zero + + separatorInset = UIEdgeInsets(top: 0, left: TwoLineCellUX.ImageSize + 2 * TwoLineCellUX.BorderViewMargin, bottom: 0, right: 0) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + twoLineHelper.layoutSubviews() + } + + override func prepareForReuse() { + super.prepareForReuse() + self.textLabel!.alpha = 1 + self.imageView!.alpha = 1 + self.selectionStyle = .default + separatorInset = UIEdgeInsets(top: 0, left: TwoLineCellUX.ImageSize + 2 * TwoLineCellUX.BorderViewMargin, bottom: 0, right: 0) + twoLineHelper.setupDynamicFonts() + } + + // Save background color on UITableViewCell "select" because it disappears in the default behavior + override func setHighlighted(_ highlighted: Bool, animated: Bool) { + let color = imageView?.backgroundColor + super.setHighlighted(highlighted, animated: animated) + imageView?.backgroundColor = color + } + + // Save background color on UITableViewCell "select" because it disappears in the default behavior + override func setSelected(_ selected: Bool, animated: Bool) { + let color = imageView?.backgroundColor + super.setSelected(selected, animated: animated) + imageView?.backgroundColor = color + } + + func setRightBadge(_ badge: UIImage?) { + if let badge = badge { + self.accessoryView = UIImageView(image: badge) + } else { + self.accessoryView = nil + } + twoLineHelper.hasRightBadge = badge != nil + } + + func setLines(_ text: String?, detailText: String?) { + twoLineHelper.setLines(text, detailText: detailText) + } + + func mergeAccessibilityLabels(_ views: [AnyObject?]? = nil) { + twoLineHelper.mergeAccessibilityLabels(views) + } +} + +class SiteTableViewCell: TwoLineTableViewCell { + let borderView = UIView() + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: UITableViewCellStyle.subtitle, reuseIdentifier: reuseIdentifier) + twoLineHelper.setUpViews(self, textLabel: textLabel!, detailTextLabel: detailTextLabel!, imageView: imageView!) + } + + override func layoutSubviews() { + super.layoutSubviews() + twoLineHelper.layoutSubviews() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +class TwoLineHeaderFooterView: UITableViewHeaderFooterView { + fileprivate let twoLineHelper = TwoLineCellHelper() + + // UITableViewHeaderFooterView includes textLabel and detailTextLabel, so we can't override + // them. Unfortunately, they're also used in ways that interfere with us just using them: I get + // hard crashes in layout if I just use them; it seems there's a battle over adding to the + // contentView. So we add our own members, and cover up the other ones. + let _textLabel = UILabel() + let _detailTextLabel = UILabel() + + let imageView = UIImageView() + + // Yes, this is strange. + override var textLabel: UILabel? { + return _textLabel + } + + // Yes, this is strange. + override var detailTextLabel: UILabel? { + return _detailTextLabel + } + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + twoLineHelper.setUpViews(self, textLabel: _textLabel, detailTextLabel: _detailTextLabel, imageView: imageView) + + contentView.addSubview(_textLabel) + contentView.addSubview(_detailTextLabel) + contentView.addSubview(imageView) + + layoutMargins = UIEdgeInsets.zero + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + twoLineHelper.layoutSubviews() + } + + override func prepareForReuse() { + super.prepareForReuse() + twoLineHelper.setupDynamicFonts() + } + + func mergeAccessibilityLabels(_ views: [AnyObject?]? = nil) { + twoLineHelper.mergeAccessibilityLabels(views) + } +} + +private class TwoLineCellHelper { + weak var container: UIView? + var textLabel: UILabel! + var detailTextLabel: UILabel! + var imageView: UIImageView! + var hasRightBadge: Bool = false + + // TODO: Not ideal. We should figure out a better way to get this initialized. + func setUpViews(_ container: UIView, textLabel: UILabel, detailTextLabel: UILabel, imageView: UIImageView) { + self.container = container + self.textLabel = textLabel + self.detailTextLabel = detailTextLabel + self.imageView = imageView + + if let headerView = self.container as? UITableViewHeaderFooterView { + headerView.contentView.backgroundColor = UIColor.clear + } else { + self.container?.backgroundColor = UIColor.clear + } + + textLabel.textColor = TwoLineCellUX.TextColor + detailTextLabel.textColor = TwoLineCellUX.DetailTextColor + setupDynamicFonts() + + imageView.contentMode = .scaleAspectFill + imageView.layer.cornerRadius = 6 //hmm + imageView.layer.masksToBounds = true + } + + func setupDynamicFonts() { + textLabel.font = DynamicFontHelper.defaultHelper.DeviceFontHistoryPanel + detailTextLabel.font = DynamicFontHelper.defaultHelper.SmallSizeRegularWeightAS + } + + func layoutSubviews() { + guard let container = self.container else { + return + } + let height = container.frame.height + let textLeft = TwoLineCellUX.ImageSize + 2 * TwoLineCellUX.BorderViewMargin + let textLabelHeight = textLabel.intrinsicContentSize.height + let detailTextLabelHeight = detailTextLabel.intrinsicContentSize.height + var contentHeight = textLabelHeight + if detailTextLabelHeight > 0 { + contentHeight += detailTextLabelHeight + TwoLineCellUX.DetailTextTopMargin + } + + let textRightInset: CGFloat = hasRightBadge ? (TwoLineCellUX.BadgeSize + TwoLineCellUX.BadgeMargin) : 0 + + imageView.frame = CGRect(x: TwoLineCellUX.BorderViewMargin, y: (height - TwoLineCellUX.ImageSize) / 2, width: TwoLineCellUX.ImageSize, height: TwoLineCellUX.ImageSize) + textLabel.frame = CGRect(x: textLeft, y: (height - contentHeight) / 2, + width: container.frame.width - textLeft - TwoLineCellUX.BorderViewMargin - textRightInset, height: textLabelHeight) + detailTextLabel.frame = CGRect(x: textLeft, y: textLabel.frame.maxY + TwoLineCellUX.DetailTextTopMargin, + width: container.frame.width - textLeft - TwoLineCellUX.BorderViewMargin - textRightInset, height: detailTextLabelHeight) + } + + func setLines(_ text: String?, detailText: String?) { + if text?.isEmpty ?? true { + textLabel.text = detailText + detailTextLabel.text = nil + } else { + textLabel.text = text + detailTextLabel.text = detailText + } + } + + func mergeAccessibilityLabels(_ labels: [AnyObject?]?) { + let labels = labels ?? [textLabel, imageView, detailTextLabel] + + let label = labels.map({ (label: AnyObject?) -> NSAttributedString? in + var label = label + if let view = label as? UIView { + label = view.value(forKey: "accessibilityLabel") as (AnyObject?) + } + + if let attrString = label as? NSAttributedString { + return attrString + } else if let string = label as? String { + return NSAttributedString(string: string) + } else { + return nil + } + }).filter({ + $0 != nil + }).reduce(NSMutableAttributedString(string: ""), { + if $0.length > 0 { + $0.append(NSAttributedString(string: ", ")) + } + $0.append($1!) + return $0 + }) + + container?.isAccessibilityElement = true + container?.setValue(NSAttributedString(attributedString: label), forKey: "accessibilityLabel") + } +} diff --git a/mobile/ios/Client/Helpers/DynamicFontHelper.swift b/mobile/ios/Client/Helpers/DynamicFontHelper.swift new file mode 100644 index 0000000000..8fd304011f --- /dev/null +++ b/mobile/ios/Client/Helpers/DynamicFontHelper.swift @@ -0,0 +1,195 @@ +/* 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/. */ + +import Foundation +import Shared + +let NotificationDynamicFontChanged = Notification.Name("NotificationDynamicFontChanged") + +private let iPadFactor: CGFloat = 1.06 +private let iPhoneFactor: CGFloat = 0.88 + +class DynamicFontHelper: NSObject { + + static var defaultHelper: DynamicFontHelper { + struct Singleton { + static let instance = DynamicFontHelper() + } + return Singleton.instance + } + + override init() { + defaultStandardFontSize = UIFontDescriptor.preferredFontDescriptor(withTextStyle: UIFontTextStyle.body).pointSize // 14pt -> 17pt -> 23pt + deviceFontSize = defaultStandardFontSize * (UIDevice.current.userInterfaceIdiom == .pad ? iPadFactor : iPhoneFactor) + defaultMediumFontSize = UIFontDescriptor.preferredFontDescriptor(withTextStyle: UIFontTextStyle.footnote).pointSize // 12pt -> 13pt -> 19pt + defaultSmallFontSize = UIFontDescriptor.preferredFontDescriptor(withTextStyle: UIFontTextStyle.caption2).pointSize // 11pt -> 11pt -> 17pt + + super.init() + } + + /** + * Starts monitoring the ContentSizeCategory chantes + */ + func startObserving() { + NotificationCenter.default.addObserver(self, selector: #selector(DynamicFontHelper.SELcontentSizeCategoryDidChange(_:)), name: NSNotification.Name.UIContentSizeCategoryDidChange, object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + /** + * Device specific + */ + fileprivate var deviceFontSize: CGFloat + var DeviceFontSize: CGFloat { + return deviceFontSize + } + var DeviceFont: UIFont { + return UIFont.systemFont(ofSize: deviceFontSize, weight: UIFontWeightMedium) + } + var DeviceFontLight: UIFont { + return UIFont.systemFont(ofSize: deviceFontSize, weight: UIFontWeightLight) + } + var DeviceFontSmall: UIFont { + return UIFont.systemFont(ofSize: deviceFontSize - 1, weight: UIFontWeightMedium) + } + var DeviceFontSmallLight: UIFont { + return UIFont.systemFont(ofSize: deviceFontSize - 1, weight: UIFontWeightLight) + } + var DeviceFontSmallHistoryPanel: UIFont { + return UIFont.systemFont(ofSize: deviceFontSize - 3, weight: UIFontWeightLight) + } + var DeviceFontHistoryPanel: UIFont { + return UIFont.systemFont(ofSize: deviceFontSize) + } + var DeviceFontSmallBold: UIFont { + return UIFont.boldSystemFont(ofSize: deviceFontSize - 1) + } + var DeviceFontLarge: UIFont { + return UIFont.systemFont(ofSize: deviceFontSize + 3) + } + var DeviceFontMedium: UIFont { + return UIFont.systemFont(ofSize: deviceFontSize + 1) + } + var DeviceFontLargeBold: UIFont { + return UIFont.boldSystemFont(ofSize: deviceFontSize + 2) + } + var DeviceFontMediumBold: UIFont { + return UIFont.boldSystemFont(ofSize: deviceFontSize + 1) + } + var DeviceFontExtraLargeBold: UIFont { + return UIFont.boldSystemFont(ofSize: deviceFontSize + 4) + } + + /* + Activity Stream supports dynamic fonts up to a certain point. Large fonts dont work. + Max out the supported font size. + Small = 14, medium = 18, larger = 20 + */ + + var MediumSizeRegularWeightAS: UIFont { + let size = min(deviceFontSize, 18) + return UIFont.systemFont(ofSize: size) + } + + var LargeSizeRegularWeightAS: UIFont { + let size = min(deviceFontSize + 2, 20) + return UIFont.systemFont(ofSize: size) + } + + var MediumSizeHeavyWeightAS: UIFont { + let size = min(deviceFontSize + 2, 18) + return UIFont.systemFont(ofSize: size, weight: UIFontWeightHeavy) + } + var SmallSizeMediumWeightAS: UIFont { + let size = min(defaultSmallFontSize, 14) + return UIFont.systemFont(ofSize: size, weight: UIFontWeightMedium) + } + + var MediumSizeBoldFontAS: UIFont { + let size = min(deviceFontSize, 18) + return UIFont.boldSystemFont(ofSize: size) + } + + var SmallSizeRegularWeightAS: UIFont { + let size = min(defaultSmallFontSize, 14) + return UIFont.systemFont(ofSize: size) + } + + /** + * Small + */ + fileprivate var defaultSmallFontSize: CGFloat + var DefaultSmallFontSize: CGFloat { + return defaultSmallFontSize + } + var DefaultSmallFont: UIFont { + return UIFont.systemFont(ofSize: defaultSmallFontSize, weight: UIFontWeightRegular) + } + var DefaultSmallFontBold: UIFont { + return UIFont.boldSystemFont(ofSize: defaultSmallFontSize) + } + + /** + * Medium + */ + fileprivate var defaultMediumFontSize: CGFloat + var DefaultMediumFontSize: CGFloat { + return defaultMediumFontSize + } + var DefaultMediumFont: UIFont { + return UIFont.systemFont(ofSize: defaultMediumFontSize, weight: UIFontWeightRegular) + } + var DefaultMediumBoldFont: UIFont { + return UIFont.boldSystemFont(ofSize: defaultMediumFontSize) + } + + /** + * Standard + */ + fileprivate var defaultStandardFontSize: CGFloat + var DefaultStandardFontSize: CGFloat { + return defaultStandardFontSize + } + var DefaultStandardFont: UIFont { + return UIFont.systemFont(ofSize: defaultStandardFontSize, weight: UIFontWeightRegular) + } + var DefaultStandardFontBold: UIFont { + return UIFont.boldSystemFont(ofSize: defaultStandardFontSize) + } + + /** + * Reader mode + */ + var ReaderStandardFontSize: CGFloat { + return defaultStandardFontSize - 2 + } + var ReaderBigFontSize: CGFloat { + return defaultStandardFontSize + 5 + } + + /** + * Intro mode + */ + var IntroStandardFontSize: CGFloat { + return min(defaultStandardFontSize - 1, 16) + } + var IntroBigFontSize: CGFloat { + return min(defaultStandardFontSize + 1, 18) + } + + func refreshFonts() { + defaultStandardFontSize = UIFontDescriptor.preferredFontDescriptor(withTextStyle: UIFontTextStyle.body).pointSize + deviceFontSize = defaultStandardFontSize * (UIDevice.current.userInterfaceIdiom == .pad ? iPadFactor : iPhoneFactor) + defaultMediumFontSize = UIFontDescriptor.preferredFontDescriptor(withTextStyle: UIFontTextStyle.footnote).pointSize + defaultSmallFontSize = UIFontDescriptor.preferredFontDescriptor(withTextStyle: UIFontTextStyle.caption2).pointSize + } + + func SELcontentSizeCategoryDidChange(_ notification: Notification) { + refreshFonts() + let notification = Notification(name: NotificationDynamicFontChanged, object: nil) + NotificationCenter.default.post(notification) + } +} diff --git a/mobile/ios/Client/Helpers/FxALoginHelper.swift b/mobile/ios/Client/Helpers/FxALoginHelper.swift new file mode 100644 index 0000000000..347de6b95c --- /dev/null +++ b/mobile/ios/Client/Helpers/FxALoginHelper.swift @@ -0,0 +1,356 @@ +/* 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/. */ + +import Account +import Deferred +import Foundation +import Shared +import SwiftyJSON +import Sync +import UserNotifications +import XCGLogger + +private let applicationDidRequestUserNotificationPermissionPrefKey = "applicationDidRequestUserNotificationPermissionPrefKey" + +private let log = Logger.browserLogger + +private let verificationPollingInterval = DispatchTimeInterval.seconds(3) +private let verificationMaxRetries = 100 // Poll every 3 seconds for 5 minutes. + +protocol FxAPushLoginDelegate: class { + func accountLoginDidFail() + + func accountLoginDidSucceed(withFlags flags: FxALoginFlags) +} + +/// Small struct to keep together the immediately actionable flags that the UI is likely to immediately +/// following a successful login. This is not supposed to be a long lived object. +struct FxALoginFlags { + let pushEnabled: Bool + let verified: Bool +} + +enum PushNotificationError: MaybeErrorType { + case registrationFailed + case userDisallowed + case wrongOSVersion + + var description: String { + switch self { + case .registrationFailed: + return "The OS was unable to complete APNS registration" + case .userDisallowed: + return "User refused permission for notifications" + case .wrongOSVersion: + return "The version of iOS is not recent enough" + } + } +} + +/// This class manages the from successful login for FxAccounts to +/// asking the user for notification permissions, registering for +/// remote push notifications (APNS), then creating an account and +/// storing it in the profile. +class FxALoginHelper { + static var sharedInstance: FxALoginHelper = { + return FxALoginHelper() + }() + + weak var delegate: FxAPushLoginDelegate? + + fileprivate weak var profile: Profile? + + fileprivate var account: FirefoxAccount! + + fileprivate var accountVerified: Bool! + + fileprivate var pushClient: PushClient? { + guard let pushConfiguration = self.getPushConfiguration() ?? self.profile?.accountConfiguration.pushConfiguration, + let accountConfiguration = self.profile?.accountConfiguration else { + log.error("Push server endpoint could not be found") + return nil + } + + // Experimental mode needs: a) the scheme to be Fennec, and b) the accountConfiguration to be flipped in debug mode. + let experimentalMode = (pushConfiguration.label == .fennec && accountConfiguration.label == .latestDev) + return PushClient(endpointURL: pushConfiguration.endpointURL, experimentalMode: experimentalMode) + } + + fileprivate var apnsTokenDeferred: Deferred>! + + // This should be called when the application has started. + // This configures the helper for logging into Firefox Accounts, and + // if already logged in, checking if anything needs to be done in response + // to changing of user settings and push notifications. + func application(_ application: UIApplication, didLoadProfile profile: Profile) { + self.profile = profile + self.account = profile.getAccount() + + self.apnsTokenDeferred = Deferred() + + guard let account = self.account else { + // There's no account, no further action. + return loginDidFail() + } + + // accountVerified is needed by delegates. + accountVerified = account.actionNeeded != .needsVerification + + guard AppConstants.MOZ_FXA_PUSH else { + return loginDidSucceed() + } + + if let _ = account.pushRegistration { + // We have an account, and it's already registered for push notifications. + return loginDidSucceed() + } + + // Now: we have an account that does not have push notifications set up. + // however, we need to deal with cases of asking for permissions too frequently. + let asked = profile.prefs.boolForKey(applicationDidRequestUserNotificationPermissionPrefKey) ?? true + let permitted = application.currentUserNotificationSettings!.types != .none + + // If we've never asked(*), then we should probably ask. + // If we've asked already, then we should not ask again. + // TODO: add UI to tell the user to go flip the Setting app. + // (*) if we asked in a prior release, and the user was ok with it, then there is no harm asking again. + // If the user denied permission, or flipped permissions in the Settings app, then + // we'll bug them once, but this is probably unavoidable. + if asked && !permitted { + return loginDidSucceed() + } + + // By the time we reach here, we haven't registered for APNS + // Either we've never asked the user, or the user declined, then re-enabled + // the notification in the Settings app. + requestUserNotifications(application) + } + + // This is called when the user logs into a new FxA account. + // It manages the asking for user permission for notification and registration + // for APNS and WebPush notifications. + func application(_ application: UIApplication, didReceiveAccountJSON data: JSON) { + if data["keyFetchToken"].stringValue() == nil || data["unwrapBKey"].stringValue() == nil { + // The /settings endpoint sends a partial "login"; ignore it entirely. + log.error("Ignoring didSignIn with keyFetchToken or unwrapBKey missing.") + return self.loginDidFail() + } + + assert(profile != nil, "Profile should still exist and be loaded into this FxAPushLoginStateMachine") + + guard let profile = profile, + let account = FirefoxAccount.from(profile.accountConfiguration, andJSON: data) else { + return self.loginDidFail() + } + accountVerified = data["verified"].bool ?? false + self.account = account + + if AppConstants.MOZ_SHOW_FXA_AVATAR { + account.updateProfile() + } + + let leanplum = LeanPlumClient.shared + if leanplum.isLPEnabled() && leanplum.isFxAPrePushEnabled() { + // If Leanplum A/B push notification tests are enabled, defer to them for + // displaying the pre-push permission dialog. If user dismisses it, we will still have + // another chance to prompt them. Afterwards, Leanplum calls `apnsRegisterDidSucceed` or + // `apnsRegisterDidFail` to finish setting up Autopush. + return readyForSyncing() + } + + requestUserNotifications(application) + } + + func getDeviceToken(_ application: UIApplication) -> Deferred> { + self.requestUserNotifications(application) + return self.apnsTokenDeferred + } + + func requestUserNotifications(_ application: UIApplication) { + if let deferred = self.apnsTokenDeferred, deferred.isFilled, + let token = deferred.value.successValue { + // If we have an account, then it'll go through ahead and register + // with autopush here. + // If not we'll just bail. The Deferred will do the rest. + return self.apnsRegisterDidSucceed(token) + } + DispatchQueue.main.async { + self.requestUserNotificationsMainThreadOnly(application) + } + } + + fileprivate func requestUserNotificationsMainThreadOnly(_ application: UIApplication) { + assert(Thread.isMainThread, "requestAuthorization should be run on the main thread") + let center = UNUserNotificationCenter.current() + return center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in + guard error == nil else { + return self.application(application, canDisplayUserNotifications: false) + } + self.application(application, canDisplayUserNotifications: granted) + } + } + + // This is necessarily called from the AppDelegate. + // Once we have permission from the user to display notifications, we should + // try and register for APNS. If not, then start syncing. + func application(_ application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) { + let types = notificationSettings.types + let allowed = types != .none && types.rawValue != 0 + self.application(application, canDisplayUserNotifications: allowed) + } + + func application(_ application: UIApplication, canDisplayUserNotifications allowed: Bool) { + guard allowed else { + apnsTokenDeferred?.fillIfUnfilled(Maybe.failure(PushNotificationError.userDisallowed)) + return readyForSyncing() + } + + // Record that we have asked the user, and they have given an answer. + profile?.prefs.setBool(true, forKey: applicationDidRequestUserNotificationPermissionPrefKey) + + if AppConstants.MOZ_FXA_PUSH { + DispatchQueue.main.async { + application.registerForRemoteNotifications() + } + } else { + readyForSyncing() + } + } + + func getPushConfiguration() -> PushConfiguration? { + let label = PushConfigurationLabel(rawValue: AppConstants.scheme) + return label?.toConfiguration() + } + + func apnsRegisterDidSucceed(_ deviceToken: Data) { + let apnsToken = deviceToken.hexEncodedString + self.apnsTokenDeferred?.fillIfUnfilled(Maybe(success: apnsToken)) + self.apnsRegisterDidSucceed(apnsToken) + } + + fileprivate func apnsRegisterDidSucceed(_ apnsToken: String) { + guard self.account != nil else { + // If we aren't logged in to FxA at this point + // we should bail. + return loginDidFail() + } + + guard let pushClient = self.pushClient else { + return pushRegistrationDidFail() + } + + if let pushRegistration = account.pushRegistration { + // Currently, we don't support routine changing of push subscriptions + // then we can assume that if we've already registered with the + // push server, then we don't need to do it again. + _ = pushClient.updateUAID(apnsToken, withRegistration: pushRegistration) + return + } + + pushClient.register(apnsToken).upon { res in + guard let pushRegistration = res.successValue else { + return self.pushRegistrationDidFail() + } + return self.pushRegistrationDidSucceed(apnsToken: apnsToken, pushRegistration: pushRegistration) + } + } + + func apnsRegisterDidFail() { + self.apnsTokenDeferred?.fillIfUnfilled(Maybe(failure: PushNotificationError.registrationFailed)) + readyForSyncing() + } + + fileprivate func pushRegistrationDidSucceed(apnsToken: String, pushRegistration: PushRegistration) { + account.pushRegistration = pushRegistration + readyForSyncing() + } + + fileprivate func pushRegistrationDidFail() { + readyForSyncing() + } + + func readyForSyncing() { + guard let profile = self.profile, let account = self.account else { + return loginDidFail() + } + + profile.setAccount(account) + + awaitVerification() + loginDidSucceed() + } + + fileprivate func awaitVerification(_ attemptsLeft: Int = verificationMaxRetries) { + guard let account = account, + let profile = profile else { + return + } + + if attemptsLeft == 0 { + return + } + + // The only way we can tell if the account has been verified is to + // start a sync. If it works, then yay, + account.advance().upon { state in + guard state.actionNeeded == .needsVerification else { + // Verification has occurred remotely, and we can proceed. + // The state machine will have told any listening UIs that + // we're done. + return self.performVerifiedSync(profile, account: account) + } + + let queue = DispatchQueue.global(qos: DispatchQoS.background.qosClass) + queue.asyncAfter(deadline: DispatchTime.now() + verificationPollingInterval) { + self.awaitVerification(attemptsLeft - 1) + } + } + } + + fileprivate func loginDidSucceed() { + let flags = FxALoginFlags(pushEnabled: account?.pushRegistration != nil, verified: accountVerified) + delegate?.accountLoginDidSucceed(withFlags: flags) + } + + fileprivate func loginDidFail() { + delegate?.accountLoginDidFail() + } + + func performVerifiedSync(_ profile: Profile, account: FirefoxAccount) { + profile.syncManager.syncEverything(why: .didLogin) + } +} + +extension FxALoginHelper { + func applicationDidDisconnect(_ application: UIApplication) { + // According to https://developer.apple.com/documentation/uikit/uiapplication/1623093-unregisterforremotenotifications + // we should be calling: + application.unregisterForRemoteNotifications() + // However, https://forums.developer.apple.com/message/179264#179264 advises against it, suggesting there is + // a 24h period after unregistering where re-registering fails. This doesn't seem to be the case (for me) + // but this may be useful to know if QA/user-testing find this a problem. + + // Whatever, we should unregister from the autopush server. That means we definitely won't be getting any + // messages. + if let pushRegistration = self.account.pushRegistration, + let pushClient = self.pushClient { + _ = pushClient.unregister(pushRegistration) + } + + // TODO: fix Bug 1168690, to tell Sync to delete this client and its tabs. + // i.e. upload a {deleted: true} client record. + + // Tell FxA we're no longer attached. + self.account.destroyDevice() + + // Cleanup the database. + self.profile?.removeAccount() + + // Cleanup the FxALoginHelper. + self.account = nil + self.accountVerified = nil + + self.profile?.prefs.removeObjectForKey(PendingAccountDisconnectedKey) + } +} diff --git a/mobile/ios/Client/Helpers/MenuHelper.swift b/mobile/ios/Client/Helpers/MenuHelper.swift new file mode 100644 index 0000000000..5609db2037 --- /dev/null +++ b/mobile/ios/Client/Helpers/MenuHelper.swift @@ -0,0 +1,47 @@ +/* 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/. */ + +import Foundation + +@objc public protocol MenuHelperInterface { + @objc optional func menuHelperCopy() + @objc optional func menuHelperOpenAndFill() + @objc optional func menuHelperReveal() + @objc optional func menuHelperSecure() + @objc optional func menuHelperFindInPage() +} + +open class MenuHelper: NSObject { + open static let SelectorCopy: Selector = #selector(MenuHelperInterface.menuHelperCopy) + open static let SelectorHide: Selector = #selector(MenuHelperInterface.menuHelperSecure) + open static let SelectorOpenAndFill: Selector = #selector(MenuHelperInterface.menuHelperOpenAndFill) + open static let SelectorReveal: Selector = #selector(MenuHelperInterface.menuHelperReveal) + open static let SelectorFindInPage: Selector = #selector(MenuHelperInterface.menuHelperFindInPage) + + open class var defaultHelper: MenuHelper { + struct Singleton { + static let instance = MenuHelper() + } + return Singleton.instance + } + + open func setItems() { + let revealPasswordTitle = NSLocalizedString("Reveal", tableName: "LoginManager", comment: "Reveal password text selection menu item") + let revealPasswordItem = UIMenuItem(title: revealPasswordTitle, action: MenuHelper.SelectorReveal) + + let hidePasswordTitle = NSLocalizedString("Hide", tableName: "LoginManager", comment: "Hide password text selection menu item") + let hidePasswordItem = UIMenuItem(title: hidePasswordTitle, action: MenuHelper.SelectorHide) + + let copyTitle = NSLocalizedString("Copy", tableName: "LoginManager", comment: "Copy password text selection menu item") + let copyItem = UIMenuItem(title: copyTitle, action: MenuHelper.SelectorCopy) + + let openAndFillTitle = NSLocalizedString("Open & Fill", tableName: "LoginManager", comment: "Open and Fill website text selection menu item") + let openAndFillItem = UIMenuItem(title: openAndFillTitle, action: MenuHelper.SelectorOpenAndFill) + + let findInPageTitle = NSLocalizedString("Find in Page", tableName: "FindInPage", comment: "Text selection menu item") + let findInPageItem = UIMenuItem(title: findInPageTitle, action: MenuHelper.SelectorFindInPage) + + UIMenuController.shared.menuItems = [copyItem, revealPasswordItem, hidePasswordItem, openAndFillItem, findInPageItem] + } +} diff --git a/mobile/ios/Client/Helpers/TabEventHandler.swift b/mobile/ios/Client/Helpers/TabEventHandler.swift new file mode 100644 index 0000000000..89099ed83c --- /dev/null +++ b/mobile/ios/Client/Helpers/TabEventHandler.swift @@ -0,0 +1,178 @@ +/* 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/. */ + +import Foundation +import Storage + +/** + * A handler can be a plain old swift object. It does not need to extend any + * other object, but can. + * + * Handlers should register for tab events with the `registerFor` method, and + * cleanup with the `unregister` method. + * + * ``` + * class HandoffHandler { + * var tabObservers: TabObservers! + * + * init() { + * tabObservers = registerFor(.didLoadFavicon, .didLoadPageMetadata) + * } + * + * deinit { + * unregister(tabObservers) + * } + * } + * ``` + * + * Handlers can implement any or all `TabEventHandler` methods. If you + * implement a method, you should probably `registerFor` the event above. + * + * ``` + * extension HandoffHandler: TabEventHandler { + * func tab(_ tab: Tab, didLoadPageMetadata metadata: PageMetadata) { + * print("\(tab) has \(pageMetadata)") + * } + * + * func tab(_ tab: Tab, didLoadFavicon favicon: Favicon) { + * print("\(tab) has \(favicon)") + * } + * } + * ``` + * + * Tab events should probably be only posted from one place, to avoid cycles. + * + * ``` + * TabEvent.post(.didLoadPageMetadata(aPageMetadata), for: tab) + * ``` + * + * In this manner, we are able to use the notification center and have type safety. + * + */ +// As we want more events we add more here. +// Each event needs: +// 1. a method in the TabEventHandler. +// 2. a default implementation of the method – so not everyone needs to implement it +// 3. a TabEventLabel, which is needed for registration +// 4. a TabEvent, with whatever parameters are needed. +// i) a case to map the event to the event label (var label) +// ii) a case to map the event to the event handler (func handle:with:) +protocol TabEventHandler { + func tab(_ tab: Tab, didChangeURL url: URL) + func tab(_ tab: Tab, didLoadPageMetadata metadata: PageMetadata) + func tab(_ tab: Tab, didLoadFavicon favicon: Favicon?, with: Data?) + func tabDidGainFocus(_ tab: Tab) + func tabDidLoseFocus(_ tab: Tab) + func tabDidClose(_ tab: Tab) +} + +// Provide default implmentations, because we don't want to litter the code with +// empty methods, and `@objc optional` doesn't really work very well. +extension TabEventHandler { + func tab(_ tab: Tab, didChangeURL url: URL) {} + func tab(_ tab: Tab, didLoadPageMetadata metadata: PageMetadata) {} + func tab(_ tab: Tab, didLoadFavicon favicon: Favicon?, with: Data?) {} + func tabDidGainFocus(_ tab: Tab) {} + func tabDidLoseFocus(_ tab: Tab) {} + func tabDidClose(_ tab: Tab) {} +} + +enum TabEventLabel: String { + case didChangeURL + case didLoadPageMetadata + case didLoadFavicon + case didGainFocus + case didLoseFocus + case didClose +} + +enum TabEvent { + case didChangeURL(URL) + case didLoadPageMetadata(PageMetadata) + case didLoadFavicon(Favicon?, with: Data?) + case didGainFocus + case didLoseFocus + case didClose + + var label: TabEventLabel { + switch self { + case .didChangeURL: + return .didChangeURL + case .didLoadPageMetadata: + return .didLoadPageMetadata + case .didLoadFavicon: + return .didLoadFavicon + case .didGainFocus: + return .didGainFocus + case .didLoseFocus: + return .didLoseFocus + case .didClose: + return .didClose + } + } + + func handle(_ tab: Tab, with handler: TabEventHandler) { + switch self { + case .didChangeURL(let url): + handler.tab(tab, didChangeURL: url) + case .didLoadPageMetadata(let metadata): + handler.tab(tab, didLoadPageMetadata: metadata) + case .didLoadFavicon(let favicon, let data): + handler.tab(tab, didLoadFavicon: favicon, with: data) + case .didGainFocus: + handler.tabDidGainFocus(tab) + case .didLoseFocus: + handler.tabDidLoseFocus(tab) + case .didClose: + handler.tabDidClose(tab) + } + } +} + +// Hide some of the machinery away from the boiler plate above. +//////////////////////////////////////////////////////////////////////////////////////// +extension TabEventLabel { + var name: Notification.Name { + return Notification.Name(self.rawValue) + } +} + +extension TabEvent { + func notification(for tab: Any) -> Notification { + return Notification(name: label.name, object: tab, userInfo: ["payload": self]) + } + + /// Use this method to post notifications to any concerned listeners. + static func post(_ event: TabEvent, for tab: Any) { + center.post(event.notification(for: tab)) + } +} + +// These methods are used by TabEventHandler implementers. +// Their usage remains consistent, even as we add more event types and handler methods. +//////////////////////////////////////////////////////////////////////////////////////// +private let center = NotificationCenter() + +typealias TabObservers = [NSObjectProtocol] +extension TabEventHandler { + /// Implementations of handles should use this method to register for events. + /// `TabObservers` should be preserved for unregistering later. + func registerFor(_ tabEvents: TabEventLabel..., queue: OperationQueue? = nil) -> TabObservers { + return tabEvents.map { eventType in + center.addObserver(forName: eventType.name, object: nil, queue: queue) { notification in + guard let tab = notification.object as? Tab, + let event = notification.userInfo?["payload"] as? TabEvent else { + return + } + event.handle(tab, with: self) + } + } + } + + func unregister(_ observers: TabObservers) { + observers.forEach { observer in + center.removeObserver(observer) + } + } +} diff --git a/mobile/ios/Client/Helpers/UserActivityHandler.swift b/mobile/ios/Client/Helpers/UserActivityHandler.swift new file mode 100644 index 0000000000..dd052dc3d6 --- /dev/null +++ b/mobile/ios/Client/Helpers/UserActivityHandler.swift @@ -0,0 +1,71 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import CoreSpotlight +import MobileCoreServices +import WebKit + +private let browsingActivityType: String = "org.mozilla.ios.firefox.browsing" + +private let searchableIndex = CSSearchableIndex(name: "firefox") + +class UserActivityHandler { + private var tabObservers: TabObservers! + + init() { + self.tabObservers = registerFor( + .didLoseFocus, + .didGainFocus, + .didChangeURL, + // .didLoadMetadata // TODO: Bug 1390294 + // .didLoadFavicon, // TODO: Bug 1390294 + .didClose, + queue: .main) + } + + deinit { + unregister(tabObservers) + } + + class func clearSearchIndex(completionHandler: ((Error?) -> Void)? = nil) { + searchableIndex.deleteAllSearchableItems(completionHandler: completionHandler) + } +} + +extension UserActivityHandler: TabEventHandler { + func tabDidGainFocus(_ tab: Tab) { + tab.userActivity?.becomeCurrent() + } + + func tabDidLoseFocus(_ tab: Tab) { + tab.userActivity?.resignCurrent() + } + + func tab(_ tab: Tab, didChangeURL url: URL) { + guard url.isWebPage(includeDataURIs: false), !url.isLocal else { + tab.userActivity?.resignCurrent() + tab.userActivity = nil + return + } + + tab.userActivity?.invalidate() + + let userActivity = NSUserActivity(activityType: browsingActivityType) + userActivity.webpageURL = url + userActivity.becomeCurrent() + + tab.userActivity = userActivity + } + + func tabDidClose(_ tab: Tab) { + guard let userActivity = tab.userActivity else { + return + } + tab.userActivity = nil + userActivity.invalidate() + } +} diff --git a/mobile/ios/Client/Info.plist b/mobile/ios/Client/Info.plist new file mode 100644 index 0000000000..a4b4c098e6 --- /dev/null +++ b/mobile/ios/Client/Info.plist @@ -0,0 +1,185 @@ + + + + + AdjustAppToken + $(ADJUST_APP_TOKEN) + AdjustEnvironment + $(ADJUST_ENVIRONMENT) + MozDevelopmentTeam + $(DEVELOPMENT_TEAM) + LeanplumAppId + + LeanplumProductionKey + + LeanplumDevelopmentKey + + AppIdentifierPrefix + $(APP_IDENTIFIER_PREFIX) + PocketEnvironmentAPIKey + $(POCKET_API_KEY) + MozWhatsNewTopic + whats-new-ios-10 + CFBundleDevelopmentRegion + en + CFBundleDisplayName + $(MOZ_BUNDLE_DISPLAY_NAME) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(MOZ_PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleURLName + org.mozilla.Client + CFBundleURLSchemes + + firefox + $(MOZ_INTERNAL_URL_SCHEME) + + + + CFBundleVersion + 1 + ITSAppUsesNonExemptEncryption + + LSApplicationQueriesSchemes + + pocket + firefox-focus + firefox-klar + ymail + ms-outlook + airmail + italiaonline-mailto + mailru-mailto + mymail-mailto + readdle-spark + itms-books + org-appextension-feature-password-management + googlegmail + inbox-gmail + + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSLocationWhenInUseUsageDescription + Websites you visit may request your location. + NSPhotoLibraryUsageDescription + This lets you save and upload photos. + NSCameraUsageDescription + This lets you take and upload photos. + NSMicrophoneUsageDescription + This lets you take and upload videos. + NSPhotoLibraryAddUsageDescription + This lets you save photos. + NSFaceIDUsageDescription + Firefox requires Face ID to access your saved logins. + NSUserActivityTypes + + org.mozilla.ios.firefox.browsing + + UIAppFonts + + CharisSILB.ttf + CharisSILBI.ttf + CharisSILI.ttf + CharisSILR.ttf + FiraSans-Bold.ttf + FiraSans-BoldItalic.ttf + FiraSans-Book.ttf + FiraSans-Italic.ttf + FiraSans-Light.ttf + FiraSans-Medium.ttf + FiraSans-Regular.ttf + FiraSans-SemiBold.ttf + FiraSans-UltraLight.ttf + + UIApplicationShortcutItems + + + UIApplicationShortcutItemIconFile + quick_action_new_tab + UIApplicationShortcutItemTitle + ShortcutItemTitleNewTab + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).NewTab + + + UIApplicationShortcutItemIconFile + quick_action_new_private_tab + UIApplicationShortcutItemTitle + ShortcutItemTitleNewPrivateTab + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).NewPrivateTab + + + UIApplicationShortcutItemIconFile + menu-ScanQRCode + UIApplicationShortcutItemTitle + ShortcutItemTitleQRCode + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).QRCode + + + UIBackgroundModes + + audio + remote-notification + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + SentryDSN + $(SENTRY_DSN) + UIViewControllerBasedStatusBarAppearance + + UTImportedTypeDeclarations + + + UTTypeConformsTo + + public.url + + UTTypeDescription + 1Password Fill Browser Action + UTTypeIdentifier + org.appextension.fill-browser-action + UTTypeSize64IconFile + + + + + diff --git a/mobile/ios/Client/MailSchemes.plist b/mobile/ios/Client/MailSchemes.plist new file mode 100644 index 0000000000..0bcc7aaeb8 --- /dev/null +++ b/mobile/ios/Client/MailSchemes.plist @@ -0,0 +1,60 @@ + + + + + + name + Mail + scheme + mailto: + + + scheme + ms-outlook:// + name + Outlook + + + name + Airmail + scheme + airmail:// + + + name + Mail.Ru + scheme + mailru-mailto:// + + + name + myMail + scheme + mymail-mailto:// + + + name + Spark + scheme + readdle-spark:// + + + name + YMail! + scheme + ymail:// + + + name + Gmail + scheme + googlegmail:// + + + name + Inbox by Gmail + scheme + inbox-gmail:// + + + diff --git a/mobile/ios/Client/TabEventHandlers.swift b/mobile/ios/Client/TabEventHandlers.swift new file mode 100644 index 0000000000..76ce60fcc6 --- /dev/null +++ b/mobile/ios/Client/TabEventHandlers.swift @@ -0,0 +1,13 @@ +/* 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/. */ + +import Foundation + +class TabEventHandlers { + static let `default` = TabEventHandlers() + + let handlers: [TabEventHandler] = [ + UserActivityHandler() + ] +} diff --git a/mobile/ios/Client/Telemetry/ActivityStreamTopics.swift b/mobile/ios/Client/Telemetry/ActivityStreamTopics.swift new file mode 100644 index 0000000000..ac13f976b2 --- /dev/null +++ b/mobile/ios/Client/Telemetry/ActivityStreamTopics.swift @@ -0,0 +1,52 @@ +/* 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/. */ + +import JSONSchema +import SyncTelemetry + +// MARK: Activity Stream +extension PingCentreTopic { + + static var ActivityStreamEvents: PingCentreTopic { + let schema = Schema([ + "type": "object", + "properties": [ + // AS-Specific properties + "event": ["type": "string"], + "page": ["type": "string"], + "source": ["type": "string"], + "action_position": ["type": "number"], + "share_provider": ["type": "string"], + + // Application metadata + "app_version": ["type": "string"], + "build": ["type": "string"], + "locale": ["type": "string"], + "release_channel": ["type": "string"] + ], + "required": ["app_version", "build", "locale", "event", "release_channel"] + ]) + + return PingCentreTopic(name: "activity-stream-mobile-events", schema: schema) + } + + static var ActivityStreamSessions: PingCentreTopic { + let schema = Schema([ + "type": "object", + "properties": [ + // AS-Specific properties + "session_duration": ["type": "number"], + + // Application metadata + "app_version": ["type": "string"], + "build": ["type": "string"], + "locale": ["type": "string"], + "release_channel": ["type": "string"] + ], + "required": ["app_version", "build", "locale", "session_duration", "release_channel"] + ]) + + return PingCentreTopic(name: "activity-stream-mobile-sessions", schema: schema) + } +} diff --git a/mobile/ios/Client/Telemetry/UnifiedTelemetry.swift b/mobile/ios/Client/Telemetry/UnifiedTelemetry.swift new file mode 100644 index 0000000000..5f5e9f89ff --- /dev/null +++ b/mobile/ios/Client/Telemetry/UnifiedTelemetry.swift @@ -0,0 +1,119 @@ +/* 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/. */ + +import Shared +import Telemetry + +// +// 'Unified Telemetry' is the name for Mozilla's telemetry system +// +class UnifiedTelemetry { + init(profile: Profile) { + NotificationCenter.default.addObserver(self, selector: #selector(uploadError(notification:)), name: Telemetry.notificationReportError, object: nil) + + let telemetryConfig = Telemetry.default.configuration + telemetryConfig.appName = "Fennec" + telemetryConfig.userDefaultsSuiteName = AppInfo.sharedContainerIdentifier + telemetryConfig.dataDirectory = .documentDirectory + telemetryConfig.updateChannel = AppConstants.BuildChannel.rawValue + let sendUsageData = profile.prefs.boolForKey(AppConstants.PrefSendUsageData) ?? true + telemetryConfig.isCollectionEnabled = sendUsageData + telemetryConfig.isUploadEnabled = sendUsageData + + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.blockPopups", withDefaultValue: true) + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.saveLogins", withDefaultValue: true) + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.showClipboardBar", withDefaultValue: false) + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.settings.closePrivateTabs", withDefaultValue: false) + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.ASPocketStoriesVisible", withDefaultValue: true) + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.ASBookmarkHighlightsVisible", withDefaultValue: true) + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.ASRecentHighlightsVisible", withDefaultValue: true) + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.prefkey.trackingprotection.enabled", withDefaultValue: "onInPrivateBrowsing") + telemetryConfig.measureUserDefaultsSetting(forKey: "profile.prefkey.trackingprotection.strength", withDefaultValue: "basic") + + let prefs = profile.prefs + Telemetry.default.beforeSerializePing(pingType: CorePingBuilder.PingType) { (inputDict) -> [String: Any?] in + var outputDict = inputDict // make a mutable copy + if let newTabChoice = prefs.stringForKey(NewTabAccessors.PrefKey) { + outputDict["defaultNewTabExperience"] = newTabChoice as AnyObject? + } + if let chosenEmailClient = prefs.stringForKey(PrefsKeys.KeyMailToOption) { + outputDict["defaultMailClient"] = chosenEmailClient as AnyObject? + } + return outputDict + } + + Telemetry.default.beforeSerializePing(pingType: MobileEventPingBuilder.PingType) { (inputDict) -> [String : Any?] in + var outputDict = inputDict + var settings: [String : Any?] = inputDict["settings"] as? [String : Any?] ?? [:] + + let searchEngines = SearchEngines(prefs: profile.prefs, files: profile.files) + settings["defaultSearchEngine"] = searchEngines.defaultEngine.engineID ?? "custom" + + outputDict["settings"] = settings + return outputDict + } + + Telemetry.default.add(pingBuilderType: CorePingBuilder.self) + Telemetry.default.add(pingBuilderType: MobileEventPingBuilder.self) + } + + @objc func uploadError(notification: NSNotification) { + guard !DeviceInfo.isSimulator(), let error = notification.userInfo?["error"] as? NSError else { return } + Sentry.shared.send(message: "Upload Error", tag: SentryTag.unifiedTelemetry, severity: .info, description: error.debugDescription) + } +} + +// Enums for Event telemetry. +extension UnifiedTelemetry { + public enum EventCategory: String { + case action = "action" + } + + public enum EventMethod: String { + case add = "add" + case background = "background" + case change = "change" + case delete = "delete" + case foreground = "foreground" + case open = "open" + case scan = "scan" + case tap = "tap" + case view = "view" + } + + public enum EventObject: String { + case app = "app" + case bookmark = "bookmark" + case bookmarksPanel = "bookmarks-panel" + case qrCodeText = "qr-code-text" + case qrCodeURL = "qr-code-url" + case readerModeCloseButton = "reader-mode-close-button" + case readerModeOpenButton = "reader-mode-open-button" + case readingListItem = "reading-list-item" + case setting = "setting" + } + + public enum EventValue: String { + case activityStream = "activity-stream" + case appMenu = "app-menu" + case awesomebarResults = "awesomebar-results" + case bookmarksPanel = "bookmarks-panel" + case homePanelTabButton = "home-panel-tab-button" + case markAsRead = "mark-as-read" + case markAsUnread = "mark-as-unread" + case pageActionMenu = "page-action-menu" + case readerModeToolbar = "reader-mode-toolbar" + case readingListPanel = "reading-list-panel" + case shareExtension = "share-extension" + case shareMenu = "share-menu" + } + + public static func recordEvent(category: EventCategory, method: EventMethod, object: EventObject, value: EventValue, extras: [String : Any?]? = nil) { + Telemetry.default.recordEvent(category: category.rawValue, method: method.rawValue, object: object.rawValue, value: value.rawValue, extras: extras) + } + + public static func recordEvent(category: EventCategory, method: EventMethod, object: EventObject, value: String? = nil, extras: [String : Any?]? = nil) { + Telemetry.default.recordEvent(category: category.rawValue, method: method.rawValue, object: object.rawValue, value: value, extras: extras) + } +} diff --git a/mobile/ios/Client/UIScrollViewSwizzled.swift b/mobile/ios/Client/UIScrollViewSwizzled.swift new file mode 100644 index 0000000000..e34977ef72 --- /dev/null +++ b/mobile/ios/Client/UIScrollViewSwizzled.swift @@ -0,0 +1,44 @@ +/* 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/. */ + +import Shared + +// Workaround for bug 1417152, whereby NaN bounds are being set on the scrollview when viewing PDFs in the web view. +// Is fixed in WebKit, remove this file when the fix arrives in iOS release. + +private let swizzling: (UIScrollView.Type) -> Void = { obj in + let originalSelector = #selector(setter: UIView.bounds) + let swizzledSelector = #selector(obj.swizzle_setBounds(bounds:)) + let originalMethod = class_getInstanceMethod(obj, originalSelector) + let swizzledMethod = class_getInstanceMethod(obj, swizzledSelector) + method_exchangeImplementations(originalMethod, swizzledMethod) +} + +extension UIScrollView { + open override class func initialize() { + // make sure this isn't a subclass + guard self == UIScrollView.self else { + return + } + swizzling(self) + } + + func swizzle_setBounds(bounds: CGRect) { + [bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height].forEach() { val in + if val.isNaN || val.isInfinite { + Sentry.shared.send(message: "Bad scrollview bounds detected [infinite/nan].") + return + } + } + + [bounds.size.width, bounds.size.height].forEach() { val in + if val < 0 { + Sentry.shared.send(message: "Bad scrollview bounds detected [negative size].") + return + } + } + + self.swizzle_setBounds(bounds: bounds) + } +} diff --git a/mobile/ios/Client/Utils/FaviconFetcher.swift b/mobile/ios/Client/Utils/FaviconFetcher.swift new file mode 100644 index 0000000000..49dd9ead2e --- /dev/null +++ b/mobile/ios/Client/Utils/FaviconFetcher.swift @@ -0,0 +1,322 @@ +/* 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/. */ + +import Storage +import Shared +import Alamofire +import XCGLogger +import Deferred +import SDWebImage +import Fuzi +import SwiftyJSON + +private let log = Logger.browserLogger +private let queue = DispatchQueue(label: "FaviconFetcher", attributes: DispatchQueue.Attributes.concurrent) + +class FaviconFetcherErrorType: MaybeErrorType { + let description: String + init(description: String) { + self.description = description + } +} + +/* A helper class to find the favicon associated with a URL. + * This will load the page and parse any icons it finds out of it. + * If that fails, it will attempt to find a favicon.ico in the root host domain. + */ +open class FaviconFetcher: NSObject, XMLParserDelegate { + open static var userAgent: String = "" + static let ExpirationTime = TimeInterval(60*60*24*7) // Only check for icons once a week + fileprivate static var characterToFaviconCache = [String: UIImage]() + static var defaultFavicon: UIImage = { + return UIImage(named: "defaultFavicon")! + }() + + static var colors: [String: UIColor] = [:] //An in-Memory data store that stores background colors domains. Stored using url.baseDomain. + + // Sites can be accessed via their baseDomain. + static var defaultIcons: [String: (color: UIColor, url: String)] = { + return FaviconFetcher.getDefaultIcons() + }() + + static let multiRegionDomains = ["craigslist", "google", "amazon"] + + class func getDefaultIconForURL(url: URL) -> (color: UIColor, url: String)? { + + // Problem: Sites like amazon exist with .ca/.de and many other tlds. + // Solution: They are stored in the default icons list as "amazon" instead of "amazon.com" this allows us to have favicons for every tld." + // Here, If the site is in the multiRegionDomain array look it up via its second level domain (amazon) instead of its baseDomain (amazon.com) + let hostName = url.hostSLD + if multiRegionDomains.contains(hostName), let icon = defaultIcons[hostName] { + return icon + } + if let name = url.baseDomain, let icon = defaultIcons[name] { + return icon + } + return nil + } + + class func getForURL(_ url: URL, profile: Profile) -> Deferred> { + let f = FaviconFetcher() + return f.loadFavicons(url, profile: profile) + } + + fileprivate func loadFavicons(_ url: URL, profile: Profile, oldIcons: [Favicon] = [Favicon]()) -> Deferred> { + if isIgnoredURL(url) { + return deferMaybe(FaviconFetcherErrorType(description: "Not fetching ignored URL to find favicons.")) + } + + let deferred = Deferred>() + + var oldIcons: [Favicon] = oldIcons + + queue.async { _ in + self.parseHTMLForFavicons(url).bind({ (result: Maybe<[Favicon]>) -> Deferred<[Maybe]> in + var deferreds = [Deferred>]() + if let icons = result.successValue { + deferreds = icons.map { self.getFavicon(url, icon: $0, profile: profile) } + } + return all(deferreds) + }).bind({ (results: [Maybe]) -> Deferred> in + for result in results { + if let icon = result.successValue { + oldIcons.append(icon) + } + } + + oldIcons = oldIcons.sorted { + return $0.width! > $1.width! + } + + return deferMaybe(oldIcons) + }).upon({ (result: Maybe<[Favicon]>) in + deferred.fill(result) + return + }) + } + + return deferred + } + + lazy fileprivate var alamofire: SessionManager = { + let configuration = URLSessionConfiguration.default + var defaultHeaders = SessionManager.default.session.configuration.httpAdditionalHeaders ?? [:] + defaultHeaders["User-Agent"] = userAgent + configuration.httpAdditionalHeaders = defaultHeaders + configuration.timeoutIntervalForRequest = 5 + return SessionManager(configuration: configuration) + }() + + fileprivate func fetchDataForURL(_ url: URL) -> Deferred> { + let deferred = Deferred>() + alamofire.request(url).response { response in + // Don't cancel requests just because our Manager is deallocated. + withExtendedLifetime(self.alamofire) { + if response.error == nil { + if let data = response.data { + deferred.fill(Maybe(success: data)) + return + } + } + let errorDescription = (response.error as NSError?)?.description ?? "No content." + deferred.fill(Maybe(failure: FaviconFetcherErrorType(description: errorDescription))) + } + } + return deferred + } + +///Users/fpatel/Documents/firefox-ios/Client/Utils/FaviconFetcher.swift:117:77: Cannot convert value of type 'String' to expected argument type 'String.Index' (aka 'String.CharacterView.Index') + // Loads and parses an html document and tries to find any known favicon-type tags for the page + fileprivate func parseHTMLForFavicons(_ url: URL) -> Deferred> { + return fetchDataForURL(url).bind({ result -> Deferred> in + var icons = [Favicon]() + guard let data = result.successValue, result.isSuccess, + let root = try? HTMLDocument(data: data as Data) else { + return deferMaybe([]) + } + var reloadUrl: URL? = nil + for meta in root.xpath("//head/meta") { + if let refresh = meta["http-equiv"], refresh == "Refresh", + let content = meta["content"], + let index = content.range(of: "URL="), + let url = NSURL(string: content.substring(from: index.upperBound)) { + reloadUrl = url as URL + } + } + + if let url = reloadUrl { + return self.parseHTMLForFavicons(url) + } + + var bestType = IconType.noneFound + for link in root.xpath("//head//link[contains(@rel, 'icon')]") { + var iconType: IconType? = nil + if let rel = link["rel"] { + switch rel { + case "shortcut icon": + iconType = .icon + case "icon": + iconType = .icon + case "apple-touch-icon": + iconType = .appleIcon + case "apple-touch-icon-precomposed": + iconType = .appleIconPrecomposed + default: + iconType = nil + } + } + + guard let href = link["href"], iconType != nil else { + continue //Skip the rest of the loop. But don't stop the loop + } + + if href.endsWith(".ico") { + iconType = .guess + } + + if let type = iconType, !bestType.isPreferredTo(type), let iconUrl = NSURL(string: href, relativeTo: url as URL), let absoluteString = iconUrl.absoluteString { + let icon = Favicon(url: absoluteString, date: NSDate() as Date, type: type) + // If we already have a list of Favicons going already, then add it… + if type == bestType { + icons.append(icon) + } else { + // otherwise, this is the first in a new best yet type. + icons = [icon] + bestType = type + } + } + + // If we haven't got any options icons, then use the default at the root of the domain. + if let url = NSURL(string: "/favicon.ico", relativeTo: url as URL), icons.isEmpty, let absoluteString = url.absoluteString { + let icon = Favicon(url: absoluteString, date: NSDate() as Date, type: .guess) + icons = [icon] + } + + } + return deferMaybe(icons) + }) + } + + func getFavicon(_ siteUrl: URL, icon: Favicon, profile: Profile) -> Deferred> { + let deferred = Deferred>() + let url = icon.url + let manager = SDWebImageManager.shared() + let site = Site(url: siteUrl.absoluteString, title: "") + + var fav = Favicon(url: url, type: icon.type) + if let url = url.asURL { + var fetch: SDWebImageOperation? + fetch = manager.loadImage(with: url, + options: .lowPriority, + progress: { (receivedSize, expectedSize, _) in + if receivedSize > FaviconManager.maximumFaviconSize || expectedSize > FaviconManager.maximumFaviconSize { + fetch?.cancel() + } + }, + completed: { (img, _, _, _, _, url) in + guard let url = url else { + deferred.fill(Maybe(failure: FaviconError())) + return + } + fav = Favicon(url: url.absoluteString, type: icon.type) + + if let img = img { + fav.width = Int(img.size.width) + fav.height = Int(img.size.height) + profile.favicons.addFavicon(fav, forSite: site) + } else { + fav.width = 0 + fav.height = 0 + } + + deferred.fill(Maybe(success: fav)) + }) + } else { + return deferMaybe(FaviconFetcherErrorType(description: "Invalid URL \(url)")) + } + + return deferred + } + + // Returns a single Favicon UIImage for a given URL + class func fetchFavImageForURL(forURL url: URL, profile: Profile) -> Deferred> { + let deferred = Deferred>() + FaviconFetcher.getForURL(url.domainURL, profile: profile).uponQueue(DispatchQueue.main) { result in + var iconURL: URL? + if let favicons = result.successValue, favicons.count > 0, let faviconImageURL = favicons.first?.url.asURL { + iconURL = faviconImageURL + } else { + return deferred.fill(Maybe(failure: FaviconError())) + } + SDWebImageManager.shared().loadImage(with: iconURL, options: .continueInBackground, progress: nil) { (image, _, _, _, _, _) in + if let image = image { + deferred.fill(Maybe(success: image)) + } else { + deferred.fill(Maybe(failure: FaviconError())) + } + } + } + return deferred + } + + // Returns the default favicon for a site based on the first letter of the site's domain + class func getDefaultFavicon(_ url: URL) -> UIImage { + guard let character = url.baseDomain?.characters.first else { + return defaultFavicon + } + + let faviconLetter = String(character).uppercased() + + if let cachedFavicon = characterToFaviconCache[faviconLetter] { + return cachedFavicon + } + + var faviconImage = UIImage() + let faviconLabel = UILabel(frame: CGRect(x: 0, y: 0, width: TwoLineCellUX.ImageSize, height: TwoLineCellUX.ImageSize)) + faviconLabel.text = faviconLetter + faviconLabel.textAlignment = .center + faviconLabel.font = UIFont.systemFont(ofSize: 18, weight: UIFontWeightMedium) + faviconLabel.textColor = UIColor.white + UIGraphicsBeginImageContextWithOptions(faviconLabel.bounds.size, false, 0.0) + faviconLabel.layer.render(in: UIGraphicsGetCurrentContext()!) + faviconImage = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + + characterToFaviconCache[faviconLetter] = faviconImage + return faviconImage + } + + // Returns a color based on the url's hash + class func getDefaultColor(_ url: URL) -> UIColor { + guard let hash = url.baseDomain?.hashValue else { + return UIColor.gray + } + let index = abs(hash) % (UIConstants.DefaultColorStrings.count - 1) + let colorHex = UIConstants.DefaultColorStrings[index] + return UIColor(colorString: colorHex) + } + + // Default favicons and background colors provided via mozilla/tippy-top-sites + class func getDefaultIcons() -> [String: (color: UIColor, url: String)] { + let filePath = Bundle.main.path(forResource: "top_sites", ofType: "json") + let file = try! Data(contentsOf: URL(fileURLWithPath: filePath!)) + let json = JSON(file) + var icons: [String: (color: UIColor, url: String)] = [:] + json.forEach({ + guard let url = $0.1["domain"].string, let color = $0.1["background_color"].string, var path = $0.1["image_url"].string else { + return + } + path = path.replacingOccurrences(of: ".png", with: "") + let filePath = Bundle.main.path(forResource: "TopSites/" + path, ofType: "png") + if let filePath = filePath { + if color == "#fff" || color == "#FFF" { + icons[url] = (UIColor.clear, filePath) + } else { + icons[url] = (UIColor(colorString: color.replacingOccurrences(of: "#", with: "")), filePath) + } + } + }) + return icons + } +} diff --git a/mobile/ios/Client/Utils/Swizzling.h b/mobile/ios/Client/Utils/Swizzling.h new file mode 100644 index 0000000000..69a367ddfc --- /dev/null +++ b/mobile/ios/Client/Utils/Swizzling.h @@ -0,0 +1,8 @@ +/* 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/. */ + +#pragma once + +BOOL SwizzleInstanceMethods(Class class, SEL dstSel, SEL srcSel); +BOOL SwizzleClassMethods(Class class, SEL dstSel, SEL srcSel); diff --git a/mobile/ios/Client/Utils/Swizzling.m b/mobile/ios/Client/Utils/Swizzling.m new file mode 100644 index 0000000000..70b168f14a --- /dev/null +++ b/mobile/ios/Client/Utils/Swizzling.m @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import +#import +#include + +BOOL SwizzleInstanceMethods(Class class, SEL dstSel, SEL srcSel) +{ + Method dstMethod = class_getInstanceMethod(class, dstSel); + Method srcMethod = class_getInstanceMethod(class, srcSel); + IMP srcIMP = method_getImplementation(srcMethod); + if (class_addMethod(class, dstSel, srcIMP, method_getTypeEncoding(srcMethod))) { + class_replaceMethod(class, dstSel, method_getImplementation(dstMethod), method_getTypeEncoding(dstMethod)); + } else { + method_exchangeImplementations(dstMethod, srcMethod); + } + return (method_getImplementation(srcMethod) == method_getImplementation(class_getInstanceMethod(class, dstSel))); +} + +BOOL SwizzleClassMethods(Class class, SEL dstSel, SEL srcSel) +{ + Class metaClass = object_getClass(class); + return SwizzleInstanceMethods(metaClass, dstSel, srcSel); +} diff --git a/mobile/ios/Client/Utils/Try.h b/mobile/ios/Client/Utils/Try.h new file mode 100644 index 0000000000..decd4a3262 --- /dev/null +++ b/mobile/ios/Client/Utils/Try.h @@ -0,0 +1,9 @@ +/* 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/. */ + +#import + +@interface Try : NSObject +- (id) initWithTry: (void(^)()) tryBlock catch: (void(^)(NSException *exception)) catchBlock; +@end diff --git a/mobile/ios/Client/Utils/Try.m b/mobile/ios/Client/Utils/Try.m new file mode 100644 index 0000000000..4367dedaa7 --- /dev/null +++ b/mobile/ios/Client/Utils/Try.m @@ -0,0 +1,21 @@ +/* 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/. */ + +#import "Try.h" + +@implementation Try + +- (id) initWithTry: (void(^)()) tryBlock catch: (void(^)(NSException *exception)) catchBlock { + if (self = [super init]) { + @try { + tryBlock(); + } + @catch (NSException *exception) { + catchBlock(exception); + } + } + return self; +} + +@end diff --git a/mobile/ios/Client/en.lproj/InfoPlist.strings b/mobile/ios/Client/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000..b2805473f1 --- /dev/null +++ b/mobile/ios/Client/en.lproj/InfoPlist.strings @@ -0,0 +1,12 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +NSLocationWhenInUseUsageDescription = "Websites you visit may request your location."; +NSPhotoLibraryUsageDescription = "This lets you save and upload photos."; +NSPhotoLibraryAddUsageDescription = "This lets you save photos."; +NSCameraUsageDescription = "This lets you take and upload photos."; +NSMicrophoneUsageDescription = "This lets you take and upload videos."; +ShortcutItemTitleNewTab = "New Tab"; +ShortcutItemTitleNewPrivateTab = "New Private Tab"; +ShortcutItemTitleQRCode = "Scan QR Code"; diff --git a/mobile/ios/ClientTests/ActivityStreamTests.swift b/mobile/ios/ClientTests/ActivityStreamTests.swift new file mode 100644 index 0000000000..b6167d83a9 --- /dev/null +++ b/mobile/ios/ClientTests/ActivityStreamTests.swift @@ -0,0 +1,284 @@ +/* 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/. */ + +import UIKit +import XCTest +@testable import Client +import Shared +import Storage +import Deferred +import SyncTelemetry + +class ActivityStreamTests: XCTestCase { + var profile: MockProfile! + var panel: ActivityStreamPanel! + var mockPingClient: MockPingClient! + var telemetry: ActivityStreamTracker! + + override func setUp() { + super.setUp() + self.profile = MockProfile() + self.telemetry = ActivityStreamTracker(eventsTracker: MockPingClient(), sessionsTracker: MockPingClient()) + self.panel = ActivityStreamPanel(profile: profile, telemetry: self.telemetry) + } + + override func tearDown() { + mockPingClient = nil + } + + func testDeletionOfSingleSuggestedSite() { + let siteToDelete = panel.defaultTopSites()[0] + + panel.hideURLFromTopSites(siteToDelete) + let newSites = panel.defaultTopSites() + + XCTAssertFalse(newSites.contains(siteToDelete, f: { (a, b) -> Bool in + return a.url == b.url + })) + } + + func testDeletionOfAllDefaultSites() { + let defaultSites = panel.defaultTopSites() + defaultSites.forEach({ + panel.hideURLFromTopSites($0) + }) + + let newSites = panel.defaultTopSites() + XCTAssertTrue(newSites.isEmpty) + } +} + +// MARK: Telemetry Tests +extension ActivityStreamTests { + fileprivate func expectedPayloadForEvent(_ event: String, source: String, position: Int) -> [String: Any] { + return [ + "event": event, + "page": "NEW_TAB", + "source": source, + "action_position": position, + "app_version": AppInfo.appVersion, + "build": AppInfo.buildNumber, + "locale": Locale.current.identifier, + "release_channel": AppConstants.BuildChannel.rawValue + ] + } + + fileprivate func expectedBadStatePayload(state: String, source: String) -> [String: Any] { + return [ + "event": state, + "page": "NEW_TAB", + "source": source, + "app_version": AppInfo.appVersion, + "build": AppInfo.buildNumber, + "locale": Locale.current.identifier, + "release_channel": AppConstants.BuildChannel.rawValue + ] + } + + fileprivate func assertPayload(_ actual: [String: Any], matches: [String: Any]) { + XCTAssertTrue(actual.count == matches.count) + actual.enumerated().forEach { index, element in + if let actualValue = element.1 as? Int, + let matchesValue = matches[element.0] as? Int { + XCTAssertTrue(actualValue == matchesValue) + } + + if let actualValue = element.1 as? String, + let matchesValue = matches[element.0] as? String { + XCTAssertTrue(actualValue == matchesValue) + } + } + } + + func testHighlightEmitsEventOnTap() { + let mockSite = Site(url: "http://mozilla.org", title: "Mozilla") + panel.highlights = [mockSite] + panel.selectItemAtIndex(0, inSection: .highlights) + + let pingsSent = (telemetry.eventsTracker as! MockPingClient).pingsReceived + XCTAssertEqual(pingsSent.count, 1) + let eventPing = pingsSent[0] + assertPayload(eventPing, matches: expectedPayloadForEvent("CLICK", source: "HIGHLIGHTS", position: 0)) + } + + func testContextMenuOnTopSiteEmitsRemoveEvent() { + let mockSite = Site(url: "http://mozilla.org", title: "Mozilla") + let topSitesContextMenu = panel.contextMenu(for: mockSite, with: IndexPath(item: 0, section: ActivityStreamPanel.Section.topSites.rawValue)) + + let removeAction = topSitesContextMenu?.actions[0].find { $0.title == Strings.RemoveContextMenuTitle } + removeAction?.handler?(removeAction!) + + let pingsSent = (telemetry.eventsTracker as! MockPingClient).pingsReceived + XCTAssertEqual(pingsSent.count, 1) + let removePing = pingsSent[0] + assertPayload(removePing, matches: expectedPayloadForEvent("REMOVE", source: "TOP_SITES", position: 0)) + } + + func testContextMenuOnHighlightsEmitsRemoveDismissEvents() { + let mockSite = Site(url: "http://mozilla.org", title: "Mozilla") + let highlightsContextMenu = panel.contextMenu(for: mockSite, with: IndexPath(row: 0, section: ActivityStreamPanel.Section.highlights.rawValue)) + + let dismiss = highlightsContextMenu?.actions[0].find { $0.title == Strings.RemoveContextMenuTitle } + let delete = highlightsContextMenu?.actions[0].find { $0.title == Strings.DeleteFromHistoryContextMenuTitle } + + dismiss?.handler?(dismiss!) + delete?.handler?(delete!) + + // Check to see that they emitted telemetry events + let pingsSent = (telemetry.eventsTracker as! MockPingClient).pingsReceived + XCTAssertEqual(pingsSent.count, 2) + + let dismissPing = pingsSent[0] + assertPayload(dismissPing, matches: expectedPayloadForEvent("DISMISS", source: "HIGHLIGHTS", position: 0)) + + let deletePing = pingsSent[1] + assertPayload(deletePing, matches: expectedPayloadForEvent("DELETE", source: "HIGHLIGHTS", position: 0)) + } + + func testSessionReportedWhenViewAppearsAndDisappears() { + // Simulate the panel opening and closing with a second in between for some session_duration + panel.viewWillAppear(false) + var pingsSent = (telemetry.sessionsTracker as! MockPingClient).pingsReceived + XCTAssertEqual(pingsSent.count, 0) + + wait(1) + panel.viewDidDisappear(false) + + pingsSent = (telemetry.sessionsTracker as! MockPingClient).pingsReceived + XCTAssertEqual(pingsSent.count, 1) + + let eventPing = pingsSent[0] + XCTAssertNotNil(eventPing["session_duration"]) + } + + func testBadStateEventsForHighlights() { + let goodSite = Site(url: "http://mozilla.org", title: "Mozilla") + goodSite.icon = Favicon(url: "http://image", date: Date(), type: .local) + goodSite.metadata = PageMetadata(id: nil, + siteURL: "http://mozilla.org", + mediaURL: "http://image", + title: "Mozilla", + description: "Web", + type: nil, + providerName: nil, + mediaDataURI: nil) + let badSite = Site(url: "http://mozilla.org", title: "Mozilla") + profile.recommendations = MockRecommender(highlights: [goodSite, badSite]) + + // Since invalidateHighlights calls back into the main thread, we can't + // simply call .value on this to block since the app will dead lock when + // trying to call back onto a blocked main thread. + let expect = XCTestExpectation(description: "Sent bad highlight pings") + panel.getHighlights() >>> { + expect.fulfill() + } + + wait(for: [expect], timeout: 3) + let pingsSent = (self.telemetry.eventsTracker as! MockPingClient).pingsReceived + XCTAssertEqual(pingsSent.count, 2) + assertPayload(pingsSent[0], + matches: expectedBadStatePayload(state: "MISSING_METADATA_IMAGE", source: "HIGHLIGHTS")) + assertPayload(pingsSent[1], + matches: expectedBadStatePayload(state: "MISSING_FAVICON", source: "HIGHLIGHTS")) + } + + func testBadStateEventsForTopSites() { + let goodSite = Site(url: "http://mozilla.org", title: "Mozilla") + goodSite.icon = Favicon(url: "http://image", date: Date(), type: .local) + goodSite.metadata = PageMetadata(id: nil, + siteURL: "http://mozilla.org", + mediaURL: "http://image", + title: "Mozilla", + description: "Web", + type: nil, + providerName: nil, + mediaDataURI: nil) + let badSite = Site(url: "http://mozilla.org", title: "Mozilla") + profile.history = MockTopSitesHistory(sites: [goodSite, badSite]) + + // Since invalidateHighlights calls back into the main thread, we can't + // simply call .value on this to block since the app will dead lock when + // trying to call back onto a blocked main thread. + let expect = XCTestExpectation(description: "Sent bad top site pings") + panel.getTopSites() >>> { + expect.fulfill() + } + + wait(for: [expect], timeout: 3) + let pingsSent = (self.telemetry.eventsTracker as! MockPingClient).pingsReceived + XCTAssertEqual(pingsSent.count, 2) + assertPayload(pingsSent[0], + matches: expectedBadStatePayload(state: "MISSING_METADATA_IMAGE", source: "TOP_SITES")) + assertPayload(pingsSent[1], + matches: expectedBadStatePayload(state: "MISSING_FAVICON", source: "TOP_SITES")) + } +} + +class MockPingClient: PingCentreClient { + + var pingsReceived: [[String: Any]] = [] + + public func sendPing(_ data: [String : Any], validate: Bool) -> Success { + pingsReceived.append(data) + return succeed() + } + + public func sendBatch(_ data: [[String : Any]], validate: Bool) -> Success { + pingsReceived += data + return succeed() + } +} + +fileprivate class MockRecommender: HistoryRecommendations { + func repopulateHighlights() -> Success { + return succeed() + } + + var highlights: [Site] + + init(highlights: [Site]) { + self.highlights = highlights + } + + func getHighlights() -> Deferred>> { + return deferMaybe(ArrayCursor(data: highlights)) + } + + func getRecentBookmarks(_ limit: Int) -> Deferred>> { + return deferMaybe(ArrayCursor(data: [])) + } + + func repopulate(invalidateTopSites shouldInvalidateTopSites: Bool, invalidateHighlights shouldInvalidateHighlights: Bool) -> Success { + return succeed() + } + + func removeHighlightForURL(_ url: String) -> Success { + guard let foundSite = highlights.filter({ $0.url == url }).first else { + return succeed() + } + let foundIndex = highlights.index(of: foundSite)! + highlights.remove(at: foundIndex) + return succeed() + } +} + +fileprivate class MockTopSitesHistory: MockableHistory { + let mockTopSites: [Site] + + init(sites: [Site]) { + mockTopSites = sites + } + + override func getTopSitesWithLimit(_ limit: Int) -> Deferred>> { + return deferMaybe(ArrayCursor(data: mockTopSites)) + } + + override func getPinnedTopSites() -> Deferred>> { + return deferMaybe(ArrayCursor(data: [])) + } + + override func updateTopSitesCacheIfInvalidated() -> Deferred> { + return deferMaybe(true) + } +} diff --git a/mobile/ios/ClientTests/AuthenticatorTests.swift b/mobile/ios/ClientTests/AuthenticatorTests.swift new file mode 100644 index 0000000000..7535fffb07 --- /dev/null +++ b/mobile/ios/ClientTests/AuthenticatorTests.swift @@ -0,0 +1,173 @@ +/* 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/. */ + +import Foundation +import XCTest +import Shared +import Deferred +@testable import Client +@testable import Storage + +class MockFiles: FileAccessor { + init() { + let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] + super.init(rootPath: (docPath as NSString).appendingPathComponent("testing")) + } +} + +class MockChallengeSender: NSObject, URLAuthenticationChallengeSender { + func use(_ credential: URLCredential, for challenge: URLAuthenticationChallenge) {} + func continueWithoutCredential(for challenge: URLAuthenticationChallenge) {} + func cancel(_ challenge: URLAuthenticationChallenge) {} +} + +class MockMalformableLogin: LoginData { + var guid: String + var credentials: URLCredential + var protectionSpace: URLProtectionSpace + var hostname: String + var username: String? + var password: String + var httpRealm: String? + var formSubmitURL: String? + var usernameField: String? + var passwordField: String? + var hasMalformedHostname = true + var isValid = Maybe(success: ()) + + static func createWithHostname(_ hostname: String, username: String, password: String, formSubmitURL: String) -> MockMalformableLogin { + return self.init(guid: Bytes.generateGUID(), hostname: hostname, username: username, password: password, formSubmitURL: formSubmitURL) + } + + required init(guid: String, hostname: String, username: String, password: String, formSubmitURL: String) { + self.guid = guid + self.credentials = URLCredential(user: username, password: password, persistence: URLCredential.Persistence.none) + self.hostname = hostname + self.password = password + self.username = username + self.protectionSpace = URLProtectionSpace(host: hostname, port: 0, protocol: nil, realm: nil, authenticationMethod: nil) + self.formSubmitURL = formSubmitURL + } + + func toDict() -> [String: String] { + // Not used for this mock + return [String: String]() + } + + func isSignificantlyDifferentFrom(_ login: LoginData) -> Bool { + // Not used for this mock + return true + } +} + +private let MainLoginColumns = "guid, username, password, hostname, httpRealm, formSubmitURL, usernameField, passwordField" + +class AuthenticatorTests: XCTestCase { + + fileprivate var db: BrowserDB! + fileprivate var logins: SQLiteLogins! + fileprivate var mockVC = UIViewController() + + override func setUp() { + super.setUp() + self.db = BrowserDB(filename: "testsqlitelogins.db", schema: LoginsSchema(), files: MockFiles()) + self.logins = SQLiteLogins(db: self.db) + self.logins.removeAll().succeeded() + } + + override func tearDown() { + self.logins.removeAll().succeeded() + } + + fileprivate func mockChallengeForURL(_ url: URL, username: String, password: String) -> URLAuthenticationChallenge { + let scheme = url.scheme + let host = url.host ?? "" + let port = (url as NSURL).port?.intValue ?? 80 + + let credential = URLCredential(user: username, password: password, persistence: .none) + let protectionSpace = URLProtectionSpace(host: host, + port: port, + protocol: scheme, + realm: "Secure Site", + authenticationMethod: nil) + return URLAuthenticationChallenge(protectionSpace: protectionSpace, + proposedCredential: credential, + previousFailureCount: 0, + failureResponse: nil, + error: nil, + sender: MockChallengeSender()) + } + + fileprivate func hostnameFactory(_ row: SDRow) -> String { + return row["hostname"] as! String + } + + fileprivate func rawQueryForAllLogins() -> Deferred>> { + let projection = MainLoginColumns + let sql = + "SELECT \(projection) FROM " + + "\(TableLoginsLocal) WHERE is_deleted = 0 " + + "UNION ALL " + + "SELECT \(projection) FROM " + + "\(TableLoginsMirror) WHERE is_overridden = 0 " + + "ORDER BY hostname ASC" + return db.runQuery(sql, args: nil, factory: hostnameFactory) + } + + func testChallengeMatchesLoginEntry() { + let login = Login.createWithHostname("https://securesite.com", username: "username", password: "password", formSubmitURL: "https://submit.me") + logins.addLogin(login).succeeded() + let challenge = mockChallengeForURL(URL(string: "https://securesite.com")!, username: "username", password: "password") + let result = Authenticator.findMatchingCredentialsForChallenge(challenge, fromLoginsProvider: logins).value.successValue! + XCTAssertNotNil(result) + XCTAssertEqual(result?.user, "username") + XCTAssertEqual(result?.password, "password") + } + + func testChallengeMatchesSingleMalformedLoginEntry() { + // Since Login has been updated to not store schemeless URL, write directly to simulate a malformed URL + let malformedLogin = MockMalformableLogin.createWithHostname("malformed.com", username: "username", password: "password", formSubmitURL: "https://submit.me") + logins.addLogin(malformedLogin).succeeded() + + // Pre-condition: Check that the hostname is malformed + let oldHostname = rawQueryForAllLogins().value.successValue![0] + XCTAssertEqual(oldHostname, "malformed.com") + + let challenge = mockChallengeForURL(URL(string: "https://malformed.com")!, username: "username", password: "password") + let result = Authenticator.findMatchingCredentialsForChallenge(challenge, fromLoginsProvider: logins).value.successValue! + XCTAssertNotNil(result) + XCTAssertEqual(result?.user, "username") + XCTAssertEqual(result?.password, "password") + + // Post-condition: Check that we updated the hostname to be not malformed + let newHostname = rawQueryForAllLogins().value.successValue![0] + XCTAssertEqual(newHostname, "https://malformed.com") + } + + func testChallengeMatchesDuplicateLoginEntries() { + // Since Login has been updated to not store schemeless URL, write directly to simulate a malformed URL + let malformedLogin = MockMalformableLogin.createWithHostname("malformed.com", username: "malformed_username", password: "malformed_password", formSubmitURL: "https://submit.me") + logins.addLogin(malformedLogin).succeeded() + + let login = Login.createWithHostname("https://malformed.com", username: "good_username", password: "good_password", formSubmitURL: "https://submit.me") + logins.addLogin(login).succeeded() + + // Pre-condition: Verify that both logins were stored + let hostnames = rawQueryForAllLogins().value.successValue! + XCTAssertEqual(hostnames.count, 2) + XCTAssertEqual(hostnames[0], "https://malformed.com") + XCTAssertEqual(hostnames[1], "malformed.com") + + let challenge = mockChallengeForURL(URL(string: "https://malformed.com")!, username: "username", password: "password") + let result = Authenticator.findMatchingCredentialsForChallenge(challenge, fromLoginsProvider: logins).value.successValue! + XCTAssertNotNil(result) + XCTAssertEqual(result?.user, "good_username") + XCTAssertEqual(result?.password, "good_password") + + // Post-condition: Verify that malformed URL was removed + let newHostnames = rawQueryForAllLogins().value.successValue! + XCTAssertEqual(newHostnames.count, 1) + XCTAssertEqual(newHostnames[0], "https://malformed.com") + } +} diff --git a/mobile/ios/ClientTests/ClientTests.swift b/mobile/ios/ClientTests/ClientTests.swift new file mode 100644 index 0000000000..7bee0d5a9b --- /dev/null +++ b/mobile/ios/ClientTests/ClientTests.swift @@ -0,0 +1,94 @@ +/* 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/. */ + +import UIKit +import XCTest + +import Shared +import Storage +import WebKit +import Alamofire +@testable import Client + +class ClientTests: XCTestCase { + + func testSyncUA() { + let ua = UserAgent.syncUserAgent + let device = DeviceInfo.deviceModel() + let systemVersion = UIDevice.current.systemVersion + let expectedRegex = "^Firefox-iOS-Sync/[0-9\\.]+b[0-9]* \\(\(device); iPhone OS \(systemVersion)\\) \\([-_A-Za-z0-9= \\(\\)]+\\)$" + let loc = ua.range(of: expectedRegex, options: NSString.CompareOptions.regularExpression) + XCTAssertTrue(loc != nil, "Sync UA is as expected. Was \(ua)") + } + + // Simple test to make sure the WKWebView UA matches the expected FxiOS pattern. + func testUserAgent() { + let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String + + let compare: (String) -> Bool = { ua in + let range = ua.range(of: "^Mozilla/5\\.0 \\(.+\\) AppleWebKit/[0-9\\.]+ \\(KHTML, like Gecko\\) FxiOS/\(appVersion)b[0-9]* Mobile/[A-Za-z0-9]+ Safari/[0-9\\.]+$", options: NSString.CompareOptions.regularExpression) + return range != nil + } + + XCTAssertTrue(compare(UserAgent.defaultUserAgent()), "User agent computes correctly.") + XCTAssertTrue(compare(UserAgent.cachedUserAgent(checkiOSVersion: true)!), "User agent is cached correctly.") + + let expectation = self.expectation(description: "Found Firefox user agent") + + let webView = WKWebView() + webView.evaluateJavaScript("navigator.userAgent") { result, error in + let userAgent = result as! String + if compare(userAgent) { + expectation.fulfill() + } else { + XCTFail("User agent did not match expected pattern! \(userAgent)") + } + } + + waitForExpectations(timeout: 5, handler: nil) + } + + func testDesktopUserAgent() { + let compare: (String) -> Bool = { ua in + let range = ua.range(of: "^Mozilla/5\\.0 \\(Macintosh; Intel Mac OS X [0-9_]+\\) AppleWebKit/[0-9\\.]+ \\(KHTML, like Gecko\\) Safari/[0-9\\.]+$", options: NSString.CompareOptions.regularExpression) + return range != nil + } + + XCTAssertTrue(compare(UserAgent.desktopUserAgent()), "Desktop user agent computes correctly.") + } + + /// Our local server should only accept whitelisted hosts (localhost and 127.0.0.1). + /// All other localhost equivalents should return 403. + func testDisallowLocalhostAliases() { + // Allowed local hosts. The first two are equivalent since iOS forwards an + // empty host to localhost. + [ "localhost", + "", + "127.0.0.1", + ].forEach { XCTAssert(hostIsValid($0), "\($0) host should be valid.") } + + // Disallowed local hosts. WKWebView will direct them to our server, but the server + // should reject them. + [ "[::1]", + "2130706433", + "0", + "127.00.00.01", + "017700000001", + "0x7f.0x0.0x0.0x1" + ].forEach { XCTAssertFalse(hostIsValid($0), "\($0) host should not be valid.") } + } + + fileprivate func hostIsValid(_ host: String) -> Bool { + let expectation = self.expectation(description: "Validate host for \(host)") + let request = URLRequest(url: URL(string: "http://\(host):6571/about/license")!) + var response: HTTPURLResponse? + Alamofire.request(request).authenticate(usingCredential: WebServer.sharedInstance.credentials).response { (res) -> Void in + response = res.response + expectation.fulfill() + } + waitForExpectations(timeout: 100, handler: nil) + return response?.statusCode == 200 + } + +} diff --git a/mobile/ios/ClientTests/CustomSearchEnginesTest.swift b/mobile/ios/ClientTests/CustomSearchEnginesTest.swift new file mode 100644 index 0000000000..06c3ab88e8 --- /dev/null +++ b/mobile/ios/ClientTests/CustomSearchEnginesTest.swift @@ -0,0 +1,60 @@ +/* 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/. */ + +@testable import Client +import Shared +import Storage +import Sync +import UIKit + +import XCTest + +class CustomSearchEnginesTest: XCTestCase { + + func testgetSearchTemplate() { + let profile = MockBrowserProfile(localName: "customSearchTests") + let customSearchEngineForm = CustomSearchViewController() + customSearchEngineForm.profile = profile + + let template = customSearchEngineForm.getSearchTemplate(withString: "https://github.com/search=%s") + XCTAssertEqual(template, "https://github.com/search={searchTerms}") + + let badTemplate = customSearchEngineForm.getSearchTemplate(withString: "https://github.com/search=blah") + XCTAssertNil(badTemplate) + } + + func testaddSearchEngine() { + let profile = MockBrowserProfile(localName: "customSearchTests") + let customSearchEngineForm = CustomSearchViewController() + customSearchEngineForm.profile = profile + let q = "http://www.google.ca/?#q=%s" + let title = "YASE" + + let expectation = self.expectation(description: "Waiting on favicon fetching") + customSearchEngineForm.createEngine(forQuery: q, andName: title).uponQueue(DispatchQueue.main) { result in + XCTAssertNotNil(result.successValue, "Make sure the new engine is not nil") + let engine = result.successValue! + XCTAssertEqual(engine.shortName, title) + XCTAssertNotNil(engine.image) + XCTAssertEqual(engine.searchTemplate, "http://www.google.ca/?#q={searchTerms}") + expectation.fulfill() + } + waitForExpectations(timeout: 5, handler: nil) + } + + func testaddSearchEngineFailure() { + let profile = MockBrowserProfile(localName: "customSearchTests") + let customSearchEngineForm = CustomSearchViewController() + customSearchEngineForm.profile = profile + let q = "isthisvalid.com/hhh%s" + let title = "YASE" + + let expectation = self.expectation(description: "Waiting on favicon fetching") + customSearchEngineForm.createEngine(forQuery: q, andName: title).uponQueue(DispatchQueue.main) { result in + XCTAssertNil(result.successValue, "Make sure the new engine is nil") + expectation.fulfill() + } + waitForExpectations(timeout: 5, handler: nil) + } +} diff --git a/mobile/ios/ClientTests/FileAccessorTests.swift b/mobile/ios/ClientTests/FileAccessorTests.swift new file mode 100644 index 0000000000..79a6516f90 --- /dev/null +++ b/mobile/ios/ClientTests/FileAccessorTests.swift @@ -0,0 +1,76 @@ +/* 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/. */ + +import Foundation +import Storage +import XCTest + +class FileAccessorTests: XCTestCase { + fileprivate var testDir: String! + fileprivate var files: FileAccessor! + + override func setUp() { + let docPath: NSString = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as NSString + files = FileAccessor(rootPath: docPath.appendingPathComponent("filetest")) + + testDir = try! files.getAndEnsureDirectory() + try! files.removeFilesInDirectory() + } + + func testFileAccessor() { + // Test existence. + XCTAssertFalse(files.exists("foo"), "File doesn't exist") + createFile("foo") + XCTAssertTrue(files.exists("foo"), "File exists") + + // Test moving. + do { + try files.move("foo", toRelativePath: "bar") + XCTAssertFalse(files.exists("foo"), "Old doesn't exist") + XCTAssertTrue(files.exists("bar"), "New file exists") + } catch { + XCTFail("Unable to move 'foo' to 'bar' \(error)") + } + + do { + try files.move("bar", toRelativePath: "foo/bar") + XCTAssertFalse(files.exists("bar"), "Old doesn't exist") + XCTAssertTrue(files.exists("foo/bar"), "New file exists") + } catch { + XCTFail("Unable to move 'bar' to 'foo/bar' \(error)") + } + + // Test removal. + do { + XCTAssertTrue(files.exists("foo"), "File exists") + try files.remove("foo") + XCTAssertFalse(files.exists("foo"), "File removed") + } catch { + XCTFail("Unable to remove 'foo' \(error)") + } + + // Test directory creation and path. + do { + XCTAssertFalse(files.exists("foo"), "Directory doesn't exist") + let path = try files.getAndEnsureDirectory("foo") + var isDirectory = ObjCBool(false) + FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) + XCTAssertTrue(isDirectory.boolValue, "Directory exists") + } catch { + XCTFail("Unable to find directory 'foo' \(error)") + } + } + + fileprivate func createFile(_ filename: String) { + let path = (testDir as NSString).appendingPathComponent(filename) + let success: Bool + do { + try "foo".write(toFile: path, atomically: false, encoding: String.Encoding.utf8) + success = true + } catch _ { + success = false + } + XCTAssertTrue(success, "Wrote to \(path)") + } +} diff --git a/mobile/ios/ClientTests/FxADeepLinkingTests.swift b/mobile/ios/ClientTests/FxADeepLinkingTests.swift new file mode 100644 index 0000000000..8d97bf7216 --- /dev/null +++ b/mobile/ios/ClientTests/FxADeepLinkingTests.swift @@ -0,0 +1,42 @@ +/* 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/. */ + +import UIKit +import XCTest +@testable import Client +import Shared + +class FxADeepLinkingTests: XCTestCase { + var profile: MockProfile! + var vc: FxAContentViewController! + var expectUrl = URL(string: "https://accounts.firefox.com/signin?service=sync&context=fx_ios_v1&signin=test&utm_source=somesource&entrypoint=one") + + override func setUp() { + super.setUp() + self.profile = MockProfile() + self.vc = FxAContentViewController(profile: self.profile) + } + + func testLaunchWithNilOptions() { + let testUrl = self.vc.createFxAURLWith(nil, profile: self.profile) + // Should use default urls for nil options + XCTAssertEqual(testUrl, self.vc.profile.accountConfiguration.signInURL) + } + + func testLaunchWithOptions() { + let url = URL(string: "firefox://fxa-signin?signin=test&utm_source=somesource&entrypoint=one&ignore=this") + let query = url!.getQuery() + let fxaOptions = FxALaunchParams(query: query) + let testUrl = self.vc.createFxAURLWith(fxaOptions, profile: self.profile) + XCTAssertEqual(testUrl, expectUrl!) + } + + func testDoesntOverrideServiceContext() { + let url = URL(string: "firefox://fxa-signin?service=asdf&context=123&signin=test&entrypoint=one&utm_source=somesource&ignore=this") + let query = url!.getQuery() + let fxaOptions = FxALaunchParams(query: query) + let testUrl = self.vc.createFxAURLWith(fxaOptions, profile: self.profile) + XCTAssertEqual(testUrl, expectUrl!) + } +} diff --git a/mobile/ios/ClientTests/FxAPushMessageTest.swift b/mobile/ios/ClientTests/FxAPushMessageTest.swift new file mode 100644 index 0000000000..dedb71a77b --- /dev/null +++ b/mobile/ios/ClientTests/FxAPushMessageTest.swift @@ -0,0 +1,153 @@ +/* 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/. */ + +@testable import Account +@testable import Client +import Foundation +import FxA +import SwiftyJSON +import XCTest + +class FxAPushMessageTest: XCTestCase { + func testMessage_subscriptionDecryption() { + var userInfo: [AnyHashable: Any] = [ + "chid": "034f52789f7b44ecaf119cc59231cdc1", + "enc": "keyid=p256dh;salt=mYBHM3B_oXlEjV0HfgHZ1A", + "body": "_tZf65gKC23STnTNuhtSSbrg1LScGiLjO4GOIuHlCGIFFEzcwsB-J-s3pe3qu2d24A-sKwVyolmShlMBEvEX_34f6FgXMs3k35g4u5STKgJMQxZ8VFDjtQqQfxfSIEt35pdKaPwXKH2zbs0xHC3qEJ0YMc60Eq8uAuQF7FQZ7ts", + "cryptokey": "keyid=p256dh;dh=BNLZ2IWMNGioofzMBnSijySib0Pa-lwgBfLYIhqvvmKxprKgEh6JCDB2DBUmj9BuJCk6xJvBbPd-4x_8tb-qIPM;p256ecdsa=BP-OR33RzQSlrzD7_d1kYE9i9WjSIQAKTuhHxYNiPEF0i-wxeNIIwxthwU7zBTbumyxFUeydrmxcVKXugjBImRU", + "con": "aesgcm", + "ver": "gAAAAABY5hUl_Pi1bVI4ptqKzPWq_aulqXEO1eOx_ncUuwoz8zItWWLA4Ix1ZbDLTOkurqK1vE3N3y1ZXsp_MZ69QJYRuWg5V_3T_XUNVBxj8dnDcNAE-ep9_M5xeKiNdngdww-cqqMOxf-tI5ZoR2nQFqWSs51XGwMMIdsGNmUPqnR4w2Rzt6FYz-AsGCrHXJ3bmYbwpq4P", + ] + + let subscription = PushSubscription(channelID: "channel", + endpoint: URL(string: "https://example.ru")!, + p256dhPrivateKey: "UDnicgor_Il7cLNTqSt--SrEblNBbgPA2yXAQ_b31xI", + p256dhPublicKey: "BB4XdAhpVVU45NYSXHpRiubMYoaeb0A-y5aSGE437YKGHQihlvlZMv5D0ebK6WmFqzpIr217Kv9oCbZVDp1KGK4", + authKey: "0gH7RiYYMhfHDQ1L1X4RMw") + + let body = userInfo["body"] as! String + let enc = userInfo["enc"] as! String + let cryptokey = userInfo["cryptokey"] as! String + + guard let plaintext = subscription.aesgcm(payload: body, encryptionHeader: enc, cryptoHeader: cryptokey) else { + return XCTFail("Decryption failed") + } + + let json = JSON(parseJSON: plaintext) + + XCTAssertEqual(json["command"].stringValue, "fxaccounts:device_connected") + } + + func testMessageHandler() { + let subscription = PushSubscription(channelID: "channel", + endpoint: URL(string: "https://example.ru")!, + p256dhPrivateKey: "t7dcZIN4w37UYjE6u3lBLB0WOShxqelkbJFKKzMDSsE", + p256dhPublicKey: "BIXFDlhppL2lc5GcIXbGPa1iVdJn5ULYaF1ltJY9Qm17-tIC_9eEZXtalPpMRXsFmEKhdn2ttg3KQ3t-ztQ3ShQ", + authKey: "a8E3EO5F6FFWdv4hAGyGyw") + + let userInfo: [AnyHashable: Any] = [ + AnyHashable("chid"): "f6defa012a6249e58bbfbf2995f8d425", + AnyHashable("enc"): "keyid=p256dh;salt=nslkEsUqUg5sQ7_sRZfOjg", + AnyHashable("body"): "Q1t-ttSwQMxUI64Ls3vOU-hE_qg1AIUzyLQSpEkx-8JITh5UJ7oq25faEc8XPoTYQoaHQ2d--QIK_yVorbt-0Yr7IO4BmtSSX-e4kSx76fWzqKjEpEt7Vr3Av5seEBeoAT2FZRzehkFjNVWoTw", + AnyHashable("cryptokey"): "keyid=p256dh;dh=BNfUPK_8eUTZGOyXq07lthBfHeIxC2B7L_gF3cMGK1jVfDe9tlgxpHD_mbKrt3p12d7_O__wizhne2a1Eb7pZgk;p256ecdsa=BFSuld8S4PbRcgGe3OQPN9NyIOXx-ccUIMb0q6nIpH7Qf894wz0TIQTXQ7I7pWjZiN9KCdYVjNhyPtr1--37ois", + AnyHashable("con"): "aesgcm", + AnyHashable("ver"): "gAAAAABZLbG-m7EHhcMdrqs51SkESIZHsZjvw2QIu8LOeXxcKEy6wDVCprOKFAfJU44cinfJcDtCnO9EEyzpFt5e0HBDCLybGyThoZzmiod6zTLhTfAKZe-SyElSVCL0UDpJ_-U3UTUUHUaJXeRf0z6NvFM-uL39Jy-dwr3cuJoSDIcTPdChRPFiIS1hwokqMlxOn36azxOi", + ] + + let profile = MockProfile() + + let account = FirefoxAccount( + configuration: FirefoxAccountConfigurationLabel.production.toConfiguration(), + email: "testtest@test.com", + uid: "uid", + deviceRegistration: nil, + stateKeyLabel: "xxx", + state: SeparatedState()) + + let registration = PushRegistration(uaid: "uaid", secret: "secret", subscription: subscription) + + account.pushRegistration = registration + profile.setAccount(account) + + let handler = FxAPushMessageHandler(with: profile) + + let expectation = XCTestExpectation() + handler.handle(userInfo: userInfo).upon { maybe in + XCTAssertTrue(maybe.isSuccess) + XCTAssertEqual(maybe.successValue!, PushMessage.collectionChanged(collections: ["clients", "tabs"])) + expectation.fulfill() + } + wait(for: [expectation], timeout: 10) + } + + func createHandler(_ profile: Profile = MockProfile()) -> FxAPushMessageHandler { + let account = FirefoxAccount( + configuration: FirefoxAccountConfigurationLabel.production.toConfiguration(), + email: "testtest@test.com", + uid: "uid", + deviceRegistration: nil, + stateKeyLabel: "xxx", + state: SeparatedState()) + + profile.setAccount(account) + + return FxAPushMessageHandler(with: profile) + } + + func test_deviceConnected() { + let handler = createHandler() + + let expectation = XCTestExpectation() + handler.handle(plaintext: "{\"command\":\"fxaccounts:device_connected\",\"data\":{\"deviceName\": \"Use Nightly on Desktop\"}}").upon { maybe in + XCTAssertTrue(maybe.isSuccess) + guard let message = maybe.successValue else { + return expectation.fulfill() + } + XCTAssertEqual(message, PushMessage.deviceConnected("Use Nightly on Desktop")) + expectation.fulfill() + } + wait(for: [expectation], timeout: 10) + } + + func test_deviceDisconnected() { + let profile = MockProfile() + let handler = createHandler(profile) + let prefs = profile.prefs + + let expectation = XCTestExpectation() + handler.handle(plaintext: "{\"command\":\"fxaccounts:device_disconnected\",\"data\":{\"id\": \"not_this_device\"}}").upon { maybe in + XCTAssertTrue(maybe.isSuccess) + guard let message = maybe.successValue else { + return expectation.fulfill() + } + XCTAssertEqual(message.messageType, .deviceDisconnected) + XCTAssertFalse(prefs.boolForKey(PendingAccountDisconnectedKey) ?? false) + expectation.fulfill() + } + wait(for: [expectation], timeout: 10) + + } + + func test_thisDeviceDisconnected() { + let profile = MockProfile() + let handler = createHandler(profile) + + let deviceRegistration = FxADeviceRegistration(id: "this-device-id", version: 1, lastRegistered: 0) + profile.account?.deviceRegistration = deviceRegistration + + let prefs = profile.prefs + + let expectation = XCTestExpectation() + handler.handle(plaintext: "{\"command\":\"fxaccounts:device_disconnected\",\"data\":{\"id\": \"\(deviceRegistration.id)\"}}").upon { maybe in + guard let message = maybe.successValue else { + return expectation.fulfill() + } + XCTAssertEqual(message, PushMessage.thisDeviceDisconnected) + XCTAssertTrue(prefs.boolForKey(PendingAccountDisconnectedKey) ?? false) + expectation.fulfill() + } + wait(for: [expectation], timeout: 10) + + } +} diff --git a/mobile/ios/ClientTests/HomePageTests.swift b/mobile/ios/ClientTests/HomePageTests.swift new file mode 100644 index 0000000000..a4bc3416bf --- /dev/null +++ b/mobile/ios/ClientTests/HomePageTests.swift @@ -0,0 +1,16 @@ +/* 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/. */ + +@testable import Client +import XCTest + +class HomePageTests: XCTestCase { + let prefs = NSUserDefaultsPrefs(prefix: "PrefsTests") + + func testHomePageSettingForInternalURLs() { + let helper = HomePageHelper(prefs: prefs) + helper.currentURL = URL(string: "http://localhost:6571") + XCTAssertNil(prefs.stringForKey(HomePageConstants.HomePageURLPrefKey)) + } +} diff --git a/mobile/ios/ClientTests/Info.plist b/mobile/ios/ClientTests/Info.plist new file mode 100644 index 0000000000..9411e4a06e --- /dev/null +++ b/mobile/ios/ClientTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/ClientTests/MockProfile.swift b/mobile/ios/ClientTests/MockProfile.swift new file mode 100644 index 0000000000..2e16e645b8 --- /dev/null +++ b/mobile/ios/ClientTests/MockProfile.swift @@ -0,0 +1,235 @@ +/* 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/. */ + +@testable import Client +import Foundation +import Account +import ReadingList +import Shared +import Storage +import Sync +import XCTest +import Deferred + +open class MockSyncManager: SyncManager { + open var isSyncing = false + open var lastSyncFinishTime: Timestamp? + open var syncDisplayState: SyncDisplayState? + + open func hasSyncedHistory() -> Deferred> { + return deferMaybe(true) + } + + private func completedWithStats(collection: String) -> Deferred> { + return deferMaybe(SyncStatus.completed(SyncEngineStatsSession(collection: collection))) + } + + open func syncClients() -> SyncResult { return completedWithStats(collection: "mock_clients") } + open func syncClientsThenTabs() -> SyncResult { return completedWithStats(collection: "mock_clientsandtabs") } + open func syncHistory() -> SyncResult { return completedWithStats(collection: "mock_history") } + open func syncLogins() -> SyncResult { return completedWithStats(collection: "mock_logins") } + open func mirrorBookmarks() -> SyncResult { return completedWithStats(collection: "mock_bookmarks") } + open func syncEverything(why: SyncReason) -> Success { + return succeed() + } + open func syncNamedCollections(why: SyncReason, names: [String]) -> Success { + return succeed() + } + open func beginTimedSyncs() {} + open func endTimedSyncs() {} + open func applicationDidBecomeActive() { + self.beginTimedSyncs() + } + open func applicationDidEnterBackground() { + self.endTimedSyncs() + } + + open func onNewProfile() { + } + + open func onAddedAccount() -> Success { + return succeed() + } + open func onRemovedAccount(_ account: FirefoxAccount?) -> Success { + return succeed() + } + + open func hasSyncedLogins() -> Deferred> { + return deferMaybe(true) + } +} + +open class MockTabQueue: TabQueue { + open func addToQueue(_ tab: ShareItem) -> Success { + return succeed() + } + + open func getQueuedTabs() -> Deferred>> { + return deferMaybe(ArrayCursor(data: [])) + } + + open func clearQueuedTabs() -> Success { + return succeed() + } +} + +open class MockPanelDataObservers: PanelDataObservers { + override init(profile: Profile) { + super.init(profile: profile) + self.activityStream = MockActivityStreamDataObserver(profile: profile) + } +} + +open class MockActivityStreamDataObserver: DataObserver { + public var profile: Profile + public weak var delegate: DataObserverDelegate? + + init(profile: Profile) { + self.profile = profile + } + + public func refreshIfNeeded(forceHighlights highlights: Bool, forceTopSites topsites: Bool) { + + } +} + +open class MockProfile: Profile { + // Read/Writeable properties for mocking + public var recommendations: HistoryRecommendations + public var places: BrowserHistory & Favicons & SyncableHistory & ResettableSyncStorage & HistoryRecommendations + public var files: FileAccessor + public var history: BrowserHistory & SyncableHistory & ResettableSyncStorage + public var logins: BrowserLogins & SyncableLogins & ResettableSyncStorage + public var syncManager: SyncManager! + + public lazy var panelDataObservers: PanelDataObservers = { + return MockPanelDataObservers(profile: self) + }() + + var db: BrowserDB + + fileprivate let name: String = "mockaccount" + + init() { + files = MockFiles() + syncManager = MockSyncManager() + logins = MockLogins(files: files) + db = BrowserDB(filename: "mock.db", schema: BrowserSchema(), files: files) + places = SQLiteHistory(db: self.db, prefs: MockProfilePrefs()) + recommendations = places + history = places + } + + public func localName() -> String { + return name + } + + public func reopen() { + } + + public func shutdown() { + } + + public var isShutdown: Bool = false + + public var favicons: Favicons { + return self.places + } + + lazy public var queue: TabQueue = { + return MockTabQueue() + }() + + lazy public var metadata: Metadata = { + return SQLiteMetadata(db: self.db) + }() + + lazy public var isChinaEdition: Bool = { + return Locale.current.identifier == "zh_CN" + }() + + lazy public var certStore: CertStore = { + return CertStore() + }() + + lazy public var bookmarks: BookmarksModelFactorySource & KeywordSearchSource & SyncableBookmarks & LocalItemSource & MirrorItemSource & ShareToDestination = { + // Make sure the rest of our tables are initialized before we try to read them! + // This expression is for side-effects only. + let p = self.places + + return MergedSQLiteBookmarks(db: self.db) + }() + + lazy public var searchEngines: SearchEngines = { + return SearchEngines(prefs: self.prefs, files: self.files) + }() + + lazy public var prefs: Prefs = { + return MockProfilePrefs() + }() + + lazy public var readingList: ReadingListService? = { + return ReadingListService(profileStoragePath: self.files.rootPath as String) + }() + + lazy public var recentlyClosedTabs: ClosedTabsStore = { + return ClosedTabsStore(prefs: self.prefs) + }() + + internal lazy var remoteClientsAndTabs: RemoteClientsAndTabs = { + return SQLiteRemoteClientsAndTabs(db: self.db) + }() + + fileprivate lazy var syncCommands: SyncCommands = { + return SQLiteRemoteClientsAndTabs(db: self.db) + }() + + public let accountConfiguration: FirefoxAccountConfiguration = ProductionFirefoxAccountConfiguration() + var account: FirefoxAccount? + + public func hasAccount() -> Bool { + return account != nil + } + + public func hasSyncableAccount() -> Bool { + return account?.actionNeeded == FxAActionNeeded.none + } + + public func getAccount() -> FirefoxAccount? { + return account + } + + public func setAccount(_ account: FirefoxAccount) { + self.account = account + self.syncManager.onAddedAccount() + } + + public func flushAccount() {} + + public func removeAccount() { + let old = self.account + self.account = nil + self.syncManager.onRemovedAccount(old) + } + + public func getClients() -> Deferred> { + return deferMaybe([]) + } + + public func getClientsAndTabs() -> Deferred> { + return deferMaybe([]) + } + + public func getCachedClientsAndTabs() -> Deferred> { + return deferMaybe([]) + } + + public func storeTabs(_ tabs: [RemoteTab]) -> Deferred> { + return deferMaybe(0) + } + + public func sendItems(_ items: [ShareItem], toClients clients: [RemoteClient]) -> Deferred> { + return deferMaybe(SyncStatus.notStarted(.offline)) + } +} diff --git a/mobile/ios/ClientTests/MockableHistory.swift b/mobile/ios/ClientTests/MockableHistory.swift new file mode 100644 index 0000000000..32ba2cfb79 --- /dev/null +++ b/mobile/ios/ClientTests/MockableHistory.swift @@ -0,0 +1,45 @@ +/* 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/. */ + +import Foundation +import Storage +import Deferred +import Shared + +/* + * A class that adheres to all the requirements for a profile's history property + * with all of the methods set to fatalError. Use this class if you're looking to + * mock out parts of the history API + */ +class MockableHistory: BrowserHistory, SyncableHistory, ResettableSyncStorage { + func getFrecentHistory() -> FrecentHistory { fatalError() } + func getTopSitesWithLimit(_ limit: Int) -> Deferred>> { fatalError() } + func addLocalVisit(_ visit: SiteVisit) -> Success { fatalError() } + func clearHistory() -> Success { fatalError() } + func removeHistoryForURL(_ url: String) -> Success { fatalError() } + func removeSiteFromTopSites(_ site: Site) -> Success { fatalError() } + func removeHostFromTopSites(_ host: String) -> Success { fatalError() } + func clearTopSitesCache() -> Success { fatalError() } + func removeFromPinnedTopSites(_ site: Site) -> Success { fatalError() } + func addPinnedTopSite(_ site: Site) -> Success { fatalError() } + func getPinnedTopSites() -> Deferred>> { fatalError() } + func getSitesByLastVisit(_ limit: Int) -> Deferred>> { fatalError() } + func setTopSitesNeedsInvalidation() { fatalError() } + func updateTopSitesCacheIfInvalidated() -> Deferred> { fatalError() } + func setTopSitesCacheSize(_ size: Int32) { fatalError() } + func onRemovedAccount() -> Success { fatalError() } + func ensurePlaceWithURL(_ url: String, hasGUID guid: GUID) -> Success { fatalError() } + func deleteByGUID(_ guid: GUID, deletedAt: Timestamp) -> Success { fatalError() } + func storeRemoteVisits(_ visits: [Visit], forGUID guid: GUID) -> Success { fatalError() } + func insertOrUpdatePlace(_ place: Place, modified: Timestamp) -> Deferred> { fatalError() } + func getModifiedHistoryToUpload() -> Deferred> { fatalError() } + func getDeletedHistoryToUpload() -> Deferred> { fatalError() } + func markAsSynchronized(_: [GUID], modified: Timestamp) -> Deferred> { fatalError() } + func markAsDeleted(_ guids: [GUID]) -> Success { fatalError() } + func doneApplyingRecordsAfterDownload() -> Success { fatalError() } + func doneUpdatingMetadataAfterUpload() -> Success { fatalError() } + func hasSyncedHistory() -> Deferred> { fatalError() } + func resetClient() -> Success { fatalError() } +} + diff --git a/mobile/ios/ClientTests/PanelDataObserversTests.swift b/mobile/ios/ClientTests/PanelDataObserversTests.swift new file mode 100644 index 0000000000..af25315fa7 --- /dev/null +++ b/mobile/ios/ClientTests/PanelDataObserversTests.swift @@ -0,0 +1,84 @@ +/* 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/. */ + +import Foundation +import Shared +import XCTest +@testable import Client + +private class MockDataObserverDelegate: DataObserverDelegate { + var didInvalidateCount = 0 + var willInvalidateCount = 0 + var highlightsRefreshCount = 0 + var topSitesRefreshCount = 0 + + func didInvalidateDataSources(refresh forced: Bool, highlightsRefreshed: Bool, topSitesRefreshed: Bool) { + didInvalidateCount += 1 + if highlightsRefreshed { + highlightsRefreshCount += 1 + } + + if topSitesRefreshed { + topSitesRefreshCount += 1 + } + } + + func willInvalidateDataSources(forceHighlights highlights: Bool, forceTopSites topSites: Bool) { + willInvalidateCount += 1 + } +} + +class PanelDataObserversTests: XCTestCase { + func testActivityStreamDelegates() { + let profile = MockProfile() + let observer = ActivityStreamDataObserver(profile: profile) + let delegate = MockDataObserverDelegate() + observer.delegate = delegate + + NotificationCenter.default.post(name: NotificationFirefoxAccountChanged, + object: nil) + NotificationCenter.default.post(name: NotificationProfileDidFinishSyncing, + object: nil) + NotificationCenter.default.post(name: NotificationPrivateDataClearedHistory, + object: nil) + + waitForCondition(timeout: 5) { delegate.didInvalidateCount == 3 && delegate.willInvalidateCount == 3 } + } + + func testHighlightsCacheInvalidation20Min() { + let profile = MockProfile() + let observer = ActivityStreamDataObserver(profile: profile) + let delegate = MockDataObserverDelegate() + observer.delegate = delegate + + // Set to 20min since refresh + profile.prefs.setLong(Date.now() - (OneMinuteInMilliseconds * 20), forKey: PrefsKeys.ASLastInvalidation) + observer.refreshIfNeeded(forceHighlights: false, forceTopSites: false) + waitForCondition(timeout: 5) { delegate.highlightsRefreshCount == 1 } + } + + func testHighlightEmptyCache() { + let profile = MockProfile() + let observer = ActivityStreamDataObserver(profile: profile) + let delegate = MockDataObserverDelegate() + observer.delegate = delegate + + // Set to no validation key + profile.prefs.removeObjectForKey(PrefsKeys.ASLastInvalidation) + observer.refreshIfNeeded(forceHighlights: false, forceTopSites: false) + waitForCondition(timeout: 5) { delegate.highlightsRefreshCount == 1 } + } + + func testHighlightActiveCache() { + let profile = MockProfile() + let observer = ActivityStreamDataObserver(profile: profile) + let delegate = MockDataObserverDelegate() + observer.delegate = delegate + + // Set to 10min since refresh + profile.prefs.setLong(Date.now() - (OneMinuteInMilliseconds * 10), forKey: PrefsKeys.ASLastInvalidation) + observer.refreshIfNeeded(forceHighlights: false, forceTopSites: false) + waitForCondition(timeout: 5) { delegate.didInvalidateCount == 1 && delegate.highlightsRefreshCount == 0 } + } +} diff --git a/mobile/ios/ClientTests/PingCentreTests.swift b/mobile/ios/ClientTests/PingCentreTests.swift new file mode 100644 index 0000000000..056f865ca2 --- /dev/null +++ b/mobile/ios/ClientTests/PingCentreTests.swift @@ -0,0 +1,104 @@ +/* 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/. */ + +@testable import Client +import XCTest +import JSONSchema +import Alamofire +import Deferred +import Shared +@testable import SyncTelemetry + +private let mockTopic = PingCentreTopic(name: "ios-mock", schema: Schema([ + "type": "object", + "properties": [ + "title": ["type": "string"] + ], + "required": [ + "title" + ] +])) + +private var receivedNetworkRequests = [URLRequest]() + +// Used to mock the network so we don't need to rely on the interweb for our unit tests. +class MockingURLProtocol: URLProtocol { + override class func canInit(with request: URLRequest) -> Bool { + return request.url?.scheme == "https" && request.httpMethod == "POST" + } + + override class func canonicalRequest(for request: URLRequest) -> URLRequest { + return request + } + + override func startLoading() { + receivedNetworkRequests.append(request) + let response = HTTPURLResponse(url: request.url!, + statusCode: 200, + httpVersion: "HTTP/1.1", + headerFields: [:]) + + self.client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: .notAllowed) + self.client?.urlProtocol(self, didLoad: "".data(using: String.Encoding.utf8)!) + self.client?.urlProtocolDidFinishLoading(self) + } + + override func stopLoading() { + //no-op + } +} + +class PingCentreTests: XCTestCase { + var manager: SessionManager! + var client: PingCentreClient! + + override func setUp() { + super.setUp() + + let configuration = URLSessionConfiguration.default + configuration.protocolClasses!.insert(MockingURLProtocol.self, at: 0) + + self.manager = SessionManager(configuration: configuration) + self.client = DefaultPingCentreImpl(topic: mockTopic, endpoint: .staging, clientID: "fakeID", manager: self.manager) + } + + override func tearDown() { + receivedNetworkRequests = [] + } + + func testSendPing() { + let validPing = [ + "title": "Test!" + ] + let invalidPing = [String: AnyObject]() + + client.sendPing(validPing, validate: true).succeeded() + let validationError = client.sendPing(invalidPing, validate: true).value + XCTAssertNotNil(validationError.failureValue) + XCTAssertTrue(validationError.failureValue! is PingValidationError) + + // Double check that we actually sent the successful ping and not the invalid one + XCTAssertTrue(receivedNetworkRequests.count == 1) + } + + func testSendBatch() { + let validPingA = ["title": "A"] + let validPingB = ["title": "B"] + let invalidPingC = [String: AnyObject]() + + client.sendBatch([validPingA, validPingB], validate: true).succeeded() + let validationError = client.sendBatch([validPingA, invalidPingC], validate: true).value + + XCTAssertNotNil(validationError.failureValue) + XCTAssertTrue(validationError.failureValue! is PingValidationError) + + // Double check that we actually sent the successful ping and not the invalid one + XCTAssertTrue(receivedNetworkRequests.count == 1) + + client.sendBatch([], validate: true).succeeded() + + // Double check that we didn't send the empty payloads request + XCTAssertTrue(receivedNetworkRequests.count == 1) + } +} diff --git a/mobile/ios/ClientTests/PocketFeedTests.swift b/mobile/ios/ClientTests/PocketFeedTests.swift new file mode 100644 index 0000000000..6c07793cf3 --- /dev/null +++ b/mobile/ios/ClientTests/PocketFeedTests.swift @@ -0,0 +1,67 @@ +/* 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/. */ + +import UIKit +import GCDWebServers +import XCTest + +@testable import Client + +class PocketStoriesTests: XCTestCase { + + var pocketAPI: String! + let webServer: GCDWebServer = GCDWebServer() + + /// Setup a basic web server that binds to a random port and that has one default handler on /hello + fileprivate func setupWebServer() { + let path = Bundle(for: type(of: self)).path(forResource: "pocketglobalfeed", ofType: "json") + let data = try! Data(contentsOf: URL(fileURLWithPath: path!)) + + webServer.addHandler(forMethod: "GET", path: "/pocketglobalfeed", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + return GCDWebServerDataResponse(data: data, contentType: "application/json") + } + + if webServer.start(withPort: 0, bonjourName: nil) == false { + XCTFail("Can't start the GCDWebServer") + } + pocketAPI = "http://localhost:\(webServer.port)/pocketglobalfeed" + } + + override func setUp() { + super.setUp() + setupWebServer() + } + + override func tearDown() { + super.tearDown() + } + + func testPocketStoriesCaching() { + let expect = expectation(description: "Pocket") + let PocketFeed = Pocket(endPoint: pocketAPI) + + PocketFeed.globalFeed(items: 4).upon { result in + let items = result + XCTAssertEqual(items.count, 2, "We are fetching a static feed. There are only 2 items in it") + self.webServer.stop() // Stop the webserver so we can check caching + + // Try again now that the webserver is down + PocketFeed.globalFeed(items: 4).upon { result in + let items = result + XCTAssertEqual(items.count, 2, "We are fetching a static feed. There are only 2 items in it") + let item = items.first + //These are all not optional so they should never be nil. + //But lets check in case someone decides to change something + XCTAssertNotNil(item?.domain, "Why") + XCTAssertNotNil(item?.imageURL, "You") + XCTAssertNotNil(item?.storyDescription, "Do") + XCTAssertNotNil(item?.title, "This") + XCTAssertNotNil(item?.url, "?") + expect.fulfill() + } + } + waitForExpectations(timeout: 10, handler: nil) + } + +} diff --git a/mobile/ios/ClientTests/PrefsTests.swift b/mobile/ios/ClientTests/PrefsTests.swift new file mode 100644 index 0000000000..8330f21f55 --- /dev/null +++ b/mobile/ios/ClientTests/PrefsTests.swift @@ -0,0 +1,100 @@ +/* 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/. */ + +@testable import Client +import Foundation +import Shared + +import XCTest + +class PrefsTests: XCTestCase { + var prefs: NSUserDefaultsPrefs! + + override func setUp() { + super.setUp() + prefs = NSUserDefaultsPrefs(prefix: "PrefsTests") + } + + override func tearDown() { + prefs.clearAll() + super.tearDown() + } + + func testClearPrefs() { + prefs.setObject("foo", forKey: "bar") + XCTAssertEqual(prefs.stringForKey("bar")!, "foo") + + // Ensure clearing prefs is branch-specific. + let otherPrefs = NSUserDefaultsPrefs(prefix: "othermockaccount") + otherPrefs.clearAll() + XCTAssertEqual(prefs.stringForKey("bar")!, "foo") + + prefs.clearAll() + XCTAssertNil(prefs.stringForKey("bar")) + } + + func testStringForKey() { + XCTAssertNil(prefs.stringForKey("key")) + prefs.setObject("value", forKey: "key") + XCTAssertEqual(prefs.stringForKey("key")!, "value") + // Non-String values return nil. + prefs.setObject(1, forKey: "key") + XCTAssertNil(prefs.stringForKey("key")) + } + + func testBoolForKey() { + XCTAssertNil(prefs.boolForKey("key")) + prefs.setObject(true, forKey: "key") + XCTAssertEqual(prefs.boolForKey("key")!, true) + prefs.setObject(false, forKey: "key") + XCTAssertEqual(prefs.boolForKey("key")!, false) + // We would like non-Bool values to return nil, but I can't figure out how to differentiate. + // Instead, this documents the undesired behaviour. + prefs.setObject(1, forKey: "key") + XCTAssertEqual(prefs.boolForKey("key")!, true) + prefs.setObject("1", forKey: "key") + XCTAssertNil(prefs.boolForKey("key")) + prefs.setObject("x", forKey: "key") + XCTAssertNil(prefs.boolForKey("key")) + } + + func testStringArrayForKey() { + XCTAssertNil(prefs.stringArrayForKey("key")) + prefs.setObject(["value1", "value2"], forKey: "key") + XCTAssertEqual(prefs.stringArrayForKey("key")!, ["value1", "value2"]) + // Non-[String] values return nil. + prefs.setObject(1, forKey: "key") + XCTAssertNil(prefs.stringArrayForKey("key")) + // [Non-String] values return nil. + prefs.setObject([1, 2], forKey: "key") + XCTAssertNil(prefs.stringArrayForKey("key")) + } + + func testMockProfilePrefsRoundtripsTimestamps() { + let prefs = MockProfilePrefs().branch("baz") + let val: Timestamp = Date.now() + prefs.setLong(val, forKey: "foobar") + XCTAssertEqual(val, prefs.unsignedLongForKey("foobar")!) + } + + func testMockProfilePrefsKeys() { + let prefs = MockProfilePrefs().branch("baz") as! MockProfilePrefs + let val: Timestamp = Date.now() + prefs.setLong(val, forKey: "foobar") + XCTAssertEqual(val, (prefs.things["baz.foobar"] as! NSNumber).uint64Value) + } + + func testMockProfilePrefsClearAll() { + let prefs1 = MockProfilePrefs().branch("bar") as! MockProfilePrefs + let prefs2 = MockProfilePrefs().branch("baz") as! MockProfilePrefs + + // Ensure clearing prefs is branch-specific. + prefs1.setInt(123, forKey: "foo") + prefs2.clearAll() + XCTAssertEqual(123, prefs1.intForKey("foo")!) + + prefs1.clearAll() + XCTAssertNil(prefs1.intForKey("foo") as AnyObject?) + } +} diff --git a/mobile/ios/ClientTests/ProfileTest.swift b/mobile/ios/ClientTests/ProfileTest.swift new file mode 100644 index 0000000000..23b997fcb7 --- /dev/null +++ b/mobile/ios/ClientTests/ProfileTest.swift @@ -0,0 +1,28 @@ +/* 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/. */ + +@testable import Client +import Foundation +import Shared +import Storage +import SwiftKeychainWrapper + +import XCTest + +/* + * A base test type for tests that need a profile. + */ +class ProfileTest: XCTestCase { + func withTestProfile(_ callback: (_ profile: Profile) -> Void) { + callback(MockProfile()) + } + + func testNewProfileClearsExistingAuthenticationInfo() { + let authInfo = AuthenticationKeychainInfo(passcode: "1234") + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authInfo) + XCTAssertNotNil(KeychainWrapper.sharedAppContainerKeychain.authenticationInfo()) + let _ = BrowserProfile(localName: "my_profile", clear: true) + XCTAssertNil(KeychainWrapper.sharedAppContainerKeychain.authenticationInfo()) + } +} diff --git a/mobile/ios/ClientTests/RelativeDatesTests.swift b/mobile/ios/ClientTests/RelativeDatesTests.swift new file mode 100644 index 0000000000..ec89b4fa2a --- /dev/null +++ b/mobile/ios/ClientTests/RelativeDatesTests.swift @@ -0,0 +1,40 @@ +/* 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/. */ + +import Foundation +import XCTest + +class RelativeDatesTests: XCTestCase { + func testRelativeDates() { + let dateOrig = Date() + var date = Date(timeInterval: 0, since: dateOrig) + + XCTAssertEqual(date.toRelativeTimeString(), "just now") + + date = Date(timeInterval: -10, since: dateOrig) + XCTAssertEqual(date.toRelativeTimeString(), "just now") + + date = Date(timeInterval: -60, since: dateOrig) + XCTAssertEqual(date.toRelativeTimeString(), ("today at " + DateFormatter.localizedString(from: date, dateStyle: DateFormatter.Style.none, timeStyle: DateFormatter.Style.short))) + + let calendar = Calendar.autoupdatingCurrent + date = calendar.date(byAdding: .day, value: -1, to: dateOrig)! + XCTAssertEqual(date.toRelativeTimeString(), "yesterday") + + date = calendar.date(byAdding: .day, value: -2, to: dateOrig)! + XCTAssertEqual(date.toRelativeTimeString(), "this week") + + date = calendar.date(byAdding: .day, value: -7, to: dateOrig)! + XCTAssertEqual(date.toRelativeTimeString(), "more than a week ago") + + date = calendar.date(byAdding: .day, value: -7 * 5, to: dateOrig)! + XCTAssertEqual(date.toRelativeTimeString(), "more than a month ago") + + date = Date(timeInterval: -60 * 60 * 24 * 7 * 5 * 2, since: dateOrig) + XCTAssertEqual(date.toRelativeTimeString(), DateFormatter.localizedString(from: date, dateStyle: DateFormatter.Style.short, timeStyle: DateFormatter.Style.short)) + + date = Date(timeInterval: -60 * 60 * 24 * 7 * 5 * 12 * 2, since: dateOrig) + XCTAssertEqual(date.toRelativeTimeString(), DateFormatter.localizedString(from: date, dateStyle: DateFormatter.Style.short, timeStyle: DateFormatter.Style.short)) + } +} diff --git a/mobile/ios/ClientTests/ResetTests.swift b/mobile/ios/ClientTests/ResetTests.swift new file mode 100644 index 0000000000..06e8e794c8 --- /dev/null +++ b/mobile/ios/ClientTests/ResetTests.swift @@ -0,0 +1,78 @@ +/* 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/. */ + +@testable import Client +import Shared +@testable import Storage +import Sync +import UIKit + +import XCTest + +class MockBrowserProfile: BrowserProfile { + var peekSyncManager: BrowserSyncManager { + return self.syncManager as! BrowserSyncManager + } + + var peekTabs: SQLiteRemoteClientsAndTabs { + return self.remoteClientsAndTabs as! SQLiteRemoteClientsAndTabs + } +} + +class MockEngineStateChanges: EngineStateChanges { + var collections: [String] = [] + var enabled: [String] = [] + var disabled: [String] = [] + var clearWasCalled: Bool = false + + func collectionsThatNeedLocalReset() -> [String] { + return self.collections + } + + func enginesEnabled() -> [String] { + return self.enabled + } + + func enginesDisabled() -> [String] { + return self.disabled + } + + func clearLocalCommands() { + clearWasCalled = true + } +} + +func assertClientsHaveGUIDsFromStorage(_ storage: RemoteClientsAndTabs, expected: [GUID]) { + let recs = storage.getClients().value.successValue + XCTAssertNotNil(recs) + XCTAssertEqual(expected, recs!.map { $0.guid! }) +} + +class ResetTests: XCTestCase { + func testResetting() { + let profile = MockBrowserProfile(localName: "testResetTests") + + // Add a client. + let tabs = profile.peekTabs + XCTAssertTrue(tabs.insertOrUpdateClient(RemoteClient(guid: "abcdefghijkl", name: "Remote", modified: Date.now(), type: "mobile", formfactor: "tablet", os: "Windows", version: "55.0.1a", fxaDeviceId: "fxa1")).value.isSuccess) + _ = tabs.replaceRemoteDevices([RemoteDevice(id: "fxa1", name: "Device 1", type: "desktop", isCurrentDevice: false, lastAccessTime: 123)]).succeeded() + + // Verify that it's there. + assertClientsHaveGUIDsFromStorage(tabs, expected: ["abcdefghijkl"]) + + // Tell the sync manager that "clients" has changed syncID. + let e = MockEngineStateChanges() + e.collections.append("clients") + + XCTAssertTrue(profile.peekSyncManager.takeActionsOnEngineStateChanges(e).value.isSuccess) + + // We threw away the command. + XCTAssertTrue(e.clearWasCalled) + + // And now we have no local clients. + let empty = tabs.getClients().value.successValue + XCTAssertNotNil(empty) + XCTAssertEqual(empty!, []) + } +} diff --git a/mobile/ios/ClientTests/SearchEnginesTests.swift b/mobile/ios/ClientTests/SearchEnginesTests.swift new file mode 100644 index 0000000000..f03ecb8bee --- /dev/null +++ b/mobile/ios/ClientTests/SearchEnginesTests.swift @@ -0,0 +1,174 @@ +/* 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/. */ + +@testable import Client +import Foundation +import XCTest +import Shared + +private let DefaultSearchEngineName = "Google" +private let ExpectedEngineNames = ["Amazon.com", "Bing", "DuckDuckGo", "Google", "Twitter", "Wikipedia", "Yahoo"] + +class SearchEnginesTests: XCTestCase { + + func testIncludesExpectedEngines() { + // Verify that the set of shipped engines includes the expected subset. + let profile = MockProfile() + let engines = SearchEngines(prefs: profile.prefs, files: profile.files).orderedEngines + XCTAssertTrue((engines?.count)! >= ExpectedEngineNames.count) + + for engineName in ExpectedEngineNames { + XCTAssertTrue(((engines?.filter { engine in engine.shortName == engineName })?.count)! > 0) + } + } + + func testDefaultEngineOnStartup() { + // If this is our first run, Yahoo should be first for the en locale. + let profile = MockProfile() + let engines = SearchEngines(prefs: profile.prefs, files: profile.files) + XCTAssertEqual(engines.defaultEngine.shortName, DefaultSearchEngineName) + XCTAssertEqual(engines.orderedEngines[0].shortName, DefaultSearchEngineName) + } + + func testAddingAndDeletingCustomEngines() { + let testEngine = OpenSearchEngine(engineID: "ATester", shortName: "ATester", image: UIImage(), searchTemplate: "http://firefox.com/find?q={searchTerm}", suggestTemplate: nil, isCustomEngine: true) + let profile = MockProfile() + let engines = SearchEngines(prefs: profile.prefs, files: profile.files) + engines.addSearchEngine(testEngine) + XCTAssertEqual(engines.orderedEngines[1].engineID, testEngine.engineID) + + engines.deleteCustomEngine(testEngine) + let deleted = engines.orderedEngines.filter {$0 == testEngine} + XCTAssertEqual(deleted, []) + } + + func testDefaultEngine() { + let profile = MockProfile() + let engines = SearchEngines(prefs: profile.prefs, files: profile.files) + let engineSet = engines.orderedEngines + + engines.defaultEngine = (engineSet?[0])! + XCTAssertTrue(engines.isEngineDefault((engineSet?[0])!)) + XCTAssertFalse(engines.isEngineDefault((engineSet?[1])!)) + // The first ordered engine is the default. + XCTAssertEqual(engines.orderedEngines[0].shortName, engineSet?[0].shortName) + + engines.defaultEngine = (engineSet?[1])! + XCTAssertFalse(engines.isEngineDefault((engineSet?[0])!)) + XCTAssertTrue(engines.isEngineDefault((engineSet?[1])!)) + // The first ordered engine is the default. + XCTAssertEqual(engines.orderedEngines[0].shortName, engineSet?[1].shortName) + + let engines2 = SearchEngines(prefs: profile.prefs, files: profile.files) + // The default engine should have been persisted. + XCTAssertTrue(engines2.isEngineDefault((engineSet?[1])!)) + // The first ordered engine is the default. + XCTAssertEqual(engines.orderedEngines[0].shortName, engineSet?[1].shortName) + } + + func testOrderedEngines() { + let profile = MockProfile() + let engines = SearchEngines(prefs: profile.prefs, files: profile.files) + + engines.orderedEngines = [ExpectedEngineNames[4], ExpectedEngineNames[2], ExpectedEngineNames[0]].map { name in + for engine in engines.orderedEngines { + if engine.shortName == name { + return engine + } + } + XCTFail("Could not find engine: \(name)") + return engines.orderedEngines.first! + } + XCTAssertEqual(engines.orderedEngines[0].shortName, ExpectedEngineNames[4]) + XCTAssertEqual(engines.orderedEngines[1].shortName, ExpectedEngineNames[2]) + XCTAssertEqual(engines.orderedEngines[2].shortName, ExpectedEngineNames[0]) + + let engines2 = SearchEngines(prefs: profile.prefs, files: profile.files) + // The ordering should have been persisted. + XCTAssertEqual(engines2.orderedEngines[0].shortName, ExpectedEngineNames[4]) + XCTAssertEqual(engines2.orderedEngines[1].shortName, ExpectedEngineNames[2]) + XCTAssertEqual(engines2.orderedEngines[2].shortName, ExpectedEngineNames[0]) + + // Remaining engines should be appended in alphabetical order. + XCTAssertEqual(engines2.orderedEngines[3].shortName, ExpectedEngineNames[1]) + XCTAssertEqual(engines2.orderedEngines[4].shortName, ExpectedEngineNames[3]) + XCTAssertEqual(engines2.orderedEngines[5].shortName, ExpectedEngineNames[5]) + XCTAssertEqual(engines2.orderedEngines[6].shortName, ExpectedEngineNames[6]) + } + + func testQuickSearchEngines() { + let profile = MockProfile() + let engines = SearchEngines(prefs: profile.prefs, files: profile.files) + let engineSet = engines.orderedEngines + + // You can't disable the default engine. + engines.defaultEngine = (engineSet?[1])! + engines.disableEngine((engineSet?[1])!) + XCTAssertTrue(engines.isEngineEnabled((engineSet?[1])!)) + + // The default engine is not included in the quick search engines. + XCTAssertEqual(0, engines.quickSearchEngines.filter { engine in engine.shortName == engineSet?[1].shortName }.count) + + // Enable and disable work. + engines.enableEngine((engineSet?[0])!) + XCTAssertTrue(engines.isEngineEnabled((engineSet?[0])!)) + XCTAssertEqual(1, engines.quickSearchEngines.filter { engine in engine.shortName == engineSet?[0].shortName }.count) + + engines.disableEngine((engineSet?[0])!) + XCTAssertFalse(engines.isEngineEnabled((engineSet?[0])!)) + XCTAssertEqual(0, engines.quickSearchEngines.filter { engine in engine.shortName == engineSet?[0].shortName }.count) + + // Setting the default engine enables it. + engines.defaultEngine = (engineSet?[0])! + XCTAssertTrue(engines.isEngineEnabled((engineSet?[1])!)) + + // Setting the order may change the default engine, which enables it. + engines.orderedEngines = [(engineSet?[2])!, (engineSet?[1])!, (engineSet?[0])!] + XCTAssertTrue(engines.isEngineDefault((engineSet?[2])!)) + XCTAssertTrue(engines.isEngineEnabled((engineSet?[2])!)) + + // The enabling should be persisted. + engines.enableEngine((engineSet?[2])!) + engines.disableEngine((engineSet?[1])!) + engines.enableEngine((engineSet?[0])!) + + let engines2 = SearchEngines(prefs: profile.prefs, files: profile.files) + XCTAssertTrue(engines2.isEngineEnabled((engineSet?[2])!)) + XCTAssertFalse(engines2.isEngineEnabled((engineSet?[1])!)) + XCTAssertTrue(engines2.isEngineEnabled((engineSet?[0])!)) + } + + func testSearchSuggestionSettings() { + let profile = MockProfile() + let engines = SearchEngines(prefs: profile.prefs, files: profile.files) + + // By default, you should see search suggestions + XCTAssertTrue(engines.shouldShowSearchSuggestions) + + // Setting should be persisted. + engines.shouldShowSearchSuggestions = false + + let engines2 = SearchEngines(prefs: profile.prefs, files: profile.files) + XCTAssertFalse(engines2.shouldShowSearchSuggestions) + } + + func testDirectoriesForLanguageIdentifier() { + XCTAssertEqual( + SearchEngines.directoriesForLanguageIdentifier("nl", basePath: "/tmp", fallbackIdentifier: "en"), + ["/tmp/nl", "/tmp/en"] + ) + XCTAssertEqual( + SearchEngines.directoriesForLanguageIdentifier("en-US", basePath: "/tmp", fallbackIdentifier: "en"), + ["/tmp/en-US", "/tmp/en"] + ) + XCTAssertEqual( + SearchEngines.directoriesForLanguageIdentifier("es-MX", basePath: "/tmp", fallbackIdentifier: "en"), + ["/tmp/es-MX", "/tmp/es", "/tmp/en"] + ) + XCTAssertEqual( + SearchEngines.directoriesForLanguageIdentifier("zh-Hans-CN", basePath: "/tmp", fallbackIdentifier: "en"), + ["/tmp/zh-Hans-CN", "/tmp/zh-CN", "/tmp/zh", "/tmp/en"] + ) + } +} diff --git a/mobile/ios/ClientTests/SearchTests.swift b/mobile/ios/ClientTests/SearchTests.swift new file mode 100644 index 0000000000..3c008cede4 --- /dev/null +++ b/mobile/ios/ClientTests/SearchTests.swift @@ -0,0 +1,155 @@ +/* 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/. */ + +import Foundation +import GCDWebServers +@testable import Client +import UIKit + +import XCTest + +class SearchTests: XCTestCase { + func testParsing() { + let parser = OpenSearchParser(pluginMode: true) + let file = Bundle.main.path(forResource: "google", ofType: "xml", inDirectory: "SearchPlugins/en") + let engine: OpenSearchEngine! = parser.parse(file!, engineID: "google") + XCTAssertEqual(engine.shortName, "Google") + + // Test regular search queries. + XCTAssertEqual(engine.searchURLForQuery("foobar")!.absoluteString, "https://www.google.com/search?q=foobar&ie=utf-8&oe=utf-8&client=firefox-b") + + // Test search suggestion queries. + XCTAssertEqual(engine.suggestURLForQuery("foobar")!.absoluteString, "https://www.google.com/complete/search?client=firefox&q=foobar") + } + + func testURIFixup() { + // Check valid URLs. We can load these after some fixup. + checkValidURL("http://www.mozilla.org", afterFixup: "http://www.mozilla.org") + checkValidURL("about:", afterFixup: "about:") + checkValidURL("about:config", afterFixup: "about:config") + checkValidURL("about: config", afterFixup: "about:%20config") + checkValidURL("file:///f/o/o", afterFixup: "file:///f/o/o") + checkValidURL("ftp://ftp.mozilla.org", afterFixup: "ftp://ftp.mozilla.org") + checkValidURL("foo.bar", afterFixup: "http://foo.bar") + checkValidURL(" foo.bar ", afterFixup: "http://foo.bar") + checkValidURL("1.2.3", afterFixup: "http://1.2.3") + + // Check invalid URLs. These are passed along to the default search engine. + checkInvalidURL("foobar") + checkInvalidURL("foo bar") + checkInvalidURL("mozilla. org") + checkInvalidURL("123") + checkInvalidURL("a/b") + checkInvalidURL("创业咖啡") + checkInvalidURL("创业咖啡 中国") + checkInvalidURL("创业咖啡. 中国") + } + + func testURIFixupPunyCode() { + checkValidURL("http://创业咖啡.中国/", afterFixup: "http://xn--vhq70hq9bhxa.xn--fiqs8s/") + checkValidURL("创业咖啡.中国", afterFixup: "http://xn--vhq70hq9bhxa.xn--fiqs8s") + checkValidURL(" 创业咖啡.中国 ", afterFixup: "http://xn--vhq70hq9bhxa.xn--fiqs8s") + } + + fileprivate func checkValidURL(_ beforeFixup: String, afterFixup: String) { + XCTAssertEqual(URIFixup.getURL(beforeFixup)!.absoluteString, afterFixup) + } + + fileprivate func checkInvalidURL(_ beforeFixup: String) { + XCTAssertNil(URIFixup.getURL(beforeFixup)) + } + + func testSuggestClient() { + let webServerBase = startMockSuggestServer() + let engine = OpenSearchEngine(engineID: "mock", shortName: "Mock engine", image: UIImage(), searchTemplate: "", suggestTemplate: "\(webServerBase)?q={searchTerms}", + isCustomEngine: false) + let client = SearchSuggestClient(searchEngine: engine, userAgent: "Fx-testSuggestClient") + + let query1 = self.expectation(description: "foo query") + client.query("foo", callback: { response, error in + withExtendedLifetime(client) { + if error != nil { + XCTFail("Error: \(error?.description ?? "nil")") + } + + XCTAssertEqual(response![0], "foo") + XCTAssertEqual(response![1], "foo2") + XCTAssertEqual(response![2], "foo you") + + query1.fulfill() + } + }) + waitForExpectations(timeout: 10, handler: nil) + + let query2 = self.expectation(description: "foo bar query") + client.query("foo bar", callback: { response, error in + withExtendedLifetime(client) { + if error != nil { + XCTFail("Error: \(error?.description ?? "nil")") + } + + XCTAssertEqual(response![0], "foo bar soap") + XCTAssertEqual(response![1], "foo barstool") + XCTAssertEqual(response![2], "foo bartender") + + query2.fulfill() + } + }) + waitForExpectations(timeout: 10, handler: nil) + } + + func testExtractingOfSearchTermsFromURL() { + let parser = OpenSearchParser(pluginMode: true) + var file = Bundle.main.path(forResource: "google", ofType: "xml", inDirectory: "SearchPlugins/en") + let googleEngine: OpenSearchEngine! = parser.parse(file!, engineID: "google") + + // create URL + let searchTerm = "Foo Bar" + let encodedSeachTerm = searchTerm.replacingOccurrences(of: " ", with: "+") + let googleSearchURL = URL(string: "https://www.google.com/search?q=\(encodedSeachTerm)&ie=utf-8&oe=utf-8&gws_rd=cr&ei=I0UyVp_qK4HtUoytjagM") + let duckDuckGoSearchURL = URL(string: "https://duckduckgo.com/?q=\(encodedSeachTerm)&ia=about") + let invalidSearchURL = URL(string: "https://www.google.co.uk") + + // check it correctly matches google search term given google config + XCTAssertEqual(searchTerm, googleEngine.queryForSearchURL(googleSearchURL)) + + // check it doesn't match when the URL is not a search URL + XCTAssertNil(googleEngine.queryForSearchURL(invalidSearchURL)) + + // check that it matches given a different configuration + file = Bundle.main.path(forResource: "duckduckgo", ofType: "xml", inDirectory: "SearchPlugins/en") + let duckDuckGoEngine: OpenSearchEngine! = parser.parse(file!, engineID: "duckduckgo") + XCTAssertEqual(searchTerm, duckDuckGoEngine.queryForSearchURL(duckDuckGoSearchURL)) + + // check it doesn't match search URLs for different configurations + XCTAssertNil(duckDuckGoEngine.queryForSearchURL(googleSearchURL)) + + // check that if you pass in a nil URL that everything works + XCTAssertNil(duckDuckGoEngine.queryForSearchURL(nil)) + } + + fileprivate func startMockSuggestServer() -> String { + let webServer: GCDWebServer = GCDWebServer() + + webServer.addHandler(forMethod: "GET", path: "/", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + var suggestions: [String]! + let query = request?.query["q"] as! String + switch query { + case "foo": + suggestions = ["foo", "foo2", "foo you"] + case "foo bar": + suggestions = ["foo bar soap", "foo barstool", "foo bartender"] + default: + XCTFail("Unexpected query: \(query)") + } + return GCDWebServerDataResponse(jsonObject: [query, suggestions]) + } + + if !webServer.start(withPort: 0, bonjourName: nil) { + XCTFail("Can't start the GCDWebServer") + } + + return "http://localhost:\(webServer.port)" + } +} diff --git a/mobile/ios/ClientTests/StringExtensionsTests.swift b/mobile/ios/ClientTests/StringExtensionsTests.swift new file mode 100644 index 0000000000..cc0599efc2 --- /dev/null +++ b/mobile/ios/ClientTests/StringExtensionsTests.swift @@ -0,0 +1,74 @@ +/* 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/. */ + +import Foundation +import XCTest + +class StringExtensionsTests: XCTestCase { + + func testStartsWith() { + XCTAssertTrue("abcde".startsWith("abcde")) + XCTAssertTrue("abcde".startsWith("")) + XCTAssertTrue("abcde".startsWith("a")) + XCTAssertTrue("abcdea".startsWith("a")) + XCTAssertFalse("abcde".startsWith("fa")) + XCTAssertFalse("abcde".startsWith("af")) + XCTAssertFalse("abcde".startsWith("b")) + } + + func testEndsWith() { + XCTAssertTrue("abcde".endsWith("abcde")) + XCTAssertTrue("abcde".endsWith("")) + XCTAssertTrue("abcde".endsWith("e")) + XCTAssertTrue("abcdea".endsWith("a")) + XCTAssertFalse("abcde".endsWith("fe")) + XCTAssertFalse("abcde".endsWith("ef")) + XCTAssertFalse("abcde".endsWith("d")) + } + + func testEllipsize() { + // Odd maxLength. Note that we ellipsize with a Unicode join character to avoid wrapping. + XCTAssertEqual("abcd…\u{2060}fgh", "abcdefgh".ellipsize(maxLength: 7)) + + // Even maxLength. + XCTAssertEqual("abcd…\u{2060}ijkl", "abcdefghijkl".ellipsize(maxLength: 8)) + + // String shorter than maxLength. + XCTAssertEqual("abcd", "abcd".ellipsize(maxLength: 7)) + + // Empty String. + XCTAssertEqual("", "".ellipsize(maxLength: 8)) + + // maxLength < 2. + XCTAssertEqual("abcdefgh", "abcdefgh".ellipsize(maxLength: 0)) + } + + func testStringByTrimmingLeadingCharactersInSet() { + XCTAssertEqual("foo ", " foo ".stringByTrimmingLeadingCharactersInSet(CharacterSet.whitespaces)) + XCTAssertEqual("foo456", "123foo456".stringByTrimmingLeadingCharactersInSet(CharacterSet.decimalDigits)) + XCTAssertEqual("", "123456".stringByTrimmingLeadingCharactersInSet(CharacterSet.decimalDigits)) + } + + func testStringSplitWithNewline() { + XCTAssertEqual("", "".stringSplitWithNewline()) + XCTAssertEqual("foo", "foo".stringSplitWithNewline()) + XCTAssertEqual("aaa\n bbb", "aaa bbb".stringSplitWithNewline()) + XCTAssertEqual("Mark as\n Read", "Mark as Read".stringSplitWithNewline()) + XCTAssertEqual("aa\n bbbbbb", "aa bbbbbb".stringSplitWithNewline()) + } + + func testPercentEscaping() { + func roundtripTest(_ input: String, _ expected: String, file: StaticString = #file, line: UInt = #line) { + let observed = input.escape()! + XCTAssertEqual(observed, expected, "input is \(input)", file: file, line: line) + let roundtrip = observed.unescape() + XCTAssertEqual(roundtrip, input, "encoded is \(observed)", file: file, line: line) + } + + roundtripTest("https://mozilla.com", "https://mozilla.com") + roundtripTest("http://www.cnn.com/2017/09/25/politics/north-korea-fm-us-bombers/index.html", "http://www.cnn.com/2017/09/25/politics/north-korea-fm-us-bombers/index.html") + roundtripTest("http://mozilla.com/?a=foo&b=bar", "http://mozilla.com/%3Fa%3Dfoo%26b%3Dbar") + } + +} diff --git a/mobile/ios/ClientTests/SyncStatusResolverTests.swift b/mobile/ios/ClientTests/SyncStatusResolverTests.swift new file mode 100644 index 0000000000..44e298cb52 --- /dev/null +++ b/mobile/ios/ClientTests/SyncStatusResolverTests.swift @@ -0,0 +1,109 @@ +/* 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/. */ + +@testable import Client +@testable import Sync + +import Shared +import Storage +import XCTest + +private class RandomError: MaybeErrorType { + var description = "random_error" +} + +class SyncStatusResolverTests: XCTestCase { + + private func mockStatsForCollection(collection: String) -> SyncEngineStatsSession { + return SyncEngineStatsSession(collection: collection) + } + + func testAllCompleted() { + let results: EngineResults = [ + ("tabs", .completed(mockStatsForCollection(collection: "tabs"))), + ("clients", .completed(mockStatsForCollection(collection: "clients"))) + ] + let maybeResults = Maybe(success: results) + + let resolver = SyncStatusResolver(engineResults: maybeResults) + XCTAssertTrue(resolver.resolveResults() == SyncDisplayState.good) + } + + func testAllCompletedExceptOneDisabledRemotely() { + let results: EngineResults = [ + ("tabs", .completed(mockStatsForCollection(collection: "tabs"))), + ("clients", .notStarted(.engineRemotelyNotEnabled(collection: "clients"))) + ] + let maybeResults = Maybe(success: results) + + let resolver = SyncStatusResolver(engineResults: maybeResults) + XCTAssertTrue(resolver.resolveResults() == SyncDisplayState.good) + } + + func testAllCompletedExceptNotStartedBecauseNoAccount() { + let results: EngineResults = [ + ("tabs", .completed(mockStatsForCollection(collection: "tabs"))), + ("clients", .notStarted(.noAccount)) + ] + let maybeResults = Maybe(success: results) + + let resolver = SyncStatusResolver(engineResults: maybeResults) + XCTAssertTrue(resolver.resolveResults() == SyncDisplayState.warning(message: Strings.FirefoxSyncOfflineTitle)) + } + + func testAllCompletedExceptNotStartedBecauseOffline() { + let results: EngineResults = [ + ("tabs", .completed(mockStatsForCollection(collection: "tabs"))), + ("clients", .notStarted(.offline)) + ] + let maybeResults = Maybe(success: results) + + let resolver = SyncStatusResolver(engineResults: maybeResults) + XCTAssertTrue(resolver.resolveResults() == SyncDisplayState.bad(message: Strings.FirefoxSyncOfflineTitle)) + } + + func testOfflineAndNoAccount() { + let results: EngineResults = [ + ("tabs", .notStarted(.noAccount)), + ("clients", .notStarted(.offline)) + ] + + let maybeResults = Maybe(success: results) + + let resolver = SyncStatusResolver(engineResults: maybeResults) + XCTAssertTrue(resolver.resolveResults() == SyncDisplayState.bad(message: Strings.FirefoxSyncOfflineTitle)) + } + + func testAllPartial() { + let results: EngineResults = [ + ("tabs", .partial(SyncEngineStatsSession(collection: "tabs"))), + ("clients", .partial(SyncEngineStatsSession(collection: "clients"))) + ] + let maybeResults = Maybe(success: results) + + let resolver = SyncStatusResolver(engineResults: maybeResults) + XCTAssertTrue(resolver.resolveResults() == SyncDisplayState.good) + } + + func testBookmarkMergeError() { + let maybeResults: Maybe = Maybe(failure: BookmarksMergeError()) + let resolver = SyncStatusResolver(engineResults: maybeResults) + let expected = SyncDisplayState.warning(message: String(format: Strings.FirefoxSyncPartialTitle, Strings.localizedStringForSyncComponent("bookmarks") ?? "")) + XCTAssertTrue(resolver.resolveResults() == expected) + } + + func testBufferInvalidError() { + let maybeResults: Maybe = Maybe(failure: BufferInvalidError(inconsistencies: [:], validationDuration: 0)) + let resolver = SyncStatusResolver(engineResults: maybeResults) + let expected = SyncDisplayState.warning(message: String(format: Strings.FirefoxSyncPartialTitle, Strings.localizedStringForSyncComponent("bookmarks") ?? "")) + XCTAssertTrue(resolver.resolveResults() == expected) + } + + func testRandomFailure() { + let maybeResults: Maybe = Maybe(failure: RandomError()) + let resolver = SyncStatusResolver(engineResults: maybeResults) + let expected = SyncDisplayState.bad(message: nil) + XCTAssertTrue(resolver.resolveResults() == expected) + } +} diff --git a/mobile/ios/ClientTests/TabEventHandlerTests.swift b/mobile/ios/ClientTests/TabEventHandlerTests.swift new file mode 100644 index 0000000000..06f546e527 --- /dev/null +++ b/mobile/ios/ClientTests/TabEventHandlerTests.swift @@ -0,0 +1,87 @@ +/* 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/. */ + +import Foundation +@testable import Client +import WebKit + +import XCTest + +class TabEventHandlerTests: XCTestCase { + + func testEventDelivery() { + let tab = Tab(configuration: WKWebViewConfiguration()) + let handler = DummyHandler() + + XCTAssertNil(handler.isFocused) + + TabEvent.post(.didGainFocus, for: tab) + XCTAssertTrue(handler.isFocused!) + + TabEvent.post(.didLoseFocus, for: tab) + XCTAssertFalse(handler.isFocused!) + } + + func testUnregistration() { + let tab = Tab(configuration: WKWebViewConfiguration()) + let handler = DummyHandler() + + XCTAssertNil(handler.isFocused) + + TabEvent.post(.didGainFocus, for: tab) + XCTAssertTrue(handler.isFocused!) + + handler.doUnregister() + TabEvent.post(.didLoseFocus, for: tab) + // The event didn't reach us, so we should still be focused. + XCTAssertTrue(handler.isFocused!) + } + + func testOnlyRegisteredForEvents() { + let tab = Tab(configuration: WKWebViewConfiguration()) + let handler = DummyHandler() + handler.doUnregister() + + let tabObservers = handler.registerFor(.didGainFocus) + + XCTAssertNil(handler.isFocused) + + TabEvent.post(.didGainFocus, for: tab) + XCTAssertTrue(handler.isFocused!) + + TabEvent.post(.didLoseFocus, for: tab) + XCTAssertTrue(handler.isFocused!) + + handler.unregister(tabObservers) + } +} + + +class DummyHandler: TabEventHandler { + var tabObservers: TabObservers! + + // This is not how this should be written in production — the handler shouldn't be keeping track + // of individual tab state. + var isFocused: Bool? = nil + + init() { + tabObservers = registerFor(.didGainFocus, .didLoseFocus) + } + + deinit { + doUnregister() + } + + fileprivate func doUnregister() { + unregister(tabObservers) + } + + func tabDidGainFocus(_ tab: Tab) { + isFocused = true + } + + func tabDidLoseFocus(_ tab: Tab) { + isFocused = false + } +} diff --git a/mobile/ios/ClientTests/TabManagerTests.swift b/mobile/ios/ClientTests/TabManagerTests.swift new file mode 100644 index 0000000000..a169ce1226 --- /dev/null +++ b/mobile/ios/ClientTests/TabManagerTests.swift @@ -0,0 +1,457 @@ +/* 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/. */ + +@testable import Client +import Shared +import Storage +import UIKit +import WebKit +import Deferred + +import XCTest + +open class TabManagerMockProfile: MockProfile { + var numberOfTabsStored = 0 + override public func storeTabs(_ tabs: [RemoteTab]) -> Deferred> { + numberOfTabsStored = tabs.count + return deferMaybe(tabs.count) + } +} + +open class MockTabManagerStateDelegate: TabManagerStateDelegate { + var numberOfTabsStored = 0 + public func tabManagerWillStoreTabs(_ tabs: [Tab]) { + numberOfTabsStored = tabs.count + } +} + +struct MethodSpy { + let functionName: String + let method: ((_ tabs: [Tab?]) -> Void)? + + init(functionName: String) { + self.functionName = functionName + self.method = nil + } + + init(functionName: String, method: ((_ tabs: [Tab?]) -> Void)?) { + self.functionName = functionName + self.method = method + } +} + +open class MockTabManagerDelegate: TabManagerDelegate { + + //this array represents the order in which delegate methods should be called. + //each delegate method will pop the first struct from the array. If the method name doesn't match the struct then the order is incorrect + //Then it evaluates the method closure which will return true/false depending on if the tabs are correct + var methodCatchers: [MethodSpy] = [] + + func expect(_ methods: [MethodSpy]) { + self.methodCatchers = methods + } + + func verify(_ message: String) { + XCTAssertTrue(methodCatchers.isEmpty, message) + } + + func testDelegateMethodWithName(_ name: String, tabs: [Tab?]) { + guard let spy = self.methodCatchers.first else { + XCTAssert(false, "No method was availible in the queue. For the delegate method \(name) to use") + return + } + XCTAssertEqual(spy.functionName, name) + if let methodCheck = spy.method { + methodCheck(tabs) + } + methodCatchers.removeFirst() + } + + public func tabManager(_ tabManager: TabManager, didSelectedTabChange selected: Tab?, previous: Tab?) { + testDelegateMethodWithName(#function, tabs: [selected, previous]) + } + + public func tabManager(_ tabManager: TabManager, didAddTab tab: Tab) { + testDelegateMethodWithName(#function, tabs: [tab]) + } + + public func tabManager(_ tabManager: TabManager, didRemoveTab tab: Tab) { + testDelegateMethodWithName(#function, tabs: [tab]) + } + + public func tabManagerDidRestoreTabs(_ tabManager: TabManager) { + testDelegateMethodWithName(#function, tabs: []) + } + + public func tabManager(_ tabManager: TabManager, willRemoveTab tab: Tab) { + testDelegateMethodWithName(#function, tabs: [tab]) + } + + public func tabManager(_ tabManager: TabManager, willAddTab tab: Tab) { + testDelegateMethodWithName(#function, tabs: [tab]) + } + + public func tabManagerDidAddTabs(_ tabManager: TabManager) { + testDelegateMethodWithName(#function, tabs: []) + } + + public func tabManagerDidRemoveAllTabs(_ tabManager: TabManager, toast: ButtonToast?) { + testDelegateMethodWithName(#function, tabs: []) + } +} + +class TabManagerTests: XCTestCase { + + let willRemove = MethodSpy(functionName: "tabManager(_:willRemoveTab:)") + let didRemove = MethodSpy(functionName: "tabManager(_:didRemoveTab:)") + let willAdd = MethodSpy(functionName: "tabManager(_:willAddTab:)") + let didAdd = MethodSpy(functionName: "tabManager(_:didAddTab:)") + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testTabManagerCallsTabManagerStateDelegateOnStoreChangesWithNormalTabs() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let stateDelegate = MockTabManagerStateDelegate() + manager.stateDelegate = stateDelegate + let configuration = WKWebViewConfiguration() + configuration.processPool = WKProcessPool() + + // test that non-private tabs are saved to the db + // add some non-private tabs to the tab manager + for _ in 0..<3 { + let tab = Tab(configuration: configuration) + tab.url = URL(string: "http://yahoo.com")! + manager.configureTab(tab, request: URLRequest(url: tab.url!), flushToDisk: false, zombie: false) + } + + manager.storeChanges() + + XCTAssertEqual(stateDelegate.numberOfTabsStored, 3, "Expected state delegate to have been called with 3 tabs, but called with \(stateDelegate.numberOfTabsStored)") + } + + func testTabManagerDoesNotCallTabManagerStateDelegateOnStoreChangesWithPrivateTabs() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let stateDelegate = MockTabManagerStateDelegate() + manager.stateDelegate = stateDelegate + let configuration = WKWebViewConfiguration() + configuration.processPool = WKProcessPool() + + // test that non-private tabs are saved to the db + // add some non-private tabs to the tab manager + for _ in 0..<3 { + let tab = Tab(configuration: configuration, isPrivate: true) + tab.url = URL(string: "http://yahoo.com")! + manager.configureTab(tab, request: URLRequest(url: tab.url!), flushToDisk: false, zombie: false) + } + + manager.storeChanges() + + XCTAssertEqual(stateDelegate.numberOfTabsStored, 0, "Expected state delegate to have been called with 3 tabs, but called with \(stateDelegate.numberOfTabsStored)") + } + + func testAddTab() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + manager.addDelegate(delegate) + + delegate.expect([willAdd, didAdd]) + manager.addTab() + delegate.verify("Not all delegate methods were called") + } + + func testDidDeleteLastTab() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + + //create the tab before adding the mock delegate. So we don't have to check delegate calls we dont care about + let tab = manager.addTab() + manager.selectTab(tab) + manager.addDelegate(delegate) + + let didSelect = MethodSpy(functionName: "tabManager(_:didSelectedTabChange:previous:)") { tabs in + let next = tabs[0]! + let previous = tabs[1]! + XCTAssertTrue(previous != next) + XCTAssertTrue(previous == tab) + XCTAssertFalse(next.isPrivate) + } + delegate.expect([willRemove, didRemove, willAdd, didAdd, didSelect]) + manager.removeTab(tab) + delegate.verify("Not all delegate methods were called") + } + + func testDidDeleteLastPrivateTab() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + + //create the tab before adding the mock delegate. So we don't have to check delegate calls we dont care about + let tab = manager.addTab() + manager.selectTab(tab) + let privateTab = manager.addTab(isPrivate: true) + manager.selectTab(privateTab) + manager.addDelegate(delegate) + + let didSelect = MethodSpy(functionName: "tabManager(_:didSelectedTabChange:previous:)") { tabs in + let next = tabs[0]! + let previous = tabs[1]! + XCTAssertTrue(previous != next) + XCTAssertTrue(previous == privateTab) + XCTAssertTrue(next == tab) + XCTAssertTrue(previous.isPrivate) + XCTAssertTrue(manager.selectedTab == next) + } + delegate.expect([willRemove, didRemove, didSelect]) + manager.removeTab(privateTab) + delegate.verify("Not all delegate methods were called") + } + + func testDeletePrivateTabsOnExit() { + //setup + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + profile.prefs.setBool(true, forKey: "settings.closePrivateTabs") + + // create one private and one normal tab + let tab = manager.addTab() + manager.selectTab(tab) + manager.selectTab(manager.addTab(isPrivate: true)) + + XCTAssertEqual(manager.selectedTab?.isPrivate, true, "The selected tab should be the private tab") + XCTAssertEqual(manager.privateTabs.count, 1, "There should only be one private tab") + + manager.selectTab(tab) + XCTAssertEqual(manager.privateTabs.count, 0, "If the normal tab is selected the private tab should have been deleted") + XCTAssertEqual(manager.normalTabs.count, 1, "The regular tab should stil be around") + + manager.selectTab(manager.addTab(isPrivate: true)) + XCTAssertEqual(manager.privateTabs.count, 1, "There should be one new private tab") + manager.willSwitchTabMode() + XCTAssertEqual(manager.privateTabs.count, 0, "After willSwitchTabMode there should be no more private tabs") + + manager.selectTab(manager.addTab(isPrivate: true)) + manager.selectTab(manager.addTab(isPrivate: true)) + XCTAssertEqual(manager.privateTabs.count, 2, "Private tabs should not be deleted when another one is added") + manager.selectTab(manager.addTab()) + XCTAssertEqual(manager.privateTabs.count, 0, "But once we add a normal tab we've switched out of private mode. Private tabs should be deleted") + XCTAssertEqual(manager.normalTabs.count, 2, "The original normal tab and the new one should both still exist") + + profile.prefs.setBool(false, forKey: "settings.closePrivateTabs") + manager.selectTab(manager.addTab(isPrivate: true)) + manager.selectTab(tab) + XCTAssertEqual(manager.selectedTab?.isPrivate, false, "The selected tab should not be private") + XCTAssertEqual(manager.privateTabs.count, 1, "If the flag is false then private tabs should still exist") + } + + func testDeleteNonSelectedTab() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + + //create the tab before adding the mock delegate. So we don't have to check delegate calls we dont care about + let tab = manager.addTab() + manager.selectTab(tab) + manager.addTab() + let deleteTab = manager.addTab() + manager.addDelegate(delegate) + + delegate.expect([willRemove, didRemove]) + manager.removeTab(deleteTab) + + delegate.verify("Not all delegate methods were called") + } + + func testDeleteSelectedTab() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + + func addTab(_ load: Bool) -> Tab { + let tab = manager.addTab() + if load { + tab.lastExecutedTime = Date.now() + } + return tab + } + + let tab0 = addTab(false) // not loaded + let tab1 = addTab(true) + let tab2 = addTab(true) + let tab3 = addTab(false) // not loaded + let tab4 = addTab(true) + + // starting at tab2, we should be selecting + // [ tab4, tab1, tab3, tab0 ] + + manager.selectTab(tab2) + manager.removeTab(manager.selectedTab!) + // Rule: most recently loaded. + XCTAssertEqual(manager.selectedTab, tab4) + + manager.removeTab(manager.selectedTab!) + // Rule: most recently loaded. + XCTAssertEqual(manager.selectedTab, tab1) + + manager.removeTab(manager.selectedTab!) + // Rule: next to the right. + XCTAssertEqual(manager.selectedTab, tab3) + + manager.removeTab(manager.selectedTab!) + // Rule: last one left. + XCTAssertEqual(manager.selectedTab, tab0) + } + + func testDeleteLastTab() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + + //create the tab before adding the mock delegate. So we don't have to check delegate calls we dont care about + (0..<10).forEach {_ in manager.addTab() } + manager.selectTab(manager.tabs.last) + let deleteTab = manager.tabs.last + let newSelectedTab = manager.tabs[8] + manager.addDelegate(delegate) + + let didSelect = MethodSpy(functionName: "tabManager(_:didSelectedTabChange:previous:)") { tabs in + let next = tabs[0]! + let previous = tabs[1]! + XCTAssertEqual(deleteTab, previous) + XCTAssertEqual(next, newSelectedTab) + } + delegate.expect([willRemove, didRemove, didSelect]) + manager.removeTab(manager.tabs.last!) + + delegate.verify("Not all delegate methods were called") + } + + func testDelegatesCalledWhenRemovingPrivateTabs() { + //setup + let profile = TabManagerMockProfile() + let delegate = MockTabManagerDelegate() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + profile.prefs.setBool(true, forKey: "settings.closePrivateTabs") + + // create one private and one normal tab + let tab = manager.addTab() + let newTab = manager.addTab() + manager.selectTab(tab) + manager.selectTab(manager.addTab(isPrivate: true)) + manager.addDelegate(delegate) + + // Double check a few things + XCTAssertEqual(manager.selectedTab?.isPrivate, true, "The selected tab should be the private tab") + XCTAssertEqual(manager.privateTabs.count, 1, "There should only be one private tab") + + // switch to normal mode. Which should delete the private tabs + manager.willSwitchTabMode() + + //make sure tabs are cleared properly and indexes are reset + XCTAssertEqual(manager.privateTabs.count, 0, "Private tab should have been deleted") + XCTAssertEqual(manager.selectedIndex, -1, "The selected index should have been reset") + + // didSelect should still be called when switching between a nil tab + let didSelect = MethodSpy(functionName: "tabManager(_:didSelectedTabChange:previous:)") { tabs in + XCTAssertNil(tabs[1], "there should be no previous tab") + let next = tabs[0]! + XCTAssertFalse(next.isPrivate) + } + + // make sure delegate method is actually called + delegate.expect([didSelect]) + + // select the new tab to trigger the delegate methods + manager.selectTab(newTab) + + // check + delegate.verify("Not all delegate methods were called") + } + + func testDeleteFirstTab() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + + //create the tab before adding the mock delegate. So we don't have to check delegate calls we dont care about + (0..<10).forEach {_ in manager.addTab() } + manager.selectTab(manager.tabs.first) + let deleteTab = manager.tabs.first + let newSelectedTab = manager.tabs[1] + manager.addDelegate(delegate) + + let didSelect = MethodSpy(functionName: "tabManager(_:didSelectedTabChange:previous:)") { tabs in + let next = tabs[0]! + let previous = tabs[1]! + XCTAssertEqual(deleteTab, previous) + XCTAssertEqual(next, newSelectedTab) + } + delegate.expect([willRemove, didRemove, didSelect]) + manager.removeTab(manager.tabs.first!) + delegate.verify("Not all delegate methods were called") + } + + // Private tabs and regular tabs are in the same tabs array. + // Make sure that when a private tab is added inbetween regular tabs it isnt accidently selected when removing a regular tab + func testTabsIndex() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + + // We add 2 tabs. Then a private one before adding another normal tab and selecting it. + // Make sure that when the last one is deleted we dont switch to the private tab + manager.addTab() + let newSelected = manager.addTab() + manager.addTab(isPrivate: true) + let deleted = manager.addTab() + manager.selectTab(manager.tabs.last) + manager.addDelegate(delegate) + + let didSelect = MethodSpy(functionName: "tabManager(_:didSelectedTabChange:previous:)") { tabs in + let next = tabs[0]! + let previous = tabs[1]! + XCTAssertEqual(deleted, previous) + XCTAssertEqual(next, newSelected) + } + delegate.expect([willRemove, didRemove, didSelect]) + manager.removeTab(manager.tabs.last!) + + delegate.verify("Not all delegate methods were called") + } + + func testTabsIndexClosingFirst() { + let profile = TabManagerMockProfile() + let manager = TabManager(prefs: profile.prefs, imageStore: nil) + let delegate = MockTabManagerDelegate() + + // We add 2 tabs. Then a private one before adding another normal tab and selecting the first. + // Make sure that when the last one is deleted we dont switch to the private tab + let deleted = manager.addTab() + let newSelected = manager.addTab() + manager.addTab(isPrivate: true) + manager.addTab() + manager.selectTab(manager.tabs.first) + manager.addDelegate(delegate) + + let didSelect = MethodSpy(functionName: "tabManager(_:didSelectedTabChange:previous:)") { tabs in + let next = tabs[0]! + let previous = tabs[1]! + XCTAssertEqual(deleted, previous) + XCTAssertEqual(next, newSelected) + } + delegate.expect([willRemove, didRemove, didSelect]) + manager.removeTab(manager.tabs.first!) + delegate.verify("Not all delegate methods were called") + } + +} diff --git a/mobile/ios/ClientTests/TestBookmarks.swift b/mobile/ios/ClientTests/TestBookmarks.swift new file mode 100644 index 0000000000..b756c069eb --- /dev/null +++ b/mobile/ios/ClientTests/TestBookmarks.swift @@ -0,0 +1,42 @@ +/* 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/. */ + +@testable import Client +import Foundation +import Shared +import Storage + +import XCTest + +class TestBookmarks: ProfileTest { + func testBookmarks() { + withTestProfile { profile -> Void in + for i in 0...10 { + let bookmark = ShareItem(url: "http://www.example.com/\(i)", title: "Example \(i)", favicon: nil) + profile.bookmarks.shareItem(bookmark) + } + + let expectation = self.expectation(description: "asynchronous request") + profile.bookmarks.modelFactory >>== { + $0.modelForFolder(BookmarkRoots.MobileFolderGUID).upon { result in + guard let model = result.successValue else { + XCTFail("Should not have failed to get mock bookmarks.") + expectation.fulfill() + return + } + // 11 bookmarks plus our two suggested sites. + XCTAssertEqual(model.current.count, 11, "We create \(model.current.count) stub bookmarks in the Mobile Bookmarks folder.") + let bookmark = model.current[0] + XCTAssertTrue(bookmark is BookmarkItem) + XCTAssertTrue((bookmark as! BookmarkItem).url.hasPrefix("http://www.example.com/"), "Example URL found.") + expectation.fulfill() + } + } + + self.waitForExpectations(timeout: 10.0, handler:nil) + // This'll do. + try! profile.files.remove("mock.db") + } + } +} diff --git a/mobile/ios/ClientTests/TestFavicons.swift b/mobile/ios/ClientTests/TestFavicons.swift new file mode 100644 index 0000000000..b2f463bf7f --- /dev/null +++ b/mobile/ios/ClientTests/TestFavicons.swift @@ -0,0 +1,57 @@ +/* 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/. */ + +import Foundation +import XCTest +import Storage +import SDWebImage +@testable import Client +import Shared + +class TestFavicons: ProfileTest { + + fileprivate func addSite(_ favicons: Favicons, url: String, s: Bool = true) { + let expectation = self.expectation(description: "Wait for history") + let site = Site(url: url, title: "") + let icon = Favicon(url: url + "/icon.png", type: IconType.icon) + favicons.addFavicon(icon, forSite: site).upon { + XCTAssertEqual($0.isSuccess, s, "Icon added \(url)") + expectation.fulfill() + } + self.waitForExpectations(timeout: 100, handler: nil) + } + + func testFaviconFetcherParse() { + let expectation = self.expectation(description: "Wait for Favicons to be fetched") + + let profile = MockProfile() + // I want a site that also has an iOS app so I can get "apple-touch-icon-precomposed" icons as well + let url = URL(string: "https://instagram.com") + FaviconFetcher.getForURL(url!, profile: profile).uponQueue(DispatchQueue.main) { result in + guard let favicons = result.successValue, favicons.count > 0, let url = favicons.first?.url.asURL else { + XCTFail("Favicons were not found.") + return expectation.fulfill() + } + XCTAssertGreaterThan(favicons.count, 1, "Instagram should have more than one Favicon.") + SDWebImageManager.shared().loadImage(with: url, options: .retryFailed, progress: nil, completed: { (img, _, _, _, _, _) in + guard let image = img else { + XCTFail("Not a valid URL provided for a favicon.") + return expectation.fulfill() + } + XCTAssertNotEqual(image.size, CGSize(width: 0, height: 0)) + expectation.fulfill() + }) + + } + self.waitForExpectations(timeout: 3000, handler: nil) + } + + func testDefaultFavicons() { + let icon = FaviconFetcher.getDefaultIconForURL(url: URL(string: "http://www.google.de")!) + XCTAssertNotNil(icon) + let craigsListIcon = FaviconFetcher.getDefaultIconForURL(url: URL(string: "http://vancouver.craigslist.ca")!) + XCTAssertNotNil(craigsListIcon) + + } +} diff --git a/mobile/ios/ClientTests/TestHashExtensions.swift b/mobile/ios/ClientTests/TestHashExtensions.swift new file mode 100644 index 0000000000..3a711c8039 --- /dev/null +++ b/mobile/ios/ClientTests/TestHashExtensions.swift @@ -0,0 +1,19 @@ +/* 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/. */ + +import Foundation +import XCTest + +class TestHashExtensions: XCTestCase { + func testSha1() { + XCTAssertEqual("test1test2".sha1.hexEncodedString, "dff964f6e3c1761b6288f5c75c319d36fb09b2b9") + XCTAssertEqual("test2test3".sha1.hexEncodedString, "66cdfcbbf4ad73f40ae06140460ff9bb0aabaf5c") + } + + func testSha256() { + let data1: Data = "4f980b6f9baa6965f760d0bf2b2ccbee483032e5df01d77bbd9e25f7517a06b9".hexDecodedData + XCTAssertEqual("test1test2".sha256, data1) + XCTAssertEqual("test2test3".sha256, "fc3ea28dc1801e4180cec1022b55bee7795cf3c9fd430fb5237c9d8054218e81".hexDecodedData) + } +} diff --git a/mobile/ios/ClientTests/TestHistory.swift b/mobile/ios/ClientTests/TestHistory.swift new file mode 100644 index 0000000000..73eacdc865 --- /dev/null +++ b/mobile/ios/ClientTests/TestHistory.swift @@ -0,0 +1,219 @@ +/* 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/. */ + +@testable import Client +import Foundation +import Storage + +import XCTest + +class TestHistory: ProfileTest { + fileprivate func addSite(_ history: BrowserHistory, url: String, title: String, s: Bool = true) { + let site = Site(url: url, title: title) + let visit = SiteVisit(site: site, date: Date.nowMicroseconds()) + XCTAssertEqual(s, history.addLocalVisit(visit).value.isSuccess, "Site added: \(url).") + } + + fileprivate func innerCheckSites(_ history: BrowserHistory, callback: @escaping (_ cursor: Cursor) -> Void) { + // Retrieve the entry + history.getSitesByLastVisit(100).upon { + XCTAssertTrue($0.isSuccess) + callback($0.successValue!) + } + } + + fileprivate func checkSites(_ history: BrowserHistory, urls: [String: String], s: Bool = true) { + // Retrieve the entry. + if let cursor = history.getSitesByLastVisit(100).value.successValue { + XCTAssertEqual(cursor.status, CursorStatus.success, "Returned success \(cursor.statusMessage).") + XCTAssertEqual(cursor.count, urls.count, "Cursor has \(urls.count) entries.") + + for index in 0.. Void in + let h = profile.history + self.addSite(h, url: "http://url1/", title: "title") + self.addSite(h, url: "http://url1/", title: "title") + self.addSite(h, url: "http://url1/", title: "title 2") + self.addSite(h, url: "https://url2/", title: "title") + self.addSite(h, url: "https://url2/", title: "title") + self.checkSites(h, urls: ["http://url1/": "title 2", "https://url2/": "title"]) + self.checkVisits(h, url: "http://url1/") + self.checkVisits(h, url: "https://url2/") + self.clear(h) + } + } + + func testAboutUrls() { + withTestProfile { (profile) -> Void in + let h = profile.history + self.addSite(h, url: "about:home", title: "About Home", s: false) + self.clear(h) + } + } + + let NumThreads = 5 + let NumCmds = 10 + + func testInsertPerformance() { + withTestProfile { profile -> Void in + let h = profile.history + var j = 0 + + self.measure({ () -> Void in + for _ in 0...self.NumCmds { + self.addSite(h, url: "https://someurl\(j).com/", title: "title \(j)") + j += 1 + } + self.clear(h) + }) + } + } + + func testGetPerformance() { + withTestProfile { profile -> Void in + let h = profile.history + var j = 0 + var urls = [String: String]() + + self.clear(h) + for _ in 0...self.NumCmds { + self.addSite(h, url: "https://someurl\(j).com/", title: "title \(j)") + urls["https://someurl\(j).com/"] = "title \(j)" + j += 1 + } + + self.measure({ () -> Void in + self.checkSites(h, urls: urls) + return + }) + + self.clear(h) + } + } + + // Fuzzing tests. These fire random insert/query/clear commands into the history database from threads. The don't check + // the results. Just look for crashes. + func testRandomThreading() { + withTestProfile { profile -> Void in + let queue = DispatchQueue(label: "My Queue", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil) + var counter = 0 + + let expectation = self.expectation(description: "Wait for history") + for _ in 0.. Void in + counter += 1 + if counter == self.NumThreads { + self.clear(history) + expectation.fulfill() + } + }) + } + self.waitForExpectations(timeout: 10, handler: nil) + } + } + + // Same as testRandomThreading, but uses one history connection for all threads + func testRandomThreading2() { + withTestProfile { profile -> Void in + let queue = DispatchQueue(label: "My Queue", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil) + var history = profile.history as BrowserHistory + var counter = 0 + + let expectation = self.expectation(description: "Wait for history") + for _ in 0.. Void in + counter += 1 + if counter == self.NumThreads { + self.clear(history) + expectation.fulfill() + } + }) + } + self.waitForExpectations(timeout: 10, handler: nil) + } + } + + // Runs a random command on a database. Calls cb when finished. + fileprivate func runRandom(_ history: inout BrowserHistory, cmdIn: Int, cb: @escaping () -> Void) { + var cmd = cmdIn + if cmd < 0 { + cmd = Int(arc4random() % 5) + } + + switch cmd { + case 0...1: + let url = "https://randomurl.com/\(arc4random() % 100)" + let title = "title \(arc4random() % 100)" + addSite(history, url: url, title: title) + cb() + case 2...3: + innerCheckSites(history) { cursor in + for site in cursor { + _ = site! + } + } + cb() + default: + history.clearHistory().upon() { success in cb() } + } + } + + // Calls numCmds random methods on this database. val is a counter used by this interally (i.e. always pass zero for it). + // Calls cb when finished. + fileprivate func runMultiRandom(_ history: inout BrowserHistory, val: Int, numCmds: Int, cb: @escaping () -> Void) { + if val == numCmds { + cb() + return + } else { + runRandom(&history, cmdIn: -1) { [history]_ in + var history = history + self.runMultiRandom(&history, val: val+1, numCmds: numCmds, cb: cb) + } + } + } + + // Helper for starting a new thread running NumCmds random methods on it. Calls cb when done. + fileprivate func runRandom(_ history: inout BrowserHistory, queue: DispatchQueue, cb: @escaping () -> Void) { + queue.async { [history] in + var history = history + // Each thread creates its own history provider + self.runMultiRandom(&history, val: 0, numCmds: self.NumCmds) { _ in + DispatchQueue.main.async(execute: cb) + } + } + } +} diff --git a/mobile/ios/ClientTests/UIImageViewExtensionsTests.swift b/mobile/ios/ClientTests/UIImageViewExtensionsTests.swift new file mode 100644 index 0000000000..da8f596473 --- /dev/null +++ b/mobile/ios/ClientTests/UIImageViewExtensionsTests.swift @@ -0,0 +1,94 @@ +/* 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/. */ + +import Foundation +import UIKit +import XCTest +import Storage +import SDWebImage +import GCDWebServers +import Shared + +@testable import Client + +class UIImageViewExtensionsTests: XCTestCase { + + override func setUp() { + SDWebImageDownloader.shared().urlCredential = WebServer.sharedInstance.credentials + } + + func testsetIcon() { + let url = URL(string: "http://mozilla.com") + let imageView = UIImageView() + + let goodIcon = FaviconFetcher.getDefaultFavicon(url!) + let correctColor = FaviconFetcher.getDefaultColor(url!) + imageView.setIcon(nil, forURL: url) + XCTAssertEqual(imageView.image!, goodIcon, "The correct default favicon should be applied") + XCTAssertEqual(imageView.backgroundColor, correctColor, "The correct default color should be applied") + + imageView.setIcon(nil, forURL: URL(string: "http://mozilla.com/blahblah")) + XCTAssertEqual(imageView.image!, goodIcon, "The same icon should be applied to all urls with the same domain") + + imageView.setIcon(nil, forURL: URL(string: "b")) + XCTAssertEqual(imageView.image, FaviconFetcher.defaultFavicon, "The default favicon should be applied when no information is given about the icon") + } + + func testAsyncSetIcon() { + let originalImage = UIImage(named: "fxLogo")! + + WebServer.sharedInstance.registerHandlerForMethod("GET", module: "favicon", resource: "icon") { (request) -> GCDWebServerResponse! in + return GCDWebServerDataResponse(data: UIImagePNGRepresentation(originalImage), contentType: "image/png") + } + + let favImageView = UIImageView() + favImageView.setIcon(Favicon(url: "http://localhost:6571/favicon/icon", type: .guess), forURL: URL(string: "http://localhost:6571")) + + let expect = expectation(description: "UIImageView async load") + let time = Int64(2 * Double(NSEC_PER_SEC)) + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(time) / Double(NSEC_PER_SEC)) { + XCTAssert(originalImage.isStrictlyEqual(to: favImageView.image!), "The correct favicon should be applied to the UIImageView") + expect.fulfill() + } + waitForExpectations(timeout: 5, handler: nil) + } + + func testAsyncSetIconFail() { + let favImageView = UIImageView() + + let gFavURL = URL(string: "https://www.nofavicon.com/noicon.ico") + let gURL = URL(string: "http://nofavicon.com") + let correctImage = FaviconFetcher.getDefaultFavicon(gURL!) + + favImageView.setIcon(Favicon(url: gFavURL!.absoluteString, type: .guess), forURL: gURL) + + let expect = expectation(description: "UIImageView async load") + let time = Int64(2 * Double(NSEC_PER_SEC)) + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(time) / Double(NSEC_PER_SEC)) { + XCTAssert(correctImage.isStrictlyEqual(to: favImageView.image!), "The correct default favicon should be applied to the UIImageView") + expect.fulfill() + } + waitForExpectations(timeout: 5, handler: nil) + } + + func testDefaultIcons() { + let favImageView = UIImageView() + + let gFavURL = URL(string: "https://www.facebook.com/fav") //This will be fetched from tippy top sites + let gURL = URL(string: "http://www.facebook.com")! + let defaultItem = FaviconFetcher.defaultIcons[gURL.baseDomain!]! + let correctImage = UIImage(contentsOfFile: defaultItem.url)! + + favImageView.setIcon(Favicon(url: gFavURL!.absoluteString, type: .guess), forURL: gURL) + + let expect = expectation(description: "UIImageView async load") + let time = Int64(2 * Double(NSEC_PER_SEC)) + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(time) / Double(NSEC_PER_SEC)) { + XCTAssertEqual(favImageView.backgroundColor, defaultItem.color) + XCTAssert(correctImage.isStrictlyEqual(to: favImageView.image!), "The correct default favicon should be applied to the UIImageView") + expect.fulfill() + } + waitForExpectations(timeout: 5, handler: nil) + } +} diff --git a/mobile/ios/ClientTests/UIPasteboardExtensionsTests.swift b/mobile/ios/ClientTests/UIPasteboardExtensionsTests.swift new file mode 100644 index 0000000000..3fee731b2c --- /dev/null +++ b/mobile/ios/ClientTests/UIPasteboardExtensionsTests.swift @@ -0,0 +1,47 @@ +/* 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/. */ + +import Foundation +import MobileCoreServices +import UIKit +import XCTest + +class UIPasteboardExtensionsTests: XCTestCase { + + fileprivate var pasteboard: UIPasteboard! + + override func setUp() { + super.setUp() + pasteboard = UIPasteboard.withUniqueName() + } + + override func tearDown() { + super.tearDown() + UIPasteboard.remove(withName: pasteboard.name) + } + + func testAddPNGImage() { + let path = Bundle(for: self.classForCoder).path(forResource: "image", ofType: "png")! + let data = try! Data(contentsOf: URL(fileURLWithPath: path)) + let url = URL(string: "http://foo.bar")! + pasteboard.addImageWithData(data, forURL: url) + verifyPasteboard(expectedURL: url, expectedImageTypeKey: kUTTypePNG) + } + + func testAddGIFImage() { + let path = Bundle(for: self.classForCoder).path(forResource: "image", ofType: "gif")! + let data = try! Data(contentsOf: URL(fileURLWithPath: path)) + let url = URL(string: "http://foo.bar")! + pasteboard.addImageWithData(data, forURL: url) + verifyPasteboard(expectedURL: url, expectedImageTypeKey: kUTTypeGIF) + } + + fileprivate func verifyPasteboard(expectedURL: URL, expectedImageTypeKey: CFString) { + XCTAssertEqual(pasteboard.items.count, 1) + XCTAssertEqual(pasteboard.items[0].count, 2) + XCTAssertEqual(pasteboard.items[0][kUTTypeURL as String] as? URL, expectedURL) + XCTAssertNotNil(pasteboard.items[0][expectedImageTypeKey as String]) + } + +} diff --git a/mobile/ios/ClientTests/WebServerTests.swift b/mobile/ios/ClientTests/WebServerTests.swift new file mode 100644 index 0000000000..bedb7cdb14 --- /dev/null +++ b/mobile/ios/ClientTests/WebServerTests.swift @@ -0,0 +1,49 @@ +/* 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/. */ + +import UIKit +import GCDWebServers +import XCTest + +/// Minimal web server tests. This class can be used as a base class for tests that need a real web server. +/// Simply add additional handlers your test class' setUp() method. +class WebServerTests: XCTestCase { + let webServer: GCDWebServer = GCDWebServer() + var webServerBase: String! + + /// Setup a basic web server that binds to a random port and that has one default handler on /hello + fileprivate func setupWebServer() { + webServer.addHandler(forMethod: "GET", path: "/hello", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + return GCDWebServerDataResponse(html: "

Hello World

") + } + if webServer.start(withPort: 0, bonjourName: nil) == false { + XCTFail("Can't start the GCDWebServer") + } + webServerBase = "http://localhost:\(webServer.port)" + } + + override func setUp() { + super.setUp() + setupWebServer() + } + + override func tearDown() { + super.tearDown() + } + + func testWebServerIsRunning() { + XCTAssertTrue(webServer.isRunning) + } + + func testWebServerIsServingRequests() { + let response: NSString? + do { + response = try NSString(contentsOf: URL(string: "\(webServerBase!)/hello")!, encoding: String.Encoding.utf8.rawValue) + } catch _ { + response = nil + } + XCTAssertNotNil(response) + XCTAssertTrue(response == "

Hello World

") + } +} diff --git a/mobile/ios/ClientTests/XCTestCaseExtensions.swift b/mobile/ios/ClientTests/XCTestCaseExtensions.swift new file mode 100644 index 0000000000..caa11f1aa4 --- /dev/null +++ b/mobile/ios/ClientTests/XCTestCaseExtensions.swift @@ -0,0 +1,30 @@ +/* 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/. */ + +import Foundation +import XCTest + +extension XCTestCase { + func wait(_ time: TimeInterval) { + let expectation = self.expectation(description: "Wait") + let delayTime = DispatchTime.now() + Double(Int64(time * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + DispatchQueue.main.asyncAfter(deadline: delayTime) { + expectation.fulfill() + } + waitForExpectations(timeout: time + 1, handler: nil) + } + + func waitForCondition(timeout: TimeInterval = 10, condition: () -> Bool) { + let timeoutTime = Date.timeIntervalSinceReferenceDate + timeout + + while !condition() { + if Date.timeIntervalSinceReferenceDate > timeoutTime { + XCTFail("Condition timed out") + return + } + + wait(0.1) + } + } +} diff --git a/mobile/ios/ClientTests/image.gif b/mobile/ios/ClientTests/image.gif new file mode 100644 index 0000000000..6ebee9cdae Binary files /dev/null and b/mobile/ios/ClientTests/image.gif differ diff --git a/mobile/ios/ClientTests/image.png b/mobile/ios/ClientTests/image.png new file mode 100644 index 0000000000..3ee62d6712 Binary files /dev/null and b/mobile/ios/ClientTests/image.png differ diff --git a/mobile/ios/ClientTests/pocketglobalfeed.json b/mobile/ios/ClientTests/pocketglobalfeed.json new file mode 100644 index 0000000000..2573bad8b3 --- /dev/null +++ b/mobile/ios/ClientTests/pocketglobalfeed.json @@ -0,0 +1,24 @@ +{ + "status": 1, + "list": [{ + "id": 2092, + "url": "https:\/\/pocket.co\/xMnD5u", + "dedupe_url": "https:\/\/www.wired.com\/story\/turn-off-your-push-notifications\/", + "title": "Turn Off Your Push Notifications. All of Them", + "excerpt": "Push notifications are ruining my life. Yours too, I bet. Download more than a few apps and the notifications become a non-stop, cacophonous waterfall of nonsense. Here's just part of an afternoon on my phone:", + "domain": "wired.com", + "image_src": "https:\/\/d33ypg4xwx0n86.cloudfront.net\/direct?url=https%3A%2F%2Fmedia.wired.com%2Fphotos%2F597267fd023c38366e1ae497%2Fmaster%2Fw_1200%2Cc_limit%2Fno_notifications-TA.gif&resize=w450", + "published_timestamp": "1332306000", + "sort_id": 0 + }, { + "id": 2091, + "url": "https:\/\/pocket.co\/sMnD5m", + "dedupe_url": "http:\/\/www.latimes.com\/business\/la-fi-agenda-best-buy-20170717-htmlstory.html", + "title": "Why the grim reaper of retail hasn't come to claim Best Buy", + "excerpt": "Five years ago Best Buy Co. looked like a retail dinosaur, another victim of e-commerce juggernaut Amazon.com and other online sellers.", + "domain": "latimes.com", + "image_src": "https:\/\/d33ypg4xwx0n86.cloudfront.net\/direct?url=http%3A%2F%2Fwww.trbimg.com%2Fimg-547cc080%2Fturbine%2Fla-fi-mh-radio-shack-20141201-004%2F&resize=w450", + "published_timestamp": "1500267600", + "sort_id": 1 + }] +} diff --git a/mobile/ios/Dangerfile b/mobile/ios/Dangerfile new file mode 100644 index 0000000000..3af0a87a34 --- /dev/null +++ b/mobile/ios/Dangerfile @@ -0,0 +1,2 @@ +# Lint files with Swiftlint. Check .swiftlint.yml for config +swiftlint.lint_files \ No newline at end of file diff --git a/mobile/ios/DeferredTestUtils.swift b/mobile/ios/DeferredTestUtils.swift new file mode 100644 index 0000000000..d5545347d3 --- /dev/null +++ b/mobile/ios/DeferredTestUtils.swift @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Shared +import Deferred +import XCTest + +protocol Succeedable { + var isSuccess: Bool { get } + var isFailure: Bool { get } +} + +extension Maybe: Succeedable {} + +extension Deferred where T: Succeedable { + func succeeded() { + XCTAssertTrue(self.value.isSuccess) + } + + func failed() { + XCTAssertTrue(self.value.isFailure) + } +} + diff --git a/mobile/ios/Docs/BUILDING.md b/mobile/ios/Docs/BUILDING.md new file mode 100644 index 0000000000..adcbd90d82 --- /dev/null +++ b/mobile/ios/Docs/BUILDING.md @@ -0,0 +1,118 @@ +Building Firefox for iOS +======================== + +Prerequisites, as of *February 14, 2017*: + +* Mac OS X 10.11.5 +* Xcode 8.2.1 with the iOS 10 SDK (Betas not supported) +* Carthage 0.15 or newer + +When running on a device: + +* A device that supports iOS 9.3 GM or later +* One of the following: + * A developer account and Admin access to the *Certificates, Identifiers & Profiles* section of the *iOS DevCenter* + * A free developer account (create an Apple ID for free and add as an account in Xcode) + +Get the Code +----------- + +``` +git clone https://github.com/mozilla/firefox-ios +cd firefox-ios +``` + +(If you have forked the repository, substitute the URL with your own repository location.) + +Pull in Dependencies +-------------------- + +We use Carthage to manage projects that we depend on. __The build will currently only work with Carthage v0.15 or newer__. If you do not already have Carthage installed, you need to grab it via Homebrew. Assuming you have Homebrew installed, execute the following: + +``` +brew update +brew upgrade +brew install carthage +``` + +You can now execute our `bootstrap.sh` script: + +``` +./bootstrap.sh +``` + +At this point you have checked out the source code for both the Firefox for iOS project and built it's dependencies. You can now build and run the application. + +Everything after this point is done from within Xcode. + +Run on the Simulator +----------------- + +* Open `Client.xcodeproj` and make sure you have the *Fennec* scheme and a simulated device selected. The app should run on any simulator. We just have not tested very well on the *Resizable iPad* and *Resizable iPhone* simulators. +* Select *Product -> Run* and the application should build and run on the selected simulator. + +Run on a Device with Xcode 8 and a Free Developer Account +--------------- + +> Only follow these instructions if you are using the free personal developer accounts. Simply add your Apple ID as an account in Xcode. + +Since the bundle identifier we use for Firefox is tied to our developer account, you'll need to generate your own identifier and update the existing configuration. + +1. Open Client/Configuration/Fennec.xcconfig +2. Change MOZ_BUNDLE_ID to your own bundle identifier. Just think of something unique: e.g., com.your_github_id.Fennec +3. Open the project editor in Xcode. +4. For the 'Client' target, in the 'Capabilities' section, turn off the capabilities 'Push Notifications' and 'Wallet'. +5. For each target, in the 'General' section, under 'Signing', select your personal development account. + +If you submit a patch, be sure to exclude these files because they are only relevant for your personal build. + +> If after building, Xcode fails to run the app with a vague `Security` error, open Settings -> Profiles on your iOS Device and Trust your personal developer profile. This may only happen on iOS 9. + +Run on a Device +--------------- + +These are instructions for development. Not production / distribution. + +> Before you try to run the application on a device, it is highly recommended that you first make sure that you can run applications on device in general. Just create one of the built-in iOS templates that Xcode provides and make sure you can run that on your device. If you can then it means you have done the basic setup like pairing your device, registering its UDID in the dev center, etc. + +Before you can run the application on your device, you need to setup a few things in the *Certificates, Identifiers & Profiles* section of the iOS Developer Center. + +> _Note_: When we mention `YOURREVERSEDOMAIN` below, use your own domain in reverse notation like `com.example` or if you do not have your own domain, just use something unique and personal like `io.github.yourgithubusername`. Please do not use existing domain names which you do not own. + +1. Create a Application Group. Name this group 'Fennec' and for its Identifier use `group.YOURREVERSEDOMAIN.Fennec` +2. Create a new App Id. Name it 'Fennec'. Give it an Explicit App ID and set its Bundle Identifier to `YOURREVERSEDOMAIN.Fennec`. In the App Services section, select *App Groups*. +3. Create a new App Id. Name it 'Fennec ShareTo'. Give it an Explicit App ID and set its Bundle Identifier to `YOURREVERSEDOMAIN.Fennec.ShareTo`. In the App Services section, select *App Groups*. +4. Create a new App Id. Name it 'Fennec SendTo'. Give it an Explicit App ID and set its Bundle Identifier to `YOURREVERSEDOMAIN.Fennec.SendTo`. In the App Services section, select *App Groups*. +5. Create a new App Id. Name it 'Fennec ViewLater'. Give it an Explicit App ID and set its Bundle Identifier to `YOURREVERSEDOMAIN.Fennec.ViewLater`. In the App Services section, select *App Groups*. +6. For all App Ids that you just created, edit their App Groups and make sure they are all part of the Fennec App Group that you created in step 1. + +Now we are going to create three Provisioning Profiles that are linked to the App Ids that we just created: + +1. Create a new *Development Provisioning Profile* and link it to the *Fennec* App ID that you created. Select the *Developer Certificates* and *Devices* that you wish to include in this profile. Finally, name this profile *Fennec*. +2. Create a new *Development Provisioning Profile* and link it to the *Fennec SendTo* App ID that you created. Select the *Developer Certificates* and *Devices* that you wish to include in this profile. Finally, name this profile *Fennec SendTo*. +3. Create a new *Development Provisioning Profile* and link it to the *Fennec ShareTo* App ID that you created. Select the *Developer Certificates* and *Devices* that you wish to include in this profile. Finally, name this profile *Fennec ShareTo*. +4. Create a new *Development Provisioning Profile* and link it to the *Fennec ViewLater* App ID that you created. Select the *Developer Certificates* and *Devices* that you wish to include in this profile. Finally, name this profile *Fennec ViewLater*. + +Now go to Xcode, *Preferences -> Accounts* and select your developer account. Hit the *View Details* button and then press the little reload button in the bottom left corner. This should sync the Provisioning Profiles and you should see the three profiles appear that you creates earlier. + +Almost done. The one thing missing is that we need to adjust the build configuration to use your new bundle identifier. + +1. Open Client/Configuration/Fennec.xcconfig +2. Change MOZ_BUNDLE_ID to `YOURREVERSEDOMAIN`. +3. Navigate to each of the application targets (Client/SendTo/ShareTo/ViewLater) and your developer account. + +Before building, do *Product -> Clean Build Folder* (option-shift-command-k) + +You should now be able to build the *Fennec* scheme and run on your device. + +We would love a Pull Request for a smarter Xcode project configuration or even a shell script that makes this process simpler. + + +Random notes +------------ + +Updating SQLCipher. + +As of bug https://bugzilla.mozilla.org/show_bug.cgi?id=1182620 we do not run the SQLCipher 'amalgamation' phase anymore. Instead we have simply included generated copies of `sqlite3.c`, `sqlite3.h` and `sqlite3ext.h` in the project. This works around problems where the amalgamation phase did not work for production builds. It also speeds up things. + +To update to a newer version of SQLCipher: check out the original SQLCipher project and build it. Do not copy the project or anything in the Firefox project. Just follow their instructions. Then copy the above three `.c` and `.h` files back into the Firefox project. Also update the `README`, `VERION` and `CHANGELOG` files from the original distribution so that we know what version we have included. diff --git a/mobile/ios/Docs/Dependency Graphs/README.md b/mobile/ios/Docs/Dependency Graphs/README.md new file mode 100644 index 0000000000..21b30648e4 --- /dev/null +++ b/mobile/ios/Docs/Dependency Graphs/README.md @@ -0,0 +1,21 @@ + +Available Dependency Graphs +=============== + +* `digraph-fxios` - a graph showing dependencies between the different targets in Firefox for iOS +* `digraph-fxios-carthage` - a graph showing dependencies between Firefox for iOS targets and our Carthage Dependencies +* `digraph-carthage-fxios` - a graph showing dependencies between our Carthage Dependencies and Firefox for iOS targets + +Generating dependency graphs +----------- + +* Download [Graphviz](http://www.graphviz.org/Download_macos.php) or install via homebrew `brew install graphviz` +* Open Graphviz.app +* Import `.dot` file +* Export as `jpg` or `pdf` + + +Examples +----------- + +Here are some [examples](http://graphs.grevian.org/example) of more things you can do with Graphviz \ No newline at end of file diff --git a/mobile/ios/Docs/Dependency Graphs/digraph-carthage-fxios.jpg b/mobile/ios/Docs/Dependency Graphs/digraph-carthage-fxios.jpg new file mode 100644 index 0000000000..d70edabb43 Binary files /dev/null and b/mobile/ios/Docs/Dependency Graphs/digraph-carthage-fxios.jpg differ diff --git a/mobile/ios/Docs/Dependency Graphs/digraph-fxios-carthage.jpg b/mobile/ios/Docs/Dependency Graphs/digraph-fxios-carthage.jpg new file mode 100644 index 0000000000..eff25c7903 Binary files /dev/null and b/mobile/ios/Docs/Dependency Graphs/digraph-fxios-carthage.jpg differ diff --git a/mobile/ios/Docs/Dependency Graphs/digraph-fxios.jpg b/mobile/ios/Docs/Dependency Graphs/digraph-fxios.jpg new file mode 100644 index 0000000000..38911cb42e Binary files /dev/null and b/mobile/ios/Docs/Dependency Graphs/digraph-fxios.jpg differ diff --git a/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-carthage-fxios.dot b/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-carthage-fxios.dot new file mode 100644 index 0000000000..9d5f287d47 --- /dev/null +++ b/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-carthage-fxios.dot @@ -0,0 +1,32 @@ +digraph CarthageFxiOS { + "Alamofire" -> "Client" + "Alamofire" -> "ShareTo" + "Alamofire" -> "Shared" + "Alamofire" -> "Account" + "Alamofire" -> "Sync" + "Alamofire" -> "ReadingList" + "Snapkit" -> "Client" + "Snapkit" -> "Today" + "SDWebImage" -> "Client" + "SDWebImage" -> "SendTo" + "SDWebImage" -> "ShareTo" + "SDWebImage" -> "ViewLater" + "GCDWebServer" -> "Client" + "Adjust" -> "Client" + "OnePasswordExtension" -> "Client" + "libPhoneNumber-iOS" -> "Client" + "web_metadata_ios" -> "Client" + "XCGLogger" -> "Client" + "XCGLogger" -> "Shared" + "XCGLogger" -> "Storage" + "XCGLogger" -> "Account" + "Fuzi" -> "Client" + "Fuzi" -> "SendTo" + "Fuzi" -> "ShareTo" + "Onyx" -> "Client" + "readability" -> "Client" + "SwiftKeychainWrapper" -> "Shared" + "Deferred" -> "Shared" + "KIF" -> "ReadingList" + "SQLite" -> "ReadingList" +} \ No newline at end of file diff --git a/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios-carthage.dot b/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios-carthage.dot new file mode 100644 index 0000000000..bf3a14e2b7 --- /dev/null +++ b/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios-carthage.dot @@ -0,0 +1,26 @@ +digraph FxiOSCarthage { + "Client" -> "Alamofire" + "Client" -> "Snapkit" + "Client" -> "SDWebImage" + "Client" -> "GCDWebServer" + "Client" -> "Adjust" + "Client" -> "OnePasswordExtension" + "Client" -> "libPhoneNumber-iOS" + "Client" -> "web_metadata_ios" + "Client" -> "XCGLogger" + "Client" -> "Fuzi" + "Client" -> "Onyx" + "Client" -> "readability" + "ShareTo" -> "Alamofire" + "ShareTo" -> "SDWebImage" + "ShareTo" -> "Fuzi" + "Shared" -> "Alamofire" + "Shared" -> "XCGLogger" + "Shared" -> "SwiftKeychainWrapper" + "Shared" -> "Deferred" + "Today" -> "Snapkit" + "SendTo" -> "SDWebImage" + "SendTo" -> "Fuzi" + "ViewLater" -> "SDWebImage" + "Storage" -> "XCGLogger" +} diff --git a/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios.dot b/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios.dot new file mode 100644 index 0000000000..faba438a31 --- /dev/null +++ b/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios.dot @@ -0,0 +1,49 @@ +digraph FxiOS { + "Shared" -> "Storage" + "Shared" -> "StorageTests" + "Shared" -> "Client" + "Shared" -> "ClientTests" + "Shared" -> "ViewLater" + "Shared" -> "ReadingList" + "Shared" -> "SendTo" + "Shared" -> "ShareTo" + "Shared" -> "Account" + "Shared" -> "AccountTests" + "Shared" -> "Sync" + "Shared" -> "SyncTests" + "Shared" -> "UITests" + "Shared" -> "Today" + "FxA" -> "Account" + "FxA" -> "AccountTests" + "FxA" -> "Sync" + "FxA" -> "SyncTests" + "Storage" -> "StorageTests" + "Storage" -> "Client" + "Storage" -> "ClientTests" + "Storage" -> "ViewLater" + "Storage" -> "SendTo" + "Storage" -> "UITests" + "Storage" -> "SyncTests" + "Storage" -> "Sync" + "Storage" -> "ShareTo" + "Sync" -> "SyncTests" + "Sync" -> "Client" + "Sync" -> "ClientTests" + "Sync" -> "ShareTo" + "Sync" -> "SendTo" + "Sync" -> "ViewLater" + "ReadingList" -> "ReadingListTests" + "ReadingList" -> "Client" + "ReadingList" -> "ClientTests" + "Account" -> "AccountTests" + "Account" -> "Sync" + "Account" -> "SyncTests" + "Account" -> "Client" + "Account" -> "ClientTests" + "Client" -> "ClientTests" + "Client" -> "UITests" + "Client" -> "ShareTo" + "Client" -> "SendTo" + "Client" -> "ViewLater" + "Client" -> "Today" +} \ No newline at end of file diff --git a/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios.jpg b/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios.jpg new file mode 100644 index 0000000000..38911cb42e Binary files /dev/null and b/mobile/ios/Docs/Dependency Graphs/dot-files/digraph-fxios.jpg differ diff --git a/mobile/ios/Docs/browserdb.md b/mobile/ios/Docs/browserdb.md new file mode 100644 index 0000000000..fbd5694f8d --- /dev/null +++ b/mobile/ios/Docs/browserdb.md @@ -0,0 +1,14 @@ +# How to get your browser DB off the device + +* Launch Firefox. +* Open Settings. +* Scroll down to "Version" and tap it several times. +* Scroll down and hit "Debug: copy databases to app container". +* Connect your device via USB. +* Open Xcode. +* Window > Devices. Choose your device. +* Find "Firefox" on the right side. +* Click the gear icon, and choose "Download Container…". Save it somewhere. +* After some time, Finder will open focused on an .xcappdata file. +* Right-click, "Show Package Contents". +* Navigate to `AppData/Documents`. Zip up `browser.*`. diff --git a/mobile/ios/Docs/sync.md b/mobile/ios/Docs/sync.md new file mode 100644 index 0000000000..c7e3b14dbb --- /dev/null +++ b/mobile/ios/Docs/sync.md @@ -0,0 +1,76 @@ +# Firefox Sync Through The Lens Of Jaded Developers +## Or, Let's Use A State Machine For Our Own Sakes + +(These docs are approximately one sentence per line to make changes more civilized in version control.) + +Sync moves through a number of states. + +Initially, we know only the Married account state: we have a valid, verified FxA. This also gives us kB. + +Sync will need to know when kB changes, but it does so implicitly -- when kB changes, we fetch a new token, and the X-Client-State header we supply will result in a new storage endpoint. + +We transition from this state, then, to one where we also have a Sync storage token and a node assignment. This is the point at which we can first talk to the Sync server. We call this "Initial Assigned". We start in this state when first signed in, and also when creating an account on the device. + +(Note that the Sync server allows us to fetch info/collections with an expired token. This is to make the process of short-circuiting a sync cheaper. We still need a server assignment, of course. That we can do this implies that the Sync client has a pull-based relationship with the token server client.) + + +The process thereafter depends on some amount of locally persisted state. + +This state falls into three categories: + +* Real storage metadata on which our syncing behavior relies. This involves timestamps of collection fetches, syncIDs for storage as a whole and for each collection, and lists of engines. (Perhaps more.) + +* Protocol-level signaling, such as Retry-After and Backoff headers. These need to persist in order for us to behave correctly. + +* Cached data to avoid repeating operations. The client can cache info/collections for the duration of a sync, and meta/global and crypto/keys until they change. + +For more on this, see "Persistence", below. + +Starting from that "initial assigned" state, we will always fetch info/collections. + +If we have local meta/global and crypto/keys caches, and nothing is indicated as changed in i/c, we can move directly to Ready. + +If either is missing, each needs to be fetched and processed. These two tasks should be independent, but typically a change to meta/global will be followed by fetching keys. + +If meta/global is missing, one must be created based on the user's datatype elections, ideally preserved from any previous configuration. For consistency's sake, the rest of storage should be wiped prior to uploading a meta/global; a missing meta/global implies that something is wrong, and it probably went wrong during a wipe or node reassignment. + +If crypto/keys is missing, there should be no other data on the server. On a non-first-sync, this is likely to be an error state, requiring recovery. If crypto/keys changed, but the server wasn't wiped and refilled, then HMAC errors will result. + +So now we have meta/global and crypto/keys, in one of three ways: cached, fetched, or computed and uploaded. If we don't get to that point, we error out; the intermediate fetching states really aren't exposed. If we had to compute and upload -- a very uncommon situation -- we re-enter the state machine from the beginning to simplify analysis. + +We call this state "Ready". + +From Ready we can perform a number of operations: + +* We can wipe the server. + +* We can safely change datatype elections or keys for collections. + +* We can perform storage operations on one or more collections. + +The first two we'll ignore for now. They're relatively straightforward. + +The last is encapsulated in a datatype-specific synchronizer and a `Sync15CollectionClient` that pushes and pulls records. + + +The process of synchronizing is driven by info/collections (indicating remote changes), by meta/global (a change to syncID implies a reset), and by local change indicators. + + +## Invalidation + +At any point we might get a 401 in response to a storage request. At this point our token is invalidated; we abort this sync, fetch a new token, and continue. That token might itself point to a new Sync server, which might result in a fresh-start sync. + + +## Persistence + +So what do we need to persist? Quite apart from the actual datatype-specific stuff: + +* We need to store the syncID and last fetch timestamp for each collection. If the syncID changes, we need to throw away the timestamp. +* We need to store the list of enabled engines, and keep it in lockstep with meta/global. The same for declined. +* We need to store our own client ID, and use that when uploading our client record. +* We need to pay attention to kB; if it changes, e.g., via a password change, then any in-memory copy of the Sync Key should be discarded. +* We ought to cache meta/global. +* We ought to cache bulk keys. If i/c changes for crypto, we should redownload and compare. If any collection key changes, then we should act as if the syncID changed. (TODO: should we change the syncID for that collection? Probably.) + (If we can't decrypt your bulk keys, probably our kB is now invalid. If it's not, the server is corrupt.) +* We ought to remember the last info/collections. +* We should store the last info/collections timestamp, so that an i/c fetch can return 304. diff --git a/mobile/ios/Extensions/Entitlements/Fennec.entitlements b/mobile/ios/Extensions/Entitlements/Fennec.entitlements new file mode 100644 index 0000000000..d3294bef8d --- /dev/null +++ b/mobile/ios/Extensions/Entitlements/Fennec.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.application-groups + + group.org.mozilla.ios.Fennec + + keychain-access-groups + + $(AppIdentifierPrefix)org.mozilla.ios.Fennec + + + diff --git a/mobile/ios/Extensions/Entitlements/FennecEnterprise.entitlements b/mobile/ios/Extensions/Entitlements/FennecEnterprise.entitlements new file mode 100644 index 0000000000..bc8c56f1ba --- /dev/null +++ b/mobile/ios/Extensions/Entitlements/FennecEnterprise.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.application-groups + + group.org.mozilla.ios.Fennec.enterprise + + keychain-access-groups + + $(AppIdentifierPrefix)org.mozilla.ios.Fennec.enterprise + + + diff --git a/mobile/ios/Extensions/Entitlements/Firefox.entitlements b/mobile/ios/Extensions/Entitlements/Firefox.entitlements new file mode 100644 index 0000000000..3e056af7ba --- /dev/null +++ b/mobile/ios/Extensions/Entitlements/Firefox.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.application-groups + + group.org.mozilla.ios.Firefox + + keychain-access-groups + + $(AppIdentifierPrefix)org.mozilla.ios.Firefox + + + diff --git a/mobile/ios/Extensions/Entitlements/FirefoxBeta.entitlements b/mobile/ios/Extensions/Entitlements/FirefoxBeta.entitlements new file mode 100644 index 0000000000..b743c4052c --- /dev/null +++ b/mobile/ios/Extensions/Entitlements/FirefoxBeta.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.application-groups + + group.org.mozilla.ios.FirefoxBeta + + keychain-access-groups + + $(AppIdentifierPrefix)org.mozilla.ios.FirefoxBeta + + + diff --git a/mobile/ios/Extensions/NotificationService/ExtensionProfile.swift b/mobile/ios/Extensions/NotificationService/ExtensionProfile.swift new file mode 100644 index 0000000000..45579f32ee --- /dev/null +++ b/mobile/ios/Extensions/NotificationService/ExtensionProfile.swift @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Deferred +import Shared +import Sync + +// This is a cut down version of the Profile. +// This will only ever be used in the NotificationService extension. +// It allows us to customize the SyncDelegate, and later the SyncManager. +class ExtensionProfile: BrowserProfile { + init(localName: String) { + super.init(localName: localName, clear: false) + self.syncManager = ExtensionSyncManager(profile: self) + } +} + +fileprivate let extensionSafeNames = Set(["clients"]) + +// Mock class required by `BrowserProfile` +open class PanelDataObservers { + init(profile: Any) {} +} + +// Mock class required by `BrowserProfile` +open class SearchEngines { + init(prefs: Any, files: Any) {} +} + +class ExtensionSyncManager: BrowserProfile.BrowserSyncManager { + init(profile: ExtensionProfile) { + super.init(profile: profile) + } + + // We don't want to send ping data at all while we're in the extension. + override func canSendUsageData() -> Bool { + return false + } + + // We should probably only want to sync client commands while we're in the extension. + override func syncNamedCollections(why: SyncReason, names: [String]) -> Success { + let names = names.filter { extensionSafeNames.contains($0) } + return super.syncNamedCollections(why: why, names: names) + } + + override func takeActionsOnEngineStateChanges(_ changes: T) -> Deferred> { + return deferMaybe(changes) + } +} diff --git a/mobile/ios/Extensions/NotificationService/Info.plist b/mobile/ios/Extensions/NotificationService/Info.plist new file mode 100644 index 0000000000..6926a90443 --- /dev/null +++ b/mobile/ios/Extensions/NotificationService/Info.plist @@ -0,0 +1,33 @@ + + + + + MozDevelopmentTeam + $(DEVELOPMENT_TEAM) + CFBundleDevelopmentRegion + en + CFBundleDisplayName + $(MOZ_BUNDLE_DISPLAY_NAME) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 10.6 + CFBundleVersion + 1 + NSExtension + + NSExtensionPointIdentifier + com.apple.usernotifications.service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).NotificationService + + + diff --git a/mobile/ios/Extensions/NotificationService/NotificationService.swift b/mobile/ios/Extensions/NotificationService/NotificationService.swift new file mode 100644 index 0000000000..95a2db9174 --- /dev/null +++ b/mobile/ios/Extensions/NotificationService/NotificationService.swift @@ -0,0 +1,274 @@ +/* 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/. */ + +import Shared +import Storage +import Sync +import UserNotifications + +class NotificationService: UNNotificationServiceExtension { + var display: SyncDataDisplay? + var profile: ExtensionProfile? + + // This is run when an APNS notification with `mutable-content` is received. + // If the app is backgrounded, then the alert notification is displayed. + // If the app is foregrounded, then the notification.userInfo is passed straight to + // AppDelegate.application(_:didReceiveRemoteNotification:completionHandler:) + // Once the notification is tapped, then the same userInfo is passed to the same method in the AppDelegate. + override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { + let userInfo = request.content.userInfo + + guard let content = (request.content.mutableCopy() as? UNMutableNotificationContent) else { + return self.didFinish(PushMessage.accountVerified) + } + + if self.profile == nil { + self.profile = ExtensionProfile(localName: "profile") + } + + guard let profile = self.profile else { + self.didFinish(with: .noProfile) + return + } + + let queue = profile.queue + let display = SyncDataDisplay(content: content, contentHandler: contentHandler, tabQueue: queue) + self.display = display + profile.syncDelegate = display + + let handler = FxAPushMessageHandler(with: profile) + + handler.handle(userInfo: userInfo).upon { res in + self.didFinish(res.successValue, with: res.failureValue as? PushMessageError) + } + } + + func didFinish(_ what: PushMessage? = nil, with error: PushMessageError? = nil) { + profile?.shutdown() + + guard let display = self.display else { + return + } + + // We cannot use tabqueue after the profile has shutdown; + // however, we can't use weak references, because TabQueue isn't a class. + // Rather than changing tabQueue, we manually nil it out here. + display.tabQueue = nil + display.messageDelivered = false + display.displayNotification(what, with: error) + if !display.messageDelivered { + display.displayUnknownMessageNotification() + } + } + + override func serviceExtensionTimeWillExpire() { + // Called just before the extension will be terminated by the system. + // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. + didFinish(with: .timeout) + } +} + +class SyncDataDisplay { + var contentHandler: ((UNNotificationContent) -> Void) + var notificationContent: UNMutableNotificationContent + var sentTabs: [SentTab] + + var tabQueue: TabQueue? + var messageDelivered: Bool = false + + init(content: UNMutableNotificationContent, contentHandler: @escaping (UNNotificationContent) -> Void, tabQueue: TabQueue) { + self.contentHandler = contentHandler + self.notificationContent = content + self.sentTabs = [] + self.tabQueue = tabQueue + } + + func displayNotification(_ message: PushMessage? = nil, with error: PushMessageError? = nil) { + guard let message = message, error == nil else { + return displayUnknownMessageNotification() + } + + switch message { + case .accountVerified: + displayAccountVerifiedNotification() + case .deviceConnected(let deviceName): + displayDeviceConnectedNotification(deviceName) + case .deviceDisconnected(let deviceName): + displayDeviceDisconnectedNotification(deviceName) + case .thisDeviceDisconnected: + displayThisDeviceDisconnectedNotification() + case .collectionChanged(let collections): + if collections.contains("clients") { + displaySentTabNotification() + } else { + displayUnknownMessageNotification() + } + default: + displayUnknownMessageNotification() + break + } + } +} + +extension SyncDataDisplay { + func displayDeviceConnectedNotification(_ deviceName: String) { + presentNotification(title: Strings.FxAPush_DeviceConnected_title, + body: Strings.FxAPush_DeviceConnected_body, + bodyArg: deviceName) + } + + func displayDeviceDisconnectedNotification(_ deviceName: String?) { + if let deviceName = deviceName { + presentNotification(title: Strings.FxAPush_DeviceDisconnected_title, + body: Strings.FxAPush_DeviceDisconnected_body, + bodyArg: deviceName) + } else { + // We should never see this branch + presentNotification(title: Strings.FxAPush_DeviceDisconnected_title, + body: Strings.FxAPush_DeviceDisconnected_UnknownDevice_body) + } + } + + func displayThisDeviceDisconnectedNotification() { + presentNotification(title: Strings.FxAPush_DeviceDisconnected_ThisDevice_title, + body: Strings.FxAPush_DeviceDisconnected_ThisDevice_body) + } + + func displayAccountVerifiedNotification() { + presentNotification(title: Strings.SentTab_NoTabArrivingNotification_title, body: Strings.SentTab_NoTabArrivingNotification_body) + } + + func displayUnknownMessageNotification() { + // if, by any change we haven't dealt with the message, then perhaps we + // can recycle it as a sent tab message. + if sentTabs.count > 0 { + displaySentTabNotification() + } else { + presentNotification(title: Strings.SentTab_NoTabArrivingNotification_title, body: Strings.SentTab_NoTabArrivingNotification_body) + } + } +} + +extension SyncDataDisplay { + func displaySentTabNotification() { + // We will need to be more precise about calling these SentTab alerts + // once we are a) detecting different types of notifications and b) adding actions. + // For now, we need to add them so we can handle zero-tab sent-tab-notifications. + notificationContent.categoryIdentifier = "org.mozilla.ios.SentTab.placeholder" + + var userInfo = notificationContent.userInfo + + // Add the tabs we've found to userInfo, so that the AppDelegate + // doesn't have to do it again. + let serializedTabs = sentTabs.flatMap { t -> NSDictionary? in + return [ + "title": t.title, + "url": t.url.absoluteString, + "displayURL": t.url.absoluteDisplayExternalString, + "deviceName": t.deviceName as Any, + ] as NSDictionary + } + + func present(_ tabs: [NSDictionary]) { + if !tabs.isEmpty { + userInfo["sentTabs"] = tabs as NSArray + } + notificationContent.userInfo = userInfo + presentSentTabsNotification(tabs) + } + + let center = UNUserNotificationCenter.current() + center.getDeliveredNotifications { notifications in + // Let's deal with sent-tab-notifications + let sentTabNotifications = notifications.filter { + $0.request.content.categoryIdentifier == self.notificationContent.categoryIdentifier + } + + // We can delete zero tab sent-tab-notifications + let emptyTabNotificationsIds = sentTabNotifications.filter { + $0.request.content.userInfo["sentTabs"] == nil + }.map { $0.request.identifier } + center.removeDeliveredNotifications(withIdentifiers: emptyTabNotificationsIds) + + // The one we've just received (but not delivered) may not have any tabs in it either + // e.g. if the previous one consumed two tabs. + if serializedTabs.count == 0 { + // In that case, we try and recycle an existing notification (one that has a tab in it). + if let firstNonEmpty = sentTabNotifications.first(where: { $0.request.content.userInfo["sentTabs"] != nil }), + let previouslyDeliveredTabs = firstNonEmpty.request.content.userInfo["sentTabs"] as? [NSDictionary] { + center.removeDeliveredNotifications(withIdentifiers: [firstNonEmpty.request.identifier]) + return present(previouslyDeliveredTabs) + } + } + + // We have tabs in this notification, or we couldn't recycle an existing one that does. + present(serializedTabs) + } + } + + func presentSentTabsNotification(_ tabs: [NSDictionary]) { + let title: String + let body: String + + if tabs.count == 0 { + title = Strings.SentTab_NoTabArrivingNotification_title + body = Strings.SentTab_NoTabArrivingNotification_body + } else { + let deviceNames = Set(tabs.flatMap { $0["deviceName"] as? String }) + if let deviceName = deviceNames.first, deviceNames.count == 1 { + title = String(format: Strings.SentTab_TabArrivingNotification_WithDevice_title, deviceName) + } else { + title = Strings.SentTab_TabArrivingNotification_NoDevice_title + } + + if tabs.count == 1 { + // We give the fallback string as the url, + // because we have only just introduced "displayURL" as a key. + body = (tabs[0]["displayURL"] as? String) ?? + (tabs[0]["url"] as! String) + } else if deviceNames.count == 0 { + body = Strings.SentTab_TabArrivingNotification_NoDevice_body + } else { + body = String(format: Strings.SentTab_TabArrivingNotification_WithDevice_body, AppInfo.displayName) + } + } + + presentNotification(title: title, body: body) + } + + func presentNotification(title: String, body: String, titleArg: String? = nil, bodyArg: String? = nil) { + func stringWithOptionalArg(_ s: String, _ a: String?) -> String { + if let a = a { + return String(format: s, a) + } + return s + } + + notificationContent.title = stringWithOptionalArg(title, titleArg) + notificationContent.body = stringWithOptionalArg(body, bodyArg) + + // This is the only place we call the contentHandler. + contentHandler(notificationContent) + // This is the only place we change messageDelivered. We can check if contentHandler hasn't be called because of + // our logic (rather than something funny with our environment, or iOS killing us). + messageDelivered = true + } +} + +extension SyncDataDisplay: SyncDelegate { + func displaySentTab(for url: URL, title: String, from deviceName: String?) { + if url.isWebPage() { + sentTabs.append(SentTab(url: url, title: title, deviceName: deviceName)) + + let item = ShareItem(url: url.absoluteString, title: title, favicon: nil) + _ = tabQueue?.addToQueue(item) + } + } +} + +struct SentTab { + let url: URL + let title: String + let deviceName: String? +} diff --git a/mobile/ios/Extensions/SendTo/ActionViewController.swift b/mobile/ios/Extensions/SendTo/ActionViewController.swift new file mode 100644 index 0000000000..fc7f337c37 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/ActionViewController.swift @@ -0,0 +1,79 @@ +/* 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/. */ + +import UIKit +import Shared +import Storage +import SnapKit + +/// The ActionViewController is the initial viewcontroller that is presented (full screen) when the share extension +/// is activated. Depending on whether the user is logged in or not, this viewcontroller will present either the +/// InstructionsVC or the ClientPicker VC. + +@objc(ActionViewController) +class ActionViewController: UIViewController, ClientPickerViewControllerDelegate, InstructionsViewControllerDelegate { + private var sharedItem: ShareItem? + + override func viewDidLoad() { + view.backgroundColor = UIColor.white + + super.viewDidLoad() + + if !hasAccount() { + let instructionsViewController = InstructionsViewController() + instructionsViewController.delegate = self + let navigationController = UINavigationController(rootViewController: instructionsViewController) + present(navigationController, animated: false, completion: nil) + return + } + + ExtensionUtils.extractSharedItemFromExtensionContext(self.extensionContext, completionHandler: { (item, error) -> Void in + guard let item = item, error == nil, item.isShareable else { + let alert = UIAlertController(title: Strings.SendToErrorTitle, message: Strings.SendToErrorMessage, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: Strings.SendToErrorOKButton, style: .default) { _ in self.finish() }) + self.present(alert, animated: true, completion: nil) + return + } + + self.sharedItem = item + let clientPickerViewController = ClientPickerViewController() + clientPickerViewController.clientPickerDelegate = self + clientPickerViewController.profile = nil // This means the picker will open and close the default profile + let navigationController = UINavigationController(rootViewController: clientPickerViewController) + self.present(navigationController, animated: false, completion: nil) + }) + } + + func finish() { + self.extensionContext!.completeRequest(returningItems: nil, completionHandler: nil) + } + + func clientPickerViewController(_ clientPickerViewController: ClientPickerViewController, didPickClients clients: [RemoteClient]) { + guard let item = sharedItem else { + return finish() + } + + let profile = BrowserProfile(localName: "profile") + profile.sendItems([item], toClients: clients).uponQueue(DispatchQueue.main) { result in + profile.shutdown() + self.finish() + } + } + + func clientPickerViewControllerDidCancel(_ clientPickerViewController: ClientPickerViewController) { + finish() + } + + func instructionsViewControllerDidClose(_ instructionsViewController: InstructionsViewController) { + finish() + } + + private func hasAccount() -> Bool { + let profile = BrowserProfile(localName: "profile") + defer { + profile.shutdown() + } + return profile.hasAccount() + } +} diff --git a/mobile/ios/Extensions/SendTo/Base.lproj/InfoPlist.strings b/mobile/ios/Extensions/SendTo/Base.lproj/InfoPlist.strings new file mode 100644 index 0000000000..529af36839 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/Base.lproj/InfoPlist.strings @@ -0,0 +1,5 @@ +/* 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/. */ + +"CFBundleDisplayName" = "Send Tab"; diff --git a/mobile/ios/Extensions/SendTo/ClientPickerViewController.swift b/mobile/ios/Extensions/SendTo/ClientPickerViewController.swift new file mode 100644 index 0000000000..c64617bdb4 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/ClientPickerViewController.swift @@ -0,0 +1,320 @@ +/* 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/. */ + +import UIKit +import Shared +import Storage +import SnapKit + +protocol ClientPickerViewControllerDelegate { + func clientPickerViewControllerDidCancel(_ clientPickerViewController: ClientPickerViewController) + func clientPickerViewController(_ clientPickerViewController: ClientPickerViewController, didPickClients clients: [RemoteClient]) +} + +struct ClientPickerViewControllerUX { + static let TableHeaderRowHeight = CGFloat(50) + static let TableHeaderTextFont = UIFont.systemFont(ofSize: 16) + static let TableHeaderTextColor = UIColor.gray + static let TableHeaderTextPaddingLeft = CGFloat(20) + + static let DeviceRowTintColor = UIColor(red: 0.427, green: 0.800, blue: 0.102, alpha: 1.0) + static let DeviceRowHeight = CGFloat(50) + static let DeviceRowTextFont = UIFont.systemFont(ofSize: 16) + static let DeviceRowTextPaddingLeft = CGFloat(72) + static let DeviceRowTextPaddingRight = CGFloat(50) +} + +/// The ClientPickerViewController displays a list of clients associated with the provided Account. +/// The user can select a number of devices and hit the Send button. +/// This viewcontroller does not implement any specific business logic that needs to happen with the selected clients. +/// That is up to it's delegate, who can listen for cancellation and success events. + +class ClientPickerViewController: UITableViewController { + var profile: Profile? + var profileNeedsShutdown = true + + var clientPickerDelegate: ClientPickerViewControllerDelegate? + + var reloading = true + var clients: [RemoteClient] = [] + var selectedClients = NSMutableSet() + + // ShareItem has been added as we are now using this class outside of the ShareTo extension to provide Share To functionality + // And in this case we need to be able to store the item we are sharing as we may not have access to the + // url later. Currently used only when sharing an item from the Tab Tray from a Preview Action. + var shareItem: ShareItem? + + override func viewDidLoad() { + super.viewDidLoad() + title = NSLocalizedString("Send Tab", tableName: "SendTo", comment: "Title of the dialog that allows you to send a tab to a different device") + refreshControl = UIRefreshControl() + refreshControl?.addTarget(self, action: #selector(ClientPickerViewController.refresh), for: UIControlEvents.valueChanged) + navigationItem.leftBarButtonItem = UIBarButtonItem( + title: Strings.SendToCancelButton, + style: .plain, + target: self, + action: #selector(ClientPickerViewController.cancel) + ) + + tableView.register(ClientPickerTableViewHeaderCell.self, forCellReuseIdentifier: ClientPickerTableViewHeaderCell.CellIdentifier) + tableView.register(ClientPickerTableViewCell.self, forCellReuseIdentifier: ClientPickerTableViewCell.CellIdentifier) + tableView.register(ClientPickerNoClientsTableViewCell.self, forCellReuseIdentifier: ClientPickerNoClientsTableViewCell.CellIdentifier) + tableView.tableFooterView = UIView(frame: CGRect.zero) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + if let refreshControl = refreshControl { + refreshControl.beginRefreshing() + let height = -(refreshControl.bounds.size.height + (self.navigationController?.navigationBar.bounds.size.height ?? 0)) + self.tableView.contentOffset = CGPoint(x: 0, y: height) + } + reloadClients() + } + + override func numberOfSections(in tableView: UITableView) -> Int { + if clients.count == 0 { + return 1 + } else { + return 2 + } + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if clients.count == 0 { + return 1 + } else { + if section == 0 { + return 1 + } else { + return clients.count + } + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell: UITableViewCell + + if clients.count > 0 { + if indexPath.section == 0 { + cell = tableView.dequeueReusableCell(withIdentifier: ClientPickerTableViewHeaderCell.CellIdentifier, for: indexPath) as! ClientPickerTableViewHeaderCell + } else { + let clientCell = tableView.dequeueReusableCell(withIdentifier: ClientPickerTableViewCell.CellIdentifier, for: indexPath) as! ClientPickerTableViewCell + clientCell.nameLabel.text = clients[indexPath.row].name + clientCell.clientType = clients[indexPath.row].type == "mobile" ? ClientType.Mobile : ClientType.Desktop + clientCell.checked = selectedClients.contains(indexPath) + cell = clientCell + } + } else { + if reloading == false { + cell = tableView.dequeueReusableCell(withIdentifier: ClientPickerNoClientsTableViewCell.CellIdentifier, for: indexPath) as! ClientPickerNoClientsTableViewCell + } else { + cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "ClientCell") + } + } + + return cell + } + + override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { + return indexPath.section != 0 + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if clients.count > 0 && indexPath.section == 1 { + tableView.deselectRow(at: indexPath, animated: true) + + if selectedClients.contains(indexPath) { + selectedClients.remove(indexPath) + } else { + selectedClients.add(indexPath) + } + + tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.none) + + navigationItem.rightBarButtonItem?.isEnabled = (selectedClients.count != 0) + } + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + if clients.count > 0 { + if indexPath.section == 0 { + return ClientPickerViewControllerUX.TableHeaderRowHeight + } else { + return ClientPickerViewControllerUX.DeviceRowHeight + } + } else { + return tableView.frame.height + } + } + + fileprivate func reloadClients() { + // If we were not given a profile, open the default profile. This happens in case we are called from an app + // extension. That also means that we need to shut down the profile, otherwise the app extension will be + // terminated when it goes into the background. + + if self.profile == nil { + self.profile = BrowserProfile(localName: "profile") + self.profileNeedsShutdown = true + } + + guard let profile = self.profile else { + return + } + + // Re-open the profile it was shutdown. This happens when we run from an app extension, where we must + // make sure that the profile is only open for brief moments of time. + + if profile.isShutdown { + profile.reopen() + } + + reloading = true + profile.getClients().upon({ result in + withExtendedLifetime(profile) { + // If we are running from an app extension then make sure we shut down the profile as soon as we are + // done with it. + + if self.profileNeedsShutdown { + profile.shutdown() + } + + self.reloading = false + guard let c = result.successValue else { + return + } + + self.clients = c + DispatchQueue.main.async { + if self.clients.count == 0 { + self.navigationItem.rightBarButtonItem = nil + } else { + self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("Send", tableName: "SendTo", comment: "Navigation bar button to Send the current page to a device"), style: UIBarButtonItemStyle.done, target: self, action: #selector(ClientPickerViewController.send)) + self.navigationItem.rightBarButtonItem?.isEnabled = false + } + self.selectedClients.removeAllObjects() + self.tableView.reloadData() + self.refreshControl?.endRefreshing() + } + } + }) + } + + func refresh() { + reloadClients() + } + + func cancel() { + clientPickerDelegate?.clientPickerViewControllerDidCancel(self) + } + + func send() { + var clients = [RemoteClient]() + for indexPath in selectedClients { + clients.append(self.clients[(indexPath as AnyObject).row]) + } + clientPickerDelegate?.clientPickerViewController(self, didPickClients: clients) + + // Replace the Send button with a loading indicator since it takes a while to sync + // up our changes to the server. + let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 25, height: 25)) + loadingIndicator.color = .darkGray + loadingIndicator.startAnimating() + let customBarButton = UIBarButtonItem(customView: loadingIndicator) + self.navigationItem.rightBarButtonItem = customBarButton + } +} + +class ClientPickerTableViewHeaderCell: UITableViewCell { + static let CellIdentifier = "ClientPickerTableViewSectionHeader" + let nameLabel = UILabel() + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + addSubview(nameLabel) + nameLabel.font = ClientPickerViewControllerUX.TableHeaderTextFont + nameLabel.text = NSLocalizedString("Available devices:", tableName: "SendTo", comment: "Header for the list of devices table") + nameLabel.textColor = ClientPickerViewControllerUX.TableHeaderTextColor + + nameLabel.snp.makeConstraints { (make) -> Void in + make.left.equalTo(ClientPickerViewControllerUX.TableHeaderTextPaddingLeft) + make.centerY.equalTo(self) + make.right.equalTo(self) + } + + preservesSuperviewLayoutMargins = false + layoutMargins = UIEdgeInsets.zero + separatorInset = UIEdgeInsets.zero + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +public enum ClientType: String { + case Mobile = "deviceTypeMobile" + case Desktop = "deviceTypeDesktop" +} + +class ClientPickerTableViewCell: UITableViewCell { + static let CellIdentifier = "ClientPickerTableViewCell" + + var nameLabel: UILabel + var checked: Bool = false { + didSet { + self.accessoryType = checked ? UITableViewCellAccessoryType.checkmark : UITableViewCellAccessoryType.none + } + } + + var clientType: ClientType = ClientType.Mobile { + didSet { + self.imageView?.image = UIImage(named: clientType.rawValue) + } + } + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + nameLabel = UILabel() + super.init(style: style, reuseIdentifier: reuseIdentifier) + contentView.addSubview(nameLabel) + nameLabel.font = ClientPickerViewControllerUX.DeviceRowTextFont + nameLabel.numberOfLines = 2 + nameLabel.lineBreakMode = NSLineBreakMode.byWordWrapping + self.tintColor = ClientPickerViewControllerUX.DeviceRowTintColor + self.preservesSuperviewLayoutMargins = false + self.selectionStyle = UITableViewCellSelectionStyle.none + } + + override func layoutSubviews() { + super.layoutSubviews() + + nameLabel.snp.makeConstraints { (make) -> Void in + make.left.equalTo(ClientPickerViewControllerUX.DeviceRowTextPaddingLeft) + make.centerY.equalTo(self.snp.centerY) + make.right.equalTo(self.snp.right).offset(-ClientPickerViewControllerUX.DeviceRowTextPaddingRight) + } + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +class ClientPickerNoClientsTableViewCell: UITableViewCell { + static let CellIdentifier = "ClientPickerNoClientsTableViewCell" + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupHelpView(contentView, + introText: NSLocalizedString("You don’t have any other devices connected to this Firefox Account available to sync.", tableName: "SendTo", comment: "Error message shown in the remote tabs panel"), + showMeText: "") // TODO We used to have a 'show me how to ...' text here. But, we cannot open web pages from the extension. So this is clear for now until we decide otherwise. + // Move the separator off screen + separatorInset = UIEdgeInsets(top: 0, left: 1000, bottom: 0, right: 0) + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/Contents.json b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..28a919cfa2 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,138 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "send-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "send-60@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "send-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "send-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "send-83.5@2x.png", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-60@2x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-60@2x.png new file mode 100644 index 0000000000..487ed390aa Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-60@2x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-60@3x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-60@3x.png new file mode 100644 index 0000000000..d8feffdccb Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-60@3x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-76.png b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-76.png new file mode 100644 index 0000000000..a2a0ab768a Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-76.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-76@2x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-76@2x.png new file mode 100644 index 0000000000..0aff7eef97 Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-76@2x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-83.5@2x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-83.5@2x.png new file mode 100644 index 0000000000..21bffd190f Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/AppIcon.appiconset/send-83.5@2x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/Contents.json b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/Contents.json new file mode 100644 index 0000000000..bb76c612f3 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "deviceTypeDesktop.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "deviceTypeDesktop@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "deviceTypeDesktop@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop.png b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop.png new file mode 100644 index 0000000000..98dadc99ea Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@2x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@2x.png new file mode 100644 index 0000000000..1d2898e243 Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@2x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@3x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@3x.png new file mode 100644 index 0000000000..5d5ab5577b Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeDesktop.imageset/deviceTypeDesktop@3x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/Contents.json b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/Contents.json new file mode 100644 index 0000000000..e936c7ebaf --- /dev/null +++ b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "deviceTypeMobile.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "deviceTypeMobile@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "deviceTypeMobile@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile.png b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile.png new file mode 100644 index 0000000000..f17820f821 Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@2x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@2x.png new file mode 100644 index 0000000000..d8d855d7c2 Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@2x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@3x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@3x.png new file mode 100644 index 0000000000..19df48506f Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/deviceTypeMobile.imageset/deviceTypeMobile@3x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/Contents.json b/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/Contents.json new file mode 100644 index 0000000000..0307cc7236 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "emptySync.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "emptySync@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "emptySync@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync.png b/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync.png new file mode 100644 index 0000000000..c11fe82e4b Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync@2x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync@2x.png new file mode 100644 index 0000000000..59db26d3d3 Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync@2x.png differ diff --git a/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync@3x.png b/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync@3x.png new file mode 100644 index 0000000000..aa5f3c242c Binary files /dev/null and b/mobile/ios/Extensions/SendTo/Images.xcassets/emptySync.imageset/emptySync@3x.png differ diff --git a/mobile/ios/Extensions/SendTo/Info.plist b/mobile/ios/Extensions/SendTo/Info.plist new file mode 100644 index 0000000000..917157f93c --- /dev/null +++ b/mobile/ios/Extensions/SendTo/Info.plist @@ -0,0 +1,48 @@ + + + + + MozDevelopmentTeam + $(DEVELOPMENT_TEAM) + CFBundleDevelopmentRegion + en + CFBundleDisplayName + CFBundleDisplayName + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIcons + + CFBundleIcons~ipad + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + UIAppFonts + + FiraSans-Regular.ttf + + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + SUBQUERY ( extensionItems, $extensionItem, SUBQUERY ( $extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url").@count == 1 ).@count == 1 + + NSExtensionPointIdentifier + com.apple.ui-services + NSExtensionPrincipalClass + ActionViewController + + + diff --git a/mobile/ios/Extensions/SendTo/InstructionsViewController.swift b/mobile/ios/Extensions/SendTo/InstructionsViewController.swift new file mode 100644 index 0000000000..85972240f3 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/InstructionsViewController.swift @@ -0,0 +1,95 @@ +/* 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/. */ + +import UIKit +import SnapKit + +struct InstructionsViewControllerUX { + static let TopPadding = CGFloat(20) + static let TextFont = UIFont.systemFont(ofSize: UIFont.labelFontSize) + static let TextColor = UIColor(rgb: 0x555555) + static let LinkColor = UIColor.blue +} + +protocol InstructionsViewControllerDelegate: class { + func instructionsViewControllerDidClose(_ instructionsViewController: InstructionsViewController) +} + +private func highlightLink(_ s: NSString, withColor color: UIColor) -> NSAttributedString { + let start = s.range(of: "<") + if start.location == NSNotFound { + return NSAttributedString(string: s as String) + } + + var s: NSString = s.replacingCharacters(in: start, with: "") as NSString + let end = s.range(of: ">") + s = s.replacingCharacters(in: end, with: "") as NSString + let a = NSMutableAttributedString(string: s as String) + let r = NSRange(location: start.location, length: end.location-start.location) + a.addAttribute(NSForegroundColorAttributeName, value: color, range: r) + return a +} + +func setupHelpView(_ view: UIView, introText: String, showMeText: String) { + let imageView = UIImageView() + imageView.image = UIImage(named: "emptySync") + view.addSubview(imageView) + imageView.snp.makeConstraints { (make) -> Void in + make.top.equalTo(view).offset(InstructionsViewControllerUX.TopPadding) + make.centerX.equalTo(view) + } + + let label1 = UILabel() + view.addSubview(label1) + label1.text = introText + label1.numberOfLines = 0 + label1.lineBreakMode = NSLineBreakMode.byWordWrapping + label1.font = InstructionsViewControllerUX.TextFont + label1.textColor = InstructionsViewControllerUX.TextColor + label1.textAlignment = NSTextAlignment.center + label1.snp.makeConstraints { (make) -> Void in + make.width.equalTo(250) + make.top.equalTo(imageView.snp.bottom).offset(InstructionsViewControllerUX.TopPadding) + make.centerX.equalTo(view) + } + + let label2 = UILabel() + view.addSubview(label2) + label2.numberOfLines = 0 + label2.lineBreakMode = NSLineBreakMode.byWordWrapping + label2.font = InstructionsViewControllerUX.TextFont + label2.textColor = InstructionsViewControllerUX.TextColor + label2.textAlignment = NSTextAlignment.center + label2.attributedText = highlightLink(showMeText as NSString, withColor: InstructionsViewControllerUX.LinkColor) + label2.snp.makeConstraints { (make) -> Void in + make.width.equalTo(250) + make.top.equalTo(label1.snp.bottom).offset(InstructionsViewControllerUX.TopPadding) + make.centerX.equalTo(view) + } +} + +class InstructionsViewController: UIViewController { + weak var delegate: InstructionsViewControllerDelegate? + + override func viewDidLoad() { + super.viewDidLoad() + edgesForExtendedLayout = [] + view.backgroundColor = UIColor.white + + navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("Close", tableName: "SendTo", comment: "Close button in top navigation bar"), style: UIBarButtonItemStyle.done, target: self, action: #selector(InstructionsViewController.close)) + navigationItem.leftBarButtonItem?.accessibilityIdentifier = "InstructionsViewController.navigationItem.leftBarButtonItem" + + setupHelpView(view, + introText: NSLocalizedString("You are not signed in to your Firefox Account.", tableName: "SendTo", comment: "See http://mzl.la/1ISlXnU"), + showMeText: NSLocalizedString("Please open Firefox, go to Settings and sign in to continue.", tableName: "SendTo", comment: "See http://mzl.la/1ISlXnU")) + } + + func close() { + delegate?.instructionsViewControllerDidClose(self) + } + + func showMeHow() { + print("Show me how") // TODO Not sure what to do or if to keep this. Waiting for UX feedback. + } +} diff --git a/mobile/ios/Extensions/SendTo/MainInterface.storyboard b/mobile/ios/Extensions/SendTo/MainInterface.storyboard new file mode 100644 index 0000000000..a7b20d60d4 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/MainInterface.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/ios/Extensions/SendTo/en.lproj/InfoPlist.strings b/mobile/ios/Extensions/SendTo/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000..529af36839 --- /dev/null +++ b/mobile/ios/Extensions/SendTo/en.lproj/InfoPlist.strings @@ -0,0 +1,5 @@ +/* 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/. */ + +"CFBundleDisplayName" = "Send Tab"; diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/Contents.json b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/Contents.json new file mode 100644 index 0000000000..e7fc60dd35 --- /dev/null +++ b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "menu-Bookmark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "menu-Bookmark@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "menu-Bookmark@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark.png new file mode 100644 index 0000000000..214afcb29e Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark.png differ diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark@2x.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark@2x.png new file mode 100644 index 0000000000..028721ac4b Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark@2x.png differ diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark@3x.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark@3x.png new file mode 100644 index 0000000000..d4d18ab6c6 Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToBookmarks.imageset/menu-Bookmark@3x.png differ diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/Contents.json b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/Contents.json new file mode 100644 index 0000000000..d505445f08 --- /dev/null +++ b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reading-list-add.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "reading-list-add@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "reading-list-add@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add.png new file mode 100644 index 0000000000..c1d899a31f Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add.png differ diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add@2x.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add@2x.png new file mode 100644 index 0000000000..66ca5a99ec Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add@2x.png differ diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add@3x.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add@3x.png new file mode 100644 index 0000000000..998f4a164c Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/AddToReadingList.imageset/reading-list-add@3x.png differ diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/Contents.json b/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/Contents.json new file mode 100644 index 0000000000..37ebd6b916 --- /dev/null +++ b/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "icon-40@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40.png new file mode 100644 index 0000000000..dc9b5a090f Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40.png differ diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40@2x.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40@2x.png new file mode 100644 index 0000000000..49db3894f1 Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40@2x.png differ diff --git a/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40@3x.png b/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40@3x.png new file mode 100644 index 0000000000..3b09cd5dbd Binary files /dev/null and b/mobile/ios/Extensions/ShareTo/Images.xcassets/Icon-Small.imageset/icon-40@3x.png differ diff --git a/mobile/ios/Extensions/ShareTo/Info.plist b/mobile/ios/Extensions/ShareTo/Info.plist new file mode 100644 index 0000000000..33f4c86a69 --- /dev/null +++ b/mobile/ios/Extensions/ShareTo/Info.plist @@ -0,0 +1,48 @@ + + + + + MozDevelopmentTeam + $(DEVELOPMENT_TEAM) + CFBundleDevelopmentRegion + en + CFBundleDisplayName + $(MOZ_BUNDLE_DISPLAY_NAME) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + SUBQUERY ( extensionItems, $extensionItem, SUBQUERY ( $extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url").@count == 1 ).@count == 1 + + NSExtensionPointIdentifier + com.apple.share-services + NSExtensionPrincipalClass + InitialViewController + + UIAppFonts + + FiraSans-Regular.ttf + FiraSans-SemiBold.ttf + FiraSans-Light.ttf + FiraSans-UltraLight.ttf + FiraSans-Medium.ttf + + + diff --git a/mobile/ios/Extensions/ShareTo/InitialViewController.swift b/mobile/ios/Extensions/ShareTo/InitialViewController.swift new file mode 100644 index 0000000000..f9c80f2061 --- /dev/null +++ b/mobile/ios/Extensions/ShareTo/InitialViewController.swift @@ -0,0 +1,136 @@ +/* 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/. */ + +import UIKit +import Shared +import Storage + +private let LastUsedShareDestinationsKey = "LastUsedShareDestinations" + +@objc(InitialViewController) +class InitialViewController: UIViewController, ShareControllerDelegate { + var shareDialogController: ShareDialogController! + + override func viewDidLoad() { + super.viewDidLoad() + self.view.backgroundColor = UIColor(white: 0.0, alpha: 0.66) // TODO: Is the correct color documented somewhere? + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + ExtensionUtils.extractSharedItemFromExtensionContext(self.extensionContext, completionHandler: { (item, error) -> Void in + if let item = item, error == nil { + DispatchQueue.main.async { + guard item.isShareable else { + let alert = UIAlertController(title: Strings.SendToErrorTitle, message: Strings.SendToErrorMessage, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: Strings.SendToErrorOKButton, style: .default) { _ in self.finish() }) + self.present(alert, animated: true, completion: nil) + return + } + + self.presentShareDialog(item) + } + } else { + self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) + } + }) + } + + // + + func shareControllerDidCancel(_ shareController: ShareDialogController) { + UIView.animate(withDuration: 0.25, animations: { () -> Void in + self.shareDialogController.view.alpha = 0.0 + }, completion: { (Bool) -> Void in + self.dismissShareDialog() + self.finish() + }) + } + + func finish() { + self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) + } + + func shareController(_ shareController: ShareDialogController, didShareItem item: ShareItem, toDestinations destinations: NSSet) { + setLastUsedShareDestinations(destinations) + + UIView.animate(withDuration: 0.25, animations: { () -> Void in + self.shareDialogController.view.alpha = 0.0 + }, completion: { (Bool) -> Void in + self.dismissShareDialog() + + let profile = BrowserProfile(localName: "profile") + + if destinations.contains(ShareDestinationReadingList) { + profile.readingList?.createRecordWithURL(item.url, title: item.title ?? "", addedBy: UIDevice.current.name) + } + + if destinations.contains(ShareDestinationBookmarks) { + _ = profile.bookmarks.shareItem(item).value // Blocks until database has settled + } + + profile.shutdown() + + self.finish() + }) + } + + // + + // TODO: use Set. + func getLastUsedShareDestinations() -> NSSet { + if let destinations = UserDefaults.standard.object(forKey: LastUsedShareDestinationsKey) as? NSArray { + return NSSet(array: destinations as [AnyObject]) + } + return NSSet(object: ShareDestinationBookmarks) + } + + func setLastUsedShareDestinations(_ destinations: NSSet) { + UserDefaults.standard.set(destinations.allObjects, forKey: LastUsedShareDestinationsKey) + UserDefaults.standard.synchronize() + } + + func presentShareDialog(_ item: ShareItem) { + shareDialogController = ShareDialogController() + shareDialogController.delegate = self + shareDialogController.item = item + shareDialogController.initialShareDestinations = getLastUsedShareDestinations() + + self.addChildViewController(shareDialogController) + shareDialogController.view.translatesAutoresizingMaskIntoConstraints = false + self.view.addSubview(shareDialogController.view) + shareDialogController.didMove(toParentViewController: self) + + // Setup constraints for the dialog. We keep the dialog centered with 16 points of padding on both + // sides. The dialog grows to max 380 points wide so that it does not look too big on landscape or + // iPad devices. + + let views: NSDictionary = ["dialog": shareDialogController.view] + + view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(16@751)-[dialog(<=380@1000)]-(16@751)-|", + options: NSLayoutFormatOptions(), metrics: nil, views: (views as? [String: AnyObject])!)) + + let cx = NSLayoutConstraint(item: shareDialogController.view, attribute: NSLayoutAttribute.centerX, + relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1.0, constant: 0) + cx.priority = 1000 // TODO: Why does UILayoutPriorityRequired give a linker error? SDK Bug? + view.addConstraint(cx) + + view.addConstraint(NSLayoutConstraint(item: shareDialogController.view, attribute: NSLayoutAttribute.centerY, + relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1.0, constant: 0)) + + // Fade the dialog in + + shareDialogController.view.alpha = 0.0 + UIView.animate(withDuration: 0.25, animations: { () -> Void in + self.shareDialogController.view.alpha = 1.0 + }, completion: nil) + } + + func dismissShareDialog() { + shareDialogController.willMove(toParentViewController: nil) + shareDialogController.view.removeFromSuperview() + shareDialogController.removeFromParentViewController() + } +} diff --git a/mobile/ios/Extensions/ShareTo/ShareViewController.swift b/mobile/ios/Extensions/ShareTo/ShareViewController.swift new file mode 100644 index 0000000000..a85279b8d8 --- /dev/null +++ b/mobile/ios/Extensions/ShareTo/ShareViewController.swift @@ -0,0 +1,245 @@ +/* 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/. */ + +import UIKit +import Shared +import Storage + +struct ShareDestination { + let code: String + let name: String + let image: String +} + +// TODO: See if we can do this with an Enum instead. Previous attempts failed because for example NSSet does not take (string) enum values. +let ShareDestinationBookmarks: String = "Bookmarks" +let ShareDestinationReadingList: String = "ReadingList" + +let ShareDestinations = [ + ShareDestination(code: ShareDestinationReadingList, name: NSLocalizedString("Add to Reading List", tableName: "ShareTo", comment: "On/off toggle to select adding this url to your reading list"), image: "AddToReadingList"), + ShareDestination(code: ShareDestinationBookmarks, name: NSLocalizedString("Add to Bookmarks", tableName: "ShareTo", comment: "On/off toggle to select adding this url to your bookmarks"), image: "AddToBookmarks") +] + +protocol ShareControllerDelegate { + func shareControllerDidCancel(_ shareController: ShareDialogController) + func shareController(_ shareController: ShareDialogController, didShareItem item: ShareItem, toDestinations destinations: NSSet) +} + +private struct ShareDialogControllerUX { + static let CornerRadius: CGFloat = 4 // Corner radius of the dialog + + static let NavigationBarTintColor = UIColor(rgb: 0xf37c00) // Tint color changes the text color in the navigation bar + static let NavigationBarCancelButtonFont = UIFont.systemFont(ofSize: UIFont.buttonFontSize) // System default + static let NavigationBarAddButtonFont = UIFont.boldSystemFont(ofSize: UIFont.buttonFontSize) // System default + static let NavigationBarIconSize = 40 // Width and height of the icon + static let NavigationBarBottomPadding = 12 + + static let ItemTitleFontMedium = UIFont.systemFont(ofSize: 15, weight: UIFontWeightMedium) + static let ItemTitleFont = UIFont.systemFont(ofSize: 15) + static let ItemTitleMaxNumberOfLines = 2 + static let ItemTitleLeftPadding = 44 + static let ItemTitleRightPadding = 44 + static let ItemTitleBottomPadding = 12 + + static let ItemLinkFont = UIFont.systemFont(ofSize: 12) + static let ItemLinkMaxNumberOfLines = 3 + static let ItemLinkLeftPadding = 44 + static let ItemLinkRightPadding = 44 + static let ItemLinkBottomPadding = 14 + + static let DividerColor = UIColor.lightGray // Divider between the item and the table with destinations + static let DividerHeight = 0.5 + + static let TableRowHeight: CGFloat = 44 // System default + static let TableRowFont = UIFont.systemFont(ofSize: 14) + static let TableRowFontMinScale: CGFloat = 0.8 + static let TableRowTintColor = UIColor(red: 0.427, green: 0.800, blue: 0.102, alpha: 1.0) // Green tint for the checkmark + static let TableRowTextColor = UIColor(rgb: 0x555555) + + static let TableHeight = 88 // Height of 2 standard 44px cells +} + +class ShareDialogController: UIViewController, UITableViewDataSource, UITableViewDelegate { + var delegate: ShareControllerDelegate! + var item: ShareItem! + var initialShareDestinations: NSSet = NSSet(object: ShareDestinationBookmarks) + + var selectedShareDestinations: NSMutableSet = NSMutableSet() + var navBar: UINavigationBar! + var navItem: UINavigationItem! + + override func viewDidLoad() { + super.viewDidLoad() + + selectedShareDestinations = NSMutableSet(set: initialShareDestinations) + + self.view.backgroundColor = UIColor.white + self.view.layer.cornerRadius = ShareDialogControllerUX.CornerRadius + self.view.clipsToBounds = true + + // Setup the NavigationBar + + navBar = UINavigationBar() + navBar.translatesAutoresizingMaskIntoConstraints = false + navBar.tintColor = ShareDialogControllerUX.NavigationBarTintColor + navBar.isTranslucent = false + self.view.addSubview(navBar) + + // Setup the NavigationItem + + navItem = UINavigationItem() + navItem.leftBarButtonItem = UIBarButtonItem( + title: Strings.ShareToCancelButton, + style: .plain, + target: self, + action: #selector(ShareDialogController.cancel) + ) + navItem.leftBarButtonItem?.setTitleTextAttributes([NSFontAttributeName: ShareDialogControllerUX.NavigationBarCancelButtonFont], for: UIControlState()) + navItem.leftBarButtonItem?.accessibilityIdentifier = "ShareDialogController.navigationItem.leftBarButtonItem" + + navItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("Add", tableName: "ShareTo", comment: "Add button in the share dialog"), style: UIBarButtonItemStyle.done, target: self, action: #selector(ShareDialogController.add)) + navItem.rightBarButtonItem?.setTitleTextAttributes([NSFontAttributeName: ShareDialogControllerUX.NavigationBarAddButtonFont], for: UIControlState()) + + let logo = UIImageView(image: UIImage(named: "Icon-Small")) + logo.contentMode = UIViewContentMode.scaleAspectFit // TODO Can go away if icon is provided in correct size + navItem.titleView = logo + + navBar.pushItem(navItem, animated: false) + + // Setup the title view + + let titleView = UILabel() + titleView.translatesAutoresizingMaskIntoConstraints = false + titleView.numberOfLines = ShareDialogControllerUX.ItemTitleMaxNumberOfLines + titleView.lineBreakMode = NSLineBreakMode.byTruncatingTail + titleView.text = item.title + titleView.font = ShareDialogControllerUX.ItemTitleFontMedium + view.addSubview(titleView) + + // Setup the link view + + let linkView = UILabel() + linkView.translatesAutoresizingMaskIntoConstraints = false + linkView.numberOfLines = ShareDialogControllerUX.ItemLinkMaxNumberOfLines + linkView.lineBreakMode = NSLineBreakMode.byTruncatingTail + linkView.text = item.url + linkView.font = ShareDialogControllerUX.ItemLinkFont + view.addSubview(linkView) + + // Setup the icon + + let iconView = UIImageView() + iconView.translatesAutoresizingMaskIntoConstraints = false + iconView.image = UIImage(named: "defaultFavicon") + view.addSubview(iconView) + + // Setup the divider + + let dividerView = UIView() + dividerView.translatesAutoresizingMaskIntoConstraints = false + dividerView.backgroundColor = ShareDialogControllerUX.DividerColor + view.addSubview(dividerView) + + // Setup the table with destinations + + let tableView = UITableView() + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.separatorInset = UIEdgeInsets.zero + tableView.layoutMargins = UIEdgeInsets.zero + tableView.isUserInteractionEnabled = true + tableView.delegate = self + tableView.allowsSelection = true + tableView.dataSource = self + tableView.isScrollEnabled = false + view.addSubview(tableView) + + // Setup constraints + + let views = [ + "nav": navBar, + "title": titleView, + "link": linkView, + "icon": iconView, + "divider": dividerView, + "table": tableView + ] + + // TODO See Bug 1102516 - Use Snappy to define share extension layout constraints + + let constraints = [ + "H:|[nav]|", + "V:|[nav]", + + "H:|-\(ShareDialogControllerUX.ItemTitleLeftPadding)-[title]-\(ShareDialogControllerUX.ItemTitleRightPadding)-|", + "V:[nav]-\(ShareDialogControllerUX.NavigationBarBottomPadding)-[title]", + + "H:|-\(ShareDialogControllerUX.ItemLinkLeftPadding)-[link]-\(ShareDialogControllerUX.ItemLinkLeftPadding)-|", + "V:[title]-\(ShareDialogControllerUX.ItemTitleBottomPadding)-[link]", + + "H:|[divider]|", + "V:[divider(\(ShareDialogControllerUX.DividerHeight))]", + "V:[link]-\(ShareDialogControllerUX.ItemLinkBottomPadding)-[divider]", + + "H:|[table]|", + "V:[divider][table]", + "V:[table(\(ShareDialogControllerUX.TableHeight))]|" + ] + + for constraint in constraints { + view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: constraint, options: NSLayoutFormatOptions(), metrics: nil, views: views)) + } + } + + // UITabBarItem Actions that map to our delegate methods + + func cancel() { + delegate?.shareControllerDidCancel(self) + } + + func add() { + delegate?.shareController(self, didShareItem: item, toDestinations: NSSet(set: selectedShareDestinations)) + } + + // UITableView Delegate and DataSource + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return ShareDestinations.count + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return ShareDialogControllerUX.TableRowHeight + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = UITableViewCell() + cell.textLabel?.textColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.darkGray : ShareDialogControllerUX.TableRowTextColor + cell.textLabel?.font = ShareDialogControllerUX.TableRowFont + cell.accessoryType = selectedShareDestinations.contains(ShareDestinations[indexPath.row].code) ? UITableViewCellAccessoryType.checkmark : UITableViewCellAccessoryType.none + cell.tintColor = ShareDialogControllerUX.TableRowTintColor + cell.layoutMargins = UIEdgeInsets.zero + cell.textLabel?.text = ShareDestinations[indexPath.row].name + cell.textLabel?.adjustsFontSizeToFitWidth = true + cell.textLabel?.minimumScaleFactor = ShareDialogControllerUX.TableRowFontMinScale + cell.imageView?.image = UIImage(named: ShareDestinations[indexPath.row].image) + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: false) + + let code = ShareDestinations[indexPath.row].code + if selectedShareDestinations.contains(code) { + selectedShareDestinations.remove(code) + } else { + selectedShareDestinations.add(code) + } + tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic) + + navItem.rightBarButtonItem?.isEnabled = (selectedShareDestinations.count != 0) + } +} diff --git a/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/Contents.json b/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/Contents.json new file mode 100644 index 0000000000..2755067221 --- /dev/null +++ b/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "todayCopiedLink.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "todayCopiedLink@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "todayCopiedLink@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink.png b/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink.png new file mode 100644 index 0000000000..ec961e3652 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink@2x.png b/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink@2x.png new file mode 100644 index 0000000000..6aaba4e712 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink@2x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink@3x.png b/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink@3x.png new file mode 100644 index 0000000000..2ee48ceea6 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/copy_link_icon.imageset/todayCopiedLink@3x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/Contents.json b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/Contents.json new file mode 100644 index 0000000000..1577937cd2 --- /dev/null +++ b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "newPrivateTabHighlight.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "newPrivateTabHighlight@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "newPrivateTabHighlight@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight.png b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight.png new file mode 100644 index 0000000000..bda053c60e Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight@2x.png b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight@2x.png new file mode 100644 index 0000000000..b70eacb526 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight@2x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight@3x.png b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight@3x.png new file mode 100644 index 0000000000..43f6e13fe4 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_highlight.imageset/newPrivateTabHighlight@3x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/Contents.json b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/Contents.json new file mode 100644 index 0000000000..3e26c70e29 --- /dev/null +++ b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "newPrivateTab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "newPrivateTab@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "newPrivateTab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab.png b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab.png new file mode 100644 index 0000000000..319f9763b0 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab@2x.png b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab@2x.png new file mode 100644 index 0000000000..87d4bdbe1e Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab@2x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab@3x.png b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab@3x.png new file mode 100644 index 0000000000..ec50af0649 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_private_tab_button_normal.imageset/newPrivateTab@3x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/Contents.json b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/Contents.json new file mode 100644 index 0000000000..11bff47496 --- /dev/null +++ b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "newTabHighlight.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "newTabHighlight@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "newTabHighlight@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight.png b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight.png new file mode 100644 index 0000000000..1098973f17 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight@2x.png b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight@2x.png new file mode 100644 index 0000000000..305fd58797 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight@2x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight@3x.png b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight@3x.png new file mode 100644 index 0000000000..3bd47318d9 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_highlight.imageset/newTabHighlight@3x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/Contents.json b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/Contents.json new file mode 100644 index 0000000000..262e9f87a3 --- /dev/null +++ b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "newTab.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "newTab@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "newTab@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab.png b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab.png new file mode 100644 index 0000000000..8030c40f35 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab@2x.png b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab@2x.png new file mode 100644 index 0000000000..250e4351ed Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab@2x.png differ diff --git a/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab@3x.png b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab@3x.png new file mode 100644 index 0000000000..c2d22b0601 Binary files /dev/null and b/mobile/ios/Extensions/Today/Images.xcassets/new_tab_button_normal.imageset/newTab@3x.png differ diff --git a/mobile/ios/Extensions/Today/Info.plist b/mobile/ios/Extensions/Today/Info.plist new file mode 100644 index 0000000000..a2d6af53a6 --- /dev/null +++ b/mobile/ios/Extensions/Today/Info.plist @@ -0,0 +1,37 @@ + + + + + MozDevelopmentTeam + $(DEVELOPMENT_TEAM) + CFBundleDevelopmentRegion + en + CFBundleDisplayName + $(MOZ_BUNDLE_DISPLAY_NAME) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSExtension + + NSExtensionPointIdentifier + com.apple.widget-extension + NSExtensionPrincipalClass + TodayViewController + + MozInternalURLScheme + $(MOZ_INTERNAL_URL_SCHEME) + + diff --git a/mobile/ios/Extensions/Today/TodayViewController.swift b/mobile/ios/Extensions/Today/TodayViewController.swift new file mode 100644 index 0000000000..28c596e0ff --- /dev/null +++ b/mobile/ios/Extensions/Today/TodayViewController.swift @@ -0,0 +1,298 @@ +/* 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/. */ + +import UIKit +import NotificationCenter +import Shared +import SnapKit +import XCGLogger + +private let log = Logger.browserLogger + +struct TodayStrings { + static let NewPrivateTabButtonLabel = NSLocalizedString("TodayWidget.NewPrivateTabButtonLabel", tableName: "Today", value: "New Private Tab", comment: "New Private Tab button label") + static let NewTabButtonLabel = NSLocalizedString("TodayWidget.NewTabButtonLabel", tableName: "Today", value: "New Tab", comment: "New Tab button label") + static let GoToCopiedLinkLabel = NSLocalizedString("TodayWidget.GoToCopiedLinkLabel", tableName: "Today", value: "Go to copied link", comment: "Go to link on clipboard") +} + +struct TodayUX { + static let privateBrowsingColor = UIColor(rgb: 0xCE6EFC) + static let backgroundHightlightColor = UIColor(white: 216.0/255.0, alpha: 44.0/255.0) + static let linkTextSize: CGFloat = 10.0 + static let labelTextSize: CGFloat = 14.0 + static let imageButtonTextSize: CGFloat = 14.0 + static let copyLinkImageWidth: CGFloat = 23 + static let margin: CGFloat = 8 + static let buttonsHorizontalMarginPercentage: CGFloat = 0.1 + static let iOS9LeftMargin: CGFloat = 40 +} + +@objc (TodayViewController) +class TodayViewController: UIViewController, NCWidgetProviding { + + var copiedURL: URL? + + fileprivate lazy var newTabButton: ImageButtonWithLabel = { + let imageButton = ImageButtonWithLabel() + imageButton.addTarget(self, action: #selector(onPressNewTab), forControlEvents: .touchUpInside) + imageButton.label.text = TodayStrings.NewTabButtonLabel + + let button = imageButton.button + + button.setImage(UIImage(named: "new_tab_button_normal")?.withRenderingMode(.alwaysTemplate), for: .normal) + button.setImage(UIImage(named: "new_tab_button_highlight")?.withRenderingMode(.alwaysTemplate), for: .highlighted) + + let label = imageButton.label + label.font = UIFont.systemFont(ofSize: TodayUX.imageButtonTextSize) + + imageButton.sizeToFit() + return imageButton + }() + + fileprivate lazy var newPrivateTabButton: ImageButtonWithLabel = { + let imageButton = ImageButtonWithLabel() + imageButton.addTarget(self, action: #selector(onPressNewPrivateTab), forControlEvents: .touchUpInside) + imageButton.label.text = TodayStrings.NewPrivateTabButtonLabel + + let button = imageButton.button + button.setImage(UIImage(named: "new_private_tab_button_normal"), for: .normal) + button.setImage(UIImage(named: "new_private_tab_button_highlight"), for: .highlighted) + + let label = imageButton.label + label.tintColor = TodayUX.privateBrowsingColor + label.textColor = TodayUX.privateBrowsingColor + label.font = UIFont.systemFont(ofSize: TodayUX.imageButtonTextSize) + imageButton.sizeToFit() + return imageButton + }() + + fileprivate lazy var openCopiedLinkButton: ButtonWithSublabel = { + let button = ButtonWithSublabel() + + button.setTitle(TodayStrings.GoToCopiedLinkLabel, for: .normal) + button.addTarget(self, action: #selector(onPressOpenClibpoard), for: .touchUpInside) + + // We need to set the background image/color for .Normal, so the whole button is tappable. + button.setBackgroundColor(UIColor.clear, forState: .normal) + button.setBackgroundColor(TodayUX.backgroundHightlightColor, forState: .highlighted) + + button.setImage(UIImage(named: "copy_link_icon")?.withRenderingMode(.alwaysTemplate), for: .normal) + + button.label.font = UIFont.systemFont(ofSize: TodayUX.labelTextSize) + button.subtitleLabel.font = UIFont.systemFont(ofSize: TodayUX.linkTextSize) + return button + }() + + fileprivate lazy var widgetStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .fill + stackView.spacing = TodayUX.margin / 2 + stackView.distribution = UIStackViewDistribution.fill + stackView.layoutMargins = UIEdgeInsets(top: TodayUX.margin, left: TodayUX.margin, bottom: TodayUX.margin, right: TodayUX.margin) + stackView.isLayoutMarginsRelativeArrangement = true + return stackView + }() + + fileprivate lazy var buttonStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.alignment = .fill + stackView.spacing = 0 + stackView.distribution = UIStackViewDistribution.fillEqually + let edge = self.view.frame.size.width * TodayUX.buttonsHorizontalMarginPercentage + stackView.layoutMargins = UIEdgeInsets(top: 0, left: edge, bottom: 0, right: edge) + stackView.isLayoutMarginsRelativeArrangement = true + return stackView + }() + + fileprivate var scheme: String { + guard let string = Bundle.main.object(forInfoDictionaryKey: "MozInternalURLScheme") as? String else { + // Something went wrong/weird, but we should fallback to the public one. + return "firefox" + } + return string + } + + override func viewDidLoad() { + super.viewDidLoad() + + let widgetView: UIView! + self.extensionContext?.widgetLargestAvailableDisplayMode = .compact + let effectView = UIVisualEffectView(effect: UIVibrancyEffect.widgetPrimary()) + self.view.addSubview(effectView) + effectView.snp.makeConstraints { make in + make.edges.equalTo(self.view) + } + widgetView = effectView.contentView + buttonStackView.addArrangedSubview(newTabButton) + buttonStackView.addArrangedSubview(newPrivateTabButton) + + widgetStackView.addArrangedSubview(buttonStackView) + widgetStackView.addArrangedSubview(openCopiedLinkButton) + + widgetView.addSubview(widgetStackView) + widgetStackView.snp.makeConstraints { make in + make.edges.equalTo(widgetView) + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + updateCopiedLink() + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + let edge = size.width * TodayUX.buttonsHorizontalMarginPercentage + buttonStackView.layoutMargins = UIEdgeInsets(top: 0, left: edge, bottom: 0, right: edge) + } + + func widgetMarginInsets(forProposedMarginInsets defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets { + return UIEdgeInsets.zero + } + + func updateCopiedLink() { + UIPasteboard.general.asyncURL().uponQueue(.main) { res in + if let copiedURL: URL? = res.successValue, + let url = copiedURL { + self.openCopiedLinkButton.isHidden = false + self.openCopiedLinkButton.subtitleLabel.isHidden = SystemUtils.isDeviceLocked() + self.openCopiedLinkButton.subtitleLabel.text = url.absoluteDisplayString + self.copiedURL = url + } else { + self.openCopiedLinkButton.isHidden = true + self.copiedURL = nil + } + } + } + + // MARK: Button behaviour + @objc func onPressNewTab(_ view: UIView) { + openContainingApp() + } + + @objc func onPressNewPrivateTab(_ view: UIView) { + openContainingApp("?private=true") + } + + fileprivate func openContainingApp(_ urlSuffix: String = "") { + let urlString = "\(scheme)://open-url\(urlSuffix)" + self.extensionContext?.open(URL(string: urlString)!) { success in + log.info("Extension opened containing app: \(success)") + } + } + + @objc func onPressOpenClibpoard(_ view: UIView) { + if let url = copiedURL, + let encodedString = url.absoluteString.escape() { + openContainingApp("?url=\(encodedString)") + } + } +} + +extension UIButton { + func setBackgroundColor(_ color: UIColor, forState state: UIControlState) { + let colorView = UIView(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) + colorView.backgroundColor = color + + UIGraphicsBeginImageContext(colorView.bounds.size) + if let context = UIGraphicsGetCurrentContext() { + colorView.layer.render(in: context) + } + let colorImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + self.setBackgroundImage(colorImage, for: state) + } +} + +class ImageButtonWithLabel: UIView { + + lazy var button = UIButton() + lazy var label = UILabel() + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override init(frame: CGRect) { + super.init(frame: frame) + performLayout() + } + + func performLayout() { + addSubview(button) + addSubview(label) + + button.snp.makeConstraints { make in + make.top.left.centerX.equalTo(self) + } + + label.snp.makeConstraints { make in + make.top.equalTo(button.snp.bottom) + make.leading.trailing.bottom.equalTo(self) + } + + label.numberOfLines = 1 + label.lineBreakMode = .byWordWrapping + label.textAlignment = .center + label.textColor = UIColor.white + } + + func addTarget(_ target: AnyObject?, action: Selector, forControlEvents events: UIControlEvents) { + button.addTarget(target, action: action, for: events) + } +} + +class ButtonWithSublabel: UIButton { + lazy var subtitleLabel: UILabel = UILabel() + lazy var label: UILabel = UILabel() + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + convenience init() { + self.init(frame: CGRect.zero) + } + + override init(frame: CGRect) { + super.init(frame: frame) + performLayout() + } + + fileprivate func performLayout() { + let titleLabel = self.label + + self.titleLabel?.removeFromSuperview() + addSubview(titleLabel) + + let imageView = self.imageView! + let subtitleLabel = self.subtitleLabel + subtitleLabel.textColor = UIColor.lightGray + self.addSubview(subtitleLabel) + + imageView.snp.makeConstraints { make in + make.centerY.left.equalTo(self) + make.width.equalTo(TodayUX.copyLinkImageWidth) + } + + titleLabel.snp.makeConstraints { make in + make.left.equalTo(imageView.snp.right).offset(TodayUX.margin) + make.trailing.top.equalTo(self) + } + + subtitleLabel.lineBreakMode = .byTruncatingTail + subtitleLabel.snp.makeConstraints { make in + make.bottom.equalTo(self) + make.top.equalTo(titleLabel.snp.bottom) + make.leading.trailing.equalTo(titleLabel) + } + } + + override func setTitle(_ text: String?, for state: UIControlState) { + self.label.text = text + super.setTitle(text, for: state) + } +} diff --git a/mobile/ios/Extensions/ViewLater/ActionRequestHandler.swift b/mobile/ios/Extensions/ViewLater/ActionRequestHandler.swift new file mode 100644 index 0000000000..b2525a73f0 --- /dev/null +++ b/mobile/ios/Extensions/ViewLater/ActionRequestHandler.swift @@ -0,0 +1,24 @@ +/* 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/. */ + +import UIKit +import MobileCoreServices + +import Shared +import Storage + +class ActionRequestHandler: NSObject, NSExtensionRequestHandling { + + public func beginRequest(with context: NSExtensionContext) { + ExtensionUtils.extractSharedItemFromExtensionContext(context, completionHandler: { (item, error) -> Void in + if let item = item, error == nil && item.isShareable { + let profile = BrowserProfile(localName: "profile") + profile.queue.addToQueue(item).uponQueue(DispatchQueue.main) { _ in + profile.shutdown() + context.completeRequest(returningItems: [], completionHandler: nil) + } + } + }) + } +} diff --git a/mobile/ios/Extensions/ViewLater/Base.lproj/InfoPlist.strings b/mobile/ios/Extensions/ViewLater/Base.lproj/InfoPlist.strings new file mode 100644 index 0000000000..e9bf97e73d --- /dev/null +++ b/mobile/ios/Extensions/ViewLater/Base.lproj/InfoPlist.strings @@ -0,0 +1,5 @@ +/* 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/. */ + +"CFBundleDisplayName" = "View Later"; diff --git a/mobile/ios/Extensions/ViewLater/Info.plist b/mobile/ios/Extensions/ViewLater/Info.plist new file mode 100644 index 0000000000..9025057d0b --- /dev/null +++ b/mobile/ios/Extensions/ViewLater/Info.plist @@ -0,0 +1,44 @@ + + + + + MozDevelopmentTeam + $(DEVELOPMENT_TEAM) + CFBundleDevelopmentRegion + en + CFBundleDisplayName + CFBundleDisplayName + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIcons + + CFBundleIcons~ipad + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + SUBQUERY ( extensionItems, $extensionItem, SUBQUERY ( $extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url").@count == 1 ).@count == 1 + + NSExtensionPointIdentifier + com.apple.services + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).ActionRequestHandler + + + diff --git a/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/Contents.json b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..5d140229dc --- /dev/null +++ b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,197 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "view-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "view-60@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "view-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "view-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "view-83.5@2x.png", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + }, + { + "size" : "24x24", + "idiom" : "watch", + "scale" : "2x", + "role" : "notificationCenter", + "subtype" : "38mm" + }, + { + "size" : "27.5x27.5", + "idiom" : "watch", + "scale" : "2x", + "role" : "notificationCenter", + "subtype" : "42mm" + }, + { + "size" : "29x29", + "idiom" : "watch", + "role" : "companionSettings", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "watch", + "role" : "companionSettings", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "watch", + "scale" : "2x", + "role" : "appLauncher", + "subtype" : "38mm" + }, + { + "size" : "44x44", + "idiom" : "watch", + "scale" : "2x", + "role" : "longLook", + "subtype" : "42mm" + }, + { + "size" : "86x86", + "idiom" : "watch", + "scale" : "2x", + "role" : "quickLook", + "subtype" : "38mm" + }, + { + "size" : "98x98", + "idiom" : "watch", + "scale" : "2x", + "role" : "quickLook", + "subtype" : "42mm" + }, + { + "idiom" : "watch-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-60@2x.png b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-60@2x.png new file mode 100644 index 0000000000..85fe65bae9 Binary files /dev/null and b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-60@2x.png differ diff --git a/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-60@3x.png b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-60@3x.png new file mode 100644 index 0000000000..4fc008583f Binary files /dev/null and b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-60@3x.png differ diff --git a/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-76.png b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-76.png new file mode 100644 index 0000000000..e267ea80ed Binary files /dev/null and b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-76.png differ diff --git a/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-76@2x.png b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-76@2x.png new file mode 100644 index 0000000000..62c6303f69 Binary files /dev/null and b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-76@2x.png differ diff --git a/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-83.5@2x.png b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-83.5@2x.png new file mode 100644 index 0000000000..4402c23b38 Binary files /dev/null and b/mobile/ios/Extensions/ViewLater/ViewLater.xcassets/AppIcon.appiconset/view-83.5@2x.png differ diff --git a/mobile/ios/Extensions/ViewLater/en.lproj/InfoPlist.strings b/mobile/ios/Extensions/ViewLater/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000..e9bf97e73d --- /dev/null +++ b/mobile/ios/Extensions/ViewLater/en.lproj/InfoPlist.strings @@ -0,0 +1,5 @@ +/* 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/. */ + +"CFBundleDisplayName" = "View Later"; diff --git a/mobile/ios/Fennec_Enterprise_XCUITests.xcscheme b/mobile/ios/Fennec_Enterprise_XCUITests.xcscheme new file mode 100644 index 0000000000..4fa2ff9562 --- /dev/null +++ b/mobile/ios/Fennec_Enterprise_XCUITests.xcscheme @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/ios/FxA/FxA.xcodeproj/project.pbxproj b/mobile/ios/FxA/FxA.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..fc5307865f --- /dev/null +++ b/mobile/ios/FxA/FxA.xcodeproj/project.pbxproj @@ -0,0 +1,934 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0A80BCCE1EC538DD00926C6A /* base64url.c in Sources */ = {isa = PBXBuildFile; fileRef = 0A80BCC81EC538DD00926C6A /* base64url.c */; }; + 0A80BCCF1EC538DD00926C6A /* decrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 0A80BCC91EC538DD00926C6A /* decrypt.c */; }; + 0A80BCD01EC538DD00926C6A /* encrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 0A80BCCA1EC538DD00926C6A /* encrypt.c */; }; + 0A80BCD11EC538DD00926C6A /* keys.c in Sources */ = {isa = PBXBuildFile; fileRef = 0A80BCCB1EC538DD00926C6A /* keys.c */; }; + 0A80BCD21EC538DD00926C6A /* params.c in Sources */ = {isa = PBXBuildFile; fileRef = 0A80BCCC1EC538DD00926C6A /* params.c */; }; + 0A80BCD31EC538DD00926C6A /* trailer.c in Sources */ = {isa = PBXBuildFile; fileRef = 0A80BCCD1EC538DD00926C6A /* trailer.c */; }; + 0A80BCD61EC538F500926C6A /* ece in Resources */ = {isa = PBXBuildFile; fileRef = 0A80BCD41EC538F500926C6A /* ece */; }; + 0A80BCD71EC538F500926C6A /* ece.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A80BCD51EC538F500926C6A /* ece.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 28F9520119D0F9FA00DCE892 /* FxA.h in Headers */ = {isa = PBXBuildFile; fileRef = 28F9520019D0F9FA00DCE892 /* FxA.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 28F9520B19D0F9FB00DCE892 /* FxATests.m in Sources */ = {isa = PBXBuildFile; fileRef = 28F9520A19D0F9FB00DCE892 /* FxATests.m */; }; + 2FA17FD219D3D32300F3D844 /* aes.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8219D3D32300F3D844 /* aes.h */; }; + 2FA17FD319D3D32300F3D844 /* asn1.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8319D3D32300F3D844 /* asn1.h */; }; + 2FA17FD419D3D32300F3D844 /* asn1_mac.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8419D3D32300F3D844 /* asn1_mac.h */; }; + 2FA17FD519D3D32300F3D844 /* asn1t.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8519D3D32300F3D844 /* asn1t.h */; }; + 2FA17FD619D3D32300F3D844 /* bio.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8619D3D32300F3D844 /* bio.h */; }; + 2FA17FD719D3D32300F3D844 /* blowfish.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8719D3D32300F3D844 /* blowfish.h */; }; + 2FA17FD819D3D32300F3D844 /* bn.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8819D3D32300F3D844 /* bn.h */; }; + 2FA17FD919D3D32300F3D844 /* buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8919D3D32300F3D844 /* buffer.h */; }; + 2FA17FDA19D3D32300F3D844 /* camellia.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8A19D3D32300F3D844 /* camellia.h */; }; + 2FA17FDB19D3D32300F3D844 /* cast.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8B19D3D32300F3D844 /* cast.h */; }; + 2FA17FDC19D3D32300F3D844 /* cmac.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8C19D3D32300F3D844 /* cmac.h */; }; + 2FA17FDD19D3D32300F3D844 /* cms.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8D19D3D32300F3D844 /* cms.h */; }; + 2FA17FDE19D3D32300F3D844 /* comp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8E19D3D32300F3D844 /* comp.h */; }; + 2FA17FDF19D3D32300F3D844 /* conf.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F8F19D3D32300F3D844 /* conf.h */; }; + 2FA17FE019D3D32300F3D844 /* conf_api.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9019D3D32300F3D844 /* conf_api.h */; }; + 2FA17FE119D3D32300F3D844 /* crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9119D3D32300F3D844 /* crypto.h */; }; + 2FA17FE219D3D32300F3D844 /* des.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9219D3D32300F3D844 /* des.h */; }; + 2FA17FE419D3D32300F3D844 /* dh.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9419D3D32300F3D844 /* dh.h */; }; + 2FA17FE519D3D32300F3D844 /* dsa.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9519D3D32300F3D844 /* dsa.h */; }; + 2FA17FE719D3D32300F3D844 /* dtls1.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9719D3D32300F3D844 /* dtls1.h */; }; + 2FA17FE819D3D32300F3D844 /* e_os2.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9819D3D32300F3D844 /* e_os2.h */; }; + 2FA17FE919D3D32300F3D844 /* ebcdic.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9919D3D32300F3D844 /* ebcdic.h */; }; + 2FA17FEA19D3D32300F3D844 /* ec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9A19D3D32300F3D844 /* ec.h */; }; + 2FA17FEB19D3D32300F3D844 /* ecdh.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9B19D3D32300F3D844 /* ecdh.h */; }; + 2FA17FEC19D3D32300F3D844 /* ecdsa.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9C19D3D32300F3D844 /* ecdsa.h */; }; + 2FA17FED19D3D32300F3D844 /* engine.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9D19D3D32300F3D844 /* engine.h */; }; + 2FA17FEE19D3D32300F3D844 /* err.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9E19D3D32300F3D844 /* err.h */; }; + 2FA17FEF19D3D32300F3D844 /* evp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17F9F19D3D32300F3D844 /* evp.h */; }; + 2FA17FF019D3D32300F3D844 /* hmac.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FA019D3D32300F3D844 /* hmac.h */; }; + 2FA17FF119D3D32300F3D844 /* idea.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FA119D3D32300F3D844 /* idea.h */; }; + 2FA17FF419D3D32300F3D844 /* lhash.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FA419D3D32300F3D844 /* lhash.h */; }; + 2FA17FF519D3D32300F3D844 /* md4.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FA519D3D32300F3D844 /* md4.h */; }; + 2FA17FF619D3D32300F3D844 /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FA619D3D32300F3D844 /* md5.h */; }; + 2FA17FF719D3D32300F3D844 /* mdc2.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FA719D3D32300F3D844 /* mdc2.h */; }; + 2FA17FF819D3D32300F3D844 /* modes.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FA819D3D32300F3D844 /* modes.h */; }; + 2FA17FF919D3D32300F3D844 /* obj_mac.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FA919D3D32300F3D844 /* obj_mac.h */; }; + 2FA17FFA19D3D32300F3D844 /* objects.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FAA19D3D32300F3D844 /* objects.h */; }; + 2FA17FFB19D3D32300F3D844 /* ocsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FAB19D3D32300F3D844 /* ocsp.h */; }; + 2FA17FFC19D3D32300F3D844 /* opensslconf.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FAC19D3D32300F3D844 /* opensslconf.h */; }; + 2FA17FFD19D3D32300F3D844 /* opensslv.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FAD19D3D32300F3D844 /* opensslv.h */; }; + 2FA17FFE19D3D32300F3D844 /* ossl_typ.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FAE19D3D32300F3D844 /* ossl_typ.h */; }; + 2FA17FFF19D3D32300F3D844 /* pem.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FAF19D3D32300F3D844 /* pem.h */; }; + 2FA1800019D3D32300F3D844 /* pem2.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB019D3D32300F3D844 /* pem2.h */; }; + 2FA1800119D3D32300F3D844 /* pkcs12.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB119D3D32300F3D844 /* pkcs12.h */; }; + 2FA1800219D3D32300F3D844 /* pkcs7.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB219D3D32300F3D844 /* pkcs7.h */; }; + 2FA1800419D3D32300F3D844 /* rand.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB419D3D32300F3D844 /* rand.h */; }; + 2FA1800519D3D32300F3D844 /* rc2.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB519D3D32300F3D844 /* rc2.h */; }; + 2FA1800619D3D32300F3D844 /* rc4.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB619D3D32300F3D844 /* rc4.h */; }; + 2FA1800719D3D32300F3D844 /* ripemd.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB719D3D32300F3D844 /* ripemd.h */; }; + 2FA1800819D3D32300F3D844 /* rsa.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB819D3D32300F3D844 /* rsa.h */; }; + 2FA1800919D3D32300F3D844 /* safestack.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FB919D3D32300F3D844 /* safestack.h */; }; + 2FA1800A19D3D32300F3D844 /* seed.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FBA19D3D32300F3D844 /* seed.h */; }; + 2FA1800B19D3D32300F3D844 /* sha.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FBB19D3D32300F3D844 /* sha.h */; }; + 2FA1800C19D3D32300F3D844 /* srp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FBC19D3D32300F3D844 /* srp.h */; }; + 2FA1800D19D3D32300F3D844 /* srtp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FBD19D3D32300F3D844 /* srtp.h */; }; + 2FA1800E19D3D32300F3D844 /* ssl.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FBE19D3D32300F3D844 /* ssl.h */; }; + 2FA1800F19D3D32300F3D844 /* ssl2.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FBF19D3D32300F3D844 /* ssl2.h */; }; + 2FA1801119D3D32300F3D844 /* ssl3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FC119D3D32300F3D844 /* ssl3.h */; }; + 2FA1801219D3D32300F3D844 /* stack.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FC219D3D32300F3D844 /* stack.h */; }; + 2FA1801319D3D32300F3D844 /* symhacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FC319D3D32300F3D844 /* symhacks.h */; }; + 2FA1801419D3D32300F3D844 /* tls1.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FC419D3D32300F3D844 /* tls1.h */; }; + 2FA1801519D3D32300F3D844 /* ts.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FC519D3D32300F3D844 /* ts.h */; }; + 2FA1801619D3D32300F3D844 /* txt_db.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FC619D3D32300F3D844 /* txt_db.h */; }; + 2FA1801719D3D32300F3D844 /* ui.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FC719D3D32300F3D844 /* ui.h */; }; + 2FA1801919D3D32300F3D844 /* whrlpool.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FC919D3D32300F3D844 /* whrlpool.h */; }; + 2FA1801A19D3D32300F3D844 /* x509.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FCA19D3D32300F3D844 /* x509.h */; }; + 2FA1801B19D3D32300F3D844 /* x509_vfy.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FCB19D3D32300F3D844 /* x509_vfy.h */; }; + 2FA1801C19D3D32300F3D844 /* x509v3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FCC19D3D32300F3D844 /* x509v3.h */; }; + 2FA1801D19D3D32300F3D844 /* JSONWebTokenUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA17FCD19D3D32300F3D844 /* JSONWebTokenUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FA1801E19D3D32300F3D844 /* JSONWebTokenUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA17FCE19D3D32300F3D844 /* JSONWebTokenUtils.m */; }; + 2FF824E019D3C6D8003ED08E /* KeyPair.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF824D419D3C6D8003ED08E /* KeyPair.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF824E119D3C6D8003ED08E /* KeyPair.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF824D519D3C6D8003ED08E /* KeyPair.m */; }; + 2FF824E219D3C6D8003ED08E /* PrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF824D619D3C6D8003ED08E /* PrivateKey.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF824E319D3C6D8003ED08E /* PrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF824D719D3C6D8003ED08E /* PrivateKey.m */; }; + 2FF824E419D3C6D8003ED08E /* PublicKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF824D819D3C6D8003ED08E /* PublicKey.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF824E519D3C6D8003ED08E /* PublicKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF824D919D3C6D8003ED08E /* PublicKey.m */; }; + 2FF824E619D3C6D8003ED08E /* RSAKeyPair.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF824DA19D3C6D8003ED08E /* RSAKeyPair.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF824E719D3C6D8003ED08E /* RSAKeyPair.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF824DB19D3C6D8003ED08E /* RSAKeyPair.m */; }; + 2FF825EB19D3CAFF003ED08E /* ASNUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF8258519D3CAFF003ED08E /* ASNUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF825EC19D3CAFF003ED08E /* ASNUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF8258619D3CAFF003ED08E /* ASNUtils.m */; }; + 2FF825ED19D3CAFF003ED08E /* CHMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF8258719D3CAFF003ED08E /* CHMath.h */; }; + 2FF825EE19D3CAFF003ED08E /* CHMutableNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF8258819D3CAFF003ED08E /* CHMutableNumber.h */; }; + 2FF825EF19D3CAFF003ED08E /* CHMutableNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF8258919D3CAFF003ED08E /* CHMutableNumber.m */; }; + 2FF825F019D3CAFF003ED08E /* CHNumber_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF8258A19D3CAFF003ED08E /* CHNumber_Private.h */; }; + 2FF825F119D3CAFF003ED08E /* CHNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF8258B19D3CAFF003ED08E /* CHNumber.h */; }; + 2FF825F219D3CAFF003ED08E /* CHNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF8258C19D3CAFF003ED08E /* CHNumber.m */; }; + 2FF8264219D3CAFF003ED08E /* NSData+Base16.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF825DF19D3CAFF003ED08E /* NSData+Base16.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF8264319D3CAFF003ED08E /* NSData+Base16.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF825E019D3CAFF003ED08E /* NSData+Base16.m */; }; + 2FF8264419D3CAFF003ED08E /* NSData+Base32.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF825E119D3CAFF003ED08E /* NSData+Base32.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF8264519D3CAFF003ED08E /* NSData+Base32.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF825E219D3CAFF003ED08E /* NSData+Base32.m */; }; + 2FF8264619D3CAFF003ED08E /* NSData+KeyDerivation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF825E319D3CAFF003ED08E /* NSData+KeyDerivation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF8264719D3CAFF003ED08E /* NSData+KeyDerivation.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF825E419D3CAFF003ED08E /* NSData+KeyDerivation.m */; }; + 2FF8264819D3CAFF003ED08E /* NSData+SHA.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF825E519D3CAFF003ED08E /* NSData+SHA.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF8264919D3CAFF003ED08E /* NSData+SHA.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF825E619D3CAFF003ED08E /* NSData+SHA.m */; }; + 2FF8264A19D3CAFF003ED08E /* NSData+Utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF825E719D3CAFF003ED08E /* NSData+Utils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FF8264B19D3CAFF003ED08E /* NSData+Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF825E819D3CAFF003ED08E /* NSData+Utils.m */; }; + 2FF8264C19D3CAFF003ED08E /* NSString+Utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FF825E919D3CAFF003ED08E /* NSString+Utils.h */; }; + 2FF8264D19D3CAFF003ED08E /* NSString+Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FF825EA19D3CAFF003ED08E /* NSString+Utils.m */; }; + E63320451EC2052100F2BC80 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FA17FD019D3D32300F3D844 /* libcrypto.a */; }; + E63320461EC2052100F2BC80 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FA17FD119D3D32300F3D844 /* libssl.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 28F9521819D0FCA000DCE892 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 28F951F219D0F9FA00DCE892 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 28F951FA19D0F9FA00DCE892; + remoteInfo = FxA; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0A80BCC81EC538DD00926C6A /* base64url.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = base64url.c; path = ../ThirdParty/ecec/src/base64url.c; sourceTree = ""; }; + 0A80BCC91EC538DD00926C6A /* decrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = decrypt.c; path = ../ThirdParty/ecec/src/decrypt.c; sourceTree = ""; }; + 0A80BCCA1EC538DD00926C6A /* encrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = encrypt.c; path = ../ThirdParty/ecec/src/encrypt.c; sourceTree = ""; }; + 0A80BCCB1EC538DD00926C6A /* keys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = keys.c; path = ../ThirdParty/ecec/src/keys.c; sourceTree = ""; }; + 0A80BCCC1EC538DD00926C6A /* params.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = params.c; path = ../ThirdParty/ecec/src/params.c; sourceTree = ""; }; + 0A80BCCD1EC538DD00926C6A /* trailer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trailer.c; path = ../ThirdParty/ecec/src/trailer.c; sourceTree = ""; }; + 0A80BCD41EC538F500926C6A /* ece */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ece; path = ../ThirdParty/ecec/include/ece; sourceTree = ""; }; + 0A80BCD51EC538F500926C6A /* ece.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ece.h; path = ../ThirdParty/ecec/include/ece.h; sourceTree = ""; }; + 28F951FB19D0F9FA00DCE892 /* FxA.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FxA.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 28F951FF19D0F9FA00DCE892 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 28F9520019D0F9FA00DCE892 /* FxA.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FxA.h; sourceTree = ""; }; + 28F9520619D0F9FB00DCE892 /* FxATests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FxATests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 28F9520919D0F9FB00DCE892 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 28F9520A19D0F9FB00DCE892 /* FxATests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FxATests.m; sourceTree = ""; }; + 2FA17F8219D3D32300F3D844 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = ""; }; + 2FA17F8319D3D32300F3D844 /* asn1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1.h; sourceTree = ""; }; + 2FA17F8419D3D32300F3D844 /* asn1_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1_mac.h; sourceTree = ""; }; + 2FA17F8519D3D32300F3D844 /* asn1t.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1t.h; sourceTree = ""; }; + 2FA17F8619D3D32300F3D844 /* bio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bio.h; sourceTree = ""; }; + 2FA17F8719D3D32300F3D844 /* blowfish.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blowfish.h; sourceTree = ""; }; + 2FA17F8819D3D32300F3D844 /* bn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bn.h; sourceTree = ""; }; + 2FA17F8919D3D32300F3D844 /* buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = buffer.h; sourceTree = ""; }; + 2FA17F8A19D3D32300F3D844 /* camellia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = camellia.h; sourceTree = ""; }; + 2FA17F8B19D3D32300F3D844 /* cast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cast.h; sourceTree = ""; }; + 2FA17F8C19D3D32300F3D844 /* cmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cmac.h; sourceTree = ""; }; + 2FA17F8D19D3D32300F3D844 /* cms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cms.h; sourceTree = ""; }; + 2FA17F8E19D3D32300F3D844 /* comp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = comp.h; sourceTree = ""; }; + 2FA17F8F19D3D32300F3D844 /* conf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conf.h; sourceTree = ""; }; + 2FA17F9019D3D32300F3D844 /* conf_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conf_api.h; sourceTree = ""; }; + 2FA17F9119D3D32300F3D844 /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto.h; sourceTree = ""; }; + 2FA17F9219D3D32300F3D844 /* des.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = des.h; sourceTree = ""; }; + 2FA17F9419D3D32300F3D844 /* dh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dh.h; sourceTree = ""; }; + 2FA17F9519D3D32300F3D844 /* dsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsa.h; sourceTree = ""; }; + 2FA17F9719D3D32300F3D844 /* dtls1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dtls1.h; sourceTree = ""; }; + 2FA17F9819D3D32300F3D844 /* e_os2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = e_os2.h; sourceTree = ""; }; + 2FA17F9919D3D32300F3D844 /* ebcdic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ebcdic.h; sourceTree = ""; }; + 2FA17F9A19D3D32300F3D844 /* ec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ec.h; sourceTree = ""; }; + 2FA17F9B19D3D32300F3D844 /* ecdh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ecdh.h; sourceTree = ""; }; + 2FA17F9C19D3D32300F3D844 /* ecdsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ecdsa.h; sourceTree = ""; }; + 2FA17F9D19D3D32300F3D844 /* engine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = engine.h; sourceTree = ""; }; + 2FA17F9E19D3D32300F3D844 /* err.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = err.h; sourceTree = ""; }; + 2FA17F9F19D3D32300F3D844 /* evp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = evp.h; sourceTree = ""; }; + 2FA17FA019D3D32300F3D844 /* hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hmac.h; sourceTree = ""; }; + 2FA17FA119D3D32300F3D844 /* idea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = idea.h; sourceTree = ""; }; + 2FA17FA419D3D32300F3D844 /* lhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lhash.h; sourceTree = ""; }; + 2FA17FA519D3D32300F3D844 /* md4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md4.h; sourceTree = ""; }; + 2FA17FA619D3D32300F3D844 /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = ""; }; + 2FA17FA719D3D32300F3D844 /* mdc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mdc2.h; sourceTree = ""; }; + 2FA17FA819D3D32300F3D844 /* modes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modes.h; sourceTree = ""; }; + 2FA17FA919D3D32300F3D844 /* obj_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = obj_mac.h; sourceTree = ""; }; + 2FA17FAA19D3D32300F3D844 /* objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objects.h; sourceTree = ""; }; + 2FA17FAB19D3D32300F3D844 /* ocsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ocsp.h; sourceTree = ""; }; + 2FA17FAC19D3D32300F3D844 /* opensslconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opensslconf.h; sourceTree = ""; }; + 2FA17FAD19D3D32300F3D844 /* opensslv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opensslv.h; sourceTree = ""; }; + 2FA17FAE19D3D32300F3D844 /* ossl_typ.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ossl_typ.h; sourceTree = ""; }; + 2FA17FAF19D3D32300F3D844 /* pem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pem.h; sourceTree = ""; }; + 2FA17FB019D3D32300F3D844 /* pem2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pem2.h; sourceTree = ""; }; + 2FA17FB119D3D32300F3D844 /* pkcs12.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pkcs12.h; sourceTree = ""; }; + 2FA17FB219D3D32300F3D844 /* pkcs7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pkcs7.h; sourceTree = ""; }; + 2FA17FB419D3D32300F3D844 /* rand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rand.h; sourceTree = ""; }; + 2FA17FB519D3D32300F3D844 /* rc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rc2.h; sourceTree = ""; }; + 2FA17FB619D3D32300F3D844 /* rc4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rc4.h; sourceTree = ""; }; + 2FA17FB719D3D32300F3D844 /* ripemd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ripemd.h; sourceTree = ""; }; + 2FA17FB819D3D32300F3D844 /* rsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsa.h; sourceTree = ""; }; + 2FA17FB919D3D32300F3D844 /* safestack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = safestack.h; sourceTree = ""; }; + 2FA17FBA19D3D32300F3D844 /* seed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seed.h; sourceTree = ""; }; + 2FA17FBB19D3D32300F3D844 /* sha.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha.h; sourceTree = ""; }; + 2FA17FBC19D3D32300F3D844 /* srp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = srp.h; sourceTree = ""; }; + 2FA17FBD19D3D32300F3D844 /* srtp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = srtp.h; sourceTree = ""; }; + 2FA17FBE19D3D32300F3D844 /* ssl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl.h; sourceTree = ""; }; + 2FA17FBF19D3D32300F3D844 /* ssl2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl2.h; sourceTree = ""; }; + 2FA17FC119D3D32300F3D844 /* ssl3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl3.h; sourceTree = ""; }; + 2FA17FC219D3D32300F3D844 /* stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack.h; sourceTree = ""; }; + 2FA17FC319D3D32300F3D844 /* symhacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = symhacks.h; sourceTree = ""; }; + 2FA17FC419D3D32300F3D844 /* tls1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tls1.h; sourceTree = ""; }; + 2FA17FC519D3D32300F3D844 /* ts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ts.h; sourceTree = ""; }; + 2FA17FC619D3D32300F3D844 /* txt_db.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = txt_db.h; sourceTree = ""; }; + 2FA17FC719D3D32300F3D844 /* ui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui.h; sourceTree = ""; }; + 2FA17FC919D3D32300F3D844 /* whrlpool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = whrlpool.h; sourceTree = ""; }; + 2FA17FCA19D3D32300F3D844 /* x509.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509.h; sourceTree = ""; }; + 2FA17FCB19D3D32300F3D844 /* x509_vfy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509_vfy.h; sourceTree = ""; }; + 2FA17FCC19D3D32300F3D844 /* x509v3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509v3.h; sourceTree = ""; }; + 2FA17FCD19D3D32300F3D844 /* JSONWebTokenUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONWebTokenUtils.h; sourceTree = ""; }; + 2FA17FCE19D3D32300F3D844 /* JSONWebTokenUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONWebTokenUtils.m; sourceTree = ""; }; + 2FA17FD019D3D32300F3D844 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libcrypto.a; sourceTree = ""; }; + 2FA17FD119D3D32300F3D844 /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libssl.a; sourceTree = ""; }; + 2FF824D419D3C6D8003ED08E /* KeyPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyPair.h; sourceTree = ""; }; + 2FF824D519D3C6D8003ED08E /* KeyPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyPair.m; sourceTree = ""; }; + 2FF824D619D3C6D8003ED08E /* PrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivateKey.h; sourceTree = ""; }; + 2FF824D719D3C6D8003ED08E /* PrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrivateKey.m; sourceTree = ""; }; + 2FF824D819D3C6D8003ED08E /* PublicKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PublicKey.h; sourceTree = ""; }; + 2FF824D919D3C6D8003ED08E /* PublicKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PublicKey.m; sourceTree = ""; }; + 2FF824DA19D3C6D8003ED08E /* RSAKeyPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSAKeyPair.h; sourceTree = ""; }; + 2FF824DB19D3C6D8003ED08E /* RSAKeyPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSAKeyPair.m; sourceTree = ""; }; + 2FF8258519D3CAFF003ED08E /* ASNUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASNUtils.h; sourceTree = ""; }; + 2FF8258619D3CAFF003ED08E /* ASNUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASNUtils.m; sourceTree = ""; }; + 2FF8258719D3CAFF003ED08E /* CHMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CHMath.h; sourceTree = ""; }; + 2FF8258819D3CAFF003ED08E /* CHMutableNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CHMutableNumber.h; sourceTree = ""; }; + 2FF8258919D3CAFF003ED08E /* CHMutableNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CHMutableNumber.m; sourceTree = ""; }; + 2FF8258A19D3CAFF003ED08E /* CHNumber_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CHNumber_Private.h; sourceTree = ""; }; + 2FF8258B19D3CAFF003ED08E /* CHNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CHNumber.h; sourceTree = ""; }; + 2FF8258C19D3CAFF003ED08E /* CHNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CHNumber.m; sourceTree = ""; }; + 2FF825DF19D3CAFF003ED08E /* NSData+Base16.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Base16.h"; sourceTree = ""; }; + 2FF825E019D3CAFF003ED08E /* NSData+Base16.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Base16.m"; sourceTree = ""; }; + 2FF825E119D3CAFF003ED08E /* NSData+Base32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Base32.h"; sourceTree = ""; }; + 2FF825E219D3CAFF003ED08E /* NSData+Base32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Base32.m"; sourceTree = ""; }; + 2FF825E319D3CAFF003ED08E /* NSData+KeyDerivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+KeyDerivation.h"; sourceTree = ""; }; + 2FF825E419D3CAFF003ED08E /* NSData+KeyDerivation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+KeyDerivation.m"; sourceTree = ""; }; + 2FF825E519D3CAFF003ED08E /* NSData+SHA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+SHA.h"; sourceTree = ""; }; + 2FF825E619D3CAFF003ED08E /* NSData+SHA.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+SHA.m"; sourceTree = ""; }; + 2FF825E719D3CAFF003ED08E /* NSData+Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Utils.h"; sourceTree = ""; }; + 2FF825E819D3CAFF003ED08E /* NSData+Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Utils.m"; sourceTree = ""; }; + 2FF825E919D3CAFF003ED08E /* NSString+Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Utils.h"; sourceTree = ""; }; + 2FF825EA19D3CAFF003ED08E /* NSString+Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Utils.m"; sourceTree = ""; }; + E6D69D091EC241C100B80600 /* opensslconf_ios_arm64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opensslconf_ios_arm64.h; sourceTree = ""; }; + E6D69D0A1EC241C100B80600 /* opensslconf_ios_armv7.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opensslconf_ios_armv7.h; sourceTree = ""; }; + E6D69D0B1EC241C100B80600 /* opensslconf_ios_armv7s.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opensslconf_ios_armv7s.h; sourceTree = ""; }; + E6D69D0C1EC241C100B80600 /* opensslconf_ios_i386.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opensslconf_ios_i386.h; sourceTree = ""; }; + E6D69D0D1EC241C100B80600 /* opensslconf_ios_x86_64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opensslconf_ios_x86_64.h; sourceTree = ""; }; + E6D69D0E1EC241C100B80600 /* opensslconf_tvos_arm64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opensslconf_tvos_arm64.h; sourceTree = ""; }; + E6D69D0F1EC241C100B80600 /* opensslconf_tvos_x86_64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opensslconf_tvos_x86_64.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 28F951F719D0F9FA00DCE892 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E63320451EC2052100F2BC80 /* libcrypto.a in Frameworks */, + E63320461EC2052100F2BC80 /* libssl.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 28F9520319D0F9FB00DCE892 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 28F951F119D0F9FA00DCE892 = { + isa = PBXGroup; + children = ( + 0A80BCD41EC538F500926C6A /* ece */, + 0A80BCD51EC538F500926C6A /* ece.h */, + 0A80BCC81EC538DD00926C6A /* base64url.c */, + 0A80BCC91EC538DD00926C6A /* decrypt.c */, + 0A80BCCA1EC538DD00926C6A /* encrypt.c */, + 0A80BCCB1EC538DD00926C6A /* keys.c */, + 0A80BCCC1EC538DD00926C6A /* params.c */, + 0A80BCCD1EC538DD00926C6A /* trailer.c */, + 28F951FD19D0F9FA00DCE892 /* FxA */, + 28F9520719D0F9FB00DCE892 /* FxATests */, + 28F951FC19D0F9FA00DCE892 /* Products */, + ); + sourceTree = ""; + }; + 28F951FC19D0F9FA00DCE892 /* Products */ = { + isa = PBXGroup; + children = ( + 28F951FB19D0F9FA00DCE892 /* FxA.framework */, + 28F9520619D0F9FB00DCE892 /* FxATests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 28F951FD19D0F9FA00DCE892 /* FxA */ = { + isa = PBXGroup; + children = ( + 28F9520019D0F9FA00DCE892 /* FxA.h */, + 2FA17FCD19D3D32300F3D844 /* JSONWebTokenUtils.h */, + 2FA17FCE19D3D32300F3D844 /* JSONWebTokenUtils.m */, + 2FF8258519D3CAFF003ED08E /* ASNUtils.h */, + 2FF8258619D3CAFF003ED08E /* ASNUtils.m */, + 2FF8258719D3CAFF003ED08E /* CHMath.h */, + 2FF8258819D3CAFF003ED08E /* CHMutableNumber.h */, + 2FF8258919D3CAFF003ED08E /* CHMutableNumber.m */, + 2FF8258A19D3CAFF003ED08E /* CHNumber_Private.h */, + 2FF8258B19D3CAFF003ED08E /* CHNumber.h */, + 2FF8258C19D3CAFF003ED08E /* CHNumber.m */, + 2FF825DF19D3CAFF003ED08E /* NSData+Base16.h */, + 2FF825E019D3CAFF003ED08E /* NSData+Base16.m */, + 2FF825E119D3CAFF003ED08E /* NSData+Base32.h */, + 2FF825E219D3CAFF003ED08E /* NSData+Base32.m */, + 2FF825E319D3CAFF003ED08E /* NSData+KeyDerivation.h */, + 2FF825E419D3CAFF003ED08E /* NSData+KeyDerivation.m */, + 2FF825E519D3CAFF003ED08E /* NSData+SHA.h */, + 2FF825E619D3CAFF003ED08E /* NSData+SHA.m */, + 2FF825E719D3CAFF003ED08E /* NSData+Utils.h */, + 2FF825E819D3CAFF003ED08E /* NSData+Utils.m */, + 2FF825E919D3CAFF003ED08E /* NSString+Utils.h */, + 2FF825EA19D3CAFF003ED08E /* NSString+Utils.m */, + 2FF824D419D3C6D8003ED08E /* KeyPair.h */, + 2FF824D519D3C6D8003ED08E /* KeyPair.m */, + 2FF824D619D3C6D8003ED08E /* PrivateKey.h */, + 2FF824D719D3C6D8003ED08E /* PrivateKey.m */, + 2FF824D819D3C6D8003ED08E /* PublicKey.h */, + 2FF824D919D3C6D8003ED08E /* PublicKey.m */, + 2FF824DA19D3C6D8003ED08E /* RSAKeyPair.h */, + 2FF824DB19D3C6D8003ED08E /* RSAKeyPair.m */, + 2FA17F8019D3D32300F3D844 /* include */, + 2FA17FCF19D3D32300F3D844 /* lib */, + 28F951FE19D0F9FA00DCE892 /* Supporting Files */, + ); + path = FxA; + sourceTree = ""; + }; + 28F951FE19D0F9FA00DCE892 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 28F951FF19D0F9FA00DCE892 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 28F9520719D0F9FB00DCE892 /* FxATests */ = { + isa = PBXGroup; + children = ( + 28F9520A19D0F9FB00DCE892 /* FxATests.m */, + 28F9520819D0F9FB00DCE892 /* Supporting Files */, + ); + path = FxATests; + sourceTree = ""; + }; + 28F9520819D0F9FB00DCE892 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 28F9520919D0F9FB00DCE892 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 2FA17F8019D3D32300F3D844 /* include */ = { + isa = PBXGroup; + children = ( + 2FA17F8119D3D32300F3D844 /* openssl */, + ); + path = include; + sourceTree = ""; + }; + 2FA17F8119D3D32300F3D844 /* openssl */ = { + isa = PBXGroup; + children = ( + E6D69D091EC241C100B80600 /* opensslconf_ios_arm64.h */, + E6D69D0A1EC241C100B80600 /* opensslconf_ios_armv7.h */, + E6D69D0B1EC241C100B80600 /* opensslconf_ios_armv7s.h */, + E6D69D0C1EC241C100B80600 /* opensslconf_ios_i386.h */, + E6D69D0D1EC241C100B80600 /* opensslconf_ios_x86_64.h */, + E6D69D0E1EC241C100B80600 /* opensslconf_tvos_arm64.h */, + E6D69D0F1EC241C100B80600 /* opensslconf_tvos_x86_64.h */, + 2FA17F8219D3D32300F3D844 /* aes.h */, + 2FA17F8319D3D32300F3D844 /* asn1.h */, + 2FA17F8419D3D32300F3D844 /* asn1_mac.h */, + 2FA17F8519D3D32300F3D844 /* asn1t.h */, + 2FA17F8619D3D32300F3D844 /* bio.h */, + 2FA17F8719D3D32300F3D844 /* blowfish.h */, + 2FA17F8819D3D32300F3D844 /* bn.h */, + 2FA17F8919D3D32300F3D844 /* buffer.h */, + 2FA17F8A19D3D32300F3D844 /* camellia.h */, + 2FA17F8B19D3D32300F3D844 /* cast.h */, + 2FA17F8C19D3D32300F3D844 /* cmac.h */, + 2FA17F8D19D3D32300F3D844 /* cms.h */, + 2FA17F8E19D3D32300F3D844 /* comp.h */, + 2FA17F8F19D3D32300F3D844 /* conf.h */, + 2FA17F9019D3D32300F3D844 /* conf_api.h */, + 2FA17F9119D3D32300F3D844 /* crypto.h */, + 2FA17F9219D3D32300F3D844 /* des.h */, + 2FA17F9419D3D32300F3D844 /* dh.h */, + 2FA17F9519D3D32300F3D844 /* dsa.h */, + 2FA17F9719D3D32300F3D844 /* dtls1.h */, + 2FA17F9819D3D32300F3D844 /* e_os2.h */, + 2FA17F9919D3D32300F3D844 /* ebcdic.h */, + 2FA17F9A19D3D32300F3D844 /* ec.h */, + 2FA17F9B19D3D32300F3D844 /* ecdh.h */, + 2FA17F9C19D3D32300F3D844 /* ecdsa.h */, + 2FA17F9D19D3D32300F3D844 /* engine.h */, + 2FA17F9E19D3D32300F3D844 /* err.h */, + 2FA17F9F19D3D32300F3D844 /* evp.h */, + 2FA17FA019D3D32300F3D844 /* hmac.h */, + 2FA17FA119D3D32300F3D844 /* idea.h */, + 2FA17FA419D3D32300F3D844 /* lhash.h */, + 2FA17FA519D3D32300F3D844 /* md4.h */, + 2FA17FA619D3D32300F3D844 /* md5.h */, + 2FA17FA719D3D32300F3D844 /* mdc2.h */, + 2FA17FA819D3D32300F3D844 /* modes.h */, + 2FA17FA919D3D32300F3D844 /* obj_mac.h */, + 2FA17FAA19D3D32300F3D844 /* objects.h */, + 2FA17FAB19D3D32300F3D844 /* ocsp.h */, + 2FA17FAC19D3D32300F3D844 /* opensslconf.h */, + 2FA17FAD19D3D32300F3D844 /* opensslv.h */, + 2FA17FAE19D3D32300F3D844 /* ossl_typ.h */, + 2FA17FAF19D3D32300F3D844 /* pem.h */, + 2FA17FB019D3D32300F3D844 /* pem2.h */, + 2FA17FB119D3D32300F3D844 /* pkcs12.h */, + 2FA17FB219D3D32300F3D844 /* pkcs7.h */, + 2FA17FB419D3D32300F3D844 /* rand.h */, + 2FA17FB519D3D32300F3D844 /* rc2.h */, + 2FA17FB619D3D32300F3D844 /* rc4.h */, + 2FA17FB719D3D32300F3D844 /* ripemd.h */, + 2FA17FB819D3D32300F3D844 /* rsa.h */, + 2FA17FB919D3D32300F3D844 /* safestack.h */, + 2FA17FBA19D3D32300F3D844 /* seed.h */, + 2FA17FBB19D3D32300F3D844 /* sha.h */, + 2FA17FBC19D3D32300F3D844 /* srp.h */, + 2FA17FBD19D3D32300F3D844 /* srtp.h */, + 2FA17FBE19D3D32300F3D844 /* ssl.h */, + 2FA17FBF19D3D32300F3D844 /* ssl2.h */, + 2FA17FC119D3D32300F3D844 /* ssl3.h */, + 2FA17FC219D3D32300F3D844 /* stack.h */, + 2FA17FC319D3D32300F3D844 /* symhacks.h */, + 2FA17FC419D3D32300F3D844 /* tls1.h */, + 2FA17FC519D3D32300F3D844 /* ts.h */, + 2FA17FC619D3D32300F3D844 /* txt_db.h */, + 2FA17FC719D3D32300F3D844 /* ui.h */, + 2FA17FC919D3D32300F3D844 /* whrlpool.h */, + 2FA17FCA19D3D32300F3D844 /* x509.h */, + 2FA17FCB19D3D32300F3D844 /* x509_vfy.h */, + 2FA17FCC19D3D32300F3D844 /* x509v3.h */, + ); + path = openssl; + sourceTree = ""; + }; + 2FA17FCF19D3D32300F3D844 /* lib */ = { + isa = PBXGroup; + children = ( + 2FA17FD019D3D32300F3D844 /* libcrypto.a */, + 2FA17FD119D3D32300F3D844 /* libssl.a */, + ); + path = lib; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 28F951F819D0F9FA00DCE892 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 2FF824E219D3C6D8003ED08E /* PrivateKey.h in Headers */, + 2FF824E419D3C6D8003ED08E /* PublicKey.h in Headers */, + 2FF824E619D3C6D8003ED08E /* RSAKeyPair.h in Headers */, + 2FF8264419D3CAFF003ED08E /* NSData+Base32.h in Headers */, + 2FA1801B19D3D32300F3D844 /* x509_vfy.h in Headers */, + 0A80BCD71EC538F500926C6A /* ece.h in Headers */, + 2FA1801419D3D32300F3D844 /* tls1.h in Headers */, + 28F9520119D0F9FA00DCE892 /* FxA.h in Headers */, + 2FA1801D19D3D32300F3D844 /* JSONWebTokenUtils.h in Headers */, + 2FA1801A19D3D32300F3D844 /* x509.h in Headers */, + 2FF8264C19D3CAFF003ED08E /* NSString+Utils.h in Headers */, + 2FA17FE519D3D32300F3D844 /* dsa.h in Headers */, + 2FA1801619D3D32300F3D844 /* txt_db.h in Headers */, + 2FA17FD319D3D32300F3D844 /* asn1.h in Headers */, + 2FA17FFC19D3D32300F3D844 /* opensslconf.h in Headers */, + 2FA17FDA19D3D32300F3D844 /* camellia.h in Headers */, + 2FF825F119D3CAFF003ED08E /* CHNumber.h in Headers */, + 2FF825EE19D3CAFF003ED08E /* CHMutableNumber.h in Headers */, + 2FF825F019D3CAFF003ED08E /* CHNumber_Private.h in Headers */, + 2FF825ED19D3CAFF003ED08E /* CHMath.h in Headers */, + 2FA17FE219D3D32300F3D844 /* des.h in Headers */, + 2FA17FDF19D3D32300F3D844 /* conf.h in Headers */, + 2FA17FED19D3D32300F3D844 /* engine.h in Headers */, + 2FA1801919D3D32300F3D844 /* whrlpool.h in Headers */, + 2FA17FD619D3D32300F3D844 /* bio.h in Headers */, + 2FA17FEA19D3D32300F3D844 /* ec.h in Headers */, + 2FA1800C19D3D32300F3D844 /* srp.h in Headers */, + 2FA17FFD19D3D32300F3D844 /* opensslv.h in Headers */, + 2FA17FEF19D3D32300F3D844 /* evp.h in Headers */, + 2FA17FD219D3D32300F3D844 /* aes.h in Headers */, + 2FA1801319D3D32300F3D844 /* symhacks.h in Headers */, + 2FA1800B19D3D32300F3D844 /* sha.h in Headers */, + 2FA17FE719D3D32300F3D844 /* dtls1.h in Headers */, + 2FA17FD819D3D32300F3D844 /* bn.h in Headers */, + 2FA17FE019D3D32300F3D844 /* conf_api.h in Headers */, + 2FA1801519D3D32300F3D844 /* ts.h in Headers */, + 2FF824E019D3C6D8003ED08E /* KeyPair.h in Headers */, + 2FA17FD419D3D32300F3D844 /* asn1_mac.h in Headers */, + 2FA17FFE19D3D32300F3D844 /* ossl_typ.h in Headers */, + 2FA17FDB19D3D32300F3D844 /* cast.h in Headers */, + 2FA1800219D3D32300F3D844 /* pkcs7.h in Headers */, + 2FA1800019D3D32300F3D844 /* pem2.h in Headers */, + 2FF8264A19D3CAFF003ED08E /* NSData+Utils.h in Headers */, + 2FA1800419D3D32300F3D844 /* rand.h in Headers */, + 2FF8264219D3CAFF003ED08E /* NSData+Base16.h in Headers */, + 2FF825EB19D3CAFF003ED08E /* ASNUtils.h in Headers */, + 2FF8264619D3CAFF003ED08E /* NSData+KeyDerivation.h in Headers */, + 2FA1801719D3D32300F3D844 /* ui.h in Headers */, + 2FA17FF019D3D32300F3D844 /* hmac.h in Headers */, + 2FA17FFB19D3D32300F3D844 /* ocsp.h in Headers */, + 2FF8264819D3CAFF003ED08E /* NSData+SHA.h in Headers */, + 2FA17FD919D3D32300F3D844 /* buffer.h in Headers */, + 2FA1801C19D3D32300F3D844 /* x509v3.h in Headers */, + 2FA17FEB19D3D32300F3D844 /* ecdh.h in Headers */, + 2FA17FDE19D3D32300F3D844 /* comp.h in Headers */, + 2FA17FEE19D3D32300F3D844 /* err.h in Headers */, + 2FA17FEC19D3D32300F3D844 /* ecdsa.h in Headers */, + 2FA1800F19D3D32300F3D844 /* ssl2.h in Headers */, + 2FA1800119D3D32300F3D844 /* pkcs12.h in Headers */, + 2FA1800519D3D32300F3D844 /* rc2.h in Headers */, + 2FA17FE119D3D32300F3D844 /* crypto.h in Headers */, + 2FA17FD719D3D32300F3D844 /* blowfish.h in Headers */, + 2FA1801119D3D32300F3D844 /* ssl3.h in Headers */, + 2FA1801219D3D32300F3D844 /* stack.h in Headers */, + 2FA17FF719D3D32300F3D844 /* mdc2.h in Headers */, + 2FA17FFA19D3D32300F3D844 /* objects.h in Headers */, + 2FA17FE819D3D32300F3D844 /* e_os2.h in Headers */, + 2FA17FE419D3D32300F3D844 /* dh.h in Headers */, + 2FA17FDD19D3D32300F3D844 /* cms.h in Headers */, + 2FA1800E19D3D32300F3D844 /* ssl.h in Headers */, + 2FA17FF919D3D32300F3D844 /* obj_mac.h in Headers */, + 2FA17FF519D3D32300F3D844 /* md4.h in Headers */, + 2FA17FF619D3D32300F3D844 /* md5.h in Headers */, + 2FA17FF819D3D32300F3D844 /* modes.h in Headers */, + 2FA17FE919D3D32300F3D844 /* ebcdic.h in Headers */, + 2FA1800719D3D32300F3D844 /* ripemd.h in Headers */, + 2FA17FF419D3D32300F3D844 /* lhash.h in Headers */, + 2FA17FF119D3D32300F3D844 /* idea.h in Headers */, + 2FA1800619D3D32300F3D844 /* rc4.h in Headers */, + 2FA1800A19D3D32300F3D844 /* seed.h in Headers */, + 2FA1800D19D3D32300F3D844 /* srtp.h in Headers */, + 2FA1800819D3D32300F3D844 /* rsa.h in Headers */, + 2FA1800919D3D32300F3D844 /* safestack.h in Headers */, + 2FA17FD519D3D32300F3D844 /* asn1t.h in Headers */, + 2FA17FDC19D3D32300F3D844 /* cmac.h in Headers */, + 2FA17FFF19D3D32300F3D844 /* pem.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 28F951FA19D0F9FA00DCE892 /* FxA */ = { + isa = PBXNativeTarget; + buildConfigurationList = 28F9520E19D0F9FB00DCE892 /* Build configuration list for PBXNativeTarget "FxA" */; + buildPhases = ( + 28F951F619D0F9FA00DCE892 /* Sources */, + 28F951F719D0F9FA00DCE892 /* Frameworks */, + 28F951F819D0F9FA00DCE892 /* Headers */, + 28F951F919D0F9FA00DCE892 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = FxA; + productName = FxA; + productReference = 28F951FB19D0F9FA00DCE892 /* FxA.framework */; + productType = "com.apple.product-type.framework"; + }; + 28F9520519D0F9FB00DCE892 /* FxATests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 28F9521119D0F9FB00DCE892 /* Build configuration list for PBXNativeTarget "FxATests" */; + buildPhases = ( + 28F9520219D0F9FB00DCE892 /* Sources */, + 28F9520319D0F9FB00DCE892 /* Frameworks */, + 28F9520419D0F9FB00DCE892 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 28F9521919D0FCA000DCE892 /* PBXTargetDependency */, + ); + name = FxATests; + productName = FxATests; + productReference = 28F9520619D0F9FB00DCE892 /* FxATests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 28F951F219D0F9FA00DCE892 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftMigration = 0700; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = Mozilla; + TargetAttributes = { + 28F951FA19D0F9FA00DCE892 = { + CreatedOnToolsVersion = 6.0.1; + LastSwiftMigration = 0820; + ProvisioningStyle = Manual; + }; + 28F9520519D0F9FB00DCE892 = { + CreatedOnToolsVersion = 6.0.1; + LastSwiftMigration = 0820; + }; + }; + }; + buildConfigurationList = 28F951F519D0F9FA00DCE892 /* Build configuration list for PBXProject "FxA" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 28F951F119D0F9FA00DCE892; + productRefGroup = 28F951FC19D0F9FA00DCE892 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 28F951FA19D0F9FA00DCE892 /* FxA */, + 28F9520519D0F9FB00DCE892 /* FxATests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 28F951F919D0F9FA00DCE892 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0A80BCD61EC538F500926C6A /* ece in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 28F9520419D0F9FB00DCE892 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 28F951F619D0F9FA00DCE892 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2FF825F219D3CAFF003ED08E /* CHNumber.m in Sources */, + 2FF824E119D3C6D8003ED08E /* KeyPair.m in Sources */, + 2FF8264519D3CAFF003ED08E /* NSData+Base32.m in Sources */, + 2FF824E319D3C6D8003ED08E /* PrivateKey.m in Sources */, + 2FF8264319D3CAFF003ED08E /* NSData+Base16.m in Sources */, + 0A80BCCF1EC538DD00926C6A /* decrypt.c in Sources */, + 2FA1801E19D3D32300F3D844 /* JSONWebTokenUtils.m in Sources */, + 2FF824E719D3C6D8003ED08E /* RSAKeyPair.m in Sources */, + 2FF8264D19D3CAFF003ED08E /* NSString+Utils.m in Sources */, + 0A80BCD21EC538DD00926C6A /* params.c in Sources */, + 0A80BCCE1EC538DD00926C6A /* base64url.c in Sources */, + 2FF825EC19D3CAFF003ED08E /* ASNUtils.m in Sources */, + 2FF8264719D3CAFF003ED08E /* NSData+KeyDerivation.m in Sources */, + 0A80BCD31EC538DD00926C6A /* trailer.c in Sources */, + 2FF8264B19D3CAFF003ED08E /* NSData+Utils.m in Sources */, + 0A80BCD11EC538DD00926C6A /* keys.c in Sources */, + 2FF825EF19D3CAFF003ED08E /* CHMutableNumber.m in Sources */, + 0A80BCD01EC538DD00926C6A /* encrypt.c in Sources */, + 2FF8264919D3CAFF003ED08E /* NSData+SHA.m in Sources */, + 2FF824E519D3C6D8003ED08E /* PublicKey.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 28F9520219D0F9FB00DCE892 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 28F9520B19D0F9FB00DCE892 /* FxATests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 28F9521919D0FCA000DCE892 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 28F951FA19D0F9FA00DCE892 /* FxA */; + targetProxy = 28F9521819D0FCA000DCE892 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 28F9520C19D0F9FB00DCE892 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 28F9520F19D0F9FB00DCE892 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/FxA/include", + "$(PROJECT_DIR)/../ThirdParty/ecec/include", + ); + INFOPLIST_FILE = FxA/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/FxA/lib", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + USER_HEADER_SEARCH_PATHS = ""; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 28F9521219D0F9FB00DCE892 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/FxA/include", + ); + INFOPLIST_FILE = FxATests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/FxA/lib"; + PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + E60222DF1C6E56C10061C436 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + MTL_ENABLE_DEBUG_INFO = NO; + ONLY_ACTIVE_ARCH = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + E60222E01C6E56C10061C436 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/FxA/include", + "$(PROJECT_DIR)/../ThirdParty/ecec/include", + ); + INFOPLIST_FILE = FxA/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/FxA/lib", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.ios.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + USER_HEADER_SEARCH_PATHS = ""; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + E60222E11C6E56C10061C436 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/FxA/include", + ); + INFOPLIST_FILE = FxATests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/FxA/lib"; + PRODUCT_BUNDLE_IDENTIFIER = "org.mozilla.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 28F951F519D0F9FA00DCE892 /* Build configuration list for PBXProject "FxA" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 28F9520C19D0F9FB00DCE892 /* Debug */, + E60222DF1C6E56C10061C436 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 28F9520E19D0F9FB00DCE892 /* Build configuration list for PBXNativeTarget "FxA" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 28F9520F19D0F9FB00DCE892 /* Debug */, + E60222E01C6E56C10061C436 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 28F9521119D0F9FB00DCE892 /* Build configuration list for PBXNativeTarget "FxATests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 28F9521219D0F9FB00DCE892 /* Debug */, + E60222E11C6E56C10061C436 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 28F951F219D0F9FA00DCE892 /* Project object */; +} diff --git a/mobile/ios/FxA/FxA.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mobile/ios/FxA/FxA.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..1685920b2f --- /dev/null +++ b/mobile/ios/FxA/FxA.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/mobile/ios/FxA/FxA.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mobile/ios/FxA/FxA.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..08de0be8d3 --- /dev/null +++ b/mobile/ios/FxA/FxA.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/mobile/ios/FxA/FxA.xcodeproj/xcshareddata/xcschemes/FxA.xcscheme b/mobile/ios/FxA/FxA.xcodeproj/xcshareddata/xcschemes/FxA.xcscheme new file mode 100644 index 0000000000..b29ab3c15d --- /dev/null +++ b/mobile/ios/FxA/FxA.xcodeproj/xcshareddata/xcschemes/FxA.xcscheme @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/ios/FxA/FxA/ASNUtils.h b/mobile/ios/FxA/FxA/ASNUtils.h new file mode 100644 index 0000000000..935043a71a --- /dev/null +++ b/mobile/ios/FxA/FxA/ASNUtils.h @@ -0,0 +1,17 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + + +#import + + +@interface ASNUtils : NSObject + ++ (NSData*) encodeSequenceOfNumbers: (NSArray*) numbers; ++ (NSArray*) decodeSequenceOfNumbers: (NSData*) sequence; + ++ (NSData*) decodeDSASignature: (NSData*) signature; ++ (NSData*) encodeDSASignature: (NSData*) flattenedSignature; + +@end diff --git a/mobile/ios/FxA/FxA/ASNUtils.m b/mobile/ios/FxA/FxA/ASNUtils.m new file mode 100644 index 0000000000..48e738ea15 --- /dev/null +++ b/mobile/ios/FxA/FxA/ASNUtils.m @@ -0,0 +1,121 @@ +// 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 "NSData+Utils.h" +#include "CHNumber.h" +#import "ASNUtils.h" + + +@implementation ASNUtils + +// +// 0x30 +// 4 + l1 + l2 +// +// 0x02 +// l1 +// d1 +// +// 0x02 +// l2 +// d2 +// + ++ (NSData*) encodeSequenceOfNumbers: (NSArray*) numbers +{ + NSUInteger totalLength = 0; + for (CHNumber *number in numbers) { + totalLength += 2 + [[number dataValue] length]; + } + + NSMutableData *encoded = [NSMutableData data]; + unsigned char header[2]; + header[0] = 0x30; // SEQUENCE + header[1] = totalLength; + [encoded appendBytes: header length: sizeof header]; + + for (CHNumber *number in numbers) { + NSData *data = [number dataValue]; + unsigned char itemHeader[2]; + itemHeader[0] = 0x02; // NUMBER + itemHeader[1] = [data length]; + [encoded appendBytes: itemHeader length: sizeof itemHeader]; + [encoded appendData: data]; + } + + return encoded; +} + ++ (NSArray*) decodeSequenceOfNumbers: (NSData*) sequence +{ + unsigned char *p = (unsigned char*) [sequence bytes]; + unsigned char *q = p + [sequence length]; + + // TODO: These checks must be way more strict + + if (p[0] != 0x30) { + return nil; + } + + if (p[1] != ([sequence length] - 2)) { + return nil; + } + + p += 2; + + NSMutableArray *numbers = [NSMutableArray new]; + + while (p < q) + { + if (p[0] != 0x02) { + return nil; + } + + NSUInteger numberLength = p[1]; + p += 2; + + NSData *data = [NSData dataWithBytes: p length: numberLength]; + p += numberLength; + + CHNumber *number = [CHNumber numberWithData: data]; + [numbers addObject: number]; + } + + return [NSArray arrayWithArray:numbers]; +} + ++ (NSData*) decodeDSASignature: (NSData*) signature +{ + if (signature == nil || [signature length] == 0) { + return nil; + } + + NSArray *numbers = [ASNUtils decodeSequenceOfNumbers: signature]; + if (numbers == nil || [numbers count] != 2) { + return nil; + } + + return [NSData dataByAppendingDatas: @[ + [[numbers[0] dataValue] dataLeftZeroPaddedToLength: 20], + [[numbers[1] dataValue] dataLeftZeroPaddedToLength: 20], + ]]; +} + ++ (NSData*) encodeDSASignature: (NSData*) flattenedSignature +{ + if (flattenedSignature == nil || [flattenedSignature length] == 0) { + return nil; + } + + NSArray *numbers = @[ + [CHNumber numberWithData: [flattenedSignature subdataWithRange: NSMakeRange(0, [flattenedSignature length]/2)]], + [CHNumber numberWithData: [flattenedSignature subdataWithRange: NSMakeRange([flattenedSignature length]/2, [flattenedSignature length]/2)]] + ]; + + NSData *transformedSignature = [ASNUtils encodeSequenceOfNumbers: numbers]; + return transformedSignature; +} + +@end diff --git a/mobile/ios/FxA/FxA/CHMath.h b/mobile/ios/FxA/FxA/CHMath.h new file mode 100644 index 0000000000..5d33e1fdf2 --- /dev/null +++ b/mobile/ios/FxA/FxA/CHMath.h @@ -0,0 +1,25 @@ +// +// CHMath.h +// CHMath +// +// Created by Dave DeLong on 9/28/09. +// Copyright 2009 Home. All rights reserved. +// + +#import +#import "CHNumber.h" +#import "CHMutableNumber.h" +#import "CHUtils.h" + +/** + @file CHMath.h + + An umbrella header which imports all the public header files for the framework. Headers for individual classes have minimal dependencies, and they import any other header files they may require. + */ + +/** + @mainpage Overview + + CHMath.framework is an open source wrapper around OpenSSL's BigNumber functions. These functions provide support for arbitrarily long integer manipulation. + + */ \ No newline at end of file diff --git a/mobile/ios/FxA/FxA/CHMutableNumber.h b/mobile/ios/FxA/FxA/CHMutableNumber.h new file mode 100644 index 0000000000..a79db1274a --- /dev/null +++ b/mobile/ios/FxA/FxA/CHMutableNumber.h @@ -0,0 +1,227 @@ +// +// CHMutableNumber.h +// CHMath +// +// Created by Dave DeLong on 9/28/09. +// Copyright 2009 Home. All rights reserved. +// + +#import "CHNumber.h" + +/** + @file CHMutableNumber.h + An arbitrarily long number that can be directly manipulated + */ + +@class CHMutableNumber; + +@interface CHNumber (CHMutableAdditions) + +- (CHMutableNumber *) mutableCopyWithZone:(NSZone *)zone; + +@end + +/** + A mutable subclass of CHNumber. It allows users to directly manipulate the wrapped BIGNUM. + */ +@interface CHMutableNumber : CHNumber { + +} + +#pragma mark Behavior + +/** + Changes the value of the receiver + @param newValue the new integer value of the receiver + */ +- (void)setIntegerValue:(int)newValue; + +/** + Changes the value of the receiver + @note if @a newValue contains invalid characters, this method does nothing + @param newValue the new string value of the receiver + */ +- (void)setStringValue:(NSString *)newValue; + +/** + Changes the value of the receiver + @note if @a newValue contains invalid characters, this method does nothing + @param newValue the new hexadecimal string value of the receiver + */ +- (void)setHexStringValue:(NSString *)newValue; + +/** + Clears the value of the receiver and sets it to 0. + */ +- (void)clear; + +#pragma mark Mathematical Operations + +/** + Performs a modular divison on the receiver. + @param mod the NSInteger by which to divide. + */ +- (void)modByInteger:(int)mod; + +/** + Performs a modular division on the receiver. + @param mod the CHNumber by which to divide. + */ +- (void)modByNumber:(CHNumber *)mod; + +/** + Adds @a addend to the receiver + @param addend the NSInteger to add + */ +- (void)addInteger:(int)addend; + +/** + Adds @a addend to the receiver + @param addend the CHNumber to add + */ +- (void)addNumber:(CHNumber *)addend; + +/** + Adds @a addend to the receiver and then divides modulo @a mod + @param addend the CHNumber to add + @param mod the CHNumber by which to divide + */ +- (void)addNumber:(CHNumber *)addend mod:(CHNumber *)mod; + +/** + Subtracts @a subtrahend from the receiver + @param subtrahend the NSInteger to subtract + */ +- (void)subtractInteger:(int)subtrahend; + +/** + Subtracts @a subtrahend from the receiver + @param subtrahend the CHNumber to subtract + */ +- (void)subtractNumber:(CHNumber *)subtrahend; + +/** + Subtracts @a subtrahend from the receiver and then divides modulo @a mod + @param subtrahend the CHNumber to subtract + @param mod the CHNumber by which to divide + */ +- (void)subtractNumber:(CHNumber *)subtrahend mod:(CHNumber *)mod; + + +/** + Multiplies the receiver by @a multiplicand + @param multiplicand the NSInteger by which to multiply + */ +- (void)multiplyByInteger:(int)multiplicand; + +/** + Multiplies the receiver by @a multiplicand + @param multiplicand the CHNumber by which to multiply + */ +- (void)multiplyByNumber:(CHNumber *)multiplicand; + +/** + Multiplies the receiver by @a multiplicand and then divides modulo @a mod + @param multiplicand the CHNumber by which to multiply + @param mod the CHNumber by which to divide + */ +- (void)multiplyByNumber:(CHNumber *)multiplicand mod:(CHNumber *)mod; + +/** + Divides the receiver by @a divisor + @param divisor the NSInteger by which to divide + */ +- (void)divideByInteger:(int)divisor; + +/** + Divides the receiver by @a divisor + @param divisor the CHNumber by which to divide + */ +- (void)divideByNumber:(CHNumber *)divisor; + +/** + Raises the receiver to the @a exponent power + @param exponent the NSInteger by which to raise + */ +- (void)raiseToInteger:(int)exponent; + +/** + Raises the receiver to the @a exponent power + @param exponent the CHNumber by which to raise + */ +- (void)raiseToNumber:(CHNumber *)exponent; + +/** + Raises the receiver to the @a exponent power and then divides modulo @a mod + @param exponent the CHNumber by which to raise + @param mod the CHNumber by which to divide + */ +- (void)raiseToNumber:(CHNumber *)exponent mod:(CHNumber *)mod; + +/** + Squares the receiver + */ +- (void)square; + +/** + Squares the receiver and then divides modulo @a mod + @param mod the CHNumber by which to divide + */ +- (void)squareMod:(CHNumber *)mod; + +#pragma mark Bitfield Operations + +/** + Negates the receiver + */ +- (void)negate; + +/** + Sets the @a bit bit of the receiver to 1 + @note the least significant bit is in position 0 + @param bit the bit to set. + */ +- (void)setBit:(int)bit; + +/** + Sets the @a bit bit of the receiver to 0 + @note the least significant bit is in position 0 + @param bit the bit to clear. + */ +- (void)clearBit:(int)bit; + +/** + Sets the @a bit bit of the receiver to its NOT. In other words, if the bit is 1, it will be flipped to 0. If it is 0, it will be flipped to 1. + @note the least significant bit is in position 0 + @param bit the bit to flip. + */ +- (void)flipBit:(int)bit; + +/** + Perform a single left shift + */ +- (void)shiftLeftOnce; + +/** + Perform a left shift + @param leftShift the number of bits to shift the receiver left + */ +- (void)shiftLeft:(int)leftShift; + +/** + Perform a single right shift + */ +- (void)shiftRightOnce; + +/** + Perform a right shift + @param rightShift the number of bits to shift the receiver right + */ +- (void)shiftRight:(int)rightShift; + +/** + Truncates the receiver to be @a mask bits long + */ +- (void)maskWithInt:(int)mask; + +@end diff --git a/mobile/ios/FxA/FxA/CHMutableNumber.m b/mobile/ios/FxA/FxA/CHMutableNumber.m new file mode 100644 index 0000000000..8468b09c73 --- /dev/null +++ b/mobile/ios/FxA/FxA/CHMutableNumber.m @@ -0,0 +1,197 @@ +/* + CHMath.framework -- CHMutableNumber.m + + Copyright (c) 2008-2009, Dave DeLong + + Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + + The software is provided "as is", without warranty of any kind, including all implied warranties of merchantability and fitness. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software. + */ + + +#import "CHMutableNumber.h" +#import "CHNumber_Private.h" + +@implementation CHNumber (CHMutableAdditions) + +- (CHMutableNumber *) mutableCopyWithZone:(NSZone *)zone { + return [[CHMutableNumber alloc] initWithString:[self stringValue]]; +} + +@end + +@implementation CHMutableNumber + +- (void) setIntegerValue:(int)newValue { + if (newValue < 0) { + newValue *= -1; + //set the initial value to the positive value + BN_set_word([self bigNumber], newValue); + [self negate]; + } else { + BN_set_word([self bigNumber], newValue); + } +} + +- (void)setStringValue:(NSString *)newValue { + NSCharacterSet * decSet = [NSCharacterSet characterSetWithCharactersInString:@"-0123456789"]; + NSRange nonDecChar = [newValue rangeOfCharacterFromSet:[decSet invertedSet]]; + if (nonDecChar.location != NSNotFound) { return; } + BN_dec2bn(&bigNumber, [newValue cStringUsingEncoding:NSASCIIStringEncoding]); +} + +- (void)setHexStringValue:(NSString *)newValue { + NSCharacterSet * hexSet = [NSCharacterSet characterSetWithCharactersInString:@"-0123456789abcdefABCDEF"]; + NSRange nonHexChar = [newValue rangeOfCharacterFromSet:[hexSet invertedSet]]; + if (nonHexChar.location != NSNotFound) { return; } + BN_hex2bn(&bigNumber, [newValue cStringUsingEncoding:NSASCIIStringEncoding]); +} + +- (void)clear { + BN_clear([self bigNumber]); +} + +- (void)modByInteger:(int)mod { + if (mod != 0) { + if (mod < 0) { mod *= -1; } + int result = BN_mod_word([self bigNumber], mod); + [self setIntegerValue:result]; + } +} + +- (void)modByNumber:(CHNumber *)mod { + if ([mod isZero] == NO) { + BN_mod([self bigNumber], [self bigNumber], [mod bigNumber], context); + } +} + +- (void)addInteger:(int)addend { + if (addend > 0) { + BN_add_word([self bigNumber], addend); + } else { + addend *= -1; + [self subtractInteger:addend]; + } +} + +- (void)addNumber:(CHNumber *)addend { + BN_add([self bigNumber], [self bigNumber], [addend bigNumber]); +} + +- (void)addNumber:(CHNumber *)addend mod:(CHNumber *)mod { + BN_mod_add([self bigNumber], [self bigNumber], [addend bigNumber], [mod bigNumber], context); +} + +- (void)subtractInteger:(int)subtrahend { + if (subtrahend > 0) { + BN_sub_word([self bigNumber], subtrahend); + } else { + subtrahend *= -1; + [self addInteger:subtrahend]; + } +} + +- (void)subtractNumber:(CHNumber *)subtrahend { + BN_sub([self bigNumber], [self bigNumber], [subtrahend bigNumber]); +} + +- (void)subtractNumber:(CHNumber *)subtrahend mod:(CHNumber *)mod { + BN_mod_sub([self bigNumber], [self bigNumber], [subtrahend bigNumber], [mod bigNumber], context); +} + +- (void)multiplyByInteger:(int)multiplicand { + if (multiplicand > 0) { + BN_mul_word([self bigNumber], multiplicand); + } else { + multiplicand *= -1; + BN_mul_word([self bigNumber], multiplicand); + [self negate]; + } +} + +- (void)multiplyByNumber:(CHNumber *)multiplicand { + BN_mul([self bigNumber], [self bigNumber], [multiplicand bigNumber], context); +} + +- (void)multiplyByNumber:(CHNumber *)multiplicand mod:(CHNumber *)mod { + BN_mod_mul([self bigNumber], [self bigNumber], [multiplicand bigNumber], [mod bigNumber], context); +} + +- (void)divideByInteger:(int)divisor { + if (divisor == 0) { return; } + if (divisor > 0) { + BN_div_word([self bigNumber], divisor); + } else { + divisor *= -1; + BN_div_word([self bigNumber], divisor); + [self negate]; + } +} + +- (void)divideByNumber:(CHNumber *)divisor { + if ([divisor isZero]) { return; } + BN_div([self bigNumber], NULL, [self bigNumber], [divisor bigNumber], context); +} + +- (void)raiseToInteger:(int)exponent { + CHNumber * exp = [CHNumber numberWithInt:exponent]; + [self raiseToNumber:exp]; +} + +- (void)raiseToNumber:(CHNumber *)exponent { + BN_exp([self bigNumber], [self bigNumber], [exponent bigNumber], context); +} + +- (void)raiseToNumber:(CHNumber *)exponent mod:(CHNumber *)mod { + BN_mod_exp([self bigNumber], [self bigNumber], [exponent bigNumber], [mod bigNumber], context); +} + +- (void)square { + BN_sqr([self bigNumber], [self bigNumber], context); +} + +- (void)squareMod:(CHNumber *)mod { + BN_mod_sqr([self bigNumber], [self bigNumber], [mod bigNumber], context); +} + +- (void)negate { + BN_set_negative([self bigNumber], ![self isNegative]); +} + +- (void)setBit:(int)bit { + BN_set_bit([self bigNumber], bit); +} + +- (void)clearBit:(int)bit { + BN_clear_bit([self bigNumber], bit); +} + +- (void)flipBit:(int)bit { + if ([self isBitSet:bit]) { + [self clearBit:bit]; + } else { + [self setBit:bit]; + } +} + +- (void)shiftLeftOnce { + BN_lshift1([self bigNumber], [self bigNumber]); +} + +- (void)shiftLeft:(int)leftShift { + BN_lshift([self bigNumber], [self bigNumber], leftShift); +} + +- (void)shiftRightOnce { + BN_rshift1([self bigNumber], [self bigNumber]); +} + +- (void)shiftRight:(int)rightShift { + BN_rshift([self bigNumber], [self bigNumber], rightShift); +} + +- (void)maskWithInt:(int)mask { + BN_mask_bits([self bigNumber], mask); +} + +@end diff --git a/mobile/ios/FxA/FxA/CHNumber.h b/mobile/ios/FxA/FxA/CHNumber.h new file mode 100644 index 0000000000..4a2e3af769 --- /dev/null +++ b/mobile/ios/FxA/FxA/CHNumber.h @@ -0,0 +1,403 @@ +// +// CHNumber.h +// CHMath +// +// Created by Dave DeLong on 9/28/09. +// Copyright 2009 Home. All rights reserved. +// + +#import +#import "openssl/bn.h" + +/** + @file CHNumber.h + A arbitrarily long integer + */ + +/** + CHNumber is a wrapper that represents an arbitrarily long integer. It provides methods for adding, subtracting, dividing, and multiplying with other CHNumbers. + + CHNumber wraps the BIGNUM type of the OpenSSL library. + */ +@interface CHNumber : NSObject { + BIGNUM *bigNumber; + BN_CTX *context; +} + +#pragma mark Convenience Methods + +/** + Determines if an NSInteger is prime or not. + @param integer the integer to test for primality + @return @c YES if the parameter is a prime number. + */ ++ (BOOL) isIntegerPrime:(int)integer; + +#pragma mark Initializers + +/** + Creates an autoreleased CHNumber initialized to 0. + @return a new CHNumber, or @a nil if an error occurs + */ ++ (id)number; + +/** + Creates an autoreleased CHNumber initialized to @a integer. + @param integer the integer value of the new number + @return a new CHNumber, or @a nil if an error occurs + */ ++ (id)numberWithInt:(int)integer; + +/** + Creates an autoreleased CHNumber initialized to @a integer. + @param integer the unsigned integer value of the new number + @return a new CHNumber, or @a nil if an error occurs + */ ++ (id)numberWithUnsignedInt:(unsigned int)integer; + +/** + Creates an autoreleased CHNumber initialized to the value represented by @a string. + @param string an NSString of decimal characters (0 - 9) + @return a new CHNumber, or @a nil if a number cannot be extracted from @a string + */ ++ (id)numberWithString:(NSString *)string; + +/** + Creates an autoreleased CHNumber initialized to the value represented by @a string + @param string an NSString of hexadecimal characters (0 - 9, A - F) + @return a new CHNumber, or @a nil if a number cannot be extracted from @a string + */ ++ (id)numberWithHexString:(NSString *)string; + ++ (id)numberWithData:(NSData *)data; + ++ (id) numberWithOpenSSLNumber: (BIGNUM*) bn; + +/** + Creates an autoreleased CHNumber initialized to the value of @a number + @param number an NSNumber that represents an integer value + @return a new CHNumber, or @a nil if an integer cannot be extracted from @a number. + */ ++ (id)numberWithNumber:(NSNumber *)number; + + +/** + Creates a new CHNumber initialized to @a integer. + @param integer the integer value of the new number + @return a new CHNumber, or @a nil if an error occurs + */ +- (id)initWithInt:(int)integer; + +/** + Creates a new CHNumber initialized to @a integer. + @param integer the unsigned integer value of the new number + @return a new CHNumber, or @a nil if an error occurs + */ +- (id)initWithUnsignedInt:(unsigned int)integer; + +/** + Creates a new CHNumber initialized to the value represented by @a string. + @param string an NSString of decimal characters (0 - 9) + @return a new CHNumber, or @a nil if a number cannot be extracted from @a string + */ +- (id)initWithString:(NSString *)string; + +/** + Creates a new CHNumber initialized to the value represented by @a string + @param string an NSString of hexadecimal characters (0 - 9, A - F) + @return a new CHNumber, or @a nil if a number cannot be extracted from @a string + */ +- (id)initWithHexString:(NSString *)string; + +/** + Created a new CHNumber initialized of the value represented by @a data. + @param data an NSData instance + @return a new CHNumber, or @a nil if a number cannot be extraced from @a data + */ +- (id)initWithData:(NSData*)data; + +- (id)initWithOpenSSLNumber:(BIGNUM*)bn; + +/** + Creates a new CHNumber initialized to the value of @a number + @param number an NSNumber that represents an integer value + @return a new CHNumber, or @a nil if an integer cannot be extracted from @a number. + */ +- (id)initWithNumber:(NSNumber *)number; + +#pragma mark Behavior + +/** + Creates a two's complement binary representation of the integer as an NSString + @return an NSString + */ +- (NSString *)binaryStringValue; + +/** + Creates a hexadecimal representation of the integer as an NSString + @return an NSString + */ +- (NSString *)hexStringValue; + +- (NSData *)dataValue; + +/** + Creates a decimal representation of the integer as an NSString + @return an NSString + */ +- (NSString *)stringValue; + +/** + Returns the receiver's value as an NSInteger + @note if the receiver's integer value is too large to be expressed in a single NSInteger, this method returns 0xFFFFFFFFFFFFFFFF. + @return an NSInteger + */ +- (NSInteger)integerValue; + +/** + Returns the receiver's value as an NSUInteger + @note if the receiver's integer value is too large to be expressed in a single NSUInteger, this method returns 0xFFFFFFFFFFFFFFFF. + @return an NSUInteger + */ +- (NSUInteger)unsignedIntegerValue; + +- (BIGNUM*) bigNumValue; + +/** + Returns the receiver's prime factors + @note depending on the size of the receiver, this method may take a very long time to return + @return an NSArray of CHNumbers. + */ +- (NSArray *)factors; + +#pragma mark Comparisons + +/** + Returns a boolean indicating whether the receiver is equal to 0. + @return @c YES if the receiver is equal to 0, @c NO otherwise. + */ +- (BOOL)isZero; + +/** + Returns a boolean indicating whether the receiver is equal to 1. + @return @c YES if the receiver is equal to 1, @c NO otherwise. + */ +- (BOOL)isOne; + +/** + Returns a boolean indicating whether the receiver is less than 0. + @return @c YES if the receiver is less than 0, @c NO otherwise. + */ +- (BOOL)isNegative; + +/** + Returns a boolean indicating whether the receiver is greater than or equal to 0. + @return @c YES if the receiver is greater than or equal to 0, @c NO otherwise. + */ +- (BOOL)isPositive; + +/** + Returns a boolean indicating whether the receiver is a prime number. + @return @c YES if the receiver is a prime number. + */ +- (BOOL)isPrime; + +/** + Returns a boolean indicating whether the receiver is an odd number. + @return @c YES if the receiver is odd, @c NO otherwise. + */ +- (BOOL)isOdd; + +/** + Returns a boolean indicating whether the receiver is an even number. + @return @c YES if the receiver is even, @c NO otherwise. + */ +- (BOOL)isEven; + +/** + Returns a boolean indicating whether the receiver is greather than @a number. This method uses the BN_cmp to do its comparison. + @param number another CHNumber + @return @c YES if the receiver is greater than @a number, @c NO otherwise. + */ +- (BOOL)isGreaterThanNumber:(CHNumber *)number; + +/** + Returns a boolean indicating whether the receiver is greather than or equal to @a number. This method uses the BN_cmp to do its comparison. + @param number another CHNumber + @return @c YES if the receiver is greater than or equal to @a number, @c NO otherwise. + */ +- (BOOL)isGreaterThanOrEqualToNumber:(CHNumber *)number; + +/** + Returns a boolean indicating whether the receiver is equal to @a number. This method uses the BN_cmp to do its comparison. + @param number another CHNumber + @return @c YES if the receiver is equal to @a number, @c NO otherwise. + */ +- (BOOL)isEqualToNumber:(CHNumber *)number; + +/** + Returns a boolean indicating whether the receiver is less than @a number. This method uses the BN_cmp to do its comparison. + @param number another CHNumber + @return @c YES if the receiver is less than @a number, @c NO otherwise. + */ +- (BOOL)isLessThanNumber:(CHNumber *)number; + +/** + Returns a boolean indicating whether the receiver is less than or equal to @a number. This method uses the BN_cmp to do its comparison. + @param number another CHNumber + @return @c YES if the receiver is less than or equal to @a number, @c NO otherwise. + */ +- (BOOL)isLessThanOrEqualToNumber:(CHNumber *)number; + +/** + Returns an NSComparisonResult indicating how the receiver compares to @a object. This method uses the BN_cmp to do its comparison. + @param object a non-nil object + @return NSOrderedAscending if the value of @a object is greater than the receiver’s, NSOrderedSame if they’re equal, and NSOrderedDescending if the value of @a object is less than the receiver’s. + */ +- (NSComparisonResult)compare:(id)object; + +#pragma mark Mathematical Operations + +/** + Perform a modular division. Returns a number n such that @c (receiver = k * mod + n). + @param mod the number by which to divide + @return a CHNumber + */ +- (CHNumber *)numberByModding:(CHNumber *)mod; + +/** + Perform an inverse modular division. Returns a number r such that @c ((receiver * r) % mod == 1). + @param mod a non-nil CHNumber + @return a CHNumber + */ +- (CHNumber *)numberByInverseModding:(CHNumber *)mod; + +/** + Perform addition. + @param addend the number to add to the receiver + @return a new CHNumber + */ +- (CHNumber *)numberByAdding:(CHNumber *)addend; + +/** + Perform modulo addition. + @param addend the number to add to the receiver + @param mod the number to divide by + @return a new CHNumber @a r such that @c (r = (receiver + addend) % mod) + */ +- (CHNumber *)numberByAdding:(CHNumber *)addend mod:(CHNumber *)mod; + +/** + Perform subtraction. + @param subtrahend the number to subtract from the receiver + @return a new CHNumber + */ +- (CHNumber *)numberBySubtracting:(CHNumber *)subtrahend; + +/** + Perform modulo subtraction. + @param subtrahend the number to subtract from the receiver + @param mod the number to divide by + @return a new CHNumber @a r such that @c (r = (receiver - subtrahend) % mod) + */ +- (CHNumber *)numberBySubtracting:(CHNumber *)subtrahend mod:(CHNumber *)mod; + +/** + Perform multiplication. + @param multiplicand the number by which to multiply the receiver + @return a new CHNumber + */ +- (CHNumber *)numberByMultiplyingBy:(CHNumber *)multiplicand; + +/** + Perform modulo multiplication. + @param multiplicand the number by which to multiply the receiver + @param mod the number to divide by + @return a new CHNumber @a r such that @c (r = (receiver * multiplicand) % mod) + */ +- (CHNumber *)numberByMultiplyingBy:(CHNumber *)multiplicand mod:(CHNumber *)mod; + +/** + Perform division. + @param divisor the number by which to divide the receiver + @return a new CHNumber + */ +- (CHNumber *)numberByDividingBy:(CHNumber *)divisor; + +/** + Square the receiver. + @return a new CHNumber @a r such that @c (r = receiver * receiver) + */ +- (CHNumber *)squaredNumber; + +/** + Modulo square the receiver. + @param mod the number to divide by + @return a new CHNumber @a r such that @c (r = (receiver * receiver) % mod) + */ +- (CHNumber *)squaredNumberMod:(CHNumber *)mod; + +/** + Raise the receiver to a power. + @param exponent the power by which to raise the receiver + @return a new CHNumber @a r such that @c (r = receiver ^ exponent) + */ +- (CHNumber *)numberByRaisingToPower:(CHNumber *)exponent; + +/** + Modulo raise the receiver to a power. + @param exponent the power by which to raise the receiver + @param mod the number to divide by + @return a new CHNumber @a r such that @c (r = (receiver ^ exponent) % mod) + */ +- (CHNumber *)numberByRaisingToPower:(CHNumber *)exponent mod:(CHNumber *)mod; + +/** + Negate the receiver. + @return a new CHNumber @a r such that @c (r = receiver * -1) + */ +- (CHNumber *)negatedNumber; + +#pragma mark Bitfield Operations + +/** + Determine if a bit is set. + @note the least significant bit of the receiver is the zeroth (0) bit + @param bit an NSUInteger + @return @c YES if the bit is set, @c NO otherwise. + */ +- (BOOL)isBitSet:(int)bit; + +/** + Perform a single left shift + @return a new CHNumber @a r such that @c (r = receiver << 1) + */ +- (CHNumber *)numberByShiftingLeftOnce; + +/** + Perform a left shift + @param leftShift the number of bits to shift left + @return a new CHNumber @a r such that @c (r = receiver << leftShift) + */ +- (CHNumber *)numberByShiftingLeft:(int)leftShift; + +/** + Perform a single right shift + @return a new CHNumber @a r such that @c (r = receiver >> 1) + */ +- (CHNumber *)numberByShiftingRightOnce; + +/** + Perform a right shift + @param rightShift the number of bits to shift right + @return a new CHNumber @a r such that @c (r = receiver >> rightShift) + */ +- (CHNumber *)numberByShiftingRight:(int)rightShift; + +/** + Truncates the receiver to be @a mask bits long + @return a new CHNumber @a r such that @c (r = receiver && (2^(mask+1))-1) + */ +- (CHNumber *)numberByMaskingWithInt:(int)mask; + +@end diff --git a/mobile/ios/FxA/FxA/CHNumber.m b/mobile/ios/FxA/FxA/CHNumber.m new file mode 100644 index 0000000000..e54a328522 --- /dev/null +++ b/mobile/ios/FxA/FxA/CHNumber.m @@ -0,0 +1,456 @@ +/* + CHMath.framework -- CHNumber.m + + Copyright (c) 2008-2009, Dave DeLong + + Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + + The software is provided "as is", without warranty of any kind, including all implied warranties of merchantability and fitness. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software. + */ + + +#import "CHNumber.h" +#import "CHNumber_Private.h" + +#define CH_ASCII_ZERO 48 + +@interface CHNumber () + +@property (readonly) BIGNUM * bigNumber; + +@end + + +@implementation CHNumber + +@synthesize bigNumber; + ++ (BOOL) isIntegerPrime:(int)integer { + CHNumber * num = [[CHNumber alloc] initWithInt:integer]; + return [num isPrime]; +} + ++ (id)numberWithInt:(int)integer { + //in class methods, self always refers to the Class object + return [[self alloc] initWithInt:integer]; +} + ++ (id)numberWithUnsignedInt:(unsigned int)integer { + return [[self alloc] initWithUnsignedInt:integer]; +} + ++ (id)numberWithString:(NSString *)string { + return [[self alloc] initWithString:string]; +} + ++ (id)numberWithHexString:(NSString *)string { + return [[self alloc] initWithHexString:string]; +} + ++ (id)numberWithData:(NSData *)data +{ + return [[self alloc] initWithData: data]; +} + ++ (id) numberWithOpenSSLNumber: (BIGNUM*) bn +{ + return [[self alloc] initWithOpenSSLNumber: bn]; +} + ++ (id)numberWithNumber:(NSNumber *)number { + return [[self alloc] initWithNumber:number]; +} + ++ (id)number { + return [[self alloc] initWithInt:0]; +} + +- (id) init { + if (self = [super init]) { + bigNumber = BN_new(); + if (bigNumber == NULL) { + //[self release]; + return nil; + } + BN_zero(bigNumber); + context = BN_CTX_new(); + if(context == NULL) { + BN_free(bigNumber); + //[self release]; + return nil; + } + } + return self; +} + +- (id)initWithInt:(int)integer { + if(self = [self init]) { + if (integer < 0) { + integer *= -1; + //set the initial value to the positive value + BN_set_word([self bigNumber], integer); + //subtract the value twice to get the negative value + BN_sub_word([self bigNumber], integer); + BN_sub_word([self bigNumber], integer); + } else { + BN_set_word([self bigNumber], integer); + } + } + return self; +} + +- (id)initWithUnsignedInt:(unsigned int)integer { + if (self = [self init]) { + BN_set_word(bigNumber, integer); + } + return self; +} + +- (id)initWithString:(NSString *)string { + NSCharacterSet * decSet = [NSCharacterSet characterSetWithCharactersInString:@"-0123456789"]; + NSRange nonDecChar = [string rangeOfCharacterFromSet:[decSet invertedSet]]; + if (nonDecChar.location != NSNotFound) { return nil; } + if (self = [self init]) { + BN_dec2bn(&bigNumber, [string cStringUsingEncoding:NSASCIIStringEncoding]); + } + return self; +} + +- (id)initWithHexString:(NSString *)string { + NSCharacterSet * hexSet = [NSCharacterSet characterSetWithCharactersInString:@"-0123456789abcdefABCDEF"]; + NSRange nonHexChar = [string rangeOfCharacterFromSet:[hexSet invertedSet]]; + if (nonHexChar.location != NSNotFound) { return nil; } + if (self = [self init]) { + BN_hex2bn(&bigNumber, [string cStringUsingEncoding:NSASCIIStringEncoding]); + } + return self; +} + +- (id)initWithData:(NSData*)data +{ + if (self = [self init]) { + if (data == nil) { + return nil; + } + if ([data length] == 0) { + return nil; + } + (void) BN_bin2bn([data bytes], (int) [data length], bigNumber); + } + return self; +} + +- (id)initWithOpenSSLNumber:(BIGNUM*)bn +{ + if ((self = [self init]) != nil) { + BN_copy(bigNumber, bn); + } + return self; +} + +- (id)initWithNumber:(NSNumber *)number { + return [self initWithString:[number descriptionWithLocale:[NSLocale currentLocale]]]; +} + +- (void) dealloc { + BN_clear_free(bigNumber), bigNumber = NULL; + BN_CTX_free(context), context = NULL; +} + +- (void) finalize { + BN_clear_free(bigNumber), bigNumber = NULL; + BN_CTX_free(context), context = NULL; + [super finalize]; +} + +#pragma mark - +#pragma mark NSCopying compliance + +- (id) copyWithZone:(NSZone *)zone { + id copy = [[[self class] alloc] init]; + BN_copy([copy bigNumber], [self bigNumber]); + return copy; +} + +#pragma mark - +#pragma mark NSCoding compliance + +- (id) initWithCoder:(NSCoder *)decoder { + return [self initWithString:[decoder decodeObjectForKey:@"num"]]; +} + +- (void) encodeWithCoder:(NSCoder *)encoder { + [encoder encodeObject:[self stringValue] forKey:@"num"]; +} + +#pragma mark - +#pragma mark Getters and Setters + +- (NSString *)stringValue { + char *cStr = BN_bn2dec([self bigNumber]); + NSString *str = [NSString stringWithCString:cStr encoding:NSASCIIStringEncoding]; + OPENSSL_free(cStr); + return str; +} + +- (NSString *)hexStringValue { + char *cStr = BN_bn2hex([self bigNumber]); + NSString *str = [[NSString stringWithCString:cStr encoding:NSASCIIStringEncoding] lowercaseString]; + OPENSSL_free(cStr); + return str; +} + +- (NSData *)dataValue +{ + NSData* result = nil; + + void* buffer = malloc(BN_num_bytes([self bigNumber])); + if (buffer != NULL) { + BN_bn2bin([self bigNumber], buffer); + result = [NSData dataWithBytesNoCopy: buffer length: BN_num_bytes([self bigNumber]) freeWhenDone: YES]; + } + + return result; +} + +- (NSString *)binaryStringValue { + int numBits = BN_num_bits([self bigNumber]); + BOOL isNegative = [self isNegative]; + BOOL shouldFlip = NO; + int totalBufferSize = numBits + 1; + unsigned char * string = malloc(totalBufferSize * sizeof(unsigned char)); + string[totalBufferSize] = '\0'; + for (int i = 0; i < numBits; ++i) { + int idx = totalBufferSize - i - 1; + int bit = BN_is_bit_set([self bigNumber], i); + if (isNegative) { + if (shouldFlip == YES) { + bit = !bit; + } else if (bit == 1) { + shouldFlip = YES; + } + } + string[idx] = bit + CH_ASCII_ZERO; + } + string[0] = (int)isNegative + CH_ASCII_ZERO; + NSString * binaryString = [[NSString alloc] initWithBytesNoCopy:string length:totalBufferSize encoding:NSASCIIStringEncoding freeWhenDone:YES]; + return binaryString; +} + +- (NSInteger)integerValue { + NSInteger value = BN_get_word([self bigNumber]); + if ([self isNegative]) { value *= -1; } + return value; +} + +- (NSUInteger)unsignedIntegerValue { + return (NSUInteger)BN_get_word([self bigNumber]); +} + +- (BIGNUM*) bigNumValue +{ + return BN_dup([self bigNumber]); +} + +- (NSString *)description { + return [self stringValue]; +} + +- (NSString *)debugDescription { + return [NSString stringWithFormat:@"<%@ %p> - %@", NSStringFromClass([self class]), self, [self stringValue]]; +} + +#pragma mark Comparisons + +- (BOOL)isZero { + return BN_is_zero([self bigNumber]); +} + +- (BOOL)isOne { + return BN_is_one([self bigNumber]); +} + +- (BOOL)isNegative { + return [self isLessThanNumber:[CHNumber number]]; +} + +- (BOOL)isPositive { + return ![self isNegative]; +} + +- (BOOL)isPrime { + return BN_is_prime_ex([self bigNumber], BN_prime_checks, context, NULL); +} + +- (BOOL)isOdd { + return BN_is_odd([self bigNumber]); +} + +- (BOOL)isEven { + return ![self isOdd]; +} + +- (BOOL)isGreaterThanNumber:(CHNumber *)number { + return (BN_cmp([self bigNumber], [number bigNumber]) == NSOrderedDescending); +} + +- (BOOL)isGreaterThanOrEqualToNumber:(CHNumber *)number { + return ([self isGreaterThanNumber:number] || [self isEqualToNumber:number]); +} + +- (NSComparisonResult) compare:(id)object { + if ([object isKindOfClass:[CHNumber class]]) { + CHNumber * other = (CHNumber *)object; + return (NSComparisonResult)BN_cmp([self bigNumber], [other bigNumber]); + } + return NSOrderedDescending; +} + +- (BOOL)isEqualToNumber:(CHNumber *)number { + return (BN_cmp([self bigNumber], [number bigNumber]) == NSOrderedSame); +} + +- (BOOL)isLessThanNumber:(CHNumber *)number { + return (BN_cmp([self bigNumber], [number bigNumber]) == NSOrderedAscending); +} + +- (BOOL)isLessThanOrEqualToNumber:(CHNumber *)number { + return ([self isLessThanNumber:number] || [self isEqualToNumber:number]); +} + +- (BOOL) isEqualTo:(id)object { + if ([object isKindOfClass:[self class]]) { + return [self isEqualToNumber:(CHNumber *)object]; + } else { + return NO; + } +} + +- (BOOL) isEqual:(id)object { + return [self isEqualTo:object]; +} + +#pragma mark - +#pragma mark Mathematical Operations + +- (CHNumber *)numberByModding:(CHNumber *)mod { + CHNumber * result = [CHNumber number]; + BN_mod([result bigNumber], [self bigNumber], [mod bigNumber], context); + return result; +} + +- (CHNumber *)numberByInverseModding:(CHNumber *)mod { + CHNumber * result = [CHNumber number]; + BN_mod_inverse([result bigNumber], [self bigNumber], [mod bigNumber], context); + return result; +} + +- (CHNumber *)numberByAdding:(CHNumber *)addend { + CHNumber * result = [CHNumber number]; + BN_add([result bigNumber], [self bigNumber], [addend bigNumber]); + return result; +} + +- (CHNumber *)numberByAdding:(CHNumber *)addend mod:(CHNumber *)mod { + CHNumber * result = [CHNumber number]; + BN_mod_add([result bigNumber], [self bigNumber], [addend bigNumber], [mod bigNumber], context); + return result; +} + +- (CHNumber *)numberBySubtracting:(CHNumber *)subtrahend { + CHNumber * result = [CHNumber number]; + BN_sub([result bigNumber], [self bigNumber], [subtrahend bigNumber]); + return result; +} + +- (CHNumber *)numberBySubtracting:(CHNumber *)subtrahend mod:(CHNumber *)mod { + CHNumber * result = [CHNumber number]; + BN_mod_sub([result bigNumber], [self bigNumber], [subtrahend bigNumber], [mod bigNumber], context); + return result; +} + +- (CHNumber *)numberByMultiplyingBy:(CHNumber *)multiplicand { + CHNumber * result = [CHNumber number]; + BN_mul([result bigNumber], [self bigNumber], [multiplicand bigNumber], context); + return result; +} + +- (CHNumber *)numberByMultiplyingBy:(CHNumber *)multiplicand mod:(CHNumber *)mod { + CHNumber * result = [CHNumber number]; + BN_mod_mul([result bigNumber], [self bigNumber], [multiplicand bigNumber], [mod bigNumber], context); + return result; +} + +- (CHNumber *)numberByDividingBy:(CHNumber *)divisor { + CHNumber * result = [CHNumber number]; + BN_div([result bigNumber], NULL, [self bigNumber], [divisor bigNumber], context); + return result; +} + +- (CHNumber *)squaredNumber { + CHNumber * result = [CHNumber number]; + BN_sqr([result bigNumber], [self bigNumber], context); + return result; +} + +- (CHNumber *)squaredNumberMod:(CHNumber *)mod { + CHNumber * result = [CHNumber number]; + BN_mod_sqr([result bigNumber], [self bigNumber], [mod bigNumber], context); + return result; +} + +- (CHNumber *)numberByRaisingToPower:(CHNumber *)exponent { + CHNumber * result = [CHNumber number]; + BN_exp([result bigNumber], [self bigNumber], [exponent bigNumber], context); + return result; +} + +- (CHNumber *)numberByRaisingToPower:(CHNumber *)exponent mod:(CHNumber *)mod { + CHNumber * result = [CHNumber number]; + BN_mod_exp([result bigNumber], [self bigNumber], [exponent bigNumber], [mod bigNumber], context); + return result; +} + +- (CHNumber *)negatedNumber { + CHNumber * result = [self copy]; + BN_set_negative([result bigNumber], ![self isNegative]); + return result; +} + +#pragma mark Bitfield Operations + +- (BOOL)isBitSet:(int)bit { + return BN_is_bit_set([self bigNumber], bit); +} + +- (CHNumber *)numberByShiftingLeftOnce { + CHNumber * result = [CHNumber number]; + BN_lshift1([result bigNumber], [self bigNumber]); + return result; +} + +- (CHNumber *)numberByShiftingLeft:(int)leftShift { + CHNumber * result = [CHNumber number]; + BN_lshift([result bigNumber], [self bigNumber], leftShift); + return result; +} + +- (CHNumber *)numberByShiftingRightOnce { + CHNumber * result = [CHNumber number]; + BN_rshift1([result bigNumber], [self bigNumber]); + return result; +} + +- (CHNumber *)numberByShiftingRight:(int)rightShift { + CHNumber * result = [CHNumber number]; + BN_rshift([result bigNumber], [self bigNumber], rightShift); + return result; +} + +- (CHNumber *)numberByMaskingWithInt:(int)mask { + CHNumber * result = [self copy]; + BN_mask_bits([result bigNumber], mask); + return result; +} + +@end diff --git a/mobile/ios/FxA/FxA/CHNumber_Private.h b/mobile/ios/FxA/FxA/CHNumber_Private.h new file mode 100644 index 0000000000..97e6d70b20 --- /dev/null +++ b/mobile/ios/FxA/FxA/CHNumber_Private.h @@ -0,0 +1,13 @@ +// +// CHNumber_Private.h +// CHMath +// +// Created by Dave DeLong on 9/30/09. +// Copyright 2009 Home. All rights reserved. +// + +@interface CHNumber (PRIVATE) + +@property(readonly) BIGNUM * bigNumber; + +@end \ No newline at end of file diff --git a/mobile/ios/FxA/FxA/FxA.h b/mobile/ios/FxA/FxA/FxA.h new file mode 100644 index 0000000000..22375a9069 --- /dev/null +++ b/mobile/ios/FxA/FxA/FxA.h @@ -0,0 +1,31 @@ +// +// FxA.h +// FxA +// +// Created by Richard Newman on 2014-09-22. +// Copyright (c) 2014 Mozilla. All rights reserved. +// + +#import + +//! Project version number for FxA. +FOUNDATION_EXPORT double FxAVersionNumber; + +//! Project version string for FxA. +FOUNDATION_EXPORT const unsigned char FxAVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + +#include +#include +#include +#include +#include +#include +#include + +// These are all the ones the compiler complains are missing. +// Some are commented out because they rely on openssl/bn.h, which we can't find +// when we try the import. *shrug* +#include "ASNUtils.h" +#include diff --git a/mobile/ios/FxA/FxA/Info.plist b/mobile/ios/FxA/FxA/Info.plist new file mode 100644 index 0000000000..d3de8eefb6 --- /dev/null +++ b/mobile/ios/FxA/FxA/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/mobile/ios/FxA/FxA/JSONWebTokenUtils.h b/mobile/ios/FxA/FxA/JSONWebTokenUtils.h new file mode 100644 index 0000000000..00b891aed8 --- /dev/null +++ b/mobile/ios/FxA/FxA/JSONWebTokenUtils.h @@ -0,0 +1,40 @@ +// 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/ + + +#import + + +@class KeyPair; +@class PublicKey; +@class PrivateKey; +@class FXACertificate; + + +extern NSString * const JSONWebTokenUtilsDefaultAssertionIssuer; + +extern const unsigned long long JSONWebTokenUtilsDefaultCertificateDuration; +extern const unsigned long long JSONWebTokenUtilsDefaultAssertionDuration; + + +@interface JSONWebTokenUtils : NSObject + ++ (NSString*) base64EncodedJSONObject: (NSDictionary*) object; + ++ (NSString*) encodePayloadString: (NSString*) payloadString withPrivateKeyToSign: (PrivateKey*) privateKey; ++ (NSString*) decodePayloadStringFromToken: (NSString*) token withPublicKeyToVerify: (PublicKey*) publicKey; + ++ (NSDictionary*) payloadWithPayload: (NSDictionary*) payload issuer: (NSString*) issuer issuedAt: (unsigned long long) issuedAt expiresAt: (unsigned long long) expiresAt audience: (NSString*) audience; ++ (NSString*) payloadStringWithPayload: (NSDictionary*) payload issuer: (NSString*) issuer issuedAt: (unsigned long long) issuedAt expiresAt: (unsigned long long) expiresAt audience: (NSString*) audience; + ++ (NSDictionary*) certificatePayloadWithPublicKeyToSign: (PublicKey*) publicKeyToSign email: (NSString*) email; ++ (NSString*) certificatePayloadStringWithPublicKeyToSign: (PublicKey*) publicKeyToSign email: (NSString*) email; + ++ (NSString*) certificateWithPublicKeyToSign: (PublicKey*) publicKeyToSign email: (NSString*) email issuer: (NSString*) issuer issuedAt: (unsigned long long) issuedAt expiresAt: (unsigned long long) expiresAt signingPrivateKey: (PrivateKey*) signingPrivateKey; + + ++ (NSString*) createAssertionWithPrivateKeyToSignWith: (PrivateKey*) privateKeyToSignWith certificate: (NSString*) certificate audience: (NSString*) audience issuer: (NSString*) issuer issuedAt: (unsigned long long) issuedAt duration: (unsigned long long) duration; ++ (NSString*) createAssertionWithPrivateKeyToSignWith: (PrivateKey*) privateKeyToSignWith certificate: (NSString*) certificate audience: (NSString*) audience; + +@end diff --git a/mobile/ios/FxA/FxA/JSONWebTokenUtils.m b/mobile/ios/FxA/FxA/JSONWebTokenUtils.m new file mode 100644 index 0000000000..a055a4711f --- /dev/null +++ b/mobile/ios/FxA/FxA/JSONWebTokenUtils.m @@ -0,0 +1,140 @@ +// 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 "CHNumber.h" +#include "NSData+Utils.h" + +#import "KeyPair.h" +#import "PrivateKey.h" +#import "PublicKey.h" +#import "JSONWebTokenUtils.h" + + +NSString * const JSONWebTokenUtilsDefaultAssertionIssuer = @"127.0.0.1"; + +const unsigned long long JSONWebTokenUtilsDefaultCertificateDuration = 60 * 60 * 1000; +const unsigned long long JSONWebTokenUtilsDefaultAssertionDuration = 60 * 60 * 1000; + + +@implementation JSONWebTokenUtils + ++ (NSString*) base64EncodedJSONObject: (NSDictionary*) object +{ + NSError *encodingError = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject: object options: 0 error: &encodingError]; + if (encodingError != nil) { + return nil; + } + + return [data base64URLEncodedStringWithOptions: 0]; +} + ++ (NSString*) encodePayloadString: (NSString*) payloadString withPrivateKeyToSign: (PrivateKey*) privateKey +{ + NSDictionary *header = @{ + @"alg": privateKey.algorithm, + }; + + NSString *encodedHeader = [self base64EncodedJSONObject: header]; + NSString *encodedPayload = [[payloadString dataUsingEncoding: NSUTF8StringEncoding] base64URLEncodedStringWithOptions: 0]; + + NSString *message = [NSString stringWithFormat: @"%@.%@", encodedHeader, encodedPayload]; + NSString *signature = [[privateKey signMessageString: message encoding: NSUTF8StringEncoding] base64URLEncodedStringWithOptions: 0]; + + return [NSString stringWithFormat: @"%@.%@", message, signature]; +} + ++ (NSString*) decodePayloadStringFromToken: (NSString*) token withPublicKeyToVerify: (PublicKey*) publicKey +{ + NSArray *components = [token componentsSeparatedByString: @"."]; + if ([components count] != 3) { + return nil; + } + + NSData *message = [[NSString stringWithFormat: @"%@.%@", components[0], components[1]] dataUsingEncoding: NSUTF8StringEncoding]; + NSData *signature = [[NSData alloc] initWithBase64URLEncodedString: components[2] options: 0]; + + if ([publicKey verifySignature: signature againstMessage: message] == NO) { + return nil; + } + + return [[NSString alloc] initWithData: [[NSData alloc] initWithBase64URLEncodedString: components[1] options: 0] encoding: NSUTF8StringEncoding]; +} + ++ (NSDictionary*) payloadWithPayload: (NSDictionary*) payload issuer: (NSString*) issuer issuedAt: (unsigned long long) issuedAt expiresAt: (unsigned long long) expiresAt audience: (NSString*) audience +{ + NSMutableDictionary *fullPayload = [NSMutableDictionary dictionaryWithDictionary: payload]; + fullPayload[@"iss"] = issuer; + fullPayload[@"iat"] = [NSNumber numberWithUnsignedLongLong: issuedAt]; + if (audience != nil) { + fullPayload[@"aud"] = audience; + } + fullPayload[@"exp"] = [NSNumber numberWithUnsignedLongLong: expiresAt]; + + return fullPayload; +} + ++ (NSString*) payloadStringWithPayload: (NSDictionary*) payload issuer: (NSString*) issuer issuedAt: (unsigned long long) issuedAt expiresAt: (unsigned long long) expiresAt audience: (NSString*) audience +{ + NSDictionary *fullPayload = [self payloadWithPayload: payload issuer:issuer issuedAt:issuedAt expiresAt:expiresAt audience:audience]; + + NSError *encodingError = nil; + NSData *payloadData = [NSJSONSerialization dataWithJSONObject: fullPayload options: 0 error: &encodingError]; + if (encodingError != nil) { + return nil; + } + + return [[NSString alloc] initWithData: payloadData encoding: NSUTF8StringEncoding]; +} + ++ (NSDictionary*) certificatePayloadWithPublicKeyToSign: (PublicKey*) publicKey email: (NSString*) email +{ + NSDictionary *payload = @{ + @"principal": @{ + @"email": email + }, + @"public-key": [publicKey JSONRepresentation] + }; + + return payload; +} + ++ (NSString*) certificatePayloadStringWithPublicKeyToSign: (PublicKey*) publicKeyToSign email: (NSString*) email +{ + NSDictionary *payloadObject = [self certificatePayloadWithPublicKeyToSign: publicKeyToSign email: email]; + + NSError *encodingError = nil; + NSData *payload = [NSJSONSerialization dataWithJSONObject: payloadObject options: 0 error: &encodingError]; + if (encodingError != nil) { + return nil; + } + + return [[NSString alloc] initWithData: payload encoding:NSUTF8StringEncoding]; +} + ++ (NSString*) certificateWithPublicKeyToSign: (PublicKey*) publicKeyToSign email: (NSString*) email issuer: (NSString*) issuer issuedAt: (unsigned long long) issuedAt expiresAt: (unsigned long long) expiresAt signingPrivateKey: (PrivateKey*) signingPrivateKey +{ + NSDictionary *certificatePayload = [JSONWebTokenUtils certificatePayloadWithPublicKeyToSign: publicKeyToSign email: email]; + NSString *payloadString = [JSONWebTokenUtils payloadStringWithPayload: certificatePayload issuer: issuer issuedAt: issuedAt expiresAt:expiresAt audience: nil]; + return [self encodePayloadString: payloadString withPrivateKeyToSign: signingPrivateKey]; +} + ++ (NSString*) createAssertionWithPrivateKeyToSignWith: (PrivateKey*) privateKeyToSignWith certificate: (NSString*) certificate audience: (NSString*) audience issuer: (NSString*) issuer issuedAt: (unsigned long long) issuedAt duration: (unsigned long long) duration +{ + unsigned long long expiresAt = issuedAt + duration; + NSString *payloadString = [self payloadStringWithPayload: @{} issuer:issuer issuedAt:issuedAt expiresAt:expiresAt audience:audience]; + NSString *signature = [self encodePayloadString: payloadString withPrivateKeyToSign: privateKeyToSignWith]; + return [NSString stringWithFormat: @"%@~%@", certificate, signature]; +} + ++ (NSString*) createAssertionWithPrivateKeyToSignWith: (PrivateKey*) privateKeyToSignWith certificate: (NSString*) certificate audience: (NSString*) audience +{ + unsigned long long issuedAt = [[NSDate date] timeIntervalSince1970] * 1000; + unsigned long long duration = JSONWebTokenUtilsDefaultAssertionDuration; + return [self createAssertionWithPrivateKeyToSignWith: privateKeyToSignWith certificate: certificate audience: audience + issuer: JSONWebTokenUtilsDefaultAssertionIssuer issuedAt: issuedAt duration: duration]; +} + +@end diff --git a/mobile/ios/FxA/FxA/KeyPair.h b/mobile/ios/FxA/FxA/KeyPair.h new file mode 100644 index 0000000000..bb53155af7 --- /dev/null +++ b/mobile/ios/FxA/FxA/KeyPair.h @@ -0,0 +1,23 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + + +#import + + +@class PublicKey; +@class PrivateKey; + + +@interface KeyPair : NSObject + +@property (readonly) PublicKey *publicKey; +@property (readonly) PrivateKey *privateKey; + +- (instancetype) initWithPublicKey: (PublicKey*) publicKey privateKey: (PrivateKey*) privateKey; +- (instancetype) initWithJSONRepresentation: (NSDictionary*) object; + +- (NSDictionary*) JSONRepresentation; + +@end diff --git a/mobile/ios/FxA/FxA/KeyPair.m b/mobile/ios/FxA/FxA/KeyPair.m new file mode 100644 index 0000000000..a3d4eb4509 --- /dev/null +++ b/mobile/ios/FxA/FxA/KeyPair.m @@ -0,0 +1,37 @@ +// 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/ + + +#import "PublicKey.h" +#import "PrivateKey.h" +#import "KeyPair.h" + + +@implementation KeyPair + +- (instancetype) initWithPublicKey: (PublicKey*) publicKey privateKey: (PrivateKey*) privateKey +{ + if ((self = [super init]) != nil) { + _publicKey = publicKey; + _privateKey = privateKey; + } + return self; +} + +- (instancetype) initWithJSONRepresentation: (NSDictionary*) object +{ + if ((self = [super init]) != nil) { + } + return self; +} + +- (NSDictionary*) JSONRepresentation +{ + return @{ + @"publicKey": [[self publicKey] JSONRepresentation], + @"privateKey": [[self privateKey] JSONRepresentation] + }; +} + +@end diff --git a/mobile/ios/FxA/FxA/NSData+Base16.h b/mobile/ios/FxA/FxA/NSData+Base16.h new file mode 100644 index 0000000000..929cba649f --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+Base16.h @@ -0,0 +1,24 @@ +// 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/ + + +#import + + +typedef NS_OPTIONS(NSUInteger, NSDataBase16DecodingOptions) { + NSDataBase16DecodingOptionsDefault = 0 +}; + +typedef NS_OPTIONS(NSUInteger, NSDataBase16EncodingOptions) { + NSDataBase16EncodingOptionsDefault = 0, + NSDataBase16EncodingOptionsLowerCase = 1 +}; + + +@interface NSData (Base16) + +- (id) initWithBase16EncodedString:(NSString *)base16String options:(NSDataBase16DecodingOptions)options; +- (NSString *)base16EncodedStringWithOptions:(NSDataBase16EncodingOptions)options; + +@end diff --git a/mobile/ios/FxA/FxA/NSData+Base16.m b/mobile/ios/FxA/FxA/NSData+Base16.m new file mode 100644 index 0000000000..6486264696 --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+Base16.m @@ -0,0 +1,80 @@ +// 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/ + + +#import "NSData+Base16.h" + + +static const char kBase16AlphabetUpperCase[] = "0123456789ABCDEF"; +static const char kBase16AlphabetLowerCase[] = "0123456789abcdef"; + + +@implementation NSData (Base16) + +- (id) initWithBase16EncodedString:(NSString *)base16String options:(NSDataBase16DecodingOptions)options +{ + if ([base16String length] & 1) { + return nil; + } + + if ([base16String length] == 0) { + return [self init]; + } + + unsigned char *decoded = (unsigned char*) malloc([base16String length] / 2); + unsigned char *dst = decoded; + + for (NSUInteger i = 0; i < [base16String length]; i += 2) { + unichar h = [base16String characterAtIndex: i]; + unichar l = [base16String characterAtIndex: i+1]; + + if (isxdigit(h) == 0 || isxdigit(l) == 0) { + free(decoded); + return nil; + } + + if (isdigit(h)) { + *dst = (h - '0') << 4; + } else { + if (h >= 'a') { + *dst = (h - 'a' + 10) << 4; + } else { + *dst = (h - 'A' + 10) << 4; + } + } + + if (isdigit(l)) { + *dst |= (l - '0'); + } else { + if (l >= 'a') { + *dst |= (10 + (l - 'a')) & 0x0f; + } else { + *dst |= (10 + (l - 'A')) & 0x0f; + } + } + + dst++; + } + + return [self initWithBytesNoCopy: decoded length: [base16String length] / 2 freeWhenDone: YES]; +} + +- (NSString *)base16EncodedStringWithOptions:(NSDataBase16EncodingOptions)options +{ + char *encoded = (char*) malloc([self length] * 2); + + const char *src = [self bytes]; + char *dst = encoded; + + const char *alphabet = (options & NSDataBase16EncodingOptionsLowerCase) ? kBase16AlphabetLowerCase : kBase16AlphabetUpperCase; + + for (NSUInteger i = 0; i < [self length]; i++, src++) { + *dst++ = alphabet[(*src >> 4) & 0b00001111]; + *dst++ = alphabet[(*src >> 0) & 0b00001111]; + } + + return [[NSString alloc] initWithBytesNoCopy: encoded length: [self length] * 2 encoding: NSASCIIStringEncoding freeWhenDone: YES]; +} + +@end diff --git a/mobile/ios/FxA/FxA/NSData+Base32.h b/mobile/ios/FxA/FxA/NSData+Base32.h new file mode 100644 index 0000000000..75e180664e --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+Base32.h @@ -0,0 +1,25 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + + +#import + + +typedef NS_OPTIONS(NSUInteger, NSDataBase32DecodingOptions) { + NSDataBase32DecodingOptionsDefault = 0, + NSDataBase32DecodingOptionsUserFriendly = 1UL << 0 +}; + +typedef NS_OPTIONS(NSUInteger, NSDataBase32EncodingOptions) { + NSDataBase32EncodingOptionsDefault = 0, + NSDataBase32EncodingOptionsUserFriendly = 1UL << 0 +}; + + +@interface NSData (Base32) + +- (id) initWithBase32EncodedString:(NSString *)base32String options:(NSDataBase32DecodingOptions)options; +- (NSString *)base32EncodedStringWithOptions:(NSDataBase32EncodingOptions)options; + +@end diff --git a/mobile/ios/FxA/FxA/NSData+Base32.m b/mobile/ios/FxA/FxA/NSData+Base32.m new file mode 100644 index 0000000000..8e6688f443 --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+Base32.m @@ -0,0 +1,207 @@ +// 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/ + + +#import "NSData+Base32.h" + + +static const char kBase32Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; +static const NSUInteger kBase32BlockSize = 5; + + +static void *base32_decode(const char *buf, unsigned int *outlen); + + +@implementation NSData (Base32) + +- (id) initWithBase32EncodedString:(NSString *)base32String options:(NSDataBase32DecodingOptions)options +{ + NSData* result = nil; + + if (options & NSDataBase32DecodingOptionsUserFriendly) { + base32String = [[[base32String uppercaseString] + stringByReplacingOccurrencesOfString: @"8" withString: @"l"] + stringByReplacingOccurrencesOfString: @"9" withString: @"o"]; + } + + unsigned int length = 0; + void* bytes = base32_decode([base32String UTF8String], &length); + if (bytes != NULL) { + result = [self initWithBytesNoCopy: bytes length: length freeWhenDone: YES]; + } + + return result; +} + +- (NSString *)base32EncodedStringWithOptions:(NSDataBase32EncodingOptions)options +{ + NSMutableString *encoded = [NSMutableString new]; + + const unsigned char *bytes = [self bytes]; + NSUInteger bytesAvailable = [self length]; + + while (bytesAvailable > 0) + { + unsigned char blockData[kBase32BlockSize] = { 0, 0, 0, 0, 0 }; + NSUInteger blockSize = MIN(bytesAvailable, kBase32BlockSize); + + memcpy(blockData, bytes, blockSize); + + bytes += blockSize; + bytesAvailable -= blockSize; + + [encoded appendFormat: @"%c", kBase32Alphabet[((blockData[0] & 0b11111000) >> 3)]]; + [encoded appendFormat: @"%c", kBase32Alphabet[((blockData[0] & 0b00000111) << 2) | ((blockData[1] & 0b11000000) >> 6)]]; + [encoded appendFormat: @"%c", kBase32Alphabet[((blockData[1] & 0b00111110) >> 1)]]; + [encoded appendFormat: @"%c", kBase32Alphabet[((blockData[1] & 0b00000001) << 4) | ((blockData[2] & 0b11110000) >> 4)]]; + [encoded appendFormat: @"%c", kBase32Alphabet[((blockData[2] & 0b00001111) << 1) | ((blockData[3] & 0b10000000) >> 7)]]; + [encoded appendFormat: @"%c", kBase32Alphabet[((blockData[3] & 0b01111100) >> 2)]]; + [encoded appendFormat: @"%c", kBase32Alphabet[((blockData[3] & 0b00000011) << 3) | ((blockData[4] & 0b11100000) >> 5)]]; + [encoded appendFormat: @"%c", kBase32Alphabet[((blockData[4] & 0b00011111))]]; + } + + NSUInteger rest = [self length] % kBase32BlockSize; + if (rest != 0) + { + switch (rest) + { + case 1: + [encoded replaceCharactersInRange: NSMakeRange([encoded length] - 6, 6) withString: @"======"]; + break; + case 2: + [encoded replaceCharactersInRange: NSMakeRange([encoded length] - 4, 4) withString: @"===="]; + break; + case 3: + [encoded replaceCharactersInRange: NSMakeRange([encoded length] - 3, 3) withString: @"==="]; + break; + case 4: + [encoded replaceCharactersInRange: NSMakeRange([encoded length] - 1, 1) withString: @"="]; + break; + } + } + + if (options & NSDataBase32EncodingOptionsUserFriendly) { + return [[encoded stringByReplacingOccurrencesOfString: @"L" withString: @"8"] stringByReplacingOccurrencesOfString: @"O" withString: @"9"]; + } else { + return encoded; + } +} + +@end + + +#pragma mark - + + +// Public domain Base32 code taken from http://bitzi.com/publicdomain + +#define BASE32_LOOKUP_MAX 43 + +static unsigned char base32Lookup[BASE32_LOOKUP_MAX][2] = +{ + { '0', 0xFF }, + { '1', 0xFF }, + { '2', 0x1A }, + { '3', 0x1B }, + { '4', 0x1C }, + { '5', 0x1D }, + { '6', 0x1E }, + { '7', 0x1F }, + { '8', 0xFF }, + { '9', 0xFF }, + { ':', 0xFF }, + { ';', 0xFF }, + { '<', 0xFF }, + { '=', 0xFF }, + { '>', 0xFF }, + { '?', 0xFF }, + { '@', 0xFF }, + { 'A', 0x00 }, + { 'B', 0x01 }, + { 'C', 0x02 }, + { 'D', 0x03 }, + { 'E', 0x04 }, + { 'F', 0x05 }, + { 'G', 0x06 }, + { 'H', 0x07 }, + { 'I', 0x08 }, + { 'J', 0x09 }, + { 'K', 0x0A }, + { 'L', 0x0B }, + { 'M', 0x0C }, + { 'N', 0x0D }, + { 'O', 0x0E }, + { 'P', 0x0F }, + { 'Q', 0x10 }, + { 'R', 0x11 }, + { 'S', 0x12 }, + { 'T', 0x13 }, + { 'U', 0x14 }, + { 'V', 0x15 }, + { 'W', 0x16 }, + { 'X', 0x17 }, + { 'Y', 0x18 }, + { 'Z', 0x19 } +}; + +static int base32_decode_length(int base32Length) +{ + return ((base32Length * 5) / 8); +} + +static int base32_decode_into(const char *base32Buffer, unsigned int base32BufLen, void *_buffer) +{ + unsigned long max; + int i, index, lookup, offset; + unsigned char word; + unsigned char *buffer = _buffer; + + memset(buffer, 0, base32_decode_length(base32BufLen)); + max = strlen(base32Buffer); + for(i = 0, index = 0, offset = 0; i < max; i++) + { + lookup = toupper(base32Buffer[i]) - '0'; + /* Check to make sure that the given word falls inside + a valid range */ + if ( lookup < 0 && lookup >= BASE32_LOOKUP_MAX) + word = 0xFF; + else + word = base32Lookup[lookup][1]; + + /* If this word is not in the table, ignore it */ + if (word == 0xFF) + continue; + + if (index <= 3) + { + index = (index + 5) % 8; + if (index == 0) + { + buffer[offset] |= word; + offset++; + } + else + buffer[offset] |= word << (8 - index); + } + else + { + index = (index + 5) % 8; + buffer[offset] |= (word >> index); + offset++; + + buffer[offset] |= word << (8 - index); + } + } + return offset; +} + +static void *base32_decode(const char *buf, unsigned int *outlen) +{ + unsigned int len = strlen(buf); + char *tmp = malloc(base32_decode_length(len)); + unsigned int x = base32_decode_into(buf, len, tmp); + if(outlen) + *outlen = x; + return tmp; +} diff --git a/mobile/ios/FxA/FxA/NSData+KeyDerivation.h b/mobile/ios/FxA/FxA/NSData+KeyDerivation.h new file mode 100644 index 0000000000..1b2cee45e4 --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+KeyDerivation.h @@ -0,0 +1,13 @@ +// 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/ + +#import + +@interface NSData (KeyDerivation) + +- (NSData*) deriveHKDFSHA256KeyWithSalt: (NSData*) salt contextInfo: (NSData*) contextInfo length: (NSUInteger) length; +- (NSData*) derivePBKDF2HMACSHA256KeyWithSalt: (NSData*) salt iterations: (NSUInteger) iterations length: (NSUInteger) length; +- (NSData*) deriveSCryptKeyWithSalt: (NSData*) salt n: (uint32_t) n r: (uint32_t) r p: (uint32_t) p length: (NSUInteger) length; + +@end diff --git a/mobile/ios/FxA/FxA/NSData+KeyDerivation.m b/mobile/ios/FxA/FxA/NSData+KeyDerivation.m new file mode 100644 index 0000000000..5ead5d7ba4 --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+KeyDerivation.m @@ -0,0 +1,292 @@ +// 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/ + +#import "openssl/evp.h" +#import "openssl/sha.h" + +#import "NSData+SHA.h" +#import "NSData+Utils.h" +#import "NSData+KeyDerivation.h" + +#pragma mark - Low Level SCrypt Functions + + + + +//#define WORDS_BIGENDIAN 1 +#define BLOCK_WORDS 16 + +static inline uint32_t +ROTL(uint32_t x, int n) +{ + return (x << n) | (x >> (32 - n)); +} + +#ifdef WORDS_BIGENDIAN +static inline uint32_t +ROTR(uint32_t x, int n) +{ + return (x >> n) | (x << (32 - n)); +} + +static inline uint32_t +BYTESWAP(uint32_t x) +{ + return (ROTR(x, 8) & 0xff00ff00) | + (ROTL(x, 8) & 0x00ff00ff); +} +#endif + +static void +salsa20_8_core (uint32_t out[BLOCK_WORDS], const uint32_t in[BLOCK_WORDS]) +{ + const uint32_t *x; + uint32_t *z; + int i; + + memcpy(out, in, sizeof(*out) * BLOCK_WORDS); + + z = out; + for (i = 8 - 1; i >= 0; i -= 2) { + z[ 4] ^= ROTL(z[ 0]+z[12], 7); + z[ 8] ^= ROTL(z[ 4]+z[ 0], 9); + z[12] ^= ROTL(z[ 8]+z[ 4],13); + z[ 0] ^= ROTL(z[12]+z[ 8],18); + z[ 9] ^= ROTL(z[ 5]+z[ 1], 7); + z[13] ^= ROTL(z[ 9]+z[ 5], 9); + z[ 1] ^= ROTL(z[13]+z[ 9],13); + z[ 5] ^= ROTL(z[ 1]+z[13],18); + z[14] ^= ROTL(z[10]+z[ 6], 7); + z[ 2] ^= ROTL(z[14]+z[10], 9); + z[ 6] ^= ROTL(z[ 2]+z[14],13); + z[10] ^= ROTL(z[ 6]+z[ 2],18); + z[ 3] ^= ROTL(z[15]+z[11], 7); + z[ 7] ^= ROTL(z[ 3]+z[15], 9); + z[11] ^= ROTL(z[ 7]+z[ 3],13); + z[15] ^= ROTL(z[11]+z[ 7],18); + z[ 1] ^= ROTL(z[ 0]+z[ 3], 7); + z[ 2] ^= ROTL(z[ 1]+z[ 0], 9); + z[ 3] ^= ROTL(z[ 2]+z[ 1],13); + z[ 0] ^= ROTL(z[ 3]+z[ 2],18); + z[ 6] ^= ROTL(z[ 5]+z[ 4], 7); + z[ 7] ^= ROTL(z[ 6]+z[ 5], 9); + z[ 4] ^= ROTL(z[ 7]+z[ 6],13); + z[ 5] ^= ROTL(z[ 4]+z[ 7],18); + z[11] ^= ROTL(z[10]+z[ 9], 7); + z[ 8] ^= ROTL(z[11]+z[10], 9); + z[ 9] ^= ROTL(z[ 8]+z[11],13); + z[10] ^= ROTL(z[ 9]+z[ 8],18); + z[12] ^= ROTL(z[15]+z[14], 7); + z[13] ^= ROTL(z[12]+z[15], 9); + z[14] ^= ROTL(z[13]+z[12],13); + z[15] ^= ROTL(z[14]+z[13],18); + } + + x = in; + for (i = BLOCK_WORDS - 1; i >= 0; i--) { + *(z++) += *(x++); + } +} + +static void +blockmix_salsa20_8_core (uint32_t out[/* (2 * r * BLOCK_WORDS) */], + const uint32_t in[/* (2 * r * BLOCK_WORDS) */], + unsigned int r) +{ + uint32_t *even, *odd; + uint32_t *x; + uint32_t tmp[BLOCK_WORDS]; + unsigned int i, j; + + even = out; + odd = &out[r * BLOCK_WORDS]; + + memcpy(tmp, &in[(2 * r - 1) * BLOCK_WORDS], sizeof(tmp)); + + for (i = r; i > 0; i--) { + x = tmp; + for (j = BLOCK_WORDS; j > 0; j--) { + *(x++) ^= *(in++); + } + salsa20_8_core(even, tmp); + memcpy(tmp, even, sizeof(tmp)); + even += BLOCK_WORDS; + + x = tmp; + for (j = BLOCK_WORDS; j > 0; j--) { + *(x++) ^= *(in++); + } + salsa20_8_core(odd, tmp); + memcpy(tmp, odd, sizeof(tmp)); + odd += BLOCK_WORDS; + } +} + +static void +smix (void *out /* (sizeof(uint32_t) * 2 * r * BLOCK_WORDS) */, + const void *in /* (sizeof(uint32_t) * 2 * r * BLOCK_WORDS) */, + unsigned int N, unsigned int r, + uint32_t tmp[/* (2 * r * BLOCK_WORDS * (N + 2)) */]) +{ + uint32_t *v; + uint32_t *X, *T, *x, *t; + uint32_t j; + unsigned int i, k; + + memcpy(tmp, in, sizeof(*tmp) * 2 * r * BLOCK_WORDS); + +#ifdef WORDS_BIGENDIAN + v = tmp; + for (i = 2 * r * BLOCK_WORDS; i > 0; i--) { + *v = BYTESWAP(*v); + v++; + } +#endif /* WORDS_BIGENDIAN */ + + v = tmp; + for (i = N; i > 0; i--) { + blockmix_salsa20_8_core(v + 2 * r * BLOCK_WORDS, v, r); + v += 2 * r * BLOCK_WORDS; + } + X = v; + T = &X[2 * r * BLOCK_WORDS]; + + for (i = N; i > 0; i--) { + j = X[(2 * r - 1) * BLOCK_WORDS] % N; + + x = X; + v = &tmp[2 * r * BLOCK_WORDS * j]; + for (k = 2 * r * BLOCK_WORDS; k > 0; k--) { + *(x++) ^= *(v++); + } + + blockmix_salsa20_8_core(T, X, r); + + /* swap X & T */ + t = T; + T = X; + X = t; + } + +#ifdef WORDS_BIGENDIAN + x = X; + for (i = 2 * r * BLOCK_WORDS; i > 0; i--) { + *x = BYTESWAP(*x); + x++; + } +#endif /* WORDS_BIGENDIAN */ + + memcpy (out, X, sizeof(*X) * 2 * r * BLOCK_WORDS); +} + +int +scrypt (const void *password, size_t passwordLen, + const void *salt, size_t saltLen, + unsigned int N, unsigned int r, unsigned int p, + uint8_t *derivedKey, size_t dkLen) +{ + size_t MFLen = sizeof(uint32_t) * 2 * r * BLOCK_WORDS; + uint8_t *B, *b; + uint32_t *tmp; + unsigned int i; + + if ((B = malloc(p * MFLen)) == NULL) + return -1; + + if (PKCS5_PBKDF2_HMAC(password, passwordLen, salt, saltLen, 1, EVP_sha256(), p * MFLen, B)) { + //return -1; +} + + if ((tmp = malloc(sizeof(*tmp) * 2 * r * BLOCK_WORDS * (N + 2))) == NULL) { + free(B); + return -1; + } + + b = B; + for (i = p; i > 0; i--) { + smix(b, b, N, r, tmp); + b += MFLen; + } + + if (PKCS5_PBKDF2_HMAC(password, passwordLen, B, p * MFLen, 1, EVP_sha256(), dkLen, derivedKey)) { + //return -1; + } + + free(tmp); + free(B); + return 0; +} + + + + + + +@implementation NSData (KeyDerivation) + +- (NSData*) deriveHKDFSHA256KeyWithSalt: (NSData*) salt contextInfo: (NSData*) contextInfo length: (NSUInteger) length +{ + // If salt is not specified then we use a zero salt + + if (salt == nil) { + salt = [NSMutableData dataWithLength: SHA256_DIGEST_LENGTH]; + } + + // Extract + + NSData *prk = [self HMACSHA256WithKey: salt]; + + // Expand + + NSUInteger iterations = (length + SHA256_DIGEST_LENGTH - 1) / SHA256_DIGEST_LENGTH; + + NSMutableData* tr = [NSMutableData dataWithCapacity: (iterations * SHA256_DIGEST_LENGTH)]; + + NSData* tn = [NSData data]; + for (NSUInteger i = 1; i <= iterations; i++) { + unsigned char n = i; + tn = [[NSData dataByAppendingDatas: @[tn, contextInfo, [NSData dataWithBytes: &n length: 1]]] HMACSHA256WithKey: prk]; + [tr appendData: tn]; + } + + return [tr subdataWithRange: NSMakeRange(0, length)]; +} + +- (NSData*) derivePBKDF2HMACSHA256KeyWithSalt: (NSData*) salt iterations: (NSUInteger) iterations length: (NSUInteger) length +{ + unsigned char *key = malloc(length); + if (key == NULL) { + return nil; + } + + PKCS5_PBKDF2_HMAC( + [self bytes], + [self length], + [salt bytes], + [salt length], + iterations, + EVP_sha256(), + length, + key + ); + + return [NSData dataWithBytesNoCopy: key length: length freeWhenDone: YES]; +} + +- (NSData*) deriveSCryptKeyWithSalt: (NSData*) salt n: (uint32_t) n r: (uint32_t) r p: (uint32_t) p length: (NSUInteger) length +{ + uint8_t *buffer = (uint8_t*) malloc(length); + if (buffer == NULL) { + return nil; + } + + if (scrypt([self bytes], [self length], [salt bytes], [salt length], n, r, p, buffer, length) != 0) { + free(buffer); + return nil; + } + + return [NSData dataWithBytesNoCopy: buffer length:length freeWhenDone:YES]; +} + +@end diff --git a/mobile/ios/FxA/FxA/NSData+SHA.h b/mobile/ios/FxA/FxA/NSData+SHA.h new file mode 100644 index 0000000000..13d359afda --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+SHA.h @@ -0,0 +1,15 @@ +// 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/ + + +#import + + +@interface NSData (SHA) + +- (NSData*) SHA1Hash; +- (NSData*) SHA256Hash; +- (NSData*) HMACSHA256WithKey: (NSData*) key; + +@end \ No newline at end of file diff --git a/mobile/ios/FxA/FxA/NSData+SHA.m b/mobile/ios/FxA/FxA/NSData+SHA.m new file mode 100644 index 0000000000..389292fc6a --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+SHA.m @@ -0,0 +1,41 @@ +// 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/ + + +#import +#import +#import "NSData+SHA.h" + + +@implementation NSData (SHA) + +// TODO: Needs a test +- (NSData*) SHA1Hash +{ + unsigned char md[CC_SHA1_DIGEST_LENGTH]; + CC_SHA1([self bytes], [self length], md); + return [NSData dataWithBytes: md length: CC_SHA1_DIGEST_LENGTH]; +} + +- (NSData*) SHA256Hash +{ + unsigned char md[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256([self bytes], [self length], md); + return [NSData dataWithBytes: md length: CC_SHA256_DIGEST_LENGTH]; +} + +- (NSData*) HMACSHA256WithKey: (NSData*) key +{ + // This is kind of odd, but we do this because [NSData dataWithBytes "" length: 0] results in an object that is invalid. + + if ([key length] == 0) { + key = [NSMutableData data]; + } + + unsigned char mac[CC_SHA256_DIGEST_LENGTH]; + CCHmac(kCCHmacAlgSHA256, [key bytes], [key length], [self bytes], [self length], mac); + return [NSData dataWithBytes: mac length: CC_SHA256_DIGEST_LENGTH]; +} + +@end diff --git a/mobile/ios/FxA/FxA/NSData+Utils.h b/mobile/ios/FxA/FxA/NSData+Utils.h new file mode 100644 index 0000000000..e6d960ff5d --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+Utils.h @@ -0,0 +1,23 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + + +#import + + +@interface NSData (Utils) + ++ (id) dataByAppendingDatas: (NSArray*) datas; + +- (id) dataLeftZeroPaddedToLength: (NSUInteger) length; +- (id) dataRightZeroPaddedToLength: (NSUInteger) length; + +- (id) exclusiveOrWithKey: (NSData*) key; + ++ (id) randomDataWithLength: (NSUInteger) length; + +- (NSString*) base64URLEncodedStringWithOptions: (NSDataBase64EncodingOptions) options; +- (instancetype) initWithBase64URLEncodedString:(NSString *)base64String options:(NSDataBase64DecodingOptions)options; + +@end diff --git a/mobile/ios/FxA/FxA/NSData+Utils.m b/mobile/ios/FxA/FxA/NSData+Utils.m new file mode 100644 index 0000000000..96733515f6 --- /dev/null +++ b/mobile/ios/FxA/FxA/NSData+Utils.m @@ -0,0 +1,112 @@ +// 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/ + + +#import +#import "NSData+Utils.h" + + +@implementation NSData (Utils) + ++ (id) dataByAppendingDatas: (NSArray*) datas +{ + NSMutableData *result = [NSMutableData data]; + for (NSData *data in datas) { + [result appendData: data]; + } + return result; +} + +- (id) dataLeftZeroPaddedToLength: (NSUInteger) length +{ + if ([self length] < length) { + return [NSData dataByAppendingDatas: @[[NSMutableData dataWithLength: (length - [self length])], self]]; + } else { + return self; + } +} + +- (id) dataRightZeroPaddedToLength: (NSUInteger) length +{ + if ([self length] < length) { + return [NSData dataByAppendingDatas: @[self, [NSMutableData dataWithLength: (length - [self length])]]]; + } else { + return self; + } +} + +- (id) exclusiveOrWithKey: (NSData*) key +{ + if ([self length] != [key length]) { + return nil; + } + + unsigned char *o = (unsigned char*) malloc([self length]); + unsigned char *p = (unsigned char*) [self bytes]; + unsigned char *q = (unsigned char*) [key bytes]; + + for (NSUInteger i = 0; i < [self length]; i++) { + o[i] = p[i] ^ q[i]; + } + + return [NSData dataWithBytesNoCopy: o length: [self length] freeWhenDone: YES]; +} + ++ (id) randomDataWithLength: (NSUInteger) length +{ + void *bytes = malloc(length); + if (bytes == NULL) { + return nil; + } + + if (SecRandomCopyBytes(kSecRandomDefault, length, bytes) != 0) { + free(bytes); + return nil; + } + + return [NSData dataWithBytesNoCopy: bytes length:length freeWhenDone: YES]; +} + +- (NSString*) base64URLEncodedStringWithOptions: (NSDataBase64EncodingOptions) options +{ + // This is not awesome but it works. + NSMutableString *encodedString = [NSMutableString stringWithString: [self base64EncodedStringWithOptions: options]]; + if (encodedString != nil) + { + [encodedString replaceOccurrencesOfString: @"+" withString: @"-" options:NSLiteralSearch range: NSMakeRange(0, [encodedString length])]; + [encodedString replaceOccurrencesOfString: @"/" withString: @"_" options:NSLiteralSearch range: NSMakeRange(0, [encodedString length])]; + + if ([encodedString hasSuffix: @"=="]) { + return [encodedString substringToIndex: [encodedString length] - 2]; + } + + if ([encodedString hasSuffix: @"="]) { + return [encodedString substringToIndex: [encodedString length] - 1]; + } + } + return encodedString; +} + +- (instancetype) initWithBase64URLEncodedString:(NSString *)base64String options:(NSDataBase64DecodingOptions)options +{ + NSMutableString *encodedString = [NSMutableString stringWithString: base64String]; + if (encodedString != nil) + { + [encodedString replaceOccurrencesOfString: @"-" withString: @"+" options:NSLiteralSearch range: NSMakeRange(0, [encodedString length])]; + [encodedString replaceOccurrencesOfString: @"_" withString: @"/" options:NSLiteralSearch range: NSMakeRange(0, [encodedString length])]; + + switch ([encodedString length] % 4) { + case 2: + [encodedString appendString: @"=="]; + break; + case 3: + [encodedString appendString: @"="]; + break; + } + } + + return [self initWithBase64EncodedString: encodedString options: options]; +} + +@end diff --git a/mobile/ios/FxA/FxA/NSString+Utils.h b/mobile/ios/FxA/FxA/NSString+Utils.h new file mode 100644 index 0000000000..e858dd90de --- /dev/null +++ b/mobile/ios/FxA/FxA/NSString+Utils.h @@ -0,0 +1,11 @@ +// 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/ + +#import + +@interface NSString (Utils) + ++ (NSString*) randomAlphanumericStringWithLength: (NSUInteger) length; + +@end diff --git a/mobile/ios/FxA/FxA/NSString+Utils.m b/mobile/ios/FxA/FxA/NSString+Utils.m new file mode 100644 index 0000000000..a6831ca370 --- /dev/null +++ b/mobile/ios/FxA/FxA/NSString+Utils.m @@ -0,0 +1,26 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + + +#import "NSString+Utils.h" + + +@implementation NSString (Utils) + ++ (NSString*) randomAlphanumericStringWithLength: (NSUInteger) length +{ + sranddev(); + + static char alphanumeric[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + NSMutableString *s = [NSMutableString string]; + + for (NSUInteger i = 0; i < length; i++) { + [s appendString: [NSString stringWithFormat: @"%c", alphanumeric[rand() % (sizeof alphanumeric - 1)]]]; + } + + return s; +} + +@end diff --git a/mobile/ios/FxA/FxA/PrivateKey.h b/mobile/ios/FxA/FxA/PrivateKey.h new file mode 100644 index 0000000000..460047bb79 --- /dev/null +++ b/mobile/ios/FxA/FxA/PrivateKey.h @@ -0,0 +1,20 @@ +// 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/ + + +#import + + +@interface PrivateKey : NSObject + +- (id) initWithJSONRepresentation: (NSDictionary*) object; + +- (NSDictionary*) JSONRepresentation; + +- (NSString*) algorithm; + +- (NSData*) signMessageString: (NSString*) string encoding: (NSStringEncoding) encoding; +- (NSData*) signMessage: (NSData*) data; + +@end diff --git a/mobile/ios/FxA/FxA/PrivateKey.m b/mobile/ios/FxA/FxA/PrivateKey.m new file mode 100644 index 0000000000..522a8bd373 --- /dev/null +++ b/mobile/ios/FxA/FxA/PrivateKey.m @@ -0,0 +1,41 @@ +// 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/ + + +#import "PrivateKey.h" + + +@implementation PrivateKey + +- (id) initWithJSONRepresentation: (NSDictionary*) object +{ + [self doesNotRecognizeSelector: _cmd]; + return nil; +} + +- (NSDictionary*) JSONRepresentation +{ + [self doesNotRecognizeSelector: _cmd]; + return nil; +} + +- (NSString*) algorithm +{ + [self doesNotRecognizeSelector: _cmd]; + return nil; +} + +- (NSData*) signMessageString: (NSString*) string encoding: (NSStringEncoding) encoding +{ + [self doesNotRecognizeSelector: _cmd]; + return nil; +} + +- (NSData*) signMessage: (NSData*) data +{ + [self doesNotRecognizeSelector: _cmd]; + return nil; +} + +@end diff --git a/mobile/ios/FxA/FxA/PublicKey.h b/mobile/ios/FxA/FxA/PublicKey.h new file mode 100644 index 0000000000..5cc23d8305 --- /dev/null +++ b/mobile/ios/FxA/FxA/PublicKey.h @@ -0,0 +1,20 @@ +// 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/ + + +#import + + +@interface PublicKey : NSObject + +- (id) initWithJSONRepresentation: (NSDictionary*) object; + +- (NSDictionary*) JSONRepresentation; + +- (NSString*) algorithm; + +- (BOOL) verifySignature: (NSData*) signature againstMessage: (NSData*) message; +- (BOOL) verifySignature: (NSData*) signature againstMessageString: (NSString*) message encoding: (NSStringEncoding) encoding; + +@end diff --git a/mobile/ios/FxA/FxA/PublicKey.m b/mobile/ios/FxA/FxA/PublicKey.m new file mode 100644 index 0000000000..b7eb7132da --- /dev/null +++ b/mobile/ios/FxA/FxA/PublicKey.m @@ -0,0 +1,41 @@ +// 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/ + + +#import "PublicKey.h" + + +@implementation PublicKey + +- (id) initWithJSONRepresentation: (NSDictionary*) object +{ + [self doesNotRecognizeSelector: _cmd]; + return nil; +} + +- (NSDictionary*) JSONRepresentation +{ + [self doesNotRecognizeSelector: _cmd]; + return nil; +} + +- (NSString*) algorithm +{ + [self doesNotRecognizeSelector: _cmd]; + return nil; +} + +- (BOOL) verifySignature: (NSData*) signature againstMessage: (NSData*) message +{ + [self doesNotRecognizeSelector: _cmd]; + return FALSE; +} + +- (BOOL) verifySignature: (NSData*) signature againstMessageString: (NSString*) message encoding: (NSStringEncoding) encoding +{ + [self doesNotRecognizeSelector: _cmd]; + return FALSE; +} + +@end diff --git a/mobile/ios/FxA/FxA/RSAKeyPair.h b/mobile/ios/FxA/FxA/RSAKeyPair.h new file mode 100644 index 0000000000..5abcf6d365 --- /dev/null +++ b/mobile/ios/FxA/FxA/RSAKeyPair.h @@ -0,0 +1,34 @@ +// 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/ + +#import "KeyPair.h" +#import "PrivateKey.h" +#import "PublicKey.h" +#import + + +@class CHNumber; +@class RSAKeyPair; + + +@interface RSAPrivateKey : PrivateKey +- (id) initWithModulus: (CHNumber*) n privateExponent: (CHNumber*) d; +@end + + +@interface RSAPublicKey : PublicKey +- (id) initWithModulus: (CHNumber*) n publicExponent: (CHNumber*) e; +@end + + +@interface RSAKeyPair : KeyPair + ++ (instancetype) generateKeyPairWithModulusSize: (int) size; + +- (instancetype) initWithModulus: (CHNumber*) n privateExponent: (CHNumber*) d publicExponent: (CHNumber*) e; + +@property (readonly) RSAPublicKey *publicKey; +@property (readonly) RSAPrivateKey *privateKey; + +@end diff --git a/mobile/ios/FxA/FxA/RSAKeyPair.m b/mobile/ios/FxA/FxA/RSAKeyPair.m new file mode 100644 index 0000000000..9e9831b6e8 --- /dev/null +++ b/mobile/ios/FxA/FxA/RSAKeyPair.m @@ -0,0 +1,297 @@ +// 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 +#include + +#include "CHNumber.h" +#import "RSAKeyPair.h" + + +@implementation RSAPrivateKey { + RSA *_rsa; +} + +- (id) initWithJSONRepresentation: (NSDictionary*) object +{ + CHNumber *n = [CHNumber numberWithString: object[@"n"]]; + CHNumber *d = [CHNumber numberWithString: object[@"d"]]; + if (n == nil || d == nil) { + return nil; + } + + return [self initWithModulus: n privateExponent: d]; +} + +- (id) initWithModulus: (CHNumber*) n privateExponent: (CHNumber*) d +{ + if ((self = [super init]) != nil) { + _rsa = RSA_new(); + BIGNUM* _e = BN_new(); + BIGNUM* _n = BN_dup([n bigNumValue]); + BIGNUM* _d = BN_dup([d bigNumValue]); + + if (_n == NULL || _e == NULL || _d == NULL) { + BN_free(_e); + BN_free(_n); + BN_free(_d); + return nil; + } + + if (BN_set_word(_e, RSA_F4) != 1) { + BN_free(_e); + BN_free(_n); + BN_free(_d); + return nil; + } + + if (RSA_set0_key(_rsa, _n, _e, _d) != 1) { + BN_free(_e); + BN_free(_n); + BN_free(_d); + return nil; + } + // Maybe there is some secret communication between a Java KeyPair where the Private Key can discover e from the associated Public Key? +// _rsa->p = BN_dup([p bigNumValue]); +// _rsa->q = BN_dup([q bigNumValue]); + } + return self; +} + +- (void) dealloc +{ + RSA_free(_rsa); + _rsa = NULL; +} + +- (NSDictionary*) JSONRepresentation +{ + BIGNUM *n, *d; + RSA_get0_key(_rsa, &n, NULL, &d); + if (n == NULL || d == NULL) { + return nil; + } + return @{ + @"algorithm": @"RS", + @"n": [[CHNumber numberWithOpenSSLNumber: n] stringValue], + @"d": [[CHNumber numberWithOpenSSLNumber: d] stringValue] + }; +} + +- (NSString*) algorithm +{ + BIGNUM *n; + RSA_get0_key(_rsa, &n, NULL, NULL); + if (n == NULL) { + return nil; + } + int sizeInBytes = (BN_num_bits(n) + 7)/8; + return [NSString stringWithFormat: @"RS%d", sizeInBytes]; +} + +- (NSData*) signMessageString: (NSString*) string encoding: (NSStringEncoding) encoding +{ + return [self signMessage: [string dataUsingEncoding: encoding]]; +} + +- (NSData*) signMessage: (NSData*) data +{ + NSData *signature = nil; + + EVP_PKEY *pkey = EVP_PKEY_new(); + if (pkey != NULL) { + if (EVP_PKEY_set1_RSA(pkey, _rsa)) { + EVP_MD_CTX *ctx = EVP_MD_CTX_create(); + if (ctx != NULL) { + if (EVP_SignInit_ex(ctx, EVP_sha256(), NULL)) { + if (EVP_SignUpdate(ctx, [data bytes], [data length])) { + unsigned int sig_size; + unsigned char *sig_data = malloc(EVP_PKEY_size(pkey)); + if (sig_data != NULL) { + if (EVP_SignFinal(ctx, sig_data, &sig_size, pkey)) { + signature = [NSData dataWithBytesNoCopy: sig_data length: sig_size freeWhenDone: YES]; + } + } + } + } + EVP_MD_CTX_destroy(ctx); + } + } + EVP_PKEY_free(pkey); + } + + return signature; +} + +@end + + +@implementation RSAPublicKey { + RSA *_rsa; +} + +- (id) initWithJSONRepresentation: (NSDictionary*) object +{ + CHNumber *n = [CHNumber numberWithString: object[@"n"]]; + CHNumber *e = [CHNumber numberWithString: object[@"e"]]; + if (n == nil || e == nil) { + return nil; + } + + return [self initWithModulus: n publicExponent: e]; +} + + +- (id) initWithModulus: (CHNumber*) n publicExponent: (CHNumber*) e; +{ + if ((self = [super init]) != nil) { + BIGNUM *_n = BN_dup([n bigNumValue]); + BIGNUM *_e = BN_dup([e bigNumValue]); + + if (_n == NULL || _e == NULL) { + BN_free(_n); + BN_free(_e); + return nil; + } + _rsa = RSA_new(); + if (RSA_set0_key(_rsa, _n, _e, NULL) != 1) { + BN_free(_n); + BN_free(_e); + return nil; + } + } + return self; +} + +- (void) dealloc +{ + RSA_free(_rsa); + _rsa = NULL; +} + +- (NSDictionary*) JSONRepresentation +{ + BIGNUM *n, *e; + RSA_get0_key(_rsa, &n, &e, NULL); + if (n == NULL || e == NULL) { + return nil; + } + return @{ + @"algorithm": @"RS", + @"n": [[CHNumber numberWithOpenSSLNumber: n] stringValue], + @"e": [[CHNumber numberWithOpenSSLNumber: e] stringValue] + }; +} + +- (NSString*) algorithm +{ + BIGNUM *n; + RSA_get0_key(_rsa, &n, NULL, NULL); + if (n == NULL) { + return nil; + } + int sizeInBytes = (BN_num_bits(n) + 7)/8; + return [NSString stringWithFormat: @"RS%d", sizeInBytes]; +} + +- (BOOL) verifySignature: (NSData*) signature againstMessage: (NSData*) message +{ + BOOL verified = NO; + + EVP_PKEY *pkey = EVP_PKEY_new(); + if (pkey != NULL) { + if (EVP_PKEY_set1_RSA(pkey, _rsa)) { + EVP_MD_CTX *ctx = EVP_MD_CTX_create(); + if (ctx != NULL) { + if (EVP_VerifyInit_ex(ctx, EVP_sha256(), NULL)) { + if (EVP_VerifyUpdate(ctx, [message bytes], [message length])) { + if (EVP_VerifyFinal(ctx, [signature bytes], [signature length], pkey)) { + verified = YES; + } + } + } + EVP_MD_CTX_destroy(ctx); + } + } + EVP_PKEY_free(pkey); + } + + return verified; +} + +- (BOOL) verifySignature: (NSData*) signature againstMessageString: (NSString*) message encoding: (NSStringEncoding) encoding +{ + return [self verifySignature: signature againstMessage: [message dataUsingEncoding: encoding]]; +} + +@end + + +@implementation RSAKeyPair + ++ (instancetype) generateKeyPairWithModulusSize: (int) modulusSize +{ + RSA* rsa = RSA_new(); + if (rsa == NULL) { + return nil; + } + + BIGNUM* exp = BN_new(); + BN_set_word(exp, RSA_F4); + if (!RSA_generate_key_ex(rsa, modulusSize, exp, NULL)) { + RSA_free(rsa); + BN_free(exp); + return nil; + } + BIGNUM *n, *e, *d; + RSA_get0_key(rsa, &n, &e, &d); + + if (n == NULL || e == NULL || d == NULL) { + RSA_free(rsa); + BN_free(exp); + return nil; + } + + RSAPublicKey *publicKey = [[RSAPublicKey alloc] initWithModulus: [CHNumber numberWithOpenSSLNumber: n] + publicExponent: [CHNumber numberWithOpenSSLNumber: e]]; + RSAPrivateKey *privateKey = [[RSAPrivateKey alloc] initWithModulus: [CHNumber numberWithOpenSSLNumber: n] + privateExponent: [CHNumber numberWithOpenSSLNumber: d]]; + + RSA_free(rsa); + + return [[self alloc] initWithPublicKey: publicKey privateKey: privateKey]; +} + +- (instancetype) initWithModulus: (CHNumber*) n privateExponent: (CHNumber*) d publicExponent: (CHNumber*) e +{ + RSAPrivateKey *privateKey = [[RSAPrivateKey alloc] initWithModulus: n privateExponent: d]; + if (privateKey == nil) { + return nil; + } + + RSAPublicKey *publicKey = [[RSAPublicKey alloc] initWithModulus: n publicExponent: e]; + if (privateKey == nil) { + return nil; + } + + return [self initWithPublicKey: publicKey privateKey: privateKey]; +} + +- (instancetype) initWithJSONRepresentation: (NSDictionary*) object +{ + RSAPublicKey *publicKey = [[RSAPublicKey alloc] initWithJSONRepresentation: object[@"publicKey"]]; + if (publicKey == nil) { + return nil; + } + + RSAPrivateKey *privateKey = [[RSAPrivateKey alloc] initWithJSONRepresentation: object[@"privateKey"]]; + if (privateKey == nil) { + return nil; + } + + return [self initWithPublicKey: publicKey privateKey: privateKey]; +} + +@end diff --git a/mobile/ios/FxA/FxA/include/openssl/aes.h b/mobile/ios/FxA/FxA/include/openssl/aes.h new file mode 100644 index 0000000000..245c552abd --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/aes.h @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_AES_H +# define HEADER_AES_H + +# include + +# include +# ifdef __cplusplus +extern "C" { +# endif + +# define AES_ENCRYPT 1 +# define AES_DECRYPT 0 + +/* + * Because array size can't be a const in C, the following two are macros. + * Both sizes are in bytes. + */ +# define AES_MAXNR 14 +# define AES_BLOCK_SIZE 16 + +/* This should be a hidden type, but EVP requires that the size be known */ +struct aes_key_st { +# ifdef AES_LONG + unsigned long rd_key[4 * (AES_MAXNR + 1)]; +# else + unsigned int rd_key[4 * (AES_MAXNR + 1)]; +# endif + int rounds; +}; +typedef struct aes_key_st AES_KEY; + +const char *AES_options(void); + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); + +void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key, const int enc); +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc); +void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, int *num, const int enc); +void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, int *num, const int enc); +void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, int *num, const int enc); +void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, int *num); +/* NB: the IV is _two_ blocks long */ +void AES_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc); +/* NB: the IV is _four_ blocks long */ +void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + const AES_KEY *key2, const unsigned char *ivec, + const int enc); + +int AES_wrap_key(AES_KEY *key, const unsigned char *iv, + unsigned char *out, + const unsigned char *in, unsigned int inlen); +int AES_unwrap_key(AES_KEY *key, const unsigned char *iv, + unsigned char *out, + const unsigned char *in, unsigned int inlen); + + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/asn1.h b/mobile/ios/FxA/FxA/include/openssl/asn1.h new file mode 100644 index 0000000000..7cf6116120 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/asn1.h @@ -0,0 +1,1096 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_ASN1_H +# define HEADER_ASN1_H + +# include +# include +# include +# include +# include +# include + +# include + +# include +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# endif + +# ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +# endif + +#ifdef __cplusplus +extern "C" { +#endif + +# define V_ASN1_UNIVERSAL 0x00 +# define V_ASN1_APPLICATION 0x40 +# define V_ASN1_CONTEXT_SPECIFIC 0x80 +# define V_ASN1_PRIVATE 0xc0 + +# define V_ASN1_CONSTRUCTED 0x20 +# define V_ASN1_PRIMITIVE_TAG 0x1f +# define V_ASN1_PRIMATIVE_TAG 0x1f + +# define V_ASN1_APP_CHOOSE -2/* let the recipient choose */ +# define V_ASN1_OTHER -3/* used in ASN1_TYPE */ +# define V_ASN1_ANY -4/* used in ASN1 template code */ + +# define V_ASN1_UNDEF -1 +/* ASN.1 tag values */ +# define V_ASN1_EOC 0 +# define V_ASN1_BOOLEAN 1 /**/ +# define V_ASN1_INTEGER 2 +# define V_ASN1_BIT_STRING 3 +# define V_ASN1_OCTET_STRING 4 +# define V_ASN1_NULL 5 +# define V_ASN1_OBJECT 6 +# define V_ASN1_OBJECT_DESCRIPTOR 7 +# define V_ASN1_EXTERNAL 8 +# define V_ASN1_REAL 9 +# define V_ASN1_ENUMERATED 10 +# define V_ASN1_UTF8STRING 12 +# define V_ASN1_SEQUENCE 16 +# define V_ASN1_SET 17 +# define V_ASN1_NUMERICSTRING 18 /**/ +# define V_ASN1_PRINTABLESTRING 19 +# define V_ASN1_T61STRING 20 +# define V_ASN1_TELETEXSTRING 20/* alias */ +# define V_ASN1_VIDEOTEXSTRING 21 /**/ +# define V_ASN1_IA5STRING 22 +# define V_ASN1_UTCTIME 23 +# define V_ASN1_GENERALIZEDTIME 24 /**/ +# define V_ASN1_GRAPHICSTRING 25 /**/ +# define V_ASN1_ISO64STRING 26 /**/ +# define V_ASN1_VISIBLESTRING 26/* alias */ +# define V_ASN1_GENERALSTRING 27 /**/ +# define V_ASN1_UNIVERSALSTRING 28 /**/ +# define V_ASN1_BMPSTRING 30 + +/* + * NB the constants below are used internally by ASN1_INTEGER + * and ASN1_ENUMERATED to indicate the sign. They are *not* on + * the wire tag values. + */ + +# define V_ASN1_NEG 0x100 +# define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG) +# define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG) + +/* For use with d2i_ASN1_type_bytes() */ +# define B_ASN1_NUMERICSTRING 0x0001 +# define B_ASN1_PRINTABLESTRING 0x0002 +# define B_ASN1_T61STRING 0x0004 +# define B_ASN1_TELETEXSTRING 0x0004 +# define B_ASN1_VIDEOTEXSTRING 0x0008 +# define B_ASN1_IA5STRING 0x0010 +# define B_ASN1_GRAPHICSTRING 0x0020 +# define B_ASN1_ISO64STRING 0x0040 +# define B_ASN1_VISIBLESTRING 0x0040 +# define B_ASN1_GENERALSTRING 0x0080 +# define B_ASN1_UNIVERSALSTRING 0x0100 +# define B_ASN1_OCTET_STRING 0x0200 +# define B_ASN1_BIT_STRING 0x0400 +# define B_ASN1_BMPSTRING 0x0800 +# define B_ASN1_UNKNOWN 0x1000 +# define B_ASN1_UTF8STRING 0x2000 +# define B_ASN1_UTCTIME 0x4000 +# define B_ASN1_GENERALIZEDTIME 0x8000 +# define B_ASN1_SEQUENCE 0x10000 +/* For use with ASN1_mbstring_copy() */ +# define MBSTRING_FLAG 0x1000 +# define MBSTRING_UTF8 (MBSTRING_FLAG) +# define MBSTRING_ASC (MBSTRING_FLAG|1) +# define MBSTRING_BMP (MBSTRING_FLAG|2) +# define MBSTRING_UNIV (MBSTRING_FLAG|4) +# define SMIME_OLDMIME 0x400 +# define SMIME_CRLFEOL 0x800 +# define SMIME_STREAM 0x1000 + struct X509_algor_st; +DEFINE_STACK_OF(X509_ALGOR) + +# define ASN1_STRING_FLAG_BITS_LEFT 0x08/* Set if 0x07 has bits left value */ +/* + * This indicates that the ASN1_STRING is not a real value but just a place + * holder for the location where indefinite length constructed data should be + * inserted in the memory buffer + */ +# define ASN1_STRING_FLAG_NDEF 0x010 + +/* + * This flag is used by the CMS code to indicate that a string is not + * complete and is a place holder for content when it had all been accessed. + * The flag will be reset when content has been written to it. + */ + +# define ASN1_STRING_FLAG_CONT 0x020 +/* + * This flag is used by ASN1 code to indicate an ASN1_STRING is an MSTRING + * type. + */ +# define ASN1_STRING_FLAG_MSTRING 0x040 +/* String is embedded and only content should be freed */ +# define ASN1_STRING_FLAG_EMBED 0x080 +/* This is the base type that holds just about everything :-) */ +struct asn1_string_st { + int length; + int type; + unsigned char *data; + /* + * The value of the following field depends on the type being held. It + * is mostly being used for BIT_STRING so if the input data has a + * non-zero 'unused bits' value, it will be handled correctly + */ + long flags; +}; + +/* + * ASN1_ENCODING structure: this is used to save the received encoding of an + * ASN1 type. This is useful to get round problems with invalid encodings + * which can break signatures. + */ + +typedef struct ASN1_ENCODING_st { + unsigned char *enc; /* DER encoding */ + long len; /* Length of encoding */ + int modified; /* set to 1 if 'enc' is invalid */ +} ASN1_ENCODING; + +/* Used with ASN1 LONG type: if a long is set to this it is omitted */ +# define ASN1_LONG_UNDEF 0x7fffffffL + +# define STABLE_FLAGS_MALLOC 0x01 +/* + * A zero passed to ASN1_STRING_TABLE_new_add for the flags is interpreted + * as "don't change" and STABLE_FLAGS_MALLOC is always set. By setting + * STABLE_FLAGS_MALLOC only we can clear the existing value. Use the alias + * STABLE_FLAGS_CLEAR to reflect this. + */ +# define STABLE_FLAGS_CLEAR STABLE_FLAGS_MALLOC +# define STABLE_NO_MASK 0x02 +# define DIRSTRING_TYPE \ + (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING) +# define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING) + +typedef struct asn1_string_table_st { + int nid; + long minsize; + long maxsize; + unsigned long mask; + unsigned long flags; +} ASN1_STRING_TABLE; + +DEFINE_STACK_OF(ASN1_STRING_TABLE) + +/* size limits: this stuff is taken straight from RFC2459 */ + +# define ub_name 32768 +# define ub_common_name 64 +# define ub_locality_name 128 +# define ub_state_name 128 +# define ub_organization_name 64 +# define ub_organization_unit_name 64 +# define ub_title 64 +# define ub_email_address 128 + +/* + * Declarations for template structures: for full definitions see asn1t.h + */ +typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE; +typedef struct ASN1_TLC_st ASN1_TLC; +/* This is just an opaque pointer */ +typedef struct ASN1_VALUE_st ASN1_VALUE; + +/* Declare ASN1 functions: the implement macro in in asn1t.h */ + +# define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type) + +# define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type) + +# define DECLARE_ASN1_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) + +# define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) + +# define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \ + type *d2i_##name(type **a, const unsigned char **in, long len); \ + int i2d_##name(type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(itname) + +# define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \ + type *d2i_##name(type **a, const unsigned char **in, long len); \ + int i2d_##name(const type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(name) + +# define DECLARE_ASN1_NDEF_FUNCTION(name) \ + int i2d_##name##_NDEF(name *a, unsigned char **out); + +# define DECLARE_ASN1_FUNCTIONS_const(name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS(name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS_const(name, name) + +# define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + type *name##_new(void); \ + void name##_free(type *a); + +# define DECLARE_ASN1_PRINT_FUNCTION(stname) \ + DECLARE_ASN1_PRINT_FUNCTION_fname(stname, stname) + +# define DECLARE_ASN1_PRINT_FUNCTION_fname(stname, fname) \ + int fname##_print_ctx(BIO *out, stname *x, int indent, \ + const ASN1_PCTX *pctx); + +# define D2I_OF(type) type *(*)(type **,const unsigned char **,long) +# define I2D_OF(type) int (*)(type *,unsigned char **) +# define I2D_OF_const(type) int (*)(const type *,unsigned char **) + +# define CHECKED_D2I_OF(type, d2i) \ + ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0))) +# define CHECKED_I2D_OF(type, i2d) \ + ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0))) +# define CHECKED_NEW_OF(type, xnew) \ + ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0))) +# define CHECKED_PTR_OF(type, p) \ + ((void*) (1 ? p : (type*)0)) +# define CHECKED_PPTR_OF(type, p) \ + ((void**) (1 ? p : (type**)0)) + +# define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **,const unsigned char **,long) +# define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(type *,unsigned char **) +# define TYPEDEF_D2I2D_OF(type) TYPEDEF_D2I_OF(type); TYPEDEF_I2D_OF(type) + +TYPEDEF_D2I2D_OF(void); + +/*- + * The following macros and typedefs allow an ASN1_ITEM + * to be embedded in a structure and referenced. Since + * the ASN1_ITEM pointers need to be globally accessible + * (possibly from shared libraries) they may exist in + * different forms. On platforms that support it the + * ASN1_ITEM structure itself will be globally exported. + * Other platforms will export a function that returns + * an ASN1_ITEM pointer. + * + * To handle both cases transparently the macros below + * should be used instead of hard coding an ASN1_ITEM + * pointer in a structure. + * + * The structure will look like this: + * + * typedef struct SOMETHING_st { + * ... + * ASN1_ITEM_EXP *iptr; + * ... + * } SOMETHING; + * + * It would be initialised as e.g.: + * + * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...}; + * + * and the actual pointer extracted with: + * + * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr); + * + * Finally an ASN1_ITEM pointer can be extracted from an + * appropriate reference with: ASN1_ITEM_rptr(X509). This + * would be used when a function takes an ASN1_ITEM * argument. + * + */ + +# ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* ASN1_ITEM pointer exported type */ +typedef const ASN1_ITEM ASN1_ITEM_EXP; + +/* Macro to obtain ASN1_ITEM pointer from exported type */ +# define ASN1_ITEM_ptr(iptr) (iptr) + +/* Macro to include ASN1_ITEM pointer from base type */ +# define ASN1_ITEM_ref(iptr) (&(iptr##_it)) + +# define ASN1_ITEM_rptr(ref) (&(ref##_it)) + +# define DECLARE_ASN1_ITEM(name) \ + OPENSSL_EXTERN const ASN1_ITEM name##_it; + +# else + +/* + * Platforms that can't easily handle shared global variables are declared as + * functions returning ASN1_ITEM pointers. + */ + +/* ASN1_ITEM pointer exported type */ +typedef const ASN1_ITEM *ASN1_ITEM_EXP (void); + +/* Macro to obtain ASN1_ITEM pointer from exported type */ +# define ASN1_ITEM_ptr(iptr) (iptr()) + +/* Macro to include ASN1_ITEM pointer from base type */ +# define ASN1_ITEM_ref(iptr) (iptr##_it) + +# define ASN1_ITEM_rptr(ref) (ref##_it()) + +# define DECLARE_ASN1_ITEM(name) \ + const ASN1_ITEM * name##_it(void); + +# endif + +/* Parameters used by ASN1_STRING_print_ex() */ + +/* + * These determine which characters to escape: RFC2253 special characters, + * control characters and MSB set characters + */ + +# define ASN1_STRFLGS_ESC_2253 1 +# define ASN1_STRFLGS_ESC_CTRL 2 +# define ASN1_STRFLGS_ESC_MSB 4 + +/* + * This flag determines how we do escaping: normally RC2253 backslash only, + * set this to use backslash and quote. + */ + +# define ASN1_STRFLGS_ESC_QUOTE 8 + +/* These three flags are internal use only. */ + +/* Character is a valid PrintableString character */ +# define CHARTYPE_PRINTABLESTRING 0x10 +/* Character needs escaping if it is the first character */ +# define CHARTYPE_FIRST_ESC_2253 0x20 +/* Character needs escaping if it is the last character */ +# define CHARTYPE_LAST_ESC_2253 0x40 + +/* + * NB the internal flags are safely reused below by flags handled at the top + * level. + */ + +/* + * If this is set we convert all character strings to UTF8 first + */ + +# define ASN1_STRFLGS_UTF8_CONVERT 0x10 + +/* + * If this is set we don't attempt to interpret content: just assume all + * strings are 1 byte per character. This will produce some pretty odd + * looking output! + */ + +# define ASN1_STRFLGS_IGNORE_TYPE 0x20 + +/* If this is set we include the string type in the output */ +# define ASN1_STRFLGS_SHOW_TYPE 0x40 + +/* + * This determines which strings to display and which to 'dump' (hex dump of + * content octets or DER encoding). We can only dump non character strings or + * everything. If we don't dump 'unknown' they are interpreted as character + * strings with 1 octet per character and are subject to the usual escaping + * options. + */ + +# define ASN1_STRFLGS_DUMP_ALL 0x80 +# define ASN1_STRFLGS_DUMP_UNKNOWN 0x100 + +/* + * These determine what 'dumping' does, we can dump the content octets or the + * DER encoding: both use the RFC2253 #XXXXX notation. + */ + +# define ASN1_STRFLGS_DUMP_DER 0x200 + +/* + * This flag specifies that RC2254 escaping shall be performed. + */ +#define ASN1_STRFLGS_ESC_2254 0x400 + +/* + * All the string flags consistent with RFC2253, escaping control characters + * isn't essential in RFC2253 but it is advisable anyway. + */ + +# define ASN1_STRFLGS_RFC2253 (ASN1_STRFLGS_ESC_2253 | \ + ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + ASN1_STRFLGS_UTF8_CONVERT | \ + ASN1_STRFLGS_DUMP_UNKNOWN | \ + ASN1_STRFLGS_DUMP_DER) + +DEFINE_STACK_OF(ASN1_INTEGER) + +DEFINE_STACK_OF(ASN1_GENERALSTRING) + +DEFINE_STACK_OF(ASN1_UTF8STRING) + +typedef struct asn1_type_st { + int type; + union { + char *ptr; + ASN1_BOOLEAN boolean; + ASN1_STRING *asn1_string; + ASN1_OBJECT *object; + ASN1_INTEGER *integer; + ASN1_ENUMERATED *enumerated; + ASN1_BIT_STRING *bit_string; + ASN1_OCTET_STRING *octet_string; + ASN1_PRINTABLESTRING *printablestring; + ASN1_T61STRING *t61string; + ASN1_IA5STRING *ia5string; + ASN1_GENERALSTRING *generalstring; + ASN1_BMPSTRING *bmpstring; + ASN1_UNIVERSALSTRING *universalstring; + ASN1_UTCTIME *utctime; + ASN1_GENERALIZEDTIME *generalizedtime; + ASN1_VISIBLESTRING *visiblestring; + ASN1_UTF8STRING *utf8string; + /* + * set and sequence are left complete and still contain the set or + * sequence bytes + */ + ASN1_STRING *set; + ASN1_STRING *sequence; + ASN1_VALUE *asn1_value; + } value; +} ASN1_TYPE; + +DEFINE_STACK_OF(ASN1_TYPE) + +typedef STACK_OF(ASN1_TYPE) ASN1_SEQUENCE_ANY; + +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SET_ANY) + +/* This is used to contain a list of bit names */ +typedef struct BIT_STRING_BITNAME_st { + int bitnum; + const char *lname; + const char *sname; +} BIT_STRING_BITNAME; + +# define B_ASN1_TIME \ + B_ASN1_UTCTIME | \ + B_ASN1_GENERALIZEDTIME + +# define B_ASN1_PRINTABLE \ + B_ASN1_NUMERICSTRING| \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_T61STRING| \ + B_ASN1_IA5STRING| \ + B_ASN1_BIT_STRING| \ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING|\ + B_ASN1_SEQUENCE|\ + B_ASN1_UNKNOWN + +# define B_ASN1_DIRECTORYSTRING \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_TELETEXSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_UTF8STRING + +# define B_ASN1_DISPLAYTEXT \ + B_ASN1_IA5STRING| \ + B_ASN1_VISIBLESTRING| \ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING + +DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE) + +int ASN1_TYPE_get(const ASN1_TYPE *a); +void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value); +int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value); +int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b); + +ASN1_TYPE *ASN1_TYPE_pack_sequence(const ASN1_ITEM *it, void *s, ASN1_TYPE **t); +void *ASN1_TYPE_unpack_sequence(const ASN1_ITEM *it, const ASN1_TYPE *t); + +ASN1_OBJECT *ASN1_OBJECT_new(void); +void ASN1_OBJECT_free(ASN1_OBJECT *a); +int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp); +ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, + long length); + +DECLARE_ASN1_ITEM(ASN1_OBJECT) + +DEFINE_STACK_OF(ASN1_OBJECT) + +ASN1_STRING *ASN1_STRING_new(void); +void ASN1_STRING_free(ASN1_STRING *a); +void ASN1_STRING_clear_free(ASN1_STRING *a); +int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str); +ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *a); +ASN1_STRING *ASN1_STRING_type_new(int type); +int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b); + /* + * Since this is used to store all sorts of things, via macros, for now, + * make its data void * + */ +int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len); +void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len); +int ASN1_STRING_length(const ASN1_STRING *x); +void ASN1_STRING_length_set(ASN1_STRING *x, int n); +int ASN1_STRING_type(const ASN1_STRING *x); +DEPRECATEDIN_1_1_0(unsigned char *ASN1_STRING_data(ASN1_STRING *x)) +const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x); + +DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING) +int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, int length); +int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value); +int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n); +int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a, + const unsigned char *flags, int flags_len); + +int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs, + BIT_STRING_BITNAME *tbl, int indent); +int ASN1_BIT_STRING_num_asc(const char *name, BIT_STRING_BITNAME *tbl); +int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, const char *name, int value, + BIT_STRING_BITNAME *tbl); + +DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER) +ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp, + long length); +ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x); +int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y); + +DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED) + +int ASN1_UTCTIME_check(const ASN1_UTCTIME *a); +ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t); +ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, + int offset_day, long offset_sec); +int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str); +int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t); + +int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a); +ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, + time_t t); +ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, + time_t t, int offset_day, + long offset_sec); +int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str); +int ASN1_TIME_diff(int *pday, int *psec, + const ASN1_TIME *from, const ASN1_TIME *to); + +DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING) +ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *a); +int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, + const ASN1_OCTET_STRING *b); +int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, + int len); + +DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_NULL) +DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING) + +int UTF8_getc(const unsigned char *str, int len, unsigned long *val); +int UTF8_putc(unsigned char *str, int len, unsigned long value); + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE) + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING) +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT) +DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_TIME) + +DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF) + +ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t); +ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, + int offset_day, long offset_sec); +int ASN1_TIME_check(const ASN1_TIME *t); +ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME + **out); +int ASN1_TIME_set_string(ASN1_TIME *s, const char *str); + +int i2a_ASN1_INTEGER(BIO *bp, const ASN1_INTEGER *a); +int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size); +int i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a); +int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size); +int i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a); +int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size); +int i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *a, int type); +int i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *a); + +int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num); +ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data, int len, + const char *sn, const char *ln); + +int ASN1_INTEGER_get_int64(int64_t *pr, const ASN1_INTEGER *a); +int ASN1_INTEGER_set_int64(ASN1_INTEGER *a, int64_t r); +int ASN1_INTEGER_get_uint64(uint64_t *pr, const ASN1_INTEGER *a); +int ASN1_INTEGER_set_uint64(ASN1_INTEGER *a, uint64_t r); + +int ASN1_INTEGER_set(ASN1_INTEGER *a, long v); +long ASN1_INTEGER_get(const ASN1_INTEGER *a); +ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai); +BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn); + +int ASN1_ENUMERATED_get_int64(int64_t *pr, const ASN1_ENUMERATED *a); +int ASN1_ENUMERATED_set_int64(ASN1_ENUMERATED *a, int64_t r); + + +int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v); +long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a); +ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(const BIGNUM *bn, ASN1_ENUMERATED *ai); +BIGNUM *ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai, BIGNUM *bn); + +/* General */ +/* given a string, return the correct type, max is the maximum length */ +int ASN1_PRINTABLE_type(const unsigned char *s, int max); + +unsigned long ASN1_tag2bit(int tag); + +/* SPECIALS */ +int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, + int *pclass, long omax); +int ASN1_check_infinite_end(unsigned char **p, long len); +int ASN1_const_check_infinite_end(const unsigned char **p, long len); +void ASN1_put_object(unsigned char **pp, int constructed, int length, + int tag, int xclass); +int ASN1_put_eoc(unsigned char **pp); +int ASN1_object_size(int constructed, int length, int tag); + +/* Used to implement other functions */ +void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x); + +# define ASN1_dup_of(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(type, x))) + +# define ASN1_dup_of_const(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(const type, x))) + +void *ASN1_item_dup(const ASN1_ITEM *it, void *x); + +/* ASN1 alloc/free macros for when a type is only used internally */ + +# define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type)) +# define M_ASN1_free_of(x, type) \ + ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type)) + +# ifndef OPENSSL_NO_STDIO +void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x); + +# define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x); +int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x); + +# define ASN1_i2d_fp_of(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +# define ASN1_i2d_fp_of_const(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x); +int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str, unsigned long flags); +# endif + +int ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in); + +void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x); + +# define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x); +int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x); + +# define ASN1_i2d_bio_of(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +# define ASN1_i2d_bio_of_const(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x); +int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a); +int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a); +int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a); +int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v); +int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, unsigned long flags); +int ASN1_buf_print(BIO *bp, const unsigned char *buf, size_t buflen, int off); +int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num, + unsigned char *buf, int off); +int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent); +int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, + int dump); +const char *ASN1_tag2str(int tag); + +/* Used to load and write Netscape format cert */ + +int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s); + +int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len); +int ASN1_TYPE_get_octetstring(const ASN1_TYPE *a, unsigned char *data, int max_len); +int ASN1_TYPE_set_int_octetstring(ASN1_TYPE *a, long num, + unsigned char *data, int len); +int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num, + unsigned char *data, int max_len); + +void *ASN1_item_unpack(const ASN1_STRING *oct, const ASN1_ITEM *it); + +ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, + ASN1_OCTET_STRING **oct); + +void ASN1_STRING_set_default_mask(unsigned long mask); +int ASN1_STRING_set_default_mask_asc(const char *p); +unsigned long ASN1_STRING_get_default_mask(void); +int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask); +int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask, + long minsize, long maxsize); + +ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, + const unsigned char *in, int inlen, + int inform, int nid); +ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid); +int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long); +void ASN1_STRING_TABLE_cleanup(void); + +/* ASN1 template functions */ + +/* Old API compatible functions */ +ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it); +void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it); +ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, + long len, const ASN1_ITEM *it); +int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); +int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it); + +void ASN1_add_oid_module(void); +void ASN1_add_stable_module(void); + +ASN1_TYPE *ASN1_generate_nconf(const char *str, CONF *nconf); +ASN1_TYPE *ASN1_generate_v3(const char *str, X509V3_CTX *cnf); +int ASN1_str2mask(const char *str, unsigned long *pmask); + +/* ASN1 Print flags */ + +/* Indicate missing OPTIONAL fields */ +# define ASN1_PCTX_FLAGS_SHOW_ABSENT 0x001 +/* Mark start and end of SEQUENCE */ +# define ASN1_PCTX_FLAGS_SHOW_SEQUENCE 0x002 +/* Mark start and end of SEQUENCE/SET OF */ +# define ASN1_PCTX_FLAGS_SHOW_SSOF 0x004 +/* Show the ASN1 type of primitives */ +# define ASN1_PCTX_FLAGS_SHOW_TYPE 0x008 +/* Don't show ASN1 type of ANY */ +# define ASN1_PCTX_FLAGS_NO_ANY_TYPE 0x010 +/* Don't show ASN1 type of MSTRINGs */ +# define ASN1_PCTX_FLAGS_NO_MSTRING_TYPE 0x020 +/* Don't show field names in SEQUENCE */ +# define ASN1_PCTX_FLAGS_NO_FIELD_NAME 0x040 +/* Show structure names of each SEQUENCE field */ +# define ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME 0x080 +/* Don't show structure name even at top level */ +# define ASN1_PCTX_FLAGS_NO_STRUCT_NAME 0x100 + +int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, + const ASN1_ITEM *it, const ASN1_PCTX *pctx); +ASN1_PCTX *ASN1_PCTX_new(void); +void ASN1_PCTX_free(ASN1_PCTX *p); +unsigned long ASN1_PCTX_get_flags(const ASN1_PCTX *p); +void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags); +unsigned long ASN1_PCTX_get_nm_flags(const ASN1_PCTX *p); +void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags); +unsigned long ASN1_PCTX_get_cert_flags(const ASN1_PCTX *p); +void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags); +unsigned long ASN1_PCTX_get_oid_flags(const ASN1_PCTX *p); +void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags); +unsigned long ASN1_PCTX_get_str_flags(const ASN1_PCTX *p); +void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags); + +ASN1_SCTX *ASN1_SCTX_new(int (*scan_cb) (ASN1_SCTX *ctx)); +void ASN1_SCTX_free(ASN1_SCTX *p); +const ASN1_ITEM *ASN1_SCTX_get_item(ASN1_SCTX *p); +const ASN1_TEMPLATE *ASN1_SCTX_get_template(ASN1_SCTX *p); +unsigned long ASN1_SCTX_get_flags(ASN1_SCTX *p); +void ASN1_SCTX_set_app_data(ASN1_SCTX *p, void *data); +void *ASN1_SCTX_get_app_data(ASN1_SCTX *p); + +const BIO_METHOD *BIO_f_asn1(void); + +BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it); + +int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, + const ASN1_ITEM *it); +int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, + const char *hdr, const ASN1_ITEM *it); +int SMIME_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags, + int ctype_nid, int econt_nid, + STACK_OF(X509_ALGOR) *mdalgs, const ASN1_ITEM *it); +ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it); +int SMIME_crlf_copy(BIO *in, BIO *out, int flags); +int SMIME_text(BIO *in, BIO *out); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_ASN1_strings(void); + +/* Error codes for the ASN1 functions. */ + +/* Function codes. */ +# define ASN1_F_A2D_ASN1_OBJECT 100 +# define ASN1_F_A2I_ASN1_INTEGER 102 +# define ASN1_F_A2I_ASN1_STRING 103 +# define ASN1_F_APPEND_EXP 176 +# define ASN1_F_ASN1_BIT_STRING_SET_BIT 183 +# define ASN1_F_ASN1_CB 177 +# define ASN1_F_ASN1_CHECK_TLEN 104 +# define ASN1_F_ASN1_COLLECT 106 +# define ASN1_F_ASN1_D2I_EX_PRIMITIVE 108 +# define ASN1_F_ASN1_D2I_FP 109 +# define ASN1_F_ASN1_D2I_READ_BIO 107 +# define ASN1_F_ASN1_DIGEST 184 +# define ASN1_F_ASN1_DO_ADB 110 +# define ASN1_F_ASN1_DO_LOCK 233 +# define ASN1_F_ASN1_DUP 111 +# define ASN1_F_ASN1_EX_C2I 204 +# define ASN1_F_ASN1_FIND_END 190 +# define ASN1_F_ASN1_GENERALIZEDTIME_ADJ 216 +# define ASN1_F_ASN1_GENERATE_V3 178 +# define ASN1_F_ASN1_GET_INT64 224 +# define ASN1_F_ASN1_GET_OBJECT 114 +# define ASN1_F_ASN1_GET_UINT64 225 +# define ASN1_F_ASN1_I2D_BIO 116 +# define ASN1_F_ASN1_I2D_FP 117 +# define ASN1_F_ASN1_ITEM_D2I_FP 206 +# define ASN1_F_ASN1_ITEM_DUP 191 +# define ASN1_F_ASN1_ITEM_EMBED_D2I 120 +# define ASN1_F_ASN1_ITEM_EMBED_NEW 121 +# define ASN1_F_ASN1_ITEM_I2D_BIO 192 +# define ASN1_F_ASN1_ITEM_I2D_FP 193 +# define ASN1_F_ASN1_ITEM_PACK 198 +# define ASN1_F_ASN1_ITEM_SIGN 195 +# define ASN1_F_ASN1_ITEM_SIGN_CTX 220 +# define ASN1_F_ASN1_ITEM_UNPACK 199 +# define ASN1_F_ASN1_ITEM_VERIFY 197 +# define ASN1_F_ASN1_MBSTRING_NCOPY 122 +# define ASN1_F_ASN1_OBJECT_NEW 123 +# define ASN1_F_ASN1_OUTPUT_DATA 214 +# define ASN1_F_ASN1_PCTX_NEW 205 +# define ASN1_F_ASN1_SCTX_NEW 221 +# define ASN1_F_ASN1_SIGN 128 +# define ASN1_F_ASN1_STR2TYPE 179 +# define ASN1_F_ASN1_STRING_GET_INT64 227 +# define ASN1_F_ASN1_STRING_GET_UINT64 230 +# define ASN1_F_ASN1_STRING_SET 186 +# define ASN1_F_ASN1_STRING_TABLE_ADD 129 +# define ASN1_F_ASN1_STRING_TO_BN 228 +# define ASN1_F_ASN1_STRING_TYPE_NEW 130 +# define ASN1_F_ASN1_TEMPLATE_EX_D2I 132 +# define ASN1_F_ASN1_TEMPLATE_NEW 133 +# define ASN1_F_ASN1_TEMPLATE_NOEXP_D2I 131 +# define ASN1_F_ASN1_TIME_ADJ 217 +# define ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING 134 +# define ASN1_F_ASN1_TYPE_GET_OCTETSTRING 135 +# define ASN1_F_ASN1_UTCTIME_ADJ 218 +# define ASN1_F_ASN1_VERIFY 137 +# define ASN1_F_B64_READ_ASN1 209 +# define ASN1_F_B64_WRITE_ASN1 210 +# define ASN1_F_BIO_NEW_NDEF 208 +# define ASN1_F_BITSTR_CB 180 +# define ASN1_F_BN_TO_ASN1_STRING 229 +# define ASN1_F_C2I_ASN1_BIT_STRING 189 +# define ASN1_F_C2I_ASN1_INTEGER 194 +# define ASN1_F_C2I_ASN1_OBJECT 196 +# define ASN1_F_C2I_IBUF 226 +# define ASN1_F_COLLECT_DATA 140 +# define ASN1_F_D2I_ASN1_OBJECT 147 +# define ASN1_F_D2I_ASN1_UINTEGER 150 +# define ASN1_F_D2I_AUTOPRIVATEKEY 207 +# define ASN1_F_D2I_PRIVATEKEY 154 +# define ASN1_F_D2I_PUBLICKEY 155 +# define ASN1_F_DO_TCREATE 222 +# define ASN1_F_I2D_ASN1_BIO_STREAM 211 +# define ASN1_F_I2D_DSA_PUBKEY 161 +# define ASN1_F_I2D_EC_PUBKEY 181 +# define ASN1_F_I2D_PRIVATEKEY 163 +# define ASN1_F_I2D_PUBLICKEY 164 +# define ASN1_F_I2D_RSA_PUBKEY 165 +# define ASN1_F_LONG_C2I 166 +# define ASN1_F_OID_MODULE_INIT 174 +# define ASN1_F_PARSE_TAGGING 182 +# define ASN1_F_PKCS5_PBE2_SET_IV 167 +# define ASN1_F_PKCS5_PBE2_SET_SCRYPT 231 +# define ASN1_F_PKCS5_PBE_SET 202 +# define ASN1_F_PKCS5_PBE_SET0_ALGOR 215 +# define ASN1_F_PKCS5_PBKDF2_SET 219 +# define ASN1_F_PKCS5_SCRYPT_SET 232 +# define ASN1_F_SMIME_READ_ASN1 212 +# define ASN1_F_SMIME_TEXT 213 +# define ASN1_F_STBL_MODULE_INIT 223 +# define ASN1_F_X509_CRL_ADD0_REVOKED 169 +# define ASN1_F_X509_INFO_NEW 170 +# define ASN1_F_X509_NAME_ENCODE 203 +# define ASN1_F_X509_NAME_EX_D2I 158 +# define ASN1_F_X509_NAME_EX_NEW 171 +# define ASN1_F_X509_PKEY_NEW 173 + +/* Reason codes. */ +# define ASN1_R_ADDING_OBJECT 171 +# define ASN1_R_ASN1_PARSE_ERROR 203 +# define ASN1_R_ASN1_SIG_PARSE_ERROR 204 +# define ASN1_R_AUX_ERROR 100 +# define ASN1_R_BAD_OBJECT_HEADER 102 +# define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 214 +# define ASN1_R_BN_LIB 105 +# define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 +# define ASN1_R_BUFFER_TOO_SMALL 107 +# define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 108 +# define ASN1_R_CONTEXT_NOT_INITIALISED 217 +# define ASN1_R_DATA_IS_WRONG 109 +# define ASN1_R_DECODE_ERROR 110 +# define ASN1_R_DEPTH_EXCEEDED 174 +# define ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 198 +# define ASN1_R_ENCODE_ERROR 112 +# define ASN1_R_ERROR_GETTING_TIME 173 +# define ASN1_R_ERROR_LOADING_SECTION 172 +# define ASN1_R_ERROR_SETTING_CIPHER_PARAMS 114 +# define ASN1_R_EXPECTING_AN_INTEGER 115 +# define ASN1_R_EXPECTING_AN_OBJECT 116 +# define ASN1_R_EXPLICIT_LENGTH_MISMATCH 119 +# define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 120 +# define ASN1_R_FIELD_MISSING 121 +# define ASN1_R_FIRST_NUM_TOO_LARGE 122 +# define ASN1_R_HEADER_TOO_LONG 123 +# define ASN1_R_ILLEGAL_BITSTRING_FORMAT 175 +# define ASN1_R_ILLEGAL_BOOLEAN 176 +# define ASN1_R_ILLEGAL_CHARACTERS 124 +# define ASN1_R_ILLEGAL_FORMAT 177 +# define ASN1_R_ILLEGAL_HEX 178 +# define ASN1_R_ILLEGAL_IMPLICIT_TAG 179 +# define ASN1_R_ILLEGAL_INTEGER 180 +# define ASN1_R_ILLEGAL_NEGATIVE_VALUE 226 +# define ASN1_R_ILLEGAL_NESTED_TAGGING 181 +# define ASN1_R_ILLEGAL_NULL 125 +# define ASN1_R_ILLEGAL_NULL_VALUE 182 +# define ASN1_R_ILLEGAL_OBJECT 183 +# define ASN1_R_ILLEGAL_OPTIONAL_ANY 126 +# define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 170 +# define ASN1_R_ILLEGAL_PADDING 221 +# define ASN1_R_ILLEGAL_TAGGED_ANY 127 +# define ASN1_R_ILLEGAL_TIME_VALUE 184 +# define ASN1_R_ILLEGAL_ZERO_CONTENT 222 +# define ASN1_R_INTEGER_NOT_ASCII_FORMAT 185 +# define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 128 +# define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 220 +# define ASN1_R_INVALID_BMPSTRING_LENGTH 129 +# define ASN1_R_INVALID_DIGIT 130 +# define ASN1_R_INVALID_MIME_TYPE 205 +# define ASN1_R_INVALID_MODIFIER 186 +# define ASN1_R_INVALID_NUMBER 187 +# define ASN1_R_INVALID_OBJECT_ENCODING 216 +# define ASN1_R_INVALID_SCRYPT_PARAMETERS 227 +# define ASN1_R_INVALID_SEPARATOR 131 +# define ASN1_R_INVALID_STRING_TABLE_VALUE 218 +# define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 133 +# define ASN1_R_INVALID_UTF8STRING 134 +# define ASN1_R_INVALID_VALUE 219 +# define ASN1_R_LIST_ERROR 188 +# define ASN1_R_MIME_NO_CONTENT_TYPE 206 +# define ASN1_R_MIME_PARSE_ERROR 207 +# define ASN1_R_MIME_SIG_PARSE_ERROR 208 +# define ASN1_R_MISSING_EOC 137 +# define ASN1_R_MISSING_SECOND_NUMBER 138 +# define ASN1_R_MISSING_VALUE 189 +# define ASN1_R_MSTRING_NOT_UNIVERSAL 139 +# define ASN1_R_MSTRING_WRONG_TAG 140 +# define ASN1_R_NESTED_ASN1_STRING 197 +# define ASN1_R_NON_HEX_CHARACTERS 141 +# define ASN1_R_NOT_ASCII_FORMAT 190 +# define ASN1_R_NOT_ENOUGH_DATA 142 +# define ASN1_R_NO_CONTENT_TYPE 209 +# define ASN1_R_NO_MATCHING_CHOICE_TYPE 143 +# define ASN1_R_NO_MULTIPART_BODY_FAILURE 210 +# define ASN1_R_NO_MULTIPART_BOUNDARY 211 +# define ASN1_R_NO_SIG_CONTENT_TYPE 212 +# define ASN1_R_NULL_IS_WRONG_LENGTH 144 +# define ASN1_R_OBJECT_NOT_ASCII_FORMAT 191 +# define ASN1_R_ODD_NUMBER_OF_CHARS 145 +# define ASN1_R_SECOND_NUMBER_TOO_LARGE 147 +# define ASN1_R_SEQUENCE_LENGTH_MISMATCH 148 +# define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 149 +# define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 192 +# define ASN1_R_SHORT_LINE 150 +# define ASN1_R_SIG_INVALID_MIME_TYPE 213 +# define ASN1_R_STREAMING_NOT_SUPPORTED 202 +# define ASN1_R_STRING_TOO_LONG 151 +# define ASN1_R_STRING_TOO_SHORT 152 +# define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 154 +# define ASN1_R_TIME_NOT_ASCII_FORMAT 193 +# define ASN1_R_TOO_LARGE 223 +# define ASN1_R_TOO_LONG 155 +# define ASN1_R_TOO_SMALL 224 +# define ASN1_R_TYPE_NOT_CONSTRUCTED 156 +# define ASN1_R_TYPE_NOT_PRIMITIVE 195 +# define ASN1_R_UNEXPECTED_EOC 159 +# define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 215 +# define ASN1_R_UNKNOWN_FORMAT 160 +# define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 161 +# define ASN1_R_UNKNOWN_OBJECT_TYPE 162 +# define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE 163 +# define ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM 199 +# define ASN1_R_UNKNOWN_TAG 194 +# define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 164 +# define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 167 +# define ASN1_R_UNSUPPORTED_TYPE 196 +# define ASN1_R_WRONG_INTEGER_TYPE 225 +# define ASN1_R_WRONG_PUBLIC_KEY_TYPE 200 +# define ASN1_R_WRONG_TAG 168 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/asn1_mac.h b/mobile/ios/FxA/FxA/include/openssl/asn1_mac.h new file mode 100644 index 0000000000..7ac1782a3f --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/asn1_mac.h @@ -0,0 +1,10 @@ +/* + * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#error "This file is obsolete; please update your software." diff --git a/mobile/ios/FxA/FxA/include/openssl/asn1t.h b/mobile/ios/FxA/FxA/include/openssl/asn1t.h new file mode 100644 index 0000000000..8eedfb3f43 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/asn1t.h @@ -0,0 +1,924 @@ +/* + * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_ASN1T_H +# define HEADER_ASN1T_H + +# include +# include +# include + +# ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +# endif + +/* ASN1 template defines, structures and functions */ + +#ifdef __cplusplus +extern "C" { +#endif + +# ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */ +# define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr)) + +/* Macros for start and end of ASN1_ITEM definition */ + +# define ASN1_ITEM_start(itname) \ + OPENSSL_GLOBAL const ASN1_ITEM itname##_it = { + +# define static_ASN1_ITEM_start(itname) \ + static const ASN1_ITEM itname##_it = { + +# define ASN1_ITEM_end(itname) \ + }; + +# else + +/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */ +# define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr())) + +/* Macros for start and end of ASN1_ITEM definition */ + +# define ASN1_ITEM_start(itname) \ + const ASN1_ITEM * itname##_it(void) \ + { \ + static const ASN1_ITEM local_it = { + +# define static_ASN1_ITEM_start(itname) \ + static ASN1_ITEM_start(itname) + +# define ASN1_ITEM_end(itname) \ + }; \ + return &local_it; \ + } + +# endif + +/* Macros to aid ASN1 template writing */ + +# define ASN1_ITEM_TEMPLATE(tname) \ + static const ASN1_TEMPLATE tname##_item_tt + +# define ASN1_ITEM_TEMPLATE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_PRIMITIVE,\ + -1,\ + &tname##_item_tt,\ + 0,\ + NULL,\ + 0,\ + #tname \ + ASN1_ITEM_end(tname) +# define static_ASN1_ITEM_TEMPLATE_END(tname) \ + ;\ + static_ASN1_ITEM_start(tname) \ + ASN1_ITYPE_PRIMITIVE,\ + -1,\ + &tname##_item_tt,\ + 0,\ + NULL,\ + 0,\ + #tname \ + ASN1_ITEM_end(tname) + +/* This is a ASN1 type which just embeds a template */ + +/*- + * This pair helps declare a SEQUENCE. We can do: + * + * ASN1_SEQUENCE(stname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END(stname) + * + * This will produce an ASN1_ITEM called stname_it + * for a structure called stname. + * + * If you want the same structure but a different + * name then use: + * + * ASN1_SEQUENCE(itname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END_name(stname, itname) + * + * This will create an item called itname_it using + * a structure called stname. + */ + +# define ASN1_SEQUENCE(tname) \ + static const ASN1_TEMPLATE tname##_seq_tt[] + +# define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname) + +# define static_ASN1_SEQUENCE_END(stname) static_ASN1_SEQUENCE_END_name(stname, stname) + +# define ASN1_SEQUENCE_END_name(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +# define static_ASN1_SEQUENCE_END_name(stname, tname) \ + ;\ + static_ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +# define ASN1_NDEF_SEQUENCE(tname) \ + ASN1_SEQUENCE(tname) + +# define ASN1_NDEF_SEQUENCE_cb(tname, cb) \ + ASN1_SEQUENCE_cb(tname, cb) + +# define ASN1_SEQUENCE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \ + ASN1_SEQUENCE(tname) + +# define ASN1_BROKEN_SEQUENCE(tname) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0, 0}; \ + ASN1_SEQUENCE(tname) + +# define ASN1_SEQUENCE_ref(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), offsetof(tname, lock), cb, 0}; \ + ASN1_SEQUENCE(tname) + +# define ASN1_SEQUENCE_enc(tname, enc, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, 0, cb, offsetof(tname, enc)}; \ + ASN1_SEQUENCE(tname) + +# define ASN1_NDEF_SEQUENCE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(tname),\ + #tname \ + ASN1_ITEM_end(tname) +# define static_ASN1_NDEF_SEQUENCE_END(tname) \ + ;\ + static_ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(tname),\ + #tname \ + ASN1_ITEM_end(tname) + +# define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname) +# define static_ASN1_BROKEN_SEQUENCE_END(stname) \ + static_ASN1_SEQUENCE_END_ref(stname, stname) + +# define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +# define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) +# define static_ASN1_SEQUENCE_END_cb(stname, tname) static_ASN1_SEQUENCE_END_ref(stname, tname) + +# define ASN1_SEQUENCE_END_ref(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) +# define static_ASN1_SEQUENCE_END_ref(stname, tname) \ + ;\ + static_ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +# define ASN1_NDEF_SEQUENCE_END_cb(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +/*- + * This pair helps declare a CHOICE type. We can do: + * + * ASN1_CHOICE(chname) = { + * ... CHOICE options ... + * ASN1_CHOICE_END(chname) + * + * This will produce an ASN1_ITEM called chname_it + * for a structure called chname. The structure + * definition must look like this: + * typedef struct { + * int type; + * union { + * ASN1_SOMETHING *opt1; + * ASN1_SOMEOTHER *opt2; + * } value; + * } chname; + * + * the name of the selector must be 'type'. + * to use an alternative selector name use the + * ASN1_CHOICE_END_selector() version. + */ + +# define ASN1_CHOICE(tname) \ + static const ASN1_TEMPLATE tname##_ch_tt[] + +# define ASN1_CHOICE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \ + ASN1_CHOICE(tname) + +# define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname) + +# define static_ASN1_CHOICE_END(stname) static_ASN1_CHOICE_END_name(stname, stname) + +# define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type) + +# define static_ASN1_CHOICE_END_name(stname, tname) static_ASN1_CHOICE_END_selector(stname, tname, type) + +# define ASN1_CHOICE_END_selector(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +# define static_ASN1_CHOICE_END_selector(stname, tname, selname) \ + ;\ + static_ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +# define ASN1_CHOICE_END_cb(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +/* This helps with the template wrapper form of ASN1_ITEM */ + +# define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \ + (flags), (tag), 0,\ + #name, ASN1_ITEM_ref(type) } + +/* These help with SEQUENCE or CHOICE components */ + +/* used to declare other types */ + +# define ASN1_EX_TYPE(flags, tag, stname, field, type) { \ + (flags), (tag), offsetof(stname, field),\ + #field, ASN1_ITEM_ref(type) } + +/* implicit and explicit helper macros */ + +# define ASN1_IMP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type) + +# define ASN1_EXP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type) + +/* Any defined by macros: the field used is in the table itself */ + +# ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION +# define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +# define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +# else +# define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, tblname##_adb } +# define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, tblname##_adb } +# endif +/* Plain simple type */ +# define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type) +/* Embedded simple type */ +# define ASN1_EMBED(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_EMBED,0, stname, field, type) + +/* OPTIONAL simple type */ +# define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* IMPLICIT tagged simple type */ +# define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0) + +/* IMPLICIT tagged OPTIONAL simple type */ +# define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* Same as above but EXPLICIT */ + +# define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0) +# define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* SEQUENCE OF type */ +# define ASN1_SEQUENCE_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type) + +/* OPTIONAL SEQUENCE OF */ +# define ASN1_SEQUENCE_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Same as above but for SET OF */ + +# define ASN1_SET_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type) + +# define ASN1_SET_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */ + +# define ASN1_IMP_SET_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +# define ASN1_EXP_SET_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +# define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +# define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +# define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +# define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +# define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +# define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +/* EXPLICIT using indefinite length constructed form */ +# define ASN1_NDEF_EXP(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF) + +/* EXPLICIT OPTIONAL using indefinite length constructed form */ +# define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF) + +/* Macros for the ASN1_ADB structure */ + +# define ASN1_ADB(name) \ + static const ASN1_ADB_TABLE name##_adbtbl[] + +# ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION + +# define ASN1_ADB_END(name, flags, field, adb_cb, def, none) \ + ;\ + static const ASN1_ADB name##_adb = {\ + flags,\ + offsetof(name, field),\ + adb_cb,\ + name##_adbtbl,\ + sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\ + def,\ + none\ + } + +# else + +# define ASN1_ADB_END(name, flags, field, adb_cb, def, none) \ + ;\ + static const ASN1_ITEM *name##_adb(void) \ + { \ + static const ASN1_ADB internal_adb = \ + {\ + flags,\ + offsetof(name, field),\ + adb_cb,\ + name##_adbtbl,\ + sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\ + def,\ + none\ + }; \ + return (const ASN1_ITEM *) &internal_adb; \ + } \ + void dummy_function(void) + +# endif + +# define ADB_ENTRY(val, template) {val, template} + +# define ASN1_ADB_TEMPLATE(name) \ + static const ASN1_TEMPLATE name##_tt + +/* + * This is the ASN1 template structure that defines a wrapper round the + * actual type. It determines the actual position of the field in the value + * structure, various flags such as OPTIONAL and the field name. + */ + +struct ASN1_TEMPLATE_st { + unsigned long flags; /* Various flags */ + long tag; /* tag, not used if no tagging */ + unsigned long offset; /* Offset of this field in structure */ + const char *field_name; /* Field name */ + ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */ +}; + +/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */ + +# define ASN1_TEMPLATE_item(t) (t->item_ptr) +# define ASN1_TEMPLATE_adb(t) (t->item_ptr) + +typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE; +typedef struct ASN1_ADB_st ASN1_ADB; + +struct ASN1_ADB_st { + unsigned long flags; /* Various flags */ + unsigned long offset; /* Offset of selector field */ + int (*adb_cb)(long *psel); /* Application callback */ + const ASN1_ADB_TABLE *tbl; /* Table of possible types */ + long tblcount; /* Number of entries in tbl */ + const ASN1_TEMPLATE *default_tt; /* Type to use if no match */ + const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */ +}; + +struct ASN1_ADB_TABLE_st { + long value; /* NID for an object or value for an int */ + const ASN1_TEMPLATE tt; /* item for this value */ +}; + +/* template flags */ + +/* Field is optional */ +# define ASN1_TFLG_OPTIONAL (0x1) + +/* Field is a SET OF */ +# define ASN1_TFLG_SET_OF (0x1 << 1) + +/* Field is a SEQUENCE OF */ +# define ASN1_TFLG_SEQUENCE_OF (0x2 << 1) + +/* + * Special case: this refers to a SET OF that will be sorted into DER order + * when encoded *and* the corresponding STACK will be modified to match the + * new order. + */ +# define ASN1_TFLG_SET_ORDER (0x3 << 1) + +/* Mask for SET OF or SEQUENCE OF */ +# define ASN1_TFLG_SK_MASK (0x3 << 1) + +/* + * These flags mean the tag should be taken from the tag field. If EXPLICIT + * then the underlying type is used for the inner tag. + */ + +/* IMPLICIT tagging */ +# define ASN1_TFLG_IMPTAG (0x1 << 3) + +/* EXPLICIT tagging, inner tag from underlying type */ +# define ASN1_TFLG_EXPTAG (0x2 << 3) + +# define ASN1_TFLG_TAG_MASK (0x3 << 3) + +/* context specific IMPLICIT */ +# define ASN1_TFLG_IMPLICIT ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT + +/* context specific EXPLICIT */ +# define ASN1_TFLG_EXPLICIT ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT + +/* + * If tagging is in force these determine the type of tag to use. Otherwise + * the tag is determined by the underlying type. These values reflect the + * actual octet format. + */ + +/* Universal tag */ +# define ASN1_TFLG_UNIVERSAL (0x0<<6) +/* Application tag */ +# define ASN1_TFLG_APPLICATION (0x1<<6) +/* Context specific tag */ +# define ASN1_TFLG_CONTEXT (0x2<<6) +/* Private tag */ +# define ASN1_TFLG_PRIVATE (0x3<<6) + +# define ASN1_TFLG_TAG_CLASS (0x3<<6) + +/* + * These are for ANY DEFINED BY type. In this case the 'item' field points to + * an ASN1_ADB structure which contains a table of values to decode the + * relevant type + */ + +# define ASN1_TFLG_ADB_MASK (0x3<<8) + +# define ASN1_TFLG_ADB_OID (0x1<<8) + +# define ASN1_TFLG_ADB_INT (0x1<<9) + +/* + * This flag when present in a SEQUENCE OF, SET OF or EXPLICIT causes + * indefinite length constructed encoding to be used if required. + */ + +# define ASN1_TFLG_NDEF (0x1<<11) + +/* Field is embedded and not a pointer */ +# define ASN1_TFLG_EMBED (0x1 << 12) + +/* This is the actual ASN1 item itself */ + +struct ASN1_ITEM_st { + char itype; /* The item type, primitive, SEQUENCE, CHOICE + * or extern */ + long utype; /* underlying type */ + const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains + * the contents */ + long tcount; /* Number of templates if SEQUENCE or CHOICE */ + const void *funcs; /* functions that handle this type */ + long size; /* Structure size (usually) */ + const char *sname; /* Structure name */ +}; + +/*- + * These are values for the itype field and + * determine how the type is interpreted. + * + * For PRIMITIVE types the underlying type + * determines the behaviour if items is NULL. + * + * Otherwise templates must contain a single + * template and the type is treated in the + * same way as the type specified in the template. + * + * For SEQUENCE types the templates field points + * to the members, the size field is the + * structure size. + * + * For CHOICE types the templates field points + * to each possible member (typically a union) + * and the 'size' field is the offset of the + * selector. + * + * The 'funcs' field is used for application + * specific functions. + * + * The EXTERN type uses a new style d2i/i2d. + * The new style should be used where possible + * because it avoids things like the d2i IMPLICIT + * hack. + * + * MSTRING is a multiple string type, it is used + * for a CHOICE of character strings where the + * actual strings all occupy an ASN1_STRING + * structure. In this case the 'utype' field + * has a special meaning, it is used as a mask + * of acceptable types using the B_ASN1 constants. + * + * NDEF_SEQUENCE is the same as SEQUENCE except + * that it will use indefinite length constructed + * encoding if requested. + * + */ + +# define ASN1_ITYPE_PRIMITIVE 0x0 + +# define ASN1_ITYPE_SEQUENCE 0x1 + +# define ASN1_ITYPE_CHOICE 0x2 + +# define ASN1_ITYPE_EXTERN 0x4 + +# define ASN1_ITYPE_MSTRING 0x5 + +# define ASN1_ITYPE_NDEF_SEQUENCE 0x6 + +/* + * Cache for ASN1 tag and length, so we don't keep re-reading it for things + * like CHOICE + */ + +struct ASN1_TLC_st { + char valid; /* Values below are valid */ + int ret; /* return value */ + long plen; /* length */ + int ptag; /* class value */ + int pclass; /* class value */ + int hdrlen; /* header length */ +}; + +/* Typedefs for ASN1 function pointers */ +typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, + const ASN1_ITEM *it, int tag, int aclass, char opt, + ASN1_TLC *ctx); + +typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass); +typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it); +typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it); + +typedef int ASN1_ex_print_func(BIO *out, ASN1_VALUE **pval, + int indent, const char *fname, + const ASN1_PCTX *pctx); + +typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont, + int *putype, const ASN1_ITEM *it); +typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont, + int len, int utype, char *free_cont, + const ASN1_ITEM *it); +typedef int ASN1_primitive_print(BIO *out, ASN1_VALUE **pval, + const ASN1_ITEM *it, int indent, + const ASN1_PCTX *pctx); + +typedef struct ASN1_EXTERN_FUNCS_st { + void *app_data; + ASN1_ex_new_func *asn1_ex_new; + ASN1_ex_free_func *asn1_ex_free; + ASN1_ex_free_func *asn1_ex_clear; + ASN1_ex_d2i *asn1_ex_d2i; + ASN1_ex_i2d *asn1_ex_i2d; + ASN1_ex_print_func *asn1_ex_print; +} ASN1_EXTERN_FUNCS; + +typedef struct ASN1_PRIMITIVE_FUNCS_st { + void *app_data; + unsigned long flags; + ASN1_ex_new_func *prim_new; + ASN1_ex_free_func *prim_free; + ASN1_ex_free_func *prim_clear; + ASN1_primitive_c2i *prim_c2i; + ASN1_primitive_i2c *prim_i2c; + ASN1_primitive_print *prim_print; +} ASN1_PRIMITIVE_FUNCS; + +/* + * This is the ASN1_AUX structure: it handles various miscellaneous + * requirements. For example the use of reference counts and an informational + * callback. The "informational callback" is called at various points during + * the ASN1 encoding and decoding. It can be used to provide minor + * customisation of the structures used. This is most useful where the + * supplied routines *almost* do the right thing but need some extra help at + * a few points. If the callback returns zero then it is assumed a fatal + * error has occurred and the main operation should be abandoned. If major + * changes in the default behaviour are required then an external type is + * more appropriate. + */ + +typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it, + void *exarg); + +typedef struct ASN1_AUX_st { + void *app_data; + int flags; + int ref_offset; /* Offset of reference value */ + int ref_lock; /* Lock type to use */ + ASN1_aux_cb *asn1_cb; + int enc_offset; /* Offset of ASN1_ENCODING structure */ +} ASN1_AUX; + +/* For print related callbacks exarg points to this structure */ +typedef struct ASN1_PRINT_ARG_st { + BIO *out; + int indent; + const ASN1_PCTX *pctx; +} ASN1_PRINT_ARG; + +/* For streaming related callbacks exarg points to this structure */ +typedef struct ASN1_STREAM_ARG_st { + /* BIO to stream through */ + BIO *out; + /* BIO with filters appended */ + BIO *ndef_bio; + /* Streaming I/O boundary */ + unsigned char **boundary; +} ASN1_STREAM_ARG; + +/* Flags in ASN1_AUX */ + +/* Use a reference count */ +# define ASN1_AFLG_REFCOUNT 1 +/* Save the encoding of structure (useful for signatures) */ +# define ASN1_AFLG_ENCODING 2 +/* The Sequence length is invalid */ +# define ASN1_AFLG_BROKEN 4 + +/* operation values for asn1_cb */ + +# define ASN1_OP_NEW_PRE 0 +# define ASN1_OP_NEW_POST 1 +# define ASN1_OP_FREE_PRE 2 +# define ASN1_OP_FREE_POST 3 +# define ASN1_OP_D2I_PRE 4 +# define ASN1_OP_D2I_POST 5 +# define ASN1_OP_I2D_PRE 6 +# define ASN1_OP_I2D_POST 7 +# define ASN1_OP_PRINT_PRE 8 +# define ASN1_OP_PRINT_POST 9 +# define ASN1_OP_STREAM_PRE 10 +# define ASN1_OP_STREAM_POST 11 +# define ASN1_OP_DETACHED_PRE 12 +# define ASN1_OP_DETACHED_POST 13 + +/* Macro to implement a primitive type */ +# define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0) +# define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement a multi string type */ +# define IMPLEMENT_ASN1_MSTRING(itname, mask) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \ + ASN1_ITEM_end(itname) + +# define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_EXTERN, \ + tag, \ + NULL, \ + 0, \ + &fptrs, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +/* Macro to implement standard functions in terms of ASN1_ITEM structures */ + +# define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname) + +# define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname) + +# define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \ + IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname) + +# define IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(static, stname, stname, stname) + +# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname) + +# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(pre, stname, itname, fname) \ + pre stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + pre void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \ + stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +# define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +# define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +# define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \ + int i2d_##stname##_NDEF(stname *a, unsigned char **out) \ + { \ + return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\ + } + +# define IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(stname) \ + static stname *d2i_##stname(stname **a, \ + const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, \ + ASN1_ITEM_rptr(stname)); \ + } \ + static int i2d_##stname(stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, \ + ASN1_ITEM_rptr(stname)); \ + } + +/* + * This includes evil casts to remove const: they will go away when full ASN1 + * constification is done. + */ +# define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(const stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +# define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \ + stname * stname##_dup(stname *x) \ + { \ + return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \ + } + +# define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \ + IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname) + +# define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \ + int fname##_print_ctx(BIO *out, stname *x, int indent, \ + const ASN1_PCTX *pctx) \ + { \ + return ASN1_item_print(out, (ASN1_VALUE *)x, indent, \ + ASN1_ITEM_rptr(itname), pctx); \ + } + +# define IMPLEMENT_ASN1_FUNCTIONS_const(name) \ + IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name) + +# define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +/* external definitions for primitive types */ + +DECLARE_ASN1_ITEM(ASN1_BOOLEAN) +DECLARE_ASN1_ITEM(ASN1_TBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_FBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_SEQUENCE) +DECLARE_ASN1_ITEM(CBIGNUM) +DECLARE_ASN1_ITEM(BIGNUM) +DECLARE_ASN1_ITEM(LONG) +DECLARE_ASN1_ITEM(ZLONG) + +DEFINE_STACK_OF(ASN1_VALUE) + +/* Functions used internally by the ASN1 code */ + +int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, + const ASN1_ITEM *it, int tag, int aclass, char opt, + ASN1_TLC *ctx); + +int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/async.h b/mobile/ios/FxA/FxA/include/openssl/async.h new file mode 100644 index 0000000000..5b2e496dbd --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/async.h @@ -0,0 +1,98 @@ +/* + * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include + +#ifndef HEADER_ASYNC_H +# define HEADER_ASYNC_H + +#if defined(_WIN32) +# if defined(BASETYPES) || defined(_WINDEF_H) +/* application has to include to use this */ +#define OSSL_ASYNC_FD HANDLE +#define OSSL_BAD_ASYNC_FD INVALID_HANDLE_VALUE +# endif +#else +#define OSSL_ASYNC_FD int +#define OSSL_BAD_ASYNC_FD -1 +#endif + + +# ifdef __cplusplus +extern "C" { +# endif + +typedef struct async_job_st ASYNC_JOB; +typedef struct async_wait_ctx_st ASYNC_WAIT_CTX; + +#define ASYNC_ERR 0 +#define ASYNC_NO_JOBS 1 +#define ASYNC_PAUSE 2 +#define ASYNC_FINISH 3 + +int ASYNC_init_thread(size_t max_size, size_t init_size); +void ASYNC_cleanup_thread(void); + +#ifdef OSSL_ASYNC_FD +ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void); +void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx); +int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key, + OSSL_ASYNC_FD fd, + void *custom_data, + void (*cleanup)(ASYNC_WAIT_CTX *, const void *, + OSSL_ASYNC_FD, void *)); +int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key, + OSSL_ASYNC_FD *fd, void **custom_data); +int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd, + size_t *numfds); +int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd, + size_t *numaddfds, OSSL_ASYNC_FD *delfd, + size_t *numdelfds); +int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key); +#endif + +int ASYNC_is_capable(void); + +int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *ctx, int *ret, + int (*func)(void *), void *args, size_t size); +int ASYNC_pause_job(void); + +ASYNC_JOB *ASYNC_get_current_job(void); +ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job); +void ASYNC_block_pause(void); +void ASYNC_unblock_pause(void); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_ASYNC_strings(void); + +/* Error codes for the ASYNC functions. */ + +/* Function codes. */ +# define ASYNC_F_ASYNC_CTX_NEW 100 +# define ASYNC_F_ASYNC_INIT_THREAD 101 +# define ASYNC_F_ASYNC_JOB_NEW 102 +# define ASYNC_F_ASYNC_PAUSE_JOB 103 +# define ASYNC_F_ASYNC_START_FUNC 104 +# define ASYNC_F_ASYNC_START_JOB 105 + +/* Reason codes. */ +# define ASYNC_R_FAILED_TO_SET_POOL 101 +# define ASYNC_R_FAILED_TO_SWAP_CONTEXT 102 +# define ASYNC_R_INIT_FAILED 105 +# define ASYNC_R_INVALID_POOL_SIZE 103 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/bio.h b/mobile/ios/FxA/FxA/include/openssl/bio.h new file mode 100644 index 0000000000..9bc941b25f --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/bio.h @@ -0,0 +1,854 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_BIO_H +# define HEADER_BIO_H + +# include + +# ifndef OPENSSL_NO_STDIO +# include +# endif +# include + +# include + +# ifndef OPENSSL_NO_SCTP +# ifndef OPENSSL_SYS_VMS +# include +# else +# include +# endif +# endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* There are the classes of BIOs */ +# define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */ +# define BIO_TYPE_FILTER 0x0200 +# define BIO_TYPE_SOURCE_SINK 0x0400 + +/* These are the 'types' of BIOs */ +# define BIO_TYPE_NONE 0 +# define BIO_TYPE_MEM ( 1|BIO_TYPE_SOURCE_SINK) +# define BIO_TYPE_FILE ( 2|BIO_TYPE_SOURCE_SINK) + +# define BIO_TYPE_FD ( 4|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR) +# define BIO_TYPE_SOCKET ( 5|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR) +# define BIO_TYPE_NULL ( 6|BIO_TYPE_SOURCE_SINK) +# define BIO_TYPE_SSL ( 7|BIO_TYPE_FILTER) +# define BIO_TYPE_MD ( 8|BIO_TYPE_FILTER) +# define BIO_TYPE_BUFFER ( 9|BIO_TYPE_FILTER) +# define BIO_TYPE_CIPHER (10|BIO_TYPE_FILTER) +# define BIO_TYPE_BASE64 (11|BIO_TYPE_FILTER) +# define BIO_TYPE_CONNECT (12|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR) +# define BIO_TYPE_ACCEPT (13|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR) + +# define BIO_TYPE_NBIO_TEST (16|BIO_TYPE_FILTER)/* server proxy BIO */ +# define BIO_TYPE_NULL_FILTER (17|BIO_TYPE_FILTER) +# define BIO_TYPE_BIO (19|BIO_TYPE_SOURCE_SINK)/* half a BIO pair */ +# define BIO_TYPE_LINEBUFFER (20|BIO_TYPE_FILTER) +# define BIO_TYPE_DGRAM (21|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR) +# define BIO_TYPE_ASN1 (22|BIO_TYPE_FILTER) +# define BIO_TYPE_COMP (23|BIO_TYPE_FILTER) +# ifndef OPENSSL_NO_SCTP +# define BIO_TYPE_DGRAM_SCTP (24|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR) +# endif + +#define BIO_TYPE_START 128 + +/* + * BIO_FILENAME_READ|BIO_CLOSE to open or close on free. + * BIO_set_fp(in,stdin,BIO_NOCLOSE); + */ +# define BIO_NOCLOSE 0x00 +# define BIO_CLOSE 0x01 + +/* + * These are used in the following macros and are passed to BIO_ctrl() + */ +# define BIO_CTRL_RESET 1/* opt - rewind/zero etc */ +# define BIO_CTRL_EOF 2/* opt - are we at the eof */ +# define BIO_CTRL_INFO 3/* opt - extra tit-bits */ +# define BIO_CTRL_SET 4/* man - set the 'IO' type */ +# define BIO_CTRL_GET 5/* man - get the 'IO' type */ +# define BIO_CTRL_PUSH 6/* opt - internal, used to signify change */ +# define BIO_CTRL_POP 7/* opt - internal, used to signify change */ +# define BIO_CTRL_GET_CLOSE 8/* man - set the 'close' on free */ +# define BIO_CTRL_SET_CLOSE 9/* man - set the 'close' on free */ +# define BIO_CTRL_PENDING 10/* opt - is their more data buffered */ +# define BIO_CTRL_FLUSH 11/* opt - 'flush' buffered output */ +# define BIO_CTRL_DUP 12/* man - extra stuff for 'duped' BIO */ +# define BIO_CTRL_WPENDING 13/* opt - number of bytes still to write */ +# define BIO_CTRL_SET_CALLBACK 14/* opt - set callback function */ +# define BIO_CTRL_GET_CALLBACK 15/* opt - set callback function */ + +# define BIO_CTRL_SET_FILENAME 30/* BIO_s_file special */ + +/* dgram BIO stuff */ +# define BIO_CTRL_DGRAM_CONNECT 31/* BIO dgram special */ +# define BIO_CTRL_DGRAM_SET_CONNECTED 32/* allow for an externally connected + * socket to be passed in */ +# define BIO_CTRL_DGRAM_SET_RECV_TIMEOUT 33/* setsockopt, essentially */ +# define BIO_CTRL_DGRAM_GET_RECV_TIMEOUT 34/* getsockopt, essentially */ +# define BIO_CTRL_DGRAM_SET_SEND_TIMEOUT 35/* setsockopt, essentially */ +# define BIO_CTRL_DGRAM_GET_SEND_TIMEOUT 36/* getsockopt, essentially */ + +# define BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP 37/* flag whether the last */ +# define BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP 38/* I/O operation tiemd out */ + +/* #ifdef IP_MTU_DISCOVER */ +# define BIO_CTRL_DGRAM_MTU_DISCOVER 39/* set DF bit on egress packets */ +/* #endif */ + +# define BIO_CTRL_DGRAM_QUERY_MTU 40/* as kernel for current MTU */ +# define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47 +# define BIO_CTRL_DGRAM_GET_MTU 41/* get cached value for MTU */ +# define BIO_CTRL_DGRAM_SET_MTU 42/* set cached value for MTU. + * want to use this if asking + * the kernel fails */ + +# define BIO_CTRL_DGRAM_MTU_EXCEEDED 43/* check whether the MTU was + * exceed in the previous write + * operation */ + +# define BIO_CTRL_DGRAM_GET_PEER 46 +# define BIO_CTRL_DGRAM_SET_PEER 44/* Destination for the data */ + +# define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45/* Next DTLS handshake timeout + * to adjust socket timeouts */ +# define BIO_CTRL_DGRAM_SET_DONT_FRAG 48 + +# define BIO_CTRL_DGRAM_GET_MTU_OVERHEAD 49 + +# define BIO_CTRL_DGRAM_SET_PEEK_MODE 50 + +# ifndef OPENSSL_NO_SCTP +/* SCTP stuff */ +# define BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE 50 +# define BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY 51 +# define BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY 52 +# define BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD 53 +# define BIO_CTRL_DGRAM_SCTP_GET_SNDINFO 60 +# define BIO_CTRL_DGRAM_SCTP_SET_SNDINFO 61 +# define BIO_CTRL_DGRAM_SCTP_GET_RCVINFO 62 +# define BIO_CTRL_DGRAM_SCTP_SET_RCVINFO 63 +# define BIO_CTRL_DGRAM_SCTP_GET_PRINFO 64 +# define BIO_CTRL_DGRAM_SCTP_SET_PRINFO 65 +# define BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN 70 +# endif + +/* modifiers */ +# define BIO_FP_READ 0x02 +# define BIO_FP_WRITE 0x04 +# define BIO_FP_APPEND 0x08 +# define BIO_FP_TEXT 0x10 + +# define BIO_FLAGS_READ 0x01 +# define BIO_FLAGS_WRITE 0x02 +# define BIO_FLAGS_IO_SPECIAL 0x04 +# define BIO_FLAGS_RWS (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL) +# define BIO_FLAGS_SHOULD_RETRY 0x08 +# ifndef BIO_FLAGS_UPLINK +/* + * "UPLINK" flag denotes file descriptors provided by application. It + * defaults to 0, as most platforms don't require UPLINK interface. + */ +# define BIO_FLAGS_UPLINK 0 +# endif + +# define BIO_FLAGS_BASE64_NO_NL 0x100 + +/* + * This is used with memory BIOs: + * BIO_FLAGS_MEM_RDONLY means we shouldn't free up or change the data in any way; + * BIO_FLAGS_NONCLEAR_RST means we should't clear data on reset. + */ +# define BIO_FLAGS_MEM_RDONLY 0x200 +# define BIO_FLAGS_NONCLEAR_RST 0x400 + +typedef union bio_addr_st BIO_ADDR; +typedef struct bio_addrinfo_st BIO_ADDRINFO; + +int BIO_get_new_index(void); +void BIO_set_flags(BIO *b, int flags); +int BIO_test_flags(const BIO *b, int flags); +void BIO_clear_flags(BIO *b, int flags); + +# define BIO_get_flags(b) BIO_test_flags(b, ~(0x0)) +# define BIO_set_retry_special(b) \ + BIO_set_flags(b, (BIO_FLAGS_IO_SPECIAL|BIO_FLAGS_SHOULD_RETRY)) +# define BIO_set_retry_read(b) \ + BIO_set_flags(b, (BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY)) +# define BIO_set_retry_write(b) \ + BIO_set_flags(b, (BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY)) + +/* These are normally used internally in BIOs */ +# define BIO_clear_retry_flags(b) \ + BIO_clear_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY)) +# define BIO_get_retry_flags(b) \ + BIO_test_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY)) + +/* These should be used by the application to tell why we should retry */ +# define BIO_should_read(a) BIO_test_flags(a, BIO_FLAGS_READ) +# define BIO_should_write(a) BIO_test_flags(a, BIO_FLAGS_WRITE) +# define BIO_should_io_special(a) BIO_test_flags(a, BIO_FLAGS_IO_SPECIAL) +# define BIO_retry_type(a) BIO_test_flags(a, BIO_FLAGS_RWS) +# define BIO_should_retry(a) BIO_test_flags(a, BIO_FLAGS_SHOULD_RETRY) + +/* + * The next three are used in conjunction with the BIO_should_io_special() + * condition. After this returns true, BIO *BIO_get_retry_BIO(BIO *bio, int + * *reason); will walk the BIO stack and return the 'reason' for the special + * and the offending BIO. Given a BIO, BIO_get_retry_reason(bio) will return + * the code. + */ +/* + * Returned from the SSL bio when the certificate retrieval code had an error + */ +# define BIO_RR_SSL_X509_LOOKUP 0x01 +/* Returned from the connect BIO when a connect would have blocked */ +# define BIO_RR_CONNECT 0x02 +/* Returned from the accept BIO when an accept would have blocked */ +# define BIO_RR_ACCEPT 0x03 + +/* These are passed by the BIO callback */ +# define BIO_CB_FREE 0x01 +# define BIO_CB_READ 0x02 +# define BIO_CB_WRITE 0x03 +# define BIO_CB_PUTS 0x04 +# define BIO_CB_GETS 0x05 +# define BIO_CB_CTRL 0x06 + +/* + * The callback is called before and after the underling operation, The + * BIO_CB_RETURN flag indicates if it is after the call + */ +# define BIO_CB_RETURN 0x80 +# define BIO_CB_return(a) ((a)|BIO_CB_RETURN) +# define BIO_cb_pre(a) (!((a)&BIO_CB_RETURN)) +# define BIO_cb_post(a) ((a)&BIO_CB_RETURN) + +typedef long (*BIO_callback_fn)(BIO *b, int oper, const char *argp, int argi, + long argl, long ret); +BIO_callback_fn BIO_get_callback(const BIO *b); +void BIO_set_callback(BIO *b, BIO_callback_fn callback); +char *BIO_get_callback_arg(const BIO *b); +void BIO_set_callback_arg(BIO *b, char *arg); + +typedef struct bio_method_st BIO_METHOD; + +const char *BIO_method_name(const BIO *b); +int BIO_method_type(const BIO *b); + +typedef void bio_info_cb(BIO *, int, const char *, int, long, long); + +DEFINE_STACK_OF(BIO) + +/* Prefix and suffix callback in ASN1 BIO */ +typedef int asn1_ps_func (BIO *b, unsigned char **pbuf, int *plen, + void *parg); + +# ifndef OPENSSL_NO_SCTP +/* SCTP parameter structs */ +struct bio_dgram_sctp_sndinfo { + uint16_t snd_sid; + uint16_t snd_flags; + uint32_t snd_ppid; + uint32_t snd_context; +}; + +struct bio_dgram_sctp_rcvinfo { + uint16_t rcv_sid; + uint16_t rcv_ssn; + uint16_t rcv_flags; + uint32_t rcv_ppid; + uint32_t rcv_tsn; + uint32_t rcv_cumtsn; + uint32_t rcv_context; +}; + +struct bio_dgram_sctp_prinfo { + uint16_t pr_policy; + uint32_t pr_value; +}; +# endif + +/* + * #define BIO_CONN_get_param_hostname BIO_ctrl + */ + +# define BIO_C_SET_CONNECT 100 +# define BIO_C_DO_STATE_MACHINE 101 +# define BIO_C_SET_NBIO 102 +/* # define BIO_C_SET_PROXY_PARAM 103 */ +# define BIO_C_SET_FD 104 +# define BIO_C_GET_FD 105 +# define BIO_C_SET_FILE_PTR 106 +# define BIO_C_GET_FILE_PTR 107 +# define BIO_C_SET_FILENAME 108 +# define BIO_C_SET_SSL 109 +# define BIO_C_GET_SSL 110 +# define BIO_C_SET_MD 111 +# define BIO_C_GET_MD 112 +# define BIO_C_GET_CIPHER_STATUS 113 +# define BIO_C_SET_BUF_MEM 114 +# define BIO_C_GET_BUF_MEM_PTR 115 +# define BIO_C_GET_BUFF_NUM_LINES 116 +# define BIO_C_SET_BUFF_SIZE 117 +# define BIO_C_SET_ACCEPT 118 +# define BIO_C_SSL_MODE 119 +# define BIO_C_GET_MD_CTX 120 +/* # define BIO_C_GET_PROXY_PARAM 121 */ +# define BIO_C_SET_BUFF_READ_DATA 122/* data to read first */ +# define BIO_C_GET_CONNECT 123 +# define BIO_C_GET_ACCEPT 124 +# define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125 +# define BIO_C_GET_SSL_NUM_RENEGOTIATES 126 +# define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127 +# define BIO_C_FILE_SEEK 128 +# define BIO_C_GET_CIPHER_CTX 129 +# define BIO_C_SET_BUF_MEM_EOF_RETURN 130/* return end of input + * value */ +# define BIO_C_SET_BIND_MODE 131 +# define BIO_C_GET_BIND_MODE 132 +# define BIO_C_FILE_TELL 133 +# define BIO_C_GET_SOCKS 134 +# define BIO_C_SET_SOCKS 135 + +# define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */ +# define BIO_C_GET_WRITE_BUF_SIZE 137 +# define BIO_C_MAKE_BIO_PAIR 138 +# define BIO_C_DESTROY_BIO_PAIR 139 +# define BIO_C_GET_WRITE_GUARANTEE 140 +# define BIO_C_GET_READ_REQUEST 141 +# define BIO_C_SHUTDOWN_WR 142 +# define BIO_C_NREAD0 143 +# define BIO_C_NREAD 144 +# define BIO_C_NWRITE0 145 +# define BIO_C_NWRITE 146 +# define BIO_C_RESET_READ_REQUEST 147 +# define BIO_C_SET_MD_CTX 148 + +# define BIO_C_SET_PREFIX 149 +# define BIO_C_GET_PREFIX 150 +# define BIO_C_SET_SUFFIX 151 +# define BIO_C_GET_SUFFIX 152 + +# define BIO_C_SET_EX_ARG 153 +# define BIO_C_GET_EX_ARG 154 + +# define BIO_C_SET_CONNECT_MODE 155 + +# define BIO_set_app_data(s,arg) BIO_set_ex_data(s,0,arg) +# define BIO_get_app_data(s) BIO_get_ex_data(s,0) + +# define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) + +# ifndef OPENSSL_NO_SOCK +/* IP families we support, for BIO_s_connect() and BIO_s_accept() */ +/* Note: the underlying operating system may not support some of them */ +# define BIO_FAMILY_IPV4 4 +# define BIO_FAMILY_IPV6 6 +# define BIO_FAMILY_IPANY 256 + +/* BIO_s_connect() */ +# define BIO_set_conn_hostname(b,name) BIO_ctrl(b,BIO_C_SET_CONNECT,0,(char *)name) +# define BIO_set_conn_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,1,(char *)port) +# define BIO_set_conn_address(b,addr) BIO_ctrl(b,BIO_C_SET_CONNECT,2,(char *)addr) +# define BIO_set_conn_ip_family(b,f) BIO_int_ctrl(b,BIO_C_SET_CONNECT,3,f) +# define BIO_get_conn_hostname(b) ((const char *)BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,0)) +# define BIO_get_conn_port(b) ((const char *)BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,1)) +# define BIO_get_conn_address(b) ((const BIO_ADDR *)BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2)) +# define BIO_get_conn_ip_family(b) BIO_ctrl(b,BIO_C_GET_CONNECT,3,NULL) +# define BIO_set_conn_mode(b,n) BIO_ctrl(b,BIO_C_SET_CONNECT_MODE,(n),NULL) + +/* BIO_s_accept() */ +# define BIO_set_accept_name(b,name) BIO_ctrl(b,BIO_C_SET_ACCEPT,0,(char *)name) +# define BIO_set_accept_port(b,port) BIO_ctrl(b,BIO_C_SET_ACCEPT,1,(char *)port) +# define BIO_get_accept_name(b) ((const char *)BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,0)) +# define BIO_get_accept_port(b) ((const char *)BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,1)) +# define BIO_get_peer_name(b) ((const char *)BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,2)) +# define BIO_get_peer_port(b) ((const char *)BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,3)) +/* #define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) */ +# define BIO_set_nbio_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,2,(n)?(void *)"a":NULL) +# define BIO_set_accept_bios(b,bio) BIO_ctrl(b,BIO_C_SET_ACCEPT,3,(char *)bio) +# define BIO_set_accept_ip_family(b,f) BIO_int_ctrl(b,BIO_C_SET_ACCEPT,4,f) +# define BIO_get_accept_ip_family(b) BIO_ctrl(b,BIO_C_GET_ACCEPT,4,NULL) + +/* Aliases kept for backward compatibility */ +# define BIO_BIND_NORMAL 0 +# define BIO_BIND_REUSEADDR BIO_SOCK_REUSEADDR +# define BIO_BIND_REUSEADDR_IF_UNUSED BIO_SOCK_REUSEADDR +# define BIO_set_bind_mode(b,mode) BIO_ctrl(b,BIO_C_SET_BIND_MODE,mode,NULL) +# define BIO_get_bind_mode(b) BIO_ctrl(b,BIO_C_GET_BIND_MODE,0,NULL) + +/* BIO_s_accept() and BIO_s_connect() */ +# define BIO_do_connect(b) BIO_do_handshake(b) +# define BIO_do_accept(b) BIO_do_handshake(b) +# endif /* OPENSSL_NO_SOCK */ + +# define BIO_do_handshake(b) BIO_ctrl(b,BIO_C_DO_STATE_MACHINE,0,NULL) + +/* BIO_s_datagram(), BIO_s_fd(), BIO_s_socket(), BIO_s_accept() and BIO_s_connect() */ +# define BIO_set_fd(b,fd,c) BIO_int_ctrl(b,BIO_C_SET_FD,c,fd) +# define BIO_get_fd(b,c) BIO_ctrl(b,BIO_C_GET_FD,0,(char *)c) + +/* BIO_s_file() */ +# define BIO_set_fp(b,fp,c) BIO_ctrl(b,BIO_C_SET_FILE_PTR,c,(char *)fp) +# define BIO_get_fp(b,fpp) BIO_ctrl(b,BIO_C_GET_FILE_PTR,0,(char *)fpp) + +/* BIO_s_fd() and BIO_s_file() */ +# define BIO_seek(b,ofs) (int)BIO_ctrl(b,BIO_C_FILE_SEEK,ofs,NULL) +# define BIO_tell(b) (int)BIO_ctrl(b,BIO_C_FILE_TELL,0,NULL) + +/* + * name is cast to lose const, but might be better to route through a + * function so we can do it safely + */ +# ifdef CONST_STRICT +/* + * If you are wondering why this isn't defined, its because CONST_STRICT is + * purely a compile-time kludge to allow const to be checked. + */ +int BIO_read_filename(BIO *b, const char *name); +# else +# define BIO_read_filename(b,name) (int)BIO_ctrl(b,BIO_C_SET_FILENAME, \ + BIO_CLOSE|BIO_FP_READ,(char *)name) +# endif +# define BIO_write_filename(b,name) (int)BIO_ctrl(b,BIO_C_SET_FILENAME, \ + BIO_CLOSE|BIO_FP_WRITE,name) +# define BIO_append_filename(b,name) (int)BIO_ctrl(b,BIO_C_SET_FILENAME, \ + BIO_CLOSE|BIO_FP_APPEND,name) +# define BIO_rw_filename(b,name) (int)BIO_ctrl(b,BIO_C_SET_FILENAME, \ + BIO_CLOSE|BIO_FP_READ|BIO_FP_WRITE,name) + +/* + * WARNING WARNING, this ups the reference count on the read bio of the SSL + * structure. This is because the ssl read BIO is now pointed to by the + * next_bio field in the bio. So when you free the BIO, make sure you are + * doing a BIO_free_all() to catch the underlying BIO. + */ +# define BIO_set_ssl(b,ssl,c) BIO_ctrl(b,BIO_C_SET_SSL,c,(char *)ssl) +# define BIO_get_ssl(b,sslp) BIO_ctrl(b,BIO_C_GET_SSL,0,(char *)sslp) +# define BIO_set_ssl_mode(b,client) BIO_ctrl(b,BIO_C_SSL_MODE,client,NULL) +# define BIO_set_ssl_renegotiate_bytes(b,num) \ + BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_BYTES,num,NULL) +# define BIO_get_num_renegotiates(b) \ + BIO_ctrl(b,BIO_C_GET_SSL_NUM_RENEGOTIATES,0,NULL) +# define BIO_set_ssl_renegotiate_timeout(b,seconds) \ + BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT,seconds,NULL) + +/* defined in evp.h */ +/* #define BIO_set_md(b,md) BIO_ctrl(b,BIO_C_SET_MD,1,(char *)md) */ + +# define BIO_get_mem_data(b,pp) BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp) +# define BIO_set_mem_buf(b,bm,c) BIO_ctrl(b,BIO_C_SET_BUF_MEM,c,(char *)bm) +# define BIO_get_mem_ptr(b,pp) BIO_ctrl(b,BIO_C_GET_BUF_MEM_PTR,0,(char *)pp) +# define BIO_set_mem_eof_return(b,v) \ + BIO_ctrl(b,BIO_C_SET_BUF_MEM_EOF_RETURN,v,NULL) + +/* For the BIO_f_buffer() type */ +# define BIO_get_buffer_num_lines(b) BIO_ctrl(b,BIO_C_GET_BUFF_NUM_LINES,0,NULL) +# define BIO_set_buffer_size(b,size) BIO_ctrl(b,BIO_C_SET_BUFF_SIZE,size,NULL) +# define BIO_set_read_buffer_size(b,size) BIO_int_ctrl(b,BIO_C_SET_BUFF_SIZE,size,0) +# define BIO_set_write_buffer_size(b,size) BIO_int_ctrl(b,BIO_C_SET_BUFF_SIZE,size,1) +# define BIO_set_buffer_read_data(b,buf,num) BIO_ctrl(b,BIO_C_SET_BUFF_READ_DATA,num,buf) + +/* Don't use the next one unless you know what you are doing :-) */ +# define BIO_dup_state(b,ret) BIO_ctrl(b,BIO_CTRL_DUP,0,(char *)(ret)) + +# define BIO_reset(b) (int)BIO_ctrl(b,BIO_CTRL_RESET,0,NULL) +# define BIO_eof(b) (int)BIO_ctrl(b,BIO_CTRL_EOF,0,NULL) +# define BIO_set_close(b,c) (int)BIO_ctrl(b,BIO_CTRL_SET_CLOSE,(c),NULL) +# define BIO_get_close(b) (int)BIO_ctrl(b,BIO_CTRL_GET_CLOSE,0,NULL) +# define BIO_pending(b) (int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL) +# define BIO_wpending(b) (int)BIO_ctrl(b,BIO_CTRL_WPENDING,0,NULL) +/* ...pending macros have inappropriate return type */ +size_t BIO_ctrl_pending(BIO *b); +size_t BIO_ctrl_wpending(BIO *b); +# define BIO_flush(b) (int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL) +# define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0, \ + cbp) +# define BIO_set_info_callback(b,cb) (int)BIO_callback_ctrl(b,BIO_CTRL_SET_CALLBACK,cb) + +/* For the BIO_f_buffer() type */ +# define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL) + +/* For BIO_s_bio() */ +# define BIO_set_write_buf_size(b,size) (int)BIO_ctrl(b,BIO_C_SET_WRITE_BUF_SIZE,size,NULL) +# define BIO_get_write_buf_size(b,size) (size_t)BIO_ctrl(b,BIO_C_GET_WRITE_BUF_SIZE,size,NULL) +# define BIO_make_bio_pair(b1,b2) (int)BIO_ctrl(b1,BIO_C_MAKE_BIO_PAIR,0,b2) +# define BIO_destroy_bio_pair(b) (int)BIO_ctrl(b,BIO_C_DESTROY_BIO_PAIR,0,NULL) +# define BIO_shutdown_wr(b) (int)BIO_ctrl(b, BIO_C_SHUTDOWN_WR, 0, NULL) +/* macros with inappropriate type -- but ...pending macros use int too: */ +# define BIO_get_write_guarantee(b) (int)BIO_ctrl(b,BIO_C_GET_WRITE_GUARANTEE,0,NULL) +# define BIO_get_read_request(b) (int)BIO_ctrl(b,BIO_C_GET_READ_REQUEST,0,NULL) +size_t BIO_ctrl_get_write_guarantee(BIO *b); +size_t BIO_ctrl_get_read_request(BIO *b); +int BIO_ctrl_reset_read_request(BIO *b); + +/* ctrl macros for dgram */ +# define BIO_ctrl_dgram_connect(b,peer) \ + (int)BIO_ctrl(b,BIO_CTRL_DGRAM_CONNECT,0, (char *)peer) +# define BIO_ctrl_set_connected(b,peer) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_CONNECTED, 0, (char *)peer) +# define BIO_dgram_recv_timedout(b) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL) +# define BIO_dgram_send_timedout(b) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP, 0, NULL) +# define BIO_dgram_get_peer(b,peer) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_PEER, 0, (char *)peer) +# define BIO_dgram_set_peer(b,peer) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)peer) +# define BIO_dgram_get_mtu_overhead(b) \ + (unsigned int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_MTU_OVERHEAD, 0, NULL) + +#define BIO_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_BIO, l, p, newf, dupf, freef) +int BIO_set_ex_data(BIO *bio, int idx, void *data); +void *BIO_get_ex_data(BIO *bio, int idx); +uint64_t BIO_number_read(BIO *bio); +uint64_t BIO_number_written(BIO *bio); + +/* For BIO_f_asn1() */ +int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, + asn1_ps_func *prefix_free); +int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, + asn1_ps_func **pprefix_free); +int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, + asn1_ps_func *suffix_free); +int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, + asn1_ps_func **psuffix_free); + +const BIO_METHOD *BIO_s_file(void); +BIO *BIO_new_file(const char *filename, const char *mode); +# ifndef OPENSSL_NO_STDIO +BIO *BIO_new_fp(FILE *stream, int close_flag); +# endif +BIO *BIO_new(const BIO_METHOD *type); +int BIO_free(BIO *a); +void BIO_set_data(BIO *a, void *ptr); +void *BIO_get_data(BIO *a); +void BIO_set_init(BIO *a, int init); +int BIO_get_init(BIO *a); +void BIO_set_shutdown(BIO *a, int shut); +int BIO_get_shutdown(BIO *a); +void BIO_vfree(BIO *a); +int BIO_up_ref(BIO *a); +int BIO_read(BIO *b, void *data, int len); +int BIO_gets(BIO *bp, char *buf, int size); +int BIO_write(BIO *b, const void *data, int len); +int BIO_puts(BIO *bp, const char *buf); +int BIO_indent(BIO *b, int indent, int max); +long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg); +long BIO_callback_ctrl(BIO *b, int cmd, + void (*fp) (BIO *, int, const char *, int, long, long)); +void *BIO_ptr_ctrl(BIO *bp, int cmd, long larg); +long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg); +BIO *BIO_push(BIO *b, BIO *append); +BIO *BIO_pop(BIO *b); +void BIO_free_all(BIO *a); +BIO *BIO_find_type(BIO *b, int bio_type); +BIO *BIO_next(BIO *b); +void BIO_set_next(BIO *b, BIO *next); +BIO *BIO_get_retry_BIO(BIO *bio, int *reason); +int BIO_get_retry_reason(BIO *bio); +void BIO_set_retry_reason(BIO *bio, int reason); +BIO *BIO_dup_chain(BIO *in); + +int BIO_nread0(BIO *bio, char **buf); +int BIO_nread(BIO *bio, char **buf, int num); +int BIO_nwrite0(BIO *bio, char **buf); +int BIO_nwrite(BIO *bio, char **buf, int num); + +long BIO_debug_callback(BIO *bio, int cmd, const char *argp, int argi, + long argl, long ret); + +const BIO_METHOD *BIO_s_mem(void); +const BIO_METHOD *BIO_s_secmem(void); +BIO *BIO_new_mem_buf(const void *buf, int len); +# ifndef OPENSSL_NO_SOCK +const BIO_METHOD *BIO_s_socket(void); +const BIO_METHOD *BIO_s_connect(void); +const BIO_METHOD *BIO_s_accept(void); +# endif +const BIO_METHOD *BIO_s_fd(void); +const BIO_METHOD *BIO_s_log(void); +const BIO_METHOD *BIO_s_bio(void); +const BIO_METHOD *BIO_s_null(void); +const BIO_METHOD *BIO_f_null(void); +const BIO_METHOD *BIO_f_buffer(void); +const BIO_METHOD *BIO_f_linebuffer(void); +const BIO_METHOD *BIO_f_nbio_test(void); +# ifndef OPENSSL_NO_DGRAM +const BIO_METHOD *BIO_s_datagram(void); +int BIO_dgram_non_fatal_error(int error); +BIO *BIO_new_dgram(int fd, int close_flag); +# ifndef OPENSSL_NO_SCTP +const BIO_METHOD *BIO_s_datagram_sctp(void); +BIO *BIO_new_dgram_sctp(int fd, int close_flag); +int BIO_dgram_is_sctp(BIO *bio); +int BIO_dgram_sctp_notification_cb(BIO *b, + void (*handle_notifications) (BIO *bio, + void *context, + void *buf), + void *context); +int BIO_dgram_sctp_wait_for_dry(BIO *b); +int BIO_dgram_sctp_msg_waiting(BIO *b); +# endif +# endif + +# ifndef OPENSSL_NO_SOCK +int BIO_sock_should_retry(int i); +int BIO_sock_non_fatal_error(int error); +# endif + +int BIO_fd_should_retry(int i); +int BIO_fd_non_fatal_error(int error); +int BIO_dump_cb(int (*cb) (const void *data, size_t len, void *u), + void *u, const char *s, int len); +int BIO_dump_indent_cb(int (*cb) (const void *data, size_t len, void *u), + void *u, const char *s, int len, int indent); +int BIO_dump(BIO *b, const char *bytes, int len); +int BIO_dump_indent(BIO *b, const char *bytes, int len, int indent); +# ifndef OPENSSL_NO_STDIO +int BIO_dump_fp(FILE *fp, const char *s, int len); +int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent); +# endif +int BIO_hex_string(BIO *out, int indent, int width, unsigned char *data, + int datalen); + +# ifndef OPENSSL_NO_SOCK +BIO_ADDR *BIO_ADDR_new(void); +int BIO_ADDR_rawmake(BIO_ADDR *ap, int family, + const void *where, size_t wherelen, unsigned short port); +void BIO_ADDR_free(BIO_ADDR *); +void BIO_ADDR_clear(BIO_ADDR *ap); +int BIO_ADDR_family(const BIO_ADDR *ap); +int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l); +unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap); +char *BIO_ADDR_hostname_string(const BIO_ADDR *ap, int numeric); +char *BIO_ADDR_service_string(const BIO_ADDR *ap, int numeric); +char *BIO_ADDR_path_string(const BIO_ADDR *ap); + +const BIO_ADDRINFO *BIO_ADDRINFO_next(const BIO_ADDRINFO *bai); +int BIO_ADDRINFO_family(const BIO_ADDRINFO *bai); +int BIO_ADDRINFO_socktype(const BIO_ADDRINFO *bai); +int BIO_ADDRINFO_protocol(const BIO_ADDRINFO *bai); +const BIO_ADDR *BIO_ADDRINFO_address(const BIO_ADDRINFO *bai); +void BIO_ADDRINFO_free(BIO_ADDRINFO *bai); + +enum BIO_hostserv_priorities { + BIO_PARSE_PRIO_HOST, BIO_PARSE_PRIO_SERV +}; +int BIO_parse_hostserv(const char *hostserv, char **host, char **service, + enum BIO_hostserv_priorities hostserv_prio); +enum BIO_lookup_type { + BIO_LOOKUP_CLIENT, BIO_LOOKUP_SERVER +}; +int BIO_lookup(const char *host, const char *service, + enum BIO_lookup_type lookup_type, + int family, int socktype, BIO_ADDRINFO **res); +int BIO_sock_error(int sock); +int BIO_socket_ioctl(int fd, long type, void *arg); +int BIO_socket_nbio(int fd, int mode); +int BIO_sock_init(void); +# if OPENSSL_API_COMPAT < 0x10100000L +# define BIO_sock_cleanup() while(0) continue +# endif +int BIO_set_tcp_ndelay(int sock, int turn_on); + +DEPRECATEDIN_1_1_0(struct hostent *BIO_gethostbyname(const char *name)) +DEPRECATEDIN_1_1_0(int BIO_get_port(const char *str, unsigned short *port_ptr)) +DEPRECATEDIN_1_1_0(int BIO_get_host_ip(const char *str, unsigned char *ip)) +DEPRECATEDIN_1_1_0(int BIO_get_accept_socket(char *host_port, int mode)) +DEPRECATEDIN_1_1_0(int BIO_accept(int sock, char **ip_port)) + +union BIO_sock_info_u { + BIO_ADDR *addr; +}; +enum BIO_sock_info_type { + BIO_SOCK_INFO_ADDRESS +}; +int BIO_sock_info(int sock, + enum BIO_sock_info_type type, union BIO_sock_info_u *info); + +# define BIO_SOCK_REUSEADDR 0x01 +# define BIO_SOCK_V6_ONLY 0x02 +# define BIO_SOCK_KEEPALIVE 0x04 +# define BIO_SOCK_NONBLOCK 0x08 +# define BIO_SOCK_NODELAY 0x10 + +int BIO_socket(int domain, int socktype, int protocol, int options); +int BIO_connect(int sock, const BIO_ADDR *addr, int options); +int BIO_listen(int sock, const BIO_ADDR *addr, int options); +int BIO_accept_ex(int accept_sock, BIO_ADDR *addr, int options); +int BIO_closesocket(int sock); + +BIO *BIO_new_socket(int sock, int close_flag); +BIO *BIO_new_connect(const char *host_port); +BIO *BIO_new_accept(const char *host_port); +# endif /* OPENSSL_NO_SOCK*/ + +BIO *BIO_new_fd(int fd, int close_flag); + +int BIO_new_bio_pair(BIO **bio1, size_t writebuf1, + BIO **bio2, size_t writebuf2); +/* + * If successful, returns 1 and in *bio1, *bio2 two BIO pair endpoints. + * Otherwise returns 0 and sets *bio1 and *bio2 to NULL. Size 0 uses default + * value. + */ + +void BIO_copy_next_retry(BIO *b); + +/* + * long BIO_ghbn_ctrl(int cmd,int iarg,char *parg); + */ + +# ifdef __GNUC__ +# define __bio_h__attr__ __attribute__ +# else +# define __bio_h__attr__(x) +# endif +int BIO_printf(BIO *bio, const char *format, ...) +__bio_h__attr__((__format__(__printf__, 2, 3))); +int BIO_vprintf(BIO *bio, const char *format, va_list args) +__bio_h__attr__((__format__(__printf__, 2, 0))); +int BIO_snprintf(char *buf, size_t n, const char *format, ...) +__bio_h__attr__((__format__(__printf__, 3, 4))); +int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) +__bio_h__attr__((__format__(__printf__, 3, 0))); +# undef __bio_h__attr__ + + +BIO_METHOD *BIO_meth_new(int type, const char *name); +void BIO_meth_free(BIO_METHOD *biom); +int (*BIO_meth_get_write(BIO_METHOD *biom)) (BIO *, const char *, int); +int BIO_meth_set_write(BIO_METHOD *biom, + int (*write) (BIO *, const char *, int)); +int (*BIO_meth_get_read(BIO_METHOD *biom)) (BIO *, char *, int); +int BIO_meth_set_read(BIO_METHOD *biom, + int (*read) (BIO *, char *, int)); +int (*BIO_meth_get_puts(BIO_METHOD *biom)) (BIO *, const char *); +int BIO_meth_set_puts(BIO_METHOD *biom, + int (*puts) (BIO *, const char *)); +int (*BIO_meth_get_gets(BIO_METHOD *biom)) (BIO *, char *, int); +int BIO_meth_set_gets(BIO_METHOD *biom, + int (*gets) (BIO *, char *, int)); +long (*BIO_meth_get_ctrl(BIO_METHOD *biom)) (BIO *, int, long, void *); +int BIO_meth_set_ctrl(BIO_METHOD *biom, + long (*ctrl) (BIO *, int, long, void *)); +int (*BIO_meth_get_create(BIO_METHOD *bion)) (BIO *); +int BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *)); +int (*BIO_meth_get_destroy(BIO_METHOD *biom)) (BIO *); +int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *)); +long (*BIO_meth_get_callback_ctrl(BIO_METHOD *biom)) + (BIO *, int, bio_info_cb *); +int BIO_meth_set_callback_ctrl(BIO_METHOD *biom, + long (*callback_ctrl) (BIO *, int, + bio_info_cb *)); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_BIO_strings(void); + +/* Error codes for the BIO functions. */ + +/* Function codes. */ +# define BIO_F_ACPT_STATE 100 +# define BIO_F_ADDR_STRINGS 134 +# define BIO_F_BIO_ACCEPT 101 +# define BIO_F_BIO_ACCEPT_EX 137 +# define BIO_F_BIO_ADDR_NEW 144 +# define BIO_F_BIO_CALLBACK_CTRL 131 +# define BIO_F_BIO_CONNECT 138 +# define BIO_F_BIO_CTRL 103 +# define BIO_F_BIO_GETS 104 +# define BIO_F_BIO_GET_HOST_IP 106 +# define BIO_F_BIO_GET_NEW_INDEX 102 +# define BIO_F_BIO_GET_PORT 107 +# define BIO_F_BIO_LISTEN 139 +# define BIO_F_BIO_LOOKUP 135 +# define BIO_F_BIO_MAKE_PAIR 121 +# define BIO_F_BIO_NEW 108 +# define BIO_F_BIO_NEW_FILE 109 +# define BIO_F_BIO_NEW_MEM_BUF 126 +# define BIO_F_BIO_NREAD 123 +# define BIO_F_BIO_NREAD0 124 +# define BIO_F_BIO_NWRITE 125 +# define BIO_F_BIO_NWRITE0 122 +# define BIO_F_BIO_PARSE_HOSTSERV 136 +# define BIO_F_BIO_PUTS 110 +# define BIO_F_BIO_READ 111 +# define BIO_F_BIO_SOCKET 140 +# define BIO_F_BIO_SOCKET_NBIO 142 +# define BIO_F_BIO_SOCK_INFO 141 +# define BIO_F_BIO_SOCK_INIT 112 +# define BIO_F_BIO_WRITE 113 +# define BIO_F_BUFFER_CTRL 114 +# define BIO_F_CONN_CTRL 127 +# define BIO_F_CONN_STATE 115 +# define BIO_F_DGRAM_SCTP_READ 132 +# define BIO_F_DGRAM_SCTP_WRITE 133 +# define BIO_F_FILE_CTRL 116 +# define BIO_F_FILE_READ 130 +# define BIO_F_LINEBUFFER_CTRL 129 +# define BIO_F_MEM_WRITE 117 +# define BIO_F_SSL_NEW 118 + +/* Reason codes. */ +# define BIO_R_ACCEPT_ERROR 100 +# define BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET 141 +# define BIO_R_AMBIGUOUS_HOST_OR_SERVICE 129 +# define BIO_R_BAD_FOPEN_MODE 101 +# define BIO_R_BROKEN_PIPE 124 +# define BIO_R_CONNECT_ERROR 103 +# define BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET 107 +# define BIO_R_GETSOCKNAME_ERROR 132 +# define BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS 133 +# define BIO_R_GETTING_SOCKTYPE 134 +# define BIO_R_INVALID_ARGUMENT 125 +# define BIO_R_INVALID_SOCKET 135 +# define BIO_R_IN_USE 123 +# define BIO_R_LISTEN_V6_ONLY 136 +# define BIO_R_LOOKUP_RETURNED_NOTHING 142 +# define BIO_R_MALFORMED_HOST_OR_SERVICE 130 +# define BIO_R_NBIO_CONNECT_ERROR 110 +# define BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED 143 +# define BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED 144 +# define BIO_R_NO_PORT_DEFINED 113 +# define BIO_R_NO_SUCH_FILE 128 +# define BIO_R_NULL_PARAMETER 115 +# define BIO_R_UNABLE_TO_BIND_SOCKET 117 +# define BIO_R_UNABLE_TO_CREATE_SOCKET 118 +# define BIO_R_UNABLE_TO_KEEPALIVE 137 +# define BIO_R_UNABLE_TO_LISTEN_SOCKET 119 +# define BIO_R_UNABLE_TO_NODELAY 138 +# define BIO_R_UNABLE_TO_REUSEADDR 139 +# define BIO_R_UNAVAILABLE_IP_FAMILY 145 +# define BIO_R_UNINITIALIZED 120 +# define BIO_R_UNKNOWN_INFO_TYPE 140 +# define BIO_R_UNSUPPORTED_IP_FAMILY 146 +# define BIO_R_UNSUPPORTED_METHOD 121 +# define BIO_R_UNSUPPORTED_PROTOCOL_FAMILY 131 +# define BIO_R_WRITE_TO_READ_ONLY_BIO 126 +# define BIO_R_WSASTARTUP 122 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/blowfish.h b/mobile/ios/FxA/FxA/include/openssl/blowfish.h new file mode 100644 index 0000000000..cd3e460e98 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/blowfish.h @@ -0,0 +1,61 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_BLOWFISH_H +# define HEADER_BLOWFISH_H + +# include + +# ifndef OPENSSL_NO_BF +# include +# ifdef __cplusplus +extern "C" { +# endif + +# define BF_ENCRYPT 1 +# define BF_DECRYPT 0 + +/*- + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! BF_LONG has to be at least 32 bits wide. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ +# define BF_LONG unsigned int + +# define BF_ROUNDS 16 +# define BF_BLOCK 8 + +typedef struct bf_key_st { + BF_LONG P[BF_ROUNDS + 2]; + BF_LONG S[4 * 256]; +} BF_KEY; + +void BF_set_key(BF_KEY *key, int len, const unsigned char *data); + +void BF_encrypt(BF_LONG *data, const BF_KEY *key); +void BF_decrypt(BF_LONG *data, const BF_KEY *key); + +void BF_ecb_encrypt(const unsigned char *in, unsigned char *out, + const BF_KEY *key, int enc); +void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length, + const BF_KEY *schedule, unsigned char *ivec, int enc); +void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, const BF_KEY *schedule, + unsigned char *ivec, int *num, int enc); +void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, const BF_KEY *schedule, + unsigned char *ivec, int *num); +const char *BF_options(void); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/bn.h b/mobile/ios/FxA/FxA/include/openssl/bn.h new file mode 100644 index 0000000000..17bd52136c --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/bn.h @@ -0,0 +1,575 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the Eric Young open source + * license provided above. + * + * The binary polynomial arithmetic software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#ifndef HEADER_BN_H +# define HEADER_BN_H + +# include +# ifndef OPENSSL_NO_STDIO +# include +# endif +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * 64-bit processor with LP64 ABI + */ +# ifdef SIXTY_FOUR_BIT_LONG +# define BN_ULONG unsigned long +# define BN_BYTES 8 +# endif + +/* + * 64-bit processor other than LP64 ABI + */ +# ifdef SIXTY_FOUR_BIT +# define BN_ULONG unsigned long long +# define BN_BYTES 8 +# endif + +# ifdef THIRTY_TWO_BIT +# define BN_ULONG unsigned int +# define BN_BYTES 4 +# endif + +# define BN_BITS2 (BN_BYTES * 8) +# define BN_BITS (BN_BITS2 * 2) +# define BN_TBIT ((BN_ULONG)1 << (BN_BITS2 - 1)) + +# define BN_FLG_MALLOCED 0x01 +# define BN_FLG_STATIC_DATA 0x02 + +/* + * avoid leaking exponent information through timing, + * BN_mod_exp_mont() will call BN_mod_exp_mont_consttime, + * BN_div() will call BN_div_no_branch, + * BN_mod_inverse() will call BN_mod_inverse_no_branch. + */ +# define BN_FLG_CONSTTIME 0x04 +# define BN_FLG_SECURE 0x08 + +# if OPENSSL_API_COMPAT < 0x00908000L +/* deprecated name for the flag */ +# define BN_FLG_EXP_CONSTTIME BN_FLG_CONSTTIME +# define BN_FLG_FREE 0x8000 /* used for debugging */ +# endif + +void BN_set_flags(BIGNUM *b, int n); +int BN_get_flags(const BIGNUM *b, int n); + +/* Values for |top| in BN_rand() */ +#define BN_RAND_TOP_ANY -1 +#define BN_RAND_TOP_ONE 0 +#define BN_RAND_TOP_TWO 1 + +/* Values for |bottom| in BN_rand() */ +#define BN_RAND_BOTTOM_ANY 0 +#define BN_RAND_BOTTOM_ODD 1 + +/* + * get a clone of a BIGNUM with changed flags, for *temporary* use only (the + * two BIGNUMs cannot be used in parallel!). Also only for *read only* use. The + * value |dest| should be a newly allocated BIGNUM obtained via BN_new() that + * has not been otherwise initialised or used. + */ +void BN_with_flags(BIGNUM *dest, const BIGNUM *b, int flags); + +/* Wrapper function to make using BN_GENCB easier */ +int BN_GENCB_call(BN_GENCB *cb, int a, int b); + +BN_GENCB *BN_GENCB_new(void); +void BN_GENCB_free(BN_GENCB *cb); + +/* Populate a BN_GENCB structure with an "old"-style callback */ +void BN_GENCB_set_old(BN_GENCB *gencb, void (*callback) (int, int, void *), + void *cb_arg); + +/* Populate a BN_GENCB structure with a "new"-style callback */ +void BN_GENCB_set(BN_GENCB *gencb, int (*callback) (int, int, BN_GENCB *), + void *cb_arg); + +void *BN_GENCB_get_arg(BN_GENCB *cb); + +# define BN_prime_checks 0 /* default: select number of iterations based + * on the size of the number */ + +/* + * number of Miller-Rabin iterations for an error rate of less than 2^-80 for + * random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook of + * Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996]; + * original paper: Damgaard, Landrock, Pomerance: Average case error + * estimates for the strong probable prime test. -- Math. Comp. 61 (1993) + * 177-194) + */ +# define BN_prime_checks_for_size(b) ((b) >= 1300 ? 2 : \ + (b) >= 850 ? 3 : \ + (b) >= 650 ? 4 : \ + (b) >= 550 ? 5 : \ + (b) >= 450 ? 6 : \ + (b) >= 400 ? 7 : \ + (b) >= 350 ? 8 : \ + (b) >= 300 ? 9 : \ + (b) >= 250 ? 12 : \ + (b) >= 200 ? 15 : \ + (b) >= 150 ? 18 : \ + /* b >= 100 */ 27) + +# define BN_num_bytes(a) ((BN_num_bits(a)+7)/8) + +int BN_abs_is_word(const BIGNUM *a, const BN_ULONG w); +int BN_is_zero(const BIGNUM *a); +int BN_is_one(const BIGNUM *a); +int BN_is_word(const BIGNUM *a, const BN_ULONG w); +int BN_is_odd(const BIGNUM *a); + +# define BN_one(a) (BN_set_word((a),1)) + +void BN_zero_ex(BIGNUM *a); + +# if OPENSSL_API_COMPAT >= 0x00908000L +# define BN_zero(a) BN_zero_ex(a) +# else +# define BN_zero(a) (BN_set_word((a),0)) +# endif + +const BIGNUM *BN_value_one(void); +char *BN_options(void); +BN_CTX *BN_CTX_new(void); +BN_CTX *BN_CTX_secure_new(void); +void BN_CTX_free(BN_CTX *c); +void BN_CTX_start(BN_CTX *ctx); +BIGNUM *BN_CTX_get(BN_CTX *ctx); +void BN_CTX_end(BN_CTX *ctx); +int BN_rand(BIGNUM *rnd, int bits, int top, int bottom); +int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom); +int BN_rand_range(BIGNUM *rnd, const BIGNUM *range); +int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range); +int BN_num_bits(const BIGNUM *a); +int BN_num_bits_word(BN_ULONG l); +int BN_security_bits(int L, int N); +BIGNUM *BN_new(void); +BIGNUM *BN_secure_new(void); +void BN_clear_free(BIGNUM *a); +BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b); +void BN_swap(BIGNUM *a, BIGNUM *b); +BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret); +int BN_bn2bin(const BIGNUM *a, unsigned char *to); +int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen); +BIGNUM *BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret); +int BN_bn2lebinpad(const BIGNUM *a, unsigned char *to, int tolen); +BIGNUM *BN_mpi2bn(const unsigned char *s, int len, BIGNUM *ret); +int BN_bn2mpi(const BIGNUM *a, unsigned char *to); +int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); +int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx); +/** BN_set_negative sets sign of a BIGNUM + * \param b pointer to the BIGNUM object + * \param n 0 if the BIGNUM b should be positive and a value != 0 otherwise + */ +void BN_set_negative(BIGNUM *b, int n); +/** BN_is_negative returns 1 if the BIGNUM is negative + * \param a pointer to the BIGNUM object + * \return 1 if a < 0 and 0 otherwise + */ +int BN_is_negative(const BIGNUM *b); + +int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, + BN_CTX *ctx); +# define BN_mod(rem,m,d,ctx) BN_div(NULL,(rem),(m),(d),(ctx)) +int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx); +int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx); +int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m); +int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx); +int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m); +int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx); +int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); +int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); +int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m); +int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m, + BN_CTX *ctx); +int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m); + +BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w); +BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w); +int BN_mul_word(BIGNUM *a, BN_ULONG w); +int BN_add_word(BIGNUM *a, BN_ULONG w); +int BN_sub_word(BIGNUM *a, BN_ULONG w); +int BN_set_word(BIGNUM *a, BN_ULONG w); +BN_ULONG BN_get_word(const BIGNUM *a); + +int BN_cmp(const BIGNUM *a, const BIGNUM *b); +void BN_free(BIGNUM *a); +int BN_is_bit_set(const BIGNUM *a, int n); +int BN_lshift(BIGNUM *r, const BIGNUM *a, int n); +int BN_lshift1(BIGNUM *r, const BIGNUM *a); +int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); + +int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); +int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *in_mont); +int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1, + const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *m_ctx); +int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); + +int BN_mask_bits(BIGNUM *a, int n); +# ifndef OPENSSL_NO_STDIO +int BN_print_fp(FILE *fp, const BIGNUM *a); +# endif +int BN_print(BIO *bio, const BIGNUM *a); +int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx); +int BN_rshift(BIGNUM *r, const BIGNUM *a, int n); +int BN_rshift1(BIGNUM *r, const BIGNUM *a); +void BN_clear(BIGNUM *a); +BIGNUM *BN_dup(const BIGNUM *a); +int BN_ucmp(const BIGNUM *a, const BIGNUM *b); +int BN_set_bit(BIGNUM *a, int n); +int BN_clear_bit(BIGNUM *a, int n); +char *BN_bn2hex(const BIGNUM *a); +char *BN_bn2dec(const BIGNUM *a); +int BN_hex2bn(BIGNUM **a, const char *str); +int BN_dec2bn(BIGNUM **a, const char *str); +int BN_asc2bn(BIGNUM **a, const char *str); +int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); +int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); /* returns + * -2 for + * error */ +BIGNUM *BN_mod_inverse(BIGNUM *ret, + const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx); +BIGNUM *BN_mod_sqrt(BIGNUM *ret, + const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx); + +void BN_consttime_swap(BN_ULONG swap, BIGNUM *a, BIGNUM *b, int nwords); + +/* Deprecated versions */ +DEPRECATEDIN_0_9_8(BIGNUM *BN_generate_prime(BIGNUM *ret, int bits, int safe, + const BIGNUM *add, + const BIGNUM *rem, + void (*callback) (int, int, + void *), + void *cb_arg)) +DEPRECATEDIN_0_9_8(int + BN_is_prime(const BIGNUM *p, int nchecks, + void (*callback) (int, int, void *), + BN_CTX *ctx, void *cb_arg)) +DEPRECATEDIN_0_9_8(int + BN_is_prime_fasttest(const BIGNUM *p, int nchecks, + void (*callback) (int, int, void *), + BN_CTX *ctx, void *cb_arg, + int do_trial_division)) + +/* Newer versions */ +int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add, + const BIGNUM *rem, BN_GENCB *cb); +int BN_is_prime_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, BN_GENCB *cb); +int BN_is_prime_fasttest_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, + int do_trial_division, BN_GENCB *cb); + +int BN_X931_generate_Xpq(BIGNUM *Xp, BIGNUM *Xq, int nbits, BN_CTX *ctx); + +int BN_X931_derive_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2, + const BIGNUM *Xp, const BIGNUM *Xp1, + const BIGNUM *Xp2, const BIGNUM *e, BN_CTX *ctx, + BN_GENCB *cb); +int BN_X931_generate_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2, BIGNUM *Xp1, + BIGNUM *Xp2, const BIGNUM *Xp, const BIGNUM *e, + BN_CTX *ctx, BN_GENCB *cb); + +BN_MONT_CTX *BN_MONT_CTX_new(void); +int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + BN_MONT_CTX *mont, BN_CTX *ctx); +int BN_to_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont, + BN_CTX *ctx); +int BN_from_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont, + BN_CTX *ctx); +void BN_MONT_CTX_free(BN_MONT_CTX *mont); +int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx); +BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from); +BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_RWLOCK *lock, + const BIGNUM *mod, BN_CTX *ctx); + +/* BN_BLINDING flags */ +# define BN_BLINDING_NO_UPDATE 0x00000001 +# define BN_BLINDING_NO_RECREATE 0x00000002 + +BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod); +void BN_BLINDING_free(BN_BLINDING *b); +int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *); +int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, + BN_CTX *); + +int BN_BLINDING_is_current_thread(BN_BLINDING *b); +void BN_BLINDING_set_current_thread(BN_BLINDING *b); +int BN_BLINDING_lock(BN_BLINDING *b); +int BN_BLINDING_unlock(BN_BLINDING *b); + +unsigned long BN_BLINDING_get_flags(const BN_BLINDING *); +void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long); +BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b, + const BIGNUM *e, BIGNUM *m, BN_CTX *ctx, + int (*bn_mod_exp) (BIGNUM *r, + const BIGNUM *a, + const BIGNUM *p, + const BIGNUM *m, + BN_CTX *ctx, + BN_MONT_CTX *m_ctx), + BN_MONT_CTX *m_ctx); + +DEPRECATEDIN_0_9_8(void BN_set_params(int mul, int high, int low, int mont)) +DEPRECATEDIN_0_9_8(int BN_get_params(int which)) /* 0, mul, 1 high, 2 low, 3 + * mont */ + +BN_RECP_CTX *BN_RECP_CTX_new(void); +void BN_RECP_CTX_free(BN_RECP_CTX *recp); +int BN_RECP_CTX_set(BN_RECP_CTX *recp, const BIGNUM *rdiv, BN_CTX *ctx); +int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y, + BN_RECP_CTX *recp, BN_CTX *ctx); +int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); +int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, + BN_RECP_CTX *recp, BN_CTX *ctx); + +# ifndef OPENSSL_NO_EC2M + +/* + * Functions for arithmetic over binary polynomials represented by BIGNUMs. + * The BIGNUM::neg property of BIGNUMs representing binary polynomials is + * ignored. Note that input arguments are not const so that their bit arrays + * can be expanded to the appropriate size if needed. + */ + +/* + * r = a + b + */ +int BN_GF2m_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +# define BN_GF2m_sub(r, a, b) BN_GF2m_add(r, a, b) +/* + * r=a mod p + */ +int BN_GF2m_mod(BIGNUM *r, const BIGNUM *a, const BIGNUM *p); +/* r = (a * b) mod p */ +int BN_GF2m_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *p, BN_CTX *ctx); +/* r = (a * a) mod p */ +int BN_GF2m_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +/* r = (1 / b) mod p */ +int BN_GF2m_mod_inv(BIGNUM *r, const BIGNUM *b, const BIGNUM *p, BN_CTX *ctx); +/* r = (a / b) mod p */ +int BN_GF2m_mod_div(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *p, BN_CTX *ctx); +/* r = (a ^ b) mod p */ +int BN_GF2m_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *p, BN_CTX *ctx); +/* r = sqrt(a) mod p */ +int BN_GF2m_mod_sqrt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); +/* r^2 + r = a mod p */ +int BN_GF2m_mod_solve_quad(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); +# define BN_GF2m_cmp(a, b) BN_ucmp((a), (b)) +/*- + * Some functions allow for representation of the irreducible polynomials + * as an unsigned int[], say p. The irreducible f(t) is then of the form: + * t^p[0] + t^p[1] + ... + t^p[k] + * where m = p[0] > p[1] > ... > p[k] = 0. + */ +/* r = a mod p */ +int BN_GF2m_mod_arr(BIGNUM *r, const BIGNUM *a, const int p[]); +/* r = (a * b) mod p */ +int BN_GF2m_mod_mul_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const int p[], BN_CTX *ctx); +/* r = (a * a) mod p */ +int BN_GF2m_mod_sqr_arr(BIGNUM *r, const BIGNUM *a, const int p[], + BN_CTX *ctx); +/* r = (1 / b) mod p */ +int BN_GF2m_mod_inv_arr(BIGNUM *r, const BIGNUM *b, const int p[], + BN_CTX *ctx); +/* r = (a / b) mod p */ +int BN_GF2m_mod_div_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const int p[], BN_CTX *ctx); +/* r = (a ^ b) mod p */ +int BN_GF2m_mod_exp_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const int p[], BN_CTX *ctx); +/* r = sqrt(a) mod p */ +int BN_GF2m_mod_sqrt_arr(BIGNUM *r, const BIGNUM *a, + const int p[], BN_CTX *ctx); +/* r^2 + r = a mod p */ +int BN_GF2m_mod_solve_quad_arr(BIGNUM *r, const BIGNUM *a, + const int p[], BN_CTX *ctx); +int BN_GF2m_poly2arr(const BIGNUM *a, int p[], int max); +int BN_GF2m_arr2poly(const int p[], BIGNUM *a); + +# endif + +/* + * faster mod functions for the 'NIST primes' 0 <= a < p^2 + */ +int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); + +const BIGNUM *BN_get0_nist_prime_192(void); +const BIGNUM *BN_get0_nist_prime_224(void); +const BIGNUM *BN_get0_nist_prime_256(void); +const BIGNUM *BN_get0_nist_prime_384(void); +const BIGNUM *BN_get0_nist_prime_521(void); + +int (*BN_nist_mod_func(const BIGNUM *p)) (BIGNUM *r, const BIGNUM *a, + const BIGNUM *field, BN_CTX *ctx); + +int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, + const BIGNUM *priv, const unsigned char *message, + size_t message_len, BN_CTX *ctx); + +/* Primes from RFC 2409 */ +BIGNUM *BN_get_rfc2409_prime_768(BIGNUM *bn); +BIGNUM *BN_get_rfc2409_prime_1024(BIGNUM *bn); + +/* Primes from RFC 3526 */ +BIGNUM *BN_get_rfc3526_prime_1536(BIGNUM *bn); +BIGNUM *BN_get_rfc3526_prime_2048(BIGNUM *bn); +BIGNUM *BN_get_rfc3526_prime_3072(BIGNUM *bn); +BIGNUM *BN_get_rfc3526_prime_4096(BIGNUM *bn); +BIGNUM *BN_get_rfc3526_prime_6144(BIGNUM *bn); +BIGNUM *BN_get_rfc3526_prime_8192(BIGNUM *bn); + +# if OPENSSL_API_COMPAT < 0x10100000L +# define get_rfc2409_prime_768 BN_get_rfc2409_prime_768 +# define get_rfc2409_prime_1024 BN_get_rfc2409_prime_1024 +# define get_rfc3526_prime_1536 BN_get_rfc3526_prime_1536 +# define get_rfc3526_prime_2048 BN_get_rfc3526_prime_2048 +# define get_rfc3526_prime_3072 BN_get_rfc3526_prime_3072 +# define get_rfc3526_prime_4096 BN_get_rfc3526_prime_4096 +# define get_rfc3526_prime_6144 BN_get_rfc3526_prime_6144 +# define get_rfc3526_prime_8192 BN_get_rfc3526_prime_8192 +# endif + +int BN_bntest_rand(BIGNUM *rnd, int bits, int top, int bottom); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_BN_strings(void); + +/* Error codes for the BN functions. */ + +/* Function codes. */ +# define BN_F_BNRAND 127 +# define BN_F_BN_BLINDING_CONVERT_EX 100 +# define BN_F_BN_BLINDING_CREATE_PARAM 128 +# define BN_F_BN_BLINDING_INVERT_EX 101 +# define BN_F_BN_BLINDING_NEW 102 +# define BN_F_BN_BLINDING_UPDATE 103 +# define BN_F_BN_BN2DEC 104 +# define BN_F_BN_BN2HEX 105 +# define BN_F_BN_COMPUTE_WNAF 142 +# define BN_F_BN_CTX_GET 116 +# define BN_F_BN_CTX_NEW 106 +# define BN_F_BN_CTX_START 129 +# define BN_F_BN_DIV 107 +# define BN_F_BN_DIV_RECP 130 +# define BN_F_BN_EXP 123 +# define BN_F_BN_EXPAND_INTERNAL 120 +# define BN_F_BN_GENCB_NEW 143 +# define BN_F_BN_GENERATE_DSA_NONCE 140 +# define BN_F_BN_GENERATE_PRIME_EX 141 +# define BN_F_BN_GF2M_MOD 131 +# define BN_F_BN_GF2M_MOD_EXP 132 +# define BN_F_BN_GF2M_MOD_MUL 133 +# define BN_F_BN_GF2M_MOD_SOLVE_QUAD 134 +# define BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR 135 +# define BN_F_BN_GF2M_MOD_SQR 136 +# define BN_F_BN_GF2M_MOD_SQRT 137 +# define BN_F_BN_LSHIFT 145 +# define BN_F_BN_MOD_EXP2_MONT 118 +# define BN_F_BN_MOD_EXP_MONT 109 +# define BN_F_BN_MOD_EXP_MONT_CONSTTIME 124 +# define BN_F_BN_MOD_EXP_MONT_WORD 117 +# define BN_F_BN_MOD_EXP_RECP 125 +# define BN_F_BN_MOD_EXP_SIMPLE 126 +# define BN_F_BN_MOD_INVERSE 110 +# define BN_F_BN_MOD_INVERSE_NO_BRANCH 139 +# define BN_F_BN_MOD_LSHIFT_QUICK 119 +# define BN_F_BN_MOD_SQRT 121 +# define BN_F_BN_MPI2BN 112 +# define BN_F_BN_NEW 113 +# define BN_F_BN_RAND 114 +# define BN_F_BN_RAND_RANGE 122 +# define BN_F_BN_RSHIFT 146 +# define BN_F_BN_SET_WORDS 144 +# define BN_F_BN_USUB 115 + +/* Reason codes. */ +# define BN_R_ARG2_LT_ARG3 100 +# define BN_R_BAD_RECIPROCAL 101 +# define BN_R_BIGNUM_TOO_LONG 114 +# define BN_R_BITS_TOO_SMALL 118 +# define BN_R_CALLED_WITH_EVEN_MODULUS 102 +# define BN_R_DIV_BY_ZERO 103 +# define BN_R_ENCODING_ERROR 104 +# define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA 105 +# define BN_R_INPUT_NOT_REDUCED 110 +# define BN_R_INVALID_LENGTH 106 +# define BN_R_INVALID_RANGE 115 +# define BN_R_INVALID_SHIFT 119 +# define BN_R_NOT_A_SQUARE 111 +# define BN_R_NOT_INITIALIZED 107 +# define BN_R_NO_INVERSE 108 +# define BN_R_NO_SOLUTION 116 +# define BN_R_PRIVATE_KEY_TOO_LARGE 117 +# define BN_R_P_IS_NOT_PRIME 112 +# define BN_R_TOO_MANY_ITERATIONS 113 +# define BN_R_TOO_MANY_TEMPORARY_VARIABLES 109 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/buffer.h b/mobile/ios/FxA/FxA/include/openssl/buffer.h new file mode 100644 index 0000000000..91f0e07ff9 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/buffer.h @@ -0,0 +1,76 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_BUFFER_H +# define HEADER_BUFFER_H + +# include +# ifndef HEADER_CRYPTO_H +# include +# endif + + +#ifdef __cplusplus +extern "C" { +#endif + +# include + +# if !defined(NO_SYS_TYPES_H) +# include +# endif + +/* + * These names are outdated as of OpenSSL 1.1; a future release + * will move them to be deprecated. + */ +# define BUF_strdup(s) OPENSSL_strdup(s) +# define BUF_strndup(s, size) OPENSSL_strndup(s, size) +# define BUF_memdup(data, size) OPENSSL_memdup(data, size) +# define BUF_strlcpy(dst, src, size) OPENSSL_strlcpy(dst, src, size) +# define BUF_strlcat(dst, src, size) OPENSSL_strlcat(dst, src, size) +# define BUF_strnlen(str, maxlen) OPENSSL_strnlen(str, maxlen) + +struct buf_mem_st { + size_t length; /* current number of bytes */ + char *data; + size_t max; /* size of buffer */ + unsigned long flags; +}; + +# define BUF_MEM_FLAG_SECURE 0x01 + +BUF_MEM *BUF_MEM_new(void); +BUF_MEM *BUF_MEM_new_ex(unsigned long flags); +void BUF_MEM_free(BUF_MEM *a); +size_t BUF_MEM_grow(BUF_MEM *str, size_t len); +size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len); +void BUF_reverse(unsigned char *out, const unsigned char *in, size_t siz); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_BUF_strings(void); + +/* Error codes for the BUF functions. */ + +/* Function codes. */ +# define BUF_F_BUF_MEM_GROW 100 +# define BUF_F_BUF_MEM_GROW_CLEAN 105 +# define BUF_F_BUF_MEM_NEW 101 + +/* Reason codes. */ + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/camellia.h b/mobile/ios/FxA/FxA/include/openssl/camellia.h new file mode 100644 index 0000000000..151f3c1349 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/camellia.h @@ -0,0 +1,83 @@ +/* + * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_CAMELLIA_H +# define HEADER_CAMELLIA_H + +# include + +# ifndef OPENSSL_NO_CAMELLIA +# include +#ifdef __cplusplus +extern "C" { +#endif + +# define CAMELLIA_ENCRYPT 1 +# define CAMELLIA_DECRYPT 0 + +/* + * Because array size can't be a const in C, the following two are macros. + * Both sizes are in bytes. + */ + +/* This should be a hidden type, but EVP requires that the size be known */ + +# define CAMELLIA_BLOCK_SIZE 16 +# define CAMELLIA_TABLE_BYTE_LEN 272 +# define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4) + +typedef unsigned int KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; /* to match + * with WORD */ + +struct camellia_key_st { + union { + double d; /* ensures 64-bit align */ + KEY_TABLE_TYPE rd_key; + } u; + int grand_rounds; +}; +typedef struct camellia_key_st CAMELLIA_KEY; + +int Camellia_set_key(const unsigned char *userKey, const int bits, + CAMELLIA_KEY *key); + +void Camellia_encrypt(const unsigned char *in, unsigned char *out, + const CAMELLIA_KEY *key); +void Camellia_decrypt(const unsigned char *in, unsigned char *out, + const CAMELLIA_KEY *key); + +void Camellia_ecb_encrypt(const unsigned char *in, unsigned char *out, + const CAMELLIA_KEY *key, const int enc); +void Camellia_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const CAMELLIA_KEY *key, + unsigned char *ivec, const int enc); +void Camellia_cfb128_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const CAMELLIA_KEY *key, + unsigned char *ivec, int *num, const int enc); +void Camellia_cfb1_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const CAMELLIA_KEY *key, + unsigned char *ivec, int *num, const int enc); +void Camellia_cfb8_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const CAMELLIA_KEY *key, + unsigned char *ivec, int *num, const int enc); +void Camellia_ofb128_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const CAMELLIA_KEY *key, + unsigned char *ivec, int *num); +void Camellia_ctr128_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const CAMELLIA_KEY *key, + unsigned char ivec[CAMELLIA_BLOCK_SIZE], + unsigned char ecount_buf[CAMELLIA_BLOCK_SIZE], + unsigned int *num); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/cast.h b/mobile/ios/FxA/FxA/include/openssl/cast.h new file mode 100644 index 0000000000..2cc89ae013 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/cast.h @@ -0,0 +1,53 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_CAST_H +# define HEADER_CAST_H + +# include + +# ifndef OPENSSL_NO_CAST +# ifdef __cplusplus +extern "C" { +# endif + +# define CAST_ENCRYPT 1 +# define CAST_DECRYPT 0 + +# define CAST_LONG unsigned int + +# define CAST_BLOCK 8 +# define CAST_KEY_LENGTH 16 + +typedef struct cast_key_st { + CAST_LONG data[32]; + int short_key; /* Use reduced rounds for short key */ +} CAST_KEY; + +void CAST_set_key(CAST_KEY *key, int len, const unsigned char *data); +void CAST_ecb_encrypt(const unsigned char *in, unsigned char *out, + const CAST_KEY *key, int enc); +void CAST_encrypt(CAST_LONG *data, const CAST_KEY *key); +void CAST_decrypt(CAST_LONG *data, const CAST_KEY *key); +void CAST_cbc_encrypt(const unsigned char *in, unsigned char *out, + long length, const CAST_KEY *ks, unsigned char *iv, + int enc); +void CAST_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, const CAST_KEY *schedule, + unsigned char *ivec, int *num, int enc); +void CAST_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, const CAST_KEY *schedule, + unsigned char *ivec, int *num); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/cmac.h b/mobile/ios/FxA/FxA/include/openssl/cmac.h new file mode 100644 index 0000000000..3535a9abf7 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/cmac.h @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_CMAC_H +# define HEADER_CMAC_H + +# ifndef OPENSSL_NO_CMAC + +#ifdef __cplusplus +extern "C" { +#endif + +# include + +/* Opaque */ +typedef struct CMAC_CTX_st CMAC_CTX; + +CMAC_CTX *CMAC_CTX_new(void); +void CMAC_CTX_cleanup(CMAC_CTX *ctx); +void CMAC_CTX_free(CMAC_CTX *ctx); +EVP_CIPHER_CTX *CMAC_CTX_get0_cipher_ctx(CMAC_CTX *ctx); +int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in); + +int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen, + const EVP_CIPHER *cipher, ENGINE *impl); +int CMAC_Update(CMAC_CTX *ctx, const void *data, size_t dlen); +int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen); +int CMAC_resume(CMAC_CTX *ctx); + +#ifdef __cplusplus +} +#endif + +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/cms.h b/mobile/ios/FxA/FxA/include/openssl/cms.h new file mode 100644 index 0000000000..7e534e0dd6 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/cms.h @@ -0,0 +1,512 @@ +/* + * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_CMS_H +# define HEADER_CMS_H + +# include + +# ifndef OPENSSL_NO_CMS +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + +typedef struct CMS_ContentInfo_st CMS_ContentInfo; +typedef struct CMS_SignerInfo_st CMS_SignerInfo; +typedef struct CMS_CertificateChoices CMS_CertificateChoices; +typedef struct CMS_RevocationInfoChoice_st CMS_RevocationInfoChoice; +typedef struct CMS_RecipientInfo_st CMS_RecipientInfo; +typedef struct CMS_ReceiptRequest_st CMS_ReceiptRequest; +typedef struct CMS_Receipt_st CMS_Receipt; +typedef struct CMS_RecipientEncryptedKey_st CMS_RecipientEncryptedKey; +typedef struct CMS_OtherKeyAttribute_st CMS_OtherKeyAttribute; + +DEFINE_STACK_OF(CMS_SignerInfo) +DEFINE_STACK_OF(CMS_RecipientEncryptedKey) +DEFINE_STACK_OF(CMS_RecipientInfo) +DEFINE_STACK_OF(CMS_RevocationInfoChoice) +DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo) +DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest) +DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo) + +# define CMS_SIGNERINFO_ISSUER_SERIAL 0 +# define CMS_SIGNERINFO_KEYIDENTIFIER 1 + +# define CMS_RECIPINFO_NONE -1 +# define CMS_RECIPINFO_TRANS 0 +# define CMS_RECIPINFO_AGREE 1 +# define CMS_RECIPINFO_KEK 2 +# define CMS_RECIPINFO_PASS 3 +# define CMS_RECIPINFO_OTHER 4 + +/* S/MIME related flags */ + +# define CMS_TEXT 0x1 +# define CMS_NOCERTS 0x2 +# define CMS_NO_CONTENT_VERIFY 0x4 +# define CMS_NO_ATTR_VERIFY 0x8 +# define CMS_NOSIGS \ + (CMS_NO_CONTENT_VERIFY|CMS_NO_ATTR_VERIFY) +# define CMS_NOINTERN 0x10 +# define CMS_NO_SIGNER_CERT_VERIFY 0x20 +# define CMS_NOVERIFY 0x20 +# define CMS_DETACHED 0x40 +# define CMS_BINARY 0x80 +# define CMS_NOATTR 0x100 +# define CMS_NOSMIMECAP 0x200 +# define CMS_NOOLDMIMETYPE 0x400 +# define CMS_CRLFEOL 0x800 +# define CMS_STREAM 0x1000 +# define CMS_NOCRL 0x2000 +# define CMS_PARTIAL 0x4000 +# define CMS_REUSE_DIGEST 0x8000 +# define CMS_USE_KEYID 0x10000 +# define CMS_DEBUG_DECRYPT 0x20000 +# define CMS_KEY_PARAM 0x40000 +# define CMS_ASCIICRLF 0x80000 + +const ASN1_OBJECT *CMS_get0_type(const CMS_ContentInfo *cms); + +BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont); +int CMS_dataFinal(CMS_ContentInfo *cms, BIO *bio); + +ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms); +int CMS_is_detached(CMS_ContentInfo *cms); +int CMS_set_detached(CMS_ContentInfo *cms, int detached); + +# ifdef HEADER_PEM_H +DECLARE_PEM_rw_const(CMS, CMS_ContentInfo) +# endif +int CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms); +CMS_ContentInfo *d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms); +int i2d_CMS_bio(BIO *bp, CMS_ContentInfo *cms); + +BIO *BIO_new_CMS(BIO *out, CMS_ContentInfo *cms); +int i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags); +int PEM_write_bio_CMS_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, + int flags); +CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont); +int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags); + +int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, + unsigned int flags); + +CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, + STACK_OF(X509) *certs, BIO *data, + unsigned int flags); + +CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, + X509 *signcert, EVP_PKEY *pkey, + STACK_OF(X509) *certs, unsigned int flags); + +int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags); +CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags); + +int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, + unsigned int flags); +CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, + unsigned int flags); + +int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, + const unsigned char *key, size_t keylen, + BIO *dcont, BIO *out, unsigned int flags); + +CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, + const unsigned char *key, + size_t keylen, unsigned int flags); + +int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, + const unsigned char *key, size_t keylen); + +int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, + X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags); + +int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, + STACK_OF(X509) *certs, + X509_STORE *store, unsigned int flags); + +STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms); + +CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in, + const EVP_CIPHER *cipher, unsigned int flags); + +int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert, + BIO *dcont, BIO *out, unsigned int flags); + +int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert); +int CMS_decrypt_set1_key(CMS_ContentInfo *cms, + unsigned char *key, size_t keylen, + const unsigned char *id, size_t idlen); +int CMS_decrypt_set1_password(CMS_ContentInfo *cms, + unsigned char *pass, ossl_ssize_t passlen); + +STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms); +int CMS_RecipientInfo_type(CMS_RecipientInfo *ri); +EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri); +CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher); +CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, + X509 *recip, unsigned int flags); +int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey); +int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert); +int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, + EVP_PKEY **pk, X509 **recip, + X509_ALGOR **palg); +int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, + ASN1_INTEGER **sno); + +CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, + unsigned char *key, size_t keylen, + unsigned char *id, size_t idlen, + ASN1_GENERALIZEDTIME *date, + ASN1_OBJECT *otherTypeId, + ASN1_TYPE *otherType); + +int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri, + X509_ALGOR **palg, + ASN1_OCTET_STRING **pid, + ASN1_GENERALIZEDTIME **pdate, + ASN1_OBJECT **potherid, + ASN1_TYPE **pothertype); + +int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri, + unsigned char *key, size_t keylen); + +int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, + const unsigned char *id, size_t idlen); + +int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri, + unsigned char *pass, + ossl_ssize_t passlen); + +CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms, + int iter, int wrap_nid, + int pbe_nid, + unsigned char *pass, + ossl_ssize_t passlen, + const EVP_CIPHER *kekciph); + +int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri); +int CMS_RecipientInfo_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri); + +int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, + unsigned int flags); +CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags); + +int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid); +const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms); + +CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms); +int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert); +int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert); +STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms); + +CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms); +int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl); +int CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl); +STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms); + +int CMS_SignedData_init(CMS_ContentInfo *cms); +CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, + X509 *signer, EVP_PKEY *pk, const EVP_MD *md, + unsigned int flags); +EVP_PKEY_CTX *CMS_SignerInfo_get0_pkey_ctx(CMS_SignerInfo *si); +EVP_MD_CTX *CMS_SignerInfo_get0_md_ctx(CMS_SignerInfo *si); +STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms); + +void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer); +int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, ASN1_INTEGER **sno); +int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert); +int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *certs, + unsigned int flags); +void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, + X509 **signer, X509_ALGOR **pdig, + X509_ALGOR **psig); +ASN1_OCTET_STRING *CMS_SignerInfo_get0_signature(CMS_SignerInfo *si); +int CMS_SignerInfo_sign(CMS_SignerInfo *si); +int CMS_SignerInfo_verify(CMS_SignerInfo *si); +int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain); + +int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs); +int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs, + int algnid, int keysize); +int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap); + +int CMS_signed_get_attr_count(const CMS_SignerInfo *si); +int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid, + int lastpos); +int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, const ASN1_OBJECT *obj, + int lastpos); +X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc); +X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc); +int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr); +int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int type, + const void *bytes, int len); +int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si, + int nid, int type, + const void *bytes, int len); +int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si, + const char *attrname, int type, + const void *bytes, int len); +void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *oid, + int lastpos, int type); + +int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si); +int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid, + int lastpos); +int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int lastpos); +X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc); +X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc); +int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr); +int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int type, + const void *bytes, int len); +int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si, + int nid, int type, + const void *bytes, int len); +int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si, + const char *attrname, int type, + const void *bytes, int len); +void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid, + int lastpos, int type); + +# ifdef HEADER_X509V3_H + +int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr); +CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen, + int allorfirst, + STACK_OF(GENERAL_NAMES) + *receiptList, STACK_OF(GENERAL_NAMES) + *receiptsTo); +int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr); +void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, + ASN1_STRING **pcid, + int *pallorfirst, + STACK_OF(GENERAL_NAMES) **plist, + STACK_OF(GENERAL_NAMES) **prto); +# endif +int CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri, + X509_ALGOR **palg, + ASN1_OCTET_STRING **pukm); +STACK_OF(CMS_RecipientEncryptedKey) +*CMS_RecipientInfo_kari_get0_reks(CMS_RecipientInfo *ri); + +int CMS_RecipientInfo_kari_get0_orig_id(CMS_RecipientInfo *ri, + X509_ALGOR **pubalg, + ASN1_BIT_STRING **pubkey, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, + ASN1_INTEGER **sno); + +int CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo *ri, X509 *cert); + +int CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek, + ASN1_OCTET_STRING **keyid, + ASN1_GENERALIZEDTIME **tm, + CMS_OtherKeyAttribute **other, + X509_NAME **issuer, ASN1_INTEGER **sno); +int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek, + X509 *cert); +int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk); +EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri); +int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri, + CMS_RecipientEncryptedKey *rek); + +int CMS_SharedInfo_encode(unsigned char **pder, X509_ALGOR *kekalg, + ASN1_OCTET_STRING *ukm, int keylen); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_CMS_strings(void); + +/* Error codes for the CMS functions. */ + +/* Function codes. */ +# define CMS_F_CHECK_CONTENT 99 +# define CMS_F_CMS_ADD0_CERT 164 +# define CMS_F_CMS_ADD0_RECIPIENT_KEY 100 +# define CMS_F_CMS_ADD0_RECIPIENT_PASSWORD 165 +# define CMS_F_CMS_ADD1_RECEIPTREQUEST 158 +# define CMS_F_CMS_ADD1_RECIPIENT_CERT 101 +# define CMS_F_CMS_ADD1_SIGNER 102 +# define CMS_F_CMS_ADD1_SIGNINGTIME 103 +# define CMS_F_CMS_COMPRESS 104 +# define CMS_F_CMS_COMPRESSEDDATA_CREATE 105 +# define CMS_F_CMS_COMPRESSEDDATA_INIT_BIO 106 +# define CMS_F_CMS_COPY_CONTENT 107 +# define CMS_F_CMS_COPY_MESSAGEDIGEST 108 +# define CMS_F_CMS_DATA 109 +# define CMS_F_CMS_DATAFINAL 110 +# define CMS_F_CMS_DATAINIT 111 +# define CMS_F_CMS_DECRYPT 112 +# define CMS_F_CMS_DECRYPT_SET1_KEY 113 +# define CMS_F_CMS_DECRYPT_SET1_PASSWORD 166 +# define CMS_F_CMS_DECRYPT_SET1_PKEY 114 +# define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX 115 +# define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO 116 +# define CMS_F_CMS_DIGESTEDDATA_DO_FINAL 117 +# define CMS_F_CMS_DIGEST_VERIFY 118 +# define CMS_F_CMS_ENCODE_RECEIPT 161 +# define CMS_F_CMS_ENCRYPT 119 +# define CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO 120 +# define CMS_F_CMS_ENCRYPTEDDATA_DECRYPT 121 +# define CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT 122 +# define CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY 123 +# define CMS_F_CMS_ENVELOPEDDATA_CREATE 124 +# define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO 125 +# define CMS_F_CMS_ENVELOPED_DATA_INIT 126 +# define CMS_F_CMS_ENV_ASN1_CTRL 171 +# define CMS_F_CMS_FINAL 127 +# define CMS_F_CMS_GET0_CERTIFICATE_CHOICES 128 +# define CMS_F_CMS_GET0_CONTENT 129 +# define CMS_F_CMS_GET0_ECONTENT_TYPE 130 +# define CMS_F_CMS_GET0_ENVELOPED 131 +# define CMS_F_CMS_GET0_REVOCATION_CHOICES 132 +# define CMS_F_CMS_GET0_SIGNED 133 +# define CMS_F_CMS_MSGSIGDIGEST_ADD1 162 +# define CMS_F_CMS_RECEIPTREQUEST_CREATE0 159 +# define CMS_F_CMS_RECEIPT_VERIFY 160 +# define CMS_F_CMS_RECIPIENTINFO_DECRYPT 134 +# define CMS_F_CMS_RECIPIENTINFO_ENCRYPT 169 +# define CMS_F_CMS_RECIPIENTINFO_KARI_ENCRYPT 178 +# define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ALG 175 +# define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ORIG_ID 173 +# define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_REKS 172 +# define CMS_F_CMS_RECIPIENTINFO_KARI_ORIG_ID_CMP 174 +# define CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT 135 +# define CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT 136 +# define CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID 137 +# define CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP 138 +# define CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP 139 +# define CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT 140 +# define CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT 141 +# define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS 142 +# define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID 143 +# define CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT 167 +# define CMS_F_CMS_RECIPIENTINFO_SET0_KEY 144 +# define CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD 168 +# define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY 145 +# define CMS_F_CMS_SD_ASN1_CTRL 170 +# define CMS_F_CMS_SET1_IAS 176 +# define CMS_F_CMS_SET1_KEYID 177 +# define CMS_F_CMS_SET1_SIGNERIDENTIFIER 146 +# define CMS_F_CMS_SET_DETACHED 147 +# define CMS_F_CMS_SIGN 148 +# define CMS_F_CMS_SIGNED_DATA_INIT 149 +# define CMS_F_CMS_SIGNERINFO_CONTENT_SIGN 150 +# define CMS_F_CMS_SIGNERINFO_SIGN 151 +# define CMS_F_CMS_SIGNERINFO_VERIFY 152 +# define CMS_F_CMS_SIGNERINFO_VERIFY_CERT 153 +# define CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT 154 +# define CMS_F_CMS_SIGN_RECEIPT 163 +# define CMS_F_CMS_STREAM 155 +# define CMS_F_CMS_UNCOMPRESS 156 +# define CMS_F_CMS_VERIFY 157 + +/* Reason codes. */ +# define CMS_R_ADD_SIGNER_ERROR 99 +# define CMS_R_CERTIFICATE_ALREADY_PRESENT 175 +# define CMS_R_CERTIFICATE_HAS_NO_KEYID 160 +# define CMS_R_CERTIFICATE_VERIFY_ERROR 100 +# define CMS_R_CIPHER_INITIALISATION_ERROR 101 +# define CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR 102 +# define CMS_R_CMS_DATAFINAL_ERROR 103 +# define CMS_R_CMS_LIB 104 +# define CMS_R_CONTENTIDENTIFIER_MISMATCH 170 +# define CMS_R_CONTENT_NOT_FOUND 105 +# define CMS_R_CONTENT_TYPE_MISMATCH 171 +# define CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA 106 +# define CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA 107 +# define CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA 108 +# define CMS_R_CONTENT_VERIFY_ERROR 109 +# define CMS_R_CTRL_ERROR 110 +# define CMS_R_CTRL_FAILURE 111 +# define CMS_R_DECRYPT_ERROR 112 +# define CMS_R_ERROR_GETTING_PUBLIC_KEY 113 +# define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 114 +# define CMS_R_ERROR_SETTING_KEY 115 +# define CMS_R_ERROR_SETTING_RECIPIENTINFO 116 +# define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 117 +# define CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER 176 +# define CMS_R_INVALID_KEY_LENGTH 118 +# define CMS_R_MD_BIO_INIT_ERROR 119 +# define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 120 +# define CMS_R_MESSAGEDIGEST_WRONG_LENGTH 121 +# define CMS_R_MSGSIGDIGEST_ERROR 172 +# define CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE 162 +# define CMS_R_MSGSIGDIGEST_WRONG_LENGTH 163 +# define CMS_R_NEED_ONE_SIGNER 164 +# define CMS_R_NOT_A_SIGNED_RECEIPT 165 +# define CMS_R_NOT_ENCRYPTED_DATA 122 +# define CMS_R_NOT_KEK 123 +# define CMS_R_NOT_KEY_AGREEMENT 181 +# define CMS_R_NOT_KEY_TRANSPORT 124 +# define CMS_R_NOT_PWRI 177 +# define CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 125 +# define CMS_R_NO_CIPHER 126 +# define CMS_R_NO_CONTENT 127 +# define CMS_R_NO_CONTENT_TYPE 173 +# define CMS_R_NO_DEFAULT_DIGEST 128 +# define CMS_R_NO_DIGEST_SET 129 +# define CMS_R_NO_KEY 130 +# define CMS_R_NO_KEY_OR_CERT 174 +# define CMS_R_NO_MATCHING_DIGEST 131 +# define CMS_R_NO_MATCHING_RECIPIENT 132 +# define CMS_R_NO_MATCHING_SIGNATURE 166 +# define CMS_R_NO_MSGSIGDIGEST 167 +# define CMS_R_NO_PASSWORD 178 +# define CMS_R_NO_PRIVATE_KEY 133 +# define CMS_R_NO_PUBLIC_KEY 134 +# define CMS_R_NO_RECEIPT_REQUEST 168 +# define CMS_R_NO_SIGNERS 135 +# define CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 136 +# define CMS_R_RECEIPT_DECODE_ERROR 169 +# define CMS_R_RECIPIENT_ERROR 137 +# define CMS_R_SIGNER_CERTIFICATE_NOT_FOUND 138 +# define CMS_R_SIGNFINAL_ERROR 139 +# define CMS_R_SMIME_TEXT_ERROR 140 +# define CMS_R_STORE_INIT_ERROR 141 +# define CMS_R_TYPE_NOT_COMPRESSED_DATA 142 +# define CMS_R_TYPE_NOT_DATA 143 +# define CMS_R_TYPE_NOT_DIGESTED_DATA 144 +# define CMS_R_TYPE_NOT_ENCRYPTED_DATA 145 +# define CMS_R_TYPE_NOT_ENVELOPED_DATA 146 +# define CMS_R_UNABLE_TO_FINALIZE_CONTEXT 147 +# define CMS_R_UNKNOWN_CIPHER 148 +# define CMS_R_UNKNOWN_DIGEST_ALGORIHM 149 +# define CMS_R_UNKNOWN_ID 150 +# define CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM 151 +# define CMS_R_UNSUPPORTED_CONTENT_TYPE 152 +# define CMS_R_UNSUPPORTED_KEK_ALGORITHM 153 +# define CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM 179 +# define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 154 +# define CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE 155 +# define CMS_R_UNSUPPORTED_TYPE 156 +# define CMS_R_UNWRAP_ERROR 157 +# define CMS_R_UNWRAP_FAILURE 180 +# define CMS_R_VERIFICATION_FAILURE 158 +# define CMS_R_WRAP_ERROR 159 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/comp.h b/mobile/ios/FxA/FxA/include/openssl/comp.h new file mode 100644 index 0000000000..260ff1e0ac --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/comp.h @@ -0,0 +1,72 @@ +/* + * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_COMP_H +# define HEADER_COMP_H + +# include + +# ifndef OPENSSL_NO_COMP +# include +# ifdef __cplusplus +extern "C" { +# endif + + + +COMP_CTX *COMP_CTX_new(COMP_METHOD *meth); +const COMP_METHOD *COMP_CTX_get_method(const COMP_CTX *ctx); +int COMP_CTX_get_type(const COMP_CTX* comp); +int COMP_get_type(const COMP_METHOD *meth); +const char *COMP_get_name(const COMP_METHOD *meth); +void COMP_CTX_free(COMP_CTX *ctx); + +int COMP_compress_block(COMP_CTX *ctx, unsigned char *out, int olen, + unsigned char *in, int ilen); +int COMP_expand_block(COMP_CTX *ctx, unsigned char *out, int olen, + unsigned char *in, int ilen); + +COMP_METHOD *COMP_zlib(void); + +#if OPENSSL_API_COMPAT < 0x10100000L +#define COMP_zlib_cleanup() while(0) continue +#endif + +# ifdef HEADER_BIO_H +# ifdef ZLIB +const BIO_METHOD *BIO_f_zlib(void); +# endif +# endif + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_COMP_strings(void); + +/* Error codes for the COMP functions. */ + +/* Function codes. */ +# define COMP_F_BIO_ZLIB_FLUSH 99 +# define COMP_F_BIO_ZLIB_NEW 100 +# define COMP_F_BIO_ZLIB_READ 101 +# define COMP_F_BIO_ZLIB_WRITE 102 + +/* Reason codes. */ +# define COMP_R_ZLIB_DEFLATE_ERROR 99 +# define COMP_R_ZLIB_INFLATE_ERROR 100 +# define COMP_R_ZLIB_NOT_SUPPORTED 101 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/conf.h b/mobile/ios/FxA/FxA/include/openssl/conf.h new file mode 100644 index 0000000000..462e3c9d39 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/conf.h @@ -0,0 +1,216 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_CONF_H +# define HEADER_CONF_H + +# include +# include +# include +# include +# include + +# include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char *section; + char *name; + char *value; +} CONF_VALUE; + +DEFINE_STACK_OF(CONF_VALUE) +DEFINE_LHASH_OF(CONF_VALUE); + +struct conf_st; +struct conf_method_st; +typedef struct conf_method_st CONF_METHOD; + +struct conf_method_st { + const char *name; + CONF *(*create) (CONF_METHOD *meth); + int (*init) (CONF *conf); + int (*destroy) (CONF *conf); + int (*destroy_data) (CONF *conf); + int (*load_bio) (CONF *conf, BIO *bp, long *eline); + int (*dump) (const CONF *conf, BIO *bp); + int (*is_number) (const CONF *conf, char c); + int (*to_int) (const CONF *conf, char c); + int (*load) (CONF *conf, const char *name, long *eline); +}; + +/* Module definitions */ + +typedef struct conf_imodule_st CONF_IMODULE; +typedef struct conf_module_st CONF_MODULE; + +DEFINE_STACK_OF(CONF_MODULE) +DEFINE_STACK_OF(CONF_IMODULE) + +/* DSO module function typedefs */ +typedef int conf_init_func (CONF_IMODULE *md, const CONF *cnf); +typedef void conf_finish_func (CONF_IMODULE *md); + +# define CONF_MFLAGS_IGNORE_ERRORS 0x1 +# define CONF_MFLAGS_IGNORE_RETURN_CODES 0x2 +# define CONF_MFLAGS_SILENT 0x4 +# define CONF_MFLAGS_NO_DSO 0x8 +# define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10 +# define CONF_MFLAGS_DEFAULT_SECTION 0x20 + +int CONF_set_default_method(CONF_METHOD *meth); +void CONF_set_nconf(CONF *conf, LHASH_OF(CONF_VALUE) *hash); +LHASH_OF(CONF_VALUE) *CONF_load(LHASH_OF(CONF_VALUE) *conf, const char *file, + long *eline); +# ifndef OPENSSL_NO_STDIO +LHASH_OF(CONF_VALUE) *CONF_load_fp(LHASH_OF(CONF_VALUE) *conf, FILE *fp, + long *eline); +# endif +LHASH_OF(CONF_VALUE) *CONF_load_bio(LHASH_OF(CONF_VALUE) *conf, BIO *bp, + long *eline); +STACK_OF(CONF_VALUE) *CONF_get_section(LHASH_OF(CONF_VALUE) *conf, + const char *section); +char *CONF_get_string(LHASH_OF(CONF_VALUE) *conf, const char *group, + const char *name); +long CONF_get_number(LHASH_OF(CONF_VALUE) *conf, const char *group, + const char *name); +void CONF_free(LHASH_OF(CONF_VALUE) *conf); +#ifndef OPENSSL_NO_STDIO +int CONF_dump_fp(LHASH_OF(CONF_VALUE) *conf, FILE *out); +#endif +int CONF_dump_bio(LHASH_OF(CONF_VALUE) *conf, BIO *out); + +DEPRECATEDIN_1_1_0(void OPENSSL_config(const char *config_name)) + +#if OPENSSL_API_COMPAT < 0x10100000L +# define OPENSSL_no_config() \ + OPENSSL_init_crypto(OPENSSL_INIT_NO_LOAD_CONFIG, NULL) +#endif + +/* + * New conf code. The semantics are different from the functions above. If + * that wasn't the case, the above functions would have been replaced + */ + +struct conf_st { + CONF_METHOD *meth; + void *meth_data; + LHASH_OF(CONF_VALUE) *data; +}; + +CONF *NCONF_new(CONF_METHOD *meth); +CONF_METHOD *NCONF_default(void); +CONF_METHOD *NCONF_WIN32(void); +void NCONF_free(CONF *conf); +void NCONF_free_data(CONF *conf); + +int NCONF_load(CONF *conf, const char *file, long *eline); +# ifndef OPENSSL_NO_STDIO +int NCONF_load_fp(CONF *conf, FILE *fp, long *eline); +# endif +int NCONF_load_bio(CONF *conf, BIO *bp, long *eline); +STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, + const char *section); +char *NCONF_get_string(const CONF *conf, const char *group, const char *name); +int NCONF_get_number_e(const CONF *conf, const char *group, const char *name, + long *result); +#ifndef OPENSSL_NO_STDIO +int NCONF_dump_fp(const CONF *conf, FILE *out); +#endif +int NCONF_dump_bio(const CONF *conf, BIO *out); + +#define NCONF_get_number(c,g,n,r) NCONF_get_number_e(c,g,n,r) + +/* Module functions */ + +int CONF_modules_load(const CONF *cnf, const char *appname, + unsigned long flags); +int CONF_modules_load_file(const char *filename, const char *appname, + unsigned long flags); +void CONF_modules_unload(int all); +void CONF_modules_finish(void); +#if OPENSSL_API_COMPAT < 0x10100000L +# define CONF_modules_free() while(0) continue +#endif +int CONF_module_add(const char *name, conf_init_func *ifunc, + conf_finish_func *ffunc); + +const char *CONF_imodule_get_name(const CONF_IMODULE *md); +const char *CONF_imodule_get_value(const CONF_IMODULE *md); +void *CONF_imodule_get_usr_data(const CONF_IMODULE *md); +void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data); +CONF_MODULE *CONF_imodule_get_module(const CONF_IMODULE *md); +unsigned long CONF_imodule_get_flags(const CONF_IMODULE *md); +void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags); +void *CONF_module_get_usr_data(CONF_MODULE *pmod); +void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data); + +char *CONF_get1_default_config_file(void); + +int CONF_parse_list(const char *list, int sep, int nospc, + int (*list_cb) (const char *elem, int len, void *usr), + void *arg); + +void OPENSSL_load_builtin_modules(void); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_CONF_strings(void); + +/* Error codes for the CONF functions. */ + +/* Function codes. */ +# define CONF_F_CONF_DUMP_FP 104 +# define CONF_F_CONF_LOAD 100 +# define CONF_F_CONF_LOAD_FP 103 +# define CONF_F_CONF_PARSE_LIST 119 +# define CONF_F_DEF_LOAD 120 +# define CONF_F_DEF_LOAD_BIO 121 +# define CONF_F_MODULE_INIT 115 +# define CONF_F_MODULE_LOAD_DSO 117 +# define CONF_F_MODULE_RUN 118 +# define CONF_F_NCONF_DUMP_BIO 105 +# define CONF_F_NCONF_DUMP_FP 106 +# define CONF_F_NCONF_GET_NUMBER_E 112 +# define CONF_F_NCONF_GET_SECTION 108 +# define CONF_F_NCONF_GET_STRING 109 +# define CONF_F_NCONF_LOAD 113 +# define CONF_F_NCONF_LOAD_BIO 110 +# define CONF_F_NCONF_LOAD_FP 114 +# define CONF_F_NCONF_NEW 111 +# define CONF_F_STR_COPY 101 + +/* Reason codes. */ +# define CONF_R_ERROR_LOADING_DSO 110 +# define CONF_R_LIST_CANNOT_BE_NULL 115 +# define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 100 +# define CONF_R_MISSING_EQUAL_SIGN 101 +# define CONF_R_MISSING_INIT_FUNCTION 112 +# define CONF_R_MODULE_INITIALIZATION_ERROR 109 +# define CONF_R_NO_CLOSE_BRACE 102 +# define CONF_R_NO_CONF 105 +# define CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE 106 +# define CONF_R_NO_SECTION 107 +# define CONF_R_NO_SUCH_FILE 114 +# define CONF_R_NO_VALUE 108 +# define CONF_R_UNABLE_TO_CREATE_NEW_SECTION 103 +# define CONF_R_UNKNOWN_MODULE_NAME 113 +# define CONF_R_VARIABLE_HAS_NO_VALUE 104 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/conf_api.h b/mobile/ios/FxA/FxA/include/openssl/conf_api.h new file mode 100644 index 0000000000..a0275ad79b --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/conf_api.h @@ -0,0 +1,40 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_CONF_API_H +# define HEADER_CONF_API_H + +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Up until OpenSSL 0.9.5a, this was new_section */ +CONF_VALUE *_CONF_new_section(CONF *conf, const char *section); +/* Up until OpenSSL 0.9.5a, this was get_section */ +CONF_VALUE *_CONF_get_section(const CONF *conf, const char *section); +/* Up until OpenSSL 0.9.5a, this was CONF_get_section */ +STACK_OF(CONF_VALUE) *_CONF_get_section_values(const CONF *conf, + const char *section); + +int _CONF_add_string(CONF *conf, CONF_VALUE *section, CONF_VALUE *value); +char *_CONF_get_string(const CONF *conf, const char *section, + const char *name); +long _CONF_get_number(const CONF *conf, const char *section, + const char *name); + +int _CONF_new_data(CONF *conf); +void _CONF_free_data(CONF *conf); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/crypto.h b/mobile/ios/FxA/FxA/include/openssl/crypto.h new file mode 100644 index 0000000000..bd0b140827 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/crypto.h @@ -0,0 +1,463 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_CRYPTO_H +# define HEADER_CRYPTO_H + +# include +# include + +# include + +# ifndef OPENSSL_NO_STDIO +# include +# endif + +# include +# include +# include +# include +# include + +# ifdef CHARSET_EBCDIC +# include +# endif + +/* + * Resolve problems on some operating systems with symbol names that clash + * one way or another + */ +# include + +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# endif + +#ifdef __cplusplus +extern "C" { +#endif + +# if OPENSSL_API_COMPAT < 0x10100000L +# define SSLeay OpenSSL_version_num +# define SSLeay_version OpenSSL_version +# define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER +# define SSLEAY_VERSION OPENSSL_VERSION +# define SSLEAY_CFLAGS OPENSSL_CFLAGS +# define SSLEAY_BUILT_ON OPENSSL_BUILT_ON +# define SSLEAY_PLATFORM OPENSSL_PLATFORM +# define SSLEAY_DIR OPENSSL_DIR + +/* + * Old type for allocating dynamic locks. No longer used. Use the new thread + * API instead. + */ +typedef struct { + int dummy; +} CRYPTO_dynlock; + +# endif /* OPENSSL_API_COMPAT */ + +typedef void CRYPTO_RWLOCK; + +CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void); +int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock); +int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock); +int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock); +void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock); + +int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock); + +/* + * The following can be used to detect memory leaks in the library. If + * used, it turns on malloc checking + */ +# define CRYPTO_MEM_CHECK_OFF 0x0 /* Control only */ +# define CRYPTO_MEM_CHECK_ON 0x1 /* Control and mode bit */ +# define CRYPTO_MEM_CHECK_ENABLE 0x2 /* Control and mode bit */ +# define CRYPTO_MEM_CHECK_DISABLE 0x3 /* Control only */ + +struct crypto_ex_data_st { + STACK_OF(void) *sk; +}; +DEFINE_STACK_OF(void) + +/* + * Per class, we have a STACK of function pointers. + */ +# define CRYPTO_EX_INDEX_SSL 0 +# define CRYPTO_EX_INDEX_SSL_CTX 1 +# define CRYPTO_EX_INDEX_SSL_SESSION 2 +# define CRYPTO_EX_INDEX_X509 3 +# define CRYPTO_EX_INDEX_X509_STORE 4 +# define CRYPTO_EX_INDEX_X509_STORE_CTX 5 +# define CRYPTO_EX_INDEX_DH 6 +# define CRYPTO_EX_INDEX_DSA 7 +# define CRYPTO_EX_INDEX_EC_KEY 8 +# define CRYPTO_EX_INDEX_RSA 9 +# define CRYPTO_EX_INDEX_ENGINE 10 +# define CRYPTO_EX_INDEX_UI 11 +# define CRYPTO_EX_INDEX_BIO 12 +# define CRYPTO_EX_INDEX_APP 13 +# define CRYPTO_EX_INDEX__COUNT 14 + +/* + * This is the default callbacks, but we can have others as well: this is + * needed in Win32 where the application malloc and the library malloc may + * not be the same. + */ +#define OPENSSL_malloc_init() \ + CRYPTO_set_mem_functions(CRYPTO_malloc, CRYPTO_realloc, CRYPTO_free) + +int CRYPTO_mem_ctrl(int mode); + +# define OPENSSL_malloc(num) \ + CRYPTO_malloc(num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_zalloc(num) \ + CRYPTO_zalloc(num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_realloc(addr, num) \ + CRYPTO_realloc(addr, num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_clear_realloc(addr, old_num, num) \ + CRYPTO_clear_realloc(addr, old_num, num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_clear_free(addr, num) \ + CRYPTO_clear_free(addr, num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_free(addr) \ + CRYPTO_free(addr, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_memdup(str, s) \ + CRYPTO_memdup((str), s, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_strdup(str) \ + CRYPTO_strdup(str, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_strndup(str, n) \ + CRYPTO_strndup(str, n, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_secure_malloc(num) \ + CRYPTO_secure_malloc(num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_secure_zalloc(num) \ + CRYPTO_secure_zalloc(num, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_secure_free(addr) \ + CRYPTO_secure_free(addr, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_secure_actual_size(ptr) \ + CRYPTO_secure_actual_size(ptr) + +size_t OPENSSL_strlcpy(char *dst, const char *src, size_t siz); +size_t OPENSSL_strlcat(char *dst, const char *src, size_t siz); +size_t OPENSSL_strnlen(const char *str, size_t maxlen); +char *OPENSSL_buf2hexstr(const unsigned char *buffer, long len); +unsigned char *OPENSSL_hexstr2buf(const char *str, long *len); +int OPENSSL_hexchar2int(unsigned char c); + +# define OPENSSL_MALLOC_MAX_NELEMS(type) (((1U<<(sizeof(int)*8-1))-1)/sizeof(type)) + +unsigned long OpenSSL_version_num(void); +const char *OpenSSL_version(int type); +# define OPENSSL_VERSION 0 +# define OPENSSL_CFLAGS 1 +# define OPENSSL_BUILT_ON 2 +# define OPENSSL_PLATFORM 3 +# define OPENSSL_DIR 4 +# define OPENSSL_ENGINES_DIR 5 + +int OPENSSL_issetugid(void); + +typedef void CRYPTO_EX_new (void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp); +typedef void CRYPTO_EX_free (void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp); +typedef int CRYPTO_EX_dup (CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from, + void *srcp, int idx, long argl, void *argp); +__owur int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, + CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +/* No longer use an index. */ +int CRYPTO_free_ex_index(int class_index, int idx); + +/* + * Initialise/duplicate/free CRYPTO_EX_DATA variables corresponding to a + * given class (invokes whatever per-class callbacks are applicable) + */ +int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad); +int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, + const CRYPTO_EX_DATA *from); + +void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad); + +/* + * Get/set data in a CRYPTO_EX_DATA variable corresponding to a particular + * index (relative to the class type involved) + */ +int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val); +void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx); + +# if OPENSSL_API_COMPAT < 0x10100000L +/* + * This function cleans up all "ex_data" state. It mustn't be called under + * potential race-conditions. + */ +# define CRYPTO_cleanup_all_ex_data() while(0) continue + +/* + * The old locking functions have been removed completely without compatibility + * macros. This is because the old functions either could not properly report + * errors, or the returned error values were not clearly documented. + * Replacing the locking functions with with no-ops would cause race condition + * issues in the affected applications. It is far better for them to fail at + * compile time. + * On the other hand, the locking callbacks are no longer used. Consequently, + * the callback management functions can be safely replaced with no-op macros. + */ +# define CRYPTO_num_locks() (1) +# define CRYPTO_set_locking_callback(func) +# define CRYPTO_get_locking_callback() (NULL) +# define CRYPTO_set_add_lock_callback(func) +# define CRYPTO_get_add_lock_callback() (NULL) + +/* + * These defines where used in combination with the old locking callbacks, + * they are not called anymore, but old code that's not called might still + * use them. + */ +# define CRYPTO_LOCK 1 +# define CRYPTO_UNLOCK 2 +# define CRYPTO_READ 4 +# define CRYPTO_WRITE 8 + +/* This structure is no longer used */ +typedef struct crypto_threadid_st { + int dummy; +} CRYPTO_THREADID; +/* Only use CRYPTO_THREADID_set_[numeric|pointer]() within callbacks */ +# define CRYPTO_THREADID_set_numeric(id, val) +# define CRYPTO_THREADID_set_pointer(id, ptr) +# define CRYPTO_THREADID_set_callback(threadid_func) (0) +# define CRYPTO_THREADID_get_callback() (NULL) +# define CRYPTO_THREADID_current(id) +# define CRYPTO_THREADID_cmp(a, b) (-1) +# define CRYPTO_THREADID_cpy(dest, src) +# define CRYPTO_THREADID_hash(id) (0UL) + +# if OPENSSL_API_COMPAT < 0x10000000L +# define CRYPTO_set_id_callback(func) +# define CRYPTO_get_id_callback() (NULL) +# define CRYPTO_thread_id() (0UL) +# endif /* OPENSSL_API_COMPAT < 0x10000000L */ + +# define CRYPTO_set_dynlock_create_callback(dyn_create_function) +# define CRYPTO_set_dynlock_lock_callback(dyn_lock_function) +# define CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function) +# define CRYPTO_get_dynlock_create_callback() (NULL) +# define CRYPTO_get_dynlock_lock_callback() (NULL) +# define CRYPTO_get_dynlock_destroy_callback() (NULL) +# endif /* OPENSSL_API_COMPAT < 0x10100000L */ + +int CRYPTO_set_mem_functions( + void *(*m) (size_t, const char *, int), + void *(*r) (void *, size_t, const char *, int), + void (*f) (void *, const char *, int)); +int CRYPTO_set_mem_debug(int flag); +void CRYPTO_get_mem_functions( + void *(**m) (size_t, const char *, int), + void *(**r) (void *, size_t, const char *, int), + void (**f) (void *, const char *, int)); + +void *CRYPTO_malloc(size_t num, const char *file, int line); +void *CRYPTO_zalloc(size_t num, const char *file, int line); +void *CRYPTO_memdup(const void *str, size_t siz, const char *file, int line); +char *CRYPTO_strdup(const char *str, const char *file, int line); +char *CRYPTO_strndup(const char *str, size_t s, const char *file, int line); +void CRYPTO_free(void *ptr, const char *file, int line); +void CRYPTO_clear_free(void *ptr, size_t num, const char *file, int line); +void *CRYPTO_realloc(void *addr, size_t num, const char *file, int line); +void *CRYPTO_clear_realloc(void *addr, size_t old_num, size_t num, + const char *file, int line); + +int CRYPTO_secure_malloc_init(size_t sz, int minsize); +int CRYPTO_secure_malloc_done(void); +void *CRYPTO_secure_malloc(size_t num, const char *file, int line); +void *CRYPTO_secure_zalloc(size_t num, const char *file, int line); +void CRYPTO_secure_free(void *ptr, const char *file, int line); +int CRYPTO_secure_allocated(const void *ptr); +int CRYPTO_secure_malloc_initialized(void); +size_t CRYPTO_secure_actual_size(void *ptr); +size_t CRYPTO_secure_used(void); + +void OPENSSL_cleanse(void *ptr, size_t len); + +# ifndef OPENSSL_NO_CRYPTO_MDEBUG +# define OPENSSL_mem_debug_push(info) \ + CRYPTO_mem_debug_push(info, OPENSSL_FILE, OPENSSL_LINE) +# define OPENSSL_mem_debug_pop() \ + CRYPTO_mem_debug_pop() +int CRYPTO_mem_debug_push(const char *info, const char *file, int line); +int CRYPTO_mem_debug_pop(void); + +/*- + * Debugging functions (enabled by CRYPTO_set_mem_debug(1)) + * The flag argument has the following significance: + * 0: called before the actual memory allocation has taken place + * 1: called after the actual memory allocation has taken place + */ +void CRYPTO_mem_debug_malloc(void *addr, size_t num, int flag, + const char *file, int line); +void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num, int flag, + const char *file, int line); +void CRYPTO_mem_debug_free(void *addr, int flag, + const char *file, int line); + +# ifndef OPENSSL_NO_STDIO +int CRYPTO_mem_leaks_fp(FILE *); +# endif +int CRYPTO_mem_leaks(BIO *bio); +# endif + +/* die if we have to */ +ossl_noreturn void OPENSSL_die(const char *assertion, const char *file, int line); +# if OPENSSL_API_COMPAT < 0x10100000L +# define OpenSSLDie(f,l,a) OPENSSL_die((a),(f),(l)) +# endif +# define OPENSSL_assert(e) \ + (void)((e) ? 0 : (OPENSSL_die("assertion failed: " #e, OPENSSL_FILE, OPENSSL_LINE), 1)) + +int OPENSSL_isservice(void); + +int FIPS_mode(void); +int FIPS_mode_set(int r); + +void OPENSSL_init(void); + +struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result); +int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec); +int OPENSSL_gmtime_diff(int *pday, int *psec, + const struct tm *from, const struct tm *to); + +/* + * CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. + * It takes an amount of time dependent on |len|, but independent of the + * contents of |a| and |b|. Unlike memcmp, it cannot be used to put elements + * into a defined order as the return value when a != b is undefined, other + * than to be non-zero. + */ +int CRYPTO_memcmp(const volatile void * volatile in_a, + const volatile void * volatile in_b, + size_t len); + +/* Standard initialisation options */ +# define OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS 0x00000001L +# define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L +# define OPENSSL_INIT_ADD_ALL_CIPHERS 0x00000004L +# define OPENSSL_INIT_ADD_ALL_DIGESTS 0x00000008L +# define OPENSSL_INIT_NO_ADD_ALL_CIPHERS 0x00000010L +# define OPENSSL_INIT_NO_ADD_ALL_DIGESTS 0x00000020L +# define OPENSSL_INIT_LOAD_CONFIG 0x00000040L +# define OPENSSL_INIT_NO_LOAD_CONFIG 0x00000080L +# define OPENSSL_INIT_ASYNC 0x00000100L +# define OPENSSL_INIT_ENGINE_RDRAND 0x00000200L +# define OPENSSL_INIT_ENGINE_DYNAMIC 0x00000400L +# define OPENSSL_INIT_ENGINE_OPENSSL 0x00000800L +# define OPENSSL_INIT_ENGINE_CRYPTODEV 0x00001000L +# define OPENSSL_INIT_ENGINE_CAPI 0x00002000L +# define OPENSSL_INIT_ENGINE_PADLOCK 0x00004000L +# define OPENSSL_INIT_ENGINE_AFALG 0x00008000L +/* OPENSSL_INIT flag 0x00010000 reserved for internal use */ +/* OPENSSL_INIT flag range 0xfff00000 reserved for OPENSSL_init_ssl() */ +/* Max OPENSSL_INIT flag value is 0x80000000 */ + +/* openssl and dasync not counted as builtin */ +# define OPENSSL_INIT_ENGINE_ALL_BUILTIN \ + (OPENSSL_INIT_ENGINE_RDRAND | OPENSSL_INIT_ENGINE_DYNAMIC \ + | OPENSSL_INIT_ENGINE_CRYPTODEV | OPENSSL_INIT_ENGINE_CAPI | \ + OPENSSL_INIT_ENGINE_PADLOCK) + + +/* Library initialisation functions */ +void OPENSSL_cleanup(void); +int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings); +int OPENSSL_atexit(void (*handler)(void)); +void OPENSSL_thread_stop(void); + +/* Low-level control of initialization */ +OPENSSL_INIT_SETTINGS *OPENSSL_INIT_new(void); +# ifndef OPENSSL_NO_STDIO +int OPENSSL_INIT_set_config_appname(OPENSSL_INIT_SETTINGS *settings, + const char *config_file); +# endif +void OPENSSL_INIT_free(OPENSSL_INIT_SETTINGS *settings); + +# if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) +# if defined(_WIN32) +# if defined(BASETYPES) || defined(_WINDEF_H) +/* application has to include in order to use this */ +typedef DWORD CRYPTO_THREAD_LOCAL; +typedef DWORD CRYPTO_THREAD_ID; + +typedef LONG CRYPTO_ONCE; +# define CRYPTO_ONCE_STATIC_INIT 0 +# endif +# else +# include +typedef pthread_once_t CRYPTO_ONCE; +typedef pthread_key_t CRYPTO_THREAD_LOCAL; +typedef pthread_t CRYPTO_THREAD_ID; + +# define CRYPTO_ONCE_STATIC_INIT PTHREAD_ONCE_INIT +# endif +# endif + +# if !defined(CRYPTO_ONCE_STATIC_INIT) +typedef unsigned int CRYPTO_ONCE; +typedef unsigned int CRYPTO_THREAD_LOCAL; +typedef unsigned int CRYPTO_THREAD_ID; +# define CRYPTO_ONCE_STATIC_INIT 0 +# endif + +int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void)); + +int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *)); +void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key); +int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val); +int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key); + +CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void); +int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_CRYPTO_strings(void); + +/* Error codes for the CRYPTO functions. */ + +/* Function codes. */ +# define CRYPTO_F_CRYPTO_DUP_EX_DATA 110 +# define CRYPTO_F_CRYPTO_FREE_EX_DATA 111 +# define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX 100 +# define CRYPTO_F_CRYPTO_MEMDUP 115 +# define CRYPTO_F_CRYPTO_NEW_EX_DATA 112 +# define CRYPTO_F_CRYPTO_SET_EX_DATA 102 +# define CRYPTO_F_FIPS_MODE_SET 109 +# define CRYPTO_F_GET_AND_LOCK 113 +# define CRYPTO_F_OPENSSL_BUF2HEXSTR 117 +# define CRYPTO_F_OPENSSL_HEXSTR2BUF 118 +# define CRYPTO_F_OPENSSL_INIT_CRYPTO 116 + +/* Reason codes. */ +# define CRYPTO_R_FIPS_MODE_NOT_SUPPORTED 101 +# define CRYPTO_R_ILLEGAL_HEX_DIGIT 102 +# define CRYPTO_R_ODD_NUMBER_OF_DIGITS 103 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ct.h b/mobile/ios/FxA/FxA/include/openssl/ct.h new file mode 100644 index 0000000000..bf29fbabe0 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ct.h @@ -0,0 +1,533 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_CT_H +# define HEADER_CT_H + +# include + +# ifndef OPENSSL_NO_CT +# include +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + + +/* Minimum RSA key size, from RFC6962 */ +# define SCT_MIN_RSA_BITS 2048 + +/* All hashes are SHA256 in v1 of Certificate Transparency */ +# define CT_V1_HASHLEN SHA256_DIGEST_LENGTH + +typedef enum { + CT_LOG_ENTRY_TYPE_NOT_SET = -1, + CT_LOG_ENTRY_TYPE_X509 = 0, + CT_LOG_ENTRY_TYPE_PRECERT = 1 +} ct_log_entry_type_t; + +typedef enum { + SCT_VERSION_NOT_SET = -1, + SCT_VERSION_V1 = 0 +} sct_version_t; + +typedef enum { + SCT_SOURCE_UNKNOWN, + SCT_SOURCE_TLS_EXTENSION, + SCT_SOURCE_X509V3_EXTENSION, + SCT_SOURCE_OCSP_STAPLED_RESPONSE +} sct_source_t; + +typedef enum { + SCT_VALIDATION_STATUS_NOT_SET, + SCT_VALIDATION_STATUS_UNKNOWN_LOG, + SCT_VALIDATION_STATUS_VALID, + SCT_VALIDATION_STATUS_INVALID, + SCT_VALIDATION_STATUS_UNVERIFIED, + SCT_VALIDATION_STATUS_UNKNOWN_VERSION +} sct_validation_status_t; + +DEFINE_STACK_OF(SCT) +DEFINE_STACK_OF(CTLOG) + +/****************************************** + * CT policy evaluation context functions * + ******************************************/ + +/* + * Creates a new, empty policy evaluation context. + * The caller is responsible for calling CT_POLICY_EVAL_CTX_free when finished + * with the CT_POLICY_EVAL_CTX. + */ +CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void); + +/* Deletes a policy evaluation context and anything it owns. */ +void CT_POLICY_EVAL_CTX_free(CT_POLICY_EVAL_CTX *ctx); + +/* Gets the peer certificate that the SCTs are for */ +X509* CT_POLICY_EVAL_CTX_get0_cert(const CT_POLICY_EVAL_CTX *ctx); + +/* + * Sets the certificate associated with the received SCTs. + * Increments the reference count of cert. + * Returns 1 on success, 0 otherwise. + */ +int CT_POLICY_EVAL_CTX_set1_cert(CT_POLICY_EVAL_CTX *ctx, X509 *cert); + +/* Gets the issuer of the aforementioned certificate */ +X509* CT_POLICY_EVAL_CTX_get0_issuer(const CT_POLICY_EVAL_CTX *ctx); + +/* + * Sets the issuer of the certificate associated with the received SCTs. + * Increments the reference count of issuer. + * Returns 1 on success, 0 otherwise. + */ +int CT_POLICY_EVAL_CTX_set1_issuer(CT_POLICY_EVAL_CTX *ctx, X509 *issuer); + +/* Gets the CT logs that are trusted sources of SCTs */ +const CTLOG_STORE *CT_POLICY_EVAL_CTX_get0_log_store(const CT_POLICY_EVAL_CTX *ctx); + +/* Sets the log store that is in use. It must outlive the CT_POLICY_EVAL_CTX. */ +void CT_POLICY_EVAL_CTX_set_shared_CTLOG_STORE(CT_POLICY_EVAL_CTX *ctx, + CTLOG_STORE *log_store); + +/* + * Gets the time, in milliseconds since the Unix epoch, that will be used as the + * current time when checking whether an SCT was issued in the future. + * Such SCTs will fail validation, as required by RFC6962. + */ +uint64_t CT_POLICY_EVAL_CTX_get_time(const CT_POLICY_EVAL_CTX *ctx); + +/* + * Sets the time to evaluate SCTs against, in milliseconds since the Unix epoch. + * If an SCT's timestamp is after this time, it will be interpreted as having + * been issued in the future. RFC6962 states that "TLS clients MUST reject SCTs + * whose timestamp is in the future", so an SCT will not validate in this case. + */ +void CT_POLICY_EVAL_CTX_set_time(CT_POLICY_EVAL_CTX *ctx, uint64_t time_in_ms); + +/***************** + * SCT functions * + *****************/ + +/* + * Creates a new, blank SCT. + * The caller is responsible for calling SCT_free when finished with the SCT. + */ +SCT *SCT_new(void); + +/* + * Creates a new SCT from some base64-encoded strings. + * The caller is responsible for calling SCT_free when finished with the SCT. + */ +SCT *SCT_new_from_base64(unsigned char version, + const char *logid_base64, + ct_log_entry_type_t entry_type, + uint64_t timestamp, + const char *extensions_base64, + const char *signature_base64); + +/* + * Frees the SCT and the underlying data structures. + */ +void SCT_free(SCT *sct); + +/* + * Free a stack of SCTs, and the underlying SCTs themselves. + * Intended to be compatible with X509V3_EXT_FREE. + */ +void SCT_LIST_free(STACK_OF(SCT) *a); + +/* + * Returns the version of the SCT. + */ +sct_version_t SCT_get_version(const SCT *sct); + +/* + * Set the version of an SCT. + * Returns 1 on success, 0 if the version is unrecognized. + */ +__owur int SCT_set_version(SCT *sct, sct_version_t version); + +/* + * Returns the log entry type of the SCT. + */ +ct_log_entry_type_t SCT_get_log_entry_type(const SCT *sct); + +/* + * Set the log entry type of an SCT. + * Returns 1 on success, 0 otherwise. + */ +__owur int SCT_set_log_entry_type(SCT *sct, ct_log_entry_type_t entry_type); + +/* + * Gets the ID of the log that an SCT came from. + * Ownership of the log ID remains with the SCT. + * Returns the length of the log ID. + */ +size_t SCT_get0_log_id(const SCT *sct, unsigned char **log_id); + +/* + * Set the log ID of an SCT to point directly to the *log_id specified. + * The SCT takes ownership of the specified pointer. + * Returns 1 on success, 0 otherwise. + */ +__owur int SCT_set0_log_id(SCT *sct, unsigned char *log_id, size_t log_id_len); + +/* + * Set the log ID of an SCT. + * This makes a copy of the log_id. + * Returns 1 on success, 0 otherwise. + */ +__owur int SCT_set1_log_id(SCT *sct, const unsigned char *log_id, + size_t log_id_len); + +/* + * Returns the timestamp for the SCT (epoch time in milliseconds). + */ +uint64_t SCT_get_timestamp(const SCT *sct); + +/* + * Set the timestamp of an SCT (epoch time in milliseconds). + */ +void SCT_set_timestamp(SCT *sct, uint64_t timestamp); + +/* + * Return the NID for the signature used by the SCT. + * For CT v1, this will be either NID_sha256WithRSAEncryption or + * NID_ecdsa_with_SHA256 (or NID_undef if incorrect/unset). + */ +int SCT_get_signature_nid(const SCT *sct); + +/* + * Set the signature type of an SCT + * For CT v1, this should be either NID_sha256WithRSAEncryption or + * NID_ecdsa_with_SHA256. + * Returns 1 on success, 0 otherwise. + */ +__owur int SCT_set_signature_nid(SCT *sct, int nid); + +/* + * Set *ext to point to the extension data for the SCT. ext must not be NULL. + * The SCT retains ownership of this pointer. + * Returns length of the data pointed to. + */ +size_t SCT_get0_extensions(const SCT *sct, unsigned char **ext); + +/* + * Set the extensions of an SCT to point directly to the *ext specified. + * The SCT takes ownership of the specified pointer. + */ +void SCT_set0_extensions(SCT *sct, unsigned char *ext, size_t ext_len); + +/* + * Set the extensions of an SCT. + * This takes a copy of the ext. + * Returns 1 on success, 0 otherwise. + */ +__owur int SCT_set1_extensions(SCT *sct, const unsigned char *ext, + size_t ext_len); + +/* + * Set *sig to point to the signature for the SCT. sig must not be NULL. + * The SCT retains ownership of this pointer. + * Returns length of the data pointed to. + */ +size_t SCT_get0_signature(const SCT *sct, unsigned char **sig); + +/* + * Set the signature of an SCT to point directly to the *sig specified. + * The SCT takes ownership of the specified pointer. + */ +void SCT_set0_signature(SCT *sct, unsigned char *sig, size_t sig_len); + +/* + * Set the signature of an SCT to be a copy of the *sig specified. + * Returns 1 on success, 0 otherwise. + */ +__owur int SCT_set1_signature(SCT *sct, const unsigned char *sig, + size_t sig_len); + +/* + * The origin of this SCT, e.g. TLS extension, OCSP response, etc. + */ +sct_source_t SCT_get_source(const SCT *sct); + +/* + * Set the origin of this SCT, e.g. TLS extension, OCSP response, etc. + * Returns 1 on success, 0 otherwise. + */ +__owur int SCT_set_source(SCT *sct, sct_source_t source); + +/* + * Returns a text string describing the validation status of |sct|. + */ +const char *SCT_validation_status_string(const SCT *sct); + +/* + * Pretty-prints an |sct| to |out|. + * It will be indented by the number of spaces specified by |indent|. + * If |logs| is not NULL, it will be used to lookup the CT log that the SCT came + * from, so that the log name can be printed. + */ +void SCT_print(const SCT *sct, BIO *out, int indent, const CTLOG_STORE *logs); + +/* + * Pretty-prints an |sct_list| to |out|. + * It will be indented by the number of spaces specified by |indent|. + * SCTs will be delimited by |separator|. + * If |logs| is not NULL, it will be used to lookup the CT log that each SCT + * came from, so that the log names can be printed. + */ +void SCT_LIST_print(const STACK_OF(SCT) *sct_list, BIO *out, int indent, + const char *separator, const CTLOG_STORE *logs); + +/* + * Gets the last result of validating this SCT. + * If it has not been validated yet, returns SCT_VALIDATION_STATUS_NOT_SET. + */ +sct_validation_status_t SCT_get_validation_status(const SCT *sct); + +/* + * Validates the given SCT with the provided context. + * Sets the "validation_status" field of the SCT. + * Returns 1 if the SCT is valid and the signature verifies. + * Returns 0 if the SCT is invalid or could not be verified. + * Returns -1 if an error occurs. + */ +__owur int SCT_validate(SCT *sct, const CT_POLICY_EVAL_CTX *ctx); + +/* + * Validates the given list of SCTs with the provided context. + * Sets the "validation_status" field of each SCT. + * Returns 1 if there are no invalid SCTs and all signatures verify. + * Returns 0 if at least one SCT is invalid or could not be verified. + * Returns a negative integer if an error occurs. + */ +__owur int SCT_LIST_validate(const STACK_OF(SCT) *scts, + CT_POLICY_EVAL_CTX *ctx); + + +/********************************* + * SCT parsing and serialisation * + *********************************/ + +/* + * Serialize (to TLS format) a stack of SCTs and return the length. + * "a" must not be NULL. + * If "pp" is NULL, just return the length of what would have been serialized. + * If "pp" is not NULL and "*pp" is null, function will allocate a new pointer + * for data that caller is responsible for freeing (only if function returns + * successfully). + * If "pp" is NULL and "*pp" is not NULL, caller is responsible for ensuring + * that "*pp" is large enough to accept all of the serialized data. + * Returns < 0 on error, >= 0 indicating bytes written (or would have been) + * on success. + */ +__owur int i2o_SCT_LIST(const STACK_OF(SCT) *a, unsigned char **pp); + +/* + * Convert TLS format SCT list to a stack of SCTs. + * If "a" or "*a" is NULL, a new stack will be created that the caller is + * responsible for freeing (by calling SCT_LIST_free). + * "**pp" and "*pp" must not be NULL. + * Upon success, "*pp" will point to after the last bytes read, and a stack + * will be returned. + * Upon failure, a NULL pointer will be returned, and the position of "*pp" is + * not defined. + */ +STACK_OF(SCT) *o2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp, + size_t len); + +/* + * Serialize (to DER format) a stack of SCTs and return the length. + * "a" must not be NULL. + * If "pp" is NULL, just returns the length of what would have been serialized. + * If "pp" is not NULL and "*pp" is null, function will allocate a new pointer + * for data that caller is responsible for freeing (only if function returns + * successfully). + * If "pp" is NULL and "*pp" is not NULL, caller is responsible for ensuring + * that "*pp" is large enough to accept all of the serialized data. + * Returns < 0 on error, >= 0 indicating bytes written (or would have been) + * on success. + */ +__owur int i2d_SCT_LIST(const STACK_OF(SCT) *a, unsigned char **pp); + +/* + * Parses an SCT list in DER format and returns it. + * If "a" or "*a" is NULL, a new stack will be created that the caller is + * responsible for freeing (by calling SCT_LIST_free). + * "**pp" and "*pp" must not be NULL. + * Upon success, "*pp" will point to after the last bytes read, and a stack + * will be returned. + * Upon failure, a NULL pointer will be returned, and the position of "*pp" is + * not defined. + */ +STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp, + long len); + +/* + * Serialize (to TLS format) an |sct| and write it to |out|. + * If |out| is null, no SCT will be output but the length will still be returned. + * If |out| points to a null pointer, a string will be allocated to hold the + * TLS-format SCT. It is the responsibility of the caller to free it. + * If |out| points to an allocated string, the TLS-format SCT will be written + * to it. + * The length of the SCT in TLS format will be returned. + */ +__owur int i2o_SCT(const SCT *sct, unsigned char **out); + +/* + * Parses an SCT in TLS format and returns it. + * If |psct| is not null, it will end up pointing to the parsed SCT. If it + * already points to a non-null pointer, the pointer will be free'd. + * |in| should be a pointer to a string containing the TLS-format SCT. + * |in| will be advanced to the end of the SCT if parsing succeeds. + * |len| should be the length of the SCT in |in|. + * Returns NULL if an error occurs. + * If the SCT is an unsupported version, only the SCT's 'sct' and 'sct_len' + * fields will be populated (with |in| and |len| respectively). + */ +SCT *o2i_SCT(SCT **psct, const unsigned char **in, size_t len); + +/******************** + * CT log functions * + ********************/ + +/* + * Creates a new CT log instance with the given |public_key| and |name|. + * Takes ownership of |public_key| but copies |name|. + * Returns NULL if malloc fails or if |public_key| cannot be converted to DER. + * Should be deleted by the caller using CTLOG_free when no longer needed. + */ +CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name); + +/* + * Creates a new CTLOG instance with the base64-encoded SubjectPublicKeyInfo DER + * in |pkey_base64|. The |name| is a string to help users identify this log. + * Returns 1 on success, 0 on failure. + * Should be deleted by the caller using CTLOG_free when no longer needed. + */ +int CTLOG_new_from_base64(CTLOG ** ct_log, + const char *pkey_base64, const char *name); + +/* + * Deletes a CT log instance and its fields. + */ +void CTLOG_free(CTLOG *log); + +/* Gets the name of the CT log */ +const char *CTLOG_get0_name(const CTLOG *log); +/* Gets the ID of the CT log */ +void CTLOG_get0_log_id(const CTLOG *log, const uint8_t **log_id, + size_t *log_id_len); +/* Gets the public key of the CT log */ +EVP_PKEY *CTLOG_get0_public_key(const CTLOG *log); + +/************************** + * CT log store functions * + **************************/ + +/* + * Creates a new CT log store. + * Should be deleted by the caller using CTLOG_STORE_free when no longer needed. + */ +CTLOG_STORE *CTLOG_STORE_new(void); + +/* + * Deletes a CT log store and all of the CT log instances held within. + */ +void CTLOG_STORE_free(CTLOG_STORE *store); + +/* + * Finds a CT log in the store based on its log ID. + * Returns the CT log, or NULL if no match is found. + */ +const CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store, + const uint8_t *log_id, + size_t log_id_len); + +/* + * Loads a CT log list into a |store| from a |file|. + * Returns 1 if loading is successful, or 0 otherwise. + */ +__owur int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file); + +/* + * Loads the default CT log list into a |store|. + * See internal/cryptlib.h for the environment variable and file path that are + * consulted to find the default file. + * Returns 1 if loading is successful, or 0 otherwise. + */ +__owur int CTLOG_STORE_load_default_file(CTLOG_STORE *store); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_CT_strings(void); + +/* Error codes for the CT functions. */ + +/* Function codes. */ +# define CT_F_CTLOG_NEW 117 +# define CT_F_CTLOG_NEW_FROM_BASE64 118 +# define CT_F_CTLOG_NEW_FROM_CONF 119 +# define CT_F_CTLOG_STORE_LOAD_CTX_NEW 122 +# define CT_F_CTLOG_STORE_LOAD_FILE 123 +# define CT_F_CTLOG_STORE_LOAD_LOG 130 +# define CT_F_CTLOG_STORE_NEW 131 +# define CT_F_CT_BASE64_DECODE 124 +# define CT_F_CT_POLICY_EVAL_CTX_NEW 133 +# define CT_F_CT_V1_LOG_ID_FROM_PKEY 125 +# define CT_F_I2O_SCT 107 +# define CT_F_I2O_SCT_LIST 108 +# define CT_F_I2O_SCT_SIGNATURE 109 +# define CT_F_O2I_SCT 110 +# define CT_F_O2I_SCT_LIST 111 +# define CT_F_O2I_SCT_SIGNATURE 112 +# define CT_F_SCT_CTX_NEW 126 +# define CT_F_SCT_CTX_VERIFY 128 +# define CT_F_SCT_NEW 100 +# define CT_F_SCT_NEW_FROM_BASE64 127 +# define CT_F_SCT_SET0_LOG_ID 101 +# define CT_F_SCT_SET1_EXTENSIONS 114 +# define CT_F_SCT_SET1_LOG_ID 115 +# define CT_F_SCT_SET1_SIGNATURE 116 +# define CT_F_SCT_SET_LOG_ENTRY_TYPE 102 +# define CT_F_SCT_SET_SIGNATURE_NID 103 +# define CT_F_SCT_SET_VERSION 104 + +/* Reason codes. */ +# define CT_R_BASE64_DECODE_ERROR 108 +# define CT_R_INVALID_LOG_ID_LENGTH 100 +# define CT_R_LOG_CONF_INVALID 109 +# define CT_R_LOG_CONF_INVALID_KEY 110 +# define CT_R_LOG_CONF_MISSING_DESCRIPTION 111 +# define CT_R_LOG_CONF_MISSING_KEY 112 +# define CT_R_LOG_KEY_INVALID 113 +# define CT_R_SCT_FUTURE_TIMESTAMP 116 +# define CT_R_SCT_INVALID 104 +# define CT_R_SCT_INVALID_SIGNATURE 107 +# define CT_R_SCT_LIST_INVALID 105 +# define CT_R_SCT_LOG_ID_MISMATCH 114 +# define CT_R_SCT_NOT_SET 106 +# define CT_R_SCT_UNSUPPORTED_VERSION 115 +# define CT_R_UNRECOGNIZED_SIGNATURE_NID 101 +# define CT_R_UNSUPPORTED_ENTRY_TYPE 102 +# define CT_R_UNSUPPORTED_VERSION 103 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/des.h b/mobile/ios/FxA/FxA/include/openssl/des.h new file mode 100644 index 0000000000..be4abbdfd0 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/des.h @@ -0,0 +1,174 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_DES_H +# define HEADER_DES_H + +# include + +# ifndef OPENSSL_NO_DES +# ifdef __cplusplus +extern "C" { +# endif +# include + +typedef unsigned int DES_LONG; + +# ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +# endif + +typedef unsigned char DES_cblock[8]; +typedef /* const */ unsigned char const_DES_cblock[8]; +/* + * With "const", gcc 2.8.1 on Solaris thinks that DES_cblock * and + * const_DES_cblock * are incompatible pointer types. + */ + +typedef struct DES_ks { + union { + DES_cblock cblock; + /* + * make sure things are correct size on machines with 8 byte longs + */ + DES_LONG deslong[2]; + } ks[16]; +} DES_key_schedule; + +# define DES_KEY_SZ (sizeof(DES_cblock)) +# define DES_SCHEDULE_SZ (sizeof(DES_key_schedule)) + +# define DES_ENCRYPT 1 +# define DES_DECRYPT 0 + +# define DES_CBC_MODE 0 +# define DES_PCBC_MODE 1 + +# define DES_ecb2_encrypt(i,o,k1,k2,e) \ + DES_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e)) + +# define DES_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \ + DES_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e)) + +# define DES_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \ + DES_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e)) + +# define DES_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \ + DES_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n)) + +OPENSSL_DECLARE_GLOBAL(int, DES_check_key); /* defaults to false */ +# define DES_check_key OPENSSL_GLOBAL_REF(DES_check_key) + +const char *DES_options(void); +void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output, + DES_key_schedule *ks1, DES_key_schedule *ks2, + DES_key_schedule *ks3, int enc); +DES_LONG DES_cbc_cksum(const unsigned char *input, DES_cblock *output, + long length, DES_key_schedule *schedule, + const_DES_cblock *ivec); +/* DES_cbc_encrypt does not update the IV! Use DES_ncbc_encrypt instead. */ +void DES_cbc_encrypt(const unsigned char *input, unsigned char *output, + long length, DES_key_schedule *schedule, + DES_cblock *ivec, int enc); +void DES_ncbc_encrypt(const unsigned char *input, unsigned char *output, + long length, DES_key_schedule *schedule, + DES_cblock *ivec, int enc); +void DES_xcbc_encrypt(const unsigned char *input, unsigned char *output, + long length, DES_key_schedule *schedule, + DES_cblock *ivec, const_DES_cblock *inw, + const_DES_cblock *outw, int enc); +void DES_cfb_encrypt(const unsigned char *in, unsigned char *out, int numbits, + long length, DES_key_schedule *schedule, + DES_cblock *ivec, int enc); +void DES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output, + DES_key_schedule *ks, int enc); + +/* + * This is the DES encryption function that gets called by just about every + * other DES routine in the library. You should not use this function except + * to implement 'modes' of DES. I say this because the functions that call + * this routine do the conversion from 'char *' to long, and this needs to be + * done to make sure 'non-aligned' memory access do not occur. The + * characters are loaded 'little endian'. Data is a pointer to 2 unsigned + * long's and ks is the DES_key_schedule to use. enc, is non zero specifies + * encryption, zero if decryption. + */ +void DES_encrypt1(DES_LONG *data, DES_key_schedule *ks, int enc); + +/* + * This functions is the same as DES_encrypt1() except that the DES initial + * permutation (IP) and final permutation (FP) have been left out. As for + * DES_encrypt1(), you should not use this function. It is used by the + * routines in the library that implement triple DES. IP() DES_encrypt2() + * DES_encrypt2() DES_encrypt2() FP() is the same as DES_encrypt1() + * DES_encrypt1() DES_encrypt1() except faster :-). + */ +void DES_encrypt2(DES_LONG *data, DES_key_schedule *ks, int enc); + +void DES_encrypt3(DES_LONG *data, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3); +void DES_decrypt3(DES_LONG *data, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3); +void DES_ede3_cbc_encrypt(const unsigned char *input, unsigned char *output, + long length, + DES_key_schedule *ks1, DES_key_schedule *ks2, + DES_key_schedule *ks3, DES_cblock *ivec, int enc); +void DES_ede3_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3, + DES_cblock *ivec, int *num, int enc); +void DES_ede3_cfb_encrypt(const unsigned char *in, unsigned char *out, + int numbits, long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3, + DES_cblock *ivec, int enc); +void DES_ede3_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3, + DES_cblock *ivec, int *num); +char *DES_fcrypt(const char *buf, const char *salt, char *ret); +char *DES_crypt(const char *buf, const char *salt); +void DES_ofb_encrypt(const unsigned char *in, unsigned char *out, int numbits, + long length, DES_key_schedule *schedule, + DES_cblock *ivec); +void DES_pcbc_encrypt(const unsigned char *input, unsigned char *output, + long length, DES_key_schedule *schedule, + DES_cblock *ivec, int enc); +DES_LONG DES_quad_cksum(const unsigned char *input, DES_cblock output[], + long length, int out_count, DES_cblock *seed); +int DES_random_key(DES_cblock *ret); +void DES_set_odd_parity(DES_cblock *key); +int DES_check_key_parity(const_DES_cblock *key); +int DES_is_weak_key(const_DES_cblock *key); +/* + * DES_set_key (= set_key = DES_key_sched = key_sched) calls + * DES_set_key_checked if global variable DES_check_key is set, + * DES_set_key_unchecked otherwise. + */ +int DES_set_key(const_DES_cblock *key, DES_key_schedule *schedule); +int DES_key_sched(const_DES_cblock *key, DES_key_schedule *schedule); +int DES_set_key_checked(const_DES_cblock *key, DES_key_schedule *schedule); +void DES_set_key_unchecked(const_DES_cblock *key, DES_key_schedule *schedule); +void DES_string_to_key(const char *str, DES_cblock *key); +void DES_string_to_2keys(const char *str, DES_cblock *key1, DES_cblock *key2); +void DES_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, DES_key_schedule *schedule, + DES_cblock *ivec, int *num, int enc); +void DES_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, DES_key_schedule *schedule, + DES_cblock *ivec, int *num); + +# define DES_fixup_key_parity DES_set_odd_parity + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/dh.h b/mobile/ios/FxA/FxA/include/openssl/dh.h new file mode 100644 index 0000000000..6d149bc932 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/dh.h @@ -0,0 +1,344 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_DH_H +# define HEADER_DH_H + +# include + +# ifndef OPENSSL_NO_DH +# include +# include +# include +# include +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# endif + +# ifdef __cplusplus +extern "C" { +# endif + +# ifndef OPENSSL_DH_MAX_MODULUS_BITS +# define OPENSSL_DH_MAX_MODULUS_BITS 10000 +# endif + +# define OPENSSL_DH_FIPS_MIN_MODULUS_BITS 1024 + +# define DH_FLAG_CACHE_MONT_P 0x01 + +# if OPENSSL_API_COMPAT < 0x10100000L +/* + * Does nothing. Previously this switched off constant time behaviour. + */ +# define DH_FLAG_NO_EXP_CONSTTIME 0x00 +# endif + +/* + * If this flag is set the DH method is FIPS compliant and can be used in + * FIPS mode. This is set in the validated module method. If an application + * sets this flag in its own methods it is its responsibility to ensure the + * result is compliant. + */ + +# define DH_FLAG_FIPS_METHOD 0x0400 + +/* + * If this flag is set the operations normally disabled in FIPS mode are + * permitted it is then the applications responsibility to ensure that the + * usage is compliant. + */ + +# define DH_FLAG_NON_FIPS_ALLOW 0x0400 + +/* Already defined in ossl_typ.h */ +/* typedef struct dh_st DH; */ +/* typedef struct dh_method DH_METHOD; */ + +DECLARE_ASN1_ITEM(DHparams) + +# define DH_GENERATOR_2 2 +/* #define DH_GENERATOR_3 3 */ +# define DH_GENERATOR_5 5 + +/* DH_check error codes */ +# define DH_CHECK_P_NOT_PRIME 0x01 +# define DH_CHECK_P_NOT_SAFE_PRIME 0x02 +# define DH_UNABLE_TO_CHECK_GENERATOR 0x04 +# define DH_NOT_SUITABLE_GENERATOR 0x08 +# define DH_CHECK_Q_NOT_PRIME 0x10 +# define DH_CHECK_INVALID_Q_VALUE 0x20 +# define DH_CHECK_INVALID_J_VALUE 0x40 + +/* DH_check_pub_key error codes */ +# define DH_CHECK_PUBKEY_TOO_SMALL 0x01 +# define DH_CHECK_PUBKEY_TOO_LARGE 0x02 +# define DH_CHECK_PUBKEY_INVALID 0x04 + +/* + * primes p where (p-1)/2 is prime too are called "safe"; we define this for + * backward compatibility: + */ +# define DH_CHECK_P_NOT_STRONG_PRIME DH_CHECK_P_NOT_SAFE_PRIME + +# define d2i_DHparams_fp(fp,x) (DH *)ASN1_d2i_fp((char *(*)())DH_new, \ + (char *(*)())d2i_DHparams,(fp),(unsigned char **)(x)) +# define i2d_DHparams_fp(fp,x) ASN1_i2d_fp(i2d_DHparams,(fp), \ + (unsigned char *)(x)) +# define d2i_DHparams_bio(bp,x) ASN1_d2i_bio_of(DH,DH_new,d2i_DHparams,bp,x) +# define i2d_DHparams_bio(bp,x) ASN1_i2d_bio_of_const(DH,i2d_DHparams,bp,x) + +DH *DHparams_dup(DH *); + +const DH_METHOD *DH_OpenSSL(void); + +void DH_set_default_method(const DH_METHOD *meth); +const DH_METHOD *DH_get_default_method(void); +int DH_set_method(DH *dh, const DH_METHOD *meth); +DH *DH_new_method(ENGINE *engine); + +DH *DH_new(void); +void DH_free(DH *dh); +int DH_up_ref(DH *dh); +int DH_bits(const DH *dh); +int DH_size(const DH *dh); +int DH_security_bits(const DH *dh); +#define DH_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_DH, l, p, newf, dupf, freef) +int DH_set_ex_data(DH *d, int idx, void *arg); +void *DH_get_ex_data(DH *d, int idx); + +/* Deprecated version */ +DEPRECATEDIN_0_9_8(DH *DH_generate_parameters(int prime_len, int generator, + void (*callback) (int, int, + void *), + void *cb_arg)) + +/* New version */ +int DH_generate_parameters_ex(DH *dh, int prime_len, int generator, + BN_GENCB *cb); + +int DH_check_params(const DH *dh, int *ret); +int DH_check(const DH *dh, int *codes); +int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *codes); +int DH_generate_key(DH *dh); +int DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh); +int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh); +DH *d2i_DHparams(DH **a, const unsigned char **pp, long length); +int i2d_DHparams(const DH *a, unsigned char **pp); +DH *d2i_DHxparams(DH **a, const unsigned char **pp, long length); +int i2d_DHxparams(const DH *a, unsigned char **pp); +# ifndef OPENSSL_NO_STDIO +int DHparams_print_fp(FILE *fp, const DH *x); +# endif +int DHparams_print(BIO *bp, const DH *x); + +/* RFC 5114 parameters */ +DH *DH_get_1024_160(void); +DH *DH_get_2048_224(void); +DH *DH_get_2048_256(void); + +# ifndef OPENSSL_NO_CMS +/* RFC2631 KDF */ +int DH_KDF_X9_42(unsigned char *out, size_t outlen, + const unsigned char *Z, size_t Zlen, + ASN1_OBJECT *key_oid, + const unsigned char *ukm, size_t ukmlen, const EVP_MD *md); +# endif + +void DH_get0_pqg(const DH *dh, + const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); +void DH_get0_key(const DH *dh, + const BIGNUM **pub_key, const BIGNUM **priv_key); +int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key); +void DH_clear_flags(DH *dh, int flags); +int DH_test_flags(const DH *dh, int flags); +void DH_set_flags(DH *dh, int flags); +ENGINE *DH_get0_engine(DH *d); +long DH_get_length(const DH *dh); +int DH_set_length(DH *dh, long length); + +DH_METHOD *DH_meth_new(const char *name, int flags); +void DH_meth_free(DH_METHOD *dhm); +DH_METHOD *DH_meth_dup(const DH_METHOD *dhm); +const char *DH_meth_get0_name(const DH_METHOD *dhm); +int DH_meth_set1_name(DH_METHOD *dhm, const char *name); +int DH_meth_get_flags(DH_METHOD *dhm); +int DH_meth_set_flags(DH_METHOD *dhm, int flags); +void *DH_meth_get0_app_data(const DH_METHOD *dhm); +int DH_meth_set0_app_data(DH_METHOD *dhm, void *app_data); +int (*DH_meth_get_generate_key(const DH_METHOD *dhm)) (DH *); +int DH_meth_set_generate_key(DH_METHOD *dhm, int (*generate_key) (DH *)); +int (*DH_meth_get_compute_key(const DH_METHOD *dhm)) + (unsigned char *key, const BIGNUM *pub_key, DH *dh); +int DH_meth_set_compute_key(DH_METHOD *dhm, + int (*compute_key) (unsigned char *key, const BIGNUM *pub_key, DH *dh)); +int (*DH_meth_get_bn_mod_exp(const DH_METHOD *dhm)) + (const DH *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *, BN_MONT_CTX *); +int DH_meth_set_bn_mod_exp(DH_METHOD *dhm, + int (*bn_mod_exp) (const DH *, BIGNUM *, const BIGNUM *, const BIGNUM *, + const BIGNUM *, BN_CTX *, BN_MONT_CTX *)); +int (*DH_meth_get_init(const DH_METHOD *dhm))(DH *); +int DH_meth_set_init(DH_METHOD *dhm, int (*init)(DH *)); +int (*DH_meth_get_finish(const DH_METHOD *dhm)) (DH *); +int DH_meth_set_finish(DH_METHOD *dhm, int (*finish) (DH *)); +int (*DH_meth_get_generate_params(const DH_METHOD *dhm)) + (DH *, int, int, BN_GENCB *); +int DH_meth_set_generate_params(DH_METHOD *dhm, + int (*generate_params) (DH *, int, int, BN_GENCB *)); + + +# define EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN, len, NULL) + +# define EVP_PKEY_CTX_set_dh_paramgen_subprime_len(ctx, len) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN, len, NULL) + +# define EVP_PKEY_CTX_set_dh_paramgen_type(ctx, typ) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DH_PARAMGEN_TYPE, typ, NULL) + +# define EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, gen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR, gen, NULL) + +# define EVP_PKEY_CTX_set_dh_rfc5114(ctx, gen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DH_RFC5114, gen, NULL) + +# define EVP_PKEY_CTX_set_dhx_rfc5114(ctx, gen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DH_RFC5114, gen, NULL) + +# define EVP_PKEY_CTX_set_dh_kdf_type(ctx, kdf) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_DH_KDF_TYPE, kdf, NULL) + +# define EVP_PKEY_CTX_get_dh_kdf_type(ctx) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_DH_KDF_TYPE, -2, NULL) + +# define EVP_PKEY_CTX_set0_dh_kdf_oid(ctx, oid) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_DH_KDF_OID, 0, (void *)oid) + +# define EVP_PKEY_CTX_get0_dh_kdf_oid(ctx, poid) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_GET_DH_KDF_OID, 0, (void *)poid) + +# define EVP_PKEY_CTX_set_dh_kdf_md(ctx, md) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_DH_KDF_MD, 0, (void *)md) + +# define EVP_PKEY_CTX_get_dh_kdf_md(ctx, pmd) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_GET_DH_KDF_MD, 0, (void *)pmd) + +# define EVP_PKEY_CTX_set_dh_kdf_outlen(ctx, len) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_DH_KDF_OUTLEN, len, NULL) + +# define EVP_PKEY_CTX_get_dh_kdf_outlen(ctx, plen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN, 0, (void *)plen) + +# define EVP_PKEY_CTX_set0_dh_kdf_ukm(ctx, p, plen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_DH_KDF_UKM, plen, (void *)p) + +# define EVP_PKEY_CTX_get0_dh_kdf_ukm(ctx, p) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_GET_DH_KDF_UKM, 0, (void *)p) + +# define EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN (EVP_PKEY_ALG_CTRL + 1) +# define EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR (EVP_PKEY_ALG_CTRL + 2) +# define EVP_PKEY_CTRL_DH_RFC5114 (EVP_PKEY_ALG_CTRL + 3) +# define EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN (EVP_PKEY_ALG_CTRL + 4) +# define EVP_PKEY_CTRL_DH_PARAMGEN_TYPE (EVP_PKEY_ALG_CTRL + 5) +# define EVP_PKEY_CTRL_DH_KDF_TYPE (EVP_PKEY_ALG_CTRL + 6) +# define EVP_PKEY_CTRL_DH_KDF_MD (EVP_PKEY_ALG_CTRL + 7) +# define EVP_PKEY_CTRL_GET_DH_KDF_MD (EVP_PKEY_ALG_CTRL + 8) +# define EVP_PKEY_CTRL_DH_KDF_OUTLEN (EVP_PKEY_ALG_CTRL + 9) +# define EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN (EVP_PKEY_ALG_CTRL + 10) +# define EVP_PKEY_CTRL_DH_KDF_UKM (EVP_PKEY_ALG_CTRL + 11) +# define EVP_PKEY_CTRL_GET_DH_KDF_UKM (EVP_PKEY_ALG_CTRL + 12) +# define EVP_PKEY_CTRL_DH_KDF_OID (EVP_PKEY_ALG_CTRL + 13) +# define EVP_PKEY_CTRL_GET_DH_KDF_OID (EVP_PKEY_ALG_CTRL + 14) + +/* KDF types */ +# define EVP_PKEY_DH_KDF_NONE 1 +# ifndef OPENSSL_NO_CMS +# define EVP_PKEY_DH_KDF_X9_42 2 +# endif + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_DH_strings(void); + +/* Error codes for the DH functions. */ + +/* Function codes. */ +# define DH_F_COMPUTE_KEY 102 +# define DH_F_DHPARAMS_PRINT_FP 101 +# define DH_F_DH_BUILTIN_GENPARAMS 106 +# define DH_F_DH_CMS_DECRYPT 114 +# define DH_F_DH_CMS_SET_PEERKEY 115 +# define DH_F_DH_CMS_SET_SHARED_INFO 116 +# define DH_F_DH_METH_DUP 117 +# define DH_F_DH_METH_NEW 118 +# define DH_F_DH_METH_SET1_NAME 119 +# define DH_F_DH_NEW_METHOD 105 +# define DH_F_DH_PARAM_DECODE 107 +# define DH_F_DH_PRIV_DECODE 110 +# define DH_F_DH_PRIV_ENCODE 111 +# define DH_F_DH_PUB_DECODE 108 +# define DH_F_DH_PUB_ENCODE 109 +# define DH_F_DO_DH_PRINT 100 +# define DH_F_GENERATE_KEY 103 +# define DH_F_PKEY_DH_DERIVE 112 +# define DH_F_PKEY_DH_KEYGEN 113 + +/* Reason codes. */ +# define DH_R_BAD_GENERATOR 101 +# define DH_R_BN_DECODE_ERROR 109 +# define DH_R_BN_ERROR 106 +# define DH_R_DECODE_ERROR 104 +# define DH_R_INVALID_PUBKEY 102 +# define DH_R_KDF_PARAMETER_ERROR 112 +# define DH_R_KEYS_NOT_SET 108 +# define DH_R_MODULUS_TOO_LARGE 103 +# define DH_R_NO_PARAMETERS_SET 107 +# define DH_R_NO_PRIVATE_VALUE 100 +# define DH_R_PARAMETER_ENCODING_ERROR 105 +# define DH_R_PEER_KEY_ERROR 111 +# define DH_R_SHARED_INFO_ERROR 113 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/dsa.h b/mobile/ios/FxA/FxA/include/openssl/dsa.h new file mode 100644 index 0000000000..139718edb9 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/dsa.h @@ -0,0 +1,283 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * The DSS routines are based on patches supplied by + * Steven Schoch . + */ + +#ifndef HEADER_DSA_H +# define HEADER_DSA_H + +# include + +# ifndef OPENSSL_NO_DSA +# ifdef __cplusplus +extern "C" { +# endif +# include +# include +# include +# include +# include +# include +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# endif + +# ifndef OPENSSL_DSA_MAX_MODULUS_BITS +# define OPENSSL_DSA_MAX_MODULUS_BITS 10000 +# endif + +# define OPENSSL_DSA_FIPS_MIN_MODULUS_BITS 1024 + +# define DSA_FLAG_CACHE_MONT_P 0x01 +# if OPENSSL_API_COMPAT < 0x10100000L +/* + * Does nothing. Previously this switched off constant time behaviour. + */ +# define DSA_FLAG_NO_EXP_CONSTTIME 0x00 +# endif + +/* + * If this flag is set the DSA method is FIPS compliant and can be used in + * FIPS mode. This is set in the validated module method. If an application + * sets this flag in its own methods it is its responsibility to ensure the + * result is compliant. + */ + +# define DSA_FLAG_FIPS_METHOD 0x0400 + +/* + * If this flag is set the operations normally disabled in FIPS mode are + * permitted it is then the applications responsibility to ensure that the + * usage is compliant. + */ + +# define DSA_FLAG_NON_FIPS_ALLOW 0x0400 +# define DSA_FLAG_FIPS_CHECKED 0x0800 + +/* Already defined in ossl_typ.h */ +/* typedef struct dsa_st DSA; */ +/* typedef struct dsa_method DSA_METHOD; */ + +typedef struct DSA_SIG_st DSA_SIG; + +# define d2i_DSAparams_fp(fp,x) (DSA *)ASN1_d2i_fp((char *(*)())DSA_new, \ + (char *(*)())d2i_DSAparams,(fp),(unsigned char **)(x)) +# define i2d_DSAparams_fp(fp,x) ASN1_i2d_fp(i2d_DSAparams,(fp), \ + (unsigned char *)(x)) +# define d2i_DSAparams_bio(bp,x) ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSAparams,bp,x) +# define i2d_DSAparams_bio(bp,x) ASN1_i2d_bio_of_const(DSA,i2d_DSAparams,bp,x) + +DSA *DSAparams_dup(DSA *x); +DSA_SIG *DSA_SIG_new(void); +void DSA_SIG_free(DSA_SIG *a); +int i2d_DSA_SIG(const DSA_SIG *a, unsigned char **pp); +DSA_SIG *d2i_DSA_SIG(DSA_SIG **v, const unsigned char **pp, long length); +void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); +int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s); + +DSA_SIG *DSA_do_sign(const unsigned char *dgst, int dlen, DSA *dsa); +int DSA_do_verify(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa); + +const DSA_METHOD *DSA_OpenSSL(void); + +void DSA_set_default_method(const DSA_METHOD *); +const DSA_METHOD *DSA_get_default_method(void); +int DSA_set_method(DSA *dsa, const DSA_METHOD *); +const DSA_METHOD *DSA_get_method(DSA *d); + +DSA *DSA_new(void); +DSA *DSA_new_method(ENGINE *engine); +void DSA_free(DSA *r); +/* "up" the DSA object's reference count */ +int DSA_up_ref(DSA *r); +int DSA_size(const DSA *); +int DSA_bits(const DSA *d); +int DSA_security_bits(const DSA *d); + /* next 4 return -1 on error */ +int DSA_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp); +int DSA_sign(int type, const unsigned char *dgst, int dlen, + unsigned char *sig, unsigned int *siglen, DSA *dsa); +int DSA_verify(int type, const unsigned char *dgst, int dgst_len, + const unsigned char *sigbuf, int siglen, DSA *dsa); +#define DSA_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_DSA, l, p, newf, dupf, freef) +int DSA_set_ex_data(DSA *d, int idx, void *arg); +void *DSA_get_ex_data(DSA *d, int idx); + +DSA *d2i_DSAPublicKey(DSA **a, const unsigned char **pp, long length); +DSA *d2i_DSAPrivateKey(DSA **a, const unsigned char **pp, long length); +DSA *d2i_DSAparams(DSA **a, const unsigned char **pp, long length); + +/* Deprecated version */ +DEPRECATEDIN_0_9_8(DSA *DSA_generate_parameters(int bits, + unsigned char *seed, + int seed_len, + int *counter_ret, + unsigned long *h_ret, void + (*callback) (int, int, + void *), + void *cb_arg)) + +/* New version */ +int DSA_generate_parameters_ex(DSA *dsa, int bits, + const unsigned char *seed, int seed_len, + int *counter_ret, unsigned long *h_ret, + BN_GENCB *cb); + +int DSA_generate_key(DSA *a); +int i2d_DSAPublicKey(const DSA *a, unsigned char **pp); +int i2d_DSAPrivateKey(const DSA *a, unsigned char **pp); +int i2d_DSAparams(const DSA *a, unsigned char **pp); + +int DSAparams_print(BIO *bp, const DSA *x); +int DSA_print(BIO *bp, const DSA *x, int off); +# ifndef OPENSSL_NO_STDIO +int DSAparams_print_fp(FILE *fp, const DSA *x); +int DSA_print_fp(FILE *bp, const DSA *x, int off); +# endif + +# define DSS_prime_checks 50 +/* + * Primality test according to FIPS PUB 186[-1], Appendix 2.1: 50 rounds of + * Rabin-Miller + */ +# define DSA_is_prime(n, callback, cb_arg) \ + BN_is_prime(n, DSS_prime_checks, callback, NULL, cb_arg) + +# ifndef OPENSSL_NO_DH +/* + * Convert DSA structure (key or just parameters) into DH structure (be + * careful to avoid small subgroup attacks when using this!) + */ +DH *DSA_dup_DH(const DSA *r); +# endif + +# define EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, nbits) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, \ + EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, nbits, NULL) + +# define EVP_PKEY_CTRL_DSA_PARAMGEN_BITS (EVP_PKEY_ALG_CTRL + 1) +# define EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS (EVP_PKEY_ALG_CTRL + 2) +# define EVP_PKEY_CTRL_DSA_PARAMGEN_MD (EVP_PKEY_ALG_CTRL + 3) + +void DSA_get0_pqg(const DSA *d, + const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); +int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g); +void DSA_get0_key(const DSA *d, + const BIGNUM **pub_key, const BIGNUM **priv_key); +int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key); +void DSA_clear_flags(DSA *d, int flags); +int DSA_test_flags(const DSA *d, int flags); +void DSA_set_flags(DSA *d, int flags); +ENGINE *DSA_get0_engine(DSA *d); + +DSA_METHOD *DSA_meth_new(const char *name, int flags); +void DSA_meth_free(DSA_METHOD *dsam); +DSA_METHOD *DSA_meth_dup(const DSA_METHOD *dsam); +const char *DSA_meth_get0_name(const DSA_METHOD *dsam); +int DSA_meth_set1_name(DSA_METHOD *dsam, const char *name); +int DSA_meth_get_flags(DSA_METHOD *dsam); +int DSA_meth_set_flags(DSA_METHOD *dsam, int flags); +void *DSA_meth_get0_app_data(const DSA_METHOD *dsam); +int DSA_meth_set0_app_data(DSA_METHOD *dsam, void *app_data); +DSA_SIG *(*DSA_meth_get_sign(const DSA_METHOD *dsam)) + (const unsigned char *, int, DSA *); +int DSA_meth_set_sign(DSA_METHOD *dsam, + DSA_SIG *(*sign) (const unsigned char *, int, DSA *)); +int (*DSA_meth_get_sign_setup(const DSA_METHOD *dsam)) + (DSA *, BN_CTX *, BIGNUM **, BIGNUM **); +int DSA_meth_set_sign_setup(DSA_METHOD *dsam, + int (*sign_setup) (DSA *, BN_CTX *, BIGNUM **, BIGNUM **)); +int (*DSA_meth_get_verify(const DSA_METHOD *dsam)) + (const unsigned char *, int , DSA_SIG *, DSA *); +int DSA_meth_set_verify(DSA_METHOD *dsam, + int (*verify) (const unsigned char *, int, DSA_SIG *, DSA *)); +int (*DSA_meth_get_mod_exp(const DSA_METHOD *dsam)) + (DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, + const BIGNUM *, const BIGNUM *, BN_CTX *, BN_MONT_CTX *); +int DSA_meth_set_mod_exp(DSA_METHOD *dsam, + int (*mod_exp) (DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *, + const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *, + BN_MONT_CTX *)); +int (*DSA_meth_get_bn_mod_exp(const DSA_METHOD *dsam)) + (DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *, BN_MONT_CTX *); +int DSA_meth_set_bn_mod_exp(DSA_METHOD *dsam, + int (*bn_mod_exp) (DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *, + const BIGNUM *, BN_CTX *, BN_MONT_CTX *)); +int (*DSA_meth_get_init(const DSA_METHOD *dsam))(DSA *); +int DSA_meth_set_init(DSA_METHOD *dsam, int (*init)(DSA *)); +int (*DSA_meth_get_finish(const DSA_METHOD *dsam)) (DSA *); +int DSA_meth_set_finish(DSA_METHOD *dsam, int (*finish) (DSA *)); +int (*DSA_meth_get_paramgen(const DSA_METHOD *dsam)) + (DSA *, int, const unsigned char *, int, int *, unsigned long *, + BN_GENCB *); +int DSA_meth_set_paramgen(DSA_METHOD *dsam, + int (*paramgen) (DSA *, int, const unsigned char *, int, int *, + unsigned long *, BN_GENCB *)); +int (*DSA_meth_get_keygen(const DSA_METHOD *dsam)) (DSA *); +int DSA_meth_set_keygen(DSA_METHOD *dsam, int (*keygen) (DSA *)); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_DSA_strings(void); + +/* Error codes for the DSA functions. */ + +/* Function codes. */ +# define DSA_F_DSAPARAMS_PRINT 100 +# define DSA_F_DSAPARAMS_PRINT_FP 101 +# define DSA_F_DSA_BUILTIN_PARAMGEN 125 +# define DSA_F_DSA_BUILTIN_PARAMGEN2 126 +# define DSA_F_DSA_DO_SIGN 112 +# define DSA_F_DSA_DO_VERIFY 113 +# define DSA_F_DSA_METH_DUP 127 +# define DSA_F_DSA_METH_NEW 128 +# define DSA_F_DSA_METH_SET1_NAME 129 +# define DSA_F_DSA_NEW_METHOD 103 +# define DSA_F_DSA_PARAM_DECODE 119 +# define DSA_F_DSA_PRINT_FP 105 +# define DSA_F_DSA_PRIV_DECODE 115 +# define DSA_F_DSA_PRIV_ENCODE 116 +# define DSA_F_DSA_PUB_DECODE 117 +# define DSA_F_DSA_PUB_ENCODE 118 +# define DSA_F_DSA_SIGN 106 +# define DSA_F_DSA_SIGN_SETUP 107 +# define DSA_F_DSA_SIG_NEW 102 +# define DSA_F_OLD_DSA_PRIV_DECODE 122 +# define DSA_F_PKEY_DSA_CTRL 120 +# define DSA_F_PKEY_DSA_KEYGEN 121 + +/* Reason codes. */ +# define DSA_R_BAD_Q_VALUE 102 +# define DSA_R_BN_DECODE_ERROR 108 +# define DSA_R_BN_ERROR 109 +# define DSA_R_DECODE_ERROR 104 +# define DSA_R_INVALID_DIGEST_TYPE 106 +# define DSA_R_INVALID_PARAMETERS 112 +# define DSA_R_MISSING_PARAMETERS 101 +# define DSA_R_MODULUS_TOO_LARGE 103 +# define DSA_R_NO_PARAMETERS_SET 107 +# define DSA_R_PARAMETER_ENCODING_ERROR 105 +# define DSA_R_Q_NOT_PRIME 113 +# define DSA_R_SEED_LEN_SMALL 110 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/dtls1.h b/mobile/ios/FxA/FxA/include/openssl/dtls1.h new file mode 100644 index 0000000000..f4769f83fe --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/dtls1.h @@ -0,0 +1,56 @@ +/* + * Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_DTLS1_H +# define HEADER_DTLS1_H + +#ifdef __cplusplus +extern "C" { +#endif + +# define DTLS1_VERSION 0xFEFF +# define DTLS1_2_VERSION 0xFEFD +# define DTLS_MIN_VERSION DTLS1_VERSION +# define DTLS_MAX_VERSION DTLS1_2_VERSION +# define DTLS1_VERSION_MAJOR 0xFE + +# define DTLS1_BAD_VER 0x0100 + +/* Special value for method supporting multiple versions */ +# define DTLS_ANY_VERSION 0x1FFFF + +/* lengths of messages */ +# define DTLS1_COOKIE_LENGTH 256 + +# define DTLS1_RT_HEADER_LENGTH 13 + +# define DTLS1_HM_HEADER_LENGTH 12 + +# define DTLS1_HM_BAD_FRAGMENT -2 +# define DTLS1_HM_FRAGMENT_RETRY -3 + +# define DTLS1_CCS_HEADER_LENGTH 1 + +# ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE +# define DTLS1_AL_HEADER_LENGTH 7 +# else +# define DTLS1_AL_HEADER_LENGTH 2 +# endif + + +/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */ +# define DTLS1_TMO_READ_COUNT 2 +# define DTLS1_TMO_WRITE_COUNT 2 + +# define DTLS1_TMO_ALERT_COUNT 12 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/e_os2.h b/mobile/ios/FxA/FxA/include/openssl/e_os2.h new file mode 100644 index 0000000000..99ea3477d7 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/e_os2.h @@ -0,0 +1,311 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_E_OS2_H +# define HEADER_E_OS2_H + +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * Detect operating systems. This probably needs completing. + * The result is that at least one OPENSSL_SYS_os macro should be defined. + * However, if none is defined, Unix is assumed. + **/ + +# define OPENSSL_SYS_UNIX + +/* --------------------- Microsoft operating systems ---------------------- */ + +/* + * Note that MSDOS actually denotes 32-bit environments running on top of + * MS-DOS, such as DJGPP one. + */ +# if defined(OPENSSL_SYS_MSDOS) +# undef OPENSSL_SYS_UNIX +# endif + +/* + * For 32 bit environment, there seems to be the CygWin environment and then + * all the others that try to do the same thing Microsoft does... + */ +/* + * UEFI lives here because it might be built with a Microsoft toolchain and + * we need to avoid the false positive match on Windows. + */ +# if defined(OPENSSL_SYS_UEFI) +# undef OPENSSL_SYS_UNIX +# elif defined(OPENSSL_SYS_UWIN) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WIN32_UWIN +# else +# if defined(__CYGWIN__) || defined(OPENSSL_SYS_CYGWIN) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WIN32_CYGWIN +# else +# if defined(_WIN32) || defined(OPENSSL_SYS_WIN32) +# undef OPENSSL_SYS_UNIX +# if !defined(OPENSSL_SYS_WIN32) +# define OPENSSL_SYS_WIN32 +# endif +# endif +# if defined(_WIN64) || defined(OPENSSL_SYS_WIN64) +# undef OPENSSL_SYS_UNIX +# if !defined(OPENSSL_SYS_WIN64) +# define OPENSSL_SYS_WIN64 +# endif +# endif +# if defined(OPENSSL_SYS_WINNT) +# undef OPENSSL_SYS_UNIX +# endif +# if defined(OPENSSL_SYS_WINCE) +# undef OPENSSL_SYS_UNIX +# endif +# endif +# endif + +/* Anything that tries to look like Microsoft is "Windows" */ +# if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN64) || defined(OPENSSL_SYS_WINNT) || defined(OPENSSL_SYS_WINCE) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WINDOWS +# ifndef OPENSSL_SYS_MSDOS +# define OPENSSL_SYS_MSDOS +# endif +# endif + +/* + * DLL settings. This part is a bit tough, because it's up to the + * application implementor how he or she will link the application, so it + * requires some macro to be used. + */ +# ifdef OPENSSL_SYS_WINDOWS +# ifndef OPENSSL_OPT_WINDLL +# if defined(_WINDLL) /* This is used when building OpenSSL to + * indicate that DLL linkage should be used */ +# define OPENSSL_OPT_WINDLL +# endif +# endif +# endif + +/* ------------------------------- OpenVMS -------------------------------- */ +# if defined(__VMS) || defined(VMS) || defined(OPENSSL_SYS_VMS) +# if !defined(OPENSSL_SYS_VMS) +# undef OPENSSL_SYS_UNIX +# endif +# define OPENSSL_SYS_VMS +# if defined(__DECC) +# define OPENSSL_SYS_VMS_DECC +# elif defined(__DECCXX) +# define OPENSSL_SYS_VMS_DECC +# define OPENSSL_SYS_VMS_DECCXX +# else +# define OPENSSL_SYS_VMS_NODECC +# endif +# endif + +/* -------------------------------- Unix ---------------------------------- */ +# ifdef OPENSSL_SYS_UNIX +# if defined(linux) || defined(__linux__) && !defined(OPENSSL_SYS_LINUX) +# define OPENSSL_SYS_LINUX +# endif +# if defined(_AIX) && !defined(OPENSSL_SYS_AIX) +# define OPENSSL_SYS_AIX +# endif +# endif + +/* -------------------------------- VOS ----------------------------------- */ +# if defined(__VOS__) && !defined(OPENSSL_SYS_VOS) +# define OPENSSL_SYS_VOS +# ifdef __HPPA__ +# define OPENSSL_SYS_VOS_HPPA +# endif +# ifdef __IA32__ +# define OPENSSL_SYS_VOS_IA32 +# endif +# endif + +/** + * That's it for OS-specific stuff + *****************************************************************************/ + +/* Specials for I/O an exit */ +# ifdef OPENSSL_SYS_MSDOS +# define OPENSSL_UNISTD_IO +# define OPENSSL_DECLARE_EXIT extern void exit(int); +# else +# define OPENSSL_UNISTD_IO OPENSSL_UNISTD +# define OPENSSL_DECLARE_EXIT /* declared in unistd.h */ +# endif + +/*- + * Definitions of OPENSSL_GLOBAL and OPENSSL_EXTERN, to define and declare + * certain global symbols that, with some compilers under VMS, have to be + * defined and declared explicitly with globaldef and globalref. + * Definitions of OPENSSL_EXPORT and OPENSSL_IMPORT, to define and declare + * DLL exports and imports for compilers under Win32. These are a little + * more complicated to use. Basically, for any library that exports some + * global variables, the following code must be present in the header file + * that declares them, before OPENSSL_EXTERN is used: + * + * #ifdef SOME_BUILD_FLAG_MACRO + * # undef OPENSSL_EXTERN + * # define OPENSSL_EXTERN OPENSSL_EXPORT + * #endif + * + * The default is to have OPENSSL_EXPORT, OPENSSL_EXTERN and OPENSSL_GLOBAL + * have some generally sensible values. + */ + +# if defined(OPENSSL_SYS_VMS_NODECC) +# define OPENSSL_EXPORT globalref +# define OPENSSL_EXTERN globalref +# define OPENSSL_GLOBAL globaldef +# elif defined(OPENSSL_SYS_WINDOWS) && defined(OPENSSL_OPT_WINDLL) +# define OPENSSL_EXPORT extern __declspec(dllexport) +# define OPENSSL_EXTERN extern __declspec(dllimport) +# define OPENSSL_GLOBAL +# else +# define OPENSSL_EXPORT extern +# define OPENSSL_EXTERN extern +# define OPENSSL_GLOBAL +# endif + +/*- + * Macros to allow global variables to be reached through function calls when + * required (if a shared library version requires it, for example. + * The way it's done allows definitions like this: + * + * // in foobar.c + * OPENSSL_IMPLEMENT_GLOBAL(int,foobar,0) + * // in foobar.h + * OPENSSL_DECLARE_GLOBAL(int,foobar); + * #define foobar OPENSSL_GLOBAL_REF(foobar) + */ +# ifdef OPENSSL_EXPORT_VAR_AS_FUNCTION +# define OPENSSL_IMPLEMENT_GLOBAL(type,name,value) \ + type *_shadow_##name(void) \ + { static type _hide_##name=value; return &_hide_##name; } +# define OPENSSL_DECLARE_GLOBAL(type,name) type *_shadow_##name(void) +# define OPENSSL_GLOBAL_REF(name) (*(_shadow_##name())) +# else +# define OPENSSL_IMPLEMENT_GLOBAL(type,name,value) OPENSSL_GLOBAL type _shadow_##name=value; +# define OPENSSL_DECLARE_GLOBAL(type,name) OPENSSL_EXPORT type _shadow_##name +# define OPENSSL_GLOBAL_REF(name) _shadow_##name +# endif + +# ifdef _WIN32 +# ifdef _WIN64 +# define ossl_ssize_t __int64 +# define OSSL_SSIZE_MAX _I64_MAX +# else +# define ossl_ssize_t int +# define OSSL_SSIZE_MAX INT_MAX +# endif +# endif + +# if defined(OPENSSL_SYS_UEFI) && !defined(ssize_t) +# define ossl_ssize_t int +# define OSSL_SSIZE_MAX INT_MAX +# endif + +# ifndef ossl_ssize_t +# define ossl_ssize_t ssize_t +# if defined(SSIZE_MAX) +# define OSSL_SSIZE_MAX SSIZE_MAX +# elif defined(_POSIX_SSIZE_MAX) +# define OSSL_SSIZE_MAX _POSIX_SSIZE_MAX +# endif +# endif + +# ifdef DEBUG_UNUSED +# define __owur __attribute__((__warn_unused_result__)) +# else +# define __owur +# endif + +/* Standard integer types */ +# if defined(OPENSSL_SYS_UEFI) +typedef INT8 int8_t; +typedef UINT8 uint8_t; +typedef INT16 int16_t; +typedef UINT16 uint16_t; +typedef INT32 int32_t; +typedef UINT32 uint32_t; +typedef INT64 int64_t; +typedef UINT64 uint64_t; +# define PRIu64 "%Lu" +# elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + defined(__osf__) || defined(__sgi) || defined(__hpux) || \ + defined(OPENSSL_SYS_VMS) || defined (__OpenBSD__) +# include +# elif defined(_MSC_VER) && _MSC_VER<=1500 +/* + * minimally required typdefs for systems not supporting inttypes.h or + * stdint.h: currently just older VC++ + */ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +# else +# include +# endif + +/* + * We need a format operator for some client tools for uint64_t. If inttypes.h + * isn't available or did not define it, just go with hard-coded. + */ +# ifndef PRIu64 +# ifdef SIXTY_FOUR_BIT_LONG +# define PRIu64 "lu" +# else +# define PRIu64 "llu" +# endif +# endif + +/* ossl_inline: portable inline definition usable in public headers */ +# if !defined(inline) && !defined(__cplusplus) +# if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L + /* just use inline */ +# define ossl_inline inline +# elif defined(__GNUC__) && __GNUC__>=2 +# define ossl_inline __inline__ +# elif defined(_MSC_VER) + /* + * Visual Studio: inline is available in C++ only, however + * __inline is available for C, see + * http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx + */ +# define ossl_inline __inline +# else +# define ossl_inline +# endif +# else +# define ossl_inline inline +# endif + +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# define ossl_noreturn _Noreturn +# elif defined(__GNUC__) && __GNUC__ >= 2 +# define ossl_noreturn __attribute__((noreturn)) +# else +# define ossl_noreturn +# endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ebcdic.h b/mobile/ios/FxA/FxA/include/openssl/ebcdic.h new file mode 100644 index 0000000000..aa01285599 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ebcdic.h @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_EBCDIC_H +# define HEADER_EBCDIC_H + +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Avoid name clashes with other applications */ +# define os_toascii _openssl_os_toascii +# define os_toebcdic _openssl_os_toebcdic +# define ebcdic2ascii _openssl_ebcdic2ascii +# define ascii2ebcdic _openssl_ascii2ebcdic + +extern const unsigned char os_toascii[256]; +extern const unsigned char os_toebcdic[256]; +void *ebcdic2ascii(void *dest, const void *srce, size_t count); +void *ascii2ebcdic(void *dest, const void *srce, size_t count); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ec.h b/mobile/ios/FxA/FxA/include/openssl/ec.h new file mode 100644 index 0000000000..656cb410e6 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ec.h @@ -0,0 +1,1581 @@ +/* + * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#ifndef HEADER_EC_H +# define HEADER_EC_H + +# include + +# ifndef OPENSSL_NO_EC +# include +# include +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# endif +# ifdef __cplusplus +extern "C" { +# endif + +# ifndef OPENSSL_ECC_MAX_FIELD_BITS +# define OPENSSL_ECC_MAX_FIELD_BITS 661 +# endif + +/** Enum for the point conversion form as defined in X9.62 (ECDSA) + * for the encoding of a elliptic curve point (x,y) */ +typedef enum { + /** the point is encoded as z||x, where the octet z specifies + * which solution of the quadratic equation y is */ + POINT_CONVERSION_COMPRESSED = 2, + /** the point is encoded as z||x||y, where z is the octet 0x04 */ + POINT_CONVERSION_UNCOMPRESSED = 4, + /** the point is encoded as z||x||y, where the octet z specifies + * which solution of the quadratic equation y is */ + POINT_CONVERSION_HYBRID = 6 +} point_conversion_form_t; + +typedef struct ec_method_st EC_METHOD; +typedef struct ec_group_st EC_GROUP; +typedef struct ec_point_st EC_POINT; +typedef struct ecpk_parameters_st ECPKPARAMETERS; +typedef struct ec_parameters_st ECPARAMETERS; + +/********************************************************************/ +/* EC_METHODs for curves over GF(p) */ +/********************************************************************/ + +/** Returns the basic GFp ec methods which provides the basis for the + * optimized methods. + * \return EC_METHOD object + */ +const EC_METHOD *EC_GFp_simple_method(void); + +/** Returns GFp methods using montgomery multiplication. + * \return EC_METHOD object + */ +const EC_METHOD *EC_GFp_mont_method(void); + +/** Returns GFp methods using optimized methods for NIST recommended curves + * \return EC_METHOD object + */ +const EC_METHOD *EC_GFp_nist_method(void); + +# ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +/** Returns 64-bit optimized methods for nistp224 + * \return EC_METHOD object + */ +const EC_METHOD *EC_GFp_nistp224_method(void); + +/** Returns 64-bit optimized methods for nistp256 + * \return EC_METHOD object + */ +const EC_METHOD *EC_GFp_nistp256_method(void); + +/** Returns 64-bit optimized methods for nistp521 + * \return EC_METHOD object + */ +const EC_METHOD *EC_GFp_nistp521_method(void); +# endif + +# ifndef OPENSSL_NO_EC2M +/********************************************************************/ +/* EC_METHOD for curves over GF(2^m) */ +/********************************************************************/ + +/** Returns the basic GF2m ec method + * \return EC_METHOD object + */ +const EC_METHOD *EC_GF2m_simple_method(void); + +# endif + +/********************************************************************/ +/* EC_GROUP functions */ +/********************************************************************/ + +/** Creates a new EC_GROUP object + * \param meth EC_METHOD to use + * \return newly created EC_GROUP object or NULL in case of an error. + */ +EC_GROUP *EC_GROUP_new(const EC_METHOD *meth); + +/** Frees a EC_GROUP object + * \param group EC_GROUP object to be freed. + */ +void EC_GROUP_free(EC_GROUP *group); + +/** Clears and frees a EC_GROUP object + * \param group EC_GROUP object to be cleared and freed. + */ +void EC_GROUP_clear_free(EC_GROUP *group); + +/** Copies EC_GROUP objects. Note: both EC_GROUPs must use the same EC_METHOD. + * \param dst destination EC_GROUP object + * \param src source EC_GROUP object + * \return 1 on success and 0 if an error occurred. + */ +int EC_GROUP_copy(EC_GROUP *dst, const EC_GROUP *src); + +/** Creates a new EC_GROUP object and copies the copies the content + * form src to the newly created EC_KEY object + * \param src source EC_GROUP object + * \return newly created EC_GROUP object or NULL in case of an error. + */ +EC_GROUP *EC_GROUP_dup(const EC_GROUP *src); + +/** Returns the EC_METHOD of the EC_GROUP object. + * \param group EC_GROUP object + * \return EC_METHOD used in this EC_GROUP object. + */ +const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group); + +/** Returns the field type of the EC_METHOD. + * \param meth EC_METHOD object + * \return NID of the underlying field type OID. + */ +int EC_METHOD_get_field_type(const EC_METHOD *meth); + +/** Sets the generator and it's order/cofactor of a EC_GROUP object. + * \param group EC_GROUP object + * \param generator EC_POINT object with the generator. + * \param order the order of the group generated by the generator. + * \param cofactor the index of the sub-group generated by the generator + * in the group of all points on the elliptic curve. + * \return 1 on success and 0 if an error occurred + */ +int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, + const BIGNUM *order, const BIGNUM *cofactor); + +/** Returns the generator of a EC_GROUP object. + * \param group EC_GROUP object + * \return the currently used generator (possibly NULL). + */ +const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group); + +/** Returns the montgomery data for order(Generator) + * \param group EC_GROUP object + * \return the currently used montgomery data (possibly NULL). +*/ +BN_MONT_CTX *EC_GROUP_get_mont_data(const EC_GROUP *group); + +/** Gets the order of a EC_GROUP + * \param group EC_GROUP object + * \param order BIGNUM to which the order is copied + * \param ctx unused + * \return 1 on success and 0 if an error occurred + */ +int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx); + +/** Gets the order of an EC_GROUP + * \param group EC_GROUP object + * \return the group order + */ +const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group); + +/** Gets the number of bits of the order of an EC_GROUP + * \param group EC_GROUP object + * \return number of bits of group order. + */ +int EC_GROUP_order_bits(const EC_GROUP *group); + +/** Gets the cofactor of a EC_GROUP + * \param group EC_GROUP object + * \param cofactor BIGNUM to which the cofactor is copied + * \param ctx unused + * \return 1 on success and 0 if an error occurred + */ +int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, + BN_CTX *ctx); + +/** Gets the cofactor of an EC_GROUP + * \param group EC_GROUP object + * \return the group cofactor + */ +const BIGNUM *EC_GROUP_get0_cofactor(const EC_GROUP *group); + +/** Sets the name of a EC_GROUP object + * \param group EC_GROUP object + * \param nid NID of the curve name OID + */ +void EC_GROUP_set_curve_name(EC_GROUP *group, int nid); + +/** Returns the curve name of a EC_GROUP object + * \param group EC_GROUP object + * \return NID of the curve name OID or 0 if not set. + */ +int EC_GROUP_get_curve_name(const EC_GROUP *group); + +void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag); +int EC_GROUP_get_asn1_flag(const EC_GROUP *group); + +void EC_GROUP_set_point_conversion_form(EC_GROUP *group, + point_conversion_form_t form); +point_conversion_form_t EC_GROUP_get_point_conversion_form(const EC_GROUP *); + +unsigned char *EC_GROUP_get0_seed(const EC_GROUP *x); +size_t EC_GROUP_get_seed_len(const EC_GROUP *); +size_t EC_GROUP_set_seed(EC_GROUP *, const unsigned char *, size_t len); + +/** Sets the parameter of a ec over GFp defined by y^2 = x^3 + a*x + b + * \param group EC_GROUP object + * \param p BIGNUM with the prime number + * \param a BIGNUM with parameter a of the equation + * \param b BIGNUM with parameter b of the equation + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); + +/** Gets the parameter of the ec over GFp defined by y^2 = x^3 + a*x + b + * \param group EC_GROUP object + * \param p BIGNUM for the prime number + * \param a BIGNUM for parameter a of the equation + * \param b BIGNUM for parameter b of the equation + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *ctx); + +# ifndef OPENSSL_NO_EC2M +/** Sets the parameter of a ec over GF2m defined by y^2 + x*y = x^3 + a*x^2 + b + * \param group EC_GROUP object + * \param p BIGNUM with the polynomial defining the underlying field + * \param a BIGNUM with parameter a of the equation + * \param b BIGNUM with parameter b of the equation + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_GROUP_set_curve_GF2m(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); + +/** Gets the parameter of the ec over GF2m defined by y^2 + x*y = x^3 + a*x^2 + b + * \param group EC_GROUP object + * \param p BIGNUM for the polynomial defining the underlying field + * \param a BIGNUM for parameter a of the equation + * \param b BIGNUM for parameter b of the equation + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_GROUP_get_curve_GF2m(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *ctx); +# endif +/** Returns the number of bits needed to represent a field element + * \param group EC_GROUP object + * \return number of bits needed to represent a field element + */ +int EC_GROUP_get_degree(const EC_GROUP *group); + +/** Checks whether the parameter in the EC_GROUP define a valid ec group + * \param group EC_GROUP object + * \param ctx BN_CTX object (optional) + * \return 1 if group is a valid ec group and 0 otherwise + */ +int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx); + +/** Checks whether the discriminant of the elliptic curve is zero or not + * \param group EC_GROUP object + * \param ctx BN_CTX object (optional) + * \return 1 if the discriminant is not zero and 0 otherwise + */ +int EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx); + +/** Compares two EC_GROUP objects + * \param a first EC_GROUP object + * \param b second EC_GROUP object + * \param ctx BN_CTX object (optional) + * \return 0 if the groups are equal, 1 if not, or -1 on error + */ +int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx); + +/* + * EC_GROUP_new_GF*() calls EC_GROUP_new() and EC_GROUP_set_GF*() after + * choosing an appropriate EC_METHOD + */ + +/** Creates a new EC_GROUP object with the specified parameters defined + * over GFp (defined by the equation y^2 = x^3 + a*x + b) + * \param p BIGNUM with the prime number + * \param a BIGNUM with the parameter a of the equation + * \param b BIGNUM with the parameter b of the equation + * \param ctx BN_CTX object (optional) + * \return newly created EC_GROUP object with the specified parameters + */ +EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); +# ifndef OPENSSL_NO_EC2M +/** Creates a new EC_GROUP object with the specified parameters defined + * over GF2m (defined by the equation y^2 + x*y = x^3 + a*x^2 + b) + * \param p BIGNUM with the polynomial defining the underlying field + * \param a BIGNUM with the parameter a of the equation + * \param b BIGNUM with the parameter b of the equation + * \param ctx BN_CTX object (optional) + * \return newly created EC_GROUP object with the specified parameters + */ +EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); +# endif + +/** Creates a EC_GROUP object with a curve specified by a NID + * \param nid NID of the OID of the curve name + * \return newly created EC_GROUP object with specified curve or NULL + * if an error occurred + */ +EC_GROUP *EC_GROUP_new_by_curve_name(int nid); + +/** Creates a new EC_GROUP object from an ECPARAMETERS object + * \param params pointer to the ECPARAMETERS object + * \return newly created EC_GROUP object with specified curve or NULL + * if an error occurred + */ +EC_GROUP *EC_GROUP_new_from_ecparameters(const ECPARAMETERS *params); + +/** Creates an ECPARAMETERS object for the the given EC_GROUP object. + * \param group pointer to the EC_GROUP object + * \param params pointer to an existing ECPARAMETERS object or NULL + * \return pointer to the new ECPARAMETERS object or NULL + * if an error occurred. + */ +ECPARAMETERS *EC_GROUP_get_ecparameters(const EC_GROUP *group, + ECPARAMETERS *params); + +/** Creates a new EC_GROUP object from an ECPKPARAMETERS object + * \param params pointer to an existing ECPKPARAMETERS object, or NULL + * \return newly created EC_GROUP object with specified curve, or NULL + * if an error occurred + */ +EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params); + +/** Creates an ECPKPARAMETERS object for the the given EC_GROUP object. + * \param group pointer to the EC_GROUP object + * \param params pointer to an existing ECPKPARAMETERS object or NULL + * \return pointer to the new ECPKPARAMETERS object or NULL + * if an error occurred. + */ +ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group, + ECPKPARAMETERS *params); + +/********************************************************************/ +/* handling of internal curves */ +/********************************************************************/ + +typedef struct { + int nid; + const char *comment; +} EC_builtin_curve; + +/* + * EC_builtin_curves(EC_builtin_curve *r, size_t size) returns number of all + * available curves or zero if a error occurred. In case r is not zero, + * nitems EC_builtin_curve structures are filled with the data of the first + * nitems internal groups + */ +size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems); + +const char *EC_curve_nid2nist(int nid); +int EC_curve_nist2nid(const char *name); + +/********************************************************************/ +/* EC_POINT functions */ +/********************************************************************/ + +/** Creates a new EC_POINT object for the specified EC_GROUP + * \param group EC_GROUP the underlying EC_GROUP object + * \return newly created EC_POINT object or NULL if an error occurred + */ +EC_POINT *EC_POINT_new(const EC_GROUP *group); + +/** Frees a EC_POINT object + * \param point EC_POINT object to be freed + */ +void EC_POINT_free(EC_POINT *point); + +/** Clears and frees a EC_POINT object + * \param point EC_POINT object to be cleared and freed + */ +void EC_POINT_clear_free(EC_POINT *point); + +/** Copies EC_POINT object + * \param dst destination EC_POINT object + * \param src source EC_POINT object + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_copy(EC_POINT *dst, const EC_POINT *src); + +/** Creates a new EC_POINT object and copies the content of the supplied + * EC_POINT + * \param src source EC_POINT object + * \param group underlying the EC_GROUP object + * \return newly created EC_POINT object or NULL if an error occurred + */ +EC_POINT *EC_POINT_dup(const EC_POINT *src, const EC_GROUP *group); + +/** Returns the EC_METHOD used in EC_POINT object + * \param point EC_POINT object + * \return the EC_METHOD used + */ +const EC_METHOD *EC_POINT_method_of(const EC_POINT *point); + +/** Sets a point to infinity (neutral element) + * \param group underlying EC_GROUP object + * \param point EC_POINT to set to infinity + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point); + +/** Sets the jacobian projective coordinates of a EC_POINT over GFp + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param x BIGNUM with the x-coordinate + * \param y BIGNUM with the y-coordinate + * \param z BIGNUM with the z-coordinate + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group, + EC_POINT *p, const BIGNUM *x, + const BIGNUM *y, const BIGNUM *z, + BN_CTX *ctx); + +/** Gets the jacobian projective coordinates of a EC_POINT over GFp + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param x BIGNUM for the x-coordinate + * \param y BIGNUM for the y-coordinate + * \param z BIGNUM for the z-coordinate + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *p, BIGNUM *x, + BIGNUM *y, BIGNUM *z, + BN_CTX *ctx); + +/** Sets the affine coordinates of a EC_POINT over GFp + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param x BIGNUM with the x-coordinate + * \param y BIGNUM with the y-coordinate + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *p, + const BIGNUM *x, const BIGNUM *y, + BN_CTX *ctx); + +/** Gets the affine coordinates of a EC_POINT over GFp + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param x BIGNUM for the x-coordinate + * \param y BIGNUM for the y-coordinate + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *p, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx); + +/** Sets the x9.62 compressed coordinates of a EC_POINT over GFp + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param x BIGNUM with x-coordinate + * \param y_bit integer with the y-Bit (either 0 or 1) + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, + EC_POINT *p, const BIGNUM *x, + int y_bit, BN_CTX *ctx); +# ifndef OPENSSL_NO_EC2M +/** Sets the affine coordinates of a EC_POINT over GF2m + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param x BIGNUM with the x-coordinate + * \param y BIGNUM with the y-coordinate + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p, + const BIGNUM *x, const BIGNUM *y, + BN_CTX *ctx); + +/** Gets the affine coordinates of a EC_POINT over GF2m + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param x BIGNUM for the x-coordinate + * \param y BIGNUM for the y-coordinate + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *group, + const EC_POINT *p, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx); + +/** Sets the x9.62 compressed coordinates of a EC_POINT over GF2m + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param x BIGNUM with x-coordinate + * \param y_bit integer with the y-Bit (either 0 or 1) + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *group, + EC_POINT *p, const BIGNUM *x, + int y_bit, BN_CTX *ctx); +# endif +/** Encodes a EC_POINT object to a octet string + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param form point conversion form + * \param buf memory buffer for the result. If NULL the function returns + * required buffer size. + * \param len length of the memory buffer + * \param ctx BN_CTX object (optional) + * \return the length of the encoded octet string or 0 if an error occurred + */ +size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *p, + point_conversion_form_t form, + unsigned char *buf, size_t len, BN_CTX *ctx); + +/** Decodes a EC_POINT from a octet string + * \param group underlying EC_GROUP object + * \param p EC_POINT object + * \param buf memory buffer with the encoded ec point + * \param len length of the encoded ec point + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *p, + const unsigned char *buf, size_t len, BN_CTX *ctx); + +/** Encodes an EC_POINT object to an allocated octet string + * \param group underlying EC_GROUP object + * \param point EC_POINT object + * \param form point conversion form + * \param pbuf returns pointer to allocated buffer + * \param len length of the memory buffer + * \param ctx BN_CTX object (optional) + * \return the length of the encoded octet string or 0 if an error occurred + */ + +size_t EC_POINT_point2buf(const EC_GROUP *group, const EC_POINT *point, + point_conversion_form_t form, + unsigned char **pbuf, BN_CTX *ctx); + +/* other interfaces to point2oct/oct2point: */ +BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *, + point_conversion_form_t form, BIGNUM *, BN_CTX *); +EC_POINT *EC_POINT_bn2point(const EC_GROUP *, const BIGNUM *, + EC_POINT *, BN_CTX *); +char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *, + point_conversion_form_t form, BN_CTX *); +EC_POINT *EC_POINT_hex2point(const EC_GROUP *, const char *, + EC_POINT *, BN_CTX *); + +/********************************************************************/ +/* functions for doing EC_POINT arithmetic */ +/********************************************************************/ + +/** Computes the sum of two EC_POINT + * \param group underlying EC_GROUP object + * \param r EC_POINT object for the result (r = a + b) + * \param a EC_POINT object with the first summand + * \param b EC_POINT object with the second summand + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx); + +/** Computes the double of a EC_POINT + * \param group underlying EC_GROUP object + * \param r EC_POINT object for the result (r = 2 * a) + * \param a EC_POINT object + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + BN_CTX *ctx); + +/** Computes the inverse of a EC_POINT + * \param group underlying EC_GROUP object + * \param a EC_POINT object to be inverted (it's used for the result as well) + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx); + +/** Checks whether the point is the neutral element of the group + * \param group the underlying EC_GROUP object + * \param p EC_POINT object + * \return 1 if the point is the neutral element and 0 otherwise + */ +int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *p); + +/** Checks whether the point is on the curve + * \param group underlying EC_GROUP object + * \param point EC_POINT object to check + * \param ctx BN_CTX object (optional) + * \return 1 if the point is on the curve, 0 if not, or -1 on error + */ +int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, + BN_CTX *ctx); + +/** Compares two EC_POINTs + * \param group underlying EC_GROUP object + * \param a first EC_POINT object + * \param b second EC_POINT object + * \param ctx BN_CTX object (optional) + * \return 1 if the points are not equal, 0 if they are, or -1 on error + */ +int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, + BN_CTX *ctx); + +int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx); +int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, + EC_POINT *points[], BN_CTX *ctx); + +/** Computes r = generator * n + sum_{i=0}^{num-1} p[i] * m[i] + * \param group underlying EC_GROUP object + * \param r EC_POINT object for the result + * \param n BIGNUM with the multiplier for the group generator (optional) + * \param num number further summands + * \param p array of size num of EC_POINT objects + * \param m array of size num of BIGNUM objects + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, + size_t num, const EC_POINT *p[], const BIGNUM *m[], + BN_CTX *ctx); + +/** Computes r = generator * n + q * m + * \param group underlying EC_GROUP object + * \param r EC_POINT object for the result + * \param n BIGNUM with the multiplier for the group generator (optional) + * \param q EC_POINT object with the first factor of the second summand + * \param m BIGNUM with the second factor of the second summand + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, + const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx); + +/** Stores multiples of generator for faster point multiplication + * \param group EC_GROUP object + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ +int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx); + +/** Reports whether a precomputation has been done + * \param group EC_GROUP object + * \return 1 if a pre-computation has been done and 0 otherwise + */ +int EC_GROUP_have_precompute_mult(const EC_GROUP *group); + +/********************************************************************/ +/* ASN1 stuff */ +/********************************************************************/ + +DECLARE_ASN1_ITEM(ECPKPARAMETERS) +DECLARE_ASN1_ALLOC_FUNCTIONS(ECPKPARAMETERS) +DECLARE_ASN1_ITEM(ECPARAMETERS) +DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS) + +/* + * EC_GROUP_get_basis_type() returns the NID of the basis type used to + * represent the field elements + */ +int EC_GROUP_get_basis_type(const EC_GROUP *); +# ifndef OPENSSL_NO_EC2M +int EC_GROUP_get_trinomial_basis(const EC_GROUP *, unsigned int *k); +int EC_GROUP_get_pentanomial_basis(const EC_GROUP *, unsigned int *k1, + unsigned int *k2, unsigned int *k3); +# endif + +# define OPENSSL_EC_EXPLICIT_CURVE 0x000 +# define OPENSSL_EC_NAMED_CURVE 0x001 + +EC_GROUP *d2i_ECPKParameters(EC_GROUP **, const unsigned char **in, long len); +int i2d_ECPKParameters(const EC_GROUP *, unsigned char **out); + +# define d2i_ECPKParameters_bio(bp,x) ASN1_d2i_bio_of(EC_GROUP,NULL,d2i_ECPKParameters,bp,x) +# define i2d_ECPKParameters_bio(bp,x) ASN1_i2d_bio_of_const(EC_GROUP,i2d_ECPKParameters,bp,x) +# define d2i_ECPKParameters_fp(fp,x) (EC_GROUP *)ASN1_d2i_fp(NULL, \ + (char *(*)())d2i_ECPKParameters,(fp),(unsigned char **)(x)) +# define i2d_ECPKParameters_fp(fp,x) ASN1_i2d_fp(i2d_ECPKParameters,(fp), \ + (unsigned char *)(x)) + +int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off); +# ifndef OPENSSL_NO_STDIO +int ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off); +# endif + +/********************************************************************/ +/* EC_KEY functions */ +/********************************************************************/ + +/* some values for the encoding_flag */ +# define EC_PKEY_NO_PARAMETERS 0x001 +# define EC_PKEY_NO_PUBKEY 0x002 + +/* some values for the flags field */ +# define EC_FLAG_NON_FIPS_ALLOW 0x1 +# define EC_FLAG_FIPS_CHECKED 0x2 +# define EC_FLAG_COFACTOR_ECDH 0x1000 + +/** Creates a new EC_KEY object. + * \return EC_KEY object or NULL if an error occurred. + */ +EC_KEY *EC_KEY_new(void); + +int EC_KEY_get_flags(const EC_KEY *key); + +void EC_KEY_set_flags(EC_KEY *key, int flags); + +void EC_KEY_clear_flags(EC_KEY *key, int flags); + +/** Creates a new EC_KEY object using a named curve as underlying + * EC_GROUP object. + * \param nid NID of the named curve. + * \return EC_KEY object or NULL if an error occurred. + */ +EC_KEY *EC_KEY_new_by_curve_name(int nid); + +/** Frees a EC_KEY object. + * \param key EC_KEY object to be freed. + */ +void EC_KEY_free(EC_KEY *key); + +/** Copies a EC_KEY object. + * \param dst destination EC_KEY object + * \param src src EC_KEY object + * \return dst or NULL if an error occurred. + */ +EC_KEY *EC_KEY_copy(EC_KEY *dst, const EC_KEY *src); + +/** Creates a new EC_KEY object and copies the content from src to it. + * \param src the source EC_KEY object + * \return newly created EC_KEY object or NULL if an error occurred. + */ +EC_KEY *EC_KEY_dup(const EC_KEY *src); + +/** Increases the internal reference count of a EC_KEY object. + * \param key EC_KEY object + * \return 1 on success and 0 if an error occurred. + */ +int EC_KEY_up_ref(EC_KEY *key); + +/** Returns the EC_GROUP object of a EC_KEY object + * \param key EC_KEY object + * \return the EC_GROUP object (possibly NULL). + */ +const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key); + +/** Sets the EC_GROUP of a EC_KEY object. + * \param key EC_KEY object + * \param group EC_GROUP to use in the EC_KEY object (note: the EC_KEY + * object will use an own copy of the EC_GROUP). + * \return 1 on success and 0 if an error occurred. + */ +int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group); + +/** Returns the private key of a EC_KEY object. + * \param key EC_KEY object + * \return a BIGNUM with the private key (possibly NULL). + */ +const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key); + +/** Sets the private key of a EC_KEY object. + * \param key EC_KEY object + * \param prv BIGNUM with the private key (note: the EC_KEY object + * will use an own copy of the BIGNUM). + * \return 1 on success and 0 if an error occurred. + */ +int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv); + +/** Returns the public key of a EC_KEY object. + * \param key the EC_KEY object + * \return a EC_POINT object with the public key (possibly NULL) + */ +const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key); + +/** Sets the public key of a EC_KEY object. + * \param key EC_KEY object + * \param pub EC_POINT object with the public key (note: the EC_KEY object + * will use an own copy of the EC_POINT object). + * \return 1 on success and 0 if an error occurred. + */ +int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub); + +unsigned EC_KEY_get_enc_flags(const EC_KEY *key); +void EC_KEY_set_enc_flags(EC_KEY *eckey, unsigned int flags); +point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key); +void EC_KEY_set_conv_form(EC_KEY *eckey, point_conversion_form_t cform); + +#define EC_KEY_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_EC_KEY, l, p, newf, dupf, freef) +int EC_KEY_set_ex_data(EC_KEY *key, int idx, void *arg); +void *EC_KEY_get_ex_data(const EC_KEY *key, int idx); + +/* wrapper functions for the underlying EC_GROUP object */ +void EC_KEY_set_asn1_flag(EC_KEY *eckey, int asn1_flag); + +/** Creates a table of pre-computed multiples of the generator to + * accelerate further EC_KEY operations. + * \param key EC_KEY object + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred. + */ +int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx); + +/** Creates a new ec private (and optional a new public) key. + * \param key EC_KEY object + * \return 1 on success and 0 if an error occurred. + */ +int EC_KEY_generate_key(EC_KEY *key); + +/** Verifies that a private and/or public key is valid. + * \param key the EC_KEY object + * \return 1 on success and 0 otherwise. + */ +int EC_KEY_check_key(const EC_KEY *key); + +/** Indicates if an EC_KEY can be used for signing. + * \param key the EC_KEY object + * \return 1 if can can sign and 0 otherwise. + */ +int EC_KEY_can_sign(const EC_KEY *eckey); + +/** Sets a public key from affine coordinates performing + * necessary NIST PKV tests. + * \param key the EC_KEY object + * \param x public key x coordinate + * \param y public key y coordinate + * \return 1 on success and 0 otherwise. + */ +int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, + BIGNUM *y); + +/** Encodes an EC_KEY public key to an allocated octet string + * \param key key to encode + * \param form point conversion form + * \param pbuf returns pointer to allocated buffer + * \param len length of the memory buffer + * \param ctx BN_CTX object (optional) + * \return the length of the encoded octet string or 0 if an error occurred + */ + +size_t EC_KEY_key2buf(const EC_KEY *key, point_conversion_form_t form, + unsigned char **pbuf, BN_CTX *ctx); + +/** Decodes a EC_KEY public key from a octet string + * \param key key to decode + * \param buf memory buffer with the encoded ec point + * \param len length of the encoded ec point + * \param ctx BN_CTX object (optional) + * \return 1 on success and 0 if an error occurred + */ + +int EC_KEY_oct2key(EC_KEY *key, const unsigned char *buf, size_t len, + BN_CTX *ctx); + +/** Decodes an EC_KEY private key from an octet string + * \param key key to decode + * \param buf memory buffer with the encoded private key + * \param len length of the encoded key + * \return 1 on success and 0 if an error occurred + */ + +int EC_KEY_oct2priv(EC_KEY *key, const unsigned char *buf, size_t len); + +/** Encodes a EC_KEY private key to an octet string + * \param key key to encode + * \param buf memory buffer for the result. If NULL the function returns + * required buffer size. + * \param len length of the memory buffer + * \return the length of the encoded octet string or 0 if an error occurred + */ + +size_t EC_KEY_priv2oct(const EC_KEY *key, unsigned char *buf, size_t len); + +/** Encodes an EC_KEY private key to an allocated octet string + * \param key key to encode + * \param pbuf returns pointer to allocated buffer + * \return the length of the encoded octet string or 0 if an error occurred + */ + +size_t EC_KEY_priv2buf(const EC_KEY *eckey, unsigned char **pbuf); + +/********************************************************************/ +/* de- and encoding functions for SEC1 ECPrivateKey */ +/********************************************************************/ + +/** Decodes a private key from a memory buffer. + * \param key a pointer to a EC_KEY object which should be used (or NULL) + * \param in pointer to memory with the DER encoded private key + * \param len length of the DER encoded private key + * \return the decoded private key or NULL if an error occurred. + */ +EC_KEY *d2i_ECPrivateKey(EC_KEY **key, const unsigned char **in, long len); + +/** Encodes a private key object and stores the result in a buffer. + * \param key the EC_KEY object to encode + * \param out the buffer for the result (if NULL the function returns number + * of bytes needed). + * \return 1 on success and 0 if an error occurred. + */ +int i2d_ECPrivateKey(EC_KEY *key, unsigned char **out); + +/********************************************************************/ +/* de- and encoding functions for EC parameters */ +/********************************************************************/ + +/** Decodes ec parameter from a memory buffer. + * \param key a pointer to a EC_KEY object which should be used (or NULL) + * \param in pointer to memory with the DER encoded ec parameters + * \param len length of the DER encoded ec parameters + * \return a EC_KEY object with the decoded parameters or NULL if an error + * occurred. + */ +EC_KEY *d2i_ECParameters(EC_KEY **key, const unsigned char **in, long len); + +/** Encodes ec parameter and stores the result in a buffer. + * \param key the EC_KEY object with ec parameters to encode + * \param out the buffer for the result (if NULL the function returns number + * of bytes needed). + * \return 1 on success and 0 if an error occurred. + */ +int i2d_ECParameters(EC_KEY *key, unsigned char **out); + +/********************************************************************/ +/* de- and encoding functions for EC public key */ +/* (octet string, not DER -- hence 'o2i' and 'i2o') */ +/********************************************************************/ + +/** Decodes a ec public key from a octet string. + * \param key a pointer to a EC_KEY object which should be used + * \param in memory buffer with the encoded public key + * \param len length of the encoded public key + * \return EC_KEY object with decoded public key or NULL if an error + * occurred. + */ +EC_KEY *o2i_ECPublicKey(EC_KEY **key, const unsigned char **in, long len); + +/** Encodes a ec public key in an octet string. + * \param key the EC_KEY object with the public key + * \param out the buffer for the result (if NULL the function returns number + * of bytes needed). + * \return 1 on success and 0 if an error occurred + */ +int i2o_ECPublicKey(const EC_KEY *key, unsigned char **out); + +/** Prints out the ec parameters on human readable form. + * \param bp BIO object to which the information is printed + * \param key EC_KEY object + * \return 1 on success and 0 if an error occurred + */ +int ECParameters_print(BIO *bp, const EC_KEY *key); + +/** Prints out the contents of a EC_KEY object + * \param bp BIO object to which the information is printed + * \param key EC_KEY object + * \param off line offset + * \return 1 on success and 0 if an error occurred + */ +int EC_KEY_print(BIO *bp, const EC_KEY *key, int off); + +# ifndef OPENSSL_NO_STDIO +/** Prints out the ec parameters on human readable form. + * \param fp file descriptor to which the information is printed + * \param key EC_KEY object + * \return 1 on success and 0 if an error occurred + */ +int ECParameters_print_fp(FILE *fp, const EC_KEY *key); + +/** Prints out the contents of a EC_KEY object + * \param fp file descriptor to which the information is printed + * \param key EC_KEY object + * \param off line offset + * \return 1 on success and 0 if an error occurred + */ +int EC_KEY_print_fp(FILE *fp, const EC_KEY *key, int off); + +# endif + +const EC_KEY_METHOD *EC_KEY_OpenSSL(void); +const EC_KEY_METHOD *EC_KEY_get_default_method(void); +void EC_KEY_set_default_method(const EC_KEY_METHOD *meth); +const EC_KEY_METHOD *EC_KEY_get_method(const EC_KEY *key); +int EC_KEY_set_method(EC_KEY *key, const EC_KEY_METHOD *meth); +EC_KEY *EC_KEY_new_method(ENGINE *engine); + +int ECDH_KDF_X9_62(unsigned char *out, size_t outlen, + const unsigned char *Z, size_t Zlen, + const unsigned char *sinfo, size_t sinfolen, + const EVP_MD *md); + +int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, + const EC_KEY *ecdh, + void *(*KDF) (const void *in, size_t inlen, + void *out, size_t *outlen)); + +typedef struct ECDSA_SIG_st ECDSA_SIG; + +/** Allocates and initialize a ECDSA_SIG structure + * \return pointer to a ECDSA_SIG structure or NULL if an error occurred + */ +ECDSA_SIG *ECDSA_SIG_new(void); + +/** frees a ECDSA_SIG structure + * \param sig pointer to the ECDSA_SIG structure + */ +void ECDSA_SIG_free(ECDSA_SIG *sig); + +/** DER encode content of ECDSA_SIG object (note: this function modifies *pp + * (*pp += length of the DER encoded signature)). + * \param sig pointer to the ECDSA_SIG object + * \param pp pointer to a unsigned char pointer for the output or NULL + * \return the length of the DER encoded ECDSA_SIG object or 0 + */ +int i2d_ECDSA_SIG(const ECDSA_SIG *sig, unsigned char **pp); + +/** Decodes a DER encoded ECDSA signature (note: this function changes *pp + * (*pp += len)). + * \param sig pointer to ECDSA_SIG pointer (may be NULL) + * \param pp memory buffer with the DER encoded signature + * \param len length of the buffer + * \return pointer to the decoded ECDSA_SIG structure (or NULL) + */ +ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **sig, const unsigned char **pp, long len); + +/** Accessor for r and s fields of ECDSA_SIG + * \param sig pointer to ECDSA_SIG pointer + * \param pr pointer to BIGNUM pointer for r (may be NULL) + * \param ps pointer to BIGNUM pointer for s (may be NULL) + */ +void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); + +/** Setter for r and s fields of ECDSA_SIG + * \param sig pointer to ECDSA_SIG pointer + * \param r pointer to BIGNUM for r (may be NULL) + * \param s pointer to BIGNUM for s (may be NULL) + */ +int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s); + +/** Computes the ECDSA signature of the given hash value using + * the supplied private key and returns the created signature. + * \param dgst pointer to the hash value + * \param dgst_len length of the hash value + * \param eckey EC_KEY object containing a private EC key + * \return pointer to a ECDSA_SIG structure or NULL if an error occurred + */ +ECDSA_SIG *ECDSA_do_sign(const unsigned char *dgst, int dgst_len, + EC_KEY *eckey); + +/** Computes ECDSA signature of a given hash value using the supplied + * private key (note: sig must point to ECDSA_size(eckey) bytes of memory). + * \param dgst pointer to the hash value to sign + * \param dgstlen length of the hash value + * \param kinv BIGNUM with a pre-computed inverse k (optional) + * \param rp BIGNUM with a pre-computed rp value (optional), + * see ECDSA_sign_setup + * \param eckey EC_KEY object containing a private EC key + * \return pointer to a ECDSA_SIG structure or NULL if an error occurred + */ +ECDSA_SIG *ECDSA_do_sign_ex(const unsigned char *dgst, int dgstlen, + const BIGNUM *kinv, const BIGNUM *rp, + EC_KEY *eckey); + +/** Verifies that the supplied signature is a valid ECDSA + * signature of the supplied hash value using the supplied public key. + * \param dgst pointer to the hash value + * \param dgst_len length of the hash value + * \param sig ECDSA_SIG structure + * \param eckey EC_KEY object containing a public EC key + * \return 1 if the signature is valid, 0 if the signature is invalid + * and -1 on error + */ +int ECDSA_do_verify(const unsigned char *dgst, int dgst_len, + const ECDSA_SIG *sig, EC_KEY *eckey); + +/** Precompute parts of the signing operation + * \param eckey EC_KEY object containing a private EC key + * \param ctx BN_CTX object (optional) + * \param kinv BIGNUM pointer for the inverse of k + * \param rp BIGNUM pointer for x coordinate of k * generator + * \return 1 on success and 0 otherwise + */ +int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **rp); + +/** Computes ECDSA signature of a given hash value using the supplied + * private key (note: sig must point to ECDSA_size(eckey) bytes of memory). + * \param type this parameter is ignored + * \param dgst pointer to the hash value to sign + * \param dgstlen length of the hash value + * \param sig memory for the DER encoded created signature + * \param siglen pointer to the length of the returned signature + * \param eckey EC_KEY object containing a private EC key + * \return 1 on success and 0 otherwise + */ +int ECDSA_sign(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, EC_KEY *eckey); + +/** Computes ECDSA signature of a given hash value using the supplied + * private key (note: sig must point to ECDSA_size(eckey) bytes of memory). + * \param type this parameter is ignored + * \param dgst pointer to the hash value to sign + * \param dgstlen length of the hash value + * \param sig buffer to hold the DER encoded signature + * \param siglen pointer to the length of the returned signature + * \param kinv BIGNUM with a pre-computed inverse k (optional) + * \param rp BIGNUM with a pre-computed rp value (optional), + * see ECDSA_sign_setup + * \param eckey EC_KEY object containing a private EC key + * \return 1 on success and 0 otherwise + */ +int ECDSA_sign_ex(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, + const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey); + +/** Verifies that the given signature is valid ECDSA signature + * of the supplied hash value using the specified public key. + * \param type this parameter is ignored + * \param dgst pointer to the hash value + * \param dgstlen length of the hash value + * \param sig pointer to the DER encoded signature + * \param siglen length of the DER encoded signature + * \param eckey EC_KEY object containing a public EC key + * \return 1 if the signature is valid, 0 if the signature is invalid + * and -1 on error + */ +int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, + const unsigned char *sig, int siglen, EC_KEY *eckey); + +/** Returns the maximum length of the DER encoded signature + * \param eckey EC_KEY object + * \return numbers of bytes required for the DER encoded signature + */ +int ECDSA_size(const EC_KEY *eckey); + +/********************************************************************/ +/* EC_KEY_METHOD constructors, destructors, writers and accessors */ +/********************************************************************/ + +EC_KEY_METHOD *EC_KEY_METHOD_new(const EC_KEY_METHOD *meth); +void EC_KEY_METHOD_free(EC_KEY_METHOD *meth); +void EC_KEY_METHOD_set_init(EC_KEY_METHOD *meth, + int (*init)(EC_KEY *key), + void (*finish)(EC_KEY *key), + int (*copy)(EC_KEY *dest, const EC_KEY *src), + int (*set_group)(EC_KEY *key, const EC_GROUP *grp), + int (*set_private)(EC_KEY *key, + const BIGNUM *priv_key), + int (*set_public)(EC_KEY *key, + const EC_POINT *pub_key)); + +void EC_KEY_METHOD_set_keygen(EC_KEY_METHOD *meth, + int (*keygen)(EC_KEY *key)); + +void EC_KEY_METHOD_set_compute_key(EC_KEY_METHOD *meth, + int (*ckey)(unsigned char **psec, + size_t *pseclen, + const EC_POINT *pub_key, + const EC_KEY *ecdh)); + +void EC_KEY_METHOD_set_sign(EC_KEY_METHOD *meth, + int (*sign)(int type, const unsigned char *dgst, + int dlen, unsigned char *sig, + unsigned int *siglen, + const BIGNUM *kinv, const BIGNUM *r, + EC_KEY *eckey), + int (*sign_setup)(EC_KEY *eckey, BN_CTX *ctx_in, + BIGNUM **kinvp, BIGNUM **rp), + ECDSA_SIG *(*sign_sig)(const unsigned char *dgst, + int dgst_len, + const BIGNUM *in_kinv, + const BIGNUM *in_r, + EC_KEY *eckey)); + +void EC_KEY_METHOD_set_verify(EC_KEY_METHOD *meth, + int (*verify)(int type, const unsigned + char *dgst, int dgst_len, + const unsigned char *sigbuf, + int sig_len, EC_KEY *eckey), + int (*verify_sig)(const unsigned char *dgst, + int dgst_len, + const ECDSA_SIG *sig, + EC_KEY *eckey)); + +void EC_KEY_METHOD_get_init(EC_KEY_METHOD *meth, + int (**pinit)(EC_KEY *key), + void (**pfinish)(EC_KEY *key), + int (**pcopy)(EC_KEY *dest, const EC_KEY *src), + int (**pset_group)(EC_KEY *key, + const EC_GROUP *grp), + int (**pset_private)(EC_KEY *key, + const BIGNUM *priv_key), + int (**pset_public)(EC_KEY *key, + const EC_POINT *pub_key)); + +void EC_KEY_METHOD_get_keygen(EC_KEY_METHOD *meth, + int (**pkeygen)(EC_KEY *key)); + +void EC_KEY_METHOD_get_compute_key(EC_KEY_METHOD *meth, + int (**pck)(unsigned char **psec, + size_t *pseclen, + const EC_POINT *pub_key, + const EC_KEY *ecdh)); + +void EC_KEY_METHOD_get_sign(EC_KEY_METHOD *meth, + int (**psign)(int type, const unsigned char *dgst, + int dlen, unsigned char *sig, + unsigned int *siglen, + const BIGNUM *kinv, const BIGNUM *r, + EC_KEY *eckey), + int (**psign_setup)(EC_KEY *eckey, BN_CTX *ctx_in, + BIGNUM **kinvp, BIGNUM **rp), + ECDSA_SIG *(**psign_sig)(const unsigned char *dgst, + int dgst_len, + const BIGNUM *in_kinv, + const BIGNUM *in_r, + EC_KEY *eckey)); + +void EC_KEY_METHOD_get_verify(EC_KEY_METHOD *meth, + int (**pverify)(int type, const unsigned + char *dgst, int dgst_len, + const unsigned char *sigbuf, + int sig_len, EC_KEY *eckey), + int (**pverify_sig)(const unsigned char *dgst, + int dgst_len, + const ECDSA_SIG *sig, + EC_KEY *eckey)); + +# define ECParameters_dup(x) ASN1_dup_of(EC_KEY,i2d_ECParameters,d2i_ECParameters,x) + +# ifndef __cplusplus +# if defined(__SUNPRO_C) +# if __SUNPRO_C >= 0x520 +# pragma error_messages (default,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE) +# endif +# endif +# endif + +# define EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_PARAMGEN|EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, nid, NULL) + +# define EVP_PKEY_CTX_set_ec_param_enc(ctx, flag) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_PARAMGEN|EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_EC_PARAM_ENC, flag, NULL) + +# define EVP_PKEY_CTX_set_ecdh_cofactor_mode(ctx, flag) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_EC_ECDH_COFACTOR, flag, NULL) + +# define EVP_PKEY_CTX_get_ecdh_cofactor_mode(ctx) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_EC_ECDH_COFACTOR, -2, NULL) + +# define EVP_PKEY_CTX_set_ecdh_kdf_type(ctx, kdf) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_EC_KDF_TYPE, kdf, NULL) + +# define EVP_PKEY_CTX_get_ecdh_kdf_type(ctx) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_EC_KDF_TYPE, -2, NULL) + +# define EVP_PKEY_CTX_set_ecdh_kdf_md(ctx, md) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_EC_KDF_MD, 0, (void *)md) + +# define EVP_PKEY_CTX_get_ecdh_kdf_md(ctx, pmd) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_GET_EC_KDF_MD, 0, (void *)pmd) + +# define EVP_PKEY_CTX_set_ecdh_kdf_outlen(ctx, len) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_EC_KDF_OUTLEN, len, NULL) + +# define EVP_PKEY_CTX_get_ecdh_kdf_outlen(ctx, plen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN, 0, (void *)plen) + +# define EVP_PKEY_CTX_set0_ecdh_kdf_ukm(ctx, p, plen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_EC_KDF_UKM, plen, (void *)p) + +# define EVP_PKEY_CTX_get0_ecdh_kdf_ukm(ctx, p) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \ + EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_GET_EC_KDF_UKM, 0, (void *)p) + +# define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID (EVP_PKEY_ALG_CTRL + 1) +# define EVP_PKEY_CTRL_EC_PARAM_ENC (EVP_PKEY_ALG_CTRL + 2) +# define EVP_PKEY_CTRL_EC_ECDH_COFACTOR (EVP_PKEY_ALG_CTRL + 3) +# define EVP_PKEY_CTRL_EC_KDF_TYPE (EVP_PKEY_ALG_CTRL + 4) +# define EVP_PKEY_CTRL_EC_KDF_MD (EVP_PKEY_ALG_CTRL + 5) +# define EVP_PKEY_CTRL_GET_EC_KDF_MD (EVP_PKEY_ALG_CTRL + 6) +# define EVP_PKEY_CTRL_EC_KDF_OUTLEN (EVP_PKEY_ALG_CTRL + 7) +# define EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN (EVP_PKEY_ALG_CTRL + 8) +# define EVP_PKEY_CTRL_EC_KDF_UKM (EVP_PKEY_ALG_CTRL + 9) +# define EVP_PKEY_CTRL_GET_EC_KDF_UKM (EVP_PKEY_ALG_CTRL + 10) +/* KDF types */ +# define EVP_PKEY_ECDH_KDF_NONE 1 +# define EVP_PKEY_ECDH_KDF_X9_62 2 + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_EC_strings(void); + +/* Error codes for the EC functions. */ + +/* Function codes. */ +# define EC_F_BN_TO_FELEM 224 +# define EC_F_D2I_ECPARAMETERS 144 +# define EC_F_D2I_ECPKPARAMETERS 145 +# define EC_F_D2I_ECPRIVATEKEY 146 +# define EC_F_DO_EC_KEY_PRINT 221 +# define EC_F_ECDH_CMS_DECRYPT 238 +# define EC_F_ECDH_CMS_SET_SHARED_INFO 239 +# define EC_F_ECDH_COMPUTE_KEY 246 +# define EC_F_ECDH_SIMPLE_COMPUTE_KEY 257 +# define EC_F_ECDSA_DO_SIGN_EX 251 +# define EC_F_ECDSA_DO_VERIFY 252 +# define EC_F_ECDSA_SIGN_EX 254 +# define EC_F_ECDSA_SIGN_SETUP 248 +# define EC_F_ECDSA_SIG_NEW 265 +# define EC_F_ECDSA_VERIFY 253 +# define EC_F_ECKEY_PARAM2TYPE 223 +# define EC_F_ECKEY_PARAM_DECODE 212 +# define EC_F_ECKEY_PRIV_DECODE 213 +# define EC_F_ECKEY_PRIV_ENCODE 214 +# define EC_F_ECKEY_PUB_DECODE 215 +# define EC_F_ECKEY_PUB_ENCODE 216 +# define EC_F_ECKEY_TYPE2PARAM 220 +# define EC_F_ECPARAMETERS_PRINT 147 +# define EC_F_ECPARAMETERS_PRINT_FP 148 +# define EC_F_ECPKPARAMETERS_PRINT 149 +# define EC_F_ECPKPARAMETERS_PRINT_FP 150 +# define EC_F_ECP_NISTZ256_GET_AFFINE 240 +# define EC_F_ECP_NISTZ256_MULT_PRECOMPUTE 243 +# define EC_F_ECP_NISTZ256_POINTS_MUL 241 +# define EC_F_ECP_NISTZ256_PRE_COMP_NEW 244 +# define EC_F_ECP_NISTZ256_WINDOWED_MUL 242 +# define EC_F_ECX_KEY_OP 266 +# define EC_F_ECX_PRIV_ENCODE 267 +# define EC_F_ECX_PUB_ENCODE 268 +# define EC_F_EC_ASN1_GROUP2CURVE 153 +# define EC_F_EC_ASN1_GROUP2FIELDID 154 +# define EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY 208 +# define EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT 159 +# define EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE 195 +# define EC_F_EC_GF2M_SIMPLE_OCT2POINT 160 +# define EC_F_EC_GF2M_SIMPLE_POINT2OCT 161 +# define EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES 162 +# define EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES 163 +# define EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES 164 +# define EC_F_EC_GFP_MONT_FIELD_DECODE 133 +# define EC_F_EC_GFP_MONT_FIELD_ENCODE 134 +# define EC_F_EC_GFP_MONT_FIELD_MUL 131 +# define EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE 209 +# define EC_F_EC_GFP_MONT_FIELD_SQR 132 +# define EC_F_EC_GFP_MONT_GROUP_SET_CURVE 189 +# define EC_F_EC_GFP_NISTP224_GROUP_SET_CURVE 225 +# define EC_F_EC_GFP_NISTP224_POINTS_MUL 228 +# define EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES 226 +# define EC_F_EC_GFP_NISTP256_GROUP_SET_CURVE 230 +# define EC_F_EC_GFP_NISTP256_POINTS_MUL 231 +# define EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES 232 +# define EC_F_EC_GFP_NISTP521_GROUP_SET_CURVE 233 +# define EC_F_EC_GFP_NISTP521_POINTS_MUL 234 +# define EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES 235 +# define EC_F_EC_GFP_NIST_FIELD_MUL 200 +# define EC_F_EC_GFP_NIST_FIELD_SQR 201 +# define EC_F_EC_GFP_NIST_GROUP_SET_CURVE 202 +# define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT 165 +# define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE 166 +# define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE 102 +# define EC_F_EC_GFP_SIMPLE_OCT2POINT 103 +# define EC_F_EC_GFP_SIMPLE_POINT2OCT 104 +# define EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE 137 +# define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES 167 +# define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES 168 +# define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES 169 +# define EC_F_EC_GROUP_CHECK 170 +# define EC_F_EC_GROUP_CHECK_DISCRIMINANT 171 +# define EC_F_EC_GROUP_COPY 106 +# define EC_F_EC_GROUP_GET_CURVE_GF2M 172 +# define EC_F_EC_GROUP_GET_CURVE_GFP 130 +# define EC_F_EC_GROUP_GET_DEGREE 173 +# define EC_F_EC_GROUP_GET_ECPARAMETERS 261 +# define EC_F_EC_GROUP_GET_ECPKPARAMETERS 262 +# define EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS 193 +# define EC_F_EC_GROUP_GET_TRINOMIAL_BASIS 194 +# define EC_F_EC_GROUP_NEW 108 +# define EC_F_EC_GROUP_NEW_BY_CURVE_NAME 174 +# define EC_F_EC_GROUP_NEW_FROM_DATA 175 +# define EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS 263 +# define EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS 264 +# define EC_F_EC_GROUP_SET_CURVE_GF2M 176 +# define EC_F_EC_GROUP_SET_CURVE_GFP 109 +# define EC_F_EC_GROUP_SET_GENERATOR 111 +# define EC_F_EC_KEY_CHECK_KEY 177 +# define EC_F_EC_KEY_COPY 178 +# define EC_F_EC_KEY_GENERATE_KEY 179 +# define EC_F_EC_KEY_NEW 182 +# define EC_F_EC_KEY_NEW_METHOD 245 +# define EC_F_EC_KEY_OCT2PRIV 255 +# define EC_F_EC_KEY_PRINT 180 +# define EC_F_EC_KEY_PRINT_FP 181 +# define EC_F_EC_KEY_PRIV2OCT 256 +# define EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES 229 +# define EC_F_EC_KEY_SIMPLE_CHECK_KEY 258 +# define EC_F_EC_KEY_SIMPLE_OCT2PRIV 259 +# define EC_F_EC_KEY_SIMPLE_PRIV2OCT 260 +# define EC_F_EC_POINTS_MAKE_AFFINE 136 +# define EC_F_EC_POINT_ADD 112 +# define EC_F_EC_POINT_CMP 113 +# define EC_F_EC_POINT_COPY 114 +# define EC_F_EC_POINT_DBL 115 +# define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M 183 +# define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP 116 +# define EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP 117 +# define EC_F_EC_POINT_INVERT 210 +# define EC_F_EC_POINT_IS_AT_INFINITY 118 +# define EC_F_EC_POINT_IS_ON_CURVE 119 +# define EC_F_EC_POINT_MAKE_AFFINE 120 +# define EC_F_EC_POINT_NEW 121 +# define EC_F_EC_POINT_OCT2POINT 122 +# define EC_F_EC_POINT_POINT2OCT 123 +# define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M 185 +# define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP 124 +# define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M 186 +# define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP 125 +# define EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP 126 +# define EC_F_EC_POINT_SET_TO_INFINITY 127 +# define EC_F_EC_PRE_COMP_NEW 196 +# define EC_F_EC_WNAF_MUL 187 +# define EC_F_EC_WNAF_PRECOMPUTE_MULT 188 +# define EC_F_I2D_ECPARAMETERS 190 +# define EC_F_I2D_ECPKPARAMETERS 191 +# define EC_F_I2D_ECPRIVATEKEY 192 +# define EC_F_I2O_ECPUBLICKEY 151 +# define EC_F_NISTP224_PRE_COMP_NEW 227 +# define EC_F_NISTP256_PRE_COMP_NEW 236 +# define EC_F_NISTP521_PRE_COMP_NEW 237 +# define EC_F_O2I_ECPUBLICKEY 152 +# define EC_F_OLD_EC_PRIV_DECODE 222 +# define EC_F_OSSL_ECDH_COMPUTE_KEY 247 +# define EC_F_OSSL_ECDSA_SIGN_SIG 249 +# define EC_F_OSSL_ECDSA_VERIFY_SIG 250 +# define EC_F_PKEY_ECX_DERIVE 269 +# define EC_F_PKEY_EC_CTRL 197 +# define EC_F_PKEY_EC_CTRL_STR 198 +# define EC_F_PKEY_EC_DERIVE 217 +# define EC_F_PKEY_EC_KEYGEN 199 +# define EC_F_PKEY_EC_PARAMGEN 219 +# define EC_F_PKEY_EC_SIGN 218 + +/* Reason codes. */ +# define EC_R_ASN1_ERROR 115 +# define EC_R_BAD_SIGNATURE 156 +# define EC_R_BIGNUM_OUT_OF_RANGE 144 +# define EC_R_BUFFER_TOO_SMALL 100 +# define EC_R_COORDINATES_OUT_OF_RANGE 146 +# define EC_R_CURVE_DOES_NOT_SUPPORT_ECDH 160 +# define EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING 159 +# define EC_R_D2I_ECPKPARAMETERS_FAILURE 117 +# define EC_R_DECODE_ERROR 142 +# define EC_R_DISCRIMINANT_IS_ZERO 118 +# define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 119 +# define EC_R_FIELD_TOO_LARGE 143 +# define EC_R_GF2M_NOT_SUPPORTED 147 +# define EC_R_GROUP2PKPARAMETERS_FAILURE 120 +# define EC_R_I2D_ECPKPARAMETERS_FAILURE 121 +# define EC_R_INCOMPATIBLE_OBJECTS 101 +# define EC_R_INVALID_ARGUMENT 112 +# define EC_R_INVALID_COMPRESSED_POINT 110 +# define EC_R_INVALID_COMPRESSION_BIT 109 +# define EC_R_INVALID_CURVE 141 +# define EC_R_INVALID_DIGEST 151 +# define EC_R_INVALID_DIGEST_TYPE 138 +# define EC_R_INVALID_ENCODING 102 +# define EC_R_INVALID_FIELD 103 +# define EC_R_INVALID_FORM 104 +# define EC_R_INVALID_GROUP_ORDER 122 +# define EC_R_INVALID_KEY 116 +# define EC_R_INVALID_OUTPUT_LENGTH 161 +# define EC_R_INVALID_PEER_KEY 133 +# define EC_R_INVALID_PENTANOMIAL_BASIS 132 +# define EC_R_INVALID_PRIVATE_KEY 123 +# define EC_R_INVALID_TRINOMIAL_BASIS 137 +# define EC_R_KDF_PARAMETER_ERROR 148 +# define EC_R_KEYS_NOT_SET 140 +# define EC_R_MISSING_PARAMETERS 124 +# define EC_R_MISSING_PRIVATE_KEY 125 +# define EC_R_NEED_NEW_SETUP_VALUES 157 +# define EC_R_NOT_A_NIST_PRIME 135 +# define EC_R_NOT_IMPLEMENTED 126 +# define EC_R_NOT_INITIALIZED 111 +# define EC_R_NO_PARAMETERS_SET 139 +# define EC_R_NO_PRIVATE_VALUE 154 +# define EC_R_OPERATION_NOT_SUPPORTED 152 +# define EC_R_PASSED_NULL_PARAMETER 134 +# define EC_R_PEER_KEY_ERROR 149 +# define EC_R_PKPARAMETERS2GROUP_FAILURE 127 +# define EC_R_POINT_ARITHMETIC_FAILURE 155 +# define EC_R_POINT_AT_INFINITY 106 +# define EC_R_POINT_IS_NOT_ON_CURVE 107 +# define EC_R_RANDOM_NUMBER_GENERATION_FAILED 158 +# define EC_R_SHARED_INFO_ERROR 150 +# define EC_R_SLOT_FULL 108 +# define EC_R_UNDEFINED_GENERATOR 113 +# define EC_R_UNDEFINED_ORDER 128 +# define EC_R_UNKNOWN_GROUP 129 +# define EC_R_UNKNOWN_ORDER 114 +# define EC_R_UNSUPPORTED_FIELD 131 +# define EC_R_WRONG_CURVE_PARAMETERS 145 +# define EC_R_WRONG_ORDER 130 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ecdh.h b/mobile/ios/FxA/FxA/include/openssl/ecdh.h new file mode 100644 index 0000000000..681f3d5e55 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ecdh.h @@ -0,0 +1,10 @@ +/* + * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include diff --git a/mobile/ios/FxA/FxA/include/openssl/ecdsa.h b/mobile/ios/FxA/FxA/include/openssl/ecdsa.h new file mode 100644 index 0000000000..681f3d5e55 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ecdsa.h @@ -0,0 +1,10 @@ +/* + * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include diff --git a/mobile/ios/FxA/FxA/include/openssl/engine.h b/mobile/ios/FxA/FxA/include/openssl/engine.h new file mode 100644 index 0000000000..26cf714843 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/engine.h @@ -0,0 +1,840 @@ +/* + * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_ENGINE_H +# define HEADER_ENGINE_H + +# include + +# ifndef OPENSSL_NO_ENGINE +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# include +# include +# include +# include +# include +# include +# include +# endif +# include +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + +/* + * These flags are used to control combinations of algorithm (methods) by + * bitwise "OR"ing. + */ +# define ENGINE_METHOD_RSA (unsigned int)0x0001 +# define ENGINE_METHOD_DSA (unsigned int)0x0002 +# define ENGINE_METHOD_DH (unsigned int)0x0004 +# define ENGINE_METHOD_RAND (unsigned int)0x0008 +# define ENGINE_METHOD_CIPHERS (unsigned int)0x0040 +# define ENGINE_METHOD_DIGESTS (unsigned int)0x0080 +# define ENGINE_METHOD_PKEY_METHS (unsigned int)0x0200 +# define ENGINE_METHOD_PKEY_ASN1_METHS (unsigned int)0x0400 +# define ENGINE_METHOD_EC (unsigned int)0x0800 +/* Obvious all-or-nothing cases. */ +# define ENGINE_METHOD_ALL (unsigned int)0xFFFF +# define ENGINE_METHOD_NONE (unsigned int)0x0000 + +/* + * This(ese) flag(s) controls behaviour of the ENGINE_TABLE mechanism used + * internally to control registration of ENGINE implementations, and can be + * set by ENGINE_set_table_flags(). The "NOINIT" flag prevents attempts to + * initialise registered ENGINEs if they are not already initialised. + */ +# define ENGINE_TABLE_FLAG_NOINIT (unsigned int)0x0001 + +/* ENGINE flags that can be set by ENGINE_set_flags(). */ +/* Not used */ +/* #define ENGINE_FLAGS_MALLOCED 0x0001 */ + +/* + * This flag is for ENGINEs that wish to handle the various 'CMD'-related + * control commands on their own. Without this flag, ENGINE_ctrl() handles + * these control commands on behalf of the ENGINE using their "cmd_defns" + * data. + */ +# define ENGINE_FLAGS_MANUAL_CMD_CTRL (int)0x0002 + +/* + * This flag is for ENGINEs who return new duplicate structures when found + * via "ENGINE_by_id()". When an ENGINE must store state (eg. if + * ENGINE_ctrl() commands are called in sequence as part of some stateful + * process like key-generation setup and execution), it can set this flag - + * then each attempt to obtain the ENGINE will result in it being copied into + * a new structure. Normally, ENGINEs don't declare this flag so + * ENGINE_by_id() just increments the existing ENGINE's structural reference + * count. + */ +# define ENGINE_FLAGS_BY_ID_COPY (int)0x0004 + +/* + * This flag if for an ENGINE that does not want its methods registered as + * part of ENGINE_register_all_complete() for example if the methods are not + * usable as default methods. + */ + +# define ENGINE_FLAGS_NO_REGISTER_ALL (int)0x0008 + +/* + * ENGINEs can support their own command types, and these flags are used in + * ENGINE_CTRL_GET_CMD_FLAGS to indicate to the caller what kind of input + * each command expects. Currently only numeric and string input is + * supported. If a control command supports none of the _NUMERIC, _STRING, or + * _NO_INPUT options, then it is regarded as an "internal" control command - + * and not for use in config setting situations. As such, they're not + * available to the ENGINE_ctrl_cmd_string() function, only raw ENGINE_ctrl() + * access. Changes to this list of 'command types' should be reflected + * carefully in ENGINE_cmd_is_executable() and ENGINE_ctrl_cmd_string(). + */ + +/* accepts a 'long' input value (3rd parameter to ENGINE_ctrl) */ +# define ENGINE_CMD_FLAG_NUMERIC (unsigned int)0x0001 +/* + * accepts string input (cast from 'void*' to 'const char *', 4th parameter + * to ENGINE_ctrl) + */ +# define ENGINE_CMD_FLAG_STRING (unsigned int)0x0002 +/* + * Indicates that the control command takes *no* input. Ie. the control + * command is unparameterised. + */ +# define ENGINE_CMD_FLAG_NO_INPUT (unsigned int)0x0004 +/* + * Indicates that the control command is internal. This control command won't + * be shown in any output, and is only usable through the ENGINE_ctrl_cmd() + * function. + */ +# define ENGINE_CMD_FLAG_INTERNAL (unsigned int)0x0008 + +/* + * NB: These 3 control commands are deprecated and should not be used. + * ENGINEs relying on these commands should compile conditional support for + * compatibility (eg. if these symbols are defined) but should also migrate + * the same functionality to their own ENGINE-specific control functions that + * can be "discovered" by calling applications. The fact these control + * commands wouldn't be "executable" (ie. usable by text-based config) + * doesn't change the fact that application code can find and use them + * without requiring per-ENGINE hacking. + */ + +/* + * These flags are used to tell the ctrl function what should be done. All + * command numbers are shared between all engines, even if some don't make + * sense to some engines. In such a case, they do nothing but return the + * error ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED. + */ +# define ENGINE_CTRL_SET_LOGSTREAM 1 +# define ENGINE_CTRL_SET_PASSWORD_CALLBACK 2 +# define ENGINE_CTRL_HUP 3/* Close and reinitialise + * any handles/connections + * etc. */ +# define ENGINE_CTRL_SET_USER_INTERFACE 4/* Alternative to callback */ +# define ENGINE_CTRL_SET_CALLBACK_DATA 5/* User-specific data, used + * when calling the password + * callback and the user + * interface */ +# define ENGINE_CTRL_LOAD_CONFIGURATION 6/* Load a configuration, + * given a string that + * represents a file name + * or so */ +# define ENGINE_CTRL_LOAD_SECTION 7/* Load data from a given + * section in the already + * loaded configuration */ + +/* + * These control commands allow an application to deal with an arbitrary + * engine in a dynamic way. Warn: Negative return values indicate errors FOR + * THESE COMMANDS because zero is used to indicate 'end-of-list'. Other + * commands, including ENGINE-specific command types, return zero for an + * error. An ENGINE can choose to implement these ctrl functions, and can + * internally manage things however it chooses - it does so by setting the + * ENGINE_FLAGS_MANUAL_CMD_CTRL flag (using ENGINE_set_flags()). Otherwise + * the ENGINE_ctrl() code handles this on the ENGINE's behalf using the + * cmd_defns data (set using ENGINE_set_cmd_defns()). This means an ENGINE's + * ctrl() handler need only implement its own commands - the above "meta" + * commands will be taken care of. + */ + +/* + * Returns non-zero if the supplied ENGINE has a ctrl() handler. If "not", + * then all the remaining control commands will return failure, so it is + * worth checking this first if the caller is trying to "discover" the + * engine's capabilities and doesn't want errors generated unnecessarily. + */ +# define ENGINE_CTRL_HAS_CTRL_FUNCTION 10 +/* + * Returns a positive command number for the first command supported by the + * engine. Returns zero if no ctrl commands are supported. + */ +# define ENGINE_CTRL_GET_FIRST_CMD_TYPE 11 +/* + * The 'long' argument specifies a command implemented by the engine, and the + * return value is the next command supported, or zero if there are no more. + */ +# define ENGINE_CTRL_GET_NEXT_CMD_TYPE 12 +/* + * The 'void*' argument is a command name (cast from 'const char *'), and the + * return value is the command that corresponds to it. + */ +# define ENGINE_CTRL_GET_CMD_FROM_NAME 13 +/* + * The next two allow a command to be converted into its corresponding string + * form. In each case, the 'long' argument supplies the command. In the + * NAME_LEN case, the return value is the length of the command name (not + * counting a trailing EOL). In the NAME case, the 'void*' argument must be a + * string buffer large enough, and it will be populated with the name of the + * command (WITH a trailing EOL). + */ +# define ENGINE_CTRL_GET_NAME_LEN_FROM_CMD 14 +# define ENGINE_CTRL_GET_NAME_FROM_CMD 15 +/* The next two are similar but give a "short description" of a command. */ +# define ENGINE_CTRL_GET_DESC_LEN_FROM_CMD 16 +# define ENGINE_CTRL_GET_DESC_FROM_CMD 17 +/* + * With this command, the return value is the OR'd combination of + * ENGINE_CMD_FLAG_*** values that indicate what kind of input a given + * engine-specific ctrl command expects. + */ +# define ENGINE_CTRL_GET_CMD_FLAGS 18 + +/* + * ENGINE implementations should start the numbering of their own control + * commands from this value. (ie. ENGINE_CMD_BASE, ENGINE_CMD_BASE + 1, etc). + */ +# define ENGINE_CMD_BASE 200 + +/* + * NB: These 2 nCipher "chil" control commands are deprecated, and their + * functionality is now available through ENGINE-specific control commands + * (exposed through the above-mentioned 'CMD'-handling). Code using these 2 + * commands should be migrated to the more general command handling before + * these are removed. + */ + +/* Flags specific to the nCipher "chil" engine */ +# define ENGINE_CTRL_CHIL_SET_FORKCHECK 100 + /* + * Depending on the value of the (long)i argument, this sets or + * unsets the SimpleForkCheck flag in the CHIL API to enable or + * disable checking and workarounds for applications that fork(). + */ +# define ENGINE_CTRL_CHIL_NO_LOCKING 101 + /* + * This prevents the initialisation function from providing mutex + * callbacks to the nCipher library. + */ + +/* + * If an ENGINE supports its own specific control commands and wishes the + * framework to handle the above 'ENGINE_CMD_***'-manipulation commands on + * its behalf, it should supply a null-terminated array of ENGINE_CMD_DEFN + * entries to ENGINE_set_cmd_defns(). It should also implement a ctrl() + * handler that supports the stated commands (ie. the "cmd_num" entries as + * described by the array). NB: The array must be ordered in increasing order + * of cmd_num. "null-terminated" means that the last ENGINE_CMD_DEFN element + * has cmd_num set to zero and/or cmd_name set to NULL. + */ +typedef struct ENGINE_CMD_DEFN_st { + unsigned int cmd_num; /* The command number */ + const char *cmd_name; /* The command name itself */ + const char *cmd_desc; /* A short description of the command */ + unsigned int cmd_flags; /* The input the command expects */ +} ENGINE_CMD_DEFN; + +/* Generic function pointer */ +typedef int (*ENGINE_GEN_FUNC_PTR) (void); +/* Generic function pointer taking no arguments */ +typedef int (*ENGINE_GEN_INT_FUNC_PTR) (ENGINE *); +/* Specific control function pointer */ +typedef int (*ENGINE_CTRL_FUNC_PTR) (ENGINE *, int, long, void *, + void (*f) (void)); +/* Generic load_key function pointer */ +typedef EVP_PKEY *(*ENGINE_LOAD_KEY_PTR)(ENGINE *, const char *, + UI_METHOD *ui_method, + void *callback_data); +typedef int (*ENGINE_SSL_CLIENT_CERT_PTR) (ENGINE *, SSL *ssl, + STACK_OF(X509_NAME) *ca_dn, + X509 **pcert, EVP_PKEY **pkey, + STACK_OF(X509) **pother, + UI_METHOD *ui_method, + void *callback_data); +/*- + * These callback types are for an ENGINE's handler for cipher and digest logic. + * These handlers have these prototypes; + * int foo(ENGINE *e, const EVP_CIPHER **cipher, const int **nids, int nid); + * int foo(ENGINE *e, const EVP_MD **digest, const int **nids, int nid); + * Looking at how to implement these handlers in the case of cipher support, if + * the framework wants the EVP_CIPHER for 'nid', it will call; + * foo(e, &p_evp_cipher, NULL, nid); (return zero for failure) + * If the framework wants a list of supported 'nid's, it will call; + * foo(e, NULL, &p_nids, 0); (returns number of 'nids' or -1 for error) + */ +/* + * Returns to a pointer to the array of supported cipher 'nid's. If the + * second parameter is non-NULL it is set to the size of the returned array. + */ +typedef int (*ENGINE_CIPHERS_PTR) (ENGINE *, const EVP_CIPHER **, + const int **, int); +typedef int (*ENGINE_DIGESTS_PTR) (ENGINE *, const EVP_MD **, const int **, + int); +typedef int (*ENGINE_PKEY_METHS_PTR) (ENGINE *, EVP_PKEY_METHOD **, + const int **, int); +typedef int (*ENGINE_PKEY_ASN1_METHS_PTR) (ENGINE *, EVP_PKEY_ASN1_METHOD **, + const int **, int); +/* + * STRUCTURE functions ... all of these functions deal with pointers to + * ENGINE structures where the pointers have a "structural reference". This + * means that their reference is to allowed access to the structure but it + * does not imply that the structure is functional. To simply increment or + * decrement the structural reference count, use ENGINE_by_id and + * ENGINE_free. NB: This is not required when iterating using ENGINE_get_next + * as it will automatically decrement the structural reference count of the + * "current" ENGINE and increment the structural reference count of the + * ENGINE it returns (unless it is NULL). + */ + +/* Get the first/last "ENGINE" type available. */ +ENGINE *ENGINE_get_first(void); +ENGINE *ENGINE_get_last(void); +/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */ +ENGINE *ENGINE_get_next(ENGINE *e); +ENGINE *ENGINE_get_prev(ENGINE *e); +/* Add another "ENGINE" type into the array. */ +int ENGINE_add(ENGINE *e); +/* Remove an existing "ENGINE" type from the array. */ +int ENGINE_remove(ENGINE *e); +/* Retrieve an engine from the list by its unique "id" value. */ +ENGINE *ENGINE_by_id(const char *id); + +#if OPENSSL_API_COMPAT < 0x10100000L +# define ENGINE_load_openssl() \ + OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_OPENSSL, NULL) +# define ENGINE_load_dynamic() \ + OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_DYNAMIC, NULL) +# ifndef OPENSSL_NO_STATIC_ENGINE +# define ENGINE_load_padlock() \ + OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_PADLOCK, NULL) +# define ENGINE_load_capi() \ + OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_CAPI, NULL) +# define ENGINE_load_afalg() \ + OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_AFALG, NULL) +# endif +# define ENGINE_load_cryptodev() \ + OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_CRYPTODEV, NULL) +# define ENGINE_load_rdrand() \ + OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_RDRAND, NULL) +#endif +void ENGINE_load_builtin_engines(void); + +/* + * Get and set global flags (ENGINE_TABLE_FLAG_***) for the implementation + * "registry" handling. + */ +unsigned int ENGINE_get_table_flags(void); +void ENGINE_set_table_flags(unsigned int flags); + +/*- Manage registration of ENGINEs per "table". For each type, there are 3 + * functions; + * ENGINE_register_***(e) - registers the implementation from 'e' (if it has one) + * ENGINE_unregister_***(e) - unregister the implementation from 'e' + * ENGINE_register_all_***() - call ENGINE_register_***() for each 'e' in the list + * Cleanup is automatically registered from each table when required. + */ + +int ENGINE_register_RSA(ENGINE *e); +void ENGINE_unregister_RSA(ENGINE *e); +void ENGINE_register_all_RSA(void); + +int ENGINE_register_DSA(ENGINE *e); +void ENGINE_unregister_DSA(ENGINE *e); +void ENGINE_register_all_DSA(void); + +int ENGINE_register_EC(ENGINE *e); +void ENGINE_unregister_EC(ENGINE *e); +void ENGINE_register_all_EC(void); + +int ENGINE_register_DH(ENGINE *e); +void ENGINE_unregister_DH(ENGINE *e); +void ENGINE_register_all_DH(void); + +int ENGINE_register_RAND(ENGINE *e); +void ENGINE_unregister_RAND(ENGINE *e); +void ENGINE_register_all_RAND(void); + +int ENGINE_register_ciphers(ENGINE *e); +void ENGINE_unregister_ciphers(ENGINE *e); +void ENGINE_register_all_ciphers(void); + +int ENGINE_register_digests(ENGINE *e); +void ENGINE_unregister_digests(ENGINE *e); +void ENGINE_register_all_digests(void); + +int ENGINE_register_pkey_meths(ENGINE *e); +void ENGINE_unregister_pkey_meths(ENGINE *e); +void ENGINE_register_all_pkey_meths(void); + +int ENGINE_register_pkey_asn1_meths(ENGINE *e); +void ENGINE_unregister_pkey_asn1_meths(ENGINE *e); +void ENGINE_register_all_pkey_asn1_meths(void); + +/* + * These functions register all support from the above categories. Note, use + * of these functions can result in static linkage of code your application + * may not need. If you only need a subset of functionality, consider using + * more selective initialisation. + */ +int ENGINE_register_complete(ENGINE *e); +int ENGINE_register_all_complete(void); + +/* + * Send parametrised control commands to the engine. The possibilities to + * send down an integer, a pointer to data or a function pointer are + * provided. Any of the parameters may or may not be NULL, depending on the + * command number. In actuality, this function only requires a structural + * (rather than functional) reference to an engine, but many control commands + * may require the engine be functional. The caller should be aware of trying + * commands that require an operational ENGINE, and only use functional + * references in such situations. + */ +int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)); + +/* + * This function tests if an ENGINE-specific command is usable as a + * "setting". Eg. in an application's config file that gets processed through + * ENGINE_ctrl_cmd_string(). If this returns zero, it is not available to + * ENGINE_ctrl_cmd_string(), only ENGINE_ctrl(). + */ +int ENGINE_cmd_is_executable(ENGINE *e, int cmd); + +/* + * This function works like ENGINE_ctrl() with the exception of taking a + * command name instead of a command number, and can handle optional + * commands. See the comment on ENGINE_ctrl_cmd_string() for an explanation + * on how to use the cmd_name and cmd_optional. + */ +int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name, + long i, void *p, void (*f) (void), int cmd_optional); + +/* + * This function passes a command-name and argument to an ENGINE. The + * cmd_name is converted to a command number and the control command is + * called using 'arg' as an argument (unless the ENGINE doesn't support such + * a command, in which case no control command is called). The command is + * checked for input flags, and if necessary the argument will be converted + * to a numeric value. If cmd_optional is non-zero, then if the ENGINE + * doesn't support the given cmd_name the return value will be success + * anyway. This function is intended for applications to use so that users + * (or config files) can supply engine-specific config data to the ENGINE at + * run-time to control behaviour of specific engines. As such, it shouldn't + * be used for calling ENGINE_ctrl() functions that return data, deal with + * binary data, or that are otherwise supposed to be used directly through + * ENGINE_ctrl() in application code. Any "return" data from an ENGINE_ctrl() + * operation in this function will be lost - the return value is interpreted + * as failure if the return value is zero, success otherwise, and this + * function returns a boolean value as a result. In other words, vendors of + * 'ENGINE'-enabled devices should write ENGINE implementations with + * parameterisations that work in this scheme, so that compliant ENGINE-based + * applications can work consistently with the same configuration for the + * same ENGINE-enabled devices, across applications. + */ +int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg, + int cmd_optional); + +/* + * These functions are useful for manufacturing new ENGINE structures. They + * don't address reference counting at all - one uses them to populate an + * ENGINE structure with personalised implementations of things prior to + * using it directly or adding it to the builtin ENGINE list in OpenSSL. + * These are also here so that the ENGINE structure doesn't have to be + * exposed and break binary compatibility! + */ +ENGINE *ENGINE_new(void); +int ENGINE_free(ENGINE *e); +int ENGINE_up_ref(ENGINE *e); +int ENGINE_set_id(ENGINE *e, const char *id); +int ENGINE_set_name(ENGINE *e, const char *name); +int ENGINE_set_RSA(ENGINE *e, const RSA_METHOD *rsa_meth); +int ENGINE_set_DSA(ENGINE *e, const DSA_METHOD *dsa_meth); +int ENGINE_set_EC(ENGINE *e, const EC_KEY_METHOD *ecdsa_meth); +int ENGINE_set_DH(ENGINE *e, const DH_METHOD *dh_meth); +int ENGINE_set_RAND(ENGINE *e, const RAND_METHOD *rand_meth); +int ENGINE_set_destroy_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR destroy_f); +int ENGINE_set_init_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR init_f); +int ENGINE_set_finish_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR finish_f); +int ENGINE_set_ctrl_function(ENGINE *e, ENGINE_CTRL_FUNC_PTR ctrl_f); +int ENGINE_set_load_privkey_function(ENGINE *e, + ENGINE_LOAD_KEY_PTR loadpriv_f); +int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f); +int ENGINE_set_load_ssl_client_cert_function(ENGINE *e, + ENGINE_SSL_CLIENT_CERT_PTR + loadssl_f); +int ENGINE_set_ciphers(ENGINE *e, ENGINE_CIPHERS_PTR f); +int ENGINE_set_digests(ENGINE *e, ENGINE_DIGESTS_PTR f); +int ENGINE_set_pkey_meths(ENGINE *e, ENGINE_PKEY_METHS_PTR f); +int ENGINE_set_pkey_asn1_meths(ENGINE *e, ENGINE_PKEY_ASN1_METHS_PTR f); +int ENGINE_set_flags(ENGINE *e, int flags); +int ENGINE_set_cmd_defns(ENGINE *e, const ENGINE_CMD_DEFN *defns); +/* These functions allow control over any per-structure ENGINE data. */ +#define ENGINE_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_ENGINE, l, p, newf, dupf, freef) +int ENGINE_set_ex_data(ENGINE *e, int idx, void *arg); +void *ENGINE_get_ex_data(const ENGINE *e, int idx); + +#if OPENSSL_API_COMPAT < 0x10100000L +/* + * This function previously cleaned up anything that needs it. Auto-deinit will + * now take care of it so it is no longer required to call this function. + */ +# define ENGINE_cleanup() while(0) continue +#endif + +/* + * These return values from within the ENGINE structure. These can be useful + * with functional references as well as structural references - it depends + * which you obtained. Using the result for functional purposes if you only + * obtained a structural reference may be problematic! + */ +const char *ENGINE_get_id(const ENGINE *e); +const char *ENGINE_get_name(const ENGINE *e); +const RSA_METHOD *ENGINE_get_RSA(const ENGINE *e); +const DSA_METHOD *ENGINE_get_DSA(const ENGINE *e); +const EC_KEY_METHOD *ENGINE_get_EC(const ENGINE *e); +const DH_METHOD *ENGINE_get_DH(const ENGINE *e); +const RAND_METHOD *ENGINE_get_RAND(const ENGINE *e); +ENGINE_GEN_INT_FUNC_PTR ENGINE_get_destroy_function(const ENGINE *e); +ENGINE_GEN_INT_FUNC_PTR ENGINE_get_init_function(const ENGINE *e); +ENGINE_GEN_INT_FUNC_PTR ENGINE_get_finish_function(const ENGINE *e); +ENGINE_CTRL_FUNC_PTR ENGINE_get_ctrl_function(const ENGINE *e); +ENGINE_LOAD_KEY_PTR ENGINE_get_load_privkey_function(const ENGINE *e); +ENGINE_LOAD_KEY_PTR ENGINE_get_load_pubkey_function(const ENGINE *e); +ENGINE_SSL_CLIENT_CERT_PTR ENGINE_get_ssl_client_cert_function(const ENGINE + *e); +ENGINE_CIPHERS_PTR ENGINE_get_ciphers(const ENGINE *e); +ENGINE_DIGESTS_PTR ENGINE_get_digests(const ENGINE *e); +ENGINE_PKEY_METHS_PTR ENGINE_get_pkey_meths(const ENGINE *e); +ENGINE_PKEY_ASN1_METHS_PTR ENGINE_get_pkey_asn1_meths(const ENGINE *e); +const EVP_CIPHER *ENGINE_get_cipher(ENGINE *e, int nid); +const EVP_MD *ENGINE_get_digest(ENGINE *e, int nid); +const EVP_PKEY_METHOD *ENGINE_get_pkey_meth(ENGINE *e, int nid); +const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid); +const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e, + const char *str, + int len); +const EVP_PKEY_ASN1_METHOD *ENGINE_pkey_asn1_find_str(ENGINE **pe, + const char *str, + int len); +const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *e); +int ENGINE_get_flags(const ENGINE *e); + +/* + * FUNCTIONAL functions. These functions deal with ENGINE structures that + * have (or will) be initialised for use. Broadly speaking, the structural + * functions are useful for iterating the list of available engine types, + * creating new engine types, and other "list" operations. These functions + * actually deal with ENGINEs that are to be used. As such these functions + * can fail (if applicable) when particular engines are unavailable - eg. if + * a hardware accelerator is not attached or not functioning correctly. Each + * ENGINE has 2 reference counts; structural and functional. Every time a + * functional reference is obtained or released, a corresponding structural + * reference is automatically obtained or released too. + */ + +/* + * Initialise a engine type for use (or up its reference count if it's + * already in use). This will fail if the engine is not currently operational + * and cannot initialise. + */ +int ENGINE_init(ENGINE *e); +/* + * Free a functional reference to a engine type. This does not require a + * corresponding call to ENGINE_free as it also releases a structural + * reference. + */ +int ENGINE_finish(ENGINE *e); + +/* + * The following functions handle keys that are stored in some secondary + * location, handled by the engine. The storage may be on a card or + * whatever. + */ +EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, + UI_METHOD *ui_method, void *callback_data); +EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id, + UI_METHOD *ui_method, void *callback_data); +int ENGINE_load_ssl_client_cert(ENGINE *e, SSL *s, + STACK_OF(X509_NAME) *ca_dn, X509 **pcert, + EVP_PKEY **ppkey, STACK_OF(X509) **pother, + UI_METHOD *ui_method, void *callback_data); + +/* + * This returns a pointer for the current ENGINE structure that is (by + * default) performing any RSA operations. The value returned is an + * incremented reference, so it should be free'd (ENGINE_finish) before it is + * discarded. + */ +ENGINE *ENGINE_get_default_RSA(void); +/* Same for the other "methods" */ +ENGINE *ENGINE_get_default_DSA(void); +ENGINE *ENGINE_get_default_EC(void); +ENGINE *ENGINE_get_default_DH(void); +ENGINE *ENGINE_get_default_RAND(void); +/* + * These functions can be used to get a functional reference to perform + * ciphering or digesting corresponding to "nid". + */ +ENGINE *ENGINE_get_cipher_engine(int nid); +ENGINE *ENGINE_get_digest_engine(int nid); +ENGINE *ENGINE_get_pkey_meth_engine(int nid); +ENGINE *ENGINE_get_pkey_asn1_meth_engine(int nid); + +/* + * This sets a new default ENGINE structure for performing RSA operations. If + * the result is non-zero (success) then the ENGINE structure will have had + * its reference count up'd so the caller should still free their own + * reference 'e'. + */ +int ENGINE_set_default_RSA(ENGINE *e); +int ENGINE_set_default_string(ENGINE *e, const char *def_list); +/* Same for the other "methods" */ +int ENGINE_set_default_DSA(ENGINE *e); +int ENGINE_set_default_EC(ENGINE *e); +int ENGINE_set_default_DH(ENGINE *e); +int ENGINE_set_default_RAND(ENGINE *e); +int ENGINE_set_default_ciphers(ENGINE *e); +int ENGINE_set_default_digests(ENGINE *e); +int ENGINE_set_default_pkey_meths(ENGINE *e); +int ENGINE_set_default_pkey_asn1_meths(ENGINE *e); + +/* + * The combination "set" - the flags are bitwise "OR"d from the + * ENGINE_METHOD_*** defines above. As with the "ENGINE_register_complete()" + * function, this function can result in unnecessary static linkage. If your + * application requires only specific functionality, consider using more + * selective functions. + */ +int ENGINE_set_default(ENGINE *e, unsigned int flags); + +void ENGINE_add_conf_module(void); + +/* Deprecated functions ... */ +/* int ENGINE_clear_defaults(void); */ + +/**************************/ +/* DYNAMIC ENGINE SUPPORT */ +/**************************/ + +/* Binary/behaviour compatibility levels */ +# define OSSL_DYNAMIC_VERSION (unsigned long)0x00030000 +/* + * Binary versions older than this are too old for us (whether we're a loader + * or a loadee) + */ +# define OSSL_DYNAMIC_OLDEST (unsigned long)0x00030000 + +/* + * When compiling an ENGINE entirely as an external shared library, loadable + * by the "dynamic" ENGINE, these types are needed. The 'dynamic_fns' + * structure type provides the calling application's (or library's) error + * functionality and memory management function pointers to the loaded + * library. These should be used/set in the loaded library code so that the + * loading application's 'state' will be used/changed in all operations. The + * 'static_state' pointer allows the loaded library to know if it shares the + * same static data as the calling application (or library), and thus whether + * these callbacks need to be set or not. + */ +typedef void *(*dyn_MEM_malloc_fn) (size_t, const char *, int); +typedef void *(*dyn_MEM_realloc_fn) (void *, size_t, const char *, int); +typedef void (*dyn_MEM_free_fn) (void *, const char *, int); +typedef struct st_dynamic_MEM_fns { + dyn_MEM_malloc_fn malloc_fn; + dyn_MEM_realloc_fn realloc_fn; + dyn_MEM_free_fn free_fn; +} dynamic_MEM_fns; +/* + * FIXME: Perhaps the memory and locking code (crypto.h) should declare and + * use these types so we (and any other dependent code) can simplify a bit?? + */ +/* The top-level structure */ +typedef struct st_dynamic_fns { + void *static_state; + dynamic_MEM_fns mem_fns; +} dynamic_fns; + +/* + * The version checking function should be of this prototype. NB: The + * ossl_version value passed in is the OSSL_DYNAMIC_VERSION of the loading + * code. If this function returns zero, it indicates a (potential) version + * incompatibility and the loaded library doesn't believe it can proceed. + * Otherwise, the returned value is the (latest) version supported by the + * loading library. The loader may still decide that the loaded code's + * version is unsatisfactory and could veto the load. The function is + * expected to be implemented with the symbol name "v_check", and a default + * implementation can be fully instantiated with + * IMPLEMENT_DYNAMIC_CHECK_FN(). + */ +typedef unsigned long (*dynamic_v_check_fn) (unsigned long ossl_version); +# define IMPLEMENT_DYNAMIC_CHECK_FN() \ + OPENSSL_EXPORT unsigned long v_check(unsigned long v); \ + OPENSSL_EXPORT unsigned long v_check(unsigned long v) { \ + if (v >= OSSL_DYNAMIC_OLDEST) return OSSL_DYNAMIC_VERSION; \ + return 0; } + +/* + * This function is passed the ENGINE structure to initialise with its own + * function and command settings. It should not adjust the structural or + * functional reference counts. If this function returns zero, (a) the load + * will be aborted, (b) the previous ENGINE state will be memcpy'd back onto + * the structure, and (c) the shared library will be unloaded. So + * implementations should do their own internal cleanup in failure + * circumstances otherwise they could leak. The 'id' parameter, if non-NULL, + * represents the ENGINE id that the loader is looking for. If this is NULL, + * the shared library can choose to return failure or to initialise a + * 'default' ENGINE. If non-NULL, the shared library must initialise only an + * ENGINE matching the passed 'id'. The function is expected to be + * implemented with the symbol name "bind_engine". A standard implementation + * can be instantiated with IMPLEMENT_DYNAMIC_BIND_FN(fn) where the parameter + * 'fn' is a callback function that populates the ENGINE structure and + * returns an int value (zero for failure). 'fn' should have prototype; + * [static] int fn(ENGINE *e, const char *id); + */ +typedef int (*dynamic_bind_engine) (ENGINE *e, const char *id, + const dynamic_fns *fns); +# define IMPLEMENT_DYNAMIC_BIND_FN(fn) \ + OPENSSL_EXPORT \ + int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); \ + OPENSSL_EXPORT \ + int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) { \ + if (ENGINE_get_static_state() == fns->static_state) goto skip_cbs; \ + CRYPTO_set_mem_functions(fns->mem_fns.malloc_fn, \ + fns->mem_fns.realloc_fn, \ + fns->mem_fns.free_fn); \ + skip_cbs: \ + if (!fn(e, id)) return 0; \ + return 1; } + +/* + * If the loading application (or library) and the loaded ENGINE library + * share the same static data (eg. they're both dynamically linked to the + * same libcrypto.so) we need a way to avoid trying to set system callbacks - + * this would fail, and for the same reason that it's unnecessary to try. If + * the loaded ENGINE has (or gets from through the loader) its own copy of + * the libcrypto static data, we will need to set the callbacks. The easiest + * way to detect this is to have a function that returns a pointer to some + * static data and let the loading application and loaded ENGINE compare + * their respective values. + */ +void *ENGINE_get_static_state(void); + +# if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV) +DEPRECATEDIN_1_1_0(void ENGINE_setup_bsd_cryptodev(void)) +# endif + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_ENGINE_strings(void); + +/* Error codes for the ENGINE functions. */ + +/* Function codes. */ +# define ENGINE_F_DYNAMIC_CTRL 180 +# define ENGINE_F_DYNAMIC_GET_DATA_CTX 181 +# define ENGINE_F_DYNAMIC_LOAD 182 +# define ENGINE_F_DYNAMIC_SET_DATA_CTX 183 +# define ENGINE_F_ENGINE_ADD 105 +# define ENGINE_F_ENGINE_BY_ID 106 +# define ENGINE_F_ENGINE_CMD_IS_EXECUTABLE 170 +# define ENGINE_F_ENGINE_CTRL 142 +# define ENGINE_F_ENGINE_CTRL_CMD 178 +# define ENGINE_F_ENGINE_CTRL_CMD_STRING 171 +# define ENGINE_F_ENGINE_FINISH 107 +# define ENGINE_F_ENGINE_GET_CIPHER 185 +# define ENGINE_F_ENGINE_GET_DIGEST 186 +# define ENGINE_F_ENGINE_GET_FIRST 195 +# define ENGINE_F_ENGINE_GET_LAST 196 +# define ENGINE_F_ENGINE_GET_NEXT 115 +# define ENGINE_F_ENGINE_GET_PKEY_ASN1_METH 193 +# define ENGINE_F_ENGINE_GET_PKEY_METH 192 +# define ENGINE_F_ENGINE_GET_PREV 116 +# define ENGINE_F_ENGINE_INIT 119 +# define ENGINE_F_ENGINE_LIST_ADD 120 +# define ENGINE_F_ENGINE_LIST_REMOVE 121 +# define ENGINE_F_ENGINE_LOAD_PRIVATE_KEY 150 +# define ENGINE_F_ENGINE_LOAD_PUBLIC_KEY 151 +# define ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT 194 +# define ENGINE_F_ENGINE_NEW 122 +# define ENGINE_F_ENGINE_PKEY_ASN1_FIND_STR 197 +# define ENGINE_F_ENGINE_REMOVE 123 +# define ENGINE_F_ENGINE_SET_DEFAULT_STRING 189 +# define ENGINE_F_ENGINE_SET_ID 129 +# define ENGINE_F_ENGINE_SET_NAME 130 +# define ENGINE_F_ENGINE_TABLE_REGISTER 184 +# define ENGINE_F_ENGINE_UNLOCKED_FINISH 191 +# define ENGINE_F_ENGINE_UP_REF 190 +# define ENGINE_F_INT_CTRL_HELPER 172 +# define ENGINE_F_INT_ENGINE_CONFIGURE 188 +# define ENGINE_F_INT_ENGINE_MODULE_INIT 187 + +/* Reason codes. */ +# define ENGINE_R_ALREADY_LOADED 100 +# define ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER 133 +# define ENGINE_R_CMD_NOT_EXECUTABLE 134 +# define ENGINE_R_COMMAND_TAKES_INPUT 135 +# define ENGINE_R_COMMAND_TAKES_NO_INPUT 136 +# define ENGINE_R_CONFLICTING_ENGINE_ID 103 +# define ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED 119 +# define ENGINE_R_DSO_FAILURE 104 +# define ENGINE_R_DSO_NOT_FOUND 132 +# define ENGINE_R_ENGINES_SECTION_ERROR 148 +# define ENGINE_R_ENGINE_CONFIGURATION_ERROR 102 +# define ENGINE_R_ENGINE_IS_NOT_IN_LIST 105 +# define ENGINE_R_ENGINE_SECTION_ERROR 149 +# define ENGINE_R_FAILED_LOADING_PRIVATE_KEY 128 +# define ENGINE_R_FAILED_LOADING_PUBLIC_KEY 129 +# define ENGINE_R_FINISH_FAILED 106 +# define ENGINE_R_ID_OR_NAME_MISSING 108 +# define ENGINE_R_INIT_FAILED 109 +# define ENGINE_R_INTERNAL_LIST_ERROR 110 +# define ENGINE_R_INVALID_ARGUMENT 143 +# define ENGINE_R_INVALID_CMD_NAME 137 +# define ENGINE_R_INVALID_CMD_NUMBER 138 +# define ENGINE_R_INVALID_INIT_VALUE 151 +# define ENGINE_R_INVALID_STRING 150 +# define ENGINE_R_NOT_INITIALISED 117 +# define ENGINE_R_NOT_LOADED 112 +# define ENGINE_R_NO_CONTROL_FUNCTION 120 +# define ENGINE_R_NO_INDEX 144 +# define ENGINE_R_NO_LOAD_FUNCTION 125 +# define ENGINE_R_NO_REFERENCE 130 +# define ENGINE_R_NO_SUCH_ENGINE 116 +# define ENGINE_R_UNIMPLEMENTED_CIPHER 146 +# define ENGINE_R_UNIMPLEMENTED_DIGEST 147 +# define ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD 101 +# define ENGINE_R_VERSION_INCOMPATIBILITY 145 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/err.h b/mobile/ios/FxA/FxA/include/openssl/err.h new file mode 100644 index 0000000000..9bbe9e1091 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/err.h @@ -0,0 +1,259 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_ERR_H +# define HEADER_ERR_H + +# include + +# ifndef OPENSSL_NO_STDIO +# include +# include +# endif + +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +# ifndef OPENSSL_NO_ERR +# define ERR_PUT_error(a,b,c,d,e) ERR_put_error(a,b,c,d,e) +# else +# define ERR_PUT_error(a,b,c,d,e) ERR_put_error(a,b,c,NULL,0) +# endif + +# include + +# define ERR_TXT_MALLOCED 0x01 +# define ERR_TXT_STRING 0x02 + +# define ERR_FLAG_MARK 0x01 + +# define ERR_NUM_ERRORS 16 +typedef struct err_state_st { + int err_flags[ERR_NUM_ERRORS]; + unsigned long err_buffer[ERR_NUM_ERRORS]; + char *err_data[ERR_NUM_ERRORS]; + int err_data_flags[ERR_NUM_ERRORS]; + const char *err_file[ERR_NUM_ERRORS]; + int err_line[ERR_NUM_ERRORS]; + int top, bottom; +} ERR_STATE; + +/* library */ +# define ERR_LIB_NONE 1 +# define ERR_LIB_SYS 2 +# define ERR_LIB_BN 3 +# define ERR_LIB_RSA 4 +# define ERR_LIB_DH 5 +# define ERR_LIB_EVP 6 +# define ERR_LIB_BUF 7 +# define ERR_LIB_OBJ 8 +# define ERR_LIB_PEM 9 +# define ERR_LIB_DSA 10 +# define ERR_LIB_X509 11 +/* #define ERR_LIB_METH 12 */ +# define ERR_LIB_ASN1 13 +# define ERR_LIB_CONF 14 +# define ERR_LIB_CRYPTO 15 +# define ERR_LIB_EC 16 +# define ERR_LIB_SSL 20 +/* #define ERR_LIB_SSL23 21 */ +/* #define ERR_LIB_SSL2 22 */ +/* #define ERR_LIB_SSL3 23 */ +/* #define ERR_LIB_RSAREF 30 */ +/* #define ERR_LIB_PROXY 31 */ +# define ERR_LIB_BIO 32 +# define ERR_LIB_PKCS7 33 +# define ERR_LIB_X509V3 34 +# define ERR_LIB_PKCS12 35 +# define ERR_LIB_RAND 36 +# define ERR_LIB_DSO 37 +# define ERR_LIB_ENGINE 38 +# define ERR_LIB_OCSP 39 +# define ERR_LIB_UI 40 +# define ERR_LIB_COMP 41 +# define ERR_LIB_ECDSA 42 +# define ERR_LIB_ECDH 43 +# define ERR_LIB_STORE 44 +# define ERR_LIB_FIPS 45 +# define ERR_LIB_CMS 46 +# define ERR_LIB_TS 47 +# define ERR_LIB_HMAC 48 +/* # define ERR_LIB_JPAKE 49 */ +# define ERR_LIB_CT 50 +# define ERR_LIB_ASYNC 51 +# define ERR_LIB_KDF 52 + +# define ERR_LIB_USER 128 + +# define SYSerr(f,r) ERR_PUT_error(ERR_LIB_SYS,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define BNerr(f,r) ERR_PUT_error(ERR_LIB_BN,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define RSAerr(f,r) ERR_PUT_error(ERR_LIB_RSA,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define DHerr(f,r) ERR_PUT_error(ERR_LIB_DH,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define EVPerr(f,r) ERR_PUT_error(ERR_LIB_EVP,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define BUFerr(f,r) ERR_PUT_error(ERR_LIB_BUF,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define OBJerr(f,r) ERR_PUT_error(ERR_LIB_OBJ,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define PEMerr(f,r) ERR_PUT_error(ERR_LIB_PEM,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define DSAerr(f,r) ERR_PUT_error(ERR_LIB_DSA,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define X509err(f,r) ERR_PUT_error(ERR_LIB_X509,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define ASN1err(f,r) ERR_PUT_error(ERR_LIB_ASN1,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define CONFerr(f,r) ERR_PUT_error(ERR_LIB_CONF,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define CRYPTOerr(f,r) ERR_PUT_error(ERR_LIB_CRYPTO,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define ECerr(f,r) ERR_PUT_error(ERR_LIB_EC,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define SSLerr(f,r) ERR_PUT_error(ERR_LIB_SSL,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define BIOerr(f,r) ERR_PUT_error(ERR_LIB_BIO,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define PKCS7err(f,r) ERR_PUT_error(ERR_LIB_PKCS7,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define X509V3err(f,r) ERR_PUT_error(ERR_LIB_X509V3,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define PKCS12err(f,r) ERR_PUT_error(ERR_LIB_PKCS12,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define RANDerr(f,r) ERR_PUT_error(ERR_LIB_RAND,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define DSOerr(f,r) ERR_PUT_error(ERR_LIB_DSO,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define ENGINEerr(f,r) ERR_PUT_error(ERR_LIB_ENGINE,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define OCSPerr(f,r) ERR_PUT_error(ERR_LIB_OCSP,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define UIerr(f,r) ERR_PUT_error(ERR_LIB_UI,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define COMPerr(f,r) ERR_PUT_error(ERR_LIB_COMP,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define ECDSAerr(f,r) ERR_PUT_error(ERR_LIB_ECDSA,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define ECDHerr(f,r) ERR_PUT_error(ERR_LIB_ECDH,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define STOREerr(f,r) ERR_PUT_error(ERR_LIB_STORE,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define FIPSerr(f,r) ERR_PUT_error(ERR_LIB_FIPS,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define CMSerr(f,r) ERR_PUT_error(ERR_LIB_CMS,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define TSerr(f,r) ERR_PUT_error(ERR_LIB_TS,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define HMACerr(f,r) ERR_PUT_error(ERR_LIB_HMAC,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define CTerr(f,r) ERR_PUT_error(ERR_LIB_CT,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define ASYNCerr(f,r) ERR_PUT_error(ERR_LIB_ASYNC,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define KDFerr(f,r) ERR_PUT_error(ERR_LIB_KDF,(f),(r),OPENSSL_FILE,OPENSSL_LINE) + +# define ERR_PACK(l,f,r) ( \ + (((unsigned int)(l) & 0x0FF) << 24L) | \ + (((unsigned int)(f) & 0xFFF) << 12L) | \ + (((unsigned int)(r) & 0xFFF) ) ) +# define ERR_GET_LIB(l) (int)(((l) >> 24L) & 0x0FFL) +# define ERR_GET_FUNC(l) (int)(((l) >> 12L) & 0xFFFL) +# define ERR_GET_REASON(l) (int)( (l) & 0xFFFL) +# define ERR_FATAL_ERROR(l) (int)( (l) & ERR_R_FATAL) + +/* OS functions */ +# define SYS_F_FOPEN 1 +# define SYS_F_CONNECT 2 +# define SYS_F_GETSERVBYNAME 3 +# define SYS_F_SOCKET 4 +# define SYS_F_IOCTLSOCKET 5 +# define SYS_F_BIND 6 +# define SYS_F_LISTEN 7 +# define SYS_F_ACCEPT 8 +# define SYS_F_WSASTARTUP 9/* Winsock stuff */ +# define SYS_F_OPENDIR 10 +# define SYS_F_FREAD 11 +# define SYS_F_GETADDRINFO 12 +# define SYS_F_GETNAMEINFO 13 +# define SYS_F_SETSOCKOPT 14 +# define SYS_F_GETSOCKOPT 15 +# define SYS_F_GETSOCKNAME 16 +# define SYS_F_GETHOSTBYNAME 17 + +/* reasons */ +# define ERR_R_SYS_LIB ERR_LIB_SYS/* 2 */ +# define ERR_R_BN_LIB ERR_LIB_BN/* 3 */ +# define ERR_R_RSA_LIB ERR_LIB_RSA/* 4 */ +# define ERR_R_DH_LIB ERR_LIB_DH/* 5 */ +# define ERR_R_EVP_LIB ERR_LIB_EVP/* 6 */ +# define ERR_R_BUF_LIB ERR_LIB_BUF/* 7 */ +# define ERR_R_OBJ_LIB ERR_LIB_OBJ/* 8 */ +# define ERR_R_PEM_LIB ERR_LIB_PEM/* 9 */ +# define ERR_R_DSA_LIB ERR_LIB_DSA/* 10 */ +# define ERR_R_X509_LIB ERR_LIB_X509/* 11 */ +# define ERR_R_ASN1_LIB ERR_LIB_ASN1/* 13 */ +# define ERR_R_EC_LIB ERR_LIB_EC/* 16 */ +# define ERR_R_BIO_LIB ERR_LIB_BIO/* 32 */ +# define ERR_R_PKCS7_LIB ERR_LIB_PKCS7/* 33 */ +# define ERR_R_X509V3_LIB ERR_LIB_X509V3/* 34 */ +# define ERR_R_ENGINE_LIB ERR_LIB_ENGINE/* 38 */ +# define ERR_R_ECDSA_LIB ERR_LIB_ECDSA/* 42 */ + +# define ERR_R_NESTED_ASN1_ERROR 58 +# define ERR_R_MISSING_ASN1_EOS 63 + +/* fatal error */ +# define ERR_R_FATAL 64 +# define ERR_R_MALLOC_FAILURE (1|ERR_R_FATAL) +# define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2|ERR_R_FATAL) +# define ERR_R_PASSED_NULL_PARAMETER (3|ERR_R_FATAL) +# define ERR_R_INTERNAL_ERROR (4|ERR_R_FATAL) +# define ERR_R_DISABLED (5|ERR_R_FATAL) +# define ERR_R_INIT_FAIL (6|ERR_R_FATAL) +# define ERR_R_PASSED_INVALID_ARGUMENT (7) + +/* + * 99 is the maximum possible ERR_R_... code, higher values are reserved for + * the individual libraries + */ + +typedef struct ERR_string_data_st { + unsigned long error; + const char *string; +} ERR_STRING_DATA; + +DEFINE_LHASH_OF(ERR_STRING_DATA); + +void ERR_put_error(int lib, int func, int reason, const char *file, int line); +void ERR_set_error_data(char *data, int flags); + +unsigned long ERR_get_error(void); +unsigned long ERR_get_error_line(const char **file, int *line); +unsigned long ERR_get_error_line_data(const char **file, int *line, + const char **data, int *flags); +unsigned long ERR_peek_error(void); +unsigned long ERR_peek_error_line(const char **file, int *line); +unsigned long ERR_peek_error_line_data(const char **file, int *line, + const char **data, int *flags); +unsigned long ERR_peek_last_error(void); +unsigned long ERR_peek_last_error_line(const char **file, int *line); +unsigned long ERR_peek_last_error_line_data(const char **file, int *line, + const char **data, int *flags); +void ERR_clear_error(void); +char *ERR_error_string(unsigned long e, char *buf); +void ERR_error_string_n(unsigned long e, char *buf, size_t len); +const char *ERR_lib_error_string(unsigned long e); +const char *ERR_func_error_string(unsigned long e); +const char *ERR_reason_error_string(unsigned long e); +void ERR_print_errors_cb(int (*cb) (const char *str, size_t len, void *u), + void *u); +# ifndef OPENSSL_NO_STDIO +void ERR_print_errors_fp(FILE *fp); +# endif +void ERR_print_errors(BIO *bp); +void ERR_add_error_data(int num, ...); +void ERR_add_error_vdata(int num, va_list args); +int ERR_load_strings(int lib, ERR_STRING_DATA str[]); +int ERR_unload_strings(int lib, ERR_STRING_DATA str[]); +int ERR_load_ERR_strings(void); + +#if OPENSSL_API_COMPAT < 0x10100000L +# define ERR_load_crypto_strings() \ + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL) +# define ERR_free_strings() while(0) continue +#endif + +DEPRECATEDIN_1_1_0(void ERR_remove_thread_state(void *)) +DEPRECATEDIN_1_0_0(void ERR_remove_state(unsigned long pid)) +ERR_STATE *ERR_get_state(void); + +int ERR_get_next_error_library(void); + +int ERR_set_mark(void); +int ERR_pop_to_mark(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/evp.h b/mobile/ios/FxA/FxA/include/openssl/evp.h new file mode 100644 index 0000000000..01f51b7be3 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/evp.h @@ -0,0 +1,1590 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_ENVELOPE_H +# define HEADER_ENVELOPE_H + +# include +# include +# include +# include + +# define EVP_MAX_MD_SIZE 64/* longest known is SHA512 */ +# define EVP_MAX_KEY_LENGTH 64 +# define EVP_MAX_IV_LENGTH 16 +# define EVP_MAX_BLOCK_LENGTH 32 + +# define PKCS5_SALT_LEN 8 +/* Default PKCS#5 iteration count */ +# define PKCS5_DEFAULT_ITER 2048 + +# include + +# define EVP_PK_RSA 0x0001 +# define EVP_PK_DSA 0x0002 +# define EVP_PK_DH 0x0004 +# define EVP_PK_EC 0x0008 +# define EVP_PKT_SIGN 0x0010 +# define EVP_PKT_ENC 0x0020 +# define EVP_PKT_EXCH 0x0040 +# define EVP_PKS_RSA 0x0100 +# define EVP_PKS_DSA 0x0200 +# define EVP_PKS_EC 0x0400 + +# define EVP_PKEY_NONE NID_undef +# define EVP_PKEY_RSA NID_rsaEncryption +# define EVP_PKEY_RSA2 NID_rsa +# define EVP_PKEY_DSA NID_dsa +# define EVP_PKEY_DSA1 NID_dsa_2 +# define EVP_PKEY_DSA2 NID_dsaWithSHA +# define EVP_PKEY_DSA3 NID_dsaWithSHA1 +# define EVP_PKEY_DSA4 NID_dsaWithSHA1_2 +# define EVP_PKEY_DH NID_dhKeyAgreement +# define EVP_PKEY_DHX NID_dhpublicnumber +# define EVP_PKEY_EC NID_X9_62_id_ecPublicKey +# define EVP_PKEY_HMAC NID_hmac +# define EVP_PKEY_CMAC NID_cmac +# define EVP_PKEY_TLS1_PRF NID_tls1_prf +# define EVP_PKEY_HKDF NID_hkdf + +#ifdef __cplusplus +extern "C" { +#endif + +# define EVP_PKEY_MO_SIGN 0x0001 +# define EVP_PKEY_MO_VERIFY 0x0002 +# define EVP_PKEY_MO_ENCRYPT 0x0004 +# define EVP_PKEY_MO_DECRYPT 0x0008 + +# ifndef EVP_MD +EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type); +EVP_MD *EVP_MD_meth_dup(const EVP_MD *md); +void EVP_MD_meth_free(EVP_MD *md); + +int EVP_MD_meth_set_input_blocksize(EVP_MD *md, int blocksize); +int EVP_MD_meth_set_result_size(EVP_MD *md, int resultsize); +int EVP_MD_meth_set_app_datasize(EVP_MD *md, int datasize); +int EVP_MD_meth_set_flags(EVP_MD *md, unsigned long flags); +int EVP_MD_meth_set_init(EVP_MD *md, int (*init)(EVP_MD_CTX *ctx)); +int EVP_MD_meth_set_update(EVP_MD *md, int (*update)(EVP_MD_CTX *ctx, + const void *data, + size_t count)); +int EVP_MD_meth_set_final(EVP_MD *md, int (*final)(EVP_MD_CTX *ctx, + unsigned char *md)); +int EVP_MD_meth_set_copy(EVP_MD *md, int (*copy)(EVP_MD_CTX *to, + const EVP_MD_CTX *from)); +int EVP_MD_meth_set_cleanup(EVP_MD *md, int (*cleanup)(EVP_MD_CTX *ctx)); +int EVP_MD_meth_set_ctrl(EVP_MD *md, int (*ctrl)(EVP_MD_CTX *ctx, int cmd, + int p1, void *p2)); + +int EVP_MD_meth_get_input_blocksize(const EVP_MD *md); +int EVP_MD_meth_get_result_size(const EVP_MD *md); +int EVP_MD_meth_get_app_datasize(const EVP_MD *md); +unsigned long EVP_MD_meth_get_flags(const EVP_MD *md); +int (*EVP_MD_meth_get_init(const EVP_MD *md))(EVP_MD_CTX *ctx); +int (*EVP_MD_meth_get_update(const EVP_MD *md))(EVP_MD_CTX *ctx, + const void *data, + size_t count); +int (*EVP_MD_meth_get_final(const EVP_MD *md))(EVP_MD_CTX *ctx, + unsigned char *md); +int (*EVP_MD_meth_get_copy(const EVP_MD *md))(EVP_MD_CTX *to, + const EVP_MD_CTX *from); +int (*EVP_MD_meth_get_cleanup(const EVP_MD *md))(EVP_MD_CTX *ctx); +int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd, + int p1, void *p2); + +/* digest can only handle a single block */ +# define EVP_MD_FLAG_ONESHOT 0x0001 + +/* DigestAlgorithmIdentifier flags... */ + +# define EVP_MD_FLAG_DIGALGID_MASK 0x0018 + +/* NULL or absent parameter accepted. Use NULL */ + +# define EVP_MD_FLAG_DIGALGID_NULL 0x0000 + +/* NULL or absent parameter accepted. Use NULL for PKCS#1 otherwise absent */ + +# define EVP_MD_FLAG_DIGALGID_ABSENT 0x0008 + +/* Custom handling via ctrl */ + +# define EVP_MD_FLAG_DIGALGID_CUSTOM 0x0018 + +/* Note if suitable for use in FIPS mode */ +# define EVP_MD_FLAG_FIPS 0x0400 + +/* Digest ctrls */ + +# define EVP_MD_CTRL_DIGALGID 0x1 +# define EVP_MD_CTRL_MICALG 0x2 + +/* Minimum Algorithm specific ctrl value */ + +# define EVP_MD_CTRL_ALG_CTRL 0x1000 + +# endif /* !EVP_MD */ + +/* values for EVP_MD_CTX flags */ + +# define EVP_MD_CTX_FLAG_ONESHOT 0x0001/* digest update will be + * called once only */ +# define EVP_MD_CTX_FLAG_CLEANED 0x0002/* context has already been + * cleaned */ +# define EVP_MD_CTX_FLAG_REUSE 0x0004/* Don't free up ctx->md_data + * in EVP_MD_CTX_reset */ +/* + * FIPS and pad options are ignored in 1.0.0, definitions are here so we + * don't accidentally reuse the values for other purposes. + */ + +# define EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 0x0008/* Allow use of non FIPS + * digest in FIPS mode */ + +/* + * The following PAD options are also currently ignored in 1.0.0, digest + * parameters are handled through EVP_DigestSign*() and EVP_DigestVerify*() + * instead. + */ +# define EVP_MD_CTX_FLAG_PAD_MASK 0xF0/* RSA mode to use */ +# define EVP_MD_CTX_FLAG_PAD_PKCS1 0x00/* PKCS#1 v1.5 mode */ +# define EVP_MD_CTX_FLAG_PAD_X931 0x10/* X9.31 mode */ +# define EVP_MD_CTX_FLAG_PAD_PSS 0x20/* PSS mode */ + +# define EVP_MD_CTX_FLAG_NO_INIT 0x0100/* Don't initialize md_data */ +/* + * Some functions such as EVP_DigestSign only finalise copies of internal + * contexts so additional data can be included after the finalisation call. + * This is inefficient if this functionality is not required: it is disabled + * if the following flag is set. + */ +# define EVP_MD_CTX_FLAG_FINALISE 0x0200 + +EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len); +EVP_CIPHER *EVP_CIPHER_meth_dup(const EVP_CIPHER *cipher); +void EVP_CIPHER_meth_free(EVP_CIPHER *cipher); + +int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len); +int EVP_CIPHER_meth_set_flags(EVP_CIPHER *cipher, unsigned long flags); +int EVP_CIPHER_meth_set_impl_ctx_size(EVP_CIPHER *cipher, int ctx_size); +int EVP_CIPHER_meth_set_init(EVP_CIPHER *cipher, + int (*init) (EVP_CIPHER_CTX *ctx, + const unsigned char *key, + const unsigned char *iv, + int enc)); +int EVP_CIPHER_meth_set_do_cipher(EVP_CIPHER *cipher, + int (*do_cipher) (EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + size_t inl)); +int EVP_CIPHER_meth_set_cleanup(EVP_CIPHER *cipher, + int (*cleanup) (EVP_CIPHER_CTX *)); +int EVP_CIPHER_meth_set_set_asn1_params(EVP_CIPHER *cipher, + int (*set_asn1_parameters) (EVP_CIPHER_CTX *, + ASN1_TYPE *)); +int EVP_CIPHER_meth_set_get_asn1_params(EVP_CIPHER *cipher, + int (*get_asn1_parameters) (EVP_CIPHER_CTX *, + ASN1_TYPE *)); +int EVP_CIPHER_meth_set_ctrl(EVP_CIPHER *cipher, + int (*ctrl) (EVP_CIPHER_CTX *, int type, + int arg, void *ptr)); + +int (*EVP_CIPHER_meth_get_init(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx, + const unsigned char *key, + const unsigned char *iv, + int enc); +int (*EVP_CIPHER_meth_get_do_cipher(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + size_t inl); +int (*EVP_CIPHER_meth_get_cleanup(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *); +int (*EVP_CIPHER_meth_get_set_asn1_params(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *, + ASN1_TYPE *); +int (*EVP_CIPHER_meth_get_get_asn1_params(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *, + ASN1_TYPE *); +int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *, + int type, int arg, + void *ptr); + +/* Values for cipher flags */ + +/* Modes for ciphers */ + +# define EVP_CIPH_STREAM_CIPHER 0x0 +# define EVP_CIPH_ECB_MODE 0x1 +# define EVP_CIPH_CBC_MODE 0x2 +# define EVP_CIPH_CFB_MODE 0x3 +# define EVP_CIPH_OFB_MODE 0x4 +# define EVP_CIPH_CTR_MODE 0x5 +# define EVP_CIPH_GCM_MODE 0x6 +# define EVP_CIPH_CCM_MODE 0x7 +# define EVP_CIPH_XTS_MODE 0x10001 +# define EVP_CIPH_WRAP_MODE 0x10002 +# define EVP_CIPH_OCB_MODE 0x10003 +# define EVP_CIPH_MODE 0xF0007 +/* Set if variable length cipher */ +# define EVP_CIPH_VARIABLE_LENGTH 0x8 +/* Set if the iv handling should be done by the cipher itself */ +# define EVP_CIPH_CUSTOM_IV 0x10 +/* Set if the cipher's init() function should be called if key is NULL */ +# define EVP_CIPH_ALWAYS_CALL_INIT 0x20 +/* Call ctrl() to init cipher parameters */ +# define EVP_CIPH_CTRL_INIT 0x40 +/* Don't use standard key length function */ +# define EVP_CIPH_CUSTOM_KEY_LENGTH 0x80 +/* Don't use standard block padding */ +# define EVP_CIPH_NO_PADDING 0x100 +/* cipher handles random key generation */ +# define EVP_CIPH_RAND_KEY 0x200 +/* cipher has its own additional copying logic */ +# define EVP_CIPH_CUSTOM_COPY 0x400 +/* Allow use default ASN1 get/set iv */ +# define EVP_CIPH_FLAG_DEFAULT_ASN1 0x1000 +/* Buffer length in bits not bytes: CFB1 mode only */ +# define EVP_CIPH_FLAG_LENGTH_BITS 0x2000 +/* Note if suitable for use in FIPS mode */ +# define EVP_CIPH_FLAG_FIPS 0x4000 +/* Allow non FIPS cipher in FIPS mode */ +# define EVP_CIPH_FLAG_NON_FIPS_ALLOW 0x8000 +/* + * Cipher handles any and all padding logic as well as finalisation. + */ +# define EVP_CIPH_FLAG_CUSTOM_CIPHER 0x100000 +# define EVP_CIPH_FLAG_AEAD_CIPHER 0x200000 +# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0x400000 +/* Cipher can handle pipeline operations */ +# define EVP_CIPH_FLAG_PIPELINE 0X800000 + +/* + * Cipher context flag to indicate we can handle wrap mode: if allowed in + * older applications it could overflow buffers. + */ + +# define EVP_CIPHER_CTX_FLAG_WRAP_ALLOW 0x1 + +/* ctrl() values */ + +# define EVP_CTRL_INIT 0x0 +# define EVP_CTRL_SET_KEY_LENGTH 0x1 +# define EVP_CTRL_GET_RC2_KEY_BITS 0x2 +# define EVP_CTRL_SET_RC2_KEY_BITS 0x3 +# define EVP_CTRL_GET_RC5_ROUNDS 0x4 +# define EVP_CTRL_SET_RC5_ROUNDS 0x5 +# define EVP_CTRL_RAND_KEY 0x6 +# define EVP_CTRL_PBE_PRF_NID 0x7 +# define EVP_CTRL_COPY 0x8 +# define EVP_CTRL_AEAD_SET_IVLEN 0x9 +# define EVP_CTRL_AEAD_GET_TAG 0x10 +# define EVP_CTRL_AEAD_SET_TAG 0x11 +# define EVP_CTRL_AEAD_SET_IV_FIXED 0x12 +# define EVP_CTRL_GCM_SET_IVLEN EVP_CTRL_AEAD_SET_IVLEN +# define EVP_CTRL_GCM_GET_TAG EVP_CTRL_AEAD_GET_TAG +# define EVP_CTRL_GCM_SET_TAG EVP_CTRL_AEAD_SET_TAG +# define EVP_CTRL_GCM_SET_IV_FIXED EVP_CTRL_AEAD_SET_IV_FIXED +# define EVP_CTRL_GCM_IV_GEN 0x13 +# define EVP_CTRL_CCM_SET_IVLEN EVP_CTRL_AEAD_SET_IVLEN +# define EVP_CTRL_CCM_GET_TAG EVP_CTRL_AEAD_GET_TAG +# define EVP_CTRL_CCM_SET_TAG EVP_CTRL_AEAD_SET_TAG +# define EVP_CTRL_CCM_SET_IV_FIXED EVP_CTRL_AEAD_SET_IV_FIXED +# define EVP_CTRL_CCM_SET_L 0x14 +# define EVP_CTRL_CCM_SET_MSGLEN 0x15 +/* + * AEAD cipher deduces payload length and returns number of bytes required to + * store MAC and eventual padding. Subsequent call to EVP_Cipher even + * appends/verifies MAC. + */ +# define EVP_CTRL_AEAD_TLS1_AAD 0x16 +/* Used by composite AEAD ciphers, no-op in GCM, CCM... */ +# define EVP_CTRL_AEAD_SET_MAC_KEY 0x17 +/* Set the GCM invocation field, decrypt only */ +# define EVP_CTRL_GCM_SET_IV_INV 0x18 + +# define EVP_CTRL_TLS1_1_MULTIBLOCK_AAD 0x19 +# define EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT 0x1a +# define EVP_CTRL_TLS1_1_MULTIBLOCK_DECRYPT 0x1b +# define EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE 0x1c + +# define EVP_CTRL_SSL3_MASTER_SECRET 0x1d + +/* EVP_CTRL_SET_SBOX takes the char * specifying S-boxes */ +# define EVP_CTRL_SET_SBOX 0x1e +/* + * EVP_CTRL_SBOX_USED takes a 'size_t' and 'char *', pointing at a + * pre-allocated buffer with specified size + */ +# define EVP_CTRL_SBOX_USED 0x1f +/* EVP_CTRL_KEY_MESH takes 'size_t' number of bytes to mesh the key after, + * 0 switches meshing off + */ +# define EVP_CTRL_KEY_MESH 0x20 +/* EVP_CTRL_BLOCK_PADDING_MODE takes the padding mode */ +# define EVP_CTRL_BLOCK_PADDING_MODE 0x21 + +/* Set the output buffers to use for a pipelined operation */ +# define EVP_CTRL_SET_PIPELINE_OUTPUT_BUFS 0x22 +/* Set the input buffers to use for a pipelined operation */ +# define EVP_CTRL_SET_PIPELINE_INPUT_BUFS 0x23 +/* Set the input buffer lengths to use for a pipelined operation */ +# define EVP_CTRL_SET_PIPELINE_INPUT_LENS 0x24 + +/* Padding modes */ +#define EVP_PADDING_PKCS7 1 +#define EVP_PADDING_ISO7816_4 2 +#define EVP_PADDING_ANSI923 3 +#define EVP_PADDING_ISO10126 4 +#define EVP_PADDING_ZERO 5 + +/* RFC 5246 defines additional data to be 13 bytes in length */ +# define EVP_AEAD_TLS1_AAD_LEN 13 + +typedef struct { + unsigned char *out; + const unsigned char *inp; + size_t len; + unsigned int interleave; +} EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM; + +/* GCM TLS constants */ +/* Length of fixed part of IV derived from PRF */ +# define EVP_GCM_TLS_FIXED_IV_LEN 4 +/* Length of explicit part of IV part of TLS records */ +# define EVP_GCM_TLS_EXPLICIT_IV_LEN 8 +/* Length of tag for TLS */ +# define EVP_GCM_TLS_TAG_LEN 16 + +/* CCM TLS constants */ +/* Length of fixed part of IV derived from PRF */ +# define EVP_CCM_TLS_FIXED_IV_LEN 4 +/* Length of explicit part of IV part of TLS records */ +# define EVP_CCM_TLS_EXPLICIT_IV_LEN 8 + +typedef struct evp_cipher_info_st { + const EVP_CIPHER *cipher; + unsigned char iv[EVP_MAX_IV_LENGTH]; +} EVP_CIPHER_INFO; + + +/* Password based encryption function */ +typedef int (EVP_PBE_KEYGEN) (EVP_CIPHER_CTX *ctx, const char *pass, + int passlen, ASN1_TYPE *param, + const EVP_CIPHER *cipher, const EVP_MD *md, + int en_de); + +# ifndef OPENSSL_NO_RSA +# define EVP_PKEY_assign_RSA(pkey,rsa) EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\ + (char *)(rsa)) +# endif + +# ifndef OPENSSL_NO_DSA +# define EVP_PKEY_assign_DSA(pkey,dsa) EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\ + (char *)(dsa)) +# endif + +# ifndef OPENSSL_NO_DH +# define EVP_PKEY_assign_DH(pkey,dh) EVP_PKEY_assign((pkey),EVP_PKEY_DH,\ + (char *)(dh)) +# endif + +# ifndef OPENSSL_NO_EC +# define EVP_PKEY_assign_EC_KEY(pkey,eckey) EVP_PKEY_assign((pkey),EVP_PKEY_EC,\ + (char *)(eckey)) +# endif + +/* Add some extra combinations */ +# define EVP_get_digestbynid(a) EVP_get_digestbyname(OBJ_nid2sn(a)) +# define EVP_get_digestbyobj(a) EVP_get_digestbynid(OBJ_obj2nid(a)) +# define EVP_get_cipherbynid(a) EVP_get_cipherbyname(OBJ_nid2sn(a)) +# define EVP_get_cipherbyobj(a) EVP_get_cipherbynid(OBJ_obj2nid(a)) + +int EVP_MD_type(const EVP_MD *md); +# define EVP_MD_nid(e) EVP_MD_type(e) +# define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_nid(e)) +int EVP_MD_pkey_type(const EVP_MD *md); +int EVP_MD_size(const EVP_MD *md); +int EVP_MD_block_size(const EVP_MD *md); +unsigned long EVP_MD_flags(const EVP_MD *md); + +const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx); +int (*EVP_MD_CTX_update_fn(EVP_MD_CTX *ctx))(EVP_MD_CTX *ctx, + const void *data, size_t count); +void EVP_MD_CTX_set_update_fn(EVP_MD_CTX *ctx, + int (*update) (EVP_MD_CTX *ctx, + const void *data, size_t count)); +# define EVP_MD_CTX_size(e) EVP_MD_size(EVP_MD_CTX_md(e)) +# define EVP_MD_CTX_block_size(e) EVP_MD_block_size(EVP_MD_CTX_md(e)) +# define EVP_MD_CTX_type(e) EVP_MD_type(EVP_MD_CTX_md(e)) +EVP_PKEY_CTX *EVP_MD_CTX_pkey_ctx(const EVP_MD_CTX *ctx); +void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx); + +int EVP_CIPHER_nid(const EVP_CIPHER *cipher); +# define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e)) +int EVP_CIPHER_block_size(const EVP_CIPHER *cipher); +int EVP_CIPHER_impl_ctx_size(const EVP_CIPHER *cipher); +int EVP_CIPHER_key_length(const EVP_CIPHER *cipher); +int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher); +unsigned long EVP_CIPHER_flags(const EVP_CIPHER *cipher); +# define EVP_CIPHER_mode(e) (EVP_CIPHER_flags(e) & EVP_CIPH_MODE) + +const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx); +const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx); +const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx); +unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx); +unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_num(const EVP_CIPHER_CTX *ctx); +void EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num); +int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in); +void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx); +void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data); +void *EVP_CIPHER_CTX_get_cipher_data(const EVP_CIPHER_CTX *ctx); +void *EVP_CIPHER_CTX_set_cipher_data(EVP_CIPHER_CTX *ctx, void *cipher_data); +# define EVP_CIPHER_CTX_type(c) EVP_CIPHER_type(EVP_CIPHER_CTX_cipher(c)) +# if OPENSSL_API_COMPAT < 0x10100000L +# define EVP_CIPHER_CTX_flags(c) EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(c)) +# endif +# define EVP_CIPHER_CTX_mode(c) EVP_CIPHER_mode(EVP_CIPHER_CTX_cipher(c)) + +# define EVP_ENCODE_LENGTH(l) (((l+2)/3*4)+(l/48+1)*2+80) +# define EVP_DECODE_LENGTH(l) ((l+3)/4*3+80) + +# define EVP_SignInit_ex(a,b,c) EVP_DigestInit_ex(a,b,c) +# define EVP_SignInit(a,b) EVP_DigestInit(a,b) +# define EVP_SignUpdate(a,b,c) EVP_DigestUpdate(a,b,c) +# define EVP_VerifyInit_ex(a,b,c) EVP_DigestInit_ex(a,b,c) +# define EVP_VerifyInit(a,b) EVP_DigestInit(a,b) +# define EVP_VerifyUpdate(a,b,c) EVP_DigestUpdate(a,b,c) +# define EVP_OpenUpdate(a,b,c,d,e) EVP_DecryptUpdate(a,b,c,d,e) +# define EVP_SealUpdate(a,b,c,d,e) EVP_EncryptUpdate(a,b,c,d,e) +# define EVP_DigestSignUpdate(a,b,c) EVP_DigestUpdate(a,b,c) +# define EVP_DigestVerifyUpdate(a,b,c) EVP_DigestUpdate(a,b,c) + +# ifdef CONST_STRICT +void BIO_set_md(BIO *, const EVP_MD *md); +# else +# define BIO_set_md(b,md) BIO_ctrl(b,BIO_C_SET_MD,0,(char *)md) +# endif +# define BIO_get_md(b,mdp) BIO_ctrl(b,BIO_C_GET_MD,0,(char *)mdp) +# define BIO_get_md_ctx(b,mdcp) BIO_ctrl(b,BIO_C_GET_MD_CTX,0,(char *)mdcp) +# define BIO_set_md_ctx(b,mdcp) BIO_ctrl(b,BIO_C_SET_MD_CTX,0,(char *)mdcp) +# define BIO_get_cipher_status(b) BIO_ctrl(b,BIO_C_GET_CIPHER_STATUS,0,NULL) +# define BIO_get_cipher_ctx(b,c_pp) BIO_ctrl(b,BIO_C_GET_CIPHER_CTX,0,(char *)c_pp) + +/*__owur*/ int EVP_Cipher(EVP_CIPHER_CTX *c, + unsigned char *out, + const unsigned char *in, unsigned int inl); + +# define EVP_add_cipher_alias(n,alias) \ + OBJ_NAME_add((alias),OBJ_NAME_TYPE_CIPHER_METH|OBJ_NAME_ALIAS,(n)) +# define EVP_add_digest_alias(n,alias) \ + OBJ_NAME_add((alias),OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS,(n)) +# define EVP_delete_cipher_alias(alias) \ + OBJ_NAME_remove(alias,OBJ_NAME_TYPE_CIPHER_METH|OBJ_NAME_ALIAS); +# define EVP_delete_digest_alias(alias) \ + OBJ_NAME_remove(alias,OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS); + +int EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2); +EVP_MD_CTX *EVP_MD_CTX_new(void); +int EVP_MD_CTX_reset(EVP_MD_CTX *ctx); +void EVP_MD_CTX_free(EVP_MD_CTX *ctx); +# define EVP_MD_CTX_create() EVP_MD_CTX_new() +# define EVP_MD_CTX_init(ctx) EVP_MD_CTX_reset((ctx)) +# define EVP_MD_CTX_destroy(ctx) EVP_MD_CTX_free((ctx)) +__owur int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in); +void EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, int flags); +void EVP_MD_CTX_clear_flags(EVP_MD_CTX *ctx, int flags); +int EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx, int flags); +__owur int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *impl); +__owur int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, + size_t cnt); +__owur int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, + unsigned int *s); +__owur int EVP_Digest(const void *data, size_t count, + unsigned char *md, unsigned int *size, + const EVP_MD *type, ENGINE *impl); + +__owur int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in); +__owur int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); +__owur int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, + unsigned int *s); + +#ifndef OPENSSL_NO_UI +int EVP_read_pw_string(char *buf, int length, const char *prompt, int verify); +int EVP_read_pw_string_min(char *buf, int minlen, int maxlen, + const char *prompt, int verify); +void EVP_set_pw_prompt(const char *prompt); +char *EVP_get_pw_prompt(void); +#endif + +__owur int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, + const unsigned char *salt, + const unsigned char *data, int datal, int count, + unsigned char *key, unsigned char *iv); + +void EVP_CIPHER_CTX_set_flags(EVP_CIPHER_CTX *ctx, int flags); +void EVP_CIPHER_CTX_clear_flags(EVP_CIPHER_CTX *ctx, int flags); +int EVP_CIPHER_CTX_test_flags(const EVP_CIPHER_CTX *ctx, int flags); + +__owur int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv); +/*__owur*/ int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const unsigned char *key, + const unsigned char *iv); +/*__owur*/ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *outl, const unsigned char *in, int inl); +/*__owur*/ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *outl); +/*__owur*/ int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *outl); + +__owur int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv); +/*__owur*/ int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const unsigned char *key, + const unsigned char *iv); +/*__owur*/ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *outl, const unsigned char *in, int inl); +__owur int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, + int *outl); +/*__owur*/ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, + int *outl); + +__owur int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv, + int enc); +/*__owur*/ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const unsigned char *key, + const unsigned char *iv, int enc); +__owur int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *outl, const unsigned char *in, int inl); +__owur int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, + int *outl); +__owur int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, + int *outl); + +__owur int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s, + EVP_PKEY *pkey); + +__owur int EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf, + unsigned int siglen, EVP_PKEY *pkey); + +/*__owur*/ int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey); +__owur int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, + size_t *siglen); + +__owur int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey); +__owur int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig, + size_t siglen); + +# ifndef OPENSSL_NO_RSA +__owur int EVP_OpenInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, + const unsigned char *ek, int ekl, + const unsigned char *iv, EVP_PKEY *priv); +__owur int EVP_OpenFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); + +__owur int EVP_SealInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, + unsigned char **ek, int *ekl, unsigned char *iv, + EVP_PKEY **pubk, int npubk); +__owur int EVP_SealFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); +# endif + +EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void); +void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx); +int EVP_ENCODE_CTX_copy(EVP_ENCODE_CTX *dctx, EVP_ENCODE_CTX *sctx); +int EVP_ENCODE_CTX_num(EVP_ENCODE_CTX *ctx); +void EVP_EncodeInit(EVP_ENCODE_CTX *ctx); +int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, + const unsigned char *in, int inl); +void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl); +int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int n); + +void EVP_DecodeInit(EVP_ENCODE_CTX *ctx); +int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, + const unsigned char *in, int inl); +int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned + char *out, int *outl); +int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n); + +# if OPENSSL_API_COMPAT < 0x10100000L +# define EVP_CIPHER_CTX_init(c) EVP_CIPHER_CTX_reset(c) +# define EVP_CIPHER_CTX_cleanup(c) EVP_CIPHER_CTX_reset(c) +# endif +EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); +int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c); +void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *c); +int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen); +int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad); +int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr); +int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key); + +const BIO_METHOD *BIO_f_md(void); +const BIO_METHOD *BIO_f_base64(void); +const BIO_METHOD *BIO_f_cipher(void); +const BIO_METHOD *BIO_f_reliable(void); +__owur int BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k, + const unsigned char *i, int enc); + +const EVP_MD *EVP_md_null(void); +# ifndef OPENSSL_NO_MD2 +const EVP_MD *EVP_md2(void); +# endif +# ifndef OPENSSL_NO_MD4 +const EVP_MD *EVP_md4(void); +# endif +# ifndef OPENSSL_NO_MD5 +const EVP_MD *EVP_md5(void); +const EVP_MD *EVP_md5_sha1(void); +# endif +# ifndef OPENSSL_NO_BLAKE2 +const EVP_MD *EVP_blake2b512(void); +const EVP_MD *EVP_blake2s256(void); +# endif +const EVP_MD *EVP_sha1(void); +const EVP_MD *EVP_sha224(void); +const EVP_MD *EVP_sha256(void); +const EVP_MD *EVP_sha384(void); +const EVP_MD *EVP_sha512(void); +# ifndef OPENSSL_NO_MDC2 +const EVP_MD *EVP_mdc2(void); +# endif +# ifndef OPENSSL_NO_RMD160 +const EVP_MD *EVP_ripemd160(void); +# endif +# ifndef OPENSSL_NO_WHIRLPOOL +const EVP_MD *EVP_whirlpool(void); +# endif +const EVP_CIPHER *EVP_enc_null(void); /* does nothing :-) */ +# ifndef OPENSSL_NO_DES +const EVP_CIPHER *EVP_des_ecb(void); +const EVP_CIPHER *EVP_des_ede(void); +const EVP_CIPHER *EVP_des_ede3(void); +const EVP_CIPHER *EVP_des_ede_ecb(void); +const EVP_CIPHER *EVP_des_ede3_ecb(void); +const EVP_CIPHER *EVP_des_cfb64(void); +# define EVP_des_cfb EVP_des_cfb64 +const EVP_CIPHER *EVP_des_cfb1(void); +const EVP_CIPHER *EVP_des_cfb8(void); +const EVP_CIPHER *EVP_des_ede_cfb64(void); +# define EVP_des_ede_cfb EVP_des_ede_cfb64 +const EVP_CIPHER *EVP_des_ede3_cfb64(void); +# define EVP_des_ede3_cfb EVP_des_ede3_cfb64 +const EVP_CIPHER *EVP_des_ede3_cfb1(void); +const EVP_CIPHER *EVP_des_ede3_cfb8(void); +const EVP_CIPHER *EVP_des_ofb(void); +const EVP_CIPHER *EVP_des_ede_ofb(void); +const EVP_CIPHER *EVP_des_ede3_ofb(void); +const EVP_CIPHER *EVP_des_cbc(void); +const EVP_CIPHER *EVP_des_ede_cbc(void); +const EVP_CIPHER *EVP_des_ede3_cbc(void); +const EVP_CIPHER *EVP_desx_cbc(void); +const EVP_CIPHER *EVP_des_ede3_wrap(void); +/* + * This should now be supported through the dev_crypto ENGINE. But also, why + * are rc4 and md5 declarations made here inside a "NO_DES" precompiler + * branch? + */ +# endif +# ifndef OPENSSL_NO_RC4 +const EVP_CIPHER *EVP_rc4(void); +const EVP_CIPHER *EVP_rc4_40(void); +# ifndef OPENSSL_NO_MD5 +const EVP_CIPHER *EVP_rc4_hmac_md5(void); +# endif +# endif +# ifndef OPENSSL_NO_IDEA +const EVP_CIPHER *EVP_idea_ecb(void); +const EVP_CIPHER *EVP_idea_cfb64(void); +# define EVP_idea_cfb EVP_idea_cfb64 +const EVP_CIPHER *EVP_idea_ofb(void); +const EVP_CIPHER *EVP_idea_cbc(void); +# endif +# ifndef OPENSSL_NO_RC2 +const EVP_CIPHER *EVP_rc2_ecb(void); +const EVP_CIPHER *EVP_rc2_cbc(void); +const EVP_CIPHER *EVP_rc2_40_cbc(void); +const EVP_CIPHER *EVP_rc2_64_cbc(void); +const EVP_CIPHER *EVP_rc2_cfb64(void); +# define EVP_rc2_cfb EVP_rc2_cfb64 +const EVP_CIPHER *EVP_rc2_ofb(void); +# endif +# ifndef OPENSSL_NO_BF +const EVP_CIPHER *EVP_bf_ecb(void); +const EVP_CIPHER *EVP_bf_cbc(void); +const EVP_CIPHER *EVP_bf_cfb64(void); +# define EVP_bf_cfb EVP_bf_cfb64 +const EVP_CIPHER *EVP_bf_ofb(void); +# endif +# ifndef OPENSSL_NO_CAST +const EVP_CIPHER *EVP_cast5_ecb(void); +const EVP_CIPHER *EVP_cast5_cbc(void); +const EVP_CIPHER *EVP_cast5_cfb64(void); +# define EVP_cast5_cfb EVP_cast5_cfb64 +const EVP_CIPHER *EVP_cast5_ofb(void); +# endif +# ifndef OPENSSL_NO_RC5 +const EVP_CIPHER *EVP_rc5_32_12_16_cbc(void); +const EVP_CIPHER *EVP_rc5_32_12_16_ecb(void); +const EVP_CIPHER *EVP_rc5_32_12_16_cfb64(void); +# define EVP_rc5_32_12_16_cfb EVP_rc5_32_12_16_cfb64 +const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void); +# endif +const EVP_CIPHER *EVP_aes_128_ecb(void); +const EVP_CIPHER *EVP_aes_128_cbc(void); +const EVP_CIPHER *EVP_aes_128_cfb1(void); +const EVP_CIPHER *EVP_aes_128_cfb8(void); +const EVP_CIPHER *EVP_aes_128_cfb128(void); +# define EVP_aes_128_cfb EVP_aes_128_cfb128 +const EVP_CIPHER *EVP_aes_128_ofb(void); +const EVP_CIPHER *EVP_aes_128_ctr(void); +const EVP_CIPHER *EVP_aes_128_ccm(void); +const EVP_CIPHER *EVP_aes_128_gcm(void); +const EVP_CIPHER *EVP_aes_128_xts(void); +const EVP_CIPHER *EVP_aes_128_wrap(void); +const EVP_CIPHER *EVP_aes_128_wrap_pad(void); +# ifndef OPENSSL_NO_OCB +const EVP_CIPHER *EVP_aes_128_ocb(void); +# endif +const EVP_CIPHER *EVP_aes_192_ecb(void); +const EVP_CIPHER *EVP_aes_192_cbc(void); +const EVP_CIPHER *EVP_aes_192_cfb1(void); +const EVP_CIPHER *EVP_aes_192_cfb8(void); +const EVP_CIPHER *EVP_aes_192_cfb128(void); +# define EVP_aes_192_cfb EVP_aes_192_cfb128 +const EVP_CIPHER *EVP_aes_192_ofb(void); +const EVP_CIPHER *EVP_aes_192_ctr(void); +const EVP_CIPHER *EVP_aes_192_ccm(void); +const EVP_CIPHER *EVP_aes_192_gcm(void); +const EVP_CIPHER *EVP_aes_192_wrap(void); +const EVP_CIPHER *EVP_aes_192_wrap_pad(void); +# ifndef OPENSSL_NO_OCB +const EVP_CIPHER *EVP_aes_192_ocb(void); +# endif +const EVP_CIPHER *EVP_aes_256_ecb(void); +const EVP_CIPHER *EVP_aes_256_cbc(void); +const EVP_CIPHER *EVP_aes_256_cfb1(void); +const EVP_CIPHER *EVP_aes_256_cfb8(void); +const EVP_CIPHER *EVP_aes_256_cfb128(void); +# define EVP_aes_256_cfb EVP_aes_256_cfb128 +const EVP_CIPHER *EVP_aes_256_ofb(void); +const EVP_CIPHER *EVP_aes_256_ctr(void); +const EVP_CIPHER *EVP_aes_256_ccm(void); +const EVP_CIPHER *EVP_aes_256_gcm(void); +const EVP_CIPHER *EVP_aes_256_xts(void); +const EVP_CIPHER *EVP_aes_256_wrap(void); +const EVP_CIPHER *EVP_aes_256_wrap_pad(void); +# ifndef OPENSSL_NO_OCB +const EVP_CIPHER *EVP_aes_256_ocb(void); +# endif +const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void); +const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void); +const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha256(void); +const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha256(void); +# ifndef OPENSSL_NO_CAMELLIA +const EVP_CIPHER *EVP_camellia_128_ecb(void); +const EVP_CIPHER *EVP_camellia_128_cbc(void); +const EVP_CIPHER *EVP_camellia_128_cfb1(void); +const EVP_CIPHER *EVP_camellia_128_cfb8(void); +const EVP_CIPHER *EVP_camellia_128_cfb128(void); +# define EVP_camellia_128_cfb EVP_camellia_128_cfb128 +const EVP_CIPHER *EVP_camellia_128_ofb(void); +const EVP_CIPHER *EVP_camellia_128_ctr(void); +const EVP_CIPHER *EVP_camellia_192_ecb(void); +const EVP_CIPHER *EVP_camellia_192_cbc(void); +const EVP_CIPHER *EVP_camellia_192_cfb1(void); +const EVP_CIPHER *EVP_camellia_192_cfb8(void); +const EVP_CIPHER *EVP_camellia_192_cfb128(void); +# define EVP_camellia_192_cfb EVP_camellia_192_cfb128 +const EVP_CIPHER *EVP_camellia_192_ofb(void); +const EVP_CIPHER *EVP_camellia_192_ctr(void); +const EVP_CIPHER *EVP_camellia_256_ecb(void); +const EVP_CIPHER *EVP_camellia_256_cbc(void); +const EVP_CIPHER *EVP_camellia_256_cfb1(void); +const EVP_CIPHER *EVP_camellia_256_cfb8(void); +const EVP_CIPHER *EVP_camellia_256_cfb128(void); +# define EVP_camellia_256_cfb EVP_camellia_256_cfb128 +const EVP_CIPHER *EVP_camellia_256_ofb(void); +const EVP_CIPHER *EVP_camellia_256_ctr(void); +# endif +# ifndef OPENSSL_NO_CHACHA +const EVP_CIPHER *EVP_chacha20(void); +# ifndef OPENSSL_NO_POLY1305 +const EVP_CIPHER *EVP_chacha20_poly1305(void); +# endif +# endif + +# ifndef OPENSSL_NO_SEED +const EVP_CIPHER *EVP_seed_ecb(void); +const EVP_CIPHER *EVP_seed_cbc(void); +const EVP_CIPHER *EVP_seed_cfb128(void); +# define EVP_seed_cfb EVP_seed_cfb128 +const EVP_CIPHER *EVP_seed_ofb(void); +# endif + +# if OPENSSL_API_COMPAT < 0x10100000L +# define OPENSSL_add_all_algorithms_conf() \ + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \ + | OPENSSL_INIT_ADD_ALL_DIGESTS \ + | OPENSSL_INIT_LOAD_CONFIG, NULL) +# define OPENSSL_add_all_algorithms_noconf() \ + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \ + | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL) + +# ifdef OPENSSL_LOAD_CONF +# define OpenSSL_add_all_algorithms() \ + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \ + | OPENSSL_INIT_ADD_ALL_DIGESTS \ + | OPENSSL_INIT_LOAD_CONFIG, NULL) +# else +# define OpenSSL_add_all_algorithms() \ + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \ + | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL) +# endif + +# define OpenSSL_add_all_ciphers() \ + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL) +# define OpenSSL_add_all_digests() \ + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL) + +# define EVP_cleanup() while(0) continue +# endif + +int EVP_add_cipher(const EVP_CIPHER *cipher); +int EVP_add_digest(const EVP_MD *digest); + +const EVP_CIPHER *EVP_get_cipherbyname(const char *name); +const EVP_MD *EVP_get_digestbyname(const char *name); + +void EVP_CIPHER_do_all(void (*fn) (const EVP_CIPHER *ciph, + const char *from, const char *to, void *x), + void *arg); +void EVP_CIPHER_do_all_sorted(void (*fn) + (const EVP_CIPHER *ciph, const char *from, + const char *to, void *x), void *arg); + +void EVP_MD_do_all(void (*fn) (const EVP_MD *ciph, + const char *from, const char *to, void *x), + void *arg); +void EVP_MD_do_all_sorted(void (*fn) + (const EVP_MD *ciph, const char *from, + const char *to, void *x), void *arg); + +int EVP_PKEY_decrypt_old(unsigned char *dec_key, + const unsigned char *enc_key, int enc_key_len, + EVP_PKEY *private_key); +int EVP_PKEY_encrypt_old(unsigned char *enc_key, + const unsigned char *key, int key_len, + EVP_PKEY *pub_key); +int EVP_PKEY_type(int type); +int EVP_PKEY_id(const EVP_PKEY *pkey); +int EVP_PKEY_base_id(const EVP_PKEY *pkey); +int EVP_PKEY_bits(const EVP_PKEY *pkey); +int EVP_PKEY_security_bits(const EVP_PKEY *pkey); +int EVP_PKEY_size(EVP_PKEY *pkey); +int EVP_PKEY_set_type(EVP_PKEY *pkey, int type); +int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len); +int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key); +void *EVP_PKEY_get0(const EVP_PKEY *pkey); +const unsigned char *EVP_PKEY_get0_hmac(const EVP_PKEY *pkey, size_t *len); + +# ifndef OPENSSL_NO_RSA +struct rsa_st; +int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key); +struct rsa_st *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); +struct rsa_st *EVP_PKEY_get1_RSA(EVP_PKEY *pkey); +# endif +# ifndef OPENSSL_NO_DSA +struct dsa_st; +int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, struct dsa_st *key); +struct dsa_st *EVP_PKEY_get0_DSA(EVP_PKEY *pkey); +struct dsa_st *EVP_PKEY_get1_DSA(EVP_PKEY *pkey); +# endif +# ifndef OPENSSL_NO_DH +struct dh_st; +int EVP_PKEY_set1_DH(EVP_PKEY *pkey, struct dh_st *key); +struct dh_st *EVP_PKEY_get0_DH(EVP_PKEY *pkey); +struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey); +# endif +# ifndef OPENSSL_NO_EC +struct ec_key_st; +int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, struct ec_key_st *key); +struct ec_key_st *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey); +struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); +# endif + +EVP_PKEY *EVP_PKEY_new(void); +int EVP_PKEY_up_ref(EVP_PKEY *pkey); +void EVP_PKEY_free(EVP_PKEY *pkey); + +EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp, + long length); +int i2d_PublicKey(EVP_PKEY *a, unsigned char **pp); + +EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp, + long length); +EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp, + long length); +int i2d_PrivateKey(EVP_PKEY *a, unsigned char **pp); + +int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from); +int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey); +int EVP_PKEY_save_parameters(EVP_PKEY *pkey, int mode); +int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b); + +int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b); + +int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); +int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); +int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + +int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid); + +int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey, + const unsigned char *pt, size_t ptlen); +size_t EVP_PKEY_get1_tls_encodedpoint(EVP_PKEY *pkey, unsigned char **ppt); + +int EVP_CIPHER_type(const EVP_CIPHER *ctx); + +/* calls methods */ +int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type); +int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type); + +/* These are used by EVP_CIPHER methods */ +int EVP_CIPHER_set_asn1_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type); +int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type); + +/* PKCS5 password based encryption */ +int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, + const EVP_MD *md, int en_de); +int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + int keylen, unsigned char *out); +int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + const EVP_MD *digest, int keylen, unsigned char *out); +int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, + const EVP_MD *md, int en_de); + +#ifndef OPENSSL_NO_SCRYPT +int EVP_PBE_scrypt(const char *pass, size_t passlen, + const unsigned char *salt, size_t saltlen, + uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem, + unsigned char *key, size_t keylen); + +int PKCS5_v2_scrypt_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, + int passlen, ASN1_TYPE *param, + const EVP_CIPHER *c, const EVP_MD *md, int en_de); +#endif + +void PKCS5_PBE_add(void); + +int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen, + ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de); + +/* PBE type */ + +/* Can appear as the outermost AlgorithmIdentifier */ +# define EVP_PBE_TYPE_OUTER 0x0 +/* Is an PRF type OID */ +# define EVP_PBE_TYPE_PRF 0x1 +/* Is a PKCS#5 v2.0 KDF */ +# define EVP_PBE_TYPE_KDF 0x2 + +int EVP_PBE_alg_add_type(int pbe_type, int pbe_nid, int cipher_nid, + int md_nid, EVP_PBE_KEYGEN *keygen); +int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md, + EVP_PBE_KEYGEN *keygen); +int EVP_PBE_find(int type, int pbe_nid, int *pcnid, int *pmnid, + EVP_PBE_KEYGEN **pkeygen); +void EVP_PBE_cleanup(void); +int EVP_PBE_get(int *ptype, int *ppbe_nid, size_t num); + +# define ASN1_PKEY_ALIAS 0x1 +# define ASN1_PKEY_DYNAMIC 0x2 +# define ASN1_PKEY_SIGPARAM_NULL 0x4 + +# define ASN1_PKEY_CTRL_PKCS7_SIGN 0x1 +# define ASN1_PKEY_CTRL_PKCS7_ENCRYPT 0x2 +# define ASN1_PKEY_CTRL_DEFAULT_MD_NID 0x3 +# define ASN1_PKEY_CTRL_CMS_SIGN 0x5 +# define ASN1_PKEY_CTRL_CMS_ENVELOPE 0x7 +# define ASN1_PKEY_CTRL_CMS_RI_TYPE 0x8 + +# define ASN1_PKEY_CTRL_SET1_TLS_ENCPT 0x9 +# define ASN1_PKEY_CTRL_GET1_TLS_ENCPT 0xa + +int EVP_PKEY_asn1_get_count(void); +const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx); +const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pe, int type); +const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pe, + const char *str, int len); +int EVP_PKEY_asn1_add0(const EVP_PKEY_ASN1_METHOD *ameth); +int EVP_PKEY_asn1_add_alias(int to, int from); +int EVP_PKEY_asn1_get0_info(int *ppkey_id, int *pkey_base_id, + int *ppkey_flags, const char **pinfo, + const char **ppem_str, + const EVP_PKEY_ASN1_METHOD *ameth); + +const EVP_PKEY_ASN1_METHOD *EVP_PKEY_get0_asn1(const EVP_PKEY *pkey); +EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_new(int id, int flags, + const char *pem_str, + const char *info); +void EVP_PKEY_asn1_copy(EVP_PKEY_ASN1_METHOD *dst, + const EVP_PKEY_ASN1_METHOD *src); +void EVP_PKEY_asn1_free(EVP_PKEY_ASN1_METHOD *ameth); +void EVP_PKEY_asn1_set_public(EVP_PKEY_ASN1_METHOD *ameth, + int (*pub_decode) (EVP_PKEY *pk, + X509_PUBKEY *pub), + int (*pub_encode) (X509_PUBKEY *pub, + const EVP_PKEY *pk), + int (*pub_cmp) (const EVP_PKEY *a, + const EVP_PKEY *b), + int (*pub_print) (BIO *out, + const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx), + int (*pkey_size) (const EVP_PKEY *pk), + int (*pkey_bits) (const EVP_PKEY *pk)); +void EVP_PKEY_asn1_set_private(EVP_PKEY_ASN1_METHOD *ameth, + int (*priv_decode) (EVP_PKEY *pk, + const PKCS8_PRIV_KEY_INFO + *p8inf), + int (*priv_encode) (PKCS8_PRIV_KEY_INFO *p8, + const EVP_PKEY *pk), + int (*priv_print) (BIO *out, + const EVP_PKEY *pkey, + int indent, + ASN1_PCTX *pctx)); +void EVP_PKEY_asn1_set_param(EVP_PKEY_ASN1_METHOD *ameth, + int (*param_decode) (EVP_PKEY *pkey, + const unsigned char **pder, + int derlen), + int (*param_encode) (const EVP_PKEY *pkey, + unsigned char **pder), + int (*param_missing) (const EVP_PKEY *pk), + int (*param_copy) (EVP_PKEY *to, + const EVP_PKEY *from), + int (*param_cmp) (const EVP_PKEY *a, + const EVP_PKEY *b), + int (*param_print) (BIO *out, + const EVP_PKEY *pkey, + int indent, + ASN1_PCTX *pctx)); + +void EVP_PKEY_asn1_set_free(EVP_PKEY_ASN1_METHOD *ameth, + void (*pkey_free) (EVP_PKEY *pkey)); +void EVP_PKEY_asn1_set_ctrl(EVP_PKEY_ASN1_METHOD *ameth, + int (*pkey_ctrl) (EVP_PKEY *pkey, int op, + long arg1, void *arg2)); +void EVP_PKEY_asn1_set_item(EVP_PKEY_ASN1_METHOD *ameth, + int (*item_verify) (EVP_MD_CTX *ctx, + const ASN1_ITEM *it, + void *asn, + X509_ALGOR *a, + ASN1_BIT_STRING *sig, + EVP_PKEY *pkey), + int (*item_sign) (EVP_MD_CTX *ctx, + const ASN1_ITEM *it, + void *asn, + X509_ALGOR *alg1, + X509_ALGOR *alg2, + ASN1_BIT_STRING *sig)); + +void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth, + int (*pkey_security_bits) (const EVP_PKEY + *pk)); + +# define EVP_PKEY_OP_UNDEFINED 0 +# define EVP_PKEY_OP_PARAMGEN (1<<1) +# define EVP_PKEY_OP_KEYGEN (1<<2) +# define EVP_PKEY_OP_SIGN (1<<3) +# define EVP_PKEY_OP_VERIFY (1<<4) +# define EVP_PKEY_OP_VERIFYRECOVER (1<<5) +# define EVP_PKEY_OP_SIGNCTX (1<<6) +# define EVP_PKEY_OP_VERIFYCTX (1<<7) +# define EVP_PKEY_OP_ENCRYPT (1<<8) +# define EVP_PKEY_OP_DECRYPT (1<<9) +# define EVP_PKEY_OP_DERIVE (1<<10) + +# define EVP_PKEY_OP_TYPE_SIG \ + (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER \ + | EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX) + +# define EVP_PKEY_OP_TYPE_CRYPT \ + (EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT) + +# define EVP_PKEY_OP_TYPE_NOGEN \ + (EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT | EVP_PKEY_OP_DERIVE) + +# define EVP_PKEY_OP_TYPE_GEN \ + (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN) + +# define EVP_PKEY_CTX_set_signature_md(ctx, md) \ + EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, \ + EVP_PKEY_CTRL_MD, 0, (void *)md) + +# define EVP_PKEY_CTX_get_signature_md(ctx, pmd) \ + EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, \ + EVP_PKEY_CTRL_GET_MD, 0, (void *)pmd) + +# define EVP_PKEY_CTX_set_mac_key(ctx, key, len) \ + EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_SET_MAC_KEY, len, (void *)key) + +# define EVP_PKEY_CTRL_MD 1 +# define EVP_PKEY_CTRL_PEER_KEY 2 + +# define EVP_PKEY_CTRL_PKCS7_ENCRYPT 3 +# define EVP_PKEY_CTRL_PKCS7_DECRYPT 4 + +# define EVP_PKEY_CTRL_PKCS7_SIGN 5 + +# define EVP_PKEY_CTRL_SET_MAC_KEY 6 + +# define EVP_PKEY_CTRL_DIGESTINIT 7 + +/* Used by GOST key encryption in TLS */ +# define EVP_PKEY_CTRL_SET_IV 8 + +# define EVP_PKEY_CTRL_CMS_ENCRYPT 9 +# define EVP_PKEY_CTRL_CMS_DECRYPT 10 +# define EVP_PKEY_CTRL_CMS_SIGN 11 + +# define EVP_PKEY_CTRL_CIPHER 12 + +# define EVP_PKEY_CTRL_GET_MD 13 + +# define EVP_PKEY_ALG_CTRL 0x1000 + +# define EVP_PKEY_FLAG_AUTOARGLEN 2 +/* + * Method handles all operations: don't assume any digest related defaults. + */ +# define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4 + +const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type); +EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags); +void EVP_PKEY_meth_get0_info(int *ppkey_id, int *pflags, + const EVP_PKEY_METHOD *meth); +void EVP_PKEY_meth_copy(EVP_PKEY_METHOD *dst, const EVP_PKEY_METHOD *src); +void EVP_PKEY_meth_free(EVP_PKEY_METHOD *pmeth); +int EVP_PKEY_meth_add0(const EVP_PKEY_METHOD *pmeth); + +EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e); +EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e); +EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx); +void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx); + +int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, + int cmd, int p1, void *p2); +int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, + const char *value); + +int EVP_PKEY_CTX_str2ctrl(EVP_PKEY_CTX *ctx, int cmd, const char *str); +int EVP_PKEY_CTX_hex2ctrl(EVP_PKEY_CTX *ctx, int cmd, const char *hex); + +int EVP_PKEY_CTX_get_operation(EVP_PKEY_CTX *ctx); +void EVP_PKEY_CTX_set0_keygen_info(EVP_PKEY_CTX *ctx, int *dat, int datlen); + +EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e, + const unsigned char *key, int keylen); + +void EVP_PKEY_CTX_set_data(EVP_PKEY_CTX *ctx, void *data); +void *EVP_PKEY_CTX_get_data(EVP_PKEY_CTX *ctx); +EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx); + +EVP_PKEY *EVP_PKEY_CTX_get0_peerkey(EVP_PKEY_CTX *ctx); + +void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data); +void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx); + +int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen); +int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen); +int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, + unsigned char *rout, size_t *routlen, + const unsigned char *sig, size_t siglen); +int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen); +int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen); + +int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer); +int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen); + +typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx); + +int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); +int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx); +int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); + +void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb); +EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx); + +int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx); + +void EVP_PKEY_meth_set_init(EVP_PKEY_METHOD *pmeth, + int (*init) (EVP_PKEY_CTX *ctx)); + +void EVP_PKEY_meth_set_copy(EVP_PKEY_METHOD *pmeth, + int (*copy) (EVP_PKEY_CTX *dst, + EVP_PKEY_CTX *src)); + +void EVP_PKEY_meth_set_cleanup(EVP_PKEY_METHOD *pmeth, + void (*cleanup) (EVP_PKEY_CTX *ctx)); + +void EVP_PKEY_meth_set_paramgen(EVP_PKEY_METHOD *pmeth, + int (*paramgen_init) (EVP_PKEY_CTX *ctx), + int (*paramgen) (EVP_PKEY_CTX *ctx, + EVP_PKEY *pkey)); + +void EVP_PKEY_meth_set_keygen(EVP_PKEY_METHOD *pmeth, + int (*keygen_init) (EVP_PKEY_CTX *ctx), + int (*keygen) (EVP_PKEY_CTX *ctx, + EVP_PKEY *pkey)); + +void EVP_PKEY_meth_set_sign(EVP_PKEY_METHOD *pmeth, + int (*sign_init) (EVP_PKEY_CTX *ctx), + int (*sign) (EVP_PKEY_CTX *ctx, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, + size_t tbslen)); + +void EVP_PKEY_meth_set_verify(EVP_PKEY_METHOD *pmeth, + int (*verify_init) (EVP_PKEY_CTX *ctx), + int (*verify) (EVP_PKEY_CTX *ctx, + const unsigned char *sig, + size_t siglen, + const unsigned char *tbs, + size_t tbslen)); + +void EVP_PKEY_meth_set_verify_recover(EVP_PKEY_METHOD *pmeth, + int (*verify_recover_init) (EVP_PKEY_CTX + *ctx), + int (*verify_recover) (EVP_PKEY_CTX + *ctx, + unsigned char + *sig, + size_t *siglen, + const unsigned + char *tbs, + size_t tbslen)); + +void EVP_PKEY_meth_set_signctx(EVP_PKEY_METHOD *pmeth, + int (*signctx_init) (EVP_PKEY_CTX *ctx, + EVP_MD_CTX *mctx), + int (*signctx) (EVP_PKEY_CTX *ctx, + unsigned char *sig, + size_t *siglen, + EVP_MD_CTX *mctx)); + +void EVP_PKEY_meth_set_verifyctx(EVP_PKEY_METHOD *pmeth, + int (*verifyctx_init) (EVP_PKEY_CTX *ctx, + EVP_MD_CTX *mctx), + int (*verifyctx) (EVP_PKEY_CTX *ctx, + const unsigned char *sig, + int siglen, + EVP_MD_CTX *mctx)); + +void EVP_PKEY_meth_set_encrypt(EVP_PKEY_METHOD *pmeth, + int (*encrypt_init) (EVP_PKEY_CTX *ctx), + int (*encryptfn) (EVP_PKEY_CTX *ctx, + unsigned char *out, + size_t *outlen, + const unsigned char *in, + size_t inlen)); + +void EVP_PKEY_meth_set_decrypt(EVP_PKEY_METHOD *pmeth, + int (*decrypt_init) (EVP_PKEY_CTX *ctx), + int (*decrypt) (EVP_PKEY_CTX *ctx, + unsigned char *out, + size_t *outlen, + const unsigned char *in, + size_t inlen)); + +void EVP_PKEY_meth_set_derive(EVP_PKEY_METHOD *pmeth, + int (*derive_init) (EVP_PKEY_CTX *ctx), + int (*derive) (EVP_PKEY_CTX *ctx, + unsigned char *key, + size_t *keylen)); + +void EVP_PKEY_meth_set_ctrl(EVP_PKEY_METHOD *pmeth, + int (*ctrl) (EVP_PKEY_CTX *ctx, int type, int p1, + void *p2), + int (*ctrl_str) (EVP_PKEY_CTX *ctx, + const char *type, + const char *value)); + +void EVP_PKEY_meth_get_init(EVP_PKEY_METHOD *pmeth, + int (**pinit) (EVP_PKEY_CTX *ctx)); + +void EVP_PKEY_meth_get_copy(EVP_PKEY_METHOD *pmeth, + int (**pcopy) (EVP_PKEY_CTX *dst, + EVP_PKEY_CTX *src)); + +void EVP_PKEY_meth_get_cleanup(EVP_PKEY_METHOD *pmeth, + void (**pcleanup) (EVP_PKEY_CTX *ctx)); + +void EVP_PKEY_meth_get_paramgen(EVP_PKEY_METHOD *pmeth, + int (**pparamgen_init) (EVP_PKEY_CTX *ctx), + int (**pparamgen) (EVP_PKEY_CTX *ctx, + EVP_PKEY *pkey)); + +void EVP_PKEY_meth_get_keygen(EVP_PKEY_METHOD *pmeth, + int (**pkeygen_init) (EVP_PKEY_CTX *ctx), + int (**pkeygen) (EVP_PKEY_CTX *ctx, + EVP_PKEY *pkey)); + +void EVP_PKEY_meth_get_sign(EVP_PKEY_METHOD *pmeth, + int (**psign_init) (EVP_PKEY_CTX *ctx), + int (**psign) (EVP_PKEY_CTX *ctx, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, + size_t tbslen)); + +void EVP_PKEY_meth_get_verify(EVP_PKEY_METHOD *pmeth, + int (**pverify_init) (EVP_PKEY_CTX *ctx), + int (**pverify) (EVP_PKEY_CTX *ctx, + const unsigned char *sig, + size_t siglen, + const unsigned char *tbs, + size_t tbslen)); + +void EVP_PKEY_meth_get_verify_recover(EVP_PKEY_METHOD *pmeth, + int (**pverify_recover_init) (EVP_PKEY_CTX + *ctx), + int (**pverify_recover) (EVP_PKEY_CTX + *ctx, + unsigned char + *sig, + size_t *siglen, + const unsigned + char *tbs, + size_t tbslen)); + +void EVP_PKEY_meth_get_signctx(EVP_PKEY_METHOD *pmeth, + int (**psignctx_init) (EVP_PKEY_CTX *ctx, + EVP_MD_CTX *mctx), + int (**psignctx) (EVP_PKEY_CTX *ctx, + unsigned char *sig, + size_t *siglen, + EVP_MD_CTX *mctx)); + +void EVP_PKEY_meth_get_verifyctx(EVP_PKEY_METHOD *pmeth, + int (**pverifyctx_init) (EVP_PKEY_CTX *ctx, + EVP_MD_CTX *mctx), + int (**pverifyctx) (EVP_PKEY_CTX *ctx, + const unsigned char *sig, + int siglen, + EVP_MD_CTX *mctx)); + +void EVP_PKEY_meth_get_encrypt(EVP_PKEY_METHOD *pmeth, + int (**pencrypt_init) (EVP_PKEY_CTX *ctx), + int (**pencryptfn) (EVP_PKEY_CTX *ctx, + unsigned char *out, + size_t *outlen, + const unsigned char *in, + size_t inlen)); + +void EVP_PKEY_meth_get_decrypt(EVP_PKEY_METHOD *pmeth, + int (**pdecrypt_init) (EVP_PKEY_CTX *ctx), + int (**pdecrypt) (EVP_PKEY_CTX *ctx, + unsigned char *out, + size_t *outlen, + const unsigned char *in, + size_t inlen)); + +void EVP_PKEY_meth_get_derive(EVP_PKEY_METHOD *pmeth, + int (**pderive_init) (EVP_PKEY_CTX *ctx), + int (**pderive) (EVP_PKEY_CTX *ctx, + unsigned char *key, + size_t *keylen)); + +void EVP_PKEY_meth_get_ctrl(EVP_PKEY_METHOD *pmeth, + int (**pctrl) (EVP_PKEY_CTX *ctx, int type, int p1, + void *p2), + int (**pctrl_str) (EVP_PKEY_CTX *ctx, + const char *type, + const char *value)); + +void EVP_add_alg_module(void); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_EVP_strings(void); + +/* Error codes for the EVP functions. */ + +/* Function codes. */ +# define EVP_F_AESNI_INIT_KEY 165 +# define EVP_F_AES_INIT_KEY 133 +# define EVP_F_AES_OCB_CIPHER 169 +# define EVP_F_AES_T4_INIT_KEY 178 +# define EVP_F_AES_WRAP_CIPHER 170 +# define EVP_F_ALG_MODULE_INIT 177 +# define EVP_F_CAMELLIA_INIT_KEY 159 +# define EVP_F_CHACHA20_POLY1305_CTRL 182 +# define EVP_F_CMLL_T4_INIT_KEY 179 +# define EVP_F_DES_EDE3_WRAP_CIPHER 171 +# define EVP_F_DO_SIGVER_INIT 161 +# define EVP_F_EVP_CIPHERINIT_EX 123 +# define EVP_F_EVP_CIPHER_CTX_COPY 163 +# define EVP_F_EVP_CIPHER_CTX_CTRL 124 +# define EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH 122 +# define EVP_F_EVP_DECRYPTFINAL_EX 101 +# define EVP_F_EVP_DECRYPTUPDATE 166 +# define EVP_F_EVP_DIGESTINIT_EX 128 +# define EVP_F_EVP_ENCRYPTFINAL_EX 127 +# define EVP_F_EVP_ENCRYPTUPDATE 167 +# define EVP_F_EVP_MD_CTX_COPY_EX 110 +# define EVP_F_EVP_MD_SIZE 162 +# define EVP_F_EVP_OPENINIT 102 +# define EVP_F_EVP_PBE_ALG_ADD 115 +# define EVP_F_EVP_PBE_ALG_ADD_TYPE 160 +# define EVP_F_EVP_PBE_CIPHERINIT 116 +# define EVP_F_EVP_PBE_SCRYPT 181 +# define EVP_F_EVP_PKCS82PKEY 111 +# define EVP_F_EVP_PKEY2PKCS8 113 +# define EVP_F_EVP_PKEY_COPY_PARAMETERS 103 +# define EVP_F_EVP_PKEY_CTX_CTRL 137 +# define EVP_F_EVP_PKEY_CTX_CTRL_STR 150 +# define EVP_F_EVP_PKEY_CTX_DUP 156 +# define EVP_F_EVP_PKEY_DECRYPT 104 +# define EVP_F_EVP_PKEY_DECRYPT_INIT 138 +# define EVP_F_EVP_PKEY_DECRYPT_OLD 151 +# define EVP_F_EVP_PKEY_DERIVE 153 +# define EVP_F_EVP_PKEY_DERIVE_INIT 154 +# define EVP_F_EVP_PKEY_DERIVE_SET_PEER 155 +# define EVP_F_EVP_PKEY_ENCRYPT 105 +# define EVP_F_EVP_PKEY_ENCRYPT_INIT 139 +# define EVP_F_EVP_PKEY_ENCRYPT_OLD 152 +# define EVP_F_EVP_PKEY_GET0_DH 119 +# define EVP_F_EVP_PKEY_GET0_DSA 120 +# define EVP_F_EVP_PKEY_GET0_EC_KEY 131 +# define EVP_F_EVP_PKEY_GET0_HMAC 183 +# define EVP_F_EVP_PKEY_GET0_RSA 121 +# define EVP_F_EVP_PKEY_KEYGEN 146 +# define EVP_F_EVP_PKEY_KEYGEN_INIT 147 +# define EVP_F_EVP_PKEY_NEW 106 +# define EVP_F_EVP_PKEY_PARAMGEN 148 +# define EVP_F_EVP_PKEY_PARAMGEN_INIT 149 +# define EVP_F_EVP_PKEY_SIGN 140 +# define EVP_F_EVP_PKEY_SIGN_INIT 141 +# define EVP_F_EVP_PKEY_VERIFY 142 +# define EVP_F_EVP_PKEY_VERIFY_INIT 143 +# define EVP_F_EVP_PKEY_VERIFY_RECOVER 144 +# define EVP_F_EVP_PKEY_VERIFY_RECOVER_INIT 145 +# define EVP_F_EVP_SIGNFINAL 107 +# define EVP_F_EVP_VERIFYFINAL 108 +# define EVP_F_INT_CTX_NEW 157 +# define EVP_F_PKCS5_PBE_KEYIVGEN 117 +# define EVP_F_PKCS5_V2_PBE_KEYIVGEN 118 +# define EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN 164 +# define EVP_F_PKCS5_V2_SCRYPT_KEYIVGEN 180 +# define EVP_F_PKEY_SET_TYPE 158 +# define EVP_F_RC2_MAGIC_TO_METH 109 +# define EVP_F_RC5_CTRL 125 + +/* Reason codes. */ +# define EVP_R_AES_KEY_SETUP_FAILED 143 +# define EVP_R_BAD_DECRYPT 100 +# define EVP_R_BUFFER_TOO_SMALL 155 +# define EVP_R_CAMELLIA_KEY_SETUP_FAILED 157 +# define EVP_R_CIPHER_PARAMETER_ERROR 122 +# define EVP_R_COMMAND_NOT_SUPPORTED 147 +# define EVP_R_COPY_ERROR 173 +# define EVP_R_CTRL_NOT_IMPLEMENTED 132 +# define EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED 133 +# define EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH 138 +# define EVP_R_DECODE_ERROR 114 +# define EVP_R_DIFFERENT_KEY_TYPES 101 +# define EVP_R_DIFFERENT_PARAMETERS 153 +# define EVP_R_ERROR_LOADING_SECTION 165 +# define EVP_R_ERROR_SETTING_FIPS_MODE 166 +# define EVP_R_EXPECTING_AN_HMAC_KEY 174 +# define EVP_R_EXPECTING_AN_RSA_KEY 127 +# define EVP_R_EXPECTING_A_DH_KEY 128 +# define EVP_R_EXPECTING_A_DSA_KEY 129 +# define EVP_R_EXPECTING_A_EC_KEY 142 +# define EVP_R_FIPS_MODE_NOT_SUPPORTED 167 +# define EVP_R_ILLEGAL_SCRYPT_PARAMETERS 171 +# define EVP_R_INITIALIZATION_ERROR 134 +# define EVP_R_INPUT_NOT_INITIALIZED 111 +# define EVP_R_INVALID_DIGEST 152 +# define EVP_R_INVALID_FIPS_MODE 168 +# define EVP_R_INVALID_KEY 163 +# define EVP_R_INVALID_KEY_LENGTH 130 +# define EVP_R_INVALID_OPERATION 148 +# define EVP_R_KEYGEN_FAILURE 120 +# define EVP_R_MEMORY_LIMIT_EXCEEDED 172 +# define EVP_R_MESSAGE_DIGEST_IS_NULL 159 +# define EVP_R_METHOD_NOT_SUPPORTED 144 +# define EVP_R_MISSING_PARAMETERS 103 +# define EVP_R_NO_CIPHER_SET 131 +# define EVP_R_NO_DEFAULT_DIGEST 158 +# define EVP_R_NO_DIGEST_SET 139 +# define EVP_R_NO_KEY_SET 154 +# define EVP_R_NO_OPERATION_SET 149 +# define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 150 +# define EVP_R_OPERATON_NOT_INITIALIZED 151 +# define EVP_R_PARTIALLY_OVERLAPPING 162 +# define EVP_R_PRIVATE_KEY_DECODE_ERROR 145 +# define EVP_R_PRIVATE_KEY_ENCODE_ERROR 146 +# define EVP_R_PUBLIC_KEY_NOT_RSA 106 +# define EVP_R_UNKNOWN_CIPHER 160 +# define EVP_R_UNKNOWN_DIGEST 161 +# define EVP_R_UNKNOWN_OPTION 169 +# define EVP_R_UNKNOWN_PBE_ALGORITHM 121 +# define EVP_R_UNSUPPORTED_ALGORITHM 156 +# define EVP_R_UNSUPPORTED_CIPHER 107 +# define EVP_R_UNSUPPORTED_KEYLENGTH 123 +# define EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION 124 +# define EVP_R_UNSUPPORTED_KEY_SIZE 108 +# define EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS 135 +# define EVP_R_UNSUPPORTED_PRF 125 +# define EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 118 +# define EVP_R_UNSUPPORTED_SALT_TYPE 126 +# define EVP_R_WRAP_MODE_NOT_ALLOWED 170 +# define EVP_R_WRONG_FINAL_BLOCK_LENGTH 109 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/hmac.h b/mobile/ios/FxA/FxA/include/openssl/hmac.h new file mode 100644 index 0000000000..9f06896059 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/hmac.h @@ -0,0 +1,49 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_HMAC_H +# define HEADER_HMAC_H + +# include + +# include + +# define HMAC_MAX_MD_CBLOCK 128/* largest known is SHA512 */ + +#ifdef __cplusplus +extern "C" { +#endif + +size_t HMAC_size(const HMAC_CTX *e); +HMAC_CTX *HMAC_CTX_new(void); +int HMAC_CTX_reset(HMAC_CTX *ctx); +void HMAC_CTX_free(HMAC_CTX *ctx); + +DEPRECATEDIN_1_1_0(__owur int HMAC_Init(HMAC_CTX *ctx, const void *key, int len, + const EVP_MD *md)) + +/*__owur*/ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, + const EVP_MD *md, ENGINE *impl); +/*__owur*/ int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, + size_t len); +/*__owur*/ int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, + unsigned int *len); +unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len, + const unsigned char *d, size_t n, unsigned char *md, + unsigned int *md_len); +__owur int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx); + +void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags); +const EVP_MD *HMAC_CTX_get_md(const HMAC_CTX *ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/idea.h b/mobile/ios/FxA/FxA/include/openssl/idea.h new file mode 100644 index 0000000000..4334f3ea71 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/idea.h @@ -0,0 +1,64 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_IDEA_H +# define HEADER_IDEA_H + +# include + +# ifndef OPENSSL_NO_IDEA +# ifdef __cplusplus +extern "C" { +# endif + +typedef unsigned int IDEA_INT; + +# define IDEA_ENCRYPT 1 +# define IDEA_DECRYPT 0 + +# define IDEA_BLOCK 8 +# define IDEA_KEY_LENGTH 16 + +typedef struct idea_key_st { + IDEA_INT data[9][6]; +} IDEA_KEY_SCHEDULE; + +const char *IDEA_options(void); +void IDEA_ecb_encrypt(const unsigned char *in, unsigned char *out, + IDEA_KEY_SCHEDULE *ks); +void IDEA_set_encrypt_key(const unsigned char *key, IDEA_KEY_SCHEDULE *ks); +void IDEA_set_decrypt_key(IDEA_KEY_SCHEDULE *ek, IDEA_KEY_SCHEDULE *dk); +void IDEA_cbc_encrypt(const unsigned char *in, unsigned char *out, + long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv, + int enc); +void IDEA_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv, + int *num, int enc); +void IDEA_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv, + int *num); +void IDEA_encrypt(unsigned long *in, IDEA_KEY_SCHEDULE *ks); + +# if OPENSSL_API_COMPAT < 0x10100000L +# define idea_options IDEA_options +# define idea_ecb_encrypt IDEA_ecb_encrypt +# define idea_set_encrypt_key IDEA_set_encrypt_key +# define idea_set_decrypt_key IDEA_set_decrypt_key +# define idea_cbc_encrypt IDEA_cbc_encrypt +# define idea_cfb64_encrypt IDEA_cfb64_encrypt +# define idea_ofb64_encrypt IDEA_ofb64_encrypt +# define idea_encrypt IDEA_encrypt +# endif + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/kdf.h b/mobile/ios/FxA/FxA/include/openssl/kdf.h new file mode 100644 index 0000000000..9f87f788b2 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/kdf.h @@ -0,0 +1,75 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_KDF_H +# define HEADER_KDF_H + +#ifdef __cplusplus +extern "C" { +#endif + +# define EVP_PKEY_CTRL_TLS_MD (EVP_PKEY_ALG_CTRL) +# define EVP_PKEY_CTRL_TLS_SECRET (EVP_PKEY_ALG_CTRL + 1) +# define EVP_PKEY_CTRL_TLS_SEED (EVP_PKEY_ALG_CTRL + 2) +# define EVP_PKEY_CTRL_HKDF_MD (EVP_PKEY_ALG_CTRL + 3) +# define EVP_PKEY_CTRL_HKDF_SALT (EVP_PKEY_ALG_CTRL + 4) +# define EVP_PKEY_CTRL_HKDF_KEY (EVP_PKEY_ALG_CTRL + 5) +# define EVP_PKEY_CTRL_HKDF_INFO (EVP_PKEY_ALG_CTRL + 6) + +# define EVP_PKEY_CTX_set_tls1_prf_md(pctx, md) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_TLS_MD, 0, (void *)md) + +# define EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, sec, seclen) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_TLS_SECRET, seclen, (void *)sec) + +# define EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed, seedlen) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_TLS_SEED, seedlen, (void *)seed) + +# define EVP_PKEY_CTX_set_hkdf_md(pctx, md) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_HKDF_MD, 0, (void *)md) + +# define EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, saltlen) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_HKDF_SALT, saltlen, (void *)salt) + +# define EVP_PKEY_CTX_set1_hkdf_key(pctx, key, keylen) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_HKDF_KEY, keylen, (void *)key) + +# define EVP_PKEY_CTX_add1_hkdf_info(pctx, info, infolen) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_HKDF_INFO, infolen, (void *)info) + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_KDF_strings(void); + +/* Error codes for the KDF functions. */ + +/* Function codes. */ +# define KDF_F_PKEY_TLS1_PRF_CTRL_STR 100 +# define KDF_F_PKEY_TLS1_PRF_DERIVE 101 + +/* Reason codes. */ +# define KDF_R_INVALID_DIGEST 100 +# define KDF_R_MISSING_PARAMETER 101 +# define KDF_R_VALUE_MISSING 102 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/lhash.h b/mobile/ios/FxA/FxA/include/openssl/lhash.h new file mode 100644 index 0000000000..e2ccb65d69 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/lhash.h @@ -0,0 +1,204 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Header for dynamic hash table routines Author - Eric Young + */ + +#ifndef HEADER_LHASH_H +# define HEADER_LHASH_H + +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct lhash_node_st OPENSSL_LH_NODE; +typedef int (*OPENSSL_LH_COMPFUNC) (const void *, const void *); +typedef unsigned long (*OPENSSL_LH_HASHFUNC) (const void *); +typedef void (*OPENSSL_LH_DOALL_FUNC) (void *); +typedef void (*OPENSSL_LH_DOALL_FUNCARG) (void *, void *); +typedef struct lhash_st OPENSSL_LHASH; + +/* + * Macros for declaring and implementing type-safe wrappers for LHASH + * callbacks. This way, callbacks can be provided to LHASH structures without + * function pointer casting and the macro-defined callbacks provide + * per-variable casting before deferring to the underlying type-specific + * callbacks. NB: It is possible to place a "static" in front of both the + * DECLARE and IMPLEMENT macros if the functions are strictly internal. + */ + +/* First: "hash" functions */ +# define DECLARE_LHASH_HASH_FN(name, o_type) \ + unsigned long name##_LHASH_HASH(const void *); +# define IMPLEMENT_LHASH_HASH_FN(name, o_type) \ + unsigned long name##_LHASH_HASH(const void *arg) { \ + const o_type *a = arg; \ + return name##_hash(a); } +# define LHASH_HASH_FN(name) name##_LHASH_HASH + +/* Second: "compare" functions */ +# define DECLARE_LHASH_COMP_FN(name, o_type) \ + int name##_LHASH_COMP(const void *, const void *); +# define IMPLEMENT_LHASH_COMP_FN(name, o_type) \ + int name##_LHASH_COMP(const void *arg1, const void *arg2) { \ + const o_type *a = arg1; \ + const o_type *b = arg2; \ + return name##_cmp(a,b); } +# define LHASH_COMP_FN(name) name##_LHASH_COMP + +/* Fourth: "doall_arg" functions */ +# define DECLARE_LHASH_DOALL_ARG_FN(name, o_type, a_type) \ + void name##_LHASH_DOALL_ARG(void *, void *); +# define IMPLEMENT_LHASH_DOALL_ARG_FN(name, o_type, a_type) \ + void name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \ + o_type *a = arg1; \ + a_type *b = arg2; \ + name##_doall_arg(a, b); } +# define LHASH_DOALL_ARG_FN(name) name##_LHASH_DOALL_ARG + + +# define LH_LOAD_MULT 256 + +int OPENSSL_LH_error(OPENSSL_LHASH *lh); +OPENSSL_LHASH *OPENSSL_LH_new(OPENSSL_LH_HASHFUNC h, OPENSSL_LH_COMPFUNC c); +void OPENSSL_LH_free(OPENSSL_LHASH *lh); +void *OPENSSL_LH_insert(OPENSSL_LHASH *lh, void *data); +void *OPENSSL_LH_delete(OPENSSL_LHASH *lh, const void *data); +void *OPENSSL_LH_retrieve(OPENSSL_LHASH *lh, const void *data); +void OPENSSL_LH_doall(OPENSSL_LHASH *lh, OPENSSL_LH_DOALL_FUNC func); +void OPENSSL_LH_doall_arg(OPENSSL_LHASH *lh, OPENSSL_LH_DOALL_FUNCARG func, void *arg); +unsigned long OPENSSL_LH_strhash(const char *c); +unsigned long OPENSSL_LH_num_items(const OPENSSL_LHASH *lh); +unsigned long OPENSSL_LH_get_down_load(const OPENSSL_LHASH *lh); +void OPENSSL_LH_set_down_load(OPENSSL_LHASH *lh, unsigned long down_load); + +# ifndef OPENSSL_NO_STDIO +void OPENSSL_LH_stats(const OPENSSL_LHASH *lh, FILE *fp); +void OPENSSL_LH_node_stats(const OPENSSL_LHASH *lh, FILE *fp); +void OPENSSL_LH_node_usage_stats(const OPENSSL_LHASH *lh, FILE *fp); +# endif +void OPENSSL_LH_stats_bio(const OPENSSL_LHASH *lh, BIO *out); +void OPENSSL_LH_node_stats_bio(const OPENSSL_LHASH *lh, BIO *out); +void OPENSSL_LH_node_usage_stats_bio(const OPENSSL_LHASH *lh, BIO *out); + +# if OPENSSL_API_COMPAT < 0x10100000L +# define _LHASH OPENSSL_LHASH +# define LHASH_NODE OPENSSL_LH_NODE +# define lh_error OPENSSL_LH_error +# define lh_new OPENSSL_lh_new +# define lh_free OPENSSL_LH_free +# define lh_insert OPENSSL_LH_insert +# define lh_delete OPENSSL_LH_delete +# define lh_retrieve OPENSSL_LH_retrieve +# define lh_doall OPENSSL_LH_doall +# define lh_doall_arg OPENSSL_LH_doall_arg +# define lh_strhash OPENSSL_LH_strhash +# define lh_num_items OPENSSL_LH_num_items +# ifndef OPENSSL_NO_STDIO +# define lh_stats OPENSSL_LH_stats +# define lh_node_stats OPENSSL_LH_node_stats +# define lh_node_usage_stats OPENSSL_LH_node_usage_stats +# endif +# define lh_stats_bio OPENSSL_LH_stats_bio +# define lh_node_stats_bio OPENSSL_LH_node_stats_bio +# define lh_node_usage_stats_bio OPENSSL_LH_node_usage_stats_bio +# endif + +/* Type checking... */ + +# define LHASH_OF(type) struct lhash_st_##type + +# define DEFINE_LHASH_OF(type) \ + LHASH_OF(type) { union lh_##type##_dummy { void* d1; unsigned long d2; int d3; } dummy; }; \ + static ossl_inline LHASH_OF(type) * \ + lh_##type##_new(unsigned long (*hfn)(const type *), \ + int (*cfn)(const type *, const type *)) \ + { \ + return (LHASH_OF(type) *) \ + OPENSSL_LH_new((OPENSSL_LH_HASHFUNC)hfn, (OPENSSL_LH_COMPFUNC)cfn); \ + } \ + static ossl_inline void lh_##type##_free(LHASH_OF(type) *lh) \ + { \ + OPENSSL_LH_free((OPENSSL_LHASH *)lh); \ + } \ + static ossl_inline type *lh_##type##_insert(LHASH_OF(type) *lh, type *d) \ + { \ + return (type *)OPENSSL_LH_insert((OPENSSL_LHASH *)lh, d); \ + } \ + static ossl_inline type *lh_##type##_delete(LHASH_OF(type) *lh, const type *d) \ + { \ + return (type *)OPENSSL_LH_delete((OPENSSL_LHASH *)lh, d); \ + } \ + static ossl_inline type *lh_##type##_retrieve(LHASH_OF(type) *lh, const type *d) \ + { \ + return (type *)OPENSSL_LH_retrieve((OPENSSL_LHASH *)lh, d); \ + } \ + static ossl_inline int lh_##type##_error(LHASH_OF(type) *lh) \ + { \ + return OPENSSL_LH_error((OPENSSL_LHASH *)lh); \ + } \ + static ossl_inline unsigned long lh_##type##_num_items(LHASH_OF(type) *lh) \ + { \ + return OPENSSL_LH_num_items((OPENSSL_LHASH *)lh); \ + } \ + static ossl_inline void lh_##type##_node_stats_bio(const LHASH_OF(type) *lh, BIO *out) \ + { \ + OPENSSL_LH_node_stats_bio((const OPENSSL_LHASH *)lh, out); \ + } \ + static ossl_inline void lh_##type##_node_usage_stats_bio(const LHASH_OF(type) *lh, BIO *out) \ + { \ + OPENSSL_LH_node_usage_stats_bio((const OPENSSL_LHASH *)lh, out); \ + } \ + static ossl_inline void lh_##type##_stats_bio(const LHASH_OF(type) *lh, BIO *out) \ + { \ + OPENSSL_LH_stats_bio((const OPENSSL_LHASH *)lh, out); \ + } \ + static ossl_inline unsigned long lh_##type##_get_down_load(LHASH_OF(type) *lh) \ + { \ + return OPENSSL_LH_get_down_load((OPENSSL_LHASH *)lh); \ + } \ + static ossl_inline void lh_##type##_set_down_load(LHASH_OF(type) *lh, unsigned long dl) \ + { \ + OPENSSL_LH_set_down_load((OPENSSL_LHASH *)lh, dl); \ + } \ + static ossl_inline void lh_##type##_doall(LHASH_OF(type) *lh, \ + void (*doall)(type *)) \ + { \ + OPENSSL_LH_doall((OPENSSL_LHASH *)lh, (OPENSSL_LH_DOALL_FUNC)doall); \ + } \ + LHASH_OF(type) + +#define IMPLEMENT_LHASH_DOALL_ARG_CONST(type, argtype) \ + int_implement_lhash_doall(type, argtype, const type) + +#define IMPLEMENT_LHASH_DOALL_ARG(type, argtype) \ + int_implement_lhash_doall(type, argtype, type) + +#define int_implement_lhash_doall(type, argtype, cbargtype) \ + static ossl_inline void \ + lh_##type##_doall_##argtype(LHASH_OF(type) *lh, \ + void (*fn)(cbargtype *, argtype *), \ + argtype *arg) \ + { \ + OPENSSL_LH_doall_arg((OPENSSL_LHASH *)lh, (OPENSSL_LH_DOALL_FUNCARG)fn, (void *)arg); \ + } \ + LHASH_OF(type) + +DEFINE_LHASH_OF(OPENSSL_STRING); +DEFINE_LHASH_OF(OPENSSL_CSTRING); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/md2.h b/mobile/ios/FxA/FxA/include/openssl/md2.h new file mode 100644 index 0000000000..7faf8e3d65 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/md2.h @@ -0,0 +1,44 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_MD2_H +# define HEADER_MD2_H + +# include + +# ifndef OPENSSL_NO_MD2 +# include +# ifdef __cplusplus +extern "C" { +# endif + +typedef unsigned char MD2_INT; + +# define MD2_DIGEST_LENGTH 16 +# define MD2_BLOCK 16 + +typedef struct MD2state_st { + unsigned int num; + unsigned char data[MD2_BLOCK]; + MD2_INT cksm[MD2_BLOCK]; + MD2_INT state[MD2_BLOCK]; +} MD2_CTX; + +const char *MD2_options(void); +int MD2_Init(MD2_CTX *c); +int MD2_Update(MD2_CTX *c, const unsigned char *data, size_t len); +int MD2_Final(unsigned char *md, MD2_CTX *c); +unsigned char *MD2(const unsigned char *d, size_t n, unsigned char *md); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/md4.h b/mobile/ios/FxA/FxA/include/openssl/md4.h new file mode 100644 index 0000000000..940e29db40 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/md4.h @@ -0,0 +1,51 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_MD4_H +# define HEADER_MD4_H + +# include + +# ifndef OPENSSL_NO_MD4 +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + +/*- + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! MD4_LONG has to be at least 32 bits wide. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ +# define MD4_LONG unsigned int + +# define MD4_CBLOCK 64 +# define MD4_LBLOCK (MD4_CBLOCK/4) +# define MD4_DIGEST_LENGTH 16 + +typedef struct MD4state_st { + MD4_LONG A, B, C, D; + MD4_LONG Nl, Nh; + MD4_LONG data[MD4_LBLOCK]; + unsigned int num; +} MD4_CTX; + +int MD4_Init(MD4_CTX *c); +int MD4_Update(MD4_CTX *c, const void *data, size_t len); +int MD4_Final(unsigned char *md, MD4_CTX *c); +unsigned char *MD4(const unsigned char *d, size_t n, unsigned char *md); +void MD4_Transform(MD4_CTX *c, const unsigned char *b); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/md5.h b/mobile/ios/FxA/FxA/include/openssl/md5.h new file mode 100644 index 0000000000..2deb772118 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/md5.h @@ -0,0 +1,50 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_MD5_H +# define HEADER_MD5_H + +# include + +# ifndef OPENSSL_NO_MD5 +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! MD5_LONG has to be at least 32 bits wide. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ +# define MD5_LONG unsigned int + +# define MD5_CBLOCK 64 +# define MD5_LBLOCK (MD5_CBLOCK/4) +# define MD5_DIGEST_LENGTH 16 + +typedef struct MD5state_st { + MD5_LONG A, B, C, D; + MD5_LONG Nl, Nh; + MD5_LONG data[MD5_LBLOCK]; + unsigned int num; +} MD5_CTX; + +int MD5_Init(MD5_CTX *c); +int MD5_Update(MD5_CTX *c, const void *data, size_t len); +int MD5_Final(unsigned char *md, MD5_CTX *c); +unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md); +void MD5_Transform(MD5_CTX *c, const unsigned char *b); +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/mdc2.h b/mobile/ios/FxA/FxA/include/openssl/mdc2.h new file mode 100644 index 0000000000..aabd2bfaad --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/mdc2.h @@ -0,0 +1,42 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_MDC2_H +# define HEADER_MDC2_H + +# include + +#ifndef OPENSSL_NO_MDC2 +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + +# define MDC2_BLOCK 8 +# define MDC2_DIGEST_LENGTH 16 + +typedef struct mdc2_ctx_st { + unsigned int num; + unsigned char data[MDC2_BLOCK]; + DES_cblock h, hh; + int pad_type; /* either 1 or 2, default 1 */ +} MDC2_CTX; + +int MDC2_Init(MDC2_CTX *c); +int MDC2_Update(MDC2_CTX *c, const unsigned char *data, size_t len); +int MDC2_Final(unsigned char *md, MDC2_CTX *c); +unsigned char *MDC2(const unsigned char *d, size_t n, unsigned char *md); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/modes.h b/mobile/ios/FxA/FxA/include/openssl/modes.h new file mode 100644 index 0000000000..a04c6a5981 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/modes.h @@ -0,0 +1,203 @@ +/* + * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif +typedef void (*block128_f) (const unsigned char in[16], + unsigned char out[16], const void *key); + +typedef void (*cbc128_f) (const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], int enc); + +typedef void (*ctr128_f) (const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, + const unsigned char ivec[16]); + +typedef void (*ccm128_f) (const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, + const unsigned char ivec[16], + unsigned char cmac[16]); + +void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], block128_f block); +void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], block128_f block); + +void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], + unsigned char ecount_buf[16], unsigned int *num, + block128_f block); + +void CRYPTO_ctr128_encrypt_ctr32(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], + unsigned char ecount_buf[16], + unsigned int *num, ctr128_f ctr); + +void CRYPTO_ofb128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], int *num, + block128_f block); + +void CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], int *num, + int enc, block128_f block); +void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const void *key, + unsigned char ivec[16], int *num, + int enc, block128_f block); +void CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out, + size_t bits, const void *key, + unsigned char ivec[16], int *num, + int enc, block128_f block); + +size_t CRYPTO_cts128_encrypt_block(const unsigned char *in, + unsigned char *out, size_t len, + const void *key, unsigned char ivec[16], + block128_f block); +size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], cbc128_f cbc); +size_t CRYPTO_cts128_decrypt_block(const unsigned char *in, + unsigned char *out, size_t len, + const void *key, unsigned char ivec[16], + block128_f block); +size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], cbc128_f cbc); + +size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in, + unsigned char *out, size_t len, + const void *key, + unsigned char ivec[16], + block128_f block); +size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], cbc128_f cbc); +size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in, + unsigned char *out, size_t len, + const void *key, + unsigned char ivec[16], + block128_f block); +size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out, + size_t len, const void *key, + unsigned char ivec[16], cbc128_f cbc); + +typedef struct gcm128_context GCM128_CONTEXT; + +GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block); +void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block); +void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const unsigned char *iv, + size_t len); +int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const unsigned char *aad, + size_t len); +int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, + const unsigned char *in, unsigned char *out, + size_t len); +int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, + const unsigned char *in, unsigned char *out, + size_t len); +int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, + const unsigned char *in, unsigned char *out, + size_t len, ctr128_f stream); +int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, + const unsigned char *in, unsigned char *out, + size_t len, ctr128_f stream); +int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const unsigned char *tag, + size_t len); +void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len); +void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx); + +typedef struct ccm128_context CCM128_CONTEXT; + +void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, + unsigned int M, unsigned int L, void *key, + block128_f block); +int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx, const unsigned char *nonce, + size_t nlen, size_t mlen); +void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx, const unsigned char *aad, + size_t alen); +int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx, const unsigned char *inp, + unsigned char *out, size_t len); +int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx, const unsigned char *inp, + unsigned char *out, size_t len); +int CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx, const unsigned char *inp, + unsigned char *out, size_t len, + ccm128_f stream); +int CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx, const unsigned char *inp, + unsigned char *out, size_t len, + ccm128_f stream); +size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len); + +typedef struct xts128_context XTS128_CONTEXT; + +int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx, + const unsigned char iv[16], + const unsigned char *inp, unsigned char *out, + size_t len, int enc); + +size_t CRYPTO_128_wrap(void *key, const unsigned char *iv, + unsigned char *out, + const unsigned char *in, size_t inlen, + block128_f block); + +size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv, + unsigned char *out, + const unsigned char *in, size_t inlen, + block128_f block); +size_t CRYPTO_128_wrap_pad(void *key, const unsigned char *icv, + unsigned char *out, const unsigned char *in, + size_t inlen, block128_f block); +size_t CRYPTO_128_unwrap_pad(void *key, const unsigned char *icv, + unsigned char *out, const unsigned char *in, + size_t inlen, block128_f block); + +#ifndef OPENSSL_NO_OCB +typedef struct ocb128_context OCB128_CONTEXT; + +typedef void (*ocb128_f) (const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, + size_t start_block_num, + unsigned char offset_i[16], + const unsigned char L_[][16], + unsigned char checksum[16]); + +OCB128_CONTEXT *CRYPTO_ocb128_new(void *keyenc, void *keydec, + block128_f encrypt, block128_f decrypt, + ocb128_f stream); +int CRYPTO_ocb128_init(OCB128_CONTEXT *ctx, void *keyenc, void *keydec, + block128_f encrypt, block128_f decrypt, + ocb128_f stream); +int CRYPTO_ocb128_copy_ctx(OCB128_CONTEXT *dest, OCB128_CONTEXT *src, + void *keyenc, void *keydec); +int CRYPTO_ocb128_setiv(OCB128_CONTEXT *ctx, const unsigned char *iv, + size_t len, size_t taglen); +int CRYPTO_ocb128_aad(OCB128_CONTEXT *ctx, const unsigned char *aad, + size_t len); +int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx, const unsigned char *in, + unsigned char *out, size_t len); +int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx, const unsigned char *in, + unsigned char *out, size_t len); +int CRYPTO_ocb128_finish(OCB128_CONTEXT *ctx, const unsigned char *tag, + size_t len); +int CRYPTO_ocb128_tag(OCB128_CONTEXT *ctx, unsigned char *tag, size_t len); +void CRYPTO_ocb128_cleanup(OCB128_CONTEXT *ctx); +#endif /* OPENSSL_NO_OCB */ + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/obj_mac.h b/mobile/ios/FxA/FxA/include/openssl/obj_mac.h new file mode 100644 index 0000000000..f97f3eaa17 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/obj_mac.h @@ -0,0 +1,4577 @@ +/* + * WARNING: do not edit! + * Generated by crypto/objects/objects.pl + * + * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#define SN_undef "UNDEF" +#define LN_undef "undefined" +#define NID_undef 0 +#define OBJ_undef 0L + +#define SN_itu_t "ITU-T" +#define LN_itu_t "itu-t" +#define NID_itu_t 645 +#define OBJ_itu_t 0L + +#define NID_ccitt 404 +#define OBJ_ccitt OBJ_itu_t + +#define SN_iso "ISO" +#define LN_iso "iso" +#define NID_iso 181 +#define OBJ_iso 1L + +#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T" +#define LN_joint_iso_itu_t "joint-iso-itu-t" +#define NID_joint_iso_itu_t 646 +#define OBJ_joint_iso_itu_t 2L + +#define NID_joint_iso_ccitt 393 +#define OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t + +#define SN_member_body "member-body" +#define LN_member_body "ISO Member Body" +#define NID_member_body 182 +#define OBJ_member_body OBJ_iso,2L + +#define SN_identified_organization "identified-organization" +#define NID_identified_organization 676 +#define OBJ_identified_organization OBJ_iso,3L + +#define SN_hmac_md5 "HMAC-MD5" +#define LN_hmac_md5 "hmac-md5" +#define NID_hmac_md5 780 +#define OBJ_hmac_md5 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,1L + +#define SN_hmac_sha1 "HMAC-SHA1" +#define LN_hmac_sha1 "hmac-sha1" +#define NID_hmac_sha1 781 +#define OBJ_hmac_sha1 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,2L + +#define SN_certicom_arc "certicom-arc" +#define NID_certicom_arc 677 +#define OBJ_certicom_arc OBJ_identified_organization,132L + +#define SN_international_organizations "international-organizations" +#define LN_international_organizations "International Organizations" +#define NID_international_organizations 647 +#define OBJ_international_organizations OBJ_joint_iso_itu_t,23L + +#define SN_wap "wap" +#define NID_wap 678 +#define OBJ_wap OBJ_international_organizations,43L + +#define SN_wap_wsg "wap-wsg" +#define NID_wap_wsg 679 +#define OBJ_wap_wsg OBJ_wap,1L + +#define SN_selected_attribute_types "selected-attribute-types" +#define LN_selected_attribute_types "Selected Attribute Types" +#define NID_selected_attribute_types 394 +#define OBJ_selected_attribute_types OBJ_joint_iso_itu_t,5L,1L,5L + +#define SN_clearance "clearance" +#define NID_clearance 395 +#define OBJ_clearance OBJ_selected_attribute_types,55L + +#define SN_ISO_US "ISO-US" +#define LN_ISO_US "ISO US Member Body" +#define NID_ISO_US 183 +#define OBJ_ISO_US OBJ_member_body,840L + +#define SN_X9_57 "X9-57" +#define LN_X9_57 "X9.57" +#define NID_X9_57 184 +#define OBJ_X9_57 OBJ_ISO_US,10040L + +#define SN_X9cm "X9cm" +#define LN_X9cm "X9.57 CM ?" +#define NID_X9cm 185 +#define OBJ_X9cm OBJ_X9_57,4L + +#define SN_dsa "DSA" +#define LN_dsa "dsaEncryption" +#define NID_dsa 116 +#define OBJ_dsa OBJ_X9cm,1L + +#define SN_dsaWithSHA1 "DSA-SHA1" +#define LN_dsaWithSHA1 "dsaWithSHA1" +#define NID_dsaWithSHA1 113 +#define OBJ_dsaWithSHA1 OBJ_X9cm,3L + +#define SN_ansi_X9_62 "ansi-X9-62" +#define LN_ansi_X9_62 "ANSI X9.62" +#define NID_ansi_X9_62 405 +#define OBJ_ansi_X9_62 OBJ_ISO_US,10045L + +#define OBJ_X9_62_id_fieldType OBJ_ansi_X9_62,1L + +#define SN_X9_62_prime_field "prime-field" +#define NID_X9_62_prime_field 406 +#define OBJ_X9_62_prime_field OBJ_X9_62_id_fieldType,1L + +#define SN_X9_62_characteristic_two_field "characteristic-two-field" +#define NID_X9_62_characteristic_two_field 407 +#define OBJ_X9_62_characteristic_two_field OBJ_X9_62_id_fieldType,2L + +#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis" +#define NID_X9_62_id_characteristic_two_basis 680 +#define OBJ_X9_62_id_characteristic_two_basis OBJ_X9_62_characteristic_two_field,3L + +#define SN_X9_62_onBasis "onBasis" +#define NID_X9_62_onBasis 681 +#define OBJ_X9_62_onBasis OBJ_X9_62_id_characteristic_two_basis,1L + +#define SN_X9_62_tpBasis "tpBasis" +#define NID_X9_62_tpBasis 682 +#define OBJ_X9_62_tpBasis OBJ_X9_62_id_characteristic_two_basis,2L + +#define SN_X9_62_ppBasis "ppBasis" +#define NID_X9_62_ppBasis 683 +#define OBJ_X9_62_ppBasis OBJ_X9_62_id_characteristic_two_basis,3L + +#define OBJ_X9_62_id_publicKeyType OBJ_ansi_X9_62,2L + +#define SN_X9_62_id_ecPublicKey "id-ecPublicKey" +#define NID_X9_62_id_ecPublicKey 408 +#define OBJ_X9_62_id_ecPublicKey OBJ_X9_62_id_publicKeyType,1L + +#define OBJ_X9_62_ellipticCurve OBJ_ansi_X9_62,3L + +#define OBJ_X9_62_c_TwoCurve OBJ_X9_62_ellipticCurve,0L + +#define SN_X9_62_c2pnb163v1 "c2pnb163v1" +#define NID_X9_62_c2pnb163v1 684 +#define OBJ_X9_62_c2pnb163v1 OBJ_X9_62_c_TwoCurve,1L + +#define SN_X9_62_c2pnb163v2 "c2pnb163v2" +#define NID_X9_62_c2pnb163v2 685 +#define OBJ_X9_62_c2pnb163v2 OBJ_X9_62_c_TwoCurve,2L + +#define SN_X9_62_c2pnb163v3 "c2pnb163v3" +#define NID_X9_62_c2pnb163v3 686 +#define OBJ_X9_62_c2pnb163v3 OBJ_X9_62_c_TwoCurve,3L + +#define SN_X9_62_c2pnb176v1 "c2pnb176v1" +#define NID_X9_62_c2pnb176v1 687 +#define OBJ_X9_62_c2pnb176v1 OBJ_X9_62_c_TwoCurve,4L + +#define SN_X9_62_c2tnb191v1 "c2tnb191v1" +#define NID_X9_62_c2tnb191v1 688 +#define OBJ_X9_62_c2tnb191v1 OBJ_X9_62_c_TwoCurve,5L + +#define SN_X9_62_c2tnb191v2 "c2tnb191v2" +#define NID_X9_62_c2tnb191v2 689 +#define OBJ_X9_62_c2tnb191v2 OBJ_X9_62_c_TwoCurve,6L + +#define SN_X9_62_c2tnb191v3 "c2tnb191v3" +#define NID_X9_62_c2tnb191v3 690 +#define OBJ_X9_62_c2tnb191v3 OBJ_X9_62_c_TwoCurve,7L + +#define SN_X9_62_c2onb191v4 "c2onb191v4" +#define NID_X9_62_c2onb191v4 691 +#define OBJ_X9_62_c2onb191v4 OBJ_X9_62_c_TwoCurve,8L + +#define SN_X9_62_c2onb191v5 "c2onb191v5" +#define NID_X9_62_c2onb191v5 692 +#define OBJ_X9_62_c2onb191v5 OBJ_X9_62_c_TwoCurve,9L + +#define SN_X9_62_c2pnb208w1 "c2pnb208w1" +#define NID_X9_62_c2pnb208w1 693 +#define OBJ_X9_62_c2pnb208w1 OBJ_X9_62_c_TwoCurve,10L + +#define SN_X9_62_c2tnb239v1 "c2tnb239v1" +#define NID_X9_62_c2tnb239v1 694 +#define OBJ_X9_62_c2tnb239v1 OBJ_X9_62_c_TwoCurve,11L + +#define SN_X9_62_c2tnb239v2 "c2tnb239v2" +#define NID_X9_62_c2tnb239v2 695 +#define OBJ_X9_62_c2tnb239v2 OBJ_X9_62_c_TwoCurve,12L + +#define SN_X9_62_c2tnb239v3 "c2tnb239v3" +#define NID_X9_62_c2tnb239v3 696 +#define OBJ_X9_62_c2tnb239v3 OBJ_X9_62_c_TwoCurve,13L + +#define SN_X9_62_c2onb239v4 "c2onb239v4" +#define NID_X9_62_c2onb239v4 697 +#define OBJ_X9_62_c2onb239v4 OBJ_X9_62_c_TwoCurve,14L + +#define SN_X9_62_c2onb239v5 "c2onb239v5" +#define NID_X9_62_c2onb239v5 698 +#define OBJ_X9_62_c2onb239v5 OBJ_X9_62_c_TwoCurve,15L + +#define SN_X9_62_c2pnb272w1 "c2pnb272w1" +#define NID_X9_62_c2pnb272w1 699 +#define OBJ_X9_62_c2pnb272w1 OBJ_X9_62_c_TwoCurve,16L + +#define SN_X9_62_c2pnb304w1 "c2pnb304w1" +#define NID_X9_62_c2pnb304w1 700 +#define OBJ_X9_62_c2pnb304w1 OBJ_X9_62_c_TwoCurve,17L + +#define SN_X9_62_c2tnb359v1 "c2tnb359v1" +#define NID_X9_62_c2tnb359v1 701 +#define OBJ_X9_62_c2tnb359v1 OBJ_X9_62_c_TwoCurve,18L + +#define SN_X9_62_c2pnb368w1 "c2pnb368w1" +#define NID_X9_62_c2pnb368w1 702 +#define OBJ_X9_62_c2pnb368w1 OBJ_X9_62_c_TwoCurve,19L + +#define SN_X9_62_c2tnb431r1 "c2tnb431r1" +#define NID_X9_62_c2tnb431r1 703 +#define OBJ_X9_62_c2tnb431r1 OBJ_X9_62_c_TwoCurve,20L + +#define OBJ_X9_62_primeCurve OBJ_X9_62_ellipticCurve,1L + +#define SN_X9_62_prime192v1 "prime192v1" +#define NID_X9_62_prime192v1 409 +#define OBJ_X9_62_prime192v1 OBJ_X9_62_primeCurve,1L + +#define SN_X9_62_prime192v2 "prime192v2" +#define NID_X9_62_prime192v2 410 +#define OBJ_X9_62_prime192v2 OBJ_X9_62_primeCurve,2L + +#define SN_X9_62_prime192v3 "prime192v3" +#define NID_X9_62_prime192v3 411 +#define OBJ_X9_62_prime192v3 OBJ_X9_62_primeCurve,3L + +#define SN_X9_62_prime239v1 "prime239v1" +#define NID_X9_62_prime239v1 412 +#define OBJ_X9_62_prime239v1 OBJ_X9_62_primeCurve,4L + +#define SN_X9_62_prime239v2 "prime239v2" +#define NID_X9_62_prime239v2 413 +#define OBJ_X9_62_prime239v2 OBJ_X9_62_primeCurve,5L + +#define SN_X9_62_prime239v3 "prime239v3" +#define NID_X9_62_prime239v3 414 +#define OBJ_X9_62_prime239v3 OBJ_X9_62_primeCurve,6L + +#define SN_X9_62_prime256v1 "prime256v1" +#define NID_X9_62_prime256v1 415 +#define OBJ_X9_62_prime256v1 OBJ_X9_62_primeCurve,7L + +#define OBJ_X9_62_id_ecSigType OBJ_ansi_X9_62,4L + +#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1" +#define NID_ecdsa_with_SHA1 416 +#define OBJ_ecdsa_with_SHA1 OBJ_X9_62_id_ecSigType,1L + +#define SN_ecdsa_with_Recommended "ecdsa-with-Recommended" +#define NID_ecdsa_with_Recommended 791 +#define OBJ_ecdsa_with_Recommended OBJ_X9_62_id_ecSigType,2L + +#define SN_ecdsa_with_Specified "ecdsa-with-Specified" +#define NID_ecdsa_with_Specified 792 +#define OBJ_ecdsa_with_Specified OBJ_X9_62_id_ecSigType,3L + +#define SN_ecdsa_with_SHA224 "ecdsa-with-SHA224" +#define NID_ecdsa_with_SHA224 793 +#define OBJ_ecdsa_with_SHA224 OBJ_ecdsa_with_Specified,1L + +#define SN_ecdsa_with_SHA256 "ecdsa-with-SHA256" +#define NID_ecdsa_with_SHA256 794 +#define OBJ_ecdsa_with_SHA256 OBJ_ecdsa_with_Specified,2L + +#define SN_ecdsa_with_SHA384 "ecdsa-with-SHA384" +#define NID_ecdsa_with_SHA384 795 +#define OBJ_ecdsa_with_SHA384 OBJ_ecdsa_with_Specified,3L + +#define SN_ecdsa_with_SHA512 "ecdsa-with-SHA512" +#define NID_ecdsa_with_SHA512 796 +#define OBJ_ecdsa_with_SHA512 OBJ_ecdsa_with_Specified,4L + +#define OBJ_secg_ellipticCurve OBJ_certicom_arc,0L + +#define SN_secp112r1 "secp112r1" +#define NID_secp112r1 704 +#define OBJ_secp112r1 OBJ_secg_ellipticCurve,6L + +#define SN_secp112r2 "secp112r2" +#define NID_secp112r2 705 +#define OBJ_secp112r2 OBJ_secg_ellipticCurve,7L + +#define SN_secp128r1 "secp128r1" +#define NID_secp128r1 706 +#define OBJ_secp128r1 OBJ_secg_ellipticCurve,28L + +#define SN_secp128r2 "secp128r2" +#define NID_secp128r2 707 +#define OBJ_secp128r2 OBJ_secg_ellipticCurve,29L + +#define SN_secp160k1 "secp160k1" +#define NID_secp160k1 708 +#define OBJ_secp160k1 OBJ_secg_ellipticCurve,9L + +#define SN_secp160r1 "secp160r1" +#define NID_secp160r1 709 +#define OBJ_secp160r1 OBJ_secg_ellipticCurve,8L + +#define SN_secp160r2 "secp160r2" +#define NID_secp160r2 710 +#define OBJ_secp160r2 OBJ_secg_ellipticCurve,30L + +#define SN_secp192k1 "secp192k1" +#define NID_secp192k1 711 +#define OBJ_secp192k1 OBJ_secg_ellipticCurve,31L + +#define SN_secp224k1 "secp224k1" +#define NID_secp224k1 712 +#define OBJ_secp224k1 OBJ_secg_ellipticCurve,32L + +#define SN_secp224r1 "secp224r1" +#define NID_secp224r1 713 +#define OBJ_secp224r1 OBJ_secg_ellipticCurve,33L + +#define SN_secp256k1 "secp256k1" +#define NID_secp256k1 714 +#define OBJ_secp256k1 OBJ_secg_ellipticCurve,10L + +#define SN_secp384r1 "secp384r1" +#define NID_secp384r1 715 +#define OBJ_secp384r1 OBJ_secg_ellipticCurve,34L + +#define SN_secp521r1 "secp521r1" +#define NID_secp521r1 716 +#define OBJ_secp521r1 OBJ_secg_ellipticCurve,35L + +#define SN_sect113r1 "sect113r1" +#define NID_sect113r1 717 +#define OBJ_sect113r1 OBJ_secg_ellipticCurve,4L + +#define SN_sect113r2 "sect113r2" +#define NID_sect113r2 718 +#define OBJ_sect113r2 OBJ_secg_ellipticCurve,5L + +#define SN_sect131r1 "sect131r1" +#define NID_sect131r1 719 +#define OBJ_sect131r1 OBJ_secg_ellipticCurve,22L + +#define SN_sect131r2 "sect131r2" +#define NID_sect131r2 720 +#define OBJ_sect131r2 OBJ_secg_ellipticCurve,23L + +#define SN_sect163k1 "sect163k1" +#define NID_sect163k1 721 +#define OBJ_sect163k1 OBJ_secg_ellipticCurve,1L + +#define SN_sect163r1 "sect163r1" +#define NID_sect163r1 722 +#define OBJ_sect163r1 OBJ_secg_ellipticCurve,2L + +#define SN_sect163r2 "sect163r2" +#define NID_sect163r2 723 +#define OBJ_sect163r2 OBJ_secg_ellipticCurve,15L + +#define SN_sect193r1 "sect193r1" +#define NID_sect193r1 724 +#define OBJ_sect193r1 OBJ_secg_ellipticCurve,24L + +#define SN_sect193r2 "sect193r2" +#define NID_sect193r2 725 +#define OBJ_sect193r2 OBJ_secg_ellipticCurve,25L + +#define SN_sect233k1 "sect233k1" +#define NID_sect233k1 726 +#define OBJ_sect233k1 OBJ_secg_ellipticCurve,26L + +#define SN_sect233r1 "sect233r1" +#define NID_sect233r1 727 +#define OBJ_sect233r1 OBJ_secg_ellipticCurve,27L + +#define SN_sect239k1 "sect239k1" +#define NID_sect239k1 728 +#define OBJ_sect239k1 OBJ_secg_ellipticCurve,3L + +#define SN_sect283k1 "sect283k1" +#define NID_sect283k1 729 +#define OBJ_sect283k1 OBJ_secg_ellipticCurve,16L + +#define SN_sect283r1 "sect283r1" +#define NID_sect283r1 730 +#define OBJ_sect283r1 OBJ_secg_ellipticCurve,17L + +#define SN_sect409k1 "sect409k1" +#define NID_sect409k1 731 +#define OBJ_sect409k1 OBJ_secg_ellipticCurve,36L + +#define SN_sect409r1 "sect409r1" +#define NID_sect409r1 732 +#define OBJ_sect409r1 OBJ_secg_ellipticCurve,37L + +#define SN_sect571k1 "sect571k1" +#define NID_sect571k1 733 +#define OBJ_sect571k1 OBJ_secg_ellipticCurve,38L + +#define SN_sect571r1 "sect571r1" +#define NID_sect571r1 734 +#define OBJ_sect571r1 OBJ_secg_ellipticCurve,39L + +#define OBJ_wap_wsg_idm_ecid OBJ_wap_wsg,4L + +#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1" +#define NID_wap_wsg_idm_ecid_wtls1 735 +#define OBJ_wap_wsg_idm_ecid_wtls1 OBJ_wap_wsg_idm_ecid,1L + +#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3" +#define NID_wap_wsg_idm_ecid_wtls3 736 +#define OBJ_wap_wsg_idm_ecid_wtls3 OBJ_wap_wsg_idm_ecid,3L + +#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4" +#define NID_wap_wsg_idm_ecid_wtls4 737 +#define OBJ_wap_wsg_idm_ecid_wtls4 OBJ_wap_wsg_idm_ecid,4L + +#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5" +#define NID_wap_wsg_idm_ecid_wtls5 738 +#define OBJ_wap_wsg_idm_ecid_wtls5 OBJ_wap_wsg_idm_ecid,5L + +#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6" +#define NID_wap_wsg_idm_ecid_wtls6 739 +#define OBJ_wap_wsg_idm_ecid_wtls6 OBJ_wap_wsg_idm_ecid,6L + +#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7" +#define NID_wap_wsg_idm_ecid_wtls7 740 +#define OBJ_wap_wsg_idm_ecid_wtls7 OBJ_wap_wsg_idm_ecid,7L + +#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8" +#define NID_wap_wsg_idm_ecid_wtls8 741 +#define OBJ_wap_wsg_idm_ecid_wtls8 OBJ_wap_wsg_idm_ecid,8L + +#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9" +#define NID_wap_wsg_idm_ecid_wtls9 742 +#define OBJ_wap_wsg_idm_ecid_wtls9 OBJ_wap_wsg_idm_ecid,9L + +#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10" +#define NID_wap_wsg_idm_ecid_wtls10 743 +#define OBJ_wap_wsg_idm_ecid_wtls10 OBJ_wap_wsg_idm_ecid,10L + +#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11" +#define NID_wap_wsg_idm_ecid_wtls11 744 +#define OBJ_wap_wsg_idm_ecid_wtls11 OBJ_wap_wsg_idm_ecid,11L + +#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12" +#define NID_wap_wsg_idm_ecid_wtls12 745 +#define OBJ_wap_wsg_idm_ecid_wtls12 OBJ_wap_wsg_idm_ecid,12L + +#define SN_cast5_cbc "CAST5-CBC" +#define LN_cast5_cbc "cast5-cbc" +#define NID_cast5_cbc 108 +#define OBJ_cast5_cbc OBJ_ISO_US,113533L,7L,66L,10L + +#define SN_cast5_ecb "CAST5-ECB" +#define LN_cast5_ecb "cast5-ecb" +#define NID_cast5_ecb 109 + +#define SN_cast5_cfb64 "CAST5-CFB" +#define LN_cast5_cfb64 "cast5-cfb" +#define NID_cast5_cfb64 110 + +#define SN_cast5_ofb64 "CAST5-OFB" +#define LN_cast5_ofb64 "cast5-ofb" +#define NID_cast5_ofb64 111 + +#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" +#define NID_pbeWithMD5AndCast5_CBC 112 +#define OBJ_pbeWithMD5AndCast5_CBC OBJ_ISO_US,113533L,7L,66L,12L + +#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC" +#define LN_id_PasswordBasedMAC "password based MAC" +#define NID_id_PasswordBasedMAC 782 +#define OBJ_id_PasswordBasedMAC OBJ_ISO_US,113533L,7L,66L,13L + +#define SN_id_DHBasedMac "id-DHBasedMac" +#define LN_id_DHBasedMac "Diffie-Hellman based MAC" +#define NID_id_DHBasedMac 783 +#define OBJ_id_DHBasedMac OBJ_ISO_US,113533L,7L,66L,30L + +#define SN_rsadsi "rsadsi" +#define LN_rsadsi "RSA Data Security, Inc." +#define NID_rsadsi 1 +#define OBJ_rsadsi OBJ_ISO_US,113549L + +#define SN_pkcs "pkcs" +#define LN_pkcs "RSA Data Security, Inc. PKCS" +#define NID_pkcs 2 +#define OBJ_pkcs OBJ_rsadsi,1L + +#define SN_pkcs1 "pkcs1" +#define NID_pkcs1 186 +#define OBJ_pkcs1 OBJ_pkcs,1L + +#define LN_rsaEncryption "rsaEncryption" +#define NID_rsaEncryption 6 +#define OBJ_rsaEncryption OBJ_pkcs1,1L + +#define SN_md2WithRSAEncryption "RSA-MD2" +#define LN_md2WithRSAEncryption "md2WithRSAEncryption" +#define NID_md2WithRSAEncryption 7 +#define OBJ_md2WithRSAEncryption OBJ_pkcs1,2L + +#define SN_md4WithRSAEncryption "RSA-MD4" +#define LN_md4WithRSAEncryption "md4WithRSAEncryption" +#define NID_md4WithRSAEncryption 396 +#define OBJ_md4WithRSAEncryption OBJ_pkcs1,3L + +#define SN_md5WithRSAEncryption "RSA-MD5" +#define LN_md5WithRSAEncryption "md5WithRSAEncryption" +#define NID_md5WithRSAEncryption 8 +#define OBJ_md5WithRSAEncryption OBJ_pkcs1,4L + +#define SN_sha1WithRSAEncryption "RSA-SHA1" +#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" +#define NID_sha1WithRSAEncryption 65 +#define OBJ_sha1WithRSAEncryption OBJ_pkcs1,5L + +#define SN_rsaesOaep "RSAES-OAEP" +#define LN_rsaesOaep "rsaesOaep" +#define NID_rsaesOaep 919 +#define OBJ_rsaesOaep OBJ_pkcs1,7L + +#define SN_mgf1 "MGF1" +#define LN_mgf1 "mgf1" +#define NID_mgf1 911 +#define OBJ_mgf1 OBJ_pkcs1,8L + +#define SN_pSpecified "PSPECIFIED" +#define LN_pSpecified "pSpecified" +#define NID_pSpecified 935 +#define OBJ_pSpecified OBJ_pkcs1,9L + +#define SN_rsassaPss "RSASSA-PSS" +#define LN_rsassaPss "rsassaPss" +#define NID_rsassaPss 912 +#define OBJ_rsassaPss OBJ_pkcs1,10L + +#define SN_sha256WithRSAEncryption "RSA-SHA256" +#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption" +#define NID_sha256WithRSAEncryption 668 +#define OBJ_sha256WithRSAEncryption OBJ_pkcs1,11L + +#define SN_sha384WithRSAEncryption "RSA-SHA384" +#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption" +#define NID_sha384WithRSAEncryption 669 +#define OBJ_sha384WithRSAEncryption OBJ_pkcs1,12L + +#define SN_sha512WithRSAEncryption "RSA-SHA512" +#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption" +#define NID_sha512WithRSAEncryption 670 +#define OBJ_sha512WithRSAEncryption OBJ_pkcs1,13L + +#define SN_sha224WithRSAEncryption "RSA-SHA224" +#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption" +#define NID_sha224WithRSAEncryption 671 +#define OBJ_sha224WithRSAEncryption OBJ_pkcs1,14L + +#define SN_pkcs3 "pkcs3" +#define NID_pkcs3 27 +#define OBJ_pkcs3 OBJ_pkcs,3L + +#define LN_dhKeyAgreement "dhKeyAgreement" +#define NID_dhKeyAgreement 28 +#define OBJ_dhKeyAgreement OBJ_pkcs3,1L + +#define SN_pkcs5 "pkcs5" +#define NID_pkcs5 187 +#define OBJ_pkcs5 OBJ_pkcs,5L + +#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" +#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" +#define NID_pbeWithMD2AndDES_CBC 9 +#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs5,1L + +#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" +#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" +#define NID_pbeWithMD5AndDES_CBC 10 +#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs5,3L + +#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" +#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" +#define NID_pbeWithMD2AndRC2_CBC 168 +#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs5,4L + +#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" +#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" +#define NID_pbeWithMD5AndRC2_CBC 169 +#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs5,6L + +#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" +#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" +#define NID_pbeWithSHA1AndDES_CBC 170 +#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs5,10L + +#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" +#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" +#define NID_pbeWithSHA1AndRC2_CBC 68 +#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs5,11L + +#define LN_id_pbkdf2 "PBKDF2" +#define NID_id_pbkdf2 69 +#define OBJ_id_pbkdf2 OBJ_pkcs5,12L + +#define LN_pbes2 "PBES2" +#define NID_pbes2 161 +#define OBJ_pbes2 OBJ_pkcs5,13L + +#define LN_pbmac1 "PBMAC1" +#define NID_pbmac1 162 +#define OBJ_pbmac1 OBJ_pkcs5,14L + +#define SN_pkcs7 "pkcs7" +#define NID_pkcs7 20 +#define OBJ_pkcs7 OBJ_pkcs,7L + +#define LN_pkcs7_data "pkcs7-data" +#define NID_pkcs7_data 21 +#define OBJ_pkcs7_data OBJ_pkcs7,1L + +#define LN_pkcs7_signed "pkcs7-signedData" +#define NID_pkcs7_signed 22 +#define OBJ_pkcs7_signed OBJ_pkcs7,2L + +#define LN_pkcs7_enveloped "pkcs7-envelopedData" +#define NID_pkcs7_enveloped 23 +#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L + +#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" +#define NID_pkcs7_signedAndEnveloped 24 +#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L + +#define LN_pkcs7_digest "pkcs7-digestData" +#define NID_pkcs7_digest 25 +#define OBJ_pkcs7_digest OBJ_pkcs7,5L + +#define LN_pkcs7_encrypted "pkcs7-encryptedData" +#define NID_pkcs7_encrypted 26 +#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L + +#define SN_pkcs9 "pkcs9" +#define NID_pkcs9 47 +#define OBJ_pkcs9 OBJ_pkcs,9L + +#define LN_pkcs9_emailAddress "emailAddress" +#define NID_pkcs9_emailAddress 48 +#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L + +#define LN_pkcs9_unstructuredName "unstructuredName" +#define NID_pkcs9_unstructuredName 49 +#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L + +#define LN_pkcs9_contentType "contentType" +#define NID_pkcs9_contentType 50 +#define OBJ_pkcs9_contentType OBJ_pkcs9,3L + +#define LN_pkcs9_messageDigest "messageDigest" +#define NID_pkcs9_messageDigest 51 +#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L + +#define LN_pkcs9_signingTime "signingTime" +#define NID_pkcs9_signingTime 52 +#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L + +#define LN_pkcs9_countersignature "countersignature" +#define NID_pkcs9_countersignature 53 +#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L + +#define LN_pkcs9_challengePassword "challengePassword" +#define NID_pkcs9_challengePassword 54 +#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L + +#define LN_pkcs9_unstructuredAddress "unstructuredAddress" +#define NID_pkcs9_unstructuredAddress 55 +#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L + +#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" +#define NID_pkcs9_extCertAttributes 56 +#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L + +#define SN_ext_req "extReq" +#define LN_ext_req "Extension Request" +#define NID_ext_req 172 +#define OBJ_ext_req OBJ_pkcs9,14L + +#define SN_SMIMECapabilities "SMIME-CAPS" +#define LN_SMIMECapabilities "S/MIME Capabilities" +#define NID_SMIMECapabilities 167 +#define OBJ_SMIMECapabilities OBJ_pkcs9,15L + +#define SN_SMIME "SMIME" +#define LN_SMIME "S/MIME" +#define NID_SMIME 188 +#define OBJ_SMIME OBJ_pkcs9,16L + +#define SN_id_smime_mod "id-smime-mod" +#define NID_id_smime_mod 189 +#define OBJ_id_smime_mod OBJ_SMIME,0L + +#define SN_id_smime_ct "id-smime-ct" +#define NID_id_smime_ct 190 +#define OBJ_id_smime_ct OBJ_SMIME,1L + +#define SN_id_smime_aa "id-smime-aa" +#define NID_id_smime_aa 191 +#define OBJ_id_smime_aa OBJ_SMIME,2L + +#define SN_id_smime_alg "id-smime-alg" +#define NID_id_smime_alg 192 +#define OBJ_id_smime_alg OBJ_SMIME,3L + +#define SN_id_smime_cd "id-smime-cd" +#define NID_id_smime_cd 193 +#define OBJ_id_smime_cd OBJ_SMIME,4L + +#define SN_id_smime_spq "id-smime-spq" +#define NID_id_smime_spq 194 +#define OBJ_id_smime_spq OBJ_SMIME,5L + +#define SN_id_smime_cti "id-smime-cti" +#define NID_id_smime_cti 195 +#define OBJ_id_smime_cti OBJ_SMIME,6L + +#define SN_id_smime_mod_cms "id-smime-mod-cms" +#define NID_id_smime_mod_cms 196 +#define OBJ_id_smime_mod_cms OBJ_id_smime_mod,1L + +#define SN_id_smime_mod_ess "id-smime-mod-ess" +#define NID_id_smime_mod_ess 197 +#define OBJ_id_smime_mod_ess OBJ_id_smime_mod,2L + +#define SN_id_smime_mod_oid "id-smime-mod-oid" +#define NID_id_smime_mod_oid 198 +#define OBJ_id_smime_mod_oid OBJ_id_smime_mod,3L + +#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3" +#define NID_id_smime_mod_msg_v3 199 +#define OBJ_id_smime_mod_msg_v3 OBJ_id_smime_mod,4L + +#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88" +#define NID_id_smime_mod_ets_eSignature_88 200 +#define OBJ_id_smime_mod_ets_eSignature_88 OBJ_id_smime_mod,5L + +#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97" +#define NID_id_smime_mod_ets_eSignature_97 201 +#define OBJ_id_smime_mod_ets_eSignature_97 OBJ_id_smime_mod,6L + +#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88" +#define NID_id_smime_mod_ets_eSigPolicy_88 202 +#define OBJ_id_smime_mod_ets_eSigPolicy_88 OBJ_id_smime_mod,7L + +#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97" +#define NID_id_smime_mod_ets_eSigPolicy_97 203 +#define OBJ_id_smime_mod_ets_eSigPolicy_97 OBJ_id_smime_mod,8L + +#define SN_id_smime_ct_receipt "id-smime-ct-receipt" +#define NID_id_smime_ct_receipt 204 +#define OBJ_id_smime_ct_receipt OBJ_id_smime_ct,1L + +#define SN_id_smime_ct_authData "id-smime-ct-authData" +#define NID_id_smime_ct_authData 205 +#define OBJ_id_smime_ct_authData OBJ_id_smime_ct,2L + +#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert" +#define NID_id_smime_ct_publishCert 206 +#define OBJ_id_smime_ct_publishCert OBJ_id_smime_ct,3L + +#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo" +#define NID_id_smime_ct_TSTInfo 207 +#define OBJ_id_smime_ct_TSTInfo OBJ_id_smime_ct,4L + +#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo" +#define NID_id_smime_ct_TDTInfo 208 +#define OBJ_id_smime_ct_TDTInfo OBJ_id_smime_ct,5L + +#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo" +#define NID_id_smime_ct_contentInfo 209 +#define OBJ_id_smime_ct_contentInfo OBJ_id_smime_ct,6L + +#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData" +#define NID_id_smime_ct_DVCSRequestData 210 +#define OBJ_id_smime_ct_DVCSRequestData OBJ_id_smime_ct,7L + +#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData" +#define NID_id_smime_ct_DVCSResponseData 211 +#define OBJ_id_smime_ct_DVCSResponseData OBJ_id_smime_ct,8L + +#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData" +#define NID_id_smime_ct_compressedData 786 +#define OBJ_id_smime_ct_compressedData OBJ_id_smime_ct,9L + +#define SN_id_smime_ct_contentCollection "id-smime-ct-contentCollection" +#define NID_id_smime_ct_contentCollection 1058 +#define OBJ_id_smime_ct_contentCollection OBJ_id_smime_ct,19L + +#define SN_id_smime_ct_authEnvelopedData "id-smime-ct-authEnvelopedData" +#define NID_id_smime_ct_authEnvelopedData 1059 +#define OBJ_id_smime_ct_authEnvelopedData OBJ_id_smime_ct,23L + +#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF" +#define NID_id_ct_asciiTextWithCRLF 787 +#define OBJ_id_ct_asciiTextWithCRLF OBJ_id_smime_ct,27L + +#define SN_id_ct_xml "id-ct-xml" +#define NID_id_ct_xml 1060 +#define OBJ_id_ct_xml OBJ_id_smime_ct,28L + +#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest" +#define NID_id_smime_aa_receiptRequest 212 +#define OBJ_id_smime_aa_receiptRequest OBJ_id_smime_aa,1L + +#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel" +#define NID_id_smime_aa_securityLabel 213 +#define OBJ_id_smime_aa_securityLabel OBJ_id_smime_aa,2L + +#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory" +#define NID_id_smime_aa_mlExpandHistory 214 +#define OBJ_id_smime_aa_mlExpandHistory OBJ_id_smime_aa,3L + +#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint" +#define NID_id_smime_aa_contentHint 215 +#define OBJ_id_smime_aa_contentHint OBJ_id_smime_aa,4L + +#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest" +#define NID_id_smime_aa_msgSigDigest 216 +#define OBJ_id_smime_aa_msgSigDigest OBJ_id_smime_aa,5L + +#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType" +#define NID_id_smime_aa_encapContentType 217 +#define OBJ_id_smime_aa_encapContentType OBJ_id_smime_aa,6L + +#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier" +#define NID_id_smime_aa_contentIdentifier 218 +#define OBJ_id_smime_aa_contentIdentifier OBJ_id_smime_aa,7L + +#define SN_id_smime_aa_macValue "id-smime-aa-macValue" +#define NID_id_smime_aa_macValue 219 +#define OBJ_id_smime_aa_macValue OBJ_id_smime_aa,8L + +#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels" +#define NID_id_smime_aa_equivalentLabels 220 +#define OBJ_id_smime_aa_equivalentLabels OBJ_id_smime_aa,9L + +#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference" +#define NID_id_smime_aa_contentReference 221 +#define OBJ_id_smime_aa_contentReference OBJ_id_smime_aa,10L + +#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref" +#define NID_id_smime_aa_encrypKeyPref 222 +#define OBJ_id_smime_aa_encrypKeyPref OBJ_id_smime_aa,11L + +#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate" +#define NID_id_smime_aa_signingCertificate 223 +#define OBJ_id_smime_aa_signingCertificate OBJ_id_smime_aa,12L + +#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts" +#define NID_id_smime_aa_smimeEncryptCerts 224 +#define OBJ_id_smime_aa_smimeEncryptCerts OBJ_id_smime_aa,13L + +#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken" +#define NID_id_smime_aa_timeStampToken 225 +#define OBJ_id_smime_aa_timeStampToken OBJ_id_smime_aa,14L + +#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId" +#define NID_id_smime_aa_ets_sigPolicyId 226 +#define OBJ_id_smime_aa_ets_sigPolicyId OBJ_id_smime_aa,15L + +#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType" +#define NID_id_smime_aa_ets_commitmentType 227 +#define OBJ_id_smime_aa_ets_commitmentType OBJ_id_smime_aa,16L + +#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation" +#define NID_id_smime_aa_ets_signerLocation 228 +#define OBJ_id_smime_aa_ets_signerLocation OBJ_id_smime_aa,17L + +#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr" +#define NID_id_smime_aa_ets_signerAttr 229 +#define OBJ_id_smime_aa_ets_signerAttr OBJ_id_smime_aa,18L + +#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert" +#define NID_id_smime_aa_ets_otherSigCert 230 +#define OBJ_id_smime_aa_ets_otherSigCert OBJ_id_smime_aa,19L + +#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp" +#define NID_id_smime_aa_ets_contentTimestamp 231 +#define OBJ_id_smime_aa_ets_contentTimestamp OBJ_id_smime_aa,20L + +#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs" +#define NID_id_smime_aa_ets_CertificateRefs 232 +#define OBJ_id_smime_aa_ets_CertificateRefs OBJ_id_smime_aa,21L + +#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs" +#define NID_id_smime_aa_ets_RevocationRefs 233 +#define OBJ_id_smime_aa_ets_RevocationRefs OBJ_id_smime_aa,22L + +#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues" +#define NID_id_smime_aa_ets_certValues 234 +#define OBJ_id_smime_aa_ets_certValues OBJ_id_smime_aa,23L + +#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues" +#define NID_id_smime_aa_ets_revocationValues 235 +#define OBJ_id_smime_aa_ets_revocationValues OBJ_id_smime_aa,24L + +#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp" +#define NID_id_smime_aa_ets_escTimeStamp 236 +#define OBJ_id_smime_aa_ets_escTimeStamp OBJ_id_smime_aa,25L + +#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp" +#define NID_id_smime_aa_ets_certCRLTimestamp 237 +#define OBJ_id_smime_aa_ets_certCRLTimestamp OBJ_id_smime_aa,26L + +#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp" +#define NID_id_smime_aa_ets_archiveTimeStamp 238 +#define OBJ_id_smime_aa_ets_archiveTimeStamp OBJ_id_smime_aa,27L + +#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType" +#define NID_id_smime_aa_signatureType 239 +#define OBJ_id_smime_aa_signatureType OBJ_id_smime_aa,28L + +#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc" +#define NID_id_smime_aa_dvcs_dvc 240 +#define OBJ_id_smime_aa_dvcs_dvc OBJ_id_smime_aa,29L + +#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES" +#define NID_id_smime_alg_ESDHwith3DES 241 +#define OBJ_id_smime_alg_ESDHwith3DES OBJ_id_smime_alg,1L + +#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2" +#define NID_id_smime_alg_ESDHwithRC2 242 +#define OBJ_id_smime_alg_ESDHwithRC2 OBJ_id_smime_alg,2L + +#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap" +#define NID_id_smime_alg_3DESwrap 243 +#define OBJ_id_smime_alg_3DESwrap OBJ_id_smime_alg,3L + +#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap" +#define NID_id_smime_alg_RC2wrap 244 +#define OBJ_id_smime_alg_RC2wrap OBJ_id_smime_alg,4L + +#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH" +#define NID_id_smime_alg_ESDH 245 +#define OBJ_id_smime_alg_ESDH OBJ_id_smime_alg,5L + +#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap" +#define NID_id_smime_alg_CMS3DESwrap 246 +#define OBJ_id_smime_alg_CMS3DESwrap OBJ_id_smime_alg,6L + +#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap" +#define NID_id_smime_alg_CMSRC2wrap 247 +#define OBJ_id_smime_alg_CMSRC2wrap OBJ_id_smime_alg,7L + +#define SN_id_alg_PWRI_KEK "id-alg-PWRI-KEK" +#define NID_id_alg_PWRI_KEK 893 +#define OBJ_id_alg_PWRI_KEK OBJ_id_smime_alg,9L + +#define SN_id_smime_cd_ldap "id-smime-cd-ldap" +#define NID_id_smime_cd_ldap 248 +#define OBJ_id_smime_cd_ldap OBJ_id_smime_cd,1L + +#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri" +#define NID_id_smime_spq_ets_sqt_uri 249 +#define OBJ_id_smime_spq_ets_sqt_uri OBJ_id_smime_spq,1L + +#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice" +#define NID_id_smime_spq_ets_sqt_unotice 250 +#define OBJ_id_smime_spq_ets_sqt_unotice OBJ_id_smime_spq,2L + +#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin" +#define NID_id_smime_cti_ets_proofOfOrigin 251 +#define OBJ_id_smime_cti_ets_proofOfOrigin OBJ_id_smime_cti,1L + +#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt" +#define NID_id_smime_cti_ets_proofOfReceipt 252 +#define OBJ_id_smime_cti_ets_proofOfReceipt OBJ_id_smime_cti,2L + +#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery" +#define NID_id_smime_cti_ets_proofOfDelivery 253 +#define OBJ_id_smime_cti_ets_proofOfDelivery OBJ_id_smime_cti,3L + +#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender" +#define NID_id_smime_cti_ets_proofOfSender 254 +#define OBJ_id_smime_cti_ets_proofOfSender OBJ_id_smime_cti,4L + +#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval" +#define NID_id_smime_cti_ets_proofOfApproval 255 +#define OBJ_id_smime_cti_ets_proofOfApproval OBJ_id_smime_cti,5L + +#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation" +#define NID_id_smime_cti_ets_proofOfCreation 256 +#define OBJ_id_smime_cti_ets_proofOfCreation OBJ_id_smime_cti,6L + +#define LN_friendlyName "friendlyName" +#define NID_friendlyName 156 +#define OBJ_friendlyName OBJ_pkcs9,20L + +#define LN_localKeyID "localKeyID" +#define NID_localKeyID 157 +#define OBJ_localKeyID OBJ_pkcs9,21L + +#define SN_ms_csp_name "CSPName" +#define LN_ms_csp_name "Microsoft CSP Name" +#define NID_ms_csp_name 417 +#define OBJ_ms_csp_name 1L,3L,6L,1L,4L,1L,311L,17L,1L + +#define SN_LocalKeySet "LocalKeySet" +#define LN_LocalKeySet "Microsoft Local Key set" +#define NID_LocalKeySet 856 +#define OBJ_LocalKeySet 1L,3L,6L,1L,4L,1L,311L,17L,2L + +#define OBJ_certTypes OBJ_pkcs9,22L + +#define LN_x509Certificate "x509Certificate" +#define NID_x509Certificate 158 +#define OBJ_x509Certificate OBJ_certTypes,1L + +#define LN_sdsiCertificate "sdsiCertificate" +#define NID_sdsiCertificate 159 +#define OBJ_sdsiCertificate OBJ_certTypes,2L + +#define OBJ_crlTypes OBJ_pkcs9,23L + +#define LN_x509Crl "x509Crl" +#define NID_x509Crl 160 +#define OBJ_x509Crl OBJ_crlTypes,1L + +#define OBJ_pkcs12 OBJ_pkcs,12L + +#define OBJ_pkcs12_pbeids OBJ_pkcs12,1L + +#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" +#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" +#define NID_pbe_WithSHA1And128BitRC4 144 +#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids,1L + +#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" +#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" +#define NID_pbe_WithSHA1And40BitRC4 145 +#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids,2L + +#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" +#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 +#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids,3L + +#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" +#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 +#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids,4L + +#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" +#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" +#define NID_pbe_WithSHA1And128BitRC2_CBC 148 +#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids,5L + +#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" +#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" +#define NID_pbe_WithSHA1And40BitRC2_CBC 149 +#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids,6L + +#define OBJ_pkcs12_Version1 OBJ_pkcs12,10L + +#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1,1L + +#define LN_keyBag "keyBag" +#define NID_keyBag 150 +#define OBJ_keyBag OBJ_pkcs12_BagIds,1L + +#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" +#define NID_pkcs8ShroudedKeyBag 151 +#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds,2L + +#define LN_certBag "certBag" +#define NID_certBag 152 +#define OBJ_certBag OBJ_pkcs12_BagIds,3L + +#define LN_crlBag "crlBag" +#define NID_crlBag 153 +#define OBJ_crlBag OBJ_pkcs12_BagIds,4L + +#define LN_secretBag "secretBag" +#define NID_secretBag 154 +#define OBJ_secretBag OBJ_pkcs12_BagIds,5L + +#define LN_safeContentsBag "safeContentsBag" +#define NID_safeContentsBag 155 +#define OBJ_safeContentsBag OBJ_pkcs12_BagIds,6L + +#define SN_md2 "MD2" +#define LN_md2 "md2" +#define NID_md2 3 +#define OBJ_md2 OBJ_rsadsi,2L,2L + +#define SN_md4 "MD4" +#define LN_md4 "md4" +#define NID_md4 257 +#define OBJ_md4 OBJ_rsadsi,2L,4L + +#define SN_md5 "MD5" +#define LN_md5 "md5" +#define NID_md5 4 +#define OBJ_md5 OBJ_rsadsi,2L,5L + +#define SN_md5_sha1 "MD5-SHA1" +#define LN_md5_sha1 "md5-sha1" +#define NID_md5_sha1 114 + +#define LN_hmacWithMD5 "hmacWithMD5" +#define NID_hmacWithMD5 797 +#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L + +#define LN_hmacWithSHA1 "hmacWithSHA1" +#define NID_hmacWithSHA1 163 +#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L + +#define LN_hmacWithSHA224 "hmacWithSHA224" +#define NID_hmacWithSHA224 798 +#define OBJ_hmacWithSHA224 OBJ_rsadsi,2L,8L + +#define LN_hmacWithSHA256 "hmacWithSHA256" +#define NID_hmacWithSHA256 799 +#define OBJ_hmacWithSHA256 OBJ_rsadsi,2L,9L + +#define LN_hmacWithSHA384 "hmacWithSHA384" +#define NID_hmacWithSHA384 800 +#define OBJ_hmacWithSHA384 OBJ_rsadsi,2L,10L + +#define LN_hmacWithSHA512 "hmacWithSHA512" +#define NID_hmacWithSHA512 801 +#define OBJ_hmacWithSHA512 OBJ_rsadsi,2L,11L + +#define SN_rc2_cbc "RC2-CBC" +#define LN_rc2_cbc "rc2-cbc" +#define NID_rc2_cbc 37 +#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L + +#define SN_rc2_ecb "RC2-ECB" +#define LN_rc2_ecb "rc2-ecb" +#define NID_rc2_ecb 38 + +#define SN_rc2_cfb64 "RC2-CFB" +#define LN_rc2_cfb64 "rc2-cfb" +#define NID_rc2_cfb64 39 + +#define SN_rc2_ofb64 "RC2-OFB" +#define LN_rc2_ofb64 "rc2-ofb" +#define NID_rc2_ofb64 40 + +#define SN_rc2_40_cbc "RC2-40-CBC" +#define LN_rc2_40_cbc "rc2-40-cbc" +#define NID_rc2_40_cbc 98 + +#define SN_rc2_64_cbc "RC2-64-CBC" +#define LN_rc2_64_cbc "rc2-64-cbc" +#define NID_rc2_64_cbc 166 + +#define SN_rc4 "RC4" +#define LN_rc4 "rc4" +#define NID_rc4 5 +#define OBJ_rc4 OBJ_rsadsi,3L,4L + +#define SN_rc4_40 "RC4-40" +#define LN_rc4_40 "rc4-40" +#define NID_rc4_40 97 + +#define SN_des_ede3_cbc "DES-EDE3-CBC" +#define LN_des_ede3_cbc "des-ede3-cbc" +#define NID_des_ede3_cbc 44 +#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L + +#define SN_rc5_cbc "RC5-CBC" +#define LN_rc5_cbc "rc5-cbc" +#define NID_rc5_cbc 120 +#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L + +#define SN_rc5_ecb "RC5-ECB" +#define LN_rc5_ecb "rc5-ecb" +#define NID_rc5_ecb 121 + +#define SN_rc5_cfb64 "RC5-CFB" +#define LN_rc5_cfb64 "rc5-cfb" +#define NID_rc5_cfb64 122 + +#define SN_rc5_ofb64 "RC5-OFB" +#define LN_rc5_ofb64 "rc5-ofb" +#define NID_rc5_ofb64 123 + +#define SN_ms_ext_req "msExtReq" +#define LN_ms_ext_req "Microsoft Extension Request" +#define NID_ms_ext_req 171 +#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L + +#define SN_ms_code_ind "msCodeInd" +#define LN_ms_code_ind "Microsoft Individual Code Signing" +#define NID_ms_code_ind 134 +#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L + +#define SN_ms_code_com "msCodeCom" +#define LN_ms_code_com "Microsoft Commercial Code Signing" +#define NID_ms_code_com 135 +#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L + +#define SN_ms_ctl_sign "msCTLSign" +#define LN_ms_ctl_sign "Microsoft Trust List Signing" +#define NID_ms_ctl_sign 136 +#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L + +#define SN_ms_sgc "msSGC" +#define LN_ms_sgc "Microsoft Server Gated Crypto" +#define NID_ms_sgc 137 +#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L + +#define SN_ms_efs "msEFS" +#define LN_ms_efs "Microsoft Encrypted File System" +#define NID_ms_efs 138 +#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L + +#define SN_ms_smartcard_login "msSmartcardLogin" +#define LN_ms_smartcard_login "Microsoft Smartcardlogin" +#define NID_ms_smartcard_login 648 +#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L + +#define SN_ms_upn "msUPN" +#define LN_ms_upn "Microsoft Universal Principal Name" +#define NID_ms_upn 649 +#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L + +#define SN_idea_cbc "IDEA-CBC" +#define LN_idea_cbc "idea-cbc" +#define NID_idea_cbc 34 +#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L + +#define SN_idea_ecb "IDEA-ECB" +#define LN_idea_ecb "idea-ecb" +#define NID_idea_ecb 36 + +#define SN_idea_cfb64 "IDEA-CFB" +#define LN_idea_cfb64 "idea-cfb" +#define NID_idea_cfb64 35 + +#define SN_idea_ofb64 "IDEA-OFB" +#define LN_idea_ofb64 "idea-ofb" +#define NID_idea_ofb64 46 + +#define SN_bf_cbc "BF-CBC" +#define LN_bf_cbc "bf-cbc" +#define NID_bf_cbc 91 +#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L + +#define SN_bf_ecb "BF-ECB" +#define LN_bf_ecb "bf-ecb" +#define NID_bf_ecb 92 + +#define SN_bf_cfb64 "BF-CFB" +#define LN_bf_cfb64 "bf-cfb" +#define NID_bf_cfb64 93 + +#define SN_bf_ofb64 "BF-OFB" +#define LN_bf_ofb64 "bf-ofb" +#define NID_bf_ofb64 94 + +#define SN_id_pkix "PKIX" +#define NID_id_pkix 127 +#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L + +#define SN_id_pkix_mod "id-pkix-mod" +#define NID_id_pkix_mod 258 +#define OBJ_id_pkix_mod OBJ_id_pkix,0L + +#define SN_id_pe "id-pe" +#define NID_id_pe 175 +#define OBJ_id_pe OBJ_id_pkix,1L + +#define SN_id_qt "id-qt" +#define NID_id_qt 259 +#define OBJ_id_qt OBJ_id_pkix,2L + +#define SN_id_kp "id-kp" +#define NID_id_kp 128 +#define OBJ_id_kp OBJ_id_pkix,3L + +#define SN_id_it "id-it" +#define NID_id_it 260 +#define OBJ_id_it OBJ_id_pkix,4L + +#define SN_id_pkip "id-pkip" +#define NID_id_pkip 261 +#define OBJ_id_pkip OBJ_id_pkix,5L + +#define SN_id_alg "id-alg" +#define NID_id_alg 262 +#define OBJ_id_alg OBJ_id_pkix,6L + +#define SN_id_cmc "id-cmc" +#define NID_id_cmc 263 +#define OBJ_id_cmc OBJ_id_pkix,7L + +#define SN_id_on "id-on" +#define NID_id_on 264 +#define OBJ_id_on OBJ_id_pkix,8L + +#define SN_id_pda "id-pda" +#define NID_id_pda 265 +#define OBJ_id_pda OBJ_id_pkix,9L + +#define SN_id_aca "id-aca" +#define NID_id_aca 266 +#define OBJ_id_aca OBJ_id_pkix,10L + +#define SN_id_qcs "id-qcs" +#define NID_id_qcs 267 +#define OBJ_id_qcs OBJ_id_pkix,11L + +#define SN_id_cct "id-cct" +#define NID_id_cct 268 +#define OBJ_id_cct OBJ_id_pkix,12L + +#define SN_id_ppl "id-ppl" +#define NID_id_ppl 662 +#define OBJ_id_ppl OBJ_id_pkix,21L + +#define SN_id_ad "id-ad" +#define NID_id_ad 176 +#define OBJ_id_ad OBJ_id_pkix,48L + +#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88" +#define NID_id_pkix1_explicit_88 269 +#define OBJ_id_pkix1_explicit_88 OBJ_id_pkix_mod,1L + +#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88" +#define NID_id_pkix1_implicit_88 270 +#define OBJ_id_pkix1_implicit_88 OBJ_id_pkix_mod,2L + +#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93" +#define NID_id_pkix1_explicit_93 271 +#define OBJ_id_pkix1_explicit_93 OBJ_id_pkix_mod,3L + +#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93" +#define NID_id_pkix1_implicit_93 272 +#define OBJ_id_pkix1_implicit_93 OBJ_id_pkix_mod,4L + +#define SN_id_mod_crmf "id-mod-crmf" +#define NID_id_mod_crmf 273 +#define OBJ_id_mod_crmf OBJ_id_pkix_mod,5L + +#define SN_id_mod_cmc "id-mod-cmc" +#define NID_id_mod_cmc 274 +#define OBJ_id_mod_cmc OBJ_id_pkix_mod,6L + +#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88" +#define NID_id_mod_kea_profile_88 275 +#define OBJ_id_mod_kea_profile_88 OBJ_id_pkix_mod,7L + +#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93" +#define NID_id_mod_kea_profile_93 276 +#define OBJ_id_mod_kea_profile_93 OBJ_id_pkix_mod,8L + +#define SN_id_mod_cmp "id-mod-cmp" +#define NID_id_mod_cmp 277 +#define OBJ_id_mod_cmp OBJ_id_pkix_mod,9L + +#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88" +#define NID_id_mod_qualified_cert_88 278 +#define OBJ_id_mod_qualified_cert_88 OBJ_id_pkix_mod,10L + +#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93" +#define NID_id_mod_qualified_cert_93 279 +#define OBJ_id_mod_qualified_cert_93 OBJ_id_pkix_mod,11L + +#define SN_id_mod_attribute_cert "id-mod-attribute-cert" +#define NID_id_mod_attribute_cert 280 +#define OBJ_id_mod_attribute_cert OBJ_id_pkix_mod,12L + +#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol" +#define NID_id_mod_timestamp_protocol 281 +#define OBJ_id_mod_timestamp_protocol OBJ_id_pkix_mod,13L + +#define SN_id_mod_ocsp "id-mod-ocsp" +#define NID_id_mod_ocsp 282 +#define OBJ_id_mod_ocsp OBJ_id_pkix_mod,14L + +#define SN_id_mod_dvcs "id-mod-dvcs" +#define NID_id_mod_dvcs 283 +#define OBJ_id_mod_dvcs OBJ_id_pkix_mod,15L + +#define SN_id_mod_cmp2000 "id-mod-cmp2000" +#define NID_id_mod_cmp2000 284 +#define OBJ_id_mod_cmp2000 OBJ_id_pkix_mod,16L + +#define SN_info_access "authorityInfoAccess" +#define LN_info_access "Authority Information Access" +#define NID_info_access 177 +#define OBJ_info_access OBJ_id_pe,1L + +#define SN_biometricInfo "biometricInfo" +#define LN_biometricInfo "Biometric Info" +#define NID_biometricInfo 285 +#define OBJ_biometricInfo OBJ_id_pe,2L + +#define SN_qcStatements "qcStatements" +#define NID_qcStatements 286 +#define OBJ_qcStatements OBJ_id_pe,3L + +#define SN_ac_auditEntity "ac-auditEntity" +#define NID_ac_auditEntity 287 +#define OBJ_ac_auditEntity OBJ_id_pe,4L + +#define SN_ac_targeting "ac-targeting" +#define NID_ac_targeting 288 +#define OBJ_ac_targeting OBJ_id_pe,5L + +#define SN_aaControls "aaControls" +#define NID_aaControls 289 +#define OBJ_aaControls OBJ_id_pe,6L + +#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock" +#define NID_sbgp_ipAddrBlock 290 +#define OBJ_sbgp_ipAddrBlock OBJ_id_pe,7L + +#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum" +#define NID_sbgp_autonomousSysNum 291 +#define OBJ_sbgp_autonomousSysNum OBJ_id_pe,8L + +#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier" +#define NID_sbgp_routerIdentifier 292 +#define OBJ_sbgp_routerIdentifier OBJ_id_pe,9L + +#define SN_ac_proxying "ac-proxying" +#define NID_ac_proxying 397 +#define OBJ_ac_proxying OBJ_id_pe,10L + +#define SN_sinfo_access "subjectInfoAccess" +#define LN_sinfo_access "Subject Information Access" +#define NID_sinfo_access 398 +#define OBJ_sinfo_access OBJ_id_pe,11L + +#define SN_proxyCertInfo "proxyCertInfo" +#define LN_proxyCertInfo "Proxy Certificate Information" +#define NID_proxyCertInfo 663 +#define OBJ_proxyCertInfo OBJ_id_pe,14L + +#define SN_tlsfeature "tlsfeature" +#define LN_tlsfeature "TLS Feature" +#define NID_tlsfeature 1020 +#define OBJ_tlsfeature OBJ_id_pe,24L + +#define SN_id_qt_cps "id-qt-cps" +#define LN_id_qt_cps "Policy Qualifier CPS" +#define NID_id_qt_cps 164 +#define OBJ_id_qt_cps OBJ_id_qt,1L + +#define SN_id_qt_unotice "id-qt-unotice" +#define LN_id_qt_unotice "Policy Qualifier User Notice" +#define NID_id_qt_unotice 165 +#define OBJ_id_qt_unotice OBJ_id_qt,2L + +#define SN_textNotice "textNotice" +#define NID_textNotice 293 +#define OBJ_textNotice OBJ_id_qt,3L + +#define SN_server_auth "serverAuth" +#define LN_server_auth "TLS Web Server Authentication" +#define NID_server_auth 129 +#define OBJ_server_auth OBJ_id_kp,1L + +#define SN_client_auth "clientAuth" +#define LN_client_auth "TLS Web Client Authentication" +#define NID_client_auth 130 +#define OBJ_client_auth OBJ_id_kp,2L + +#define SN_code_sign "codeSigning" +#define LN_code_sign "Code Signing" +#define NID_code_sign 131 +#define OBJ_code_sign OBJ_id_kp,3L + +#define SN_email_protect "emailProtection" +#define LN_email_protect "E-mail Protection" +#define NID_email_protect 132 +#define OBJ_email_protect OBJ_id_kp,4L + +#define SN_ipsecEndSystem "ipsecEndSystem" +#define LN_ipsecEndSystem "IPSec End System" +#define NID_ipsecEndSystem 294 +#define OBJ_ipsecEndSystem OBJ_id_kp,5L + +#define SN_ipsecTunnel "ipsecTunnel" +#define LN_ipsecTunnel "IPSec Tunnel" +#define NID_ipsecTunnel 295 +#define OBJ_ipsecTunnel OBJ_id_kp,6L + +#define SN_ipsecUser "ipsecUser" +#define LN_ipsecUser "IPSec User" +#define NID_ipsecUser 296 +#define OBJ_ipsecUser OBJ_id_kp,7L + +#define SN_time_stamp "timeStamping" +#define LN_time_stamp "Time Stamping" +#define NID_time_stamp 133 +#define OBJ_time_stamp OBJ_id_kp,8L + +#define SN_OCSP_sign "OCSPSigning" +#define LN_OCSP_sign "OCSP Signing" +#define NID_OCSP_sign 180 +#define OBJ_OCSP_sign OBJ_id_kp,9L + +#define SN_dvcs "DVCS" +#define LN_dvcs "dvcs" +#define NID_dvcs 297 +#define OBJ_dvcs OBJ_id_kp,10L + +#define SN_ipsec_IKE "ipsecIKE" +#define LN_ipsec_IKE "ipsec Internet Key Exchange" +#define NID_ipsec_IKE 1022 +#define OBJ_ipsec_IKE OBJ_id_kp,17L + +#define SN_capwapAC "capwapAC" +#define LN_capwapAC "Ctrl/provision WAP Access" +#define NID_capwapAC 1023 +#define OBJ_capwapAC OBJ_id_kp,18L + +#define SN_capwapWTP "capwapWTP" +#define LN_capwapWTP "Ctrl/Provision WAP Termination" +#define NID_capwapWTP 1024 +#define OBJ_capwapWTP OBJ_id_kp,19L + +#define SN_sshClient "secureShellClient" +#define LN_sshClient "SSH Client" +#define NID_sshClient 1025 +#define OBJ_sshClient OBJ_id_kp,21L + +#define SN_sshServer "secureShellServer" +#define LN_sshServer "SSH Server" +#define NID_sshServer 1026 +#define OBJ_sshServer OBJ_id_kp,22L + +#define SN_sendRouter "sendRouter" +#define LN_sendRouter "Send Router" +#define NID_sendRouter 1027 +#define OBJ_sendRouter OBJ_id_kp,23L + +#define SN_sendProxiedRouter "sendProxiedRouter" +#define LN_sendProxiedRouter "Send Proxied Router" +#define NID_sendProxiedRouter 1028 +#define OBJ_sendProxiedRouter OBJ_id_kp,24L + +#define SN_sendOwner "sendOwner" +#define LN_sendOwner "Send Owner" +#define NID_sendOwner 1029 +#define OBJ_sendOwner OBJ_id_kp,25L + +#define SN_sendProxiedOwner "sendProxiedOwner" +#define LN_sendProxiedOwner "Send Proxied Owner" +#define NID_sendProxiedOwner 1030 +#define OBJ_sendProxiedOwner OBJ_id_kp,26L + +#define SN_id_it_caProtEncCert "id-it-caProtEncCert" +#define NID_id_it_caProtEncCert 298 +#define OBJ_id_it_caProtEncCert OBJ_id_it,1L + +#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes" +#define NID_id_it_signKeyPairTypes 299 +#define OBJ_id_it_signKeyPairTypes OBJ_id_it,2L + +#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes" +#define NID_id_it_encKeyPairTypes 300 +#define OBJ_id_it_encKeyPairTypes OBJ_id_it,3L + +#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg" +#define NID_id_it_preferredSymmAlg 301 +#define OBJ_id_it_preferredSymmAlg OBJ_id_it,4L + +#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo" +#define NID_id_it_caKeyUpdateInfo 302 +#define OBJ_id_it_caKeyUpdateInfo OBJ_id_it,5L + +#define SN_id_it_currentCRL "id-it-currentCRL" +#define NID_id_it_currentCRL 303 +#define OBJ_id_it_currentCRL OBJ_id_it,6L + +#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs" +#define NID_id_it_unsupportedOIDs 304 +#define OBJ_id_it_unsupportedOIDs OBJ_id_it,7L + +#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest" +#define NID_id_it_subscriptionRequest 305 +#define OBJ_id_it_subscriptionRequest OBJ_id_it,8L + +#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse" +#define NID_id_it_subscriptionResponse 306 +#define OBJ_id_it_subscriptionResponse OBJ_id_it,9L + +#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq" +#define NID_id_it_keyPairParamReq 307 +#define OBJ_id_it_keyPairParamReq OBJ_id_it,10L + +#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep" +#define NID_id_it_keyPairParamRep 308 +#define OBJ_id_it_keyPairParamRep OBJ_id_it,11L + +#define SN_id_it_revPassphrase "id-it-revPassphrase" +#define NID_id_it_revPassphrase 309 +#define OBJ_id_it_revPassphrase OBJ_id_it,12L + +#define SN_id_it_implicitConfirm "id-it-implicitConfirm" +#define NID_id_it_implicitConfirm 310 +#define OBJ_id_it_implicitConfirm OBJ_id_it,13L + +#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime" +#define NID_id_it_confirmWaitTime 311 +#define OBJ_id_it_confirmWaitTime OBJ_id_it,14L + +#define SN_id_it_origPKIMessage "id-it-origPKIMessage" +#define NID_id_it_origPKIMessage 312 +#define OBJ_id_it_origPKIMessage OBJ_id_it,15L + +#define SN_id_it_suppLangTags "id-it-suppLangTags" +#define NID_id_it_suppLangTags 784 +#define OBJ_id_it_suppLangTags OBJ_id_it,16L + +#define SN_id_regCtrl "id-regCtrl" +#define NID_id_regCtrl 313 +#define OBJ_id_regCtrl OBJ_id_pkip,1L + +#define SN_id_regInfo "id-regInfo" +#define NID_id_regInfo 314 +#define OBJ_id_regInfo OBJ_id_pkip,2L + +#define SN_id_regCtrl_regToken "id-regCtrl-regToken" +#define NID_id_regCtrl_regToken 315 +#define OBJ_id_regCtrl_regToken OBJ_id_regCtrl,1L + +#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator" +#define NID_id_regCtrl_authenticator 316 +#define OBJ_id_regCtrl_authenticator OBJ_id_regCtrl,2L + +#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo" +#define NID_id_regCtrl_pkiPublicationInfo 317 +#define OBJ_id_regCtrl_pkiPublicationInfo OBJ_id_regCtrl,3L + +#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions" +#define NID_id_regCtrl_pkiArchiveOptions 318 +#define OBJ_id_regCtrl_pkiArchiveOptions OBJ_id_regCtrl,4L + +#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID" +#define NID_id_regCtrl_oldCertID 319 +#define OBJ_id_regCtrl_oldCertID OBJ_id_regCtrl,5L + +#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey" +#define NID_id_regCtrl_protocolEncrKey 320 +#define OBJ_id_regCtrl_protocolEncrKey OBJ_id_regCtrl,6L + +#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs" +#define NID_id_regInfo_utf8Pairs 321 +#define OBJ_id_regInfo_utf8Pairs OBJ_id_regInfo,1L + +#define SN_id_regInfo_certReq "id-regInfo-certReq" +#define NID_id_regInfo_certReq 322 +#define OBJ_id_regInfo_certReq OBJ_id_regInfo,2L + +#define SN_id_alg_des40 "id-alg-des40" +#define NID_id_alg_des40 323 +#define OBJ_id_alg_des40 OBJ_id_alg,1L + +#define SN_id_alg_noSignature "id-alg-noSignature" +#define NID_id_alg_noSignature 324 +#define OBJ_id_alg_noSignature OBJ_id_alg,2L + +#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1" +#define NID_id_alg_dh_sig_hmac_sha1 325 +#define OBJ_id_alg_dh_sig_hmac_sha1 OBJ_id_alg,3L + +#define SN_id_alg_dh_pop "id-alg-dh-pop" +#define NID_id_alg_dh_pop 326 +#define OBJ_id_alg_dh_pop OBJ_id_alg,4L + +#define SN_id_cmc_statusInfo "id-cmc-statusInfo" +#define NID_id_cmc_statusInfo 327 +#define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L + +#define SN_id_cmc_identification "id-cmc-identification" +#define NID_id_cmc_identification 328 +#define OBJ_id_cmc_identification OBJ_id_cmc,2L + +#define SN_id_cmc_identityProof "id-cmc-identityProof" +#define NID_id_cmc_identityProof 329 +#define OBJ_id_cmc_identityProof OBJ_id_cmc,3L + +#define SN_id_cmc_dataReturn "id-cmc-dataReturn" +#define NID_id_cmc_dataReturn 330 +#define OBJ_id_cmc_dataReturn OBJ_id_cmc,4L + +#define SN_id_cmc_transactionId "id-cmc-transactionId" +#define NID_id_cmc_transactionId 331 +#define OBJ_id_cmc_transactionId OBJ_id_cmc,5L + +#define SN_id_cmc_senderNonce "id-cmc-senderNonce" +#define NID_id_cmc_senderNonce 332 +#define OBJ_id_cmc_senderNonce OBJ_id_cmc,6L + +#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce" +#define NID_id_cmc_recipientNonce 333 +#define OBJ_id_cmc_recipientNonce OBJ_id_cmc,7L + +#define SN_id_cmc_addExtensions "id-cmc-addExtensions" +#define NID_id_cmc_addExtensions 334 +#define OBJ_id_cmc_addExtensions OBJ_id_cmc,8L + +#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP" +#define NID_id_cmc_encryptedPOP 335 +#define OBJ_id_cmc_encryptedPOP OBJ_id_cmc,9L + +#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP" +#define NID_id_cmc_decryptedPOP 336 +#define OBJ_id_cmc_decryptedPOP OBJ_id_cmc,10L + +#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness" +#define NID_id_cmc_lraPOPWitness 337 +#define OBJ_id_cmc_lraPOPWitness OBJ_id_cmc,11L + +#define SN_id_cmc_getCert "id-cmc-getCert" +#define NID_id_cmc_getCert 338 +#define OBJ_id_cmc_getCert OBJ_id_cmc,15L + +#define SN_id_cmc_getCRL "id-cmc-getCRL" +#define NID_id_cmc_getCRL 339 +#define OBJ_id_cmc_getCRL OBJ_id_cmc,16L + +#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest" +#define NID_id_cmc_revokeRequest 340 +#define OBJ_id_cmc_revokeRequest OBJ_id_cmc,17L + +#define SN_id_cmc_regInfo "id-cmc-regInfo" +#define NID_id_cmc_regInfo 341 +#define OBJ_id_cmc_regInfo OBJ_id_cmc,18L + +#define SN_id_cmc_responseInfo "id-cmc-responseInfo" +#define NID_id_cmc_responseInfo 342 +#define OBJ_id_cmc_responseInfo OBJ_id_cmc,19L + +#define SN_id_cmc_queryPending "id-cmc-queryPending" +#define NID_id_cmc_queryPending 343 +#define OBJ_id_cmc_queryPending OBJ_id_cmc,21L + +#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom" +#define NID_id_cmc_popLinkRandom 344 +#define OBJ_id_cmc_popLinkRandom OBJ_id_cmc,22L + +#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness" +#define NID_id_cmc_popLinkWitness 345 +#define OBJ_id_cmc_popLinkWitness OBJ_id_cmc,23L + +#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance" +#define NID_id_cmc_confirmCertAcceptance 346 +#define OBJ_id_cmc_confirmCertAcceptance OBJ_id_cmc,24L + +#define SN_id_on_personalData "id-on-personalData" +#define NID_id_on_personalData 347 +#define OBJ_id_on_personalData OBJ_id_on,1L + +#define SN_id_on_permanentIdentifier "id-on-permanentIdentifier" +#define LN_id_on_permanentIdentifier "Permanent Identifier" +#define NID_id_on_permanentIdentifier 858 +#define OBJ_id_on_permanentIdentifier OBJ_id_on,3L + +#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth" +#define NID_id_pda_dateOfBirth 348 +#define OBJ_id_pda_dateOfBirth OBJ_id_pda,1L + +#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth" +#define NID_id_pda_placeOfBirth 349 +#define OBJ_id_pda_placeOfBirth OBJ_id_pda,2L + +#define SN_id_pda_gender "id-pda-gender" +#define NID_id_pda_gender 351 +#define OBJ_id_pda_gender OBJ_id_pda,3L + +#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship" +#define NID_id_pda_countryOfCitizenship 352 +#define OBJ_id_pda_countryOfCitizenship OBJ_id_pda,4L + +#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence" +#define NID_id_pda_countryOfResidence 353 +#define OBJ_id_pda_countryOfResidence OBJ_id_pda,5L + +#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo" +#define NID_id_aca_authenticationInfo 354 +#define OBJ_id_aca_authenticationInfo OBJ_id_aca,1L + +#define SN_id_aca_accessIdentity "id-aca-accessIdentity" +#define NID_id_aca_accessIdentity 355 +#define OBJ_id_aca_accessIdentity OBJ_id_aca,2L + +#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity" +#define NID_id_aca_chargingIdentity 356 +#define OBJ_id_aca_chargingIdentity OBJ_id_aca,3L + +#define SN_id_aca_group "id-aca-group" +#define NID_id_aca_group 357 +#define OBJ_id_aca_group OBJ_id_aca,4L + +#define SN_id_aca_role "id-aca-role" +#define NID_id_aca_role 358 +#define OBJ_id_aca_role OBJ_id_aca,5L + +#define SN_id_aca_encAttrs "id-aca-encAttrs" +#define NID_id_aca_encAttrs 399 +#define OBJ_id_aca_encAttrs OBJ_id_aca,6L + +#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1" +#define NID_id_qcs_pkixQCSyntax_v1 359 +#define OBJ_id_qcs_pkixQCSyntax_v1 OBJ_id_qcs,1L + +#define SN_id_cct_crs "id-cct-crs" +#define NID_id_cct_crs 360 +#define OBJ_id_cct_crs OBJ_id_cct,1L + +#define SN_id_cct_PKIData "id-cct-PKIData" +#define NID_id_cct_PKIData 361 +#define OBJ_id_cct_PKIData OBJ_id_cct,2L + +#define SN_id_cct_PKIResponse "id-cct-PKIResponse" +#define NID_id_cct_PKIResponse 362 +#define OBJ_id_cct_PKIResponse OBJ_id_cct,3L + +#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage" +#define LN_id_ppl_anyLanguage "Any language" +#define NID_id_ppl_anyLanguage 664 +#define OBJ_id_ppl_anyLanguage OBJ_id_ppl,0L + +#define SN_id_ppl_inheritAll "id-ppl-inheritAll" +#define LN_id_ppl_inheritAll "Inherit all" +#define NID_id_ppl_inheritAll 665 +#define OBJ_id_ppl_inheritAll OBJ_id_ppl,1L + +#define SN_Independent "id-ppl-independent" +#define LN_Independent "Independent" +#define NID_Independent 667 +#define OBJ_Independent OBJ_id_ppl,2L + +#define SN_ad_OCSP "OCSP" +#define LN_ad_OCSP "OCSP" +#define NID_ad_OCSP 178 +#define OBJ_ad_OCSP OBJ_id_ad,1L + +#define SN_ad_ca_issuers "caIssuers" +#define LN_ad_ca_issuers "CA Issuers" +#define NID_ad_ca_issuers 179 +#define OBJ_ad_ca_issuers OBJ_id_ad,2L + +#define SN_ad_timeStamping "ad_timestamping" +#define LN_ad_timeStamping "AD Time Stamping" +#define NID_ad_timeStamping 363 +#define OBJ_ad_timeStamping OBJ_id_ad,3L + +#define SN_ad_dvcs "AD_DVCS" +#define LN_ad_dvcs "ad dvcs" +#define NID_ad_dvcs 364 +#define OBJ_ad_dvcs OBJ_id_ad,4L + +#define SN_caRepository "caRepository" +#define LN_caRepository "CA Repository" +#define NID_caRepository 785 +#define OBJ_caRepository OBJ_id_ad,5L + +#define OBJ_id_pkix_OCSP OBJ_ad_OCSP + +#define SN_id_pkix_OCSP_basic "basicOCSPResponse" +#define LN_id_pkix_OCSP_basic "Basic OCSP Response" +#define NID_id_pkix_OCSP_basic 365 +#define OBJ_id_pkix_OCSP_basic OBJ_id_pkix_OCSP,1L + +#define SN_id_pkix_OCSP_Nonce "Nonce" +#define LN_id_pkix_OCSP_Nonce "OCSP Nonce" +#define NID_id_pkix_OCSP_Nonce 366 +#define OBJ_id_pkix_OCSP_Nonce OBJ_id_pkix_OCSP,2L + +#define SN_id_pkix_OCSP_CrlID "CrlID" +#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID" +#define NID_id_pkix_OCSP_CrlID 367 +#define OBJ_id_pkix_OCSP_CrlID OBJ_id_pkix_OCSP,3L + +#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses" +#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses" +#define NID_id_pkix_OCSP_acceptableResponses 368 +#define OBJ_id_pkix_OCSP_acceptableResponses OBJ_id_pkix_OCSP,4L + +#define SN_id_pkix_OCSP_noCheck "noCheck" +#define LN_id_pkix_OCSP_noCheck "OCSP No Check" +#define NID_id_pkix_OCSP_noCheck 369 +#define OBJ_id_pkix_OCSP_noCheck OBJ_id_pkix_OCSP,5L + +#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff" +#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff" +#define NID_id_pkix_OCSP_archiveCutoff 370 +#define OBJ_id_pkix_OCSP_archiveCutoff OBJ_id_pkix_OCSP,6L + +#define SN_id_pkix_OCSP_serviceLocator "serviceLocator" +#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator" +#define NID_id_pkix_OCSP_serviceLocator 371 +#define OBJ_id_pkix_OCSP_serviceLocator OBJ_id_pkix_OCSP,7L + +#define SN_id_pkix_OCSP_extendedStatus "extendedStatus" +#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status" +#define NID_id_pkix_OCSP_extendedStatus 372 +#define OBJ_id_pkix_OCSP_extendedStatus OBJ_id_pkix_OCSP,8L + +#define SN_id_pkix_OCSP_valid "valid" +#define NID_id_pkix_OCSP_valid 373 +#define OBJ_id_pkix_OCSP_valid OBJ_id_pkix_OCSP,9L + +#define SN_id_pkix_OCSP_path "path" +#define NID_id_pkix_OCSP_path 374 +#define OBJ_id_pkix_OCSP_path OBJ_id_pkix_OCSP,10L + +#define SN_id_pkix_OCSP_trustRoot "trustRoot" +#define LN_id_pkix_OCSP_trustRoot "Trust Root" +#define NID_id_pkix_OCSP_trustRoot 375 +#define OBJ_id_pkix_OCSP_trustRoot OBJ_id_pkix_OCSP,11L + +#define SN_algorithm "algorithm" +#define LN_algorithm "algorithm" +#define NID_algorithm 376 +#define OBJ_algorithm 1L,3L,14L,3L,2L + +#define SN_md5WithRSA "RSA-NP-MD5" +#define LN_md5WithRSA "md5WithRSA" +#define NID_md5WithRSA 104 +#define OBJ_md5WithRSA OBJ_algorithm,3L + +#define SN_des_ecb "DES-ECB" +#define LN_des_ecb "des-ecb" +#define NID_des_ecb 29 +#define OBJ_des_ecb OBJ_algorithm,6L + +#define SN_des_cbc "DES-CBC" +#define LN_des_cbc "des-cbc" +#define NID_des_cbc 31 +#define OBJ_des_cbc OBJ_algorithm,7L + +#define SN_des_ofb64 "DES-OFB" +#define LN_des_ofb64 "des-ofb" +#define NID_des_ofb64 45 +#define OBJ_des_ofb64 OBJ_algorithm,8L + +#define SN_des_cfb64 "DES-CFB" +#define LN_des_cfb64 "des-cfb" +#define NID_des_cfb64 30 +#define OBJ_des_cfb64 OBJ_algorithm,9L + +#define SN_rsaSignature "rsaSignature" +#define NID_rsaSignature 377 +#define OBJ_rsaSignature OBJ_algorithm,11L + +#define SN_dsa_2 "DSA-old" +#define LN_dsa_2 "dsaEncryption-old" +#define NID_dsa_2 67 +#define OBJ_dsa_2 OBJ_algorithm,12L + +#define SN_dsaWithSHA "DSA-SHA" +#define LN_dsaWithSHA "dsaWithSHA" +#define NID_dsaWithSHA 66 +#define OBJ_dsaWithSHA OBJ_algorithm,13L + +#define SN_shaWithRSAEncryption "RSA-SHA" +#define LN_shaWithRSAEncryption "shaWithRSAEncryption" +#define NID_shaWithRSAEncryption 42 +#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L + +#define SN_des_ede_ecb "DES-EDE" +#define LN_des_ede_ecb "des-ede" +#define NID_des_ede_ecb 32 +#define OBJ_des_ede_ecb OBJ_algorithm,17L + +#define SN_des_ede3_ecb "DES-EDE3" +#define LN_des_ede3_ecb "des-ede3" +#define NID_des_ede3_ecb 33 + +#define SN_des_ede_cbc "DES-EDE-CBC" +#define LN_des_ede_cbc "des-ede-cbc" +#define NID_des_ede_cbc 43 + +#define SN_des_ede_cfb64 "DES-EDE-CFB" +#define LN_des_ede_cfb64 "des-ede-cfb" +#define NID_des_ede_cfb64 60 + +#define SN_des_ede3_cfb64 "DES-EDE3-CFB" +#define LN_des_ede3_cfb64 "des-ede3-cfb" +#define NID_des_ede3_cfb64 61 + +#define SN_des_ede_ofb64 "DES-EDE-OFB" +#define LN_des_ede_ofb64 "des-ede-ofb" +#define NID_des_ede_ofb64 62 + +#define SN_des_ede3_ofb64 "DES-EDE3-OFB" +#define LN_des_ede3_ofb64 "des-ede3-ofb" +#define NID_des_ede3_ofb64 63 + +#define SN_desx_cbc "DESX-CBC" +#define LN_desx_cbc "desx-cbc" +#define NID_desx_cbc 80 + +#define SN_sha "SHA" +#define LN_sha "sha" +#define NID_sha 41 +#define OBJ_sha OBJ_algorithm,18L + +#define SN_sha1 "SHA1" +#define LN_sha1 "sha1" +#define NID_sha1 64 +#define OBJ_sha1 OBJ_algorithm,26L + +#define SN_dsaWithSHA1_2 "DSA-SHA1-old" +#define LN_dsaWithSHA1_2 "dsaWithSHA1-old" +#define NID_dsaWithSHA1_2 70 +#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L + +#define SN_sha1WithRSA "RSA-SHA1-2" +#define LN_sha1WithRSA "sha1WithRSA" +#define NID_sha1WithRSA 115 +#define OBJ_sha1WithRSA OBJ_algorithm,29L + +#define SN_ripemd160 "RIPEMD160" +#define LN_ripemd160 "ripemd160" +#define NID_ripemd160 117 +#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L + +#define SN_ripemd160WithRSA "RSA-RIPEMD160" +#define LN_ripemd160WithRSA "ripemd160WithRSA" +#define NID_ripemd160WithRSA 119 +#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L + +#define SN_blake2b512 "BLAKE2b512" +#define LN_blake2b512 "blake2b512" +#define NID_blake2b512 1056 +#define OBJ_blake2b512 1L,3L,6L,1L,4L,1L,1722L,12L,2L,1L,16L + +#define SN_blake2s256 "BLAKE2s256" +#define LN_blake2s256 "blake2s256" +#define NID_blake2s256 1057 +#define OBJ_blake2s256 1L,3L,6L,1L,4L,1L,1722L,12L,2L,2L,8L + +#define SN_sxnet "SXNetID" +#define LN_sxnet "Strong Extranet ID" +#define NID_sxnet 143 +#define OBJ_sxnet 1L,3L,101L,1L,4L,1L + +#define SN_X500 "X500" +#define LN_X500 "directory services (X.500)" +#define NID_X500 11 +#define OBJ_X500 2L,5L + +#define SN_X509 "X509" +#define NID_X509 12 +#define OBJ_X509 OBJ_X500,4L + +#define SN_commonName "CN" +#define LN_commonName "commonName" +#define NID_commonName 13 +#define OBJ_commonName OBJ_X509,3L + +#define SN_surname "SN" +#define LN_surname "surname" +#define NID_surname 100 +#define OBJ_surname OBJ_X509,4L + +#define LN_serialNumber "serialNumber" +#define NID_serialNumber 105 +#define OBJ_serialNumber OBJ_X509,5L + +#define SN_countryName "C" +#define LN_countryName "countryName" +#define NID_countryName 14 +#define OBJ_countryName OBJ_X509,6L + +#define SN_localityName "L" +#define LN_localityName "localityName" +#define NID_localityName 15 +#define OBJ_localityName OBJ_X509,7L + +#define SN_stateOrProvinceName "ST" +#define LN_stateOrProvinceName "stateOrProvinceName" +#define NID_stateOrProvinceName 16 +#define OBJ_stateOrProvinceName OBJ_X509,8L + +#define SN_streetAddress "street" +#define LN_streetAddress "streetAddress" +#define NID_streetAddress 660 +#define OBJ_streetAddress OBJ_X509,9L + +#define SN_organizationName "O" +#define LN_organizationName "organizationName" +#define NID_organizationName 17 +#define OBJ_organizationName OBJ_X509,10L + +#define SN_organizationalUnitName "OU" +#define LN_organizationalUnitName "organizationalUnitName" +#define NID_organizationalUnitName 18 +#define OBJ_organizationalUnitName OBJ_X509,11L + +#define SN_title "title" +#define LN_title "title" +#define NID_title 106 +#define OBJ_title OBJ_X509,12L + +#define LN_description "description" +#define NID_description 107 +#define OBJ_description OBJ_X509,13L + +#define LN_searchGuide "searchGuide" +#define NID_searchGuide 859 +#define OBJ_searchGuide OBJ_X509,14L + +#define LN_businessCategory "businessCategory" +#define NID_businessCategory 860 +#define OBJ_businessCategory OBJ_X509,15L + +#define LN_postalAddress "postalAddress" +#define NID_postalAddress 861 +#define OBJ_postalAddress OBJ_X509,16L + +#define LN_postalCode "postalCode" +#define NID_postalCode 661 +#define OBJ_postalCode OBJ_X509,17L + +#define LN_postOfficeBox "postOfficeBox" +#define NID_postOfficeBox 862 +#define OBJ_postOfficeBox OBJ_X509,18L + +#define LN_physicalDeliveryOfficeName "physicalDeliveryOfficeName" +#define NID_physicalDeliveryOfficeName 863 +#define OBJ_physicalDeliveryOfficeName OBJ_X509,19L + +#define LN_telephoneNumber "telephoneNumber" +#define NID_telephoneNumber 864 +#define OBJ_telephoneNumber OBJ_X509,20L + +#define LN_telexNumber "telexNumber" +#define NID_telexNumber 865 +#define OBJ_telexNumber OBJ_X509,21L + +#define LN_teletexTerminalIdentifier "teletexTerminalIdentifier" +#define NID_teletexTerminalIdentifier 866 +#define OBJ_teletexTerminalIdentifier OBJ_X509,22L + +#define LN_facsimileTelephoneNumber "facsimileTelephoneNumber" +#define NID_facsimileTelephoneNumber 867 +#define OBJ_facsimileTelephoneNumber OBJ_X509,23L + +#define LN_x121Address "x121Address" +#define NID_x121Address 868 +#define OBJ_x121Address OBJ_X509,24L + +#define LN_internationaliSDNNumber "internationaliSDNNumber" +#define NID_internationaliSDNNumber 869 +#define OBJ_internationaliSDNNumber OBJ_X509,25L + +#define LN_registeredAddress "registeredAddress" +#define NID_registeredAddress 870 +#define OBJ_registeredAddress OBJ_X509,26L + +#define LN_destinationIndicator "destinationIndicator" +#define NID_destinationIndicator 871 +#define OBJ_destinationIndicator OBJ_X509,27L + +#define LN_preferredDeliveryMethod "preferredDeliveryMethod" +#define NID_preferredDeliveryMethod 872 +#define OBJ_preferredDeliveryMethod OBJ_X509,28L + +#define LN_presentationAddress "presentationAddress" +#define NID_presentationAddress 873 +#define OBJ_presentationAddress OBJ_X509,29L + +#define LN_supportedApplicationContext "supportedApplicationContext" +#define NID_supportedApplicationContext 874 +#define OBJ_supportedApplicationContext OBJ_X509,30L + +#define SN_member "member" +#define NID_member 875 +#define OBJ_member OBJ_X509,31L + +#define SN_owner "owner" +#define NID_owner 876 +#define OBJ_owner OBJ_X509,32L + +#define LN_roleOccupant "roleOccupant" +#define NID_roleOccupant 877 +#define OBJ_roleOccupant OBJ_X509,33L + +#define SN_seeAlso "seeAlso" +#define NID_seeAlso 878 +#define OBJ_seeAlso OBJ_X509,34L + +#define LN_userPassword "userPassword" +#define NID_userPassword 879 +#define OBJ_userPassword OBJ_X509,35L + +#define LN_userCertificate "userCertificate" +#define NID_userCertificate 880 +#define OBJ_userCertificate OBJ_X509,36L + +#define LN_cACertificate "cACertificate" +#define NID_cACertificate 881 +#define OBJ_cACertificate OBJ_X509,37L + +#define LN_authorityRevocationList "authorityRevocationList" +#define NID_authorityRevocationList 882 +#define OBJ_authorityRevocationList OBJ_X509,38L + +#define LN_certificateRevocationList "certificateRevocationList" +#define NID_certificateRevocationList 883 +#define OBJ_certificateRevocationList OBJ_X509,39L + +#define LN_crossCertificatePair "crossCertificatePair" +#define NID_crossCertificatePair 884 +#define OBJ_crossCertificatePair OBJ_X509,40L + +#define SN_name "name" +#define LN_name "name" +#define NID_name 173 +#define OBJ_name OBJ_X509,41L + +#define SN_givenName "GN" +#define LN_givenName "givenName" +#define NID_givenName 99 +#define OBJ_givenName OBJ_X509,42L + +#define SN_initials "initials" +#define LN_initials "initials" +#define NID_initials 101 +#define OBJ_initials OBJ_X509,43L + +#define LN_generationQualifier "generationQualifier" +#define NID_generationQualifier 509 +#define OBJ_generationQualifier OBJ_X509,44L + +#define LN_x500UniqueIdentifier "x500UniqueIdentifier" +#define NID_x500UniqueIdentifier 503 +#define OBJ_x500UniqueIdentifier OBJ_X509,45L + +#define SN_dnQualifier "dnQualifier" +#define LN_dnQualifier "dnQualifier" +#define NID_dnQualifier 174 +#define OBJ_dnQualifier OBJ_X509,46L + +#define LN_enhancedSearchGuide "enhancedSearchGuide" +#define NID_enhancedSearchGuide 885 +#define OBJ_enhancedSearchGuide OBJ_X509,47L + +#define LN_protocolInformation "protocolInformation" +#define NID_protocolInformation 886 +#define OBJ_protocolInformation OBJ_X509,48L + +#define LN_distinguishedName "distinguishedName" +#define NID_distinguishedName 887 +#define OBJ_distinguishedName OBJ_X509,49L + +#define LN_uniqueMember "uniqueMember" +#define NID_uniqueMember 888 +#define OBJ_uniqueMember OBJ_X509,50L + +#define LN_houseIdentifier "houseIdentifier" +#define NID_houseIdentifier 889 +#define OBJ_houseIdentifier OBJ_X509,51L + +#define LN_supportedAlgorithms "supportedAlgorithms" +#define NID_supportedAlgorithms 890 +#define OBJ_supportedAlgorithms OBJ_X509,52L + +#define LN_deltaRevocationList "deltaRevocationList" +#define NID_deltaRevocationList 891 +#define OBJ_deltaRevocationList OBJ_X509,53L + +#define SN_dmdName "dmdName" +#define NID_dmdName 892 +#define OBJ_dmdName OBJ_X509,54L + +#define LN_pseudonym "pseudonym" +#define NID_pseudonym 510 +#define OBJ_pseudonym OBJ_X509,65L + +#define SN_role "role" +#define LN_role "role" +#define NID_role 400 +#define OBJ_role OBJ_X509,72L + +#define SN_X500algorithms "X500algorithms" +#define LN_X500algorithms "directory services - algorithms" +#define NID_X500algorithms 378 +#define OBJ_X500algorithms OBJ_X500,8L + +#define SN_rsa "RSA" +#define LN_rsa "rsa" +#define NID_rsa 19 +#define OBJ_rsa OBJ_X500algorithms,1L,1L + +#define SN_mdc2WithRSA "RSA-MDC2" +#define LN_mdc2WithRSA "mdc2WithRSA" +#define NID_mdc2WithRSA 96 +#define OBJ_mdc2WithRSA OBJ_X500algorithms,3L,100L + +#define SN_mdc2 "MDC2" +#define LN_mdc2 "mdc2" +#define NID_mdc2 95 +#define OBJ_mdc2 OBJ_X500algorithms,3L,101L + +#define SN_id_ce "id-ce" +#define NID_id_ce 81 +#define OBJ_id_ce OBJ_X500,29L + +#define SN_subject_directory_attributes "subjectDirectoryAttributes" +#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes" +#define NID_subject_directory_attributes 769 +#define OBJ_subject_directory_attributes OBJ_id_ce,9L + +#define SN_subject_key_identifier "subjectKeyIdentifier" +#define LN_subject_key_identifier "X509v3 Subject Key Identifier" +#define NID_subject_key_identifier 82 +#define OBJ_subject_key_identifier OBJ_id_ce,14L + +#define SN_key_usage "keyUsage" +#define LN_key_usage "X509v3 Key Usage" +#define NID_key_usage 83 +#define OBJ_key_usage OBJ_id_ce,15L + +#define SN_private_key_usage_period "privateKeyUsagePeriod" +#define LN_private_key_usage_period "X509v3 Private Key Usage Period" +#define NID_private_key_usage_period 84 +#define OBJ_private_key_usage_period OBJ_id_ce,16L + +#define SN_subject_alt_name "subjectAltName" +#define LN_subject_alt_name "X509v3 Subject Alternative Name" +#define NID_subject_alt_name 85 +#define OBJ_subject_alt_name OBJ_id_ce,17L + +#define SN_issuer_alt_name "issuerAltName" +#define LN_issuer_alt_name "X509v3 Issuer Alternative Name" +#define NID_issuer_alt_name 86 +#define OBJ_issuer_alt_name OBJ_id_ce,18L + +#define SN_basic_constraints "basicConstraints" +#define LN_basic_constraints "X509v3 Basic Constraints" +#define NID_basic_constraints 87 +#define OBJ_basic_constraints OBJ_id_ce,19L + +#define SN_crl_number "crlNumber" +#define LN_crl_number "X509v3 CRL Number" +#define NID_crl_number 88 +#define OBJ_crl_number OBJ_id_ce,20L + +#define SN_crl_reason "CRLReason" +#define LN_crl_reason "X509v3 CRL Reason Code" +#define NID_crl_reason 141 +#define OBJ_crl_reason OBJ_id_ce,21L + +#define SN_invalidity_date "invalidityDate" +#define LN_invalidity_date "Invalidity Date" +#define NID_invalidity_date 142 +#define OBJ_invalidity_date OBJ_id_ce,24L + +#define SN_delta_crl "deltaCRL" +#define LN_delta_crl "X509v3 Delta CRL Indicator" +#define NID_delta_crl 140 +#define OBJ_delta_crl OBJ_id_ce,27L + +#define SN_issuing_distribution_point "issuingDistributionPoint" +#define LN_issuing_distribution_point "X509v3 Issuing Distribution Point" +#define NID_issuing_distribution_point 770 +#define OBJ_issuing_distribution_point OBJ_id_ce,28L + +#define SN_certificate_issuer "certificateIssuer" +#define LN_certificate_issuer "X509v3 Certificate Issuer" +#define NID_certificate_issuer 771 +#define OBJ_certificate_issuer OBJ_id_ce,29L + +#define SN_name_constraints "nameConstraints" +#define LN_name_constraints "X509v3 Name Constraints" +#define NID_name_constraints 666 +#define OBJ_name_constraints OBJ_id_ce,30L + +#define SN_crl_distribution_points "crlDistributionPoints" +#define LN_crl_distribution_points "X509v3 CRL Distribution Points" +#define NID_crl_distribution_points 103 +#define OBJ_crl_distribution_points OBJ_id_ce,31L + +#define SN_certificate_policies "certificatePolicies" +#define LN_certificate_policies "X509v3 Certificate Policies" +#define NID_certificate_policies 89 +#define OBJ_certificate_policies OBJ_id_ce,32L + +#define SN_any_policy "anyPolicy" +#define LN_any_policy "X509v3 Any Policy" +#define NID_any_policy 746 +#define OBJ_any_policy OBJ_certificate_policies,0L + +#define SN_policy_mappings "policyMappings" +#define LN_policy_mappings "X509v3 Policy Mappings" +#define NID_policy_mappings 747 +#define OBJ_policy_mappings OBJ_id_ce,33L + +#define SN_authority_key_identifier "authorityKeyIdentifier" +#define LN_authority_key_identifier "X509v3 Authority Key Identifier" +#define NID_authority_key_identifier 90 +#define OBJ_authority_key_identifier OBJ_id_ce,35L + +#define SN_policy_constraints "policyConstraints" +#define LN_policy_constraints "X509v3 Policy Constraints" +#define NID_policy_constraints 401 +#define OBJ_policy_constraints OBJ_id_ce,36L + +#define SN_ext_key_usage "extendedKeyUsage" +#define LN_ext_key_usage "X509v3 Extended Key Usage" +#define NID_ext_key_usage 126 +#define OBJ_ext_key_usage OBJ_id_ce,37L + +#define SN_freshest_crl "freshestCRL" +#define LN_freshest_crl "X509v3 Freshest CRL" +#define NID_freshest_crl 857 +#define OBJ_freshest_crl OBJ_id_ce,46L + +#define SN_inhibit_any_policy "inhibitAnyPolicy" +#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy" +#define NID_inhibit_any_policy 748 +#define OBJ_inhibit_any_policy OBJ_id_ce,54L + +#define SN_target_information "targetInformation" +#define LN_target_information "X509v3 AC Targeting" +#define NID_target_information 402 +#define OBJ_target_information OBJ_id_ce,55L + +#define SN_no_rev_avail "noRevAvail" +#define LN_no_rev_avail "X509v3 No Revocation Available" +#define NID_no_rev_avail 403 +#define OBJ_no_rev_avail OBJ_id_ce,56L + +#define SN_anyExtendedKeyUsage "anyExtendedKeyUsage" +#define LN_anyExtendedKeyUsage "Any Extended Key Usage" +#define NID_anyExtendedKeyUsage 910 +#define OBJ_anyExtendedKeyUsage OBJ_ext_key_usage,0L + +#define SN_netscape "Netscape" +#define LN_netscape "Netscape Communications Corp." +#define NID_netscape 57 +#define OBJ_netscape 2L,16L,840L,1L,113730L + +#define SN_netscape_cert_extension "nsCertExt" +#define LN_netscape_cert_extension "Netscape Certificate Extension" +#define NID_netscape_cert_extension 58 +#define OBJ_netscape_cert_extension OBJ_netscape,1L + +#define SN_netscape_data_type "nsDataType" +#define LN_netscape_data_type "Netscape Data Type" +#define NID_netscape_data_type 59 +#define OBJ_netscape_data_type OBJ_netscape,2L + +#define SN_netscape_cert_type "nsCertType" +#define LN_netscape_cert_type "Netscape Cert Type" +#define NID_netscape_cert_type 71 +#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L + +#define SN_netscape_base_url "nsBaseUrl" +#define LN_netscape_base_url "Netscape Base Url" +#define NID_netscape_base_url 72 +#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L + +#define SN_netscape_revocation_url "nsRevocationUrl" +#define LN_netscape_revocation_url "Netscape Revocation Url" +#define NID_netscape_revocation_url 73 +#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L + +#define SN_netscape_ca_revocation_url "nsCaRevocationUrl" +#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" +#define NID_netscape_ca_revocation_url 74 +#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L + +#define SN_netscape_renewal_url "nsRenewalUrl" +#define LN_netscape_renewal_url "Netscape Renewal Url" +#define NID_netscape_renewal_url 75 +#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L + +#define SN_netscape_ca_policy_url "nsCaPolicyUrl" +#define LN_netscape_ca_policy_url "Netscape CA Policy Url" +#define NID_netscape_ca_policy_url 76 +#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L + +#define SN_netscape_ssl_server_name "nsSslServerName" +#define LN_netscape_ssl_server_name "Netscape SSL Server Name" +#define NID_netscape_ssl_server_name 77 +#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L + +#define SN_netscape_comment "nsComment" +#define LN_netscape_comment "Netscape Comment" +#define NID_netscape_comment 78 +#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L + +#define SN_netscape_cert_sequence "nsCertSequence" +#define LN_netscape_cert_sequence "Netscape Certificate Sequence" +#define NID_netscape_cert_sequence 79 +#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L + +#define SN_ns_sgc "nsSGC" +#define LN_ns_sgc "Netscape Server Gated Crypto" +#define NID_ns_sgc 139 +#define OBJ_ns_sgc OBJ_netscape,4L,1L + +#define SN_org "ORG" +#define LN_org "org" +#define NID_org 379 +#define OBJ_org OBJ_iso,3L + +#define SN_dod "DOD" +#define LN_dod "dod" +#define NID_dod 380 +#define OBJ_dod OBJ_org,6L + +#define SN_iana "IANA" +#define LN_iana "iana" +#define NID_iana 381 +#define OBJ_iana OBJ_dod,1L + +#define OBJ_internet OBJ_iana + +#define SN_Directory "directory" +#define LN_Directory "Directory" +#define NID_Directory 382 +#define OBJ_Directory OBJ_internet,1L + +#define SN_Management "mgmt" +#define LN_Management "Management" +#define NID_Management 383 +#define OBJ_Management OBJ_internet,2L + +#define SN_Experimental "experimental" +#define LN_Experimental "Experimental" +#define NID_Experimental 384 +#define OBJ_Experimental OBJ_internet,3L + +#define SN_Private "private" +#define LN_Private "Private" +#define NID_Private 385 +#define OBJ_Private OBJ_internet,4L + +#define SN_Security "security" +#define LN_Security "Security" +#define NID_Security 386 +#define OBJ_Security OBJ_internet,5L + +#define SN_SNMPv2 "snmpv2" +#define LN_SNMPv2 "SNMPv2" +#define NID_SNMPv2 387 +#define OBJ_SNMPv2 OBJ_internet,6L + +#define LN_Mail "Mail" +#define NID_Mail 388 +#define OBJ_Mail OBJ_internet,7L + +#define SN_Enterprises "enterprises" +#define LN_Enterprises "Enterprises" +#define NID_Enterprises 389 +#define OBJ_Enterprises OBJ_Private,1L + +#define SN_dcObject "dcobject" +#define LN_dcObject "dcObject" +#define NID_dcObject 390 +#define OBJ_dcObject OBJ_Enterprises,1466L,344L + +#define SN_mime_mhs "mime-mhs" +#define LN_mime_mhs "MIME MHS" +#define NID_mime_mhs 504 +#define OBJ_mime_mhs OBJ_Mail,1L + +#define SN_mime_mhs_headings "mime-mhs-headings" +#define LN_mime_mhs_headings "mime-mhs-headings" +#define NID_mime_mhs_headings 505 +#define OBJ_mime_mhs_headings OBJ_mime_mhs,1L + +#define SN_mime_mhs_bodies "mime-mhs-bodies" +#define LN_mime_mhs_bodies "mime-mhs-bodies" +#define NID_mime_mhs_bodies 506 +#define OBJ_mime_mhs_bodies OBJ_mime_mhs,2L + +#define SN_id_hex_partial_message "id-hex-partial-message" +#define LN_id_hex_partial_message "id-hex-partial-message" +#define NID_id_hex_partial_message 507 +#define OBJ_id_hex_partial_message OBJ_mime_mhs_headings,1L + +#define SN_id_hex_multipart_message "id-hex-multipart-message" +#define LN_id_hex_multipart_message "id-hex-multipart-message" +#define NID_id_hex_multipart_message 508 +#define OBJ_id_hex_multipart_message OBJ_mime_mhs_headings,2L + +#define SN_zlib_compression "ZLIB" +#define LN_zlib_compression "zlib compression" +#define NID_zlib_compression 125 +#define OBJ_zlib_compression OBJ_id_smime_alg,8L + +#define OBJ_csor 2L,16L,840L,1L,101L,3L + +#define OBJ_nistAlgorithms OBJ_csor,4L + +#define OBJ_aes OBJ_nistAlgorithms,1L + +#define SN_aes_128_ecb "AES-128-ECB" +#define LN_aes_128_ecb "aes-128-ecb" +#define NID_aes_128_ecb 418 +#define OBJ_aes_128_ecb OBJ_aes,1L + +#define SN_aes_128_cbc "AES-128-CBC" +#define LN_aes_128_cbc "aes-128-cbc" +#define NID_aes_128_cbc 419 +#define OBJ_aes_128_cbc OBJ_aes,2L + +#define SN_aes_128_ofb128 "AES-128-OFB" +#define LN_aes_128_ofb128 "aes-128-ofb" +#define NID_aes_128_ofb128 420 +#define OBJ_aes_128_ofb128 OBJ_aes,3L + +#define SN_aes_128_cfb128 "AES-128-CFB" +#define LN_aes_128_cfb128 "aes-128-cfb" +#define NID_aes_128_cfb128 421 +#define OBJ_aes_128_cfb128 OBJ_aes,4L + +#define SN_id_aes128_wrap "id-aes128-wrap" +#define NID_id_aes128_wrap 788 +#define OBJ_id_aes128_wrap OBJ_aes,5L + +#define SN_aes_128_gcm "id-aes128-GCM" +#define LN_aes_128_gcm "aes-128-gcm" +#define NID_aes_128_gcm 895 +#define OBJ_aes_128_gcm OBJ_aes,6L + +#define SN_aes_128_ccm "id-aes128-CCM" +#define LN_aes_128_ccm "aes-128-ccm" +#define NID_aes_128_ccm 896 +#define OBJ_aes_128_ccm OBJ_aes,7L + +#define SN_id_aes128_wrap_pad "id-aes128-wrap-pad" +#define NID_id_aes128_wrap_pad 897 +#define OBJ_id_aes128_wrap_pad OBJ_aes,8L + +#define SN_aes_192_ecb "AES-192-ECB" +#define LN_aes_192_ecb "aes-192-ecb" +#define NID_aes_192_ecb 422 +#define OBJ_aes_192_ecb OBJ_aes,21L + +#define SN_aes_192_cbc "AES-192-CBC" +#define LN_aes_192_cbc "aes-192-cbc" +#define NID_aes_192_cbc 423 +#define OBJ_aes_192_cbc OBJ_aes,22L + +#define SN_aes_192_ofb128 "AES-192-OFB" +#define LN_aes_192_ofb128 "aes-192-ofb" +#define NID_aes_192_ofb128 424 +#define OBJ_aes_192_ofb128 OBJ_aes,23L + +#define SN_aes_192_cfb128 "AES-192-CFB" +#define LN_aes_192_cfb128 "aes-192-cfb" +#define NID_aes_192_cfb128 425 +#define OBJ_aes_192_cfb128 OBJ_aes,24L + +#define SN_id_aes192_wrap "id-aes192-wrap" +#define NID_id_aes192_wrap 789 +#define OBJ_id_aes192_wrap OBJ_aes,25L + +#define SN_aes_192_gcm "id-aes192-GCM" +#define LN_aes_192_gcm "aes-192-gcm" +#define NID_aes_192_gcm 898 +#define OBJ_aes_192_gcm OBJ_aes,26L + +#define SN_aes_192_ccm "id-aes192-CCM" +#define LN_aes_192_ccm "aes-192-ccm" +#define NID_aes_192_ccm 899 +#define OBJ_aes_192_ccm OBJ_aes,27L + +#define SN_id_aes192_wrap_pad "id-aes192-wrap-pad" +#define NID_id_aes192_wrap_pad 900 +#define OBJ_id_aes192_wrap_pad OBJ_aes,28L + +#define SN_aes_256_ecb "AES-256-ECB" +#define LN_aes_256_ecb "aes-256-ecb" +#define NID_aes_256_ecb 426 +#define OBJ_aes_256_ecb OBJ_aes,41L + +#define SN_aes_256_cbc "AES-256-CBC" +#define LN_aes_256_cbc "aes-256-cbc" +#define NID_aes_256_cbc 427 +#define OBJ_aes_256_cbc OBJ_aes,42L + +#define SN_aes_256_ofb128 "AES-256-OFB" +#define LN_aes_256_ofb128 "aes-256-ofb" +#define NID_aes_256_ofb128 428 +#define OBJ_aes_256_ofb128 OBJ_aes,43L + +#define SN_aes_256_cfb128 "AES-256-CFB" +#define LN_aes_256_cfb128 "aes-256-cfb" +#define NID_aes_256_cfb128 429 +#define OBJ_aes_256_cfb128 OBJ_aes,44L + +#define SN_id_aes256_wrap "id-aes256-wrap" +#define NID_id_aes256_wrap 790 +#define OBJ_id_aes256_wrap OBJ_aes,45L + +#define SN_aes_256_gcm "id-aes256-GCM" +#define LN_aes_256_gcm "aes-256-gcm" +#define NID_aes_256_gcm 901 +#define OBJ_aes_256_gcm OBJ_aes,46L + +#define SN_aes_256_ccm "id-aes256-CCM" +#define LN_aes_256_ccm "aes-256-ccm" +#define NID_aes_256_ccm 902 +#define OBJ_aes_256_ccm OBJ_aes,47L + +#define SN_id_aes256_wrap_pad "id-aes256-wrap-pad" +#define NID_id_aes256_wrap_pad 903 +#define OBJ_id_aes256_wrap_pad OBJ_aes,48L + +#define SN_aes_128_cfb1 "AES-128-CFB1" +#define LN_aes_128_cfb1 "aes-128-cfb1" +#define NID_aes_128_cfb1 650 + +#define SN_aes_192_cfb1 "AES-192-CFB1" +#define LN_aes_192_cfb1 "aes-192-cfb1" +#define NID_aes_192_cfb1 651 + +#define SN_aes_256_cfb1 "AES-256-CFB1" +#define LN_aes_256_cfb1 "aes-256-cfb1" +#define NID_aes_256_cfb1 652 + +#define SN_aes_128_cfb8 "AES-128-CFB8" +#define LN_aes_128_cfb8 "aes-128-cfb8" +#define NID_aes_128_cfb8 653 + +#define SN_aes_192_cfb8 "AES-192-CFB8" +#define LN_aes_192_cfb8 "aes-192-cfb8" +#define NID_aes_192_cfb8 654 + +#define SN_aes_256_cfb8 "AES-256-CFB8" +#define LN_aes_256_cfb8 "aes-256-cfb8" +#define NID_aes_256_cfb8 655 + +#define SN_aes_128_ctr "AES-128-CTR" +#define LN_aes_128_ctr "aes-128-ctr" +#define NID_aes_128_ctr 904 + +#define SN_aes_192_ctr "AES-192-CTR" +#define LN_aes_192_ctr "aes-192-ctr" +#define NID_aes_192_ctr 905 + +#define SN_aes_256_ctr "AES-256-CTR" +#define LN_aes_256_ctr "aes-256-ctr" +#define NID_aes_256_ctr 906 + +#define SN_aes_128_ocb "AES-128-OCB" +#define LN_aes_128_ocb "aes-128-ocb" +#define NID_aes_128_ocb 958 + +#define SN_aes_192_ocb "AES-192-OCB" +#define LN_aes_192_ocb "aes-192-ocb" +#define NID_aes_192_ocb 959 + +#define SN_aes_256_ocb "AES-256-OCB" +#define LN_aes_256_ocb "aes-256-ocb" +#define NID_aes_256_ocb 960 + +#define SN_aes_128_xts "AES-128-XTS" +#define LN_aes_128_xts "aes-128-xts" +#define NID_aes_128_xts 913 + +#define SN_aes_256_xts "AES-256-XTS" +#define LN_aes_256_xts "aes-256-xts" +#define NID_aes_256_xts 914 + +#define SN_des_cfb1 "DES-CFB1" +#define LN_des_cfb1 "des-cfb1" +#define NID_des_cfb1 656 + +#define SN_des_cfb8 "DES-CFB8" +#define LN_des_cfb8 "des-cfb8" +#define NID_des_cfb8 657 + +#define SN_des_ede3_cfb1 "DES-EDE3-CFB1" +#define LN_des_ede3_cfb1 "des-ede3-cfb1" +#define NID_des_ede3_cfb1 658 + +#define SN_des_ede3_cfb8 "DES-EDE3-CFB8" +#define LN_des_ede3_cfb8 "des-ede3-cfb8" +#define NID_des_ede3_cfb8 659 + +#define OBJ_nist_hashalgs OBJ_nistAlgorithms,2L + +#define SN_sha256 "SHA256" +#define LN_sha256 "sha256" +#define NID_sha256 672 +#define OBJ_sha256 OBJ_nist_hashalgs,1L + +#define SN_sha384 "SHA384" +#define LN_sha384 "sha384" +#define NID_sha384 673 +#define OBJ_sha384 OBJ_nist_hashalgs,2L + +#define SN_sha512 "SHA512" +#define LN_sha512 "sha512" +#define NID_sha512 674 +#define OBJ_sha512 OBJ_nist_hashalgs,3L + +#define SN_sha224 "SHA224" +#define LN_sha224 "sha224" +#define NID_sha224 675 +#define OBJ_sha224 OBJ_nist_hashalgs,4L + +#define OBJ_dsa_with_sha2 OBJ_nistAlgorithms,3L + +#define SN_dsa_with_SHA224 "dsa_with_SHA224" +#define NID_dsa_with_SHA224 802 +#define OBJ_dsa_with_SHA224 OBJ_dsa_with_sha2,1L + +#define SN_dsa_with_SHA256 "dsa_with_SHA256" +#define NID_dsa_with_SHA256 803 +#define OBJ_dsa_with_SHA256 OBJ_dsa_with_sha2,2L + +#define SN_hold_instruction_code "holdInstructionCode" +#define LN_hold_instruction_code "Hold Instruction Code" +#define NID_hold_instruction_code 430 +#define OBJ_hold_instruction_code OBJ_id_ce,23L + +#define OBJ_holdInstruction OBJ_X9_57,2L + +#define SN_hold_instruction_none "holdInstructionNone" +#define LN_hold_instruction_none "Hold Instruction None" +#define NID_hold_instruction_none 431 +#define OBJ_hold_instruction_none OBJ_holdInstruction,1L + +#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer" +#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer" +#define NID_hold_instruction_call_issuer 432 +#define OBJ_hold_instruction_call_issuer OBJ_holdInstruction,2L + +#define SN_hold_instruction_reject "holdInstructionReject" +#define LN_hold_instruction_reject "Hold Instruction Reject" +#define NID_hold_instruction_reject 433 +#define OBJ_hold_instruction_reject OBJ_holdInstruction,3L + +#define SN_data "data" +#define NID_data 434 +#define OBJ_data OBJ_itu_t,9L + +#define SN_pss "pss" +#define NID_pss 435 +#define OBJ_pss OBJ_data,2342L + +#define SN_ucl "ucl" +#define NID_ucl 436 +#define OBJ_ucl OBJ_pss,19200300L + +#define SN_pilot "pilot" +#define NID_pilot 437 +#define OBJ_pilot OBJ_ucl,100L + +#define LN_pilotAttributeType "pilotAttributeType" +#define NID_pilotAttributeType 438 +#define OBJ_pilotAttributeType OBJ_pilot,1L + +#define LN_pilotAttributeSyntax "pilotAttributeSyntax" +#define NID_pilotAttributeSyntax 439 +#define OBJ_pilotAttributeSyntax OBJ_pilot,3L + +#define LN_pilotObjectClass "pilotObjectClass" +#define NID_pilotObjectClass 440 +#define OBJ_pilotObjectClass OBJ_pilot,4L + +#define LN_pilotGroups "pilotGroups" +#define NID_pilotGroups 441 +#define OBJ_pilotGroups OBJ_pilot,10L + +#define LN_iA5StringSyntax "iA5StringSyntax" +#define NID_iA5StringSyntax 442 +#define OBJ_iA5StringSyntax OBJ_pilotAttributeSyntax,4L + +#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax" +#define NID_caseIgnoreIA5StringSyntax 443 +#define OBJ_caseIgnoreIA5StringSyntax OBJ_pilotAttributeSyntax,5L + +#define LN_pilotObject "pilotObject" +#define NID_pilotObject 444 +#define OBJ_pilotObject OBJ_pilotObjectClass,3L + +#define LN_pilotPerson "pilotPerson" +#define NID_pilotPerson 445 +#define OBJ_pilotPerson OBJ_pilotObjectClass,4L + +#define SN_account "account" +#define NID_account 446 +#define OBJ_account OBJ_pilotObjectClass,5L + +#define SN_document "document" +#define NID_document 447 +#define OBJ_document OBJ_pilotObjectClass,6L + +#define SN_room "room" +#define NID_room 448 +#define OBJ_room OBJ_pilotObjectClass,7L + +#define LN_documentSeries "documentSeries" +#define NID_documentSeries 449 +#define OBJ_documentSeries OBJ_pilotObjectClass,9L + +#define SN_Domain "domain" +#define LN_Domain "Domain" +#define NID_Domain 392 +#define OBJ_Domain OBJ_pilotObjectClass,13L + +#define LN_rFC822localPart "rFC822localPart" +#define NID_rFC822localPart 450 +#define OBJ_rFC822localPart OBJ_pilotObjectClass,14L + +#define LN_dNSDomain "dNSDomain" +#define NID_dNSDomain 451 +#define OBJ_dNSDomain OBJ_pilotObjectClass,15L + +#define LN_domainRelatedObject "domainRelatedObject" +#define NID_domainRelatedObject 452 +#define OBJ_domainRelatedObject OBJ_pilotObjectClass,17L + +#define LN_friendlyCountry "friendlyCountry" +#define NID_friendlyCountry 453 +#define OBJ_friendlyCountry OBJ_pilotObjectClass,18L + +#define LN_simpleSecurityObject "simpleSecurityObject" +#define NID_simpleSecurityObject 454 +#define OBJ_simpleSecurityObject OBJ_pilotObjectClass,19L + +#define LN_pilotOrganization "pilotOrganization" +#define NID_pilotOrganization 455 +#define OBJ_pilotOrganization OBJ_pilotObjectClass,20L + +#define LN_pilotDSA "pilotDSA" +#define NID_pilotDSA 456 +#define OBJ_pilotDSA OBJ_pilotObjectClass,21L + +#define LN_qualityLabelledData "qualityLabelledData" +#define NID_qualityLabelledData 457 +#define OBJ_qualityLabelledData OBJ_pilotObjectClass,22L + +#define SN_userId "UID" +#define LN_userId "userId" +#define NID_userId 458 +#define OBJ_userId OBJ_pilotAttributeType,1L + +#define LN_textEncodedORAddress "textEncodedORAddress" +#define NID_textEncodedORAddress 459 +#define OBJ_textEncodedORAddress OBJ_pilotAttributeType,2L + +#define SN_rfc822Mailbox "mail" +#define LN_rfc822Mailbox "rfc822Mailbox" +#define NID_rfc822Mailbox 460 +#define OBJ_rfc822Mailbox OBJ_pilotAttributeType,3L + +#define SN_info "info" +#define NID_info 461 +#define OBJ_info OBJ_pilotAttributeType,4L + +#define LN_favouriteDrink "favouriteDrink" +#define NID_favouriteDrink 462 +#define OBJ_favouriteDrink OBJ_pilotAttributeType,5L + +#define LN_roomNumber "roomNumber" +#define NID_roomNumber 463 +#define OBJ_roomNumber OBJ_pilotAttributeType,6L + +#define SN_photo "photo" +#define NID_photo 464 +#define OBJ_photo OBJ_pilotAttributeType,7L + +#define LN_userClass "userClass" +#define NID_userClass 465 +#define OBJ_userClass OBJ_pilotAttributeType,8L + +#define SN_host "host" +#define NID_host 466 +#define OBJ_host OBJ_pilotAttributeType,9L + +#define SN_manager "manager" +#define NID_manager 467 +#define OBJ_manager OBJ_pilotAttributeType,10L + +#define LN_documentIdentifier "documentIdentifier" +#define NID_documentIdentifier 468 +#define OBJ_documentIdentifier OBJ_pilotAttributeType,11L + +#define LN_documentTitle "documentTitle" +#define NID_documentTitle 469 +#define OBJ_documentTitle OBJ_pilotAttributeType,12L + +#define LN_documentVersion "documentVersion" +#define NID_documentVersion 470 +#define OBJ_documentVersion OBJ_pilotAttributeType,13L + +#define LN_documentAuthor "documentAuthor" +#define NID_documentAuthor 471 +#define OBJ_documentAuthor OBJ_pilotAttributeType,14L + +#define LN_documentLocation "documentLocation" +#define NID_documentLocation 472 +#define OBJ_documentLocation OBJ_pilotAttributeType,15L + +#define LN_homeTelephoneNumber "homeTelephoneNumber" +#define NID_homeTelephoneNumber 473 +#define OBJ_homeTelephoneNumber OBJ_pilotAttributeType,20L + +#define SN_secretary "secretary" +#define NID_secretary 474 +#define OBJ_secretary OBJ_pilotAttributeType,21L + +#define LN_otherMailbox "otherMailbox" +#define NID_otherMailbox 475 +#define OBJ_otherMailbox OBJ_pilotAttributeType,22L + +#define LN_lastModifiedTime "lastModifiedTime" +#define NID_lastModifiedTime 476 +#define OBJ_lastModifiedTime OBJ_pilotAttributeType,23L + +#define LN_lastModifiedBy "lastModifiedBy" +#define NID_lastModifiedBy 477 +#define OBJ_lastModifiedBy OBJ_pilotAttributeType,24L + +#define SN_domainComponent "DC" +#define LN_domainComponent "domainComponent" +#define NID_domainComponent 391 +#define OBJ_domainComponent OBJ_pilotAttributeType,25L + +#define LN_aRecord "aRecord" +#define NID_aRecord 478 +#define OBJ_aRecord OBJ_pilotAttributeType,26L + +#define LN_pilotAttributeType27 "pilotAttributeType27" +#define NID_pilotAttributeType27 479 +#define OBJ_pilotAttributeType27 OBJ_pilotAttributeType,27L + +#define LN_mXRecord "mXRecord" +#define NID_mXRecord 480 +#define OBJ_mXRecord OBJ_pilotAttributeType,28L + +#define LN_nSRecord "nSRecord" +#define NID_nSRecord 481 +#define OBJ_nSRecord OBJ_pilotAttributeType,29L + +#define LN_sOARecord "sOARecord" +#define NID_sOARecord 482 +#define OBJ_sOARecord OBJ_pilotAttributeType,30L + +#define LN_cNAMERecord "cNAMERecord" +#define NID_cNAMERecord 483 +#define OBJ_cNAMERecord OBJ_pilotAttributeType,31L + +#define LN_associatedDomain "associatedDomain" +#define NID_associatedDomain 484 +#define OBJ_associatedDomain OBJ_pilotAttributeType,37L + +#define LN_associatedName "associatedName" +#define NID_associatedName 485 +#define OBJ_associatedName OBJ_pilotAttributeType,38L + +#define LN_homePostalAddress "homePostalAddress" +#define NID_homePostalAddress 486 +#define OBJ_homePostalAddress OBJ_pilotAttributeType,39L + +#define LN_personalTitle "personalTitle" +#define NID_personalTitle 487 +#define OBJ_personalTitle OBJ_pilotAttributeType,40L + +#define LN_mobileTelephoneNumber "mobileTelephoneNumber" +#define NID_mobileTelephoneNumber 488 +#define OBJ_mobileTelephoneNumber OBJ_pilotAttributeType,41L + +#define LN_pagerTelephoneNumber "pagerTelephoneNumber" +#define NID_pagerTelephoneNumber 489 +#define OBJ_pagerTelephoneNumber OBJ_pilotAttributeType,42L + +#define LN_friendlyCountryName "friendlyCountryName" +#define NID_friendlyCountryName 490 +#define OBJ_friendlyCountryName OBJ_pilotAttributeType,43L + +#define SN_uniqueIdentifier "uid" +#define LN_uniqueIdentifier "uniqueIdentifier" +#define NID_uniqueIdentifier 102 +#define OBJ_uniqueIdentifier OBJ_pilotAttributeType,44L + +#define LN_organizationalStatus "organizationalStatus" +#define NID_organizationalStatus 491 +#define OBJ_organizationalStatus OBJ_pilotAttributeType,45L + +#define LN_janetMailbox "janetMailbox" +#define NID_janetMailbox 492 +#define OBJ_janetMailbox OBJ_pilotAttributeType,46L + +#define LN_mailPreferenceOption "mailPreferenceOption" +#define NID_mailPreferenceOption 493 +#define OBJ_mailPreferenceOption OBJ_pilotAttributeType,47L + +#define LN_buildingName "buildingName" +#define NID_buildingName 494 +#define OBJ_buildingName OBJ_pilotAttributeType,48L + +#define LN_dSAQuality "dSAQuality" +#define NID_dSAQuality 495 +#define OBJ_dSAQuality OBJ_pilotAttributeType,49L + +#define LN_singleLevelQuality "singleLevelQuality" +#define NID_singleLevelQuality 496 +#define OBJ_singleLevelQuality OBJ_pilotAttributeType,50L + +#define LN_subtreeMinimumQuality "subtreeMinimumQuality" +#define NID_subtreeMinimumQuality 497 +#define OBJ_subtreeMinimumQuality OBJ_pilotAttributeType,51L + +#define LN_subtreeMaximumQuality "subtreeMaximumQuality" +#define NID_subtreeMaximumQuality 498 +#define OBJ_subtreeMaximumQuality OBJ_pilotAttributeType,52L + +#define LN_personalSignature "personalSignature" +#define NID_personalSignature 499 +#define OBJ_personalSignature OBJ_pilotAttributeType,53L + +#define LN_dITRedirect "dITRedirect" +#define NID_dITRedirect 500 +#define OBJ_dITRedirect OBJ_pilotAttributeType,54L + +#define SN_audio "audio" +#define NID_audio 501 +#define OBJ_audio OBJ_pilotAttributeType,55L + +#define LN_documentPublisher "documentPublisher" +#define NID_documentPublisher 502 +#define OBJ_documentPublisher OBJ_pilotAttributeType,56L + +#define SN_id_set "id-set" +#define LN_id_set "Secure Electronic Transactions" +#define NID_id_set 512 +#define OBJ_id_set OBJ_international_organizations,42L + +#define SN_set_ctype "set-ctype" +#define LN_set_ctype "content types" +#define NID_set_ctype 513 +#define OBJ_set_ctype OBJ_id_set,0L + +#define SN_set_msgExt "set-msgExt" +#define LN_set_msgExt "message extensions" +#define NID_set_msgExt 514 +#define OBJ_set_msgExt OBJ_id_set,1L + +#define SN_set_attr "set-attr" +#define NID_set_attr 515 +#define OBJ_set_attr OBJ_id_set,3L + +#define SN_set_policy "set-policy" +#define NID_set_policy 516 +#define OBJ_set_policy OBJ_id_set,5L + +#define SN_set_certExt "set-certExt" +#define LN_set_certExt "certificate extensions" +#define NID_set_certExt 517 +#define OBJ_set_certExt OBJ_id_set,7L + +#define SN_set_brand "set-brand" +#define NID_set_brand 518 +#define OBJ_set_brand OBJ_id_set,8L + +#define SN_setct_PANData "setct-PANData" +#define NID_setct_PANData 519 +#define OBJ_setct_PANData OBJ_set_ctype,0L + +#define SN_setct_PANToken "setct-PANToken" +#define NID_setct_PANToken 520 +#define OBJ_setct_PANToken OBJ_set_ctype,1L + +#define SN_setct_PANOnly "setct-PANOnly" +#define NID_setct_PANOnly 521 +#define OBJ_setct_PANOnly OBJ_set_ctype,2L + +#define SN_setct_OIData "setct-OIData" +#define NID_setct_OIData 522 +#define OBJ_setct_OIData OBJ_set_ctype,3L + +#define SN_setct_PI "setct-PI" +#define NID_setct_PI 523 +#define OBJ_setct_PI OBJ_set_ctype,4L + +#define SN_setct_PIData "setct-PIData" +#define NID_setct_PIData 524 +#define OBJ_setct_PIData OBJ_set_ctype,5L + +#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned" +#define NID_setct_PIDataUnsigned 525 +#define OBJ_setct_PIDataUnsigned OBJ_set_ctype,6L + +#define SN_setct_HODInput "setct-HODInput" +#define NID_setct_HODInput 526 +#define OBJ_setct_HODInput OBJ_set_ctype,7L + +#define SN_setct_AuthResBaggage "setct-AuthResBaggage" +#define NID_setct_AuthResBaggage 527 +#define OBJ_setct_AuthResBaggage OBJ_set_ctype,8L + +#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage" +#define NID_setct_AuthRevReqBaggage 528 +#define OBJ_setct_AuthRevReqBaggage OBJ_set_ctype,9L + +#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage" +#define NID_setct_AuthRevResBaggage 529 +#define OBJ_setct_AuthRevResBaggage OBJ_set_ctype,10L + +#define SN_setct_CapTokenSeq "setct-CapTokenSeq" +#define NID_setct_CapTokenSeq 530 +#define OBJ_setct_CapTokenSeq OBJ_set_ctype,11L + +#define SN_setct_PInitResData "setct-PInitResData" +#define NID_setct_PInitResData 531 +#define OBJ_setct_PInitResData OBJ_set_ctype,12L + +#define SN_setct_PI_TBS "setct-PI-TBS" +#define NID_setct_PI_TBS 532 +#define OBJ_setct_PI_TBS OBJ_set_ctype,13L + +#define SN_setct_PResData "setct-PResData" +#define NID_setct_PResData 533 +#define OBJ_setct_PResData OBJ_set_ctype,14L + +#define SN_setct_AuthReqTBS "setct-AuthReqTBS" +#define NID_setct_AuthReqTBS 534 +#define OBJ_setct_AuthReqTBS OBJ_set_ctype,16L + +#define SN_setct_AuthResTBS "setct-AuthResTBS" +#define NID_setct_AuthResTBS 535 +#define OBJ_setct_AuthResTBS OBJ_set_ctype,17L + +#define SN_setct_AuthResTBSX "setct-AuthResTBSX" +#define NID_setct_AuthResTBSX 536 +#define OBJ_setct_AuthResTBSX OBJ_set_ctype,18L + +#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS" +#define NID_setct_AuthTokenTBS 537 +#define OBJ_setct_AuthTokenTBS OBJ_set_ctype,19L + +#define SN_setct_CapTokenData "setct-CapTokenData" +#define NID_setct_CapTokenData 538 +#define OBJ_setct_CapTokenData OBJ_set_ctype,20L + +#define SN_setct_CapTokenTBS "setct-CapTokenTBS" +#define NID_setct_CapTokenTBS 539 +#define OBJ_setct_CapTokenTBS OBJ_set_ctype,21L + +#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg" +#define NID_setct_AcqCardCodeMsg 540 +#define OBJ_setct_AcqCardCodeMsg OBJ_set_ctype,22L + +#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS" +#define NID_setct_AuthRevReqTBS 541 +#define OBJ_setct_AuthRevReqTBS OBJ_set_ctype,23L + +#define SN_setct_AuthRevResData "setct-AuthRevResData" +#define NID_setct_AuthRevResData 542 +#define OBJ_setct_AuthRevResData OBJ_set_ctype,24L + +#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS" +#define NID_setct_AuthRevResTBS 543 +#define OBJ_setct_AuthRevResTBS OBJ_set_ctype,25L + +#define SN_setct_CapReqTBS "setct-CapReqTBS" +#define NID_setct_CapReqTBS 544 +#define OBJ_setct_CapReqTBS OBJ_set_ctype,26L + +#define SN_setct_CapReqTBSX "setct-CapReqTBSX" +#define NID_setct_CapReqTBSX 545 +#define OBJ_setct_CapReqTBSX OBJ_set_ctype,27L + +#define SN_setct_CapResData "setct-CapResData" +#define NID_setct_CapResData 546 +#define OBJ_setct_CapResData OBJ_set_ctype,28L + +#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS" +#define NID_setct_CapRevReqTBS 547 +#define OBJ_setct_CapRevReqTBS OBJ_set_ctype,29L + +#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX" +#define NID_setct_CapRevReqTBSX 548 +#define OBJ_setct_CapRevReqTBSX OBJ_set_ctype,30L + +#define SN_setct_CapRevResData "setct-CapRevResData" +#define NID_setct_CapRevResData 549 +#define OBJ_setct_CapRevResData OBJ_set_ctype,31L + +#define SN_setct_CredReqTBS "setct-CredReqTBS" +#define NID_setct_CredReqTBS 550 +#define OBJ_setct_CredReqTBS OBJ_set_ctype,32L + +#define SN_setct_CredReqTBSX "setct-CredReqTBSX" +#define NID_setct_CredReqTBSX 551 +#define OBJ_setct_CredReqTBSX OBJ_set_ctype,33L + +#define SN_setct_CredResData "setct-CredResData" +#define NID_setct_CredResData 552 +#define OBJ_setct_CredResData OBJ_set_ctype,34L + +#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS" +#define NID_setct_CredRevReqTBS 553 +#define OBJ_setct_CredRevReqTBS OBJ_set_ctype,35L + +#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX" +#define NID_setct_CredRevReqTBSX 554 +#define OBJ_setct_CredRevReqTBSX OBJ_set_ctype,36L + +#define SN_setct_CredRevResData "setct-CredRevResData" +#define NID_setct_CredRevResData 555 +#define OBJ_setct_CredRevResData OBJ_set_ctype,37L + +#define SN_setct_PCertReqData "setct-PCertReqData" +#define NID_setct_PCertReqData 556 +#define OBJ_setct_PCertReqData OBJ_set_ctype,38L + +#define SN_setct_PCertResTBS "setct-PCertResTBS" +#define NID_setct_PCertResTBS 557 +#define OBJ_setct_PCertResTBS OBJ_set_ctype,39L + +#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData" +#define NID_setct_BatchAdminReqData 558 +#define OBJ_setct_BatchAdminReqData OBJ_set_ctype,40L + +#define SN_setct_BatchAdminResData "setct-BatchAdminResData" +#define NID_setct_BatchAdminResData 559 +#define OBJ_setct_BatchAdminResData OBJ_set_ctype,41L + +#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS" +#define NID_setct_CardCInitResTBS 560 +#define OBJ_setct_CardCInitResTBS OBJ_set_ctype,42L + +#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS" +#define NID_setct_MeAqCInitResTBS 561 +#define OBJ_setct_MeAqCInitResTBS OBJ_set_ctype,43L + +#define SN_setct_RegFormResTBS "setct-RegFormResTBS" +#define NID_setct_RegFormResTBS 562 +#define OBJ_setct_RegFormResTBS OBJ_set_ctype,44L + +#define SN_setct_CertReqData "setct-CertReqData" +#define NID_setct_CertReqData 563 +#define OBJ_setct_CertReqData OBJ_set_ctype,45L + +#define SN_setct_CertReqTBS "setct-CertReqTBS" +#define NID_setct_CertReqTBS 564 +#define OBJ_setct_CertReqTBS OBJ_set_ctype,46L + +#define SN_setct_CertResData "setct-CertResData" +#define NID_setct_CertResData 565 +#define OBJ_setct_CertResData OBJ_set_ctype,47L + +#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS" +#define NID_setct_CertInqReqTBS 566 +#define OBJ_setct_CertInqReqTBS OBJ_set_ctype,48L + +#define SN_setct_ErrorTBS "setct-ErrorTBS" +#define NID_setct_ErrorTBS 567 +#define OBJ_setct_ErrorTBS OBJ_set_ctype,49L + +#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE" +#define NID_setct_PIDualSignedTBE 568 +#define OBJ_setct_PIDualSignedTBE OBJ_set_ctype,50L + +#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE" +#define NID_setct_PIUnsignedTBE 569 +#define OBJ_setct_PIUnsignedTBE OBJ_set_ctype,51L + +#define SN_setct_AuthReqTBE "setct-AuthReqTBE" +#define NID_setct_AuthReqTBE 570 +#define OBJ_setct_AuthReqTBE OBJ_set_ctype,52L + +#define SN_setct_AuthResTBE "setct-AuthResTBE" +#define NID_setct_AuthResTBE 571 +#define OBJ_setct_AuthResTBE OBJ_set_ctype,53L + +#define SN_setct_AuthResTBEX "setct-AuthResTBEX" +#define NID_setct_AuthResTBEX 572 +#define OBJ_setct_AuthResTBEX OBJ_set_ctype,54L + +#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE" +#define NID_setct_AuthTokenTBE 573 +#define OBJ_setct_AuthTokenTBE OBJ_set_ctype,55L + +#define SN_setct_CapTokenTBE "setct-CapTokenTBE" +#define NID_setct_CapTokenTBE 574 +#define OBJ_setct_CapTokenTBE OBJ_set_ctype,56L + +#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX" +#define NID_setct_CapTokenTBEX 575 +#define OBJ_setct_CapTokenTBEX OBJ_set_ctype,57L + +#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE" +#define NID_setct_AcqCardCodeMsgTBE 576 +#define OBJ_setct_AcqCardCodeMsgTBE OBJ_set_ctype,58L + +#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE" +#define NID_setct_AuthRevReqTBE 577 +#define OBJ_setct_AuthRevReqTBE OBJ_set_ctype,59L + +#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE" +#define NID_setct_AuthRevResTBE 578 +#define OBJ_setct_AuthRevResTBE OBJ_set_ctype,60L + +#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB" +#define NID_setct_AuthRevResTBEB 579 +#define OBJ_setct_AuthRevResTBEB OBJ_set_ctype,61L + +#define SN_setct_CapReqTBE "setct-CapReqTBE" +#define NID_setct_CapReqTBE 580 +#define OBJ_setct_CapReqTBE OBJ_set_ctype,62L + +#define SN_setct_CapReqTBEX "setct-CapReqTBEX" +#define NID_setct_CapReqTBEX 581 +#define OBJ_setct_CapReqTBEX OBJ_set_ctype,63L + +#define SN_setct_CapResTBE "setct-CapResTBE" +#define NID_setct_CapResTBE 582 +#define OBJ_setct_CapResTBE OBJ_set_ctype,64L + +#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE" +#define NID_setct_CapRevReqTBE 583 +#define OBJ_setct_CapRevReqTBE OBJ_set_ctype,65L + +#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX" +#define NID_setct_CapRevReqTBEX 584 +#define OBJ_setct_CapRevReqTBEX OBJ_set_ctype,66L + +#define SN_setct_CapRevResTBE "setct-CapRevResTBE" +#define NID_setct_CapRevResTBE 585 +#define OBJ_setct_CapRevResTBE OBJ_set_ctype,67L + +#define SN_setct_CredReqTBE "setct-CredReqTBE" +#define NID_setct_CredReqTBE 586 +#define OBJ_setct_CredReqTBE OBJ_set_ctype,68L + +#define SN_setct_CredReqTBEX "setct-CredReqTBEX" +#define NID_setct_CredReqTBEX 587 +#define OBJ_setct_CredReqTBEX OBJ_set_ctype,69L + +#define SN_setct_CredResTBE "setct-CredResTBE" +#define NID_setct_CredResTBE 588 +#define OBJ_setct_CredResTBE OBJ_set_ctype,70L + +#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE" +#define NID_setct_CredRevReqTBE 589 +#define OBJ_setct_CredRevReqTBE OBJ_set_ctype,71L + +#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX" +#define NID_setct_CredRevReqTBEX 590 +#define OBJ_setct_CredRevReqTBEX OBJ_set_ctype,72L + +#define SN_setct_CredRevResTBE "setct-CredRevResTBE" +#define NID_setct_CredRevResTBE 591 +#define OBJ_setct_CredRevResTBE OBJ_set_ctype,73L + +#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE" +#define NID_setct_BatchAdminReqTBE 592 +#define OBJ_setct_BatchAdminReqTBE OBJ_set_ctype,74L + +#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE" +#define NID_setct_BatchAdminResTBE 593 +#define OBJ_setct_BatchAdminResTBE OBJ_set_ctype,75L + +#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE" +#define NID_setct_RegFormReqTBE 594 +#define OBJ_setct_RegFormReqTBE OBJ_set_ctype,76L + +#define SN_setct_CertReqTBE "setct-CertReqTBE" +#define NID_setct_CertReqTBE 595 +#define OBJ_setct_CertReqTBE OBJ_set_ctype,77L + +#define SN_setct_CertReqTBEX "setct-CertReqTBEX" +#define NID_setct_CertReqTBEX 596 +#define OBJ_setct_CertReqTBEX OBJ_set_ctype,78L + +#define SN_setct_CertResTBE "setct-CertResTBE" +#define NID_setct_CertResTBE 597 +#define OBJ_setct_CertResTBE OBJ_set_ctype,79L + +#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS" +#define NID_setct_CRLNotificationTBS 598 +#define OBJ_setct_CRLNotificationTBS OBJ_set_ctype,80L + +#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS" +#define NID_setct_CRLNotificationResTBS 599 +#define OBJ_setct_CRLNotificationResTBS OBJ_set_ctype,81L + +#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS" +#define NID_setct_BCIDistributionTBS 600 +#define OBJ_setct_BCIDistributionTBS OBJ_set_ctype,82L + +#define SN_setext_genCrypt "setext-genCrypt" +#define LN_setext_genCrypt "generic cryptogram" +#define NID_setext_genCrypt 601 +#define OBJ_setext_genCrypt OBJ_set_msgExt,1L + +#define SN_setext_miAuth "setext-miAuth" +#define LN_setext_miAuth "merchant initiated auth" +#define NID_setext_miAuth 602 +#define OBJ_setext_miAuth OBJ_set_msgExt,3L + +#define SN_setext_pinSecure "setext-pinSecure" +#define NID_setext_pinSecure 603 +#define OBJ_setext_pinSecure OBJ_set_msgExt,4L + +#define SN_setext_pinAny "setext-pinAny" +#define NID_setext_pinAny 604 +#define OBJ_setext_pinAny OBJ_set_msgExt,5L + +#define SN_setext_track2 "setext-track2" +#define NID_setext_track2 605 +#define OBJ_setext_track2 OBJ_set_msgExt,7L + +#define SN_setext_cv "setext-cv" +#define LN_setext_cv "additional verification" +#define NID_setext_cv 606 +#define OBJ_setext_cv OBJ_set_msgExt,8L + +#define SN_set_policy_root "set-policy-root" +#define NID_set_policy_root 607 +#define OBJ_set_policy_root OBJ_set_policy,0L + +#define SN_setCext_hashedRoot "setCext-hashedRoot" +#define NID_setCext_hashedRoot 608 +#define OBJ_setCext_hashedRoot OBJ_set_certExt,0L + +#define SN_setCext_certType "setCext-certType" +#define NID_setCext_certType 609 +#define OBJ_setCext_certType OBJ_set_certExt,1L + +#define SN_setCext_merchData "setCext-merchData" +#define NID_setCext_merchData 610 +#define OBJ_setCext_merchData OBJ_set_certExt,2L + +#define SN_setCext_cCertRequired "setCext-cCertRequired" +#define NID_setCext_cCertRequired 611 +#define OBJ_setCext_cCertRequired OBJ_set_certExt,3L + +#define SN_setCext_tunneling "setCext-tunneling" +#define NID_setCext_tunneling 612 +#define OBJ_setCext_tunneling OBJ_set_certExt,4L + +#define SN_setCext_setExt "setCext-setExt" +#define NID_setCext_setExt 613 +#define OBJ_setCext_setExt OBJ_set_certExt,5L + +#define SN_setCext_setQualf "setCext-setQualf" +#define NID_setCext_setQualf 614 +#define OBJ_setCext_setQualf OBJ_set_certExt,6L + +#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities" +#define NID_setCext_PGWYcapabilities 615 +#define OBJ_setCext_PGWYcapabilities OBJ_set_certExt,7L + +#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier" +#define NID_setCext_TokenIdentifier 616 +#define OBJ_setCext_TokenIdentifier OBJ_set_certExt,8L + +#define SN_setCext_Track2Data "setCext-Track2Data" +#define NID_setCext_Track2Data 617 +#define OBJ_setCext_Track2Data OBJ_set_certExt,9L + +#define SN_setCext_TokenType "setCext-TokenType" +#define NID_setCext_TokenType 618 +#define OBJ_setCext_TokenType OBJ_set_certExt,10L + +#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities" +#define NID_setCext_IssuerCapabilities 619 +#define OBJ_setCext_IssuerCapabilities OBJ_set_certExt,11L + +#define SN_setAttr_Cert "setAttr-Cert" +#define NID_setAttr_Cert 620 +#define OBJ_setAttr_Cert OBJ_set_attr,0L + +#define SN_setAttr_PGWYcap "setAttr-PGWYcap" +#define LN_setAttr_PGWYcap "payment gateway capabilities" +#define NID_setAttr_PGWYcap 621 +#define OBJ_setAttr_PGWYcap OBJ_set_attr,1L + +#define SN_setAttr_TokenType "setAttr-TokenType" +#define NID_setAttr_TokenType 622 +#define OBJ_setAttr_TokenType OBJ_set_attr,2L + +#define SN_setAttr_IssCap "setAttr-IssCap" +#define LN_setAttr_IssCap "issuer capabilities" +#define NID_setAttr_IssCap 623 +#define OBJ_setAttr_IssCap OBJ_set_attr,3L + +#define SN_set_rootKeyThumb "set-rootKeyThumb" +#define NID_set_rootKeyThumb 624 +#define OBJ_set_rootKeyThumb OBJ_setAttr_Cert,0L + +#define SN_set_addPolicy "set-addPolicy" +#define NID_set_addPolicy 625 +#define OBJ_set_addPolicy OBJ_setAttr_Cert,1L + +#define SN_setAttr_Token_EMV "setAttr-Token-EMV" +#define NID_setAttr_Token_EMV 626 +#define OBJ_setAttr_Token_EMV OBJ_setAttr_TokenType,1L + +#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime" +#define NID_setAttr_Token_B0Prime 627 +#define OBJ_setAttr_Token_B0Prime OBJ_setAttr_TokenType,2L + +#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM" +#define NID_setAttr_IssCap_CVM 628 +#define OBJ_setAttr_IssCap_CVM OBJ_setAttr_IssCap,3L + +#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2" +#define NID_setAttr_IssCap_T2 629 +#define OBJ_setAttr_IssCap_T2 OBJ_setAttr_IssCap,4L + +#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig" +#define NID_setAttr_IssCap_Sig 630 +#define OBJ_setAttr_IssCap_Sig OBJ_setAttr_IssCap,5L + +#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm" +#define LN_setAttr_GenCryptgrm "generate cryptogram" +#define NID_setAttr_GenCryptgrm 631 +#define OBJ_setAttr_GenCryptgrm OBJ_setAttr_IssCap_CVM,1L + +#define SN_setAttr_T2Enc "setAttr-T2Enc" +#define LN_setAttr_T2Enc "encrypted track 2" +#define NID_setAttr_T2Enc 632 +#define OBJ_setAttr_T2Enc OBJ_setAttr_IssCap_T2,1L + +#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt" +#define LN_setAttr_T2cleartxt "cleartext track 2" +#define NID_setAttr_T2cleartxt 633 +#define OBJ_setAttr_T2cleartxt OBJ_setAttr_IssCap_T2,2L + +#define SN_setAttr_TokICCsig "setAttr-TokICCsig" +#define LN_setAttr_TokICCsig "ICC or token signature" +#define NID_setAttr_TokICCsig 634 +#define OBJ_setAttr_TokICCsig OBJ_setAttr_IssCap_Sig,1L + +#define SN_setAttr_SecDevSig "setAttr-SecDevSig" +#define LN_setAttr_SecDevSig "secure device signature" +#define NID_setAttr_SecDevSig 635 +#define OBJ_setAttr_SecDevSig OBJ_setAttr_IssCap_Sig,2L + +#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA" +#define NID_set_brand_IATA_ATA 636 +#define OBJ_set_brand_IATA_ATA OBJ_set_brand,1L + +#define SN_set_brand_Diners "set-brand-Diners" +#define NID_set_brand_Diners 637 +#define OBJ_set_brand_Diners OBJ_set_brand,30L + +#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress" +#define NID_set_brand_AmericanExpress 638 +#define OBJ_set_brand_AmericanExpress OBJ_set_brand,34L + +#define SN_set_brand_JCB "set-brand-JCB" +#define NID_set_brand_JCB 639 +#define OBJ_set_brand_JCB OBJ_set_brand,35L + +#define SN_set_brand_Visa "set-brand-Visa" +#define NID_set_brand_Visa 640 +#define OBJ_set_brand_Visa OBJ_set_brand,4L + +#define SN_set_brand_MasterCard "set-brand-MasterCard" +#define NID_set_brand_MasterCard 641 +#define OBJ_set_brand_MasterCard OBJ_set_brand,5L + +#define SN_set_brand_Novus "set-brand-Novus" +#define NID_set_brand_Novus 642 +#define OBJ_set_brand_Novus OBJ_set_brand,6011L + +#define SN_des_cdmf "DES-CDMF" +#define LN_des_cdmf "des-cdmf" +#define NID_des_cdmf 643 +#define OBJ_des_cdmf OBJ_rsadsi,3L,10L + +#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET" +#define NID_rsaOAEPEncryptionSET 644 +#define OBJ_rsaOAEPEncryptionSET OBJ_rsadsi,1L,1L,6L + +#define SN_ipsec3 "Oakley-EC2N-3" +#define LN_ipsec3 "ipsec3" +#define NID_ipsec3 749 + +#define SN_ipsec4 "Oakley-EC2N-4" +#define LN_ipsec4 "ipsec4" +#define NID_ipsec4 750 + +#define SN_whirlpool "whirlpool" +#define NID_whirlpool 804 +#define OBJ_whirlpool OBJ_iso,0L,10118L,3L,0L,55L + +#define SN_cryptopro "cryptopro" +#define NID_cryptopro 805 +#define OBJ_cryptopro OBJ_member_body,643L,2L,2L + +#define SN_cryptocom "cryptocom" +#define NID_cryptocom 806 +#define OBJ_cryptocom OBJ_member_body,643L,2L,9L + +#define SN_id_tc26 "id-tc26" +#define NID_id_tc26 974 +#define OBJ_id_tc26 OBJ_member_body,643L,7L,1L + +#define SN_id_GostR3411_94_with_GostR3410_2001 "id-GostR3411-94-with-GostR3410-2001" +#define LN_id_GostR3411_94_with_GostR3410_2001 "GOST R 34.11-94 with GOST R 34.10-2001" +#define NID_id_GostR3411_94_with_GostR3410_2001 807 +#define OBJ_id_GostR3411_94_with_GostR3410_2001 OBJ_cryptopro,3L + +#define SN_id_GostR3411_94_with_GostR3410_94 "id-GostR3411-94-with-GostR3410-94" +#define LN_id_GostR3411_94_with_GostR3410_94 "GOST R 34.11-94 with GOST R 34.10-94" +#define NID_id_GostR3411_94_with_GostR3410_94 808 +#define OBJ_id_GostR3411_94_with_GostR3410_94 OBJ_cryptopro,4L + +#define SN_id_GostR3411_94 "md_gost94" +#define LN_id_GostR3411_94 "GOST R 34.11-94" +#define NID_id_GostR3411_94 809 +#define OBJ_id_GostR3411_94 OBJ_cryptopro,9L + +#define SN_id_HMACGostR3411_94 "id-HMACGostR3411-94" +#define LN_id_HMACGostR3411_94 "HMAC GOST 34.11-94" +#define NID_id_HMACGostR3411_94 810 +#define OBJ_id_HMACGostR3411_94 OBJ_cryptopro,10L + +#define SN_id_GostR3410_2001 "gost2001" +#define LN_id_GostR3410_2001 "GOST R 34.10-2001" +#define NID_id_GostR3410_2001 811 +#define OBJ_id_GostR3410_2001 OBJ_cryptopro,19L + +#define SN_id_GostR3410_94 "gost94" +#define LN_id_GostR3410_94 "GOST R 34.10-94" +#define NID_id_GostR3410_94 812 +#define OBJ_id_GostR3410_94 OBJ_cryptopro,20L + +#define SN_id_Gost28147_89 "gost89" +#define LN_id_Gost28147_89 "GOST 28147-89" +#define NID_id_Gost28147_89 813 +#define OBJ_id_Gost28147_89 OBJ_cryptopro,21L + +#define SN_gost89_cnt "gost89-cnt" +#define NID_gost89_cnt 814 + +#define SN_gost89_cnt_12 "gost89-cnt-12" +#define NID_gost89_cnt_12 975 + +#define SN_gost89_cbc "gost89-cbc" +#define NID_gost89_cbc 1009 + +#define SN_gost89_ecb "gost89-ecb" +#define NID_gost89_ecb 1010 + +#define SN_gost89_ctr "gost89-ctr" +#define NID_gost89_ctr 1011 + +#define SN_id_Gost28147_89_MAC "gost-mac" +#define LN_id_Gost28147_89_MAC "GOST 28147-89 MAC" +#define NID_id_Gost28147_89_MAC 815 +#define OBJ_id_Gost28147_89_MAC OBJ_cryptopro,22L + +#define SN_gost_mac_12 "gost-mac-12" +#define NID_gost_mac_12 976 + +#define SN_id_GostR3411_94_prf "prf-gostr3411-94" +#define LN_id_GostR3411_94_prf "GOST R 34.11-94 PRF" +#define NID_id_GostR3411_94_prf 816 +#define OBJ_id_GostR3411_94_prf OBJ_cryptopro,23L + +#define SN_id_GostR3410_2001DH "id-GostR3410-2001DH" +#define LN_id_GostR3410_2001DH "GOST R 34.10-2001 DH" +#define NID_id_GostR3410_2001DH 817 +#define OBJ_id_GostR3410_2001DH OBJ_cryptopro,98L + +#define SN_id_GostR3410_94DH "id-GostR3410-94DH" +#define LN_id_GostR3410_94DH "GOST R 34.10-94 DH" +#define NID_id_GostR3410_94DH 818 +#define OBJ_id_GostR3410_94DH OBJ_cryptopro,99L + +#define SN_id_Gost28147_89_CryptoPro_KeyMeshing "id-Gost28147-89-CryptoPro-KeyMeshing" +#define NID_id_Gost28147_89_CryptoPro_KeyMeshing 819 +#define OBJ_id_Gost28147_89_CryptoPro_KeyMeshing OBJ_cryptopro,14L,1L + +#define SN_id_Gost28147_89_None_KeyMeshing "id-Gost28147-89-None-KeyMeshing" +#define NID_id_Gost28147_89_None_KeyMeshing 820 +#define OBJ_id_Gost28147_89_None_KeyMeshing OBJ_cryptopro,14L,0L + +#define SN_id_GostR3411_94_TestParamSet "id-GostR3411-94-TestParamSet" +#define NID_id_GostR3411_94_TestParamSet 821 +#define OBJ_id_GostR3411_94_TestParamSet OBJ_cryptopro,30L,0L + +#define SN_id_GostR3411_94_CryptoProParamSet "id-GostR3411-94-CryptoProParamSet" +#define NID_id_GostR3411_94_CryptoProParamSet 822 +#define OBJ_id_GostR3411_94_CryptoProParamSet OBJ_cryptopro,30L,1L + +#define SN_id_Gost28147_89_TestParamSet "id-Gost28147-89-TestParamSet" +#define NID_id_Gost28147_89_TestParamSet 823 +#define OBJ_id_Gost28147_89_TestParamSet OBJ_cryptopro,31L,0L + +#define SN_id_Gost28147_89_CryptoPro_A_ParamSet "id-Gost28147-89-CryptoPro-A-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_A_ParamSet 824 +#define OBJ_id_Gost28147_89_CryptoPro_A_ParamSet OBJ_cryptopro,31L,1L + +#define SN_id_Gost28147_89_CryptoPro_B_ParamSet "id-Gost28147-89-CryptoPro-B-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_B_ParamSet 825 +#define OBJ_id_Gost28147_89_CryptoPro_B_ParamSet OBJ_cryptopro,31L,2L + +#define SN_id_Gost28147_89_CryptoPro_C_ParamSet "id-Gost28147-89-CryptoPro-C-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_C_ParamSet 826 +#define OBJ_id_Gost28147_89_CryptoPro_C_ParamSet OBJ_cryptopro,31L,3L + +#define SN_id_Gost28147_89_CryptoPro_D_ParamSet "id-Gost28147-89-CryptoPro-D-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_D_ParamSet 827 +#define OBJ_id_Gost28147_89_CryptoPro_D_ParamSet OBJ_cryptopro,31L,4L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 828 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet OBJ_cryptopro,31L,5L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 829 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet OBJ_cryptopro,31L,6L + +#define SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 830 +#define OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet OBJ_cryptopro,31L,7L + +#define SN_id_GostR3410_94_TestParamSet "id-GostR3410-94-TestParamSet" +#define NID_id_GostR3410_94_TestParamSet 831 +#define OBJ_id_GostR3410_94_TestParamSet OBJ_cryptopro,32L,0L + +#define SN_id_GostR3410_94_CryptoPro_A_ParamSet "id-GostR3410-94-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_A_ParamSet 832 +#define OBJ_id_GostR3410_94_CryptoPro_A_ParamSet OBJ_cryptopro,32L,2L + +#define SN_id_GostR3410_94_CryptoPro_B_ParamSet "id-GostR3410-94-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_B_ParamSet 833 +#define OBJ_id_GostR3410_94_CryptoPro_B_ParamSet OBJ_cryptopro,32L,3L + +#define SN_id_GostR3410_94_CryptoPro_C_ParamSet "id-GostR3410-94-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_C_ParamSet 834 +#define OBJ_id_GostR3410_94_CryptoPro_C_ParamSet OBJ_cryptopro,32L,4L + +#define SN_id_GostR3410_94_CryptoPro_D_ParamSet "id-GostR3410-94-CryptoPro-D-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_D_ParamSet 835 +#define OBJ_id_GostR3410_94_CryptoPro_D_ParamSet OBJ_cryptopro,32L,5L + +#define SN_id_GostR3410_94_CryptoPro_XchA_ParamSet "id-GostR3410-94-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchA_ParamSet 836 +#define OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet OBJ_cryptopro,33L,1L + +#define SN_id_GostR3410_94_CryptoPro_XchB_ParamSet "id-GostR3410-94-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchB_ParamSet 837 +#define OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet OBJ_cryptopro,33L,2L + +#define SN_id_GostR3410_94_CryptoPro_XchC_ParamSet "id-GostR3410-94-CryptoPro-XchC-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchC_ParamSet 838 +#define OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet OBJ_cryptopro,33L,3L + +#define SN_id_GostR3410_2001_TestParamSet "id-GostR3410-2001-TestParamSet" +#define NID_id_GostR3410_2001_TestParamSet 839 +#define OBJ_id_GostR3410_2001_TestParamSet OBJ_cryptopro,35L,0L + +#define SN_id_GostR3410_2001_CryptoPro_A_ParamSet "id-GostR3410-2001-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_A_ParamSet 840 +#define OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet OBJ_cryptopro,35L,1L + +#define SN_id_GostR3410_2001_CryptoPro_B_ParamSet "id-GostR3410-2001-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_B_ParamSet 841 +#define OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet OBJ_cryptopro,35L,2L + +#define SN_id_GostR3410_2001_CryptoPro_C_ParamSet "id-GostR3410-2001-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_C_ParamSet 842 +#define OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet OBJ_cryptopro,35L,3L + +#define SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet "id-GostR3410-2001-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet 843 +#define OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet OBJ_cryptopro,36L,0L + +#define SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet "id-GostR3410-2001-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet 844 +#define OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet OBJ_cryptopro,36L,1L + +#define SN_id_GostR3410_94_a "id-GostR3410-94-a" +#define NID_id_GostR3410_94_a 845 +#define OBJ_id_GostR3410_94_a OBJ_id_GostR3410_94,1L + +#define SN_id_GostR3410_94_aBis "id-GostR3410-94-aBis" +#define NID_id_GostR3410_94_aBis 846 +#define OBJ_id_GostR3410_94_aBis OBJ_id_GostR3410_94,2L + +#define SN_id_GostR3410_94_b "id-GostR3410-94-b" +#define NID_id_GostR3410_94_b 847 +#define OBJ_id_GostR3410_94_b OBJ_id_GostR3410_94,3L + +#define SN_id_GostR3410_94_bBis "id-GostR3410-94-bBis" +#define NID_id_GostR3410_94_bBis 848 +#define OBJ_id_GostR3410_94_bBis OBJ_id_GostR3410_94,4L + +#define SN_id_Gost28147_89_cc "id-Gost28147-89-cc" +#define LN_id_Gost28147_89_cc "GOST 28147-89 Cryptocom ParamSet" +#define NID_id_Gost28147_89_cc 849 +#define OBJ_id_Gost28147_89_cc OBJ_cryptocom,1L,6L,1L + +#define SN_id_GostR3410_94_cc "gost94cc" +#define LN_id_GostR3410_94_cc "GOST 34.10-94 Cryptocom" +#define NID_id_GostR3410_94_cc 850 +#define OBJ_id_GostR3410_94_cc OBJ_cryptocom,1L,5L,3L + +#define SN_id_GostR3410_2001_cc "gost2001cc" +#define LN_id_GostR3410_2001_cc "GOST 34.10-2001 Cryptocom" +#define NID_id_GostR3410_2001_cc 851 +#define OBJ_id_GostR3410_2001_cc OBJ_cryptocom,1L,5L,4L + +#define SN_id_GostR3411_94_with_GostR3410_94_cc "id-GostR3411-94-with-GostR3410-94-cc" +#define LN_id_GostR3411_94_with_GostR3410_94_cc "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_94_cc 852 +#define OBJ_id_GostR3411_94_with_GostR3410_94_cc OBJ_cryptocom,1L,3L,3L + +#define SN_id_GostR3411_94_with_GostR3410_2001_cc "id-GostR3411-94-with-GostR3410-2001-cc" +#define LN_id_GostR3411_94_with_GostR3410_2001_cc "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_2001_cc 853 +#define OBJ_id_GostR3411_94_with_GostR3410_2001_cc OBJ_cryptocom,1L,3L,4L + +#define SN_id_GostR3410_2001_ParamSet_cc "id-GostR3410-2001-ParamSet-cc" +#define LN_id_GostR3410_2001_ParamSet_cc "GOST R 3410-2001 Parameter Set Cryptocom" +#define NID_id_GostR3410_2001_ParamSet_cc 854 +#define OBJ_id_GostR3410_2001_ParamSet_cc OBJ_cryptocom,1L,8L,1L + +#define SN_id_tc26_algorithms "id-tc26-algorithms" +#define NID_id_tc26_algorithms 977 +#define OBJ_id_tc26_algorithms OBJ_id_tc26,1L + +#define SN_id_tc26_sign "id-tc26-sign" +#define NID_id_tc26_sign 978 +#define OBJ_id_tc26_sign OBJ_id_tc26_algorithms,1L + +#define SN_id_GostR3410_2012_256 "gost2012_256" +#define LN_id_GostR3410_2012_256 "GOST R 34.10-2012 with 256 bit modulus" +#define NID_id_GostR3410_2012_256 979 +#define OBJ_id_GostR3410_2012_256 OBJ_id_tc26_sign,1L + +#define SN_id_GostR3410_2012_512 "gost2012_512" +#define LN_id_GostR3410_2012_512 "GOST R 34.10-2012 with 512 bit modulus" +#define NID_id_GostR3410_2012_512 980 +#define OBJ_id_GostR3410_2012_512 OBJ_id_tc26_sign,2L + +#define SN_id_tc26_digest "id-tc26-digest" +#define NID_id_tc26_digest 981 +#define OBJ_id_tc26_digest OBJ_id_tc26_algorithms,2L + +#define SN_id_GostR3411_2012_256 "md_gost12_256" +#define LN_id_GostR3411_2012_256 "GOST R 34.11-2012 with 256 bit hash" +#define NID_id_GostR3411_2012_256 982 +#define OBJ_id_GostR3411_2012_256 OBJ_id_tc26_digest,2L + +#define SN_id_GostR3411_2012_512 "md_gost12_512" +#define LN_id_GostR3411_2012_512 "GOST R 34.11-2012 with 512 bit hash" +#define NID_id_GostR3411_2012_512 983 +#define OBJ_id_GostR3411_2012_512 OBJ_id_tc26_digest,3L + +#define SN_id_tc26_signwithdigest "id-tc26-signwithdigest" +#define NID_id_tc26_signwithdigest 984 +#define OBJ_id_tc26_signwithdigest OBJ_id_tc26_algorithms,3L + +#define SN_id_tc26_signwithdigest_gost3410_2012_256 "id-tc26-signwithdigest-gost3410-2012-256" +#define LN_id_tc26_signwithdigest_gost3410_2012_256 "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" +#define NID_id_tc26_signwithdigest_gost3410_2012_256 985 +#define OBJ_id_tc26_signwithdigest_gost3410_2012_256 OBJ_id_tc26_signwithdigest,2L + +#define SN_id_tc26_signwithdigest_gost3410_2012_512 "id-tc26-signwithdigest-gost3410-2012-512" +#define LN_id_tc26_signwithdigest_gost3410_2012_512 "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" +#define NID_id_tc26_signwithdigest_gost3410_2012_512 986 +#define OBJ_id_tc26_signwithdigest_gost3410_2012_512 OBJ_id_tc26_signwithdigest,3L + +#define SN_id_tc26_mac "id-tc26-mac" +#define NID_id_tc26_mac 987 +#define OBJ_id_tc26_mac OBJ_id_tc26_algorithms,4L + +#define SN_id_tc26_hmac_gost_3411_2012_256 "id-tc26-hmac-gost-3411-2012-256" +#define LN_id_tc26_hmac_gost_3411_2012_256 "HMAC GOST 34.11-2012 256 bit" +#define NID_id_tc26_hmac_gost_3411_2012_256 988 +#define OBJ_id_tc26_hmac_gost_3411_2012_256 OBJ_id_tc26_mac,1L + +#define SN_id_tc26_hmac_gost_3411_2012_512 "id-tc26-hmac-gost-3411-2012-512" +#define LN_id_tc26_hmac_gost_3411_2012_512 "HMAC GOST 34.11-2012 512 bit" +#define NID_id_tc26_hmac_gost_3411_2012_512 989 +#define OBJ_id_tc26_hmac_gost_3411_2012_512 OBJ_id_tc26_mac,2L + +#define SN_id_tc26_cipher "id-tc26-cipher" +#define NID_id_tc26_cipher 990 +#define OBJ_id_tc26_cipher OBJ_id_tc26_algorithms,5L + +#define SN_id_tc26_agreement "id-tc26-agreement" +#define NID_id_tc26_agreement 991 +#define OBJ_id_tc26_agreement OBJ_id_tc26_algorithms,6L + +#define SN_id_tc26_agreement_gost_3410_2012_256 "id-tc26-agreement-gost-3410-2012-256" +#define NID_id_tc26_agreement_gost_3410_2012_256 992 +#define OBJ_id_tc26_agreement_gost_3410_2012_256 OBJ_id_tc26_agreement,1L + +#define SN_id_tc26_agreement_gost_3410_2012_512 "id-tc26-agreement-gost-3410-2012-512" +#define NID_id_tc26_agreement_gost_3410_2012_512 993 +#define OBJ_id_tc26_agreement_gost_3410_2012_512 OBJ_id_tc26_agreement,2L + +#define SN_id_tc26_constants "id-tc26-constants" +#define NID_id_tc26_constants 994 +#define OBJ_id_tc26_constants OBJ_id_tc26,2L + +#define SN_id_tc26_sign_constants "id-tc26-sign-constants" +#define NID_id_tc26_sign_constants 995 +#define OBJ_id_tc26_sign_constants OBJ_id_tc26_constants,1L + +#define SN_id_tc26_gost_3410_2012_512_constants "id-tc26-gost-3410-2012-512-constants" +#define NID_id_tc26_gost_3410_2012_512_constants 996 +#define OBJ_id_tc26_gost_3410_2012_512_constants OBJ_id_tc26_sign_constants,2L + +#define SN_id_tc26_gost_3410_2012_512_paramSetTest "id-tc26-gost-3410-2012-512-paramSetTest" +#define LN_id_tc26_gost_3410_2012_512_paramSetTest "GOST R 34.10-2012 (512 bit) testing parameter set" +#define NID_id_tc26_gost_3410_2012_512_paramSetTest 997 +#define OBJ_id_tc26_gost_3410_2012_512_paramSetTest OBJ_id_tc26_gost_3410_2012_512_constants,0L + +#define SN_id_tc26_gost_3410_2012_512_paramSetA "id-tc26-gost-3410-2012-512-paramSetA" +#define LN_id_tc26_gost_3410_2012_512_paramSetA "GOST R 34.10-2012 (512 bit) ParamSet A" +#define NID_id_tc26_gost_3410_2012_512_paramSetA 998 +#define OBJ_id_tc26_gost_3410_2012_512_paramSetA OBJ_id_tc26_gost_3410_2012_512_constants,1L + +#define SN_id_tc26_gost_3410_2012_512_paramSetB "id-tc26-gost-3410-2012-512-paramSetB" +#define LN_id_tc26_gost_3410_2012_512_paramSetB "GOST R 34.10-2012 (512 bit) ParamSet B" +#define NID_id_tc26_gost_3410_2012_512_paramSetB 999 +#define OBJ_id_tc26_gost_3410_2012_512_paramSetB OBJ_id_tc26_gost_3410_2012_512_constants,2L + +#define SN_id_tc26_digest_constants "id-tc26-digest-constants" +#define NID_id_tc26_digest_constants 1000 +#define OBJ_id_tc26_digest_constants OBJ_id_tc26_constants,2L + +#define SN_id_tc26_cipher_constants "id-tc26-cipher-constants" +#define NID_id_tc26_cipher_constants 1001 +#define OBJ_id_tc26_cipher_constants OBJ_id_tc26_constants,5L + +#define SN_id_tc26_gost_28147_constants "id-tc26-gost-28147-constants" +#define NID_id_tc26_gost_28147_constants 1002 +#define OBJ_id_tc26_gost_28147_constants OBJ_id_tc26_cipher_constants,1L + +#define SN_id_tc26_gost_28147_param_Z "id-tc26-gost-28147-param-Z" +#define LN_id_tc26_gost_28147_param_Z "GOST 28147-89 TC26 parameter set" +#define NID_id_tc26_gost_28147_param_Z 1003 +#define OBJ_id_tc26_gost_28147_param_Z OBJ_id_tc26_gost_28147_constants,1L + +#define SN_INN "INN" +#define LN_INN "INN" +#define NID_INN 1004 +#define OBJ_INN OBJ_member_body,643L,3L,131L,1L,1L + +#define SN_OGRN "OGRN" +#define LN_OGRN "OGRN" +#define NID_OGRN 1005 +#define OBJ_OGRN OBJ_member_body,643L,100L,1L + +#define SN_SNILS "SNILS" +#define LN_SNILS "SNILS" +#define NID_SNILS 1006 +#define OBJ_SNILS OBJ_member_body,643L,100L,3L + +#define SN_subjectSignTool "subjectSignTool" +#define LN_subjectSignTool "Signing Tool of Subject" +#define NID_subjectSignTool 1007 +#define OBJ_subjectSignTool OBJ_member_body,643L,100L,111L + +#define SN_issuerSignTool "issuerSignTool" +#define LN_issuerSignTool "Signing Tool of Issuer" +#define NID_issuerSignTool 1008 +#define OBJ_issuerSignTool OBJ_member_body,643L,100L,112L + +#define SN_grasshopper_ecb "grasshopper-ecb" +#define NID_grasshopper_ecb 1012 + +#define SN_grasshopper_ctr "grasshopper-ctr" +#define NID_grasshopper_ctr 1013 + +#define SN_grasshopper_ofb "grasshopper-ofb" +#define NID_grasshopper_ofb 1014 + +#define SN_grasshopper_cbc "grasshopper-cbc" +#define NID_grasshopper_cbc 1015 + +#define SN_grasshopper_cfb "grasshopper-cfb" +#define NID_grasshopper_cfb 1016 + +#define SN_grasshopper_mac "grasshopper-mac" +#define NID_grasshopper_mac 1017 + +#define SN_camellia_128_cbc "CAMELLIA-128-CBC" +#define LN_camellia_128_cbc "camellia-128-cbc" +#define NID_camellia_128_cbc 751 +#define OBJ_camellia_128_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,2L + +#define SN_camellia_192_cbc "CAMELLIA-192-CBC" +#define LN_camellia_192_cbc "camellia-192-cbc" +#define NID_camellia_192_cbc 752 +#define OBJ_camellia_192_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,3L + +#define SN_camellia_256_cbc "CAMELLIA-256-CBC" +#define LN_camellia_256_cbc "camellia-256-cbc" +#define NID_camellia_256_cbc 753 +#define OBJ_camellia_256_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,4L + +#define SN_id_camellia128_wrap "id-camellia128-wrap" +#define NID_id_camellia128_wrap 907 +#define OBJ_id_camellia128_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,2L + +#define SN_id_camellia192_wrap "id-camellia192-wrap" +#define NID_id_camellia192_wrap 908 +#define OBJ_id_camellia192_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,3L + +#define SN_id_camellia256_wrap "id-camellia256-wrap" +#define NID_id_camellia256_wrap 909 +#define OBJ_id_camellia256_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,4L + +#define OBJ_ntt_ds 0L,3L,4401L,5L + +#define OBJ_camellia OBJ_ntt_ds,3L,1L,9L + +#define SN_camellia_128_ecb "CAMELLIA-128-ECB" +#define LN_camellia_128_ecb "camellia-128-ecb" +#define NID_camellia_128_ecb 754 +#define OBJ_camellia_128_ecb OBJ_camellia,1L + +#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB" +#define LN_camellia_128_ofb128 "camellia-128-ofb" +#define NID_camellia_128_ofb128 766 +#define OBJ_camellia_128_ofb128 OBJ_camellia,3L + +#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB" +#define LN_camellia_128_cfb128 "camellia-128-cfb" +#define NID_camellia_128_cfb128 757 +#define OBJ_camellia_128_cfb128 OBJ_camellia,4L + +#define SN_camellia_128_gcm "CAMELLIA-128-GCM" +#define LN_camellia_128_gcm "camellia-128-gcm" +#define NID_camellia_128_gcm 961 +#define OBJ_camellia_128_gcm OBJ_camellia,6L + +#define SN_camellia_128_ccm "CAMELLIA-128-CCM" +#define LN_camellia_128_ccm "camellia-128-ccm" +#define NID_camellia_128_ccm 962 +#define OBJ_camellia_128_ccm OBJ_camellia,7L + +#define SN_camellia_128_ctr "CAMELLIA-128-CTR" +#define LN_camellia_128_ctr "camellia-128-ctr" +#define NID_camellia_128_ctr 963 +#define OBJ_camellia_128_ctr OBJ_camellia,9L + +#define SN_camellia_128_cmac "CAMELLIA-128-CMAC" +#define LN_camellia_128_cmac "camellia-128-cmac" +#define NID_camellia_128_cmac 964 +#define OBJ_camellia_128_cmac OBJ_camellia,10L + +#define SN_camellia_192_ecb "CAMELLIA-192-ECB" +#define LN_camellia_192_ecb "camellia-192-ecb" +#define NID_camellia_192_ecb 755 +#define OBJ_camellia_192_ecb OBJ_camellia,21L + +#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB" +#define LN_camellia_192_ofb128 "camellia-192-ofb" +#define NID_camellia_192_ofb128 767 +#define OBJ_camellia_192_ofb128 OBJ_camellia,23L + +#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB" +#define LN_camellia_192_cfb128 "camellia-192-cfb" +#define NID_camellia_192_cfb128 758 +#define OBJ_camellia_192_cfb128 OBJ_camellia,24L + +#define SN_camellia_192_gcm "CAMELLIA-192-GCM" +#define LN_camellia_192_gcm "camellia-192-gcm" +#define NID_camellia_192_gcm 965 +#define OBJ_camellia_192_gcm OBJ_camellia,26L + +#define SN_camellia_192_ccm "CAMELLIA-192-CCM" +#define LN_camellia_192_ccm "camellia-192-ccm" +#define NID_camellia_192_ccm 966 +#define OBJ_camellia_192_ccm OBJ_camellia,27L + +#define SN_camellia_192_ctr "CAMELLIA-192-CTR" +#define LN_camellia_192_ctr "camellia-192-ctr" +#define NID_camellia_192_ctr 967 +#define OBJ_camellia_192_ctr OBJ_camellia,29L + +#define SN_camellia_192_cmac "CAMELLIA-192-CMAC" +#define LN_camellia_192_cmac "camellia-192-cmac" +#define NID_camellia_192_cmac 968 +#define OBJ_camellia_192_cmac OBJ_camellia,30L + +#define SN_camellia_256_ecb "CAMELLIA-256-ECB" +#define LN_camellia_256_ecb "camellia-256-ecb" +#define NID_camellia_256_ecb 756 +#define OBJ_camellia_256_ecb OBJ_camellia,41L + +#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB" +#define LN_camellia_256_ofb128 "camellia-256-ofb" +#define NID_camellia_256_ofb128 768 +#define OBJ_camellia_256_ofb128 OBJ_camellia,43L + +#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB" +#define LN_camellia_256_cfb128 "camellia-256-cfb" +#define NID_camellia_256_cfb128 759 +#define OBJ_camellia_256_cfb128 OBJ_camellia,44L + +#define SN_camellia_256_gcm "CAMELLIA-256-GCM" +#define LN_camellia_256_gcm "camellia-256-gcm" +#define NID_camellia_256_gcm 969 +#define OBJ_camellia_256_gcm OBJ_camellia,46L + +#define SN_camellia_256_ccm "CAMELLIA-256-CCM" +#define LN_camellia_256_ccm "camellia-256-ccm" +#define NID_camellia_256_ccm 970 +#define OBJ_camellia_256_ccm OBJ_camellia,47L + +#define SN_camellia_256_ctr "CAMELLIA-256-CTR" +#define LN_camellia_256_ctr "camellia-256-ctr" +#define NID_camellia_256_ctr 971 +#define OBJ_camellia_256_ctr OBJ_camellia,49L + +#define SN_camellia_256_cmac "CAMELLIA-256-CMAC" +#define LN_camellia_256_cmac "camellia-256-cmac" +#define NID_camellia_256_cmac 972 +#define OBJ_camellia_256_cmac OBJ_camellia,50L + +#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1" +#define LN_camellia_128_cfb1 "camellia-128-cfb1" +#define NID_camellia_128_cfb1 760 + +#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1" +#define LN_camellia_192_cfb1 "camellia-192-cfb1" +#define NID_camellia_192_cfb1 761 + +#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1" +#define LN_camellia_256_cfb1 "camellia-256-cfb1" +#define NID_camellia_256_cfb1 762 + +#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8" +#define LN_camellia_128_cfb8 "camellia-128-cfb8" +#define NID_camellia_128_cfb8 763 + +#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8" +#define LN_camellia_192_cfb8 "camellia-192-cfb8" +#define NID_camellia_192_cfb8 764 + +#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8" +#define LN_camellia_256_cfb8 "camellia-256-cfb8" +#define NID_camellia_256_cfb8 765 + +#define SN_kisa "KISA" +#define LN_kisa "kisa" +#define NID_kisa 773 +#define OBJ_kisa OBJ_member_body,410L,200004L + +#define SN_seed_ecb "SEED-ECB" +#define LN_seed_ecb "seed-ecb" +#define NID_seed_ecb 776 +#define OBJ_seed_ecb OBJ_kisa,1L,3L + +#define SN_seed_cbc "SEED-CBC" +#define LN_seed_cbc "seed-cbc" +#define NID_seed_cbc 777 +#define OBJ_seed_cbc OBJ_kisa,1L,4L + +#define SN_seed_cfb128 "SEED-CFB" +#define LN_seed_cfb128 "seed-cfb" +#define NID_seed_cfb128 779 +#define OBJ_seed_cfb128 OBJ_kisa,1L,5L + +#define SN_seed_ofb128 "SEED-OFB" +#define LN_seed_ofb128 "seed-ofb" +#define NID_seed_ofb128 778 +#define OBJ_seed_ofb128 OBJ_kisa,1L,6L + +#define SN_hmac "HMAC" +#define LN_hmac "hmac" +#define NID_hmac 855 + +#define SN_cmac "CMAC" +#define LN_cmac "cmac" +#define NID_cmac 894 + +#define SN_rc4_hmac_md5 "RC4-HMAC-MD5" +#define LN_rc4_hmac_md5 "rc4-hmac-md5" +#define NID_rc4_hmac_md5 915 + +#define SN_aes_128_cbc_hmac_sha1 "AES-128-CBC-HMAC-SHA1" +#define LN_aes_128_cbc_hmac_sha1 "aes-128-cbc-hmac-sha1" +#define NID_aes_128_cbc_hmac_sha1 916 + +#define SN_aes_192_cbc_hmac_sha1 "AES-192-CBC-HMAC-SHA1" +#define LN_aes_192_cbc_hmac_sha1 "aes-192-cbc-hmac-sha1" +#define NID_aes_192_cbc_hmac_sha1 917 + +#define SN_aes_256_cbc_hmac_sha1 "AES-256-CBC-HMAC-SHA1" +#define LN_aes_256_cbc_hmac_sha1 "aes-256-cbc-hmac-sha1" +#define NID_aes_256_cbc_hmac_sha1 918 + +#define SN_aes_128_cbc_hmac_sha256 "AES-128-CBC-HMAC-SHA256" +#define LN_aes_128_cbc_hmac_sha256 "aes-128-cbc-hmac-sha256" +#define NID_aes_128_cbc_hmac_sha256 948 + +#define SN_aes_192_cbc_hmac_sha256 "AES-192-CBC-HMAC-SHA256" +#define LN_aes_192_cbc_hmac_sha256 "aes-192-cbc-hmac-sha256" +#define NID_aes_192_cbc_hmac_sha256 949 + +#define SN_aes_256_cbc_hmac_sha256 "AES-256-CBC-HMAC-SHA256" +#define LN_aes_256_cbc_hmac_sha256 "aes-256-cbc-hmac-sha256" +#define NID_aes_256_cbc_hmac_sha256 950 + +#define SN_chacha20_poly1305 "ChaCha20-Poly1305" +#define LN_chacha20_poly1305 "chacha20-poly1305" +#define NID_chacha20_poly1305 1018 + +#define SN_chacha20 "ChaCha20" +#define LN_chacha20 "chacha20" +#define NID_chacha20 1019 + +#define SN_dhpublicnumber "dhpublicnumber" +#define LN_dhpublicnumber "X9.42 DH" +#define NID_dhpublicnumber 920 +#define OBJ_dhpublicnumber OBJ_ISO_US,10046L,2L,1L + +#define SN_brainpoolP160r1 "brainpoolP160r1" +#define NID_brainpoolP160r1 921 +#define OBJ_brainpoolP160r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,1L + +#define SN_brainpoolP160t1 "brainpoolP160t1" +#define NID_brainpoolP160t1 922 +#define OBJ_brainpoolP160t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,2L + +#define SN_brainpoolP192r1 "brainpoolP192r1" +#define NID_brainpoolP192r1 923 +#define OBJ_brainpoolP192r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,3L + +#define SN_brainpoolP192t1 "brainpoolP192t1" +#define NID_brainpoolP192t1 924 +#define OBJ_brainpoolP192t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,4L + +#define SN_brainpoolP224r1 "brainpoolP224r1" +#define NID_brainpoolP224r1 925 +#define OBJ_brainpoolP224r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,5L + +#define SN_brainpoolP224t1 "brainpoolP224t1" +#define NID_brainpoolP224t1 926 +#define OBJ_brainpoolP224t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,6L + +#define SN_brainpoolP256r1 "brainpoolP256r1" +#define NID_brainpoolP256r1 927 +#define OBJ_brainpoolP256r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,7L + +#define SN_brainpoolP256t1 "brainpoolP256t1" +#define NID_brainpoolP256t1 928 +#define OBJ_brainpoolP256t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,8L + +#define SN_brainpoolP320r1 "brainpoolP320r1" +#define NID_brainpoolP320r1 929 +#define OBJ_brainpoolP320r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,9L + +#define SN_brainpoolP320t1 "brainpoolP320t1" +#define NID_brainpoolP320t1 930 +#define OBJ_brainpoolP320t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,10L + +#define SN_brainpoolP384r1 "brainpoolP384r1" +#define NID_brainpoolP384r1 931 +#define OBJ_brainpoolP384r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,11L + +#define SN_brainpoolP384t1 "brainpoolP384t1" +#define NID_brainpoolP384t1 932 +#define OBJ_brainpoolP384t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,12L + +#define SN_brainpoolP512r1 "brainpoolP512r1" +#define NID_brainpoolP512r1 933 +#define OBJ_brainpoolP512r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,13L + +#define SN_brainpoolP512t1 "brainpoolP512t1" +#define NID_brainpoolP512t1 934 +#define OBJ_brainpoolP512t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,14L + +#define OBJ_x9_63_scheme 1L,3L,133L,16L,840L,63L,0L + +#define OBJ_secg_scheme OBJ_certicom_arc,1L + +#define SN_dhSinglePass_stdDH_sha1kdf_scheme "dhSinglePass-stdDH-sha1kdf-scheme" +#define NID_dhSinglePass_stdDH_sha1kdf_scheme 936 +#define OBJ_dhSinglePass_stdDH_sha1kdf_scheme OBJ_x9_63_scheme,2L + +#define SN_dhSinglePass_stdDH_sha224kdf_scheme "dhSinglePass-stdDH-sha224kdf-scheme" +#define NID_dhSinglePass_stdDH_sha224kdf_scheme 937 +#define OBJ_dhSinglePass_stdDH_sha224kdf_scheme OBJ_secg_scheme,11L,0L + +#define SN_dhSinglePass_stdDH_sha256kdf_scheme "dhSinglePass-stdDH-sha256kdf-scheme" +#define NID_dhSinglePass_stdDH_sha256kdf_scheme 938 +#define OBJ_dhSinglePass_stdDH_sha256kdf_scheme OBJ_secg_scheme,11L,1L + +#define SN_dhSinglePass_stdDH_sha384kdf_scheme "dhSinglePass-stdDH-sha384kdf-scheme" +#define NID_dhSinglePass_stdDH_sha384kdf_scheme 939 +#define OBJ_dhSinglePass_stdDH_sha384kdf_scheme OBJ_secg_scheme,11L,2L + +#define SN_dhSinglePass_stdDH_sha512kdf_scheme "dhSinglePass-stdDH-sha512kdf-scheme" +#define NID_dhSinglePass_stdDH_sha512kdf_scheme 940 +#define OBJ_dhSinglePass_stdDH_sha512kdf_scheme OBJ_secg_scheme,11L,3L + +#define SN_dhSinglePass_cofactorDH_sha1kdf_scheme "dhSinglePass-cofactorDH-sha1kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha1kdf_scheme 941 +#define OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme OBJ_x9_63_scheme,3L + +#define SN_dhSinglePass_cofactorDH_sha224kdf_scheme "dhSinglePass-cofactorDH-sha224kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha224kdf_scheme 942 +#define OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme OBJ_secg_scheme,14L,0L + +#define SN_dhSinglePass_cofactorDH_sha256kdf_scheme "dhSinglePass-cofactorDH-sha256kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha256kdf_scheme 943 +#define OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme OBJ_secg_scheme,14L,1L + +#define SN_dhSinglePass_cofactorDH_sha384kdf_scheme "dhSinglePass-cofactorDH-sha384kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha384kdf_scheme 944 +#define OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme OBJ_secg_scheme,14L,2L + +#define SN_dhSinglePass_cofactorDH_sha512kdf_scheme "dhSinglePass-cofactorDH-sha512kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha512kdf_scheme 945 +#define OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme OBJ_secg_scheme,14L,3L + +#define SN_dh_std_kdf "dh-std-kdf" +#define NID_dh_std_kdf 946 + +#define SN_dh_cofactor_kdf "dh-cofactor-kdf" +#define NID_dh_cofactor_kdf 947 + +#define SN_ct_precert_scts "ct_precert_scts" +#define LN_ct_precert_scts "CT Precertificate SCTs" +#define NID_ct_precert_scts 951 +#define OBJ_ct_precert_scts 1L,3L,6L,1L,4L,1L,11129L,2L,4L,2L + +#define SN_ct_precert_poison "ct_precert_poison" +#define LN_ct_precert_poison "CT Precertificate Poison" +#define NID_ct_precert_poison 952 +#define OBJ_ct_precert_poison 1L,3L,6L,1L,4L,1L,11129L,2L,4L,3L + +#define SN_ct_precert_signer "ct_precert_signer" +#define LN_ct_precert_signer "CT Precertificate Signer" +#define NID_ct_precert_signer 953 +#define OBJ_ct_precert_signer 1L,3L,6L,1L,4L,1L,11129L,2L,4L,4L + +#define SN_ct_cert_scts "ct_cert_scts" +#define LN_ct_cert_scts "CT Certificate SCTs" +#define NID_ct_cert_scts 954 +#define OBJ_ct_cert_scts 1L,3L,6L,1L,4L,1L,11129L,2L,4L,5L + +#define SN_jurisdictionLocalityName "jurisdictionL" +#define LN_jurisdictionLocalityName "jurisdictionLocalityName" +#define NID_jurisdictionLocalityName 955 +#define OBJ_jurisdictionLocalityName 1L,3L,6L,1L,4L,1L,311L,60L,2L,1L,1L + +#define SN_jurisdictionStateOrProvinceName "jurisdictionST" +#define LN_jurisdictionStateOrProvinceName "jurisdictionStateOrProvinceName" +#define NID_jurisdictionStateOrProvinceName 956 +#define OBJ_jurisdictionStateOrProvinceName 1L,3L,6L,1L,4L,1L,311L,60L,2L,1L,2L + +#define SN_jurisdictionCountryName "jurisdictionC" +#define LN_jurisdictionCountryName "jurisdictionCountryName" +#define NID_jurisdictionCountryName 957 +#define OBJ_jurisdictionCountryName 1L,3L,6L,1L,4L,1L,311L,60L,2L,1L,3L + +#define SN_id_scrypt "id-scrypt" +#define NID_id_scrypt 973 +#define OBJ_id_scrypt 1L,3L,6L,1L,4L,1L,11591L,4L,11L + +#define SN_tls1_prf "TLS1-PRF" +#define LN_tls1_prf "tls1-prf" +#define NID_tls1_prf 1021 + +#define SN_hkdf "HKDF" +#define LN_hkdf "hkdf" +#define NID_hkdf 1036 + +#define SN_id_pkinit "id-pkinit" +#define NID_id_pkinit 1031 +#define OBJ_id_pkinit 1L,3L,6L,1L,5L,2L,3L + +#define SN_pkInitClientAuth "pkInitClientAuth" +#define LN_pkInitClientAuth "PKINIT Client Auth" +#define NID_pkInitClientAuth 1032 +#define OBJ_pkInitClientAuth OBJ_id_pkinit,4L + +#define SN_pkInitKDC "pkInitKDC" +#define LN_pkInitKDC "Signing KDC Response" +#define NID_pkInitKDC 1033 +#define OBJ_pkInitKDC OBJ_id_pkinit,5L + +#define SN_X25519 "X25519" +#define NID_X25519 1034 +#define OBJ_X25519 1L,3L,101L,110L + +#define SN_X448 "X448" +#define NID_X448 1035 +#define OBJ_X448 1L,3L,101L,111L + +#define SN_kx_rsa "KxRSA" +#define LN_kx_rsa "kx-rsa" +#define NID_kx_rsa 1037 + +#define SN_kx_ecdhe "KxECDHE" +#define LN_kx_ecdhe "kx-ecdhe" +#define NID_kx_ecdhe 1038 + +#define SN_kx_dhe "KxDHE" +#define LN_kx_dhe "kx-dhe" +#define NID_kx_dhe 1039 + +#define SN_kx_ecdhe_psk "KxECDHE-PSK" +#define LN_kx_ecdhe_psk "kx-ecdhe-psk" +#define NID_kx_ecdhe_psk 1040 + +#define SN_kx_dhe_psk "KxDHE-PSK" +#define LN_kx_dhe_psk "kx-dhe-psk" +#define NID_kx_dhe_psk 1041 + +#define SN_kx_rsa_psk "KxRSA_PSK" +#define LN_kx_rsa_psk "kx-rsa-psk" +#define NID_kx_rsa_psk 1042 + +#define SN_kx_psk "KxPSK" +#define LN_kx_psk "kx-psk" +#define NID_kx_psk 1043 + +#define SN_kx_srp "KxSRP" +#define LN_kx_srp "kx-srp" +#define NID_kx_srp 1044 + +#define SN_kx_gost "KxGOST" +#define LN_kx_gost "kx-gost" +#define NID_kx_gost 1045 + +#define SN_auth_rsa "AuthRSA" +#define LN_auth_rsa "auth-rsa" +#define NID_auth_rsa 1046 + +#define SN_auth_ecdsa "AuthECDSA" +#define LN_auth_ecdsa "auth-ecdsa" +#define NID_auth_ecdsa 1047 + +#define SN_auth_psk "AuthPSK" +#define LN_auth_psk "auth-psk" +#define NID_auth_psk 1048 + +#define SN_auth_dss "AuthDSS" +#define LN_auth_dss "auth-dss" +#define NID_auth_dss 1049 + +#define SN_auth_gost01 "AuthGOST01" +#define LN_auth_gost01 "auth-gost01" +#define NID_auth_gost01 1050 + +#define SN_auth_gost12 "AuthGOST12" +#define LN_auth_gost12 "auth-gost12" +#define NID_auth_gost12 1051 + +#define SN_auth_srp "AuthSRP" +#define LN_auth_srp "auth-srp" +#define NID_auth_srp 1052 + +#define SN_auth_null "AuthNULL" +#define LN_auth_null "auth-null" +#define NID_auth_null 1053 diff --git a/mobile/ios/FxA/FxA/include/openssl/objects.h b/mobile/ios/FxA/FxA/include/openssl/objects.h new file mode 100644 index 0000000000..09d614ffc0 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/objects.h @@ -0,0 +1,1097 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_OBJECTS_H +# define HEADER_OBJECTS_H + +# define USE_OBJ_MAC + +# ifdef USE_OBJ_MAC +# include +# else +# define SN_undef "UNDEF" +# define LN_undef "undefined" +# define NID_undef 0 +# define OBJ_undef 0L + +# define SN_Algorithm "Algorithm" +# define LN_algorithm "algorithm" +# define NID_algorithm 38 +# define OBJ_algorithm 1L,3L,14L,3L,2L + +# define LN_rsadsi "rsadsi" +# define NID_rsadsi 1 +# define OBJ_rsadsi 1L,2L,840L,113549L + +# define LN_pkcs "pkcs" +# define NID_pkcs 2 +# define OBJ_pkcs OBJ_rsadsi,1L + +# define SN_md2 "MD2" +# define LN_md2 "md2" +# define NID_md2 3 +# define OBJ_md2 OBJ_rsadsi,2L,2L + +# define SN_md5 "MD5" +# define LN_md5 "md5" +# define NID_md5 4 +# define OBJ_md5 OBJ_rsadsi,2L,5L + +# define SN_rc4 "RC4" +# define LN_rc4 "rc4" +# define NID_rc4 5 +# define OBJ_rc4 OBJ_rsadsi,3L,4L + +# define LN_rsaEncryption "rsaEncryption" +# define NID_rsaEncryption 6 +# define OBJ_rsaEncryption OBJ_pkcs,1L,1L + +# define SN_md2WithRSAEncryption "RSA-MD2" +# define LN_md2WithRSAEncryption "md2WithRSAEncryption" +# define NID_md2WithRSAEncryption 7 +# define OBJ_md2WithRSAEncryption OBJ_pkcs,1L,2L + +# define SN_md5WithRSAEncryption "RSA-MD5" +# define LN_md5WithRSAEncryption "md5WithRSAEncryption" +# define NID_md5WithRSAEncryption 8 +# define OBJ_md5WithRSAEncryption OBJ_pkcs,1L,4L + +# define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" +# define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" +# define NID_pbeWithMD2AndDES_CBC 9 +# define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs,5L,1L + +# define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" +# define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" +# define NID_pbeWithMD5AndDES_CBC 10 +# define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs,5L,3L + +# define LN_X500 "X500" +# define NID_X500 11 +# define OBJ_X500 2L,5L + +# define LN_X509 "X509" +# define NID_X509 12 +# define OBJ_X509 OBJ_X500,4L + +# define SN_commonName "CN" +# define LN_commonName "commonName" +# define NID_commonName 13 +# define OBJ_commonName OBJ_X509,3L + +# define SN_countryName "C" +# define LN_countryName "countryName" +# define NID_countryName 14 +# define OBJ_countryName OBJ_X509,6L + +# define SN_localityName "L" +# define LN_localityName "localityName" +# define NID_localityName 15 +# define OBJ_localityName OBJ_X509,7L + +/* Postal Address? PA */ + +/* should be "ST" (rfc1327) but MS uses 'S' */ +# define SN_stateOrProvinceName "ST" +# define LN_stateOrProvinceName "stateOrProvinceName" +# define NID_stateOrProvinceName 16 +# define OBJ_stateOrProvinceName OBJ_X509,8L + +# define SN_organizationName "O" +# define LN_organizationName "organizationName" +# define NID_organizationName 17 +# define OBJ_organizationName OBJ_X509,10L + +# define SN_organizationalUnitName "OU" +# define LN_organizationalUnitName "organizationalUnitName" +# define NID_organizationalUnitName 18 +# define OBJ_organizationalUnitName OBJ_X509,11L + +# define SN_rsa "RSA" +# define LN_rsa "rsa" +# define NID_rsa 19 +# define OBJ_rsa OBJ_X500,8L,1L,1L + +# define LN_pkcs7 "pkcs7" +# define NID_pkcs7 20 +# define OBJ_pkcs7 OBJ_pkcs,7L + +# define LN_pkcs7_data "pkcs7-data" +# define NID_pkcs7_data 21 +# define OBJ_pkcs7_data OBJ_pkcs7,1L + +# define LN_pkcs7_signed "pkcs7-signedData" +# define NID_pkcs7_signed 22 +# define OBJ_pkcs7_signed OBJ_pkcs7,2L + +# define LN_pkcs7_enveloped "pkcs7-envelopedData" +# define NID_pkcs7_enveloped 23 +# define OBJ_pkcs7_enveloped OBJ_pkcs7,3L + +# define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" +# define NID_pkcs7_signedAndEnveloped 24 +# define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L + +# define LN_pkcs7_digest "pkcs7-digestData" +# define NID_pkcs7_digest 25 +# define OBJ_pkcs7_digest OBJ_pkcs7,5L + +# define LN_pkcs7_encrypted "pkcs7-encryptedData" +# define NID_pkcs7_encrypted 26 +# define OBJ_pkcs7_encrypted OBJ_pkcs7,6L + +# define LN_pkcs3 "pkcs3" +# define NID_pkcs3 27 +# define OBJ_pkcs3 OBJ_pkcs,3L + +# define LN_dhKeyAgreement "dhKeyAgreement" +# define NID_dhKeyAgreement 28 +# define OBJ_dhKeyAgreement OBJ_pkcs3,1L + +# define SN_des_ecb "DES-ECB" +# define LN_des_ecb "des-ecb" +# define NID_des_ecb 29 +# define OBJ_des_ecb OBJ_algorithm,6L + +# define SN_des_cfb64 "DES-CFB" +# define LN_des_cfb64 "des-cfb" +# define NID_des_cfb64 30 +/* IV + num */ +# define OBJ_des_cfb64 OBJ_algorithm,9L + +# define SN_des_cbc "DES-CBC" +# define LN_des_cbc "des-cbc" +# define NID_des_cbc 31 +/* IV */ +# define OBJ_des_cbc OBJ_algorithm,7L + +# define SN_des_ede "DES-EDE" +# define LN_des_ede "des-ede" +# define NID_des_ede 32 +/* ?? */ +# define OBJ_des_ede OBJ_algorithm,17L + +# define SN_des_ede3 "DES-EDE3" +# define LN_des_ede3 "des-ede3" +# define NID_des_ede3 33 + +# define SN_idea_cbc "IDEA-CBC" +# define LN_idea_cbc "idea-cbc" +# define NID_idea_cbc 34 +# define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L + +# define SN_idea_cfb64 "IDEA-CFB" +# define LN_idea_cfb64 "idea-cfb" +# define NID_idea_cfb64 35 + +# define SN_idea_ecb "IDEA-ECB" +# define LN_idea_ecb "idea-ecb" +# define NID_idea_ecb 36 + +# define SN_rc2_cbc "RC2-CBC" +# define LN_rc2_cbc "rc2-cbc" +# define NID_rc2_cbc 37 +# define OBJ_rc2_cbc OBJ_rsadsi,3L,2L + +# define SN_rc2_ecb "RC2-ECB" +# define LN_rc2_ecb "rc2-ecb" +# define NID_rc2_ecb 38 + +# define SN_rc2_cfb64 "RC2-CFB" +# define LN_rc2_cfb64 "rc2-cfb" +# define NID_rc2_cfb64 39 + +# define SN_rc2_ofb64 "RC2-OFB" +# define LN_rc2_ofb64 "rc2-ofb" +# define NID_rc2_ofb64 40 + +# define SN_sha "SHA" +# define LN_sha "sha" +# define NID_sha 41 +# define OBJ_sha OBJ_algorithm,18L + +# define SN_shaWithRSAEncryption "RSA-SHA" +# define LN_shaWithRSAEncryption "shaWithRSAEncryption" +# define NID_shaWithRSAEncryption 42 +# define OBJ_shaWithRSAEncryption OBJ_algorithm,15L + +# define SN_des_ede_cbc "DES-EDE-CBC" +# define LN_des_ede_cbc "des-ede-cbc" +# define NID_des_ede_cbc 43 + +# define SN_des_ede3_cbc "DES-EDE3-CBC" +# define LN_des_ede3_cbc "des-ede3-cbc" +# define NID_des_ede3_cbc 44 +# define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L + +# define SN_des_ofb64 "DES-OFB" +# define LN_des_ofb64 "des-ofb" +# define NID_des_ofb64 45 +# define OBJ_des_ofb64 OBJ_algorithm,8L + +# define SN_idea_ofb64 "IDEA-OFB" +# define LN_idea_ofb64 "idea-ofb" +# define NID_idea_ofb64 46 + +# define LN_pkcs9 "pkcs9" +# define NID_pkcs9 47 +# define OBJ_pkcs9 OBJ_pkcs,9L + +# define SN_pkcs9_emailAddress "Email" +# define LN_pkcs9_emailAddress "emailAddress" +# define NID_pkcs9_emailAddress 48 +# define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L + +# define LN_pkcs9_unstructuredName "unstructuredName" +# define NID_pkcs9_unstructuredName 49 +# define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L + +# define LN_pkcs9_contentType "contentType" +# define NID_pkcs9_contentType 50 +# define OBJ_pkcs9_contentType OBJ_pkcs9,3L + +# define LN_pkcs9_messageDigest "messageDigest" +# define NID_pkcs9_messageDigest 51 +# define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L + +# define LN_pkcs9_signingTime "signingTime" +# define NID_pkcs9_signingTime 52 +# define OBJ_pkcs9_signingTime OBJ_pkcs9,5L + +# define LN_pkcs9_countersignature "countersignature" +# define NID_pkcs9_countersignature 53 +# define OBJ_pkcs9_countersignature OBJ_pkcs9,6L + +# define LN_pkcs9_challengePassword "challengePassword" +# define NID_pkcs9_challengePassword 54 +# define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L + +# define LN_pkcs9_unstructuredAddress "unstructuredAddress" +# define NID_pkcs9_unstructuredAddress 55 +# define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L + +# define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" +# define NID_pkcs9_extCertAttributes 56 +# define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L + +# define SN_netscape "Netscape" +# define LN_netscape "Netscape Communications Corp." +# define NID_netscape 57 +# define OBJ_netscape 2L,16L,840L,1L,113730L + +# define SN_netscape_cert_extension "nsCertExt" +# define LN_netscape_cert_extension "Netscape Certificate Extension" +# define NID_netscape_cert_extension 58 +# define OBJ_netscape_cert_extension OBJ_netscape,1L + +# define SN_netscape_data_type "nsDataType" +# define LN_netscape_data_type "Netscape Data Type" +# define NID_netscape_data_type 59 +# define OBJ_netscape_data_type OBJ_netscape,2L + +# define SN_des_ede_cfb64 "DES-EDE-CFB" +# define LN_des_ede_cfb64 "des-ede-cfb" +# define NID_des_ede_cfb64 60 + +# define SN_des_ede3_cfb64 "DES-EDE3-CFB" +# define LN_des_ede3_cfb64 "des-ede3-cfb" +# define NID_des_ede3_cfb64 61 + +# define SN_des_ede_ofb64 "DES-EDE-OFB" +# define LN_des_ede_ofb64 "des-ede-ofb" +# define NID_des_ede_ofb64 62 + +# define SN_des_ede3_ofb64 "DES-EDE3-OFB" +# define LN_des_ede3_ofb64 "des-ede3-ofb" +# define NID_des_ede3_ofb64 63 + +/* I'm not sure about the object ID */ +# define SN_sha1 "SHA1" +# define LN_sha1 "sha1" +# define NID_sha1 64 +# define OBJ_sha1 OBJ_algorithm,26L +/* 28 Jun 1996 - eay */ +/* #define OBJ_sha1 1L,3L,14L,2L,26L,05L <- wrong */ + +# define SN_sha1WithRSAEncryption "RSA-SHA1" +# define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" +# define NID_sha1WithRSAEncryption 65 +# define OBJ_sha1WithRSAEncryption OBJ_pkcs,1L,5L + +# define SN_dsaWithSHA "DSA-SHA" +# define LN_dsaWithSHA "dsaWithSHA" +# define NID_dsaWithSHA 66 +# define OBJ_dsaWithSHA OBJ_algorithm,13L + +# define SN_dsa_2 "DSA-old" +# define LN_dsa_2 "dsaEncryption-old" +# define NID_dsa_2 67 +# define OBJ_dsa_2 OBJ_algorithm,12L + +/* proposed by microsoft to RSA */ +# define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" +# define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" +# define NID_pbeWithSHA1AndRC2_CBC 68 +# define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs,5L,11L + +/* + * proposed by microsoft to RSA as pbeWithSHA1AndRC4: it is now defined + * explicitly in PKCS#5 v2.0 as id-PBKDF2 which is something completely + * different. + */ +# define LN_id_pbkdf2 "PBKDF2" +# define NID_id_pbkdf2 69 +# define OBJ_id_pbkdf2 OBJ_pkcs,5L,12L + +# define SN_dsaWithSHA1_2 "DSA-SHA1-old" +# define LN_dsaWithSHA1_2 "dsaWithSHA1-old" +# define NID_dsaWithSHA1_2 70 +/* Got this one from 'sdn706r20.pdf' which is actually an NSA document :-) */ +# define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L + +# define SN_netscape_cert_type "nsCertType" +# define LN_netscape_cert_type "Netscape Cert Type" +# define NID_netscape_cert_type 71 +# define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L + +# define SN_netscape_base_url "nsBaseUrl" +# define LN_netscape_base_url "Netscape Base Url" +# define NID_netscape_base_url 72 +# define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L + +# define SN_netscape_revocation_url "nsRevocationUrl" +# define LN_netscape_revocation_url "Netscape Revocation Url" +# define NID_netscape_revocation_url 73 +# define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L + +# define SN_netscape_ca_revocation_url "nsCaRevocationUrl" +# define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" +# define NID_netscape_ca_revocation_url 74 +# define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L + +# define SN_netscape_renewal_url "nsRenewalUrl" +# define LN_netscape_renewal_url "Netscape Renewal Url" +# define NID_netscape_renewal_url 75 +# define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L + +# define SN_netscape_ca_policy_url "nsCaPolicyUrl" +# define LN_netscape_ca_policy_url "Netscape CA Policy Url" +# define NID_netscape_ca_policy_url 76 +# define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L + +# define SN_netscape_ssl_server_name "nsSslServerName" +# define LN_netscape_ssl_server_name "Netscape SSL Server Name" +# define NID_netscape_ssl_server_name 77 +# define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L + +# define SN_netscape_comment "nsComment" +# define LN_netscape_comment "Netscape Comment" +# define NID_netscape_comment 78 +# define OBJ_netscape_comment OBJ_netscape_cert_extension,13L + +# define SN_netscape_cert_sequence "nsCertSequence" +# define LN_netscape_cert_sequence "Netscape Certificate Sequence" +# define NID_netscape_cert_sequence 79 +# define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L + +# define SN_desx_cbc "DESX-CBC" +# define LN_desx_cbc "desx-cbc" +# define NID_desx_cbc 80 + +# define SN_id_ce "id-ce" +# define NID_id_ce 81 +# define OBJ_id_ce 2L,5L,29L + +# define SN_subject_key_identifier "subjectKeyIdentifier" +# define LN_subject_key_identifier "X509v3 Subject Key Identifier" +# define NID_subject_key_identifier 82 +# define OBJ_subject_key_identifier OBJ_id_ce,14L + +# define SN_key_usage "keyUsage" +# define LN_key_usage "X509v3 Key Usage" +# define NID_key_usage 83 +# define OBJ_key_usage OBJ_id_ce,15L + +# define SN_private_key_usage_period "privateKeyUsagePeriod" +# define LN_private_key_usage_period "X509v3 Private Key Usage Period" +# define NID_private_key_usage_period 84 +# define OBJ_private_key_usage_period OBJ_id_ce,16L + +# define SN_subject_alt_name "subjectAltName" +# define LN_subject_alt_name "X509v3 Subject Alternative Name" +# define NID_subject_alt_name 85 +# define OBJ_subject_alt_name OBJ_id_ce,17L + +# define SN_issuer_alt_name "issuerAltName" +# define LN_issuer_alt_name "X509v3 Issuer Alternative Name" +# define NID_issuer_alt_name 86 +# define OBJ_issuer_alt_name OBJ_id_ce,18L + +# define SN_basic_constraints "basicConstraints" +# define LN_basic_constraints "X509v3 Basic Constraints" +# define NID_basic_constraints 87 +# define OBJ_basic_constraints OBJ_id_ce,19L + +# define SN_crl_number "crlNumber" +# define LN_crl_number "X509v3 CRL Number" +# define NID_crl_number 88 +# define OBJ_crl_number OBJ_id_ce,20L + +# define SN_certificate_policies "certificatePolicies" +# define LN_certificate_policies "X509v3 Certificate Policies" +# define NID_certificate_policies 89 +# define OBJ_certificate_policies OBJ_id_ce,32L + +# define SN_authority_key_identifier "authorityKeyIdentifier" +# define LN_authority_key_identifier "X509v3 Authority Key Identifier" +# define NID_authority_key_identifier 90 +# define OBJ_authority_key_identifier OBJ_id_ce,35L + +# define SN_bf_cbc "BF-CBC" +# define LN_bf_cbc "bf-cbc" +# define NID_bf_cbc 91 +# define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L + +# define SN_bf_ecb "BF-ECB" +# define LN_bf_ecb "bf-ecb" +# define NID_bf_ecb 92 + +# define SN_bf_cfb64 "BF-CFB" +# define LN_bf_cfb64 "bf-cfb" +# define NID_bf_cfb64 93 + +# define SN_bf_ofb64 "BF-OFB" +# define LN_bf_ofb64 "bf-ofb" +# define NID_bf_ofb64 94 + +# define SN_mdc2 "MDC2" +# define LN_mdc2 "mdc2" +# define NID_mdc2 95 +# define OBJ_mdc2 2L,5L,8L,3L,101L +/* An alternative? 1L,3L,14L,3L,2L,19L */ + +# define SN_mdc2WithRSA "RSA-MDC2" +# define LN_mdc2WithRSA "mdc2withRSA" +# define NID_mdc2WithRSA 96 +# define OBJ_mdc2WithRSA 2L,5L,8L,3L,100L + +# define SN_rc4_40 "RC4-40" +# define LN_rc4_40 "rc4-40" +# define NID_rc4_40 97 + +# define SN_rc2_40_cbc "RC2-40-CBC" +# define LN_rc2_40_cbc "rc2-40-cbc" +# define NID_rc2_40_cbc 98 + +# define SN_givenName "G" +# define LN_givenName "givenName" +# define NID_givenName 99 +# define OBJ_givenName OBJ_X509,42L + +# define SN_surname "S" +# define LN_surname "surname" +# define NID_surname 100 +# define OBJ_surname OBJ_X509,4L + +# define SN_initials "I" +# define LN_initials "initials" +# define NID_initials 101 +# define OBJ_initials OBJ_X509,43L + +# define SN_uniqueIdentifier "UID" +# define LN_uniqueIdentifier "uniqueIdentifier" +# define NID_uniqueIdentifier 102 +# define OBJ_uniqueIdentifier OBJ_X509,45L + +# define SN_crl_distribution_points "crlDistributionPoints" +# define LN_crl_distribution_points "X509v3 CRL Distribution Points" +# define NID_crl_distribution_points 103 +# define OBJ_crl_distribution_points OBJ_id_ce,31L + +# define SN_md5WithRSA "RSA-NP-MD5" +# define LN_md5WithRSA "md5WithRSA" +# define NID_md5WithRSA 104 +# define OBJ_md5WithRSA OBJ_algorithm,3L + +# define SN_serialNumber "SN" +# define LN_serialNumber "serialNumber" +# define NID_serialNumber 105 +# define OBJ_serialNumber OBJ_X509,5L + +# define SN_title "T" +# define LN_title "title" +# define NID_title 106 +# define OBJ_title OBJ_X509,12L + +# define SN_description "D" +# define LN_description "description" +# define NID_description 107 +# define OBJ_description OBJ_X509,13L + +/* CAST5 is CAST-128, I'm just sticking with the documentation */ +# define SN_cast5_cbc "CAST5-CBC" +# define LN_cast5_cbc "cast5-cbc" +# define NID_cast5_cbc 108 +# define OBJ_cast5_cbc 1L,2L,840L,113533L,7L,66L,10L + +# define SN_cast5_ecb "CAST5-ECB" +# define LN_cast5_ecb "cast5-ecb" +# define NID_cast5_ecb 109 + +# define SN_cast5_cfb64 "CAST5-CFB" +# define LN_cast5_cfb64 "cast5-cfb" +# define NID_cast5_cfb64 110 + +# define SN_cast5_ofb64 "CAST5-OFB" +# define LN_cast5_ofb64 "cast5-ofb" +# define NID_cast5_ofb64 111 + +# define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" +# define NID_pbeWithMD5AndCast5_CBC 112 +# define OBJ_pbeWithMD5AndCast5_CBC 1L,2L,840L,113533L,7L,66L,12L + +/*- + * This is one sun will soon be using :-( + * id-dsa-with-sha1 ID ::= { + * iso(1) member-body(2) us(840) x9-57 (10040) x9cm(4) 3 } + */ +# define SN_dsaWithSHA1 "DSA-SHA1" +# define LN_dsaWithSHA1 "dsaWithSHA1" +# define NID_dsaWithSHA1 113 +# define OBJ_dsaWithSHA1 1L,2L,840L,10040L,4L,3L + +# define NID_md5_sha1 114 +# define SN_md5_sha1 "MD5-SHA1" +# define LN_md5_sha1 "md5-sha1" + +# define SN_sha1WithRSA "RSA-SHA1-2" +# define LN_sha1WithRSA "sha1WithRSA" +# define NID_sha1WithRSA 115 +# define OBJ_sha1WithRSA OBJ_algorithm,29L + +# define SN_dsa "DSA" +# define LN_dsa "dsaEncryption" +# define NID_dsa 116 +# define OBJ_dsa 1L,2L,840L,10040L,4L,1L + +# define SN_ripemd160 "RIPEMD160" +# define LN_ripemd160 "ripemd160" +# define NID_ripemd160 117 +# define OBJ_ripemd160 1L,3L,36L,3L,2L,1L + +/* + * The name should actually be rsaSignatureWithripemd160, but I'm going to + * continue using the convention I'm using with the other ciphers + */ +# define SN_ripemd160WithRSA "RSA-RIPEMD160" +# define LN_ripemd160WithRSA "ripemd160WithRSA" +# define NID_ripemd160WithRSA 119 +# define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L + +/*- + * Taken from rfc2040 + * RC5_CBC_Parameters ::= SEQUENCE { + * version INTEGER (v1_0(16)), + * rounds INTEGER (8..127), + * blockSizeInBits INTEGER (64, 128), + * iv OCTET STRING OPTIONAL + * } + */ +# define SN_rc5_cbc "RC5-CBC" +# define LN_rc5_cbc "rc5-cbc" +# define NID_rc5_cbc 120 +# define OBJ_rc5_cbc OBJ_rsadsi,3L,8L + +# define SN_rc5_ecb "RC5-ECB" +# define LN_rc5_ecb "rc5-ecb" +# define NID_rc5_ecb 121 + +# define SN_rc5_cfb64 "RC5-CFB" +# define LN_rc5_cfb64 "rc5-cfb" +# define NID_rc5_cfb64 122 + +# define SN_rc5_ofb64 "RC5-OFB" +# define LN_rc5_ofb64 "rc5-ofb" +# define NID_rc5_ofb64 123 + +# define SN_rle_compression "RLE" +# define LN_rle_compression "run length compression" +# define NID_rle_compression 124 +# define OBJ_rle_compression 1L,1L,1L,1L,666L,1L + +# define SN_zlib_compression "ZLIB" +# define LN_zlib_compression "zlib compression" +# define NID_zlib_compression 125 +# define OBJ_zlib_compression 1L,1L,1L,1L,666L,2L + +# define SN_ext_key_usage "extendedKeyUsage" +# define LN_ext_key_usage "X509v3 Extended Key Usage" +# define NID_ext_key_usage 126 +# define OBJ_ext_key_usage OBJ_id_ce,37 + +# define SN_id_pkix "PKIX" +# define NID_id_pkix 127 +# define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L + +# define SN_id_kp "id-kp" +# define NID_id_kp 128 +# define OBJ_id_kp OBJ_id_pkix,3L + +/* PKIX extended key usage OIDs */ + +# define SN_server_auth "serverAuth" +# define LN_server_auth "TLS Web Server Authentication" +# define NID_server_auth 129 +# define OBJ_server_auth OBJ_id_kp,1L + +# define SN_client_auth "clientAuth" +# define LN_client_auth "TLS Web Client Authentication" +# define NID_client_auth 130 +# define OBJ_client_auth OBJ_id_kp,2L + +# define SN_code_sign "codeSigning" +# define LN_code_sign "Code Signing" +# define NID_code_sign 131 +# define OBJ_code_sign OBJ_id_kp,3L + +# define SN_email_protect "emailProtection" +# define LN_email_protect "E-mail Protection" +# define NID_email_protect 132 +# define OBJ_email_protect OBJ_id_kp,4L + +# define SN_time_stamp "timeStamping" +# define LN_time_stamp "Time Stamping" +# define NID_time_stamp 133 +# define OBJ_time_stamp OBJ_id_kp,8L + +/* Additional extended key usage OIDs: Microsoft */ + +# define SN_ms_code_ind "msCodeInd" +# define LN_ms_code_ind "Microsoft Individual Code Signing" +# define NID_ms_code_ind 134 +# define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L + +# define SN_ms_code_com "msCodeCom" +# define LN_ms_code_com "Microsoft Commercial Code Signing" +# define NID_ms_code_com 135 +# define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L + +# define SN_ms_ctl_sign "msCTLSign" +# define LN_ms_ctl_sign "Microsoft Trust List Signing" +# define NID_ms_ctl_sign 136 +# define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L + +# define SN_ms_sgc "msSGC" +# define LN_ms_sgc "Microsoft Server Gated Crypto" +# define NID_ms_sgc 137 +# define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L + +# define SN_ms_efs "msEFS" +# define LN_ms_efs "Microsoft Encrypted File System" +# define NID_ms_efs 138 +# define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L + +/* Additional usage: Netscape */ + +# define SN_ns_sgc "nsSGC" +# define LN_ns_sgc "Netscape Server Gated Crypto" +# define NID_ns_sgc 139 +# define OBJ_ns_sgc OBJ_netscape,4L,1L + +# define SN_delta_crl "deltaCRL" +# define LN_delta_crl "X509v3 Delta CRL Indicator" +# define NID_delta_crl 140 +# define OBJ_delta_crl OBJ_id_ce,27L + +# define SN_crl_reason "CRLReason" +# define LN_crl_reason "CRL Reason Code" +# define NID_crl_reason 141 +# define OBJ_crl_reason OBJ_id_ce,21L + +# define SN_invalidity_date "invalidityDate" +# define LN_invalidity_date "Invalidity Date" +# define NID_invalidity_date 142 +# define OBJ_invalidity_date OBJ_id_ce,24L + +# define SN_sxnet "SXNetID" +# define LN_sxnet "Strong Extranet ID" +# define NID_sxnet 143 +# define OBJ_sxnet 1L,3L,101L,1L,4L,1L + +/* PKCS12 and related OBJECT IDENTIFIERS */ + +# define OBJ_pkcs12 OBJ_pkcs,12L +# define OBJ_pkcs12_pbeids OBJ_pkcs12, 1 + +# define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" +# define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" +# define NID_pbe_WithSHA1And128BitRC4 144 +# define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids, 1L + +# define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" +# define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" +# define NID_pbe_WithSHA1And40BitRC4 145 +# define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids, 2L + +# define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" +# define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" +# define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 +# define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids, 3L + +# define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" +# define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" +# define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 +# define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids, 4L + +# define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" +# define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" +# define NID_pbe_WithSHA1And128BitRC2_CBC 148 +# define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids, 5L + +# define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" +# define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" +# define NID_pbe_WithSHA1And40BitRC2_CBC 149 +# define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids, 6L + +# define OBJ_pkcs12_Version1 OBJ_pkcs12, 10L + +# define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1, 1L + +# define LN_keyBag "keyBag" +# define NID_keyBag 150 +# define OBJ_keyBag OBJ_pkcs12_BagIds, 1L + +# define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" +# define NID_pkcs8ShroudedKeyBag 151 +# define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds, 2L + +# define LN_certBag "certBag" +# define NID_certBag 152 +# define OBJ_certBag OBJ_pkcs12_BagIds, 3L + +# define LN_crlBag "crlBag" +# define NID_crlBag 153 +# define OBJ_crlBag OBJ_pkcs12_BagIds, 4L + +# define LN_secretBag "secretBag" +# define NID_secretBag 154 +# define OBJ_secretBag OBJ_pkcs12_BagIds, 5L + +# define LN_safeContentsBag "safeContentsBag" +# define NID_safeContentsBag 155 +# define OBJ_safeContentsBag OBJ_pkcs12_BagIds, 6L + +# define LN_friendlyName "friendlyName" +# define NID_friendlyName 156 +# define OBJ_friendlyName OBJ_pkcs9, 20L + +# define LN_localKeyID "localKeyID" +# define NID_localKeyID 157 +# define OBJ_localKeyID OBJ_pkcs9, 21L + +# define OBJ_certTypes OBJ_pkcs9, 22L + +# define LN_x509Certificate "x509Certificate" +# define NID_x509Certificate 158 +# define OBJ_x509Certificate OBJ_certTypes, 1L + +# define LN_sdsiCertificate "sdsiCertificate" +# define NID_sdsiCertificate 159 +# define OBJ_sdsiCertificate OBJ_certTypes, 2L + +# define OBJ_crlTypes OBJ_pkcs9, 23L + +# define LN_x509Crl "x509Crl" +# define NID_x509Crl 160 +# define OBJ_x509Crl OBJ_crlTypes, 1L + +/* PKCS#5 v2 OIDs */ + +# define LN_pbes2 "PBES2" +# define NID_pbes2 161 +# define OBJ_pbes2 OBJ_pkcs,5L,13L + +# define LN_pbmac1 "PBMAC1" +# define NID_pbmac1 162 +# define OBJ_pbmac1 OBJ_pkcs,5L,14L + +# define LN_hmacWithSHA1 "hmacWithSHA1" +# define NID_hmacWithSHA1 163 +# define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L + +/* Policy Qualifier Ids */ + +# define LN_id_qt_cps "Policy Qualifier CPS" +# define SN_id_qt_cps "id-qt-cps" +# define NID_id_qt_cps 164 +# define OBJ_id_qt_cps OBJ_id_pkix,2L,1L + +# define LN_id_qt_unotice "Policy Qualifier User Notice" +# define SN_id_qt_unotice "id-qt-unotice" +# define NID_id_qt_unotice 165 +# define OBJ_id_qt_unotice OBJ_id_pkix,2L,2L + +# define SN_rc2_64_cbc "RC2-64-CBC" +# define LN_rc2_64_cbc "rc2-64-cbc" +# define NID_rc2_64_cbc 166 + +# define SN_SMIMECapabilities "SMIME-CAPS" +# define LN_SMIMECapabilities "S/MIME Capabilities" +# define NID_SMIMECapabilities 167 +# define OBJ_SMIMECapabilities OBJ_pkcs9,15L + +# define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" +# define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" +# define NID_pbeWithMD2AndRC2_CBC 168 +# define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs,5L,4L + +# define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" +# define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" +# define NID_pbeWithMD5AndRC2_CBC 169 +# define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs,5L,6L + +# define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" +# define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" +# define NID_pbeWithSHA1AndDES_CBC 170 +# define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs,5L,10L + +/* Extension request OIDs */ + +# define LN_ms_ext_req "Microsoft Extension Request" +# define SN_ms_ext_req "msExtReq" +# define NID_ms_ext_req 171 +# define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L + +# define LN_ext_req "Extension Request" +# define SN_ext_req "extReq" +# define NID_ext_req 172 +# define OBJ_ext_req OBJ_pkcs9,14L + +# define SN_name "name" +# define LN_name "name" +# define NID_name 173 +# define OBJ_name OBJ_X509,41L + +# define SN_dnQualifier "dnQualifier" +# define LN_dnQualifier "dnQualifier" +# define NID_dnQualifier 174 +# define OBJ_dnQualifier OBJ_X509,46L + +# define SN_id_pe "id-pe" +# define NID_id_pe 175 +# define OBJ_id_pe OBJ_id_pkix,1L + +# define SN_id_ad "id-ad" +# define NID_id_ad 176 +# define OBJ_id_ad OBJ_id_pkix,48L + +# define SN_info_access "authorityInfoAccess" +# define LN_info_access "Authority Information Access" +# define NID_info_access 177 +# define OBJ_info_access OBJ_id_pe,1L + +# define SN_ad_OCSP "OCSP" +# define LN_ad_OCSP "OCSP" +# define NID_ad_OCSP 178 +# define OBJ_ad_OCSP OBJ_id_ad,1L + +# define SN_ad_ca_issuers "caIssuers" +# define LN_ad_ca_issuers "CA Issuers" +# define NID_ad_ca_issuers 179 +# define OBJ_ad_ca_issuers OBJ_id_ad,2L + +# define SN_OCSP_sign "OCSPSigning" +# define LN_OCSP_sign "OCSP Signing" +# define NID_OCSP_sign 180 +# define OBJ_OCSP_sign OBJ_id_kp,9L +# endif /* USE_OBJ_MAC */ + +# include +# include + +# define OBJ_NAME_TYPE_UNDEF 0x00 +# define OBJ_NAME_TYPE_MD_METH 0x01 +# define OBJ_NAME_TYPE_CIPHER_METH 0x02 +# define OBJ_NAME_TYPE_PKEY_METH 0x03 +# define OBJ_NAME_TYPE_COMP_METH 0x04 +# define OBJ_NAME_TYPE_NUM 0x05 + +# define OBJ_NAME_ALIAS 0x8000 + +# define OBJ_BSEARCH_VALUE_ON_NOMATCH 0x01 +# define OBJ_BSEARCH_FIRST_VALUE_ON_MATCH 0x02 + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct obj_name_st { + int type; + int alias; + const char *name; + const char *data; +} OBJ_NAME; + +# define OBJ_create_and_add_object(a,b,c) OBJ_create(a,b,c) + +int OBJ_NAME_init(void); +int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *), + int (*cmp_func) (const char *, const char *), + void (*free_func) (const char *, int, const char *)); +const char *OBJ_NAME_get(const char *name, int type); +int OBJ_NAME_add(const char *name, int type, const char *data); +int OBJ_NAME_remove(const char *name, int type); +void OBJ_NAME_cleanup(int type); /* -1 for everything */ +void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg), + void *arg); +void OBJ_NAME_do_all_sorted(int type, + void (*fn) (const OBJ_NAME *, void *arg), + void *arg); + +ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *o); +ASN1_OBJECT *OBJ_nid2obj(int n); +const char *OBJ_nid2ln(int n); +const char *OBJ_nid2sn(int n); +int OBJ_obj2nid(const ASN1_OBJECT *o); +ASN1_OBJECT *OBJ_txt2obj(const char *s, int no_name); +int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name); +int OBJ_txt2nid(const char *s); +int OBJ_ln2nid(const char *s); +int OBJ_sn2nid(const char *s); +int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b); +const void *OBJ_bsearch_(const void *key, const void *base, int num, int size, + int (*cmp) (const void *, const void *)); +const void *OBJ_bsearch_ex_(const void *key, const void *base, int num, + int size, + int (*cmp) (const void *, const void *), + int flags); + +# define _DECLARE_OBJ_BSEARCH_CMP_FN(scope, type1, type2, nm) \ + static int nm##_cmp_BSEARCH_CMP_FN(const void *, const void *); \ + static int nm##_cmp(type1 const *, type2 const *); \ + scope type2 * OBJ_bsearch_##nm(type1 *key, type2 const *base, int num) + +# define DECLARE_OBJ_BSEARCH_CMP_FN(type1, type2, cmp) \ + _DECLARE_OBJ_BSEARCH_CMP_FN(static, type1, type2, cmp) +# define DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(type1, type2, nm) \ + type2 * OBJ_bsearch_##nm(type1 *key, type2 const *base, int num) + +/*- + * Unsolved problem: if a type is actually a pointer type, like + * nid_triple is, then its impossible to get a const where you need + * it. Consider: + * + * typedef int nid_triple[3]; + * const void *a_; + * const nid_triple const *a = a_; + * + * The assignement discards a const because what you really want is: + * + * const int const * const *a = a_; + * + * But if you do that, you lose the fact that a is an array of 3 ints, + * which breaks comparison functions. + * + * Thus we end up having to cast, sadly, or unpack the + * declarations. Or, as I finally did in this case, delcare nid_triple + * to be a struct, which it should have been in the first place. + * + * Ben, August 2008. + * + * Also, strictly speaking not all types need be const, but handling + * the non-constness means a lot of complication, and in practice + * comparison routines do always not touch their arguments. + */ + +# define IMPLEMENT_OBJ_BSEARCH_CMP_FN(type1, type2, nm) \ + static int nm##_cmp_BSEARCH_CMP_FN(const void *a_, const void *b_) \ + { \ + type1 const *a = a_; \ + type2 const *b = b_; \ + return nm##_cmp(a,b); \ + } \ + static type2 *OBJ_bsearch_##nm(type1 *key, type2 const *base, int num) \ + { \ + return (type2 *)OBJ_bsearch_(key, base, num, sizeof(type2), \ + nm##_cmp_BSEARCH_CMP_FN); \ + } \ + extern void dummy_prototype(void) + +# define IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(type1, type2, nm) \ + static int nm##_cmp_BSEARCH_CMP_FN(const void *a_, const void *b_) \ + { \ + type1 const *a = a_; \ + type2 const *b = b_; \ + return nm##_cmp(a,b); \ + } \ + type2 *OBJ_bsearch_##nm(type1 *key, type2 const *base, int num) \ + { \ + return (type2 *)OBJ_bsearch_(key, base, num, sizeof(type2), \ + nm##_cmp_BSEARCH_CMP_FN); \ + } \ + extern void dummy_prototype(void) + +# define OBJ_bsearch(type1,key,type2,base,num,cmp) \ + ((type2 *)OBJ_bsearch_(CHECKED_PTR_OF(type1,key),CHECKED_PTR_OF(type2,base), \ + num,sizeof(type2), \ + ((void)CHECKED_PTR_OF(type1,cmp##_type_1), \ + (void)CHECKED_PTR_OF(type2,cmp##_type_2), \ + cmp##_BSEARCH_CMP_FN))) + +# define OBJ_bsearch_ex(type1,key,type2,base,num,cmp,flags) \ + ((type2 *)OBJ_bsearch_ex_(CHECKED_PTR_OF(type1,key),CHECKED_PTR_OF(type2,base), \ + num,sizeof(type2), \ + ((void)CHECKED_PTR_OF(type1,cmp##_type_1), \ + (void)type_2=CHECKED_PTR_OF(type2,cmp##_type_2), \ + cmp##_BSEARCH_CMP_FN)),flags) + +int OBJ_new_nid(int num); +int OBJ_add_object(const ASN1_OBJECT *obj); +int OBJ_create(const char *oid, const char *sn, const char *ln); +#if OPENSSL_API_COMPAT < 0x10100000L +# define OBJ_cleanup() while(0) continue +#endif +int OBJ_create_objects(BIO *in); + +size_t OBJ_length(const ASN1_OBJECT *obj); +const unsigned char *OBJ_get0_data(const ASN1_OBJECT *obj); + +int OBJ_find_sigid_algs(int signid, int *pdig_nid, int *ppkey_nid); +int OBJ_find_sigid_by_algs(int *psignid, int dig_nid, int pkey_nid); +int OBJ_add_sigid(int signid, int dig_id, int pkey_id); +void OBJ_sigid_free(void); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_OBJ_strings(void); + +/* Error codes for the OBJ functions. */ + +/* Function codes. */ +# define OBJ_F_OBJ_ADD_OBJECT 105 +# define OBJ_F_OBJ_CREATE 100 +# define OBJ_F_OBJ_DUP 101 +# define OBJ_F_OBJ_NAME_NEW_INDEX 106 +# define OBJ_F_OBJ_NID2LN 102 +# define OBJ_F_OBJ_NID2OBJ 103 +# define OBJ_F_OBJ_NID2SN 104 + +/* Reason codes. */ +# define OBJ_R_OID_EXISTS 102 +# define OBJ_R_UNKNOWN_NID 101 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ocsp.h b/mobile/ios/FxA/FxA/include/openssl/ocsp.h new file mode 100644 index 0000000000..08debc5b78 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ocsp.h @@ -0,0 +1,412 @@ +/* + * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_OCSP_H +# define HEADER_OCSP_H + +#include + +/* + * These definitions are outside the OPENSSL_NO_OCSP guard because although for + * historical reasons they have OCSP_* names, they can actually be used + * independently of OCSP. E.g. see RFC5280 + */ +/*- + * CRLReason ::= ENUMERATED { + * unspecified (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * removeFromCRL (8) } + */ +# define OCSP_REVOKED_STATUS_NOSTATUS -1 +# define OCSP_REVOKED_STATUS_UNSPECIFIED 0 +# define OCSP_REVOKED_STATUS_KEYCOMPROMISE 1 +# define OCSP_REVOKED_STATUS_CACOMPROMISE 2 +# define OCSP_REVOKED_STATUS_AFFILIATIONCHANGED 3 +# define OCSP_REVOKED_STATUS_SUPERSEDED 4 +# define OCSP_REVOKED_STATUS_CESSATIONOFOPERATION 5 +# define OCSP_REVOKED_STATUS_CERTIFICATEHOLD 6 +# define OCSP_REVOKED_STATUS_REMOVEFROMCRL 8 + + +# ifndef OPENSSL_NO_OCSP + +# include +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Various flags and values */ + +# define OCSP_DEFAULT_NONCE_LENGTH 16 + +# define OCSP_NOCERTS 0x1 +# define OCSP_NOINTERN 0x2 +# define OCSP_NOSIGS 0x4 +# define OCSP_NOCHAIN 0x8 +# define OCSP_NOVERIFY 0x10 +# define OCSP_NOEXPLICIT 0x20 +# define OCSP_NOCASIGN 0x40 +# define OCSP_NODELEGATED 0x80 +# define OCSP_NOCHECKS 0x100 +# define OCSP_TRUSTOTHER 0x200 +# define OCSP_RESPID_KEY 0x400 +# define OCSP_NOTIME 0x800 + +typedef struct ocsp_cert_id_st OCSP_CERTID; + +DEFINE_STACK_OF(OCSP_CERTID) + +typedef struct ocsp_one_request_st OCSP_ONEREQ; + +DEFINE_STACK_OF(OCSP_ONEREQ) + +typedef struct ocsp_req_info_st OCSP_REQINFO; +typedef struct ocsp_signature_st OCSP_SIGNATURE; +typedef struct ocsp_request_st OCSP_REQUEST; + +# define OCSP_RESPONSE_STATUS_SUCCESSFUL 0 +# define OCSP_RESPONSE_STATUS_MALFORMEDREQUEST 1 +# define OCSP_RESPONSE_STATUS_INTERNALERROR 2 +# define OCSP_RESPONSE_STATUS_TRYLATER 3 +# define OCSP_RESPONSE_STATUS_SIGREQUIRED 5 +# define OCSP_RESPONSE_STATUS_UNAUTHORIZED 6 + +typedef struct ocsp_resp_bytes_st OCSP_RESPBYTES; + +# define V_OCSP_RESPID_NAME 0 +# define V_OCSP_RESPID_KEY 1 + +DEFINE_STACK_OF(OCSP_RESPID) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPID) + +typedef struct ocsp_revoked_info_st OCSP_REVOKEDINFO; + +# define V_OCSP_CERTSTATUS_GOOD 0 +# define V_OCSP_CERTSTATUS_REVOKED 1 +# define V_OCSP_CERTSTATUS_UNKNOWN 2 + +typedef struct ocsp_cert_status_st OCSP_CERTSTATUS; +typedef struct ocsp_single_response_st OCSP_SINGLERESP; + +DEFINE_STACK_OF(OCSP_SINGLERESP) + +typedef struct ocsp_response_data_st OCSP_RESPDATA; + +typedef struct ocsp_basic_response_st OCSP_BASICRESP; + +typedef struct ocsp_crl_id_st OCSP_CRLID; +typedef struct ocsp_service_locator_st OCSP_SERVICELOC; + +# define PEM_STRING_OCSP_REQUEST "OCSP REQUEST" +# define PEM_STRING_OCSP_RESPONSE "OCSP RESPONSE" + +# define d2i_OCSP_REQUEST_bio(bp,p) ASN1_d2i_bio_of(OCSP_REQUEST,OCSP_REQUEST_new,d2i_OCSP_REQUEST,bp,p) + +# define d2i_OCSP_RESPONSE_bio(bp,p) ASN1_d2i_bio_of(OCSP_RESPONSE,OCSP_RESPONSE_new,d2i_OCSP_RESPONSE,bp,p) + +# define PEM_read_bio_OCSP_REQUEST(bp,x,cb) (OCSP_REQUEST *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,bp,(char **)x,cb,NULL) + +# define PEM_read_bio_OCSP_RESPONSE(bp,x,cb)(OCSP_RESPONSE *)PEM_ASN1_read_bio(\ + (char *(*)())d2i_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,bp,(char **)x,cb,NULL) + +# define PEM_write_bio_OCSP_REQUEST(bp,o) \ + PEM_ASN1_write_bio((int (*)())i2d_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,\ + bp,(char *)o, NULL,NULL,0,NULL,NULL) + +# define PEM_write_bio_OCSP_RESPONSE(bp,o) \ + PEM_ASN1_write_bio((int (*)())i2d_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,\ + bp,(char *)o, NULL,NULL,0,NULL,NULL) + +# define i2d_OCSP_RESPONSE_bio(bp,o) ASN1_i2d_bio_of(OCSP_RESPONSE,i2d_OCSP_RESPONSE,bp,o) + +# define i2d_OCSP_REQUEST_bio(bp,o) ASN1_i2d_bio_of(OCSP_REQUEST,i2d_OCSP_REQUEST,bp,o) + +# define OCSP_REQUEST_sign(o,pkey,md) \ + ASN1_item_sign(ASN1_ITEM_rptr(OCSP_REQINFO),\ + &o->optionalSignature->signatureAlgorithm,NULL,\ + o->optionalSignature->signature,&o->tbsRequest,pkey,md) + +# define OCSP_BASICRESP_sign(o,pkey,md,d) \ + ASN1_item_sign(ASN1_ITEM_rptr(OCSP_RESPDATA),&o->signatureAlgorithm,NULL,\ + o->signature,&o->tbsResponseData,pkey,md) + +# define OCSP_REQUEST_verify(a,r) ASN1_item_verify(ASN1_ITEM_rptr(OCSP_REQINFO),\ + &a->optionalSignature->signatureAlgorithm,\ + a->optionalSignature->signature,&a->tbsRequest,r) + +# define OCSP_BASICRESP_verify(a,r,d) ASN1_item_verify(ASN1_ITEM_rptr(OCSP_RESPDATA),\ + &a->signatureAlgorithm,a->signature,&a->tbsResponseData,r) + +# define ASN1_BIT_STRING_digest(data,type,md,len) \ + ASN1_item_digest(ASN1_ITEM_rptr(ASN1_BIT_STRING),type,data,md,len) + +# define OCSP_CERTSTATUS_dup(cs)\ + (OCSP_CERTSTATUS*)ASN1_dup((int(*)())i2d_OCSP_CERTSTATUS,\ + (char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs)) + +OCSP_CERTID *OCSP_CERTID_dup(OCSP_CERTID *id); + +OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, const char *path, OCSP_REQUEST *req); +OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, const char *path, OCSP_REQUEST *req, + int maxline); +int OCSP_REQ_CTX_nbio(OCSP_REQ_CTX *rctx); +int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx); +OCSP_REQ_CTX *OCSP_REQ_CTX_new(BIO *io, int maxline); +void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx); +void OCSP_set_max_response_length(OCSP_REQ_CTX *rctx, unsigned long len); +int OCSP_REQ_CTX_i2d(OCSP_REQ_CTX *rctx, const ASN1_ITEM *it, + ASN1_VALUE *val); +int OCSP_REQ_CTX_nbio_d2i(OCSP_REQ_CTX *rctx, ASN1_VALUE **pval, + const ASN1_ITEM *it); +BIO *OCSP_REQ_CTX_get0_mem_bio(OCSP_REQ_CTX *rctx); +int OCSP_REQ_CTX_i2d(OCSP_REQ_CTX *rctx, const ASN1_ITEM *it, + ASN1_VALUE *val); +int OCSP_REQ_CTX_http(OCSP_REQ_CTX *rctx, const char *op, const char *path); +int OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX *rctx, OCSP_REQUEST *req); +int OCSP_REQ_CTX_add1_header(OCSP_REQ_CTX *rctx, + const char *name, const char *value); + +OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, const X509 *subject, + const X509 *issuer); + +OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst, + const X509_NAME *issuerName, + const ASN1_BIT_STRING *issuerKey, + const ASN1_INTEGER *serialNumber); + +OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid); + +int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len); +int OCSP_basic_add1_nonce(OCSP_BASICRESP *resp, unsigned char *val, int len); +int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs); +int OCSP_copy_nonce(OCSP_BASICRESP *resp, OCSP_REQUEST *req); + +int OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm); +int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert); + +int OCSP_request_sign(OCSP_REQUEST *req, + X509 *signer, + EVP_PKEY *key, + const EVP_MD *dgst, + STACK_OF(X509) *certs, unsigned long flags); + +int OCSP_response_status(OCSP_RESPONSE *resp); +OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp); + +const ASN1_OCTET_STRING *OCSP_resp_get0_signature(const OCSP_BASICRESP *bs); + +int OCSP_resp_count(OCSP_BASICRESP *bs); +OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx); +const ASN1_GENERALIZEDTIME *OCSP_resp_get0_produced_at(const OCSP_BASICRESP* bs); +const STACK_OF(X509) *OCSP_resp_get0_certs(const OCSP_BASICRESP *bs); +int OCSP_resp_get0_id(const OCSP_BASICRESP *bs, + const ASN1_OCTET_STRING **pid, + const X509_NAME **pname); + +int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last); +int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, + ASN1_GENERALIZEDTIME **revtime, + ASN1_GENERALIZEDTIME **thisupd, + ASN1_GENERALIZEDTIME **nextupd); +int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status, + int *reason, + ASN1_GENERALIZEDTIME **revtime, + ASN1_GENERALIZEDTIME **thisupd, + ASN1_GENERALIZEDTIME **nextupd); +int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, + ASN1_GENERALIZEDTIME *nextupd, long sec, long maxsec); + +int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, + X509_STORE *store, unsigned long flags); + +int OCSP_parse_url(const char *url, char **phost, char **pport, char **ppath, + int *pssl); + +int OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b); +int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b); + +int OCSP_request_onereq_count(OCSP_REQUEST *req); +OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *req, int i); +OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *one); +int OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, + ASN1_OCTET_STRING **pikeyHash, + ASN1_INTEGER **pserial, OCSP_CERTID *cid); +int OCSP_request_is_signed(OCSP_REQUEST *req); +OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs); +OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *rsp, + OCSP_CERTID *cid, + int status, int reason, + ASN1_TIME *revtime, + ASN1_TIME *thisupd, + ASN1_TIME *nextupd); +int OCSP_basic_add1_cert(OCSP_BASICRESP *resp, X509 *cert); +int OCSP_basic_sign(OCSP_BASICRESP *brsp, + X509 *signer, EVP_PKEY *key, const EVP_MD *dgst, + STACK_OF(X509) *certs, unsigned long flags); +int OCSP_RESPID_set_by_name(OCSP_RESPID *respid, X509 *cert); +int OCSP_RESPID_set_by_key(OCSP_RESPID *respid, X509 *cert); +int OCSP_RESPID_match(OCSP_RESPID *respid, X509 *cert); + +X509_EXTENSION *OCSP_crlID_new(const char *url, long *n, char *tim); + +X509_EXTENSION *OCSP_accept_responses_new(char **oids); + +X509_EXTENSION *OCSP_archive_cutoff_new(char *tim); + +X509_EXTENSION *OCSP_url_svcloc_new(X509_NAME *issuer, const char **urls); + +int OCSP_REQUEST_get_ext_count(OCSP_REQUEST *x); +int OCSP_REQUEST_get_ext_by_NID(OCSP_REQUEST *x, int nid, int lastpos); +int OCSP_REQUEST_get_ext_by_OBJ(OCSP_REQUEST *x, const ASN1_OBJECT *obj, + int lastpos); +int OCSP_REQUEST_get_ext_by_critical(OCSP_REQUEST *x, int crit, int lastpos); +X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *x, int loc); +X509_EXTENSION *OCSP_REQUEST_delete_ext(OCSP_REQUEST *x, int loc); +void *OCSP_REQUEST_get1_ext_d2i(OCSP_REQUEST *x, int nid, int *crit, + int *idx); +int OCSP_REQUEST_add1_ext_i2d(OCSP_REQUEST *x, int nid, void *value, int crit, + unsigned long flags); +int OCSP_REQUEST_add_ext(OCSP_REQUEST *x, X509_EXTENSION *ex, int loc); + +int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *x); +int OCSP_ONEREQ_get_ext_by_NID(OCSP_ONEREQ *x, int nid, int lastpos); +int OCSP_ONEREQ_get_ext_by_OBJ(OCSP_ONEREQ *x, const ASN1_OBJECT *obj, int lastpos); +int OCSP_ONEREQ_get_ext_by_critical(OCSP_ONEREQ *x, int crit, int lastpos); +X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *x, int loc); +X509_EXTENSION *OCSP_ONEREQ_delete_ext(OCSP_ONEREQ *x, int loc); +void *OCSP_ONEREQ_get1_ext_d2i(OCSP_ONEREQ *x, int nid, int *crit, int *idx); +int OCSP_ONEREQ_add1_ext_i2d(OCSP_ONEREQ *x, int nid, void *value, int crit, + unsigned long flags); +int OCSP_ONEREQ_add_ext(OCSP_ONEREQ *x, X509_EXTENSION *ex, int loc); + +int OCSP_BASICRESP_get_ext_count(OCSP_BASICRESP *x); +int OCSP_BASICRESP_get_ext_by_NID(OCSP_BASICRESP *x, int nid, int lastpos); +int OCSP_BASICRESP_get_ext_by_OBJ(OCSP_BASICRESP *x, const ASN1_OBJECT *obj, + int lastpos); +int OCSP_BASICRESP_get_ext_by_critical(OCSP_BASICRESP *x, int crit, + int lastpos); +X509_EXTENSION *OCSP_BASICRESP_get_ext(OCSP_BASICRESP *x, int loc); +X509_EXTENSION *OCSP_BASICRESP_delete_ext(OCSP_BASICRESP *x, int loc); +void *OCSP_BASICRESP_get1_ext_d2i(OCSP_BASICRESP *x, int nid, int *crit, + int *idx); +int OCSP_BASICRESP_add1_ext_i2d(OCSP_BASICRESP *x, int nid, void *value, + int crit, unsigned long flags); +int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *x, X509_EXTENSION *ex, int loc); + +int OCSP_SINGLERESP_get_ext_count(OCSP_SINGLERESP *x); +int OCSP_SINGLERESP_get_ext_by_NID(OCSP_SINGLERESP *x, int nid, int lastpos); +int OCSP_SINGLERESP_get_ext_by_OBJ(OCSP_SINGLERESP *x, const ASN1_OBJECT *obj, + int lastpos); +int OCSP_SINGLERESP_get_ext_by_critical(OCSP_SINGLERESP *x, int crit, + int lastpos); +X509_EXTENSION *OCSP_SINGLERESP_get_ext(OCSP_SINGLERESP *x, int loc); +X509_EXTENSION *OCSP_SINGLERESP_delete_ext(OCSP_SINGLERESP *x, int loc); +void *OCSP_SINGLERESP_get1_ext_d2i(OCSP_SINGLERESP *x, int nid, int *crit, + int *idx); +int OCSP_SINGLERESP_add1_ext_i2d(OCSP_SINGLERESP *x, int nid, void *value, + int crit, unsigned long flags); +int OCSP_SINGLERESP_add_ext(OCSP_SINGLERESP *x, X509_EXTENSION *ex, int loc); +const OCSP_CERTID *OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *x); + +DECLARE_ASN1_FUNCTIONS(OCSP_SINGLERESP) +DECLARE_ASN1_FUNCTIONS(OCSP_CERTSTATUS) +DECLARE_ASN1_FUNCTIONS(OCSP_REVOKEDINFO) +DECLARE_ASN1_FUNCTIONS(OCSP_BASICRESP) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPDATA) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPID) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPONSE) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPBYTES) +DECLARE_ASN1_FUNCTIONS(OCSP_ONEREQ) +DECLARE_ASN1_FUNCTIONS(OCSP_CERTID) +DECLARE_ASN1_FUNCTIONS(OCSP_REQUEST) +DECLARE_ASN1_FUNCTIONS(OCSP_SIGNATURE) +DECLARE_ASN1_FUNCTIONS(OCSP_REQINFO) +DECLARE_ASN1_FUNCTIONS(OCSP_CRLID) +DECLARE_ASN1_FUNCTIONS(OCSP_SERVICELOC) + +const char *OCSP_response_status_str(long s); +const char *OCSP_cert_status_str(long s); +const char *OCSP_crl_reason_str(long s); + +int OCSP_REQUEST_print(BIO *bp, OCSP_REQUEST *a, unsigned long flags); +int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE *o, unsigned long flags); + +int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, + X509_STORE *st, unsigned long flags); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_OCSP_strings(void); + +/* Error codes for the OCSP functions. */ + +/* Function codes. */ +# define OCSP_F_D2I_OCSP_NONCE 102 +# define OCSP_F_OCSP_BASIC_ADD1_STATUS 103 +# define OCSP_F_OCSP_BASIC_SIGN 104 +# define OCSP_F_OCSP_BASIC_VERIFY 105 +# define OCSP_F_OCSP_CERT_ID_NEW 101 +# define OCSP_F_OCSP_CHECK_DELEGATED 106 +# define OCSP_F_OCSP_CHECK_IDS 107 +# define OCSP_F_OCSP_CHECK_ISSUER 108 +# define OCSP_F_OCSP_CHECK_VALIDITY 115 +# define OCSP_F_OCSP_MATCH_ISSUERID 109 +# define OCSP_F_OCSP_PARSE_URL 114 +# define OCSP_F_OCSP_REQUEST_SIGN 110 +# define OCSP_F_OCSP_REQUEST_VERIFY 116 +# define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111 +# define OCSP_F_PARSE_HTTP_LINE1 118 + +/* Reason codes. */ +# define OCSP_R_CERTIFICATE_VERIFY_ERROR 101 +# define OCSP_R_DIGEST_ERR 102 +# define OCSP_R_ERROR_IN_NEXTUPDATE_FIELD 122 +# define OCSP_R_ERROR_IN_THISUPDATE_FIELD 123 +# define OCSP_R_ERROR_PARSING_URL 121 +# define OCSP_R_MISSING_OCSPSIGNING_USAGE 103 +# define OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE 124 +# define OCSP_R_NOT_BASIC_RESPONSE 104 +# define OCSP_R_NO_CERTIFICATES_IN_CHAIN 105 +# define OCSP_R_NO_RESPONSE_DATA 108 +# define OCSP_R_NO_REVOKED_TIME 109 +# define OCSP_R_NO_SIGNER_KEY 130 +# define OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 110 +# define OCSP_R_REQUEST_NOT_SIGNED 128 +# define OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA 111 +# define OCSP_R_ROOT_CA_NOT_TRUSTED 112 +# define OCSP_R_SERVER_RESPONSE_ERROR 114 +# define OCSP_R_SERVER_RESPONSE_PARSE_ERROR 115 +# define OCSP_R_SIGNATURE_FAILURE 117 +# define OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND 118 +# define OCSP_R_STATUS_EXPIRED 125 +# define OCSP_R_STATUS_NOT_YET_VALID 126 +# define OCSP_R_STATUS_TOO_OLD 127 +# define OCSP_R_UNKNOWN_MESSAGE_DIGEST 119 +# define OCSP_R_UNKNOWN_NID 120 +# define OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE 129 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslconf.h b/mobile/ios/FxA/FxA/include/openssl/opensslconf.h new file mode 100644 index 0000000000..f70f152d51 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslconf.h @@ -0,0 +1,27 @@ +/* + * Building OpenSSL for the different architectures of all iOS and tvOS devices requires different settings. + * In order to be able to use assembly code on all devices, the choice was made to keep optimal settings for all + * devices and use this intermediate header file to use the proper opensslconf.h file for each architecture. + + * See also https://github.com/x2on/OpenSSL-for-iPhone/issues/126 and referenced pull requests + */ + +#include + +#if TARGET_OS_IOS && TARGET_OS_SIMULATOR && TARGET_CPU_X86_64 +# include +#elif TARGET_OS_IOS && TARGET_OS_SIMULATOR && TARGET_CPU_X86 +# include +#elif TARGET_OS_IOS && TARGET_OS_EMBEDDED && TARGET_CPU_ARM64 +# include +#elif TARGET_OS_IOS && TARGET_OS_EMBEDDED && TARGET_CPU_ARM && defined(__ARM_ARCH_7S__) +# include +#elif TARGET_OS_IOS && TARGET_OS_EMBEDDED && TARGET_CPU_ARM && !defined(__ARM_ARCH_7S__) +# include +#elif TARGET_OS_TV && TARGET_OS_SIMULATOR && TARGET_CPU_X86_64 +# include +#elif TARGET_OS_TV && TARGET_OS_EMBEDDED && TARGET_CPU_ARM64 +# include +#else +# error Unable to determine target or target not included in OpenSSL build +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_arm64.h b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_arm64.h new file mode 100644 index 0000000000..19bfb801a6 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_arm64.h @@ -0,0 +1,179 @@ +/* + * WARNING: do not edit! + * Generated by Makefile from include/openssl/opensslconf.h.in + * + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_ALGORITHM_DEFINES +# error OPENSSL_ALGORITHM_DEFINES no longer supported +#endif + +/* + * OpenSSL was configured with the following options: + */ + +#ifndef OPENSSL_SYS_iOS +# define OPENSSL_SYS_iOS 1 +#endif +#define OPENSSL_MIN_API 0x10100000L +#ifndef OPENSSL_NO_MD2 +# define OPENSSL_NO_MD2 +#endif +#ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +#endif +#ifndef OPENSSL_THREADS +# define OPENSSL_THREADS +#endif +#ifndef OPENSSL_NO_ASAN +# define OPENSSL_NO_ASAN +#endif +#ifndef OPENSSL_NO_ASYNC +# define OPENSSL_NO_ASYNC +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG +# define OPENSSL_NO_CRYPTO_MDEBUG +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +# define OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +#endif +#ifndef OPENSSL_NO_DEPRECATED +# define OPENSSL_NO_DEPRECATED +#endif +#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +# define OPENSSL_NO_EC_NISTP_64_GCC_128 +#endif +#ifndef OPENSSL_NO_EGD +# define OPENSSL_NO_EGD +#endif +#ifndef OPENSSL_NO_FUZZ_AFL +# define OPENSSL_NO_FUZZ_AFL +#endif +#ifndef OPENSSL_NO_FUZZ_LIBFUZZER +# define OPENSSL_NO_FUZZ_LIBFUZZER +#endif +#ifndef OPENSSL_NO_HEARTBEATS +# define OPENSSL_NO_HEARTBEATS +#endif +#ifndef OPENSSL_NO_MSAN +# define OPENSSL_NO_MSAN +#endif +#ifndef OPENSSL_NO_SCTP +# define OPENSSL_NO_SCTP +#endif +#ifndef OPENSSL_NO_SSL_TRACE +# define OPENSSL_NO_SSL_TRACE +#endif +#ifndef OPENSSL_NO_SSL3 +# define OPENSSL_NO_SSL3 +#endif +#ifndef OPENSSL_NO_SSL3_METHOD +# define OPENSSL_NO_SSL3_METHOD +#endif +#ifndef OPENSSL_NO_UBSAN +# define OPENSSL_NO_UBSAN +#endif +#ifndef OPENSSL_NO_UNIT_TEST +# define OPENSSL_NO_UNIT_TEST +#endif +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS +# define OPENSSL_NO_WEAK_SSL_CIPHERS +#endif +#ifndef OPENSSL_NO_AFALGENG +# define OPENSSL_NO_AFALGENG +#endif + + +/* + * Sometimes OPENSSSL_NO_xxx ends up with an empty file and some compilers + * don't like that. This will hopefully silence them. + */ +#define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy; + +/* + * Applications should use -DOPENSSL_API_COMPAT= to suppress the + * declarations of functions deprecated in or before . Otherwise, they + * still won't see them if the library has been built to disable deprecated + * functions. + */ +#if defined(OPENSSL_NO_DEPRECATED) +# define DECLARE_DEPRECATED(f) +#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define DECLARE_DEPRECATED(f) f __attribute__ ((deprecated)); +#else +# define DECLARE_DEPRECATED(f) f; +#endif + +#ifndef OPENSSL_FILE +# ifdef OPENSSL_NO_FILENAMES +# define OPENSSL_FILE "" +# define OPENSSL_LINE 0 +# else +# define OPENSSL_FILE __FILE__ +# define OPENSSL_LINE __LINE__ +# endif +#endif + +#ifndef OPENSSL_MIN_API +# define OPENSSL_MIN_API 0 +#endif + +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < OPENSSL_MIN_API +# undef OPENSSL_API_COMPAT +# define OPENSSL_API_COMPAT OPENSSL_MIN_API +#endif + +#if OPENSSL_API_COMPAT < 0x10100000L +# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_1_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x10000000L +# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_0_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x00908000L +# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_0_9_8(f) +#endif + +#define OPENSSL_CPUID_OBJ + +/* Generate 80386 code? */ +#undef I386_ONLY + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* + * The following are cipher-specific, but are part of the public API. + */ +#if !defined(OPENSSL_SYS_UEFI) +# undef BN_LLONG +/* Only one for the following should be defined */ +# define SIXTY_FOUR_BIT_LONG +# undef SIXTY_FOUR_BIT +# undef THIRTY_TWO_BIT +#endif + +#define RC4_INT unsigned char + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_armv7.h b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_armv7.h new file mode 100644 index 0000000000..aba635bb58 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_armv7.h @@ -0,0 +1,179 @@ +/* + * WARNING: do not edit! + * Generated by Makefile from include/openssl/opensslconf.h.in + * + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_ALGORITHM_DEFINES +# error OPENSSL_ALGORITHM_DEFINES no longer supported +#endif + +/* + * OpenSSL was configured with the following options: + */ + +#ifndef OPENSSL_SYS_iOS +# define OPENSSL_SYS_iOS 1 +#endif +#define OPENSSL_MIN_API 0x10100000L +#ifndef OPENSSL_NO_MD2 +# define OPENSSL_NO_MD2 +#endif +#ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +#endif +#ifndef OPENSSL_THREADS +# define OPENSSL_THREADS +#endif +#ifndef OPENSSL_NO_ASAN +# define OPENSSL_NO_ASAN +#endif +#ifndef OPENSSL_NO_ASYNC +# define OPENSSL_NO_ASYNC +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG +# define OPENSSL_NO_CRYPTO_MDEBUG +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +# define OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +#endif +#ifndef OPENSSL_NO_DEPRECATED +# define OPENSSL_NO_DEPRECATED +#endif +#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +# define OPENSSL_NO_EC_NISTP_64_GCC_128 +#endif +#ifndef OPENSSL_NO_EGD +# define OPENSSL_NO_EGD +#endif +#ifndef OPENSSL_NO_FUZZ_AFL +# define OPENSSL_NO_FUZZ_AFL +#endif +#ifndef OPENSSL_NO_FUZZ_LIBFUZZER +# define OPENSSL_NO_FUZZ_LIBFUZZER +#endif +#ifndef OPENSSL_NO_HEARTBEATS +# define OPENSSL_NO_HEARTBEATS +#endif +#ifndef OPENSSL_NO_MSAN +# define OPENSSL_NO_MSAN +#endif +#ifndef OPENSSL_NO_SCTP +# define OPENSSL_NO_SCTP +#endif +#ifndef OPENSSL_NO_SSL_TRACE +# define OPENSSL_NO_SSL_TRACE +#endif +#ifndef OPENSSL_NO_SSL3 +# define OPENSSL_NO_SSL3 +#endif +#ifndef OPENSSL_NO_SSL3_METHOD +# define OPENSSL_NO_SSL3_METHOD +#endif +#ifndef OPENSSL_NO_UBSAN +# define OPENSSL_NO_UBSAN +#endif +#ifndef OPENSSL_NO_UNIT_TEST +# define OPENSSL_NO_UNIT_TEST +#endif +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS +# define OPENSSL_NO_WEAK_SSL_CIPHERS +#endif +#ifndef OPENSSL_NO_AFALGENG +# define OPENSSL_NO_AFALGENG +#endif + + +/* + * Sometimes OPENSSSL_NO_xxx ends up with an empty file and some compilers + * don't like that. This will hopefully silence them. + */ +#define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy; + +/* + * Applications should use -DOPENSSL_API_COMPAT= to suppress the + * declarations of functions deprecated in or before . Otherwise, they + * still won't see them if the library has been built to disable deprecated + * functions. + */ +#if defined(OPENSSL_NO_DEPRECATED) +# define DECLARE_DEPRECATED(f) +#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define DECLARE_DEPRECATED(f) f __attribute__ ((deprecated)); +#else +# define DECLARE_DEPRECATED(f) f; +#endif + +#ifndef OPENSSL_FILE +# ifdef OPENSSL_NO_FILENAMES +# define OPENSSL_FILE "" +# define OPENSSL_LINE 0 +# else +# define OPENSSL_FILE __FILE__ +# define OPENSSL_LINE __LINE__ +# endif +#endif + +#ifndef OPENSSL_MIN_API +# define OPENSSL_MIN_API 0 +#endif + +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < OPENSSL_MIN_API +# undef OPENSSL_API_COMPAT +# define OPENSSL_API_COMPAT OPENSSL_MIN_API +#endif + +#if OPENSSL_API_COMPAT < 0x10100000L +# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_1_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x10000000L +# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_0_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x00908000L +# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_0_9_8(f) +#endif + +#define OPENSSL_CPUID_OBJ + +/* Generate 80386 code? */ +#undef I386_ONLY + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* + * The following are cipher-specific, but are part of the public API. + */ +#if !defined(OPENSSL_SYS_UEFI) +# define BN_LLONG +/* Only one for the following should be defined */ +# undef SIXTY_FOUR_BIT_LONG +# undef SIXTY_FOUR_BIT +# define THIRTY_TWO_BIT +#endif + +#define RC4_INT unsigned char + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_armv7s.h b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_armv7s.h new file mode 100644 index 0000000000..aba635bb58 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_armv7s.h @@ -0,0 +1,179 @@ +/* + * WARNING: do not edit! + * Generated by Makefile from include/openssl/opensslconf.h.in + * + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_ALGORITHM_DEFINES +# error OPENSSL_ALGORITHM_DEFINES no longer supported +#endif + +/* + * OpenSSL was configured with the following options: + */ + +#ifndef OPENSSL_SYS_iOS +# define OPENSSL_SYS_iOS 1 +#endif +#define OPENSSL_MIN_API 0x10100000L +#ifndef OPENSSL_NO_MD2 +# define OPENSSL_NO_MD2 +#endif +#ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +#endif +#ifndef OPENSSL_THREADS +# define OPENSSL_THREADS +#endif +#ifndef OPENSSL_NO_ASAN +# define OPENSSL_NO_ASAN +#endif +#ifndef OPENSSL_NO_ASYNC +# define OPENSSL_NO_ASYNC +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG +# define OPENSSL_NO_CRYPTO_MDEBUG +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +# define OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +#endif +#ifndef OPENSSL_NO_DEPRECATED +# define OPENSSL_NO_DEPRECATED +#endif +#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +# define OPENSSL_NO_EC_NISTP_64_GCC_128 +#endif +#ifndef OPENSSL_NO_EGD +# define OPENSSL_NO_EGD +#endif +#ifndef OPENSSL_NO_FUZZ_AFL +# define OPENSSL_NO_FUZZ_AFL +#endif +#ifndef OPENSSL_NO_FUZZ_LIBFUZZER +# define OPENSSL_NO_FUZZ_LIBFUZZER +#endif +#ifndef OPENSSL_NO_HEARTBEATS +# define OPENSSL_NO_HEARTBEATS +#endif +#ifndef OPENSSL_NO_MSAN +# define OPENSSL_NO_MSAN +#endif +#ifndef OPENSSL_NO_SCTP +# define OPENSSL_NO_SCTP +#endif +#ifndef OPENSSL_NO_SSL_TRACE +# define OPENSSL_NO_SSL_TRACE +#endif +#ifndef OPENSSL_NO_SSL3 +# define OPENSSL_NO_SSL3 +#endif +#ifndef OPENSSL_NO_SSL3_METHOD +# define OPENSSL_NO_SSL3_METHOD +#endif +#ifndef OPENSSL_NO_UBSAN +# define OPENSSL_NO_UBSAN +#endif +#ifndef OPENSSL_NO_UNIT_TEST +# define OPENSSL_NO_UNIT_TEST +#endif +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS +# define OPENSSL_NO_WEAK_SSL_CIPHERS +#endif +#ifndef OPENSSL_NO_AFALGENG +# define OPENSSL_NO_AFALGENG +#endif + + +/* + * Sometimes OPENSSSL_NO_xxx ends up with an empty file and some compilers + * don't like that. This will hopefully silence them. + */ +#define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy; + +/* + * Applications should use -DOPENSSL_API_COMPAT= to suppress the + * declarations of functions deprecated in or before . Otherwise, they + * still won't see them if the library has been built to disable deprecated + * functions. + */ +#if defined(OPENSSL_NO_DEPRECATED) +# define DECLARE_DEPRECATED(f) +#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define DECLARE_DEPRECATED(f) f __attribute__ ((deprecated)); +#else +# define DECLARE_DEPRECATED(f) f; +#endif + +#ifndef OPENSSL_FILE +# ifdef OPENSSL_NO_FILENAMES +# define OPENSSL_FILE "" +# define OPENSSL_LINE 0 +# else +# define OPENSSL_FILE __FILE__ +# define OPENSSL_LINE __LINE__ +# endif +#endif + +#ifndef OPENSSL_MIN_API +# define OPENSSL_MIN_API 0 +#endif + +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < OPENSSL_MIN_API +# undef OPENSSL_API_COMPAT +# define OPENSSL_API_COMPAT OPENSSL_MIN_API +#endif + +#if OPENSSL_API_COMPAT < 0x10100000L +# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_1_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x10000000L +# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_0_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x00908000L +# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_0_9_8(f) +#endif + +#define OPENSSL_CPUID_OBJ + +/* Generate 80386 code? */ +#undef I386_ONLY + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* + * The following are cipher-specific, but are part of the public API. + */ +#if !defined(OPENSSL_SYS_UEFI) +# define BN_LLONG +/* Only one for the following should be defined */ +# undef SIXTY_FOUR_BIT_LONG +# undef SIXTY_FOUR_BIT +# define THIRTY_TWO_BIT +#endif + +#define RC4_INT unsigned char + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_i386.h b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_i386.h new file mode 100644 index 0000000000..e047b0e808 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_i386.h @@ -0,0 +1,179 @@ +/* + * WARNING: do not edit! + * Generated by Makefile from include/openssl/opensslconf.h.in + * + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_ALGORITHM_DEFINES +# error OPENSSL_ALGORITHM_DEFINES no longer supported +#endif + +/* + * OpenSSL was configured with the following options: + */ + +#ifndef OPENSSL_SYS_iOS +# define OPENSSL_SYS_iOS 1 +#endif +#define OPENSSL_MIN_API 0x10100000L +#ifndef OPENSSL_NO_MD2 +# define OPENSSL_NO_MD2 +#endif +#ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +#endif +#ifndef OPENSSL_THREADS +# define OPENSSL_THREADS +#endif +#ifndef OPENSSL_NO_ASAN +# define OPENSSL_NO_ASAN +#endif +#ifndef OPENSSL_NO_ASYNC +# define OPENSSL_NO_ASYNC +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG +# define OPENSSL_NO_CRYPTO_MDEBUG +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +# define OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +#endif +#ifndef OPENSSL_NO_DEPRECATED +# define OPENSSL_NO_DEPRECATED +#endif +#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +# define OPENSSL_NO_EC_NISTP_64_GCC_128 +#endif +#ifndef OPENSSL_NO_EGD +# define OPENSSL_NO_EGD +#endif +#ifndef OPENSSL_NO_FUZZ_AFL +# define OPENSSL_NO_FUZZ_AFL +#endif +#ifndef OPENSSL_NO_FUZZ_LIBFUZZER +# define OPENSSL_NO_FUZZ_LIBFUZZER +#endif +#ifndef OPENSSL_NO_HEARTBEATS +# define OPENSSL_NO_HEARTBEATS +#endif +#ifndef OPENSSL_NO_MSAN +# define OPENSSL_NO_MSAN +#endif +#ifndef OPENSSL_NO_SCTP +# define OPENSSL_NO_SCTP +#endif +#ifndef OPENSSL_NO_SSL_TRACE +# define OPENSSL_NO_SSL_TRACE +#endif +#ifndef OPENSSL_NO_SSL3 +# define OPENSSL_NO_SSL3 +#endif +#ifndef OPENSSL_NO_SSL3_METHOD +# define OPENSSL_NO_SSL3_METHOD +#endif +#ifndef OPENSSL_NO_UBSAN +# define OPENSSL_NO_UBSAN +#endif +#ifndef OPENSSL_NO_UNIT_TEST +# define OPENSSL_NO_UNIT_TEST +#endif +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS +# define OPENSSL_NO_WEAK_SSL_CIPHERS +#endif +#ifndef OPENSSL_NO_AFALGENG +# define OPENSSL_NO_AFALGENG +#endif + + +/* + * Sometimes OPENSSSL_NO_xxx ends up with an empty file and some compilers + * don't like that. This will hopefully silence them. + */ +#define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy; + +/* + * Applications should use -DOPENSSL_API_COMPAT= to suppress the + * declarations of functions deprecated in or before . Otherwise, they + * still won't see them if the library has been built to disable deprecated + * functions. + */ +#if defined(OPENSSL_NO_DEPRECATED) +# define DECLARE_DEPRECATED(f) +#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define DECLARE_DEPRECATED(f) f __attribute__ ((deprecated)); +#else +# define DECLARE_DEPRECATED(f) f; +#endif + +#ifndef OPENSSL_FILE +# ifdef OPENSSL_NO_FILENAMES +# define OPENSSL_FILE "" +# define OPENSSL_LINE 0 +# else +# define OPENSSL_FILE __FILE__ +# define OPENSSL_LINE __LINE__ +# endif +#endif + +#ifndef OPENSSL_MIN_API +# define OPENSSL_MIN_API 0 +#endif + +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < OPENSSL_MIN_API +# undef OPENSSL_API_COMPAT +# define OPENSSL_API_COMPAT OPENSSL_MIN_API +#endif + +#if OPENSSL_API_COMPAT < 0x10100000L +# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_1_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x10000000L +# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_0_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x00908000L +# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_0_9_8(f) +#endif + +#define OPENSSL_CPUID_OBJ + +/* Generate 80386 code? */ +#undef I386_ONLY + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* + * The following are cipher-specific, but are part of the public API. + */ +#if !defined(OPENSSL_SYS_UEFI) +# define BN_LLONG +/* Only one for the following should be defined */ +# undef SIXTY_FOUR_BIT_LONG +# undef SIXTY_FOUR_BIT +# define THIRTY_TWO_BIT +#endif + +#define RC4_INT unsigned int + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_x86_64.h b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_x86_64.h new file mode 100644 index 0000000000..b05ebfeac0 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslconf_ios_x86_64.h @@ -0,0 +1,179 @@ +/* + * WARNING: do not edit! + * Generated by Makefile from include/openssl/opensslconf.h.in + * + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_ALGORITHM_DEFINES +# error OPENSSL_ALGORITHM_DEFINES no longer supported +#endif + +/* + * OpenSSL was configured with the following options: + */ + +#ifndef OPENSSL_SYS_iOS +# define OPENSSL_SYS_iOS 1 +#endif +#define OPENSSL_MIN_API 0x10100000L +#ifndef OPENSSL_NO_MD2 +# define OPENSSL_NO_MD2 +#endif +#ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +#endif +#ifndef OPENSSL_THREADS +# define OPENSSL_THREADS +#endif +#ifndef OPENSSL_NO_ASAN +# define OPENSSL_NO_ASAN +#endif +#ifndef OPENSSL_NO_ASYNC +# define OPENSSL_NO_ASYNC +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG +# define OPENSSL_NO_CRYPTO_MDEBUG +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +# define OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +#endif +#ifndef OPENSSL_NO_DEPRECATED +# define OPENSSL_NO_DEPRECATED +#endif +#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +# define OPENSSL_NO_EC_NISTP_64_GCC_128 +#endif +#ifndef OPENSSL_NO_EGD +# define OPENSSL_NO_EGD +#endif +#ifndef OPENSSL_NO_FUZZ_AFL +# define OPENSSL_NO_FUZZ_AFL +#endif +#ifndef OPENSSL_NO_FUZZ_LIBFUZZER +# define OPENSSL_NO_FUZZ_LIBFUZZER +#endif +#ifndef OPENSSL_NO_HEARTBEATS +# define OPENSSL_NO_HEARTBEATS +#endif +#ifndef OPENSSL_NO_MSAN +# define OPENSSL_NO_MSAN +#endif +#ifndef OPENSSL_NO_SCTP +# define OPENSSL_NO_SCTP +#endif +#ifndef OPENSSL_NO_SSL_TRACE +# define OPENSSL_NO_SSL_TRACE +#endif +#ifndef OPENSSL_NO_SSL3 +# define OPENSSL_NO_SSL3 +#endif +#ifndef OPENSSL_NO_SSL3_METHOD +# define OPENSSL_NO_SSL3_METHOD +#endif +#ifndef OPENSSL_NO_UBSAN +# define OPENSSL_NO_UBSAN +#endif +#ifndef OPENSSL_NO_UNIT_TEST +# define OPENSSL_NO_UNIT_TEST +#endif +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS +# define OPENSSL_NO_WEAK_SSL_CIPHERS +#endif +#ifndef OPENSSL_NO_AFALGENG +# define OPENSSL_NO_AFALGENG +#endif + + +/* + * Sometimes OPENSSSL_NO_xxx ends up with an empty file and some compilers + * don't like that. This will hopefully silence them. + */ +#define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy; + +/* + * Applications should use -DOPENSSL_API_COMPAT= to suppress the + * declarations of functions deprecated in or before . Otherwise, they + * still won't see them if the library has been built to disable deprecated + * functions. + */ +#if defined(OPENSSL_NO_DEPRECATED) +# define DECLARE_DEPRECATED(f) +#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define DECLARE_DEPRECATED(f) f __attribute__ ((deprecated)); +#else +# define DECLARE_DEPRECATED(f) f; +#endif + +#ifndef OPENSSL_FILE +# ifdef OPENSSL_NO_FILENAMES +# define OPENSSL_FILE "" +# define OPENSSL_LINE 0 +# else +# define OPENSSL_FILE __FILE__ +# define OPENSSL_LINE __LINE__ +# endif +#endif + +#ifndef OPENSSL_MIN_API +# define OPENSSL_MIN_API 0 +#endif + +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < OPENSSL_MIN_API +# undef OPENSSL_API_COMPAT +# define OPENSSL_API_COMPAT OPENSSL_MIN_API +#endif + +#if OPENSSL_API_COMPAT < 0x10100000L +# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_1_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x10000000L +# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_0_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x00908000L +# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_0_9_8(f) +#endif + +#define OPENSSL_CPUID_OBJ + +/* Generate 80386 code? */ +#undef I386_ONLY + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* + * The following are cipher-specific, but are part of the public API. + */ +#if !defined(OPENSSL_SYS_UEFI) +# undef BN_LLONG +/* Only one for the following should be defined */ +# define SIXTY_FOUR_BIT_LONG +# undef SIXTY_FOUR_BIT +# undef THIRTY_TWO_BIT +#endif + +#define RC4_INT unsigned int + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslconf_tvos_arm64.h b/mobile/ios/FxA/FxA/include/openssl/opensslconf_tvos_arm64.h new file mode 100644 index 0000000000..e54b4c5774 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslconf_tvos_arm64.h @@ -0,0 +1,179 @@ +/* + * WARNING: do not edit! + * Generated by Makefile from include/openssl/opensslconf.h.in + * + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_ALGORITHM_DEFINES +# error OPENSSL_ALGORITHM_DEFINES no longer supported +#endif + +/* + * OpenSSL was configured with the following options: + */ + +#ifndef OPENSSL_SYS_tvOS +# define OPENSSL_SYS_tvOS 1 +#endif +#define OPENSSL_MIN_API 0x10100000L +#ifndef OPENSSL_NO_MD2 +# define OPENSSL_NO_MD2 +#endif +#ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +#endif +#ifndef OPENSSL_THREADS +# define OPENSSL_THREADS +#endif +#ifndef OPENSSL_NO_ASAN +# define OPENSSL_NO_ASAN +#endif +#ifndef OPENSSL_NO_ASYNC +# define OPENSSL_NO_ASYNC +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG +# define OPENSSL_NO_CRYPTO_MDEBUG +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +# define OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +#endif +#ifndef OPENSSL_NO_DEPRECATED +# define OPENSSL_NO_DEPRECATED +#endif +#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +# define OPENSSL_NO_EC_NISTP_64_GCC_128 +#endif +#ifndef OPENSSL_NO_EGD +# define OPENSSL_NO_EGD +#endif +#ifndef OPENSSL_NO_FUZZ_AFL +# define OPENSSL_NO_FUZZ_AFL +#endif +#ifndef OPENSSL_NO_FUZZ_LIBFUZZER +# define OPENSSL_NO_FUZZ_LIBFUZZER +#endif +#ifndef OPENSSL_NO_HEARTBEATS +# define OPENSSL_NO_HEARTBEATS +#endif +#ifndef OPENSSL_NO_MSAN +# define OPENSSL_NO_MSAN +#endif +#ifndef OPENSSL_NO_SCTP +# define OPENSSL_NO_SCTP +#endif +#ifndef OPENSSL_NO_SSL_TRACE +# define OPENSSL_NO_SSL_TRACE +#endif +#ifndef OPENSSL_NO_SSL3 +# define OPENSSL_NO_SSL3 +#endif +#ifndef OPENSSL_NO_SSL3_METHOD +# define OPENSSL_NO_SSL3_METHOD +#endif +#ifndef OPENSSL_NO_UBSAN +# define OPENSSL_NO_UBSAN +#endif +#ifndef OPENSSL_NO_UNIT_TEST +# define OPENSSL_NO_UNIT_TEST +#endif +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS +# define OPENSSL_NO_WEAK_SSL_CIPHERS +#endif +#ifndef OPENSSL_NO_AFALGENG +# define OPENSSL_NO_AFALGENG +#endif + + +/* + * Sometimes OPENSSSL_NO_xxx ends up with an empty file and some compilers + * don't like that. This will hopefully silence them. + */ +#define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy; + +/* + * Applications should use -DOPENSSL_API_COMPAT= to suppress the + * declarations of functions deprecated in or before . Otherwise, they + * still won't see them if the library has been built to disable deprecated + * functions. + */ +#if defined(OPENSSL_NO_DEPRECATED) +# define DECLARE_DEPRECATED(f) +#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define DECLARE_DEPRECATED(f) f __attribute__ ((deprecated)); +#else +# define DECLARE_DEPRECATED(f) f; +#endif + +#ifndef OPENSSL_FILE +# ifdef OPENSSL_NO_FILENAMES +# define OPENSSL_FILE "" +# define OPENSSL_LINE 0 +# else +# define OPENSSL_FILE __FILE__ +# define OPENSSL_LINE __LINE__ +# endif +#endif + +#ifndef OPENSSL_MIN_API +# define OPENSSL_MIN_API 0 +#endif + +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < OPENSSL_MIN_API +# undef OPENSSL_API_COMPAT +# define OPENSSL_API_COMPAT OPENSSL_MIN_API +#endif + +#if OPENSSL_API_COMPAT < 0x10100000L +# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_1_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x10000000L +# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_0_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x00908000L +# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_0_9_8(f) +#endif + +#define OPENSSL_CPUID_OBJ + +/* Generate 80386 code? */ +#undef I386_ONLY + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* + * The following are cipher-specific, but are part of the public API. + */ +#if !defined(OPENSSL_SYS_UEFI) +# undef BN_LLONG +/* Only one for the following should be defined */ +# define SIXTY_FOUR_BIT_LONG +# undef SIXTY_FOUR_BIT +# undef THIRTY_TWO_BIT +#endif + +#define RC4_INT unsigned char + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslconf_tvos_x86_64.h b/mobile/ios/FxA/FxA/include/openssl/opensslconf_tvos_x86_64.h new file mode 100644 index 0000000000..e0314c054b --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslconf_tvos_x86_64.h @@ -0,0 +1,179 @@ +/* + * WARNING: do not edit! + * Generated by Makefile from include/openssl/opensslconf.h.in + * + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_ALGORITHM_DEFINES +# error OPENSSL_ALGORITHM_DEFINES no longer supported +#endif + +/* + * OpenSSL was configured with the following options: + */ + +#ifndef OPENSSL_SYS_tvOS +# define OPENSSL_SYS_tvOS 1 +#endif +#define OPENSSL_MIN_API 0x10100000L +#ifndef OPENSSL_NO_MD2 +# define OPENSSL_NO_MD2 +#endif +#ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +#endif +#ifndef OPENSSL_THREADS +# define OPENSSL_THREADS +#endif +#ifndef OPENSSL_NO_ASAN +# define OPENSSL_NO_ASAN +#endif +#ifndef OPENSSL_NO_ASYNC +# define OPENSSL_NO_ASYNC +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG +# define OPENSSL_NO_CRYPTO_MDEBUG +#endif +#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +# define OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE +#endif +#ifndef OPENSSL_NO_DEPRECATED +# define OPENSSL_NO_DEPRECATED +#endif +#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 +# define OPENSSL_NO_EC_NISTP_64_GCC_128 +#endif +#ifndef OPENSSL_NO_EGD +# define OPENSSL_NO_EGD +#endif +#ifndef OPENSSL_NO_FUZZ_AFL +# define OPENSSL_NO_FUZZ_AFL +#endif +#ifndef OPENSSL_NO_FUZZ_LIBFUZZER +# define OPENSSL_NO_FUZZ_LIBFUZZER +#endif +#ifndef OPENSSL_NO_HEARTBEATS +# define OPENSSL_NO_HEARTBEATS +#endif +#ifndef OPENSSL_NO_MSAN +# define OPENSSL_NO_MSAN +#endif +#ifndef OPENSSL_NO_SCTP +# define OPENSSL_NO_SCTP +#endif +#ifndef OPENSSL_NO_SSL_TRACE +# define OPENSSL_NO_SSL_TRACE +#endif +#ifndef OPENSSL_NO_SSL3 +# define OPENSSL_NO_SSL3 +#endif +#ifndef OPENSSL_NO_SSL3_METHOD +# define OPENSSL_NO_SSL3_METHOD +#endif +#ifndef OPENSSL_NO_UBSAN +# define OPENSSL_NO_UBSAN +#endif +#ifndef OPENSSL_NO_UNIT_TEST +# define OPENSSL_NO_UNIT_TEST +#endif +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS +# define OPENSSL_NO_WEAK_SSL_CIPHERS +#endif +#ifndef OPENSSL_NO_AFALGENG +# define OPENSSL_NO_AFALGENG +#endif + + +/* + * Sometimes OPENSSSL_NO_xxx ends up with an empty file and some compilers + * don't like that. This will hopefully silence them. + */ +#define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy; + +/* + * Applications should use -DOPENSSL_API_COMPAT= to suppress the + * declarations of functions deprecated in or before . Otherwise, they + * still won't see them if the library has been built to disable deprecated + * functions. + */ +#if defined(OPENSSL_NO_DEPRECATED) +# define DECLARE_DEPRECATED(f) +#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define DECLARE_DEPRECATED(f) f __attribute__ ((deprecated)); +#else +# define DECLARE_DEPRECATED(f) f; +#endif + +#ifndef OPENSSL_FILE +# ifdef OPENSSL_NO_FILENAMES +# define OPENSSL_FILE "" +# define OPENSSL_LINE 0 +# else +# define OPENSSL_FILE __FILE__ +# define OPENSSL_LINE __LINE__ +# endif +#endif + +#ifndef OPENSSL_MIN_API +# define OPENSSL_MIN_API 0 +#endif + +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < OPENSSL_MIN_API +# undef OPENSSL_API_COMPAT +# define OPENSSL_API_COMPAT OPENSSL_MIN_API +#endif + +#if OPENSSL_API_COMPAT < 0x10100000L +# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_1_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x10000000L +# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_1_0_0(f) +#endif + +#if OPENSSL_API_COMPAT < 0x00908000L +# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) +#else +# define DEPRECATEDIN_0_9_8(f) +#endif + +#define OPENSSL_CPUID_OBJ + +/* Generate 80386 code? */ +#undef I386_ONLY + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* + * The following are cipher-specific, but are part of the public API. + */ +#if !defined(OPENSSL_SYS_UEFI) +# undef BN_LLONG +/* Only one for the following should be defined */ +# define SIXTY_FOUR_BIT_LONG +# undef SIXTY_FOUR_BIT +# undef THIRTY_TWO_BIT +#endif + +#define RC4_INT unsigned int + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/opensslv.h b/mobile/ios/FxA/FxA/include/openssl/opensslv.h new file mode 100644 index 0000000000..9d6708fa8b --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/opensslv.h @@ -0,0 +1,105 @@ +/* + * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_OPENSSLV_H +# define HEADER_OPENSSLV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*- + * Numeric release version identifier: + * MNNFFPPS: major minor fix patch status + * The status nibble has one of the values 0 for development, 1 to e for betas + * 1 to 14, and f for release. The patch level is exactly that. + * For example: + * 0.9.3-dev 0x00903000 + * 0.9.3-beta1 0x00903001 + * 0.9.3-beta2-dev 0x00903002 + * 0.9.3-beta2 0x00903002 (same as ...beta2-dev) + * 0.9.3 0x0090300f + * 0.9.3a 0x0090301f + * 0.9.4 0x0090400f + * 1.2.3z 0x102031af + * + * For continuity reasons (because 0.9.5 is already out, and is coded + * 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level + * part is slightly different, by setting the highest bit. This means + * that 0.9.5a looks like this: 0x0090581f. At 0.9.6, we can start + * with 0x0090600S... + * + * (Prior to 0.9.3-dev a different scheme was used: 0.9.2b is 0x0922.) + * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for + * major minor fix final patch/beta) + */ +# define OPENSSL_VERSION_NUMBER 0x1010005fL +# ifdef OPENSSL_FIPS +# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.0e-fips 16 Feb 2017" +# else +# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.0e 16 Feb 2017" +# endif + +/*- + * The macros below are to be used for shared library (.so, .dll, ...) + * versioning. That kind of versioning works a bit differently between + * operating systems. The most usual scheme is to set a major and a minor + * number, and have the runtime loader check that the major number is equal + * to what it was at application link time, while the minor number has to + * be greater or equal to what it was at application link time. With this + * scheme, the version number is usually part of the file name, like this: + * + * libcrypto.so.0.9 + * + * Some unixen also make a softlink with the major version number only: + * + * libcrypto.so.0 + * + * On Tru64 and IRIX 6.x it works a little bit differently. There, the + * shared library version is stored in the file, and is actually a series + * of versions, separated by colons. The rightmost version present in the + * library when linking an application is stored in the application to be + * matched at run time. When the application is run, a check is done to + * see if the library version stored in the application matches any of the + * versions in the version string of the library itself. + * This version string can be constructed in any way, depending on what + * kind of matching is desired. However, to implement the same scheme as + * the one used in the other unixen, all compatible versions, from lowest + * to highest, should be part of the string. Consecutive builds would + * give the following versions strings: + * + * 3.0 + * 3.0:3.1 + * 3.0:3.1:3.2 + * 4.0 + * 4.0:4.1 + * + * Notice how version 4 is completely incompatible with version, and + * therefore give the breach you can see. + * + * There may be other schemes as well that I haven't yet discovered. + * + * So, here's the way it works here: first of all, the library version + * number doesn't need at all to match the overall OpenSSL version. + * However, it's nice and more understandable if it actually does. + * The current library version is stored in the macro SHLIB_VERSION_NUMBER, + * which is just a piece of text in the format "M.m.e" (Major, minor, edit). + * For the sake of Tru64, IRIX, and any other OS that behaves in similar ways, + * we need to keep a history of version numbers, which is done in the + * macro SHLIB_VERSION_HISTORY. The numbers are separated by colons and + * should only keep the versions that are binary compatible with the current. + */ +# define SHLIB_VERSION_HISTORY "" +# define SHLIB_VERSION_NUMBER "1.1" + + +#ifdef __cplusplus +} +#endif +#endif /* HEADER_OPENSSLV_H */ diff --git a/mobile/ios/FxA/FxA/include/openssl/ossl_typ.h b/mobile/ios/FxA/FxA/include/openssl/ossl_typ.h new file mode 100644 index 0000000000..129a67f057 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ossl_typ.h @@ -0,0 +1,190 @@ +/* + * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_OPENSSL_TYPES_H +# define HEADER_OPENSSL_TYPES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +# include + +# ifdef NO_ASN1_TYPEDEFS +# define ASN1_INTEGER ASN1_STRING +# define ASN1_ENUMERATED ASN1_STRING +# define ASN1_BIT_STRING ASN1_STRING +# define ASN1_OCTET_STRING ASN1_STRING +# define ASN1_PRINTABLESTRING ASN1_STRING +# define ASN1_T61STRING ASN1_STRING +# define ASN1_IA5STRING ASN1_STRING +# define ASN1_UTCTIME ASN1_STRING +# define ASN1_GENERALIZEDTIME ASN1_STRING +# define ASN1_TIME ASN1_STRING +# define ASN1_GENERALSTRING ASN1_STRING +# define ASN1_UNIVERSALSTRING ASN1_STRING +# define ASN1_BMPSTRING ASN1_STRING +# define ASN1_VISIBLESTRING ASN1_STRING +# define ASN1_UTF8STRING ASN1_STRING +# define ASN1_BOOLEAN int +# define ASN1_NULL int +# else +typedef struct asn1_string_st ASN1_INTEGER; +typedef struct asn1_string_st ASN1_ENUMERATED; +typedef struct asn1_string_st ASN1_BIT_STRING; +typedef struct asn1_string_st ASN1_OCTET_STRING; +typedef struct asn1_string_st ASN1_PRINTABLESTRING; +typedef struct asn1_string_st ASN1_T61STRING; +typedef struct asn1_string_st ASN1_IA5STRING; +typedef struct asn1_string_st ASN1_GENERALSTRING; +typedef struct asn1_string_st ASN1_UNIVERSALSTRING; +typedef struct asn1_string_st ASN1_BMPSTRING; +typedef struct asn1_string_st ASN1_UTCTIME; +typedef struct asn1_string_st ASN1_TIME; +typedef struct asn1_string_st ASN1_GENERALIZEDTIME; +typedef struct asn1_string_st ASN1_VISIBLESTRING; +typedef struct asn1_string_st ASN1_UTF8STRING; +typedef struct asn1_string_st ASN1_STRING; +typedef int ASN1_BOOLEAN; +typedef int ASN1_NULL; +# endif + +typedef struct asn1_object_st ASN1_OBJECT; + +typedef struct ASN1_ITEM_st ASN1_ITEM; +typedef struct asn1_pctx_st ASN1_PCTX; +typedef struct asn1_sctx_st ASN1_SCTX; + +# ifdef _WIN32 +# undef X509_NAME +# undef X509_EXTENSIONS +# undef PKCS7_ISSUER_AND_SERIAL +# undef PKCS7_SIGNER_INFO +# undef OCSP_REQUEST +# undef OCSP_RESPONSE +# endif + +# ifdef BIGNUM +# undef BIGNUM +# endif +struct dane_st; +typedef struct bio_st BIO; +typedef struct bignum_st BIGNUM; +typedef struct bignum_ctx BN_CTX; +typedef struct bn_blinding_st BN_BLINDING; +typedef struct bn_mont_ctx_st BN_MONT_CTX; +typedef struct bn_recp_ctx_st BN_RECP_CTX; +typedef struct bn_gencb_st BN_GENCB; + +typedef struct buf_mem_st BUF_MEM; + +typedef struct evp_cipher_st EVP_CIPHER; +typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX; +typedef struct evp_md_st EVP_MD; +typedef struct evp_md_ctx_st EVP_MD_CTX; +typedef struct evp_pkey_st EVP_PKEY; + +typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD; + +typedef struct evp_pkey_method_st EVP_PKEY_METHOD; +typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; + +typedef struct evp_Encode_Ctx_st EVP_ENCODE_CTX; + +typedef struct hmac_ctx_st HMAC_CTX; + +typedef struct dh_st DH; +typedef struct dh_method DH_METHOD; + +typedef struct dsa_st DSA; +typedef struct dsa_method DSA_METHOD; + +typedef struct rsa_st RSA; +typedef struct rsa_meth_st RSA_METHOD; + +typedef struct ec_key_st EC_KEY; +typedef struct ec_key_method_st EC_KEY_METHOD; + +typedef struct rand_meth_st RAND_METHOD; + +typedef struct ssl_dane_st SSL_DANE; +typedef struct x509_st X509; +typedef struct X509_algor_st X509_ALGOR; +typedef struct X509_crl_st X509_CRL; +typedef struct x509_crl_method_st X509_CRL_METHOD; +typedef struct x509_revoked_st X509_REVOKED; +typedef struct X509_name_st X509_NAME; +typedef struct X509_pubkey_st X509_PUBKEY; +typedef struct x509_store_st X509_STORE; +typedef struct x509_store_ctx_st X509_STORE_CTX; + +typedef struct x509_object_st X509_OBJECT; +typedef struct x509_lookup_st X509_LOOKUP; +typedef struct x509_lookup_method_st X509_LOOKUP_METHOD; +typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM; + +typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO; + +typedef struct v3_ext_ctx X509V3_CTX; +typedef struct conf_st CONF; +typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS; + +typedef struct ui_st UI; +typedef struct ui_method_st UI_METHOD; + +typedef struct engine_st ENGINE; +typedef struct ssl_st SSL; +typedef struct ssl_ctx_st SSL_CTX; + +typedef struct comp_ctx_st COMP_CTX; +typedef struct comp_method_st COMP_METHOD; + +typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; +typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL; +typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; +typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE; + +typedef struct AUTHORITY_KEYID_st AUTHORITY_KEYID; +typedef struct DIST_POINT_st DIST_POINT; +typedef struct ISSUING_DIST_POINT_st ISSUING_DIST_POINT; +typedef struct NAME_CONSTRAINTS_st NAME_CONSTRAINTS; + +typedef struct crypto_ex_data_st CRYPTO_EX_DATA; + +typedef struct ocsp_req_ctx_st OCSP_REQ_CTX; +typedef struct ocsp_response_st OCSP_RESPONSE; +typedef struct ocsp_responder_id_st OCSP_RESPID; + +typedef struct sct_st SCT; +typedef struct sct_ctx_st SCT_CTX; +typedef struct ctlog_st CTLOG; +typedef struct ctlog_store_st CTLOG_STORE; +typedef struct ct_policy_eval_ctx_st CT_POLICY_EVAL_CTX; + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ + defined(INTMAX_MAX) && defined(UINTMAX_MAX) +typedef intmax_t ossl_intmax_t; +typedef uintmax_t ossl_uintmax_t; +#else +/* + * Not long long, because the C-library can only be expected to provide + * strtoll(), strtoull() at the same time as intmax_t and strtoimax(), + * strtoumax(). Since we use these for parsing arguments, we need the + * conversion functions, not just the sizes. + */ +typedef long ossl_intmax_t; +typedef unsigned long ossl_uintmax_t; +#endif + +#ifdef __cplusplus +} +#endif +#endif /* def HEADER_OPENSSL_TYPES_H */ diff --git a/mobile/ios/FxA/FxA/include/openssl/pem.h b/mobile/ios/FxA/FxA/include/openssl/pem.h new file mode 100644 index 0000000000..2375d63553 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/pem.h @@ -0,0 +1,501 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_PEM_H +# define HEADER_PEM_H + +# include +# include +# include +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +# define PEM_BUFSIZE 1024 + +# define PEM_STRING_X509_OLD "X509 CERTIFICATE" +# define PEM_STRING_X509 "CERTIFICATE" +# define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE" +# define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST" +# define PEM_STRING_X509_REQ "CERTIFICATE REQUEST" +# define PEM_STRING_X509_CRL "X509 CRL" +# define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY" +# define PEM_STRING_PUBLIC "PUBLIC KEY" +# define PEM_STRING_RSA "RSA PRIVATE KEY" +# define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY" +# define PEM_STRING_DSA "DSA PRIVATE KEY" +# define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY" +# define PEM_STRING_PKCS7 "PKCS7" +# define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA" +# define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY" +# define PEM_STRING_PKCS8INF "PRIVATE KEY" +# define PEM_STRING_DHPARAMS "DH PARAMETERS" +# define PEM_STRING_DHXPARAMS "X9.42 DH PARAMETERS" +# define PEM_STRING_SSL_SESSION "SSL SESSION PARAMETERS" +# define PEM_STRING_DSAPARAMS "DSA PARAMETERS" +# define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY" +# define PEM_STRING_ECPARAMETERS "EC PARAMETERS" +# define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY" +# define PEM_STRING_PARAMETERS "PARAMETERS" +# define PEM_STRING_CMS "CMS" + +# define PEM_TYPE_ENCRYPTED 10 +# define PEM_TYPE_MIC_ONLY 20 +# define PEM_TYPE_MIC_CLEAR 30 +# define PEM_TYPE_CLEAR 40 + +typedef struct pem_recip_st { + char *name; + X509_NAME *dn; + int cipher; + int key_enc; + /* char iv[8]; unused and wrong size */ +} PEM_USER; + +typedef struct pem_ctx_st { + int type; /* what type of object */ + struct { + int version; + int mode; + } proc_type; + + char *domain; + + struct { + int cipher; + /*- + unused, and wrong size + unsigned char iv[8]; */ + } DEK_info; + + PEM_USER *originator; + + int num_recipient; + PEM_USER **recipient; + +/*- + XXX(ben): don#t think this is used! + STACK *x509_chain; / * certificate chain */ + EVP_MD *md; /* signature type */ + + int md_enc; /* is the md encrypted or not? */ + int md_len; /* length of md_data */ + char *md_data; /* message digest, could be pkey encrypted */ + + EVP_CIPHER *dec; /* date encryption cipher */ + int key_len; /* key length */ + unsigned char *key; /* key */ + /*- + unused, and wrong size + unsigned char iv[8]; */ + + int data_enc; /* is the data encrypted */ + int data_len; + unsigned char *data; +} PEM_CTX; + +/* + * These macros make the PEM_read/PEM_write functions easier to maintain and + * write. Now they are all implemented with either: IMPLEMENT_PEM_rw(...) or + * IMPLEMENT_PEM_rw_cb(...) + */ + +# ifdef OPENSSL_NO_STDIO + +# define IMPLEMENT_PEM_read_fp(name, type, str, asn1) /**/ +# define IMPLEMENT_PEM_write_fp(name, type, str, asn1) /**/ +# define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) /**/ +# define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) /**/ +# define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) /**/ +# else + +# define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \ +type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\ +{ \ +return PEM_ASN1_read((d2i_of_void *)d2i_##asn1, str,fp,(void **)x,cb,u); \ +} + +# define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \ +int PEM_write_##name(FILE *fp, type *x) \ +{ \ +return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL); \ +} + +# define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \ +int PEM_write_##name(FILE *fp, const type *x) \ +{ \ +return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,(void *)x,NULL,NULL,0,NULL,NULL); \ +} + +# define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \ +int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ + } + +# define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \ +int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ + } + +# endif + +# define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ +type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\ +{ \ +return PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \ +} + +# define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ +int PEM_write_bio_##name(BIO *bp, type *x) \ +{ \ +return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL); \ +} + +# define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ +int PEM_write_bio_##name(BIO *bp, const type *x) \ +{ \ +return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,NULL,NULL,0,NULL,NULL); \ +} + +# define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ +int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u); \ + } + +# define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ +int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,enc,kstr,klen,cb,u); \ + } + +# define IMPLEMENT_PEM_write(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp(name, type, str, asn1) + +# define IMPLEMENT_PEM_write_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) + +# define IMPLEMENT_PEM_write_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) + +# define IMPLEMENT_PEM_write_cb_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) + +# define IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_read_fp(name, type, str, asn1) + +# define IMPLEMENT_PEM_rw(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write(name, type, str, asn1) + +# define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_const(name, type, str, asn1) + +# define IMPLEMENT_PEM_rw_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb(name, type, str, asn1) + +/* These are the same except they are for the declarations */ + +# if defined(OPENSSL_NO_STDIO) + +# define DECLARE_PEM_read_fp(name, type) /**/ +# define DECLARE_PEM_write_fp(name, type) /**/ +# define DECLARE_PEM_write_fp_const(name, type) /**/ +# define DECLARE_PEM_write_cb_fp(name, type) /**/ +# else + +# define DECLARE_PEM_read_fp(name, type) \ + type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u); + +# define DECLARE_PEM_write_fp(name, type) \ + int PEM_write_##name(FILE *fp, type *x); + +# define DECLARE_PEM_write_fp_const(name, type) \ + int PEM_write_##name(FILE *fp, const type *x); + +# define DECLARE_PEM_write_cb_fp(name, type) \ + int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + +# endif + +# define DECLARE_PEM_read_bio(name, type) \ + type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u); + +# define DECLARE_PEM_write_bio(name, type) \ + int PEM_write_bio_##name(BIO *bp, type *x); + +# define DECLARE_PEM_write_bio_const(name, type) \ + int PEM_write_bio_##name(BIO *bp, const type *x); + +# define DECLARE_PEM_write_cb_bio(name, type) \ + int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + +# define DECLARE_PEM_write(name, type) \ + DECLARE_PEM_write_bio(name, type) \ + DECLARE_PEM_write_fp(name, type) +# define DECLARE_PEM_write_const(name, type) \ + DECLARE_PEM_write_bio_const(name, type) \ + DECLARE_PEM_write_fp_const(name, type) +# define DECLARE_PEM_write_cb(name, type) \ + DECLARE_PEM_write_cb_bio(name, type) \ + DECLARE_PEM_write_cb_fp(name, type) +# define DECLARE_PEM_read(name, type) \ + DECLARE_PEM_read_bio(name, type) \ + DECLARE_PEM_read_fp(name, type) +# define DECLARE_PEM_rw(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write(name, type) +# define DECLARE_PEM_rw_const(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_const(name, type) +# define DECLARE_PEM_rw_cb(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_cb(name, type) +typedef int pem_password_cb (char *buf, int size, int rwflag, void *userdata); + +int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher); +int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *len, + pem_password_cb *callback, void *u); + +int PEM_read_bio(BIO *bp, char **name, char **header, + unsigned char **data, long *len); +int PEM_write_bio(BIO *bp, const char *name, const char *hdr, + const unsigned char *data, long len); +int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, + const char *name, BIO *bp, pem_password_cb *cb, + void *u); +void *PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x, + pem_password_cb *cb, void *u); +int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, void *x, + const EVP_CIPHER *enc, unsigned char *kstr, int klen, + pem_password_cb *cb, void *u); + +STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, + pem_password_cb *cb, void *u); +int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cd, void *u); + +#ifndef OPENSSL_NO_STDIO +int PEM_read(FILE *fp, char **name, char **header, + unsigned char **data, long *len); +int PEM_write(FILE *fp, const char *name, const char *hdr, + const unsigned char *data, long len); +void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, + pem_password_cb *cb, void *u); +int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp, + void *x, const EVP_CIPHER *enc, unsigned char *kstr, + int klen, pem_password_cb *callback, void *u); +STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, + pem_password_cb *cb, void *u); +#endif + +int PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type); +int PEM_SignUpdate(EVP_MD_CTX *ctx, unsigned char *d, unsigned int cnt); +int PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, + unsigned int *siglen, EVP_PKEY *pkey); + +int PEM_def_callback(char *buf, int num, int w, void *key); +void PEM_proc_type(char *buf, int type); +void PEM_dek_info(char *buf, const char *type, int len, char *str); + +# include + +DECLARE_PEM_rw(X509, X509) +DECLARE_PEM_rw(X509_AUX, X509) +DECLARE_PEM_rw(X509_REQ, X509_REQ) +DECLARE_PEM_write(X509_REQ_NEW, X509_REQ) +DECLARE_PEM_rw(X509_CRL, X509_CRL) +DECLARE_PEM_rw(PKCS7, PKCS7) +DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE) +DECLARE_PEM_rw(PKCS8, X509_SIG) +DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO) +# ifndef OPENSSL_NO_RSA +DECLARE_PEM_rw_cb(RSAPrivateKey, RSA) +DECLARE_PEM_rw_const(RSAPublicKey, RSA) +DECLARE_PEM_rw(RSA_PUBKEY, RSA) +# endif +# ifndef OPENSSL_NO_DSA +DECLARE_PEM_rw_cb(DSAPrivateKey, DSA) +DECLARE_PEM_rw(DSA_PUBKEY, DSA) +DECLARE_PEM_rw_const(DSAparams, DSA) +# endif +# ifndef OPENSSL_NO_EC +DECLARE_PEM_rw_const(ECPKParameters, EC_GROUP) +DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY) +DECLARE_PEM_rw(EC_PUBKEY, EC_KEY) +# endif +# ifndef OPENSSL_NO_DH +DECLARE_PEM_rw_const(DHparams, DH) +DECLARE_PEM_write_const(DHxparams, DH) +# endif +DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY) +DECLARE_PEM_rw(PUBKEY, EVP_PKEY) + +int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x, + const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u); + +int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, + char *, int, pem_password_cb *, void *); +int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); +EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, + void *u); + +# ifndef OPENSSL_NO_STDIO +int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); + +EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, + void *u); + +int PEM_write_PKCS8PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, pem_password_cb *cd, + void *u); +# endif +EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x); +int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x); + +# ifndef OPENSSL_NO_DSA +EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length); +EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length); +EVP_PKEY *b2i_PrivateKey_bio(BIO *in); +EVP_PKEY *b2i_PublicKey_bio(BIO *in); +int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk); +int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk); +# ifndef OPENSSL_NO_RC4 +EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u); +int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, + pem_password_cb *cb, void *u); +# endif +# endif + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_PEM_strings(void); + +/* Error codes for the PEM functions. */ + +/* Function codes. */ +# define PEM_F_B2I_DSS 127 +# define PEM_F_B2I_PVK_BIO 128 +# define PEM_F_B2I_RSA 129 +# define PEM_F_CHECK_BITLEN_DSA 130 +# define PEM_F_CHECK_BITLEN_RSA 131 +# define PEM_F_D2I_PKCS8PRIVATEKEY_BIO 120 +# define PEM_F_D2I_PKCS8PRIVATEKEY_FP 121 +# define PEM_F_DO_B2I 132 +# define PEM_F_DO_B2I_BIO 133 +# define PEM_F_DO_BLOB_HEADER 134 +# define PEM_F_DO_PK8PKEY 126 +# define PEM_F_DO_PK8PKEY_FP 125 +# define PEM_F_DO_PVK_BODY 135 +# define PEM_F_DO_PVK_HEADER 136 +# define PEM_F_I2B_PVK 137 +# define PEM_F_I2B_PVK_BIO 138 +# define PEM_F_LOAD_IV 101 +# define PEM_F_PEM_ASN1_READ 102 +# define PEM_F_PEM_ASN1_READ_BIO 103 +# define PEM_F_PEM_ASN1_WRITE 104 +# define PEM_F_PEM_ASN1_WRITE_BIO 105 +# define PEM_F_PEM_DEF_CALLBACK 100 +# define PEM_F_PEM_DO_HEADER 106 +# define PEM_F_PEM_GET_EVP_CIPHER_INFO 107 +# define PEM_F_PEM_READ 108 +# define PEM_F_PEM_READ_BIO 109 +# define PEM_F_PEM_READ_BIO_DHPARAMS 141 +# define PEM_F_PEM_READ_BIO_PARAMETERS 140 +# define PEM_F_PEM_READ_BIO_PRIVATEKEY 123 +# define PEM_F_PEM_READ_DHPARAMS 142 +# define PEM_F_PEM_READ_PRIVATEKEY 124 +# define PEM_F_PEM_SIGNFINAL 112 +# define PEM_F_PEM_WRITE 113 +# define PEM_F_PEM_WRITE_BIO 114 +# define PEM_F_PEM_WRITE_PRIVATEKEY 139 +# define PEM_F_PEM_X509_INFO_READ 115 +# define PEM_F_PEM_X509_INFO_READ_BIO 116 +# define PEM_F_PEM_X509_INFO_WRITE_BIO 117 + +/* Reason codes. */ +# define PEM_R_BAD_BASE64_DECODE 100 +# define PEM_R_BAD_DECRYPT 101 +# define PEM_R_BAD_END_LINE 102 +# define PEM_R_BAD_IV_CHARS 103 +# define PEM_R_BAD_MAGIC_NUMBER 116 +# define PEM_R_BAD_PASSWORD_READ 104 +# define PEM_R_BAD_VERSION_NUMBER 117 +# define PEM_R_BIO_WRITE_FAILURE 118 +# define PEM_R_CIPHER_IS_NULL 127 +# define PEM_R_ERROR_CONVERTING_PRIVATE_KEY 115 +# define PEM_R_EXPECTING_PRIVATE_KEY_BLOB 119 +# define PEM_R_EXPECTING_PUBLIC_KEY_BLOB 120 +# define PEM_R_HEADER_TOO_LONG 128 +# define PEM_R_INCONSISTENT_HEADER 121 +# define PEM_R_KEYBLOB_HEADER_PARSE_ERROR 122 +# define PEM_R_KEYBLOB_TOO_SHORT 123 +# define PEM_R_MISSING_DEK_IV 129 +# define PEM_R_NOT_DEK_INFO 105 +# define PEM_R_NOT_ENCRYPTED 106 +# define PEM_R_NOT_PROC_TYPE 107 +# define PEM_R_NO_START_LINE 108 +# define PEM_R_PROBLEMS_GETTING_PASSWORD 109 +# define PEM_R_PVK_DATA_TOO_SHORT 124 +# define PEM_R_PVK_TOO_SHORT 125 +# define PEM_R_READ_KEY 111 +# define PEM_R_SHORT_HEADER 112 +# define PEM_R_UNEXPECTED_DEK_IV 130 +# define PEM_R_UNSUPPORTED_CIPHER 113 +# define PEM_R_UNSUPPORTED_ENCRYPTION 114 +# define PEM_R_UNSUPPORTED_KEY_COMPONENTS 126 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/pem2.h b/mobile/ios/FxA/FxA/include/openssl/pem2.h new file mode 100644 index 0000000000..cfe73f139e --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/pem2.h @@ -0,0 +1,20 @@ +/* + * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HEADER_PEM_H +int ERR_load_PEM_strings(void); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/pkcs12.h b/mobile/ios/FxA/FxA/include/openssl/pkcs12.h new file mode 100644 index 0000000000..deaded9df9 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/pkcs12.h @@ -0,0 +1,282 @@ +/* + * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_PKCS12_H +# define HEADER_PKCS12_H + +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +# define PKCS12_KEY_ID 1 +# define PKCS12_IV_ID 2 +# define PKCS12_MAC_ID 3 + +/* Default iteration count */ +# ifndef PKCS12_DEFAULT_ITER +# define PKCS12_DEFAULT_ITER PKCS5_DEFAULT_ITER +# endif + +# define PKCS12_MAC_KEY_LENGTH 20 + +# define PKCS12_SALT_LEN 8 + +/* It's not clear if these are actually needed... */ +# define PKCS12_key_gen PKCS12_key_gen_utf8 +# define PKCS12_add_friendlyname PKCS12_add_friendlyname_utf8 + +/* MS key usage constants */ + +# define KEY_EX 0x10 +# define KEY_SIG 0x80 + +typedef struct PKCS12_MAC_DATA_st PKCS12_MAC_DATA; + +typedef struct PKCS12_st PKCS12; + +typedef struct PKCS12_SAFEBAG_st PKCS12_SAFEBAG; + +DEFINE_STACK_OF(PKCS12_SAFEBAG) + +typedef struct pkcs12_bag_st PKCS12_BAGS; + +# define PKCS12_ERROR 0 +# define PKCS12_OK 1 + +/* Compatibility macros */ + +#if OPENSSL_API_COMPAT < 0x10100000L + +# define M_PKCS12_bag_type PKCS12_bag_type +# define M_PKCS12_cert_bag_type PKCS12_cert_bag_type +# define M_PKCS12_crl_bag_type PKCS12_cert_bag_type + +# define PKCS12_certbag2x509 PKCS12_SAFEBAG_get1_cert +# define PKCS12_certbag2scrl PKCS12_SAFEBAG_get1_crl +# define PKCS12_bag_type PKCS12_SAFEBAG_get_nid +# define PKCS12_cert_bag_type PKCS12_SAFEBAG_get_bag_nid +# define PKCS12_x5092certbag PKCS12_SAFEBAG_create_cert +# define PKCS12_x509crl2certbag PKCS12_SAFEBAG_create_crl +# define PKCS12_MAKE_KEYBAG PKCS12_SAFEBAG_create0_p8inf +# define PKCS12_MAKE_SHKEYBAG PKCS12_SAFEBAG_create_pkcs8_encrypt + +#endif + +DEPRECATEDIN_1_1_0(ASN1_TYPE *PKCS12_get_attr(const PKCS12_SAFEBAG *bag, int attr_nid)) + +ASN1_TYPE *PKCS8_get_attr(PKCS8_PRIV_KEY_INFO *p8, int attr_nid); +int PKCS12_mac_present(const PKCS12 *p12); +void PKCS12_get0_mac(const ASN1_OCTET_STRING **pmac, + const X509_ALGOR **pmacalg, + const ASN1_OCTET_STRING **psalt, + const ASN1_INTEGER **piter, + const PKCS12 *p12); + +const ASN1_TYPE *PKCS12_SAFEBAG_get0_attr(const PKCS12_SAFEBAG *bag, + int attr_nid); +const ASN1_OBJECT *PKCS12_SAFEBAG_get0_type(const PKCS12_SAFEBAG *bag); +int PKCS12_SAFEBAG_get_nid(const PKCS12_SAFEBAG *bag); +int PKCS12_SAFEBAG_get_bag_nid(const PKCS12_SAFEBAG *bag); + +X509 *PKCS12_SAFEBAG_get1_cert(const PKCS12_SAFEBAG *bag); +X509_CRL *PKCS12_SAFEBAG_get1_crl(const PKCS12_SAFEBAG *bag); +const STACK_OF(PKCS12_SAFEBAG) * +PKCS12_SAFEBAG_get0_safes(const PKCS12_SAFEBAG *bag); +const PKCS8_PRIV_KEY_INFO *PKCS12_SAFEBAG_get0_p8inf(const PKCS12_SAFEBAG *bag); +const X509_SIG *PKCS12_SAFEBAG_get0_pkcs8(const PKCS12_SAFEBAG *bag); + +PKCS12_SAFEBAG *PKCS12_SAFEBAG_create_cert(X509 *x509); +PKCS12_SAFEBAG *PKCS12_SAFEBAG_create_crl(X509_CRL *crl); +PKCS12_SAFEBAG *PKCS12_SAFEBAG_create0_p8inf(PKCS8_PRIV_KEY_INFO *p8); +PKCS12_SAFEBAG *PKCS12_SAFEBAG_create0_pkcs8(X509_SIG *p8); +PKCS12_SAFEBAG *PKCS12_SAFEBAG_create_pkcs8_encrypt(int pbe_nid, + const char *pass, + int passlen, + unsigned char *salt, + int saltlen, int iter, + PKCS8_PRIV_KEY_INFO *p8inf); + +PKCS12_SAFEBAG *PKCS12_item_pack_safebag(void *obj, const ASN1_ITEM *it, + int nid1, int nid2); +PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(const X509_SIG *p8, const char *pass, + int passlen); +PKCS8_PRIV_KEY_INFO *PKCS12_decrypt_skey(const PKCS12_SAFEBAG *bag, + const char *pass, int passlen); +X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, + const char *pass, int passlen, unsigned char *salt, + int saltlen, int iter, PKCS8_PRIV_KEY_INFO *p8); +X509_SIG *PKCS8_set0_pbe(const char *pass, int passlen, + PKCS8_PRIV_KEY_INFO *p8inf, X509_ALGOR *pbe); +PKCS7 *PKCS12_pack_p7data(STACK_OF(PKCS12_SAFEBAG) *sk); +STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7data(PKCS7 *p7); +PKCS7 *PKCS12_pack_p7encdata(int pbe_nid, const char *pass, int passlen, + unsigned char *salt, int saltlen, int iter, + STACK_OF(PKCS12_SAFEBAG) *bags); +STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7encdata(PKCS7 *p7, const char *pass, + int passlen); + +int PKCS12_pack_authsafes(PKCS12 *p12, STACK_OF(PKCS7) *safes); +STACK_OF(PKCS7) *PKCS12_unpack_authsafes(const PKCS12 *p12); + +int PKCS12_add_localkeyid(PKCS12_SAFEBAG *bag, unsigned char *name, + int namelen); +int PKCS12_add_friendlyname_asc(PKCS12_SAFEBAG *bag, const char *name, + int namelen); +int PKCS12_add_friendlyname_utf8(PKCS12_SAFEBAG *bag, const char *name, + int namelen); +int PKCS12_add_CSPName_asc(PKCS12_SAFEBAG *bag, const char *name, + int namelen); +int PKCS12_add_friendlyname_uni(PKCS12_SAFEBAG *bag, + const unsigned char *name, int namelen); +int PKCS8_add_keyusage(PKCS8_PRIV_KEY_INFO *p8, int usage); +ASN1_TYPE *PKCS12_get_attr_gen(const STACK_OF(X509_ATTRIBUTE) *attrs, + int attr_nid); +char *PKCS12_get_friendlyname(PKCS12_SAFEBAG *bag); +const STACK_OF(X509_ATTRIBUTE) * +PKCS12_SAFEBAG_get0_attrs(const PKCS12_SAFEBAG *bag); +unsigned char *PKCS12_pbe_crypt(const X509_ALGOR *algor, + const char *pass, int passlen, + const unsigned char *in, int inlen, + unsigned char **data, int *datalen, + int en_de); +void *PKCS12_item_decrypt_d2i(const X509_ALGOR *algor, const ASN1_ITEM *it, + const char *pass, int passlen, + const ASN1_OCTET_STRING *oct, int zbuf); +ASN1_OCTET_STRING *PKCS12_item_i2d_encrypt(X509_ALGOR *algor, + const ASN1_ITEM *it, + const char *pass, int passlen, + void *obj, int zbuf); +PKCS12 *PKCS12_init(int mode); +int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt, + int saltlen, int id, int iter, int n, + unsigned char *out, const EVP_MD *md_type); +int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, + int saltlen, int id, int iter, int n, + unsigned char *out, const EVP_MD *md_type); +int PKCS12_key_gen_utf8(const char *pass, int passlen, unsigned char *salt, + int saltlen, int id, int iter, int n, + unsigned char *out, const EVP_MD *md_type); +int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, + const EVP_MD *md_type, int en_de); +int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen, + unsigned char *mac, unsigned int *maclen); +int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen); +int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen, + unsigned char *salt, int saltlen, int iter, + const EVP_MD *md_type); +int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, + int saltlen, const EVP_MD *md_type); +unsigned char *OPENSSL_asc2uni(const char *asc, int asclen, + unsigned char **uni, int *unilen); +char *OPENSSL_uni2asc(const unsigned char *uni, int unilen); +unsigned char *OPENSSL_utf82uni(const char *asc, int asclen, + unsigned char **uni, int *unilen); +char *OPENSSL_uni2utf8(const unsigned char *uni, int unilen); + +DECLARE_ASN1_FUNCTIONS(PKCS12) +DECLARE_ASN1_FUNCTIONS(PKCS12_MAC_DATA) +DECLARE_ASN1_FUNCTIONS(PKCS12_SAFEBAG) +DECLARE_ASN1_FUNCTIONS(PKCS12_BAGS) + +DECLARE_ASN1_ITEM(PKCS12_SAFEBAGS) +DECLARE_ASN1_ITEM(PKCS12_AUTHSAFES) + +void PKCS12_PBE_add(void); +int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, + STACK_OF(X509) **ca); +PKCS12 *PKCS12_create(const char *pass, const char *name, EVP_PKEY *pkey, + X509 *cert, STACK_OF(X509) *ca, int nid_key, int nid_cert, + int iter, int mac_iter, int keytype); + +PKCS12_SAFEBAG *PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert); +PKCS12_SAFEBAG *PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags, + EVP_PKEY *key, int key_usage, int iter, + int key_nid, const char *pass); +int PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags, + int safe_nid, int iter, const char *pass); +PKCS12 *PKCS12_add_safes(STACK_OF(PKCS7) *safes, int p7_nid); + +int i2d_PKCS12_bio(BIO *bp, PKCS12 *p12); +# ifndef OPENSSL_NO_STDIO +int i2d_PKCS12_fp(FILE *fp, PKCS12 *p12); +# endif +PKCS12 *d2i_PKCS12_bio(BIO *bp, PKCS12 **p12); +# ifndef OPENSSL_NO_STDIO +PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12); +# endif +int PKCS12_newpass(PKCS12 *p12, const char *oldpass, const char *newpass); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_PKCS12_strings(void); + +/* Error codes for the PKCS12 functions. */ + +/* Function codes. */ +# define PKCS12_F_PKCS12_CREATE 105 +# define PKCS12_F_PKCS12_GEN_MAC 107 +# define PKCS12_F_PKCS12_INIT 109 +# define PKCS12_F_PKCS12_ITEM_DECRYPT_D2I 106 +# define PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT 108 +# define PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG 117 +# define PKCS12_F_PKCS12_KEY_GEN_ASC 110 +# define PKCS12_F_PKCS12_KEY_GEN_UNI 111 +# define PKCS12_F_PKCS12_KEY_GEN_UTF8 116 +# define PKCS12_F_PKCS12_NEWPASS 128 +# define PKCS12_F_PKCS12_PACK_P7DATA 114 +# define PKCS12_F_PKCS12_PACK_P7ENCDATA 115 +# define PKCS12_F_PKCS12_PARSE 118 +# define PKCS12_F_PKCS12_PBE_CRYPT 119 +# define PKCS12_F_PKCS12_PBE_KEYIVGEN 120 +# define PKCS12_F_PKCS12_SAFEBAG_CREATE0_P8INF 112 +# define PKCS12_F_PKCS12_SAFEBAG_CREATE0_PKCS8 113 +# define PKCS12_F_PKCS12_SAFEBAG_CREATE_PKCS8_ENCRYPT 133 +# define PKCS12_F_PKCS12_SETUP_MAC 122 +# define PKCS12_F_PKCS12_SET_MAC 123 +# define PKCS12_F_PKCS12_UNPACK_AUTHSAFES 130 +# define PKCS12_F_PKCS12_UNPACK_P7DATA 131 +# define PKCS12_F_PKCS12_VERIFY_MAC 126 +# define PKCS12_F_PKCS8_ENCRYPT 125 +# define PKCS12_F_PKCS8_SET0_PBE 132 + +/* Reason codes. */ +# define PKCS12_R_CANT_PACK_STRUCTURE 100 +# define PKCS12_R_CONTENT_TYPE_NOT_DATA 121 +# define PKCS12_R_DECODE_ERROR 101 +# define PKCS12_R_ENCODE_ERROR 102 +# define PKCS12_R_ENCRYPT_ERROR 103 +# define PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE 120 +# define PKCS12_R_INVALID_NULL_ARGUMENT 104 +# define PKCS12_R_INVALID_NULL_PKCS12_POINTER 105 +# define PKCS12_R_IV_GEN_ERROR 106 +# define PKCS12_R_KEY_GEN_ERROR 107 +# define PKCS12_R_MAC_ABSENT 108 +# define PKCS12_R_MAC_GENERATION_ERROR 109 +# define PKCS12_R_MAC_SETUP_ERROR 110 +# define PKCS12_R_MAC_STRING_SET_ERROR 111 +# define PKCS12_R_MAC_VERIFY_FAILURE 113 +# define PKCS12_R_PARSE_ERROR 114 +# define PKCS12_R_PKCS12_ALGOR_CIPHERINIT_ERROR 115 +# define PKCS12_R_PKCS12_CIPHERFINAL_ERROR 116 +# define PKCS12_R_PKCS12_PBE_CRYPT_ERROR 117 +# define PKCS12_R_UNKNOWN_DIGEST_ALGORITHM 118 +# define PKCS12_R_UNSUPPORTED_PKCS12_MODE 119 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/pkcs7.h b/mobile/ios/FxA/FxA/include/openssl/pkcs7.h new file mode 100644 index 0000000000..691f722022 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/pkcs7.h @@ -0,0 +1,404 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_PKCS7_H +# define HEADER_PKCS7_H + +# include +# include +# include + +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/*- +Encryption_ID DES-CBC +Digest_ID MD5 +Digest_Encryption_ID rsaEncryption +Key_Encryption_ID rsaEncryption +*/ + +typedef struct pkcs7_issuer_and_serial_st { + X509_NAME *issuer; + ASN1_INTEGER *serial; +} PKCS7_ISSUER_AND_SERIAL; + +typedef struct pkcs7_signer_info_st { + ASN1_INTEGER *version; /* version 1 */ + PKCS7_ISSUER_AND_SERIAL *issuer_and_serial; + X509_ALGOR *digest_alg; + STACK_OF(X509_ATTRIBUTE) *auth_attr; /* [ 0 ] */ + X509_ALGOR *digest_enc_alg; + ASN1_OCTET_STRING *enc_digest; + STACK_OF(X509_ATTRIBUTE) *unauth_attr; /* [ 1 ] */ + /* The private key to sign with */ + EVP_PKEY *pkey; +} PKCS7_SIGNER_INFO; + +DEFINE_STACK_OF(PKCS7_SIGNER_INFO) + +typedef struct pkcs7_recip_info_st { + ASN1_INTEGER *version; /* version 0 */ + PKCS7_ISSUER_AND_SERIAL *issuer_and_serial; + X509_ALGOR *key_enc_algor; + ASN1_OCTET_STRING *enc_key; + X509 *cert; /* get the pub-key from this */ +} PKCS7_RECIP_INFO; + +DEFINE_STACK_OF(PKCS7_RECIP_INFO) + +typedef struct pkcs7_signed_st { + ASN1_INTEGER *version; /* version 1 */ + STACK_OF(X509_ALGOR) *md_algs; /* md used */ + STACK_OF(X509) *cert; /* [ 0 ] */ + STACK_OF(X509_CRL) *crl; /* [ 1 ] */ + STACK_OF(PKCS7_SIGNER_INFO) *signer_info; + struct pkcs7_st *contents; +} PKCS7_SIGNED; +/* + * The above structure is very very similar to PKCS7_SIGN_ENVELOPE. How about + * merging the two + */ + +typedef struct pkcs7_enc_content_st { + ASN1_OBJECT *content_type; + X509_ALGOR *algorithm; + ASN1_OCTET_STRING *enc_data; /* [ 0 ] */ + const EVP_CIPHER *cipher; +} PKCS7_ENC_CONTENT; + +typedef struct pkcs7_enveloped_st { + ASN1_INTEGER *version; /* version 0 */ + STACK_OF(PKCS7_RECIP_INFO) *recipientinfo; + PKCS7_ENC_CONTENT *enc_data; +} PKCS7_ENVELOPE; + +typedef struct pkcs7_signedandenveloped_st { + ASN1_INTEGER *version; /* version 1 */ + STACK_OF(X509_ALGOR) *md_algs; /* md used */ + STACK_OF(X509) *cert; /* [ 0 ] */ + STACK_OF(X509_CRL) *crl; /* [ 1 ] */ + STACK_OF(PKCS7_SIGNER_INFO) *signer_info; + PKCS7_ENC_CONTENT *enc_data; + STACK_OF(PKCS7_RECIP_INFO) *recipientinfo; +} PKCS7_SIGN_ENVELOPE; + +typedef struct pkcs7_digest_st { + ASN1_INTEGER *version; /* version 0 */ + X509_ALGOR *md; /* md used */ + struct pkcs7_st *contents; + ASN1_OCTET_STRING *digest; +} PKCS7_DIGEST; + +typedef struct pkcs7_encrypted_st { + ASN1_INTEGER *version; /* version 0 */ + PKCS7_ENC_CONTENT *enc_data; +} PKCS7_ENCRYPT; + +typedef struct pkcs7_st { + /* + * The following is non NULL if it contains ASN1 encoding of this + * structure + */ + unsigned char *asn1; + long length; +# define PKCS7_S_HEADER 0 +# define PKCS7_S_BODY 1 +# define PKCS7_S_TAIL 2 + int state; /* used during processing */ + int detached; + ASN1_OBJECT *type; + /* content as defined by the type */ + /* + * all encryption/message digests are applied to the 'contents', leaving + * out the 'type' field. + */ + union { + char *ptr; + /* NID_pkcs7_data */ + ASN1_OCTET_STRING *data; + /* NID_pkcs7_signed */ + PKCS7_SIGNED *sign; + /* NID_pkcs7_enveloped */ + PKCS7_ENVELOPE *enveloped; + /* NID_pkcs7_signedAndEnveloped */ + PKCS7_SIGN_ENVELOPE *signed_and_enveloped; + /* NID_pkcs7_digest */ + PKCS7_DIGEST *digest; + /* NID_pkcs7_encrypted */ + PKCS7_ENCRYPT *encrypted; + /* Anything else */ + ASN1_TYPE *other; + } d; +} PKCS7; + +DEFINE_STACK_OF(PKCS7) + +# define PKCS7_OP_SET_DETACHED_SIGNATURE 1 +# define PKCS7_OP_GET_DETACHED_SIGNATURE 2 + +# define PKCS7_get_signed_attributes(si) ((si)->auth_attr) +# define PKCS7_get_attributes(si) ((si)->unauth_attr) + +# define PKCS7_type_is_signed(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_signed) +# define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted) +# define PKCS7_type_is_enveloped(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_enveloped) +# define PKCS7_type_is_signedAndEnveloped(a) \ + (OBJ_obj2nid((a)->type) == NID_pkcs7_signedAndEnveloped) +# define PKCS7_type_is_data(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_data) +# define PKCS7_type_is_digest(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_digest) + +# define PKCS7_set_detached(p,v) \ + PKCS7_ctrl(p,PKCS7_OP_SET_DETACHED_SIGNATURE,v,NULL) +# define PKCS7_get_detached(p) \ + PKCS7_ctrl(p,PKCS7_OP_GET_DETACHED_SIGNATURE,0,NULL) + +# define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7)) + +/* S/MIME related flags */ + +# define PKCS7_TEXT 0x1 +# define PKCS7_NOCERTS 0x2 +# define PKCS7_NOSIGS 0x4 +# define PKCS7_NOCHAIN 0x8 +# define PKCS7_NOINTERN 0x10 +# define PKCS7_NOVERIFY 0x20 +# define PKCS7_DETACHED 0x40 +# define PKCS7_BINARY 0x80 +# define PKCS7_NOATTR 0x100 +# define PKCS7_NOSMIMECAP 0x200 +# define PKCS7_NOOLDMIMETYPE 0x400 +# define PKCS7_CRLFEOL 0x800 +# define PKCS7_STREAM 0x1000 +# define PKCS7_NOCRL 0x2000 +# define PKCS7_PARTIAL 0x4000 +# define PKCS7_REUSE_DIGEST 0x8000 +# define PKCS7_NO_DUAL_CONTENT 0x10000 + +/* Flags: for compatibility with older code */ + +# define SMIME_TEXT PKCS7_TEXT +# define SMIME_NOCERTS PKCS7_NOCERTS +# define SMIME_NOSIGS PKCS7_NOSIGS +# define SMIME_NOCHAIN PKCS7_NOCHAIN +# define SMIME_NOINTERN PKCS7_NOINTERN +# define SMIME_NOVERIFY PKCS7_NOVERIFY +# define SMIME_DETACHED PKCS7_DETACHED +# define SMIME_BINARY PKCS7_BINARY +# define SMIME_NOATTR PKCS7_NOATTR + +/* CRLF ASCII canonicalisation */ +# define SMIME_ASCIICRLF 0x80000 + +DECLARE_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL) + +int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data, + const EVP_MD *type, unsigned char *md, + unsigned int *len); +# ifndef OPENSSL_NO_STDIO +PKCS7 *d2i_PKCS7_fp(FILE *fp, PKCS7 **p7); +int i2d_PKCS7_fp(FILE *fp, PKCS7 *p7); +# endif +PKCS7 *PKCS7_dup(PKCS7 *p7); +PKCS7 *d2i_PKCS7_bio(BIO *bp, PKCS7 **p7); +int i2d_PKCS7_bio(BIO *bp, PKCS7 *p7); +int i2d_PKCS7_bio_stream(BIO *out, PKCS7 *p7, BIO *in, int flags); +int PEM_write_bio_PKCS7_stream(BIO *out, PKCS7 *p7, BIO *in, int flags); + +DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNER_INFO) +DECLARE_ASN1_FUNCTIONS(PKCS7_RECIP_INFO) +DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNED) +DECLARE_ASN1_FUNCTIONS(PKCS7_ENC_CONTENT) +DECLARE_ASN1_FUNCTIONS(PKCS7_ENVELOPE) +DECLARE_ASN1_FUNCTIONS(PKCS7_SIGN_ENVELOPE) +DECLARE_ASN1_FUNCTIONS(PKCS7_DIGEST) +DECLARE_ASN1_FUNCTIONS(PKCS7_ENCRYPT) +DECLARE_ASN1_FUNCTIONS(PKCS7) + +DECLARE_ASN1_ITEM(PKCS7_ATTR_SIGN) +DECLARE_ASN1_ITEM(PKCS7_ATTR_VERIFY) + +DECLARE_ASN1_NDEF_FUNCTION(PKCS7) +DECLARE_ASN1_PRINT_FUNCTION(PKCS7) + +long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg); + +int PKCS7_set_type(PKCS7 *p7, int type); +int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other); +int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data); +int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, + const EVP_MD *dgst); +int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si); +int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *p7i); +int PKCS7_add_certificate(PKCS7 *p7, X509 *x509); +int PKCS7_add_crl(PKCS7 *p7, X509_CRL *x509); +int PKCS7_content_new(PKCS7 *p7, int nid); +int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, + BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si); +int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, + X509 *x509); + +BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio); +int PKCS7_dataFinal(PKCS7 *p7, BIO *bio); +BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert); + +PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, + EVP_PKEY *pkey, const EVP_MD *dgst); +X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si); +int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md); +STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7); + +PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509); +void PKCS7_SIGNER_INFO_get0_algs(PKCS7_SIGNER_INFO *si, EVP_PKEY **pk, + X509_ALGOR **pdig, X509_ALGOR **psig); +void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc); +int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri); +int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509); +int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher); +int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7); + +PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx); +ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk); +int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int type, + void *data); +int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, + void *value); +ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid); +ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid); +int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, + STACK_OF(X509_ATTRIBUTE) *sk); +int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, + STACK_OF(X509_ATTRIBUTE) *sk); + +PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, + BIO *data, int flags); + +PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, + X509 *signcert, EVP_PKEY *pkey, + const EVP_MD *md, int flags); + +int PKCS7_final(PKCS7 *p7, BIO *data, int flags); +int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, + BIO *indata, BIO *out, int flags); +STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, + int flags); +PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, + int flags); +int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, + int flags); + +int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si, + STACK_OF(X509_ALGOR) *cap); +STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si); +int PKCS7_simple_smimecap(STACK_OF(X509_ALGOR) *sk, int nid, int arg); + +int PKCS7_add_attrib_content_type(PKCS7_SIGNER_INFO *si, ASN1_OBJECT *coid); +int PKCS7_add0_attrib_signing_time(PKCS7_SIGNER_INFO *si, ASN1_TIME *t); +int PKCS7_add1_attrib_digest(PKCS7_SIGNER_INFO *si, + const unsigned char *md, int mdlen); + +int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags); +PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont); + +BIO *BIO_new_PKCS7(BIO *out, PKCS7 *p7); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_PKCS7_strings(void); + +/* Error codes for the PKCS7 functions. */ + +/* Function codes. */ +# define PKCS7_F_DO_PKCS7_SIGNED_ATTRIB 136 +# define PKCS7_F_PKCS7_ADD0_ATTRIB_SIGNING_TIME 135 +# define PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP 118 +# define PKCS7_F_PKCS7_ADD_CERTIFICATE 100 +# define PKCS7_F_PKCS7_ADD_CRL 101 +# define PKCS7_F_PKCS7_ADD_RECIPIENT_INFO 102 +# define PKCS7_F_PKCS7_ADD_SIGNATURE 131 +# define PKCS7_F_PKCS7_ADD_SIGNER 103 +# define PKCS7_F_PKCS7_BIO_ADD_DIGEST 125 +# define PKCS7_F_PKCS7_COPY_EXISTING_DIGEST 138 +# define PKCS7_F_PKCS7_CTRL 104 +# define PKCS7_F_PKCS7_DATADECODE 112 +# define PKCS7_F_PKCS7_DATAFINAL 128 +# define PKCS7_F_PKCS7_DATAINIT 105 +# define PKCS7_F_PKCS7_DATAVERIFY 107 +# define PKCS7_F_PKCS7_DECRYPT 114 +# define PKCS7_F_PKCS7_DECRYPT_RINFO 133 +# define PKCS7_F_PKCS7_ENCODE_RINFO 132 +# define PKCS7_F_PKCS7_ENCRYPT 115 +# define PKCS7_F_PKCS7_FINAL 134 +# define PKCS7_F_PKCS7_FIND_DIGEST 127 +# define PKCS7_F_PKCS7_GET0_SIGNERS 124 +# define PKCS7_F_PKCS7_RECIP_INFO_SET 130 +# define PKCS7_F_PKCS7_SET_CIPHER 108 +# define PKCS7_F_PKCS7_SET_CONTENT 109 +# define PKCS7_F_PKCS7_SET_DIGEST 126 +# define PKCS7_F_PKCS7_SET_TYPE 110 +# define PKCS7_F_PKCS7_SIGN 116 +# define PKCS7_F_PKCS7_SIGNATUREVERIFY 113 +# define PKCS7_F_PKCS7_SIGNER_INFO_SET 129 +# define PKCS7_F_PKCS7_SIGNER_INFO_SIGN 139 +# define PKCS7_F_PKCS7_SIGN_ADD_SIGNER 137 +# define PKCS7_F_PKCS7_SIMPLE_SMIMECAP 119 +# define PKCS7_F_PKCS7_VERIFY 117 + +/* Reason codes. */ +# define PKCS7_R_CERTIFICATE_VERIFY_ERROR 117 +# define PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 144 +# define PKCS7_R_CIPHER_NOT_INITIALIZED 116 +# define PKCS7_R_CONTENT_AND_DATA_PRESENT 118 +# define PKCS7_R_CTRL_ERROR 152 +# define PKCS7_R_DECRYPT_ERROR 119 +# define PKCS7_R_DIGEST_FAILURE 101 +# define PKCS7_R_ENCRYPTION_CTRL_FAILURE 149 +# define PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 150 +# define PKCS7_R_ERROR_ADDING_RECIPIENT 120 +# define PKCS7_R_ERROR_SETTING_CIPHER 121 +# define PKCS7_R_INVALID_NULL_POINTER 143 +# define PKCS7_R_INVALID_SIGNED_DATA_TYPE 155 +# define PKCS7_R_NO_CONTENT 122 +# define PKCS7_R_NO_DEFAULT_DIGEST 151 +# define PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND 154 +# define PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE 115 +# define PKCS7_R_NO_SIGNATURES_ON_DATA 123 +# define PKCS7_R_NO_SIGNERS 142 +# define PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE 104 +# define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR 124 +# define PKCS7_R_PKCS7_ADD_SIGNER_ERROR 153 +# define PKCS7_R_PKCS7_DATASIGN 145 +# define PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 127 +# define PKCS7_R_SIGNATURE_FAILURE 105 +# define PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND 128 +# define PKCS7_R_SIGNING_CTRL_FAILURE 147 +# define PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 148 +# define PKCS7_R_SMIME_TEXT_ERROR 129 +# define PKCS7_R_UNABLE_TO_FIND_CERTIFICATE 106 +# define PKCS7_R_UNABLE_TO_FIND_MEM_BIO 107 +# define PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST 108 +# define PKCS7_R_UNKNOWN_DIGEST_TYPE 109 +# define PKCS7_R_UNKNOWN_OPERATION 110 +# define PKCS7_R_UNSUPPORTED_CIPHER_TYPE 111 +# define PKCS7_R_UNSUPPORTED_CONTENT_TYPE 112 +# define PKCS7_R_WRONG_CONTENT_TYPE 113 +# define PKCS7_R_WRONG_PKCS7_TYPE 114 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/rand.h b/mobile/ios/FxA/FxA/include/openssl/rand.h new file mode 100644 index 0000000000..d521ae192a --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/rand.h @@ -0,0 +1,89 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_RAND_H +# define HEADER_RAND_H + +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Already defined in ossl_typ.h */ +/* typedef struct rand_meth_st RAND_METHOD; */ + +struct rand_meth_st { + int (*seed) (const void *buf, int num); + int (*bytes) (unsigned char *buf, int num); + void (*cleanup) (void); + int (*add) (const void *buf, int num, double entropy); + int (*pseudorand) (unsigned char *buf, int num); + int (*status) (void); +}; + +# ifdef BN_DEBUG +extern int rand_predictable; +# endif + +int RAND_set_rand_method(const RAND_METHOD *meth); +const RAND_METHOD *RAND_get_rand_method(void); +# ifndef OPENSSL_NO_ENGINE +int RAND_set_rand_engine(ENGINE *engine); +# endif +RAND_METHOD *RAND_OpenSSL(void); +#if OPENSSL_API_COMPAT < 0x10100000L +# define RAND_cleanup() while(0) continue +#endif +int RAND_bytes(unsigned char *buf, int num); +DEPRECATEDIN_1_1_0(int RAND_pseudo_bytes(unsigned char *buf, int num)) +void RAND_seed(const void *buf, int num); +#if defined(__ANDROID__) && defined(__NDK_FPABI__) +__NDK_FPABI__ /* __attribute__((pcs("aapcs"))) on ARM */ +#endif +void RAND_add(const void *buf, int num, double entropy); +int RAND_load_file(const char *file, long max_bytes); +int RAND_write_file(const char *file); +const char *RAND_file_name(char *file, size_t num); +int RAND_status(void); +# ifndef OPENSSL_NO_EGD +int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes); +int RAND_egd(const char *path); +int RAND_egd_bytes(const char *path, int bytes); +# endif +int RAND_poll(void); + +#if defined(_WIN32) && (defined(BASETYPES) || defined(_WINDEF_H)) +/* application has to include in order to use these */ +DEPRECATEDIN_1_1_0(void RAND_screen(void)) +DEPRECATEDIN_1_1_0(int RAND_event(UINT, WPARAM, LPARAM)) +#endif + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_RAND_strings(void); + +/* Error codes for the RAND functions. */ + +/* Function codes. */ +# define RAND_F_RAND_BYTES 100 + +/* Reason codes. */ +# define RAND_R_PRNG_NOT_SEEDED 100 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/rc2.h b/mobile/ios/FxA/FxA/include/openssl/rc2.h new file mode 100644 index 0000000000..585f9e4c38 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/rc2.h @@ -0,0 +1,51 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_RC2_H +# define HEADER_RC2_H + +# include + +# ifndef OPENSSL_NO_RC2 +# ifdef __cplusplus +extern "C" { +# endif + +typedef unsigned int RC2_INT; + +# define RC2_ENCRYPT 1 +# define RC2_DECRYPT 0 + +# define RC2_BLOCK 8 +# define RC2_KEY_LENGTH 16 + +typedef struct rc2_key_st { + RC2_INT data[64]; +} RC2_KEY; + +void RC2_set_key(RC2_KEY *key, int len, const unsigned char *data, int bits); +void RC2_ecb_encrypt(const unsigned char *in, unsigned char *out, + RC2_KEY *key, int enc); +void RC2_encrypt(unsigned long *data, RC2_KEY *key); +void RC2_decrypt(unsigned long *data, RC2_KEY *key); +void RC2_cbc_encrypt(const unsigned char *in, unsigned char *out, long length, + RC2_KEY *ks, unsigned char *iv, int enc); +void RC2_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, RC2_KEY *schedule, unsigned char *ivec, + int *num, int enc); +void RC2_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, RC2_KEY *schedule, unsigned char *ivec, + int *num); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/rc4.h b/mobile/ios/FxA/FxA/include/openssl/rc4.h new file mode 100644 index 0000000000..86803b37fb --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/rc4.h @@ -0,0 +1,36 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_RC4_H +# define HEADER_RC4_H + +# include + +# ifndef OPENSSL_NO_RC4 +# include +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct rc4_key_st { + RC4_INT x, y; + RC4_INT data[256]; +} RC4_KEY; + +const char *RC4_options(void); +void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data); +void RC4(RC4_KEY *key, size_t len, const unsigned char *indata, + unsigned char *outdata); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/rc5.h b/mobile/ios/FxA/FxA/include/openssl/rc5.h new file mode 100644 index 0000000000..793f88e4e8 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/rc5.h @@ -0,0 +1,63 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_RC5_H +# define HEADER_RC5_H + +# include + +# ifndef OPENSSL_NO_RC5 +# ifdef __cplusplus +extern "C" { +# endif + +# define RC5_ENCRYPT 1 +# define RC5_DECRYPT 0 + +# define RC5_32_INT unsigned int + +# define RC5_32_BLOCK 8 +# define RC5_32_KEY_LENGTH 16/* This is a default, max is 255 */ + +/* + * This are the only values supported. Tweak the code if you want more The + * most supported modes will be RC5-32/12/16 RC5-32/16/8 + */ +# define RC5_8_ROUNDS 8 +# define RC5_12_ROUNDS 12 +# define RC5_16_ROUNDS 16 + +typedef struct rc5_key_st { + /* Number of rounds */ + int rounds; + RC5_32_INT data[2 * (RC5_16_ROUNDS + 1)]; +} RC5_32_KEY; + +void RC5_32_set_key(RC5_32_KEY *key, int len, const unsigned char *data, + int rounds); +void RC5_32_ecb_encrypt(const unsigned char *in, unsigned char *out, + RC5_32_KEY *key, int enc); +void RC5_32_encrypt(unsigned long *data, RC5_32_KEY *key); +void RC5_32_decrypt(unsigned long *data, RC5_32_KEY *key); +void RC5_32_cbc_encrypt(const unsigned char *in, unsigned char *out, + long length, RC5_32_KEY *ks, unsigned char *iv, + int enc); +void RC5_32_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, RC5_32_KEY *schedule, + unsigned char *ivec, int *num, int enc); +void RC5_32_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, RC5_32_KEY *schedule, + unsigned char *ivec, int *num); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ripemd.h b/mobile/ios/FxA/FxA/include/openssl/ripemd.h new file mode 100644 index 0000000000..c42026aa42 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ripemd.h @@ -0,0 +1,47 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_RIPEMD_H +# define HEADER_RIPEMD_H + +# include + +#ifndef OPENSSL_NO_RMD160 +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + +# define RIPEMD160_LONG unsigned int + +# define RIPEMD160_CBLOCK 64 +# define RIPEMD160_LBLOCK (RIPEMD160_CBLOCK/4) +# define RIPEMD160_DIGEST_LENGTH 20 + +typedef struct RIPEMD160state_st { + RIPEMD160_LONG A, B, C, D, E; + RIPEMD160_LONG Nl, Nh; + RIPEMD160_LONG data[RIPEMD160_LBLOCK]; + unsigned int num; +} RIPEMD160_CTX; + +int RIPEMD160_Init(RIPEMD160_CTX *c); +int RIPEMD160_Update(RIPEMD160_CTX *c, const void *data, size_t len); +int RIPEMD160_Final(unsigned char *md, RIPEMD160_CTX *c); +unsigned char *RIPEMD160(const unsigned char *d, size_t n, unsigned char *md); +void RIPEMD160_Transform(RIPEMD160_CTX *c, const unsigned char *b); + +# ifdef __cplusplus +} +# endif +# endif + + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/rsa.h b/mobile/ios/FxA/FxA/include/openssl/rsa.h new file mode 100644 index 0000000000..d97d6e075a --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/rsa.h @@ -0,0 +1,590 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_RSA_H +# define HEADER_RSA_H + +# include + +# ifndef OPENSSL_NO_RSA +# include +# include +# include +# include +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# endif +# ifdef __cplusplus +extern "C" { +# endif + +/* The types RSA and RSA_METHOD are defined in ossl_typ.h */ + +# ifndef OPENSSL_RSA_MAX_MODULUS_BITS +# define OPENSSL_RSA_MAX_MODULUS_BITS 16384 +# endif + +# define OPENSSL_RSA_FIPS_MIN_MODULUS_BITS 1024 + +# ifndef OPENSSL_RSA_SMALL_MODULUS_BITS +# define OPENSSL_RSA_SMALL_MODULUS_BITS 3072 +# endif +# ifndef OPENSSL_RSA_MAX_PUBEXP_BITS + +/* exponent limit enforced for "large" modulus only */ +# define OPENSSL_RSA_MAX_PUBEXP_BITS 64 +# endif + +# define RSA_3 0x3L +# define RSA_F4 0x10001L + +# define RSA_METHOD_FLAG_NO_CHECK 0x0001/* don't check pub/private + * match */ + +# define RSA_FLAG_CACHE_PUBLIC 0x0002 +# define RSA_FLAG_CACHE_PRIVATE 0x0004 +# define RSA_FLAG_BLINDING 0x0008 +# define RSA_FLAG_THREAD_SAFE 0x0010 +/* + * This flag means the private key operations will be handled by rsa_mod_exp + * and that they do not depend on the private key components being present: + * for example a key stored in external hardware. Without this flag + * bn_mod_exp gets called when private key components are absent. + */ +# define RSA_FLAG_EXT_PKEY 0x0020 + +/* + * new with 0.9.6j and 0.9.7b; the built-in + * RSA implementation now uses blinding by + * default (ignoring RSA_FLAG_BLINDING), + * but other engines might not need it + */ +# define RSA_FLAG_NO_BLINDING 0x0080 +# if OPENSSL_API_COMPAT < 0x10100000L +/* + * Does nothing. Previously this switched off constant time behaviour. + */ +# define RSA_FLAG_NO_CONSTTIME 0x0000 +# endif +# if OPENSSL_API_COMPAT < 0x00908000L +/* deprecated name for the flag*/ +/* + * new with 0.9.7h; the built-in RSA + * implementation now uses constant time + * modular exponentiation for secret exponents + * by default. This flag causes the + * faster variable sliding window method to + * be used for all exponents. + */ +# define RSA_FLAG_NO_EXP_CONSTTIME RSA_FLAG_NO_CONSTTIME +# endif + +# define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, \ + pad, NULL) + +# define EVP_PKEY_CTX_get_rsa_padding(ctx, ppad) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, \ + EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad) + +# define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, \ + (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \ + EVP_PKEY_CTRL_RSA_PSS_SALTLEN, \ + len, NULL) + +# define EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx, plen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, \ + (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \ + EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, \ + 0, plen) + +# define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) + +# define EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, pubexp) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp) + +# define EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, \ + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \ + EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)md) + +# define EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ + EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md) + +# define EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, pmd) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, \ + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \ + EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void *)pmd) + +# define EVP_PKEY_CTX_get_rsa_oaep_md(ctx, pmd) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ + EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void *)pmd) + +# define EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, l, llen) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ + EVP_PKEY_CTRL_RSA_OAEP_LABEL, llen, (void *)l) + +# define EVP_PKEY_CTX_get0_rsa_oaep_label(ctx, l) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ + EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, (void *)l) + +# define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1) +# define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 2) + +# define EVP_PKEY_CTRL_RSA_KEYGEN_BITS (EVP_PKEY_ALG_CTRL + 3) +# define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP (EVP_PKEY_ALG_CTRL + 4) +# define EVP_PKEY_CTRL_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 5) + +# define EVP_PKEY_CTRL_GET_RSA_PADDING (EVP_PKEY_ALG_CTRL + 6) +# define EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 7) +# define EVP_PKEY_CTRL_GET_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 8) + +# define EVP_PKEY_CTRL_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 9) +# define EVP_PKEY_CTRL_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 10) + +# define EVP_PKEY_CTRL_GET_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 11) +# define EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 12) + +# define RSA_PKCS1_PADDING 1 +# define RSA_SSLV23_PADDING 2 +# define RSA_NO_PADDING 3 +# define RSA_PKCS1_OAEP_PADDING 4 +# define RSA_X931_PADDING 5 +/* EVP_PKEY_ only */ +# define RSA_PKCS1_PSS_PADDING 6 + +# define RSA_PKCS1_PADDING_SIZE 11 + +# define RSA_set_app_data(s,arg) RSA_set_ex_data(s,0,arg) +# define RSA_get_app_data(s) RSA_get_ex_data(s,0) + +RSA *RSA_new(void); +RSA *RSA_new_method(ENGINE *engine); +int RSA_bits(const RSA *rsa); +int RSA_size(const RSA *rsa); +int RSA_security_bits(const RSA *rsa); + +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d); +int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q); +int RSA_set0_crt_params(RSA *r,BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp); +void RSA_get0_key(const RSA *r, + const BIGNUM **n, const BIGNUM **e, const BIGNUM **d); +void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q); +void RSA_get0_crt_params(const RSA *r, + const BIGNUM **dmp1, const BIGNUM **dmq1, + const BIGNUM **iqmp); +void RSA_clear_flags(RSA *r, int flags); +int RSA_test_flags(const RSA *r, int flags); +void RSA_set_flags(RSA *r, int flags); +ENGINE *RSA_get0_engine(const RSA *r); + +/* Deprecated version */ +DEPRECATEDIN_0_9_8(RSA *RSA_generate_key(int bits, unsigned long e, void + (*callback) (int, int, void *), + void *cb_arg)) + +/* New version */ +int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); + +int RSA_X931_derive_ex(RSA *rsa, BIGNUM *p1, BIGNUM *p2, BIGNUM *q1, + BIGNUM *q2, const BIGNUM *Xp1, const BIGNUM *Xp2, + const BIGNUM *Xp, const BIGNUM *Xq1, const BIGNUM *Xq2, + const BIGNUM *Xq, const BIGNUM *e, BN_GENCB *cb); +int RSA_X931_generate_key_ex(RSA *rsa, int bits, const BIGNUM *e, + BN_GENCB *cb); + +int RSA_check_key(const RSA *); +int RSA_check_key_ex(const RSA *, BN_GENCB *cb); + /* next 4 return -1 on error */ +int RSA_public_encrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +int RSA_private_encrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +int RSA_public_decrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +int RSA_private_decrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +void RSA_free(RSA *r); +/* "up" the RSA object's reference count */ +int RSA_up_ref(RSA *r); + +int RSA_flags(const RSA *r); + +void RSA_set_default_method(const RSA_METHOD *meth); +const RSA_METHOD *RSA_get_default_method(void); +const RSA_METHOD *RSA_get_method(const RSA *rsa); +int RSA_set_method(RSA *rsa, const RSA_METHOD *meth); + +/* these are the actual RSA functions */ +const RSA_METHOD *RSA_PKCS1_OpenSSL(void); + +const RSA_METHOD *RSA_null_method(void); + +DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPublicKey) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPrivateKey) + +typedef struct rsa_pss_params_st { + X509_ALGOR *hashAlgorithm; + X509_ALGOR *maskGenAlgorithm; + ASN1_INTEGER *saltLength; + ASN1_INTEGER *trailerField; +} RSA_PSS_PARAMS; + +DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS) + +typedef struct rsa_oaep_params_st { + X509_ALGOR *hashFunc; + X509_ALGOR *maskGenFunc; + X509_ALGOR *pSourceFunc; +} RSA_OAEP_PARAMS; + +DECLARE_ASN1_FUNCTIONS(RSA_OAEP_PARAMS) + +# ifndef OPENSSL_NO_STDIO +int RSA_print_fp(FILE *fp, const RSA *r, int offset); +# endif + +int RSA_print(BIO *bp, const RSA *r, int offset); + +/* + * The following 2 functions sign and verify a X509_SIG ASN1 object inside + * PKCS#1 padded RSA encryption + */ +int RSA_sign(int type, const unsigned char *m, unsigned int m_length, + unsigned char *sigret, unsigned int *siglen, RSA *rsa); +int RSA_verify(int type, const unsigned char *m, unsigned int m_length, + const unsigned char *sigbuf, unsigned int siglen, RSA *rsa); + +/* + * The following 2 function sign and verify a ASN1_OCTET_STRING object inside + * PKCS#1 padded RSA encryption + */ +int RSA_sign_ASN1_OCTET_STRING(int type, + const unsigned char *m, unsigned int m_length, + unsigned char *sigret, unsigned int *siglen, + RSA *rsa); +int RSA_verify_ASN1_OCTET_STRING(int type, const unsigned char *m, + unsigned int m_length, unsigned char *sigbuf, + unsigned int siglen, RSA *rsa); + +int RSA_blinding_on(RSA *rsa, BN_CTX *ctx); +void RSA_blinding_off(RSA *rsa); +BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *ctx); + +int RSA_padding_add_PKCS1_type_1(unsigned char *to, int tlen, + const unsigned char *f, int fl); +int RSA_padding_check_PKCS1_type_1(unsigned char *to, int tlen, + const unsigned char *f, int fl, + int rsa_len); +int RSA_padding_add_PKCS1_type_2(unsigned char *to, int tlen, + const unsigned char *f, int fl); +int RSA_padding_check_PKCS1_type_2(unsigned char *to, int tlen, + const unsigned char *f, int fl, + int rsa_len); +int PKCS1_MGF1(unsigned char *mask, long len, const unsigned char *seed, + long seedlen, const EVP_MD *dgst); +int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, + const unsigned char *f, int fl, + const unsigned char *p, int pl); +int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen, + const unsigned char *f, int fl, int rsa_len, + const unsigned char *p, int pl); +int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, + const unsigned char *from, int flen, + const unsigned char *param, int plen, + const EVP_MD *md, const EVP_MD *mgf1md); +int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, + const unsigned char *from, int flen, + int num, const unsigned char *param, + int plen, const EVP_MD *md, + const EVP_MD *mgf1md); +int RSA_padding_add_SSLv23(unsigned char *to, int tlen, + const unsigned char *f, int fl); +int RSA_padding_check_SSLv23(unsigned char *to, int tlen, + const unsigned char *f, int fl, int rsa_len); +int RSA_padding_add_none(unsigned char *to, int tlen, const unsigned char *f, + int fl); +int RSA_padding_check_none(unsigned char *to, int tlen, + const unsigned char *f, int fl, int rsa_len); +int RSA_padding_add_X931(unsigned char *to, int tlen, const unsigned char *f, + int fl); +int RSA_padding_check_X931(unsigned char *to, int tlen, + const unsigned char *f, int fl, int rsa_len); +int RSA_X931_hash_id(int nid); + +int RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash, + const EVP_MD *Hash, const unsigned char *EM, + int sLen); +int RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM, + const unsigned char *mHash, const EVP_MD *Hash, + int sLen); + +int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const unsigned char *mHash, + const EVP_MD *Hash, const EVP_MD *mgf1Hash, + const unsigned char *EM, int sLen); + +int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, + const unsigned char *mHash, + const EVP_MD *Hash, const EVP_MD *mgf1Hash, + int sLen); + +#define RSA_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_RSA, l, p, newf, dupf, freef) +int RSA_set_ex_data(RSA *r, int idx, void *arg); +void *RSA_get_ex_data(const RSA *r, int idx); + +RSA *RSAPublicKey_dup(RSA *rsa); +RSA *RSAPrivateKey_dup(RSA *rsa); + +/* + * If this flag is set the RSA method is FIPS compliant and can be used in + * FIPS mode. This is set in the validated module method. If an application + * sets this flag in its own methods it is its responsibility to ensure the + * result is compliant. + */ + +# define RSA_FLAG_FIPS_METHOD 0x0400 + +/* + * If this flag is set the operations normally disabled in FIPS mode are + * permitted it is then the applications responsibility to ensure that the + * usage is compliant. + */ + +# define RSA_FLAG_NON_FIPS_ALLOW 0x0400 +/* + * Application has decided PRNG is good enough to generate a key: don't + * check. + */ +# define RSA_FLAG_CHECKED 0x0800 + +RSA_METHOD *RSA_meth_new(const char *name, int flags); +void RSA_meth_free(RSA_METHOD *meth); +RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth); +const char *RSA_meth_get0_name(const RSA_METHOD *meth); +int RSA_meth_set1_name(RSA_METHOD *meth, const char *name); +int RSA_meth_get_flags(RSA_METHOD *meth); +int RSA_meth_set_flags(RSA_METHOD *meth, int flags); +void *RSA_meth_get0_app_data(const RSA_METHOD *meth); +int RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data); +int (*RSA_meth_get_pub_enc(const RSA_METHOD *meth)) + (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +int RSA_meth_set_pub_enc(RSA_METHOD *rsa, + int (*pub_enc) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)); +int (*RSA_meth_get_pub_dec(const RSA_METHOD *meth)) + (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +int RSA_meth_set_pub_dec(RSA_METHOD *rsa, + int (*pub_dec) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)); +int (*RSA_meth_get_priv_enc(const RSA_METHOD *meth)) + (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +int RSA_meth_set_priv_enc(RSA_METHOD *rsa, + int (*priv_enc) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)); +int (*RSA_meth_get_priv_dec(const RSA_METHOD *meth)) + (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding); +int RSA_meth_set_priv_dec(RSA_METHOD *rsa, + int (*priv_dec) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)); +int (*RSA_meth_get_mod_exp(const RSA_METHOD *meth)) + (BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx); +int RSA_meth_set_mod_exp(RSA_METHOD *rsa, + int (*mod_exp) (BIGNUM *r0, const BIGNUM *I, RSA *rsa, + BN_CTX *ctx)); +int (*RSA_meth_get_bn_mod_exp(const RSA_METHOD *meth)) + (BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +int RSA_meth_set_bn_mod_exp(RSA_METHOD *rsa, + int (*bn_mod_exp) (BIGNUM *r, + const BIGNUM *a, + const BIGNUM *p, + const BIGNUM *m, + BN_CTX *ctx, + BN_MONT_CTX *m_ctx)); +int (*RSA_meth_get_init(const RSA_METHOD *meth)) (RSA *rsa); +int RSA_meth_set_init(RSA_METHOD *rsa, int (*init) (RSA *rsa)); +int (*RSA_meth_get_finish(const RSA_METHOD *meth)) (RSA *rsa); +int RSA_meth_set_finish(RSA_METHOD *rsa, int (*finish) (RSA *rsa)); +int (*RSA_meth_get_sign(const RSA_METHOD *meth)) + (int type, + const unsigned char *m, unsigned int m_length, + unsigned char *sigret, unsigned int *siglen, + const RSA *rsa); +int RSA_meth_set_sign(RSA_METHOD *rsa, + int (*sign) (int type, const unsigned char *m, + unsigned int m_length, + unsigned char *sigret, unsigned int *siglen, + const RSA *rsa)); +int (*RSA_meth_get_verify(const RSA_METHOD *meth)) + (int dtype, const unsigned char *m, + unsigned int m_length, const unsigned char *sigbuf, + unsigned int siglen, const RSA *rsa); +int RSA_meth_set_verify(RSA_METHOD *rsa, + int (*verify) (int dtype, const unsigned char *m, + unsigned int m_length, + const unsigned char *sigbuf, + unsigned int siglen, const RSA *rsa)); +int (*RSA_meth_get_keygen(const RSA_METHOD *meth)) + (RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); +int RSA_meth_set_keygen(RSA_METHOD *rsa, + int (*keygen) (RSA *rsa, int bits, BIGNUM *e, + BN_GENCB *cb)); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_RSA_strings(void); + +/* Error codes for the RSA functions. */ + +/* Function codes. */ +# define RSA_F_CHECK_PADDING_MD 140 +# define RSA_F_ENCODE_PKCS1 146 +# define RSA_F_INT_RSA_VERIFY 145 +# define RSA_F_OLD_RSA_PRIV_DECODE 147 +# define RSA_F_PKEY_RSA_CTRL 143 +# define RSA_F_PKEY_RSA_CTRL_STR 144 +# define RSA_F_PKEY_RSA_SIGN 142 +# define RSA_F_PKEY_RSA_VERIFY 149 +# define RSA_F_PKEY_RSA_VERIFYRECOVER 141 +# define RSA_F_RSA_ALGOR_TO_MD 156 +# define RSA_F_RSA_BUILTIN_KEYGEN 129 +# define RSA_F_RSA_CHECK_KEY 123 +# define RSA_F_RSA_CHECK_KEY_EX 160 +# define RSA_F_RSA_CMS_DECRYPT 159 +# define RSA_F_RSA_ITEM_VERIFY 148 +# define RSA_F_RSA_METH_DUP 161 +# define RSA_F_RSA_METH_NEW 162 +# define RSA_F_RSA_METH_SET1_NAME 163 +# define RSA_F_RSA_MGF1_TO_MD 157 +# define RSA_F_RSA_NEW_METHOD 106 +# define RSA_F_RSA_NULL 124 +# define RSA_F_RSA_NULL_PRIVATE_DECRYPT 132 +# define RSA_F_RSA_NULL_PRIVATE_ENCRYPT 133 +# define RSA_F_RSA_NULL_PUBLIC_DECRYPT 134 +# define RSA_F_RSA_NULL_PUBLIC_ENCRYPT 135 +# define RSA_F_RSA_OSSL_PRIVATE_DECRYPT 101 +# define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT 102 +# define RSA_F_RSA_OSSL_PUBLIC_DECRYPT 103 +# define RSA_F_RSA_OSSL_PUBLIC_ENCRYPT 104 +# define RSA_F_RSA_PADDING_ADD_NONE 107 +# define RSA_F_RSA_PADDING_ADD_PKCS1_OAEP 121 +# define RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1 154 +# define RSA_F_RSA_PADDING_ADD_PKCS1_PSS 125 +# define RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1 152 +# define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1 108 +# define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2 109 +# define RSA_F_RSA_PADDING_ADD_SSLV23 110 +# define RSA_F_RSA_PADDING_ADD_X931 127 +# define RSA_F_RSA_PADDING_CHECK_NONE 111 +# define RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP 122 +# define RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1 153 +# define RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1 112 +# define RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2 113 +# define RSA_F_RSA_PADDING_CHECK_SSLV23 114 +# define RSA_F_RSA_PADDING_CHECK_X931 128 +# define RSA_F_RSA_PRINT 115 +# define RSA_F_RSA_PRINT_FP 116 +# define RSA_F_RSA_PRIV_ENCODE 138 +# define RSA_F_RSA_PSS_TO_CTX 155 +# define RSA_F_RSA_PUB_DECODE 139 +# define RSA_F_RSA_SETUP_BLINDING 136 +# define RSA_F_RSA_SIGN 117 +# define RSA_F_RSA_SIGN_ASN1_OCTET_STRING 118 +# define RSA_F_RSA_VERIFY 119 +# define RSA_F_RSA_VERIFY_ASN1_OCTET_STRING 120 +# define RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1 126 + +/* Reason codes. */ +# define RSA_R_ALGORITHM_MISMATCH 100 +# define RSA_R_BAD_E_VALUE 101 +# define RSA_R_BAD_FIXED_HEADER_DECRYPT 102 +# define RSA_R_BAD_PAD_BYTE_COUNT 103 +# define RSA_R_BAD_SIGNATURE 104 +# define RSA_R_BLOCK_TYPE_IS_NOT_01 106 +# define RSA_R_BLOCK_TYPE_IS_NOT_02 107 +# define RSA_R_DATA_GREATER_THAN_MOD_LEN 108 +# define RSA_R_DATA_TOO_LARGE 109 +# define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 110 +# define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 132 +# define RSA_R_DATA_TOO_SMALL 111 +# define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 122 +# define RSA_R_DIGEST_DOES_NOT_MATCH 158 +# define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 112 +# define RSA_R_DMP1_NOT_CONGRUENT_TO_D 124 +# define RSA_R_DMQ1_NOT_CONGRUENT_TO_D 125 +# define RSA_R_D_E_NOT_CONGRUENT_TO_1 123 +# define RSA_R_FIRST_OCTET_INVALID 133 +# define RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 144 +# define RSA_R_INVALID_DIGEST 157 +# define RSA_R_INVALID_DIGEST_LENGTH 143 +# define RSA_R_INVALID_HEADER 137 +# define RSA_R_INVALID_LABEL 160 +# define RSA_R_INVALID_MESSAGE_LENGTH 131 +# define RSA_R_INVALID_MGF1_MD 156 +# define RSA_R_INVALID_OAEP_PARAMETERS 161 +# define RSA_R_INVALID_PADDING 138 +# define RSA_R_INVALID_PADDING_MODE 141 +# define RSA_R_INVALID_PSS_PARAMETERS 149 +# define RSA_R_INVALID_PSS_SALTLEN 146 +# define RSA_R_INVALID_SALT_LENGTH 150 +# define RSA_R_INVALID_TRAILER 139 +# define RSA_R_INVALID_X931_DIGEST 142 +# define RSA_R_IQMP_NOT_INVERSE_OF_Q 126 +# define RSA_R_KEY_SIZE_TOO_SMALL 120 +# define RSA_R_LAST_OCTET_INVALID 134 +# define RSA_R_MODULUS_TOO_LARGE 105 +# define RSA_R_NO_PUBLIC_EXPONENT 140 +# define RSA_R_NULL_BEFORE_BLOCK_MISSING 113 +# define RSA_R_N_DOES_NOT_EQUAL_P_Q 127 +# define RSA_R_OAEP_DECODING_ERROR 121 +# define RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 148 +# define RSA_R_PADDING_CHECK_FAILED 114 +# define RSA_R_PKCS_DECODING_ERROR 159 +# define RSA_R_P_NOT_PRIME 128 +# define RSA_R_Q_NOT_PRIME 129 +# define RSA_R_RSA_OPERATIONS_NOT_SUPPORTED 130 +# define RSA_R_SLEN_CHECK_FAILED 136 +# define RSA_R_SLEN_RECOVERY_FAILED 135 +# define RSA_R_SSLV3_ROLLBACK_ATTACK 115 +# define RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 116 +# define RSA_R_UNKNOWN_ALGORITHM_TYPE 117 +# define RSA_R_UNKNOWN_DIGEST 166 +# define RSA_R_UNKNOWN_MASK_DIGEST 151 +# define RSA_R_UNKNOWN_PADDING_TYPE 118 +# define RSA_R_UNSUPPORTED_ENCRYPTION_TYPE 162 +# define RSA_R_UNSUPPORTED_LABEL_SOURCE 163 +# define RSA_R_UNSUPPORTED_MASK_ALGORITHM 153 +# define RSA_R_UNSUPPORTED_MASK_PARAMETER 154 +# define RSA_R_UNSUPPORTED_SIGNATURE_TYPE 155 +# define RSA_R_VALUE_MISSING 147 +# define RSA_R_WRONG_SIGNATURE_LENGTH 119 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/safestack.h b/mobile/ios/FxA/FxA/include/openssl/safestack.h new file mode 100644 index 0000000000..9fe733c24e --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/safestack.h @@ -0,0 +1,164 @@ +/* + * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_SAFESTACK_H +# define HEADER_SAFESTACK_H + +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +# define STACK_OF(type) struct stack_st_##type + +# define SKM_DEFINE_STACK_OF(t1, t2, t3) \ + STACK_OF(t1); \ + typedef int (*sk_##t1##_compfunc)(const t3 * const *a, const t3 *const *b); \ + typedef void (*sk_##t1##_freefunc)(t3 *a); \ + typedef t3 * (*sk_##t1##_copyfunc)(const t3 *a); \ + static ossl_inline int sk_##t1##_num(const STACK_OF(t1) *sk) \ + { \ + return OPENSSL_sk_num((const OPENSSL_STACK *)sk); \ + } \ + static ossl_inline t2 *sk_##t1##_value(const STACK_OF(t1) *sk, int idx) \ + { \ + return (t2 *)OPENSSL_sk_value((const OPENSSL_STACK *)sk, idx); \ + } \ + static ossl_inline STACK_OF(t1) *sk_##t1##_new(sk_##t1##_compfunc compare) \ + { \ + return (STACK_OF(t1) *)OPENSSL_sk_new((OPENSSL_sk_compfunc)compare); \ + } \ + static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \ + { \ + return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \ + } \ + static ossl_inline void sk_##t1##_free(STACK_OF(t1) *sk) \ + { \ + OPENSSL_sk_free((OPENSSL_STACK *)sk); \ + } \ + static ossl_inline void sk_##t1##_zero(STACK_OF(t1) *sk) \ + { \ + OPENSSL_sk_zero((OPENSSL_STACK *)sk); \ + } \ + static ossl_inline t2 *sk_##t1##_delete(STACK_OF(t1) *sk, int i) \ + { \ + return (t2 *)OPENSSL_sk_delete((OPENSSL_STACK *)sk, i); \ + } \ + static ossl_inline t2 *sk_##t1##_delete_ptr(STACK_OF(t1) *sk, t2 *ptr) \ + { \ + return (t2 *)OPENSSL_sk_delete_ptr((OPENSSL_STACK *)sk, \ + (const void *)ptr); \ + } \ + static ossl_inline int sk_##t1##_push(STACK_OF(t1) *sk, t2 *ptr) \ + { \ + return OPENSSL_sk_push((OPENSSL_STACK *)sk, (const void *)ptr); \ + } \ + static ossl_inline int sk_##t1##_unshift(STACK_OF(t1) *sk, t2 *ptr) \ + { \ + return OPENSSL_sk_unshift((OPENSSL_STACK *)sk, (const void *)ptr); \ + } \ + static ossl_inline t2 *sk_##t1##_pop(STACK_OF(t1) *sk) \ + { \ + return (t2 *)OPENSSL_sk_pop((OPENSSL_STACK *)sk); \ + } \ + static ossl_inline t2 *sk_##t1##_shift(STACK_OF(t1) *sk) \ + { \ + return (t2 *)OPENSSL_sk_shift((OPENSSL_STACK *)sk); \ + } \ + static ossl_inline void sk_##t1##_pop_free(STACK_OF(t1) *sk, sk_##t1##_freefunc freefunc) \ + { \ + OPENSSL_sk_pop_free((OPENSSL_STACK *)sk, (OPENSSL_sk_freefunc)freefunc); \ + } \ + static ossl_inline int sk_##t1##_insert(STACK_OF(t1) *sk, t2 *ptr, int idx) \ + { \ + return OPENSSL_sk_insert((OPENSSL_STACK *)sk, (const void *)ptr, idx); \ + } \ + static ossl_inline t2 *sk_##t1##_set(STACK_OF(t1) *sk, int idx, t2 *ptr) \ + { \ + return (t2 *)OPENSSL_sk_set((OPENSSL_STACK *)sk, idx, (const void *)ptr); \ + } \ + static ossl_inline int sk_##t1##_find(STACK_OF(t1) *sk, t2 *ptr) \ + { \ + return OPENSSL_sk_find((OPENSSL_STACK *)sk, (const void *)ptr); \ + } \ + static ossl_inline int sk_##t1##_find_ex(STACK_OF(t1) *sk, t2 *ptr) \ + { \ + return OPENSSL_sk_find_ex((OPENSSL_STACK *)sk, (const void *)ptr); \ + } \ + static ossl_inline void sk_##t1##_sort(STACK_OF(t1) *sk) \ + { \ + OPENSSL_sk_sort((OPENSSL_STACK *)sk); \ + } \ + static ossl_inline int sk_##t1##_is_sorted(const STACK_OF(t1) *sk) \ + { \ + return OPENSSL_sk_is_sorted((const OPENSSL_STACK *)sk); \ + } \ + static ossl_inline STACK_OF(t1) * sk_##t1##_dup(const STACK_OF(t1) *sk) \ + { \ + return (STACK_OF(t1) *)OPENSSL_sk_dup((const OPENSSL_STACK *)sk); \ + } \ + static ossl_inline STACK_OF(t1) *sk_##t1##_deep_copy(const STACK_OF(t1) *sk, \ + sk_##t1##_copyfunc copyfunc, \ + sk_##t1##_freefunc freefunc) \ + { \ + return (STACK_OF(t1) *)OPENSSL_sk_deep_copy((const OPENSSL_STACK *)sk, \ + (OPENSSL_sk_copyfunc)copyfunc, \ + (OPENSSL_sk_freefunc)freefunc); \ + } \ + static ossl_inline sk_##t1##_compfunc sk_##t1##_set_cmp_func(STACK_OF(t1) *sk, sk_##t1##_compfunc compare) \ + { \ + return (sk_##t1##_compfunc)OPENSSL_sk_set_cmp_func((OPENSSL_STACK *)sk, (OPENSSL_sk_compfunc)compare); \ + } + +# define DEFINE_SPECIAL_STACK_OF(t1, t2) SKM_DEFINE_STACK_OF(t1, t2, t2) +# define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t) +# define DEFINE_SPECIAL_STACK_OF_CONST(t1, t2) \ + SKM_DEFINE_STACK_OF(t1, const t2, t2) +# define DEFINE_STACK_OF_CONST(t) SKM_DEFINE_STACK_OF(t, const t, t) + +/*- + * Strings are special: normally an lhash entry will point to a single + * (somewhat) mutable object. In the case of strings: + * + * a) Instead of a single char, there is an array of chars, NUL-terminated. + * b) The string may have be immutable. + * + * So, they need their own declarations. Especially important for + * type-checking tools, such as Deputy. + * + * In practice, however, it appears to be hard to have a const + * string. For now, I'm settling for dealing with the fact it is a + * string at all. + */ +typedef char *OPENSSL_STRING; +typedef const char *OPENSSL_CSTRING; + +/*- + * Confusingly, LHASH_OF(STRING) deals with char ** throughout, but + * STACK_OF(STRING) is really more like STACK_OF(char), only, as mentioned + * above, instead of a single char each entry is a NUL-terminated array of + * chars. So, we have to implement STRING specially for STACK_OF. This is + * dealt with in the autogenerated macros below. + */ +DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char) +DEFINE_SPECIAL_STACK_OF_CONST(OPENSSL_CSTRING, char) + +/* + * Similarly, we sometimes use a block of characters, NOT nul-terminated. + * These should also be distinguished from "normal" stacks. + */ +typedef void *OPENSSL_BLOCK; +DEFINE_SPECIAL_STACK_OF(OPENSSL_BLOCK, void) + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/seed.h b/mobile/ios/FxA/FxA/include/openssl/seed.h new file mode 100644 index 0000000000..bb97131d76 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/seed.h @@ -0,0 +1,98 @@ +/* + * Copyright 2007-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Copyright (c) 2007 KISA(Korea Information Security Agency). All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Neither the name of author nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEADER_SEED_H +# define HEADER_SEED_H + +# include + +# ifndef OPENSSL_NO_SEED +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* look whether we need 'long' to get 32 bits */ +# ifdef AES_LONG +# ifndef SEED_LONG +# define SEED_LONG 1 +# endif +# endif + +# if !defined(NO_SYS_TYPES_H) +# include +# endif + +# define SEED_BLOCK_SIZE 16 +# define SEED_KEY_LENGTH 16 + +typedef struct seed_key_st { +# ifdef SEED_LONG + unsigned long data[32]; +# else + unsigned int data[32]; +# endif +} SEED_KEY_SCHEDULE; + +void SEED_set_key(const unsigned char rawkey[SEED_KEY_LENGTH], + SEED_KEY_SCHEDULE *ks); + +void SEED_encrypt(const unsigned char s[SEED_BLOCK_SIZE], + unsigned char d[SEED_BLOCK_SIZE], + const SEED_KEY_SCHEDULE *ks); +void SEED_decrypt(const unsigned char s[SEED_BLOCK_SIZE], + unsigned char d[SEED_BLOCK_SIZE], + const SEED_KEY_SCHEDULE *ks); + +void SEED_ecb_encrypt(const unsigned char *in, unsigned char *out, + const SEED_KEY_SCHEDULE *ks, int enc); +void SEED_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t len, + const SEED_KEY_SCHEDULE *ks, + unsigned char ivec[SEED_BLOCK_SIZE], int enc); +void SEED_cfb128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const SEED_KEY_SCHEDULE *ks, + unsigned char ivec[SEED_BLOCK_SIZE], int *num, + int enc); +void SEED_ofb128_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const SEED_KEY_SCHEDULE *ks, + unsigned char ivec[SEED_BLOCK_SIZE], int *num); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/sha.h b/mobile/ios/FxA/FxA/include/openssl/sha.h new file mode 100644 index 0000000000..6a1eb0de8b --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/sha.h @@ -0,0 +1,119 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_SHA_H +# define HEADER_SHA_H + +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/*- + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! SHA_LONG has to be at least 32 bits wide. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ +# define SHA_LONG unsigned int + +# define SHA_LBLOCK 16 +# define SHA_CBLOCK (SHA_LBLOCK*4)/* SHA treats input data as a + * contiguous array of 32 bit wide + * big-endian values. */ +# define SHA_LAST_BLOCK (SHA_CBLOCK-8) +# define SHA_DIGEST_LENGTH 20 + +typedef struct SHAstate_st { + SHA_LONG h0, h1, h2, h3, h4; + SHA_LONG Nl, Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num; +} SHA_CTX; + +int SHA1_Init(SHA_CTX *c); +int SHA1_Update(SHA_CTX *c, const void *data, size_t len); +int SHA1_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md); +void SHA1_Transform(SHA_CTX *c, const unsigned char *data); + +# define SHA256_CBLOCK (SHA_LBLOCK*4)/* SHA-256 treats input data as a + * contiguous array of 32 bit wide + * big-endian values. */ + +typedef struct SHA256state_st { + SHA_LONG h[8]; + SHA_LONG Nl, Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num, md_len; +} SHA256_CTX; + +int SHA224_Init(SHA256_CTX *c); +int SHA224_Update(SHA256_CTX *c, const void *data, size_t len); +int SHA224_Final(unsigned char *md, SHA256_CTX *c); +unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md); +int SHA256_Init(SHA256_CTX *c); +int SHA256_Update(SHA256_CTX *c, const void *data, size_t len); +int SHA256_Final(unsigned char *md, SHA256_CTX *c); +unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md); +void SHA256_Transform(SHA256_CTX *c, const unsigned char *data); + +# define SHA224_DIGEST_LENGTH 28 +# define SHA256_DIGEST_LENGTH 32 +# define SHA384_DIGEST_LENGTH 48 +# define SHA512_DIGEST_LENGTH 64 + +/* + * Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64 + * being exactly 64-bit wide. See Implementation Notes in sha512.c + * for further details. + */ +/* + * SHA-512 treats input data as a + * contiguous array of 64 bit + * wide big-endian values. + */ +# define SHA512_CBLOCK (SHA_LBLOCK*8) +# if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) +# define SHA_LONG64 unsigned __int64 +# define U64(C) C##UI64 +# elif defined(__arch64__) +# define SHA_LONG64 unsigned long +# define U64(C) C##UL +# else +# define SHA_LONG64 unsigned long long +# define U64(C) C##ULL +# endif + +typedef struct SHA512state_st { + SHA_LONG64 h[8]; + SHA_LONG64 Nl, Nh; + union { + SHA_LONG64 d[SHA_LBLOCK]; + unsigned char p[SHA512_CBLOCK]; + } u; + unsigned int num, md_len; +} SHA512_CTX; + +int SHA384_Init(SHA512_CTX *c); +int SHA384_Update(SHA512_CTX *c, const void *data, size_t len); +int SHA384_Final(unsigned char *md, SHA512_CTX *c); +unsigned char *SHA384(const unsigned char *d, size_t n, unsigned char *md); +int SHA512_Init(SHA512_CTX *c); +int SHA512_Update(SHA512_CTX *c, const void *data, size_t len); +int SHA512_Final(unsigned char *md, SHA512_CTX *c); +unsigned char *SHA512(const unsigned char *d, size_t n, unsigned char *md); +void SHA512_Transform(SHA512_CTX *c, const unsigned char *data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/srp.h b/mobile/ios/FxA/FxA/include/openssl/srp.h new file mode 100644 index 0000000000..f2b6ec750d --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/srp.h @@ -0,0 +1,131 @@ +/* + * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_SRP_H +# define HEADER_SRP_H + +#include + +#ifndef OPENSSL_NO_SRP +# include +# include +# include +# include +# include + +# ifdef __cplusplus +extern "C" { +# endif + +typedef struct SRP_gN_cache_st { + char *b64_bn; + BIGNUM *bn; +} SRP_gN_cache; + + +DEFINE_STACK_OF(SRP_gN_cache) + +typedef struct SRP_user_pwd_st { + /* Owned by us. */ + char *id; + BIGNUM *s; + BIGNUM *v; + /* Not owned by us. */ + const BIGNUM *g; + const BIGNUM *N; + /* Owned by us. */ + char *info; +} SRP_user_pwd; + +void SRP_user_pwd_free(SRP_user_pwd *user_pwd); + +DEFINE_STACK_OF(SRP_user_pwd) + +typedef struct SRP_VBASE_st { + STACK_OF(SRP_user_pwd) *users_pwd; + STACK_OF(SRP_gN_cache) *gN_cache; +/* to simulate a user */ + char *seed_key; + const BIGNUM *default_g; + const BIGNUM *default_N; +} SRP_VBASE; + +/* + * Internal structure storing N and g pair + */ +typedef struct SRP_gN_st { + char *id; + const BIGNUM *g; + const BIGNUM *N; +} SRP_gN; + +DEFINE_STACK_OF(SRP_gN) + +SRP_VBASE *SRP_VBASE_new(char *seed_key); +void SRP_VBASE_free(SRP_VBASE *vb); +int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file); + +/* This method ignores the configured seed and fails for an unknown user. */ +DEPRECATEDIN_1_1_0(SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username)) +/* NOTE: unlike in SRP_VBASE_get_by_user, caller owns the returned pointer.*/ +SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username); + +char *SRP_create_verifier(const char *user, const char *pass, char **salt, + char **verifier, const char *N, const char *g); +int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, + BIGNUM **verifier, const BIGNUM *N, + const BIGNUM *g); + +# define SRP_NO_ERROR 0 +# define SRP_ERR_VBASE_INCOMPLETE_FILE 1 +# define SRP_ERR_VBASE_BN_LIB 2 +# define SRP_ERR_OPEN_FILE 3 +# define SRP_ERR_MEMORY 4 + +# define DB_srptype 0 +# define DB_srpverifier 1 +# define DB_srpsalt 2 +# define DB_srpid 3 +# define DB_srpgN 4 +# define DB_srpinfo 5 +# undef DB_NUMBER +# define DB_NUMBER 6 + +# define DB_SRP_INDEX 'I' +# define DB_SRP_VALID 'V' +# define DB_SRP_REVOKED 'R' +# define DB_SRP_MODIF 'v' + +/* see srp.c */ +char *SRP_check_known_gN_param(const BIGNUM *g, const BIGNUM *N); +SRP_gN *SRP_get_default_gN(const char *id); + +/* server side .... */ +BIGNUM *SRP_Calc_server_key(const BIGNUM *A, const BIGNUM *v, const BIGNUM *u, + const BIGNUM *b, const BIGNUM *N); +BIGNUM *SRP_Calc_B(const BIGNUM *b, const BIGNUM *N, const BIGNUM *g, + const BIGNUM *v); +int SRP_Verify_A_mod_N(const BIGNUM *A, const BIGNUM *N); +BIGNUM *SRP_Calc_u(const BIGNUM *A, const BIGNUM *B, const BIGNUM *N); + +/* client side .... */ +BIGNUM *SRP_Calc_x(const BIGNUM *s, const char *user, const char *pass); +BIGNUM *SRP_Calc_A(const BIGNUM *a, const BIGNUM *N, const BIGNUM *g); +BIGNUM *SRP_Calc_client_key(const BIGNUM *N, const BIGNUM *B, const BIGNUM *g, + const BIGNUM *x, const BIGNUM *a, const BIGNUM *u); +int SRP_Verify_B_mod_N(const BIGNUM *B, const BIGNUM *N); + +# define SRP_MINIMAL_N 1024 + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/srtp.h b/mobile/ios/FxA/FxA/include/openssl/srtp.h new file mode 100644 index 0000000000..5ddfa46d9b --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/srtp.h @@ -0,0 +1,50 @@ +/* + * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DTLS code by Eric Rescorla + * + * Copyright (C) 2006, Network Resonance, Inc. Copyright (C) 2011, RTFM, Inc. + */ + +#ifndef HEADER_D1_SRTP_H +# define HEADER_D1_SRTP_H + +# include + +#ifdef __cplusplus +extern "C" { +#endif + +# define SRTP_AES128_CM_SHA1_80 0x0001 +# define SRTP_AES128_CM_SHA1_32 0x0002 +# define SRTP_AES128_F8_SHA1_80 0x0003 +# define SRTP_AES128_F8_SHA1_32 0x0004 +# define SRTP_NULL_SHA1_80 0x0005 +# define SRTP_NULL_SHA1_32 0x0006 + +/* AEAD SRTP protection profiles from RFC 7714 */ +# define SRTP_AEAD_AES_128_GCM 0x0007 +# define SRTP_AEAD_AES_256_GCM 0x0008 + +# ifndef OPENSSL_NO_SRTP + +__owur int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles); +__owur int SSL_set_tlsext_use_srtp(SSL *ctx, const char *profiles); + +__owur STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *ssl); +__owur SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s); + +# endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ssl.h b/mobile/ios/FxA/FxA/include/openssl/ssl.h new file mode 100644 index 0000000000..8d75d53eca --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ssl.h @@ -0,0 +1,2531 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef HEADER_SSL_H +# define HEADER_SSL_H + +# include +# include +# include +# include +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# include +# include +# include +# endif +# include +# include +# include + +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* OpenSSL version number for ASN.1 encoding of the session information */ +/*- + * Version 0 - initial version + * Version 1 - added the optional peer certificate + */ +# define SSL_SESSION_ASN1_VERSION 0x0001 + +# define SSL_MAX_SSL_SESSION_ID_LENGTH 32 +# define SSL_MAX_SID_CTX_LENGTH 32 + +# define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES (512/8) +# define SSL_MAX_KEY_ARG_LENGTH 8 +# define SSL_MAX_MASTER_KEY_LENGTH 48 + +/* The maximum number of encrypt/decrypt pipelines we can support */ +# define SSL_MAX_PIPELINES 32 + +/* text strings for the ciphers */ + +/* These are used to specify which ciphers to use and not to use */ + +# define SSL_TXT_LOW "LOW" +# define SSL_TXT_MEDIUM "MEDIUM" +# define SSL_TXT_HIGH "HIGH" +# define SSL_TXT_FIPS "FIPS" + +# define SSL_TXT_aNULL "aNULL" +# define SSL_TXT_eNULL "eNULL" +# define SSL_TXT_NULL "NULL" + +# define SSL_TXT_kRSA "kRSA" +# define SSL_TXT_kDHr "kDHr" +# define SSL_TXT_kDHd "kDHd" +# define SSL_TXT_kDH "kDH" +# define SSL_TXT_kEDH "kEDH"/* alias for kDHE */ +# define SSL_TXT_kDHE "kDHE" +# define SSL_TXT_kECDHr "kECDHr" +# define SSL_TXT_kECDHe "kECDHe" +# define SSL_TXT_kECDH "kECDH" +# define SSL_TXT_kEECDH "kEECDH"/* alias for kECDHE */ +# define SSL_TXT_kECDHE "kECDHE" +# define SSL_TXT_kPSK "kPSK" +# define SSL_TXT_kRSAPSK "kRSAPSK" +# define SSL_TXT_kECDHEPSK "kECDHEPSK" +# define SSL_TXT_kDHEPSK "kDHEPSK" +# define SSL_TXT_kGOST "kGOST" +# define SSL_TXT_kSRP "kSRP" + +# define SSL_TXT_aRSA "aRSA" +# define SSL_TXT_aDSS "aDSS" +# define SSL_TXT_aDH "aDH" +# define SSL_TXT_aECDH "aECDH" +# define SSL_TXT_aECDSA "aECDSA" +# define SSL_TXT_aPSK "aPSK" +# define SSL_TXT_aGOST94 "aGOST94" +# define SSL_TXT_aGOST01 "aGOST01" +# define SSL_TXT_aGOST12 "aGOST12" +# define SSL_TXT_aGOST "aGOST" +# define SSL_TXT_aSRP "aSRP" + +# define SSL_TXT_DSS "DSS" +# define SSL_TXT_DH "DH" +# define SSL_TXT_DHE "DHE"/* same as "kDHE:-ADH" */ +# define SSL_TXT_EDH "EDH"/* alias for DHE */ +# define SSL_TXT_ADH "ADH" +# define SSL_TXT_RSA "RSA" +# define SSL_TXT_ECDH "ECDH" +# define SSL_TXT_EECDH "EECDH"/* alias for ECDHE" */ +# define SSL_TXT_ECDHE "ECDHE"/* same as "kECDHE:-AECDH" */ +# define SSL_TXT_AECDH "AECDH" +# define SSL_TXT_ECDSA "ECDSA" +# define SSL_TXT_PSK "PSK" +# define SSL_TXT_SRP "SRP" + +# define SSL_TXT_DES "DES" +# define SSL_TXT_3DES "3DES" +# define SSL_TXT_RC4 "RC4" +# define SSL_TXT_RC2 "RC2" +# define SSL_TXT_IDEA "IDEA" +# define SSL_TXT_SEED "SEED" +# define SSL_TXT_AES128 "AES128" +# define SSL_TXT_AES256 "AES256" +# define SSL_TXT_AES "AES" +# define SSL_TXT_AES_GCM "AESGCM" +# define SSL_TXT_AES_CCM "AESCCM" +# define SSL_TXT_AES_CCM_8 "AESCCM8" +# define SSL_TXT_CAMELLIA128 "CAMELLIA128" +# define SSL_TXT_CAMELLIA256 "CAMELLIA256" +# define SSL_TXT_CAMELLIA "CAMELLIA" +# define SSL_TXT_CHACHA20 "CHACHA20" +# define SSL_TXT_GOST "GOST89" + +# define SSL_TXT_MD5 "MD5" +# define SSL_TXT_SHA1 "SHA1" +# define SSL_TXT_SHA "SHA"/* same as "SHA1" */ +# define SSL_TXT_GOST94 "GOST94" +# define SSL_TXT_GOST89MAC "GOST89MAC" +# define SSL_TXT_GOST12 "GOST12" +# define SSL_TXT_GOST89MAC12 "GOST89MAC12" +# define SSL_TXT_SHA256 "SHA256" +# define SSL_TXT_SHA384 "SHA384" + +# define SSL_TXT_SSLV3 "SSLv3" +# define SSL_TXT_TLSV1 "TLSv1" +# define SSL_TXT_TLSV1_1 "TLSv1.1" +# define SSL_TXT_TLSV1_2 "TLSv1.2" + +# define SSL_TXT_ALL "ALL" + +/*- + * COMPLEMENTOF* definitions. These identifiers are used to (de-select) + * ciphers normally not being used. + * Example: "RC4" will activate all ciphers using RC4 including ciphers + * without authentication, which would normally disabled by DEFAULT (due + * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT" + * will make sure that it is also disabled in the specific selection. + * COMPLEMENTOF* identifiers are portable between version, as adjustments + * to the default cipher setup will also be included here. + * + * COMPLEMENTOFDEFAULT does not experience the same special treatment that + * DEFAULT gets, as only selection is being done and no sorting as needed + * for DEFAULT. + */ +# define SSL_TXT_CMPALL "COMPLEMENTOFALL" +# define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT" + +/* + * The following cipher list is used by default. It also is substituted when + * an application-defined cipher list string starts with 'DEFAULT'. + */ +# define SSL_DEFAULT_CIPHER_LIST "ALL:!COMPLEMENTOFDEFAULT:!eNULL" +/* + * As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always + * starts with a reasonable order, and all we have to do for DEFAULT is + * throwing out anonymous and unencrypted ciphersuites! (The latter are not + * actually enabled by ALL, but "ALL:RSA" would enable some of them.) + */ + +/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ +# define SSL_SENT_SHUTDOWN 1 +# define SSL_RECEIVED_SHUTDOWN 2 + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +# define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1 +# define SSL_FILETYPE_PEM X509_FILETYPE_PEM + +/* + * This is needed to stop compilers complaining about the 'struct ssl_st *' + * function parameters used to prototype callbacks in SSL_CTX. + */ +typedef struct ssl_st *ssl_crock_st; +typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT; +typedef struct ssl_method_st SSL_METHOD; +typedef struct ssl_cipher_st SSL_CIPHER; +typedef struct ssl_session_st SSL_SESSION; +typedef struct tls_sigalgs_st TLS_SIGALGS; +typedef struct ssl_conf_ctx_st SSL_CONF_CTX; +typedef struct ssl_comp_st SSL_COMP; + +STACK_OF(SSL_CIPHER); +STACK_OF(SSL_COMP); + +/* SRTP protection profiles for use with the use_srtp extension (RFC 5764)*/ +typedef struct srtp_protection_profile_st { + const char *name; + unsigned long id; +} SRTP_PROTECTION_PROFILE; + +DEFINE_STACK_OF(SRTP_PROTECTION_PROFILE) + +typedef int (*tls_session_ticket_ext_cb_fn) (SSL *s, + const unsigned char *data, + int len, void *arg); +typedef int (*tls_session_secret_cb_fn) (SSL *s, void *secret, + int *secret_len, + STACK_OF(SSL_CIPHER) *peer_ciphers, + const SSL_CIPHER **cipher, void *arg); + +/* Typedefs for handling custom extensions */ + +typedef int (*custom_ext_add_cb) (SSL *s, unsigned int ext_type, + const unsigned char **out, + size_t *outlen, int *al, void *add_arg); + +typedef void (*custom_ext_free_cb) (SSL *s, unsigned int ext_type, + const unsigned char *out, void *add_arg); + +typedef int (*custom_ext_parse_cb) (SSL *s, unsigned int ext_type, + const unsigned char *in, + size_t inlen, int *al, void *parse_arg); + +/* Typedef for verification callback */ +typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx); + +/* Allow initial connection to servers that don't support RI */ +# define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004U +/* Removed from OpenSSL 0.9.8q and 1.0.0c */ +/* Dead forever, see CVE-2010-4180. */ +# define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x0U +# define SSL_OP_TLSEXT_PADDING 0x00000010U +# define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x0U +# define SSL_OP_SAFARI_ECDHE_ECDSA_BUG 0x00000040U +/* Ancient SSLeay version, retained for compatibility */ +# define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x0 +# define SSL_OP_TLS_D5_BUG 0x0U +/* Removed from OpenSSL 1.1.0 */ +# define SSL_OP_TLS_BLOCK_PADDING_BUG 0x0U + +/* Hasn't done anything since OpenSSL 0.9.7h, retained for compatibility */ +# define SSL_OP_MSIE_SSLV2_RSA_PADDING 0x0 +/* Refers to ancient SSLREF and SSLv2, retained for compatibility */ +# define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x0 +/* Related to removed SSLv2 */ +# define SSL_OP_MICROSOFT_SESS_ID_BUG 0x0 +# define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x0 + +/* + * Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added in + * OpenSSL 0.9.6d. Usually (depending on the application protocol) the + * workaround is not needed. Unfortunately some broken SSL/TLS + * implementations cannot handle it at all, which is why we include it in + * SSL_OP_ALL. + */ +/* added in 0.9.6e */ +# define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800U + +/* + * SSL_OP_ALL: various bug workarounds that should be rather harmless. This + * used to be 0x000FFFFFL before 0.9.7. + */ +# define SSL_OP_ALL 0x80000BFFU + +/* DTLS options */ +# define SSL_OP_NO_QUERY_MTU 0x00001000U +/* Turn on Cookie Exchange (on relevant for servers) */ +# define SSL_OP_COOKIE_EXCHANGE 0x00002000U +/* Don't use RFC4507 ticket extension */ +# define SSL_OP_NO_TICKET 0x00004000U +# ifndef OPENSSL_NO_DTLS1_METHOD +/* Use Cisco's "speshul" version of DTLS_BAD_VER + * (only with deprecated DTLSv1_client_method()) */ +# define SSL_OP_CISCO_ANYCONNECT 0x00008000U +# endif + +/* As server, disallow session resumption on renegotiation */ +# define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000U +/* Don't use compression even if supported */ +# define SSL_OP_NO_COMPRESSION 0x00020000U +/* Permit unsafe legacy renegotiation */ +# define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000U +/* Does nothing: retained for compatibility */ +# define SSL_OP_SINGLE_ECDH_USE 0x0 +/* Does nothing: retained for compatibility */ +# define SSL_OP_SINGLE_DH_USE 0x0 +/* Does nothing: retained for compatibility */ +# define SSL_OP_EPHEMERAL_RSA 0x0 +/* + * Set on servers to choose the cipher according to the server's preferences + */ +# define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000U +/* + * If set, a server will allow a client to issue a SSLv3.0 version number as + * latest version supported in the premaster secret, even when TLSv1.0 + * (version 3.1) was announced in the client hello. Normally this is + * forbidden to prevent version rollback attacks. + */ +# define SSL_OP_TLS_ROLLBACK_BUG 0x00800000U + +# define SSL_OP_NO_SSLv2 0x00000000U +# define SSL_OP_NO_SSLv3 0x02000000U +# define SSL_OP_NO_TLSv1 0x04000000U +# define SSL_OP_NO_TLSv1_2 0x08000000U +# define SSL_OP_NO_TLSv1_1 0x10000000U + +# define SSL_OP_NO_DTLSv1 0x04000000U +# define SSL_OP_NO_DTLSv1_2 0x08000000U + +# define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv3|\ + SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2) +# define SSL_OP_NO_DTLS_MASK (SSL_OP_NO_DTLSv1|SSL_OP_NO_DTLSv1_2) + + +/* Removed from previous versions */ +# define SSL_OP_PKCS1_CHECK_1 0x0 +# define SSL_OP_PKCS1_CHECK_2 0x0 +# define SSL_OP_NETSCAPE_CA_DN_BUG 0x0 +# define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x0U +/* + * Make server add server-hello extension from early version of cryptopro + * draft, when GOST ciphersuite is negotiated. Required for interoperability + * with CryptoPro CSP 3.x + */ +# define SSL_OP_CRYPTOPRO_TLSEXT_BUG 0x80000000U + +/* + * Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success + * when just a single record has been written): + */ +# define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001U +/* + * Make it possible to retry SSL_write() with changed buffer location (buffer + * contents must stay the same!); this is not the default to avoid the + * misconception that non-blocking SSL_write() behaves like non-blocking + * write(): + */ +# define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002U +/* + * Never bother the application with retries if the transport is blocking: + */ +# define SSL_MODE_AUTO_RETRY 0x00000004U +/* Don't attempt to automatically build certificate chain */ +# define SSL_MODE_NO_AUTO_CHAIN 0x00000008U +/* + * Save RAM by releasing read and write buffers when they're empty. (SSL3 and + * TLS only.) "Released" buffers are put onto a free-list in the context or + * just freed (depending on the context's setting for freelist_max_len). + */ +# define SSL_MODE_RELEASE_BUFFERS 0x00000010U +/* + * Send the current time in the Random fields of the ClientHello and + * ServerHello records for compatibility with hypothetical implementations + * that require it. + */ +# define SSL_MODE_SEND_CLIENTHELLO_TIME 0x00000020U +# define SSL_MODE_SEND_SERVERHELLO_TIME 0x00000040U +/* + * Send TLS_FALLBACK_SCSV in the ClientHello. To be set only by applications + * that reconnect with a downgraded protocol version; see + * draft-ietf-tls-downgrade-scsv-00 for details. DO NOT ENABLE THIS if your + * application attempts a normal handshake. Only use this in explicit + * fallback retries, following the guidance in + * draft-ietf-tls-downgrade-scsv-00. + */ +# define SSL_MODE_SEND_FALLBACK_SCSV 0x00000080U +/* + * Support Asynchronous operation + */ +# define SSL_MODE_ASYNC 0x00000100U + +/* Cert related flags */ +/* + * Many implementations ignore some aspects of the TLS standards such as + * enforcing certificate chain algorithms. When this is set we enforce them. + */ +# define SSL_CERT_FLAG_TLS_STRICT 0x00000001U + +/* Suite B modes, takes same values as certificate verify flags */ +# define SSL_CERT_FLAG_SUITEB_128_LOS_ONLY 0x10000 +/* Suite B 192 bit only mode */ +# define SSL_CERT_FLAG_SUITEB_192_LOS 0x20000 +/* Suite B 128 bit mode allowing 192 bit algorithms */ +# define SSL_CERT_FLAG_SUITEB_128_LOS 0x30000 + +/* Perform all sorts of protocol violations for testing purposes */ +# define SSL_CERT_FLAG_BROKEN_PROTOCOL 0x10000000 + +/* Flags for building certificate chains */ +/* Treat any existing certificates as untrusted CAs */ +# define SSL_BUILD_CHAIN_FLAG_UNTRUSTED 0x1 +/* Don't include root CA in chain */ +# define SSL_BUILD_CHAIN_FLAG_NO_ROOT 0x2 +/* Just check certificates already there */ +# define SSL_BUILD_CHAIN_FLAG_CHECK 0x4 +/* Ignore verification errors */ +# define SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR 0x8 +/* Clear verification errors from queue */ +# define SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR 0x10 + +/* Flags returned by SSL_check_chain */ +/* Certificate can be used with this session */ +# define CERT_PKEY_VALID 0x1 +/* Certificate can also be used for signing */ +# define CERT_PKEY_SIGN 0x2 +/* EE certificate signing algorithm OK */ +# define CERT_PKEY_EE_SIGNATURE 0x10 +/* CA signature algorithms OK */ +# define CERT_PKEY_CA_SIGNATURE 0x20 +/* EE certificate parameters OK */ +# define CERT_PKEY_EE_PARAM 0x40 +/* CA certificate parameters OK */ +# define CERT_PKEY_CA_PARAM 0x80 +/* Signing explicitly allowed as opposed to SHA1 fallback */ +# define CERT_PKEY_EXPLICIT_SIGN 0x100 +/* Client CA issuer names match (always set for server cert) */ +# define CERT_PKEY_ISSUER_NAME 0x200 +/* Cert type matches client types (always set for server cert) */ +# define CERT_PKEY_CERT_TYPE 0x400 +/* Cert chain suitable to Suite B */ +# define CERT_PKEY_SUITEB 0x800 + +# define SSL_CONF_FLAG_CMDLINE 0x1 +# define SSL_CONF_FLAG_FILE 0x2 +# define SSL_CONF_FLAG_CLIENT 0x4 +# define SSL_CONF_FLAG_SERVER 0x8 +# define SSL_CONF_FLAG_SHOW_ERRORS 0x10 +# define SSL_CONF_FLAG_CERTIFICATE 0x20 +# define SSL_CONF_FLAG_REQUIRE_PRIVATE 0x40 +/* Configuration value types */ +# define SSL_CONF_TYPE_UNKNOWN 0x0 +# define SSL_CONF_TYPE_STRING 0x1 +# define SSL_CONF_TYPE_FILE 0x2 +# define SSL_CONF_TYPE_DIR 0x3 +# define SSL_CONF_TYPE_NONE 0x4 + +/* + * Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, they + * cannot be used to clear bits. + */ + +unsigned long SSL_CTX_get_options(const SSL_CTX *ctx); +unsigned long SSL_get_options(const SSL* s); +unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op); +unsigned long SSL_clear_options(SSL *s, unsigned long op); +unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long op); +unsigned long SSL_set_options(SSL *s, unsigned long op); + +# define SSL_CTX_set_mode(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL) +# define SSL_CTX_clear_mode(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL) +# define SSL_CTX_get_mode(ctx) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL) +# define SSL_clear_mode(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL) +# define SSL_set_mode(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL) +# define SSL_get_mode(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL) +# define SSL_set_mtu(ssl, mtu) \ + SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL) +# define DTLS_set_link_mtu(ssl, mtu) \ + SSL_ctrl((ssl),DTLS_CTRL_SET_LINK_MTU,(mtu),NULL) +# define DTLS_get_link_min_mtu(ssl) \ + SSL_ctrl((ssl),DTLS_CTRL_GET_LINK_MIN_MTU,0,NULL) + +# define SSL_get_secure_renegotiation_support(ssl) \ + SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL) + +# ifndef OPENSSL_NO_HEARTBEATS +# define SSL_heartbeat(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_DTLS_EXT_SEND_HEARTBEAT,0,NULL) +# endif + +# define SSL_CTX_set_cert_flags(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_CERT_FLAGS,(op),NULL) +# define SSL_set_cert_flags(s,op) \ + SSL_ctrl((s),SSL_CTRL_CERT_FLAGS,(op),NULL) +# define SSL_CTX_clear_cert_flags(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_CERT_FLAGS,(op),NULL) +# define SSL_clear_cert_flags(s,op) \ + SSL_ctrl((s),SSL_CTRL_CLEAR_CERT_FLAGS,(op),NULL) + +void SSL_CTX_set_msg_callback(SSL_CTX *ctx, + void (*cb) (int write_p, int version, + int content_type, const void *buf, + size_t len, SSL *ssl, void *arg)); +void SSL_set_msg_callback(SSL *ssl, + void (*cb) (int write_p, int version, + int content_type, const void *buf, + size_t len, SSL *ssl, void *arg)); +# define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) +# define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) + +# define SSL_get_extms_support(s) \ + SSL_ctrl((s),SSL_CTRL_GET_EXTMS_SUPPORT,0,NULL) + +# ifndef OPENSSL_NO_SRP + +/* see tls_srp.c */ +__owur int SSL_SRP_CTX_init(SSL *s); +__owur int SSL_CTX_SRP_CTX_init(SSL_CTX *ctx); +int SSL_SRP_CTX_free(SSL *ctx); +int SSL_CTX_SRP_CTX_free(SSL_CTX *ctx); +__owur int SSL_srp_server_param_with_username(SSL *s, int *ad); +__owur int SRP_Calc_A_param(SSL *s); + +# endif + +/* 100k max cert list */ +# define SSL_MAX_CERT_LIST_DEFAULT 1024*100 + +# define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024*20) + +/* + * This callback type is used inside SSL_CTX, SSL, and in the functions that + * set them. It is used to override the generation of SSL/TLS session IDs in + * a server. Return value should be zero on an error, non-zero to proceed. + * Also, callbacks should themselves check if the id they generate is unique + * otherwise the SSL handshake will fail with an error - callbacks can do + * this using the 'ssl' value they're passed by; + * SSL_has_matching_session_id(ssl, id, *id_len) The length value passed in + * is set at the maximum size the session ID can be. In SSLv3/TLSv1 it is 32 + * bytes. The callback can alter this length to be less if desired. It is + * also an error for the callback to set the size to zero. + */ +typedef int (*GEN_SESSION_CB) (const SSL *ssl, unsigned char *id, + unsigned int *id_len); + +# define SSL_SESS_CACHE_OFF 0x0000 +# define SSL_SESS_CACHE_CLIENT 0x0001 +# define SSL_SESS_CACHE_SERVER 0x0002 +# define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER) +# define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080 +/* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */ +# define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100 +# define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200 +# define SSL_SESS_CACHE_NO_INTERNAL \ + (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE) + +LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx); +# define SSL_CTX_sess_number(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL) +# define SSL_CTX_sess_connect(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL) +# define SSL_CTX_sess_connect_good(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL) +# define SSL_CTX_sess_connect_renegotiate(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL) +# define SSL_CTX_sess_accept(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL) +# define SSL_CTX_sess_accept_renegotiate(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL) +# define SSL_CTX_sess_accept_good(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL) +# define SSL_CTX_sess_hits(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL) +# define SSL_CTX_sess_cb_hits(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL) +# define SSL_CTX_sess_misses(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL) +# define SSL_CTX_sess_timeouts(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL) +# define SSL_CTX_sess_cache_full(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL) + +void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, + int (*new_session_cb) (struct ssl_st *ssl, + SSL_SESSION *sess)); +int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx)) (struct ssl_st *ssl, + SSL_SESSION *sess); +void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, + void (*remove_session_cb) (struct ssl_ctx_st + *ctx, + SSL_SESSION + *sess)); +void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx)) (struct ssl_ctx_st *ctx, + SSL_SESSION *sess); +void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, + SSL_SESSION *(*get_session_cb) (struct ssl_st + *ssl, + const unsigned char + *data, int len, + int *copy)); +SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx)) (struct ssl_st *ssl, + const unsigned char *data, + int len, int *copy); +void SSL_CTX_set_info_callback(SSL_CTX *ctx, + void (*cb) (const SSL *ssl, int type, + int val)); +void (*SSL_CTX_get_info_callback(SSL_CTX *ctx)) (const SSL *ssl, int type, + int val); +void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, + int (*client_cert_cb) (SSL *ssl, X509 **x509, + EVP_PKEY **pkey)); +int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx)) (SSL *ssl, X509 **x509, + EVP_PKEY **pkey); +# ifndef OPENSSL_NO_ENGINE +__owur int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e); +# endif +void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, + int (*app_gen_cookie_cb) (SSL *ssl, + unsigned char + *cookie, + unsigned int + *cookie_len)); +void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, + int (*app_verify_cookie_cb) (SSL *ssl, + const unsigned char + *cookie, + unsigned int + cookie_len)); +# ifndef OPENSSL_NO_NEXTPROTONEG +void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s, + int (*cb) (SSL *ssl, + const unsigned char + **out, + unsigned int *outlen, + void *arg), void *arg); +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *s, + int (*cb) (SSL *ssl, + unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg); +void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, + unsigned *len); +# endif + +__owur int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const unsigned char *client, + unsigned int client_len); + +# define OPENSSL_NPN_UNSUPPORTED 0 +# define OPENSSL_NPN_NEGOTIATED 1 +# define OPENSSL_NPN_NO_OVERLAP 2 + +__owur int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, + unsigned int protos_len); +__owur int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos, + unsigned int protos_len); +void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg); +void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, + unsigned int *len); + +# ifndef OPENSSL_NO_PSK +/* + * the maximum length of the buffer given to callbacks containing the + * resulting identity/psk + */ +# define PSK_MAX_IDENTITY_LEN 128 +# define PSK_MAX_PSK_LEN 256 +void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, + unsigned int (*psk_client_callback) (SSL + *ssl, + const + char + *hint, + char + *identity, + unsigned + int + max_identity_len, + unsigned + char + *psk, + unsigned + int + max_psk_len)); +void SSL_set_psk_client_callback(SSL *ssl, + unsigned int (*psk_client_callback) (SSL + *ssl, + const + char + *hint, + char + *identity, + unsigned + int + max_identity_len, + unsigned + char + *psk, + unsigned + int + max_psk_len)); +void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, + unsigned int (*psk_server_callback) (SSL + *ssl, + const + char + *identity, + unsigned + char + *psk, + unsigned + int + max_psk_len)); +void SSL_set_psk_server_callback(SSL *ssl, + unsigned int (*psk_server_callback) (SSL + *ssl, + const + char + *identity, + unsigned + char + *psk, + unsigned + int + max_psk_len)); +__owur int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint); +__owur int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint); +const char *SSL_get_psk_identity_hint(const SSL *s); +const char *SSL_get_psk_identity(const SSL *s); +# endif + +/* Register callbacks to handle custom TLS Extensions for client or server. */ + +__owur int SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx, + unsigned int ext_type); + +__owur int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type, + custom_ext_add_cb add_cb, + custom_ext_free_cb free_cb, + void *add_arg, + custom_ext_parse_cb parse_cb, + void *parse_arg); + +__owur int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned int ext_type, + custom_ext_add_cb add_cb, + custom_ext_free_cb free_cb, + void *add_arg, + custom_ext_parse_cb parse_cb, + void *parse_arg); + +__owur int SSL_extension_supported(unsigned int ext_type); + +# define SSL_NOTHING 1 +# define SSL_WRITING 2 +# define SSL_READING 3 +# define SSL_X509_LOOKUP 4 +# define SSL_ASYNC_PAUSED 5 +# define SSL_ASYNC_NO_JOBS 6 + +/* These will only be used when doing non-blocking IO */ +# define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) +# define SSL_want_read(s) (SSL_want(s) == SSL_READING) +# define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) +# define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP) +# define SSL_want_async(s) (SSL_want(s) == SSL_ASYNC_PAUSED) +# define SSL_want_async_job(s) (SSL_want(s) == SSL_ASYNC_NO_JOBS) + +# define SSL_MAC_FLAG_READ_MAC_STREAM 1 +# define SSL_MAC_FLAG_WRITE_MAC_STREAM 2 + +#ifdef __cplusplus +} +#endif + +# include +# include +# include /* This is mostly sslv3 with a few tweaks */ +# include /* Datagram TLS */ +# include /* Support for the use_srtp extension */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * These need to be after the above set of includes due to a compiler bug + * in VisualStudio 2015 + */ +DEFINE_STACK_OF_CONST(SSL_CIPHER) +DEFINE_STACK_OF(SSL_COMP) + +/* compatibility */ +# define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg)) +# define SSL_get_app_data(s) (SSL_get_ex_data(s,0)) +# define SSL_SESSION_set_app_data(s,a) (SSL_SESSION_set_ex_data(s,0,(char *)a)) +# define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s,0)) +# define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx,0)) +# define SSL_CTX_set_app_data(ctx,arg) (SSL_CTX_set_ex_data(ctx,0,(char *)arg)) +DEPRECATEDIN_1_1_0(void SSL_set_debug(SSL *s, int debug)) + + +/* + * The valid handshake states (one for each type message sent and one for each + * type of message received). There are also two "special" states: + * TLS = TLS or DTLS state + * DTLS = DTLS specific state + * CR/SR = Client Read/Server Read + * CW/SW = Client Write/Server Write + * + * The "special" states are: + * TLS_ST_BEFORE = No handshake has been initiated yet + * TLS_ST_OK = A handshake has been successfully completed + */ +typedef enum { + TLS_ST_BEFORE, + TLS_ST_OK, + DTLS_ST_CR_HELLO_VERIFY_REQUEST, + TLS_ST_CR_SRVR_HELLO, + TLS_ST_CR_CERT, + TLS_ST_CR_CERT_STATUS, + TLS_ST_CR_KEY_EXCH, + TLS_ST_CR_CERT_REQ, + TLS_ST_CR_SRVR_DONE, + TLS_ST_CR_SESSION_TICKET, + TLS_ST_CR_CHANGE, + TLS_ST_CR_FINISHED, + TLS_ST_CW_CLNT_HELLO, + TLS_ST_CW_CERT, + TLS_ST_CW_KEY_EXCH, + TLS_ST_CW_CERT_VRFY, + TLS_ST_CW_CHANGE, + TLS_ST_CW_NEXT_PROTO, + TLS_ST_CW_FINISHED, + TLS_ST_SW_HELLO_REQ, + TLS_ST_SR_CLNT_HELLO, + DTLS_ST_SW_HELLO_VERIFY_REQUEST, + TLS_ST_SW_SRVR_HELLO, + TLS_ST_SW_CERT, + TLS_ST_SW_KEY_EXCH, + TLS_ST_SW_CERT_REQ, + TLS_ST_SW_SRVR_DONE, + TLS_ST_SR_CERT, + TLS_ST_SR_KEY_EXCH, + TLS_ST_SR_CERT_VRFY, + TLS_ST_SR_NEXT_PROTO, + TLS_ST_SR_CHANGE, + TLS_ST_SR_FINISHED, + TLS_ST_SW_SESSION_TICKET, + TLS_ST_SW_CERT_STATUS, + TLS_ST_SW_CHANGE, + TLS_ST_SW_FINISHED +} OSSL_HANDSHAKE_STATE; + +/* + * Most of the following state values are no longer used and are defined to be + * the closest equivalent value in the current state machine code. Not all + * defines have an equivalent and are set to a dummy value (-1). SSL_ST_CONNECT + * and SSL_ST_ACCEPT are still in use in the definition of SSL_CB_ACCEPT_LOOP, + * SSL_CB_ACCEPT_EXIT, SSL_CB_CONNECT_LOOP and SSL_CB_CONNECT_EXIT. + */ + +# define SSL_ST_CONNECT 0x1000 +# define SSL_ST_ACCEPT 0x2000 + +# define SSL_ST_MASK 0x0FFF + +# define SSL_CB_LOOP 0x01 +# define SSL_CB_EXIT 0x02 +# define SSL_CB_READ 0x04 +# define SSL_CB_WRITE 0x08 +# define SSL_CB_ALERT 0x4000/* used in callback */ +# define SSL_CB_READ_ALERT (SSL_CB_ALERT|SSL_CB_READ) +# define SSL_CB_WRITE_ALERT (SSL_CB_ALERT|SSL_CB_WRITE) +# define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT|SSL_CB_LOOP) +# define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT|SSL_CB_EXIT) +# define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT|SSL_CB_LOOP) +# define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT|SSL_CB_EXIT) +# define SSL_CB_HANDSHAKE_START 0x10 +# define SSL_CB_HANDSHAKE_DONE 0x20 + +/* Is the SSL_connection established? */ +# define SSL_in_connect_init(a) (SSL_in_init(a) && !SSL_is_server(a)) +# define SSL_in_accept_init(a) (SSL_in_init(a) && SSL_is_server(a)) +int SSL_in_init(SSL *s); +int SSL_in_before(SSL *s); +int SSL_is_init_finished(SSL *s); + +/* + * The following 3 states are kept in ssl->rlayer.rstate when reads fail, you + * should not need these + */ +# define SSL_ST_READ_HEADER 0xF0 +# define SSL_ST_READ_BODY 0xF1 +# define SSL_ST_READ_DONE 0xF2 + +/*- + * Obtain latest Finished message + * -- that we sent (SSL_get_finished) + * -- that we expected from peer (SSL_get_peer_finished). + * Returns length (0 == no Finished so far), copies up to 'count' bytes. + */ +size_t SSL_get_finished(const SSL *s, void *buf, size_t count); +size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count); + +/* + * use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options are + * 'ored' with SSL_VERIFY_PEER if they are desired + */ +# define SSL_VERIFY_NONE 0x00 +# define SSL_VERIFY_PEER 0x01 +# define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +# define SSL_VERIFY_CLIENT_ONCE 0x04 + +# define OpenSSL_add_ssl_algorithms() SSL_library_init() +# if OPENSSL_API_COMPAT < 0x10100000L +# define SSLeay_add_ssl_algorithms() SSL_library_init() +# endif + +/* More backward compatibility */ +# define SSL_get_cipher(s) \ + SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +# define SSL_get_cipher_bits(s,np) \ + SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np) +# define SSL_get_cipher_version(s) \ + SSL_CIPHER_get_version(SSL_get_current_cipher(s)) +# define SSL_get_cipher_name(s) \ + SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +# define SSL_get_time(a) SSL_SESSION_get_time(a) +# define SSL_set_time(a,b) SSL_SESSION_set_time((a),(b)) +# define SSL_get_timeout(a) SSL_SESSION_get_timeout(a) +# define SSL_set_timeout(a,b) SSL_SESSION_set_timeout((a),(b)) + +# define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id) +# define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id) + +DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) +# define SSL_AD_REASON_OFFSET 1000/* offset to get SSL_R_... value + * from SSL_AD_... */ +/* These alert types are for SSLv3 and TLSv1 */ +# define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY +/* fatal */ +# define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE +/* fatal */ +# define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC +# define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED +# define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW +/* fatal */ +# define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE +/* fatal */ +# define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE +/* Not for TLS */ +# define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE +# define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE +# define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE +# define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED +# define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED +# define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN +/* fatal */ +# define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER +/* fatal */ +# define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA +/* fatal */ +# define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED +/* fatal */ +# define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR +# define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR +/* fatal */ +# define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION +/* fatal */ +# define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION +/* fatal */ +# define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY +/* fatal */ +# define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR +# define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED +# define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION +# define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION +# define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE +# define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME +# define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE +# define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE +/* fatal */ +# define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY +/* fatal */ +# define SSL_AD_INAPPROPRIATE_FALLBACK TLS1_AD_INAPPROPRIATE_FALLBACK +# define SSL_AD_NO_APPLICATION_PROTOCOL TLS1_AD_NO_APPLICATION_PROTOCOL +# define SSL_ERROR_NONE 0 +# define SSL_ERROR_SSL 1 +# define SSL_ERROR_WANT_READ 2 +# define SSL_ERROR_WANT_WRITE 3 +# define SSL_ERROR_WANT_X509_LOOKUP 4 +# define SSL_ERROR_SYSCALL 5/* look at error stack/return + * value/errno */ +# define SSL_ERROR_ZERO_RETURN 6 +# define SSL_ERROR_WANT_CONNECT 7 +# define SSL_ERROR_WANT_ACCEPT 8 +# define SSL_ERROR_WANT_ASYNC 9 +# define SSL_ERROR_WANT_ASYNC_JOB 10 +# define SSL_CTRL_SET_TMP_DH 3 +# define SSL_CTRL_SET_TMP_ECDH 4 +# define SSL_CTRL_SET_TMP_DH_CB 6 +# define SSL_CTRL_GET_CLIENT_CERT_REQUEST 9 +# define SSL_CTRL_GET_NUM_RENEGOTIATIONS 10 +# define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11 +# define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12 +# define SSL_CTRL_GET_FLAGS 13 +# define SSL_CTRL_EXTRA_CHAIN_CERT 14 +# define SSL_CTRL_SET_MSG_CALLBACK 15 +# define SSL_CTRL_SET_MSG_CALLBACK_ARG 16 +/* only applies to datagram connections */ +# define SSL_CTRL_SET_MTU 17 +/* Stats */ +# define SSL_CTRL_SESS_NUMBER 20 +# define SSL_CTRL_SESS_CONNECT 21 +# define SSL_CTRL_SESS_CONNECT_GOOD 22 +# define SSL_CTRL_SESS_CONNECT_RENEGOTIATE 23 +# define SSL_CTRL_SESS_ACCEPT 24 +# define SSL_CTRL_SESS_ACCEPT_GOOD 25 +# define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE 26 +# define SSL_CTRL_SESS_HIT 27 +# define SSL_CTRL_SESS_CB_HIT 28 +# define SSL_CTRL_SESS_MISSES 29 +# define SSL_CTRL_SESS_TIMEOUTS 30 +# define SSL_CTRL_SESS_CACHE_FULL 31 +# define SSL_CTRL_MODE 33 +# define SSL_CTRL_GET_READ_AHEAD 40 +# define SSL_CTRL_SET_READ_AHEAD 41 +# define SSL_CTRL_SET_SESS_CACHE_SIZE 42 +# define SSL_CTRL_GET_SESS_CACHE_SIZE 43 +# define SSL_CTRL_SET_SESS_CACHE_MODE 44 +# define SSL_CTRL_GET_SESS_CACHE_MODE 45 +# define SSL_CTRL_GET_MAX_CERT_LIST 50 +# define SSL_CTRL_SET_MAX_CERT_LIST 51 +# define SSL_CTRL_SET_MAX_SEND_FRAGMENT 52 +/* see tls1.h for macros based on these */ +# define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53 +# define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54 +# define SSL_CTRL_SET_TLSEXT_HOSTNAME 55 +# define SSL_CTRL_SET_TLSEXT_DEBUG_CB 56 +# define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57 +# define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58 +# define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59 +/*# define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60 */ +/*# define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61 */ +/*# define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62 */ +# define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63 +# define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64 +# define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65 +# define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66 +# define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67 +# define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68 +# define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69 +# define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70 +# define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71 +# define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72 +# define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB 75 +# define SSL_CTRL_SET_SRP_VERIFY_PARAM_CB 76 +# define SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB 77 +# define SSL_CTRL_SET_SRP_ARG 78 +# define SSL_CTRL_SET_TLS_EXT_SRP_USERNAME 79 +# define SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH 80 +# define SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD 81 +# ifndef OPENSSL_NO_HEARTBEATS +# define SSL_CTRL_DTLS_EXT_SEND_HEARTBEAT 85 +# define SSL_CTRL_GET_DTLS_EXT_HEARTBEAT_PENDING 86 +# define SSL_CTRL_SET_DTLS_EXT_HEARTBEAT_NO_REQUESTS 87 +# endif +# define DTLS_CTRL_GET_TIMEOUT 73 +# define DTLS_CTRL_HANDLE_TIMEOUT 74 +# define SSL_CTRL_GET_RI_SUPPORT 76 +# define SSL_CTRL_CLEAR_MODE 78 +# define SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB 79 +# define SSL_CTRL_GET_EXTRA_CHAIN_CERTS 82 +# define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS 83 +# define SSL_CTRL_CHAIN 88 +# define SSL_CTRL_CHAIN_CERT 89 +# define SSL_CTRL_GET_CURVES 90 +# define SSL_CTRL_SET_CURVES 91 +# define SSL_CTRL_SET_CURVES_LIST 92 +# define SSL_CTRL_GET_SHARED_CURVE 93 +# define SSL_CTRL_SET_SIGALGS 97 +# define SSL_CTRL_SET_SIGALGS_LIST 98 +# define SSL_CTRL_CERT_FLAGS 99 +# define SSL_CTRL_CLEAR_CERT_FLAGS 100 +# define SSL_CTRL_SET_CLIENT_SIGALGS 101 +# define SSL_CTRL_SET_CLIENT_SIGALGS_LIST 102 +# define SSL_CTRL_GET_CLIENT_CERT_TYPES 103 +# define SSL_CTRL_SET_CLIENT_CERT_TYPES 104 +# define SSL_CTRL_BUILD_CERT_CHAIN 105 +# define SSL_CTRL_SET_VERIFY_CERT_STORE 106 +# define SSL_CTRL_SET_CHAIN_CERT_STORE 107 +# define SSL_CTRL_GET_PEER_SIGNATURE_NID 108 +# define SSL_CTRL_GET_SERVER_TMP_KEY 109 +# define SSL_CTRL_GET_RAW_CIPHERLIST 110 +# define SSL_CTRL_GET_EC_POINT_FORMATS 111 +# define SSL_CTRL_GET_CHAIN_CERTS 115 +# define SSL_CTRL_SELECT_CURRENT_CERT 116 +# define SSL_CTRL_SET_CURRENT_CERT 117 +# define SSL_CTRL_SET_DH_AUTO 118 +# define DTLS_CTRL_SET_LINK_MTU 120 +# define DTLS_CTRL_GET_LINK_MIN_MTU 121 +# define SSL_CTRL_GET_EXTMS_SUPPORT 122 +# define SSL_CTRL_SET_MIN_PROTO_VERSION 123 +# define SSL_CTRL_SET_MAX_PROTO_VERSION 124 +# define SSL_CTRL_SET_SPLIT_SEND_FRAGMENT 125 +# define SSL_CTRL_SET_MAX_PIPELINES 126 +# define SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE 127 +# define SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB 128 +# define SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB_ARG 129 +# define SSL_CERT_SET_FIRST 1 +# define SSL_CERT_SET_NEXT 2 +# define SSL_CERT_SET_SERVER 3 +# define DTLSv1_get_timeout(ssl, arg) \ + SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg) +# define DTLSv1_handle_timeout(ssl) \ + SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL) +# define SSL_num_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL) +# define SSL_clear_num_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL) +# define SSL_total_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL) +# define SSL_CTX_set_tmp_dh(ctx,dh) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh) +# define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) +# define SSL_CTX_set_dh_auto(ctx, onoff) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_DH_AUTO,onoff,NULL) +# define SSL_set_dh_auto(s, onoff) \ + SSL_ctrl(s,SSL_CTRL_SET_DH_AUTO,onoff,NULL) +# define SSL_set_tmp_dh(ssl,dh) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh) +# define SSL_set_tmp_ecdh(ssl,ecdh) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) +# define SSL_CTX_add_extra_chain_cert(ctx,x509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509) +# define SSL_CTX_get_extra_chain_certs(ctx,px509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_EXTRA_CHAIN_CERTS,0,px509) +# define SSL_CTX_get_extra_chain_certs_only(ctx,px509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_EXTRA_CHAIN_CERTS,1,px509) +# define SSL_CTX_clear_extra_chain_certs(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS,0,NULL) +# define SSL_CTX_set0_chain(ctx,sk) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN,0,(char *)sk) +# define SSL_CTX_set1_chain(ctx,sk) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN,1,(char *)sk) +# define SSL_CTX_add0_chain_cert(ctx,x509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)x509) +# define SSL_CTX_add1_chain_cert(ctx,x509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_CHAIN_CERT,1,(char *)x509) +# define SSL_CTX_get0_chain_certs(ctx,px509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_CHAIN_CERTS,0,px509) +# define SSL_CTX_clear_chain_certs(ctx) \ + SSL_CTX_set0_chain(ctx,NULL) +# define SSL_CTX_build_cert_chain(ctx, flags) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_BUILD_CERT_CHAIN, flags, NULL) +# define SSL_CTX_select_current_cert(ctx,x509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SELECT_CURRENT_CERT,0,(char *)x509) +# define SSL_CTX_set_current_cert(ctx, op) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CURRENT_CERT, op, NULL) +# define SSL_CTX_set0_verify_cert_store(ctx,st) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)st) +# define SSL_CTX_set1_verify_cert_store(ctx,st) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,1,(char *)st) +# define SSL_CTX_set0_chain_cert_store(ctx,st) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CHAIN_CERT_STORE,0,(char *)st) +# define SSL_CTX_set1_chain_cert_store(ctx,st) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)st) +# define SSL_set0_chain(ctx,sk) \ + SSL_ctrl(ctx,SSL_CTRL_CHAIN,0,(char *)sk) +# define SSL_set1_chain(ctx,sk) \ + SSL_ctrl(ctx,SSL_CTRL_CHAIN,1,(char *)sk) +# define SSL_add0_chain_cert(ctx,x509) \ + SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)x509) +# define SSL_add1_chain_cert(ctx,x509) \ + SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,1,(char *)x509) +# define SSL_get0_chain_certs(ctx,px509) \ + SSL_ctrl(ctx,SSL_CTRL_GET_CHAIN_CERTS,0,px509) +# define SSL_clear_chain_certs(ctx) \ + SSL_set0_chain(ctx,NULL) +# define SSL_build_cert_chain(s, flags) \ + SSL_ctrl(s,SSL_CTRL_BUILD_CERT_CHAIN, flags, NULL) +# define SSL_select_current_cert(ctx,x509) \ + SSL_ctrl(ctx,SSL_CTRL_SELECT_CURRENT_CERT,0,(char *)x509) +# define SSL_set_current_cert(ctx,op) \ + SSL_ctrl(ctx,SSL_CTRL_SET_CURRENT_CERT, op, NULL) +# define SSL_set0_verify_cert_store(s,st) \ + SSL_ctrl(s,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)st) +# define SSL_set1_verify_cert_store(s,st) \ + SSL_ctrl(s,SSL_CTRL_SET_VERIFY_CERT_STORE,1,(char *)st) +# define SSL_set0_chain_cert_store(s,st) \ + SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,0,(char *)st) +# define SSL_set1_chain_cert_store(s,st) \ + SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)st) +# define SSL_get1_curves(ctx, s) \ + SSL_ctrl(ctx,SSL_CTRL_GET_CURVES,0,(char *)s) +# define SSL_CTX_set1_curves(ctx, clist, clistlen) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CURVES,clistlen,(char *)clist) +# define SSL_CTX_set1_curves_list(ctx, s) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CURVES_LIST,0,(char *)s) +# define SSL_set1_curves(ctx, clist, clistlen) \ + SSL_ctrl(ctx,SSL_CTRL_SET_CURVES,clistlen,(char *)clist) +# define SSL_set1_curves_list(ctx, s) \ + SSL_ctrl(ctx,SSL_CTRL_SET_CURVES_LIST,0,(char *)s) +# define SSL_get_shared_curve(s, n) \ + SSL_ctrl(s,SSL_CTRL_GET_SHARED_CURVE,n,NULL) +# define SSL_CTX_set1_sigalgs(ctx, slist, slistlen) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SIGALGS,slistlen,(int *)slist) +# define SSL_CTX_set1_sigalgs_list(ctx, s) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SIGALGS_LIST,0,(char *)s) +# define SSL_set1_sigalgs(ctx, slist, slistlen) \ + SSL_ctrl(ctx,SSL_CTRL_SET_SIGALGS,slistlen,(int *)slist) +# define SSL_set1_sigalgs_list(ctx, s) \ + SSL_ctrl(ctx,SSL_CTRL_SET_SIGALGS_LIST,0,(char *)s) +# define SSL_CTX_set1_client_sigalgs(ctx, slist, slistlen) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS,slistlen,(int *)slist) +# define SSL_CTX_set1_client_sigalgs_list(ctx, s) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS_LIST,0,(char *)s) +# define SSL_set1_client_sigalgs(ctx, slist, slistlen) \ + SSL_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS,clistlen,(int *)slist) +# define SSL_set1_client_sigalgs_list(ctx, s) \ + SSL_ctrl(ctx,SSL_CTRL_SET_CLIENT_SIGALGS_LIST,0,(char *)s) +# define SSL_get0_certificate_types(s, clist) \ + SSL_ctrl(s, SSL_CTRL_GET_CLIENT_CERT_TYPES, 0, (char *)clist) +# define SSL_CTX_set1_client_certificate_types(ctx, clist, clistlen) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CLIENT_CERT_TYPES,clistlen,(char *)clist) +# define SSL_set1_client_certificate_types(s, clist, clistlen) \ + SSL_ctrl(s,SSL_CTRL_SET_CLIENT_CERT_TYPES,clistlen,(char *)clist) +# define SSL_get_peer_signature_nid(s, pn) \ + SSL_ctrl(s,SSL_CTRL_GET_PEER_SIGNATURE_NID,0,pn) +# define SSL_get_server_tmp_key(s, pk) \ + SSL_ctrl(s,SSL_CTRL_GET_SERVER_TMP_KEY,0,pk) +# define SSL_get0_raw_cipherlist(s, plst) \ + SSL_ctrl(s,SSL_CTRL_GET_RAW_CIPHERLIST,0,plst) +# define SSL_get0_ec_point_formats(s, plst) \ + SSL_ctrl(s,SSL_CTRL_GET_EC_POINT_FORMATS,0,plst) +#define SSL_CTX_set_min_proto_version(ctx, version) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL) +#define SSL_CTX_set_max_proto_version(ctx, version) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL) +#define SSL_set_min_proto_version(s, version) \ + SSL_ctrl(s, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL) +#define SSL_set_max_proto_version(s, version) \ + SSL_ctrl(s, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL) + +#if OPENSSL_API_COMPAT < 0x10100000L +/* Provide some compatibility macros for removed functionality. */ +# define SSL_CTX_need_tmp_RSA(ctx) 0 +# define SSL_CTX_set_tmp_rsa(ctx,rsa) 1 +# define SSL_need_tmp_RSA(ssl) 0 +# define SSL_set_tmp_rsa(ssl,rsa) 1 +# define SSL_CTX_set_ecdh_auto(dummy, onoff) ((onoff) != 0) +# define SSL_set_ecdh_auto(dummy, onoff) ((onoff) != 0) +/* + * We "pretend" to call the callback to avoid warnings about unused static + * functions. + */ +# define SSL_CTX_set_tmp_rsa_callback(ctx, cb) while(0) (cb)(NULL, 0, 0) +# define SSL_set_tmp_rsa_callback(ssl, cb) while(0) (cb)(NULL, 0, 0) +#endif + +__owur const BIO_METHOD *BIO_f_ssl(void); +__owur BIO *BIO_new_ssl(SSL_CTX *ctx, int client); +__owur BIO *BIO_new_ssl_connect(SSL_CTX *ctx); +__owur BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx); +__owur int BIO_ssl_copy_session_id(BIO *to, BIO *from); +void BIO_ssl_shutdown(BIO *ssl_bio); + +__owur int SSL_CTX_set_cipher_list(SSL_CTX *, const char *str); +__owur SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth); +int SSL_CTX_up_ref(SSL_CTX *ctx); +void SSL_CTX_free(SSL_CTX *); +__owur long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); +__owur long SSL_CTX_get_timeout(const SSL_CTX *ctx); +__owur X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); +void SSL_CTX_set_cert_store(SSL_CTX *, X509_STORE *); +__owur int SSL_want(const SSL *s); +__owur int SSL_clear(SSL *s); + +void SSL_CTX_flush_sessions(SSL_CTX *ctx, long tm); + +__owur const SSL_CIPHER *SSL_get_current_cipher(const SSL *s); +__owur int SSL_CIPHER_get_bits(const SSL_CIPHER *c, int *alg_bits); +__owur const char *SSL_CIPHER_get_version(const SSL_CIPHER *c); +__owur const char *SSL_CIPHER_get_name(const SSL_CIPHER *c); +__owur uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c); +__owur int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c); +__owur int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c); +__owur int SSL_CIPHER_is_aead(const SSL_CIPHER *c); + +__owur int SSL_get_fd(const SSL *s); +__owur int SSL_get_rfd(const SSL *s); +__owur int SSL_get_wfd(const SSL *s); +__owur const char *SSL_get_cipher_list(const SSL *s, int n); +__owur char *SSL_get_shared_ciphers(const SSL *s, char *buf, int len); +__owur int SSL_get_read_ahead(const SSL *s); +__owur int SSL_pending(const SSL *s); +__owur int SSL_has_pending(const SSL *s); +# ifndef OPENSSL_NO_SOCK +__owur int SSL_set_fd(SSL *s, int fd); +__owur int SSL_set_rfd(SSL *s, int fd); +__owur int SSL_set_wfd(SSL *s, int fd); +# endif +void SSL_set0_rbio(SSL *s, BIO *rbio); +void SSL_set0_wbio(SSL *s, BIO *wbio); +void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio); +__owur BIO *SSL_get_rbio(const SSL *s); +__owur BIO *SSL_get_wbio(const SSL *s); +__owur int SSL_set_cipher_list(SSL *s, const char *str); +void SSL_set_read_ahead(SSL *s, int yes); +__owur int SSL_get_verify_mode(const SSL *s); +__owur int SSL_get_verify_depth(const SSL *s); +__owur SSL_verify_cb SSL_get_verify_callback(const SSL *s); +void SSL_set_verify(SSL *s, int mode, SSL_verify_cb callback); +void SSL_set_verify_depth(SSL *s, int depth); +void SSL_set_cert_cb(SSL *s, int (*cb) (SSL *ssl, void *arg), void *arg); +# ifndef OPENSSL_NO_RSA +__owur int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa); +__owur int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const unsigned char *d, long len); +# endif +__owur int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey); +__owur int SSL_use_PrivateKey_ASN1(int pk, SSL *ssl, const unsigned char *d, + long len); +__owur int SSL_use_certificate(SSL *ssl, X509 *x); +__owur int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len); + +/* Set serverinfo data for the current active cert. */ +__owur int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo, + size_t serverinfo_length); +__owur int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file); + +#ifndef OPENSSL_NO_RSA +__owur int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type); +#endif + +__owur int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type); +__owur int SSL_use_certificate_file(SSL *ssl, const char *file, int type); + +#ifndef OPENSSL_NO_RSA +__owur int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); +#endif +__owur int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); +__owur int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); +/* PEM type */ +__owur int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); +__owur int SSL_use_certificate_chain_file(SSL *ssl, const char *file); +__owur STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file); +__owur int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs, + const char *file); +int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs, + const char *dir); + +#if OPENSSL_API_COMPAT < 0x10100000L +# define SSL_load_error_strings() \ + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \ + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL) +#endif + +__owur const char *SSL_state_string(const SSL *s); +__owur const char *SSL_rstate_string(const SSL *s); +__owur const char *SSL_state_string_long(const SSL *s); +__owur const char *SSL_rstate_string_long(const SSL *s); +__owur long SSL_SESSION_get_time(const SSL_SESSION *s); +__owur long SSL_SESSION_set_time(SSL_SESSION *s, long t); +__owur long SSL_SESSION_get_timeout(const SSL_SESSION *s); +__owur long SSL_SESSION_set_timeout(SSL_SESSION *s, long t); +__owur int SSL_SESSION_get_protocol_version(const SSL_SESSION *s); +__owur const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s); +__owur const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *s); +__owur int SSL_SESSION_has_ticket(const SSL_SESSION *s); +__owur unsigned long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *s); +void SSL_SESSION_get0_ticket(const SSL_SESSION *s, const unsigned char **tick, + size_t *len); +__owur int SSL_copy_session_id(SSL *to, const SSL *from); +__owur X509 *SSL_SESSION_get0_peer(SSL_SESSION *s); +__owur int SSL_SESSION_set1_id_context(SSL_SESSION *s, const unsigned char *sid_ctx, + unsigned int sid_ctx_len); +__owur int SSL_SESSION_set1_id(SSL_SESSION *s, const unsigned char *sid, + unsigned int sid_len); + +__owur SSL_SESSION *SSL_SESSION_new(void); +const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, + unsigned int *len); +const unsigned char *SSL_SESSION_get0_id_context(const SSL_SESSION *s, + unsigned int *len); +__owur unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s); +# ifndef OPENSSL_NO_STDIO +int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *ses); +# endif +int SSL_SESSION_print(BIO *fp, const SSL_SESSION *ses); +int SSL_SESSION_print_keylog(BIO *bp, const SSL_SESSION *x); +int SSL_SESSION_up_ref(SSL_SESSION *ses); +void SSL_SESSION_free(SSL_SESSION *ses); +__owur int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp); +__owur int SSL_set_session(SSL *to, SSL_SESSION *session); +__owur int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c); +int SSL_CTX_remove_session(SSL_CTX *, SSL_SESSION *c); +__owur int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB); +__owur int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB); +__owur int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, + unsigned int id_len); +SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, + long length); + +# ifdef HEADER_X509_H +__owur X509 *SSL_get_peer_certificate(const SSL *s); +# endif + +__owur STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s); + +__owur int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); +__owur int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); +__owur SSL_verify_cb SSL_CTX_get_verify_callback(const SSL_CTX *ctx); +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, SSL_verify_cb callback); +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); +void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, + int (*cb) (X509_STORE_CTX *, void *), + void *arg); +void SSL_CTX_set_cert_cb(SSL_CTX *c, int (*cb) (SSL *ssl, void *arg), + void *arg); +# ifndef OPENSSL_NO_RSA +__owur int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); +__owur int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, + long len); +# endif +__owur int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); +__owur int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, + const unsigned char *d, long len); +__owur int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); +__owur int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d); + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb); +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u); +pem_password_cb *SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx); +void *SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx); +void SSL_set_default_passwd_cb(SSL *s, pem_password_cb *cb); +void SSL_set_default_passwd_cb_userdata(SSL *s, void *u); +pem_password_cb *SSL_get_default_passwd_cb(SSL *s); +void *SSL_get_default_passwd_cb_userdata(SSL *s); + +__owur int SSL_CTX_check_private_key(const SSL_CTX *ctx); +__owur int SSL_check_private_key(const SSL *ctx); + +__owur int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len); + +SSL *SSL_new(SSL_CTX *ctx); +int SSL_up_ref(SSL *s); +int SSL_is_dtls(const SSL *s); +__owur int SSL_set_session_id_context(SSL *ssl, const unsigned char *sid_ctx, + unsigned int sid_ctx_len); + +__owur int SSL_CTX_set_purpose(SSL_CTX *s, int purpose); +__owur int SSL_set_purpose(SSL *s, int purpose); +__owur int SSL_CTX_set_trust(SSL_CTX *s, int trust); +__owur int SSL_set_trust(SSL *s, int trust); + +__owur int SSL_set1_host(SSL *s, const char *hostname); +__owur int SSL_add1_host(SSL *s, const char *hostname); +__owur const char *SSL_get0_peername(SSL *s); +void SSL_set_hostflags(SSL *s, unsigned int flags); + +__owur int SSL_CTX_dane_enable(SSL_CTX *ctx); +__owur int SSL_CTX_dane_mtype_set(SSL_CTX *ctx, const EVP_MD *md, + uint8_t mtype, uint8_t ord); +__owur int SSL_dane_enable(SSL *s, const char *basedomain); +__owur int SSL_dane_tlsa_add(SSL *s, uint8_t usage, uint8_t selector, + uint8_t mtype, unsigned char *data, size_t dlen); +__owur int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki); +__owur int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector, + uint8_t *mtype, unsigned const char **data, + size_t *dlen); +/* + * Bridge opacity barrier between libcrypt and libssl, also needed to support + * offline testing in test/danetest.c + */ +SSL_DANE *SSL_get0_dane(SSL *ssl); +/* + * DANE flags + */ +unsigned long SSL_CTX_dane_set_flags(SSL_CTX *ctx, unsigned long flags); +unsigned long SSL_CTX_dane_clear_flags(SSL_CTX *ctx, unsigned long flags); +unsigned long SSL_dane_set_flags(SSL *ssl, unsigned long flags); +unsigned long SSL_dane_clear_flags(SSL *ssl, unsigned long flags); + +__owur int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm); +__owur int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm); + +__owur X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx); +__owur X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl); + +# ifndef OPENSSL_NO_SRP +int SSL_CTX_set_srp_username(SSL_CTX *ctx, char *name); +int SSL_CTX_set_srp_password(SSL_CTX *ctx, char *password); +int SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength); +int SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx, + char *(*cb) (SSL *, void *)); +int SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx, + int (*cb) (SSL *, void *)); +int SSL_CTX_set_srp_username_callback(SSL_CTX *ctx, + int (*cb) (SSL *, int *, void *)); +int SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg); + +int SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g, + BIGNUM *sa, BIGNUM *v, char *info); +int SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass, + const char *grp); + +__owur BIGNUM *SSL_get_srp_g(SSL *s); +__owur BIGNUM *SSL_get_srp_N(SSL *s); + +__owur char *SSL_get_srp_username(SSL *s); +__owur char *SSL_get_srp_userinfo(SSL *s); +# endif + +void SSL_certs_clear(SSL *s); +void SSL_free(SSL *ssl); +# ifdef OSSL_ASYNC_FD +/* + * Windows application developer has to include windows.h to use these. + */ +__owur int SSL_waiting_for_async(SSL *s); +__owur int SSL_get_all_async_fds(SSL *s, OSSL_ASYNC_FD *fds, size_t *numfds); +__owur int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd, + size_t *numaddfds, OSSL_ASYNC_FD *delfd, + size_t *numdelfds); +# endif +__owur int SSL_accept(SSL *ssl); +__owur int SSL_connect(SSL *ssl); +__owur int SSL_read(SSL *ssl, void *buf, int num); +__owur int SSL_peek(SSL *ssl, void *buf, int num); +__owur int SSL_write(SSL *ssl, const void *buf, int num); +long SSL_ctrl(SSL *ssl, int cmd, long larg, void *parg); +long SSL_callback_ctrl(SSL *, int, void (*)(void)); +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); +long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void)); + +__owur int SSL_get_error(const SSL *s, int ret_code); +__owur const char *SSL_get_version(const SSL *s); + +/* This sets the 'default' SSL version that SSL_new() will create */ +__owur int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); + +# ifndef OPENSSL_NO_SSL3_METHOD +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *SSLv3_method(void)) /* SSLv3 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *SSLv3_server_method(void)) /* SSLv3 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *SSLv3_client_method(void)) /* SSLv3 */ +# endif + +#define SSLv23_method TLS_method +#define SSLv23_server_method TLS_server_method +#define SSLv23_client_method TLS_client_method + +/* Negotiate highest available SSL/TLS version */ +__owur const SSL_METHOD *TLS_method(void); +__owur const SSL_METHOD *TLS_server_method(void); +__owur const SSL_METHOD *TLS_client_method(void); + +# ifndef OPENSSL_NO_TLS1_METHOD +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_method(void)) /* TLSv1.0 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_server_method(void)) /* TLSv1.0 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_client_method(void)) /* TLSv1.0 */ +# endif + +# ifndef OPENSSL_NO_TLS1_1_METHOD +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_1_method(void)) /* TLSv1.1 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_1_server_method(void)) /* TLSv1.1 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_1_client_method(void)) /* TLSv1.1 */ +# endif + +# ifndef OPENSSL_NO_TLS1_2_METHOD +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_2_method(void)) /* TLSv1.2 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_2_server_method(void)) /* TLSv1.2 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_2_client_method(void)) /* TLSv1.2 */ +# endif + +# ifndef OPENSSL_NO_DTLS1_METHOD +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *DTLSv1_method(void)) /* DTLSv1.0 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *DTLSv1_server_method(void)) /* DTLSv1.0 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *DTLSv1_client_method(void)) /* DTLSv1.0 */ +# endif + +# ifndef OPENSSL_NO_DTLS1_2_METHOD +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *DTLSv1_2_method(void)) /* DTLSv1.2 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *DTLSv1_2_server_method(void)) /* DTLSv1.2 */ +DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *DTLSv1_2_client_method(void)) /* DTLSv1.2 */ +#endif + +__owur const SSL_METHOD *DTLS_method(void); /* DTLS 1.0 and 1.2 */ +__owur const SSL_METHOD *DTLS_server_method(void); /* DTLS 1.0 and 1.2 */ +__owur const SSL_METHOD *DTLS_client_method(void); /* DTLS 1.0 and 1.2 */ + +__owur STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s); +__owur STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx); +__owur STACK_OF(SSL_CIPHER) *SSL_get_client_ciphers(const SSL *s); +__owur STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s); + +__owur int SSL_do_handshake(SSL *s); +int SSL_renegotiate(SSL *s); +__owur int SSL_renegotiate_abbreviated(SSL *s); +__owur int SSL_renegotiate_pending(SSL *s); +int SSL_shutdown(SSL *s); + +__owur const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); +__owur const SSL_METHOD *SSL_get_ssl_method(SSL *s); +__owur int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); +__owur const char *SSL_alert_type_string_long(int value); +__owur const char *SSL_alert_type_string(int value); +__owur const char *SSL_alert_desc_string_long(int value); +__owur const char *SSL_alert_desc_string(int value); + +void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list); +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); +__owur STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s); +__owur STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s); +__owur int SSL_add_client_CA(SSL *ssl, X509 *x); +__owur int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +void SSL_set_connect_state(SSL *s); +void SSL_set_accept_state(SSL *s); + +__owur long SSL_get_default_timeout(const SSL *s); + +#if OPENSSL_API_COMPAT < 0x10100000L +# define SSL_library_init() OPENSSL_init_ssl(0, NULL) +#endif + +__owur char *SSL_CIPHER_description(const SSL_CIPHER *, char *buf, int size); +__owur STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk); + +__owur SSL *SSL_dup(SSL *ssl); + +__owur X509 *SSL_get_certificate(const SSL *ssl); +/* + * EVP_PKEY + */ struct evp_pkey_st *SSL_get_privatekey(const SSL *ssl); + +__owur X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); +__owur EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx); + +void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); +__owur int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); +void SSL_set_quiet_shutdown(SSL *ssl, int mode); +__owur int SSL_get_quiet_shutdown(const SSL *ssl); +void SSL_set_shutdown(SSL *ssl, int mode); +__owur int SSL_get_shutdown(const SSL *ssl); +__owur int SSL_version(const SSL *ssl); +__owur int SSL_client_version(const SSL *s); +__owur int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +__owur int SSL_CTX_set_default_verify_dir(SSL_CTX *ctx); +__owur int SSL_CTX_set_default_verify_file(SSL_CTX *ctx); +__owur int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath); +# define SSL_get0_session SSL_get_session/* just peek at pointer */ +__owur SSL_SESSION *SSL_get_session(const SSL *ssl); +__owur SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */ +__owur SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); +SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx); +void SSL_set_info_callback(SSL *ssl, + void (*cb) (const SSL *ssl, int type, int val)); +void (*SSL_get_info_callback(const SSL *ssl)) (const SSL *ssl, int type, + int val); +__owur OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); + +void SSL_set_verify_result(SSL *ssl, long v); +__owur long SSL_get_verify_result(const SSL *ssl); +__owur STACK_OF(X509) *SSL_get0_verified_chain(const SSL *s); + +__owur size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, + size_t outlen); +__owur size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, + size_t outlen); +__owur size_t SSL_SESSION_get_master_key(const SSL_SESSION *ssl, + unsigned char *out, size_t outlen); + +#define SSL_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, l, p, newf, dupf, freef) +__owur int SSL_set_ex_data(SSL *ssl, int idx, void *data); +void *SSL_get_ex_data(const SSL *ssl, int idx); +#define SSL_SESSION_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, l, p, newf, dupf, freef) +__owur int SSL_SESSION_set_ex_data(SSL_SESSION *ss, int idx, void *data); +void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss, int idx); +#define SSL_CTX_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, l, p, newf, dupf, freef) +__owur int SSL_CTX_set_ex_data(SSL_CTX *ssl, int idx, void *data); +void *SSL_CTX_get_ex_data(const SSL_CTX *ssl, int idx); + +__owur int SSL_get_ex_data_X509_STORE_CTX_idx(void); + +# define SSL_CTX_sess_set_cache_size(ctx,t) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL) +# define SSL_CTX_sess_get_cache_size(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL) +# define SSL_CTX_set_session_cache_mode(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL) +# define SSL_CTX_get_session_cache_mode(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL) + +# define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx) +# define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m) +# define SSL_CTX_get_read_ahead(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL) +# define SSL_CTX_set_read_ahead(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL) +# define SSL_CTX_get_max_cert_list(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL) +# define SSL_CTX_set_max_cert_list(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) +# define SSL_get_max_cert_list(ssl) \ + SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL) +# define SSL_set_max_cert_list(ssl,m) \ + SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) + +# define SSL_CTX_set_max_send_fragment(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL) +# define SSL_set_max_send_fragment(ssl,m) \ + SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL) +# define SSL_CTX_set_split_send_fragment(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SPLIT_SEND_FRAGMENT,m,NULL) +# define SSL_set_split_send_fragment(ssl,m) \ + SSL_ctrl(ssl,SSL_CTRL_SET_SPLIT_SEND_FRAGMENT,m,NULL) +# define SSL_CTX_set_max_pipelines(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_PIPELINES,m,NULL) +# define SSL_set_max_pipelines(ssl,m) \ + SSL_ctrl(ssl,SSL_CTRL_SET_MAX_PIPELINES,m,NULL) + +void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); +void SSL_set_default_read_buffer_len(SSL *s, size_t len); + +# ifndef OPENSSL_NO_DH +/* NB: the |keylength| is only applicable when is_export is true */ +void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx, + DH *(*dh) (SSL *ssl, int is_export, + int keylength)); +void SSL_set_tmp_dh_callback(SSL *ssl, + DH *(*dh) (SSL *ssl, int is_export, + int keylength)); +# endif + +__owur const COMP_METHOD *SSL_get_current_compression(SSL *s); +__owur const COMP_METHOD *SSL_get_current_expansion(SSL *s); +__owur const char *SSL_COMP_get_name(const COMP_METHOD *comp); +__owur const char *SSL_COMP_get0_name(const SSL_COMP *comp); +__owur int SSL_COMP_get_id(const SSL_COMP *comp); +STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void); +__owur STACK_OF(SSL_COMP) *SSL_COMP_set0_compression_methods(STACK_OF(SSL_COMP) + *meths); +#if OPENSSL_API_COMPAT < 0x10100000L +# define SSL_COMP_free_compression_methods() while(0) continue +#endif +__owur int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm); + +const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); +int SSL_CIPHER_get_cipher_nid(const SSL_CIPHER *c); +int SSL_CIPHER_get_digest_nid(const SSL_CIPHER *c); + +/* TLS extensions functions */ +__owur int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len); + +__owur int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, + void *arg); + +/* Pre-shared secret session resumption functions */ +__owur int SSL_set_session_secret_cb(SSL *s, + tls_session_secret_cb_fn tls_session_secret_cb, + void *arg); + +void SSL_CTX_set_not_resumable_session_callback(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + int + is_forward_secure)); + +void SSL_set_not_resumable_session_callback(SSL *ssl, + int (*cb) (SSL *ssl, + int + is_forward_secure)); +# if OPENSSL_API_COMPAT < 0x10100000L +# define SSL_cache_hit(s) SSL_session_reused(s) +# endif + +__owur int SSL_session_reused(SSL *s); +__owur int SSL_is_server(SSL *s); + +__owur __owur SSL_CONF_CTX *SSL_CONF_CTX_new(void); +int SSL_CONF_CTX_finish(SSL_CONF_CTX *cctx); +void SSL_CONF_CTX_free(SSL_CONF_CTX *cctx); +unsigned int SSL_CONF_CTX_set_flags(SSL_CONF_CTX *cctx, unsigned int flags); +__owur unsigned int SSL_CONF_CTX_clear_flags(SSL_CONF_CTX *cctx, unsigned int flags); +__owur int SSL_CONF_CTX_set1_prefix(SSL_CONF_CTX *cctx, const char *pre); + +void SSL_CONF_CTX_set_ssl(SSL_CONF_CTX *cctx, SSL *ssl); +void SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *cctx, SSL_CTX *ctx); + +__owur int SSL_CONF_cmd(SSL_CONF_CTX *cctx, const char *cmd, const char *value); +__owur int SSL_CONF_cmd_argv(SSL_CONF_CTX *cctx, int *pargc, char ***pargv); +__owur int SSL_CONF_cmd_value_type(SSL_CONF_CTX *cctx, const char *cmd); + +void SSL_add_ssl_module(void); +int SSL_config(SSL *s, const char *name); +int SSL_CTX_config(SSL_CTX *ctx, const char *name); + +# ifndef OPENSSL_NO_SSL_TRACE +void SSL_trace(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); +__owur const char *SSL_CIPHER_standard_name(const SSL_CIPHER *c); +# endif + +# ifndef OPENSSL_NO_SOCK +int DTLSv1_listen(SSL *s, BIO_ADDR *client); +# endif + +# ifndef OPENSSL_NO_CT + +/* + * A callback for verifying that the received SCTs are sufficient. + * Expected to return 1 if they are sufficient, otherwise 0. + * May return a negative integer if an error occurs. + * A connection should be aborted if the SCTs are deemed insufficient. + */ +typedef int(*ssl_ct_validation_cb)(const CT_POLICY_EVAL_CTX *ctx, + const STACK_OF(SCT) *scts, void *arg); + +/* + * Sets a |callback| that is invoked upon receipt of ServerHelloDone to validate + * the received SCTs. + * If the callback returns a non-positive result, the connection is terminated. + * Call this function before beginning a handshake. + * If a NULL |callback| is provided, SCT validation is disabled. + * |arg| is arbitrary userdata that will be passed to the callback whenever it + * is invoked. Ownership of |arg| remains with the caller. + * + * NOTE: A side-effect of setting a CT callback is that an OCSP stapled response + * will be requested. + */ +int SSL_set_ct_validation_callback(SSL *s, ssl_ct_validation_cb callback, + void *arg); +int SSL_CTX_set_ct_validation_callback(SSL_CTX *ctx, + ssl_ct_validation_cb callback, + void *arg); +#define SSL_disable_ct(s) \ + ((void) SSL_set_validation_callback((s), NULL, NULL)) +#define SSL_CTX_disable_ct(ctx) \ + ((void) SSL_CTX_set_validation_callback((ctx), NULL, NULL)) + +/* + * The validation type enumerates the available behaviours of the built-in SSL + * CT validation callback selected via SSL_enable_ct() and SSL_CTX_enable_ct(). + * The underlying callback is a static function in libssl. + */ +enum { + SSL_CT_VALIDATION_PERMISSIVE = 0, + SSL_CT_VALIDATION_STRICT +}; + +/* + * Enable CT by setting up a callback that implements one of the built-in + * validation variants. The SSL_CT_VALIDATION_PERMISSIVE variant always + * continues the handshake, the application can make appropriate decisions at + * handshake completion. The SSL_CT_VALIDATION_STRICT variant requires at + * least one valid SCT, or else handshake termination will be requested. The + * handshake may continue anyway if SSL_VERIFY_NONE is in effect. + */ +int SSL_enable_ct(SSL *s, int validation_mode); +int SSL_CTX_enable_ct(SSL_CTX *ctx, int validation_mode); + +/* + * Report whether a non-NULL callback is enabled. + */ +int SSL_ct_is_enabled(const SSL *s); +int SSL_CTX_ct_is_enabled(const SSL_CTX *ctx); + +/* Gets the SCTs received from a connection */ +const STACK_OF(SCT) *SSL_get0_peer_scts(SSL *s); + +/* + * Loads the CT log list from the default location. + * If a CTLOG_STORE has previously been set using SSL_CTX_set_ctlog_store, + * the log information loaded from this file will be appended to the + * CTLOG_STORE. + * Returns 1 on success, 0 otherwise. + */ +int SSL_CTX_set_default_ctlog_list_file(SSL_CTX *ctx); + +/* + * Loads the CT log list from the specified file path. + * If a CTLOG_STORE has previously been set using SSL_CTX_set_ctlog_store, + * the log information loaded from this file will be appended to the + * CTLOG_STORE. + * Returns 1 on success, 0 otherwise. + */ +int SSL_CTX_set_ctlog_list_file(SSL_CTX *ctx, const char *path); + +/* + * Sets the CT log list used by all SSL connections created from this SSL_CTX. + * Ownership of the CTLOG_STORE is transferred to the SSL_CTX. + */ +void SSL_CTX_set0_ctlog_store(SSL_CTX *ctx, CTLOG_STORE *logs); + +/* + * Gets the CT log list used by all SSL connections created from this SSL_CTX. + * This will be NULL unless one of the following functions has been called: + * - SSL_CTX_set_default_ctlog_list_file + * - SSL_CTX_set_ctlog_list_file + * - SSL_CTX_set_ctlog_store + */ +const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx); + +# endif /* OPENSSL_NO_CT */ + +/* What the "other" parameter contains in security callback */ +/* Mask for type */ +# define SSL_SECOP_OTHER_TYPE 0xffff0000 +# define SSL_SECOP_OTHER_NONE 0 +# define SSL_SECOP_OTHER_CIPHER (1 << 16) +# define SSL_SECOP_OTHER_CURVE (2 << 16) +# define SSL_SECOP_OTHER_DH (3 << 16) +# define SSL_SECOP_OTHER_PKEY (4 << 16) +# define SSL_SECOP_OTHER_SIGALG (5 << 16) +# define SSL_SECOP_OTHER_CERT (6 << 16) + +/* Indicated operation refers to peer key or certificate */ +# define SSL_SECOP_PEER 0x1000 + +/* Values for "op" parameter in security callback */ + +/* Called to filter ciphers */ +/* Ciphers client supports */ +# define SSL_SECOP_CIPHER_SUPPORTED (1 | SSL_SECOP_OTHER_CIPHER) +/* Cipher shared by client/server */ +# define SSL_SECOP_CIPHER_SHARED (2 | SSL_SECOP_OTHER_CIPHER) +/* Sanity check of cipher server selects */ +# define SSL_SECOP_CIPHER_CHECK (3 | SSL_SECOP_OTHER_CIPHER) +/* Curves supported by client */ +# define SSL_SECOP_CURVE_SUPPORTED (4 | SSL_SECOP_OTHER_CURVE) +/* Curves shared by client/server */ +# define SSL_SECOP_CURVE_SHARED (5 | SSL_SECOP_OTHER_CURVE) +/* Sanity check of curve server selects */ +# define SSL_SECOP_CURVE_CHECK (6 | SSL_SECOP_OTHER_CURVE) +/* Temporary DH key */ +# define SSL_SECOP_TMP_DH (7 | SSL_SECOP_OTHER_PKEY) +/* SSL/TLS version */ +# define SSL_SECOP_VERSION (9 | SSL_SECOP_OTHER_NONE) +/* Session tickets */ +# define SSL_SECOP_TICKET (10 | SSL_SECOP_OTHER_NONE) +/* Supported signature algorithms sent to peer */ +# define SSL_SECOP_SIGALG_SUPPORTED (11 | SSL_SECOP_OTHER_SIGALG) +/* Shared signature algorithm */ +# define SSL_SECOP_SIGALG_SHARED (12 | SSL_SECOP_OTHER_SIGALG) +/* Sanity check signature algorithm allowed */ +# define SSL_SECOP_SIGALG_CHECK (13 | SSL_SECOP_OTHER_SIGALG) +/* Used to get mask of supported public key signature algorithms */ +# define SSL_SECOP_SIGALG_MASK (14 | SSL_SECOP_OTHER_SIGALG) +/* Use to see if compression is allowed */ +# define SSL_SECOP_COMPRESSION (15 | SSL_SECOP_OTHER_NONE) +/* EE key in certificate */ +# define SSL_SECOP_EE_KEY (16 | SSL_SECOP_OTHER_CERT) +/* CA key in certificate */ +# define SSL_SECOP_CA_KEY (17 | SSL_SECOP_OTHER_CERT) +/* CA digest algorithm in certificate */ +# define SSL_SECOP_CA_MD (18 | SSL_SECOP_OTHER_CERT) +/* Peer EE key in certificate */ +# define SSL_SECOP_PEER_EE_KEY (SSL_SECOP_EE_KEY | SSL_SECOP_PEER) +/* Peer CA key in certificate */ +# define SSL_SECOP_PEER_CA_KEY (SSL_SECOP_CA_KEY | SSL_SECOP_PEER) +/* Peer CA digest algorithm in certificate */ +# define SSL_SECOP_PEER_CA_MD (SSL_SECOP_CA_MD | SSL_SECOP_PEER) + +void SSL_set_security_level(SSL *s, int level); +__owur int SSL_get_security_level(const SSL *s); +void SSL_set_security_callback(SSL *s, + int (*cb) (const SSL *s, const SSL_CTX *ctx, int op, + int bits, int nid, void *other, + void *ex)); +int (*SSL_get_security_callback(const SSL *s)) (const SSL *s, const SSL_CTX *ctx, int op, + int bits, int nid, + void *other, void *ex); +void SSL_set0_security_ex_data(SSL *s, void *ex); +__owur void *SSL_get0_security_ex_data(const SSL *s); + +void SSL_CTX_set_security_level(SSL_CTX *ctx, int level); +__owur int SSL_CTX_get_security_level(const SSL_CTX *ctx); +void SSL_CTX_set_security_callback(SSL_CTX *ctx, + int (*cb) (const SSL *s, const SSL_CTX *ctx, int op, + int bits, int nid, void *other, + void *ex)); +int (*SSL_CTX_get_security_callback(const SSL_CTX *ctx)) (const SSL *s, + const SSL_CTX *ctx, + int op, int bits, + int nid, + void *other, + void *ex); +void SSL_CTX_set0_security_ex_data(SSL_CTX *ctx, void *ex); +__owur void *SSL_CTX_get0_security_ex_data(const SSL_CTX *ctx); + +/* OPENSSL_INIT flag 0x010000 reserved for internal use */ +#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L +#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L + +#define OPENSSL_INIT_SSL_DEFAULT \ + (OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS) + +int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings); + +# ifndef OPENSSL_NO_UNIT_TEST +__owur const struct openssl_ssl_test_functions *SSL_test_functions(void); +# endif + +extern const char SSL_version_str[]; + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_SSL_strings(void); + +/* Error codes for the SSL functions. */ + +/* Function codes. */ +# define SSL_F_CHECK_SUITEB_CIPHER_LIST 331 +# define SSL_F_CT_MOVE_SCTS 345 +# define SSL_F_CT_STRICT 349 +# define SSL_F_D2I_SSL_SESSION 103 +# define SSL_F_DANE_CTX_ENABLE 347 +# define SSL_F_DANE_MTYPE_SET 393 +# define SSL_F_DANE_TLSA_ADD 394 +# define SSL_F_DO_DTLS1_WRITE 245 +# define SSL_F_DO_SSL3_WRITE 104 +# define SSL_F_DTLS1_BUFFER_RECORD 247 +# define SSL_F_DTLS1_CHECK_TIMEOUT_NUM 318 +# define SSL_F_DTLS1_HEARTBEAT 305 +# define SSL_F_DTLS1_PREPROCESS_FRAGMENT 288 +# define SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS 424 +# define SSL_F_DTLS1_PROCESS_RECORD 257 +# define SSL_F_DTLS1_READ_BYTES 258 +# define SSL_F_DTLS1_READ_FAILED 339 +# define SSL_F_DTLS1_RETRANSMIT_MESSAGE 390 +# define SSL_F_DTLS1_WRITE_APP_DATA_BYTES 268 +# define SSL_F_DTLSV1_LISTEN 350 +# define SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC 371 +# define SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST 385 +# define SSL_F_DTLS_GET_REASSEMBLED_MESSAGE 370 +# define SSL_F_DTLS_PROCESS_HELLO_VERIFY 386 +# define SSL_F_OPENSSL_INIT_SSL 342 +# define SSL_F_OSSL_STATEM_CLIENT_READ_TRANSITION 417 +# define SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION 418 +# define SSL_F_READ_STATE_MACHINE 352 +# define SSL_F_SSL3_CHANGE_CIPHER_STATE 129 +# define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130 +# define SSL_F_SSL3_CTRL 213 +# define SSL_F_SSL3_CTX_CTRL 133 +# define SSL_F_SSL3_DIGEST_CACHED_RECORDS 293 +# define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC 292 +# define SSL_F_SSL3_FINAL_FINISH_MAC 285 +# define SSL_F_SSL3_GENERATE_KEY_BLOCK 238 +# define SSL_F_SSL3_GENERATE_MASTER_SECRET 388 +# define SSL_F_SSL3_GET_RECORD 143 +# define SSL_F_SSL3_INIT_FINISHED_MAC 397 +# define SSL_F_SSL3_OUTPUT_CERT_CHAIN 147 +# define SSL_F_SSL3_READ_BYTES 148 +# define SSL_F_SSL3_READ_N 149 +# define SSL_F_SSL3_SETUP_KEY_BLOCK 157 +# define SSL_F_SSL3_SETUP_READ_BUFFER 156 +# define SSL_F_SSL3_SETUP_WRITE_BUFFER 291 +# define SSL_F_SSL3_WRITE_BYTES 158 +# define SSL_F_SSL3_WRITE_PENDING 159 +# define SSL_F_SSL_ADD_CERT_CHAIN 316 +# define SSL_F_SSL_ADD_CERT_TO_BUF 319 +# define SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT 298 +# define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 277 +# define SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT 307 +# define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215 +# define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216 +# define SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT 299 +# define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 278 +# define SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT 308 +# define SSL_F_SSL_BAD_METHOD 160 +# define SSL_F_SSL_BUILD_CERT_CHAIN 332 +# define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161 +# define SSL_F_SSL_CERT_ADD0_CHAIN_CERT 346 +# define SSL_F_SSL_CERT_DUP 221 +# define SSL_F_SSL_CERT_NEW 162 +# define SSL_F_SSL_CERT_SET0_CHAIN 340 +# define SSL_F_SSL_CHECK_PRIVATE_KEY 163 +# define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 280 +# define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG 279 +# define SSL_F_SSL_CIPHER_PROCESS_RULESTR 230 +# define SSL_F_SSL_CIPHER_STRENGTH_SORT 231 +# define SSL_F_SSL_CLEAR 164 +# define SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD 165 +# define SSL_F_SSL_CONF_CMD 334 +# define SSL_F_SSL_CREATE_CIPHER_LIST 166 +# define SSL_F_SSL_CTRL 232 +# define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY 168 +# define SSL_F_SSL_CTX_ENABLE_CT 398 +# define SSL_F_SSL_CTX_MAKE_PROFILES 309 +# define SSL_F_SSL_CTX_NEW 169 +# define SSL_F_SSL_CTX_SET_ALPN_PROTOS 343 +# define SSL_F_SSL_CTX_SET_CIPHER_LIST 269 +# define SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE 290 +# define SSL_F_SSL_CTX_SET_CT_VALIDATION_CALLBACK 396 +# define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219 +# define SSL_F_SSL_CTX_SET_SSL_VERSION 170 +# define SSL_F_SSL_CTX_USE_CERTIFICATE 171 +# define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172 +# define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173 +# define SSL_F_SSL_CTX_USE_PRIVATEKEY 174 +# define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175 +# define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE 176 +# define SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT 272 +# define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY 177 +# define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1 178 +# define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179 +# define SSL_F_SSL_CTX_USE_SERVERINFO 336 +# define SSL_F_SSL_CTX_USE_SERVERINFO_FILE 337 +# define SSL_F_SSL_DANE_DUP 403 +# define SSL_F_SSL_DANE_ENABLE 395 +# define SSL_F_SSL_DO_CONFIG 391 +# define SSL_F_SSL_DO_HANDSHAKE 180 +# define SSL_F_SSL_DUP_CA_LIST 408 +# define SSL_F_SSL_ENABLE_CT 402 +# define SSL_F_SSL_GET_NEW_SESSION 181 +# define SSL_F_SSL_GET_PREV_SESSION 217 +# define SSL_F_SSL_GET_SERVER_CERT_INDEX 322 +# define SSL_F_SSL_GET_SIGN_PKEY 183 +# define SSL_F_SSL_INIT_WBIO_BUFFER 184 +# define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185 +# define SSL_F_SSL_MODULE_INIT 392 +# define SSL_F_SSL_NEW 186 +# define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 300 +# define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 302 +# define SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT 310 +# define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 301 +# define SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT 303 +# define SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT 311 +# define SSL_F_SSL_PEEK 270 +# define SSL_F_SSL_READ 223 +# define SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT 320 +# define SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT 321 +# define SSL_F_SSL_SESSION_DUP 348 +# define SSL_F_SSL_SESSION_NEW 189 +# define SSL_F_SSL_SESSION_PRINT_FP 190 +# define SSL_F_SSL_SESSION_SET1_ID 423 +# define SSL_F_SSL_SESSION_SET1_ID_CONTEXT 312 +# define SSL_F_SSL_SET_ALPN_PROTOS 344 +# define SSL_F_SSL_SET_CERT 191 +# define SSL_F_SSL_SET_CIPHER_LIST 271 +# define SSL_F_SSL_SET_CT_VALIDATION_CALLBACK 399 +# define SSL_F_SSL_SET_FD 192 +# define SSL_F_SSL_SET_PKEY 193 +# define SSL_F_SSL_SET_RFD 194 +# define SSL_F_SSL_SET_SESSION 195 +# define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218 +# define SSL_F_SSL_SET_SESSION_TICKET_EXT 294 +# define SSL_F_SSL_SET_WFD 196 +# define SSL_F_SSL_SHUTDOWN 224 +# define SSL_F_SSL_SRP_CTX_INIT 313 +# define SSL_F_SSL_START_ASYNC_JOB 389 +# define SSL_F_SSL_UNDEFINED_FUNCTION 197 +# define SSL_F_SSL_UNDEFINED_VOID_FUNCTION 244 +# define SSL_F_SSL_USE_CERTIFICATE 198 +# define SSL_F_SSL_USE_CERTIFICATE_ASN1 199 +# define SSL_F_SSL_USE_CERTIFICATE_FILE 200 +# define SSL_F_SSL_USE_PRIVATEKEY 201 +# define SSL_F_SSL_USE_PRIVATEKEY_ASN1 202 +# define SSL_F_SSL_USE_PRIVATEKEY_FILE 203 +# define SSL_F_SSL_USE_PSK_IDENTITY_HINT 273 +# define SSL_F_SSL_USE_RSAPRIVATEKEY 204 +# define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1 205 +# define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206 +# define SSL_F_SSL_VALIDATE_CT 400 +# define SSL_F_SSL_VERIFY_CERT_CHAIN 207 +# define SSL_F_SSL_WRITE 208 +# define SSL_F_STATE_MACHINE 353 +# define SSL_F_TLS12_CHECK_PEER_SIGALG 333 +# define SSL_F_TLS1_CHANGE_CIPHER_STATE 209 +# define SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS 341 +# define SSL_F_TLS1_ENC 401 +# define SSL_F_TLS1_EXPORT_KEYING_MATERIAL 314 +# define SSL_F_TLS1_GET_CURVELIST 338 +# define SSL_F_TLS1_PRF 284 +# define SSL_F_TLS1_SETUP_KEY_BLOCK 211 +# define SSL_F_TLS1_SET_SERVER_SIGALGS 335 +# define SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK 354 +# define SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST 372 +# define SSL_F_TLS_CONSTRUCT_CKE_DHE 404 +# define SSL_F_TLS_CONSTRUCT_CKE_ECDHE 405 +# define SSL_F_TLS_CONSTRUCT_CKE_GOST 406 +# define SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE 407 +# define SSL_F_TLS_CONSTRUCT_CKE_RSA 409 +# define SSL_F_TLS_CONSTRUCT_CKE_SRP 410 +# define SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE 355 +# define SSL_F_TLS_CONSTRUCT_CLIENT_HELLO 356 +# define SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE 357 +# define SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY 358 +# define SSL_F_TLS_CONSTRUCT_FINISHED 359 +# define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST 373 +# define SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET 428 +# define SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE 374 +# define SSL_F_TLS_CONSTRUCT_SERVER_DONE 375 +# define SSL_F_TLS_CONSTRUCT_SERVER_HELLO 376 +# define SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE 377 +# define SSL_F_TLS_GET_MESSAGE_BODY 351 +# define SSL_F_TLS_GET_MESSAGE_HEADER 387 +# define SSL_F_TLS_POST_PROCESS_CLIENT_HELLO 378 +# define SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE 384 +# define SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE 360 +# define SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST 361 +# define SSL_F_TLS_PROCESS_CERT_STATUS 362 +# define SSL_F_TLS_PROCESS_CERT_VERIFY 379 +# define SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC 363 +# define SSL_F_TLS_PROCESS_CKE_DHE 411 +# define SSL_F_TLS_PROCESS_CKE_ECDHE 412 +# define SSL_F_TLS_PROCESS_CKE_GOST 413 +# define SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE 414 +# define SSL_F_TLS_PROCESS_CKE_RSA 415 +# define SSL_F_TLS_PROCESS_CKE_SRP 416 +# define SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE 380 +# define SSL_F_TLS_PROCESS_CLIENT_HELLO 381 +# define SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE 382 +# define SSL_F_TLS_PROCESS_FINISHED 364 +# define SSL_F_TLS_PROCESS_KEY_EXCHANGE 365 +# define SSL_F_TLS_PROCESS_NEW_SESSION_TICKET 366 +# define SSL_F_TLS_PROCESS_NEXT_PROTO 383 +# define SSL_F_TLS_PROCESS_SERVER_CERTIFICATE 367 +# define SSL_F_TLS_PROCESS_SERVER_DONE 368 +# define SSL_F_TLS_PROCESS_SERVER_HELLO 369 +# define SSL_F_TLS_PROCESS_SKE_DHE 419 +# define SSL_F_TLS_PROCESS_SKE_ECDHE 420 +# define SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE 421 +# define SSL_F_TLS_PROCESS_SKE_SRP 422 +# define SSL_F_USE_CERTIFICATE_CHAIN_FILE 220 + +/* Reason codes. */ +# define SSL_R_APP_DATA_IN_HANDSHAKE 100 +# define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272 +# define SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE 143 +# define SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE 158 +# define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 +# define SSL_R_BAD_DATA 390 +# define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 +# define SSL_R_BAD_DECOMPRESSION 107 +# define SSL_R_BAD_DH_VALUE 102 +# define SSL_R_BAD_DIGEST_LENGTH 111 +# define SSL_R_BAD_ECC_CERT 304 +# define SSL_R_BAD_ECPOINT 306 +# define SSL_R_BAD_HANDSHAKE_LENGTH 332 +# define SSL_R_BAD_HELLO_REQUEST 105 +# define SSL_R_BAD_LENGTH 271 +# define SSL_R_BAD_PACKET_LENGTH 115 +# define SSL_R_BAD_PROTOCOL_VERSION_NUMBER 116 +# define SSL_R_BAD_RSA_ENCRYPT 119 +# define SSL_R_BAD_SIGNATURE 123 +# define SSL_R_BAD_SRP_A_LENGTH 347 +# define SSL_R_BAD_SRP_PARAMETERS 371 +# define SSL_R_BAD_SRTP_MKI_VALUE 352 +# define SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST 353 +# define SSL_R_BAD_SSL_FILETYPE 124 +# define SSL_R_BAD_VALUE 384 +# define SSL_R_BAD_WRITE_RETRY 127 +# define SSL_R_BIO_NOT_SET 128 +# define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 129 +# define SSL_R_BN_LIB 130 +# define SSL_R_CA_DN_LENGTH_MISMATCH 131 +# define SSL_R_CA_KEY_TOO_SMALL 397 +# define SSL_R_CA_MD_TOO_WEAK 398 +# define SSL_R_CCS_RECEIVED_EARLY 133 +# define SSL_R_CERTIFICATE_VERIFY_FAILED 134 +# define SSL_R_CERT_CB_ERROR 377 +# define SSL_R_CERT_LENGTH_MISMATCH 135 +# define SSL_R_CIPHER_CODE_WRONG_LENGTH 137 +# define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 138 +# define SSL_R_CLIENTHELLO_TLSEXT 226 +# define SSL_R_COMPRESSED_LENGTH_TOO_LONG 140 +# define SSL_R_COMPRESSION_DISABLED 343 +# define SSL_R_COMPRESSION_FAILURE 141 +# define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307 +# define SSL_R_COMPRESSION_LIBRARY_ERROR 142 +# define SSL_R_CONNECTION_TYPE_NOT_SET 144 +# define SSL_R_CONTEXT_NOT_DANE_ENABLED 167 +# define SSL_R_COOKIE_GEN_CALLBACK_FAILURE 400 +# define SSL_R_COOKIE_MISMATCH 308 +# define SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED 206 +# define SSL_R_DANE_ALREADY_ENABLED 172 +# define SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL 173 +# define SSL_R_DANE_NOT_ENABLED 175 +# define SSL_R_DANE_TLSA_BAD_CERTIFICATE 180 +# define SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE 184 +# define SSL_R_DANE_TLSA_BAD_DATA_LENGTH 189 +# define SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH 192 +# define SSL_R_DANE_TLSA_BAD_MATCHING_TYPE 200 +# define SSL_R_DANE_TLSA_BAD_PUBLIC_KEY 201 +# define SSL_R_DANE_TLSA_BAD_SELECTOR 202 +# define SSL_R_DANE_TLSA_NULL_DATA 203 +# define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145 +# define SSL_R_DATA_LENGTH_TOO_LONG 146 +# define SSL_R_DECRYPTION_FAILED 147 +# define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281 +# define SSL_R_DH_KEY_TOO_SMALL 394 +# define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148 +# define SSL_R_DIGEST_CHECK_FAILED 149 +# define SSL_R_DTLS_MESSAGE_TOO_BIG 334 +# define SSL_R_DUPLICATE_COMPRESSION_ID 309 +# define SSL_R_ECC_CERT_NOT_FOR_SIGNING 318 +# define SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE 374 +# define SSL_R_EE_KEY_TOO_SMALL 399 +# define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354 +# define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150 +# define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151 +# define SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN 204 +# define SSL_R_EXCESSIVE_MESSAGE_SIZE 152 +# define SSL_R_EXTRA_DATA_IN_MESSAGE 153 +# define SSL_R_FAILED_TO_INIT_ASYNC 405 +# define SSL_R_FRAGMENTED_CLIENT_HELLO 401 +# define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154 +# define SSL_R_HTTPS_PROXY_REQUEST 155 +# define SSL_R_HTTP_REQUEST 156 +# define SSL_R_ILLEGAL_SUITEB_DIGEST 380 +# define SSL_R_INAPPROPRIATE_FALLBACK 373 +# define SSL_R_INCONSISTENT_COMPRESSION 340 +# define SSL_R_INCONSISTENT_EXTMS 104 +# define SSL_R_INVALID_COMMAND 280 +# define SSL_R_INVALID_COMPRESSION_ALGORITHM 341 +# define SSL_R_INVALID_CONFIGURATION_NAME 113 +# define SSL_R_INVALID_CT_VALIDATION_TYPE 212 +# define SSL_R_INVALID_NULL_CMD_NAME 385 +# define SSL_R_INVALID_SEQUENCE_NUMBER 402 +# define SSL_R_INVALID_SERVERINFO_DATA 388 +# define SSL_R_INVALID_SRP_USERNAME 357 +# define SSL_R_INVALID_STATUS_RESPONSE 328 +# define SSL_R_INVALID_TICKET_KEYS_LENGTH 325 +# define SSL_R_LENGTH_MISMATCH 159 +# define SSL_R_LENGTH_TOO_LONG 404 +# define SSL_R_LENGTH_TOO_SHORT 160 +# define SSL_R_LIBRARY_BUG 274 +# define SSL_R_LIBRARY_HAS_NO_CIPHERS 161 +# define SSL_R_MISSING_DSA_SIGNING_CERT 165 +# define SSL_R_MISSING_ECDSA_SIGNING_CERT 381 +# define SSL_R_MISSING_RSA_CERTIFICATE 168 +# define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169 +# define SSL_R_MISSING_RSA_SIGNING_CERT 170 +# define SSL_R_MISSING_SRP_PARAM 358 +# define SSL_R_MISSING_TMP_DH_KEY 171 +# define SSL_R_MISSING_TMP_ECDH_KEY 311 +# define SSL_R_NO_CERTIFICATES_RETURNED 176 +# define SSL_R_NO_CERTIFICATE_ASSIGNED 177 +# define SSL_R_NO_CERTIFICATE_SET 179 +# define SSL_R_NO_CIPHERS_AVAILABLE 181 +# define SSL_R_NO_CIPHERS_SPECIFIED 183 +# define SSL_R_NO_CIPHER_MATCH 185 +# define SSL_R_NO_CLIENT_CERT_METHOD 331 +# define SSL_R_NO_COMPRESSION_SPECIFIED 187 +# define SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER 330 +# define SSL_R_NO_METHOD_SPECIFIED 188 +# define SSL_R_NO_PEM_EXTENSIONS 389 +# define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190 +# define SSL_R_NO_PROTOCOLS_AVAILABLE 191 +# define SSL_R_NO_RENEGOTIATION 339 +# define SSL_R_NO_REQUIRED_DIGEST 324 +# define SSL_R_NO_SHARED_CIPHER 193 +# define SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS 376 +# define SSL_R_NO_SRTP_PROFILES 359 +# define SSL_R_NO_VALID_SCTS 216 +# define SSL_R_NO_VERIFY_COOKIE_CALLBACK 403 +# define SSL_R_NULL_SSL_CTX 195 +# define SSL_R_NULL_SSL_METHOD_PASSED 196 +# define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197 +# define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344 +# define SSL_R_PACKET_LENGTH_TOO_LONG 198 +# define SSL_R_PARSE_TLSEXT 227 +# define SSL_R_PATH_TOO_LONG 270 +# define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199 +# define SSL_R_PEM_NAME_BAD_PREFIX 391 +# define SSL_R_PEM_NAME_TOO_SHORT 392 +# define SSL_R_PIPELINE_FAILURE 406 +# define SSL_R_PROTOCOL_IS_SHUTDOWN 207 +# define SSL_R_PSK_IDENTITY_NOT_FOUND 223 +# define SSL_R_PSK_NO_CLIENT_CB 224 +# define SSL_R_PSK_NO_SERVER_CB 225 +# define SSL_R_READ_BIO_NOT_SET 211 +# define SSL_R_READ_TIMEOUT_EXPIRED 312 +# define SSL_R_RECORD_LENGTH_MISMATCH 213 +# define SSL_R_RECORD_TOO_SMALL 298 +# define SSL_R_RENEGOTIATE_EXT_TOO_LONG 335 +# define SSL_R_RENEGOTIATION_ENCODING_ERR 336 +# define SSL_R_RENEGOTIATION_MISMATCH 337 +# define SSL_R_REQUIRED_CIPHER_MISSING 215 +# define SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING 342 +# define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 345 +# define SSL_R_SCT_VERIFICATION_FAILED 208 +# define SSL_R_SERVERHELLO_TLSEXT 275 +# define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277 +# define SSL_R_SHUTDOWN_WHILE_IN_INIT 407 +# define SSL_R_SIGNATURE_ALGORITHMS_ERROR 360 +# define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220 +# define SSL_R_SRP_A_CALC 361 +# define SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES 362 +# define SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG 363 +# define SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE 364 +# define SSL_R_SSL3_EXT_INVALID_SERVERNAME 319 +# define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 320 +# define SSL_R_SSL3_SESSION_ID_TOO_LONG 300 +# define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042 +# define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 +# define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045 +# define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044 +# define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046 +# define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030 +# define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040 +# define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047 +# define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041 +# define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 +# define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043 +# define SSL_R_SSL_COMMAND_SECTION_EMPTY 117 +# define SSL_R_SSL_COMMAND_SECTION_NOT_FOUND 125 +# define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 228 +# define SSL_R_SSL_HANDSHAKE_FAILURE 229 +# define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS 230 +# define SSL_R_SSL_NEGATIVE_LENGTH 372 +# define SSL_R_SSL_SECTION_EMPTY 126 +# define SSL_R_SSL_SECTION_NOT_FOUND 136 +# define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 301 +# define SSL_R_SSL_SESSION_ID_CONFLICT 302 +# define SSL_R_SSL_SESSION_ID_TOO_LONG 408 +# define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273 +# define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303 +# define SSL_R_SSL_SESSION_VERSION_MISMATCH 210 +# define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 +# define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 +# define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 +# define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051 +# define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060 +# define SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK 1086 +# define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 +# define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 +# define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 +# define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070 +# define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022 +# define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048 +# define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 +# define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 +# define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 +# define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111 +# define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 +# define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 +# define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT 365 +# define SSL_R_TLS_HEARTBEAT_PENDING 366 +# define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 367 +# define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157 +# define SSL_R_TOO_MANY_WARN_ALERTS 409 +# define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 314 +# define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239 +# define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242 +# define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243 +# define SSL_R_UNEXPECTED_MESSAGE 244 +# define SSL_R_UNEXPECTED_RECORD 245 +# define SSL_R_UNINITIALIZED 276 +# define SSL_R_UNKNOWN_ALERT_TYPE 246 +# define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247 +# define SSL_R_UNKNOWN_CIPHER_RETURNED 248 +# define SSL_R_UNKNOWN_CIPHER_TYPE 249 +# define SSL_R_UNKNOWN_CMD_NAME 386 +# define SSL_R_UNKNOWN_COMMAND 139 +# define SSL_R_UNKNOWN_DIGEST 368 +# define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250 +# define SSL_R_UNKNOWN_PKEY_TYPE 251 +# define SSL_R_UNKNOWN_PROTOCOL 252 +# define SSL_R_UNKNOWN_SSL_VERSION 254 +# define SSL_R_UNKNOWN_STATE 255 +# define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 338 +# define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 +# define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315 +# define SSL_R_UNSUPPORTED_PROTOCOL 258 +# define SSL_R_UNSUPPORTED_SSL_VERSION 259 +# define SSL_R_UNSUPPORTED_STATUS_TYPE 329 +# define SSL_R_USE_SRTP_NOT_NEGOTIATED 369 +# define SSL_R_VERSION_TOO_HIGH 166 +# define SSL_R_VERSION_TOO_LOW 396 +# define SSL_R_WRONG_CERTIFICATE_TYPE 383 +# define SSL_R_WRONG_CIPHER_RETURNED 261 +# define SSL_R_WRONG_CURVE 378 +# define SSL_R_WRONG_SIGNATURE_LENGTH 264 +# define SSL_R_WRONG_SIGNATURE_SIZE 265 +# define SSL_R_WRONG_SIGNATURE_TYPE 370 +# define SSL_R_WRONG_SSL_VERSION 266 +# define SSL_R_WRONG_VERSION_NUMBER 267 +# define SSL_R_X509_LIB 268 +# define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ssl2.h b/mobile/ios/FxA/FxA/include/openssl/ssl2.h new file mode 100644 index 0000000000..5321bd272c --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ssl2.h @@ -0,0 +1,24 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_SSL2_H +# define HEADER_SSL2_H + +#ifdef __cplusplus +extern "C" { +#endif + +# define SSL2_VERSION 0x0002 + +# define SSL2_MT_CLIENT_HELLO 1 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ssl3.h b/mobile/ios/FxA/FxA/include/openssl/ssl3.h new file mode 100644 index 0000000000..4ca434e760 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ssl3.h @@ -0,0 +1,310 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_SSL3_H +# define HEADER_SSL3_H + +# include +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Signalling cipher suite value from RFC 5746 + * (TLS_EMPTY_RENEGOTIATION_INFO_SCSV) + */ +# define SSL3_CK_SCSV 0x030000FF + +/* + * Signalling cipher suite value from draft-ietf-tls-downgrade-scsv-00 + * (TLS_FALLBACK_SCSV) + */ +# define SSL3_CK_FALLBACK_SCSV 0x03005600 + +# define SSL3_CK_RSA_NULL_MD5 0x03000001 +# define SSL3_CK_RSA_NULL_SHA 0x03000002 +# define SSL3_CK_RSA_RC4_40_MD5 0x03000003 +# define SSL3_CK_RSA_RC4_128_MD5 0x03000004 +# define SSL3_CK_RSA_RC4_128_SHA 0x03000005 +# define SSL3_CK_RSA_RC2_40_MD5 0x03000006 +# define SSL3_CK_RSA_IDEA_128_SHA 0x03000007 +# define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008 +# define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009 +# define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A + +# define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B +# define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C +# define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D +# define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E +# define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F +# define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010 + +# define SSL3_CK_DHE_DSS_DES_40_CBC_SHA 0x03000011 +# define SSL3_CK_EDH_DSS_DES_40_CBC_SHA SSL3_CK_DHE_DSS_DES_40_CBC_SHA +# define SSL3_CK_DHE_DSS_DES_64_CBC_SHA 0x03000012 +# define SSL3_CK_EDH_DSS_DES_64_CBC_SHA SSL3_CK_DHE_DSS_DES_64_CBC_SHA +# define SSL3_CK_DHE_DSS_DES_192_CBC3_SHA 0x03000013 +# define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA SSL3_CK_DHE_DSS_DES_192_CBC3_SHA +# define SSL3_CK_DHE_RSA_DES_40_CBC_SHA 0x03000014 +# define SSL3_CK_EDH_RSA_DES_40_CBC_SHA SSL3_CK_DHE_RSA_DES_40_CBC_SHA +# define SSL3_CK_DHE_RSA_DES_64_CBC_SHA 0x03000015 +# define SSL3_CK_EDH_RSA_DES_64_CBC_SHA SSL3_CK_DHE_RSA_DES_64_CBC_SHA +# define SSL3_CK_DHE_RSA_DES_192_CBC3_SHA 0x03000016 +# define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA SSL3_CK_DHE_RSA_DES_192_CBC3_SHA + +# define SSL3_CK_ADH_RC4_40_MD5 0x03000017 +# define SSL3_CK_ADH_RC4_128_MD5 0x03000018 +# define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019 +# define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A +# define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B + +# define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5" +# define SSL3_TXT_RSA_NULL_SHA "NULL-SHA" +# define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5" +# define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5" +# define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA" +# define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5" +# define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA" +# define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA" +# define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA" +# define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA" + +# define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA" +# define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA" +# define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA" +# define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA" +# define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA" +# define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA" + +# define SSL3_TXT_DHE_DSS_DES_40_CBC_SHA "EXP-DHE-DSS-DES-CBC-SHA" +# define SSL3_TXT_DHE_DSS_DES_64_CBC_SHA "DHE-DSS-DES-CBC-SHA" +# define SSL3_TXT_DHE_DSS_DES_192_CBC3_SHA "DHE-DSS-DES-CBC3-SHA" +# define SSL3_TXT_DHE_RSA_DES_40_CBC_SHA "EXP-DHE-RSA-DES-CBC-SHA" +# define SSL3_TXT_DHE_RSA_DES_64_CBC_SHA "DHE-RSA-DES-CBC-SHA" +# define SSL3_TXT_DHE_RSA_DES_192_CBC3_SHA "DHE-RSA-DES-CBC3-SHA" + +/* + * This next block of six "EDH" labels is for backward compatibility with + * older versions of OpenSSL. New code should use the six "DHE" labels above + * instead: + */ +# define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA" +# define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA" +# define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA" +# define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA" +# define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA" +# define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA" + +# define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5" +# define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5" +# define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA" +# define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA" +# define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA" + +# define SSL3_SSL_SESSION_ID_LENGTH 32 +# define SSL3_MAX_SSL_SESSION_ID_LENGTH 32 + +# define SSL3_MASTER_SECRET_SIZE 48 +# define SSL3_RANDOM_SIZE 32 +# define SSL3_SESSION_ID_SIZE 32 +# define SSL3_RT_HEADER_LENGTH 5 + +# define SSL3_HM_HEADER_LENGTH 4 + +# ifndef SSL3_ALIGN_PAYLOAD + /* + * Some will argue that this increases memory footprint, but it's not + * actually true. Point is that malloc has to return at least 64-bit aligned + * pointers, meaning that allocating 5 bytes wastes 3 bytes in either case. + * Suggested pre-gaping simply moves these wasted bytes from the end of + * allocated region to its front, but makes data payload aligned, which + * improves performance:-) + */ +# define SSL3_ALIGN_PAYLOAD 8 +# else +# if (SSL3_ALIGN_PAYLOAD&(SSL3_ALIGN_PAYLOAD-1))!=0 +# error "insane SSL3_ALIGN_PAYLOAD" +# undef SSL3_ALIGN_PAYLOAD +# endif +# endif + +/* + * This is the maximum MAC (digest) size used by the SSL library. Currently + * maximum of 20 is used by SHA1, but we reserve for future extension for + * 512-bit hashes. + */ + +# define SSL3_RT_MAX_MD_SIZE 64 + +/* + * Maximum block size used in all ciphersuites. Currently 16 for AES. + */ + +# define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16 + +# define SSL3_RT_MAX_EXTRA (16384) + +/* Maximum plaintext length: defined by SSL/TLS standards */ +# define SSL3_RT_MAX_PLAIN_LENGTH 16384 +/* Maximum compression overhead: defined by SSL/TLS standards */ +# define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024 + +/* + * The standards give a maximum encryption overhead of 1024 bytes. In + * practice the value is lower than this. The overhead is the maximum number + * of padding bytes (256) plus the mac size. + */ +# define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE) + +/* + * OpenSSL currently only uses a padding length of at most one block so the + * send overhead is smaller. + */ + +# define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \ + (SSL_RT_MAX_CIPHER_BLOCK_SIZE + SSL3_RT_MAX_MD_SIZE) + +/* If compression isn't used don't include the compression overhead */ + +# ifdef OPENSSL_NO_COMP +# define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH +# else +# define SSL3_RT_MAX_COMPRESSED_LENGTH \ + (SSL3_RT_MAX_PLAIN_LENGTH+SSL3_RT_MAX_COMPRESSED_OVERHEAD) +# endif +# define SSL3_RT_MAX_ENCRYPTED_LENGTH \ + (SSL3_RT_MAX_ENCRYPTED_OVERHEAD+SSL3_RT_MAX_COMPRESSED_LENGTH) +# define SSL3_RT_MAX_PACKET_SIZE \ + (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH) + +# define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54" +# define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52" + +# define SSL3_VERSION 0x0300 +# define SSL3_VERSION_MAJOR 0x03 +# define SSL3_VERSION_MINOR 0x00 + +# define SSL3_RT_CHANGE_CIPHER_SPEC 20 +# define SSL3_RT_ALERT 21 +# define SSL3_RT_HANDSHAKE 22 +# define SSL3_RT_APPLICATION_DATA 23 +# define DTLS1_RT_HEARTBEAT 24 + +/* Pseudo content types to indicate additional parameters */ +# define TLS1_RT_CRYPTO 0x1000 +# define TLS1_RT_CRYPTO_PREMASTER (TLS1_RT_CRYPTO | 0x1) +# define TLS1_RT_CRYPTO_CLIENT_RANDOM (TLS1_RT_CRYPTO | 0x2) +# define TLS1_RT_CRYPTO_SERVER_RANDOM (TLS1_RT_CRYPTO | 0x3) +# define TLS1_RT_CRYPTO_MASTER (TLS1_RT_CRYPTO | 0x4) + +# define TLS1_RT_CRYPTO_READ 0x0000 +# define TLS1_RT_CRYPTO_WRITE 0x0100 +# define TLS1_RT_CRYPTO_MAC (TLS1_RT_CRYPTO | 0x5) +# define TLS1_RT_CRYPTO_KEY (TLS1_RT_CRYPTO | 0x6) +# define TLS1_RT_CRYPTO_IV (TLS1_RT_CRYPTO | 0x7) +# define TLS1_RT_CRYPTO_FIXED_IV (TLS1_RT_CRYPTO | 0x8) + +/* Pseudo content type for SSL/TLS header info */ +# define SSL3_RT_HEADER 0x100 + +# define SSL3_AL_WARNING 1 +# define SSL3_AL_FATAL 2 + +# define SSL3_AD_CLOSE_NOTIFY 0 +# define SSL3_AD_UNEXPECTED_MESSAGE 10/* fatal */ +# define SSL3_AD_BAD_RECORD_MAC 20/* fatal */ +# define SSL3_AD_DECOMPRESSION_FAILURE 30/* fatal */ +# define SSL3_AD_HANDSHAKE_FAILURE 40/* fatal */ +# define SSL3_AD_NO_CERTIFICATE 41 +# define SSL3_AD_BAD_CERTIFICATE 42 +# define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +# define SSL3_AD_CERTIFICATE_REVOKED 44 +# define SSL3_AD_CERTIFICATE_EXPIRED 45 +# define SSL3_AD_CERTIFICATE_UNKNOWN 46 +# define SSL3_AD_ILLEGAL_PARAMETER 47/* fatal */ + +# define TLS1_HB_REQUEST 1 +# define TLS1_HB_RESPONSE 2 + + +# define SSL3_CT_RSA_SIGN 1 +# define SSL3_CT_DSS_SIGN 2 +# define SSL3_CT_RSA_FIXED_DH 3 +# define SSL3_CT_DSS_FIXED_DH 4 +# define SSL3_CT_RSA_EPHEMERAL_DH 5 +# define SSL3_CT_DSS_EPHEMERAL_DH 6 +# define SSL3_CT_FORTEZZA_DMS 20 +/* + * SSL3_CT_NUMBER is used to size arrays and it must be large enough to + * contain all of the cert types defined either for SSLv3 and TLSv1. + */ +# define SSL3_CT_NUMBER 9 + +# define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001 + +/* Removed from OpenSSL 1.1.0 */ +# define TLS1_FLAGS_TLS_PADDING_BUG 0x0 + +# define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010 + +/* Set if we encrypt then mac instead of usual mac then encrypt */ +# define TLS1_FLAGS_ENCRYPT_THEN_MAC_READ 0x0100 +# define TLS1_FLAGS_ENCRYPT_THEN_MAC TLS1_FLAGS_ENCRYPT_THEN_MAC_READ + +/* Set if extended master secret extension received from peer */ +# define TLS1_FLAGS_RECEIVED_EXTMS 0x0200 + +# define TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE 0x0400 + +# define SSL3_MT_HELLO_REQUEST 0 +# define SSL3_MT_CLIENT_HELLO 1 +# define SSL3_MT_SERVER_HELLO 2 +# define SSL3_MT_NEWSESSION_TICKET 4 +# define SSL3_MT_CERTIFICATE 11 +# define SSL3_MT_SERVER_KEY_EXCHANGE 12 +# define SSL3_MT_CERTIFICATE_REQUEST 13 +# define SSL3_MT_SERVER_DONE 14 +# define SSL3_MT_CERTIFICATE_VERIFY 15 +# define SSL3_MT_CLIENT_KEY_EXCHANGE 16 +# define SSL3_MT_FINISHED 20 +# define SSL3_MT_CERTIFICATE_STATUS 22 +# ifndef OPENSSL_NO_NEXTPROTONEG +# define SSL3_MT_NEXT_PROTO 67 +# endif +# define DTLS1_MT_HELLO_VERIFY_REQUEST 3 + +/* Dummy message type for handling CCS like a normal handshake message */ +# define SSL3_MT_CHANGE_CIPHER_SPEC 0x0101 + +# define SSL3_MT_CCS 1 + +/* These are used when changing over to a new cipher */ +# define SSL3_CC_READ 0x01 +# define SSL3_CC_WRITE 0x02 +# define SSL3_CC_CLIENT 0x10 +# define SSL3_CC_SERVER 0x20 +# define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE) +# define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ) +# define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ) +# define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER|SSL3_CC_WRITE) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/stack.h b/mobile/ios/FxA/FxA/include/openssl/stack.h new file mode 100644 index 0000000000..23ad3b89f9 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/stack.h @@ -0,0 +1,78 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_STACK_H +# define HEADER_STACK_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct stack_st OPENSSL_STACK; /* Use STACK_OF(...) instead */ + +typedef int (*OPENSSL_sk_compfunc)(const void *, const void *); +typedef void (*OPENSSL_sk_freefunc)(void *); +typedef void *(*OPENSSL_sk_copyfunc)(const void *); + +int OPENSSL_sk_num(const OPENSSL_STACK *); +void *OPENSSL_sk_value(const OPENSSL_STACK *, int); + +void *OPENSSL_sk_set(OPENSSL_STACK *st, int i, const void *data); + +OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_compfunc cmp); +OPENSSL_STACK *OPENSSL_sk_new_null(void); +void OPENSSL_sk_free(OPENSSL_STACK *); +void OPENSSL_sk_pop_free(OPENSSL_STACK *st, void (*func) (void *)); +OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *, OPENSSL_sk_copyfunc c, OPENSSL_sk_freefunc f); +int OPENSSL_sk_insert(OPENSSL_STACK *sk, const void *data, int where); +void *OPENSSL_sk_delete(OPENSSL_STACK *st, int loc); +void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *st, const void *p); +int OPENSSL_sk_find(OPENSSL_STACK *st, const void *data); +int OPENSSL_sk_find_ex(OPENSSL_STACK *st, const void *data); +int OPENSSL_sk_push(OPENSSL_STACK *st, const void *data); +int OPENSSL_sk_unshift(OPENSSL_STACK *st, const void *data); +void *OPENSSL_sk_shift(OPENSSL_STACK *st); +void *OPENSSL_sk_pop(OPENSSL_STACK *st); +void OPENSSL_sk_zero(OPENSSL_STACK *st); +OPENSSL_sk_compfunc OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk, OPENSSL_sk_compfunc cmp); +OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *st); +void OPENSSL_sk_sort(OPENSSL_STACK *st); +int OPENSSL_sk_is_sorted(const OPENSSL_STACK *st); + +# if OPENSSL_API_COMPAT < 0x10100000L +# define _STACK OPENSSL_STACK +# define sk_num OPENSSL_sk_num +# define sk_value OPENSSL_sk_value +# define sk_set OPENSSL_sk_set +# define sk_new OPENSSL_sk_new +# define sk_new_null OPENSSL_sk_new_null +# define sk_free OPENSSL_sk_free +# define sk_pop_free OPENSSL_sk_pop_free +# define sk_deep_copy OPENSSL_sk_deep_copy +# define sk_insert OPENSSL_sk_insert +# define sk_delete OPENSSL_sk_delete +# define sk_delete_ptr OPENSSL_sk_delete_ptr +# define sk_find OPENSSL_sk_find +# define sk_find_ex OPENSSL_sk_find_ex +# define sk_push OPENSSL_sk_push +# define sk_unshift OPENSSL_sk_unshift +# define sk_shift OPENSSL_sk_shift +# define sk_pop OPENSSL_sk_pop +# define sk_zero OPENSSL_sk_zero +# define sk_set_cmp_func OPENSSL_sk_set_cmp_func +# define sk_dup OPENSSL_sk_dup +# define sk_sort OPENSSL_sk_sort +# define sk_is_sorted OPENSSL_sk_is_sorted +# endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/symhacks.h b/mobile/ios/FxA/FxA/include/openssl/symhacks.h new file mode 100644 index 0000000000..caf1f1a75d --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/symhacks.h @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_SYMHACKS_H +# define HEADER_SYMHACKS_H + +# include + +/* Case insensitive linking causes problems.... */ +# if defined(OPENSSL_SYS_VMS) +# undef ERR_load_CRYPTO_strings +# define ERR_load_CRYPTO_strings ERR_load_CRYPTOlib_strings +# undef OCSP_crlID_new +# define OCSP_crlID_new OCSP_crlID2_new + +# undef d2i_ECPARAMETERS +# define d2i_ECPARAMETERS d2i_UC_ECPARAMETERS +# undef i2d_ECPARAMETERS +# define i2d_ECPARAMETERS i2d_UC_ECPARAMETERS +# undef d2i_ECPKPARAMETERS +# define d2i_ECPKPARAMETERS d2i_UC_ECPKPARAMETERS +# undef i2d_ECPKPARAMETERS +# define i2d_ECPKPARAMETERS i2d_UC_ECPKPARAMETERS + +/* + * These functions do not seem to exist! However, I'm paranoid... Original + * command in x509v3.h: These functions are being redefined in another + * directory, and clash when the linker is case-insensitive, so let's hide + * them a little, by giving them an extra 'o' at the beginning of the name... + */ +# undef X509v3_cleanup_extensions +# define X509v3_cleanup_extensions oX509v3_cleanup_extensions +# undef X509v3_add_extension +# define X509v3_add_extension oX509v3_add_extension +# undef X509v3_add_netscape_extensions +# define X509v3_add_netscape_extensions oX509v3_add_netscape_extensions +# undef X509v3_add_standard_extensions +# define X509v3_add_standard_extensions oX509v3_add_standard_extensions + +/* This one clashes with CMS_data_create */ +# undef cms_Data_create +# define cms_Data_create priv_cms_Data_create + +# endif + +#endif /* ! defined HEADER_VMS_IDHACKS_H */ diff --git a/mobile/ios/FxA/FxA/include/openssl/tls1.h b/mobile/ios/FxA/FxA/include/openssl/tls1.h new file mode 100644 index 0000000000..23e382cdd3 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/tls1.h @@ -0,0 +1,972 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef HEADER_TLS1_H +# define HEADER_TLS1_H + +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Default security level if not overridden at config time */ +# ifndef OPENSSL_TLS_SECURITY_LEVEL +# define OPENSSL_TLS_SECURITY_LEVEL 1 +# endif + +# define TLS1_VERSION 0x0301 +# define TLS1_1_VERSION 0x0302 +# define TLS1_2_VERSION 0x0303 +# define TLS_MAX_VERSION TLS1_2_VERSION + +/* Special value for method supporting multiple versions */ +# define TLS_ANY_VERSION 0x10000 + +# define TLS1_VERSION_MAJOR 0x03 +# define TLS1_VERSION_MINOR 0x01 + +# define TLS1_1_VERSION_MAJOR 0x03 +# define TLS1_1_VERSION_MINOR 0x02 + +# define TLS1_2_VERSION_MAJOR 0x03 +# define TLS1_2_VERSION_MINOR 0x03 + +# define TLS1_get_version(s) \ + ((SSL_version(s) >> 8) == TLS1_VERSION_MAJOR ? SSL_version(s) : 0) + +# define TLS1_get_client_version(s) \ + ((SSL_client_version(s) >> 8) == TLS1_VERSION_MAJOR ? SSL_client_version(s) : 0) + +# define TLS1_AD_DECRYPTION_FAILED 21 +# define TLS1_AD_RECORD_OVERFLOW 22 +# define TLS1_AD_UNKNOWN_CA 48/* fatal */ +# define TLS1_AD_ACCESS_DENIED 49/* fatal */ +# define TLS1_AD_DECODE_ERROR 50/* fatal */ +# define TLS1_AD_DECRYPT_ERROR 51 +# define TLS1_AD_EXPORT_RESTRICTION 60/* fatal */ +# define TLS1_AD_PROTOCOL_VERSION 70/* fatal */ +# define TLS1_AD_INSUFFICIENT_SECURITY 71/* fatal */ +# define TLS1_AD_INTERNAL_ERROR 80/* fatal */ +# define TLS1_AD_INAPPROPRIATE_FALLBACK 86/* fatal */ +# define TLS1_AD_USER_CANCELLED 90 +# define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +# define TLS1_AD_UNSUPPORTED_EXTENSION 110 +# define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +# define TLS1_AD_UNRECOGNIZED_NAME 112 +# define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +# define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +# define TLS1_AD_UNKNOWN_PSK_IDENTITY 115/* fatal */ +# define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */ + +/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */ +# define TLSEXT_TYPE_server_name 0 +# define TLSEXT_TYPE_max_fragment_length 1 +# define TLSEXT_TYPE_client_certificate_url 2 +# define TLSEXT_TYPE_trusted_ca_keys 3 +# define TLSEXT_TYPE_truncated_hmac 4 +# define TLSEXT_TYPE_status_request 5 +/* ExtensionType values from RFC4681 */ +# define TLSEXT_TYPE_user_mapping 6 +/* ExtensionType values from RFC5878 */ +# define TLSEXT_TYPE_client_authz 7 +# define TLSEXT_TYPE_server_authz 8 +/* ExtensionType values from RFC6091 */ +# define TLSEXT_TYPE_cert_type 9 + +/* ExtensionType values from RFC4492 */ +# define TLSEXT_TYPE_elliptic_curves 10 +# define TLSEXT_TYPE_ec_point_formats 11 + +/* ExtensionType value from RFC5054 */ +# define TLSEXT_TYPE_srp 12 + +/* ExtensionType values from RFC5246 */ +# define TLSEXT_TYPE_signature_algorithms 13 + +/* ExtensionType value from RFC5764 */ +# define TLSEXT_TYPE_use_srtp 14 + +/* ExtensionType value from RFC5620 */ +# define TLSEXT_TYPE_heartbeat 15 + +/* ExtensionType value from RFC7301 */ +# define TLSEXT_TYPE_application_layer_protocol_negotiation 16 + +/* + * Extension type for Certificate Transparency + * https://tools.ietf.org/html/rfc6962#section-3.3.1 + */ +# define TLSEXT_TYPE_signed_certificate_timestamp 18 + +/* + * ExtensionType value for TLS padding extension. + * http://tools.ietf.org/html/draft-agl-tls-padding + */ +# define TLSEXT_TYPE_padding 21 + +/* ExtensionType value from RFC7366 */ +# define TLSEXT_TYPE_encrypt_then_mac 22 + +/* ExtensionType value from RFC7627 */ +# define TLSEXT_TYPE_extended_master_secret 23 + +/* ExtensionType value from RFC4507 */ +# define TLSEXT_TYPE_session_ticket 35 + +/* Temporary extension type */ +# define TLSEXT_TYPE_renegotiate 0xff01 + +# ifndef OPENSSL_NO_NEXTPROTONEG +/* This is not an IANA defined extension number */ +# define TLSEXT_TYPE_next_proto_neg 13172 +# endif + +/* NameType value from RFC3546 */ +# define TLSEXT_NAMETYPE_host_name 0 +/* status request value from RFC3546 */ +# define TLSEXT_STATUSTYPE_ocsp 1 + +/* ECPointFormat values from RFC4492 */ +# define TLSEXT_ECPOINTFORMAT_first 0 +# define TLSEXT_ECPOINTFORMAT_uncompressed 0 +# define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime 1 +# define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2 +# define TLSEXT_ECPOINTFORMAT_last 2 + +/* Signature and hash algorithms from RFC5246 */ +# define TLSEXT_signature_anonymous 0 +# define TLSEXT_signature_rsa 1 +# define TLSEXT_signature_dsa 2 +# define TLSEXT_signature_ecdsa 3 +# define TLSEXT_signature_gostr34102001 237 +# define TLSEXT_signature_gostr34102012_256 238 +# define TLSEXT_signature_gostr34102012_512 239 + +/* Total number of different signature algorithms */ +# define TLSEXT_signature_num 7 + +# define TLSEXT_hash_none 0 +# define TLSEXT_hash_md5 1 +# define TLSEXT_hash_sha1 2 +# define TLSEXT_hash_sha224 3 +# define TLSEXT_hash_sha256 4 +# define TLSEXT_hash_sha384 5 +# define TLSEXT_hash_sha512 6 +# define TLSEXT_hash_gostr3411 237 +# define TLSEXT_hash_gostr34112012_256 238 +# define TLSEXT_hash_gostr34112012_512 239 + +/* Total number of different digest algorithms */ + +# define TLSEXT_hash_num 10 + +/* Flag set for unrecognised algorithms */ +# define TLSEXT_nid_unknown 0x1000000 + +/* ECC curves */ + +# define TLSEXT_curve_P_256 23 +# define TLSEXT_curve_P_384 24 + +# define TLSEXT_MAXLEN_host_name 255 + +__owur const char *SSL_get_servername(const SSL *s, const int type); +__owur int SSL_get_servername_type(const SSL *s); +/* + * SSL_export_keying_material exports a value derived from the master secret, + * as specified in RFC 5705. It writes |olen| bytes to |out| given a label and + * optional context. (Since a zero length context is allowed, the |use_context| + * flag controls whether a context is included.) It returns 1 on success and + * zero otherwise. + */ +__owur int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen, + const char *label, size_t llen, + const unsigned char *p, size_t plen, + int use_context); + +int SSL_get_sigalgs(SSL *s, int idx, + int *psign, int *phash, int *psignandhash, + unsigned char *rsig, unsigned char *rhash); + +int SSL_get_shared_sigalgs(SSL *s, int idx, + int *psign, int *phash, int *psignandhash, + unsigned char *rsig, unsigned char *rhash); + +__owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain); + +# define SSL_set_tlsext_host_name(s,name) \ +SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name) + +# define SSL_set_tlsext_debug_callback(ssl, cb) \ +SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb) + +# define SSL_set_tlsext_debug_arg(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg) + +# define SSL_get_tlsext_status_type(ssl) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE,0, NULL) + +# define SSL_set_tlsext_status_type(ssl, type) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL) + +# define SSL_get_tlsext_status_exts(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) + +# define SSL_set_tlsext_status_exts(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) + +# define SSL_get_tlsext_status_ids(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) + +# define SSL_set_tlsext_status_ids(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) + +# define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg) + +# define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg) + +# define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ +SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb) + +# define SSL_TLSEXT_ERR_OK 0 +# define SSL_TLSEXT_ERR_ALERT_WARNING 1 +# define SSL_TLSEXT_ERR_ALERT_FATAL 2 +# define SSL_TLSEXT_ERR_NOACK 3 + +# define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \ +SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg) + +# define SSL_CTX_get_tlsext_ticket_keys(ctx, keys, keylen) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLSEXT_TICKET_KEYS,(keylen),(keys)) +# define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLSEXT_TICKET_KEYS,(keylen),(keys)) + +# define SSL_CTX_get_tlsext_status_cb(ssl, cb) \ +SSL_CTX_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB,0, (void (**)(void))cb) +# define SSL_CTX_set_tlsext_status_cb(ssl, cb) \ +SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb) + +# define SSL_CTX_get_tlsext_status_arg(ssl, arg) \ +SSL_CTX_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg +# define SSL_CTX_set_tlsext_status_arg(ssl, arg) \ +SSL_CTX_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg) + +#define SSL_CTX_set_tlsext_status_type(ssl, type) \ + SSL_CTX_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, type, NULL) + +#define SSL_CTX_get_tlsext_status_type(ssl) \ + SSL_CTX_ctrl(ssl, SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE, 0, NULL) + +# define SSL_CTX_set_tlsext_ticket_key_cb(ssl, cb) \ +SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb) + +# ifndef OPENSSL_NO_HEARTBEATS +# define SSL_DTLSEXT_HB_ENABLED 0x01 +# define SSL_DTLSEXT_HB_DONT_SEND_REQUESTS 0x02 +# define SSL_DTLSEXT_HB_DONT_RECV_REQUESTS 0x04 +# define SSL_get_dtlsext_heartbeat_pending(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_DTLS_EXT_HEARTBEAT_PENDING,0,NULL) +# define SSL_set_dtlsext_heartbeat_no_requests(ssl, arg) \ + SSL_ctrl((ssl),SSL_CTRL_SET_DTLS_EXT_HEARTBEAT_NO_REQUESTS,arg,NULL) + +# if OPENSSL_API_COMPAT < 0x10100000L +# define SSL_CTRL_TLS_EXT_SEND_HEARTBEAT \ + SSL_CTRL_DTLS_EXT_SEND_HEARTBEAT +# define SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING \ + SSL_CTRL_GET_DTLS_EXT_HEARTBEAT_PENDING +# define SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS \ + SSL_CTRL_SET_DTLS_EXT_HEARTBEAT_NO_REQUESTS +# define SSL_TLSEXT_HB_ENABLED \ + SSL_DTLSEXT_HB_ENABLED +# define SSL_TLSEXT_HB_DONT_SEND_REQUESTS \ + SSL_DTLSEXT_HB_DONT_SEND_REQUESTS +# define SSL_TLSEXT_HB_DONT_RECV_REQUESTS \ + SSL_DTLSEXT_HB_DONT_RECV_REQUESTS +# define SSL_get_tlsext_heartbeat_pending(ssl) \ + SSL_get_dtlsext_heartbeat_pending(ssl) +# define SSL_set_tlsext_heartbeat_no_requests(ssl, arg) \ + SSL_set_dtlsext_heartbeat_no_requests(ssl, arg) +# endif +# endif + +/* PSK ciphersuites from 4279 */ +# define TLS1_CK_PSK_WITH_RC4_128_SHA 0x0300008A +# define TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA 0x0300008B +# define TLS1_CK_PSK_WITH_AES_128_CBC_SHA 0x0300008C +# define TLS1_CK_PSK_WITH_AES_256_CBC_SHA 0x0300008D + +# define TLS1_CK_DHE_PSK_WITH_RC4_128_SHA 0x0300008E +# define TLS1_CK_DHE_PSK_WITH_3DES_EDE_CBC_SHA 0x0300008F +# define TLS1_CK_DHE_PSK_WITH_AES_128_CBC_SHA 0x03000090 +# define TLS1_CK_DHE_PSK_WITH_AES_256_CBC_SHA 0x03000091 + +# define TLS1_CK_RSA_PSK_WITH_RC4_128_SHA 0x03000092 +# define TLS1_CK_RSA_PSK_WITH_3DES_EDE_CBC_SHA 0x03000093 +# define TLS1_CK_RSA_PSK_WITH_AES_128_CBC_SHA 0x03000094 +# define TLS1_CK_RSA_PSK_WITH_AES_256_CBC_SHA 0x03000095 + +/* PSK ciphersuites from 5487 */ +# define TLS1_CK_PSK_WITH_AES_128_GCM_SHA256 0x030000A8 +# define TLS1_CK_PSK_WITH_AES_256_GCM_SHA384 0x030000A9 +# define TLS1_CK_DHE_PSK_WITH_AES_128_GCM_SHA256 0x030000AA +# define TLS1_CK_DHE_PSK_WITH_AES_256_GCM_SHA384 0x030000AB +# define TLS1_CK_RSA_PSK_WITH_AES_128_GCM_SHA256 0x030000AC +# define TLS1_CK_RSA_PSK_WITH_AES_256_GCM_SHA384 0x030000AD + +# define TLS1_CK_PSK_WITH_AES_128_CBC_SHA256 0x030000AE +# define TLS1_CK_PSK_WITH_AES_256_CBC_SHA384 0x030000AF +# define TLS1_CK_PSK_WITH_NULL_SHA256 0x030000B0 +# define TLS1_CK_PSK_WITH_NULL_SHA384 0x030000B1 + +# define TLS1_CK_DHE_PSK_WITH_AES_128_CBC_SHA256 0x030000B2 +# define TLS1_CK_DHE_PSK_WITH_AES_256_CBC_SHA384 0x030000B3 +# define TLS1_CK_DHE_PSK_WITH_NULL_SHA256 0x030000B4 +# define TLS1_CK_DHE_PSK_WITH_NULL_SHA384 0x030000B5 + +# define TLS1_CK_RSA_PSK_WITH_AES_128_CBC_SHA256 0x030000B6 +# define TLS1_CK_RSA_PSK_WITH_AES_256_CBC_SHA384 0x030000B7 +# define TLS1_CK_RSA_PSK_WITH_NULL_SHA256 0x030000B8 +# define TLS1_CK_RSA_PSK_WITH_NULL_SHA384 0x030000B9 + +/* NULL PSK ciphersuites from RFC4785 */ +# define TLS1_CK_PSK_WITH_NULL_SHA 0x0300002C +# define TLS1_CK_DHE_PSK_WITH_NULL_SHA 0x0300002D +# define TLS1_CK_RSA_PSK_WITH_NULL_SHA 0x0300002E + +/* AES ciphersuites from RFC3268 */ +# define TLS1_CK_RSA_WITH_AES_128_SHA 0x0300002F +# define TLS1_CK_DH_DSS_WITH_AES_128_SHA 0x03000030 +# define TLS1_CK_DH_RSA_WITH_AES_128_SHA 0x03000031 +# define TLS1_CK_DHE_DSS_WITH_AES_128_SHA 0x03000032 +# define TLS1_CK_DHE_RSA_WITH_AES_128_SHA 0x03000033 +# define TLS1_CK_ADH_WITH_AES_128_SHA 0x03000034 + +# define TLS1_CK_RSA_WITH_AES_256_SHA 0x03000035 +# define TLS1_CK_DH_DSS_WITH_AES_256_SHA 0x03000036 +# define TLS1_CK_DH_RSA_WITH_AES_256_SHA 0x03000037 +# define TLS1_CK_DHE_DSS_WITH_AES_256_SHA 0x03000038 +# define TLS1_CK_DHE_RSA_WITH_AES_256_SHA 0x03000039 +# define TLS1_CK_ADH_WITH_AES_256_SHA 0x0300003A + +/* TLS v1.2 ciphersuites */ +# define TLS1_CK_RSA_WITH_NULL_SHA256 0x0300003B +# define TLS1_CK_RSA_WITH_AES_128_SHA256 0x0300003C +# define TLS1_CK_RSA_WITH_AES_256_SHA256 0x0300003D +# define TLS1_CK_DH_DSS_WITH_AES_128_SHA256 0x0300003E +# define TLS1_CK_DH_RSA_WITH_AES_128_SHA256 0x0300003F +# define TLS1_CK_DHE_DSS_WITH_AES_128_SHA256 0x03000040 + +/* Camellia ciphersuites from RFC4132 */ +# define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000041 +# define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000042 +# define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000043 +# define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000044 +# define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000045 +# define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA 0x03000046 + +/* TLS v1.2 ciphersuites */ +# define TLS1_CK_DHE_RSA_WITH_AES_128_SHA256 0x03000067 +# define TLS1_CK_DH_DSS_WITH_AES_256_SHA256 0x03000068 +# define TLS1_CK_DH_RSA_WITH_AES_256_SHA256 0x03000069 +# define TLS1_CK_DHE_DSS_WITH_AES_256_SHA256 0x0300006A +# define TLS1_CK_DHE_RSA_WITH_AES_256_SHA256 0x0300006B +# define TLS1_CK_ADH_WITH_AES_128_SHA256 0x0300006C +# define TLS1_CK_ADH_WITH_AES_256_SHA256 0x0300006D + +/* Camellia ciphersuites from RFC4132 */ +# define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000084 +# define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000085 +# define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000086 +# define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000087 +# define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000088 +# define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA 0x03000089 + +/* SEED ciphersuites from RFC4162 */ +# define TLS1_CK_RSA_WITH_SEED_SHA 0x03000096 +# define TLS1_CK_DH_DSS_WITH_SEED_SHA 0x03000097 +# define TLS1_CK_DH_RSA_WITH_SEED_SHA 0x03000098 +# define TLS1_CK_DHE_DSS_WITH_SEED_SHA 0x03000099 +# define TLS1_CK_DHE_RSA_WITH_SEED_SHA 0x0300009A +# define TLS1_CK_ADH_WITH_SEED_SHA 0x0300009B + +/* TLS v1.2 GCM ciphersuites from RFC5288 */ +# define TLS1_CK_RSA_WITH_AES_128_GCM_SHA256 0x0300009C +# define TLS1_CK_RSA_WITH_AES_256_GCM_SHA384 0x0300009D +# define TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 0x0300009E +# define TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384 0x0300009F +# define TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256 0x030000A0 +# define TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384 0x030000A1 +# define TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256 0x030000A2 +# define TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384 0x030000A3 +# define TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256 0x030000A4 +# define TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384 0x030000A5 +# define TLS1_CK_ADH_WITH_AES_128_GCM_SHA256 0x030000A6 +# define TLS1_CK_ADH_WITH_AES_256_GCM_SHA384 0x030000A7 + +/* CCM ciphersuites from RFC6655 */ +# define TLS1_CK_RSA_WITH_AES_128_CCM 0x0300C09C +# define TLS1_CK_RSA_WITH_AES_256_CCM 0x0300C09D +# define TLS1_CK_DHE_RSA_WITH_AES_128_CCM 0x0300C09E +# define TLS1_CK_DHE_RSA_WITH_AES_256_CCM 0x0300C09F +# define TLS1_CK_RSA_WITH_AES_128_CCM_8 0x0300C0A0 +# define TLS1_CK_RSA_WITH_AES_256_CCM_8 0x0300C0A1 +# define TLS1_CK_DHE_RSA_WITH_AES_128_CCM_8 0x0300C0A2 +# define TLS1_CK_DHE_RSA_WITH_AES_256_CCM_8 0x0300C0A3 +# define TLS1_CK_PSK_WITH_AES_128_CCM 0x0300C0A4 +# define TLS1_CK_PSK_WITH_AES_256_CCM 0x0300C0A5 +# define TLS1_CK_DHE_PSK_WITH_AES_128_CCM 0x0300C0A6 +# define TLS1_CK_DHE_PSK_WITH_AES_256_CCM 0x0300C0A7 +# define TLS1_CK_PSK_WITH_AES_128_CCM_8 0x0300C0A8 +# define TLS1_CK_PSK_WITH_AES_256_CCM_8 0x0300C0A9 +# define TLS1_CK_DHE_PSK_WITH_AES_128_CCM_8 0x0300C0AA +# define TLS1_CK_DHE_PSK_WITH_AES_256_CCM_8 0x0300C0AB + +/* CCM ciphersuites from RFC7251 */ +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CCM 0x0300C0AC +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CCM 0x0300C0AD +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CCM_8 0x0300C0AE +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CCM_8 0x0300C0AF + +/* TLS 1.2 Camellia SHA-256 ciphersuites from RFC5932 */ +# define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA256 0x030000BA +# define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 0x030000BB +# define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 0x030000BC +# define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 0x030000BD +# define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0x030000BE +# define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA256 0x030000BF + +# define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA256 0x030000C0 +# define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 0x030000C1 +# define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 0x030000C2 +# define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 0x030000C3 +# define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 0x030000C4 +# define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA256 0x030000C5 + +/* ECC ciphersuites from RFC4492 */ +# define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x0300C001 +# define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x0300C002 +# define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C003 +# define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x0300C004 +# define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x0300C005 + +# define TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA 0x0300C006 +# define TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA 0x0300C007 +# define TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C008 +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x0300C009 +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0x0300C00A + +# define TLS1_CK_ECDH_RSA_WITH_NULL_SHA 0x0300C00B +# define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA 0x0300C00C +# define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA 0x0300C00D +# define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA 0x0300C00E +# define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA 0x0300C00F + +# define TLS1_CK_ECDHE_RSA_WITH_NULL_SHA 0x0300C010 +# define TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA 0x0300C011 +# define TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA 0x0300C012 +# define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0300C013 +# define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA 0x0300C014 + +# define TLS1_CK_ECDH_anon_WITH_NULL_SHA 0x0300C015 +# define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA 0x0300C016 +# define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA 0x0300C017 +# define TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA 0x0300C018 +# define TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA 0x0300C019 + +/* SRP ciphersuites from RFC 5054 */ +# define TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA 0x0300C01A +# define TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA 0x0300C01B +# define TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA 0x0300C01C +# define TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA 0x0300C01D +# define TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA 0x0300C01E +# define TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA 0x0300C01F +# define TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA 0x0300C020 +# define TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA 0x0300C021 +# define TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA 0x0300C022 + +/* ECDH HMAC based ciphersuites from RFC5289 */ + +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256 0x0300C023 +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384 0x0300C024 +# define TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256 0x0300C025 +# define TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384 0x0300C026 +# define TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256 0x0300C027 +# define TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384 0x0300C028 +# define TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256 0x0300C029 +# define TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384 0x0300C02A + +/* ECDH GCM based ciphersuites from RFC5289 */ +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02B +# define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02C +# define TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02D +# define TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02E +# define TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0x0300C02F +# define TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0x0300C030 +# define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256 0x0300C031 +# define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384 0x0300C032 + +/* ECDHE PSK ciphersuites from RFC5489 */ +# define TLS1_CK_ECDHE_PSK_WITH_RC4_128_SHA 0x0300C033 +# define TLS1_CK_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA 0x0300C034 +# define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA 0x0300C035 +# define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA 0x0300C036 + +# define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256 0x0300C037 +# define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384 0x0300C038 + +/* NULL PSK ciphersuites from RFC4785 */ + +# define TLS1_CK_ECDHE_PSK_WITH_NULL_SHA 0x0300C039 +# define TLS1_CK_ECDHE_PSK_WITH_NULL_SHA256 0x0300C03A +# define TLS1_CK_ECDHE_PSK_WITH_NULL_SHA384 0x0300C03B + +/* Camellia-CBC ciphersuites from RFC6367 */ +# define TLS1_CK_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0x0300C072 +# define TLS1_CK_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0x0300C073 +# define TLS1_CK_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0x0300C074 +# define TLS1_CK_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0x0300C075 +# define TLS1_CK_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0x0300C076 +# define TLS1_CK_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 0x0300C077 +# define TLS1_CK_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 0x0300C078 +# define TLS1_CK_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 0x0300C079 + +# define TLS1_CK_PSK_WITH_CAMELLIA_128_CBC_SHA256 0x0300C094 +# define TLS1_CK_PSK_WITH_CAMELLIA_256_CBC_SHA384 0x0300C095 +# define TLS1_CK_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0x0300C096 +# define TLS1_CK_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0x0300C097 +# define TLS1_CK_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 0x0300C098 +# define TLS1_CK_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 0x0300C099 +# define TLS1_CK_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0x0300C09A +# define TLS1_CK_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0x0300C09B + +/* draft-ietf-tls-chacha20-poly1305-03 */ +# define TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305 0x0300CCA8 +# define TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 0x0300CCA9 +# define TLS1_CK_DHE_RSA_WITH_CHACHA20_POLY1305 0x0300CCAA +# define TLS1_CK_PSK_WITH_CHACHA20_POLY1305 0x0300CCAB +# define TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305 0x0300CCAC +# define TLS1_CK_DHE_PSK_WITH_CHACHA20_POLY1305 0x0300CCAD +# define TLS1_CK_RSA_PSK_WITH_CHACHA20_POLY1305 0x0300CCAE + +/* + * XXX Backward compatibility alert: Older versions of OpenSSL gave some DHE + * ciphers names with "EDH" instead of "DHE". Going forward, we should be + * using DHE everywhere, though we may indefinitely maintain aliases for + * users or configurations that used "EDH" + */ +# define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA "DHE-DSS-RC4-SHA" + +# define TLS1_TXT_PSK_WITH_NULL_SHA "PSK-NULL-SHA" +# define TLS1_TXT_DHE_PSK_WITH_NULL_SHA "DHE-PSK-NULL-SHA" +# define TLS1_TXT_RSA_PSK_WITH_NULL_SHA "RSA-PSK-NULL-SHA" + +/* AES ciphersuites from RFC3268 */ +# define TLS1_TXT_RSA_WITH_AES_128_SHA "AES128-SHA" +# define TLS1_TXT_DH_DSS_WITH_AES_128_SHA "DH-DSS-AES128-SHA" +# define TLS1_TXT_DH_RSA_WITH_AES_128_SHA "DH-RSA-AES128-SHA" +# define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA "DHE-DSS-AES128-SHA" +# define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA "DHE-RSA-AES128-SHA" +# define TLS1_TXT_ADH_WITH_AES_128_SHA "ADH-AES128-SHA" + +# define TLS1_TXT_RSA_WITH_AES_256_SHA "AES256-SHA" +# define TLS1_TXT_DH_DSS_WITH_AES_256_SHA "DH-DSS-AES256-SHA" +# define TLS1_TXT_DH_RSA_WITH_AES_256_SHA "DH-RSA-AES256-SHA" +# define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA "DHE-DSS-AES256-SHA" +# define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA" +# define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA" + +/* ECC ciphersuites from RFC4492 */ +# define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA" +# define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA" +# define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA" +# define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA "ECDH-ECDSA-AES128-SHA" +# define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA "ECDH-ECDSA-AES256-SHA" + +# define TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA "ECDHE-ECDSA-NULL-SHA" +# define TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA "ECDHE-ECDSA-RC4-SHA" +# define TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA "ECDHE-ECDSA-DES-CBC3-SHA" +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA "ECDHE-ECDSA-AES128-SHA" +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA "ECDHE-ECDSA-AES256-SHA" + +# define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA "ECDH-RSA-NULL-SHA" +# define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA "ECDH-RSA-RC4-SHA" +# define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA "ECDH-RSA-DES-CBC3-SHA" +# define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA "ECDH-RSA-AES128-SHA" +# define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA "ECDH-RSA-AES256-SHA" + +# define TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA "ECDHE-RSA-NULL-SHA" +# define TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA "ECDHE-RSA-RC4-SHA" +# define TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA "ECDHE-RSA-DES-CBC3-SHA" +# define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA" +# define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA "ECDHE-RSA-AES256-SHA" + +# define TLS1_TXT_ECDH_anon_WITH_NULL_SHA "AECDH-NULL-SHA" +# define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA "AECDH-RC4-SHA" +# define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA "AECDH-DES-CBC3-SHA" +# define TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA "AECDH-AES128-SHA" +# define TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA "AECDH-AES256-SHA" + +/* PSK ciphersuites from RFC 4279 */ +# define TLS1_TXT_PSK_WITH_RC4_128_SHA "PSK-RC4-SHA" +# define TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA "PSK-3DES-EDE-CBC-SHA" +# define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA "PSK-AES128-CBC-SHA" +# define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA "PSK-AES256-CBC-SHA" + +# define TLS1_TXT_DHE_PSK_WITH_RC4_128_SHA "DHE-PSK-RC4-SHA" +# define TLS1_TXT_DHE_PSK_WITH_3DES_EDE_CBC_SHA "DHE-PSK-3DES-EDE-CBC-SHA" +# define TLS1_TXT_DHE_PSK_WITH_AES_128_CBC_SHA "DHE-PSK-AES128-CBC-SHA" +# define TLS1_TXT_DHE_PSK_WITH_AES_256_CBC_SHA "DHE-PSK-AES256-CBC-SHA" +# define TLS1_TXT_RSA_PSK_WITH_RC4_128_SHA "RSA-PSK-RC4-SHA" +# define TLS1_TXT_RSA_PSK_WITH_3DES_EDE_CBC_SHA "RSA-PSK-3DES-EDE-CBC-SHA" +# define TLS1_TXT_RSA_PSK_WITH_AES_128_CBC_SHA "RSA-PSK-AES128-CBC-SHA" +# define TLS1_TXT_RSA_PSK_WITH_AES_256_CBC_SHA "RSA-PSK-AES256-CBC-SHA" + +/* PSK ciphersuites from RFC 5487 */ +# define TLS1_TXT_PSK_WITH_AES_128_GCM_SHA256 "PSK-AES128-GCM-SHA256" +# define TLS1_TXT_PSK_WITH_AES_256_GCM_SHA384 "PSK-AES256-GCM-SHA384" +# define TLS1_TXT_DHE_PSK_WITH_AES_128_GCM_SHA256 "DHE-PSK-AES128-GCM-SHA256" +# define TLS1_TXT_DHE_PSK_WITH_AES_256_GCM_SHA384 "DHE-PSK-AES256-GCM-SHA384" +# define TLS1_TXT_RSA_PSK_WITH_AES_128_GCM_SHA256 "RSA-PSK-AES128-GCM-SHA256" +# define TLS1_TXT_RSA_PSK_WITH_AES_256_GCM_SHA384 "RSA-PSK-AES256-GCM-SHA384" + +# define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA256 "PSK-AES128-CBC-SHA256" +# define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA384 "PSK-AES256-CBC-SHA384" +# define TLS1_TXT_PSK_WITH_NULL_SHA256 "PSK-NULL-SHA256" +# define TLS1_TXT_PSK_WITH_NULL_SHA384 "PSK-NULL-SHA384" + +# define TLS1_TXT_DHE_PSK_WITH_AES_128_CBC_SHA256 "DHE-PSK-AES128-CBC-SHA256" +# define TLS1_TXT_DHE_PSK_WITH_AES_256_CBC_SHA384 "DHE-PSK-AES256-CBC-SHA384" +# define TLS1_TXT_DHE_PSK_WITH_NULL_SHA256 "DHE-PSK-NULL-SHA256" +# define TLS1_TXT_DHE_PSK_WITH_NULL_SHA384 "DHE-PSK-NULL-SHA384" + +# define TLS1_TXT_RSA_PSK_WITH_AES_128_CBC_SHA256 "RSA-PSK-AES128-CBC-SHA256" +# define TLS1_TXT_RSA_PSK_WITH_AES_256_CBC_SHA384 "RSA-PSK-AES256-CBC-SHA384" +# define TLS1_TXT_RSA_PSK_WITH_NULL_SHA256 "RSA-PSK-NULL-SHA256" +# define TLS1_TXT_RSA_PSK_WITH_NULL_SHA384 "RSA-PSK-NULL-SHA384" + +/* SRP ciphersuite from RFC 5054 */ +# define TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA "SRP-3DES-EDE-CBC-SHA" +# define TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA "SRP-RSA-3DES-EDE-CBC-SHA" +# define TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA "SRP-DSS-3DES-EDE-CBC-SHA" +# define TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA "SRP-AES-128-CBC-SHA" +# define TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA "SRP-RSA-AES-128-CBC-SHA" +# define TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA "SRP-DSS-AES-128-CBC-SHA" +# define TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA "SRP-AES-256-CBC-SHA" +# define TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA "SRP-RSA-AES-256-CBC-SHA" +# define TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA "SRP-DSS-AES-256-CBC-SHA" + +/* Camellia ciphersuites from RFC4132 */ +# define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA "CAMELLIA128-SHA" +# define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA "DH-DSS-CAMELLIA128-SHA" +# define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA "DH-RSA-CAMELLIA128-SHA" +# define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA "DHE-DSS-CAMELLIA128-SHA" +# define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA "DHE-RSA-CAMELLIA128-SHA" +# define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA "ADH-CAMELLIA128-SHA" + +# define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA "CAMELLIA256-SHA" +# define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA "DH-DSS-CAMELLIA256-SHA" +# define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA "DH-RSA-CAMELLIA256-SHA" +# define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA "DHE-DSS-CAMELLIA256-SHA" +# define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA "DHE-RSA-CAMELLIA256-SHA" +# define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA "ADH-CAMELLIA256-SHA" + +/* TLS 1.2 Camellia SHA-256 ciphersuites from RFC5932 */ +# define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA256 "CAMELLIA128-SHA256" +# define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 "DH-DSS-CAMELLIA128-SHA256" +# define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 "DH-RSA-CAMELLIA128-SHA256" +# define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 "DHE-DSS-CAMELLIA128-SHA256" +# define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 "DHE-RSA-CAMELLIA128-SHA256" +# define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA256 "ADH-CAMELLIA128-SHA256" + +# define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA256 "CAMELLIA256-SHA256" +# define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 "DH-DSS-CAMELLIA256-SHA256" +# define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 "DH-RSA-CAMELLIA256-SHA256" +# define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 "DHE-DSS-CAMELLIA256-SHA256" +# define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 "DHE-RSA-CAMELLIA256-SHA256" +# define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA256 "ADH-CAMELLIA256-SHA256" + +# define TLS1_TXT_PSK_WITH_CAMELLIA_128_CBC_SHA256 "PSK-CAMELLIA128-SHA256" +# define TLS1_TXT_PSK_WITH_CAMELLIA_256_CBC_SHA384 "PSK-CAMELLIA256-SHA384" +# define TLS1_TXT_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 "DHE-PSK-CAMELLIA128-SHA256" +# define TLS1_TXT_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 "DHE-PSK-CAMELLIA256-SHA384" +# define TLS1_TXT_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 "RSA-PSK-CAMELLIA128-SHA256" +# define TLS1_TXT_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 "RSA-PSK-CAMELLIA256-SHA384" +# define TLS1_TXT_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 "ECDHE-PSK-CAMELLIA128-SHA256" +# define TLS1_TXT_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 "ECDHE-PSK-CAMELLIA256-SHA384" + +/* SEED ciphersuites from RFC4162 */ +# define TLS1_TXT_RSA_WITH_SEED_SHA "SEED-SHA" +# define TLS1_TXT_DH_DSS_WITH_SEED_SHA "DH-DSS-SEED-SHA" +# define TLS1_TXT_DH_RSA_WITH_SEED_SHA "DH-RSA-SEED-SHA" +# define TLS1_TXT_DHE_DSS_WITH_SEED_SHA "DHE-DSS-SEED-SHA" +# define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA" +# define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA" + +/* TLS v1.2 ciphersuites */ +# define TLS1_TXT_RSA_WITH_NULL_SHA256 "NULL-SHA256" +# define TLS1_TXT_RSA_WITH_AES_128_SHA256 "AES128-SHA256" +# define TLS1_TXT_RSA_WITH_AES_256_SHA256 "AES256-SHA256" +# define TLS1_TXT_DH_DSS_WITH_AES_128_SHA256 "DH-DSS-AES128-SHA256" +# define TLS1_TXT_DH_RSA_WITH_AES_128_SHA256 "DH-RSA-AES128-SHA256" +# define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256 "DHE-DSS-AES128-SHA256" +# define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 "DHE-RSA-AES128-SHA256" +# define TLS1_TXT_DH_DSS_WITH_AES_256_SHA256 "DH-DSS-AES256-SHA256" +# define TLS1_TXT_DH_RSA_WITH_AES_256_SHA256 "DH-RSA-AES256-SHA256" +# define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256 "DHE-DSS-AES256-SHA256" +# define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 "DHE-RSA-AES256-SHA256" +# define TLS1_TXT_ADH_WITH_AES_128_SHA256 "ADH-AES128-SHA256" +# define TLS1_TXT_ADH_WITH_AES_256_SHA256 "ADH-AES256-SHA256" + +/* TLS v1.2 GCM ciphersuites from RFC5288 */ +# define TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256 "AES128-GCM-SHA256" +# define TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 "AES256-GCM-SHA384" +# define TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 "DHE-RSA-AES128-GCM-SHA256" +# define TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 "DHE-RSA-AES256-GCM-SHA384" +# define TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256 "DH-RSA-AES128-GCM-SHA256" +# define TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384 "DH-RSA-AES256-GCM-SHA384" +# define TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256 "DHE-DSS-AES128-GCM-SHA256" +# define TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384 "DHE-DSS-AES256-GCM-SHA384" +# define TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256 "DH-DSS-AES128-GCM-SHA256" +# define TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384 "DH-DSS-AES256-GCM-SHA384" +# define TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256 "ADH-AES128-GCM-SHA256" +# define TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384 "ADH-AES256-GCM-SHA384" + +/* CCM ciphersuites from RFC6655 */ + +# define TLS1_TXT_RSA_WITH_AES_128_CCM "AES128-CCM" +# define TLS1_TXT_RSA_WITH_AES_256_CCM "AES256-CCM" +# define TLS1_TXT_DHE_RSA_WITH_AES_128_CCM "DHE-RSA-AES128-CCM" +# define TLS1_TXT_DHE_RSA_WITH_AES_256_CCM "DHE-RSA-AES256-CCM" + +# define TLS1_TXT_RSA_WITH_AES_128_CCM_8 "AES128-CCM8" +# define TLS1_TXT_RSA_WITH_AES_256_CCM_8 "AES256-CCM8" +# define TLS1_TXT_DHE_RSA_WITH_AES_128_CCM_8 "DHE-RSA-AES128-CCM8" +# define TLS1_TXT_DHE_RSA_WITH_AES_256_CCM_8 "DHE-RSA-AES256-CCM8" + +# define TLS1_TXT_PSK_WITH_AES_128_CCM "PSK-AES128-CCM" +# define TLS1_TXT_PSK_WITH_AES_256_CCM "PSK-AES256-CCM" +# define TLS1_TXT_DHE_PSK_WITH_AES_128_CCM "DHE-PSK-AES128-CCM" +# define TLS1_TXT_DHE_PSK_WITH_AES_256_CCM "DHE-PSK-AES256-CCM" + +# define TLS1_TXT_PSK_WITH_AES_128_CCM_8 "PSK-AES128-CCM8" +# define TLS1_TXT_PSK_WITH_AES_256_CCM_8 "PSK-AES256-CCM8" +# define TLS1_TXT_DHE_PSK_WITH_AES_128_CCM_8 "DHE-PSK-AES128-CCM8" +# define TLS1_TXT_DHE_PSK_WITH_AES_256_CCM_8 "DHE-PSK-AES256-CCM8" + +/* CCM ciphersuites from RFC7251 */ + +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CCM "ECDHE-ECDSA-AES128-CCM" +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CCM "ECDHE-ECDSA-AES256-CCM" +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CCM_8 "ECDHE-ECDSA-AES128-CCM8" +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CCM_8 "ECDHE-ECDSA-AES256-CCM8" + +/* ECDH HMAC based ciphersuites from RFC5289 */ + +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256 "ECDHE-ECDSA-AES128-SHA256" +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384 "ECDHE-ECDSA-AES256-SHA384" +# define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256 "ECDH-ECDSA-AES128-SHA256" +# define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384 "ECDH-ECDSA-AES256-SHA384" +# define TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 "ECDHE-RSA-AES128-SHA256" +# define TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 "ECDHE-RSA-AES256-SHA384" +# define TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256 "ECDH-RSA-AES128-SHA256" +# define TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384 "ECDH-RSA-AES256-SHA384" + +/* ECDH GCM based ciphersuites from RFC5289 */ +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 "ECDHE-ECDSA-AES128-GCM-SHA256" +# define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 "ECDHE-ECDSA-AES256-GCM-SHA384" +# define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 "ECDH-ECDSA-AES128-GCM-SHA256" +# define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 "ECDH-ECDSA-AES256-GCM-SHA384" +# define TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 "ECDHE-RSA-AES128-GCM-SHA256" +# define TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 "ECDHE-RSA-AES256-GCM-SHA384" +# define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256 "ECDH-RSA-AES128-GCM-SHA256" +# define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384 "ECDH-RSA-AES256-GCM-SHA384" + +/* TLS v1.2 PSK GCM ciphersuites from RFC5487 */ +# define TLS1_TXT_PSK_WITH_AES_128_GCM_SHA256 "PSK-AES128-GCM-SHA256" +# define TLS1_TXT_PSK_WITH_AES_256_GCM_SHA384 "PSK-AES256-GCM-SHA384" + +/* ECDHE PSK ciphersuites from RFC 5489 */ +# define TLS1_TXT_ECDHE_PSK_WITH_RC4_128_SHA "ECDHE-PSK-RC4-SHA" +# define TLS1_TXT_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA "ECDHE-PSK-3DES-EDE-CBC-SHA" +# define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA "ECDHE-PSK-AES128-CBC-SHA" +# define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA "ECDHE-PSK-AES256-CBC-SHA" + +# define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256 "ECDHE-PSK-AES128-CBC-SHA256" +# define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384 "ECDHE-PSK-AES256-CBC-SHA384" + +# define TLS1_TXT_ECDHE_PSK_WITH_NULL_SHA "ECDHE-PSK-NULL-SHA" +# define TLS1_TXT_ECDHE_PSK_WITH_NULL_SHA256 "ECDHE-PSK-NULL-SHA256" +# define TLS1_TXT_ECDHE_PSK_WITH_NULL_SHA384 "ECDHE-PSK-NULL-SHA384" + +/* Camellia-CBC ciphersuites from RFC6367 */ +# define TLS1_TXT_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 "ECDHE-ECDSA-CAMELLIA128-SHA256" +# define TLS1_TXT_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 "ECDHE-ECDSA-CAMELLIA256-SHA384" +# define TLS1_TXT_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 "ECDH-ECDSA-CAMELLIA128-SHA256" +# define TLS1_TXT_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 "ECDH-ECDSA-CAMELLIA256-SHA384" +# define TLS1_TXT_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 "ECDHE-RSA-CAMELLIA128-SHA256" +# define TLS1_TXT_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 "ECDHE-RSA-CAMELLIA256-SHA384" +# define TLS1_TXT_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 "ECDH-RSA-CAMELLIA128-SHA256" +# define TLS1_TXT_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 "ECDH-RSA-CAMELLIA256-SHA384" + +/* draft-ietf-tls-chacha20-poly1305-03 */ +# define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 "ECDHE-RSA-CHACHA20-POLY1305" +# define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "ECDHE-ECDSA-CHACHA20-POLY1305" +# define TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 "DHE-RSA-CHACHA20-POLY1305" +# define TLS1_TXT_PSK_WITH_CHACHA20_POLY1305 "PSK-CHACHA20-POLY1305" +# define TLS1_TXT_ECDHE_PSK_WITH_CHACHA20_POLY1305 "ECDHE-PSK-CHACHA20-POLY1305" +# define TLS1_TXT_DHE_PSK_WITH_CHACHA20_POLY1305 "DHE-PSK-CHACHA20-POLY1305" +# define TLS1_TXT_RSA_PSK_WITH_CHACHA20_POLY1305 "RSA-PSK-CHACHA20-POLY1305" + +# define TLS_CT_RSA_SIGN 1 +# define TLS_CT_DSS_SIGN 2 +# define TLS_CT_RSA_FIXED_DH 3 +# define TLS_CT_DSS_FIXED_DH 4 +# define TLS_CT_ECDSA_SIGN 64 +# define TLS_CT_RSA_FIXED_ECDH 65 +# define TLS_CT_ECDSA_FIXED_ECDH 66 +# define TLS_CT_GOST01_SIGN 22 +# define TLS_CT_GOST12_SIGN 238 +# define TLS_CT_GOST12_512_SIGN 239 + +/* + * when correcting this number, correct also SSL3_CT_NUMBER in ssl3.h (see + * comment there) + */ +# define TLS_CT_NUMBER 9 + +# define TLS1_FINISH_MAC_LENGTH 12 + +# define TLS_MD_MAX_CONST_SIZE 22 +# define TLS_MD_CLIENT_FINISH_CONST "client finished" +# define TLS_MD_CLIENT_FINISH_CONST_SIZE 15 +# define TLS_MD_SERVER_FINISH_CONST "server finished" +# define TLS_MD_SERVER_FINISH_CONST_SIZE 15 +# define TLS_MD_KEY_EXPANSION_CONST "key expansion" +# define TLS_MD_KEY_EXPANSION_CONST_SIZE 13 +# define TLS_MD_CLIENT_WRITE_KEY_CONST "client write key" +# define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE 16 +# define TLS_MD_SERVER_WRITE_KEY_CONST "server write key" +# define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16 +# define TLS_MD_IV_BLOCK_CONST "IV block" +# define TLS_MD_IV_BLOCK_CONST_SIZE 8 +# define TLS_MD_MASTER_SECRET_CONST "master secret" +# define TLS_MD_MASTER_SECRET_CONST_SIZE 13 +# define TLS_MD_EXTENDED_MASTER_SECRET_CONST "extended master secret" +# define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE 22 + +# ifdef CHARSET_EBCDIC +# undef TLS_MD_CLIENT_FINISH_CONST +/* + * client finished + */ +# define TLS_MD_CLIENT_FINISH_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x66\x69\x6e\x69\x73\x68\x65\x64" + +# undef TLS_MD_SERVER_FINISH_CONST +/* + * server finished + */ +# define TLS_MD_SERVER_FINISH_CONST "\x73\x65\x72\x76\x65\x72\x20\x66\x69\x6e\x69\x73\x68\x65\x64" + +# undef TLS_MD_SERVER_WRITE_KEY_CONST +/* + * server write key + */ +# define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" + +# undef TLS_MD_KEY_EXPANSION_CONST +/* + * key expansion + */ +# define TLS_MD_KEY_EXPANSION_CONST "\x6b\x65\x79\x20\x65\x78\x70\x61\x6e\x73\x69\x6f\x6e" + +# undef TLS_MD_CLIENT_WRITE_KEY_CONST +/* + * client write key + */ +# define TLS_MD_CLIENT_WRITE_KEY_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" + +# undef TLS_MD_SERVER_WRITE_KEY_CONST +/* + * server write key + */ +# define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" + +# undef TLS_MD_IV_BLOCK_CONST +/* + * IV block + */ +# define TLS_MD_IV_BLOCK_CONST "\x49\x56\x20\x62\x6c\x6f\x63\x6b" + +# undef TLS_MD_MASTER_SECRET_CONST +/* + * master secret + */ +# define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" +# undef TLS_MD_EXTENDED_MASTER_SECRET_CONST +/* + * extended master secret + */ +# define TLS_MD_EXTENDED_MASTER_SECRET_CONST "\x65\x78\x74\x65\x63\x64\x65\x64\x20\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" +# endif + +/* TLS Session Ticket extension struct */ +struct tls_session_ticket_ext_st { + unsigned short length; + void *data; +}; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ts.h b/mobile/ios/FxA/FxA/include/openssl/ts.h new file mode 100644 index 0000000000..a5659825fb --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ts.h @@ -0,0 +1,643 @@ +/* + * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_TS_H +# define HEADER_TS_H + +# include + +# ifndef OPENSSL_NO_TS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + +# include +# include + +typedef struct TS_msg_imprint_st TS_MSG_IMPRINT; +typedef struct TS_req_st TS_REQ; +typedef struct TS_accuracy_st TS_ACCURACY; +typedef struct TS_tst_info_st TS_TST_INFO; + +/* Possible values for status. */ +# define TS_STATUS_GRANTED 0 +# define TS_STATUS_GRANTED_WITH_MODS 1 +# define TS_STATUS_REJECTION 2 +# define TS_STATUS_WAITING 3 +# define TS_STATUS_REVOCATION_WARNING 4 +# define TS_STATUS_REVOCATION_NOTIFICATION 5 + +/* Possible values for failure_info. */ +# define TS_INFO_BAD_ALG 0 +# define TS_INFO_BAD_REQUEST 2 +# define TS_INFO_BAD_DATA_FORMAT 5 +# define TS_INFO_TIME_NOT_AVAILABLE 14 +# define TS_INFO_UNACCEPTED_POLICY 15 +# define TS_INFO_UNACCEPTED_EXTENSION 16 +# define TS_INFO_ADD_INFO_NOT_AVAILABLE 17 +# define TS_INFO_SYSTEM_FAILURE 25 + + +typedef struct TS_status_info_st TS_STATUS_INFO; +typedef struct ESS_issuer_serial ESS_ISSUER_SERIAL; +typedef struct ESS_cert_id ESS_CERT_ID; +typedef struct ESS_signing_cert ESS_SIGNING_CERT; + +DEFINE_STACK_OF(ESS_CERT_ID) + +typedef struct TS_resp_st TS_RESP; + +TS_REQ *TS_REQ_new(void); +void TS_REQ_free(TS_REQ *a); +int i2d_TS_REQ(const TS_REQ *a, unsigned char **pp); +TS_REQ *d2i_TS_REQ(TS_REQ **a, const unsigned char **pp, long length); + +TS_REQ *TS_REQ_dup(TS_REQ *a); + +#ifndef OPENSSL_NO_STDIO +TS_REQ *d2i_TS_REQ_fp(FILE *fp, TS_REQ **a); +int i2d_TS_REQ_fp(FILE *fp, TS_REQ *a); +#endif +TS_REQ *d2i_TS_REQ_bio(BIO *fp, TS_REQ **a); +int i2d_TS_REQ_bio(BIO *fp, TS_REQ *a); + +TS_MSG_IMPRINT *TS_MSG_IMPRINT_new(void); +void TS_MSG_IMPRINT_free(TS_MSG_IMPRINT *a); +int i2d_TS_MSG_IMPRINT(const TS_MSG_IMPRINT *a, unsigned char **pp); +TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT(TS_MSG_IMPRINT **a, + const unsigned char **pp, long length); + +TS_MSG_IMPRINT *TS_MSG_IMPRINT_dup(TS_MSG_IMPRINT *a); + +#ifndef OPENSSL_NO_STDIO +TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT **a); +int i2d_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT *a); +#endif +TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_bio(BIO *bio, TS_MSG_IMPRINT **a); +int i2d_TS_MSG_IMPRINT_bio(BIO *bio, TS_MSG_IMPRINT *a); + +TS_RESP *TS_RESP_new(void); +void TS_RESP_free(TS_RESP *a); +int i2d_TS_RESP(const TS_RESP *a, unsigned char **pp); +TS_RESP *d2i_TS_RESP(TS_RESP **a, const unsigned char **pp, long length); +TS_TST_INFO *PKCS7_to_TS_TST_INFO(PKCS7 *token); +TS_RESP *TS_RESP_dup(TS_RESP *a); + +#ifndef OPENSSL_NO_STDIO +TS_RESP *d2i_TS_RESP_fp(FILE *fp, TS_RESP **a); +int i2d_TS_RESP_fp(FILE *fp, TS_RESP *a); +#endif +TS_RESP *d2i_TS_RESP_bio(BIO *bio, TS_RESP **a); +int i2d_TS_RESP_bio(BIO *bio, TS_RESP *a); + +TS_STATUS_INFO *TS_STATUS_INFO_new(void); +void TS_STATUS_INFO_free(TS_STATUS_INFO *a); +int i2d_TS_STATUS_INFO(const TS_STATUS_INFO *a, unsigned char **pp); +TS_STATUS_INFO *d2i_TS_STATUS_INFO(TS_STATUS_INFO **a, + const unsigned char **pp, long length); +TS_STATUS_INFO *TS_STATUS_INFO_dup(TS_STATUS_INFO *a); + +TS_TST_INFO *TS_TST_INFO_new(void); +void TS_TST_INFO_free(TS_TST_INFO *a); +int i2d_TS_TST_INFO(const TS_TST_INFO *a, unsigned char **pp); +TS_TST_INFO *d2i_TS_TST_INFO(TS_TST_INFO **a, const unsigned char **pp, + long length); +TS_TST_INFO *TS_TST_INFO_dup(TS_TST_INFO *a); + +#ifndef OPENSSL_NO_STDIO +TS_TST_INFO *d2i_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO **a); +int i2d_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO *a); +#endif +TS_TST_INFO *d2i_TS_TST_INFO_bio(BIO *bio, TS_TST_INFO **a); +int i2d_TS_TST_INFO_bio(BIO *bio, TS_TST_INFO *a); + +TS_ACCURACY *TS_ACCURACY_new(void); +void TS_ACCURACY_free(TS_ACCURACY *a); +int i2d_TS_ACCURACY(const TS_ACCURACY *a, unsigned char **pp); +TS_ACCURACY *d2i_TS_ACCURACY(TS_ACCURACY **a, const unsigned char **pp, + long length); +TS_ACCURACY *TS_ACCURACY_dup(TS_ACCURACY *a); + +ESS_ISSUER_SERIAL *ESS_ISSUER_SERIAL_new(void); +void ESS_ISSUER_SERIAL_free(ESS_ISSUER_SERIAL *a); +int i2d_ESS_ISSUER_SERIAL(const ESS_ISSUER_SERIAL *a, unsigned char **pp); +ESS_ISSUER_SERIAL *d2i_ESS_ISSUER_SERIAL(ESS_ISSUER_SERIAL **a, + const unsigned char **pp, + long length); +ESS_ISSUER_SERIAL *ESS_ISSUER_SERIAL_dup(ESS_ISSUER_SERIAL *a); + +ESS_CERT_ID *ESS_CERT_ID_new(void); +void ESS_CERT_ID_free(ESS_CERT_ID *a); +int i2d_ESS_CERT_ID(const ESS_CERT_ID *a, unsigned char **pp); +ESS_CERT_ID *d2i_ESS_CERT_ID(ESS_CERT_ID **a, const unsigned char **pp, + long length); +ESS_CERT_ID *ESS_CERT_ID_dup(ESS_CERT_ID *a); + +ESS_SIGNING_CERT *ESS_SIGNING_CERT_new(void); +void ESS_SIGNING_CERT_free(ESS_SIGNING_CERT *a); +int i2d_ESS_SIGNING_CERT(const ESS_SIGNING_CERT *a, unsigned char **pp); +ESS_SIGNING_CERT *d2i_ESS_SIGNING_CERT(ESS_SIGNING_CERT **a, + const unsigned char **pp, long length); +ESS_SIGNING_CERT *ESS_SIGNING_CERT_dup(ESS_SIGNING_CERT *a); + +int TS_REQ_set_version(TS_REQ *a, long version); +long TS_REQ_get_version(const TS_REQ *a); + +int TS_STATUS_INFO_set_status(TS_STATUS_INFO *a, int i); +const ASN1_INTEGER *TS_STATUS_INFO_get0_status(const TS_STATUS_INFO *a); + +const STACK_OF(ASN1_UTF8STRING) * +TS_STATUS_INFO_get0_text(const TS_STATUS_INFO *a); + +const ASN1_BIT_STRING * +TS_STATUS_INFO_get0_failure_info(const TS_STATUS_INFO *a); + +int TS_REQ_set_msg_imprint(TS_REQ *a, TS_MSG_IMPRINT *msg_imprint); +TS_MSG_IMPRINT *TS_REQ_get_msg_imprint(TS_REQ *a); + +int TS_MSG_IMPRINT_set_algo(TS_MSG_IMPRINT *a, X509_ALGOR *alg); +X509_ALGOR *TS_MSG_IMPRINT_get_algo(TS_MSG_IMPRINT *a); + +int TS_MSG_IMPRINT_set_msg(TS_MSG_IMPRINT *a, unsigned char *d, int len); +ASN1_OCTET_STRING *TS_MSG_IMPRINT_get_msg(TS_MSG_IMPRINT *a); + +int TS_REQ_set_policy_id(TS_REQ *a, const ASN1_OBJECT *policy); +ASN1_OBJECT *TS_REQ_get_policy_id(TS_REQ *a); + +int TS_REQ_set_nonce(TS_REQ *a, const ASN1_INTEGER *nonce); +const ASN1_INTEGER *TS_REQ_get_nonce(const TS_REQ *a); + +int TS_REQ_set_cert_req(TS_REQ *a, int cert_req); +int TS_REQ_get_cert_req(const TS_REQ *a); + +STACK_OF(X509_EXTENSION) *TS_REQ_get_exts(TS_REQ *a); +void TS_REQ_ext_free(TS_REQ *a); +int TS_REQ_get_ext_count(TS_REQ *a); +int TS_REQ_get_ext_by_NID(TS_REQ *a, int nid, int lastpos); +int TS_REQ_get_ext_by_OBJ(TS_REQ *a, const ASN1_OBJECT *obj, int lastpos); +int TS_REQ_get_ext_by_critical(TS_REQ *a, int crit, int lastpos); +X509_EXTENSION *TS_REQ_get_ext(TS_REQ *a, int loc); +X509_EXTENSION *TS_REQ_delete_ext(TS_REQ *a, int loc); +int TS_REQ_add_ext(TS_REQ *a, X509_EXTENSION *ex, int loc); +void *TS_REQ_get_ext_d2i(TS_REQ *a, int nid, int *crit, int *idx); + +/* Function declarations for TS_REQ defined in ts/ts_req_print.c */ + +int TS_REQ_print_bio(BIO *bio, TS_REQ *a); + +/* Function declarations for TS_RESP defined in ts/ts_resp_utils.c */ + +int TS_RESP_set_status_info(TS_RESP *a, TS_STATUS_INFO *info); +TS_STATUS_INFO *TS_RESP_get_status_info(TS_RESP *a); + +/* Caller loses ownership of PKCS7 and TS_TST_INFO objects. */ +void TS_RESP_set_tst_info(TS_RESP *a, PKCS7 *p7, TS_TST_INFO *tst_info); +PKCS7 *TS_RESP_get_token(TS_RESP *a); +TS_TST_INFO *TS_RESP_get_tst_info(TS_RESP *a); + +int TS_TST_INFO_set_version(TS_TST_INFO *a, long version); +long TS_TST_INFO_get_version(const TS_TST_INFO *a); + +int TS_TST_INFO_set_policy_id(TS_TST_INFO *a, ASN1_OBJECT *policy_id); +ASN1_OBJECT *TS_TST_INFO_get_policy_id(TS_TST_INFO *a); + +int TS_TST_INFO_set_msg_imprint(TS_TST_INFO *a, TS_MSG_IMPRINT *msg_imprint); +TS_MSG_IMPRINT *TS_TST_INFO_get_msg_imprint(TS_TST_INFO *a); + +int TS_TST_INFO_set_serial(TS_TST_INFO *a, const ASN1_INTEGER *serial); +const ASN1_INTEGER *TS_TST_INFO_get_serial(const TS_TST_INFO *a); + +int TS_TST_INFO_set_time(TS_TST_INFO *a, const ASN1_GENERALIZEDTIME *gtime); +const ASN1_GENERALIZEDTIME *TS_TST_INFO_get_time(const TS_TST_INFO *a); + +int TS_TST_INFO_set_accuracy(TS_TST_INFO *a, TS_ACCURACY *accuracy); +TS_ACCURACY *TS_TST_INFO_get_accuracy(TS_TST_INFO *a); + +int TS_ACCURACY_set_seconds(TS_ACCURACY *a, const ASN1_INTEGER *seconds); +const ASN1_INTEGER *TS_ACCURACY_get_seconds(const TS_ACCURACY *a); + +int TS_ACCURACY_set_millis(TS_ACCURACY *a, const ASN1_INTEGER *millis); +const ASN1_INTEGER *TS_ACCURACY_get_millis(const TS_ACCURACY *a); + +int TS_ACCURACY_set_micros(TS_ACCURACY *a, const ASN1_INTEGER *micros); +const ASN1_INTEGER *TS_ACCURACY_get_micros(const TS_ACCURACY *a); + +int TS_TST_INFO_set_ordering(TS_TST_INFO *a, int ordering); +int TS_TST_INFO_get_ordering(const TS_TST_INFO *a); + +int TS_TST_INFO_set_nonce(TS_TST_INFO *a, const ASN1_INTEGER *nonce); +const ASN1_INTEGER *TS_TST_INFO_get_nonce(const TS_TST_INFO *a); + +int TS_TST_INFO_set_tsa(TS_TST_INFO *a, GENERAL_NAME *tsa); +GENERAL_NAME *TS_TST_INFO_get_tsa(TS_TST_INFO *a); + +STACK_OF(X509_EXTENSION) *TS_TST_INFO_get_exts(TS_TST_INFO *a); +void TS_TST_INFO_ext_free(TS_TST_INFO *a); +int TS_TST_INFO_get_ext_count(TS_TST_INFO *a); +int TS_TST_INFO_get_ext_by_NID(TS_TST_INFO *a, int nid, int lastpos); +int TS_TST_INFO_get_ext_by_OBJ(TS_TST_INFO *a, const ASN1_OBJECT *obj, + int lastpos); +int TS_TST_INFO_get_ext_by_critical(TS_TST_INFO *a, int crit, int lastpos); +X509_EXTENSION *TS_TST_INFO_get_ext(TS_TST_INFO *a, int loc); +X509_EXTENSION *TS_TST_INFO_delete_ext(TS_TST_INFO *a, int loc); +int TS_TST_INFO_add_ext(TS_TST_INFO *a, X509_EXTENSION *ex, int loc); +void *TS_TST_INFO_get_ext_d2i(TS_TST_INFO *a, int nid, int *crit, int *idx); + +/* + * Declarations related to response generation, defined in ts/ts_resp_sign.c. + */ + +/* Optional flags for response generation. */ + +/* Don't include the TSA name in response. */ +# define TS_TSA_NAME 0x01 + +/* Set ordering to true in response. */ +# define TS_ORDERING 0x02 + +/* + * Include the signer certificate and the other specified certificates in + * the ESS signing certificate attribute beside the PKCS7 signed data. + * Only the signer certificates is included by default. + */ +# define TS_ESS_CERT_ID_CHAIN 0x04 + +/* Forward declaration. */ +struct TS_resp_ctx; + +/* This must return a unique number less than 160 bits long. */ +typedef ASN1_INTEGER *(*TS_serial_cb) (struct TS_resp_ctx *, void *); + +/* + * This must return the seconds and microseconds since Jan 1, 1970 in the sec + * and usec variables allocated by the caller. Return non-zero for success + * and zero for failure. + */ +typedef int (*TS_time_cb) (struct TS_resp_ctx *, void *, long *sec, + long *usec); + +/* + * This must process the given extension. It can modify the TS_TST_INFO + * object of the context. Return values: !0 (processed), 0 (error, it must + * set the status info/failure info of the response). + */ +typedef int (*TS_extension_cb) (struct TS_resp_ctx *, X509_EXTENSION *, + void *); + +typedef struct TS_resp_ctx TS_RESP_CTX; + +DEFINE_STACK_OF_CONST(EVP_MD) + +/* Creates a response context that can be used for generating responses. */ +TS_RESP_CTX *TS_RESP_CTX_new(void); +void TS_RESP_CTX_free(TS_RESP_CTX *ctx); + +/* This parameter must be set. */ +int TS_RESP_CTX_set_signer_cert(TS_RESP_CTX *ctx, X509 *signer); + +/* This parameter must be set. */ +int TS_RESP_CTX_set_signer_key(TS_RESP_CTX *ctx, EVP_PKEY *key); + +int TS_RESP_CTX_set_signer_digest(TS_RESP_CTX *ctx, + const EVP_MD *signer_digest); + +/* This parameter must be set. */ +int TS_RESP_CTX_set_def_policy(TS_RESP_CTX *ctx, const ASN1_OBJECT *def_policy); + +/* No additional certs are included in the response by default. */ +int TS_RESP_CTX_set_certs(TS_RESP_CTX *ctx, STACK_OF(X509) *certs); + +/* + * Adds a new acceptable policy, only the default policy is accepted by + * default. + */ +int TS_RESP_CTX_add_policy(TS_RESP_CTX *ctx, const ASN1_OBJECT *policy); + +/* + * Adds a new acceptable message digest. Note that no message digests are + * accepted by default. The md argument is shared with the caller. + */ +int TS_RESP_CTX_add_md(TS_RESP_CTX *ctx, const EVP_MD *md); + +/* Accuracy is not included by default. */ +int TS_RESP_CTX_set_accuracy(TS_RESP_CTX *ctx, + int secs, int millis, int micros); + +/* + * Clock precision digits, i.e. the number of decimal digits: '0' means sec, + * '3' msec, '6' usec, and so on. Default is 0. + */ +int TS_RESP_CTX_set_clock_precision_digits(TS_RESP_CTX *ctx, + unsigned clock_precision_digits); +/* At most we accept usec precision. */ +# define TS_MAX_CLOCK_PRECISION_DIGITS 6 + +/* Maximum status message length */ +# define TS_MAX_STATUS_LENGTH (1024 * 1024) + +/* No flags are set by default. */ +void TS_RESP_CTX_add_flags(TS_RESP_CTX *ctx, int flags); + +/* Default callback always returns a constant. */ +void TS_RESP_CTX_set_serial_cb(TS_RESP_CTX *ctx, TS_serial_cb cb, void *data); + +/* Default callback uses the gettimeofday() and gmtime() system calls. */ +void TS_RESP_CTX_set_time_cb(TS_RESP_CTX *ctx, TS_time_cb cb, void *data); + +/* + * Default callback rejects all extensions. The extension callback is called + * when the TS_TST_INFO object is already set up and not signed yet. + */ +/* FIXME: extension handling is not tested yet. */ +void TS_RESP_CTX_set_extension_cb(TS_RESP_CTX *ctx, + TS_extension_cb cb, void *data); + +/* The following methods can be used in the callbacks. */ +int TS_RESP_CTX_set_status_info(TS_RESP_CTX *ctx, + int status, const char *text); + +/* Sets the status info only if it is still TS_STATUS_GRANTED. */ +int TS_RESP_CTX_set_status_info_cond(TS_RESP_CTX *ctx, + int status, const char *text); + +int TS_RESP_CTX_add_failure_info(TS_RESP_CTX *ctx, int failure); + +/* The get methods below can be used in the extension callback. */ +TS_REQ *TS_RESP_CTX_get_request(TS_RESP_CTX *ctx); + +TS_TST_INFO *TS_RESP_CTX_get_tst_info(TS_RESP_CTX *ctx); + +/* + * Creates the signed TS_TST_INFO and puts it in TS_RESP. + * In case of errors it sets the status info properly. + * Returns NULL only in case of memory allocation/fatal error. + */ +TS_RESP *TS_RESP_create_response(TS_RESP_CTX *ctx, BIO *req_bio); + +/* + * Declarations related to response verification, + * they are defined in ts/ts_resp_verify.c. + */ + +int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs, + X509_STORE *store, X509 **signer_out); + +/* Context structure for the generic verify method. */ + +/* Verify the signer's certificate and the signature of the response. */ +# define TS_VFY_SIGNATURE (1u << 0) +/* Verify the version number of the response. */ +# define TS_VFY_VERSION (1u << 1) +/* Verify if the policy supplied by the user matches the policy of the TSA. */ +# define TS_VFY_POLICY (1u << 2) +/* + * Verify the message imprint provided by the user. This flag should not be + * specified with TS_VFY_DATA. + */ +# define TS_VFY_IMPRINT (1u << 3) +/* + * Verify the message imprint computed by the verify method from the user + * provided data and the MD algorithm of the response. This flag should not + * be specified with TS_VFY_IMPRINT. + */ +# define TS_VFY_DATA (1u << 4) +/* Verify the nonce value. */ +# define TS_VFY_NONCE (1u << 5) +/* Verify if the TSA name field matches the signer certificate. */ +# define TS_VFY_SIGNER (1u << 6) +/* Verify if the TSA name field equals to the user provided name. */ +# define TS_VFY_TSA_NAME (1u << 7) + +/* You can use the following convenience constants. */ +# define TS_VFY_ALL_IMPRINT (TS_VFY_SIGNATURE \ + | TS_VFY_VERSION \ + | TS_VFY_POLICY \ + | TS_VFY_IMPRINT \ + | TS_VFY_NONCE \ + | TS_VFY_SIGNER \ + | TS_VFY_TSA_NAME) +# define TS_VFY_ALL_DATA (TS_VFY_SIGNATURE \ + | TS_VFY_VERSION \ + | TS_VFY_POLICY \ + | TS_VFY_DATA \ + | TS_VFY_NONCE \ + | TS_VFY_SIGNER \ + | TS_VFY_TSA_NAME) + +typedef struct TS_verify_ctx TS_VERIFY_CTX; + +int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response); +int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token); + +/* + * Declarations related to response verification context, + */ +TS_VERIFY_CTX *TS_VERIFY_CTX_new(void); +void TS_VERIFY_CTX_init(TS_VERIFY_CTX *ctx); +void TS_VERIFY_CTX_free(TS_VERIFY_CTX *ctx); +void TS_VERIFY_CTX_cleanup(TS_VERIFY_CTX *ctx); +int TS_VERIFY_CTX_set_flags(TS_VERIFY_CTX *ctx, int f); +int TS_VERIFY_CTX_add_flags(TS_VERIFY_CTX *ctx, int f); +BIO *TS_VERIFY_CTX_set_data(TS_VERIFY_CTX *ctx, BIO *b); +unsigned char *TS_VERIFY_CTX_set_imprint(TS_VERIFY_CTX *ctx, + unsigned char *hexstr, long len); +X509_STORE *TS_VERIFY_CTX_set_store(TS_VERIFY_CTX *ctx, X509_STORE *s); +STACK_OF(X509) *TS_VERIFY_CTS_set_certs(TS_VERIFY_CTX *ctx, STACK_OF(X509) *certs); + +/*- + * If ctx is NULL, it allocates and returns a new object, otherwise + * it returns ctx. It initialises all the members as follows: + * flags = TS_VFY_ALL_IMPRINT & ~(TS_VFY_TSA_NAME | TS_VFY_SIGNATURE) + * certs = NULL + * store = NULL + * policy = policy from the request or NULL if absent (in this case + * TS_VFY_POLICY is cleared from flags as well) + * md_alg = MD algorithm from request + * imprint, imprint_len = imprint from request + * data = NULL + * nonce, nonce_len = nonce from the request or NULL if absent (in this case + * TS_VFY_NONCE is cleared from flags as well) + * tsa_name = NULL + * Important: after calling this method TS_VFY_SIGNATURE should be added! + */ +TS_VERIFY_CTX *TS_REQ_to_TS_VERIFY_CTX(TS_REQ *req, TS_VERIFY_CTX *ctx); + +/* Function declarations for TS_RESP defined in ts/ts_resp_print.c */ + +int TS_RESP_print_bio(BIO *bio, TS_RESP *a); +int TS_STATUS_INFO_print_bio(BIO *bio, TS_STATUS_INFO *a); +int TS_TST_INFO_print_bio(BIO *bio, TS_TST_INFO *a); + +/* Common utility functions defined in ts/ts_lib.c */ + +int TS_ASN1_INTEGER_print_bio(BIO *bio, const ASN1_INTEGER *num); +int TS_OBJ_print_bio(BIO *bio, const ASN1_OBJECT *obj); +int TS_ext_print_bio(BIO *bio, const STACK_OF(X509_EXTENSION) *extensions); +int TS_X509_ALGOR_print_bio(BIO *bio, const X509_ALGOR *alg); +int TS_MSG_IMPRINT_print_bio(BIO *bio, TS_MSG_IMPRINT *msg); + +/* + * Function declarations for handling configuration options, defined in + * ts/ts_conf.c + */ + +X509 *TS_CONF_load_cert(const char *file); +STACK_OF(X509) *TS_CONF_load_certs(const char *file); +EVP_PKEY *TS_CONF_load_key(const char *file, const char *pass); +const char *TS_CONF_get_tsa_section(CONF *conf, const char *section); +int TS_CONF_set_serial(CONF *conf, const char *section, TS_serial_cb cb, + TS_RESP_CTX *ctx); +#ifndef OPENSSL_NO_ENGINE +int TS_CONF_set_crypto_device(CONF *conf, const char *section, + const char *device); +int TS_CONF_set_default_engine(const char *name); +#endif +int TS_CONF_set_signer_cert(CONF *conf, const char *section, + const char *cert, TS_RESP_CTX *ctx); +int TS_CONF_set_certs(CONF *conf, const char *section, const char *certs, + TS_RESP_CTX *ctx); +int TS_CONF_set_signer_key(CONF *conf, const char *section, + const char *key, const char *pass, + TS_RESP_CTX *ctx); +int TS_CONF_set_signer_digest(CONF *conf, const char *section, + const char *md, TS_RESP_CTX *ctx); +int TS_CONF_set_def_policy(CONF *conf, const char *section, + const char *policy, TS_RESP_CTX *ctx); +int TS_CONF_set_policies(CONF *conf, const char *section, TS_RESP_CTX *ctx); +int TS_CONF_set_digests(CONF *conf, const char *section, TS_RESP_CTX *ctx); +int TS_CONF_set_accuracy(CONF *conf, const char *section, TS_RESP_CTX *ctx); +int TS_CONF_set_clock_precision_digits(CONF *conf, const char *section, + TS_RESP_CTX *ctx); +int TS_CONF_set_ordering(CONF *conf, const char *section, TS_RESP_CTX *ctx); +int TS_CONF_set_tsa_name(CONF *conf, const char *section, TS_RESP_CTX *ctx); +int TS_CONF_set_ess_cert_id_chain(CONF *conf, const char *section, + TS_RESP_CTX *ctx); + +/* -------------------------------------------------- */ +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_TS_strings(void); + +/* Error codes for the TS functions. */ + +/* Function codes. */ +# define TS_F_DEF_SERIAL_CB 110 +# define TS_F_DEF_TIME_CB 111 +# define TS_F_ESS_ADD_SIGNING_CERT 112 +# define TS_F_ESS_CERT_ID_NEW_INIT 113 +# define TS_F_ESS_SIGNING_CERT_NEW_INIT 114 +# define TS_F_INT_TS_RESP_VERIFY_TOKEN 149 +# define TS_F_PKCS7_TO_TS_TST_INFO 148 +# define TS_F_TS_ACCURACY_SET_MICROS 115 +# define TS_F_TS_ACCURACY_SET_MILLIS 116 +# define TS_F_TS_ACCURACY_SET_SECONDS 117 +# define TS_F_TS_CHECK_IMPRINTS 100 +# define TS_F_TS_CHECK_NONCES 101 +# define TS_F_TS_CHECK_POLICY 102 +# define TS_F_TS_CHECK_SIGNING_CERTS 103 +# define TS_F_TS_CHECK_STATUS_INFO 104 +# define TS_F_TS_COMPUTE_IMPRINT 145 +# define TS_F_TS_CONF_INVALID 151 +# define TS_F_TS_CONF_LOAD_CERT 153 +# define TS_F_TS_CONF_LOAD_CERTS 154 +# define TS_F_TS_CONF_LOAD_KEY 155 +# define TS_F_TS_CONF_LOOKUP_FAIL 152 +# define TS_F_TS_CONF_SET_DEFAULT_ENGINE 146 +# define TS_F_TS_GET_STATUS_TEXT 105 +# define TS_F_TS_MSG_IMPRINT_SET_ALGO 118 +# define TS_F_TS_REQ_SET_MSG_IMPRINT 119 +# define TS_F_TS_REQ_SET_NONCE 120 +# define TS_F_TS_REQ_SET_POLICY_ID 121 +# define TS_F_TS_RESP_CREATE_RESPONSE 122 +# define TS_F_TS_RESP_CREATE_TST_INFO 123 +# define TS_F_TS_RESP_CTX_ADD_FAILURE_INFO 124 +# define TS_F_TS_RESP_CTX_ADD_MD 125 +# define TS_F_TS_RESP_CTX_ADD_POLICY 126 +# define TS_F_TS_RESP_CTX_NEW 127 +# define TS_F_TS_RESP_CTX_SET_ACCURACY 128 +# define TS_F_TS_RESP_CTX_SET_CERTS 129 +# define TS_F_TS_RESP_CTX_SET_DEF_POLICY 130 +# define TS_F_TS_RESP_CTX_SET_SIGNER_CERT 131 +# define TS_F_TS_RESP_CTX_SET_STATUS_INFO 132 +# define TS_F_TS_RESP_GET_POLICY 133 +# define TS_F_TS_RESP_SET_GENTIME_WITH_PRECISION 134 +# define TS_F_TS_RESP_SET_STATUS_INFO 135 +# define TS_F_TS_RESP_SET_TST_INFO 150 +# define TS_F_TS_RESP_SIGN 136 +# define TS_F_TS_RESP_VERIFY_SIGNATURE 106 +# define TS_F_TS_TST_INFO_SET_ACCURACY 137 +# define TS_F_TS_TST_INFO_SET_MSG_IMPRINT 138 +# define TS_F_TS_TST_INFO_SET_NONCE 139 +# define TS_F_TS_TST_INFO_SET_POLICY_ID 140 +# define TS_F_TS_TST_INFO_SET_SERIAL 141 +# define TS_F_TS_TST_INFO_SET_TIME 142 +# define TS_F_TS_TST_INFO_SET_TSA 143 +# define TS_F_TS_VERIFY 108 +# define TS_F_TS_VERIFY_CERT 109 +# define TS_F_TS_VERIFY_CTX_NEW 144 + +/* Reason codes. */ +# define TS_R_BAD_PKCS7_TYPE 132 +# define TS_R_BAD_TYPE 133 +# define TS_R_CANNOT_LOAD_CERT 137 +# define TS_R_CANNOT_LOAD_KEY 138 +# define TS_R_CERTIFICATE_VERIFY_ERROR 100 +# define TS_R_COULD_NOT_SET_ENGINE 127 +# define TS_R_COULD_NOT_SET_TIME 115 +# define TS_R_DETACHED_CONTENT 134 +# define TS_R_ESS_ADD_SIGNING_CERT_ERROR 116 +# define TS_R_ESS_SIGNING_CERTIFICATE_ERROR 101 +# define TS_R_INVALID_NULL_POINTER 102 +# define TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE 117 +# define TS_R_MESSAGE_IMPRINT_MISMATCH 103 +# define TS_R_NONCE_MISMATCH 104 +# define TS_R_NONCE_NOT_RETURNED 105 +# define TS_R_NO_CONTENT 106 +# define TS_R_NO_TIME_STAMP_TOKEN 107 +# define TS_R_PKCS7_ADD_SIGNATURE_ERROR 118 +# define TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR 119 +# define TS_R_PKCS7_TO_TS_TST_INFO_FAILED 129 +# define TS_R_POLICY_MISMATCH 108 +# define TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 120 +# define TS_R_RESPONSE_SETUP_ERROR 121 +# define TS_R_SIGNATURE_FAILURE 109 +# define TS_R_THERE_MUST_BE_ONE_SIGNER 110 +# define TS_R_TIME_SYSCALL_ERROR 122 +# define TS_R_TOKEN_NOT_PRESENT 130 +# define TS_R_TOKEN_PRESENT 131 +# define TS_R_TSA_NAME_MISMATCH 111 +# define TS_R_TSA_UNTRUSTED 112 +# define TS_R_TST_INFO_SETUP_ERROR 123 +# define TS_R_TS_DATASIGN 124 +# define TS_R_UNACCEPTABLE_POLICY 125 +# define TS_R_UNSUPPORTED_MD_ALGORITHM 126 +# define TS_R_UNSUPPORTED_VERSION 113 +# define TS_R_VAR_BAD_VALUE 135 +# define TS_R_VAR_LOOKUP_FAILURE 136 +# define TS_R_WRONG_CONTENT_TYPE 114 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/txt_db.h b/mobile/ios/FxA/FxA/include/openssl/txt_db.h new file mode 100644 index 0000000000..0e6c943e0e --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/txt_db.h @@ -0,0 +1,57 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_TXT_DB_H +# define HEADER_TXT_DB_H + +# include +# include +# include +# include + +# define DB_ERROR_OK 0 +# define DB_ERROR_MALLOC 1 +# define DB_ERROR_INDEX_CLASH 2 +# define DB_ERROR_INDEX_OUT_OF_RANGE 3 +# define DB_ERROR_NO_INDEX 4 +# define DB_ERROR_INSERT_INDEX_CLASH 5 +# define DB_ERROR_WRONG_NUM_FIELDS 6 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef OPENSSL_STRING *OPENSSL_PSTRING; +DEFINE_SPECIAL_STACK_OF(OPENSSL_PSTRING, OPENSSL_STRING) + +typedef struct txt_db_st { + int num_fields; + STACK_OF(OPENSSL_PSTRING) *data; + LHASH_OF(OPENSSL_STRING) **index; + int (**qual) (OPENSSL_STRING *); + long error; + long arg1; + long arg2; + OPENSSL_STRING *arg_row; +} TXT_DB; + +TXT_DB *TXT_DB_read(BIO *in, int num); +long TXT_DB_write(BIO *out, TXT_DB *db); +int TXT_DB_create_index(TXT_DB *db, int field, int (*qual) (OPENSSL_STRING *), + OPENSSL_LH_HASHFUNC hash, OPENSSL_LH_COMPFUNC cmp); +void TXT_DB_free(TXT_DB *db); +OPENSSL_STRING *TXT_DB_get_by_index(TXT_DB *db, int idx, + OPENSSL_STRING *value); +int TXT_DB_insert(TXT_DB *db, OPENSSL_STRING *value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/ui.h b/mobile/ios/FxA/FxA/include/openssl/ui.h new file mode 100644 index 0000000000..49e763de3e --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/ui.h @@ -0,0 +1,378 @@ +/* + * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_UI_H +# define HEADER_UI_H + +# include + +# ifndef OPENSSL_NO_UI + +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# endif +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * All the following functions return -1 or NULL on error and in some cases + * (UI_process()) -2 if interrupted or in some other way cancelled. When + * everything is fine, they return 0, a positive value or a non-NULL pointer, + * all depending on their purpose. + */ + +/* Creators and destructor. */ +UI *UI_new(void); +UI *UI_new_method(const UI_METHOD *method); +void UI_free(UI *ui); + +/*- + The following functions are used to add strings to be printed and prompt + strings to prompt for data. The names are UI_{add,dup}__string + and UI_{add,dup}_input_boolean. + + UI_{add,dup}__string have the following meanings: + add add a text or prompt string. The pointers given to these + functions are used verbatim, no copying is done. + dup make a copy of the text or prompt string, then add the copy + to the collection of strings in the user interface. + + The function is a name for the functionality that the given + string shall be used for. It can be one of: + input use the string as data prompt. + verify use the string as verification prompt. This + is used to verify a previous input. + info use the string for informational output. + error use the string for error output. + Honestly, there's currently no difference between info and error for the + moment. + + UI_{add,dup}_input_boolean have the same semantics for "add" and "dup", + and are typically used when one wants to prompt for a yes/no response. + + All of the functions in this group take a UI and a prompt string. + The string input and verify addition functions also take a flag argument, + a buffer for the result to end up with, a minimum input size and a maximum + input size (the result buffer MUST be large enough to be able to contain + the maximum number of characters). Additionally, the verify addition + functions takes another buffer to compare the result against. + The boolean input functions take an action description string (which should + be safe to ignore if the expected user action is obvious, for example with + a dialog box with an OK button and a Cancel button), a string of acceptable + characters to mean OK and to mean Cancel. The two last strings are checked + to make sure they don't have common characters. Additionally, the same + flag argument as for the string input is taken, as well as a result buffer. + The result buffer is required to be at least one byte long. Depending on + the answer, the first character from the OK or the Cancel character strings + will be stored in the first byte of the result buffer. No NUL will be + added, so the result is *not* a string. + + On success, the all return an index of the added information. That index + is useful when retrieving results with UI_get0_result(). */ +int UI_add_input_string(UI *ui, const char *prompt, int flags, + char *result_buf, int minsize, int maxsize); +int UI_dup_input_string(UI *ui, const char *prompt, int flags, + char *result_buf, int minsize, int maxsize); +int UI_add_verify_string(UI *ui, const char *prompt, int flags, + char *result_buf, int minsize, int maxsize, + const char *test_buf); +int UI_dup_verify_string(UI *ui, const char *prompt, int flags, + char *result_buf, int minsize, int maxsize, + const char *test_buf); +int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc, + const char *ok_chars, const char *cancel_chars, + int flags, char *result_buf); +int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc, + const char *ok_chars, const char *cancel_chars, + int flags, char *result_buf); +int UI_add_info_string(UI *ui, const char *text); +int UI_dup_info_string(UI *ui, const char *text); +int UI_add_error_string(UI *ui, const char *text); +int UI_dup_error_string(UI *ui, const char *text); + +/* These are the possible flags. They can be or'ed together. */ +/* Use to have echoing of input */ +# define UI_INPUT_FLAG_ECHO 0x01 +/* + * Use a default password. Where that password is found is completely up to + * the application, it might for example be in the user data set with + * UI_add_user_data(). It is not recommended to have more than one input in + * each UI being marked with this flag, or the application might get + * confused. + */ +# define UI_INPUT_FLAG_DEFAULT_PWD 0x02 + +/*- + * The user of these routines may want to define flags of their own. The core + * UI won't look at those, but will pass them on to the method routines. They + * must use higher bits so they don't get confused with the UI bits above. + * UI_INPUT_FLAG_USER_BASE tells which is the lowest bit to use. A good + * example of use is this: + * + * #define MY_UI_FLAG1 (0x01 << UI_INPUT_FLAG_USER_BASE) + * +*/ +# define UI_INPUT_FLAG_USER_BASE 16 + +/*- + * The following function helps construct a prompt. object_desc is a + * textual short description of the object, for example "pass phrase", + * and object_name is the name of the object (might be a card name or + * a file name. + * The returned string shall always be allocated on the heap with + * OPENSSL_malloc(), and need to be free'd with OPENSSL_free(). + * + * If the ui_method doesn't contain a pointer to a user-defined prompt + * constructor, a default string is built, looking like this: + * + * "Enter {object_desc} for {object_name}:" + * + * So, if object_desc has the value "pass phrase" and object_name has + * the value "foo.key", the resulting string is: + * + * "Enter pass phrase for foo.key:" +*/ +char *UI_construct_prompt(UI *ui_method, + const char *object_desc, const char *object_name); + +/* + * The following function is used to store a pointer to user-specific data. + * Any previous such pointer will be returned and replaced. + * + * For callback purposes, this function makes a lot more sense than using + * ex_data, since the latter requires that different parts of OpenSSL or + * applications share the same ex_data index. + * + * Note that the UI_OpenSSL() method completely ignores the user data. Other + * methods may not, however. + */ +void *UI_add_user_data(UI *ui, void *user_data); +/* We need a user data retrieving function as well. */ +void *UI_get0_user_data(UI *ui); + +/* Return the result associated with a prompt given with the index i. */ +const char *UI_get0_result(UI *ui, int i); + +/* When all strings have been added, process the whole thing. */ +int UI_process(UI *ui); + +/* + * Give a user interface parametrised control commands. This can be used to + * send down an integer, a data pointer or a function pointer, as well as be + * used to get information from a UI. + */ +int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void)); + +/* The commands */ +/* + * Use UI_CONTROL_PRINT_ERRORS with the value 1 to have UI_process print the + * OpenSSL error stack before printing any info or added error messages and + * before any prompting. + */ +# define UI_CTRL_PRINT_ERRORS 1 +/* + * Check if a UI_process() is possible to do again with the same instance of + * a user interface. This makes UI_ctrl() return 1 if it is redoable, and 0 + * if not. + */ +# define UI_CTRL_IS_REDOABLE 2 + +/* Some methods may use extra data */ +# define UI_set_app_data(s,arg) UI_set_ex_data(s,0,arg) +# define UI_get_app_data(s) UI_get_ex_data(s,0) + +#define UI_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_UI, l, p, newf, dupf, freef) +int UI_set_ex_data(UI *r, int idx, void *arg); +void *UI_get_ex_data(UI *r, int idx); + +/* Use specific methods instead of the built-in one */ +void UI_set_default_method(const UI_METHOD *meth); +const UI_METHOD *UI_get_default_method(void); +const UI_METHOD *UI_get_method(UI *ui); +const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth); + +/* The method with all the built-in thingies */ +UI_METHOD *UI_OpenSSL(void); + +/* ---------- For method writers ---------- */ +/*- + A method contains a number of functions that implement the low level + of the User Interface. The functions are: + + an opener This function starts a session, maybe by opening + a channel to a tty, or by opening a window. + a writer This function is called to write a given string, + maybe to the tty, maybe as a field label in a + window. + a flusher This function is called to flush everything that + has been output so far. It can be used to actually + display a dialog box after it has been built. + a reader This function is called to read a given prompt, + maybe from the tty, maybe from a field in a + window. Note that it's called with all string + structures, not only the prompt ones, so it must + check such things itself. + a closer This function closes the session, maybe by closing + the channel to the tty, or closing the window. + + All these functions are expected to return: + + 0 on error. + 1 on success. + -1 on out-of-band events, for example if some prompting has + been canceled (by pressing Ctrl-C, for example). This is + only checked when returned by the flusher or the reader. + + The way this is used, the opener is first called, then the writer for all + strings, then the flusher, then the reader for all strings and finally the + closer. Note that if you want to prompt from a terminal or other command + line interface, the best is to have the reader also write the prompts + instead of having the writer do it. If you want to prompt from a dialog + box, the writer can be used to build up the contents of the box, and the + flusher to actually display the box and run the event loop until all data + has been given, after which the reader only grabs the given data and puts + them back into the UI strings. + + All method functions take a UI as argument. Additionally, the writer and + the reader take a UI_STRING. +*/ + +/* + * The UI_STRING type is the data structure that contains all the needed info + * about a string or a prompt, including test data for a verification prompt. + */ +typedef struct ui_string_st UI_STRING; +DEFINE_STACK_OF(UI_STRING) + +/* + * The different types of strings that are currently supported. This is only + * needed by method authors. + */ +enum UI_string_types { + UIT_NONE = 0, + UIT_PROMPT, /* Prompt for a string */ + UIT_VERIFY, /* Prompt for a string and verify */ + UIT_BOOLEAN, /* Prompt for a yes/no response */ + UIT_INFO, /* Send info to the user */ + UIT_ERROR /* Send an error message to the user */ +}; + +/* Create and manipulate methods */ +UI_METHOD *UI_create_method(const char *name); +void UI_destroy_method(UI_METHOD *ui_method); +int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui)); +int UI_method_set_writer(UI_METHOD *method, + int (*writer) (UI *ui, UI_STRING *uis)); +int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui)); +int UI_method_set_reader(UI_METHOD *method, + int (*reader) (UI *ui, UI_STRING *uis)); +int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui)); +int UI_method_set_prompt_constructor(UI_METHOD *method, + char *(*prompt_constructor) (UI *ui, + const char + *object_desc, + const char + *object_name)); +int (*UI_method_get_opener(UI_METHOD *method)) (UI *); +int (*UI_method_get_writer(UI_METHOD *method)) (UI *, UI_STRING *); +int (*UI_method_get_flusher(UI_METHOD *method)) (UI *); +int (*UI_method_get_reader(UI_METHOD *method)) (UI *, UI_STRING *); +int (*UI_method_get_closer(UI_METHOD *method)) (UI *); +char *(*UI_method_get_prompt_constructor(UI_METHOD *method)) (UI *, + const char *, + const char *); + +/* + * The following functions are helpers for method writers to access relevant + * data from a UI_STRING. + */ + +/* Return type of the UI_STRING */ +enum UI_string_types UI_get_string_type(UI_STRING *uis); +/* Return input flags of the UI_STRING */ +int UI_get_input_flags(UI_STRING *uis); +/* Return the actual string to output (the prompt, info or error) */ +const char *UI_get0_output_string(UI_STRING *uis); +/* + * Return the optional action string to output (the boolean prompt + * instruction) + */ +const char *UI_get0_action_string(UI_STRING *uis); +/* Return the result of a prompt */ +const char *UI_get0_result_string(UI_STRING *uis); +/* + * Return the string to test the result against. Only useful with verifies. + */ +const char *UI_get0_test_string(UI_STRING *uis); +/* Return the required minimum size of the result */ +int UI_get_result_minsize(UI_STRING *uis); +/* Return the required maximum size of the result */ +int UI_get_result_maxsize(UI_STRING *uis); +/* Set the result of a UI_STRING. */ +int UI_set_result(UI *ui, UI_STRING *uis, const char *result); + +/* A couple of popular utility functions */ +int UI_UTIL_read_pw_string(char *buf, int length, const char *prompt, + int verify); +int UI_UTIL_read_pw(char *buf, char *buff, int size, const char *prompt, + int verify); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_UI_strings(void); + +/* Error codes for the UI functions. */ + +/* Function codes. */ +# define UI_F_CLOSE_CONSOLE 115 +# define UI_F_ECHO_CONSOLE 116 +# define UI_F_GENERAL_ALLOCATE_BOOLEAN 108 +# define UI_F_GENERAL_ALLOCATE_PROMPT 109 +# define UI_F_NOECHO_CONSOLE 117 +# define UI_F_OPEN_CONSOLE 114 +# define UI_F_UI_CREATE_METHOD 112 +# define UI_F_UI_CTRL 111 +# define UI_F_UI_DUP_ERROR_STRING 101 +# define UI_F_UI_DUP_INFO_STRING 102 +# define UI_F_UI_DUP_INPUT_BOOLEAN 110 +# define UI_F_UI_DUP_INPUT_STRING 103 +# define UI_F_UI_DUP_VERIFY_STRING 106 +# define UI_F_UI_GET0_RESULT 107 +# define UI_F_UI_NEW_METHOD 104 +# define UI_F_UI_PROCESS 113 +# define UI_F_UI_SET_RESULT 105 + +/* Reason codes. */ +# define UI_R_COMMON_OK_AND_CANCEL_CHARACTERS 104 +# define UI_R_INDEX_TOO_LARGE 102 +# define UI_R_INDEX_TOO_SMALL 103 +# define UI_R_NO_RESULT_BUFFER 105 +# define UI_R_PROCESSING_ERROR 107 +# define UI_R_RESULT_TOO_LARGE 100 +# define UI_R_RESULT_TOO_SMALL 101 +# define UI_R_SYSASSIGN_ERROR 109 +# define UI_R_SYSDASSGN_ERROR 110 +# define UI_R_SYSQIOW_ERROR 111 +# define UI_R_UNKNOWN_CONTROL_COMMAND 106 +# define UI_R_UNKNOWN_TTYGET_ERRNO_VALUE 108 + +# ifdef __cplusplus +} +# endif +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/whrlpool.h b/mobile/ios/FxA/FxA/include/openssl/whrlpool.h new file mode 100644 index 0000000000..20ea3503b7 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/whrlpool.h @@ -0,0 +1,48 @@ +/* + * Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_WHRLPOOL_H +# define HEADER_WHRLPOOL_H + +#include + +# ifndef OPENSSL_NO_WHIRLPOOL +# include +# include +# ifdef __cplusplus +extern "C" { +# endif + +# define WHIRLPOOL_DIGEST_LENGTH (512/8) +# define WHIRLPOOL_BBLOCK 512 +# define WHIRLPOOL_COUNTER (256/8) + +typedef struct { + union { + unsigned char c[WHIRLPOOL_DIGEST_LENGTH]; + /* double q is here to ensure 64-bit alignment */ + double q[WHIRLPOOL_DIGEST_LENGTH / sizeof(double)]; + } H; + unsigned char data[WHIRLPOOL_BBLOCK / 8]; + unsigned int bitoff; + size_t bitlen[WHIRLPOOL_COUNTER / sizeof(size_t)]; +} WHIRLPOOL_CTX; + +int WHIRLPOOL_Init(WHIRLPOOL_CTX *c); +int WHIRLPOOL_Update(WHIRLPOOL_CTX *c, const void *inp, size_t bytes); +void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c, const void *inp, size_t bits); +int WHIRLPOOL_Final(unsigned char *md, WHIRLPOOL_CTX *c); +unsigned char *WHIRLPOOL(const void *inp, size_t bytes, unsigned char *md); + +# ifdef __cplusplus +} +# endif +# endif + +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/x509.h b/mobile/ios/FxA/FxA/include/openssl/x509.h new file mode 100644 index 0000000000..c8996f3520 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/x509.h @@ -0,0 +1,1123 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_X509_H +# define HEADER_X509_H + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# if OPENSSL_API_COMPAT < 0x10100000L +# include +# include +# include +# endif + +# include + +#ifdef __cplusplus +extern "C" { +#endif + +# define X509_FILETYPE_PEM 1 +# define X509_FILETYPE_ASN1 2 +# define X509_FILETYPE_DEFAULT 3 + +# define X509v3_KU_DIGITAL_SIGNATURE 0x0080 +# define X509v3_KU_NON_REPUDIATION 0x0040 +# define X509v3_KU_KEY_ENCIPHERMENT 0x0020 +# define X509v3_KU_DATA_ENCIPHERMENT 0x0010 +# define X509v3_KU_KEY_AGREEMENT 0x0008 +# define X509v3_KU_KEY_CERT_SIGN 0x0004 +# define X509v3_KU_CRL_SIGN 0x0002 +# define X509v3_KU_ENCIPHER_ONLY 0x0001 +# define X509v3_KU_DECIPHER_ONLY 0x8000 +# define X509v3_KU_UNDEF 0xffff + +struct X509_algor_st { + ASN1_OBJECT *algorithm; + ASN1_TYPE *parameter; +} /* X509_ALGOR */ ; + +typedef STACK_OF(X509_ALGOR) X509_ALGORS; + +typedef struct X509_val_st { + ASN1_TIME *notBefore; + ASN1_TIME *notAfter; +} X509_VAL; + +typedef struct X509_sig_st X509_SIG; + +typedef struct X509_name_entry_st X509_NAME_ENTRY; + +DEFINE_STACK_OF(X509_NAME_ENTRY) + +DEFINE_STACK_OF(X509_NAME) + +# define X509_EX_V_NETSCAPE_HACK 0x8000 +# define X509_EX_V_INIT 0x0001 +typedef struct X509_extension_st X509_EXTENSION; + +typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; + +DEFINE_STACK_OF(X509_EXTENSION) + +typedef struct x509_attributes_st X509_ATTRIBUTE; + +DEFINE_STACK_OF(X509_ATTRIBUTE) + +typedef struct X509_req_info_st X509_REQ_INFO; + +typedef struct X509_req_st X509_REQ; + +typedef struct x509_cert_aux_st X509_CERT_AUX; + +typedef struct x509_cinf_st X509_CINF; + +DEFINE_STACK_OF(X509) + +/* This is used for a table of trust checking functions */ + +typedef struct x509_trust_st { + int trust; + int flags; + int (*check_trust) (struct x509_trust_st *, X509 *, int); + char *name; + int arg1; + void *arg2; +} X509_TRUST; + +DEFINE_STACK_OF(X509_TRUST) + +/* standard trust ids */ + +# define X509_TRUST_DEFAULT 0 /* Only valid in purpose settings */ + +# define X509_TRUST_COMPAT 1 +# define X509_TRUST_SSL_CLIENT 2 +# define X509_TRUST_SSL_SERVER 3 +# define X509_TRUST_EMAIL 4 +# define X509_TRUST_OBJECT_SIGN 5 +# define X509_TRUST_OCSP_SIGN 6 +# define X509_TRUST_OCSP_REQUEST 7 +# define X509_TRUST_TSA 8 + +/* Keep these up to date! */ +# define X509_TRUST_MIN 1 +# define X509_TRUST_MAX 8 + +/* trust_flags values */ +# define X509_TRUST_DYNAMIC (1U << 0) +# define X509_TRUST_DYNAMIC_NAME (1U << 1) +/* No compat trust if self-signed, preempts "DO_SS" */ +# define X509_TRUST_NO_SS_COMPAT (1U << 2) +/* Compat trust if no explicit accepted trust EKUs */ +# define X509_TRUST_DO_SS_COMPAT (1U << 3) +/* Accept "anyEKU" as a wildcard trust OID */ +# define X509_TRUST_OK_ANY_EKU (1U << 4) + +/* check_trust return codes */ + +# define X509_TRUST_TRUSTED 1 +# define X509_TRUST_REJECTED 2 +# define X509_TRUST_UNTRUSTED 3 + +/* Flags for X509_print_ex() */ + +# define X509_FLAG_COMPAT 0 +# define X509_FLAG_NO_HEADER 1L +# define X509_FLAG_NO_VERSION (1L << 1) +# define X509_FLAG_NO_SERIAL (1L << 2) +# define X509_FLAG_NO_SIGNAME (1L << 3) +# define X509_FLAG_NO_ISSUER (1L << 4) +# define X509_FLAG_NO_VALIDITY (1L << 5) +# define X509_FLAG_NO_SUBJECT (1L << 6) +# define X509_FLAG_NO_PUBKEY (1L << 7) +# define X509_FLAG_NO_EXTENSIONS (1L << 8) +# define X509_FLAG_NO_SIGDUMP (1L << 9) +# define X509_FLAG_NO_AUX (1L << 10) +# define X509_FLAG_NO_ATTRIBUTES (1L << 11) +# define X509_FLAG_NO_IDS (1L << 12) + +/* Flags specific to X509_NAME_print_ex() */ + +/* The field separator information */ + +# define XN_FLAG_SEP_MASK (0xf << 16) + +# define XN_FLAG_COMPAT 0/* Traditional; use old X509_NAME_print */ +# define XN_FLAG_SEP_COMMA_PLUS (1 << 16)/* RFC2253 ,+ */ +# define XN_FLAG_SEP_CPLUS_SPC (2 << 16)/* ,+ spaced: more readable */ +# define XN_FLAG_SEP_SPLUS_SPC (3 << 16)/* ;+ spaced */ +# define XN_FLAG_SEP_MULTILINE (4 << 16)/* One line per field */ + +# define XN_FLAG_DN_REV (1 << 20)/* Reverse DN order */ + +/* How the field name is shown */ + +# define XN_FLAG_FN_MASK (0x3 << 21) + +# define XN_FLAG_FN_SN 0/* Object short name */ +# define XN_FLAG_FN_LN (1 << 21)/* Object long name */ +# define XN_FLAG_FN_OID (2 << 21)/* Always use OIDs */ +# define XN_FLAG_FN_NONE (3 << 21)/* No field names */ + +# define XN_FLAG_SPC_EQ (1 << 23)/* Put spaces round '=' */ + +/* + * This determines if we dump fields we don't recognise: RFC2253 requires + * this. + */ + +# define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24) + +# define XN_FLAG_FN_ALIGN (1 << 25)/* Align field names to 20 + * characters */ + +/* Complete set of RFC2253 flags */ + +# define XN_FLAG_RFC2253 (ASN1_STRFLGS_RFC2253 | \ + XN_FLAG_SEP_COMMA_PLUS | \ + XN_FLAG_DN_REV | \ + XN_FLAG_FN_SN | \ + XN_FLAG_DUMP_UNKNOWN_FIELDS) + +/* readable oneline form */ + +# define XN_FLAG_ONELINE (ASN1_STRFLGS_RFC2253 | \ + ASN1_STRFLGS_ESC_QUOTE | \ + XN_FLAG_SEP_CPLUS_SPC | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_SN) + +/* readable multiline form */ + +# define XN_FLAG_MULTILINE (ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + XN_FLAG_SEP_MULTILINE | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_LN | \ + XN_FLAG_FN_ALIGN) + +DEFINE_STACK_OF(X509_REVOKED) + +typedef struct X509_crl_info_st X509_CRL_INFO; + +DEFINE_STACK_OF(X509_CRL) + +typedef struct private_key_st { + int version; + /* The PKCS#8 data types */ + X509_ALGOR *enc_algor; + ASN1_OCTET_STRING *enc_pkey; /* encrypted pub key */ + /* When decrypted, the following will not be NULL */ + EVP_PKEY *dec_pkey; + /* used to encrypt and decrypt */ + int key_length; + char *key_data; + int key_free; /* true if we should auto free key_data */ + /* expanded version of 'enc_algor' */ + EVP_CIPHER_INFO cipher; +} X509_PKEY; + +typedef struct X509_info_st { + X509 *x509; + X509_CRL *crl; + X509_PKEY *x_pkey; + EVP_CIPHER_INFO enc_cipher; + int enc_len; + char *enc_data; +} X509_INFO; + +DEFINE_STACK_OF(X509_INFO) + +/* + * The next 2 structures and their 8 routines were sent to me by Pat Richard + * and are used to manipulate Netscapes spki structures - + * useful if you are writing a CA web page + */ +typedef struct Netscape_spkac_st { + X509_PUBKEY *pubkey; + ASN1_IA5STRING *challenge; /* challenge sent in atlas >= PR2 */ +} NETSCAPE_SPKAC; + +typedef struct Netscape_spki_st { + NETSCAPE_SPKAC *spkac; /* signed public key and challenge */ + X509_ALGOR sig_algor; + ASN1_BIT_STRING *signature; +} NETSCAPE_SPKI; + +/* Netscape certificate sequence structure */ +typedef struct Netscape_certificate_sequence { + ASN1_OBJECT *type; + STACK_OF(X509) *certs; +} NETSCAPE_CERT_SEQUENCE; + +/*- Unused (and iv length is wrong) +typedef struct CBCParameter_st + { + unsigned char iv[8]; + } CBC_PARAM; +*/ + +/* Password based encryption structure */ + +typedef struct PBEPARAM_st { + ASN1_OCTET_STRING *salt; + ASN1_INTEGER *iter; +} PBEPARAM; + +/* Password based encryption V2 structures */ + +typedef struct PBE2PARAM_st { + X509_ALGOR *keyfunc; + X509_ALGOR *encryption; +} PBE2PARAM; + +typedef struct PBKDF2PARAM_st { +/* Usually OCTET STRING but could be anything */ + ASN1_TYPE *salt; + ASN1_INTEGER *iter; + ASN1_INTEGER *keylength; + X509_ALGOR *prf; +} PBKDF2PARAM; + +#ifdef __cplusplus +} +#endif + +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +# define X509_EXT_PACK_UNKNOWN 1 +# define X509_EXT_PACK_STRING 2 + +# define X509_extract_key(x) X509_get_pubkey(x)/*****/ +# define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a) +# define X509_name_cmp(a,b) X509_NAME_cmp((a),(b)) + +void X509_CRL_set_default_method(const X509_CRL_METHOD *meth); +X509_CRL_METHOD *X509_CRL_METHOD_new(int (*crl_init) (X509_CRL *crl), + int (*crl_free) (X509_CRL *crl), + int (*crl_lookup) (X509_CRL *crl, + X509_REVOKED **ret, + ASN1_INTEGER *ser, + X509_NAME *issuer), + int (*crl_verify) (X509_CRL *crl, + EVP_PKEY *pk)); +void X509_CRL_METHOD_free(X509_CRL_METHOD *m); + +void X509_CRL_set_meth_data(X509_CRL *crl, void *dat); +void *X509_CRL_get_meth_data(X509_CRL *crl); + +const char *X509_verify_cert_error_string(long n); + +int X509_verify(X509 *a, EVP_PKEY *r); + +int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r); +int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r); +int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r); + +NETSCAPE_SPKI *NETSCAPE_SPKI_b64_decode(const char *str, int len); +char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *x); +EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x); +int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey); + +int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki); + +int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent); +int X509_signature_print(BIO *bp, const X509_ALGOR *alg, + const ASN1_STRING *sig); + +int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx); +# ifndef OPENSSL_NO_OCSP +int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert); +# endif +int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md); +int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx); +int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md); +int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx); +# ifndef OPENSSL_NO_OCSP +int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl); +# endif +int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md); + +int X509_pubkey_digest(const X509 *data, const EVP_MD *type, + unsigned char *md, unsigned int *len); +int X509_digest(const X509 *data, const EVP_MD *type, + unsigned char *md, unsigned int *len); +int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type, + unsigned char *md, unsigned int *len); +int X509_REQ_digest(const X509_REQ *data, const EVP_MD *type, + unsigned char *md, unsigned int *len); +int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type, + unsigned char *md, unsigned int *len); + +# ifndef OPENSSL_NO_STDIO +X509 *d2i_X509_fp(FILE *fp, X509 **x509); +int i2d_X509_fp(FILE *fp, X509 *x509); +X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl); +int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl); +X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req); +int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req); +# ifndef OPENSSL_NO_RSA +RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa); +int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa); +RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa); +int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa); +RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa); +int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa); +# endif +# ifndef OPENSSL_NO_DSA +DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa); +int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa); +DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa); +int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa); +# endif +# ifndef OPENSSL_NO_EC +EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey); +int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey); +EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey); +int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey); +# endif +X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8); +int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8); +PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, + PKCS8_PRIV_KEY_INFO **p8inf); +int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, PKCS8_PRIV_KEY_INFO *p8inf); +int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); +int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); +int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a); +# endif + +X509 *d2i_X509_bio(BIO *bp, X509 **x509); +int i2d_X509_bio(BIO *bp, X509 *x509); +X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl); +int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl); +X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req); +int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req); +# ifndef OPENSSL_NO_RSA +RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa); +int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa); +RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa); +int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa); +RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa); +int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa); +# endif +# ifndef OPENSSL_NO_DSA +DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa); +int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa); +DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa); +int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa); +# endif +# ifndef OPENSSL_NO_EC +EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey); +int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey); +EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey); +int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey); +# endif +X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8); +int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8); +PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, + PKCS8_PRIV_KEY_INFO **p8inf); +int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, PKCS8_PRIV_KEY_INFO *p8inf); +int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); +int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); +int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a); + +X509 *X509_dup(X509 *x509); +X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa); +X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex); +X509_CRL *X509_CRL_dup(X509_CRL *crl); +X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev); +X509_REQ *X509_REQ_dup(X509_REQ *req); +X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn); +int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *aobj, int ptype, + void *pval); +void X509_ALGOR_get0(const ASN1_OBJECT **paobj, int *pptype, + const void **ppval, const X509_ALGOR *algor); +void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md); +int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b); + +X509_NAME *X509_NAME_dup(X509_NAME *xn); +X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne); + +int X509_cmp_time(const ASN1_TIME *s, time_t *t); +int X509_cmp_current_time(const ASN1_TIME *s); +ASN1_TIME *X509_time_adj(ASN1_TIME *s, long adj, time_t *t); +ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s, + int offset_day, long offset_sec, time_t *t); +ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj); + +const char *X509_get_default_cert_area(void); +const char *X509_get_default_cert_dir(void); +const char *X509_get_default_cert_file(void); +const char *X509_get_default_cert_dir_env(void); +const char *X509_get_default_cert_file_env(void); +const char *X509_get_default_private_dir(void); + +X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey); + +DECLARE_ASN1_FUNCTIONS(X509_ALGOR) +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS) +DECLARE_ASN1_FUNCTIONS(X509_VAL) + +DECLARE_ASN1_FUNCTIONS(X509_PUBKEY) + +int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey); +EVP_PKEY *X509_PUBKEY_get0(X509_PUBKEY *key); +EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key); +int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain); +long X509_get_pathlen(X509 *x); +int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp); +EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length); +# ifndef OPENSSL_NO_RSA +int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp); +RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, long length); +# endif +# ifndef OPENSSL_NO_DSA +int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp); +DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length); +# endif +# ifndef OPENSSL_NO_EC +int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp); +EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length); +# endif + +DECLARE_ASN1_FUNCTIONS(X509_SIG) +void X509_SIG_get0(const X509_SIG *sig, const X509_ALGOR **palg, + const ASN1_OCTET_STRING **pdigest); +void X509_SIG_getm(X509_SIG *sig, X509_ALGOR **palg, + ASN1_OCTET_STRING **pdigest); + +DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO) +DECLARE_ASN1_FUNCTIONS(X509_REQ) + +DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE) +X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value); + +DECLARE_ASN1_FUNCTIONS(X509_EXTENSION) +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) + +DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY) + +DECLARE_ASN1_FUNCTIONS(X509_NAME) + +int X509_NAME_set(X509_NAME **xn, X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(X509_CINF) + +DECLARE_ASN1_FUNCTIONS(X509) +DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX) + +#define X509_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509, l, p, newf, dupf, freef) +int X509_set_ex_data(X509 *r, int idx, void *arg); +void *X509_get_ex_data(X509 *r, int idx); +int i2d_X509_AUX(X509 *a, unsigned char **pp); +X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length); + +int i2d_re_X509_tbs(X509 *x, unsigned char **pp); + +void X509_get0_signature(const ASN1_BIT_STRING **psig, + const X509_ALGOR **palg, const X509 *x); +int X509_get_signature_nid(const X509 *x); + +int X509_trusted(const X509 *x); +int X509_alias_set1(X509 *x, const unsigned char *name, int len); +int X509_keyid_set1(X509 *x, const unsigned char *id, int len); +unsigned char *X509_alias_get0(X509 *x, int *len); +unsigned char *X509_keyid_get0(X509 *x, int *len); +int (*X509_TRUST_set_default(int (*trust) (int, X509 *, int))) (int, X509 *, + int); +int X509_TRUST_set(int *t, int trust); +int X509_add1_trust_object(X509 *x, const ASN1_OBJECT *obj); +int X509_add1_reject_object(X509 *x, const ASN1_OBJECT *obj); +void X509_trust_clear(X509 *x); +void X509_reject_clear(X509 *x); + +STACK_OF(ASN1_OBJECT) *X509_get0_trust_objects(X509 *x); +STACK_OF(ASN1_OBJECT) *X509_get0_reject_objects(X509 *x); + +DECLARE_ASN1_FUNCTIONS(X509_REVOKED) +DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO) +DECLARE_ASN1_FUNCTIONS(X509_CRL) + +int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); +int X509_CRL_get0_by_serial(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial); +int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x); + +X509_PKEY *X509_PKEY_new(void); +void X509_PKEY_free(X509_PKEY *a); + +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE) + +X509_INFO *X509_INFO_new(void); +void X509_INFO_free(X509_INFO *a); +char *X509_NAME_oneline(const X509_NAME *a, char *buf, int size); + +int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *algor1, + ASN1_BIT_STRING *signature, char *data, EVP_PKEY *pkey); + +int ASN1_digest(i2d_of_void *i2d, const EVP_MD *type, char *data, + unsigned char *md, unsigned int *len); + +int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1, + X509_ALGOR *algor2, ASN1_BIT_STRING *signature, + char *data, EVP_PKEY *pkey, const EVP_MD *type); + +int ASN1_item_digest(const ASN1_ITEM *it, const EVP_MD *type, void *data, + unsigned char *md, unsigned int *len); + +int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1, + ASN1_BIT_STRING *signature, void *data, EVP_PKEY *pkey); + +int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, + X509_ALGOR *algor2, ASN1_BIT_STRING *signature, void *data, + EVP_PKEY *pkey, const EVP_MD *type); +int ASN1_item_sign_ctx(const ASN1_ITEM *it, X509_ALGOR *algor1, + X509_ALGOR *algor2, ASN1_BIT_STRING *signature, + void *asn, EVP_MD_CTX *ctx); + +long X509_get_version(const X509 *x); +int X509_set_version(X509 *x, long version); +int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial); +ASN1_INTEGER *X509_get_serialNumber(X509 *x); +const ASN1_INTEGER *X509_get0_serialNumber(const X509 *x); +int X509_set_issuer_name(X509 *x, X509_NAME *name); +X509_NAME *X509_get_issuer_name(const X509 *a); +int X509_set_subject_name(X509 *x, X509_NAME *name); +X509_NAME *X509_get_subject_name(const X509 *a); +const ASN1_TIME * X509_get0_notBefore(const X509 *x); +ASN1_TIME *X509_getm_notBefore(const X509 *x); +int X509_set1_notBefore(X509 *x, const ASN1_TIME *tm); +const ASN1_TIME *X509_get0_notAfter(const X509 *x); +ASN1_TIME *X509_getm_notAfter(const X509 *x); +int X509_set1_notAfter(X509 *x, const ASN1_TIME *tm); +int X509_set_pubkey(X509 *x, EVP_PKEY *pkey); +int X509_up_ref(X509 *x); +int X509_get_signature_type(const X509 *x); + +# if OPENSSL_API_COMPAT < 0x10100000L +# define X509_get_notBefore X509_getm_notBefore +# define X509_get_notAfter X509_getm_notAfter +# define X509_set_notBefore X509_set1_notBefore +# define X509_set_notAfter X509_set1_notAfter +#endif + + +/* + * This one is only used so that a binary form can output, as in + * i2d_X509_NAME(X509_get_X509_PUBKEY(x),&buf) + */ +X509_PUBKEY *X509_get_X509_PUBKEY(const X509 *x); +const STACK_OF(X509_EXTENSION) *X509_get0_extensions(const X509 *x); +void X509_get0_uids(const X509 *x, const ASN1_BIT_STRING **piuid, + const ASN1_BIT_STRING **psuid); +const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x); + +EVP_PKEY *X509_get0_pubkey(const X509 *x); +EVP_PKEY *X509_get_pubkey(X509 *x); +ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x); +int X509_certificate_type(const X509 *x, const EVP_PKEY *pubkey); + +long X509_REQ_get_version(const X509_REQ *req); +int X509_REQ_set_version(X509_REQ *x, long version); +X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req); +int X509_REQ_set_subject_name(X509_REQ *req, X509_NAME *name); +void X509_REQ_get0_signature(const X509_REQ *req, const ASN1_BIT_STRING **psig, + const X509_ALGOR **palg); +int X509_REQ_get_signature_nid(const X509_REQ *req); +int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp); +int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey); +EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req); +EVP_PKEY *X509_REQ_get0_pubkey(X509_REQ *req); +X509_PUBKEY *X509_REQ_get_X509_PUBKEY(X509_REQ *req); +int X509_REQ_extension_nid(int nid); +int *X509_REQ_get_extension_nids(void); +void X509_REQ_set_extension_nids(int *nids); +STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req); +int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts, + int nid); +int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts); +int X509_REQ_get_attr_count(const X509_REQ *req); +int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, int lastpos); +int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, const ASN1_OBJECT *obj, + int lastpos); +X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc); +X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc); +int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr); +int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +int X509_REQ_add1_attr_by_NID(X509_REQ *req, + int nid, int type, + const unsigned char *bytes, int len); +int X509_REQ_add1_attr_by_txt(X509_REQ *req, + const char *attrname, int type, + const unsigned char *bytes, int len); + +int X509_CRL_set_version(X509_CRL *x, long version); +int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); +int X509_CRL_set1_lastUpdate(X509_CRL *x, const ASN1_TIME *tm); +int X509_CRL_set1_nextUpdate(X509_CRL *x, const ASN1_TIME *tm); +int X509_CRL_sort(X509_CRL *crl); +int X509_CRL_up_ref(X509_CRL *crl); + +# if OPENSSL_API_COMPAT < 0x10100000L +# define X509_CRL_set_lastUpdate X509_CRL_set1_lastUpdate +# define X509_CRL_set_nextUpdate X509_CRL_set1_nextUpdate +#endif + +long X509_CRL_get_version(const X509_CRL *crl); +const ASN1_TIME *X509_CRL_get0_lastUpdate(const X509_CRL *crl); +const ASN1_TIME *X509_CRL_get0_nextUpdate(const X509_CRL *crl); +DEPRECATEDIN_1_1_0(ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *crl)) +DEPRECATEDIN_1_1_0(ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl)) +X509_NAME *X509_CRL_get_issuer(const X509_CRL *crl); +const STACK_OF(X509_EXTENSION) *X509_CRL_get0_extensions(const X509_CRL *crl); +STACK_OF(X509_REVOKED) *X509_CRL_get_REVOKED(X509_CRL *crl); +void X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig, + const X509_ALGOR **palg); +int X509_CRL_get_signature_nid(const X509_CRL *crl); +int i2d_re_X509_CRL_tbs(X509_CRL *req, unsigned char **pp); + +const ASN1_INTEGER *X509_REVOKED_get0_serialNumber(const X509_REVOKED *x); +int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial); +const ASN1_TIME *X509_REVOKED_get0_revocationDate(const X509_REVOKED *x); +int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm); +const STACK_OF(X509_EXTENSION) * +X509_REVOKED_get0_extensions(const X509_REVOKED *r); + +X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, + EVP_PKEY *skey, const EVP_MD *md, unsigned int flags); + +int X509_REQ_check_private_key(X509_REQ *x509, EVP_PKEY *pkey); + +int X509_check_private_key(const X509 *x509, const EVP_PKEY *pkey); +int X509_chain_check_suiteb(int *perror_depth, + X509 *x, STACK_OF(X509) *chain, + unsigned long flags); +int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags); +STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain); + +int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b); +unsigned long X509_issuer_and_serial_hash(X509 *a); + +int X509_issuer_name_cmp(const X509 *a, const X509 *b); +unsigned long X509_issuer_name_hash(X509 *a); + +int X509_subject_name_cmp(const X509 *a, const X509 *b); +unsigned long X509_subject_name_hash(X509 *x); + +# ifndef OPENSSL_NO_MD5 +unsigned long X509_issuer_name_hash_old(X509 *a); +unsigned long X509_subject_name_hash_old(X509 *x); +# endif + +int X509_cmp(const X509 *a, const X509 *b); +int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b); +unsigned long X509_NAME_hash(X509_NAME *x); +unsigned long X509_NAME_hash_old(X509_NAME *x); + +int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b); +int X509_CRL_match(const X509_CRL *a, const X509_CRL *b); +int X509_aux_print(BIO *out, X509 *x, int indent); +# ifndef OPENSSL_NO_STDIO +int X509_print_ex_fp(FILE *bp, X509 *x, unsigned long nmflag, + unsigned long cflag); +int X509_print_fp(FILE *bp, X509 *x); +int X509_CRL_print_fp(FILE *bp, X509_CRL *x); +int X509_REQ_print_fp(FILE *bp, X509_REQ *req); +int X509_NAME_print_ex_fp(FILE *fp, const X509_NAME *nm, int indent, + unsigned long flags); +# endif + +int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase); +int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent, + unsigned long flags); +int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflag, + unsigned long cflag); +int X509_print(BIO *bp, X509 *x); +int X509_ocspid_print(BIO *bp, X509 *x); +int X509_CRL_print(BIO *bp, X509_CRL *x); +int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, + unsigned long cflag); +int X509_REQ_print(BIO *bp, X509_REQ *req); + +int X509_NAME_entry_count(const X509_NAME *name); +int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len); +int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + char *buf, int len); + +/* + * NOTE: you should be passing -1, not 0 as lastpos. The functions that use + * lastpos, search after that position on. + */ +int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos); +int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + int lastpos); +X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc); +X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc); +int X509_NAME_add_entry(X509_NAME *name, const X509_NAME_ENTRY *ne, + int loc, int set); +int X509_NAME_add_entry_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len, int loc, + int set); +int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + const unsigned char *bytes, int len, int loc, + int set); +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + const char *field, int type, + const unsigned char *bytes, + int len); +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, + int type, + const unsigned char *bytes, + int len); +int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, + const unsigned char *bytes, int len, int loc, + int set); +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, + int len); +int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, const ASN1_OBJECT *obj); +int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, + const unsigned char *bytes, int len); +ASN1_OBJECT *X509_NAME_ENTRY_get_object(const X509_NAME_ENTRY *ne); +ASN1_STRING * X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne); +int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne); + +int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, + size_t *pderlen); + +int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x); +int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, + int nid, int lastpos); +int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x, + const ASN1_OBJECT *obj, int lastpos); +int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x, + int crit, int lastpos); +X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc); +X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc); +STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, + X509_EXTENSION *ex, int loc); + +int X509_get_ext_count(const X509 *x); +int X509_get_ext_by_NID(const X509 *x, int nid, int lastpos); +int X509_get_ext_by_OBJ(const X509 *x, const ASN1_OBJECT *obj, int lastpos); +int X509_get_ext_by_critical(const X509 *x, int crit, int lastpos); +X509_EXTENSION *X509_get_ext(const X509 *x, int loc); +X509_EXTENSION *X509_delete_ext(X509 *x, int loc); +int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); +void *X509_get_ext_d2i(const X509 *x, int nid, int *crit, int *idx); +int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, + unsigned long flags); + +int X509_CRL_get_ext_count(const X509_CRL *x); +int X509_CRL_get_ext_by_NID(const X509_CRL *x, int nid, int lastpos); +int X509_CRL_get_ext_by_OBJ(const X509_CRL *x, const ASN1_OBJECT *obj, + int lastpos); +int X509_CRL_get_ext_by_critical(const X509_CRL *x, int crit, int lastpos); +X509_EXTENSION *X509_CRL_get_ext(const X509_CRL *x, int loc); +X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc); +int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc); +void *X509_CRL_get_ext_d2i(const X509_CRL *x, int nid, int *crit, int *idx); +int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, + unsigned long flags); + +int X509_REVOKED_get_ext_count(const X509_REVOKED *x); +int X509_REVOKED_get_ext_by_NID(const X509_REVOKED *x, int nid, int lastpos); +int X509_REVOKED_get_ext_by_OBJ(const X509_REVOKED *x, const ASN1_OBJECT *obj, + int lastpos); +int X509_REVOKED_get_ext_by_critical(const X509_REVOKED *x, int crit, + int lastpos); +X509_EXTENSION *X509_REVOKED_get_ext(const X509_REVOKED *x, int loc); +X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc); +int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc); +void *X509_REVOKED_get_ext_d2i(const X509_REVOKED *x, int nid, int *crit, + int *idx); +int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, + unsigned long flags); + +X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, + int nid, int crit, + ASN1_OCTET_STRING *data); +X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex, + const ASN1_OBJECT *obj, int crit, + ASN1_OCTET_STRING *data); +int X509_EXTENSION_set_object(X509_EXTENSION *ex, const ASN1_OBJECT *obj); +int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit); +int X509_EXTENSION_set_data(X509_EXTENSION *ex, ASN1_OCTET_STRING *data); +ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex); +ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne); +int X509_EXTENSION_get_critical(const X509_EXTENSION *ex); + +int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x); +int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, + int lastpos); +int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, + const ASN1_OBJECT *obj, int lastpos); +X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc); +X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc); +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr); +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) + **x, const ASN1_OBJECT *obj, + int type, + const unsigned char *bytes, + int len); +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) + **x, int nid, int type, + const unsigned char *bytes, + int len); +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) + **x, const char *attrname, + int type, + const unsigned char *bytes, + int len); +void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, + const ASN1_OBJECT *obj, int lastpos, int type); +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, + int atrtype, const void *data, + int len); +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, + const ASN1_OBJECT *obj, + int atrtype, const void *data, + int len); +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, + const char *atrname, int type, + const unsigned char *bytes, + int len); +int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj); +int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, + const void *data, int len); +void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, int atrtype, + void *data); +int X509_ATTRIBUTE_count(const X509_ATTRIBUTE *attr); +ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr); +ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx); + +int EVP_PKEY_get_attr_count(const EVP_PKEY *key); +int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, int lastpos); +int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, const ASN1_OBJECT *obj, + int lastpos); +X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc); +X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc); +int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr); +int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key, + int nid, int type, + const unsigned char *bytes, int len); +int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, + const char *attrname, int type, + const unsigned char *bytes, int len); + +int X509_verify_cert(X509_STORE_CTX *ctx); + +/* lookup a cert from a X509 STACK */ +X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name, + ASN1_INTEGER *serial); +X509 *X509_find_by_subject(STACK_OF(X509) *sk, X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(PBEPARAM) +DECLARE_ASN1_FUNCTIONS(PBE2PARAM) +DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM) + +int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter, + const unsigned char *salt, int saltlen); + +X509_ALGOR *PKCS5_pbe_set(int alg, int iter, + const unsigned char *salt, int saltlen); +X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen); +X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen, + unsigned char *aiv, int prf_nid); + +#ifndef OPENSSL_NO_SCRYPT +X509_ALGOR *PKCS5_pbe2_set_scrypt(const EVP_CIPHER *cipher, + const unsigned char *salt, int saltlen, + unsigned char *aiv, uint64_t N, uint64_t r, + uint64_t p); +#endif + +X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, + int prf_nid, int keylen); + +/* PKCS#8 utilities */ + +DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) + +EVP_PKEY *EVP_PKCS82PKEY(const PKCS8_PRIV_KEY_INFO *p8); +PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey); + +int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, + int version, int ptype, void *pval, + unsigned char *penc, int penclen); +int PKCS8_pkey_get0(const ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + const X509_ALGOR **pa, const PKCS8_PRIV_KEY_INFO *p8); + +const STACK_OF(X509_ATTRIBUTE) * +PKCS8_pkey_get0_attrs(const PKCS8_PRIV_KEY_INFO *p8); +int PKCS8_pkey_add1_attr_by_NID(PKCS8_PRIV_KEY_INFO *p8, int nid, int type, + const unsigned char *bytes, int len); + +int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj, + int ptype, void *pval, + unsigned char *penc, int penclen); +int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, X509_PUBKEY *pub); + +int X509_check_trust(X509 *x, int id, int flags); +int X509_TRUST_get_count(void); +X509_TRUST *X509_TRUST_get0(int idx); +int X509_TRUST_get_by_id(int id); +int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int), + const char *name, int arg1, void *arg2); +void X509_TRUST_cleanup(void); +int X509_TRUST_get_flags(const X509_TRUST *xp); +char *X509_TRUST_get0_name(const X509_TRUST *xp); +int X509_TRUST_get_trust(const X509_TRUST *xp); + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_X509_strings(void); + +/* Error codes for the X509 functions. */ + +/* Function codes. */ +# define X509_F_ADD_CERT_DIR 100 +# define X509_F_BUILD_CHAIN 106 +# define X509_F_BY_FILE_CTRL 101 +# define X509_F_CHECK_NAME_CONSTRAINTS 149 +# define X509_F_CHECK_POLICY 145 +# define X509_F_DANE_I2D 107 +# define X509_F_DIR_CTRL 102 +# define X509_F_GET_CERT_BY_SUBJECT 103 +# define X509_F_NETSCAPE_SPKI_B64_DECODE 129 +# define X509_F_NETSCAPE_SPKI_B64_ENCODE 130 +# define X509_F_X509AT_ADD1_ATTR 135 +# define X509_F_X509V3_ADD_EXT 104 +# define X509_F_X509_ATTRIBUTE_CREATE_BY_NID 136 +# define X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ 137 +# define X509_F_X509_ATTRIBUTE_CREATE_BY_TXT 140 +# define X509_F_X509_ATTRIBUTE_GET0_DATA 139 +# define X509_F_X509_ATTRIBUTE_SET1_DATA 138 +# define X509_F_X509_CHECK_PRIVATE_KEY 128 +# define X509_F_X509_CRL_DIFF 105 +# define X509_F_X509_CRL_PRINT_FP 147 +# define X509_F_X509_EXTENSION_CREATE_BY_NID 108 +# define X509_F_X509_EXTENSION_CREATE_BY_OBJ 109 +# define X509_F_X509_GET_PUBKEY_PARAMETERS 110 +# define X509_F_X509_LOAD_CERT_CRL_FILE 132 +# define X509_F_X509_LOAD_CERT_FILE 111 +# define X509_F_X509_LOAD_CRL_FILE 112 +# define X509_F_X509_NAME_ADD_ENTRY 113 +# define X509_F_X509_NAME_ENTRY_CREATE_BY_NID 114 +# define X509_F_X509_NAME_ENTRY_CREATE_BY_TXT 131 +# define X509_F_X509_NAME_ENTRY_SET_OBJECT 115 +# define X509_F_X509_NAME_ONELINE 116 +# define X509_F_X509_NAME_PRINT 117 +# define X509_F_X509_OBJECT_NEW 150 +# define X509_F_X509_PRINT_EX_FP 118 +# define X509_F_X509_PUBKEY_DECODE 148 +# define X509_F_X509_PUBKEY_GET0 119 +# define X509_F_X509_PUBKEY_SET 120 +# define X509_F_X509_REQ_CHECK_PRIVATE_KEY 144 +# define X509_F_X509_REQ_PRINT_EX 121 +# define X509_F_X509_REQ_PRINT_FP 122 +# define X509_F_X509_REQ_TO_X509 123 +# define X509_F_X509_STORE_ADD_CERT 124 +# define X509_F_X509_STORE_ADD_CRL 125 +# define X509_F_X509_STORE_CTX_GET1_ISSUER 146 +# define X509_F_X509_STORE_CTX_INIT 143 +# define X509_F_X509_STORE_CTX_NEW 142 +# define X509_F_X509_STORE_CTX_PURPOSE_INHERIT 134 +# define X509_F_X509_TO_X509_REQ 126 +# define X509_F_X509_TRUST_ADD 133 +# define X509_F_X509_TRUST_SET 141 +# define X509_F_X509_VERIFY_CERT 127 + +/* Reason codes. */ +# define X509_R_AKID_MISMATCH 110 +# define X509_R_BAD_SELECTOR 133 +# define X509_R_BAD_X509_FILETYPE 100 +# define X509_R_BASE64_DECODE_ERROR 118 +# define X509_R_CANT_CHECK_DH_KEY 114 +# define X509_R_CERT_ALREADY_IN_HASH_TABLE 101 +# define X509_R_CRL_ALREADY_DELTA 127 +# define X509_R_CRL_VERIFY_FAILURE 131 +# define X509_R_IDP_MISMATCH 128 +# define X509_R_INVALID_DIRECTORY 113 +# define X509_R_INVALID_FIELD_NAME 119 +# define X509_R_INVALID_TRUST 123 +# define X509_R_ISSUER_MISMATCH 129 +# define X509_R_KEY_TYPE_MISMATCH 115 +# define X509_R_KEY_VALUES_MISMATCH 116 +# define X509_R_LOADING_CERT_DIR 103 +# define X509_R_LOADING_DEFAULTS 104 +# define X509_R_METHOD_NOT_SUPPORTED 124 +# define X509_R_NAME_TOO_LONG 134 +# define X509_R_NEWER_CRL_NOT_NEWER 132 +# define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY 105 +# define X509_R_NO_CRL_NUMBER 130 +# define X509_R_PUBLIC_KEY_DECODE_ERROR 125 +# define X509_R_PUBLIC_KEY_ENCODE_ERROR 126 +# define X509_R_SHOULD_RETRY 106 +# define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN 107 +# define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY 108 +# define X509_R_UNKNOWN_KEY_TYPE 117 +# define X509_R_UNKNOWN_NID 109 +# define X509_R_UNKNOWN_PURPOSE_ID 121 +# define X509_R_UNKNOWN_TRUST_ID 120 +# define X509_R_UNSUPPORTED_ALGORITHM 111 +# define X509_R_WRONG_LOOKUP_TYPE 112 +# define X509_R_WRONG_TYPE 122 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/x509_vfy.h b/mobile/ios/FxA/FxA/include/openssl/x509_vfy.h new file mode 100644 index 0000000000..64f56df7f0 --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/x509_vfy.h @@ -0,0 +1,545 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_X509_VFY_H +# define HEADER_X509_VFY_H + +/* + * Protect against recursion, x509.h and x509_vfy.h each include the other. + */ +# ifndef HEADER_X509_H +# include +# endif + +# include +# include +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/*- +SSL_CTX -> X509_STORE + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + +SSL -> X509_STORE_CTX + ->X509_STORE + +The X509_STORE holds the tables etc for verification stuff. +A X509_STORE_CTX is used while validating a single certificate. +The X509_STORE has X509_LOOKUPs for looking up certs. +The X509_STORE then calls a function to actually verify the +certificate chain. +*/ + +typedef enum { + X509_LU_NONE = 0, + X509_LU_X509, X509_LU_CRL +} X509_LOOKUP_TYPE; + +#if OPENSSL_API_COMPAT < 0x10100000L +#define X509_LU_RETRY -1 +#define X509_LU_FAIL 0 +#endif + +DEFINE_STACK_OF(X509_LOOKUP) +DEFINE_STACK_OF(X509_OBJECT) +DEFINE_STACK_OF(X509_VERIFY_PARAM) + +int X509_STORE_set_depth(X509_STORE *store, int depth); + +typedef int (*X509_STORE_CTX_verify_cb)(int, X509_STORE_CTX *); +typedef int (*X509_STORE_CTX_verify_fn)(X509_STORE_CTX *); +typedef int (*X509_STORE_CTX_get_issuer_fn)(X509 **issuer, + X509_STORE_CTX *ctx, X509 *x); +typedef int (*X509_STORE_CTX_check_issued_fn)(X509_STORE_CTX *ctx, + X509 *x, X509 *issuer); +typedef int (*X509_STORE_CTX_check_revocation_fn)(X509_STORE_CTX *ctx); +typedef int (*X509_STORE_CTX_get_crl_fn)(X509_STORE_CTX *ctx, + X509_CRL **crl, X509 *x); +typedef int (*X509_STORE_CTX_check_crl_fn)(X509_STORE_CTX *ctx, X509_CRL *crl); +typedef int (*X509_STORE_CTX_cert_crl_fn)(X509_STORE_CTX *ctx, + X509_CRL *crl, X509 *x); +typedef int (*X509_STORE_CTX_check_policy_fn)(X509_STORE_CTX *ctx); +typedef STACK_OF(X509) *(*X509_STORE_CTX_lookup_certs_fn)(X509_STORE_CTX *ctx, + X509_NAME *nm); +typedef STACK_OF(X509_CRL) *(*X509_STORE_CTX_lookup_crls_fn)(X509_STORE_CTX *ctx, + X509_NAME *nm); +typedef int (*X509_STORE_CTX_cleanup_fn)(X509_STORE_CTX *ctx); + + +void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); + +# define X509_STORE_CTX_set_app_data(ctx,data) \ + X509_STORE_CTX_set_ex_data(ctx,0,data) +# define X509_STORE_CTX_get_app_data(ctx) \ + X509_STORE_CTX_get_ex_data(ctx,0) + +# define X509_L_FILE_LOAD 1 +# define X509_L_ADD_DIR 2 + +# define X509_LOOKUP_load_file(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL) + +# define X509_LOOKUP_add_dir(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL) + +# define X509_V_OK 0 +# define X509_V_ERR_UNSPECIFIED 1 +# define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 +# define X509_V_ERR_UNABLE_TO_GET_CRL 3 +# define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 +# define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5 +# define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6 +# define X509_V_ERR_CERT_SIGNATURE_FAILURE 7 +# define X509_V_ERR_CRL_SIGNATURE_FAILURE 8 +# define X509_V_ERR_CERT_NOT_YET_VALID 9 +# define X509_V_ERR_CERT_HAS_EXPIRED 10 +# define X509_V_ERR_CRL_NOT_YET_VALID 11 +# define X509_V_ERR_CRL_HAS_EXPIRED 12 +# define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13 +# define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14 +# define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15 +# define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16 +# define X509_V_ERR_OUT_OF_MEM 17 +# define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18 +# define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19 +# define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20 +# define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21 +# define X509_V_ERR_CERT_CHAIN_TOO_LONG 22 +# define X509_V_ERR_CERT_REVOKED 23 +# define X509_V_ERR_INVALID_CA 24 +# define X509_V_ERR_PATH_LENGTH_EXCEEDED 25 +# define X509_V_ERR_INVALID_PURPOSE 26 +# define X509_V_ERR_CERT_UNTRUSTED 27 +# define X509_V_ERR_CERT_REJECTED 28 +/* These are 'informational' when looking for issuer cert */ +# define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29 +# define X509_V_ERR_AKID_SKID_MISMATCH 30 +# define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31 +# define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 +# define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +# define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 +# define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 +# define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +# define X509_V_ERR_INVALID_NON_CA 37 +# define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38 +# define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39 +# define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40 +# define X509_V_ERR_INVALID_EXTENSION 41 +# define X509_V_ERR_INVALID_POLICY_EXTENSION 42 +# define X509_V_ERR_NO_EXPLICIT_POLICY 43 +# define X509_V_ERR_DIFFERENT_CRL_SCOPE 44 +# define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45 +# define X509_V_ERR_UNNESTED_RESOURCE 46 +# define X509_V_ERR_PERMITTED_VIOLATION 47 +# define X509_V_ERR_EXCLUDED_VIOLATION 48 +# define X509_V_ERR_SUBTREE_MINMAX 49 +/* The application is not happy */ +# define X509_V_ERR_APPLICATION_VERIFICATION 50 +# define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51 +# define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52 +# define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 +# define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54 +/* Another issuer check debug option */ +# define X509_V_ERR_PATH_LOOP 55 +/* Suite B mode algorithm violation */ +# define X509_V_ERR_SUITE_B_INVALID_VERSION 56 +# define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57 +# define X509_V_ERR_SUITE_B_INVALID_CURVE 58 +# define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59 +# define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60 +# define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61 +/* Host, email and IP check errors */ +# define X509_V_ERR_HOSTNAME_MISMATCH 62 +# define X509_V_ERR_EMAIL_MISMATCH 63 +# define X509_V_ERR_IP_ADDRESS_MISMATCH 64 +/* DANE TLSA errors */ +# define X509_V_ERR_DANE_NO_MATCH 65 +/* security level errors */ +# define X509_V_ERR_EE_KEY_TOO_SMALL 66 +# define X509_V_ERR_CA_KEY_TOO_SMALL 67 +# define X509_V_ERR_CA_MD_TOO_WEAK 68 +/* Caller error */ +# define X509_V_ERR_INVALID_CALL 69 +/* Issuer lookup error */ +# define X509_V_ERR_STORE_LOOKUP 70 +/* Certificate transparency */ +# define X509_V_ERR_NO_VALID_SCTS 71 + +# define X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION 72 + +/* Certificate verify flags */ + +# if OPENSSL_API_COMPAT < 0x10100000L +# define X509_V_FLAG_CB_ISSUER_CHECK 0x0 /* Deprecated */ +# endif +/* Use check time instead of current time */ +# define X509_V_FLAG_USE_CHECK_TIME 0x2 +/* Lookup CRLs */ +# define X509_V_FLAG_CRL_CHECK 0x4 +/* Lookup CRLs for whole chain */ +# define X509_V_FLAG_CRL_CHECK_ALL 0x8 +/* Ignore unhandled critical extensions */ +# define X509_V_FLAG_IGNORE_CRITICAL 0x10 +/* Disable workarounds for broken certificates */ +# define X509_V_FLAG_X509_STRICT 0x20 +/* Enable proxy certificate validation */ +# define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40 +/* Enable policy checking */ +# define X509_V_FLAG_POLICY_CHECK 0x80 +/* Policy variable require-explicit-policy */ +# define X509_V_FLAG_EXPLICIT_POLICY 0x100 +/* Policy variable inhibit-any-policy */ +# define X509_V_FLAG_INHIBIT_ANY 0x200 +/* Policy variable inhibit-policy-mapping */ +# define X509_V_FLAG_INHIBIT_MAP 0x400 +/* Notify callback that policy is OK */ +# define X509_V_FLAG_NOTIFY_POLICY 0x800 +/* Extended CRL features such as indirect CRLs, alternate CRL signing keys */ +# define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000 +/* Delta CRL support */ +# define X509_V_FLAG_USE_DELTAS 0x2000 +/* Check self-signed CA signature */ +# define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 +/* Use trusted store first */ +# define X509_V_FLAG_TRUSTED_FIRST 0x8000 +/* Suite B 128 bit only mode: not normally used */ +# define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000 +/* Suite B 192 bit only mode */ +# define X509_V_FLAG_SUITEB_192_LOS 0x20000 +/* Suite B 128 bit mode allowing 192 bit algorithms */ +# define X509_V_FLAG_SUITEB_128_LOS 0x30000 +/* Allow partial chains if at least one certificate is in trusted store */ +# define X509_V_FLAG_PARTIAL_CHAIN 0x80000 +/* + * If the initial chain is not trusted, do not attempt to build an alternative + * chain. Alternate chain checking was introduced in 1.1.0. Setting this flag + * will force the behaviour to match that of previous versions. + */ +# define X509_V_FLAG_NO_ALT_CHAINS 0x100000 +/* Do not check certificate/CRL validity against current time */ +# define X509_V_FLAG_NO_CHECK_TIME 0x200000 + +# define X509_VP_FLAG_DEFAULT 0x1 +# define X509_VP_FLAG_OVERWRITE 0x2 +# define X509_VP_FLAG_RESET_FLAGS 0x4 +# define X509_VP_FLAG_LOCKED 0x8 +# define X509_VP_FLAG_ONCE 0x10 + +/* Internal use: mask of policy related options */ +# define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \ + | X509_V_FLAG_EXPLICIT_POLICY \ + | X509_V_FLAG_INHIBIT_ANY \ + | X509_V_FLAG_INHIBIT_MAP) + +int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, X509_LOOKUP_TYPE type, + X509_NAME *name); +X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h, + X509_LOOKUP_TYPE type, + X509_NAME *name); +X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, + X509_OBJECT *x); +int X509_OBJECT_up_ref_count(X509_OBJECT *a); +X509_OBJECT *X509_OBJECT_new(void); +void X509_OBJECT_free(X509_OBJECT *a); +X509_LOOKUP_TYPE X509_OBJECT_get_type(const X509_OBJECT *a); +X509 *X509_OBJECT_get0_X509(const X509_OBJECT *a); +X509_CRL *X509_OBJECT_get0_X509_CRL(X509_OBJECT *a); +X509_STORE *X509_STORE_new(void); +void X509_STORE_free(X509_STORE *v); +int X509_STORE_lock(X509_STORE *ctx); +int X509_STORE_unlock(X509_STORE *ctx); +int X509_STORE_up_ref(X509_STORE *v); +STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *v); + +STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *st, X509_NAME *nm); +STACK_OF(X509_CRL) *X509_STORE_CTX_get1_crls(X509_STORE_CTX *st, X509_NAME *nm); +int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); +int X509_STORE_set_purpose(X509_STORE *ctx, int purpose); +int X509_STORE_set_trust(X509_STORE *ctx, int trust); +int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm); +X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *ctx); +int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); + +void X509_STORE_set_verify(X509_STORE *ctx, X509_STORE_CTX_verify_fn verify); +#define X509_STORE_set_verify_func(ctx, func) \ + X509_STORE_set_verify((ctx),(func)) +void X509_STORE_CTX_set_verify(X509_STORE_CTX *ctx, + X509_STORE_CTX_verify_fn verify); +X509_STORE_CTX_verify_fn X509_STORE_get_verify(X509_STORE *ctx); +void X509_STORE_set_verify_cb(X509_STORE *ctx, + X509_STORE_CTX_verify_cb verify_cb); +# define X509_STORE_set_verify_cb_func(ctx,func) \ + X509_STORE_set_verify_cb((ctx),(func)) +X509_STORE_CTX_verify_cb X509_STORE_get_verify_cb(X509_STORE *ctx); +void X509_STORE_set_get_issuer(X509_STORE *ctx, + X509_STORE_CTX_get_issuer_fn get_issuer); +X509_STORE_CTX_get_issuer_fn X509_STORE_get_get_issuer(X509_STORE *ctx); +void X509_STORE_set_check_issued(X509_STORE *ctx, + X509_STORE_CTX_check_issued_fn check_issued); +X509_STORE_CTX_check_issued_fn X509_STORE_get_check_issued(X509_STORE *ctx); +void X509_STORE_set_check_revocation(X509_STORE *ctx, + X509_STORE_CTX_check_revocation_fn check_revocation); +X509_STORE_CTX_check_revocation_fn X509_STORE_get_check_revocation(X509_STORE *ctx); +void X509_STORE_set_get_crl(X509_STORE *ctx, + X509_STORE_CTX_get_crl_fn get_crl); +X509_STORE_CTX_get_crl_fn X509_STORE_get_get_crl(X509_STORE *ctx); +void X509_STORE_set_check_crl(X509_STORE *ctx, + X509_STORE_CTX_check_crl_fn check_crl); +X509_STORE_CTX_check_crl_fn X509_STORE_get_check_crl(X509_STORE *ctx); +void X509_STORE_set_cert_crl(X509_STORE *ctx, + X509_STORE_CTX_cert_crl_fn cert_crl); +X509_STORE_CTX_cert_crl_fn X509_STORE_get_cert_crl(X509_STORE *ctx); +void X509_STORE_set_check_policy(X509_STORE *ctx, + X509_STORE_CTX_check_policy_fn check_policy); +X509_STORE_CTX_check_policy_fn X509_STORE_get_check_policy(X509_STORE *ctx); +void X509_STORE_set_lookup_certs(X509_STORE *ctx, + X509_STORE_CTX_lookup_certs_fn lookup_certs); +X509_STORE_CTX_lookup_certs_fn X509_STORE_get_lookup_certs(X509_STORE *ctx); +void X509_STORE_set_lookup_crls(X509_STORE *ctx, + X509_STORE_CTX_lookup_crls_fn lookup_crls); +#define X509_STORE_set_lookup_crls_cb(ctx, func) \ + X509_STORE_set_lookup_crls((ctx), (func)) +X509_STORE_CTX_lookup_crls_fn X509_STORE_get_lookup_crls(X509_STORE *ctx); +void X509_STORE_set_cleanup(X509_STORE *ctx, + X509_STORE_CTX_cleanup_fn cleanup); +X509_STORE_CTX_cleanup_fn X509_STORE_get_cleanup(X509_STORE *ctx); + +#define X509_STORE_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, l, p, newf, dupf, freef) +int X509_STORE_set_ex_data(X509_STORE *ctx, int idx, void *data); +void *X509_STORE_get_ex_data(X509_STORE *ctx, int idx); + +X509_STORE_CTX *X509_STORE_CTX_new(void); + +int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); + +void X509_STORE_CTX_free(X509_STORE_CTX *ctx); +int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, + X509 *x509, STACK_OF(X509) *chain); +void X509_STORE_CTX_set0_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk); +void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx); + +X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx); +X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx); +STACK_OF(X509)* X509_STORE_CTX_get0_untrusted(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set0_untrusted(X509_STORE_CTX *ctx, STACK_OF(X509) *sk); +void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, + X509_STORE_CTX_verify_cb verify); +X509_STORE_CTX_verify_cb X509_STORE_CTX_get_verify_cb(X509_STORE_CTX *ctx); +X509_STORE_CTX_verify_fn X509_STORE_CTX_get_verify(X509_STORE_CTX *ctx); +X509_STORE_CTX_get_issuer_fn X509_STORE_CTX_get_get_issuer(X509_STORE_CTX *ctx); +X509_STORE_CTX_check_issued_fn X509_STORE_CTX_get_check_issued(X509_STORE_CTX *ctx); +X509_STORE_CTX_check_revocation_fn X509_STORE_CTX_get_check_revocation(X509_STORE_CTX *ctx); +X509_STORE_CTX_get_crl_fn X509_STORE_CTX_get_get_crl(X509_STORE_CTX *ctx); +X509_STORE_CTX_check_crl_fn X509_STORE_CTX_get_check_crl(X509_STORE_CTX *ctx); +X509_STORE_CTX_cert_crl_fn X509_STORE_CTX_get_cert_crl(X509_STORE_CTX *ctx); +X509_STORE_CTX_check_policy_fn X509_STORE_CTX_get_check_policy(X509_STORE_CTX *ctx); +X509_STORE_CTX_lookup_certs_fn X509_STORE_CTX_get_lookup_certs(X509_STORE_CTX *ctx); +X509_STORE_CTX_lookup_crls_fn X509_STORE_CTX_get_lookup_crls(X509_STORE_CTX *ctx); +X509_STORE_CTX_cleanup_fn X509_STORE_CTX_get_cleanup(X509_STORE_CTX *ctx); + +#if OPENSSL_API_COMPAT < 0x10100000L +# define X509_STORE_CTX_get_chain X509_STORE_CTX_get0_chain +# define X509_STORE_CTX_set_chain X509_STORE_CTX_set0_untrusted +# define X509_STORE_CTX_trusted_stack X509_STORE_CTX_set0_trusted_stack +# define X509_STORE_get_by_subject X509_STORE_CTX_get_by_subject +# define X509_STORE_get1_cert X509_STORE_CTX_get1_certs +# define X509_STORE_get1_crl X509_STORE_CTX_get1_crls +#endif + +X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m); +X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void); +X509_LOOKUP_METHOD *X509_LOOKUP_file(void); + +int X509_STORE_add_cert(X509_STORE *ctx, X509 *x); +int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x); + +int X509_STORE_CTX_get_by_subject(X509_STORE_CTX *vs, X509_LOOKUP_TYPE type, + X509_NAME *name, X509_OBJECT *ret); +X509_OBJECT *X509_STORE_CTX_get_obj_by_subject(X509_STORE_CTX *vs, + X509_LOOKUP_TYPE type, + X509_NAME *name); + +int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, + long argl, char **ret); + +int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type); +int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type); +int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type); + +X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method); +void X509_LOOKUP_free(X509_LOOKUP *ctx); +int X509_LOOKUP_init(X509_LOOKUP *ctx); +int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, + X509_NAME *name, X509_OBJECT *ret); +int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, + X509_NAME *name, ASN1_INTEGER *serial, + X509_OBJECT *ret); +int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, + const unsigned char *bytes, int len, + X509_OBJECT *ret); +int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, + const char *str, int len, X509_OBJECT *ret); +int X509_LOOKUP_shutdown(X509_LOOKUP *ctx); + +int X509_STORE_load_locations(X509_STORE *ctx, + const char *file, const char *dir); +int X509_STORE_set_default_paths(X509_STORE *ctx); + +#define X509_STORE_CTX_get_ex_new_index(l, p, newf, dupf, freef) \ + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE_CTX, l, p, newf, dupf, freef) +int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, void *data); +void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx); +int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int s); +int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set_error_depth(X509_STORE_CTX *ctx, int depth); +X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set_current_cert(X509_STORE_CTX *ctx, X509 *x); +X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx); +X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx); +X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx); +STACK_OF(X509) *X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx); +STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set_cert(X509_STORE_CTX *c, X509 *x); +void X509_STORE_CTX_set0_verified_chain(X509_STORE_CTX *c, STACK_OF(X509) *sk); +void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c, STACK_OF(X509_CRL) *sk); +int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); +int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); +int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, + int purpose, int trust); +void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags); +void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, + time_t t); + +X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx); +int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx); +int X509_STORE_CTX_get_num_untrusted(X509_STORE_CTX *ctx); + +X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param); +int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name); + +/* + * Bridge opacity barrier between libcrypt and libssl, also needed to support + * offline testing in test/danetest.c + */ +void X509_STORE_CTX_set0_dane(X509_STORE_CTX *ctx, SSL_DANE *dane); +#define DANE_FLAG_NO_DANE_EE_NAMECHECKS (1L << 0) + +/* X509_VERIFY_PARAM functions */ + +X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void); +void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param); +int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name); +int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, + unsigned long flags); +int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, + unsigned long flags); +unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param); +int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); +int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); +void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth); +void X509_VERIFY_PARAM_set_auth_level(X509_VERIFY_PARAM *param, int auth_level); +time_t X509_VERIFY_PARAM_get_time(const X509_VERIFY_PARAM *param); +void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t); +int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, + ASN1_OBJECT *policy); +int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies); + +int X509_VERIFY_PARAM_set_inh_flags(X509_VERIFY_PARAM *param, + uint32_t flags); +uint32_t X509_VERIFY_PARAM_get_inh_flags(const X509_VERIFY_PARAM *param); + +int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen); +int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen); +void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, + unsigned int flags); +char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *); +void X509_VERIFY_PARAM_move_peername(X509_VERIFY_PARAM *, X509_VERIFY_PARAM *); +int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, + const char *email, size_t emaillen); +int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, + const unsigned char *ip, size_t iplen); +int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, + const char *ipasc); + +int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param); +int X509_VERIFY_PARAM_get_auth_level(const X509_VERIFY_PARAM *param); +const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param); + +int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param); +int X509_VERIFY_PARAM_get_count(void); +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id); +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name); +void X509_VERIFY_PARAM_table_cleanup(void); + +/* Non positive return values are errors */ +#define X509_PCY_TREE_FAILURE -2 /* Failure to satisfy explicit policy */ +#define X509_PCY_TREE_INVALID -1 /* Inconsistent or invalid extensions */ +#define X509_PCY_TREE_INTERNAL 0 /* Internal error, most likely malloc */ + +/* + * Positive return values form a bit mask, all but the first are internal to + * the library and don't appear in results from X509_policy_check(). + */ +#define X509_PCY_TREE_VALID 1 /* The policy tree is valid */ +#define X509_PCY_TREE_EMPTY 2 /* The policy tree is empty */ +#define X509_PCY_TREE_EXPLICIT 4 /* Explicit policy required */ + +int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, + STACK_OF(X509) *certs, + STACK_OF(ASN1_OBJECT) *policy_oids, unsigned int flags); + +void X509_policy_tree_free(X509_POLICY_TREE *tree); + +int X509_policy_tree_level_count(const X509_POLICY_TREE *tree); +X509_POLICY_LEVEL *X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, + int i); + +STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_policies(const + X509_POLICY_TREE + *tree); + +STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_user_policies(const + X509_POLICY_TREE + *tree); + +int X509_policy_level_node_count(X509_POLICY_LEVEL *level); + +X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, + int i); + +const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node); + +STACK_OF(POLICYQUALINFO) *X509_policy_node_get0_qualifiers(const + X509_POLICY_NODE + *node); +const X509_POLICY_NODE *X509_policy_node_get0_parent(const X509_POLICY_NODE + *node); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mobile/ios/FxA/FxA/include/openssl/x509v3.h b/mobile/ios/FxA/FxA/include/openssl/x509v3.h new file mode 100644 index 0000000000..1d8ef87c4c --- /dev/null +++ b/mobile/ios/FxA/FxA/include/openssl/x509v3.h @@ -0,0 +1,1006 @@ +/* + * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_X509V3_H +# define HEADER_X509V3_H + +# include +# include +# include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward reference */ +struct v3_ext_method; +struct v3_ext_ctx; + +/* Useful typedefs */ + +typedef void *(*X509V3_EXT_NEW)(void); +typedef void (*X509V3_EXT_FREE) (void *); +typedef void *(*X509V3_EXT_D2I)(void *, const unsigned char **, long); +typedef int (*X509V3_EXT_I2D) (void *, unsigned char **); +typedef STACK_OF(CONF_VALUE) * + (*X509V3_EXT_I2V) (const struct v3_ext_method *method, void *ext, + STACK_OF(CONF_VALUE) *extlist); +typedef void *(*X509V3_EXT_V2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, + STACK_OF(CONF_VALUE) *values); +typedef char *(*X509V3_EXT_I2S)(const struct v3_ext_method *method, + void *ext); +typedef void *(*X509V3_EXT_S2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, const char *str); +typedef int (*X509V3_EXT_I2R) (const struct v3_ext_method *method, void *ext, + BIO *out, int indent); +typedef void *(*X509V3_EXT_R2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, const char *str); + +/* V3 extension structure */ + +struct v3_ext_method { + int ext_nid; + int ext_flags; +/* If this is set the following four fields are ignored */ + ASN1_ITEM_EXP *it; +/* Old style ASN1 calls */ + X509V3_EXT_NEW ext_new; + X509V3_EXT_FREE ext_free; + X509V3_EXT_D2I d2i; + X509V3_EXT_I2D i2d; +/* The following pair is used for string extensions */ + X509V3_EXT_I2S i2s; + X509V3_EXT_S2I s2i; +/* The following pair is used for multi-valued extensions */ + X509V3_EXT_I2V i2v; + X509V3_EXT_V2I v2i; +/* The following are used for raw extensions */ + X509V3_EXT_I2R i2r; + X509V3_EXT_R2I r2i; + void *usr_data; /* Any extension specific data */ +}; + +typedef struct X509V3_CONF_METHOD_st { + char *(*get_string) (void *db, const char *section, const char *value); + STACK_OF(CONF_VALUE) *(*get_section) (void *db, const char *section); + void (*free_string) (void *db, char *string); + void (*free_section) (void *db, STACK_OF(CONF_VALUE) *section); +} X509V3_CONF_METHOD; + +/* Context specific info */ +struct v3_ext_ctx { +# define CTX_TEST 0x1 +# define X509V3_CTX_REPLACE 0x2 + int flags; + X509 *issuer_cert; + X509 *subject_cert; + X509_REQ *subject_req; + X509_CRL *crl; + X509V3_CONF_METHOD *db_meth; + void *db; +/* Maybe more here */ +}; + +typedef struct v3_ext_method X509V3_EXT_METHOD; + +DEFINE_STACK_OF(X509V3_EXT_METHOD) + +/* ext_flags values */ +# define X509V3_EXT_DYNAMIC 0x1 +# define X509V3_EXT_CTX_DEP 0x2 +# define X509V3_EXT_MULTILINE 0x4 + +typedef BIT_STRING_BITNAME ENUMERATED_NAMES; + +typedef struct BASIC_CONSTRAINTS_st { + int ca; + ASN1_INTEGER *pathlen; +} BASIC_CONSTRAINTS; + +typedef struct PKEY_USAGE_PERIOD_st { + ASN1_GENERALIZEDTIME *notBefore; + ASN1_GENERALIZEDTIME *notAfter; +} PKEY_USAGE_PERIOD; + +typedef struct otherName_st { + ASN1_OBJECT *type_id; + ASN1_TYPE *value; +} OTHERNAME; + +typedef struct EDIPartyName_st { + ASN1_STRING *nameAssigner; + ASN1_STRING *partyName; +} EDIPARTYNAME; + +typedef struct GENERAL_NAME_st { +# define GEN_OTHERNAME 0 +# define GEN_EMAIL 1 +# define GEN_DNS 2 +# define GEN_X400 3 +# define GEN_DIRNAME 4 +# define GEN_EDIPARTY 5 +# define GEN_URI 6 +# define GEN_IPADD 7 +# define GEN_RID 8 + int type; + union { + char *ptr; + OTHERNAME *otherName; /* otherName */ + ASN1_IA5STRING *rfc822Name; + ASN1_IA5STRING *dNSName; + ASN1_TYPE *x400Address; + X509_NAME *directoryName; + EDIPARTYNAME *ediPartyName; + ASN1_IA5STRING *uniformResourceIdentifier; + ASN1_OCTET_STRING *iPAddress; + ASN1_OBJECT *registeredID; + /* Old names */ + ASN1_OCTET_STRING *ip; /* iPAddress */ + X509_NAME *dirn; /* dirn */ + ASN1_IA5STRING *ia5; /* rfc822Name, dNSName, + * uniformResourceIdentifier */ + ASN1_OBJECT *rid; /* registeredID */ + ASN1_TYPE *other; /* x400Address */ + } d; +} GENERAL_NAME; + +typedef struct ACCESS_DESCRIPTION_st { + ASN1_OBJECT *method; + GENERAL_NAME *location; +} ACCESS_DESCRIPTION; + +typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; + +typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE; + +typedef STACK_OF(ASN1_INTEGER) TLS_FEATURE; + +DEFINE_STACK_OF(GENERAL_NAME) +typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES; +DEFINE_STACK_OF(GENERAL_NAMES) + +DEFINE_STACK_OF(ACCESS_DESCRIPTION) + +typedef struct DIST_POINT_NAME_st { + int type; + union { + GENERAL_NAMES *fullname; + STACK_OF(X509_NAME_ENTRY) *relativename; + } name; +/* If relativename then this contains the full distribution point name */ + X509_NAME *dpname; +} DIST_POINT_NAME; +/* All existing reasons */ +# define CRLDP_ALL_REASONS 0x807f + +# define CRL_REASON_NONE -1 +# define CRL_REASON_UNSPECIFIED 0 +# define CRL_REASON_KEY_COMPROMISE 1 +# define CRL_REASON_CA_COMPROMISE 2 +# define CRL_REASON_AFFILIATION_CHANGED 3 +# define CRL_REASON_SUPERSEDED 4 +# define CRL_REASON_CESSATION_OF_OPERATION 5 +# define CRL_REASON_CERTIFICATE_HOLD 6 +# define CRL_REASON_REMOVE_FROM_CRL 8 +# define CRL_REASON_PRIVILEGE_WITHDRAWN 9 +# define CRL_REASON_AA_COMPROMISE 10 + +struct DIST_POINT_st { + DIST_POINT_NAME *distpoint; + ASN1_BIT_STRING *reasons; + GENERAL_NAMES *CRLissuer; + int dp_reasons; +}; + +typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS; + +DEFINE_STACK_OF(DIST_POINT) + +struct AUTHORITY_KEYID_st { + ASN1_OCTET_STRING *keyid; + GENERAL_NAMES *issuer; + ASN1_INTEGER *serial; +}; + +/* Strong extranet structures */ + +typedef struct SXNET_ID_st { + ASN1_INTEGER *zone; + ASN1_OCTET_STRING *user; +} SXNETID; + +DEFINE_STACK_OF(SXNETID) + +typedef struct SXNET_st { + ASN1_INTEGER *version; + STACK_OF(SXNETID) *ids; +} SXNET; + +typedef struct NOTICEREF_st { + ASN1_STRING *organization; + STACK_OF(ASN1_INTEGER) *noticenos; +} NOTICEREF; + +typedef struct USERNOTICE_st { + NOTICEREF *noticeref; + ASN1_STRING *exptext; +} USERNOTICE; + +typedef struct POLICYQUALINFO_st { + ASN1_OBJECT *pqualid; + union { + ASN1_IA5STRING *cpsuri; + USERNOTICE *usernotice; + ASN1_TYPE *other; + } d; +} POLICYQUALINFO; + +DEFINE_STACK_OF(POLICYQUALINFO) + +typedef struct POLICYINFO_st { + ASN1_OBJECT *policyid; + STACK_OF(POLICYQUALINFO) *qualifiers; +} POLICYINFO; + +typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES; + +DEFINE_STACK_OF(POLICYINFO) + +typedef struct POLICY_MAPPING_st { + ASN1_OBJECT *issuerDomainPolicy; + ASN1_OBJECT *subjectDomainPolicy; +} POLICY_MAPPING; + +DEFINE_STACK_OF(POLICY_MAPPING) + +typedef STACK_OF(POLICY_MAPPING) POLICY_MAPPINGS; + +typedef struct GENERAL_SUBTREE_st { + GENERAL_NAME *base; + ASN1_INTEGER *minimum; + ASN1_INTEGER *maximum; +} GENERAL_SUBTREE; + +DEFINE_STACK_OF(GENERAL_SUBTREE) + +struct NAME_CONSTRAINTS_st { + STACK_OF(GENERAL_SUBTREE) *permittedSubtrees; + STACK_OF(GENERAL_SUBTREE) *excludedSubtrees; +}; + +typedef struct POLICY_CONSTRAINTS_st { + ASN1_INTEGER *requireExplicitPolicy; + ASN1_INTEGER *inhibitPolicyMapping; +} POLICY_CONSTRAINTS; + +/* Proxy certificate structures, see RFC 3820 */ +typedef struct PROXY_POLICY_st { + ASN1_OBJECT *policyLanguage; + ASN1_OCTET_STRING *policy; +} PROXY_POLICY; + +typedef struct PROXY_CERT_INFO_EXTENSION_st { + ASN1_INTEGER *pcPathLengthConstraint; + PROXY_POLICY *proxyPolicy; +} PROXY_CERT_INFO_EXTENSION; + +DECLARE_ASN1_FUNCTIONS(PROXY_POLICY) +DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) + +struct ISSUING_DIST_POINT_st { + DIST_POINT_NAME *distpoint; + int onlyuser; + int onlyCA; + ASN1_BIT_STRING *onlysomereasons; + int indirectCRL; + int onlyattr; +}; + +/* Values in idp_flags field */ +/* IDP present */ +# define IDP_PRESENT 0x1 +/* IDP values inconsistent */ +# define IDP_INVALID 0x2 +/* onlyuser true */ +# define IDP_ONLYUSER 0x4 +/* onlyCA true */ +# define IDP_ONLYCA 0x8 +/* onlyattr true */ +# define IDP_ONLYATTR 0x10 +/* indirectCRL true */ +# define IDP_INDIRECT 0x20 +/* onlysomereasons present */ +# define IDP_REASONS 0x40 + +# define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \ +",name:", val->name, ",value:", val->value); + +# define X509V3_set_ctx_test(ctx) \ + X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST) +# define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL; + +# define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \ + 0,0,0,0, \ + 0,0, \ + (X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \ + (X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \ + NULL, NULL, \ + table} + +# define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \ + 0,0,0,0, \ + (X509V3_EXT_I2S)i2s_ASN1_IA5STRING, \ + (X509V3_EXT_S2I)s2i_ASN1_IA5STRING, \ + 0,0,0,0, \ + NULL} + +# define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +/* X509_PURPOSE stuff */ + +# define EXFLAG_BCONS 0x1 +# define EXFLAG_KUSAGE 0x2 +# define EXFLAG_XKUSAGE 0x4 +# define EXFLAG_NSCERT 0x8 + +# define EXFLAG_CA 0x10 +/* Really self issued not necessarily self signed */ +# define EXFLAG_SI 0x20 +# define EXFLAG_V1 0x40 +# define EXFLAG_INVALID 0x80 +/* EXFLAG_SET is set to indicate that some values have been precomputed */ +# define EXFLAG_SET 0x100 +# define EXFLAG_CRITICAL 0x200 +# define EXFLAG_PROXY 0x400 + +# define EXFLAG_INVALID_POLICY 0x800 +# define EXFLAG_FRESHEST 0x1000 +/* Self signed */ +# define EXFLAG_SS 0x2000 + +# define KU_DIGITAL_SIGNATURE 0x0080 +# define KU_NON_REPUDIATION 0x0040 +# define KU_KEY_ENCIPHERMENT 0x0020 +# define KU_DATA_ENCIPHERMENT 0x0010 +# define KU_KEY_AGREEMENT 0x0008 +# define KU_KEY_CERT_SIGN 0x0004 +# define KU_CRL_SIGN 0x0002 +# define KU_ENCIPHER_ONLY 0x0001 +# define KU_DECIPHER_ONLY 0x8000 + +# define NS_SSL_CLIENT 0x80 +# define NS_SSL_SERVER 0x40 +# define NS_SMIME 0x20 +# define NS_OBJSIGN 0x10 +# define NS_SSL_CA 0x04 +# define NS_SMIME_CA 0x02 +# define NS_OBJSIGN_CA 0x01 +# define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA) + +# define XKU_SSL_SERVER 0x1 +# define XKU_SSL_CLIENT 0x2 +# define XKU_SMIME 0x4 +# define XKU_CODE_SIGN 0x8 +# define XKU_SGC 0x10 +# define XKU_OCSP_SIGN 0x20 +# define XKU_TIMESTAMP 0x40 +# define XKU_DVCS 0x80 +# define XKU_ANYEKU 0x100 + +# define X509_PURPOSE_DYNAMIC 0x1 +# define X509_PURPOSE_DYNAMIC_NAME 0x2 + +typedef struct x509_purpose_st { + int purpose; + int trust; /* Default trust ID */ + int flags; + int (*check_purpose) (const struct x509_purpose_st *, const X509 *, int); + char *name; + char *sname; + void *usr_data; +} X509_PURPOSE; + +# define X509_PURPOSE_SSL_CLIENT 1 +# define X509_PURPOSE_SSL_SERVER 2 +# define X509_PURPOSE_NS_SSL_SERVER 3 +# define X509_PURPOSE_SMIME_SIGN 4 +# define X509_PURPOSE_SMIME_ENCRYPT 5 +# define X509_PURPOSE_CRL_SIGN 6 +# define X509_PURPOSE_ANY 7 +# define X509_PURPOSE_OCSP_HELPER 8 +# define X509_PURPOSE_TIMESTAMP_SIGN 9 + +# define X509_PURPOSE_MIN 1 +# define X509_PURPOSE_MAX 9 + +/* Flags for X509V3_EXT_print() */ + +# define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) +/* Return error for unknown extensions */ +# define X509V3_EXT_DEFAULT 0 +/* Print error for unknown extensions */ +# define X509V3_EXT_ERROR_UNKNOWN (1L << 16) +/* ASN1 parse unknown extensions */ +# define X509V3_EXT_PARSE_UNKNOWN (2L << 16) +/* BIO_dump unknown extensions */ +# define X509V3_EXT_DUMP_UNKNOWN (3L << 16) + +/* Flags for X509V3_add1_i2d */ + +# define X509V3_ADD_OP_MASK 0xfL +# define X509V3_ADD_DEFAULT 0L +# define X509V3_ADD_APPEND 1L +# define X509V3_ADD_REPLACE 2L +# define X509V3_ADD_REPLACE_EXISTING 3L +# define X509V3_ADD_KEEP_EXISTING 4L +# define X509V3_ADD_DELETE 5L +# define X509V3_ADD_SILENT 0x10 + +DEFINE_STACK_OF(X509_PURPOSE) + +DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) + +DECLARE_ASN1_FUNCTIONS(SXNET) +DECLARE_ASN1_FUNCTIONS(SXNETID) + +int SXNET_add_id_asc(SXNET **psx, const char *zone, const char *user, int userlen); +int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, const char *user, + int userlen); +int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *izone, const char *user, + int userlen); + +ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, const char *zone); +ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone); +ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone); + +DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID) + +DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD) + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAME) +GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a); +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b); + +ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval); +STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + ASN1_BIT_STRING *bits, + STACK_OF(CONF_VALUE) *extlist); +char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5); +ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, const char *str); + +STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, + GENERAL_NAME *gen, + STACK_OF(CONF_VALUE) *ret); +int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen); + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES) + +STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, + GENERAL_NAMES *gen, + STACK_OF(CONF_VALUE) *extlist); +GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); + +DECLARE_ASN1_FUNCTIONS(OTHERNAME) +DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME) +int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b); +void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value); +void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype); +int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, + ASN1_OBJECT *oid, ASN1_TYPE *value); +int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen, + ASN1_OBJECT **poid, ASN1_TYPE **pvalue); + +char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, + const ASN1_OCTET_STRING *ia5); +ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, const char *str); + +DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) +int i2a_ACCESS_DESCRIPTION(BIO *bp, const ACCESS_DESCRIPTION *a); + +DECLARE_ASN1_ALLOC_FUNCTIONS(TLS_FEATURE) + +DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) +DECLARE_ASN1_FUNCTIONS(POLICYINFO) +DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO) +DECLARE_ASN1_FUNCTIONS(USERNOTICE) +DECLARE_ASN1_FUNCTIONS(NOTICEREF) + +DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS) +DECLARE_ASN1_FUNCTIONS(DIST_POINT) +DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME) +DECLARE_ASN1_FUNCTIONS(ISSUING_DIST_POINT) + +int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname); + +int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc); +int NAME_CONSTRAINTS_check_CN(X509 *x, NAME_CONSTRAINTS *nc); + +DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) +DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) + +DECLARE_ASN1_ITEM(POLICY_MAPPING) +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING) +DECLARE_ASN1_ITEM(POLICY_MAPPINGS) + +DECLARE_ASN1_ITEM(GENERAL_SUBTREE) +DECLARE_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) + +DECLARE_ASN1_ITEM(NAME_CONSTRAINTS) +DECLARE_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) + +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS) +DECLARE_ASN1_ITEM(POLICY_CONSTRAINTS) + +GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, int gen_type, + const char *value, int is_nc); + +# ifdef HEADER_CONF_H +GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, CONF_VALUE *cnf); +GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, CONF_VALUE *cnf, + int is_nc); +void X509V3_conf_free(CONF_VALUE *val); + +X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, + const char *value); +X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, const char *name, + const char *value); +int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, const char *section, + STACK_OF(X509_EXTENSION) **sk); +int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section, + X509 *cert); +int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section, + X509_REQ *req); +int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section, + X509_CRL *crl); + +X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, + X509V3_CTX *ctx, int ext_nid, + const char *value); +X509_EXTENSION *X509V3_EXT_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, + const char *name, const char *value); +int X509V3_EXT_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, + const char *section, X509 *cert); +int X509V3_EXT_REQ_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, + const char *section, X509_REQ *req); +int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, + const char *section, X509_CRL *crl); + +int X509V3_add_value_bool_nf(const char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +int X509V3_get_value_bool(const CONF_VALUE *value, int *asn1_bool); +int X509V3_get_value_int(const CONF_VALUE *value, ASN1_INTEGER **aint); +void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf); +void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash); +# endif + +char *X509V3_get_string(X509V3_CTX *ctx, const char *name, const char *section); +STACK_OF(CONF_VALUE) *X509V3_get_section(X509V3_CTX *ctx, const char *section); +void X509V3_string_free(X509V3_CTX *ctx, char *str); +void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section); +void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject, + X509_REQ *req, X509_CRL *crl, int flags); + +int X509V3_add_value(const char *name, const char *value, + STACK_OF(CONF_VALUE) **extlist); +int X509V3_add_value_uchar(const char *name, const unsigned char *value, + STACK_OF(CONF_VALUE) **extlist); +int X509V3_add_value_bool(const char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +int X509V3_add_value_int(const char *name, const ASN1_INTEGER *aint, + STACK_OF(CONF_VALUE) **extlist); +char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, const ASN1_INTEGER *aint); +ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, const char *value); +char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, const ASN1_ENUMERATED *aint); +char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *meth, + const ASN1_ENUMERATED *aint); +int X509V3_EXT_add(X509V3_EXT_METHOD *ext); +int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist); +int X509V3_EXT_add_alias(int nid_to, int nid_from); +void X509V3_EXT_cleanup(void); + +const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext); +const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid); +int X509V3_add_standard_extensions(void); +STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line); +void *X509V3_EXT_d2i(X509_EXTENSION *ext); +void *X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit, + int *idx); + +X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc); +int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, + int crit, unsigned long flags); + +#if OPENSSL_API_COMPAT < 0x10100000L +/* The new declarations are in crypto.h, but the old ones were here. */ +# define hex_to_string OPENSSL_buf2hexstr +# define string_to_hex OPENSSL_hexstr2buf +#endif + +void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, + int ml); +int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, + int indent); +#ifndef OPENSSL_NO_STDIO +int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent); +#endif +int X509V3_extensions_print(BIO *out, const char *title, + const STACK_OF(X509_EXTENSION) *exts, + unsigned long flag, int indent); + +int X509_check_ca(X509 *x); +int X509_check_purpose(X509 *x, int id, int ca); +int X509_supported_extension(X509_EXTENSION *ex); +int X509_PURPOSE_set(int *p, int purpose); +int X509_check_issued(X509 *issuer, X509 *subject); +int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid); +void X509_set_proxy_flag(X509 *x); +void X509_set_proxy_pathlen(X509 *x, long l); +long X509_get_proxy_pathlen(X509 *x); + +uint32_t X509_get_extension_flags(X509 *x); +uint32_t X509_get_key_usage(X509 *x); +uint32_t X509_get_extended_key_usage(X509 *x); +const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x); + +int X509_PURPOSE_get_count(void); +X509_PURPOSE *X509_PURPOSE_get0(int idx); +int X509_PURPOSE_get_by_sname(const char *sname); +int X509_PURPOSE_get_by_id(int id); +int X509_PURPOSE_add(int id, int trust, int flags, + int (*ck) (const X509_PURPOSE *, const X509 *, int), + const char *name, const char *sname, void *arg); +char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp); +char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp); +int X509_PURPOSE_get_trust(const X509_PURPOSE *xp); +void X509_PURPOSE_cleanup(void); +int X509_PURPOSE_get_id(const X509_PURPOSE *); + +STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x); +STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x); +void X509_email_free(STACK_OF(OPENSSL_STRING) *sk); +STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); +/* Flags for X509_check_* functions */ + +/* + * Always check subject name for host match even if subject alt names present + */ +# define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1 +/* Disable wildcard matching for dnsName fields and common name. */ +# define X509_CHECK_FLAG_NO_WILDCARDS 0x2 +/* Wildcards must not match a partial label. */ +# define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0x4 +/* Allow (non-partial) wildcards to match multiple labels. */ +# define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8 +/* Constraint verifier subdomain patterns to match a single labels. */ +# define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10 +/* Never check the subject CN */ +# define X509_CHECK_FLAG_NEVER_CHECK_SUBJECT 0x20 +/* + * Match reference identifiers starting with "." to any sub-domain. + * This is a non-public flag, turned on implicitly when the subject + * reference identity is a DNS name. + */ +# define _X509_CHECK_FLAG_DOT_SUBDOMAINS 0x8000 + +int X509_check_host(X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername); +int X509_check_email(X509 *x, const char *chk, size_t chklen, + unsigned int flags); +int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags); +int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags); + +ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc); +ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc); +int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE) *dn_sk, + unsigned long chtype); + +void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent); +DEFINE_STACK_OF(X509_POLICY_NODE) + +#ifndef OPENSSL_NO_RFC3779 +typedef struct ASRange_st { + ASN1_INTEGER *min, *max; +} ASRange; + +# define ASIdOrRange_id 0 +# define ASIdOrRange_range 1 + +typedef struct ASIdOrRange_st { + int type; + union { + ASN1_INTEGER *id; + ASRange *range; + } u; +} ASIdOrRange; + +typedef STACK_OF(ASIdOrRange) ASIdOrRanges; +DEFINE_STACK_OF(ASIdOrRange) + +# define ASIdentifierChoice_inherit 0 +# define ASIdentifierChoice_asIdsOrRanges 1 + +typedef struct ASIdentifierChoice_st { + int type; + union { + ASN1_NULL *inherit; + ASIdOrRanges *asIdsOrRanges; + } u; +} ASIdentifierChoice; + +typedef struct ASIdentifiers_st { + ASIdentifierChoice *asnum, *rdi; +} ASIdentifiers; + +DECLARE_ASN1_FUNCTIONS(ASRange) +DECLARE_ASN1_FUNCTIONS(ASIdOrRange) +DECLARE_ASN1_FUNCTIONS(ASIdentifierChoice) +DECLARE_ASN1_FUNCTIONS(ASIdentifiers) + +typedef struct IPAddressRange_st { + ASN1_BIT_STRING *min, *max; +} IPAddressRange; + +# define IPAddressOrRange_addressPrefix 0 +# define IPAddressOrRange_addressRange 1 + +typedef struct IPAddressOrRange_st { + int type; + union { + ASN1_BIT_STRING *addressPrefix; + IPAddressRange *addressRange; + } u; +} IPAddressOrRange; + +typedef STACK_OF(IPAddressOrRange) IPAddressOrRanges; +DEFINE_STACK_OF(IPAddressOrRange) + +# define IPAddressChoice_inherit 0 +# define IPAddressChoice_addressesOrRanges 1 + +typedef struct IPAddressChoice_st { + int type; + union { + ASN1_NULL *inherit; + IPAddressOrRanges *addressesOrRanges; + } u; +} IPAddressChoice; + +typedef struct IPAddressFamily_st { + ASN1_OCTET_STRING *addressFamily; + IPAddressChoice *ipAddressChoice; +} IPAddressFamily; + +typedef STACK_OF(IPAddressFamily) IPAddrBlocks; +DEFINE_STACK_OF(IPAddressFamily) + +DECLARE_ASN1_FUNCTIONS(IPAddressRange) +DECLARE_ASN1_FUNCTIONS(IPAddressOrRange) +DECLARE_ASN1_FUNCTIONS(IPAddressChoice) +DECLARE_ASN1_FUNCTIONS(IPAddressFamily) + +/* + * API tag for elements of the ASIdentifer SEQUENCE. + */ +# define V3_ASID_ASNUM 0 +# define V3_ASID_RDI 1 + +/* + * AFI values, assigned by IANA. It'd be nice to make the AFI + * handling code totally generic, but there are too many little things + * that would need to be defined for other address families for it to + * be worth the trouble. + */ +# define IANA_AFI_IPV4 1 +# define IANA_AFI_IPV6 2 + +/* + * Utilities to construct and extract values from RFC3779 extensions, + * since some of the encodings (particularly for IP address prefixes + * and ranges) are a bit tedious to work with directly. + */ +int X509v3_asid_add_inherit(ASIdentifiers *asid, int which); +int X509v3_asid_add_id_or_range(ASIdentifiers *asid, int which, + ASN1_INTEGER *min, ASN1_INTEGER *max); +int X509v3_addr_add_inherit(IPAddrBlocks *addr, + const unsigned afi, const unsigned *safi); +int X509v3_addr_add_prefix(IPAddrBlocks *addr, + const unsigned afi, const unsigned *safi, + unsigned char *a, const int prefixlen); +int X509v3_addr_add_range(IPAddrBlocks *addr, + const unsigned afi, const unsigned *safi, + unsigned char *min, unsigned char *max); +unsigned X509v3_addr_get_afi(const IPAddressFamily *f); +int X509v3_addr_get_range(IPAddressOrRange *aor, const unsigned afi, + unsigned char *min, unsigned char *max, + const int length); + +/* + * Canonical forms. + */ +int X509v3_asid_is_canonical(ASIdentifiers *asid); +int X509v3_addr_is_canonical(IPAddrBlocks *addr); +int X509v3_asid_canonize(ASIdentifiers *asid); +int X509v3_addr_canonize(IPAddrBlocks *addr); + +/* + * Tests for inheritance and containment. + */ +int X509v3_asid_inherits(ASIdentifiers *asid); +int X509v3_addr_inherits(IPAddrBlocks *addr); +int X509v3_asid_subset(ASIdentifiers *a, ASIdentifiers *b); +int X509v3_addr_subset(IPAddrBlocks *a, IPAddrBlocks *b); + +/* + * Check whether RFC 3779 extensions nest properly in chains. + */ +int X509v3_asid_validate_path(X509_STORE_CTX *); +int X509v3_addr_validate_path(X509_STORE_CTX *); +int X509v3_asid_validate_resource_set(STACK_OF(X509) *chain, + ASIdentifiers *ext, + int allow_inheritance); +int X509v3_addr_validate_resource_set(STACK_OF(X509) *chain, + IPAddrBlocks *ext, int allow_inheritance); + +#endif /* OPENSSL_NO_RFC3779 */ + +/* BEGIN ERROR CODES */ +/* + * The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +int ERR_load_X509V3_strings(void); + +/* Error codes for the X509V3 functions. */ + +/* Function codes. */ +# define X509V3_F_A2I_GENERAL_NAME 164 +# define X509V3_F_ADDR_VALIDATE_PATH_INTERNAL 166 +# define X509V3_F_ASIDENTIFIERCHOICE_CANONIZE 161 +# define X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL 162 +# define X509V3_F_COPY_EMAIL 122 +# define X509V3_F_COPY_ISSUER 123 +# define X509V3_F_DO_DIRNAME 144 +# define X509V3_F_DO_EXT_I2D 135 +# define X509V3_F_DO_EXT_NCONF 151 +# define X509V3_F_GNAMES_FROM_SECTNAME 156 +# define X509V3_F_I2S_ASN1_ENUMERATED 121 +# define X509V3_F_I2S_ASN1_IA5STRING 149 +# define X509V3_F_I2S_ASN1_INTEGER 120 +# define X509V3_F_I2V_AUTHORITY_INFO_ACCESS 138 +# define X509V3_F_NOTICE_SECTION 132 +# define X509V3_F_NREF_NOS 133 +# define X509V3_F_POLICY_SECTION 131 +# define X509V3_F_PROCESS_PCI_VALUE 150 +# define X509V3_F_R2I_CERTPOL 130 +# define X509V3_F_R2I_PCI 155 +# define X509V3_F_S2I_ASN1_IA5STRING 100 +# define X509V3_F_S2I_ASN1_INTEGER 108 +# define X509V3_F_S2I_ASN1_OCTET_STRING 112 +# define X509V3_F_S2I_SKEY_ID 115 +# define X509V3_F_SET_DIST_POINT_NAME 158 +# define X509V3_F_SXNET_ADD_ID_ASC 125 +# define X509V3_F_SXNET_ADD_ID_INTEGER 126 +# define X509V3_F_SXNET_ADD_ID_ULONG 127 +# define X509V3_F_SXNET_GET_ID_ASC 128 +# define X509V3_F_SXNET_GET_ID_ULONG 129 +# define X509V3_F_V2I_ASIDENTIFIERS 163 +# define X509V3_F_V2I_ASN1_BIT_STRING 101 +# define X509V3_F_V2I_AUTHORITY_INFO_ACCESS 139 +# define X509V3_F_V2I_AUTHORITY_KEYID 119 +# define X509V3_F_V2I_BASIC_CONSTRAINTS 102 +# define X509V3_F_V2I_CRLD 134 +# define X509V3_F_V2I_EXTENDED_KEY_USAGE 103 +# define X509V3_F_V2I_GENERAL_NAMES 118 +# define X509V3_F_V2I_GENERAL_NAME_EX 117 +# define X509V3_F_V2I_IDP 157 +# define X509V3_F_V2I_IPADDRBLOCKS 159 +# define X509V3_F_V2I_ISSUER_ALT 153 +# define X509V3_F_V2I_NAME_CONSTRAINTS 147 +# define X509V3_F_V2I_POLICY_CONSTRAINTS 146 +# define X509V3_F_V2I_POLICY_MAPPINGS 145 +# define X509V3_F_V2I_SUBJECT_ALT 154 +# define X509V3_F_V2I_TLS_FEATURE 165 +# define X509V3_F_V3_GENERIC_EXTENSION 116 +# define X509V3_F_X509V3_ADD1_I2D 140 +# define X509V3_F_X509V3_ADD_VALUE 105 +# define X509V3_F_X509V3_EXT_ADD 104 +# define X509V3_F_X509V3_EXT_ADD_ALIAS 106 +# define X509V3_F_X509V3_EXT_I2D 136 +# define X509V3_F_X509V3_EXT_NCONF 152 +# define X509V3_F_X509V3_GET_SECTION 142 +# define X509V3_F_X509V3_GET_STRING 143 +# define X509V3_F_X509V3_GET_VALUE_BOOL 110 +# define X509V3_F_X509V3_PARSE_LIST 109 +# define X509V3_F_X509_PURPOSE_ADD 137 +# define X509V3_F_X509_PURPOSE_SET 141 + +/* Reason codes. */ +# define X509V3_R_BAD_IP_ADDRESS 118 +# define X509V3_R_BAD_OBJECT 119 +# define X509V3_R_BN_DEC2BN_ERROR 100 +# define X509V3_R_BN_TO_ASN1_INTEGER_ERROR 101 +# define X509V3_R_DIRNAME_ERROR 149 +# define X509V3_R_DISTPOINT_ALREADY_SET 160 +# define X509V3_R_DUPLICATE_ZONE_ID 133 +# define X509V3_R_ERROR_CONVERTING_ZONE 131 +# define X509V3_R_ERROR_CREATING_EXTENSION 144 +# define X509V3_R_ERROR_IN_EXTENSION 128 +# define X509V3_R_EXPECTED_A_SECTION_NAME 137 +# define X509V3_R_EXTENSION_EXISTS 145 +# define X509V3_R_EXTENSION_NAME_ERROR 115 +# define X509V3_R_EXTENSION_NOT_FOUND 102 +# define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED 103 +# define X509V3_R_EXTENSION_VALUE_ERROR 116 +# define X509V3_R_ILLEGAL_EMPTY_EXTENSION 151 +# define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG 152 +# define X509V3_R_INVALID_ASNUMBER 162 +# define X509V3_R_INVALID_ASRANGE 163 +# define X509V3_R_INVALID_BOOLEAN_STRING 104 +# define X509V3_R_INVALID_EXTENSION_STRING 105 +# define X509V3_R_INVALID_INHERITANCE 165 +# define X509V3_R_INVALID_IPADDRESS 166 +# define X509V3_R_INVALID_MULTIPLE_RDNS 161 +# define X509V3_R_INVALID_NAME 106 +# define X509V3_R_INVALID_NULL_ARGUMENT 107 +# define X509V3_R_INVALID_NULL_NAME 108 +# define X509V3_R_INVALID_NULL_VALUE 109 +# define X509V3_R_INVALID_NUMBER 140 +# define X509V3_R_INVALID_NUMBERS 141 +# define X509V3_R_INVALID_OBJECT_IDENTIFIER 110 +# define X509V3_R_INVALID_OPTION 138 +# define X509V3_R_INVALID_POLICY_IDENTIFIER 134 +# define X509V3_R_INVALID_PROXY_POLICY_SETTING 153 +# define X509V3_R_INVALID_PURPOSE 146 +# define X509V3_R_INVALID_SAFI 164 +# define X509V3_R_INVALID_SECTION 135 +# define X509V3_R_INVALID_SYNTAX 143 +# define X509V3_R_ISSUER_DECODE_ERROR 126 +# define X509V3_R_MISSING_VALUE 124 +# define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS 142 +# define X509V3_R_NO_CONFIG_DATABASE 136 +# define X509V3_R_NO_ISSUER_CERTIFICATE 121 +# define X509V3_R_NO_ISSUER_DETAILS 127 +# define X509V3_R_NO_POLICY_IDENTIFIER 139 +# define X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED 154 +# define X509V3_R_NO_PUBLIC_KEY 114 +# define X509V3_R_NO_SUBJECT_DETAILS 125 +# define X509V3_R_OPERATION_NOT_DEFINED 148 +# define X509V3_R_OTHERNAME_ERROR 147 +# define X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED 155 +# define X509V3_R_POLICY_PATH_LENGTH 156 +# define X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED 157 +# define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 159 +# define X509V3_R_SECTION_NOT_FOUND 150 +# define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 122 +# define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 123 +# define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT 111 +# define X509V3_R_UNKNOWN_EXTENSION 129 +# define X509V3_R_UNKNOWN_EXTENSION_NAME 130 +# define X509V3_R_UNKNOWN_OPTION 120 +# define X509V3_R_UNSUPPORTED_OPTION 117 +# define X509V3_R_UNSUPPORTED_TYPE 167 +# define X509V3_R_USER_TOO_LONG 132 + +# ifdef __cplusplus +} +# endif +#endif diff --git a/mobile/ios/FxA/FxA/lib/libcrypto.a b/mobile/ios/FxA/FxA/lib/libcrypto.a new file mode 100644 index 0000000000..7da435ef1b Binary files /dev/null and b/mobile/ios/FxA/FxA/lib/libcrypto.a differ diff --git a/mobile/ios/FxA/FxA/lib/libssl.a b/mobile/ios/FxA/FxA/lib/libssl.a new file mode 100644 index 0000000000..d537897db4 Binary files /dev/null and b/mobile/ios/FxA/FxA/lib/libssl.a differ diff --git a/mobile/ios/FxA/FxATests/FxATests.m b/mobile/ios/FxA/FxATests/FxATests.m new file mode 100644 index 0000000000..47bccdb461 --- /dev/null +++ b/mobile/ios/FxA/FxATests/FxATests.m @@ -0,0 +1,37 @@ +// +// FxATests.m +// FxATests +// +// Created by Richard Newman on 2014-09-22. +// Copyright (c) 2014 Mozilla. All rights reserved. +// + +#import +#import + +#import + +@interface FxATests : XCTestCase + +@end + +@implementation FxATests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/mobile/ios/FxA/FxATests/Info.plist b/mobile/ios/FxA/FxATests/Info.plist new file mode 100644 index 0000000000..ba72822e87 --- /dev/null +++ b/mobile/ios/FxA/FxATests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/Gemfile b/mobile/ios/Gemfile new file mode 100644 index 0000000000..eab52f7235 --- /dev/null +++ b/mobile/ios/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +gem 'danger', :git => 'git@github.com:danger/danger.git', :branch => 'master' +gem 'danger-swiftlint' \ No newline at end of file diff --git a/mobile/ios/ISSUE_TEMPLATE.md b/mobile/ios/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..1b5c6a1c5c --- /dev/null +++ b/mobile/ios/ISSUE_TEMPLATE.md @@ -0,0 +1,7 @@ +Hey there! Thanks for using Firefox! + +We prefer to have bugs in Bugzilla. That way issues can be tracked and the rest of Mozilla can help us fix and verify issues as well. + +We would love if you have found a bug to report it in Bugzilla. [File a new bug](https://bugzilla.mozilla.org/enter_bug.cgi?bug_file_loc=http%3A%2F%2F&bug_ignored=0&op_sys=iOS%20&product=Firefox%20for%20iOS&rep_platform=All) + +If you are having an issue building or running the project message us on IRC. There are lots of people who are around to help. We are on [#mobile](https://wiki.mozilla.org/IRC) \ No newline at end of file diff --git a/mobile/ios/L10nSnapshotTests-Info.plist b/mobile/ios/L10nSnapshotTests-Info.plist new file mode 100644 index 0000000000..ba72822e87 --- /dev/null +++ b/mobile/ios/L10nSnapshotTests-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/L10nSnapshotTests/Info.plist b/mobile/ios/L10nSnapshotTests/Info.plist new file mode 100644 index 0000000000..9411e4a06e --- /dev/null +++ b/mobile/ios/L10nSnapshotTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/L10nSnapshotTests/L10nBaseSnapshotTests.swift b/mobile/ios/L10nSnapshotTests/L10nBaseSnapshotTests.swift new file mode 100644 index 0000000000..0bf22ce1ef --- /dev/null +++ b/mobile/ios/L10nSnapshotTests/L10nBaseSnapshotTests.swift @@ -0,0 +1,74 @@ +/* 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/. */ + +import XCTest + +class L10nBaseSnapshotTests: XCTestCase { + var skipIntro: Bool { + return true + } + + override func setUp() { + super.setUp() + continueAfterFailure = false + let app = XCUIApplication() + setupSnapshot(app) + app.launchArguments = [LaunchArguments.Test, LaunchArguments.ClearProfile] + if skipIntro { + app.launchArguments.append(LaunchArguments.SkipIntro) + } + app.launch() + } + + func waitforExistence(_ element: XCUIElement) { + let exists = NSPredicate(format: "exists == true") + + expectation(for: exists, evaluatedWith: element, handler: nil) + waitForExpectations(timeout: 20, handler: nil) + } + + func waitforNoExistence(_ element: XCUIElement) { + let exists = NSPredicate(format: "exists != true") + + expectation(for: exists, evaluatedWith: element, handler: nil) + waitForExpectations(timeout: 20, handler: nil) + } + + func loadWebPage(url: String, waitForOtherElementWithAriaLabel ariaLabel: String) { + let app = XCUIApplication() + UIPasteboard.general.string = url + app.textFields["url"].press(forDuration: 2.0) + app.sheets.element(boundBy: 0).buttons.element(boundBy: 0).tap() + sleep(3) // TODO Otherwise we detect the body in the currently loaded document, before the new page has loaded + + let webView = app.webViews.element(boundBy: 0) + let element = webView.otherElements[ariaLabel] + expectation(for: NSPredicate(format: "exists == 1"), evaluatedWith: element, handler: nil) + + waitForExpectations(timeout: 5.0) { (error) -> Void in + if error != nil { + XCTFail("Failed to detect element with ariaLabel=\(ariaLabel) on \(url): \(error)") + } + } + } + + func loadWebPage(url: String, waitForLoadToFinish: Bool = true) { + let LoadingTimeout: TimeInterval = 60 + let exists = NSPredicate(format: "exists = true") + let loaded = NSPredicate(format: "value BEGINSWITH '100'") + + let app = XCUIApplication() + + UIPasteboard.general.string = url + app.textFields["url"].press(forDuration: 2.0) + app.sheets.element(boundBy: 0).buttons.element(boundBy: 0).tap() + + if waitForLoadToFinish { + let progressIndicator = app.progressIndicators.element(boundBy: 0) + expectation(for: exists, evaluatedWith: progressIndicator, handler: nil) + expectation(for: loaded, evaluatedWith: progressIndicator, handler: nil) + waitForExpectations(timeout: LoadingTimeout, handler: nil) + } + } +} diff --git a/mobile/ios/L10nSnapshotTests/L10nIntroSnapshotTests.swift b/mobile/ios/L10nSnapshotTests/L10nIntroSnapshotTests.swift new file mode 100644 index 0000000000..5d1be9a3da --- /dev/null +++ b/mobile/ios/L10nSnapshotTests/L10nIntroSnapshotTests.swift @@ -0,0 +1,28 @@ +/* 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/. */ + +import XCTest + +class L10nIntroSnapshotTests: L10nBaseSnapshotTests { + override var skipIntro: Bool { + return false + } + + func testIntro() { + let app = XCUIApplication() + snapshot("Intro-1") + app.scrollViews["IntroViewController.scrollView"].swipeLeft() + sleep(2) + snapshot("Intro-2") + app.scrollViews["IntroViewController.scrollView"].swipeLeft() + sleep(2) + snapshot("Intro-3") + app.scrollViews["IntroViewController.scrollView"].swipeLeft() + sleep(2) + snapshot("Intro-4") + app.scrollViews["IntroViewController.scrollView"].swipeLeft() + sleep(2) + snapshot("01Intro-5") + } +} diff --git a/mobile/ios/L10nSnapshotTests/L10nPermissionStringsSnapshotTests.swift b/mobile/ios/L10nSnapshotTests/L10nPermissionStringsSnapshotTests.swift new file mode 100644 index 0000000000..d079e637aa --- /dev/null +++ b/mobile/ios/L10nSnapshotTests/L10nPermissionStringsSnapshotTests.swift @@ -0,0 +1,13 @@ +/* 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/. */ + +import XCTest + +class L10nPermissionStringsSnapshotTests: L10nBaseSnapshotTests { + func testNSLocationWhenInUseUsageDescription() { + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/geolocation.html", waitForOtherElementWithAriaLabel: "body") + snapshot("15LocationDialog-01") + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + } +} diff --git a/mobile/ios/L10nSnapshotTests/L10nSnapshotTests.swift b/mobile/ios/L10nSnapshotTests/L10nSnapshotTests.swift new file mode 100644 index 0000000000..471e203d61 --- /dev/null +++ b/mobile/ios/L10nSnapshotTests/L10nSnapshotTests.swift @@ -0,0 +1,268 @@ +/* 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/. */ + +import XCTest + +class L10nSnapshotTests: L10nBaseSnapshotTests { + func test02DefaultTopSites() { + snapshot("02DefaultTopSites-01") + } + + func test03MenuOnTopSites() { + let app = XCUIApplication() + app.buttons["TabToolbar.menuButton"].tap() + snapshot("03MenuOnTopSites-01") + app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.25)).tap() + + loadWebPage(url: "about:blank", waitForLoadToFinish: false) + sleep(2) + app.buttons["TabToolbar.menuButton"].tap() + snapshot("10MenuOnWebPage-01") + app.otherElements["MenuViewController.menuView"].swipeLeft() + snapshot("10MenuOnWebPage-02") + app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.25)).tap() + + app.buttons["URLBarView.tabsButton"].tap() + app.buttons["TabTrayController.menuButton"].tap() + snapshot("10MenuOnTabsTray-02") + } + + func test04Foo() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabToolbar.menuButton"].tap() + snapshot("10MenuOnWebPage-01") + app.otherElements["MenuViewController.menuView"].swipeLeft() + snapshot("10MenuOnWebPage-02") + } + + func test04Settings() { + let app = XCUIApplication() + app.buttons["TabToolbar.menuButton"].tap() + app.otherElements["MenuViewController.menuView"].swipeLeft() + app.cells["SettingsMenuItem"].tap() + snapshot("04SettingsTopLevel") + + // TODO Scroll through the settings and make a screenshot of every page + + // Screenshot all the settings that have a separate page + for cellName in ["Search", "NewTab", "Homepage", "Logins"] { + app.tables["AppSettingsTableViewController.tableView"].cells[cellName].tap() + snapshot("04Settings-\(cellName)") + app.navigationBars.element(boundBy: 0).buttons.element(boundBy: 0).tap() + } + + // Unclear why this is needed - without it the test framework finds two TouchIDPasscode cells + app.tables["AppSettingsTableViewController.tableView"].swipeUp() + + for cellName in ["TouchIDPasscode", "ClearPrivateData", "TrackingProtection"] { + app.tables["AppSettingsTableViewController.tableView"].cells[cellName].tap() + snapshot("04Settings-\(cellName)") + app.navigationBars.element(boundBy: 0).buttons.element(boundBy: 0).tap() + } + } + + func test05PrivateBrowsingTabsEmptyState() { + let app = XCUIApplication() + app.buttons["URLBarView.tabsButton"].tap() // Open tabs tray + app.buttons["TabTrayController.maskButton"].tap() // Switch to private mode + snapshot("05PrivateBrowsingTabsEmptyState-01") + } + + func test06PanelsEmptyState() { + let app = XCUIApplication() + app.textFields["url"].tap() + app.buttons["HomePanels.Bookmarks"].tap() + snapshot("06PanelsEmptyState-01") + app.buttons["HomePanels.History"].tap() + snapshot("06PanelsEmptyState-02") + app.cells["HistoryPanel.syncedDevicesCell"].tap() + snapshot("06PanelsEmptyState-03") + app.buttons["HomePanels.ReadingList"].tap() + snapshot("06PanelsEmptyState-04") + } + + // From here on it is fine to load pages + + func test07AddSearchProvider() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/addSearchProvider.html", waitForOtherElementWithAriaLabel: "body") + app.webViews.element(boundBy: 0).buttons["focus"].tap() + snapshot("07AddSearchProvider-01", waitForLoadingIndicator: false) + app.buttons["BrowserViewController.customSearchEngineButton"].tap() + snapshot("07AddSearchProvider-02", waitForLoadingIndicator: false) + + let alert = XCUIApplication().alerts.element(boundBy: 0) + expectation(for: NSPredicate(format: "exists == 1"), evaluatedWith: alert, handler: nil) + waitForExpectations(timeout: 3, handler: nil) + alert.buttons.element(boundBy: 0).tap() + } + + func test08URLBar() { + let app = XCUIApplication() + app.textFields["url"].tap() + snapshot("08URLBar-01") + app.textFields["address"].typeText("moz") + snapshot("08URLBar-02") + } + + func test09URLBarContextMenu() { + let app = XCUIApplication() + // Long press with nothing on the clipboard + app.textFields["url"].press(forDuration: 2.0) + snapshot("09LocationBarContextMenu-01") + app.sheets.element(boundBy: 0).buttons.element(boundBy: 0).tap() + sleep(2) + + // Long press with a URL on the clipboard + UIPasteboard.general.string = "https://www.mozilla.com" + app.textFields["url"].press(forDuration: 2.0) + snapshot("09LocationBarContextMenu-02") + app.sheets.element(boundBy: 0).buttons.element(boundBy: 0).tap() + sleep(2) + } + + func test10MenuOnWebPage() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabToolbar.menuButton"].tap() + snapshot("10MenuOnWebPage-01") + app.otherElements["MenuViewController.menuView"].swipeLeft() + snapshot("10MenuOnWebPage-02") + } + + func test11WebViewContextMenu() { + let app = XCUIApplication() + + // Link + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/link.html", waitForOtherElementWithAriaLabel: "body") + app.webViews.element(boundBy: 0).links["link"].press(forDuration: 2.0) + snapshot("11WebViewContextMenu-01") + app.sheets.element(boundBy: 0).buttons.element(boundBy: app.sheets.element(boundBy: 0).buttons.count-1).tap() + + // Image + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/image.html", waitForOtherElementWithAriaLabel: "body") + app.webViews.element(boundBy: 0).images["image"].press(forDuration: 2.0) + snapshot("11WebViewContextMenu-02") + app.sheets.element(boundBy: 0).buttons.element(boundBy: app.sheets.element(boundBy: 0).buttons.count-1).tap() + + // Image inside Link + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/imageWithLink.html", waitForOtherElementWithAriaLabel: "body") + app.webViews.element(boundBy: 0).links["link"].press(forDuration: 2.0) + snapshot("11WebViewContextMenu-03") + app.sheets.element(boundBy: 0).buttons.element(boundBy: app.sheets.element(boundBy: 0).buttons.count-1).tap() + } + + func test12WebViewAuthenticationDialog() { + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/basicauth/index.html", waitForLoadToFinish: false) + let predicate = NSPredicate(format: "exists == 1") + let query = XCUIApplication().alerts.element(boundBy: 0) + expectation(for: predicate, evaluatedWith: query, handler: nil) + self.waitForExpectations(timeout: 3, handler: nil) + snapshot("12WebViewAuthenticationDialog-01", waitForLoadingIndicator: false) + } + + func test13ReloadButtonContextMenu() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabToolbar.stopReloadButton"].press(forDuration: 2.0) + snapshot("13ContextMenuReloadButton-01", waitForLoadingIndicator: false) + app.sheets.element(boundBy: 0).buttons.element(boundBy: 0).tap() + app.buttons["TabToolbar.stopReloadButton"].press(forDuration: 2.0) + snapshot("13ContextMenuReloadButton-02", waitForLoadingIndicator: false) + } + + func test14SetHompage() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabToolbar.menuButton"].tap() + app.cells["SetHomePageMenuItem"].tap() + snapshot("14SetHomepage-01", waitForLoadingIndicator: false) + } + + func test17PasswordSnackbar() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/password.html", waitForOtherElementWithAriaLabel: "body") + app.webViews.element(boundBy: 0).buttons["submit"].tap() + snapshot("17PasswordSnackbar-01") + app.buttons["SaveLoginPrompt.saveLoginButton"].tap() + // The password is pre-filled with a random value so second this this will cause the update prompt + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/password.html", waitForOtherElementWithAriaLabel: "body") + app.webViews.element(boundBy: 0).buttons["submit"].tap() + snapshot("17PasswordSnackbar-02") + } + + func test18TopSitesMenu() { + let app = XCUIApplication() + let topSites = app.cells["TopSitesCell"] + topSites.cells.matching(identifier: "TopSite").element(boundBy: 0).press(forDuration: 2.0) + snapshot("18TopSitesMenu-01") + } + + func test19HistoryTableContextMenu() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabToolbar.menuButton"].tap() + app.toolbars.buttons["HistoryMenuToolbarItem"].tap() + app.tables["History List"].cells.element(boundBy: 2).press(forDuration: 2.0) + snapshot("19HistoryTableContextMenu-01") + } + + func test20BookmarksTableContextMenu() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabToolbar.menuButton"].tap() + app.cells["AddBookmarkMenuItem"].tap() + waitforNoExistence(app.otherElements["MenuViewController.menuView"]) + app.textFields["url"].tap() + app.buttons["HomePanels.Bookmarks"].tap() + app.tables["Bookmarks List"].cells.element(boundBy: 0).press(forDuration: 2.0) + snapshot("20BookmarksTableContextMenu-01") + } + + func test21ReaderModeSettingsMenu() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabLocationView.readerModeButton"].tap() + app.buttons["ReaderModeBarView.settingsButton"].tap() + snapshot("21ReaderModeSettingsMenu-01") + } + + func test22ReadingListTableContextMenu() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabLocationView.readerModeButton"].tap() + app.buttons["ReaderModeBarView.listStatusButton"].tap() + app.textFields["url"].tap() + app.buttons["HomePanels.ReadingList"].tap() + app.tables["ReadingTable"].cells.element(boundBy: 0).press(forDuration: 2.0) + snapshot("22ReadingListTableContextMenu-01") + } + + func test23ReadingListTableRowMenu() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabLocationView.readerModeButton"].tap() + app.buttons["ReaderModeBarView.listStatusButton"].tap() + app.textFields["url"].tap() + app.buttons["HomePanels.ReadingList"].tap() + app.tables["ReadingTable"].cells.element(boundBy: 0).swipeLeft() + snapshot("23ReadingListTableRowMenu-01") + app.tables["ReadingTable"].cells.element(boundBy: 0).buttons.element(boundBy: 1).tap() + app.tables["ReadingTable"].cells.element(boundBy: 0).swipeLeft() + snapshot("23ReadingListTableRowMenu-02") + } + + func test24BookmarksListTableRowMenu() { + let app = XCUIApplication() + loadWebPage(url: "http://wopr.norad.org/~sarentz/fxios/testpages/index.html", waitForOtherElementWithAriaLabel: "body") + app.buttons["TabToolbar.menuButton"].tap() + app.cells["AddBookmarkMenuItem"].tap() + waitforNoExistence(app.otherElements["MenuViewController.menuView"]) + app.textFields["url"].tap() + app.buttons["HomePanels.Bookmarks"].tap() + app.tables["Bookmarks List"].cells.element(boundBy: 0).swipeLeft() + snapshot("24BookmarksListTableRowMenu-01") + } +} diff --git a/mobile/ios/LICENSE b/mobile/ios/LICENSE new file mode 100644 index 0000000000..e87a115e46 --- /dev/null +++ b/mobile/ios/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + 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/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/mobile/ios/Leanplum.json b/mobile/ios/Leanplum.json new file mode 100644 index 0000000000..be89fdf336 --- /dev/null +++ b/mobile/ios/Leanplum.json @@ -0,0 +1,4 @@ +{ + "2.0.1": "https://github.com/Leanplum/Leanplum-iOS-SDK/releases/download/2.0.1/Leanplum.framework.zip", + "2.0.2": "https://github.com/Leanplum/Leanplum-iOS-SDK/releases/download/2.0.2/Leanplum.framework.zip" +} diff --git a/mobile/ios/MMA.md b/mobile/ios/MMA.md new file mode 100644 index 0000000000..3973f2d884 --- /dev/null +++ b/mobile/ios/MMA.md @@ -0,0 +1,223 @@ + MMA (Mobile Marketing Automation) +================================ + +Mozilla wants to engage with users more. MMA is the project for this purpose. When a user performs a certain UI action (or set of UI actions), she will see a prompt and have a chance to interact with it. For example, if a user uses Firefox 10 times a week, but Firefox is not her default browser, we'll prompt the user the next time when she launches our app, and guide her to set us as default browser. + +Starting in Firefox 8.0 on iOS, Mozilla is using a third party framework called "Leanplum" in order to achieve this. Leanplum is a San Francisco company, founded in 2012. We put their SDK in our codebase via Carthage. + +The SDK is documented at https://www.leanplum.com/docs/ios + +There are three major component in Leanplum SDK. +1. Events : Events are fired when users perform certain actions. +2. User Attributes: User Attributes are set on a per-user basis, and inform us about an aspect of the user. +3. Deep Links: Actions that users can perform to interact with the Message. +4. Messages: User Interaction points that we want to engage with users that help them use Firefox better. + +An Event or a series of Events plus some User Attributes may trigger a Message, and when the user acts on the Message, a Deep Link may be processed. + + +Data collection +===================================================== + + +Who will have Leanplum enabled? +====================================================== + +Users who have a device locale listed in the following code snippet will have Leanplum enabled: https://github.com/mozilla-mobile/firefox-ios/blob/master/Client/Application/LeanplumIntegration.swift + + +Where does data sent to the Leanplum backend go? +============================================== + +The Leanplum SDK is hard-coded to send data to the endpoint https://www.leanplum.com. The endpoint is +defined by ``com.leanplum.internal.Constants.API_HOST_NAME`` at +https://searchfox.org/mozilla-central/rev/c49a70b53f67dd5550eec8a08793805f2aca8d42/mobile/android/thirdparty/com/leanplum/internal/Constants.java#32. + +The user is identified by Leanplum using a random UUID generated by Apple when Leanplum is initialized for the first time (see https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor). +This unique identifier is only used by Leanplum and can't be tracked back to any Firefox users. + + +What data is collected and sent to the Leanplum backend? +====================================================== + +The Leanplum SDK collects and sends the following information at various times while the SDK is in use. + +Sent every time when an event is triggered: +~~~~~~~~~~~~~~~ + "action" -> "track" // track: an event is tracked. + "event" -> "Launch" // Used when an event is triggered. e.g. E_Saved_Bookmark. + "info" -> "" // Used when an event is triggered. Basic context associated with the event. + "value" -> 0.0 // Used when an event is triggered. Value of that event. + "messageId" -> 5111602214338560 // Used when an event is triggered. The ID of the message. +~~~~~~~~~~~~~~~ + +Sent when the app starts: +~~~~~~~~~~~~~~~ + "action" -> "start" // start: Leanplum SDK starts. heartbeat + "userAttributes" -> "{ // A set of key-value pairs used to describe the user. + "Focus Installed" -> true // If Focus for iOS is installed. + "Klar Installed" -> true // If Klar for iOS is installed. + "Signed In Sync" -> true // If the user signed into a Firefox Account. + "Mailto Is Default" -> true // If the user has not changed their default mailto handler. + "Telemetry Opt In" -> true // If the user has not disabled Sending Anonymous Product Usage. + }" + "appId" -> "app_6Ao...." // Leanplum App ID. + "clientKey" -> "dev_srwDUNZR...." // Leanplum client access key. + "systemName" -> "iOS" // Fixed String in SDK. + "locale" -> "zh_TW" // System Locale. + "timezone" -> "Asia/Taipei" // System Timezone. + "versionName" -> "55.0a1" // Fennec version. + "systemVersion" -> "10.3.1" // System version. + "deviceModel" -> "iPhone" // System device model. + "timezoneOffsetSeconds" -> "28800" // User timezone offset with PST. + "deviceName" -> "sdaswani-31710" // System device name. + "region" -> "(detect)" // Not used. We strip location so this is will be the default stub value in Leanplum SDK. + "city" -> "(detect)" // Same as above. + "country" -> "(detect)" // Same as above. + "location" -> "(detect)" // Same as above. + "newsfeedMessages" -> " size = 0" // Not used. New Leanplum Inbox message(Leanplum feature) count. + "includeDefaults" -> "false" // Not used. Always false. + ~~~~~~~~~~~~~~~ + +Sent every time a session is renewed or has a state change: +~~~~~~~~~~~~~~~ + "action" -> "heartbeat" // heartbeat: every 15 minutes when app is in the foreground + // pauseSession: when app goes to background + // resumeSession: when app goes to foreground +~~~~~~~~~~~~~~~ + +Sent for every Message: +~~~~~~~~~~~~~~~ + "userId" -> "b13b3c239d01aa7c" // Set by Fennec, we use random uuid so users are anonymous to Leanplum. + "deviceId" -> "b13b3c239d01aa7c" // Same as above. + "sdkVersion" -> "2.2.2-SNAPSHOT" // Leanplum SDK version. + "devMode" -> "true" // If the SDK is in developer mode. For official builds, it's false. + "time" -> "1.497595093902E9" // System time in second. + "token" -> "nksZ5pa0R5iegC7wj...." // Token come from Leanplum backend. +~~~~~~~~~~~~~~~ + +Notes on what data is collected +=============================== +User Identifier +--------------- +Since Device ID is a random UUID, Leanplum can't map the device to any know Client ID in Fennec nor Advertising ID. + +Events +------- +Most of the Leanplum events can be mapped to a single combination of Telemetry event (Event+Method+Extra). +Some events are not collected in Mozilla Telemetry. This will be addressed separately in each campaign review. +There are three elements that are used for each event. They are: event name, value(default: 0.0), and info(default: ""). +Default value for event value is 0.0. Default value for event info is empty string. + +Here is the list of current Events sent, which can be found here in the code base: https://github.com/mozilla-mobile/firefox-ios/blob/master/Client/Application/LeanplumIntegration.swift#L21 + +The first launch after install +~~~~ +{ + "event": "E_First_Run" +} +~~~~ + +The second launch after install +~~~~ +{ + "event": "E_Second_Run" +} +~~~~ + +Whenever the App is launched. +~~~~ +{ + "event": "E_Opened_App" +} +~~~~ + +The user loads a bookmark from home panel. +~~~~ +{ + "event": "E_Opened_Bookmark" +} +~~~~ + +The user opened a new tab. +~~~~ +{ + + "event": "E_Opened_New_Tab" +} +~~~~ + +The user opens a Pocket trending story +~~~~ +{ + + "event": "E_Opened_Pocket_Story" +} +~~~~ + +The user interacts with search url area. +~~~~ +{ + "event": "E_Interact_With_Search_URL_Area" +} +~~~~ + +The user saves a bookmark. +~~~~ +{ + "event": "E_Saved_Bookmark" +} +~~~~ + +The user opened a mailto link from a web page. +~~~~ +{ + "event": "E_Opened_Mailto_Link" +} +~~~~ + +The user cleared their private data. +~~~~ +{ + "event": "E_Cleared_Private_Data" +} +~~~~ + +Download videos or any other media +~~~~ +{ + "event": "E_Download_Media_Saved_Image" +} +~~~~ + +Save password and login from door hanger +~~~~ +{ + "event": "E_Saved_Login_And_Password" +} +~~~~ + +Deep Links +---------- +Deep links are actions that can point Firefox to open certain pages or load features such as `show bookmark list` or +`open Firefox Account Settings`. When users receives a Message, they can click the button(s) on it. These buttons can +trigger the following deep links: +* Link to sync signup/sign in (firefox://deep-link?url=settings/fxa) +* Link to default search engine settings (firefox://deep-link?url=settings/search) +* Link to bookmark list (firefox://deep-link?url=homepanel/bookmarks) +* Link to history list (firefox://deep-link?url=/history) +* Link to general preferences (firefox://deep-link?url=settings) +* Link to the mailto preferences (firefox://deep-link?url=settings/mailto) +* Link to open a new tab (firefox://deep-link?url=settings/newtab) +* Link to open the user's homepage (firefox://deep-link?url=settings/homepage) +* Link to open the settings page so the user can clear their private data (firefox://deep-link?url=settings/clear-private-data) +* Link to open a new private tab (firefox://deep-link?url=homepanel/new-private-tab) + + +Note these deep links can only be processed from within Firefox (i.e., if they are clicked from outside of Firefox, Firefox will open but nothing further will happen). + +Messages +----------- +Messages are in-app prompts to the user from Leanplum. The user interaction of that prompt will be sent to the Leanplum backend (such as "Accept" or "Show") to track overall engagement with the Message. The Message is downloaded from Leanplum when the Leanplum SDK is initialized at App start, assuming the fulfillment criteria for the Message is met. As mentioned before, the fulfillment criteria is a set of required Events and User Attributes. The fulfillment criteria are set in the Leanplum backend. + +The List of current Messages for iOS can be found here: https://wiki.mozilla.org/Leanplum_Contextual_Hints diff --git a/mobile/ios/MarketingUITests/Info.plist b/mobile/ios/MarketingUITests/Info.plist new file mode 100644 index 0000000000..9411e4a06e --- /dev/null +++ b/mobile/ios/MarketingUITests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/MarketingUITests/MarketingUITests.swift b/mobile/ios/MarketingUITests/MarketingUITests.swift new file mode 100644 index 0000000000..3c3dfc208b --- /dev/null +++ b/mobile/ios/MarketingUITests/MarketingUITests.swift @@ -0,0 +1,118 @@ +/* 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/. */ + +import XCTest + +class MarketingSnapshotTests: XCTestCase { + + let LoadingTimeout: NSTimeInterval = 60 + let exists = NSPredicate(format: "exists = true") + let loaded = NSPredicate(format: "value BEGINSWITH '100'") + + var sleep = false + + override func setUp() { + super.setUp() + + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + let app = XCUIApplication() + setupSnapshot(app) + app.launch() + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func loadWebPage(url: String, testForAutocompleteDialog: Bool = false) { + let app = XCUIApplication() + let addressTextField = app.textFields.elementBoundByIndex(0) + addressTextField.tap() + addressTextField.typeText(url) + if testForAutocompleteDialog { + // for var idx:UInt = 0; idx < app.buttons.count; idx++ { + // let button = app.buttons.elementBoundByIndex(idx) + // print("\(button.identifier): \(button.value)") + // } + app.buttons.elementBoundByIndex(8).tap() + } + let progressIndicator = app.progressIndicators.elementBoundByIndex(0) + expectationForPredicate(exists, evaluatedWithObject: progressIndicator, handler: nil) + expectationForPredicate(loaded, evaluatedWithObject: progressIndicator, handler: nil) + app.typeText("\n") + waitForExpectations(timeout: LoadingTimeout, handler: nil) + } + + func testTakeMarketingScreenshots() { + + let app = XCUIApplication() + + // dismiss the intro tour + app.buttons.elementBoundByIndex(1).tap() + snapshot("00TopSites") + + // go to synced tabs home screen + app.buttons.elementBoundByIndex(4).tap() + snapshot("03SyncedTabs") + + // return to top sites + app.buttons.elementBoundByIndex(1).tap() + + // create new tab + app.staticTexts.firstWithName("1").tap() + let addTabButton = app.buttons.elementBoundByIndex(3) + addTabButton.tap() + + // load some web pages in some new tabs + loadWebPage("http://twitter.com", testForAutocompleteDialog: true) + + app.staticTexts.firstWithName("2").tap() + addTabButton.tap() + loadWebPage("https://mozilla.org/firefox/desktop") + + app.staticTexts.firstWithName("3").tap() + addTabButton.tap() + loadWebPage("https://mozilla.org") + app.staticTexts.firstWithName("4").tap() + addTabButton.tap() + + loadWebPage("firefox") + loadWebPage("https://mozilla.org/firefox/new") + app.staticTexts.firstWithName("5").tap() + snapshot("02TabTray") + + // return to first tab + app.collectionViews.firstMatchingType(.Cell).tap() + let addressTextField = app.textFields.elementBoundByIndex(0) + addressTextField.tap() + + // perform a search but don't complete (we're testing autocomplete here) + addressTextField.typeText("firef") + snapshot("01SearchResults") + + // cancel search + app.buttons.elementBoundByIndex(1).tap() + } + +} + +extension XCUIElementQuery { + func firstWithName(name: String) -> XCUIElement { + let values = self.containingPredicate(NSPredicate(format: "label = '\(name)'")) + if values.count > 0 { + return values.elementBoundByIndex(0) + } + + return self.elementBoundByIndex(0) + } + + func firstMatchingType( type: XCUIElementType) -> XCUIElement { + return self.childrenMatchingType(type).elementBoundByIndex(0) + } +} diff --git a/mobile/ios/Mocking.swift b/mobile/ios/Mocking.swift new file mode 100644 index 0000000000..952af39cca --- /dev/null +++ b/mobile/ios/Mocking.swift @@ -0,0 +1,68 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON +@testable import Sync + +class MockBackoffStorage: BackoffStorage { + var serverBackoffUntilLocalTimestamp: Timestamp? + + func clearServerBackoff() { + serverBackoffUntilLocalTimestamp = nil + } + + func isInBackoff(_ now: Timestamp) -> Timestamp? { + return nil + } +} + +class MockSyncCollectionClient: Sync15CollectionClient { + let uploader: BatchUploadFunction + let infoConfig: InfoConfiguration + + init(uploader: @escaping BatchUploadFunction, + infoConfig: InfoConfiguration, + collection: String, + encrypter: RecordEncrypter, + client: Sync15StorageClient = getClient(server: getServer(preStart: { _ in })), + serverURI: URL = URL(string: "http://localhost/collections")!) { + self.uploader = uploader + self.infoConfig = infoConfig + super.init(client: client, serverURI: serverURI, collection: collection, encrypter: encrypter) + } + + override func newBatch(ifUnmodifiedSince: Timestamp? = nil, onCollectionUploaded: @escaping (POSTResult, Timestamp?) -> DeferredTimestamp) -> Sync15BatchClient { + return Sync15BatchClient(config: self.infoConfig, + ifUnmodifiedSince: ifUnmodifiedSince, + serializeRecord: self.serializeRecord, + uploader: self.uploader, + onCollectionUploaded: onCollectionUploaded) + } +} + +// MARK: Various mocks + +// Non-encrypting 'encrypter'. +func getEncrypter() -> RecordEncrypter { + let serializer: (Record) -> JSON? = { $0.payload.json } + let factory: (String) -> CleartextPayloadJSON = { CleartextPayloadJSON($0) } + return RecordEncrypter(serializer: serializer, factory: factory) +} + +func getClient(server: MockSyncServer) -> Sync15StorageClient { + let url = server.baseURL.asURL! + let authorizer: Authorizer = identity + let queue = DispatchQueue.global(qos: DispatchQoS.background.qosClass) + + return Sync15StorageClient(serverURI: url, authorizer: authorizer, workQueue: queue, resultQueue: queue, backoff: MockBackoffStorage()) +} + +func getServer(username: String = "1234567", preStart: (MockSyncServer) -> Void) -> MockSyncServer { + let server = MockSyncServer(username: username) + preStart(server) + server.start() + return server +} diff --git a/mobile/ios/Providers/NSUserDefaultsPrefs.swift b/mobile/ios/Providers/NSUserDefaultsPrefs.swift new file mode 100644 index 0000000000..4cd30690db --- /dev/null +++ b/mobile/ios/Providers/NSUserDefaultsPrefs.swift @@ -0,0 +1,137 @@ +/* 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/. */ + +import Foundation +import Shared + +open class NSUserDefaultsPrefs: Prefs { + + fileprivate let prefixWithDot: String + fileprivate let userDefaults: UserDefaults + + open func getBranchPrefix() -> String { + return self.prefixWithDot + } + + init(prefix: String, userDefaults: UserDefaults) { + self.prefixWithDot = prefix + (prefix.endsWith(".") ? "" : ".") + self.userDefaults = userDefaults + } + + init(prefix: String) { + self.prefixWithDot = prefix + (prefix.endsWith(".") ? "" : ".") + self.userDefaults = UserDefaults(suiteName: AppInfo.sharedContainerIdentifier)! + } + + open func branch(_ branch: String) -> Prefs { + let prefix = self.prefixWithDot + branch + "." + return NSUserDefaultsPrefs(prefix: prefix, userDefaults: self.userDefaults) + } + + // Preferences are qualified by the profile's local name. + // Connecting a profile to a Firefox Account, or changing to another, won't alter this. + fileprivate func qualifyKey(_ key: String) -> String { + return self.prefixWithDot + key + } + + open func setInt(_ value: Int32, forKey defaultName: String) { + // Why aren't you using userDefaults.setInteger? + // Because userDefaults.getInteger returns a non-optional; it's impossible + // to tell whether there's a value set, and you thus can't distinguish + // between "not present" and zero. + // Yeah, NSUserDefaults is meant to be used for storing "defaults", not data. + setObject(NSNumber(value: value), forKey: defaultName) + } + + open func setTimestamp(_ value: Timestamp, forKey defaultName: String) { + setLong(value, forKey: defaultName) + } + + open func setLong(_ value: UInt64, forKey defaultName: String) { + setObject(NSNumber(value: value), forKey: defaultName) + } + + open func setLong(_ value: Int64, forKey defaultName: String) { + setObject(NSNumber(value: value), forKey: defaultName) + } + + open func setString(_ value: String, forKey defaultName: String) { + setObject(value as AnyObject?, forKey: defaultName) + } + + open func setObject(_ value: Any?, forKey defaultName: String) { + userDefaults.set(value, forKey: qualifyKey(defaultName)) + } + + open func stringForKey(_ defaultName: String) -> String? { + // stringForKey converts numbers to strings, which is almost always a bug. + return userDefaults.object(forKey: qualifyKey(defaultName)) as? String + } + + open func setBool(_ value: Bool, forKey defaultName: String) { + setObject(NSNumber(value: value as Bool), forKey: defaultName) + } + + open func boolForKey(_ defaultName: String) -> Bool? { + // boolForKey just returns false if the key doesn't exist. We need to + // distinguish between false and non-existent keys, so use objectForKey + // and cast the result instead. + let number = userDefaults.object(forKey: qualifyKey(defaultName)) as? NSNumber + return number?.boolValue + } + + fileprivate func nsNumberForKey(_ defaultName: String) -> NSNumber? { + return userDefaults.object(forKey: qualifyKey(defaultName)) as? NSNumber + } + + open func unsignedLongForKey(_ defaultName: String) -> UInt64? { + return nsNumberForKey(defaultName)?.uint64Value + } + + open func timestampForKey(_ defaultName: String) -> Timestamp? { + return unsignedLongForKey(defaultName) + } + + open func longForKey(_ defaultName: String) -> Int64? { + return nsNumberForKey(defaultName)?.int64Value + } + + open func objectForKey(_ defaultName: String) -> T? { + return userDefaults.object(forKey: qualifyKey(defaultName)) as? T + } + + open func intForKey(_ defaultName: String) -> Int32? { + return nsNumberForKey(defaultName)?.int32Value + } + + open func stringArrayForKey(_ defaultName: String) -> [String]? { + let objects = userDefaults.stringArray(forKey: qualifyKey(defaultName)) + if let strings = objects { + return strings + } + return nil + } + + open func arrayForKey(_ defaultName: String) -> [Any]? { + return userDefaults.array(forKey: qualifyKey(defaultName)) as [Any]? + } + + open func dictionaryForKey(_ defaultName: String) -> [String: Any]? { + return userDefaults.dictionary(forKey: qualifyKey(defaultName)) as [String: Any]? + } + + open func removeObjectForKey(_ defaultName: String) { + userDefaults.removeObject(forKey: qualifyKey(defaultName)) + } + + open func clearAll() { + // TODO: userDefaults.removePersistentDomainForName() has no effect for app group suites. + // iOS Bug? Iterate and remove each manually for now. + for key in userDefaults.dictionaryRepresentation().keys { + if key.startsWith(prefixWithDot) { + userDefaults.removeObject(forKey: key) + } + } + } +} diff --git a/mobile/ios/Providers/PocketFeed.swift b/mobile/ios/Providers/PocketFeed.swift new file mode 100644 index 0000000000..415ccfa8ff --- /dev/null +++ b/mobile/ios/Providers/PocketFeed.swift @@ -0,0 +1,144 @@ +/* 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/. */ + +import Foundation +import Alamofire +import Shared +import Deferred +import Storage + +private let PocketEnvAPIKey = "PocketEnvironmentAPIKey" +private let PocketGlobalFeed = "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs" +private let MaxCacheAge: Timestamp = OneMinuteInMilliseconds * 60 // 1 hour in milliseconds +private let SupportedLocales = ["en_US", "en_GB", "en_ZA", "de_DE", "de_AT", "de_CH"] + +/*s + The Pocket class is used to fetch stories from the Pocked API. + Right now this only supports the global feed + + For a sample feed item check ClientTests/pocketglobalfeed.json + */ +struct PocketStory { + let url: URL + let title: String + let storyDescription: String + let imageURL: URL + let domain: String + let dedupeURL: URL + + static func parseJSON(list: Array<[String: Any]>) -> [PocketStory] { + return list.flatMap({ (storyDict) -> PocketStory? in + guard let urlS = storyDict["url"] as? String, let domain = storyDict["domain"] as? String, + let dedupe_URL = storyDict["dedupe_url"] as? String, + let imageURLS = storyDict["image_src"] as? String, + let title = storyDict["title"] as? String, + let description = storyDict["excerpt"] as? String else { + return nil + } + guard let url = URL(string: urlS), let imageURL = URL(string: imageURLS), let dedupeURL = URL(string: dedupe_URL) else { + return nil + } + return PocketStory(url: url, title: title, storyDescription: description, imageURL: imageURL, domain: domain, dedupeURL: dedupeURL) + }) + } +} + +private class PocketError: MaybeErrorType { + var description = "Failed to load from API" +} + +class Pocket { + private let pocketGlobalFeed: String + static let MoreStoriesURL = URL(string: "https://getpocket.com/explore/trending?src=ff_ios&cdn=0")! + + // Allow endPoint to be overriden for testing + init(endPoint: String = PocketGlobalFeed) { + self.pocketGlobalFeed = endPoint + } + + lazy fileprivate var alamofire: SessionManager = { + let ua = UserAgent.defaultClientUserAgent + let configuration = URLSessionConfiguration.default + var defaultHeaders = SessionManager.default.session.configuration.httpAdditionalHeaders ?? [:] + defaultHeaders["User-Agent"] = ua + configuration.httpAdditionalHeaders = defaultHeaders + return SessionManager(configuration: configuration) + }() + + private func findCachedResponse(for request: URLRequest) -> [String: Any]? { + let cachedResponse = URLCache.shared.cachedResponse(for: request) + guard let cachedAtTime = cachedResponse?.userInfo?["cache-time"] as? Timestamp, (Date.now() - cachedAtTime) < MaxCacheAge else { + return nil + } + + guard let data = cachedResponse?.data, let json = try? JSONSerialization.jsonObject(with: data, options: []) else { + return nil + } + + return json as? [String: Any] + } + + private func cache(response: HTTPURLResponse?, for request: URLRequest, with data: Data?) { + guard let resp = response, let data = data else { + return + } + let metadata = ["cache-time": Date.now()] + let cachedResp = CachedURLResponse(response: resp, data: data, userInfo: metadata, storagePolicy: .allowed) + URLCache.shared.removeCachedResponse(for: request) + URLCache.shared.storeCachedResponse(cachedResp, for: request) + } + + // Fetch items from the global pocket feed + func globalFeed(items: Int = 2) -> Deferred> { + let deferred = Deferred>() + + guard let request = createGlobalFeedRequest(items: items) else { + deferred.fill([]) + return deferred + } + + if let cachedResponse = findCachedResponse(for: request), let items = cachedResponse["list"] as? Array<[String: Any]> { + deferred.fill(PocketStory.parseJSON(list: items)) + return deferred + } + + alamofire.request(request).validate(contentType: ["application/json"]).responseJSON { response in + guard response.error == nil, let result = response.result.value as? [String: Any] else { + return deferred.fill([]) + } + self.cache(response: response.response, for: request, with: response.data) + guard let items = result["list"] as? Array<[String: Any]> else { + return deferred.fill([]) + } + return deferred.fill(PocketStory.parseJSON(list: items)) + } + + return deferred + } + + // Returns nil if the locale is not supported + static func IslocaleSupported(_ locale: String) -> Bool { + return SupportedLocales.contains(locale) + } + + // Create the URL request to query the Pocket API. The max items that the query can return is 20 + private func createGlobalFeedRequest(items: Int = 2) -> URLRequest? { + guard items > 0 && items <= 20 else { + return nil + } + + let locale = Locale.current.identifier + let pocketLocale = locale.replacingOccurrences(of: "_", with: "-") + var params = [URLQueryItem(name: "count", value: String(items)), URLQueryItem(name: "locale_lang", value: pocketLocale)] + if let consumerKey = Bundle.main.object(forInfoDictionaryKey: PocketEnvAPIKey) as? String { + params.append(URLQueryItem(name: "consumer_key", value: consumerKey)) + } + + guard let feedURL = URL(string: pocketGlobalFeed)?.withQueryParams(params) else { + return nil + } + + return URLRequest(url: feedURL, cachePolicy: URLRequest.CachePolicy.reloadIgnoringCacheData, timeoutInterval: 5) + } +} diff --git a/mobile/ios/Providers/Profile.swift b/mobile/ios/Providers/Profile.swift new file mode 100644 index 0000000000..2151d9a6f6 --- /dev/null +++ b/mobile/ios/Providers/Profile.swift @@ -0,0 +1,1251 @@ +/* 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/. */ + +// IMPORTANT!: Please take into consideration when adding new imports to +// this file that it is utilized by external components besides the core +// application (i.e. App Extensions). Introducing new dependencies here +// may have unintended negative consequences for App Extensions such as +// increased startup times which may lead to termination by the OS. +import Account +import Shared +import Storage +import Sync +import XCGLogger +import SwiftKeychainWrapper +import Deferred + +// Import these dependencies ONLY for the main `Client` application target. +#if MOZ_TARGET_CLIENT + import SwiftyJSON + import SyncTelemetry +#endif + +// Import these dependencies for ALL targets *EXCEPT* `NotificationService`. +#if !MOZ_TARGET_NOTIFICATIONSERVICE + import ReadingList +#endif + +private let log = Logger.syncLogger + +public let NotificationProfileDidStartSyncing = Notification.Name("NotificationProfileDidStartSyncing") +public let NotificationProfileDidFinishSyncing = Notification.Name("NotificationProfileDidFinishSyncing") + +public let ProfileRemoteTabsSyncDelay: TimeInterval = 0.1 + +public protocol SyncManager { + var isSyncing: Bool { get } + var lastSyncFinishTime: Timestamp? { get set } + var syncDisplayState: SyncDisplayState? { get } + + func hasSyncedHistory() -> Deferred> + func hasSyncedLogins() -> Deferred> + + func syncClients() -> SyncResult + func syncClientsThenTabs() -> SyncResult + func syncHistory() -> SyncResult + func syncLogins() -> SyncResult + func mirrorBookmarks() -> SyncResult + @discardableResult func syncEverything(why: SyncReason) -> Success + func syncNamedCollections(why: SyncReason, names: [String]) -> Success + + // The simplest possible approach. + func beginTimedSyncs() + func endTimedSyncs() + func applicationDidEnterBackground() + func applicationDidBecomeActive() + + func onNewProfile() + @discardableResult func onRemovedAccount(_ account: FirefoxAccount?) -> Success + @discardableResult func onAddedAccount() -> Success +} + +typealias SyncFunction = (SyncDelegate, Prefs, Ready, SyncReason) -> SyncResult + +class ProfileFileAccessor: FileAccessor { + convenience init(profile: Profile) { + self.init(localName: profile.localName()) + } + + init(localName: String) { + let profileDirName = "profile.\(localName)" + + // Bug 1147262: First option is for device, second is for simulator. + var rootPath: String + let sharedContainerIdentifier = AppInfo.sharedContainerIdentifier + if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: sharedContainerIdentifier) { + rootPath = url.path + } else { + log.error("Unable to find the shared container. Defaulting profile location to ~/Documents instead.") + rootPath = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0]) + } + + super.init(rootPath: URL(fileURLWithPath: rootPath).appendingPathComponent(profileDirName).path) + } +} + +class CommandStoringSyncDelegate: SyncDelegate { + let profile: Profile + + init(profile: Profile) { + self.profile = profile + } + + public func displaySentTab(for url: URL, title: String, from deviceName: String?) { + let item = ShareItem(url: url.absoluteString, title: title, favicon: nil) + _ = self.profile.queue.addToQueue(item) + } +} + +/** + * This exists because the Sync code is extension-safe, and thus doesn't get + * direct access to UIApplication.sharedApplication, which it would need to + * display a notification. + * This will also likely be the extension point for wipes, resets, and + * getting access to data sources during a sync. + */ + +let TabSendURLKey = "TabSendURL" +let TabSendTitleKey = "TabSendTitle" +let TabSendCategory = "TabSendCategory" + +enum SentTabAction: String { + case view = "TabSendViewAction" + case bookmark = "TabSendBookmarkAction" + case readingList = "TabSendReadingListAction" +} + +/** + * A Profile manages access to the user's data. + */ +protocol Profile: class { + var bookmarks: BookmarksModelFactorySource & KeywordSearchSource & ShareToDestination & SyncableBookmarks & LocalItemSource & MirrorItemSource { get } + // var favicons: Favicons { get } + var prefs: Prefs { get } + var queue: TabQueue { get } + var searchEngines: SearchEngines { get } + var files: FileAccessor { get } + var history: BrowserHistory & SyncableHistory & ResettableSyncStorage { get } + var metadata: Metadata { get } + var recommendations: HistoryRecommendations { get } + var favicons: Favicons { get } + var logins: BrowserLogins & SyncableLogins & ResettableSyncStorage { get } + var certStore: CertStore { get } + var recentlyClosedTabs: ClosedTabsStore { get } + var panelDataObservers: PanelDataObservers { get } + + #if !MOZ_TARGET_NOTIFICATIONSERVICE + var readingList: ReadingListService? { get } + #endif + + var isShutdown: Bool { get } + + func shutdown() + func reopen() + + // I got really weird EXC_BAD_ACCESS errors on a non-null reference when I made this a getter. + // Similar to . + func localName() -> String + + // URLs and account configuration. + var accountConfiguration: FirefoxAccountConfiguration { get } + + // Do we have an account at all? + func hasAccount() -> Bool + + // Do we have an account that (as far as we know) is in a syncable state? + func hasSyncableAccount() -> Bool + + func getAccount() -> FirefoxAccount? + func removeAccount() + func setAccount(_ account: FirefoxAccount) + func flushAccount() + + func getClients() -> Deferred> + func getClientsAndTabs() -> Deferred> + func getCachedClientsAndTabs() -> Deferred> + + @discardableResult func storeTabs(_ tabs: [RemoteTab]) -> Deferred> + + func sendItems(_ items: [ShareItem], toClients clients: [RemoteClient]) -> Deferred> + + var syncManager: SyncManager! { get } + var isChinaEdition: Bool { get } +} + +fileprivate let PrefKeyClientID = "PrefKeyClientID" +extension Profile { + var clientID: String { + let clientID: String + if let id = prefs.stringForKey(PrefKeyClientID) { + clientID = id + } else { + clientID = UUID().uuidString + prefs.setString(clientID, forKey: PrefKeyClientID) + } + return clientID + } +} + +open class BrowserProfile: Profile { + fileprivate let name: String + fileprivate let keychain: KeychainWrapper + var isShutdown = false + + internal let files: FileAccessor + + let db: BrowserDB + let loginsDB: BrowserDB + var syncManager: SyncManager! + + private static var loginsKey: String? { + let key = "sqlcipher.key.logins.db" + let keychain = KeychainWrapper.sharedAppContainerKeychain + keychain.ensureStringItemAccessibility(.afterFirstUnlock, forKey: key) + if keychain.hasValue(forKey: key) { + return keychain.string(forKey: key) + } + + let Length: UInt = 256 + let secret = Bytes.generateRandomBytes(Length).base64EncodedString + keychain.set(secret, forKey: key, withAccessibility: .afterFirstUnlock) + return secret + } + + var syncDelegate: SyncDelegate? + + /** + * N.B., BrowserProfile is used from our extensions, often via a pattern like + * + * BrowserProfile(…).foo.saveSomething(…) + * + * This can break if BrowserProfile's initializer does async work that + * subsequently — and asynchronously — expects the profile to stick around: + * see Bug 1218833. Be sure to only perform synchronous actions here. + * + * A SyncDelegate can be provided in this initializer, or once the profile is initialized. + * However, if we provide it here, it's assumed that we're initializing it from the application, + * and initialize the logins.db. + */ + init(localName: String, syncDelegate: SyncDelegate? = nil, clear: Bool = false) { + log.debug("Initing profile \(localName) on thread \(Thread.current).") + self.name = localName + self.files = ProfileFileAccessor(localName: localName) + self.keychain = KeychainWrapper.sharedAppContainerKeychain + self.syncDelegate = syncDelegate + + if clear { + do { + // Remove the contents of the directory… + try self.files.removeFilesInDirectory() + // …then remove the directory itself. + try self.files.remove("") + } catch { + log.info("Cannot clear profile: \(error)") + } + } + + // If the profile dir doesn't exist yet, this is first run (for this profile). The check is made here + // since the DB handles will create new DBs under the new profile folder. + let isNewProfile = !files.exists("") + + // Set up our database handles. + self.loginsDB = BrowserDB(filename: "logins.db", secretKey: BrowserProfile.loginsKey, schema: LoginsSchema(), files: files) + self.db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + + // This has to happen prior to the databases being opened, because opening them can trigger + // events to which the SyncManager listens. + self.syncManager = BrowserSyncManager(profile: self) + + let notificationCenter = NotificationCenter.default + + notificationCenter.addObserver(self, selector: #selector(onLocationChange(notification:)), name: NotificationOnLocationChange, object: nil) + notificationCenter.addObserver(self, selector: #selector(onPageMetadataFetched(notification:)), name: NotificationOnPageMetadataFetched, object: nil) + + if isNewProfile { + log.info("New profile. Removing old account metadata.") + self.removeAccountMetadata() + self.syncManager.onNewProfile() + self.removeExistingAuthenticationInfo() + prefs.clearAll() + } + + // Always start by needing invalidation. + // This is the same as self.history.setTopSitesNeedsInvalidation, but without the + // side-effect of instantiating SQLiteHistory (and thus BrowserDB) on the main thread. + prefs.setBool(false, forKey: PrefsKeys.KeyTopSitesCacheIsValid) + + if isChinaEdition { + // Set the default homepage. + prefs.setString(PrefsDefaults.ChineseHomePageURL, forKey: PrefsKeys.KeyDefaultHomePageURL) + + if prefs.stringForKey(PrefsKeys.KeyNewTab) == nil { + prefs.setString(PrefsDefaults.ChineseNewTabDefault, forKey: PrefsKeys.KeyNewTab) + } + } else { + // Remove the default homepage. This does not change the user's preference, + // just the behaviour when there is no homepage. + prefs.removeObjectForKey(PrefsKeys.KeyDefaultHomePageURL) + } + } + + func reopen() { + log.debug("Reopening profile.") + isShutdown = false + + db.reopenIfClosed() + loginsDB.reopenIfClosed() + } + + func shutdown() { + log.debug("Shutting down profile.") + isShutdown = true + + db.forceClose() + loginsDB.forceClose() + } + + @objc + func onLocationChange(notification: NSNotification) { + if let v = notification.userInfo!["visitType"] as? Int, + let visitType = VisitType(rawValue: v), + let url = notification.userInfo!["url"] as? URL, !isIgnoredURL(url), + let title = notification.userInfo!["title"] as? NSString { + // Only record local vists if the change notification originated from a non-private tab + if !(notification.userInfo!["isPrivate"] as? Bool ?? false) { + // We don't record a visit if no type was specified -- that means "ignore me". + let site = Site(url: url.absoluteString, title: title as String) + let visit = SiteVisit(site: site, date: Date.nowMicroseconds(), type: visitType) + history.addLocalVisit(visit) + } + + history.setTopSitesNeedsInvalidation() + } else { + log.debug("Ignoring navigation.") + } + } + + @objc + func onPageMetadataFetched(notification: NSNotification) { + let isPrivate = notification.userInfo?["isPrivate"] as? Bool ?? true + guard !isPrivate else { + log.debug("Private mode - Ignoring page metadata.") + return + } + guard let pageURL = notification.userInfo?["tabURL"] as? URL, + let pageMetadata = notification.userInfo?["pageMetadata"] as? PageMetadata else { + log.debug("Metadata notification doesn't contain any metadata!") + return + } + let defaultMetadataTTL: UInt64 = 3 * 24 * 60 * 60 * 1000 // 3 days for the metadata to live + self.metadata.storeMetadata(pageMetadata, forPageURL: pageURL, expireAt: defaultMetadataTTL + Date.now()) + } + + deinit { + log.debug("Deiniting profile \(self.localName).") + self.syncManager.endTimedSyncs() + } + + func localName() -> String { + return name + } + + lazy var queue: TabQueue = { + withExtendedLifetime(self.history) { + return SQLiteQueue(db: self.db) + } + }() + + /** + * Favicons, history, and bookmarks are all stored in one intermeshed + * collection of tables. + * + * Any other class that needs to access any one of these should ensure + * that this is initialized first. + */ + fileprivate lazy var places: BrowserHistory & Favicons & SyncableHistory & ResettableSyncStorage & HistoryRecommendations = { + return SQLiteHistory(db: self.db, prefs: self.prefs) + }() + + var favicons: Favicons { + return self.places + } + + var history: BrowserHistory & SyncableHistory & ResettableSyncStorage { + return self.places + } + + lazy var panelDataObservers: PanelDataObservers = { + return PanelDataObservers(profile: self) + }() + + lazy var metadata: Metadata = { + return SQLiteMetadata(db: self.db) + }() + + var recommendations: HistoryRecommendations { + return self.places + } + + lazy var bookmarks: BookmarksModelFactorySource & KeywordSearchSource & ShareToDestination & SyncableBookmarks & LocalItemSource & MirrorItemSource = { + // Make sure the rest of our tables are initialized before we try to read them! + // This expression is for side-effects only. + withExtendedLifetime(self.places) { + return MergedSQLiteBookmarks(db: self.db) + } + }() + + lazy var mirrorBookmarks: BookmarkBufferStorage & BufferItemSource = { + // Yeah, this is lazy. Sorry. + return self.bookmarks as! MergedSQLiteBookmarks + }() + + lazy var searchEngines: SearchEngines = { + return SearchEngines(prefs: self.prefs, files: self.files) + }() + + func makePrefs() -> Prefs { + return NSUserDefaultsPrefs(prefix: self.localName()) + } + + lazy var prefs: Prefs = { + return self.makePrefs() + }() + + #if !MOZ_TARGET_NOTIFICATIONSERVICE + lazy var readingList: ReadingListService? = { + return ReadingListService(profileStoragePath: self.files.rootPath as String) + }() + #endif + + lazy var remoteClientsAndTabs: RemoteClientsAndTabs & ResettableSyncStorage & AccountRemovalDelegate & RemoteDevices = { + return SQLiteRemoteClientsAndTabs(db: self.db) + }() + + lazy var certStore: CertStore = { + return CertStore() + }() + + lazy var recentlyClosedTabs: ClosedTabsStore = { + return ClosedTabsStore(prefs: self.prefs) + }() + + open func getSyncDelegate() -> SyncDelegate { + return syncDelegate ?? CommandStoringSyncDelegate(profile: self) + } + + public func getClients() -> Deferred> { + return self.syncManager.syncClients() + >>> { self.remoteClientsAndTabs.getClients() } + } + + public func getClientsAndTabs() -> Deferred> { + return self.syncManager.syncClientsThenTabs() + >>> { self.remoteClientsAndTabs.getClientsAndTabs() } + } + + public func getCachedClientsAndTabs() -> Deferred> { + return self.remoteClientsAndTabs.getClientsAndTabs() + } + + func storeTabs(_ tabs: [RemoteTab]) -> Deferred> { + return self.remoteClientsAndTabs.insertOrUpdateTabs(tabs) + } + + public func sendItems(_ items: [ShareItem], toClients clients: [RemoteClient]) -> Deferred> { + let id = DeviceInfo.clientIdentifier(self.prefs) + let commands = items.map { item in + SyncCommand.displayURIFromShareItem(item, asClient: id) + } + + func notifyClients() { + let deviceIDs = clients.flatMap { $0.fxaDeviceId } + guard let account = self.getAccount() else { + return + } + + account.notify(deviceIDs: deviceIDs, collectionsChanged: ["clients"], reason: "sendtab") + } + + return self.remoteClientsAndTabs.insertCommands(commands, forClients: clients) >>> { + let syncStatus = self.syncManager.syncClients() + syncStatus >>> notifyClients + return syncStatus + } + } + + lazy var logins: BrowserLogins & SyncableLogins & ResettableSyncStorage = { + return SQLiteLogins(db: self.loginsDB) + }() + + lazy var isChinaEdition: Bool = { + return Locale.current.identifier == "zh_CN" + }() + + var accountConfiguration: FirefoxAccountConfiguration { + if prefs.boolForKey("useCustomSyncService") ?? false { + return CustomFirefoxAccountConfiguration(prefs: self.prefs) + } + if prefs.boolForKey("useChinaSyncService") ?? isChinaEdition { + return ChinaEditionFirefoxAccountConfiguration() + } + if prefs.boolForKey("useStageSyncService") ?? false { + return StageFirefoxAccountConfiguration() + } + return ProductionFirefoxAccountConfiguration() + } + + fileprivate lazy var account: FirefoxAccount? = { + let key = self.name + ".account" + self.keychain.ensureObjectItemAccessibility(.afterFirstUnlock, forKey: key) + if let dictionary = self.keychain.object(forKey: key) as? [String: AnyObject] { + let account = FirefoxAccount.fromDictionary(dictionary) + + // Check to see if the account configuration set is a custom service + // and update it to use the custom servers. + if let configuration = account?.configuration as? CustomFirefoxAccountConfiguration { + account?.configuration = CustomFirefoxAccountConfiguration(prefs: self.prefs) + } + + return account + } + return nil + }() + + func hasAccount() -> Bool { + return account != nil + } + + func hasSyncableAccount() -> Bool { + return account?.actionNeeded == FxAActionNeeded.none + } + + func getAccount() -> FirefoxAccount? { + return account + } + + func removeAccountMetadata() { + self.prefs.removeObjectForKey(PrefsKeys.KeyLastRemoteTabSyncTime) + self.keychain.removeObject(forKey: self.name + ".account") + } + + func removeExistingAuthenticationInfo() { + self.keychain.setAuthenticationInfo(nil) + } + + func removeAccount() { + let old = self.account + removeAccountMetadata() + self.account = nil + + // Tell any observers that our account has changed. + NotificationCenter.default.post(name: NotificationFirefoxAccountChanged, object: nil) + + // Trigger cleanup. Pass in the account in case we want to try to remove + // client-specific data from the server. + self.syncManager.onRemovedAccount(old) + } + + func setAccount(_ account: FirefoxAccount) { + self.account = account + + flushAccount() + + // tell any observers that our account has changed + DispatchQueue.main.async { + // Many of the observers for this notifications are on the main thread, + // so we should post the notification there, just in case we're not already + // on the main thread. + let userInfo = [NotificationUserInfoKeyHasSyncableAccount: self.hasSyncableAccount()] + NotificationCenter.default.post(name: NotificationFirefoxAccountChanged, object: nil, userInfo: userInfo) + } + + self.syncManager.onAddedAccount() + } + + func flushAccount() { + if let account = account { + self.keychain.set(account.dictionary() as NSCoding, forKey: name + ".account", withAccessibility: .afterFirstUnlock) + } + } + + // Extends NSObject so we can use timers. + public class BrowserSyncManager: NSObject, SyncManager, CollectionChangedNotifier { + // We shouldn't live beyond our containing BrowserProfile, either in the main app or in + // an extension. + // But it's possible that we'll finish a side-effect sync after we've ditched the profile + // as a whole, so we hold on to our Prefs, potentially for a little while longer. This is + // safe as a strong reference, because there's no cycle. + unowned fileprivate let profile: BrowserProfile + fileprivate let prefs: Prefs + + let FifteenMinutes = TimeInterval(60 * 15) + let OneMinute = TimeInterval(60) + + fileprivate var syncTimer: Timer? + + fileprivate var backgrounded: Bool = true + public func applicationDidEnterBackground() { + self.backgrounded = true + self.endTimedSyncs() + } + + public func applicationDidBecomeActive() { + self.backgrounded = false + + guard self.profile.hasSyncableAccount() else { + return + } + + self.beginTimedSyncs() + + // Sync now if it's been more than our threshold. + let now = Date.now() + let then = self.lastSyncFinishTime ?? 0 + guard now >= then else { + log.debug("Time was modified since last sync.") + self.syncEverythingSoon() + return + } + let since = now - then + log.debug("\(since)msec since last sync.") + if since > SyncConstants.SyncOnForegroundMinimumDelayMillis { + self.syncEverythingSoon() + } + } + + /** + * Locking is managed by syncSeveral. Make sure you take and release these + * whenever you do anything Sync-ey. + */ + fileprivate let syncLock = NSRecursiveLock() + + public var isSyncing: Bool { + syncLock.lock() + defer { syncLock.unlock() } + return syncDisplayState != nil && syncDisplayState! == .inProgress + } + + public var syncDisplayState: SyncDisplayState? + + // The dispatch queue for coordinating syncing and resetting the database. + fileprivate let syncQueue = DispatchQueue(label: "com.mozilla.firefox.sync") + + fileprivate typealias EngineResults = [(EngineIdentifier, SyncStatus)] + fileprivate typealias EngineTasks = [(EngineIdentifier, SyncFunction)] + + // Used as a task queue for syncing. + fileprivate var syncReducer: AsyncReducer? + + fileprivate func beginSyncing() { + notifySyncing(notification: NotificationProfileDidStartSyncing) + } + + fileprivate func endSyncing(_ result: SyncOperationResult) { + // loop through statuses and fill sync state + syncLock.lock() + defer { syncLock.unlock() } + log.info("Ending all queued syncs.") + + syncDisplayState = SyncStatusResolver(engineResults: result.engineResults).resolveResults() + + #if MOZ_TARGET_CLIENT + if let account = profile.account, canSendUsageData() { + SyncPing.from(result: result, + account: account, + remoteClientsAndTabs: profile.remoteClientsAndTabs, + prefs: prefs, + why: .schedule) >>== { SyncTelemetry.send(ping: $0, docType: .sync) } + } else { + log.debug("Profile isn't sending usage data. Not sending sync status event.") + } + #endif + + // Dont notify if we are performing a sync in the background. This prevents more db access from happening + if !self.backgrounded { + notifySyncing(notification: NotificationProfileDidFinishSyncing) + } + syncReducer = nil + } + + func canSendUsageData() -> Bool { + return profile.prefs.boolForKey(AppConstants.PrefSendUsageData) ?? true + } + + private func notifySyncing(notification: Notification.Name) { + NotificationCenter.default.post(name: notification, object: syncDisplayState?.asObject()) + } + + init(profile: BrowserProfile) { + self.profile = profile + self.prefs = profile.prefs + + super.init() + + let center = NotificationCenter.default + center.addObserver(self, selector: #selector(onDatabaseWasRecreated(notification:)), name: NotificationDatabaseWasRecreated, object: nil) + center.addObserver(self, selector: #selector(onLoginDidChange(_:)), name: NotificationDataLoginDidChange, object: nil) + center.addObserver(self, selector: #selector(onStartSyncing(_:)), name: NotificationProfileDidStartSyncing, object: nil) + center.addObserver(self, selector: #selector(onFinishSyncing(_:)), name: NotificationProfileDidFinishSyncing, object: nil) + center.addObserver(self, selector: #selector(onBookmarkBufferValidated(notification:)), name: NotificationBookmarkBufferValidated, object: nil) + } + + func onBookmarkBufferValidated(notification: NSNotification) { + #if MOZ_TARGET_CLIENT + // We don't send this ad hoc telemetry on the release channel. + guard AppConstants.BuildChannel != AppBuildChannel.release else { + return + } + + guard profile.prefs.boolForKey(AppConstants.PrefSendUsageData) ?? true else { + log.debug("Profile isn't sending usage data. Not sending bookmark event.") + return + } + + guard let validations = (notification.object as? Box<[String: Bool]>)?.value else { + log.warning("Notification didn't have validations.") + return + } + + let attempt: Int32 = self.prefs.intForKey("bookmarkvalidationattempt") ?? 1 + self.prefs.setInt(attempt + 1, forKey: "bookmarkvalidationattempt") + + // Capture the buffer count ASAP, not in the delayed op, because the merge could wipe it! + let bufferRows = (self.profile.bookmarks as? MergedSQLiteBookmarks)?.synchronousBufferCount() + + self.doInBackgroundAfter(300) { + self.profile.remoteClientsAndTabs.getClientGUIDs() >>== { clients in + // We would love to include the version and OS etc. of each remote client, + // but we don't store that information. For now, just do a count. + let clientCount = clients.count + + let id = DeviceInfo.clientIdentifier(self.prefs) + let ping = makeAdHocBookmarkMergePing(Bundle.main, clientID: id, attempt: attempt, bufferRows: bufferRows, valid: validations, clientCount: clientCount) + let payload = ping.stringValue + + log.debug("Payload is: \(payload)") + guard let body = payload.data(using: String.Encoding.utf8) else { + log.debug("Invalid JSON!") + return + } + + guard let url = URL(string: "https://mozilla-anonymous-sync-metrics.moo.mx/post/bookmarkvalidation") else { + return + } + + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.httpBody = body + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + URLSession.shared.dataTask(with: request) { data, response, error in + let httpResponse = response as? HTTPURLResponse + log.debug("Bookmark validation upload response: \(httpResponse?.statusCode ?? -1).") + } + } + } + #endif + } + + private func handleRecreationOfDatabaseNamed(name: String?) -> Success { + let loginsCollections = ["passwords"] + let browserCollections = ["bookmarks", "history", "tabs"] + + let dbName = name ?? "" + switch dbName { + case "": + return self.locallyResetCollections(loginsCollections + browserCollections) + case "logins.db": + return self.locallyResetCollections(loginsCollections) + case "browser.db": + return self.locallyResetCollections(browserCollections) + default: + log.debug("Unknown database \(dbName).") + return succeed() + } + } + + func doInBackgroundAfter(_ millis: Int64, _ block: @escaping () -> Void) { + let queue = DispatchQueue.global(qos: DispatchQoS.background.qosClass) + //Pretty ambiguous here. I'm thinking .now was DispatchTime.now() and not Date.now() + queue.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(Int(millis)), execute: block) + } + + @objc + func onDatabaseWasRecreated(notification: NSNotification) { + log.debug("Database was recreated.") + let name = notification.object as? String + log.debug("Database was \(name ?? "nil").") + + // We run this in the background after a few hundred milliseconds; + // it doesn't really matter when it runs, so long as it doesn't + // happen in the middle of a sync. + + let resetDatabase = { + return self.handleRecreationOfDatabaseNamed(name: name) >>== { + log.debug("Reset of \(name ?? "nil") done") + } + } + + self.doInBackgroundAfter(300) { + self.syncLock.lock() + defer { self.syncLock.unlock() } + // If we're syncing already, then wait for sync to end, + // then reset the database on the same serial queue. + if let reducer = self.syncReducer, !reducer.isFilled { + reducer.terminal.upon { _ in + self.syncQueue.async(execute: resetDatabase) + } + } else { + // Otherwise, reset the database on the sync queue now + // Sync can't start while this is still going on. + self.syncQueue.async(execute: resetDatabase) + } + } + } + + // Simple in-memory rate limiting. + var lastTriggeredLoginSync: Timestamp = 0 + @objc func onLoginDidChange(_ notification: NSNotification) { + log.debug("Login did change.") + if (Date.now() - lastTriggeredLoginSync) > OneMinuteInMilliseconds { + lastTriggeredLoginSync = Date.now() + + // Give it a few seconds. + // Trigger on the main queue. The bulk of the sync work runs in the background. + let greenLight = self.greenLight() + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(SyncConstants.SyncDelayTriggered)) { + if greenLight() { + self.syncLogins() + } + } + } + } + + public var lastSyncFinishTime: Timestamp? { + get { + return self.prefs.timestampForKey(PrefsKeys.KeyLastSyncFinishTime) + } + + set(value) { + if let value = value { + self.prefs.setTimestamp(value, forKey: PrefsKeys.KeyLastSyncFinishTime) + } else { + self.prefs.removeObjectForKey(PrefsKeys.KeyLastSyncFinishTime) + } + } + } + + @objc func onStartSyncing(_ notification: NSNotification) { + syncLock.lock() + defer { syncLock.unlock() } + syncDisplayState = .inProgress + } + + @objc func onFinishSyncing(_ notification: NSNotification) { + syncLock.lock() + defer { syncLock.unlock() } + if let syncState = syncDisplayState, syncState == .good { + self.lastSyncFinishTime = Date.now() + } + } + + var prefsForSync: Prefs { + return self.prefs.branch("sync") + } + + public func onAddedAccount() -> Success { + // Only sync if we're green lit. This makes sure that we don't sync unverified accounts. + guard self.profile.hasSyncableAccount() else { return succeed() } + + self.beginTimedSyncs() + return self.syncEverything(why: .didLogin) + } + + func locallyResetCollections(_ collections: [String]) -> Success { + return walk(collections, f: self.locallyResetCollection) + } + + func locallyResetCollection(_ collection: String) -> Success { + switch collection { + case "bookmarks": + return BufferingBookmarksSynchronizer.resetSynchronizerWithStorage(self.profile.bookmarks, basePrefs: self.prefsForSync, collection: "bookmarks") + + case "clients": + fallthrough + case "tabs": + // Because clients and tabs share storage, and thus we wipe data for both if we reset either, + // we reset the prefs for both at the same time. + return TabsSynchronizer.resetClientsAndTabsWithStorage(self.profile.remoteClientsAndTabs, basePrefs: self.prefsForSync) + + case "history": + return HistorySynchronizer.resetSynchronizerWithStorage(self.profile.history, basePrefs: self.prefsForSync, collection: "history") + case "passwords": + return LoginsSynchronizer.resetSynchronizerWithStorage(self.profile.logins, basePrefs: self.prefsForSync, collection: "passwords") + + case "forms": + log.debug("Requested reset for forms, but this client doesn't sync them yet.") + return succeed() + case "addons": + log.debug("Requested reset for addons, but this client doesn't sync them.") + return succeed() + case "prefs": + log.debug("Requested reset for prefs, but this client doesn't sync them.") + return succeed() + default: + log.warning("Asked to reset collection \(collection), which we don't know about.") + return succeed() + } + } + + public func onNewProfile() { + SyncStateMachine.clearStateFromPrefs(self.prefsForSync) + } + + public func onRemovedAccount(_ account: FirefoxAccount?) -> Success { + let profile = self.profile + + // Run these in order, because they might write to the same DB! + let remove = [ + profile.history.onRemovedAccount, + profile.remoteClientsAndTabs.onRemovedAccount, + profile.logins.onRemovedAccount, + profile.bookmarks.onRemovedAccount, + ] + + let clearPrefs: () -> Success = { + withExtendedLifetime(self) { + // Clear prefs after we're done clearing everything else -- just in case + // one of them needs the prefs and we race. Clear regardless of success + // or failure. + + // This will remove keys from the Keychain if they exist, as well + // as wiping the Sync prefs. + SyncStateMachine.clearStateFromPrefs(self.prefsForSync) + } + return succeed() + } + + return accumulate(remove) >>> clearPrefs + } + + fileprivate func repeatingTimerAtInterval(_ interval: TimeInterval, selector: Selector) -> Timer { + return Timer.scheduledTimer(timeInterval: interval, target: self, selector: selector, userInfo: nil, repeats: true) + } + + public func beginTimedSyncs() { + if self.syncTimer != nil { + log.debug("Already running sync timer.") + return + } + + let interval = FifteenMinutes + let selector = #selector(BrowserSyncManager.syncOnTimer) + log.debug("Starting sync timer.") + self.syncTimer = repeatingTimerAtInterval(interval, selector: selector) + } + + /** + * The caller is responsible for calling this on the same thread on which it called + * beginTimedSyncs. + */ + public func endTimedSyncs() { + if let t = self.syncTimer { + log.debug("Stopping sync timer.") + self.syncTimer = nil + t.invalidate() + } + } + + fileprivate func syncClientsWithDelegate(_ delegate: SyncDelegate, prefs: Prefs, ready: Ready, why: SyncReason) -> SyncResult { + log.debug("Syncing clients to storage.") + + let clientSynchronizer = ready.synchronizer(ClientsSynchronizer.self, delegate: delegate, prefs: prefs, why: why) + return clientSynchronizer.synchronizeLocalClients(self.profile.remoteClientsAndTabs, withServer: ready.client, info: ready.info, notifier: self) >>== { result in + guard case .completed = result else { + return deferMaybe(result) + } + guard let account = self.profile.account else { + return deferMaybe(result) + } + log.debug("Updating FxA devices list.") + return account.updateFxADevices(remoteDevices: self.profile.remoteClientsAndTabs).bind { _ in + return deferMaybe(result) + } + } + } + + fileprivate func syncTabsWithDelegate(_ delegate: SyncDelegate, prefs: Prefs, ready: Ready, why: SyncReason) -> SyncResult { + let storage = self.profile.remoteClientsAndTabs + let tabSynchronizer = ready.synchronizer(TabsSynchronizer.self, delegate: delegate, prefs: prefs, why: why) + return tabSynchronizer.synchronizeLocalTabs(storage, withServer: ready.client, info: ready.info) + } + + fileprivate func syncHistoryWithDelegate(_ delegate: SyncDelegate, prefs: Prefs, ready: Ready, why: SyncReason) -> SyncResult { + log.debug("Syncing history to storage.") + let historySynchronizer = ready.synchronizer(HistorySynchronizer.self, delegate: delegate, prefs: prefs, why: why) + return historySynchronizer.synchronizeLocalHistory(self.profile.history, withServer: ready.client, info: ready.info, greenLight: self.greenLight()) + } + + fileprivate func syncLoginsWithDelegate(_ delegate: SyncDelegate, prefs: Prefs, ready: Ready, why: SyncReason) -> SyncResult { + log.debug("Syncing logins to storage.") + let loginsSynchronizer = ready.synchronizer(LoginsSynchronizer.self, delegate: delegate, prefs: prefs, why: why) + return loginsSynchronizer.synchronizeLocalLogins(self.profile.logins, withServer: ready.client, info: ready.info) + } + + fileprivate func mirrorBookmarksWithDelegate(_ delegate: SyncDelegate, prefs: Prefs, ready: Ready, why: SyncReason) -> SyncResult { + log.debug("Synchronizing server bookmarks to storage.") + let bookmarksMirrorer = ready.synchronizer(BufferingBookmarksSynchronizer.self, delegate: delegate, prefs: prefs, why: why) + return bookmarksMirrorer.synchronizeBookmarksToStorage(self.profile.bookmarks, usingBuffer: self.profile.mirrorBookmarks, withServer: ready.client, info: ready.info, greenLight: self.greenLight(), remoteClientsAndTabs: self.profile.remoteClientsAndTabs) + } + + func takeActionsOnEngineStateChanges(_ changes: T) -> Deferred> { + var needReset = Set(changes.collectionsThatNeedLocalReset()) + needReset.formUnion(changes.enginesDisabled()) + needReset.formUnion(changes.enginesEnabled()) + if needReset.isEmpty { + log.debug("No collections need reset. Moving on.") + return deferMaybe(changes) + } + + // needReset needs at most one of clients and tabs, because we reset them + // both if either needs reset. This is strictly an optimization to avoid + // doing duplicate work. + if needReset.contains("clients") { + if needReset.remove("tabs") != nil { + log.debug("Already resetting clients (and tabs); not bothering to also reset tabs again.") + } + } + + return walk(Array(needReset), f: self.locallyResetCollection) + >>> effect(changes.clearLocalCommands) + >>> always(changes) + } + + /** + * Runs the single provided synchronization function and returns its status. + */ + fileprivate func sync(_ label: EngineIdentifier, function: @escaping SyncFunction) -> SyncResult { + return syncSeveral(why: .user, synchronizers: [(label, function)]) >>== { statuses in + let status = statuses.find { label == $0.0 }?.1 + return deferMaybe(status ?? .notStarted(.unknown)) + } + } + + /** + * Convenience method for syncSeveral([(EngineIdentifier, SyncFunction)]) + */ + private func syncSeveral(why: SyncReason, synchronizers: (EngineIdentifier, SyncFunction)...) -> Deferred> { + return syncSeveral(why: why, synchronizers: synchronizers) + } + + /** + * Runs each of the provided synchronization functions with the same inputs. + * Returns an array of IDs and SyncStatuses at least length as the input. + * The statuses returned will be a superset of the ones that are requested here. + * While a sync is ongoing, each engine from successive calls to this method will only be called once. + */ + fileprivate func syncSeveral(why: SyncReason, synchronizers: [(EngineIdentifier, SyncFunction)]) -> Deferred> { + syncLock.lock() + defer { syncLock.unlock() } + + guard let account = self.profile.account else { + log.info("No account to sync with.") + let statuses = synchronizers.map { + ($0.0, SyncStatus.notStarted(.noAccount)) + } + return deferMaybe(statuses) + } + + if !isSyncing { + // A sync isn't already going on, so start another one. + let statsSession = SyncOperationStatsSession(why: why, uid: account.uid, deviceID: account.deviceRegistration?.id) + let reducer = AsyncReducer(initialValue: [], queue: syncQueue) { (statuses, synchronizers) in + let done = Set(statuses.map { $0.0 }) + let remaining = synchronizers.filter { !done.contains($0.0) } + if remaining.isEmpty { + log.info("Nothing left to sync") + return deferMaybe(statuses) + } + + return self.syncWith(synchronizers: remaining, account: account, statsSession: statsSession, why: why) >>== { deferMaybe(statuses + $0) } + } + + reducer.terminal.upon { results in + let result = SyncOperationResult( + engineResults: results, + stats: statsSession.hasStarted() ? statsSession.end() : nil + ) + self.endSyncing(result) + } + + // The actual work of synchronizing doesn't start until we append + // the synchronizers to the reducer below. + self.syncReducer = reducer + self.beginSyncing() + } + + do { + return try syncReducer!.append(synchronizers) + } catch let error { + log.error("Synchronizers appended after sync was finished. This is a bug. \(error)") + let statuses = synchronizers.map { + ($0.0, SyncStatus.notStarted(.unknown)) + } + return deferMaybe(statuses) + } + } + + // This SHOULD NOT be called directly: use syncSeveral instead. + fileprivate func syncWith(synchronizers: [(EngineIdentifier, SyncFunction)], + account: FirefoxAccount, + statsSession: SyncOperationStatsSession, why: SyncReason) -> Deferred> { + log.info("Syncing \(synchronizers.map { $0.0 })") + let authState = account.syncAuthState + let delegate = self.profile.getSyncDelegate() + let readyDeferred = SyncStateMachine(prefs: self.prefsForSync).toReady(authState!) + + let function: (SyncDelegate, Prefs, Ready) -> Deferred> = { delegate, syncPrefs, ready in + let thunks = synchronizers.map { (i, f) in + return { () -> Deferred> in + log.debug("Syncing \(i)…") + return f(delegate, syncPrefs, ready, why) >>== { deferMaybe((i, $0)) } + } + } + return accumulate(thunks) + } + + return readyDeferred >>== self.takeActionsOnEngineStateChanges >>== { ready in + statsSession.start() + return function(delegate, self.prefsForSync, ready) + } + } + + @discardableResult public func syncEverything(why: SyncReason) -> Success { + return self.syncSeveral( + why: why, + synchronizers: + ("clients", self.syncClientsWithDelegate), + ("tabs", self.syncTabsWithDelegate), + ("logins", self.syncLoginsWithDelegate), + ("bookmarks", self.mirrorBookmarksWithDelegate), + ("history", self.syncHistoryWithDelegate)) >>> succeed + } + + func syncEverythingSoon() { + self.doInBackgroundAfter(SyncConstants.SyncOnForegroundAfterMillis) { + log.debug("Running delayed startup sync.") + self.syncEverything(why: .startup) + } + } + + /** + * Allows selective sync of different collections, for use by external APIs. + * Some help is given to callers who use different namespaces (specifically: `passwords` is mapped to `logins`) + * and to preserve some ordering rules. + */ + public func syncNamedCollections(why: SyncReason, names: [String]) -> Success { + // Massage the list of names into engine identifiers. + let engineIdentifiers = names.map { name -> [EngineIdentifier] in + switch name { + case "passwords": + return ["logins"] + case "tabs": + return ["clients", "tabs"] + default: + return [name] + } + }.flatMap { $0 } + + // By this time, `engineIdentifiers` may have duplicates in. We won't try and dedupe here + // because `syncSeveral` will do that for us. + + let synchronizers: [(EngineIdentifier, SyncFunction)] = engineIdentifiers.flatMap { + switch $0 { + case "clients": return ("clients", self.syncClientsWithDelegate) + case "tabs": return ("tabs", self.syncTabsWithDelegate) + case "logins": return ("logins", self.syncLoginsWithDelegate) + case "bookmarks": return ("bookmarks", self.mirrorBookmarksWithDelegate) + case "history": return ("history", self.syncHistoryWithDelegate) + default: return nil + } + } + return self.syncSeveral(why: why, synchronizers: synchronizers) >>> succeed + } + + @objc func syncOnTimer() { + self.syncEverything(why: .scheduled) + } + + public func hasSyncedHistory() -> Deferred> { + return self.profile.history.hasSyncedHistory() + } + + public func hasSyncedLogins() -> Deferred> { + return self.profile.logins.hasSyncedLogins() + } + + public func syncClients() -> SyncResult { + // TODO: recognize .NotStarted. + return self.sync("clients", function: syncClientsWithDelegate) + } + + public func syncClientsThenTabs() -> SyncResult { + return self.syncSeveral( + why: .user, + synchronizers: + ("clients", self.syncClientsWithDelegate), + ("tabs", self.syncTabsWithDelegate)) >>== { statuses in + let status = statuses.find { "tabs" == $0.0 } + return deferMaybe(status!.1) + } + } + + @discardableResult public func syncLogins() -> SyncResult { + return self.sync("logins", function: syncLoginsWithDelegate) + } + + public func syncHistory() -> SyncResult { + // TODO: recognize .NotStarted. + return self.sync("history", function: syncHistoryWithDelegate) + } + + public func mirrorBookmarks() -> SyncResult { + return self.sync("bookmarks", function: mirrorBookmarksWithDelegate) + } + + /** + * Return a thunk that continues to return true so long as an ongoing sync + * should continue. + */ + func greenLight() -> () -> Bool { + let start = Date.now() + + // Give it two minutes to run before we stop. + let stopBy = start + (2 * OneMinuteInMilliseconds) + log.debug("Checking green light. Backgrounded: \(self.backgrounded).") + return { + Date.now() < stopBy && + self.profile.hasSyncableAccount() + } + } + + class NoAccountError: MaybeErrorType { + var description = "No account." + } + + public func notify(deviceIDs: [GUID], collectionsChanged collections: [String], reason: String) -> Success { + guard let account = self.profile.account else { + return deferMaybe(NoAccountError()) + } + return account.notify(deviceIDs: deviceIDs, collectionsChanged: collections, reason: reason) + } + + public func notifyAll(collectionsChanged collections: [String], reason: String) -> Success { + guard let account = self.profile.account else { + return deferMaybe(NoAccountError()) + } + return account.notifyAll(collectionsChanged: collections, reason: reason) + } + } +} diff --git a/mobile/ios/Providers/SyncStatusResolver.swift b/mobile/ios/Providers/SyncStatusResolver.swift new file mode 100644 index 0000000000..fa8abff483 --- /dev/null +++ b/mobile/ios/Providers/SyncStatusResolver.swift @@ -0,0 +1,131 @@ +/* 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/. */ + +import Sync +import Shared +import Storage + +public enum SyncDisplayState { + case inProgress + case good + case bad(message: String?) + case warning(message: String) + + func asObject() -> [String: String]? { + switch self { + case .bad(let msg): + guard let message = msg else { + return ["state": "Error"] + } + return ["state": "Error", + "message": message] + case .warning(let message): + return ["state": "Warning", + "message": message] + default: + break + } + return nil + } +} + +public func ==(a: SyncDisplayState, b: SyncDisplayState) -> Bool { + switch (a, b) { + case (.inProgress, .inProgress): + return true + case (.good, .good): + return true + case (.bad(let a), .bad(let b)) where a == b: + return true + case (.warning(let a), .warning(let b)) where a == b: + return true + default: + return false + } +} + +/* + * Translates the fine-grained SyncStatuses of each sync engine into a more coarse-grained + * display-oriented state for displaying warnings/errors to the user. + */ +public struct SyncStatusResolver { + + let engineResults: Maybe + + public func resolveResults() -> SyncDisplayState { + guard let results = engineResults.successValue else { + switch engineResults.failureValue { + case _ as BookmarksMergeError, _ as BufferInvalidError: + return SyncDisplayState.warning(message: String(format: Strings.FirefoxSyncPartialTitle, Strings.localizedStringForSyncComponent("bookmarks") ?? "")) + default: + return SyncDisplayState.bad(message: nil) + } + } + + // Run through the engine results and produce a relevant display status for each one + let displayStates: [SyncDisplayState] = results.map { (engineIdentifier, syncStatus) in + print("Sync status for \(engineIdentifier): \(syncStatus)") + + // Explicitly call out each of the enum cases to let us lean on the compiler when + // we add new error states + switch syncStatus { + case .notStarted(let reason): + switch reason { + case .offline: + return .bad(message: Strings.FirefoxSyncOfflineTitle) + case .noAccount: + return .warning(message: Strings.FirefoxSyncOfflineTitle) + case .backoff(_): + return .good + case .engineRemotelyNotEnabled(_): + return .good + case .engineFormatOutdated(_): + return .good + case .engineFormatTooNew(_): + return .good + case .storageFormatOutdated(_): + return .good + case .storageFormatTooNew(_): + return .good + case .stateMachineNotReady: + return .good + case .redLight: + return .good + case .unknown: + return .good + } + case .completed: + return .good + case .partial: + return .good + } + } + + // TODO: Instead of finding the worst offender in a list of statuses, we should better surface + // what might have happened with a particular engine when syncing. + let aggregate: SyncDisplayState = displayStates.reduce(.good) { carried, displayState in + switch displayState { + + case .bad(_): + return displayState + + case .warning(_): + // If the state we're carrying is worse than the stale one, keep passing + // along the worst one + switch carried { + case .bad(_): + return carried + default: + return displayState + } + default: + // This one is good so just pass on what was being carried + return carried + } + } + + print("Resolved sync display state: \(aggregate)") + return aggregate + } +} diff --git a/mobile/ios/Push/PushClient.swift b/mobile/ios/Push/PushClient.swift new file mode 100644 index 0000000000..1d0b0359f9 --- /dev/null +++ b/mobile/ios/Push/PushClient.swift @@ -0,0 +1,187 @@ +/* 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/. */ + +import Foundation +import Alamofire +import Deferred +import Shared +import SwiftyJSON + +//public struct PushRemoteError { +// static let MissingNecessaryCryptoKeys: Int32 = 101 +// static let InvalidURLEndpoint: Int32 = 102 +// static let ExpiredURLEndpoint: Int32 = 103 +// static let DataPayloadTooLarge: Int32 = 104 +// static let EndpointBecameUnavailable: Int32 = 105 +// static let InvalidSubscription: Int32 = 106 +// static let RouterTypeIsInvalid: Int32 = 108 +// static let InvalidAuthentication: Int32 = 109 +// static let InvalidCryptoKeysSpecified: Int32 = 110 +// static let MissingRequiredHeader: Int32 = 111 +// static let InvalidTTLHeaderValue: Int32 = 112 +// static let UnknownError: Int32 = 999 +//} + +public let PushClientErrorDomain = "org.mozilla.push.error" +private let PushClientUnknownError = NSError(domain: PushClientErrorDomain, code: 999, + userInfo: [NSLocalizedDescriptionKey: "Invalid server response"]) +private let log = Logger.browserLogger + +/// Bug 1364403 – This is to be put into the push registration +private let apsEnvironment: [String: Any] = [ + "mutable-content": 1, + "alert": [ + "title": " ", + "body": " " + ], +] + +public struct PushRemoteError { + let code: Int + let errno: Int + let error: String + let message: String? + + public static func from(json: JSON) -> PushRemoteError? { + guard let code = json["code"].int, + let errno = json["errno"].int, + let error = json["error"].string else { + return nil + } + + let message = json["message"].string + return PushRemoteError(code: code, errno: errno, error: error, message: message) + } +} + +public enum PushClientError: MaybeErrorType { + case Remote(PushRemoteError) + case Local(Error) + + public var description: String { + switch self { + case let .Remote(error): + let errorString = error.error + let messageString = error.message ?? "" + return "" + case let .Local(error): + return "" + } + } +} + +public class PushClient { + let endpointURL: NSURL + let experimentalMode: Bool + + lazy fileprivate var alamofire: SessionManager = { + let ua = UserAgent.fxaUserAgent + let configuration = URLSessionConfiguration.ephemeral + var defaultHeaders = SessionManager.default.session.configuration.httpAdditionalHeaders ?? [:] + defaultHeaders["User-Agent"] = ua + configuration.httpAdditionalHeaders = defaultHeaders + return SessionManager(configuration: configuration) + }() + + public init(endpointURL: NSURL, experimentalMode: Bool = false) { + self.endpointURL = endpointURL + self.experimentalMode = experimentalMode + } +} + +public extension PushClient { + public func register(_ apnsToken: String) -> Deferred> { + // POST /v1/{type}/{app_id}/registration + let registerURL = endpointURL.appendingPathComponent("registration")! + + var mutableURLRequest = URLRequest(url: registerURL) + mutableURLRequest.httpMethod = HTTPMethod.post.rawValue + + mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") + let parameters: [String: Any] + if experimentalMode { + parameters = [ + "token": apnsToken, + "aps": apsEnvironment, + ] + } else { + parameters = ["token": apnsToken] + } + + mutableURLRequest.httpBody = JSON(parameters).stringValue()?.utf8EncodedData + + if experimentalMode { + log.info("curl -X POST \(registerURL.absoluteString) --data '\(JSON(parameters).stringValue()!)'") + } + + return send(request: mutableURLRequest) >>== { json in + guard let response = PushRegistration.from(json: json) else { + return deferMaybe(PushClientError.Local(PushClientUnknownError)) + } + + return deferMaybe(response) + } + } + + public func updateUAID(_ apnsToken: String, withRegistration creds: PushRegistration) -> Deferred> { + // PUT /v1/{type}/{app_id}/registration/{uaid} + let registerURL = endpointURL.appendingPathComponent("registration/\(creds.uaid)")! + var mutableURLRequest = URLRequest(url: registerURL) + + mutableURLRequest.httpMethod = HTTPMethod.put.rawValue + mutableURLRequest.addValue("Bearer \(creds.secret)", forHTTPHeaderField: "Authorization") + + mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") + let parameters = ["token": apnsToken] + mutableURLRequest.httpBody = JSON(parameters).stringValue()?.utf8EncodedData + + return send(request: mutableURLRequest) >>== { json in + return deferMaybe(creds) + } + } + + public func unregister(_ creds: PushRegistration) -> Success { + // DELETE /v1/{type}/{app_id}/registration/{uaid} + let unregisterURL = endpointURL.appendingPathComponent("registration/\(creds.uaid)") + + var mutableURLRequest = URLRequest(url: unregisterURL!) + mutableURLRequest.httpMethod = HTTPMethod.delete.rawValue + mutableURLRequest.addValue("Bearer \(creds.secret)", forHTTPHeaderField: "Authorization") + + return send(request: mutableURLRequest) >>> succeed + } +} + +/// Utilities +extension PushClient { + fileprivate func send(request: URLRequest) -> Deferred> { + log.info("\(request.httpMethod!) \(request.url?.absoluteString ?? "nil")") + let deferred = Deferred>() + alamofire.request(request) + .validate(contentType: ["application/json"]) + .responseJSON { response in + // Don't cancel requests just because our client is deallocated. + withExtendedLifetime(self.alamofire) { + let result = response.result + if let error = result.error { + return deferred.fill(Maybe(failure: PushClientError.Local(error))) + } + + guard let data = response.data else { + return deferred.fill(Maybe(failure: PushClientError.Local(PushClientUnknownError))) + } + + let json = JSON(data: data) + + if let remoteError = PushRemoteError.from(json: json) { + return deferred.fill(Maybe(failure: PushClientError.Remote(remoteError))) + } + + deferred.fill(Maybe(success: json)) + } + } + + return deferred + } +} diff --git a/mobile/ios/Push/PushConfiguration.swift b/mobile/ios/Push/PushConfiguration.swift new file mode 100644 index 0000000000..3ce5cb555b --- /dev/null +++ b/mobile/ios/Push/PushConfiguration.swift @@ -0,0 +1,82 @@ +/* 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/. */ + +import Foundation + +public enum PushConfigurationLabel: String { + case fennec = "Fennec" + case fennecEnterprise = "FennecEnterprise" + case firefoxBeta = "FirefoxBeta" + case firefoxNightlyEnterprise = "FirefoxNightly" + case firefox = "Firefox" + + public func toConfiguration() -> PushConfiguration { + switch self { + case .fennec: return FennecPushConfiguration() + case .fennecEnterprise: return FennecEnterprisePushConfiguration() + case .firefoxBeta: return FirefoxBetaPushConfiguration() + case .firefoxNightlyEnterprise: return FirefoxNightlyEnterprisePushConfiguration() + case .firefox: return FirefoxPushConfiguration() + } + } +} + +public protocol PushConfiguration { + var label: PushConfigurationLabel { get } + + /// The associated autopush server should speak the protocol documented at + /// http://autopush.readthedocs.io/en/latest/http.html#push-service-http-api + /// /v1/{type}/{app_id} + /// type == apns + /// app_id == the “platform” or “channel” of development (e.g. “firefox”, “beta”, “gecko”, etc.) + var endpointURL: NSURL { get } +} + +public struct FennecPushConfiguration: PushConfiguration { + public init() {} + public let label = PushConfigurationLabel.fennec + public let endpointURL = NSURL(string: "https://updates.push.services.mozilla.com/v1/apns/fennec")! +} + +public struct FennecStagingPushConfiguration: PushConfiguration { + public init() {} + public let label = PushConfigurationLabel.fennec + public let endpointURL = NSURL(string: "https://updates-autopush.stage.mozaws.net/v1/apns/fennec")! +} + +public struct FennecEnterprisePushConfiguration: PushConfiguration { + public init() {} + public let label = PushConfigurationLabel.fennecEnterprise + public let endpointURL = NSURL(string: "https://updates.push.services.mozilla.com/v1/apns/fennecenterprise")! +} + +public struct FirefoxBetaPushConfiguration: PushConfiguration { + public init() {} + public let label = PushConfigurationLabel.firefoxBeta + public let endpointURL = NSURL(string: "https://updates.push.services.mozilla.com/v1/apns/firefoxbeta")! +} + +public struct FirefoxBetaStagingPushConfiguration: PushConfiguration { + public init() {} + public let label = PushConfigurationLabel.firefoxBeta + public let endpointURL = NSURL(string: "https://updates-autopush.stage.mozaws.net/v1/apns/firefoxbeta")! +} + +public struct FirefoxNightlyEnterprisePushConfiguration: PushConfiguration { + public init() {} + public let label = PushConfigurationLabel.firefoxNightlyEnterprise + public let endpointURL = NSURL(string: "https://updates.push.services.mozilla.com/v1/apns/firefoxnightlyenterprise")! +} + +public struct FirefoxPushConfiguration: PushConfiguration { + public init() {} + public let label = PushConfigurationLabel.firefox + public let endpointURL = NSURL(string: "https://updates.push.services.mozilla.com/v1/apns/firefox")! +} + +public struct FirefoxStagingPushConfiguration: PushConfiguration { + public init() {} + public let label = PushConfigurationLabel.firefox + public let endpointURL = NSURL(string: "https://updates-autopush.stage.mozaws.net/v1/apns/firefox")! +} diff --git a/mobile/ios/Push/PushCrypto.swift b/mobile/ios/Push/PushCrypto.swift new file mode 100644 index 0000000000..541a770546 --- /dev/null +++ b/mobile/ios/Push/PushCrypto.swift @@ -0,0 +1,335 @@ +/* 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/. */ + +import Foundation +import FxA + +/// Class to wrap ecec which does the encryption, decryption and key generation with OpenSSL. +/// This supports aesgcm and the newer aes128gcm. +/// For each standard of decryption, two methods are supplied: one with Data parameters and return value, +/// and one with a String based one. +class PushCrypto { + // Stateless, we provide a singleton for convenience. + open static var sharedInstance = PushCrypto() +} + +// AES128GCM +extension PushCrypto { + func aes128gcm(payload data: String, decryptWith privateKey: String, authenticateWith authKey: String) throws -> String { + guard let authSecret = authKey.base64urlSafeDecodedData, + let rawRecvPrivKey = privateKey.base64urlSafeDecodedData, + let payload = data.base64urlSafeDecodedData else { + throw PushCryptoError.base64DecodeError + } + + let decrypted = try aes128gcm(payload: payload, + decryptWith: rawRecvPrivKey, + authenticateWith: authSecret) + + guard let plaintext = decrypted.utf8EncodedString else { + throw PushCryptoError.utf8EncodingError + } + + return plaintext + } + + func aes128gcm(payload: Data, decryptWith rawRecvPrivKey: Data, authenticateWith authSecret: Data) throws -> Data { + var plaintextLen = ece_aes128gcm_plaintext_max_length(payload.getBytes(), payload.count) + 1 + var plaintext = [UInt8](repeating: 0, count: plaintextLen) + + let err = ece_webpush_aes128gcm_decrypt( + rawRecvPrivKey.getBytes(), rawRecvPrivKey.count, + authSecret.getBytes(), authSecret.count, + payload.getBytes(), payload.count, + &plaintext, &plaintextLen) + + if err != ECE_OK { + throw PushCryptoError.decryptionError(errCode: err) + } + + return Data(bytes: plaintext, count: plaintextLen) + } + + func aes128gcm(plaintext: String, encryptWith rawRecvPubKey: String, authenticateWith authSecret: String, rs: Int, padLen: Int) throws -> String { + guard let rawRecvPubKey = rawRecvPubKey.base64urlSafeDecodedData, + let authSecret = authSecret.base64urlSafeDecodedData else { + throw PushCryptoError.base64DecodeError + } + + let plaintextData = plaintext.utf8EncodedData + + let payloadData = try aes128gcm(plaintext: plaintextData, + encryptWith: rawRecvPubKey, + authenticateWith: authSecret, + rs: rs, padLen: padLen) + + guard let payload = payloadData.base64urlSafeEncodedString else { + throw PushCryptoError.base64EncodeError + } + + return payload + } + + func aes128gcm(plaintext: Data, encryptWith rawRecvPubKey: Data, authenticateWith authSecret: Data, rs rsInt: Int, padLen: Int) throws -> Data { + let rs = UInt32(rsInt) + + // rs needs to be >= 18. + assert(rsInt >= Int(ECE_AES128GCM_MIN_RS)) + var payloadLen = ece_aes128gcm_payload_max_length(rs, padLen, plaintext.count) + 1 + var payload = [UInt8](repeating: 0, count: payloadLen) + + let err = ece_webpush_aes128gcm_encrypt(rawRecvPubKey.getBytes(), rawRecvPubKey.count, + authSecret.getBytes(), authSecret.count, + rs, padLen, + plaintext.getBytes(), plaintext.count, + &payload, &payloadLen) + if err != ECE_OK { + throw PushCryptoError.encryptionError(errCode: err) + } + + return Data(bytes: payload, count: payloadLen) + } +} + +// AESGCM +extension PushCrypto { + func aesgcm(ciphertext data: String, withHeaders headers: PushCryptoHeaders, decryptWith privateKey: String, authenticateWith authKey: String) throws -> String { + guard let authSecret = authKey.base64urlSafeDecodedData, + let rawRecvPrivKey = privateKey.base64urlSafeDecodedData, + let ciphertext = data.base64urlSafeDecodedData else { + throw PushCryptoError.base64DecodeError + } + + let decrypted = try aesgcm(ciphertext: ciphertext, + withHeaders: headers, + decryptWith: rawRecvPrivKey, + authenticateWith: authSecret) + + guard let plaintext = decrypted.utf8EncodedString else { + throw PushCryptoError.utf8EncodingError + } + + return plaintext + } + + func aesgcm(ciphertext: Data, withHeaders headers: PushCryptoHeaders, decryptWith rawRecvPrivKey: Data, authenticateWith authSecret: Data) throws -> Data { + let saltLength = Int(ECE_SALT_LENGTH) + var salt = [UInt8](repeating: 0, count: saltLength) + + let rawSenderPubKeyLength = Int(ECE_WEBPUSH_PUBLIC_KEY_LENGTH) + var rawSenderPubKey = [UInt8](repeating: 0, count: rawSenderPubKeyLength) + + var rs = UInt32(0) + + let paramsErr = ece_webpush_aesgcm_headers_extract_params( + headers.cryptoKey, headers.encryption, + &salt, saltLength, + &rawSenderPubKey, rawSenderPubKeyLength, + &rs) + if paramsErr != ECE_OK { + throw PushCryptoError.decryptionError(errCode: paramsErr) + } + + var plaintextLen = ece_aesgcm_plaintext_max_length(rs, ciphertext.count) + 1 + var plaintext = [UInt8](repeating: 0, count: plaintextLen) + + let decryptErr = ece_webpush_aesgcm_decrypt( + rawRecvPrivKey.getBytes(), rawRecvPrivKey.count, + authSecret.getBytes(), authSecret.count, + &salt, salt.count, + &rawSenderPubKey, rawSenderPubKey.count, + rs, + ciphertext.getBytes(), ciphertext.count, + &plaintext, &plaintextLen) + + if decryptErr != ECE_OK { + throw PushCryptoError.decryptionError(errCode: decryptErr) + } + + return Data(bytes: plaintext, count: plaintextLen) + } + + func aesgcm(plaintext: String, encryptWith rawRecvPubKey: String, authenticateWith authSecret: String, rs: Int, padLen: Int) throws -> (headers: PushCryptoHeaders, ciphertext: String) { + guard let rawRecvPubKey = rawRecvPubKey.base64urlSafeDecodedData, + let authSecret = authSecret.base64urlSafeDecodedData else { + throw PushCryptoError.base64DecodeError + } + + let plaintextData = plaintext.utf8EncodedData + + let (headers, messageData) = try aesgcm( + plaintext: plaintextData, + encryptWith: rawRecvPubKey, + authenticateWith: authSecret, + rs: rs, padLen: padLen) + + guard let message = messageData.base64urlSafeEncodedString else { + throw PushCryptoError.base64EncodeError + } + + return (headers, message) + } + + func aesgcm(plaintext: Data, encryptWith rawRecvPubKey: Data, authenticateWith authSecret: Data, rs rsInt: Int, padLen: Int) throws -> (headers: PushCryptoHeaders, data: Data) { + let rs = UInt32(rsInt) + + // rs needs to be >= 3. + assert(rsInt >= Int(ECE_AESGCM_MIN_RS)) + var ciphertextLength = ece_aesgcm_ciphertext_max_length(rs, padLen, plaintext.count) + 1 + var ciphertext = [UInt8](repeating: 0, count: ciphertextLength) + + let saltLength = Int(ECE_SALT_LENGTH) + var salt = [UInt8](repeating: 0, count: saltLength) + + let rawSenderPubKeyLength = Int(ECE_WEBPUSH_PUBLIC_KEY_LENGTH) + var rawSenderPubKey = [UInt8](repeating: 0, count: rawSenderPubKeyLength) + + let encryptErr = ece_webpush_aesgcm_encrypt(rawRecvPubKey.getBytes(), rawRecvPubKey.count, + authSecret.getBytes(), authSecret.count, + rs, padLen, + plaintext.getBytes(), plaintext.count, + &salt, saltLength, + &rawSenderPubKey, rawSenderPubKeyLength, + &ciphertext, &ciphertextLength) + if encryptErr != ECE_OK { + throw PushCryptoError.encryptionError(errCode: encryptErr) + } + + var cryptoKeyHeaderLength = 0 + var encryptionHeaderLength = 0 + + let paramsSizeErr = ece_webpush_aesgcm_headers_from_params( + salt, saltLength, + rawSenderPubKey, rawSenderPubKeyLength, + rs, + nil, &cryptoKeyHeaderLength, + nil, &encryptionHeaderLength) + if paramsSizeErr != ECE_OK { + throw PushCryptoError.encryptionError(errCode: paramsSizeErr) + } + + var cryptoKeyHeaderBytes = [CChar](repeating: 0, count: cryptoKeyHeaderLength) + var encryptionHeaderBytes = [CChar](repeating: 0, count: encryptionHeaderLength) + + let paramsErr = ece_webpush_aesgcm_headers_from_params( + salt, saltLength, + rawSenderPubKey, rawSenderPubKeyLength, + rs, + &cryptoKeyHeaderBytes, &cryptoKeyHeaderLength, + &encryptionHeaderBytes, &encryptionHeaderLength) + if paramsErr != ECE_OK { + throw PushCryptoError.encryptionError(errCode: paramsErr) + } + + guard let cryptoKeyHeader = String(data: Data(bytes: cryptoKeyHeaderBytes, count: cryptoKeyHeaderLength), + encoding: .ascii), + let encryptionHeader = String(data: Data(bytes: encryptionHeaderBytes, count: encryptionHeaderLength), + encoding: .ascii) else { + throw PushCryptoError.base64EncodeError + } + + let headers = PushCryptoHeaders(encryption: encryptionHeader, cryptoKey: cryptoKeyHeader) + return (headers, Data(bytes: ciphertext, count: ciphertextLength)) + } +} + +extension PushCrypto { + func generateKeys() throws -> PushKeys { + // The subscription private key. This key should never be sent to the app + // server. It should be persisted with the endpoint and auth secret, and used + // to decrypt all messages sent to the subscription. + let privateKeyLength = Int(ECE_WEBPUSH_PRIVATE_KEY_LENGTH) + var rawRecvPrivKey = [UInt8](repeating: 0, count: privateKeyLength) + + // The subscription public key. This key should be sent to the app server, + // and used to encrypt messages. The Push DOM API exposes the public key via + // `pushSubscription.getKey("p256dh")`. + let publicKeyLength = Int(ECE_WEBPUSH_PUBLIC_KEY_LENGTH) + var rawRecvPubKey = [UInt8](repeating: 0, count: publicKeyLength) + + // The shared auth secret. This secret should be persisted with the + // subscription information, and sent to the app server. The DOM API exposes + // the auth secret via `pushSubscription.getKey("auth")`. + let authSecretLength = Int(ECE_WEBPUSH_AUTH_SECRET_LENGTH) + var authSecret = [UInt8](repeating: 0, count: authSecretLength) + + let err = ece_webpush_generate_keys( + &rawRecvPrivKey, privateKeyLength, + &rawRecvPubKey, publicKeyLength, + &authSecret, authSecretLength) + + if err != ECE_OK { + throw PushCryptoError.keyGenerationError(errCode: err) + } + + guard let privKey = Data(bytes: rawRecvPrivKey, count: privateKeyLength).base64urlSafeEncodedString, + let pubKey = Data(bytes: rawRecvPubKey, count: publicKeyLength).base64urlSafeEncodedString, + let authKey = Data(bytes: authSecret, count: authSecretLength).base64urlSafeEncodedString else { + throw PushCryptoError.base64EncodeError + } + + return PushKeys(p256dhPrivateKey: privKey, p256dhPublicKey: pubKey, auth: authKey) + } +} + +struct PushKeys { + let p256dhPrivateKey: String + let p256dhPublicKey: String + let auth: String +} + +enum PushCryptoError: Error { + case base64DecodeError + case base64EncodeError + case decryptionError(errCode: Int32) + case encryptionError(errCode: Int32) + case keyGenerationError(errCode: Int32) + case utf8EncodingError +} + +struct PushCryptoHeaders { + let encryption: String + let cryptoKey: String +} + +extension String { + /// Returns a base64 url safe decoding of the given string. + /// The string is allowed to be padded + /// What is padding?: http://stackoverflow.com/a/26632221 + var base64urlSafeDecodedData: Data? { + // We call this method twice: once with the last two args as nil, 0 – this gets us the length + // of the decoded string. + let length = ece_base64url_decode(self, self.characters.count, ECE_BASE64URL_REJECT_PADDING, nil, 0) + guard length > 0 else { + return nil + } + + // The second time, we actually decode, and copy it into a made to measure byte array. + var bytes = [UInt8](repeating: 0, count: length) + let checkLength = ece_base64url_decode(self, self.characters.count, ECE_BASE64URL_REJECT_PADDING, &bytes, length) + guard checkLength == length else { + return nil + } + + return Data(bytes: bytes, count: length) + } +} + +extension Data { + /// Returns a base64 url safe encoding of the given data. + var base64urlSafeEncodedString: String? { + let length = ece_base64url_encode(self.getBytes(), self.count, ECE_BASE64URL_OMIT_PADDING, nil, 0) + guard length > 0 else { + return nil + } + + var bytes = [CChar](repeating: 0, count: length) + let checkLength = ece_base64url_encode(self.getBytes(), self.count, ECE_BASE64URL_OMIT_PADDING, &bytes, length) + guard checkLength == length else { + return nil + } + + return String(data: Data(bytes: bytes, count: length), encoding: .ascii) + } +} diff --git a/mobile/ios/Push/PushRegistration.swift b/mobile/ios/Push/PushRegistration.swift new file mode 100644 index 0000000000..4919a6a7d9 --- /dev/null +++ b/mobile/ios/Push/PushRegistration.swift @@ -0,0 +1,129 @@ +/* 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/. */ + +import Foundation +import FxA +import Shared +import SwiftyJSON + +public class PushRegistration: NSObject, NSCoding { + let uaid: String + let secret: String + // We don't need to have more than one subscription until WebPush is exposed to content Javascript + // however, if/when we do, it'll make migrating easier if we have been serializing it like this all along. + fileprivate var subscriptions: [String: PushSubscription] + + public var defaultSubscription: PushSubscription { + return subscriptions[defaultSubscriptionID]! + } + + public init(uaid: String, secret: String, subscriptions: [String: PushSubscription] = [:]) { + self.uaid = uaid + self.secret = secret + + self.subscriptions = subscriptions + } + + public convenience init(uaid: String, secret: String, subscription: PushSubscription) { + self.init(uaid: uaid, secret: secret, subscriptions: [defaultSubscriptionID: subscription]) + } + + @objc public convenience required init?(coder aDecoder: NSCoder) { + guard let uaid = aDecoder.decodeObject(forKey: "uaid") as? String, + let secret = aDecoder.decodeObject(forKey: "secret") as? String, + let subscriptions = aDecoder.decodeObject(forKey: "subscriptions") as? [String: PushSubscription] else { + fatalError("Cannot decode registration") + } + self.init(uaid: uaid, secret: secret, subscriptions: subscriptions) + } + + @objc public func encode(with aCoder: NSCoder) { + aCoder.encode(uaid, forKey: "uaid") + aCoder.encode(secret, forKey: "secret") + aCoder.encode(subscriptions, forKey: "subscriptions") + } + + public static func from(json: JSON) -> PushRegistration? { + guard let endpointString = json["endpoint"].stringValue(), + let endpoint = URL(string: endpointString), + let secret = json["secret"].stringValue(), + let uaid = json["uaid"].stringValue(), + let channelID = json["channelID"].stringValue() else { + return nil + } + guard let defaultSubscription = try? PushSubscription(channelID: channelID, endpoint: endpoint) else { + return nil + } + return PushRegistration(uaid: uaid, secret: secret, subscriptions: [defaultSubscriptionID: defaultSubscription]) + } +} + +fileprivate let defaultSubscriptionID = "defaultSubscription" +/// Small NSCodable class for persisting a channel subscription. +/// We use NSCoder because we expect it to be stored in the profile. +public class PushSubscription: NSObject, NSCoding { + let channelID: String + let endpoint: URL + + let p256dhPublicKey: String + let p256dhPrivateKey: String + let authKey: String + + init(channelID: String, endpoint: URL, p256dhPrivateKey: String, p256dhPublicKey: String, authKey: String) { + self.channelID = channelID + self.endpoint = endpoint + self.p256dhPrivateKey = p256dhPrivateKey + self.p256dhPublicKey = p256dhPublicKey + self.authKey = authKey + } + + convenience init(channelID: String, endpoint: URL, keys: PushKeys) { + self.init(channelID: channelID, + endpoint: endpoint, + p256dhPrivateKey: keys.p256dhPrivateKey, + p256dhPublicKey: keys.p256dhPublicKey, + authKey: keys.auth) + } + + convenience init(channelID: String, endpoint: URL) throws { + let keys = try PushCrypto.sharedInstance.generateKeys() + self.init(channelID: channelID, endpoint: endpoint, keys: keys) + } + + @objc public convenience required init?(coder aDecoder: NSCoder) { + guard let channelID = aDecoder.decodeObject(forKey: "channelID") as? String, + let urlString = aDecoder.decodeObject(forKey: "endpoint") as? String, + let endpoint = URL(string: urlString), + let p256dhPrivateKey = aDecoder.decodeObject(forKey: "p256dhPrivateKey") as? String, + let p256dhPublicKey = aDecoder.decodeObject(forKey: "p256dhPublicKey") as? String, + let authKey = aDecoder.decodeObject(forKey: "authKey") as? String else { + return nil + } + + self.init(channelID: channelID, + endpoint: endpoint, + p256dhPrivateKey: p256dhPrivateKey, + p256dhPublicKey: p256dhPublicKey, + authKey: authKey) + } + + @objc public func encode(with aCoder: NSCoder) { + aCoder.encode(channelID, forKey: "channelID") + aCoder.encode(endpoint.absoluteString, forKey: "endpoint") + aCoder.encode(p256dhPrivateKey, forKey: "p256dhPrivateKey") + aCoder.encode(p256dhPublicKey, forKey: "p256dhPublicKey") + aCoder.encode(authKey, forKey: "authKey") + } +} + +public extension PushSubscription { + public func aesgcm(payload: String, encryptionHeader: String, cryptoHeader: String) -> String? { + let headers = PushCryptoHeaders(encryption: encryptionHeader, cryptoKey: cryptoHeader) + return try? PushCrypto.sharedInstance.aesgcm(ciphertext: payload, withHeaders: headers, decryptWith: p256dhPrivateKey, authenticateWith: authKey) + } + + public func aes128gcm(payload: String) -> String? { + return try? PushCrypto.sharedInstance.aes128gcm(payload: payload, decryptWith: p256dhPrivateKey, authenticateWith: authKey) + } +} diff --git a/mobile/ios/PushTests/LivePushClientTests.swift b/mobile/ios/PushTests/LivePushClientTests.swift new file mode 100644 index 0000000000..60e476be22 --- /dev/null +++ b/mobile/ios/PushTests/LivePushClientTests.swift @@ -0,0 +1,60 @@ +/* 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/. */ + +@testable import Account +import Foundation +import Shared +import XCTest + +class LivePushClientTests: XCTestCase { + + var endpointURL: NSURL { + return FennecPushConfiguration().endpointURL + } + + func generateDeviceID() -> String { + let num = arc4random_uniform(1 << 31) + return "test-id-deadbeef-\(num)" + } + + func testClientRegistration() { + let deviceID = generateDeviceID() + let client = PushClient(endpointURL: endpointURL) + + let registrationExpectation = XCTestExpectation() + let unregistrationExpectation = XCTestExpectation() + + client.register(deviceID) >>== { registration in + registrationExpectation.fulfill() + client.unregister(registration) >>== { res in + unregistrationExpectation.fulfill() + } + } + + wait(for: [registrationExpectation, unregistrationExpectation], timeout: 2 * 60) + } + + func testClientUpdate() { + let client = PushClient(endpointURL: endpointURL) + + let registrationExpectation = XCTestExpectation() + let updateExpectation = XCTestExpectation() + let unregistrationExpectation = XCTestExpectation() + + client.register(generateDeviceID()) >>== { ogRegistration in + registrationExpectation.fulfill() + + client.updateUAID(self.generateDeviceID(), withRegistration: ogRegistration) >>== { registration in + updateExpectation.fulfill() + XCTAssertEqual(ogRegistration, registration) + + client.unregister(registration) >>== { res in + unregistrationExpectation.fulfill() + } + } + } + + wait(for: [registrationExpectation, updateExpectation, unregistrationExpectation], timeout: 2 * 60) + } +} diff --git a/mobile/ios/PushTests/PushCryptoTests.swift b/mobile/ios/PushTests/PushCryptoTests.swift new file mode 100644 index 0000000000..3a737651f4 --- /dev/null +++ b/mobile/ios/PushTests/PushCryptoTests.swift @@ -0,0 +1,258 @@ +/* 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/. */ + +@testable import Account +import XCTest + +class PushCryptoTests: XCTestCase { + + let push = PushCrypto.sharedInstance + + func testRoundtrip_base64urlSafe() { + let ogString = "I am the walrus! I am the eggman!" + let ogData = ogString.data(using: .utf8)! + + guard let encodedString = ogData.base64urlSafeEncodedString else { + return XCTFail("base64urlSafeEncodedString failed") + } + + guard let decodedData = encodedString.base64urlSafeDecodedData else { + return XCTFail("base64urlSafeDecodedData failed") + } + + guard let decodedString = decodedData.utf8EncodedString else { + return XCTFail("utf8EncodedString failed") + } + + XCTAssertEqual(decodedString, ogString) + } + + func testRoundtrip_base64urlSafe_withSpecialChars() { + let encoded = "mW-ti1CqLQK4PyZBKy4q7g" + + XCTAssertEqual(encoded.base64urlSafeDecodedData!.base64urlSafeEncodedString, encoded) + } + + struct Aes128GcmTest { + let payload: String + let recvPrivKey: String + let authSecret: String + let plaintext: String + } + + func testDecrypt_aes128gcm() { + let tests = [ + Aes128GcmTest( + payload: "SVzmyN6TpFOehi6GNJk8uwAAABhBBDwzeKLAq5VOFJhxjoXwi7cj-30l4TWmY_44WITrgZIza_kKVO1yDxwEXAtAXpu8OiFCsWyJCGc0w3Trr3CZ5kJ-LTLIraUBhwPFSxC0geECfXIJ2Ma0NVP6Ezr6WX8t3EWluoFAlE5kkLuNbZm6HQLmDZX0jOZER3wXIx2VuXpPld0", + recvPrivKey: "yJnRHTLit-b-dJh4b1DyO5is5Tl60mHeObpkSezBLK0", + authSecret: "mW-ti1CqLQK4PyZBKy4q7g", + plaintext: "I am the walrus" + ), + Aes128GcmTest( + payload: "DGv6ra1nlYgDCS1FRnbzlwAAEABBBP4z9KsN6nGRTbVYI_c7VJSPQTBtkgcy27mlmlMoZIIgDll6e3vCYLocInmYWAmS6TlzAC8wEqKK6PBru3jl7A_yl95bQpu6cVPTpK4Mqgkf1CXztLVBSt2Ks3oZwbuwXPXLWyouBWLVWGNWQexSgSxsj_Qulcy4a-fN", + recvPrivKey: "q1dXpw3UpT5VOmu_cf_v6ih07Aems3njxI-JWgLcM94", + authSecret: "BTBZMqHH6r4Tts7J_aSIgg", + plaintext: "When I grow up, I want to be a watermelon" + ), + ] + + for test in tests { + if let deciphered = try? push.aes128gcm(payload: test.payload, + decryptWith: test.recvPrivKey, + authenticateWith: test.authSecret) { + XCTAssertEqual(deciphered, test.plaintext) + } else { + XCTFail("Failed to decipher \(test.plaintext)") + } + } + } + + func testFail_aes128gcm() { + let tests = [ + Aes128GcmTest( + payload: "bad base 64 encoding", + recvPrivKey: "yJnRHTLit-b-dJh4b1DyO5is5Tl60mHeObpkSezBLK0", + authSecret: "mW-ti1CqLQK4PyZBKy4q7g", + plaintext: "bad base64" + ), + Aes128GcmTest( + payload: "DGv6ra1nlYgDCS1FRnbzlwAAEABBBP4z9KsN6nGRTbVYI_c7VJSPQTBtkgcy27mlmlMoZIIgDll6e3vCYLocInmYWAmS6TlzAC8wEqKK6PBru3jl7A_yl95bQpu6cVPTpK4Mqgkf1CXztLVBSt2Ks3oZwbuwXPXLWyouBWLVWGNWQexSgSxsj_Qulcy4a-fN", + recvPrivKey: "badkey", + authSecret: "BTBZMqHH6r4Tts7J_aSIgg", + plaintext: "bad key" + ), + ] + + for test in tests { + do { + _ = try push.aes128gcm(payload: test.payload, + decryptWith: test.recvPrivKey, + authenticateWith: test.authSecret) + + XCTFail("Somehow, deciphered \(test.plaintext)") + } catch PushCryptoError.base64DecodeError { + XCTAssertEqual(test.plaintext, tests[0].plaintext) + } catch PushCryptoError.decryptionError(_) { + XCTAssertEqual(test.plaintext, tests[1].plaintext) + } catch PushCryptoError.utf8EncodingError { + XCTFail("Not tested") + } catch { + XCTFail("Not tested but found \(error)") + } + } + } + + func testRoundTrip_aes128gcm() { + // The real reason for this test is to test generateKeys() + guard let keys = try? push.generateKeys() else { + return XCTFail("Generating keys should not fail") + } + + let plaintext = "I am the egg man!" + + guard let payload = try? push.aes128gcm(plaintext: plaintext, encryptWith: keys.p256dhPublicKey, authenticateWith: keys.auth, rs: 1024, padLen: 2) else { + return XCTFail("Encryption should not fail") + } + + guard let deciphered = try? push.aes128gcm(payload: payload, decryptWith: keys.p256dhPrivateKey, authenticateWith: keys.auth) else { + return XCTFail("Decryption should not fail") + } + + XCTAssertEqual(deciphered, plaintext) + } + + struct AesGcmTest { + let plaintext: String + let recvPrivKey: String + let authSecret: String + let ciphertext: String + let cryptoKey: String + let encryption: String + } + + func testDecrypt_aesgcm() { + let tests = [ + AesGcmTest( + plaintext: "I am the walrus", + recvPrivKey: "9FWl15_QUQAWDaD3k3l50ZBZQJ4au27F1V4F0uLSD_M", + authSecret: "R29vIGdvbyBnJyBqb29iIQ", + ciphertext: "6nqAQUME8hNqw5J3kl8cpVVJylXKYqZOeseZG8UueKpA", + cryptoKey: "keyid=\"dhkey\"; dh=\"BNoRDbb84JGm8g5Z5CFxurSqsXWJ11ItfXEWYVLE85Y7CYkDjXsIEc4aqxYaQ1G8BqkXCJ6DPpDrWtdWj_mugHU\"", + encryption: "keyid=\"dhkey\"; salt=\"lngarbyKfMoi9Z75xYXmkg\"" + ), + AesGcmTest( + plaintext: "Small record size", + recvPrivKey: "4h23G_KkXC9TvBSK2v0Q7ImpS2YAuRd8hQyN0rFAwBg", + authSecret: "g2rWVHUCpUxgcL9Tz7vyeQ", + ciphertext: "oY4e5eDatDVt2fpQylxbPJM-3vrfhDasfPc8Q1PWt4tPfMVbz_sDNL_cvr0DXXkdFzS1lxsJsj550USx4MMl01ihjImXCjrw9R5xFgFrCAqJD3GwXA1vzS4T5yvGVbUp3SndMDdT1OCcEofTn7VC6xZ-zP8rzSQfDCBBxmPU7OISzr8Z4HyzFCGJeBfqiZ7yUfNlKF1x5UaZ4X6iU_TXx5KlQy_toV1dXZ2eEAMHJUcSdArvB6zRpFdEIxdcHcJyo1BIYgAYTDdAIy__IJVCPY_b2CE5W_6ohlYKB7xDyH8giNuWWXAgBozUfScLUVjPC38yJTpAUi6w6pXgXUWffende5FreQpnMFL1L4G-38wsI_-ISIOzdO8QIrXHxmtc1S5xzYu8bMqSgCinvCEwdeGFCmighRjj8t1zRWo0D14rHbQLPR_b1P5SvEeJTtS9Nm3iibM", + cryptoKey: "dh=BCg6ZIGuE2ZNm2ti6Arf4CDVD_8--aLXAGLYhpghwjl1xxVjTLLpb7zihuEOGGbyt8Qj0_fYHBP4ObxwJNl56bk", + encryption: "salt=5LIDBXbvkBvvb7ZdD-T4PQ; rs=3" + ), + AesGcmTest( + plaintext: "Yet another message", + recvPrivKey: "4h23G_KkXC9TvBSK2v0Q7ImpS2YAuRd8hQyN0rFAwBg", + authSecret: "6plwZnSpVUbF7APDXus3UQ", + ciphertext: "uEC5B_tR-fuQ3delQcrzrDCp40W6ipMZjGZ78USDJ5sMj-6bAOVG3AK6JqFl9E6AoWiBYYvMZfwThVxmDnw6RHtVeLKFM5DWgl1EwkOohwH2EhiDD0gM3io-d79WKzOPZE9rDWUSv64JstImSfX_ADQfABrvbZkeaWxh53EG59QMOElFJqHue4dMURpsMXg", + cryptoKey: "dh=BEaA4gzA3i0JDuirGhiLgymS4hfFX7TNTdEhSk_HBlLpkjgCpjPL5c-GL9uBGIfa_fhGNKKFhXz1k9Kyens2ZpQ", + encryption: "salt=ZFhzj0S-n29g9P2p4-I7tA; rs=8" + ), + AesGcmTest( + plaintext: "Some message", + recvPrivKey: "4h23G_KkXC9TvBSK2v0Q7ImpS2YAuRd8hQyN0rFAwBg", + authSecret: "aTDc6JebzR6eScy2oLo4RQ", + ciphertext: "Oo34w2F9VVnTMFfKtdx48AZWQ9Li9M6DauWJVgXU", + cryptoKey: "dh=BCHFVrflyxibGLlgztLwKelsRZp4gqX3tNfAKFaxAcBhpvYeN1yIUMrxaDKiLh4LNKPtj0BOXGdr-IQ-QP82Wjo", + encryption: "salt=zCU18Rw3A5aB_Xi-vfixmA; rs=24" + ) + ] + + for test in tests { + if let deciphered = try? push.aesgcm(ciphertext: test.ciphertext, + withHeaders: PushCryptoHeaders(encryption: test.encryption, cryptoKey: test.cryptoKey), + decryptWith: test.recvPrivKey, + authenticateWith: test.authSecret) { + XCTAssertEqual(deciphered, test.plaintext) + } else { + XCTFail("Failed to decipher \(test.plaintext)") + } + } + } + + func testFail_aesgcm() { + let tests = [ + AesGcmTest( + plaintext: "bad base64", + recvPrivKey: "4h23G_KkXC9TvBSK2v0Q7ImpS2YAuRd8hQyN0rFAwBg", + authSecret: "aTDc6JebzR6eScy2oLo4RQ", + ciphertext: "non base64", + cryptoKey: "dh=BCHFVrflyxibGLlgztLwKelsRZp4gqX3tNfAKFaxAcBhpvYeN1yIUMrxaDKiLh4LNKPtj0BOXGdr-IQ-QP82Wjo", + encryption: "salt=zCU18Rw3A5aB_Xi-vfixmA; rs=24" + ), + + AesGcmTest( + plaintext: "bad key", + recvPrivKey: "badkey", + authSecret: "aTDc6JebzR6eScy2oLo4RQ", + ciphertext: "Oo34w2F9VVnTMFfKtdx48AZWQ9Li9M6DauWJVgXU", + cryptoKey: "dh=BCHFVrflyxibGLlgztLwKelsRZp4gqX3tNfAKFaxAcBhpvYeN1yIUMrxaDKiLh4LNKPtj0BOXGdr-IQ-QP82Wjo", + encryption: "salt=zCU18Rw3A5aB_Xi-vfixmA; rs=24" + ), + ] + + for test in tests { + do { + _ = try push.aesgcm(ciphertext: test.ciphertext, + withHeaders: PushCryptoHeaders(encryption: test.encryption, cryptoKey: test.cryptoKey), + decryptWith: test.recvPrivKey, + authenticateWith: test.authSecret) + + XCTFail("Somehow, deciphered \(test.plaintext)") + } catch PushCryptoError.base64DecodeError { + XCTAssertEqual(test.plaintext, tests[0].plaintext) + } catch PushCryptoError.decryptionError(_) { + XCTAssertEqual(test.plaintext, tests[1].plaintext) + } catch PushCryptoError.utf8EncodingError { + XCTFail("Not tested") + } catch { + XCTFail("Not tested but found \(error)") + } + } + } + + func testRoundTrip_aesgcm() { + guard let keys = try? push.generateKeys() else { + return XCTFail("Generating keys should not fail") + } + + let plaintext = "While I'm away, I'll write home every day" + + guard let (headers, ciphertext) = try? push.aesgcm(plaintext: plaintext, + encryptWith: keys.p256dhPublicKey, + authenticateWith: keys.auth, + rs: 28, + padLen: 16) else { + return XCTFail("Encryption should not fail") + } + + guard let deciphered = try? push.aesgcm(ciphertext: ciphertext, + withHeaders: headers, + decryptWith: keys.p256dhPrivateKey, + authenticateWith: keys.auth) else { + return XCTFail("Decryption should not fail") + } + + XCTAssertEqual(deciphered, plaintext) + } + + func testKeyGeneration() { + guard let keys = try? push.generateKeys() else { + return XCTFail("Keys can't be tested") + } + // We can't really test if the keys are random enough, but we can check if they + // roundtrip with the base64urlSafe encoding. + for string in [keys.p256dhPublicKey, keys.p256dhPrivateKey, keys.auth] { + XCTAssertEqual(string.base64urlSafeDecodedData?.base64urlSafeEncodedString, string) + } + } +} diff --git a/mobile/ios/README.md b/mobile/ios/README.md new file mode 100644 index 0000000000..b03454ed63 --- /dev/null +++ b/mobile/ios/README.md @@ -0,0 +1,25 @@ +# Dactyloidae iOS + +This code only works with Xcode 9.2 and supports iOS 10 and above. + +This code is written in Swift 3.2. + +## Building the code + +1. Install the latest [Xcode developer tools](https://developer.apple.com/xcode/downloads/) from Apple. +2. Install Carthage + ```shell + brew update + brew install carthage + ``` +3. Clone the repository: + ```shell + git clone https://repo.dactyloidae.xyz/dactyloidae/dactyloidae + ``` +4. Pull in the project dependencies: + ```shell + cd dactyloidae/mobile/ios + sh ./bootstrap.sh + ``` +5. Open `Client.xcodeproj` in Xcode. +6. Build the `Fennec` scheme in Xcode. diff --git a/mobile/ios/ReadingList/Info.plist b/mobile/ios/ReadingList/Info.plist new file mode 100644 index 0000000000..b3205ecaf4 --- /dev/null +++ b/mobile/ios/ReadingList/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/mobile/ios/ReadingList/ReadingList-Bridging-Header.h b/mobile/ios/ReadingList/ReadingList-Bridging-Header.h new file mode 100644 index 0000000000..1df775e1a4 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingList-Bridging-Header.h @@ -0,0 +1,13 @@ +// +// ReadingList-Bridging-Header.h +// Client +// +// Created by Emily Toop on 1/8/16. +// Copyright © 2016 Mozilla. All rights reserved. +// + +#ifndef ReadingList_Bridging_Header_h +#define ReadingList_Bridging_Header_h + + +#endif /* ReadingList_Bridging_Header_h */ diff --git a/mobile/ios/ReadingList/ReadingListAuthenticator.swift b/mobile/ios/ReadingList/ReadingListAuthenticator.swift new file mode 100644 index 0000000000..9d1e4449a0 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListAuthenticator.swift @@ -0,0 +1,9 @@ +/* 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/. */ + +import Foundation + +protocol ReadingListAuthenticator { + var headers: [String: String] { get } +} diff --git a/mobile/ios/ReadingList/ReadingListBasicAuthAuthenticator.swift b/mobile/ios/ReadingList/ReadingListBasicAuthAuthenticator.swift new file mode 100644 index 0000000000..a430fd6dc1 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListBasicAuthAuthenticator.swift @@ -0,0 +1,16 @@ +/* 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/. */ + +import Foundation + +class ReadingListBasicAuthAuthenticator: ReadingListAuthenticator { + var headers: [String: String] + + init(username: String, password: String) { + let credentials = "\(username):\(password)" + let credentialsData = credentials.data(using: String.Encoding.utf8)! + let encodedCredentials = credentialsData.base64EncodedString(options: NSData.Base64EncodingOptions()) + self.headers = ["Authorization": "Basic \(encodedCredentials)"] + } +} diff --git a/mobile/ios/ReadingList/ReadingListBatchRecordResponse.swift b/mobile/ios/ReadingList/ReadingListBatchRecordResponse.swift new file mode 100644 index 0000000000..dab8e3e89c --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListBatchRecordResponse.swift @@ -0,0 +1,35 @@ +/* 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/. */ + +import Foundation + +class ReadingListBatchRecordResponse: ReadingListResponse { + var responses: [ReadingListRecordResponse] = [ReadingListRecordResponse]() + + override init?(response: HTTPURLResponse, json: [String: Any]) { + super.init(response: response, json: json) + guard let responses = json["responses"] as? [[String: Any]] else { + return nil + } + + for resp in responses { + guard let body = resp["body"] as? [String: Any], + let statusCode = resp["status"] as? Int, + let path = resp["path"] as? String, + let url = URL(string: path, relativeTo: self.response.url), + let headers = resp["headers"] as? [String: String], + let r = HTTPURLResponse(url: url, statusCode: statusCode, httpVersion: "1.1", headerFields: headers), + let recordResponse = ReadingListRecordResponse(response: r, json: body) else { + return nil + } + self.responses.append(recordResponse) + } + } + + var wasSuccessful: Bool { + get { + return response.statusCode == 200 + } + } +} diff --git a/mobile/ios/ReadingList/ReadingListChangeAccumulator.swift b/mobile/ios/ReadingList/ReadingListChangeAccumulator.swift new file mode 100644 index 0000000000..b8c5f695d1 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListChangeAccumulator.swift @@ -0,0 +1,14 @@ +/* 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/. */ + +import Foundation + +protocol ReadingListChangeAccumulator { + func addDeletedClientRecord(_ deletedRecord: ReadingListClientRecord) + func addDeletedServerRecord(_ deletedRecord: ReadingListServerRecord) + func addChangedRecord(_ changedRecord: ReadingListClientRecord) + func addUploadedRecord(_ uploadedRecord: ReadingListClientRecord, down: ReadingListServerRecord) + func addDownloadedRecord(_ downloadedRecord: ReadingListServerRecord) + func applyAccumulatedChanges() +} diff --git a/mobile/ios/ReadingList/ReadingListClient.swift b/mobile/ios/ReadingList/ReadingListClient.swift new file mode 100644 index 0000000000..abd685662d --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListClient.swift @@ -0,0 +1,211 @@ +/* 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/. */ + +import Foundation +import Alamofire + +enum ReadingListDeleteRecordResult { + case success(ReadingListRecordResponse) + case preconditionFailed(ReadingListResponse) + case notFound(ReadingListResponse) + case failure(ReadingListResponse) + case error(NSError) +} + +enum ReadingListGetRecordResult { + case success(ReadingListRecordResponse) + case notModified(ReadingListResponse) // TODO Should really call this NotModified for clarity + case notFound(ReadingListResponse) + case failure(ReadingListResponse) + case error(NSError) +} + +enum ReadingListGetAllRecordsResult { + case success(ReadingListRecordsResponse) + case notModified(ReadingListResponse) // TODO Should really call this NotModified for clarity + case failure(ReadingListResponse) + case error(NSError) +} + +enum ReadingListPatchRecordResult { +} + +enum ReadingListAddRecordResult { + case success(ReadingListRecordResponse) + case failure(ReadingListResponse) + case conflict(ReadingListResponse) + case error(NSError) +} + +enum ReadingListBatchAddRecordsResult { + case success(ReadingListBatchRecordResponse) + case failure(ReadingListResponse) + case error(NSError) +} + +private let ReadingListClientUnknownError = NSError(domain: "org.mozilla.ios.Fennec.ReadingListClient", code: -1, userInfo: nil) + +class ReadingListClient { + var serviceURL: URL + var authenticator: ReadingListAuthenticator + + var articlesURL: URL! + var articlesBaseURL: URL! + var batchURL: URL! + + func getRecordWithGuid(_ guid: String, ifModifiedSince: ReadingListTimestamp?, completion: @escaping (ReadingListGetRecordResult) -> Void) { + if let url = URL(string: guid, relativeTo: articlesBaseURL) { + SessionManager.default.request(createRequest("GET", url, ifModifiedSince: ifModifiedSince)).responseJSON(options: [], completionHandler: { response -> Void in + if let json = response.result.value as? [String: Any], let response = response.response { + switch response.statusCode { + case 200: + completion(.success(ReadingListRecordResponse(response: response, json: json)!)) + case 304: + completion(.notModified(ReadingListResponse(response: response, json: json)!)) + case 404: + completion(.notFound(ReadingListResponse(response: response, json: json)!)) + default: + completion(.failure(ReadingListResponse(response: response, json: json)!)) + } + } else { + completion(.error(response.result.error as NSError? ?? ReadingListClientUnknownError)) + } + }) + } else { + // TODO ??? + } + } + + func getRecordWithGuid(_ guid: String, completion: @escaping (ReadingListGetRecordResult) -> Void) { + getRecordWithGuid(guid, ifModifiedSince: nil, completion: completion) + } + + func getAllRecordsWithFetchSpec(_ fetchSpec: ReadingListFetchSpec, ifModifiedSince: ReadingListTimestamp?, completion: @escaping (ReadingListGetAllRecordsResult) -> Void) { + if let url = fetchSpec.getURL(serviceURL: serviceURL, path: "/v1/articles") { + SessionManager.default.request(createRequest("GET", url)).responseJSON(options: [], completionHandler: { response -> Void in + if let json = response.result.value as? [String: Any], let response = response.response { + switch response.statusCode { + case 200: + completion(.success(ReadingListRecordsResponse(response: response, json: json)!)) + case 304: + completion(.notModified(ReadingListResponse(response: response, json: json)!)) + default: + completion(.failure(ReadingListResponse(response: response, json: json)!)) + } + } else { + completion(.error(response.result.error as NSError? ?? ReadingListClientUnknownError)) + } + }) + } else { + // TODO ??? + } + } + + func getAllRecordsWithFetchSpec(_ fetchSpec: ReadingListFetchSpec, completion: @escaping (ReadingListGetAllRecordsResult) -> Void) { + getAllRecordsWithFetchSpec(fetchSpec, ifModifiedSince: nil, completion: completion) + } + + func patchRecord(_ record: ReadingListClientRecord, completion: (ReadingListPatchRecordResult) -> Void) { + } + + func addRecord(_ record: ReadingListClientRecord, completion: @escaping (ReadingListAddRecordResult) -> Void) { + SessionManager.default.request(createRequest("POST", articlesURL, json: record.json)).responseJSON(options: [], completionHandler: { response in + if let json = response.result.value as? [String: Any], let response = response.response { + switch response.statusCode { + case 200, 201: // TODO Should we have different results for these? Do we care about 200 vs 201? + completion(.success(ReadingListRecordResponse(response: response, json: json)!)) + case 303: + completion(.conflict(ReadingListResponse(response: response, json: json)!)) + default: + completion(.failure(ReadingListResponse(response: response, json: json)!)) + } + } else { + completion(.error(response.result.error as NSError? ?? ReadingListClientUnknownError)) + } + }) + } + + /// Build the JSON body for POST /v1/batch { defaults: {}, request: [ {body: {} } ] } + fileprivate func recordsToBatchJSON(_ records: [ReadingListClientRecord]) -> AnyObject { + return [ + "defaults": ["method": "POST", "path": "/v1/articles", "headers": ["Content-Type": "application/json"]], + "requests": records.map { ["body": $0.json] } + ] as NSDictionary + } + + func batchAddRecords(_ records: [ReadingListClientRecord], completion: @escaping (ReadingListBatchAddRecordsResult) -> Void) { + SessionManager.default.request(createRequest("POST", batchURL, json: recordsToBatchJSON(records))).responseJSON(options: [], completionHandler: { response in + if let json = response.result.value as? [String: Any], let response = response.response { + switch response.statusCode { + case 200: + completion(.success(ReadingListBatchRecordResponse(response: response, json: json)!)) + default: + completion(.failure(ReadingListResponse(response: response, json: json)!)) + } + } else { + completion(.error(response.result.error as NSError? ?? ReadingListClientUnknownError)) + } + }) + } + + func deleteRecordWithGuid(_ guid: String, ifUnmodifiedSince: ReadingListTimestamp?, completion: @escaping (ReadingListDeleteRecordResult) -> Void) { + if let url = URL(string: guid, relativeTo: articlesBaseURL) { + SessionManager.default.request(createRequest("DELETE", url, ifUnmodifiedSince: ifUnmodifiedSince)).responseJSON(options: [], completionHandler: { response in + if let json = response.result.value as? [String: Any], let response = response.response { + switch response.statusCode { + case 200: + completion(.success(ReadingListRecordResponse(response: response, json: json)!)) + case 412: + completion(.preconditionFailed(ReadingListResponse(response: response, json: json)!)) + case 404: + completion(.notFound(ReadingListResponse(response: response, json: json)!)) + default: + completion(.failure(ReadingListResponse(response: response, json: json)!)) + } + } else { + completion(.error(response.result.error as NSError? ?? ReadingListClientUnknownError)) + } + }) + } else { + // TODO ??? + } + } + + func deleteRecordWithGuid(_ guid: String, completion: @escaping (ReadingListDeleteRecordResult) -> Void) { + deleteRecordWithGuid(guid, ifUnmodifiedSince: nil, completion: completion) + } + + func createRequest(_ method: String, _ url: URL, ifUnmodifiedSince: ReadingListTimestamp? = nil, ifModifiedSince: ReadingListTimestamp? = nil, json: AnyObject? = nil) -> URLRequest { + let request = NSMutableURLRequest(url: url) + request.httpMethod = method + if let ifUnmodifiedSince = ifUnmodifiedSince { + request.setValue(String(ifUnmodifiedSince), forHTTPHeaderField: "If-Unmodified-Since") + } + if let ifModifiedSince = ifModifiedSince { + request.setValue(String(ifModifiedSince), forHTTPHeaderField: "If-Modified-Since") + } + for (headerField, value) in authenticator.headers { + request.setValue(value, forHTTPHeaderField: headerField) + } + request.addValue("application/json", forHTTPHeaderField: "Accept") + if let json = json { + request.addValue("application/json", forHTTPHeaderField: "Content-Type") + do { + request.httpBody = try JSONSerialization.data(withJSONObject: json, options: JSONSerialization.WritingOptions.prettyPrinted) + } catch _ { + request.httpBody = nil + } // TODO Handle errors here + } + return request as URLRequest + } + + init(serviceURL: URL, authenticator: ReadingListAuthenticator) { + self.serviceURL = serviceURL + self.authenticator = authenticator + + self.articlesURL = URL(string: "/v1/articles", relativeTo: self.serviceURL) + self.articlesBaseURL = URL(string: "/v1/articles/", relativeTo: self.serviceURL) + self.batchURL = URL(string: "/v1/batch", relativeTo: self.serviceURL) + } +} diff --git a/mobile/ios/ReadingList/ReadingListClientMetadata.swift b/mobile/ios/ReadingList/ReadingListClientMetadata.swift new file mode 100644 index 0000000000..f3921ae10b --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListClientMetadata.swift @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation + +public struct ReadingListClientMetadata: Equatable { + /// The id of the record in the database + public var id: Int64 + /// A client timestamp + public var lastModified: ReadingListTimestamp + + public init?(row: [String: Any]) { + guard let id = row["client_id"] as? Int64, + let lastModified = row["client_last_modified"] as? Int64 else { + return nil + } + self.id = id + self.lastModified = lastModified + } +} + +public func ==(lhs: ReadingListClientMetadata, rhs: ReadingListClientMetadata) -> Bool { + return lhs.id == rhs.id && lhs.lastModified == rhs.lastModified +} diff --git a/mobile/ios/ReadingList/ReadingListClientRecord.swift b/mobile/ios/ReadingList/ReadingListClientRecord.swift new file mode 100644 index 0000000000..705343623d --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListClientRecord.swift @@ -0,0 +1,67 @@ +/* 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/. */ + +import Foundation + +public struct ReadingListClientRecord: Equatable { + public let clientMetadata: ReadingListClientMetadata + public let serverMetadata: ReadingListServerMetadata? + + public let url: String + public let title: String + public let addedBy: String + public let unread: Bool + public let archived: Bool + public let favorite: Bool + + /// Initializer for when a record is loaded from a database row + public init?(row: [String: Any]) { + guard let clientMetadata = ReadingListClientMetadata(row: row) else { + return nil + } + + guard let url = row["url"] as? String, + let title = row["title"] as? String, + let addedBy = row["added_by"] as? String, + let unread = row["unread"] as? Bool else { + return nil + } + + self.clientMetadata = clientMetadata + self.serverMetadata = ReadingListServerMetadata(row: row) + + self.url = url + self.title = title + self.addedBy = addedBy + + self.unread = unread + + self.archived = row["archived"] as? Bool ?? false + self.favorite = row["favorite"] as? Bool ?? false + } + + public var json: AnyObject { + get { + let json = NSMutableDictionary() + json["url"] = url + json["title"] = title + json["added_by"] = addedBy + json["unread"] = unread + json["archived"] = archived + json["favorite"] = favorite + return json + } + } +} + +public func ==(lhs: ReadingListClientRecord, rhs: ReadingListClientRecord) -> Bool { + return lhs.clientMetadata == rhs.clientMetadata + && lhs.serverMetadata == rhs.serverMetadata + && lhs.url == rhs.url + && lhs.title == rhs.title + && lhs.addedBy == rhs.addedBy + && lhs.unread == rhs.unread + && lhs.archived == rhs.archived + && lhs.favorite == rhs.favorite +} diff --git a/mobile/ios/ReadingList/ReadingListError.swift b/mobile/ios/ReadingList/ReadingListError.swift new file mode 100644 index 0000000000..39fd68ddf7 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListError.swift @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +import Shared + +// TODO This needs to encapsulate an NSError eventually +open class ReadingListError: MaybeErrorType { + var message: String + init(_ message: String) { + self.message = message + } + open var description: String { + return message + } +} diff --git a/mobile/ios/ReadingList/ReadingListFetchSpec.swift b/mobile/ios/ReadingList/ReadingListFetchSpec.swift new file mode 100644 index 0000000000..404aea34df --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListFetchSpec.swift @@ -0,0 +1,87 @@ +/* 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/. */ + +import Foundation + +// TODO This should really use NSURLComponents to build up the query part. And not string ops. + +class ReadingListFetchSpec { + var queryString: String + + init(queryString: String) { + self.queryString = queryString + } + + func getURL(serviceURL: URL) -> URL? { + if var components = URLComponents(url: serviceURL, resolvingAgainstBaseURL: true) { + components.query = queryString + return components.url + } + return nil + } + + func getURL(serviceURL: URL, path: String) -> URL? { + if var components = URLComponents(url: serviceURL, resolvingAgainstBaseURL: true) { + components.path = path + components.query = queryString + return components.url + } + return nil + } + + // This should really generate a dictionary of values that we can pass to NSURLComponents instead of building the query string by hand + + class Builder { + var buffer: String = "" + var first = true + + func build() -> ReadingListFetchSpec { + return ReadingListFetchSpec(queryString: buffer) + } + + fileprivate func ampersand() { + if first { + first = false + return + } + buffer += "&" + } + + func setUnread(_ unread: Bool) -> Builder { + ampersand() + buffer += "unread=" + buffer += unread ? "true" : "false" + return self + } + + func setStatus(_ status: String, not: Bool) -> Builder { + ampersand() + if not { + buffer += "not_" + } + buffer += "status=" + buffer += status + return self + } + + fileprivate func qualifyAttribute(_ attribute: String, withQualifier qualifier: String, value: String) -> Builder { + ampersand() + buffer += qualifier + buffer += attribute + buffer += "=" + buffer += value + return self + } + + func setMinAttribute(_ attribute: String, value: String) -> Builder { + _ = qualifyAttribute(attribute, withQualifier: "min_", value: value) + return self + } + + func setMaxAttribute(_ attribute: String, value: String) -> Builder { + _ = qualifyAttribute(attribute, withQualifier: "max_", value: value) + return self + } + } +} diff --git a/mobile/ios/ReadingList/ReadingListOAuthAuthenticator.swift b/mobile/ios/ReadingList/ReadingListOAuthAuthenticator.swift new file mode 100644 index 0000000000..b312aa5ae0 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListOAuthAuthenticator.swift @@ -0,0 +1,15 @@ +/* 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/. */ + +import Foundation + +class ReadingListOAuthAuthAuthenticator: ReadingListAuthenticator { + var token: String + var headers: [String: String] + + init(token: String) { + self.token = token + self.headers = ["Authorization": "Bearer \(token)"] + } +} \ No newline at end of file diff --git a/mobile/ios/ReadingList/ReadingListRecord.swift b/mobile/ios/ReadingList/ReadingListRecord.swift new file mode 100644 index 0000000000..53ffa51788 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListRecord.swift @@ -0,0 +1,44 @@ +/* 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/. */ + +import Foundation + +// TODO This is not used anymore. Decide if we need to turn this into a protocol that the ClientRecord and ServerRecord implement. Not sure if we actually need that though. +class ReadingListRecord { + let serverMetadata: ReadingListServerMetadata? + + init(serverMetadata: ReadingListServerMetadata?) { + self.serverMetadata = serverMetadata + } + + var guid: String? { + get { + return serverMetadata?.guid + } + } + + var serverLastModified: Int64? { + get { + return serverMetadata?.lastModified + } + } + + var url: String { + get { + fatalError("Subclass Responsibility") + } + } + + var title: String { + get { + fatalError("Subclass Responsibility") + } + } + + var addedBy: String { + get { + fatalError("Subclass Responsibility") + } + } +} diff --git a/mobile/ios/ReadingList/ReadingListRecordResponse.swift b/mobile/ios/ReadingList/ReadingListRecordResponse.swift new file mode 100644 index 0000000000..206eb7cdb5 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListRecordResponse.swift @@ -0,0 +1,28 @@ +/* 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/. */ + +import Foundation + +class ReadingListRecordResponse: ReadingListResponse { + override init?(response: HTTPURLResponse, json: [String: Any]) { + super.init(response: response, json: json) + } + + var wasSuccessful: Bool { + get { + return response.statusCode == 200 || response.statusCode == 201 || response.statusCode == 204 + // TODO On Android we call super.wasSuccessful() .. is there another value that we consider a success? + } + } + + var record: ReadingListServerRecord? { + get { + if let json = self.json { + return ReadingListServerRecord(json: json) + } else { + return nil + } + } + } +} diff --git a/mobile/ios/ReadingList/ReadingListRecordsResponse.swift b/mobile/ios/ReadingList/ReadingListRecordsResponse.swift new file mode 100644 index 0000000000..97827df040 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListRecordsResponse.swift @@ -0,0 +1,36 @@ +/* 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/. */ + +import Foundation + +class ReadingListRecordsResponse: ReadingListResponse { + override init?(response: HTTPURLResponse, json: [String: Any]) { + super.init(response: response, json: json) + } + + var wasSuccessful: Bool { + get { + return response.statusCode == 200 || response.statusCode == 201 || response.statusCode == 204 + // TODO On Android we call super.wasSuccessful() .. is there another value that we consider a success? + } + } + + var records: [ReadingListServerRecord]? { + get { + if let json = self.json { + var records = [ReadingListServerRecord]() + if let items = json["items"] as? [[String: Any]] { + for item in items { + if let record = ReadingListServerRecord(json: item) { + records.append(record) + } + } + } + return records + } else { + return nil + } + } + } +} diff --git a/mobile/ios/ReadingList/ReadingListResponse.swift b/mobile/ios/ReadingList/ReadingListResponse.swift new file mode 100644 index 0000000000..fb9739a17a --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListResponse.swift @@ -0,0 +1,28 @@ +/* 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/. */ + +import Foundation + +/// Wrapper around NSURLResponse and the response json object to easily pass this to delegates. Also contains some higher level functions to access service specific headers. +/// +/// TODO: In the Android code this is a subclass of MozResponse - Which has a bunch of other useful shortcuts. Maybe we should do that too? Or for the sake of simplicity, move some of those functions (which ones do we need?) into this class +class ReadingListResponse { + var response: HTTPURLResponse + var json: [String: Any]? + + init?(response: HTTPURLResponse, json: [String: Any]) { + self.response = response + self.json = json + } + + var lastModified: Int64? { + get { + if let lastModified = response.allHeaderFields["Last-Modified"] as? String { + return Int64(lastModified) + } else { + return nil + } + } + } +} diff --git a/mobile/ios/ReadingList/ReadingListSQLStorage.swift b/mobile/ios/ReadingList/ReadingListSQLStorage.swift new file mode 100644 index 0000000000..e0e5193a23 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListSQLStorage.swift @@ -0,0 +1,180 @@ +/* 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/. */ + +import Foundation + +import SQLite +import Shared + +class ReadingListSQLStorage: ReadingListStorage { + var db: Connection! + let items: Table! + struct ItemColumns { + // Client Metadata + static let ClientId = Expression("client_id") + static let ClientLastModified = Expression("client_last_modified") + // Server Metadata + static let Id = Expression("id") + static let LastModified = Expression("last_modified") + // Properties + static let Url = Expression("url") + static let Title = Expression("title") + static let AddedBy = Expression("added_by") + static let Archived = Expression("archived") + static let Favorite = Expression("favorite") + static let Unread = Expression("unread") + } + + init(path: String) { + db = try! Connection(path) + + items = Table("items") + do { + try db.run(items.create(temporary: false, ifNotExists: true, block: { (t: SQLite.TableBuilder) in + // Client Metadata + t.column(ItemColumns.ClientId, primaryKey: .autoincrement) + t.column(ItemColumns.ClientLastModified) + // Server Metadata + t.column(ItemColumns.Id) // TODO Unique but may be null? + t.column(ItemColumns.LastModified) + // Properties + t.column(ItemColumns.Url, unique: true) + t.column(ItemColumns.Title) + t.column(ItemColumns.AddedBy) + t.column(ItemColumns.Archived, defaultValue: false) + t.column(ItemColumns.Favorite, defaultValue: false) + t.column(ItemColumns.Unread, defaultValue: true) + })) + } catch { + print("Unable to create items database '\(error)") + } + } + + func getAllRecords() -> Maybe<[ReadingListClientRecord]> { + do { + let preparedItems = try db.prepare(items) + return Maybe(success: Array(preparedItems).map {ReadingListClientRecord(row: self.rowToDictionary($0))!}) + } catch { + return Maybe(failure: ReadingListStorageError("Can't fetch all records: \(error)")) + } + } + + func getNewRecords() -> Maybe<[ReadingListClientRecord]> { + do { + let preparedItems = try db.prepare(items.filter(ItemColumns.Id == nil)) + return Maybe(success: Array(preparedItems).map {ReadingListClientRecord(row: self.rowToDictionary($0))!}) + } catch { + return Maybe(failure: ReadingListStorageError("Can't fetch all records: \(error)")) + } + } + + func getUnreadRecords() -> Maybe<[ReadingListClientRecord]> { + do { + let preparedItems = try db.prepare(items.filter(ItemColumns.Unread == true)) + return Maybe(success: Array(preparedItems).map {ReadingListClientRecord(row: self.rowToDictionary($0))!}) + } catch { + return Maybe(failure: ReadingListStorageError("Can't fetch all records: \(error)")) + } + } + + func getAvailableRecords() -> Maybe<[ReadingListClientRecord]> { + do { + let preparedItems = try db.prepare(items.order(ItemColumns.ClientLastModified.desc)) + return Maybe(success: Array(preparedItems).map {ReadingListClientRecord(row: self.rowToDictionary($0))!}) + } catch { + return Maybe(failure: ReadingListStorageError("Can't fetch all records: \(error)")) + } + } + + func deleteRecord(_ record: ReadingListClientRecord) -> Maybe { + print("Trying to delete record with id \(record.clientMetadata.id)\n") + let query = items.filter(ItemColumns.ClientId == record.clientMetadata.id) + do { + try db.run(query.delete()) + return Maybe(success: Void()) + } catch { + return Maybe(failure: ReadingListStorageError("Failed to delete")) + } + } + + func deleteAllRecords() -> Maybe { + do { + try db.run(self.items.delete()) + return Maybe(success: Void()) + } catch { + return Maybe(failure: ReadingListStorageError("Failed to delete")) + } + } + + func createRecordWithURL(_ url: String, title: String, addedBy: String) -> Maybe { + let insert = items.insert(ItemColumns.ClientLastModified <- ReadingListNow(), ItemColumns.Url <- url, ItemColumns.Title <- title, ItemColumns.AddedBy <- addedBy) + + do { + let id = try db.run(insert) + let preparedItems = try db.prepare(items.filter(ItemColumns.ClientId == id)) + if let item = Array(preparedItems).first { + if let record = ReadingListClientRecord(row: rowToDictionary(item)) { + return Maybe(success: record) + } else { + return Maybe(failure: ReadingListStorageError("Can't create RLCR from row")) + } + } else { + return Maybe(failure: ReadingListStorageError("Can't get first item from results")) + } + } catch { + return Maybe(failure: ReadingListStorageError("Can't insert: \(error)")) + } + } + + func getRecordWithURL(_ url: String) -> Maybe { + do { + let preparedItems = try db.prepare(items.filter(ItemColumns.Url == url)) + if let item = Array(preparedItems).first { + if let record = ReadingListClientRecord(row: rowToDictionary(item)) { + return Maybe(success: record) + } else { + return Maybe(failure: ReadingListStorageError("Can't create RLCR from row")) + } + } else { + return Maybe(success: nil) + } + } catch { + return Maybe(failure: ReadingListStorageError("Can't fetch: \(error)")) + } + } + + func updateRecord(_ record: ReadingListClientRecord, unread: Bool) -> Maybe { + let query = items.filter(ItemColumns.ClientId == record.clientMetadata.id).update(ItemColumns.Unread <- unread) + do { + try db.run(query) + let preparedItems = try db.prepare(items.filter(ItemColumns.ClientId == record.clientMetadata.id)) + if let item = Array(preparedItems).first { + if let record = ReadingListClientRecord(row: rowToDictionary(item)) { + return Maybe(success: record) + } else { + return Maybe(failure: ReadingListStorageError("Can't create RLCR from row")) + } + } else { + return Maybe(success: nil) + } + } catch { + return Maybe(success: nil) + } + } + + fileprivate func rowToDictionary(_ row: Row) -> [String: Any] { + var result: [String: Any] = [:] + result["client_id"] = NSNumber(value: row.get(ItemColumns.ClientId)) + result["client_last_modified"] = NSNumber(value: row.get(ItemColumns.ClientLastModified)) + result["id"] = row.get(ItemColumns.Id) + result["last_modified"] = NSNumber(value: row.get(ItemColumns.LastModified) ?? 0) + result["url"] = row.get(ItemColumns.Url) + result["title"] = row.get(ItemColumns.Title) + result["added_by"] = row.get(ItemColumns.AddedBy) + result["archived"] = row.get(ItemColumns.Archived) + result["favorite"] = row.get(ItemColumns.Favorite) + result["unread"] = row.get(ItemColumns.Unread) + return result + } +} diff --git a/mobile/ios/ReadingList/ReadingListServerMetadata.swift b/mobile/ios/ReadingList/ReadingListServerMetadata.swift new file mode 100644 index 0000000000..e307a09feb --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListServerMetadata.swift @@ -0,0 +1,37 @@ +/* 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/. */ + +import Foundation + +public struct ReadingListServerMetadata: Equatable { + public var guid: String + public var lastModified: ReadingListTimestamp + + init(guid: String, lastModified: ReadingListTimestamp) { + self.guid = guid + self.lastModified = lastModified + } + + /// Initialize from server record. + init?(json: [String: Any]) { + self.init(data: json) + } + + init?(row: [String: Any]) { + self.init(data: row) + } + + private init?(data: [String: Any]) { + guard let guid = data["id"] as? String, + let lastModified = data["last_modified"] as? Int64 else { + return nil + } + self.guid = guid + self.lastModified = lastModified + } +} + +public func ==(lhs: ReadingListServerMetadata, rhs: ReadingListServerMetadata) -> Bool { + return lhs.guid == rhs.guid && lhs.lastModified == rhs.lastModified +} diff --git a/mobile/ios/ReadingList/ReadingListServerRecord.swift b/mobile/ios/ReadingList/ReadingListServerRecord.swift new file mode 100644 index 0000000000..700f9c2ec7 --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListServerRecord.swift @@ -0,0 +1,41 @@ +/* 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/. */ + +import Foundation + +struct ReadingListServerRecord { + let serverMetadata: ReadingListServerMetadata? + + let url: String + let title: String + let addedBy: String + let unread: Bool + let archived: Bool + let favorite: Bool + + /// Initializer for when a record is loaded from server-sent json + init?(json: [String: Any]?) { + guard let json = json, + let serverMetadata = ReadingListServerMetadata(json: json), + let url = json["url"] as? String, + let title = json["title"] as? String, + let addedBy = json["added_by"] as? String, + let unread = json["unread"] as? Bool, + let archived = json["archived"] as? Bool, + let favorite = json["favorite"] as? Bool else { + return nil + } + + self.serverMetadata = serverMetadata + + self.url = url + self.title = title + self.addedBy = addedBy + + self.unread = unread + self.archived = archived + self.favorite = favorite + } + +} diff --git a/mobile/ios/ReadingList/ReadingListService.swift b/mobile/ios/ReadingList/ReadingListService.swift new file mode 100644 index 0000000000..ca3ff9cf3b --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListService.swift @@ -0,0 +1,42 @@ +/* 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/. */ + +import Foundation +import Shared + +/// This is the public API that the application and extension talk to. It exposes the bare minimum +/// functions that need to be public and hides details like storage and syncing. +open class ReadingListService { + var databasePath: String + var storage: ReadingListStorage + + public init?(profileStoragePath: String) { + databasePath = (profileStoragePath as NSString).appendingPathComponent("ReadingList.db") + storage = ReadingListSQLStorage(path: "\(profileStoragePath)/ReadingList.db") + } + + open func getAvailableRecords() -> Maybe<[ReadingListClientRecord]> { + return storage.getAvailableRecords() + } + + @discardableResult open func deleteRecord(_ record: ReadingListClientRecord) -> Maybe { + return storage.deleteRecord(record) + } + + open func deleteAllRecords() -> Maybe { + return storage.deleteAllRecords() + } + + @discardableResult open func createRecordWithURL(_ url: String, title: String, addedBy: String) -> Maybe { + return storage.createRecordWithURL(url, title: title, addedBy: addedBy) + } + + open func getRecordWithURL(_ url: String) -> Maybe { + return storage.getRecordWithURL(url) + } + + @discardableResult open func updateRecord(_ record: ReadingListClientRecord, unread: Bool) -> Maybe { + return storage.updateRecord(record, unread: unread) + } +} diff --git a/mobile/ios/ReadingList/ReadingListStorage.swift b/mobile/ios/ReadingList/ReadingListStorage.swift new file mode 100644 index 0000000000..5d7bb6ec6f --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListStorage.swift @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +import Shared + +class ReadingListStorageError: MaybeErrorType { + var message: String + init(_ message: String) { + self.message = message + } + var description: String { + return message + } +} + +/// Storage protocol. The only thing the client (application) communicates with is the storage. Adding, removing and updating items. +protocol ReadingListStorage { + func getAllRecords() -> Maybe<[ReadingListClientRecord]> + func getNewRecords() -> Maybe<[ReadingListClientRecord]> + + // These are the used by the application + func getUnreadRecords() -> Maybe<[ReadingListClientRecord]> + func getAvailableRecords() -> Maybe<[ReadingListClientRecord]> + func deleteRecord(_ record: ReadingListClientRecord) -> Maybe + func deleteAllRecords() -> Maybe + func createRecordWithURL(_ url: String, title: String, addedBy: String) -> Maybe + func getRecordWithURL(_ url: String) -> Maybe + func updateRecord(_ record: ReadingListClientRecord, unread: Bool) -> Maybe +} diff --git a/mobile/ios/ReadingList/ReadingListSyncMetadata.swift b/mobile/ios/ReadingList/ReadingListSyncMetadata.swift new file mode 100644 index 0000000000..40cf0fd2cc --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListSyncMetadata.swift @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation + +enum ReadingListSyncChanges { + +} + +enum ReadingListSyncStatus { + case synced + case new + case deleted + case modified +} + +enum ReadingListSyncChange { + case none, unread, favorite, resolved +} + +struct ReadingListSyncMetadata { + var changes: ReadingListSyncChanges + var status: ReadingListSyncStatus +} diff --git a/mobile/ios/ReadingList/ReadingListSynchronizer.swift b/mobile/ios/ReadingList/ReadingListSynchronizer.swift new file mode 100644 index 0000000000..0658d8755f --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListSynchronizer.swift @@ -0,0 +1,69 @@ +/* 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/. */ + +import Foundation + +enum ReadingListSynchronizerResult { + case success + case failure + case error(NSError) +} + +enum ReadingListSyncType { + case uploadOnly + case full +} + +class ReadingListSynchronizer { + var storage: ReadingListStorage + var client: ReadingListClient + + init(storage: ReadingListStorage, client: ReadingListClient) { + self.storage = storage + self.client = client + } + + func synchronize(type: ReadingListSyncType, completion: (ReadingListSynchronizerResult) -> Void) { + // TODO Check if we are already syncing - Keep state somewhere + // TODO If this is a first time sync then we want to remember the account and server in storage, so that: + // TODO Check if the client is configured to use a different account or server + switch type { + case .uploadOnly: + let synchronizer = ReadingListUploadOnlySynchronizer(storage: storage, client: client) + synchronizer.synchronizeWithCompletion(completion) + case .full: + let synchronizer = ReadingListFullSynchronizer(storage: storage, client: client) + synchronizer.synchronizeWithCompletion(completion) + } + } +} + +// This is implemented in two different classes to make the design simpler. There will be some duplicate +// code but I prefer that instead of having two implementations in one class. + +private class ReadingListUploadOnlySynchronizer { + var storage: ReadingListStorage + var client: ReadingListClient + + init(storage: ReadingListStorage, client: ReadingListClient) { + self.storage = storage + self.client = client + } + + func synchronizeWithCompletion(_ completion: (ReadingListSynchronizerResult) -> Void) { + } +} + +private class ReadingListFullSynchronizer { + var storage: ReadingListStorage + var client: ReadingListClient + + init(storage: ReadingListStorage, client: ReadingListClient) { + self.storage = storage + self.client = client + } + + func synchronizeWithCompletion(_ completion: (ReadingListSynchronizerResult) -> Void) { + } +} diff --git a/mobile/ios/ReadingList/ReadingListUtils.swift b/mobile/ios/ReadingList/ReadingListUtils.swift new file mode 100644 index 0000000000..520145255f --- /dev/null +++ b/mobile/ios/ReadingList/ReadingListUtils.swift @@ -0,0 +1,16 @@ +/* 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/. */ + +import Foundation + +public typealias ReadingListRecordId = Int64 +public typealias ReadingListTimestamp = Int64 + +func ReadingListNow() -> ReadingListTimestamp { + return ReadingListTimestamp(Date.timeIntervalSinceReferenceDate * 1000.0) +} + +let ReadingListDefaultUnread: Bool = true +let ReadingListDefaultFavorite: Bool = false +let ReadingListDefaultArchived: Bool = false diff --git a/mobile/ios/ReadingListTests/Info.plist b/mobile/ios/ReadingListTests/Info.plist new file mode 100644 index 0000000000..9411e4a06e --- /dev/null +++ b/mobile/ios/ReadingListTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/ReadingListTests/ReadingListClientRecordTestCase.swift b/mobile/ios/ReadingListTests/ReadingListClientRecordTestCase.swift new file mode 100644 index 0000000000..fddfbdbbde --- /dev/null +++ b/mobile/ios/ReadingListTests/ReadingListClientRecordTestCase.swift @@ -0,0 +1,126 @@ +/* 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/. */ + +@testable import ReadingList +import Foundation + +import XCTest + +class ReadingListClientRecordTestCase: XCTestCase { + + func testInitWithRow() { + let now = ReadingListNow() + let row: [String: Any] = [ + "client_id": Int64(1234), + "client_last_modified": now, + "id": "5DB5597A-8E60-454D-B1F5-51810C2A5FFE", + "last_modified": now, + "url": "http://localhost/article/1", + "title": "Article 1", + "added_by": "Stefan's iPhone", + "unread": true, + "archived": false, + "favorite": true + ] + + let record = ReadingListClientRecord(row: row) + XCTAssert(record != nil) + + if let record = record { + XCTAssertEqual(record.url, "http://localhost/article/1") + XCTAssertEqual(record.title, "Article 1") + XCTAssertEqual(record.addedBy, "Stefan's iPhone") + XCTAssertEqual(record.unread, true) + XCTAssertEqual(record.archived, false) + XCTAssertEqual(record.favorite, true) + + XCTAssert(record.clientMetadata.id == 1234) + XCTAssert(record.clientMetadata.lastModified == now) + + XCTAssert(record.serverMetadata != nil) + XCTAssertEqual(record.serverMetadata!.guid, "5DB5597A-8E60-454D-B1F5-51810C2A5FFE") + XCTAssertEqual(record.serverMetadata!.lastModified, now) + } + } + + func testInitWithRowWithoutServerMeta() { + let now = ReadingListNow() + let row: [String:Any] = [ + "client_id": Int64(1234), + "client_last_modified": now, + "url": "http://localhost/article/1", + "title": "Article 1", + "added_by": "Stefan's iPhone", + "unread": true, + "archived": false, + "favorite": true + ] + + let record = ReadingListClientRecord(row: row) + XCTAssert(record != nil) + + if let record = record { + XCTAssertEqual(record.url, "http://localhost/article/1") + XCTAssertEqual(record.title, "Article 1") + XCTAssertEqual(record.addedBy, "Stefan's iPhone") + XCTAssertEqual(record.unread, true) + XCTAssertEqual(record.archived, false) + XCTAssertEqual(record.favorite, true) + + XCTAssert(record.clientMetadata.id == 1234) + XCTAssert(record.clientMetadata.lastModified == now) + + XCTAssert(record.serverMetadata == nil) + } + } + + func testInitWithEmptyRow() { + let row = NSDictionary() + let record = ReadingListClientRecord(row: row as! [String : Any]) + XCTAssert(record == nil) + } + +// func testInit() { +// let record = ReadingListClientRecord(url: "http://localhost/some/article", title: "Some Article", addedBy: "Stefan's iPad Mini") +// XCTAssertNil(record.clientMetadata.id) +// XCTAssert(record.clientMetadata.lastModified != 0) +// XCTAssert(record.serverMetadata == nil) +// XCTAssertEqual(record.url, "http://localhost/some/article") +// XCTAssertEqual(record.title, "Some Article") +// XCTAssertEqual(record.addedBy, "Stefan's iPad Mini") +// XCTAssertEqual(record.unread, ReadingListDefaultUnread) +// XCTAssertEqual(record.favorite, ReadingListDefaultFavorite) +// XCTAssertEqual(record.archived, ReadingListDefaultArchived) +// } + + func testJSON() { + let now = ReadingListNow() + let row: [String:Any] = [ + "client_id": Int64(1234), + "client_last_modified": now, + "id": "5DB5597A-8E60-454D-B1F5-51810C2A5FFE", + "last_modified": now, + "url": "http://localhost/article/1", + "title": "Article 1", + "added_by": "Stefan's iPhone 3GS", + "unread": true, + "archived": false, + "favorite": true + ] + + let record = ReadingListClientRecord(row: row) + XCTAssert(record != nil) + + if let record = record { + let json: AnyObject = record.json + XCTAssertEqual(json.value(forKeyPath: "url") as? String, "http://localhost/article/1") + XCTAssertEqual(json.value(forKeyPath: "title") as? String, "Article 1") + XCTAssertEqual(json.value(forKeyPath: "added_by") as? String, "Stefan's iPhone 3GS") + + XCTAssertEqual(json.value(forKeyPath: "unread") as? Bool, true) + XCTAssertEqual(json.value(forKeyPath: "archived") as? Bool, false) + XCTAssertEqual(json.value(forKeyPath: "favorite") as? Bool, true) + } + } +} diff --git a/mobile/ios/ReadingListTests/ReadingListStorageTestCase.swift b/mobile/ios/ReadingListTests/ReadingListStorageTestCase.swift new file mode 100644 index 0000000000..507f91ecdf --- /dev/null +++ b/mobile/ios/ReadingListTests/ReadingListStorageTestCase.swift @@ -0,0 +1,195 @@ +/* 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/. */ + +@testable import ReadingList +import Foundation +import Shared + +import XCTest + +class ReadingListStorageTestCase: XCTestCase { + var storage: ReadingListStorage! + + override func setUp() { + let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + if FileManager.default.fileExists(atPath: "\(path)/ReadingList.db") { + do { + try FileManager.default.removeItem(atPath: "\(path)/ReadingList.db") + } catch _ { + XCTFail("Cannot remove old \(path)/ReadingList.db") + } + } + storage = ReadingListSQLStorage(path: "\(path)/ReadingList.db") + } + + func testCreateRecord() { + let result = storage.createRecordWithURL("http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance", title: "Analyzing Intel Core M Performance: How 5Y10 can beat 5Y71 & the OEMs' Dilemma", addedBy: "Stefan's iPhone") + switch result { + case .failure(let error): + XCTFail(error.description) + case .success(let result): + XCTAssertEqual(result.value.url, "http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance") + XCTAssertEqual(result.value.title, "Analyzing Intel Core M Performance: How 5Y10 can beat 5Y71 & the OEMs' Dilemma") + XCTAssertEqual(result.value.addedBy, "Stefan's iPhone") + XCTAssertEqual(result.value.unread, true) + XCTAssertEqual(result.value.archived, false) + XCTAssertEqual(result.value.favorite, false) + } + } + + func testGetRecordWithURL() { + let result1 = storage.createRecordWithURL("http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance", title: "Analyzing Intel Core M Performance: How 5Y10 can beat 5Y71 & the OEMs' Dilemma", addedBy: "Stefan's iPhone") + switch result1 { + case .failure(let error): + XCTFail(error.description) + case .success( _): + break + } + + let result2 = storage.getRecordWithURL("http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance") + switch result2 { + case .failure(let error): + XCTFail(error.description) + case .success( _): + XCTAssert(result1.successValue == result2.successValue!) + } + } + + func testGetUnreadRecords() { + // Create 3 records, mark the 2nd as read. + let _ = createRecordWithURL("http://localhost/article1", title: "Test 1", addedBy: "Stefan's iPhone") + let createResult2 = createRecordWithURL("http://localhost/article2", title: "Test 2", addedBy: "Stefan's iPhone") + let _ = createRecordWithURL("http://localhost/article3", title: "Test 3", addedBy: "Stefan's iPhone") + if let record = createResult2.successValue { + let _ = updateRecord(record, unread: false) + } + + // Get all unread records, make sure we only get the first and last + let getUnreadResult = storage.getUnreadRecords() + if let records = getUnreadResult.successValue { + XCTAssertEqual(2, records.count) + for record in records { + XCTAssert(record.title == "Test 1" || record.title == "Test 3") + XCTAssertEqual(record.unread, true) + } + } + } + + func testGetAllRecords() { + let _ = createRecordWithURL("http://localhost/article1", title: "Test 1", addedBy: "Stefan's iPhone") + let createResult2 = createRecordWithURL("http://localhost/article2", title: "Test 2", addedBy: "Stefan's iPhone") + let _ = createRecordWithURL("http://localhost/article3", title: "Test 3", addedBy: "Stefan's iPhone") + if let record = createResult2.successValue { + let _ = updateRecord(record, unread: false) + } + + let getAllResult = storage.getAllRecords() + if let records = getAllResult.successValue { + XCTAssertEqual(3, records.count) + } + } + + func testGetNewRecords() { + let _ = createRecordWithURL("http://localhost/article1", title: "Test 1", addedBy: "Stefan's iPhone") + let _ = createRecordWithURL("http://localhost/article2", title: "Test 2", addedBy: "Stefan's iPhone") + let _ = createRecordWithURL("http://localhost/article3", title: "Test 3", addedBy: "Stefan's iPhone") + let getAllResult = getAllRecords() + if let records = getAllResult.successValue { + XCTAssertEqual(3, records.count) + } + // TODO When we are able to create records coming from the server, we can extend this test to see if we query correctly + } + + func testDeleteRecord() { + let result1 = storage.createRecordWithURL("http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance", title: "Analyzing Intel Core M Performance: How 5Y10 can beat 5Y71 & the OEMs' Dilemma", addedBy: "Stefan's iPhone") + switch result1 { + case .failure(let error): + XCTFail(error.description) + case .success(_): + break + } + + let result2 = storage.deleteRecord(result1.successValue!) + switch result2 { + case .failure(let error): + XCTFail(error.description) + case .success: + break + } + + let result3 = storage.getRecordWithURL("http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance") + switch result3 { + case .failure(let error): + XCTFail(error.description) + case .success(let result): + XCTAssert(result.value == nil) + } + } + + func testDeleteAllRecords() { + let _ = createRecordWithURL("http://localhost/article1", title: "Test 1", addedBy: "Stefan's iPhone") + let _ = createRecordWithURL("http://localhost/article2", title: "Test 2", addedBy: "Stefan's iPhone") + let _ = createRecordWithURL("http://localhost/article3", title: "Test 3", addedBy: "Stefan's iPhone") + + let getAllResult1 = storage.getAllRecords() + if let records = getAllResult1.successValue { + XCTAssertEqual(3, records.count) + } + + let _ = deleteAllRecords() + + let getAllResult2 = getAllRecords() + if let records = getAllResult2.successValue { + XCTAssertEqual(0, records.count) + } + } + + func testUpdateRecord() { + let result = createRecordWithURL("http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance", title: "Analyzing Intel Core M Performance: How 5Y10 can beat 5Y71 & the OEMs' Dilemma", addedBy: "Stefan's iPhone") + if let record = result.successValue { + XCTAssertEqual(record.url, "http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance") + XCTAssertEqual(record.title, "Analyzing Intel Core M Performance: How 5Y10 can beat 5Y71 & the OEMs' Dilemma") + XCTAssertEqual(record.addedBy, "Stefan's iPhone") + XCTAssertEqual(record.unread, true) + XCTAssertEqual(record.archived, false) + XCTAssertEqual(record.favorite, false) + + let result = updateRecord(record, unread: false) + if let record = result.successValue! { + XCTAssertEqual(record.url, "http://www.anandtech.com/show/9117/analyzing-intel-core-m-performance") + XCTAssertEqual(record.title, "Analyzing Intel Core M Performance: How 5Y10 can beat 5Y71 & the OEMs' Dilemma") + XCTAssertEqual(record.addedBy, "Stefan's iPhone") + XCTAssertEqual(record.unread, false) + XCTAssertEqual(record.archived, false) + XCTAssertEqual(record.favorite, false) + } + } + } + + // Helpers that croak if the storage call was not successful + + func createRecordWithURL(_ url: String, title: String, addedBy: String) -> Maybe { + let result = storage.createRecordWithURL(url, title: title, addedBy: addedBy) + XCTAssertTrue(result.isSuccess) + return result + } + + func deleteAllRecords() -> Maybe { + let result = storage.deleteAllRecords() + XCTAssertTrue(result.isSuccess) + return result + } + + func getAllRecords() -> Maybe<[ReadingListClientRecord]> { + let result = storage.getAllRecords() + XCTAssertTrue(result.isSuccess) + return result + } + + func updateRecord(_ record: ReadingListClientRecord, unread: Bool) -> Maybe { + let result = storage.updateRecord(record, unread: unread) + XCTAssertTrue(result.isSuccess) + return result + } +} diff --git a/mobile/ios/Shared/Accessibility.swift b/mobile/ios/Shared/Accessibility.swift new file mode 100644 index 0000000000..8ee70a12fb --- /dev/null +++ b/mobile/ios/Shared/Accessibility.swift @@ -0,0 +1,41 @@ +/* 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/. */ + +import UIKit + +public protocol AccessibilityActionsSource: class { + func accessibilityCustomActionsForView(_ view: UIView) -> [UIAccessibilityCustomAction]? +} + +open class AccessibleAction { + open let name: String + open let handler: () -> Bool + + public init(name: String, handler: @escaping () -> Bool) { + self.name = name + self.handler = handler + } +} + +extension AccessibleAction { // UIAccessibilityCustomAction + @objc private func SELperformAccessibilityAction() -> Bool { + return handler() + } + + public var accessibilityCustomAction: UIAccessibilityCustomAction { + return UIAccessibilityCustomAction(name: name, target: self, selector: #selector(AccessibleAction.SELperformAccessibilityAction)) + } +} + +extension AccessibleAction { // UIAlertAction + private var alertActionHandler: (UIAlertAction!) -> Void { + return { (_: UIAlertAction!) -> Void in + _ = self.handler() + } + } + + public func alertAction(style: UIAlertActionStyle) -> UIAlertAction { + return UIAlertAction(title: name, style: style, handler: alertActionHandler) + } +} diff --git a/mobile/ios/Shared/AppConstants.swift b/mobile/ios/Shared/AppConstants.swift new file mode 100644 index 0000000000..495b2b51fe --- /dev/null +++ b/mobile/ios/Shared/AppConstants.swift @@ -0,0 +1,230 @@ +/* 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/. */ + +import UIKit + +public enum AppBuildChannel: String { + case release = "release" + case beta = "beta" + case developer = "developer" +} + +public enum KVOConstants: String { + case loading = "loading" + case estimatedProgress = "estimatedProgress" + case URL = "URL" + case title = "title" + case canGoBack = "canGoBack" + case canGoForward = "canGoForward" + case contentSize = "contentSize" +} + +public struct AppConstants { + public static let IsRunningTest = NSClassFromString("XCTestCase") != nil || ProcessInfo.processInfo.arguments.contains(LaunchArguments.Test) + + public static let FxAiOSClientId = "1b1a3e44c54fbb58" + + /// Build Channel. + public static let BuildChannel: AppBuildChannel = { + #if MOZ_CHANNEL_RELEASE + return AppBuildChannel.release + #elseif MOZ_CHANNEL_BETA + return AppBuildChannel.beta + #elseif MOZ_CHANNEL_FENNEC + return AppBuildChannel.developer + #endif + }() + + public static let scheme: String = { + guard let identifier = Bundle.main.bundleIdentifier else { + return "unknown" + } + + let scheme = identifier.replacingOccurrences(of: "org.mozilla.ios.", with: "") + if scheme == "FirefoxNightly.enterprise" { + return "FirefoxNightly" + } + return scheme + }() + + public static let PrefSendUsageData = "settings.sendUsageData" + + /// Whether we just mirror (false) or actively do a full bookmark merge and upload (true). + public static var shouldMergeBookmarks = false + + /// Should we try to sync (no merging) the Mobile Folder (if shouldMergeBookmarks is false). + public static let MOZ_SIMPLE_BOOKMARKS_SYNCING: Bool = { + #if MOZ_CHANNEL_RELEASE + return true + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Should we send a repair request to other clients when the bookmarks buffer validation fails. + public static let MOZ_BOOKMARKS_REPAIR_REQUEST: Bool = { + #if MOZ_CHANNEL_RELEASE + return false + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Flag indicating if we are running in Debug mode or not. + public static let isDebug: Bool = { + #if MOZ_CHANNEL_FENNEC + return true + #else + return false + #endif + }() + + /// Enables support for International Domain Names (IDN) + /// Disabled because of https://bugzilla.mozilla.org/show_bug.cgi?id=1312294 + public static let MOZ_PUNYCODE: Bool = { + #if MOZ_CHANNEL_RELEASE + return false + #elseif MOZ_CHANNEL_BETA + return false + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Enables/disables deep linking form fill for FxA + public static let MOZ_FXA_DEEP_LINK_FORM_FILL: Bool = { + #if MOZ_CHANNEL_RELEASE + return true + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Toggles reporting our ad-hoc bookmark sync ping + public static let MOZ_ADHOC_SYNC_REPORTING: Bool = { + #if MOZ_CHANNEL_RELEASE + return false + #elseif MOZ_CHANNEL_BETA + return false + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Toggles the ability to add a custom search engine + public static let MOZ_CUSTOM_SEARCH_ENGINE: Bool = { + #if MOZ_CHANNEL_RELEASE + return true + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Enables/disables push notificatuibs for FxA + public static let MOZ_FXA_PUSH: Bool = { + #if MOZ_CHANNEL_RELEASE + return true + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Toggle the feature that shows the blue 'Open copied link' banner + public static let MOZ_CLIPBOARD_BAR: Bool = { + #if MOZ_CHANNEL_RELEASE + return true + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Toggle pocket stories feature + public static let MOZ_POCKET_STORIES: Bool = { + #if MOZ_CHANNEL_RELEASE + return true + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// Toggle the use of Leanplum. + public static let MOZ_ENABLE_LEANPLUM: Bool = { + #if MOZ_CHANNEL_RELEASE + return true + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return false + #endif + }() + + /// Toggle the feature that shows updated FxA preferences cell + public static let MOZ_SHOW_FXA_AVATAR: Bool = { + #if MOZ_CHANNEL_RELEASE + return true + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return true + #endif + }() + + /// The maximum length of a URL stored by Firefox. Shared with Places on desktop. + public static let DB_URL_LENGTH_MAX = 65536 + + /// The maximum length of a page title stored by Firefox. Shared with Places on desktop. + public static let DB_TITLE_LENGTH_MAX = 4096 + + /// The maximum length of a bookmark description stored by Firefox. Shared with Places on desktop. + public static let DB_DESCRIPTION_LENGTH_MAX = 1024 + + /// Toggle FxA Leanplum A/B test for prompting push permissions + public static let MOZ_FXA_LEANPLUM_AB_PUSH_TEST: Bool = { + #if MOZ_CHANNEL_RELEASE + return false + #elseif MOZ_CHANNEL_BETA + return true + #elseif MOZ_CHANNEL_FENNEC + return true + #else + return false + #endif + }() +} diff --git a/mobile/ios/Shared/AppInfo.swift b/mobile/ios/Shared/AppInfo.swift new file mode 100644 index 0000000000..8dd7ef0dda --- /dev/null +++ b/mobile/ios/Shared/AppInfo.swift @@ -0,0 +1,86 @@ +/* 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/. */ + +import Foundation + +open class AppInfo { + /// Return the main application bundle. If this is called from an extension, the containing app bundle is returned. + open static var applicationBundle: Bundle { + let bundle = Bundle.main + switch bundle.bundleURL.pathExtension { + case "app": + return bundle + case "appex": + // .../Client.app/PlugIns/SendTo.appex + return Bundle(url: bundle.bundleURL.deletingLastPathComponent().deletingLastPathComponent())! + default: + fatalError("Unable to get application Bundle (Bundle.main.bundlePath=\(bundle.bundlePath))") + } + } + + open static var displayName: String { + return applicationBundle.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String + } + + open static var appVersion: String { + return applicationBundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String + } + + open static var buildNumber: String { + return applicationBundle.object(forInfoDictionaryKey: String(kCFBundleVersionKey)) as! String + } + + open static var majorAppVersion: String { + return appVersion.components(separatedBy: ".").first! + } + + /// Return the shared container identifier (also known as the app group) to be used with for example background + /// http requests. It is the base bundle identifier with a "group." prefix. + open static var sharedContainerIdentifier: String { + var bundleIdentifier = baseBundleIdentifier + if bundleIdentifier == "org.mozilla.ios.FennecEnterprise" { + // Bug 1373726 - Base bundle identifier incorrectly generated for Nightly builds + // This can be removed when we are able to fix the app group in the developer portal + bundleIdentifier = "org.mozilla.ios.Fennec.enterprise" + } + return "group." + bundleIdentifier + } + + /// Return the keychain access group. + open static func keychainAccessGroupWithPrefix(_ prefix: String) -> String { + var bundleIdentifier = baseBundleIdentifier + if bundleIdentifier == "org.mozilla.ios.FennecEnterprise" { + // Bug 1373726 - Base bundle identifier incorrectly generated for Nightly builds + // This can be removed when we are able to fix the app group in the developer portal + bundleIdentifier = "org.mozilla.ios.Fennec.enterprise" + } + return prefix + "." + bundleIdentifier + } + + /// Return the base bundle identifier. + /// + /// This function is smart enough to find out if it is being called from an extension or the main application. In + /// case of the former, it will chop off the extension identifier from the bundle since that is a suffix not part + /// of the *base* bundle identifier. + open static var baseBundleIdentifier: String { + let bundle = Bundle.main + let packageType = bundle.object(forInfoDictionaryKey: "CFBundlePackageType") as! String + let baseBundleIdentifier = bundle.bundleIdentifier! + if packageType == "XPC!" { + let components = baseBundleIdentifier.components(separatedBy: ".") + return components[0..(_ initialValue: T, combine: @escaping (T, U) -> Deferred>) -> AsyncReducer { + return AsyncReducer(initialValue: initialValue, combine: combine) +} + +/** + * A appendable, async `reduce`. + * + * The reducer starts empty. New items need to be `append`ed. + * + * The constructor takes an `initialValue`, a `dispatch_queue_t`, and a `combine` function. + * + * The reduced value can be accessed via the `reducer.terminal` `Deferred>`, which is + * run once all items have been combined. + * + * The terminal will never be filled if no items have been appended. + * + * Once the terminal has been filled, no more items can be appended, and `append` methods will error. + */ +open class AsyncReducer { + // T is the accumulator. U is the input value. The returned T is the new accumulated value. + public typealias Combine = (T, U) -> Deferred> + fileprivate let lock = NSRecursiveLock() + + private let dispatchQueue: DispatchQueue + private let combine: Combine + + private let initialValueDeferred: Deferred> + open let terminal: Deferred> = Deferred() + + private var queuedItems: [U] = [] + + private var isStarted: Bool = false + + /** + * Has this task queue finished? + * Once the task queue has finished, it cannot have more tasks appended. + */ + open var isFilled: Bool { + lock.lock() + defer { lock.unlock() } + return terminal.isFilled + } + + public convenience init(initialValue: T, queue: DispatchQueue = DefaultDispatchQueue, combine: @escaping Combine) { + self.init(initialValue: deferMaybe(initialValue), queue: queue, combine: combine) + } + + public init(initialValue: Deferred>, queue: DispatchQueue = DefaultDispatchQueue, combine: @escaping Combine) { + self.dispatchQueue = queue + self.combine = combine + self.initialValueDeferred = initialValue + } + + // This is always protected by a lock, so we don't need to + // take another one. + fileprivate func ensureStarted() { + if self.isStarted { + return + } + + func queueNext(_ deferredValue: Deferred>) { + deferredValue.uponQueue(dispatchQueue, block: continueMaybe) + } + + func nextItem() -> U? { + // Because popFirst is only available on array slices. + // removeFirst is fine for range-replaceable collections. + return queuedItems.isEmpty ? nil : queuedItems.removeFirst() + } + + func continueMaybe(_ res: Maybe) { + lock.lock() + defer { lock.unlock() } + + if res.isFailure { + self.queuedItems.removeAll() + self.terminal.fill(Maybe(failure: res.failureValue!)) + return + } + + let accumulator = res.successValue! + + guard let item = nextItem() else { + self.terminal.fill(Maybe(success: accumulator)) + return + } + + let combineItem = deferDispatchAsync(dispatchQueue) { _ in + return self.combine(accumulator, item) + } + + queueNext(combineItem) + } + + queueNext(self.initialValueDeferred) + self.isStarted = true + } + + /** + * Append one or more tasks onto the end of the queue. + * + * @throws AlreadyFilled if the queue has finished already. + */ + open func append(_ items: U...) throws -> Deferred> { + return try append(items) + } + + /** + * Append a list of tasks onto the end of the queue. + * + * @throws AlreadyFilled if the queue has already finished. + */ + open func append(_ items: [U]) throws -> Deferred> { + lock.lock() + defer { lock.unlock() } + + if terminal.isFilled { + throw ReducerError.alreadyFilled + } + + queuedItems.append(contentsOf: items) + ensureStarted() + + return terminal + } +} + +enum ReducerError: Error { + case alreadyFilled +} diff --git a/mobile/ios/Shared/AuthenticationKeychainInfo.swift b/mobile/ios/Shared/AuthenticationKeychainInfo.swift new file mode 100644 index 0000000000..3bbc145262 --- /dev/null +++ b/mobile/ios/Shared/AuthenticationKeychainInfo.swift @@ -0,0 +1,157 @@ +/* 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/. */ + +import Foundation +import SwiftKeychainWrapper + +public let KeychainKeyAuthenticationInfo = "authenticationInfo" +public let AllowedPasscodeFailedAttempts = 3 + +// Passcode intervals with rawValue in seconds. +public enum PasscodeInterval: Int { + case immediately = 2 + case oneMinute = 60 + case fiveMinutes = 300 + case tenMinutes = 600 + case fifteenMinutes = 900 + case oneHour = 3600 +} + +// MARK: - Helper methods for accessing Authentication information from the Keychain +public extension KeychainWrapper { + func authenticationInfo() -> AuthenticationKeychainInfo? { + NSKeyedUnarchiver.setClass(AuthenticationKeychainInfo.self, forClassName: "AuthenticationKeychainInfo") + return object(forKey: KeychainKeyAuthenticationInfo) as? AuthenticationKeychainInfo + } + + func setAuthenticationInfo(_ info: AuthenticationKeychainInfo?) { + NSKeyedArchiver.setClassName("AuthenticationKeychainInfo", for: AuthenticationKeychainInfo.self) + if let info = info { + set(info, forKey: KeychainKeyAuthenticationInfo) + } else { + removeObject(forKey: KeychainKeyAuthenticationInfo) + } + } +} + +open class AuthenticationKeychainInfo: NSObject, NSCoding { + fileprivate(set) open var lastPasscodeValidationInterval: TimeInterval? + fileprivate(set) open var passcode: String? + fileprivate(set) open var requiredPasscodeInterval: PasscodeInterval? + fileprivate(set) open var lockOutInterval: TimeInterval? + fileprivate(set) open var failedAttempts: Int + open var useTouchID: Bool + + // Timeout period before user can retry entering passcodes + open var lockTimeInterval: TimeInterval = 15 * 60 + + public init(passcode: String) { + self.passcode = passcode + self.requiredPasscodeInterval = .immediately + self.failedAttempts = 0 + self.useTouchID = false + } + + open func encode(with aCoder: NSCoder) { + if let lastPasscodeValidationInterval = lastPasscodeValidationInterval { + let interval = NSNumber(value: lastPasscodeValidationInterval as Double) + aCoder.encode(interval, forKey: "lastPasscodeValidationInterval") + } + + if let lockOutInterval = lockOutInterval, isLocked() { + let interval = NSNumber(value: lockOutInterval as Double) + aCoder.encode(interval, forKey: "lockOutInterval") + } + + aCoder.encode(passcode, forKey: "passcode") + aCoder.encode(requiredPasscodeInterval?.rawValue, forKey: "requiredPasscodeInterval") + aCoder.encode(failedAttempts, forKey: "failedAttempts") + aCoder.encode(useTouchID, forKey: "useTouchID") + } + + public required init?(coder aDecoder: NSCoder) { + self.lastPasscodeValidationInterval = aDecoder.decodeAsDouble(forKey: "lastPasscodeValidationInterval") + if let lockOutInterval = aDecoder.decodeObject(forKey: "lockOutInterval") as? NSNumber { + self.lockOutInterval = lockOutInterval.doubleValue + } + self.passcode = aDecoder.decodeObject(forKey: "passcode") as? String + self.failedAttempts = aDecoder.decodeAsInt(forKey: "failedAttempts") + self.useTouchID = aDecoder.decodeAsBool(forKey: "useTouchID") + if var interval = aDecoder.decodeObject(forKey: "requiredPasscodeInterval") as? NSNumber { + // We have updated the immediate lockout value to 2 from 0 due to timing issues with systemUptime() + interval = interval == 0 ? 2 : interval + self.requiredPasscodeInterval = PasscodeInterval(rawValue: interval.intValue) + } + } +} + +// MARK: - API +public extension AuthenticationKeychainInfo { + private func resetLockoutState() { + self.failedAttempts = 0 + self.lockOutInterval = nil + } + + func updatePasscode(_ passcode: String) { + self.passcode = passcode + self.lastPasscodeValidationInterval = nil + } + + func updateRequiredPasscodeInterval(_ interval: PasscodeInterval) { + self.requiredPasscodeInterval = interval + self.lastPasscodeValidationInterval = nil + } + + func recordValidation() { + // Save the timestamp to remember the last time we successfully + // validated and clear out the failed attempts counter. + self.lastPasscodeValidationInterval = SystemUtils.systemUptime() + resetLockoutState() + } + + func lockOutUser() { + self.lockOutInterval = SystemUtils.systemUptime() + } + + func recordFailedAttempt() { + if self.failedAttempts >= AllowedPasscodeFailedAttempts { + //This is a failed attempt after a lockout period. Reset the lockout state + //This prevents failedAttemps from being higher than 3 + self.resetLockoutState() + } + self.failedAttempts += 1 + } + + func isLocked() -> Bool { + guard let lockOutInterval = self.lockOutInterval else { + return false + } + + if SystemUtils.systemUptime() < lockOutInterval { + // Unlock and require passcode input + resetLockoutState() + return false + } + return (SystemUtils.systemUptime() - (self.lockOutInterval ?? 0)) < lockTimeInterval + } + + func requiresValidation() -> Bool { + // If there isn't a passcode, don't need validation. + guard let _ = passcode else { + return false + } + + // Need to make sure we've validated in the past. If not, its a definite yes. + guard let lastValidationInterval = lastPasscodeValidationInterval, + let requireInterval = requiredPasscodeInterval + else { + return true + } + + // We've authenticated before so lets see how long since. If the uptime is less than the last validation stamp, + // we probably restarted which means we should require validation. + return SystemUtils.systemUptime() - lastValidationInterval > Double(requireInterval.rawValue) || + SystemUtils.systemUptime() < lastValidationInterval + } +} diff --git a/mobile/ios/Shared/Bytes.swift b/mobile/ios/Shared/Bytes.swift new file mode 100644 index 0000000000..b1e7c3f1e3 --- /dev/null +++ b/mobile/ios/Shared/Bytes.swift @@ -0,0 +1,49 @@ +/* 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/. */ + +import Foundation + +public typealias GUID = String + +/** + * Utilities for futzing with bytes and such. + */ +open class Bytes { + open class func generateRandomBytes(_ len: UInt) -> Data { + let len = Int(len) + var data = Data(count: len) + data.withUnsafeMutableBytes { (p: UnsafeMutablePointer) in + if (SecRandomCopyBytes(kSecRandomDefault, len, p) != errSecSuccess) { + fatalError("Random byte generation failed.") + } + } + return data + } + + open class func generateGUID() -> GUID { + // Turns the standard NSData encoding into the URL-safe variant that Sync expects. + return generateRandomBytes(9) + .base64EncodedString(options: NSData.Base64EncodingOptions()) + .replacingOccurrences(of: "/", with: "_", options: NSString.CompareOptions(), range: nil) + .replacingOccurrences(of: "+", with: "-", options: NSString.CompareOptions(), range: nil) + } + + open class func decodeBase64(_ b64: String) -> Data? { + return Data(base64Encoded: b64, + options: NSData.Base64DecodingOptions()) + } + + /** + * Turn a string of base64 characters into an NSData *without decoding*. + * This is to allow HMAC to be computed of the raw base64 string. + */ + open class func dataFromBase64(_ b64: String) -> Data? { + return b64.data(using: String.Encoding.ascii, allowLossyConversion: false) + } + + func fromHex(_ str: String) -> Data { + // TODO + return Data() + } +} diff --git a/mobile/ios/Shared/Cancellable.swift b/mobile/ios/Shared/Cancellable.swift new file mode 100644 index 0000000000..6cb1e240f1 --- /dev/null +++ b/mobile/ios/Shared/Cancellable.swift @@ -0,0 +1,9 @@ +/* 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/. */ + +public protocol Cancellable: class { + func cancel() + var cancelled: Bool { get } + var running: Bool { get set } +} diff --git a/mobile/ios/Shared/CrashSimulator.h b/mobile/ios/Shared/CrashSimulator.h new file mode 100644 index 0000000000..3258c7356b --- /dev/null +++ b/mobile/ios/Shared/CrashSimulator.h @@ -0,0 +1,11 @@ +/* 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/. */ + +#import + +@interface CrashSimulator : NSObject + ++ (void)forceCrash; + +@end diff --git a/mobile/ios/Shared/CrashSimulator.m b/mobile/ios/Shared/CrashSimulator.m new file mode 100644 index 0000000000..ce182ac09e --- /dev/null +++ b/mobile/ios/Shared/CrashSimulator.m @@ -0,0 +1,14 @@ +/* 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/. */ + +#import "CrashSimulator.h" + +@implementation CrashSimulator + ++ (void)forceCrash +{ + @throw [[NSException alloc] initWithName:@"Simulated Crash" reason:@"This is a simulated crash." userInfo:nil]; +} + +@end diff --git a/mobile/ios/Shared/DeferredUtils.swift b/mobile/ios/Shared/DeferredUtils.swift new file mode 100644 index 0000000000..e96d0e3168 --- /dev/null +++ b/mobile/ios/Shared/DeferredUtils.swift @@ -0,0 +1,199 @@ +/* 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/. */ + +import Deferred +// Haskell, baby. + +// Monadic bind/flatMap operator for Deferred. +precedencegroup MonadicBindPrecedence { + associativity: left + higherThan: MonadicDoPrecedence + lowerThan: BitwiseShiftPrecedence +} + +precedencegroup MonadicDoPrecedence { + associativity: left + higherThan: MultiplicationPrecedence +} + +infix operator >>== : MonadicBindPrecedence +infix operator >>> : MonadicDoPrecedence + +@discardableResult public func >>== (x: Deferred>, f: @escaping (T) -> Deferred>) -> Deferred> { + return chainDeferred(x, f: f) +} + +// A termination case. +public func >>== (x: Deferred>, f: @escaping (T) -> Void) { + return x.upon { result in + if let v = result.successValue { + f(v) + } + } +} + +// Monadic `do` for Deferred. +@discardableResult public func >>> (x: Deferred>, f: @escaping () -> Deferred>) -> Deferred> { + return x.bind { res in + if res.isSuccess { + return f() + } + return deferMaybe(res.failureValue!) + } +} + +// Another termination case. +public func >>> (x: Deferred>, f: @escaping () -> Void) { + return x.upon { res in + if res.isSuccess { + f() + } + } +} + +/** +* Returns a thunk that return a Deferred that resolves to the provided value. +*/ +public func always(_ t: T) -> () -> Deferred> { + return { deferMaybe(t) } +} + +public func deferMaybe(_ s: T) -> Deferred> { + return Deferred(value: Maybe(success: s)) +} + +public func deferMaybe(_ e: MaybeErrorType) -> Deferred> { + return Deferred(value: Maybe(failure: e)) +} + +public typealias Success = Deferred> + +@discardableResult public func succeed() -> Success { + return deferMaybe(()) +} + +/** + * Return a single Deferred that represents the sequential chaining + * of f over the provided items. + */ +public func walk(_ items: [T], f: @escaping (T) -> Success) -> Success { + return items.reduce(succeed()) { success, item -> Success in + success >>> { f(item) } + } +} + +/** + * Like `all`, but thanks to its taking thunks as input, each result is + * generated in strict sequence. Fails immediately if any result is failure. + */ +public func accumulate(_ thunks: [() -> Deferred>]) -> Deferred> { + if thunks.isEmpty { + return deferMaybe([]) + } + + let combined = Deferred>() + var results: [T] = [] + results.reserveCapacity(thunks.count) + + var onValue: ((T) -> Void)! + var onResult: ((Maybe) -> Void)! + + // onValue and onResult both hold references to each other niling them out before exiting breaks a reference cycle + // We also cannot use unowned here because the thunks are not class types. + onValue = { t in + results.append(t) + if results.count == thunks.count { + onResult = nil + combined.fill(Maybe(success: results)) + } else { + thunks[results.count]().upon(onResult) + } + } + + onResult = { r in + if r.isFailure { + onValue = nil + combined.fill(Maybe(failure: r.failureValue!)) + return + } + onValue(r.successValue!) + } + + thunks[0]().upon(onResult) + + return combined +} + +/** + * Take a function and turn it into a side-effect that can appear + * in a chain of async operations without producing its own value. + */ +public func effect(_ f: @escaping (T) -> U) -> (T) -> Deferred> { + return { t in + _ = f(t) + return deferMaybe(t) + } +} + +/** + * Return a single Deferred that represents the sequential chaining of + * f over the provided items, with the return value chained through. + */ +public func walk(_ items: S, start: Deferred>, f: @escaping (T, U) -> Deferred>) -> Deferred> where S.Iterator.Element == T { + let fs = items.map { item in + return { val in + f(item, val) + } + } + return fs.reduce(start, >>==) +} + +/** + * Like `all`, but doesn't accrue individual values. + */ +extension Array where Element: Success { + public func allSucceed() -> Success { + return all(self).bind { results -> Success in + if let failure = results.find({ $0.isFailure }) { + return deferMaybe(failure.failureValue!) + } + + return succeed() + } + } +} + +public func chainDeferred(_ a: Deferred>, f: @escaping (T) -> Deferred>) -> Deferred> { + return a.bind { res in + if let v = res.successValue { + return f(v) + } + return Deferred(value: Maybe(failure: res.failureValue!)) + } +} + +public func chainResult(_ a: Deferred>, f: @escaping (T) -> Maybe) -> Deferred> { + return a.map { res in + if let v = res.successValue { + return f(v) + } + return Maybe(failure: res.failureValue!) + } +} + +public func chain(_ a: Deferred>, f: @escaping (T) -> U) -> Deferred> { + return chainResult(a, f: { Maybe(success: f($0)) }) +} + +/// Defer-ifies a block to an async dispatch queue. +public func deferDispatchAsync(_ queue: DispatchQueue, f: @escaping () -> Deferred>) -> Deferred> { + let deferred = Deferred>() + queue.async(execute: { + f().upon { result in + deferred.fill(result) + } + }) + + return deferred +} diff --git a/mobile/ios/Shared/DeviceInfo.swift b/mobile/ios/Shared/DeviceInfo.swift new file mode 100644 index 0000000000..4306c20245 --- /dev/null +++ b/mobile/ios/Shared/DeviceInfo.swift @@ -0,0 +1,72 @@ +/* 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/. */ + +import UIKit + +open class DeviceInfo { + // List of device names that don't support advanced visual settings + static let lowGraphicsQualityModels = ["iPad", "iPad1,1", "iPhone1,1", "iPhone1,2", "iPhone2,1", "iPhone3,1", "iPhone3,2", "iPhone3,3", "iPod1,1", "iPod2,1", "iPod2,2", "iPod3,1", "iPod4,1", "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4", "iPad3,1", "iPad3,2", "iPad3,3"] + + open static var specificModelName: String { + var systemInfo = utsname() + uname(&systemInfo) + + let machine = systemInfo.machine + let mirror = Mirror(reflecting: machine) + var identifier = "" + + // Parses the string for the model name via NSUTF8StringEncoding, refer to + // http://stackoverflow.com/questions/26028918/ios-how-to-determine-iphone-model-in-swift + for child in mirror.children.enumerated() { + if let value = child.1.value as? Int8, value != 0 { + identifier.append(String(UnicodeScalar(UInt8(value)))) + } + } + return identifier + } + + /// Return the client name, which can be either "Fennec on Stefan's iPod" or simply "Stefan's iPod" if the application display name cannot be obtained. + open class func defaultClientName() -> String { + let format = NSLocalizedString("%@ on %@", tableName: "Shared", comment: "A brief descriptive name for this app on this device, used for Send Tab and Synced Tabs. The first argument is the app name. The second argument is the device name.") + return String(format: format, AppInfo.displayName, UIDevice.current.name) + } + + open class func clientIdentifier(_ prefs: Prefs) -> String { + if let id = prefs.stringForKey("clientIdentifier") { + return id + } + let id = UUID().uuidString + prefs.setString(id, forKey: "clientIdentifier") + return id + } + + open class func deviceModel() -> String { + return UIDevice.current.model + } + + open class func isSimulator() -> Bool { + return ProcessInfo.processInfo.environment["SIMULATOR_ROOT"] != nil + } + + open class func isBlurSupported() -> Bool { + // We've tried multiple ways to make this change visible on simulators, but we + // haven't found a solution that worked: + // 1. http://stackoverflow.com/questions/21603475/how-can-i-detect-if-the-iphone-my-app-is-on-is-going-to-use-a-simple-transparen + // 2. https://gist.github.com/conradev/8655650 + // Thus, testing has to take place on actual devices. + return !lowGraphicsQualityModels.contains(specificModelName) + } + + open class func hasConnectivity() -> Bool { + let status = Reach().connectionStatus() + switch status { + case .online(.wwan): + return true + case .online(.wiFi): + return true + default: + return false + } + } +} diff --git a/mobile/ios/Shared/Extensions/ArrayExtensions.swift b/mobile/ios/Shared/Extensions/ArrayExtensions.swift new file mode 100644 index 0000000000..06447d4aa9 --- /dev/null +++ b/mobile/ios/Shared/Extensions/ArrayExtensions.swift @@ -0,0 +1,70 @@ +/* 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/. */ + +import Foundation + +public extension Array where Element: Comparable { + func sameElements(_ arr: [Element]) -> Bool { + guard self.count == arr.count else { return false } + let sorted = self.sorted(by: <) + let arrSorted = arr.sorted(by: <) + for elements in sorted.zip(arrSorted) where elements.0 != elements.1 { + return false + } + return true + } +} + +public extension Array { + + func find(_ f: (Iterator.Element) -> Bool) -> Iterator.Element? { + for x in self { + if f(x) { + return x + } + } + return nil + } + + func contains(_ x: Element, f: (Element, Element) -> Bool) -> Bool { + for y in self { + if f(x, y) { + return true + } + } + return false + } + + // Performs a union operator using the result of f(Element) as the value to base uniqueness on. + func union(_ arr: [Element], f: ((Element) -> T)) -> [Element] { + let result = self + arr + return result.unique(f) + } + + // Returns unique values in an array using the result of f() + func unique(_ f: ((Element) -> T)) -> [Element] { + var map: [T: Element] = [T: Element]() + return self.flatMap { a in + let t = f(a) + if map[t] == nil { + map[t] = a + return a + } else { + return nil + } + } + } + +} + +public extension Sequence { + func every(_ f: (Self.Iterator.Element) -> Bool) -> Bool { + for x in self { + if !f(x) { + return false + } + } + return true + } +} diff --git a/mobile/ios/Shared/Extensions/DataExtensions.swift b/mobile/ios/Shared/Extensions/DataExtensions.swift new file mode 100644 index 0000000000..2293ddbc40 --- /dev/null +++ b/mobile/ios/Shared/Extensions/DataExtensions.swift @@ -0,0 +1,19 @@ +/* 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/. */ + +import Foundation + +public extension Data { + public mutating func appendBytes(fromData data: Data) { + var bytes = [UInt8](repeating: 0, count: data.count) + data.copyBytes(to: &bytes, count: data.count) + self.append(bytes, count: bytes.count) + } + + public func getBytes() -> [UInt8] { + var bytes = [UInt8](repeating: 0, count: self.count) + self.copyBytes(to: &bytes, count: self.count) + return bytes + } +} diff --git a/mobile/ios/Shared/Extensions/DictionaryExtensions.swift b/mobile/ios/Shared/Extensions/DictionaryExtensions.swift new file mode 100644 index 0000000000..3fd10ae3c7 --- /dev/null +++ b/mobile/ios/Shared/Extensions/DictionaryExtensions.swift @@ -0,0 +1,9 @@ +/* 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/. */ + +extension Dictionary { + public mutating func merge(with dictionary: Dictionary) { + dictionary.forEach { updateValue($1, forKey: $0) } + } +} diff --git a/mobile/ios/Shared/Extensions/HashExtensions.swift b/mobile/ios/Shared/Extensions/HashExtensions.swift new file mode 100644 index 0000000000..bfe2da4d3e --- /dev/null +++ b/mobile/ios/Shared/Extensions/HashExtensions.swift @@ -0,0 +1,74 @@ +/* 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/. */ + +import Foundation + +extension Data { + public var sha1: Data { + let len = Int(CC_SHA1_DIGEST_LENGTH) + let digest = UnsafeMutablePointer.allocate(capacity: len) + CC_SHA1((self as NSData).bytes, CC_LONG(self.count), digest) + return Data(bytes: UnsafePointer(digest), count: len) + } + + public var sha256: Data { + let len = Int(CC_SHA256_DIGEST_LENGTH) + let digest = UnsafeMutablePointer.allocate(capacity: len) + CC_SHA256((self as NSData).bytes, CC_LONG(self.count), digest) + return Data(bytes: UnsafePointer(digest), count: len) + } +} + +extension String { + public var sha1: Data { + let data = self.data(using: String.Encoding.utf8)! + return data.sha1 + } + + public var sha256: Data { + let data = self.data(using: String.Encoding.utf8)! + return data.sha256 + } +} + +extension Data { + public func hmacSha256WithKey(_ key: Data) -> Data { + let len = Int(CC_SHA256_DIGEST_LENGTH) + + let digest = UnsafeMutablePointer.allocate(capacity: len) + CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), + (key as NSData).bytes, Int(key.count), + (self as NSData).bytes, Int(self.count), + digest) + return Data(bytes: UnsafePointer(digest), count: len) + } +} + +extension String { + public var utf8EncodedData: Data { + return self.data(using: String.Encoding.utf8, allowLossyConversion: false)! + } +} + +extension Data { + public var utf8EncodedString: String? { + return NSString(data: self, encoding: String.Encoding.utf8.rawValue) as String? + } +} + +extension Data { + public func xoredWith(_ other: Data) -> Data? { + if self.count != other.count { + return nil + } + var xoredBytes = [UInt8](repeating: 0, count: self.count) + let selfBytes = (self as NSData).bytes.bindMemory(to: UInt8.self, capacity: self.count) + let otherBytes = (other as NSData).bytes.bindMemory(to: UInt8.self, capacity: other.count) + for i in 0..(xoredBytes), count: self.count) + } + +} diff --git a/mobile/ios/Shared/Extensions/HexExtensions.swift b/mobile/ios/Shared/Extensions/HexExtensions.swift new file mode 100644 index 0000000000..5900ec58e9 --- /dev/null +++ b/mobile/ios/Shared/Extensions/HexExtensions.swift @@ -0,0 +1,70 @@ +/* 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/. */ + +import Foundation + +extension String { + public var hexDecodedData: Data { + // Convert to a CString and make sure it has an even number of characters (terminating 0 is included, so we + // check for uneven!) + guard let cString = self.cString(using: String.Encoding.ascii), (cString.count % 2) == 1 else { + return Data() + } + + var result = Data(capacity: (cString.count - 1) / 2) + for i in stride(from: 0, to: (cString.count - 1), by: 2) { + guard let l = hexCharToByte(cString[i]), let r = hexCharToByte(cString[i+1]) else { + return Data() + } + var value: UInt8 = (l << 4) | r + result.append(&value, count: MemoryLayout.size(ofValue: value)) + } + return result + } + + private func hexCharToByte(_ c: CChar) -> UInt8? { + if c >= 48 && c <= 57 { // 0 - 9 + return UInt8(c - 48) + } + if c >= 97 && c <= 102 { // a - f + return UInt8(10) + UInt8(c - 97) + } + if c >= 65 && c <= 70 { // A - F + return UInt8(10) + UInt8(c - 65) + } + return nil + } +} + +private let HexDigits: [String] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"] + +extension Data { + public var hexEncodedString: String { + var result = String() + result.reserveCapacity(count * 2) + withUnsafeBytes { (p: UnsafePointer) in + for i in 0..> 4)]) + result.append(HexDigits[Int(p[i] & 0x0f)]) + } + } + return String(result) + } + + public static func randomOfLength(_ length: UInt) -> Data? { + let length = Int(length) + var data = Data(count: length) + var result: Int32 = 0 + data.withUnsafeMutableBytes { (p: UnsafeMutablePointer) in + result = SecRandomCopyBytes(kSecRandomDefault, length, p) + } + return result == 0 ? data : nil + } +} + +extension Data { + public var base64EncodedString: String { + return self.base64EncodedString(options: NSData.Base64EncodingOptions()) + } +} diff --git a/mobile/ios/Shared/Extensions/JSONExtensions.swift b/mobile/ios/Shared/Extensions/JSONExtensions.swift new file mode 100644 index 0000000000..85c29de98f --- /dev/null +++ b/mobile/ios/Shared/Extensions/JSONExtensions.swift @@ -0,0 +1,65 @@ +/* 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/. */ + +import Foundation +import SwiftyJSON + +public extension JSON { + func isStringOrNull() -> Bool { + return self.isString() || + self.isNull() + } + + func isError() -> Bool { + return self.error != nil + } + + func isString() -> Bool { + // SwiftyJSON doesn't link values to types; it's possible for `self.type == .string` but + // `self.string` to return `nil`. Validate both. + return self.type == .string && + self.string != nil + } + + func isBool() -> Bool { + return self.type == .bool + } + + func isArray() -> Bool { + return self.type == .array + } + + func isDictionary() -> Bool { + return self.type == .dictionary + } + + // Bear in mind that for this function to work you need to set the value to NSNull: + // ``` + // var myObj = JSON(…) + // myObj["foo"] = someOptional ?? NSNull() + // ``` + // This is… easy to get wrong. + func isNull() -> Bool { + return self.type == .null + } + + func isInt() -> Bool { + return self.type == .number && self.int != nil + } + + func isNumber() -> Bool { + return self.type == .number && self.number != nil + } + + func isDouble() -> Bool { + return self.type == .number && self.double != nil + } + + // SwiftyJSON pretty prints the string value by default. Since all of our + // existing code required the string to not be pretty printed, this helper + // can be used as a shorthand for non-pretty printed strings. + func stringValue() -> String? { + return self.rawString(.utf8, options: []) + } +} diff --git a/mobile/ios/Shared/Extensions/KeychainWrapperExtensions.swift b/mobile/ios/Shared/Extensions/KeychainWrapperExtensions.swift new file mode 100644 index 0000000000..64b548940d --- /dev/null +++ b/mobile/ios/Shared/Extensions/KeychainWrapperExtensions.swift @@ -0,0 +1,62 @@ +/* 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/. */ + +import Foundation +import XCGLogger +import SwiftKeychainWrapper + +private let log = Logger.keychainLogger + +public extension KeychainWrapper { + static var sharedAppContainerKeychain: KeychainWrapper { + let baseBundleIdentifier = AppInfo.baseBundleIdentifier + let accessGroupPrefix = Bundle.main.object(forInfoDictionaryKey: "MozDevelopmentTeam") as! String + let accessGroupIdentifier = AppInfo.keychainAccessGroupWithPrefix(accessGroupPrefix) + return KeychainWrapper(serviceName: baseBundleIdentifier, accessGroup: accessGroupIdentifier) + } +} + +public extension KeychainWrapper { + func ensureStringItemAccessibility(_ accessibility: SwiftKeychainWrapper.KeychainItemAccessibility, forKey key: String) { + if self.hasValue(forKey: key) { + if self.accessibilityOfKey(key) != .afterFirstUnlock { + log.debug("updating item \(key) with \(accessibility)") + + guard let value = self.string(forKey: key) else { + log.error("failed to get item \(key)") + return + } + + if !self.removeObject(forKey: key) { + log.warning("failed to remove item \(key)") + } + + if !self.set(value, forKey: key, withAccessibility: accessibility) { + log.warning("failed to update item \(key)") + } + } + } + } + + func ensureObjectItemAccessibility(_ accessibility: SwiftKeychainWrapper.KeychainItemAccessibility, forKey key: String) { + if self.hasValue(forKey: key) { + if self.accessibilityOfKey(key) != .afterFirstUnlock { + log.debug("updating item \(key) with \(accessibility)") + + guard let value = self.object(forKey: key) else { + log.error("failed to get item \(key)") + return + } + + if !self.removeObject(forKey: key) { + log.warning("failed to remove item \(key)") + } + + if !self.set(value, forKey: key, withAccessibility: accessibility) { + log.warning("failed to update item \(key)") + } + } + } + } +} diff --git a/mobile/ios/Shared/Extensions/NSCharacterSetExtensions.swift b/mobile/ios/Shared/Extensions/NSCharacterSetExtensions.swift new file mode 100644 index 0000000000..dd90cc2b50 --- /dev/null +++ b/mobile/ios/Shared/Extensions/NSCharacterSetExtensions.swift @@ -0,0 +1,15 @@ +/* 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/. */ + +import Foundation + +extension CharacterSet { + public static func URLAllowedCharacterSet() -> CharacterSet { + return CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=%") + } + + public static func SearchTermsAllowedCharacterSet() -> CharacterSet { + return CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*-_.") + } +} diff --git a/mobile/ios/Shared/Extensions/NSCoderExtensions.swift b/mobile/ios/Shared/Extensions/NSCoderExtensions.swift new file mode 100644 index 0000000000..a891d27675 --- /dev/null +++ b/mobile/ios/Shared/Extensions/NSCoderExtensions.swift @@ -0,0 +1,41 @@ +/* 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/. */ + +import Foundation + +/** + * There are some oddnesses around the different ways that NSKeyedArchiver decodes objects based on whether or not they were + * originally encoded using Swift 2.x or Swift 3. + * If the object was encoded on Swift 2.x, then you need to use decodeObject to unwrap it. But that will return a nil if the object was encoded on Swift 3 + * For swift 3 encoded objects to you need to use decode + * These helper functions provide a unified way of achieving that + **/ +extension NSCoder { + /** + * Decode as Int regardless of which Swift version was used to encode it + **/ + open func decodeAsInt(forKey key: String) -> Int { + return self.decodeObject(forKey: key) as? Int ?? self.decodeInteger(forKey: key) + } + /** + * Decode as UInt64 regardless of which Swift version was used to encode it + **/ + open func decodeAsUInt64(forKey key: String) -> UInt64 { + return (self.decodeObject(forKey: key) as? NSNumber)?.uint64Value ?? UInt64(self.decodeInt64(forKey: key)) + } + + /** + * Decode as Bool regardless of which Swift version was used to encode it + **/ + open func decodeAsBool(forKey key: String) -> Bool { + return self.decodeObject(forKey: key) as? Bool ?? self.decodeBool(forKey: key) + } + + /** + * Decode as Double regardless of which Swift version was used to encode it + **/ + open func decodeAsDouble(forKey key: String) -> Double { + return (self.decodeObject(forKey: key) as? NSNumber)?.doubleValue ?? self.decodeDouble(forKey: key) + } +} diff --git a/mobile/ios/Shared/Extensions/NSFileManagerExtensions.swift b/mobile/ios/Shared/Extensions/NSFileManagerExtensions.swift new file mode 100644 index 0000000000..828cee6ca5 --- /dev/null +++ b/mobile/ios/Shared/Extensions/NSFileManagerExtensions.swift @@ -0,0 +1,112 @@ +/* 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/. */ + +/* Created and contributed by Nikolai Ruhe and rewritten in Swift. + * https://github.com/NikolaiRuhe/NRFoundation */ + +import Foundation + +public let NSFileManagerExtensionsDomain = "org.mozilla.NSFileManagerExtensions" + +public enum NSFileManagerExtensionsErrorCodes: Int { + case enumeratorFailure = 0 + case enumeratorElementNotURL = 1 + case errorEnumeratingDirectory = 2 +} + +public extension FileManager { + + private func directoryEnumeratorForURL(_ url: URL) throws -> FileManager.DirectoryEnumerator { + let prefetchedProperties = [ + URLResourceKey.isRegularFileKey, + URLResourceKey.fileAllocatedSizeKey, + URLResourceKey.totalFileAllocatedSizeKey + ] + + // If we run into an issue getting an enumerator for the given URL, capture the error and bail out later. + var enumeratorError: NSError? + let errorHandler: (URL, Error) -> Bool = { _, error in + enumeratorError = error as NSError + return false + } + + guard let directoryEnumerator = FileManager.default.enumerator(at: url, + includingPropertiesForKeys: prefetchedProperties, + options: [], + errorHandler: errorHandler) else { + throw errorWithCode(.enumeratorFailure) + } + + // Bail out if we encountered an issue getting the enumerator. + if let _ = enumeratorError { + throw errorWithCode(.errorEnumeratingDirectory, underlyingError: enumeratorError) + } + + return directoryEnumerator + } + + private func sizeForItemURL(_ url: Any, withPrefix prefix: String) throws -> Int64 { + guard let itemURL = url as? URL else { + throw errorWithCode(.enumeratorElementNotURL) + } + + // Skip files that are not regular and don't match our prefix + guard itemURL.isRegularFile && itemURL.lastComponentIsPrefixedBy(prefix) else { + return 0 + } + + return itemURL.allocatedFileSize() + } + + func allocatedSizeOfDirectoryAtURL(_ url: URL, forFilesPrefixedWith prefix: String, isLargerThanBytes threshold: Int64) throws -> Bool { + let directoryEnumerator = try directoryEnumeratorForURL(url) + var acc: Int64 = 0 + for item in directoryEnumerator { + acc += try sizeForItemURL(item as AnyObject, withPrefix: prefix) + if acc > threshold { + return true + } + } + return false + } + + /** + Returns the precise size of the given directory on disk. + + - parameter url: Directory URL + - parameter prefix: Prefix of files to check for size + + - throws: Error reading/operating on disk. + */ + func getAllocatedSizeOfDirectoryAtURL(_ url: URL, forFilesPrefixedWith prefix: String) throws -> Int64 { + let directoryEnumerator = try directoryEnumeratorForURL(url) + return try directoryEnumerator.reduce(0) { + let size = try sizeForItemURL($1 as AnyObject, withPrefix: prefix) + return $0 + size + } + } + + func contentsOfDirectoryAtPath(_ path: String, withFilenamePrefix prefix: String) throws -> [String] { + return try FileManager.default.contentsOfDirectory(atPath: path) + .filter { $0.hasPrefix("\(prefix).") } + .sorted { $0 < $1 } + } + + func removeItemInDirectory(_ directory: String, named: String) throws { + let file = URL(fileURLWithPath: directory).appendingPathComponent(named).path + try self.removeItem(atPath: file) + } + + private func errorWithCode(_ code: NSFileManagerExtensionsErrorCodes, underlyingError error: NSError? = nil) -> NSError { + var userInfo = [String: AnyObject]() + if let _ = error { + userInfo[NSUnderlyingErrorKey] = error + } + + return NSError( + domain: NSFileManagerExtensionsDomain, + code: code.rawValue, + userInfo: userInfo) + } +} diff --git a/mobile/ios/Shared/Extensions/NSMutableAttributedStringExtensions.swift b/mobile/ios/Shared/Extensions/NSMutableAttributedStringExtensions.swift new file mode 100644 index 0000000000..89d0be1357 --- /dev/null +++ b/mobile/ios/Shared/Extensions/NSMutableAttributedStringExtensions.swift @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import UIKit + +extension NSMutableAttributedString { + public func colorSubstring(_ substring: String, withColor color: UIColor) { + self.attributeSubstring(substring, forAttribute: NSForegroundColorAttributeName, withValue: color) + } + + public func pitchSubstring(_ substring: String, withPitch pitch: Double) { + let pitchValue = NSNumber(value: pitch as Double) + self.attributeSubstring(substring, forAttribute: UIAccessibilitySpeechAttributePitch, withValue: pitchValue) + } + + private func attributeSubstring(_ substring: String, forAttribute attribute: String, withValue value: AnyObject) { + let nsString = self.string as NSString + let range = nsString.range(of: substring) + self.addAttribute(attribute, value: value, range: range) + } +} diff --git a/mobile/ios/Shared/Extensions/NSScannerExtensions.swift b/mobile/ios/Shared/Extensions/NSScannerExtensions.swift new file mode 100644 index 0000000000..ada72571e4 --- /dev/null +++ b/mobile/ios/Shared/Extensions/NSScannerExtensions.swift @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation + +extension Scanner { + public func scanUnsignedLongLong() -> UInt64? { + var value: UInt64 = 0 + if scanUnsignedLongLong(&value) { + return value + } + return nil + } + + public func scanLongLong() -> Int64? { + var value: Int64 = 0 + if scanInt64(&value) { + return value + } + return nil + } + + public func scanDouble() -> Double? { + var value: Double = 0 + if scanDouble(&value) { + return value + } + return nil + } +} diff --git a/mobile/ios/Shared/Extensions/NSStringExtensions.swift b/mobile/ios/Shared/Extensions/NSStringExtensions.swift new file mode 100644 index 0000000000..3938f040c0 --- /dev/null +++ b/mobile/ios/Shared/Extensions/NSStringExtensions.swift @@ -0,0 +1,20 @@ +/* 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/. */ + +import Foundation + +extension String { + public static func contentsOfFileWithResourceName(_ name: String, ofType type: String, fromBundle bundle: Bundle, encoding: String.Encoding, error: NSErrorPointer) -> String? { + if let path = bundle.path(forResource: name, ofType: type) { + do { + return try String(contentsOfFile: path, encoding: encoding) + } catch { + return nil + } + } else { + return nil + } + } +} + diff --git a/mobile/ios/Shared/Extensions/NSURLExtensions.swift b/mobile/ios/Shared/Extensions/NSURLExtensions.swift new file mode 100644 index 0000000000..64654a8684 --- /dev/null +++ b/mobile/ios/Shared/Extensions/NSURLExtensions.swift @@ -0,0 +1,498 @@ +/* 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/. */ + +import UIKit + +private struct ETLDEntry: CustomStringConvertible { + let entry: String + + var isNormal: Bool { return isWild || !isException } + var isWild: Bool = false + var isException: Bool = false + + init(entry: String) { + self.entry = entry + self.isWild = entry.hasPrefix("*") + self.isException = entry.hasPrefix("!") + } + + fileprivate var description: String { + return "{ Entry: \(entry), isWildcard: \(isWild), isException: \(isException) }" + } +} + +private typealias TLDEntryMap = [String: ETLDEntry] + +private func loadEntriesFromDisk() -> TLDEntryMap? { + if let data = String.contentsOfFileWithResourceName("effective_tld_names", ofType: "dat", fromBundle: Bundle(identifier: "org.mozilla.Shared")!, encoding: String.Encoding.utf8, error: nil) { + let lines = data.components(separatedBy: "\n") + let trimmedLines = lines.filter { !$0.hasPrefix("//") && $0 != "\n" && $0 != "" } + + var entries = TLDEntryMap() + for line in trimmedLines { + let entry = ETLDEntry(entry: line) + let key: String + if entry.isWild { + // Trim off the '*.' part of the line + key = line.substring(from: line.characters.index(line.startIndex, offsetBy: 2)) + } else if entry.isException { + // Trim off the '!' part of the line + key = line.substring(from: line.characters.index(line.startIndex, offsetBy: 1)) + } else { + key = line + } + entries[key] = entry + } + return entries + } + return nil +} + +private var etldEntries: TLDEntryMap? = { + return loadEntriesFromDisk() +}() + +// MARK: - Local Resource URL Extensions +extension URL { + + public func allocatedFileSize() -> Int64 { + // First try to get the total allocated size and in failing that, get the file allocated size + return getResourceLongLongForKey(URLResourceKey.totalFileAllocatedSizeKey.rawValue) + ?? getResourceLongLongForKey(URLResourceKey.fileAllocatedSizeKey.rawValue) + ?? 0 + } + + public func getResourceValueForKey(_ key: String) -> Any? { + let resourceKey = URLResourceKey(key) + let keySet = Set([resourceKey]) + + var val: Any? + do { + let values = try resourceValues(forKeys: keySet) + val = values.allValues[resourceKey] + } catch _ { + return nil + } + return val + } + + public func getResourceLongLongForKey(_ key: String) -> Int64? { + return (getResourceValueForKey(key) as? NSNumber)?.int64Value + } + + public func getResourceBoolForKey(_ key: String) -> Bool? { + return getResourceValueForKey(key) as? Bool + } + + public var isRegularFile: Bool { + return getResourceBoolForKey(URLResourceKey.isRegularFileKey.rawValue) ?? false + } + + public func lastComponentIsPrefixedBy(_ prefix: String) -> Bool { + return (pathComponents.last?.hasPrefix(prefix) ?? false) + } +} + +// The list of permanent URI schemes has been taken from http://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml +private let permanentURISchemes = ["aaa", "aaas", "about", "acap", "acct", "cap", "cid", "coap", "coaps", "crid", "data", "dav", "dict", "dns", "example", "file", "ftp", "geo", "go", "gopher", "h323", "http", "https", "iax", "icap", "im", "imap", "info", "ipp", "ipps", "iris", "iris.beep", "iris.lwz", "iris.xpc", "iris.xpcs", "jabber", "ldap", "mailto", "mid", "msrp", "msrps", "mtqp", "mupdate", "news", "nfs", "ni", "nih", "nntp", "opaquelocktoken", "pkcs11", "pop", "pres", "reload", "rtsp", "rtsps", "rtspu", "service", "session", "shttp", "sieve", "sip", "sips", "sms", "snmp", "soap.beep", "soap.beeps", "stun", "stuns", "tag", "tel", "telnet", "tftp", "thismessage", "tip", "tn3270", "turn", "turns", "tv", "urn", "vemmi", "vnc", "ws", "wss", "xcon", "xcon-userid", "xmlrpc.beep", "xmlrpc.beeps", "xmpp", "z39.50r", "z39.50s"] + +extension URL { + + public func withQueryParams(_ params: [URLQueryItem]) -> URL { + var components = URLComponents(url: self, resolvingAgainstBaseURL: false)! + var items = (components.queryItems ?? []) + for param in params { + items.append(param) + } + components.queryItems = items + return components.url! + } + + public func withQueryParam(_ name: String, value: String) -> URL { + var components = URLComponents(url: self, resolvingAgainstBaseURL: false)! + let item = URLQueryItem(name: name, value: value) + components.queryItems = (components.queryItems ?? []) + [item] + return components.url! + } + + public func getQuery() -> [String: String] { + var results = [String: String]() + let keyValues = self.query?.components(separatedBy: "&") + + if keyValues?.count ?? 0 > 0 { + for pair in keyValues! { + let kv = pair.components(separatedBy: "=") + if kv.count > 1 { + results[kv[0]] = kv[1] + } + } + } + + return results + } + + public var hostPort: String? { + if let host = self.host { + if let port = (self as NSURL).port?.int32Value { + return "\(host):\(port)" + } + return host + } + return nil + } + + public var origin: String? { + guard isWebPage(includeDataURIs: false), let hostPort = self.hostPort, let scheme = scheme else { + return nil + } + return "\(scheme)://\(hostPort)" + } + + /** + * Returns the second level domain (SLD) of a url. It removes any subdomain/TLD + * + * E.g., https://m.foo.com/bar/baz?noo=abc#123 => foo + **/ + public var hostSLD: String { + guard let publicSuffix = self.publicSuffix, let baseDomain = self.baseDomain else { + return self.normalizedHost ?? self.absoluteString + } + return baseDomain.replacingOccurrences(of: ".\(publicSuffix)", with: "") + } + + public var normalizedHostAndPath: String? { + if let normalizedHost = self.normalizedHost { + return normalizedHost + self.path + } + return nil + } + + public var absoluteDisplayString: String { + var urlString = self.absoluteString + // For http URLs, get rid of the trailing slash if the path is empty or '/' + if (self.scheme == "http" || self.scheme == "https") && (self.path == "/") && urlString.endsWith("/") { + urlString = urlString.substring(to: urlString.characters.index(urlString.endIndex, offsetBy: -1)) + } + // If it's basic http, strip out the string but leave anything else in + if urlString.hasPrefix("http://") { + return urlString.substring(from: urlString.characters.index(urlString.startIndex, offsetBy: 7)) + } else { + return urlString + } + } + + /// String suitable for displaying outside of the app, for example in notifications, were Data Detectors will + /// linkify the text and make it into a openable-in-Safari link. + public var absoluteDisplayExternalString: String { + return self.absoluteDisplayString.replacingOccurrences(of: ".", with: "\u{2024}") + } + + public var displayURL: URL? { + if self.isReaderModeURL { + return self.decodeReaderModeURL?.havingRemovedAuthorisationComponents() + } + + if self.isErrorPageURL { + if let decodedURL = self.originalURLFromErrorURL { + return decodedURL.displayURL + } else { + return nil + } + } + + if !self.isAboutURL { + return self.havingRemovedAuthorisationComponents() + } + + return nil + } + + /** + Returns the base domain from a given hostname. The base domain name is defined as the public domain suffix + with the base private domain attached to the front. For example, for the URL www.bbc.co.uk, the base domain + would be bbc.co.uk. The base domain includes the public suffix (co.uk) + one level down (bbc). + + :returns: The base domain string for the given host name. + */ + public var baseDomain: String? { + guard !isIPv6, let host = host else { return nil } + + // If this is just a hostname and not a FQDN, use the entire hostname. + if !host.contains(".") { + return host + } + + return publicSuffixFromHost(host, withAdditionalParts: 1) + } + + /** + * Returns just the domain, but with the same scheme, and a trailing '/'. + * + * E.g., https://m.foo.com/bar/baz?noo=abc#123 => https://foo.com/ + * + * Any failure? Return this URL. + */ + public var domainURL: URL { + if let normalized = self.normalizedHost { + // Use NSURLComponents instead of NSURL since the former correctly preserves + // brackets for IPv6 hosts, whereas the latter escapes them. + var components = URLComponents() + components.scheme = self.scheme + components.host = normalized + components.path = "/" + return components.url ?? self + } + return self + } + + public var normalizedHost: String? { + // Use components.host instead of self.host since the former correctly preserves + // brackets for IPv6 hosts, whereas the latter strips them. + guard let components = URLComponents(url: self, resolvingAgainstBaseURL: false), var host = components.host, host != "" else { + return nil + } + + if let range = host.range(of: "^(www|mobile|m)\\.", options: .regularExpression) { + host.replaceSubrange(range, with: "") + } + + return host + } + + /** + Returns the public portion of the host name determined by the public suffix list found here: https://publicsuffix.org/list/. + For example for the url www.bbc.co.uk, based on the entries in the TLD list, the public suffix would return co.uk. + + :returns: The public suffix for within the given hostname. + */ + public var publicSuffix: String? { + if let host = self.host { + return publicSuffixFromHost(host, withAdditionalParts: 0) + } else { + return nil + } + } + + public func isWebPage(includeDataURIs: Bool = true) -> Bool { + let schemes = includeDataURIs ? ["http", "https", "data"] : ["http", "https"] + if let scheme = scheme, schemes.contains(scheme) { + return true + } + + return false + } + + // This helps find local urls that we do not want to show loading bars on. + // These utility pages should be invisible to the user + public var isLocalUtility: Bool { + guard self.isLocal else { + return false + } + let utilityURLs = ["/errors", "/about/sessionrestore", "/about/home", "/reader-mode"] + return utilityURLs.contains { self.path.startsWith($0) } + } + + public var isLocal: Bool { + guard isWebPage(includeDataURIs: false) else { + return false + } + // iOS forwards hostless URLs (e.g., http://:6571) to localhost. + guard let host = host, !host.isEmpty else { + return true + } + + return host.lowercased() == "localhost" || host == "127.0.0.1" + } + + public var isIPv6: Bool { + return host?.contains(":") ?? false + } + + /** + Returns whether the URL's scheme is one of those listed on the official list of URI schemes. + This only accepts permanent schemes: historical and provisional schemes are not accepted. + */ + public var schemeIsValid: Bool { + guard let scheme = scheme else { return false } + return permanentURISchemes.contains(scheme.lowercased()) + } + + public func havingRemovedAuthorisationComponents() -> URL { + guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: false) else { + return self + } + urlComponents.user = nil + urlComponents.password = nil + if let url = urlComponents.url { + return url + } + return self + } +} + +// Extensions to deal with ReaderMode URLs + +extension URL { + public var isReaderModeURL: Bool { + let scheme = self.scheme, host = self.host, path = self.path + return scheme == "http" && host == "localhost" && path == "/reader-mode/page" + } + + public var decodeReaderModeURL: URL? { + if self.isReaderModeURL { + if let components = URLComponents(url: self, resolvingAgainstBaseURL: false), let queryItems = components.queryItems, queryItems.count == 1 { + if let queryItem = queryItems.first, let value = queryItem.value { + return URL(string: value) + } + } + } + return nil + } + + public func encodeReaderModeURL(_ baseReaderModeURL: String) -> URL? { + if let encodedURL = absoluteString.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics) { + if let aboutReaderURL = URL(string: "\(baseReaderModeURL)?url=\(encodedURL)") { + return aboutReaderURL + } + } + return nil + } +} + +// Helpers to deal with ErrorPage URLs + +extension URL { + public var isErrorPageURL: Bool { + if let host = self.host { + return self.scheme == "http" && host == "localhost" && path == "/errors/error.html" + } + return false + } + + public var originalURLFromErrorURL: URL? { + let components = URLComponents(url: self, resolvingAgainstBaseURL: false) + if let queryURL = components?.queryItems?.find({ $0.name == "url" })?.value { + return URL(string: queryURL) + } + return nil + } +} + +// Helpers to deal with About URLs +extension URL { + public var isAboutHomeURL: Bool { + if let urlString = self.getQuery()["url"]?.unescape(), isErrorPageURL { + let url = URL(string: urlString) ?? self + return url.aboutComponent == "home" + } + return self.aboutComponent == "home" + } + + public var isAboutURL: Bool { + return self.aboutComponent != nil + } + + /// If the URI is an about: URI, return the path after "about/" in the URI. + /// For example, return "home" for "http://localhost:1234/about/home/#panel=0". + public var aboutComponent: String? { + let aboutPath = "/about/" + guard let scheme = self.scheme, let host = self.host else { + return nil + } + if scheme == "http" && host == "localhost" && path.startsWith(aboutPath) { + return path.substring(from: aboutPath.endIndex) + } + return nil + } + +} + +//MARK: Private Helpers +private extension URL { + func publicSuffixFromHost( _ host: String, withAdditionalParts additionalPartCount: Int) -> String? { + if host.isEmpty { + return nil + } + + // Check edge case where the host is either a single or double '.'. + if host.isEmpty || NSString(string: host).lastPathComponent == "." { + return "" + } + + /** + * The following algorithm breaks apart the domain and checks each sub domain against the effective TLD + * entries from the effective_tld_names.dat file. It works like this: + * + * Example Domain: test.bbc.co.uk + * TLD Entry: bbc + * + * 1. Start off by checking the current domain (test.bbc.co.uk) + * 2. Also store the domain after the next dot (bbc.co.uk) + * 3. If we find an entry that matches the current domain (test.bbc.co.uk), perform the following checks: + * i. If the domain is a wildcard AND the previous entry is not nil, then the current domain matches + * since it satisfies the wildcard requirement. + * ii. If the domain is normal (no wildcard) and we don't have anything after the next dot, then + * currentDomain is a valid TLD + * iii. If the entry we matched is an exception case, then the base domain is the part after the next dot + * + * On the next run through the loop, we set the new domain to check as the part after the next dot, + * update the next dot reference to be the string after the new next dot, and check the TLD entries again. + * If we reach the end of the host (nextDot = nil) and we haven't found anything, then we've hit the + * top domain level so we use it by default. + */ + + let tokens = host.components(separatedBy: ".") + let tokenCount = tokens.count + var suffix: String? + var previousDomain: String? = nil + var currentDomain: String = host + + for offset in 0.. 0 { + if let suffix = suffix { + // Take out the public suffixed and add in the additional parts we want. + let literalFromEnd: NSString.CompareOptions = [NSString.CompareOptions.literal, // Match the string exactly. + NSString.CompareOptions.backwards, // Search from the end. + NSString.CompareOptions.anchored] // Stick to the end. + let suffixlessHost = host.replacingOccurrences(of: suffix, with: "", options: literalFromEnd, range: nil) + let suffixlessTokens = suffixlessHost.components(separatedBy: ".").filter { $0 != "" } + let maxAdditionalCount = max(0, suffixlessTokens.count - additionalPartCount) + let additionalParts = suffixlessTokens[maxAdditionalCount.. String { + // If our host is empty, return nothing since it doesn't make sense to add the scheme or port. + guard !host.isEmpty else { + return "" + } + + var urlString: String + if let p = `protocol` { + urlString = "\(p)://\(host)" + } else { + urlString = host + } + + // Check for non-standard ports + if port != 0 && port != 443 && port != 80 { + urlString += ":\(port)" + } + + return urlString + } +} diff --git a/mobile/ios/Shared/Extensions/OptionalExtensions.swift b/mobile/ios/Shared/Extensions/OptionalExtensions.swift new file mode 100644 index 0000000000..460f8d3027 --- /dev/null +++ b/mobile/ios/Shared/Extensions/OptionalExtensions.swift @@ -0,0 +1,18 @@ +/* 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/. */ + +import Foundation + +/* A smarter ?? operator which allows the left hand/right hand arguments to not be + * the same type. This is useful where we want to print the string representation + * of an optional value that is not a string but want to return a string value when + * a value is absent. + * + * For more informatin, check out Oleb's post: + * https://oleb.net/blog/2016/12/optionals-string-interpolation/ */ + +infix operator ???: NilCoalescingPrecedence +public func ???(optional: T?, defaultValue: @autoclosure () -> String) -> String { + return optional.map { String(describing: $0) } ?? defaultValue() +} diff --git a/mobile/ios/Shared/Extensions/SetExtensions.swift b/mobile/ios/Shared/Extensions/SetExtensions.swift new file mode 100644 index 0000000000..810b7766f3 --- /dev/null +++ b/mobile/ios/Shared/Extensions/SetExtensions.swift @@ -0,0 +1,84 @@ +/* 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/. */ + +import Foundation + +public extension SetIterator { + mutating func take(_ n: Int) -> [Element]? { + precondition(n >= 0) + + if n == 0 { + return [] + } + + var count: Int = 0 + var out: [Element] = [] + + while count < n { + count += 1 + guard let val = self.next() else { + if out.isEmpty { + return nil + } + return out + } + out.append(val) + } + return out + } +} + +public extension Set { + func withSubsetsOfSize(_ n: Int, f: (Set) throws -> Void) rethrows { + precondition(n > 0) + + if self.isEmpty { + return + } + + if n > self.count { + try f(self) + return + } + + if n == 1 { + try self.forEach { try f(Set([$0])) } + return + } + + var generator = self.makeIterator() + while let next = generator.take(n) { + if !next.isEmpty { + try f(Set(next)) + } + } + } + + func subsetsOfSize(_ n: Int) -> [Set] { + precondition(n > 0) + + if self.isEmpty { + return [] + } + + if n > self.count { + return [self] + } + + if n == 1 { + // Special case. + return self.map({ Set([$0]) }) + } + + var generator = self.makeIterator() + var out: [Set] = [] + out.reserveCapacity(self.count / n) + while let next = generator.take(n) { + if !next.isEmpty { + out.append(Set(next)) + } + } + return out + } +} diff --git a/mobile/ios/Shared/Extensions/StringExtensions.swift b/mobile/ios/Shared/Extensions/StringExtensions.swift new file mode 100644 index 0000000000..9b717d4510 --- /dev/null +++ b/mobile/ios/Shared/Extensions/StringExtensions.swift @@ -0,0 +1,107 @@ +/* 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/. */ + +import Foundation + +public extension String { + public func startsWith(_ other: String) -> Bool { + // rangeOfString returns nil if other is empty, destroying the analogy with (ordered) sets. + if other.isEmpty { + return true + } + if let range = self.range(of: other, + options: NSString.CompareOptions.anchored) { + return range.lowerBound == self.startIndex + } + return false + } + + public func endsWith(_ other: String) -> Bool { + // rangeOfString returns nil if other is empty, destroying the analogy with (ordered) sets. + if other.isEmpty { + return true + } + if let range = self.range(of: other, + options: [NSString.CompareOptions.anchored, NSString.CompareOptions.backwards]) { + return range.upperBound == self.endIndex + } + return false + } + + func escape() -> String? { + // We can't guaruntee that strings have a valid string encoding, as this is an entry point for tainted data, + // we should be very careful about forcefully dereferencing optional types. + // https://stackoverflow.com/questions/33558933/why-is-the-return-value-of-string-addingpercentencoding-optional#33558934 + let queryItemDividers = CharacterSet(charactersIn: "?=&") + let allowedEscapes = CharacterSet.urlQueryAllowed.symmetricDifference(queryItemDividers) + return self.addingPercentEncoding(withAllowedCharacters: allowedEscapes) + } + + func unescape() -> String? { + return self.removingPercentEncoding + } + + /** + Ellipsizes a String only if it's longer than `maxLength` + + "ABCDEF".ellipsize(4) + // "AB…EF" + + :param: maxLength The maximum length of the String. + + :returns: A String with `maxLength` characters or less + */ + func ellipsize(maxLength: Int) -> String { + if (maxLength >= 2) && (self.characters.count > maxLength) { + let index1 = self.characters.index(self.startIndex, offsetBy: (maxLength + 1) / 2) // `+ 1` has the same effect as an int ceil + let index2 = self.characters.index(self.endIndex, offsetBy: maxLength / -2) + + return self.substring(to: index1) + "…\u{2060}" + self.substring(from: index2) + } + return self + } + + private var stringWithAdditionalEscaping: String { + return self.replacingOccurrences(of: "|", with: "%7C", options: NSString.CompareOptions(), range: nil) + } + + public var asURL: URL? { + // Firefox and NSURL disagree about the valid contents of a URL. + // Let's escape | for them. + // We'd love to use one of the more sophisticated CFURL* or NSString.* functions, but + // none seem to be quite suitable. + return URL(string: self) ?? + URL(string: self.stringWithAdditionalEscaping) + } + + /// Returns a new string made by removing the leading String characters contained + /// in a given character set. + public func stringByTrimmingLeadingCharactersInSet(_ set: CharacterSet) -> String { + var trimmed = self + while trimmed.rangeOfCharacter(from: set)?.lowerBound == trimmed.startIndex { + trimmed.remove(at: trimmed.startIndex) + } + return trimmed + } + + /// Adds a newline at the closest space from the middle of a string. + /// Example turning "Mark as Read" into "Mark as\n Read" + public func stringSplitWithNewline() -> String { + let mid = self.characters.count/2 + + let arr: [Int] = self.characters.indices.flatMap { + if self.characters[$0] == " " { + return self.distance(from: startIndex, to: $0) + } + + return nil + } + guard let closest = arr.enumerated().min(by: { abs($0.1 - mid) < abs($1.1 - mid) }) else { + return self + } + var newString = self + newString.insert("\n", at: newString.characters.index(newString.characters.startIndex, offsetBy: closest.element)) + return newString + } +} diff --git a/mobile/ios/Shared/Extensions/UIColorExtensions.swift b/mobile/ios/Shared/Extensions/UIColorExtensions.swift new file mode 100644 index 0000000000..33118b575d --- /dev/null +++ b/mobile/ios/Shared/Extensions/UIColorExtensions.swift @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +import UIKit + +private struct Color { + var red: CGFloat + var green: CGFloat + var blue: CGFloat +} + +extension UIColor { + /** + * Initializes and returns a color object for the given RGB hex integer. + */ + public convenience init(rgb: Int) { + self.init( + red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0, + green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0, + blue: CGFloat((rgb & 0x0000FF) >> 0) / 255.0, + alpha: 1) + } + + public convenience init(colorString: String) { + var colorInt: UInt32 = 0 + Scanner(string: colorString).scanHexInt32(&colorInt) + self.init(rgb: (Int) (colorInt)) + } +} diff --git a/mobile/ios/Shared/Extensions/UIImageExtensions.swift b/mobile/ios/Shared/Extensions/UIImageExtensions.swift new file mode 100644 index 0000000000..4c616ca2fb --- /dev/null +++ b/mobile/ios/Shared/Extensions/UIImageExtensions.swift @@ -0,0 +1,83 @@ +/* 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/. */ + +import Foundation +import UIKit +import SDWebImage + +private let imageLock = NSLock() + +extension UIImage { + /// Despite docs that say otherwise, UIImage(data: NSData) isn't thread-safe (see bug 1223132). + /// As a workaround, synchronize access to this initializer. + /// This fix requires that you *always* use this over UIImage(data: NSData)! + public static func imageFromDataThreadSafe(_ data: Data) -> UIImage? { + imageLock.lock() + let image = UIImage(data: data) + imageLock.unlock() + return image + } + + /// Generates a UIImage from GIF data by calling out to SDWebImage. The latter in turn uses UIImage(data: NSData) + /// in certain cases so we have to synchronize calls (see bug 1223132). + public static func imageFromGIFDataThreadSafe(_ data: Data) -> UIImage? { + imageLock.lock() + let image = UIImage.sd_animatedGIF(with: data) + imageLock.unlock() + return image + } + + public static func dataIsGIF(_ data: Data) -> Bool { + guard data.count > 3 else { + return false + } + + // Look for "GIF" header to identify GIF images + var header = [UInt8](repeating: 0, count: 3) + data.copyBytes(to: &header, count: 3 * MemoryLayout.size) + return header == [0x47, 0x49, 0x46] + } + + public static func createWithColor(_ size: CGSize, color: UIColor) -> UIImage { + UIGraphicsBeginImageContextWithOptions(size, false, 0.0) + let context = UIGraphicsGetCurrentContext() + let rect = CGRect(origin: CGPoint.zero, size: size) + color.setFill() + context!.fill(rect) + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return image! + } + + public func createScaled(_ size: CGSize) -> UIImage { + UIGraphicsBeginImageContextWithOptions(size, false, 0) + draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: size)) + let scaledImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return scaledImage! + } + + public static func templateImageNamed(_ name: String) -> UIImage? { + return UIImage(named: name)?.withRenderingMode(.alwaysTemplate) + } + + // TESTING ONLY: not for use in release/production code. + // PNG comparison can return false negatives, be very careful using for non-equal comparison. + // PNG comparison requires UIImages to be constructed the same way in order for the metadata block to match, + // this function ensures that. + // + // This can be verified with this code: + // let image = UIImage(named: "fxLogo")! + // let data = UIImagePNGRepresentation(image)! + // assert(data != UIImagePNGRepresentation(UIImage(data: data)!)) + @available(*, deprecated, message: "use only in testing code") + public func isStrictlyEqual(to other: UIImage) -> Bool { + // Must use same constructor for PNG metadata block to be the same. + let imageA = UIImage(data: UIImagePNGRepresentation(self)!)! + let imageB = UIImage(data: UIImagePNGRepresentation(other)!)! + let dataA = UIImagePNGRepresentation(imageA)! + let dataB = UIImagePNGRepresentation(imageB)! + return dataA == dataB + } +} diff --git a/mobile/ios/Shared/Extensions/URLRequestExtensions.swift b/mobile/ios/Shared/Extensions/URLRequestExtensions.swift new file mode 100644 index 0000000000..4a45bd48a8 --- /dev/null +++ b/mobile/ios/Shared/Extensions/URLRequestExtensions.swift @@ -0,0 +1,14 @@ +/* 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/. */ + +import Foundation + +public extension URLRequest { + public enum Method: String { + case get = "GET" + case post = "POST" + case delete = "DELETE" + case put = "PUT" + } +} diff --git a/mobile/ios/Shared/FSUtils.h b/mobile/ios/Shared/FSUtils.h new file mode 100644 index 0000000000..cbec7f5e38 --- /dev/null +++ b/mobile/ios/Shared/FSUtils.h @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@import Foundation; + +@interface FSUtils : NSObject + +/** + * Grabs all open file descriptions and returns them in a key-value dictionary where + * the key is the descriptor # and the value being the filename. + * + * @return Dictionary of open file descriptors. + */ ++ (NSDictionary * _Nonnull)openFileDescriptors; + +@end diff --git a/mobile/ios/Shared/FSUtils.m b/mobile/ios/Shared/FSUtils.m new file mode 100644 index 0000000000..1d2e136c2e --- /dev/null +++ b/mobile/ios/Shared/FSUtils.m @@ -0,0 +1,42 @@ +/* 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/. */ + +#import "FSUtils.h" + +#import +#import +#import +#import + +@implementation FSUtils + ++ (NSDictionary * _Nonnull)openFileDescriptors +{ + int flags; + int fd; + char buf[MAXPATHLEN+1] ; + int n = 1 ; + NSMutableDictionary *dict = [@{} mutableCopy]; + + for (fd = 0; fd < (int) FD_SETSIZE; fd++) { + errno = 0; + flags = fcntl(fd, F_GETFD, 0); + if (flags == -1 && errno) { + if (errno != EBADF) { + return @{}; + } else { + continue; + } + } + fcntl(fd , F_GETPATH, buf ) ; + + dict[@(fd)] = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding]; + ++n ; + } + + return dict; +} + +@end + diff --git a/mobile/ios/Shared/FeatureSwitch.swift b/mobile/ios/Shared/FeatureSwitch.swift new file mode 100644 index 0000000000..996b1be3e7 --- /dev/null +++ b/mobile/ios/Shared/FeatureSwitch.swift @@ -0,0 +1,83 @@ +/* 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/. */ + +import Foundation + +/// Steadily growing set of feature switches controlling access to features by populations of Release users. +open class FeatureSwitches { +} + +/// Small class to allow a percentage of users to access a given feature. +/// It is deliberately low tech, and is not remotely changeable. +/// Randomized bucketing is only applied when the app's release build channel. +open class FeatureSwitch { + let featureID: String + let buildChannel: AppBuildChannel + let nonChannelValue: Bool + let percentage: Int + fileprivate let switchKey: String + init(named featureID: String, _ value: Bool = true, allowPercentage percentage: Int, buildChannel: AppBuildChannel = .release) { + self.featureID = featureID + self.percentage = percentage + self.buildChannel = buildChannel + self.nonChannelValue = value + self.switchKey = "feature_switches.\(self.featureID)" + } + + /// Is this user a member of the bucket that is allowed to use this feature. + /// Bucketing is decided with the hash of a UUID, which is randomly generated and cached + /// in the preferences. + /// This gives us stable properties across restarts and new releases. + open func isMember(_ prefs: Prefs) -> Bool { + // Only use bucketing if we're in the correct build channel, and feature flag is true. + guard buildChannel == AppConstants.BuildChannel, nonChannelValue else { + return nonChannelValue + } + + // Check if this feature has been enabled by the user + let key = "\(self.switchKey).enabled" + if let isEnabled = prefs.boolForKey(key) { + return isEnabled + } + + return lowerCaseS(prefs) < self.percentage + } + + /// Is this user always a member of the test set, whatever the percentage probability? + /// This _only_ tests the probabilities, not the other conditions. + open func alwaysMembership(_ prefs: Prefs) -> Bool { + return lowerCaseS(prefs) == 99 + } + + /// Reset the random component of this switch (`lowerCaseS`). This is primarily useful for testing. + open func resetMembership(_ prefs: Prefs) { + let uuidKey = "\(self.switchKey).uuid" + prefs.removeObjectForKey(uuidKey) + } + + // If the set of all possible values the switch can be in is `S` (integers between 0 and 99) + // then the specific value is `s`. + // We use this to compare with the probability of membership. + fileprivate func lowerCaseS(_ prefs: Prefs) -> Int { + // Use a branch of the prefs. + let uuidKey = "\(self.switchKey).uuid" + + let uuidString: String + if let string = prefs.stringForKey(uuidKey) { + uuidString = string + } else { + uuidString = UUID().uuidString + prefs.setString(uuidString, forKey: uuidKey) + } + + let hash = abs(uuidString.hashValue) + + return hash % 100 + } + + open func setMembership(_ isEnabled: Bool, for prefs: Prefs) { + let key = "\(self.switchKey).enabled" + prefs.setBool(isEnabled, forKey: key) + } +} diff --git a/mobile/ios/Shared/Functions.swift b/mobile/ios/Shared/Functions.swift new file mode 100644 index 0000000000..6b81c7c6d8 --- /dev/null +++ b/mobile/ios/Shared/Functions.swift @@ -0,0 +1,253 @@ +/* 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/. */ +import SwiftyJSON + +// Pipelining. +precedencegroup PipelinePrecedence { + associativity: left +} +infix operator |> : PipelinePrecedence + +public func |> (x: T, f: (T) -> U) -> U { + return f(x) +} + +// Basic currying. +public func curry(_ f: @escaping (A) -> B) -> (A) -> B { + return { a in + return f(a) + } +} + +public func curry(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C { + return { a in + return { b in + return f(a, b) + } + } +} + +public func curry(_ f: @escaping (A, B, C) -> D) -> (A) -> (B) -> (C) -> D { + return { a in + return { b in + return { c in + return f(a, b, c) + } + } + } +} + +public func curry(_ f: @escaping (A, B, C, D) -> E) -> (A, B, C) -> (D) -> E { + return { (a, b, c) in + return { d in + return f(a, b, c, d) + } + } +} + +// Function composition. +infix operator • + +public func •(f: @escaping (T) -> U, g: @escaping (U) -> V) -> (T) -> V { + return { t in + return g(f(t)) + } +} +public func •(f: @escaping (T) -> Void, g: @escaping () -> V) -> (T) -> V { + return { t in + f(t) + return g() + } +} +public func •(f: @escaping () -> Void, g: @escaping () -> V) -> () -> V { + return { + f() + return g() + } +} + +// Why not simply provide an override for ==? Well, that's scary, and can accidentally recurse. +// This is enough to catch arrays, which Swift will delegate to element-==. +public func optArrayEqual(_ lhs: [T]?, rhs: [T]?) -> Bool { + switch (lhs, rhs) { + case (.none, .none): + return true + case (.none, _): + return false + case (_, .none): + return false + default: + // This delegates to Swift's own array '==', which calls T's == on each element. + return lhs! == rhs! + } +} + +/** + * Given an array, return an array of slices of size `by` (possibly excepting the last slice). + * + * If `by` is longer than the input, returns a single chunk. + * If `by` is less than 1, acts as if `by` is 1. + * If the length of the array isn't a multiple of `by`, the final slice will + * be smaller than `by`, but never empty. + * + * If the input array is empty, returns an empty array. + */ + +public func chunk(_ arr: [T], by: Int) -> [ArraySlice] { + var result = [ArraySlice]() + var chunk = -1 + let size = max(1, by) + for (index, elem) in arr.enumerated() { + if index % size == 0 { + result.append(ArraySlice()) + chunk += 1 + } + result[chunk].append(elem) + } + return result +} + +public func chunkCollection(_ items: T, by: Int, f: ([E]) -> [X]) -> [X] where T.Iterator.Element == E { + assert(by >= 0) + let max = by > 0 ? by : 1 + var i = 0 + var acc: [E] = [] + var results: [X] = [] + var iter = items.makeIterator() + + while let item = iter.next() { + if i >= max { + results.append(contentsOf: f(acc)) + acc = [] + i = 0 + } + acc.append(item) + i += 1 + } + + if !acc.isEmpty { + results.append(contentsOf: f(acc)) + } + + return results +} + +public extension Sequence { + // [T] -> (T -> K) -> [K: [T]] + // As opposed to `groupWith` (to follow Haskell's naming), which would be + // [T] -> (T -> K) -> [[T]] + func groupBy(_ selector: (Self.Iterator.Element) -> Key, transformer: (Self.Iterator.Element) -> Value) -> [Key: [Value]] { + var acc: [Key: [Value]] = [:] + for x in self { + let k = selector(x) + var a = acc[k] ?? [] + a.append(transformer(x)) + acc[k] = a + } + return acc + } + + func zip(_ elems: S) -> [(Self.Iterator.Element, S.Iterator.Element)] { + var rights = elems.makeIterator() + return self.flatMap { lhs in + guard let rhs = rights.next() else { + return nil + } + return (lhs, rhs) + } + } +} + +public func optDictionaryEqual(_ lhs: [K: V]?, rhs: [K: V]?) -> Bool { + switch (lhs, rhs) { + case (.none, .none): + return true + case (.none, _): + return false + case (_, .none): + return false + default: + return lhs! == rhs! + } +} + +/** + * Return members of `a` that aren't nil, changing the type of the sequence accordingly. + */ +public func optFilter(_ a: [T?]) -> [T] { + return a.flatMap { $0 } +} + +/** + * Return a new map with only key-value pairs that have a non-nil value. + */ +public func optFilter(_ source: [K: V?]) -> [K: V] { + var m = [K: V]() + for (k, v) in source { + if let v = v { + m[k] = v + } + } + return m +} + +/** + * Map a function over the values of a map. + */ +public func mapValues(_ source: [K: T], f: ((T) -> U)) -> [K: U] { + var m = [K: U]() + for (k, v) in source { + m[k] = f(v) + } + return m +} + +public func findOneValue(_ map: [K: V], f: (V) -> Bool) -> V? { + for v in map.values { + if f(v) { + return v + } + } + return nil +} + +/** + * Take a JSON array, returning the String elements as an array. + * It's usually convenient for this to accept an optional. + */ +public func jsonsToStrings(_ arr: [JSON]?) -> [String]? { + return arr?.flatMap { $0.stringValue } +} + +// Encapsulate a callback in a way that we can use it with NSTimer. +private class Callback { + private let handler:() -> Void + + init(handler:@escaping () -> Void) { + self.handler = handler + } + + @objc + func go() { + handler() + } +} + +/** + * Taken from http://stackoverflow.com/questions/27116684/how-can-i-debounce-a-method-call + * Allows creating a block that will fire after a delay. Resets the timer if called again before the delay expires. + **/ +public func debounce(_ delay: TimeInterval, action:@escaping () -> Void) -> () -> Void { + let callback = Callback(handler: action) + var timer: Timer? + + return { + // If calling again, invalidate the last timer. + if let timer = timer { + timer.invalidate() + } + timer = Timer(timeInterval: delay, target: callback, selector: #selector(Callback.go), userInfo: nil, repeats: false) + RunLoop.current.add(timer!, forMode: RunLoopMode.defaultRunLoopMode) + } +} diff --git a/mobile/ios/Shared/KeyboardHelper.swift b/mobile/ios/Shared/KeyboardHelper.swift new file mode 100644 index 0000000000..009c50d16f --- /dev/null +++ b/mobile/ios/Shared/KeyboardHelper.swift @@ -0,0 +1,126 @@ +/* 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/. */ + +import UIKit +import Foundation + +/** + * The keyboard state at the time of notification. + */ +public struct KeyboardState { + public let animationDuration: Double + public let animationCurve: UIViewAnimationCurve + private let userInfo: [AnyHashable: Any] + + fileprivate init(_ userInfo: [AnyHashable: Any]) { + self.userInfo = userInfo + animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double + // HACK: UIViewAnimationCurve doesn't expose the keyboard animation used (curveValue = 7), + // so UIViewAnimationCurve(rawValue: curveValue) returns nil. As a workaround, get a + // reference to an EaseIn curve, then change the underlying pointer data with that ref. + var curve = UIViewAnimationCurve.easeIn + if let curveValue = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int { + NSNumber(value: curveValue as Int).getValue(&curve) + } + self.animationCurve = curve + } + + /// Return the height of the keyboard that overlaps with the specified view. This is more + /// accurate than simply using the height of UIKeyboardFrameBeginUserInfoKey since for example + /// on iPad the overlap may be partial or if an external keyboard is attached, the intersection + /// height will be zero. (Even if the height of the *invisible* keyboard will look normal!) + public func intersectionHeightForView(_ view: UIView) -> CGFloat { + if let keyboardFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue { + let keyboardFrame = keyboardFrameValue.cgRectValue + let convertedKeyboardFrame = view.convert(keyboardFrame, from: nil) + let intersection = convertedKeyboardFrame.intersection(view.bounds) + return intersection.size.height + } + return 0 + } +} + +public protocol KeyboardHelperDelegate: class { + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillShowWithState state: KeyboardState) + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardDidShowWithState state: KeyboardState) + func keyboardHelper(_ keyboardHelper: KeyboardHelper, keyboardWillHideWithState state: KeyboardState) +} + +/** + * Convenience class for observing keyboard state. + */ +open class KeyboardHelper: NSObject { + open var currentState: KeyboardState? + + fileprivate var delegates = [WeakKeyboardDelegate]() + + open class var defaultHelper: KeyboardHelper { + struct Singleton { + static let instance = KeyboardHelper() + } + return Singleton.instance + } + + /** + * Starts monitoring the keyboard state. + */ + open func startObserving() { + NotificationCenter.default.addObserver(self, selector: #selector(KeyboardHelper.SELkeyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(KeyboardHelper.SELkeyboardDidShow(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(KeyboardHelper.SELkeyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + /** + * Adds a delegate to the helper. + * Delegates are weakly held. + */ + open func addDelegate(_ delegate: KeyboardHelperDelegate) { + // Reuse any existing slots that have been deallocated. + for weakDelegate in delegates where weakDelegate.delegate == nil { + weakDelegate.delegate = delegate + return + } + + delegates.append(WeakKeyboardDelegate(delegate)) + } + + func SELkeyboardWillShow(_ notification: Notification) { + if let userInfo = notification.userInfo { + currentState = KeyboardState(userInfo) + for weakDelegate in delegates { + weakDelegate.delegate?.keyboardHelper(self, keyboardWillShowWithState: currentState!) + } + } + } + + func SELkeyboardDidShow(_ notification: Notification) { + if let userInfo = notification.userInfo { + currentState = KeyboardState(userInfo) + for weakDelegate in delegates { + weakDelegate.delegate?.keyboardHelper(self, keyboardDidShowWithState: currentState!) + } + } + } + + func SELkeyboardWillHide(_ notification: Notification) { + if let userInfo = notification.userInfo { + currentState = KeyboardState(userInfo) + for weakDelegate in delegates { + weakDelegate.delegate?.keyboardHelper(self, keyboardWillHideWithState: currentState!) + } + } + } +} + +private class WeakKeyboardDelegate { + weak var delegate: KeyboardHelperDelegate? + + init(_ delegate: KeyboardHelperDelegate) { + self.delegate = delegate + } +} diff --git a/mobile/ios/Shared/KeychainCache.swift b/mobile/ios/Shared/KeychainCache.swift new file mode 100644 index 0000000000..dce3789aeb --- /dev/null +++ b/mobile/ios/Shared/KeychainCache.swift @@ -0,0 +1,65 @@ +/* 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/. */ + +import Foundation +import XCGLogger +import SwiftKeychainWrapper +import SwiftyJSON + +private let log = Logger.keychainLogger + +public protocol JSONLiteralConvertible { + func asJSON() -> JSON +} + +open class KeychainCache { + open let branch: String + open let label: String + + open var value: T? { + didSet { + checkpoint() + } + } + + public init(branch: String, label: String, value: T?) { + self.branch = branch + self.label = label + self.value = value + } + + open class func fromBranch(_ branch: String, withLabel label: String?, withDefault defaultValue: T? = nil, factory: (JSON) -> T?) -> KeychainCache { + if let l = label { + let key = "\(branch).\(l)" + KeychainWrapper.sharedAppContainerKeychain.ensureStringItemAccessibility(.afterFirstUnlock, forKey: key) + if let s = KeychainWrapper.sharedAppContainerKeychain.string(forKey: key) { + if let t = factory(JSON(parseJSON: s)) { + log.info("Read \(branch) from Keychain with label \(branch).\(l).") + return KeychainCache(branch: branch, label: l, value: t) + } else { + log.warning("Found \(branch) in Keychain with label \(branch).\(l), but could not parse it.") + } + } else { + log.warning("Did not find \(branch) in Keychain with label \(branch).\(l).") + } + } else { + log.warning("Did not find \(branch) label in Keychain.") + } + // Fall through to missing. + log.warning("Failed to read \(branch) from Keychain.") + let label = label ?? Bytes.generateGUID() + return KeychainCache(branch: branch, label: label, value: defaultValue) + } + + open func checkpoint() { + log.info("Storing \(self.branch) in Keychain with label \(self.branch).\(self.label).") + // TODO: PII logging. + if let value = value, + let jsonString = value.asJSON().stringValue() { + KeychainWrapper.sharedAppContainerKeychain.set(jsonString, forKey: "\(branch).\(label)", withAccessibility: .afterFirstUnlock) + } else { + KeychainWrapper.sharedAppContainerKeychain.removeObject(forKey: "\(branch).\(label)") + } + } +} diff --git a/mobile/ios/Shared/LaunchArguments.swift b/mobile/ios/Shared/LaunchArguments.swift new file mode 100644 index 0000000000..5a4679fcc3 --- /dev/null +++ b/mobile/ios/Shared/LaunchArguments.swift @@ -0,0 +1,12 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation + +public struct LaunchArguments { + public static let Test = "FIREFOX_TEST" + public static let SkipIntro = "FIREFOX_SKIP_INTRO" + public static let SkipWhatsNew = "FIREFOX_SKIP_WHATS_NEW" + public static let ClearProfile = "FIREFOX_CLEAR_PROFILE" +} diff --git a/mobile/ios/Shared/Loader.swift b/mobile/ios/Shared/Loader.swift new file mode 100644 index 0000000000..b73a2a0589 --- /dev/null +++ b/mobile/ios/Shared/Loader.swift @@ -0,0 +1,33 @@ +/* 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/. */ + +import Foundation + +/** + * Interface for listening to Loader updates. + */ +public protocol LoaderListener: class { + associatedtype T + func loader(dataLoaded data: T) +} + +/** + * Base implementation for a "push" data model. + * Interested clients add themselves as listeners for data changes. + */ +open class Loader where T == ListenerType.T { + private let listeners = WeakList() + + public init() {} + + open func addListener(_ listener: ListenerType) { + listeners.insert(listener) + } + + open func load(_ data: T) { + for listener in listeners { + listener.loader(dataLoaded: data) + } + } +} diff --git a/mobile/ios/Shared/Logger.swift b/mobile/ios/Shared/Logger.swift new file mode 100644 index 0000000000..44740ad95e --- /dev/null +++ b/mobile/ios/Shared/Logger.swift @@ -0,0 +1,96 @@ +/* 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/. */ + +import Foundation +import XCGLogger + +public struct Logger {} + +// MARK: - Singleton Logger Instances +public extension Logger { + static let logPII = false + + /// Logger used for recording happenings with Sync, Accounts, Providers, Storage, and Profiles + static let syncLogger = RollingFileLogger(filenameRoot: "sync", logDirectoryPath: Logger.logFileDirectoryPath()) + + /// Logger used for recording frontend/browser happenings + static let browserLogger = RollingFileLogger(filenameRoot: "browser", logDirectoryPath: Logger.logFileDirectoryPath()) + + /// Logger used for recording interactions with the keychain + static let keychainLogger: XCGLogger = Logger.fileLoggerWithName("keychain") + + /// Logger used for logging database errors such as corruption + static let corruptLogger: RollingFileLogger = { + let logger = RollingFileLogger(filenameRoot: "corruptLogger", logDirectoryPath: Logger.logFileDirectoryPath()) + logger.newLogWithDate(Date()) + return logger + }() + + /** + Return the log file directory path. If the directory doesn't exist, make sure it exist first before returning the path. + + :returns: Directory path where log files are stored + */ + static func logFileDirectoryPath() -> String? { + if let cacheDir = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first { + let logDir = "\(cacheDir)/Logs" + if !FileManager.default.fileExists(atPath: logDir) { + do { + try FileManager.default.createDirectory(atPath: logDir, withIntermediateDirectories: false, attributes: nil) + return logDir + } catch _ as NSError { + return nil + } + } else { + return logDir + } + } + + return nil + } + + static private func fileLoggerWithName(_ name: String) -> XCGLogger { + let log = XCGLogger() + if let logFileURL = urlForLogNamed(name) { + let fileDestination = FileDestination( + owner: log, + writeToFile: logFileURL.absoluteString, + identifier: "com.mozilla.firefox.filelogger.\(name)" + ) + log.add(destination: fileDestination) + } + return log + } + + static private func urlForLogNamed(_ name: String) -> URL? { + guard let logDir = Logger.logFileDirectoryPath() else { + return nil + } + + return URL(string: "\(logDir)/\(name).log") + } + + /** + Grabs all of the configured logs that write to disk and returns them in NSData format along with their + associated filename. + + - returns: Tuples of filenames to each file's contexts in a NSData object + */ + static func diskLogFilenamesAndData() throws -> [(String, Data?)] { + var filenamesAndURLs = [(String, URL)]() + filenamesAndURLs.append(("browser", urlForLogNamed("browser")!)) + filenamesAndURLs.append(("keychain", urlForLogNamed("keychain")!)) + + // Grab all sync log files + do { + filenamesAndURLs += try syncLogger.logFilenamesAndURLs() + filenamesAndURLs += try corruptLogger.logFilenamesAndURLs() + filenamesAndURLs += try browserLogger.logFilenamesAndURLs() + } catch _ { + } + + return filenamesAndURLs.map { ($0, try? Data(contentsOf: URL(fileURLWithPath: $1.absoluteString))) } + } +} + diff --git a/mobile/ios/Shared/NotificationConstants.swift b/mobile/ios/Shared/NotificationConstants.swift new file mode 100644 index 0000000000..456f966e71 --- /dev/null +++ b/mobile/ios/Shared/NotificationConstants.swift @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +public let NotificationDataLoginDidChange = Notification.Name("Data:Login:DidChange") + +// add a property to allow the observation of firefox accounts +public let NotificationFirefoxAccountChanged = Notification.Name("FirefoxAccountChangedNotification") + +public let NotificationFirefoxAccountProfileChanged = Notification.Name("NotificationFirefoxAccountProfileChanged") + +public let NotificationFirefoxAccountDeviceRegistrationUpdated = Notification.Name("FirefoxAccountDeviceRegistrationUpdated") + +public let NotificationPrivateDataClearedHistory = Notification.Name("PrivateDataClearedHistoryNotification") + +// Fired when the user finishes navigating to a page and the location has changed +public let NotificationOnLocationChange = Notification.Name("OnLocationChange") + +// Fired when a the page metadata extraction script has completed and is being passed back to the native client +public let NotificationOnPageMetadataFetched = Notification.Name("OnPageMetadataFetched") + +// Fired when the login synchronizer has finished applying remote changes +public let NotificationDataRemoteLoginChangesWereApplied = Notification.Name("NotificationDataRemoteLoginChangesWereApplied") + +// Fired when the FxA account has been verified. This should only be fired by the FxALoginStateMachine. +public let NotificationFirefoxAccountVerified = Notification.Name("FirefoxAccountVerifiedNotification") + +// MARK: Notification UserInfo Keys +public let NotificationUserInfoKeyHasSyncableAccount = Notification.Name("NotificationUserInfoKeyHasSyncableAccount") + +public let NotificationDidRestoreSession = Notification.Name("NotificationDidRestoreSession") diff --git a/mobile/ios/Shared/Prefs.swift b/mobile/ios/Shared/Prefs.swift new file mode 100644 index 0000000000..39a12be94b --- /dev/null +++ b/mobile/ios/Shared/Prefs.swift @@ -0,0 +1,193 @@ +/* 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/. */ + +import Foundation + +public struct PrefsKeys { + public static let KeyLastRemoteTabSyncTime = "lastRemoteTabSyncTime" + public static let KeyLastSyncFinishTime = "lastSyncFinishTime" + public static let KeyDefaultHomePageURL = "KeyDefaultHomePageURL" + public static let KeyNoImageModeStatus = "NoImageModeStatus" + public static let KeyNightModeButtonIsInMenu = "NightModeButtonIsInMenuPrefKey" + public static let KeyNightModeStatus = "NightModeStatus" + public static let KeyMailToOption = "MailToOption" + public static let HasFocusInstalled = "HasFocusInstalled" + public static let HasPocketInstalled = "HasPocketInstalled" + + //Activity Stream + public static let KeyTopSitesCacheIsValid = "topSitesCacheIsValid" + public static let KeyTopSitesCacheSize = "topSitesCacheSize" + public static let KeyNewTab = "NewTabPrefKey" + public static let ASPocketStoriesVisible = "ASPocketStoriesVisible" + public static let ASRecentHighlightsVisible = "ASRecentHighlightsVisible" + public static let ASBookmarkHighlightsVisible = "ASBookmarkHighlightsVisible" + public static let ASLastInvalidation = "ASLastInvalidation" + + public static let KeyUseCustomSyncService = "useCustomSyncService" + public static let KeyCustomSyncToken = "customSyncTokenServer" + public static let KeyCustomSyncProfile = "customSyncProfileServer" + public static let KeyCustomSyncOauth = "customSyncOauthServer" + public static let KeyCustomSyncAuth = "customSyncAuthServer" + public static let KeyCustomSyncWeb = "customSyncWebServer" + +} + +public struct PrefsDefaults { + public static let ChineseHomePageURL = "http://mobile.firefoxchina.cn/" + public static let ChineseNewTabDefault = "HomePage" +} + +public protocol Prefs { + func getBranchPrefix() -> String + func branch(_ branch: String) -> Prefs + func setTimestamp(_ value: Timestamp, forKey defaultName: String) + func setLong(_ value: UInt64, forKey defaultName: String) + func setLong(_ value: Int64, forKey defaultName: String) + func setInt(_ value: Int32, forKey defaultName: String) + func setString(_ value: String, forKey defaultName: String) + func setBool(_ value: Bool, forKey defaultName: String) + func setObject(_ value: Any?, forKey defaultName: String) + func stringForKey(_ defaultName: String) -> String? + func objectForKey(_ defaultName: String) -> T? + func boolForKey(_ defaultName: String) -> Bool? + func intForKey(_ defaultName: String) -> Int32? + func timestampForKey(_ defaultName: String) -> Timestamp? + func longForKey(_ defaultName: String) -> Int64? + func unsignedLongForKey(_ defaultName: String) -> UInt64? + func stringArrayForKey(_ defaultName: String) -> [String]? + func arrayForKey(_ defaultName: String) -> [Any]? + func dictionaryForKey(_ defaultName: String) -> [String: Any]? + func removeObjectForKey(_ defaultName: String) + func clearAll() +} + +open class MockProfilePrefs: Prefs { + let prefix: String + + open func getBranchPrefix() -> String { + return self.prefix + } + + // Public for testing. + open var things: NSMutableDictionary = NSMutableDictionary() + + public init(things: NSMutableDictionary, prefix: String) { + self.things = things + self.prefix = prefix + } + + public init() { + self.prefix = "" + } + + open func branch(_ branch: String) -> Prefs { + return MockProfilePrefs(things: self.things, prefix: self.prefix + branch + ".") + } + + private func name(_ name: String) -> String { + return self.prefix + name + } + + open func setTimestamp(_ value: Timestamp, forKey defaultName: String) { + self.setLong(value, forKey: defaultName) + } + + open func setLong(_ value: UInt64, forKey defaultName: String) { + setObject(NSNumber(value: value as UInt64), forKey: defaultName) + } + + open func setLong(_ value: Int64, forKey defaultName: String) { + setObject(NSNumber(value: value as Int64), forKey: defaultName) + } + + open func setInt(_ value: Int32, forKey defaultName: String) { + things[name(defaultName)] = NSNumber(value: value as Int32) + } + + open func setString(_ value: String, forKey defaultName: String) { + things[name(defaultName)] = value + } + + open func setBool(_ value: Bool, forKey defaultName: String) { + things[name(defaultName)] = value + } + + open func setObject(_ value: Any?, forKey defaultName: String) { + things[name(defaultName)] = value + } + + open func stringForKey(_ defaultName: String) -> String? { + return things[name(defaultName)] as? String + } + + open func boolForKey(_ defaultName: String) -> Bool? { + return things[name(defaultName)] as? Bool + } + + open func objectForKey(_ defaultName: String) -> T? { + return things[name(defaultName)] as? T + } + + open func timestampForKey(_ defaultName: String) -> Timestamp? { + return unsignedLongForKey(defaultName) + } + + open func unsignedLongForKey(_ defaultName: String) -> UInt64? { + let num = things[name(defaultName)] as? UInt64 + if let num = num { + return num + } + return nil + } + + open func longForKey(_ defaultName: String) -> Int64? { + let num = things[name(defaultName)] as? Int64 + if let num = num { + return num + } + return nil + } + + open func intForKey(_ defaultName: String) -> Int32? { + let num = things[name(defaultName)] as? Int32 + if let num = num { + return num + } + return nil + } + + open func stringArrayForKey(_ defaultName: String) -> [String]? { + if let arr = self.arrayForKey(defaultName) { + if let arr = arr as? [String] { + return arr + } + } + return nil + } + + open func arrayForKey(_ defaultName: String) -> [Any]? { + let r: Any? = things.object(forKey: name(defaultName)) as Any? + if r == nil { + return nil + } + if let arr = r as? [Any] { + return arr + } + return nil + } + + open func dictionaryForKey(_ defaultName: String) -> [String: Any]? { + return things.object(forKey: name(defaultName)) as? [String: Any] + } + + open func removeObjectForKey(_ defaultName: String) { + self.things.removeObject(forKey: name(defaultName)) + } + + open func clearAll() { + let dictionary = things as! [String: Any] + let keysToDelete: [String] = dictionary.keys.filter { $0.startsWith(self.prefix) } + things.removeObjects(forKeys: keysToDelete) + } +} diff --git a/mobile/ios/Shared/RemoteDevices.swift b/mobile/ios/Shared/RemoteDevices.swift new file mode 100644 index 0000000000..d8bcac60cb --- /dev/null +++ b/mobile/ios/Shared/RemoteDevices.swift @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +public protocol RemoteDevices { + func replaceRemoteDevices(_ remoteDevices: [RemoteDevice]) -> Success +} + +open class RemoteDevice { + public let id: String? + public let name: String + public let type: String? + public let isCurrentDevice: Bool + public let lastAccessTime: Timestamp? + + public init(id: String?, name: String, type: String?, isCurrentDevice: Bool, lastAccessTime: Timestamp?) { + self.id = id + self.name = name + self.type = type + self.isCurrentDevice = isCurrentDevice + self.lastAccessTime = lastAccessTime + } +} diff --git a/mobile/ios/Shared/RollingFileLogger.swift b/mobile/ios/Shared/RollingFileLogger.swift new file mode 100644 index 0000000000..a47f5ac713 --- /dev/null +++ b/mobile/ios/Shared/RollingFileLogger.swift @@ -0,0 +1,115 @@ +/* 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/. */ + +import Foundation +import XCGLogger + +//// A rolling file logger that saves to a different log file based on given timestamp. +open class RollingFileLogger: XCGLogger { + + fileprivate static let TwoMBsInBytes: Int64 = 2 * 100000 + fileprivate let sizeLimit: Int64 + fileprivate let logDirectoryPath: String? + + let fileLogIdentifierPrefix = "com.mozilla.firefox.filelogger." + + fileprivate static let DateFormatter: DateFormatter = { + let formatter = Foundation.DateFormatter() + formatter.dateFormat = "yyyyMMdd'T'HHmmssZ" + return formatter + }() + + let root: String + + public init(filenameRoot: String, logDirectoryPath: String?, sizeLimit: Int64 = TwoMBsInBytes) { + root = filenameRoot + self.sizeLimit = sizeLimit + self.logDirectoryPath = logDirectoryPath + super.init() + } + + /** + Create a new log file with the given timestamp to log events into + + :param: date Date for with to start and mark the new log file + */ + open func newLogWithDate(_ date: Date) { + // Don't start a log if we don't have a valid log directory path + if logDirectoryPath == nil { + return + } + + if let filename = filenameWithRoot(root, withDate: date) { + remove(destinationWithIdentifier: fileLogIdentifierWithRoot(root)) + add(destination: FileDestination(owner: self, writeToFile: filename, identifier: fileLogIdentifierWithRoot(root))) + info("Created file destination for logger with root: \(self.root) and timestamp: \(date)") + } else { + error("Failed to create a new log with root name: \(self.root) and timestamp: \(date)") + } + } + + open func deleteOldLogsDownToSizeLimit() { + // Check to see we haven't hit our size limit and if we did, clear out some logs to make room. + while sizeOfAllLogFilesWithPrefix(self.root, exceedsSizeInBytes: sizeLimit) { + deleteOldestLogWithPrefix(self.root) + } + } + + open func logFilenamesAndURLs() throws -> [(String, URL)] { + guard let logPath = logDirectoryPath else { + return [] + } + + let files = try FileManager.default.contentsOfDirectoryAtPath(logPath, withFilenamePrefix: root) + return files.flatMap { filename in + if let url = URL(string: "\(logPath)/\(filename)") { + return (filename, url) + } + return nil + } + } + + fileprivate func deleteOldestLogWithPrefix(_ prefix: String) { + if logDirectoryPath == nil { + return + } + + do { + let logFiles = try FileManager.default.contentsOfDirectoryAtPath(logDirectoryPath!, withFilenamePrefix: prefix) + if let oldestLogFilename = logFiles.first { + try FileManager.default.removeItem(atPath: "\(logDirectoryPath!)/\(oldestLogFilename)") + } + } catch _ as NSError { + error("Shouldn't get here") + return + } + } + + fileprivate func sizeOfAllLogFilesWithPrefix(_ prefix: String, exceedsSizeInBytes threshold: Int64) -> Bool { + guard let path = logDirectoryPath else { + return false + } + + let logDirURL = URL(fileURLWithPath: path) + do { + return try FileManager.default.allocatedSizeOfDirectoryAtURL(logDirURL, forFilesPrefixedWith: prefix, isLargerThanBytes: threshold) + } catch let errorValue as NSError { + error("Error determining log directory size: \(errorValue)") + } + + return false + } + + fileprivate func filenameWithRoot(_ root: String, withDate date: Date) -> String? { + if let dir = logDirectoryPath { + return "\(dir)/\(root).\(RollingFileLogger.DateFormatter.string(from: date)).log" + } + + return nil + } + + fileprivate func fileLogIdentifierWithRoot(_ root: String) -> String { + return "\(fileLogIdentifierPrefix).\(root)" + } +} diff --git a/mobile/ios/Shared/SentryIntegration.swift b/mobile/ios/Shared/SentryIntegration.swift new file mode 100644 index 0000000000..763c11fbc1 --- /dev/null +++ b/mobile/ios/Shared/SentryIntegration.swift @@ -0,0 +1,163 @@ +/* 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/. */ + +import Foundation +import Sentry + +public enum SentryTag: String { + case swiftData = "SwiftData" + case browserDB = "BrowserDB" + case notificationService = "NotificationService" + case unifiedTelemetry = "UnifiedTelemetry" + case general = "General" + case tabManager = "TabManager" + case bookmarks = "Bookmarks" +} + +public class Sentry { + public static let shared = Sentry() + + public static var crashedLastLaunch: Bool { + return Client.shared?.crashedLastLaunch() ?? false + } + + private let SentryDSNKey = "SentryDSN" + private let SentryDeviceAppHashKey = "SentryDeviceAppHash" + private let DefaultDeviceAppHash = "0000000000000000000000000000000000000000" + private let DeviceAppHashLength = UInt(20) + + private var enabled = false + + private var attributes: [String: Any] = [:] + + public func setup(sendUsageData: Bool) { + assert(!enabled, "Sentry.setup() should only be called once") + + if DeviceInfo.isSimulator() { + Logger.browserLogger.debug("Not enabling Sentry; Running in Simulator") + return + } + + if !sendUsageData { + Logger.browserLogger.debug("Not enabling Sentry; Not enabled by user choice") + return + } + + guard let dsn = Bundle.main.object(forInfoDictionaryKey: SentryDSNKey) as? String, !dsn.isEmpty else { + Logger.browserLogger.debug("Not enabling Sentry; Not configured in Info.plist") + return + } + + Logger.browserLogger.debug("Enabling Sentry crash handler") + + do { + Client.shared = try Client(dsn: dsn) + try Client.shared?.startCrashHandler() + enabled = true + + // If we have not already for this install, generate a completely random identifier + // for this device. It is stored in the app group so that the same value will + // be used for both the main application and the app extensions. + if let defaults = UserDefaults(suiteName: AppInfo.sharedContainerIdentifier), defaults.string(forKey: SentryDeviceAppHashKey) == nil { + defaults.set(Bytes.generateRandomBytes(DeviceAppHashLength).hexEncodedString, forKey: SentryDeviceAppHashKey) + defaults.synchronize() + } + + // For all outgoing reports, override the default device identifier with our own random + // version. Default to a blank (zero) identifier in case of errors. + Client.shared?.beforeSerializeEvent = { event in + let deviceAppHash = UserDefaults(suiteName: AppInfo.sharedContainerIdentifier)?.string(forKey: self.SentryDeviceAppHashKey) + event.context?.appContext?["device_app_hash"] = deviceAppHash ?? self.DefaultDeviceAppHash + + var attributes = event.extra ?? [:] + attributes.merge(with: self.attributes) + event.extra = attributes + } + } catch let error { + Logger.browserLogger.error("Failed to initialize Sentry: \(error)") + } + + } + + public func crash() { + Client.shared?.crash() + } + + /* + This is the behaviour we want for Sentry logging + .info .error .severe + Debug y y y + Beta y y y + Relase n n y + */ + private func shouldNotSendEventFor(_ severity: SentrySeverity) -> Bool { + return !enabled || (AppConstants.BuildChannel == .release && severity != .fatal) + } + + private func makeEvent(message: String, tag: String, severity: SentrySeverity, extra: [String: Any]?) -> Event { + let event = Event(level: severity) + event.message = message + event.tags = ["tag": tag] + if let extra = extra { + event.extra = extra + } + return event + } + + public func send(message: String, tag: SentryTag = .general, severity: SentrySeverity = .info, extra: [String: Any]? = nil, description: String? = nil, completion: SentryRequestFinished? = nil) { + // Build the dictionary + var extraEvents: [String: Any] = [:] + if let paramEvents = extra { + extraEvents.merge(with: paramEvents) + } + if let extraString = description { + extraEvents.merge(with: ["errorDescription": extraString]) + } + printMessage(message: message, extra: extraEvents) + + // Only report fatal errors on release + if shouldNotSendEventFor(severity) { + completion?(nil) + return + } + + let event = makeEvent(message: message, tag: tag.rawValue, severity: severity, extra: extraEvents) + Client.shared?.send(event: event, completion: completion) + } + + public func sendWithStacktrace(message: String, tag: SentryTag = .general, severity: SentrySeverity = .info, extra: [String: Any]? = nil, description: String? = nil, completion: SentryRequestFinished? = nil) { + var extraEvents: [String: Any] = [:] + if let paramEvents = extra { + extraEvents.merge(with: paramEvents) + } + if let extraString = description { + extraEvents.merge(with: ["errorDescription": extraString]) + } + printMessage(message: message, extra: extraEvents) + + // Do not send messages to Sentry if disabled OR if we are not on beta and the severity isnt severe + if shouldNotSendEventFor(severity) { + completion?(nil) + return + } + Client.shared?.snapshotStacktrace { + let event = self.makeEvent(message: message, tag: tag.rawValue, severity: severity, extra: extraEvents) + Client.shared?.appendStacktrace(to: event) + event.debugMeta = nil + Client.shared?.send(event: event, completion: completion) + } + } + + public func addAttributes(_ attributes: [String: Any]) { + self.attributes.merge(with: attributes) + } + + private func printMessage(message: String, extra: [String: Any]? = nil) { + let string = extra?.reduce("") { (result: String, arg1) in + let (key, value) = arg1 + return "\(result), \(key): \(value)" + } + Logger.browserLogger.debug("Sentry: \(message) \(string ??? "")") + } +} diff --git a/mobile/ios/Shared/Shared-Bridging-Header.h b/mobile/ios/Shared/Shared-Bridging-Header.h new file mode 100644 index 0000000000..3dafa01863 --- /dev/null +++ b/mobile/ios/Shared/Shared-Bridging-Header.h @@ -0,0 +1,9 @@ +#ifndef Client_Shared_Bridging_Header_h +#define Client_Shared_Bridging_Header_h + +#import +#import +#import "FSUtils.h" +#import "CrashSimulator.h" + +#endif diff --git a/mobile/ios/Shared/SupportUtils.swift b/mobile/ios/Shared/SupportUtils.swift new file mode 100644 index 0000000000..ef8f29d912 --- /dev/null +++ b/mobile/ios/Shared/SupportUtils.swift @@ -0,0 +1,21 @@ +/* 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/. */ + +import Foundation + +/// Utility functions related to SUMO. +public struct SupportUtils { + /// Construct a NSURL pointing to a specific topic on SUMO. The topic should be a non-escaped string. It will + /// be properly escaped by this function. + /// + /// The resulting NSURL will include the app version, operating system and locale code. For example, a topic + /// "cheese" will be turned into a link that looks like https://support.mozilla.org/1/mobile/2.0/iOS/en-US/cheese + public static func URLForTopic(_ topic: String) -> URL? { + guard let escapedTopic = topic.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlPathAllowed), + let languageIdentifier = Locale.preferredLanguages.first else { + return nil + } + return URL(string: "https://support.mozilla.org/1/mobile/\(AppInfo.appVersion)/iOS/\(languageIdentifier)/\(escapedTopic)") + } +} diff --git a/mobile/ios/Shared/Supporting Files/Info.plist b/mobile/ios/Shared/Supporting Files/Info.plist new file mode 100644 index 0000000000..b3205ecaf4 --- /dev/null +++ b/mobile/ios/Shared/Supporting Files/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/mobile/ios/Shared/SystemUtils.swift b/mobile/ios/Shared/SystemUtils.swift new file mode 100644 index 0000000000..e7621e2626 --- /dev/null +++ b/mobile/ios/Shared/SystemUtils.swift @@ -0,0 +1,69 @@ +/* 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/. */ + +import Foundation + +/** + * System helper methods written in Swift. + */ +public struct SystemUtils { + + /** + Returns an accurate version of the system uptime even while the device is asleep. + http://stackoverflow.com/questions/12488481/getting-ios-system-uptime-that-doesnt-pause-when-asleep + + - returns: Time interval since last reboot. + */ + public static func systemUptime() -> TimeInterval { + var boottime = timeval() + var mib = [CTL_KERN, KERN_BOOTTIME] + var size = MemoryLayout.stride + var now = time_t() + time(&now) + + sysctl(&mib, u_int(mib.count), &boottime, &size, nil, 0) + let tv_sec: time_t = withUnsafePointer(to: &boottime.tv_sec) { $0.pointee } + return TimeInterval(now - tv_sec) + } +} + +extension SystemUtils { + // This should be run on first run of the application. + // It shouldn't be run from an extension. + // Its function is to write a lock file that is only accessible from the application, + // and not accessible from extension when the device is locked. Thus, we can tell if an extension is being run + // when the device is locked. + public static func onFirstRun() { + guard let lockFileURL = lockedDeviceURL else { + return + } + + let lockFile = lockFileURL.path + let fm = FileManager.default + if fm.fileExists(atPath: lockFile) { + return + } + let contents = "Device is unlocked".data(using: String.Encoding.utf8) + fm.createFile(atPath: lockFile, contents: contents, attributes: [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) + } + + private static var lockedDeviceURL: URL? { + let directoryURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: AppInfo.sharedContainerIdentifier) + return directoryURL?.appendingPathComponent("security.dummy") + } + + public static func isDeviceLocked() -> Bool { + guard let lockFileURL = lockedDeviceURL else { + return true + } + do { + _ = try Data(contentsOf: lockFileURL, options: .mappedIfSafe) + return false + } catch let err as NSError { + return err.code == 257 + } catch _ { + return true + } + } +} diff --git a/mobile/ios/Shared/TimeConstants.swift b/mobile/ios/Shared/TimeConstants.swift new file mode 100644 index 0000000000..0c1c81afd4 --- /dev/null +++ b/mobile/ios/Shared/TimeConstants.swift @@ -0,0 +1,172 @@ +/* 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/. */ + +import Foundation + +public typealias Timestamp = UInt64 +public typealias MicrosecondTimestamp = UInt64 + +public let ThreeWeeksInSeconds = 3 * 7 * 24 * 60 * 60 + +public let OneYearInMilliseconds = 12 * OneMonthInMilliseconds +public let OneMonthInMilliseconds = 30 * OneDayInMilliseconds +public let OneWeekInMilliseconds = 7 * OneDayInMilliseconds +public let OneDayInMilliseconds = 24 * OneHourInMilliseconds +public let OneHourInMilliseconds = 60 * OneMinuteInMilliseconds +public let OneMinuteInMilliseconds = 60 * OneSecondInMilliseconds +public let OneSecondInMilliseconds: UInt64 = 1000 + +fileprivate let rfc822DateFormatter: DateFormatter = { + let dateFormatter = DateFormatter() + dateFormatter.timeZone = TimeZone(abbreviation: "GMT") + dateFormatter.dateFormat = "EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'" + dateFormatter.locale = Locale(identifier: "en_US") + return dateFormatter +}() + +extension Timestamp { + public static func uptimeInMilliseconds() -> Timestamp { + return Timestamp(DispatchTime.now().uptimeNanoseconds) / 1000000 + } +} + +extension Date { + public static func now() -> Timestamp { + return UInt64(1000 * Date().timeIntervalSince1970) + } + + public static func nowNumber() -> NSNumber { + return NSNumber(value: now() as UInt64) + } + + public static func nowMicroseconds() -> MicrosecondTimestamp { + return UInt64(1000000 * Date().timeIntervalSince1970) + } + + public static func fromTimestamp(_ timestamp: Timestamp) -> Date { + return Date(timeIntervalSince1970: Double(timestamp) / 1000) + } + + public static func fromMicrosecondTimestamp(_ microsecondTimestamp: MicrosecondTimestamp) -> Date { + return Date(timeIntervalSince1970: Double(microsecondTimestamp) / 1000000) + } + + public func toRelativeTimeString() -> String { + let now = Date() + + let units: NSCalendar.Unit = [NSCalendar.Unit.second, NSCalendar.Unit.minute, NSCalendar.Unit.day, NSCalendar.Unit.weekOfYear, NSCalendar.Unit.month, NSCalendar.Unit.year, NSCalendar.Unit.hour] + + let components = (Calendar.current as NSCalendar).components(units, + from: self, + to: now, + options: []) + + if components.year! > 0 { + return String(format: DateFormatter.localizedString(from: self, dateStyle: DateFormatter.Style.short, timeStyle: DateFormatter.Style.short)) + } + + if components.month == 1 { + return String(format: NSLocalizedString("more than a month ago", comment: "Relative date for dates older than a month and less than two months.")) + } + + if components.month! > 1 { + return String(format: DateFormatter.localizedString(from: self, dateStyle: DateFormatter.Style.short, timeStyle: DateFormatter.Style.short)) + } + + if components.weekOfYear! > 0 { + return String(format: NSLocalizedString("more than a week ago", comment: "Description for a date more than a week ago, but less than a month ago.")) + } + + if components.day == 1 { + return String(format: NSLocalizedString("yesterday", comment: "Relative date for yesterday.")) + } + + if components.day! > 1 { + return String(format: NSLocalizedString("this week", comment: "Relative date for date in past week."), String(describing: components.day)) + } + + if components.hour! > 0 || components.minute! > 0 { + let absoluteTime = DateFormatter.localizedString(from: self, dateStyle: DateFormatter.Style.none, timeStyle: DateFormatter.Style.short) + let format = NSLocalizedString("today at %@", comment: "Relative date for date older than a minute.") + return String(format: format, absoluteTime) + } + + return String(format: NSLocalizedString("just now", comment: "Relative time for a tab that was visited within the last few moments.")) + } + + public func toRFC822String() -> String { + return rfc822DateFormatter.string(from: self) + } +} + +let MaxTimestampAsDouble: Double = Double(UInt64.max) + +/** This is just like decimalSecondsStringToTimestamp, but it looks for values that seem to be + * milliseconds and fixes them. That's necessary because Firefox for iOS <= 7.3 uploaded millis + * when seconds were expected. + */ +public func someKindOfTimestampStringToTimestamp(_ input: String) -> Timestamp? { + var double = 0.0 + if Scanner(string: input).scanDouble(&double) { + // This should never happen. Hah! + if double.isNaN || double.isInfinite { + return nil + } + + // `double` will be either huge or negatively huge on overflow, and 0 on underflow. + // We clamp to reasonable ranges. + if double < 0 { + return nil + } + + if double >= MaxTimestampAsDouble { + // Definitely not representable as a timestamp if the seconds are this large! + return nil + } + + if double > 1000000000000 { + // Oh, this was in milliseconds. + return Timestamp(double) + } + + let millis = double * 1000 + if millis >= MaxTimestampAsDouble { + // Not representable as a timestamp. + return nil + } + + return Timestamp(millis) + } + return nil +} + +public func decimalSecondsStringToTimestamp(_ input: String) -> Timestamp? { + var double = 0.0 + if Scanner(string: input).scanDouble(&double) { + // This should never happen. Hah! + if double.isNaN || double.isInfinite { + return nil + } + + // `double` will be either huge or negatively huge on overflow, and 0 on underflow. + // We clamp to reasonable ranges. + if double < 0 { + return nil + } + + let millis = double * 1000 + if millis >= MaxTimestampAsDouble { + // Not representable as a timestamp. + return nil + } + + return Timestamp(millis) + } + return nil +} + +public func millisecondsToDecimalSeconds(_ input: Timestamp) -> String { + let val: Double = Double(input) / 1000 + return String(format: "%.2F", val) +} diff --git a/mobile/ios/Shared/UserAgent.swift b/mobile/ios/Shared/UserAgent.swift new file mode 100644 index 0000000000..2459e5e987 --- /dev/null +++ b/mobile/ios/Shared/UserAgent.swift @@ -0,0 +1,131 @@ +/* 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/. */ + +import AVFoundation +import UIKit + +open class UserAgent { + private static var defaults = UserDefaults(suiteName: AppInfo.sharedContainerIdentifier)! + + private static func clientUserAgent(prefix: String) -> String { + return "\(prefix)/\(AppInfo.appVersion)b\(AppInfo.buildNumber) (\(DeviceInfo.deviceModel()); iPhone OS \(UIDevice.current.systemVersion)) (\(AppInfo.displayName))" + } + + open static var syncUserAgent: String { + return clientUserAgent(prefix: "Firefox-iOS-Sync") + } + + open static var tokenServerClientUserAgent: String { + return clientUserAgent(prefix: "Firefox-iOS-Token") + } + + open static var fxaUserAgent: String { + return clientUserAgent(prefix: "Firefox-iOS-FxA") + } + + open static var defaultClientUserAgent: String { + return clientUserAgent(prefix: "Firefox-iOS") + } + + /** + * Use this if you know that a value must have been computed before your + * code runs, or you don't mind failure. + */ + open static func cachedUserAgent(checkiOSVersion: Bool = true, + checkFirefoxVersion: Bool = true, + checkFirefoxBuildNumber: Bool = true) -> String? { + let currentiOSVersion = UIDevice.current.systemVersion + let lastiOSVersion = defaults.string(forKey: "LastDeviceSystemVersionNumber") + + let currentFirefoxBuildNumber = AppInfo.buildNumber + let currentFirefoxVersion = AppInfo.appVersion + let lastFirefoxVersion = defaults.string(forKey: "LastFirefoxVersionNumber") + let lastFirefoxBuildNumber = defaults.string(forKey: "LastFirefoxBuildNumber") + + if let firefoxUA = defaults.string(forKey: "UserAgent") { + if (!checkiOSVersion || (lastiOSVersion == currentiOSVersion)) + && (!checkFirefoxVersion || (lastFirefoxVersion == currentFirefoxVersion) + && (!checkFirefoxBuildNumber || (lastFirefoxBuildNumber == currentFirefoxBuildNumber))) { + return firefoxUA + } + } + + return nil + } + + /** + * This will typically return quickly, but can require creation of a UIWebView. + * As a result, it must be called on the UI thread. + */ + open static func defaultUserAgent() -> String { + assert(Thread.current.isMainThread, "This method must be called on the main thread.") + + if let firefoxUA = UserAgent.cachedUserAgent(checkiOSVersion: true) { + return firefoxUA + } + + let webView = UIWebView() + + let appVersion = AppInfo.appVersion + let buildNumber = AppInfo.buildNumber + let currentiOSVersion = UIDevice.current.systemVersion + defaults.set(currentiOSVersion, forKey: "LastDeviceSystemVersionNumber") + defaults.set(appVersion, forKey: "LastFirefoxVersionNumber") + defaults.set(buildNumber, forKey: "LastFirefoxBuildNumber") + + let userAgent = webView.stringByEvaluatingJavaScript(from: "navigator.userAgent")! + + // Extract the WebKit version and use it as the Safari version. + let webKitVersionRegex = try! NSRegularExpression(pattern: "AppleWebKit/([^ ]+) ", options: []) + + let match = webKitVersionRegex.firstMatch(in: userAgent, options: [], + range: NSRange(location: 0, length: userAgent.characters.count)) + + if match == nil { + print("Error: Unable to determine WebKit version in UA.") + return userAgent // Fall back to Safari's. + } + + let webKitVersion = (userAgent as NSString).substring(with: match!.rangeAt(1)) + + // Insert "FxiOS/" before the Mobile/ section. + let mobileRange = (userAgent as NSString).range(of: "Mobile/") + if mobileRange.location == NSNotFound { + print("Error: Unable to find Mobile section in UA.") + return userAgent // Fall back to Safari's. + } + + let mutableUA = NSMutableString(string: userAgent) + mutableUA.insert("FxiOS/\(appVersion)b\(AppInfo.buildNumber) ", at: mobileRange.location) + + let firefoxUA = "\(mutableUA) Safari/\(webKitVersion)" + + defaults.set(firefoxUA, forKey: "UserAgent") + + return firefoxUA + } + + open static func desktopUserAgent() -> String { + let userAgent = NSMutableString(string: defaultUserAgent()) + + // Spoof platform section + let platformRegex = try! NSRegularExpression(pattern: "\\([^\\)]+\\)", options: []) + guard let platformMatch = platformRegex.firstMatch(in: userAgent as String, options: [], range: NSRange(location: 0, length: userAgent.length)) else { + print("Error: Unable to determine platform in UA.") + return String(userAgent) + } + userAgent.replaceCharacters(in: platformMatch.range, with: "(Macintosh; Intel Mac OS X 10_11_1)") + + // Strip mobile section + let mobileRegex = try! NSRegularExpression(pattern: " FxiOS/[^ ]+ Mobile/[^ ]+", options: []) + + guard let mobileMatch = mobileRegex.firstMatch(in: userAgent as String, options: [], range: NSRange(location: 0, length: userAgent.length)) else { + print("Error: Unable to find Mobile section in UA.") + return String(userAgent) + } + userAgent.replaceCharacters(in: mobileMatch.range, with: "") + + return String(userAgent) + } +} diff --git a/mobile/ios/Shared/WeakList.swift b/mobile/ios/Shared/WeakList.swift new file mode 100644 index 0000000000..fb34cc3439 --- /dev/null +++ b/mobile/ios/Shared/WeakList.swift @@ -0,0 +1,64 @@ +/* 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/. */ + +import Foundation + +/** + * A list that weakly holds references to its items. + * Note that while the references themselves are cleared, their wrapper objects + * are not (though they are reused). Also note that since slots are reused, + * order is not preserved. + * + * This class crashes at runtime with EXC_BAD_ACCESS if a protocol is given as + * the type T. Make sure to use a class type. + */ +open class WeakList: Sequence { + private var items = [WeakRef]() + + public init() {} + + /** + * Adds an item to the list. + * Note that every insertion iterates through the list to find any "holes" (items that have + * been deallocated) to reuse them, so this class may not be appropriate in situations where + * insertion is frequent. + */ + open func insert(_ item: T) { + // Reuse any existing slots that have been deallocated. + for wrapper in items where wrapper.value == nil { + wrapper.value = item + return + } + + items.append(WeakRef(item)) + } + + open func makeIterator() -> AnyIterator { + var index = 0 + + return AnyIterator() { + if index >= self.items.count { + return nil + } + + for i in index.. { + public weak var value: T? + + public init(_ value: T) { + self.value = value + } +} diff --git a/mobile/ios/Shared/effective_tld_names.dat b/mobile/ios/Shared/effective_tld_names.dat new file mode 100644 index 0000000000..d5c9924ed5 --- /dev/null +++ b/mobile/ios/Shared/effective_tld_names.dat @@ -0,0 +1,10309 @@ +// 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/. + +// ===BEGIN ICANN DOMAINS=== + +// ac : http://en.wikipedia.org/wiki/.ac +ac +com.ac +edu.ac +gov.ac +net.ac +mil.ac +org.ac + +// ad : http://en.wikipedia.org/wiki/.ad +ad +nom.ad + +// ae : http://en.wikipedia.org/wiki/.ae +// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php +ae +co.ae +net.ae +org.ae +sch.ae +ac.ae +gov.ae +mil.ae + +// aero : see http://www.information.aero/index.php?id=66 +aero +accident-investigation.aero +accident-prevention.aero +aerobatic.aero +aeroclub.aero +aerodrome.aero +agents.aero +aircraft.aero +airline.aero +airport.aero +air-surveillance.aero +airtraffic.aero +air-traffic-control.aero +ambulance.aero +amusement.aero +association.aero +author.aero +ballooning.aero +broker.aero +caa.aero +cargo.aero +catering.aero +certification.aero +championship.aero +charter.aero +civilaviation.aero +club.aero +conference.aero +consultant.aero +consulting.aero +control.aero +council.aero +crew.aero +design.aero +dgca.aero +educator.aero +emergency.aero +engine.aero +engineer.aero +entertainment.aero +equipment.aero +exchange.aero +express.aero +federation.aero +flight.aero +freight.aero +fuel.aero +gliding.aero +government.aero +groundhandling.aero +group.aero +hanggliding.aero +homebuilt.aero +insurance.aero +journal.aero +journalist.aero +leasing.aero +logistics.aero +magazine.aero +maintenance.aero +marketplace.aero +media.aero +microlight.aero +modelling.aero +navigation.aero +parachuting.aero +paragliding.aero +passenger-association.aero +pilot.aero +press.aero +production.aero +recreation.aero +repbody.aero +res.aero +research.aero +rotorcraft.aero +safety.aero +scientist.aero +services.aero +show.aero +skydiving.aero +software.aero +student.aero +taxi.aero +trader.aero +trading.aero +trainer.aero +union.aero +workinggroup.aero +works.aero + +// af : http://www.nic.af/help.jsp +af +gov.af +com.af +org.af +net.af +edu.af + +// ag : http://www.nic.ag/prices.htm +ag +com.ag +org.ag +net.ag +co.ag +nom.ag + +// ai : http://nic.com.ai/ +ai +off.ai +com.ai +net.ai +org.ai + +// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 +al +com.al +edu.al +gov.al +mil.al +net.al +org.al + +// am : http://en.wikipedia.org/wiki/.am +am + +// an : http://www.una.an/an_domreg/default.asp +an +com.an +net.an +org.an +edu.an + +// ao : http://en.wikipedia.org/wiki/.ao +// http://www.dns.ao/REGISTR.DOC +ao +ed.ao +gv.ao +og.ao +co.ao +pb.ao +it.ao + +// aq : http://en.wikipedia.org/wiki/.aq +aq + +// ar : https://nic.ar/normativa-vigente.xhtml +ar +com.ar +edu.ar +gob.ar +gov.ar +int.ar +mil.ar +net.ar +org.ar +tur.ar + +// arpa : http://en.wikipedia.org/wiki/.arpa +// Confirmed by registry 2008-06-18 +arpa +e164.arpa +in-addr.arpa +ip6.arpa +iris.arpa +uri.arpa +urn.arpa + +// as : http://en.wikipedia.org/wiki/.as +as +gov.as + +// asia : http://en.wikipedia.org/wiki/.asia +asia + +// at : http://en.wikipedia.org/wiki/.at +// Confirmed by registry 2008-06-17 +at +ac.at +co.at +gv.at +or.at + +// au : http://en.wikipedia.org/wiki/.au +// http://www.auda.org.au/ +au +// 2LDs +com.au +net.au +org.au +edu.au +gov.au +asn.au +id.au +// Historic 2LDs (closed to new registration, but sites still exist) +info.au +conf.au +oz.au +// CGDNs - http://www.cgdn.org.au/ +act.au +nsw.au +nt.au +qld.au +sa.au +tas.au +vic.au +wa.au +// 3LDs +act.edu.au +nsw.edu.au +nt.edu.au +qld.edu.au +sa.edu.au +tas.edu.au +vic.edu.au +wa.edu.au +// act.gov.au Bug 984824 - Removed at request of Greg Tankard +// nsw.gov.au Bug 547985 - Removed at request of +// nt.gov.au Bug 940478 - Removed at request of Greg Connors +qld.gov.au +sa.gov.au +tas.gov.au +vic.gov.au +wa.gov.au + +// aw : http://en.wikipedia.org/wiki/.aw +aw +com.aw + +// ax : http://en.wikipedia.org/wiki/.ax +ax + +// az : http://en.wikipedia.org/wiki/.az +az +com.az +net.az +int.az +gov.az +org.az +edu.az +info.az +pp.az +mil.az +name.az +pro.az +biz.az + +// ba : http://en.wikipedia.org/wiki/.ba +ba +org.ba +net.ba +edu.ba +gov.ba +mil.ba +unsa.ba +unbi.ba +co.ba +com.ba +rs.ba + +// bb : http://en.wikipedia.org/wiki/.bb +bb +biz.bb +co.bb +com.bb +edu.bb +gov.bb +info.bb +net.bb +org.bb +store.bb +tv.bb + +// bd : http://en.wikipedia.org/wiki/.bd +*.bd + +// be : http://en.wikipedia.org/wiki/.be +// Confirmed by registry 2008-06-08 +be +ac.be + +// bf : http://en.wikipedia.org/wiki/.bf +bf +gov.bf + +// bg : http://en.wikipedia.org/wiki/.bg +// https://www.register.bg/user/static/rules/en/index.html +bg +a.bg +b.bg +c.bg +d.bg +e.bg +f.bg +g.bg +h.bg +i.bg +j.bg +k.bg +l.bg +m.bg +n.bg +o.bg +p.bg +q.bg +r.bg +s.bg +t.bg +u.bg +v.bg +w.bg +x.bg +y.bg +z.bg +0.bg +1.bg +2.bg +3.bg +4.bg +5.bg +6.bg +7.bg +8.bg +9.bg + +// bh : http://en.wikipedia.org/wiki/.bh +bh +com.bh +edu.bh +net.bh +org.bh +gov.bh + +// bi : http://en.wikipedia.org/wiki/.bi +// http://whois.nic.bi/ +bi +co.bi +com.bi +edu.bi +or.bi +org.bi + +// biz : http://en.wikipedia.org/wiki/.biz +biz + +// bj : http://en.wikipedia.org/wiki/.bj +bj +asso.bj +barreau.bj +gouv.bj + +// bm : http://www.bermudanic.bm/dnr-text.txt +bm +com.bm +edu.bm +gov.bm +net.bm +org.bm + +// bn : http://en.wikipedia.org/wiki/.bn +*.bn + +// bo : http://www.nic.bo/ +bo +com.bo +edu.bo +gov.bo +gob.bo +int.bo +org.bo +net.bo +mil.bo +tv.bo + +// br : http://registro.br/dominio/categoria.html +// Submitted by registry 2014-08-11 +br +adm.br +adv.br +agr.br +am.br +arq.br +art.br +ato.br +b.br +bio.br +blog.br +bmd.br +cim.br +cng.br +cnt.br +com.br +coop.br +ecn.br +eco.br +edu.br +emp.br +eng.br +esp.br +etc.br +eti.br +far.br +flog.br +fm.br +fnd.br +fot.br +fst.br +g12.br +ggf.br +gov.br +imb.br +ind.br +inf.br +jor.br +jus.br +leg.br +lel.br +mat.br +med.br +mil.br +mp.br +mus.br +net.br +*.nom.br +not.br +ntr.br +odo.br +org.br +ppg.br +pro.br +psc.br +psi.br +qsl.br +radio.br +rec.br +slg.br +srv.br +taxi.br +teo.br +tmp.br +trd.br +tur.br +tv.br +vet.br +vlog.br +wiki.br +zlg.br + +// bs : http://www.nic.bs/rules.html +bs +com.bs +net.bs +org.bs +edu.bs +gov.bs + +// bt : http://en.wikipedia.org/wiki/.bt +bt +com.bt +edu.bt +gov.bt +net.bt +org.bt + +// bv : No registrations at this time. +// Submitted by registry 2006-06-16 +bv + +// bw : http://en.wikipedia.org/wiki/.bw +// http://www.gobin.info/domainname/bw.doc +// list of other 2nd level tlds ? +bw +co.bw +org.bw + +// by : http://en.wikipedia.org/wiki/.by +// http://tld.by/rules_2006_en.html +// list of other 2nd level tlds ? +by +gov.by +mil.by +// Official information does not indicate that com.by is a reserved +// second-level domain, but it's being used as one (see www.google.com.by and +// www.yahoo.com.by, for example), so we list it here for safety's sake. +com.by + +// http://hoster.by/ +of.by + +// bz : http://en.wikipedia.org/wiki/.bz +// http://www.belizenic.bz/ +bz +com.bz +net.bz +org.bz +edu.bz +gov.bz + +// ca : http://en.wikipedia.org/wiki/.ca +ca +// ca geographical names +ab.ca +bc.ca +mb.ca +nb.ca +nf.ca +nl.ca +ns.ca +nt.ca +nu.ca +on.ca +pe.ca +qc.ca +sk.ca +yk.ca +// gc.ca: http://en.wikipedia.org/wiki/.gc.ca +// see also: http://registry.gc.ca/en/SubdomainFAQ +gc.ca + +// cat : http://en.wikipedia.org/wiki/.cat +cat + +// cc : http://en.wikipedia.org/wiki/.cc +cc + +// cd : http://en.wikipedia.org/wiki/.cd +// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 +cd +gov.cd + +// cf : http://en.wikipedia.org/wiki/.cf +cf + +// cg : http://en.wikipedia.org/wiki/.cg +cg + +// ch : http://en.wikipedia.org/wiki/.ch +ch + +// ci : http://en.wikipedia.org/wiki/.ci +// http://www.nic.ci/index.php?page=charte +ci +org.ci +or.ci +com.ci +co.ci +edu.ci +ed.ci +ac.ci +net.ci +go.ci +asso.ci +aéroport.ci +int.ci +presse.ci +md.ci +gouv.ci + +// ck : http://en.wikipedia.org/wiki/.ck +*.ck +!www.ck + +// cl : http://en.wikipedia.org/wiki/.cl +cl +gov.cl +gob.cl +co.cl +mil.cl + +// cm : http://en.wikipedia.org/wiki/.cm plus bug 981927 +cm +co.cm +com.cm +gov.cm +net.cm + +// cn : http://en.wikipedia.org/wiki/.cn +// Submitted by registry 2008-06-11 +cn +ac.cn +com.cn +edu.cn +gov.cn +net.cn +org.cn +mil.cn +公司.cn +网络.cn +網絡.cn +// cn geographic names +ah.cn +bj.cn +cq.cn +fj.cn +gd.cn +gs.cn +gz.cn +gx.cn +ha.cn +hb.cn +he.cn +hi.cn +hl.cn +hn.cn +jl.cn +js.cn +jx.cn +ln.cn +nm.cn +nx.cn +qh.cn +sc.cn +sd.cn +sh.cn +sn.cn +sx.cn +tj.cn +xj.cn +xz.cn +yn.cn +zj.cn +hk.cn +mo.cn +tw.cn + +// co : http://en.wikipedia.org/wiki/.co +// Submitted by registry 2008-06-11 +co +arts.co +com.co +edu.co +firm.co +gov.co +info.co +int.co +mil.co +net.co +nom.co +org.co +rec.co +web.co + +// com : http://en.wikipedia.org/wiki/.com +com + +// coop : http://en.wikipedia.org/wiki/.coop +coop + +// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do +cr +ac.cr +co.cr +ed.cr +fi.cr +go.cr +or.cr +sa.cr + +// cu : http://en.wikipedia.org/wiki/.cu +cu +com.cu +edu.cu +org.cu +net.cu +gov.cu +inf.cu + +// cv : http://en.wikipedia.org/wiki/.cv +cv + +// cw : http://www.una.cw/cw_registry/ +// Confirmed by registry 2013-03-26 +cw +com.cw +edu.cw +net.cw +org.cw + +// cx : http://en.wikipedia.org/wiki/.cx +// list of other 2nd level tlds ? +cx +gov.cx + +// cy : http://en.wikipedia.org/wiki/.cy +*.cy + +// cz : http://en.wikipedia.org/wiki/.cz +cz + +// de : http://en.wikipedia.org/wiki/.de +// Confirmed by registry (with technical +// reservations) 2008-07-01 +de + +// dj : http://en.wikipedia.org/wiki/.dj +dj + +// dk : http://en.wikipedia.org/wiki/.dk +// Confirmed by registry 2008-06-17 +dk + +// dm : http://en.wikipedia.org/wiki/.dm +dm +com.dm +net.dm +org.dm +edu.dm +gov.dm + +// do : http://en.wikipedia.org/wiki/.do +do +art.do +com.do +edu.do +gob.do +gov.do +mil.do +net.do +org.do +sld.do +web.do + +// dz : http://en.wikipedia.org/wiki/.dz +dz +com.dz +org.dz +net.dz +gov.dz +edu.dz +asso.dz +pol.dz +art.dz + +// ec : http://www.nic.ec/reg/paso1.asp +// Submitted by registry 2008-07-04 +ec +com.ec +info.ec +net.ec +fin.ec +k12.ec +med.ec +pro.ec +org.ec +edu.ec +gov.ec +gob.ec +mil.ec + +// edu : http://en.wikipedia.org/wiki/.edu +edu + +// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B +ee +edu.ee +gov.ee +riik.ee +lib.ee +med.ee +com.ee +pri.ee +aip.ee +org.ee +fie.ee + +// eg : http://en.wikipedia.org/wiki/.eg +eg +com.eg +edu.eg +eun.eg +gov.eg +mil.eg +name.eg +net.eg +org.eg +sci.eg + +// er : http://en.wikipedia.org/wiki/.er +*.er + +// es : https://www.nic.es/site_ingles/ingles/dominios/index.html +es +com.es +nom.es +org.es +gob.es +edu.es + +// et : http://en.wikipedia.org/wiki/.et +et +com.et +gov.et +org.et +edu.et +biz.et +name.et +info.et +net.et + +// eu : http://en.wikipedia.org/wiki/.eu +eu + +// fi : http://en.wikipedia.org/wiki/.fi +fi +// aland.fi : http://en.wikipedia.org/wiki/.ax +// This domain is being phased out in favor of .ax. As there are still many +// domains under aland.fi, we still keep it on the list until aland.fi is +// completely removed. +// TODO: Check for updates (expected to be phased out around Q1/2009) +aland.fi + +// fj : http://en.wikipedia.org/wiki/.fj +*.fj + +// fk : http://en.wikipedia.org/wiki/.fk +*.fk + +// fm : http://en.wikipedia.org/wiki/.fm +fm + +// fo : http://en.wikipedia.org/wiki/.fo +fo + +// fr : http://www.afnic.fr/ +// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs +fr +com.fr +asso.fr +nom.fr +prd.fr +presse.fr +tm.fr +// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels +aeroport.fr +assedic.fr +avocat.fr +avoues.fr +cci.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +geometre-expert.fr +gouv.fr +greta.fr +huissier-justice.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + +// ga : http://en.wikipedia.org/wiki/.ga +ga + +// gb : This registry is effectively dormant +// Submitted by registry 2008-06-12 +gb + +// gd : http://en.wikipedia.org/wiki/.gd +gd + +// ge : http://www.nic.net.ge/policy_en.pdf +ge +com.ge +edu.ge +gov.ge +org.ge +mil.ge +net.ge +pvt.ge + +// gf : http://en.wikipedia.org/wiki/.gf +gf + +// gg : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +gg +co.gg +net.gg +org.gg + +// gh : http://en.wikipedia.org/wiki/.gh +// see also: http://www.nic.gh/reg_now.php +// Although domains directly at second level are not possible at the moment, +// they have been possible for some time and may come back. +gh +com.gh +edu.gh +gov.gh +org.gh +mil.gh + +// gi : http://www.nic.gi/rules.html +gi +com.gi +ltd.gi +gov.gi +mod.gi +edu.gi +org.gi + +// gl : http://en.wikipedia.org/wiki/.gl +// http://nic.gl +gl +co.gl +com.gl +edu.gl +net.gl +org.gl + +// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm +gm + +// gn : http://psg.com/dns/gn/gn.txt +// Submitted by registry 2008-06-17 +gn +ac.gn +com.gn +edu.gn +gov.gn +org.gn +net.gn + +// gov : http://en.wikipedia.org/wiki/.gov +gov + +// gp : http://www.nic.gp/index.php?lang=en +gp +com.gp +net.gp +mobi.gp +edu.gp +org.gp +asso.gp + +// gq : http://en.wikipedia.org/wiki/.gq +gq + +// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html +// Submitted by registry 2008-06-09 +gr +com.gr +edu.gr +net.gr +org.gr +gov.gr + +// gs : http://en.wikipedia.org/wiki/.gs +gs + +// gt : http://www.gt/politicas_de_registro.html +gt +com.gt +edu.gt +gob.gt +ind.gt +mil.gt +net.gt +org.gt + +// gu : http://gadao.gov.gu/registration.txt +*.gu + +// gw : http://en.wikipedia.org/wiki/.gw +gw + +// gy : http://en.wikipedia.org/wiki/.gy +// http://registry.gy/ +gy +co.gy +com.gy +net.gy + +// hk : https://www.hkdnr.hk +// Submitted by registry 2008-06-11 +hk +com.hk +edu.hk +gov.hk +idv.hk +net.hk +org.hk +公司.hk +教育.hk +敎育.hk +政府.hk +個人.hk +个人.hk +箇人.hk +網络.hk +网络.hk +组織.hk +網絡.hk +网絡.hk +组织.hk +組織.hk +組织.hk + +// hm : http://en.wikipedia.org/wiki/.hm +hm + +// hn : http://www.nic.hn/politicas/ps02,,05.html +hn +com.hn +edu.hn +org.hn +net.hn +mil.hn +gob.hn + +// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf +hr +iz.hr +from.hr +name.hr +com.hr + +// ht : http://www.nic.ht/info/charte.cfm +ht +com.ht +shop.ht +firm.ht +info.ht +adult.ht +net.ht +pro.ht +org.ht +med.ht +art.ht +coop.ht +pol.ht +asso.ht +edu.ht +rel.ht +gouv.ht +perso.ht + +// hu : http://www.domain.hu/domain/English/sld.html +// Confirmed by registry 2008-06-12 +hu +co.hu +info.hu +org.hu +priv.hu +sport.hu +tm.hu +2000.hu +agrar.hu +bolt.hu +casino.hu +city.hu +erotica.hu +erotika.hu +film.hu +forum.hu +games.hu +hotel.hu +ingatlan.hu +jogasz.hu +konyvelo.hu +lakas.hu +media.hu +news.hu +reklam.hu +sex.hu +shop.hu +suli.hu +szex.hu +tozsde.hu +utazas.hu +video.hu + +// id : https://register.pandi.or.id/ +id +ac.id +biz.id +co.id +desa.id +go.id +mil.id +my.id +net.id +or.id +sch.id +web.id + +// ie : http://en.wikipedia.org/wiki/.ie +ie +gov.ie + +// il : http://en.wikipedia.org/wiki/.il +*.il + +// im : https://www.nic.im/ +// Submitted by registry 2013-11-15 +im +ac.im +co.im +com.im +ltd.co.im +net.im +org.im +plc.co.im +tt.im +tv.im + +// in : http://en.wikipedia.org/wiki/.in +// see also: https://registry.in/Policies +// Please note, that nic.in is not an offical eTLD, but used by most +// government institutions. +in +co.in +firm.in +net.in +org.in +gen.in +ind.in +nic.in +ac.in +edu.in +res.in +gov.in +mil.in + +// info : http://en.wikipedia.org/wiki/.info +info + +// int : http://en.wikipedia.org/wiki/.int +// Confirmed by registry 2008-06-18 +int +eu.int + +// io : http://www.nic.io/rules.html +// list of other 2nd level tlds ? +io +com.io + +// iq : http://www.cmc.iq/english/iq/iqregister1.htm +iq +gov.iq +edu.iq +mil.iq +com.iq +org.iq +net.iq + +// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules +// Also see http://www.nic.ir/Internationalized_Domain_Names +// Two .ir entries added at request of , 2010-04-16 +ir +ac.ir +co.ir +gov.ir +id.ir +net.ir +org.ir +sch.ir +// xn--mgba3a4f16a.ir (.ir, Persian YEH) +ایران.ir +// xn--mgba3a4fra.ir (.ir, Arabic YEH) +ايران.ir + +// is : http://www.isnic.is/domain/rules.php +// Confirmed by registry 2008-12-06 +is +net.is +com.is +edu.is +gov.is +org.is +int.is + +// it : http://en.wikipedia.org/wiki/.it +it +gov.it +edu.it +// Reserved geo-names: +// http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf +// There is also a list of reserved geo-names corresponding to Italian municipalities +// http://www.nic.it/documenti/appendice-c.pdf, but it is not included here. +// Regions +abr.it +abruzzo.it +aosta-valley.it +aostavalley.it +bas.it +basilicata.it +cal.it +calabria.it +cam.it +campania.it +emilia-romagna.it +emiliaromagna.it +emr.it +friuli-v-giulia.it +friuli-ve-giulia.it +friuli-vegiulia.it +friuli-venezia-giulia.it +friuli-veneziagiulia.it +friuli-vgiulia.it +friuliv-giulia.it +friulive-giulia.it +friulivegiulia.it +friulivenezia-giulia.it +friuliveneziagiulia.it +friulivgiulia.it +fvg.it +laz.it +lazio.it +lig.it +liguria.it +lom.it +lombardia.it +lombardy.it +lucania.it +mar.it +marche.it +mol.it +molise.it +piedmont.it +piemonte.it +pmn.it +pug.it +puglia.it +sar.it +sardegna.it +sardinia.it +sic.it +sicilia.it +sicily.it +taa.it +tos.it +toscana.it +trentino-a-adige.it +trentino-aadige.it +trentino-alto-adige.it +trentino-altoadige.it +trentino-s-tirol.it +trentino-stirol.it +trentino-sud-tirol.it +trentino-sudtirol.it +trentino-sued-tirol.it +trentino-suedtirol.it +trentinoa-adige.it +trentinoaadige.it +trentinoalto-adige.it +trentinoaltoadige.it +trentinos-tirol.it +trentinostirol.it +trentinosud-tirol.it +trentinosudtirol.it +trentinosued-tirol.it +trentinosuedtirol.it +tuscany.it +umb.it +umbria.it +val-d-aosta.it +val-daosta.it +vald-aosta.it +valdaosta.it +valle-aosta.it +valle-d-aosta.it +valle-daosta.it +valleaosta.it +valled-aosta.it +valledaosta.it +vallee-aoste.it +valleeaoste.it +vao.it +vda.it +ven.it +veneto.it +// Provinces +ag.it +agrigento.it +al.it +alessandria.it +alto-adige.it +altoadige.it +an.it +ancona.it +andria-barletta-trani.it +andria-trani-barletta.it +andriabarlettatrani.it +andriatranibarletta.it +ao.it +aosta.it +aoste.it +ap.it +aq.it +aquila.it +ar.it +arezzo.it +ascoli-piceno.it +ascolipiceno.it +asti.it +at.it +av.it +avellino.it +ba.it +balsan.it +bari.it +barletta-trani-andria.it +barlettatraniandria.it +belluno.it +benevento.it +bergamo.it +bg.it +bi.it +biella.it +bl.it +bn.it +bo.it +bologna.it +bolzano.it +bozen.it +br.it +brescia.it +brindisi.it +bs.it +bt.it +bz.it +ca.it +cagliari.it +caltanissetta.it +campidano-medio.it +campidanomedio.it +campobasso.it +carbonia-iglesias.it +carboniaiglesias.it +carrara-massa.it +carraramassa.it +caserta.it +catania.it +catanzaro.it +cb.it +ce.it +cesena-forli.it +cesenaforli.it +ch.it +chieti.it +ci.it +cl.it +cn.it +co.it +como.it +cosenza.it +cr.it +cremona.it +crotone.it +cs.it +ct.it +cuneo.it +cz.it +dell-ogliastra.it +dellogliastra.it +en.it +enna.it +fc.it +fe.it +fermo.it +ferrara.it +fg.it +fi.it +firenze.it +florence.it +fm.it +foggia.it +forli-cesena.it +forlicesena.it +fr.it +frosinone.it +ge.it +genoa.it +genova.it +go.it +gorizia.it +gr.it +grosseto.it +iglesias-carbonia.it +iglesiascarbonia.it +im.it +imperia.it +is.it +isernia.it +kr.it +la-spezia.it +laquila.it +laspezia.it +latina.it +lc.it +le.it +lecce.it +lecco.it +li.it +livorno.it +lo.it +lodi.it +lt.it +lu.it +lucca.it +macerata.it +mantova.it +massa-carrara.it +massacarrara.it +matera.it +mb.it +mc.it +me.it +medio-campidano.it +mediocampidano.it +messina.it +mi.it +milan.it +milano.it +mn.it +mo.it +modena.it +monza-brianza.it +monza-e-della-brianza.it +monza.it +monzabrianza.it +monzaebrianza.it +monzaedellabrianza.it +ms.it +mt.it +na.it +naples.it +napoli.it +no.it +novara.it +nu.it +nuoro.it +og.it +ogliastra.it +olbia-tempio.it +olbiatempio.it +or.it +oristano.it +ot.it +pa.it +padova.it +padua.it +palermo.it +parma.it +pavia.it +pc.it +pd.it +pe.it +perugia.it +pesaro-urbino.it +pesarourbino.it +pescara.it +pg.it +pi.it +piacenza.it +pisa.it +pistoia.it +pn.it +po.it +pordenone.it +potenza.it +pr.it +prato.it +pt.it +pu.it +pv.it +pz.it +ra.it +ragusa.it +ravenna.it +rc.it +re.it +reggio-calabria.it +reggio-emilia.it +reggiocalabria.it +reggioemilia.it +rg.it +ri.it +rieti.it +rimini.it +rm.it +rn.it +ro.it +roma.it +rome.it +rovigo.it +sa.it +salerno.it +sassari.it +savona.it +si.it +siena.it +siracusa.it +so.it +sondrio.it +sp.it +sr.it +ss.it +suedtirol.it +sv.it +ta.it +taranto.it +te.it +tempio-olbia.it +tempioolbia.it +teramo.it +terni.it +tn.it +to.it +torino.it +tp.it +tr.it +trani-andria-barletta.it +trani-barletta-andria.it +traniandriabarletta.it +tranibarlettaandria.it +trapani.it +trentino.it +trento.it +treviso.it +trieste.it +ts.it +turin.it +tv.it +ud.it +udine.it +urbino-pesaro.it +urbinopesaro.it +va.it +varese.it +vb.it +vc.it +ve.it +venezia.it +venice.it +verbania.it +vercelli.it +verona.it +vi.it +vibo-valentia.it +vibovalentia.it +vicenza.it +viterbo.it +vr.it +vs.it +vt.it +vv.it + +// je : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +je +co.je +net.je +org.je + +// jm : http://www.com.jm/register.html +*.jm + +// jo : http://www.dns.jo/Registration_policy.aspx +jo +com.jo +org.jo +net.jo +edu.jo +sch.jo +gov.jo +mil.jo +name.jo + +// jobs : http://en.wikipedia.org/wiki/.jobs +jobs + +// jp : http://en.wikipedia.org/wiki/.jp +// http://jprs.co.jp/en/jpdomain.html +// Submitted by registry 2014-10-30 +jp +// jp organizational type names +ac.jp +ad.jp +co.jp +ed.jp +go.jp +gr.jp +lg.jp +ne.jp +or.jp +// jp prefecture type names +aichi.jp +akita.jp +aomori.jp +chiba.jp +ehime.jp +fukui.jp +fukuoka.jp +fukushima.jp +gifu.jp +gunma.jp +hiroshima.jp +hokkaido.jp +hyogo.jp +ibaraki.jp +ishikawa.jp +iwate.jp +kagawa.jp +kagoshima.jp +kanagawa.jp +kochi.jp +kumamoto.jp +kyoto.jp +mie.jp +miyagi.jp +miyazaki.jp +nagano.jp +nagasaki.jp +nara.jp +niigata.jp +oita.jp +okayama.jp +okinawa.jp +osaka.jp +saga.jp +saitama.jp +shiga.jp +shimane.jp +shizuoka.jp +tochigi.jp +tokushima.jp +tokyo.jp +tottori.jp +toyama.jp +wakayama.jp +yamagata.jp +yamaguchi.jp +yamanashi.jp +栃木.jp +愛知.jp +愛媛.jp +兵庫.jp +熊本.jp +茨城.jp +北海道.jp +千葉.jp +和歌山.jp +長崎.jp +長野.jp +新潟.jp +青森.jp +静岡.jp +東京.jp +石川.jp +埼玉.jp +三重.jp +京都.jp +佐賀.jp +大分.jp +大阪.jp +奈良.jp +宮城.jp +宮崎.jp +富山.jp +山口.jp +山形.jp +山梨.jp +岩手.jp +岐阜.jp +岡山.jp +島根.jp +広島.jp +徳島.jp +沖縄.jp +滋賀.jp +神奈川.jp +福井.jp +福岡.jp +福島.jp +秋田.jp +群馬.jp +香川.jp +高知.jp +鳥取.jp +鹿児島.jp +// jp geographic type names +// http://jprs.jp/doc/rule/saisoku-1.html +*.kawasaki.jp +*.kitakyushu.jp +*.kobe.jp +*.nagoya.jp +*.sapporo.jp +*.sendai.jp +*.yokohama.jp +!city.kawasaki.jp +!city.kitakyushu.jp +!city.kobe.jp +!city.nagoya.jp +!city.sapporo.jp +!city.sendai.jp +!city.yokohama.jp +// 4th level registration +aisai.aichi.jp +ama.aichi.jp +anjo.aichi.jp +asuke.aichi.jp +chiryu.aichi.jp +chita.aichi.jp +fuso.aichi.jp +gamagori.aichi.jp +handa.aichi.jp +hazu.aichi.jp +hekinan.aichi.jp +higashiura.aichi.jp +ichinomiya.aichi.jp +inazawa.aichi.jp +inuyama.aichi.jp +isshiki.aichi.jp +iwakura.aichi.jp +kanie.aichi.jp +kariya.aichi.jp +kasugai.aichi.jp +kira.aichi.jp +kiyosu.aichi.jp +komaki.aichi.jp +konan.aichi.jp +kota.aichi.jp +mihama.aichi.jp +miyoshi.aichi.jp +nishio.aichi.jp +nisshin.aichi.jp +obu.aichi.jp +oguchi.aichi.jp +oharu.aichi.jp +okazaki.aichi.jp +owariasahi.aichi.jp +seto.aichi.jp +shikatsu.aichi.jp +shinshiro.aichi.jp +shitara.aichi.jp +tahara.aichi.jp +takahama.aichi.jp +tobishima.aichi.jp +toei.aichi.jp +togo.aichi.jp +tokai.aichi.jp +tokoname.aichi.jp +toyoake.aichi.jp +toyohashi.aichi.jp +toyokawa.aichi.jp +toyone.aichi.jp +toyota.aichi.jp +tsushima.aichi.jp +yatomi.aichi.jp +akita.akita.jp +daisen.akita.jp +fujisato.akita.jp +gojome.akita.jp +hachirogata.akita.jp +happou.akita.jp +higashinaruse.akita.jp +honjo.akita.jp +honjyo.akita.jp +ikawa.akita.jp +kamikoani.akita.jp +kamioka.akita.jp +katagami.akita.jp +kazuno.akita.jp +kitaakita.akita.jp +kosaka.akita.jp +kyowa.akita.jp +misato.akita.jp +mitane.akita.jp +moriyoshi.akita.jp +nikaho.akita.jp +noshiro.akita.jp +odate.akita.jp +oga.akita.jp +ogata.akita.jp +semboku.akita.jp +yokote.akita.jp +yurihonjo.akita.jp +aomori.aomori.jp +gonohe.aomori.jp +hachinohe.aomori.jp +hashikami.aomori.jp +hiranai.aomori.jp +hirosaki.aomori.jp +itayanagi.aomori.jp +kuroishi.aomori.jp +misawa.aomori.jp +mutsu.aomori.jp +nakadomari.aomori.jp +noheji.aomori.jp +oirase.aomori.jp +owani.aomori.jp +rokunohe.aomori.jp +sannohe.aomori.jp +shichinohe.aomori.jp +shingo.aomori.jp +takko.aomori.jp +towada.aomori.jp +tsugaru.aomori.jp +tsuruta.aomori.jp +abiko.chiba.jp +asahi.chiba.jp +chonan.chiba.jp +chosei.chiba.jp +choshi.chiba.jp +chuo.chiba.jp +funabashi.chiba.jp +futtsu.chiba.jp +hanamigawa.chiba.jp +ichihara.chiba.jp +ichikawa.chiba.jp +ichinomiya.chiba.jp +inzai.chiba.jp +isumi.chiba.jp +kamagaya.chiba.jp +kamogawa.chiba.jp +kashiwa.chiba.jp +katori.chiba.jp +katsuura.chiba.jp +kimitsu.chiba.jp +kisarazu.chiba.jp +kozaki.chiba.jp +kujukuri.chiba.jp +kyonan.chiba.jp +matsudo.chiba.jp +midori.chiba.jp +mihama.chiba.jp +minamiboso.chiba.jp +mobara.chiba.jp +mutsuzawa.chiba.jp +nagara.chiba.jp +nagareyama.chiba.jp +narashino.chiba.jp +narita.chiba.jp +noda.chiba.jp +oamishirasato.chiba.jp +omigawa.chiba.jp +onjuku.chiba.jp +otaki.chiba.jp +sakae.chiba.jp +sakura.chiba.jp +shimofusa.chiba.jp +shirako.chiba.jp +shiroi.chiba.jp +shisui.chiba.jp +sodegaura.chiba.jp +sosa.chiba.jp +tako.chiba.jp +tateyama.chiba.jp +togane.chiba.jp +tohnosho.chiba.jp +tomisato.chiba.jp +urayasu.chiba.jp +yachimata.chiba.jp +yachiyo.chiba.jp +yokaichiba.chiba.jp +yokoshibahikari.chiba.jp +yotsukaido.chiba.jp +ainan.ehime.jp +honai.ehime.jp +ikata.ehime.jp +imabari.ehime.jp +iyo.ehime.jp +kamijima.ehime.jp +kihoku.ehime.jp +kumakogen.ehime.jp +masaki.ehime.jp +matsuno.ehime.jp +matsuyama.ehime.jp +namikata.ehime.jp +niihama.ehime.jp +ozu.ehime.jp +saijo.ehime.jp +seiyo.ehime.jp +shikokuchuo.ehime.jp +tobe.ehime.jp +toon.ehime.jp +uchiko.ehime.jp +uwajima.ehime.jp +yawatahama.ehime.jp +echizen.fukui.jp +eiheiji.fukui.jp +fukui.fukui.jp +ikeda.fukui.jp +katsuyama.fukui.jp +mihama.fukui.jp +minamiechizen.fukui.jp +obama.fukui.jp +ohi.fukui.jp +ono.fukui.jp +sabae.fukui.jp +sakai.fukui.jp +takahama.fukui.jp +tsuruga.fukui.jp +wakasa.fukui.jp +ashiya.fukuoka.jp +buzen.fukuoka.jp +chikugo.fukuoka.jp +chikuho.fukuoka.jp +chikujo.fukuoka.jp +chikushino.fukuoka.jp +chikuzen.fukuoka.jp +chuo.fukuoka.jp +dazaifu.fukuoka.jp +fukuchi.fukuoka.jp +hakata.fukuoka.jp +higashi.fukuoka.jp +hirokawa.fukuoka.jp +hisayama.fukuoka.jp +iizuka.fukuoka.jp +inatsuki.fukuoka.jp +kaho.fukuoka.jp +kasuga.fukuoka.jp +kasuya.fukuoka.jp +kawara.fukuoka.jp +keisen.fukuoka.jp +koga.fukuoka.jp +kurate.fukuoka.jp +kurogi.fukuoka.jp +kurume.fukuoka.jp +minami.fukuoka.jp +miyako.fukuoka.jp +miyama.fukuoka.jp +miyawaka.fukuoka.jp +mizumaki.fukuoka.jp +munakata.fukuoka.jp +nakagawa.fukuoka.jp +nakama.fukuoka.jp +nishi.fukuoka.jp +nogata.fukuoka.jp +ogori.fukuoka.jp +okagaki.fukuoka.jp +okawa.fukuoka.jp +oki.fukuoka.jp +omuta.fukuoka.jp +onga.fukuoka.jp +onojo.fukuoka.jp +oto.fukuoka.jp +saigawa.fukuoka.jp +sasaguri.fukuoka.jp +shingu.fukuoka.jp +shinyoshitomi.fukuoka.jp +shonai.fukuoka.jp +soeda.fukuoka.jp +sue.fukuoka.jp +tachiarai.fukuoka.jp +tagawa.fukuoka.jp +takata.fukuoka.jp +toho.fukuoka.jp +toyotsu.fukuoka.jp +tsuiki.fukuoka.jp +ukiha.fukuoka.jp +umi.fukuoka.jp +usui.fukuoka.jp +yamada.fukuoka.jp +yame.fukuoka.jp +yanagawa.fukuoka.jp +yukuhashi.fukuoka.jp +aizubange.fukushima.jp +aizumisato.fukushima.jp +aizuwakamatsu.fukushima.jp +asakawa.fukushima.jp +bandai.fukushima.jp +date.fukushima.jp +fukushima.fukushima.jp +furudono.fukushima.jp +futaba.fukushima.jp +hanawa.fukushima.jp +higashi.fukushima.jp +hirata.fukushima.jp +hirono.fukushima.jp +iitate.fukushima.jp +inawashiro.fukushima.jp +ishikawa.fukushima.jp +iwaki.fukushima.jp +izumizaki.fukushima.jp +kagamiishi.fukushima.jp +kaneyama.fukushima.jp +kawamata.fukushima.jp +kitakata.fukushima.jp +kitashiobara.fukushima.jp +koori.fukushima.jp +koriyama.fukushima.jp +kunimi.fukushima.jp +miharu.fukushima.jp +mishima.fukushima.jp +namie.fukushima.jp +nango.fukushima.jp +nishiaizu.fukushima.jp +nishigo.fukushima.jp +okuma.fukushima.jp +omotego.fukushima.jp +ono.fukushima.jp +otama.fukushima.jp +samegawa.fukushima.jp +shimogo.fukushima.jp +shirakawa.fukushima.jp +showa.fukushima.jp +soma.fukushima.jp +sukagawa.fukushima.jp +taishin.fukushima.jp +tamakawa.fukushima.jp +tanagura.fukushima.jp +tenei.fukushima.jp +yabuki.fukushima.jp +yamato.fukushima.jp +yamatsuri.fukushima.jp +yanaizu.fukushima.jp +yugawa.fukushima.jp +anpachi.gifu.jp +ena.gifu.jp +gifu.gifu.jp +ginan.gifu.jp +godo.gifu.jp +gujo.gifu.jp +hashima.gifu.jp +hichiso.gifu.jp +hida.gifu.jp +higashishirakawa.gifu.jp +ibigawa.gifu.jp +ikeda.gifu.jp +kakamigahara.gifu.jp +kani.gifu.jp +kasahara.gifu.jp +kasamatsu.gifu.jp +kawaue.gifu.jp +kitagata.gifu.jp +mino.gifu.jp +minokamo.gifu.jp +mitake.gifu.jp +mizunami.gifu.jp +motosu.gifu.jp +nakatsugawa.gifu.jp +ogaki.gifu.jp +sakahogi.gifu.jp +seki.gifu.jp +sekigahara.gifu.jp +shirakawa.gifu.jp +tajimi.gifu.jp +takayama.gifu.jp +tarui.gifu.jp +toki.gifu.jp +tomika.gifu.jp +wanouchi.gifu.jp +yamagata.gifu.jp +yaotsu.gifu.jp +yoro.gifu.jp +annaka.gunma.jp +chiyoda.gunma.jp +fujioka.gunma.jp +higashiagatsuma.gunma.jp +isesaki.gunma.jp +itakura.gunma.jp +kanna.gunma.jp +kanra.gunma.jp +katashina.gunma.jp +kawaba.gunma.jp +kiryu.gunma.jp +kusatsu.gunma.jp +maebashi.gunma.jp +meiwa.gunma.jp +midori.gunma.jp +minakami.gunma.jp +naganohara.gunma.jp +nakanojo.gunma.jp +nanmoku.gunma.jp +numata.gunma.jp +oizumi.gunma.jp +ora.gunma.jp +ota.gunma.jp +shibukawa.gunma.jp +shimonita.gunma.jp +shinto.gunma.jp +showa.gunma.jp +takasaki.gunma.jp +takayama.gunma.jp +tamamura.gunma.jp +tatebayashi.gunma.jp +tomioka.gunma.jp +tsukiyono.gunma.jp +tsumagoi.gunma.jp +ueno.gunma.jp +yoshioka.gunma.jp +asaminami.hiroshima.jp +daiwa.hiroshima.jp +etajima.hiroshima.jp +fuchu.hiroshima.jp +fukuyama.hiroshima.jp +hatsukaichi.hiroshima.jp +higashihiroshima.hiroshima.jp +hongo.hiroshima.jp +jinsekikogen.hiroshima.jp +kaita.hiroshima.jp +kui.hiroshima.jp +kumano.hiroshima.jp +kure.hiroshima.jp +mihara.hiroshima.jp +miyoshi.hiroshima.jp +naka.hiroshima.jp +onomichi.hiroshima.jp +osakikamijima.hiroshima.jp +otake.hiroshima.jp +saka.hiroshima.jp +sera.hiroshima.jp +seranishi.hiroshima.jp +shinichi.hiroshima.jp +shobara.hiroshima.jp +takehara.hiroshima.jp +abashiri.hokkaido.jp +abira.hokkaido.jp +aibetsu.hokkaido.jp +akabira.hokkaido.jp +akkeshi.hokkaido.jp +asahikawa.hokkaido.jp +ashibetsu.hokkaido.jp +ashoro.hokkaido.jp +assabu.hokkaido.jp +atsuma.hokkaido.jp +bibai.hokkaido.jp +biei.hokkaido.jp +bifuka.hokkaido.jp +bihoro.hokkaido.jp +biratori.hokkaido.jp +chippubetsu.hokkaido.jp +chitose.hokkaido.jp +date.hokkaido.jp +ebetsu.hokkaido.jp +embetsu.hokkaido.jp +eniwa.hokkaido.jp +erimo.hokkaido.jp +esan.hokkaido.jp +esashi.hokkaido.jp +fukagawa.hokkaido.jp +fukushima.hokkaido.jp +furano.hokkaido.jp +furubira.hokkaido.jp +haboro.hokkaido.jp +hakodate.hokkaido.jp +hamatonbetsu.hokkaido.jp +hidaka.hokkaido.jp +higashikagura.hokkaido.jp +higashikawa.hokkaido.jp +hiroo.hokkaido.jp +hokuryu.hokkaido.jp +hokuto.hokkaido.jp +honbetsu.hokkaido.jp +horokanai.hokkaido.jp +horonobe.hokkaido.jp +ikeda.hokkaido.jp +imakane.hokkaido.jp +ishikari.hokkaido.jp +iwamizawa.hokkaido.jp +iwanai.hokkaido.jp +kamifurano.hokkaido.jp +kamikawa.hokkaido.jp +kamishihoro.hokkaido.jp +kamisunagawa.hokkaido.jp +kamoenai.hokkaido.jp +kayabe.hokkaido.jp +kembuchi.hokkaido.jp +kikonai.hokkaido.jp +kimobetsu.hokkaido.jp +kitahiroshima.hokkaido.jp +kitami.hokkaido.jp +kiyosato.hokkaido.jp +koshimizu.hokkaido.jp +kunneppu.hokkaido.jp +kuriyama.hokkaido.jp +kuromatsunai.hokkaido.jp +kushiro.hokkaido.jp +kutchan.hokkaido.jp +kyowa.hokkaido.jp +mashike.hokkaido.jp +matsumae.hokkaido.jp +mikasa.hokkaido.jp +minamifurano.hokkaido.jp +mombetsu.hokkaido.jp +moseushi.hokkaido.jp +mukawa.hokkaido.jp +muroran.hokkaido.jp +naie.hokkaido.jp +nakagawa.hokkaido.jp +nakasatsunai.hokkaido.jp +nakatombetsu.hokkaido.jp +nanae.hokkaido.jp +nanporo.hokkaido.jp +nayoro.hokkaido.jp +nemuro.hokkaido.jp +niikappu.hokkaido.jp +niki.hokkaido.jp +nishiokoppe.hokkaido.jp +noboribetsu.hokkaido.jp +numata.hokkaido.jp +obihiro.hokkaido.jp +obira.hokkaido.jp +oketo.hokkaido.jp +okoppe.hokkaido.jp +otaru.hokkaido.jp +otobe.hokkaido.jp +otofuke.hokkaido.jp +otoineppu.hokkaido.jp +oumu.hokkaido.jp +ozora.hokkaido.jp +pippu.hokkaido.jp +rankoshi.hokkaido.jp +rebun.hokkaido.jp +rikubetsu.hokkaido.jp +rishiri.hokkaido.jp +rishirifuji.hokkaido.jp +saroma.hokkaido.jp +sarufutsu.hokkaido.jp +shakotan.hokkaido.jp +shari.hokkaido.jp +shibecha.hokkaido.jp +shibetsu.hokkaido.jp +shikabe.hokkaido.jp +shikaoi.hokkaido.jp +shimamaki.hokkaido.jp +shimizu.hokkaido.jp +shimokawa.hokkaido.jp +shinshinotsu.hokkaido.jp +shintoku.hokkaido.jp +shiranuka.hokkaido.jp +shiraoi.hokkaido.jp +shiriuchi.hokkaido.jp +sobetsu.hokkaido.jp +sunagawa.hokkaido.jp +taiki.hokkaido.jp +takasu.hokkaido.jp +takikawa.hokkaido.jp +takinoue.hokkaido.jp +teshikaga.hokkaido.jp +tobetsu.hokkaido.jp +tohma.hokkaido.jp +tomakomai.hokkaido.jp +tomari.hokkaido.jp +toya.hokkaido.jp +toyako.hokkaido.jp +toyotomi.hokkaido.jp +toyoura.hokkaido.jp +tsubetsu.hokkaido.jp +tsukigata.hokkaido.jp +urakawa.hokkaido.jp +urausu.hokkaido.jp +uryu.hokkaido.jp +utashinai.hokkaido.jp +wakkanai.hokkaido.jp +wassamu.hokkaido.jp +yakumo.hokkaido.jp +yoichi.hokkaido.jp +aioi.hyogo.jp +akashi.hyogo.jp +ako.hyogo.jp +amagasaki.hyogo.jp +aogaki.hyogo.jp +asago.hyogo.jp +ashiya.hyogo.jp +awaji.hyogo.jp +fukusaki.hyogo.jp +goshiki.hyogo.jp +harima.hyogo.jp +himeji.hyogo.jp +ichikawa.hyogo.jp +inagawa.hyogo.jp +itami.hyogo.jp +kakogawa.hyogo.jp +kamigori.hyogo.jp +kamikawa.hyogo.jp +kasai.hyogo.jp +kasuga.hyogo.jp +kawanishi.hyogo.jp +miki.hyogo.jp +minamiawaji.hyogo.jp +nishinomiya.hyogo.jp +nishiwaki.hyogo.jp +ono.hyogo.jp +sanda.hyogo.jp +sannan.hyogo.jp +sasayama.hyogo.jp +sayo.hyogo.jp +shingu.hyogo.jp +shinonsen.hyogo.jp +shiso.hyogo.jp +sumoto.hyogo.jp +taishi.hyogo.jp +taka.hyogo.jp +takarazuka.hyogo.jp +takasago.hyogo.jp +takino.hyogo.jp +tamba.hyogo.jp +tatsuno.hyogo.jp +toyooka.hyogo.jp +yabu.hyogo.jp +yashiro.hyogo.jp +yoka.hyogo.jp +yokawa.hyogo.jp +ami.ibaraki.jp +asahi.ibaraki.jp +bando.ibaraki.jp +chikusei.ibaraki.jp +daigo.ibaraki.jp +fujishiro.ibaraki.jp +hitachi.ibaraki.jp +hitachinaka.ibaraki.jp +hitachiomiya.ibaraki.jp +hitachiota.ibaraki.jp +ibaraki.ibaraki.jp +ina.ibaraki.jp +inashiki.ibaraki.jp +itako.ibaraki.jp +iwama.ibaraki.jp +joso.ibaraki.jp +kamisu.ibaraki.jp +kasama.ibaraki.jp +kashima.ibaraki.jp +kasumigaura.ibaraki.jp +koga.ibaraki.jp +miho.ibaraki.jp +mito.ibaraki.jp +moriya.ibaraki.jp +naka.ibaraki.jp +namegata.ibaraki.jp +oarai.ibaraki.jp +ogawa.ibaraki.jp +omitama.ibaraki.jp +ryugasaki.ibaraki.jp +sakai.ibaraki.jp +sakuragawa.ibaraki.jp +shimodate.ibaraki.jp +shimotsuma.ibaraki.jp +shirosato.ibaraki.jp +sowa.ibaraki.jp +suifu.ibaraki.jp +takahagi.ibaraki.jp +tamatsukuri.ibaraki.jp +tokai.ibaraki.jp +tomobe.ibaraki.jp +tone.ibaraki.jp +toride.ibaraki.jp +tsuchiura.ibaraki.jp +tsukuba.ibaraki.jp +uchihara.ibaraki.jp +ushiku.ibaraki.jp +yachiyo.ibaraki.jp +yamagata.ibaraki.jp +yawara.ibaraki.jp +yuki.ibaraki.jp +anamizu.ishikawa.jp +hakui.ishikawa.jp +hakusan.ishikawa.jp +kaga.ishikawa.jp +kahoku.ishikawa.jp +kanazawa.ishikawa.jp +kawakita.ishikawa.jp +komatsu.ishikawa.jp +nakanoto.ishikawa.jp +nanao.ishikawa.jp +nomi.ishikawa.jp +nonoichi.ishikawa.jp +noto.ishikawa.jp +shika.ishikawa.jp +suzu.ishikawa.jp +tsubata.ishikawa.jp +tsurugi.ishikawa.jp +uchinada.ishikawa.jp +wajima.ishikawa.jp +fudai.iwate.jp +fujisawa.iwate.jp +hanamaki.iwate.jp +hiraizumi.iwate.jp +hirono.iwate.jp +ichinohe.iwate.jp +ichinoseki.iwate.jp +iwaizumi.iwate.jp +iwate.iwate.jp +joboji.iwate.jp +kamaishi.iwate.jp +kanegasaki.iwate.jp +karumai.iwate.jp +kawai.iwate.jp +kitakami.iwate.jp +kuji.iwate.jp +kunohe.iwate.jp +kuzumaki.iwate.jp +miyako.iwate.jp +mizusawa.iwate.jp +morioka.iwate.jp +ninohe.iwate.jp +noda.iwate.jp +ofunato.iwate.jp +oshu.iwate.jp +otsuchi.iwate.jp +rikuzentakata.iwate.jp +shiwa.iwate.jp +shizukuishi.iwate.jp +sumita.iwate.jp +tanohata.iwate.jp +tono.iwate.jp +yahaba.iwate.jp +yamada.iwate.jp +ayagawa.kagawa.jp +higashikagawa.kagawa.jp +kanonji.kagawa.jp +kotohira.kagawa.jp +manno.kagawa.jp +marugame.kagawa.jp +mitoyo.kagawa.jp +naoshima.kagawa.jp +sanuki.kagawa.jp +tadotsu.kagawa.jp +takamatsu.kagawa.jp +tonosho.kagawa.jp +uchinomi.kagawa.jp +utazu.kagawa.jp +zentsuji.kagawa.jp +akune.kagoshima.jp +amami.kagoshima.jp +hioki.kagoshima.jp +isa.kagoshima.jp +isen.kagoshima.jp +izumi.kagoshima.jp +kagoshima.kagoshima.jp +kanoya.kagoshima.jp +kawanabe.kagoshima.jp +kinko.kagoshima.jp +kouyama.kagoshima.jp +makurazaki.kagoshima.jp +matsumoto.kagoshima.jp +minamitane.kagoshima.jp +nakatane.kagoshima.jp +nishinoomote.kagoshima.jp +satsumasendai.kagoshima.jp +soo.kagoshima.jp +tarumizu.kagoshima.jp +yusui.kagoshima.jp +aikawa.kanagawa.jp +atsugi.kanagawa.jp +ayase.kanagawa.jp +chigasaki.kanagawa.jp +ebina.kanagawa.jp +fujisawa.kanagawa.jp +hadano.kanagawa.jp +hakone.kanagawa.jp +hiratsuka.kanagawa.jp +isehara.kanagawa.jp +kaisei.kanagawa.jp +kamakura.kanagawa.jp +kiyokawa.kanagawa.jp +matsuda.kanagawa.jp +minamiashigara.kanagawa.jp +miura.kanagawa.jp +nakai.kanagawa.jp +ninomiya.kanagawa.jp +odawara.kanagawa.jp +oi.kanagawa.jp +oiso.kanagawa.jp +sagamihara.kanagawa.jp +samukawa.kanagawa.jp +tsukui.kanagawa.jp +yamakita.kanagawa.jp +yamato.kanagawa.jp +yokosuka.kanagawa.jp +yugawara.kanagawa.jp +zama.kanagawa.jp +zushi.kanagawa.jp +aki.kochi.jp +geisei.kochi.jp +hidaka.kochi.jp +higashitsuno.kochi.jp +ino.kochi.jp +kagami.kochi.jp +kami.kochi.jp +kitagawa.kochi.jp +kochi.kochi.jp +mihara.kochi.jp +motoyama.kochi.jp +muroto.kochi.jp +nahari.kochi.jp +nakamura.kochi.jp +nankoku.kochi.jp +nishitosa.kochi.jp +niyodogawa.kochi.jp +ochi.kochi.jp +okawa.kochi.jp +otoyo.kochi.jp +otsuki.kochi.jp +sakawa.kochi.jp +sukumo.kochi.jp +susaki.kochi.jp +tosa.kochi.jp +tosashimizu.kochi.jp +toyo.kochi.jp +tsuno.kochi.jp +umaji.kochi.jp +yasuda.kochi.jp +yusuhara.kochi.jp +amakusa.kumamoto.jp +arao.kumamoto.jp +aso.kumamoto.jp +choyo.kumamoto.jp +gyokuto.kumamoto.jp +hitoyoshi.kumamoto.jp +kamiamakusa.kumamoto.jp +kashima.kumamoto.jp +kikuchi.kumamoto.jp +kosa.kumamoto.jp +kumamoto.kumamoto.jp +mashiki.kumamoto.jp +mifune.kumamoto.jp +minamata.kumamoto.jp +minamioguni.kumamoto.jp +nagasu.kumamoto.jp +nishihara.kumamoto.jp +oguni.kumamoto.jp +ozu.kumamoto.jp +sumoto.kumamoto.jp +takamori.kumamoto.jp +uki.kumamoto.jp +uto.kumamoto.jp +yamaga.kumamoto.jp +yamato.kumamoto.jp +yatsushiro.kumamoto.jp +ayabe.kyoto.jp +fukuchiyama.kyoto.jp +higashiyama.kyoto.jp +ide.kyoto.jp +ine.kyoto.jp +joyo.kyoto.jp +kameoka.kyoto.jp +kamo.kyoto.jp +kita.kyoto.jp +kizu.kyoto.jp +kumiyama.kyoto.jp +kyotamba.kyoto.jp +kyotanabe.kyoto.jp +kyotango.kyoto.jp +maizuru.kyoto.jp +minami.kyoto.jp +minamiyamashiro.kyoto.jp +miyazu.kyoto.jp +muko.kyoto.jp +nagaokakyo.kyoto.jp +nakagyo.kyoto.jp +nantan.kyoto.jp +oyamazaki.kyoto.jp +sakyo.kyoto.jp +seika.kyoto.jp +tanabe.kyoto.jp +uji.kyoto.jp +ujitawara.kyoto.jp +wazuka.kyoto.jp +yamashina.kyoto.jp +yawata.kyoto.jp +asahi.mie.jp +inabe.mie.jp +ise.mie.jp +kameyama.mie.jp +kawagoe.mie.jp +kiho.mie.jp +kisosaki.mie.jp +kiwa.mie.jp +komono.mie.jp +kumano.mie.jp +kuwana.mie.jp +matsusaka.mie.jp +meiwa.mie.jp +mihama.mie.jp +minamiise.mie.jp +misugi.mie.jp +miyama.mie.jp +nabari.mie.jp +shima.mie.jp +suzuka.mie.jp +tado.mie.jp +taiki.mie.jp +taki.mie.jp +tamaki.mie.jp +toba.mie.jp +tsu.mie.jp +udono.mie.jp +ureshino.mie.jp +watarai.mie.jp +yokkaichi.mie.jp +furukawa.miyagi.jp +higashimatsushima.miyagi.jp +ishinomaki.miyagi.jp +iwanuma.miyagi.jp +kakuda.miyagi.jp +kami.miyagi.jp +kawasaki.miyagi.jp +kesennuma.miyagi.jp +marumori.miyagi.jp +matsushima.miyagi.jp +minamisanriku.miyagi.jp +misato.miyagi.jp +murata.miyagi.jp +natori.miyagi.jp +ogawara.miyagi.jp +ohira.miyagi.jp +onagawa.miyagi.jp +osaki.miyagi.jp +rifu.miyagi.jp +semine.miyagi.jp +shibata.miyagi.jp +shichikashuku.miyagi.jp +shikama.miyagi.jp +shiogama.miyagi.jp +shiroishi.miyagi.jp +tagajo.miyagi.jp +taiwa.miyagi.jp +tome.miyagi.jp +tomiya.miyagi.jp +wakuya.miyagi.jp +watari.miyagi.jp +yamamoto.miyagi.jp +zao.miyagi.jp +aya.miyazaki.jp +ebino.miyazaki.jp +gokase.miyazaki.jp +hyuga.miyazaki.jp +kadogawa.miyazaki.jp +kawaminami.miyazaki.jp +kijo.miyazaki.jp +kitagawa.miyazaki.jp +kitakata.miyazaki.jp +kitaura.miyazaki.jp +kobayashi.miyazaki.jp +kunitomi.miyazaki.jp +kushima.miyazaki.jp +mimata.miyazaki.jp +miyakonojo.miyazaki.jp +miyazaki.miyazaki.jp +morotsuka.miyazaki.jp +nichinan.miyazaki.jp +nishimera.miyazaki.jp +nobeoka.miyazaki.jp +saito.miyazaki.jp +shiiba.miyazaki.jp +shintomi.miyazaki.jp +takaharu.miyazaki.jp +takanabe.miyazaki.jp +takazaki.miyazaki.jp +tsuno.miyazaki.jp +achi.nagano.jp +agematsu.nagano.jp +anan.nagano.jp +aoki.nagano.jp +asahi.nagano.jp +azumino.nagano.jp +chikuhoku.nagano.jp +chikuma.nagano.jp +chino.nagano.jp +fujimi.nagano.jp +hakuba.nagano.jp +hara.nagano.jp +hiraya.nagano.jp +iida.nagano.jp +iijima.nagano.jp +iiyama.nagano.jp +iizuna.nagano.jp +ikeda.nagano.jp +ikusaka.nagano.jp +ina.nagano.jp +karuizawa.nagano.jp +kawakami.nagano.jp +kiso.nagano.jp +kisofukushima.nagano.jp +kitaaiki.nagano.jp +komagane.nagano.jp +komoro.nagano.jp +matsukawa.nagano.jp +matsumoto.nagano.jp +miasa.nagano.jp +minamiaiki.nagano.jp +minamimaki.nagano.jp +minamiminowa.nagano.jp +minowa.nagano.jp +miyada.nagano.jp +miyota.nagano.jp +mochizuki.nagano.jp +nagano.nagano.jp +nagawa.nagano.jp +nagiso.nagano.jp +nakagawa.nagano.jp +nakano.nagano.jp +nozawaonsen.nagano.jp +obuse.nagano.jp +ogawa.nagano.jp +okaya.nagano.jp +omachi.nagano.jp +omi.nagano.jp +ookuwa.nagano.jp +ooshika.nagano.jp +otaki.nagano.jp +otari.nagano.jp +sakae.nagano.jp +sakaki.nagano.jp +saku.nagano.jp +sakuho.nagano.jp +shimosuwa.nagano.jp +shinanomachi.nagano.jp +shiojiri.nagano.jp +suwa.nagano.jp +suzaka.nagano.jp +takagi.nagano.jp +takamori.nagano.jp +takayama.nagano.jp +tateshina.nagano.jp +tatsuno.nagano.jp +togakushi.nagano.jp +togura.nagano.jp +tomi.nagano.jp +ueda.nagano.jp +wada.nagano.jp +yamagata.nagano.jp +yamanouchi.nagano.jp +yasaka.nagano.jp +yasuoka.nagano.jp +chijiwa.nagasaki.jp +futsu.nagasaki.jp +goto.nagasaki.jp +hasami.nagasaki.jp +hirado.nagasaki.jp +iki.nagasaki.jp +isahaya.nagasaki.jp +kawatana.nagasaki.jp +kuchinotsu.nagasaki.jp +matsuura.nagasaki.jp +nagasaki.nagasaki.jp +obama.nagasaki.jp +omura.nagasaki.jp +oseto.nagasaki.jp +saikai.nagasaki.jp +sasebo.nagasaki.jp +seihi.nagasaki.jp +shimabara.nagasaki.jp +shinkamigoto.nagasaki.jp +togitsu.nagasaki.jp +tsushima.nagasaki.jp +unzen.nagasaki.jp +ando.nara.jp +gose.nara.jp +heguri.nara.jp +higashiyoshino.nara.jp +ikaruga.nara.jp +ikoma.nara.jp +kamikitayama.nara.jp +kanmaki.nara.jp +kashiba.nara.jp +kashihara.nara.jp +katsuragi.nara.jp +kawai.nara.jp +kawakami.nara.jp +kawanishi.nara.jp +koryo.nara.jp +kurotaki.nara.jp +mitsue.nara.jp +miyake.nara.jp +nara.nara.jp +nosegawa.nara.jp +oji.nara.jp +ouda.nara.jp +oyodo.nara.jp +sakurai.nara.jp +sango.nara.jp +shimoichi.nara.jp +shimokitayama.nara.jp +shinjo.nara.jp +soni.nara.jp +takatori.nara.jp +tawaramoto.nara.jp +tenkawa.nara.jp +tenri.nara.jp +uda.nara.jp +yamatokoriyama.nara.jp +yamatotakada.nara.jp +yamazoe.nara.jp +yoshino.nara.jp +aga.niigata.jp +agano.niigata.jp +gosen.niigata.jp +itoigawa.niigata.jp +izumozaki.niigata.jp +joetsu.niigata.jp +kamo.niigata.jp +kariwa.niigata.jp +kashiwazaki.niigata.jp +minamiuonuma.niigata.jp +mitsuke.niigata.jp +muika.niigata.jp +murakami.niigata.jp +myoko.niigata.jp +nagaoka.niigata.jp +niigata.niigata.jp +ojiya.niigata.jp +omi.niigata.jp +sado.niigata.jp +sanjo.niigata.jp +seiro.niigata.jp +seirou.niigata.jp +sekikawa.niigata.jp +shibata.niigata.jp +tagami.niigata.jp +tainai.niigata.jp +tochio.niigata.jp +tokamachi.niigata.jp +tsubame.niigata.jp +tsunan.niigata.jp +uonuma.niigata.jp +yahiko.niigata.jp +yoita.niigata.jp +yuzawa.niigata.jp +beppu.oita.jp +bungoono.oita.jp +bungotakada.oita.jp +hasama.oita.jp +hiji.oita.jp +himeshima.oita.jp +hita.oita.jp +kamitsue.oita.jp +kokonoe.oita.jp +kuju.oita.jp +kunisaki.oita.jp +kusu.oita.jp +oita.oita.jp +saiki.oita.jp +taketa.oita.jp +tsukumi.oita.jp +usa.oita.jp +usuki.oita.jp +yufu.oita.jp +akaiwa.okayama.jp +asakuchi.okayama.jp +bizen.okayama.jp +hayashima.okayama.jp +ibara.okayama.jp +kagamino.okayama.jp +kasaoka.okayama.jp +kibichuo.okayama.jp +kumenan.okayama.jp +kurashiki.okayama.jp +maniwa.okayama.jp +misaki.okayama.jp +nagi.okayama.jp +niimi.okayama.jp +nishiawakura.okayama.jp +okayama.okayama.jp +satosho.okayama.jp +setouchi.okayama.jp +shinjo.okayama.jp +shoo.okayama.jp +soja.okayama.jp +takahashi.okayama.jp +tamano.okayama.jp +tsuyama.okayama.jp +wake.okayama.jp +yakage.okayama.jp +aguni.okinawa.jp +ginowan.okinawa.jp +ginoza.okinawa.jp +gushikami.okinawa.jp +haebaru.okinawa.jp +higashi.okinawa.jp +hirara.okinawa.jp +iheya.okinawa.jp +ishigaki.okinawa.jp +ishikawa.okinawa.jp +itoman.okinawa.jp +izena.okinawa.jp +kadena.okinawa.jp +kin.okinawa.jp +kitadaito.okinawa.jp +kitanakagusuku.okinawa.jp +kumejima.okinawa.jp +kunigami.okinawa.jp +minamidaito.okinawa.jp +motobu.okinawa.jp +nago.okinawa.jp +naha.okinawa.jp +nakagusuku.okinawa.jp +nakijin.okinawa.jp +nanjo.okinawa.jp +nishihara.okinawa.jp +ogimi.okinawa.jp +okinawa.okinawa.jp +onna.okinawa.jp +shimoji.okinawa.jp +taketomi.okinawa.jp +tarama.okinawa.jp +tokashiki.okinawa.jp +tomigusuku.okinawa.jp +tonaki.okinawa.jp +urasoe.okinawa.jp +uruma.okinawa.jp +yaese.okinawa.jp +yomitan.okinawa.jp +yonabaru.okinawa.jp +yonaguni.okinawa.jp +zamami.okinawa.jp +abeno.osaka.jp +chihayaakasaka.osaka.jp +chuo.osaka.jp +daito.osaka.jp +fujiidera.osaka.jp +habikino.osaka.jp +hannan.osaka.jp +higashiosaka.osaka.jp +higashisumiyoshi.osaka.jp +higashiyodogawa.osaka.jp +hirakata.osaka.jp +ibaraki.osaka.jp +ikeda.osaka.jp +izumi.osaka.jp +izumiotsu.osaka.jp +izumisano.osaka.jp +kadoma.osaka.jp +kaizuka.osaka.jp +kanan.osaka.jp +kashiwara.osaka.jp +katano.osaka.jp +kawachinagano.osaka.jp +kishiwada.osaka.jp +kita.osaka.jp +kumatori.osaka.jp +matsubara.osaka.jp +minato.osaka.jp +minoh.osaka.jp +misaki.osaka.jp +moriguchi.osaka.jp +neyagawa.osaka.jp +nishi.osaka.jp +nose.osaka.jp +osakasayama.osaka.jp +sakai.osaka.jp +sayama.osaka.jp +sennan.osaka.jp +settsu.osaka.jp +shijonawate.osaka.jp +shimamoto.osaka.jp +suita.osaka.jp +tadaoka.osaka.jp +taishi.osaka.jp +tajiri.osaka.jp +takaishi.osaka.jp +takatsuki.osaka.jp +tondabayashi.osaka.jp +toyonaka.osaka.jp +toyono.osaka.jp +yao.osaka.jp +ariake.saga.jp +arita.saga.jp +fukudomi.saga.jp +genkai.saga.jp +hamatama.saga.jp +hizen.saga.jp +imari.saga.jp +kamimine.saga.jp +kanzaki.saga.jp +karatsu.saga.jp +kashima.saga.jp +kitagata.saga.jp +kitahata.saga.jp +kiyama.saga.jp +kouhoku.saga.jp +kyuragi.saga.jp +nishiarita.saga.jp +ogi.saga.jp +omachi.saga.jp +ouchi.saga.jp +saga.saga.jp +shiroishi.saga.jp +taku.saga.jp +tara.saga.jp +tosu.saga.jp +yoshinogari.saga.jp +arakawa.saitama.jp +asaka.saitama.jp +chichibu.saitama.jp +fujimi.saitama.jp +fujimino.saitama.jp +fukaya.saitama.jp +hanno.saitama.jp +hanyu.saitama.jp +hasuda.saitama.jp +hatogaya.saitama.jp +hatoyama.saitama.jp +hidaka.saitama.jp +higashichichibu.saitama.jp +higashimatsuyama.saitama.jp +honjo.saitama.jp +ina.saitama.jp +iruma.saitama.jp +iwatsuki.saitama.jp +kamiizumi.saitama.jp +kamikawa.saitama.jp +kamisato.saitama.jp +kasukabe.saitama.jp +kawagoe.saitama.jp +kawaguchi.saitama.jp +kawajima.saitama.jp +kazo.saitama.jp +kitamoto.saitama.jp +koshigaya.saitama.jp +kounosu.saitama.jp +kuki.saitama.jp +kumagaya.saitama.jp +matsubushi.saitama.jp +minano.saitama.jp +misato.saitama.jp +miyashiro.saitama.jp +miyoshi.saitama.jp +moroyama.saitama.jp +nagatoro.saitama.jp +namegawa.saitama.jp +niiza.saitama.jp +ogano.saitama.jp +ogawa.saitama.jp +ogose.saitama.jp +okegawa.saitama.jp +omiya.saitama.jp +otaki.saitama.jp +ranzan.saitama.jp +ryokami.saitama.jp +saitama.saitama.jp +sakado.saitama.jp +satte.saitama.jp +sayama.saitama.jp +shiki.saitama.jp +shiraoka.saitama.jp +soka.saitama.jp +sugito.saitama.jp +toda.saitama.jp +tokigawa.saitama.jp +tokorozawa.saitama.jp +tsurugashima.saitama.jp +urawa.saitama.jp +warabi.saitama.jp +yashio.saitama.jp +yokoze.saitama.jp +yono.saitama.jp +yorii.saitama.jp +yoshida.saitama.jp +yoshikawa.saitama.jp +yoshimi.saitama.jp +aisho.shiga.jp +gamo.shiga.jp +higashiomi.shiga.jp +hikone.shiga.jp +koka.shiga.jp +konan.shiga.jp +kosei.shiga.jp +koto.shiga.jp +kusatsu.shiga.jp +maibara.shiga.jp +moriyama.shiga.jp +nagahama.shiga.jp +nishiazai.shiga.jp +notogawa.shiga.jp +omihachiman.shiga.jp +otsu.shiga.jp +ritto.shiga.jp +ryuoh.shiga.jp +takashima.shiga.jp +takatsuki.shiga.jp +torahime.shiga.jp +toyosato.shiga.jp +yasu.shiga.jp +akagi.shimane.jp +ama.shimane.jp +gotsu.shimane.jp +hamada.shimane.jp +higashiizumo.shimane.jp +hikawa.shimane.jp +hikimi.shimane.jp +izumo.shimane.jp +kakinoki.shimane.jp +masuda.shimane.jp +matsue.shimane.jp +misato.shimane.jp +nishinoshima.shimane.jp +ohda.shimane.jp +okinoshima.shimane.jp +okuizumo.shimane.jp +shimane.shimane.jp +tamayu.shimane.jp +tsuwano.shimane.jp +unnan.shimane.jp +yakumo.shimane.jp +yasugi.shimane.jp +yatsuka.shimane.jp +arai.shizuoka.jp +atami.shizuoka.jp +fuji.shizuoka.jp +fujieda.shizuoka.jp +fujikawa.shizuoka.jp +fujinomiya.shizuoka.jp +fukuroi.shizuoka.jp +gotemba.shizuoka.jp +haibara.shizuoka.jp +hamamatsu.shizuoka.jp +higashiizu.shizuoka.jp +ito.shizuoka.jp +iwata.shizuoka.jp +izu.shizuoka.jp +izunokuni.shizuoka.jp +kakegawa.shizuoka.jp +kannami.shizuoka.jp +kawanehon.shizuoka.jp +kawazu.shizuoka.jp +kikugawa.shizuoka.jp +kosai.shizuoka.jp +makinohara.shizuoka.jp +matsuzaki.shizuoka.jp +minamiizu.shizuoka.jp +mishima.shizuoka.jp +morimachi.shizuoka.jp +nishiizu.shizuoka.jp +numazu.shizuoka.jp +omaezaki.shizuoka.jp +shimada.shizuoka.jp +shimizu.shizuoka.jp +shimoda.shizuoka.jp +shizuoka.shizuoka.jp +susono.shizuoka.jp +yaizu.shizuoka.jp +yoshida.shizuoka.jp +ashikaga.tochigi.jp +bato.tochigi.jp +haga.tochigi.jp +ichikai.tochigi.jp +iwafune.tochigi.jp +kaminokawa.tochigi.jp +kanuma.tochigi.jp +karasuyama.tochigi.jp +kuroiso.tochigi.jp +mashiko.tochigi.jp +mibu.tochigi.jp +moka.tochigi.jp +motegi.tochigi.jp +nasu.tochigi.jp +nasushiobara.tochigi.jp +nikko.tochigi.jp +nishikata.tochigi.jp +nogi.tochigi.jp +ohira.tochigi.jp +ohtawara.tochigi.jp +oyama.tochigi.jp +sakura.tochigi.jp +sano.tochigi.jp +shimotsuke.tochigi.jp +shioya.tochigi.jp +takanezawa.tochigi.jp +tochigi.tochigi.jp +tsuga.tochigi.jp +ujiie.tochigi.jp +utsunomiya.tochigi.jp +yaita.tochigi.jp +aizumi.tokushima.jp +anan.tokushima.jp +ichiba.tokushima.jp +itano.tokushima.jp +kainan.tokushima.jp +komatsushima.tokushima.jp +matsushige.tokushima.jp +mima.tokushima.jp +minami.tokushima.jp +miyoshi.tokushima.jp +mugi.tokushima.jp +nakagawa.tokushima.jp +naruto.tokushima.jp +sanagochi.tokushima.jp +shishikui.tokushima.jp +tokushima.tokushima.jp +wajiki.tokushima.jp +adachi.tokyo.jp +akiruno.tokyo.jp +akishima.tokyo.jp +aogashima.tokyo.jp +arakawa.tokyo.jp +bunkyo.tokyo.jp +chiyoda.tokyo.jp +chofu.tokyo.jp +chuo.tokyo.jp +edogawa.tokyo.jp +fuchu.tokyo.jp +fussa.tokyo.jp +hachijo.tokyo.jp +hachioji.tokyo.jp +hamura.tokyo.jp +higashikurume.tokyo.jp +higashimurayama.tokyo.jp +higashiyamato.tokyo.jp +hino.tokyo.jp +hinode.tokyo.jp +hinohara.tokyo.jp +inagi.tokyo.jp +itabashi.tokyo.jp +katsushika.tokyo.jp +kita.tokyo.jp +kiyose.tokyo.jp +kodaira.tokyo.jp +koganei.tokyo.jp +kokubunji.tokyo.jp +komae.tokyo.jp +koto.tokyo.jp +kouzushima.tokyo.jp +kunitachi.tokyo.jp +machida.tokyo.jp +meguro.tokyo.jp +minato.tokyo.jp +mitaka.tokyo.jp +mizuho.tokyo.jp +musashimurayama.tokyo.jp +musashino.tokyo.jp +nakano.tokyo.jp +nerima.tokyo.jp +ogasawara.tokyo.jp +okutama.tokyo.jp +ome.tokyo.jp +oshima.tokyo.jp +ota.tokyo.jp +setagaya.tokyo.jp +shibuya.tokyo.jp +shinagawa.tokyo.jp +shinjuku.tokyo.jp +suginami.tokyo.jp +sumida.tokyo.jp +tachikawa.tokyo.jp +taito.tokyo.jp +tama.tokyo.jp +toshima.tokyo.jp +chizu.tottori.jp +hino.tottori.jp +kawahara.tottori.jp +koge.tottori.jp +kotoura.tottori.jp +misasa.tottori.jp +nanbu.tottori.jp +nichinan.tottori.jp +sakaiminato.tottori.jp +tottori.tottori.jp +wakasa.tottori.jp +yazu.tottori.jp +yonago.tottori.jp +asahi.toyama.jp +fuchu.toyama.jp +fukumitsu.toyama.jp +funahashi.toyama.jp +himi.toyama.jp +imizu.toyama.jp +inami.toyama.jp +johana.toyama.jp +kamiichi.toyama.jp +kurobe.toyama.jp +nakaniikawa.toyama.jp +namerikawa.toyama.jp +nanto.toyama.jp +nyuzen.toyama.jp +oyabe.toyama.jp +taira.toyama.jp +takaoka.toyama.jp +tateyama.toyama.jp +toga.toyama.jp +tonami.toyama.jp +toyama.toyama.jp +unazuki.toyama.jp +uozu.toyama.jp +yamada.toyama.jp +arida.wakayama.jp +aridagawa.wakayama.jp +gobo.wakayama.jp +hashimoto.wakayama.jp +hidaka.wakayama.jp +hirogawa.wakayama.jp +inami.wakayama.jp +iwade.wakayama.jp +kainan.wakayama.jp +kamitonda.wakayama.jp +katsuragi.wakayama.jp +kimino.wakayama.jp +kinokawa.wakayama.jp +kitayama.wakayama.jp +koya.wakayama.jp +koza.wakayama.jp +kozagawa.wakayama.jp +kudoyama.wakayama.jp +kushimoto.wakayama.jp +mihama.wakayama.jp +misato.wakayama.jp +nachikatsuura.wakayama.jp +shingu.wakayama.jp +shirahama.wakayama.jp +taiji.wakayama.jp +tanabe.wakayama.jp +wakayama.wakayama.jp +yuasa.wakayama.jp +yura.wakayama.jp +asahi.yamagata.jp +funagata.yamagata.jp +higashine.yamagata.jp +iide.yamagata.jp +kahoku.yamagata.jp +kaminoyama.yamagata.jp +kaneyama.yamagata.jp +kawanishi.yamagata.jp +mamurogawa.yamagata.jp +mikawa.yamagata.jp +murayama.yamagata.jp +nagai.yamagata.jp +nakayama.yamagata.jp +nanyo.yamagata.jp +nishikawa.yamagata.jp +obanazawa.yamagata.jp +oe.yamagata.jp +oguni.yamagata.jp +ohkura.yamagata.jp +oishida.yamagata.jp +sagae.yamagata.jp +sakata.yamagata.jp +sakegawa.yamagata.jp +shinjo.yamagata.jp +shirataka.yamagata.jp +shonai.yamagata.jp +takahata.yamagata.jp +tendo.yamagata.jp +tozawa.yamagata.jp +tsuruoka.yamagata.jp +yamagata.yamagata.jp +yamanobe.yamagata.jp +yonezawa.yamagata.jp +yuza.yamagata.jp +abu.yamaguchi.jp +hagi.yamaguchi.jp +hikari.yamaguchi.jp +hofu.yamaguchi.jp +iwakuni.yamaguchi.jp +kudamatsu.yamaguchi.jp +mitou.yamaguchi.jp +nagato.yamaguchi.jp +oshima.yamaguchi.jp +shimonoseki.yamaguchi.jp +shunan.yamaguchi.jp +tabuse.yamaguchi.jp +tokuyama.yamaguchi.jp +toyota.yamaguchi.jp +ube.yamaguchi.jp +yuu.yamaguchi.jp +chuo.yamanashi.jp +doshi.yamanashi.jp +fuefuki.yamanashi.jp +fujikawa.yamanashi.jp +fujikawaguchiko.yamanashi.jp +fujiyoshida.yamanashi.jp +hayakawa.yamanashi.jp +hokuto.yamanashi.jp +ichikawamisato.yamanashi.jp +kai.yamanashi.jp +kofu.yamanashi.jp +koshu.yamanashi.jp +kosuge.yamanashi.jp +minami-alps.yamanashi.jp +minobu.yamanashi.jp +nakamichi.yamanashi.jp +nanbu.yamanashi.jp +narusawa.yamanashi.jp +nirasaki.yamanashi.jp +nishikatsura.yamanashi.jp +oshino.yamanashi.jp +otsuki.yamanashi.jp +showa.yamanashi.jp +tabayama.yamanashi.jp +tsuru.yamanashi.jp +uenohara.yamanashi.jp +yamanakako.yamanashi.jp +yamanashi.yamanashi.jp + +// ke : http://www.kenic.or.ke/index.php?option=com_content&task=view&id=117&Itemid=145 +*.ke + +// kg : http://www.domain.kg/dmn_n.html +kg +org.kg +net.kg +com.kg +edu.kg +gov.kg +mil.kg + +// kh : http://www.mptc.gov.kh/dns_registration.htm +*.kh + +// ki : http://www.ki/dns/index.html +ki +edu.ki +biz.ki +net.ki +org.ki +gov.ki +info.ki +com.ki + +// km : http://en.wikipedia.org/wiki/.km +// http://www.domaine.km/documents/charte.doc +km +org.km +nom.km +gov.km +prd.km +tm.km +edu.km +mil.km +ass.km +com.km +// These are only mentioned as proposed suggestions at domaine.km, but +// http://en.wikipedia.org/wiki/.km says they're available for registration: +coop.km +asso.km +presse.km +medecin.km +notaires.km +pharmaciens.km +veterinaire.km +gouv.km + +// kn : http://en.wikipedia.org/wiki/.kn +// http://www.dot.kn/domainRules.html +kn +net.kn +org.kn +edu.kn +gov.kn + +// kp : http://www.kcce.kp/en_index.php +kp +com.kp +edu.kp +gov.kp +org.kp +rep.kp +tra.kp + +// kr : http://en.wikipedia.org/wiki/.kr +// see also: http://domain.nida.or.kr/eng/registration.jsp +kr +ac.kr +co.kr +es.kr +go.kr +hs.kr +kg.kr +mil.kr +ms.kr +ne.kr +or.kr +pe.kr +re.kr +sc.kr +// kr geographical names +busan.kr +chungbuk.kr +chungnam.kr +daegu.kr +daejeon.kr +gangwon.kr +gwangju.kr +gyeongbuk.kr +gyeonggi.kr +gyeongnam.kr +incheon.kr +jeju.kr +jeonbuk.kr +jeonnam.kr +seoul.kr +ulsan.kr + +// kw : http://en.wikipedia.org/wiki/.kw +*.kw + +// ky : http://www.icta.ky/da_ky_reg_dom.php +// Confirmed by registry 2008-06-17 +ky +edu.ky +gov.ky +com.ky +org.ky +net.ky + +// kz : http://en.wikipedia.org/wiki/.kz +// see also: http://www.nic.kz/rules/index.jsp +kz +org.kz +edu.kz +net.kz +gov.kz +mil.kz +com.kz + +// la : http://en.wikipedia.org/wiki/.la +// Submitted by registry 2008-06-10 +la +int.la +net.la +info.la +edu.la +gov.la +per.la +com.la +org.la + +// lb : http://en.wikipedia.org/wiki/.lb +// Submitted by registry 2008-06-17 +lb +com.lb +edu.lb +gov.lb +net.lb +org.lb + +// lc : http://en.wikipedia.org/wiki/.lc +// see also: http://www.nic.lc/rules.htm +lc +com.lc +net.lc +co.lc +org.lc +edu.lc +gov.lc + +// li : http://en.wikipedia.org/wiki/.li +li + +// lk : http://www.nic.lk/seclevpr.html +lk +gov.lk +sch.lk +net.lk +int.lk +com.lk +org.lk +edu.lk +ngo.lk +soc.lk +web.lk +ltd.lk +assn.lk +grp.lk +hotel.lk +ac.lk + +// lr : http://psg.com/dns/lr/lr.txt +// Submitted by registry 2008-06-17 +lr +com.lr +edu.lr +gov.lr +org.lr +net.lr + +// ls : http://en.wikipedia.org/wiki/.ls +ls +co.ls +org.ls + +// lt : http://en.wikipedia.org/wiki/.lt +lt +// gov.lt : http://www.gov.lt/index_en.php +gov.lt + +// lu : http://www.dns.lu/en/ +lu + +// lv : http://www.nic.lv/DNS/En/generic.php +lv +com.lv +edu.lv +gov.lv +org.lv +mil.lv +id.lv +net.lv +asn.lv +conf.lv + +// ly : http://www.nic.ly/regulations.php +ly +com.ly +net.ly +gov.ly +plc.ly +edu.ly +sch.ly +med.ly +org.ly +id.ly + +// ma : http://en.wikipedia.org/wiki/.ma +// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf +ma +co.ma +net.ma +gov.ma +org.ma +ac.ma +press.ma + +// mc : http://www.nic.mc/ +mc +tm.mc +asso.mc + +// md : http://en.wikipedia.org/wiki/.md +md + +// me : http://en.wikipedia.org/wiki/.me +me +co.me +net.me +org.me +edu.me +ac.me +gov.me +its.me +priv.me + +// mg : http://www.nic.mg/tarif.htm +mg +org.mg +nom.mg +gov.mg +prd.mg +tm.mg +edu.mg +mil.mg +com.mg + +// mh : http://en.wikipedia.org/wiki/.mh +mh + +// mil : http://en.wikipedia.org/wiki/.mil +mil + +// mk : http://en.wikipedia.org/wiki/.mk +// see also: http://dns.marnet.net.mk/postapka.php +mk +com.mk +org.mk +net.mk +edu.mk +gov.mk +inf.mk +name.mk + +// ml : http://www.gobin.info/domainname/ml-template.doc +// see also: http://en.wikipedia.org/wiki/.ml +ml +com.ml +edu.ml +gouv.ml +gov.ml +net.ml +org.ml +presse.ml + +// mm : http://en.wikipedia.org/wiki/.mm +*.mm + +// mn : http://en.wikipedia.org/wiki/.mn +mn +gov.mn +edu.mn +org.mn + +// mo : http://www.monic.net.mo/ +mo +com.mo +net.mo +org.mo +edu.mo +gov.mo + +// mobi : http://en.wikipedia.org/wiki/.mobi +mobi + +// mp : http://www.dot.mp/ +// Confirmed by registry 2008-06-17 +mp + +// mq : http://en.wikipedia.org/wiki/.mq +mq + +// mr : http://en.wikipedia.org/wiki/.mr +mr +gov.mr + +// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf +ms +com.ms +edu.ms +gov.ms +net.ms +org.ms + +// mt : https://www.nic.org.mt/go/policy +// Submitted by registry 2013-11-19 +mt +com.mt +edu.mt +net.mt +org.mt + +// mu : http://en.wikipedia.org/wiki/.mu +mu +com.mu +net.mu +org.mu +gov.mu +ac.mu +co.mu +or.mu + +// museum : http://about.museum/naming/ +// http://index.museum/ +museum +academy.museum +agriculture.museum +air.museum +airguard.museum +alabama.museum +alaska.museum +amber.museum +ambulance.museum +american.museum +americana.museum +americanantiques.museum +americanart.museum +amsterdam.museum +and.museum +annefrank.museum +anthro.museum +anthropology.museum +antiques.museum +aquarium.museum +arboretum.museum +archaeological.museum +archaeology.museum +architecture.museum +art.museum +artanddesign.museum +artcenter.museum +artdeco.museum +arteducation.museum +artgallery.museum +arts.museum +artsandcrafts.museum +asmatart.museum +assassination.museum +assisi.museum +association.museum +astronomy.museum +atlanta.museum +austin.museum +australia.museum +automotive.museum +aviation.museum +axis.museum +badajoz.museum +baghdad.museum +bahn.museum +bale.museum +baltimore.museum +barcelona.museum +baseball.museum +basel.museum +baths.museum +bauern.museum +beauxarts.museum +beeldengeluid.museum +bellevue.museum +bergbau.museum +berkeley.museum +berlin.museum +bern.museum +bible.museum +bilbao.museum +bill.museum +birdart.museum +birthplace.museum +bonn.museum +boston.museum +botanical.museum +botanicalgarden.museum +botanicgarden.museum +botany.museum +brandywinevalley.museum +brasil.museum +bristol.museum +british.museum +britishcolumbia.museum +broadcast.museum +brunel.museum +brussel.museum +brussels.museum +bruxelles.museum +building.museum +burghof.museum +bus.museum +bushey.museum +cadaques.museum +california.museum +cambridge.museum +can.museum +canada.museum +capebreton.museum +carrier.museum +cartoonart.museum +casadelamoneda.museum +castle.museum +castres.museum +celtic.museum +center.museum +chattanooga.museum +cheltenham.museum +chesapeakebay.museum +chicago.museum +children.museum +childrens.museum +childrensgarden.museum +chiropractic.museum +chocolate.museum +christiansburg.museum +cincinnati.museum +cinema.museum +circus.museum +civilisation.museum +civilization.museum +civilwar.museum +clinton.museum +clock.museum +coal.museum +coastaldefence.museum +cody.museum +coldwar.museum +collection.museum +colonialwilliamsburg.museum +coloradoplateau.museum +columbia.museum +columbus.museum +communication.museum +communications.museum +community.museum +computer.museum +computerhistory.museum +comunicações.museum +contemporary.museum +contemporaryart.museum +convent.museum +copenhagen.museum +corporation.museum +correios-e-telecomunicações.museum +corvette.museum +costume.museum +countryestate.museum +county.museum +crafts.museum +cranbrook.museum +creation.museum +cultural.museum +culturalcenter.museum +culture.museum +cyber.museum +cymru.museum +dali.museum +dallas.museum +database.museum +ddr.museum +decorativearts.museum +delaware.museum +delmenhorst.museum +denmark.museum +depot.museum +design.museum +detroit.museum +dinosaur.museum +discovery.museum +dolls.museum +donostia.museum +durham.museum +eastafrica.museum +eastcoast.museum +education.museum +educational.museum +egyptian.museum +eisenbahn.museum +elburg.museum +elvendrell.museum +embroidery.museum +encyclopedic.museum +england.museum +entomology.museum +environment.museum +environmentalconservation.museum +epilepsy.museum +essex.museum +estate.museum +ethnology.museum +exeter.museum +exhibition.museum +family.museum +farm.museum +farmequipment.museum +farmers.museum +farmstead.museum +field.museum +figueres.museum +filatelia.museum +film.museum +fineart.museum +finearts.museum +finland.museum +flanders.museum +florida.museum +force.museum +fortmissoula.museum +fortworth.museum +foundation.museum +francaise.museum +frankfurt.museum +franziskaner.museum +freemasonry.museum +freiburg.museum +fribourg.museum +frog.museum +fundacio.museum +furniture.museum +gallery.museum +garden.museum +gateway.museum +geelvinck.museum +gemological.museum +geology.museum +georgia.museum +giessen.museum +glas.museum +glass.museum +gorge.museum +grandrapids.museum +graz.museum +guernsey.museum +halloffame.museum +hamburg.museum +handson.museum +harvestcelebration.museum +hawaii.museum +health.museum +heimatunduhren.museum +hellas.museum +helsinki.museum +hembygdsforbund.museum +heritage.museum +histoire.museum +historical.museum +historicalsociety.museum +historichouses.museum +historisch.museum +historisches.museum +history.museum +historyofscience.museum +horology.museum +house.museum +humanities.museum +illustration.museum +imageandsound.museum +indian.museum +indiana.museum +indianapolis.museum +indianmarket.museum +intelligence.museum +interactive.museum +iraq.museum +iron.museum +isleofman.museum +jamison.museum +jefferson.museum +jerusalem.museum +jewelry.museum +jewish.museum +jewishart.museum +jfk.museum +journalism.museum +judaica.museum +judygarland.museum +juedisches.museum +juif.museum +karate.museum +karikatur.museum +kids.museum +koebenhavn.museum +koeln.museum +kunst.museum +kunstsammlung.museum +kunstunddesign.museum +labor.museum +labour.museum +lajolla.museum +lancashire.museum +landes.museum +lans.museum +läns.museum +larsson.museum +lewismiller.museum +lincoln.museum +linz.museum +living.museum +livinghistory.museum +localhistory.museum +london.museum +losangeles.museum +louvre.museum +loyalist.museum +lucerne.museum +luxembourg.museum +luzern.museum +mad.museum +madrid.museum +mallorca.museum +manchester.museum +mansion.museum +mansions.museum +manx.museum +marburg.museum +maritime.museum +maritimo.museum +maryland.museum +marylhurst.museum +media.museum +medical.museum +medizinhistorisches.museum +meeres.museum +memorial.museum +mesaverde.museum +michigan.museum +midatlantic.museum +military.museum +mill.museum +miners.museum +mining.museum +minnesota.museum +missile.museum +missoula.museum +modern.museum +moma.museum +money.museum +monmouth.museum +monticello.museum +montreal.museum +moscow.museum +motorcycle.museum +muenchen.museum +muenster.museum +mulhouse.museum +muncie.museum +museet.museum +museumcenter.museum +museumvereniging.museum +music.museum +national.museum +nationalfirearms.museum +nationalheritage.museum +nativeamerican.museum +naturalhistory.museum +naturalhistorymuseum.museum +naturalsciences.museum +nature.museum +naturhistorisches.museum +natuurwetenschappen.museum +naumburg.museum +naval.museum +nebraska.museum +neues.museum +newhampshire.museum +newjersey.museum +newmexico.museum +newport.museum +newspaper.museum +newyork.museum +niepce.museum +norfolk.museum +north.museum +nrw.museum +nuernberg.museum +nuremberg.museum +nyc.museum +nyny.museum +oceanographic.museum +oceanographique.museum +omaha.museum +online.museum +ontario.museum +openair.museum +oregon.museum +oregontrail.museum +otago.museum +oxford.museum +pacific.museum +paderborn.museum +palace.museum +paleo.museum +palmsprings.museum +panama.museum +paris.museum +pasadena.museum +pharmacy.museum +philadelphia.museum +philadelphiaarea.museum +philately.museum +phoenix.museum +photography.museum +pilots.museum +pittsburgh.museum +planetarium.museum +plantation.museum +plants.museum +plaza.museum +portal.museum +portland.museum +portlligat.museum +posts-and-telecommunications.museum +preservation.museum +presidio.museum +press.museum +project.museum +public.museum +pubol.museum +quebec.museum +railroad.museum +railway.museum +research.museum +resistance.museum +riodejaneiro.museum +rochester.museum +rockart.museum +roma.museum +russia.museum +saintlouis.museum +salem.museum +salvadordali.museum +salzburg.museum +sandiego.museum +sanfrancisco.museum +santabarbara.museum +santacruz.museum +santafe.museum +saskatchewan.museum +satx.museum +savannahga.museum +schlesisches.museum +schoenbrunn.museum +schokoladen.museum +school.museum +schweiz.museum +science.museum +scienceandhistory.museum +scienceandindustry.museum +sciencecenter.museum +sciencecenters.museum +science-fiction.museum +sciencehistory.museum +sciences.museum +sciencesnaturelles.museum +scotland.museum +seaport.museum +settlement.museum +settlers.museum +shell.museum +sherbrooke.museum +sibenik.museum +silk.museum +ski.museum +skole.museum +society.museum +sologne.museum +soundandvision.museum +southcarolina.museum +southwest.museum +space.museum +spy.museum +square.museum +stadt.museum +stalbans.museum +starnberg.museum +state.museum +stateofdelaware.museum +station.museum +steam.museum +steiermark.museum +stjohn.museum +stockholm.museum +stpetersburg.museum +stuttgart.museum +suisse.museum +surgeonshall.museum +surrey.museum +svizzera.museum +sweden.museum +sydney.museum +tank.museum +tcm.museum +technology.museum +telekommunikation.museum +television.museum +texas.museum +textile.museum +theater.museum +time.museum +timekeeping.museum +topology.museum +torino.museum +touch.museum +town.museum +transport.museum +tree.museum +trolley.museum +trust.museum +trustee.museum +uhren.museum +ulm.museum +undersea.museum +university.museum +usa.museum +usantiques.museum +usarts.museum +uscountryestate.museum +usculture.museum +usdecorativearts.museum +usgarden.museum +ushistory.museum +ushuaia.museum +uslivinghistory.museum +utah.museum +uvic.museum +valley.museum +vantaa.museum +versailles.museum +viking.museum +village.museum +virginia.museum +virtual.museum +virtuel.museum +vlaanderen.museum +volkenkunde.museum +wales.museum +wallonie.museum +war.museum +washingtondc.museum +watchandclock.museum +watch-and-clock.museum +western.museum +westfalen.museum +whaling.museum +wildlife.museum +williamsburg.museum +windmill.museum +workshop.museum +york.museum +yorkshire.museum +yosemite.museum +youth.museum +zoological.museum +zoology.museum +ירושלים.museum +иком.museum + +// mv : http://en.wikipedia.org/wiki/.mv +// "mv" included because, contra Wikipedia, google.mv exists. +mv +aero.mv +biz.mv +com.mv +coop.mv +edu.mv +gov.mv +info.mv +int.mv +mil.mv +museum.mv +name.mv +net.mv +org.mv +pro.mv + +// mw : http://www.registrar.mw/ +mw +ac.mw +biz.mw +co.mw +com.mw +coop.mw +edu.mw +gov.mw +int.mw +museum.mw +net.mw +org.mw + +// mx : http://www.nic.mx/ +// Submitted by registry 2008-06-19 +mx +com.mx +org.mx +gob.mx +edu.mx +net.mx + +// my : http://www.mynic.net.my/ +my +com.my +net.my +org.my +gov.my +edu.my +mil.my +name.my + +// mz : http://www.gobin.info/domainname/mz-template.doc +*.mz +!teledata.mz + +// na : http://www.na-nic.com.na/ +// http://www.info.na/domain/ +na +info.na +pro.na +name.na +school.na +or.na +dr.na +us.na +mx.na +ca.na +in.na +cc.na +tv.na +ws.na +mobi.na +co.na +com.na +org.na + +// name : has 2nd-level tlds, but there's no list of them +name + +// nc : http://www.cctld.nc/ +nc +asso.nc + +// ne : http://en.wikipedia.org/wiki/.ne +ne + +// net : http://en.wikipedia.org/wiki/.net +net + +// nf : http://en.wikipedia.org/wiki/.nf +nf +com.nf +net.nf +per.nf +rec.nf +web.nf +arts.nf +firm.nf +info.nf +other.nf +store.nf + +// ng : http://psg.com/dns/ng/ +ng +com.ng +edu.ng +name.ng +net.ng +org.ng +sch.ng +gov.ng +mil.ng +mobi.ng + +// ni : http://www.nic.ni/dominios.htm +*.ni + +// nl : http://en.wikipedia.org/wiki/.nl +// https://www.sidn.nl/ +// ccTLD for the Netherlands +nl + +// BV.nl will be a registry for dutch BV's (besloten vennootschap) +bv.nl + +// no : http://www.norid.no/regelverk/index.en.html +// The Norwegian registry has declined to notify us of updates. The web pages +// referenced below are the official source of the data. There is also an +// announce mailing list: +// https://postlister.uninett.no/sympa/info/norid-diskusjon +no +// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html +fhs.no +vgs.no +fylkesbibl.no +folkebibl.no +museum.no +idrett.no +priv.no +// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html +mil.no +stat.no +dep.no +kommune.no +herad.no +// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html +// counties +aa.no +ah.no +bu.no +fm.no +hl.no +hm.no +jan-mayen.no +mr.no +nl.no +nt.no +of.no +ol.no +oslo.no +rl.no +sf.no +st.no +svalbard.no +tm.no +tr.no +va.no +vf.no +// primary and lower secondary schools per county +gs.aa.no +gs.ah.no +gs.bu.no +gs.fm.no +gs.hl.no +gs.hm.no +gs.jan-mayen.no +gs.mr.no +gs.nl.no +gs.nt.no +gs.of.no +gs.ol.no +gs.oslo.no +gs.rl.no +gs.sf.no +gs.st.no +gs.svalbard.no +gs.tm.no +gs.tr.no +gs.va.no +gs.vf.no +// cities +akrehamn.no +åkrehamn.no +algard.no +ålgård.no +arna.no +brumunddal.no +bryne.no +bronnoysund.no +brønnøysund.no +drobak.no +drøbak.no +egersund.no +fetsund.no +floro.no +florø.no +fredrikstad.no +hokksund.no +honefoss.no +hønefoss.no +jessheim.no +jorpeland.no +jørpeland.no +kirkenes.no +kopervik.no +krokstadelva.no +langevag.no +langevåg.no +leirvik.no +mjondalen.no +mjøndalen.no +mo-i-rana.no +mosjoen.no +mosjøen.no +nesoddtangen.no +orkanger.no +osoyro.no +osøyro.no +raholt.no +råholt.no +sandnessjoen.no +sandnessjøen.no +skedsmokorset.no +slattum.no +spjelkavik.no +stathelle.no +stavern.no +stjordalshalsen.no +stjørdalshalsen.no +tananger.no +tranby.no +vossevangen.no +// communities +afjord.no +åfjord.no +agdenes.no +al.no +ål.no +alesund.no +ålesund.no +alstahaug.no +alta.no +áltá.no +alaheadju.no +álaheadju.no +alvdal.no +amli.no +åmli.no +amot.no +åmot.no +andebu.no +andoy.no +andøy.no +andasuolo.no +ardal.no +årdal.no +aremark.no +arendal.no +ås.no +aseral.no +åseral.no +asker.no +askim.no +askvoll.no +askoy.no +askøy.no +asnes.no +åsnes.no +audnedaln.no +aukra.no +aure.no +aurland.no +aurskog-holand.no +aurskog-høland.no +austevoll.no +austrheim.no +averoy.no +averøy.no +balestrand.no +ballangen.no +balat.no +bálát.no +balsfjord.no +bahccavuotna.no +báhccavuotna.no +bamble.no +bardu.no +beardu.no +beiarn.no +bajddar.no +bájddar.no +baidar.no +báidár.no +berg.no +bergen.no +berlevag.no +berlevåg.no +bearalvahki.no +bearalváhki.no +bindal.no +birkenes.no +bjarkoy.no +bjarkøy.no +bjerkreim.no +bjugn.no +bodo.no +bodø.no +badaddja.no +bådåddjå.no +budejju.no +bokn.no +bremanger.no +bronnoy.no +brønnøy.no +bygland.no +bykle.no +barum.no +bærum.no +bo.telemark.no +bø.telemark.no +bo.nordland.no +bø.nordland.no +bievat.no +bievát.no +bomlo.no +bømlo.no +batsfjord.no +båtsfjord.no +bahcavuotna.no +báhcavuotna.no +dovre.no +drammen.no +drangedal.no +dyroy.no +dyrøy.no +donna.no +dønna.no +eid.no +eidfjord.no +eidsberg.no +eidskog.no +eidsvoll.no +eigersund.no +elverum.no +enebakk.no +engerdal.no +etne.no +etnedal.no +evenes.no +evenassi.no +evenášši.no +evje-og-hornnes.no +farsund.no +fauske.no +fuossko.no +fuoisku.no +fedje.no +fet.no +finnoy.no +finnøy.no +fitjar.no +fjaler.no +fjell.no +flakstad.no +flatanger.no +flekkefjord.no +flesberg.no +flora.no +fla.no +flå.no +folldal.no +forsand.no +fosnes.no +frei.no +frogn.no +froland.no +frosta.no +frana.no +fræna.no +froya.no +frøya.no +fusa.no +fyresdal.no +forde.no +førde.no +gamvik.no +gangaviika.no +gáŋgaviika.no +gaular.no +gausdal.no +gildeskal.no +gildeskål.no +giske.no +gjemnes.no +gjerdrum.no +gjerstad.no +gjesdal.no +gjovik.no +gjøvik.no +gloppen.no +gol.no +gran.no +grane.no +granvin.no +gratangen.no +grimstad.no +grong.no +kraanghke.no +kråanghke.no +grue.no +gulen.no +hadsel.no +halden.no +halsa.no +hamar.no +hamaroy.no +habmer.no +hábmer.no +hapmir.no +hápmir.no +hammerfest.no +hammarfeasta.no +hámmárfeasta.no +haram.no +hareid.no +harstad.no +hasvik.no +aknoluokta.no +ákŋoluokta.no +hattfjelldal.no +aarborte.no +haugesund.no +hemne.no +hemnes.no +hemsedal.no +heroy.more-og-romsdal.no +herøy.møre-og-romsdal.no +heroy.nordland.no +herøy.nordland.no +hitra.no +hjartdal.no +hjelmeland.no +hobol.no +hobøl.no +hof.no +hol.no +hole.no +holmestrand.no +holtalen.no +holtålen.no +hornindal.no +horten.no +hurdal.no +hurum.no +hvaler.no +hyllestad.no +hagebostad.no +hægebostad.no +hoyanger.no +høyanger.no +hoylandet.no +høylandet.no +ha.no +hå.no +ibestad.no +inderoy.no +inderøy.no +iveland.no +jevnaker.no +jondal.no +jolster.no +jølster.no +karasjok.no +karasjohka.no +kárášjohka.no +karlsoy.no +galsa.no +gálsá.no +karmoy.no +karmøy.no +kautokeino.no +guovdageaidnu.no +klepp.no +klabu.no +klæbu.no +kongsberg.no +kongsvinger.no +kragero.no +kragerø.no +kristiansand.no +kristiansund.no +krodsherad.no +krødsherad.no +kvalsund.no +rahkkeravju.no +ráhkkerávju.no +kvam.no +kvinesdal.no +kvinnherad.no +kviteseid.no +kvitsoy.no +kvitsøy.no +kvafjord.no +kvæfjord.no +giehtavuoatna.no +kvanangen.no +kvænangen.no +navuotna.no +návuotna.no +kafjord.no +kåfjord.no +gaivuotna.no +gáivuotna.no +larvik.no +lavangen.no +lavagis.no +loabat.no +loabát.no +lebesby.no +davvesiida.no +leikanger.no +leirfjord.no +leka.no +leksvik.no +lenvik.no +leangaviika.no +leaŋgaviika.no +lesja.no +levanger.no +lier.no +lierne.no +lillehammer.no +lillesand.no +lindesnes.no +lindas.no +lindås.no +lom.no +loppa.no +lahppi.no +láhppi.no +lund.no +lunner.no +luroy.no +lurøy.no +luster.no +lyngdal.no +lyngen.no +ivgu.no +lardal.no +lerdal.no +lærdal.no +lodingen.no +lødingen.no +lorenskog.no +lørenskog.no +loten.no +løten.no +malvik.no +masoy.no +måsøy.no +muosat.no +muosát.no +mandal.no +marker.no +marnardal.no +masfjorden.no +meland.no +meldal.no +melhus.no +meloy.no +meløy.no +meraker.no +meråker.no +moareke.no +moåreke.no +midsund.no +midtre-gauldal.no +modalen.no +modum.no +molde.no +moskenes.no +moss.no +mosvik.no +malselv.no +målselv.no +malatvuopmi.no +málatvuopmi.no +namdalseid.no +aejrie.no +namsos.no +namsskogan.no +naamesjevuemie.no +nååmesjevuemie.no +laakesvuemie.no +nannestad.no +narvik.no +narviika.no +naustdal.no +nedre-eiker.no +nes.akershus.no +nes.buskerud.no +nesna.no +nesodden.no +nesseby.no +unjarga.no +unjárga.no +nesset.no +nissedal.no +nittedal.no +nord-aurdal.no +nord-fron.no +nord-odal.no +norddal.no +nordkapp.no +davvenjarga.no +davvenjárga.no +nordre-land.no +nordreisa.no +raisa.no +ráisa.no +nore-og-uvdal.no +notodden.no +naroy.no +nærøy.no +notteroy.no +nøtterøy.no +odda.no +oksnes.no +øksnes.no +oppdal.no +oppegard.no +oppegård.no +orkdal.no +orland.no +ørland.no +orskog.no +ørskog.no +orsta.no +ørsta.no +os.hedmark.no +os.hordaland.no +osen.no +osteroy.no +osterøy.no +ostre-toten.no +østre-toten.no +overhalla.no +ovre-eiker.no +øvre-eiker.no +oyer.no +øyer.no +oygarden.no +øygarden.no +oystre-slidre.no +øystre-slidre.no +porsanger.no +porsangu.no +porsáŋgu.no +porsgrunn.no +radoy.no +radøy.no +rakkestad.no +rana.no +ruovat.no +randaberg.no +rauma.no +rendalen.no +rennebu.no +rennesoy.no +rennesøy.no +rindal.no +ringebu.no +ringerike.no +ringsaker.no +rissa.no +risor.no +risør.no +roan.no +rollag.no +rygge.no +ralingen.no +rælingen.no +rodoy.no +rødøy.no +romskog.no +rømskog.no +roros.no +røros.no +rost.no +røst.no +royken.no +røyken.no +royrvik.no +røyrvik.no +rade.no +råde.no +salangen.no +siellak.no +saltdal.no +salat.no +sálát.no +sálat.no +samnanger.no +sande.more-og-romsdal.no +sande.møre-og-romsdal.no +sande.vestfold.no +sandefjord.no +sandnes.no +sandoy.no +sandøy.no +sarpsborg.no +sauda.no +sauherad.no +sel.no +selbu.no +selje.no +seljord.no +sigdal.no +siljan.no +sirdal.no +skaun.no +skedsmo.no +ski.no +skien.no +skiptvet.no +skjervoy.no +skjervøy.no +skierva.no +skiervá.no +skjak.no +skjåk.no +skodje.no +skanland.no +skånland.no +skanit.no +skánit.no +smola.no +smøla.no +snillfjord.no +snasa.no +snåsa.no +snoasa.no +snaase.no +snåase.no +sogndal.no +sokndal.no +sola.no +solund.no +songdalen.no +sortland.no +spydeberg.no +stange.no +stavanger.no +steigen.no +steinkjer.no +stjordal.no +stjørdal.no +stokke.no +stor-elvdal.no +stord.no +stordal.no +storfjord.no +omasvuotna.no +strand.no +stranda.no +stryn.no +sula.no +suldal.no +sund.no +sunndal.no +surnadal.no +sveio.no +svelvik.no +sykkylven.no +sogne.no +søgne.no +somna.no +sømna.no +sondre-land.no +søndre-land.no +sor-aurdal.no +sør-aurdal.no +sor-fron.no +sør-fron.no +sor-odal.no +sør-odal.no +sor-varanger.no +sør-varanger.no +matta-varjjat.no +mátta-várjjat.no +sorfold.no +sørfold.no +sorreisa.no +sørreisa.no +sorum.no +sørum.no +tana.no +deatnu.no +time.no +tingvoll.no +tinn.no +tjeldsund.no +dielddanuorri.no +tjome.no +tjøme.no +tokke.no +tolga.no +torsken.no +tranoy.no +tranøy.no +tromso.no +tromsø.no +tromsa.no +romsa.no +trondheim.no +troandin.no +trysil.no +trana.no +træna.no +trogstad.no +trøgstad.no +tvedestrand.no +tydal.no +tynset.no +tysfjord.no +divtasvuodna.no +divttasvuotna.no +tysnes.no +tysvar.no +tysvær.no +tonsberg.no +tønsberg.no +ullensaker.no +ullensvang.no +ulvik.no +utsira.no +vadso.no +vadsø.no +cahcesuolo.no +čáhcesuolo.no +vaksdal.no +valle.no +vang.no +vanylven.no +vardo.no +vardø.no +varggat.no +várggát.no +vefsn.no +vaapste.no +vega.no +vegarshei.no +vegårshei.no +vennesla.no +verdal.no +verran.no +vestby.no +vestnes.no +vestre-slidre.no +vestre-toten.no +vestvagoy.no +vestvågøy.no +vevelstad.no +vik.no +vikna.no +vindafjord.no +volda.no +voss.no +varoy.no +værøy.no +vagan.no +vågan.no +voagat.no +vagsoy.no +vågsøy.no +vaga.no +vågå.no +valer.ostfold.no +våler.østfold.no +valer.hedmark.no +våler.hedmark.no + +// np : http://www.mos.com.np/register.html +*.np + +// nr : http://cenpac.net.nr/dns/index.html +// Confirmed by registry 2008-06-17 +nr +biz.nr +info.nr +gov.nr +edu.nr +org.nr +net.nr +com.nr + +// nu : http://en.wikipedia.org/wiki/.nu +nu + +// nz : http://en.wikipedia.org/wiki/.nz +// Confirmed by registry 2014-05-19 +nz +ac.nz +co.nz +cri.nz +geek.nz +gen.nz +govt.nz +health.nz +iwi.nz +kiwi.nz +maori.nz +mil.nz +māori.nz +net.nz +org.nz +parliament.nz +school.nz + +// om : http://en.wikipedia.org/wiki/.om +om +co.om +com.om +edu.om +gov.om +med.om +museum.om +net.om +org.om +pro.om + +// org : http://en.wikipedia.org/wiki/.org +org + +// pa : http://www.nic.pa/ +// Some additional second level "domains" resolve directly as hostnames, such as +// pannet.pa, so we add a rule for "pa". +pa +ac.pa +gob.pa +com.pa +org.pa +sld.pa +edu.pa +net.pa +ing.pa +abo.pa +med.pa +nom.pa + +// pe : https://www.nic.pe/InformeFinalComision.pdf +pe +edu.pe +gob.pe +nom.pe +mil.pe +org.pe +com.pe +net.pe + +// pf : http://www.gobin.info/domainname/formulaire-pf.pdf +pf +com.pf +org.pf +edu.pf + +// pg : http://en.wikipedia.org/wiki/.pg +*.pg + +// ph : http://www.domains.ph/FAQ2.asp +// Submitted by registry 2008-06-13 +ph +com.ph +net.ph +org.ph +gov.ph +edu.ph +ngo.ph +mil.ph +i.ph + +// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK +pk +com.pk +net.pk +edu.pk +org.pk +fam.pk +biz.pk +web.pk +gov.pk +gob.pk +gok.pk +gon.pk +gop.pk +gos.pk +info.pk + +// pl http://www.dns.pl/english/index.html +// updated by .PL registry on 2015-04-28 +pl +com.pl +net.pl +org.pl +// pl functional domains (http://www.dns.pl/english/index.html) +aid.pl +agro.pl +atm.pl +auto.pl +biz.pl +edu.pl +gmina.pl +gsm.pl +info.pl +mail.pl +miasta.pl +media.pl +mil.pl +nieruchomosci.pl +nom.pl +pc.pl +powiat.pl +priv.pl +realestate.pl +rel.pl +sex.pl +shop.pl +sklep.pl +sos.pl +szkola.pl +targi.pl +tm.pl +tourism.pl +travel.pl +turystyka.pl +// Government domains +gov.pl +ap.gov.pl +ic.gov.pl +is.gov.pl +us.gov.pl +kmpsp.gov.pl +kppsp.gov.pl +kwpsp.gov.pl +psp.gov.pl +wskr.gov.pl +kwp.gov.pl +mw.gov.pl +ug.gov.pl +um.gov.pl +umig.gov.pl +ugim.gov.pl +upow.gov.pl +uw.gov.pl +starostwo.gov.pl +pa.gov.pl +po.gov.pl +psse.gov.pl +pup.gov.pl +rzgw.gov.pl +sa.gov.pl +so.gov.pl +sr.gov.pl +wsa.gov.pl +sko.gov.pl +uzs.gov.pl +wiih.gov.pl +winb.gov.pl +pinb.gov.pl +wios.gov.pl +witd.gov.pl +wzmiuw.gov.pl +piw.gov.pl +wiw.gov.pl +griw.gov.pl +wif.gov.pl +oum.gov.pl +sdn.gov.pl +zp.gov.pl +uppo.gov.pl +mup.gov.pl +wuoz.gov.pl +konsulat.gov.pl +oirm.gov.pl +// pl regional domains (http://www.dns.pl/english/index.html) +augustow.pl +babia-gora.pl +bedzin.pl +beskidy.pl +bialowieza.pl +bialystok.pl +bielawa.pl +bieszczady.pl +boleslawiec.pl +bydgoszcz.pl +bytom.pl +cieszyn.pl +czeladz.pl +czest.pl +dlugoleka.pl +elblag.pl +elk.pl +glogow.pl +gniezno.pl +gorlice.pl +grajewo.pl +ilawa.pl +jaworzno.pl +jelenia-gora.pl +jgora.pl +kalisz.pl +kazimierz-dolny.pl +karpacz.pl +kartuzy.pl +kaszuby.pl +katowice.pl +kepno.pl +ketrzyn.pl +klodzko.pl +kobierzyce.pl +kolobrzeg.pl +konin.pl +konskowola.pl +kutno.pl +lapy.pl +lebork.pl +legnica.pl +lezajsk.pl +limanowa.pl +lomza.pl +lowicz.pl +lubin.pl +lukow.pl +malbork.pl +malopolska.pl +mazowsze.pl +mazury.pl +mielec.pl +mielno.pl +mragowo.pl +naklo.pl +nowaruda.pl +nysa.pl +olawa.pl +olecko.pl +olkusz.pl +olsztyn.pl +opoczno.pl +opole.pl +ostroda.pl +ostroleka.pl +ostrowiec.pl +ostrowwlkp.pl +pila.pl +pisz.pl +podhale.pl +podlasie.pl +polkowice.pl +pomorze.pl +pomorskie.pl +prochowice.pl +pruszkow.pl +przeworsk.pl +pulawy.pl +radom.pl +rawa-maz.pl +rybnik.pl +rzeszow.pl +sanok.pl +sejny.pl +slask.pl +slupsk.pl +sosnowiec.pl +stalowa-wola.pl +skoczow.pl +starachowice.pl +stargard.pl +suwalki.pl +swidnica.pl +swiebodzin.pl +swinoujscie.pl +szczecin.pl +szczytno.pl +tarnobrzeg.pl +tgory.pl +turek.pl +tychy.pl +ustka.pl +walbrzych.pl +warmia.pl +warszawa.pl +waw.pl +wegrow.pl +wielun.pl +wlocl.pl +wloclawek.pl +wodzislaw.pl +wolomin.pl +wroclaw.pl +zachpomor.pl +zagan.pl +zarow.pl +zgora.pl +zgorzelec.pl + +// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +pm + +// pn : http://www.government.pn/PnRegistry/policies.htm +pn +gov.pn +co.pn +org.pn +edu.pn +net.pn + +// post : http://en.wikipedia.org/wiki/.post +post + +// pr : http://www.nic.pr/index.asp?f=1 +pr +com.pr +net.pr +org.pr +gov.pr +edu.pr +isla.pr +pro.pr +biz.pr +info.pr +name.pr +// these aren't mentioned on nic.pr, but on http://en.wikipedia.org/wiki/.pr +est.pr +prof.pr +ac.pr + +// pro : http://www.nic.pro/support_faq.htm +pro +aca.pro +bar.pro +cpa.pro +jur.pro +law.pro +med.pro +eng.pro + +// ps : http://en.wikipedia.org/wiki/.ps +// http://www.nic.ps/registration/policy.html#reg +ps +edu.ps +gov.ps +sec.ps +plo.ps +com.ps +org.ps +net.ps + +// pt : http://online.dns.pt/dns/start_dns +pt +net.pt +gov.pt +org.pt +edu.pt +int.pt +publ.pt +com.pt +nome.pt + +// pw : http://en.wikipedia.org/wiki/.pw +pw +co.pw +ne.pw +or.pw +ed.pw +go.pw +belau.pw + +// py : http://www.nic.py/pautas.html#seccion_9 +// Confirmed by registry 2012-10-03 +py +com.py +coop.py +edu.py +gov.py +mil.py +net.py +org.py + +// qa : http://domains.qa/en/ +qa +com.qa +edu.qa +gov.qa +mil.qa +name.qa +net.qa +org.qa +sch.qa + +// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs +re +com.re +asso.re +nom.re + +// ro : http://www.rotld.ro/ +ro +com.ro +org.ro +tm.ro +nt.ro +nom.ro +info.ro +rec.ro +arts.ro +firm.ro +store.ro +www.ro + +// rs : http://en.wikipedia.org/wiki/.rs +rs +co.rs +org.rs +edu.rs +ac.rs +gov.rs +in.rs + +// ru : http://www.cctld.ru/ru/docs/aktiv_8.php +// Industry domains +ru +ac.ru +com.ru +edu.ru +int.ru +net.ru +org.ru +pp.ru +// Geographical domains +adygeya.ru +altai.ru +amur.ru +arkhangelsk.ru +astrakhan.ru +bashkiria.ru +belgorod.ru +bir.ru +bryansk.ru +buryatia.ru +cbg.ru +chel.ru +chelyabinsk.ru +chita.ru +chukotka.ru +chuvashia.ru +dagestan.ru +dudinka.ru +e-burg.ru +grozny.ru +irkutsk.ru +ivanovo.ru +izhevsk.ru +jar.ru +joshkar-ola.ru +kalmykia.ru +kaluga.ru +kamchatka.ru +karelia.ru +kazan.ru +kchr.ru +kemerovo.ru +khabarovsk.ru +khakassia.ru +khv.ru +kirov.ru +koenig.ru +komi.ru +kostroma.ru +krasnoyarsk.ru +kuban.ru +kurgan.ru +kursk.ru +lipetsk.ru +magadan.ru +mari.ru +mari-el.ru +marine.ru +mordovia.ru +// mosreg.ru Bug 1090800 - removed at request of Aleksey Konstantinov +msk.ru +murmansk.ru +nalchik.ru +nnov.ru +nov.ru +novosibirsk.ru +nsk.ru +omsk.ru +orenburg.ru +oryol.ru +palana.ru +penza.ru +perm.ru +ptz.ru +rnd.ru +ryazan.ru +sakhalin.ru +samara.ru +saratov.ru +simbirsk.ru +smolensk.ru +spb.ru +stavropol.ru +stv.ru +surgut.ru +tambov.ru +tatarstan.ru +tom.ru +tomsk.ru +tsaritsyn.ru +tsk.ru +tula.ru +tuva.ru +tver.ru +tyumen.ru +udm.ru +udmurtia.ru +ulan-ude.ru +vladikavkaz.ru +vladimir.ru +vladivostok.ru +volgograd.ru +vologda.ru +voronezh.ru +vrn.ru +vyatka.ru +yakutia.ru +yamal.ru +yaroslavl.ru +yekaterinburg.ru +yuzhno-sakhalinsk.ru +// More geographical domains +amursk.ru +baikal.ru +cmw.ru +fareast.ru +jamal.ru +kms.ru +k-uralsk.ru +kustanai.ru +kuzbass.ru +magnitka.ru +mytis.ru +nakhodka.ru +nkz.ru +norilsk.ru +oskol.ru +pyatigorsk.ru +rubtsovsk.ru +snz.ru +syzran.ru +vdonsk.ru +zgrad.ru +// State domains +gov.ru +mil.ru +// Technical domains +test.ru + +// rw : http://www.nic.rw/cgi-bin/policy.pl +rw +gov.rw +net.rw +edu.rw +ac.rw +com.rw +co.rw +int.rw +mil.rw +gouv.rw + +// sa : http://www.nic.net.sa/ +sa +com.sa +net.sa +org.sa +gov.sa +med.sa +pub.sa +edu.sa +sch.sa + +// sb : http://www.sbnic.net.sb/ +// Submitted by registry 2008-06-08 +sb +com.sb +edu.sb +gov.sb +net.sb +org.sb + +// sc : http://www.nic.sc/ +sc +com.sc +gov.sc +net.sc +org.sc +edu.sc + +// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm +// Submitted by registry 2008-06-17 +sd +com.sd +net.sd +org.sd +edu.sd +med.sd +tv.sd +gov.sd +info.sd + +// se : http://en.wikipedia.org/wiki/.se +// Submitted by registry 2014-03-18 +se +a.se +ac.se +b.se +bd.se +brand.se +c.se +d.se +e.se +f.se +fh.se +fhsk.se +fhv.se +g.se +h.se +i.se +k.se +komforb.se +kommunalforbund.se +komvux.se +l.se +lanbib.se +m.se +n.se +naturbruksgymn.se +o.se +org.se +p.se +parti.se +pp.se +press.se +r.se +s.se +t.se +tm.se +u.se +w.se +x.se +y.se +z.se + +// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines +sg +com.sg +net.sg +org.sg +gov.sg +edu.sg +per.sg + +// sh : http://www.nic.sh/registrar.html +sh +com.sh +net.sh +gov.sh +org.sh +mil.sh + +// si : http://en.wikipedia.org/wiki/.si +si + +// sj : No registrations at this time. +// Submitted by registry 2008-06-16 +sj + +// sk : http://en.wikipedia.org/wiki/.sk +// list of 2nd level domains ? +sk + +// sl : http://www.nic.sl +// Submitted by registry 2008-06-12 +sl +com.sl +net.sl +edu.sl +gov.sl +org.sl + +// sm : http://en.wikipedia.org/wiki/.sm +sm + +// sn : http://en.wikipedia.org/wiki/.sn +sn +art.sn +com.sn +edu.sn +gouv.sn +org.sn +perso.sn +univ.sn + +// so : http://www.soregistry.com/ +so +com.so +net.so +org.so + +// sr : http://en.wikipedia.org/wiki/.sr +sr + +// st : http://www.nic.st/html/policyrules/ +st +co.st +com.st +consulado.st +edu.st +embaixada.st +gov.st +mil.st +net.st +org.st +principe.st +saotome.st +store.st + +// su : http://en.wikipedia.org/wiki/.su +su +adygeya.su +arkhangelsk.su +balashov.su +bashkiria.su +bryansk.su +dagestan.su +grozny.su +ivanovo.su +kalmykia.su +kaluga.su +karelia.su +khakassia.su +krasnodar.su +kurgan.su +lenug.su +mordovia.su +msk.su +murmansk.su +nalchik.su +nov.su +obninsk.su +penza.su +pokrovsk.su +sochi.su +spb.su +togliatti.su +troitsk.su +tula.su +tuva.su +vladikavkaz.su +vladimir.su +vologda.su + +// sv : http://www.svnet.org.sv/niveldos.pdf +sv +com.sv +edu.sv +gob.sv +org.sv +red.sv + +// sx : http://en.wikipedia.org/wiki/.sx +// Confirmed by registry 2012-05-31 +sx +gov.sx + +// sy : http://en.wikipedia.org/wiki/.sy +// see also: http://www.gobin.info/domainname/sy.doc +sy +edu.sy +gov.sy +net.sy +mil.sy +com.sy +org.sy + +// sz : http://en.wikipedia.org/wiki/.sz +// http://www.sispa.org.sz/ +sz +co.sz +ac.sz +org.sz + +// tc : http://en.wikipedia.org/wiki/.tc +tc + +// td : http://en.wikipedia.org/wiki/.td +td + +// tel: http://en.wikipedia.org/wiki/.tel +// http://www.telnic.org/ +tel + +// tf : http://en.wikipedia.org/wiki/.tf +tf + +// tg : http://en.wikipedia.org/wiki/.tg +// http://www.nic.tg/ +tg + +// th : http://en.wikipedia.org/wiki/.th +// Submitted by registry 2008-06-17 +th +ac.th +co.th +go.th +in.th +mi.th +net.th +or.th + +// tj : http://www.nic.tj/policy.html +tj +ac.tj +biz.tj +co.tj +com.tj +edu.tj +go.tj +gov.tj +int.tj +mil.tj +name.tj +net.tj +nic.tj +org.tj +test.tj +web.tj + +// tk : http://en.wikipedia.org/wiki/.tk +tk + +// tl : http://en.wikipedia.org/wiki/.tl +tl +gov.tl + +// tm : http://www.nic.tm/local.html +tm +com.tm +co.tm +org.tm +net.tm +nom.tm +gov.tm +mil.tm +edu.tm + +// tn : http://en.wikipedia.org/wiki/.tn +// http://whois.ati.tn/ +tn +com.tn +ens.tn +fin.tn +gov.tn +ind.tn +intl.tn +nat.tn +net.tn +org.tn +info.tn +perso.tn +tourism.tn +edunet.tn +rnrt.tn +rns.tn +rnu.tn +mincom.tn +agrinet.tn +defense.tn +turen.tn + +// to : http://en.wikipedia.org/wiki/.to +// Submitted by registry 2008-06-17 +to +com.to +gov.to +net.to +org.to +edu.to +mil.to + +// tp : No registrations at this time. +// Submitted by Ryan Sleevi 2014-01-03 +tp + +// subTLDs: https://www.nic.tr/forms/eng/policies.pdf +// and: https://www.nic.tr/forms/politikalar.pdf +// Submitted by 2014-07-19 +tr +com.tr +info.tr +biz.tr +net.tr +org.tr +web.tr +gen.tr +tv.tr +av.tr +dr.tr +bbs.tr +name.tr +tel.tr +gov.tr +bel.tr +pol.tr +mil.tr +k12.tr +edu.tr +kep.tr + +// Used by Northern Cyprus +nc.tr + +// Used by government agencies of Northern Cyprus +gov.nc.tr + +// travel : http://en.wikipedia.org/wiki/.travel +travel + +// tt : http://www.nic.tt/ +tt +co.tt +com.tt +org.tt +net.tt +biz.tt +info.tt +pro.tt +int.tt +coop.tt +jobs.tt +mobi.tt +travel.tt +museum.tt +aero.tt +name.tt +gov.tt +edu.tt + +// tv : http://en.wikipedia.org/wiki/.tv +// Not listing any 2LDs as reserved since none seem to exist in practice, +// Wikipedia notwithstanding. +tv + +// tw : http://en.wikipedia.org/wiki/.tw +tw +edu.tw +gov.tw +mil.tw +com.tw +net.tw +org.tw +idv.tw +game.tw +ebiz.tw +club.tw +網路.tw +組織.tw +商業.tw + +// tz : http://www.tznic.or.tz/index.php/domains +// Confirmed by registry 2013-01-22 +tz +ac.tz +co.tz +go.tz +hotel.tz +info.tz +me.tz +mil.tz +mobi.tz +ne.tz +or.tz +sc.tz +tv.tz + +// ua : https://hostmaster.ua/policy/?ua +// Submitted by registry 2012-04-27 +ua +// ua 2LD +com.ua +edu.ua +gov.ua +in.ua +net.ua +org.ua +// ua geographic names +// https://hostmaster.ua/2ld/ +cherkassy.ua +cherkasy.ua +chernigov.ua +chernihiv.ua +chernivtsi.ua +chernovtsy.ua +ck.ua +cn.ua +cr.ua +crimea.ua +cv.ua +dn.ua +dnepropetrovsk.ua +dnipropetrovsk.ua +dominic.ua +donetsk.ua +dp.ua +if.ua +ivano-frankivsk.ua +kh.ua +kharkiv.ua +kharkov.ua +kherson.ua +khmelnitskiy.ua +khmelnytskyi.ua +kiev.ua +kirovograd.ua +km.ua +kr.ua +krym.ua +ks.ua +kv.ua +kyiv.ua +lg.ua +lt.ua +lugansk.ua +lutsk.ua +lv.ua +lviv.ua +mk.ua +mykolaiv.ua +nikolaev.ua +od.ua +odesa.ua +odessa.ua +pl.ua +poltava.ua +rivne.ua +rovno.ua +rv.ua +sb.ua +sebastopol.ua +sevastopol.ua +sm.ua +sumy.ua +te.ua +ternopil.ua +uz.ua +uzhgorod.ua +vinnica.ua +vinnytsia.ua +vn.ua +volyn.ua +yalta.ua +zaporizhzhe.ua +zaporizhzhia.ua +zhitomir.ua +zhytomyr.ua +zp.ua +zt.ua + +// Private registries in .ua +co.ua +pp.ua + +// ug : https://www.registry.co.ug/ +ug +co.ug +or.ug +ac.ug +sc.ug +go.ug +ne.ug +com.ug +org.ug + +// uk : http://en.wikipedia.org/wiki/.uk +// Submitted by registry +uk +ac.uk +co.uk +gov.uk +ltd.uk +me.uk +net.uk +nhs.uk +org.uk +plc.uk +police.uk +*.sch.uk + +// us : http://en.wikipedia.org/wiki/.us +us +dni.us +fed.us +isa.us +kids.us +nsn.us +// us geographic names +ak.us +al.us +ar.us +as.us +az.us +ca.us +co.us +ct.us +dc.us +de.us +fl.us +ga.us +gu.us +hi.us +ia.us +id.us +il.us +in.us +ks.us +ky.us +la.us +ma.us +md.us +me.us +mi.us +mn.us +mo.us +ms.us +mt.us +nc.us +nd.us +ne.us +nh.us +nj.us +nm.us +nv.us +ny.us +oh.us +ok.us +or.us +pa.us +pr.us +ri.us +sc.us +sd.us +tn.us +tx.us +ut.us +vi.us +vt.us +va.us +wa.us +wi.us +wv.us +wy.us +// The registrar notes several more specific domains available in each state, +// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat +// haphazard; in some states these domains resolve as addresses, while in others +// only subdomains are available, or even nothing at all. We include the +// most common ones where it's clear that different sites are different +// entities. +k12.ak.us +k12.al.us +k12.ar.us +k12.as.us +k12.az.us +k12.ca.us +k12.co.us +k12.ct.us +k12.dc.us +k12.de.us +k12.fl.us +k12.ga.us +k12.gu.us +// k12.hi.us Bug 614565 - Hawaii has a state-wide DOE login +k12.ia.us +k12.id.us +k12.il.us +k12.in.us +k12.ks.us +k12.ky.us +k12.la.us +k12.ma.us +k12.md.us +k12.me.us +k12.mi.us +k12.mn.us +k12.mo.us +k12.ms.us +k12.mt.us +k12.nc.us +// k12.nd.us Bug 1028347 - Removed at request of Travis Rosso +k12.ne.us +k12.nh.us +k12.nj.us +k12.nm.us +k12.nv.us +k12.ny.us +k12.oh.us +k12.ok.us +k12.or.us +k12.pa.us +k12.pr.us +k12.ri.us +k12.sc.us +// k12.sd.us Bug 934131 - Removed at request of James Booze +k12.tn.us +k12.tx.us +k12.ut.us +k12.vi.us +k12.vt.us +k12.va.us +k12.wa.us +k12.wi.us +// k12.wv.us Bug 947705 - Removed at request of Verne Britton +k12.wy.us +cc.ak.us +cc.al.us +cc.ar.us +cc.as.us +cc.az.us +cc.ca.us +cc.co.us +cc.ct.us +cc.dc.us +cc.de.us +cc.fl.us +cc.ga.us +cc.gu.us +cc.hi.us +cc.ia.us +cc.id.us +cc.il.us +cc.in.us +cc.ks.us +cc.ky.us +cc.la.us +cc.ma.us +cc.md.us +cc.me.us +cc.mi.us +cc.mn.us +cc.mo.us +cc.ms.us +cc.mt.us +cc.nc.us +cc.nd.us +cc.ne.us +cc.nh.us +cc.nj.us +cc.nm.us +cc.nv.us +cc.ny.us +cc.oh.us +cc.ok.us +cc.or.us +cc.pa.us +cc.pr.us +cc.ri.us +cc.sc.us +cc.sd.us +cc.tn.us +cc.tx.us +cc.ut.us +cc.vi.us +cc.vt.us +cc.va.us +cc.wa.us +cc.wi.us +cc.wv.us +cc.wy.us +lib.ak.us +lib.al.us +lib.ar.us +lib.as.us +lib.az.us +lib.ca.us +lib.co.us +lib.ct.us +lib.dc.us +lib.de.us +lib.fl.us +lib.ga.us +lib.gu.us +lib.hi.us +lib.ia.us +lib.id.us +lib.il.us +lib.in.us +lib.ks.us +lib.ky.us +lib.la.us +lib.ma.us +lib.md.us +lib.me.us +lib.mi.us +lib.mn.us +lib.mo.us +lib.ms.us +lib.mt.us +lib.nc.us +lib.nd.us +lib.ne.us +lib.nh.us +lib.nj.us +lib.nm.us +lib.nv.us +lib.ny.us +lib.oh.us +lib.ok.us +lib.or.us +lib.pa.us +lib.pr.us +lib.ri.us +lib.sc.us +lib.sd.us +lib.tn.us +lib.tx.us +lib.ut.us +lib.vi.us +lib.vt.us +lib.va.us +lib.wa.us +lib.wi.us +// lib.wv.us Bug 941670 - Removed at request of Larry W Arnold +lib.wy.us +// k12.ma.us contains school districts in Massachusetts. The 4LDs are +// managed indepedently except for private (PVT), charter (CHTR) and +// parochial (PAROCH) schools. Those are delegated dorectly to the +// 5LD operators. +pvt.k12.ma.us +chtr.k12.ma.us +paroch.k12.ma.us + +// uy : http://www.nic.org.uy/ +uy +com.uy +edu.uy +gub.uy +mil.uy +net.uy +org.uy + +// uz : http://www.reg.uz/ +uz +co.uz +com.uz +net.uz +org.uz + +// va : http://en.wikipedia.org/wiki/.va +va + +// vc : http://en.wikipedia.org/wiki/.vc +// Submitted by registry 2008-06-13 +vc +com.vc +net.vc +org.vc +gov.vc +mil.vc +edu.vc + +// ve : https://registro.nic.ve/ +// Confirmed by registry 2012-10-04 +// Updated 2014-05-20 - Bug 940478 +ve +arts.ve +co.ve +com.ve +e12.ve +edu.ve +firm.ve +gob.ve +gov.ve +info.ve +int.ve +mil.ve +net.ve +org.ve +rec.ve +store.ve +tec.ve +web.ve + +// vg : http://en.wikipedia.org/wiki/.vg +vg + +// vi : http://www.nic.vi/newdomainform.htm +// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other +// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they +// are available for registration (which they do not seem to be). +vi +co.vi +com.vi +k12.vi +net.vi +org.vi + +// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp +vn +com.vn +net.vn +org.vn +edu.vn +gov.vn +int.vn +ac.vn +biz.vn +info.vn +name.vn +pro.vn +health.vn + +// vu : http://en.wikipedia.org/wiki/.vu +// http://www.vunic.vu/ +vu +com.vu +edu.vu +net.vu +org.vu + +// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +wf + +// ws : http://en.wikipedia.org/wiki/.ws +// http://samoanic.ws/index.dhtml +ws +com.ws +net.ws +org.ws +gov.ws +edu.ws + +// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +yt + +// IDN ccTLDs +// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then +// U-label, and follow this format: +// // A-Label ("", [, variant info]) : +// // [sponsoring org] +// U-Label + +// xn--mgbaam7a8h ("Emerat", Arabic) : AE +// http://nic.ae/english/arabicdomain/rules.jsp +امارات + +// xn--y9a3aq ("hye", Armenian) : AM +// ISOC AM (operated by .am Registry) +հայ + +// xn--54b7fta0cc ("Bangla", Bangla) : BD +বাংলা + +// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY +// Operated by .by registry +бел + +// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中国 + +// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中國 + +// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ +الجزائر + +// xn--wgbh1c ("Egypt/Masr", Arabic) : EG +// http://www.dotmasr.eg/ +مصر + +// xn--node ("ge", Georgian Mkhedruli) : GE +გე + +// xn--qxam ("el", Greek) : GR +// Hellenic Ministry of Infrastructure, Transport, and Networks +ελ + +// xn--j6w193g ("Hong Kong", Chinese) : HK +// https://www2.hkirc.hk/register/rules.jsp +香港 + +// xn--h2brj9c ("Bharat", Devanagari) : IN +// India +भारत + +// xn--mgbbh1a71e ("Bharat", Arabic) : IN +// India +بھارت + +// xn--fpcrj9c3d ("Bharat", Telugu) : IN +// India +భారత్ + +// xn--gecrj9c ("Bharat", Gujarati) : IN +// India +ભારત + +// xn--s9brj9c ("Bharat", Gurmukhi) : IN +// India +ਭਾਰਤ + +// xn--45brj9c ("Bharat", Bengali) : IN +// India +ভারত + +// xn--xkc2dl3a5ee0h ("India", Tamil) : IN +// India +இந்தியா + +// xn--mgba3a4f16a ("Iran", Persian) : IR +ایران + +// xn--mgba3a4fra ("Iran", Arabic) : IR +ايران + +// xn--mgbtx2b ("Iraq", Arabic) : IQ +// Communications and Media Commission +عراق + +// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO +// National Information Technology Center (NITC) +// Royal Scientific Society, Al-Jubeiha +الاردن + +// xn--3e0b707e ("Republic of Korea", Hangul) : KR +한국 + +// xn--80ao21a ("Kaz", Kazakh) : KZ +қаз + +// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK +// http://nic.lk +ලංකා + +// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK +// http://nic.lk +இலங்கை + +// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA +المغرب + +// xn--d1alf ("mkd", Macedonian) : MK +// MARnet +мкд + +// xn--l1acc ("mon", Mongolian) : MN +мон + +// xn--mix891f ("Macao", Chinese, Traditional) : MO +// MONIC / HNET Asia (Registry Operator for .mo) +澳門 + +// xn--mix082f ("Macao", Chinese, Simplified) : MO +澳门 + +// xn--mgbx4cd0ab ("Malaysia", Malay) : MY +مليسيا + +// xn--mgb9awbf ("Oman", Arabic) : OM +عمان + +// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK +پاکستان + +// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK +پاكستان + +// xn--ygbi2ammx ("Falasteen", Arabic) : PS +// The Palestinian National Internet Naming Authority (PNINA) +// http://www.pnina.ps +فلسطين + +// xn--90a3ac ("srb", Cyrillic) : RS +// http://www.rnids.rs/en/the-.срб-domain +срб +пр.срб +орг.срб +обр.срб +од.срб +упр.срб +ак.срб + +// xn--p1ai ("rf", Russian-Cyrillic) : RU +// http://www.cctld.ru/en/docs/rulesrf.php +рф + +// xn--wgbl6a ("Qatar", Arabic) : QA +// http://www.ict.gov.qa/ +قطر + +// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA +// http://www.nic.net.sa/ +السعودية + +// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant) : SA +السعودیة + +// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA +السعودیۃ + +// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA +السعوديه + +// xn--mgbpl2fh ("sudan", Arabic) : SD +// Operated by .sd registry +سودان + +// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG +新加坡 + +// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG +சிங்கப்பூர் + +// xn--ogbpf8fl ("Syria", Arabic) : SY +سورية + +// xn--mgbtf8fl ("Syria", Arabic, variant) : SY +سوريا + +// xn--o3cw4h ("Thai", Thai) : TH +// http://www.thnic.co.th +ไทย + +// xn--pgbs0dh ("Tunisia", Arabic) : TN +// http://nic.tn +تونس + +// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台灣 + +// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台湾 + +// xn--nnx388a ("Taiwan", Chinese, variant) : TW +臺灣 + +// xn--j1amh ("ukr", Cyrillic) : UA +укр + +// xn--mgb2ddes ("AlYemen", Arabic) : YE +اليمن + +// xxx : http://icmregistry.com +xxx + +// ye : http://www.y.net.ye/services/domain_name.htm +*.ye + +// za : http://www.zadna.org.za/slds.html +*.za + +// zm : http://en.wikipedia.org/wiki/.zm +*.zm + +// zw : http://en.wikipedia.org/wiki/.zw +*.zw + + +// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-05-06T09:31:08Z + +// aaa : 2015-02-26 American Automobile Association, Inc. +aaa + +// abb : 2014-10-24 ABB Ltd +abb + +// abbott : 2014-07-24 Abbott Laboratories, Inc. +abbott + +// abogado : 2014-04-24 Top Level Domain Holdings Limited +abogado + +// academy : 2013-11-07 Half Oaks, LLC +academy + +// accenture : 2014-08-15 Accenture plc +accenture + +// accountant : 2014-11-20 dot Accountant Limited +accountant + +// accountants : 2014-03-20 Knob Town, LLC +accountants + +// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG +aco + +// active : 2014-05-01 The Active Network, Inc +active + +// actor : 2013-12-12 United TLD Holdco Ltd. +actor + +// ads : 2014-12-04 Charleston Road Registry Inc. +ads + +// adult : 2014-10-16 ICM Registry AD LLC +adult + +// aeg : 2015-03-19 Aktiebolaget Electrolux +aeg + +// afl : 2014-10-02 Australian Football League +afl + +// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa +africa + +// africamagic : 2015-03-05 Electronic Media Network (Pty) Ltd +africamagic + +// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +agakhan + +// agency : 2013-11-14 Steel Falls, LLC +agency + +// aig : 2014-12-18 American International Group, Inc. +aig + +// airforce : 2014-03-06 United TLD Holdco Ltd. +airforce + +// airtel : 2014-10-24 Bharti Airtel Limited +airtel + +// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +akdn + +// alibaba : 2015-01-15 Alibaba Group Holding Limited +alibaba + +// alipay : 2015-01-15 Alibaba Group Holding Limited +alipay + +// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +allfinanz + +// alsace : 2014-07-02 REGION D ALSACE +alsace + +// amsterdam : 2014-07-24 Gemeente Amsterdam +amsterdam + +// analytics : 2014-12-18 Campus IP LLC +analytics + +// android : 2014-08-07 Charleston Road Registry Inc. +android + +// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +anquan + +// apartments : 2014-12-11 June Maple, LLC +apartments + +// aquarelle : 2014-07-24 Aquarelle.com +aquarelle + +// aramco : 2014-11-20 Aramco Services Company +aramco + +// archi : 2014-02-06 STARTING DOT LIMITED +archi + +// army : 2014-03-06 United TLD Holdco Ltd. +army + +// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E. +arte + +// associates : 2014-03-06 Baxter Hill, LLC +associates + +// attorney : 2014-03-20 +attorney + +// auction : 2014-03-20 +auction + +// audio : 2014-03-20 Uniregistry, Corp. +audio + +// author : 2014-12-18 Amazon EU S.à r.l. +author + +// auto : 2014-11-13 Uniregistry, Corp. +auto + +// autos : 2014-01-09 DERAutos, LLC +autos + +// avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca +avianca + +// axa : 2013-12-19 AXA SA +axa + +// azure : 2014-12-18 Microsoft Corporation +azure + +// baby : 2015-04-09 Johnson & Johnson Services, Inc. +baby + +// baidu : 2015-01-08 Baidu, Inc. +baidu + +// band : 2014-06-12 +band + +// bank : 2014-09-25 fTLD Registry Services LLC +bank + +// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +bar + +// barcelona : 2014-07-24 Municipi de Barcelona +barcelona + +// barclaycard : 2014-11-20 Barclays Bank PLC +barclaycard + +// barclays : 2014-11-20 Barclays Bank PLC +barclays + +// bargains : 2013-11-14 Half Hallow, LLC +bargains + +// bauhaus : 2014-04-17 Werkhaus GmbH +bauhaus + +// bayern : 2014-01-23 Bayern Connect GmbH +bayern + +// bbc : 2014-12-18 British Broadcasting Corporation +bbc + +// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +bbva + +// bcg : 2015-04-02 The Boston Consulting Group, Inc. +bcg + +// bcn : 2014-07-24 Municipi de Barcelona +bcn + +// beer : 2014-01-09 Top Level Domain Holdings Limited +beer + +// bentley : 2014-12-18 Bentley Motors Limited +bentley + +// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG +berlin + +// best : 2013-12-19 BestTLD Pty Ltd +best + +// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited +bharti + +// bible : 2014-06-19 American Bible Society +bible + +// bid : 2013-12-19 dot Bid Limited +bid + +// bike : 2013-08-27 Grand Hollow, LLC +bike + +// bing : 2014-12-18 Microsoft Corporation +bing + +// bingo : 2014-12-04 Sand Cedar, LLC +bingo + +// bio : 2014-03-06 STARTING DOT LIMITED +bio + +// black : 2014-01-16 Afilias Limited +black + +// blackfriday : 2014-01-16 Uniregistry, Corp. +blackfriday + +// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC +bloomberg + +// blue : 2013-11-07 Afilias Limited +blue + +// bms : 2014-10-30 Bristol-Myers Squibb Company +bms + +// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +bmw + +// bnl : 2014-07-24 Banca Nazionale del Lavoro +bnl + +// bnpparibas : 2014-05-29 BNP Paribas +bnpparibas + +// boats : 2014-12-04 DERBoats, LLC +boats + +// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +bom + +// bond : 2014-06-05 Bond University Limited +bond + +// boo : 2014-01-30 Charleston Road Registry Inc. +boo + +// boots : 2015-01-08 THE BOOTS COMPANY PLC +boots + +// bot : 2014-12-18 Amazon EU S.à r.l. +bot + +// boutique : 2013-11-14 Over Galley, LLC +boutique + +// bradesco : 2014-12-18 Banco Bradesco S.A. +bradesco + +// bridgestone : 2014-12-18 Bridgestone Corporation +bridgestone + +// broadway : 2014-12-22 Celebrate Broadway, Inc. +broadway + +// broker : 2014-12-11 IG Group Holdings PLC +broker + +// brother : 2015-01-29 Brother Industries, Ltd. +brother + +// brussels : 2014-02-06 DNS.be vzw +brussels + +// budapest : 2013-11-21 Top Level Domain Holdings Limited +budapest + +// build : 2013-11-07 Plan Bee LLC +build + +// builders : 2013-11-07 Atomic Madison, LLC +builders + +// business : 2013-11-07 Spring Cross, LLC +business + +// buy : 2014-12-18 Amazon EU S.à r.l. +buy + +// buzz : 2013-10-02 DOTSTRATEGY CO. +buzz + +// bzh : 2014-02-27 Association www.bzh +bzh + +// cab : 2013-10-24 Half Sunset, LLC +cab + +// cafe : 2015-02-11 Pioneer Canyon, LLC +cafe + +// cal : 2014-07-24 Charleston Road Registry Inc. +cal + +// call : 2014-12-18 Amazon EU S.à r.l. +call + +// camera : 2013-08-27 Atomic Maple, LLC +camera + +// camp : 2013-11-07 Delta Dynamite, LLC +camp + +// cancerresearch : 2014-05-15 Australian Cancer Research Foundation +cancerresearch + +// canon : 2014-09-12 Canon Inc. +canon + +// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +capetown + +// capital : 2014-03-06 Delta Mill, LLC +capital + +// car : 2015-01-22 Charleston Road Registry Inc. +car + +// caravan : 2013-12-12 Caravan International, Inc. +caravan + +// cards : 2013-12-05 Foggy Hollow, LLC +cards + +// care : 2014-03-06 Goose Cross +care + +// career : 2013-10-09 dotCareer LLC +career + +// careers : 2013-10-02 Wild Corner, LLC +careers + +// cars : 2014-11-13 Uniregistry, Corp. +cars + +// cartier : 2014-06-23 Richemont DNS Inc. +cartier + +// casa : 2013-11-21 Top Level Domain Holdings Limited +casa + +// cash : 2014-03-06 Delta Lake, LLC +cash + +// casino : 2014-12-18 Binky Sky, LLC +casino + +// catering : 2013-12-05 New Falls. LLC +catering + +// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +cba + +// cbn : 2014-08-22 The Christian Broadcasting Network, Inc. +cbn + +// ceb : 2015-04-09 The Corporate Executive Board Company +ceb + +// center : 2013-11-07 Tin Mill, LLC +center + +// ceo : 2013-11-07 CEOTLD Pty Ltd +ceo + +// cern : 2014-06-05 European Organization for Nuclear Research ("CERN") +cern + +// cfa : 2014-08-28 CFA Institute +cfa + +// cfd : 2014-12-11 IG Group Holdings PLC +cfd + +// chanel : 2015-04-09 Chanel International B.V. +chanel + +// channel : 2014-05-08 Charleston Road Registry Inc. +channel + +// chase : 2015-04-30 JPMorgan Chase & Co. +chase + +// chat : 2014-12-04 Sand Fields, LLC +chat + +// cheap : 2013-11-14 Sand Cover, LLC +cheap + +// chloe : 2014-10-16 Richemont DNS Inc. +chloe + +// christmas : 2013-11-21 Uniregistry, Corp. +christmas + +// chrome : 2014-07-24 Charleston Road Registry Inc. +chrome + +// church : 2014-02-06 Holly Fields, LLC +church + +// cipriani : 2015-02-19 Hotel Cipriani Srl +cipriani + +// circle : 2014-12-18 Amazon EU S.à r.l. +circle + +// cisco : 2014-12-22 Cisco Technology, Inc. +cisco + +// citic : 2014-01-09 CITIC Group Corporation +citic + +// city : 2014-05-29 Snow Sky, LLC +city + +// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc. +cityeats + +// claims : 2014-03-20 Black Corner, LLC +claims + +// cleaning : 2013-12-05 Fox Shadow, LLC +cleaning + +// click : 2014-06-05 Uniregistry, Corp. +click + +// clinic : 2014-03-20 Goose Park, LLC +clinic + +// clothing : 2013-08-27 Steel Lake, LLC +clothing + +// cloud : 2015-04-16 ARUBA S.p.A. +cloud + +// club : 2013-11-08 .CLUB DOMAINS, LLC +club + +// coach : 2014-10-09 Koko Island, LLC +coach + +// codes : 2013-10-31 Puff Willow, LLC +codes + +// coffee : 2013-10-17 Trixy Cover, LLC +coffee + +// college : 2014-01-16 XYZ.COM LLC +college + +// cologne : 2014-02-05 NetCologne Gesellschaft für Telekommunikation mbH +cologne + +// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +commbank + +// community : 2013-12-05 Fox Orchard, LLC +community + +// company : 2013-11-07 Silver Avenue, LLC +company + +// computer : 2013-10-24 Pine Mill, LLC +computer + +// comsec : 2015-01-08 VeriSign, Inc. +comsec + +// condos : 2013-12-05 Pine House, LLC +condos + +// construction : 2013-09-16 Fox Dynamite, LLC +construction + +// consulting : 2013-12-05 +consulting + +// contact : 2015-01-08 Top Level Spectrum, Inc. +contact + +// contractors : 2013-09-10 Magic Woods, LLC +contractors + +// cooking : 2013-11-21 Top Level Domain Holdings Limited +cooking + +// cool : 2013-11-14 Koko Lake, LLC +cool + +// corsica : 2014-09-25 Collectivité Territoriale de Corse +corsica + +// country : 2013-12-19 Top Level Domain Holdings Limited +country + +// coupon : 2015-02-26 Amazon EU S.à r.l. +coupon + +// coupons : 2015-03-26 Black Island, LLC +coupons + +// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD +courses + +// credit : 2014-03-20 Snow Shadow, LLC +credit + +// creditcard : 2014-03-20 Binky Frostbite, LLC +creditcard + +// creditunion : 2015-01-22 CUNA Performance Resources, LLC +creditunion + +// cricket : 2014-10-09 dot Cricket Limited +cricket + +// crown : 2014-10-24 Crown Equipment Corporation +crown + +// crs : 2014-04-03 Federated Co-operatives Limited +crs + +// cruises : 2013-12-05 Spring Way, LLC +cruises + +// csc : 2014-09-25 Alliance-One Services, Inc. +csc + +// cuisinella : 2014-04-03 SALM S.A.S. +cuisinella + +// cymru : 2014-05-08 Nominet UK +cymru + +// cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd. +cyou + +// dabur : 2014-02-06 Dabur India Limited +dabur + +// dad : 2014-01-23 Charleston Road Registry Inc. +dad + +// dance : 2013-10-24 United TLD Holdco Ltd. +dance + +// date : 2014-11-20 dot Date Limited +date + +// dating : 2013-12-05 Pine Fest, LLC +dating + +// datsun : 2014-03-27 NISSAN MOTOR CO., LTD. +datsun + +// day : 2014-01-30 Charleston Road Registry Inc. +day + +// dclk : 2014-11-20 Charleston Road Registry Inc. +dclk + +// dealer : 2014-12-22 Dealer Dot Com, Inc. +dealer + +// deals : 2014-05-22 Sand Sunset, LLC +deals + +// degree : 2014-03-06 +degree + +// delivery : 2014-09-11 Steel Station, LLC +delivery + +// dell : 2014-10-24 Dell Inc. +dell + +// delta : 2015-02-19 Delta Air Lines, Inc. +delta + +// democrat : 2013-10-24 United TLD Holdco Ltd. +democrat + +// dental : 2014-03-20 Tin Birch, LLC +dental + +// dentist : 2014-03-20 +dentist + +// desi : 2013-11-14 Desi Networks LLC +desi + +// design : 2014-11-07 Top Level Design, LLC +design + +// dev : 2014-10-16 Charleston Road Registry Inc. +dev + +// diamonds : 2013-09-22 John Edge, LLC +diamonds + +// diet : 2014-06-26 Uniregistry, Corp. +diet + +// digital : 2014-03-06 Dash Park, LLC +digital + +// direct : 2014-04-10 Half Trail, LLC +direct + +// directory : 2013-09-20 Extra Madison, LLC +directory + +// discount : 2014-03-06 Holly Hill, LLC +discount + +// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd. +dnp + +// docs : 2014-10-16 Charleston Road Registry Inc. +docs + +// dog : 2014-12-04 Koko Mill, LLC +dog + +// doha : 2014-09-18 Communications Regulatory Authority (CRA) +doha + +// domains : 2013-10-17 Sugar Cross, LLC +domains + +// doosan : 2014-04-03 Doosan Corporation +doosan + +// download : 2014-11-20 dot Support Limited +download + +// drive : 2015-03-05 Charleston Road Registry Inc. +drive + +// dstv : 2015-03-12 MultiChoice (Proprietary) Limited +dstv + +// dubai : 2015-01-01 Dubai Smart Government Department +dubai + +// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +durban + +// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +dvag + +// earth : 2014-12-04 Interlink Co., Ltd. +earth + +// eat : 2014-01-23 Charleston Road Registry Inc. +eat + +// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V. +edeka + +// education : 2013-11-07 Brice Way, LLC +education + +// email : 2013-10-31 Spring Madison, LLC +email + +// emerck : 2014-04-03 Merck KGaA +emerck + +// energy : 2014-09-11 Binky Birch, LLC +energy + +// engineer : 2014-03-06 United TLD Holdco Ltd. +engineer + +// engineering : 2014-03-06 Romeo Canyon +engineering + +// enterprises : 2013-09-20 Snow Oaks, LLC +enterprises + +// epson : 2014-12-04 Seiko Epson Corporation +epson + +// equipment : 2013-08-27 Corn Station, LLC +equipment + +// erni : 2014-04-03 ERNI Group Holding AG +erni + +// esq : 2014-05-08 Charleston Road Registry Inc. +esq + +// estate : 2013-08-27 Trixy Park, LLC +estate + +// eurovision : 2014-04-24 European Broadcasting Union (EBU) +eurovision + +// eus : 2013-12-12 Puntueus Fundazioa +eus + +// events : 2013-12-05 Pioneer Maple, LLC +events + +// everbank : 2014-05-15 EverBank +everbank + +// exchange : 2014-03-06 Spring Falls, LLC +exchange + +// expert : 2013-11-21 Magic Pass, LLC +expert + +// exposed : 2013-12-05 Victor Beach, LLC +exposed + +// express : 2015-02-11 Sea Sunset, LLC +express + +// fage : 2014-12-18 Fage International S.A. +fage + +// fail : 2014-03-06 Atomic Pipe, LLC +fail + +// fairwinds : 2014-11-13 FairWinds Partners, LLC +fairwinds + +// faith : 2014-11-20 dot Faith Limited +faith + +// family : 2015-04-02 Bitter Galley, LLC +family + +// fan : 2014-03-06 +fan + +// fans : 2014-11-07 Asiamix Digital Limited +fans + +// farm : 2013-11-07 Just Maple, LLC +farm + +// fashion : 2014-07-03 Top Level Domain Holdings Limited +fashion + +// fast : 2014-12-18 Amazon EU S.à r.l. +fast + +// feedback : 2013-12-19 Top Level Spectrum, Inc. +feedback + +// ferrero : 2014-12-18 Ferrero Trading Lux S.A. +ferrero + +// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd +film + +// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +final + +// finance : 2014-03-20 Cotton Cypress, LLC +finance + +// financial : 2014-03-06 Just Cover, LLC +financial + +// firestone : 2014-12-18 Bridgestone Corporation +firestone + +// firmdale : 2014-03-27 Firmdale Holdings Limited +firmdale + +// fish : 2013-12-12 Fox Woods, LLC +fish + +// fishing : 2013-11-21 Top Level Domain Holdings Limited +fishing + +// fit : 2014-11-07 Top Level Domain Holdings Limited +fit + +// fitness : 2014-03-06 Brice Orchard, LLC +fitness + +// flickr : 2015-04-02 Yahoo! Domain Services Inc. +flickr + +// flights : 2013-12-05 Fox Station, LLC +flights + +// florist : 2013-11-07 Half Cypress, LLC +florist + +// flowers : 2014-10-09 Uniregistry, Corp. +flowers + +// flsmidth : 2014-07-24 FLSmidth A/S +flsmidth + +// fly : 2014-05-08 Charleston Road Registry Inc. +fly + +// foo : 2014-01-23 Charleston Road Registry Inc. +foo + +// football : 2014-12-18 Foggy Farms, LLC +football + +// ford : 2014-11-13 Ford Motor Company +ford + +// forex : 2014-12-11 IG Group Holdings PLC +forex + +// forsale : 2014-05-22 +forsale + +// forum : 2015-04-02 Fegistry, LLC +forum + +// foundation : 2013-12-05 John Dale, LLC +foundation + +// frl : 2014-05-15 FRLregistry B.V. +frl + +// frogans : 2013-12-19 OP3FT +frogans + +// frontier : 2015-02-05 Frontier Communications Corporation +frontier + +// fund : 2014-03-20 John Castle, LLC +fund + +// furniture : 2014-03-20 Lone Fields, LLC +furniture + +// futbol : 2013-09-20 +futbol + +// fyi : 2015-04-02 Silver Tigers, LLC +fyi + +// gal : 2013-11-07 Asociación puntoGAL +gal + +// gallery : 2013-09-13 Sugar House, LLC +gallery + +// gallup : 2015-02-19 Gallup, Inc. +gallup + +// garden : 2014-06-26 Top Level Domain Holdings Limited +garden + +// gbiz : 2014-07-17 Charleston Road Registry Inc. +gbiz + +// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems" +gdn + +// gea : 2014-12-04 GEA Group Aktiengesellschaft +gea + +// gent : 2014-01-23 COMBELL GROUP NV/SA +gent + +// genting : 2015-03-12 Resorts World Inc Pte. Ltd. +genting + +// ggee : 2014-01-09 GMO Internet, Inc. +ggee + +// gift : 2013-10-17 Uniregistry, Corp. +gift + +// gifts : 2014-07-03 Goose Sky, LLC +gifts + +// gives : 2014-03-06 United TLD Holdco Ltd. +gives + +// giving : 2014-11-13 Giving Limited +giving + +// glass : 2013-11-07 Black Cover, LLC +glass + +// gle : 2014-07-24 Charleston Road Registry Inc. +gle + +// global : 2014-04-17 Dot GLOBAL AS +global + +// globo : 2013-12-19 Globo Comunicação e Participações S.A +globo + +// gmail : 2014-05-01 Charleston Road Registry Inc. +gmail + +// gmo : 2014-01-09 GMO Internet, Inc. +gmo + +// gmx : 2014-04-24 1&1 Mail & Media GmbH +gmx + +// gold : 2015-01-22 June Edge, LLC +gold + +// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +goldpoint + +// golf : 2014-12-18 Lone falls, LLC +golf + +// goo : 2014-12-18 NTT Resonant Inc. +goo + +// goog : 2014-11-20 Charleston Road Registry Inc. +goog + +// google : 2014-07-24 Charleston Road Registry Inc. +google + +// gop : 2014-01-16 Republican State Leadership Committee, Inc. +gop + +// got : 2014-12-18 Amazon EU S.à r.l. +got + +// gotv : 2015-03-12 MultiChoice (Proprietary) Limited +gotv + +// graphics : 2013-09-13 Over Madison, LLC +graphics + +// gratis : 2014-03-20 Pioneer Tigers, LLC +gratis + +// green : 2014-05-08 Afilias Limited +green + +// gripe : 2014-03-06 Corn Sunset, LLC +gripe + +// group : 2014-08-15 Romeo Town, LLC +group + +// gucci : 2014-11-13 Guccio Gucci S.p.a. +gucci + +// guge : 2014-08-28 Charleston Road Registry Inc. +guge + +// guide : 2013-09-13 Snow Moon, LLC +guide + +// guitars : 2013-11-14 Uniregistry, Corp. +guitars + +// guru : 2013-08-27 Pioneer Cypress, LLC +guru + +// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH +hamburg + +// hangout : 2014-11-13 Charleston Road Registry Inc. +hangout + +// haus : 2013-12-05 +haus + +// hdfcbank : 2015-02-12 HDFC Bank Limited +hdfcbank + +// health : 2015-02-11 DotHealth, LLC +health + +// healthcare : 2014-06-12 Silver Glen, LLC +healthcare + +// help : 2014-06-26 Uniregistry, Corp. +help + +// helsinki : 2015-02-05 City of Helsinki +helsinki + +// here : 2014-02-06 Charleston Road Registry Inc. +here + +// hermes : 2014-07-10 HERMES INTERNATIONAL +hermes + +// hiphop : 2014-03-06 Uniregistry, Corp. +hiphop + +// hitachi : 2014-10-31 Hitachi, Ltd. +hitachi + +// hiv : 2014-03-13 dotHIV gemeinnuetziger e.V. +hiv + +// hockey : 2015-03-19 Half Willow, LLC +hockey + +// holdings : 2013-08-27 John Madison, LLC +holdings + +// holiday : 2013-11-07 Goose Woods, LLC +holiday + +// homedepot : 2015-04-02 Homer TLC, Inc. +homedepot + +// homes : 2014-01-09 DERHomes, LLC +homes + +// honda : 2014-12-18 Honda Motor Co., Ltd. +honda + +// horse : 2013-11-21 Top Level Domain Holdings Limited +horse + +// host : 2014-04-17 DotHost Inc. +host + +// hosting : 2014-05-29 Uniregistry, Corp. +hosting + +// hoteles : 2015-03-05 Travel Reservations SRL +hoteles + +// hotmail : 2014-12-18 Microsoft Corporation +hotmail + +// house : 2013-11-07 Sugar Park, LLC +house + +// how : 2014-01-23 Charleston Road Registry Inc. +how + +// hsbc : 2014-10-24 HSBC Holdings PLC +hsbc + +// htc : 2015-04-02 HTC corporation +htc + +// ibm : 2014-07-31 International Business Machines Corporation +ibm + +// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited +icbc + +// ice : 2014-10-30 IntercontinentalExchange, Inc. +ice + +// icu : 2015-01-08 One.com A/S +icu + +// ifm : 2014-01-30 ifm electronic gmbh +ifm + +// iinet : 2014-07-03 Connect West Pty. Ltd. +iinet + +// immo : 2014-07-10 Auburn Bloom, LLC +immo + +// immobilien : 2013-11-07 United TLD Holdco Ltd. +immobilien + +// industries : 2013-12-05 Outer House, LLC +industries + +// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD. +infiniti + +// ing : 2014-01-23 Charleston Road Registry Inc. +ing + +// ink : 2013-12-05 Top Level Design, LLC +ink + +// institute : 2013-11-07 Outer Maple, LLC +institute + +// insurance : 2015-02-19 fTLD Registry Services LLC +insurance + +// insure : 2014-03-20 Pioneer Willow, LLC +insure + +// international : 2013-11-07 Wild Way, LLC +international + +// investments : 2014-03-20 Holly Glen, LLC +investments + +// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A. +ipiranga + +// irish : 2014-08-07 Dot-Irish LLC +irish + +// iselect : 2015-02-11 iSelect Ltd +iselect + +// ist : 2014-08-28 Istanbul Metropolitan Municipality +ist + +// istanbul : 2014-08-28 Istanbul Metropolitan Municipality +istanbul + +// itau : 2014-10-02 Itau Unibanco Holding S.A. +itau + +// iwc : 2014-06-23 Richemont DNS Inc. +iwc + +// jaguar : 2014-11-13 Jaguar Land Rover Ltd +jaguar + +// java : 2014-06-19 Oracle Corporation +java + +// jcb : 2014-11-20 JCB Co., Ltd. +jcb + +// jcp : 2015-04-23 JCP Media, Inc. +jcp + +// jetzt : 2014-01-09 New TLD Company AB +jetzt + +// jewelry : 2015-03-05 Wild Bloom, LLC +jewelry + +// jio : 2015-04-02 Affinity Names, Inc. +jio + +// jlc : 2014-12-04 Richemont DNS Inc. +jlc + +// jll : 2015-04-02 Jones Lang LaSalle Incorporated +jll + +// jmp : 2015-03-26 Matrix IP LLC +jmp + +// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +joburg + +// jot : 2014-12-18 Amazon EU S.à r.l. +jot + +// joy : 2014-12-18 Amazon EU S.à r.l. +joy + +// jpmorgan : 2015-04-30 JPMorgan Chase & Co. +jpmorgan + +// jprs : 2014-09-18 Japan Registry Services Co., Ltd. +jprs + +// juegos : 2014-03-20 Uniregistry, Corp. +juegos + +// kaufen : 2013-11-07 United TLD Holdco Ltd. +kaufen + +// kddi : 2014-09-12 KDDI CORPORATION +kddi + +// kerryhotels : 2015-04-30 Kerry Trading Co. Limited +kerryhotels + +// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited +kerrylogistics + +// kerryproperties : 2015-04-09 Kerry Trading Co. Limited +kerryproperties + +// kfh : 2014-12-04 Kuwait Finance House +kfh + +// kim : 2013-09-23 Afilias Limited +kim + +// kinder : 2014-11-07 Ferrero Trading Lux S.A. +kinder + +// kitchen : 2013-09-20 Just Goodbye, LLC +kitchen + +// kiwi : 2013-09-20 DOT KIWI LIMITED +kiwi + +// koeln : 2014-01-09 NetCologne Gesellschaft für Telekommunikation mbH +koeln + +// komatsu : 2015-01-08 Komatsu Ltd. +komatsu + +// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft) +kpmg + +// kpn : 2015-01-08 Koninklijke KPN N.V. +kpn + +// krd : 2013-12-05 KRG Department of Information Technology +krd + +// kred : 2013-12-19 KredTLD Pty Ltd +kred + +// kuokgroup : 2015-04-09 Kerry Trading Co. Limited +kuokgroup + +// kyknet : 2015-03-05 Electronic Media Network (Pty) Ltd +kyknet + +// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen +kyoto + +// lacaixa : 2014-01-09 CAIXA D'ESTALVIS I PENSIONS DE BARCELONA +lacaixa + +// lancaster : 2015-02-12 LANCASTER +lancaster + +// land : 2013-09-10 Pine Moon, LLC +land + +// landrover : 2014-11-13 Jaguar Land Rover Ltd +landrover + +// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated +lasalle + +// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico +lat + +// latrobe : 2014-06-16 La Trobe University +latrobe + +// law : 2015-01-22 Minds + Machines Group Limited +law + +// lawyer : 2014-03-20 +lawyer + +// lds : 2014-03-20 IRI Domain Management, LLC ("Applicant") +lds + +// lease : 2014-03-06 Victor Trail, LLC +lease + +// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +leclerc + +// legal : 2014-10-16 Blue Falls, LLC +legal + +// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION +lexus + +// lgbt : 2014-05-08 Afilias Limited +lgbt + +// liaison : 2014-10-02 Liaison Technologies, Incorporated +liaison + +// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +lidl + +// life : 2014-02-06 Trixy Oaks, LLC +life + +// lifeinsurance : 2015-01-15 American Council of Life Insurers +lifeinsurance + +// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. +lifestyle + +// lighting : 2013-08-27 John McCook, LLC +lighting + +// like : 2014-12-18 Amazon EU S.à r.l. +like + +// limited : 2014-03-06 Big Fest, LLC +limited + +// limo : 2013-10-17 Hidden Frostbite, LLC +limo + +// lincoln : 2014-11-13 Ford Motor Company +lincoln + +// linde : 2014-12-04 Linde Aktiengesellschaft +linde + +// link : 2013-11-14 Uniregistry, Corp. +link + +// live : 2014-12-04 Half Woods, LLC +live + +// lixil : 2015-03-19 LIXIL Group Corporation +lixil + +// loan : 2014-11-20 dot Loan Limited +loan + +// loans : 2014-03-20 June Woods, LLC +loans + +// lol : 2015-01-30 Uniregistry, Corp. +lol + +// london : 2013-11-14 Dot London Domains Limited +london + +// lotte : 2014-11-07 Lotte Holdings Co., Ltd. +lotte + +// lotto : 2014-04-10 Afilias Limited +lotto + +// love : 2014-12-22 Merchant Law Group LLP +love + +// ltd : 2014-09-25 Over Corner, LLC +ltd + +// ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA +ltda + +// lupin : 2014-11-07 LUPIN LIMITED +lupin + +// luxe : 2014-01-09 Top Level Domain Holdings Limited +luxe + +// luxury : 2013-10-17 Luxury Partners, LLC +luxury + +// madrid : 2014-05-01 Comunidad de Madrid +madrid + +// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF) +maif + +// maison : 2013-12-05 Victor Frostbite, LLC +maison + +// makeup : 2015-01-15 L'Oréal +makeup + +// man : 2014-12-04 MAN SE +man + +// management : 2013-11-07 John Goodbye, LLC +management + +// mango : 2013-10-24 PUNTO FA S.L. +mango + +// market : 2014-03-06 +market + +// marketing : 2013-11-07 Fern Pass, LLC +marketing + +// markets : 2014-12-11 IG Group Holdings PLC +markets + +// marriott : 2014-10-09 Marriott Worldwide Corporation +marriott + +// mba : 2015-04-02 Lone Hollow, LLC +mba + +// media : 2014-03-06 Grand Glen, LLC +media + +// meet : 2014-01-16 +meet + +// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +melbourne + +// meme : 2014-01-30 Charleston Road Registry Inc. +meme + +// memorial : 2014-10-16 Dog Beach, LLC +memorial + +// men : 2015-02-26 Exclusive Registry Limited +men + +// menu : 2013-09-11 Wedding TLD2, LLC +menu + +// meo : 2014-11-07 PT Comunicacoes S.A. +meo + +// miami : 2013-12-19 Top Level Domain Holdings Limited +miami + +// microsoft : 2014-12-18 Microsoft Corporation +microsoft + +// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +mini + +// mls : 2015-04-23 The Canadian Real Estate Association +mls + +// mma : 2014-11-07 MMA IARD +mma + +// mnet : 2015-03-05 Electronic Media Network (Pty) Ltd +mnet + +// mobily : 2014-12-18 GreenTech Consultancy Company W.L.L. +mobily + +// moda : 2013-11-07 United TLD Holdco Ltd. +moda + +// moe : 2013-11-13 Interlink Co., Ltd. +moe + +// moi : 2014-12-18 Amazon EU S.à r.l. +moi + +// mom : 2015-04-16 Uniregistry, Corp. +mom + +// monash : 2013-09-30 Monash University +monash + +// money : 2014-10-16 Outer McCook, LLC +money + +// montblanc : 2014-06-23 Richemont DNS Inc. +montblanc + +// mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant") +mormon + +// mortgage : 2014-03-20 +mortgage + +// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +moscow + +// motorcycles : 2014-01-09 DERMotorcycles, LLC +motorcycles + +// mov : 2014-01-30 Charleston Road Registry Inc. +mov + +// movie : 2015-02-05 New Frostbite, LLC +movie + +// movistar : 2014-10-16 Telefónica S.A. +movistar + +// mtn : 2014-12-04 MTN Dubai Limited +mtn + +// mtpc : 2014-11-20 Mitsubishi Tanabe Pharma Corporation +mtpc + +// mtr : 2015-03-12 MTR Corporation Limited +mtr + +// multichoice : 2015-03-12 MultiChoice (Proprietary) Limited +multichoice + +// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC +mutual + +// mzansimagic : 2015-03-05 Electronic Media Network (Pty) Ltd +mzansimagic + +// nadex : 2014-12-11 IG Group Holdings PLC +nadex + +// nagoya : 2013-10-24 GMO Registry, Inc. +nagoya + +// naspers : 2015-02-12 Intelprop (Proprietary) Limited +naspers + +// natura : 2015-03-12 NATURA COSMÉTICOS S.A. +natura + +// navy : 2014-03-06 United TLD Holdco Ltd. +navy + +// nec : 2015-01-08 NEC Corporation +nec + +// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +netbank + +// network : 2013-11-14 Trixy Manor, LLC +network + +// neustar : 2013-12-05 NeuStar, Inc. +neustar + +// new : 2014-01-30 Charleston Road Registry Inc. +new + +// news : 2014-12-18 +news + +// nexus : 2014-07-24 Charleston Road Registry Inc. +nexus + +// ngo : 2014-03-06 Public Interest Registry +ngo + +// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK) +nhk + +// nico : 2014-12-04 DWANGO Co., Ltd. +nico + +// ninja : 2013-11-07 United TLD Holdco Ltd. +ninja + +// nissan : 2014-03-27 NISSAN MOTOR CO., LTD. +nissan + +// nokia : 2015-01-08 Nokia Corporation +nokia + +// norton : 2014-12-04 Symantec Corporation +norton + +// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +nowruz + +// nra : 2014-05-22 NRA Holdings Company, INC. +nra + +// nrw : 2013-11-21 Minds + Machines GmbH +nrw + +// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION +ntt + +// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications +nyc + +// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA +obi + +// observer : 2015-04-30 Guardian News and Media Limited +observer + +// office : 2015-03-12 Microsoft Corporation +office + +// okinawa : 2013-12-05 BusinessRalliart Inc. +okinawa + +// omega : 2015-01-08 The Swatch Group Ltd +omega + +// one : 2014-11-07 One.com A/S +one + +// ong : 2014-03-06 Public Interest Registry +ong + +// onl : 2013-09-16 I-Registry Ltd. +onl + +// online : 2015-01-15 DotOnline Inc. +online + +// ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED +ooo + +// oracle : 2014-06-19 Oracle Corporation +oracle + +// orange : 2015-03-12 Orange Brand Services Limited +orange + +// organic : 2014-03-27 Afilias Limited +organic + +// orientexpress : 2015-02-05 Belmond Ltd. +orientexpress + +// osaka : 2014-09-04 Interlink Co., Ltd. +osaka + +// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd. +otsuka + +// ovh : 2014-01-16 OVH SAS +ovh + +// page : 2014-12-04 Charleston Road Registry Inc. +page + +// pamperedchef : 2015-02-05 The Pampered Chef, Ltd. +pamperedchef + +// panerai : 2014-11-07 Richemont DNS Inc. +panerai + +// paris : 2014-01-30 City of Paris +paris + +// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +pars + +// partners : 2013-12-05 Magic Glen, LLC +partners + +// parts : 2013-12-05 Sea Goodbye, LLC +parts + +// party : 2014-09-11 Blue Sky Registry Limited +party + +// passagens : 2015-03-05 Travel Reservations SRL +passagens + +// payu : 2015-02-12 MIH PayU B.V. +payu + +// pharmacy : 2014-06-19 National Association of Boards of Pharmacy +pharmacy + +// philips : 2014-11-07 Koninklijke Philips N.V. +philips + +// photo : 2013-11-14 Uniregistry, Corp. +photo + +// photography : 2013-09-20 Sugar Glen, LLC +photography + +// photos : 2013-10-17 Sea Corner, LLC +photos + +// physio : 2014-05-01 PhysBiz Pty Ltd +physio + +// piaget : 2014-10-16 Richemont DNS Inc. +piaget + +// pics : 2013-11-14 Uniregistry, Corp. +pics + +// pictet : 2014-06-26 Pictet Europe S.A. +pictet + +// pictures : 2014-03-06 Foggy Sky, LLC +pictures + +// pid : 2015-01-08 Top Level Spectrum, Inc. +pid + +// pin : 2014-12-18 Amazon EU S.à r.l. +pin + +// pink : 2013-10-01 Afilias Limited +pink + +// pizza : 2014-06-26 Foggy Moon, LLC +pizza + +// place : 2014-04-24 Snow Galley, LLC +place + +// play : 2015-03-05 Charleston Road Registry Inc. +play + +// plumbing : 2013-09-10 Spring Tigers, LLC +plumbing + +// plus : 2015-02-05 Sugar Mill, LLC +plus + +// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +pohl + +// poker : 2014-07-03 Afilias Domains No. 5 Limited +poker + +// porn : 2014-10-16 ICM Registry PN LLC +porn + +// praxi : 2013-12-05 Praxi S.p.A. +praxi + +// press : 2014-04-03 DotPress Inc. +press + +// prod : 2014-01-23 Charleston Road Registry Inc. +prod + +// productions : 2013-12-05 Magic Birch, LLC +productions + +// prof : 2014-07-24 Charleston Road Registry Inc. +prof + +// promo : 2014-12-18 Play.PROMO Oy +promo + +// properties : 2013-12-05 Big Pass, LLC +properties + +// property : 2014-05-22 Uniregistry, Corp. +property + +// protection : 2015-04-23 Symantec Corporation +protection + +// pub : 2013-12-12 United TLD Holdco Ltd. +pub + +// qpon : 2013-11-14 dotCOOL, Inc. +qpon + +// quebec : 2013-12-19 PointQuébec Inc +quebec + +// quest : 2015-03-26 Quest ION Limited +quest + +// racing : 2014-12-04 Premier Registry Limited +racing + +// read : 2014-12-18 Amazon EU S.à r.l. +read + +// realtor : 2014-05-29 Real Estate Domains LLC +realtor + +// realty : 2015-03-19 Fegistry, LLC +realty + +// recipes : 2013-10-17 Grand Island, LLC +recipes + +// red : 2013-11-07 Afilias Limited +red + +// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. +redstone + +// redumbrella : 2015-03-26 Travelers TLD, LLC +redumbrella + +// rehab : 2014-03-06 United TLD Holdco Ltd. +rehab + +// reise : 2014-03-13 dotreise GmbH +reise + +// reisen : 2014-03-06 New Cypress, LLC +reisen + +// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. +reit + +// reliance : 2015-04-02 Reliance Industries Limited +reliance + +// ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd. +ren + +// rent : 2014-12-04 DERRent, LLC +rent + +// rentals : 2013-12-05 Big Hollow,LLC +rentals + +// repair : 2013-11-07 Lone Sunset, LLC +repair + +// report : 2013-12-05 Binky Glen, LLC +report + +// republican : 2014-03-20 United TLD Holdco Ltd. +republican + +// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +rest + +// restaurant : 2014-07-03 Snow Avenue, LLC +restaurant + +// review : 2014-11-20 dot Review Limited +review + +// reviews : 2013-09-13 +reviews + +// rich : 2013-11-21 I-Registry Ltd. +rich + +// ricoh : 2014-11-20 Ricoh Company, Ltd. +ricoh + +// ril : 2015-04-02 Reliance Industries Limited +ril + +// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO +rio + +// rip : 2014-07-10 United TLD Holdco Ltd. +rip + +// rocher : 2014-12-18 Ferrero Trading Lux S.A. +rocher + +// rocks : 2013-11-14 +rocks + +// rodeo : 2013-12-19 Top Level Domain Holdings Limited +rodeo + +// room : 2014-12-18 Amazon EU S.à r.l. +room + +// rsvp : 2014-05-08 Charleston Road Registry Inc. +rsvp + +// ruhr : 2013-10-02 regiodot GmbH & Co. KG +ruhr + +// run : 2015-03-19 Snow Park, LLC +run + +// rwe : 2015-04-02 RWE AG +rwe + +// ryukyu : 2014-01-09 BusinessRalliart Inc. +ryukyu + +// saarland : 2013-12-12 dotSaarland GmbH +saarland + +// safe : 2014-12-18 Amazon EU S.à r.l. +safe + +// safety : 2015-01-08 Safety Registry Services, LLC. +safety + +// sakura : 2014-12-18 SAKURA Internet Inc. +sakura + +// sale : 2014-10-16 +sale + +// salon : 2014-12-11 Outer Orchard, LLC +salon + +// samsung : 2014-04-03 SAMSUNG SDS CO., LTD +samsung + +// sandvik : 2014-11-13 Sandvik AB +sandvik + +// sandvikcoromant : 2014-11-07 Sandvik AB +sandvikcoromant + +// sanofi : 2014-10-09 Sanofi +sanofi + +// sap : 2014-03-27 SAP AG +sap + +// sapo : 2014-11-07 PT Comunicacoes S.A. +sapo + +// sarl : 2014-07-03 Delta Orchard, LLC +sarl + +// sas : 2015-04-02 Research IP LLC +sas + +// saxo : 2014-10-31 Saxo Bank A/S +saxo + +// sbi : 2015-03-12 STATE BANK OF INDIA +sbi + +// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION +sbs + +// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) +sca + +// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB") +scb + +// schmidt : 2014-04-03 SALM S.A.S. +schmidt + +// scholarships : 2014-04-24 Scholarships.com, LLC +scholarships + +// school : 2014-12-18 Little Galley, LLC +school + +// schule : 2014-03-06 Outer Moon, LLC +schule + +// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +schwarz + +// science : 2014-09-11 dot Science Limited +science + +// scor : 2014-10-31 SCOR SE +scor + +// scot : 2014-01-23 Dot Scot Registry Limited +scot + +// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal) +seat + +// seek : 2014-12-04 Seek Limited +seek + +// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A. +sener + +// services : 2014-02-27 Fox Castle, LLC +services + +// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG +sew + +// sex : 2014-11-13 ICM Registry SX LLC +sex + +// sexy : 2013-09-11 Uniregistry, Corp. +sexy + +// sharp : 2014-05-01 Sharp Corporation +sharp + +// shaw : 2015-04-23 Shaw Cablesystems G.P. +shaw + +// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +shia + +// shiksha : 2013-11-14 Afilias Limited +shiksha + +// shoes : 2013-10-02 Binky Galley, LLC +shoes + +// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +shouji + +// show : 2015-03-05 Snow Beach, LLC +show + +// shriram : 2014-01-23 Shriram Capital Ltd. +shriram + +// sina : 2015-03-12 Sina Corporation +sina + +// singles : 2013-08-27 Fern Madison, LLC +singles + +// site : 2015-01-15 DotSite Inc. +site + +// ski : 2015-04-09 STARTING DOT LIMITED +ski + +// skin : 2015-01-15 L'Oréal +skin + +// sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch +sky + +// skype : 2014-12-18 Microsoft Corporation +skype + +// smile : 2014-12-18 Amazon EU S.à r.l. +smile + +// sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F +sncf + +// soccer : 2015-03-26 Foggy Shadow, LLC +soccer + +// social : 2013-11-07 United TLD Holdco Ltd. +social + +// software : 2014-03-20 +software + +// sohu : 2013-12-19 Sohu.com Limited +sohu + +// solar : 2013-11-07 Ruby Town, LLC +solar + +// solutions : 2013-11-07 Silver Cover, LLC +solutions + +// song : 2015-02-26 Amazon EU S.à r.l. +song + +// sony : 2015-01-08 Sony Corporation +sony + +// soy : 2014-01-23 Charleston Road Registry Inc. +soy + +// space : 2014-04-03 DotSpace Inc. +space + +// spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG +spiegel + +// spot : 2015-02-26 Amazon EU S.à r.l. +spot + +// spreadbetting : 2014-12-11 IG Group Holdings PLC +spreadbetting + +// stada : 2014-11-13 STADA Arzneimittel AG +stada + +// star : 2015-01-08 Star India Private Limited +star + +// starhub : 2015-02-05 StarHub Limited +starhub + +// statebank : 2015-03-12 STATE BANK OF INDIA +statebank + +// statoil : 2014-12-04 Statoil ASA +statoil + +// stc : 2014-10-09 Saudi Telecom Company +stc + +// stcgroup : 2014-10-09 Saudi Telecom Company +stcgroup + +// stockholm : 2014-12-18 Stockholms kommun +stockholm + +// storage : 2014-12-22 Self Storage Company LLC +storage + +// store : 2015-04-09 DotStore Inc. +store + +// studio : 2015-02-11 Spring Goodbye, LLC +studio + +// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD +study + +// style : 2014-12-04 Binky Moon, LLC +style + +// sucks : 2014-12-22 Vox Populi Registry Inc. +sucks + +// supersport : 2015-03-05 SuperSport International Holdings Proprietary Limited +supersport + +// supplies : 2013-12-19 Atomic Fields, LLC +supplies + +// supply : 2013-12-19 Half Falls, LLC +supply + +// support : 2013-10-24 Grand Orchard, LLC +support + +// surf : 2014-01-09 Top Level Domain Holdings Limited +surf + +// surgery : 2014-03-20 Tin Avenue, LLC +surgery + +// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION +suzuki + +// swatch : 2015-01-08 The Swatch Group Ltd +swatch + +// swiss : 2014-10-16 Swiss Confederation +swiss + +// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet +sydney + +// symantec : 2014-12-04 Symantec Corporation +symantec + +// systems : 2013-11-07 Dash Cypress, LLC +systems + +// tab : 2014-12-04 Tabcorp Holdings Limited +tab + +// taipei : 2014-07-10 Taipei City Government +taipei + +// talk : 2015-04-09 Amazon EU S.à r.l. +talk + +// taobao : 2015-01-15 Alibaba Group Holding Limited +taobao + +// tatamotors : 2015-03-12 Tata Motors Ltd +tatamotors + +// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +tatar + +// tattoo : 2013-08-30 Uniregistry, Corp. +tattoo + +// tax : 2014-03-20 Storm Orchard, LLC +tax + +// taxi : 2015-03-19 Pine Falls, LLC +taxi + +// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +tci + +// team : 2015-03-05 Atomic Lake, LLC +team + +// tech : 2015-01-30 Dot Tech LLC +tech + +// technology : 2013-09-13 Auburn Falls +technology + +// telecity : 2015-02-19 TelecityGroup International Limited +telecity + +// telefonica : 2014-10-16 Telefónica S.A. +telefonica + +// temasek : 2014-08-07 Temasek Holdings (Private) Limited +temasek + +// tennis : 2014-12-04 Cotton Bloom, LLC +tennis + +// thd : 2015-04-02 Homer TLC, Inc. +thd + +// theater : 2015-03-19 Blue Tigers, LLC +theater + +// theguardian : 2015-04-30 Guardian News and Media Limited +theguardian + +// tickets : 2015-02-05 Accent Media Limited +tickets + +// tienda : 2013-11-14 Victor Manor, LLC +tienda + +// tiffany : 2015-01-30 Tiffany and Company +tiffany + +// tips : 2013-09-20 Corn Willow, LLC +tips + +// tires : 2014-11-07 Dog Edge, LLC +tires + +// tirol : 2014-04-24 punkt Tirol GmbH +tirol + +// tmall : 2015-01-15 Alibaba Group Holding Limited +tmall + +// today : 2013-09-20 Pearl Woods, LLC +today + +// tokyo : 2013-11-13 GMO Registry, Inc. +tokyo + +// tools : 2013-11-21 Pioneer North, LLC +tools + +// top : 2014-03-20 Jiangsu Bangning Science & Technology Co.,Ltd. +top + +// toray : 2014-12-18 Toray Industries, Inc. +toray + +// toshiba : 2014-04-10 TOSHIBA Corporation +toshiba + +// tours : 2015-01-22 Sugar Station, LLC +tours + +// town : 2014-03-06 Koko Moon, LLC +town + +// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION +toyota + +// toys : 2014-03-06 Pioneer Orchard, LLC +toys + +// trade : 2014-01-23 Elite Registry Limited +trade + +// trading : 2014-12-11 IG Group Holdings PLC +trading + +// training : 2013-11-07 Wild Willow, LLC +training + +// travelers : 2015-03-26 Travelers TLD, LLC +travelers + +// travelersinsurance : 2015-03-26 Travelers TLD, LLC +travelersinsurance + +// trust : 2014-10-16 +trust + +// trv : 2015-03-26 Travelers TLD, LLC +trv + +// tui : 2014-07-03 TUI AG +tui + +// tunes : 2015-02-26 Amazon EU S.à r.l. +tunes + +// tushu : 2014-12-18 Amazon EU S.à r.l. +tushu + +// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED +tvs + +// ubs : 2014-12-11 UBS AG +ubs + +// university : 2014-03-06 Little Station, LLC +university + +// uno : 2013-09-11 Dot Latin LLC +uno + +// uol : 2014-05-01 UBN INTERNET LTDA. +uol + +// vacations : 2013-12-05 Atomic Tigers, LLC +vacations + +// vana : 2014-12-11 Lifestyle Domain Holdings, Inc. +vana + +// vegas : 2014-01-16 Dot Vegas, Inc. +vegas + +// ventures : 2013-08-27 Binky Lake, LLC +ventures + +// versicherung : 2014-03-20 dotversicherung-registry GmbH +versicherung + +// vet : 2014-03-06 +vet + +// viajes : 2013-10-17 Black Madison, LLC +viajes + +// video : 2014-10-16 +video + +// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. +viking + +// villas : 2013-12-05 New Sky, LLC +villas + +// vip : 2015-01-22 Minds + Machines Group Limited +vip + +// virgin : 2014-09-25 Virgin Enterprises Limited +virgin + +// vision : 2013-12-05 Koko Station, LLC +vision + +// vista : 2014-09-18 Vistaprint Limited +vista + +// vistaprint : 2014-09-18 Vistaprint Limited +vistaprint + +// viva : 2014-11-07 Saudi Telecom Company +viva + +// vlaanderen : 2014-02-06 DNS.be vzw +vlaanderen + +// vodka : 2013-12-19 Top Level Domain Holdings Limited +vodka + +// vote : 2013-11-21 Monolith Registry LLC +vote + +// voting : 2013-11-13 Valuetainment Corp. +voting + +// voto : 2013-11-21 Monolith Registry LLC +voto + +// voyage : 2013-08-27 Ruby House, LLC +voyage + +// vuelos : 2015-03-05 Travel Reservations SRL +vuelos + +// wales : 2014-05-08 Nominet UK +wales + +// walter : 2014-11-13 Sandvik AB +walter + +// wang : 2013-10-24 Zodiac Leo Limited +wang + +// wanggou : 2014-12-18 Amazon EU S.à r.l. +wanggou + +// watch : 2013-11-14 Sand Shadow, LLC +watch + +// watches : 2014-12-22 Richemont DNS Inc. +watches + +// weather : 2015-01-08 The Weather Channel, LLC +weather + +// weatherchannel : 2015-03-12 The Weather Channel, LLC +weatherchannel + +// webcam : 2014-01-23 dot Webcam Limited +webcam + +// website : 2014-04-03 DotWebsite Inc. +website + +// wed : 2013-10-01 Atgron, Inc. +wed + +// wedding : 2014-04-24 Top Level Domain Holdings Limited +wedding + +// weibo : 2015-03-05 Sina Corporation +weibo + +// weir : 2015-01-29 Weir Group IP Limited +weir + +// whoswho : 2014-02-20 Who's Who Registry +whoswho + +// wien : 2013-10-28 punkt.wien GmbH +wien + +// wiki : 2013-11-07 Top Level Design, LLC +wiki + +// williamhill : 2014-03-13 William Hill Organization Limited +williamhill + +// win : 2014-11-20 First Registry Limited +win + +// windows : 2014-12-18 Microsoft Corporation +windows + +// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC +wme + +// work : 2013-12-19 Top Level Domain Holdings Limited +work + +// works : 2013-11-14 Little Dynamite, LLC +works + +// world : 2014-06-12 Bitter Fields, LLC +world + +// wtc : 2013-12-19 World Trade Centers Association, Inc. +wtc + +// wtf : 2014-03-06 Hidden Way, LLC +wtf + +// xbox : 2014-12-18 Microsoft Corporation +xbox + +// xerox : 2014-10-24 Xerox DNHC LLC +xerox + +// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +xihuan + +// xin : 2014-12-11 Elegant Leader Limited +xin + +// xn--11b4c3d : 2015-01-15 VeriSign Sarl +कॉम + +// xn--1ck2e1b : 2015-02-26 Amazon EU S.à r.l. +セール + +// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. +佛山 + +// xn--30rr7y : 2014-06-12 Excellent First Limited +慈善 + +// xn--3bst00m : 2013-09-13 Eagle Horizon Limited +集团 + +// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED +在线 + +// xn--3pxu8k : 2015-01-15 VeriSign Sarl +点看 + +// xn--42c2d9a : 2015-01-15 VeriSign Sarl +คอม + +// xn--45q11c : 2013-11-21 Zodiac Scorpio Limited +八卦 + +// xn--4gbrim : 2013-10-04 Suhub Electronic Establishment +موقع + +// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center +公益 + +// xn--55qx5d : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) +公司 + +// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited +网站 + +// xn--6frz82g : 2013-09-23 Afilias Limited +移动 + +// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited +我爱你 + +// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +москва + +// xn--80asehdb : 2013-07-14 CORE Association +онлайн + +// xn--80aswg : 2013-07-14 CORE Association +сайт + +// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited +联通 + +// xn--9dbq2a : 2015-01-15 VeriSign Sarl +קום + +// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED +时尚 + +// xn--9krt00a : 2015-03-12 Sina Corporation +微博 + +// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited +淡马锡 + +// xn--bck1b9a5dre4c : 2015-02-26 Amazon EU S.à r.l. +ファッション + +// xn--c1avg : 2013-11-14 Public Interest Registry +орг + +// xn--c2br7g : 2015-01-15 VeriSign Sarl +नेट + +// xn--cck2b3b : 2015-02-26 Amazon EU S.à r.l. +ストア + +// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD +삼성 + +// xn--czr694b : 2014-01-16 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY.HONGKONG LIMITED +商标 + +// xn--czrs0t : 2013-12-19 Wild Island, LLC +商店 + +// xn--czru2d : 2013-11-21 Zodiac Capricorn Limited +商城 + +// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet” +дети + +// xn--eckvdtc9d : 2014-12-18 Amazon EU S.à r.l. +ポイント + +// xn--efvy88h : 2014-08-22 Xinhua News Agency Guangdong Branch 新华通讯社广东分社 +新闻 + +// xn--estv75g : 2015-02-19 Industrial and Commercial Bank of China Limited +工行 + +// xn--fct429k : 2015-04-09 Amazon EU S.à r.l. +家電 + +// xn--fhbei : 2015-01-15 VeriSign Sarl +كوم + +// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED +中文网 + +// xn--fiq64b : 2013-10-14 CITIC Group Corporation +中信 + +// xn--fjq720a : 2014-05-22 Will Bloom, LLC +娱乐 + +// xn--flw351e : 2014-07-31 Charleston Road Registry Inc. +谷歌 + +// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited +购物 + +// xn--gckr3f0f : 2015-02-26 Amazon EU S.à r.l. +クラウド + +// xn--hxt814e : 2014-05-15 Zodiac Libra Limited +网店 + +// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry +संगठन + +// xn--imr513n : 2014-12-11 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY. HONGKONG LIMITED +餐厅 + +// xn--io0a7i : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) +网络 + +// xn--j1aef : 2015-01-15 VeriSign Sarl +ком + +// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation +诺基亚 + +// xn--jvr189m : 2015-02-26 Amazon EU S.à r.l. +食品 + +// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. +飞利浦 + +// xn--kpu716f : 2014-12-22 Richemont DNS Inc. +手表 + +// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd +手机 + +// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company +ارامكو + +// xn--mgbab2bd : 2013-10-31 CORE Association +بازار + +// xn--mgbb9fbpob : 2014-12-18 GreenTech Consultancy Company W.L.L. +موبايلي + +// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +همراه + +// xn--mk1bu44c : 2015-01-15 VeriSign Sarl +닷컴 + +// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. +政府 + +// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd. +شبكة + +// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House +بيتك + +// xn--nqv7f : 2013-11-14 Public Interest Registry +机构 + +// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry +组织机构 + +// xn--nyqy26a : 2014-11-07 Stable Tone Limited +健康 + +// xn--p1acf : 2013-12-12 Rusnames Limited +рус + +// xn--pbt977c : 2014-12-22 Richemont DNS Inc. +珠宝 + +// xn--pssy2u : 2015-01-15 VeriSign Sarl +大拿 + +// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. +みんな + +// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc. +グーグル + +// xn--rhqv96g : 2013-09-11 Stable Tone Limited +世界 + +// xn--rovu88b : 2015-02-26 Amazon EU S.à r.l. +書籍 + +// xn--ses554g : 2014-01-16 +网址 + +// xn--t60b56a : 2015-01-15 VeriSign Sarl +닷넷 + +// xn--tckwe : 2015-01-15 VeriSign Sarl +コム + +// xn--unup4y : 2013-07-14 Spring Fields, LLC +游戏 + +// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberater + +// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberatung + +// xn--vhquv : 2013-08-27 Dash McCook, LLC +企业 + +// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd. +信息 + +// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited +嘉里大酒店 + +// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd. +广东 + +// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center +政务 + +// xyz : 2013-12-05 XYZ.COM LLC +xyz + +// yachts : 2014-01-09 DERYachts, LLC +yachts + +// yahoo : 2015-04-02 Yahoo! Domain Services Inc. +yahoo + +// yamaxun : 2014-12-18 Amazon EU S.à r.l. +yamaxun + +// yandex : 2014-04-10 YANDEX, LLC +yandex + +// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +yodobashi + +// yoga : 2014-05-29 Top Level Domain Holdings Limited +yoga + +// yokohama : 2013-12-12 GMO Registry, Inc. +yokohama + +// you : 2015-04-09 Amazon EU S.à r.l. +you + +// youtube : 2014-05-01 Charleston Road Registry Inc. +youtube + +// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +yun + +// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) +zara + +// zero : 2014-12-18 Amazon EU S.à r.l. +zero + +// zip : 2014-05-08 Charleston Road Registry Inc. +zip + +// zone : 2013-11-14 Outer Falls, LLC +zone + +// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) +zuerich + + +// ===END ICANN DOMAINS=== +// ===BEGIN PRIVATE DOMAINS=== +// (Note: these are in alphabetical order by company name) + +// Amazon CloudFront : https://aws.amazon.com/cloudfront/ +// Submitted by Donavan Miller 2013-03-22 +cloudfront.net + +// Amazon Elastic Compute Cloud: https://aws.amazon.com/ec2/ +// Submitted by Osman Surkatty 2014-12-16 +ap-northeast-1.compute.amazonaws.com +ap-southeast-1.compute.amazonaws.com +ap-southeast-2.compute.amazonaws.com +cn-north-1.compute.amazonaws.cn +compute.amazonaws.cn +compute.amazonaws.com +compute-1.amazonaws.com +eu-west-1.compute.amazonaws.com +eu-central-1.compute.amazonaws.com +sa-east-1.compute.amazonaws.com +us-east-1.amazonaws.com +us-gov-west-1.compute.amazonaws.com +us-west-1.compute.amazonaws.com +us-west-2.compute.amazonaws.com +z-1.compute-1.amazonaws.com +z-2.compute-1.amazonaws.com + +// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/ +// Submitted by Adam Stein 2013-04-02 +elasticbeanstalk.com + +// Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/ +// Submitted by Scott Vidmar 2013-03-27 +elb.amazonaws.com + +// Amazon S3 : https://aws.amazon.com/s3/ +// Submitted by Courtney Eckhardt 2013-03-22 +s3.amazonaws.com +s3-us-west-2.amazonaws.com +s3-us-west-1.amazonaws.com +s3-eu-west-1.amazonaws.com +s3-ap-southeast-1.amazonaws.com +s3-ap-southeast-2.amazonaws.com +s3-ap-northeast-1.amazonaws.com +s3-sa-east-1.amazonaws.com +s3-us-gov-west-1.amazonaws.com +s3-fips-us-gov-west-1.amazonaws.com +s3-website-us-east-1.amazonaws.com +s3-website-us-west-2.amazonaws.com +s3-website-us-west-1.amazonaws.com +s3-website-eu-west-1.amazonaws.com +s3-website-ap-southeast-1.amazonaws.com +s3-website-ap-southeast-2.amazonaws.com +s3-website-ap-northeast-1.amazonaws.com +s3-website-sa-east-1.amazonaws.com +s3-website-us-gov-west-1.amazonaws.com + +// BetaInABox +// Submitted by adrian@betainabox.com 2012-09-13 +betainabox.com + +// CentralNic : http://www.centralnic.com/names/domains +// Submitted by registry 2012-09-27 +ae.org +ar.com +br.com +cn.com +com.de +com.se +de.com +eu.com +gb.com +gb.net +hu.com +hu.net +jp.net +jpn.com +kr.com +mex.com +no.com +qc.com +ru.com +sa.com +se.com +se.net +uk.com +uk.net +us.com +uy.com +za.bz +za.com + +// Africa.com Web Solutions Ltd : https://registry.africa.com +// Submitted by Gavin Brown 2014-02-04 +africa.com + +// iDOT Services Limited : http://www.domain.gr.com +// Submitted by Gavin Brown 2014-02-04 +gr.com + +// Radix FZC : http://domains.in.net +// Submitted by Gavin Brown 2014-02-04 +in.net + +// US REGISTRY LLC : http://us.org +// Submitted by Gavin Brown 2014-02-04 +us.org + +// co.com Registry, LLC : https://registry.co.com +// Submitted by Gavin Brown 2014-02-04 +co.com + +// c.la : http://www.c.la/ +c.la + +// cloudControl : https://www.cloudcontrol.com/ +// Submitted by Tobias Wilken 2013-07-23 +cloudcontrolled.com +cloudcontrolapp.com + +// co.ca : http://registry.co.ca/ +co.ca + +// CoDNS B.V. +co.nl +co.no + +// Commerce Guys, SAS +// Submitted by Damien Tournoud 2015-01-22 +*.platform.sh + +// Cupcake : https://cupcake.io/ +// Submitted by Jonathan Rudenberg 2013-10-08 +cupcake.is + +// DreamHost : http://www.dreamhost.com/ +// Submitted by Andrew Farmer 2012-10-02 +dreamhosters.com + +// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ +dyndns-at-home.com +dyndns-at-work.com +dyndns-blog.com +dyndns-free.com +dyndns-home.com +dyndns-ip.com +dyndns-mail.com +dyndns-office.com +dyndns-pics.com +dyndns-remote.com +dyndns-server.com +dyndns-web.com +dyndns-wiki.com +dyndns-work.com +dyndns.biz +dyndns.info +dyndns.org +dyndns.tv +at-band-camp.net +ath.cx +barrel-of-knowledge.info +barrell-of-knowledge.info +better-than.tv +blogdns.com +blogdns.net +blogdns.org +blogsite.org +boldlygoingnowhere.org +broke-it.net +buyshouses.net +cechire.com +dnsalias.com +dnsalias.net +dnsalias.org +dnsdojo.com +dnsdojo.net +dnsdojo.org +does-it.net +doesntexist.com +doesntexist.org +dontexist.com +dontexist.net +dontexist.org +doomdns.com +doomdns.org +dvrdns.org +dyn-o-saur.com +dynalias.com +dynalias.net +dynalias.org +dynathome.net +dyndns.ws +endofinternet.net +endofinternet.org +endoftheinternet.org +est-a-la-maison.com +est-a-la-masion.com +est-le-patron.com +est-mon-blogueur.com +for-better.biz +for-more.biz +for-our.info +for-some.biz +for-the.biz +forgot.her.name +forgot.his.name +from-ak.com +from-al.com +from-ar.com +from-az.net +from-ca.com +from-co.net +from-ct.com +from-dc.com +from-de.com +from-fl.com +from-ga.com +from-hi.com +from-ia.com +from-id.com +from-il.com +from-in.com +from-ks.com +from-ky.com +from-la.net +from-ma.com +from-md.com +from-me.org +from-mi.com +from-mn.com +from-mo.com +from-ms.com +from-mt.com +from-nc.com +from-nd.com +from-ne.com +from-nh.com +from-nj.com +from-nm.com +from-nv.com +from-ny.net +from-oh.com +from-ok.com +from-or.com +from-pa.com +from-pr.com +from-ri.com +from-sc.com +from-sd.com +from-tn.com +from-tx.com +from-ut.com +from-va.com +from-vt.com +from-wa.com +from-wi.com +from-wv.com +from-wy.com +ftpaccess.cc +fuettertdasnetz.de +game-host.org +game-server.cc +getmyip.com +gets-it.net +go.dyndns.org +gotdns.com +gotdns.org +groks-the.info +groks-this.info +ham-radio-op.net +here-for-more.info +hobby-site.com +hobby-site.org +home.dyndns.org +homedns.org +homeftp.net +homeftp.org +homeip.net +homelinux.com +homelinux.net +homelinux.org +homeunix.com +homeunix.net +homeunix.org +iamallama.com +in-the-band.net +is-a-anarchist.com +is-a-blogger.com +is-a-bookkeeper.com +is-a-bruinsfan.org +is-a-bulls-fan.com +is-a-candidate.org +is-a-caterer.com +is-a-celticsfan.org +is-a-chef.com +is-a-chef.net +is-a-chef.org +is-a-conservative.com +is-a-cpa.com +is-a-cubicle-slave.com +is-a-democrat.com +is-a-designer.com +is-a-doctor.com +is-a-financialadvisor.com +is-a-geek.com +is-a-geek.net +is-a-geek.org +is-a-green.com +is-a-guru.com +is-a-hard-worker.com +is-a-hunter.com +is-a-knight.org +is-a-landscaper.com +is-a-lawyer.com +is-a-liberal.com +is-a-libertarian.com +is-a-linux-user.org +is-a-llama.com +is-a-musician.com +is-a-nascarfan.com +is-a-nurse.com +is-a-painter.com +is-a-patsfan.org +is-a-personaltrainer.com +is-a-photographer.com +is-a-player.com +is-a-republican.com +is-a-rockstar.com +is-a-socialist.com +is-a-soxfan.org +is-a-student.com +is-a-teacher.com +is-a-techie.com +is-a-therapist.com +is-an-accountant.com +is-an-actor.com +is-an-actress.com +is-an-anarchist.com +is-an-artist.com +is-an-engineer.com +is-an-entertainer.com +is-by.us +is-certified.com +is-found.org +is-gone.com +is-into-anime.com +is-into-cars.com +is-into-cartoons.com +is-into-games.com +is-leet.com +is-lost.org +is-not-certified.com +is-saved.org +is-slick.com +is-uberleet.com +is-very-bad.org +is-very-evil.org +is-very-good.org +is-very-nice.org +is-very-sweet.org +is-with-theband.com +isa-geek.com +isa-geek.net +isa-geek.org +isa-hockeynut.com +issmarterthanyou.com +isteingeek.de +istmein.de +kicks-ass.net +kicks-ass.org +knowsitall.info +land-4-sale.us +lebtimnetz.de +leitungsen.de +likes-pie.com +likescandy.com +merseine.nu +mine.nu +misconfused.org +mypets.ws +myphotos.cc +neat-url.com +office-on-the.net +on-the-web.tv +podzone.net +podzone.org +readmyblog.org +saves-the-whales.com +scrapper-site.net +scrapping.cc +selfip.biz +selfip.com +selfip.info +selfip.net +selfip.org +sells-for-less.com +sells-for-u.com +sells-it.net +sellsyourhome.org +servebbs.com +servebbs.net +servebbs.org +serveftp.net +serveftp.org +servegame.org +shacknet.nu +simple-url.com +space-to-rent.com +stuff-4-sale.org +stuff-4-sale.us +teaches-yoga.com +thruhere.net +traeumtgerade.de +webhop.biz +webhop.info +webhop.net +webhop.org +worse-than.tv +writesthisblog.com + +// EU.org https://eu.org/ +// Submitted by Pierre Beyssac 2015-04-17 + +eu.org +al.eu.org +asso.eu.org +at.eu.org +au.eu.org +be.eu.org +bg.eu.org +ca.eu.org +cd.eu.org +ch.eu.org +cn.eu.org +cy.eu.org +cz.eu.org +de.eu.org +dk.eu.org +edu.eu.org +ee.eu.org +es.eu.org +fi.eu.org +fr.eu.org +gr.eu.org +hr.eu.org +hu.eu.org +ie.eu.org +il.eu.org +in.eu.org +int.eu.org +is.eu.org +it.eu.org +jp.eu.org +kr.eu.org +lt.eu.org +lu.eu.org +lv.eu.org +mc.eu.org +me.eu.org +mk.eu.org +mt.eu.org +my.eu.org +net.eu.org +ng.eu.org +nl.eu.org +no.eu.org +nz.eu.org +paris.eu.org +pl.eu.org +pt.eu.org +q-a.eu.org +ro.eu.org +ru.eu.org +se.eu.org +si.eu.org +sk.eu.org +tr.eu.org +uk.eu.org +us.eu.org + +// Fastly Inc. http://www.fastly.com/ +// Submitted by Vladimir Vuksan 2013-05-31 +a.ssl.fastly.net +b.ssl.fastly.net +global.ssl.fastly.net +a.prod.fastly.net +global.prod.fastly.net + +// Firebase, Inc. +// Submitted by Chris Raynor 2014-01-21 +firebaseapp.com + +// Flynn : https://flynn.io +// Submitted by Jonathan Rudenberg 2014-07-12 +flynnhub.com + +// GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains +// Submitted by David Illsley 2014-08-28 +service.gov.uk + +// GitHub, Inc. +// Submitted by Ben Toews 2014-02-06 +github.io +githubusercontent.com + +// GlobeHosting, Inc. +// Submitted by Zoltan Egresi 2013-07-12 +ro.com + +// Google, Inc. +// Submitted by Eduardo Vela 2014-12-19 +appspot.com +blogspot.ae +blogspot.be +blogspot.bj +blogspot.ca +blogspot.cf +blogspot.ch +blogspot.co.at +blogspot.co.il +blogspot.co.nz +blogspot.co.uk +blogspot.com +blogspot.com.ar +blogspot.com.au +blogspot.com.br +blogspot.com.es +blogspot.com.tr +blogspot.cv +blogspot.cz +blogspot.de +blogspot.dk +blogspot.fi +blogspot.fr +blogspot.gr +blogspot.hk +blogspot.hu +blogspot.ie +blogspot.in +blogspot.it +blogspot.jp +blogspot.kr +blogspot.mr +blogspot.mx +blogspot.nl +blogspot.no +blogspot.pt +blogspot.re +blogspot.ro +blogspot.ru +blogspot.se +blogspot.sg +blogspot.sk +blogspot.td +blogspot.tw +codespot.com +googleapis.com +googlecode.com +pagespeedmobilizer.com +withgoogle.com + +// Heroku : https://www.heroku.com/ +// Submitted by Tom Maher 2013-05-02 +herokuapp.com +herokussl.com + +// iki.fi +// Submitted by Hannu Aronsson 2009-11-05 +iki.fi + +// info.at : http://www.info.at/ +biz.at +info.at + +// Michau Enterprises Limited : http://www.co.pl/ +co.pl + +// Microsoft : http://microsoft.com +// Submitted by Barry Dorrans 2014-01-24 +azurewebsites.net +azure-mobile.net +cloudapp.net + +// Neustar Inc. +// Submitted by Trung Tran 2015-04-23 +4u.com + +// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ +// Submitted by Jeff Wheelhouse 2014-02-02 +nfshost.com + +// NYC.mn : http://www.information.nyc.mn +// Submitted by Matthew Brown 2013-03-11 +nyc.mn + +// One Fold Media : http://www.onefoldmedia.com/ +// Submitted by Eddie Jones 2014-06-10 +nid.io + +// Opera Software, A.S.A. +// Submitted by Yngve Pettersen 2009-11-26 +operaunite.com + +// OutSystems +// Submitted by Duarte Santos 2014-03-11 +outsystemscloud.com + +// .pl domains (grandfathered) +art.pl +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// priv.at : http://www.nic.priv.at/ +// Submitted by registry 2008-06-09 +priv.at + +// Red Hat, Inc. OpenShift : https://openshift.redhat.com/ +// Submitted by Tim Kramer 2012-10-24 +rhcloud.com + +// SinaAppEngine : http://sae.sina.com.cn/ +// Submitted by SinaAppEngine 2015-02-02 +sinaapp.com +vipsinaapp.com +1kapp.com + +// TASK geographical domains (www.task.gda.pl/uslugi/dns) +gda.pl +gdansk.pl +gdynia.pl +med.pl +sopot.pl + +// UDR Limited : http://www.udr.hk.com +// Submitted by registry 2014-11-07 +hk.com +hk.org +ltd.hk +inc.hk + +// Yola : https://www.yola.com/ +// Submitted by Stefano Rivera 2014-07-09 +yolasite.com + +// ZaNiC : http://www.za.net/ +// Submitted by registry 2009-10-03 +za.net +za.org + +// ===END PRIVATE DOMAINS=== diff --git a/mobile/ios/SharedTests/ArrayExtensionTests.swift b/mobile/ios/SharedTests/ArrayExtensionTests.swift new file mode 100644 index 0000000000..7ff01378d8 --- /dev/null +++ b/mobile/ios/SharedTests/ArrayExtensionTests.swift @@ -0,0 +1,62 @@ +/* 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/. */ + +import Foundation +import Shared +import XCTest + +class ArrayExtensionTests: XCTestCase { + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testUnique() { + let a = [1, 2, 3, 4, 5, 6, 1, 2] + let result = a.unique { return $0 } + XCTAssertEqual(result, [1, 2, 3, 4, 5, 6]) + + let b = [1, 2, 3] + let resultB = b.unique { return $0 } + XCTAssertEqual(resultB, [1, 2, 3]) + } + + func testUnion() { + let a = [1, 2, 3, 4, 5, 6] + let b = [7, 8, 9, 10] + XCTAssertEqual(a.union(b) { return $0 }, + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + + let c = [1, 2, 3, 4, 5, 6] + let d = [4, 5, 6, 7, 8, 9, 10] + XCTAssertEqual(c.union(d) { return $0 }, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + + let e = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + let f = [4, 5, 6, 7, 8, 9, 10] + XCTAssertEqual(e.union(f) { return $0 }, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + + let g = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + let h = [Int]() + XCTAssertEqual(g.union(h) { return $0 }, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + + let i = [Int]() + let j = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + XCTAssertEqual(i.union(j) { return $0 }, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + } + + func testSameElements() { + let k = [1, 2, 3, 4, 5] + let l = [1, 2, 3, 4, 5] + let m = [2, 4, 6, 8, 10] + let n: [Int]? + n = k + XCTAssertTrue(k.sameElements(l)) + XCTAssertFalse(l.sameElements(m)) + XCTAssertTrue((n?.sameElements(k))!) + } + +} diff --git a/mobile/ios/SharedTests/AsyncReducerTests.swift b/mobile/ios/SharedTests/AsyncReducerTests.swift new file mode 100644 index 0000000000..94cb1c728b --- /dev/null +++ b/mobile/ios/SharedTests/AsyncReducerTests.swift @@ -0,0 +1,167 @@ +/* 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/. */ + +import XCTest +import Deferred +@testable import Shared + +private let timeoutPeriod: TimeInterval = 600 + +class AsyncReducerTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testSimpleBehaviour() { + let expectation = self.expectation(description: #function) + happyCase(expectation, combine: simpleAdder) + } + + func testWaitingFillerBehaviour() { + let expectation = self.expectation(description: #function) + happyCase(expectation, combine: waitingFillingAdder) + } + + func testWaitingFillerAppendingBehaviour() { + let expectation = self.expectation(description: #function) + appendingCase(expectation, combine: waitingFillingAdder) + } + + func testFailingCombine() { + let expectation = self.expectation(description: #function) + let combine = { (a: Int, b: Int) -> Deferred> in + if a >= 6 { + return deferMaybe(TestError()) + } + return deferMaybe(a + b) + } + let reducer = AsyncReducer(initialValue: 0, combine: combine) + reducer.terminal.upon { res in + XCTAssert(res.isFailure) + expectation.fulfill() + } + + self.append(reducer, items: 1, 2, 3, 4, 5) + waitForExpectations(timeout: timeoutPeriod, handler: nil) + } + + func testFailingAppend() { + let expectation = self.expectation(description: #function) + + let reducer = AsyncReducer(initialValue: 0, combine: simpleAdder) + reducer.terminal.upon { res in + XCTAssert(res.isSuccess) + XCTAssertEqual(res.successValue!, 15) + } + + self.append(reducer, items: 1, 2, 3, 4, 5) + + delay(0.1) { + do { + let _ = try reducer.append(6, 7, 8) + XCTFail("Can't append to a reducer that's already finished") + } catch let error { + XCTAssert(true, "Properly received error on finished reducer \(error)") + } + expectation.fulfill() + } + + waitForExpectations(timeout: timeoutPeriod, handler: nil) + } + + func testAccumulation() { + var addDuring: [String] = ["bar", "baz"] + var reducer: AsyncReducer<[String: Bool], String>! + + func combine(_ t: [String: Bool], u: String) -> Deferred> { + var out = t + out[u] = true + + // Pretend that some new work arrived while we were handling this. + if let nextUp = addDuring.popLast() { + let _ = try! reducer.append(nextUp) + } + + return deferMaybe(out) + } + + // Start with 'foo'. + reducer = AsyncReducer(initialValue: deferMaybe([:]), combine: combine) + let _ = try! reducer.append("foo") + + // Wait for the result. We should have handled all three by the time this returns. + let result = reducer.terminal.value + XCTAssertTrue(result.isSuccess) + XCTAssertEqual(["foo": true, "bar": true, "baz": true], result.successValue!) + } +} + +extension AsyncReducerTests { + func happyCase(_ expectation: XCTestExpectation, combine: @escaping (Int, Int) -> Deferred>) { + let reducer = AsyncReducer(initialValue: 0, combine: combine) + reducer.terminal.upon { res in + XCTAssert(res.isSuccess) + XCTAssertEqual(res.successValue!, 15) + expectation.fulfill() + } + + self.append(reducer, items: 1, 2, 3, 4, 5) + waitForExpectations(timeout: timeoutPeriod, handler: nil) + } + + func appendingCase(_ expectation: XCTestExpectation, combine: @escaping (Int, Int) -> Deferred>) { + let reducer = AsyncReducer(initialValue: 0, combine: combine) + reducer.terminal.upon { res in + XCTAssert(res.isSuccess) + XCTAssertEqual(res.successValue!, 15) + expectation.fulfill() + } + + self.append(reducer, items: 1, 2) + + delay(0.1) { + self.append(reducer, items: 3, 4, 5) + } + waitForExpectations(timeout: timeoutPeriod, handler: nil) + } + + func append(_ reducer: AsyncReducer, items: Int...) { + do { + let _ = try reducer.append(items) + } catch let error { + XCTFail("Append failed with \(error)") + } + } +} + +class TestError: MaybeErrorType { + var description = "Error" +} + +private let serialQueue = DispatchQueue(label: "com.mozilla.test.serial", attributes: []) +private let concurrentQueue = DispatchQueue(label: "com.mozilla.test.concurrent", attributes: DispatchQueue.Attributes.concurrent) + +func delay(_ delay: Double, closure:@escaping () -> Void) { + concurrentQueue.asyncAfter( + deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure) +} + +private func simpleAdder(_ a: Int, b: Int) -> Deferred> { + return deferMaybe(a + b) +} + +private func waitingFillingAdder(_ a: Int, b: Int) -> Deferred> { + let deferred = Deferred>() + delay(0.1) { + deferred.fill(Maybe(success: a + b)) + } + return deferred +} + diff --git a/mobile/ios/SharedTests/AuthenticationKeychainInfoTests.swift b/mobile/ios/SharedTests/AuthenticationKeychainInfoTests.swift new file mode 100644 index 0000000000..176dd613a7 --- /dev/null +++ b/mobile/ios/SharedTests/AuthenticationKeychainInfoTests.swift @@ -0,0 +1,45 @@ +/* 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/. */ + +import Foundation +import Shared +import XCTest +import SwiftKeychainWrapper + +class AuthenticationKeychainInfoTests: XCTestCase { + + func testEncodingAndDecoding() { + let passcode = "1234" + let authInfo = AuthenticationKeychainInfo(passcode: passcode) + authInfo.updateRequiredPasscodeInterval(.fiveMinutes) + authInfo.recordValidation() + authInfo.recordFailedAttempt() // failed attempt should be 1 + authInfo.lockOutUser() //lock out a user so a lockoutInterval is set. + authInfo.useTouchID = true + + let savedInterval = authInfo.lockOutInterval + let savedValidation = authInfo.lastPasscodeValidationInterval + + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authInfo) //Save to disk + let decodedAuthInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo()! //Fetch from disk + + XCTAssertEqual(savedInterval, decodedAuthInfo.lockOutInterval) + XCTAssertEqual(passcode, decodedAuthInfo.passcode) + XCTAssertEqual(1, decodedAuthInfo.failedAttempts, "We performed a recordFailedAttempt. This should be 1.") + XCTAssertTrue(decodedAuthInfo.useTouchID) + XCTAssertEqual(savedValidation, decodedAuthInfo.lastPasscodeValidationInterval) + XCTAssertEqual(PasscodeInterval.fiveMinutes, decodedAuthInfo.requiredPasscodeInterval) + } + + func testNilIntervalsArentZero() { + let passcode = "1234" + let authInfo = AuthenticationKeychainInfo(passcode: passcode) + + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(authInfo) //Save to disk + let decodedAuthInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo()! //Fetch from disk + + XCTAssertNil(decodedAuthInfo.lockOutInterval, "The lockoutInterval was never used. It should be nil") + } + +} diff --git a/mobile/ios/SharedTests/DeferredTests.swift b/mobile/ios/SharedTests/DeferredTests.swift new file mode 100644 index 0000000000..402735697c --- /dev/null +++ b/mobile/ios/SharedTests/DeferredTests.swift @@ -0,0 +1,127 @@ +/* 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/. */ + +@testable import Shared +import Deferred +import XCTest + +// Trivial test for using Deferred. + +class DeferredTests: XCTestCase { + func testDeferred() { + let d = Deferred() + XCTAssertNil(d.peek(), "Value not yet filled.") + + let expectation = self.expectation(description: "Waiting on value.") + d.upon({ x in + expectation.fulfill() + }) + + d.fill(5) + waitForExpectations(timeout: 10) { (error) in + XCTAssertNil(error, "\(error.debugDescription)") + } + + XCTAssertEqual(5, d.peek()!, "Value is filled.") + } + + func testMultipleUponBlocks() { + let e1 = self.expectation(description: "First.") + let e2 = self.expectation(description: "Second.") + let d = Deferred() + d.upon { x in + XCTAssertEqual(x, 5) + e1.fulfill() + } + d.upon { x in + XCTAssertEqual(x, 5) + e2.fulfill() + } + d.fill(5) + waitForExpectations(timeout: 10, handler: nil) + } + + func testOperators() { + let e1 = self.expectation(description: "First.") + let e2 = self.expectation(description: "Second.") + + let f1: () -> Deferred> = { + return deferMaybe(5) + } + + let f2: (_ x: Int) -> Deferred> = { + if $0 == 5 { + e1.fulfill() + } + return deferMaybe("Hello!") + } + + // Type signatures: + let combined: () -> Deferred> = { f1() >>== f2 } + let result: Deferred> = combined() + + result.upon { + XCTAssertEqual("Hello!", $0.successValue!) + e2.fulfill() + } + + waitForExpectations(timeout: 10, handler: nil) + } + + func testPassAccumulate() { + let leak = self.expectation(description: "deinit") + + class TestClass { + let end: XCTestExpectation + init(e: XCTestExpectation) { + end = e + accumulate([self.aSimpleFunction]).upon { _ in + + } + } + + func aSimpleFunction() -> Success { + return succeed() + } + deinit { + end.fulfill() + } + } + + var myclass: TestClass? = TestClass(e: leak) + myclass = nil + waitForExpectations(timeout: 3, handler: nil) + } + + + func testFailAccumulate() { + let leak = self.expectation(description: "deinit") + + class TestError: MaybeErrorType { + var description = "Error" + } + + class TestClass { + let end: XCTestExpectation + init(e: XCTestExpectation) { + end = e + accumulate([self.aSimpleFunction]).upon { _ in + + } + } + + func aSimpleFunction() -> Success { + return Deferred(value: Maybe(failure: TestError())) + } + deinit { + end.fulfill() + } + } + + var myclass: TestClass? = TestClass(e: leak) + myclass = nil + waitForExpectations(timeout: 3, handler: nil) + } + +} diff --git a/mobile/ios/SharedTests/FeatureSwitchTests.swift b/mobile/ios/SharedTests/FeatureSwitchTests.swift new file mode 100644 index 0000000000..d2cef34493 --- /dev/null +++ b/mobile/ios/SharedTests/FeatureSwitchTests.swift @@ -0,0 +1,147 @@ +/* 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/. */ + +@testable import Shared +import XCTest + +class FeatureSwitchTests: XCTestCase { + let buildChannel = AppConstants.BuildChannel + + func testPersistent() { + let featureSwitch = FeatureSwitch(named: "test-persistent-over-restarts", allowPercentage: 50, buildChannel: buildChannel) + let prefs = MockProfilePrefs() + var membership = featureSwitch.isMember(prefs) + var changed = 0 + for _ in 0..<100 { + if featureSwitch.isMember(prefs) != membership { + membership = !membership + changed += 1 + } + } + + XCTAssertEqual(changed, 0, "Users should get and keep the feature over restarts") + } + + func testConsistentWhenChangingPercentage() { + let featureID = "test-persistent-over-releases" + let prefs = MockProfilePrefs() + let guardFeatureSwitch = FeatureSwitch(named: featureID, allowPercentage: 50, buildChannel: buildChannel) + while guardFeatureSwitch.alwaysMembership(prefs) { + guardFeatureSwitch.resetMembership(prefs) + } + var membership = false + var changed = 0 + for percent in 0..<100 { + let featureSwitch = FeatureSwitch(named: featureID, allowPercentage: percent, buildChannel: buildChannel) + if featureSwitch.isMember(prefs) != membership { + membership = !membership + changed += 1 + } + } + + XCTAssertEqual(changed, 1, "Users should get and keep the feature if the feature is becoming successful") + } + + func testReallyConsistentWhenChangingPercentage() { + for _ in 0..<1000 { + testConsistentWhenChangingPercentage() + } + } + + func testUserEnabled() { + let prefs = MockProfilePrefs() + let featureSwitch = FeatureSwitch(named: "test-user-enabled", allowPercentage: 0, buildChannel: buildChannel) + XCTAssertFalse(featureSwitch.isMember(prefs), "The feature should be disabled") + featureSwitch.setMembership(true, for: prefs) // enable the feature + XCTAssertTrue(featureSwitch.isMember(prefs), "The feature should be enabled") + featureSwitch.setMembership(false, for: prefs) // disable the feature + XCTAssertFalse(featureSwitch.isMember(prefs), "The feature should be disabled again") + } + + func testForceDisabled() { + let prefs = MockProfilePrefs() + let featureSwitch = FeatureSwitch(named: "test-user-disabled", allowPercentage: 100, buildChannel: buildChannel) + XCTAssertTrue(featureSwitch.isMember(prefs), "The feature should be enabled") + featureSwitch.setMembership(false, for: prefs) // disable the feature + XCTAssertFalse(featureSwitch.isMember(prefs), "The feature should be disabled again") + } +} + +extension FeatureSwitchTests { + func test0Percent() { + let featureSwitch = FeatureSwitch(named: "test-never", allowPercentage: 0, buildChannel: buildChannel) + testExactly(featureSwitch, expected: 0) + testApprox(featureSwitch, expected: 0) + } + + func test100Percent() { + let featureSwitch = FeatureSwitch(named: "test-always", allowPercentage: 100, buildChannel: buildChannel) + testExactly(featureSwitch, expected: 100) + testApprox(featureSwitch, expected: 100) + } + + func test50Percent() { + let featureSwitch = FeatureSwitch(named: "test-half-the-population", allowPercentage: 50, buildChannel: buildChannel) + testApprox(featureSwitch, expected: 50) + } + + func test30Percent() { + let featureSwitch = FeatureSwitch(named: "test-30%-population", allowPercentage: 30, buildChannel: buildChannel) + testApprox(featureSwitch, expected: 30) + } + + func testPerformance() { + let featureSwitch = FeatureSwitch(named: "test-30%-population", allowPercentage: 30, buildChannel: buildChannel) + let prefs = MockProfilePrefs() + measure { + for _ in 0..<1000 { + _ = featureSwitch.isMember(prefs) + } + } + } + + func testAppConstantsWin() { + // simulate in release channel, but switched off in AppConstants. + let featureFlaggedOff = FeatureSwitch(named: "test-release-flagged-off", false, allowPercentage: 100, buildChannel: buildChannel) + testExactly(featureFlaggedOff, expected: 0) + + // simulate in non-release channel, but switched on in AppConstants. + let buildChannelAndFlaggedOn = FeatureSwitch(named: "test-flagged-on", true, allowPercentage: 0) + testExactly(buildChannelAndFlaggedOn, expected: 100) + + // simulate in non-release channel, but switched off in AppConstants. + let buildChannelAndFlaggedOff = FeatureSwitch(named: "test-flagged-off", false, allowPercentage: 100) + testExactly(buildChannelAndFlaggedOff, expected: 0) + } +} + +private extension FeatureSwitchTests { + func sampleN(_ featureSwitch: FeatureSwitch, testCount: Int = 1000) -> Int { + var count = 0 + for _ in 0.. + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/SharedTests/NSMutableAttributedStringExtensionsTests.swift b/mobile/ios/SharedTests/NSMutableAttributedStringExtensionsTests.swift new file mode 100644 index 0000000000..dad2b16f6d --- /dev/null +++ b/mobile/ios/SharedTests/NSMutableAttributedStringExtensionsTests.swift @@ -0,0 +1,49 @@ +/* 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/. */ + +import UIKit +import XCTest +@testable import Shared + +class NSMutableAttributedStringExtensionsTests: XCTestCase { + fileprivate func checkCharacterAtPosition(_ position: Int, isColored color: UIColor, inString string: NSAttributedString) -> Bool { + let attributes = string.attributes(at: position, effectiveRange: nil) + if let foregroundColor = attributes[NSForegroundColorAttributeName] as? UIColor { + if foregroundColor == color { + return true + } + } + return false + } + + func testColorsSubstring() { + let substring = "bc" + let example = NSMutableAttributedString(string: "abcd") + example.colorSubstring(substring, withColor: UIColor.red) + + XCTAssertFalse(checkCharacterAtPosition(0, isColored: UIColor.red, inString: example)) + for position in 1..<3 { + XCTAssertTrue(checkCharacterAtPosition(position, isColored: UIColor.red, inString: example)) + } + XCTAssertFalse(checkCharacterAtPosition(3, isColored: UIColor.red, inString: example)) + } + + func testDoesNothingWithEmptySubstring() { + let substring = "" + let example = NSMutableAttributedString(string: "abcd") + example.colorSubstring(substring, withColor: UIColor.red) + for position in 0.. 0 else { + print("\(url) doesn't match as a URL") + continue + } + + let modified = url.absoluteDisplayExternalString + XCTAssertNotEqual(original, modified) + + let newMatches = detector.matches(in: modified, options: [], range: NSMakeRange(0, modified.count)) + + XCTAssertEqual(0, newMatches.count, "\(modified) is not a valid URL") + } + + } + +} diff --git a/mobile/ios/SharedTests/ResultTests.swift b/mobile/ios/SharedTests/ResultTests.swift new file mode 100644 index 0000000000..508d1164e1 --- /dev/null +++ b/mobile/ios/SharedTests/ResultTests.swift @@ -0,0 +1,18 @@ +/* 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/. */ + +import Shared +import XCTest + +// Trivial test for using Result. +class ResultTests: XCTestCase { + func testResult() { + let r = Maybe(success: 5) + if let i = r.successValue { + XCTAssertEqual(5, i) + } else { + XCTFail("Expected success.") + } + } +} diff --git a/mobile/ios/SharedTests/RollingFileLoggerTests.swift b/mobile/ios/SharedTests/RollingFileLoggerTests.swift new file mode 100644 index 0000000000..cec27a414b --- /dev/null +++ b/mobile/ios/SharedTests/RollingFileLoggerTests.swift @@ -0,0 +1,119 @@ +/* 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/. */ + +import Foundation +import XCTest +import XCGLogger +@testable import Shared + +class RollingFileLoggerTests: XCTestCase { + var logger: RollingFileLogger! + var logDir: String = "" + var sizeLimit: Int = 5000 + + fileprivate lazy var formatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "yyyyMMdd'T'HHmmssZ" + return formatter + }() + + override func setUp() { + super.setUp() + logDir = (NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!) + "/Logs" + do { + try FileManager.default.createDirectory(atPath: logDir, withIntermediateDirectories: false, attributes: nil) + } catch _ { + } + logger = RollingFileLogger(filenameRoot: "test", logDirectoryPath: logDir, sizeLimit: Int64(sizeLimit)) + } + + func testNewLogCreatesLogFileWithTimestamp() { + let date = Date() + let expected = "test.\(formatter.string(from: date)).log" + let expectedPath = "\(logDir)/\(expected)" + logger.newLogWithDate(date) + XCTAssertTrue(FileManager.default.fileExists(atPath: expectedPath), "Log file should exist") + + let testMessage = "Logging some text" + logger.info(testMessage) + let logData = try? Data(contentsOf: URL(fileURLWithPath: expectedPath)) + XCTAssertNotNil(logData, "Log data should not be nil") + let logString = NSString(data: logData!, encoding: String.Encoding.utf8.rawValue) + XCTAssertTrue(logString!.contains(testMessage), "Log should contain our test message that we wrote") + } + + func testNewLogDeletesPreviousLogIfItsTooLarge() { + let manager = FileManager.default + let dirURL = URL(fileURLWithPath: logDir) + let prefix = "test" + let expectedPath = createNewLogFileWithSize(sizeLimit + 1) + + let directorySize = try! manager.getAllocatedSizeOfDirectoryAtURL(dirURL, forFilesPrefixedWith: prefix) + + // Pre-condition: Folder needs to be larger than the size limit + XCTAssertGreaterThan(directorySize, Int64(sizeLimit), "Log folder should be larger than size limit") + + let exceedsSmaller = try! manager.allocatedSizeOfDirectoryAtURL(dirURL, forFilesPrefixedWith: prefix, isLargerThanBytes: directorySize - 1) + let doesNotExceedLarger = try! manager.allocatedSizeOfDirectoryAtURL(dirURL, forFilesPrefixedWith: prefix, isLargerThanBytes: Int64(sizeLimit + 2)) + XCTAssertTrue(exceedsSmaller) + XCTAssertTrue(doesNotExceedLarger) + + let newDate = Date().addingTimeInterval(60*60) // Create a log file using a date an hour ahead + let newExpected = "\(prefix).\(formatter.string(from: newDate)).log" + let newExpectedPath = "\(logDir)/\(newExpected)" + logger.newLogWithDate(newDate) + + XCTAssertTrue(manager.fileExists(atPath: newExpectedPath), "New log file should exist") + XCTAssertTrue(manager.fileExists(atPath: expectedPath), "Old log file exists until pruned") + logger.deleteOldLogsDownToSizeLimit() + XCTAssertFalse(manager.fileExists(atPath: expectedPath), "Old log file should NOT exist") + } + + func testNewLogDeletesOldestLogFileToMakeRoomForNewFile() { + let manager = FileManager.default + let dirURL = URL(fileURLWithPath: logDir) + let prefix = "test" + + // Create 5 log files with spread out over 5 hours and reorder paths so oldest is first + let logFilePaths = [0, 1, 2, 3, 4].map { self.createNewLogFileWithSize(200, withDate: Date().addingTimeInterval(60 * 60 * $0)) } + .sorted { $0 < $1 } + + let directorySize = try! manager.getAllocatedSizeOfDirectoryAtURL(dirURL, forFilesPrefixedWith: prefix) + + // Pre-condition: Folder needs to be larger than the size limit + XCTAssertGreaterThan(directorySize, Int64(sizeLimit), "Log folder should be larger than size limit") + + let newDate = Date().addingTimeInterval(60*60*5) // Create a log file using a date an hour ahead + let newExpected = "\(prefix).\(formatter.string(from: newDate)).log" + let newExpectedPath = "\(logDir)/\(newExpected)" + logger.newLogWithDate(newDate) + + XCTAssertTrue(manager.fileExists(atPath: newExpectedPath), "New log file should exist") + XCTAssertTrue(manager.fileExists(atPath: logFilePaths.first!), "Old log file exists until pruned") + logger.deleteOldLogsDownToSizeLimit() + XCTAssertFalse(manager.fileExists(atPath: logFilePaths.first!), "Oldest log file should NOT exist") + } + + /** + Create a log file using the test logger and returns the path to that log file + + - parameter size: Size to make the log file + + - returns: Path to log file + */ + fileprivate func createNewLogFileWithSize(_ size: Int, withDate date: Date = Date()) -> String { + let expected = "test.\(formatter.string(from: date)).log" + let expectedPath = "\(logDir)/\(expected)" + logger.newLogWithDate(date) + XCTAssertTrue(FileManager.default.fileExists(atPath: expectedPath), "Log file should exist") + + let logFileHandle = FileHandle(forWritingAtPath: expectedPath) + XCTAssertNotNil(logFileHandle, "File should exist") + let garbageBytes = malloc(size) + let blankData = Data(bytes: garbageBytes!, count: size) + logFileHandle!.write(blankData) + logFileHandle!.closeFile() + return expectedPath + } +} diff --git a/mobile/ios/SharedTests/SupportUtilsTests.swift b/mobile/ios/SharedTests/SupportUtilsTests.swift new file mode 100644 index 0000000000..c56472acd6 --- /dev/null +++ b/mobile/ios/SharedTests/SupportUtilsTests.swift @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +import Shared +import XCTest + +class SupportUtilsTests: XCTestCase { + func testURLForTopic() { + let appVersion = AppInfo.appVersion + let languageIdentifier = Locale.preferredLanguages.first! + XCTAssertEqual(SupportUtils.URLForTopic("Bacon")?.absoluteString, "https://support.mozilla.org/1/mobile/\(appVersion)/iOS/\(languageIdentifier)/Bacon") + XCTAssertEqual(SupportUtils.URLForTopic("Cheese & Crackers")?.absoluteString, "https://support.mozilla.org/1/mobile/\(appVersion)/iOS/\(languageIdentifier)/Cheese%20&%20Crackers") + XCTAssertEqual(SupportUtils.URLForTopic("Möbelträgerfüße")?.absoluteString, "https://support.mozilla.org/1/mobile/\(appVersion)/iOS/\(languageIdentifier)/M%C3%B6beltr%C3%A4gerf%C3%BC%C3%9Fe") + } +} diff --git a/mobile/ios/SharedTests/UtilsTests.swift b/mobile/ios/SharedTests/UtilsTests.swift new file mode 100644 index 0000000000..054e2cb630 --- /dev/null +++ b/mobile/ios/SharedTests/UtilsTests.swift @@ -0,0 +1,108 @@ +/* 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/. */ + +import Foundation +import Shared +import XCTest + +/** + * Test for our own utils. + */ +class UtilsTests: XCTestCase { + func testMapUtils() { + let m: [String: Int] = ["foo": 123, "bar": 456] + let f: (Int) -> Int? = { v in + return (v > 200) ? 999 : nil + } + + let o = mapValues(m, f: f) + XCTAssertEqual(2, o.count) + XCTAssertTrue(o["foo"]! == nil) + XCTAssertTrue(o["bar"]! == 999) + + let filtered = optFilter(o) + XCTAssertEqual(1, filtered.count) + XCTAssertTrue(filtered["bar"] == 999) + } + + func testOptFilter() { + let a: [Int?] = [nil, 1, nil, 2, 3, 4] + let b = optFilter(a) + XCTAssertEqual(4, b.count) + XCTAssertEqual([1, 2, 3, 4], b) + } + + func testOptArrayEqual() { + let x: [String] = ["a", "b", "c"] + let y: [String]? = ["a", "b", "c"] + let z: [String]? = nil + + XCTAssertTrue(optArrayEqual(x, rhs: y)) + XCTAssertTrue(optArrayEqual(x, rhs: x)) + XCTAssertTrue(optArrayEqual(y, rhs: y)) + XCTAssertTrue(optArrayEqual(z, rhs: z)) + XCTAssertFalse(optArrayEqual(x, rhs: z)) + XCTAssertFalse(optArrayEqual(z, rhs: y)) + } + + func testChunk() { + let examples: [([Int], Int, [[Int]])] = [ + ([], 2, []), + ([1, 2], 0, [[1], [2]]), + ([1, 2], 1, [[1], [2]]), + ([1, 2, 3], 2, [[1, 2], [3]]), + ([1, 2], 3, [[1, 2]]), + ([1, 2, 3], 1, [[1], [2], [3]]), + ] + for (arr, by, expected) in examples { + // Turn the ArraySlices back into Arrays for comparison. + let actual = chunk(arr as [Int], by: by).map { Array($0) } + XCTAssertEqual(expected as NSArray, actual as NSArray) //wtf. why is XCTAssert being so weeird + } + } + + func testChunkCollection() { + let examples: [([Int], Int, [[Int]])] = [ + ([], 2, []), + ([1, 2], 0, [[1], [2]]), + ([1, 2], 1, [[1], [2]]), + ([1, 2, 3], 2, [[1, 2], [3]]), + ([1, 2], 3, [[1, 2]]), + ([1, 2, 3], 1, [[1], [2], [3]]), + ] + for (arr, by, expected) in examples { + let actual = chunkCollection(arr, by: by) { xs in [xs] } + XCTAssertEqual(expected as NSArray, actual as NSArray) + } + } + + func testParseTimestamps() { + let millis = "1492316843992" // Firefox for iOS produced millisecond timestamps. Oops. + let decimal = "1492316843.99" + let truncated = "1492316843" + let huge = "1844674407370955161512" + + XCTAssertNil(decimalSecondsStringToTimestamp("")) + XCTAssertNil(decimalSecondsStringToTimestamp(huge)) + XCTAssertNil(decimalSecondsStringToTimestamp("foo")) + + XCTAssertNil(someKindOfTimestampStringToTimestamp("")) + XCTAssertNil(someKindOfTimestampStringToTimestamp(huge)) + XCTAssertNil(someKindOfTimestampStringToTimestamp("foo")) + + let ts1: Timestamp = 1492316843990 + XCTAssertEqual(decimalSecondsStringToTimestamp(decimal) ?? 0, ts1) + XCTAssertEqual(someKindOfTimestampStringToTimestamp(decimal) ?? 0, ts1) + + let ts2: Timestamp = 1492316843000 + XCTAssertEqual(decimalSecondsStringToTimestamp(truncated) ?? 0, ts2) + XCTAssertEqual(someKindOfTimestampStringToTimestamp(truncated) ?? 0, ts2) + + let ts3: Timestamp = 1492316843992000 + XCTAssertEqual(decimalSecondsStringToTimestamp(millis) ?? 0, ts3) // Oops. + + let ts4: Timestamp = 1492316843992 + XCTAssertEqual(someKindOfTimestampStringToTimestamp(millis) ?? 0, ts4) + } +} diff --git a/mobile/ios/Storage/Bookmarks/Bookmarks.swift b/mobile/ios/Storage/Bookmarks/Bookmarks.swift new file mode 100644 index 0000000000..5bc6f45047 --- /dev/null +++ b/mobile/ios/Storage/Bookmarks/Bookmarks.swift @@ -0,0 +1,529 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared +import Deferred +import SwiftyJSON + +private let log = Logger.syncLogger + +public protocol SearchableBookmarks: class { + func bookmarksByURL(_ url: URL) -> Deferred>> +} + +public protocol SyncableBookmarks: class, ResettableSyncStorage, AccountRemovalDelegate { + // TODO + func isUnchanged() -> Deferred> + func getLocalBookmarksModifications(limit: Int) -> Deferred> + func getLocalDeletions() -> Deferred> + func treesForEdges() -> Deferred> + func treeForMirror() -> Deferred> + func applyLocalOverrideCompletionOp(_ op: LocalOverrideCompletionOp, itemSources: ItemSources) -> Success + func applyBufferUpdatedCompletionOp(_ op: BufferUpdatedCompletionOp) -> Success +} + +public let NotificationBookmarkBufferValidated = Notification.Name("NotificationBookmarkBufferValidated") + +public protocol BookmarkBufferStorage: class { + func isEmpty() -> Deferred> + func applyRecords(_ records: [BookmarkMirrorItem]) -> Success + func doneApplyingRecordsAfterDownload() -> Success + + func validate() -> Success + func getBufferedDeletions() -> Deferred> + func applyBufferCompletionOp(_ op: BufferCompletionOp, itemSources: ItemSources) -> Success + + // Only use for diagnostics. + func synchronousBufferCount() -> Int? + func getUpstreamRecordCount() -> Deferred +} + +public protocol MirrorItemSource: class { + func getMirrorItemWithGUID(_ guid: GUID) -> Deferred> + func getMirrorItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID + func prefetchMirrorItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID +} + +public protocol BufferItemSource: class { + func getBufferItemWithGUID(_ guid: GUID) -> Deferred> + func getBufferItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID + func getBufferChildrenGUIDsForParent(_ guid: GUID) -> Deferred> + func prefetchBufferItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID +} + +public protocol LocalItemSource: class { + func getLocalItemWithGUID(_ guid: GUID) -> Deferred> + func getLocalItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID + func prefetchLocalItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID +} + +open class ItemSources { + open let local: LocalItemSource + open let mirror: MirrorItemSource + open let buffer: BufferItemSource + + public init(local: LocalItemSource, mirror: MirrorItemSource, buffer: BufferItemSource) { + self.local = local + self.mirror = mirror + self.buffer = buffer + } + + open func prefetchWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return self.local.prefetchLocalItemsWithGUIDs(guids) + >>> { self.mirror.prefetchMirrorItemsWithGUIDs(guids) } + >>> { self.buffer.prefetchBufferItemsWithGUIDs(guids) } + } +} + +public struct BookmarkRoots { + // These match Places on desktop. + public static let RootGUID = "root________" + public static let MobileFolderGUID = "mobile______" + public static let MenuFolderGUID = "menu________" + public static let ToolbarFolderGUID = "toolbar_____" + public static let UnfiledFolderGUID = "unfiled_____" + + public static let FakeDesktopFolderGUID = "desktop_____" // Pseudo. Never mentioned in a real record. + + // This is the order we use. + public static let RootChildren: [GUID] = [ + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + BookmarkRoots.MobileFolderGUID, + ] + + public static let DesktopRoots: [GUID] = [ + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + ] + + public static let Real = Set([ + BookmarkRoots.RootGUID, + BookmarkRoots.MobileFolderGUID, + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + ]) + + public static let All = Set([ + BookmarkRoots.RootGUID, + BookmarkRoots.MobileFolderGUID, + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + BookmarkRoots.FakeDesktopFolderGUID, + ]) + + /** + * Sync records are a horrible mess of Places-native GUIDs and Sync-native IDs. + * For example: + * {"id":"places", + * "type":"folder", + * "title":"", + * "description":null, + * "children":["menu________","toolbar_____", + * "tags________","unfiled_____", + * "jKnyPDrBQSDg","T6XK5oJMU8ih"], + * "parentid":"2hYxKgBwvkEH"}" + * + * We thus normalize on the extended Places IDs (with underscores) for + * local storage, and translate to the Sync IDs when creating an outbound + * record. + * We translate the record's ID and also its parent. Evidence suggests that + * we don't need to translate children IDs. + * + * TODO: We don't create outbound records yet, so that's why there's no + * translation in that direction yet! + */ + public static func translateIncomingRootGUID(_ guid: GUID) -> GUID { + return [ + "places": RootGUID, + "root": RootGUID, + "mobile": MobileFolderGUID, + "menu": MenuFolderGUID, + "toolbar": ToolbarFolderGUID, + "unfiled": UnfiledFolderGUID + ][guid] ?? guid + } + + public static func translateOutgoingRootGUID(_ guid: GUID) -> GUID { + return [ + RootGUID: "places", + MobileFolderGUID: "mobile", + MenuFolderGUID: "menu", + ToolbarFolderGUID: "toolbar", + UnfiledFolderGUID: "unfiled" + ][guid] ?? guid + } + + /* + public static let TagsFolderGUID = "tags________" + public static let PinnedFolderGUID = "pinned______" + */ + + static let RootID = 0 + static let MobileID = 1 + static let MenuID = 2 + static let ToolbarID = 3 + static let UnfiledID = 4 +} + +/** + * This partly matches Places's nsINavBookmarksService, just for sanity. + * + * It is further extended to support the types that exist in Sync, so we can use + * this to store mirrored rows. + * + * These are only used at the DB layer. + */ +public enum BookmarkNodeType: Int { + case bookmark = 1 + case folder = 2 + case separator = 3 + case dynamicContainer = 4 + + case livemark = 5 + case query = 6 + + // No microsummary: those turn into bookmarks. +} + +public func == (lhs: BookmarkMirrorItem, rhs: BookmarkMirrorItem) -> Bool { + if lhs.type != rhs.type || + lhs.guid != rhs.guid || + lhs.dateAdded != rhs.dateAdded || + lhs.serverModified != rhs.serverModified || + lhs.isDeleted != rhs.isDeleted || + lhs.hasDupe != rhs.hasDupe || + lhs.pos != rhs.pos || + lhs.faviconID != rhs.faviconID || + lhs.localModified != rhs.localModified || + lhs.parentID != rhs.parentID || + lhs.parentName != rhs.parentName || + lhs.feedURI != rhs.feedURI || + lhs.siteURI != rhs.siteURI || + lhs.title != rhs.title || + lhs.description != rhs.description || + lhs.bookmarkURI != rhs.bookmarkURI || + lhs.tags != rhs.tags || + lhs.keyword != rhs.keyword || + lhs.folderName != rhs.folderName || + lhs.queryID != rhs.queryID { + return false + } + + if let lhsChildren = lhs.children, let rhsChildren = rhs.children { + return lhsChildren == rhsChildren + } + return lhs.children == nil && rhs.children == nil +} + +public struct BookmarkMirrorItem: Equatable { + public let guid: GUID + public let type: BookmarkNodeType + public let dateAdded: Timestamp? + public var serverModified: Timestamp + public let isDeleted: Bool + public let hasDupe: Bool + public let parentID: GUID? + public let parentName: String? + + // Livemarks. + public let feedURI: String? + public let siteURI: String? + + // Separators. + let pos: Int? + + // Folders, livemarks, bookmarks and queries. + public let title: String? + let description: String? + + // Bookmarks and queries. + let bookmarkURI: String? + let tags: String? + let keyword: String? + + // Queries. + let folderName: String? + let queryID: String? + + // Folders. + public let children: [GUID]? + + // Internal stuff. + let faviconID: Int? + public let localModified: Timestamp? + let syncStatus: SyncStatus? + + public func copyWithDateAdded(_ dateAdded: Timestamp) -> BookmarkMirrorItem { + return BookmarkMirrorItem( + guid: self.guid, + type: self.type, + dateAdded: dateAdded, + serverModified: self.serverModified, + isDeleted: self.isDeleted, + hasDupe: self.hasDupe, + parentID: self.parentID, + parentName: self.parentName, + feedURI: self.feedURI, + siteURI: self.siteURI, + pos: self.pos, + title: self.title, + description: self.description, + bookmarkURI: self.bookmarkURI, + tags: self.tags, + keyword: self.keyword, + folderName: self.folderName, + queryID: self.queryID, + children: self.children, + faviconID: self.faviconID, + localModified: self.localModified, + syncStatus: self.syncStatus) + } + + public func copyWithParentID(_ parentID: GUID, parentName: String?) -> BookmarkMirrorItem { + return BookmarkMirrorItem( + guid: self.guid, + type: self.type, + dateAdded: self.dateAdded, + serverModified: self.serverModified, + isDeleted: self.isDeleted, + hasDupe: self.hasDupe, + parentID: parentID, + parentName: parentName, + feedURI: self.feedURI, + siteURI: self.siteURI, + pos: self.pos, + title: self.title, + description: self.description, + bookmarkURI: self.bookmarkURI, + tags: self.tags, + keyword: self.keyword, + folderName: self.folderName, + queryID: self.queryID, + children: self.children, + faviconID: self.faviconID, + localModified: self.localModified, + syncStatus: self.syncStatus) + } + + // Ignores internal metadata and GUID; a pure value comparison. + // Does compare child GUIDs! + public func sameAs(_ rhs: BookmarkMirrorItem) -> Bool { + if self.type != rhs.type || + self.dateAdded != rhs.dateAdded || + self.isDeleted != rhs.isDeleted || + self.pos != rhs.pos || + self.parentID != rhs.parentID || + self.parentName != rhs.parentName || + self.feedURI != rhs.feedURI || + self.siteURI != rhs.siteURI || + self.title != rhs.title || + (self.description ?? "") != (rhs.description ?? "") || + self.bookmarkURI != rhs.bookmarkURI || + self.tags != rhs.tags || + self.keyword != rhs.keyword || + self.folderName != rhs.folderName || + self.queryID != rhs.queryID { + return false + } + + if let lhsChildren = self.children, let rhsChildren = rhs.children { + return lhsChildren == rhsChildren + } + return self.children == nil && rhs.children == nil + } + + public func asJSON() -> JSON { + return self.asJSONWithChildren(self.children) + } + + public func asJSONWithChildren(_ children: [GUID]?) -> JSON { + var out: [String: Any] = [:] + + out["id"] = BookmarkRoots.translateOutgoingRootGUID(self.guid) + + func take(_ key: String, _ val: String?) { + guard let val = val else { + return + } + out[key] = val + } + + if self.isDeleted { + out["deleted"] = true + return JSON(out) + } + + out["dateAdded"] = self.dateAdded + out["hasDupe"] = self.hasDupe + + // TODO: this should never be nil! + if let parentID = self.parentID { + out["parentid"] = BookmarkRoots.translateOutgoingRootGUID(parentID) + take("parentName", titleForSpecialGUID(parentID) ?? self.parentName ?? "") + } + + func takeBookmarkFields() { + take("title", self.title) + take("bmkUri", self.bookmarkURI) + take("description", self.description) + if let tags = self.tags { + let tagsJSON = JSON(parseJSON: tags) + if let tagsArray = tagsJSON.array, tagsArray.every({ $0.type == SwiftyJSON.Type.string }) { + out["tags"] = tagsArray + } else { + out["tags"] = [] + } + } else { + out["tags"] = [] + } + take("keyword", self.keyword) + } + + func takeFolderFields() { + take("title", titleForSpecialGUID(self.guid) ?? self.title) + take("description", self.description) + if let children = children { + if BookmarkRoots.RootGUID == self.guid { + // Only the root contains roots, and so only its children + // need to be translated. + out["children"] = children.map(BookmarkRoots.translateOutgoingRootGUID) + } else { + out["children"] = children + } + } + } + + switch self.type { + + case .query: + out["type"] = "query" + take("folderName", self.folderName) + take("queryId", self.queryID) + takeBookmarkFields() + + case .bookmark: + out["type"] = "bookmark" + takeBookmarkFields() + + case .livemark: + out["type"] = "livemark" + take("siteUri", self.siteURI) + take("feedUri", self.feedURI) + takeFolderFields() + + case .folder: + out["type"] = "folder" + takeFolderFields() + + case .separator: + out["type"] = "separator" + if let pos = self.pos { + out["pos"] = pos + } + + case .dynamicContainer: + // Sigh. + preconditionFailure("DynamicContainer not supported.") + } + + return JSON(out) + } + + // The places root is a folder but has no parentName. + public static func folder(_ guid: GUID, dateAdded: Timestamp?, modified: Timestamp, hasDupe: Bool, parentID: GUID, parentName: String?, title: String, description: String?, children: [GUID]) -> BookmarkMirrorItem { + let id = BookmarkRoots.translateIncomingRootGUID(guid) + let parent = BookmarkRoots.translateIncomingRootGUID(parentID) + + return BookmarkMirrorItem(guid: id, type: .folder, dateAdded: dateAdded, serverModified: modified, + isDeleted: false, hasDupe: hasDupe, parentID: parent, parentName: parentName, + feedURI: nil, siteURI: nil, + pos: nil, + title: title, description: description, + bookmarkURI: nil, tags: nil, keyword: nil, + folderName: nil, queryID: nil, + children: children, + faviconID: nil, localModified: nil, syncStatus: nil) + } + + public static func livemark(_ guid: GUID, dateAdded: Timestamp?, modified: Timestamp, hasDupe: Bool, parentID: GUID, parentName: String?, title: String?, description: String?, feedURI: String, siteURI: String) -> BookmarkMirrorItem { + let id = BookmarkRoots.translateIncomingRootGUID(guid) + let parent = BookmarkRoots.translateIncomingRootGUID(parentID) + + return BookmarkMirrorItem(guid: id, type: .livemark, dateAdded: dateAdded, serverModified: modified, + isDeleted: false, hasDupe: hasDupe, parentID: parent, parentName: parentName, + feedURI: feedURI, siteURI: siteURI, + pos: nil, + title: title, description: description, + bookmarkURI: nil, tags: nil, keyword: nil, + folderName: nil, queryID: nil, + children: nil, + faviconID: nil, localModified: nil, syncStatus: nil) + } + + public static func separator(_ guid: GUID, dateAdded: Timestamp?, modified: Timestamp, hasDupe: Bool, parentID: GUID, parentName: String?, pos: Int) -> BookmarkMirrorItem { + let id = BookmarkRoots.translateIncomingRootGUID(guid) + let parent = BookmarkRoots.translateIncomingRootGUID(parentID) + + return BookmarkMirrorItem(guid: id, type: .separator, dateAdded: dateAdded, serverModified: modified, + isDeleted: false, hasDupe: hasDupe, parentID: parent, parentName: parentName, + feedURI: nil, siteURI: nil, + pos: pos, + title: nil, description: nil, + bookmarkURI: nil, tags: nil, keyword: nil, + folderName: nil, queryID: nil, + children: nil, + faviconID: nil, localModified: nil, syncStatus: nil) + } + + public static func bookmark(_ guid: GUID, dateAdded: Timestamp?, modified: Timestamp, hasDupe: Bool, parentID: GUID, parentName: String?, title: String, description: String?, URI: String, tags: String, keyword: String?) -> BookmarkMirrorItem { + let id = BookmarkRoots.translateIncomingRootGUID(guid) + let parent = BookmarkRoots.translateIncomingRootGUID(parentID) + + return BookmarkMirrorItem(guid: id, type: .bookmark, dateAdded: dateAdded, serverModified: modified, + isDeleted: false, hasDupe: hasDupe, parentID: parent, parentName: parentName, + feedURI: nil, siteURI: nil, + pos: nil, + title: title, description: description, + bookmarkURI: URI, tags: tags, keyword: keyword, + folderName: nil, queryID: nil, + children: nil, + faviconID: nil, localModified: nil, syncStatus: nil) + } + + public static func query(_ guid: GUID, dateAdded: Timestamp?, modified: Timestamp, hasDupe: Bool, parentID: GUID, parentName: String?, title: String, description: String?, URI: String, tags: String, keyword: String?, folderName: String?, queryID: String?) -> BookmarkMirrorItem { + let id = BookmarkRoots.translateIncomingRootGUID(guid) + let parent = BookmarkRoots.translateIncomingRootGUID(parentID) + + return BookmarkMirrorItem(guid: id, type: .query, dateAdded: dateAdded, serverModified: modified, + isDeleted: false, hasDupe: hasDupe, parentID: parent, parentName: parentName, + feedURI: nil, siteURI: nil, + pos: nil, + title: title, description: description, + bookmarkURI: URI, tags: tags, keyword: keyword, + folderName: folderName, queryID: queryID, + children: nil, + faviconID: nil, localModified: nil, syncStatus: nil) + } + + public static func deleted(_ type: BookmarkNodeType, guid: GUID, modified: Timestamp) -> BookmarkMirrorItem { + let id = BookmarkRoots.translateIncomingRootGUID(guid) + + return BookmarkMirrorItem(guid: id, type: type, dateAdded: nil, serverModified: modified, + isDeleted: true, hasDupe: false, parentID: nil, parentName: nil, + feedURI: nil, siteURI: nil, + pos: nil, + title: nil, description: nil, + bookmarkURI: nil, tags: nil, keyword: nil, + folderName: nil, queryID: nil, + children: nil, + faviconID: nil, localModified: nil, syncStatus: nil) + } +} diff --git a/mobile/ios/Storage/Bookmarks/BookmarksModel.swift b/mobile/ios/Storage/Bookmarks/BookmarksModel.swift new file mode 100644 index 0000000000..179e230011 --- /dev/null +++ b/mobile/ios/Storage/Bookmarks/BookmarksModel.swift @@ -0,0 +1,417 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared + +private let log = Logger.syncLogger + +/** + * The kinda-immutable base interface for bookmarks and folders. + */ +open class BookmarkNode { + open var id: Int? + open let guid: GUID + open let title: String + open let isEditable: Bool + open var favicon: Favicon? + + init(guid: GUID, title: String, isEditable: Bool=false) { + self.guid = guid + self.title = title + self.isEditable = isEditable + } + + open var canDelete: Bool { + return self.isEditable + } +} + +open class BookmarkSeparator: BookmarkNode { + init(guid: GUID) { + super.init(guid: guid, title: "—") + } +} + +/** + * An immutable item representing a bookmark. + * + * To modify this, issue changes against the backing store and get an updated model. + */ +open class BookmarkItem: BookmarkNode { + open let url: String! + + public init(guid: String, title: String, url: String, isEditable: Bool=false) { + self.url = url + super.init(guid: guid, title: title, isEditable: isEditable) + } +} + +/** + * A folder is an immutable abstraction over a named + * thing that can return its child nodes by index. + */ +open class BookmarkFolder: BookmarkNode { + open var count: Int { return 0 } + open subscript(index: Int) -> BookmarkNode? { return nil } + + open func itemIsEditableAtIndex(_ index: Int) -> Bool { + return self[index]?.canDelete ?? false + } + + override open var canDelete: Bool { + return false + } + + open func removeItemWithGUID(_ guid: GUID) -> BookmarkFolder? { + return nil + } +} + +/** + * A model is a snapshot of the bookmarks store, suitable for backing a table view. + * + * Navigation through the folder hierarchy produces a sequence of models. + * + * Changes to the backing store implicitly invalidates a subset of models. + * + * 'Refresh' means requesting a new model from the store. + */ +open class BookmarksModel: BookmarksModelFactorySource { + fileprivate let factory: BookmarksModelFactory + open let modelFactory: Deferred> + open let current: BookmarkFolder + + public init(modelFactory: BookmarksModelFactory, root: BookmarkFolder) { + self.factory = modelFactory + self.modelFactory = deferMaybe(modelFactory) + self.current = root + } + + /** + * Produce a new model rooted at the appropriate folder. Fails if the folder doesn't exist. + */ + open func selectFolder(_ folder: BookmarkFolder) -> Deferred> { + return self.factory.modelForFolder(folder) + } + + /** + * Produce a new model rooted at the appropriate folder. Fails if the folder doesn't exist. + */ + open func selectFolder(_ guid: String) -> Deferred> { + return self.factory.modelForFolder(guid) + } + + /** + * Produce a new model rooted at the base of the hierarchy. Should never fail. + */ + open func selectRoot() -> Deferred> { + return self.factory.modelForRoot() + } + + /** + * Produce a new model with a memory-backed root with the given GUID removed from the current folder + */ + open func removeGUIDFromCurrent(_ guid: GUID) -> BookmarksModel { + if let removedRoot = self.current.removeItemWithGUID(guid) { + return BookmarksModel(modelFactory: self.factory, root: removedRoot) + } + log.warning("BookmarksModel.removeGUIDFromCurrent did not remove anything. Check to make sure you're not using the abstract BookmarkFolder class.") + return self + } + + /** + * Produce a new model rooted at the same place as this model. Can fail if + * the folder has been deleted from the backing store. + */ + open func reloadData() -> Deferred> { + return self.factory.modelForFolder(current) + } + + open var canDelete: Bool { + return false + } +} + +public protocol BookmarksModelFactorySource { + var modelFactory: Deferred> { get } +} + +public protocol BookmarksModelFactory { + func factoryForIndex(_ index: Int, inFolder folder: BookmarkFolder) -> BookmarksModelFactory + func modelForFolder(_ folder: BookmarkFolder) -> Deferred> + func modelForFolder(_ guid: GUID) -> Deferred> + func modelForFolder(_ guid: GUID, title: String) -> Deferred> + + func modelForRoot() -> Deferred> + + // Whenever async construction is necessary, we fall into a pattern of needing + // a placeholder that behaves correctly for the period between kickoff and set. + var nullModel: BookmarksModel { get } + + func isBookmarked(_ url: String) -> Deferred> + func removeByGUID(_ guid: GUID) -> Success + @discardableResult func removeByURL(_ url: String) -> Success +} + +/* + * A folder that contains an array of children. + */ +open class MemoryBookmarkFolder: BookmarkFolder, Sequence { + let children: [BookmarkNode] + + public init(guid: GUID, title: String, children: [BookmarkNode]) { + self.children = children + super.init(guid: guid, title: title) + } + + public struct BookmarkNodeGenerator: IteratorProtocol { + public typealias Element = BookmarkNode + let children: [BookmarkNode] + var index: Int = 0 + + init(children: [BookmarkNode]) { + self.children = children + } + + public mutating func next() -> BookmarkNode? { + if index < children.count { + defer { index += 1 } + return children[index] + } + return nil + } + } + + override open var favicon: Favicon? { + get { + if let path = Bundle.main.path(forResource: "bookmarkFolder", ofType: "png") { + let url = URL(fileURLWithPath: path) + return Favicon(url: url.absoluteString, date: Date(), type: IconType.local) + } + return nil + } + set { + } + } + + override open var count: Int { + return children.count + } + + override open subscript(index: Int) -> BookmarkNode { + get { + return children[index] + } + } + + override open func itemIsEditableAtIndex(_ index: Int) -> Bool { + return true + } + + override open func removeItemWithGUID(_ guid: GUID) -> BookmarkFolder? { + let without = children.filter { $0.guid != guid } + return MemoryBookmarkFolder(guid: self.guid, title: self.title, children: without) + } + + open func makeIterator() -> BookmarkNodeGenerator { + return BookmarkNodeGenerator(children: self.children) + } + + /** + * Return a new immutable folder that's just like this one, + * but also contains the new items. + */ + func append(_ items: [BookmarkNode]) -> MemoryBookmarkFolder { + if items.isEmpty { + return self + } + return MemoryBookmarkFolder(guid: self.guid, title: self.title, children: self.children + items) + } +} + +open class MemoryBookmarksSink: ShareToDestination { + var queue: [BookmarkNode] = [] + public init() { } + open func shareItem(_ item: ShareItem) -> Success { + let title = item.title == nil ? "Untitled" : item.title! + func exists(_ e: BookmarkNode) -> Bool { + if let bookmark = e as? BookmarkItem { + return bookmark.url == item.url + } + + return false + } + + // Don't create duplicates. + if !queue.contains(where: exists) { + queue.append(BookmarkItem(guid: Bytes.generateGUID(), title: title, url: item.url)) + } + + return succeed() + } +} + +private extension SuggestedSite { + func asBookmark() -> BookmarkNode { + let b = BookmarkItem(guid: self.guid ?? Bytes.generateGUID(), title: self.title, url: self.url) + b.favicon = self.icon + return b + } +} + +open class PrependedBookmarkFolder: BookmarkFolder { + let main: BookmarkFolder + fileprivate let prepend: BookmarkNode + + init(main: BookmarkFolder, prepend: BookmarkNode) { + self.main = main + self.prepend = prepend + super.init(guid: main.guid, title: main.guid) + } + + override open var count: Int { + return self.main.count + 1 + } + + override open subscript(index: Int) -> BookmarkNode? { + if index == 0 { + return self.prepend + } + + return self.main[index - 1] + } + + override open func itemIsEditableAtIndex(_ index: Int) -> Bool { + return index > 0 && self.main.itemIsEditableAtIndex(index - 1) + } + + override open func removeItemWithGUID(_ guid: GUID) -> BookmarkFolder? { + guard let removedFolder = main.removeItemWithGUID(guid) else { + log.warning("Failed to remove child item from prepended folder. Check that main folder overrides removeItemWithGUID.") + return nil + } + return PrependedBookmarkFolder(main: removedFolder, prepend: prepend) + } +} + +open class ConcatenatedBookmarkFolder: BookmarkFolder { + fileprivate let main: BookmarkFolder + fileprivate let append: BookmarkFolder + + init(main: BookmarkFolder, append: BookmarkFolder) { + self.main = main + self.append = append + super.init(guid: main.guid, title: main.title) + } + + var pivot: Int { + return main.count + } + + override open var count: Int { + return main.count + append.count + } + + override open subscript(index: Int) -> BookmarkNode? { + return index < main.count ? main[index] : append[index - main.count] + } + + override open func itemIsEditableAtIndex(_ index: Int) -> Bool { + return index < main.count ? main.itemIsEditableAtIndex(index) : append.itemIsEditableAtIndex(index - main.count) + } + + override open func removeItemWithGUID(_ guid: GUID) -> BookmarkFolder? { + let newMain = main.removeItemWithGUID(guid) ?? main + let newAppend = append.removeItemWithGUID(guid) ?? append + return ConcatenatedBookmarkFolder(main: newMain, append: newAppend) + } +} + +/** + * A trivial offline model factory that represents a simple hierarchy. + */ +open class MockMemoryBookmarksStore: BookmarksModelFactory, ShareToDestination { + let mobile: MemoryBookmarkFolder + let root: MemoryBookmarkFolder + var unsorted: MemoryBookmarkFolder + + let sink: MemoryBookmarksSink + + public init() { + let res = [BookmarkItem]() + + mobile = MemoryBookmarkFolder(guid: BookmarkRoots.MobileFolderGUID, title: "Mobile Bookmarks", children: res) + + unsorted = MemoryBookmarkFolder(guid: BookmarkRoots.UnfiledFolderGUID, title: "Unsorted Bookmarks", children: []) + sink = MemoryBookmarksSink() + + root = MemoryBookmarkFolder(guid: BookmarkRoots.RootGUID, title: "Root", children: [mobile, unsorted]) + } + + public func factoryForIndex(_ index: Int, inFolder folder: BookmarkFolder) -> BookmarksModelFactory { + return self + } + + open func modelForFolder(_ folder: BookmarkFolder) -> Deferred> { + return self.modelForFolder(folder.guid, title: folder.title) + } + + open func modelForFolder(_ guid: GUID) -> Deferred> { + return self.modelForFolder(guid, title: "") + } + + open func modelForFolder(_ guid: GUID, title: String) -> Deferred> { + var m: BookmarkFolder + switch guid { + case BookmarkRoots.MobileFolderGUID: + // Transparently merges in any queued items. + m = self.mobile.append(self.sink.queue) + break + case BookmarkRoots.RootGUID: + m = self.root + break + case BookmarkRoots.UnfiledFolderGUID: + m = self.unsorted + break + default: + return deferMaybe(DatabaseError(description: "No such folder \(guid).")) + } + + return deferMaybe(BookmarksModel(modelFactory: self, root: m)) + } + + open func modelForRoot() -> Deferred> { + return deferMaybe(BookmarksModel(modelFactory: self, root: self.root)) + } + + /** + * This class could return the full data immediately. We don't, because real DB-backed code won't. + */ + open var nullModel: BookmarksModel { + let f = MemoryBookmarkFolder(guid: BookmarkRoots.RootGUID, title: "Root", children: []) + return BookmarksModel(modelFactory: self, root: f) + } + + open func shareItem(_ item: ShareItem) -> Success { + return self.sink.shareItem(item) + } + + open func isBookmarked(_ url: String) -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + open func removeByGUID(_ guid: GUID) -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + open func removeByURL(_ url: String) -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + open func clearBookmarks() -> Success { + return succeed() + } +} diff --git a/mobile/ios/Storage/Bookmarks/CachingItemSource.swift b/mobile/ios/Storage/Bookmarks/CachingItemSource.swift new file mode 100644 index 0000000000..40ec28ccb0 --- /dev/null +++ b/mobile/ios/Storage/Bookmarks/CachingItemSource.swift @@ -0,0 +1,192 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared + +private let log = Logger.syncLogger + +private class CachedSource { + // We track not just mappings between values and non-nil items, but also whether we've tried + // to look up a value at all. This allows us to distinguish between a cache miss and a + // cache hit that didn't find an item in the backing store. + // We expect, given our prefetching, that cache misses will be rare. + fileprivate var cache: [GUID: BookmarkMirrorItem] = [:] + fileprivate var seen: Set = Set() + + subscript(guid: GUID) -> BookmarkMirrorItem? { + get { + return self.cache[guid] + } + + set(value) { + self.cache[guid] = value + } + } + + func lookup(_ guid: GUID) -> Deferred>? { + guard self.seen.contains(guid) else { + log.warning("Cache miss for \(guid).") + return nil + } + + guard let found = self.cache[guid] else { + log.verbose("Cache hit, but no record found for \(guid).") + return deferMaybe(NoSuchRecordError(guid: guid)) + } + + log.verbose("Cache hit for \(guid).") + return deferMaybe(found) + } + + var isEmpty: Bool { + return self.cache.isEmpty + } + + // fill and seen are separate: we won't find every item in the DB. + func fill(_ items: [GUID: BookmarkMirrorItem]) -> Success { + for (x, y) in items { + self.cache[x] = y + } + return succeed() + } + + func markSeen(_ guid: GUID) { + self.seen.insert(guid) + } + + func markSeen(_ guids: T) where T.Iterator.Element == GUID { + self.seen.formUnion(guids) + } + + func takingGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + var out: [GUID: BookmarkMirrorItem] = [:] + guids.forEach { + if let v = self.cache[$0] { + out[$0] = v + } + } + return deferMaybe(out) + } +} + +// Sorry about the boilerplate. +// These are separate protocols so that the method names don't collide when implemented +// by the same class, but that means extracting more base implementation is more trouble than +// it's worth. +open class CachingLocalItemSource: LocalItemSource { + fileprivate let cache: CachedSource + fileprivate let source: LocalItemSource + + public init(source: LocalItemSource) { + self.cache = CachedSource() + self.source = source + } + + open func getLocalItemWithGUID(_ guid: GUID) -> Deferred> { + if let found = self.cache.lookup(guid) { + return found + } + + return self.source.getLocalItemWithGUID(guid) >>== effect { + self.cache.markSeen(guid) + self.cache[guid] = $0 + } + } + + open func getLocalItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.prefetchLocalItemsWithGUIDs(guids) >>> { self.cache.takingGUIDs(guids) } + } + + open func prefetchLocalItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + log.debug("Prefetching \(guids.count) local items: \(guids.prefix(10))….") + if guids.isEmpty { + return succeed() + } + + return self.source.getLocalItemsWithGUIDs(guids) >>== { + self.cache.markSeen(guids) + return self.cache.fill($0) + } + } +} + +open class CachingMirrorItemSource: MirrorItemSource { + fileprivate let cache: CachedSource + fileprivate let source: MirrorItemSource + + public init(source: MirrorItemSource) { + self.cache = CachedSource() + self.source = source + } + + open func getMirrorItemWithGUID(_ guid: GUID) -> Deferred> { + if let found = self.cache.lookup(guid) { + return found + } + + return self.source.getMirrorItemWithGUID(guid) >>== effect { + self.cache.markSeen(guid) + self.cache[guid] = $0 + } + } + + open func getMirrorItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.prefetchMirrorItemsWithGUIDs(guids) >>> { self.cache.takingGUIDs(guids) } + } + + open func prefetchMirrorItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + log.debug("Prefetching \(guids.count) mirror items: \(guids.prefix(10))….") + if guids.isEmpty { + return succeed() + } + + return self.source.getMirrorItemsWithGUIDs(guids) >>== { + self.cache.markSeen(guids) + return self.cache.fill($0) + } + } +} + +open class CachingBufferItemSource: BufferItemSource { + fileprivate let cache: CachedSource + fileprivate let source: BufferItemSource + + public init(source: BufferItemSource) { + self.cache = CachedSource() + self.source = source + } + + open func getBufferItemWithGUID(_ guid: GUID) -> Deferred> { + if let found = self.cache.lookup(guid) { + return found + } + + return self.source.getBufferItemWithGUID(guid) >>== effect { + self.cache.markSeen(guid) + self.cache[guid] = $0 + } + } + + open func getBufferItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.prefetchBufferItemsWithGUIDs(guids) >>> { self.cache.takingGUIDs(guids) } + } + + public func getBufferChildrenGUIDsForParent(_ guid: GUID) -> Deferred> { + return self.source.getBufferChildrenGUIDsForParent(guid) + } + + open func prefetchBufferItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + log.debug("Prefetching \(guids.count) buffer items: \(guids.prefix(10))….") + if guids.isEmpty { + return succeed() + } + + return self.source.getBufferItemsWithGUIDs(guids) >>== { + self.cache.markSeen(guids) + return self.cache.fill($0) + } + } +} diff --git a/mobile/ios/Storage/Bookmarks/Trees.swift b/mobile/ios/Storage/Bookmarks/Trees.swift new file mode 100644 index 0000000000..ac3aad43d3 --- /dev/null +++ b/mobile/ios/Storage/Bookmarks/Trees.swift @@ -0,0 +1,319 @@ +/* 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/. */ + +import Foundation +import Shared + +private let log = Logger.syncLogger + +// MARK: - Defining a tree structure for syncability. +public enum BookmarkTreeNode: Comparable { + indirect case folder(guid: GUID, children: [BookmarkTreeNode]) + case nonFolder(guid: GUID) + case unknown(guid: GUID) + + // Because shared associated values between enum cases aren't possible. + public var recordGUID: GUID { + switch self { + case let .folder(guid, _): + return guid + case let .nonFolder(guid): + return guid + case let .unknown(guid): + return guid + } + } + + public var isRoot: Bool { + return BookmarkRoots.All.contains(self.recordGUID) + } + + public var isUnknown: Bool { + if case .unknown = self { + return true + } + return false + } + + public var children: [BookmarkTreeNode]? { + if case let .folder(_, children) = self { + return children + } + return nil + } + + public func hasChildList(_ nodes: [BookmarkTreeNode]) -> Bool { + if case let .folder(_, ours) = self { + return ours.elementsEqual(nodes, by: { $0.recordGUID == $1.recordGUID }) + } + return false + } + + public func hasSameChildListAs(_ other: BookmarkTreeNode) -> Bool { + if case let .folder(_, ours) = self { + if case let .folder(_, theirs) = other { + return ours.elementsEqual(theirs, by: { $0.recordGUID == $1.recordGUID }) + } + } + return false + } + + // Returns false for unknowns. + public func isSameTypeAs(_ other: BookmarkTreeNode) -> Bool { + switch self { + case .folder: + if case .folder = other { + return true + } + case .nonFolder: + if case .nonFolder = other { + return true + } + default: + return false + } + return false + } +} + +public func == (lhs: BookmarkTreeNode, rhs: BookmarkTreeNode) -> Bool { + switch lhs { + case let .folder(guid, children): + if case let .folder(rguid, rchildren) = rhs { + return guid == rguid && children == rchildren + } + return false + case let .nonFolder(guid): + if case let .nonFolder(rguid) = rhs { + return guid == rguid + } + return false + case let .unknown(guid): + if case let .unknown(rguid) = rhs { + return guid == rguid + } + return false + } +} + +public func < (lhs: BookmarkTreeNode, rhs: BookmarkTreeNode) -> Bool { + return lhs.recordGUID < rhs.recordGUID +} + +typealias StructureRow = (parent: GUID, child: GUID, type: BookmarkNodeType?) + +// This is really a forest, not a tree: it can have multiple 'subtrees' +// and carries a collection of associated values. +public struct BookmarkTree { + // Records with no parents. + public let subtrees: [BookmarkTreeNode] + + // Record GUID -> record. + public let lookup: [GUID: BookmarkTreeNode] + + // Child GUID -> parent GUID. + public let parents: [GUID: GUID] + + // Records that appear in 'lookup' because they're modified, but aren't present + // in 'subtrees' because their parent didn't change. + public let orphans: Set + + // Records that have been deleted. + public let deleted: Set + + // Every record that's changed but not deleted. + public let modified: Set + + // Nodes that are present in this tree but aren't present in the source. + // In practical terms, this will be roots that we pretend exist in + // the mirror for purposes of three-way merging. + public let virtual: Set + + // Accessor for all top-level folders' GUIDs. + public var subtreeGUIDs: Set { + return Set(self.subtrees.map { $0.recordGUID }) + } + + public var isEmpty: Bool { + return self.subtrees.isEmpty && self.deleted.isEmpty + } + + public static func emptyTree() -> BookmarkTree { + return BookmarkTree(subtrees: [], lookup: [:], parents: [:], orphans: Set(), deleted: Set(), modified: Set(), virtual: Set()) + } + + public static func emptyMirrorTree() -> BookmarkTree { + return mappingsToTreeForStructureRows([], withNonFoldersAndEmptyFolders: [], withDeletedRecords: Set(), modifiedRecords: Set(), alwaysIncludeRoots: true) + } + + public func includesOrDeletesNode(_ node: BookmarkTreeNode) -> Bool { + return self.includesOrDeletesGUID(node.recordGUID) + } + + public func includesNode(_ node: BookmarkTreeNode) -> Bool { + return self.includesGUID(node.recordGUID) + } + + public func includesOrDeletesGUID(_ guid: GUID) -> Bool { + return self.includesGUID(guid) || self.deleted.contains(guid) + } + + public func includesGUID(_ guid: GUID) -> Bool { + return self.lookup[guid] != nil + } + + public func find(_ guid: GUID) -> BookmarkTreeNode? { + return self.lookup[guid] + } + + public func find(_ node: BookmarkTreeNode) -> BookmarkTreeNode? { + return self.find(node.recordGUID) + } + + /** + * True if there is one subtree, and it's the Root, when overlayed. + * We assume that the mirror will always be consistent, so what + * this really means is that every subtree in this tree is *present* + * in the comparison tree, or is itself rooted in a known root. + * + * In a fully rooted tree there can be no orphans; if our partial tree + * includes orphans, they must be known by the comparison tree. + */ + public func isFullyRootedIn(_ tree: BookmarkTree) -> Bool { + // We don't compare against tree.deleted, because you can't *undelete*. + return self.orphans.every(tree.includesGUID) && + self.subtrees.every { subtree in + tree.includesNode(subtree) || subtree.isRoot + } + } + + // If this tree contains the root, return it. + public var root: BookmarkTreeNode? { + return self.find(BookmarkRoots.RootGUID) + } + + // Recursively process an input set of structure pairs to yield complete subtrees, + // assembling those subtrees to make a minimal set of trees. + static func mappingsToTreeForStructureRows(_ mappings: [StructureRow], withNonFoldersAndEmptyFolders nonFoldersAndEmptyFolders: [BookmarkTreeNode], withDeletedRecords deleted: Set, modifiedRecords modified: Set, alwaysIncludeRoots: Bool) -> BookmarkTree { + // Accumulate. + var nodes: [GUID: BookmarkTreeNode] = [:] + var parents: [GUID: GUID] = [:] + var remainingFolders = Set() + + // `tops` is the collection of things that we think are the roots of subtrees (until + // we're proved wrong). We add GUIDs here when we don't know their parents; if we get to + // the end and they're still here, they're roots. + var tops = Set() + var notTops = Set() + var orphans = Set() + var virtual = Set() + + // We can't immediately build the final tree, because we need to do it bottom-up! + // So store structure, which we can figure out flat. + var pseudoTree: [GUID: [GUID]] = mappings.groupBy({ $0.parent }, transformer: { $0.child }) + + // Deal with the ones that are non-structural first. + nonFoldersAndEmptyFolders.forEach { node in + let guid = node.recordGUID + nodes[guid] = node + + switch node { + case .folder: + // If we end up here, it's because this folder is empty, and it won't + // appear in structure. Assert to make sure that's true! + assert(pseudoTree[guid] == nil) + pseudoTree[guid] = [] + + // It'll be a top unless we find it as a child in the structure somehow. + tops.insert(guid) + default: + orphans.insert(guid) + } + } + + // Precompute every leaf node. + mappings.forEach { row in + parents[row.child] = row.parent + remainingFolders.insert(row.parent) + tops.insert(row.parent) + + // None of the children we've seen can be top, so remove them. + notTops.insert(row.child) + + if let type = row.type { + switch type { + case .folder: + // The child is itself a folder. + remainingFolders.insert(row.child) + default: + nodes[row.child] = BookmarkTreeNode.nonFolder(guid: row.child) + } + } else { + // This will be the case if we've shadowed a folder; we indirectly reference the original rows. + nodes[row.child] = BookmarkTreeNode.unknown(guid: row.child) + } + } + + // When we build the mirror, we always want to pretend it has our stock roots. + // This gives us our shared basis from which to merge. + // Doing it here means we don't need to protect the mirror database table. + if alwaysIncludeRoots { + func setVirtual(_ guid: GUID) { + if !remainingFolders.contains(guid) && nodes[guid] == nil { + virtual.insert(guid) + } + } + + // Note that we don't check whether the input already contained the roots; we + // never change them, so it's safe to do this unconditionally. + setVirtual(BookmarkRoots.RootGUID) + BookmarkRoots.RootChildren.forEach { + setVirtual($0) + } + + pseudoTree[BookmarkRoots.RootGUID] = BookmarkRoots.RootChildren + tops.insert(BookmarkRoots.RootGUID) + notTops.formUnion(Set(BookmarkRoots.RootChildren)) + remainingFolders.formUnion(BookmarkRoots.All) + BookmarkRoots.RootChildren.forEach { + parents[$0] = BookmarkRoots.RootGUID + } + } + + tops.subtract(notTops) + orphans.subtract(notTops) + + // Recursive. (Not tail recursive, but trees shouldn't be deep enough to blow the stack….) + @discardableResult func nodeForGUID(_ guid: GUID) -> BookmarkTreeNode { + if let already = nodes[guid] { + return already + } + + if !remainingFolders.contains(guid) { + let node = BookmarkTreeNode.unknown(guid: guid) + nodes[guid] = node + return node + } + + // Removing these eagerly prevents infinite recursion in the case of a cycle. + let childGUIDs = pseudoTree[guid] ?? [] + pseudoTree.removeValue(forKey: guid) + remainingFolders.remove(guid) + + let node = BookmarkTreeNode.folder(guid: guid, children: childGUIDs.map(nodeForGUID)) + nodes[guid] = node + return node + } + + // Process every record. + // Do the not-tops first: shallower recursion. + notTops.forEach({ nodeForGUID($0) }) + + let subtrees = tops.map(nodeForGUID) // These will all be folders. + + // Whatever we're left with in `tops` is the set of records for which we + // didn't process a parent. + return BookmarkTree(subtrees: subtrees, lookup: nodes, parents: parents, orphans: orphans, deleted: deleted, modified: modified, virtual: virtual) + } +} diff --git a/mobile/ios/Storage/CertStore.swift b/mobile/ios/Storage/CertStore.swift new file mode 100644 index 0000000000..13ec695b77 --- /dev/null +++ b/mobile/ios/Storage/CertStore.swift @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +import Shared +import UIKit +import Deferred + +/// In-memory certificate store. +open class CertStore { + fileprivate var keys = Set() + + public init() {} + + open func addCertificate(_ cert: SecCertificate, forOrigin origin: String) { + let data: Data = SecCertificateCopyData(cert) as Data + let key = keyForData(data, origin: origin) + keys.insert(key) + } + + open func containsCertificate(_ cert: SecCertificate, forOrigin origin: String) -> Bool { + let data: Data = SecCertificateCopyData(cert) as Data + let key = keyForData(data, origin: origin) + return keys.contains(key) + } + + fileprivate func keyForData(_ data: Data, origin: String) -> String { + return "\(origin)/\(data.sha256.hexEncodedString)" + } +} diff --git a/mobile/ios/Storage/Clients.swift b/mobile/ios/Storage/Clients.swift new file mode 100644 index 0000000000..401e15f736 --- /dev/null +++ b/mobile/ios/Storage/Clients.swift @@ -0,0 +1,75 @@ +/* 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/. */ + +import Shared +import SwiftyJSON + +public struct RemoteClient: Equatable { + public let guid: GUID? + public let modified: Timestamp + + public let name: String + public let type: String? + public let os: String? + public let version: String? + public let fxaDeviceId: String? + + let protocols: [String]? + + let appPackage: String? + let application: String? + let formfactor: String? + let device: String? + + // Requires a valid ClientPayload (: CleartextPayloadJSON: JSON). + public init(json: JSON, modified: Timestamp) { + self.guid = json["id"].string + self.modified = modified + self.name = json["name"].stringValue + self.type = json["type"].string + + self.version = json["version"].string + self.protocols = jsonsToStrings(json["protocols"].array) + self.os = json["os"].string + self.appPackage = json["appPackage"].string + self.application = json["application"].string + self.formfactor = json["formfactor"].string + self.device = json["device"].string + self.fxaDeviceId = json["fxaDeviceId"].string + } + + public init(guid: GUID?, name: String, modified: Timestamp, type: String?, formfactor: String?, os: String?, version: String?, fxaDeviceId: String?) { + self.guid = guid + self.name = name + self.modified = modified + self.type = type + self.formfactor = formfactor + self.os = os + self.version = version + self.fxaDeviceId = fxaDeviceId + + self.device = nil + self.appPackage = nil + self.application = nil + self.protocols = nil + } +} + +// TODO: should this really compare tabs? +public func ==(lhs: RemoteClient, rhs: RemoteClient) -> Bool { + return lhs.guid == rhs.guid && + lhs.name == rhs.name && + lhs.modified == rhs.modified && + lhs.type == rhs.type && + lhs.formfactor == rhs.formfactor && + lhs.os == rhs.os && + lhs.version == rhs.version && + lhs.fxaDeviceId == rhs.fxaDeviceId +} + +extension RemoteClient: CustomStringConvertible { + public var description: String { + return "" + } +} diff --git a/mobile/ios/Storage/CompletionOps.swift b/mobile/ios/Storage/CompletionOps.swift new file mode 100644 index 0000000000..2e4d804c1e --- /dev/null +++ b/mobile/ios/Storage/CompletionOps.swift @@ -0,0 +1,89 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger + +private let log = Logger.syncLogger + +public protocol PerhapsNoOp { + var isNoOp: Bool { get } +} + +open class LocalOverrideCompletionOp: PerhapsNoOp { + open var processedLocalChanges: Set = Set() // These can be deleted when we're run. Mark mirror as non-overridden, too. + + open var mirrorItemsToDelete: Set = Set() // These were locally or remotely deleted. + open var mirrorItemsToInsert: [GUID: BookmarkMirrorItem] = [:] // These were locally or remotely added. + open var mirrorItemsToUpdate: [GUID: BookmarkMirrorItem] = [:] // These were already in the mirror, but changed. + open var mirrorStructures: [GUID: [GUID]] = [:] // New or changed structure. + + open var mirrorValuesToCopyFromBuffer: Set = Set() // No need to synthesize BookmarkMirrorItem instances in memory. + open var mirrorValuesToCopyFromLocal: Set = Set() + open var modifiedTimes: [Timestamp: [GUID]] = [:] // Only for copy. + + open var isNoOp: Bool { + return processedLocalChanges.isEmpty && + mirrorValuesToCopyFromBuffer.isEmpty && + mirrorValuesToCopyFromLocal.isEmpty && + mirrorItemsToDelete.isEmpty && + mirrorItemsToInsert.isEmpty && + mirrorItemsToUpdate.isEmpty && + mirrorStructures.isEmpty + } + + open func setModifiedTime(_ time: Timestamp, guids: [GUID]) { + var forCopy: [GUID] = self.modifiedTimes[time] ?? [] + for guid in guids { + // This saves us doing an UPDATE on these items. + if var item = self.mirrorItemsToInsert[guid] { + item.serverModified = time + } else if var item = self.mirrorItemsToUpdate[guid] { + item.serverModified = time + } else { + forCopy.append(guid) + } + } + + if !forCopy.isEmpty { + modifiedTimes[time] = forCopy + } + } + + public init() { + } +} + +open class BufferCompletionOp: PerhapsNoOp { + open var processedBufferChanges: Set = Set() // These can be deleted when we're run. + + open var isNoOp: Bool { + return self.processedBufferChanges.isEmpty + } + + public init() { + } +} + +// This supports the "simple" bookmark syncing scenario where 3-way-merging is disabled: +// After upload, we first remove from the buffer the deleted records, +// then we move new local records to the buffer. +open class BufferUpdatedCompletionOp: PerhapsNoOp { + internal let bufferValuesToMoveFromLocal: Set + internal let deletedValues: Set + internal let mobileRoot: BookmarkMirrorItem + internal let modifiedTime: Timestamp + + open var isNoOp: Bool { + return false + } + + public init(bufferValuesToMoveFromLocal: Set, deletedValues: Set, mobileRoot: BookmarkMirrorItem, modifiedTime: Timestamp) { + self.bufferValuesToMoveFromLocal = bufferValuesToMoveFromLocal + self.deletedValues = deletedValues + self.mobileRoot = mobileRoot + self.modifiedTime = modifiedTime + } +} diff --git a/mobile/ios/Storage/Cursor.swift b/mobile/ios/Storage/Cursor.swift new file mode 100644 index 0000000000..e5286b5cd0 --- /dev/null +++ b/mobile/ios/Storage/Cursor.swift @@ -0,0 +1,124 @@ +/* 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/. */ + +import Foundation + +/** + * Status results for a Cursor + */ +public enum CursorStatus { + case success + case failure + case closed +} + +public protocol TypedCursor: Sequence { + associatedtype T + var count: Int { get } + var status: CursorStatus { get } + var statusMessage: String { get } + subscript(index: Int) -> T? { get } + func asArray() -> [T] +} + +/** + * Provides a generic method of returning some data and status information about a request. + */ +open class Cursor: TypedCursor { + open var count: Int { + get { return 0 } + } + + // Extra status information + open var status: CursorStatus + public var statusMessage: String + + init(err: NSError) { + self.status = .failure + self.statusMessage = err.description + } + + public init(status: CursorStatus = .success, msg: String = "") { + self.statusMessage = msg + self.status = status + } + + // Collection iteration and access functions + open subscript(index: Int) -> T? { + get { return nil } + } + + open func asArray() -> [T] { + var acc = [T]() + acc.reserveCapacity(self.count) + for row in self { + // Shouldn't ever be nil -- that's to allow the generator or subscript to be + // out of range. + if let row = row { + acc.append(row) + } + } + return acc + } + + open func makeIterator() -> AnyIterator { + var nextIndex = 0 + return AnyIterator() { + if nextIndex >= self.count || self.status != CursorStatus.success { + return nil + } + + defer { nextIndex += 1 } + return self[nextIndex] + } + } + + open func close() { + status = .closed + statusMessage = "Closed" + } + + deinit { + if status != CursorStatus.closed { + close() + } + } +} + +/* + * A cursor implementation that wraps an array. + */ +open class ArrayCursor : Cursor { + fileprivate var data: [T] + + open override var count: Int { + if status != .success { + return 0 + } + return data.count + } + + public init(data: [T], status: CursorStatus, statusMessage: String) { + self.data = data + super.init(status: status, msg: statusMessage) + } + + public convenience init(data: [T]) { + self.init(data: data, status: CursorStatus.success, statusMessage: "Success") + } + + open override subscript(index: Int) -> T? { + get { + if index >= data.count || index < 0 || status != .success { + return nil + } + return data[index] + } + } + + override open func close() { + data = [T]() + super.close() + } +} diff --git a/mobile/ios/Storage/DatabaseError.swift b/mobile/ios/Storage/DatabaseError.swift new file mode 100644 index 0000000000..6039ca4607 --- /dev/null +++ b/mobile/ios/Storage/DatabaseError.swift @@ -0,0 +1,24 @@ +/* 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/. */ + +import Shared + +/** + * Used to bridge the NSErrors we get here into something that Result is happy with. + */ +open class DatabaseError: MaybeErrorType { + let err: NSError? + + open var description: String { + return err?.localizedDescription ?? "Unknown database error." + } + + public init(description: String) { + self.err = NSError(domain: "mozilla", code: 0, userInfo: [NSLocalizedDescriptionKey: description]) + } + + public init(err: NSError?) { + self.err = err + } +} diff --git a/mobile/ios/Storage/DefaultSuggestedSites.swift b/mobile/ios/Storage/DefaultSuggestedSites.swift new file mode 100644 index 0000000000..40dec5994e --- /dev/null +++ b/mobile/ios/Storage/DefaultSuggestedSites.swift @@ -0,0 +1,130 @@ +/* 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/. */ + +import Foundation + +open class DefaultSuggestedSites { + open static let urlMap = [ + "https://www.amazon.com/": [ + "as": "https://www.amazon.in", + "cy": "https://www.amazon.co.uk", + "da": "https://www.amazon.co.uk", + "de": "https://www.amazon.de", + "dsb": "https://www.amazon.de", + "en_GB": "https://www.amazon.co.uk", + "et": "https://www.amazon.co.uk", + "ff": "https://www.amazon.fr", + "ga_IE": "https://www.amazon.co.uk", + "gu_IN": "https://www.amazon.in", + "hi_IN": "https://www.amazon.in", + "hr": "https://www.amazon.co.uk", + "hsb": "https://www.amazon.de", + "ja": "https://www.amazon.co.jp", + "kn": "https://www.amazon.in", + "mr": "https://www.amazon.in", + "or": "https://www.amazon.in", + "sq": "https://www.amazon.co.uk", + "ta": "https://www.amazon.in", + "te": "https://www.amazon.in", + "ur": "https://www.amazon.in", + "en_CA": "https://www.amazon.ca", + "fr_CA": "https://www.amazon.ca" + ] + ] + + open static let sites = [ + "default": [ + SuggestedSiteData( + url: "https://m.facebook.com/", + bgColor: "0x385185", + imageUrl: "asset://suggestedsites_facebook", + faviconUrl: "asset://defaultFavicon", + trackingId: 632, + title: NSLocalizedString("Facebook", comment: "Tile title for Facebook") + ), + SuggestedSiteData( + url: "https://m.youtube.com/", + bgColor: "0xcd201f", + imageUrl: "asset://suggestedsites_youtube", + faviconUrl: "asset://defaultFavicon", + trackingId: 631, + title: NSLocalizedString("YouTube", comment: "Tile title for YouTube") + ), + SuggestedSiteData( + url: "https://www.amazon.com/", + bgColor: "0x000000", + imageUrl: "asset://suggestedsites_amazon", + faviconUrl: "asset://defaultFavicon", + trackingId: 630, + title: NSLocalizedString("Amazon", comment: "Tile title for Amazon") + ), + SuggestedSiteData( + url: "https://www.wikipedia.org/", + bgColor: "0x000000", + imageUrl: "asset://suggestedsites_wikipedia", + faviconUrl: "asset://defaultFavicon", + trackingId: 629, + title: NSLocalizedString("Wikipedia", comment: "Tile title for Wikipedia") + ), + SuggestedSiteData( + url: "https://mobile.twitter.com/", + bgColor: "0x55acee", + imageUrl: "asset://suggestedsites_twitter", + faviconUrl: "asset://defaultFavicon", + trackingId: 628, + title: NSLocalizedString("Twitter", comment: "Tile title for Twitter") + ) + ], + "zh_CN": [ + SuggestedSiteData( + url: "http://mozilla.com.cn", + bgColor: "0xbc3326", + imageUrl: "asset://suggestedsites_mozchina", + faviconUrl: "asset://mozChinaLogo", + trackingId: 700, + title: "火狐社区" + ), + SuggestedSiteData( + url: "https://m.baidu.com/?from=1000969b", + bgColor: "0x00479d", + imageUrl: "asset://suggestedsites_baidu", + faviconUrl: "asset://baiduLogo", + trackingId: 701, + title: "百度" + ), + SuggestedSiteData( + url: "http://sina.cn", + bgColor: "0xe60012", + imageUrl: "asset://suggestedsites_sina", + faviconUrl: "asset://sinaLogo", + trackingId: 702, + title: "新浪" + ), + SuggestedSiteData( + url: "http://info.3g.qq.com/g/s?aid=index&g_f=23946&g_ut=3", + bgColor: "0x028cca", + imageUrl: "asset://suggestedsites_qq", + faviconUrl: "asset://qqLogo", + trackingId: 703, + title: "腾讯" + ), + SuggestedSiteData( + url: "http://m.taobao.com", + bgColor: "0xee5900", + imageUrl: "asset://suggestedsites_taobao", + faviconUrl: "asset://taobaoLogo", + trackingId: 704, + title: "淘宝" + ), + SuggestedSiteData( + url: "http://union.click.jd.com/jdc?e=0&p=AyIHVCtaJQMiQwpDBUoyS0IQWlALHE4YDk5ER1xONwdJKVxASgI%2BeDkWfGJ6HEAOUmkbcjUXVyUBEQZRG1IXARQ3VhhaEQETBVweayVkbzcedVolBxIEUBxdFAoQN1UeXRQLGwFXHlsUABs3UisnS0lKWghLWBQCFzdlK2s%3D&t=W1dCFBBFC14NXAAECUte", + bgColor: "0xc71622", + imageUrl: "asset://suggestedsites_jd", + faviconUrl: "asset://jdLogo", + trackingId: 705, + title: "京东" + ) + ] + ] +} diff --git a/mobile/ios/Storage/DiskImageStore.swift b/mobile/ios/Storage/DiskImageStore.swift new file mode 100644 index 0000000000..42ca16645b --- /dev/null +++ b/mobile/ios/Storage/DiskImageStore.swift @@ -0,0 +1,105 @@ +/* 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/. */ + +import Foundation +import Shared +import UIKit +import Deferred +import XCGLogger + +private var log = XCGLogger.default + +private class DiskImageStoreErrorType: MaybeErrorType { + let description: String + init(description: String) { + self.description = description + } +} + +/** + * Disk-backed key-value image store. + */ +open class DiskImageStore { + fileprivate let files: FileAccessor + fileprivate let filesDir: String + fileprivate let queue = DispatchQueue(label: "DiskImageStore") + fileprivate let quality: CGFloat + fileprivate var keys: Set + + required public init(files: FileAccessor, namespace: String, quality: Float) { + self.files = files + self.filesDir = try! files.getAndEnsureDirectory(namespace) + self.quality = CGFloat(quality) + + // Build an in-memory set of keys from the existing images on disk. + var keys = [String]() + if let fileEnumerator = FileManager.default.enumerator(atPath: filesDir) { + for file in fileEnumerator { + keys.append(file as! String) + } + } + self.keys = Set(keys) + } + + /// Gets an image for the given key if it is in the store. + open func get(_ key: String) -> Deferred> { + return deferDispatchAsync(queue) { () -> Deferred> in + if !self.keys.contains(key) { + return deferMaybe(DiskImageStoreErrorType(description: "Image key not found")) + } + + let imagePath = URL(fileURLWithPath: self.filesDir).appendingPathComponent(key) + if let data = try? Data(contentsOf: imagePath), + let image = UIImage.imageFromDataThreadSafe(data) { + return deferMaybe(image) + } + + return deferMaybe(DiskImageStoreErrorType(description: "Invalid image data")) + } + } + + /// Adds an image for the given key. + /// This put is asynchronous; the image is not recorded in the cache until the write completes. + /// Does nothing if this key already exists in the store. + @discardableResult open func put(_ key: String, image: UIImage) -> Success { + return deferDispatchAsync(queue) { () -> Success in + if self.keys.contains(key) { + return deferMaybe(DiskImageStoreErrorType(description: "Key already in store")) + } + + let imageURL = URL(fileURLWithPath: self.filesDir).appendingPathComponent(key) + if let data = UIImageJPEGRepresentation(image, self.quality) { + do { + try data.write(to: imageURL, options: .noFileProtection) + self.keys.insert(key) + return succeed() + } catch { + log.error("Unable to write image to disk: \(error)") + } + } + + return deferMaybe(DiskImageStoreErrorType(description: "Could not write image to file")) + } + } + + /// Clears all images from the cache, excluding the given set of keys. + open func clearExcluding(_ keys: Set) -> Success { + return deferDispatchAsync(queue) { () -> Success in + let keysToDelete = self.keys.subtracting(keys) + + for key in keysToDelete { + let url = URL(fileURLWithPath: self.filesDir).appendingPathComponent(key) + do { + try FileManager.default.removeItem(at: url) + } catch { + log.warning("Failed to remove DiskImageStore item at \(url.absoluteString): \(error)") + } + } + + self.keys = self.keys.intersection(keys) + + return succeed() + } + } +} diff --git a/mobile/ios/Storage/ExtensionUtils.swift b/mobile/ios/Storage/ExtensionUtils.swift new file mode 100644 index 0000000000..75bfb7d9ff --- /dev/null +++ b/mobile/ios/Storage/ExtensionUtils.swift @@ -0,0 +1,47 @@ +/* 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/. */ + +import UIKit +import MobileCoreServices + +public struct ExtensionUtils { + /// Look through the extensionContext for a url and title. Walks over all inputItems and then over all the attachments. + /// Has a completionHandler because ultimately an XPC call to the sharing application is done. + /// We can always extract a URL and sometimes a title. The favicon is currently just a placeholder, but + /// future code can possibly interact with a web page to find a proper icon. + public static func extractSharedItemFromExtensionContext(_ extensionContext: NSExtensionContext?, completionHandler: @escaping (ShareItem?, NSError?) -> Void) { + guard let extensionContext = extensionContext, + let inputItems = extensionContext.inputItems as? [NSExtensionItem] else { + completionHandler(nil, nil) + return + } + + for inputItem in inputItems { + guard let attachments = inputItem.attachments as? [NSItemProvider] else { continue } + + for attachment in attachments { + if attachment.hasItemConformingToTypeIdentifier(kUTTypeURL as String) { + attachment.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { obj, err in + guard err == nil else { + completionHandler(nil, err as NSError!) + return + } + + guard let url = obj as? URL else { + completionHandler(nil, NSError(domain: "org.mozilla.fennec", code: 999, userInfo: ["Problem": "Non-URL result."])) + return + } + + let title = inputItem.attributedContentText?.string + completionHandler(ShareItem(url: url.absoluteString, title: title, favicon: nil), nil) + } + + return + } + } + } + + completionHandler(nil, nil) + } +} diff --git a/mobile/ios/Storage/Favicons.swift b/mobile/ios/Storage/Favicons.swift new file mode 100644 index 0000000000..f3c9e54d41 --- /dev/null +++ b/mobile/ios/Storage/Favicons.swift @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Shared +import UIKit +import Deferred + +/* The base favicons protocol */ +public protocol Favicons { + func clearAllFavicons() -> Success + + /** + * Returns the ID of the added favicon. + */ + func addFavicon(_ icon: Favicon) -> Deferred> + + /** + * Returns the ID of the added favicon. + */ + @discardableResult func addFavicon(_ icon: Favicon, forSite site: Site) -> Deferred> +} diff --git a/mobile/ios/Storage/FileAccessor.swift b/mobile/ios/Storage/FileAccessor.swift new file mode 100644 index 0000000000..8122163591 --- /dev/null +++ b/mobile/ios/Storage/FileAccessor.swift @@ -0,0 +1,117 @@ +/* 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/. */ + +import Foundation + +/** + * A convenience class for file operations under a given root directory. + * Note that while this class is intended to be used to operate only on files + * under the root, this is not strictly enforced: clients can go outside + * the path using ".." or symlinks. + */ +open class FileAccessor { + open let rootPath: String + + public init(rootPath: String) { + self.rootPath = rootPath + } + + /** + * Gets the absolute directory path at the given relative path, creating it if it does not exist. + */ + open func getAndEnsureDirectory(_ relativeDir: String? = nil) throws -> String { + var absolutePath = rootPath + if let relativeDir = relativeDir { + absolutePath = URL(fileURLWithPath: absolutePath).appendingPathComponent(relativeDir).path + } + + try createDir(absolutePath) + return absolutePath + } + + /** + * Removes the file or directory at the given path, relative to the root. + */ + open func remove(_ relativePath: String) throws { + let path = URL(fileURLWithPath: rootPath).appendingPathComponent(relativePath).path + try FileManager.default.removeItem(atPath: path) + } + + /** + * Removes the contents of the directory without removing the directory itself. + */ + open func removeFilesInDirectory(_ relativePath: String = "") throws { + let fileManager = FileManager.default + let path = URL(fileURLWithPath: rootPath).appendingPathComponent(relativePath).path + let files = try fileManager.contentsOfDirectory(atPath: path) + for file in files { + try remove(URL(fileURLWithPath: relativePath).appendingPathComponent(file).path) + } + return + } + + /** + * Determines whether a file exists at the given path, relative to the root. + */ + open func exists(_ relativePath: String) -> Bool { + let path = URL(fileURLWithPath: rootPath).appendingPathComponent(relativePath).path + return FileManager.default.fileExists(atPath: path) + } + + open func attributesForFileAt(relativePath: String) throws -> [FileAttributeKey: Any] { + return try FileManager.default.attributesOfItem(atPath: URL(fileURLWithPath: rootPath).appendingPathComponent(relativePath).path) + } + + /** + * Moves the file or directory to the given destination, with both paths relative to the root. + * The destination directory is created if it does not exist. + */ + open func move(_ fromRelativePath: String, toRelativePath: String) throws { + let rootPathURL = URL(fileURLWithPath: rootPath) + let fromPath = rootPathURL.appendingPathComponent(fromRelativePath).path + let toPath = rootPathURL.appendingPathComponent(toRelativePath) + let toDir = toPath.deletingLastPathComponent() + let toDirPath = toDir.path + try createDir(toDirPath) + + try FileManager.default.moveItem(atPath: fromPath, toPath: toPath.path) + } + + open func copyMatching(fromRelativeDirectory relativePath: String, toAbsoluteDirectory absolutePath: String, matching: (String) -> Bool) throws { + let fileManager = FileManager.default + let pathURL = URL(fileURLWithPath: rootPath).appendingPathComponent(relativePath) + let path = pathURL.path + let destURL = URL(fileURLWithPath: absolutePath, isDirectory: true) + + let files = try fileManager.contentsOfDirectory(atPath: path) + for file in files { + if !matching(file) { + continue + } + + let from = pathURL.appendingPathComponent(file, isDirectory: false).path + let to = destURL.appendingPathComponent(file, isDirectory: false).path + do { + try fileManager.copyItem(atPath: from, toPath: to) + } catch { + } + } + } + + open func copy(_ fromRelativePath: String, toAbsolutePath: String) throws -> Bool { + let fromPath = URL(fileURLWithPath: rootPath).appendingPathComponent(fromRelativePath).path + let dest = URL(fileURLWithPath: toAbsolutePath).deletingLastPathComponent().path + try createDir(dest) + try FileManager.default.copyItem(atPath: fromPath, toPath: toAbsolutePath) + return true + } + + /** + * Creates a directory with the given path, including any intermediate directories. + * Does nothing if the directory already exists. + */ + fileprivate func createDir(_ absolutePath: String) throws { + try FileManager.default.createDirectory(atPath: absolutePath, withIntermediateDirectories: true, attributes: nil) + } +} diff --git a/mobile/ios/Storage/History.swift b/mobile/ios/Storage/History.swift new file mode 100644 index 0000000000..1e3a4c5374 --- /dev/null +++ b/mobile/ios/Storage/History.swift @@ -0,0 +1,108 @@ +/* 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/. */ + +import Shared +import Deferred + +open class IgnoredSiteError: MaybeErrorType { + open var description: String { + return "Ignored site." + } +} + +/** + * The base history protocol for front-end code. + * + * Note that the implementation of these methods might be complicated if + * the implementing class also implements SyncableHistory -- for example, + * `clear` might or might not need to set a bunch of flags to upload deletions. + */ +public protocol BrowserHistory { + @discardableResult func addLocalVisit(_ visit: SiteVisit) -> Success + func clearHistory() -> Success + @discardableResult func removeHistoryForURL(_ url: String) -> Success + func removeSiteFromTopSites(_ site: Site) -> Success + func removeHostFromTopSites(_ host: String) -> Success + func getFrecentHistory() -> FrecentHistory + func getSitesByLastVisit(_ limit: Int) -> Deferred>> + func getTopSitesWithLimit(_ limit: Int) -> Deferred>> + func setTopSitesNeedsInvalidation() + func setTopSitesCacheSize(_ size: Int32) + func clearTopSitesCache() -> Success + + // Pinning top sites + func removeFromPinnedTopSites(_ site: Site) -> Success + func addPinnedTopSite(_ site: Site) -> Success + func getPinnedTopSites() -> Deferred>> +} + +/** + * An interface for fast repeated frecency queries. + */ +public protocol FrecentHistory { + func getSites(whereURLContains filter: String?, historyLimit limit: Int, bookmarksLimit: Int) -> Deferred>> + func updateTopSitesCacheQuery() -> (String, Args?) +} + +/** + * An interface for accessing recommendation content from Storage + */ +public protocol HistoryRecommendations { + func getHighlights() -> Deferred>> + func getRecentBookmarks(_ limit: Int) -> Deferred>> + + func removeHighlightForURL(_ url: String) -> Success + func repopulate(invalidateTopSites shouldInvalidateTopSites: Bool, invalidateHighlights shouldInvalidateHighlights: Bool) -> Success +} + +/** + * The interface that history storage needs to provide in order to be + * synced by a `HistorySynchronizer`. + */ +public protocol SyncableHistory: AccountRemovalDelegate { + /** + * Make sure that the local place with the provided URL has the provided GUID. + * Succeeds if no place exists with that URL. + */ + func ensurePlaceWithURL(_ url: String, hasGUID guid: GUID) -> Success + + /** + * Delete the place with the provided GUID, and all of its visits. Succeeds if the GUID is unknown. + */ + func deleteByGUID(_ guid: GUID, deletedAt: Timestamp) -> Success + + func storeRemoteVisits(_ visits: [Visit], forGUID guid: GUID) -> Success + func insertOrUpdatePlace(_ place: Place, modified: Timestamp) -> Deferred> + + func getModifiedHistoryToUpload() -> Deferred> + func getDeletedHistoryToUpload() -> Deferred> + + /** + * Chains through the provided timestamp. + */ + func markAsSynchronized(_: [GUID], modified: Timestamp) -> Deferred> + func markAsDeleted(_ guids: [GUID]) -> Success + + func doneApplyingRecordsAfterDownload() -> Success + func doneUpdatingMetadataAfterUpload() -> Success + + /** + * For inspecting whether we're an active participant in history sync. + */ + func hasSyncedHistory() -> Deferred> +} + +// TODO: integrate Site with this. + +open class Place { + open let guid: GUID + open let url: String + open let title: String + + public init(guid: GUID, url: String, title: String) { + self.guid = guid + self.url = url + self.title = title + } +} diff --git a/mobile/ios/Storage/Info.plist b/mobile/ios/Storage/Info.plist new file mode 100644 index 0000000000..b3205ecaf4 --- /dev/null +++ b/mobile/ios/Storage/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/mobile/ios/Storage/Logins.swift b/mobile/ios/Storage/Logins.swift new file mode 100644 index 0000000000..faccc18397 --- /dev/null +++ b/mobile/ios/Storage/Logins.swift @@ -0,0 +1,621 @@ +/* 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/. */ + +import Foundation +import WebKit +import Shared +import Deferred +import XCGLogger + +private var log = Logger.syncLogger + +enum SyncStatus: Int { + // Ordinarily not needed; synced items are removed from the overlay. But they start here when cloned. + case synced = 0 + + // A material change that we want to upload on next sync. + case changed = 1 + + // Created locally. + case new = 2 +} + +public enum CommutativeLoginField { + case timesUsed(increment: Int) +} + +public protocol Indexable { + var index: Int { get } +} + +public enum NonCommutativeLoginField: Indexable { + case hostname(to: String) + case password(to: String) + case username(to: String?) + case httpRealm(to: String?) + case formSubmitURL(to: String?) + case timeCreated(to: MicrosecondTimestamp) // Should be immutable. + case timeLastUsed(to: MicrosecondTimestamp) + case timePasswordChanged(to: MicrosecondTimestamp) + + public var index: Int { + switch self { + case .hostname: + return 0 + case .password: + return 1 + case .username: + return 2 + case .httpRealm: + return 3 + case .formSubmitURL: + return 4 + case .timeCreated: + return 5 + case .timeLastUsed: + return 6 + case .timePasswordChanged: + return 7 + } + } + + static let Entries: Int = 8 +} + +// We don't care about these, because they're slated for removal at some point -- +// we don't really use them for form fill. +// We handle them in the same way as NonCommutative, just broken out to allow us +// flexibility in removing them or reconciling them differently. +public enum NonConflictingLoginField: Indexable { + case usernameField(to: String?) + case passwordField(to: String?) + + public var index: Int { + switch self { + case .usernameField: + return 0 + case .passwordField: + return 1 + } + } + + static let Entries: Int = 2 +} + +public typealias LoginDeltas = ( + commutative: [CommutativeLoginField], + nonCommutative: [NonCommutativeLoginField], + nonConflicting: [NonConflictingLoginField] +) + +public typealias TimestampedLoginDeltas = (at: Timestamp, changed: LoginDeltas) + +/** + * LoginData is a wrapper around NSURLCredential and NSURLProtectionSpace to allow us to add extra fields where needed. + **/ +public protocol LoginData: class { + var guid: String { get set } // It'd be nice if this were read-only. + var credentials: URLCredential { get } + var protectionSpace: URLProtectionSpace { get } + var hostname: String { get } + var username: String? { get } + var password: String { get } + var httpRealm: String? { get set } + var formSubmitURL: String? { get set } + var usernameField: String? { get set } + var passwordField: String? { get set } + var isValid: Maybe<()> { get } + + // https://bugzilla.mozilla.org/show_bug.cgi?id=1238103 + var hasMalformedHostname: Bool { get set } + + func toDict() -> [String: String] + + func isSignificantlyDifferentFrom(_ login: LoginData) -> Bool +} + +public protocol LoginUsageData { + var timesUsed: Int { get set } + var timeCreated: MicrosecondTimestamp { get set } + var timeLastUsed: MicrosecondTimestamp { get set } + var timePasswordChanged: MicrosecondTimestamp { get set } +} + +open class Login: CustomStringConvertible, LoginData, LoginUsageData, Equatable { + open var guid: String + + open fileprivate(set) var credentials: URLCredential + open let protectionSpace: URLProtectionSpace + + open var hostname: String { + if let _ = protectionSpace.`protocol` { + return protectionSpace.urlString() + } + return protectionSpace.host + } + + open var hasMalformedHostname: Bool = false + + open var username: String? { return credentials.user } + open var password: String { return credentials.password ?? "" } + open var usernameField: String? + open var passwordField: String? + + fileprivate var _httpRealm: String? + open var httpRealm: String? { + get { return self._httpRealm ?? protectionSpace.realm } + set { self._httpRealm = newValue } + } + + fileprivate var _formSubmitURL: String? + open var formSubmitURL: String? { + get { + return self._formSubmitURL + } + set(value) { + guard let value = value, !value.isEmpty else { + self._formSubmitURL = nil + return + } + + let url2 = URL(string: self.hostname) + let url1 = URL(string: value) + + if url1?.host != url2?.host { + log.warning("Form submit URL domain doesn't match login's domain.") + } + + self._formSubmitURL = value + } + } + + // LoginUsageData. These defaults only apply to locally created records. + open var timesUsed = 0 + open var timeCreated = Date.nowMicroseconds() + open var timeLastUsed = Date.nowMicroseconds() + open var timePasswordChanged = Date.nowMicroseconds() + + // Printable + open var description: String { + return "Login for \(hostname)" + } + + open var isValid: Maybe<()> { + // Referenced from https://mxr.mozilla.org/mozilla-central/source/toolkit/components/passwordmgr/nsLoginManager.js?rev=f76692f0fcf8&mark=280-281#271 + + // Logins with empty hostnames are not valid. + if hostname.isEmpty { + return Maybe(failure: LoginDataError(description: "Can't add a login with an empty hostname.")) + } + + // Logins with empty passwords are not valid. + if password.isEmpty { + return Maybe(failure: LoginDataError(description: "Can't add a login with an empty password.")) + } + + // Logins with both a formSubmitURL and httpRealm are not valid. + if let _ = formSubmitURL, let _ = httpRealm { + return Maybe(failure: LoginDataError(description: "Can't add a login with both a httpRealm and formSubmitURL.")) + } + + // Login must have at least a formSubmitURL or httpRealm. + if (formSubmitURL == nil) && (httpRealm == nil) { + return Maybe(failure: LoginDataError(description: "Can't add a login without a httpRealm or formSubmitURL.")) + } + + // All good. + return Maybe(success: ()) + } + + open func update(password: String, username: String) { + self.credentials = + URLCredential(user: username, password: password, persistence: credentials.persistence) + } + + // Essentially: should we sync a change? + // Desktop ignores usernameField and hostnameField. + open func isSignificantlyDifferentFrom(_ login: LoginData) -> Bool { + return login.password != self.password || + login.hostname != self.hostname || + login.username != self.username || + login.formSubmitURL != self.formSubmitURL || + login.httpRealm != self.httpRealm + } + + /* Used for testing purposes since formSubmitURL should be given back to use from the Logins.js script */ + open class func createWithHostname(_ hostname: String, username: String, password: String, formSubmitURL: String?) -> LoginData { + let loginData = Login(hostname: hostname, username: username, password: password) as LoginData + loginData.formSubmitURL = formSubmitURL + return loginData + } + + open class func createWithHostname(_ hostname: String, username: String, password: String) -> LoginData { + return Login(hostname: hostname, username: username, password: password) as LoginData + } + + open class func createWithCredential(_ credential: URLCredential, protectionSpace: URLProtectionSpace) -> LoginData { + return Login(credential: credential, protectionSpace: protectionSpace) as LoginData + } + + public init(guid: String, hostname: String, username: String, password: String) { + self.guid = guid + self.credentials = URLCredential(user: username, password: password, persistence: URLCredential.Persistence.none) + + // Break down the full url hostname into its scheme/protocol and host components + let hostnameURL = hostname.asURL + let host = hostnameURL?.host ?? hostname + let scheme = hostnameURL?.scheme ?? "" + + // We should ignore any SSL or normal web ports in the URL. + var port = hostnameURL?.port ?? 0 + if port == 443 || port == 80 { + port = 0 + } + + self.protectionSpace = URLProtectionSpace(host: host, port: port, protocol: scheme, realm: nil, authenticationMethod: nil) + } + + convenience init(hostname: String, username: String, password: String) { + self.init(guid: Bytes.generateGUID(), hostname: hostname, username: username, password: password) + } + + // Why do we need this initializer to be marked as required? Because otherwise we can't + // use this type in our factory for MirrorLogin and LocalLogin. + // SO: http://stackoverflow.com/questions/26280176/swift-generics-not-preserving-type + // Playground: https://gist.github.com/rnewman/3fb0c4dbd25e7fda7e3d + // Conversation: https://twitter.com/rnewman/status/611332618412359680 + required public init(credential: URLCredential, protectionSpace: URLProtectionSpace) { + self.guid = Bytes.generateGUID() + self.credentials = credential + self.protectionSpace = protectionSpace + } + + open func toDict() -> [String: String] { + return [ + "hostname": hostname, + "formSubmitURL": formSubmitURL ?? "", + "httpRealm": httpRealm ?? "", + "username": username ?? "", + "password": password, + "usernameField": usernameField ?? "", + "passwordField": passwordField ?? "" + ] + } + + open class func fromScript(_ url: URL, script: [String: Any]) -> LoginData? { + guard let username = script["username"] as? String, + let password = script["password"] as? String else { + return nil + } + + guard let origin = getPasswordOrigin(url.absoluteString) else { + return nil + } + + let login = Login(hostname: origin, username: username, password: password) + + if let formSubmit = script["formSubmitURL"] as? String { + login.formSubmitURL = formSubmit + } + + if let passwordField = script["passwordField"] as? String { + login.passwordField = passwordField + } + + if let userField = script["usernameField"] as? String { + login.usernameField = userField + } + + return login as LoginData + } + + fileprivate class func getPasswordOrigin(_ uriString: String, allowJS: Bool = false) -> String? { + var realm: String? = nil + if let uri = URL(string: uriString), + let scheme = uri.scheme, !scheme.isEmpty, + let host = uri.host { + if allowJS && scheme == "javascript" { + return "javascript:" + } + + realm = "\(scheme)://\(host)" + + // If the URI explicitly specified a port, only include it when + // it's not the default. (We never want "http://foo.com:80") + if let port = uri.port { + realm? += ":\(port)" + } + } else { + // bug 159484 - disallow url types that don't support a hostPort. + // (although we handle "javascript:..." as a special case above.) + log.debug("Couldn't parse origin for \(uriString)") + realm = nil + } + return realm + } + + /** + * Produce a delta stream by comparing this record to a source. + * Note that the source might be missing the timestamp and counter fields + * introduced in Bug 555755, so we pay special attention to those, checking for + * and ignoring transitions to zero. + * + * TODO: it's possible that we'll have, say, two iOS clients working with a desktop. + * Each time the desktop changes the password fields, it'll upload a record without + * these extra timestamp fields. We need to make sure the right thing happens. + * + * There are three phases in this process: + * 1. Producing deltas. There is no intrinsic ordering here, but we yield ordered + * arrays for convenience and ease of debugging. + * 2. Comparing deltas. This is done through a kind of array-based Perlish Schwartzian + * transform, where each field has a known index in space to allow for trivial + * comparison; this, of course, is ordered. + * 3. Applying a merged delta stream to a record. Again, this is unordered, but we + * use arrays for convenience. + */ + open func deltas(from: Login) -> LoginDeltas { + let commutative: [CommutativeLoginField] + + if self.timesUsed > 0 && self.timesUsed != from.timesUsed { + commutative = [CommutativeLoginField.timesUsed(increment: self.timesUsed - from.timesUsed)] + } else { + commutative = [] + } + + var nonCommutative = [NonCommutativeLoginField]() + + if self.hostname != from.hostname { + nonCommutative.append(NonCommutativeLoginField.hostname(to: self.hostname)) + } + if self.password != from.password { + nonCommutative.append(NonCommutativeLoginField.password(to: self.password)) + } + if self.username != from.username { + nonCommutative.append(NonCommutativeLoginField.username(to: self.username)) + } + if self.httpRealm != from.httpRealm { + nonCommutative.append(NonCommutativeLoginField.httpRealm(to: self.httpRealm)) + } + if self.formSubmitURL != from.formSubmitURL { + nonCommutative.append(NonCommutativeLoginField.formSubmitURL(to: self.formSubmitURL)) + } + if self.timeCreated > 0 && self.timeCreated != from.timeCreated { + nonCommutative.append(NonCommutativeLoginField.timeCreated(to: self.timeCreated)) + } + if self.timeLastUsed > 0 && self.timeLastUsed != from.timeLastUsed { + nonCommutative.append(NonCommutativeLoginField.timeLastUsed(to: self.timeLastUsed)) + } + if self.timeLastUsed > 0 && self.timePasswordChanged != from.timePasswordChanged { + nonCommutative.append(NonCommutativeLoginField.timePasswordChanged(to: self.timePasswordChanged)) + } + + var nonConflicting = [NonConflictingLoginField]() + + if self.passwordField != from.passwordField { + nonConflicting.append(NonConflictingLoginField.passwordField(to: self.passwordField)) + } + if self.usernameField != from.usernameField { + nonConflicting.append(NonConflictingLoginField.usernameField(to: self.usernameField)) + } + + return (commutative, nonCommutative, nonConflicting) + } + + fileprivate class func mergeDeltaFields(_ count: Int, a: [T], b: [T], preferBToA: Bool) -> [T] { + var deltas = Array(repeating: nil, count: count) + + // Let's start with the 'a's. + for f in a { + deltas[f.index] = f + } + + // Then detect any conflicts and fill out the rest. + for f in b { + let index = f.index + if deltas[index] != nil { + log.warning("Collision in \(T.self) \(f.index). Using latest.") + if preferBToA { + deltas[index] = f + } + } else { + deltas[index] = f + } + } + + return optFilter(deltas) + } + + open class func mergeDeltas(a: TimestampedLoginDeltas, b: TimestampedLoginDeltas) -> LoginDeltas { + let (aAt, aChanged) = a + let (bAt, bChanged) = b + let (aCommutative, aNonCommutative, aNonConflicting) = aChanged + let (bCommutative, bNonCommutative, bNonConflicting) = bChanged + + // If the timestamps are exactly the same -- an exceedingly rare occurrence -- we default + // to 'b', which is the remote record by convention. + let bLatest = aAt <= bAt + + let commutative = aCommutative + bCommutative + let nonCommutative: [NonCommutativeLoginField] + let nonConflicting: [NonConflictingLoginField] + + if aNonCommutative.isEmpty { + nonCommutative = bNonCommutative + } else if bNonCommutative.isEmpty { + nonCommutative = aNonCommutative + } else { + nonCommutative = mergeDeltaFields(NonCommutativeLoginField.Entries, a: aNonCommutative, b: bNonCommutative, preferBToA: bLatest) + } + + if aNonConflicting.isEmpty { + nonConflicting = bNonConflicting + } else if bNonCommutative.isEmpty { + nonConflicting = aNonConflicting + } else { + nonConflicting = mergeDeltaFields(NonConflictingLoginField.Entries, a: aNonConflicting, b: bNonConflicting, preferBToA: bLatest) + } + + return ( + commutative: commutative, + nonCommutative: nonCommutative, + nonConflicting: nonConflicting + ) + } + + /** + * Apply the provided changes to yield a new login. + */ + open func applyDeltas(_ deltas: LoginDeltas) -> Login { + let guid = self.guid + var hostname = self.hostname + var username = self.username + var password = self.password + var usernameField = self.usernameField + var passwordField = self.passwordField + var timesUsed = self.timesUsed + var httpRealm = self.httpRealm + var formSubmitURL = self.formSubmitURL + var timeCreated = self.timeCreated + var timeLastUsed = self.timeLastUsed + var timePasswordChanged = self.timePasswordChanged + + for delta in deltas.commutative { + switch delta { + case let .timesUsed(increment): + timesUsed += increment + } + } + + for delta in deltas.nonCommutative { + switch delta { + case let .hostname(to): + hostname = to + break + case let .password(to): + password = to + break + case let .username(to): + username = to + break + case let .httpRealm(to): + httpRealm = to + break + case let .formSubmitURL(to): + formSubmitURL = to + break + case let .timeCreated(to): + timeCreated = to + break + case let .timeLastUsed(to): + timeLastUsed = to + break + case let .timePasswordChanged(to): + timePasswordChanged = to + break + } + } + + for delta in deltas.nonConflicting { + switch delta { + case let .usernameField(to): + usernameField = to + break + case let .passwordField(to): + passwordField = to + break + } + } + + let out = Login(guid: guid, hostname: hostname, username: username ?? "", password: password) + out.timesUsed = timesUsed + out.httpRealm = httpRealm + out.formSubmitURL = formSubmitURL + out.timeCreated = timeCreated + out.timeLastUsed = timeLastUsed + out.timePasswordChanged = timePasswordChanged + out.usernameField = usernameField + out.passwordField = passwordField + + return out + } +} + +public func ==(lhs: Login, rhs: Login) -> Bool { + return lhs.credentials == rhs.credentials && lhs.protectionSpace == rhs.protectionSpace +} + +open class ServerLogin: Login { + var serverModified: Timestamp = 0 + + public init(guid: String, hostname: String, username: String, password: String, modified: Timestamp) { + self.serverModified = modified + super.init(guid: guid, hostname: hostname, username: username, password: password) + } + + required public init(credential: URLCredential, protectionSpace: URLProtectionSpace) { + super.init(credential: credential, protectionSpace: protectionSpace) + } +} + +class MirrorLogin: ServerLogin { + var isOverridden: Bool = false +} + +class LocalLogin: Login { + var syncStatus: SyncStatus = .synced + var isDeleted: Bool = false + var localModified: Timestamp = 0 +} + +public protocol BrowserLogins { + func getUsageDataForLoginByGUID(_ guid: GUID) -> Deferred> + func getLoginDataForGUID(_ guid: GUID) -> Deferred> + func getLoginsForProtectionSpace(_ protectionSpace: URLProtectionSpace) -> Deferred>> + func getLoginsForProtectionSpace(_ protectionSpace: URLProtectionSpace, withUsername username: String?) -> Deferred>> + func getAllLogins() -> Deferred>> + func searchLoginsWithQuery(_ query: String?) -> Deferred>> + + // Add a new login regardless of whether other logins might match some fields. Callers + // are responsible for querying first if they care. + @discardableResult func addLogin(_ login: LoginData) -> Success + + @discardableResult func updateLoginByGUID(_ guid: GUID, new: LoginData, significant: Bool) -> Success + + // Add the use of a login by GUID. + @discardableResult func addUseOfLoginByGUID(_ guid: GUID) -> Success + func removeLoginByGUID(_ guid: GUID) -> Success + func removeLoginsWithGUIDs(_ guids: [GUID]) -> Success + + func removeAll() -> Success +} + +public protocol SyncableLogins: AccountRemovalDelegate { + /** + * Delete the login with the provided GUID. Succeeds if the GUID is unknown. + */ + func deleteByGUID(_ guid: GUID, deletedAt: Timestamp) -> Success + + func applyChangedLogin(_ upstream: ServerLogin) -> Success + + func getModifiedLoginsToUpload() -> Deferred> + func getDeletedLoginsToUpload() -> Deferred> + + /** + * Chains through the provided timestamp. + */ + func markAsSynchronized(_: T, modified: Timestamp) -> Deferred> where T.Iterator.Element == GUID + func markAsDeleted(_ guids: T) -> Success where T.Iterator.Element == GUID + + /** + * For inspecting whether we're an active participant in login sync. + */ + func hasSyncedLogins() -> Deferred> +} + +open class LoginDataError: MaybeErrorType { + open let description: String + public init(description: String) { + self.description = description + } +} diff --git a/mobile/ios/Storage/Metadata.swift b/mobile/ios/Storage/Metadata.swift new file mode 100644 index 0000000000..1f4e68f6d4 --- /dev/null +++ b/mobile/ios/Storage/Metadata.swift @@ -0,0 +1,13 @@ +/* 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/. */ + +import Foundation +import Deferred +import Shared + +/// Interface for saving and retrieving metadata web content +public protocol Metadata { + @discardableResult func storeMetadata(_ metadata: PageMetadata, forPageURL: URL, expireAt: UInt64) -> Success + func deleteExpiredMetadata() -> Success +} diff --git a/mobile/ios/Storage/MockLogins.swift b/mobile/ios/Storage/MockLogins.swift new file mode 100644 index 0000000000..5e44b59c2e --- /dev/null +++ b/mobile/ios/Storage/MockLogins.swift @@ -0,0 +1,154 @@ +/* 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/. */ + +import Foundation +import Shared +import Deferred + +open class MockLogins: BrowserLogins, SyncableLogins { + fileprivate var cache = [Login]() + + public init(files: FileAccessor) { + } + + open func getLoginsForProtectionSpace(_ protectionSpace: URLProtectionSpace) -> Deferred>> { + let cursor = ArrayCursor(data: cache.filter({ login in + return login.protectionSpace.host == protectionSpace.host + }).sorted(by: { (loginA, loginB) -> Bool in + return loginA.timeLastUsed > loginB.timeLastUsed + }).map({ login in + return login as LoginData + })) + return Deferred(value: Maybe(success: cursor)) + } + + open func getLoginsForProtectionSpace(_ protectionSpace: URLProtectionSpace, withUsername username: String?) -> Deferred>> { + let cursor = ArrayCursor(data: cache.filter({ login in + return login.protectionSpace.host == protectionSpace.host && + login.username == username + }).sorted(by: { (loginA, loginB) -> Bool in + return loginA.timeLastUsed > loginB.timeLastUsed + }).map({ login in + return login as LoginData + })) + return Deferred(value: Maybe(success: cursor)) + } + + open func getLoginDataForGUID(_ guid: GUID) -> Deferred> { + if let login = (cache.filter { $0.guid == guid }).first { + return deferMaybe(login) + } else { + return deferMaybe(LoginDataError(description: "Login for GUID \(guid) not found")) + } + } + + open func getAllLogins() -> Deferred>> { + let cursor = ArrayCursor(data: cache.sorted(by: { (loginA, loginB) -> Bool in + return loginA.hostname > loginB.hostname + })) + return Deferred(value: Maybe(success: cursor)) + } + + open func searchLoginsWithQuery(_ query: String?) -> Deferred>> { + let cursor = ArrayCursor(data: cache.filter({ login in + var checks = [Bool]() + if let query = query { + checks.append(login.username?.contains(query) ?? false) + checks.append(login.password.contains(query)) + checks.append(login.hostname.contains(query)) + } + return checks.contains(true) + }).sorted(by: { (loginA, loginB) -> Bool in + return loginA.hostname > loginB.hostname + })) + return Deferred(value: Maybe(success: cursor)) + } + + // This method is only here for testing + open func getUsageDataForLoginByGUID(_ guid: GUID) -> Deferred> { + let res = cache.filter({ login in + return login.guid == guid + }).sorted(by: { (loginA, loginB) -> Bool in + return loginA.timeLastUsed > loginB.timeLastUsed + })[0] as LoginUsageData + + return Deferred(value: Maybe(success: res)) + } + + open func addLogin(_ login: LoginData) -> Success { + if let _ = cache.index(of: login as! Login) { + return deferMaybe(LoginDataError(description: "Already in the cache")) + } + cache.append(login as! Login) + return succeed() + } + + open func updateLoginByGUID(_ guid: GUID, new: LoginData, significant: Bool) -> Success { + // TODO + return succeed() + } + + open func getModifiedLoginsToUpload() -> Deferred> { + // TODO + return deferMaybe([]) + } + + open func getDeletedLoginsToUpload() -> Deferred> { + // TODO + return deferMaybe([]) + } + + open func updateLogin(_ login: LoginData) -> Success { + if let index = cache.index(of: login as! Login) { + cache[index].timePasswordChanged = Date.nowMicroseconds() + return succeed() + } + return deferMaybe(LoginDataError(description: "Password wasn't cached yet. Can't update")) + } + + open func addUseOfLoginByGUID(_ guid: GUID) -> Success { + if let login = cache.filter({ $0.guid == guid }).first { + login.timeLastUsed = Date.nowMicroseconds() + return succeed() + } + return deferMaybe(LoginDataError(description: "Password wasn't cached yet. Can't update")) + } + + open func removeLoginByGUID(_ guid: GUID) -> Success { + let filtered = cache.filter { $0.guid != guid } + if filtered.count == cache.count { + return deferMaybe(LoginDataError(description: "Can not remove a password that wasn't stored")) + } + cache = filtered + return succeed() + } + + open func removeLoginsWithGUIDs(_ guids: [GUID]) -> Success { + return walk(guids) { guid in + self.removeLoginByGUID(guid) + } + } + + open func removeAll() -> Success { + cache.removeAll(keepingCapacity: false) + return succeed() + } + + open func hasSyncedLogins() -> Deferred> { + return deferMaybe(true) + } + + // TODO + open func deleteByGUID(_ guid: GUID, deletedAt: Timestamp) -> Success { return succeed() } + open func applyChangedLogin(_ upstream: ServerLogin) -> Success { return succeed() } + open func markAsSynchronized(_: T, modified: Timestamp) -> Deferred> where T.Iterator.Element == GUID { return deferMaybe(0) } + open func markAsDeleted(_ guids: T) -> Success where T.Iterator.Element == GUID { return succeed() } + open func onRemovedAccount() -> Success { return succeed() } +} + +extension MockLogins: ResettableSyncStorage { + public func resetClient() -> Success { + return succeed() + } +} diff --git a/mobile/ios/Storage/PageMetadata.swift b/mobile/ios/Storage/PageMetadata.swift new file mode 100644 index 0000000000..48f93f911a --- /dev/null +++ b/mobile/ios/Storage/PageMetadata.swift @@ -0,0 +1,106 @@ +/* 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/. */ + +import Foundation +import UIKit +import SDWebImage + +enum MetadataKeys: String { + case imageURL = "image" + case imageDataURI = "image_data_uri" + case pageURL = "url" + case title = "title" + case description = "description" + case type = "type" + case provider = "provider" + case favicon = "icon" + case keywords = "keywords" +} + +/* + * Value types representing a page's metadata + */ +public struct PageMetadata { + public let id: Int? + public let siteURL: String + public let mediaURL: String? + public let title: String? + public let description: String? + public let type: String? + public let providerName: String? + public let faviconURL: String? + public let keywordsString: String? + public var keywords: Set { + guard let string = keywordsString else { + return Set() + } + + let strings = string.split(separator: ",", omittingEmptySubsequences: true).map(String.init) + return Set(strings) + } + + public init(id: Int?, siteURL: String, mediaURL: String?, title: String?, description: String?, type: String?, providerName: String?, mediaDataURI: String?, faviconURL: String? = nil, keywords: String? = nil, cacheImages: Bool = true) { + self.id = id + self.siteURL = siteURL + self.mediaURL = mediaURL + self.title = title + self.description = description + self.type = type + self.providerName = providerName + self.faviconURL = faviconURL + self.keywordsString = keywords + + if let urlString = mediaURL, let url = URL(string: urlString), cacheImages { + self.cacheImage(fromDataURI: mediaDataURI, forURL: url) + } + } + + public static func fromDictionary(_ dict: [String: Any]) -> PageMetadata? { + guard let siteURL = dict[MetadataKeys.pageURL.rawValue] as? String else { + return nil + } + + return PageMetadata(id: nil, siteURL: siteURL, mediaURL: dict[MetadataKeys.imageURL.rawValue] as? String, + title: dict[MetadataKeys.title.rawValue] as? String, description: dict[MetadataKeys.description.rawValue] as? String, + type: dict[MetadataKeys.type.rawValue] as? String, providerName: dict[MetadataKeys.provider.rawValue] as? String, mediaDataURI: dict[MetadataKeys.imageDataURI.rawValue] as? String, faviconURL: dict[MetadataKeys.favicon.rawValue] as? String, keywords: dict[MetadataKeys.keywords.rawValue] as? String) + } + + fileprivate func cacheImage(fromDataURI dataURI: String?, forURL url: URL) { + let manager = SDWebImageManager.shared() + + func cacheUsingURLOnly() { + manager.cachedImageExists(for: url) { exists in + if !exists { + self.downloadAndCache(fromURL: url) + } + } + } + + guard let dataURI = dataURI, let dataURL = URL(string: dataURI) else { + cacheUsingURLOnly() + return + } + + manager.cachedImageExists(for: dataURL) { exists in + if let data = try? Data(contentsOf: dataURL), let image = UIImage(data: data), !exists { + self.cache(image: image, forURL: url) + } else { + cacheUsingURLOnly() + } + } + } + + fileprivate func downloadAndCache(fromURL webUrl: URL) { + let manager = SDWebImageManager.shared() + manager.loadImage(with: webUrl, options: .continueInBackground, progress: nil) { (image, _, _, _, _, _) in + if let image = image { + self.cache(image: image, forURL: webUrl) + } + } + } + + fileprivate func cache(image: UIImage, forURL url: URL) { + SDWebImageManager.shared().saveImage(toCache: image, for: url) + } +} diff --git a/mobile/ios/Storage/Queue.swift b/mobile/ios/Storage/Queue.swift new file mode 100644 index 0000000000..882e3142bc --- /dev/null +++ b/mobile/ios/Storage/Queue.swift @@ -0,0 +1,13 @@ +/* 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/. */ + +import Foundation +import Shared +import Deferred + +public protocol TabQueue { + func addToQueue(_ tab: ShareItem) -> Success + func getQueuedTabs() -> Deferred>> + @discardableResult func clearQueuedTabs() -> Success +} diff --git a/mobile/ios/Storage/RecentlyClosedTabs.swift b/mobile/ios/Storage/RecentlyClosedTabs.swift new file mode 100644 index 0000000000..fbffabbbbd --- /dev/null +++ b/mobile/ios/Storage/RecentlyClosedTabs.swift @@ -0,0 +1,76 @@ +/* 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/. */ + +import Foundation +import Shared + +open class ClosedTabsStore { + let prefs: Prefs + + lazy open var tabs: [ClosedTab] = { + guard let tabsArray: Data = self.prefs.objectForKey("recentlyClosedTabs") as Any? as? Data, + let unarchivedArray = NSKeyedUnarchiver.unarchiveObject(with: tabsArray) as? [ClosedTab] else { + return [] + } + return unarchivedArray + }() + + public init(prefs: Prefs) { + self.prefs = prefs + } + + open func addTab(_ url: URL, title: String?, faviconURL: String?) { + let recentlyClosedTab = ClosedTab(url: url, title: title ?? "", faviconURL: faviconURL ?? "") + tabs.insert(recentlyClosedTab, at: 0) + if tabs.count > 5 { + tabs.removeLast() + } + let archivedTabsArray = NSKeyedArchiver.archivedData(withRootObject: tabs) + prefs.setObject(archivedTabsArray, forKey: "recentlyClosedTabs") + } + + open func clearTabs() { + prefs.removeObjectForKey("recentlyClosedTabs") + tabs = [] + } +} + +open class ClosedTab: NSObject, NSCoding { + open let url: URL + open let title: String? + open let faviconURL: String? + + var jsonDictionary: [String: Any] { + let title = (self.title ?? "") + let faviconURL = (self.faviconURL ?? "") + let json: [String: Any] = ["title": title, "url": url, "faviconURL": faviconURL] + return json + } + + init(url: URL, title: String?, faviconURL: String?) { + assert(Thread.isMainThread) + self.title = title + self.url = url + self.faviconURL = faviconURL + super.init() + } + + required convenience public init?(coder: NSCoder) { + guard let url = coder.decodeObject(forKey: "url") as? URL, + let faviconURL = coder.decodeObject(forKey: "faviconURL") as? String, + let title = coder.decodeObject(forKey: "title") as? String else { return nil } + + self.init( + url: url, + title: title, + faviconURL: faviconURL + ) + } + + open func encode(with coder: NSCoder) { + coder.encode(url, forKey: "url") + coder.encode(faviconURL, forKey: "faviconURL") + coder.encode(title, forKey: "title") + } +} diff --git a/mobile/ios/Storage/RemoteTabs.swift b/mobile/ios/Storage/RemoteTabs.swift new file mode 100644 index 0000000000..59cf906bad --- /dev/null +++ b/mobile/ios/Storage/RemoteTabs.swift @@ -0,0 +1,109 @@ +/* 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/. */ + +import Foundation +import Shared +import Deferred + +public struct ClientAndTabs: Equatable, CustomStringConvertible { + public let client: RemoteClient + public let tabs: [RemoteTab] + + public var description: String { + return "" + } + + // See notes in RemoteTabsPanel.swift. + public func approximateLastSyncTime() -> Timestamp { + if tabs.isEmpty { + return client.modified + } + + return tabs.reduce(Timestamp(0), { m, tab in + return max(m, tab.lastUsed) + }) + } +} + +public func ==(lhs: ClientAndTabs, rhs: ClientAndTabs) -> Bool { + return (lhs.client == rhs.client) && + (lhs.tabs == rhs.tabs) +} + +public protocol RemoteClientsAndTabs: SyncCommands { + func wipeClients() -> Deferred> + func wipeRemoteTabs() -> Deferred> + func wipeTabs() -> Deferred> + func getClientGUIDs() -> Deferred>> + func getClients() -> Deferred> + func getClient(guid: GUID) -> Deferred> + func getClient(fxaDeviceId: String) -> Deferred> + @available(*, deprecated, message: "use getClient(guid:) instead") + func getClientWithId(_ clientID: GUID) -> Deferred> + func getClientsAndTabs() -> Deferred> + func getTabsForClientWithGUID(_ guid: GUID?) -> Deferred> + func insertOrUpdateClient(_ client: RemoteClient) -> Deferred> + func insertOrUpdateClients(_ clients: [RemoteClient]) -> Deferred> + + // Returns number of tabs inserted. + func insertOrUpdateTabs(_ tabs: [RemoteTab]) -> Deferred> // Insert into the local client. + func insertOrUpdateTabsForClientGUID(_ clientGUID: String?, tabs: [RemoteTab]) -> Deferred> + + func deleteClient(guid: GUID) -> Success +} + +public struct RemoteTab: Equatable { + public let clientGUID: String? + public let URL: Foundation.URL + public let title: String + public let history: [Foundation.URL] + public let lastUsed: Timestamp + public let icon: Foundation.URL? + + public static func shouldIncludeURL(_ url: Foundation.URL) -> Bool { + let scheme = url.scheme + if scheme == "about" { + return false + } + if scheme == "javascript" { + return false + } + + if let hostname = url.host?.lowercased() { + if hostname == "localhost" { + return false + } + return true + } + return false + } + + public init(clientGUID: String?, URL: Foundation.URL, title: String, history: [Foundation.URL], lastUsed: Timestamp, icon: Foundation.URL?) { + self.clientGUID = clientGUID + self.URL = URL + self.title = title + self.history = history + self.lastUsed = lastUsed + self.icon = icon + } + + public func withClientGUID(_ clientGUID: String?) -> RemoteTab { + return RemoteTab(clientGUID: clientGUID, URL: URL, title: title, history: history, lastUsed: lastUsed, icon: icon) + } +} + +public func ==(lhs: RemoteTab, rhs: RemoteTab) -> Bool { + return lhs.clientGUID == rhs.clientGUID && + lhs.URL == rhs.URL && + lhs.title == rhs.title && + lhs.history == rhs.history && + lhs.lastUsed == rhs.lastUsed && + lhs.icon == rhs.icon +} + +extension RemoteTab: CustomStringConvertible { + public var description: String { + return "" + } +} diff --git a/mobile/ios/Storage/SQL/BrowserDB.swift b/mobile/ios/Storage/SQL/BrowserDB.swift new file mode 100644 index 0000000000..0a4f29d901 --- /dev/null +++ b/mobile/ios/Storage/SQL/BrowserDB.swift @@ -0,0 +1,226 @@ +/* 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/. */ + +import Foundation +import XCGLogger +import Deferred +import Shared + +public let NotificationDatabaseWasRecreated = Notification.Name("NotificationDatabaseWasRecreated") + +private let log = Logger.syncLogger + +public typealias Args = [Any?] + +open class BrowserDB { + fileprivate let db: SwiftData + + // SQLITE_MAX_VARIABLE_NUMBER = 999 by default. This controls how many ?s can + // appear in a query string. + open static let MaxVariableNumber = 999 + + public init(filename: String, secretKey: String? = nil, schema: Schema, files: FileAccessor) { + log.debug("Initializing BrowserDB: \(filename).") + + let file = URL(fileURLWithPath: (try! files.getAndEnsureDirectory())).appendingPathComponent(filename).path + + if AppConstants.BuildChannel == .developer && secretKey != nil { + log.debug("Will attempt to use encrypted DB: \(file) with secret = \(secretKey ?? "nil")") + } + + self.db = SwiftData(filename: file, key: secretKey, prevKey: nil, schema: schema, files: files) + } + + // Remove the DB op from the queue (by marking it cancelled), and if it is already running tell sqlite to cancel it. + // At any point the operation could complete on another thread, so it is held weakly. + // Swift compiler bug: failing to compile WeakRef here. + public func cancel(databaseOperation: WeakRef) { + weak var databaseOperation = databaseOperation.value as? Cancellable + + db.suspendQueue() + defer { + db.resumeQueue() + } + + databaseOperation?.cancel() + if databaseOperation?.running ?? false { + db.cancel() + } + } + + // For testing purposes or other cases where we want to ensure that this `BrowserDB` + // instance has been initialized (schema is created/updated). + public func touch() -> Success { + return withConnection { connection -> Void in + guard let _ = connection as? ConcreteSQLiteDBConnection else { + throw DatabaseError(description: "Could not establish a database connection") + } + } + } + + /* + * Opening a WAL-using database with a hot journal cannot complete in read-only mode. + * The supported mechanism for a read-only query against a WAL-using SQLite database is to use PRAGMA query_only, + * but this isn't all that useful for us, because we have a mixed read/write workload. + */ + @discardableResult func withConnection(flags: SwiftData.Flags = .readWriteCreate, _ callback: @escaping (_ connection: SQLiteDBConnection) throws -> T) -> Deferred> { + return db.withConnection(flags, callback) + } + + func transaction(_ callback: @escaping (_ connection: SQLiteDBConnection) throws -> T) -> Deferred> { + return db.transaction(callback) + } + + @discardableResult func vacuum() -> Success { + log.debug("Vacuuming a BrowserDB.") + + return withConnection({ connection -> Void in + try connection.vacuum() + }) + } + + @discardableResult func checkpoint() -> Success { + log.debug("Checkpointing a BrowserDB.") + + return transaction { connection in + connection.checkpoint() + } + } + + public class func varlist(_ count: Int) -> String { + return "(" + Array(repeating: "?", count: count).joined(separator: ", ") + ")" + } + + enum InsertOperation: String { + case Insert = "INSERT" + case Replace = "REPLACE" + case InsertOrIgnore = "INSERT OR IGNORE" + case InsertOrReplace = "INSERT OR REPLACE" + case InsertOrRollback = "INSERT OR ROLLBACK" + case InsertOrAbort = "INSERT OR ABORT" + case InsertOrFail = "INSERT OR FAIL" + } + + /** + * Insert multiple sets of values into the given table. + * + * Assumptions: + * 1. The table exists and contains the provided columns. + * 2. Every item in `values` is the same length. + * 3. That length is the same as the length of `columns`. + * 4. Every value in each element of `values` is non-nil. + * + * If there are too many items to insert, multiple individual queries will run + * in sequence. + * + * A failure anywhere in the sequence will cause immediate return of failure, but + * will not roll back — use a transaction if you need one. + */ + func bulkInsert(_ table: String, op: InsertOperation, columns: [String], values: [Args]) -> Success { + // Note that there's a limit to how many ?s can be in a single query! + // So here we execute 999 / (columns * rows) insertions per query. + // Note that we can't use variables for the column names, so those don't affect the count. + if values.isEmpty { + log.debug("No values to insert.") + return succeed() + } + + let variablesPerRow = columns.count + + // Sanity check. + assert(values[0].count == variablesPerRow) + + let cols = columns.joined(separator: ", ") + let queryStart = "\(op.rawValue) INTO \(table) (\(cols)) VALUES " + + let varString = BrowserDB.varlist(variablesPerRow) + + let insertChunk: ([Args]) -> Success = { vals -> Success in + let valuesString = Array(repeating: varString, count: vals.count).joined(separator: ", ") + let args: Args = vals.flatMap { $0 } + return self.run(queryStart + valuesString, withArgs: args) + } + + let rowCount = values.count + if (variablesPerRow * rowCount) < BrowserDB.MaxVariableNumber { + return insertChunk(values) + } + + log.debug("Splitting bulk insert across multiple runs. I hope you started a transaction!") + let rowsPerInsert = (999 / variablesPerRow) + let chunks = chunk(values, by: rowsPerInsert) + log.debug("Inserting in \(chunks.count) chunks.") + + // There's no real reason why we can't pass the ArraySlice here, except that I don't + // want to keep fighting Swift. + return walk(chunks, f: { insertChunk(Array($0)) }) + } + + func write(_ sql: String, withArgs args: Args? = nil) -> Deferred> { + return withConnection { connection -> Int in + try connection.executeChange(sql, withArgs: args) + + let modified = connection.numberOfRowsModified + log.debug("Modified rows: \(modified).") + return modified + } + } + + public func forceClose() { + db.forceClose() + } + + public func reopenIfClosed() { + db.reopenIfClosed() + } + + func run(_ sql: String, withArgs args: Args? = nil) -> Success { + return run([(sql, args)]) + } + + func run(_ commands: [String]) -> Success { + return run(commands.map { (sql: $0, args: nil) }) + } + + /** + * Runs an array of SQL commands. Note: These will all run in order in a transaction and will block + * the caller's thread until they've finished. If any of them fail the operation will abort (no more + * commands will be run) and the transaction will roll back, returning a DatabaseError. + */ + func run(_ commands: [(sql: String, args: Args?)]) -> Success { + if commands.isEmpty { + return succeed() + } + + return transaction { connection -> Void in + for (sql, args) in commands { + try connection.executeChange(sql, withArgs: args) + } + } + } + + func runQuery(_ sql: String, args: Args?, factory: @escaping (SDRow) -> T) -> Deferred>> { + return withConnection { connection -> Cursor in + connection.executeQuery(sql, factory: factory, withArgs: args) + } + } + + func runQueryUnsafe(_ sql: String, args: Args?, factory: @escaping (SDRow) -> T, block: @escaping (Cursor) throws -> U) -> Deferred> { + return withConnection { connection -> U in + let cursor = connection.executeQueryUnsafe(sql, factory: factory, withArgs: args) + defer { cursor.close() } + return try block(cursor) + } + } + + func queryReturnsResults(_ sql: String, args: Args? = nil) -> Deferred> { + return runQuery(sql, args: args, factory: { _ in true }) + >>== { deferMaybe($0[0] ?? false) } + } + + func queryReturnsNoResults(_ sql: String, args: Args? = nil) -> Deferred> { + return runQuery(sql, args: nil, factory: { _ in false }) + >>== { deferMaybe($0[0] ?? true) } + } +} diff --git a/mobile/ios/Storage/SQL/BrowserSchema.swift b/mobile/ios/Storage/SQL/BrowserSchema.swift new file mode 100644 index 0000000000..976c488072 --- /dev/null +++ b/mobile/ios/Storage/SQL/BrowserSchema.swift @@ -0,0 +1,1379 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger + +let BookmarksFolderTitleMobile: String = NSLocalizedString("Mobile Bookmarks", tableName: "Storage", comment: "The title of the folder that contains mobile bookmarks. This should match bookmarks.folder.mobile.label on Android.") +let BookmarksFolderTitleMenu: String = NSLocalizedString("Bookmarks Menu", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the menu. This should match bookmarks.folder.menu.label on Android.") +let BookmarksFolderTitleToolbar: String = NSLocalizedString("Bookmarks Toolbar", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the toolbar. This should match bookmarks.folder.toolbar.label on Android.") +let BookmarksFolderTitleUnsorted: String = NSLocalizedString("Unsorted Bookmarks", tableName: "Storage", comment: "The name of the folder that contains unsorted desktop bookmarks. This should match bookmarks.folder.unfiled.label on Android.") + +let _TableBookmarks = "bookmarks" // Removed in v12. Kept for migration. +let TableBookmarksMirror = "bookmarksMirror" // Added in v9. +let TableBookmarksMirrorStructure = "bookmarksMirrorStructure" // Added in v10. + +let TableBookmarksBuffer = "bookmarksBuffer" // Added in v12. bookmarksMirror is renamed to bookmarksBuffer. +let TableBookmarksBufferStructure = "bookmarksBufferStructure" // Added in v12. +let TableBookmarksLocal = "bookmarksLocal" // Added in v12. Supersedes 'bookmarks'. +let TableBookmarksLocalStructure = "bookmarksLocalStructure" // Added in v12. + +let TablePendingBookmarksDeletions = "pending_deletions" // Added in v28. + +let TableFavicons = "favicons" +let TableHistory = "history" +let TableCachedTopSites = "cached_top_sites" +let TablePinnedTopSites = "pinned_top_sites" +let TableDomains = "domains" +let TableVisits = "visits" +let TableFaviconSites = "favicon_sites" +let TableQueuedTabs = "queue" +let TableSyncCommands = "commands" +let TableClients = "clients" +let TableTabs = "tabs" + +let TableActivityStreamBlocklist = "activity_stream_blocklist" +let TablePageMetadata = "page_metadata" +let TableHighlights = "highlights" + +let TableRemoteDevices = "remote_devices" // Added in v29. + +let ViewBookmarksBufferOnMirror = "view_bookmarksBuffer_on_mirror" +let ViewBookmarksBufferWithDeletionsOnMirror = "view_bookmarksBuffer_with_deletions_on_mirror" +let ViewBookmarksBufferStructureOnMirror = "view_bookmarksBufferStructure_on_mirror" +let ViewBookmarksLocalOnMirror = "view_bookmarksLocal_on_mirror" +let ViewBookmarksLocalStructureOnMirror = "view_bookmarksLocalStructure_on_mirror" +let ViewAllBookmarks = "view_all_bookmarks" +let ViewAwesomebarBookmarks = "view_awesomebar_bookmarks" +let TempTableAwesomebarBookmarks = "awesomebar_bookmarks_temp_table" +let ViewAwesomebarBookmarksWithIcons = "view_awesomebar_bookmarks_with_favicons" + +let ViewHistoryVisits = "view_history_visits" +let ViewWidestFaviconsForSites = "view_favicons_widest" +let ViewHistoryIDsWithWidestFavicons = "view_history_id_favicon" +let ViewIconForURL = "view_icon_for_url" + +let IndexHistoryShouldUpload = "idx_history_should_upload" +let IndexVisitsSiteIDDate = "idx_visits_siteID_date" // Removed in v6. +let IndexVisitsSiteIDIsLocalDate = "idx_visits_siteID_is_local_date" // Added in v6. +let IndexBookmarksMirrorStructureParentIdx = "idx_bookmarksMirrorStructure_parent_idx" // Added in v10. +let IndexBookmarksLocalStructureParentIdx = "idx_bookmarksLocalStructure_parent_idx" // Added in v12. +let IndexBookmarksBufferStructureParentIdx = "idx_bookmarksBufferStructure_parent_idx" // Added in v12. +let IndexBookmarksMirrorStructureChild = "idx_bookmarksMirrorStructure_child" // Added in v14. +let IndexPageMetadataCacheKey = "idx_page_metadata_cache_key_uniqueindex" // Added in v19 +let IndexPageMetadataSiteURL = "idx_page_metadata_site_url_uniqueindex" // Added in v21 + +private let AllTables: [String] = [ + TableDomains, + TableFavicons, + TableFaviconSites, + + TableHistory, + TableVisits, + TableCachedTopSites, + + TableBookmarksBuffer, + TableBookmarksBufferStructure, + TableBookmarksLocal, + TableBookmarksLocalStructure, + TableBookmarksMirror, + TableBookmarksMirrorStructure, + TablePendingBookmarksDeletions, + TableQueuedTabs, + + TableActivityStreamBlocklist, + TablePageMetadata, + TableHighlights, + TablePinnedTopSites, + TableRemoteDevices, + + TableSyncCommands, + TableClients, + TableTabs, +] + +private let AllViews: [String] = [ + ViewHistoryIDsWithWidestFavicons, + ViewWidestFaviconsForSites, + ViewIconForURL, + ViewBookmarksBufferOnMirror, + ViewBookmarksBufferWithDeletionsOnMirror, + ViewBookmarksBufferStructureOnMirror, + ViewBookmarksLocalOnMirror, + ViewBookmarksLocalStructureOnMirror, + ViewAllBookmarks, + ViewAwesomebarBookmarks, + ViewAwesomebarBookmarksWithIcons, + ViewHistoryVisits, +] + +private let AllIndices: [String] = [ + IndexHistoryShouldUpload, + IndexVisitsSiteIDIsLocalDate, + IndexBookmarksBufferStructureParentIdx, + IndexBookmarksLocalStructureParentIdx, + IndexBookmarksMirrorStructureParentIdx, + IndexBookmarksMirrorStructureChild, + IndexPageMetadataCacheKey, + IndexPageMetadataSiteURL, +] + +private let AllTablesIndicesAndViews: [String] = AllViews + AllIndices + AllTables + +private let log = Logger.syncLogger + +/** + * The monolithic class that manages the inter-related history etc. tables. + * We rely on SQLiteHistory having initialized the favicon table first. + */ +open class BrowserSchema: Schema { + static let DefaultVersion = 34 // Bug 1409777. + + public var name: String { return "BROWSER" } + public var version: Int { return BrowserSchema.DefaultVersion } + + let sqliteVersion: Int32 + let supportsPartialIndices: Bool + + public init() { + let v = sqlite3_libversion_number() + self.sqliteVersion = v + self.supportsPartialIndices = v >= 3008000 // 3.8.0. + let ver = String(cString: sqlite3_libversion()) + log.info("SQLite version: \(ver) (\(v)).") + } + + func run(_ db: SQLiteDBConnection, sql: String, args: Args? = nil) -> Bool { + do { + try db.executeChange(sql, withArgs: args) + } catch let err as NSError { + log.error("Error running SQL in BrowserSchema: \(err.localizedDescription)") + log.error("SQL was \(sql)") + return false + } + + return true + } + + // TODO: transaction. + func run(_ db: SQLiteDBConnection, queries: [(String, Args?)]) -> Bool { + for (sql, args) in queries { + if !run(db, sql: sql, args: args) { + return false + } + } + return true + } + + func run(_ db: SQLiteDBConnection, queries: [String]) -> Bool { + for sql in queries { + if !run(db, sql: sql) { + return false + } + } + return true + } + + func runValidQueries(_ db: SQLiteDBConnection, queries: [(String?, Args?)]) -> Bool { + for (sql, args) in queries { + if let sql = sql { + if !run(db, sql: sql, args: args) { + return false + } + } + } + return true + } + + func runValidQueries(_ db: SQLiteDBConnection, queries: [String?]) -> Bool { + return self.run(db, queries: optFilter(queries)) + } + + func prepopulateRootFolders(_ db: SQLiteDBConnection) -> Bool { + let type = BookmarkNodeType.folder.rawValue + let now = Date.nowNumber() + let status = SyncStatus.new.rawValue + + let localArgs: Args = [ + BookmarkRoots.RootID, BookmarkRoots.RootGUID, type, now, BookmarkRoots.RootGUID, status, now, + BookmarkRoots.MobileID, BookmarkRoots.MobileFolderGUID, type, now, BookmarkRoots.RootGUID, status, now, + BookmarkRoots.MenuID, BookmarkRoots.MenuFolderGUID, type, now, BookmarkRoots.RootGUID, status, now, + BookmarkRoots.ToolbarID, BookmarkRoots.ToolbarFolderGUID, type, now, BookmarkRoots.RootGUID, status, now, + BookmarkRoots.UnfiledID, BookmarkRoots.UnfiledFolderGUID, type, now, BookmarkRoots.RootGUID, status, now, + ] + + // Compute these args using the sequence in RootChildren, rather than hard-coding. + var idx = 0 + var structureArgs = Args() + structureArgs.reserveCapacity(BookmarkRoots.RootChildren.count * 3) + BookmarkRoots.RootChildren.forEach { guid in + structureArgs.append(BookmarkRoots.RootGUID) + structureArgs.append(guid) + structureArgs.append(idx) + idx += 1 + } + + // Note that we specify an empty title and parentName for these records. We should + // never need a parentName -- we don't use content-based reconciling or + // reparent these -- and we'll use the current locale's string, retrieved + // via titleForSpecialGUID, if necessary. + + let local = + "INSERT INTO \(TableBookmarksLocal) " + + "(id, guid, type, date_added, parentid, title, parentName, sync_status, local_modified) VALUES " + + Array(repeating: "(?, ?, ?, ?, ?, '', '', ?, ?)", count: BookmarkRoots.RootChildren.count + 1).joined(separator: ", ") + + let structure = + "INSERT INTO \(TableBookmarksLocalStructure) (parent, child, idx) VALUES " + + Array(repeating: "(?, ?, ?)", count: BookmarkRoots.RootChildren.count).joined(separator: ", ") + + return self.run(db, queries: [(local, localArgs), (structure, structureArgs)]) + } + + let topSitesTableCreate = + "CREATE TABLE IF NOT EXISTS \(TableCachedTopSites) (" + + "historyID INTEGER, " + + "url TEXT NOT NULL, " + + "title TEXT NOT NULL, " + + "guid TEXT NOT NULL UNIQUE, " + + "domain_id INTEGER, " + + "domain TEXT NO NULL, " + + "localVisitDate REAL, " + + "remoteVisitDate REAL, " + + "localVisitCount INTEGER, " + + "remoteVisitCount INTEGER, " + + "iconID INTEGER, " + + "iconURL TEXT, " + + "iconDate REAL, " + + "iconType INTEGER, " + + "iconWidth INTEGER, " + + "frecencies REAL" + + ")" + + let pinnedTopSitesTableCreate = + "CREATE TABLE IF NOT EXISTS \(TablePinnedTopSites) (" + + "historyID INTEGER, " + + "url TEXT NOT NULL UNIQUE, " + + "title TEXT, " + + "guid TEXT, " + + "pinDate REAL, " + + "domain TEXT NOT NULL " + + ")" + + let domainsTableCreate = + "CREATE TABLE IF NOT EXISTS \(TableDomains) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "domain TEXT NOT NULL UNIQUE, " + + "showOnTopSites TINYINT NOT NULL DEFAULT 1" + + ")" + + let queueTableCreate = + "CREATE TABLE IF NOT EXISTS \(TableQueuedTabs) (" + + "url TEXT NOT NULL UNIQUE, " + + "title TEXT" + + ") " + + let syncCommandsTableCreate = + "CREATE TABLE IF NOT EXISTS \(TableSyncCommands) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "client_guid TEXT NOT NULL, " + + "value TEXT NOT NULL" + + ")" + + let clientsTableCreate = + "CREATE TABLE IF NOT EXISTS \(TableClients) (" + + "guid TEXT PRIMARY KEY, " + + "name TEXT NOT NULL, " + + "modified INTEGER NOT NULL, " + + "type TEXT, " + + "formfactor TEXT, " + + "os TEXT, " + + "version TEXT, " + + "fxaDeviceId TEXT" + + ")" + + let tabsTableCreate = + "CREATE TABLE IF NOT EXISTS \(TableTabs) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "client_guid TEXT REFERENCES clients(guid) ON DELETE CASCADE, " + + "url TEXT NOT NULL, " + + "title TEXT, " + + "history TEXT, " + + "last_used INTEGER" + + ")" + + let activityStreamBlocklistCreate = + "CREATE TABLE IF NOT EXISTS \(TableActivityStreamBlocklist) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "url TEXT NOT NULL UNIQUE, " + + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP " + + ") " + + let pageMetadataCreate = + "CREATE TABLE IF NOT EXISTS \(TablePageMetadata) (" + + "id INTEGER PRIMARY KEY, " + + "cache_key LONGVARCHAR UNIQUE, " + + "site_url TEXT, " + + "media_url LONGVARCHAR, " + + "title TEXT, " + + "type VARCHAR(32), " + + "description TEXT, " + + "provider_name TEXT, " + + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " + + "expired_at LONG" + + ") " + + let highlightsCreate = + "CREATE TABLE IF NOT EXISTS \(TableHighlights) (" + + "historyID INTEGER PRIMARY KEY," + + "cache_key LONGVARCHAR," + + "url TEXT," + + "title TEXT," + + "guid TEXT," + + "visitCount INTEGER," + + "visitDate DATETIME," + + "is_bookmarked INTEGER" + + ") " + + let indexPageMetadataCacheKeyCreate = + "CREATE UNIQUE INDEX IF NOT EXISTS \(IndexPageMetadataCacheKey) ON page_metadata (cache_key)" + + let indexPageMetadataSiteURLCreate = + "CREATE UNIQUE INDEX IF NOT EXISTS \(IndexPageMetadataSiteURL) ON page_metadata (site_url)" + + let iconColumns = ", faviconID INTEGER REFERENCES \(TableFavicons)(id) ON DELETE SET NULL" + let mirrorColumns = ", is_overridden TINYINT NOT NULL DEFAULT 0" + + let serverColumns = ", server_modified INTEGER NOT NULL" + // Milliseconds. + ", hasDupe TINYINT NOT NULL DEFAULT 0" // Boolean, 0 (false) if deleted. + + let localColumns = ", local_modified INTEGER" + // Can be null. Client clock. In extremis only. + ", sync_status TINYINT NOT NULL" // SyncStatus enum. Set when changed or created. + + func getBookmarksTableCreationStringForTable(_ table: String, withAdditionalColumns: String="") -> String { + // The stupid absence of naming conventions here is thanks to pre-Sync Weave. Sorry. + // For now we have the simplest possible schema: everything in one. + let sql = + "CREATE TABLE IF NOT EXISTS \(table) " + + + // Shared fields. + "( id INTEGER PRIMARY KEY AUTOINCREMENT" + + ", guid TEXT NOT NULL UNIQUE" + + ", type TINYINT NOT NULL" + // Type enum. + ", date_added INTEGER" + + + // Record/envelope metadata that'll allow us to do merges. + ", is_deleted TINYINT NOT NULL DEFAULT 0" + // Boolean + + ", parentid TEXT" + // GUID + ", parentName TEXT" + + + // Type-specific fields. These should be NOT NULL in many cases, but we're going + // for a sparse schema, so this'll do for now. Enforce these in the application code. + ", feedUri TEXT, siteUri TEXT" + // LIVEMARKS + ", pos INT" + // SEPARATORS + ", title TEXT, description TEXT" + // FOLDERS, BOOKMARKS, QUERIES + ", bmkUri TEXT, tags TEXT, keyword TEXT" + // BOOKMARKS, QUERIES + ", folderName TEXT, queryId TEXT" + // QUERIES + withAdditionalColumns + + ", CONSTRAINT parentidOrDeleted CHECK (parentid IS NOT NULL OR is_deleted = 1)" + + ", CONSTRAINT parentNameOrDeleted CHECK (parentName IS NOT NULL OR is_deleted = 1)" + + ")" + + return sql + } + + /** + * We need to explicitly store what's provided by the server, because we can't rely on + * referenced child nodes to exist yet! + */ + func getBookmarksStructureTableCreationStringForTable(_ table: String, referencingMirror mirror: String) -> String { + let sql = + "CREATE TABLE IF NOT EXISTS \(table) " + + "( parent TEXT NOT NULL REFERENCES \(mirror)(guid) ON DELETE CASCADE" + + ", child TEXT NOT NULL" + // Should be the GUID of a child. + ", idx INTEGER NOT NULL" + // Should advance from 0. + ")" + + return sql + } + + fileprivate let bufferBookmarksView = + "CREATE VIEW \(ViewBookmarksBufferOnMirror) AS " + + "SELECT" + + " -1 AS id" + + ", mirror.guid AS guid" + + ", mirror.type AS type" + + ", mirror.date_added AS date_added" + + ", mirror.is_deleted AS is_deleted" + + ", mirror.parentid AS parentid" + + ", mirror.parentName AS parentName" + + ", mirror.feedUri AS feedUri" + + ", mirror.siteUri AS siteUri" + + ", mirror.pos AS pos" + + ", mirror.title AS title" + + ", mirror.description AS description" + + ", mirror.bmkUri AS bmkUri" + + ", mirror.keyword AS keyword" + + ", mirror.folderName AS folderName" + + ", null AS faviconID" + + ", 0 AS is_overridden" + + + // LEFT EXCLUDING JOIN to get mirror records that aren't in the buffer. + // We don't have an is_overridden flag to help us here. + " FROM \(TableBookmarksMirror) mirror LEFT JOIN" + + " \(TableBookmarksBuffer) buffer ON mirror.guid = buffer.guid" + + " WHERE buffer.guid IS NULL" + + " UNION ALL " + + "SELECT" + + " -1 AS id" + + ", guid" + + ", type" + + ", date_added" + + ", is_deleted" + + ", parentid" + + ", parentName" + + ", feedUri" + + ", siteUri" + + ", pos" + + ", title" + + ", description" + + ", bmkUri" + + ", keyword" + + ", folderName" + + ", null AS faviconID" + + ", 1 AS is_overridden" + + " FROM \(TableBookmarksBuffer) WHERE is_deleted IS 0" + + fileprivate let bufferBookmarksWithDeletionsView = + "CREATE VIEW \(ViewBookmarksBufferWithDeletionsOnMirror) AS " + + "SELECT" + + " -1 AS id" + + ", mirror.guid AS guid" + + ", mirror.type AS type" + + ", mirror.date_added AS date_added" + + ", mirror.is_deleted AS is_deleted" + + ", mirror.parentid AS parentid" + + ", mirror.parentName AS parentName" + + ", mirror.feedUri AS feedUri" + + ", mirror.siteUri AS siteUri" + + ", mirror.pos AS pos" + + ", mirror.title AS title" + + ", mirror.description AS description" + + ", mirror.bmkUri AS bmkUri" + + ", mirror.keyword AS keyword" + + ", mirror.folderName AS folderName" + + ", null AS faviconID" + + ", 0 AS is_overridden" + + + // LEFT EXCLUDING JOIN to get mirror records that aren't in the buffer. + // We don't have an is_overridden flag to help us here. + " FROM \(TableBookmarksMirror) mirror LEFT JOIN" + + " \(TableBookmarksBuffer) buffer ON mirror.guid = buffer.guid" + + " WHERE buffer.guid IS NULL" + + " UNION ALL " + + "SELECT" + + " -1 AS id" + + ", guid" + + ", type" + + ", date_added" + + ", is_deleted" + + ", parentid" + + ", parentName" + + ", feedUri" + + ", siteUri" + + ", pos" + + ", title" + + ", description" + + ", bmkUri" + + ", keyword" + + ", folderName" + + ", null AS faviconID" + + ", 1 AS is_overridden" + + " FROM \(TableBookmarksBuffer) WHERE is_deleted IS 0" + + " AND NOT EXISTS (SELECT 1 FROM \(TablePendingBookmarksDeletions) deletions WHERE deletions.id = guid)" + + // TODO: phrase this without the subselect… + fileprivate let bufferBookmarksStructureView = + // We don't need to exclude deleted parents, because we drop those from the structure + // table when we see them. + "CREATE VIEW \(ViewBookmarksBufferStructureOnMirror) AS " + + "SELECT parent, child, idx, 1 AS is_overridden FROM \(TableBookmarksBufferStructure) " + + "UNION ALL " + + + // Exclude anything from the mirror that's present in the buffer -- dynamic is_overridden. + "SELECT parent, child, idx, 0 AS is_overridden FROM \(TableBookmarksMirrorStructure) " + + "LEFT JOIN \(TableBookmarksBuffer) ON parent = guid WHERE guid IS NULL" + + fileprivate let localBookmarksView = + "CREATE VIEW \(ViewBookmarksLocalOnMirror) AS " + + "SELECT -1 AS id, guid, type, date_added, is_deleted, parentid, parentName, feedUri," + + " siteUri, pos, title, description, bmkUri, folderName, faviconID, NULL AS local_modified, server_modified, 0 AS is_overridden " + + "FROM \(TableBookmarksMirror) WHERE is_overridden IS NOT 1 " + + "UNION ALL " + + "SELECT -1 AS id, guid, type, date_added, is_deleted, parentid, parentName, feedUri, siteUri, pos, title, description, bmkUri, folderName, faviconID," + + " local_modified, NULL AS server_modified, 1 AS is_overridden " + + "FROM \(TableBookmarksLocal) WHERE is_deleted IS NOT 1" + + // TODO: phrase this without the subselect… + fileprivate let localBookmarksStructureView = + "CREATE VIEW \(ViewBookmarksLocalStructureOnMirror) AS " + + "SELECT parent, child, idx, 1 AS is_overridden FROM \(TableBookmarksLocalStructure) " + + "WHERE " + + "((SELECT is_deleted FROM \(TableBookmarksLocal) WHERE guid = parent) IS NOT 1) " + + "UNION ALL " + + "SELECT parent, child, idx, 0 AS is_overridden FROM \(TableBookmarksMirrorStructure) " + + "WHERE " + + "((SELECT is_overridden FROM \(TableBookmarksMirror) WHERE guid = parent) IS NOT 1) " + + // This view exists only to allow for text searching of URLs and titles in the awesomebar. + // As such, we cheat a little: we include buffer, non-overridden mirror, and local. + // Usually this will be indistinguishable from a more sophisticated approach, and it's way + // easier. + fileprivate let allBookmarksView = + "CREATE VIEW \(ViewAllBookmarks) AS " + + "SELECT guid, bmkUri AS url, title, description, faviconID FROM " + + "\(TableBookmarksMirror) WHERE " + + "type = \(BookmarkNodeType.bookmark.rawValue) AND is_overridden IS 0 AND is_deleted IS 0 " + + "UNION ALL " + + "SELECT guid, bmkUri AS url, title, description, faviconID FROM " + + "\(TableBookmarksLocal) WHERE " + + "type = \(BookmarkNodeType.bookmark.rawValue) AND is_deleted IS 0 " + + "UNION ALL " + + "SELECT guid, bmkUri AS url, title, description, -1 AS faviconID FROM " + + "\(TableBookmarksBuffer) bb WHERE " + + "bb.type = \(BookmarkNodeType.bookmark.rawValue) AND bb.is_deleted IS 0 " + + + // Exclude pending bookmark deletions. + "AND NOT EXISTS (SELECT 1 FROM \(TablePendingBookmarksDeletions) AS pd WHERE pd.id = bb.guid)" + + // This exists only to allow upgrade from old versions. We have view dependencies, so + // we can't simply skip creating ViewAllBookmarks. Here's a stub. + fileprivate let oldAllBookmarksView = + "CREATE VIEW \(ViewAllBookmarks) AS " + + "SELECT guid, bmkUri AS url, title, description, faviconID FROM " + + "\(TableBookmarksMirror) WHERE " + + "type = \(BookmarkNodeType.bookmark.rawValue) AND is_overridden IS 0 AND is_deleted IS 0" + + // This smushes together remote and local visits. So it goes. + fileprivate let historyVisitsView = + "CREATE VIEW \(ViewHistoryVisits) AS " + + "SELECT h.url AS url, MAX(v.date) AS visitDate, h.domain_id AS domain_id FROM " + + "\(TableHistory) h JOIN \(TableVisits) v ON v.siteID = h.id " + + "GROUP BY h.id" + + // Join all bookmarks against history to find the most recent visit. + // visits. + fileprivate let awesomebarBookmarksView = + "CREATE VIEW \(ViewAwesomebarBookmarks) AS " + + "SELECT b.guid AS guid, b.url AS url, b.title AS title, " + + "b.description AS description, b.faviconID AS faviconID, " + + "h.visitDate AS visitDate " + + "FROM \(ViewAllBookmarks) b " + + "LEFT JOIN " + + "\(ViewHistoryVisits) h ON b.url = h.url" + + fileprivate let awesomebarBookmarksWithIconsView = + "CREATE VIEW \(ViewAwesomebarBookmarksWithIcons) AS " + + "SELECT b.guid AS guid, b.url AS url, b.title AS title, " + + "b.description AS description, b.visitDate AS visitDate, " + + "f.id AS iconID, f.url AS iconURL, f.date AS iconDate, " + + "f.type AS iconType, f.width AS iconWidth " + + "FROM \(ViewAwesomebarBookmarks) b " + + "LEFT JOIN " + + "\(TableFavicons) f ON f.id = b.faviconID" + + fileprivate let pendingBookmarksDeletions = + "CREATE TABLE IF NOT EXISTS \(TablePendingBookmarksDeletions) (" + + "id TEXT PRIMARY KEY REFERENCES \(TableBookmarksBuffer)(guid) ON DELETE CASCADE" + + ")" + + fileprivate let remoteDevices = + "CREATE TABLE IF NOT EXISTS \(TableRemoteDevices) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT UNIQUE NOT NULL, " + + "name TEXT NOT NULL, " + + "type TEXT NOT NULL, " + + "is_current_device INTEGER NOT NULL, " + + "date_created INTEGER NOT NULL, " + // Timestamps in ms. + "date_modified INTEGER NOT NULL, " + + "last_access_time INTEGER" + + ")" + + public func create(_ db: SQLiteDBConnection) -> Bool { + let favicons = + "CREATE TABLE IF NOT EXISTS \(TableFavicons) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "url TEXT NOT NULL UNIQUE, " + + "width INTEGER, " + + "height INTEGER, " + + "type INTEGER NOT NULL, " + + "date REAL NOT NULL" + + ") " + + let history = + "CREATE TABLE IF NOT EXISTS \(TableHistory) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + // Not null, but the value might be replaced by the server's. + "url TEXT UNIQUE, " + // May only be null for deleted records. + "title TEXT NOT NULL, " + + "server_modified INTEGER, " + // Can be null. Integer milliseconds. + "local_modified INTEGER, " + // Can be null. Client clock. In extremis only. + "is_deleted TINYINT NOT NULL, " + // Boolean. Locally deleted. + "should_upload TINYINT NOT NULL, " + // Boolean. Set when changed or visits added. + "domain_id INTEGER REFERENCES \(TableDomains)(id) ON DELETE CASCADE, " + + "CONSTRAINT urlOrDeleted CHECK (url IS NOT NULL OR is_deleted = 1)" + + ")" + + // Right now we don't need to track per-visit deletions: Sync can't + // represent them! See Bug 1157553 Comment 6. + // We flip the should_upload flag on the history item when we add a visit. + // If we ever want to support logic like not bothering to sync if we added + // and then rapidly removed a visit, then we need an 'is_new' flag on each visit. + let visits = + "CREATE TABLE IF NOT EXISTS \(TableVisits) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES \(TableHistory)(id) ON DELETE CASCADE, " + + "date REAL NOT NULL, " + // Microseconds since epoch. + "type INTEGER NOT NULL, " + + "is_local TINYINT NOT NULL, " + // Some visits are local. Some are remote ('mirrored'). This boolean flag is the split. + "UNIQUE (siteID, date, type) " + + ") " + + let indexShouldUpload: String + if self.supportsPartialIndices { + // There's no point tracking rows that are not flagged for upload. + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON \(TableHistory) (should_upload) WHERE should_upload = 1" + } else { + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON \(TableHistory) (should_upload)" + } + + let indexSiteIDDate = + "CREATE INDEX IF NOT EXISTS \(IndexVisitsSiteIDIsLocalDate) " + + "ON \(TableVisits) (siteID, is_local, date)" + + let faviconSites = + "CREATE TABLE IF NOT EXISTS \(TableFaviconSites) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES \(TableHistory)(id) ON DELETE CASCADE, " + + "faviconID INTEGER NOT NULL REFERENCES \(TableFavicons)(id) ON DELETE CASCADE, " + + "UNIQUE (siteID, faviconID) " + + ") " + + let widestFavicons = + "CREATE VIEW IF NOT EXISTS \(ViewWidestFaviconsForSites) AS " + + "SELECT " + + "\(TableFaviconSites).siteID AS siteID, " + + "\(TableFavicons).id AS iconID, " + + "\(TableFavicons).url AS iconURL, " + + "\(TableFavicons).date AS iconDate, " + + "\(TableFavicons).type AS iconType, " + + "MAX(\(TableFavicons).width) AS iconWidth " + + "FROM \(TableFaviconSites), \(TableFavicons) WHERE " + + "\(TableFaviconSites).faviconID = \(TableFavicons).id " + + "GROUP BY siteID " + + let historyIDsWithIcon = + "CREATE VIEW IF NOT EXISTS \(ViewHistoryIDsWithWidestFavicons) AS " + + "SELECT \(TableHistory).id AS id, " + + "iconID, iconURL, iconDate, iconType, iconWidth " + + "FROM \(TableHistory) " + + "LEFT OUTER JOIN " + + "\(ViewWidestFaviconsForSites) ON history.id = \(ViewWidestFaviconsForSites).siteID " + + let iconForURL = + "CREATE VIEW IF NOT EXISTS \(ViewIconForURL) AS " + + "SELECT history.url AS url, icons.iconID AS iconID FROM " + + "\(TableHistory), \(ViewWidestFaviconsForSites) AS icons WHERE " + + "\(TableHistory).id = icons.siteID " + + // Locally we track faviconID. + // Local changes end up in the mirror, so we track it there too. + // The buffer and the mirror additionally track some server metadata. + let bookmarksLocal = getBookmarksTableCreationStringForTable(TableBookmarksLocal, withAdditionalColumns: self.localColumns + self.iconColumns) + let bookmarksLocalStructure = getBookmarksStructureTableCreationStringForTable(TableBookmarksLocalStructure, referencingMirror: TableBookmarksLocal) + let bookmarksBuffer = getBookmarksTableCreationStringForTable(TableBookmarksBuffer, withAdditionalColumns: self.serverColumns) + let bookmarksBufferStructure = getBookmarksStructureTableCreationStringForTable(TableBookmarksBufferStructure, referencingMirror: TableBookmarksBuffer) + let bookmarksMirror = getBookmarksTableCreationStringForTable(TableBookmarksMirror, withAdditionalColumns: self.serverColumns + self.mirrorColumns + self.iconColumns) + let bookmarksMirrorStructure = getBookmarksStructureTableCreationStringForTable(TableBookmarksMirrorStructure, referencingMirror: TableBookmarksMirror) + + let indexLocalStructureParentIdx = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksLocalStructureParentIdx) " + + "ON \(TableBookmarksLocalStructure) (parent, idx)" + let indexBufferStructureParentIdx = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksBufferStructureParentIdx) " + + "ON \(TableBookmarksBufferStructure) (parent, idx)" + let indexMirrorStructureParentIdx = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksMirrorStructureParentIdx) " + + "ON \(TableBookmarksMirrorStructure) (parent, idx)" + let indexMirrorStructureChild = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksMirrorStructureChild) " + + "ON \(TableBookmarksMirrorStructure) (child)" + + let queries: [String] = [ + // Tables. + self.domainsTableCreate, + history, + favicons, + visits, + bookmarksBuffer, + bookmarksBufferStructure, + bookmarksLocal, + bookmarksLocalStructure, + bookmarksMirror, + bookmarksMirrorStructure, + self.pendingBookmarksDeletions, + faviconSites, + widestFavicons, + historyIDsWithIcon, + iconForURL, + pageMetadataCreate, + pinnedTopSitesTableCreate, + highlightsCreate, + self.remoteDevices, + activityStreamBlocklistCreate, + indexPageMetadataSiteURLCreate, + indexPageMetadataCacheKeyCreate, + self.queueTableCreate, + self.topSitesTableCreate, + syncCommandsTableCreate, + clientsTableCreate, + tabsTableCreate, + + // Indices. + indexBufferStructureParentIdx, + indexLocalStructureParentIdx, + indexMirrorStructureParentIdx, + indexMirrorStructureChild, + indexShouldUpload, + indexSiteIDDate, + + // Views. + self.localBookmarksView, + self.localBookmarksStructureView, + self.bufferBookmarksView, + self.bufferBookmarksWithDeletionsView, + self.bufferBookmarksStructureView, + allBookmarksView, + historyVisitsView, + awesomebarBookmarksView, + awesomebarBookmarksWithIconsView, + ] + + assert(queries.count == AllTablesIndicesAndViews.count, "Did you forget to add your table, index, or view to the list?") + + log.debug("Creating \(queries.count) tables, views, and indices.") + + return self.run(db, queries: queries) && + self.prepopulateRootFolders(db) + } + + public func update(_ db: SQLiteDBConnection, from: Int) -> Bool { + let to = self.version + if from == to { + log.debug("Skipping update from \(from) to \(to).") + return true + } + + if from == 0 { + + // If we're upgrading from `0`, it is likely that we have not yet switched + // from tracking the schema version using `tableList` to `PRAGMA user_version`. + // This will write the *previous* version number from `tableList` into + // `PRAGMA user_version` if necessary in addition to upgrading the schema of + // some of the old tables that were previously managed separately. + if self.migrateFromSchemaTableIfNeeded(db) { + let version = db.version + + // If the database is now properly reporting a `user_version`, it may + // still need to be upgraded further to get to the current version of + // the schema. So, let's simply call this `update()` function a second + // time to handle any remaining post-v31 migrations. + if version > 0 { + return self.update(db, from: version) + } + } + + // Otherwise, this is likely an upgrade from before Bug 1160399, so + // let's drop and re-create. + log.debug("Updating schema \(self.name) from zero. Assuming drop and recreate.") + return drop(db) && create(db) + } + + if from > to { + // This is likely an upgrade from before Bug 1160399. + log.debug("Downgrading browser tables. Assuming drop and recreate.") + return drop(db) && create(db) + } + + log.debug("Updating schema \(self.name) from \(from) to \(to).") + + if from < 4 && to >= 4 { + return drop(db) && create(db) + } + + if from < 5 && to >= 5 { + if !self.run(db, sql: self.queueTableCreate) { + return false + } + } + + if from < 6 && to >= 6 { + if !self.run(db, queries: [ + "DROP INDEX IF EXISTS \(IndexVisitsSiteIDDate)", + "CREATE INDEX IF NOT EXISTS \(IndexVisitsSiteIDIsLocalDate) ON \(TableVisits) (siteID, is_local, date)", + self.domainsTableCreate, + "ALTER TABLE \(TableHistory) ADD COLUMN domain_id INTEGER REFERENCES \(TableDomains)(id) ON DELETE CASCADE", + ]) { + return false + } + + let urls = db.executeQuery("SELECT DISTINCT url FROM \(TableHistory) WHERE url IS NOT NULL", + factory: { $0["url"] as! String }) + if !fillDomainNamesFromCursor(urls, db: db) { + return false + } + } + + if from < 8 && to == 8 { + // Nothing to do: we're just shifting the favicon table to be owned by this class. + return true + } + + if from < 9 && to >= 9 { + if !self.run(db, sql: getBookmarksTableCreationStringForTable(TableBookmarksMirror)) { + return false + } + } + + if from < 10 && to >= 10 { + if !self.run(db, sql: getBookmarksStructureTableCreationStringForTable(TableBookmarksMirrorStructure, referencingMirror: TableBookmarksMirror)) { + return false + } + + let indexStructureParentIdx = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksMirrorStructureParentIdx) " + + "ON \(TableBookmarksMirrorStructure) (parent, idx)" + if !self.run(db, sql: indexStructureParentIdx) { + return false + } + } + + if from < 11 && to >= 11 { + if !self.run(db, sql: self.topSitesTableCreate) { + return false + } + } + + if from < 12 && to >= 12 { + let bookmarksLocal = getBookmarksTableCreationStringForTable(TableBookmarksLocal, withAdditionalColumns: self.localColumns + self.iconColumns) + let bookmarksLocalStructure = getBookmarksStructureTableCreationStringForTable(TableBookmarksLocalStructure, referencingMirror: TableBookmarksLocal) + let bookmarksMirror = getBookmarksTableCreationStringForTable(TableBookmarksMirror, withAdditionalColumns: self.serverColumns + self.mirrorColumns + self.iconColumns) + let bookmarksMirrorStructure = getBookmarksStructureTableCreationStringForTable(TableBookmarksMirrorStructure, referencingMirror: TableBookmarksMirror) + + let indexLocalStructureParentIdx = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksLocalStructureParentIdx) " + + "ON \(TableBookmarksLocalStructure) (parent, idx)" + let indexBufferStructureParentIdx = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksBufferStructureParentIdx) " + + "ON \(TableBookmarksBufferStructure) (parent, idx)" + let indexMirrorStructureParentIdx = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksMirrorStructureParentIdx) " + + "ON \(TableBookmarksMirrorStructure) (parent, idx)" + + let prep = [ + // Drop indices. + "DROP INDEX IF EXISTS idx_bookmarksMirrorStructure_parent_idx", + + // Rename the old mirror tables to buffer. + // The v11 one is the same shape as the current buffer table. + "ALTER TABLE \(TableBookmarksMirror) RENAME TO \(TableBookmarksBuffer)", + "ALTER TABLE \(TableBookmarksMirrorStructure) RENAME TO \(TableBookmarksBufferStructure)", + + // Create the new mirror and local tables. + bookmarksLocal, + bookmarksMirror, + bookmarksLocalStructure, + bookmarksMirrorStructure, + ] + + // Only migrate bookmarks. The only folders are our roots, and we'll create those later. + // There should be nothing else in the table, and no structure. + // Our old bookmarks table didn't have creation date, so we use the current timestamp. + let modified = Date.now() + let status = SyncStatus.new.rawValue + + // We don't specify a title, expecting it to be generated on the fly, because we're smarter than Android. + // We also don't migrate the 'id' column; we'll generate new ones that won't conflict with our roots. + let migrateArgs: Args = [BookmarkRoots.MobileFolderGUID] + let migrateLocal = + "INSERT INTO \(TableBookmarksLocal) " + + "(guid, type, bmkUri, title, faviconID, local_modified, sync_status, parentid, parentName) " + + "SELECT guid, type, url AS bmkUri, title, faviconID, " + + "\(modified) AS local_modified, \(status) AS sync_status, ?, '' " + + "FROM \(_TableBookmarks) WHERE type IS \(BookmarkNodeType.bookmark.rawValue)" + + // Create structure for our migrated bookmarks. + // In order to get contiguous positions (idx), we first insert everything we just migrated under + // Mobile Bookmarks into a temporary table, then use rowid as our idx. + + let temporaryTable = + "CREATE TEMPORARY TABLE children AS " + + "SELECT guid FROM \(_TableBookmarks) WHERE " + + "type IS \(BookmarkNodeType.bookmark.rawValue) ORDER BY id ASC" + + let createStructure = + "INSERT INTO \(TableBookmarksLocalStructure) (parent, child, idx) " + + "SELECT ? AS parent, guid AS child, (rowid - 1) AS idx FROM children" + + let migrate: [(String, Args?)] = [ + (migrateLocal, migrateArgs), + (temporaryTable, nil), + (createStructure, migrateArgs), + + // Drop the temporary table. + ("DROP TABLE children", nil), + + // Drop the old bookmarks table. + ("DROP TABLE \(_TableBookmarks)", nil), + + // Create indices for each structure table. + (indexBufferStructureParentIdx, nil), + (indexLocalStructureParentIdx, nil), + (indexMirrorStructureParentIdx, nil), + ] + + if !self.run(db, queries: prep) || + !self.prepopulateRootFolders(db) || + !self.run(db, queries: migrate) { + return false + } + // TODO: trigger a sync? + } + + // Add views for the overlays. + if from < 14 && to >= 14 { + let indexMirrorStructureChild = + "CREATE INDEX IF NOT EXISTS \(IndexBookmarksMirrorStructureChild) " + + "ON \(TableBookmarksMirrorStructure) (child)" + if !self.run(db, queries: [ + self.bufferBookmarksStructureView, + self.localBookmarksStructureView, + indexMirrorStructureChild]) { + return false + } + } + + if from == 14 && to >= 15 { + // We screwed up some of the views. Recreate them. + if !self.run(db, queries: [ + "DROP VIEW IF EXISTS \(ViewBookmarksBufferStructureOnMirror)", + "DROP VIEW IF EXISTS \(ViewBookmarksLocalStructureOnMirror)", + self.bufferBookmarksStructureView, + self.localBookmarksStructureView]) { + return false + } + } + + if from < 16 && to >= 16 { + if !self.run(db, queries: [ + oldAllBookmarksView, // Replaced in v30. The new one is not compatible here. + historyVisitsView, + awesomebarBookmarksView, // … but this depends on ViewAllBookmarks. + awesomebarBookmarksWithIconsView]) { + return false + } + } + + // That view is re-created later + // if from < 17 && to >= 17 { + // if !self.run(db, queries: [ + // // Adds the local_modified, server_modified times to the local bookmarks view + // "DROP VIEW IF EXISTS \(ViewBookmarksLocalOnMirror)", + // self.localBookmarksView]) { + // return false + // } + // } + + if from < 18 && to >= 18 { + if !self.run(db, queries: [ + // Adds the Activity Stream blocklist table + activityStreamBlocklistCreate]) { + return false + } + } + + if from < 19 && to >= 19 { + if !self.run(db, queries: [ + // Adds tables/indicies for metadata content + pageMetadataCreate, + indexPageMetadataCacheKeyCreate]) { + return false + } + } + + // That view is re-created later + // if from < 20 && to >= 20 { + // if !self.run(db, queries: [ + // "DROP VIEW IF EXISTS \(ViewBookmarksBufferOnMirror)", + // self.bufferBookmarksView]) { + // return false + // } + // } + + if from < 21 && to >= 21 { + if !self.run(db, queries: [ + "DROP VIEW IF EXISTS \(ViewHistoryVisits)", + self.historyVisitsView, + indexPageMetadataSiteURLCreate]) { + return false + } + } + + // Someone upgrading from v21 will get these tables anyway. + // So, there's no need to create them only to be dropped and + // re-created at v27 anyway. + // if from < 22 && to >= 22 { + // if !self.run(db, queries: [ + // "DROP TABLE IF EXISTS \(TablePageMetadata)", + // pageMetadataCreate, + // indexPageMetadataCacheKeyCreate, + // indexPageMetadataSiteURLCreate]) { + // return false + // } + // } + // + // if from < 23 && to >= 23 { + // if !self.run(db, queries: [ + // highlightsCreate]) { + // return false + // } + // } + // + // if from < 24 && to >= 24 { + // if !self.run(db, queries: [ + // // We can safely drop the highlights cache table since it gets cleared on every invalidate anyways. + // "DROP TABLE IF EXISTS \(TableHighlights)", + // highlightsCreate + // ]) { + // return false + // } + // } + + // Someone upgrading from v21 will get this table anyway. + // So, there's no need to create it only to be dropped and + // re-created at v26 anyway. + // if from < 25 && to >= 25 { + // if !self.run(db, queries: [ + // pinnedTopSitesTableCreate + // ]) { + // return false + // } + // } + + if from < 26 && to >= 26 { + if !self.run(db, queries: [ + // The old pin table was never released so we can safely drop + "DROP TABLE IF EXISTS \(TablePinnedTopSites)", + pinnedTopSitesTableCreate + ]) { + return false + } + } + + if from < 27 && to >= 27 { + if !self.run(db, queries: [ + "DROP TABLE IF EXISTS \(TablePageMetadata)", + "DROP TABLE IF EXISTS \(TableHighlights)", + pageMetadataCreate, + indexPageMetadataCacheKeyCreate, + indexPageMetadataSiteURLCreate, + highlightsCreate + ]) { + return false + } + } + + if from < 28 && to >= 28 { + if !self.run(db, queries: [ + self.pendingBookmarksDeletions + ]) { + return false + } + } + + if from < 29 && to >= 29 { + if !self.run(db, queries: [ + self.remoteDevices + ]) { + return false + } + } + + if from < 30 && to >= 30 { + // We changed this view as a follow-up to the above in order to exclude buffer + // deletions from the bookmarked set. + if !self.run(db, queries: [ + "DROP VIEW IF EXISTS \(ViewAllBookmarks)", + allBookmarksView + ]) { + return false + } + } + + // NOTE: These tables should have already existed in prior + // versions, but were managed separately via the SchemaTable. + // Here we create them if they don't already exist to handle + // cases where we are creating a brand new DB. + if from < 31 && to >= 31 { + if !self.run(db, queries: [ + syncCommandsTableCreate, + clientsTableCreate, + tabsTableCreate + ]) { + return false + } + } + + if from < 32 && to >= 32 { + var queries: [String] = [] + // If upgrading from < 12 these tables are created with that column already present. + if from > 12 { + queries.append(contentsOf: [ + "ALTER TABLE \(TableBookmarksLocal) ADD date_added INTEGER", + "ALTER TABLE \(TableBookmarksMirror) ADD date_added INTEGER", + "ALTER TABLE \(TableBookmarksBuffer) ADD date_added INTEGER" + ]) + } + queries.append(contentsOf: [ + "UPDATE \(TableBookmarksLocal) SET date_added = local_modified", + "UPDATE \(TableBookmarksMirror) SET date_added = server_modified" + ]) + if !self.run(db, queries: queries) { + return false + } + } + + if from < 33 && to >= 33 { + if !self.run(db, queries: [ + "DROP VIEW IF EXISTS \(ViewBookmarksBufferOnMirror)", + "DROP VIEW IF EXISTS \(ViewBookmarksBufferWithDeletionsOnMirror)", + "DROP VIEW IF EXISTS \(ViewBookmarksLocalOnMirror)", + self.bufferBookmarksView, + self.bufferBookmarksWithDeletionsView, + self.localBookmarksView + ]) { + return false + } + } + + if from < 34 && to >= 34 { + // Drop over-large items from the database, and truncate + // over-long titles. + // We do this once, and only for local bookmarks: if they + // already escaped, then it's better to let them be. + // Hard-code values here both for simplicity and to make + // migrations predictable. + // We don't need to worry about description: we never wrote it. + if !self.run(db, queries: [ + "DELETE FROM \(TableHistory) WHERE is_deleted = 0 AND length(url) > 65536", + "DELETE FROM \(TablePageMetadata) WHERE length(site_url) > 65536", + "DELETE FROM \(TableBookmarksLocal) WHERE is_deleted = 0 AND length(bmkUri) > 65536", + "UPDATE \(TableBookmarksLocal) SET title = substr(title, 1, 4096)" + + " WHERE is_deleted = 0 AND length(title) > 4096", + ]) { + return false + } + } + + return true + } + + fileprivate func migrateFromSchemaTableIfNeeded(_ db: SQLiteDBConnection) -> Bool { + log.info("Checking if schema table migration is needed.") + + // If `PRAGMA user_version` is v31 or later, we don't need to do anything here. + guard db.version < 31 else { + return true + } + + // Query for the existence of the `tableList` table to determine if we are + // migrating from an older DB version or if this is just a brand new DB. + let sqliteMasterCursor = db.executeQueryUnsafe("SELECT COUNT(*) AS number FROM sqlite_master WHERE type = 'table' AND name = 'tableList'", factory: IntFactory, withArgs: [] as Args) + + let tableListTableExists = sqliteMasterCursor[0] == 1 + sqliteMasterCursor.close() + + // If `tableList` still exists in this DB, then we need to continue to check if + // any table-specific migrations are required before removing it. Otherwise, if + // `tableList` does not exist, it is likely due to this being a brand new DB and + // no additional steps need to be taken at this point. + guard tableListTableExists else { + return true + } + + // If we are unable to migrate the `clients` table from the schema table, we + // have failed and cannot continue. + guard migrateClientsTableFromSchemaTableIfNeeded(db) != .failure else { + return false + } + + // Get the *previous* schema version (prior to v31) specified in `tableList` + // before dropping it. + let previousVersionCursor = db.executeQueryUnsafe("SELECT version FROM tableList WHERE name = 'BROWSER'", factory: IntFactory, withArgs: [] as Args) + + let previousVersion = previousVersionCursor[0] ?? 0 + previousVersionCursor.close() + + // No other intermediate migrations are needed for the remaining tables and + // we have already captured the *previous* schema version specified in + // `tableList`, so we can now safely drop it. + log.info("Schema table migrations complete; Dropping 'tableList' table.") + + let sql = "DROP TABLE IF EXISTS tableList" + do { + try db.executeChange(sql) + } catch let err as NSError { + Sentry.shared.sendWithStacktrace(message: "Error dropping tableList table", tag: SentryTag.browserDB, severity: .error, description: "\(err.localizedDescription)") + return false + } + + // Lastly, write the *previous* schema version (prior to v31) to the database + // using `PRAGMA user_version = ?`. + do { + try db.setVersion(previousVersion) + } catch let err as NSError { + Sentry.shared.sendWithStacktrace(message: "Error setting database version", tag: SentryTag.browserDB, severity: .error, description: "\(err.localizedDescription)") + return false + } + + return true + } + + // Performs the intermediate migrations for the `clients` table that were previously + // being handled by the schema table. This should update older versions of the `clients` + // table prior to v31. If the `clients` table is able to be successfully migrated, this + // will return `.success`. If no migration is required because either the `clients` table + // is already at v31 or it does not exist yet at all, this will return `.skipped`. + // Otherwise, if the `clients` table migration is needed and an error was encountered, we + // return `.failure`. + fileprivate func migrateClientsTableFromSchemaTableIfNeeded(_ db: SQLiteDBConnection) -> SchemaUpgradeResult { + // Query for the existence of the `clients` table to determine if we are + // migrating from an older DB version or if this is just a brand new DB. + let sqliteMasterCursor = db.executeQueryUnsafe("SELECT COUNT(*) AS number FROM sqlite_master WHERE type = 'table' AND name = '\(TableClients)'", factory: IntFactory, withArgs: [] as Args) + + let clientsTableExists = sqliteMasterCursor[0] == 1 + sqliteMasterCursor.close() + + guard clientsTableExists else { + return .skipped + } + + // Check if intermediate migrations are necessary for the 'clients' table. + let previousVersionCursor = db.executeQueryUnsafe("SELECT version FROM tableList WHERE name = '\(TableClients)'", factory: IntFactory, withArgs: [] as Args) + + let previousClientsTableVersion = previousVersionCursor[0] ?? 0 + previousVersionCursor.close() + + guard previousClientsTableVersion > 0 && previousClientsTableVersion <= 3 else { + return .skipped + } + + log.info("Migrating '\(TableClients)' table from version \(previousClientsTableVersion).") + + if previousClientsTableVersion < 2 { + let sql = "ALTER TABLE \(TableClients) ADD COLUMN version TEXT" + do { + try db.executeChange(sql) + } catch let err as NSError { + log.error("Error altering \(TableClients) table: \(err.localizedDescription); SQL was \(sql)") + let extra = ["table": "\(TableClients)", "errorDescription": "\(err.localizedDescription)", "sql": "\(sql)"] + Sentry.shared.sendWithStacktrace(message: "Error altering table", tag: SentryTag.browserDB, severity: .error, extra: extra) + return .failure + } + } + + if previousClientsTableVersion < 3 { + let sql = "ALTER TABLE \(TableClients) ADD COLUMN fxaDeviceId TEXT" + do { + try db.executeChange(sql) + } catch let err as NSError { + log.error("Error altering \(TableClients) table: \(err.localizedDescription); SQL was \(sql)") + let extra = ["table": "\(TableClients)", "errorDescription": "\(err.localizedDescription)", "sql": "\(sql)"] + Sentry.shared.sendWithStacktrace(message: "Error altering table", tag: SentryTag.browserDB, severity: .error, extra: extra) + return .failure + } + } + + return .success + } + + fileprivate func fillDomainNamesFromCursor(_ cursor: Cursor, db: SQLiteDBConnection) -> Bool { + if cursor.count == 0 { + return true + } + + // URL -> hostname, flattened to make args. + var pairs = Args() + pairs.reserveCapacity(cursor.count * 2) + for url in cursor { + if let url = url, let host = url.asURL?.normalizedHost { + pairs.append(url) + pairs.append(host) + } + } + cursor.close() + + let tmpTable = "tmp_hostnames" + let table = "CREATE TEMP TABLE \(tmpTable) (url TEXT NOT NULL UNIQUE, domain TEXT NOT NULL, domain_id INT)" + if !self.run(db, sql: table, args: nil) { + log.error("Can't create temporary table. Unable to migrate domain names. Top Sites is likely to be broken.") + return false + } + + // Now insert these into the temporary table. Chunk by an even number, for obvious reasons. + let chunks = chunk(pairs, by: BrowserDB.MaxVariableNumber - (BrowserDB.MaxVariableNumber % 2)) + for chunk in chunks { + let ins = "INSERT INTO \(tmpTable) (url, domain) VALUES " + + Array(repeating: "(?, ?)", count: chunk.count / 2).joined(separator: ", ") + if !self.run(db, sql: ins, args: Array(chunk)) { + log.error("Couldn't insert domains into temporary table. Aborting migration.") + return false + } + } + + // Now make those into domains. + let domains = "INSERT OR IGNORE INTO \(TableDomains) (domain) SELECT DISTINCT domain FROM \(tmpTable)" + + // … and fill that temporary column. + let domainIDs = "UPDATE \(tmpTable) SET domain_id = (SELECT id FROM \(TableDomains) WHERE \(TableDomains).domain = \(tmpTable).domain)" + + // Update the history table from the temporary table. + let updateHistory = "UPDATE \(TableHistory) SET domain_id = (SELECT domain_id FROM \(tmpTable) WHERE \(tmpTable).url = \(TableHistory).url)" + + // Clean up. + let dropTemp = "DROP TABLE \(tmpTable)" + + // Now run these. + if !self.run(db, queries: [domains, + domainIDs, + updateHistory, + dropTemp]) { + log.error("Unable to migrate domains.") + return false + } + + return true + } + + public func drop(_ db: SQLiteDBConnection) -> Bool { + log.debug("Dropping all browser tables.") + let additional = [ + "DROP TABLE IF EXISTS faviconSites" // We renamed it to match naming convention. + ] + + let views = AllViews.map { "DROP VIEW IF EXISTS \($0)" } + let indices = AllIndices.map { "DROP INDEX IF EXISTS \($0)" } + let tables = AllTables.map { "DROP TABLE IF EXISTS \($0)" } + let queries = Array([views, indices, tables, additional].joined()) + return self.run(db, queries: queries) + } +} diff --git a/mobile/ios/Storage/SQL/LoginsSchema.swift b/mobile/ios/Storage/SQL/LoginsSchema.swift new file mode 100644 index 0000000000..92877cffc8 --- /dev/null +++ b/mobile/ios/Storage/SQL/LoginsSchema.swift @@ -0,0 +1,123 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger + +let TableLoginsMirror = "loginsM" +let TableLoginsLocal = "loginsL" +let IndexLoginsOverrideHostname = "idx_loginsM_is_overridden_hostname" +let IndexLoginsDeletedHostname = "idx_loginsL_is_deleted_hostname" + +private let AllTables: [String] = [ + TableLoginsMirror, + TableLoginsLocal +] + +private let log = Logger.syncLogger + +open class LoginsSchema: Schema { + static let DefaultVersion = 3 + + public var name: String { return "LOGINS" } + public var version: Int { return LoginsSchema.DefaultVersion } + + public init() {} + + func run(_ db: SQLiteDBConnection, sql: String, args: Args? = nil) -> Bool { + do { + try db.executeChange(sql, withArgs: args) + } catch let err as NSError { + log.error("Error running SQL in LoginsSchema: \(err.localizedDescription)") + log.error("SQL was \(sql)") + return false + } + + return true + } + + // TODO: transaction. + func run(_ db: SQLiteDBConnection, queries: [String]) -> Bool { + for sql in queries { + if !run(db, sql: sql, args: nil) { + return false + } + } + return true + } + + let indexIsOverriddenHostname = + "CREATE INDEX IF NOT EXISTS \(IndexLoginsOverrideHostname) ON \(TableLoginsMirror) (is_overridden, hostname)" + + let indexIsDeletedHostname = + "CREATE INDEX IF NOT EXISTS \(IndexLoginsDeletedHostname) ON \(TableLoginsLocal) (is_deleted, hostname)" + + public func create(_ db: SQLiteDBConnection) -> Bool { + let common = + "id INTEGER PRIMARY KEY AUTOINCREMENT" + + ", hostname TEXT NOT NULL" + + ", httpRealm TEXT" + + ", formSubmitURL TEXT" + + ", usernameField TEXT" + + ", passwordField TEXT" + + ", timesUsed INTEGER NOT NULL DEFAULT 0" + + ", timeCreated INTEGER NOT NULL" + + ", timeLastUsed INTEGER" + + ", timePasswordChanged INTEGER NOT NULL" + + ", username TEXT" + + ", password TEXT NOT NULL" + + let mirror = "CREATE TABLE IF NOT EXISTS \(TableLoginsMirror) (" + + common + + ", guid TEXT NOT NULL UNIQUE" + + ", server_modified INTEGER NOT NULL" + // Integer milliseconds. + ", is_overridden TINYINT NOT NULL DEFAULT 0" + + ")" + + let local = "CREATE TABLE IF NOT EXISTS \(TableLoginsLocal) (" + + common + + ", guid TEXT NOT NULL UNIQUE " + // Typically overlaps one in the mirror unless locally new. + ", local_modified INTEGER" + // Can be null. Client clock. In extremis only. + ", is_deleted TINYINT NOT NULL DEFAULT 0" + // Boolean. Locally deleted. + ", sync_status TINYINT " + // SyncStatus enum. Set when changed or created. + "NOT NULL DEFAULT \(SyncStatus.synced.rawValue)" + + ")" + return self.run(db, queries: [mirror, local, indexIsOverriddenHostname, indexIsDeletedHostname]) + } + + public func update(_ db: SQLiteDBConnection, from: Int) -> Bool { + let to = self.version + if from == to { + log.debug("Skipping update from \(from) to \(to).") + return true + } + + if from == 0 { + // This is likely an upgrade from before Bug 1160399. + log.debug("Updating logins tables from zero. Assuming drop and recreate.") + return drop(db) && create(db) + } + + if from < 3 && to >= 3 { + log.debug("Updating logins tables to include version 3 indices") + return self.run(db, queries: [indexIsOverriddenHostname, indexIsDeletedHostname]) + } + + // TODO: real update! + log.debug("Updating logins table from \(from) to \(to).") + return drop(db) && create(db) + } + + public func drop(_ db: SQLiteDBConnection) -> Bool { + log.debug("Dropping logins table.") + do { + try db.executeChange("DROP TABLE IF EXISTS \(name)") + } catch { + return false + } + + return true + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteBookmarksBase.swift b/mobile/ios/Storage/SQL/SQLiteBookmarksBase.swift new file mode 100644 index 0000000000..8845a6b4c4 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteBookmarksBase.swift @@ -0,0 +1,65 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared + +private let log = Logger.syncLogger + +class NoSuchSearchKeywordError: MaybeErrorType { + let keyword: String + init(keyword: String) { + self.keyword = keyword + } + var description: String { + return "No such search keyword: \(keyword)." + } +} + +open class SQLiteBookmarks: BookmarksModelFactorySource, KeywordSearchSource { + let db: BrowserDB + let favicons: SQLiteFavicons + + static let defaultFolderTitle: String = NSLocalizedString("Untitled", tableName: "Storage", comment: "The default name for bookmark folders without titles.") + static let defaultItemTitle: String = NSLocalizedString("Untitled", tableName: "Storage", comment: "The default name for bookmark nodes without titles.") + + open lazy var modelFactory: Deferred> = + deferMaybe(SQLiteBookmarksModelFactory(bookmarks: self, direction: .local)) + + public init(db: BrowserDB) { + self.db = db + self.favicons = SQLiteFavicons(db: self.db) + } + + open func isBookmarked(_ url: String, direction: Direction) -> Deferred> { + let sql = "SELECT id FROM " + + "(SELECT id FROM \(direction.valueTable) WHERE " + + " bmkUri = ? AND is_deleted IS NOT 1" + + " UNION ALL " + + " SELECT id FROM \(TableBookmarksMirror) WHERE " + + " bmkUri = ? AND is_deleted IS NOT 1 AND is_overridden IS NOT 1" + + " LIMIT 1)" + let args: Args = [url, url] + + return self.db.queryReturnsResults(sql, args: args) + } + + open func getURLForKeywordSearch(_ keyword: String) -> Deferred> { + let sql = "SELECT bmkUri FROM \(ViewBookmarksBufferOnMirror) WHERE " + + " keyword = ?" + let args: Args = [keyword] + + return self.db.runQuery(sql, args: args, factory: { $0["bmkUri"] as! String }) + >>== { cursor in + if cursor.status == .success { + if let str = cursor[0] { + return deferMaybe(str) + } + } + + return deferMaybe(NoSuchSearchKeywordError(keyword: keyword)) + } + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteBookmarksHelpers.swift b/mobile/ios/Storage/SQL/SQLiteBookmarksHelpers.swift new file mode 100644 index 0000000000..c64c9ada9c --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteBookmarksHelpers.swift @@ -0,0 +1,75 @@ +/* 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/. */ + +import Foundation +import Shared + +public func titleForSpecialGUID(_ guid: GUID) -> String? { + switch guid { + case BookmarkRoots.RootGUID: + return "" + case BookmarkRoots.MobileFolderGUID: + return BookmarksFolderTitleMobile + case BookmarkRoots.ToolbarFolderGUID: + return BookmarksFolderTitleToolbar + case BookmarkRoots.MenuFolderGUID: + return BookmarksFolderTitleMenu + case BookmarkRoots.UnfiledFolderGUID: + return BookmarksFolderTitleUnsorted + default: + return nil + } +} + +class BookmarkURLTooLargeError: MaybeErrorType { + init() { + } + var description: String { + return "URL too long to bookmark." + } +} + +extension String { + public func truncateToUTF8ByteCount(_ keep: Int) -> String { + let byteCount = self.lengthOfBytes(using: String.Encoding.utf8) + if byteCount <= keep { + return self + } + let toDrop = keep - byteCount + + // If we drop this many characters from the string, we will drop at least this many bytes. + // That's aggressive, but that's OK for our purposes. + guard let endpoint = self.index(self.endIndex, offsetBy: toDrop, limitedBy: self.startIndex) else { + return "" + } + return self.substring(to: endpoint) + } +} + +extension SQLiteBookmarks: ShareToDestination { + public func addToMobileBookmarks(_ url: URL, title: String, favicon: Favicon?) -> Success { + if url.absoluteString.lengthOfBytes(using: String.Encoding.utf8) > AppConstants.DB_URL_LENGTH_MAX { + return deferMaybe(BookmarkURLTooLargeError()) + } + + let title = title.truncateToUTF8ByteCount(AppConstants.DB_TITLE_LENGTH_MAX) + + return isBookmarked(String(describing: url), direction: Direction.local) + >>== { yes in + guard !yes else { return succeed() } + return self.insertBookmark(url, title: title, favicon: favicon, + intoFolder: BookmarkRoots.MobileFolderGUID, + withTitle: BookmarksFolderTitleMobile) + } + } + + public func shareItem(_ item: ShareItem) -> Success { + // We parse here in anticipation of getting real URLs at some point. + if let url = item.url.asURL { + let title = item.title ?? url.absoluteString + return self.addToMobileBookmarks(url, title: title, favicon: item.favicon) + } + return succeed() + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteBookmarksModel.swift b/mobile/ios/Storage/SQL/SQLiteBookmarksModel.swift new file mode 100644 index 0000000000..56576fe1a8 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteBookmarksModel.swift @@ -0,0 +1,948 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared + +private let log = Logger.syncLogger +private let desktopBookmarksLabel: String = NSLocalizedString("Desktop Bookmarks", tableName: "BookmarkPanel", comment: "The folder name for the virtual folder that contains all desktop bookmarks.") + +public enum Direction { + case buffer + case local + + var structureTable: String { + switch self { + case .local: + return TableBookmarksLocalStructure + case .buffer: + return TableBookmarksBufferStructure + } + } + + var valueTable: String { + switch self { + case .local: + return TableBookmarksLocal + case .buffer: + return TableBookmarksBuffer + } + } + + var valueView: String { + switch self { + case .local: + return ViewBookmarksLocalOnMirror + case .buffer: + return ViewBookmarksBufferWithDeletionsOnMirror + } + } + + var structureView: String { + switch self { + case .local: + return ViewBookmarksLocalStructureOnMirror + case .buffer: + return ViewBookmarksBufferStructureOnMirror + } + } +} + +public protocol KeywordSearchSource { + func getURLForKeywordSearch(_ keyword: String) -> Deferred> +} + +open class SQLiteBookmarksModelFactory: BookmarksModelFactory { + fileprivate let bookmarks: SQLiteBookmarks + fileprivate let direction: Direction + + public init(bookmarks: SQLiteBookmarks, direction: Direction) { + self.bookmarks = bookmarks + self.direction = direction + } + + public func factoryForIndex(_ index: Int, inFolder folder: BookmarkFolder) -> BookmarksModelFactory { + return self + } + + fileprivate func withDifferentDirection(_ direction: Direction) -> SQLiteBookmarksModelFactory { + if self.direction == direction { + return self + } + return SQLiteBookmarksModelFactory(bookmarks: self.bookmarks, direction: direction) + } + + fileprivate func getChildrenWithParent(_ parentGUID: GUID, excludingGUIDs: [GUID]?=nil, includeIcon: Bool) -> Deferred>> { + return self.bookmarks.getChildrenWithParent(parentGUID, direction: self.direction, excludingGUIDs: excludingGUIDs, includeIcon: includeIcon) + } + + fileprivate func getRootChildren() -> Deferred>> { + return self.getChildrenWithParent(BookmarkRoots.RootGUID, excludingGUIDs: [BookmarkRoots.RootGUID], includeIcon: true) + } + + fileprivate func getChildren(_ guid: String) -> Deferred>> { + return self.getChildrenWithParent(guid, includeIcon: true) + } + + func folderForGUID(_ guid: GUID, title: String) -> Deferred> { + return self.getChildren(guid) + >>== { cursor in + + if cursor.status == .failure { + return deferMaybe(DatabaseError(description: "Couldn't get children: \(cursor.statusMessage).")) + } + + return deferMaybe(SQLiteBookmarkFolder(guid: guid, title: title, children: cursor)) + } + } + + fileprivate func modelWithRoot(_ root: BookmarkFolder) -> Deferred> { + return deferMaybe(BookmarksModel(modelFactory: self, root: root)) + } + + open func modelForFolder(_ guid: String, title: String) -> Deferred> { + if guid == BookmarkRoots.MobileFolderGUID { + return self.modelForRoot() + } + + if guid == BookmarkRoots.FakeDesktopFolderGUID { + return self.modelForDesktopBookmarks() + } + + let outputTitle = titleForSpecialGUID(guid) ?? title + return self.folderForGUID(guid, title: outputTitle) + >>== self.modelWithRoot + } + + open func modelForFolder(_ folder: BookmarkFolder) -> Deferred> { + return self.modelForFolder(folder.guid, title: folder.title) + } + + open func modelForFolder(_ guid: String) -> Deferred> { + return self.modelForFolder(guid, title: "") + } + + open func modelForRoot() -> Deferred> { + log.debug("Getting model for root.") + let getFolder = self.folderForGUID(BookmarkRoots.MobileFolderGUID, title: BookmarksFolderTitleMobile) + if self.direction == .buffer { + return getFolder >>== self.modelWithRoot + } + + // Return a virtual model containing "Desktop bookmarks" prepended to the local mobile bookmarks. + return getFolder >>== { folder in + self.extendWithDesktopBookmarksFolder(folder, factory: self) + } + } + + open var nullModel: BookmarksModel { + let children = Cursor(status: .failure, msg: "Null model") + let folder = SQLiteBookmarkFolder(guid: "Null", title: "Null", children: children) + return BookmarksModel(modelFactory: self, root: folder) + } + + open func isBookmarked(_ url: String) -> Deferred> { + return self.bookmarks.isBookmarked(url, direction: self.direction) + } + + open func removeByURL(_ url: String) -> Success { + if self.direction == Direction.buffer { + return deferMaybe(DatabaseError(description: "Refusing to remove URL from buffer in model.")) + } + + // Find all of the records for the provided URL. Don't bother with + // any that are already deleted! + return self.bookmarks.nonDeletedGUIDsForURL(url) + >>== self.bookmarks.removeGUIDs + } + + open func removeByGUID(_ guid: GUID) -> Success { + if self.direction == Direction.buffer { + return deferMaybe(DatabaseError(description: "Refusing to remove GUID from buffer in model.")) + } + + log.debug("removeByGUID: \(guid)") + return self.bookmarks.removeGUIDs([guid]) + } + + func hasDesktopBookmarks() -> Deferred> { + // This is very lazy, but it has the nice property of keeping Desktop Bookmarks visible + // for a while after you mark the last desktop child as deleted. + let parents: Args = [ + // Local. + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + + // Mirror. + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + ] + + let sql = + "SELECT 1 FROM \(self.direction.structureTable) WHERE parent IN (?, ?, ?)" + + " UNION ALL " + + "SELECT 1 FROM \(TableBookmarksMirrorStructure) WHERE parent IN (?, ?, ?)" + + " LIMIT 1" + + return self.bookmarks.db.queryReturnsResults(sql, args: parents) + } + + func getDesktopRoots() -> Deferred>> { + if self.direction == .buffer { + // DesktopRoots excludes the Mobile folder, local and non-local mobile are aggregated + return self.bookmarks.getRecordsWithGUIDs(BookmarkRoots.DesktopRoots, direction: self.direction, includeIcon: false) + } + + // We deliberately exclude the mobile folder, because we're inverting the containment + // relationship here. + let exclude = [BookmarkRoots.MobileFolderGUID, BookmarkRoots.RootGUID] + return self.getChildrenWithParent(BookmarkRoots.RootGUID, excludingGUIDs: exclude, includeIcon: false) + } + + /** + * Prepend the provided mobile bookmarks folder with a single folder. + * The prepended folder is "Desktop Bookmarks". It contains mirrored folders. + */ + open func extendWithDesktopBookmarksFolder(_ mobile: BookmarkFolder, factory: BookmarksModelFactory) -> Deferred> { + + func onlyMobile() -> Deferred> { + // No desktop bookmarks. + log.debug("No desktop bookmarks. Only showing mobile.") + return deferMaybe(BookmarksModel(modelFactory: factory, root: mobile)) + } + + return self.hasDesktopBookmarks() >>== { yes in + if !yes { + return onlyMobile() + } + + return self.getDesktopRoots() >>== { cursor in + if cursor.count == 0 { + // This shouldn't occur. + return onlyMobile() + } + + let desktop = self.folderForDesktopBookmarksCursor(cursor) + let prepended = PrependedBookmarkFolder(main: mobile, prepend: desktop) + return deferMaybe(BookmarksModel(modelFactory: factory, root: prepended)) + } + } + } + + fileprivate func modelForDesktopBookmarks() -> Deferred> { + return self.getDesktopRoots() >>== { cursor in + let desktop = self.folderForDesktopBookmarksCursor(cursor) + return deferMaybe(BookmarksModel(modelFactory: self, root: desktop)) + } + } + + fileprivate func folderForDesktopBookmarksCursor(_ cursor: Cursor) -> SQLiteBookmarkFolder { + return SQLiteBookmarkFolder(guid: BookmarkRoots.FakeDesktopFolderGUID, title: desktopBookmarksLabel, children: cursor) + } +} + +class EditableBufferBookmarksSQLiteBookmarksModelFactory: SQLiteBookmarksModelFactory { + override func getChildrenWithParent(_ parentGUID: GUID, excludingGUIDs: [GUID]?, includeIcon: Bool) -> Deferred>> { + if parentGUID == BookmarkRoots.MobileFolderGUID { + return self.bookmarks.getChildrenWithParent(parentGUID, direction: self.direction, excludingGUIDs: excludingGUIDs, includeIcon: includeIcon, factory: BookmarkFactory.editableItemsFactory) + } + return super.getChildrenWithParent(parentGUID, excludingGUIDs: excludingGUIDs, includeIcon: includeIcon) + } + + override func removeByGUID(_ guid: GUID) -> Success { + log.debug("Removing \(guid) from buffer.") + return self.bookmarks.markBufferBookmarkAsDeleted(guid) + } +} + +private func isEditableExpression(_ direction: Direction) -> String { + if direction == .buffer { + return "0" + } + + return "SELECT exists( " + + " SELECT exists(SELECT 1 FROM \(TableBookmarksBuffer)) AS hasBuffer, exists(SELECT 1 FROM \(TableBookmarksMirror)) AS hasMirror " + + " WHERE hasBuffer IS 0 OR hasMirror IS 0" + + ")" +} + +extension SQLiteBookmarks { + + fileprivate func getRecordsWithGUIDs(_ guids: [GUID], direction: Direction, includeIcon: Bool) -> Deferred>> { + + let args: Args = guids + let varlist = BrowserDB.varlist(args.count) + let values = + "SELECT -1 AS id, guid, type, date_added, is_deleted, parentid, parentName, feedUri, pos, title, bmkUri, siteUri, folderName, faviconID, (\(isEditableExpression(direction))) AS isEditable " + + "FROM \(direction.valueView) WHERE guid IN \(varlist) AND NOT is_deleted" + + let withIcon = [ + "SELECT bookmarks.id AS id, bookmarks.guid AS guid, bookmarks.type AS type,", + " bookmarks.date_added AS date_added,", + " bookmarks.is_deleted AS is_deleted,", + " bookmarks.parentid AS parentid, bookmarks.parentName AS parentName,", + " bookmarks.feedUri AS feedUri, bookmarks.pos AS pos, title AS title,", + " bookmarks.bmkUri AS bmkUri, bookmarks.siteUri AS siteUri,", + " bookmarks.folderName AS folderName,", + " bookmarks.isEditable AS isEditable,", + " favicons.url AS iconURL, favicons.date AS iconDate, favicons.type AS iconType", + "FROM (", values, ") AS bookmarks", + "LEFT OUTER JOIN favicons ON bookmarks.faviconID = favicons.id", + "ORDER BY title ASC", + ].joined(separator: " ") + + let sql = (includeIcon ? withIcon : values) + " ORDER BY title ASC" + return self.db.runQuery(sql, args: args, factory: BookmarkFactory.factory) + } + + /** + * Return the children of the provided parent. + * Rows are ordered by positional index. + * This method is aware of is_overridden and deletion, using local override structure by preference. + * Note that a folder can be empty locally; we thus use the flag rather than looking at the structure itself. + */ + func getChildrenWithParent(_ parentGUID: GUID, direction: Direction, excludingGUIDs: [GUID]?=nil, includeIcon: Bool, factory: @escaping (SDRow) -> BookmarkNode = BookmarkFactory.factory) -> Deferred>> { + + precondition((excludingGUIDs ?? []).count < 100, "Sanity bound for the number of GUIDs we can exclude.") + + let valueView = direction.valueView + let structureView = direction.structureView + + let structure = + "SELECT parent, child AS guid, idx FROM \(structureView) " + + "WHERE parent = ?" + + let values = + "SELECT -1 AS id, guid, type, date_added, is_deleted, parentid, parentName, feedUri, pos, title, bmkUri, siteUri, folderName, faviconID, (\(isEditableExpression(direction))) AS isEditable " + + "FROM \(valueView)" + + // We exclude queries and dynamic containers, because we can't + // usefully display them. + let typeQuery = BookmarkNodeType.query.rawValue + let typeDynamic = BookmarkNodeType.dynamicContainer.rawValue + let typeFilter = " vals.type NOT IN (\(typeQuery), \(typeDynamic))" + + let args: Args + let exclusion: String + if let excludingGUIDs = excludingGUIDs { + args = ([parentGUID] + excludingGUIDs).map { $0 } + exclusion = "\(typeFilter) AND vals.guid NOT IN " + BrowserDB.varlist(excludingGUIDs.count) + } else { + args = [parentGUID] + exclusion = typeFilter + } + + let fleshed = + "SELECT vals.id AS id, vals.guid AS guid, vals.type AS type, vals.date_added AS date_added, vals.is_deleted AS is_deleted, " + + " vals.parentid AS parentid, vals.parentName AS parentName, vals.feedUri AS feedUri, " + + " vals.siteUri AS siteUri," + + " vals.pos AS pos, vals.title AS title, vals.bmkUri AS bmkUri, vals.folderName AS folderName, " + + " vals.faviconID AS faviconID, " + + " vals.isEditable AS isEditable, " + + " structure.idx AS idx, " + + " structure.parent AS _parent " + + "FROM (\(structure)) AS structure JOIN (\(values)) AS vals " + + "ON vals.guid = structure.guid " + + "WHERE " + exclusion + + let withIcon = + "SELECT bookmarks.id AS id, bookmarks.guid AS guid, bookmarks.type AS type, " + + " bookmarks.date_added AS date_added, " + + " bookmarks.is_deleted AS is_deleted, " + + " bookmarks.parentid AS parentid, bookmarks.parentName AS parentName, " + + " bookmarks.feedUri AS feedUri, bookmarks.siteUri AS siteUri, " + + " bookmarks.pos AS pos, title AS title, " + + " bookmarks.bmkUri AS bmkUri, bookmarks.folderName AS folderName, " + + " bookmarks.idx AS idx, bookmarks._parent AS _parent, " + + " bookmarks.isEditable AS isEditable, " + + " favicons.url AS iconURL, favicons.date AS iconDate, favicons.type AS iconType " + + "FROM (\(fleshed)) AS bookmarks " + + "LEFT OUTER JOIN favicons ON bookmarks.faviconID = favicons.id" + + let sql = (includeIcon ? withIcon : fleshed) + " ORDER BY idx ASC" + return self.db.runQuery(sql, args: args, factory: factory) + } + + // This is only used from tests. + func clearBookmarks() -> Success { + log.warning("CALLING clearBookmarks -- this should only be used from tests.") + return self.db.run([ + ("DELETE FROM \(TableBookmarksLocal) WHERE parentid IS NOT ?", [BookmarkRoots.RootGUID]), + self.favicons.getCleanupFaviconsQuery() + ]) + } + + public func removeGUIDs(_ guids: [GUID]) -> Success { + log.debug("removeGUIDs: \(guids)") + + // Override any parents that aren't already overridden. We're about to remove some + // of their children. + return self.overrideParentsOfGUIDs(guids) + + // Find, recursively, any children of the provided GUIDs. This will only be the case + // if you specify folders. This is a special case because we're removing *all* + // children, so we don't need to do the reindexing dance. + >>> { self.deleteChildrenOfGUIDs(guids) } + + // Override any records that aren't already overridden. + >>> { self.overrideGUIDs(guids) } + + // Then delete the already-overridden records. We do this one at a time in order + // to get indices correct in edge cases. (We do bulk-delete their children + // one layer at a time, at least.) + >>> { walk(guids, f: self.removeLocalByGUID) } + } + + fileprivate func nonDeletedGUIDsForURL(_ url: String) -> Deferred> { + let sql = "SELECT DISTINCT guid FROM \(ViewBookmarksLocalOnMirror) WHERE bmkUri = ? AND is_deleted = 0" + let args: Args = [url] + + return self.db.runQuery(sql, args: args, factory: { $0[0] as! GUID }) >>== { guids in + return deferMaybe(guids.asArray()) + } + } + + fileprivate func overrideParentsOfGUIDs(_ guids: [GUID]) -> Success { + log.debug("Overriding parents of \(guids).") + + // TODO: Yes, this can be done in one go. + let getParentsSQL = + "SELECT DISTINCT parent FROM \(ViewBookmarksLocalStructureOnMirror) " + + "WHERE child IN \(BrowserDB.varlist(guids.count)) AND is_overridden = 0" + let getParentsArgs: Args = guids + + return self.db.runQuery(getParentsSQL, args: getParentsArgs, factory: { $0[0] as! GUID }) + >>== { parentsCursor in + let parents = parentsCursor.asArray() + log.debug("Overriding parents: \(parents).") + let (sql, args) = self.getSQLToOverrideFolders(parents, atModifiedTime: Date.now()) + return self.db.run(sql.map { ($0, args) }) + } + } + + fileprivate func overrideGUIDs(_ guids: [GUID]) -> Success { + log.debug("Overriding GUIDs: \(guids).") + let (sql, args) = self.getSQLToOverrideNonFolders(guids, atModifiedTime: Date.now()) + return self.db.run(sql.map { ($0, args) }) + } + + // Recursive. + fileprivate func deleteChildrenOfGUIDs(_ guids: [GUID]) -> Success { + if guids.isEmpty { + return succeed() + } + + precondition(BookmarkRoots.All.intersection(guids).isEmpty, "You can't even touch the roots for removal.") + + log.debug("Deleting children of \(guids).") + + let topArgs: Args = guids + let topVarlist = BrowserDB.varlist(topArgs.count) + let query = + "SELECT child FROM \(ViewBookmarksLocalStructureOnMirror) " + + "WHERE parent IN \(topVarlist)" + + // We're deleting whole folders, so we don't need to worry about indices. + return self.db.runQuery(query, args: topArgs, factory: { $0[0] as! GUID }) + >>== { children in + let childGUIDs = children.asArray() + log.debug("… children of \(guids) are \(childGUIDs).") + + if childGUIDs.isEmpty { + log.debug("No children; nothing more to do.") + return succeed() + } + + let childArgs: Args = childGUIDs + let childVarlist = BrowserDB.varlist(childArgs.count) + + // Mirror the children if they're not already. + // We use the non-folder version of this query because we're recursively + // destroying structure right after this, so there's no point cloning the + // mirror structure. + // Then delete the children's children, so we don't leave orphans. This is + // recursive, so by the time this succeeds we know that all of these records + // have no remaining children. + let (overrideSQL, overrideArgs) = self.getSQLToOverrideNonFolders(childGUIDs, atModifiedTime: Date.now()) + + return self.deleteChildrenOfGUIDs(childGUIDs) + >>> { self.db.run(overrideSQL.map { ($0, overrideArgs) }) } + >>> { + // Delete the children themselves. + + // Remove each child from structure. We use the top list to save effort. + let deleteStructure = + "DELETE FROM \(TableBookmarksLocalStructure) WHERE parent IN \(topVarlist)" + + // If a bookmark is New, delete it outright. + let deleteNew = + "DELETE FROM \(TableBookmarksLocal) WHERE guid IN \(childVarlist) AND sync_status = \(SyncStatus.new.rawValue)" + + // If a bookmark is Changed, mark it as deleted and bump its modified time. + let markChanged = self.getMarkDeletedSQLWithWhereFragment("guid IN \(childVarlist)") + + return self.db.run([ + (deleteStructure, topArgs), + (deleteNew, childArgs), + (markChanged, childArgs), + ]) + } + } + } + + fileprivate func getMarkDeletedSQLWithWhereFragment(_ whereFragment: String) -> String { + let sql = + "UPDATE \(TableBookmarksLocal) SET" + + " date_added = NULL" + + ", is_deleted = 1" + + ", local_modified = \(Date.now())" + + ", bmkUri = NULL" + + ", feedUri = NULL" + + ", siteUri = NULL" + + ", pos = NULL" + + ", title = NULL" + + ", tags = NULL" + + ", keyword = NULL" + + ", description = NULL" + + ", parentid = NULL" + + ", parentName = NULL" + + ", folderName = NULL" + + ", queryId = NULL" + + " WHERE \(whereFragment) AND sync_status = \(SyncStatus.changed.rawValue)" + + return sql + } + /** + * This depends on the record's parent already being overridden if necessary. + */ + fileprivate func removeLocalByGUID(_ guid: GUID) -> Success { + let args: Args = [guid] + + // Find the index we're currently occupying. + let previousIndexSubquery = "SELECT idx FROM \(TableBookmarksLocalStructure) WHERE child = ?" + + // Fix up the indices of subsequent siblings. + let updateIndices = + "UPDATE \(TableBookmarksLocalStructure) SET idx = (idx - 1) WHERE idx > (\(previousIndexSubquery))" + + // If the bookmark is New, delete it outright. + let deleteNew = + "DELETE FROM \(TableBookmarksLocal) WHERE guid = ? AND sync_status = \(SyncStatus.new.rawValue)" + + // If the bookmark is Changed, mark it as deleted and bump its modified time. + let markChanged = self.getMarkDeletedSQLWithWhereFragment("guid = ?") + + // Its parent must be either New or Changed, so we don't need to re-mirror it. + // TODO: bump the parent's modified time, because the child list changed? + + // Now delete from structure. + let deleteStructure = + "DELETE FROM \(TableBookmarksLocalStructure) WHERE child = ?" + + return self.db.run([ + (updateIndices, args), + (deleteNew, args), + (markChanged, args), + (deleteStructure, args), + ]) + } + + fileprivate func markBufferBookmarkAsDeleted(_ guid: GUID) -> Success { + let insertInPendingDeletions = + "INSERT OR IGNORE INTO \(TablePendingBookmarksDeletions) " + + "(id) " + + "VALUES (?)" + let args: Args = [guid] + return self.db.run(insertInPendingDeletions, withArgs: args) + } +} + +class SQLiteBookmarkFolder: BookmarkFolder { + fileprivate let cursor: Cursor + override var count: Int { + return cursor.count + } + + override subscript(index: Int) -> BookmarkNode { + let bookmark = cursor[index] + return bookmark! as BookmarkNode + } + + init(guid: String, title: String, children: Cursor) { + self.cursor = children + super.init(guid: guid, title: title) + } + + override func removeItemWithGUID(_ guid: GUID) -> BookmarkFolder? { + let without = cursor.asArray().filter { $0.guid != guid } + return MemoryBookmarkFolder(guid: self.guid, title: self.title, children: without) + } +} + +class BookmarkFactory { + fileprivate class func addIcon(_ bookmark: BookmarkNode, row: SDRow) { + // TODO: share this logic with SQLiteHistory. + if let faviconURL = row["iconURL"] as? String, + let date = row["iconDate"] as? Double, + let faviconType = row["iconType"] as? Int, + let type = IconType(rawValue: faviconType) { + bookmark.favicon = Favicon(url: faviconURL, + date: Date(timeIntervalSince1970: date), + type: type) + } + } + + fileprivate class func livemarkFactory(_ row: SDRow) -> BookmarkItem { + let id = row["id"] as? Int + let guid = row["guid"] as! String + let url = row["siteUri"] as! String + let title = row["title"] as? String ?? "Livemark" // TODO + let isEditable = row.getBoolean("isEditable") // Defaults to false. + let bookmark = BookmarkItem(guid: guid, title: title, url: url, isEditable: isEditable) + bookmark.id = id + BookmarkFactory.addIcon(bookmark, row: row) + return bookmark + } + + // We ignore queries altogether inside the model factory. + fileprivate class func queryFactory(_ row: SDRow) -> BookmarkItem { + log.warning("Creating a BookmarkItem from a query. This is almost certainly unexpected.") + let id = row["id"] as? Int + let guid = row["guid"] as! String + let title = row["title"] as? String ?? SQLiteBookmarks.defaultItemTitle + let isEditable = row.getBoolean("isEditable") // Defaults to false. + let bookmark = BookmarkItem(guid: guid, title: title, url: "about:blank", isEditable: isEditable) + bookmark.id = id + BookmarkFactory.addIcon(bookmark, row: row) + return bookmark + } + + fileprivate class func separatorFactory(_ row: SDRow) -> BookmarkSeparator { + let id = row["id"] as? Int + let guid = row["guid"] as! String + let separator = BookmarkSeparator(guid: guid) + separator.id = id + return separator + } + + fileprivate class func itemRowFactory(_ row: SDRow, forceEditable: Bool = false) -> BookmarkItem { + let id = row["id"] as? Int + let guid = row["guid"] as! String + let url = row["bmkUri"] as! String + let title = row["title"] as? String ?? url + let isEditable = forceEditable || row.getBoolean("isEditable") // Defaults to false. + let bookmark = BookmarkItem(guid: guid, title: title, url: url, isEditable: isEditable) + bookmark.id = id + BookmarkFactory.addIcon(bookmark, row: row) + return bookmark + } + + fileprivate class func itemFactory(_ row: SDRow) -> BookmarkItem { + return BookmarkFactory.itemRowFactory(row, forceEditable: false) + } + + fileprivate class func folderFactory(_ row: SDRow) -> BookmarkFolder { + let id = row["id"] as? Int + let guid = row["guid"] as! String + let isEditable = row.getBoolean("isEditable") // Defaults to false. + let title = titleForSpecialGUID(guid) ?? + row["title"] as? String ?? + SQLiteBookmarks.defaultFolderTitle + + let folder = BookmarkFolder(guid: guid, title: title, isEditable: isEditable) + folder.id = id + BookmarkFactory.addIcon(folder, row: row) + return folder + } + + class func factory(_ row: SDRow) -> BookmarkNode { + return BookmarkFactory.rowFactory(row, forceEditable: false) + } + + class func editableItemsFactory(_ row: SDRow) -> BookmarkNode { + return BookmarkFactory.rowFactory(row, forceEditable: true) + } + + class func rowFactory(_ row: SDRow, forceEditable: Bool = false) -> BookmarkNode { + if let typeCode = row["type"] as? Int, let type = BookmarkNodeType(rawValue: typeCode) { + switch type { + case .bookmark: + return itemRowFactory(row, forceEditable: forceEditable) + case .dynamicContainer: + // This should never be hit: we exclude dynamic containers from our models. + fallthrough + case .folder: + return folderFactory(row) + case .separator: + return separatorFactory(row) + case .livemark: + return livemarkFactory(row) + case .query: + // This should never be hit: we exclude queries from our models. + return queryFactory(row) + } + } + assert(false, "Invalid bookmark data.") + return itemFactory(row) // This will fail, but it keeps the compiler happy. + } + + // N.B., doesn't include children! + class func mirrorItemFactory(_ row: SDRow) -> BookmarkMirrorItem { + // TODO + // let id = row["id"] as! Int + + let guid = row["guid"] as! GUID + let typeCode = row["type"] as! Int + let is_deleted = row.getBoolean("is_deleted") + let parentid = row["parentid"] as? GUID + let parentName = row["parentName"] as? String + let feedUri = row["feedUri"] as? String + let siteUri = row["siteUri"] as? String + let pos = row["pos"] as? Int + let title = row["title"] as? String + let description = row["description"] as? String + let bmkUri = row["bmkUri"] as? String + let tags = row["tags"] as? String + let keyword = row["keyword"] as? String + let folderName = row["folderName"] as? String + let queryId = row["queryId"] as? String + let date_added = row.getTimestamp("date_added") + + // Local and mirror only. + let faviconID = row["faviconID"] as? Int + + // Local only. + let local_modified = row.getTimestamp("local_modified") + + // Mirror and buffer. + let server_modified = row.getTimestamp("server_modified") + let hasDupe = row.getBoolean("hasDupe") + + // Mirror only. TODO + //let is_overridden = row.getBoolean("is_overridden") + + // Use the struct initializer directly. Yes, this doesn't validate as strongly as + // using the static constructors, but it'll be as valid as the contents of the DB. + let type = BookmarkNodeType(rawValue: typeCode)! + + // This one might really be missing (it's local-only), so do this the hard way. + let syncStatus: SyncStatus? + if let s = row["sync_status"] as? Int { + syncStatus = SyncStatus(rawValue: s) + } else { + syncStatus = nil + } + let item = BookmarkMirrorItem(guid: guid, type: type, dateAdded: date_added, serverModified: server_modified ?? 0, + isDeleted: is_deleted, hasDupe: hasDupe, parentID: parentid, parentName: parentName, + feedURI: feedUri, siteURI: siteUri, + pos: pos, + title: title, description: description, + bookmarkURI: bmkUri, tags: tags, keyword: keyword, + folderName: folderName, queryID: queryId, + children: nil, + faviconID: faviconID, localModified: local_modified, + syncStatus: syncStatus) + return item + } +} + +extension SQLiteBookmarks: SearchableBookmarks { + public func bookmarksByURL(_ url: URL) -> Deferred>> { + let inner = + "SELECT id, type, date_added, guid, bmkUri, title, faviconID FROM \(TableBookmarksLocal) " + + "WHERE " + + "type = \(BookmarkNodeType.bookmark.rawValue) AND is_deleted IS NOT 1 AND bmkUri = ? " + + "UNION ALL " + + "SELECT id, type, date_added, guid, bmkUri, title, faviconID FROM \(TableBookmarksMirror) " + + "WHERE " + + "type = \(BookmarkNodeType.bookmark.rawValue) AND is_overridden IS NOT 1 AND is_deleted IS NOT 1 AND bmkUri = ? " + + let sql = + "SELECT bookmarks.id AS id, bookmarks.type AS type, bookmarks.date_added AS date_added, guid, bookmarks.bmkUri AS bmkUri, title, " + + "favicons.url AS iconURL, favicons.date AS iconDate, favicons.type AS iconType " + + "FROM (\(inner)) AS bookmarks " + + "LEFT OUTER JOIN favicons ON bookmarks.faviconID = favicons.id" + + let u = url.absoluteString + let args: Args = [u, u] + return db.runQuery(sql, args: args, factory: BookmarkFactory.itemFactory) + } +} + +extension SQLiteBookmarks { + // We're in sync (even partially) if the mirror is non-empty. + // We can show fallback desktop bookmarks if the mirror is empty and the buffer contains + // children of the roots. + func hasOnlyUnmergedRemoteBookmarks() -> Deferred> { + let parents: Args = [ + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + BookmarkRoots.MobileFolderGUID, + ] + let sql = [ + "SELECT", + "not exists(SELECT 1 FROM \(TableBookmarksMirror))", + "AND", + "exists(SELECT 1 FROM \(TableBookmarksBufferStructure) WHERE parent IN (?, ?, ?, ?))", + ].joined(separator: " ") + return self.db.runQuery(sql, args: parents, factory: { $0[0] as! Int == 1 }) + >>== { row in + guard row.status == .success, + let result = row[0] else { + // if the query did not succeed, we should return false so that we can use local bookmarks + return deferMaybe(false) + } + return deferMaybe(result) + } + } +} + +// It's a factory where the root contains Desktop Bookmarks from the buffer, and +// mobile bookmarks from local. +open class UnsyncedBookmarksFallbackModelFactory: BookmarksModelFactory { + let localFactory: SQLiteBookmarksModelFactory + let bufferFactory: SQLiteBookmarksModelFactory + + init(bookmarks: SQLiteBookmarks) { + // This relies on SQLiteBookmarks being the storage for both directions. + self.localFactory = SQLiteBookmarksModelFactory(bookmarks: bookmarks, direction: .local) + if AppConstants.MOZ_SIMPLE_BOOKMARKS_SYNCING { + self.bufferFactory = EditableBufferBookmarksSQLiteBookmarksModelFactory(bookmarks: bookmarks, direction: .buffer) + } else { + self.bufferFactory = SQLiteBookmarksModelFactory(bookmarks: bookmarks, direction: .buffer) + } + } + + // This is a special-case class, so here's the special-case behavior to + // know how to handle a folder that contains items drawn from different + // parts of the database. We look for the special kinds of folders we + // nest at the top level, and then we pick a folder to match. + public func factoryForIndex(_ index: Int, inFolder folder: BookmarkFolder) -> BookmarksModelFactory { + let concatenated: ConcatenatedBookmarkFolder + let i: Int + + // We have either just remote and local mobile bookmarks, or we have Desktop Bookmarks + // followed by remote and local mobile bookmarks. Handle either. + if let prepended = folder as? PrependedBookmarkFolder { + if index == 0 { + return self + } + + guard let c = prepended.main as? ConcatenatedBookmarkFolder else { + return self + } + i = index - 1 // Drop the prepend. + concatenated = c + } else { + guard let c = folder as? ConcatenatedBookmarkFolder else { + return self + } + i = index + concatenated = c + } + + if i < concatenated.pivot { + return self.bufferFactory // This comes first in our concatenation. + } + return self.localFactory + } + + open func modelForFolder(_ folder: BookmarkFolder) -> Deferred> { + return self.modelForFolder(folder.guid, title: folder.title) + } + + open func modelForFolder(_ guid: GUID) -> Deferred> { + return self.modelForFolder(guid, title: "") + } + + open func modelForFolder(_ guid: GUID, title: String) -> Deferred> { + if guid == BookmarkRoots.MobileFolderGUID { + return self.modelForRoot() + } + + if guid == BookmarkRoots.FakeDesktopFolderGUID { + return self.bufferFactory.modelForFolder(guid, title: title) + } + + return self.localFactory.modelForFolder(guid, title: title) + } + + open func modelForRoot() -> Deferred> { + log.debug("Getting model for fallback root.") + // Return a virtual model containing "Desktop bookmarks" prepended to the local mobile bookmarks. + return self.localFactory.folderForGUID(BookmarkRoots.MobileFolderGUID, title: BookmarksFolderTitleMobile) + >>== { + localMobileFolder in + + self.bufferFactory.folderForGUID(BookmarkRoots.MobileFolderGUID, title: BookmarksFolderTitleMobile) >>== { + bufferMobileFolder in + + let bufferAndLocalMobile = ConcatenatedBookmarkFolder(main: bufferMobileFolder, append: localMobileFolder) + return self.bufferFactory.hasDesktopBookmarks() >>== { yes in + guard yes else { + return deferMaybe(BookmarksModel(modelFactory: self, root: bufferAndLocalMobile)) + } + return self.bufferFactory.getDesktopRoots() >>== { cursor in + let desktop = self.bufferFactory.folderForDesktopBookmarksCursor(cursor) + let withDesktopPrepended = PrependedBookmarkFolder(main: bufferAndLocalMobile, prepend: desktop) + return deferMaybe(BookmarksModel(modelFactory: self, root: withDesktopPrepended)) + } + } + } + } + } + + // Whenever async construction is necessary, we fall into a pattern of needing + // a placeholder that behaves correctly for the period between kickoff and set. + open var nullModel: BookmarksModel { + let children = Cursor(status: .failure, msg: "Null model") + let folder = SQLiteBookmarkFolder(guid: "Null", title: "Null", children: children) + return BookmarksModel(modelFactory: self, root: folder) + } + + open func isBookmarked(_ url: String) -> Deferred> { + // We don't include buffer items in this check, because we can't un-star them! + return self.localFactory.isBookmarked(url) + } + + open func removeByGUID(_ guid: GUID) -> Success { + return self.localFactory.removeByGUID(guid) + } + + open func removeByURL(_ url: String) -> Success { + return self.localFactory.removeByURL(url) + } +} + +open class MergedSQLiteBookmarks: BookmarksModelFactorySource, KeywordSearchSource { + let local: SQLiteBookmarks + let buffer: SQLiteBookmarkBufferStorage + + // Figuring out our factory can require hitting the DB, so this is async. + // Note that we check *every time* -- we don't want to get stuck in a dead + // end when you might sync soon. + open var modelFactory: Deferred> { + return self.local.hasOnlyUnmergedRemoteBookmarks() >>== { yes in + if yes { + log.debug("Only unmerged remote bookmarks; using fallback factory.") + return deferMaybe(UnsyncedBookmarksFallbackModelFactory(bookmarks: self.local)) + } + log.debug("Using local+mirror bookmark factory.") + return self.local.modelFactory + } + } + + public init(db: BrowserDB) { + self.local = SQLiteBookmarks(db: db) + self.buffer = SQLiteBookmarkBufferStorage(db: db) + } + + open func getURLForKeywordSearch(_ keyword: String) -> Deferred> { + return self.local.getURLForKeywordSearch(keyword) + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteBookmarksResetting.swift b/mobile/ios/Storage/SQL/SQLiteBookmarksResetting.swift new file mode 100644 index 0000000000..1347f6c81a --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteBookmarksResetting.swift @@ -0,0 +1,146 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger + +private let log = Logger.syncLogger + +extension MergedSQLiteBookmarks: AccountRemovalDelegate { + public func onRemovedAccount() -> Success { + return self.local.onRemovedAccount() >>> self.buffer.onRemovedAccount + } +} + +extension MergedSQLiteBookmarks: ResettableSyncStorage { + public func resetClient() -> Success { + return self.local.resetClient() >>> self.buffer.resetClient + } +} + +extension SQLiteBookmarkBufferStorage: AccountRemovalDelegate { + public func onRemovedAccount() -> Success { + return self.resetClient() + } +} + +extension SQLiteBookmarkBufferStorage: ResettableSyncStorage { + /** + * Our buffer is simply a copy of server contents. That means we should + * be very willing to drop it and re-populate it from the server whenever we might + * be out of sync. See Bug 1212431 Comment 2. + */ + public func resetClient() -> Success { + return self.wipeBookmarks() + } + + public func wipeBookmarks() -> Success { + return self.db.run([ + "DELETE FROM \(TableBookmarksBufferStructure)", + "DELETE FROM \(TableBookmarksBuffer)", + ]) + } +} + +extension SQLiteBookmarks { + /** + * If a synced record is deleted locally, but hasn't been synced to the server, + * then `preserveDeletions=true` will result in that deletion being kept. + * + * During a reset, we'll redownload all server records. If we don't keep the + * local deletion, then when we re-process the (non-deleted) server counterpart + * to the now-missing local record, it'll be reinserted: the user's deletion will + * be undone. + * + * Right now we don't preserve deletions when removing the Firefox Account, but + * we could do so if we were willing to trade local database space to handle this + * possible situation. + */ + fileprivate func collapseMirrorIntoLocalPreservingDeletions(_ preserveDeletions: Bool) -> Success { + // As implemented, this won't work correctly without ON DELETE CASCADE. + assert(SwiftData.EnableForeignKeys) + + // 1. Wait until we commit to complain about constraint violations. + let deferForeignKeys = + "PRAGMA defer_foreign_keys = ON" + + // 2. Drop anything from local that's deleted. We don't need to track the + // deletion now. Optional: keep them around if they're non-uploaded changes. + let removeLocalDeletions = + "DELETE FROM \(TableBookmarksLocal) WHERE is_deleted IS 1 " + + (preserveDeletions ? "AND sync_status IS NOT \(SyncStatus.changed.rawValue)" : "") + + // 3. Mark everything in local as New. + let markLocalAsNew = + "UPDATE \(TableBookmarksLocal) SET sync_status = \(SyncStatus.new.rawValue)" + + // 4. Insert into local anything not overridden left in mirror. + // Note that we use the server modified time as our substitute local modified time. + // This will provide an ounce of conflict avoidance if the user re-links the same + // account at a later date. + let copyMirrorContents = + "INSERT OR IGNORE INTO \(TableBookmarksLocal) " + + "(sync_status, local_modified, " + + " guid, date_added, type, bmkUri, title, parentid, parentName, feedUri, siteUri, pos," + + " description, tags, keyword, folderName, queryId, faviconID) " + + "SELECT " + + "\(SyncStatus.new.rawValue) AS sync_status, " + + "server_modified AS local_modified, " + + "guid, date_added, type, bmkUri, title, parentid, parentName, " + + "feedUri, siteUri, pos, description, tags, keyword, folderName, queryId, faviconID " + + "FROM \(TableBookmarksMirror) WHERE is_overridden IS 0" + + // 5.(pre) I have a database right in front of me that violates an assumption: a full + // bookmarksMirrorStructure and an empty bookmarksMirror. Clean up, just in case. + let removeOverriddenStructure = + "DELETE FROM \(TableBookmarksMirrorStructure) WHERE parent IN (SELECT guid FROM \(TableBookmarksMirror) WHERE is_overridden IS 1)" + + // 5. Insert into localStructure anything left in mirrorStructure. + // This won't copy the structure of any folders that were already overridden -- + // we already deleted those, and the deletions cascaded. + let copyMirrorStructure = + "INSERT INTO \(TableBookmarksLocalStructure) SELECT * FROM \(TableBookmarksMirrorStructure)" + + // 6. Blank the mirror. + let removeMirrorStructure = + "DELETE FROM \(TableBookmarksMirrorStructure)" + + let removeMirrorContents = + "DELETE FROM \(TableBookmarksMirror)" + + return db.run([ + deferForeignKeys, + removeLocalDeletions, + markLocalAsNew, + copyMirrorContents, + removeOverriddenStructure, + copyMirrorStructure, + removeMirrorStructure, + removeMirrorContents, + ]) + } +} +extension SQLiteBookmarks: AccountRemovalDelegate { + public func onRemovedAccount() -> Success { + return self.collapseMirrorIntoLocalPreservingDeletions(false) + } +} + +extension SQLiteBookmarks: ResettableSyncStorage { + public func resetClient() -> Success { + // Flip flags to prompt a re-sync. + // + // We copy the mirror to local, preserving local changes, apart from + // deletions of records that were never synced. + // + // Records that match the server record that we'll redownload will be + // marked as Synced and won't be reuploaded. + // + // Records that are present locally but aren't on the server will be + // uploaded. + // + return self.collapseMirrorIntoLocalPreservingDeletions(true) + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteBookmarksSyncing.swift b/mobile/ios/Storage/SQL/SQLiteBookmarksSyncing.swift new file mode 100644 index 0000000000..f7ecee0605 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteBookmarksSyncing.swift @@ -0,0 +1,1216 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared +import XCGLogger + +private let log = Logger.syncLogger + +extension SQLiteBookmarks: LocalItemSource { + public func getLocalItemWithGUID(_ guid: GUID) -> Deferred> { + return self.db.getMirrorItemFromTable(TableBookmarksLocal, guid: guid) + } + + public func getLocalItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.db.getMirrorItemsFromTable(TableBookmarksLocal, guids: guids) + } + + public func prefetchLocalItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + log.debug("Not implemented for SQLiteBookmarks.") + return succeed() + } +} + +extension SQLiteBookmarks: MirrorItemSource { + public func getMirrorItemWithGUID(_ guid: GUID) -> Deferred> { + return self.db.getMirrorItemFromTable(TableBookmarksMirror, guid: guid) + } + + public func getMirrorItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.db.getMirrorItemsFromTable(TableBookmarksMirror, guids: guids) + } + + public func prefetchMirrorItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + log.debug("Not implemented for SQLiteBookmarks.") + return succeed() + } +} + +extension SQLiteBookmarks { + func getSQLToOverrideFolder(_ folder: GUID, atModifiedTime modified: Timestamp) -> (sql: [String], args: Args) { + return self.getSQLToOverrideFolders([folder], atModifiedTime: modified) + } + + func getSQLToOverrideFolders(_ folders: [GUID], atModifiedTime modified: Timestamp) -> (sql: [String], args: Args) { + if folders.isEmpty { + return (sql: [], args: []) + } + + let vars = BrowserDB.varlist(folders.count) + let args: Args = folders + + // Copy it to the local table. + // Most of these will be NULL, because we're only dealing with folders, + // and typically only the Mobile Bookmarks root. + let overrideSQL = "INSERT OR IGNORE INTO \(TableBookmarksLocal) " + + "(guid, type, date_added, bmkUri, title, parentid, parentName, feedUri, siteUri, pos," + + " description, tags, keyword, folderName, queryId, is_deleted, " + + " local_modified, sync_status, faviconID) " + + "SELECT guid, type, date_added, bmkUri, title, parentid, parentName, " + + "feedUri, siteUri, pos, description, tags, keyword, folderName, queryId, " + + "is_deleted, " + + "\(modified) AS local_modified, \(SyncStatus.changed.rawValue) AS sync_status, faviconID " + + "FROM \(TableBookmarksMirror) WHERE guid IN \(vars)" + + // Copy its mirror structure. + let dropSQL = "DELETE FROM \(TableBookmarksLocalStructure) WHERE parent IN \(vars)" + let copySQL = "INSERT INTO \(TableBookmarksLocalStructure) " + + "SELECT * FROM \(TableBookmarksMirrorStructure) WHERE parent IN \(vars)" + + // Mark as overridden. + let markSQL = "UPDATE \(TableBookmarksMirror) SET is_overridden = 1 WHERE guid IN \(vars)" + return (sql: [overrideSQL, dropSQL, copySQL, markSQL], args: args) + } + + func getSQLToOverrideNonFolders(_ records: [GUID], atModifiedTime modified: Timestamp) -> (sql: [String], args: Args) { + log.info("Getting SQL to override \(records).") + if records.isEmpty { + return (sql: [], args: []) + } + + let vars = BrowserDB.varlist(records.count) + let args: Args = records.map { $0 } + + // Copy any that aren't overridden to the local table. + let overrideSQL = + "INSERT OR IGNORE INTO \(TableBookmarksLocal) " + + "(guid, type, date_added, bmkUri, title, parentid, parentName, feedUri, siteUri, pos," + + " description, tags, keyword, folderName, queryId, is_deleted, " + + " local_modified, sync_status, faviconID) " + + "SELECT guid, type, date_added, bmkUri, title, parentid, parentName, " + + "feedUri, siteUri, pos, description, tags, keyword, folderName, queryId, " + + "is_deleted, " + + "\(modified) AS local_modified, \(SyncStatus.changed.rawValue) AS sync_status, faviconID " + + "FROM \(TableBookmarksMirror) WHERE guid IN \(vars) AND is_overridden = 0" + + // Mark as overridden. + let markSQL = "UPDATE \(TableBookmarksMirror) SET is_overridden = 1 WHERE guid IN \(vars)" + return (sql: [overrideSQL, markSQL], args: args) + } + + /** + * Insert a bookmark into the specified folder. + * If the folder doesn't exist, or is deleted, insertion will fail. + * + * Preconditions: + * * `deferred` has not been filled. + * * this function is called inside a transaction that hasn't been finished. + * + * Postconditions: + * * `deferred` has been filled with success or failure. + * * the transaction will include any status/overlay changes necessary to save the bookmark. + * * the return value determines whether the transaction should be committed, and + * matches the success-ness of the Deferred. + * + * Sorry about the long line. If we break it, the indenting below gets crazy. + */ + fileprivate func insertBookmarkInTransaction(url: URL, title: String, favicon: Favicon?, intoFolder parent: GUID, withTitle parentTitle: String, conn: SQLiteDBConnection) throws { + + log.debug("Inserting bookmark in transaction on thread \(Thread.current)") + + // Keep going if this does not throw. + func change(_ sql: String, args: Args?, desc: String) throws { + try conn.executeChange(sql, withArgs: args) + } + + let urlString = url.absoluteString + let newGUID = Bytes.generateGUID() + let now = Date.now() + let parentArgs: Args = [parent] + + //// Insert the new bookmark and icon without touching structure. + var args: Args = [ + newGUID, + BookmarkNodeType.bookmark.rawValue, + now, + urlString, + title, + parent, + parentTitle, + Date.nowNumber(), + SyncStatus.new.rawValue, + ] + + let faviconID: Int? + + // Insert the favicon. + if let icon = favicon { + faviconID = self.favicons.insertOrUpdateFaviconInTransaction(icon, conn: conn) + } else { + faviconID = nil + } + + log.debug("Inserting bookmark with GUID \(newGUID) and specified icon \(faviconID ??? "nil").") + + // If the caller didn't provide an icon (and they usually don't!), + // do a reverse lookup in history. We use a view to make this simple. + let iconValue: String + if let faviconID = faviconID { + iconValue = "?" + args.append(faviconID ) + } else { + iconValue = "(SELECT iconID FROM \(ViewIconForURL) WHERE url = ?)" + args.append(urlString ) + } + + let insertSQL = "INSERT INTO \(TableBookmarksLocal) " + + "(guid, type, date_added, bmkUri, title, parentid, parentName, local_modified, sync_status, faviconID) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, \(iconValue))" + try change(insertSQL, args: args, desc: "Error inserting \(newGUID).") + + func bumpParentStatus(_ status: Int) throws { + let bumpSQL = "UPDATE \(TableBookmarksLocal) SET sync_status = \(status), local_modified = \(now) WHERE guid = ?" + try change(bumpSQL, args: parentArgs, desc: "Error bumping \(parent)'s modified time.") + } + + func overrideParentMirror() throws { + // We do this slightly tortured work so that we can reuse these queries + // in a different context. + let (sql, args) = getSQLToOverrideFolder(parent, atModifiedTime: now) + var generator = sql.makeIterator() + while let query = generator.next() { + try change(query, args: args, desc: "Error running overriding query.") + } + } + + //// Make sure our parent is overridden and appropriately bumped. + // See discussion here: + // Note that this isn't as obvious as you might think. We must: + let localStatusFactory: (SDRow) -> (Int, Bool) = { row in + let status = row["sync_status"] as! Int + let deleted = (row["is_deleted"] as! Int) != 0 + return (status, deleted) + } + + let overriddenFactory: (SDRow) -> Bool = { row in + row.getBoolean("is_overridden") + } + + // TODO: these can be merged into a single query. + let mirrorStatusSQL = "SELECT is_overridden FROM \(TableBookmarksMirror) WHERE guid = ?" + let localStatusSQL = "SELECT sync_status, is_deleted FROM \(TableBookmarksLocal) WHERE guid = ?" + let mirrorStatus = conn.executeQuery(mirrorStatusSQL, factory: overriddenFactory, withArgs: parentArgs)[0] + let localStatus = conn.executeQuery(localStatusSQL, factory: localStatusFactory, withArgs: parentArgs)[0] + + let parentExistsInMirror = mirrorStatus != nil + let parentExistsLocally = localStatus != nil + + // * Figure out if we were already overridden. We only want to re-clone + // if we weren't. + if !parentExistsLocally { + if !parentExistsInMirror { + throw DatabaseError(description: "Folder \(parent) doesn't exist in either mirror or local.") + } + // * Mark the parent folder as overridden if necessary. + // Overriding the parent involves copying the parent's structure, so that + // we can amend it, but also the parent's row itself so that we know it's + // changed. + try overrideParentMirror() + } else { + let (status, deleted) = localStatus! + if deleted { + throw DatabaseError(description: "Local folder \(parent) is deleted.") + } + + // * Bump the overridden parent's modified time. We already copied its + // structure and values, and if it's in the local table it'll either + // already be New or Changed. + + if let syncStatus = SyncStatus(rawValue: status) { + switch syncStatus { + case .synced: + log.debug("We don't expect folders to ever be marked as Synced.") + try bumpParentStatus(SyncStatus.changed.rawValue) + case .new: + fallthrough + case .changed: + // Leave it marked as new or changed, but bump the timestamp. + try bumpParentStatus(syncStatus.rawValue) + } + } else { + log.warning("Local folder marked with unknown state \(status). This should never occur.") + try bumpParentStatus(SyncStatus.changed.rawValue) + } + } + + /// Add the new bookmark as a child in the modified local structure. + // We always append the new row: after insertion, the new item will have the largest index. + let newIndex = "(SELECT (COALESCE(MAX(idx), -1) + 1) AS newIndex FROM \(TableBookmarksLocalStructure) WHERE parent = ?)" + let structureSQL = "INSERT INTO \(TableBookmarksLocalStructure) (parent, child, idx) " + + "VALUES (?, ?, \(newIndex))" + let structureArgs: Args = [parent, newGUID, parent] + + try change(structureSQL, args: structureArgs, desc: "Error adding new item \(newGUID) to local structure.") + } + + /** + * Assumption: the provided folder GUID exists in either the local table or the mirror table. + */ + func insertBookmark(_ url: URL, title: String, favicon: Favicon?, intoFolder parent: GUID, withTitle parentTitle: String) -> Success { + log.debug("Inserting bookmark task on thread \(Thread.current)") + return db.transaction { conn -> Void in + try self.insertBookmarkInTransaction(url: url, title: title, favicon: favicon, intoFolder: parent, withTitle: parentTitle, conn: conn) + } + } +} + +private extension BookmarkMirrorItem { + // Let's say the buffer structure table looks like this: + // =============================== + // | parent | child | idx | + // ------------------------------- + // | aaaa | bbbb | 5 | + // | aaaa | cccc | 8 | + // | aaaa | dddd | 19 | + // =============================== + // And the self.children array has 5 children (2 new to insert). + // Then this function should be called with offset = 3 and nextIdx = 20 + func getChildrenArgs(offset: Int = 0, nextIdx: Int = 0) -> [Args] { + // Only folders have children, and we manage roots ourselves. + if self.type != .folder || + self.guid == BookmarkRoots.RootGUID { + return [] + } + let parent = self.guid + var idx = nextIdx + return self.children?.suffix(from: offset).map { child in + let ret: Args = [parent, child, idx] + idx += 1 + return ret + } ?? [] + } + + func getUpdateOrInsertArgs() -> Args { + let args: Args = [ + self.type.rawValue , + self.dateAdded, + self.serverModified, + self.isDeleted ? 1 : 0 , + self.hasDupe ? 1 : 0, + self.parentID, + self.parentName ?? "", // Workaround for dirty data before Bug 1318414. + self.feedURI, + self.siteURI, + self.pos, + self.title, + self.description, + self.bookmarkURI, + self.tags, + self.keyword, + self.folderName, + self.queryID, + self.guid, + ] + + return args + } +} + +private func deleteStructureForGUIDs(_ guids: [GUID], fromTable table: String, connection: SQLiteDBConnection, withMaxVars maxVars: Int=BrowserDB.MaxVariableNumber) throws { + log.debug("Deleting \(guids.count) parents from \(table).") + let chunks = chunk(guids, by: maxVars) + for chunk in chunks { + let delStructure = "DELETE FROM \(table) WHERE parent IN \(BrowserDB.varlist(chunk.count))" + + let args: Args = chunk.flatMap { $0 } + try connection.executeChange(delStructure, withArgs: args) + } +} + +private func insertStructureIntoTable(_ table: String, connection: SQLiteDBConnection, children: [Args], maxVars: Int) throws { + if children.isEmpty { + return + } + + // Insert the new structure rows. This uses three vars per row. + let maxRowsPerInsert: Int = maxVars / 3 + let chunks = chunk(children, by: maxRowsPerInsert) + for chunk in chunks { + log.verbose("Inserting \(chunk.count)…") + let childArgs: Args = chunk.flatMap { $0 } // Flatten [[a, b, c], [...]] into [a, b, c, ...]. + let ins = "INSERT INTO \(table) (parent, child, idx) VALUES " + + Array(repeating: "(?, ?, ?)", count: chunk.count).joined(separator: ", ") + log.debug("Inserting \(chunk.count) records (out of \(children.count)).") + try connection.executeChange(ins, withArgs: childArgs) + } +} + +/** + * This stores incoming records in a buffer. + * When appropriate, the buffer is merged with the mirror and local storage + * in the DB. + */ +open class SQLiteBookmarkBufferStorage: BookmarkBufferStorage { + let db: BrowserDB + + public init(db: BrowserDB) { + self.db = db + } + + open func synchronousBufferCount() -> Int? { + return self.db.runQuery("SELECT COUNT(*) FROM \(TableBookmarksBuffer)", args: nil, factory: IntFactory).value.successValue?[0] + } + + public func getUpstreamRecordCount() -> Deferred { + let sql = + "SELECT (SELECT COUNT(*) FROM \(TableBookmarksBuffer)) + " + + "(SELECT COUNT(*) FROM \(TableBookmarksMirror) WHERE is_overridden = 0) " + + "AS c" + + return self.db.runQuery(sql, args: nil, factory: IntFactory).bind { result in + return Deferred(value: result.successValue?[0]!) + } + } + + /** + * Remove child records for any folders that've been deleted or are empty. + */ + fileprivate func deleteChildrenInTransactionWithGUIDs(_ guids: [GUID], connection: SQLiteDBConnection, withMaxVars maxVars: Int=BrowserDB.MaxVariableNumber) throws { + try deleteStructureForGUIDs(guids, fromTable: TableBookmarksBufferStructure, connection: connection, withMaxVars: maxVars) + } + + open func isEmpty() -> Deferred> { + return self.db.queryReturnsNoResults("SELECT 1 FROM \(TableBookmarksBuffer)") + } + + /** + * This is a little gnarly because our DB access layer is rough. + * Within a single transaction, we walk the list of items, attempting to update + * and inserting if the update failed. (TODO: batch the inserts!) + * Once we've added all of the records, we flatten all of their children + * into big arg lists and hard-update the structure table. + */ + open func applyRecords(_ records: [BookmarkMirrorItem]) -> Success { + return self.applyRecords(records, withMaxVars: BrowserDB.MaxVariableNumber) + } + + open func applyRecords(_ records: [BookmarkMirrorItem], withMaxVars maxVars: Int) -> Success { + let guids = records.map { $0.guid } + let deleted = records.filter { $0.isDeleted }.map { $0.guid } + let values = records.map { $0.getUpdateOrInsertArgs() } + let children = records.filter { !$0.isDeleted }.flatMap { $0.getChildrenArgs() } + let folders = records.filter { $0.type == BookmarkNodeType.folder }.map { $0.guid } + + return db.transaction { conn -> Void in + // These have the same values in the same order. + let update = + "UPDATE \(TableBookmarksBuffer) SET " + + "type = ?, date_added = ?, server_modified = ?, is_deleted = ?, " + + "hasDupe = ?, parentid = ?, parentName = ?, " + + "feedUri = ?, siteUri = ?, pos = ?, title = ?, " + + "description = ?, bmkUri = ?, tags = ?, keyword = ?, " + + "folderName = ?, queryId = ? " + + "WHERE guid = ?" + + // We used to use INSERT OR IGNORE here, but it muffles legitimate errors. The only + // real use for that is/was to catch duplicates, but the UPDATE we run first should + // serve that purpose just as well. + let insert = + "INSERT INTO \(TableBookmarksBuffer) " + + "(type, date_added, server_modified, is_deleted, hasDupe, parentid, parentName, " + + "feedUri, siteUri, pos, title, description, bmkUri, tags, keyword, folderName, queryId, guid) " + + "VALUES " + + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + + for args in values { + try conn.executeChange(update, withArgs: args) + + if conn.numberOfRowsModified > 0 { + continue + } + + try conn.executeChange(insert, withArgs: args) + } + + // Delete existing structure for any folders we've seen. We always trust the folders, + // not the children's parent pointers, so we do this here: we'll insert their current + // children right after, when we process the child structure rows. + // We only drop the child structure for deleted folders, not the record itself. + // Deleted records stay in the buffer table so that we know about the deletion + // when we do a real sync! + + log.debug("\(folders.count) folders and \(deleted.count) deleted maybe-folders to drop from buffer structure table.") + + try self.deleteChildrenInTransactionWithGUIDs(folders + deleted, connection: conn) + + // (Re-)insert children in chunks. + log.debug("Inserting \(children.count) children.") + try insertStructureIntoTable(TableBookmarksBufferStructure, connection: conn, children: children, maxVars: maxVars) + + // Drop pending deletions of items we just received. + // In practice that means we have made the choice that we will always + // discard local deletions if there was a modification or a deletion made remotely. + log.debug("Deleting \(guids.count) pending deletions.") + let chunks = chunk(guids, by: BrowserDB.MaxVariableNumber) + for chunk in chunks { + let delPendingDeletions = "DELETE FROM \(TablePendingBookmarksDeletions) WHERE id IN \(BrowserDB.varlist(chunk.count))" + + let args: Args = chunk.flatMap { $0 } + try conn.executeChange(delPendingDeletions, withArgs: args) + } + } + } + + open func doneApplyingRecordsAfterDownload() -> Success { + self.db.checkpoint() + return succeed() + } +} + +extension SQLiteBookmarkBufferStorage: BufferItemSource { + public func getBufferItemWithGUID(_ guid: GUID) -> Deferred> { + return self.db.getMirrorItemFromTable(TableBookmarksBuffer, guid: guid) + } + + public func getBufferItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.db.getMirrorItemsFromTable(TableBookmarksBuffer, guids: guids) + } + + public func getBufferChildrenGUIDsForParent(_ guid: GUID) -> Deferred> { + return self.getChildrenGUIDsOf(guid) + } + + public func prefetchBufferItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + log.debug("Not implemented.") + return succeed() + } +} + +extension BrowserDB { + fileprivate func getMirrorItemFromTable(_ table: String, guid: GUID) -> Deferred> { + let args: Args = [guid] + let sql = "SELECT * FROM \(table) WHERE guid = ?" + return self.runQuery(sql, args: args, factory: BookmarkFactory.mirrorItemFactory) + >>== { cursor in + guard let item = cursor[0] else { + return deferMaybe(DatabaseError(description: "Expected to find \(guid) in \(table) but did not.")) + } + return deferMaybe(item) + } + } + + fileprivate func getMirrorItemsFromTable(_ table: String, guids: T) -> Deferred> where T.Iterator.Element == GUID { + var acc: [GUID: BookmarkMirrorItem] = [:] + func accumulate(_ args: Args) -> Success { + let sql = "SELECT * FROM \(table) WHERE guid IN \(BrowserDB.varlist(args.count))" + return self.runQuery(sql, args: args, factory: BookmarkFactory.mirrorItemFactory) + >>== { cursor in + cursor.forEach { row in + guard let row = row else { return } // Oh, Cursor. + acc[row.guid] = row + } + return succeed() + } + } + + let args: Args = guids.map { $0 } + if args.count < BrowserDB.MaxVariableNumber { + return accumulate(args) >>> { deferMaybe(acc) } + } + + let chunks = chunk(args, by: BrowserDB.MaxVariableNumber) + return walk(chunks.lazy.map { Array($0) }, f: accumulate) + >>> { deferMaybe(acc) } + } +} + +extension MergedSQLiteBookmarks: BookmarkBufferStorage { + public func synchronousBufferCount() -> Int? { + return self.buffer.synchronousBufferCount() + } + + public func getUpstreamRecordCount() -> Deferred { + return self.buffer.getUpstreamRecordCount() + } + + public func isEmpty() -> Deferred> { + return self.buffer.isEmpty() + } + + public func applyRecords(_ records: [BookmarkMirrorItem]) -> Success { + return self.buffer.applyRecords(records) + } + + public func doneApplyingRecordsAfterDownload() -> Success { + // It doesn't really matter which one we checkpoint -- they're both backed by the same DB. + return self.buffer.doneApplyingRecordsAfterDownload() + } + + public func validate() -> Success { + return self.buffer.validate() + } + + public func getBufferedDeletions() -> Deferred> { + return self.buffer.getBufferedDeletions() + } + + public func applyBufferCompletionOp(_ op: BufferCompletionOp, itemSources: ItemSources) -> Success { + return self.buffer.applyBufferCompletionOp(op, itemSources: itemSources) + } +} + +extension MergedSQLiteBookmarks: BufferItemSource { + public func getBufferItemWithGUID(_ guid: GUID) -> Deferred> { + return self.buffer.getBufferItemWithGUID(guid) + } + + public func getBufferItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.buffer.getBufferItemsWithGUIDs(guids) + } + + public func getBufferChildrenGUIDsForParent(_ guid: GUID) -> Deferred> { + return self.buffer.getChildrenGUIDsOf(guid) + } + + public func prefetchBufferItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return self.buffer.prefetchBufferItemsWithGUIDs(guids) + } +} + +extension MergedSQLiteBookmarks: MirrorItemSource { + public func getMirrorItemWithGUID(_ guid: GUID) -> Deferred> { + return self.local.getMirrorItemWithGUID(guid) + } + + public func getMirrorItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.local.getMirrorItemsWithGUIDs(guids) + } + + public func prefetchMirrorItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return self.local.prefetchMirrorItemsWithGUIDs(guids) + } +} + +extension MergedSQLiteBookmarks: LocalItemSource { + public func getLocalItemWithGUID(_ guid: GUID) -> Deferred> { + return self.local.getLocalItemWithGUID(guid) + } + + public func getLocalItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + return self.local.getLocalItemsWithGUIDs(guids) + } + + public func prefetchLocalItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return self.local.prefetchLocalItemsWithGUIDs(guids) + } +} + +extension MergedSQLiteBookmarks: ShareToDestination { + public func shareItem(_ item: ShareItem) -> Success { + return self.local.shareItem(item) + } +} + +// Not actually implementing SyncableBookmarks, just a utility for MergedSQLiteBookmarks to do so. +extension SQLiteBookmarks { + public func isUnchanged() -> Deferred> { + return self.db.queryReturnsNoResults("SELECT 1 FROM \(TableBookmarksLocal)") + } + + // Retrieve all the local bookmarks that are not present remotely in order to avoid merge logic later. + public func getLocalBookmarksModifications(limit: Int) -> Deferred> { + let deletionsQuery = + "SELECT id FROM \(TablePendingBookmarksDeletions) " + + "LIMIT ?" + let deletionsArgs: Args = [limit] + + return db.runQuery(deletionsQuery, args: deletionsArgs, factory: StringFactory) >>== { + let deletedGUIDs = $0.asArray() + let newLimit = limit - deletedGUIDs.count + + let additionsQuery = + "SELECT * FROM \(TableBookmarksLocal) AS bookmarks " + + "WHERE type = \(BookmarkNodeType.bookmark.rawValue) AND sync_status = \(SyncStatus.new.rawValue) AND parentID = ? " + + "AND NOT EXISTS (SELECT 1 FROM \(TableBookmarksBuffer) buf WHERE buf.guid = bookmarks.guid) " + + "LIMIT ?" + let additionsArgs: Args = [BookmarkRoots.MobileFolderGUID, newLimit] + + return self.db.runQuery(additionsQuery, args: additionsArgs, factory: BookmarkFactory.mirrorItemFactory) >>== { + return deferMaybe((deletedGUIDs, $0.asArray())) + } + } + } + + public func getLocalDeletions() -> Deferred> { + let sql = + "SELECT guid, local_modified FROM \(TableBookmarksLocal) " + + "WHERE is_deleted = 1" + + return self.db.runQuery(sql, args: nil, factory: { ($0["guid"] as! GUID, $0.getTimestamp("local_modified")!) }) + >>== { deferMaybe($0.asArray()) } + } +} + +extension MergedSQLiteBookmarks: SyncableBookmarks { + public func isUnchanged() -> Deferred> { + return self.local.isUnchanged() + } + + public func getLocalBookmarksModifications(limit: Int) -> Deferred> { + return self.local.getLocalBookmarksModifications(limit: limit) + } + + public func getLocalDeletions() -> Deferred> { + return self.local.getLocalDeletions() + } + + public func treeForMirror() -> Deferred> { + return self.local.treeForMirror() + } + + public func treesForEdges() -> Deferred> { + return self.local.treeForLocal() >>== { local in + return self.local.treeForBuffer() >>== { buffer in + return deferMaybe((local: local, buffer: buffer)) + } + } + } +} + +// MARK: - Validation of buffer contents. + +// Note that these queries tend to not have exceptions for deletions. +// That's because a record can't be deleted in isolation -- if it's +// deleted its parent should be changed, too -- and so our views will +// correctly reflect that. We'll have updated rows in the structure table, +// and updated values -- and thus a complete override -- for the parent and +// the deleted child. +private let allBufferStructuresReferToRecords = [ +"SELECT s.child AS pointee, s.parent AS pointer FROM", +ViewBookmarksBufferStructureOnMirror, +"s LEFT JOIN", +ViewBookmarksBufferOnMirror, +"b ON b.guid = s.child WHERE b.guid IS NULL", +].joined(separator: " ") + +private let allNonDeletedBufferRecordsAreInStructure = [ +"SELECT b.guid AS missing, b.parentid AS parent FROM", +ViewBookmarksBufferOnMirror, "b LEFT JOIN", +ViewBookmarksBufferStructureOnMirror, +"s ON b.guid = s.child WHERE s.child IS NULL AND", +"b.is_deleted IS 0 AND b.parentid IS NOT '\(BookmarkRoots.RootGUID)'", +].joined(separator: " ") + +private let allRecordsAreChildrenOnce = [ +"SELECT s.child FROM", +ViewBookmarksBufferStructureOnMirror, +"s INNER JOIN (", +"SELECT child, COUNT(*) AS dupes FROM", ViewBookmarksBufferStructureOnMirror, +"GROUP BY child HAVING dupes > 1", +") i ON s.child = i.child", +].joined(separator: " ") + +private let bufferParentidMatchesStructure = [ +"SELECT b.guid, b.parentid, s.parent, s.child, s.idx FROM", +TableBookmarksBuffer, "b JOIN", TableBookmarksBufferStructure, +"s ON b.guid = s.child WHERE b.is_deleted IS 0 AND b.parentid IS NOT s.parent", +].joined(separator: " ") + +public enum BufferInconsistency { + case missingValues + case missingStructure + case overlappingStructure + case parentIDDisagreement + + public var query: String { + switch self { + case .missingValues: + return allBufferStructuresReferToRecords + case .missingStructure: + return allNonDeletedBufferRecordsAreInStructure + case .overlappingStructure: + return allRecordsAreChildrenOnce + case .parentIDDisagreement: + return bufferParentidMatchesStructure + } + } + + public var trackingEvent: String { + switch self { + case .missingValues: + return "missingvalues" + case .missingStructure: + return "missingstructure" + case .overlappingStructure: + return "overlappingstructure" + case .parentIDDisagreement: + return "parentiddisagreement" + } + } + + public var description: String { + switch self { + case .missingValues: + return "Not all buffer structures refer to records." + case .missingStructure: + return "Not all buffer records are in structure." + case .overlappingStructure: + return "Some buffer structures refer to the same records." + case .parentIDDisagreement: + return "Some buffer record parent IDs don't match structure." + } + } + + var idsFactory: (SDRow) -> [String] { + switch self { + case .missingValues: + return self.getConcernedIDs(colNames: ["pointee", "pointer"]) + case .missingStructure: + return self.getConcernedIDs(colNames: ["missing", "parent"]) + case .overlappingStructure: + return self.getConcernedIDs(colNames: ["child"]) + case .parentIDDisagreement: + return self.getConcernedIDs(colNames: ["guid", "parentid", "parent", "child"]) + } + } + + private func getConcernedIDs(colNames: [String]) -> ((SDRow) -> [String]) { + return { (row: SDRow) in + colNames.flatMap({ row[$0] as? String}) + } + } + + public static let all: [BufferInconsistency] = [.missingValues, .missingStructure, .overlappingStructure, .parentIDDisagreement] +} + +public struct BufferInvalidError: MaybeErrorType { + public let description = "Bookmarks buffer contains invalid data" + public let inconsistencies: [BufferInconsistency: [GUID]] + public let validationDuration: Int64 + + public init(inconsistencies: [BufferInconsistency: [GUID]], validationDuration: Int64) { + self.inconsistencies = inconsistencies + self.validationDuration = validationDuration + } +} + +extension SQLiteBookmarkBufferStorage { + public func validate() -> Success { + func idsFor(inconsistency inc: BufferInconsistency) -> () -> Deferred> { + return { + self.db.runQuery(inc.query, args: nil, factory: inc.idsFactory) + >>== { deferMaybe((type: inc, ids: $0.asArray().reduce([], +))) } + } + } + + let start = Date.now() + let ops = BufferInconsistency.all.map { idsFor(inconsistency: $0) } + return accumulate(ops) >>== { results in + var inconsistencies = [BufferInconsistency: [GUID]]() + results.forEach { type, ids in + guard !ids.isEmpty else { return } + inconsistencies[type] = ids + } + + return inconsistencies.isEmpty ? succeed() : + deferMaybe(BufferInvalidError(inconsistencies: inconsistencies, validationDuration: Int64(Date.now() - start))) + } + } + + public func getBufferedDeletions() -> Deferred> { + let sql = + "SELECT guid, server_modified FROM \(TableBookmarksBuffer) " + + "WHERE is_deleted = 1" + + return self.db.runQuery(sql, args: nil, factory: { ($0["guid"] as! GUID, $0.getTimestamp("server_modified")!) }) + >>== { deferMaybe($0.asArray()) } + } +} + +extension SQLiteBookmarks { + fileprivate func structureQueryForTable(_ table: String, structure: String) -> String { + // We use a subquery so we get back rows for overridden folders, even when their + // children aren't in the shadowing table. + let sql = + "SELECT s.parent AS parent, s.child AS child, COALESCE(m.type, -1) AS type " + + "FROM \(structure) s LEFT JOIN \(table) m ON s.child = m.guid AND m.is_deleted IS NOT 1 " + + "ORDER BY s.parent, s.idx ASC" + return sql + } + + fileprivate func remainderQueryForTable(_ table: String, structure: String) -> String { + // This gives us value rows that aren't children of a folder. + // You might notice that these complementary LEFT JOINs are how you + // express a FULL OUTER JOIN in sqlite. + // We exclude folders here because if they have children, they'll appear + // in the structure query, and if they don't, they'll appear in the bottom + // half of this query. + let sql = + "SELECT m.guid AS guid, m.type AS type " + + "FROM \(table) m LEFT JOIN \(structure) s ON s.child = m.guid " + + "WHERE m.is_deleted IS NOT 1 AND m.type IS NOT \(BookmarkNodeType.folder.rawValue) AND s.child IS NULL " + + + "UNION ALL " + + + // This gives us folders with no children. + "SELECT m.guid AS guid, m.type AS type " + + "FROM \(table) m LEFT JOIN \(structure) s ON s.parent = m.guid " + + "WHERE m.is_deleted IS NOT 1 AND m.type IS \(BookmarkNodeType.folder.rawValue) AND s.parent IS NULL " + + return sql + } + + fileprivate func statusQueryForTable(_ table: String) -> String { + return "SELECT guid, is_deleted FROM \(table)" + } + + fileprivate func treeForTable(_ table: String, structure: String, alwaysIncludeRoots includeRoots: Bool) -> Deferred> { + // The structure query doesn't give us non-structural rows -- that is, if you + // make a value-only change to a record, and it's not otherwise mentioned by + // way of being a child of a structurally modified folder, it won't appear here at all. + // It also doesn't give us empty folders, because they have no children. + // We run a separate query to get those. + let structureSQL = self.structureQueryForTable(table, structure: structure) + let remainderSQL = self.remainderQueryForTable(table, structure: structure) + let statusSQL = self.statusQueryForTable(table) + + func structureFactory(_ row: SDRow) -> StructureRow { + let typeCode = row["type"] as! Int + let type = BookmarkNodeType(rawValue: typeCode) // nil if typeCode is invalid (e.g., -1). + return (parent: row["parent"] as! GUID, child: row["child"] as! GUID, type: type) + } + + func nonStructureFactory(_ row: SDRow) -> BookmarkTreeNode { + let guid = row["guid"] as! GUID + let typeCode = row["type"] as! Int + if let type = BookmarkNodeType(rawValue: typeCode) { + switch type { + case .folder: + return BookmarkTreeNode.folder(guid: guid, children: []) + default: + return BookmarkTreeNode.nonFolder(guid: guid) + } + } else { + return BookmarkTreeNode.unknown(guid: guid) + } + } + + func statusFactory(_ row: SDRow) -> (GUID, Bool) { + return (row["guid"] as! GUID, row.getBoolean("is_deleted")) + } + + return self.db.runQuery(statusSQL, args: nil, factory: statusFactory) + >>== { cursor in + var deleted = Set() + var modified = Set() + cursor.forEach { pair in + let (guid, del) = pair! // Oh, cursor. + if del { + deleted.insert(guid) + } else { + modified.insert(guid) + } + } + + return self.db.runQuery(remainderSQL, args: nil, factory: nonStructureFactory) + >>== { cursor in + let nonFoldersAndEmptyFolders = cursor.asArray() + return self.db.runQuery(structureSQL, args: nil, factory: structureFactory) + >>== { cursor in + let structureRows = cursor.asArray() + let tree = BookmarkTree.mappingsToTreeForStructureRows(structureRows, withNonFoldersAndEmptyFolders: nonFoldersAndEmptyFolders, withDeletedRecords: deleted, modifiedRecords: modified, alwaysIncludeRoots: includeRoots) + return deferMaybe(tree) + } + } + } + } + + public func treeForMirror() -> Deferred> { + return self.treeForTable(TableBookmarksMirror, structure: TableBookmarksMirrorStructure, alwaysIncludeRoots: true) + } + + public func treeForBuffer() -> Deferred> { + return self.treeForTable(TableBookmarksBuffer, structure: TableBookmarksBufferStructure, alwaysIncludeRoots: false) + } + + public func treeForLocal() -> Deferred> { + return self.treeForTable(TableBookmarksLocal, structure: TableBookmarksLocalStructure, alwaysIncludeRoots: false) + } +} + +// MARK: - Applying merge operations. + +public extension SQLiteBookmarkBufferStorage { + public func applyBufferCompletionOp(_ op: BufferCompletionOp, itemSources: ItemSources) -> Success { + log.debug("Marking buffer rows as applied.") + if op.isNoOp { + log.debug("Nothing to do.") + return succeed() + } + + var queries: [(sql: String, args: Args?)] = [] + op.processedBufferChanges.subsetsOfSize(BrowserDB.MaxVariableNumber).forEach { guids in + let varlist = BrowserDB.varlist(guids.count) + let args: Args = guids.map { $0 } + queries.append((sql: "DELETE FROM \(TableBookmarksBufferStructure) WHERE parent IN \(varlist)", args: args)) + queries.append((sql: "DELETE FROM \(TableBookmarksBuffer) WHERE guid IN \(varlist)", args: args)) + } + + return self.db.run(queries) + } + + public func getChildrenGUIDsOf(_ guid: GUID) -> Deferred> { + let sql = "SELECT child FROM \(TableBookmarksBufferStructure) WHERE parent = ? ORDER BY idx ASC" + let args: Args = [guid] + + return self.db.runQuery(sql, args: args, factory: StringFactory) >>== { deferMaybe($0.asArray()) } + } +} + +extension MergedSQLiteBookmarks { + public func applyLocalOverrideCompletionOp(_ op: LocalOverrideCompletionOp, itemSources: ItemSources) -> Success { + log.debug("Applying local op to merged.") + if op.isNoOp { + log.debug("Nothing to do.") + return succeed() + } + + // This is a little tortured because we want it all to happen in a single transaction. + // We walk through the accrued work items, applying them in the right order (e.g., structure + // then value). If at any point we fail, we abort, roll back the transaction by throwing. + return local.db.transaction { conn -> Void in + // So we can trample the DB in any order. + try conn.executeChange("PRAGMA defer_foreign_keys = ON") + + log.debug("Deleting \(op.mirrorItemsToDelete.count) mirror items.") + + try op.mirrorItemsToDelete.withSubsetsOfSize(BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let varlist = BrowserDB.varlist(guids.count) + + let sqlMirrorStructure = "DELETE FROM \(TableBookmarksMirrorStructure) WHERE parent IN \(varlist)" + try conn.executeChange(sqlMirrorStructure, withArgs: args) + + let sqlMirror = "DELETE FROM \(TableBookmarksMirror) WHERE guid IN \(varlist)" + try conn.executeChange(sqlMirror, withArgs: args) + } + + // Copy from other tables for simplicity. + // Do this *before* we throw away local and buffer changes! + // This is one reason why the local override step needs to be processed before the buffer is cleared. + try op.mirrorValuesToCopyFromBuffer.withSubsetsOfSize(BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let varlist = BrowserDB.varlist(guids.count) + let copySQL = [ + "INSERT OR REPLACE INTO \(TableBookmarksMirror)", + "(guid, type, date_added, parentid, parentName, feedUri, siteUri, pos, title, description,", + "bmkUri, tags, keyword, folderName, queryId, server_modified)", + "SELECT guid, type, date_added, parentid, parentName, feedUri, siteUri, pos, title, description,", + "bmkUri, tags, keyword, folderName, queryId, server_modified", + "FROM \(TableBookmarksBuffer)", + "WHERE guid IN", + varlist + ].joined(separator: " ") + + try conn.executeChange(copySQL, withArgs: args) + } + + try op.mirrorValuesToCopyFromLocal.withSubsetsOfSize(BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let varlist = BrowserDB.varlist(guids.count) + let copySQL = [ + "INSERT OR REPLACE INTO \(TableBookmarksMirror)", + "(guid, type, date_added, parentid, parentName, feedUri, siteUri, pos, title, description,", + "bmkUri, tags, keyword, folderName, queryId, faviconID, server_modified)", + "SELECT guid, type, date_added, parentid, parentName, feedUri, siteUri, pos, title, description,", + "bmkUri, tags, keyword, folderName, queryId, faviconID,", + + // This will be fixed up in batches after the initial copy. + "0 AS server_modified", + "FROM \(TableBookmarksLocal) WHERE guid IN", + varlist + ].joined(separator: " ") + + try conn.executeChange(copySQL, withArgs: args) + } + + try op.modifiedTimes.forEach { (time, guids) in + // This will never be too big: we upload in chunks + // smaller than 999! + precondition(guids.count < BrowserDB.MaxVariableNumber) + + log.debug("Swizzling server modified time to \(time) for \(guids.count) GUIDs.") + let args: Args = guids.map { $0 } + let varlist = BrowserDB.varlist(guids.count) + let updateSQL = [ + "UPDATE \(TableBookmarksMirror) SET server_modified = \(time)", + "WHERE guid IN", + varlist, + ].joined(separator: " ") + try conn.executeChange(updateSQL, withArgs: args) + } + + log.debug("Marking \(op.processedLocalChanges.count) local changes as processed.") + try op.processedLocalChanges.withSubsetsOfSize(BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let varlist = BrowserDB.varlist(guids.count) + + let sqlLocalStructure = "DELETE FROM \(TableBookmarksLocalStructure) WHERE parent IN \(varlist)" + try conn.executeChange(sqlLocalStructure, withArgs: args) + + let sqlLocal = "DELETE FROM \(TableBookmarksLocal) WHERE guid IN \(varlist)" + try conn.executeChange(sqlLocal, withArgs: args) + + // If the values change, we'll handle those elsewhere, but at least we need to mark these as non-overridden. + let sqlMirrorOverride = "UPDATE \(TableBookmarksMirror) SET is_overridden = 0 WHERE guid IN \(varlist)" + try conn.executeChange(sqlMirrorOverride, withArgs: args) + } + + if !op.mirrorItemsToUpdate.isEmpty { + let updateSQL = [ + "UPDATE \(TableBookmarksMirror) SET", + "type = ?, date_added = ?, server_modified = ?, is_deleted = ?,", + "hasDupe = ?, parentid = ?, parentName = ?,", + "feedUri = ?, siteUri = ?, pos = ?, title = ?,", + "description = ?, bmkUri = ?, tags = ?, keyword = ?,", + "folderName = ?, queryId = ?, is_overridden = 0", + "WHERE guid = ?", + ].joined(separator: " ") + + try op.mirrorItemsToUpdate.forEach { (_, mirrorItem) in + let args = mirrorItem.getUpdateOrInsertArgs() + try conn.executeChange(updateSQL, withArgs: args) + } + } + + if !op.mirrorItemsToInsert.isEmpty { + let insertSQL = [ + "INSERT OR IGNORE INTO \(TableBookmarksMirror) (", + "type, date_added, server_modified, is_deleted,", + "hasDupe, parentid, parentName,", + "feedUri, siteUri, pos, title,", + "description, bmkUri, tags, keyword,", + "folderName, queryId, guid", + "VALUES", + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + ].joined(separator: " ") + + try op.mirrorItemsToInsert.forEach { (_, mirrorItem) in + let args = mirrorItem.getUpdateOrInsertArgs() + try conn.executeChange(insertSQL, withArgs: args) + } + } + + if !op.mirrorStructures.isEmpty { + let structureRows = + op.mirrorStructures.flatMap { (parent, children) in + return children.enumerated().map { (idx, child) -> Args in + let vals: Args = [parent, child, idx] + return vals + } + } + + let parents = op.mirrorStructures.map { $0.0 } + try deleteStructureForGUIDs(parents, fromTable: TableBookmarksMirrorStructure, connection: conn) + try insertStructureIntoTable(TableBookmarksMirrorStructure, connection: conn, children: structureRows, maxVars: BrowserDB.MaxVariableNumber) + } + } + } + + public func applyBufferUpdatedCompletionOp(_ op: BufferUpdatedCompletionOp) -> Success { + log.debug("Applying buffer updates.") + if op.isNoOp { + log.debug("Nothing to do.") + return succeed() + } + + return local.db.transaction { conn -> Void in + // So we can trample the DB in any order. + try conn.executeChange("PRAGMA defer_foreign_keys = ON") + + try op.deletedValues.withSubsetsOfSize(BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let varlist = BrowserDB.varlist(guids.count) + + // This will leave the idx column sparse for the buffer children. + let sqlBufferStructure = "DELETE FROM \(TableBookmarksBufferStructure) WHERE child IN \(varlist)" + try conn.executeChange(sqlBufferStructure, withArgs: args) + + // This will also delete items from the pending deletions table on cascade. + let sqlBuffer = "DELETE FROM \(TableBookmarksBuffer) WHERE guid IN \(varlist)" + try conn.executeChange(sqlBuffer, withArgs: args) + } + + let insertSQL = [ + "INSERT OR IGNORE INTO \(TableBookmarksBuffer) (", + "type, date_added, server_modified, is_deleted,", + "hasDupe, parentid, parentName,", + "feedUri, siteUri, pos, title,", + "description, bmkUri, tags, keyword,", + "folderName, queryId, guid)", + "VALUES", + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + ].joined(separator: " ") + + let args = op.mobileRoot.getUpdateOrInsertArgs() + try conn.executeChange(insertSQL, withArgs: args) + + // We update server_modified in another operation because the first statement is an INSERT OR IGNORE + // and we can't turn that into a INSERT OR REPLACE because this will cascade delete children + // in the buffer structure table. + let updateMobileRootTimeSQL = [ + "UPDATE \(TableBookmarksBuffer) SET server_modified = \(op.modifiedTime)", + "WHERE guid = ?", + ].joined(separator: " ") + try conn.executeChange(updateMobileRootTimeSQL, withArgs: [op.mobileRoot.guid]) + + try op.bufferValuesToMoveFromLocal.withSubsetsOfSize(BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let varlist = BrowserDB.varlist(guids.count) + + let copySQL = [ + "INSERT OR REPLACE INTO \(TableBookmarksBuffer)", + "(guid, type, date_added, parentid, parentName, feedUri, siteUri, pos, title, description,", + "bmkUri, tags, keyword, folderName, queryId, server_modified)", + "SELECT guid, type, date_added, parentid, parentName, feedUri, siteUri, pos, title, description,", + "bmkUri, tags, keyword, folderName, queryId,", + "\(op.modifiedTime) AS server_modified", + "FROM \(TableBookmarksLocal) WHERE guid IN", + varlist + ].joined(separator: " ") + try conn.executeChange(copySQL, withArgs: args) + } + + try op.bufferValuesToMoveFromLocal.withSubsetsOfSize(BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let varlist = BrowserDB.varlist(guids.count) + + // This will leave the idx column sparse for the local children. + let sqlLocalStructure = "DELETE FROM \(TableBookmarksLocalStructure) WHERE child IN \(varlist)" + try conn.executeChange(sqlLocalStructure, withArgs: args) + + let sqlLocal = "DELETE FROM \(TableBookmarksLocal) WHERE guid IN \(varlist)" + try conn.executeChange(sqlLocal, withArgs: args) + } + + if op.bufferValuesToMoveFromLocal.count > 0 { + guard let allChildren = op.mobileRoot.children else { + let err = DatabaseError(description: "Absent mobileRoot children. Aborting.") + log.error("applyBufferUpdatedCompletionOp(_:) encountered error: \(err.localizedDescription)") + throw err + } + let offset = allChildren.count - op.bufferValuesToMoveFromLocal.count + + let sqlNextIdx = "SELECT (COALESCE(MAX(idx), -1) + 1) AS newIndex FROM \(TableBookmarksBufferStructure) WHERE parent = ?" + let nextIdxArgs: Args = [BookmarkRoots.MobileFolderGUID] + let nextIdx = conn.executeQuery(sqlNextIdx, factory: IntFactory, withArgs: nextIdxArgs).asArray()[0] + + let toInsertArgs = Array(op.mobileRoot.getChildrenArgs(offset: offset, nextIdx: nextIdx)) + try insertStructureIntoTable(TableBookmarksBufferStructure, connection: conn, children: toInsertArgs, maxVars: BrowserDB.MaxVariableNumber) + } + } + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteFavicons.swift b/mobile/ios/Storage/SQL/SQLiteFavicons.swift new file mode 100644 index 0000000000..63f43799d6 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteFavicons.swift @@ -0,0 +1,87 @@ +/* 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/. */ + +import Foundation +import Deferred +import Shared + +open class SQLiteFavicons { + let db: BrowserDB + + required public init(db: BrowserDB) { + self.db = db + } + + public func getFaviconIDQuery(url: String) -> (sql: String, args: Args?) { + var args: Args = [] + args.append(url) + return (sql: "SELECT id FROM \(TableFavicons) WHERE url = ? LIMIT 1", args: args) + } + + public func getInsertFaviconQuery(favicon: Favicon) -> (sql: String, args: Args?) { + var args: Args = [] + args.append(favicon.url) + args.append(favicon.width) + args.append(favicon.height) + args.append(favicon.date) + args.append(favicon.type.rawValue) + return (sql: "INSERT INTO \(TableFavicons) (url, width, height, date, type) VALUES (?,?,?,?,?)", args: args) + } + + public func getUpdateFaviconQuery(favicon: Favicon) -> (sql: String, args: Args?) { + var args = Args() + args.append(favicon.width) + args.append(favicon.height) + args.append(favicon.date) + args.append(favicon.type.rawValue) + args.append(favicon.url) + return (sql: "UPDATE \(TableFavicons) SET width = ?, height = ?, date = ?, type = ? WHERE url = ?", args: args) + } + + public func getCleanupFaviconsQuery() -> (sql: String, args: Args?) { + return (sql: "DELETE FROM \(TableFavicons) " + + "WHERE \(TableFavicons).id NOT IN (" + + "SELECT faviconID FROM \(TableFaviconSites) " + + "UNION ALL " + + "SELECT faviconID FROM \(TableBookmarksLocal) WHERE faviconID IS NOT NULL " + + "UNION ALL " + + "SELECT faviconID FROM \(TableBookmarksMirror) WHERE faviconID IS NOT NULL" + + ")", args: nil) + } + + public func insertOrUpdateFavicon(_ favicon: Favicon) -> Deferred> { + return db.withConnection { conn -> Int in + self.insertOrUpdateFaviconInTransaction(favicon, conn: conn) ?? 0 + } + } + + func insertOrUpdateFaviconInTransaction(_ favicon: Favicon, conn: SQLiteDBConnection) -> Int? { + let query = self.getFaviconIDQuery(url: favicon.url) + let cursor = conn.executeQuery(query.sql, factory: IntFactory, withArgs: query.args) + + if let id = cursor[0] { + let updateQuery = self.getUpdateFaviconQuery(favicon: favicon) + do { + try conn.executeChange(updateQuery.sql, withArgs: updateQuery.args) + } catch { + return nil + } + + return id + } + + let insertQuery = self.getInsertFaviconQuery(favicon: favicon) + do { + try conn.executeChange(insertQuery.sql, withArgs: insertQuery.args) + } catch { + return nil + } + + return conn.lastInsertedRowID + } + + public func cleanupFavicons() -> Success { + return self.db.run([getCleanupFaviconsQuery()]) + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteHistory.swift b/mobile/ios/Storage/SQL/SQLiteHistory.swift new file mode 100644 index 0000000000..6c6579a9c2 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteHistory.swift @@ -0,0 +1,1118 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger +import Deferred + +private let log = Logger.syncLogger +public let TopSiteCacheSize: Int32 = 16 + +class NoSuchRecordError: MaybeErrorType { + let guid: GUID + init(guid: GUID) { + self.guid = guid + } + var description: String { + return "No such record: \(guid)." + } +} + +private var ignoredSchemes = ["about"] + +public func isIgnoredURL(_ url: URL) -> Bool { + guard let scheme = url.scheme else { return false } + + if let _ = ignoredSchemes.index(of: scheme) { + return true + } + + if url.host == "localhost" { + return true + } + + return false +} + +public func isIgnoredURL(_ url: String) -> Bool { + if let url = URL(string: url) { + return isIgnoredURL(url) + } + + return false +} + +/* +// Here's the Swift equivalent of the below. +func simulatedFrecency(now: MicrosecondTimestamp, then: MicrosecondTimestamp, visitCount: Int) -> Double { + let ageMicroseconds = (now - then) + let ageDays = Double(ageMicroseconds) / 86400000000.0 // In SQL the .0 does the coercion. + let f = 100 * 225 / ((ageSeconds * ageSeconds) + 225) + return Double(visitCount) * max(1.0, f) +} +*/ + +// The constants in these functions were arrived at by utterly unscientific experimentation. + +func getRemoteFrecencySQL() -> String { + let visitCountExpression = "remoteVisitCount" + let now = Date.nowMicroseconds() + let microsecondsPerDay = 86_400_000_000.0 // 1000 * 1000 * 60 * 60 * 24 + let ageDays = "((\(now) - remoteVisitDate) / \(microsecondsPerDay))" + + return "\(visitCountExpression) * max(1, 100 * 110 / (\(ageDays) * \(ageDays) + 110))" +} + +func getLocalFrecencySQL() -> String { + let visitCountExpression = "((2 + localVisitCount) * (2 + localVisitCount))" + let now = Date.nowMicroseconds() + let microsecondsPerDay = 86_400_000_000.0 // 1000 * 1000 * 60 * 60 * 24 + let ageDays = "((\(now) - localVisitDate) / \(microsecondsPerDay))" + + return "\(visitCountExpression) * max(2, 100 * 225 / (\(ageDays) * \(ageDays) + 225))" +} + +fileprivate func computeWordsWithFilter(_ filter: String) -> [String] { + // Split filter on whitespace. + let words = filter.components(separatedBy: .whitespaces) + + // Remove substrings and duplicates. + // TODO: this can probably be improved. + return words.enumerated().filter({ (index: Int, word: String) in + if word.isEmpty { + return false + } + + for i in words.indices where i != index { + if words[i].range(of: word) != nil && (words[i].count != word.count || i < index) { + return false + } + } + + return true + }).map({ $0.1 }) +} + +/** + * Take input like "foo bar" and a template fragment and produce output like + * + * ((x.y LIKE ?) OR (x.z LIKE ?)) AND ((x.y LIKE ?) OR (x.z LIKE ?)) + * + * with args ["foo", "foo", "bar", "bar"]. + */ +internal func computeWhereFragmentWithFilter(_ filter: String, perWordFragment: String, perWordArgs: (String) -> Args) -> (fragment: String, args: Args) { + precondition(!filter.isEmpty) + + let words = computeWordsWithFilter(filter) + return computeWhereFragmentForWords(words, perWordFragment: perWordFragment, perWordArgs: perWordArgs) +} + +internal func computeWhereFragmentForWords(_ words: [String], perWordFragment: String, perWordArgs: (String) -> Args) -> (fragment: String, args: Args) { + assert(!words.isEmpty) + + let fragment = Array(repeating: perWordFragment, count: words.count).joined(separator: " AND ") + let args = words.flatMap(perWordArgs) + return (fragment, args) +} + +extension SDRow { + func getTimestamp(_ column: String) -> Timestamp? { + return (self[column] as? NSNumber)?.uint64Value + } + + func getBoolean(_ column: String) -> Bool { + if let val = self[column] as? Int { + return val != 0 + } + return false + } +} + +/** + * The sqlite-backed implementation of the history protocol. + */ +open class SQLiteHistory { + let db: BrowserDB + let favicons: SQLiteFavicons + let prefs: Prefs + let clearTopSitesQuery: (String, Args?) = ("DELETE FROM \(TableCachedTopSites)", nil) + + required public init(db: BrowserDB, prefs: Prefs) { + self.db = db + self.favicons = SQLiteFavicons(db: self.db) + self.prefs = prefs + } +} + +private let topSitesQuery = "SELECT \(TableCachedTopSites).*, \(TablePageMetadata).provider_name FROM \(TableCachedTopSites) LEFT OUTER JOIN \(TablePageMetadata) ON \(TableCachedTopSites).url = \(TablePageMetadata).site_url ORDER BY frecencies DESC LIMIT (?)" + +/** + * The init for this will perform the heaviest part of the frecency query + * and create a temporary table that can be queried quickly. Currently this accounts for + * >75% of the query time. + * The scope/lifetime of this object is important as the data is 'frozen' until a new instance is created. + */ +fileprivate struct SQLiteFrecentHistory : FrecentHistory { + private let db: BrowserDB + private let prefs: Prefs + + init(db: BrowserDB, prefs: Prefs) { + self.db = db + self.prefs = prefs + + let empty = "DELETE FROM \(TempTableAwesomebarBookmarks)" + let create = + "CREATE TEMP TABLE IF NOT EXISTS \(TempTableAwesomebarBookmarks) (" + + "guid TEXT, url TEXT, title TEXT, description TEXT, " + + "faviconID INT, visitDate DATE)" + let insert = + "INSERT INTO \(TempTableAwesomebarBookmarks) " + + "SELECT b.guid AS guid, b.url AS url, b.title AS title, " + + "b.description AS description, b.faviconID AS faviconID, " + + "h.visitDate AS visitDate " + + "FROM \(ViewAwesomebarBookmarks) b " + + "LEFT JOIN \(ViewHistoryVisits) h ON b.url = h.url" + + let _ = db.transaction { connection in + try connection.executeChange(create) + try connection.executeChange(empty) + try connection.executeChange(insert) + } + } + + func getSites(whereURLContains filter: String?, historyLimit limit: Int, bookmarksLimit: Int) -> Deferred>> { + let factory = SQLiteHistory.basicHistoryColumnFactory + + let params = FrecencyQueryParams.urlCompletion(bookmarksLimit: bookmarksLimit, whereURLContains: filter ?? "", groupClause: "GROUP BY historyID ") + let (query, args) = getFrecencyQuery(historyLimit: limit, params: params) + + return db.runQuery(query, args: args, factory: factory) + } + + func updateTopSitesCacheQuery() -> (String, Args?) { + let limit = Int(prefs.intForKey(PrefsKeys.KeyTopSitesCacheSize) ?? TopSiteCacheSize) + + let (whereData, groupBy) = topSiteClauses() + let params = FrecencyQueryParams.topSites(groupClause: groupBy, whereData: whereData) + let (frecencyQuery, args) = getFrecencyQuery(historyLimit: limit, params: params) + + // We must project, because we get bookmarks in these results. + let insertQuery = [ + "WITH siteFrecency AS (\(frecencyQuery))", + "INSERT INTO \(TableCachedTopSites)", + "SELECT historyID, url, title, guid, domain_id, domain,", + "localVisitDate, remoteVisitDate, localVisitCount, remoteVisitCount,", + "iconID, iconURL, iconDate, iconType, iconWidth, frecencies", + "FROM (SELECT * FROM", + "siteFrecency LEFT JOIN view_history_id_favicon ON", + "siteFrecency.historyID = view_history_id_favicon.id)" + ].joined(separator: " ") + + // @TODO: remove the LEFT JOIN to fill in the icon columns, it is just there because the code has been doing this historically. + // Those favicon data columns are not used, and view_history_id_favicon appears to only contain null data. + + return (insertQuery, args) + } + + private func topSiteClauses() -> (String, String) { + let whereData = "(\(TableDomains).showOnTopSites IS 1) AND (\(TableDomains).domain NOT LIKE 'r.%') AND (\(TableDomains).domain NOT LIKE 'google.%') " + let groupBy = "GROUP BY domain_id " + return (whereData, groupBy) + } + + + enum FrecencyQueryParams { + case urlCompletion(bookmarksLimit: Int, whereURLContains: String, groupClause: String) + case topSites(groupClause: String, whereData: String) + } + + private func getFrecencyQuery(historyLimit: Int, params: FrecencyQueryParams) -> (String, Args?) { + let bookmarksLimit: Int + let groupClause: String + let whereData: String? + let urlFilter: String? + + switch params { + case let .urlCompletion(bmLimit, filter, group): + bookmarksLimit = bmLimit + urlFilter = filter + groupClause = group + whereData = nil + case let .topSites(group, whereArg): + bookmarksLimit = 0 + urlFilter = nil + whereData = whereArg + groupClause = group + } + + let includeBookmarks = bookmarksLimit > 0 + let localFrecencySQL = getLocalFrecencySQL() + let remoteFrecencySQL = getRemoteFrecencySQL() + let sixMonthsInMicroseconds: UInt64 = 15_724_800_000_000 // 182 * 1000 * 1000 * 60 * 60 * 24 + let sixMonthsAgo = Date.nowMicroseconds() - sixMonthsInMicroseconds + + let args: Args + let whereClause: String + let whereFragment = (whereData == nil) ? "" : " AND (\(whereData!))" + + if let urlFilter = urlFilter?.trimmingCharacters(in: .whitespaces), !urlFilter.isEmpty { + let perWordFragment = "((url LIKE ?) OR (title LIKE ?))" + let perWordArgs: (String) -> Args = { ["%\($0)%", "%\($0)%"] } + let (filterFragment, filterArgs) = computeWhereFragmentWithFilter(urlFilter, perWordFragment: perWordFragment, perWordArgs: perWordArgs) + + // No deleted item has a URL, so there is no need to explicitly add that here. + whereClause = "WHERE (\(filterFragment))\(whereFragment)" + + if includeBookmarks { + // We'll need them twice: once to filter history, and once to filter bookmarks. + args = filterArgs + filterArgs + } else { + args = filterArgs + } + } else { + whereClause = " WHERE (\(TableHistory).is_deleted = 0)\(whereFragment)" + args = [] + } + + // Innermost: grab history items and basic visit/domain metadata. + var ungroupedSQL = + "SELECT \(TableHistory).id AS historyID, \(TableHistory).url AS url, \(TableHistory).title AS title, \(TableHistory).guid AS guid, domain_id, domain" + + ", COALESCE(max(case \(TableVisits).is_local when 1 then \(TableVisits).date else 0 end), 0) AS localVisitDate" + + ", COALESCE(max(case \(TableVisits).is_local when 0 then \(TableVisits).date else 0 end), 0) AS remoteVisitDate" + + ", COALESCE(sum(\(TableVisits).is_local), 0) AS localVisitCount" + + ", COALESCE(sum(case \(TableVisits).is_local when 1 then 0 else 1 end), 0) AS remoteVisitCount" + + " FROM \(TableHistory) " + + "INNER JOIN \(TableDomains) ON \(TableDomains).id = \(TableHistory).domain_id " + + "INNER JOIN \(TableVisits) ON \(TableVisits).siteID = \(TableHistory).id " + + if includeBookmarks { + ungroupedSQL.append("LEFT JOIN \(ViewAllBookmarks) on \(ViewAllBookmarks).url = \(TableHistory).url ") + } + ungroupedSQL.append(whereClause.replacingOccurrences(of: "url", with: "\(TableHistory).url").replacingOccurrences(of: "title", with: "\(TableHistory).title")) + if includeBookmarks { + ungroupedSQL.append(" AND \(ViewAllBookmarks).url IS NULL") + } + ungroupedSQL.append(" GROUP BY historyID") + + // Next: limit to only those that have been visited at all within the last six months. + // (Don't do that in the innermost: we want to get the full count, even if some visits are older.) + // Discard all but the 1000 most frecent. + // Compute and return the frecency for all 1000 URLs. + let frecenciedSQL = + "SELECT *, (\(localFrecencySQL) + \(remoteFrecencySQL)) AS frecency" + + " FROM (" + ungroupedSQL + ")" + + " WHERE (" + + "((localVisitCount > 0) OR (remoteVisitCount > 0)) AND " + // Eliminate dead rows from coalescing. + "((localVisitDate > \(sixMonthsAgo)) OR (remoteVisitDate > \(sixMonthsAgo)))" + // Exclude really old items. + ") ORDER BY frecency DESC" + + " LIMIT 1000" // Don't even look at a huge set. This avoids work. + + // Next: merge by domain and select the URL with the max frecency of a domain, ordering by that sum frecency and reducing to a (typically much lower) limit. + // NOTE: When using GROUP BY we need to be explicit about which URL to use when grouping. By using "max(frecency)" the result row + // for that domain will contain the projected URL corresponding to the history item with the max frecency, https://sqlite.org/lang_select.html#resultset + // This is the behavior we want in order to ensure that the most popular URL for a domain is used for the top sites tile. + // TODO: make is_bookmarked here accurate by joining against ViewAllBookmarks. + // TODO: ensure that the same URL doesn't appear twice in the list, either from duplicate + // bookmarks or from being in both bookmarks and history. + let historySQL = [ + "SELECT historyID, url, title, guid, domain_id, domain,", + "max(localVisitDate) AS localVisitDate,", + "max(remoteVisitDate) AS remoteVisitDate,", + "sum(localVisitCount) AS localVisitCount,", + "sum(remoteVisitCount) AS remoteVisitCount,", + "max(frecency) AS maxFrecency,", + "sum(frecency) AS frecencies,", + "0 AS is_bookmarked", + "FROM (", frecenciedSQL, ") ", + groupClause, + "ORDER BY frecencies DESC", + "LIMIT \(historyLimit)", + ].joined(separator: " ") + + let bookmarksSQL = [ + "SELECT NULL AS historyID, url, title, guid, NULL AS domain_id, NULL AS domain,", + "visitDate AS localVisitDate, 0 AS remoteVisitDate, 0 AS localVisitCount,", + "0 AS remoteVisitCount,", + "visitDate AS frecencies,", // Fake this for ordering purposes. + "0 as maxFrecency,", // Need this column for UNION + "1 AS is_bookmarked", + "FROM \(TempTableAwesomebarBookmarks)", + whereClause, // The columns match, so we can reuse this. + "GROUP BY url", + "ORDER BY visitDate DESC LIMIT \(bookmarksLimit)", + ].joined(separator: " ") + + if !includeBookmarks { + return (historySQL, args) + } + + let allSQL = "SELECT * FROM (SELECT * FROM (\(historySQL)) UNION SELECT * FROM (\(bookmarksSQL))) ORDER BY is_bookmarked DESC, frecencies DESC" + return (allSQL, args) + } +} + +extension SQLiteHistory: BrowserHistory { + public func removeSiteFromTopSites(_ site: Site) -> Success { + if let host = (site.url as String).asURL?.normalizedHost { + return self.removeHostFromTopSites(host) + } + return deferMaybe(DatabaseError(description: "Invalid url for site \(site.url)")) + } + + public func removeFromPinnedTopSites(_ site: Site) -> Success { + guard let host = (site.url as String).asURL?.normalizedHost else { + return deferMaybe(DatabaseError(description: "Invalid url for site \(site.url)")) + } + + //do a fuzzy delete so dupes can be removed + let query: (String, Args?) = ("DELETE FROM \(TablePinnedTopSites) where domain = ?", [host]) + return db.run([query]) >>== { + return self.db.run([("UPDATE \(TableDomains) set showOnTopSites = 1 WHERE domain = ?", [host])]) + } + } + + public func getPinnedTopSites() -> Deferred>> { + let sql = "SELECT * from \(TablePinnedTopSites) " + + "LEFT OUTER JOIN view_history_id_favicon on historyID = view_history_id_favicon.id ORDER BY pinDate DESC" + return db.runQuery(sql, args: [], factory: SQLiteHistory.iconHistoryMetadataColumnFactory) + } + + public func addPinnedTopSite(_ site: Site) -> Success { // needs test + let now = Date.now() + guard let guid = site.guid, let host = (site.url as String).asURL?.normalizedHost else { + return deferMaybe(DatabaseError(description: "Invalid site \(site.url)")) + } + + let args: Args = [site.url, now, site.title, site.id, guid, host] + let arglist = BrowserDB.varlist(args.count) + // Prevent the pinned site from being used in topsite calculations + // We dont have to worry about this when removing a pin because the assumption is that a user probably doesnt want it being recommended as a topsite either + return self.removeHostFromTopSites(host) >>== { + return self.db.run([("INSERT OR REPLACE INTO \(TablePinnedTopSites)(url, pinDate, title, historyID, guid, domain) VALUES \(arglist)", args)]) + } + } + + public func removeHostFromTopSites(_ host: String) -> Success { + return db.run([("UPDATE \(TableDomains) set showOnTopSites = 0 WHERE domain = ?", [host])]) + } + + public func removeHistoryForURL(_ url: String) -> Success { + let visitArgs: Args = [url] + let deleteVisits = "DELETE FROM \(TableVisits) WHERE siteID = (SELECT id FROM \(TableHistory) WHERE url = ?)" + + let markArgs: Args = [Date.nowNumber(), url] + let markDeleted = "UPDATE \(TableHistory) SET url = NULL, is_deleted = 1, should_upload = 1, local_modified = ? WHERE url = ?" + //return db.run([(sql: String, args: Args?)]) + let command = [(sql: deleteVisits, args: visitArgs), (sql: markDeleted, args: markArgs), self.favicons.getCleanupFaviconsQuery()] as [(sql: String, args: Args?)] + return db.run(command) + } + + // Note: clearing history isn't really a sane concept in the presence of Sync. + // This method should be split to do something else. + // Bug 1162778. + public func clearHistory() -> Success { + return self.db.run([ + ("DELETE FROM \(TableVisits)", nil), + ("DELETE FROM \(TableHistory)", nil), + ("DELETE FROM \(TableDomains)", nil), + ("DELETE FROM \(TablePageMetadata)", nil), + self.favicons.getCleanupFaviconsQuery() + ]) + // We've probably deleted a lot of stuff. Vacuum now to recover the space. + >>> effect(self.db.vacuum) + } + + func recordVisitedSite(_ site: Site) -> Success { + // Don't store visits to sites with about: protocols + if isIgnoredURL(site.url as String) { + return deferMaybe(IgnoredSiteError()) + } + + return db.withConnection { conn -> Void in + let now = Date.now() + + if self.updateSite(site, atTime: now, withConnection: conn) > 0 { + return + } + + // Insert instead. + if self.insertSite(site, atTime: now, withConnection: conn) > 0 { + return + } + + let err = DatabaseError(description: "Unable to update or insert site; Invalid key returned") + log.error("recordVisitedSite(_:) encountered an error: \(err.localizedDescription)") + throw err + } + } + + func updateSite(_ site: Site, atTime time: Timestamp, withConnection conn: SQLiteDBConnection) -> Int { + // We know we're adding a new visit, so we'll need to upload this record. + // If we ever switch to per-visit change flags, this should turn into a CASE statement like + // CASE WHEN title IS ? THEN max(should_upload, 1) ELSE should_upload END + // so that we don't flag this as changed unless the title changed. + // + // Note that we will never match against a deleted item, because deleted items have no URL, + // so we don't need to unset is_deleted here. + guard let host = (site.url as String).asURL?.normalizedHost else { + return 0 + } + + let update = "UPDATE \(TableHistory) SET title = ?, local_modified = ?, should_upload = 1, domain_id = (SELECT id FROM \(TableDomains) where domain = ?) WHERE url = ?" + let updateArgs: Args? = [site.title, time, host, site.url] + if Logger.logPII { + log.debug("Setting title to \(site.title) for URL \(site.url)") + } + do { + try conn.executeChange(update, withArgs: updateArgs) + return conn.numberOfRowsModified + } catch let error as NSError { + log.warning("Update failed with error: \(error.localizedDescription)") + return 0 + } + } + + fileprivate func insertSite(_ site: Site, atTime time: Timestamp, withConnection conn: SQLiteDBConnection) -> Int { + if let host = (site.url as String).asURL?.normalizedHost { + do { + try conn.executeChange("INSERT OR IGNORE INTO \(TableDomains) (domain) VALUES (?)", withArgs: [host]) + } catch let error as NSError { + log.warning("Domain insertion failed with \(error.localizedDescription)") + return 0 + } + + let insert = "INSERT INTO \(TableHistory) " + + "(guid, url, title, local_modified, is_deleted, should_upload, domain_id) " + + "SELECT ?, ?, ?, ?, 0, 1, id FROM \(TableDomains) WHERE domain = ?" + let insertArgs: Args? = [site.guid ?? Bytes.generateGUID(), site.url, site.title, time, host] + do { + try conn.executeChange(insert, withArgs: insertArgs) + } catch let error as NSError { + log.warning("Site insertion failed with \(error.localizedDescription)") + return 0 + } + + return 1 + } + + if Logger.logPII { + log.warning("Invalid URL \(site.url). Not stored in history.") + } + return 0 + } + + // TODO: thread siteID into this to avoid the need to do the lookup. + func addLocalVisitForExistingSite(_ visit: SiteVisit) -> Success { + return db.withConnection { conn -> Void in + // INSERT OR IGNORE because we *might* have a clock error that causes a timestamp + // collision with an existing visit, and it would really suck to error out for that reason. + let insert = "INSERT OR IGNORE INTO \(TableVisits) (siteID, date, type, is_local) VALUES (" + + "(SELECT id FROM \(TableHistory) WHERE url = ?), ?, ?, 1)" + let realDate = visit.date + let insertArgs: Args? = [visit.site.url, realDate, visit.type.rawValue] + + try conn.executeChange(insert, withArgs: insertArgs) + } + } + + public func addLocalVisit(_ visit: SiteVisit) -> Success { + return recordVisitedSite(visit.site) + >>> { self.addLocalVisitForExistingSite(visit) } + } + + public func getFrecentHistory() -> FrecentHistory { + return SQLiteFrecentHistory(db: db, prefs: prefs) + } + + public func getTopSitesWithLimit(_ limit: Int) -> Deferred>> { + return self.db.runQuery(topSitesQuery, args: [limit], factory: SQLiteHistory.iconHistoryMetadataColumnFactory) + } + + public func setTopSitesNeedsInvalidation() { + prefs.setBool(false, forKey: PrefsKeys.KeyTopSitesCacheIsValid) + } + + public func setTopSitesCacheSize(_ size: Int32) { + let oldValue = prefs.intForKey(PrefsKeys.KeyTopSitesCacheSize) ?? 0 + if oldValue != size { + prefs.setInt(size, forKey: PrefsKeys.KeyTopSitesCacheSize) + setTopSitesNeedsInvalidation() + } + } + + public func refreshTopSitesQuery() -> [(String, Args?)] { + return [clearTopSitesQuery, getFrecentHistory().updateTopSitesCacheQuery()] + } + + public func clearTopSitesCache() -> Success { + return self.db.run([clearTopSitesQuery]) >>> { + self.prefs.removeObjectForKey(PrefsKeys.KeyTopSitesCacheIsValid) + return succeed() + } + } + + public func getSitesByLastVisit(_ limit: Int) -> Deferred>> { + return self.getFilteredSitesByVisitDateWithLimit(limit, whereURLContains: nil, includeIcon: true) + } + + fileprivate func topSiteClauses() -> (String, String) { + let whereData = "(\(TableDomains).showOnTopSites IS 1) AND (\(TableDomains).domain NOT LIKE 'r.%') AND (\(TableDomains).domain NOT LIKE 'google.%') " + let groupBy = "GROUP BY domain_id " + return (whereData, groupBy) + } + + fileprivate func computeWordsWithFilter(_ filter: String) -> [String] { + // Split filter on whitespace. + let words = filter.components(separatedBy: CharacterSet.whitespaces) + + // Remove substrings and duplicates. + // TODO: this can probably be improved. + return words.enumerated().filter({ (index: Int, word: String) in + if word.isEmpty { + return false + } + + for i in words.indices where i != index { + if words[i].range(of: word) != nil && (words[i].characters.count != word.characters.count || i < index) { + return false + } + } + + return true + }).map({ $0.1 }) + } + + /** + * Take input like "foo bar" and a template fragment and produce output like + * + * ((x.y LIKE ?) OR (x.z LIKE ?)) AND ((x.y LIKE ?) OR (x.z LIKE ?)) + * + * with args ["foo", "foo", "bar", "bar"]. + */ + internal func computeWhereFragmentWithFilter(_ filter: String, perWordFragment: String, perWordArgs: (String) -> Args) -> (fragment: String, args: Args) { + precondition(!filter.isEmpty) + + let words = computeWordsWithFilter(filter) + return self.computeWhereFragmentForWords(words, perWordFragment: perWordFragment, perWordArgs: perWordArgs) + } + + internal func computeWhereFragmentForWords(_ words: [String], perWordFragment: String, perWordArgs: (String) -> Args) -> (fragment: String, args: Args) { + assert(!words.isEmpty) + + let fragment = Array(repeating: perWordFragment, count: words.count).joined(separator: " AND ") + let args = words.flatMap(perWordArgs) + return (fragment, args) + } + + fileprivate func getFilteredSitesByVisitDateWithLimit(_ limit: Int, + whereURLContains filter: String? = nil, + includeIcon: Bool = true) -> Deferred>> { + let args: Args? + let whereClause: String + if let filter = filter?.trimmingCharacters(in: CharacterSet.whitespaces), !filter.isEmpty { + let perWordFragment = "((\(TableHistory).url LIKE ?) OR (\(TableHistory).title LIKE ?))" + let perWordArgs: (String) -> Args = { ["%\($0)%", "%\($0)%"] } + let (filterFragment, filterArgs) = computeWhereFragmentWithFilter(filter, perWordFragment: perWordFragment, perWordArgs: perWordArgs) + + // No deleted item has a URL, so there is no need to explicitly add that here. + whereClause = "WHERE (\(filterFragment))" + args = filterArgs + } else { + whereClause = "WHERE (\(TableHistory).is_deleted = 0)" + args = [] + } + + let sql = [ + "SELECT", + "history.id AS historyID, history.url, title, guid, domain_id, domain,", + "COALESCE(MAX(CASE visits.is_local WHEN 1 THEN visits.date ELSE 0 END), 0) AS localVisitDate,", + "COALESCE(MAX(CASE visits.is_local WHEN 0 THEN visits.date ELSE 0 END), 0) AS remoteVisitDate,", + "COALESCE(COUNT(visits.is_local), 0) AS visitCount", + includeIcon ? ", iconID, iconURL, iconDate, iconType, iconWidth" : "", + "FROM", + "history", + "INNER JOIN domains ON domains.id = history.domain_id", + "INNER JOIN visits ON visits.siteID = history.id", + includeIcon ? "LEFT OUTER JOIN view_history_id_favicon ON view_history_id_favicon.id = history.id" : "", + whereClause, + "GROUP BY historyID", + "HAVING COUNT(visits.is_local) > 0", + "ORDER BY MAX(localVisitDate, remoteVisitDate) DESC", + "LIMIT \(limit)", + ].joined(separator: " ") + + let factory = includeIcon ? SQLiteHistory.iconHistoryColumnFactory : SQLiteHistory.basicHistoryColumnFactory + return db.runQuery(sql, args: args, factory: factory) + } +} + +extension SQLiteHistory: Favicons { + // These two getter functions are only exposed for testing purposes (and aren't part of the public interface). + func getFaviconsForURL(_ url: String) -> Deferred>> { + let sql = "SELECT iconID AS id, iconURL AS url, iconDate AS date, iconType AS type, iconWidth AS width FROM " + + "\(ViewWidestFaviconsForSites), \(TableHistory) WHERE " + + "\(TableHistory).id = siteID AND \(TableHistory).url = ?" + let args: Args = [url] + return db.runQuery(sql, args: args, factory: SQLiteHistory.iconColumnFactory) + } + + func getFaviconsForBookmarkedURL(_ url: String) -> Deferred>> { + let sql = + "SELECT " + + " \(TableFavicons).id AS id" + + ", \(TableFavicons).url AS url" + + ", \(TableFavicons).date AS date" + + ", \(TableFavicons).type AS type" + + ", \(TableFavicons).width AS width" + + " FROM \(TableFavicons), \(ViewBookmarksLocalOnMirror) AS bm" + + " WHERE bm.faviconID = \(TableFavicons).id AND bm.bmkUri IS ?" + let args: Args = [url] + return db.runQuery(sql, args: args, factory: SQLiteHistory.iconColumnFactory) + } + + public func getSitesForURLs(_ urls: [String]) -> Deferred>> { + let inExpression = urls.joined(separator: "\",\"") + let sql = "SELECT \(TableHistory).id AS historyID, \(TableHistory).url AS url, title, guid, iconID, iconURL, iconDate, iconType, iconWidth FROM " + + "\(ViewWidestFaviconsForSites), \(TableHistory) WHERE " + + "\(TableHistory).id = siteID AND \(TableHistory).url IN (\"\(inExpression)\")" + let args: Args = [] + return db.runQuery(sql, args: args, factory: SQLiteHistory.iconHistoryColumnFactory) + } + + public func clearAllFavicons() -> Success { + return db.transaction { conn -> Void in + try conn.executeChange("DELETE FROM \(TableFaviconSites)") + try conn.executeChange("DELETE FROM \(TableFavicons)") + } + } + + public func addFavicon(_ icon: Favicon) -> Deferred> { + return self.favicons.insertOrUpdateFavicon(icon) + } + + /** + * This method assumes that the site has already been recorded + * in the history table. + */ + public func addFavicon(_ icon: Favicon, forSite site: Site) -> Deferred> { + if Logger.logPII { + log.verbose("Adding favicon \(icon.url) for site \(site.url).") + } + func doChange(_ query: String, args: Args?) -> Deferred> { + return db.withConnection { conn -> Int in + // Blind! We don't see failure here. + let id = self.favicons.insertOrUpdateFaviconInTransaction(icon, conn: conn) + + // Now set up the mapping. + try conn.executeChange(query, withArgs: args) + + // Try to update the favicon ID column in each bookmarks table. There can be + // multiple bookmarks with a particular URI, and a mirror bookmark can be + // locally changed, so either or both of these statements can update multiple rows. + if let id = id { + icon.id = id + + try? conn.executeChange("UPDATE \(TableBookmarksLocal) SET faviconID = ? WHERE bmkUri = ?", withArgs: [id, site.url]) + try? conn.executeChange("UPDATE \(TableBookmarksMirror) SET faviconID = ? WHERE bmkUri = ?", withArgs: [id, site.url]) + + return id + } + + let err = DatabaseError(description: "Error adding favicon. ID = 0") + log.error("addFavicon(_:, forSite:) encountered an error: \(err.localizedDescription)") + throw err + } + } + + let siteSubselect = "(SELECT id FROM \(TableHistory) WHERE url = ?)" + let iconSubselect = "(SELECT id FROM \(TableFavicons) WHERE url = ?)" + let insertOrIgnore = "INSERT OR IGNORE INTO \(TableFaviconSites)(siteID, faviconID) VALUES " + if let iconID = icon.id { + // Easy! + if let siteID = site.id { + // So easy! + let args: Args? = [siteID, iconID] + return doChange("\(insertOrIgnore) (?, ?)", args: args) + } + + // Nearly easy. + let args: Args? = [site.url, iconID] + return doChange("\(insertOrIgnore) (\(siteSubselect), ?)", args: args) + + } + + // Sigh. + if let siteID = site.id { + let args: Args? = [siteID, icon.url] + return doChange("\(insertOrIgnore) (?, \(iconSubselect))", args: args) + } + + // The worst. + let args: Args? = [site.url, icon.url] + return doChange("\(insertOrIgnore) (\(siteSubselect), \(iconSubselect))", args: args) + } +} + +extension SQLiteHistory: SyncableHistory { + /** + * TODO: + * When we replace an existing row, we want to create a deleted row with the old + * GUID and switch the new one in -- if the old record has escaped to a Sync server, + * we want to delete it so that we don't have two records with the same URL on the server. + * We will know if it's been uploaded because it'll have a server_modified time. + */ + public func ensurePlaceWithURL(_ url: String, hasGUID guid: GUID) -> Success { + let args: Args = [guid, url, guid] + + // The additional IS NOT is to ensure that we don't do a write for no reason. + return db.run("UPDATE \(TableHistory) SET guid = ? WHERE url = ? AND guid IS NOT ?", withArgs: args) + } + + public func deleteByGUID(_ guid: GUID, deletedAt: Timestamp) -> Success { + let args: Args = [guid] + // This relies on ON DELETE CASCADE to remove visits. + return db.run("DELETE FROM \(TableHistory) WHERE guid = ?", withArgs: args) + } + + // Fails on non-existence. + fileprivate func getSiteIDForGUID(_ guid: GUID) -> Deferred> { + let args: Args = [guid] + let query = "SELECT id FROM history WHERE guid = ?" + let factory: (SDRow) -> Int = { return $0["id"] as! Int } + + return db.runQuery(query, args: args, factory: factory) + >>== { cursor in + if cursor.count == 0 { + return deferMaybe(NoSuchRecordError(guid: guid)) + } + return deferMaybe(cursor[0]!) + } + } + + public func storeRemoteVisits(_ visits: [Visit], forGUID guid: GUID) -> Success { + return self.getSiteIDForGUID(guid) + >>== { (siteID: Int) -> Success in + let visitArgs = visits.map { (visit: Visit) -> Args in + let realDate = visit.date + let isLocal = 0 + let args: Args = [siteID, realDate, visit.type.rawValue, isLocal] + return args + } + + // Magic happens here. The INSERT OR IGNORE relies on the multi-column uniqueness + // constraint on `visits`: we allow only one row for (siteID, date, type), so if a + // local visit already exists, this silently keeps it. End result? Any new remote + // visits are added with only one query, keeping any existing rows. + return self.db.bulkInsert(TableVisits, op: .InsertOrIgnore, columns: ["siteID", "date", "type", "is_local"], values: visitArgs) + } + } + + fileprivate struct HistoryMetadata { + let id: Int + let serverModified: Timestamp? + let localModified: Timestamp? + let isDeleted: Bool + let shouldUpload: Bool + let title: String + } + + fileprivate func metadataForGUID(_ guid: GUID) -> Deferred> { + let select = "SELECT id, server_modified, local_modified, is_deleted, should_upload, title FROM \(TableHistory) WHERE guid = ?" + let args: Args = [guid] + let factory = { (row: SDRow) -> HistoryMetadata in + return HistoryMetadata( + id: row["id"] as! Int, + serverModified: row.getTimestamp("server_modified"), + localModified: row.getTimestamp("local_modified"), + isDeleted: row.getBoolean("is_deleted"), + shouldUpload: row.getBoolean("should_upload"), + title: row["title"] as! String + ) + } + return db.runQuery(select, args: args, factory: factory) >>== { cursor in + return deferMaybe(cursor[0]) + } + } + + public func insertOrUpdatePlace(_ place: Place, modified: Timestamp) -> Deferred> { + // One of these things will be true here. + // 0. The item is new. + // (a) We have a local place with the same URL but a different GUID. + // (b) We have never visited this place locally. + // In either case, reconcile and proceed. + // 1. The remote place is not modified when compared to our mirror of it. This + // can occur when we redownload after a partial failure. + // (a) And it's not modified locally, either. Nothing to do. Ideally we + // will short-circuit so we don't need to update visits. (TODO) + // (b) It's modified locally. Don't overwrite anything; let the upload happen. + // 2. The remote place is modified (either title or visits). + // (a) And it's not locally modified. Update the local entry. + // (b) And it's locally modified. Preserve the title of whichever was modified last. + // N.B., this is the only instance where we compare two timestamps to see + // which one wins. + + // We use this throughout. + let serverModified = modified + + // Check to see if our modified time is unchanged, if the record exists locally, etc. + let insertWithMetadata = { (metadata: HistoryMetadata?) -> Deferred> in + if let metadata = metadata { + // The item exists locally (perhaps originally with a different GUID). + if metadata.serverModified == modified { + log.verbose("History item \(place.guid) is unchanged; skipping insert-or-update.") + return deferMaybe(place.guid) + } + + // Otherwise, the server record must have changed since we last saw it. + if metadata.shouldUpload { + // Uh oh, it changed locally. + // This might well just be a visit change, but we can't tell. Usually this conflict is harmless. + log.debug("Warning: history item \(place.guid) changed both locally and remotely. Comparing timestamps from different clocks!") + if let localModified = metadata.localModified, localModified > modified { + log.debug("Local changes overriding remote.") + + // Update server modified time only. (Though it'll be overwritten again after a successful upload.) + let update = "UPDATE \(TableHistory) SET server_modified = ? WHERE id = ?" + let args: Args = [serverModified, metadata.id] + return self.db.run(update, withArgs: args) >>> always(place.guid) + } + + log.verbose("Remote changes overriding local.") + // Fall through. + } + + // The record didn't change locally. Update it. + log.verbose("Updating local history item for guid \(place.guid).") + let update = "UPDATE \(TableHistory) SET title = ?, server_modified = ?, is_deleted = 0 WHERE id = ?" + let args: Args = [place.title, serverModified, metadata.id] + return self.db.run(update, withArgs: args) >>> always(place.guid) + } + + // The record doesn't exist locally. Insert it. + log.verbose("Inserting remote history item for guid \(place.guid).") + if let host = place.url.asURL?.normalizedHost { + if Logger.logPII { + log.debug("Inserting: \(place.url).") + } + + let insertDomain = "INSERT OR IGNORE INTO \(TableDomains) (domain) VALUES (?)" + let insertHistory = "INSERT INTO \(TableHistory) (guid, url, title, server_modified, is_deleted, should_upload, domain_id) " + + "SELECT ?, ?, ?, ?, 0, 0, id FROM \(TableDomains) where domain = ?" + return self.db.run([ + (insertDomain, [host]), + (insertHistory, [place.guid, place.url, place.title, serverModified, host]) + ]) >>> always(place.guid) + } else { + // This is a URL with no domain. Insert it directly. + if Logger.logPII { + log.debug("Inserting: \(place.url) with no domain.") + } + + let insertHistory = "INSERT INTO \(TableHistory) (guid, url, title, server_modified, is_deleted, should_upload, domain_id) " + + "VALUES (?, ?, ?, ?, 0, 0, NULL)" + return self.db.run([ + (insertHistory, [place.guid, place.url, place.title, serverModified]) + ]) >>> always(place.guid) + } + } + + // Make sure that we only need to compare GUIDs by pre-merging on URL. + return self.ensurePlaceWithURL(place.url, hasGUID: place.guid) + >>> { self.metadataForGUID(place.guid) >>== insertWithMetadata } + } + + public func getDeletedHistoryToUpload() -> Deferred> { + // Use the partial index on should_upload to make this nice and quick. + let sql = "SELECT guid FROM \(TableHistory) WHERE \(TableHistory).should_upload = 1 AND \(TableHistory).is_deleted = 1" + let f: (SDRow) -> String = { $0["guid"] as! String } + + return self.db.runQuery(sql, args: nil, factory: f) >>== { deferMaybe($0.asArray()) } + } + + public func getModifiedHistoryToUpload() -> Deferred> { + // What we want to do: find all history items that are flagged for upload, then find a number of recent visits for each item. + // This was originally all in a single SQL query but was seperated into two to save some memory when returning back the cursor. + return getModifiedHistory(limit: 1000) >>== { self.attachVisitsTo(places: $0, visitLimit: 20) } + } + + private func getModifiedHistory(limit: Int) -> Deferred> { + let sql = + "SELECT id, guid, url, title " + + "FROM \(TableHistory) " + + "WHERE should_upload = 1 AND NOT is_deleted = 1 " + + "ORDER BY id " + + "LIMIT ?" + + var places = [Int: Place]() + let placeFactory: (SDRow) -> Void = { row in + let id = row["id"] as! Int + let guid = row["guid"] as! String + let url = row["url"] as! String + let title = row["title"] as! String + places[id] = Place(guid: guid, url: url, title: title) + } + + let args: Args = [limit] + return db.runQuery(sql, args: args, factory: placeFactory) >>> { deferMaybe(places) } + } + + private func attachVisitsTo(places: [Int: Place], visitLimit: Int) -> Deferred> { + // A difficulty here: we don't want to fetch *all* visits, only some number of the most recent. + // (It's not enough to only get new ones, because the server record should contain more.) + // + // That's the greatest-N-per-group problem. We used to do this in SQL, joining + // the visits table to a subselect of visits table, however, ran into OOM issues (Bug 1417034) + // + // Now, we want a more dumb approach with no joins in SQL and doing group-by-site and limit-to-N in swift. + // + // We do this in a single query, rather than the N+1 that desktop takes. + // + // We then need to flatten the cursor. We do that by collecting + // places as a side-effect of the factory, producing visits as a result, and merging in memory. + + // Turn our lazy collection of integers into a comma-seperated string for the IN clause. + let historyIDs = Array(places.keys) + + let sql = + "SELECT siteID, date AS visitDate, type AS visitType " + + "FROM \(TableVisits) " + + "WHERE siteID IN (\(historyIDs.map(String.init).joined(separator: ","))) " + + "ORDER BY siteID DESC, date DESC" + + // We want to get a tuple Visit and Place here. We can either have an explicit tuple factory + // or we use an identity function, and make do without creating extra data structures. + // Since we have a known Out Of Memory issue here, let's avoid extra data structures. + let rowIdentity: (SDRow) -> SDRow = { $0 } + + // We'll need to runQueryUnsafe so we get a LiveSQLiteCursor, i.e. we don't get the cursor + // contents into memory all at once. + return db.runQueryUnsafe(sql, args: nil, factory: rowIdentity) { (cursor: Cursor) -> [Int: [Visit]] in + // Accumulate a mapping of site IDs to list of visits. Each list should be shorter than visitLimit. + // Seed our accumulator with empty lists since we already know which IDs we will be fetching. + var visits = [Int: [Visit]]() + historyIDs.forEach { visits[$0] = [] } + + // We need to iterate through these explicitly, without relying on the + // factory. + for row in cursor.makeIterator() { + guard let row = row, cursor.status == .success else { + throw NSError(domain: "mozilla", code: 0, userInfo: [NSLocalizedDescriptionKey: cursor.statusMessage]) + } + + guard let id = row["siteID"] as? Int, + let existingCount = visits[id]?.count, + existingCount < visitLimit else { + continue + } + + guard let date = row.getTimestamp("visitDate"), + let visitType = row["visitType"] as? Int, + let type = VisitType(rawValue: visitType) else { + continue + } + + let visit = Visit(date: date, type: type) + + // Append the visits in descending date order, so we only get the + // most recent top N. + visits[id]?.append(visit) + } + + return visits + } >>== { visits in + // Join up the places map we received as input with our visits map. + let placesAndVisits: [(Place, [Visit])] = places.flatMap { id, place in + guard let visitsList = visits[id], !visitsList.isEmpty else { + return nil + } + return (place, visitsList) + } + + let recentVisitCount = placesAndVisits.reduce(0) { $0 + $1.1.count } + + log.info("Attaching \(placesAndVisits.count) places to \(recentVisitCount) most recent visits") + return deferMaybe(placesAndVisits) + } + } + + public func markAsDeleted(_ guids: [GUID]) -> Success { + if guids.isEmpty { + return succeed() + } + + log.debug("Wiping \(guids.count) deleted GUIDs.") + return self.db.run(chunk(guids, by: BrowserDB.MaxVariableNumber).flatMap(markAsDeletedStatementForGUIDs)) + } + + fileprivate func markAsDeletedStatementForGUIDs(_ guids: ArraySlice) -> (String, Args?) { + // We deliberately don't limit this to records marked as should_upload, just + // in case a coding error leaves records with is_deleted=1 but not flagged for + // upload -- this will catch those and throw them away. + let inClause = BrowserDB.varlist(guids.count) + let sql = "DELETE FROM \(TableHistory) WHERE is_deleted = 1 AND guid IN \(inClause)" + + let args: Args = guids.map { $0 } + return (sql, args) + } + + public func markAsSynchronized(_ guids: [GUID], modified: Timestamp) -> Deferred> { + if guids.isEmpty { + return deferMaybe(modified) + } + + log.debug("Marking \(guids.count) GUIDs as synchronized. Returning timestamp \(modified).") + return self.db.run(chunk(guids, by: BrowserDB.MaxVariableNumber).flatMap { chunk in + return markAsSynchronizedStatementForGUIDs(chunk, modified: modified) + }) >>> always(modified) + } + + fileprivate func markAsSynchronizedStatementForGUIDs(_ guids: ArraySlice, modified: Timestamp) -> (String, Args?) { + let inClause = BrowserDB.varlist(guids.count) + let sql = + "UPDATE \(TableHistory) SET " + + "should_upload = 0, server_modified = \(modified) " + + "WHERE guid IN \(inClause)" + + let args: Args = guids.map { $0 } + return (sql, args) + } + + public func doneApplyingRecordsAfterDownload() -> Success { + self.db.checkpoint() + return succeed() + } + + public func doneUpdatingMetadataAfterUpload() -> Success { + self.db.checkpoint() + return succeed() + } +} + +extension SQLiteHistory { + // Returns a deferred `true` if there are rows in the DB that have a server_modified time. + // Because we clear this when we reset or remove the account, and never set server_modified + // without syncing, the presence of matching rows directly indicates that a deletion + // would be synced to the server. + public func hasSyncedHistory() -> Deferred> { + return self.db.queryReturnsResults("SELECT 1 FROM \(TableHistory) WHERE server_modified IS NOT NULL LIMIT 1") + } +} + +extension SQLiteHistory: ResettableSyncStorage { + // We don't drop deletions when we reset -- we might need to upload a deleted item + // that never made it to the server. + public func resetClient() -> Success { + let flag = "UPDATE \(TableHistory) SET should_upload = 1, server_modified = NULL" + return self.db.run(flag) + } +} + +extension SQLiteHistory: AccountRemovalDelegate { + public func onRemovedAccount() -> Success { + log.info("Clearing history metadata and deleted items after account removal.") + let discard = "DELETE FROM \(TableHistory) WHERE is_deleted = 1" + return self.db.run(discard) >>> self.resetClient + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteHistoryFactories.swift b/mobile/ios/Storage/SQL/SQLiteHistoryFactories.swift new file mode 100644 index 0000000000..805778fdd5 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteHistoryFactories.swift @@ -0,0 +1,75 @@ +/* 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/. */ + +import Foundation +import Shared + +/* + * Factory methods for converting rows from SQLite into model objects + */ +extension SQLiteHistory { + class func basicHistoryColumnFactory(_ row: SDRow) -> Site { + let id = row["historyID"] as? Int + let url = row["url"] as! String + let title = row["title"] as! String + let guid = row["guid"] as! String + + // Extract a boolean from the row if it's present. + let iB = row["is_bookmarked"] as? Int + let isBookmarked: Bool? = (iB == nil) ? nil : (iB! != 0) + + let site = Site(url: url, title: title, bookmarked: isBookmarked) + site.guid = guid + site.id = id + + // Find the most recent visit, regardless of which column it might be in. + let local = row.getTimestamp("localVisitDate") ?? 0 + let remote = row.getTimestamp("remoteVisitDate") ?? 0 + let either = row.getTimestamp("visitDate") ?? 0 + + let latest = max(local, remote, either) + if latest > 0 { + site.latestVisit = Visit(date: latest, type: VisitType.unknown) + } + + return site + } + + class func iconColumnFactory(_ row: SDRow) -> Favicon? { + if let iconType = row["iconType"] as? Int, + let iconURL = row["iconURL"] as? String, + let iconDate = row["iconDate"] as? Double, + let _ = row["iconID"] as? Int { + let date = Date(timeIntervalSince1970: iconDate) + return Favicon(url: iconURL, date: date, type: IconType(rawValue: iconType)!) + } + return nil + } + + class func pageMetadataColumnFactory(_ row: SDRow) -> PageMetadata? { + guard let siteURL = row["url"] as? String else { + return nil + } + + return PageMetadata(id: row["metadata_id"] as? Int, siteURL: siteURL, mediaURL: row["media_url"] as? String, title: row["metadata_title"] as? String, description: row["description"] as? String, type: row["type"] as? String, providerName: row["provider_name"] as? String, mediaDataURI: nil) + } + + class func iconHistoryColumnFactory(_ row: SDRow) -> Site { + let site = basicHistoryColumnFactory(row) + site.icon = iconColumnFactory(row) + return site + } + + class func iconHistoryMetadataColumnFactory(_ row: SDRow) -> Site { + let site = iconHistoryColumnFactory(row) + site.metadata = pageMetadataColumnFactory(row) + return site + } + + class func basicHistoryMetadataColumnFactory(_ row: SDRow) -> Site { + let site = basicHistoryColumnFactory(row) + site.metadata = pageMetadataColumnFactory(row) + return site + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteHistoryRecommendations.swift b/mobile/ios/Storage/SQL/SQLiteHistoryRecommendations.swift new file mode 100644 index 0000000000..1ecedc34df --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteHistoryRecommendations.swift @@ -0,0 +1,179 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger +import Deferred + +fileprivate let log = Logger.syncLogger + +extension SQLiteHistory: HistoryRecommendations { + // Bookmarks Query + static let removeMultipleDomainsSubquery = + " INNER JOIN (SELECT \(ViewHistoryVisits).domain_id AS domain_id" + + " FROM \(ViewHistoryVisits)" + + " GROUP BY \(ViewHistoryVisits).domain_id) AS domains ON domains.domain_id = \(TableHistory).domain_id" + + static let urisForSimpleSyncedBookmarks = + "SELECT bmkUri FROM \(TableBookmarksBuffer) WHERE server_modified > ? AND is_deleted = 0 " + + "UNION ALL " + + "SELECT bmkUri FROM \(TableBookmarksLocal) WHERE local_modified > ? AND is_deleted = 0" + + static let urisForLocalBookmarks = + "SELECT bmkUri" + + "FROM \(ViewBookmarksLocalOnMirror) " + + "WHERE \(ViewBookmarksLocalOnMirror).server_modified > ? OR " + + "\(ViewBookmarksLocalOnMirror).local_modified > ?" + + static let bookmarkHighlights = + "SELECT historyID, url, siteTitle, guid, is_bookmarked FROM (" + + " SELECT \(TableHistory).id AS historyID, \(TableHistory).url AS url, \(TableHistory).title AS siteTitle, guid, \(TableHistory).domain_id, NULL AS visitDate, 1 AS is_bookmarked" + + " FROM (" + + (AppConstants.MOZ_SIMPLE_BOOKMARKS_SYNCING ? urisForSimpleSyncedBookmarks : urisForLocalBookmarks) + + " )" + + " LEFT JOIN \(TableHistory) ON \(TableHistory).url = bmkUri" + removeMultipleDomainsSubquery + + " WHERE \(TableHistory).title NOT NULL and \(TableHistory).title != '' AND url NOT IN" + + " (SELECT \(TableActivityStreamBlocklist).url FROM \(TableActivityStreamBlocklist))" + + " LIMIT ?" + + ")" + + static let bookmarksQuery = + "SELECT historyID, url, siteTitle AS title, guid, is_bookmarked, iconID, iconURL, iconType, iconDate, iconWidth, \(TablePageMetadata).title AS metadata_title, media_url, type, description, provider_name " + + "FROM (\(bookmarkHighlights) ) " + + "LEFT JOIN \(ViewHistoryIDsWithWidestFavicons) ON \(ViewHistoryIDsWithWidestFavicons).id = historyID " + + "LEFT OUTER JOIN \(TablePageMetadata) ON \(TablePageMetadata).cache_key = url " + + "GROUP BY url" + + // Highlights Query + static let highlightsLimit = 8 + static let blacklistedHosts: Args = [ + "google.com", + "google.ca", + "calendar.google.com", + "mail.google.com", + "mail.yahoo.com", + "search.yahoo.com", + "localhost", + "t.co" + ] + + static let blacklistSubquery = "SELECT \(TableDomains).id FROM \(TableDomains) WHERE \(TableDomains).domain IN " + BrowserDB.varlist(blacklistedHosts.count) + static let removeMultipleDomainsSubqueryFromHighlights = + " INNER JOIN (SELECT \(ViewHistoryVisits).domain_id AS domain_id, MAX(\(ViewHistoryVisits).visitDate) AS visit_date" + + " FROM \(ViewHistoryVisits)" + + " GROUP BY \(ViewHistoryVisits).domain_id) AS domains ON domains.domain_id = \(TableHistory).domain_id AND visitDate = domains.visit_date" + + static let nonRecentHistory = + "SELECT historyID, url, siteTitle, guid, visitCount, visitDate, is_bookmarked, visitCount * icon_url_score * media_url_score AS score FROM (" + + " SELECT \(TableHistory).id as historyID, url, \(TableHistory).title AS siteTitle, guid, visitDate, \(TableHistory).domain_id," + + " (SELECT COUNT(1) FROM \(TableVisits) WHERE s = \(TableVisits).siteID) AS visitCount," + + " (SELECT COUNT(1) FROM \(ViewBookmarksLocalOnMirror) WHERE \(ViewBookmarksLocalOnMirror).bmkUri == url) AS is_bookmarked," + + " CASE WHEN iconURL IS NULL THEN 1 ELSE 2 END AS icon_url_score," + + " CASE WHEN media_url IS NULL THEN 1 ELSE 4 END AS media_url_score" + + " FROM (" + + " SELECT siteID AS s, MAX(date) AS visitDate" + + " FROM \(TableVisits)" + + " WHERE date < ?" + + " GROUP BY siteID" + + " ORDER BY visitDate DESC" + + " )" + + " LEFT JOIN \(TableHistory) ON \(TableHistory).id = s" + + removeMultipleDomainsSubqueryFromHighlights + + " LEFT OUTER JOIN \(ViewHistoryIDsWithWidestFavicons) ON" + + " \(ViewHistoryIDsWithWidestFavicons).id = \(TableHistory).id" + + " LEFT OUTER JOIN \(TablePageMetadata) ON" + + " \(TablePageMetadata).site_url = \(TableHistory).url" + + " WHERE visitCount <= 3 AND \(TableHistory).title NOT NULL AND \(TableHistory).title != '' AND is_bookmarked == 0 AND url NOT IN" + + " (SELECT url FROM \(TableActivityStreamBlocklist))" + + " AND \(TableHistory).domain_id NOT IN (" + + blacklistSubquery + ")" + + ")" + + public func getHighlights() -> Deferred>> { + let highlightsProjection = [ + "historyID", + "\(TableHighlights).cache_key AS cache_key", + "url", + "\(TableHighlights).title AS title", + "guid", + "visitCount", + "visitDate", + "is_bookmarked" + ] + let faviconsProjection = ["iconID", "iconURL", "iconType", "iconDate", "iconWidth"] + let metadataProjections = [ + "\(TablePageMetadata).title AS metadata_title", + "media_url", + "type", + "description", + "provider_name" + ] + + let allProjection = highlightsProjection + faviconsProjection + metadataProjections + + let highlightsHistoryIDs = + "SELECT historyID FROM \(TableHighlights)" + + // Search the history/favicon view with our limited set of highlight IDs + // to avoid doing a full table scan on history + let faviconSearch = + "SELECT * FROM \(ViewHistoryIDsWithWidestFavicons) WHERE id IN (\(highlightsHistoryIDs))" + + let sql = + "SELECT \(allProjection.joined(separator: ",")) " + + "FROM \(TableHighlights) " + + "LEFT JOIN (\(faviconSearch)) AS f1 ON f1.id = historyID " + + "LEFT OUTER JOIN \(TablePageMetadata) ON " + + "\(TablePageMetadata).cache_key = \(TableHighlights).cache_key" + + return self.db.runQuery(sql, args: nil, factory: SQLiteHistory.iconHistoryMetadataColumnFactory) + } + + public func removeHighlightForURL(_ url: String) -> Success { + return self.db.run([("INSERT INTO \(TableActivityStreamBlocklist) (url) VALUES (?)", [url])]) + } + + private func repopulateHighlightsQuery() -> [(String, Args?)] { + let (query, args) = computeHighlightsQuery() + let clearHighlightsQuery = "DELETE FROM \(TableHighlights)" + + let sql = "INSERT INTO \(TableHighlights) " + + "SELECT historyID, url as cache_key, url, title, guid, visitCount, visitDate, is_bookmarked " + + "FROM (\(query))" + return [(clearHighlightsQuery, nil), (sql, args)] + } + + public func repopulate(invalidateTopSites shouldInvalidateTopSites: Bool, invalidateHighlights shouldInvalidateHighlights: Bool) -> Success { + var queries: [(String, Args?)] = [] + if shouldInvalidateTopSites { + queries.append(contentsOf: self.refreshTopSitesQuery()) + } + if shouldInvalidateHighlights { + queries.append(contentsOf: self.repopulateHighlightsQuery()) + } + return self.db.run(queries) + } + + public func getRecentBookmarks(_ limit: Int = 3) -> Deferred>> { + let fiveDaysAgo: UInt64 = Date.now() - (OneDayInMilliseconds * 5) // The data is joined with a millisecond not a microsecond one. (History) + let args = [fiveDaysAgo, fiveDaysAgo, limit] as Args + return self.db.runQuery(SQLiteHistory.bookmarksQuery, args: args, factory: SQLiteHistory.iconHistoryMetadataColumnFactory) + } + + private func computeHighlightsQuery() -> (String, Args) { + let microsecondsPerMinute: UInt64 = 60_000_000 // 1000 * 1000 * 60 + let now = Date.nowMicroseconds() + let thirtyMinutesAgo: UInt64 = now - 30 * microsecondsPerMinute + + let highlightsQuery = + "SELECT historyID, url, siteTitle AS title, guid, visitCount, visitDate, is_bookmarked, score " + + "FROM ( \(SQLiteHistory.nonRecentHistory) ) " + + "GROUP BY url " + + "ORDER BY score DESC " + + "LIMIT \(SQLiteHistory.highlightsLimit)" + let args: Args = [thirtyMinutesAgo] + SQLiteHistory.blacklistedHosts + return (highlightsQuery, args) + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteLogins.swift b/mobile/ios/Storage/SQL/SQLiteLogins.swift new file mode 100644 index 0000000000..9487691929 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteLogins.swift @@ -0,0 +1,894 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger +import Deferred + +private let log = Logger.syncLogger + +open class SQLiteLogins: BrowserLogins { + + fileprivate let db: BrowserDB + fileprivate static let MainColumns: String = "guid, username, password, hostname, httpRealm, formSubmitURL, usernameField, passwordField" + fileprivate static let MainWithLastUsedColumns: String = MainColumns + ", timeLastUsed, timesUsed" + fileprivate static let LoginColumns: String = MainColumns + ", timeCreated, timeLastUsed, timePasswordChanged, timesUsed" + + public init(db: BrowserDB) { + self.db = db + } + + fileprivate class func populateLogin(_ login: Login, row: SDRow) { + login.formSubmitURL = row["formSubmitURL"] as? String + login.usernameField = row["usernameField"] as? String + login.passwordField = row["passwordField"] as? String + login.guid = row["guid"] as! String + + if let timeCreated = row.getTimestamp("timeCreated"), + let timeLastUsed = row.getTimestamp("timeLastUsed"), + let timePasswordChanged = row.getTimestamp("timePasswordChanged"), + let timesUsed = row["timesUsed"] as? Int { + login.timeCreated = timeCreated + login.timeLastUsed = timeLastUsed + login.timePasswordChanged = timePasswordChanged + login.timesUsed = timesUsed + } + } + + fileprivate class func constructLogin(_ row: SDRow, c: T.Type) -> T { + let credential = URLCredential(user: row["username"] as? String ?? "", + password: row["password"] as! String, + persistence: URLCredential.Persistence.none) + + // There was a bug in previous versions of the app where we saved only the hostname and not the + // scheme and port in the DB. To work with these scheme-less hostnames, we try to extract the scheme and + // hostname by converting to a URL first. If there is no valid hostname or scheme for the URL, + // fallback to returning the raw hostname value from the DB as the host and allow NSURLProtectionSpace + // to use the default (http) scheme. See https://bugzilla.mozilla.org/show_bug.cgi?id=1238103. + + let hostnameString = (row["hostname"] as? String) ?? "" + let hostnameURL = hostnameString.asURL + + let scheme = hostnameURL?.scheme + let port = hostnameURL?.port ?? 0 + + // Check for malformed hostname urls in the DB + let host: String + var malformedHostname = false + if let h = hostnameURL?.host { + host = h + } else { + host = hostnameString + malformedHostname = true + } + + let protectionSpace = URLProtectionSpace(host: host, + port: port, + protocol: scheme, + realm: row["httpRealm"] as? String, + authenticationMethod: nil) + + let login = T(credential: credential, protectionSpace: protectionSpace) + self.populateLogin(login, row: row) + login.hasMalformedHostname = malformedHostname + return login + } + + class func LocalLoginFactory(_ row: SDRow) -> LocalLogin { + let login = self.constructLogin(row, c: LocalLogin.self) + + login.localModified = row.getTimestamp("local_modified") ?? 0 + login.isDeleted = row.getBoolean("is_deleted") + login.syncStatus = SyncStatus(rawValue: row["sync_status"] as! Int)! + + return login + } + + class func MirrorLoginFactory(_ row: SDRow) -> MirrorLogin { + let login = self.constructLogin(row, c: MirrorLogin.self) + + login.serverModified = row.getTimestamp("server_modified")! + login.isOverridden = row.getBoolean("is_overridden") + + return login + } + + fileprivate class func LoginFactory(_ row: SDRow) -> Login { + return self.constructLogin(row, c: Login.self) + } + + fileprivate class func LoginDataFactory(_ row: SDRow) -> LoginData { + return LoginFactory(row) as LoginData + } + + fileprivate class func LoginUsageDataFactory(_ row: SDRow) -> LoginUsageData { + return LoginFactory(row) as LoginUsageData + } + + func notifyLoginDidChange() { + log.debug("Notifying login did change.") + + // For now we don't care about the contents. + // This posts immediately to the shared notification center. + NotificationCenter.default.post(name: NotificationDataLoginDidChange, object: nil) + } + + open func getUsageDataForLoginByGUID(_ guid: GUID) -> Deferred> { + let projection = SQLiteLogins.LoginColumns + let sql = + "SELECT \(projection) FROM " + + "\(TableLoginsLocal) WHERE is_deleted = 0 AND guid = ? " + + "UNION ALL " + + "SELECT \(projection) FROM " + + "\(TableLoginsMirror) WHERE is_overridden = 0 AND guid = ? " + + "LIMIT 1" + + let args: Args = [guid, guid] + return db.runQuery(sql, args: args, factory: SQLiteLogins.LoginUsageDataFactory) + >>== { value in + deferMaybe(value[0]!) + } + } + + open func getLoginDataForGUID(_ guid: GUID) -> Deferred> { + let projection = SQLiteLogins.LoginColumns + let sql = + "SELECT \(projection) FROM " + + "\(TableLoginsLocal) WHERE is_deleted = 0 AND guid = ? " + + "UNION ALL " + + "SELECT \(projection) FROM " + + "\(TableLoginsMirror) WHERE is_overriden IS NOT 1 AND guid = ? " + + "ORDER BY hostname ASC " + + "LIMIT 1" + + let args: Args = [guid, guid] + return db.runQuery(sql, args: args, factory: SQLiteLogins.LoginFactory) + >>== { value in + if let login = value[0] { + return deferMaybe(login) + } else { + return deferMaybe(LoginDataError(description: "Login not found for GUID \(guid)")) + } + } + } + + open func getLoginsForProtectionSpace(_ protectionSpace: URLProtectionSpace) -> Deferred>> { + let projection = SQLiteLogins.MainWithLastUsedColumns + + let sql = + "SELECT \(projection) FROM " + + "\(TableLoginsLocal) WHERE is_deleted = 0 AND hostname IS ? OR hostname IS ?" + + "UNION ALL " + + "SELECT \(projection) FROM " + + "\(TableLoginsMirror) WHERE is_overridden = 0 AND hostname IS ? OR hostname IS ?" + + "ORDER BY timeLastUsed DESC" + + // Since we store hostnames as the full scheme/protocol + host, combine the two to look up in our DB. + // In the case of https://bugzilla.mozilla.org/show_bug.cgi?id=1238103, there may be hostnames without + // a scheme. Check for these as well. + let args: Args = [ + protectionSpace.urlString(), + protectionSpace.host, + protectionSpace.urlString(), + protectionSpace.host, + ] + if Logger.logPII { + log.debug("Looking for login: \(protectionSpace.urlString()) && \(protectionSpace.host)") + } + return db.runQuery(sql, args: args, factory: SQLiteLogins.LoginDataFactory) + } + + // username is really Either; we explicitly match no username. + open func getLoginsForProtectionSpace(_ protectionSpace: URLProtectionSpace, withUsername username: String?) -> Deferred>> { + let projection = SQLiteLogins.MainWithLastUsedColumns + + let args: Args + let usernameMatch: String + if let username = username { + args = [ + protectionSpace.urlString(), username, protectionSpace.host, + protectionSpace.urlString(), username, protectionSpace.host + ] + usernameMatch = "username = ?" + } else { + args = [ + protectionSpace.urlString(), protectionSpace.host, + protectionSpace.urlString(), protectionSpace.host + ] + usernameMatch = "username IS NULL" + } + + if Logger.logPII { + log.debug("Looking for login with username: \(username ?? "nil"), first arg: \(args[0] ?? "nil")") + } + + let sql = + "SELECT \(projection) FROM " + + "\(TableLoginsLocal) WHERE is_deleted = 0 AND hostname IS ? AND \(usernameMatch) OR hostname IS ?" + + "UNION ALL " + + "SELECT \(projection) FROM " + + "\(TableLoginsMirror) WHERE is_overridden = 0 AND hostname IS ? AND \(usernameMatch) OR hostname IS ?" + + "ORDER BY timeLastUsed DESC" + + return db.runQuery(sql, args: args, factory: SQLiteLogins.LoginDataFactory) + } + + open func getAllLogins() -> Deferred>> { + return searchLoginsWithQuery(nil) + } + + open func searchLoginsWithQuery(_ query: String?) -> Deferred>> { + let projection = SQLiteLogins.LoginColumns + var searchClauses = [String]() + var args: Args? = nil + if let query = query, !query.isEmpty { + // Add wildcards to change query to 'contains in' and add them to args. We need 6 args because + // we include the where clause twice: Once for the local table and another for the remote. + args = (0..<6).map { _ in + return "%\(query)%" as String? + } + + searchClauses.append("username LIKE ? ") + searchClauses.append(" password LIKE ? ") + searchClauses.append(" hostname LIKE ?") + } + + let whereSearchClause = searchClauses.count > 0 ? "AND (" + searchClauses.joined(separator: "OR") + ") " : "" + let sql = + "SELECT \(projection) FROM " + + "\(TableLoginsLocal) WHERE is_deleted = 0 " + whereSearchClause + + "UNION ALL " + + "SELECT \(projection) FROM " + + "\(TableLoginsMirror) WHERE is_overridden = 0 " + whereSearchClause + + "ORDER BY hostname ASC" + + return db.runQuery(sql, args: args, factory: SQLiteLogins.LoginFactory) + } + + open func addLogin(_ login: LoginData) -> Success { + if let error = login.isValid.failureValue { + return deferMaybe(error) + } + + let nowMicro = Date.nowMicroseconds() + let nowMilli = nowMicro / 1000 + let dateMicro = nowMicro + let dateMilli = nowMilli + + let args: Args = [ + login.hostname, + login.httpRealm, + login.formSubmitURL, + login.usernameField, + login.passwordField, + login.username, + login.password, + login.guid, + dateMicro, // timeCreated + dateMicro, // timeLastUsed + dateMicro, // timePasswordChanged + dateMilli, // localModified + ] + + let sql = + "INSERT OR IGNORE INTO \(TableLoginsLocal) " + + // Shared fields. + "( hostname" + + ", httpRealm" + + ", formSubmitURL" + + ", usernameField" + + ", passwordField" + + ", timesUsed" + + ", username" + + ", password " + + // Local metadata. + ", guid " + + ", timeCreated" + + ", timeLastUsed" + + ", timePasswordChanged" + + ", local_modified " + + ", is_deleted " + + ", sync_status " + + ") " + + "VALUES (?,?,?,?,?,1,?,?,?,?,?, " + + "?, ?, 0, \(SyncStatus.new.rawValue)" + // Metadata. + ")" + + return db.run(sql, withArgs: args) + >>> effect(self.notifyLoginDidChange) + } + + fileprivate func cloneMirrorToOverlay(whereClause: String?, args: Args?) -> Deferred> { + let shared = "guid, hostname, httpRealm, formSubmitURL, usernameField, passwordField, timeCreated, timeLastUsed, timePasswordChanged, timesUsed, username, password " + let local = ", local_modified, is_deleted, sync_status " + let sql = "INSERT OR IGNORE INTO \(TableLoginsLocal) (\(shared)\(local)) SELECT \(shared), NULL AS local_modified, 0 AS is_deleted, 0 AS sync_status FROM \(TableLoginsMirror) \(whereClause ?? "")" + return self.db.write(sql, withArgs: args) + } + + /** + * Returns success if either a local row already existed, or + * one could be copied from the mirror. + */ + fileprivate func ensureLocalOverlayExistsForGUID(_ guid: GUID) -> Success { + let sql = "SELECT guid FROM \(TableLoginsLocal) WHERE guid = ?" + let args: Args = [guid] + let c = db.runQuery(sql, args: args, factory: { _ in 1 }) + + return c >>== { rows in + if rows.count > 0 { + return succeed() + } + log.debug("No overlay; cloning one for GUID \(guid).") + return self.cloneMirrorToOverlay(guid) + >>== { count in + if count > 0 { + return succeed() + } + log.warning("Failed to create local overlay for GUID \(guid).") + return deferMaybe(NoSuchRecordError(guid: guid)) + } + } + } + + fileprivate func cloneMirrorToOverlay(_ guid: GUID) -> Deferred> { + let whereClause = "WHERE guid = ?" + let args: Args = [guid] + + return self.cloneMirrorToOverlay(whereClause: whereClause, args: args) + } + + fileprivate func markMirrorAsOverridden(_ guid: GUID) -> Success { + let args: Args = [guid] + let sql = + "UPDATE \(TableLoginsMirror) SET " + + "is_overridden = 1 " + + "WHERE guid = ?" + + return self.db.run(sql, withArgs: args) + } + + /** + * Replace the local DB row with the provided GUID. + * If no local overlay exists, one is first created. + * + * If `significant` is `true`, the `sync_status` of the row is bumped to at least `Changed`. + * If it's already `New`, it remains marked as `New`. + * + * This flag allows callers to make minor changes (such as incrementing a usage count) + * without triggering an upload or a conflict. + */ + open func updateLoginByGUID(_ guid: GUID, new: LoginData, significant: Bool) -> Success { + if let error = new.isValid.failureValue { + return deferMaybe(error) + } + + // Right now this method is only ever called if the password changes at + // point of use, so we always set `timePasswordChanged` and `timeLastUsed`. + // We can (but don't) also assume that `significant` will always be `true`, + // at least for the time being. + let nowMicro = Date.nowMicroseconds() + let nowMilli = nowMicro / 1000 + let dateMicro = nowMicro + let dateMilli = nowMilli + + let args: Args = [ + dateMilli, // local_modified + dateMicro, // timeLastUsed + dateMicro, // timePasswordChanged + new.httpRealm, + new.formSubmitURL, + new.usernameField, + new.passwordField, + new.password, + new.hostname, + new.username, + guid, + ] + + let update = + "UPDATE \(TableLoginsLocal) SET " + + " local_modified = ?, timeLastUsed = ?, timePasswordChanged = ?" + + ", httpRealm = ?, formSubmitURL = ?, usernameField = ?" + + ", passwordField = ?, timesUsed = timesUsed + 1" + + ", password = ?, hostname = ?, username = ?" + + + // We keep rows marked as New in preference to marking them as changed. This allows us to + // delete them immediately if they don't reach the server. + (significant ? ", sync_status = max(sync_status, 1) " : "") + + " WHERE guid = ?" + + return self.ensureLocalOverlayExistsForGUID(guid) + >>> { self.markMirrorAsOverridden(guid) } + >>> { self.db.run(update, withArgs: args) } + >>> effect(self.notifyLoginDidChange) + } + + open func addUseOfLoginByGUID(_ guid: GUID) -> Success { + let sql = + "UPDATE \(TableLoginsLocal) SET " + + "timesUsed = timesUsed + 1, timeLastUsed = ?, local_modified = ? " + + "WHERE guid = ? AND is_deleted = 0" + + // For now, mere use is not enough to flip sync_status to Changed. + + let nowMicro = Date.nowMicroseconds() + let nowMilli = nowMicro / 1000 + let args: Args = [nowMicro, nowMilli, guid] + + return self.ensureLocalOverlayExistsForGUID(guid) + >>> { self.markMirrorAsOverridden(guid) } + >>> { self.db.run(sql, withArgs: args) } + } + + open func removeLoginByGUID(_ guid: GUID) -> Success { + return removeLoginsWithGUIDs([guid]) + } + + fileprivate func getDeletionStatementsForGUIDs(_ guids: ArraySlice, nowMillis: Timestamp) -> [(sql: String, args: Args?)] { + let inClause = BrowserDB.varlist(guids.count) + + // Immediately delete anything that's marked as new -- i.e., it's never reached + // the server. + let delete = + "DELETE FROM \(TableLoginsLocal) WHERE guid IN \(inClause) AND sync_status = \(SyncStatus.new.rawValue)" + + // Otherwise, mark it as changed. + let update = + "UPDATE \(TableLoginsLocal) SET " + + " local_modified = \(nowMillis)" + + ", sync_status = \(SyncStatus.changed.rawValue)" + + ", is_deleted = 1" + + ", password = ''" + + ", hostname = ''" + + ", username = ''" + + " WHERE guid IN \(inClause)" + + let markMirrorAsOverridden = + "UPDATE \(TableLoginsMirror) SET " + + "is_overridden = 1 " + + "WHERE guid IN \(inClause)" + + let insert = + "INSERT OR IGNORE INTO \(TableLoginsLocal) " + + "(guid, local_modified, is_deleted, sync_status, hostname, timeCreated, timePasswordChanged, password, username) " + + "SELECT guid, \(nowMillis), 1, \(SyncStatus.changed.rawValue), '', timeCreated, \(nowMillis)000, '', '' FROM \(TableLoginsMirror) WHERE guid IN \(inClause)" + + let args: Args = guids.map { $0 } + return [ (delete, args), (update, args), (markMirrorAsOverridden, args), (insert, args)] + } + + open func removeLoginsWithGUIDs(_ guids: [GUID]) -> Success { + let timestamp = Date.now() + return db.run(chunk(guids, by: BrowserDB.MaxVariableNumber).flatMap { + self.getDeletionStatementsForGUIDs($0, nowMillis: timestamp) + }) >>> effect(self.notifyLoginDidChange) + } + + open func removeAll() -> Success { + // Immediately delete anything that's marked as new -- i.e., it's never reached + // the server. If Sync isn't set up, this will be everything. + let delete = + "DELETE FROM \(TableLoginsLocal) WHERE sync_status = \(SyncStatus.new.rawValue)" + + let nowMillis = Date.now() + + // Mark anything we haven't already deleted. + let update = + "UPDATE \(TableLoginsLocal) SET local_modified = \(nowMillis), sync_status = \(SyncStatus.changed.rawValue), is_deleted = 1, password = '', hostname = '', username = '' WHERE is_deleted = 0" + + // Copy all the remaining rows from our mirror, marking them as locally deleted. The + // OR IGNORE will cause conflicts due to non-unique guids to be dropped, preserving + // anything we already deleted. + let insert = + "INSERT OR IGNORE INTO \(TableLoginsLocal) (guid, local_modified, is_deleted, sync_status, hostname, timeCreated, timePasswordChanged, password, username) " + + "SELECT guid, \(nowMillis), 1, \(SyncStatus.changed.rawValue), '', timeCreated, \(nowMillis)000, '', '' FROM \(TableLoginsMirror)" + + // After that, we mark all of the mirror rows as overridden. + return self.db.run(delete) + >>> { self.db.run(update) } + >>> { self.db.run("UPDATE \(TableLoginsMirror) SET is_overridden = 1") } + >>> { self.db.run(insert) } + >>> effect(self.notifyLoginDidChange) + } +} + +// When a server change is detected (e.g., syncID changes), we should consider shifting the contents +// of the mirror into the local overlay, allowing a content-based reconciliation to occur on the next +// full sync. Or we could flag the mirror as to-clear, download the server records and un-clear, and +// resolve the remainder on completion. This assumes that a fresh start will typically end up with +// the exact same records, so we might as well keep the shared parents around and double-check. +extension SQLiteLogins: SyncableLogins { + /** + * Delete the login with the provided GUID. Succeeds if the GUID is unknown. + */ + public func deleteByGUID(_ guid: GUID, deletedAt: Timestamp) -> Success { + // Simply ignore the possibility of a conflicting local change for now. + let local = "DELETE FROM \(TableLoginsLocal) WHERE guid = ?" + let remote = "DELETE FROM \(TableLoginsMirror) WHERE guid = ?" + let args: Args = [guid] + + return self.db.run(local, withArgs: args) >>> { self.db.run(remote, withArgs: args) } + } + + func getExistingMirrorRecordByGUID(_ guid: GUID) -> Deferred> { + let sql = "SELECT * FROM \(TableLoginsMirror) WHERE guid = ? LIMIT 1" + let args: Args = [guid] + return self.db.runQuery(sql, args: args, factory: SQLiteLogins.MirrorLoginFactory) >>== { deferMaybe($0[0]) } + } + + func getExistingLocalRecordByGUID(_ guid: GUID) -> Deferred> { + let sql = "SELECT * FROM \(TableLoginsLocal) WHERE guid = ? LIMIT 1" + let args: Args = [guid] + return self.db.runQuery(sql, args: args, factory: SQLiteLogins.LocalLoginFactory) >>== { deferMaybe($0[0]) } + } + + fileprivate func storeReconciledLogin(_ login: Login) -> Success { + let dateMilli = Date.now() + + let args: Args = [ + dateMilli, // local_modified + login.httpRealm, + login.formSubmitURL, + login.usernameField, + login.passwordField, + login.timeLastUsed, + login.timePasswordChanged, + login.timesUsed, + login.password, + login.hostname, + login.username, + login.guid, + ] + + let update = + "UPDATE \(TableLoginsLocal) SET " + + " local_modified = ?" + + ", httpRealm = ?, formSubmitURL = ?, usernameField = ?" + + ", passwordField = ?, timeLastUsed = ?, timePasswordChanged = ?, timesUsed = ?" + + ", password = ?" + + ", hostname = ?, username = ?" + + ", sync_status = \(SyncStatus.changed.rawValue) " + + " WHERE guid = ?" + + return self.db.run(update, withArgs: args) + } + + public func applyChangedLogin(_ upstream: ServerLogin) -> Success { + // Our login storage tracks the shared parent from the last sync (the "mirror"). + // This allows us to conclusively determine what changed in the case of conflict. + // + // Our first step is to determine whether the record is changed or new: i.e., whether + // or not it's present in the mirror. + // + // TODO: these steps can be done in a single query. Make it work, make it right, make it fast. + // TODO: if there's no mirror record, all incoming records can be applied in one go; the only + // reason we need to fetch first is to establish the shared parent. That would be nice. + let guid = upstream.guid + return self.getExistingMirrorRecordByGUID(guid) >>== { mirror in + return self.getExistingLocalRecordByGUID(guid) >>== { local in + return self.applyChangedLogin(upstream, local: local, mirror: mirror) + } + } + } + + fileprivate func applyChangedLogin(_ upstream: ServerLogin, local: LocalLogin?, mirror: MirrorLogin?) -> Success { + // Once we have the server record, the mirror record (if any), and the local overlay (if any), + // we can always know which state a record is in. + + // If it's present in the mirror, then we can proceed directly to handling the change; + // we assume that once a record makes it into the mirror, that the local record association + // has already taken place, and we're tracking local changes correctly. + if let mirror = mirror { + log.debug("Mirror record found for changed record \(mirror.guid).") + if let local = local { + log.debug("Changed local overlay found for \(local.guid). Resolving conflict with 3WM.") + // * Changed remotely and locally (conflict). Resolve the conflict using a three-way merge: the + // local mirror is the shared parent of both the local overlay and the new remote record. + // Apply results as in the co-creation case. + return self.resolveConflictBetween(local: local, upstream: upstream, shared: mirror) + } + + log.debug("No local overlay found. Updating mirror to upstream.") + // * Changed remotely but not locally. Apply the remote changes to the mirror. + // There is no local overlay to discard or resolve against. + return self.updateMirrorToLogin(upstream, fromPrevious: mirror) + } + + // * New both locally and remotely with no shared parent (cocreation). + // Or we matched the GUID, and we're assuming we just forgot the mirror. + // + // Merge and apply the results remotely, writing the result into the mirror and discarding the overlay + // if the upload succeeded. (Doing it in this order allows us to safely replay on failure.) + // + // If the local and remote record are the same, this is trivial. + // At this point we also switch our local GUID to match the remote. + if let local = local { + // We might have randomly computed the same GUID on two devices connected + // to the same Sync account. + // With our 9-byte GUIDs, the chance of that happening is very small, so we + // assume that this device has previously connected to this account, and we + // go right ahead with a merge. + log.debug("Local record with GUID \(local.guid) but no mirror. This is unusual; assuming disconnect-reconnect scenario. Smushing.") + return self.resolveConflictWithoutParentBetween(local: local, upstream: upstream) + } + + // If it's not present, we must first check whether we have a local record that's substantially + // the same -- the co-creation or re-sync case. + // + // In this case, we apply the server record to the mirror, change the local record's GUID, + // and proceed to reconcile the change on a content basis. + return self.findLocalRecordByContent(upstream) >>== { local in + if let local = local { + log.debug("Local record \(local.guid) content-matches new remote record \(upstream.guid). Smushing.") + return self.resolveConflictWithoutParentBetween(local: local, upstream: upstream) + } + + // * New upstream only; no local overlay, content-based merge, + // or shared parent in the mirror. Insert it in the mirror. + log.debug("Never seen remote record \(upstream.guid). Mirroring.") + return self.insertNewMirror(upstream) + } + } + + // N.B., the final guid is sometimes a WHERE and sometimes inserted. + fileprivate func mirrorArgs(_ login: ServerLogin) -> Args { + let args: Args = [ + login.serverModified, + login.httpRealm, + login.formSubmitURL, + login.usernameField, + login.passwordField, + login.timesUsed, + login.timeLastUsed, + login.timePasswordChanged, + login.timeCreated, + login.password, + login.hostname, + login.username, + login.guid, + ] + return args + } + + /** + * Called when we have a changed upstream record and no local changes. + * There's no need to flip the is_overridden flag. + */ + fileprivate func updateMirrorToLogin(_ login: ServerLogin, fromPrevious previous: Login) -> Success { + let args = self.mirrorArgs(login) + let sql = + "UPDATE \(TableLoginsMirror) SET " + + " server_modified = ?" + + ", httpRealm = ?, formSubmitURL = ?, usernameField = ?" + + ", passwordField = ?" + + + // These we need to coalesce, because we might be supplying zeroes if the remote has + // been overwritten by an older client. In this case, preserve the old value in the + // mirror. + ", timesUsed = coalesce(nullif(?, 0), timesUsed)" + + ", timeLastUsed = coalesce(nullif(?, 0), timeLastUsed)" + + ", timePasswordChanged = coalesce(nullif(?, 0), timePasswordChanged)" + + ", timeCreated = coalesce(nullif(?, 0), timeCreated)" + + ", password = ?, hostname = ?, username = ?" + + " WHERE guid = ?" + + return self.db.run(sql, withArgs: args) + } + + /** + * Called when we have a completely new record. Naturally the new record + * is marked as non-overridden. + */ + fileprivate func insertNewMirror(_ login: ServerLogin, isOverridden: Int = 0) -> Success { + let args = self.mirrorArgs(login) + let sql = + "INSERT OR IGNORE INTO \(TableLoginsMirror) (" + + " is_overridden, server_modified" + + ", httpRealm, formSubmitURL, usernameField" + + ", passwordField, timesUsed, timeLastUsed, timePasswordChanged, timeCreated" + + ", password, hostname, username, guid" + + ") VALUES (\(isOverridden), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + + return self.db.run(sql, withArgs: args) + } + + /** + * We assume a local record matches if it has the same username (password can differ), + * hostname, httpRealm. We also check that the formSubmitURLs are either blank or have the + * same host and port. + * + * This is roughly the same as desktop's .matches(): + * + */ + fileprivate func findLocalRecordByContent(_ login: Login) -> Deferred> { + let primary = + "SELECT * FROM \(TableLoginsLocal) WHERE " + + "hostname IS ? AND httpRealm IS ? AND username IS ?" + + var args: Args = [login.hostname, login.httpRealm, login.username] + let sql: String + + if login.formSubmitURL == nil { + sql = primary + " AND formSubmitURL IS NULL" + } else if login.formSubmitURL!.isEmpty { + sql = primary + } else { + if let hostPort = login.formSubmitURL?.asURL?.hostPort { + // Substring check will suffice for now. TODO: proper host/port check after fetching the cursor. + sql = primary + " AND (formSubmitURL = '' OR (instr(formSubmitURL, ?) > 0))" + args.append(hostPort) + } else { + log.warning("Incoming formSubmitURL is non-empty but is not a valid URL with a host. Not matching local.") + return deferMaybe(nil) + } + } + + return self.db.runQuery(sql, args: args, factory: SQLiteLogins.LocalLoginFactory) + >>== { cursor in + switch cursor.count { + case 0: + return deferMaybe(nil) + case 1: + // Great! + return deferMaybe(cursor[0]) + default: + // TODO: join against the mirror table to exclude local logins that + // already match a server record. + // Right now just take the first. + log.warning("Got \(cursor.count) local logins with matching details! This is most unexpected.") + return deferMaybe(cursor[0]) + } + } + } + + fileprivate func resolveConflictBetween(local: LocalLogin, upstream: ServerLogin, shared: Login) -> Success { + // Attempt to compute two delta sets by comparing each new record to the shared record. + // Then we can merge the two delta sets -- either perfectly or by picking a winner in the case + // of a true conflict -- and produce a resultant record. + + let localDeltas = (local.localModified, local.deltas(from: shared)) + let upstreamDeltas = (upstream.serverModified, upstream.deltas(from: shared)) + + let mergedDeltas = Login.mergeDeltas(a: localDeltas, b: upstreamDeltas) + + // Not all Sync clients handle the optional timestamp fields introduced in Bug 555755. + // We might get a server record with no timestamps, and it will differ from the original + // mirror! + // We solve that by refusing to generate deltas that discard information. We'll preserve + // the local values -- either from the local record or from the last shared parent that + // still included them -- and propagate them back to the server. + // It's OK for us to reconcile and reupload; it causes extra work for every client, but + // should not cause looping. + let resultant = shared.applyDeltas(mergedDeltas) + + // We can immediately write the downloaded upstream record -- the old one -- to + // the mirror store. + // We then apply this record to the local store, and mark it as needing upload. + // When the reconciled record is uploaded, it'll be flushed into the mirror + // with the correct modified time. + return self.updateMirrorToLogin(upstream, fromPrevious: shared) + >>> { self.storeReconciledLogin(resultant) } + } + + fileprivate func resolveConflictWithoutParentBetween(local: LocalLogin, upstream: ServerLogin) -> Success { + // Do the best we can. Either the local wins and will be + // uploaded, or the remote wins and we delete our overlay. + if local.timePasswordChanged > upstream.timePasswordChanged { + log.debug("Conflicting records with no shared parent. Using newer local record.") + return self.insertNewMirror(upstream, isOverridden: 1) + } + + log.debug("Conflicting records with no shared parent. Using newer remote record.") + let args: Args = [local.guid] + return self.insertNewMirror(upstream, isOverridden: 0) + >>> { self.db.run("DELETE FROM \(TableLoginsLocal) WHERE guid = ?", withArgs: args) } + } + + public func getModifiedLoginsToUpload() -> Deferred> { + let sql = + "SELECT * FROM \(TableLoginsLocal) " + + "WHERE sync_status IS NOT \(SyncStatus.synced.rawValue) AND is_deleted = 0" + + // Swift 2.0: use Cursor.asArray directly. + return self.db.runQuery(sql, args: nil, factory: SQLiteLogins.LoginFactory) + >>== { deferMaybe($0.asArray()) } + } + + public func getDeletedLoginsToUpload() -> Deferred> { + // There are no logins that are marked as deleted that were not originally synced -- + // others are deleted immediately. + let sql = + "SELECT guid FROM \(TableLoginsLocal) " + + "WHERE is_deleted = 1" + + // Swift 2.0: use Cursor.asArray directly. + return self.db.runQuery(sql, args: nil, factory: { return $0["guid"] as! GUID }) + >>== { deferMaybe($0.asArray()) } + } + + /** + * Chains through the provided timestamp. + */ + public func markAsSynchronized(_ guids: T, modified: Timestamp) -> Deferred> where T.Iterator.Element == GUID { + // Update the mirror from the local record that we just uploaded. + // sqlite doesn't support UPDATE FROM, so instead of running 10 subqueries * n GUIDs, + // we issue a single DELETE and a single INSERT on the mirror, then throw away the + // local overlay that we just uploaded with another DELETE. + log.debug("Marking \(guids.count) GUIDs as synchronized.") + + let queries: [(String, Args?)] = chunkCollection(guids, by: BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let inClause = BrowserDB.varlist(args.count) + + let delMirror = "DELETE FROM \(TableLoginsMirror) WHERE guid IN \(inClause)" + + let insMirror = + "INSERT OR IGNORE INTO \(TableLoginsMirror) (" + + " is_overridden, server_modified" + + ", httpRealm, formSubmitURL, usernameField" + + ", passwordField, timesUsed, timeLastUsed, timePasswordChanged, timeCreated" + + ", password, hostname, username, guid" + + ") SELECT 0, \(modified)" + + ", httpRealm, formSubmitURL, usernameField" + + ", passwordField, timesUsed, timeLastUsed, timePasswordChanged, timeCreated" + + ", password, hostname, username, guid " + + "FROM \(TableLoginsLocal) " + + "WHERE guid IN \(inClause)" + + let delLocal = "DELETE FROM \(TableLoginsLocal) WHERE guid IN \(inClause)" + + return [(delMirror, args), + (insMirror, args), + (delLocal, args)] + } + + return self.db.run(queries) + >>> always(modified) + } + + public func markAsDeleted(_ guids: T) -> Success where T.Iterator.Element == GUID { + log.debug("Marking \(guids.count) GUIDs as deleted.") + + let queries: [(String, Args?)] = chunkCollection(guids, by: BrowserDB.MaxVariableNumber) { guids in + let args: Args = guids.map { $0 } + let inClause = BrowserDB.varlist(args.count) + return [("DELETE FROM \(TableLoginsMirror) WHERE guid IN \(inClause)", args), + ("DELETE FROM \(TableLoginsLocal) WHERE guid IN \(inClause)", args)] + } + + return self.db.run(queries) + } + + public func hasSyncedLogins() -> Deferred> { + let checkLoginsMirror = "SELECT 1 FROM \(TableLoginsMirror)" + let checkLoginsLocal = "SELECT 1 FROM \(TableLoginsLocal) WHERE sync_status IS NOT \(SyncStatus.new.rawValue)" + + let sql = "\(checkLoginsMirror) UNION ALL \(checkLoginsLocal)" + return self.db.queryReturnsResults(sql) + } +} + +extension SQLiteLogins: ResettableSyncStorage { + /** + * Clean up any metadata. + * TODO: is this safe for a regular reset? It forces a content-based merge. + */ + public func resetClient() -> Success { + // Clone all the mirrors so we don't lose data. + return self.cloneMirrorToOverlay(whereClause: nil, args: nil) + + // Drop all of the mirror data. + >>> { self.db.run("DELETE FROM \(TableLoginsMirror)") } + + // Mark all of the local data as new. + >>> { self.db.run("UPDATE \(TableLoginsLocal) SET sync_status = \(SyncStatus.new.rawValue)") } + } +} + +extension SQLiteLogins: AccountRemovalDelegate { + public func onRemovedAccount() -> Success { + return self.resetClient() + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteMetadata.swift b/mobile/ios/Storage/SQL/SQLiteMetadata.swift new file mode 100644 index 0000000000..a1cc54f7f5 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteMetadata.swift @@ -0,0 +1,58 @@ +/* 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/. */ + +import Foundation +import Deferred +import Shared + +/// The sqlite-backed implementation of the metadata protocol containing images and content for pages. +open class SQLiteMetadata { + let db: BrowserDB + + required public init(db: BrowserDB) { + self.db = db + } +} + +extension SQLiteMetadata: Metadata { + // A cache key is a conveninent, readable identifier for a site in the metadata database which helps + // with deduping entries for the same page. + typealias CacheKey = String + + /// Persists the given PageMetadata object to browser.db in the page_metadata table. + /// + /// - parameter metadata: Metadata object + /// - parameter pageURL: URL of page metadata was fetched from + /// - parameter expireAt: Expiration/TTL interval for when this metadata should expire at. + /// + /// - returns: Deferred on success + public func storeMetadata(_ metadata: PageMetadata, forPageURL pageURL: URL, + expireAt: UInt64) -> Success { + guard let cacheKey = pageURL.displayURL?.absoluteString else { + return succeed() + } + + // Replace any matching cache_key entries if they exist + let selectUniqueCacheKey = "COALESCE((SELECT cache_key FROM \(TablePageMetadata) WHERE cache_key = ?), ?)" + let args: Args = [cacheKey, cacheKey, metadata.siteURL, metadata.mediaURL, metadata.title, + metadata.type, metadata.description, metadata.providerName, + expireAt] + + let insert = + "INSERT OR REPLACE INTO \(TablePageMetadata)" + + "(cache_key, site_url, media_url, title, type, description, provider_name, expired_at) " + + "VALUES ( \(selectUniqueCacheKey), ?, ?, ?, ?, ?, ?, ?)" + + return self.db.run(insert, withArgs: args) + } + + /// Purges any metadata items living in page_metadata that are expired. + /// + /// - returns: Deferred on success + public func deleteExpiredMetadata() -> Success { + let sql = "DELETE FROM page_metadata WHERE expired_at <= (CAST(strftime('%s', 'now') AS LONG)*1000)" + return self.db.run(sql) + } + +} diff --git a/mobile/ios/Storage/SQL/SQLiteQueue.swift b/mobile/ios/Storage/SQL/SQLiteQueue.swift new file mode 100644 index 0000000000..645658d882 --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteQueue.swift @@ -0,0 +1,35 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger +import Deferred + +private let log = Logger.syncLogger + +open class SQLiteQueue: TabQueue { + let db: BrowserDB + + public init(db: BrowserDB) { + self.db = db + } + + open func addToQueue(_ tab: ShareItem) -> Success { + let args: Args = [tab.url, tab.title] + return db.run("INSERT OR IGNORE INTO \(TableQueuedTabs) (url, title) VALUES (?, ?)", withArgs: args) + } + + fileprivate func factory(_ row: SDRow) -> ShareItem { + return ShareItem(url: row["url"] as! String, title: row["title"] as? String, favicon: nil) + } + + open func getQueuedTabs() -> Deferred>> { + return db.runQuery("SELECT url, title FROM \(TableQueuedTabs)", args: nil, factory: self.factory) + } + + open func clearQueuedTabs() -> Success { + return db.run("DELETE FROM \(TableQueuedTabs)") + } +} diff --git a/mobile/ios/Storage/SQL/SQLiteRemoteClientsAndTabs.swift b/mobile/ios/Storage/SQL/SQLiteRemoteClientsAndTabs.swift new file mode 100644 index 0000000000..5b16e473fa --- /dev/null +++ b/mobile/ios/Storage/SQL/SQLiteRemoteClientsAndTabs.swift @@ -0,0 +1,382 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger +import Deferred + +private let log = Logger.syncLogger + +open class SQLiteRemoteClientsAndTabs: RemoteClientsAndTabs { + let db: BrowserDB + + public init(db: BrowserDB) { + self.db = db + } + + class func remoteClientFactory(_ row: SDRow) -> RemoteClient { + let guid = row["guid"] as? String + let name = row["name"] as! String + let mod = (row["modified"] as! NSNumber).uint64Value + let type = row["type"] as? String + let form = row["formfactor"] as? String + let os = row["os"] as? String + let version = row["version"] as? String + let fxaDeviceId = row["fxaDeviceId"] as? String + return RemoteClient(guid: guid, name: name, modified: mod, type: type, formfactor: form, os: os, version: version, fxaDeviceId: fxaDeviceId) + } + + class func remoteTabFactory(_ row: SDRow) -> RemoteTab { + let clientGUID = row["client_guid"] as? String + let url = URL(string: row["url"] as! String)! // TODO: find a way to make this less dangerous. + let title = row["title"] as! String + let history = SQLiteRemoteClientsAndTabs.convertStringToHistory(row["history"] as? String) + let lastUsed = row.getTimestamp("last_used")! + return RemoteTab(clientGUID: clientGUID, URL: url, title: title, history: history, lastUsed: lastUsed, icon: nil) + } + + class func convertStringToHistory(_ history: String?) -> [URL] { + guard let data = history?.data(using: String.Encoding.utf8), + let decoded = try? JSONSerialization.jsonObject(with: data, options: [JSONSerialization.ReadingOptions.allowFragments]), + let urlStrings = decoded as? [String] else { + return [] + } + return optFilter(urlStrings.flatMap { URL(string: $0) }) + } + + class func convertHistoryToString(_ history: [URL]) -> String? { + let historyAsStrings = optFilter(history.map { $0.absoluteString }) + + guard let data = try? JSONSerialization.data(withJSONObject: historyAsStrings, options: []) else { + return nil + } + return String(data: data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) + } + + open func wipeClients() -> Success { + return db.run("DELETE FROM \(TableClients)") + } + + open func wipeRemoteTabs() -> Success { + return db.run("DELETE FROM \(TableTabs) WHERE client_guid IS NOT NULL") + } + + open func wipeTabs() -> Success { + return db.run("DELETE FROM \(TableTabs)") + } + + open func insertOrUpdateTabs(_ tabs: [RemoteTab]) -> Deferred> { + return self.insertOrUpdateTabsForClientGUID(nil, tabs: tabs) + } + + open func insertOrUpdateTabsForClientGUID(_ clientGUID: String?, tabs: [RemoteTab]) -> Deferred> { + let deleteQuery = "DELETE FROM \(TableTabs) WHERE client_guid IS ?" + let deleteArgs: Args = [clientGUID] + + return db.transaction { connection -> Int in + // Delete any existing tabs. + try connection.executeChange(deleteQuery, withArgs: deleteArgs) + + // Insert replacement tabs. + var inserted = 0 + for tab in tabs { + let args: Args = [ + tab.clientGUID, + tab.URL.absoluteString, + tab.title, + SQLiteRemoteClientsAndTabs.convertHistoryToString(tab.history), + NSNumber(value: tab.lastUsed) + ] + + let lastInsertedRowID = connection.lastInsertedRowID + + // We trust that each tab's clientGUID matches the supplied client! + // Really tabs shouldn't have a GUID at all. Future cleanup! + try connection.executeChange("INSERT INTO \(TableTabs) (client_guid, url, title, history, last_used) VALUES (?, ?, ?, ?, ?)", withArgs: args) + + if connection.lastInsertedRowID == lastInsertedRowID { + log.debug("Unable to INSERT RemoteTab!") + } else { + inserted += 1 + } + } + + return inserted + } + } + + open func insertOrUpdateClients(_ clients: [RemoteClient]) -> Deferred> { + // TODO: insert multiple clients in a single query. + // ORM systems are foolish. + return db.transaction { connection -> Int in + var succeeded = 0 + + // Update or insert client records. + for client in clients { + let args: Args = [ + client.name, + NSNumber(value: client.modified), + client.type, + client.formfactor, + client.os, + client.version, + client.fxaDeviceId, + client.guid + ] + + try connection.executeChange("UPDATE \(TableClients) SET name = ?, modified = ?, type = ?, formfactor = ?, os = ?, version = ?, fxaDeviceId = ? WHERE guid = ?", withArgs: args) + + if connection.numberOfRowsModified == 0 { + let args: Args = [ + client.guid, + client.name, + NSNumber(value: client.modified), + client.type, + client.formfactor, + client.os, + client.version, + client.fxaDeviceId + ] + + let lastInsertedRowID = connection.lastInsertedRowID + + try connection.executeChange("INSERT INTO \(TableClients) (guid, name, modified, type, formfactor, os, version, fxaDeviceId) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", withArgs: args) + + if connection.lastInsertedRowID == lastInsertedRowID { + log.debug("INSERT did not change last inserted row ID.") + } + } + + succeeded += 1 + } + + return succeeded + } + } + + open func insertOrUpdateClient(_ client: RemoteClient) -> Deferred> { + return insertOrUpdateClients([client]) + } + + open func deleteClient(guid: GUID) -> Success { + let deleteTabsQuery = "DELETE FROM \(TableTabs) WHERE client_guid = ?" + let deleteClientQuery = "DELETE FROM \(TableClients) WHERE guid = ?" + let deleteArgs: Args = [guid] + + return db.transaction { connection -> Void in + try connection.executeChange(deleteClientQuery, withArgs: deleteArgs) + try connection.executeChange(deleteTabsQuery, withArgs: deleteArgs) + } + } + + open func getClient(guid: GUID) -> Deferred> { + let factory = SQLiteRemoteClientsAndTabs.remoteClientFactory + return self.db.runQuery("SELECT * FROM \(TableClients) WHERE guid = ?", args: [guid], factory: factory) >>== { deferMaybe($0[0]) } + } + + open func getClient(fxaDeviceId: String) -> Deferred> { + let factory = SQLiteRemoteClientsAndTabs.remoteClientFactory + return self.db.runQuery("SELECT * FROM \(TableClients) WHERE fxaDeviceId = ?", args: [fxaDeviceId], factory: factory) >>== { deferMaybe($0[0]) } + } + + open func getClientWithId(_ clientID: GUID) -> Deferred> { + return self.getClient(guid: clientID) + } + + open func getClients() -> Deferred> { + return db.withConnection { connection -> [RemoteClient] in + let cursor = connection.executeQuery("SELECT * FROM \(TableClients) WHERE EXISTS (SELECT 1 FROM \(TableRemoteDevices) rd WHERE rd.guid = fxaDeviceId) ORDER BY modified DESC", factory: SQLiteRemoteClientsAndTabs.remoteClientFactory) + defer { + cursor.close() + } + + return cursor.asArray() + } + } + + open func getClientGUIDs() -> Deferred>> { + let c = db.runQuery("SELECT guid FROM \(TableClients) WHERE guid IS NOT NULL", args: nil, factory: { $0["guid"] as! String }) + return c >>== { cursor in + let guids = Set(cursor.asArray()) + return deferMaybe(guids) + } + } + + open func getTabsForClientWithGUID(_ guid: GUID?) -> Deferred> { + let tabsSQL: String + let clientArgs: Args? + if let _ = guid { + tabsSQL = "SELECT * FROM \(TableTabs) WHERE client_guid = ?" + clientArgs = [guid] + } else { + tabsSQL = "SELECT * FROM \(TableTabs) WHERE client_guid IS NULL" + clientArgs = nil + } + + log.debug("Looking for tabs for client with guid: \(guid ?? "nil")") + return db.runQuery(tabsSQL, args: clientArgs, factory: SQLiteRemoteClientsAndTabs.remoteTabFactory) >>== { + let tabs = $0.asArray() + log.debug("Found \(tabs.count) tabs for client with guid: \(guid ?? "nil")") + return deferMaybe(tabs) + } + } + + open func getClientsAndTabs() -> Deferred> { + return db.withConnection { conn -> ([RemoteClient], [RemoteTab]) in + let clientsCursor = conn.executeQuery("SELECT * FROM \(TableClients) WHERE EXISTS (SELECT 1 FROM \(TableRemoteDevices) rd WHERE rd.guid = fxaDeviceId) ORDER BY modified DESC", factory: SQLiteRemoteClientsAndTabs.remoteClientFactory) + let tabsCursor = conn.executeQuery("SELECT * FROM \(TableTabs) WHERE client_guid IS NOT NULL ORDER BY client_guid DESC, last_used DESC", factory: SQLiteRemoteClientsAndTabs.remoteTabFactory) + + defer { + clientsCursor.close() + tabsCursor.close() + } + + return (clientsCursor.asArray(), tabsCursor.asArray()) + } >>== { clients, tabs in + var acc = [String: [RemoteTab]]() + for tab in tabs { + if let guid = tab.clientGUID { + if acc[guid] == nil { + acc[guid] = [tab] + } else { + acc[guid]!.append(tab) + } + } else { + log.error("RemoteTab (\(tab)) has a nil clientGUID") + } + } + + // Most recent first. + let fillTabs: (RemoteClient) -> ClientAndTabs = { client in + var tabs: [RemoteTab]? = nil + if let guid: String = client.guid { + tabs = acc[guid] + } + return ClientAndTabs(client: client, tabs: tabs ?? []) + } + + return deferMaybe(clients.map(fillTabs)) + } + } + + open func deleteCommands() -> Success { + return db.run("DELETE FROM \(TableSyncCommands)") + } + + open func deleteCommands(_ clientGUID: GUID) -> Success { + return db.run("DELETE FROM \(TableSyncCommands) WHERE client_guid = ?", withArgs: [clientGUID] as Args) + } + + open func insertCommand(_ command: SyncCommand, forClients clients: [RemoteClient]) -> Deferred> { + return insertCommands([command], forClients: clients) + } + + open func insertCommands(_ commands: [SyncCommand], forClients clients: [RemoteClient]) -> Deferred> { + return db.transaction { connection -> Int in + var numberOfInserts = 0 + + // Update or insert client records. + for command in commands { + for client in clients { + do { + if let commandID = try self.insert(connection, sql: "INSERT INTO \(TableSyncCommands) (client_guid, value) VALUES (?, ?)", args: [client.guid, command.value] as Args) { + log.verbose("Inserted command: \(commandID)") + numberOfInserts += 1 + } else { + log.warning("Command not inserted, but no error!") + } + } catch let err as NSError { + log.error("insertCommands(_:, forClients:) failed: \(err.localizedDescription) (numberOfInserts: \(numberOfInserts)") + throw err + } + } + } + + return numberOfInserts + } + } + + open func getCommands() -> Deferred> { + return db.withConnection { connection -> [GUID: [SyncCommand]] in + let cursor = connection.executeQuery("SELECT * FROM \(TableSyncCommands)", factory: { row -> SyncCommand in + SyncCommand( + id: row["command_id"] as? Int, + value: row["value"] as! String, + clientGUID: row["client_guid"] as? GUID) + }) + defer { + cursor.close() + } + + return self.clientsFromCommands(cursor.asArray()) + } + } + + func clientsFromCommands(_ commands: [SyncCommand]) -> [GUID: [SyncCommand]] { + var syncCommands = [GUID: [SyncCommand]]() + for command in commands { + var cmds: [SyncCommand] = syncCommands[command.clientGUID!] ?? [SyncCommand]() + cmds.append(command) + syncCommands[command.clientGUID!] = cmds + } + return syncCommands + } + + func insert(_ db: SQLiteDBConnection, sql: String, args: Args?) throws -> Int? { + let lastID = db.lastInsertedRowID + try db.executeChange(sql, withArgs: args) + + let id = db.lastInsertedRowID + if id == lastID { + log.debug("INSERT did not change last inserted row ID.") + return nil + } + + return id + } +} + +extension SQLiteRemoteClientsAndTabs: RemoteDevices { + open func replaceRemoteDevices(_ remoteDevices: [RemoteDevice]) -> Success { + // Drop corrupted records and our own record too. + let remoteDevices = remoteDevices.filter { $0.id != nil && $0.type != nil && !$0.isCurrentDevice } + + return db.transaction { conn -> Void in + try conn.executeChange("DELETE FROM \(TableRemoteDevices)") + + let now = Date.now() + + for device in remoteDevices { + let sql = + "INSERT INTO \(TableRemoteDevices) (guid, name, type, is_current_device, date_created, date_modified, last_access_time) " + + "VALUES (?, ?, ?, ?, ?, ?, ?)" + let args: Args = [device.id, device.name, device.type, device.isCurrentDevice, now, now, device.lastAccessTime] + try conn.executeChange(sql, withArgs: args) + } + } + } +} + +extension SQLiteRemoteClientsAndTabs: ResettableSyncStorage { + public func resetClient() -> Success { + // For this engine, resetting is equivalent to wiping. + return self.clear() + } + + public func clear() -> Success { + return db.transaction { conn -> Void in + try conn.executeChange("DELETE FROM \(TableTabs) WHERE client_guid IS NOT NULL") + try conn.executeChange("DELETE FROM \(TableClients)") + } + } +} + +extension SQLiteRemoteClientsAndTabs: AccountRemovalDelegate { + public func onRemovedAccount() -> Success { + log.info("Clearing clients and tabs after account removal.") + // TODO: Bug 1168690 - delete our client and tabs records from the server. + return self.resetClient() + } +} diff --git a/mobile/ios/Storage/SQL/Schema.swift b/mobile/ios/Storage/SQL/Schema.swift new file mode 100644 index 0000000000..0c22d65460 --- /dev/null +++ b/mobile/ios/Storage/SQL/Schema.swift @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation + +/** + * Something that knows how to construct a database. + */ +public protocol Schema { + var name: String { get } + var version: Int { get } + + func create(_ db: SQLiteDBConnection) -> Bool + func update(_ db: SQLiteDBConnection, from: Int) -> Bool + func drop(_ db: SQLiteDBConnection) -> Bool +} + +enum SchemaUpgradeResult { + case success + case failure + case skipped +} diff --git a/mobile/ios/Storage/Sharing.swift b/mobile/ios/Storage/Sharing.swift new file mode 100644 index 0000000000..51fa13a1c8 --- /dev/null +++ b/mobile/ios/Storage/Sharing.swift @@ -0,0 +1,30 @@ +/* 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/. */ + +import Foundation +import UIKit +import Shared + +// A small structure to encapsulate all the possible data that we can get +// from an application sharing a web page or a URL. +public struct ShareItem { + public let url: String + public let title: String? + public let favicon: Favicon? + + public init(url: String, title: String?, favicon: Favicon?) { + self.url = url + self.title = title + self.favicon = favicon + } + + // We only support sharing HTTP and HTTPS URLs, as well as data URIs. + public var isShareable: Bool { + return URL(string: url)?.isWebPage() ?? false + } +} + +public protocol ShareToDestination { + func shareItem(_ item: ShareItem) -> Success +} diff --git a/mobile/ios/Storage/Site.swift b/mobile/ios/Storage/Site.swift new file mode 100644 index 0000000000..0da738f264 --- /dev/null +++ b/mobile/ios/Storage/Site.swift @@ -0,0 +1,95 @@ +/* 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/. */ + +import UIKit +import Shared + +public protocol Identifiable: Equatable { + var id: Int? { get set } +} + +public func ==(lhs: T, rhs: T) -> Bool where T: Identifiable { + return lhs.id == rhs.id +} + +public enum IconType: Int { + public func isPreferredTo (_ other: IconType) -> Bool { + return rank > other.rank + } + + fileprivate var rank: Int { + switch self { + case .appleIconPrecomposed: + return 5 + case .appleIcon: + return 4 + case .icon: + return 3 + case .local: + return 2 + case .guess: + return 1 + case .noneFound: + return 0 + } + } + + case icon = 0 + case appleIcon = 1 + case appleIconPrecomposed = 2 + case guess = 3 + case local = 4 + case noneFound = 5 +} + +open class Favicon: Identifiable { + open var id: Int? + + open let url: String + open let date: Date + open var width: Int? + open var height: Int? + open let type: IconType + + public init(url: String, date: Date = Date(), type: IconType) { + self.url = url + self.date = date + self.type = type + } +} + +// TODO: Site shouldn't have all of these optional decorators. Include those in the +// cursor results, perhaps as a tuple. +open class Site: Identifiable { + open var id: Int? + var guid: String? + + open var tileURL: URL { + return URL(string: url)?.domainURL ?? URL(string: "about:blank")! + } + + open let url: String + open let title: String + open var metadata: PageMetadata? + // Sites may have multiple favicons. We'll return the largest. + open var icon: Favicon? + open var latestVisit: Visit? + open fileprivate(set) var bookmarked: Bool? + + public convenience init(url: String, title: String) { + self.init(url: url, title: title, bookmarked: false, guid: nil) + } + + public init(url: String, title: String, bookmarked: Bool?, guid: String? = nil) { + self.url = url + self.title = title + self.bookmarked = bookmarked + self.guid = guid + } + + open func setBookmarked(_ bookmarked: Bool) { + self.bookmarked = bookmarked + } + +} diff --git a/mobile/ios/Storage/Storage-Bridging-Header.h b/mobile/ios/Storage/Storage-Bridging-Header.h new file mode 100644 index 0000000000..2be82409d9 --- /dev/null +++ b/mobile/ios/Storage/Storage-Bridging-Header.h @@ -0,0 +1,10 @@ +#ifndef Client_Storage_Bridging_Header_h +#define Client_Storage_Bridging_Header_h + +#define SQLITE_HAS_CODEC 1 + +#import "Shared-Bridging-Header.h" +#import +#import "ThirdParty/sqlcipher/sqlite3.h" + +#endif diff --git a/mobile/ios/Storage/Storage.xcodeproj/project.pbxproj b/mobile/ios/Storage/Storage.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..640f468ea7 --- /dev/null +++ b/mobile/ios/Storage/Storage.xcodeproj/project.pbxproj @@ -0,0 +1,727 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0B2770451A89276900CE7692 /* BookmarksSqlite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2770441A89276900CE7692 /* BookmarksSqlite.swift */; }; + 0B2770471A893C2C00CE7692 /* TestBookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2770461A893C2C00CE7692 /* TestBookmarks.swift */; }; + 0B2770481A893C4700CE7692 /* BookmarksSqlite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2770441A89276900CE7692 /* BookmarksSqlite.swift */; }; + 0B2770491A893C9500CE7692 /* Bookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA497801A7B094B004C8E17 /* Bookmarks.swift */; }; + 0B2770DD1A8AD83200CE7692 /* Bytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2770DC1A8AD83200CE7692 /* Bytes.swift */; }; + 0B2770E91A8AD85000CE7692 /* Bytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2770DC1A8AD83200CE7692 /* Bytes.swift */; }; + 0B30602F1A80338F0085B8BC /* Passwords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B30602E1A80338F0085B8BC /* Passwords.swift */; }; + 0B3060311A8151B70085B8BC /* SQLitePasswords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3060301A8151B70085B8BC /* SQLitePasswords.swift */; }; + 0BA4977E1A7B0941004C8E17 /* SQLiteHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA4977A1A7B0941004C8E17 /* SQLiteHistory.swift */; }; + 0BA497821A7B094B004C8E17 /* Bookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA497801A7B094B004C8E17 /* Bookmarks.swift */; }; + 0BA497831A7B094B004C8E17 /* Visit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA497811A7B094B004C8E17 /* Visit.swift */; }; + 0BA4978C1A7B0E44004C8E17 /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4C01A699EF200A406E2 /* Cursor.swift */; }; + 0BA4978D1A7B0E55004C8E17 /* FileAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4D01A69A14500A406E2 /* FileAccessor.swift */; }; + 0BAE69561A7E1FD100B3609D /* SchemaTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BAE69551A7E1FD100B3609D /* SchemaTable.swift */; }; + 0BAE69571A7E209200B3609D /* SchemaTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BAE69551A7E1FD100B3609D /* SchemaTable.swift */; }; + 0BAE69591A7EEF8E00B3609D /* TestTableTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BAE69581A7EEF8E00B3609D /* TestTableTable.swift */; }; + 0BCFBBAF1A77650E0087E26D /* GenericTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59B3F1AAD619686DB9450C /* GenericTable.swift */; }; + 0BCFBBB41A7769A30087E26D /* JoinedHistoryVisitsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59BCB8D38CE6E6F5F5F2DE /* JoinedHistoryVisitsTable.swift */; }; + 0BCFBBB51A7769B70087E26D /* VisitsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59B22E909B6CAC95DBE879 /* VisitsTable.swift */; }; + 0BCFBBB81A776A200087E26D /* MockFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCFBBB71A776A200087E26D /* MockFiles.swift */; }; + 0BF42D3E1A7C148F00889E28 /* Favicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D3D1A7C148F00889E28 /* Favicons.swift */; }; + 0BF42D401A7C18CD00889E28 /* SQLFavicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D3F1A7C18CD00889E28 /* SQLFavicons.swift */; }; + 0BF42D421A7C31E300889E28 /* JoinedFaviconsHistoryTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D411A7C31E300889E28 /* JoinedFaviconsHistoryTable.swift */; }; + 0BF42D441A7C31EE00889E28 /* FaviconsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D431A7C31EE00889E28 /* FaviconsTable.swift */; }; + 0BF42D461A7C52C800889E28 /* TestFaviconsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D451A7C52C800889E28 /* TestFaviconsTable.swift */; }; + 0BF42D471A7C558000889E28 /* Visit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA497811A7B094B004C8E17 /* Visit.swift */; }; + 0BF42D481A7C55D200889E28 /* Site.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4D61A69A28000A406E2 /* Site.swift */; }; + 0BF42D4A1A7C55F000889E28 /* FaviconsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D431A7C31EE00889E28 /* FaviconsTable.swift */; }; + 0BF42D4B1A7C55F300889E28 /* JoinedFaviconsHistoryTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D411A7C31E300889E28 /* JoinedFaviconsHistoryTable.swift */; }; + 0BF42D4D1A7CC4ED00889E28 /* TestJoinedFaviconTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF42D4C1A7CC4ED00889E28 /* TestJoinedFaviconTable.swift */; }; + 282DA49B1A699E0300A406E2 /* Storage.h in Headers */ = {isa = PBXBuildFile; fileRef = 282DA49A1A699E0300A406E2 /* Storage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 282DA4A11A699E0300A406E2 /* Storage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 282DA4951A699E0300A406E2 /* Storage.framework */; }; + 282DA4A81A699E0300A406E2 /* StorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4A71A699E0300A406E2 /* StorageTests.swift */; }; + 282DA4C21A699EF200A406E2 /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4C01A699EF200A406E2 /* Cursor.swift */; }; + 282DA4C51A699F8A00A406E2 /* SwiftData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4C41A699F8A00A406E2 /* SwiftData.swift */; }; + 282DA4C61A699F8A00A406E2 /* SwiftData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4C41A699F8A00A406E2 /* SwiftData.swift */; }; + 282DA4D21A69A14500A406E2 /* FileAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4D01A69A14500A406E2 /* FileAccessor.swift */; }; + 282DA4D41A69A24300A406E2 /* History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4D31A69A24300A406E2 /* History.swift */; }; + 282DA4D71A69A28000A406E2 /* Site.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282DA4D61A69A28000A406E2 /* Site.swift */; }; + 282DA5211A69BCB700A406E2 /* module.modulemap in Sources */ = {isa = PBXBuildFile; fileRef = 282DA51F1A69BCB700A406E2 /* module.modulemap */; }; + 282DA5241A69BCBB00A406E2 /* libsqlite3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 282DA5231A69BCBB00A406E2 /* libsqlite3.0.dylib */; }; + 4A59B21913DCFA81C7CD9C91 /* GenericTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59B3F1AAD619686DB9450C /* GenericTable.swift */; }; + 4A59B334A243792894D6E614 /* TestHistoryTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59B6E9AB0A08F28227C050 /* TestHistoryTable.swift */; }; + 4A59BA1E93D5603E198EDCB9 /* HistoryTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59BB07A2812FE4B516FD30 /* HistoryTable.swift */; }; + 4A59BAEB154EA6E1B621E067 /* BrowserDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59BF61F0D956D2A1BDAE29 /* BrowserDB.swift */; }; + 4A59BB4F36A20F30229034C6 /* VisitsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59B22E909B6CAC95DBE879 /* VisitsTable.swift */; }; + 4A59BC6033BD93D1DC36E18F /* TestJoinedHistoryVisits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59B33FF96A39A59CBBBBD7 /* TestJoinedHistoryVisits.swift */; }; + 4A59BD24F6210866F59EF0F6 /* JoinedHistoryVisitsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59BCB8D38CE6E6F5F5F2DE /* JoinedHistoryVisitsTable.swift */; }; + 4A59BF0BBF50FC218A6D1143 /* BrowserDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59BF61F0D956D2A1BDAE29 /* BrowserDB.swift */; }; + 4A59BF2F408CDEF8D50AF9D3 /* TestVisitsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59BE48DBF43989C51D3F98 /* TestVisitsTable.swift */; }; + 4A59BFF7C37812C7955B9E79 /* HistoryTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A59BB07A2812FE4B516FD30 /* HistoryTable.swift */; }; + E47726181A8A794B00FC058B /* ReadingList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47726171A8A794B00FC058B /* ReadingList.swift */; }; + E47726191A8A794B00FC058B /* ReadingList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47726171A8A794B00FC058B /* ReadingList.swift */; }; + E477261B1A8A7DE500FC058B /* SQLiteReadingList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E477261A1A8A7DE500FC058B /* SQLiteReadingList.swift */; }; + E477261C1A8A7DE500FC058B /* SQLiteReadingList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E477261A1A8A7DE500FC058B /* SQLiteReadingList.swift */; }; + E477261E1A8A7EDA00FC058B /* ReadingListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E477261D1A8A7EDA00FC058B /* ReadingListTable.swift */; }; + E477261F1A8A7EDA00FC058B /* ReadingListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E477261D1A8A7EDA00FC058B /* ReadingListTable.swift */; }; + E47726211A8A87F400FC058B /* TestReadingListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47726201A8A87F400FC058B /* TestReadingListTable.swift */; }; + E4F43AC21A8CF9A200ACAC05 /* TestSQLiteReadingList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F43AC11A8CF9A200ACAC05 /* TestSQLiteReadingList.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 282DA4A21A699E0300A406E2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 282DA48C1A699E0300A406E2 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 282DA4941A699E0300A406E2; + remoteInfo = Storage; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0B2770441A89276900CE7692 /* BookmarksSqlite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksSqlite.swift; sourceTree = ""; }; + 0B2770461A893C2C00CE7692 /* TestBookmarks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestBookmarks.swift; sourceTree = ""; }; + 0B2770DC1A8AD83200CE7692 /* Bytes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bytes.swift; path = ../../Sync/Bytes.swift; sourceTree = ""; }; + 0B30602E1A80338F0085B8BC /* Passwords.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Passwords.swift; sourceTree = ""; }; + 0B3060301A8151B70085B8BC /* SQLitePasswords.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLitePasswords.swift; sourceTree = ""; }; + 0BA4977A1A7B0941004C8E17 /* SQLiteHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SQLiteHistory.swift; path = SQL/SQLiteHistory.swift; sourceTree = ""; }; + 0BA497801A7B094B004C8E17 /* Bookmarks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bookmarks.swift; sourceTree = ""; }; + 0BA497811A7B094B004C8E17 /* Visit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Visit.swift; sourceTree = ""; }; + 0BAE69551A7E1FD100B3609D /* SchemaTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaTable.swift; sourceTree = ""; }; + 0BAE69581A7EEF8E00B3609D /* TestTableTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestTableTable.swift; sourceTree = ""; }; + 0BCFBBB71A776A200087E26D /* MockFiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockFiles.swift; sourceTree = ""; }; + 0BF42D3D1A7C148F00889E28 /* Favicons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Favicons.swift; sourceTree = ""; }; + 0BF42D3F1A7C18CD00889E28 /* SQLFavicons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLFavicons.swift; sourceTree = ""; }; + 0BF42D411A7C31E300889E28 /* JoinedFaviconsHistoryTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JoinedFaviconsHistoryTable.swift; sourceTree = ""; }; + 0BF42D431A7C31EE00889E28 /* FaviconsTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconsTable.swift; sourceTree = ""; }; + 0BF42D451A7C52C800889E28 /* TestFaviconsTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestFaviconsTable.swift; sourceTree = ""; }; + 0BF42D4C1A7CC4ED00889E28 /* TestJoinedFaviconTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestJoinedFaviconTable.swift; sourceTree = ""; }; + 282DA4951A699E0300A406E2 /* Storage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Storage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 282DA4991A699E0300A406E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 282DA49A1A699E0300A406E2 /* Storage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Storage.h; sourceTree = ""; }; + 282DA4A01A699E0300A406E2 /* StorageTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StorageTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 282DA4A61A699E0300A406E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 282DA4A71A699E0300A406E2 /* StorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageTests.swift; sourceTree = ""; }; + 282DA4C01A699EF200A406E2 /* Cursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cursor.swift; sourceTree = ""; }; + 282DA4C41A699F8A00A406E2 /* SwiftData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftData.swift; path = ThirdParty/SwiftData.swift; sourceTree = ""; }; + 282DA4D01A69A14500A406E2 /* FileAccessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileAccessor.swift; sourceTree = ""; }; + 282DA4D31A69A24300A406E2 /* History.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = History.swift; sourceTree = ""; }; + 282DA4D61A69A28000A406E2 /* Site.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Site.swift; sourceTree = ""; }; + 282DA51F1A69BCB700A406E2 /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + 282DA5231A69BCBB00A406E2 /* libsqlite3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.0.dylib; path = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/usr/lib/libsqlite3.0.dylib; sourceTree = ""; }; + 4A59B22E909B6CAC95DBE879 /* VisitsTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VisitsTable.swift; path = SQL/VisitsTable.swift; sourceTree = ""; }; + 4A59B33FF96A39A59CBBBBD7 /* TestJoinedHistoryVisits.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestJoinedHistoryVisits.swift; sourceTree = ""; }; + 4A59B3F1AAD619686DB9450C /* GenericTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GenericTable.swift; path = SQL/GenericTable.swift; sourceTree = ""; }; + 4A59B6E9AB0A08F28227C050 /* TestHistoryTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHistoryTable.swift; sourceTree = ""; }; + 4A59BB07A2812FE4B516FD30 /* HistoryTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HistoryTable.swift; path = SQL/HistoryTable.swift; sourceTree = ""; }; + 4A59BCB8D38CE6E6F5F5F2DE /* JoinedHistoryVisitsTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JoinedHistoryVisitsTable.swift; path = SQL/JoinedHistoryVisitsTable.swift; sourceTree = ""; }; + 4A59BE48DBF43989C51D3F98 /* TestVisitsTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestVisitsTable.swift; sourceTree = ""; }; + 4A59BF61F0D956D2A1BDAE29 /* BrowserDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BrowserDB.swift; path = SQL/BrowserDB.swift; sourceTree = ""; }; + E47726171A8A794B00FC058B /* ReadingList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingList.swift; sourceTree = ""; }; + E477261A1A8A7DE500FC058B /* SQLiteReadingList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SQLiteReadingList.swift; path = SQL/SQLiteReadingList.swift; sourceTree = ""; }; + E477261D1A8A7EDA00FC058B /* ReadingListTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListTable.swift; sourceTree = ""; }; + E47726201A8A87F400FC058B /* TestReadingListTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestReadingListTable.swift; sourceTree = ""; }; + E4F43AC11A8CF9A200ACAC05 /* TestSQLiteReadingList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSQLiteReadingList.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 282DA4911A699E0300A406E2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 282DA5241A69BCBB00A406E2 /* libsqlite3.0.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 282DA49D1A699E0300A406E2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 282DA4A11A699E0300A406E2 /* Storage.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 282DA48B1A699E0300A406E2 = { + isa = PBXGroup; + children = ( + 282DA5231A69BCBB00A406E2 /* libsqlite3.0.dylib */, + 282DA5201A69BCB700A406E2 /* modules */, + 282DA4971A699E0300A406E2 /* Storage */, + 282DA4C31A699F5600A406E2 /* Third-Party Source */, + 282DA4A41A699E0300A406E2 /* StorageTests */, + 282DA4961A699E0300A406E2 /* Products */, + ); + sourceTree = ""; + }; + 282DA4961A699E0300A406E2 /* Products */ = { + isa = PBXGroup; + children = ( + 282DA4951A699E0300A406E2 /* Storage.framework */, + 282DA4A01A699E0300A406E2 /* StorageTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 282DA4971A699E0300A406E2 /* Storage */ = { + isa = PBXGroup; + children = ( + 0B2770DC1A8AD83200CE7692 /* Bytes.swift */, + 0BA497801A7B094B004C8E17 /* Bookmarks.swift */, + E47726171A8A794B00FC058B /* ReadingList.swift */, + 0BA497811A7B094B004C8E17 /* Visit.swift */, + 282DA4D91A69A2C400A406E2 /* SQL */, + 282DA4D01A69A14500A406E2 /* FileAccessor.swift */, + 282DA4D61A69A28000A406E2 /* Site.swift */, + 282DA4D31A69A24300A406E2 /* History.swift */, + 282DA4C01A699EF200A406E2 /* Cursor.swift */, + 282DA49A1A699E0300A406E2 /* Storage.h */, + 282DA4981A699E0300A406E2 /* Supporting Files */, + 0BF42D3D1A7C148F00889E28 /* Favicons.swift */, + 0B30602E1A80338F0085B8BC /* Passwords.swift */, + ); + path = Storage; + sourceTree = ""; + }; + 282DA4981A699E0300A406E2 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 282DA4991A699E0300A406E2 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 282DA4A41A699E0300A406E2 /* StorageTests */ = { + isa = PBXGroup; + children = ( + 282DA4A71A699E0300A406E2 /* StorageTests.swift */, + 282DA4A51A699E0300A406E2 /* Supporting Files */, + 4A59B6E9AB0A08F28227C050 /* TestHistoryTable.swift */, + 0BF42D451A7C52C800889E28 /* TestFaviconsTable.swift */, + 4A59B33FF96A39A59CBBBBD7 /* TestJoinedHistoryVisits.swift */, + 0BF42D4C1A7CC4ED00889E28 /* TestJoinedFaviconTable.swift */, + 4A59BE48DBF43989C51D3F98 /* TestVisitsTable.swift */, + 0BCFBBB71A776A200087E26D /* MockFiles.swift */, + 0BAE69581A7EEF8E00B3609D /* TestTableTable.swift */, + 0B2770461A893C2C00CE7692 /* TestBookmarks.swift */, + E47726201A8A87F400FC058B /* TestReadingListTable.swift */, + E4F43AC11A8CF9A200ACAC05 /* TestSQLiteReadingList.swift */, + ); + path = StorageTests; + sourceTree = ""; + }; + 282DA4A51A699E0300A406E2 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 282DA4A61A699E0300A406E2 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 282DA4C31A699F5600A406E2 /* Third-Party Source */ = { + isa = PBXGroup; + children = ( + 282DA4C41A699F8A00A406E2 /* SwiftData.swift */, + ); + name = "Third-Party Source"; + sourceTree = ""; + }; + 282DA4D91A69A2C400A406E2 /* SQL */ = { + isa = PBXGroup; + children = ( + 0B2770441A89276900CE7692 /* BookmarksSqlite.swift */, + 4A59BF61F0D956D2A1BDAE29 /* BrowserDB.swift */, + 0BF42D431A7C31EE00889E28 /* FaviconsTable.swift */, + 4A59B3F1AAD619686DB9450C /* GenericTable.swift */, + 4A59BB07A2812FE4B516FD30 /* HistoryTable.swift */, + 0BF42D411A7C31E300889E28 /* JoinedFaviconsHistoryTable.swift */, + 4A59BCB8D38CE6E6F5F5F2DE /* JoinedHistoryVisitsTable.swift */, + E477261D1A8A7EDA00FC058B /* ReadingListTable.swift */, + 0BAE69551A7E1FD100B3609D /* SchemaTable.swift */, + 0BF42D3F1A7C18CD00889E28 /* SQLFavicons.swift */, + 0BA4977A1A7B0941004C8E17 /* SQLiteHistory.swift */, + 0B3060301A8151B70085B8BC /* SQLitePasswords.swift */, + E477261A1A8A7DE500FC058B /* SQLiteReadingList.swift */, + 4A59B22E909B6CAC95DBE879 /* VisitsTable.swift */, + ); + name = SQL; + sourceTree = ""; + }; + 282DA5201A69BCB700A406E2 /* modules */ = { + isa = PBXGroup; + children = ( + 282DA51F1A69BCB700A406E2 /* module.modulemap */, + ); + path = modules; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 282DA4921A699E0300A406E2 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 282DA49B1A699E0300A406E2 /* Storage.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 282DA4941A699E0300A406E2 /* Storage */ = { + isa = PBXNativeTarget; + buildConfigurationList = 282DA4AB1A699E0300A406E2 /* Build configuration list for PBXNativeTarget "Storage" */; + buildPhases = ( + 282DA4901A699E0300A406E2 /* Sources */, + 282DA4911A699E0300A406E2 /* Frameworks */, + 282DA4921A699E0300A406E2 /* Headers */, + 282DA4931A699E0300A406E2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Storage; + productName = Storage; + productReference = 282DA4951A699E0300A406E2 /* Storage.framework */; + productType = "com.apple.product-type.framework"; + }; + 282DA49F1A699E0300A406E2 /* StorageTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 282DA4AE1A699E0300A406E2 /* Build configuration list for PBXNativeTarget "StorageTests" */; + buildPhases = ( + 282DA49C1A699E0300A406E2 /* Sources */, + 282DA49D1A699E0300A406E2 /* Frameworks */, + 282DA49E1A699E0300A406E2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 282DA4A31A699E0300A406E2 /* PBXTargetDependency */, + ); + name = StorageTests; + productName = StorageTests; + productReference = 282DA4A01A699E0300A406E2 /* StorageTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 282DA48C1A699E0300A406E2 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = Mozilla; + TargetAttributes = { + 282DA4941A699E0300A406E2 = { + CreatedOnToolsVersion = 6.1.1; + }; + 282DA49F1A699E0300A406E2 = { + CreatedOnToolsVersion = 6.1.1; + }; + }; + }; + buildConfigurationList = 282DA48F1A699E0300A406E2 /* Build configuration list for PBXProject "Storage" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 282DA48B1A699E0300A406E2; + productRefGroup = 282DA4961A699E0300A406E2 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 282DA4941A699E0300A406E2 /* Storage */, + 282DA49F1A699E0300A406E2 /* StorageTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 282DA4931A699E0300A406E2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 282DA49E1A699E0300A406E2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 282DA4901A699E0300A406E2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B30602F1A80338F0085B8BC /* Passwords.swift in Sources */, + 0BA497821A7B094B004C8E17 /* Bookmarks.swift in Sources */, + 282DA4C51A699F8A00A406E2 /* SwiftData.swift in Sources */, + E47726181A8A794B00FC058B /* ReadingList.swift in Sources */, + E477261E1A8A7EDA00FC058B /* ReadingListTable.swift in Sources */, + 0BA4977E1A7B0941004C8E17 /* SQLiteHistory.swift in Sources */, + 282DA5211A69BCB700A406E2 /* module.modulemap in Sources */, + 0BA4978C1A7B0E44004C8E17 /* Cursor.swift in Sources */, + 0BF42D401A7C18CD00889E28 /* SQLFavicons.swift in Sources */, + 0B2770451A89276900CE7692 /* BookmarksSqlite.swift in Sources */, + 282DA4D71A69A28000A406E2 /* Site.swift in Sources */, + 0B2770DD1A8AD83200CE7692 /* Bytes.swift in Sources */, + 282DA4D41A69A24300A406E2 /* History.swift in Sources */, + 0BA497831A7B094B004C8E17 /* Visit.swift in Sources */, + 0BAE69561A7E1FD100B3609D /* SchemaTable.swift in Sources */, + 4A59BB4F36A20F30229034C6 /* VisitsTable.swift in Sources */, + 0BF42D421A7C31E300889E28 /* JoinedFaviconsHistoryTable.swift in Sources */, + 0BF42D441A7C31EE00889E28 /* FaviconsTable.swift in Sources */, + E477261B1A8A7DE500FC058B /* SQLiteReadingList.swift in Sources */, + 4A59B21913DCFA81C7CD9C91 /* GenericTable.swift in Sources */, + 0BF42D3E1A7C148F00889E28 /* Favicons.swift in Sources */, + 0BA4978D1A7B0E55004C8E17 /* FileAccessor.swift in Sources */, + 4A59BD24F6210866F59EF0F6 /* JoinedHistoryVisitsTable.swift in Sources */, + 0B3060311A8151B70085B8BC /* SQLitePasswords.swift in Sources */, + 4A59BFF7C37812C7955B9E79 /* HistoryTable.swift in Sources */, + 4A59BAEB154EA6E1B621E067 /* BrowserDB.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 282DA49C1A699E0300A406E2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 282DA4D21A69A14500A406E2 /* FileAccessor.swift in Sources */, + 0BCFBBB81A776A200087E26D /* MockFiles.swift in Sources */, + 0BF42D4B1A7C55F300889E28 /* JoinedFaviconsHistoryTable.swift in Sources */, + E4F43AC21A8CF9A200ACAC05 /* TestSQLiteReadingList.swift in Sources */, + 0BCFBBB51A7769B70087E26D /* VisitsTable.swift in Sources */, + 282DA4A81A699E0300A406E2 /* StorageTests.swift in Sources */, + 0BCFBBB41A7769A30087E26D /* JoinedHistoryVisitsTable.swift in Sources */, + 0BF42D461A7C52C800889E28 /* TestFaviconsTable.swift in Sources */, + 0BCFBBAF1A77650E0087E26D /* GenericTable.swift in Sources */, + E477261C1A8A7DE500FC058B /* SQLiteReadingList.swift in Sources */, + 282DA4C61A699F8A00A406E2 /* SwiftData.swift in Sources */, + 0B2770481A893C4700CE7692 /* BookmarksSqlite.swift in Sources */, + 0B2770471A893C2C00CE7692 /* TestBookmarks.swift in Sources */, + 0BF42D471A7C558000889E28 /* Visit.swift in Sources */, + E47726191A8A794B00FC058B /* ReadingList.swift in Sources */, + E47726211A8A87F400FC058B /* TestReadingListTable.swift in Sources */, + 282DA4C21A699EF200A406E2 /* Cursor.swift in Sources */, + 0B2770491A893C9500CE7692 /* Bookmarks.swift in Sources */, + 0BF42D481A7C55D200889E28 /* Site.swift in Sources */, + 0B2770E91A8AD85000CE7692 /* Bytes.swift in Sources */, + 4A59BA1E93D5603E198EDCB9 /* HistoryTable.swift in Sources */, + 0BAE69571A7E209200B3609D /* SchemaTable.swift in Sources */, + 4A59BF0BBF50FC218A6D1143 /* BrowserDB.swift in Sources */, + E477261F1A8A7EDA00FC058B /* ReadingListTable.swift in Sources */, + 4A59B334A243792894D6E614 /* TestHistoryTable.swift in Sources */, + 4A59BC6033BD93D1DC36E18F /* TestJoinedHistoryVisits.swift in Sources */, + 0BF42D4D1A7CC4ED00889E28 /* TestJoinedFaviconTable.swift in Sources */, + 0BF42D4A1A7C55F000889E28 /* FaviconsTable.swift in Sources */, + 4A59BF2F408CDEF8D50AF9D3 /* TestVisitsTable.swift in Sources */, + 0BAE69591A7EEF8E00B3609D /* TestTableTable.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 282DA4A31A699E0300A406E2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 282DA4941A699E0300A406E2 /* Storage */; + targetProxy = 282DA4A21A699E0300A406E2 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 282DA4A91A699E0300A406E2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.1; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/modules"; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 282DA4AA1A699E0300A406E2 /* FennecAurora */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)"; + COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/modules"; + SWIFT_OBJC_BRIDGING_HEADER = ""; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = FennecAurora; + }; + 282DA4AC1A699E0300A406E2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "/Users/rnewman/moz/git/firefox-ios/SQLite/build/Debug-iphoneos", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Client-fhgufntxvuxtwfbmkckrmnagytst/Build/Products/Debug-iphoneos", + ); + INFOPLIST_FILE = Storage/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/modules"; + }; + name = Debug; + }; + 282DA4AD1A699E0300A406E2 /* FennecAurora */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "/Users/rnewman/moz/git/firefox-ios/SQLite/build/Debug-iphoneos", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Client-fhgufntxvuxtwfbmkckrmnagytst/Build/Products/Debug-iphoneos", + ); + INFOPLIST_FILE = Storage/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/modules"; + }; + name = FennecAurora; + }; + 282DA4AF1A699E0300A406E2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = StorageTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 282DA4B01A699E0300A406E2 /* FennecAurora */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = StorageTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = FennecAurora; + }; + E4D438F51A8D3197003FCF55 /* FennecNightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)"; + COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/modules"; + SWIFT_OBJC_BRIDGING_HEADER = ""; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = FennecNightly; + }; + E4D438F61A8D3197003FCF55 /* FennecNightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "/Users/rnewman/moz/git/firefox-ios/SQLite/build/Debug-iphoneos", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Client-fhgufntxvuxtwfbmkckrmnagytst/Build/Products/Debug-iphoneos", + ); + INFOPLIST_FILE = Storage/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/modules"; + }; + name = FennecNightly; + }; + E4D438F71A8D3197003FCF55 /* FennecNightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = StorageTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = FennecNightly; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 282DA48F1A699E0300A406E2 /* Build configuration list for PBXProject "Storage" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 282DA4A91A699E0300A406E2 /* Debug */, + 282DA4AA1A699E0300A406E2 /* FennecAurora */, + E4D438F51A8D3197003FCF55 /* FennecNightly */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = FennecAurora; + }; + 282DA4AB1A699E0300A406E2 /* Build configuration list for PBXNativeTarget "Storage" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 282DA4AC1A699E0300A406E2 /* Debug */, + 282DA4AD1A699E0300A406E2 /* FennecAurora */, + E4D438F61A8D3197003FCF55 /* FennecNightly */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = FennecAurora; + }; + 282DA4AE1A699E0300A406E2 /* Build configuration list for PBXNativeTarget "StorageTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 282DA4AF1A699E0300A406E2 /* Debug */, + 282DA4B01A699E0300A406E2 /* FennecAurora */, + E4D438F71A8D3197003FCF55 /* FennecNightly */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = FennecAurora; + }; +/* End XCConfigurationList section */ + }; + rootObject = 282DA48C1A699E0300A406E2 /* Project object */; +} diff --git a/mobile/ios/Storage/SuggestedSites.swift b/mobile/ios/Storage/SuggestedSites.swift new file mode 100644 index 0000000000..b4a6f937e6 --- /dev/null +++ b/mobile/ios/Storage/SuggestedSites.swift @@ -0,0 +1,46 @@ +/* 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/. */ + +import UIKit +import Shared + +open class SuggestedSite: Site { + override open var tileURL: URL { + return URL(string: url as String) ?? URL(string: "about:blank")! + } + + let trackingId: Int + init(data: SuggestedSiteData) { + self.trackingId = data.trackingId + super.init(url: data.url, title: data.title, bookmarked: nil) + self.guid = "default" + data.title // A guid is required in the case the site might become a pinned site + } +} + +public let SuggestedSites: SuggestedSitesCursor = SuggestedSitesCursor() + +open class SuggestedSitesCursor: ArrayCursor { + fileprivate init() { + let locale = Locale.current + let sites = DefaultSuggestedSites.sites[locale.identifier] ?? + DefaultSuggestedSites.sites["default"]! as Array + let tiles = sites.map({ data -> SuggestedSite in + var site = data + if let domainMap = DefaultSuggestedSites.urlMap[data.url], let localizedURL = domainMap[locale.identifier] { + site.url = localizedURL + } + return SuggestedSite(data: site) + }) + super.init(data: tiles, status: .success, statusMessage: "Loaded") + } +} + +public struct SuggestedSiteData { + var url: String + var bgColor: String + var imageUrl: String + var faviconUrl: String + var trackingId: Int + var title: String +} diff --git a/mobile/ios/Storage/SyncQueue.swift b/mobile/ios/Storage/SyncQueue.swift new file mode 100644 index 0000000000..643432ecce --- /dev/null +++ b/mobile/ios/Storage/SyncQueue.swift @@ -0,0 +1,65 @@ +/* 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/. */ + +import Shared +import Deferred +import SwiftyJSON + +public struct SyncCommand: Equatable { + public let value: String + public var commandID: Int? + public var clientGUID: GUID? + + let version: String? + + public init(value: String) { + self.value = value + self.version = nil + self.commandID = nil + self.clientGUID = nil + } + + public init(id: Int, value: String) { + self.value = value + self.version = nil + self.commandID = id + self.clientGUID = nil + } + + public init(id: Int?, value: String, clientGUID: GUID?) { + self.value = value + self.version = nil + self.clientGUID = clientGUID + self.commandID = id + } + + /** + * Sent displayURI commands include the sender client GUID. + */ + public static func displayURIFromShareItem(_ shareItem: ShareItem, asClient sender: GUID) -> SyncCommand { + let jsonObj: [String: Any] = [ + "command": "displayURI", + "args": [shareItem.url, sender, shareItem.title ?? ""] + ] + return SyncCommand(value: JSON(object: jsonObj).stringValue()!) + } + + public func withClientGUID(_ clientGUID: String?) -> SyncCommand { + return SyncCommand(id: self.commandID, value: self.value, clientGUID: clientGUID) + } +} + +public func ==(lhs: SyncCommand, rhs: SyncCommand) -> Bool { + return lhs.value == rhs.value +} + +public protocol SyncCommands { + func deleteCommands() -> Success + func deleteCommands(_ clientGUID: GUID) -> Success + + func getCommands() -> Deferred> + + func insertCommand(_ command: SyncCommand, forClients clients: [RemoteClient]) -> Deferred> + func insertCommands(_ commands: [SyncCommand], forClients clients: [RemoteClient]) -> Deferred> +} diff --git a/mobile/ios/Storage/Syncable.swift b/mobile/ios/Storage/Syncable.swift new file mode 100644 index 0000000000..8c806f9fb6 --- /dev/null +++ b/mobile/ios/Storage/Syncable.swift @@ -0,0 +1,24 @@ +/* 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/. */ + +import Shared + +/** + * This exists to allow resets after meta/global or crypto/key changes. + * + * 'Reset' in this case means that timestamps and progress tracking are + * discarded: this storage is reconfigured such that all data will be + * reuploaded, and all data will be re-merged as necessary. + * + * This protocol is primarily consumed by `ResettableSynchronizer`, and + * is invoked when a significant server change is observed — changed keys, + * changed engine elections or syncIDs, or a node reassignment. + */ +public protocol ResettableSyncStorage { + func resetClient() -> Success +} + +public protocol AccountRemovalDelegate { + func onRemovedAccount() -> Success +} diff --git a/mobile/ios/Storage/ThirdParty/SwiftData.swift b/mobile/ios/Storage/ThirdParty/SwiftData.swift new file mode 100644 index 0000000000..ade5651fd7 --- /dev/null +++ b/mobile/ios/Storage/ThirdParty/SwiftData.swift @@ -0,0 +1,1488 @@ +/* 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 is a heavily modified version of SwiftData.swift by Ryan Fowler + * This has been enhanced to support custom files, correct binding, versioning, + * and a streaming results via Cursors. The API has also been changed to use NSError, Cursors, and + * to force callers to request a connection before executing commands. Database creation helpers, savepoint + * helpers, image support, and other features have been removed. + */ + +// SwiftData.swift +// +// Copyright (c) 2014 Ryan Fowler +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import UIKit +import Deferred +import Shared +import XCGLogger + +private let DatabaseBusyTimeout: Int32 = 3 * 1000 +private let log = Logger.syncLogger + +public class DBOperationCancelled : MaybeErrorType { + public var description: String { + return "Database operation cancelled" + } +} + +class DeferredDBOperation: Deferred, Cancellable { + fileprivate var dispatchWorkItem: DispatchWorkItem? + private var _running = false + + func cancel() { + objc_sync_enter(self) + defer { objc_sync_exit(self) } + dispatchWorkItem?.cancel() + } + + var cancelled: Bool { + objc_sync_enter(self) + defer { objc_sync_exit(self) } + return dispatchWorkItem?.isCancelled ?? false + } + + var running: Bool { + get { + objc_sync_enter(self) + defer { objc_sync_exit(self) } + return _running + } + set { + objc_sync_enter(self) + defer { objc_sync_exit(self) } + _running = newValue + } + } +} + +enum SQLiteDBConnectionCreatedResult { + case success + case failure + case needsRecovery +} + +// SQLite standard error codes when the DB file is locked, busy or the disk is +// full. These error codes indicate that any issues with writing to the database +// are temporary and we should not wipe out and re-create the database file when +// we encounter them. +enum SQLiteDBRecoverableError: Int { + case Busy = 5 + case Locked = 6 + case ReadOnly = 8 + case IOErr = 10 + case Full = 13 +} + +/** + * Handle to a SQLite database. + * Each instance holds a single connection that is shared across all queries. + */ +open class SwiftData { + let filename: String + let schema: Schema + let files: FileAccessor + + static var EnableWAL = true + static var EnableForeignKeys = true + + /// Used to keep track of the corrupted databases we've logged. + static var corruptionLogsWritten = Set() + + /// Used for testing. + static var ReuseConnections = true + + /// For thread-safe access to the shared connection. + fileprivate let sharedConnectionQueue: DispatchQueue + + /// Shared connection to this database. + fileprivate var sharedConnection: ConcreteSQLiteDBConnection? + fileprivate var key: String? + fileprivate var prevKey: String? + + /// A simple state flag to track whether we should accept new connection requests. + /// If a connection request is made while the database is closed, a + /// FailedSQLiteDBConnection will be returned. + fileprivate(set) var closed = false + + init(filename: String, key: String? = nil, prevKey: String? = nil, schema: Schema, files: FileAccessor) { + self.filename = filename + self.key = key + self.prevKey = prevKey + self.schema = schema + self.files = files + + self.sharedConnectionQueue = DispatchQueue(label: "SwiftData queue: \(filename)", attributes: []) + + // Ensure that multi-thread mode is enabled by default. + // See https://www.sqlite.org/threadsafe.html + assert(sqlite3_threadsafe() == 2) + } + + /** + * The real meat of all the execute methods. This is used internally to open and + * close a database connection and run a block of code inside it. + */ + func withConnection(_ flags: SwiftData.Flags, synchronous: Bool = false, _ callback: @escaping (_ connection: SQLiteDBConnection) throws -> T) -> Deferred> { + let deferred = DeferredDBOperation>() + + let queue = self.sharedConnectionQueue + + func doWork() { + if deferred.cancelled { + deferred.fill(Maybe(failure: DBOperationCancelled())) + return + } + + deferred.running = true + defer { + deferred.running = false + } + + if !self.closed && self.sharedConnection == nil { + self.sharedConnection = ConcreteSQLiteDBConnection(filename: self.filename, flags: SwiftData.Flags.readWriteCreate.toSQL(), key: self.key, prevKey: self.prevKey, schema: self.schema, files: self.files) + } + + guard let connection = SwiftData.ReuseConnections ? self.sharedConnection : + ConcreteSQLiteDBConnection(filename: self.filename, flags: flags.toSQL(), key: self.key, prevKey: self.prevKey, schema: self.schema, files: self.files) else { + do { + _ = try callback(FailedSQLiteDBConnection()) + + deferred.fill(Maybe(failure: NSError(domain: "mozilla", code: 0, userInfo: [NSLocalizedDescriptionKey: "Could not create a connection"]))) + } catch let err as NSError { + deferred.fill(Maybe(failure: DatabaseError(err: err))) + } + return + } + + do { + let result = try callback(connection) + deferred.fill(Maybe(success: result)) + } catch let err as NSError { + deferred.fill(Maybe(failure: DatabaseError(err: err))) + } + } + + let work = DispatchWorkItem { doWork() } + deferred.dispatchWorkItem = work + + if synchronous { + queue.sync(execute: work) + } else { + queue.async(execute: work) + } + + return deferred + } + + /** + * Helper for opening a connection, starting a transaction, and then running a block of code inside it. + * The code block can return true if the transaction should be committed. False if we should roll back. + */ + func transaction(synchronous: Bool = false, _ transactionClosure: @escaping (_ connection: SQLiteDBConnection) throws -> T) -> Deferred> { + return withConnection(SwiftData.Flags.readWriteCreate, synchronous: synchronous) { connection in + try connection.transaction(transactionClosure) + } + } + + /// Don't use this unless you know what you're doing. The deinitializer should be used to achieve refcounting semantics. + /// The shutdown is *sync*, meaning the queue will complete the current db operations before closing. + /// If an operation is queued with an open connection, it will execute before this runs. + func forceClose() { + sharedConnectionQueue.sync { + self.closed = true + self.sharedConnection = nil + } + } + + /// Reopens a database that had previously been force-closed. + /// Does nothing if this database is already open. + func reopenIfClosed() { + sharedConnectionQueue.sync { + self.closed = false + } + } + + public func cancel() { + if let db = sharedConnection?.sqliteDB, !closed { + sqlite3_interrupt(db) + } + } + + public func suspendQueue() { + sharedConnectionQueue.suspend() + } + + public func resumeQueue() { + sharedConnectionQueue.resume() + } + + public enum Flags { + case readOnly + case readWrite + case readWriteCreate + + fileprivate func toSQL() -> Int32 { + switch self { + case .readOnly: + return SQLITE_OPEN_READONLY + case .readWrite: + return SQLITE_OPEN_READWRITE + case .readWriteCreate: + return SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE + } + } + } +} + +/** + * Wrapper class for a SQLite statement. + * This class helps manage the statement lifecycle. By holding a reference to the SQL connection, we ensure + * the connection is never deinitialized while the statement is active. This class is responsible for + * finalizing the SQL statement once it goes out of scope. + */ +private class SQLiteDBStatement { + var pointer: OpaquePointer? + fileprivate let connection: ConcreteSQLiteDBConnection + + init(connection: ConcreteSQLiteDBConnection, query: String, args: [Any?]?) throws { + self.connection = connection + + let status = sqlite3_prepare_v2(connection.sqliteDB, query, -1, &pointer, nil) + if status != SQLITE_OK { + throw connection.createErr("During: SQL Prepare \(query)", status: Int(status)) + } + + if let args = args, + let bindError = bind(args) { + throw bindError + } + } + + /// Binds arguments to the statement. + fileprivate func bind(_ objects: [Any?]) -> NSError? { + let count = Int(sqlite3_bind_parameter_count(pointer)) + if count < objects.count { + return connection.createErr("During: Bind", status: 202) + } + if count > objects.count { + return connection.createErr("During: Bind", status: 201) + } + + for (index, obj) in objects.enumerated() { + var status: Int32 = SQLITE_OK + + // Doubles also pass obj as Int, so order is important here. + if obj is Double { + status = sqlite3_bind_double(pointer, Int32(index+1), obj as! Double) + } else if obj is Int { + status = sqlite3_bind_int(pointer, Int32(index+1), Int32(obj as! Int)) + } else if obj is Bool { + status = sqlite3_bind_int(pointer, Int32(index+1), (obj as! Bool) ? 1 : 0) + } else if obj is String { + typealias CFunction = @convention(c) (UnsafeMutableRawPointer?) -> Void + let transient = unsafeBitCast(-1, to: CFunction.self) + status = sqlite3_bind_text(pointer, Int32(index+1), (obj as! String).cString(using: String.Encoding.utf8)!, -1, transient) + } else if obj is Data { + status = sqlite3_bind_blob(pointer, Int32(index+1), ((obj as! Data) as NSData).bytes, -1, nil) + } else if obj is Date { + let timestamp = (obj as! Date).timeIntervalSince1970 + status = sqlite3_bind_double(pointer, Int32(index+1), timestamp) + } else if obj is UInt64 { + status = sqlite3_bind_double(pointer, Int32(index+1), Double(obj as! UInt64)) + } else if obj == nil { + status = sqlite3_bind_null(pointer, Int32(index+1)) + } + + if status != SQLITE_OK { + return connection.createErr("During: Bind", status: Int(status)) + } + } + + return nil + } + + func close() { + if nil != self.pointer { + sqlite3_finalize(self.pointer) + self.pointer = nil + } + } + + deinit { + if nil != self.pointer { + sqlite3_finalize(self.pointer) + } + } +} + +public protocol SQLiteDBConnection { + var lastInsertedRowID: Int { get } + var numberOfRowsModified: Int { get } + var version: Int { get } + + func executeChange(_ sqlStr: String) throws -> Void + func executeChange(_ sqlStr: String, withArgs args: Args?) throws -> Void + + func executeQuery(_ sqlStr: String, factory: @escaping ((SDRow) -> T)) -> Cursor + func executeQuery(_ sqlStr: String, factory: @escaping ((SDRow) -> T), withArgs args: Args?) -> Cursor + func executeQueryUnsafe(_ sqlStr: String, factory: @escaping ((SDRow) -> T), withArgs args: Args?) -> Cursor + + func transaction(_ transactionClosure: @escaping (_ connection: SQLiteDBConnection) throws -> T) throws -> T + + func interrupt() + func checkpoint() + func checkpoint(_ mode: Int32) + func vacuum() throws -> Void + func setVersion(_ version: Int) throws -> Void +} + +// Represents a failure to open. +class FailedSQLiteDBConnection: SQLiteDBConnection { + var lastInsertedRowID: Int = 0 + var numberOfRowsModified: Int = 0 + var version: Int = 0 + + fileprivate func fail(_ str: String) -> NSError { + return NSError(domain: "mozilla", code: 0, userInfo: [NSLocalizedDescriptionKey: str]) + } + + func executeChange(_ sqlStr: String, withArgs args: Args?) throws -> Void { + throw fail("Non-open connection; can't execute change.") + } + func executeChange(_ sqlStr: String) throws -> Void { + throw fail("Non-open connection; can't execute change.") + } + + func executeQuery(_ sqlStr: String, factory: @escaping ((SDRow) -> T)) -> Cursor { + return Cursor(err: fail("Non-open connection; can't execute query.")) + } + func executeQuery(_ sqlStr: String, factory: @escaping ((SDRow) -> T), withArgs args: Args?) -> Cursor { + return Cursor(err: fail("Non-open connection; can't execute query.")) + } + func executeQueryUnsafe(_ sqlStr: String, factory: @escaping ((SDRow) -> T), withArgs args: Args?) -> Cursor { + return Cursor(err: fail("Non-open connection; can't execute query.")) + } + + func transaction(_ transactionClosure: @escaping (_ connection: SQLiteDBConnection) throws -> T) throws -> T { + throw fail("Non-open connection; can't start transaction.") + } + + func interrupt() {} + func checkpoint() {} + func checkpoint(_ mode: Int32) {} + func vacuum() throws -> Void { + throw fail("Non-open connection; can't vacuum.") + } + func setVersion(_ version: Int) throws -> Void { + throw fail("Non-open connection; can't set user_version.") + } +} + +open class ConcreteSQLiteDBConnection: SQLiteDBConnection { + open var lastInsertedRowID: Int { + return Int(sqlite3_last_insert_rowid(sqliteDB)) + } + + open var numberOfRowsModified: Int { + return Int(sqlite3_changes(sqliteDB)) + } + + open var version: Int { + return pragma("user_version", factory: IntFactory) ?? 0 + } + + fileprivate var sqliteDB: OpaquePointer? + fileprivate let filename: String + fileprivate let schema: Schema + fileprivate let files: FileAccessor + + fileprivate let debug_enabled = false + + init?(filename: String, flags: Int32, key: String? = nil, prevKey: String? = nil, schema: Schema, files: FileAccessor) { + log.debug("Opening connection to \(filename).") + + self.filename = filename + self.schema = schema + self.files = files + + func doOpen() -> Bool { + if let failure = openWithFlags(flags) { + log.warning("Opening connection to \(filename) failed: \(failure).") + return false + } + + if key == nil && prevKey == nil { + do { + try self.prepareCleartext() + } catch { + return false + } + } else { + do { + try self.prepareEncrypted(flags, key: key, prevKey: prevKey) + } catch { + return false + } + } + + return true + } + + // If we cannot even open the database file, return `nil` to force SwiftData + // into using a `FailedSQLiteDBConnection` so we can retry opening again later. + if !doOpen() { + let extra = ["filename" : filename] + Sentry.shared.sendWithStacktrace(message: "Cannot open a database connection.", tag: SentryTag.swiftData, severity: .error, extra: extra) + return nil + } + + // Now that we've successfully opened a connection to the database file, call + // `prepareSchema()`. If it succeeds, our work here is done. If it returns + // `.failure`, this means there was a temporary error preventing us from initing + // the schema (e.g. SQLITE_BUSY, SQLITE_LOCK, SQLITE_FULL); so we return `nil` to + // force SwiftData into using a `FailedSQLiteDBConnection` to retry preparing the + // schema again later. However, if it returns `.needsRecovery`, this means there + // was a permanent error preparing the schema and we need to move the current + // database file to a backup location and start over with a brand new one. + switch self.prepareSchema() { + case .success: + log.debug("Database successfully created or updated.") + case .failure: + Sentry.shared.sendWithStacktrace(message: "Failed to create or update the database schema.", tag: SentryTag.swiftData, severity: .error) + return nil + case .needsRecovery: + Sentry.shared.sendWithStacktrace(message: "Database schema cannot be created or updated due to an unrecoverable error.", tag: SentryTag.swiftData, severity: .error) + + // We need to close this new connection before we can move the database file to + // its backup location. If we cannot even close the connection, something has + // gone really wrong. In that case, bail out and return `nil` to force SwiftData + // into using a `FailedSQLiteDBConnection` so we can retry again later. + if let error = self.closeCustomConnection(immediately: true) { + Sentry.shared.sendWithStacktrace(message: "Cannot close the database connection to begin recovery.", tag: SentryTag.swiftData, severity: .error, description: error.localizedDescription) + return nil + } + + // Move the current database file to its backup location. + self.moveDatabaseFileToBackupLocation() + + // If we cannot open the *new* database file (which shouldn't happen), return + // `nil` to force SwiftData into using a `FailedSQLiteDBConnection` so we can + // retry opening again later. + if !doOpen() { + log.error("Cannot re-open a database connection to the new database file to begin recovery.") + Sentry.shared.sendWithStacktrace(message: "Cannot re-open a database connection to the new database file to begin recovery.", tag: SentryTag.swiftData, severity: .error) + return nil + } + + // Notify the world that we re-created the database schema. This allows us to + // reset Sync and start over in the case of corruption. + defer { + let baseFilename = URL(fileURLWithPath: self.filename).lastPathComponent + NotificationCenter.default.post(name: NotificationDatabaseWasRecreated, object: baseFilename) + } + + // Now that we've got a brand new database file, let's call `prepareSchema()` on + // it to re-create the schema. Again, if this fails (it shouldn't), return `nil` + // to force SwiftData into using a `FailedSQLiteDBConnection` so we can retry + // again later. + if self.prepareSchema() != .success { + log.error("Cannot re-create the schema in the new database file to complete recovery.") + Sentry.shared.sendWithStacktrace(message: "Cannot re-create the schema in the new database file to complete recovery.", tag: SentryTag.swiftData, severity: .error) + return nil + } + } + } + + deinit { + log.debug("deinit: closing connection on thread \(Thread.current).") + self.closeCustomConnection() + } + + fileprivate func setKey(_ key: String?) -> NSError? { + sqlite3_key(sqliteDB, key ?? "", Int32((key ?? "").characters.count)) + let cursor = executeQuery("SELECT count(*) FROM sqlite_master;", factory: IntFactory, withArgs: nil as Args?) + if cursor.status != .success { + return NSError(domain: "mozilla", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid key"]) + } + return nil + } + + fileprivate func reKey(_ oldKey: String?, newKey: String?) -> NSError? { + sqlite3_key(sqliteDB, oldKey ?? "", Int32((oldKey ?? "").characters.count)) + sqlite3_rekey(sqliteDB, newKey ?? "", Int32((newKey ?? "").characters.count)) + // Check that the new key actually works + sqlite3_key(sqliteDB, newKey ?? "", Int32((newKey ?? "").characters.count)) + let cursor = executeQuery("SELECT count(*) FROM sqlite_master;", factory: IntFactory, withArgs: nil as Args?) + if cursor.status != .success { + return NSError(domain: "mozilla", code: 0, userInfo: [NSLocalizedDescriptionKey: "Rekey failed"]) + } + + return nil + } + + public func setVersion(_ version: Int) throws -> Void { + try executeChange("PRAGMA user_version = \(version)") + } + + public func interrupt() { + log.debug("Interrupt") + sqlite3_interrupt(sqliteDB) + } + + fileprivate func pragma(_ pragma: String, expected: T?, factory: @escaping (SDRow) -> T, message: String) throws { + let cursorResult = self.pragma(pragma, factory: factory) + if cursorResult != expected { + log.error("\(message): \(cursorResult.debugDescription), \(expected.debugDescription)") + throw NSError(domain: "mozilla", code: 0, userInfo: [NSLocalizedDescriptionKey: "PRAGMA didn't return expected output: \(message)."]) + } + } + + fileprivate func pragma(_ pragma: String, factory: @escaping (SDRow) -> T) -> T? { + let cursor = executeQueryUnsafe("PRAGMA \(pragma)", factory: factory, withArgs: [] as Args) + defer { cursor.close() } + return cursor[0] + } + + fileprivate func prepareShared() { + if SwiftData.EnableForeignKeys { + let _ = pragma("foreign_keys=ON", factory: IntFactory) + } + + // Retry queries before returning locked errors. + sqlite3_busy_timeout(self.sqliteDB, DatabaseBusyTimeout) + } + + fileprivate func prepareEncrypted(_ flags: Int32, key: String?, prevKey: String? = nil) throws { + // Setting the key needs to be the first thing done with the database. + if let _ = setKey(key) { + if let err = closeCustomConnection(immediately: true) { + log.error("Couldn't close connection: \(err). Failing to open.") + throw err + } + if let err = openWithFlags(flags) { + Sentry.shared.sendWithStacktrace(message: "Error opening database with flags.", tag: SentryTag.swiftData, severity: .error, description: "\(err.code), \(err)") + throw err + } + if let err = reKey(prevKey, newKey: key) { + // Note: Don't log the error here as it may contain sensitive data. + Sentry.shared.sendWithStacktrace(message: "Unable to encrypt database.", tag: SentryTag.swiftData, severity: .error) + throw err + } + } + + if SwiftData.EnableWAL { + log.info("Enabling WAL mode.") + try pragma("journal_mode=WAL", expected: "wal", + factory: StringFactory, message: "WAL journal mode set") + } + + self.prepareShared() + } + + fileprivate func prepareCleartext() throws { + // If we just created the DB -- i.e., no tables have been created yet -- then + // we can set the page size right now and save a vacuum. + // + // For where these values come from, see Bug 1213623. + // + // Note that sqlcipher uses cipher_page_size instead, but we don't set that + // because it needs to be set from day one. + + let desiredPageSize = 32 * 1024 + let _ = pragma("page_size=\(desiredPageSize)", factory: IntFactory) + + let currentPageSize = pragma("page_size", factory: IntFactory) + + // This has to be done without WAL, so we always hop into rollback/delete journal mode. + if currentPageSize != desiredPageSize { + try pragma("journal_mode=DELETE", expected: "delete", + factory: StringFactory, message: "delete journal mode set") + + try pragma("page_size=\(desiredPageSize)", expected: nil, + factory: IntFactory, message: "Page size set") + + log.info("Vacuuming to alter database page size from \(currentPageSize ?? 0) to \(desiredPageSize).") + + do { + try vacuum() + log.debug("Vacuuming succeeded.") + } catch let err as NSError { + log.error("Vacuuming failed: \(err.localizedDescription).") + } + } + + if SwiftData.EnableWAL { + log.info("Enabling WAL mode.") + + let desiredPagesPerJournal = 16 + let desiredCheckpointSize = desiredPagesPerJournal * desiredPageSize + let desiredJournalSizeLimit = 3 * desiredCheckpointSize + + /* + * With whole-module-optimization enabled in Xcode 7.2 and 7.2.1, the + * compiler seems to eagerly discard these queries if they're simply + * inlined, causing a crash in `pragma`. + * + * Hackily hold on to them. + */ + let journalModeQuery = "journal_mode=WAL" + let autoCheckpointQuery = "wal_autocheckpoint=\(desiredPagesPerJournal)" + let journalSizeQuery = "journal_size_limit=\(desiredJournalSizeLimit)" + + try withExtendedLifetime(journalModeQuery, { + try pragma(journalModeQuery, expected: "wal", + factory: StringFactory, message: "WAL journal mode set") + }) + try withExtendedLifetime(autoCheckpointQuery, { + try pragma(autoCheckpointQuery, expected: desiredPagesPerJournal, + factory: IntFactory, message: "WAL autocheckpoint set") + }) + try withExtendedLifetime(journalSizeQuery, { + try pragma(journalSizeQuery, expected: desiredJournalSizeLimit, + factory: IntFactory, message: "WAL journal size limit set") + }) + } + + self.prepareShared() + } + + // Creates the database schema in a new database. + fileprivate func createSchema() -> Bool { + log.debug("Trying to create schema \(self.schema.name) at version \(self.schema.version)") + if !schema.create(self) { + // If schema couldn't be created, we'll bail without setting the `PRAGMA user_version`. + log.debug("Creation failed.") + return false + } + + do { + try setVersion(schema.version) + } catch let error as NSError { + log.error("Unable to set the schema version; \(error.localizedDescription)") + } + + return true + } + + // Updates the database schema in an existing database. + fileprivate func updateSchema() -> Bool { + log.debug("Trying to update schema \(self.schema.name) from version \(self.version) to \(self.schema.version)") + if !schema.update(self, from: self.version) { + // If schema couldn't be updated, we'll bail without setting the `PRAGMA user_version`. + log.debug("Updating failed.") + return false + } + + do { + try setVersion(schema.version) + } catch let error as NSError { + log.error("Unable to set the schema version; \(error.localizedDescription)") + } + + return true + } + + // Drops the database schema from an existing database. + fileprivate func dropSchema() -> Bool { + log.debug("Trying to drop schema \(self.schema.name)") + if !self.schema.drop(self) { + // If schema couldn't be dropped, we'll bail without setting the `PRAGMA user_version`. + log.debug("Dropping failed.") + return false + } + + do { + try setVersion(0) + } catch let error as NSError { + log.error("Unable to reset the schema version; \(error.localizedDescription)") + } + + return true + } + + // Checks if the database schema needs created or updated and acts accordingly. + // Calls to this function will be serialized to prevent race conditions when + // creating or updating the schema. + fileprivate func prepareSchema() -> SQLiteDBConnectionCreatedResult { + Sentry.shared.addAttributes(["dbSchema.\(schema.name).version": schema.version]) + + // Get the current schema version for the database. + let currentVersion = self.version + + // If the current schema version for the database matches the specified + // `Schema` version, no further action is necessary and we can bail out. + // NOTE: This assumes that we always use *ONE* `Schema` per database file + // since SQLite can only track a single value in `PRAGMA user_version`. + if currentVersion == schema.version { + log.debug("Schema \(self.schema.name) already exists at version \(self.schema.version). Skipping additional schema preparation.") + return .success + } + + // Set an attribute for Sentry to include with any future error/crash + // logs to indicate what schema version we're coming from and going to. + Sentry.shared.addAttributes(["dbUpgrade.\(self.schema.name).from": currentVersion, "dbUpgrade.\(self.schema.name).to": self.schema.version]) + + // This should not ever happen since the schema version should always be + // increasing whenever a structural change is made in an app update. + guard currentVersion <= schema.version else { + let errorString = "\(self.schema.name) cannot be downgraded from version \(currentVersion) to \(self.schema.version)." + Sentry.shared.sendWithStacktrace(message: "Schema cannot be downgraded.", tag: SentryTag.swiftData, severity: .error, description: errorString) + return .failure + } + + log.debug("Schema \(self.schema.name) needs created or updated from version \(currentVersion) to \(self.schema.version).") + + var success = true + + do { + success = try transaction { connection -> Bool in + log.debug("Create or update \(self.schema.name) version \(self.schema.version) on \(Thread.current.description).") + + // If `PRAGMA user_version` is zero, check if we can safely create the + // database schema from scratch. + if connection.version == 0 { + // Query for the existence of the `tableList` table to determine if we are + // migrating from an older DB version. + let sqliteMasterCursor = connection.executeQueryUnsafe("SELECT COUNT(*) AS number FROM sqlite_master WHERE type = 'table' AND name = 'tableList'", factory: IntFactory, withArgs: [] as Args) + + let tableListTableExists = sqliteMasterCursor[0] == 1 + sqliteMasterCursor.close() + + // If the `tableList` table doesn't exist, we can simply invoke + // `createSchema()` to create a brand new DB from scratch. + if !tableListTableExists { + log.debug("Schema \(self.schema.name) doesn't exist. Creating.") + success = self.createSchema() + return success + } + } + + Sentry.shared.send(message: "Attempting to update schema", tag: SentryTag.swiftData, severity: .info, description: "\(currentVersion) to \(self.schema.version).") + + // If we can't create a brand new schema from scratch, we must + // call `updateSchema()` to go through the update process. + if self.updateSchema() { + log.debug("Updated schema \(self.schema.name).") + success = true + return success + } + + // If we failed to update the schema, we'll drop everything from the DB + // and create everything again from scratch. Assuming our schema upgrade + // code is correct, this *shouldn't* happen. If it does, log it to Sentry. + Sentry.shared.sendWithStacktrace(message: "Update failed for schema. Dropping and re-creating.", tag: SentryTag.swiftData, severity: .error, description: "\(self.schema.name) from version \(currentVersion) to \(self.schema.version)") + + // If we can't even drop the schema here, something has gone really wrong, so + // return `false` which should force us into recovery. + if !self.dropSchema() { + Sentry.shared.sendWithStacktrace(message: "Unable to drop schema.", tag: SentryTag.swiftData, severity: .error, description: "\(self.schema.name) from version \(currentVersion).") + success = false + return success + } + + // Try to re-create the schema. If this fails, we are out of options and we'll + // return `false` which should force us into recovery. + success = self.createSchema() + return success + } + } catch let error as NSError { + // If we got an error trying to get a transaction, then we either bail out early and return + // `.failure` if we think we can retry later or return `.needsRecovery` if the error is not + // recoverable. + Sentry.shared.sendWithStacktrace(message: "Unable to get a transaction", tag: SentryTag.swiftData, severity: .error, description: "\(error.localizedDescription)") + + // Check if the error we got is recoverable (e.g. SQLITE_BUSY, SQLITE_LOCK, SQLITE_FULL). + // If so, just return `.failure` so we can retry preparing the schema again later. + if let _ = SQLiteDBRecoverableError(rawValue: error.code) { + return .failure + } + + // Otherwise, this is a non-recoverable error and we return `.needsRecovery` so the database + // file can be backed up and a new one will be created. + return .needsRecovery + } + + // If any of our operations inside the transaction failed, this also means we need to go through + // the recovery process to re-create the database from scratch. + if !success { + return .needsRecovery + } + + // No error means we're all good! \o/ + return .success + } + + fileprivate func moveDatabaseFileToBackupLocation() { + let baseFilename = URL(fileURLWithPath: filename).lastPathComponent + + // Attempt to make a backup as long as the database file still exists. + if files.exists(baseFilename) { + Sentry.shared.sendWithStacktrace(message: "Couldn't create or update schema. Attempted to move db to another location.", tag: SentryTag.swiftData, severity: .warning, description: "Attempting to move '\(baseFilename)' for schema '\(self.schema.name)'") + + // Note that a backup file might already exist! We append a counter to avoid this. + var bakCounter = 0 + var bak: String + repeat { + bakCounter += 1 + bak = "\(baseFilename).bak.\(bakCounter)" + } while files.exists(bak) + + do { + try files.move(baseFilename, toRelativePath: bak) + + let shm = baseFilename + "-shm" + let wal = baseFilename + "-wal" + log.debug("Moving \(shm) and \(wal)…") + if files.exists(shm) { + log.debug("\(shm) exists.") + try files.move(shm, toRelativePath: bak + "-shm") + } + if files.exists(wal) { + log.debug("\(wal) exists.") + try files.move(wal, toRelativePath: bak + "-wal") + } + + log.debug("Finished moving database \(baseFilename) successfully.") + } catch let error as NSError { + Sentry.shared.sendWithStacktrace(message: "Unable to move db to another location", tag: SentryTag.swiftData, severity: .error, description: "DB file '\(baseFilename)'. \(error.localizedDescription)") + } + } else { + // No backup was attempted since the database file did not exist. + Sentry.shared.sendWithStacktrace(message: "The database file has been deleted while previously in use.", tag: SentryTag.swiftData, description: "DB file '\(baseFilename)'") + } + } + + public func checkpoint() { + self.checkpoint(SQLITE_CHECKPOINT_FULL) + } + + /** + * Blindly attempts a WAL checkpoint on all attached databases. + */ + public func checkpoint(_ mode: Int32) { + guard sqliteDB != nil else { + log.warning("Trying to checkpoint a nil DB!") + return + } + + log.debug("Running WAL checkpoint on \(self.filename) on thread \(Thread.current).") + sqlite3_wal_checkpoint_v2(sqliteDB, nil, mode, nil, nil) + log.debug("WAL checkpoint done on \(self.filename).") + } + + public func vacuum() throws -> Void { + try executeChange("VACUUM") + } + + /// Creates an error from a sqlite status. Will print to the console if debug_enabled is set. + /// Do not call this unless you're going to return this error. + fileprivate func createErr(_ description: String, status: Int) -> NSError { + var msg = SDError.errorMessageFromCode(status) + + if debug_enabled { + log.debug("SwiftData Error -> \(description)") + log.debug(" -> Code: \(status) - \(msg)") + } + + if let errMsg = String(validatingUTF8: sqlite3_errmsg(sqliteDB)) { + msg += " " + errMsg + if debug_enabled { + log.debug(" -> Details: \(errMsg)") + } + } + + return NSError(domain: "org.mozilla", code: status, userInfo: [NSLocalizedDescriptionKey: msg]) + } + + /// Open the connection. This is called when the db is created. You should not call it yourself. + fileprivate func openWithFlags(_ flags: Int32) -> NSError? { + let status = sqlite3_open_v2(filename.cString(using: String.Encoding.utf8)!, &sqliteDB, flags, nil) + if status != SQLITE_OK { + return createErr("During: Opening Database with Flags", status: Int(status)) + } + return nil + } + + /// Closes a connection. This is called via deinit. Do not call this yourself. + @discardableResult fileprivate func closeCustomConnection(immediately: Bool = false) -> NSError? { + log.debug("Closing custom connection for \(self.filename) on \(Thread.current).") + // TODO: add a lock here? + let db = self.sqliteDB + self.sqliteDB = nil + + // Don't bother trying to call sqlite3_close multiple times. + guard db != nil else { + log.warning("Connection was nil.") + return nil + } + + var status = sqlite3_close(db) + + if status != SQLITE_OK { + Sentry.shared.sendWithStacktrace(message: "Got error status while attempting to close.", tag: SentryTag.swiftData, severity: .error, description: "SQLite status: \(status)") + + if immediately { + return createErr("During: closing database with flags", status: Int(status)) + } + + // Note that if we use sqlite3_close_v2, this will still return SQLITE_OK even if + // there are outstanding prepared statements + status = sqlite3_close_v2(db) + + if status != SQLITE_OK { + + // Based on the above comment regarding sqlite3_close_v2, this shouldn't happen. + Sentry.shared.sendWithStacktrace(message: "Got error status while attempting to close_v2.", tag: SentryTag.swiftData, severity: .error, description: "SQLite status: \(status)") + return createErr("During: closing database with flags", status: Int(status)) + } + } + + log.debug("Closed \(self.filename).") + return nil + } + + open func executeChange(_ sqlStr: String) throws -> Void { + try executeChange(sqlStr, withArgs: nil) + } + + /// Executes a change on the database. + open func executeChange(_ sqlStr: String, withArgs args: Args?) throws -> Void { + var error: NSError? + let statement: SQLiteDBStatement? + do { + statement = try SQLiteDBStatement(connection: self, query: sqlStr, args: args) + } catch let error1 as NSError { + error = error1 + statement = nil + } + + // Close, not reset -- this isn't going to be reused. + defer { statement?.close() } + + if let error = error { + // Special case: Write additional info to the database log in the case of a database corruption. + if error.code == Int(SQLITE_CORRUPT) { + writeCorruptionInfoForDBNamed(filename, toLogger: Logger.corruptLogger) + Sentry.shared.sendWithStacktrace(message: "SQLITE_CORRUPT", tag: SentryTag.swiftData, severity: .error, description: "DB file '\(filename)'. \(error.localizedDescription)") + } + + let message = "Error code: \(error.code), \(error) for SQL \(String(sqlStr.characters.prefix(500)))." + Sentry.shared.sendWithStacktrace(message: "SQL error", tag: SentryTag.swiftData, severity: .error, description: message) + + throw error + } + + let status = sqlite3_step(statement!.pointer) + + if status != SQLITE_DONE && status != SQLITE_OK { + throw createErr("During: SQL Step \(sqlStr)", status: Int(status)) + } + } + + public func executeQuery(_ sqlStr: String, factory: @escaping ((SDRow) -> T)) -> Cursor { + return self.executeQuery(sqlStr, factory: factory, withArgs: nil) + } + + /// Queries the database. + /// Returns a cursor pre-filled with the complete result set. + public func executeQuery(_ sqlStr: String, factory: @escaping ((SDRow) -> T), withArgs args: Args?) -> Cursor { + var error: NSError? + let statement: SQLiteDBStatement? + do { + statement = try SQLiteDBStatement(connection: self, query: sqlStr, args: args) + } catch let error1 as NSError { + error = error1 + statement = nil + } + + // Close, not reset -- this isn't going to be reused, and the FilledSQLiteCursor + // consumes everything. + defer { statement?.close() } + + if let error = error { + // Special case: Write additional info to the database log in the case of a database corruption. + if error.code == Int(SQLITE_CORRUPT) { + writeCorruptionInfoForDBNamed(filename, toLogger: Logger.corruptLogger) + Sentry.shared.sendWithStacktrace(message: "SQLITE_CORRUPT", tag: SentryTag.swiftData, severity: .error, description: "DB file '\(filename)'. \(error.localizedDescription)") + } + Sentry.shared.sendWithStacktrace(message: "SQL error", tag: SentryTag.swiftData, severity: .error, description: "Error code: \(error.code), \(error) for SQL \(String(sqlStr.characters.prefix(500))).") + + return Cursor(err: error) + } + + return FilledSQLiteCursor(statement: statement!, factory: factory) + } + + func writeCorruptionInfoForDBNamed(_ dbFilename: String, toLogger logger: XCGLogger) { + DispatchQueue.global(qos: DispatchQoS.default.qosClass).sync { + guard !SwiftData.corruptionLogsWritten.contains(dbFilename) else { return } + + logger.error("Corrupt DB detected! DB filename: \(dbFilename)") + + let dbFileSize = ("file://\(dbFilename)".asURL)?.allocatedFileSize() ?? 0 + logger.error("DB file size: \(dbFileSize) bytes") + + logger.error("Integrity check:") + + let args: [Any?]? = nil + let messages = self.executeQueryUnsafe("PRAGMA integrity_check", factory: StringFactory, withArgs: args) + defer { messages.close() } + + if messages.status == CursorStatus.success { + for message in messages { + logger.error(message) + } + logger.error("----") + } else { + logger.error("Couldn't run integrity check: \(messages.statusMessage).") + } + + // Write call stack. + logger.error("Call stack: ") + for message in Thread.callStackSymbols { + logger.error(" >> \(message)") + } + logger.error("----") + + // Write open file handles. + let openDescriptors = FSUtils.openFileDescriptors() + logger.error("Open file descriptors: ") + for (k, v) in openDescriptors { + logger.error(" \(k): \(v)") + } + logger.error("----") + + SwiftData.corruptionLogsWritten.insert(dbFilename) + } + } + + /** + * Queries the database. + * Returns a live cursor that holds the query statement and database connection. + * Instances of this class *must not* leak outside of the connection queue! + */ + public func executeQueryUnsafe(_ sqlStr: String, factory: @escaping ((SDRow) -> T), withArgs args: Args?) -> Cursor { + var error: NSError? + let statement: SQLiteDBStatement? + do { + statement = try SQLiteDBStatement(connection: self, query: sqlStr, args: args) + } catch let error1 as NSError { + error = error1 + statement = nil + } + if let error = error { + return Cursor(err: error) + } + + return LiveSQLiteCursor(statement: statement!, factory: factory) + } + + public func transaction(_ transactionClosure: @escaping (_ connection: SQLiteDBConnection) throws -> T) throws -> T { + do { + try executeChange("BEGIN EXCLUSIVE") + } catch let err as NSError { + Sentry.shared.sendWithStacktrace(message: "BEGIN EXCLUSIVE failed.", tag: SentryTag.swiftData, severity: .error, description: "\(err.code), \(err)") + throw err + } + + var result: T + + do { + result = try transactionClosure(self) + } catch let err as NSError { + log.error("Op in transaction threw an error. Rolling back.") + Sentry.shared.sendWithStacktrace(message: "Op in transaction threw an error. Rolling back.", tag: SentryTag.swiftData, severity: .error) + + do { + try executeChange("ROLLBACK") + } catch let err as NSError { + Sentry.shared.sendWithStacktrace(message: "ROLLBACK after errored op in transaction failed", tag: SentryTag.swiftData, severity: .error, description: "\(err.code), \(err)") + throw err + } + + throw err + } + + log.verbose("Op in transaction succeeded. Committing.") + + do { + try executeChange("COMMIT") + } catch let err as NSError { + Sentry.shared.sendWithStacktrace(message: "COMMIT failed. Rolling back.", tag: SentryTag.swiftData, severity: .error, description: "\(err.code), \(err)") + + do { + try executeChange("ROLLBACK") + } catch let err as NSError { + Sentry.shared.sendWithStacktrace(message: "ROLLBACK after failed COMMIT failed.", tag: SentryTag.swiftData, severity: .error, description: "\(err.code), \(err)") + throw err + } + + throw err + } + + return result + } +} + +/// Helper for queries that return a single integer result. +func IntFactory(_ row: SDRow) -> Int { + return row[0] as! Int +} + +/// Helper for queries that return a single String result. +func StringFactory(_ row: SDRow) -> String { + return row[0] as! String +} + +/// Wrapper around a statement for getting data from a row. This provides accessors for subscript indexing +/// and a generator for iterating over columns. +open class SDRow: Sequence { + // The sqlite statement this row came from. + fileprivate let statement: SQLiteDBStatement + + // The columns of this database. The indices of these are assumed to match the indices + // of the statement. + fileprivate let columnNames: [String] + + fileprivate init(statement: SQLiteDBStatement, columns: [String]) { + self.statement = statement + self.columnNames = columns + } + + // Return the value at this index in the row + fileprivate func getValue(_ index: Int) -> Any? { + let i = Int32(index) + + let type = sqlite3_column_type(statement.pointer, i) + var ret: Any? = nil + + switch type { + case SQLITE_NULL: + return nil + case SQLITE_INTEGER: + //Everyone expects this to be an Int. On Ints larger than 2^31 this will lose information. + ret = Int(truncatingBitPattern: sqlite3_column_int64(statement.pointer, i)) + case SQLITE_TEXT: + if let text = sqlite3_column_text(statement.pointer, i) { + return String(cString: text) + } + case SQLITE_BLOB: + if let blob = sqlite3_column_blob(statement.pointer, i) { + let size = sqlite3_column_bytes(statement.pointer, i) + ret = Data(bytes: blob, count: Int(size)) + } + case SQLITE_FLOAT: + ret = Double(sqlite3_column_double(statement.pointer, i)) + default: + log.warning("SwiftData Warning -> Column: \(index) is of an unrecognized type, returning nil") + } + + return ret + } + + // Accessor getting column 'key' in the row + subscript(key: Int) -> Any? { + return getValue(key) + } + + // Accessor getting a named column in the row. This (currently) depends on + // the columns array passed into this Row to find the correct index. + subscript(key: String) -> Any? { + get { + if let index = columnNames.index(of: key) { + return getValue(index) + } + return nil + } + } + + // Allow iterating through the row. + public func makeIterator() -> AnyIterator { + let nextIndex = 0 + return AnyIterator() { + if nextIndex < self.columnNames.count { + return self.getValue(nextIndex) + } + return nil + } + } +} + +/// Helper for pretty printing SQL (and other custom) error codes. +private struct SDError { + fileprivate static func errorMessageFromCode(_ errorCode: Int) -> String { + switch errorCode { + case -1: + return "No error" + // SQLite error codes and descriptions as per: http://www.sqlite.org/c3ref/c_abort.html + case 0: + return "Successful result" + case 1: + return "SQL error or missing database" + case 2: + return "Internal logic error in SQLite" + case 3: + return "Access permission denied" + case 4: + return "Callback routine requested an abort" + case 5: + return "The database file is busy" + case 6: + return "A table in the database is locked" + case 7: + return "A malloc() failed" + case 8: + return "Attempt to write a readonly database" + case 9: + return "Operation terminated by sqlite3_interrupt()" + case 10: + return "Some kind of disk I/O error occurred" + case 11: + return "The database disk image is malformed" + case 12: + return "Unknown opcode in sqlite3_file_control()" + case 13: + return "Insertion failed because database is full" + case 14: + return "Unable to open the database file" + case 15: + return "Database lock protocol error" + case 16: + return "Database is empty" + case 17: + return "The database schema changed" + case 18: + return "String or BLOB exceeds size limit" + case 19: + return "Abort due to constraint violation" + case 20: + return "Data type mismatch" + case 21: + return "Library used incorrectly" + case 22: + return "Uses OS features not supported on host" + case 23: + return "Authorization denied" + case 24: + return "Auxiliary database format error" + case 25: + return "2nd parameter to sqlite3_bind out of range" + case 26: + return "File opened that is not a database file" + case 27: + return "Notifications from sqlite3_log()" + case 28: + return "Warnings from sqlite3_log()" + case 100: + return "sqlite3_step() has another row ready" + case 101: + return "sqlite3_step() has finished executing" + + // Custom SwiftData errors + // Binding errors + case 201: + return "Not enough objects to bind provided" + case 202: + return "Too many objects to bind provided" + + // Custom connection errors + case 301: + return "A custom connection is already open" + case 302: + return "Cannot open a custom connection inside a transaction" + case 303: + return "Cannot open a custom connection inside a savepoint" + case 304: + return "A custom connection is not currently open" + case 305: + return "Cannot close a custom connection inside a transaction" + case 306: + return "Cannot close a custom connection inside a savepoint" + + // Index and table errors + case 401: + return "At least one column name must be provided" + case 402: + return "Error extracting index names from sqlite_master" + case 403: + return "Error extracting table names from sqlite_master" + + // Transaction and savepoint errors + case 501: + return "Cannot begin a transaction within a savepoint" + case 502: + return "Cannot begin a transaction within another transaction" + + // Unknown error + default: + return "Unknown error" + } + } +} + +/// Provides access to the result set returned by a database query. +/// The entire result set is cached, so this does not retain a reference +/// to the statement or the database connection. +private class FilledSQLiteCursor: ArrayCursor { + fileprivate init(statement: SQLiteDBStatement, factory: (SDRow) -> T) { + let (data, status, statusMessage) = FilledSQLiteCursor.getValues(statement, factory: factory) + super.init(data: data, status: status, statusMessage: statusMessage) + } + + /// Return an array with the set of results and release the statement. + fileprivate class func getValues(_ statement: SQLiteDBStatement, factory: (SDRow) -> T) -> ([T], CursorStatus, String) { + var rows = [T]() + var status = CursorStatus.success + var statusMessage = "Success" + var count = 0 + + var columns = [String]() + let columnCount = sqlite3_column_count(statement.pointer) + for i in 0..: Cursor { + fileprivate var statement: SQLiteDBStatement! + + // Function for generating objects of type T from a row. + fileprivate let factory: (SDRow) -> T + + // Status of the previous fetch request. + fileprivate var sqlStatus: Int32 = 0 + + // Number of rows in the database + // XXX - When Cursor becomes an interface, this should be a normal property, but right now + // we can't override the Cursor getter for count with a stored property. + fileprivate var _count: Int = 0 + override var count: Int { + get { + if status != .success { + return 0 + } + return _count + } + } + + fileprivate var position: Int = -1 { + didSet { + // If we're already there, shortcut out. + if oldValue == position { + return + } + + var stepStart = oldValue + + // If we're currently somewhere in the list after this position + // we'll have to jump back to the start. + if position < oldValue { + sqlite3_reset(self.statement.pointer) + stepStart = -1 + } + + // Now step up through the list to the requested position + for _ in stepStart.. T) { + self.factory = factory + self.statement = statement + + // The only way I know to get a count. Walk through the entire statement to see how many rows there are. + var count = 0 + self.sqlStatus = sqlite3_step(statement.pointer) + while self.sqlStatus != SQLITE_DONE { + count += 1 + self.sqlStatus = sqlite3_step(statement.pointer) + } + + sqlite3_reset(statement.pointer) + self._count = count + + super.init(status: .success, msg: "success") + } + + // Helper for finding all the column names in this statement. + fileprivate lazy var columns: [String] = { + // This untangles all of the columns and values for this row when its created + let columnCount = sqlite3_column_count(self.statement.pointer) + var columns = [String]() + for i: Int32 in 0 ..< columnCount { + let columnName = String(cString: sqlite3_column_name(self.statement.pointer, i)) + columns.append(columnName) + } + return columns + }() + + override subscript(index: Int) -> T? { + get { + if status != .success { + return nil + } + + self.position = index + if self.sqlStatus != SQLITE_ROW { + return nil + } + + let row = SDRow(statement: statement, columns: self.columns) + return self.factory(row) + } + } + + override func close() { + statement = nil + super.close() + } +} diff --git a/mobile/ios/Storage/Visit.swift b/mobile/ios/Storage/Visit.swift new file mode 100644 index 0000000000..7eb31357e1 --- /dev/null +++ b/mobile/ios/Storage/Visit.swift @@ -0,0 +1,121 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON + +// These are taken from the Places docs +// http://mxr.mozilla.org/mozilla-central/source/toolkit/components/places/nsINavHistoryService.idl#1187 +@objc public enum VisitType: Int { + case unknown = 0 + + /** + * This transition type means the user followed a link and got a new toplevel + * window. + */ + case link = 1 + + /** + * This transition type means that the user typed the page's URL in the + * URL bar or selected it from URL bar autocomplete results, clicked on + * it from a history query (from the History sidebar, History menu, + * or history query in the personal toolbar or Places organizer). + */ + case typed = 2 + + case bookmark = 3 + case embed = 4 + case permanentRedirect = 5 + case temporaryRedirect = 6 + case download = 7 + case framedLink = 8 +} + +// WKWebView has these: +/* +WKNavigationTypeLinkActivated, +WKNavigationTypeFormSubmitted, +WKNavigationTypeBackForward, +WKNavigationTypeReload, +WKNavigationTypeFormResubmitted, +WKNavigationTypeOther = -1, +*/ + +/** + * SiteVisit is a sop to the existing API, which expects to be able to go + * backwards from a visit to a site, and preserve the ID of the database row. + * Visit is the model of what lives on the wire: just a date and a type. + * Ultimately we'll end up with something similar to ClientAndTabs: the tabs + * don't need to know about the client, and visits don't need to know about + * the site, because they're bound together. + * + * (Furthermore, we probably shouldn't ever need something like SiteVisit + * to reach the UI: we care about "last visited", "visit count", or just + * "places ordered by frecency" — we don't care about lists of visits.) + */ + +open class Visit: Hashable { + open let date: MicrosecondTimestamp + open let type: VisitType + + open var hashValue: Int { + return date.hashValue ^ type.hashValue + } + + public init(date: MicrosecondTimestamp, type: VisitType = .unknown) { + self.date = date + self.type = type + } + + open class func fromJSON(_ json: [String: Any]) -> Visit? { + if let type = json["type"] as? Int, + let typeEnum = VisitType(rawValue: type), + let date = json["date"] as? Int64, date >= 0 { + return Visit(date: MicrosecondTimestamp(date), type: typeEnum) + } + return nil + } + + open func toJSON() -> [String: Any] { + let d = NSNumber(value: self.date) + let o: [String: Any] = ["type": self.type.rawValue, "date": d] + return o + } +} + +public func ==(lhs: Visit, rhs: Visit) -> Bool { + return lhs.date == rhs.date && + lhs.type == rhs.type +} + +open class SiteVisit: Visit { + var id: Int? + open let site: Site + + open override var hashValue: Int { + return date.hashValue ^ type.hashValue ^ (id?.hashValue ?? 0) ^ (site.id ?? 0) + } + + public init(site: Site, date: MicrosecondTimestamp, type: VisitType = .unknown) { + self.site = site + super.init(date: date, type: type) + } +} + +public func ==(lhs: SiteVisit, rhs: SiteVisit) -> Bool { + if let lhsID = lhs.id, let rhsID = rhs.id { + if lhsID != rhsID { + return false + } + } else { + if lhs.id != nil || rhs.id != nil { + return false + } + } + + // TODO: compare Site. + return lhs.date == rhs.date && + lhs.type == rhs.type +} diff --git a/mobile/ios/StoragePerfTests/Info.plist b/mobile/ios/StoragePerfTests/Info.plist new file mode 100644 index 0000000000..6366f45b20 --- /dev/null +++ b/mobile/ios/StoragePerfTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleVersion + 1 + + diff --git a/mobile/ios/StoragePerfTests/StoragePerfTests.swift b/mobile/ios/StoragePerfTests/StoragePerfTests.swift new file mode 100644 index 0000000000..121611a61c --- /dev/null +++ b/mobile/ios/StoragePerfTests/StoragePerfTests.swift @@ -0,0 +1,107 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage +import Deferred +import XCTest + +class MockFiles: FileAccessor { + init() { + let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] + super.init(rootPath: (docPath as NSString).appendingPathComponent("testing")) + } +} + +// Start everything three months ago. +let threeMonthsInMillis: UInt64 = 3 * 30 * 24 * 60 * 60 * 1000 +let threeMonthsInMicros: UInt64 = UInt64(threeMonthsInMillis) * UInt64(1000) + +let baseInstantInMillis = Date.now() - threeMonthsInMillis +let baseInstantInMicros = Date.nowMicroseconds() - threeMonthsInMicros + +func advanceMicrosecondTimestamp(_ timestamp: MicrosecondTimestamp, by: Int) -> MicrosecondTimestamp { + return timestamp + UInt64(by) +} + +extension Site { + func asPlace() -> Place { + return Place(guid: self.guid!, url: self.url, title: self.title) + } +} + +class TestSQLiteHistoryFrecencyPerf: XCTestCase { + func testFrecencyPerf() { + let files = MockFiles() + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + let count = 500 + + history.clearHistory().succeeded() + populateHistoryForFrecencyCalculations(history, siteCount: count) + + self.measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true) { + for _ in 0...5 { + history.getFrecentHistory().getSites(whereURLContains: nil, historyLimit: 10, bookmarksLimit: 0).succeeded() + } + self.stopMeasuring() + } + } +} + +class TestSQLiteHistoryTopSitesCachePref: XCTestCase { + func testCachePerf() { + let files = MockFiles() + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + let count = 500 + + history.clearHistory().succeeded() + populateHistoryForFrecencyCalculations(history, siteCount: count) + + history.setTopSitesNeedsInvalidation() + self.measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true) { + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + self.stopMeasuring() + } + } +} + +// MARK - Private Test Helper Methods + +private enum VisitOrigin { + case local + case remote +} + +private func populateHistoryForFrecencyCalculations(_ history: SQLiteHistory, siteCount count: Int) { + for i in 0...count { + let site = Site(url: "http://s\(i)ite\(i)/foo", title: "A \(i)") + site.guid = "abc\(i)def" + + let baseMillis: UInt64 = baseInstantInMillis - 20000 + history.insertOrUpdatePlace(site.asPlace(), modified: baseMillis).succeeded() + + for j in 0...20 { + let visitTime = advanceMicrosecondTimestamp(baseInstantInMicros, by: (1000000 * i) + (1000 * j)) + addVisitForSite(site, intoHistory: history, from: .local, atTime: visitTime) + addVisitForSite(site, intoHistory: history, from: .remote, atTime: visitTime) + } + } +} + +private func addVisitForSite(_ site: Site, intoHistory history: SQLiteHistory, from: VisitOrigin, atTime: MicrosecondTimestamp) { + let visit = SiteVisit(site: site, date: atTime, type: VisitType.link) + switch from { + case .local: + history.addLocalVisit(visit).succeeded() + case .remote: + history.storeRemoteVisits([visit], forGUID: site.guid!).succeeded() + } +} diff --git a/mobile/ios/StorageTests/CertTests.swift b/mobile/ios/StorageTests/CertTests.swift new file mode 100644 index 0000000000..5ed815e3f3 --- /dev/null +++ b/mobile/ios/StorageTests/CertTests.swift @@ -0,0 +1,46 @@ +/* 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/. */ + +import XCTest +import Storage + +class CertTests: XCTestCase { + func testCertStore() { + let certStore = CertStore() + let origin1 = "www.mozilla.org:80" + let origin2 = "people.mozilla.org:80" + let cert1 = getCertificate("testcert1") + let cert2 = getCertificate("testcert2") + + // Check that contains return false for certs not in store. + XCTAssertFalse(certStore.containsCertificate(cert1, forOrigin: origin1)) + + // Add a certificate. + certStore.addCertificate(cert1, forOrigin: origin1) + + // Check that the cert is in the store. + XCTAssert(certStore.containsCertificate(cert1, forOrigin: origin1)) + + // Check that the cert is unique to the origin. + XCTAssertFalse(certStore.containsCertificate(cert1, forOrigin: origin2)) + XCTAssertFalse(certStore.containsCertificate(cert2, forOrigin: origin1)) + + // Add a different certificate for the same origin. + certStore.addCertificate(cert2, forOrigin: origin1) + + // Check that adding a cert for an existing origin doesn't do a replace. + XCTAssert(certStore.containsCertificate(cert1, forOrigin: origin1)) + XCTAssert(certStore.containsCertificate(cert2, forOrigin: origin1)) + + // Check that adding an existing cert has no effect. + certStore.addCertificate(cert1, forOrigin: origin1) + XCTAssert(certStore.containsCertificate(cert1, forOrigin: origin1)) + } + + fileprivate func getCertificate(_ file: String) -> SecCertificate { + let path = Bundle(for: type(of: self)).path(forResource: file, ofType: "pem") + let data = try? Data(contentsOf: URL(fileURLWithPath: path!)) + return SecCertificateCreateWithData(nil, data! as CFData)! + } +} diff --git a/mobile/ios/StorageTests/DiskImageStoreTests.swift b/mobile/ios/StorageTests/DiskImageStoreTests.swift new file mode 100644 index 0000000000..9a88163866 --- /dev/null +++ b/mobile/ios/StorageTests/DiskImageStoreTests.swift @@ -0,0 +1,76 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage +import UIKit + +import XCTest + +class DiskImageStoreTests: XCTestCase { + var files: FileAccessor! + var store: DiskImageStore! + + override func setUp() { + files = MockFiles() + store = DiskImageStore(files: files, namespace: "DiskImageStoreTests", quality: 1) + + _ = store.clearExcluding(Set()).value + } + + func testStore() { + var success = false + + // Avoid image comparison and use size of the image for equality + let redImage = makeImageWithColor(UIColor.red, size: CGSize(width: 100, height: 100)) + let blueImage = makeImageWithColor(UIColor.blue, size: CGSize(width: 17, height: 17)) + + [(key: "blue", image: blueImage), (key: "red", image: redImage)].forEach() { (key, image) in + XCTAssertNil(getImage(key), "\(key) key is nil") + success = putImage(key, image: image) + XCTAssert(success, "\(key) image added to store") + XCTAssertEqual(getImage(key)!.size.width, image.size.width, "Images are equal") + + success = putImage(key, image: image) + XCTAssertFalse(success, "\(key) image not added again") + } + + _ = store.clearExcluding(Set(["red"])).value + XCTAssertNotNil(getImage("red"), "Red image still exists") + XCTAssertNil(getImage("blue"), "Blue image cleared") + } + + private func makeImageWithColor(_ color: UIColor, size: CGSize) -> UIImage { + let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) + UIGraphicsBeginImageContextWithOptions(size, false, 1.0) + color.setFill() + UIRectFill(rect) + let image = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + return image + } + + private func getImage(_ key: String) -> UIImage? { + let expectation = self.expectation(description: "Get succeeded") + var image: UIImage? + store.get(key).upon { + image = $0.successValue + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + return image + } + + private func putImage(_ key: String, image: UIImage) -> Bool { + let expectation = self.expectation(description: "Put succeeded") + var success = false + store.put(key, image: image).upon { + success = $0.isSuccess + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + return success + } +} diff --git a/mobile/ios/StorageTests/Info.plist b/mobile/ios/StorageTests/Info.plist new file mode 100644 index 0000000000..9411e4a06e --- /dev/null +++ b/mobile/ios/StorageTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/StorageTests/MockFiles.swift b/mobile/ios/StorageTests/MockFiles.swift new file mode 100644 index 0000000000..9298d62b6c --- /dev/null +++ b/mobile/ios/StorageTests/MockFiles.swift @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation +@testable import Storage + +import XCTest + +class MockFiles: FileAccessor { + init() { + let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] + super.init(rootPath: (docPath as NSString).appendingPathComponent("testing")) + } +} + +class SupportingFiles: FileAccessor { + init() { + let path = Bundle.main.bundlePath + "/PlugIns/StorageTests.xctest/" + NSLog("Supporting files: \(path)") + super.init(rootPath: path) + } +} diff --git a/mobile/ios/StorageTests/StorageTestUtils.swift b/mobile/ios/StorageTests/StorageTestUtils.swift new file mode 100644 index 0000000000..b5b90bb7fd --- /dev/null +++ b/mobile/ios/StorageTests/StorageTestUtils.swift @@ -0,0 +1,140 @@ +/* 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/. */ + +// Note that this file is imported into SyncTests, too. + +import Deferred +import Foundation +import Shared +@testable import Storage +import XCTest + +extension BrowserDB { + func assertQueryReturns(_ query: String, int: Int) { + XCTAssertEqual(int, self.runQuery(query, args: nil, factory: IntFactory).value.successValue![0]) + } +} + +extension BrowserDB { + func moveLocalToMirrorForTesting() { + // This is a risky process -- it's not the same logic that the real synchronizer uses + // (because I haven't written it yet), so it might end up lying. We do what we can. + let valueSQL = [ + "INSERT OR IGNORE INTO \(TableBookmarksMirror)", + "(guid, type, date_added, bmkUri, title, parentid, parentName, feedUri, siteUri, pos,", + " description, tags, keyword, folderName, queryId,", + " is_overridden, server_modified, faviconID)", + "SELECT guid, type, date_added, bmkUri, title, parentid, parentName,", + "feedUri, siteUri, pos, description, tags, keyword, folderName, queryId,", + "0 AS is_overridden, \(Date.now()) AS server_modified, faviconID", + "FROM \(TableBookmarksLocal)", + ].joined(separator: " ") + + // Copy its mirror structure. + let structureSQL = "INSERT INTO \(TableBookmarksMirrorStructure) SELECT * FROM \(TableBookmarksLocalStructure)" + + // Throw away the old. + let deleteLocalStructureSQL = "DELETE FROM \(TableBookmarksLocalStructure)" + let deleteLocalSQL = "DELETE FROM \(TableBookmarksLocal)" + + self.run([ + valueSQL, + structureSQL, + deleteLocalStructureSQL, + deleteLocalSQL, + ]).succeeded() + } + + func moveBufferToMirrorForTesting() { + let valueSQL = [ + "INSERT OR IGNORE INTO \(TableBookmarksMirror)", + "(guid, type, date_added, bmkUri, title, parentid, parentName, feedUri, siteUri, pos,", + "description, tags, keyword, folderName, queryId, server_modified)", + "SELECT", + "guid, type, date_added, bmkUri, title, parentid, parentName, feedUri, siteUri, pos,", + "description, tags, keyword, folderName, queryId, server_modified", + "FROM \(TableBookmarksBuffer)", + ].joined(separator: " ") + + let structureSQL = "INSERT INTO \(TableBookmarksMirrorStructure) SELECT * FROM \(TableBookmarksBufferStructure)" + let deleteBufferStructureSQL = "DELETE FROM \(TableBookmarksBufferStructure)" + let deleteBufferSQL = "DELETE FROM \(TableBookmarksBuffer)" + + self.run([ + valueSQL, + structureSQL, + deleteBufferStructureSQL, + deleteBufferSQL, + ]).succeeded() + } +} + +extension BrowserDB { + func getGUIDs(_ sql: String) -> [GUID] { + func guidFactory(_ row: SDRow) -> GUID { + return row[0] as! GUID + } + + guard let cursor = self.runQuery(sql, args: nil, factory: guidFactory).value.successValue else { + XCTFail("Unable to get cursor.") + return [] + } + return cursor.asArray() + } + + func getPositionsForChildrenOfParent(_ parent: GUID, fromTable table: String) -> [GUID: Int] { + let args: Args = [parent] + let factory: (SDRow) -> (GUID, Int) = { + return ($0["child"] as! GUID, $0["idx"] as! Int) + } + let cursor = self.runQuery("SELECT child, idx FROM \(table) WHERE parent = ?", args: args, factory: factory).value.successValue! + return cursor.reduce([:], { (dict, pair) in + var dict = dict + if let (k, v) = pair { + dict[k] = v + } + return dict + }) + } + + func isLocallyDeleted(_ guid: GUID) -> Bool? { + let args: Args = [guid] + let cursor = self.runQuery("SELECT is_deleted FROM \(TableBookmarksLocal) WHERE guid = ?", args: args, factory: { $0.getBoolean("is_deleted") }).value.successValue! + return cursor[0] + } + + func isOverridden(_ guid: GUID) -> Bool? { + let args: Args = [guid] + let cursor = self.runQuery("SELECT is_overridden FROM \(TableBookmarksMirror) WHERE guid = ?", args: args, factory: { $0.getBoolean("is_overridden") }).value.successValue! + return cursor[0] + } + + func getSyncStatusForGUID(_ guid: GUID) -> SyncStatus? { + let args: Args = [guid] + let cursor = self.runQuery("SELECT sync_status FROM \(TableBookmarksLocal) WHERE guid = ?", args: args, factory: { $0[0] as! Int }).value.successValue! + if let raw = cursor[0] { + return SyncStatus(rawValue: raw) + } + return nil + } + + func getRecordByURL(_ url: String, fromTable table: String) -> BookmarkMirrorItem { + let args: Args = [url] + return self.runQuery("SELECT * FROM \(table) WHERE bmkUri = ?", args: args, factory: BookmarkFactory.mirrorItemFactory).value.successValue![0]! + } + + func getRecordByGUID(_ guid: GUID, fromTable table: String) -> BookmarkMirrorItem { + let args: Args = [guid] + return self.runQuery("SELECT * FROM \(table) WHERE guid = ?", args: args, factory: BookmarkFactory.mirrorItemFactory).value.successValue![0]! + } + + func getChildrenOfFolder(_ folder: GUID) -> [GUID] { + let args: Args = [folder] + let sql = + "SELECT child FROM \(ViewBookmarksLocalStructureOnMirror) " + + "WHERE parent = ? " + + "ORDER BY idx ASC" + return self.runQuery(sql, args: args, factory: { $0[0] as! GUID }).value.successValue!.asArray() + } +} diff --git a/mobile/ios/StorageTests/SyncCommandsTests.swift b/mobile/ios/StorageTests/SyncCommandsTests.swift new file mode 100644 index 0000000000..6bd918ba49 --- /dev/null +++ b/mobile/ios/StorageTests/SyncCommandsTests.swift @@ -0,0 +1,237 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage + +import XCTest +import SwiftyJSON + +func byValue(_ a: SyncCommand, b: SyncCommand) -> Bool { + return a.value < b.value +} + +func byClient(_ a: RemoteClient, b: RemoteClient) -> Bool { + return a.guid! < b.guid! +} + +class SyncCommandsTests: XCTestCase { + + var clients: [RemoteClient] = [RemoteClient]() + var clientsAndTabs: SQLiteRemoteClientsAndTabs! + + var shareItems = [ShareItem]() + + var multipleCommands: [ShareItem] = [ShareItem]() + var wipeCommand: SyncCommand! + var db: BrowserDB! + + override func setUp() { + let files = MockFiles() + do { + try files.remove("browser.db") + } catch _ { + } + db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + + // create clients + let now = Date.now() + let client1GUID = Bytes.generateGUID() + let client2GUID = Bytes.generateGUID() + let client3GUID = Bytes.generateGUID() + + self.clients.append(RemoteClient(guid: client1GUID, name: "Test client 1", modified: (now - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: "55.0.1", fxaDeviceId: nil)) + self.clients.append(RemoteClient(guid: client2GUID, name: "Test client 2", modified: (now - OneHourInMilliseconds), type: "desktop", formfactor: "laptop", os: "Darwin", version: "55.0.1", fxaDeviceId: nil)) + self.clients.append(RemoteClient(guid: client3GUID, name: "Test local client", modified: (now - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: "55.0.1", fxaDeviceId: nil)) + clientsAndTabs = SQLiteRemoteClientsAndTabs(db: db) + clientsAndTabs.insertOrUpdateClients(clients).succeeded() + + shareItems.append(ShareItem(url: "http://mozilla.com", title: "Mozilla", favicon: nil)) + shareItems.append(ShareItem(url: "http://slashdot.org", title: "Slashdot", favicon: nil)) + shareItems.append(ShareItem(url: "http://news.bbc.co.uk", title: "BBC News", favicon: nil)) + shareItems.append(ShareItem(url: "http://news.bbc.co.uk", title: nil, favicon: nil)) + + wipeCommand = SyncCommand(value: "{'command':'wipeAll', 'args':[]}") + } + + override func tearDown() { + clientsAndTabs.deleteCommands().succeeded() + clientsAndTabs.clear().succeeded() + } + + func testCreateSyncCommandFromShareItem() { + let shareItem = shareItems[0] + let syncCommand = SyncCommand.displayURIFromShareItem(shareItem, asClient: "abcdefghijkl") + XCTAssertNil(syncCommand.commandID) + XCTAssertNotNil(syncCommand.value) + let jsonObj: [String: Any] = [ + "command": "displayURI", + "args": [shareItem.url, "abcdefghijkl", shareItem.title ?? ""] + ] + XCTAssertEqual(JSON(object: jsonObj).stringValue(), syncCommand.value) + } + + func testInsertWithNoURLOrTitle() { + // Test insert command to table for + let e = self.expectation(description: "Insert.") + clientsAndTabs.insertCommand(self.wipeCommand, forClients: clients).upon { + XCTAssertTrue($0.isSuccess) + XCTAssertEqual(3, $0.successValue!) + + let commandCursorDeferred = self.db.withConnection { connection -> Cursor in + let select = "SELECT COUNT(*) FROM \(TableSyncCommands)" + return connection.executeQuery(select, factory: IntFactory, withArgs: nil) + } + + let commandCursor = commandCursorDeferred.value.successValue! + + XCTAssertNotNil(commandCursor[0]) + XCTAssertEqual(3, commandCursor[0]!) + e.fulfill() + } + self.waitForExpectations(timeout: 5, handler: nil) + } + + func testInsertWithURLOnly() { + let shareItem = shareItems[3] + let syncCommand = SyncCommand.displayURIFromShareItem(shareItem, asClient: "abcdefghijkl") + + let e = self.expectation(description: "Insert.") + clientsAndTabs.insertCommand(syncCommand, forClients: clients).upon { + XCTAssertTrue($0.isSuccess) + XCTAssertEqual(3, $0.successValue!) + + let commandCursorDeferred = self.db.withConnection { connection -> Cursor in + let select = "SELECT COUNT(*) FROM \(TableSyncCommands)" + return connection.executeQuery(select, factory: IntFactory, withArgs: nil) + } + + let commandCursor = commandCursorDeferred.value.successValue! + + XCTAssertNotNil(commandCursor[0]) + XCTAssertEqual(3, commandCursor[0]!) + e.fulfill() + } + self.waitForExpectations(timeout: 5, handler: nil) + } + + func testInsertWithMultipleCommands() { + let e = self.expectation(description: "Insert.") + let syncCommands = shareItems.map { item in + return SyncCommand.displayURIFromShareItem(item, asClient: "abcdefghijkl") + } + clientsAndTabs.insertCommands(syncCommands, forClients: clients).upon { + XCTAssertTrue($0.isSuccess) + XCTAssertEqual(12, $0.successValue!) + + let commandCursorDeferred = self.db.withConnection { connection -> Cursor in + let select = "SELECT COUNT(*) FROM \(TableSyncCommands)" + return connection.executeQuery(select, factory: IntFactory, withArgs: nil) + } + + let commandCursor = commandCursorDeferred.value.successValue! + + XCTAssertNotNil(commandCursor[0]) + XCTAssertEqual(12, commandCursor[0]!) + e.fulfill() + } + self.waitForExpectations(timeout: 5, handler: nil) + } + + func testGetForAllClients() { + let syncCommands = shareItems.map { item in + return SyncCommand.displayURIFromShareItem(item, asClient: "abcdefghijkl") + }.sorted(by: byValue) + clientsAndTabs.insertCommands(syncCommands, forClients: clients).succeeded() + + let b = self.expectation(description: "Get for invalid client.") + clientsAndTabs.getCommands().upon({ result in + XCTAssertTrue(result.isSuccess) + if let clientCommands = result.successValue { + XCTAssertEqual(clientCommands.count, self.clients.count) + for client in clientCommands.keys { + XCTAssertEqual(syncCommands, clientCommands[client]!.sorted(by: byValue)) + } + } else { + XCTFail("Expected no commands!") + } + b.fulfill() + }) + self.waitForExpectations(timeout: 5, handler: nil) + } + + func testDeleteForValidClient() { + let syncCommands = shareItems.map { item in + return SyncCommand.displayURIFromShareItem(item, asClient: "abcdefghijkl") + }.sorted(by: byValue) + + var client = self.clients[0] + let a = self.expectation(description: "delete for client.") + let b = self.expectation(description: "Get for deleted client.") + let c = self.expectation(description: "Get for not deleted client.") + clientsAndTabs.insertCommands(syncCommands, forClients: clients).upon { + XCTAssertTrue($0.isSuccess) + XCTAssertEqual(12, $0.successValue!) + + let result = self.clientsAndTabs.deleteCommands(client.guid!).value + XCTAssertTrue(result.isSuccess) + a.fulfill() + + let commandCursorDeferred = self.db.withConnection { connection -> Cursor in + let select = "SELECT COUNT(*) FROM \(TableSyncCommands) WHERE client_guid = '\(client.guid!)'" + return connection.executeQuery(select, factory: IntFactory, withArgs: nil) + } + + let commandCursor = commandCursorDeferred.value.successValue! + + XCTAssertNotNil(commandCursor[0]) + XCTAssertEqual(0, commandCursor[0]!) + b.fulfill() + + client = self.clients[1] + let commandCursor2Deferred = self.db.withConnection { connection -> Cursor in + let select = "SELECT COUNT(*) FROM \(TableSyncCommands) WHERE client_guid = '\(client.guid!)'" + return connection.executeQuery(select, factory: IntFactory, withArgs: nil) + } + + let commandCursor2 = commandCursor2Deferred.value.successValue! + + XCTAssertNotNil(commandCursor2[0]) + XCTAssertEqual(4, commandCursor2[0]!) + c.fulfill() + } + + self.waitForExpectations(timeout: 5, handler: nil) + } + + func testDeleteForAllClients() { + let syncCommands = shareItems.map { item in + return SyncCommand.displayURIFromShareItem(item, asClient: "abcdefghijkl") + } + + let a = self.expectation(description: "Wipe for all clients.") + let b = self.expectation(description: "Get for clients.") + clientsAndTabs.insertCommands(syncCommands, forClients: clients).upon { + XCTAssertTrue($0.isSuccess) + XCTAssertEqual(12, $0.successValue!) + + let result = self.clientsAndTabs.deleteCommands().value + XCTAssertTrue(result.isSuccess) + a.fulfill() + + self.clientsAndTabs.getCommands().upon({ result in + XCTAssertTrue(result.isSuccess) + if let clientCommands = result.successValue { + XCTAssertEqual(0, clientCommands.count) + } else { + XCTFail("Expected no commands!") + } + b.fulfill() + }) + } + + self.waitForExpectations(timeout: 5, handler: nil) + } +} diff --git a/mobile/ios/StorageTests/SyncTelemetryTests.swift b/mobile/ios/StorageTests/SyncTelemetryTests.swift new file mode 100644 index 0000000000..a853330020 --- /dev/null +++ b/mobile/ios/StorageTests/SyncTelemetryTests.swift @@ -0,0 +1,118 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON +@testable import Sync + +import XCTest + +fileprivate class MockFailure: MaybeErrorType { + let record: Record + + var description: String { + return "Failed to store or upload record: \(record)" + } + + init(record: Record) { + self.record = record + } +} + +class SyncTelemetryTests: XCTestCase { +} + +// MARK: IndependentRecordSynchronizer +extension SyncTelemetryTests { + private func getMockedIndependentRecordSynchronizer() -> IndependentRecordSynchronizer { + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + let delegate = MockSyncDelegate() + + return IndependentRecordSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled, collection: "mockHistory") + } + + func testApplyIncomingRecordsReportsDownloadStats() { + let synchronizer = getMockedIndependentRecordSynchronizer() + synchronizer.statsSession.start() + + // Fake remote records for incoming changes + let payloadA = CleartextPayloadJSON("{\"id\":\"A\",\"title\": \"A\"}") + let A = Record(id: "A", payload: payloadA) + + let payloadB = CleartextPayloadJSON("{\"id\":\"B\",\"title\": \"B\"}") + let B = Record(id: "B", payload: payloadB) + + let remoteRecords = [A, B] + + let _ = synchronizer.applyIncomingRecords(remoteRecords) { record in + return record.id == "B" ? deferMaybe(MockFailure(record: record)) : succeed() + }.value + + let session = synchronizer.statsSession.end() + + let downloadStats = session.downloadStats + XCTAssertEqual(downloadStats.applied, 2) + XCTAssertEqual(downloadStats.succeeded, 1) + XCTAssertEqual(downloadStats.failed, 1) + } + + func testApplyIncomingRecordsToStorageReportsDownloadStats() { + let synchronizer = getMockedIndependentRecordSynchronizer() + synchronizer.statsSession.start() + + // Fake remote records for incoming changes + let payloadA = CleartextPayloadJSON("{\"id\":\"A\",\"title\": \"A\"}") + let A = Record(id: "A", payload: payloadA) + + let payloadB = CleartextPayloadJSON("{\"id\":\"B\",\"title\": \"B\"}") + let B = Record(id: "B", payload: payloadB) + + let records = [A, B] + + let _ = synchronizer.applyIncomingToStorage(records, fetched: Date.now()) { record in + return record.id == "B" ? deferMaybe(MockFailure(record: record)) : succeed() + }.value + + let session = synchronizer.statsSession.end() + + let downloadStats = session.downloadStats + XCTAssertEqual(downloadStats.applied, 2) + XCTAssertEqual(downloadStats.succeeded, 1) + XCTAssertEqual(downloadStats.failed, 1) + } + + func testUploadRecordsReportsUploadStats() { + let synchronizer = getMockedIndependentRecordSynchronizer() + synchronizer.statsSession.start() + + let now = Date.now() + + // Fake local records for outgoing changes + let payloadC = CleartextPayloadJSON("{\"id\":\"C\",\"title\": \"C\"}") + let C = Record(id: "C", payload: payloadC) + + let payloadD = CleartextPayloadJSON("{\"id\":\"D\", \"title\": \"D\"}") + let D = Record(id: "D", payload: payloadD) + let records = [C, D] + + // Mock out a response for the uploader + let uploader: BatchUploadFunction = { _, _, _ in + let result = POSTResult(success: [C.id], failed: [D.id: "Invalid GUID"]) + let response = StorageResponse(value: result, metadata: ResponseMetadata(status: 200, headers: [:])) + return deferMaybe(response) + } + + let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 2, maxPostBytes: 1_048_576, maxTotalRecords: 10, maxTotalBytes: 104_857_600) + let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "mockdata", encrypter: getEncrypter()) + let _ = synchronizer.uploadRecords(records, lastTimestamp: now, storageClient: collectionClient) { _, _ in + return deferMaybe(now) + }.value + + let uploadStats = synchronizer.statsSession.uploadStats + XCTAssertEqual(uploadStats.sent, 1) + XCTAssertEqual(uploadStats.sentFailed, 1) + } +} diff --git a/mobile/ios/StorageTests/TestBrowserDB.swift b/mobile/ios/StorageTests/TestBrowserDB.swift new file mode 100644 index 0000000000..3363c703fa --- /dev/null +++ b/mobile/ios/StorageTests/TestBrowserDB.swift @@ -0,0 +1,124 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage +import XCGLogger + +import XCTest + +private let log = XCGLogger.default + +class TestBrowserDB: XCTestCase { + let files = MockFiles() + + fileprivate func rm(_ path: String) { + do { + try files.remove(path) + } catch { + } + } + + override func setUp() { + super.setUp() + rm("foo.db") + rm("foo.db-shm") + rm("foo.db-wal") + rm("foo.db.bak.1") + rm("foo.db.bak.1-shm") + rm("foo.db.bak.1-wal") + } + + class MockFailingSchema: Schema { + var name: String { return "FAILURE" } + var version: Int { return BrowserSchema.DefaultVersion + 1 } + func drop(_ db: SQLiteDBConnection) -> Bool { + return true + } + func create(_ db: SQLiteDBConnection) -> Bool { + return false + } + func update(_ db: SQLiteDBConnection, from: Int) -> Bool { + return false + } + } + + fileprivate class MockListener { + var notification: Notification? + @objc + func onDatabaseWasRecreated(_ notification: Notification) { + self.notification = notification + } + } + + func testUpgradeV33toV34RemovesLongURLs() { + let db = BrowserDB(filename: "v33.db", schema: BrowserSchema(), files: SupportingFiles()) + let results = db.runQuery("SELECT bmkUri, title FROM bookmarksLocal WHERE type = 1", args: nil, factory: { row in + (row[0] as! String, row[1] as! String) + }).value.successValue! + + // The bookmark with the long URL has been deleted. + XCTAssertTrue(results.count == 1) + + let remaining = results[0]! + + // This one's title has been truncated to 4096 chars. + XCTAssertEqual(remaining.1.characters.count, 4096) + XCTAssertEqual(remaining.1.utf8.count, 4096) + XCTAssertTrue(remaining.1.hasPrefix("abcdefghijkl")) + XCTAssertEqual(remaining.0, "http://example.com/short") + } + + func testMovesDB() { + var db = BrowserDB(filename: "foo.db", schema: BrowserSchema(), files: self.files) + db.run("CREATE TABLE foo (bar TEXT)").succeeded() // Just so we have writes in the WAL. + + XCTAssertTrue(files.exists("foo.db")) + XCTAssertTrue(files.exists("foo.db-shm")) + XCTAssertTrue(files.exists("foo.db-wal")) + + // Grab a pointer to the -shm so we can compare later. + let shmAAttributes = try! files.attributesForFileAt(relativePath: "foo.db-shm") + let creationA = shmAAttributes[FileAttributeKey.creationDate] as! Date + let inodeA = (shmAAttributes[FileAttributeKey.systemFileNumber] as! NSNumber).uintValue + + XCTAssertFalse(files.exists("foo.db.bak.1")) + XCTAssertFalse(files.exists("foo.db.bak.1-shm")) + XCTAssertFalse(files.exists("foo.db.bak.1-wal")) + + let center = NotificationCenter.default + let listener = MockListener() + center.addObserver(listener, selector: #selector(MockListener.onDatabaseWasRecreated(_:)), name: NotificationDatabaseWasRecreated, object: nil) + defer { center.removeObserver(listener) } + + // It'll still fail, but it moved our old DB. + // Our current observation is that closing the DB deletes the .shm file and also + // checkpoints the WAL. + db.forceClose() + + db = BrowserDB(filename: "foo.db", schema: MockFailingSchema(), files: self.files) + db.run("CREATE TABLE foo (bar TEXT)").failed() // This won't actually write since we'll get a failed connection + db = BrowserDB(filename: "foo.db", schema: BrowserSchema(), files: self.files) + db.run("CREATE TABLE foo (bar TEXT)").succeeded() // Just so we have writes in the WAL. + + XCTAssertTrue(files.exists("foo.db")) + XCTAssertTrue(files.exists("foo.db-shm")) + XCTAssertTrue(files.exists("foo.db-wal")) + + // But now it's been reopened, it's not the same -shm! + let shmBAttributes = try! files.attributesForFileAt(relativePath: "foo.db-shm") + let creationB = shmBAttributes[FileAttributeKey.creationDate] as! Date + let inodeB = (shmBAttributes[FileAttributeKey.systemFileNumber] as! NSNumber).uintValue + XCTAssertTrue(creationA.compare(creationB) != ComparisonResult.orderedDescending) + XCTAssertNotEqual(inodeA, inodeB) + + XCTAssertTrue(files.exists("foo.db.bak.1")) + XCTAssertFalse(files.exists("foo.db.bak.1-shm")) + XCTAssertFalse(files.exists("foo.db.bak.1-wal")) + + // The right notification was issued. + XCTAssertEqual("foo.db", (listener.notification?.object as? String)) + } +} diff --git a/mobile/ios/StorageTests/TestLogins.swift b/mobile/ios/StorageTests/TestLogins.swift new file mode 100644 index 0000000000..8068c1dfed --- /dev/null +++ b/mobile/ios/StorageTests/TestLogins.swift @@ -0,0 +1,741 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage +import XCGLogger + +import XCTest + +private let log = XCGLogger.default + +class TestSQLiteLogins: XCTestCase { + var db: BrowserDB! + var logins: SQLiteLogins! + + let formSubmitURL = "http://submit.me" + let login = Login.createWithHostname("hostname1", username: "username1", password: "password1", formSubmitURL: "http://submit.me") + + override func setUp() { + super.setUp() + + let files = MockFiles() + self.db = BrowserDB(filename: "testsqlitelogins.db", schema: LoginsSchema(), files: files) + self.logins = SQLiteLogins(db: self.db) + + let expectation = self.expectation(description: "Remove all logins.") + self.removeAllLogins().upon({ res in expectation.fulfill() }) + waitForExpectations(timeout: 10.0, handler: nil) + } + + func testAddLogin() { + log.debug("Created \(self.login)") + let expectation = self.expectation(description: "Add login") + + addLogin(login) + >>> getLoginsFor(login.protectionSpace, expected: [login]) + >>> done(expectation) + + waitForExpectations(timeout: 10.0, handler: nil) + } + + func testGetOrder() { + let expectation = self.expectation(description: "Add login") + + // Different GUID. + let login2 = Login.createWithHostname("hostname1", username: "username2", password: "password2") + login2.formSubmitURL = "http://submit.me" + + addLogin(login) >>> { self.addLogin(login2) } >>> + getLoginsFor(login.protectionSpace, expected: [login2, login]) >>> + done(expectation) + + waitForExpectations(timeout: 10.0, handler: nil) + } + + func testRemoveLogin() { + let expectation = self.expectation(description: "Remove login") + + addLogin(login) + >>> { self.removeLogin(self.login) } + >>> getLoginsFor(login.protectionSpace, expected: []) + >>> done(expectation) + + waitForExpectations(timeout: 10.0, handler: nil) + } + + func testRemoveLogins() { + let loginA = Login.createWithHostname("alphabet.com", username: "username1", password: "password1", formSubmitURL: formSubmitURL) + let loginB = Login.createWithHostname("alpha.com", username: "username2", password: "password2", formSubmitURL: formSubmitURL) + let loginC = Login.createWithHostname("berry.com", username: "username3", password: "password3", formSubmitURL: formSubmitURL) + let loginD = Login.createWithHostname("candle.com", username: "username4", password: "password4", formSubmitURL: formSubmitURL) + + func addLogins() -> Success { + addLogin(loginA).succeeded() + addLogin(loginB).succeeded() + addLogin(loginC).succeeded() + addLogin(loginD).succeeded() + return succeed() + } + + addLogins().succeeded() + let guids = [loginA.guid, loginB.guid] + logins.removeLoginsWithGUIDs(guids).succeeded() + let result = logins.getAllLogins().value.successValue! + XCTAssertEqual(result.count, 2) + } + + func testRemoveManyLogins() { + log.debug("Remove a large number of logins at once") + var guids: [GUID] = [] + for i in 0..<2000 { + let login = Login.createWithHostname("mozilla.org", username: "Fire", password: "fox", formSubmitURL: formSubmitURL) + if i <= 1000 { + guids += [login.guid] + } + addLogin(login).succeeded() + } + logins.removeLoginsWithGUIDs(guids).succeeded() + let result = logins.getAllLogins().value.successValue! + XCTAssertEqual(result.count, 999) + } + + func testUpdateLogin() { + let expectation = self.expectation(description: "Update login") + let updated = Login.createWithHostname("hostname1", username: "username1", password: "password3", formSubmitURL: formSubmitURL) + updated.guid = self.login.guid + + addLogin(login) >>> { self.updateLogin(updated) } >>> + getLoginsFor(login.protectionSpace, expected: [updated]) >>> + done(expectation) + + waitForExpectations(timeout: 10.0, handler: nil) + } + + func testAddInvalidLogin() { + let emptyPasswordLogin = Login.createWithHostname("hostname1", username: "username1", password: "", formSubmitURL: formSubmitURL) + var result = logins.addLogin(emptyPasswordLogin).value + XCTAssertNil(result.successValue) + XCTAssertNotNil(result.failureValue) + XCTAssertEqual(result.failureValue?.description, "Can't add a login with an empty password.") + + let emptyHostnameLogin = Login.createWithHostname("", username: "username1", password: "password", formSubmitURL: formSubmitURL) + result = logins.addLogin(emptyHostnameLogin).value + XCTAssertNil(result.successValue) + XCTAssertNotNil(result.failureValue) + XCTAssertEqual(result.failureValue?.description, "Can't add a login with an empty hostname.") + + let credential = URLCredential(user: "username", password: "password", persistence: .forSession) + let protectionSpace = URLProtectionSpace(host: "https://website.com", port: 443, protocol: "https", realm: "Basic Auth", authenticationMethod: "Basic Auth") + let bothFormSubmitURLAndRealm = Login.createWithCredential(credential, protectionSpace: protectionSpace) + bothFormSubmitURLAndRealm.formSubmitURL = "http://submit.me" + result = logins.addLogin(bothFormSubmitURLAndRealm).value + XCTAssertNil(result.successValue) + XCTAssertNotNil(result.failureValue) + XCTAssertEqual(result.failureValue?.description, "Can't add a login with both a httpRealm and formSubmitURL.") + + let noFormSubmitURLOrRealm = Login.createWithHostname("host", username: "username1", password: "password", formSubmitURL: nil) + result = logins.addLogin(noFormSubmitURLOrRealm).value + XCTAssertNil(result.successValue) + XCTAssertNotNil(result.failureValue) + XCTAssertEqual(result.failureValue?.description, "Can't add a login without a httpRealm or formSubmitURL.") + } + + func testUpdateInvalidLogin() { + let updated = Login.createWithHostname("hostname1", username: "username1", password: "", formSubmitURL: formSubmitURL) + updated.guid = self.login.guid + + addLogin(login).succeeded() + var result = logins.updateLoginByGUID(login.guid, new: updated, significant: true).value + XCTAssertNil(result.successValue) + XCTAssertNotNil(result.failureValue) + XCTAssertEqual(result.failureValue?.description, "Can't add a login with an empty password.") + + let emptyHostnameLogin = Login.createWithHostname("", username: "username1", password: "", formSubmitURL: formSubmitURL) + emptyHostnameLogin.guid = self.login.guid + result = logins.updateLoginByGUID(login.guid, new: emptyHostnameLogin, significant: true).value + XCTAssertNil(result.successValue) + XCTAssertNotNil(result.failureValue) + XCTAssertEqual(result.failureValue?.description, "Can't add a login with an empty hostname.") + + let credential = URLCredential(user: "username", password: "password", persistence: .forSession) + let protectionSpace = URLProtectionSpace(host: "https://website.com", port: 443, protocol: "https", realm: "Basic Auth", authenticationMethod: "Basic Auth") + let bothFormSubmitURLAndRealm = Login.createWithCredential(credential, protectionSpace: protectionSpace) + bothFormSubmitURLAndRealm.formSubmitURL = "http://submit.me" + bothFormSubmitURLAndRealm.guid = self.login.guid + result = logins.updateLoginByGUID(login.guid, new: bothFormSubmitURLAndRealm, significant: true).value + XCTAssertNil(result.successValue) + XCTAssertNotNil(result.failureValue) + XCTAssertEqual(result.failureValue?.description, "Can't add a login with both a httpRealm and formSubmitURL.") + + let noFormSubmitURLOrRealm = Login.createWithHostname("host", username: "username1", password: "password", formSubmitURL: nil) + noFormSubmitURLOrRealm.guid = self.login.guid + result = logins.updateLoginByGUID(login.guid, new: noFormSubmitURLOrRealm, significant: true).value + XCTAssertNil(result.successValue) + XCTAssertNotNil(result.failureValue) + XCTAssertEqual(result.failureValue?.description, "Can't add a login without a httpRealm or formSubmitURL.") + } + + func testSearchLogins() { + let loginA = Login.createWithHostname("alphabet.com", username: "username1", password: "password1", formSubmitURL: formSubmitURL) + let loginB = Login.createWithHostname("alpha.com", username: "username2", password: "password2", formSubmitURL: formSubmitURL) + let loginC = Login.createWithHostname("berry.com", username: "username3", password: "password3", formSubmitURL: formSubmitURL) + let loginD = Login.createWithHostname("candle.com", username: "username4", password: "password4", formSubmitURL: formSubmitURL) + + func addLogins() -> Success { + addLogin(loginA).succeeded() + addLogin(loginB).succeeded() + addLogin(loginC).succeeded() + addLogin(loginD).succeeded() + return succeed() + } + + func checkAllLogins() -> Success { + return logins.getAllLogins() >>== { results in + XCTAssertEqual(results.count, 4) + return succeed() + } + } + + func checkSearchHostnames() -> Success { + return logins.searchLoginsWithQuery("pha") >>== { results in + XCTAssertEqual(results.count, 2) + XCTAssertEqual(results[0]!.hostname, "http://alpha.com") + XCTAssertEqual(results[1]!.hostname, "http://alphabet.com") + return succeed() + } + } + + func checkSearchUsernames() -> Success { + return logins.searchLoginsWithQuery("username") >>== { results in + XCTAssertEqual(results.count, 4) + XCTAssertEqual(results[0]!.username, "username2") + XCTAssertEqual(results[1]!.username, "username1") + XCTAssertEqual(results[2]!.username, "username3") + XCTAssertEqual(results[3]!.username, "username4") + return succeed() + } + } + + func checkSearchPasswords() -> Success { + return logins.searchLoginsWithQuery("pass") >>== { results in + XCTAssertEqual(results.count, 4) + XCTAssertEqual(results[0]!.password, "password2") + XCTAssertEqual(results[1]!.password, "password1") + XCTAssertEqual(results[2]!.password, "password3") + XCTAssertEqual(results[3]!.password, "password4") + return succeed() + } + } + + XCTAssertTrue(addLogins().value.isSuccess) + + XCTAssertTrue(checkAllLogins().value.isSuccess) + XCTAssertTrue(checkSearchHostnames().value.isSuccess) + XCTAssertTrue(checkSearchUsernames().value.isSuccess) + XCTAssertTrue(checkSearchPasswords().value.isSuccess) + + XCTAssertTrue(removeAllLogins().value.isSuccess) + } + + /* + func testAddUseOfLogin() { + let expectation = self.self.expectation(description: "Add visit") + + if var usageData = login as? LoginUsageData { + usageData.timeCreated = Date.nowMicroseconds() + } + + addLogin(login) >>> + addUseDelayed(login, time: 1) >>> + getLoginDetailsFor(login, expected: login as! LoginUsageData) >>> + done(login.protectionSpace, expectation: expectation) + + waitForExpectations(timeout: 10.0, handler: nil) + } + */ + + func done(_ expectation: XCTestExpectation) -> () -> Success { + return { + self.removeAllLogins() + >>> self.getLoginsFor(self.login.protectionSpace, expected: []) + >>> { + expectation.fulfill() + return succeed() + } + } + } + + // Note: These functions are all curried so that we pass arguments, but still chain them below + func addLogin(_ login: LoginData) -> Success { + log.debug("Add \(login)") + return logins.addLogin(login) + } + + func updateLogin(_ login: LoginData) -> Success { + log.debug("Update \(login)") + return logins.updateLoginByGUID(login.guid, new: login, significant: true) + } + + func addUseDelayed(_ login: Login, time: UInt32) -> Success { + sleep(time) + login.timeLastUsed = Date.nowMicroseconds() + let res = logins.addUseOfLoginByGUID(login.guid) + sleep(time) + return res + } + + func getLoginsFor(_ protectionSpace: URLProtectionSpace, expected: [LoginData]) -> (() -> Success) { + return { + log.debug("Get logins for \(protectionSpace)") + return self.logins.getLoginsForProtectionSpace(protectionSpace) >>== { results in + XCTAssertEqual(expected.count, results.count) + for (index, login) in expected.enumerated() { + XCTAssertEqual(results[index]!.username!, login.username!) + XCTAssertEqual(results[index]!.hostname, login.hostname) + XCTAssertEqual(results[index]!.password, login.password) + } + return succeed() + } + } + } + + /* + func getLoginDetailsFor(login: LoginData, expected: LoginUsageData) -> (() -> Success) { + return { + log.debug("Get details for \(login)") + let deferred = self.logins.getUsageDataForLogin(login) + log.debug("Final result \(deferred)") + return deferred >>== { l in + log.debug("Got cursor") + XCTAssertLessThan(expected.timePasswordChanged - l.timePasswordChanged, 10) + XCTAssertLessThan(expected.timeLastUsed - l.timeLastUsed, 10) + XCTAssertLessThan(expected.timeCreated - l.timeCreated, 10) + return succeed() + } + } + } + */ + + func removeLogin(_ login: LoginData) -> Success { + log.debug("Remove \(login)") + return logins.removeLoginByGUID(login.guid) + } + + func removeAllLogins() -> Success { + log.debug("Remove All") + // Because we don't want to just mark them as deleted. + return self.db.run("DELETE FROM \(TableLoginsMirror)") >>> { self.db.run("DELETE FROM \(TableLoginsLocal)") } + } +} + +class TestSQLiteLoginsPerf: XCTestCase { + var db: BrowserDB! + var logins: SQLiteLogins! + + override func setUp() { + super.setUp() + let files = MockFiles() + self.db = BrowserDB(filename: "testsqlitelogins.db", schema: LoginsSchema(), files: files) + self.logins = SQLiteLogins(db: self.db) + } + + func testLoginsSearchMatchOnePerf() { + populateTestLogins() + + // Measure time to find one entry amongst the 1000 of them + self.measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true) { + for _ in 0...5 { + self.logins.searchLoginsWithQuery("username500").succeeded() + } + self.stopMeasuring() + } + + XCTAssertTrue(removeAllLogins().value.isSuccess) + } + + func testLoginsSearchMatchAllPerf() { + populateTestLogins() + + // Measure time to find all matching results + self.measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true) { + for _ in 0...5 { + self.logins.searchLoginsWithQuery("username").succeeded() + } + self.stopMeasuring() + } + + XCTAssertTrue(removeAllLogins().value.isSuccess) + } + + func testLoginsGetAllPerf() { + populateTestLogins() + + // Measure time to find all matching results + self.measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true) { + for _ in 0...5 { + self.logins.getAllLogins().succeeded() + } + self.stopMeasuring() + } + + XCTAssertTrue(removeAllLogins().value.isSuccess) + } + + func populateTestLogins() { + for i in 0..<1000 { + let login = Login.createWithHostname("website\(i).com", username: "username\(i)", password: "password\(i)", formSubmitURL: "test") + addLogin(login).succeeded() + } + } + + func addLogin(_ login: LoginData) -> Success { + return logins.addLogin(login) + } + + func removeAllLogins() -> Success { + log.debug("Remove All") + // Because we don't want to just mark them as deleted. + return self.db.run("DELETE FROM \(TableLoginsMirror)") >>> { self.db.run("DELETE FROM \(TableLoginsLocal)") } + } +} + +class TestSyncableLogins: XCTestCase { + var db: BrowserDB! + var logins: SQLiteLogins! + + override func setUp() { + super.setUp() + + let files = MockFiles() + self.db = BrowserDB(filename: "testsyncablelogins.db", schema: LoginsSchema(), files: files) + self.logins = SQLiteLogins(db: self.db) + + let expectation = self.expectation(description: "Remove all logins.") + self.removeAllLogins().upon({ res in expectation.fulfill() }) + waitForExpectations(timeout: 10.0, handler: nil) + } + + func removeAllLogins() -> Success { + log.debug("Remove All") + // Because we don't want to just mark them as deleted. + return self.db.run("DELETE FROM \(TableLoginsMirror)") >>> { self.db.run("DELETE FROM \(TableLoginsLocal)") } + } + + func testDiffers() { + let guid = "abcdabcdabcd" + let host = "http://example.com" + let user = "username" + let loginA1 = Login(guid: guid, hostname: host, username: user, password: "password1") + loginA1.formSubmitURL = "\(host)/form1/" + loginA1.usernameField = "afield" + + let loginA2 = Login(guid: guid, hostname: host, username: user, password: "password1") + loginA2.formSubmitURL = "\(host)/form1/" + loginA2.usernameField = "somefield" + + let loginB = Login(guid: guid, hostname: host, username: user, password: "password2") + loginB.formSubmitURL = "\(host)/form1/" + + let loginC = Login(guid: guid, hostname: host, username: user, password: "password") + loginC.formSubmitURL = "\(host)/form2/" + + XCTAssert(loginA1.isSignificantlyDifferentFrom(loginB)) + XCTAssert(loginA1.isSignificantlyDifferentFrom(loginC)) + XCTAssert(loginA2.isSignificantlyDifferentFrom(loginB)) + XCTAssert(loginA2.isSignificantlyDifferentFrom(loginC)) + XCTAssert(!loginA1.isSignificantlyDifferentFrom(loginA2)) + } + + func testLocalNewStaysNewAndIsRemoved() { + let guidA = "abcdabcdabcd" + let loginA1 = Login(guid: guidA, hostname: "http://example.com", username: "username", password: "password") + loginA1.formSubmitURL = "http://example.com/form/" + loginA1.timesUsed = 1 + XCTAssertTrue((self.logins as BrowserLogins).addLogin(loginA1).value.isSuccess) + + let local1 = self.logins.getExistingLocalRecordByGUID(guidA).value.successValue! + XCTAssertNotNil(local1) + XCTAssertEqual(local1!.guid, guidA) + XCTAssertEqual(local1!.syncStatus, SyncStatus.new) + XCTAssertEqual(local1!.timesUsed, 1) + + XCTAssertTrue(self.logins.addUseOfLoginByGUID(guidA).value.isSuccess) + + // It's still new. + let local2 = self.logins.getExistingLocalRecordByGUID(guidA).value.successValue! + XCTAssertNotNil(local2) + XCTAssertEqual(local2!.guid, guidA) + XCTAssertEqual(local2!.syncStatus, SyncStatus.new) + XCTAssertEqual(local2!.timesUsed, 2) + + // It's removed immediately, because it was never synced. + XCTAssertTrue((self.logins as BrowserLogins).removeLoginByGUID(guidA).value.isSuccess) + XCTAssertNil(self.logins.getExistingLocalRecordByGUID(guidA).value.successValue!) + } + + func testApplyLogin() { + let guidA = "abcdabcdabcd" + let loginA1 = ServerLogin(guid: guidA, hostname: "http://example.com", username: "username", password: "password", modified: 1234) + loginA1.formSubmitURL = "http://example.com/form/" + loginA1.timesUsed = 3 + + XCTAssertTrue(self.logins.applyChangedLogin(loginA1).value.isSuccess) + + let local = self.logins.getExistingLocalRecordByGUID(guidA).value.successValue! + let mirror = self.logins.getExistingMirrorRecordByGUID(guidA).value.successValue! + + XCTAssertTrue(nil == local) + XCTAssertTrue(nil != mirror) + + XCTAssertEqual(mirror!.guid, guidA) + XCTAssertFalse(mirror!.isOverridden) + XCTAssertEqual(mirror!.serverModified, Timestamp(1234), "Timestamp matches.") + XCTAssertEqual(mirror!.timesUsed, 3) + XCTAssertTrue(nil == mirror!.httpRealm) + XCTAssertTrue(nil == mirror!.passwordField) + XCTAssertTrue(nil == mirror!.usernameField) + XCTAssertEqual(mirror!.formSubmitURL!, "http://example.com/form/") + XCTAssertEqual(mirror!.hostname, "http://example.com") + XCTAssertEqual(mirror!.username!, "username") + XCTAssertEqual(mirror!.password, "password") + + // Change it. + let loginA2 = ServerLogin(guid: guidA, hostname: "http://example.com", username: "username", password: "newpassword", modified: 2234) + loginA2.formSubmitURL = "http://example.com/form/" + loginA2.timesUsed = 4 + + XCTAssertTrue(self.logins.applyChangedLogin(loginA2).value.isSuccess) + let changed = self.logins.getExistingMirrorRecordByGUID(guidA).value.successValue! + + XCTAssertTrue(nil != changed) + XCTAssertFalse(changed!.isOverridden) + XCTAssertEqual(changed!.serverModified, Timestamp(2234), "Timestamp is new.") + XCTAssertEqual(changed!.username!, "username") + XCTAssertEqual(changed!.password, "newpassword") + XCTAssertEqual(changed!.timesUsed, 4) + + // Change it locally. + let preUse = Date.now() + XCTAssertTrue(self.logins.addUseOfLoginByGUID(guidA).value.isSuccess) + + let localUsed = self.logins.getExistingLocalRecordByGUID(guidA).value.successValue! + let mirrorUsed = self.logins.getExistingMirrorRecordByGUID(guidA).value.successValue! + + XCTAssertNotNil(localUsed) + XCTAssertNotNil(mirrorUsed) + + XCTAssertEqual(mirrorUsed!.guid, guidA) + XCTAssertEqual(localUsed!.guid, guidA) + XCTAssertEqual(mirrorUsed!.password, "newpassword") + XCTAssertEqual(localUsed!.password, "newpassword") + + XCTAssertTrue(mirrorUsed!.isOverridden) // It's now overridden. + XCTAssertEqual(mirrorUsed!.serverModified, Timestamp(2234), "Timestamp is new.") + + XCTAssertTrue(localUsed!.localModified >= preUse) // Local record is modified. + XCTAssertEqual(localUsed!.syncStatus, SyncStatus.synced) // Uses aren't enough to warrant upload. + + // Uses are local until reconciled. + XCTAssertEqual(localUsed!.timesUsed, 5) + XCTAssertEqual(mirrorUsed!.timesUsed, 4) + + // Change the password and form URL locally. + let newLocalPassword = Login(guid: guidA, hostname: "http://example.com", username: "username", password: "yupyup") + newLocalPassword.formSubmitURL = "http://example.com/form2/" + + let preUpdate = Date.now() + + // Updates always bump our usages, too. + XCTAssertTrue(self.logins.updateLoginByGUID(guidA, new: newLocalPassword, significant: true).value.isSuccess) + + let localAltered = self.logins.getExistingLocalRecordByGUID(guidA).value.successValue! + let mirrorAltered = self.logins.getExistingMirrorRecordByGUID(guidA).value.successValue! + + XCTAssertFalse(mirrorAltered!.isSignificantlyDifferentFrom(mirrorUsed!)) // The mirror is unchanged. + XCTAssertFalse(mirrorAltered!.isSignificantlyDifferentFrom(localUsed!)) + XCTAssertTrue(mirrorAltered!.isOverridden) // It's still overridden. + + XCTAssertTrue(localAltered!.isSignificantlyDifferentFrom(localUsed!)) + XCTAssertEqual(localAltered!.password, "yupyup") + XCTAssertEqual(localAltered!.formSubmitURL!, "http://example.com/form2/") + XCTAssertTrue(localAltered!.localModified >= preUpdate) + XCTAssertEqual(localAltered!.syncStatus, SyncStatus.changed) // Changes are enough to warrant upload. + XCTAssertEqual(localAltered!.timesUsed, 6) + XCTAssertEqual(mirrorAltered!.timesUsed, 4) + } + + func testDeltas() { + // Shared. + let guidA = "abcdabcdabcd" + let loginA1 = ServerLogin(guid: guidA, hostname: "http://example.com", username: "username", password: "password", modified: 1234) + loginA1.timeCreated = 1200 + loginA1.timeLastUsed = 1234 + loginA1.timePasswordChanged = 1200 + loginA1.formSubmitURL = "http://example.com/form/" + loginA1.timesUsed = 3 + + let a1a1 = loginA1.deltas(from: loginA1) + XCTAssertEqual(0, a1a1.nonCommutative.count) + XCTAssertEqual(0, a1a1.nonConflicting.count) + XCTAssertEqual(0, a1a1.commutative.count) + + let loginA2 = ServerLogin(guid: guidA, hostname: "http://example.com", username: "username", password: "password", modified: 1235) + loginA2.timeCreated = 1200 + loginA2.timeLastUsed = 1235 + loginA2.timePasswordChanged = 1200 + loginA2.timesUsed = 4 + + let a1a2 = loginA2.deltas(from: loginA1) + + XCTAssertEqual(2, a1a2.nonCommutative.count) + XCTAssertEqual(0, a1a2.nonConflicting.count) + XCTAssertEqual(1, a1a2.commutative.count) + + switch a1a2.commutative[0] { + case let .timesUsed(increment): + XCTAssertEqual(increment, 1) + break + } + switch a1a2.nonCommutative[0] { + case let .formSubmitURL(to): + XCTAssertNil(to) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + switch a1a2.nonCommutative[1] { + case let .timeLastUsed(to): + XCTAssertEqual(to, 1235) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + + let loginA3 = ServerLogin(guid: guidA, hostname: "http://example.com", username: "username", password: "something else", modified: 1280) + loginA3.timeCreated = 1200 + loginA3.timeLastUsed = 1250 + loginA3.timePasswordChanged = 1250 + loginA3.formSubmitURL = "http://example.com/form/" + loginA3.timesUsed = 5 + + let a1a3 = loginA3.deltas(from: loginA1) + + XCTAssertEqual(3, a1a3.nonCommutative.count) + XCTAssertEqual(0, a1a3.nonConflicting.count) + XCTAssertEqual(1, a1a3.commutative.count) + + switch a1a3.commutative[0] { + case let .timesUsed(increment): + XCTAssertEqual(increment, 2) + break + } + + switch a1a3.nonCommutative[0] { + case let .password(to): + XCTAssertEqual("something else", to) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + switch a1a3.nonCommutative[1] { + case let .timeLastUsed(to): + XCTAssertEqual(to, 1250) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + switch a1a3.nonCommutative[2] { + case let .timePasswordChanged(to): + XCTAssertEqual(to, 1250) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + + // Now apply the deltas to the original record and check that they match! + XCTAssertFalse(loginA1.applyDeltas(a1a2).isSignificantlyDifferentFrom(loginA2)) + XCTAssertFalse(loginA1.applyDeltas(a1a3).isSignificantlyDifferentFrom(loginA3)) + + let merged = Login.mergeDeltas(a: (loginA2.serverModified, a1a2), b: (loginA3.serverModified, a1a3)) + let mCCount = merged.commutative.count + let a2CCount = a1a2.commutative.count + let a3CCount = a1a3.commutative.count + XCTAssertEqual(mCCount, a2CCount + a3CCount) + + let mNCount = merged.nonCommutative.count + let a2NCount = a1a2.nonCommutative.count + let a3NCount = a1a3.nonCommutative.count + XCTAssertLessThanOrEqual(mNCount, a2NCount + a3NCount) + XCTAssertGreaterThanOrEqual(mNCount, max(a2NCount, a3NCount)) + + let mFCount = merged.nonConflicting.count + let a2FCount = a1a2.nonConflicting.count + let a3FCount = a1a3.nonConflicting.count + XCTAssertLessThanOrEqual(mFCount, a2FCount + a3FCount) + XCTAssertGreaterThanOrEqual(mFCount, max(a2FCount, a3FCount)) + + switch merged.commutative[0] { + case let .timesUsed(increment): + XCTAssertEqual(1, increment) + } + switch merged.commutative[1] { + case let .timesUsed(increment): + XCTAssertEqual(2, increment) + } + + switch merged.nonCommutative[0] { + case let .password(to): + XCTAssertEqual("something else", to) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + switch merged.nonCommutative[1] { + case let .formSubmitURL(to): + XCTAssertNil(to) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + switch merged.nonCommutative[2] { + case let .timeLastUsed(to): + XCTAssertEqual(to, 1250) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + switch merged.nonCommutative[3] { + case let .timePasswordChanged(to): + XCTAssertEqual(to, 1250) + break + default: + XCTFail("Unexpected non-commutative login field.") + } + + // Applying the merged deltas gives us the expected login. + let expected = Login(guid: guidA, hostname: "http://example.com", username: "username", password: "something else") + expected.timeCreated = 1200 + expected.timeLastUsed = 1250 + expected.timePasswordChanged = 1250 + expected.formSubmitURL = nil + expected.timesUsed = 6 + + let applied = loginA1.applyDeltas(merged) + XCTAssertFalse(applied.isSignificantlyDifferentFrom(expected)) + XCTAssertFalse(expected.isSignificantlyDifferentFrom(applied)) + } + + func testLoginsIsSynced() { + let loginA = Login.createWithHostname("alphabet.com", username: "username1", password: "password1") + let serverLoginA = ServerLogin(guid: loginA.guid, hostname: "alpha.com", username: "username1", password: "password1", modified: Date.now()) + + XCTAssertFalse(logins.hasSyncedLogins().value.successValue ?? true) + let _ = logins.addLogin(loginA).value + XCTAssertFalse(logins.hasSyncedLogins().value.successValue ?? false) + let _ = logins.applyChangedLogin(serverLoginA).value + XCTAssertTrue(logins.hasSyncedLogins().value.successValue ?? false) + } +} diff --git a/mobile/ios/StorageTests/TestSQLiteBookmarks.swift b/mobile/ios/StorageTests/TestSQLiteBookmarks.swift new file mode 100644 index 0000000000..89e7834b26 --- /dev/null +++ b/mobile/ios/StorageTests/TestSQLiteBookmarks.swift @@ -0,0 +1,1150 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage + +import XCTest + +private func getBrowserDB(_ filename: String, files: FileAccessor) -> BrowserDB? { + return BrowserDB(filename: filename, schema: BrowserSchema(), files: files) +} + +extension SQLiteBookmarks { + var testFactory: SQLiteBookmarksModelFactory { + return SQLiteBookmarksModelFactory(bookmarks: self, direction: .local) + } +} + +// MARK: - Tests. + +class TestTruncation: XCTestCase { + func testTruncate() { + let a = "🤠" + let b = "abcdefghi" + let c = "" + XCTAssertEqual(a.truncateToUTF8ByteCount(1), "") + XCTAssertEqual(a.truncateToUTF8ByteCount(4), a) + XCTAssertEqual(a.truncateToUTF8ByteCount(16), a) + + XCTAssertEqual(b.truncateToUTF8ByteCount(16), b) + XCTAssertEqual(b.truncateToUTF8ByteCount(5), "abcde") + XCTAssertEqual(b.truncateToUTF8ByteCount(0), "") + XCTAssertEqual(c.truncateToUTF8ByteCount(1), c) + XCTAssertEqual(c.truncateToUTF8ByteCount(4), c) + } +} + +class BrowserDBV15: Schema { + var name: String = "BROWSER" + var version: Int = 15 + + func getHistoryTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS history (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + // Not null, but the value might be replaced by the server's. + "url TEXT UNIQUE, " + // May only be null for deleted records. + "title TEXT NOT NULL, " + + "server_modified INTEGER, " + // Can be null. Integer milliseconds. + "local_modified INTEGER, " + // Can be null. Client clock. In extremis only. + "is_deleted TINYINT NOT NULL, " + // Boolean. Locally deleted. + "should_upload TINYINT NOT NULL, " + // Boolean. Set when changed or visits added. + "domain_id INTEGER REFERENCES \(TableDomains)(id) ON DELETE CASCADE, " + + "CONSTRAINT urlOrDeleted CHECK (url IS NOT NULL OR is_deleted = 1)" + + ")" + } + + func getDomainsTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableDomains) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "domain TEXT NOT NULL UNIQUE, " + + "showOnTopSites TINYINT NOT NULL DEFAULT 1" + + ")" + } + + func getQueueTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableQueuedTabs) (" + + "url TEXT NOT NULL UNIQUE, " + + "title TEXT" + + ") " + } + + func getVisitsTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableVisits) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES history(id) ON DELETE CASCADE, " + + "date REAL NOT NULL, " + // Microseconds since epoch. + "type INTEGER NOT NULL, " + + "is_local TINYINT NOT NULL, " + // Some visits are local. Some are remote ('mirrored'). This boolean flag is the split. + "UNIQUE (siteID, date, type) " + + ") " + } + + func getFaviconsTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS favicons (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "url TEXT NOT NULL UNIQUE, " + + "width INTEGER, " + + "height INTEGER, " + + "type INTEGER NOT NULL, " + + "date REAL NOT NULL" + + ") " + } + + func getBookmarksTableCreationStringForTable(_ table: String, withAdditionalColumns: String="") -> String { + // The stupid absence of naming conventions here is thanks to pre-Sync Weave. Sorry. + // For now we have the simplest possible schema: everything in one. + let sql = + "CREATE TABLE IF NOT EXISTS \(table) " + + + // Shared fields. + "( id INTEGER PRIMARY KEY AUTOINCREMENT" + + ", guid TEXT NOT NULL UNIQUE" + + ", type TINYINT NOT NULL" + // Type enum. + + // Record/envelope metadata that'll allow us to do merges. + ", is_deleted TINYINT NOT NULL DEFAULT 0" + // Boolean + + ", parentid TEXT" + // GUID + ", parentName TEXT" + + + // Type-specific fields. These should be NOT NULL in many cases, but we're going + // for a sparse schema, so this'll do for now. Enforce these in the application code. + ", feedUri TEXT, siteUri TEXT" + // LIVEMARKS + ", pos INT" + // SEPARATORS + ", title TEXT, description TEXT" + // FOLDERS, BOOKMARKS, QUERIES + ", bmkUri TEXT, tags TEXT, keyword TEXT" + // BOOKMARKS, QUERIES + ", folderName TEXT, queryId TEXT" + // QUERIES + withAdditionalColumns + + ", CONSTRAINT parentidOrDeleted CHECK (parentid IS NOT NULL OR is_deleted = 1)" + + ", CONSTRAINT parentNameOrDeleted CHECK (parentName IS NOT NULL OR is_deleted = 1)" + + ")" + + return sql + } + + func getBookmarksStructureTableCreationStringForTable(_ table: String, referencingMirror mirror: String) -> String { + let sql = + "CREATE TABLE IF NOT EXISTS \(table) " + + "( parent TEXT NOT NULL REFERENCES \(mirror)(guid) ON DELETE CASCADE" + + ", child TEXT NOT NULL" + // Should be the GUID of a child. + ", idx INTEGER NOT NULL" + // Should advance from 0. + ")" + + return sql + } + + let iconColumns = ", faviconID INTEGER REFERENCES \(TableFavicons)(id) ON DELETE SET NULL" + let mirrorColumns = ", is_overridden TINYINT NOT NULL DEFAULT 0" + + let serverColumns = ", server_modified INTEGER NOT NULL" + // Milliseconds. + ", hasDupe TINYINT NOT NULL DEFAULT 0" // Boolean, 0 (false) if deleted. + + let localColumns = ", local_modified INTEGER" + // Can be null. Client clock. In extremis only. + ", sync_status TINYINT NOT NULL" // SyncStatus enum. Set when changed or created. + + func create(_ db: SQLiteDBConnection) -> Bool { + let bookmarksLocal = self.getBookmarksTableCreationStringForTable(TableBookmarksLocal, withAdditionalColumns: self.localColumns + self.iconColumns) + let bookmarksLocalStructure = self.getBookmarksStructureTableCreationStringForTable(TableBookmarksLocalStructure, referencingMirror: TableBookmarksLocal) + let bookmarksBuffer = getBookmarksTableCreationStringForTable(TableBookmarksBuffer, withAdditionalColumns: self.serverColumns) + let bookmarksBufferStructure = self.getBookmarksStructureTableCreationStringForTable(TableBookmarksBufferStructure, referencingMirror: TableBookmarksBuffer) + let bookmarksMirror = getBookmarksTableCreationStringForTable(TableBookmarksMirror, withAdditionalColumns: self.serverColumns + self.mirrorColumns + self.iconColumns) + let bookmarksMirrorStructure = self.getBookmarksStructureTableCreationStringForTable(TableBookmarksMirrorStructure, referencingMirror: TableBookmarksMirror) + + let stmts = [ + bookmarksLocal, + bookmarksLocalStructure, + bookmarksBuffer, + bookmarksBufferStructure, + bookmarksMirror, + bookmarksMirrorStructure, + self.getHistoryTableCreationString(), + self.getDomainsTableCreationString(), + self.getQueueTableCreationString(), + self.getVisitsTableCreationString(), + self.getFaviconsTableCreationString() + ] + do { + for sql in stmts { + try db.executeChange(sql, withArgs: nil) + } + } catch _ as NSError { + return false + } + return true + } + + func update(_ db: SQLiteDBConnection, from: Int) -> Bool { + // Do nothing + return false + } + + func drop(_ db: SQLiteDBConnection) -> Bool { + // Do nothing + return false + } + + +} + +class TestSQLiteBookmarks: XCTestCase { + let files = MockFiles() + + fileprivate func remove(_ path: String) { + do { + try self.files.remove(path) + } catch {} + } + + override func tearDown() { + self.remove("TSQLBtestBookmarks.db") + self.remove("TSQLBtestBufferStorage.db") + self.remove("TSQLBtestLocalAndMirror.db") + self.remove("TSQLBtestRecursiveAndURLDelete.db") + self.remove("TSQLBtestUnrooted.db") + self.remove("TSQLBtestTreeBuilding.db") + self.remove("TSQLBtestLocalBookmarksModifications.db") + self.remove("TSQLBtestApplyBufferUpdatedCompletionOp.db") + self.remove("TSQLBtestApplyRecordsPendingDeletions.db") + self.remove("TSQLBtestDBUpgradeBeforeDateAdded.db") + super.tearDown() + } + + func testDateAddedMigration() { + let schema = BrowserDBV15() + let destination = BrowserSchema() + var db = BrowserDB(filename: "TSQLBtestDBUpgradeBeforeDateAdded.db", schema: schema, files: files) + XCTAssertTrue(db.withConnection({ connection -> Int in + connection.version + }).value.successValue == schema.version, "Creating BrowserSchema beforeDateAdded") + db.forceClose() + + db = BrowserDB(filename: "TSQLBtestDBUpgradeBeforeDateAdded.db", schema: destination, files: files) + XCTAssertTrue(db.withConnection({ connection -> Int in + connection.version + }).value.successValue == destination.version, "Upgrading BrowserSchema to the latest version") + db.forceClose() + } + + func testBookmarks() { + guard let db = getBrowserDB("TSQLBtestBookmarks.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + let bookmarks = SQLiteBookmarks(db: db) + let factory = bookmarks.testFactory + + let url = "http://url1/" + let u = url.asURL! + + bookmarks.addToMobileBookmarks(u, title: "Title", favicon: nil).succeeded() + let model = factory.modelForFolder(BookmarkRoots.MobileFolderGUID).value.successValue + XCTAssertEqual((model?.current[0] as? BookmarkItem)?.url, url) + XCTAssertTrue(factory.isBookmarked(url).value.successValue ?? false) + factory.removeByURL("").succeeded() + + // Grab that GUID and move it into desktop bookmarks. + let guid = (model?.current[0] as! BookmarkItem).guid + + // Desktop bookmarks. + XCTAssertFalse(factory.hasDesktopBookmarks().value.successValue ?? true) + let toolbar = BookmarkRoots.ToolbarFolderGUID + XCTAssertTrue(bookmarks.db.run([ + "UPDATE \(TableBookmarksLocal) SET parentid = '\(toolbar)' WHERE guid = '\(guid)'", + "UPDATE \(TableBookmarksLocalStructure) SET parent = '\(toolbar)' WHERE child = '\(guid)'", + ]).value.isSuccess) + XCTAssertTrue(factory.hasDesktopBookmarks().value.successValue ?? true) + } + + func testGetLocalBookmarksModifications() { + guard let db = getBrowserDB("TSQLBtestLocalBookmarksModifications.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + let bookmarks = SQLiteBookmarks(db: db) + + let localQuery = + "INSERT INTO \(TableBookmarksLocal) (guid, type, bmkUri, title, parentid, parentName, sync_status) " + + "VALUES " + + "(?, \(BookmarkNodeType.folder.rawValue), NULL, ?, ?, '', 2), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', 2), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', 2), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', 2), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', 0), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', 2), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', 2), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', 2) " + + let localArgs: Args = [ + "folder123", "123 (nok)", BookmarkRoots.MobileFolderGUID, + "bookmark123", "http://example.org/1", "Bookmark in folder 123 (nok)", "folder123", + "bookmark_other_folder", "http://example.org/2", "Bookmark in another folder (nok)", BookmarkRoots.ToolbarFolderGUID, + "bookmark_good_nonsynced", "http://example.org/3", "Bookmark 1 (ok)", BookmarkRoots.MobileFolderGUID, + "bookmark_good_synced", "http://example.org/4", "Bookmark 2 (nok)", BookmarkRoots.MobileFolderGUID, + "bookmark_duplicate_in_buffer", "http://example.org/5", "Bookmark in buffer(nok)", BookmarkRoots.MobileFolderGUID, + "bookmark_good_additional", "http://example.org/6", "Bookmark additional 1", BookmarkRoots.MobileFolderGUID, + "bookmark_good_additional_over_limit", "http://example.org/7", "Bookmark additional 2", BookmarkRoots.MobileFolderGUID, + ] + + let structureQuery = + "INSERT INTO \(TableBookmarksLocalStructure) (parent, child, idx) VALUES " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?) " + + let structureArgs: Args = [ + BookmarkRoots.MobileFolderGUID, "folder123", 0, + "folder123", "bookmark123", 0, + BookmarkRoots.ToolbarFolderGUID, "bookmark_other_folder", 0, + BookmarkRoots.MobileFolderGUID, "bookmark_good_nonsynced", 1, + BookmarkRoots.MobileFolderGUID, "bookmark_good_synced", 2, + BookmarkRoots.MobileFolderGUID, "bookmark_duplicate_in_buffer", 3, + BookmarkRoots.MobileFolderGUID, "bookmark_good_additional", 4, + BookmarkRoots.MobileFolderGUID, "bookmark_good_additional_over_limit", 5, + ] + + let bufferQuery = + "INSERT INTO \(TableBookmarksBuffer) (guid, type, bmkUri, title, parentid, parentName, server_modified) VALUES " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', ?), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', ?) " + + let bufferArgs: Args = [ + "bookmark_duplicate_in_buffer", "http://example.org/5", "Bookmark in buffer(nok)", BookmarkRoots.MobileFolderGUID, Date.now(), + "bookmark_to_delete", "http://example.org/delme", "Bookmark in buffer to delete(ok)", BookmarkRoots.MobileFolderGUID, 88888 + ] + + let bufferStructureQuery = + "INSERT INTO \(TableBookmarksBufferStructure) (parent, child, idx) VALUES " + + "(?, ?, ?), " + + "(?, ?, ?)" + + let bufferStructureArgs: Args = [ + "bookmark_duplicate_in_buffer", "bookmark_duplicate_in_buffer", 0, // It's its own parent because we are lazy. + "bookmark_to_delete", "bookmark_to_delete", 0 + ] + + let pendingDeletionsQuery = + "INSERT INTO \(TablePendingBookmarksDeletions) (id) VALUES " + + "(?)" + + let pendingDeletionsArgs: Args = [ + "bookmark_to_delete" + ] + + db.run([ + (sql: localQuery, args: localArgs), + (sql: structureQuery, args: structureArgs), + (sql: bufferQuery, args: bufferArgs), + (sql: bufferStructureQuery, args: bufferStructureArgs), + (sql: pendingDeletionsQuery, args: pendingDeletionsArgs), + ]).succeeded() + + var modifications = bookmarks.getLocalBookmarksModifications(limit: 3).value.successValue! + XCTAssertEqual(modifications.additions.count, 2) + XCTAssertEqual(modifications.additions.map { $0.guid }, ["bookmark_good_nonsynced", "bookmark_good_additional"]) + XCTAssertEqual(modifications.deletions.count, 1) + XCTAssertEqual(modifications.deletions, ["bookmark_to_delete"]) + + // Deletions are prioritized. + modifications = bookmarks.getLocalBookmarksModifications(limit: 1).value.successValue! + XCTAssertEqual(modifications.additions.count, 0) + XCTAssertEqual(modifications.deletions.count, 1) + XCTAssertEqual(modifications.deletions, ["bookmark_to_delete"]) + } + + func testApplyRecordsRemovesPendingDeletions() { + guard let db = getBrowserDB("TSQLBtestApplyRecordsPendingDeletions.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + let bookmarks = MergedSQLiteBookmarks(db: db) + + let bufferQuery = + "INSERT INTO \(TableBookmarksBuffer) (guid, type, bmkUri, title, parentid, parentName, server_modified) VALUES " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', ?), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', ?) " + + let bufferArgs: Args = [ + "bkm1", "http://example.org/1", "Bookmark 1", BookmarkRoots.MobileFolderGUID, Date.now(), + "bkm2", "http://example.org/2", "Bookmark 2", BookmarkRoots.MobileFolderGUID, Date.now() + ] + + let bufferStructureQuery = + "INSERT INTO \(TableBookmarksBufferStructure) (parent, child, idx) VALUES " + + "(?, ?, ?), " + + "(?, ?, ?)" + + let bufferStructureArgs: Args = [ + "bkm1", "bkm1", 0, // It's its own parent because we are lazy. + "bkm2", "bkm2", 0 + ] + + let pendingDeletionsQuery = + "INSERT INTO \(TablePendingBookmarksDeletions) (id) VALUES " + + "(?)" + + let pendingDeletionsArgs: Args = [ + "bkm2" + ] + + db.run([ + (sql: bufferQuery, args: bufferArgs), + (sql: bufferStructureQuery, args: bufferStructureArgs), + (sql: pendingDeletionsQuery, args: pendingDeletionsArgs), + ]).succeeded() + + let modified: [BookmarkMirrorItem] = [BookmarkMirrorItem.bookmark("bkm2", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: "bkm2", parentName: nil, title: "BKM 2", description: nil, URI: "https://test.com", tags: "", keyword: nil)] + bookmarks.applyRecords(modified).succeeded() + + XCTAssertTrue(db.queryReturnsNoResults("SELECT * FROM \(TablePendingBookmarksDeletions)").value.successValue!) + } + + func testApplyBufferUpdatedCompletionOp() { + guard let db = getBrowserDB("TSQLBtestApplyBufferUpdatedCompletionOp.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + let bookmarks = SQLiteBookmarks(db: db) + bookmarks.addToMobileBookmarks("http://example.org/1".asURL!, title: "Bookmark 1", favicon: nil).succeeded() + bookmarks.addToMobileBookmarks("http://example.org/2".asURL!, title: "Bookmark 2", favicon: nil).succeeded() + bookmarks.addToMobileBookmarks("http://example.org/3".asURL!, title: "Bookmark 3", favicon: nil).succeeded() + bookmarks.addToMobileBookmarks("http://example.org/4".asURL!, title: "Bookmark 4", favicon: nil).succeeded() + var localTree = bookmarks.treeForLocal().value.successValue! + var mobileFolderNode = localTree.find(BookmarkRoots.MobileFolderGUID)! + let localChildrenGUIDs = mobileFolderNode.children!.map { $0.recordGUID } + XCTAssertEqual(localChildrenGUIDs.count, 4) + let childrenGUIDsUploaded = localChildrenGUIDs.dropLast(1) + let childrenGUIDsFailed = localChildrenGUIDs.dropFirst(3) + + let bufferQuery = + "INSERT INTO \(TableBookmarksBuffer) (guid, type, bmkUri, title, parentid, parentName, server_modified) VALUES " + + "(?, \(BookmarkNodeType.folder.rawValue), NULL, ?, ?, '', ?), " + + "(?, \(BookmarkNodeType.folder.rawValue), NULL, ?, ?, '', ?), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', ?), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', ?), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', ?) " + + let bkmBufModified = Date.now() + let bufferArgs: Args = [ + BookmarkRoots.RootGUID, "", BookmarkRoots.RootGUID, 123, + BookmarkRoots.MobileFolderGUID, "Mobile Bookmarks", BookmarkRoots.RootGUID, 456, + "bkmbuf", "http://example.org/5", "Bookmark 5", BookmarkRoots.MobileFolderGUID, bkmBufModified, + "bkmtodelete", "http://example.org/to_delete", "Bookmark to delete", BookmarkRoots.MobileFolderGUID, 88888, + "bkmtodelete_uploadfail", "http://example.org/to_delete_updfail", "Bookmark to delete but upload failed", BookmarkRoots.MobileFolderGUID, 88888 + ] + + let bufferStructureQuery = + "INSERT INTO \(TableBookmarksBufferStructure) (parent, child, idx) VALUES " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?)" + + let bufferStructureArgs: Args = [ + BookmarkRoots.RootGUID, BookmarkRoots.RootGUID, 0, + BookmarkRoots.RootGUID, BookmarkRoots.MobileFolderGUID, 0, + BookmarkRoots.MobileFolderGUID, "bkmbuf", 0, + BookmarkRoots.MobileFolderGUID, "bkmtodelete", 1, + BookmarkRoots.MobileFolderGUID, "bkmtodelete_uploadfail", 2, + ] + + let pendingDeletionsQuery = + "INSERT INTO \(TablePendingBookmarksDeletions) (id) VALUES " + + "(?), " + + "(?)" + + let pendingDeletionsArgs: Args = [ + "bkmtodelete", "bkmtodelete_uploadfail" + ] + + db.run([ + (sql: bufferQuery, args: bufferArgs), + (sql: bufferStructureQuery, args: bufferStructureArgs), + (sql: pendingDeletionsQuery, args: pendingDeletionsArgs), + ]).succeeded() + + let mobileRoot = BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, + parentName: nil, title: "Mobile Bookmarks", description: nil, children: ["bkmbuf"] + childrenGUIDsUploaded) + let op = BufferUpdatedCompletionOp(bufferValuesToMoveFromLocal: Set(childrenGUIDsUploaded), deletedValues: Set(["bkmtodelete"]), mobileRoot: mobileRoot, modifiedTime: 123456) + + let mergedBookmarks = MergedSQLiteBookmarks(db: db) + mergedBookmarks.applyBufferUpdatedCompletionOp(op).succeeded() + + let rootFolder = mergedBookmarks.getBufferItemWithGUID(BookmarkRoots.RootGUID).value.successValue! + XCTAssertEqual(rootFolder.serverModified, 123) + let mobileFolder = mergedBookmarks.getBufferItemWithGUID(BookmarkRoots.MobileFolderGUID).value.successValue! + XCTAssertEqual(mobileFolder.serverModified, 123456) + let childrenGUIDs = mergedBookmarks.getBufferChildrenGUIDsForParent(BookmarkRoots.MobileFolderGUID).value.successValue! + XCTAssertEqual(childrenGUIDs, ["bkmbuf", "bkmtodelete_uploadfail"] + childrenGUIDsUploaded) + let children = mergedBookmarks.getBufferItemsWithGUIDs(["bkmbuf"] + childrenGUIDsUploaded).value.successValue! + for item in children.values { + XCTAssertEqual(item.serverModified, item.guid == "bkmbuf" ? bkmBufModified : 123456) + } + localTree = bookmarks.treeForLocal().value.successValue! + mobileFolderNode = localTree.find(BookmarkRoots.MobileFolderGUID)! + XCTAssertEqual(mobileFolderNode.children!.map { $0.recordGUID }, Array(childrenGUIDsFailed)) + } + + fileprivate func createStockMirrorTree(_ db: BrowserDB) { + // Set up a mirror tree. + let mirrorQuery = + "INSERT INTO \(TableBookmarksMirror) (guid, type, bmkUri, title, parentid, parentName, description, tags, keyword, is_overridden, server_modified, pos) " + + "VALUES " + + "(?, \(BookmarkNodeType.folder.rawValue), NULL, ?, ?, '', '', '', '', 0, \(Date.now()), NULL), " + + "(?, \(BookmarkNodeType.folder.rawValue), NULL, ?, ?, '', '', '', '', 0, \(Date.now()), NULL), " + + "(?, \(BookmarkNodeType.folder.rawValue), NULL, ?, ?, '', '', '', '', 0, \(Date.now()), NULL), " + + + "(?, \(BookmarkNodeType.separator.rawValue), NULL, NULL, ?, '', '', '', '', 0, \(Date.now()), 0), " + + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', '', '', '', 0, \(Date.now()), NULL), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', '', '', '', 0, \(Date.now()), NULL), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', '', '', '', 0, \(Date.now()), NULL), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', '', '', '', 0, \(Date.now()), NULL), " + + "(?, \(BookmarkNodeType.bookmark.rawValue), ?, ?, ?, '', '', '', '', 0, \(Date.now()), NULL) " + + let mirrorArgs: Args = [ + "folderAAAAAA", "AAA", BookmarkRoots.ToolbarFolderGUID, + "folderBBBBBB", "BBB", BookmarkRoots.MenuFolderGUID, + "folderCCCCCC", "CCC", "folderBBBBBB", + + "separator101", "folderAAAAAA", + + "bookmark1001", "http://example.org/1", "Bookmark 1", "folderAAAAAA", + "bookmark1002", "http://example.org/1", "Bookmark 1 Again", "folderAAAAAA", + "bookmark2001", "http://example.org/2", "Bookmark 2", "folderAAAAAA", + "bookmark2002", "http://example.org/2", "Bookmark 2 Again", "folderCCCCCC", + "bookmark3001", "http://example.org/3", "Bookmark 3", "folderBBBBBB", + ] + + let structureQuery = + "INSERT INTO \(TableBookmarksMirrorStructure) (parent, child, idx) VALUES " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?), " + + "(?, ?, ?) " + + let structureArgs: Args = [ + BookmarkRoots.ToolbarFolderGUID, "folderAAAAAA", 0, + BookmarkRoots.MenuFolderGUID, "folderBBBBBB", 0, + "folderAAAAAA", "bookmark1001", 0, + "folderAAAAAA", "separator101", 1, + "folderAAAAAA", "bookmark1002", 2, + "folderAAAAAA", "bookmark2001", 3, + "folderBBBBBB", "bookmark3001", 0, + "folderBBBBBB", "folderCCCCCC", 1, + "folderCCCCCC", "bookmark2002", 0, + ] + + db.moveLocalToMirrorForTesting() // So we have the roots. + db.run([ + (sql: mirrorQuery, args: mirrorArgs), + (sql: structureQuery, args: structureArgs), + ]).succeeded() + } + + fileprivate func isUnknown(_ folder: BookmarkTreeNode, withGUID: GUID) { + switch folder { + case .unknown(let guid): + XCTAssertEqual(withGUID, guid) + default: + XCTFail("Not an unknown with GUID \(withGUID).") + } + } + + fileprivate func isNonFolder(_ folder: BookmarkTreeNode, withGUID: GUID) { + switch folder { + case .nonFolder(let guid): + XCTAssertEqual(withGUID, guid) + default: + XCTFail("Not a non-folder with GUID \(withGUID).") + } + } + + fileprivate func isFolder(_ folder: BookmarkTreeNode, withGUID: GUID) { + switch folder { + case .folder(let record): + XCTAssertEqual(withGUID, record.guid) + default: + XCTFail("Not a folder with GUID \(withGUID).") + } + } + + fileprivate func areFolders(_ folders: [BookmarkTreeNode], withGUIDs: [GUID]) { + folders.zip(withGUIDs).forEach { (node, guid) in + self.isFolder(node, withGUID: guid) + } + } + + fileprivate func assertTreeIsEmpty(_ treeMaybe: Maybe) { + guard let tree = treeMaybe.successValue else { + XCTFail("Couldn't get tree!") + return + } + XCTAssertTrue(tree.orphans.isEmpty) + XCTAssertTrue(tree.deleted.isEmpty) + XCTAssertTrue(tree.isEmpty) + } + + fileprivate func assertTreeContainsOnlyRoots(_ treeMaybe: Maybe) { + guard let tree = treeMaybe.successValue else { + XCTFail("Couldn't get tree!") + return + } + + XCTAssertTrue(tree.orphans.isEmpty) + XCTAssertTrue(tree.deleted.isEmpty) + XCTAssertFalse(tree.isEmpty) + XCTAssertEqual(1, tree.subtrees.count) + if case let .folder(guid, children) = tree.subtrees[0] { + XCTAssertEqual(guid, "root________") + XCTAssertEqual(4, children.count) + children.forEach { child in + guard case let .folder(_, lower) = child, lower.isEmpty else { + XCTFail("Child \(child) wasn't empty!") + return + } + } + } else { + XCTFail("Tree didn't contain root.") + } + } + + func testUnrootedBufferRowsDontAppearInTrees() { + guard let db = getBrowserDB("TSQLBtestUnrooted.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + + let bookmarks = SQLiteBookmarks(db: db) + self.assertTreeContainsOnlyRoots(bookmarks.treeForMirror().value) + self.assertTreeIsEmpty(bookmarks.treeForBuffer().value) + self.assertTreeContainsOnlyRoots(bookmarks.treeForLocal().value) + + let args: Args = [ + "unrooted0001", BookmarkNodeType.bookmark.rawValue, 0, "somefolder01", "Some Folder", "I have no folder", "http://example.org/", + "rooted000002", BookmarkNodeType.bookmark.rawValue, 0, "somefolder02", "Some Other Folder", "I have a folder", "http://example.org/", + "somefolder02", BookmarkNodeType.folder.rawValue, 0, BookmarkRoots.MobileFolderGUID, "Mobile Bookmarks", "Some Other Folder", + ] + let now = Date.now() + let bufferSQL = + "INSERT INTO \(TableBookmarksBuffer) (server_modified, guid, type, date_added, is_deleted, parentid, parentName, title, bmkUri) VALUES " + + "(\(now), ?, ?, \(now), ?, ?, ?, ?, ?), " + + "(\(now), ?, ?, \(now), ?, ?, ?, ?, ?), " + + "(\(now), ?, ?, \(now), ?, ?, ?, ?, NULL)" + + let bufferStructureSQL = "INSERT INTO \(TableBookmarksBufferStructure) (parent, child, idx) VALUES ('somefolder02', 'rooted000002', 0)" + db.run(bufferSQL, withArgs: args).succeeded() + db.run(bufferStructureSQL).succeeded() + + let tree = bookmarks.treeForBuffer().value.successValue! + XCTAssertFalse(tree.orphans.contains("somefolder02")) // Folders are never orphans; they appear in subtrees instead. + XCTAssertFalse(tree.orphans.contains("rooted000002")) // This tree contains its parent, so it's not an orphan. + XCTAssertTrue(tree.orphans.contains("unrooted0001")) + XCTAssertEqual(Set(tree.subtrees.map { $0.recordGUID }), Set(["somefolder02"])) + } + + func testTreeBuilding() { + guard let db = getBrowserDB("TSQLBtestTreeBuilding.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + + let bookmarks = SQLiteBookmarks(db: db) + self.assertTreeContainsOnlyRoots(bookmarks.treeForMirror().value) + self.assertTreeIsEmpty(bookmarks.treeForBuffer().value) + self.assertTreeContainsOnlyRoots(bookmarks.treeForLocal().value) + + self.createStockMirrorTree(db) + self.assertTreeIsEmpty(bookmarks.treeForBuffer().value) + + // Local was emptied when we moved the roots to the mirror. + self.assertTreeIsEmpty(bookmarks.treeForLocal().value) + + guard let tree = bookmarks.treeForMirror().value.successValue else { + XCTFail("Couldn't get tree!") + return + } + + // Mirror is no longer empty. + XCTAssertFalse(tree.isEmpty) + + // There's one root. + XCTAssertEqual(1, tree.subtrees.count) + if case let .folder(guid, children) = tree.subtrees[0] { + XCTAssertEqual("root________", guid) + XCTAssertEqual(4, children.count) + self.areFolders(children, withGUIDs: BookmarkRoots.RootChildren) + } else { + XCTFail("Root should be a folder.") + } + + // Every GUID is in the tree's nodes. + ["folderAAAAAA", + "folderBBBBBB", + "folderCCCCCC"].forEach { + isFolder(tree.lookup[$0]!, withGUID: $0) + } + + ["separator101", + "bookmark1001", + "bookmark1002", + "bookmark2001", + "bookmark2002", + "bookmark3001"].forEach { + isNonFolder(tree.lookup[$0]!, withGUID: $0) + } + + let expectedCount = + BookmarkRoots.RootChildren.count + 1 + // The roots. + 6 + // Non-folders. + 3 // Folders. + + XCTAssertEqual(expectedCount, tree.lookup.count) + + // There are no orphans and no deletions. + XCTAssertTrue(tree.orphans.isEmpty) + XCTAssertTrue(tree.deleted.isEmpty) + + // root________ + // menu________ + // folderBBBBBB + // bookmark3001 + if case let .folder(guidR, rootChildren) = tree.subtrees[0] { + XCTAssertEqual(guidR, "root________") + if case let .folder(guidM, menuChildren) = rootChildren[0] { + XCTAssertEqual(guidM, "menu________") + if case let .folder(guidB, bbbChildren) = menuChildren[0] { + XCTAssertEqual(guidB, "folderBBBBBB") + // BBB contains bookmark3001. + if case let .nonFolder(guidBM) = bbbChildren[0] { + XCTAssertEqual(guidBM, "bookmark3001") + } else { + XCTFail("First child of BBB should be bookmark3001.") + } + + // BBB contains folderCCCCCC. + if case let .folder(guidBF, _) = bbbChildren[1] { + XCTAssertEqual(guidBF, "folderCCCCCC") + } else { + XCTFail("Second child of BBB should be folderCCCCCC.") + } + } else { + XCTFail("First child of menu should be BBB.") + } + } else { + XCTFail("First child of root should be menu________") + } + } else { + XCTFail("First root should be root________") + } + + // Add a bookmark. It'll override the folder. + bookmarks.insertBookmark("https://foo.com/".asURL!, title: "Foo", favicon: nil, intoFolder: "folderBBBBBB", withTitle: "BBB").succeeded() + let newlyInserted = db.getRecordByURL("https://foo.com/", fromTable: TableBookmarksLocal).guid + + guard let local = bookmarks.treeForLocal().value.successValue else { + XCTFail("Couldn't get local tree!") + return + } + + XCTAssertFalse(local.isEmpty) + XCTAssertEqual(4, local.lookup.count) // Folder, new bookmark, original two children. + XCTAssertEqual(1, local.subtrees.count) + if case let .folder(guid, children) = local.subtrees[0] { + XCTAssertEqual("folderBBBBBB", guid) + + // We have shadows of the original two children. + XCTAssertEqual(3, children.count) + self.isUnknown(children[0], withGUID: "bookmark3001") + self.isUnknown(children[1], withGUID: "folderCCCCCC") + self.isNonFolder(children[2], withGUID: newlyInserted) + } else { + XCTFail("Root should be folderBBBBBB.") + } + + // Insert partial data into the buffer. + // We insert: + let bufferArgs: Args = [ + // * A folder whose parent isn't present in the structure. + "ihavenoparent", BookmarkNodeType.folder.rawValue, 0, "myparentnoexist", "No Exist", "No Parent", + // * A folder with no children. + "ihavenochildren", BookmarkNodeType.folder.rawValue, 0, "ihavenoparent", "No Parent", "No Children", + // * A folder that meets both criteria. + "xhavenoparent", BookmarkNodeType.folder.rawValue, 0, "myparentnoexist", "No Exist", "No Parent And No Children", + // * A changed bookmark with no parent. + "changedbookmark", BookmarkNodeType.bookmark.rawValue, 0, "folderCCCCCC", "CCC", "I changed", "http://change.org/", + // * A deleted record. + "iwasdeleted", BookmarkNodeType.bookmark.rawValue, + ] + + let now = Date.now() + let bufferSQL = "INSERT INTO \(TableBookmarksBuffer) (server_modified, guid, type, date_added, is_deleted, parentid, parentName, title, bmkUri) VALUES " + + "(\(now), ?, ?, \(now), ?, ?, ?, ?, NULL), " + + "(\(now), ?, ?, \(now), ?, ?, ?, ?, NULL), " + + "(\(now), ?, ?, \(now), ?, ?, ?, ?, NULL), " + + "(\(now), ?, ?, \(now), ?, ?, ?, ?, ?), " + + "(\(now), ?, ?, \(now), 1, NULL, NULL, NULL, NULL) " + + let bufferStructureSQL = "INSERT INTO \(TableBookmarksBufferStructure) (parent, child, idx) VALUES (?, ?, ?)" + let bufferStructureArgs: Args = ["ihavenoparent", "ihavenochildren", 0] + db.run([(bufferSQL, bufferArgs), (bufferStructureSQL, bufferStructureArgs)]).succeeded() + + // Now build the tree. + guard let partialBuffer = bookmarks.treeForBuffer().value.successValue else { + XCTFail("Couldn't get buffer tree!") + return + } + + XCTAssertEqual(partialBuffer.deleted, Set(["iwasdeleted"])) + XCTAssertEqual(partialBuffer.orphans, Set(["changedbookmark"])) + XCTAssertEqual(partialBuffer.subtreeGUIDs, Set(["ihavenoparent", "xhavenoparent"])) + if case let .folder(_, children) = partialBuffer.lookup["ihavenochildren"]! { + XCTAssertTrue(children.isEmpty) + } else { + XCTFail("Couldn't look up childless folder.") + } + } + + func testRecursiveAndURLDelete() { + guard let db = getBrowserDB("TSQLBtestRecursiveAndURLDelete.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + + let bookmarks = SQLiteBookmarks(db: db) + self.createStockMirrorTree(db) + + let menuOverridden = BookmarkRoots.MenuFolderGUID + XCTAssertFalse(db.isOverridden(menuOverridden) ?? true) + + func getMenuChildren() -> [GUID] { + return db.getChildrenOfFolder(BookmarkRoots.MenuFolderGUID) + } + + XCTAssertEqual(["folderBBBBBB"], getMenuChildren()) + + // Locally add an item to the menu. This'll override the menu folder. + bookmarks.insertBookmark(URL(string: "http://example.com/2")!, title: "Bookmark 2 added locally", favicon: nil, intoFolder: BookmarkRoots.MenuFolderGUID, withTitle: "Bookmarks Menu").succeeded() + + XCTAssertTrue(db.isOverridden(BookmarkRoots.MenuFolderGUID) ?? false) + + let menuChildrenBeforeRecursiveDelete = getMenuChildren() + XCTAssertEqual(2, menuChildrenBeforeRecursiveDelete.count) + XCTAssertEqual("folderBBBBBB", menuChildrenBeforeRecursiveDelete[0]) + + let locallyAddedBookmark2 = menuChildrenBeforeRecursiveDelete[1] + + // It's local, so it's not overridden. + // N.B., these tests all use XCTAssertEqual instead of XCTAssert{True,False} because + // the former plays well with optionals. + XCTAssertNil(db.isOverridden(locallyAddedBookmark2)) + XCTAssertEqual(false, db.isLocallyDeleted(locallyAddedBookmark2)) + + // Now let's delete folder B and check that things that weren't deleted now are. + XCTAssertEqual(false, db.isOverridden("folderBBBBBB")) + XCTAssertNil(db.isLocallyDeleted("folderBBBBBB")) + XCTAssertEqual(false, db.isOverridden("folderCCCCCC")) + XCTAssertNil(db.isLocallyDeleted("folderCCCCCC")) + XCTAssertEqual(false, db.isOverridden("bookmark2002")) + XCTAssertNil(db.isLocallyDeleted("bookmark2002")) + XCTAssertEqual(false, db.isOverridden("bookmark3001")) + XCTAssertNil(db.isLocallyDeleted("bookmark3001")) + + bookmarks.testFactory.removeByGUID("folderBBBBBB").succeeded() + + XCTAssertEqual(true, db.isOverridden("folderBBBBBB")) + XCTAssertEqual(true, db.isLocallyDeleted("folderBBBBBB")) + XCTAssertEqual(true, db.isOverridden("folderCCCCCC")) + XCTAssertEqual(true, db.isLocallyDeleted("folderCCCCCC")) + XCTAssertEqual(true, db.isOverridden("bookmark2002")) + XCTAssertEqual(true, db.isLocallyDeleted("bookmark2002")) + XCTAssertEqual(true, db.isOverridden("bookmark3001")) + XCTAssertEqual(true, db.isLocallyDeleted("bookmark3001")) + + // Still there. + XCTAssertNil(db.isOverridden(locallyAddedBookmark2)) + XCTAssertFalse(db.isLocallyDeleted(locallyAddedBookmark2) ?? true) + + let menuChildrenAfterRecursiveDelete = getMenuChildren() + XCTAssertEqual(1, menuChildrenAfterRecursiveDelete.count) + XCTAssertEqual(locallyAddedBookmark2, menuChildrenAfterRecursiveDelete[0]) + + // Now let's delete by URL. + XCTAssertEqual(false, db.isOverridden("bookmark1001")) + XCTAssertNil(db.isLocallyDeleted("bookmark1001")) + XCTAssertEqual(false, db.isOverridden("bookmark1002")) + XCTAssertNil(db.isLocallyDeleted("bookmark1002")) + + bookmarks.testFactory.removeByURL("http://example.org/1").succeeded() + + // To conclude, check the entire hierarchy. + // Menu: overridden, only the locally-added bookmark 2. + // B, 3001, C, 2002: locally deleted. + // A: overridden, children [separator101, 2001]. + // No bookmarks with URL /1. + XCTAssertEqual(true, db.isOverridden(BookmarkRoots.MenuFolderGUID)) + XCTAssertEqual(true, db.isOverridden("folderBBBBBB")) + XCTAssertEqual(true, db.isLocallyDeleted("folderBBBBBB")) + XCTAssertEqual(true, db.isOverridden("folderCCCCCC")) + XCTAssertEqual(true, db.isLocallyDeleted("folderCCCCCC")) + XCTAssertEqual(true, db.isOverridden("bookmark2002")) + XCTAssertEqual(true, db.isLocallyDeleted("bookmark2002")) + XCTAssertEqual(true, db.isOverridden("bookmark3001")) + XCTAssertEqual(true, db.isLocallyDeleted("bookmark3001")) + XCTAssertEqual(true, db.isOverridden("bookmark1001")) + XCTAssertEqual(true, db.isLocallyDeleted("bookmark1001")) + XCTAssertEqual(true, db.isOverridden("bookmark1002")) + XCTAssertEqual(true, db.isLocallyDeleted("bookmark1002")) + + let menuChildrenAfterURLDelete = getMenuChildren() + XCTAssertEqual(1, menuChildrenAfterURLDelete.count) + XCTAssertEqual(locallyAddedBookmark2, menuChildrenAfterURLDelete[0]) + + XCTAssertEqual(["separator101", "bookmark2001"], db.getChildrenOfFolder("folderAAAAAA")) + } + + func testLocalAndMirror() { + guard let db = getBrowserDB("TSQLBtestLocalAndMirror.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + + // Preconditions. + let rootGUIDs = [ + BookmarkRoots.RootGUID, + BookmarkRoots.MobileFolderGUID, + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + ] + + let positioned = [ + BookmarkRoots.MenuFolderGUID, + BookmarkRoots.ToolbarFolderGUID, + BookmarkRoots.UnfiledFolderGUID, + BookmarkRoots.MobileFolderGUID, + ] + + XCTAssertEqual(rootGUIDs, db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) ORDER BY id")) + XCTAssertEqual(positioned, db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure) ORDER BY idx")) + XCTAssertEqual([], db.getGUIDs("SELECT guid FROM \(TableBookmarksMirror)")) + XCTAssertEqual([], db.getGUIDs("SELECT child FROM \(TableBookmarksMirrorStructure)")) + + // Add a local bookmark. + let bookmarks = SQLiteBookmarks(db: db) + bookmarks.insertBookmark("http://example.org/".asURL!, title: "Example", favicon: nil, intoFolder: BookmarkRoots.MobileFolderGUID, withTitle: "The Mobile").succeeded() + + let rowA = db.getRecordByURL("http://example.org/", fromTable: TableBookmarksLocal) + XCTAssertEqual(rowA.bookmarkURI, "http://example.org/") + XCTAssertEqual(rowA.title, "Example") + XCTAssertEqual(rowA.parentName, "The Mobile") + XCTAssertEqual(rootGUIDs + [rowA.guid], db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) ORDER BY id")) + XCTAssertEqual([rowA.guid], db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + XCTAssertEqual(SyncStatus.new, db.getSyncStatusForGUID(rowA.guid)) + + // Add another. Order should be maintained. + bookmarks.insertBookmark("https://reddit.com/".asURL!, title: "Reddit", favicon: nil, intoFolder: BookmarkRoots.MobileFolderGUID, withTitle: "Mobile").succeeded() + + let rowB = db.getRecordByURL("https://reddit.com/", fromTable: TableBookmarksLocal) + XCTAssertEqual(rowB.bookmarkURI, "https://reddit.com/") + XCTAssertEqual(rowB.title, "Reddit") + XCTAssertEqual(rootGUIDs + [rowA.guid, rowB.guid], db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) ORDER BY id")) + XCTAssertEqual([rowA.guid, rowB.guid], db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + XCTAssertEqual(SyncStatus.new, db.getSyncStatusForGUID(rowA.guid)) + XCTAssertEqual(SyncStatus.new, db.getSyncStatusForGUID(rowB.guid)) + + // The indices should be 0, 1. + let positions = db.getPositionsForChildrenOfParent(BookmarkRoots.MobileFolderGUID, fromTable: TableBookmarksLocalStructure) + XCTAssertEqual(positions.count, 2) + XCTAssertEqual(positions[rowA.guid], 0) + XCTAssertEqual(positions[rowB.guid], 1) + + // Delete the first. sync_status was New, so the row was immediately deleted. + bookmarks.testFactory.removeByURL("http://example.org/").succeeded() + XCTAssertEqual(rootGUIDs + [rowB.guid], db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) ORDER BY id")) + XCTAssertEqual([rowB.guid], db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + let positionsAfterDelete = db.getPositionsForChildrenOfParent(BookmarkRoots.MobileFolderGUID, fromTable: TableBookmarksLocalStructure) + XCTAssertEqual(positionsAfterDelete.count, 1) + XCTAssertEqual(positionsAfterDelete[rowB.guid], 0) + + // Manually shuffle all of these into the mirror, as if we were fully synchronized. + db.moveLocalToMirrorForTesting() + XCTAssertEqual([], db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) ORDER BY id")) + XCTAssertEqual([], db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure)")) + XCTAssertEqual(rootGUIDs + [rowB.guid], db.getGUIDs("SELECT guid FROM \(TableBookmarksMirror) ORDER BY id")) + XCTAssertEqual([rowB.guid], db.getGUIDs("SELECT child FROM \(TableBookmarksMirrorStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + let mirrorPositions = db.getPositionsForChildrenOfParent(BookmarkRoots.MobileFolderGUID, fromTable: TableBookmarksMirrorStructure) + XCTAssertEqual(mirrorPositions.count, 1) + XCTAssertEqual(mirrorPositions[rowB.guid], 0) + + // Now insert a new mobile bookmark. + bookmarks.insertBookmark("https://letsencrypt.org/".asURL!, title: "Let's Encrypt", favicon: nil, intoFolder: BookmarkRoots.MobileFolderGUID, withTitle: "Mobile").succeeded() + + // The mobile bookmarks folder is overridden. + XCTAssertEqual(true, db.isOverridden(BookmarkRoots.MobileFolderGUID)) + + // Our previous inserted bookmark is not. + XCTAssertEqual(false, db.isOverridden(rowB.guid)) + + let rowC = db.getRecordByURL("https://letsencrypt.org/", fromTable: TableBookmarksLocal) + + // We have the old structure in the mirror. + XCTAssertEqual(rootGUIDs + [rowB.guid], db.getGUIDs("SELECT guid FROM \(TableBookmarksMirror) ORDER BY id")) + XCTAssertEqual([rowB.guid], db.getGUIDs("SELECT child FROM \(TableBookmarksMirrorStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + + // We have the new structure in the local table. + XCTAssertEqual(Set([BookmarkRoots.MobileFolderGUID, rowC.guid]), Set(db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) ORDER BY id"))) + XCTAssertEqual([rowB.guid, rowC.guid], db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + + // Parent is changed. The new record is New. The unmodified and deleted records aren't present. + XCTAssertNil(db.getSyncStatusForGUID(rowA.guid)) + XCTAssertNil(db.getSyncStatusForGUID(rowB.guid)) + XCTAssertEqual(SyncStatus.new, db.getSyncStatusForGUID(rowC.guid)) + XCTAssertEqual(SyncStatus.changed, db.getSyncStatusForGUID(BookmarkRoots.MobileFolderGUID)) + + // If we delete the old record, we mark it as changed, and it's no longer in the structure. + bookmarks.testFactory.removeByGUID(rowB.guid).succeeded() + XCTAssertEqual(SyncStatus.changed, db.getSyncStatusForGUID(rowB.guid)) + XCTAssertEqual([rowC.guid], db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + + // Add a duplicate to test multi-deletion (unstar). + bookmarks.insertBookmark("https://letsencrypt.org/".asURL!, title: "Let's Encrypt", favicon: nil, intoFolder: BookmarkRoots.MobileFolderGUID, withTitle: "Mobile").succeeded() + let guidD = db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx").last! + XCTAssertNotEqual(rowC.guid, guidD) + XCTAssertEqual(SyncStatus.new, db.getSyncStatusForGUID(guidD)) + XCTAssertEqual(SyncStatus.changed, db.getSyncStatusForGUID(BookmarkRoots.MobileFolderGUID)) + + // Delete by URL. + // If we delete the new records, they just go away -- there's no server version to delete. + bookmarks.testFactory.removeByURL(rowC.bookmarkURI!).succeeded() + XCTAssertNil(db.getSyncStatusForGUID(rowC.guid)) + XCTAssertNil(db.getSyncStatusForGUID(guidD)) + XCTAssertEqual([], db.getGUIDs("SELECT child FROM \(TableBookmarksLocalStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + + // The mirror structure is unchanged after all this. + XCTAssertEqual(rootGUIDs + [rowB.guid], db.getGUIDs("SELECT guid FROM \(TableBookmarksMirror) ORDER BY id")) + XCTAssertEqual([rowB.guid], db.getGUIDs("SELECT child FROM \(TableBookmarksMirrorStructure) WHERE parent = '\(BookmarkRoots.MobileFolderGUID)' ORDER BY idx")) + } + + /* + // This is dead test code after we eliminated the merged view. + // Expect this to be ported to reflect post-sync state. + func testBookmarkStructure() { + guard let db = getBrowserDB("TSQLBtestBufferStorage.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + let bookmarks = MergedSQLiteBookmarks(db: db) + + guard let model = bookmarks.modelForRoot().value.successValue else { + XCTFail("Unable to get root.") + return + } + let root = model.current + + // The root isn't useful. The merged bookmark implementation doesn't use it. + XCTAssertEqual(root.guid, BookmarkRoots.RootGUID) + XCTAssertEqual(0, root.count) + + // Specifically fetching the fake desktop folder works, though. + guard let desktopModel = bookmarks.modelForFolder(BookmarkRoots.FakeDesktopFolderGUID).value.successValue else { + XCTFail("Unable to get desktop bookmarks.") + return + } + + // It contains the toolbar. + let desktopFolder = desktopModel.current + XCTAssertEqual(desktopFolder.guid, BookmarkRoots.FakeDesktopFolderGUID) + XCTAssertEqual(1, desktopFolder.count) + + guard let toolbarModel = desktopModel.selectFolder(BookmarkRoots.ToolbarFolderGUID).value.successValue else { + XCTFail("Unable to get toolbar.") + return + } + + // The toolbar is the child, and it has the two bookmarks as entries. + let toolbarFolder = toolbarModel.current + XCTAssertEqual(toolbarFolder.guid, BookmarkRoots.ToolbarFolderGUID) + XCTAssertEqual(2, toolbarFolder.count) + + guard let first = toolbarModel.current[0] else { + XCTFail("Expected to get AAA.") + return + } + guard let second = toolbarModel.current[1] else { + XCTFail("Expected to get BBB.") + return + } + XCTAssertEqual(first.guid, "aaaaaaaaaaaa") + XCTAssertEqual(first.title, "AAA") + XCTAssertEqual((first as? BookmarkItem)?.url, "http://getfirefox.com") + XCTAssertEqual(second.guid, "bbbbbbbbbbbb") + XCTAssertEqual(second.title, "BBB") + XCTAssertEqual((second as? BookmarkItem)?.url, "http://getfirefox.com") + + let del: [BookmarkMirrorItem] = [BookmarkMirrorItem.deleted(BookmarkNodeType.Bookmark, guid: "aaaaaaaaaaaa", modified: Date.now())] + bookmarks.applyRecords(del, withMaxVars: 1) + + guard let newToolbar = bookmarks.modelForFolder(BookmarkRoots.ToolbarFolderGUID).value.successValue else { + XCTFail("Unable to get toolbar.") + return + } + XCTAssertEqual(newToolbar.current.count, 1) + XCTAssertEqual(newToolbar.current[0]?.guid, "bbbbbbbbbbbb") + } + */ + + func testBufferStorage() { + guard let db = getBrowserDB("TSQLBtestBufferStorage.db", files: self.files) else { + XCTFail("Unable to create browser DB.") + return + } + let bookmarks = SQLiteBookmarkBufferStorage(db: db) + + let record1 = BookmarkMirrorItem.bookmark("aaaaaaaaaaaa", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: "Bookmarks Toolbar", title: "AAA", description: "AAA desc", URI: "http://getfirefox.com", tags: "[]", keyword: nil) + let record2 = BookmarkMirrorItem.bookmark("bbbbbbbbbbbb", dateAdded: Date.now(), modified: Date.now() + 10, hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: "Bookmarks Toolbar", title: "BBB", description: "BBB desc", URI: "http://getfirefox.com", tags: "[]", keyword: nil) + let toolbar = BookmarkMirrorItem.folder("toolbar", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: "places", parentName: "", title: "Bookmarks Toolbar", description: "Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar", children: ["aaaaaaaaaaaa", "bbbbbbbbbbbb"]) + let recordsA: [BookmarkMirrorItem] = [record1, toolbar, record2] + bookmarks.applyRecords(recordsA, withMaxVars: 3).succeeded() + + // Insert mobile bookmarks as produced by Firefox 40-something on desktop. + // swiftlint:disable line_length + + let children = ["M87np9Vfh_2s", "-JxRyqNte-ue", "6lIQzUtbjE8O", "eOg3jPSslzXl", "1WJIi9EjQErp", "z5uRo45Rvfbd", "EK3lcNd0sUFN", "gFD3GTljgu12", "eRZGsbN1ew9-", "widfEdgGn9de", "l7eTOR4Uf6xq", "vPbxG-gpN4Rb", "4dwJ8CototFe", "zK-kw9Ii6ScW", "eDmDU-gtEFW6", "lKjqWQaL_syt", "ETVDvWgGT31Q", "3Z_bMIHPSZQ8", "Fqu4_bJOk7fT", "Uo_5K1QrA67j", "gDTXNg4m1AJZ", "zpds8P-9xews", "87zjNtVGPtEp", "ZJru8Sn3qhW7", "txVnzBBBOgLP", "JTnRqFaj_oNa", "soaMlfmM4kjR", "g8AcVBjo6IRf", "uPUDaiG4q637", "rfq2bUud_w4d", "XBGxsiuUG2UD", "-VQRnJlyAvMs", "6wu7TScKdTU7", "ZeFji2hLVpLj", "HpCn_TVizMWX", "IPR5HZwRdlwi", "00JFOGuWnhWB", "P1jb3qKt32Vg", "D6MQJ43V1Ir5", "qWSoXFteRfsq", "o2avfYqEdomL", "xRS0U0YnjK9G", "VgOgzE_xfP4w", "SwP3rMJGvoO3", "Hf2jEgI_-PWa", "AyhmBi7Cv598", "-PaMuzTJXxVk", "JMhYrg8SlY5K", "SQeySEjzyplL", "GTAwd2UkEQEe", "x3RsZj5Ilebr", "sRZWZqPi74FP", "amHR50TpygA6", "XSk782ceVNN6", "ipiMyYQzeypI", "ph2k3Nqfhau4", "m5JKC3hAEQ0H", "yTVerkmQbNxk", "7taA6FbbbUbH", "PZvpbSRuJLPs", "C8atoa25U94F", "KOfNJk_ISLc6", "Bt74lBG9tJq6", "BuHoY2rUhuKA", "XTmoWKnwfIPl", "ZATwa3oTD1m0", "e8TczN5It6Am", "6kCUYs8hQtKg", "jDD8s5aiKoex", "QmpmcrYwLU29", "nCRcekynuJ08", "resttaI4J9tu", "EKSX3HV55VU3", "2-yCz0EIsVls", "sSeeGw3VbBY-", "qfpCrU34w9y0", "RKDgzPWecD6m", "5SgXEKu_dICW", "R143WAeB5E5r", "8Ns4-NiKG62r", "4AHuZDvop5XX", "YCP1OsO1goFF", "CYYaU1mQ_N6t", "UGkzEOMK8cuU", "1RzZOarkzQBa", "qSW2Z3cZSI9c", "ooPlKEAfQsnn", "jIUScoKLiXQt", "bjNTKugzRRL1", "hR24ZVnHUZcs", "3j2IDAZgUyYi", "xnWcy-sQDJRu", "UCcgJqGk3bTV", "WSSRWeptH9tq", "4ugv47OGD2E2", "XboCZgUx-x3x", "HrmWqiqsuLrm", "OjdxvRJ3Jb6j"] + // swiftlint:enable line_length + + let mA = BookmarkMirrorItem.bookmark("jIUScoKLiXQt", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: "mobile", parentName: "mobile", title: "Join the Engineering Leisure Class — Medium", description: nil, URI: "https://medium.com/@chrisloer/join-the-engineering-leisure-class-b3083c09a78e", tags: "[]", keyword: nil) + + let mB = BookmarkMirrorItem.folder("UjAHxFOGEqU8", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: "places", parentName: "", title: "mobile", description: nil, children: children) + bookmarks.applyRecords([mA, mB]).succeeded() + + func childCount(_ parent: GUID) -> Int? { + let sql = "SELECT COUNT(*) AS childCount FROM \(TableBookmarksBufferStructure) WHERE parent = ?" + let args: Args = [parent] + return db.runQuery(sql, args: args, factory: { $0["childCount"] as! Int }).value.successValue?[0] + } + + // We have children. + XCTAssertEqual(children.count, childCount("UjAHxFOGEqU8")) + + // Insert an empty mobile bookmarks folder, so we can verify that the structure table is wiped. + let mBEmpty = BookmarkMirrorItem.folder("UjAHxFOGEqU8", dateAdded: Date.now(), modified: Date.now() + 1, hasDupe: false, parentID: "places", parentName: "", title: "mobile", description: nil, children: []) + bookmarks.applyRecords([mBEmpty]).succeeded() + + // We no longer have children. + XCTAssertEqual(0, childCount("UjAHxFOGEqU8")) + } +} diff --git a/mobile/ios/StorageTests/TestSQLiteHistory.swift b/mobile/ios/StorageTests/TestSQLiteHistory.swift new file mode 100644 index 0000000000..2ea7dbc9ac --- /dev/null +++ b/mobile/ios/StorageTests/TestSQLiteHistory.swift @@ -0,0 +1,1625 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage +import Deferred + +import XCTest + +let threeMonthsInMillis: UInt64 = 3 * 30 * 24 * 60 * 60 * 1000 +let threeMonthsInMicros: UInt64 = UInt64(threeMonthsInMillis) * UInt64(1000) + +// Start everything three months ago. +let baseInstantInMillis = Date.now() - threeMonthsInMillis +let baseInstantInMicros = Date.nowMicroseconds() - threeMonthsInMicros + +func advanceTimestamp(_ timestamp: Timestamp, by: Int) -> Timestamp { + return timestamp + UInt64(by) +} + +func advanceMicrosecondTimestamp(_ timestamp: MicrosecondTimestamp, by: Int) -> MicrosecondTimestamp { + return timestamp + UInt64(by) +} + +extension Site { + func asPlace() -> Place { + return Place(guid: self.guid!, url: self.url, title: self.title) + } +} + +class BaseHistoricalBrowserSchema: Schema { + var name: String { return "BROWSER" } + var version: Int { return -1 } + + func update(_ db: SQLiteDBConnection, from: Int) -> Bool { + fatalError("Should never be called.") + } + + func create(_ db: SQLiteDBConnection) -> Bool { + return false + } + + func drop(_ db: SQLiteDBConnection) -> Bool { + return false + } + + var supportsPartialIndices: Bool { + let v = sqlite3_libversion_number() + return v >= 3008000 // 3.8.0. + } + + let oldFaviconsSQL = + "CREATE TABLE IF NOT EXISTS favicons (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "url TEXT NOT NULL UNIQUE, " + + "width INTEGER, " + + "height INTEGER, " + + "type INTEGER NOT NULL, " + + "date REAL NOT NULL" + + ") " + + func run(_ db: SQLiteDBConnection, sql: String?, args: Args? = nil) -> Bool { + if let sql = sql { + do { + try db.executeChange(sql, withArgs: args) + } catch { + return false + } + } + + return true + } + + func run(_ db: SQLiteDBConnection, queries: [String?]) -> Bool { + for sql in queries { + if let sql = sql { + if !run(db, sql: sql) { + return false + } + } + } + return true + } + + func run(_ db: SQLiteDBConnection, queries: [String]) -> Bool { + for sql in queries { + if !run(db, sql: sql) { + return false + } + } + return true + } +} + +// Versions of BrowserSchema that we care about: +// v6, prior to 001c73ea1903c238be1340950770879b40c41732, July 2015. +// This is when we first started caring about database versions. +// +// v7, 81e22fa6f7446e27526a5a9e8f4623df159936c3. History tiles. +// +// v8, 02c08ddc6d805d853bbe053884725dc971ef37d7. Favicons. +// +// v10, 4428c7d181ff4779ab1efb39e857e41bdbf4de67. Mirroring. We skipped v9. +// +// These tests snapshot the table creation code at each of these points. + +class BrowserSchemaV6: BaseHistoricalBrowserSchema { + override var version: Int { return 6 } + + func prepopulateRootFolders(_ db: SQLiteDBConnection) -> Bool { + let type = BookmarkNodeType.folder.rawValue + let root = BookmarkRoots.RootID + + let titleMobile = NSLocalizedString("Mobile Bookmarks", tableName: "Storage", comment: "The title of the folder that contains mobile bookmarks. This should match bookmarks.folder.mobile.label on Android.") + let titleMenu = NSLocalizedString("Bookmarks Menu", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the menu. This should match bookmarks.folder.menu.label on Android.") + let titleToolbar = NSLocalizedString("Bookmarks Toolbar", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the toolbar. This should match bookmarks.folder.toolbar.label on Android.") + let titleUnsorted = NSLocalizedString("Unsorted Bookmarks", tableName: "Storage", comment: "The name of the folder that contains unsorted desktop bookmarks. This should match bookmarks.folder.unfiled.label on Android.") + + let args: Args = [ + root, BookmarkRoots.RootGUID, type, "Root", root, + BookmarkRoots.MobileID, BookmarkRoots.MobileFolderGUID, type, titleMobile, root, + BookmarkRoots.MenuID, BookmarkRoots.MenuFolderGUID, type, titleMenu, root, + BookmarkRoots.ToolbarID, BookmarkRoots.ToolbarFolderGUID, type, titleToolbar, root, + BookmarkRoots.UnfiledID, BookmarkRoots.UnfiledFolderGUID, type, titleUnsorted, root, + ] + + let sql = + "INSERT INTO bookmarks (id, guid, type, url, title, parent) VALUES " + + "(?, ?, ?, NULL, ?, ?), " + // Root + "(?, ?, ?, NULL, ?, ?), " + // Mobile + "(?, ?, ?, NULL, ?, ?), " + // Menu + "(?, ?, ?, NULL, ?, ?), " + // Toolbar + "(?, ?, ?, NULL, ?, ?) " // Unsorted + + return self.run(db, sql: sql, args: args) + } + + func CreateHistoryTable() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableHistory) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + // Not null, but the value might be replaced by the server's. + "url TEXT UNIQUE, " + // May only be null for deleted records. + "title TEXT NOT NULL, " + + "server_modified INTEGER, " + // Can be null. Integer milliseconds. + "local_modified INTEGER, " + // Can be null. Client clock. In extremis only. + "is_deleted TINYINT NOT NULL, " + // Boolean. Locally deleted. + "should_upload TINYINT NOT NULL, " + // Boolean. Set when changed or visits added. + "domain_id INTEGER REFERENCES \(TableDomains)(id) ON DELETE CASCADE, " + + "CONSTRAINT urlOrDeleted CHECK (url IS NOT NULL OR is_deleted = 1)" + + ")" + } + + func CreateDomainsTable() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableDomains) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "domain TEXT NOT NULL UNIQUE, " + + "showOnTopSites TINYINT NOT NULL DEFAULT 1" + + ")" + } + + func CreateQueueTable() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableQueuedTabs) (" + + "url TEXT NOT NULL UNIQUE, " + + "title TEXT" + + ") " + } + + override func create(_ db: SQLiteDBConnection) -> Bool { + let visits = + "CREATE TABLE IF NOT EXISTS \(TableVisits) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES \(TableHistory)(id) ON DELETE CASCADE, " + + "date REAL NOT NULL, " + // Microseconds since epoch. + "type INTEGER NOT NULL, " + + "is_local TINYINT NOT NULL, " + // Some visits are local. Some are remote ('mirrored'). This boolean flag is the split. + "UNIQUE (siteID, date, type) " + + ") " + + let indexShouldUpload: String + if self.supportsPartialIndices { + // There's no point tracking rows that are not flagged for upload. + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON \(TableHistory) (should_upload) WHERE should_upload = 1" + } else { + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON \(TableHistory) (should_upload)" + } + + let indexSiteIDDate = + "CREATE INDEX IF NOT EXISTS \(IndexVisitsSiteIDIsLocalDate) " + + "ON \(TableVisits) (siteID, is_local, date)" + + let faviconSites = + "CREATE TABLE IF NOT EXISTS \(TableFaviconSites) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES \(TableHistory)(id) ON DELETE CASCADE, " + + "faviconID INTEGER NOT NULL REFERENCES \(TableFavicons)(id) ON DELETE CASCADE, " + + "UNIQUE (siteID, faviconID) " + + ") " + + let widestFavicons = + "CREATE VIEW IF NOT EXISTS \(ViewWidestFaviconsForSites) AS " + + "SELECT " + + "\(TableFaviconSites).siteID AS siteID, " + + "\(TableFavicons).id AS iconID, " + + "\(TableFavicons).url AS iconURL, " + + "\(TableFavicons).date AS iconDate, " + + "\(TableFavicons).type AS iconType, " + + "MAX(\(TableFavicons).width) AS iconWidth " + + "FROM \(TableFaviconSites), \(TableFavicons) WHERE " + + "\(TableFaviconSites).faviconID = \(TableFavicons).id " + + "GROUP BY siteID " + + let historyIDsWithIcon = + "CREATE VIEW IF NOT EXISTS \(ViewHistoryIDsWithWidestFavicons) AS " + + "SELECT \(TableHistory).id AS id, " + + "iconID, iconURL, iconDate, iconType, iconWidth " + + "FROM \(TableHistory) " + + "LEFT OUTER JOIN " + + "\(ViewWidestFaviconsForSites) ON history.id = \(ViewWidestFaviconsForSites).siteID " + + let iconForURL = + "CREATE VIEW IF NOT EXISTS \(ViewIconForURL) AS " + + "SELECT history.url AS url, icons.iconID AS iconID FROM " + + "\(TableHistory), \(ViewWidestFaviconsForSites) AS icons WHERE " + + "\(TableHistory).id = icons.siteID " + + let bookmarks = + "CREATE TABLE IF NOT EXISTS bookmarks (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + + "type TINYINT NOT NULL, " + + "url TEXT, " + + "parent INTEGER REFERENCES bookmarks(id) NOT NULL, " + + "faviconID INTEGER REFERENCES favicons(id) ON DELETE SET NULL, " + + "title TEXT" + + ") " + + let queries = [ + // This used to be done by FaviconsTable. + self.oldFaviconsSQL, + CreateDomainsTable(), + CreateHistoryTable(), + visits, bookmarks, faviconSites, + indexShouldUpload, indexSiteIDDate, + widestFavicons, historyIDsWithIcon, iconForURL, + CreateQueueTable(), + ] + + return self.run(db, queries: queries) && + self.prepopulateRootFolders(db) + } +} + +class BrowserSchemaV7: BaseHistoricalBrowserSchema { + override var version: Int { return 7 } + + func prepopulateRootFolders(_ db: SQLiteDBConnection) -> Bool { + let type = BookmarkNodeType.folder.rawValue + let root = BookmarkRoots.RootID + + let titleMobile = NSLocalizedString("Mobile Bookmarks", tableName: "Storage", comment: "The title of the folder that contains mobile bookmarks. This should match bookmarks.folder.mobile.label on Android.") + let titleMenu = NSLocalizedString("Bookmarks Menu", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the menu. This should match bookmarks.folder.menu.label on Android.") + let titleToolbar = NSLocalizedString("Bookmarks Toolbar", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the toolbar. This should match bookmarks.folder.toolbar.label on Android.") + let titleUnsorted = NSLocalizedString("Unsorted Bookmarks", tableName: "Storage", comment: "The name of the folder that contains unsorted desktop bookmarks. This should match bookmarks.folder.unfiled.label on Android.") + + let args: Args = [ + root, BookmarkRoots.RootGUID, type, "Root", root, + BookmarkRoots.MobileID, BookmarkRoots.MobileFolderGUID, type, titleMobile, root, + BookmarkRoots.MenuID, BookmarkRoots.MenuFolderGUID, type, titleMenu, root, + BookmarkRoots.ToolbarID, BookmarkRoots.ToolbarFolderGUID, type, titleToolbar, root, + BookmarkRoots.UnfiledID, BookmarkRoots.UnfiledFolderGUID, type, titleUnsorted, root, + ] + + let sql = + "INSERT INTO bookmarks (id, guid, type, url, title, parent) VALUES " + + "(?, ?, ?, NULL, ?, ?), " + // Root + "(?, ?, ?, NULL, ?, ?), " + // Mobile + "(?, ?, ?, NULL, ?, ?), " + // Menu + "(?, ?, ?, NULL, ?, ?), " + // Toolbar + "(?, ?, ?, NULL, ?, ?) " // Unsorted + + return self.run(db, sql: sql, args: args) + } + + func getHistoryTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS history (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + // Not null, but the value might be replaced by the server's. + "url TEXT UNIQUE, " + // May only be null for deleted records. + "title TEXT NOT NULL, " + + "server_modified INTEGER, " + // Can be null. Integer milliseconds. + "local_modified INTEGER, " + // Can be null. Client clock. In extremis only. + "is_deleted TINYINT NOT NULL, " + // Boolean. Locally deleted. + "should_upload TINYINT NOT NULL, " + // Boolean. Set when changed or visits added. + "domain_id INTEGER REFERENCES \(TableDomains)(id) ON DELETE CASCADE, " + + "CONSTRAINT urlOrDeleted CHECK (url IS NOT NULL OR is_deleted = 1)" + + ")" + } + + func getDomainsTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableDomains) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "domain TEXT NOT NULL UNIQUE, " + + "showOnTopSites TINYINT NOT NULL DEFAULT 1" + + ")" + } + + func getQueueTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableQueuedTabs) (" + + "url TEXT NOT NULL UNIQUE, " + + "title TEXT" + + ") " + } + + override func create(_ db: SQLiteDBConnection) -> Bool { + // Right now we don't need to track per-visit deletions: Sync can't + // represent them! See Bug 1157553 Comment 6. + // We flip the should_upload flag on the history item when we add a visit. + // If we ever want to support logic like not bothering to sync if we added + // and then rapidly removed a visit, then we need an 'is_new' flag on each visit. + let visits = + "CREATE TABLE IF NOT EXISTS \(TableVisits) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES history(id) ON DELETE CASCADE, " + + "date REAL NOT NULL, " + // Microseconds since epoch. + "type INTEGER NOT NULL, " + + "is_local TINYINT NOT NULL, " + // Some visits are local. Some are remote ('mirrored'). This boolean flag is the split. + "UNIQUE (siteID, date, type) " + + ") " + + let indexShouldUpload: String + if self.supportsPartialIndices { + // There's no point tracking rows that are not flagged for upload. + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON history (should_upload) WHERE should_upload = 1" + } else { + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON history (should_upload)" + } + + let indexSiteIDDate = + "CREATE INDEX IF NOT EXISTS \(IndexVisitsSiteIDIsLocalDate) " + + "ON \(TableVisits) (siteID, is_local, date)" + + let faviconSites = + "CREATE TABLE IF NOT EXISTS \(TableFaviconSites) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES history(id) ON DELETE CASCADE, " + + "faviconID INTEGER NOT NULL REFERENCES favicons(id) ON DELETE CASCADE, " + + "UNIQUE (siteID, faviconID) " + + ") " + + let widestFavicons = + "CREATE VIEW IF NOT EXISTS \(ViewWidestFaviconsForSites) AS " + + "SELECT " + + "\(TableFaviconSites).siteID AS siteID, " + + "favicons.id AS iconID, " + + "favicons.url AS iconURL, " + + "favicons.date AS iconDate, " + + "favicons.type AS iconType, " + + "MAX(favicons.width) AS iconWidth " + + "FROM \(TableFaviconSites), favicons WHERE " + + "\(TableFaviconSites).faviconID = favicons.id " + + "GROUP BY siteID " + + let historyIDsWithIcon = + "CREATE VIEW IF NOT EXISTS \(ViewHistoryIDsWithWidestFavicons) AS " + + "SELECT history.id AS id, " + + "iconID, iconURL, iconDate, iconType, iconWidth " + + "FROM history " + + "LEFT OUTER JOIN " + + "\(ViewWidestFaviconsForSites) ON history.id = \(ViewWidestFaviconsForSites).siteID " + + let iconForURL = + "CREATE VIEW IF NOT EXISTS \(ViewIconForURL) AS " + + "SELECT history.url AS url, icons.iconID AS iconID FROM " + + "\(TableHistory), \(ViewWidestFaviconsForSites) AS icons WHERE " + + "\(TableHistory).id = icons.siteID " + + let bookmarks = + "CREATE TABLE IF NOT EXISTS bookmarks (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + + "type TINYINT NOT NULL, " + + "url TEXT, " + + "parent INTEGER REFERENCES bookmarks(id) NOT NULL, " + + "faviconID INTEGER REFERENCES favicons(id) ON DELETE SET NULL, " + + "title TEXT" + + ") " + + let queries = [ + // This used to be done by FaviconsTable. + self.oldFaviconsSQL, + getDomainsTableCreationString(), + getHistoryTableCreationString(), + visits, bookmarks, faviconSites, + indexShouldUpload, indexSiteIDDate, + widestFavicons, historyIDsWithIcon, iconForURL, + getQueueTableCreationString(), + ] + + return self.run(db, queries: queries) && + self.prepopulateRootFolders(db) + } +} + +class BrowserSchemaV8: BaseHistoricalBrowserSchema { + override var version: Int { return 8 } + + func prepopulateRootFolders(_ db: SQLiteDBConnection) -> Bool { + let type = BookmarkNodeType.folder.rawValue + let root = BookmarkRoots.RootID + + let titleMobile = NSLocalizedString("Mobile Bookmarks", tableName: "Storage", comment: "The title of the folder that contains mobile bookmarks. This should match bookmarks.folder.mobile.label on Android.") + let titleMenu = NSLocalizedString("Bookmarks Menu", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the menu. This should match bookmarks.folder.menu.label on Android.") + let titleToolbar = NSLocalizedString("Bookmarks Toolbar", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the toolbar. This should match bookmarks.folder.toolbar.label on Android.") + let titleUnsorted = NSLocalizedString("Unsorted Bookmarks", tableName: "Storage", comment: "The name of the folder that contains unsorted desktop bookmarks. This should match bookmarks.folder.unfiled.label on Android.") + + let args: Args = [ + root, BookmarkRoots.RootGUID, type, "Root", root, + BookmarkRoots.MobileID, BookmarkRoots.MobileFolderGUID, type, titleMobile, root, + BookmarkRoots.MenuID, BookmarkRoots.MenuFolderGUID, type, titleMenu, root, + BookmarkRoots.ToolbarID, BookmarkRoots.ToolbarFolderGUID, type, titleToolbar, root, + BookmarkRoots.UnfiledID, BookmarkRoots.UnfiledFolderGUID, type, titleUnsorted, root, + ] + + let sql = + "INSERT INTO bookmarks (id, guid, type, url, title, parent) VALUES " + + "(?, ?, ?, NULL, ?, ?), " + // Root + "(?, ?, ?, NULL, ?, ?), " + // Mobile + "(?, ?, ?, NULL, ?, ?), " + // Menu + "(?, ?, ?, NULL, ?, ?), " + // Toolbar + "(?, ?, ?, NULL, ?, ?) " // Unsorted + + return self.run(db, sql: sql, args: args) + } + + func getHistoryTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableHistory) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + // Not null, but the value might be replaced by the server's. + "url TEXT UNIQUE, " + // May only be null for deleted records. + "title TEXT NOT NULL, " + + "server_modified INTEGER, " + // Can be null. Integer milliseconds. + "local_modified INTEGER, " + // Can be null. Client clock. In extremis only. + "is_deleted TINYINT NOT NULL, " + // Boolean. Locally deleted. + "should_upload TINYINT NOT NULL, " + // Boolean. Set when changed or visits added. + "domain_id INTEGER REFERENCES \(TableDomains)(id) ON DELETE CASCADE, " + + "CONSTRAINT urlOrDeleted CHECK (url IS NOT NULL OR is_deleted = 1)" + + ")" + } + + func getDomainsTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableDomains) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "domain TEXT NOT NULL UNIQUE, " + + "showOnTopSites TINYINT NOT NULL DEFAULT 1" + + ")" + } + + func getQueueTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableQueuedTabs) (" + + "url TEXT NOT NULL UNIQUE, " + + "title TEXT" + + ") " + } + + override func create(_ db: SQLiteDBConnection) -> Bool { + let favicons = + "CREATE TABLE IF NOT EXISTS favicons (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "url TEXT NOT NULL UNIQUE, " + + "width INTEGER, " + + "height INTEGER, " + + "type INTEGER NOT NULL, " + + "date REAL NOT NULL" + + ") " + + // Right now we don't need to track per-visit deletions: Sync can't + // represent them! See Bug 1157553 Comment 6. + // We flip the should_upload flag on the history item when we add a visit. + // If we ever want to support logic like not bothering to sync if we added + // and then rapidly removed a visit, then we need an 'is_new' flag on each visit. + let visits = + "CREATE TABLE IF NOT EXISTS visits (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES history(id) ON DELETE CASCADE, " + + "date REAL NOT NULL, " + // Microseconds since epoch. + "type INTEGER NOT NULL, " + + "is_local TINYINT NOT NULL, " + // Some visits are local. Some are remote ('mirrored'). This boolean flag is the split. + "UNIQUE (siteID, date, type) " + + ") " + + let indexShouldUpload: String + if self.supportsPartialIndices { + // There's no point tracking rows that are not flagged for upload. + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON \(TableHistory) (should_upload) WHERE should_upload = 1" + } else { + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON \(TableHistory) (should_upload)" + } + + let indexSiteIDDate = + "CREATE INDEX IF NOT EXISTS \(IndexVisitsSiteIDIsLocalDate) " + + "ON \(TableVisits) (siteID, is_local, date)" + + let faviconSites = + "CREATE TABLE IF NOT EXISTS \(TableFaviconSites) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES history(id) ON DELETE CASCADE, " + + "faviconID INTEGER NOT NULL REFERENCES favicons(id) ON DELETE CASCADE, " + + "UNIQUE (siteID, faviconID) " + + ") " + + let widestFavicons = + "CREATE VIEW IF NOT EXISTS \(ViewWidestFaviconsForSites) AS " + + "SELECT " + + "\(TableFaviconSites).siteID AS siteID, " + + "favicons.id AS iconID, " + + "favicons.url AS iconURL, " + + "favicons.date AS iconDate, " + + "favicons.type AS iconType, " + + "MAX(favicons.width) AS iconWidth " + + "FROM \(TableFaviconSites), favicons WHERE " + + "\(TableFaviconSites).faviconID = favicons.id " + + "GROUP BY siteID " + + let historyIDsWithIcon = + "CREATE VIEW IF NOT EXISTS \(ViewHistoryIDsWithWidestFavicons) AS " + + "SELECT history.id AS id, " + + "iconID, iconURL, iconDate, iconType, iconWidth " + + "FROM history " + + "LEFT OUTER JOIN " + + "\(ViewWidestFaviconsForSites) ON history.id = \(ViewWidestFaviconsForSites).siteID " + + let iconForURL = + "CREATE VIEW IF NOT EXISTS \(ViewIconForURL) AS " + + "SELECT history.url AS url, icons.iconID AS iconID FROM " + + "history, \(ViewWidestFaviconsForSites) AS icons WHERE " + + "history.id = icons.siteID " + + let bookmarks = + "CREATE TABLE IF NOT EXISTS bookmarks (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + + "type TINYINT NOT NULL, " + + "url TEXT, " + + "parent INTEGER REFERENCES bookmarks(id) NOT NULL, " + + "faviconID INTEGER REFERENCES favicons(id) ON DELETE SET NULL, " + + "title TEXT" + + ") " + + let queries: [String] = [ + getDomainsTableCreationString(), + getHistoryTableCreationString(), + favicons, + visits, + bookmarks, + faviconSites, + indexShouldUpload, + indexSiteIDDate, + widestFavicons, + historyIDsWithIcon, + iconForURL, + getQueueTableCreationString(), + ] + + return self.run(db, queries: queries) && + self.prepopulateRootFolders(db) + } +} + +class BrowserSchemaV10: BaseHistoricalBrowserSchema { + override var version: Int { return 10 } + + func prepopulateRootFolders(_ db: SQLiteDBConnection) -> Bool { + let type = BookmarkNodeType.folder.rawValue + let root = BookmarkRoots.RootID + + let titleMobile = NSLocalizedString("Mobile Bookmarks", tableName: "Storage", comment: "The title of the folder that contains mobile bookmarks. This should match bookmarks.folder.mobile.label on Android.") + let titleMenu = NSLocalizedString("Bookmarks Menu", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the menu. This should match bookmarks.folder.menu.label on Android.") + let titleToolbar = NSLocalizedString("Bookmarks Toolbar", tableName: "Storage", comment: "The name of the folder that contains desktop bookmarks in the toolbar. This should match bookmarks.folder.toolbar.label on Android.") + let titleUnsorted = NSLocalizedString("Unsorted Bookmarks", tableName: "Storage", comment: "The name of the folder that contains unsorted desktop bookmarks. This should match bookmarks.folder.unfiled.label on Android.") + + let args: Args = [ + root, BookmarkRoots.RootGUID, type, "Root", root, + BookmarkRoots.MobileID, BookmarkRoots.MobileFolderGUID, type, titleMobile, root, + BookmarkRoots.MenuID, BookmarkRoots.MenuFolderGUID, type, titleMenu, root, + BookmarkRoots.ToolbarID, BookmarkRoots.ToolbarFolderGUID, type, titleToolbar, root, + BookmarkRoots.UnfiledID, BookmarkRoots.UnfiledFolderGUID, type, titleUnsorted, root, + ] + + let sql = + "INSERT INTO bookmarks (id, guid, type, url, title, parent) VALUES " + + "(?, ?, ?, NULL, ?, ?), " + // Root + "(?, ?, ?, NULL, ?, ?), " + // Mobile + "(?, ?, ?, NULL, ?, ?), " + // Menu + "(?, ?, ?, NULL, ?, ?), " + // Toolbar + "(?, ?, ?, NULL, ?, ?) " // Unsorted + + return self.run(db, sql: sql, args: args) + } + + func getHistoryTableCreationString(forVersion version: Int = BrowserSchema.DefaultVersion) -> String { + return "CREATE TABLE IF NOT EXISTS history (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + // Not null, but the value might be replaced by the server's. + "url TEXT UNIQUE, " + // May only be null for deleted records. + "title TEXT NOT NULL, " + + "server_modified INTEGER, " + // Can be null. Integer milliseconds. + "local_modified INTEGER, " + // Can be null. Client clock. In extremis only. + "is_deleted TINYINT NOT NULL, " + // Boolean. Locally deleted. + "should_upload TINYINT NOT NULL, " + // Boolean. Set when changed or visits added. + "domain_id INTEGER REFERENCES \(TableDomains)(id) ON DELETE CASCADE, " + + "CONSTRAINT urlOrDeleted CHECK (url IS NOT NULL OR is_deleted = 1)" + + ")" + } + + func getDomainsTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableDomains) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "domain TEXT NOT NULL UNIQUE, " + + "showOnTopSites TINYINT NOT NULL DEFAULT 1" + + ")" + } + + func getQueueTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableQueuedTabs) (" + + "url TEXT NOT NULL UNIQUE, " + + "title TEXT" + + ") " + } + + func getBookmarksMirrorTableCreationString() -> String { + // The stupid absence of naming conventions here is thanks to pre-Sync Weave. Sorry. + // For now we have the simplest possible schema: everything in one. + let sql = + "CREATE TABLE IF NOT EXISTS \(TableBookmarksMirror) " + + + // Shared fields. + "( id INTEGER PRIMARY KEY AUTOINCREMENT" + + ", guid TEXT NOT NULL UNIQUE" + + ", type TINYINT NOT NULL" + // Type enum. TODO: BookmarkNodeType needs to be extended. + + // Record/envelope metadata that'll allow us to do merges. + ", server_modified INTEGER NOT NULL" + // Milliseconds. + ", is_deleted TINYINT NOT NULL DEFAULT 0" + // Boolean + + ", hasDupe TINYINT NOT NULL DEFAULT 0" + // Boolean, 0 (false) if deleted. + ", parentid TEXT" + // GUID + ", parentName TEXT" + + + // Type-specific fields. These should be NOT NULL in many cases, but we're going + // for a sparse schema, so this'll do for now. Enforce these in the application code. + ", feedUri TEXT, siteUri TEXT" + // LIVEMARKS + ", pos INT" + // SEPARATORS + ", title TEXT, description TEXT" + // FOLDERS, BOOKMARKS, QUERIES + ", bmkUri TEXT, tags TEXT, keyword TEXT" + // BOOKMARKS, QUERIES + ", folderName TEXT, queryId TEXT" + // QUERIES + ", CONSTRAINT parentidOrDeleted CHECK (parentid IS NOT NULL OR is_deleted = 1)" + + ", CONSTRAINT parentNameOrDeleted CHECK (parentName IS NOT NULL OR is_deleted = 1)" + + ")" + + return sql + } + + /** + * We need to explicitly store what's provided by the server, because we can't rely on + * referenced child nodes to exist yet! + */ + func getBookmarksMirrorStructureTableCreationString() -> String { + return "CREATE TABLE IF NOT EXISTS \(TableBookmarksMirrorStructure) " + + "( parent TEXT NOT NULL REFERENCES \(TableBookmarksMirror)(guid) ON DELETE CASCADE" + + ", child TEXT NOT NULL" + // Should be the GUID of a child. + ", idx INTEGER NOT NULL" + // Should advance from 0. + ")" + } + + override func create(_ db: SQLiteDBConnection) -> Bool { + let favicons = + "CREATE TABLE IF NOT EXISTS favicons (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "url TEXT NOT NULL UNIQUE, " + + "width INTEGER, " + + "height INTEGER, " + + "type INTEGER NOT NULL, " + + "date REAL NOT NULL" + + ") " + + // Right now we don't need to track per-visit deletions: Sync can't + // represent them! See Bug 1157553 Comment 6. + // We flip the should_upload flag on the history item when we add a visit. + // If we ever want to support logic like not bothering to sync if we added + // and then rapidly removed a visit, then we need an 'is_new' flag on each visit. + let visits = + "CREATE TABLE IF NOT EXISTS visits (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES history(id) ON DELETE CASCADE, " + + "date REAL NOT NULL, " + // Microseconds since epoch. + "type INTEGER NOT NULL, " + + "is_local TINYINT NOT NULL, " + // Some visits are local. Some are remote ('mirrored'). This boolean flag is the split. + "UNIQUE (siteID, date, type) " + + ") " + + let indexShouldUpload: String + if self.supportsPartialIndices { + // There's no point tracking rows that are not flagged for upload. + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON history (should_upload) WHERE should_upload = 1" + } else { + indexShouldUpload = + "CREATE INDEX IF NOT EXISTS \(IndexHistoryShouldUpload) " + + "ON history (should_upload)" + } + + let indexSiteIDDate = + "CREATE INDEX IF NOT EXISTS \(IndexVisitsSiteIDIsLocalDate) " + + "ON visits (siteID, is_local, date)" + + let faviconSites = + "CREATE TABLE IF NOT EXISTS \(TableFaviconSites) (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "siteID INTEGER NOT NULL REFERENCES history(id) ON DELETE CASCADE, " + + "faviconID INTEGER NOT NULL REFERENCES favicons(id) ON DELETE CASCADE, " + + "UNIQUE (siteID, faviconID) " + + ") " + + let widestFavicons = + "CREATE VIEW IF NOT EXISTS \(ViewWidestFaviconsForSites) AS " + + "SELECT " + + "\(TableFaviconSites).siteID AS siteID, " + + "favicons.id AS iconID, " + + "favicons.url AS iconURL, " + + "favicons.date AS iconDate, " + + "favicons.type AS iconType, " + + "MAX(favicons.width) AS iconWidth " + + "FROM \(TableFaviconSites), favicons WHERE " + + "\(TableFaviconSites).faviconID = favicons.id " + + "GROUP BY siteID " + + let historyIDsWithIcon = + "CREATE VIEW IF NOT EXISTS \(ViewHistoryIDsWithWidestFavicons) AS " + + "SELECT history.id AS id, " + + "iconID, iconURL, iconDate, iconType, iconWidth " + + "FROM history " + + "LEFT OUTER JOIN " + + "\(ViewWidestFaviconsForSites) ON history.id = \(ViewWidestFaviconsForSites).siteID " + + let iconForURL = + "CREATE VIEW IF NOT EXISTS \(ViewIconForURL) AS " + + "SELECT history.url AS url, icons.iconID AS iconID FROM " + + "history, \(ViewWidestFaviconsForSites) AS icons WHERE " + + "history.id = icons.siteID " + + let bookmarks = + "CREATE TABLE IF NOT EXISTS bookmarks (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "guid TEXT NOT NULL UNIQUE, " + + "type TINYINT NOT NULL, " + + "url TEXT, " + + "parent INTEGER REFERENCES bookmarks(id) NOT NULL, " + + "faviconID INTEGER REFERENCES favicons(id) ON DELETE SET NULL, " + + "title TEXT" + + ") " + + let bookmarksMirror = getBookmarksMirrorTableCreationString() + let bookmarksMirrorStructure = getBookmarksMirrorStructureTableCreationString() + + let indexStructureParentIdx = "CREATE INDEX IF NOT EXISTS \(IndexBookmarksMirrorStructureParentIdx) " + + "ON \(TableBookmarksMirrorStructure) (parent, idx)" + + let queries: [String] = [ + getDomainsTableCreationString(), + getHistoryTableCreationString(), + favicons, + visits, + bookmarks, + bookmarksMirror, + bookmarksMirrorStructure, + indexStructureParentIdx, + faviconSites, + indexShouldUpload, + indexSiteIDDate, + widestFavicons, + historyIDsWithIcon, + iconForURL, + getQueueTableCreationString(), + ] + + return self.run(db, queries: queries) && + self.prepopulateRootFolders(db) + } +} + +class TestSQLiteHistory: XCTestCase { + let files = MockFiles() + + fileprivate func deleteDatabases() { + for v in ["6", "7", "8", "10", "6-data"] { + do { + try files.remove("browser-v\(v).db") + } catch {} + } + do { + try files.remove("browser.db") + try files.remove("historysynced.db") + } catch {} + } + + override func tearDown() { + super.tearDown() + self.deleteDatabases() + } + + override func setUp() { + super.setUp() + + // Just in case tearDown didn't run or succeed last time! + self.deleteDatabases() + } + + // Test that our visit partitioning for frecency is correct. + func testHistoryLocalAndRemoteVisits() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + let siteL = Site(url: "http://url1/", title: "title local only") + let siteR = Site(url: "http://url2/", title: "title remote only") + let siteB = Site(url: "http://url3/", title: "title local and remote") + + siteL.guid = "locallocal12" + siteR.guid = "remoteremote" + siteB.guid = "bothbothboth" + + let siteVisitL1 = SiteVisit(site: siteL, date: baseInstantInMicros + 1000, type: VisitType.link) + let siteVisitL2 = SiteVisit(site: siteL, date: baseInstantInMicros + 2000, type: VisitType.link) + + let siteVisitR1 = SiteVisit(site: siteR, date: baseInstantInMicros + 1000, type: VisitType.link) + let siteVisitR2 = SiteVisit(site: siteR, date: baseInstantInMicros + 2000, type: VisitType.link) + let siteVisitR3 = SiteVisit(site: siteR, date: baseInstantInMicros + 3000, type: VisitType.link) + + let siteVisitBL1 = SiteVisit(site: siteB, date: baseInstantInMicros + 4000, type: VisitType.link) + let siteVisitBR1 = SiteVisit(site: siteB, date: baseInstantInMicros + 5000, type: VisitType.link) + + let deferred = + history.clearHistory() + >>> { history.addLocalVisit(siteVisitL1) } + >>> { history.addLocalVisit(siteVisitL2) } + >>> { history.addLocalVisit(siteVisitBL1) } + >>> { history.insertOrUpdatePlace(siteL.asPlace(), modified: baseInstantInMillis + 2) } + >>> { history.insertOrUpdatePlace(siteR.asPlace(), modified: baseInstantInMillis + 3) } + >>> { history.insertOrUpdatePlace(siteB.asPlace(), modified: baseInstantInMillis + 5) } + + // Do this step twice, so we exercise the dupe-visit handling. + >>> { history.storeRemoteVisits([siteVisitR1, siteVisitR2, siteVisitR3], forGUID: siteR.guid!) } + >>> { history.storeRemoteVisits([siteVisitR1, siteVisitR2, siteVisitR3], forGUID: siteR.guid!) } + + >>> { history.storeRemoteVisits([siteVisitBR1], forGUID: siteB.guid!) } + + >>> { + history.getFrecentHistory().getSites(whereURLContains: nil, historyLimit: 3, bookmarksLimit: 0) + >>== { (sites: Cursor) -> Success in + XCTAssertEqual(3, sites.count) + + // Two local visits beat a single later remote visit and one later local visit. + // Two local visits beat three remote visits. + XCTAssertEqual(siteL.guid!, sites[0]!.guid!) + XCTAssertEqual(siteB.guid!, sites[1]!.guid!) + XCTAssertEqual(siteR.guid!, sites[2]!.guid!) + return succeed() + } + + // This marks everything as modified so we can fetch it. + >>> history.onRemovedAccount + + // Now check that we have no duplicate visits. + >>> { history.getModifiedHistoryToUpload() + >>== { (places) -> Success in + if let (_, visits) = places.find({$0.0.guid == siteR.guid!}) { + XCTAssertEqual(3, visits.count) + } else { + XCTFail("Couldn't find site R.") + } + return succeed() + } + } + } + + XCTAssertTrue(deferred.value.isSuccess) + } + + func testUpgrades() { + let sources: [(Int, Schema)] = [ + (6, BrowserSchemaV6()), + (7, BrowserSchemaV7()), + (8, BrowserSchemaV8()), + (10, BrowserSchemaV10()), + ] + + let destination = BrowserSchema() + + for (version, schema) in sources { + var db = BrowserDB(filename: "browser-v\(version).db", schema: schema, files: files) + XCTAssertTrue(db.withConnection({ connection -> Int in + connection.version + }).value.successValue == schema.version, "Creating BrowserSchema at version \(version)") + db.forceClose() + + db = BrowserDB(filename: "browser-v\(version).db", schema: destination, files: files) + XCTAssertTrue(db.withConnection({ connection -> Int in + connection.version + }).value.successValue == destination.version, "Upgrading BrowserSchema from version \(version) to version \(schema.version)") + db.forceClose() + } + } + + func testUpgradesWithData() { + var db = BrowserDB(filename: "browser-v6-data.db", schema: BrowserSchemaV6(), files: files) + + // Insert some data. + let queries = [ + "INSERT INTO domains (id, domain) VALUES (1, 'example.com')", + "INSERT INTO history (id, guid, url, title, server_modified, local_modified, is_deleted, should_upload, domain_id) VALUES (5, 'guid', 'http://www.example.com', 'title', 5, 10, 0, 1, 1)", + "INSERT INTO visits (siteID, date, type, is_local) VALUES (5, 15, 1, 1)", + "INSERT INTO favicons (url, width, height, type, date) VALUES ('http://www.example.com/favicon.ico', 10, 10, 1, 20)", + "INSERT INTO favicon_sites (siteID, faviconID) VALUES (5, 1)", + "INSERT INTO bookmarks (guid, type, url, parent, faviconID, title) VALUES ('guid', 1, 'http://www.example.com', 0, 1, 'title')" + ] + + XCTAssertTrue(db.run(queries).value.isSuccess) + + // And we can upgrade to the current version. + db = BrowserDB(filename: "browser-v6-data.db", schema: BrowserSchema(), files: files) + + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + let results = history.getSitesByLastVisit(10).value.successValue + XCTAssertNotNil(results) + XCTAssertEqual(results![0]?.url, "http://www.example.com") + + db.forceClose() + } + + func testDomainUpgrade() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + let site = Site(url: "http://www.example.com/test1.1", title: "title one") + + // Insert something with an invalid domain ID. We have to manually do this since domains are usually hidden. + let insertDeferred = db.withConnection { connection -> Void in + try connection.executeChange("PRAGMA foreign_keys = OFF") + let insert = "INSERT INTO \(TableHistory) (guid, url, title, local_modified, is_deleted, should_upload, domain_id) VALUES (?, ?, ?, ?, ?, ?, ?)" + let args: Args = [Bytes.generateGUID(), site.url, site.title, Date.now(), 0, 0, -1] + try connection.executeChange(insert, withArgs: args) + } + + XCTAssertTrue(insertDeferred.value.isSuccess) + + // Now insert it again. This should update the domain. + history.addLocalVisit(SiteVisit(site: site, date: Date.nowMicroseconds(), type: VisitType.link)).succeeded() + + // domain_id isn't normally exposed, so we manually query to get it. + let resultsDeferred = db.withConnection { connection -> Cursor in + let sql = "SELECT domain_id FROM \(TableHistory) WHERE url = ?" + let args: Args = [site.url] + return connection.executeQuery(sql, factory: { $0[0] as? Int }, withArgs: args) + } + + let results = resultsDeferred.value.successValue! + let domain = results[0]! // Unwrap to get the first item from the cursor. + XCTAssertNil(domain) + } + + func testDomains() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + let initialGuid = Bytes.generateGUID() + let site11 = Site(url: "http://www.example.com/test1.1", title: "title one") + let site12 = Site(url: "http://www.example.com/test1.2", title: "title two") + let site13 = Place(guid: initialGuid, url: "http://www.example.com/test1.3", title: "title three") + let site3 = Site(url: "http://www.example2.com/test1", title: "title three") + let expectation = self.expectation(description: "First.") + + let clearTopSites = "DELETE FROM \(TableCachedTopSites)" + let updateTopSites: [(String, Args?)] = [(clearTopSites, nil), (history.getFrecentHistory().updateTopSitesCacheQuery())] + + func countTopSites() -> Deferred>> { + return db.runQuery("SELECT COUNT(*) from \(TableCachedTopSites)", args: nil, factory: { sdrow -> Int in + return sdrow[0] as? Int ?? 0 + }) + } + + history.clearHistory().bind({ success in + return all([history.addLocalVisit(SiteVisit(site: site11, date: Date.nowMicroseconds(), type: VisitType.link)), + history.addLocalVisit(SiteVisit(site: site12, date: Date.nowMicroseconds(), type: VisitType.link)), + history.addLocalVisit(SiteVisit(site: site3, date: Date.nowMicroseconds(), type: VisitType.link))]) + }).bind({ (results: [Maybe<()>]) in + return history.insertOrUpdatePlace(site13, modified: Date.nowMicroseconds()) + }).bind({ guid -> Success in + XCTAssertEqual(guid.successValue!, initialGuid, "Guid is correct") + return db.run(updateTopSites) + }).bind({ success in + XCTAssertTrue(success.isSuccess, "update was successful") + return countTopSites() + }).bind({ (count: Maybe>) -> Success in + XCTAssert(count.successValue![0] == 2, "2 sites returned") + return history.removeSiteFromTopSites(site11) + }).bind({ success -> Success in + XCTAssertTrue(success.isSuccess, "Remove was successful") + return db.run(updateTopSites) + }).bind({ success -> Deferred>> in + XCTAssertTrue(success.isSuccess, "update was successful") + return countTopSites() + }) + .upon({ (count: Maybe>) in + XCTAssert(count.successValue![0] == 1, "1 site returned") + expectation.fulfill() + }) + + waitForExpectations(timeout: 10.0) { error in + return + } + } + + func testHistoryIsSynced() { + let db = BrowserDB(filename: "historysynced.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + let initialGUID = Bytes.generateGUID() + let site = Place(guid: initialGUID, url: "http://www.example.com/test1.3", title: "title") + + XCTAssertFalse(history.hasSyncedHistory().value.successValue ?? true) + + XCTAssertTrue(history.insertOrUpdatePlace(site, modified: Date.now()).value.isSuccess) + + XCTAssertTrue(history.hasSyncedHistory().value.successValue ?? false) + } + + // This is a very basic test. Adds an entry, retrieves it, updates it, + // and then clears the database. + func testHistoryTable() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + let bookmarks = SQLiteBookmarks(db: db) + + let site1 = Site(url: "http://url1/", title: "title one") + let site1Changed = Site(url: "http://url1/", title: "title one alt") + + let siteVisit1 = SiteVisit(site: site1, date: Date.nowMicroseconds(), type: VisitType.link) + let siteVisit2 = SiteVisit(site: site1Changed, date: Date.nowMicroseconds() + 1000, type: VisitType.bookmark) + + let site2 = Site(url: "http://url2/", title: "title two") + let siteVisit3 = SiteVisit(site: site2, date: Date.nowMicroseconds() + 2000, type: VisitType.link) + + let expectation = self.expectation(description: "First.") + func done() -> Success { + expectation.fulfill() + return succeed() + } + + func checkSitesByFrecency(_ f: @escaping (Cursor) -> Success) -> () -> Success { + return { + history.getFrecentHistory().getSites(whereURLContains: nil, historyLimit: 10, bookmarksLimit: 0) + >>== f + } + } + + func checkSitesByDate(_ f: @escaping (Cursor) -> Success) -> () -> Success { + return { + history.getSitesByLastVisit(10) + >>== f + } + } + + func checkSitesWithFilter(_ filter: String, f: @escaping (Cursor) -> Success) -> () -> Success { + return { + history.getFrecentHistory().getSites(whereURLContains: filter, historyLimit: 10, bookmarksLimit: 0) + >>== f + } + } + + func checkDeletedCount(_ expected: Int) -> () -> Success { + return { + history.getDeletedHistoryToUpload() + >>== { guids in + XCTAssertEqual(expected, guids.count) + return succeed() + } + } + } + + history.clearHistory() + >>> { history.addLocalVisit(siteVisit1) } + >>> checkSitesByFrecency { (sites: Cursor) -> Success in + XCTAssertEqual(1, sites.count) + XCTAssertEqual(site1.title, sites[0]!.title) + XCTAssertEqual(site1.url, sites[0]!.url) + sites.close() + return succeed() + } + >>> { history.addLocalVisit(siteVisit2) } + >>> checkSitesByFrecency { (sites: Cursor) -> Success in + XCTAssertEqual(1, sites.count) + XCTAssertEqual(site1Changed.title, sites[0]!.title) + XCTAssertEqual(site1Changed.url, sites[0]!.url) + sites.close() + return succeed() + } + >>> { history.addLocalVisit(siteVisit3) } + >>> checkSitesByFrecency { (sites: Cursor) -> Success in + XCTAssertEqual(2, sites.count) + // They're in order of frecency. + XCTAssertEqual(site1Changed.title, sites[0]!.title) + XCTAssertEqual(site2.title, sites[1]!.title) + return succeed() + } + >>> checkSitesByDate { (sites: Cursor) -> Success in + XCTAssertEqual(2, sites.count) + // They're in order of date last visited. + let first = sites[0]! + let second = sites[1]! + XCTAssertEqual(site2.title, first.title) + XCTAssertEqual(site1Changed.title, second.title) + XCTAssertTrue(siteVisit3.date == first.latestVisit!.date) + return succeed() + } + >>> checkSitesWithFilter("two") { (sites: Cursor) -> Success in + XCTAssertEqual(1, sites.count) + let first = sites[0]! + XCTAssertEqual(site2.title, first.title) + return succeed() + } + >>> + checkDeletedCount(0) + >>> { history.removeHistoryForURL("http://url2/") } + >>> + checkDeletedCount(1) + >>> checkSitesByFrecency { (sites: Cursor) -> Success in + XCTAssertEqual(1, sites.count) + // They're in order of frecency. + XCTAssertEqual(site1Changed.title, sites[0]!.title) + return succeed() + } + >>> { history.clearHistory() } + >>> + checkDeletedCount(0) + >>> checkSitesByDate { (sites: Cursor) -> Success in + XCTAssertEqual(0, sites.count) + return succeed() + } + >>> checkSitesByFrecency { (sites: Cursor) -> Success in + XCTAssertEqual(0, sites.count) + return succeed() + } + >>> done + + waitForExpectations(timeout: 10.0) { error in + return + } + } + + func testFaviconTable() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + let bookmarks = SQLiteBookmarks(db: db) + + let expectation = self.expectation(description: "First.") + func done() -> Success { + expectation.fulfill() + return succeed() + } + + func updateFavicon() -> Success { + let fav = Favicon(url: "http://url2/", date: Date(), type: .icon) + fav.id = 1 + let site = Site(url: "http://bookmarkedurl/", title: "My Bookmark") + return history.addFavicon(fav, forSite: site) >>> succeed + } + + func checkFaviconForBookmarkIsNil() -> Success { + return bookmarks.bookmarksByURL("http://bookmarkedurl/".asURL!) >>== { results in + XCTAssertEqual(1, results.count) + XCTAssertNil(results[0]?.favicon) + return succeed() + } + } + + func checkFaviconWasSetForBookmark() -> Success { + return history.getFaviconsForBookmarkedURL("http://bookmarkedurl/") >>== { results in + XCTAssertEqual(1, results.count) + if let actualFaviconURL = results[0]??.url { + XCTAssertEqual("http://url2/", actualFaviconURL) + } + return succeed() + } + } + + func removeBookmark() -> Success { + return bookmarks.testFactory.removeByURL("http://bookmarkedurl/") + } + + func checkFaviconWasRemovedForBookmark() -> Success { + return history.getFaviconsForBookmarkedURL("http://bookmarkedurl/") >>== { results in + XCTAssertEqual(0, results.count) + return succeed() + } + } + + history.clearAllFavicons() + >>> bookmarks.clearBookmarks + >>> { bookmarks.addToMobileBookmarks("http://bookmarkedurl/".asURL!, title: "Title", favicon: nil) } + >>> checkFaviconForBookmarkIsNil + >>> updateFavicon + >>> checkFaviconWasSetForBookmark + >>> removeBookmark + >>> checkFaviconWasRemovedForBookmark + >>> done + + waitForExpectations(timeout: 10.0) { error in + return + } + } + + func testTopSitesFrecencyOrder() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + history.setTopSitesCacheSize(20) + history.clearTopSitesCache().succeeded() + history.clearHistory().succeeded() + + // Lets create some history. This will create 100 sites that will have 21 local and 21 remote visits + populateHistoryForFrecencyCalculations(history, siteCount: 100) + + // Create a new site thats for an existing domain but a different URL. + let site = Site(url: "http://s\(5)ite\(5).com/foo-different-url", title: "A \(5) different url") + site.guid = "abc\(5)defhi" + history.insertOrUpdatePlace(site.asPlace(), modified: baseInstantInMillis - 20000).succeeded() + // Don't give it any remote visits. But give it 100 local visits. This should be the new Topsite! + for i in 0...100 { + addVisitForSite(site, intoHistory: history, from: .local, atTime: advanceTimestamp(baseInstantInMicros, by: 1000000 * i)) + } + + let expectation = self.expectation(description: "First.") + func done() -> Success { + expectation.fulfill() + return succeed() + } + + func loadCache() -> Success { + return history.repopulate(invalidateTopSites: true, invalidateHighlights: true) >>> succeed + } + + func checkTopSitesReturnsResults() -> Success { + return history.getTopSitesWithLimit(20) >>== { topSites in + XCTAssertEqual(topSites.count, 20) + XCTAssertEqual(topSites[0]!.guid, "abc\(5)defhi") + return succeed() + } + } + + loadCache() + >>> checkTopSitesReturnsResults + >>> done + + waitForExpectations(timeout: 10.0) { error in + return + } + } + + func testTopSitesFiltersGoogle() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + history.setTopSitesCacheSize(20) + history.clearTopSitesCache().succeeded() + history.clearHistory().succeeded() + // Lets create some history. This will create 100 sites that will have 21 local and 21 remote visits + populateHistoryForFrecencyCalculations(history, siteCount: 100) + + func createTopSite(url: String, guid: String) { + let site = Site(url: url, title: "Hi") + site.guid = guid + history.insertOrUpdatePlace(site.asPlace(), modified: baseInstantInMillis - 20000).succeeded() + // Don't give it any remote visits. But give it 100 local visits. This should be the new Topsite! + for i in 0...100 { + addVisitForSite(site, intoHistory: history, from: .local, atTime: advanceTimestamp(baseInstantInMicros, by: 1000000 * i)) + } + } + + createTopSite(url: "http://google.com", guid: "abcgoogle") // should not be a topsite + createTopSite(url: "http://www.google.com", guid: "abcgoogle1") // should not be a topsite + createTopSite(url: "http://google.co.za", guid: "abcgoogleza") // should not be a topsite + createTopSite(url: "http://docs.google.com", guid: "docsgoogle") // should be a topsite + + let expectation = self.expectation(description: "First.") + func done() -> Success { + expectation.fulfill() + return succeed() + } + + func loadCache() -> Success { + return history.repopulate(invalidateTopSites: true, invalidateHighlights: true) >>> succeed + } + + func checkTopSitesReturnsResults() -> Success { + return history.getTopSitesWithLimit(20) >>== { topSites in + XCTAssertEqual(topSites[0]?.guid, "docsgoogle") // google docs should be the first topsite + // make sure all other google guids are not in the topsites array + topSites.forEach { + let guid: String = $0!.guid! // type checking is hard + XCTAssertNil(["abcgoogle", "abcgoogle1", "abcgoogleza"].index(of: guid)) + } + XCTAssertEqual(topSites.count, 20) + return succeed() + } + } + + loadCache() + >>> checkTopSitesReturnsResults + >>> done + + waitForExpectations(timeout: 10.0) { error in + return + } + } + + func testTopSitesCache() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + history.setTopSitesCacheSize(20) + history.clearTopSitesCache().succeeded() + history.clearHistory().succeeded() + + // Make sure that we get back the top sites + populateHistoryForFrecencyCalculations(history, siteCount: 100) + + // Add extra visits to the 5th site to bubble it to the top of the top sites cache + let site = Site(url: "http://s\(5)ite\(5).com/foo", title: "A \(5)") + site.guid = "abc\(5)def" + for i in 0...20 { + addVisitForSite(site, intoHistory: history, from: .local, atTime: advanceTimestamp(baseInstantInMicros, by: 1000000 * i)) + } + + let expectation = self.expectation(description: "First.") + func done() -> Success { + expectation.fulfill() + return succeed() + } + + func loadCache() -> Success { + return history.repopulate(invalidateTopSites: true, invalidateHighlights: true) >>> succeed + } + + func checkTopSitesReturnsResults() -> Success { + return history.getTopSitesWithLimit(20) >>== { topSites in + XCTAssertEqual(topSites.count, 20) + XCTAssertEqual(topSites[0]!.guid, "abc\(5)def") + return succeed() + } + } + + func invalidateIfNeededDoesntChangeResults() -> Success { + return history.repopulate(invalidateTopSites: true, invalidateHighlights: true) >>> { + return history.getTopSitesWithLimit(20) >>== { topSites in + XCTAssertEqual(topSites.count, 20) + XCTAssertEqual(topSites[0]!.guid, "abc\(5)def") + return succeed() + } + } + } + + func addVisitsToZerothSite() -> Success { + let site = Site(url: "http://s\(0)ite\(0).com/foo", title: "A \(0)") + site.guid = "abc\(0)def" + for i in 0...20 { + addVisitForSite(site, intoHistory: history, from: .local, atTime: advanceTimestamp(baseInstantInMicros, by: 1000000 * i)) + } + return succeed() + } + + func markInvalidation() -> Success { + history.setTopSitesNeedsInvalidation() + return succeed() + } + + func checkSitesInvalidate() -> Success { + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + + return history.getTopSitesWithLimit(20) >>== { topSites in + XCTAssertEqual(topSites.count, 20) + XCTAssertEqual(topSites[0]!.guid, "abc\(5)def") + XCTAssertEqual(topSites[1]!.guid, "abc\(0)def") + return succeed() + } + } + + loadCache() + >>> checkTopSitesReturnsResults + >>> invalidateIfNeededDoesntChangeResults + >>> markInvalidation + >>> addVisitsToZerothSite + >>> checkSitesInvalidate + >>> done + + waitForExpectations(timeout: 10.0) { error in + return + } + } + + func testPinnedTopSites() { + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + history.setTopSitesCacheSize(20) + history.clearTopSitesCache().succeeded() + history.clearHistory().succeeded() + + // add 2 sites to pinned topsite + // get pinned site and make sure it exists in the right order + // remove pinned sites + // make sure pinned sites dont exist + + // create pinned sites. + let site1 = Site(url: "http://s\(1)ite\(1).com/foo", title: "A \(1)") + site1.id = 1 + site1.guid = "abc\(1)def" + addVisitForSite(site1, intoHistory: history, from: .local, atTime: Date.now()) + let site2 = Site(url: "http://s\(2)ite\(2).com/foo", title: "A \(2)") + site2.id = 2 + site2.guid = "abc\(2)def" + addVisitForSite(site2, intoHistory: history, from: .local, atTime: Date.now()) + + + let expectation = self.expectation(description: "First.") + func done() -> Success { + expectation.fulfill() + return succeed() + } + + func addPinnedSites() -> Success { + return history.addPinnedTopSite(site1) >>== { + sleep(1) // Sleep to prevent intermittent issue with sorting on the timestamp + return history.addPinnedTopSite(site2) + } + } + + func checkPinnedSites() -> Success { + return history.getPinnedTopSites() >>== { pinnedSites in + XCTAssertEqual(pinnedSites.count, 2) + XCTAssertEqual(pinnedSites[0]!.url, site2.url) + XCTAssertEqual(pinnedSites[1]!.url, site1.url, "The older pinned site should be last") + return succeed() + } + } + + func removePinnedSites() -> Success { + return history.removeFromPinnedTopSites(site2) >>== { + return history.getPinnedTopSites() >>== { pinnedSites in + XCTAssertEqual(pinnedSites.count, 1, "There should only be one pinned site") + XCTAssertEqual(pinnedSites[0]!.url, site1.url, "Site2 should be the only pin left") + return succeed() + } + } + } + + func dupePinnedSite() -> Success { + return history.addPinnedTopSite(site1) >>== { + return history.getPinnedTopSites() >>== { pinnedSites in + XCTAssertEqual(pinnedSites.count, 1, "There should not be a dupe") + XCTAssertEqual(pinnedSites[0]!.url, site1.url, "Site2 should be the only pin left") + return succeed() + } + } + } + + func removeHistory() -> Success { + return history.clearHistory() >>== { + return history.getPinnedTopSites() >>== { pinnedSites in + XCTAssertEqual(pinnedSites.count, 1, "Pinned sites should exist after a history clear") + return succeed() + } + } + } + + addPinnedSites() + >>> checkPinnedSites + >>> removePinnedSites + >>> dupePinnedSite + >>> removeHistory + >>> done + + waitForExpectations(timeout: 10.0) { error in + return + } + + } +} + +class TestSQLiteHistoryTransactionUpdate: XCTestCase { + func testUpdateInTransaction() { + let files = MockFiles() + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + + history.clearHistory().succeeded() + let site = Site(url: "http://site/foo", title: "AA") + site.guid = "abcdefghiabc" + + history.insertOrUpdatePlace(site.asPlace(), modified: 1234567890).succeeded() + + let ts: MicrosecondTimestamp = baseInstantInMicros + let local = SiteVisit(site: site, date: ts, type: VisitType.link) + XCTAssertTrue(history.addLocalVisit(local).value.isSuccess) + } +} + +class TestSQLiteHistoryFilterSplitting: XCTestCase { + let history: SQLiteHistory = { + let files = MockFiles() + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let prefs = MockProfilePrefs() + return SQLiteHistory(db: db, prefs: prefs) + }() + + func testWithSingleWord() { + let (fragment, args) = computeWhereFragmentWithFilter("foo", perWordFragment: "?", perWordArgs: { [$0] }) + XCTAssertEqual(fragment, "?") + XCTAssert(stringArgsEqual(args, ["foo"])) + } + + func testWithIdenticalWords() { + let (fragment, args) = computeWhereFragmentWithFilter("foo fo foo", perWordFragment: "?", perWordArgs: { [$0] }) + XCTAssertEqual(fragment, "?") + XCTAssert(stringArgsEqual(args, ["foo"])) + } + + func testWithDistinctWords() { + let (fragment, args) = computeWhereFragmentWithFilter("foo bar", perWordFragment: "?", perWordArgs: { [$0] }) + XCTAssertEqual(fragment, "? AND ?") + XCTAssert(stringArgsEqual(args, ["foo", "bar"])) + } + + func testWithDistinctWordsAndWhitespace() { + let (fragment, args) = computeWhereFragmentWithFilter(" foo bar ", perWordFragment: "?", perWordArgs: { [$0] }) + XCTAssertEqual(fragment, "? AND ?") + XCTAssert(stringArgsEqual(args, ["foo", "bar"])) + } + + func testWithSubstrings() { + let (fragment, args) = computeWhereFragmentWithFilter("foo bar foobar", perWordFragment: "?", perWordArgs: { [$0] }) + XCTAssertEqual(fragment, "?") + XCTAssert(stringArgsEqual(args, ["foobar"])) + } + + func testWithSubstringsAndIdenticalWords() { + let (fragment, args) = computeWhereFragmentWithFilter("foo bar foobar foobar", perWordFragment: "?", perWordArgs: { [$0] }) + XCTAssertEqual(fragment, "?") + XCTAssert(stringArgsEqual(args, ["foobar"])) + } + + fileprivate func stringArgsEqual(_ one: Args, _ other: Args) -> Bool { + return one.elementsEqual(other, by: { (oneElement: Any?, otherElement: Any?) -> Bool in + return (oneElement as! String) == (otherElement as! String) + }) + } +} + +// MARK - Private Test Helper Methods + +enum VisitOrigin { + case local + case remote +} + +private func populateHistoryForFrecencyCalculations(_ history: SQLiteHistory, siteCount count: Int) { + for i in 0...count { + let site = Site(url: "http://s\(i)ite\(i).com/foo", title: "A \(i)") + site.guid = "abc\(i)def" + + let baseMillis: UInt64 = baseInstantInMillis - 20000 + history.insertOrUpdatePlace(site.asPlace(), modified: baseMillis).succeeded() + + for j in 0...20 { + let visitTime = advanceMicrosecondTimestamp(baseInstantInMicros, by: (1000000 * i) + (1000 * j)) + addVisitForSite(site, intoHistory: history, from: .local, atTime: visitTime) + addVisitForSite(site, intoHistory: history, from: .remote, atTime: visitTime - 100) + } + } +} + +func addVisitForSite(_ site: Site, intoHistory history: SQLiteHistory, from: VisitOrigin, atTime: MicrosecondTimestamp) { + let visit = SiteVisit(site: site, date: atTime, type: VisitType.link) + switch from { + case .local: + history.addLocalVisit(visit).succeeded() + case .remote: + history.storeRemoteVisits([visit], forGUID: site.guid!).succeeded() + } +} diff --git a/mobile/ios/StorageTests/TestSQLiteHistoryRecommendations.swift b/mobile/ios/StorageTests/TestSQLiteHistoryRecommendations.swift new file mode 100644 index 0000000000..706228f151 --- /dev/null +++ b/mobile/ios/StorageTests/TestSQLiteHistoryRecommendations.swift @@ -0,0 +1,333 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage +import Deferred +import SDWebImage + +import XCTest + +private let microsecondsPerMinute: UInt64 = 60_000_000 // 1000 * 1000 * 60 +private let oneHourInMicroseconds: UInt64 = 60 * microsecondsPerMinute +private let oneDayInMicroseconds: UInt64 = 24 * oneHourInMicroseconds + +class TestSQLiteHistoryRecommendations: XCTestCase { + let files = MockFiles() + + var db: BrowserDB! + var prefs: MockProfilePrefs! + var history: SQLiteHistory! + var bookmarks: MergedSQLiteBookmarks! + var metadata: SQLiteMetadata! + + override func setUp() { + super.setUp() + + db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + metadata = SQLiteMetadata(db: db) + prefs = MockProfilePrefs() + history = SQLiteHistory(db: db, prefs: prefs) + bookmarks = MergedSQLiteBookmarks(db: db) + } + + override func tearDown() { + // Clear out anything we might have changed on disk + history.clearHistory().succeeded() + db.run("DELETE FROM \(TablePageMetadata)").succeeded() + db.run("DELETE FROM \(TableHighlights)").succeeded() + db.run("DELETE FROM \(TableActivityStreamBlocklist)").succeeded() + + SDWebImageManager.shared().imageCache?.clearDisk() + SDWebImageManager.shared().imageCache?.clearMemory() + + super.tearDown() + } + + /* + * Verify that we return a non-recent history highlight if: + * + * 1. We haven't visited the site in the last 30 minutes + * 2. We've only visited the site less than or equal to 3 times + * 3. The site we visited has a non-empty title + * + */ + func testHistoryHighlights() { + let startTime = Date.nowMicroseconds() + let oneHourAgo = startTime - oneHourInMicroseconds + let fifteenMinutesAgo = startTime - 15 * microsecondsPerMinute + + /* + * Site A: 1 visit, 1 hour ago = highlight + * Site B: 1 visits, 15 minutes ago = non-highlight + * Site C: 3 visits, 1 hour ago = highlight + * Site D: 4 visits, 1 hour ago = non-highlight + */ + let siteA = Site(url: "http://siteA/", title: "A") + let siteB = Site(url: "http://siteB/", title: "B") + let siteC = Site(url: "http://siteC/", title: "C") + let siteD = Site(url: "http://siteD/", title: "D") + + let siteVisitA1 = SiteVisit(site: siteA, date: oneHourAgo, type: .link) + let siteVisitB1 = SiteVisit(site: siteB, date: fifteenMinutesAgo, type: .link) + + let siteVisitC1 = SiteVisit(site: siteC, date: oneHourAgo + 1, type: .link) + let siteVisitC2 = SiteVisit(site: siteC, date: oneHourAgo + 1000, type: .link) + let siteVisitC3 = SiteVisit(site: siteC, date: oneHourAgo + 2000, type: .link) + + let siteVisitD1 = SiteVisit(site: siteD, date: oneHourAgo, type: .link) + let siteVisitD2 = SiteVisit(site: siteD, date: oneHourAgo + 1000, type: .link) + let siteVisitD3 = SiteVisit(site: siteD, date: oneHourAgo + 2000, type: .link) + let siteVisitD4 = SiteVisit(site: siteD, date: oneHourAgo + 3000, type: .link) + + history.clearHistory().succeeded() + history.addLocalVisit(siteVisitA1).succeeded() + + history.addLocalVisit(siteVisitB1).succeeded() + + history.addLocalVisit(siteVisitC1).succeeded() + history.addLocalVisit(siteVisitC2).succeeded() + history.addLocalVisit(siteVisitC3).succeeded() + + history.addLocalVisit(siteVisitD1).succeeded() + history.addLocalVisit(siteVisitD2).succeeded() + history.addLocalVisit(siteVisitD3).succeeded() + history.addLocalVisit(siteVisitD4).succeeded() + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + let highlights = history.getHighlights().value.successValue! + XCTAssertEqual(highlights.count, 2) + XCTAssertEqual(highlights[0]!.title, "A") + XCTAssertEqual(highlights[1]!.title, "C") + } + + /* + * Verify that we do not return a highlight if + * its domain is in the blacklist + * + */ + func testBlacklistHighlights() { + let startTime = Date.nowMicroseconds() + let oneHourAgo = startTime - oneHourInMicroseconds + let fifteenMinutesAgo = startTime - 15 * microsecondsPerMinute + + /* + * Site A: 1 visit, 1 hour ago = highlight that is on the blacklist + * Site B: 1 visits, 15 minutes ago = non-highlight + * Site C: 3 visits, 1 hour ago = highlight that is on the blacklist + * Site D: 4 visits, 1 hour ago = non-highlight + */ + let siteA = Site(url: "http://www.google.com", title: "A") + let siteB = Site(url: "http://siteB/", title: "B") + let siteC = Site(url: "http://www.search.yahoo.com/", title: "C") + let siteD = Site(url: "http://siteD/", title: "D") + + let siteVisitA1 = SiteVisit(site: siteA, date: oneHourAgo, type: .link) + let siteVisitB1 = SiteVisit(site: siteB, date: fifteenMinutesAgo, type: .link) + + let siteVisitC1 = SiteVisit(site: siteC, date: oneHourAgo, type: .link) + let siteVisitC2 = SiteVisit(site: siteC, date: oneHourAgo + 1000, type: .link) + let siteVisitC3 = SiteVisit(site: siteC, date: oneHourAgo + 2000, type: .link) + + let siteVisitD1 = SiteVisit(site: siteD, date: oneHourAgo, type: .link) + let siteVisitD2 = SiteVisit(site: siteD, date: oneHourAgo + 1000, type: .link) + let siteVisitD3 = SiteVisit(site: siteD, date: oneHourAgo + 2000, type: .link) + let siteVisitD4 = SiteVisit(site: siteD, date: oneHourAgo + 3000, type: .link) + + history.clearHistory().succeeded() + history.addLocalVisit(siteVisitA1).succeeded() + + history.addLocalVisit(siteVisitB1).succeeded() + + history.addLocalVisit(siteVisitC1).succeeded() + history.addLocalVisit(siteVisitC2).succeeded() + history.addLocalVisit(siteVisitC3).succeeded() + + history.addLocalVisit(siteVisitD1).succeeded() + history.addLocalVisit(siteVisitD2).succeeded() + history.addLocalVisit(siteVisitD3).succeeded() + history.addLocalVisit(siteVisitD4).succeeded() + + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + let highlights = history.getHighlights().value.successValue! + XCTAssertEqual(highlights.count, 0) + } + + /* + * Verify that we return the most recent highlight per domain + */ + func testMostRecentUniqueDomainReturnedInHighlights() { + let startTime = Date.nowMicroseconds() + let oneHourAgo = startTime - oneHourInMicroseconds + let twoHoursAgo = startTime - 2 * oneHourInMicroseconds + + /* + * Site A: 1 visit, 1 hour ago = highlight + * Site C: 2 visits, 2 hours ago = highlight with the same domain + */ + let siteA = Site(url: "http://www.foo.com/", title: "A") + let siteC = Site(url: "http://m.foo.com/", title: "C") + + let siteVisitA1 = SiteVisit(site: siteA, date: oneHourAgo, type: .link) + + let siteVisitC1 = SiteVisit(site: siteC, date: twoHoursAgo, type: .link) + let siteVisitC2 = SiteVisit(site: siteC, date: twoHoursAgo + 1000, type: .link) + + history.clearHistory().succeeded() + history.addLocalVisit(siteVisitA1).succeeded() + + history.addLocalVisit(siteVisitC1).succeeded() + history.addLocalVisit(siteVisitC2).succeeded() + + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + let highlights = history.getHighlights().value.successValue! + XCTAssertEqual(highlights.count, 1) + XCTAssertEqual(highlights[0]!.title, "A") + } + + func testBookmarkHighlights() { + history.clearHistory().succeeded() + populateForRecommendationCalculations(history, bookmarks: bookmarks, metadata: metadata, historyCount: 10, bookmarkCount: 10) + + let sites = history.getRecentBookmarks(5).value.successValue?.asArray() + XCTAssertEqual(sites!.count, 5, "5 bookmarks should have been fetched") + sites!.forEach { XCTAssertEqual($0.guid, "bookmark-\(sites!.index(of: $0)!)"); XCTAssertEqual($0.metadata?.description, "Test Description") } + } + + func testMetadataReturnedInHighlights() { + let startTime = Date.nowMicroseconds() + let oneHourAgo = startTime - oneHourInMicroseconds + + let siteA = Site(url: "http://siteA.com", title: "Site A") + let siteB = Site(url: "http://siteB.com/", title: "Site B") + let siteC = Site(url: "http://siteC.com/", title: "Site C") + + let siteVisitA1 = SiteVisit(site: siteA, date: oneHourAgo, type: .link) + let siteVisitB1 = SiteVisit(site: siteB, date: oneHourAgo + 1000, type: .link) + + let siteVisitC1 = SiteVisit(site: siteC, date: oneHourAgo, type: .link) + let siteVisitC2 = SiteVisit(site: siteC, date: oneHourAgo + 1000, type: .link) + let siteVisitC3 = SiteVisit(site: siteC, date: oneHourAgo + 2000, type: .link) + + history.clearHistory().succeeded() + history.addLocalVisit(siteVisitA1).succeeded() + + history.addLocalVisit(siteVisitB1).succeeded() + + history.addLocalVisit(siteVisitC1).succeeded() + history.addLocalVisit(siteVisitC2).succeeded() + history.addLocalVisit(siteVisitC3).succeeded() + + // add metadata for 2 of the sites + let metadata = SQLiteMetadata(db: db) + let pageA = PageMetadata(id: nil, siteURL: siteA.url, mediaURL: "http://image.com", + title: siteA.title, description: "Test Description", type: nil, providerName: nil, mediaDataURI: nil, cacheImages: false) + metadata.storeMetadata(pageA, forPageURL: siteA.url.asURL!, expireAt: Date.now() + 3000).succeeded() + let pageB = PageMetadata(id: nil, siteURL: siteB.url, mediaURL: "http://image.com", + title: siteB.title, description: "Test Description", type: nil, providerName: nil, mediaDataURI: nil, cacheImages: false) + metadata.storeMetadata(pageB, forPageURL: siteB.url.asURL!, expireAt: Date.now() + 3000).succeeded() + let pageC = PageMetadata(id: nil, siteURL: siteC.url, mediaURL: "http://image.com", + title: siteC.title, description: "Test Description", type: nil, providerName: nil, mediaDataURI: nil, cacheImages: false) + metadata.storeMetadata(pageC, forPageURL: siteC.url.asURL!, expireAt: Date.now() + 3000).succeeded() + + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + let highlights = history.getHighlights().value.successValue! + XCTAssertEqual(highlights.count, 3) + + for highlight in highlights { + XCTAssertNotNil(highlight?.metadata) + XCTAssertNotNil(highlight?.metadata?.mediaURL) + } + } + + func testRemoveHighlightForURL() { + let startTime = Date.nowMicroseconds() + let oneHourAgo = startTime - oneHourInMicroseconds + + let siteA = Site(url: "http://siteA/", title: "A") + let siteVisitA1 = SiteVisit(site: siteA, date: oneHourAgo, type: .link) + + history.clearHistory().succeeded() + history.addLocalVisit(siteVisitA1).succeeded() + + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + var highlights = history.getHighlights().value.successValue! + XCTAssertEqual(highlights.count, 1) + XCTAssertEqual(highlights[0]!.title, "A") + + history.removeHighlightForURL(siteA.url).succeeded() + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + highlights = history.getHighlights().value.successValue! + XCTAssertEqual(highlights.count, 0) + } + + func testClearHighlightsCache() { + let startTime = Date.nowMicroseconds() + let oneHourAgo = startTime - oneHourInMicroseconds + + let siteA = Site(url: "http://siteA/", title: "A") + let siteVisitA1 = SiteVisit(site: siteA, date: oneHourAgo, type: .link) + + history.clearHistory().succeeded() + history.addLocalVisit(siteVisitA1).succeeded() + + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + let highlights = history.getHighlights().value.successValue! + XCTAssertEqual(highlights.count, 1) + XCTAssertEqual(highlights[0]!.title, "A") + } +} + +class TestSQLiteHistoryRecommendationsPerf: XCTestCase { + func testRecommendationPref() { + let files = MockFiles() + let db = BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files) + let metadata = SQLiteMetadata(db: db) + let prefs = MockProfilePrefs() + let history = SQLiteHistory(db: db, prefs: prefs) + let bookmarks = MergedSQLiteBookmarks(db: db) + + let count = 500 + + history.clearHistory().succeeded() + populateForRecommendationCalculations(history, bookmarks: bookmarks, metadata: metadata, historyCount: count, bookmarkCount: count) + self.measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true) { + for _ in 0...5 { + history.repopulate(invalidateTopSites: true, invalidateHighlights: true).succeeded() + } + self.stopMeasuring() + } + } +} + +private func populateForRecommendationCalculations(_ history: SQLiteHistory, bookmarks: MergedSQLiteBookmarks, metadata: SQLiteMetadata, historyCount: Int, bookmarkCount: Int) { + let baseMillis: UInt64 = baseInstantInMillis - 20000 + + for i in 0.. Deferred>> { + let sql = "SELECT * FROM \(TablePageMetadata)" + return db.runQuery(sql, args: nil, factory: pageMetadataFactory) +} + +private func removeAllMetadata(_ db: BrowserDB) -> Success { + return db.run("DELETE FROM \(TablePageMetadata)") +} + +private func pageMetadataFactory(_ row: SDRow) -> PageMetadata { + let id = row["id"] as! Int + let siteURL = row["site_url"] as! String + let mediaURL = row["media_url"] as? String + let title = row["title"] as? String + let description = row["description"] as? String + let type = row["type"] as? String + let providerName = row["provider_name"] as? String + return PageMetadata(id: id, siteURL: siteURL, mediaURL: mediaURL, title: title, + description: description, type: type, providerName: providerName, mediaDataURI: nil, cacheImages: false) +} diff --git a/mobile/ios/StorageTests/TestSQLiteRemoteClientsAndTabs.swift b/mobile/ios/StorageTests/TestSQLiteRemoteClientsAndTabs.swift new file mode 100644 index 0000000000..09f2d106f9 --- /dev/null +++ b/mobile/ios/StorageTests/TestSQLiteRemoteClientsAndTabs.swift @@ -0,0 +1,303 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage +import Deferred + +import XCTest + +open class MockRemoteClientsAndTabs: RemoteClientsAndTabs { + open let clientsAndTabs: [ClientAndTabs] + + public init() { + let now = Date.now() + let client1GUID = Bytes.generateGUID() + let client2GUID = Bytes.generateGUID() + let u11 = URL(string: "http://test.com/test1")! + let tab11 = RemoteTab(clientGUID: client1GUID, URL: u11, title: "Test 1", history: [ ], lastUsed: (now - OneMinuteInMilliseconds), icon: nil) + + let u12 = URL(string: "http://test.com/test2")! + let tab12 = RemoteTab(clientGUID: client1GUID, URL: u12, title: "Test 2", history: [], lastUsed: (now - OneHourInMilliseconds), icon: nil) + + let tab21 = RemoteTab(clientGUID: client2GUID, URL: u11, title: "Test 1", history: [], lastUsed: (now - OneDayInMilliseconds), icon: nil) + + let u22 = URL(string: "http://different.com/test2")! + let tab22 = RemoteTab(clientGUID: client2GUID, URL: u22, title: "Different Test 2", history: [], lastUsed: now + OneHourInMilliseconds, icon: nil) + + let client1 = RemoteClient(guid: client1GUID, name: "Test client 1", modified: (now - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: "55.0.1", fxaDeviceId: "fxa1") + let client2 = RemoteClient(guid: client2GUID, name: "Test client 2", modified: (now - OneHourInMilliseconds), type: "desktop", formfactor: "laptop", os: "Darwin", version: "55.0.1", fxaDeviceId: "fxa2") + + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (now - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: "55.0.1", fxaDeviceId: "fxa3") + let localUrl1 = URL(string: "http://test.com/testlocal1")! + let localTab1 = RemoteTab(clientGUID: nil, URL: localUrl1, title: "Local test 1", history: [], lastUsed: (now - OneMinuteInMilliseconds), icon: nil) + let localUrl2 = URL(string: "http://test.com/testlocal2")! + let localTab2 = RemoteTab(clientGUID: nil, URL: localUrl2, title: "Local test 2", history: [], lastUsed: (now - OneMinuteInMilliseconds), icon: nil) + + // Tabs are ordered most-recent-first. + self.clientsAndTabs = [ClientAndTabs(client: client1, tabs: [tab11, tab12]), + ClientAndTabs(client: client2, tabs: [tab22, tab21]), + ClientAndTabs(client: localClient, tabs: [localTab1, localTab2])] + } + + open func onRemovedAccount() -> Success { + return succeed() + } + + open func wipeClients() -> Success { + return succeed() + } + + open func wipeRemoteTabs() -> Deferred> { + return succeed() + } + + open func wipeTabs() -> Success { + return succeed() + } + + open func insertOrUpdateClients(_ clients: [RemoteClient]) -> Deferred> { + return deferMaybe(0) + } + + open func insertOrUpdateClient(_ client: RemoteClient) -> Deferred> { + return deferMaybe(0) + } + + open func insertOrUpdateTabs(_ tabs: [RemoteTab]) -> Deferred> { + return insertOrUpdateTabsForClientGUID(nil, tabs: [RemoteTab]()) + } + + open func insertOrUpdateTabsForClientGUID(_ clientGUID: String?, tabs: [RemoteTab]) -> Deferred> { + return deferMaybe(-1) + } + + open func getClientsAndTabs() -> Deferred> { + return deferMaybe(self.clientsAndTabs) + } + + open func getClients() -> Deferred> { + return deferMaybe(self.clientsAndTabs.map { $0.client }) + } + + public func getClient(guid: GUID) -> Deferred> { + return deferMaybe(self.clientsAndTabs.find { clientAndTabs in + return clientAndTabs.client.guid == guid + }?.client) + } + + public func getClient(fxaDeviceId: GUID) -> Deferred> { + return deferMaybe(self.clientsAndTabs.find { clientAndTabs in + return clientAndTabs.client.fxaDeviceId == fxaDeviceId + }?.client) + } + + open func getClientWithId(_ clientID: GUID) -> Deferred> { + return getClient(guid: clientID) + } + + open func getClientGUIDs() -> Deferred>> { + return deferMaybe(Set(optFilter(self.clientsAndTabs.map { $0.client.guid }))) + } + + open func getTabsForClientWithGUID(_ guid: GUID?) -> Deferred> { + return deferMaybe(optFilter(self.clientsAndTabs.map { $0.client.guid == guid ? $0.tabs : nil })[0]) + } + + open func deleteClient(guid: GUID) -> Success { return succeed() } + + open func deleteCommands() -> Success { return succeed() } + open func deleteCommands(_ clientGUID: GUID) -> Success { return succeed() } + + open func getCommands() -> Deferred> { return deferMaybe([GUID: [SyncCommand]]()) } + + open func insertCommand(_ command: SyncCommand, forClients clients: [RemoteClient]) -> Deferred> { return deferMaybe(0) } + open func insertCommands(_ commands: [SyncCommand], forClients clients: [RemoteClient]) -> Deferred> { return deferMaybe(0) } +} + +func removeLocalClient(_ a: ClientAndTabs) -> Bool { + return a.client.guid != nil +} + +func byGUID(_ a: ClientAndTabs, b: ClientAndTabs) -> Bool { + guard let aGUID = a.client.guid, let bGUID = b.client.guid else { + return false + } + return aGUID < bGUID +} + +func byURL(_ a: RemoteTab, b: RemoteTab) -> Bool { + return a.URL.absoluteString < b.URL.absoluteString +} + +class SQLRemoteClientsAndTabsTests: XCTestCase { + var clientsAndTabs: SQLiteRemoteClientsAndTabs! + + lazy var clients: [ClientAndTabs] = MockRemoteClientsAndTabs().clientsAndTabs + + override func setUp() { + let files = MockFiles() + do { + try files.remove("browser.db") + } catch _ { + } + clientsAndTabs = SQLiteRemoteClientsAndTabs(db: BrowserDB(filename: "browser.db", schema: BrowserSchema(), files: files)) + } + + func testInsertGetClear() { + // Insert some test data. + var remoteDevicesToInsert: [RemoteDevice] = [] + // Filter the local client from mock test data. + let remoteClients = clients.filter(removeLocalClient) + for c in remoteClients { + let e = self.expectation(description: "Insert.") + clientsAndTabs.insertOrUpdateClient(c.client).upon { + XCTAssertTrue($0.isSuccess) + e.fulfill() + } + let remoteDevice = RemoteDevice(id: c.client.fxaDeviceId!, name: "FxA Device", type: "desktop", isCurrentDevice: false, lastAccessTime: 12345678) + remoteDevicesToInsert.append(remoteDevice) + clientsAndTabs.insertOrUpdateTabsForClientGUID(c.client.guid, tabs: c.tabs).succeeded() + } + _ = clientsAndTabs.replaceRemoteDevices(remoteDevicesToInsert).succeeded() + + let f = self.expectation(description: "Get after insert.") + clientsAndTabs.getClientsAndTabs().upon { + if let got = $0.successValue { + let expected = remoteClients.sorted(by: byGUID) + let actual = got.sorted(by: byGUID) + + // This comparison will fail if the order of the tabs changes. We sort the result + // as part of the DB query, so it's not actively sorted in Swift. + XCTAssertEqual(expected, actual) + } else { + XCTFail("Expected clients!") + } + f.fulfill() + } + + // Update the test data with a client with new tabs, and one with no tabs. + let client0NewTabs = clients[1].tabs.map { $0.withClientGUID(self.clients[0].client.guid) } + let client1NewTabs: [RemoteTab] = [] + let expected = [ + ClientAndTabs(client: clients[0].client, tabs: client0NewTabs), + ClientAndTabs(client: clients[1].client, tabs: client1NewTabs), + ].sorted(by: byGUID) + + func doUpdate(_ guid: String?, tabs: [RemoteTab]) { + let g0 = self.expectation(description: "Update client: \(guid ?? "nil").") + clientsAndTabs.insertOrUpdateTabsForClientGUID(guid, tabs: tabs).upon { + if let rowID = $0.successValue { + XCTAssertTrue(rowID > -1) + } else { + XCTFail("Didn't successfully update.") + } + g0.fulfill() + } + } + + doUpdate(clients[0].client.guid, tabs: client0NewTabs) + doUpdate(clients[1].client.guid, tabs: client1NewTabs) + // Also update the local tabs list. It should still not appear in the expected tabs below. + doUpdate(clients[2].client.guid, tabs: client1NewTabs) + + let h = self.expectation(description: "Get after update.") + clientsAndTabs.getClientsAndTabs().upon { + if let clients = $0.successValue { + XCTAssertEqual(expected, clients.sorted(by: byGUID)) + } else { + XCTFail("Expected clients!") + } + h.fulfill() + } + + // Now clear everything, and verify we have no clients or tabs whatsoever. + let i = self.expectation(description: "Clear.") + clientsAndTabs.clear().upon { + XCTAssertTrue($0.isSuccess) + i.fulfill() + } + + let j = self.expectation(description: "Get after clear.") + clientsAndTabs.getClientsAndTabs().upon { + if let clients = $0.successValue { + XCTAssertEqual(0, clients.count) + } else { + XCTFail("Expected clients!") + } + j.fulfill() + } + + self.waitForExpectations(timeout: 10, handler: nil) + } + + func testGetTabsForClient() { + for c in clients { + let e = self.expectation(description: "Insert.") + clientsAndTabs.insertOrUpdateClient(c.client).upon { + XCTAssertTrue($0.isSuccess) + e.fulfill() + } + clientsAndTabs.insertOrUpdateTabsForClientGUID(c.client.guid, tabs: c.tabs).succeeded() + } + + let e = self.expectation(description: "Get after insert.") + let ct = clients[0] + clientsAndTabs.getTabsForClientWithGUID(ct.client.guid).upon { + if let got = $0.successValue { + // This comparison will fail if the order of the tabs changes. We sort the result + // as part of the DB query, so it's not actively sorted in Swift. + XCTAssertEqual(ct.tabs.count, got.count) + XCTAssertEqual(ct.tabs.sorted(by: byURL), got.sorted(by: byURL)) + } else { + XCTFail("Expected tabs!") + } + e.fulfill() + } + + let f = self.expectation(description: "Get after insert.") + let localClient = clients[0] + clientsAndTabs.getTabsForClientWithGUID(localClient.client.guid).upon { + if let got = $0.successValue { + // This comparison will fail if the order of the tabs changes. We sort the result + // as part of the DB query, so it's not actively sorted in Swift. + XCTAssertEqual(localClient.tabs.count, got.count) + XCTAssertEqual(localClient.tabs.sorted(by: byURL), got.sorted(by: byURL)) + } else { + XCTFail("Expected tabs!") + } + f.fulfill() + } + + self.waitForExpectations(timeout: 10, handler: nil) + } + + func remoteDeviceFactory(_ row: SDRow) -> RemoteDevice { + return RemoteDevice( + id: row["guid"] as? String, + name: row["name"] as! String, + type: row["type"] as? String, + isCurrentDevice: row["is_current_device"] as! Int > 0, + lastAccessTime: row["last_access_time"] as? Timestamp) + } + + func testReplaceRemoteDevices() { + let device1 = RemoteDevice(id: "fx1", name: "Device 1", type: "mobile", isCurrentDevice: false, lastAccessTime: 12345678) + let device2 = RemoteDevice(id: "fx2", name: "Device 2 (local)", type: "desktop", isCurrentDevice: true, lastAccessTime: nil) + let device3 = RemoteDevice(id: nil, name: "Device 3 (fauly)", type: "desktop", isCurrentDevice: false, lastAccessTime: 12345678) + let device4 = RemoteDevice(id: "fx4", name: "Device 4 (fauly)", type: nil, isCurrentDevice: false, lastAccessTime: 12345678) + + _ = clientsAndTabs.replaceRemoteDevices([device1, device2, device3, device4]).succeeded() + + let devices = clientsAndTabs.db.runQuery("SELECT * FROM \(TableRemoteDevices)", args: nil, factory: remoteDeviceFactory).value.successValue!.asArray() + XCTAssertEqual(devices.count, 1) // Fauly devices + local device were not inserted. + + let device5 = RemoteDevice(id: "fx5", name: "Device 5", type: "mobile", isCurrentDevice: false, lastAccessTime: 12345678) + _ = clientsAndTabs.replaceRemoteDevices([device5]).succeeded() + + let newDevices = clientsAndTabs.db.runQuery("SELECT * FROM \(TableRemoteDevices)", args: nil, factory: remoteDeviceFactory).value.successValue!.asArray() + XCTAssertEqual(newDevices.count, 1) // replaceRemoteDevices wipes the whole list before inserting. + } +} diff --git a/mobile/ios/StorageTests/TestSwiftData.swift b/mobile/ios/StorageTests/TestSwiftData.swift new file mode 100644 index 0000000000..8db05db0cf --- /dev/null +++ b/mobile/ios/StorageTests/TestSwiftData.swift @@ -0,0 +1,220 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Storage + +import XCTest + +// TODO: rewrite this test to not use BrowserSchema. It used to use HistoryTable… +class TestSwiftData: XCTestCase { + var swiftData: SwiftData? + var urlCounter = 1 + var testDB: String! + + override func setUp() { + let files = MockFiles() + do { + try files.remove("testSwiftData.db") + } catch _ { + } + testDB = (try! (files.getAndEnsureDirectory() as NSString)).appendingPathComponent("testSwiftData.db") + swiftData = SwiftData(filename: testDB, schema: BrowserSchema(), files: files) + let table = BrowserSchema() + + // Ensure static flags match expected values. + XCTAssert(SwiftData.ReuseConnections, "Reusing database connections") + XCTAssert(SwiftData.EnableWAL, "WAL enabled") + + XCTAssertNil(addSite(table, url: "http://url0", title: "title0"), "Added url0.") + } + + override func tearDown() { + // Restore static flags to their default values. + SwiftData.ReuseConnections = true + SwiftData.EnableWAL = true + } + + /* + // These two tests broke after pull #427. + func testNoWALOrConnectionReuse() { + SwiftData.EnableWAL = false + SwiftData.ReuseConnections = false + var error = writeDuringRead() + XCTAssertEqual(error!.code, 5, "Got 'database is locked' error") + } + + func testNoConnectionReuse() { + SwiftData.EnableWAL = true + SwiftData.ReuseConnections = false + var error = writeDuringRead() + XCTAssertNotNil(error, "Expected error during write.") + XCTAssertEqual(error?.code ?? 0, 8, "Got 'attempt to write to read-only database' error") + } + */ + + func testNoWAL() { + SwiftData.EnableWAL = false + SwiftData.ReuseConnections = true + let error = writeDuringRead() + XCTAssertNil(error, "Insertion succeeded") + } + + func testDefaultSettings() { + SwiftData.EnableWAL = true + SwiftData.ReuseConnections = true + let error = writeDuringRead() + XCTAssertNil(error, "Insertion succeeded") + } + + func testBusyTimeout() { + SwiftData.EnableWAL = false + SwiftData.ReuseConnections = false + let error = writeDuringRead(closeTimeout: 1) + XCTAssertNil(error, "Insertion succeeded") + } + + func testFilledCursor() { + SwiftData.ReuseConnections = false + SwiftData.EnableWAL = false + XCTAssertNil(writeDuringRead(true), "Insertion succeeded") + } + + fileprivate func writeDuringRead(_ safeQuery: Bool = false, closeTimeout: UInt64? = nil) -> MaybeErrorType? { + + // Query the database and hold the cursor. + var c: Cursor! + let result = swiftData!.withConnection(SwiftData.Flags.readOnly) { db -> Void in + if safeQuery { + c = db.executeQuery("SELECT * FROM history", factory: { $0 }) + } else { + c = db.executeQueryUnsafe("SELECT * FROM history", factory: { $0 }, withArgs: nil) + } + return () + } + + XCTAssertNil(result.value.failureValue, "Queried database") + + // If we have a live cursor, this will step to the first result. + // Stepping through a prepared statement without resetting it will lock the connection. + let _ = c[0] + + // Close the cursor after a delay if there's a close timeout set. + if let closeTimeout = closeTimeout { + let queue = DispatchQueue(label: "cursor timeout queue", attributes: []) + queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(closeTimeout * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) { + c.close() + } + } + + defer { urlCounter += 1 } + return addSite(BrowserSchema(), url: "http://url/\(urlCounter)", title: "title\(urlCounter)") + } + + fileprivate func addSite(_ table: BrowserSchema, url: String, title: String) -> MaybeErrorType? { + let result = swiftData!.withConnection(SwiftData.Flags.readWrite) { connection -> Void in + let args: Args = [Bytes.generateGUID(), url, title] + try connection.executeChange("INSERT INTO history (guid, url, title, is_deleted, should_upload) VALUES (?, ?, ?, 0, 0)", withArgs: args) + } + + return result.value.failureValue + } + + func testEncrypt() { + // XXX: Something is holding an open connection to the normal database, making it impossible + // to change its encryption. This kills it so that we can move on. + let files = MockFiles() + do { + try files.remove("testSwiftData.db") + } catch _ { + } + let path = testDB + func verifyData(_ swiftData: SwiftData) -> MaybeErrorType? { + let resultDeferred = swiftData.withConnection(SwiftData.Flags.readOnly) { db -> Void in + return () + } + return resultDeferred.value.failureValue + } + + XCTAssertNotNil(SwiftData(filename: path!, schema: BrowserSchema(), files: files), "Connected to unencrypted database") + + // Encrypt the database. + XCTAssertNil(verifyData(SwiftData(filename: path!, key: "Secret", schema: BrowserSchema(), files: files)), "Encrypted database") + + // Now change the encryption key. + XCTAssertNil(verifyData(SwiftData(filename: path!, key: "Secret2", prevKey: "Secret", schema: BrowserSchema(), files: files)), "Re-encrypted database") + + // Changing the encryption without the prevKey should fail. + XCTAssertNotNil(verifyData(SwiftData(filename: path!, schema: BrowserSchema(), files: files)), "Failed decrypting database") + + // Now remove the encryption key. + XCTAssertNil(verifyData(SwiftData(filename: path!, prevKey: "Secret2", schema: BrowserSchema(), files: files)), "Decrypted database") + } + + func testNulls() { + guard let db = swiftData else { + XCTFail("DB not open") + return + } + db.withConnection(SwiftData.Flags.readWriteCreate) { db in + try! db.executeChange("CREATE TABLE foo ( bar TEXT, baz INTEGER )") + try! db.executeChange("INSERT INTO foo VALUES (NULL, 1), ('here', 2)") + let shouldBeString = db.executeQuery("SELECT bar FROM foo WHERE baz = 2", factory: { (row) in row["bar"] }).asArray()[0] + guard let s = shouldBeString as? String else { + XCTFail("Couldn't cast.") + return + } + XCTAssertEqual(s, "here") + + let shouldBeNull = db.executeQuery("SELECT bar FROM foo WHERE baz = 1", factory: { (row) in row["bar"] }).asArray()[0] + XCTAssertNil(shouldBeNull as? String) + XCTAssertNil(shouldBeNull) + }.succeeded() + } + + func testArrayCursor() { + let data = ["One", "Two", "Three"] + let t = ArrayCursor(data: data) + + // Test subscript access + XCTAssertNil(t[-1], "Subscript -1 returns nil") + XCTAssertEqual(t[0]!, "One", "Subscript zero returns the correct data") + XCTAssertEqual(t[1]!, "Two", "Subscript one returns the correct data") + XCTAssertEqual(t[2]!, "Three", "Subscript two returns the correct data") + XCTAssertNil(t[3], "Subscript three returns nil") + + // Test status data with default initializer + XCTAssertEqual(t.status, CursorStatus.success, "Cursor as correct status") + XCTAssertEqual(t.statusMessage, "Success", "Cursor as correct status message") + XCTAssertEqual(t.count, 3, "Cursor as correct size") + + // Test generator access + var i = 0 + for s in t { + XCTAssertEqual(s!, data[i], "Subscript zero returns the correct data") + i += 1 + } + + // Test creating a failed cursor + let t2 = ArrayCursor(data: data, status: CursorStatus.failure, statusMessage: "Custom status message") + XCTAssertEqual(t2.status, CursorStatus.failure, "Cursor as correct status") + XCTAssertEqual(t2.statusMessage, "Custom status message", "Cursor as correct status message") + XCTAssertEqual(t2.count, 0, "Cursor as correct size") + + // Test subscript access return nil for a failed cursor + XCTAssertNil(t2[0], "Subscript zero returns nil if failure") + XCTAssertNil(t2[1], "Subscript one returns nil if failure") + XCTAssertNil(t2[2], "Subscript two returns nil if failure") + XCTAssertNil(t2[3], "Subscript three returns nil if failure") + + // Test that generator doesn't work with failed cursors + var ran = false + for s in t2 { + print("Got \(s ?? "nil")", terminator: "\n") + ran = true + } + XCTAssertFalse(ran, "for...in didn't run for failed cursor") + } +} diff --git a/mobile/ios/StorageTests/fixtures/v33.db b/mobile/ios/StorageTests/fixtures/v33.db new file mode 100644 index 0000000000..9707dae26e Binary files /dev/null and b/mobile/ios/StorageTests/fixtures/v33.db differ diff --git a/mobile/ios/StorageTests/testcert1.pem b/mobile/ios/StorageTests/testcert1.pem new file mode 100644 index 0000000000..6e47859ee9 Binary files /dev/null and b/mobile/ios/StorageTests/testcert1.pem differ diff --git a/mobile/ios/StorageTests/testcert2.pem b/mobile/ios/StorageTests/testcert2.pem new file mode 100644 index 0000000000..fe6dcf5387 Binary files /dev/null and b/mobile/ios/StorageTests/testcert2.pem differ diff --git a/mobile/ios/Sync/BatchingClient.swift b/mobile/ios/Sync/BatchingClient.swift new file mode 100644 index 0000000000..3901829130 --- /dev/null +++ b/mobile/ios/Sync/BatchingClient.swift @@ -0,0 +1,294 @@ +/* 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/. */ + +import Foundation +import Alamofire +import Shared +import XCGLogger +import Deferred + +open class SerializeRecordFailure: MaybeErrorType, SyncPingFailureFormattable { + open let record: Record + + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } + + open var description: String { + return "Failed to serialize record: \(record)" + } + + public init(record: Record) { + self.record = record + } +} + +private let log = Logger.syncLogger + +private typealias UploadRecord = (guid: GUID, payload: String, sizeBytes: Int) +public typealias DeferredResponse = Deferred>> + +typealias BatchUploadFunction = (_ lines: [String], _ ifUnmodifiedSince: Timestamp?, _ queryParams: [URLQueryItem]?) -> Deferred>> + +private let commitParam = URLQueryItem(name: "commit", value: "true") + +private enum AccumulateRecordError: MaybeErrorType { + var description: String { + switch self { + case .full: + return "Batch or payload is full." + case .unknown: + return "Unknown errored while trying to accumulate records in batch" + } + } + + case full(uploadOp: DeferredResponse) + case unknown +} + +open class TooManyRecordsError: MaybeErrorType, SyncPingFailureFormattable { + open var description: String { + return "Trying to send too many records in a single batch." + } + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } +} + +open class RecordsFailedToUpload: MaybeErrorType, SyncPingFailureFormattable { + open var description: String { + return "Some records failed to upload" + } + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } +} + +open class Sync15BatchClient { + fileprivate(set) var ifUnmodifiedSince: Timestamp? + + fileprivate let config: InfoConfiguration + fileprivate let uploader: BatchUploadFunction + fileprivate let serializeRecord: (Record) -> String? + + fileprivate var batchToken: BatchToken? + + // Keep track of the limits of a single batch + fileprivate var totalBytes: ByteCount = 0 + fileprivate var totalRecords: Int = 0 + + // Keep track of the limits of a single POST + fileprivate var postBytes: ByteCount = 0 + fileprivate var postRecords: Int = 0 + + fileprivate var records = [UploadRecord]() + + fileprivate var onCollectionUploaded: (POSTResult, Timestamp?) -> DeferredTimestamp + + fileprivate func batchQueryParamWithValue(_ value: String) -> URLQueryItem { + return URLQueryItem(name: "batch", value: value) + } + + init(config: InfoConfiguration, ifUnmodifiedSince: Timestamp? = nil, serializeRecord: @escaping (Record) -> String?, + uploader: @escaping BatchUploadFunction, onCollectionUploaded: @escaping (POSTResult, Timestamp?) -> DeferredTimestamp) { + self.config = config + self.ifUnmodifiedSince = ifUnmodifiedSince + self.uploader = uploader + self.serializeRecord = serializeRecord + + self.onCollectionUploaded = onCollectionUploaded + } + + open func endBatch() -> Success { + guard !records.isEmpty else { + return succeed() + } + + if let token = self.batchToken { + return commitBatch(token) >>> succeed + } + + let lines = self.freezePost() + return self.uploader(lines, self.ifUnmodifiedSince, nil) + >>== effect(moveForward) + >>> succeed + } + + // If in batch mode, will discard the batch if any record fails + open func endSingleBatch() -> Deferred> { + return self.start() >>== { response in + let succeeded = response.value.success + guard let token = self.batchToken else { + return deferMaybe((succeeded: succeeded, lastModified: response.metadata.lastModifiedMilliseconds)) + } + guard succeeded.count == self.totalRecords else { + return deferMaybe(RecordsFailedToUpload()) + } + return self.commitBatch(token) >>== { commitResp in + return deferMaybe((succeeded: succeeded, lastModified: commitResp.metadata.lastModifiedMilliseconds)) + } + } + } + + open func addRecords(_ records: [Record], singleBatch: Bool = false) -> Success { + guard !records.isEmpty else { + return succeed() + } + + // Eagerly serializer the record prior to processing them so we can catch any issues + // with record sizes before we start uploading to the server. + let serializeThunks = records.map { record in + return { self.serialize(record) } + } + + return accumulate(serializeThunks) >>== { + let iter = $0.makeIterator() + if singleBatch { + return self.addRecordsInSingleBatch(iter) + } else { + return self.addRecords(iter) + } + } + } + + fileprivate func addRecords(_ generator: IndexingIterator<[UploadRecord]>) -> Success { + var mutGenerator = generator + while let record = mutGenerator.next() { + return accumulateOrUpload(record) >>> { self.addRecords(mutGenerator) } + } + return succeed() + } + + fileprivate func addRecordsInSingleBatch(_ generator: IndexingIterator<[UploadRecord]>) -> Success { + var mutGenerator = generator + while let record = mutGenerator.next() { + guard self.addToPost(record) else { + return deferMaybe(TooManyRecordsError()) + } + } + return succeed() + } + + fileprivate func accumulateOrUpload(_ record: UploadRecord) -> Success { + return accumulateRecord(record).bind { result in + // Try to add the record to our buffer + guard let e = result.failureValue as? AccumulateRecordError else { + return succeed() + } + + switch e { + case .full(let uploadOp): + return uploadOp >>> { self.accumulateOrUpload(record) } + default: + return deferMaybe(e) + } + } + } + + fileprivate func accumulateRecord(_ record: UploadRecord) -> Success { + guard let token = self.batchToken else { + guard addToPost(record) else { + return deferMaybe(AccumulateRecordError.full(uploadOp: self.start())) + } + return succeed() + } + + guard fitsInBatch(record) else { + return deferMaybe(AccumulateRecordError.full(uploadOp: self.commitBatch(token))) + } + + guard addToPost(record) else { + return deferMaybe(AccumulateRecordError.full(uploadOp: self.postInBatch(token))) + } + + addToBatch(record) + return succeed() + } + + fileprivate func serialize(_ record: Record) -> Deferred> { + guard let line = self.serializeRecord(record) else { + return deferMaybe(SerializeRecordFailure(record: record)) + } + + let lineSize = line.utf8.count + guard lineSize < Sync15StorageClient.maxRecordSizeBytes else { + return deferMaybe(RecordTooLargeError(size: lineSize, guid: record.id)) + } + + return deferMaybe((record.id, line, lineSize)) + } + + fileprivate func addToPost(_ record: UploadRecord) -> Bool { + guard postRecords + 1 <= config.maxPostRecords && postBytes + record.sizeBytes <= config.maxPostBytes else { + return false + } + postRecords += 1 + postBytes += record.sizeBytes + records.append(record) + return true + } + + fileprivate func fitsInBatch(_ record: UploadRecord) -> Bool { + return totalRecords + 1 <= config.maxTotalRecords && totalBytes + record.sizeBytes <= config.maxTotalBytes + } + + fileprivate func addToBatch(_ record: UploadRecord) { + totalRecords += 1 + totalBytes += record.sizeBytes + } + + fileprivate func postInBatch(_ token: BatchToken) -> DeferredResponse { + // Push up the current payload to the server and reset + let lines = self.freezePost() + return uploader(lines, self.ifUnmodifiedSince, [batchQueryParamWithValue(token)]) + } + + fileprivate func commitBatch(_ token: BatchToken) -> DeferredResponse { + resetBatch() + let lines = self.freezePost() + let queryParams = [batchQueryParamWithValue(token), commitParam] + return uploader(lines, self.ifUnmodifiedSince, queryParams) + >>== effect(moveForward) + } + + fileprivate func start() -> DeferredResponse { + let postRecordCount = self.postRecords + let postBytesCount = self.postBytes + let lines = freezePost() + return self.uploader(lines, self.ifUnmodifiedSince, [batchQueryParamWithValue("true")]) + >>== effect(moveForward) + >>== { response in + if let token = response.value.batchToken { + self.batchToken = token + + // Now that we've started a batch, make sure to set the counters for the batch to include + // the records we just sent as part of the start call. + self.totalRecords = postRecordCount + self.totalBytes = postBytesCount + } + + return deferMaybe(response) + } + } + + fileprivate func moveForward(_ response: StorageResponse) { + let lastModified = response.metadata.lastModifiedMilliseconds + self.ifUnmodifiedSince = lastModified + _ = self.onCollectionUploaded(response.value, lastModified) + } + + fileprivate func resetBatch() { + totalBytes = 0 + totalRecords = 0 + self.batchToken = nil + } + + fileprivate func freezePost() -> [String] { + let lines = records.map { $0.payload } + self.records = [] + self.postBytes = 0 + self.postRecords = 0 + return lines + } +} diff --git a/mobile/ios/Sync/BookmarkPayload.swift b/mobile/ios/Sync/BookmarkPayload.swift new file mode 100644 index 0000000000..2c4972e023 --- /dev/null +++ b/mobile/ios/Sync/BookmarkPayload.swift @@ -0,0 +1,571 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import SwiftyJSON + +private let log = Logger.syncLogger + +public protocol MirrorItemable { + func toMirrorItem(_ modified: Timestamp) -> BookmarkMirrorItem +} + +extension BookmarkMirrorItem { + func asPayload() -> BookmarkBasePayload { + return BookmarkType.somePayloadFromJSON(self.asJSON()) + } + + func asPayloadWithChildren(_ children: [GUID]?) -> BookmarkBasePayload { + let remappedChildren: [GUID]? + if let children = children { + if BookmarkRoots.RootGUID == self.guid { + // Only the root contains roots, and so only its children + // need to be translated. + remappedChildren = children.map(BookmarkRoots.translateOutgoingRootGUID) + } else { + remappedChildren = children + } + } else { + remappedChildren = nil + } + + let json = self.asJSONWithChildren(remappedChildren) + return BookmarkType.somePayloadFromJSON(json) + } +} + +/** + * Hierarchy: + * - BookmarkBasePayload + * \_ FolderPayload + * \_ LivemarkPayload + * \_ SeparatorPayload + * \_ BookmarkPayload + * \_ BookmarkQueryPayload + */ + +public enum BookmarkType: String { + case livemark + case separator + case folder + case bookmark + case query + case microsummary // Dead: now a bookmark. + + // The result might be invalid, but it won't be nil. + public static func somePayloadFromJSON(_ json: JSON) -> BookmarkBasePayload { + return payloadFromJSON(json) ?? BookmarkBasePayload(json) + } + + public static func payloadFromJSON(_ json: JSON) -> BookmarkBasePayload? { + if json["deleted"].bool ?? false { + // Deleted records won't have a type. + return BookmarkBasePayload(json) + } + + guard let typeString = json["type"].string else { + return nil + } + + guard let type = BookmarkType(rawValue: typeString) else { + return nil + } + + switch type { + case microsummary: + fallthrough + case bookmark: + return BookmarkPayload(json) + case folder: + return FolderPayload(json) + case livemark: + return LivemarkPayload(json) + case separator: + return SeparatorPayload(json) + case query: + return BookmarkQueryPayload(json) + } + } + + public static func isValid(_ type: String?) -> Bool { + guard let type = type else { + return false + } + + return BookmarkType(rawValue: type) != nil + } +} + +open class LivemarkPayload: BookmarkBasePayload { + open var feedURI: String? { + return self["feedUri"].string + } + + open var siteURI: String? { + return self["siteUri"].string + } + + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + return self.hasRequiredStringFields(["feedUri", "siteUri"]) + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + guard let p = obj as? LivemarkPayload else { + return false + } + + if !super.equalPayloads(p) { + return false + } + + if self.deleted { + return true + } + + if self.feedURI != p.feedURI { + return false + } + + if self.siteURI != p.siteURI { + return false + } + + return true + } + + override open func toMirrorItem(_ modified: Timestamp) -> BookmarkMirrorItem { + if self.deleted { + return BookmarkMirrorItem.deleted(.livemark, guid: self.id, modified: modified) + } + + return BookmarkMirrorItem.livemark( + self.id, + dateAdded: self["dateAdded"].uInt64, + modified: modified, + hasDupe: self.hasDupe, + // TODO: these might need to be weakened if real-world data is dirty. + parentID: self["parentid"].stringValue, + parentName: self["parentName"].string, + title: self["title"].string, + description: self["description"].string, + feedURI: self.feedURI!, + siteURI: self.siteURI! + ) + } +} + +open class SeparatorPayload: BookmarkBasePayload { + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + if !self["pos"].isInt() { + log.warning("Separator \(self.id) missing pos.") + return false + } + return true + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + guard let p = obj as? SeparatorPayload else { + return false + } + + if !super.equalPayloads(p) { + return false + } + + if self.deleted { + return true + } + + if self["pos"].int != p["pos"].int { + return false + } + + return true + } + + override open func toMirrorItem(_ modified: Timestamp) -> BookmarkMirrorItem { + if self.deleted { + return BookmarkMirrorItem.deleted(.separator, guid: self.id, modified: modified) + } + + return BookmarkMirrorItem.separator( + self.id, + dateAdded: self["dateAdded"].uInt64, + modified: modified, + hasDupe: self.hasDupe, + // TODO: these might need to be weakened if real-world data is dirty. + parentID: self["parentid"].string!, + parentName: self["parentName"].string, + pos: self["pos"].int! + ) + } +} + +open class FolderPayload: BookmarkBasePayload { + fileprivate var childrenAreValid: Bool { + return self.hasStringArrayField("children") + } + + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + + if !self.hasRequiredStringFields(["title"]) { + log.warning("Folder \(self.id) missing title.") + return false + } + + if !self.hasOptionalStringFields(["description"]) { + log.warning("Folder \(self.id) missing string description.") + return false + + } + if !self.childrenAreValid { + log.warning("Folder \(self.id) has invalid children.") + return false + } + + return true + } + + open var children: [String] { + return self["children"].arrayValue.map { $0.string! } + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + guard let p = obj as? FolderPayload else { + return false + } + + if !super.equalPayloads(p) { + return false + } + + if self.deleted { + return true + } + + if self["title"].string != p["title"].string { + return false + } + + if self["description"].string != p["description"].string { + return false + } + + if self.children != p.children { + return false + } + + return true + } + + override open func toMirrorItem(_ modified: Timestamp) -> BookmarkMirrorItem { + if self.deleted { + return BookmarkMirrorItem.deleted(.folder, guid: self.id, modified: modified) + } + + return BookmarkMirrorItem.folder( + self.id, + dateAdded: self["dateAdded"].uInt64, + modified: modified, + hasDupe: self.hasDupe, + // TODO: these might need to be weakened if real-world data is dirty. + parentID: self["parentid"].string!, + parentName: self["parentName"].string, + title: self["title"].string!, + description: self["description"].string, + children: self.children + ) + } +} + +open class BookmarkPayload: BookmarkBasePayload { + fileprivate static let requiredBookmarkStringFields = ["bmkUri"] + + // Title *should* be required, but can be missing for queries. Great. + fileprivate static let optionalBookmarkStringFields = ["title", "keyword", "description"] + fileprivate static let optionalBookmarkBooleanFields = ["loadInSidebar"] + + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + + if !self.hasRequiredStringFields(BookmarkPayload.requiredBookmarkStringFields) { + log.warning("Bookmark \(self.id) missing required string field.") + return false + } + + if !self.hasStringArrayField("tags") { + log.warning("Bookmark \(self.id) missing tags array. We'll replace with an empty array.") + // Ignore. + } + + if !self.hasOptionalStringFields(BookmarkPayload.optionalBookmarkStringFields) { + return false + } + + return self.hasOptionalBooleanFields(BookmarkPayload.optionalBookmarkBooleanFields) + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + guard let p = obj as? BookmarkPayload else { + return false + } + + if !super.equalPayloads(p) { + return false + } + + if self.deleted { + return true + } + + if !BookmarkPayload.requiredBookmarkStringFields.every({ p[$0].string! == self[$0].string! }) { + return false + } + + // TODO: compare optional fields. + + if Set(self.tags) != Set(p.tags) { + return false + } + + if self["loadInSidebar"].bool != p["loadInSidebar"].bool { + return false + } + + return true + } + + lazy var tags: [String] = { + return self["tags"].arrayValue.flatMap { $0.string } + }() + + lazy var tagsString: String = { + if self["tags"].isArray() { + return self["tags"].stringValue() ?? "[]" + } + return "[]" + }() + + override open func toMirrorItem(_ modified: Timestamp) -> BookmarkMirrorItem { + if self.deleted { + return BookmarkMirrorItem.deleted(.bookmark, guid: self.id, modified: modified) + } + + return BookmarkMirrorItem.bookmark( + self.id, + dateAdded: self["dateAdded"].uInt64, + modified: modified, + hasDupe: self.hasDupe, + // TODO: these might need to be weakened if real-world data is dirty. + parentID: self["parentid"].string!, + parentName: self["parentName"].string, + title: self["title"].string ?? "", + description: self["description"].string, + URI: self["bmkUri"].string!, + tags: self.tagsString, // Stringify it so we can put the array in the DB. + keyword: self["keyword"].string + ) + } +} + +open class BookmarkQueryPayload: BookmarkPayload { + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + + if !self.hasOptionalStringFields(["queryId", "folderName"]) { + log.warning("Query \(self.id) missing queryId or folderName.") + return false + } + + return true + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + guard let p = obj as? BookmarkQueryPayload else { + return false + } + + if !super.equalPayloads(p) { + return false + } + + if self.deleted { + return true + } + + if self["folderName"].string != p["folderName"].string { + return false + } + + if self["queryId"].string != p["queryId"].string { + return false + } + + return true + } + + override open func toMirrorItem(_ modified: Timestamp) -> BookmarkMirrorItem { + if self.deleted { + return BookmarkMirrorItem.deleted(.query, guid: self.id, modified: modified) + } + + return BookmarkMirrorItem.query( + self.id, + dateAdded: self["dateAdded"].uInt64, + modified: modified, + hasDupe: self.hasDupe, + parentID: self["parentid"].string!, + parentName: self["parentName"].string, + title: self["title"].string ?? "", + description: self["description"].string, + URI: self["bmkUri"].string!, + tags: self.tagsString, // Stringify it so we can put the array in the DB. + keyword: self["keyword"].string, + folderName: self["folderName"].string, + queryID: self["queryID"].string + ) + } +} + +open class BookmarkBasePayload: CleartextPayloadJSON, MirrorItemable { + fileprivate static let requiredStringFields: [String] = ["parentid", "type"] + fileprivate static let optionalBooleanFields: [String] = ["hasDupe"] + + static func deletedPayload(_ guid: GUID) -> BookmarkBasePayload { + let remappedGUID = BookmarkRoots.translateOutgoingRootGUID(guid) + return BookmarkBasePayload(JSON(["id": remappedGUID, "deleted": true])) + } + + func hasStringArrayField(_ name: String) -> Bool { + guard let arr = self[name].array else { + return false + } + return arr.every { $0.isString() } + } + + func hasRequiredStringFields(_ fields: [String]) -> Bool { + return fields.every { self[$0].isString() } + } + + func hasOptionalStringFields(_ fields: [String]) -> Bool { + return fields.every { field in + let val = self[field] + // Yup, 404 is not found, so this means "string or nothing". + let valid = val.isString() || val.isNull() || val.isError() + if !valid { + log.debug("Field \(field) is invalid: \(val).") + } + return valid + } + } + + func hasOptionalBooleanFields(_ fields: [String]) -> Bool { + return fields.every { field in + let val = self[field] + // Yup, 404 is not found, so this means "boolean or nothing". + let valid = val.isBool() || val.isNull() || val.error?.code == 404 + if !valid { + log.debug("Field \(field) is invalid: \(val).") + } + return valid + } + } + + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + + if self["deleted"].bool ?? false { + return true + } + + // If not deleted, we must be a specific, known, type! + if !BookmarkType.isValid(self["type"].string) { + return false + } + + if !(self["parentName"].isString() || self.id == "places") { + if self["parentid"].string! == "places" { + log.debug("Accepting root with missing parent name.") + } else { + // Bug 1318414. + log.warning("Accepting bookmark with missing parent name.") + } + } + + if !self.hasRequiredStringFields(BookmarkBasePayload.requiredStringFields) { + log.warning("Item missing required string field.") + return false + } + + return self.hasOptionalBooleanFields(BookmarkBasePayload.optionalBooleanFields) + } + + open var hasDupe: Bool { + return self["hasDupe"].bool ?? false + } + + /** + * This only makes sense for valid payloads. + */ + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + guard let p = obj as? BookmarkBasePayload else { + return false + } + + if !super.equalPayloads(p) { + return false + } + + if self.deleted { + return true + } + + if p.deleted { + return self.deleted == p.deleted + } + + // If either record is deleted, these other fields might be missing. + // But we just checked, so we're good to roll on. + + let same: (String) -> Bool = { field in + let left = self[field].string + let right = p[field].string + return left == right + } + + if !BookmarkBasePayload.requiredStringFields.every(same) { + return false + } + + if p["parentName"].string != self["parentName"].string { + return false + } + + return self.hasDupe == p.hasDupe + } + + // This goes here because extensions cannot override methods yet. + open func toMirrorItem(_ modified: Timestamp) -> BookmarkMirrorItem { + precondition(self.deleted, "Non-deleted items should have a specific type.") + return BookmarkMirrorItem.deleted(.bookmark, guid: self.id, modified: modified) + } +} diff --git a/mobile/ios/Sync/BookmarkTelemetryPing.swift b/mobile/ios/Sync/BookmarkTelemetryPing.swift new file mode 100644 index 0000000000..dc5fcd0105 --- /dev/null +++ b/mobile/ios/Sync/BookmarkTelemetryPing.swift @@ -0,0 +1,53 @@ +/* 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/. */ +import SwiftyJSON +import Shared + +public func makeAdHocBookmarkMergePing(_ bundle: Bundle, clientID: String, attempt: Int32, bufferRows: Int?, valid: [String: Bool], clientCount: Int) -> JSON { + let anyFailed = valid.reduce(false, { $0 || $1.1 }) + + var out: [String: Any] = [ + "v": 1, + "appV": AppInfo.appVersion, + "build": AppInfo.buildNumber, + "id": clientID, + "attempt": Int(attempt), + "success": !anyFailed, + "date": Date().description, + "clientCount": clientCount, + ] + + if let bufferRows = bufferRows { + out["rows"] = bufferRows + } + + if anyFailed { + valid.forEach { key, value in + out[key] = value + } + } + + return JSON(out) +} + +public func makeAdHocSyncStatusPing(_ bundle: Bundle, clientID: String, statusObject: [String: String]?, engineResults: [String: String]?, resultsFailure: MaybeErrorType?, clientCount: Int) -> JSON { + + let statusObject: Any = statusObject ?? JSON.null + let engineResults: Any = engineResults ?? JSON.null + let resultsFailure: Any = resultsFailure?.description ?? JSON.null + + let out: [String: Any] = [ + "v": 1, + "appV": AppInfo.appVersion, + "build": AppInfo.buildNumber, + "id": clientID, + "date": Date().description, + "clientCount": clientCount, + "statusObject": statusObject, + "engineResults": engineResults, + "resultsFailure": resultsFailure + ] + + return JSON(out) +} diff --git a/mobile/ios/Sync/CleartextPayloadJSON.swift b/mobile/ios/Sync/CleartextPayloadJSON.swift new file mode 100644 index 0000000000..9303acf63d --- /dev/null +++ b/mobile/ios/Sync/CleartextPayloadJSON.swift @@ -0,0 +1,61 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON + +open class BasePayloadJSON { + let json: JSON + required public init(_ jsonString: String) { + self.json = JSON(parseJSON: jsonString) + } + + public init(_ json: JSON) { + self.json = json + } + + // Override me. + fileprivate func isValid() -> Bool { + return self.json.type != .unknown && + self.json.error == nil + } + + subscript(key: String) -> JSON { + get { + return json[key] + } + } +} + +/** + * http://docs.services.mozilla.com/sync/objectformats.html + * "In addition to these custom collection object structures, the + * Encrypted DataObject adds fields like id and deleted." + */ +open class CleartextPayloadJSON: BasePayloadJSON { + // Override me. + override open func isValid() -> Bool { + return super.isValid() && self["id"].isString() + } + + open var id: String { + return self["id"].string! + } + + open var deleted: Bool { + let d = self["deleted"] + if let bool = d.bool { + return bool + } else { + return false + } + } + + // Override me. + // Doesn't check id. Should it? + open func equalPayloads (_ obj: CleartextPayloadJSON) -> Bool { + return self.deleted == obj.deleted + } +} diff --git a/mobile/ios/Sync/ClientPayload.swift b/mobile/ios/Sync/ClientPayload.swift new file mode 100644 index 0000000000..3c60c5ca29 --- /dev/null +++ b/mobile/ios/Sync/ClientPayload.swift @@ -0,0 +1,57 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON + +open class ClientPayload: CleartextPayloadJSON { + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + + if self["deleted"].bool ?? false { + return true + } + + return self["name"].isString() && + self["type"].isString() + } + + var commands: [JSON] { + return self["commands"].array ?? [] // It might not be present at all. + } + + var name: String { + return self["name"].stringValue + } + + var clientType: String { + return self["type"].stringValue + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + if !(obj is ClientPayload) { + return false + } + + if !super.equalPayloads(obj) { + return false + } + + let p = obj as! ClientPayload + if p.name != self.name { + return false + } + + if p.clientType != self.clientType { + return false + } + + return true + } + + // TODO: version, protocols. +} diff --git a/mobile/ios/Sync/EncryptedJSON.swift b/mobile/ios/Sync/EncryptedJSON.swift new file mode 100644 index 0000000000..33d0cad00c --- /dev/null +++ b/mobile/ios/Sync/EncryptedJSON.swift @@ -0,0 +1,169 @@ +/* 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/. */ + +import Foundation +import Shared +import FxA +import Account +import XCGLogger +import SwiftyJSON + +private let log = Logger.syncLogger + +/** + * Turns JSON of the form + * + * { ciphertext: ..., hmac: ..., iv: ...} + * + * into a new JSON object resulting from decrypting and parsing the ciphertext. + */ +open class EncryptedJSON { + var json: JSON + var _cleartext: JSON? // Cache decrypted cleartext. + var _ciphertextBytes: Data? // Cache decoded ciphertext. + var _hmacBytes: Data? // Cache decoded HMAC. + var _ivBytes: Data? // Cache decoded IV. + + var valid: Bool = false + var validated: Bool = false + + let keyBundle: KeyBundle + + public init(json: String, keyBundle: KeyBundle) { + self.keyBundle = keyBundle + self.json = JSON(parseJSON: json) + } + + public init(json: JSON, keyBundle: KeyBundle) { + self.keyBundle = keyBundle + self.json = json + } + + // For validating HMAC: the raw ciphertext as bytes without decoding. + fileprivate var ciphertextB64: Data? { + if let ct = self["ciphertext"].string { + return Bytes.dataFromBase64(ct) + } + return nil + } + + /** + * You probably want to call validate() and then use .ciphertext. + */ + fileprivate var ciphertextBytes: Data? { + return Bytes.decodeBase64(self["ciphertext"].string!) + } + + fileprivate func validate() -> Bool { + if validated { + return valid + } + + defer { validated = true } + + guard self["ciphertext"].isString() && + self["hmac"].isString() && + self["IV"].isString() else { + valid = false + return false + } + + guard let ciphertextForHMAC = self.ciphertextB64 else { + valid = false + return false + } + + guard keyBundle.verify(hmac: self.hmac, ciphertextB64: ciphertextForHMAC) else { + valid = false + return false + } + + // I guess we called validate twice… + if self._ciphertextBytes != nil { + valid = true + return true + } + + // Also verify that the ciphertext is valid base64. Do this by + // retrieving the value in a failable way, leaving the accessors + // to take the dangerous/simple path. + // We can force-unwrap self["ciphertext"] because we already checked + // it when verifying the HMAC above. + guard let data = self.ciphertextBytes else { + log.error("Unable to decode ciphertext base64 in record \(self["id"].string ?? "")") + valid = false + return false + } + + self._ciphertextBytes = data + valid = true + return valid + } + + open func isValid() -> Bool { + return !json.isError() && self.validate() + } + + /** + * Make sure you call isValid first. This API force-unwraps for simplicity. + */ + var ciphertext: Data { + if _ciphertextBytes != nil { + return _ciphertextBytes! + } + + _ciphertextBytes = self.ciphertextBytes + return _ciphertextBytes! + } + + var hmac: Data { + if _hmacBytes != nil { + return _hmacBytes! + } + //NSData(base16EncodedString: self["hmac"].asString!, options: NSDataBase16DecodingOptions.Default) + _hmacBytes = NSData(base16EncodedString: self["hmac"].stringValue, options: []) as Data + return _hmacBytes! + } + + var iv: Data { + if _ivBytes != nil { + return _ivBytes! + } + + _ivBytes = Bytes.decodeBase64(self["IV"].string!) + return _ivBytes! + } + + // Returns nil on error. + open var cleartext: JSON? { + if _cleartext != nil { + return _cleartext + } + + if !isValid() { + log.error("Failed to validate.") + return nil + } + + let decrypted: String? = keyBundle.decrypt(self.ciphertext, iv: self.iv) + if decrypted == nil { + log.error("Failed to decrypt.") + valid = false + return nil + } + + _cleartext = JSON(parseJSON: decrypted!) + return _cleartext! + } + + subscript(key: String) -> JSON { + get { + return json[key] + } + + set { + json[key] = newValue + } + } +} diff --git a/mobile/ios/Sync/EnvelopeJSON.swift b/mobile/ios/Sync/EnvelopeJSON.swift new file mode 100644 index 0000000000..d0525940f4 --- /dev/null +++ b/mobile/ios/Sync/EnvelopeJSON.swift @@ -0,0 +1,73 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON + +open class EnvelopeJSON { + fileprivate let json: JSON + + public init(_ jsonString: String) { + self.json = JSON(parseJSON: jsonString) + } + + public init(_ json: JSON) { + self.json = json + } + + open func isValid() -> Bool { + return !self.json.isError() && + self.json["id"].isString() && + //self["collection"].isString && + self.json["payload"].isString() + } + + open var id: String { + return self.json["id"].string! + } + + open var collection: String { + return self.json["collection"].string ?? "" + } + + open var payload: String { + return self.json["payload"].string! + } + + open var sortindex: Int { + let s = self.json["sortindex"] + return s.int ?? 0 + } + + open var modified: Timestamp { +// if let intValue = self.json["modified"].int64 { +// return Timestamp(intValue) * 1000 +// } + + if let doubleValue = self.json["modified"].double { + return Timestamp(1000 * (doubleValue)) + } + + return 0 + } + + open func toString() -> String { + return self.json.stringValue()! + } + + open func withModified(_ now: Timestamp) -> EnvelopeJSON { + if var d = self.json.dictionary { + d["modified"] = JSON(Double(now) / 1000) + return EnvelopeJSON(JSON(d)) + } + return EnvelopeJSON(JSON(parseJSON: "!")) // Intentionally bad JSON. + } +} + +extension EnvelopeJSON { + func asJSON() -> JSON { + return self.json + } +} diff --git a/mobile/ios/Sync/HistoryPayload.swift b/mobile/ios/Sync/HistoryPayload.swift new file mode 100644 index 0000000000..0f1508037f --- /dev/null +++ b/mobile/ios/Sync/HistoryPayload.swift @@ -0,0 +1,82 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import SwiftyJSON + +open class HistoryPayload: CleartextPayloadJSON { + open class func fromJSON(_ json: JSON) -> HistoryPayload? { + let p = HistoryPayload(json) + if p.isValid() { + return p + } + return nil + } + + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + + if self["deleted"].bool ?? false { + return true + } + + return self["histUri"].string != nil && // TODO: validate URI. + self["title"].isStringOrNull() && + self["visits"].isArray() + } + + open func asPlace() -> Place { + return Place(guid: self.id, url: self.histURI, title: self.title) + } + + var visits: [Visit] { + let visits = self["visits"].arrayObject as! [[String: Any]] + return optFilter(visits.map(Visit.fromJSON)) + } + + fileprivate var histURI: String { + return self["histUri"].string! + } + + var historyURI: URL { + return self.histURI.asURL! + } + + var title: String { + return self["title"].string ?? "" + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + if let p = obj as? HistoryPayload { + if !super.equalPayloads(p) { + return false + } + + if p.deleted { + return self.deleted == p.deleted + } + + // If either record is deleted, these other fields might be missing. + // But we just checked, so we're good to roll on. + + if p.title != self.title { + return false + } + + if p.historyURI != self.historyURI { + return false + } + + // TODO: compare visits. + + return true + } + + return false + } +} diff --git a/mobile/ios/Sync/Info.plist b/mobile/ios/Sync/Info.plist new file mode 100644 index 0000000000..b3205ecaf4 --- /dev/null +++ b/mobile/ios/Sync/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/mobile/ios/Sync/Info.swift b/mobile/ios/Sync/Info.swift new file mode 100644 index 0000000000..0b41fcb389 --- /dev/null +++ b/mobile/ios/Sync/Info.swift @@ -0,0 +1,75 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON + +open class InfoCollections { + fileprivate let collections: [String: Timestamp] + + init(collections: [String: Timestamp]) { + self.collections = collections + } + + open class func fromJSON(_ json: JSON) -> InfoCollections? { + if let dict = json.dictionary { + var coll = [String: Timestamp]() + for (key, value) in dict { + if let value = value.double { + coll[key] = Timestamp(value * 1000) + } else { + return nil // Invalid, so bail out. + } + } + return InfoCollections(collections: coll) + } + return nil + } + + open func collectionNames() -> [String] { + return Array(self.collections.keys) + } + + open func modified(_ collection: String) -> Timestamp? { + return self.collections[collection] + } + + // Two I/Cs are the same if they have the same modified times for a set of + // collections. If no collections are specified, they're considered the same + // if the other I/C has the same values for this I/C's collections, and + // they have the same collection array. + open func same(_ other: InfoCollections, collections: [String]?) -> Bool { + if let collections = collections { + return collections.every({ self.modified($0) == other.modified($0) }) + } + + // Same collections? + let ours = self.collectionNames() + let theirs = other.collectionNames() + return ours.sameElements(theirs) && same(other, collections: ours) + } +} + +// Response object from https:///info/configuration +public struct InfoConfiguration { + + // Maximum size in bytes of the overall HTTP request body. + public let maxRequestBytes: Int + + // Maximum number of records that can be uploaded to a collection in a single POST request. + public let maxPostRecords: Int + + // Maximum combined size in bytes of the record payloads that can be uploaded to a collection in + // a single POST request. + public let maxPostBytes: Int + + // Maximum total number of records that can be uploaded to a collection as part of a batched upload. + public let maxTotalRecords: Int + + // Maximum total combined size in bytes of the record payloads that can be uploaded to a collection + // as part of a batched upload. + public let maxTotalBytes: Int +} + diff --git a/mobile/ios/Sync/KeyBundle.swift b/mobile/ios/Sync/KeyBundle.swift new file mode 100644 index 0000000000..c9a3c9eb25 --- /dev/null +++ b/mobile/ios/Sync/KeyBundle.swift @@ -0,0 +1,319 @@ +/* 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/. */ + +import Foundation +import Shared +import FxA +import Account +import SwiftyJSON + +private let KeyLength = 32 + +open class KeyBundle: Hashable { + let encKey: Data + let hmacKey: Data + + open class func fromKB(_ kB: Data) -> KeyBundle { + let salt = Data() + let contextInfo = FxAClient10.KW("oldsync") + let len: UInt = 64 // KeyLength + KeyLength, without type nonsense. + let derived = (kB as NSData).deriveHKDFSHA256Key(withSalt: salt, contextInfo: contextInfo, length: len)! + return KeyBundle(encKey: derived.subdata(in: 0.. KeyBundle { + // Bytes.generateRandomBytes uses SecRandomCopyBytes, which hits /dev/random, which + // on iOS is populated by the OS from kernel-level sources of entropy. + // That should mean that we don't need to seed or initialize anything before calling + // this. That is probably not true on (some versions of) OS X. + return KeyBundle(encKey: Bytes.generateRandomBytes(32), hmacKey: Bytes.generateRandomBytes(32)) + } + + open class var invalid: KeyBundle { + return KeyBundle(encKeyB64: "deadbeef", hmacKeyB64: "deadbeef")! + } + + public init?(encKeyB64: String, hmacKeyB64: String) { + guard let e = Bytes.decodeBase64(encKeyB64), + let h = Bytes.decodeBase64(hmacKeyB64) else { + return nil + } + self.encKey = e + self.hmacKey = h + } + + public init(encKey: Data, hmacKey: Data) { + self.encKey = encKey + self.hmacKey = hmacKey + } + + fileprivate func _hmac(_ ciphertext: Data) -> (data: UnsafeMutablePointer, len: Int) { + let hmacAlgorithm = CCHmacAlgorithm(kCCHmacAlgSHA256) + let digestLen: Int = Int(CC_SHA256_DIGEST_LENGTH) + let result = UnsafeMutablePointer.allocate(capacity: digestLen) + CCHmac(hmacAlgorithm, hmacKey.getBytes(), hmacKey.count, ciphertext.getBytes(), ciphertext.count, result) + return (result, digestLen) + } + + open func hmac(_ ciphertext: Data) -> Data { + let (result, digestLen) = _hmac(ciphertext) + let data = NSMutableData(bytes: result, length: digestLen) + + result.deinitialize() + result.deallocate(capacity: digestLen) + return data as Data + } + + /** + * Returns a hex string for the HMAC. + */ + open func hmacString(_ ciphertext: Data) -> String { + let (result, digestLen) = _hmac(ciphertext) + let hash = NSMutableString() + for i in 0.. (ciphertext: Data, iv: Data)? { + let iv = iv ?? Bytes.generateRandomBytes(16) + + let (success, b, copied) = self.crypt(cleartext, iv: iv, op: CCOperation(kCCEncrypt)) + let byteCount = cleartext.count + kCCBlockSizeAES128 + if success == CCCryptorStatus(kCCSuccess) { + // Hooray! + let d = Data(bytes: b, count: Int(copied)) + b.deallocate(bytes: byteCount, alignedTo: MemoryLayout.size) + return (d, iv) + } + + b.deallocate(bytes: byteCount, alignedTo: MemoryLayout.size) + return nil + } + + // You *must* verify HMAC before calling this. + open func decrypt(_ ciphertext: Data, iv: Data) -> String? { + let (success, b, copied) = self.crypt(ciphertext, iv: iv, op: CCOperation(kCCDecrypt)) + let byteCount = ciphertext.count + kCCBlockSizeAES128 + if success == CCCryptorStatus(kCCSuccess) { + // Hooray! + let d = Data(bytes: b, count: Int(copied)) + let s = NSString(data: d, encoding: String.Encoding.utf8.rawValue) + b.deallocate(bytes: byteCount, alignedTo: MemoryLayout.size) + return s as String? + } + + b.deallocate(bytes: byteCount, alignedTo: MemoryLayout.size) + return nil + } + + fileprivate func crypt(_ input: Data, iv: Data, op: CCOperation) -> (status: CCCryptorStatus, buffer: UnsafeMutableRawPointer, count: Int) { + let resultSize = input.count + kCCBlockSizeAES128 + var copied: Int = 0 + let result = UnsafeMutableRawPointer.allocate(bytes: resultSize, alignedTo: MemoryLayout.size) + + let success: CCCryptorStatus = + CCCrypt(op, + CCHmacAlgorithm(kCCAlgorithmAES128), + CCOptions(kCCOptionPKCS7Padding), + encKey.getBytes(), + kCCKeySizeAES256, + iv.getBytes(), + input.getBytes(), + input.count, + result, + resultSize, + &copied + ) + + return (success, result, copied) + } + + open func verify(hmac: Data, ciphertextB64: Data) -> Bool { + let expectedHMAC = hmac + let computedHMAC = self.hmac(ciphertextB64) + return (expectedHMAC == computedHMAC) + } + + /** + * Swift can't do functional factories. I would like to have one of the following + * approaches be viable: + * + * 1. Derive the constructor from the consumer of the factory. + * 2. Accept a type as input. + * + * Neither of these are viable, so we instead pass an explicit constructor closure. + * + * Most of these approaches produce either odd compiler errors, or -- worse -- + * compile and then yield runtime EXC_BAD_ACCESS (see Radar 20230159). + * + * For this reason, be careful trying to simplify or improve this code. + */ + open func factory(_ f: @escaping (JSON) -> T) -> (String) -> T? { + return { (payload: String) -> T? in + let potential = EncryptedJSON(json: payload, keyBundle: self) + if !potential.isValid() { + return nil + } + + let cleartext = potential.cleartext + if cleartext == nil { + return nil + } + return f(cleartext!) + } + } + + // TODO: how much do we want to move this into EncryptedJSON? + open func serializer(_ f: @escaping (T) -> JSON) -> (Record) -> JSON? { + return { (record: Record) -> JSON? in + let json = f(record.payload) + if json.isNull() { + // This should never happen, but if it does, we don't want to leak this + // record to the server! + return nil + } + + let bytes: Data + do { + // Get the most basic kind of encoding: no pretty printing. + // This can throw; if so, we return nil. + // `rawData` simply calls JSONSerialization.dataWithJSONObject:options:error, which + // guarantees UTF-8 encoded output. + bytes = try json.rawData(options: []) + } catch { + return nil + } + + // Given a valid non-null JSON object, we don't ever expect a round-trip to fail. + assert(!JSON(bytes).isNull()) + + // We pass a null IV, which means "generate me a new one". + // We then include the generated IV in the resulting record. + if let (ciphertext, iv) = self.encrypt(bytes, iv: nil) { + // So we have the encrypted payload. Now let's build the envelope around it. + let ciphertext = ciphertext.base64EncodedString + + // The HMAC is computed over the base64 string. As bytes. Yes, I know. + if let encodedCiphertextBytes = ciphertext.data(using: String.Encoding.ascii, allowLossyConversion: false) { + let hmac = self.hmacString(encodedCiphertextBytes) + let iv = iv.base64EncodedString + + // The payload is stringified JSON. Yes, I know. + let payload: Any = JSON(object: ["ciphertext": ciphertext, "IV": iv, "hmac": hmac]).stringValue()! as Any + let obj = ["id": record.id, + "sortindex": record.sortindex, + // This is how SwiftyJSON wants us to express a null that we want to + // serialize. Yes, this is gross. + "ttl": record.ttl ?? NSNull(), + "payload": payload] + return JSON(object: obj) + } + } + return nil + } + } + + open func asPair() -> [String] { + return [self.encKey.base64EncodedString, self.hmacKey.base64EncodedString] + } + + open var hashValue: Int { + return "\(self.encKey.base64EncodedString) \(self.hmacKey.base64EncodedString)".hashValue + } +} + +public func == (lhs: KeyBundle, rhs: KeyBundle) -> Bool { + return (lhs.encKey == rhs.encKey) && + (lhs.hmacKey == rhs.hmacKey) +} + +open class Keys: Equatable { + let valid: Bool + let defaultBundle: KeyBundle + var collectionKeys: [String: KeyBundle] = [String: KeyBundle]() + + public init(defaultBundle: KeyBundle) { + self.defaultBundle = defaultBundle + self.valid = true + } + + public init(payload: KeysPayload?) { + if let payload = payload, payload.isValid() { + if let keys = payload.defaultKeys { + self.defaultBundle = keys + self.collectionKeys = payload.collectionKeys + self.valid = true + return + } + } + self.defaultBundle = KeyBundle.invalid + self.valid = false + } + + public convenience init(downloaded: EnvelopeJSON, master: KeyBundle) { + let f: (JSON) -> KeysPayload = { KeysPayload($0) } + let keysRecord = Record.fromEnvelope(downloaded, payloadFactory: master.factory(f)) + self.init(payload: keysRecord?.payload) + } + + open class func random() -> Keys { + return Keys(defaultBundle: KeyBundle.random()) + } + + open func forCollection(_ collection: String) -> KeyBundle { + if let bundle = collectionKeys[collection] { + return bundle + } + return defaultBundle + } + + open func encrypter(_ collection: String, encoder: RecordEncoder) -> RecordEncrypter { + return RecordEncrypter(bundle: forCollection(collection), encoder: encoder) + } + + open func asPayload() -> KeysPayload { + let json: JSON = JSON([ + "id": "keys", + "collection": "crypto", + "default": self.defaultBundle.asPair(), + "collections": mapValues(self.collectionKeys, f: { $0.asPair() }) + ]) + return KeysPayload(json) + } +} + +/** + * Yup, these are basically typed tuples. + */ +public struct RecordEncoder { + let decode: (JSON) -> T + let encode: (T) -> JSON +} + +public struct RecordEncrypter { + let serializer: (Record) -> JSON? + let factory: (String) -> T? + + init(bundle: KeyBundle, encoder: RecordEncoder) { + self.serializer = bundle.serializer(encoder.encode) + self.factory = bundle.factory(encoder.decode) + } + + init(serializer: @escaping (Record) -> JSON?, factory: @escaping (String) -> T?) { + self.serializer = serializer + self.factory = factory + } +} + +public func ==(lhs: Keys, rhs: Keys) -> Bool { + return lhs.valid == rhs.valid && + lhs.defaultBundle == rhs.defaultBundle && + lhs.collectionKeys == rhs.collectionKeys +} diff --git a/mobile/ios/Sync/KeysPayload.swift b/mobile/ios/Sync/KeysPayload.swift new file mode 100644 index 0000000000..72570f07b5 --- /dev/null +++ b/mobile/ios/Sync/KeysPayload.swift @@ -0,0 +1,55 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON + +open class KeysPayload: CleartextPayloadJSON { + override open func isValid() -> Bool { + return super.isValid() && + self["default"].isArray() + } + + fileprivate func keyBundleFromPair(_ input: JSON) -> KeyBundle? { + if let pair: [JSON] = input.array { + if let encKey = pair[0].string { + if let hmacKey = pair[1].string { + return KeyBundle(encKeyB64: encKey, hmacKeyB64: hmacKey) + } + } + } + return nil + } + + var defaultKeys: KeyBundle? { + return self.keyBundleFromPair(self["default"]) + } + + var collectionKeys: [String: KeyBundle] { + if let collections: [String: JSON] = self["collections"].dictionary { + return optFilter(mapValues(collections, f: self.keyBundleFromPair)) + } + return [:] + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + if !(obj is KeysPayload) { + return false + } + + if !super.equalPayloads(obj) { + return false + } + + let p = obj as! KeysPayload + if p.defaultKeys != self.defaultKeys { + return false + } + + // TODO: check collections. + + return true + } +} diff --git a/mobile/ios/Sync/LoginPayload.swift b/mobile/ios/Sync/LoginPayload.swift new file mode 100644 index 0000000000..b1b321c496 --- /dev/null +++ b/mobile/ios/Sync/LoginPayload.swift @@ -0,0 +1,156 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger +import SwiftyJSON + +private let log = Logger.syncLogger + +open class LoginPayload: CleartextPayloadJSON { + fileprivate static let OptionalStringFields = [ + "formSubmitURL", + "httpRealm", + ] + + fileprivate static let OptionalNumericFields = [ + "timeLastUsed", + "timeCreated", + "timePasswordChanged", + "timesUsed", + ] + + fileprivate static let RequiredStringFields = [ + "hostname", + "username", + "password", + "usernameField", + "passwordField", + ] + + open class func fromJSON(_ json: JSON) -> LoginPayload? { + let p = LoginPayload(json) + if p.isValid() { + return p + } + return nil + } + + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + + if self["deleted"].bool ?? false { + return true + } + + if !LoginPayload.RequiredStringFields.every({ self[$0].isString() }) { + return false + } + + if !LoginPayload.OptionalStringFields.every({ field in + let val = self[field] + // Yup, 404 is not found, so this means "string or nothing". + let valid = val.isString() || val.isNull() || val.error?.code == 404 + if !valid { + log.debug("Field \(field) is invalid: \(val)") + } + return valid + }) { + return false + } + + if !LoginPayload.OptionalNumericFields.every({ field in + let val = self[field] + // Yup, 404 is not found, so this means "number or nothing". + // We only check for number because we're including timestamps as NSNumbers. + let valid = val.isNumber() || val.isNull() || val.error?.code == 404 + if !valid { + log.debug("Field \(field) is invalid: \(val)") + } + return valid + }) { + return false + } + + return true + } + + open var hostname: String { + return self["hostname"].string! + } + + open var username: String { + return self["username"].string! + } + + open var password: String { + return self["password"].string! + } + + open var usernameField: String { + return self["usernameField"].string! + } + + open var passwordField: String { + return self["passwordField"].string! + } + + open var formSubmitURL: String? { + return self["formSubmitURL"].string + } + + open var httpRealm: String? { + return self["httpRealm"].string + } + + fileprivate func timestamp(_ field: String) -> Timestamp? { + let json = self[field] + if let i = json.int64, i > 0 { + return Timestamp(i) + } + return nil + } + + open var timesUsed: Int? { + return self["timesUsed"].int + } + + open var timeCreated: Timestamp? { + return self.timestamp("timeCreated") + } + + open var timeLastUsed: Timestamp? { + return self.timestamp("timeLastUsed") + } + + open var timePasswordChanged: Timestamp? { + return self.timestamp("timePasswordChanged") + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + if let p = obj as? LoginPayload { + if !super.equalPayloads(p) { + return false + } + + if p.deleted || self.deleted { + return self.deleted == p.deleted + } + + // If either record is deleted, these other fields might be missing. + // But we just checked, so we're good to roll on. + + return LoginPayload.RequiredStringFields.every({ field in + p[field].string == self[field].string + }) + + // TODO: optional fields. + } + + return false + } +} diff --git a/mobile/ios/Sync/Record.swift b/mobile/ios/Sync/Record.swift new file mode 100644 index 0000000000..b280128d11 --- /dev/null +++ b/mobile/ios/Sync/Record.swift @@ -0,0 +1,98 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger + +private let log = Logger.syncLogger + +let ONE_YEAR_IN_SECONDS = 365 * 24 * 60 * 60 + +/** + * Immutable representation for Sync records. + * + * Envelopes consist of: + * Required: "id", "collection", "payload". + * Optional: "modified", "sortindex", "ttl". + * + * Deletedness is a property of the payload. + */ +open class Record { + open let id: String + open let payload: T + + open let modified: Timestamp + open let sortindex: Int + open let ttl: Int? // Seconds. Can be null, which means 'don't expire'. + + // This is a hook for decryption. + // Right now it only parses the string. In subclasses, it'll parse the + // string, decrypt the contents, and return the data as a JSON object. + // From the docs: + // + // payload none string 256k + // A string containing a JSON structure encapsulating the data of the record. + // This structure is defined separately for each WBO type. + // Parts of the structure may be encrypted, in which case the structure + // should also specify a record for decryption. + // + // @seealso EncryptedRecord. + open class func payloadFromPayloadString(_ envelope: EnvelopeJSON, payload: String) -> T? { + return T(payload) + } + + // TODO: consider using error tuples. + open class func fromEnvelope(_ envelope: EnvelopeJSON, payloadFactory: (String) -> T?) -> Record? { + if !(envelope.isValid()) { + log.error("Invalid envelope.") + return nil + } + guard let payload = payloadFactory(envelope.payload) else { + log.error("Unable to parse payload.") + return nil + } + + if !payload.isValid() { + log.error("Invalid payload \(envelope.payload).") + return nil + } + + return Record(envelope: envelope, payload: payload) + } + + /** + * Accepts an envelope and a decrypted payload. + * Inputs are not validated. Use `fromEnvelope` above. + */ + convenience init(envelope: EnvelopeJSON, payload: T) { + // TODO: modified, sortindex, ttl + self.init(id: envelope.id, payload: payload, modified: envelope.modified, sortindex: envelope.sortindex) + } + + init(id: GUID, payload: T, modified: Timestamp = Timestamp(time(nil)), sortindex: Int = 0, ttl: Int? = nil) { + self.id = id + + self.payload = payload + + self.modified = modified + self.sortindex = sortindex + self.ttl = ttl + } + + func equalIdentifiers(_ rec: Record) -> Bool { + return rec.id == self.id + } + + // Override me. + func equalPayloads(_ rec: Record) -> Bool { + return equalIdentifiers(rec) && rec.payload.deleted == self.payload.deleted + } + + func equals(_ rec: Record) -> Bool { + return rec.sortindex == self.sortindex && + rec.modified == self.modified && + equalPayloads(rec) + } +} diff --git a/mobile/ios/Sync/RequestExtensions.swift b/mobile/ios/Sync/RequestExtensions.swift new file mode 100644 index 0000000000..f890f2c588 --- /dev/null +++ b/mobile/ios/Sync/RequestExtensions.swift @@ -0,0 +1,72 @@ +/* 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/. */ + +import Foundation +import Alamofire +import Shared +import SwiftyJSON + +extension DataRequest { + public func responsePartialParsedJSON(_ completionHandler: @escaping (DataResponse) -> Void) -> Self { + return response(responseSerializer: parsedJSONResponseSerializer(), completionHandler: completionHandler) + } + + public func responsePartialParsedJSON(queue: DispatchQueue, completionHandler: @escaping (DataResponse) -> Void) -> Self { + return response(queue: queue, responseSerializer: partialParsedJSONResponseSerializer(), completionHandler: completionHandler) + } + + public func responseParsedJSON(_ partial: Bool, completionHandler: @escaping (DataResponse) -> Void) -> Self { + return response(responseSerializer: parsedJSONResponseSerializer(), completionHandler: completionHandler) + } + + public func responseParsedJSON(queue: DispatchQueue, completionHandler: @escaping (DataResponse) -> Void) -> Self { + return response(queue: queue, responseSerializer: parsedJSONResponseSerializer(), completionHandler: completionHandler) + } +} + +public enum JSONSerializeError: Error { + case noData + case parseError +} + +private func parsedJSONResponseSerializer() -> DataResponseSerializer { + return DataResponseSerializer() { (request, response, data, error) -> Alamofire.Result in + guard let data = data, !data.isEmpty else { + return .failure(JSONSerializeError.noData) + } + + let json = JSON(data: data) + if json.isError() { + return .failure(JSONSerializeError.parseError) + } + + return .success(json) + } +} + +private func partialParsedJSONResponseSerializer() -> DataResponseSerializer { + return DataResponseSerializer() { (request, response, data, error) -> Alamofire.Result in + guard let data = data, !data.isEmpty else { + return .failure(JSONSerializeError.noData) + } + + let o: Any? + do { + try o = JSONSerialization.jsonObject(with: data, options: .allowFragments) + } catch { + return .failure(JSONSerializeError.parseError) + } + + guard let object = o else { + return .failure(JSONSerializeError.noData) + } + + let json = JSON(object) + if json.isError() { + return .failure(JSONSerializeError.parseError) + } + + return .success(json) + } +} diff --git a/mobile/ios/Sync/State.swift b/mobile/ios/Sync/State.swift new file mode 100644 index 0000000000..4373eb55cd --- /dev/null +++ b/mobile/ios/Sync/State.swift @@ -0,0 +1,579 @@ +/* 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/. */ + +import Foundation +import Shared +import XCGLogger +import SwiftKeychainWrapper +import SwiftyJSON + +private let log = Logger.syncLogger + +/* + * This file includes types that manage intra-sync and inter-sync metadata + * for the use of synchronizers and the state machine. + * + * See docs/sync.md for details on what exactly we need to persist. + */ + +public struct Fetched: Equatable { + let value: T + let timestamp: Timestamp +} + +public func ==(lhs: Fetched, rhs: Fetched) -> Bool { + return lhs.timestamp == rhs.timestamp && + lhs.value == rhs.value +} + +public enum LocalCommand: CustomStringConvertible, Hashable { + // We've seen something (a blank server, a changed global sync ID, a + // crypto/keys with a different meta/global) that requires us to reset all + // local engine timestamps (save the ones listed) and possibly re-upload. + case resetAllEngines(except: Set) + + // We've seen something (a changed engine sync ID, a crypto/keys with a + // different per-engine bulk key) that requires us to reset our local engine + // timestamp and possibly re-upload. + case resetEngine(engine: String) + + // We've seen a change in meta/global: an engine has come or gone. + case enableEngine(engine: String) + case disableEngine(engine: String) + + public func toJSON() -> JSON { + switch self { + case let .resetAllEngines(except): + return JSON(["type": "ResetAllEngines", "except": Array(except).sorted()]) + + case let .resetEngine(engine): + return JSON(["type": "ResetEngine", "engine": engine]) + + case let .enableEngine(engine): + return JSON(["type": "EnableEngine", "engine": engine]) + + case let .disableEngine(engine): + return JSON(["type": "DisableEngine", "engine": engine]) + } + } + + public static func fromJSON(_ json: JSON) -> LocalCommand? { + if json.isError() { + return nil + } + guard let type = json["type"].string else { + return nil + } + switch type { + case "ResetAllEngines": + if let except = json["except"].array, except.every({$0.isString()}) { + return .resetAllEngines(except: Set(except.map({$0.stringValue}))) + } + return nil + case "ResetEngine": + if let engine = json["engine"].string { + return .resetEngine(engine: engine) + } + return nil + case "EnableEngine": + if let engine = json["engine"].string { + return .enableEngine(engine: engine) + } + return nil + case "DisableEngine": + if let engine = json["engine"].string { + return .disableEngine(engine: engine) + } + return nil + default: + return nil + } + } + + public var description: String { + return self.toJSON().description + } + + public var hashValue: Int { + return self.description.hashValue + } +} + +public func ==(lhs: LocalCommand, rhs: LocalCommand) -> Bool { + switch (lhs, rhs) { + case (let .resetAllEngines(exceptL), let .resetAllEngines(exceptR)): + return exceptL == exceptR + + case (let .resetEngine(engineL), let .resetEngine(engineR)): + return engineL == engineR + + case (let .enableEngine(engineL), let .enableEngine(engineR)): + return engineL == engineR + + case (let .disableEngine(engineL), let .disableEngine(engineR)): + return engineL == engineR + + default: + return false + } +} + +/* + * Persistence pref names. + * Note that syncKeyBundle isn't persisted by us. + * + * Note also that fetched keys aren't kept in prefs: we keep the timestamp ("PrefKeysTS"), + * and we keep a 'label'. This label is used to find the real fetched keys in the Keychain. + */ + +private let PrefVersion = "_v" +private let PrefGlobal = "global" +private let PrefGlobalTS = "globalTS" +private let PrefKeyLabel = "keyLabel" +private let PrefKeysTS = "keysTS" +private let PrefLastFetched = "lastFetched" +private let PrefLocalCommands = "localCommands" +private let PrefClientName = "clientName" +private let PrefClientGUID = "clientGUID" +private let PrefHashedUID = "hashedUID" +private let PrefEngineConfiguration = "engineConfiguration" +private let PrefDeviceID = "deviceID" + +class PrefsBackoffStorage: BackoffStorage { + let prefs: Prefs + fileprivate let key = "timestamp" + + init(prefs: Prefs) { + self.prefs = prefs + } + + var serverBackoffUntilLocalTimestamp: Timestamp? { + get { + return self.prefs.unsignedLongForKey(self.key) + } + + set(value) { + if let value = value { + self.prefs.setLong(value, forKey: self.key) + } else { + self.prefs.removeObjectForKey(self.key) + } + } + } + + func clearServerBackoff() { + self.prefs.removeObjectForKey(self.key) + } + + func isInBackoff(_ now: Timestamp) -> Timestamp? { + if let ts = self.serverBackoffUntilLocalTimestamp, now < ts { + return ts + } + return nil + } +} + +/** + * The scratchpad consists of the following: + * + * 1. Cached records. We cache meta/global and crypto/keys until they change. + * 2. Metadata like timestamps, both for cached records and for server fetches. + * 3. User preferences -- engine enablement. + * 4. Client record state. + * 5. Local commands that have yet to be processed. + * + * Note that the scratchpad itself is immutable, but is a class passed by reference. + * Its mutable fields can be mutated, but you can't accidentally e.g., switch out + * meta/global and get confused. + * + * TODO: the Scratchpad needs to be loaded from persistent storage, and written + * back at certain points in the state machine (after a replayable action is taken). + */ +open class Scratchpad { + open class Builder { + var syncKeyBundle: KeyBundle // For the love of god, if you change this, invalidate keys, too! + fileprivate var global: Fetched? + fileprivate var keys: Fetched? + fileprivate var keyLabel: String + var localCommands: Set + var engineConfiguration: EngineConfiguration? + var clientGUID: String + var clientName: String + var fxaDeviceId: String + var hashedUID: String? + var prefs: Prefs + + init(p: Scratchpad) { + self.syncKeyBundle = p.syncKeyBundle + self.prefs = p.prefs + + self.global = p.global + + self.keys = p.keys + self.keyLabel = p.keyLabel + self.localCommands = p.localCommands + self.engineConfiguration = p.engineConfiguration + self.clientGUID = p.clientGUID + self.clientName = p.clientName + self.fxaDeviceId = p.fxaDeviceId + self.hashedUID = p.hashedUID + } + + open func clearLocalCommands() -> Builder { + self.localCommands.removeAll() + return self + } + + open func addLocalCommandsFromKeys(_ keys: Fetched?) -> Builder { + // Getting new keys can force local collection resets. + guard let freshKeys = keys?.value, let staleKeys = self.keys?.value, staleKeys.valid else { + // Removing keys, or new keys and either we didn't have old keys or they weren't valid. Everybody gets a reset! + self.localCommands.insert(LocalCommand.resetAllEngines(except: [])) + return self + } + + // New keys, and we have valid old keys. + if freshKeys.defaultBundle != staleKeys.defaultBundle { + // Default bundle has changed. Reset everything but collections that have unchanged bulk keys. + var except: Set = Set() + // Symmetric difference, like an animal. Swift doesn't allow Hashable tuples; don't fight it. + for (collection, keyBundle) in staleKeys.collectionKeys { + if keyBundle == freshKeys.forCollection(collection) { + except.insert(collection) + } + } + for (collection, keyBundle) in freshKeys.collectionKeys { + if keyBundle == staleKeys.forCollection(collection) { + except.insert(collection) + } + } + self.localCommands.insert(.resetAllEngines(except: except)) + } else { + // Default bundle is the same. Reset collections that have changed bulk keys. + for (collection, keyBundle) in staleKeys.collectionKeys { + if keyBundle != freshKeys.forCollection(collection) { + self.localCommands.insert(.resetEngine(engine: collection)) + } + } + for (collection, keyBundle) in freshKeys.collectionKeys { + if keyBundle != staleKeys.forCollection(collection) { + self.localCommands.insert(.resetEngine(engine: collection)) + } + } + } + return self + } + + open func setKeys(_ keys: Fetched?) -> Builder { + self.keys = keys + return self + } + + open func setGlobal(_ global: Fetched?) -> Builder { + self.global = global + if let global = global { + // We always take the incoming meta/global's engine configuration. + self.engineConfiguration = global.value.engineConfiguration() + } + return self + } + + open func setEngineConfiguration(_ engineConfiguration: EngineConfiguration?) -> Builder { + self.engineConfiguration = engineConfiguration + return self + } + + open func build() -> Scratchpad { + return Scratchpad( + b: self.syncKeyBundle, + m: self.global, + k: self.keys, + keyLabel: self.keyLabel, + localCommands: self.localCommands, + engines: self.engineConfiguration, + clientGUID: self.clientGUID, + clientName: self.clientName, + fxaDeviceId: self.fxaDeviceId, + hashedUID: self.hashedUID, + persistingTo: self.prefs + ) + } + } + + open lazy var backoffStorage: BackoffStorage = { + return PrefsBackoffStorage(prefs: self.prefs.branch("backoff.storage")) + }() + + open func evolve() -> Scratchpad.Builder { + return Scratchpad.Builder(p: self) + } + + // This is never persisted. + let syncKeyBundle: KeyBundle + + // Cached records. + // This cached meta/global is what we use to add or remove enabled engines. See also + // engineConfiguration, below. + // We also use it to detect when meta/global hasn't changed -- compare timestamps. + // + // Note that a Scratchpad held by a Ready state will have the current server meta/global + // here. That means we don't need to track syncIDs separately (which is how desktop and + // Android are implemented). + // If we don't have a meta/global, and thus we don't know syncIDs, it means we haven't + // synced with this server before, and we'll do a fresh sync. + let global: Fetched? + + // We don't store these keys (so-called "collection keys" or "bulk keys") in Prefs. + // Instead, we store a label, which is seeded when you first create a Scratchpad. + // This label is used to retrieve the real keys from your Keychain. + // + // Note that we also don't store the syncKeyBundle here. That's always created from kB, + // provided by the Firefox Account. + // + // Why don't we derive the label from your Sync Key? Firstly, we'd like to be able to + // clean up without having your key. Secondly, we don't want to accidentally load keys + // from the Keychain just because the Sync Key is the same -- e.g., after a node + // reassignment. Randomly generating a label offers all of the benefits with none of the + // problems, with only the cost of persisting that label alongside the rest of the state. + let keys: Fetched? + let keyLabel: String + + // Local commands. + var localCommands: Set + + // Enablement states. + let engineConfiguration: EngineConfiguration? + + // What's our client name? + let clientName: String + let clientGUID: String + let fxaDeviceId: String + let hashedUID: String? + + var hashedDeviceID: String? { + guard let hashedUID = hashedUID else { + return nil + } + return (fxaDeviceId + hashedUID).sha256.hexEncodedString + } + + // Where do we persist when told? + let prefs: Prefs + + init(b: KeyBundle, + m: Fetched?, + k: Fetched?, + keyLabel: String, + localCommands: Set, + engines: EngineConfiguration?, + clientGUID: String, + clientName: String, + fxaDeviceId: String, + hashedUID: String?, + persistingTo prefs: Prefs + ) { + self.syncKeyBundle = b + self.prefs = prefs + + self.keys = k + self.keyLabel = keyLabel + self.global = m + self.engineConfiguration = engines + self.localCommands = localCommands + self.clientGUID = clientGUID + self.clientName = clientName + self.fxaDeviceId = fxaDeviceId + self.hashedUID = hashedUID + } + + // This should never be used in the end; we'll unpickle instead. + // This should be a convenience initializer, but... Swift compiler bug? + init(b: KeyBundle, persistingTo prefs: Prefs) { + self.syncKeyBundle = b + self.prefs = prefs + + self.keys = nil + self.keyLabel = Bytes.generateGUID() + self.global = nil + self.engineConfiguration = nil + self.localCommands = Set() + self.clientGUID = Bytes.generateGUID() + self.clientName = DeviceInfo.defaultClientName() + + self.fxaDeviceId = "unknown_fxaDeviceId" + + self.hashedUID = nil + } + + func freshStartWithGlobal(_ global: Fetched) -> Scratchpad { + // TODO: I *think* a new keyLabel is unnecessary. + return self.evolve() + .setGlobal(global) + .addLocalCommandsFromKeys(nil) + .setKeys(nil) + .build() + } + + fileprivate class func unpickleV1FromPrefs(_ prefs: Prefs, syncKeyBundle: KeyBundle) -> Scratchpad { + let b = Scratchpad(b: syncKeyBundle, persistingTo: prefs).evolve() + + if let mg = prefs.stringForKey(PrefGlobal) { + if let mgTS = prefs.unsignedLongForKey(PrefGlobalTS) { + if let global = MetaGlobal.fromJSON(JSON(parseJSON: mg)) { + _ = b.setGlobal(Fetched(value: global, timestamp: mgTS)) + } else { + log.error("Malformed meta/global in prefs. Ignoring.") + } + } else { + // This should never happen. + log.error("Found global in prefs, but not globalTS!") + } + } + + if let keyLabel = prefs.stringForKey(PrefKeyLabel) { + b.keyLabel = keyLabel + if let ckTS = prefs.unsignedLongForKey(PrefKeysTS) { + let key = "keys." + keyLabel + KeychainWrapper.sharedAppContainerKeychain.ensureStringItemAccessibility(.afterFirstUnlock, forKey: key) + if let keys = KeychainWrapper.sharedAppContainerKeychain.string(forKey: key) { + // We serialize as JSON. + let keys = Keys(payload: KeysPayload(keys)) + if keys.valid { + log.debug("Read keys from Keychain with label \(keyLabel).") + _ = b.setKeys(Fetched(value: keys, timestamp: ckTS)) + } else { + log.error("Invalid keys extracted from Keychain. Discarding.") + } + } else { + log.error("Found keysTS in prefs, but didn't find keys in Keychain!") + } + } + } + + b.clientGUID = prefs.stringForKey(PrefClientGUID) ?? { + log.error("No value found in prefs for client GUID! Generating one.") + return Bytes.generateGUID() + }() + + b.clientName = prefs.stringForKey(PrefClientName) ?? { + log.error("No value found in prefs for client name! Using default.") + return DeviceInfo.defaultClientName() + }() + + b.hashedUID = prefs.stringForKey(PrefHashedUID) + + b.fxaDeviceId = prefs.stringForKey(PrefDeviceID) ?? { + // Migrate from previous way of storing device id. + // This code will only be run once – the id will be stored + // in PrefDeviceID. + let PrefDeviceRegistration = "deviceRegistration" + if let string = prefs.stringForKey(PrefDeviceRegistration) { + let json = JSON(parseJSON: string) + if let id = json["id"].string { + return id + } + prefs.removeObjectForKey(PrefDeviceRegistration) + } + // This is run the first time we sync with a new account. + // It will be replaced by a real fxaDeviceId, from account.deviceRegistration?.id. + log.warning("No value found in prefs for fxaDeviceId! Will overwrite on first sync") + return "unknown_fxaDeviceId" + }() + + if let localCommands: [String] = prefs.stringArrayForKey(PrefLocalCommands) { + b.localCommands = Set(localCommands.flatMap({LocalCommand.fromJSON(JSON(parseJSON: $0))})) + } + + if let engineConfigurationString = prefs.stringForKey(PrefEngineConfiguration) { + if let engineConfiguration = EngineConfiguration.fromJSON(JSON(parseJSON: engineConfigurationString)) { + b.engineConfiguration = engineConfiguration + } else { + log.error("Invalid engineConfiguration found in prefs. Discarding.") + } + } + + return b.build() + } + + /** + * Remove anything that might be left around after prefs is wiped. + */ + open class func clearFromPrefs(_ prefs: Prefs) { + if let keyLabel = prefs.stringForKey(PrefKeyLabel) { + log.debug("Removing saved key from keychain.") + KeychainWrapper.sharedAppContainerKeychain.removeObject(forKey: keyLabel) + } else { + log.debug("No key label; nothing to remove from keychain.") + } + } + + open class func restoreFromPrefs(_ prefs: Prefs, syncKeyBundle: KeyBundle) -> Scratchpad? { + if let ver = prefs.intForKey(PrefVersion) { + switch ver { + case 1: + return unpickleV1FromPrefs(prefs, syncKeyBundle: syncKeyBundle) + default: + return nil + } + } + + log.debug("No scratchpad found in prefs.") + return nil + } + + /** + * Persist our current state to our origin prefs. + * Note that calling this from multiple threads with either mutated or evolved + * scratchpads will cause sadness — individual writes are thread-safe, but the + * overall pseudo-transaction is not atomic. + */ + open func checkpoint() -> Scratchpad { + return pickle(self.prefs) + } + + func pickle(_ prefs: Prefs) -> Scratchpad { + prefs.setInt(1, forKey: PrefVersion) + if let global = global { + prefs.setLong(global.timestamp, forKey: PrefGlobalTS) + prefs.setString(global.value.asPayload().json.stringValue()!, forKey: PrefGlobal) + } else { + prefs.removeObjectForKey(PrefGlobal) + prefs.removeObjectForKey(PrefGlobalTS) + } + + // We store the meat of your keys in the Keychain, using a random identifier that we persist in prefs. + prefs.setString(self.keyLabel, forKey: PrefKeyLabel) + if let keys = self.keys, + let payload = keys.value.asPayload().json.stringValue() { + let label = "keys." + self.keyLabel + log.debug("Storing keys in Keychain with label \(label).") + prefs.setString(self.keyLabel, forKey: PrefKeyLabel) + prefs.setLong(keys.timestamp, forKey: PrefKeysTS) + KeychainWrapper.sharedAppContainerKeychain.set(payload, forKey: label, withAccessibility: .afterFirstUnlock) + } else { + log.debug("Removing keys from Keychain.") + KeychainWrapper.sharedAppContainerKeychain.removeObject(forKey: self.keyLabel) + } + + prefs.setString(clientName, forKey: PrefClientName) + prefs.setString(clientGUID, forKey: PrefClientGUID) + + if let uid = hashedUID { + prefs.setString(uid, forKey: PrefHashedUID) + } + + prefs.setString(fxaDeviceId, forKey: PrefDeviceID) + + let localCommands: [String] = Array(self.localCommands).map({$0.toJSON().stringValue()!}) + prefs.setObject(localCommands, forKey: PrefLocalCommands) + + if let engineConfiguration = self.engineConfiguration { + prefs.setString(engineConfiguration.toJSON().stringValue()!, forKey: PrefEngineConfiguration) + } else { + prefs.removeObjectForKey(PrefEngineConfiguration) + } + + return self + } +} diff --git a/mobile/ios/Sync/StorageClient.swift b/mobile/ios/Sync/StorageClient.swift new file mode 100644 index 0000000000..e8f80d4d4f --- /dev/null +++ b/mobile/ios/Sync/StorageClient.swift @@ -0,0 +1,820 @@ +/* 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/. */ + +import Foundation +import Alamofire +import Shared +import Account +import XCGLogger +import Deferred +import SwiftyJSON + +private let log = Logger.syncLogger + +// Not an error that indicates a server problem, but merely an +// error that encloses a StorageResponse. +open class StorageResponseError: MaybeErrorType, SyncPingFailureFormattable { + open let response: StorageResponse + + open var failureReasonName: SyncPingFailureReasonName { + return .httpError + } + + public init(_ response: StorageResponse) { + self.response = response + } + + open var description: String { + return "Error." + } +} + +open class RequestError: MaybeErrorType, SyncPingFailureFormattable { + open var failureReasonName: SyncPingFailureReasonName { + return .httpError + } + + open var description: String { + return "Request error." + } +} + +open class BadRequestError: StorageResponseError { + open let request: URLRequest? + + public init(request: URLRequest?, response: StorageResponse) { + self.request = request + super.init(response) + } + + override open var description: String { + return "Bad request." + } +} + +open class ServerError: StorageResponseError { + override open var description: String { + return "Server error." + } + + override public init(_ response: StorageResponse) { + super.init(response) + } +} + +open class NotFound: StorageResponseError { + override open var description: String { + return "Not found. (\(T.self))" + } + + override public init(_ response: StorageResponse) { + super.init(response) + } +} + +open class RecordParseError: MaybeErrorType, SyncPingFailureFormattable { + open var description: String { + return "Failed to parse record." + } + + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } +} + +open class MalformedMetaGlobalError: MaybeErrorType, SyncPingFailureFormattable { + open var description: String { + return "Supplied meta/global for upload did not serialize to valid JSON." + } + + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } +} + +open class RecordTooLargeError: MaybeErrorType, SyncPingFailureFormattable { + open let guid: GUID + open let size: ByteCount + + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } + + public init(size: ByteCount, guid: GUID) { + self.size = size + self.guid = guid + } + + open var description: String { + return "Record \(self.guid) too large: \(size) bytes." + } +} + +/** + * Raised when the storage client is refusing to make a request due to a known + * server backoff. + * If you want to bypass this, remove the backoff from the BackoffStorage that + * the storage client is using. + */ +open class ServerInBackoffError: MaybeErrorType, SyncPingFailureFormattable { + fileprivate let until: Timestamp + + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } + + open var description: String { + let formatter = DateFormatter() + formatter.dateStyle = DateFormatter.Style.short + formatter.timeStyle = DateFormatter.Style.medium + let s = formatter.string(from: Date.fromTimestamp(self.until)) + return "Server in backoff until \(s)." + } + + public init(until: Timestamp) { + self.until = until + } +} + +// Returns milliseconds. Handles decimals. +private func optionalSecondsHeader(_ input: AnyObject?) -> Timestamp? { + if input == nil { + return nil + } + + if let val = input as? String { + if let timestamp = decimalSecondsStringToTimestamp(val) { + return timestamp + } + } + + if let seconds: Double = input as? Double { + // Oh for a BigDecimal library. + return Timestamp(seconds * 1000) + } + + if let seconds: NSNumber = input as? NSNumber { + // Who knows. + return seconds.uint64Value * 1000 + } + + return nil +} + +private func optionalIntegerHeader(_ input: AnyObject?) -> Int64? { + if input == nil { + return nil + } + + if let val = input as? String { + return Scanner(string: val).scanLongLong() + } + + if let val: Double = input as? Double { + // Oh for a BigDecimal library. + return Int64(val) + } + + if let val: NSNumber = input as? NSNumber { + // Who knows. + return val.int64Value + } + + return nil +} + +private func optionalUIntegerHeader(_ input: AnyObject?) -> Timestamp? { + if input == nil { + return nil + } + + if let val = input as? String { + return Scanner(string: val).scanUnsignedLongLong() + } + + if let val: Double = input as? Double { + // Oh for a BigDecimal library. + return Timestamp(val) + } + + if let val: NSNumber = input as? NSNumber { + // Who knows. + return val.uint64Value + } + + return nil +} + +public enum SortOption: String { + case NewestFirst = "newest" + case OldestFirst = "oldest" + case Index = "index" +} + +public struct ResponseMetadata { + public let status: Int + public let alert: String? + public let nextOffset: String? + public let records: UInt64? + public let quotaRemaining: Int64? + public let timestampMilliseconds: Timestamp // Non-optional. Server timestamp when handling request. + public let lastModifiedMilliseconds: Timestamp? // Included for all success responses. Collection or record timestamp. + public let backoffMilliseconds: UInt64? + public let retryAfterMilliseconds: UInt64? + + public init(response: HTTPURLResponse) { + self.init(status: response.statusCode, headers: response.allHeaderFields) + } + + init(status: Int, headers: [AnyHashable: Any]) { + self.status = status + alert = headers["X-Weave-Alert"] as? String + nextOffset = headers["X-Weave-Next-Offset"] as? String + records = optionalUIntegerHeader(headers["X-Weave-Records"] as AnyObject?) + quotaRemaining = optionalIntegerHeader(headers["X-Weave-Quota-Remaining"] as AnyObject?) + timestampMilliseconds = optionalSecondsHeader(headers["X-Weave-Timestamp"] as AnyObject?) ?? 0 + lastModifiedMilliseconds = optionalSecondsHeader(headers["X-Last-Modified"] as AnyObject?) + backoffMilliseconds = optionalSecondsHeader(headers["X-Weave-Backoff"] as AnyObject?) ?? + optionalSecondsHeader(headers["X-Backoff"] as AnyObject?) + retryAfterMilliseconds = optionalSecondsHeader(headers["Retry-After"] as AnyObject?) + } +} + +public struct StorageResponse { + public let value: T + public let metadata: ResponseMetadata + + init(value: T, metadata: ResponseMetadata) { + self.value = value + self.metadata = metadata + } + + init(value: T, response: HTTPURLResponse) { + self.value = value + self.metadata = ResponseMetadata(response: response) + } +} + +public typealias BatchToken = String + +public typealias ByteCount = Int + +public struct POSTResult { + public let success: [GUID] + public let failed: [GUID: String] + public let batchToken: BatchToken? + + public init(success: [GUID], failed: [GUID: String], batchToken: BatchToken? = nil) { + self.success = success + self.failed = failed + self.batchToken = batchToken + } + + public static func fromJSON(_ json: JSON) -> POSTResult? { + if json.isError() { + return nil + } + + let batchToken = json["batch"].string + + if let s = json["success"].array, + let f = json["failed"].dictionary { + var failed = false + let stringOrFail: (JSON) -> String = { $0.string ?? { failed = true; return "" }() } + + // That's the basic structure. Now let's transform the contents. + let successGUIDs = s.map(stringOrFail) + if failed { + return nil + } + let failedGUIDs = mapValues(f, f: stringOrFail) + if failed { + return nil + } + return POSTResult(success: successGUIDs, failed: failedGUIDs, batchToken: batchToken) + } + return nil + } +} + +public typealias Authorizer = (URLRequest) -> URLRequest + +// TODO: don't be so naïve. Use a combination of uptime and wall clock time. +public protocol BackoffStorage { + var serverBackoffUntilLocalTimestamp: Timestamp? { get set } + func clearServerBackoff() + func isInBackoff(_ now: Timestamp) -> Timestamp? // Returns 'until' for convenience. +} + +// Don't forget to batch downloads. +open class Sync15StorageClient { + fileprivate let authorizer: Authorizer + fileprivate let serverURI: URL + + open static let maxRecordSizeBytes: Int = 262_140 // A shade under 256KB. + open static let maxPayloadSizeBytes: Int = 1_000_000 // A shade under 1MB. + open static let maxPayloadItemCount: Int = 100 // Bug 1250747 will raise this. + + var backoff: BackoffStorage + + let workQueue: DispatchQueue + let resultQueue: DispatchQueue + + public init(token: TokenServerToken, workQueue: DispatchQueue, resultQueue: DispatchQueue, backoff: BackoffStorage) { + self.workQueue = workQueue + self.resultQueue = resultQueue + self.backoff = backoff + + // This is a potentially dangerous assumption, but failable initializers up the stack are a giant pain. + // We want the serverURI to *not* have a trailing slash: to efficiently wipe a user's storage, we delete + // the user root (like /1.5/1234567) and not an "empty collection" (like /1.5/1234567/); the storage + // server treats the first like a DROP table and the latter like a DELETE *, and the former is more + // efficient than the latter. + self.serverURI = URL(string: token.api_endpoint.endsWith("/") + ? token.api_endpoint.substring(to: token.api_endpoint.index(before: token.api_endpoint.endIndex)) + : token.api_endpoint)! + self.authorizer = { + (r: URLRequest) -> URLRequest in + var req = r + let helper = HawkHelper(id: token.id, key: token.key.data(using: String.Encoding.utf8, allowLossyConversion: false)!) + req.setValue(helper.getAuthorizationValueFor(r), forHTTPHeaderField: "Authorization") + return req + } + } + + public init(serverURI: URL, authorizer: @escaping Authorizer, workQueue: DispatchQueue, resultQueue: DispatchQueue, backoff: BackoffStorage) { + self.serverURI = serverURI + self.authorizer = authorizer + self.workQueue = workQueue + self.resultQueue = resultQueue + self.backoff = backoff + } + + func updateBackoffFromResponse(_ response: StorageResponse) { + // N.B., we would not have made this request if a backoff were set, so + // we can safely avoid doing the write if there's no backoff in the + // response. + // This logic will have to change if we ever invalidate that assumption. + if let ms = response.metadata.backoffMilliseconds ?? response.metadata.retryAfterMilliseconds { + log.info("Backing off for \(ms)ms.") + self.backoff.serverBackoffUntilLocalTimestamp = ms + Date.now() + } + } + + func errorWrap(_ deferred: Deferred>, handler: @escaping (DataResponse) -> Void) -> (DataResponse) -> Void { + return { response in + log.verbose("Response is \(response.response ??? "nil").") + + /** + * Returns true if handled. + */ + func failFromResponse(_ HTTPResponse: HTTPURLResponse?) -> Bool { + guard let HTTPResponse = HTTPResponse else { + // TODO: better error. + log.error("No response") + let result = Maybe(failure: RecordParseError()) + deferred.fill(result) + return true + } + + log.debug("Status code: \(HTTPResponse.statusCode).") + + let storageResponse = StorageResponse(value: HTTPResponse, metadata: ResponseMetadata(response: HTTPResponse)) + + self.updateBackoffFromResponse(storageResponse) + + if HTTPResponse.statusCode >= 500 { + log.debug("ServerError.") + let result = Maybe(failure: ServerError(storageResponse)) + deferred.fill(result) + return true + } + + if HTTPResponse.statusCode == 404 { + log.debug("NotFound<\(T.self)>.") + let result = Maybe(failure: NotFound(storageResponse)) + deferred.fill(result) + return true + } + + if HTTPResponse.statusCode >= 400 { + log.debug("BadRequestError.") + let result = Maybe(failure: BadRequestError(request: response.request, response: storageResponse)) + deferred.fill(result) + return true + } + + return false + } + + // Check for an error from the request processor. + if response.result.isFailure { + log.error("Response: \(response.response?.statusCode ?? 0). Got error \(response.result.error ??? "nil").") + + // If we got one, we don't want to hit the response nil case above and + // return a RecordParseError, because a RequestError is more fitting. + if let response = response.response { + if failFromResponse(response) { + log.error("This was a failure response. Filled specific error type.") + return + } + } + + log.error("Filling generic RequestError.") + deferred.fill(Maybe(failure: RequestError())) + return + } + + if failFromResponse(response.response) { + return + } + + handler(response) + } + } + + lazy fileprivate var alamofire: SessionManager = { + let ua = UserAgent.syncUserAgent + let configuration = URLSessionConfiguration.ephemeral + var defaultHeaders = SessionManager.default.session.configuration.httpAdditionalHeaders ?? [:] + defaultHeaders["User-Agent"] = ua + configuration.httpAdditionalHeaders = defaultHeaders + return SessionManager(configuration: configuration) + }() + + func requestGET(_ url: URL) -> DataRequest { + var req = URLRequest(url: url as URL) + req.httpMethod = URLRequest.Method.get.rawValue + req.setValue("application/json", forHTTPHeaderField: "Accept") + let authorized: URLRequest = self.authorizer(req) + return alamofire.request(authorized) + .validate(contentType: ["application/json"]) + } + + func requestDELETE(_ url: URL) -> DataRequest { + var req = URLRequest(url: url as URL) + req.httpMethod = URLRequest.Method.delete.rawValue + req.setValue("1", forHTTPHeaderField: "X-Confirm-Delete") + let authorized: URLRequest = self.authorizer(req) + return alamofire.request(authorized) + } + + func requestWrite(_ url: URL, method: String, body: String, contentType: String, ifUnmodifiedSince: Timestamp?) -> Request { + var req = URLRequest(url: url as URL) + req.httpMethod = method + req.setValue(contentType, forHTTPHeaderField: "Content-Type") + + if let ifUnmodifiedSince = ifUnmodifiedSince { + req.setValue(millisecondsToDecimalSeconds(ifUnmodifiedSince), forHTTPHeaderField: "X-If-Unmodified-Since") + } + + req.httpBody = body.data(using: String.Encoding.utf8)! + let authorized: URLRequest = self.authorizer(req) + return alamofire.request(authorized) + } + + func requestPUT(_ url: URL, body: JSON, ifUnmodifiedSince: Timestamp?) -> Request { + return self.requestWrite(url, method: URLRequest.Method.put.rawValue, body: body.stringValue()!, contentType: "application/json;charset=utf-8", ifUnmodifiedSince: ifUnmodifiedSince) + } + + func requestPOST(_ url: URL, body: JSON, ifUnmodifiedSince: Timestamp?) -> Request { + return self.requestWrite(url, method: URLRequest.Method.post.rawValue, body: body.stringValue()!, contentType: "application/json;charset=utf-8", ifUnmodifiedSince: ifUnmodifiedSince) + } + + func requestPOST(_ url: URL, body: [String], ifUnmodifiedSince: Timestamp?) -> Request { + let content = body.joined(separator: "\n") + return self.requestWrite(url, method: URLRequest.Method.post.rawValue, body: content, contentType: "application/newlines", ifUnmodifiedSince: ifUnmodifiedSince) + } + + func requestPOST(_ url: URL, body: [JSON], ifUnmodifiedSince: Timestamp?) -> Request { + return self.requestPOST(url, body: body.map { $0.stringValue()! }, ifUnmodifiedSince: ifUnmodifiedSince) + } + + /** + * Returns true and fills the provided Deferred if our state shows that we're in backoff. + * Returns false otherwise. + */ + fileprivate func checkBackoff(_ deferred: Deferred>) -> Bool { + if let until = self.backoff.isInBackoff(Date.now()) { + deferred.fill(Maybe(failure: ServerInBackoffError(until: until))) + return true + } + return false + } + + fileprivate func doOp(_ op: (URL) -> DataRequest, path: String, f: @escaping (JSON) -> T?) -> Deferred>> { + + let deferred = Deferred>>(defaultQueue: self.resultQueue) + + if self.checkBackoff(deferred) { + return deferred + } + + // Special case "": we want /1.5/1234567 and not /1.5/1234567/. See note about trailing slashes above. + let url: URL + if path == "" { + url = self.serverURI // No trailing slash. + } else { + url = self.serverURI.appendingPathComponent(path) + + } + + let req = op(url) + let handler = self.errorWrap(deferred) { (response: DataResponse) in + if let json: JSON = response.result.value { + if let v = f(json) { + let storageResponse = StorageResponse(value: v, response: response.response!) + deferred.fill(Maybe(success: storageResponse)) + } else { + deferred.fill(Maybe(failure: RecordParseError())) + } + return + } + + deferred.fill(Maybe(failure: RecordParseError())) + } + + _ = req.responseParsedJSON(true, completionHandler: handler) + return deferred + } + + // Sync storage responds with a plain timestamp to a PUT, not with a JSON body. + fileprivate func putResource(_ path: String, body: JSON, ifUnmodifiedSince: Timestamp?, parser: @escaping (String) -> T?) -> Deferred>> { + let url = self.serverURI.appendingPathComponent(path) + return self.putResource(url, body: body, ifUnmodifiedSince: ifUnmodifiedSince, parser: parser) + } + + fileprivate func putResource(_ URL: Foundation.URL, body: JSON, ifUnmodifiedSince: Timestamp?, parser: @escaping (String) -> T?) -> Deferred>> { + + let deferred = Deferred>>(defaultQueue: self.resultQueue) + if self.checkBackoff(deferred) { + return deferred + } + + let req = self.requestPUT(URL, body: body, ifUnmodifiedSince: ifUnmodifiedSince) as! DataRequest + let handler = self.errorWrap(deferred) { (response: DataResponse) in + if let data = response.result.value { + if let v = parser(data) { + let storageResponse = StorageResponse(value: v, response: response.response!) + deferred.fill(Maybe(success: storageResponse)) + } else { + deferred.fill(Maybe(failure: RecordParseError())) + } + return + } + deferred.fill(Maybe(failure: RecordParseError())) + } + req.responseString(completionHandler: handler) + return deferred + } + + fileprivate func getResource(_ path: String, f: @escaping (JSON) -> T?) -> Deferred>> { + return doOp(self.requestGET, path: path, f: f) + } + + fileprivate func deleteResource(_ path: String, f: @escaping (JSON) -> T?) -> Deferred>> { + return doOp(self.requestDELETE, path: path, f: f) + } + + func wipeStorage() -> Deferred>> { + // In Sync 1.5 it's preferred that we delete the root, not /storage. + return deleteResource("", f: { $0 }) + } + + func getInfoCollections() -> Deferred>> { + return getResource("info/collections", f: InfoCollections.fromJSON) + } + + func getMetaGlobal() -> Deferred>> { + return getResource("storage/meta/global") { json in + // We have an envelope. Parse the meta/global record embedded in the 'payload' string. + let envelope = EnvelopeJSON(json) + if envelope.isValid() { + return MetaGlobal.fromJSON(JSON(parseJSON: envelope.payload)) + } + return nil + } + } + + func getCryptoKeys(_ syncKeyBundle: KeyBundle, ifUnmodifiedSince: Timestamp?) -> Deferred>>> { + let syncKey = Keys(defaultBundle: syncKeyBundle) + let encoder = RecordEncoder(decode: { KeysPayload($0) }, encode: { $0.json }) + let encrypter = syncKey.encrypter("keys", encoder: encoder) + let client = self.clientForCollection("crypto", encrypter: encrypter) + return client.get("keys") + } + + func uploadMetaGlobal(_ metaGlobal: MetaGlobal, ifUnmodifiedSince: Timestamp?) -> Deferred>> { + let payload = metaGlobal.asPayload() + if payload.json.isError() { + return Deferred(value: Maybe(failure: MalformedMetaGlobalError())) + } + + let record: JSON = JSON(object: ["payload": payload.json.stringValue() ?? JSON.null as Any, "id": "global"]) + return putResource("storage/meta/global", body: record, ifUnmodifiedSince: ifUnmodifiedSince, parser: decimalSecondsStringToTimestamp) + } + + // The crypto/keys record is a special snowflake: it is encrypted with the Sync key bundle. All other records are + // encrypted with the bulk key bundle (including possibly a per-collection bulk key) stored in crypto/keys. + func uploadCryptoKeys(_ keys: Keys, withSyncKeyBundle syncKeyBundle: KeyBundle, ifUnmodifiedSince: Timestamp?) -> Deferred>> { + let syncKey = Keys(defaultBundle: syncKeyBundle) + let encoder = RecordEncoder(decode: { KeysPayload($0) }, encode: { $0.json }) + let encrypter = syncKey.encrypter("keys", encoder: encoder) + let client = self.clientForCollection("crypto", encrypter: encrypter) + + let record = Record(id: "keys", payload: keys.asPayload()) + return client.put(record, ifUnmodifiedSince: ifUnmodifiedSince) + } + + // It would be convenient to have the storage client manage Keys, but of course we need to use a different set of + // keys to fetch crypto/keys itself. See uploadCryptoKeys. + func clientForCollection(_ collection: String, encrypter: RecordEncrypter) -> Sync15CollectionClient { + let storage = self.serverURI.appendingPathComponent("storage", isDirectory: true) + return Sync15CollectionClient(client: self, serverURI: storage, collection: collection, encrypter: encrypter) + } +} + +private let DefaultInfoConfiguration = InfoConfiguration(maxRequestBytes: 1_048_576, + maxPostRecords: 100, + maxPostBytes: 1_048_576, + maxTotalRecords: 10_000, + maxTotalBytes: 104_857_600) + +/** + * We'd love to nest this in the overall storage client, but Swift + * forbids the nesting of a generic class inside another class. + */ +open class Sync15CollectionClient { + fileprivate let client: Sync15StorageClient + fileprivate let encrypter: RecordEncrypter + fileprivate let collectionURI: URL + fileprivate let collectionQueue = DispatchQueue(label: "com.mozilla.sync.collectionclient", attributes: []) + fileprivate let infoConfig = DefaultInfoConfiguration + + public init(client: Sync15StorageClient, serverURI: URL, collection: String, encrypter: RecordEncrypter) { + self.client = client + self.encrypter = encrypter + self.collectionURI = serverURI.appendingPathComponent(collection, isDirectory: false) + } + + var maxBatchPostRecords: Int { + get { + return infoConfig.maxPostRecords + } + } + + fileprivate func uriForRecord(_ guid: String) -> URL { + return self.collectionURI.appendingPathComponent(guid) + } + + open func newBatch(ifUnmodifiedSince: Timestamp? = nil, onCollectionUploaded: @escaping (POSTResult, Timestamp?) -> DeferredTimestamp) -> Sync15BatchClient { + return Sync15BatchClient(config: infoConfig, + ifUnmodifiedSince: ifUnmodifiedSince, + serializeRecord: self.serializeRecord, + uploader: self.post, + onCollectionUploaded: onCollectionUploaded) + } + + // Exposed so we can batch by size. + open func serializeRecord(_ record: Record) -> String? { + return self.encrypter.serializer(record)?.stringValue() + } + + open func post(_ lines: [String], ifUnmodifiedSince: Timestamp?, queryParams: [URLQueryItem]? = nil) -> Deferred>> { + let deferred = Deferred>>(defaultQueue: client.resultQueue) + + if self.client.checkBackoff(deferred) { + return deferred + } + + let requestURI: URL + if let queryParams = queryParams { + requestURI = self.collectionURI.withQueryParams(queryParams) + } else { + requestURI = self.collectionURI + } + + let req = client.requestPOST(requestURI, body: lines, ifUnmodifiedSince: ifUnmodifiedSince) as! DataRequest + _ = req.responsePartialParsedJSON(queue: collectionQueue, completionHandler: self.client.errorWrap(deferred) { (response: DataResponse) in + if let json: JSON = response.result.value, + let result = POSTResult.fromJSON(json) { + let storageResponse = StorageResponse(value: result, response: response.response!) + deferred.fill(Maybe(success: storageResponse)) + return + } else { + log.warning("Couldn't parse JSON response.") + } + deferred.fill(Maybe(failure: RecordParseError())) + }) + + return deferred + } + + open func post(_ records: [Record], ifUnmodifiedSince: Timestamp?, queryParams: [URLQueryItem]? = nil) -> Deferred>> { + // TODO: charset + // TODO: if any of these fail, we should do _something_. Right now we just ignore them. + let lines = optFilter(records.map(self.serializeRecord)) + return self.post(lines, ifUnmodifiedSince: ifUnmodifiedSince, queryParams: queryParams) + } + + open func put(_ record: Record, ifUnmodifiedSince: Timestamp?) -> Deferred>> { + if let body = self.encrypter.serializer(record) { + return self.client.putResource(uriForRecord(record.id), body: body, ifUnmodifiedSince: ifUnmodifiedSince, parser: decimalSecondsStringToTimestamp) + } + return deferMaybe(RecordParseError()) + } + + open func get(_ guid: String) -> Deferred>>> { + let deferred = Deferred>>>(defaultQueue: client.resultQueue) + + if self.client.checkBackoff(deferred) { + return deferred + } + + let req = client.requestGET(uriForRecord(guid)) + _ = req.responsePartialParsedJSON(queue: collectionQueue, completionHandler: self.client.errorWrap(deferred) { (response: DataResponse) in + + if let json: JSON = response.result.value { + let envelope = EnvelopeJSON(json) + let record = Record.fromEnvelope(envelope, payloadFactory: self.encrypter.factory) + if let record = record { + let storageResponse = StorageResponse(value: record, response: response.response!) + deferred.fill(Maybe(success: storageResponse)) + return + } + } else { + log.warning("Couldn't parse JSON response.") + } + + deferred.fill(Maybe(failure: RecordParseError())) + }) + + return deferred + } + + /** + * Unlike every other Sync client, we use the application/json format for fetching + * multiple requests. The others use application/newlines. We don't want to write + * another Serializer, and we're loading everything into memory anyway. + * + * It is the caller's responsibility to check whether the returned payloads are invalid. + * + * Only non-JSON and malformed envelopes will be dropped. + */ + open func getSince(_ since: Timestamp, sort: SortOption?=nil, limit: Int?=nil, offset: String?=nil) -> Deferred]>>> { + let deferred = Deferred]>>>(defaultQueue: client.resultQueue) + + // Fills the Deferred for us. + if self.client.checkBackoff(deferred) { + return deferred + } + + var params: [URLQueryItem] = [ + URLQueryItem(name: "full", value: "1"), + URLQueryItem(name: "newer", value: millisecondsToDecimalSeconds(since)), + ] + + if let offset = offset { + params.append(URLQueryItem(name: "offset", value: offset)) + } + + if let limit = limit { + params.append(URLQueryItem(name: "limit", value: "\(limit)")) + } + + if let sort = sort { + params.append(URLQueryItem(name: "sort", value: sort.rawValue)) + } + + log.debug("Issuing GET with newer = \(since), offset = \(offset ??? "nil"), sort = \(sort ??? "nil").") + let req = client.requestGET(self.collectionURI.withQueryParams(params)) + + _ = req.responsePartialParsedJSON(queue: collectionQueue, completionHandler: self.client.errorWrap(deferred) { (response: DataResponse) in + + log.verbose("Response is \(response).") + guard let json: JSON = response.result.value else { + log.warning("Non-JSON response.") + deferred.fill(Maybe(failure: RecordParseError())) + return + } + + guard let arr = json.array else { + log.warning("Non-array response.") + deferred.fill(Maybe(failure: RecordParseError())) + return + } + + func recordify(_ json: JSON) -> Record? { + let envelope = EnvelopeJSON(json) + return Record.fromEnvelope(envelope, payloadFactory: self.encrypter.factory) + } + + let records = arr.flatMap(recordify) + let response = StorageResponse(value: records, response: response.response!) + deferred.fill(Maybe(success: response)) + }) + + return deferred + } +} diff --git a/mobile/ios/Sync/Sync-Bridging-Header.h b/mobile/ios/Sync/Sync-Bridging-Header.h new file mode 100644 index 0000000000..d2517c4a1e --- /dev/null +++ b/mobile/ios/Sync/Sync-Bridging-Header.h @@ -0,0 +1,8 @@ +#ifndef Client_Sync_Bridging_Header_h +#define Client_Sync_Bridging_Header_h + +#import +#import "Shared-Bridging-Header.h" +#import "Storage-Bridging-Header.h" + +#endif diff --git a/mobile/ios/Sync/SyncConstants.swift b/mobile/ios/Sync/SyncConstants.swift new file mode 100644 index 0000000000..6c403aaa13 --- /dev/null +++ b/mobile/ios/Sync/SyncConstants.swift @@ -0,0 +1,12 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Foundation + +public struct SyncConstants { + // Suitable for use in dispatch_time(). + public static let SyncDelayTriggered: Int = 3000 + public static let SyncOnForegroundMinimumDelayMillis: UInt64 = 5 * 60 * 1000 + public static let SyncOnForegroundAfterMillis: Int64 = 5000 +} diff --git a/mobile/ios/Sync/SyncMeta.swift b/mobile/ios/Sync/SyncMeta.swift new file mode 100644 index 0000000000..b00063a77a --- /dev/null +++ b/mobile/ios/Sync/SyncMeta.swift @@ -0,0 +1,149 @@ +/* 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/. */ + +import Foundation +import Shared +import SwiftyJSON + +// Our engine choices need to persist across server changes. +// Note that EngineConfiguration is not enough to evolve an existing meta/global: +// a meta/global generated from this will have different syncIDs and will +// always use this device's engine versions. +open class EngineConfiguration: Equatable { + let enabled: [String] + let declined: [String] + public init(enabled: [String], declined: [String]) { + self.enabled = enabled + self.declined = declined + } + + open class func fromJSON(_ json: JSON) -> EngineConfiguration? { + if json.isError() { + return nil + } + if let enabled = jsonsToStrings(json["enabled"].array) { + if let declined = jsonsToStrings(json["declined"].array) { + return EngineConfiguration(enabled: enabled, declined: declined) + } + } + return nil + } + + open func toJSON() -> JSON { + let json: [String: AnyObject] = ["enabled": self.enabled as AnyObject, "declined": self.declined as AnyObject] + return JSON(json) + } +} + +public func ==(lhs: EngineConfiguration, rhs: EngineConfiguration) -> Bool { + return Set(lhs.enabled) == Set(rhs.enabled) +} + +extension EngineConfiguration: CustomStringConvertible { + public var description: String { + return "EngineConfiguration(enabled: \(self.enabled.sorted()), declined: \(self.declined.sorted()))" + } +} + +// Equivalent to Android Sync's EngineSettings, but here +// we use them for meta/global itself. +public struct EngineMeta: Equatable { + let version: Int + let syncID: String + + public static func fromJSON(_ json: JSON) -> EngineMeta? { + if let syncID = json["syncID"].string { + if let version = json["version"].int { + return EngineMeta(version: version, syncID: syncID) + } + } + return nil + } + + public static func mapFromJSON(_ map: [String: JSON]?) -> [String: EngineMeta]? { + if let map = map { + return optFilter(mapValues(map, f: EngineMeta.fromJSON)) + } + return nil + } + + public func toJSON() -> JSON { + let json: [String: AnyObject] = ["version": self.version as AnyObject, "syncID": self.syncID as AnyObject] + return JSON(json) + } +} + +public func ==(lhs: EngineMeta, rhs: EngineMeta) -> Bool { + return (lhs.version == rhs.version) && (lhs.syncID == rhs.syncID) +} + +public struct MetaGlobal: Equatable { + let syncID: String + let storageVersion: Int + let engines: [String: EngineMeta] + let declined: [String] + + // TODO: is it more useful to support partial globals? + // TODO: how do we return error states here? + public static func fromJSON(_ json: JSON) -> MetaGlobal? { + if json.isError() { + return nil + } + if let syncID = json["syncID"].string { + if let storageVersion = json["storageVersion"].int { + let engines = EngineMeta.mapFromJSON(json["engines"].dictionary) ?? [:] + let declined = json["declined"].array ?? [] + return MetaGlobal(syncID: syncID, + storageVersion: storageVersion, + engines: engines, + declined: jsonsToStrings(declined) ?? []) + } + } + return nil + } + + public func enginesPayload() -> JSON { + return JSON(mapValues(engines, f: { $0.toJSON() })) + } + + // TODO: make a whole record JSON for this. + public func asPayload() -> CleartextPayloadJSON { + let json: JSON = JSON([ + "syncID": self.syncID, + "storageVersion": self.storageVersion, + "engines": enginesPayload().dictionaryObject as Any, + "declined": self.declined + ]) + return CleartextPayloadJSON(json) + } + + public func withSyncID(_ syncID: String) -> MetaGlobal { + return MetaGlobal(syncID: syncID, storageVersion: self.storageVersion, engines: self.engines, declined: self.declined) + } + + public func engineConfiguration() -> EngineConfiguration { + return EngineConfiguration(enabled: Array(engines.keys), declined: declined) + } +} + +public func ==(lhs: MetaGlobal, rhs: MetaGlobal) -> Bool { + return (lhs.syncID == rhs.syncID) && + (lhs.storageVersion == rhs.storageVersion) && + optArrayEqual(lhs.declined, rhs: rhs.declined) && + optDictionaryEqual(lhs.engines, rhs: rhs.engines) +} + +/** + * Encapsulates a meta/global, identity-derived keys, and keys. + */ +open class SyncMeta { + let syncKey: KeyBundle + + var keys: Keys? + var global: MetaGlobal? + + public init(syncKey: KeyBundle) { + self.syncKey = syncKey + } +} diff --git a/mobile/ios/Sync/SyncStateMachine.swift b/mobile/ios/Sync/SyncStateMachine.swift new file mode 100644 index 0000000000..dc1249dc16 --- /dev/null +++ b/mobile/ios/Sync/SyncStateMachine.swift @@ -0,0 +1,966 @@ +/* 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/. */ + +import Foundation +import Shared +import Account +import XCGLogger +import Deferred + +private let log = Logger.syncLogger + +private let StorageVersionCurrent = 5 + +// Names of collections for which a synchronizer is implemented locally. +private let LocalEngines: [String] = [ + "bookmarks", + "clients", + "history", + "passwords", + "tabs", +] + +// Names of collections which will appear in a default meta/global produced locally. +// Map collection name to engine version. See http://docs.services.mozilla.com/sync/objectformats.html. +private let DefaultEngines: [String: Int] = [ + "bookmarks": BookmarksStorageVersion, + "clients": ClientsStorageVersion, + "history": HistoryStorageVersion, + "passwords": PasswordsStorageVersion, + "tabs": TabsStorageVersion, + // We opt-in to syncing collections we don't know about, since no client offers to sync non-enabled, + // non-declined engines yet. See Bug 969669. + "forms": 1, + "addons": 1, + "prefs": 2, +] + +// Names of collections which will appear as declined in a default +// meta/global produced locally. +private let DefaultDeclined: [String] = [String]() + +// public for testing. +public func createMetaGlobalWithEngineConfiguration(_ engineConfiguration: EngineConfiguration) -> MetaGlobal { + var engines: [String: EngineMeta] = [:] + for engine in engineConfiguration.enabled { + // We take this device's version, or, if we don't know the correct version, 0. Another client should recognize + // the engine, see an old version, wipe and start again. + // TODO: this client does not yet do this wipe-and-update itself! + let version = DefaultEngines[engine] ?? 0 + engines[engine] = EngineMeta(version: version, syncID: Bytes.generateGUID()) + } + return MetaGlobal(syncID: Bytes.generateGUID(), storageVersion: StorageVersionCurrent, engines: engines, declined: engineConfiguration.declined) +} + +public func createMetaGlobal() -> MetaGlobal { + let engineConfiguration = EngineConfiguration(enabled: Array(DefaultEngines.keys), declined: DefaultDeclined) + return createMetaGlobalWithEngineConfiguration(engineConfiguration) +} + +public typealias TokenSource = () -> Deferred> +public typealias ReadyDeferred = Deferred> + +// See docs in docs/sync.md. + +// You might be wondering why this doesn't have a Sync15StorageClient like FxALoginStateMachine +// does. Well, such a client is pinned to a particular server, and this state machine must +// acknowledge that a Sync client occasionally must migrate between two servers, preserving +// some state from the last. +// The resultant 'Ready' will be able to provide a suitably initialized storage client. +open class SyncStateMachine { + // The keys are used as a set, to prevent cycles in the state machine. + var stateLabelsSeen = [SyncStateLabel: Bool]() + var stateLabelSequence = [SyncStateLabel]() + + let stateLabelsAllowed: Set + + let scratchpadPrefs: Prefs + + /// Use this set of states to constrain the state machine to attempt the barest + /// minimum to get to Ready. This is suitable for extension uses. If it is not possible, + /// then no destructive or expensive actions are taken (e.g. total HTTP requests, + /// duration, records processed, database writes, fsyncs, blanking any local collections) + public static let OptimisticStates = Set(SyncStateLabel.optimisticValues) + + /// The default set of states that the state machine is allowed to use. + public static let AllStates = Set(SyncStateLabel.allValues) + + public init(prefs: Prefs, allowingStates labels: Set = SyncStateMachine.AllStates) { + self.scratchpadPrefs = prefs.branch("scratchpad") + self.stateLabelsAllowed = labels + } + + open class func clearStateFromPrefs(_ prefs: Prefs) { + log.debug("Clearing all Sync prefs.") + Scratchpad.clearFromPrefs(prefs.branch("scratchpad")) // XXX this is convoluted. + prefs.clearAll() + } + + fileprivate func advanceFromState(_ state: SyncState) -> ReadyDeferred { + log.info("advanceFromState: \(state.label)") + + // Record visibility before taking any action. + let labelAlreadySeen = self.stateLabelsSeen.updateValue(true, forKey: state.label) != nil + stateLabelSequence.append(state.label) + + if let ready = state as? Ready { + // Sweet, we made it! + return deferMaybe(ready) + } + + // Cycles are not necessarily a problem, but seeing the same (recoverable) error condition is a problem. + if state is RecoverableSyncState && labelAlreadySeen { + return deferMaybe(StateMachineCycleError()) + } + + guard stateLabelsAllowed.contains(state.label) else { + return deferMaybe(DisallowedStateError(state.label, allowedStates: stateLabelsAllowed)) + } + + return state.advance() >>== self.advanceFromState + } + + open func toReady(_ authState: SyncAuthState) -> ReadyDeferred { + let token = authState.token(Date.now(), canBeExpired: false) + return chainDeferred(token, f: { (token, kB) in + log.debug("Got token from auth state.") + if Logger.logPII { + log.debug("Server is \(token.api_endpoint).") + } + let prior = Scratchpad.restoreFromPrefs(self.scratchpadPrefs, syncKeyBundle: KeyBundle.fromKB(kB)) + if prior == nil { + log.info("No persisted Sync state. Starting over.") + } + var scratchpad = prior ?? Scratchpad(b: KeyBundle.fromKB(kB), persistingTo: self.scratchpadPrefs) + + // Take the scratchpad and add the fxaDeviceId from the state, and hashedUID from the token + let b = Scratchpad.Builder(p: scratchpad) + if let deviceID = authState.deviceID { + b.fxaDeviceId = deviceID + } else { + // Either deviceRegistration hasn't occurred yet (our bug) or + // FxA has given us an UnknownDevice error. + log.warning("Device registration has not taken place before sync.") + } + b.hashedUID = token.hashedFxAUID + + // Detect if we've changed anything in our client record from the last time we synced… + let ourClientUnchanged = (b.fxaDeviceId == scratchpad.fxaDeviceId) + + // …and if so, trigger a reset of clients. + if !ourClientUnchanged { + b.localCommands.insert(LocalCommand.resetEngine(engine: "clients")) + } + + scratchpad = b.build() + + log.info("Advancing to InitialWithLiveToken.") + let state = InitialWithLiveToken(scratchpad: scratchpad, token: token) + + // Start with fresh visibility data. + self.stateLabelsSeen = [:] + self.stateLabelSequence = [] + + return self.advanceFromState(state) + }) + } +} + +public enum SyncStateLabel: String { + case Stub = "STUB" // For 'abstract' base classes. + + case InitialWithExpiredToken = "initialWithExpiredToken" + case InitialWithExpiredTokenAndInfo = "initialWithExpiredTokenAndInfo" + case InitialWithLiveToken = "initialWithLiveToken" + case InitialWithLiveTokenAndInfo = "initialWithLiveTokenAndInfo" + case ResolveMetaGlobalVersion = "resolveMetaGlobalVersion" + case ResolveMetaGlobalContent = "resolveMetaGlobalContent" + case NeedsFreshMetaGlobal = "needsFreshMetaGlobal" + case NewMetaGlobal = "newMetaGlobal" + case HasMetaGlobal = "hasMetaGlobal" + case NeedsFreshCryptoKeys = "needsFreshCryptoKeys" + case HasFreshCryptoKeys = "hasFreshCryptoKeys" + case Ready = "ready" + case FreshStartRequired = "freshStartRequired" // Go around again... once only, perhaps. + case ServerConfigurationRequired = "serverConfigurationRequired" + + case ChangedServer = "changedServer" + case MissingMetaGlobal = "missingMetaGlobal" + case MissingCryptoKeys = "missingCryptoKeys" + case MalformedCryptoKeys = "malformedCryptoKeys" + case SyncIDChanged = "syncIDChanged" + case RemoteUpgradeRequired = "remoteUpgradeRequired" + case ClientUpgradeRequired = "clientUpgradeRequired" + + static let allValues: [SyncStateLabel] = [ + InitialWithExpiredToken, + InitialWithExpiredTokenAndInfo, + InitialWithLiveToken, + InitialWithLiveTokenAndInfo, + NeedsFreshMetaGlobal, + ResolveMetaGlobalVersion, + ResolveMetaGlobalContent, + NewMetaGlobal, + HasMetaGlobal, + NeedsFreshCryptoKeys, + HasFreshCryptoKeys, + Ready, + + FreshStartRequired, + ServerConfigurationRequired, + + ChangedServer, + MissingMetaGlobal, + MissingCryptoKeys, + MalformedCryptoKeys, + SyncIDChanged, + RemoteUpgradeRequired, + ClientUpgradeRequired, + ] + + // This is the list of states needed to get to Ready, or failing. + // This is useful in circumstances where it is important to conserve time and/or battery, and failure + // to timely sync is acceptable. + static let optimisticValues: [SyncStateLabel] = [ + InitialWithLiveToken, + InitialWithLiveTokenAndInfo, + HasMetaGlobal, + HasFreshCryptoKeys, + Ready, + ] +} + +/** + * States in this state machine all implement SyncState. + * + * States are either successful main-flow states, or (recoverable) error states. + * Errors that aren't recoverable are simply errors. + * Main-flow states flow one to one. + * + * (Terminal failure states might be introduced at some point.) + * + * Multiple error states (but typically only one) can arise from each main state transition. + * For example, parsing meta/global can result in a number of different non-routine situations. + * + * For these reasons, and the lack of useful ADTs in Swift, we model the main flow as + * the success branch of a Result, and the recovery flows as a part of the failure branch. + * + * We could just as easily use a ternary Either-style operator, but thanks to Swift's + * optional-cast-let it's no saving to do so. + * + * Because of the lack of type system support, all RecoverableSyncStates must have the same + * signature. That signature implies a possibly multi-state transition; individual states + * will have richer type signatures. + */ +public protocol SyncState { + var label: SyncStateLabel { get } + + func advance() -> Deferred> +} + +/* + * Base classes to avoid repeating initializers all over the place. + */ +open class BaseSyncState: SyncState { + open var label: SyncStateLabel { return SyncStateLabel.Stub } + + open let client: Sync15StorageClient! + let token: TokenServerToken // Maybe expired. + var scratchpad: Scratchpad + + // TODO: 304 for i/c. + open func getInfoCollections() -> Deferred> { + return chain(self.client.getInfoCollections(), f: { + return $0.value + }) + } + + public init(client: Sync15StorageClient, scratchpad: Scratchpad, token: TokenServerToken) { + self.scratchpad = scratchpad + self.token = token + self.client = client + log.info("Inited \(self.label.rawValue)") + } + + open func synchronizer(_ synchronizerClass: T.Type, delegate: SyncDelegate, prefs: Prefs, why: SyncReason) -> T { + return T(scratchpad: self.scratchpad, delegate: delegate, basePrefs: prefs, why: why) + } + + // This isn't a convenience initializer 'cos subclasses can't call convenience initializers. + public init(scratchpad: Scratchpad, token: TokenServerToken) { + let workQueue = DispatchQueue.global() + let resultQueue = DispatchQueue.main + let backoff = scratchpad.backoffStorage + let client = Sync15StorageClient(token: token, workQueue: workQueue, resultQueue: resultQueue, backoff: backoff) + self.scratchpad = scratchpad + self.token = token + self.client = client + log.info("Inited \(self.label.rawValue)") + } + + open func advance() -> Deferred> { + return deferMaybe(StubStateError()) + } +} + +open class BaseSyncStateWithInfo: BaseSyncState { + open let info: InfoCollections + + init(client: Sync15StorageClient, scratchpad: Scratchpad, token: TokenServerToken, info: InfoCollections) { + self.info = info + super.init(client: client, scratchpad: scratchpad, token: token) + } + + init(scratchpad: Scratchpad, token: TokenServerToken, info: InfoCollections) { + self.info = info + super.init(scratchpad: scratchpad, token: token) + } +} + +/* + * Error types. + */ +public protocol SyncError: MaybeErrorType, SyncPingFailureFormattable {} + +extension SyncError { + public var failureReasonName: SyncPingFailureReasonName { + return .unexpectedError + } +} + +open class UnknownError: SyncError { + open var description: String { + return "Unknown error." + } +} + +open class StateMachineCycleError: SyncError { + open var description: String { + return "The Sync state machine encountered a cycle. This is a coding error." + } +} + +open class CouldNotFetchMetaGlobalError: SyncError { + open var description: String { + return "Could not fetch meta/global." + } +} + +open class CouldNotFetchKeysError: SyncError { + open var description: String { + return "Could not fetch crypto/keys." + } +} + +open class StubStateError: SyncError { + open var description: String { + return "Unexpectedly reached a stub state. This is a coding error." + } +} + +open class ClientUpgradeRequiredError: SyncError { + let targetStorageVersion: Int + + public init(target: Int) { + self.targetStorageVersion = target + } + + open var description: String { + return "Client upgrade required to work with storage version \(self.targetStorageVersion)." + } +} + +open class InvalidKeysError: SyncError { + let keys: Keys + + public init(_ keys: Keys) { + self.keys = keys + } + + open var description: String { + return "Downloaded crypto/keys, but couldn't parse them." + } +} + +open class DisallowedStateError: SyncError { + let state: SyncStateLabel + let allowedStates: Set + + public init(_ state: SyncStateLabel, allowedStates: Set) { + self.state = state + self.allowedStates = allowedStates + } + + open var description: String { + return "Sync state machine reached \(String(describing: state)) state, which is disallowed. Legal states are: \(String(describing: allowedStates))" + } +} + +/** + * Error states. These are errors that can be recovered from by taking actions. We use RecoverableSyncState as a + * sentinel: if we see the same recoverable state twice, we bail out and complain that we've seen a cycle. (Seeing + * some states -- principally initial states -- twice is fine.) +*/ + +public protocol RecoverableSyncState: SyncState { +} + +/** + * Recovery: discard our local timestamps and sync states; discard caches. + * Be prepared to handle a conflict between our selected engines and the new + * server's meta/global; if an engine is selected locally but not declined + * remotely, then we'll need to upload a new meta/global and sync that engine. + */ +open class ChangedServerError: RecoverableSyncState { + open var label: SyncStateLabel { return SyncStateLabel.ChangedServer } + + let newToken: TokenServerToken + let newScratchpad: Scratchpad + + public init(scratchpad: Scratchpad, token: TokenServerToken) { + self.newToken = token + self.newScratchpad = Scratchpad(b: scratchpad.syncKeyBundle, persistingTo: scratchpad.prefs) + } + + open func advance() -> Deferred> { + // TODO: mutate local storage to allow for a fresh start. + let state = InitialWithLiveToken(scratchpad: newScratchpad.checkpoint(), token: newToken) + return deferMaybe(state) + } +} + +/** + * Recovery: same as for changed server, but no need to upload a new meta/global. + */ +open class SyncIDChangedError: RecoverableSyncState { + open var label: SyncStateLabel { return SyncStateLabel.SyncIDChanged } + + fileprivate let previousState: BaseSyncStateWithInfo + fileprivate let newMetaGlobal: Fetched + + public init(previousState: BaseSyncStateWithInfo, newMetaGlobal: Fetched) { + self.previousState = previousState + self.newMetaGlobal = newMetaGlobal + } + + open func advance() -> Deferred> { + // TODO: mutate local storage to allow for a fresh start. + let s = self.previousState.scratchpad.evolve().setGlobal(self.newMetaGlobal).setKeys(nil).build().checkpoint() + let state = HasMetaGlobal(client: self.previousState.client, scratchpad: s, token: self.previousState.token, info: self.previousState.info) + return deferMaybe(state) + } +} + +/** + * Recovery: configure the server. + */ +open class ServerConfigurationRequiredError: RecoverableSyncState { + open var label: SyncStateLabel { return SyncStateLabel.ServerConfigurationRequired } + + fileprivate let previousState: BaseSyncStateWithInfo + + public init(previousState: BaseSyncStateWithInfo) { + self.previousState = previousState + } + + open func advance() -> Deferred> { + let client = self.previousState.client! + let s = self.previousState.scratchpad.evolve() + .setGlobal(nil) + .addLocalCommandsFromKeys(nil) + .setKeys(nil) + .build().checkpoint() + // Upload a new meta/global ... + let metaGlobal: MetaGlobal + if let oldEngineConfiguration = s.engineConfiguration { + metaGlobal = createMetaGlobalWithEngineConfiguration(oldEngineConfiguration) + } else { + metaGlobal = createMetaGlobal() + } + return client.uploadMetaGlobal(metaGlobal, ifUnmodifiedSince: nil) + // ... and a new crypto/keys. + >>> { return client.uploadCryptoKeys(Keys.random(), withSyncKeyBundle: s.syncKeyBundle, ifUnmodifiedSince: nil) } + >>> { return deferMaybe(InitialWithLiveToken(client: client, scratchpad: s, token: self.previousState.token)) } + } +} + +/** + * Recovery: wipe the server (perhaps unnecessarily) and proceed to configure the server. + */ +open class FreshStartRequiredError: RecoverableSyncState { + open var label: SyncStateLabel { return SyncStateLabel.FreshStartRequired } + + fileprivate let previousState: BaseSyncStateWithInfo + + public init(previousState: BaseSyncStateWithInfo) { + self.previousState = previousState + } + + open func advance() -> Deferred> { + let client = self.previousState.client! + return client.wipeStorage() + >>> { return deferMaybe(ServerConfigurationRequiredError(previousState: self.previousState)) } + } +} + +open class MissingMetaGlobalError: RecoverableSyncState { + open var label: SyncStateLabel { return SyncStateLabel.MissingMetaGlobal } + + fileprivate let previousState: BaseSyncStateWithInfo + + public init(previousState: BaseSyncStateWithInfo) { + self.previousState = previousState + } + + open func advance() -> Deferred> { + return deferMaybe(FreshStartRequiredError(previousState: self.previousState)) + } +} + +open class MissingCryptoKeysError: RecoverableSyncState { + open var label: SyncStateLabel { return SyncStateLabel.MissingCryptoKeys } + + fileprivate let previousState: BaseSyncStateWithInfo + + public init(previousState: BaseSyncStateWithInfo) { + self.previousState = previousState + } + + open func advance() -> Deferred> { + return deferMaybe(FreshStartRequiredError(previousState: self.previousState)) + } +} + +open class RemoteUpgradeRequired: RecoverableSyncState { + open var label: SyncStateLabel { return SyncStateLabel.RemoteUpgradeRequired } + + fileprivate let previousState: BaseSyncStateWithInfo + + public init(previousState: BaseSyncStateWithInfo) { + self.previousState = previousState + } + + open func advance() -> Deferred> { + return deferMaybe(FreshStartRequiredError(previousState: self.previousState)) + } +} + +open class ClientUpgradeRequired: RecoverableSyncState { + open var label: SyncStateLabel { return SyncStateLabel.ClientUpgradeRequired } + + fileprivate let previousState: BaseSyncStateWithInfo + let targetStorageVersion: Int + + public init(previousState: BaseSyncStateWithInfo, target: Int) { + self.previousState = previousState + self.targetStorageVersion = target + } + + open func advance() -> Deferred> { + return deferMaybe(ClientUpgradeRequiredError(target: self.targetStorageVersion)) + } +} + +/* + * Non-error states. + */ + +open class InitialWithLiveToken: BaseSyncState { + open override var label: SyncStateLabel { return SyncStateLabel.InitialWithLiveToken } + + // This looks totally redundant, but try taking it out, I dare you. + public override init(scratchpad: Scratchpad, token: TokenServerToken) { + super.init(scratchpad: scratchpad, token: token) + } + + // This looks totally redundant, but try taking it out, I dare you. + public override init(client: Sync15StorageClient, scratchpad: Scratchpad, token: TokenServerToken) { + super.init(client: client, scratchpad: scratchpad, token: token) + } + + func advanceWithInfo(_ info: InfoCollections) -> SyncState { + return InitialWithLiveTokenAndInfo(scratchpad: self.scratchpad, token: self.token, info: info) + } + + override open func advance() -> Deferred> { + return chain(getInfoCollections(), f: self.advanceWithInfo) + } +} + +/** + * Each time we fetch a new meta/global, we need to reconcile it with our + * current state. + * + * It might be identical to our current meta/global, in which case we can short-circuit. + * + * We might have no previous meta/global at all, in which case this state + * simply configures local storage to be ready to sync according to the + * supplied meta/global. (Not necessarily datatype elections: those will be per-device.) + * + * Or it might be different. In this case the previous m/g and our local user preferences + * are compared to the new, resulting in some actions and a final state. + * + * This states are similar in purpose to GlobalSession.processMetaGlobal in Android Sync. + */ + +open class ResolveMetaGlobalVersion: BaseSyncStateWithInfo { + let fetched: Fetched + + init(fetched: Fetched, client: Sync15StorageClient, scratchpad: Scratchpad, token: TokenServerToken, info: InfoCollections) { + self.fetched = fetched + super.init(client: client, scratchpad: scratchpad, token: token, info: info) + } + open override var label: SyncStateLabel { return SyncStateLabel.ResolveMetaGlobalVersion } + + class func fromState(_ state: BaseSyncStateWithInfo, fetched: Fetched) -> ResolveMetaGlobalVersion { + return ResolveMetaGlobalVersion(fetched: fetched, client: state.client, scratchpad: state.scratchpad, token: state.token, info: state.info) + } + + override open func advance() -> Deferred> { + // First: check storage version. + let v = fetched.value.storageVersion + if v > StorageVersionCurrent { + // New storage version? Uh-oh. No recovery possible here. + log.info("Client upgrade required for storage version \(v)") + return deferMaybe(ClientUpgradeRequired(previousState: self, target: v)) + } + + if v < StorageVersionCurrent { + // Old storage version? Uh-oh. Wipe and upload both meta/global and crypto/keys. + log.info("Server storage version \(v) is outdated.") + return deferMaybe(RemoteUpgradeRequired(previousState: self)) + } + + return deferMaybe(ResolveMetaGlobalContent.fromState(self, fetched: self.fetched)) + } +} + +open class ResolveMetaGlobalContent: BaseSyncStateWithInfo { + let fetched: Fetched + + init(fetched: Fetched, client: Sync15StorageClient, scratchpad: Scratchpad, token: TokenServerToken, info: InfoCollections) { + self.fetched = fetched + super.init(client: client, scratchpad: scratchpad, token: token, info: info) + } + open override var label: SyncStateLabel { return SyncStateLabel.ResolveMetaGlobalContent } + + class func fromState(_ state: BaseSyncStateWithInfo, fetched: Fetched) -> ResolveMetaGlobalContent { + return ResolveMetaGlobalContent(fetched: fetched, client: state.client, scratchpad: state.scratchpad, token: state.token, info: state.info) + } + + override open func advance() -> Deferred> { + // Check global syncID and contents. + if let previous = self.scratchpad.global?.value { + // Do checks that only apply when we're coming from a previous meta/global. + if previous.syncID != fetched.value.syncID { + log.info("Remote global sync ID has changed. Dropping keys and resetting all local collections.") + let s = self.scratchpad.freshStartWithGlobal(fetched).checkpoint() + return deferMaybe(HasMetaGlobal.fromState(self, scratchpad: s)) + } + + let b = self.scratchpad.evolve() + .setGlobal(fetched) // We always adopt the upstream meta/global record. + + let previousEngines = Set(previous.engines.keys) + let remoteEngines = Set(fetched.value.engines.keys) + + for engine in previousEngines.subtracting(remoteEngines) { + log.info("Remote meta/global disabled previously enabled engine \(engine).") + b.localCommands.insert(.disableEngine(engine: engine)) + } + + for engine in remoteEngines.subtracting(previousEngines) { + log.info("Remote meta/global enabled previously disabled engine \(engine).") + b.localCommands.insert(.enableEngine(engine: engine)) + } + + for engine in remoteEngines.intersection(previousEngines) { + let remoteEngine = fetched.value.engines[engine]! + let previousEngine = previous.engines[engine]! + if previousEngine.syncID != remoteEngine.syncID { + log.info("Remote sync ID for \(engine) has changed. Resetting local.") + b.localCommands.insert(.resetEngine(engine: engine)) + } + } + + let s = b.build().checkpoint() + return deferMaybe(HasMetaGlobal.fromState(self, scratchpad: s)) + } + + // No previous meta/global. Adopt the new meta/global. + let s = self.scratchpad.freshStartWithGlobal(fetched).checkpoint() + return deferMaybe(HasMetaGlobal.fromState(self, scratchpad: s)) + } +} + +private func processFailure(_ failure: MaybeErrorType?) -> MaybeErrorType { + if let failure = failure as? ServerInBackoffError { + log.warning("Server in backoff. Bailing out. \(failure.description)") + return failure + } + + // TODO: backoff etc. for all of these. + if let failure = failure as? ServerError { + // Be passive. + log.error("Server error. Bailing out. \(failure.description)") + return failure + } + + if let failure = failure as? BadRequestError { + // Uh oh. + log.error("Bad request. Bailing out. \(failure.description)") + return failure + } + + log.error("Unexpected failure. \(failure?.description ?? "nil")") + return failure ?? UnknownError() +} + +open class InitialWithLiveTokenAndInfo: BaseSyncStateWithInfo { + open override var label: SyncStateLabel { return SyncStateLabel.InitialWithLiveTokenAndInfo } + + // This method basically hops over HasMetaGlobal, because it's not a state + // that we expect consumers to know about. + override open func advance() -> Deferred> { + // Either m/g and c/k are in our local cache, and they're up-to-date with i/c, + // or we need to fetch them. + // Cached and not changed in i/c? Use that. + // This check would be inaccurate if any other fields were stored in meta/; this + // has been the case in the past, with the Sync 1.1 migration indicator. + if let global = self.scratchpad.global { + if let metaModified = self.info.modified("meta") { + // We check the last time we fetched the record, and that can be + // later than the collection timestamp. All we care about here is if the + // server might have a newer record. + if global.timestamp >= metaModified { + log.debug("Cached meta/global fetched at \(global.timestamp), newer than server modified \(metaModified). Using cached meta/global.") + // Strictly speaking we can avoid fetching if this condition is not true, + // but if meta/ is modified for a different reason -- store timestamps + // for the last collection fetch. This will do for now. + return deferMaybe(HasMetaGlobal.fromState(self)) + } + log.info("Cached meta/global fetched at \(global.timestamp) older than server modified \(metaModified). Fetching fresh meta/global.") + } else { + // No known modified time for meta/. That means the server has no meta/global. + // Drop our cached value and fall through; we'll try to fetch, fail, and + // go through the usual failure flow. + log.warning("Local meta/global fetched at \(global.timestamp) found, but no meta collection on server. Dropping cached meta/global.") + // If we bail because we've been overly optimistic, then we nil out the current (broken) + // meta/global. Next time around, we end up in the "No cached meta/global found" branch. + self.scratchpad = self.scratchpad.evolve().setGlobal(nil).setKeys(nil).build().checkpoint() + } + } else { + log.debug("No cached meta/global found. Fetching fresh meta/global.") + } + + return deferMaybe(NeedsFreshMetaGlobal.fromState(self)) + } +} + +/* + * We've reached NeedsFreshMetaGlobal somehow, but we haven't yet done anything about it + * (e.g. fetch a new one with GET /storage/meta/global ). + * + * If we don't want to hit the network (e.g. from an extension), we should stop if we get to this state. + */ +open class NeedsFreshMetaGlobal: BaseSyncStateWithInfo { + open override var label: SyncStateLabel { return SyncStateLabel.NeedsFreshMetaGlobal } + + class func fromState(_ state: BaseSyncStateWithInfo) -> NeedsFreshMetaGlobal { + return NeedsFreshMetaGlobal(client: state.client, scratchpad: state.scratchpad, token: state.token, info: state.info) + } + + override open func advance() -> Deferred> { + // Fetch. + return self.client.getMetaGlobal().bind { result in + if let resp = result.successValue { + // We use the server's timestamp, rather than the record's modified field. + // Either can be made to work, but the latter has suffered from bugs: see Bug 1210625. + let fetched = Fetched(value: resp.value, timestamp: resp.metadata.timestampMilliseconds) + return deferMaybe(ResolveMetaGlobalVersion.fromState(self, fetched: fetched)) + } + + if let _ = result.failureValue as? NotFound { + // OK, this is easy. + // This state is responsible for creating the new m/g, uploading it, and + // restarting with a clean scratchpad. + return deferMaybe(MissingMetaGlobalError(previousState: self)) + } + + // Otherwise, we have a failure state. Die on the sword! + return deferMaybe(processFailure(result.failureValue)) + } + } +} + +open class HasMetaGlobal: BaseSyncStateWithInfo { + open override var label: SyncStateLabel { return SyncStateLabel.HasMetaGlobal } + + class func fromState(_ state: BaseSyncStateWithInfo) -> HasMetaGlobal { + return HasMetaGlobal(client: state.client, scratchpad: state.scratchpad, token: state.token, info: state.info) + } + + class func fromState(_ state: BaseSyncStateWithInfo, scratchpad: Scratchpad) -> HasMetaGlobal { + return HasMetaGlobal(client: state.client, scratchpad: scratchpad, token: state.token, info: state.info) + } + + override open func advance() -> Deferred> { + // Check if crypto/keys is fresh in the cache already. + if let keys = self.scratchpad.keys, keys.value.valid { + if let cryptoModified = self.info.modified("crypto") { + // Both of these are server timestamps. If the record we stored was fetched after the last time the record was modified, as represented by the "crypto" entry in info/collections, and we're fetching from the + // same server, then the record must be identical, and we can use it directly. If are ever additional records in the crypto collection, this will fetch keys too frequently. In that case, we should use X-I-U-S and expect some 304 responses. + if keys.timestamp >= cryptoModified { + log.debug("Cached keys fetched at \(keys.timestamp), newer than server modified \(cryptoModified). Using cached keys.") + return deferMaybe(HasFreshCryptoKeys.fromState(self, scratchpad: self.scratchpad, collectionKeys: keys.value)) + } + + // The server timestamp is newer, so there might be new keys. + // Re-fetch keys and check to see if the actual contents differ. + // If the keys are the same, we can ignore this change. If they differ, + // we need to re-sync any collection whose keys just changed. + log.info("Cached keys fetched at \(keys.timestamp) older than server modified \(cryptoModified). Fetching fresh keys.") + return deferMaybe(NeedsFreshCryptoKeys.fromState(self, scratchpad: self.scratchpad, staleCollectionKeys: keys.value)) + } else { + // No known modified time for crypto/. That likely means the server has no keys. + // Drop our cached value and fall through; we'll try to fetch, fail, and + // go through the usual failure flow. + log.warning("Local keys fetched at \(keys.timestamp) found, but no crypto collection on server. Dropping cached keys.") + self.scratchpad = self.scratchpad.evolve().setKeys(nil).build().checkpoint() + } + } else { + log.debug("No cached keys found. Fetching fresh keys.") + } + + return deferMaybe(NeedsFreshCryptoKeys.fromState(self, scratchpad: self.scratchpad, staleCollectionKeys: nil)) + } +} + +open class NeedsFreshCryptoKeys: BaseSyncStateWithInfo { + open override var label: SyncStateLabel { return SyncStateLabel.NeedsFreshCryptoKeys } + let staleCollectionKeys: Keys? + + class func fromState(_ state: BaseSyncStateWithInfo, scratchpad: Scratchpad, staleCollectionKeys: Keys?) -> NeedsFreshCryptoKeys { + return NeedsFreshCryptoKeys(client: state.client, scratchpad: scratchpad, token: state.token, info: state.info, keys: staleCollectionKeys) + } + + public init(client: Sync15StorageClient, scratchpad: Scratchpad, token: TokenServerToken, info: InfoCollections, keys: Keys?) { + self.staleCollectionKeys = keys + super.init(client: client, scratchpad: scratchpad, token: token, info: info) + } + + override open func advance() -> Deferred> { + // Fetch crypto/keys. + return self.client.getCryptoKeys(self.scratchpad.syncKeyBundle, ifUnmodifiedSince: nil).bind { result in + if let resp = result.successValue { + let collectionKeys = Keys(payload: resp.value.payload) + if !collectionKeys.valid { + log.error("Unexpectedly invalid crypto/keys during a successful fetch.") + return Deferred(value: Maybe(failure: InvalidKeysError(collectionKeys))) + } + + let fetched = Fetched(value: collectionKeys, timestamp: resp.metadata.timestampMilliseconds) + let s = self.scratchpad.evolve() + .addLocalCommandsFromKeys(fetched) + .setKeys(fetched) + .build().checkpoint() + return deferMaybe(HasFreshCryptoKeys.fromState(self, scratchpad: s, collectionKeys: collectionKeys)) + } + + if let _ = result.failureValue as? NotFound { + // No crypto/keys? We can handle this. Wipe and upload both meta/global and crypto/keys. + return deferMaybe(MissingCryptoKeysError(previousState: self)) + } + + // Otherwise, we have a failure state. + return deferMaybe(processFailure(result.failureValue)) + } + } +} + +open class HasFreshCryptoKeys: BaseSyncStateWithInfo { + open override var label: SyncStateLabel { return SyncStateLabel.HasFreshCryptoKeys } + let collectionKeys: Keys + + class func fromState(_ state: BaseSyncStateWithInfo, scratchpad: Scratchpad, collectionKeys: Keys) -> HasFreshCryptoKeys { + return HasFreshCryptoKeys(client: state.client, scratchpad: scratchpad, token: state.token, info: state.info, keys: collectionKeys) + } + + public init(client: Sync15StorageClient, scratchpad: Scratchpad, token: TokenServerToken, info: InfoCollections, keys: Keys) { + self.collectionKeys = keys + super.init(client: client, scratchpad: scratchpad, token: token, info: info) + } + + override open func advance() -> Deferred> { + return deferMaybe(Ready(client: self.client, scratchpad: self.scratchpad, token: self.token, info: self.info, keys: self.collectionKeys)) + } +} + +public protocol EngineStateChanges { + func collectionsThatNeedLocalReset() -> [String] + func enginesEnabled() -> [String] + func enginesDisabled() -> [String] + func clearLocalCommands() +} + +open class Ready: BaseSyncStateWithInfo { + open override var label: SyncStateLabel { return SyncStateLabel.Ready } + let collectionKeys: Keys + + public var hashedFxADeviceID: String { + return (scratchpad.fxaDeviceId + token.hashedFxAUID).sha256.hexEncodedString + } + + public init(client: Sync15StorageClient, scratchpad: Scratchpad, token: TokenServerToken, info: InfoCollections, keys: Keys) { + self.collectionKeys = keys + super.init(client: client, scratchpad: scratchpad, token: token, info: info) + } +} + +extension Ready: EngineStateChanges { + public func collectionsThatNeedLocalReset() -> [String] { + var needReset: Set = Set() + for command in self.scratchpad.localCommands { + switch command { + case let .resetAllEngines(except: except): + needReset.formUnion(Set(LocalEngines).subtracting(except)) + case let .resetEngine(engine): + needReset.insert(engine) + case .enableEngine, .disableEngine: + break + } + } + return Array(needReset).sorted() + } + + public func enginesEnabled() -> [String] { + var engines: Set = Set() + for command in self.scratchpad.localCommands { + switch command { + case let .enableEngine(engine): + engines.insert(engine) + default: + break + } + } + return Array(engines).sorted() + } + + public func enginesDisabled() -> [String] { + var engines: Set = Set() + for command in self.scratchpad.localCommands { + switch command { + case let .disableEngine(engine): + engines.insert(engine) + default: + break + } + } + return Array(engines).sorted() + } + + public func clearLocalCommands() { + self.scratchpad = self.scratchpad.evolve().clearLocalCommands().build().checkpoint() + } +} diff --git a/mobile/ios/Sync/SyncTelemetryUtils.swift b/mobile/ios/Sync/SyncTelemetryUtils.swift new file mode 100644 index 0000000000..5daa88b761 --- /dev/null +++ b/mobile/ios/Sync/SyncTelemetryUtils.swift @@ -0,0 +1,356 @@ +/* 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/. */ + +import Foundation +import Shared +import Account +import Storage +import SwiftyJSON +import SyncTelemetry +import Deferred + +fileprivate let log = Logger.syncLogger + +public let PrefKeySyncEvents = "sync.telemetry.events" + +public enum SyncReason: String { + case startup = "startup" + case scheduled = "scheduled" + case backgrounded = "backgrounded" + case user = "user" + case syncNow = "syncNow" + case didLogin = "didLogin" + case push = "push" +} + +public enum SyncPingReason: String { + case shutdown = "shutdown" + case schedule = "schedule" + case idChanged = "idchanged" +} + +public protocol Stats { + func hasData() -> Bool +} + +private protocol DictionaryRepresentable { + func asDictionary() -> [String: Any] +} + +public struct SyncUploadStats: Stats { + var sent: Int = 0 + var sentFailed: Int = 0 + + public func hasData() -> Bool { + return sent > 0 || sentFailed > 0 + } +} + +extension SyncUploadStats: DictionaryRepresentable { + func asDictionary() -> [String: Any] { + return [ + "sent": sent, + "sentFailed": sentFailed + ] + } +} + +public struct SyncDownloadStats: Stats { + var applied: Int = 0 + var succeeded: Int = 0 + var failed: Int = 0 + var newFailed: Int = 0 + var reconciled: Int = 0 + + public func hasData() -> Bool { + return applied > 0 || + succeeded > 0 || + failed > 0 || + newFailed > 0 || + reconciled > 0 + } +} + +extension SyncDownloadStats: DictionaryRepresentable { + func asDictionary() -> [String: Any] { + return [ + "applied": applied, + "succeeded": succeeded, + "failed": failed, + "newFailed": newFailed, + "reconciled": reconciled + ] + } +} + +public struct ValidationStats: Stats, DictionaryRepresentable { + let problems: [ValidationProblem] + let took: Int64 + let checked: Int? + + public func hasData() -> Bool { + return !problems.isEmpty + } + + func asDictionary() -> [String: Any] { + var dict: [String: Any] = [ + "problems": problems.map { $0.asDictionary() }, + "took": took + ] + if let checked = self.checked { + dict["checked"] = checked + } + return dict + } +} + +public struct ValidationProblem: DictionaryRepresentable { + let name: String + let count: Int + + func asDictionary() -> [String: Any] { + return ["name": name, "count": count] + } +} + +public class StatsSession { + var took: Int64 = 0 + var when: Timestamp? + + private var startUptimeNanos: UInt64? + + public func start(when: UInt64 = Date.now()) { + self.when = when + self.startUptimeNanos = DispatchTime.now().uptimeNanoseconds + } + + public func hasStarted() -> Bool { + return startUptimeNanos != nil + } + + public func end() -> Self { + guard let startUptime = startUptimeNanos else { + assertionFailure("SyncOperationStats called end without first calling start!") + return self + } + + // Casting to Int64 should be safe since we're using uptime since boot in both cases. + // Convert to milliseconds as stated in the sync ping format + took = (Int64(DispatchTime.now().uptimeNanoseconds) - Int64(startUptime)) / 1000000 + return self + } +} + +// Stats about a single engine's sync. +public class SyncEngineStatsSession: StatsSession { + public var validationStats: ValidationStats? + + private(set) var uploadStats: SyncUploadStats + private(set) var downloadStats: SyncDownloadStats + + public init(collection: String) { + self.uploadStats = SyncUploadStats() + self.downloadStats = SyncDownloadStats() + } + + public func recordDownload(stats: SyncDownloadStats) { + self.downloadStats.applied += stats.applied + self.downloadStats.succeeded += stats.succeeded + self.downloadStats.failed += stats.failed + self.downloadStats.newFailed += stats.newFailed + self.downloadStats.reconciled += stats.reconciled + } + + public func recordUpload(stats: SyncUploadStats) { + self.uploadStats.sent += stats.sent + self.uploadStats.sentFailed += stats.sentFailed + } +} + +extension SyncEngineStatsSession: DictionaryRepresentable { + func asDictionary() -> [String: Any] { + var dict: [String: Any] = [ + "took": took, + ] + + if downloadStats.hasData() { + dict["incoming"] = downloadStats.asDictionary() + } + + if uploadStats.hasData() { + dict["outgoing"] = uploadStats.asDictionary() + } + + if let validation = self.validationStats, validation.hasData() { + dict["validation"] = validation.asDictionary() + } + + return dict + } +} + +// Stats and metadata for a sync operation. +public class SyncOperationStatsSession: StatsSession { + public let why: SyncReason + public var uid: String? + public var deviceID: String? + + fileprivate let didLogin: Bool + + public init(why: SyncReason, uid: String, deviceID: String?) { + self.why = why + self.uid = uid + self.deviceID = deviceID + self.didLogin = (why == .didLogin) + } +} + +extension SyncOperationStatsSession: DictionaryRepresentable { + func asDictionary() -> [String: Any] { + let whenValue = when ?? 0 + return [ + "when": whenValue, + "took": took, + "didLogin": didLogin, + "why": why.rawValue + ] + } +} + +public enum SyncPingError: MaybeErrorType { + case failedToRestoreScratchpad + + public var description: String { + switch self { + case .failedToRestoreScratchpad: return "Failed to restore Scratchpad from prefs" + } + } +} + +public enum SyncPingFailureReasonName: String { + case httpError = "httperror" + case unexpectedError = "unexpectederror" + case sqlError = "sqlerror" + case otherError = "othererror" +} + +public protocol SyncPingFailureFormattable { + var failureReasonName: SyncPingFailureReasonName { get } +} + +public struct SyncPing: SyncTelemetryPing { + public private(set) var payload: JSON + + public static func from(result: SyncOperationResult, + account: FirefoxAccount, + remoteClientsAndTabs: RemoteClientsAndTabs, + prefs: Prefs, + why: SyncPingReason) -> Deferred> { + // Grab our token so we can use the hashed_fxa_uid and clientGUID from our scratchpad for + // our ping's identifiers + return account.syncAuthState.token(Date.now(), canBeExpired: false) >>== { (token, kB) in + let scratchpadPrefs = prefs.branch("sync.scratchpad") + guard let scratchpad = Scratchpad.restoreFromPrefs(scratchpadPrefs, syncKeyBundle: KeyBundle.fromKB(kB)) else { + return deferMaybe(SyncPingError.failedToRestoreScratchpad) + } + + var ping: [String: Any] = [ + "version": 1, + "why": why.rawValue, + "uid": token.hashedFxAUID, + "deviceID": (scratchpad.clientGUID + token.hashedFxAUID).sha256.hexEncodedString + ] + + // TODO: We don't cache our sync pings so if it fails, it fails. Once we add + // some kind of caching we'll want to make sure we don't dump the events if + // the ping has failed. + let pickledEvents = prefs.arrayForKey(PrefKeySyncEvents) as? [Data] ?? [] + let events = pickledEvents.flatMap(Event.unpickle).map { $0.toArray() } + ping["events"] = events + prefs.setObject(nil, forKey: PrefKeySyncEvents) + + return dictionaryFrom(result: result, storage: remoteClientsAndTabs, token: token) >>== { syncDict in + // TODO: Split the sync ping metadata from storing a single sync. + ping["syncs"] = [syncDict] + return deferMaybe(SyncPing(payload: JSON(ping))) + } + } + } + + // Generates a single sync ping payload that is stored in the 'syncs' list in the sync ping. + private static func dictionaryFrom(result: SyncOperationResult, + storage: RemoteClientsAndTabs, + token: TokenServerToken) -> Deferred> { + return connectedDevices(fromStorage: storage, token: token) >>== { devices in + guard let stats = result.stats else { + return deferMaybe([String: Any]()) + } + + var dict = stats.asDictionary() + if let engineResults = result.engineResults.successValue { + dict["engines"] = SyncPing.enginePingDataFrom(engineResults: engineResults) + } else if let failure = result.engineResults.failureValue { + var errorName: SyncPingFailureReasonName + if let formattableFailure = failure as? SyncPingFailureFormattable { + errorName = formattableFailure.failureReasonName + } else { + errorName = .unexpectedError + } + + dict["failureReason"] = [ + "name": errorName.rawValue, + "error": "\(type(of: failure))", + ] + } + + dict["devices"] = devices + return deferMaybe(dict) + } + } + + // Returns a list of connected devices formatted for use in the 'devices' property in the sync ping. + private static func connectedDevices(fromStorage storage: RemoteClientsAndTabs, + token: TokenServerToken) -> Deferred> { + func dictionaryFrom(client: RemoteClient) -> [String: Any]? { + var device = [String: Any]() + if let os = client.os { + device["os"] = os + } + if let version = client.version { + device["version"] = version + } + if let guid = client.guid { + device["id"] = (guid + token.hashedFxAUID).sha256.hexEncodedString + } + return device + } + + return storage.getClients() >>== { deferMaybe($0.flatMap(dictionaryFrom)) } + } + + private static func enginePingDataFrom(engineResults: EngineResults) -> [[String: Any]] { + return engineResults.map { result in + let (name, status) = result + var engine: [String: Any] = [ + "name": name + ] + + // For complete/partial results, extract out the collect stats + // and add it to engine information. For syncs that were not able to + // start, return why and a reason. + switch status { + case .completed(let stats): + engine.merge(with: stats.asDictionary()) + case .partial(let stats): + engine.merge(with: stats.asDictionary()) + case .notStarted(let reason): + engine.merge(with: [ + "status": reason.telemetryId + ]) + } + + return engine + } + } +} diff --git a/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksDownloader.swift b/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksDownloader.swift new file mode 100644 index 0000000000..94b0f6e9ec --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksDownloader.swift @@ -0,0 +1,161 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage + +private let log = Logger.syncLogger +let BookmarksStorageVersion = 2 + +/** + * This is like a synchronizer, but it downloads records bit by bit, eventually + * notifying that the local storage is up to date with the server contents. + * + * Because batches might be separated over time, it's possible for the server + * state to change between calls. These state changes might include: + * + * 1. New changes arriving. This is fairly routine, but it's worth noting that + * changes might affect existing records that have been batched! + * 2. Wipes. The collection (or the server as a whole) might be deleted. This + * should be accompanied by a change in syncID in meta/global; it's the caller's + * responsibility to detect this. + * 3. A storage format change. This should be unfathomably rare, but if it happens + * we must also be prepared to discard our existing batched data. + * 4. TTL expiry. We need to do better about TTL handling in general, but here + * we might find that a downloaded record is no longer live by the time we + * come to apply it! This doesn't apply to bookmark records, so we will ignore + * it for the moment. + * + * Batch downloading without continuation tokens is achieved as follows: + * + * * A minimum timestamp is established. This starts as zero. + * * A fetch is issued against the server for records changed since that timestamp, + * ordered by modified time ascending, and limited to the batch size. + * * If the batch is complete, we flush it to storage and advance the minimum + * timestamp to just before the newest record in the batch. This ensures that + * a divided set of records with the same modified times will be downloaded + * entirely so long as the set is never larger than the batch size. + * * Iterate until we determine that there are no new records to fetch. + * + * Batch downloading with continuation tokens is much easier: + * + * * A minimum timestamp is established. + * * Make a request with limit=N. + * * Look for an X-Weave-Next-Offset header. Supply that in the next request. + * Also supply X-If-Unmodified-Since to avoid missed modifications. + * + * We do the latter, because we only support Sync 1.5. The use of the offset + * allows us to efficiently process batches, particularly those that contain + * large sets of records with the same timestamp. We still maintain the last + * modified timestamp to allow for resuming a batch in the case of a conflicting + * write, detected via X-I-U-S. + */ + +public class BookmarksMirrorer { + private let downloader: BatchingDownloader + private let storage: BookmarkBufferStorage + private let batchSize: Int + private let statsSession: SyncEngineStatsSession + + public init(storage: BookmarkBufferStorage, client: Sync15CollectionClient, basePrefs: Prefs, collection: String, statsSession: SyncEngineStatsSession, batchSize: Int=100) { + self.storage = storage + self.downloader = BatchingDownloader(collectionClient: client, basePrefs: basePrefs, collection: collection) + self.batchSize = batchSize + self.statsSession = statsSession + } + + var lastModified: Timestamp { + get { + return self.downloader.lastModified + } + } + + // TODO + public func storageFormatDidChange() { + } + + // TODO + public func onWipeWasAppliedToStorage() { + } + + private func applyRecordsFromBatcher() -> Success { + let retrieved = self.downloader.retrieve() + let invalid = retrieved.filter { !$0.payload.isValid() } + + if !invalid.isEmpty { + // There's nothing we can do with invalid input. There's also no point in + // tracking failing GUIDs here yet: if another client reuploads those records + // correctly, we'll encounter them routinely due to a newer timestamp. + // The only improvement we could make is to drop records from the buffer if we + // happen to see a new, invalid one before somehow syncing again, but that's + // unlikely enough that it's not worth doing. + // + // Bug 1258801 tracks recording telemetry for these invalid items, which is + // why we don't simply drop them on the ground at the download stage. + // + // We might also choose to perform certain simple recovery actions here: for example, + // bookmarks with null URIs are clearly invalid, and could be treated as if they + // weren't present on the server, or transparently deleted. + log.warning("Invalid records: \(invalid.map { $0.id }.joined(separator: ", ")).") + } + + let mirrorItems = retrieved.flatMap { record -> BookmarkMirrorItem? in + guard record.payload.isValid() else { + return nil + } + + return (record.payload as MirrorItemable).toMirrorItem(record.modified) + } + + if mirrorItems.isEmpty { + log.debug("Got empty batch.") + return succeed() + } + + log.debug("Applying \(mirrorItems.count) downloaded bookmarks.") + return self.storage.applyRecords(mirrorItems) + } + + public func go(info: InfoCollections, greenLight: @escaping () -> Bool) -> SyncResult { + if !greenLight() { + log.info("Green light turned red. Stopping mirror operation.") + return deferMaybe(SyncStatus.notStarted(.redLight)) + } + + log.debug("Downloading up to \(self.batchSize) records.") + return self.downloader.go(info, limit: self.batchSize) + .bind { result in + guard let end = result.successValue else { + log.warning("Got failure: \(result.failureValue!)") + return deferMaybe(result.failureValue!) + } + switch end { + case .complete: + log.info("Done with batched mirroring.") + return self.applyRecordsFromBatcher() + >>> effect(self.downloader.advance) + >>> self.storage.doneApplyingRecordsAfterDownload + >>> always(SyncStatus.completed(self.statsSession.end())) + case .incomplete: + log.debug("Running another batch.") + // This recursion is fine because Deferred always pushes callbacks onto a queue. + return self.applyRecordsFromBatcher() + >>> effect(self.downloader.advance) + >>> { self.go(info: info, greenLight: greenLight) } + case .interrupted: + log.info("Interrupted. Aborting batching this time.") + return deferMaybe(SyncStatus.partial(self.statsSession)) + case .noNewData: + log.info("No new data. No need to continue batching.") + self.downloader.advance() + return deferMaybe(SyncStatus.completed(self.statsSession.end())) + } + } + } + + func advanceNextDownloadTimestampTo(timestamp: Timestamp) { + self.downloader.advanceTimestampTo(timestamp) + } +} diff --git a/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksRepairRequestor.swift b/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksRepairRequestor.swift new file mode 100644 index 0000000000..bbe464b86a --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksRepairRequestor.swift @@ -0,0 +1,571 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import Deferred +import SwiftyJSON +import SyncTelemetry + +private let log = Logger.syncLogger + +// How long should we wait after sending a repair request before we give up? +private let ResponseIntervalTimeout = OneDayInMilliseconds * 3 + +// The maximum number of IDs we will request to be repaired. Beyond this +// number we assume that trying to repair may do more harm than good and may +// ask another client to wipe the server and reupload everything. Bug 1341972 +// is tracking that work for Desktop. +private let MaxRequestedIDs = 1000 + +// If a repair is in progress, this is the generated GUID for the "flow ID". +private let PrefFlowID = "flowID" +// The IDs we are currently trying to obtain via the repair process. +private let PrefMissingIDs = "ids" +// The ID of the client we're currently trying to get the missing items from. +private let PrefCurrentClient = "currentClient" +// The IDs of the clients we've previously tried to get the missing items +// from. +private let PrefPreviousClients = "previousClients" +// The time, in seconds, when we initiated the most recent client request. +private let PrefLastRepair = "when" +// Our current state. +private let PrefCurrentState = "state" + +private enum RepairState: String { + // We have not started the repair process. + case notRepairing = "" + + // We need to try to find another client to use. + case needNewClient = "repair.need-new-client" + + // We've sent the first request to a client. + case sentRequest = "repair.sent" + + // We've retried a request to a client. + case sentSecondRequest = "repair.sent-again" + + // There were no problems, but we've gone as far as we can. + case finished = "repair.finished" + + // We've found an error that forces us to abort this entire repair cycle. + case aborted = "repair.aborted" +} + +struct RepairResponse { + let collection: String + let request: String + let flowID: String + let clientID: String + let ids: [String] + + static func fromJSON(args: JSON) -> RepairResponse { + return RepairResponse(collection: args["collection"].stringValue, request: args["request"].stringValue, + flowID: args["flowID"].stringValue, clientID: args["clientID"].stringValue, + ids: args["ids"].arrayValue.map { $0.stringValue }) + } +} + +struct RepairRequest { + let collection: String + let request: String + let flowID: String + let requestor: String + let ids: [String] + + func toSyncCommand() -> SyncCommand { + let jsonObj: [String: Any] = [ + "command": "repairRequest", + "args": [ + [ + "collection": collection, + "request": request, + "flowID": flowID, + "requestor": requestor, + "ids": ids + ] + ] + ] + return SyncCommand(value: JSON(object: jsonObj).stringValue()!) + } +} + +private class AbortRepairError: MaybeErrorType { + let description: String + init(_ description: String) { + self.description = description + } +} + +private class UnknownClientError: MaybeErrorType { + let description: String + init(_ description: String) { + self.description = description + } +} + +private class InvalidStateError: MaybeErrorType { + let description: String + init(_ description: String) { + self.description = description + } +} + +class BookmarksRepairRequestor { + let prefs: Prefs + let basePrefs: Prefs + let remoteClients: RemoteClientsAndTabs + let scratchpad: Scratchpad + + init(scratchpad: Scratchpad, basePrefs: Prefs, remoteClients: RemoteClientsAndTabs) { + self.scratchpad = scratchpad + self.basePrefs = basePrefs + self.prefs = basePrefs.branch("repairs.bookmark") + self.remoteClients = remoteClients + } + + /** + * See if the repairer is willing and able to begin a repair process given + * the specified validation information. + * + * - returns: true if a repair was started and false otherwise. + */ + func startRepairs(validationInfo: [BufferInconsistency: [GUID]], flowID: String = Bytes.generateGUID()) -> Deferred> { + guard self.currentState == .notRepairing else { + log.info("Can't start a repair - repair with ID \(self.flowID) is already in progress") + return deferMaybe(false) + } + + let ids = self.getProblemIDs(validationInfo) + + guard ids.count > 0 else { + log.info("Not starting a repair as there are no problems") + return deferMaybe(false) + } + + guard ids.count <= MaxRequestedIDs else { + log.info("Not starting a repair as there are over \(MaxRequestedIDs) problems") + let extra = [ + "flowID": flowID, + "reason": "too many problems: \(ids.count)" + ] + + let event = Event(category: "sync", method: "repair", object: "aborted", extra: extra) + recordTelemetry(event: event) + + return deferMaybe(false) + } + + return self.anyClientsRepairing() >>== { clientsRepairing in + guard !clientsRepairing else { + log.info("Can't start repair, since other clients are already repairing bookmarks") + let extra = [ + "flowID": flowID, + "reason": "other clients repairing" + ] + let event = Event(category: "sync", method: "repair", object: "aborted", extra: extra) + self.recordTelemetry(event: event) + return deferMaybe(false) + } + + log.info("Starting a repair, looking for \(ids.count) missing item(s)") + // Setup our prefs to indicate we are on our way. + self.flowID = flowID + self.currentIDs = ids + self.currentState = .needNewClient + + let extra = ["flowID": flowID, "numIDs": String(ids.count)] + let event = Event(category: "sync", method: "repair", object: "started", extra: extra) + self.recordTelemetry(event: event) + + return self.continueRepairs() + } + } + + /** + * Work out what state our current repair request is in, and whether it can + * proceed to a new state. + * + * - returns: true if we could continue the repair - even if the state didn't + * actually move. Returns false if we aren't actually repairing. + */ + func continueRepairs(response: RepairResponse? = nil) -> Deferred> { + // Note that "aborted" and "finished" should never be current when this + // function returns - this function resets to notRepairing in those cases. + guard self.currentState != .notRepairing else { + return deferMaybe(false) + } + + var abortReason: String? + + func runStateMachine(iteration: Int = 0) -> Deferred> { + let state = self.currentState + log.info("continueRepairs starting with state \(state)") + + return self.advanceRepairState(state: state, response: response).bind { result in + let newState: RepairState + if result.isSuccess { + newState = result.successValue! + log.info("continueRepairs has next state \(newState)") + } else { + let failure = result.failureValue! + if failure is AbortRepairError { + let reason = failure.description + log.info("Repair has been aborted: \(reason)") + newState = .aborted + abortReason = reason + } else { + return deferMaybe(failure) + } + } + let done = deferMaybe((state: state, newState: newState)) + + if newState == .aborted { + return done + } + + self.currentState = newState + if state == newState { + return done + } + + // we loop until the state doesn't change - but enforce a max of 10 times + // to prevent errors causing infinite loops. + return (iteration < 10) ? runStateMachine(iteration: iteration + 1) : done + } + } + + return runStateMachine() >>== { stateMachineResult in + let state = stateMachineResult.state + let newState = stateMachineResult.newState + + if state != newState { + log.error("continueRepairs spun without getting a new state") + } + + if newState == .finished || newState == .aborted { + let method = newState == .finished ? "finished" : "aborted" + var extra = [ + "flowID": self.flowID, + "numIDs": String(self.currentIDs.count), + ] + if abortReason != nil { + extra["reason"] = abortReason + } + + let event = Event(category: "sync", method: "repair", object: method, extra: extra) + self.recordTelemetry(event: event) + + self.prefs.clearAll() + } + return deferMaybe(true) + } + } + + func recordTelemetry(event: Event) { + var events = self.basePrefs.arrayForKey(PrefKeySyncEvents) as? [Data] ?? [] + + if let data = event.pickle(), event.validate() { + events.append(data) + self.basePrefs.setObject(events, forKey: PrefKeySyncEvents) + } else { + log.info("Event not recorded due to validation failure or pickling error!") + } + } + + private func advanceRepairState(state: RepairState, response: RepairResponse?) -> Deferred> { + return self.anyClientsRepairing(flowID: self.flowID) >>== { anyClientsRepairing in + guard !anyClientsRepairing else { + return deferMaybe(AbortRepairError("other clients repairing")) + } + + switch state { + + case .sentRequest, .sentSecondRequest: + let flowID = self.flowID + guard let clientID = self.currentRemoteClient else { + return deferMaybe(InvalidStateError("currentRemoteClient should be defined")) + } + if let response = response { + // We got an explicit response - let's see how we went. + return deferMaybe(self.handleResponse(state: state, response: response)) + } + // So we've sent a request - and don't yet have a response. See if the + // client we sent it to has removed it from its list (ie, whether it + // has synced since we wrote the request.) + return self.remoteClients.getClientWithId(clientID) >>== { client in + guard let client = client else { + // hrmph - the client has disappeared. + log.info("previously requested client \(clientID) has vanished - moving to next step") + let extra = [ + "deviceID": self.scratchpad.hashedDeviceID ?? "unknown_deviceID", + "flowID": flowID + ] + + let event = Event(category: "sync", method: "repair", object: "abandon", value: "missing", extra: extra) + self.recordTelemetry(event: event) + + return deferMaybe(.needNewClient) + } + return self.isCommandPending(clientID: clientID, flowID: flowID) >>== { isCommandPending in + if isCommandPending { + // So the command we previously sent is still queued for the client + // (ie, that client is yet to have synced). Let's see if we should + // give up on that client. + if self.lastRepair + ResponseIntervalTimeout <= Date.now() { + log.info("previous request to client \(clientID) is pending, but has taken too long") + // XXX - should we remove the command? + let extra = [ + "deviceID": self.scratchpad.hashedDeviceID ?? "unknown_deviceID", + "flowID": flowID + ] + + let event = Event(category: "sync", method: "repair", object: "abandon", value: "silent", extra: extra) + self.recordTelemetry(event: event) + + return deferMaybe(.needNewClient) + } + // Let's continue to wait for that client to respond. + // We are now sure that timeLeft > 0, so we can calculate it (Timestamp type is UInt64) + let timeLeft = self.lastRepair + ResponseIntervalTimeout - Date.now() + log.verbose("previous request to client \(clientID) has \(timeLeft) seconds before we give up on it") + return deferMaybe(state) + } + // The command isn't pending - if this was the first request, we give + // it another go (as that client may have cleared the command but is yet + // to complete the sync) + // XXX - note that this is no longer true - the responders don't remove + // their command until they have written a response. This might mean + // we could drop the entire STATE.SENT_SECOND_REQUEST concept??? + if state == .sentRequest { + log.info("previous request to client \(clientID) was removed - trying a second time") + return self.writeRequest(client: client) >>== { success in + return deferMaybe(.sentSecondRequest) + } + } else { + // this was the second time around, so give up on this client + log.info("previous 2 requests to client \(clientID) were removed - need a new client") + return deferMaybe(.needNewClient) + } + } + } + + case .needNewClient: + // We need to find a new client to request. + return self.findNextClient() >>== { client in + guard let nextClient = client else { + return deferMaybe(.finished) + } + if let currentRemoteClient = self.currentRemoteClient { + var previousRemoteClients = self.previousRemoteClients + previousRemoteClients.append(currentRemoteClient) + self.previousRemoteClients = previousRemoteClients + } + self.currentRemoteClient = nextClient.guid! + return self.writeRequest(client: nextClient) >>== { success in + return deferMaybe(.sentRequest) + } + } + + case .aborted: + break // our caller will take the abort action. + + case .finished: + break + + case .notRepairing: + // No repair is in progress. This is a common case, so only log trace. + log.verbose("continue repairs called but no repair in progress.") + break + } + return deferMaybe(state) + } + } + + /** + * Handle being in the SENT_REQUEST or SENT_SECOND_REQUEST state with an + * explicit response. + */ + private func handleResponse(state: RepairState, response: RepairResponse) -> RepairState { + guard let clientID = self.currentRemoteClient else { + log.error("Cannot handle the response of an unknown client") + return state + } + let flowID = self.flowID + guard response.flowID == flowID && response.clientID == clientID && + response.request == "upload" else { + log.info("got a response to a different repair request: \(response)") + // hopefully just a stale request that finally came in (either from + // an entirely different repair flow, or from a client we've since + // given up on.) It doesn't mean we need to abort though... + return state + } + // Pull apart the response and see if it provided everything we asked for. + let remainingIDs = Array(Set(self.currentIDs).subtracting(Set(response.ids))) + log.info("repair response from \(clientID) provided '\(response.ids)', remaining now '\(remainingIDs)'") + self.currentIDs = remainingIDs + let newState: RepairState + if remainingIDs.count > 0 { + // try a new client for the remaining ones. + newState = .needNewClient + } else { + newState = .finished + } + // record telemetry about this + let extra = [ + "deviceID": scratchpad.hashedDeviceID ?? "unknown_deviceID", + "flowID": flowID, + "numIDs": String(response.ids.count) + ] + let event = Event(category: "sync", method: "repair", object: "response", value: "upload", extra: extra) + recordTelemetry(event: event) + return newState + } + + /** + * Issue a repair request to a specific client. + */ + private func writeRequest(client: RemoteClient) -> Success { + log.verbose("writing repair request to client \(client.guid!)") + let ids = self.currentIDs + let flowID = self.flowID + // Post a command to that client. + let request = RepairRequest(collection: "bookmarks", request: "upload", flowID: flowID, requestor: self.scratchpad.clientGUID, ids: ids) + + return self.remoteClients.insertCommand(request.toSyncCommand(), forClients: [client]) >>== { (_: Int) -> Success in + self.lastRepair = Date.now() + // record telemetry about this + let extra = [ + "deviceID": self.scratchpad.hashedDeviceID ?? "unknown_deviceID", + "flowID": flowID, + "numIDs": String(ids.count), + ] + + let event = Event(category: "sync", method: "repair", object: "request", value: "upload", extra: extra) + self.recordTelemetry(event: event) + + return succeed() + } + } + + private func findNextClient() -> Deferred> { + var alreadyDone = self.previousRemoteClients + if let currentRemoteClient = self.currentRemoteClient { + alreadyDone.append(currentRemoteClient) + } + return self.remoteClients.getClients() >>== { remoteClients in + // we want to consider the most-recently synced clients first. + let sortedClients = remoteClients.sorted(by: { (a, b) -> Bool in + return a.modified > b.modified + }) + for client in sortedClients { + log.verbose("findNextClient considering \(client)") + guard let clientID = client.guid else { + continue + } + if !alreadyDone.contains(clientID) && self.isSuitableClient(client) { + return deferMaybe(client) + } + } + log.verbose("findNextClient found no client") + return deferMaybe(nil) + } + } + + private func isSuitableClient(_ client: RemoteClient) -> Bool { + if let type = client.type, + let version = client.version, + let major = Int(version.components(separatedBy: ".")[0]) { + return type == "desktop" && major > 53 + } + return false + } + + private func getProblemIDs(_ validations: [BufferInconsistency: [GUID]]) -> [GUID] { + return validations.reduce([]) { acc, pair in acc + pair.value } + } + + private func anyClientsRepairing(flowID: String? = nil) -> Deferred> { + return self.remoteClients.getCommands() >>== { allCommands in + return deferMaybe(allCommands.contains { (clientID: GUID, commands: [SyncCommand]) in + return commands.contains { (command: SyncCommand) in + let json = JSON(parseJSON: command.value) + guard let cmdName = json["command"].string, + let argsArray = json["args"].array, + let argObj = argsArray[0].dictionary, + let argCol = argObj["collection"]?.string, + let argFlowID = argObj["flowID"]?.string + else { + return false + } + return !((cmdName != "repairResponse" && cmdName != "repairRequest") || + argsArray.count != 1 || + argCol != "bookmarks" || + argFlowID == flowID + ) + } + }) + } + } + + private func isCommandPending(clientID: String, flowID: String) -> Deferred> { + return self.remoteClients.getCommands() >>== { allCommands in + guard let commands = allCommands[clientID] else { + return deferMaybe(false) + } + return deferMaybe(commands.contains { (command: SyncCommand) in + let json = JSON(parseJSON: command.value) + guard let cmdName = json["command"].string, + let argsArray = json["args"].array, + let argObj = argsArray[0].dictionary, + let argCol = argObj["collection"]?.string, + let argFlowID = argObj["flowID"]?.string, + let argRequest = argObj["request"]?.string + else { + return false + } + return cmdName == "repairRequest" && argsArray.count == 1 && + argCol == "bookmarks" && argRequest == "upload" && + argFlowID == flowID + }) + } + } + + private var flowID: String { + get { return self.prefs.stringForKey(PrefFlowID)! } + set { self.prefs.setString(newValue, forKey: PrefFlowID) } + } + + private var currentIDs: [String] { + get { return self.prefs.stringArrayForKey(PrefMissingIDs) ?? [String]() } + set { self.prefs.setObject(newValue, forKey: PrefMissingIDs) } + } + + private var currentRemoteClient: String? { + get { return self.prefs.stringForKey(PrefCurrentClient) } + set { self.prefs.setString(newValue!, forKey: PrefCurrentClient) } + } + + private var previousRemoteClients: [String] { + get { return self.prefs.stringArrayForKey(PrefPreviousClients) ?? [String]() } + set { self.prefs.setObject(newValue, forKey: PrefPreviousClients) } + } + + private var lastRepair: Timestamp { + get { return self.prefs.timestampForKey(PrefLastRepair)! } + set { self.prefs.setTimestamp(newValue, forKey: PrefLastRepair) } + } + + private var currentState: RepairState { + get { + let Default = RepairState.notRepairing + guard let raw = self.prefs.stringForKey(PrefCurrentState) else { + return Default + } + return RepairState(rawValue: raw) ?? Default + } + set { self.prefs.setString(newValue.rawValue, forKey: PrefCurrentState) } + } +} diff --git a/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksSynchronizer.swift b/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksSynchronizer.swift new file mode 100644 index 0000000000..cd8aff5346 --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/Bookmarks/BookmarksSynchronizer.swift @@ -0,0 +1,511 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared +import Storage +import XCGLogger + +private let log = Logger.syncLogger + +typealias UploadFunction = ([Record], _ lastTimestamp: Timestamp?, _ onUpload: @escaping (POSTResult, Timestamp?) -> DeferredTimestamp) -> DeferredTimestamp + +class TrivialBookmarkStorer: BookmarkStorer { + let uploader: UploadFunction + init(uploader: @escaping UploadFunction) { + self.uploader = uploader + } + + func applyUpstreamCompletionOp(_ op: UpstreamCompletionOp, itemSources: ItemSources, trackingTimesInto local: LocalOverrideCompletionOp) -> Deferred> { + log.debug("Uploading \(op.records.count) modified records.") + log.debug("Uploading \(op.amendChildrenFromBuffer.count) amended buffer records.") + log.debug("Uploading \(op.amendChildrenFromMirror.count) amended mirror records.") + log.debug("Uploading \(op.amendChildrenFromLocal.count) amended local records.") + + var records: [Record] = [] + records.reserveCapacity(op.records.count + op.amendChildrenFromBuffer.count + op.amendChildrenFromLocal.count + op.amendChildrenFromMirror.count) + records.append(contentsOf: op.records) + + func accumulateFromAmendMap(_ itemsWithNewChildren: [GUID: [GUID]], fetch: ([GUID: [GUID]]) -> Maybe<[GUID: BookmarkMirrorItem]>) throws /* MaybeErrorType */ { + if itemsWithNewChildren.isEmpty { + return + } + + let fetched = fetch(itemsWithNewChildren) + guard let items = fetched.successValue else { + log.warning("Couldn't fetch items to amend.") + throw fetched.failureValue! + } + + items.forEach { (guid, item) in + let payload = item.asPayloadWithChildren(itemsWithNewChildren[guid]) + let mappedGUID = payload["id"].string ?? guid + let record = Record(id: mappedGUID, payload: payload) + records.append(record) + } + } + + do { + try accumulateFromAmendMap(op.amendChildrenFromBuffer, fetch: { itemSources.buffer.getBufferItemsWithGUIDs($0.keys).value }) + try accumulateFromAmendMap(op.amendChildrenFromMirror, fetch: { itemSources.mirror.getMirrorItemsWithGUIDs($0.keys).value }) + try accumulateFromAmendMap(op.amendChildrenFromLocal, fetch: { itemSources.local.getLocalItemsWithGUIDs($0.keys).value }) + } catch { + return deferMaybe(error as MaybeErrorType) + } + + var success: [GUID] = [] + var failed: [GUID: String] = [:] + + func onUpload(_ result: POSTResult, lastModified: Timestamp?) -> DeferredTimestamp { + success.append(contentsOf: result.success) + result.failed.forEach { guid, message in + failed[guid] = message + } + + log.debug("Uploaded records got timestamp \(lastModified ??? "nil").") + let modified = lastModified ?? 0 + local.setModifiedTime(modified, guids: result.success) + return deferMaybe(modified) + } + + // Chain the last upload timestamp right into our lastFetched timestamp. + // This is what Sync clients tend to do, but we can probably do better. + return uploader(records, op.ifUnmodifiedSince, onUpload) + // As if we uploaded everything in one go. + >>> { deferMaybe(POSTResult(success: success, failed: failed)) } + } +} + +open class MalformedRecordError: MaybeErrorType, SyncPingFailureFormattable { + open var description: String { + return "Malformed record." + } + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } +} + +// MARK: - External synchronizer interface. + +open class BufferingBookmarksSynchronizer: TimestampedSingleCollectionSynchronizer, Synchronizer { + public required init(scratchpad: Scratchpad, delegate: SyncDelegate, basePrefs: Prefs, why: SyncReason) { + super.init(scratchpad: scratchpad, delegate: delegate, basePrefs: basePrefs, why: why, collection: "bookmarks") + } + + override var storageVersion: Int { + return BookmarksStorageVersion + } + + fileprivate func buildMobileRootRecord(_ local: LocalItemSource, _ buffer: BufferItemSource, additionalChildren: [BookmarkMirrorItem], deletedChildren: [GUID]) -> Deferred>> { + let newBookmarkGUIDs = additionalChildren.map { $0.guid } + return buffer.getBufferItemWithGUID(BookmarkRoots.MobileFolderGUID).bind { maybeMobileRoot in + // Update (or create!) the Mobile Root folder with its new children. + if let mobileRoot = maybeMobileRoot.successValue { + return buffer.getBufferChildrenGUIDsForParent(mobileRoot.guid) + .map { $0.map({ (mobileRoot: mobileRoot, children: $0.filter { !deletedChildren.contains($0) } + newBookmarkGUIDs) }) } + } else { + return local.getLocalItemWithGUID(BookmarkRoots.MobileFolderGUID) + .map { $0.map({ (mobileRoot: $0, children: newBookmarkGUIDs) }) } + } + } >>== { (mobileRoot: BookmarkMirrorItem, children: [GUID]) in + let payload = mobileRoot.asPayloadWithChildren(children) + guard let mappedGUID = payload["id"].string else { + return deferMaybe(MalformedRecordError()) + } + return deferMaybe(Record(id: mappedGUID, payload: payload)) + } + } + + func buildMobileRootAndChildrenRecords(_ local: LocalItemSource, _ buffer: BufferItemSource, additionalChildren: [BookmarkMirrorItem], deletedChildren: [GUID]) -> Deferred, childrenRecords: [Record])>> { + let childrenRecords = + additionalChildren.map { bkm -> Record in + let payload = bkm.asPayload() + let mappedGUID = payload["id"].string ?? bkm.guid + return Record(id: mappedGUID, payload: payload) + } + + deletedChildren.map { guid -> Record in + let payload = BookmarkBasePayload.deletedPayload(guid) + let mappedGUID = payload["id"].string ?? guid + return Record(id: mappedGUID, payload: payload) + } + + return self.buildMobileRootRecord(local, buffer, additionalChildren: additionalChildren, deletedChildren: deletedChildren) >>== { mobileRootRecord in + return deferMaybe((mobileRootRecord: mobileRootRecord, childrenRecords: childrenRecords)) + } + } + + func uploadSomeLocalRecords(_ storage: SyncableBookmarks & LocalItemSource & MirrorItemSource, _ mirrorer: BookmarksMirrorer, _ bookmarksClient: Sync15CollectionClient, mobileRootRecord: Record, childrenRecords: [Record]) -> Success { + var newBookmarkGUIDs: [GUID] = [] + var deletedBookmarksGUIDs: [GUID] = [] + for record in childrenRecords { + // No mutable l-values in Swift :( + if record.payload.deleted { + deletedBookmarksGUIDs.append(record.id) + } else { + newBookmarkGUIDs.append(record.id) + } + } + let records = [mobileRootRecord] + childrenRecords + return self.uploadRecordsSingleBatch(records, lastTimestamp: mirrorer.lastModified, storageClient: bookmarksClient) >>== { (timestamp: Timestamp, succeeded: [GUID]) -> Success in + + let bufferValuesToMoveFromLocal = Set(newBookmarkGUIDs).intersection(Set(succeeded)) + let deletedValues = Set(deletedBookmarksGUIDs).intersection(Set(succeeded)) + let mobileRoot = (mobileRootRecord.payload as MirrorItemable).toMirrorItem(timestamp) + let bufferOP = BufferUpdatedCompletionOp(bufferValuesToMoveFromLocal: bufferValuesToMoveFromLocal, deletedValues: deletedValues, mobileRoot: mobileRoot, modifiedTime: timestamp) + return storage.applyBufferUpdatedCompletionOp(bufferOP) >>> { + mirrorer.advanceNextDownloadTimestampTo(timestamp: timestamp) // We need to advance our batching downloader timestamp to match. See Bug 1253458. + return succeed() + } + } + } + + open func synchronizeBookmarksToStorage(_ storage: SyncableBookmarks & LocalItemSource & MirrorItemSource, usingBuffer buffer: BookmarkBufferStorage & BufferItemSource, withServer storageClient: Sync15StorageClient, info: InfoCollections, greenLight: @escaping () -> Bool, remoteClientsAndTabs: RemoteClientsAndTabs) -> SyncResult { + if self.prefs.boolForKey("dateAddedMigrationDone") != true { + self.lastFetched = 0 + self.prefs.setBool(true, forKey: "dateAddedMigrationDone") + } + + if let reason = self.reasonToNotSync(storageClient) { + return deferMaybe(.notStarted(reason)) + } + + let encoder = RecordEncoder(decode: BookmarkType.somePayloadFromJSON, encode: { $0.json }) + + guard let bookmarksClient = self.collectionClient(encoder, storageClient: storageClient) else { + log.error("Couldn't make bookmarks factory.") + return deferMaybe(FatalError(message: "Couldn't make bookmarks factory.")) + } + + let start = Date.nowMicroseconds() + let mirrorer = BookmarksMirrorer(storage: buffer, client: bookmarksClient, basePrefs: self.prefs, collection: "bookmarks", statsSession: self.statsSession) + let storer = TrivialBookmarkStorer(uploader: { records, lastTimestamp, onUpload in + let timestamp = lastTimestamp ?? self.lastFetched + return self.uploadRecords(records, lastTimestamp: timestamp, storageClient: bookmarksClient, onUpload: onUpload) + >>== effect { timestamp in + // We need to advance our batching downloader timestamp to match. See Bug 1253458. + self.setTimestamp(timestamp) + mirrorer.advanceNextDownloadTimestampTo(timestamp: timestamp) + } + }) + + statsSession.start() + + let doMirror = mirrorer.go(info: info, greenLight: greenLight) + let run: SyncResult + + if !AppConstants.shouldMergeBookmarks { + run = doMirror >>== { result -> SyncResult in + // Validate the buffer to report statistics. + if case .completed = result { + log.debug("Validating completed buffer download.") + return buffer.validate().bind { validationResult in + guard let invalidError = validationResult.failureValue as? BufferInvalidError else { + return deferMaybe(result) + } + return buffer.getUpstreamRecordCount().bind { checked -> Success in + self.statsSession.validationStats = self.validationStatsFrom(error: invalidError, checked: checked) + return self.maybeStartRepairProcedure(greenLight: greenLight, error: invalidError, remoteClientsAndTabs: remoteClientsAndTabs) + } >>> { + return deferMaybe(result) + } + } + } + return deferMaybe(result) + } >>== { result in + guard AppConstants.MOZ_SIMPLE_BOOKMARKS_SYNCING else { + return deferMaybe(result) + } + guard case .completed = result else { + return deferMaybe(result) + } + + // -1 because we also need to upload the mobile root. + return (storage.getLocalBookmarksModifications(limit: bookmarksClient.maxBatchPostRecords - 1) >>== { (deletedGUIDs, newBookmarks) -> Success in + guard newBookmarks.count > 0 || deletedGUIDs.count > 0 else { + return succeed() + } + return self.buildMobileRootAndChildrenRecords(storage, buffer, additionalChildren: newBookmarks, deletedChildren: deletedGUIDs) >>== { (mobileRootRecord, childrenRecords) in + return self.uploadSomeLocalRecords(storage, mirrorer, bookmarksClient, mobileRootRecord: mobileRootRecord, childrenRecords: childrenRecords) + } + }).bind { simpleSyncingResult in + if let failure = simpleSyncingResult.failureValue { + let description = failure is RecordTooLargeError ? "Record too large" : failure.description + Sentry.shared.send(message: "Failed to simple sync bookmarks", tag: SentryTag.bookmarks, severity: .error, description: description) + } + return deferMaybe(result) + } + } + } else { + run = doMirror >>== { result in + // Only bother trying to sync if the mirror operation wasn't interrupted or partial. + if case .completed = result { + return buffer.validate().bind { result in + if let invalidError = result.failureValue as? BufferInvalidError { + return buffer.getUpstreamRecordCount().bind { checked in + self.statsSession.validationStats = self.validationStatsFrom(error: invalidError, checked: checked) + return self.maybeStartRepairProcedure(greenLight: greenLight, error: invalidError, remoteClientsAndTabs: remoteClientsAndTabs) >>> { + return deferMaybe(invalidError) + } + } + } + + let applier = MergeApplier(buffer: buffer, storage: storage, client: storer, statsSession: self.statsSession, greenLight: greenLight) + return applier.go() + } + } + return deferMaybe(result) + } + } + + run.upon { result in + let end = Date.nowMicroseconds() + let duration = end - start + log.info("Bookmark \(AppConstants.shouldMergeBookmarks ? "sync" : "mirroring") took \(duration)µs. Result was \(result.successValue?.description ?? result.failureValue?.description ?? "failure")") + } + + return run + } + + private func validationStatsFrom(error: BufferInvalidError, checked: Int?) -> ValidationStats { + let problems = error.inconsistencies.map { ValidationProblem(name: $0.trackingEvent, count: $1.count) } + return ValidationStats(problems: problems, took: error.validationDuration, checked: checked) + } + + private func maybeStartRepairProcedure(greenLight: () -> Bool, error: BufferInvalidError, remoteClientsAndTabs: RemoteClientsAndTabs) -> Success { + guard AppConstants.MOZ_BOOKMARKS_REPAIR_REQUEST && greenLight() else { + return succeed() + } + log.warning("Buffer inconsistent, starting repair procedure") + let repairer = BookmarksRepairRequestor(scratchpad: self.scratchpad, basePrefs: self.basePrefs, remoteClients: remoteClientsAndTabs) + return repairer.startRepairs(validationInfo: error.inconsistencies).bind { result in + if let repairFailure = result.failureValue { + Sentry.shared.send(message: "Bookmarks repair failure", tag: SentryTag.bookmarks, severity: .error, description: repairFailure.description) + } else { + Sentry.shared.send(message: "Bookmarks repair succeeded", tag: SentryTag.bookmarks, severity: .debug) + } + return succeed() + } + } +} + +class MergeApplier { + let greenLight: () -> Bool + let buffer: BookmarkBufferStorage + let storage: SyncableBookmarks + let client: BookmarkStorer + let merger: BookmarksStorageMerger + let statsSession: SyncEngineStatsSession + + init(buffer: BookmarkBufferStorage & BufferItemSource, storage: SyncableBookmarks & LocalItemSource & MirrorItemSource, client: BookmarkStorer, statsSession: SyncEngineStatsSession, greenLight: @escaping () -> Bool) { + self.greenLight = greenLight + self.buffer = buffer + self.storage = storage + self.merger = ThreeWayBookmarksStorageMerger(buffer: buffer, storage: storage) + self.client = client + self.statsSession = statsSession + } + + // Exposed for use from tests. + func applyResult(_ result: BookmarksMergeResult) -> Success { + return result.applyToClient(self.client, storage: self.storage, buffer: self.buffer) + } + + func go() -> SyncResult { + guard self.greenLight() else { + log.info("Green light turned red; not merging bookmarks.") + return deferMaybe(SyncStatus.completed(statsSession.end())) + } + + return self.merger.merge() + >>== self.applyResult + >>> always(SyncStatus.completed(statsSession.end())) + } +} + +/** + * The merger takes as input an existing storage state (mirror and local override), + * a buffer of new incoming records that relate to the mirror, and performs a three-way + * merge. + * + * The merge itself does not mutate storage. The result of the merge is conceptually a + * tuple: a new mirror state, a set of reconciled + locally changed records to upload, + * and two checklists of buffer and local state to discard. + * + * Typically the merge will be complete, resulting in a new mirror state, records to + * upload, and completely emptied buffer and local. In the case of partial inconsistency + * this will not be the case; incomplete subtrees will remain in the buffer. (We don't + * expect local subtrees to ever be incomplete.) + * + * It is expected that the caller will immediately apply the result in this order: + * + * 1. Upload the remote changes, if any. If this fails we can retry the entire process. + * + * 2(a). Apply the local changes, if any. If this fails we will re-download the records + * we just uploaded, and should reach the same end state. + * This step takes a timestamp key from (1), because pushing a record into the mirror + * requires a server timestamp. + * + * 2(b). Switch to the new mirror state. If this fails, we should find that our reconciled + * server contents apply neatly to our mirror and empty local, and we'll reach the + * same end state. + * + * Mirror state is applied in a sane order to respect relational constraints, even though + * we configure sqlite to defer constraint validation until the transaction is committed. + * That means: + * + * - Add any new records in the value table. + * - Change any existing records in the value table. + * - Update structure. + * - Remove records from the value table. + * + * 3. Apply buffer changes. We only do this after the mirror has advanced; if we fail to + * clean up the buffer, it'll reconcile neatly with the mirror on a subsequent try. + * + * 4. Update bookkeeping timestamps. If this fails we will download uploaded records, + * find they match, and have no repeat merging work to do. + * + * The goal of merging is that the buffer is empty (because we reconciled conflicts and + * updated the server), our local overlay is empty (because we reconciled conflicts and + * applied our changes to the server), and the mirror matches the server. + * + * Note that upstream application is robust: we can use XIUS to ensure that writes don't + * race. Buffer application is similarly robust, because this code owns all writes to the + * buffer. Local and mirror application, however, is not: the user's actions can cause + * changes to write to the database before we're done applying the results of a sync. + * We mitigate this a little by being explicit about the local changes that we're flushing + * (rather than, say, `DELETE FROM local`), but to do better we'd need change detection + * (e.g., an in-memory monotonic counter) or locking to prevent bookmark operations from + * racing. Later! + */ +protocol BookmarksStorageMerger: class { + init(buffer: BookmarkBufferStorage & BufferItemSource, storage: SyncableBookmarks & LocalItemSource & MirrorItemSource) + func merge() -> Deferred> +} + +class NoOpBookmarksMerger: BookmarksStorageMerger { + let buffer: BookmarkBufferStorage & BufferItemSource + let storage: SyncableBookmarks & LocalItemSource & MirrorItemSource + + required init(buffer: BookmarkBufferStorage & BufferItemSource, storage: SyncableBookmarks & LocalItemSource & MirrorItemSource) { + self.buffer = buffer + self.storage = storage + } + + func merge() -> Deferred> { + return deferMaybe(BookmarksMergeResult.NoOp(ItemSources(local: self.storage, mirror: self.storage, buffer: self.buffer))) + } +} + +class ThreeWayBookmarksStorageMerger: BookmarksStorageMerger { + let buffer: BookmarkBufferStorage & BufferItemSource + let storage: SyncableBookmarks & LocalItemSource & MirrorItemSource + + required init(buffer: BookmarkBufferStorage & BufferItemSource, storage: SyncableBookmarks & LocalItemSource & MirrorItemSource) { + self.buffer = buffer + self.storage = storage + } + + // MARK: - BookmarksStorageMerger. + + // Trivial one-way sync. + fileprivate func applyLocalDirectlyToMirror() -> Deferred> { + // Theoretically, we do the following: + // * Construct a virtual bookmark tree overlaying local on the mirror. + // * Walk the tree to produce Sync records. + // * Upload those records. + // * Flatten that tree into the mirror, clearing local. + // + // This is simpler than a full three-way merge: it's tree delta then flatten. + // + // But we are confident that our local changes, when overlaid on the mirror, are + // consistent. So we can take a little bit of a shortcut: process records + // directly, rather than building a tree. + // + // So do the following: + // * Take everything in `local` and turn it into a Sync record. This means pulling + // folder hierarchies out of localStructure, values out of local, and turning + // them into records. Do so in hierarchical order if we can, and set sortindex + // attributes to put folders first. + // * Upload those records in as few batches as possible. Ensure that each batch + // is consistent, if at all possible, though we're hoping for server support for + // atomic writes. + // * Take everything in local that was successfully uploaded and move it into the + // mirror, using the timestamps we tracked from the upload. + // + // Optionally, set 'again' to true in our response, and do this work only for a + // particular subtree (e.g., a single root, or a single branch of changes). This + // allows us to make incremental progress. + + // TODO + log.debug("No special-case local-only merging yet. Falling back to three-way merge.") + return self.threeWayMerge() + } + + fileprivate func applyIncomingDirectlyToMirror() -> Deferred> { + // If the incoming buffer is consistent -- and the result of the mirrorer + // gives us a hint about that! -- then we can move the buffer records into + // the mirror directly. + // + // Note that this is also true for entire subtrees: if none of the children + // of, say, 'menu________' are modified locally, then we can apply it without + // merging. + // + // TODO + log.debug("No special-case remote-only merging yet. Falling back to three-way merge.") + return self.threeWayMerge() + } + + // This is exposed for testing. + func getMerger() -> Deferred> { + return self.storage.treesForEdges() >>== { (local, remote) in + // At this point *might* have two empty trees. This should only be the case if + // there are value-only changes (e.g., a renamed bookmark). + // We don't fail in that case, but we could optimize here. + + // Find the mirror tree so we can compare. + return self.storage.treeForMirror() >>== { mirror in + // At this point we know that there have been changes both locally and remotely. + // (Or, in the general case, changes either locally or remotely.) + + let itemSources = ItemSources(local: CachingLocalItemSource(source: self.storage), mirror: CachingMirrorItemSource(source: self.storage), buffer: CachingBufferItemSource(source: self.buffer)) + return deferMaybe(ThreeWayTreeMerger(local: local, mirror: mirror, remote: remote, itemSources: itemSources)) + } + } + } + + func getMergedTree() -> Deferred> { + return self.getMerger() >>== { $0.produceMergedTree() } + } + + func threeWayMerge() -> Deferred> { + return self.getMerger() >>== { $0.produceMergedTree() >>== $0.produceMergeResultFromMergedTree } + } + + func merge() -> Deferred> { + return self.buffer.isEmpty() >>== { noIncoming in + + // TODO: the presence of empty desktop roots in local storage + // isn't something we really need to worry about. Can we skip it here? + + return self.storage.isUnchanged() >>== { noOutgoing in + switch (noIncoming, noOutgoing) { + case (true, true): + // Nothing to do! + log.debug("No incoming and no outgoing records: no-op.") + return deferMaybe(BookmarksMergeResult.NoOp(ItemSources(local: self.storage, mirror: self.storage, buffer: self.buffer))) + case (true, false): + // No incoming records to apply. Unilaterally apply local changes. + return self.applyLocalDirectlyToMirror() + case (false, true): + // No outgoing changes. Unilaterally apply remote changes if they're consistent. + return self.buffer.validate() >>> self.applyIncomingDirectlyToMirror + default: + // Changes on both sides. Merge. + return self.buffer.validate() >>> self.threeWayMerge + } + } + } + } +} diff --git a/mobile/ios/Sync/Synchronizers/Bookmarks/Merging.swift b/mobile/ios/Sync/Synchronizers/Bookmarks/Merging.swift new file mode 100644 index 0000000000..40f1a23a65 --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/Bookmarks/Merging.swift @@ -0,0 +1,336 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared +import Storage +import XCGLogger + +private let log = Logger.syncLogger + +// Because generic protocols in Swift are a pain in the ass. +public protocol BookmarkStorer: class { + // TODO: this should probably return a timestamp. + func applyUpstreamCompletionOp(_ op: UpstreamCompletionOp, itemSources: ItemSources, trackingTimesInto local: LocalOverrideCompletionOp) -> Deferred> +} + +open class UpstreamCompletionOp: PerhapsNoOp { + // Upload these records from the buffer, but with these child lists. + open var amendChildrenFromBuffer: [GUID: [GUID]] = [:] + + // Upload these records from the mirror, but with these child lists. + open var amendChildrenFromMirror: [GUID: [GUID]] = [:] + + // Upload these records from local, but with these child lists. + open var amendChildrenFromLocal: [GUID: [GUID]] = [:] + + // Upload these records as-is. + open var records: [Record] = [] + + open let ifUnmodifiedSince: Timestamp? + + open var isNoOp: Bool { + return records.isEmpty + } + + public init(ifUnmodifiedSince: Timestamp?=nil) { + self.ifUnmodifiedSince = ifUnmodifiedSince + } +} + +open class BookmarksMergeResult: PerhapsNoOp { + let uploadCompletion: UpstreamCompletionOp + let overrideCompletion: LocalOverrideCompletionOp + let bufferCompletion: BufferCompletionOp + let itemSources: ItemSources + + open var isNoOp: Bool { + return self.uploadCompletion.isNoOp && + self.overrideCompletion.isNoOp && + self.bufferCompletion.isNoOp + } + + func applyToClient(_ client: BookmarkStorer, storage: SyncableBookmarks, buffer: BookmarkBufferStorage) -> Success { + return client.applyUpstreamCompletionOp(self.uploadCompletion, itemSources: self.itemSources, trackingTimesInto: self.overrideCompletion) + >>> { storage.applyLocalOverrideCompletionOp(self.overrideCompletion, itemSources: self.itemSources) } + >>> { buffer.applyBufferCompletionOp(self.bufferCompletion, itemSources: self.itemSources) } + } + + init(uploadCompletion: UpstreamCompletionOp, overrideCompletion: LocalOverrideCompletionOp, bufferCompletion: BufferCompletionOp, itemSources: ItemSources) { + self.uploadCompletion = uploadCompletion + self.overrideCompletion = overrideCompletion + self.bufferCompletion = bufferCompletion + self.itemSources = itemSources + } + + static func NoOp(_ itemSources: ItemSources) -> BookmarksMergeResult { + return BookmarksMergeResult(uploadCompletion: UpstreamCompletionOp(), overrideCompletion: LocalOverrideCompletionOp(), bufferCompletion: BufferCompletionOp(), itemSources: itemSources) + } +} + +// MARK: - Errors. + +open class BookmarksMergeError: MaybeErrorType, SyncPingFailureFormattable { + fileprivate let error: Error? + + init(error: Error?=nil) { + self.error = error + } + + open var description: String { + return "Merge error: \(self.error ??? "nil")" + } + + open var failureReasonName: SyncPingFailureReasonName { + return .otherError + } +} + +open class BookmarksMergeConsistencyError: BookmarksMergeError { + override open var description: String { + return "Merge consistency error" + } +} + +open class BookmarksMergeErrorTreeIsUnrooted: BookmarksMergeConsistencyError { + open let roots: Set + + public init(roots: Set) { + self.roots = roots + } + + override open var description: String { + return "Tree is unrooted: roots are \(self.roots)" + } +} + +enum MergeState { + case unknown // Default state. + case unchanged // Nothing changed: no work needed. + case remote // Take the associated remote value. + case local // Take the associated local value. + case new(value: T) // Take this synthesized value. + + var isUnchanged: Bool { + if case .unchanged = self { + return true + } + return false + } + + var isUnknown: Bool { + if case .unknown = self { + return true + } + return false + } + + var label: String { + switch self { + case .unknown: + return "Unknown" + case .unchanged: + return "Unchanged" + case .remote: + return "Remote" + case .local: + return "Local" + case .new: + return "New" + } + } +} + +func ==(lhs: MergeState, rhs: MergeState) -> Bool { + switch (lhs, rhs) { + case (.unknown, .unknown): + return true + case (.unchanged, .unchanged): + return true + case (.remote, .remote): + return true + case (.local, .local): + return true + case let (.new(lh), .new(rh)): + return lh == rh + default: + return false + } +} + +/** + * Using this: + * + * You get one for the root. Then you give it children for the roots + * from the mirror. + * + * Then you walk those, populating the remote and local nodes by looking + * at the left/right trees. + * + * By comparing left and right, and doing value-based comparisons if necessary, + * a merge state is decided and assigned for both value and structure. + * + * One then walks both left and right child structures (both to ensure that + * all nodes on both left and right will be visited!) recursively. + */ +class MergedTreeNode { + let guid: GUID + let mirror: BookmarkTreeNode? + var remote: BookmarkTreeNode? + var local: BookmarkTreeNode? + + var hasLocal: Bool { return self.local != nil } + var hasMirror: Bool { return self.mirror != nil } + var hasRemote: Bool { return self.remote != nil } + + var valueState: MergeState = MergeState.unknown + var structureState: MergeState = MergeState.unknown + + var hasDecidedChildren: Bool { + return !self.structureState.isUnknown + } + + var mergedChildren: [MergedTreeNode]? + + // One-sided constructors. + static func forRemote(_ remote: BookmarkTreeNode, mirror: BookmarkTreeNode?=nil) -> MergedTreeNode { + let n = MergedTreeNode(guid: remote.recordGUID, mirror: mirror, structureState: MergeState.remote) + n.remote = remote + n.valueState = MergeState.remote + return n + } + + static func forLocal(_ local: BookmarkTreeNode, mirror: BookmarkTreeNode?=nil) -> MergedTreeNode { + let n = MergedTreeNode(guid: local.recordGUID, mirror: mirror, structureState: MergeState.local) + n.local = local + n.valueState = MergeState.local + return n + } + + static func forUnchanged(_ mirror: BookmarkTreeNode) -> MergedTreeNode { + let n = MergedTreeNode(guid: mirror.recordGUID, mirror: mirror, structureState: MergeState.unchanged) + n.valueState = MergeState.unchanged + return n + } + + init(guid: GUID, mirror: BookmarkTreeNode?, structureState: MergeState) { + self.guid = guid + self.mirror = mirror + self.structureState = structureState + } + + init(guid: GUID, mirror: BookmarkTreeNode?) { + self.guid = guid + self.mirror = mirror + } + + // N.B., you cannot recurse down `decidedStructure`: you'll depart from the + // merged tree. You need to use `mergedChildren` instead. + fileprivate var decidedStructure: BookmarkTreeNode? { + switch self.structureState { + case .unknown: + return nil + case .unchanged: + return self.mirror + case .remote: + return self.remote + case .local: + return self.local + case let .new(node): + return node + } + } + + func asUnmergedTreeNode() -> BookmarkTreeNode { + return self.decidedStructure ?? BookmarkTreeNode.unknown(guid: self.guid) + } + + // Recursive. Starts returning Unknown when nodes haven't been processed. + func asMergedTreeNode() -> BookmarkTreeNode { + guard let decided = self.decidedStructure, + let merged = self.mergedChildren else { + return BookmarkTreeNode.unknown(guid: self.guid) + } + + if case .folder = decided { + let children = merged.map { $0.asMergedTreeNode() } + return BookmarkTreeNode.folder(guid: self.guid, children: children) + } + + return decided + } + + var isFolder: Bool { + return self.mergedChildren != nil + } + + func dump(_ indent: Int) { + precondition(indent < 200) + let r: Character = "R" + let l: Character = "L" + let m: Character = "M" + let ind = indenting(indent) + print(ind, "[V: ", box(self.remote, r), box(self.mirror, m), box(self.local, l), self.guid, self.valueState.label, "]") + guard self.isFolder else { + return + } + + print(ind, "[S: ", self.structureState.label, "]") + if let children = self.mergedChildren { + print(ind, " ..") + for child in children { + child.dump(indent + 2) + } + } + } +} + +private func box(_ x: T?, _ c: Character) -> Character { + if x == nil { + return "□" + } + return c +} + +private func indenting(_ by: Int) -> String { + return String(repeating: " ", count: by) +} + +class MergedTree { + var root: MergedTreeNode + var deleteLocally: Set = Set() + var deleteRemotely: Set = Set() + var deleteFromMirror: Set = Set() + var acceptLocalDeletion: Set = Set() + var acceptRemoteDeletion: Set = Set() + + var allGUIDs: Set { + var out = Set([self.root.guid]) + func acc(_ node: MergedTreeNode) { + guard let children = node.mergedChildren else { + return + } + out.formUnion(Set(children.map { $0.guid })) + children.forEach(acc) + } + acc(self.root) + return out + } + + init(mirrorRoot: BookmarkTreeNode) { + self.root = MergedTreeNode(guid: mirrorRoot.recordGUID, mirror: mirrorRoot, structureState: MergeState.unchanged) + self.root.valueState = MergeState.unchanged + } + + func dump() { + print("Deleted locally: \(self.deleteLocally.joined(separator: ", "))") + print("Deleted remotely: \(self.deleteRemotely.joined(separator: ", "))") + print("Deleted from mirror: \(self.deleteFromMirror.joined(separator: ", "))") + print("Accepted local deletions: \(self.acceptLocalDeletion.joined(separator: ", "))") + print("Accepted remote deletions: \(self.acceptRemoteDeletion.joined(separator: ", "))") + print("Root: ") + self.root.dump(0) + } +} diff --git a/mobile/ios/Sync/Synchronizers/Bookmarks/ThreeWayTreeMerger.swift b/mobile/ios/Sync/Synchronizers/Bookmarks/ThreeWayTreeMerger.swift new file mode 100644 index 0000000000..00aabadf00 --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/Bookmarks/ThreeWayTreeMerger.swift @@ -0,0 +1,1423 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared +import Storage +import XCGLogger + +private let log = Logger.syncLogger + +private func negate(_ f: @escaping (T) throws -> Bool) -> (T) throws -> Bool { + return { try !f($0) } +} + +extension Collection { + func exclude(_ predicate: @escaping (Self.Iterator.Element) throws -> Bool) throws -> [Self.Iterator.Element] { + return try self.filter(negate(predicate)) + } +} + +/** + * This class takes as input three 'trees'. + * + * The mirror is always complete, never contains deletions, never has + * orphans, and has a single root. + * + * Each of local and remote can contain a number of subtrees (each of which must + * be a folder or root), a number of deleted GUIDs, and a number of orphans (records + * with no known parent). + * + * As output it produces a merged tree. The tree contains the new structure, + * including every record that we're keeping, and also makes note of any deletions. + * + * The merged tree can be walked to yield a set of operations against the original + * three trees. Those operations will make the upstream source and local storage + * match the merge output. + * + * It's very likely that there's almost no overlap between local and remote, and + * thus no real conflicts to resolve -- a three-way merge isn't always a bad thing + * -- but we won't know until we compare records. + * + * + * Even though this is called 'three way merge', it also handles the case + * of a two-way merge (one without a shared parent; for the roots, this will only + * be on a first sync): content-based and structural merging is needed at all + * layers of the hierarchy, so we simply generalize that to also apply to roots. + * + * In a sense, a two-way merge is solved by constructing a shared parent consisting of + * roots, which are implicitly shared. + * + * (Special care must be taken to not deduce that one side has deleted a root, of course, + * as would be the case of a Sync server that doesn't contain + * a Mobile Bookmarks folder -- the set of roots can only grow, not shrink.) + * + * + * To begin with we structurally reconcile. If necessary we will lazily fetch the + * attributes of records in order to do a content-based reconciliation. Once we've + * matched up any records that match (including remapping local GUIDs), we're able to + * process _content_ changes, which is much simpler. + * + * We have to handle an arbitrary combination of the following structural operations: + * + * * Creating a folder. + * Created folders might now hold existing items, new items, or nothing at all. + * * Creating a bookmark. + * It might be in a new folder or an existing folder. + * * Moving one or more leaf records to an existing or new folder. + * * Reordering the children of a folder. + * * Deleting an entire subtree. + * * Deleting an entire subtree apart from some moved nodes. + * * Deleting a leaf node. + * * Transplanting a subtree: moving a folder but not changing its children. + * + * And, of course, the non-structural operations such as renaming or changing URLs. + * + * We ignore all changes to roots themselves; the only acceptable operation on a root + * is to change its children. The Places root is entirely immutable. + * + * Steps: + * * Construct a collection of subtrees for local and buffer, and a complete tree for the mirror. + * The more thorough this step, the more confidence we have in consistency. + * * Fetch all local and remote deletions. These won't be included in structure (for obvious + * reasons); we hold on to them explicitly so we can spot the difference between a move + * and a deletion. + * * Walk each subtree, top-down. At each point if there are two back-pointers to + * the mirror node for a GUID, we have a potential conflict, and we have all three + * parts that we need to resolve it via a content-based or structure-based 3WM. + * + * Observations: + * * If every GUID on each side is present in the mirror, we have no new records. + * * If a non-root GUID is present on both sides but not in the mirror, then either + * we're re-syncing from scratch, or (unlikely) we have a random collision. + * * Otherwise, we have a GUID that we don't recognize. We will structure+content reconcile + * this later -- we first make sure we have handled any tree moves, so that the addition + * of a bookmark to a moved folder on A, and the addition of the same bookmark to the non- + * moved version of the folder, will collide successfully. + * + * When we look at a child list: + * * It's the same. Great! Keep walking down. + * * There are added GUIDs. + * * An added GUID might be a move from elsewhere. Coordinate with the removal step. + * * An added GUID might be a brand new record. If there are local additions too, + * check to see if they value-reconcile, and keep the remote GUID. + * * There are removed GUIDs. + * * A removed GUID might have been deleted. Deletions win. + * * A missing GUID might be a move -- removed from here and added to another folder. + * Process this as a move. + * * The order has changed. + * + * When we get to a subtree that contains no changes, we can never hit conflicts, and + * application becomes easier. + * + * When we run out of subtrees on both sides, we're done. + * + * Note that these trees don't include values. This is because we usually don't need them: + * if there are no conflicts, or no shared parents, we can do everything we need to do + * at this stage simply with structure and GUIDs, and then flush rows straight from the + * buffer into the mirror with a single SQL INSERT. We do need to fetch values later + * in some cases: to amend child lists or otherwise construct outbound records. We do + * need to fetch values immediately in other cases: in order to reconcile conflicts. + * Those should ordinarily be uncommon, and because we know most of the conflicting + * GUIDs up-front, we can prime a cache of records. + */ +class ThreeWayTreeMerger { + let local: BookmarkTree + let mirror: BookmarkTree + let remote: BookmarkTree + var merged: MergedTree + + // Don't merge twice. + var mergeAttempted: Bool = false + + let itemSources: ItemSources + + // Sets computed by looking at the three trees. These are used for diagnostics, + // to simplify operations, to pre-fetch items for value comparison, and for testing. + + let mirrorAllGUIDs: Set // Excluding deletions. + let localAllGUIDs: Set // Excluding deletions. + let remoteAllGUIDs: Set // Excluding deletions. + let localAdditions: Set // New records added locally, not present in the mirror. + let remoteAdditions: Set // New records from the server, not present in the mirror. + let allDeletions: Set // Records deleted locally or remotely. + var allChangedGUIDs: Set // Everything added or changed locally or remotely. + let conflictingGUIDs: Set // Anything added or changed both locally and remotely. + + let nonRemoteKnownGUIDs: Set // Everything existing, added, or deleted locally or in the mirror. + + // For now, track just one list. We might need to split this later. + var done: Set = Set() + + // Local records that we identified as being the same as remote records. + var duped: Set = Set() + + init(local: BookmarkTree, mirror: BookmarkTree, remote: BookmarkTree, itemSources: ItemSources) { + precondition(mirror.root != nil) + assert((mirror.root!.children?.count ?? 0) == BookmarkRoots.RootChildren.count) + precondition(mirror.orphans.isEmpty) + precondition(mirror.deleted.isEmpty) + precondition(mirror.subtrees.count == 1) + + // These are runtime-tested in merge(). assert to make sure that tests + // don't do anything stupid, and we don't slip past those constraints. + //assert(local.isFullyRootedIn(mirror)) + //assert(remote.isFullyRootedIn(mirror)) + + self.local = local + self.mirror = mirror + self.remote = remote + self.itemSources = itemSources + self.merged = MergedTree(mirrorRoot: self.mirror.root!) + + // We won't get here unless every local and remote orphan is correctly rooted + // when overlaid on the mirror, so we don't need to exclude orphans here. + self.mirrorAllGUIDs = self.mirror.modified + self.localAllGUIDs = self.local.modified + self.remoteAllGUIDs = self.remote.modified + + self.localAdditions = localAllGUIDs.subtracting(mirrorAllGUIDs) + self.remoteAdditions = remoteAllGUIDs.subtracting(mirrorAllGUIDs) + self.allDeletions = self.local.deleted.union(self.remote.deleted) + self.allChangedGUIDs = localAllGUIDs.union(self.remoteAllGUIDs) + self.conflictingGUIDs = localAllGUIDs.intersection(remoteAllGUIDs) + self.nonRemoteKnownGUIDs = self.mirrorAllGUIDs.union(self.localAllGUIDs).union(self.local.deleted) + } + + fileprivate func nullOrMatch(_ a: String?, _ b: String?) -> Bool { + guard let a = a, let b = b else { + return true + } + return a == b + } + + /** + * When we have a folder match and new records on each side -- records + * not mentioned in the buffer -- it's possible that the new records + * are the same but have different GUIDs. + * This function will look at value matches to identify a local + * equivalent in this folder, returning nil if none are found. + * + * Note that we don't match records that have already been matched, and + * we don't match any for which a GUID is known in the mirror or remote. + */ + fileprivate func findNewLocalNodeMatchingContentOfRemoteNote(_ remote: BookmarkTreeNode, inFolder parent: GUID, withLocalChildren children: [BookmarkTreeNode], havingSeen seen: Set) -> BookmarkTreeNode? { + // TODO: don't compute this list once per incoming child! Profile me. + let candidates = children.filter { child in + let childGUID = child.recordGUID + return !seen.contains(childGUID) && // Not already used in this folder. + !self.remoteAdditions.contains(childGUID) && // Not locally and remotely added with same GUID. + !self.remote.deleted.contains(childGUID) && // Not remotely deleted. + !self.done.contains(childGUID) // Not already processed elsewhere in the tree. + } + + guard let remoteValue = self.itemSources.buffer.getBufferItemWithGUID(remote.recordGUID).value.successValue else { + log.error("Couldn't find remote value for \(remote.recordGUID).") + return nil + } + + let guids = candidates.map { $0.recordGUID } + guard let items = self.itemSources.local.getLocalItemsWithGUIDs(guids).value.successValue else { + log.error("Couldn't find local values for \(candidates.count) candidates.") + return nil + } + + // Return the first candidate that's a value match. + guard let localItem = (guids.flatMap { items[$0] }.find { $0.sameAs(remoteValue) }) else { + log.debug("Didn't find a local value match for new remote record \(remote.recordGUID).") + return nil + } + + log.debug("Found a local match \(localItem.guid) for new remote record \(remote.recordGUID) in parent \(parent).") + // Find the original contributing child node by GUID. + return children.find { $0.recordGUID == localItem.guid } + } + + fileprivate func takeMirrorChildrenInMergedNode(_ result: MergedTreeNode) throws { + guard let mirrorChildren = result.mirror?.children else { + preconditionFailure("Expected children.") + } + + let out: [MergedTreeNode] = try mirrorChildren.flatMap { child in + // TODO: handle deletions. That might change the below from 'Unchanged' + // to 'New'. + let childGUID = child.recordGUID + if self.done.contains(childGUID) { + log.warning("Not taking mirror child \(childGUID): already done. This is unexpected.") + return nil + } + let localCounterpart = self.local.find(childGUID) + let remoteCounterpart = self.remote.find(childGUID) + return try self.mergeNode(childGUID, localNode: localCounterpart, mirrorNode: child, remoteNode: remoteCounterpart) + } + + result.mergedChildren = out + result.structureState = MergeState.unchanged + } + + fileprivate func oneWayMergeChildListsIntoMergedNode(_ result: MergedTreeNode, fromRemote remote: BookmarkTreeNode) throws { + guard case .folder = remote else { + preconditionFailure("Expected folder from which to merge children.") + } + + result.structureState = MergeState.remote // If the list changes, this will switch to .new. + try self.mergeChildListsIntoMergedNode(result, fromLocal: nil, remote: remote, mirror: self.mirror.find(remote.recordGUID)) + } + + fileprivate func oneWayMergeChildListsIntoMergedNode(_ result: MergedTreeNode, fromLocal local: BookmarkTreeNode) throws { + guard case .folder = local else { + preconditionFailure("Expected folder from which to merge children.") + } + + result.structureState = MergeState.local // If the list changes, this will switch to .new. + try self.mergeChildListsIntoMergedNode(result, fromLocal: local, remote: nil, mirror: self.mirror.find(local.recordGUID)) + } + + fileprivate func mergeChildListsIntoMergedNode(_ result: MergedTreeNode, fromLocal local: BookmarkTreeNode?, remote: BookmarkTreeNode?, mirror: BookmarkTreeNode?) throws { + precondition(local != nil || remote != nil, "Expected either local or remote folder for merge.") + + // The most trivial implementation: take everything in the first list, then append + // everything new in the second list. + // Anything present in both is resolved. + // We can't get away from handling deletions and moves, etc. -- one might have + // created a folder on two devices and moved existing items on one, some of which + // might have been deleted on the other. + // This kind of shit is why bookmark sync is hard. + // See each of the test cases in TestBookmarkTreeMerging, which have helpful diagrams. + var out: [MergedTreeNode] = [] + var seen: Set = Set() + + var changed = false + + func processRemoteOrphansForNode(_ node: BookmarkTreeNode) throws -> [MergedTreeNode]? { + // Now we recursively merge down into our list of orphans. If those contain deleted + // subtrees, excess leaves will be flattened up; we'll get a single list of nodes + // here, and we'll take them as additional children. + + let guid = node.recordGUID + func isLocallyDeleted(_ child: BookmarkTreeNode) throws -> Bool { + return try checkForLocalDeletionOfRemoteNode(child, mirrorNode: self.mirror.find(child.recordGUID)) + } + + guard let orphans = try node.children?.exclude(isLocallyDeleted), !orphans.isEmpty else { + log.debug("No remote orphans from local deletion of \(guid).") + return nil + } + + let mergedOrphans = try orphans.map { (orphan: BookmarkTreeNode) throws -> MergedTreeNode in + let guidO = orphan.recordGUID + let locO = self.local.find(guidO) + let remO = orphan + let mirO = self.mirror.find(guidO) + log.debug("Merging up remote orphan \(guidO).") + return try self.mergeNode(guidO, localNode: locO, mirrorNode: mirO, remoteNode: remO) + } + + log.debug("Collected \(mergedOrphans.count) remote orphans for deleted folder \(guid).") + if mergedOrphans.isEmpty { + return nil + } + changed = true + return mergedOrphans + } + + func processLocalOrphansForNode(_ node: BookmarkTreeNode) throws -> [MergedTreeNode]? { + // Now we recursively merge down into our list of orphans. If those contain deleted + // subtrees, excess leaves will be flattened up; we'll get a single list of nodes + // here, and we'll take them as additional children. + + let guid = node.recordGUID + + if case .folder = node {} else { + log.debug("\(guid) isn't a folder, so it won't have orphans.") + return nil + } + + func isRemotelyDeleted(_ child: BookmarkTreeNode) throws -> Bool { + return try checkForRemoteDeletionOfLocalNode(child, mirrorNode: self.mirror.find(child.recordGUID)) + } + + guard let orphans = try node.children?.exclude(isRemotelyDeleted), !orphans.isEmpty else { + log.debug("No local orphans from remote deletion of folder \(guid).") + return nil + } + + let mergedOrphans = try orphans.map { (orphan: BookmarkTreeNode) throws -> MergedTreeNode in + let guidO = orphan.recordGUID + let locO = orphan + let remO = self.remote.find(guidO) + let mirO = self.mirror.find(guidO) + log.debug("Merging up local orphan \(guidO).") + return try self.mergeNode(guidO, localNode: locO, mirrorNode: mirO, remoteNode: remO) + } + + log.debug("Collected \(mergedOrphans.count) local orphans for deleted folder \(guid).") + if mergedOrphans.isEmpty { + return nil + } + changed = true + return mergedOrphans + } + + func checkForLocalDeletionOfRemoteNode(_ node: BookmarkTreeNode, mirrorNode: BookmarkTreeNode?) throws -> Bool { + let guid = node.recordGUID + + guard self.local.deleted.contains(guid) else { + return false + } + + // It was locally deleted. This would be good enough for us, + // but we need to ensure that any remote children are recursively + // deleted or handled as orphans. + log.warning("Quietly accepting local deletion of record \(guid).") + changed = true + + self.merged.deleteRemotely.insert(guid) + self.merged.acceptLocalDeletion.insert(guid) + if mirrorNode != nil { + self.merged.deleteFromMirror.insert(guid) + } + + if let orphans = try processRemoteOrphansForNode(node) { + out.append(contentsOf: try self.relocateOrphansTo(result, orphans: orphans)) + } + return true + } + + func checkForRemoteDeletionOfLocalNode(_ node: BookmarkTreeNode, mirrorNode: BookmarkTreeNode?) throws -> Bool { + let guid = node.recordGUID + + guard self.remote.deleted.contains(guid) else { + return false + } + + // It was remotely deleted. This would be good enough for us, + // but we need to ensure that any local children are recursively + // deleted or handled as orphans. + log.warning("Quietly accepting remote deletion of record \(guid).") + + self.merged.deleteLocally.insert(guid) + self.merged.acceptRemoteDeletion.insert(guid) + if mirrorNode != nil { + self.merged.deleteFromMirror.insert(guid) + } + + if let orphans = try processLocalOrphansForNode(node) { + out.append(contentsOf: try self.relocateOrphansTo(result, orphans: orphans)) + } + return true + } + + // Do a recursive merge of each child. + if let remote = remote, let children = remote.children { + try children.forEach { rem in + let guid = rem.recordGUID + seen.insert(guid) + + if self.done.contains(guid) { + log.debug("Processing children of \(result.guid). Child \(guid) already seen elsewhere!") + return + } + + if try checkForLocalDeletionOfRemoteNode(rem, mirrorNode: self.mirror.find(guid)) { + log.debug("Child \(guid) is locally deleted.") + return + } + + let mir = self.mirror.find(guid) + if let localByGUID = self.local.find(guid) { + // Let's check the parent of the local match. If it differs, then the matching + // record is elsewhere in the local tree, and we need to decide which place to + // keep it. + // We do so by finding the modification time of the parent on each side, + // unless one of the records is explicitly non-modified. + if let localParentGUID = self.local.parents[guid] { + + // Oh hey look! Ad hoc three-way merge! + let mirrorParentGUID = self.mirror.parents[guid] + + if localParentGUID != result.guid { + log.debug("Local child \(guid) is in folder \(localParentGUID), but remotely is in \(result.guid).") + if mirrorParentGUID != localParentGUID { + log.debug("… and locally it has changed since our last sync, moving from \(mirrorParentGUID ?? "nil") to \(localParentGUID).") + + // Find out which parent is most recent. + if let localRecords = self.itemSources.local.getLocalItemsWithGUIDs([localParentGUID, guid]).value.successValue, + let remoteRecords = self.itemSources.buffer.getBufferItemsWithGUIDs([result.guid, guid]).value.successValue { + + let latestLocalTimestamp = max(localRecords[guid]?.localModified ?? 0, localRecords[localParentGUID]?.localModified ?? 0) + let latestRemoteTimestamp = max(remoteRecords[guid]?.serverModified ?? 0, remoteRecords[result.guid]?.serverModified ?? 0) + log.debug("Latest remote timestamp: \(latestRemoteTimestamp). Latest local timestamp: \(latestLocalTimestamp).") + + if latestLocalTimestamp > latestRemoteTimestamp { + log.debug("Keeping record in its local position. We'll merge these later.") + return + } + + log.debug("Taking remote, because it's later. Merging now.") + } + } else { + log.debug("\(guid) didn't move from \(mirrorParentGUID ?? "nil") since our last sync. Taking remote parent.") + } + } else { + log.debug("\(guid) is locally in \(localParentGUID) and remotely in \(result.guid). Easy.") + } + } + + out.append(try self.mergeNode(guid, localNode: localByGUID, mirrorNode: mir, remoteNode: rem)) + return + } + + // We don't ever have to handle moves in this case: we only search this directory. + let localByContent: BookmarkTreeNode? + if let localChildren = local?.children { + localByContent = self.findNewLocalNodeMatchingContentOfRemoteNote(rem, inFolder: result.guid, withLocalChildren: localChildren, havingSeen: seen) + } else { + localByContent = nil + } + out.append(try self.mergeNode(guid, localNode: localByContent, mirrorNode: mir, remoteNode: rem)) + } + } + + if let local = local, let children = local.children { + try children.forEach { loc in + let guid = loc.recordGUID + if seen.contains(guid) { + log.debug("Already saw local child \(guid).") + return + } + + if self.done.contains(guid) { + log.debug("Already saw local child \(guid) elsewhere.") + return + } + + if try checkForRemoteDeletionOfLocalNode(loc, mirrorNode: self.mirror.find(guid)) { + return + } + + let mir = self.mirror.find(guid) + let rem = self.remote.find(guid) + changed = true + out.append(try self.mergeNode(guid, localNode: loc, mirrorNode: mir, remoteNode: rem)) + } + } + + // Walk the mirror node's children. Any that are deleted on only one side might contribute + // orphans, so descend into those nodes' children on the other side. + if let expectedParent = mirror?.recordGUID, let mirrorChildren = mirror?.children { + try mirrorChildren.forEach { child in + let potentiallyDeleted = child.recordGUID + if seen.contains(potentiallyDeleted) || self.done.contains(potentiallyDeleted) { + return + } + + let locallyDeleted = self.local.deleted.contains(potentiallyDeleted) + let remotelyDeleted = self.remote.deleted.contains(potentiallyDeleted) + if !locallyDeleted && !remotelyDeleted { + log.debug("Mirror child \(potentiallyDeleted) no longer here, but not deleted on either side: must be elsewhere.") + return + } + + if locallyDeleted && remotelyDeleted { + log.debug("Mirror child \(potentiallyDeleted) was deleted both locally and remoted. We cool.") + self.merged.deleteFromMirror.insert(potentiallyDeleted) + self.merged.acceptLocalDeletion.insert(potentiallyDeleted) + self.merged.acceptRemoteDeletion.insert(potentiallyDeleted) + return + } + + if locallyDeleted { + // See if the remote side still thinks this is the parent. + let parent = self.remote.parents[potentiallyDeleted] + if parent == nil || parent == expectedParent { + log.debug("Remote still thinks \(potentiallyDeleted) is here. Processing for orphans.") + if let parentOfOrphans = self.remote.find(potentiallyDeleted), + let orphans = try processRemoteOrphansForNode(parentOfOrphans) { + out.append(contentsOf: try self.relocateOrphansTo(result, orphans: orphans)) + } + } + + // Accept the local deletion, and make a note to apply it elsewhere. + self.merged.deleteFromMirror.insert(potentiallyDeleted) + self.merged.deleteRemotely.insert(potentiallyDeleted) + self.merged.acceptLocalDeletion.insert(potentiallyDeleted) + return + } + + // Remotely deleted. + + let parent = self.local.parents[potentiallyDeleted] + if parent == nil || parent == expectedParent { + log.debug("Local still thinks \(potentiallyDeleted) is here. Processing for orphans.") + if let parentOfOrphans = self.local.find(potentiallyDeleted), + let orphans = try processLocalOrphansForNode(parentOfOrphans) { + out.append(contentsOf: try self.relocateOrphansTo(result, orphans: orphans)) + } + } + + // Accept the remote deletion, and make a note to apply it elsewhere. + self.merged.deleteFromMirror.insert(potentiallyDeleted) + self.merged.deleteLocally.insert(potentiallyDeleted) + self.merged.acceptRemoteDeletion.insert(potentiallyDeleted) + } + } + + log.debug("Setting \(result.guid)'s children to \(out.map { $0.guid }).") + result.mergedChildren = out + + // If the child list didn't change, then we don't need .new. + if changed { + let newStructure = out.map { $0.asMergedTreeNode() } + result.structureState = MergeState.new(value: BookmarkTreeNode.folder(guid: result.guid, children: newStructure)) + return + } + + log.debug("Child list didn't change for \(result.guid). Keeping structure state \(result.structureState).") + } + + fileprivate func resolveThreeWayValueConflict(_ guid: GUID) throws -> MergeState { + // TODO + return try self.resolveTwoWayValueConflict(guid, localGUID: guid) + } + + fileprivate func resolveTwoWayValueConflict(_ guid: GUID, localGUID: GUID) throws -> MergeState { + // We don't check for all roots, because we might have to + // copy them to the mirror or buffer, so we need to pick + // a direction. The Places root is never uploaded. + if BookmarkRoots.RootGUID == guid { + log.debug("Two-way value merge on the root: always unaltered.") + return MergeState.unchanged + } + + let localRecord = self.itemSources.local.getLocalItemWithGUID(localGUID).value.successValue + let remoteRecord = self.itemSources.buffer.getBufferItemWithGUID(guid).value.successValue + + if let local = localRecord { + if let remote = remoteRecord { + // Two-way. + // If they're the same, take the remote record. It saves us having to rewrite + // local values to keep a remote GUID. + if local.sameAs(remote) { + log.debug("Local record \(local.guid) same as remote \(remote.guid). Taking remote.") + return MergeState.remote + } + + log.debug("Comparing local (\(local.localModified ??? "0")) to remote (\(remote.serverModified)) clock for two-way value merge of \(guid).") + if let localModified = local.localModified, localModified > remote.serverModified { + // If we're taking the local record because it was modified, check to see + // whether the remote record has a creation date that we want to keep. + let dateAddedRemote = remote.dateAdded ?? remote.serverModified + if (local.dateAdded ?? UInt64.max) > dateAddedRemote { + return MergeState.new(value: local.copyWithDateAdded(dateAddedRemote)) + } + return MergeState.local + } + return MergeState.remote + } + + // No remote! + log.debug("Expected two-way merge for \(guid), but no remote item found.") + return MergeState.local + } + + if let _ = remoteRecord { + // No local! + log.debug("Expected two-way merge for \(guid), but no local item found.") + return MergeState.remote + } + + // Can't two-way merge with nothing! + log.error("Expected two-way merge for \(guid), but no local or remote item found!") + throw BookmarksMergeError() + } + + // This will never be called with two primary .unknown values. + fileprivate func threeWayMerge(_ guid: GUID, localNode: BookmarkTreeNode, remoteNode: BookmarkTreeNode, mirrorNode: BookmarkTreeNode?) throws -> MergedTreeNode { + if mirrorNode == nil { + log.debug("Two-way merge for \(guid).") + } else { + log.debug("Three-way merge for \(guid).") + } + + if remoteNode.isUnknown { + if localNode.isUnknown { + preconditionFailure("Two unknown nodes!") + } + + log.debug("Taking local node in two/three-way merge: remote bafflingly unchanged.") + // TODO: value-unchanged + return MergedTreeNode.forLocal(localNode) + } + + if localNode.isUnknown { + log.debug("Taking remote node in two/three-way merge: local bafflingly unchanged.") + // TODO: value-unchanged + return MergedTreeNode.forRemote(remoteNode) + } + + let result = MergedTreeNode(guid: guid, mirror: mirrorNode) + result.local = localNode + result.remote = remoteNode + + // Value merge. This applies regardless. + if localNode.isUnknown { + result.valueState = MergeState.remote + } else if remoteNode.isUnknown { + result.valueState = MergeState.local + } else { + if mirrorNode == nil { + result.valueState = try self.resolveTwoWayValueConflict(guid, localGUID: localNode.recordGUID) + } else { + result.valueState = try self.resolveThreeWayValueConflict(guid) + } + } + + switch localNode { + case let .folder(_, localChildren): + if case let .folder(_, remoteChildren) = remoteNode { + // Structural merge. + if localChildren.sameElements(remoteChildren) { + // Great! + log.debug("Local and remote records have same children in two-way merge.") + result.structureState = MergeState.new(value: localNode) // TODO: what if it's the same as the mirror? + try self.mergeChildListsIntoMergedNode(result, fromLocal: localNode, remote: remoteNode, mirror: mirrorNode) + return result + } + + // Merge the two folder lists. + // We know that each side is internally consistent: that is, each + // node in this list is present in the tree once only. But when we + // combine the two lists, we might be inadvertently duplicating a + // record that has already been, or will soon be, found in the other + // tree. We need to be careful to make sure that we don't feature + // a node in the tree more than once. + // Remember to check deletions. + log.debug("Local and remote records have different children. Merging.") + + // Assume it'll be the same as the remote one; mergeChildListsIntoMergedNode + // sets this to New if the structure changes. + result.structureState = MergeState.remote + try self.mergeChildListsIntoMergedNode(result, fromLocal: localNode, remote: remoteNode, mirror: mirrorNode) + return result + } + + case .nonFolder: + if case .nonFolder = remoteNode { + log.debug("Two non-folders with GUID \(guid) collide. Taking remote.") + return result + } + + default: + break + } + + // Otherwise, this must be a GUID collision between different types. + // TODO: Assign a new GUID to the local record + // but do not upload a deletion; these shouldn't merge. + log.debug("Remote and local records with same GUID \(guid) but different types. Consistency error.") + throw BookmarksMergeConsistencyError() + } + + fileprivate func twoWayMerge(_ guid: GUID, localNode: BookmarkTreeNode, remoteNode: BookmarkTreeNode) throws -> MergedTreeNode { + return try self.threeWayMerge(guid, localNode: localNode, remoteNode: remoteNode, mirrorNode: nil) + } + + fileprivate func unchangedIf(_ out: MergedTreeNode, original: BookmarkMirrorItem?, new: BookmarkMirrorItem?) -> MergedTreeNode { + guard let original = original, let new = new else { + return out + } + + if new.sameAs(original) { + out.valueState = MergeState.unchanged + } + return out + } + + fileprivate func takeLocalIfChanged(_ local: BookmarkTreeNode, mirror: BookmarkTreeNode?=nil) -> MergedTreeNode { + let guid = local.recordGUID + let localValues = self.itemSources.local.getLocalItemWithGUID(guid).value.successValue + let mirrorValues = self.itemSources.mirror.getMirrorItemWithGUID(guid).value.successValue + + // We don't expect these to ever fail to exist. + assert(localValues != nil) + + let merged = MergedTreeNode.forLocal(local, mirror: mirror) + return unchangedIf(merged, original: mirrorValues, new: localValues) + } + + fileprivate func takeRemoteIfChanged(_ remote: BookmarkTreeNode, mirror: BookmarkTreeNode?=nil) -> MergedTreeNode { + let guid = remote.recordGUID + let remoteValues = self.itemSources.buffer.getBufferItemWithGUID(guid).value.successValue + let mirrorValues = self.itemSources.mirror.getMirrorItemWithGUID(guid).value.successValue + + assert(remoteValues != nil) + + let merged = MergedTreeNode.forRemote(remote, mirror: mirror) + return unchangedIf(merged, original: mirrorValues, new: remoteValues) + } + + fileprivate var folderNameCache: [GUID: String?] = [:] + func getNameForFolder(_ folder: MergedTreeNode) throws -> String? { + if let name = self.folderNameCache[folder.guid] { + return name + } + let name = try self.fetchNameForFolder(folder) + self.folderNameCache[folder.guid] = name + return name + } + + func fetchNameForFolder(_ folder: MergedTreeNode) throws -> String? { + switch folder.valueState { + case let .new(v): + return v.title + case .unchanged: + if let mirror = folder.mirror?.recordGUID, + let title = self.itemSources.mirror.getMirrorItemWithGUID(mirror).value.successValue?.title { + return title + } + case .remote: + if let remote = folder.remote?.recordGUID, + let title = self.itemSources.buffer.getBufferItemWithGUID(remote).value.successValue?.title { + return title + } + case .local: + if let local = folder.local?.recordGUID, + let title = self.itemSources.local.getLocalItemWithGUID(local).value.successValue?.title { + return title + } + case .unknown: + break + } + + throw BookmarksMergeConsistencyError() + } + + func relocateOrphansTo(_ mergedNode: MergedTreeNode, orphans: [MergedTreeNode]?) throws -> [MergedTreeNode] { + guard let orphans = orphans else { + return [] + } + + let parentName = try self.getNameForFolder(mergedNode) + return try orphans.map { + try self.relocateMergedTreeNode($0, parentID: mergedNode.guid, parentName: parentName) + } + } + + func relocateMergedTreeNode(_ node: MergedTreeNode, parentID: GUID, parentName: String?) throws -> MergedTreeNode { + func copyWithMirrorItem(_ item: BookmarkMirrorItem?) throws -> MergedTreeNode { + guard let item = item else { + throw BookmarksMergeConsistencyError() + } + + if item.parentID == parentID && item.parentName == parentName { + log.debug("Don't need to relocate \(node.guid)'s for value table.") + return node + } + + log.debug("Relocating \(node.guid) to parent \(parentID).") + let n = MergedTreeNode(guid: node.guid, mirror: node.mirror) + n.local = node.local + n.remote = node.remote + n.mergedChildren = node.mergedChildren + n.structureState = node.structureState + n.valueState = .new(value: item.copyWithParentID(parentID, parentName: parentName)) + + return n + } + + switch node.valueState { + case .unknown: + return node + case .unchanged: + return try copyWithMirrorItem(self.itemSources.mirror.getMirrorItemWithGUID(node.guid).value.successValue) + case .local: + return try copyWithMirrorItem(self.itemSources.local.getLocalItemWithGUID(node.guid).value.successValue) + case .remote: + return try copyWithMirrorItem(self.itemSources.buffer.getBufferItemWithGUID(node.guid).value.successValue) + case let .new(value): + return try copyWithMirrorItem(value) + } + } + + // A helper that'll rewrite the resulting node's value to have the right parent. + func mergeNode(_ guid: GUID, intoFolder parentID: GUID, withParentName parentName: String?, localNode: BookmarkTreeNode?, mirrorNode: BookmarkTreeNode?, remoteNode: BookmarkTreeNode?) throws -> MergedTreeNode { + let m = try self.mergeNode(guid, localNode: localNode, mirrorNode: mirrorNode, remoteNode: remoteNode) + + // We could check the parent pointers in the tree, but looking at the values themselves + // will catch any mismatches between the value and structure tables. + return try self.relocateMergedTreeNode(m, parentID: parentID, parentName: parentName) + } + + // We'll end up looking at deletions and such as we go. + // TODO: accumulate deletions into the three buckets as we go. + // + // TODO: if a local or remote node is kept but put in a different folder, we actually + // need to generate a .new node, so we can take the parentid and parentNode that we + // must preserve. + func mergeNode(_ guid: GUID, localNode: BookmarkTreeNode?, mirrorNode: BookmarkTreeNode?, remoteNode: BookmarkTreeNode?) throws -> MergedTreeNode { + if let localGUID = localNode?.recordGUID { + log.verbose("Merging nodes with GUID \(guid). Local match is \(localGUID).") + } else { + log.verbose("Merging nodes with GUID \(guid). No local match.") + } + + // TODO: if the local node has a different GUID, it's because we did a value-based + // merge. Make sure the local row with the differing local GUID doesn't + // stick around. + + // We'll never get here with no nodes at all… right? + precondition((localNode != nil) || (mirrorNode != nil) || (remoteNode != nil)) + + // Note that not all of the input nodes must share a GUID: we might have decided, based on + // value comparison in an earlier recursive call, that a local node will be replaced by a + // remote node, and we'll need to mark the local GUID as a deletion, using its values and + // structure during our reconciling. + // But we will never have the mirror and remote differ. + precondition(nullOrMatch(remoteNode?.recordGUID, mirrorNode?.recordGUID)) + precondition(nullOrMatch(remoteNode?.recordGUID, guid)) + precondition(nullOrMatch(mirrorNode?.recordGUID, guid)) + + // Immediately mark this GUID -- and the local GUID, if it differs -- as done. + // This avoids repeated code in each conditional branch, and avoids the possibility of + // certain moves causing us to hit the same node again. + self.done.insert(guid) + if let otherGUID = localNode?.recordGUID, otherGUID != guid { + log.debug("Marking superseded local record \(otherGUID) as merged.") + self.done.insert(otherGUID) + self.duped.insert(otherGUID) + } + + func takeRemoteAndMergeChildren(_ remote: BookmarkTreeNode, mirror: BookmarkTreeNode?=nil) throws -> MergedTreeNode { + let merged = self.takeRemoteIfChanged(remote, mirror: mirror) + if case .folder = remote { + log.debug("… and it's a folder. Taking remote children.") + try self.oneWayMergeChildListsIntoMergedNode(merged, fromRemote: remote) + } + return merged + } + + func takeLocalAndMergeChildren(_ local: BookmarkTreeNode, mirror: BookmarkTreeNode?=nil) throws -> MergedTreeNode { + let merged = self.takeLocalIfChanged(local, mirror: mirror) + if case .folder = local { + log.debug("… and it's a folder. Taking local children.") + try self.oneWayMergeChildListsIntoMergedNode(merged, fromLocal: local) + } + return merged + } + + func takeMirrorNode(_ mirror: BookmarkTreeNode) throws -> MergedTreeNode { + let merged = MergedTreeNode.forUnchanged(mirror) + if case .folder = mirror { + try self.takeMirrorChildrenInMergedNode(merged) + } + return merged + } + + // If we ended up here with two unknowns, just proceed down the mirror. + // We know we have a mirror, else we'd have a non-unknown edge. + if (localNode?.isUnknown ?? true) && (remoteNode?.isUnknown ?? true) { + precondition(mirrorNode != nil) + log.verbose("Record \(guid) didn't change from mirror.") + + self.done.insert(guid) + return try takeMirrorNode(mirrorNode!) + } + + guard let mirrorNode = mirrorNode else { + // No mirror node: at most a two-way merge. + if let loc = localNode, !loc.isUnknown { + if let rem = remoteNode { + // Two-way merge; probably a disconnect-reconnect scenario. + return try self.twoWayMerge(guid, localNode: loc, remoteNode: rem) + } + + // No remote. Node only exists locally. + // However! The children might be mentioned in the mirror or + // remote tree. + log.verbose("Node \(guid) only exists locally.") + return try takeLocalAndMergeChildren(loc) + } + + // No local. + + guard let rem = remoteNode, !rem.isUnknown else { + // No remote! + // This should not occur: we have preconditions above. + preconditionFailure("Unexpectedly got past our preconditions!") + } + + // Node only exists remotely. Take it. + log.verbose("Node \(guid) only exists remotely.") + return try takeRemoteAndMergeChildren(rem) + } + + // We have a mirror node. + if let loc = localNode, !loc.isUnknown { + if let rem = remoteNode, !rem.isUnknown { + log.debug("Both local and remote changes to mirror item \(guid). Resolving conflict.") + return try self.threeWayMerge(guid, localNode: loc, remoteNode: rem, mirrorNode: mirrorNode) + } + log.verbose("Local-only change to mirror item \(guid).") + return try takeLocalAndMergeChildren(loc, mirror: mirrorNode) + } + + if let rem = remoteNode, !rem.isUnknown { + log.verbose("Remote-only change to mirror item \(guid).") + return try takeRemoteAndMergeChildren(rem, mirror: mirrorNode) + } + + log.verbose("Record \(guid) didn't change from mirror.") + return try takeMirrorNode(mirrorNode) + } + + func merge() -> Deferred> { + return self.produceMergedTree() + >>== self.produceMergeResultFromMergedTree + } + + func produceMergedTree() -> Deferred> { + // Don't ever do this work twice. + if self.mergeAttempted { + return deferMaybe(self.merged) + } + + // Both local and remote should reach a single root when overlayed. If not, it means that + // the tree is inconsistent -- there isn't a full tree present either on the server (or + // local) or in the mirror, or the changes aren't congruent in some way. If we reach this + // state, we cannot proceed. + // + // This is assert()ed in the initializer, too, so that we crash hard and early in developer + // builds and tests. + + if !self.local.isFullyRootedIn(self.mirror) { + log.warning("Local bookmarks not fully rooted when overlayed on mirror. This is most unusual.") + return deferMaybe(BookmarksMergeErrorTreeIsUnrooted(roots: self.local.subtreeGUIDs)) + } + + if !self.remote.isFullyRootedIn(mirror) { + log.warning("Remote bookmarks not fully rooted when overlayed on mirror. Partial read or write in buffer?") + + // This might be a temporary state: another client might not have uploaded all of its + // records yet. Another batch might arrive in a second, or it might arrive a month + // later if the user just closed the lid of their laptop and went on vacation! + // + // This can also be a semi-stable state; e.g., Bug 1235269. It's theoretically + // possible for us to try to recover by requesting reupload from other devices + // by changing syncID, or through some new command. + // + // Regardless, we can't proceed until this situation changes. + return deferMaybe(BookmarksMergeErrorTreeIsUnrooted(roots: self.remote.subtreeGUIDs)) + } + + log.debug("Processing \(self.localAllGUIDs.count) local changes and \(self.remoteAllGUIDs.count) remote changes.") + log.debug("\(self.local.subtrees.count) local subtrees and \(self.remote.subtrees.count) remote subtrees.") + log.debug("Local is adding \(self.localAdditions.count) records, and remote is adding \(self.remoteAdditions.count).") + log.debug("Local and remote have \(self.allDeletions.count) deletions.") + + if !conflictingGUIDs.isEmpty { + log.warning("Expecting conflicts between local and remote: \(self.conflictingGUIDs.joined(separator: ", ")).") + } + + // Pre-fetch items so we don't need to do async work later. + return self.prefetchItems() >>> self.walkProducingMergedTree + } + + fileprivate func prefetchItems() -> Success { + return self.itemSources.prefetchWithGUIDs(self.allChangedGUIDs) + } + + // This should only be called once. + // Callers should ensure validity of inputs. + fileprivate func walkProducingMergedTree() -> Deferred> { + let root = self.merged.root + assert((root.mirror?.children?.count ?? 0) == BookmarkRoots.RootChildren.count) + + // Get to walkin'. + root.structureState = MergeState.unchanged // We never change the root. + root.valueState = MergeState.unchanged + root.local = self.local.find(BookmarkRoots.RootGUID) + + do { + try root.mergedChildren = root.mirror!.children!.map { + let guid = $0.recordGUID + let loc = self.local.find(guid) + let mir = self.mirror.find(guid) + let rem = self.remote.find(guid) + return try self.mergeNode(guid, localNode: loc, mirrorNode: mir, remoteNode: rem) + } + } catch let error as MaybeErrorType { + return deferMaybe(error) + } catch let error { + return deferMaybe(BookmarksMergeError(error: error)) + } + + // If the buffer contains deletions for records that aren't in the mirror or in local, + // then we'll never normally encounter them, and thus we'll never accept the deletion. + // Check for that here. + let additionalRemoteDeletions = self.remote.deleted.subtracting(self.done) + log.debug("Additional remote deletions: \(additionalRemoteDeletions.count).") + self.merged.acceptRemoteDeletion.formUnion(additionalRemoteDeletions) + + self.mergeAttempted = true + + // Validate. Note that we might end up with *more* records than this -- records + // that didn't change naturally aren't present in the change list on either side. + let expected = self.allChangedGUIDs.subtracting(self.allDeletions).subtracting(self.duped) + assert(self.merged.allGUIDs.isSuperset(of: expected)) + assert(self.merged.allGUIDs.intersection(self.allDeletions).isEmpty) + + return deferMaybe(self.merged) + } + + /** + * Input to this function will be a merged tree: a collection of known deletions, + * and a tree of nodes that reflect an action and pointers to the edges and the + * mirror, something like this: + * + * ------------------------------------------------------------------------------- + * Deleted locally: folderBBBBBB + * Deleted remotely: folderDDDDDD + * Deleted from mirror: folderBBBBBB, folderDDDDDD + * Accepted local deletions: folderDDDDDD + * Accepted remote deletions: folderBBBBBB + * Root: + * [V: □ M □ root________ Unchanged ] + * [S: Unchanged ] + * .. + * [V: □ M □ menu________ Unchanged ] + * [S: Unchanged ] + * .. + * [V: □ M L folderCCCCCC Unchanged ] + * [S: New ] + * .. + * [V: R □ □ bookmarkFFFF Remote ] + * [V: □ M □ toolbar_____ Unchanged ] + * [S: Unchanged ] + * .. + * [V: R M □ folderAAAAAA Unchanged ] + * [S: New ] + * .. + * [V: □ □ L r_FpO9_RAXp3 Local ] + * [V: □ M □ unfiled_____ Unchanged ] + * [S: Unchanged ] + * .. + * [V: □ M □ mobile______ Unchanged ] + * [S: Unchanged ] + * .. + * ------------------------------------------------------------------------------- + * + * We walk this tree from the root, breadth-first in order to process folders before + * their children. We look at the valueState and structureState (for folders) to decide + * whether to spit out actions into the completion ops. + * + * Changes recorded in the completion ops are along the lines of "copy the record with + * this GUID from local into the mirror", "upload this record from local", "delete this + * record". Dependencies are encoded by the sequence of completion ops: for example, we + * don't want to drop local changes and update the mirror until the server reflects our + * local state, and we achieve that by only running the local completion op if the + * upload succeeds. + * + * There's a lot of boilerplate in this function. That's partly because the lines of + * switch statements are easier to read through and match up to expected behavior, but + * also because it's simpler than threading all of the edge cases around. + */ + func produceMergeResultFromMergedTree(_ mergedTree: MergedTree) -> Deferred> { + let upstreamOp = UpstreamCompletionOp() + let bufferOp = BufferCompletionOp() + let localOp = LocalOverrideCompletionOp() + + func accumulateNonRootFolder(_ node: MergedTreeNode) { + assert(node.isFolder) + + guard let children = node.mergedChildren else { + preconditionFailure("Shouldn't have a non-Unknown folder without known children.") + } + + let childGUIDs = children.map { $0.guid } + + // Recurse first — because why not? + // We don't expect deep enough bookmark trees that we'll overflow the stack, so + // we don't bother making a queue. + children.forEach(accumulateNode) + + // Verify that computed child lists match the right source node. + switch node.structureState { + case .remote: + assert(node.remote?.children?.map { $0.recordGUID } ?? [] == childGUIDs) + case .local: + assert(node.local?.children?.map { $0.recordGUID } ?? [] == childGUIDs) + case let .new(treeNode): + assert(treeNode.children?.map { $0.recordGUID } ?? [] == childGUIDs) + default: + break + } + + switch node.valueState { + case .unknown: + return // Never occurs: guarded by precondition. + case .unchanged: + // We can't have Unchanged value without a mirror node… + assert(node.hasMirror) + + switch node.structureState { + case .unknown: + return // Never occurs: guarded by precondition. + case .unchanged: + // Nothing changed! + return + case .remote: + // Nothing special to do: no need to amend server. + break + case .local: + upstreamOp.amendChildrenFromMirror[node.guid] = childGUIDs + case .new: + // No change in value, but a new structure. + // Construct a new upstream record from the old mirror value, + // and update the mirror structure. + upstreamOp.amendChildrenFromMirror[node.guid] = childGUIDs + } + + // We always need to do this for Remote, Local, New. + localOp.mirrorStructures[node.guid] = childGUIDs + + case .local: + localOp.mirrorValuesToCopyFromLocal.insert(node.guid) + + // Generate a new upstream record. + upstreamOp.amendChildrenFromLocal[node.guid] = childGUIDs + + // Update the structure in the mirror if necessary. + if case .unchanged = node.structureState { + return + } + localOp.mirrorStructures[node.guid] = childGUIDs + + case .remote: + localOp.mirrorValuesToCopyFromBuffer.insert(node.guid) + + // Update the structure in the mirror if necessary. + switch node.structureState { + case .unchanged: + return + case .remote: + localOp.mirrorStructures[node.guid] = childGUIDs + default: + // We need to upload a new record. + upstreamOp.amendChildrenFromBuffer[node.guid] = childGUIDs + localOp.mirrorStructures[node.guid] = childGUIDs + } + + case let .new(value): + // We can only do this if we stuffed the BookmarkMirrorItem with the right children. + // Verify that with a precondition. + precondition(value.children ?? [] == childGUIDs) + + localOp.mirrorStructures[node.guid] = childGUIDs + if node.hasMirror { + localOp.mirrorItemsToUpdate[node.guid] = value + } else { + localOp.mirrorItemsToInsert[node.guid] = value + } + let record = Record(id: node.guid, payload: value.asPayload()) + upstreamOp.records.append(record) + } + } + + func accumulateRoot(_ node: MergedTreeNode) { + log.debug("Accumulating \(node.guid).") + assert(node.isFolder) + assert(BookmarkRoots.Real.contains(node.guid)) + + guard let children = node.mergedChildren else { + preconditionFailure("Shouldn't have a non-Unknown folder without known children.") + } + + // Recurse first — because why not? + children.forEach(accumulateNode) + + let mirrorVersionIsVirtual = self.mirror.virtual.contains(node.guid) + + // Note that a root can be Unchanged, but be missing from the mirror. That's OK: roots + // don't really have values. Take whichever we find. + if node.mirror == nil || mirrorVersionIsVirtual { + if node.hasLocal { + localOp.mirrorValuesToCopyFromLocal.insert(node.guid) + } else if node.hasRemote { + localOp.mirrorValuesToCopyFromBuffer.insert(node.guid) + } else { + log.warning("No values to copy into mirror for \(node.guid). Need to synthesize root. Empty merge?") + } + } + + log.debug("Need to accumulate a root.") + if case .unchanged = node.structureState { + if !mirrorVersionIsVirtual { + log.debug("Root \(node.guid) is unchanged and already in the mirror.") + return + } + } + + let childGUIDs = children.map { $0.guid } + localOp.mirrorStructures[node.guid] = childGUIDs + + switch node.structureState { + case .remote: + log.debug("Root \(node.guid) taking remote structure.") + return + case .local: + log.debug("Root \(node.guid) taking local structure.") + upstreamOp.amendChildrenFromLocal[node.guid] = childGUIDs + case .new: + log.debug("Root \(node.guid) taking new structure.") + if node.hasMirror && !mirrorVersionIsVirtual { + log.debug("… uploading with mirror value.") + upstreamOp.amendChildrenFromMirror[node.guid] = childGUIDs + } else if node.hasLocal { + log.debug("… uploading with local value.") + upstreamOp.amendChildrenFromLocal[node.guid] = childGUIDs + } else if node.hasRemote { + log.debug("… uploading with remote value.") + upstreamOp.amendChildrenFromBuffer[node.guid] = childGUIDs + } else { + log.warning("No values to copy to remote for \(node.guid). Need to synthesize root. Empty merge?") + } + default: + // Filler. + return + } + } + + func accumulateNode(_ node: MergedTreeNode) { + precondition(!node.valueState.isUnknown) + precondition(!node.isFolder || !node.structureState.isUnknown) + + // These two clauses are common to all: if we walk through a node, + // it means it's been processed, and no longer needs to be kept + // on the edges. + if node.hasLocal { + let localGUID = node.local!.recordGUID + log.debug("Marking \(localGUID) to drop from local.") + localOp.processedLocalChanges.insert(localGUID) + } + + if node.hasRemote { + log.debug("Marking \(node.guid) to drop from buffer.") + bufferOp.processedBufferChanges.insert(node.guid) + } + + if node.isFolder { + if BookmarkRoots.Real.contains(node.guid) { + accumulateRoot(node) + return + } + + // We have to consider structure, and we have to recurse. + accumulateNonRootFolder(node) + return + } + + // Value didn't change, and no structure to handle. Done. + if node.valueState.isUnchanged { + precondition(node.hasMirror, "Can't have an unchanged non-root without there being a mirror record.") + } + + // Not new. Emit copy directives. + + switch node.valueState { + case .remote: + localOp.mirrorValuesToCopyFromBuffer.insert(node.guid) + + case .local: + let localGUID = node.local!.recordGUID + + // If we're taking the local value, we expect to keep the local GUID. + // TODO: this restriction isn't strictly required, but we know that our + // content-based merges will only ever take the remote value. + precondition(localGUID == node.guid, "Can't take local value without keeping local GUID.") + + guard let value = self.itemSources.local.getLocalItemWithGUID(localGUID).value.successValue else { + assertionFailure("Couldn't fetch local value for new item \(localGUID). This should never happen.") + return + } + + let record = Record(id: localGUID, payload: value.asPayload()) + upstreamOp.records.append(record) + + localOp.mirrorValuesToCopyFromLocal.insert(localGUID) + + // New. Emit explicit insertions into all three places, + // and eliminate any existing records for this GUID. + // Note that we don't check structure: this isn't a folder. + case let .new(value): + // + // TODO: ensure that `value` has the right parent GUID!!! + // Reparenting means that the moved node has _new_ values + // pointing to the _new_ parent. + // + // It also must have the correct child list. That isn't a + // problem in this value-only branch. + // + + // Upstream. + let record = Record(id: node.guid, payload: value.asPayload()) + upstreamOp.records.append(record) + + // Mirror. No structure needed. + if node.hasMirror { + localOp.mirrorItemsToUpdate[node.guid] = value + } else { + localOp.mirrorItemsToInsert[node.guid] = value + } + + default: + return // Deliberately incomplete switch. + } + } + + // Upload deleted records for anything we need to delete. + // Each one also ends up being dropped from the buffer. + if !mergedTree.deleteRemotely.isEmpty { + upstreamOp.records.append(contentsOf: mergedTree.deleteRemotely.map { + Record(id: $0, payload: BookmarkBasePayload.deletedPayload($0)) + }) + bufferOp.processedBufferChanges.formUnion(mergedTree.deleteRemotely) + } + + // Drop deleted items from the mirror. + localOp.mirrorItemsToDelete.formUnion(mergedTree.deleteFromMirror) + + // Anything we deleted on either end and accepted, add to the processed lists to be + // automatically dropped. + localOp.processedLocalChanges.formUnion(mergedTree.acceptLocalDeletion) + bufferOp.processedBufferChanges.formUnion(mergedTree.acceptRemoteDeletion) + + // We draw a terminological distinction between accepting a local deletion (which + // drops it from the local table) and deleting an item that's locally modified + // (which drops it from the local table, and perhaps also from the mirror). + // Either way, we put it in the list to drop. + // The former is `localOp.processedLocalChanges`, accumulated as we walk local. + // The latter is `mergedTree.deleteLocally`, accumulated as we process incoming deletions. + localOp.processedLocalChanges.formUnion(mergedTree.deleteLocally) + + // Now walk the final tree to get the substantive changes. + accumulateNode(mergedTree.root) + + // Postconditions. + // None of the work items appear in more than one place. + assert(Set(upstreamOp.amendChildrenFromBuffer.keys).isDisjoint(with: Set(upstreamOp.amendChildrenFromLocal.keys))) + assert(Set(upstreamOp.amendChildrenFromBuffer.keys).isDisjoint(with: Set(upstreamOp.amendChildrenFromMirror.keys))) + assert(Set(upstreamOp.amendChildrenFromLocal.keys).isDisjoint(with: Set(upstreamOp.amendChildrenFromMirror.keys))) + assert(localOp.mirrorItemsToDelete.isDisjoint(with: Set(localOp.mirrorItemsToInsert.keys))) + assert(localOp.mirrorItemsToDelete.isDisjoint(with: Set(localOp.mirrorItemsToUpdate.keys))) + assert(Set(localOp.mirrorItemsToInsert.keys).isDisjoint(with: Set(localOp.mirrorItemsToUpdate.keys))) + assert(localOp.mirrorValuesToCopyFromBuffer.isDisjoint(with: Set(localOp.mirrorValuesToCopyFromLocal))) + + // Pass through the item sources so we're able to apply the parts of the result that + // are in reference to storage. + let result = BookmarksMergeResult(uploadCompletion: upstreamOp, overrideCompletion: localOp, bufferCompletion: bufferOp, itemSources: self.itemSources) + return deferMaybe(result) + } +} diff --git a/mobile/ios/Sync/Synchronizers/ClientsSynchronizer.swift b/mobile/ios/Sync/Synchronizers/ClientsSynchronizer.swift new file mode 100644 index 0000000000..9a3e4d823a --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/ClientsSynchronizer.swift @@ -0,0 +1,432 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import Deferred +import SwiftyJSON + +private let log = Logger.syncLogger +let ClientsStorageVersion = 1 + +// TODO +public protocol Command { + static func fromName(_ command: String, args: [JSON]) -> Command? + func run(_ synchronizer: ClientsSynchronizer) -> Success + static func commandFromSyncCommand(_ syncCommand: SyncCommand) -> Command? +} + +// Shit. +// We need a way to wipe or reset engines. +// We need a way to log out the account. +// So when we sync commands, we're gonna need a delegate of some kind. +open class WipeCommand: Command { + + public init?(command: String, args: [JSON]) { + return nil + } + + open class func fromName(_ command: String, args: [JSON]) -> Command? { + return WipeCommand(command: command, args: args) + } + + open func run(_ synchronizer: ClientsSynchronizer) -> Success { + return succeed() + } + + open static func commandFromSyncCommand(_ syncCommand: SyncCommand) -> Command? { + let json = JSON(parseJSON: syncCommand.value) + if let name = json["command"].string, + let args = json["args"].array { + return WipeCommand.fromName(name, args: args) + } + return nil + } +} + +open class DisplayURICommand: Command { + let uri: URL + let title: String + let sender: String + + public init?(command: String, args: [JSON]) { + if let uri = args[0].string?.asURL, + let sender = args[1].string, + let title = args[2].string { + self.uri = uri + self.sender = sender + self.title = title + } else { + // Oh, Swift. + self.uri = "http://localhost/".asURL! + self.title = "" + return nil + } + } + + open class func fromName(_ command: String, args: [JSON]) -> Command? { + return DisplayURICommand(command: command, args: args) + } + + open func run(_ synchronizer: ClientsSynchronizer) -> Success { + func display(_ deviceName: String? = nil) -> Success { + synchronizer.delegate.displaySentTab(for: uri, title: title, from: deviceName) + return succeed() + } + + guard let getClientWithId = synchronizer.localClients?.getClientWithId(sender) else { + return display() + } + + return getClientWithId >>== { client in + return display(client?.name) + } + } + + open static func commandFromSyncCommand(_ syncCommand: SyncCommand) -> Command? { + let json = JSON(parseJSON: syncCommand.value) + if let name = json["command"].string, + let args = json["args"].array { + return DisplayURICommand.fromName(name, args: args) + } + return nil + } +} + +open class RepairResponseCommand: Command { + let repairResponse: RepairResponse + + public init(command: String, args: [JSON]) { + self.repairResponse = RepairResponse.fromJSON(args: args[0]) + } + + open class func fromName(_ command: String, args: [JSON]) -> Command? { + return RepairResponseCommand(command: command, args: args) + } + + open func run(_ synchronizer: ClientsSynchronizer) -> Success { + let repairer = BookmarksRepairRequestor(scratchpad: synchronizer.scratchpad, basePrefs: synchronizer.basePrefs, remoteClients: synchronizer.localClients!) + return repairer.continueRepairs(response: self.repairResponse) >>> succeed + } + + open static func commandFromSyncCommand(_ syncCommand: SyncCommand) -> Command? { + let json = JSON(parseJSON: syncCommand.value) + if let name = json["command"].string, + let args = json["args"].array { + return RepairResponseCommand.fromName(name, args: args) + } + return nil + } +} + +let Commands: [String: (String, [JSON]) -> Command?] = [ + "wipeAll": WipeCommand.fromName, + "wipeEngine": WipeCommand.fromName, + // resetEngine + // resetAll + // logout + "displayURI": DisplayURICommand.fromName, + "repairResponse": RepairResponseCommand.fromName +] + +open class ClientsSynchronizer: TimestampedSingleCollectionSynchronizer, Synchronizer { + public required init(scratchpad: Scratchpad, delegate: SyncDelegate, basePrefs: Prefs, why: SyncReason) { + super.init(scratchpad: scratchpad, delegate: delegate, basePrefs: basePrefs, why: why, collection: "clients") + } + + var localClients: RemoteClientsAndTabs? + + override var storageVersion: Int { + return ClientsStorageVersion + } + + var clientRecordLastUpload: Timestamp { + set(value) { + self.prefs.setLong(value, forKey: "lastClientUpload") + } + + get { + return self.prefs.unsignedLongForKey("lastClientUpload") ?? 0 + } + } + + // Sync Object Format (Version 1) for Form Factors: http://docs.services.mozilla.com/sync/objectformats.html#id2 + fileprivate enum SyncFormFactorFormat: String { + case phone = "phone" + case tablet = "tablet" + } + + open func getOurClientRecord() -> Record { + let guid = self.scratchpad.clientGUID + let formfactor = formFactorString() + + let json = JSON(object: [ + "id": guid, + "fxaDeviceId": self.scratchpad.fxaDeviceId, + "version": AppInfo.appVersion, + "protocols": ["1.5"], + "name": self.scratchpad.clientName, + "os": "iOS", + "commands": [JSON](), + "type": "mobile", + "appPackage": AppInfo.baseBundleIdentifier, + "application": AppInfo.displayName, + "device": DeviceInfo.deviceModel(), + "formfactor": formfactor]) + + let payload = ClientPayload(json) + return Record(id: guid, payload: payload, ttl: ThreeWeeksInSeconds) + } + + fileprivate func formFactorString() -> String { + let userInterfaceIdiom = UIDevice.current.userInterfaceIdiom + var formfactor: String + + switch userInterfaceIdiom { + case .phone: + formfactor = SyncFormFactorFormat.phone.rawValue + case .pad: + formfactor = SyncFormFactorFormat.tablet.rawValue + default: + formfactor = SyncFormFactorFormat.phone.rawValue + } + + return formfactor + } + + fileprivate func clientRecordToLocalClientEntry(_ record: Record) -> RemoteClient { + let modified = record.modified + let payload = record.payload + return RemoteClient(json: payload.json, modified: modified) + } + + // If this is a fresh start, do a wipe. + // N.B., we don't wipe outgoing commands! (TODO: check this when we implement commands!) + // N.B., but perhaps we should discard outgoing wipe/reset commands! + fileprivate func wipeIfNecessary(_ localClients: RemoteClientsAndTabs) -> Success { + if self.lastFetched == 0 { + return localClients.wipeClients() + } + return succeed() + } + + /** + * Returns whether any commands were found (and thus a replacement record + * needs to be uploaded). Also returns the commands: we run them after we + * upload a replacement record. + */ + fileprivate func processCommandsFromRecord(_ record: Record?, withServer storageClient: Sync15CollectionClient) -> Deferred> { + log.debug("Processing commands from downloaded record.") + + // TODO: short-circuit based on the modified time of the record we uploaded, so we don't need to skip ahead. + if let record = record { + let commands = record.payload.commands + if !commands.isEmpty { + func parse(_ json: JSON) -> Command? { + if let name = json["command"].string, + let args = json["args"].array, + let constructor = Commands[name] { + return constructor(name, args) + } + return nil + } + + // TODO: can we do anything better if a command fails? + return deferMaybe((true, optFilter(commands.map(parse)))) + } + } + + return deferMaybe((false, [])) + } + + fileprivate func uploadClientCommands(toLocalClients localClients: RemoteClientsAndTabs, withServer storageClient: Sync15CollectionClient) -> Success { + return localClients.getCommands() >>== { clientCommands in + return clientCommands.map { (clientGUID, commands) -> Success in + self.syncClientCommands(clientGUID, commands: commands, clientsAndTabs: localClients, withServer: storageClient) + }.allSucceed() + } + } + + fileprivate func syncClientCommands(_ clientGUID: GUID, commands: [SyncCommand], clientsAndTabs: RemoteClientsAndTabs, withServer storageClient: Sync15CollectionClient) -> Success { + + let deleteCommands: () -> Success = { + return clientsAndTabs.deleteCommands(clientGUID).bind({ x in return succeed() }) + } + + log.debug("Fetching current client record for client \(clientGUID).") + let fetch = storageClient.get(clientGUID) + return fetch.bind() { result in + if let response = result.successValue, response.value.payload.isValid() { + let record = response.value + if var clientRecord = record.payload.json.dictionary { + clientRecord["commands"] = JSON(record.payload.commands + commands.map { JSON(parseJSON: $0.value) }) + let uploadRecord = Record(id: clientGUID, payload: ClientPayload(JSON(clientRecord)), ttl: ThreeWeeksInSeconds) + return storageClient.put(uploadRecord, ifUnmodifiedSince: record.modified) + >>== { resp in + log.debug("Client \(clientGUID) commands upload succeeded.") + + // Always succeed, even if we couldn't delete the commands. + return deleteCommands() + } + } + } else { + if let failure = result.failureValue { + log.warning("Failed to fetch record with GUID \(clientGUID).") + if failure is NotFound { + log.debug("Not waiting to see if the client comes back.") + + // TODO: keep these around and retry, expiring after a while. + // For now we just throw them away so we don't fail every time. + return deleteCommands() + } + + if failure is BadRequestError { + log.debug("We made a bad request. Throwing away queued commands.") + return deleteCommands() + } + } + } + + log.error("Client \(clientGUID) commands upload failed: No remote client for GUID") + return deferMaybe(UnknownError()) + } + } + + /** + * Upload our record if either (a) we know we should upload, or (b) + * our own notes tell us we're due to reupload. + */ + fileprivate func maybeUploadOurRecord(_ should: Bool, ifUnmodifiedSince: Timestamp?, toServer storageClient: Sync15CollectionClient) -> Success { + + let lastUpload = self.clientRecordLastUpload + let expired = lastUpload < (Date.now() - (2 * OneDayInMilliseconds)) + log.debug("Should we upload our client record? Caller = \(should), expired = \(expired).") + if !should && !expired { + return succeed() + } + + let iUS: Timestamp? = ifUnmodifiedSince ?? ((lastUpload == 0) ? nil : lastUpload) + + var uploadStats = SyncUploadStats() + return storageClient.put(getOurClientRecord(), ifUnmodifiedSince: iUS) + >>== { resp in + if let ts = resp.metadata.lastModifiedMilliseconds { + // Protocol says this should always be present for success responses. + log.debug("Client record upload succeeded. New timestamp: \(ts).") + self.clientRecordLastUpload = ts + uploadStats.sent += 1 + } else { + uploadStats.sentFailed += 1 + } + self.statsSession.recordUpload(stats: uploadStats) + return succeed() + } + } + + fileprivate func applyStorageResponse(_ response: StorageResponse<[Record]>, toLocalClients localClients: RemoteClientsAndTabs, withServer storageClient: Sync15CollectionClient, notifier: CollectionChangedNotifier?) -> Success { + log.debug("Applying clients response.") + + var downloadStats = SyncDownloadStats() + + let records = response.value + let responseTimestamp = response.metadata.lastModifiedMilliseconds + + log.debug("Got \(records.count) client records.") + + let ourGUID = self.scratchpad.clientGUID + var toInsert = [RemoteClient]() + var ours: Record? = nil + + for (rec) in records { + guard rec.payload.isValid() else { + log.warning("Client record \(rec.id) is invalid. Skipping.") + continue + } + + if rec.id == ourGUID { + if rec.modified == self.clientRecordLastUpload { + log.debug("Skipping our own unmodified record.") + } else { + log.debug("Saw our own record in response.") + ours = rec + } + } else { + toInsert.append(self.clientRecordToLocalClientEntry(rec)) + } + } + + downloadStats.applied += toInsert.count + + // Apply remote changes. + // Collect commands from our own record and reupload if necessary. + // Then run the commands and return. + return localClients.insertOrUpdateClients(toInsert) + >>== { succeeded in + downloadStats.succeeded += succeeded + downloadStats.failed += (toInsert.count - succeeded) + self.statsSession.recordDownload(stats: downloadStats) + return succeed() + } + >>== { self.processCommandsFromRecord(ours, withServer: storageClient) } + >>== { (shouldUpload, commands) in + let isFirstSync = self.lastFetched == 0 + return self.maybeUploadOurRecord(shouldUpload || self.why == .didLogin, ifUnmodifiedSince: ours?.modified, toServer: storageClient) + >>> { self.uploadClientCommands(toLocalClients: localClients, withServer: storageClient) } + >>> { + log.debug("Running \(commands.count) commands.") + for command in commands { + _ = command.run(self) + } + self.lastFetched = responseTimestamp! + if isFirstSync, + let notifier = notifier { + DispatchQueue.global(qos: DispatchQoS.background.qosClass).async { _ = notifier.notifyAll(collectionsChanged: ["clients"], reason: "firstsync") } + } + return succeed() + } + } + } + + open func synchronizeLocalClients(_ localClients: RemoteClientsAndTabs, withServer storageClient: Sync15StorageClient, info: InfoCollections, notifier: CollectionChangedNotifier?) -> SyncResult { + log.debug("Synchronizing clients.") + self.localClients = localClients // Store for later when we process a repairResponse command + + if let reason = self.reasonToNotSync(storageClient) { + switch reason { + case .engineRemotelyNotEnabled: + // This is a hard error for us. + return deferMaybe(FatalError(message: "clients not mentioned in meta/global. Server wiped?")) + default: + return deferMaybe(SyncStatus.notStarted(reason)) + } + } + + let keys = self.scratchpad.keys?.value + let encoder = RecordEncoder(decode: { ClientPayload($0) }, encode: { $0.json }) + let encrypter = keys?.encrypter(self.collection, encoder: encoder) + if encrypter == nil { + log.error("Couldn't make clients encrypter.") + return deferMaybe(FatalError(message: "Couldn't make clients encrypter.")) + } + + let clientsClient = storageClient.clientForCollection(self.collection, encrypter: encrypter!) + + // TODO: some of the commands we process might involve wiping collections or the + // entire profile. We should model this as an explicit status, and return it here + // instead of .completed. + statsSession.start() + // XXX: This is terrible. We always force a re-sync of the clients to work around + // the fact that `fxaDeviceId` may not have been populated if the list of clients + // hadn't changed since before the update to v8.0. To force a re-sync, we get all + // clients since the beginning of time instead of looking at `self.lastFetched`. + return clientsClient.getSince(0) + >>== { response in + return self.wipeIfNecessary(localClients) + >>> { self.applyStorageResponse(response, toLocalClients: localClients, withServer: clientsClient, notifier: notifier) } + } + >>> { deferMaybe(self.completedWithStats) } + } +} diff --git a/mobile/ios/Sync/Synchronizers/Downloader.swift b/mobile/ios/Sync/Synchronizers/Downloader.swift new file mode 100644 index 0000000000..7eff893124 --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/Downloader.swift @@ -0,0 +1,231 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import Deferred + +private let log = Logger.syncLogger + +class BatchingDownloader { + let client: Sync15CollectionClient + let collection: String + let prefs: Prefs + + var batch: [Record] = [] + + func store(_ records: [Record]) { + self.batch += records + } + + func retrieve() -> [Record] { + let ret = self.batch + self.batch = [] + return ret + } + + var _advance: (() -> Void)? + func advance() { + guard let f = self._advance else { + return + } + self._advance = nil + f() + } + + init(collectionClient: Sync15CollectionClient, basePrefs: Prefs, collection: String) { + self.client = collectionClient + self.collection = collection + let branchName = "downloader." + collection + "." + self.prefs = basePrefs.branch(branchName) + + log.info("Downloader configured with prefs '\(self.prefs.getBranchPrefix())'.") + } + + static func resetDownloaderWithPrefs(_ basePrefs: Prefs, collection: String) { + // This leads to stupid paths like 'profile.sync.synchronizer.history..downloader.history..'. + // Sorry, but it's out in the world now... + let branchName = "downloader." + collection + "." + let prefs = basePrefs.branch(branchName) + + let lm = prefs.timestampForKey("lastModified") + let bt = prefs.timestampForKey("baseTimestamp") + log.debug("Resetting downloader prefs \(prefs.getBranchPrefix()). Previous values: \(lm ??? "nil"), \(bt ??? "nil").") + + prefs.removeObjectForKey("nextOffset") + prefs.removeObjectForKey("offsetNewer") + prefs.removeObjectForKey("baseTimestamp") + prefs.removeObjectForKey("lastModified") + } + + /** + * Clients should provide the same set of parameters alongside an `offset` as was + * provided with the initial request. The only thing that varies in our batch fetches + * is `newer`, so we track the original value alongside. + */ + var nextFetchParameters: (String, Timestamp)? { + get { + let o = self.prefs.stringForKey("nextOffset") + let n = self.prefs.timestampForKey("offsetNewer") + guard let offset = o, let newer = n else { + return nil + } + return (offset, newer) + } + set (value) { + if let (offset, newer) = value { + self.prefs.setString(offset, forKey: "nextOffset") + self.prefs.setTimestamp(newer, forKey: "offsetNewer") + } else { + self.prefs.removeObjectForKey("nextOffset") + self.prefs.removeObjectForKey("offsetNewer") + } + } + } + + // Set after each batch, from record timestamps. + var baseTimestamp: Timestamp { + get { + return self.prefs.timestampForKey("baseTimestamp") ?? 0 + } + set (value) { + self.prefs.setTimestamp(value, forKey: "baseTimestamp") + } + } + + // Only set at the end of a batch, from headers. + var lastModified: Timestamp { + get { + return self.prefs.timestampForKey("lastModified") ?? 0 + } + set (value) { + self.prefs.setTimestamp(value, forKey: "lastModified") + } + } + + /** + * Call this when a significant structural server change has been detected. + */ + func reset() -> Success { + self.baseTimestamp = 0 + self.lastModified = 0 + self.nextFetchParameters = nil + self.batch = [] + self._advance = nil + return succeed() + } + + func go(_ info: InfoCollections, limit: Int) -> Deferred> { + guard let modified = info.modified(self.collection) else { + log.debug("No server modified time for collection \(self.collection).") + return deferMaybe(.noNewData) + } + + log.debug("Modified: \(modified); last \(self.lastModified).") + if modified == self.lastModified { + log.debug("No more data to batch-download.") + return deferMaybe(.noNewData) + } + + // If the caller hasn't advanced after the last batch, strange things will happen -- + // potentially looping indefinitely. Warn. + if self._advance != nil && !self.batch.isEmpty { + log.warning("Downloading another batch without having advanced. This might be a bug.") + } + return self.downloadNextBatchWithLimit(limit, infoModified: modified) + } + + func advanceTimestampTo(_ timestamp: Timestamp) { + log.debug("Advancing downloader lastModified from \(self.lastModified) to \(timestamp).") + self.lastModified = timestamp + } + + // We're either fetching from our current base timestamp with no offset, + // or the timestamp we were using when we last saved an offset. + func fetchParameters() -> (String?, Timestamp) { + if let (offset, since) = self.nextFetchParameters { + return (offset, since) + } + return (nil, max(self.lastModified, self.baseTimestamp)) + } + + func downloadNextBatchWithLimit(_ limit: Int, infoModified: Timestamp) -> Deferred> { + let (offset, since) = self.fetchParameters() + log.debug("Fetching newer=\(since), offset=\(offset ?? "nil").") + + let fetch = self.client.getSince(since, sort: SortOption.OldestFirst, limit: limit, offset: offset) + + func handleFailure(_ err: MaybeErrorType) -> Deferred> { + log.debug("Handling failure.") + guard let badRequest = err as? BadRequestError<[Record]>, badRequest.response.metadata.status == 412 else { + // Just pass through the failure. + return deferMaybe(err) + } + + // Conflict. Start again. + log.warning("Server contents changed during offset-based batching. Stepping back.") + self.nextFetchParameters = nil + return deferMaybe(.interrupted) + } + + func handleSuccess(_ response: StorageResponse<[Record]>) -> Deferred> { + log.debug("Handling success.") + let nextOffset = response.metadata.nextOffset + let responseModified = response.value.last?.modified + + // Queue up our metadata advance. We wait until the consumer has fetched + // and processed this batch; they'll call .advance() on success. + self._advance = { + // Shift to the next offset. This might be nil, in which case… fine! + // Note that we preserve the previous 'newer' value from the offset or the original fetch, + // even as we update baseTimestamp. + self.nextFetchParameters = nextOffset == nil ? nil : (nextOffset!, since) + + // If there are records, advance to just before the timestamp of the last. + // If our next fetch with X-Weave-Next-Offset fails, at least we'll start here. + // + // This approach is only valid if we're fetching oldest-first. + if let newBase = responseModified { + log.debug("Advancing baseTimestamp to \(newBase) - 1") + self.baseTimestamp = newBase - 1 + } + + if nextOffset == nil { + // If we can't get a timestamp from the header -- and we should always be able to -- + // we fall back on the collection modified time in i/c, as supplied by the caller. + // In any case where there is no racing writer these two values should be the same. + // If they differ, the header should be later. If it's missing, and we use the i/c + // value, we'll simply redownload some records. + // All bets are off if we hit this case and are filtering somehow… don't do that. + let lm = response.metadata.lastModifiedMilliseconds + log.debug("Advancing lastModified to \(String(describing: lm)) ?? \(infoModified).") + self.lastModified = lm ?? infoModified + } + } + + log.debug("Got success response with \(response.metadata.records ?? 0) records.") + + // Store the incoming records for collection. + self.store(response.value) + + return deferMaybe(nextOffset == nil ? .complete : .incomplete) + } + + return fetch.bind { result in + guard let response = result.successValue else { + return handleFailure(result.failureValue!) + } + return handleSuccess(response) + } + } +} + +public enum DownloadEndState: String { + case complete // We're done. Records are waiting for you. + case incomplete // applyBatch was called, and we think there are more records. + case noNewData // There were no records. + case interrupted // We got a 412 conflict when fetching the next batch. +} diff --git a/mobile/ios/Sync/Synchronizers/HistorySynchronizer.swift b/mobile/ios/Sync/Synchronizers/HistorySynchronizer.swift new file mode 100644 index 0000000000..ac37bd1c5f --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/HistorySynchronizer.swift @@ -0,0 +1,287 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import Deferred +import SwiftyJSON + +private let log = Logger.syncLogger +private let HistoryTTLInSeconds = 5184000 // 60 days. +let HistoryStorageVersion = 1 + +func makeDeletedHistoryRecord(_ guid: GUID) -> Record { + // Local modified time is ignored in upload serialization. + let modified: Timestamp = 0 + + // Sortindex for history is frecency. Make deleted items more frecent than almost + // anything. + let sortindex = 5_000_000 + + let ttl = HistoryTTLInSeconds + + let json: JSON = JSON([ + "id": guid, + "deleted": true, + ]) + let payload = HistoryPayload(json) + return Record(id: guid, payload: payload, modified: modified, sortindex: sortindex, ttl: ttl) +} + +func makeHistoryRecord(_ place: Place, visits: [Visit]) -> Record { + let id = place.guid + let modified: Timestamp = 0 // Ignored in upload serialization. + let sortindex = 1 // TODO: frecency! + let ttl = HistoryTTLInSeconds + let json: JSON = JSON([ + "id": id, + "visits": visits.map { $0.toJSON() }, + "histUri": place.url, + "title": place.title, + ]) + let payload = HistoryPayload(json) + return Record(id: id, payload: payload, modified: modified, sortindex: sortindex, ttl: ttl) +} + +open class HistorySynchronizer: IndependentRecordSynchronizer, Synchronizer { + public required init(scratchpad: Scratchpad, delegate: SyncDelegate, basePrefs: Prefs, why: SyncReason) { + super.init(scratchpad: scratchpad, delegate: delegate, basePrefs: basePrefs, why: why, collection: "history") + } + + override var storageVersion: Int { + return HistoryStorageVersion + } + + fileprivate let batchSize: Int = 1000 // A balance between number of requests and per-request size. + + fileprivate func mask(_ maxFailures: Int) -> (Maybe<()>) -> Success { + var failures = 0 + return { result in + if result.isSuccess { + return Deferred(value: result) + } + + failures += 1 + if failures > maxFailures { + return Deferred(value: result) + } + + log.debug("Masking failure \(failures).") + return succeed() + } + } + + // TODO: this function should establish a transaction at suitable points. + // TODO: a much more efficient way to do this is to: + // 1. Start a transaction. + // 2. Try to update each place. Note failures. + // 3. bulkInsert all failed updates in one go. + // 4. Store all remote visits for all places in one go, constructing a single sequence of visits. + func applyIncomingToStorage(_ storage: SyncableHistory, records: [Record]) -> Success { + // Skip over at most this many failing records before aborting the sync. + let maskSomeFailures = self.mask(3) + + // TODO: it'd be nice to put this in an extension on SyncableHistory. Waiting for Swift 2.0... + func applyRecord(_ rec: Record) -> Success { + let guid = rec.id + let payload = rec.payload + let modified = rec.modified + + // We apply deletions immediately. Yes, this will throw away local visits + // that haven't yet been synced. That's how Sync works, alas. + if payload.deleted { + return storage.deleteByGUID(guid, deletedAt: modified).bind(maskSomeFailures) + } + + // It's safe to apply other remote records, too -- even if we re-download, we know + // from our local cached server timestamp on each record that we've already seen it. + // We have to reconcile on-the-fly: we're about to overwrite the server record, which + // is our shared parent. + let place = rec.payload.asPlace() + + if isIgnoredURL(place.url) { + log.debug("Ignoring incoming record \(guid) because its URL is one we wish to ignore.") + return succeed() + } + + let placeThenVisits = storage.insertOrUpdatePlace(place, modified: modified) + >>> { storage.storeRemoteVisits(payload.visits, forGUID: guid) } + return placeThenVisits.map({ result in + if result.isFailure { + let reason = result.failureValue?.description ?? "unknown reason" + log.error("Record application failed: \(reason)") + } + return result + }).bind(maskSomeFailures) + } + + return self.applyIncomingRecords(records, apply: applyRecord) + } + + fileprivate func uploadModifiedPlaces(_ places: [(Place, [Visit])], lastTimestamp: Timestamp, fromStorage storage: SyncableHistory, withServer storageClient: Sync15CollectionClient) -> DeferredTimestamp { + log.info("Preparing upload…") + + // Build sequences of 1000 history items, sequence by sequence + // These will be uploaded in smaller batches by the upload batcher, but we chunk here + // in order to bound peak memory usage when we call makeHistoryRecord below. + let toUpload = chunk(places, by: 1000) + let perChunk: (ArraySlice<(Place, [Visit])>, Timestamp) -> DeferredTimestamp = { (records, timestamp) in + let recs = records.map(makeHistoryRecord) + log.info("Uploading \(recs.count) history items…") + return self.uploadRecords(recs, lastTimestamp: timestamp, storageClient: storageClient) { result, lastModified in + // We don't do anything with failed. + return storage.markAsSynchronized(result.success, modified: lastModified ?? timestamp) + } + } + + let start = deferMaybe(lastTimestamp) + return walk(toUpload, start: start, f: perChunk) + } + + fileprivate func uploadDeletedPlaces(_ guids: [GUID], lastTimestamp: Timestamp, fromStorage storage: SyncableHistory, withServer storageClient: Sync15CollectionClient) -> DeferredTimestamp { + + let records = guids.map(makeDeletedHistoryRecord) + + // Deletions are smaller, so upload 100 at a time. + return self.uploadRecords(records, lastTimestamp: lastTimestamp, storageClient: storageClient) { result, lastModified in + storage.markAsDeleted(result.success) >>> always(lastModified ?? lastTimestamp) + } + } + + fileprivate func uploadOutgoingFromStorage(_ storage: SyncableHistory, lastTimestamp: Timestamp, withServer storageClient: Sync15CollectionClient) -> Success { + var workWasDone = false + + let uploadDeleted: (Timestamp) -> DeferredTimestamp = { timestamp in + storage.getDeletedHistoryToUpload() + >>== { guids in + if !guids.isEmpty { + workWasDone = true + } + log.info("Uploading \(guids.count) deleted places.") + return self.uploadDeletedPlaces(guids, lastTimestamp: timestamp, fromStorage: storage, withServer: storageClient) + } + } + + let uploadModified: (Timestamp) -> DeferredTimestamp = { timestamp in + storage.getModifiedHistoryToUpload() + >>== { places in + if !places.isEmpty { + workWasDone = true + } + log.info("Uploading \(places.count) modified places.") + return self.uploadModifiedPlaces(places, lastTimestamp: timestamp, fromStorage: storage, withServer: storageClient) + } + } + + // The last clause will checkpoint the DB. But we just checkpointed the DB after downloading records! + // Yes, that's true. Either there will be lots of work to do (e.g., having just marked + // thousands of records as uploaded, or dropping lots of deleted rows), and so it's + // worthwhile… or there won't be much work to do, and the checkpoint will be cheap. + // If we did nothing -- uploaded no deletions, uploaded no modified records -- then we + // don't checkpoint at all. + return deferMaybe(lastTimestamp) + >>== uploadDeleted + >>== uploadModified + >>> effect({ log.debug("Done syncing. Work was done? \(workWasDone)") }) + >>> { workWasDone ? storage.doneUpdatingMetadataAfterUpload() : succeed() } // A closure so we eval workWasDone after it's set! + >>> effect({ log.debug("Done.") }) + } + + /** + * If the green light turns red, we don't want to continue to upload -- doing + * so would cause us to fast-forward our last sync timestamp and skip whatever + * we hadn't yet downloaded. + */ + fileprivate func go(_ info: InfoCollections, greenLight: @escaping () -> Bool, downloader: BatchingDownloader, history: SyncableHistory) -> SyncResult { + + if !greenLight() { + log.info("Green light turned red. Stopping history download.") + return deferMaybe(.partial(self.statsSession)) + } + + func applyBatched() -> Success { + return self.applyIncomingToStorage(history, records: downloader.retrieve()) + >>> effect(downloader.advance) + } + + func onBatchResult(_ result: Maybe) -> SyncResult { + guard let end = result.successValue else { + log.warning("Got failure: \(result.failureValue!)") + return deferMaybe(completedWithStats) + } + + switch end { + case .complete: + log.info("Done with batched mirroring.") + return applyBatched() + >>> history.doneApplyingRecordsAfterDownload + >>> { deferMaybe(self.completedWithStats) } + case .incomplete: + log.debug("Running another batch.") + // This recursion is fine because Deferred always pushes callbacks onto a queue. + return applyBatched() + >>> { self.go(info, greenLight: greenLight, downloader: downloader, history: history) } + case .interrupted: + log.info("Interrupted. Aborting batching this time.") + return deferMaybe(.partial(self.statsSession)) + case .noNewData: + log.info("No new data. No need to continue batching.") + downloader.advance() + return deferMaybe(completedWithStats) + } + } + + return downloader.go(info, limit: self.batchSize) + .bind(onBatchResult) + } + + open func synchronizeLocalHistory(_ history: SyncableHistory, withServer storageClient: Sync15StorageClient, info: InfoCollections, greenLight: @escaping () -> Bool) -> SyncResult { + if let reason = self.reasonToNotSync(storageClient) { + return deferMaybe(.notStarted(reason)) + } + + let encoder = RecordEncoder(decode: { HistoryPayload($0) }, encode: { $0.json }) + + guard let historyClient = self.collectionClient(encoder, storageClient: storageClient) else { + log.error("Couldn't make history factory.") + return deferMaybe(FatalError(message: "Couldn't make history factory.")) + } + + let downloader = BatchingDownloader(collectionClient: historyClient, basePrefs: self.prefs, collection: "history") + + // The original version of the history synchronizer tracked its + // own last fetched time. We need to migrate this into the + // batching downloader. + let since: Timestamp = self.lastFetched + if since > downloader.lastModified { + log.debug("Advancing downloader lastModified to synchronizer lastFetched \(since).") + downloader.lastModified = since + self.lastFetched = 0 + } + + statsSession.start() + return self.go(info, greenLight: greenLight, downloader: downloader, history: history) + >>== { syncResult in + switch syncResult { + case .completed: + // When we're done downloading, we can upload. + return self.uploadOutgoingFromStorage(history, + lastTimestamp: 0, + withServer: historyClient) + >>> { deferMaybe(self.completedWithStats) } + + // If we didn't finish downloading, do nothing further -- just pass + // through the download result. + case .notStarted(_): + return deferMaybe(syncResult) + + case .partial: + log.debug("Didn't finish downloading history; not uploading yet.") + return deferMaybe(syncResult) + } + } + } +} diff --git a/mobile/ios/Sync/Synchronizers/IndependentRecordSynchronizer.swift b/mobile/ios/Sync/Synchronizers/IndependentRecordSynchronizer.swift new file mode 100644 index 0000000000..508acdbac8 --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/IndependentRecordSynchronizer.swift @@ -0,0 +1,147 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import Deferred + +private let log = Logger.syncLogger + +class Uploader { + /** + * Upload just about anything that can be turned into something we can upload. + */ + func sequentialPosts(_ items: [T], by: Int, lastTimestamp: Timestamp, storageOp: @escaping ([T], Timestamp) -> DeferredTimestamp) -> DeferredTimestamp { + + // This needs to be a real Array, not an ArraySlice, + // for the types to line up. + let chunks = chunk(items, by: by).map { Array($0) } + + let start = deferMaybe(lastTimestamp) + + let perChunk: ([T], Timestamp) -> DeferredTimestamp = { (records, timestamp) in + // TODO: detect interruptions -- clients uploading records during our sync -- + // by using ifUnmodifiedSince. We can detect uploaded records since our download + // (chain the download timestamp into this function), and we can detect uploads + // that race with our own (chain download timestamps across 'walk' steps). + // If we do that, we can also advance our last fetch timestamp after each chunk. + log.debug("Uploading \(records.count) records.") + return storageOp(records, timestamp) + } + + return walk(chunks, start: start, f: perChunk) + } +} + +open class IndependentRecordSynchronizer: TimestampedSingleCollectionSynchronizer { + private func reportApplyStatsWrap(apply: @escaping (T) -> Success) -> (T) -> Success { + return { record in + return apply(record).bind({ result in + var stats = SyncDownloadStats() + stats.applied = 1 + if result.isSuccess { + stats.succeeded = 1 + } else { + stats.failed = 1 + } + self.statsSession.recordDownload(stats: stats) + return Deferred(value: result) + }) + } + } + + /** + * Just like the usual applyIncomingToStorage, but doesn't fast-forward the timestamp. + */ + func applyIncomingRecords(_ records: [T], apply: @escaping (T) -> Success) -> Success { + if records.isEmpty { + log.debug("No records; done applying.") + return succeed() + } + + return walk(records, f: reportApplyStatsWrap(apply: apply)) + } + + func applyIncomingToStorage(_ records: [T], fetched: Timestamp, apply: @escaping (T) -> Success) -> Success { + func done() -> Success { + log.debug("Bumping fetch timestamp to \(fetched).") + self.lastFetched = fetched + return succeed() + } + + if records.isEmpty { + log.debug("No records; done applying.") + return done() + } + + return walk(records, f: reportApplyStatsWrap(apply: apply)) >>> done + } +} + +extension TimestampedSingleCollectionSynchronizer { + /** + * On each chunk that we upload, we pass along the server modified timestamp to the next, + * chained through the provided `onUpload` function. + * + * The last chunk passes this modified timestamp out, and we assign it to lastFetched. + * + * The idea of this is twofold: + * + * 1. It does the fast-forwarding that every other Sync client does. + * + * 2. It allows us to (eventually) pass the last collection modified time as If-Unmodified-Since + * on each upload batch, as we do between the download and the upload phase. + * This alone allows us to detect conflicts from racing clients. + * + * In order to implement the latter, we'd need to chain the date from getSince in place of the + * 0 in the call to uploadOutgoingFromStorage in each synchronizer. + */ + func uploadRecords(_ records: [Record], lastTimestamp: Timestamp, storageClient: Sync15CollectionClient, onUpload: @escaping (POSTResult, Timestamp?) -> DeferredTimestamp) -> DeferredTimestamp { + if records.isEmpty { + log.debug("No modified records to upload.") + return deferMaybe(lastTimestamp) + } + + func reportUploadStatsWrap(result: POSTResult, timestamp: Timestamp?) -> DeferredTimestamp { + let stats = SyncUploadStats(sent: result.success.count, sentFailed: result.failed.count) + self.statsSession.recordUpload(stats: stats) + return onUpload(result, timestamp) + } + + let batch = storageClient.newBatch(ifUnmodifiedSince: (lastTimestamp == 0) ? nil : lastTimestamp, onCollectionUploaded: reportUploadStatsWrap) + return batch.addRecords(records) + >>> batch.endBatch + >>> { + let timestamp = batch.ifUnmodifiedSince ?? lastTimestamp + self.setTimestamp(timestamp) + return deferMaybe(timestamp) + } + } + + func uploadRecordsSingleBatch(_ records: [Record], lastTimestamp: Timestamp, storageClient: Sync15CollectionClient) -> Deferred> { + if records.isEmpty { + log.debug("No modified records to upload.") + return deferMaybe((timestamp: lastTimestamp, succeeded: [])) + } + + func reportUploadStatsWrap(result: POSTResult, timestamp: Timestamp?) -> DeferredTimestamp { + let stats = SyncUploadStats(sent: result.success.count, sentFailed: result.failed.count) + self.statsSession.recordUpload(stats: stats) + return deferMaybe(timestamp ?? lastTimestamp) + } + + let batch = storageClient.newBatch(ifUnmodifiedSince: (lastTimestamp == 0) ? nil : lastTimestamp, onCollectionUploaded: reportUploadStatsWrap) + return batch.addRecords(records, singleBatch: true) + >>== batch.endSingleBatch + >>== { (succeeded, lastModified) in + guard let timestamp = lastModified else { + return deferMaybe(FatalError(message: "Could not retrieve lastModified from the server response.")) + } + self.setTimestamp(timestamp) + return deferMaybe((timestamp: timestamp, succeeded: succeeded)) + } + } +} diff --git a/mobile/ios/Sync/Synchronizers/LoginsSynchronizer.swift b/mobile/ios/Sync/Synchronizers/LoginsSynchronizer.swift new file mode 100644 index 0000000000..cfdbba4e47 --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/LoginsSynchronizer.swift @@ -0,0 +1,190 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import Deferred +import SwiftyJSON + +private let log = Logger.syncLogger +let PasswordsStorageVersion = 1 + +private func makeDeletedLoginRecord(_ guid: GUID) -> Record { + // Local modified time is ignored in upload serialization. + let modified: Timestamp = 0 + + // Arbitrary large number: deletions sync down first. + let sortindex = 5_000_000 + + let json: JSON = JSON([ + "id": guid, + "deleted": true, + ]) + let payload = LoginPayload(json) + return Record(id: guid, payload: payload, modified: modified, sortindex: sortindex) +} + +func makeLoginRecord(_ login: Login) -> Record { + let id = login.guid + let modified: Timestamp = 0 // Ignored in upload serialization. + let sortindex = 1 + + let tLU = NSNumber(value: login.timeLastUsed / 1000) + let tPC = NSNumber(value: login.timePasswordChanged / 1000) + let tC = NSNumber(value: login.timeCreated / 1000) + + let dict: [String: Any] = [ + "id": id, + "hostname": login.hostname, + "httpRealm": login.httpRealm as Any, + "formSubmitURL": login.formSubmitURL as Any, + "username": login.username ?? "", + "password": login.password , + "usernameField": login.usernameField ?? "", + "passwordField": login.passwordField ?? "", + "timesUsed": login.timesUsed, + "timeLastUsed": tLU, + "timePasswordChanged": tPC, + "timeCreated": tC, + ] + + let payload = LoginPayload(JSON(dict)) + return Record(id: id, payload: payload, modified: modified, sortindex: sortindex) +} + +/** + * Our current local terminology ("logins") has diverged from the terminology in + * use when Sync was built ("passwords"). I've done my best to draw a reasonable line + * between the server collection/record format/etc. and local stuff: local storage + * works with logins, server records and collection are passwords. + */ +open class LoginsSynchronizer: IndependentRecordSynchronizer, Synchronizer { + public required init(scratchpad: Scratchpad, delegate: SyncDelegate, basePrefs: Prefs, why: SyncReason) { + super.init(scratchpad: scratchpad, delegate: delegate, basePrefs: basePrefs, why: why, collection: "passwords") + } + + override var storageVersion: Int { + return PasswordsStorageVersion + } + + func getLogin(_ record: Record) -> ServerLogin { + let guid = record.id + let payload = record.payload + let modified = record.modified + + let login = ServerLogin(guid: guid, hostname: payload.hostname, username: payload.username, password: payload.password, modified: modified) + login.formSubmitURL = payload.formSubmitURL + login.httpRealm = payload.httpRealm + login.usernameField = payload.usernameField + login.passwordField = payload.passwordField + + // Microseconds locally, milliseconds remotely. We should clean this up. + login.timeCreated = 1000 * (payload.timeCreated ?? 0) + login.timeLastUsed = 1000 * (payload.timeLastUsed ?? 0) + login.timePasswordChanged = 1000 * (payload.timePasswordChanged ?? 0) + login.timesUsed = payload.timesUsed ?? 0 + return login + } + + func applyIncomingToStorage(_ storage: SyncableLogins, records: [Record], fetched: Timestamp) -> Success { + return self.applyIncomingToStorage(records, fetched: fetched) { rec in + let guid = rec.id + let payload = rec.payload + + guard payload.isValid() else { + log.warning("Login record \(guid) is invalid. Skipping.") + return succeed() + } + + // We apply deletions immediately. That might not be exactly what we want -- perhaps you changed + // a password locally after deleting it remotely -- but it's expedient. + if payload.deleted { + return storage.deleteByGUID(guid, deletedAt: rec.modified) + } + + return storage.applyChangedLogin(self.getLogin(rec)) + } + } + + fileprivate func uploadChangedRecords(_ deleted: Set, modified: Set, records: [Record], lastTimestamp: Timestamp, storage: SyncableLogins, withServer storageClient: Sync15CollectionClient) -> Success { + + let onUpload: (POSTResult, Timestamp?) -> DeferredTimestamp = { result, lastModified in + let uploaded = Set(result.success) + return storage.markAsDeleted(uploaded.intersection(deleted)) >>> { storage.markAsSynchronized(uploaded.intersection(modified), modified: lastModified ?? lastTimestamp) } + } + + return uploadRecords(records, + lastTimestamp: lastTimestamp, + storageClient: storageClient, + onUpload: onUpload) >>> succeed + } + + // Find any records for which a local overlay exists. If we want to be really precise, + // we can find the original server modified time for each record and use it as + // If-Unmodified-Since on a PUT, or just use the last fetch timestamp, which should + // be equivalent. + // We will already have reconciled any conflicts on download, so this upload phase should + // be as simple as uploading any changed or deleted items. + fileprivate func uploadOutgoingFromStorage(_ storage: SyncableLogins, lastTimestamp: Timestamp, withServer storageClient: Sync15CollectionClient) -> Success { + let deleted: () -> Deferred, [Record])>> = { + return storage.getDeletedLoginsToUpload() >>== { guids in + let records = guids.map(makeDeletedLoginRecord) + return deferMaybe((Set(guids), records)) + } + } + + let modified: () -> Deferred, [Record])>> = { + return storage.getModifiedLoginsToUpload() >>== { logins in + let guids = Set(logins.map { $0.guid }) + let records = logins.map(makeLoginRecord) + return deferMaybe((guids, records)) + } + } + + return accumulate([deleted, modified]) >>== { result in + let (deletedGUIDs, deletedRecords) = result[0] + let (modifiedGUIDs, modifiedRecords) = result[1] + let allRecords = deletedRecords + modifiedRecords + + return self.uploadChangedRecords(deletedGUIDs, modified: modifiedGUIDs, records: allRecords, + lastTimestamp: lastTimestamp, storage: storage, withServer: storageClient) + } + } + + open func synchronizeLocalLogins(_ logins: SyncableLogins, withServer storageClient: Sync15StorageClient, info: InfoCollections) -> SyncResult { + if let reason = self.reasonToNotSync(storageClient) { + return deferMaybe(.notStarted(reason)) + } + + let encoder = RecordEncoder(decode: { LoginPayload($0) }, encode: { $0.json }) + guard let passwordsClient = self.collectionClient(encoder, storageClient: storageClient) else { + log.error("Couldn't make logins factory.") + return deferMaybe(FatalError(message: "Couldn't make logins factory.")) + } + + let since: Timestamp = self.lastFetched + log.debug("Synchronizing \(self.collection). Last fetched: \(since).") + + let applyIncomingToStorage: (StorageResponse<[Record]>) -> Success = { response in + let ts = response.metadata.timestampMilliseconds + let lm = response.metadata.lastModifiedMilliseconds! + log.debug("Applying incoming password records from response timestamped \(ts), last modified \(lm).") + log.debug("Records header hint: \(response.metadata.records ??? "nil")") + return self.applyIncomingToStorage(logins, records: response.value, fetched: lm) >>> effect { + NotificationCenter.default.post(name: NotificationDataRemoteLoginChangesWereApplied, object: nil) + } + } + + statsSession.start() + return passwordsClient.getSince(since) + >>== applyIncomingToStorage + // TODO: If we fetch sorted by date, we can bump the lastFetched timestamp + // to the last successfully applied record timestamp, no matter where we fail. + // There's no need to do the upload before bumping -- the storage of local changes is stable. + >>> { self.uploadOutgoingFromStorage(logins, lastTimestamp: 0, withServer: passwordsClient) } + >>> { return deferMaybe(self.completedWithStats) } + } +} diff --git a/mobile/ios/Sync/Synchronizers/Synchronizer.swift b/mobile/ios/Sync/Synchronizers/Synchronizer.swift new file mode 100644 index 0000000000..cf7e3a70aa --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/Synchronizer.swift @@ -0,0 +1,293 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import Deferred + +private let log = Logger.syncLogger + +/** + * This exists to pass in external context: e.g., the UIApplication can + * expose notification functionality in this way. + */ +public protocol SyncDelegate { + func displaySentTab(for url: URL, title: String, from deviceName: String?) + // TODO: storage. +} + +/** + * We sometimes want to make a synchronizer start from scratch: to throw away any + * metadata and reset storage to match, allowing us to respond to significant server + * changes. + * + * But instantiating a Synchronizer is a lot of work if we simply want to change some + * persistent state. This protocol describes a static func that fits most synchronizers. + * + * When the returned `Deferred` is filled with a success value, the supplied prefs and + * storage are ready to sync from scratch. + * + * Persisted long-term/local data is kept, and will later be reconciled as appropriate. + */ +public protocol ResettableSynchronizer { + static func resetSynchronizerWithStorage(_ storage: ResettableSyncStorage, basePrefs: Prefs, collection: String) -> Success +} + +/** + * This is a delegate that allows synchronizers to notify other devices in the Sync account + * that a collection changed. + */ +public protocol CollectionChangedNotifier { + func notify(deviceIDs: [GUID], collectionsChanged collections: [String], reason: String) -> Success + func notifyAll(collectionsChanged collections: [String], reason: String) -> Success +} + +// TODO: return values? +/** + * A Synchronizer is (unavoidably) entirely in charge of what it does within a sync. + * For example, it might make incremental progress in building a local cache of remote records, never actually performing an upload or modifying local storage. + * It might only upload data. Etc. + * + * Eventually I envision an intent-like approach, or additional methods, to specify preferences and constraints + * (e.g., "do what you can in a few seconds", or "do a full sync, no matter how long it takes"), but that'll come in time. + * + * A Synchronizer is a two-stage beast. It needs to support synchronization, of course; that + * needs a completely configured client, which can only be obtained from Ready. But it also + * needs to be able to do certain things beforehand: + * + * * Wipe its collections from the server (presumably via a delegate from the state machine). + * * Prepare to sync from scratch ("reset") in response to a changed set of keys, syncID, or node assignment. + * * Wipe local storage ("wipeClient"). + * + * Those imply that some kind of 'Synchronizer' exists throughout the state machine. We *could* + * pickle instructions for eventual delivery next time one is made and synchronized… + */ +public protocol Synchronizer { + init(scratchpad: Scratchpad, delegate: SyncDelegate, basePrefs: Prefs, why: SyncReason) + + /** + * Return a reason if the current state of this synchronizer -- particularly prefs and scratchpad -- + * prevent a routine sync from occurring. + */ + func reasonToNotSync(_: Sync15StorageClient) -> SyncNotStartedReason? +} + +/** + * We sometimes wish to return something more nuanced than simple success or failure. + * For example, refusing to sync because the engine was disabled isn't success (nothing was transferred!) + * but it also isn't an error. + * + * To do this we model real failures -- something went wrong -- as failures in the Result, and + * everything else in this status enum. This will grow as we return more details from a sync to allow + * for batch scheduling, success-case backoff and so on. + */ +public enum SyncStatus { + case completed(SyncEngineStatsSession) + case notStarted(SyncNotStartedReason) + case partial(SyncEngineStatsSession) + + public var description: String { + switch self { + case .completed: + return "Completed" + case let .notStarted(reason): + return "Not started: \(reason.description)" + case .partial: + return "Partial" + } + } +} + +public typealias DeferredTimestamp = Deferred> +public typealias SyncResult = Deferred> +public typealias EngineIdentifier = String +public typealias EngineStatus = (EngineIdentifier, SyncStatus) +public typealias EngineResults = [EngineStatus] +public typealias SyncOperationResult = (engineResults: Maybe, stats: SyncOperationStatsSession?) + +public enum SyncNotStartedReason { + case noAccount + case offline + case backoff(remainingSeconds: Int) + case engineRemotelyNotEnabled(collection: String) + case engineFormatOutdated(needs: Int) + case engineFormatTooNew(expected: Int) // This'll disappear eventually; we'll wipe the server and upload m/g. + case storageFormatOutdated(needs: Int) + case storageFormatTooNew(expected: Int) // This'll disappear eventually; we'll wipe the server and upload m/g. + case stateMachineNotReady // Because we're not done implementing. + case redLight + case unknown // Likely a programming error. + + var telemetryId: String { + switch self { + case .noAccount: + return "sync.not_started.reason.no_account" + case .offline: + return "sync.not_started.reason.offline" + case .backoff(_): + return "sync.not_started.reason.backoff" + case .engineRemotelyNotEnabled(_): + return "sync.not_started.reason.remotely_not_enabled" + case .engineFormatOutdated(_): + return "sync.not_started.reason.format_outdated" + case .engineFormatTooNew(_): // This'll disappear eventually; we'll wipe the server and upload m/g. + return "sync.not_started.reason.format_too_new" + case .storageFormatOutdated(_): + return "sync.not_started.reason.storage_format_outdated" + case .storageFormatTooNew(_): // This'll disappear eventually; we'll wipe the server and upload m/g. + return "sync.not_started.reason.storage_format_too_new" + case .stateMachineNotReady: // Because we're not done implementing. + return "sync.not_started.reason.state_machine_not_ready" + case .redLight: + return "sync.not_started.reason.red_light" + case .unknown: // Likely a programming error + return "sync.not_started.reason.unknown" + } + } + + var description: String { + switch self { + case .noAccount: + return "no account" + case let .backoff(remaining): + return "in backoff: \(remaining) seconds remaining" + default: + return "undescribed reason" + } + } +} + +open class FatalError: SyncError { + let message: String + init(message: String) { + self.message = message + } + + open var description: String { + return self.message + } +} + +public protocol SingleCollectionSynchronizer { + func remoteHasChanges(_ info: InfoCollections) -> Bool +} + +open class BaseCollectionSynchronizer { + let collection: String + + let scratchpad: Scratchpad + let delegate: SyncDelegate + let basePrefs: Prefs + let prefs: Prefs + let why: SyncReason + + var statsSession: SyncEngineStatsSession + + static func prefsForCollection(_ collection: String, withBasePrefs basePrefs: Prefs) -> Prefs { + let branchName = "synchronizer." + collection + "." + return basePrefs.branch(branchName) + } + + init(scratchpad: Scratchpad, delegate: SyncDelegate, basePrefs: Prefs, why: SyncReason, collection: String) { + self.scratchpad = scratchpad + self.delegate = delegate + self.collection = collection + self.basePrefs = basePrefs + self.prefs = BaseCollectionSynchronizer.prefsForCollection(collection, withBasePrefs: basePrefs) + self.statsSession = SyncEngineStatsSession(collection: collection) + self.why = why + + log.info("Synchronizer configured with prefs '\(self.prefs.getBranchPrefix()).'") + } + + var storageVersion: Int { + assert(false, "Override me!") + return 0 + } + + // Short-hand for returning .Complete status + recorded stats + var completedWithStats: SyncStatus { + return .completed(statsSession.end()) + } + + open func reasonToNotSync(_ client: Sync15StorageClient) -> SyncNotStartedReason? { + let now = Date.now() + if let until = client.backoff.isInBackoff(now) { + let remaining = (until - now) / 1000 + return .backoff(remainingSeconds: Int(remaining)) + } + + if let metaGlobal = self.scratchpad.global?.value { + // There's no need to check the global storage format here; the state machine will already have + // done so. + if let engineMeta = metaGlobal.engines[collection] { + if engineMeta.version > self.storageVersion { + return .engineFormatOutdated(needs: engineMeta.version) + } + if engineMeta.version < self.storageVersion { + return .engineFormatTooNew(expected: engineMeta.version) + } + } else { + return .engineRemotelyNotEnabled(collection: self.collection) + } + } else { + // But a missing meta/global is a real problem. + return .stateMachineNotReady + } + + // Success! + return nil + } + + func encrypter(_ encoder: RecordEncoder) -> RecordEncrypter? { + return self.scratchpad.keys?.value.encrypter(self.collection, encoder: encoder) + } + + func collectionClient(_ encoder: RecordEncoder, storageClient: Sync15StorageClient) -> Sync15CollectionClient? { + if let encrypter = self.encrypter(encoder) { + return storageClient.clientForCollection(self.collection, encrypter: encrypter) + } + return nil + } +} + +/** + * Tracks a lastFetched timestamp, uses it to decide if there are any + * remote changes, and exposes a method to fast-forward after upload. + */ +open class TimestampedSingleCollectionSynchronizer: BaseCollectionSynchronizer, SingleCollectionSynchronizer { + + var lastFetched: Timestamp { + set(value) { + self.prefs.setLong(value, forKey: "lastFetched") + } + + get { + return self.prefs.unsignedLongForKey("lastFetched") ?? 0 + } + } + + func setTimestamp(_ timestamp: Timestamp) { + log.debug("Setting post-upload lastFetched to \(timestamp).") + self.lastFetched = timestamp + } + + open func remoteHasChanges(_ info: InfoCollections) -> Bool { + return info.modified(self.collection) ?? 0 > self.lastFetched + } +} + +extension BaseCollectionSynchronizer: ResettableSynchronizer { + public static func resetSynchronizerWithStorage(_ storage: ResettableSyncStorage, basePrefs: Prefs, collection: String) -> Success { + let synchronizerPrefs = BaseCollectionSynchronizer.prefsForCollection(collection, withBasePrefs: basePrefs) + synchronizerPrefs.removeObjectForKey("lastFetched") + + // Not all synchronizers use a batching downloader, but it's + // convenient to just always reset it here. + return storage.resetClient() + >>> effect({ BatchingDownloader.resetDownloaderWithPrefs(synchronizerPrefs, collection: collection) }) + } +} diff --git a/mobile/ios/Sync/Synchronizers/TabsSynchronizer.swift b/mobile/ios/Sync/Synchronizers/TabsSynchronizer.swift new file mode 100644 index 0000000000..d2cd349daf --- /dev/null +++ b/mobile/ios/Sync/Synchronizers/TabsSynchronizer.swift @@ -0,0 +1,206 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import Deferred +import SwiftyJSON + +private let log = Logger.syncLogger +let TabsStorageVersion = 1 + +open class TabsSynchronizer: TimestampedSingleCollectionSynchronizer, Synchronizer { + public required init(scratchpad: Scratchpad, delegate: SyncDelegate, basePrefs: Prefs, why: SyncReason) { + super.init(scratchpad: scratchpad, delegate: delegate, basePrefs: basePrefs, why: why, collection: "tabs") + } + + override var storageVersion: Int { + return TabsStorageVersion + } + + var tabsRecordLastUpload: Timestamp { + set(value) { + self.prefs.setLong(value, forKey: "lastTabsUpload") + } + + get { + return self.prefs.unsignedLongForKey("lastTabsUpload") ?? 0 + } + } + + fileprivate func createOwnTabsRecord(_ tabs: [RemoteTab]) -> Record { + let guid = self.scratchpad.clientGUID + + let tabsJSON = JSON([ + "id": guid, + "clientName": self.scratchpad.clientName, + "tabs": tabs.flatMap { $0.toDictionary() } + ]) + if Logger.logPII { + log.verbose("Sending tabs JSON \(tabsJSON.stringValue() ?? "nil")") + } + let payload = TabsPayload(tabsJSON) + return Record(id: guid, payload: payload, ttl: ThreeWeeksInSeconds) + } + + fileprivate func uploadOurTabs(_ localTabs: RemoteClientsAndTabs, toServer tabsClient: Sync15CollectionClient) -> Success { + // check to see if our tabs have changed or we're in a fresh start + let lastUploadTime: Timestamp? = (self.tabsRecordLastUpload == 0) ? nil : self.tabsRecordLastUpload + if let lastUploadTime = lastUploadTime, + lastUploadTime >= (Date.now() - (OneMinuteInMilliseconds)) { + log.debug("Not uploading tabs: already did so at \(lastUploadTime).") + return succeed() + } + + return localTabs.getTabsForClientWithGUID(nil) >>== { tabs in + if let lastUploadTime = lastUploadTime { + // TODO: track this in memory so we don't have to hit the disk to figure out when our tabs have + // changed and need to be uploaded. + if tabs.every({ $0.lastUsed < lastUploadTime }) { + return succeed() + } + } + + let tabsRecord = self.createOwnTabsRecord(tabs) + log.debug("Uploading our tabs: \(tabs.count).") + + var uploadStats = SyncUploadStats() + uploadStats.sent += 1 + + // We explicitly don't send If-Unmodified-Since, because we always + // want our upload to succeed -- we own the record. + return tabsClient.put(tabsRecord, ifUnmodifiedSince: nil) >>== { resp in + if let ts = resp.metadata.lastModifiedMilliseconds { + // Protocol says this should always be present for success responses. + log.debug("Tabs record upload succeeded. New timestamp: \(ts).") + self.tabsRecordLastUpload = ts + } else { + uploadStats.sentFailed += 1 + } + return succeed() + } >>== effect({ self.statsSession.recordUpload(stats: uploadStats) }) + } + } + + open func synchronizeLocalTabs(_ localTabs: RemoteClientsAndTabs, withServer storageClient: Sync15StorageClient, info: InfoCollections) -> SyncResult { + func onResponseReceived(_ response: StorageResponse<[Record]>) -> Success { + + func afterWipe() -> Success { + var downloadStats = SyncDownloadStats() + + let doInsert: (Record) -> Deferred> = { record in + let remotes = record.payload.isValid() ? record.payload.remoteTabs : [] + let ins = localTabs.insertOrUpdateTabsForClientGUID(record.id, tabs: remotes) + + // Since tabs are all sent within a single record, we don't count number of tabs applied + // but number of records. In this case it's just one. + downloadStats.applied += 1 + ins.upon() { res in + if let inserted = res.successValue { + if inserted != remotes.count { + log.warning("Only inserted \(inserted) tabs, not \(remotes.count). Malformed or missing client?") + } + downloadStats.applied += 1 + } else { + downloadStats.failed += 1 + } + } + return ins + } + + let ourGUID = self.scratchpad.clientGUID + + let records = response.value + let responseTimestamp = response.metadata.lastModifiedMilliseconds + + log.debug("Got \(records.count) tab records.") + + // We can only insert tabs for clients that we know locally, so + // first we fetch the list of IDs and intersect the two. + // TODO: there's a much more efficient way of doing this. + return localTabs.getClientGUIDs() + >>== { clientGUIDs in + let filtered = records.filter({ $0.id != ourGUID && clientGUIDs.contains($0.id) }) + if filtered.count != records.count { + log.debug("Filtered \(records.count) records down to \(filtered.count).") + } + + let allDone = all(filtered.map(doInsert)) + return allDone.bind { (results) -> Success in + if let failure = results.find({ $0.isFailure }) { + return deferMaybe(failure.failureValue!) + } + + self.lastFetched = responseTimestamp! + return succeed() + } + } >>== effect({ self.statsSession.downloadStats }) + } + + // If this is a fresh start, do a wipe. + if self.lastFetched == 0 { + log.info("Last fetch was 0. Wiping tabs.") + return localTabs.wipeRemoteTabs() + >>== afterWipe + } + + return afterWipe() + } + + if let reason = self.reasonToNotSync(storageClient) { + return deferMaybe(SyncStatus.notStarted(reason)) + } + + let keys = self.scratchpad.keys?.value + let encoder = RecordEncoder(decode: { TabsPayload($0) }, encode: { $0.json }) + if let encrypter = keys?.encrypter(self.collection, encoder: encoder) { + let tabsClient = storageClient.clientForCollection(self.collection, encrypter: encrypter) + + statsSession.start() + + if !self.remoteHasChanges(info) { + // upload local tabs if they've changed or we're in a fresh start. + return uploadOurTabs(localTabs, toServer: tabsClient) + >>> { deferMaybe(self.completedWithStats) } + } + + return tabsClient.getSince(self.lastFetched) + >>== onResponseReceived + >>> { self.uploadOurTabs(localTabs, toServer: tabsClient) } + >>> { deferMaybe(self.completedWithStats) } + } + + log.error("Couldn't make tabs factory.") + return deferMaybe(FatalError(message: "Couldn't make tabs factory.")) + } + + /** + * This is a dedicated resetting interface that does both tabs and clients at the + * same time. + */ + open static func resetClientsAndTabsWithStorage(_ storage: ResettableSyncStorage, basePrefs: Prefs) -> Success { + let clientPrefs = BaseCollectionSynchronizer.prefsForCollection("clients", withBasePrefs: basePrefs) + let tabsPrefs = BaseCollectionSynchronizer.prefsForCollection("tabs", withBasePrefs: basePrefs) + clientPrefs.removeObjectForKey("lastFetched") + tabsPrefs.removeObjectForKey("lastFetched") + return storage.resetClient() + } +} + +extension RemoteTab { + public func toDictionary() -> Dictionary? { + let tabHistory = history.flatMap { $0.absoluteString } + if tabHistory.isEmpty { + return nil + } + return [ + "title": title, + "icon": icon?.absoluteString as Any? ?? NSNull(), + "urlHistory": tabHistory, + "lastUsed": millisecondsToDecimalSeconds(lastUsed) + ] + } +} diff --git a/mobile/ios/Sync/TabsPayload.swift b/mobile/ios/Sync/TabsPayload.swift new file mode 100644 index 0000000000..28e32b9602 --- /dev/null +++ b/mobile/ios/Sync/TabsPayload.swift @@ -0,0 +1,155 @@ +/* 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/. */ + +import Foundation +import Shared +import Storage +import XCGLogger +import SwiftyJSON + +// Int64.max / 1000. +private let MaxSecondsToConvertInt64: Int64 = 9223372036854775 +private let MaxSecondsToConvertDouble: Double = Double(9223372036854775 as Int64) + +private let log = Logger.browserLogger + +open class TabsPayload: CleartextPayloadJSON { + open class Tab { + let title: String + let urlHistory: [String] + let lastUsed: Timestamp + let icon: String? + + fileprivate init(title: String, urlHistory: [String], lastUsed: Timestamp, icon: String?) { + self.title = title + self.urlHistory = urlHistory + self.lastUsed = lastUsed + self.icon = icon + } + + func toRemoteTabForClient(_ guid: GUID) -> RemoteTab? { + let urls = urlHistory.flatMap({ $0.asURL }) + if urls.isEmpty { + log.debug("Bug 1201875 - Discarding tab as history has no conforming URLs.") + return nil + } + + return RemoteTab(clientGUID: guid, URL: urls[0], title: self.title, history: urls, lastUsed: self.lastUsed, icon: self.icon?.asURL) + } + + class func remoteTabFromJSON(_ json: JSON, clientGUID: GUID) -> RemoteTab? { + return fromJSON(json)?.toRemoteTabForClient(clientGUID) + } + + class func fromJSON(_ json: JSON) -> Tab? { + func getLastUsed(_ json: JSON) -> Timestamp? { + let lastUsed = json["lastUsed"] + if lastUsed.isBool() { + return nil + } + // This might be a string or a number. + if let num = lastUsed.int64 { + if num < 0 { + // Timestamps are unsigned. + return nil + } + if num > MaxSecondsToConvertInt64 { + // This will overflow when multiplied. + return nil + } + return Timestamp(num * 1000) + } + + if let num = lastUsed.double { + if num < 0 { + // Timestamps are unsigned. + return nil + } + if num > MaxSecondsToConvertDouble { + // This will overflow when multiplied. + return nil + } + return Timestamp(num * 1000) + } + + if let num = lastUsed.string { + // Try parsing. + return someKindOfTimestampStringToTimestamp(num) + } + + return nil + } + + if let title = json["title"].string, + let urlHistory = jsonsToStrings(json["urlHistory"].array), + let lastUsed = getLastUsed(json) { + return Tab(title: title, urlHistory: urlHistory, lastUsed: lastUsed, icon: json["icon"].string) + } + + return nil + } + } + + override open func isValid() -> Bool { + if !super.isValid() { + return false + } + + if self["deleted"].bool ?? false { + return true + } + + return self["clientName"].isString() && + self["tabs"].isArray() + } + + // Eventually it'd be nice to unify RemoteTab and Tab. We want to kill the GUID in RemoteTab, + // at which point the only distinction between the two is that RemoteTab is "simple" and + // lives in Storage, and Tab is more closely tied to TabsPayload. + + var remoteTabs: [RemoteTab] { + if let clientGUID = self["id"].string { + let payloadTabs = self["tabs"].arrayValue + let remoteTabs = payloadTabs.flatMap({ Tab.remoteTabFromJSON($0, clientGUID: clientGUID) }) + if payloadTabs.count != remoteTabs.count { + log.debug("Bug 1201875 - Missing remote tabs from sync") + } + return remoteTabs + } + log.debug("no client ID for remote tabs") + return [] + } + + var tabs: [Tab] { + return self["tabs"].arrayValue.flatMap(Tab.fromJSON) + } + + var clientName: String { + return self["clientName"].string! + } + + override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { + if !(obj is TabsPayload) { + return false + } + + if !super.equalPayloads(obj) { + return false + } + + let p = obj as! TabsPayload + if p.clientName != self.clientName { + return false + } + + // TODO: compare tabs. + /* + if p.tabs != self.tabs { + return false; + } + */ + + return true + } +} diff --git a/mobile/ios/SyncTelemetry/Info.plist b/mobile/ios/SyncTelemetry/Info.plist new file mode 100644 index 0000000000..4eb29b3ffd --- /dev/null +++ b/mobile/ios/SyncTelemetry/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 10.6 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/mobile/ios/SyncTelemetry/SyncPingCentre.swift b/mobile/ios/SyncTelemetry/SyncPingCentre.swift new file mode 100644 index 0000000000..89bc6c317e --- /dev/null +++ b/mobile/ios/SyncTelemetry/SyncPingCentre.swift @@ -0,0 +1,170 @@ +/* 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/. */ + +import Alamofire +import Shared +import JSONSchema +import Deferred + +// MARK: Ping Centre Client +public protocol PingCentreClient { + @discardableResult func sendPing(_ data: [String: Any], validate: Bool) -> Success + @discardableResult func sendBatch(_ data: [[String: Any]], validate: Bool) -> Success +} + +/* + * A Ping Centre Topic has a name and an associated JSON schema describing the ping data. + */ +public struct PingCentreTopic { + public let name: String + public let schema: Schema + public init(name: String, schema: Schema) { + self.name = name + self.schema = schema + } +} + +public struct PingCentre { + public static func clientForTopic(_ topic: PingCentreTopic, clientID: String) -> PingCentreClient { + guard !AppConstants.IsRunningTest else { + return DefaultPingCentreImpl(topic: topic, endpoint: .staging, clientID: clientID) + } + + switch AppConstants.BuildChannel { + case .developer: + return DefaultPingCentreImpl(topic: topic, endpoint: .staging, clientID: clientID) + case .beta: + fallthrough + case .release: + return DefaultPingCentreImpl(topic: topic, endpoint: .production, clientID: clientID) + } + } +} + +public struct PingValidationError: MaybeErrorType { + public let errors: [String] + public var description: String { + return "Ping JSON validation failed with the following errors: \(errors)" + } +} + +public struct PingJSONError: MaybeErrorType { + public let error: Error + public var description: String { + return "Failed to serialize JSON ping into NSData format -- \(error)" + } +} + +enum Endpoint { + case staging + case production + + var url: URL { + switch self { + case .staging: + return URL(string: "https://onyx_tiles.stage.mozaws.net/v3/links/ping-centre")! + case .production: + return URL(string: "https://tiles.services.mozilla.com/v3/links/ping-centre")! + } + } +} + +class DefaultPingCentreImpl: PingCentreClient { + fileprivate let topic: PingCentreTopic + fileprivate let clientID: String + fileprivate let endpoint: Endpoint + fileprivate let manager: SessionManager + + fileprivate let validationQueue: DispatchQueue + fileprivate static let queueLabel = "org.mozilla.pingcentre.validationQueue" + + init(topic: PingCentreTopic, endpoint: Endpoint, clientID: String, + validationQueue: DispatchQueue = DispatchQueue(label: queueLabel), + manager: SessionManager = SessionManager()) { + self.topic = topic + self.clientID = clientID + self.endpoint = endpoint + self.manager = manager + self.validationQueue = validationQueue + } + + public func sendPing(_ data: [String: Any], validate: Bool) -> Success { + return (validate ? validatePayload(data, schema: topic.schema) : succeed()) + >>> { + do { + let request = try self.singleRequestFor(payload: data) + return self.send(request: request) + } catch let e { + return deferMaybe(PingJSONError(error: e)) + } + } + } + + public func sendBatch(_ data: [[String: Any]], validate: Bool) -> Success { + // Ignore call if we don't have anything to send! + guard !data.isEmpty else { + return succeed() + } + + // Walk through all the pings if we need to validate + return (validate ? walk(data) { self.validatePayload($0, schema: self.topic.schema) } : succeed()) + >>> { + do { + let request = try self.batchRequestFor(payloads: data) + return self.send(request: request) + } catch let e { + return deferMaybe(PingJSONError(error: e)) + } + } + } + + fileprivate func singleRequestFor(payload: [String: Any]) throws -> URLRequest { + var request = URLRequest(url: endpoint.url) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + var root = payload + root["topic"] = topic.name + root["client_id"] = clientID + request.httpBody = try JSONSerialization.data(withJSONObject: root, options: []) + return request + } + + fileprivate func batchRequestFor(payloads: [[String: Any]]) throws -> URLRequest { + var request = URLRequest(url: endpoint.url) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + let root: [String: Any] = [ + "topic": self.topic.name, + "batch-mode": true, + "payloads": payloads + ] + request.httpBody = try JSONSerialization.data(withJSONObject: root, options: []) + return request + } + + fileprivate func send(request: URLRequest) -> Success { + let deferred = Deferred>() + self.manager.request(request as URLRequestConvertible) + .validate(statusCode: 200..<300) + .response(queue: DispatchQueue.global()) { (response) in + if let e = response.error { + NSLog("Failed to send ping to ping centre -- topic: \(self.topic.name), error: \(e)") + deferred.fill(Maybe(failure: e as MaybeErrorType)) + return + } + deferred.fill(Maybe(success: ())) + } + return deferred + } + + fileprivate func validatePayload(_ payload: [String: Any], schema: Schema) -> Success { + return deferDispatchAsync(validationQueue) { + let errors = schema.validate(payload).errors ?? [] + guard errors.isEmpty else { + return deferMaybe(PingValidationError(errors: errors)) + } + return succeed() + } + } +} diff --git a/mobile/ios/SyncTelemetry/SyncTelemetry.h b/mobile/ios/SyncTelemetry/SyncTelemetry.h new file mode 100644 index 0000000000..b63450760a --- /dev/null +++ b/mobile/ios/SyncTelemetry/SyncTelemetry.h @@ -0,0 +1,15 @@ +/* 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/. */ + +#import + +//! Project version number for SyncTelemetry. +FOUNDATION_EXPORT double TelemetryVersionNumber; + +//! Project version string for SyncTelemetry. +FOUNDATION_EXPORT const unsigned char TelemetryVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/mobile/ios/SyncTelemetry/SyncTelemetry.swift b/mobile/ios/SyncTelemetry/SyncTelemetry.swift new file mode 100644 index 0000000000..89c04eceaa --- /dev/null +++ b/mobile/ios/SyncTelemetry/SyncTelemetry.swift @@ -0,0 +1,120 @@ +/* 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/. */ + +import Alamofire +import Foundation +import XCGLogger +import SwiftyJSON +import Shared + +private let log = Logger.browserLogger +private let ServerURL = "https://incoming.telemetry.mozilla.org".asURL! +private let AppName = "Fennec" + +public enum TelemetryDocType: String { + case core = "core" + case sync = "sync" +} + +public protocol SyncTelemetryEvent { + func record(_ prefs: Prefs) +} + +open class SyncTelemetry { + private static var prefs: Prefs? + private static var telemetryVersion: Int = 4 + + open class func initWithPrefs(_ prefs: Prefs) { + assert(self.prefs == nil, "Prefs already initialized") + self.prefs = prefs + } + + open class func recordEvent(_ event: SyncTelemetryEvent) { + guard let prefs = prefs else { + assertionFailure("Prefs not initialized") + return + } + + event.record(prefs) + } + + open class func send(ping: SyncTelemetryPing, docType: TelemetryDocType) { + let docID = UUID().uuidString + let appVersion = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String + let buildID = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as! String + + let channel = AppConstants.BuildChannel.rawValue + let path = "/submit/telemetry/\(docID)/\(docType.rawValue)/\(AppName)/\(appVersion)/\(channel)/\(buildID)" + let url = ServerURL.appendingPathComponent(path) + var request = URLRequest(url: url) + + log.debug("Ping URL: \(url)") + log.debug("Ping payload: \(ping.payload.stringValue() ?? "")") + + // Don't add the common ping format for the mobile core ping. + let pingString: String? + if docType != .core { + var json = JSON(commonPingFormat(forType: docType)) + json["payload"] = ping.payload + pingString = json.stringValue() + } else { + pingString = ping.payload.stringValue() + } + + guard let body = pingString?.data(using: String.Encoding.utf8) else { + log.error("Invalid data!") + assertionFailure() + return + } + + guard channel != "default" else { + log.debug("Non-release build; not sending ping") + return + } + + request.httpMethod = "POST" + request.httpBody = body + request.addValue(Date().toRFC822String(), forHTTPHeaderField: "Date") + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + SessionManager.default.request(request).response { response in + log.debug("Ping response: \(response.response?.statusCode ?? -1).") + } + } + + private static func commonPingFormat(forType type: TelemetryDocType) -> [String: Any] { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd" + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + let date = formatter.string(from: NSDate() as Date) + let displayVersion = [ + AppInfo.appVersion, + "b", + AppInfo.buildNumber + ].joined() + let version = ProcessInfo.processInfo.operatingSystemVersion + let osVersion = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" + + return [ + "type": type.rawValue, + "id": UUID().uuidString, + "creationDate": date, + "version": SyncTelemetry.telemetryVersion, + "application": [ + "architecture": "arm", + "buildId": AppInfo.buildNumber, + "name": AppInfo.displayName, + "version": AppInfo.appVersion, + "displayVersion": displayVersion, + "platformVersion": osVersion, + "channel": AppConstants.BuildChannel.rawValue + ] + ] + } +} + +public protocol SyncTelemetryPing { + var payload: JSON { get } +} diff --git a/mobile/ios/SyncTelemetry/SyncTelemetryEvents.swift b/mobile/ios/SyncTelemetry/SyncTelemetryEvents.swift new file mode 100644 index 0000000000..7aac85ce6a --- /dev/null +++ b/mobile/ios/SyncTelemetry/SyncTelemetryEvents.swift @@ -0,0 +1,98 @@ +/* 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/. */ + +import Shared +import SwiftyJSON + +private let log = Logger.browserLogger + +public typealias IdentifierString = String +public extension IdentifierString { + func validate() -> Bool { + // Regex located here: http://gecko.readthedocs.io/en/latest/toolkit/components/telemetry/telemetry/collection/events.html#limits + let regex = try! NSRegularExpression(pattern: "^[a-zA-Z][a-zA-Z0-9_.]*[a-zA-Z0-9]$", options: []) + return regex.matches(in: self, options: [], range: NSRange(location: 0, length: self.characters.count)).count > 0 + } +} + +// Telemetry Events +// Documentation: http://gecko.readthedocs.io/en/latest/toolkit/components/telemetry/telemetry/collection/events.html#events +public struct Event { + let timestamp: Timestamp + let category: IdentifierString + let method: IdentifierString + let object: IdentifierString + let value: String? + let extra: [String: String]? + + public init(category: IdentifierString, + method: IdentifierString, + object: IdentifierString, + value: String? = nil, + extra: [String: String]? = nil) { + + self.init(timestamp: .uptimeInMilliseconds(), + category: category, + method: method, + object: object, + value: value, + extra: extra) + } + + init(timestamp: Timestamp, + category: IdentifierString, + method: IdentifierString, + object: IdentifierString, + value: String? = nil, + extra: [String: String]? = nil) { + self.timestamp = timestamp + self.category = category + self.method = method + self.object = object + self.value = value + self.extra = extra + } + + public func validate() -> Bool { + let results = [category, method, object].map { $0.validate() } + // Fold down the results into false if any of the results is false. + return results.reduce(true) { $0 ? $1 :$0 } + } + + public func pickle() -> Data? { + do { + return try JSONSerialization.data(withJSONObject: toArray(), options: []) + } catch let error { + log.error("Error pickling telemetry event. Error: \(error), Event: \(self)") + return nil + } + } + + public static func unpickle(_ data: Data) -> Event? { + do { + let array = try JSONSerialization.jsonObject(with: data, options: []) as! [Any] + return Event( + timestamp: Timestamp(array[0] as! UInt64), + category: array[1] as! String, + method: array[2] as! String, + object: array[3] as! String, + value: array[4] as? String, + extra: array[5] as? [String: String] + ) + } catch let error { + log.error("Error unpickling telemetry event: \(error)") + return nil + } + } + + public func toArray() -> [Any] { + return [timestamp, category, method, object, value ?? NSNull(), extra ?? NSNull()] + } +} + +extension Event: CustomDebugStringConvertible { + public var debugDescription: String { + return toArray().description + } +} diff --git a/mobile/ios/SyncTelemetryTests/EventTests.swift b/mobile/ios/SyncTelemetryTests/EventTests.swift new file mode 100644 index 0000000000..ff95fec287 --- /dev/null +++ b/mobile/ios/SyncTelemetryTests/EventTests.swift @@ -0,0 +1,102 @@ +/* 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/. */ + +import Foundation +import XCTest +import Shared +@testable import SyncTelemetry + +class EventTests: XCTestCase { + func testPickling() { + let mockTimestamp = Date.now() + XCTAssertEqual(String(data: basicEvent(timestamp: mockTimestamp).pickle()!, encoding: .utf8), + basicEventString(timestamp: mockTimestamp)) + XCTAssertEqual(String(data: basicWithValueEvent(timestamp: mockTimestamp).pickle()!, encoding: .utf8), + basicWithValueString(timestamp: mockTimestamp)) + XCTAssertEqual(String(data: extraEvent(timestamp: mockTimestamp).pickle()!, encoding: .utf8), + extraEventString(timestamp: mockTimestamp)) + } + + func testUnpickling() { + let mockTimestamp = Date.now() + let dataA = basicEventString(timestamp: mockTimestamp).data(using: .utf8)! + XCTAssertEqual(Event.unpickle(dataA), basicEvent(timestamp: mockTimestamp)) + + let dataB = basicWithValueString(timestamp: mockTimestamp).data(using: .utf8)! + XCTAssertEqual(Event.unpickle(dataB), basicWithValueEvent(timestamp: mockTimestamp)) + + let dataC = extraEventString(timestamp: mockTimestamp).data(using: .utf8)! + XCTAssertEqual(Event.unpickle(dataC), extraEvent(timestamp: mockTimestamp)) + } + + func testIdentifierStringValidation() { + let identifierA: IdentifierString = "basic" + XCTAssertTrue(identifierA.validate()) + + let identifierB: IdentifierString = "complex1234_more1234" + XCTAssertTrue(identifierB.validate()) + + let identifierC: IdentifierString = "invalid#!" + XCTAssertFalse(identifierC.validate()) + + let identifierD: IdentifierString = "almost_valid." + XCTAssertFalse(identifierD.validate()) + } + + func testEventValidation() { + let mockTimestamp = Date.now() + let eventA = basicEvent(timestamp: mockTimestamp) + XCTAssertTrue(eventA.validate()) + + let eventB = extraEvent(timestamp: mockTimestamp) + XCTAssertTrue(eventB.validate()) + + let eventC = Event(category: "invalid__", method: "valid", object: "valid") + XCTAssertFalse(eventC.validate()) + + let eventD = Event(category: "valid", method: "invalid__", object: "valid") + XCTAssertFalse(eventD.validate()) + } +} + +// Builder methods for easier mocking of the pickled/unpickled events +extension EventTests { + fileprivate func basicEventString(timestamp: Timestamp) -> String { + return "[\(timestamp),\"test\",\"pickling\",\"this\",null,null]" + } + + fileprivate func basicWithValueString(timestamp: Timestamp) -> String { + return "[\(timestamp),\"test\",\"pickling\",\"this\",\"value\",null]" + } + + fileprivate func extraEventString(timestamp: Timestamp) -> String { + return "[\(timestamp),\"test\",\"pickling\",\"this\",\"value\",{\"flowID\":\"testFlowID\",\"numIDs\":\"12\"}]" + } + + fileprivate func basicEvent(timestamp: Timestamp) -> Event { + return Event(timestamp: timestamp, category: "test", method: "pickling", object: "this") + } + + fileprivate func basicWithValueEvent(timestamp: Timestamp) -> Event { + return Event(timestamp: timestamp, category: "test", method: "pickling", object: "this", value: "value") + } + + fileprivate func extraEvent(timestamp: Timestamp) -> Event { + let extra = ["flowID": "testFlowID", "numIDs": "12"] + return Event(timestamp: timestamp, category: "test", method: "pickling", object: "this", value: "value", extra: extra) + } +} + +// Don't have a need for this in the app but is great for testing! +extension Event: Equatable { + public static func ==(left: Event, right: Event) -> Bool { + let propsAreEqual = (left.category == right.category) && + (left.method == right.method) && + (left.object == right.object) && + (left.value ?? "" == right.value ?? "") && + (left.extra ?? [:] == right.extra ?? [:]) + return propsAreEqual + } +} + diff --git a/mobile/ios/SyncTelemetryTests/Info.plist b/mobile/ios/SyncTelemetryTests/Info.plist new file mode 100644 index 0000000000..6366f45b20 --- /dev/null +++ b/mobile/ios/SyncTelemetryTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleVersion + 1 + + diff --git a/mobile/ios/SyncTests/BatchingClientTests.swift b/mobile/ios/SyncTests/BatchingClientTests.swift new file mode 100644 index 0000000000..d7f1b19733 --- /dev/null +++ b/mobile/ios/SyncTests/BatchingClientTests.swift @@ -0,0 +1,608 @@ +/* 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/. */ + +import Foundation +import Shared +import Deferred +@testable import Sync + +import XCTest +import SwiftyJSON + +// Always return a gigantic encoded payload. +private func massivify(_ record: Record) -> JSON? { + return JSON([ + "id": record.id, + "foo": String(repeating: "X", count: Sync15StorageClient.maxRecordSizeBytes + 1) + ]) +} + +private func basicSerializer(record: Record) -> String { + return JSON(object: [ + "id": record.id, + "payload": record.payload.json.dictionaryObject as Any + ]).stringValue()! +} + +// Create a basic record with an ID and a title that is the `Site$ID`. +private func createRecordWithID(id: String) -> Record { + let jsonString = "{\"id\":\"\(id)\",\"title\": \"\(id)\"}" + return Record(id: id, + payload: CleartextPayloadJSON(JSON(parseJSON: jsonString)), + modified: 10_000, + sortindex: 123, + ttl: 1_000_000) +} + +private func assertLinesMatchRecords(lines: [String], records: [Record], serializer: (Record) -> String) { + guard lines.count == records.count else { + XCTFail("Number of lines mismatch number of records") + return + } + + lines.enumerated().forEach { index, line in + let record = records[index] + XCTAssertEqual(line, serializer(record)) + } +} + +private func deferEmptyResponse(token batchToken: BatchToken? = nil, lastModified: Timestamp? = nil) -> Deferred>> { + var headers = [String: Any]() + if let lastModified = lastModified { + headers["X-Last-Modified"] = lastModified + } + + return deferMaybe( + StorageResponse(value: POSTResult(success: [], failed: [:], batchToken: batchToken), metadata: ResponseMetadata(status: 200, headers: headers)) + ) +} + +// Small helper operator for comparing query parameters below +private func ==(param1: NSURLQueryItem, param2: NSURLQueryItem) -> Bool { + return param1.name == param2.name && param1.value == param2.value +} + +private let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 2, maxPostBytes: 1_048_576, maxTotalRecords: 10, maxTotalBytes: 104_857_600) + +class Sync15BatchClientTests: XCTestCase { + + func testAddLargeRecordFails() { + let uploader: BatchUploadFunction = { _ in deferEmptyResponse(lastModified: 10_000) } + let serializeRecord = { massivify($0)?.stringValue() } + + let batch = Sync15BatchClient(config: miniConfig, + ifUnmodifiedSince: nil, + serializeRecord: serializeRecord, + uploader: uploader, + onCollectionUploaded: { _ in deferMaybe(Date() as! MaybeErrorType)}) + + let record = createRecordWithID(id: "A") + let result = batch.addRecords([record]).value + XCTAssertTrue(result.isFailure) + XCTAssertTrue(result.failureValue! is RecordTooLargeError) + } + + func testFailToSerializeRecord() { + let uploader: BatchUploadFunction = { _ in deferEmptyResponse(lastModified: 10_000) } + let batch = Sync15BatchClient(config: miniConfig, + ifUnmodifiedSince: nil, + serializeRecord: { _ in nil }, + uploader: uploader, + onCollectionUploaded: { _ in deferMaybe(Date.now())}) + + let record = createRecordWithID(id: "A") + let result = batch.addRecords([record]).value + XCTAssertTrue(result.isFailure) + XCTAssertTrue(result.failureValue! is SerializeRecordFailure) + } + + func testBackoffDuringBatchUploading() { + let uploader: BatchUploadFunction = { lines, ius, queryParams in + deferMaybe(ServerInBackoffError(until: 10_000)) + } + + // Setup a configuration so each batch supports two payloads of two records each + let twoRecordBatchesConfig = InfoConfiguration( + maxRequestBytes: 1_048_576, + maxPostRecords: 1, + maxPostBytes: 1_048_576, + maxTotalRecords: 4, + maxTotalBytes: 104_857_600 + ) + + let batch = Sync15BatchClient(config: twoRecordBatchesConfig, + ifUnmodifiedSince: 10_000, + serializeRecord: basicSerializer, + uploader: uploader, + onCollectionUploaded: { _ in deferMaybe(Date.now())}) + + let record = createRecordWithID(id: "A") + batch.addRecords([record]).succeeded() + let result = batch.endBatch().value + + // Verify that when the server goes into backoff, we get those bubbled up through the batching client + XCTAssertTrue(result.isFailure) + XCTAssertTrue(result.failureValue! is ServerInBackoffError) + } + + func testIfUnmodifiedSinceUpdatesForSinglePOSTs() { + var requestCount = 0 + var linesSent = [String]() + var lastIUS: Timestamp? = 0 + + // Since we never return a batch token, the batch client won't batch upload and default to single POSTs + let uploader: BatchUploadFunction = { lines, ius, _ in + linesSent += lines + requestCount += 1 + switch requestCount { + case 1: + XCTAssertEqual(ius, 10_000_000) + return deferEmptyResponse(lastModified: 20_000) + case 2: + XCTAssertEqual(ius, 20_000_000) + return deferEmptyResponse(lastModified: 30_000) + case 3: + XCTAssertEqual(ius, 30_000_000) + lastIUS = ius + return deferEmptyResponse(lastModified: 30_000) + default: + XCTFail() + return deferEmptyResponse(lastModified: 0) + } + } + + let singleRecordConfig = InfoConfiguration( + maxRequestBytes: 1_048_576, + maxPostRecords: 1, + maxPostBytes: 1_048_576, + maxTotalRecords: 10, + maxTotalBytes: 104_857_600 + ) + + let batch = Sync15BatchClient(config: singleRecordConfig, + ifUnmodifiedSince: 10_000_000, + serializeRecord: basicSerializer, + uploader: uploader, + onCollectionUploaded: { _ in deferMaybe(Date.now())}) + + let recordA = createRecordWithID(id: "A") + let recordB = createRecordWithID(id: "B") + let recordC = createRecordWithID(id: "C") + let allRecords = [recordA, recordB, recordC] + + batch.addRecords([recordA, recordB, recordC]).succeeded() + batch.endBatch().succeeded() + + // Validate number of requests sent + XCTAssertEqual(requestCount, 3) + + // Validate contents sent to the server + assertLinesMatchRecords(lines: linesSent, records: allRecords, serializer: basicSerializer) + + // Validate the last IUS we got is the last request + XCTAssertEqual(lastIUS, 30_000_000) + } + + func testUploadBatchUnsupportedBatching() { + var requestCount = 0 + var uploadedCollectionCount = 0 + var linesSent = [String]() + + // Since we never return a batch token, the batch client won't batch upload and default to single POSTs + let uploader: BatchUploadFunction = { lines, ius, _ in + linesSent += lines + requestCount += 1 + return deferEmptyResponse(lastModified: 10_000) + } + + let collectionUploaded: (POSTResult, Timestamp?) -> DeferredTimestamp = { _ in + uploadedCollectionCount += 1 + return deferMaybe(Date.now()) + } + + // Setup a configuration so we each payload would be one record + let twoRecordBatchesConfig = InfoConfiguration( + maxRequestBytes: 1_048_576, + maxPostRecords: 1, + maxPostBytes: 1_048_576, + maxTotalRecords: 10, + maxTotalBytes: 104_857_600 + ) + + let batch = Sync15BatchClient(config: twoRecordBatchesConfig, + ifUnmodifiedSince: 10_000, + serializeRecord: basicSerializer, + uploader: uploader, + onCollectionUploaded: collectionUploaded) + + let recordA = createRecordWithID(id: "A") + let recordB = createRecordWithID(id: "B") + let allRecords = [recordA, recordB] + + batch.addRecords([recordA, recordB]).succeeded() + batch.endBatch().succeeded() + + // Validate number of requests sent. One for the start post, and one for the committing + XCTAssertEqual(requestCount, 2) + + // Validate contents sent to the server + assertLinesMatchRecords(lines: linesSent, records: allRecords, serializer: basicSerializer) + + // Validate we only made 2 calls to collection uploaded since we're doing single POSTs + XCTAssertEqual(uploadedCollectionCount, 2) + } + + /** + Tests sending a batch consisting of 3 full payloads. This batch is regular in the sense that it should + contain a batch=true call, an upload within the batch, and finish with a commit=true upload. + */ + func testUploadRegularSingleBatch() { + var requestCount = 0 + var uploadedCollectionCount = 0 + var linesSent = [String]() + + let allRecords: [Record] = "ABCDEF".characters.reduce([]) { list, char in + return list + [createRecordWithID(id: String(char))] + } + + // Since we never return a batch token, the batch client won't batch upload and default to single POSTs + let uploader: BatchUploadFunction = { lines, ius, queryParams in + linesSent += lines + requestCount += 1 + switch requestCount { + case 1: + let expected = URLQueryItem(name: "batch", value: "true") + XCTAssertEqual(expected, queryParams![0]) + XCTAssertEqual(ius, 10_000) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[0..<2]), serializer: basicSerializer) + return deferEmptyResponse(token: "1", lastModified: 10_000) + case 2: + let expected = URLQueryItem(name: "batch", value: "1") + XCTAssertEqual(expected, queryParams![0]) + XCTAssertEqual(ius, 10_000_000) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[2..<4]), serializer: basicSerializer) + return deferEmptyResponse(token: "1", lastModified: 10_000) + case 3: + let expectedBatch = URLQueryItem(name: "batch", value: "1") + let expectedCommit = URLQueryItem(name: "commit", value: "true") + XCTAssertEqual(expectedBatch, queryParams![0]) + XCTAssertEqual(expectedCommit, queryParams![1]) + XCTAssertEqual(ius, 10_000_000) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[4..<6]), serializer: basicSerializer) + return deferEmptyResponse(lastModified: 20_000) + default: + XCTFail() + return deferEmptyResponse(lastModified: 0) + } + } + + let collectionUploaded: (POSTResult, Timestamp?) -> DeferredTimestamp = { _ in + uploadedCollectionCount += 1 + return deferMaybe(Date.now()) + } + + // Setup a configuration so we send 2 records per each payload + let twoRecordBatchesConfig = InfoConfiguration( + maxRequestBytes: 1_048_576, + maxPostRecords: 2, + maxPostBytes: 1_048_576, + maxTotalRecords: 10, + maxTotalBytes: 104_857_600 + ) + + let batch = Sync15BatchClient(config: twoRecordBatchesConfig, + ifUnmodifiedSince: 10_000, + serializeRecord: basicSerializer, + uploader: uploader, + onCollectionUploaded: collectionUploaded) + + batch.addRecords(allRecords).succeeded() + batch.endBatch().succeeded() + + // Validate number of requests sent. One for the start post, and one for the committing + XCTAssertEqual(requestCount, 3) + + // Validate contents sent to the server + assertLinesMatchRecords(lines: linesSent, records: allRecords, serializer: basicSerializer) + + // Validate we only made one call to the collection upload callback + XCTAssertEqual(uploadedCollectionCount, 2) + XCTAssertEqual(batch.ifUnmodifiedSince!, 20_000_000) + } + + /** + Tests pushing a batch where one of the payloads is not at limit. + */ + func testBatchUploadWithPartialPayload() { + var requestCount = 0 + var uploadedCollectionCount = 0 + var linesSent = [String]() + + let allRecords: [Record] = "ABC".characters.reduce([]) { list, char in + return list + [createRecordWithID(id: String(char))] + } + + // Since we never return a batch token, the batch client won't batch upload and default to single POSTs + let uploader: BatchUploadFunction = { lines, ius, queryParams in + linesSent += lines + requestCount += 1 + switch requestCount { + case 1: + let expected = URLQueryItem(name: "batch", value: "true") + XCTAssertEqual(expected, queryParams![0]) + XCTAssertEqual(ius, 10_000) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[0..<2]), serializer: basicSerializer) + return deferEmptyResponse(token: "1", lastModified: 10_000) + case 2: + let expectedBatch = URLQueryItem(name: "batch", value: "1") + let expectedCommit = URLQueryItem(name: "commit", value: "true") + XCTAssertEqual(expectedBatch, queryParams![0]) + XCTAssertEqual(expectedCommit, queryParams![1]) + XCTAssertEqual(ius, 10_000_000) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[2..<3]), serializer: basicSerializer) + return deferEmptyResponse(lastModified: 20_000) + default: + XCTFail() + return deferEmptyResponse(lastModified: 0) + } + } + + let collectionUploaded: (POSTResult, Timestamp?) -> DeferredTimestamp = { _ in + uploadedCollectionCount += 1 + return deferMaybe(Date.now()) + } + + // Setup a configuration so we send 2 records per each payload + let twoRecordBatchesConfig = InfoConfiguration( + maxRequestBytes: 1_048_576, + maxPostRecords: 2, + maxPostBytes: 1_048_576, + maxTotalRecords: 10, + maxTotalBytes: 104_857_600 + ) + + let batch = Sync15BatchClient(config: twoRecordBatchesConfig, + ifUnmodifiedSince: 10_000, + serializeRecord: basicSerializer, + uploader: uploader, + onCollectionUploaded: collectionUploaded) + + batch.addRecords(allRecords).succeeded() + batch.endBatch().succeeded() + + // Validate number of requests sent. One for the start post, and one for the committing + XCTAssertEqual(requestCount, 2) + + // Validate contents sent to the server + assertLinesMatchRecords(lines: linesSent, records: allRecords, serializer: basicSerializer) + + // Validate we only made one call to the collection upload callback + XCTAssertEqual(uploadedCollectionCount, 2) + XCTAssertEqual(batch.ifUnmodifiedSince!, 20_000_000) + } + + /** + Attempt to send 3 payloads: 2 which are full, 1 that is partial, within a batch that only supports 5 records. + */ + func testBatchUploadWithUnevenPayloadsInBatch() { + var requestCount = 0 + var uploadedCollectionCount = 0 + var linesSent = [String]() + + let allRecords: [Record] = "ABCDE".characters.reduce([]) { list, char in + return list + [createRecordWithID(id: String(char))] + } + + // Since we never return a batch token, the batch client won't batch upload and default to single POSTs + let uploader: BatchUploadFunction = { lines, ius, queryParams in + linesSent += lines + requestCount += 1 + switch requestCount { + case 1: + let expected = URLQueryItem(name: "batch", value: "true") + XCTAssertEqual(expected, queryParams![0]) + XCTAssertEqual(ius, 10_000) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[0..<2]), serializer: basicSerializer) + return deferEmptyResponse(token: "1", lastModified: 10_000) + case 2: + let expectedBatch = URLQueryItem(name: "batch", value: "1") + XCTAssertEqual(expectedBatch, queryParams![0]) + XCTAssertEqual(ius, 10_000_000) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[2..<4]), serializer: basicSerializer) + return deferEmptyResponse(lastModified: 10_000) + case 3: + let expectedBatch = URLQueryItem(name: "batch", value: "1") + let expectedCommit = URLQueryItem(name: "commit", value: "true") + XCTAssertEqual(expectedBatch, queryParams![0]) + XCTAssertEqual(expectedCommit, queryParams![1]) + XCTAssertEqual(ius, 10_000_000) + assertLinesMatchRecords(lines: lines, records: [allRecords[4]], serializer: basicSerializer) + return deferEmptyResponse(lastModified: 20_000) + default: + XCTFail() + return deferEmptyResponse(lastModified: 0) + } + } + + let collectionUploaded: (POSTResult, Timestamp?) -> DeferredTimestamp = { _ in + uploadedCollectionCount += 1 + return deferMaybe(Date.now()) + } + + // Setup a configuration so we send 2 records per each payload + let twoRecordBatchesConfig = InfoConfiguration( + maxRequestBytes: 1_048_576, + maxPostRecords: 2, + maxPostBytes: 1_048_576, + maxTotalRecords: 5, + maxTotalBytes: 104_857_600 + ) + + let batch = Sync15BatchClient(config: twoRecordBatchesConfig, + ifUnmodifiedSince: 10_000, + serializeRecord: basicSerializer, + uploader: uploader, + onCollectionUploaded: collectionUploaded) + + batch.addRecords(allRecords).succeeded() + batch.endBatch().succeeded() + + // Validate number of requests sent. One for the start post, and one for the committing + XCTAssertEqual(requestCount, 3) + + // Validate contents sent to the server + assertLinesMatchRecords(lines: linesSent, records: allRecords, serializer: basicSerializer) + + // Validate we only made one call to the collection upload callback + XCTAssertEqual(uploadedCollectionCount, 2) + XCTAssertEqual(batch.ifUnmodifiedSince!, 20_000_000) + } + + /** + Tests pushing up a single payload as part of a batch. + */ + func testBatchUploadWithSinglePayload() { + var requestCount = 0 + var uploadedCollectionCount = 0 + var linesSent = [String]() + + let recordA = createRecordWithID(id: "A") + + // Since we never return a batch token, the batch client won't batch upload and default to single POSTs + let uploader: BatchUploadFunction = { lines, ius, queryParams in + linesSent += lines + requestCount += 1 + switch requestCount { + case 1: + XCTAssertEqual(ius, 10_000) + assertLinesMatchRecords(lines: lines, records: [recordA], serializer: basicSerializer) + return deferEmptyResponse(lastModified: 20_000) + default: + XCTFail() + return deferEmptyResponse(lastModified: 0) + } + } + + let collectionUploaded: (POSTResult, Timestamp?) -> DeferredTimestamp = { _ in + uploadedCollectionCount += 1 + return deferMaybe(Date.now()) + } + + // Setup a configuration so we send 2 records per each payload + let twoRecordBatchesConfig = InfoConfiguration( + maxRequestBytes: 1_048_576, + maxPostRecords: 2, + maxPostBytes: 1_048_576, + maxTotalRecords: 10, + maxTotalBytes: 104_857_600 + ) + + let batch = Sync15BatchClient(config: twoRecordBatchesConfig, + ifUnmodifiedSince: 10_000, + serializeRecord: basicSerializer, + uploader: uploader, + onCollectionUploaded: collectionUploaded) + + batch.addRecords([recordA]).succeeded() + batch.endBatch().succeeded() + + // Validate number of requests sent. One for the start post, and one for the committing + XCTAssertEqual(requestCount, 1) + + // Validate contents sent to the server + assertLinesMatchRecords(lines: linesSent, records: [recordA], serializer: basicSerializer) + + // Validate we only made one call to the collection upload callback + XCTAssertEqual(uploadedCollectionCount, 1) + XCTAssertEqual(batch.ifUnmodifiedSince!, 20_000_000) + } + + func testMultipleBatchUpload() { + var requestCount = 0 + var uploadedCollectionCount = 0 + var linesSent = [String]() + + let allRecords: [Record] = "ABCDEFGHIJKL".characters.reduce([]) { list, char in + return list + [createRecordWithID(id: String(char))] + } + + // For each upload, verify that we are getting the correct queryParams and records to be sent. + let uploader: BatchUploadFunction = { lines, ius, queryParams in + linesSent += lines + requestCount += 1 + switch requestCount { + case 1: + let expected = URLQueryItem(name: "batch", value: "true") + XCTAssertEqual(expected, queryParams![0]) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[0..<2]), serializer: basicSerializer) + return deferEmptyResponse(token: "1", lastModified: 20_000) + case 2: + let expectedBatch = URLQueryItem(name: "batch", value: "1") + XCTAssertEqual(expectedBatch, queryParams![0]) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[2..<4]), serializer: basicSerializer) + return deferEmptyResponse(lastModified: 20_000) + case 3: + let expectedBatch = URLQueryItem(name: "batch", value: "1") + let expectedCommit = URLQueryItem(name: "commit", value: "true") + XCTAssertEqual(expectedBatch, queryParams![0]) + XCTAssertEqual(expectedCommit, queryParams![1]) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[4..<6]), serializer: basicSerializer) + return deferEmptyResponse(lastModified: 20_000) + case 4: + let expected = URLQueryItem(name: "batch", value: "true") + XCTAssertEqual(expected, queryParams![0]) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[6..<8]), serializer: basicSerializer) + return deferEmptyResponse(token: "2", lastModified: 30_000) + case 5: + let expectedBatch = URLQueryItem(name: "batch", value: "2") + XCTAssertEqual(expectedBatch, queryParams![0]) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[8..<10]), serializer: basicSerializer) + return deferEmptyResponse(lastModified: 30_000) + case 6: + let expectedBatch = URLQueryItem(name: "batch", value: "2") + let expectedCommit = URLQueryItem(name: "commit", value: "true") + XCTAssertEqual(expectedBatch, queryParams![0]) + XCTAssertEqual(expectedCommit, queryParams![1]) + assertLinesMatchRecords(lines: lines, records: Array(allRecords[10..<12]), serializer: basicSerializer) + return deferEmptyResponse(lastModified: 30_000) + default: + XCTFail() + return deferEmptyResponse(lastModified: 0) + } + } + + let collectionUploaded: (POSTResult, Timestamp?) -> DeferredTimestamp = { _ in + uploadedCollectionCount += 1 + return deferMaybe(Date.now()) + } + + // Setup a configuration so each batch supports two payloads of two records each + let twoRecordBatchesConfig = InfoConfiguration( + maxRequestBytes: 1_048_576, + maxPostRecords: 2, + maxPostBytes: 1_048_576, + maxTotalRecords: 6, + maxTotalBytes: 104_857_600 + ) + + let batch = Sync15BatchClient(config: twoRecordBatchesConfig, + ifUnmodifiedSince: 10_000_000, + serializeRecord: basicSerializer, + uploader: uploader, + onCollectionUploaded: collectionUploaded) + + batch.addRecords(allRecords).succeeded() + batch.endBatch().succeeded() + + // Validate number of requests sent. One for the start post, and one for the committing + XCTAssertEqual(requestCount, 6) + + // Validate contents sent to the server + assertLinesMatchRecords(lines: linesSent, records: allRecords, serializer: basicSerializer) + + // Validate we only called collection uploaded when we start and finish a batch. The uploads inside + // a batch should not trigger the callback. + XCTAssertEqual(uploadedCollectionCount, 4) + } +} diff --git a/mobile/ios/SyncTests/CryptoTests.swift b/mobile/ios/SyncTests/CryptoTests.swift new file mode 100644 index 0000000000..a1bd80662d --- /dev/null +++ b/mobile/ios/SyncTests/CryptoTests.swift @@ -0,0 +1,88 @@ +/* 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/. */ + +import UIKit +import Shared +import Storage +@testable import Sync + +import XCTest + +class CryptoTests: XCTestCase { + let hmacB16 = "b1e6c18ac30deb70236bc0d65a46f7a4dce3b8b0e02cf92182b914e3afa5eebc" + let ivB64 = "GX8L37AAb2FZJMzIoXlX8w==" + + let hmacKey = Bytes.decodeBase64("MMntEfutgLTc8FlTLQFms8/xMPmCldqPlq/QQXEjx70=")! + let encKey = Bytes.decodeBase64("9K/wLdXdw+nrTtXo4ZpECyHFNr4d7aYHqeg3KW9+m6Q=")! + + let invalidB64 = "NMsdnRulLwQsVcwxKW9XwaUe7ouJk5~~~~~~~~~~~~~~~" + + let ciphertextB64 = "NMsdnRulLwQsVcwxKW9XwaUe7ouJk5Wn80QhbD80l0HEcZGCynh45qIbeYBik0lgcHbKmlIxTJNwU+OeqipN+/j7MqhjKOGIlvbpiPQQLC6/ffF2vbzL0nzMUuSyvaQzyGGkSYM2xUFt06aNivoQTvU2GgGmUK6MvadoY38hhW2LCMkoZcNfgCqJ26lO1O0sEO6zHsk3IVz6vsKiJ2Hq6VCo7hu123wNegmujHWQSGyf8JeudZjKzfi0OFRRvvm4QAKyBWf0MgrW1F8SFDnVfkq8amCB7NhdwhgLWbN+21NitNwWYknoEWe1m6hmGZDgDT32uxzWxCV8QqqrpH/ZggViEr9uMgoy4lYaWqP7G5WKvvechc62aqnsNEYhH26A5QgzmlNyvB+KPFvPsYzxDnSCjOoRSLx7GG86wT59QZw=" + + let cleartextB64 = "eyJpZCI6IjVxUnNnWFdSSlpYciIsImhpc3RVcmkiOiJmaWxlOi8vL1VzZXJzL2phc29uL0xpYnJhcnkvQXBwbGljYXRpb24lMjBTdXBwb3J0L0ZpcmVmb3gvUHJvZmlsZXMva3NnZDd3cGsuTG9jYWxTeW5jU2VydmVyL3dlYXZlL2xvZ3MvIiwidGl0bGUiOiJJbmRleCBvZiBmaWxlOi8vL1VzZXJzL2phc29uL0xpYnJhcnkvQXBwbGljYXRpb24gU3VwcG9ydC9GaXJlZm94L1Byb2ZpbGVzL2tzZ2Q3d3BrLkxvY2FsU3luY1NlcnZlci93ZWF2ZS9sb2dzLyIsInZpc2l0cyI6W3siZGF0ZSI6MTMxOTE0OTAxMjM3MjQyNSwidHlwZSI6MX1dfQ==" + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testHMAC() { + let keyBundle = KeyBundle(encKey: encKey, hmacKey: hmacKey) + // HMAC is computed against the Base64 ciphertext. + let ciphertextRaw: Data = dataFromBase64(b64: ciphertextB64) + XCTAssertNotNil(ciphertextRaw) + XCTAssertEqual(hmacB16, keyBundle.hmacString(ciphertextRaw)) + } + + func dataFromBase64(b64: String) -> Data { + return Bytes.dataFromBase64(b64)! + } + + func testDecrypt() { + let keyBundle = KeyBundle(encKey: encKey, hmacKey: hmacKey) + // Decryption is done against raw bytes. + let ciphertext = Bytes.decodeBase64(ciphertextB64)! + let iv = Bytes.decodeBase64(ivB64)! + let s = keyBundle.decrypt(ciphertext, iv: iv) + let cleartext = NSString(data: Bytes.decodeBase64(cleartextB64)!, + encoding: String.Encoding.utf8.rawValue) + XCTAssertTrue(cleartext!.isEqual(to: s!)) + } + + func testBadBase64() { + XCTAssertNil(Bytes.decodeBase64(invalidB64)) + } + + func testEncrypt() { + let keyBundle = KeyBundle(encKey: encKey, hmacKey: hmacKey) + let cleartext = Bytes.decodeBase64(cleartextB64)! + + // With specified IV. + let iv = Bytes.decodeBase64(ivB64)! + if let (b, ivOut) = keyBundle.encrypt(cleartext, iv: iv) { + // The output IV should be the input. + XCTAssertEqual(ivOut, iv) + XCTAssertEqual(b, Bytes.decodeBase64(ciphertextB64)!) + } else { + XCTFail("Encrypt failed.") + } + + // With a random IV. + if let (b, ivOut) = keyBundle.encrypt(cleartext) { + // The output IV should be different. + // TODO: check that it's not empty! + XCTAssertNotEqual(ivOut, iv) + + // The result will not match the ciphertext for which a different IV was used. + XCTAssertNotEqual(b, Bytes.decodeBase64(ciphertextB64)!) + } else { + XCTFail("Encrypt failed.") + } + } +} diff --git a/mobile/ios/SyncTests/DownloadTests.swift b/mobile/ios/SyncTests/DownloadTests.swift new file mode 100644 index 0000000000..ce63abf116 --- /dev/null +++ b/mobile/ios/SyncTests/DownloadTests.swift @@ -0,0 +1,96 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Sync + +import XCTest +import SwiftyJSON + +func identity(x: T) -> T { + return x +} + +class DownloadTests: XCTestCase { + func loadEmptyBookmarksIntoServer(server: MockSyncServer) { + server.storeRecords(records: [], inCollection: "bookmarks") + } + + func testBasicDownload() { + let server = getServer(preStart: loadEmptyBookmarksIntoServer) + server.storeRecords(records: [], inCollection: "bookmarks") + + let storageClient = getClient(server: server) + let bookmarksClient = storageClient.clientForCollection("bookmarks", encrypter: getEncrypter()) + + let expectation = self.expectation(description: "Waiting for result.") + let deferred = bookmarksClient.getSince(0) + deferred >>== { response in + XCTAssertEqual(response.metadata.status, 200) + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testDownloadBatches() { + let guid1: GUID = "abcdefghijkl" + let ts1: Timestamp = 1326254123650 + let rec1 = MockSyncServer.makeValidEnvelope(guid: guid1, modified: ts1) + + let guid2: GUID = "bbcdefghijkl" + let ts2: Timestamp = 1326254125650 + let rec2 = MockSyncServer.makeValidEnvelope(guid: guid2, modified: ts2) + + let server = getServer(preStart: loadEmptyBookmarksIntoServer) + + server.storeRecords(records: [rec1], inCollection: "clients", now: ts1) + + let storageClient = getClient(server: server) + let bookmarksClient = storageClient.clientForCollection("clients", encrypter: getEncrypter()) + let prefs = MockProfilePrefs() + + let batcher = BatchingDownloader(collectionClient: bookmarksClient, basePrefs: prefs, collection: "clients") + + let ic1 = InfoCollections(collections: ["clients": ts1]) + let fetch1 = batcher.go(ic1, limit: 1).value + XCTAssertEqual(fetch1.successValue, DownloadEndState.complete) + XCTAssertEqual(0, batcher.baseTimestamp) // This isn't updated until after success. + let records1 = batcher.retrieve() + XCTAssertEqual(1, records1.count) + XCTAssertEqual(guid1, records1[0].id) + batcher.advance() + XCTAssertNotEqual(0, batcher.baseTimestamp) + + // Fetching again yields nothing, because the collection hasn't + // changed. + XCTAssertEqual(batcher.go(ic1, limit: 1).value.successValue, DownloadEndState.noNewData) + + // More records. Start again. + let _ = batcher.reset().value + + let ic2 = InfoCollections(collections: ["clients": ts2]) + server.storeRecords(records: [rec2], inCollection: "clients", now: ts2) + + let fetch2 = batcher.go(ic2, limit: 1).value + XCTAssertEqual(fetch2.successValue, DownloadEndState.incomplete) + let records2 = batcher.retrieve() + XCTAssertEqual(1, records2.count) + XCTAssertEqual(guid1, records2[0].id) + batcher.advance() + + let fetch3 = batcher.go(ic2, limit: 1).value + XCTAssertEqual(fetch3.successValue, DownloadEndState.complete) + let records3 = batcher.retrieve() + XCTAssertEqual(1, records3.count) + XCTAssertEqual(guid2, records3[0].id) + batcher.advance() + + let fetch4 = batcher.go(ic2, limit: 1).value + XCTAssertEqual(fetch4.successValue, DownloadEndState.noNewData) + let records4 = batcher.retrieve() + XCTAssertEqual(0, records4.count) + batcher.advance() + } +} diff --git a/mobile/ios/SyncTests/HistorySynchronizerTests.swift b/mobile/ios/SyncTests/HistorySynchronizerTests.swift new file mode 100644 index 0000000000..7fe55402e8 --- /dev/null +++ b/mobile/ios/SyncTests/HistorySynchronizerTests.swift @@ -0,0 +1,269 @@ +/* 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/. */ + +import Shared +import Storage +@testable import Sync +import XCGLogger +import Deferred + +import XCTest +import SwiftyJSON + +private let log = Logger.syncLogger + +class MockSyncDelegate: SyncDelegate { + func displaySentTab(for url: URL, title: String, from deviceName: String?) { + } +} + +class DBPlace: Place { + var isDeleted = false + var shouldUpload = false + var serverModified: Timestamp? + var localModified: Timestamp? +} + +class MockSyncableHistory { + var wasReset: Bool = false + var places = [GUID: DBPlace]() + var remoteVisits = [GUID: Set]() + var localVisits = [GUID: Set]() + + init() { + } + + fileprivate func placeForURL(url: String) -> DBPlace? { + return findOneValue(places) { $0.url == url } + } +} + +extension MockSyncableHistory: ResettableSyncStorage { + func resetClient() -> Success { + self.wasReset = true + return succeed() + } +} + +extension MockSyncableHistory: SyncableHistory { + // TODO: consider comparing the timestamp to local visits, perhaps opting to + // not delete the local place (and instead to give it a new GUID) if the visits + // are newer than the deletion. + // Obviously this'll behave badly during reconciling on other devices: + // they might apply our new record first, renaming their local copy of + // the old record with that URL, and thus bring all the old visits back to life. + // Desktop just finds by GUID then deletes by URL. + func deleteByGUID(_ guid: GUID, deletedAt: Timestamp) -> Deferred> { + self.remoteVisits.removeValue(forKey: guid) + self.localVisits.removeValue(forKey: guid) + self.places.removeValue(forKey: guid) + + return succeed() + } + + func hasSyncedHistory() -> Deferred> { + let has = self.places.values.contains(where: { $0.serverModified != nil }) + return deferMaybe(has) + } + + /** + * This assumes that the provided GUID doesn't already map to a different URL! + */ + func ensurePlaceWithURL(_ url: String, hasGUID guid: GUID) -> Success { + // Find by URL. + if let existing = self.placeForURL(url: url) { + let p = DBPlace(guid: guid, url: url, title: existing.title) + p.isDeleted = existing.isDeleted + p.serverModified = existing.serverModified + p.localModified = existing.localModified + self.places.removeValue(forKey: existing.guid) + self.places[guid] = p + } + + return succeed() + } + + func storeRemoteVisits(_ visits: [Visit], forGUID guid: GUID) -> Success { + // Strip out existing local visits. + // We trust that an identical timestamp and type implies an identical visit. + var remote = Set(visits) + if let local = self.localVisits[guid] { + remote.subtract(local) + } + + // Visits are only ever added. + if var r = self.remoteVisits[guid] { + r.formUnion(remote) + } else { + self.remoteVisits[guid] = remote + } + return succeed() + } + + func insertOrUpdatePlace(_ place: Place, modified: Timestamp) -> Deferred> { + // See if we've already applied this one. + if let existingModified = self.places[place.guid]?.serverModified { + if existingModified == modified { + log.debug("Already seen unchanged record \(place.guid).") + return deferMaybe(place.guid) + } + } + + // Make sure that we collide with any matching URLs -- whether locally + // modified or not. Then overwrite the upstream and merge any local changes. + return self.ensurePlaceWithURL(place.url, hasGUID: place.guid) + >>> { + if let existingLocal = self.places[place.guid] { + if existingLocal.shouldUpload { + log.debug("Record \(existingLocal.guid) modified locally and remotely.") + log.debug("Local modified: \(existingLocal.localModified ??? "nil"); remote: \(modified).") + + // Should always be a value if marked as changed. + if let localModified = existingLocal.localModified, localModified > modified { + // Nothing to do: it's marked as changed. + log.debug("Discarding remote non-visit changes!") + self.places[place.guid]?.serverModified = modified + return deferMaybe(place.guid) + } else { + log.debug("Discarding local non-visit changes!") + self.places[place.guid]?.shouldUpload = false + } + } else { + log.debug("Remote record exists, but has no local changes.") + } + } else { + log.debug("Remote record doesn't exist locally.") + } + + // Apply the new remote record. + let p = DBPlace(guid: place.guid, url: place.url, title: place.title) + p.localModified = Date.now() + p.serverModified = modified + p.isDeleted = false + self.places[place.guid] = p + return deferMaybe(place.guid) + } + } + + func getModifiedHistoryToUpload() -> Deferred> { + // TODO. + return deferMaybe([]) + } + + func getDeletedHistoryToUpload() -> Deferred> { + // TODO. + return deferMaybe([]) + } + + func markAsSynchronized(_: [GUID], modified: Timestamp) -> Deferred> { + // TODO + return deferMaybe(0) + } + + func markAsDeleted(_: [GUID]) -> Success { + // TODO + return succeed() + } + + func onRemovedAccount() -> Success { + // TODO + return succeed() + } + + func doneApplyingRecordsAfterDownload() -> Success { + return succeed() + } + + func doneUpdatingMetadataAfterUpload() -> Success { + return succeed() + } +} + +class HistorySynchronizerTests: XCTestCase { + private func applyRecords(records: [Record], toStorage storage: SyncableHistory & ResettableSyncStorage) -> (synchronizer: HistorySynchronizer, prefs: Prefs, scratchpad: Scratchpad) { + let delegate = MockSyncDelegate() + + // We can use these useless values because we're directly injecting decrypted + // payloads; no need for real keys etc. + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let synchronizer = HistorySynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + + let expectation = self.expectation(description: "Waiting for application.") + var succeeded = false + synchronizer.applyIncomingToStorage(storage, records: records) + .upon({ result in + succeeded = result.isSuccess + expectation.fulfill() + }) + + waitForExpectations(timeout: 10, handler: nil) + XCTAssertTrue(succeeded, "Application succeeded.") + return (synchronizer, prefs, scratchpad) + } + + func testRecordSerialization() { + let id = "abcdefghi" + let modified: Timestamp = 0 // Ignored in upload serialization. + let sortindex = 1 + let ttl = 12345 + let json: JSON = JSON([ + "id": id, + "visits": [], + "histUri": "http://www.slideshare.net/swadpasc/bpm-edu-netseminarscepwithreactionrulemlprova", + "title": "Semantic Complex Event Processing with \(Character(UnicodeScalar(11)))Reaction RuleML 1.0 and Prova", + ]) + let payload = HistoryPayload(json) + let record = Record(id: id, payload: payload, modified: modified, sortindex: sortindex, ttl: ttl) + let k = KeyBundle.random() + let s = k.serializer({ (x: HistoryPayload) -> JSON in x.json }) + let converter = { (x: JSON) -> HistoryPayload in HistoryPayload(x) } + let f = k.factory(converter) + let serialized = s(record)! + let envelope = EnvelopeJSON(serialized) + + // With a badly serialized payload, we get null JSON! + let p = f(envelope.payload) + XCTAssertFalse(p!.json.isNull()) + + // When we round-trip, the payload should be valid, and we'll get a record here. + let roundtripped = Record.fromEnvelope(envelope, payloadFactory: f) + XCTAssertNotNil(roundtripped) + } + + func testApplyRecords() { + let earliest = Date.now() + + let empty = MockSyncableHistory() + let noRecords = [Record]() + + // Apply no records. + let _ = self.applyRecords(records: noRecords, toStorage: empty) + + // Hey look! Nothing changed. + XCTAssertTrue(empty.places.isEmpty) + XCTAssertTrue(empty.remoteVisits.isEmpty) + XCTAssertTrue(empty.localVisits.isEmpty) + + // Apply one remote record. + let jA = "{\"id\":\"aaaaaa\",\"histUri\":\"http://foo.com/\",\"title\": \"ñ\",\"visits\":[{\"date\":1222222222222222,\"type\":1}]}" + let pA = HistoryPayload.fromJSON(JSON(parseJSON: jA))! + let rA = Record(id: "aaaaaa", payload: pA, modified: earliest + 10000, sortindex: 123, ttl: 1000000) + + let (_, prefs, _) = self.applyRecords(records: [rA], toStorage: empty) + + // The record was stored. This is checking our mock implementation, but real storage should work, too! + + XCTAssertEqual(1, empty.places.count) + XCTAssertEqual(1, empty.remoteVisits.count) + XCTAssertEqual(1, empty.remoteVisits["aaaaaa"]!.count) + XCTAssertTrue(empty.localVisits.isEmpty) + + // Test resetting now that we have a timestamp. + XCTAssertFalse(empty.wasReset) + XCTAssertTrue(HistorySynchronizer.resetSynchronizerWithStorage(empty, basePrefs: prefs, collection: "history").value.isSuccess) + XCTAssertTrue(empty.wasReset) + } +} diff --git a/mobile/ios/SyncTests/Info.plist b/mobile/ios/SyncTests/Info.plist new file mode 100644 index 0000000000..9411e4a06e --- /dev/null +++ b/mobile/ios/SyncTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/SyncTests/InfoTests.swift b/mobile/ios/SyncTests/InfoTests.swift new file mode 100644 index 0000000000..a8a390ceac --- /dev/null +++ b/mobile/ios/SyncTests/InfoTests.swift @@ -0,0 +1,56 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Sync + +import XCTest +import SwiftyJSON + +class InfoTests: XCTestCase { + func testSame() { + let empty = JSON(parseJSON: "{}") + + let oneA = JSON(parseJSON: "{\"foo\": 1234.0, \"bar\": 456.12}") + let oneB = JSON(parseJSON: "{\"bar\": 456.12, \"foo\": 1234.0}") + + let twoA = JSON(parseJSON: "{\"bar\": 456.12}") + let twoB = JSON(parseJSON: "{\"foo\": 1234.0}") + + let iEmpty = InfoCollections.fromJSON(empty)! + let iOneA = InfoCollections.fromJSON(oneA)! + let iOneB = InfoCollections.fromJSON(oneB)! + let iTwoA = InfoCollections.fromJSON(twoA)! + let iTwoB = InfoCollections.fromJSON(twoB)! + + XCTAssertTrue(iEmpty.same(iEmpty, collections: nil)) + XCTAssertTrue(iEmpty.same(iEmpty, collections: [])) + XCTAssertTrue(iEmpty.same(iEmpty, collections: ["anything"])) + + XCTAssertTrue(iEmpty.same(iOneA, collections: [])) + XCTAssertTrue(iEmpty.same(iOneA, collections: ["anything"])) + XCTAssertTrue(iOneA.same(iEmpty, collections: [])) + XCTAssertTrue(iOneA.same(iEmpty, collections: ["anything"])) + + XCTAssertFalse(iEmpty.same(iOneA, collections: ["foo"])) + XCTAssertFalse(iOneA.same(iEmpty, collections: ["foo"])) + XCTAssertFalse(iEmpty.same(iOneA, collections: nil)) + XCTAssertFalse(iOneA.same(iEmpty, collections: nil)) + + XCTAssertTrue(iOneA.same(iOneA, collections: nil)) + XCTAssertTrue(iOneA.same(iOneA, collections: ["foo", "bar", "baz"])) + XCTAssertTrue(iOneA.same(iOneB, collections: ["foo", "bar", "baz"])) + XCTAssertTrue(iOneB.same(iOneA, collections: ["foo", "bar", "baz"])) + + XCTAssertFalse(iTwoA.same(iOneA, collections: nil)) + XCTAssertTrue(iTwoA.same(iOneA, collections: ["bar", "baz"])) + XCTAssertTrue(iOneA.same(iTwoA, collections: ["bar", "baz"])) + XCTAssertTrue(iTwoB.same(iOneA, collections: ["foo", "baz"])) + + XCTAssertFalse(iTwoA.same(iTwoB, collections: nil)) + XCTAssertFalse(iTwoA.same(iTwoB, collections: ["foo"])) + XCTAssertFalse(iTwoA.same(iTwoB, collections: ["bar"])) + } +} diff --git a/mobile/ios/SyncTests/LiveStorageClientTests.swift b/mobile/ios/SyncTests/LiveStorageClientTests.swift new file mode 100644 index 0000000000..c4b16b6701 --- /dev/null +++ b/mobile/ios/SyncTests/LiveStorageClientTests.swift @@ -0,0 +1,131 @@ +/* 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/. */ + +import Account +import Foundation +import FxA +import Shared +import Deferred +@testable import Sync + +import XCTest +import SwiftyJSON + +private class KeyFetchError: MaybeErrorType { + var description: String { + return "key fetch error" + } +} + +class LiveStorageClientTests: LiveAccountTest { + func getKeys(kB: Data, token: TokenServerToken) -> Deferred>> { + let endpoint = token.api_endpoint + XCTAssertTrue(endpoint.range(of: "services.mozilla.com") != nil, "We got a Sync server.") + + let cryptoURI = URL(string: endpoint) + let authorizer: Authorizer = { + (r: URLRequest) -> URLRequest in + var request = r + let helper = HawkHelper(id: token.id, key: token.key.data(using: String.Encoding.utf8, allowLossyConversion: false)!) + request.addValue(helper.getAuthorizationValueFor(r), forHTTPHeaderField: "Authorization") + return request + } + + let keyBundle: KeyBundle = KeyBundle.fromKB(kB as Data) + let encoder = RecordEncoder(decode: { KeysPayload($0) }, encode: { $0.json }) + let encrypter = Keys(defaultBundle: keyBundle).encrypter("crypto", encoder: encoder) + + let workQueue = DispatchQueue.global(qos: DispatchQoS.default.qosClass) + let resultQueue = DispatchQueue.main + let backoff = MockBackoffStorage() + + let storageClient = Sync15StorageClient(serverURI: cryptoURI!, authorizer: authorizer, workQueue: workQueue, resultQueue: resultQueue, backoff: backoff) + let keysFetcher = storageClient.clientForCollection("crypto", encrypter: encrypter) + + return keysFetcher.get("keys").map({ res in + // Unwrap the response. + if let r = res.successValue { + return Maybe(success: r.value) + } + return Maybe(failure: KeyFetchError()) + }) + } + + func getState(user: String, password: String) -> Deferred> { + let err: NSError = NSError(domain: FxAClientErrorDomain, code: 0, userInfo: nil) + return Deferred(value: Maybe(failure: FxAClientError.local(err))) + } + + func getTokenAndDefaultKeys() -> Deferred> { + let authState = self.syncAuthState(Date.now()) + + let keysPayload: Deferred>> = authState.bind { tokenResult in + if let (token, forKey) = tokenResult.successValue { + return self.getKeys(kB: forKey, token: token) + } + XCTAssertEqual(tokenResult.failureValue!.description, "") + return Deferred(value: Maybe(failure: KeyFetchError())) + } + + let result = Deferred>() + keysPayload.upon { res in + if let rec = res.successValue { + XCTAssert(rec.id == "keys", "GUID is correct.") + XCTAssert(rec.modified > 1000, "modified is sane.") + let payload: KeysPayload = rec.payload as KeysPayload + print("Body: \(payload.json.stringValue() ?? "nil")", terminator: "\n") + XCTAssert(rec.id == "keys", "GUID inside is correct.") + if let keys = payload.defaultKeys { + // Extracting the token like this is not great, but... + result.fill(Maybe(success: (authState.value.successValue!.token, keys))) + return + } + } + + result.fill(Maybe(failure: KeyFetchError())) + } + return result + } + + func testLive() { + let expctn = expectation(description: "Waiting on value.") + let deferred = getTokenAndDefaultKeys() + deferred.upon { res in + if let (_, _) = res.successValue { + print("Yay", terminator: "\n") + } else { + XCTAssertEqual(res.failureValue!.description, "") + } + expctn.fulfill() + } + + // client: mgWl22CIzHiE + waitForExpectations(timeout: 20) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testStateMachine() { + let expctn = expectation(description: "Waiting on value.") + let authState = self.getAuthState(Date.now()) + + let d = chainDeferred(authState, f: { SyncStateMachine(prefs: MockProfilePrefs()).toReady($0) }) + + d.upon { result in + if let ready = result.successValue { + XCTAssertTrue(ready.collectionKeys.defaultBundle.encKey.count == 32) + XCTAssertTrue(ready.scratchpad.global != nil) + if let clients = ready.scratchpad.global?.value.engines["clients"] { + XCTAssertTrue(clients.syncID.characters.count == 12) + } + } + XCTAssertTrue(result.isSuccess) + expctn.fulfill() + } + + waitForExpectations(timeout: 20) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } +} diff --git a/mobile/ios/SyncTests/MetaGlobalTests.swift b/mobile/ios/SyncTests/MetaGlobalTests.swift new file mode 100644 index 0000000000..774ff4c34d --- /dev/null +++ b/mobile/ios/SyncTests/MetaGlobalTests.swift @@ -0,0 +1,624 @@ +/* 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/. */ + +@testable import Account +import Foundation +import Shared +import Storage +@testable import Sync +import XCGLogger +import Deferred + +import XCTest +import SwiftyJSON + +private let log = Logger.syncLogger + +class MockSyncAuthState: SyncAuthState { + + let serverRoot: String + let kB: Data + + var deviceID: String? { + return "mock_device_id" + } + + init(serverRoot: String, kB: Data) { + self.serverRoot = serverRoot + self.kB = kB + } + + func invalidate() { + } + + func token(_ now: Timestamp, canBeExpired: Bool) -> Deferred> { + let token = TokenServerToken(id: "id", key: "key", api_endpoint: serverRoot, uid: UInt64(0), hashedFxAUID: "", + durationInSeconds: UInt64(5 * 60), remoteTimestamp: Timestamp(now - 1)) + return deferMaybe((token, self.kB)) + } +} + +class MetaGlobalTests: XCTestCase { + var server: MockSyncServer! + var serverRoot: String! + var kB: Data! + var syncPrefs: Prefs! + var authState: SyncAuthState! + var stateMachine: SyncStateMachine! + + override func setUp() { + kB = Data.randomOfLength(32)! + server = MockSyncServer(username: "1234567") + server.start() + serverRoot = server.baseURL + syncPrefs = MockProfilePrefs() + authState = MockSyncAuthState(serverRoot: serverRoot, kB: kB) + stateMachine = SyncStateMachine(prefs: syncPrefs) + } + + func storeMetaGlobal(metaGlobal: MetaGlobal) { + let envelope = EnvelopeJSON(JSON(object: [ + "id": "global", + "collection": "meta", + "payload": metaGlobal.asPayload().json.stringValue()!, + "modified": Double(Date.now())/1000])) + server.storeRecords(records: [envelope], inCollection: "meta") + } + + func storeCryptoKeys(keys: Keys) { + let keyBundle = KeyBundle.fromKB(kB) + let record = Record(id: "keys", payload: keys.asPayload()) + let envelope = EnvelopeJSON(keyBundle.serializer({ $0.json })(record)!) + server.storeRecords(records: [envelope], inCollection: "crypto") + } + + func assertFreshStart(ready: Ready?, after: Timestamp) { + XCTAssertNotNil(ready) + guard let ready = ready else { + return + } + // We should have wiped. + // We should have uploaded new meta/global and crypto/keys. + XCTAssertGreaterThan(server.collections["meta"]?.records["global"]?.modified ?? 0, after) + XCTAssertGreaterThan(server.collections["meta"]?.modified ?? 0, after) + XCTAssertGreaterThan(server.collections["crypto"]?.records["keys"]?.modified ?? 0, after) + XCTAssertGreaterThan(server.collections["crypto"]?.modified ?? 0, after) + + // And we should have downloaded meta/global and crypto/keys. + XCTAssertNotNil(ready.scratchpad.global) + XCTAssertNotNil(ready.scratchpad.keys) + + // We should have the default engine configuration. + XCTAssertNotNil(ready.scratchpad.engineConfiguration) + guard let engineConfiguration = ready.scratchpad.engineConfiguration else { + return + } + XCTAssertEqual(engineConfiguration.enabled.sorted(), ["addons", "bookmarks", "clients", "forms", "history", "passwords", "prefs", "tabs"]) + XCTAssertEqual(engineConfiguration.declined, []) + + // Basic verifications. + XCTAssertEqual(ready.collectionKeys.defaultBundle.encKey.count, 32) + if let clients = ready.scratchpad.global?.value.engines["clients"] { + XCTAssertTrue(clients.syncID.characters.count == 12) + } + } + + func testMetaGlobalVersionTooNew() { + // There's no recovery from a meta/global version "in the future": just bail out with an UpgradeRequiredError. + storeMetaGlobal(metaGlobal: MetaGlobal(syncID: "id", storageVersion: 6, engines: [String: EngineMeta](), declined: [])) + + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "clientUpgradeRequired"]) + XCTAssertNotNil(result.failureValue as? ClientUpgradeRequiredError) + XCTAssertNil(result.successValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testMetaGlobalVersionTooOld() { + // To recover from a meta/global version "in the past", fresh start. + storeMetaGlobal(metaGlobal: MetaGlobal(syncID: "id", storageVersion: 4, engines: [String: EngineMeta](), declined: [])) + + let afterStores = Date.now() + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "remoteUpgradeRequired", + "freshStartRequired", "serverConfigurationRequired", "initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + self.assertFreshStart(ready: result.successValue, after: afterStores) + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testMetaGlobalMissing() { + // To recover from a missing meta/global, fresh start. + let afterStores = Date.now() + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "missingMetaGlobal", + "freshStartRequired", "serverConfigurationRequired", "initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + self.assertFreshStart(ready: result.successValue, after: afterStores) + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testCryptoKeysMissing() { + // To recover from a missing crypto/keys, fresh start. + storeMetaGlobal(metaGlobal: createMetaGlobal()) + + let afterStores = Date.now() + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "missingCryptoKeys", "freshStartRequired", "serverConfigurationRequired", "initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + self.assertFreshStart(ready: result.successValue, after: afterStores) + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testMetaGlobalAndCryptoKeysFresh() { + // When encountering a valid meta/global and crypto/keys, advance smoothly. + let metaGlobal = MetaGlobal(syncID: "id", storageVersion: 5, engines: [String: EngineMeta](), declined: []) + let cryptoKeys = Keys.random() + storeMetaGlobal(metaGlobal: metaGlobal) + storeCryptoKeys(keys: cryptoKeys) + + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + + // And we should have downloaded meta/global and crypto/keys. + XCTAssertEqual(ready.scratchpad.global?.value, metaGlobal) + XCTAssertEqual(ready.scratchpad.keys?.value, cryptoKeys) + + // We should have marked all local engines for reset. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), ["bookmarks", "clients", "history", "passwords", "tabs"]) + ready.clearLocalCommands() + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + + let afterFirstSync = Date.now() + + // Now, run through the state machine again. Nothing's changed remotely, so we should advance quickly. + let secondExpectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "hasMetaGlobal", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + // And we should have not downloaded a fresh meta/global or crypto/keys. + XCTAssertLessThan(ready.scratchpad.global?.timestamp ?? Timestamp.max, afterFirstSync) + XCTAssertLessThan(ready.scratchpad.keys?.timestamp ?? Timestamp.max, afterFirstSync) + + // We should not have marked any local engines for reset. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), []) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + secondExpectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testFailingOptimisticStateMachine() { + // We test only the optimistic state machine, knowing it will need to go through + // needsFreshMetaGlobal, and fail. + let metaGlobal = MetaGlobal(syncID: "id", storageVersion: 5, engines: [String: EngineMeta](), declined: []) + let cryptoKeys = Keys.random() + storeMetaGlobal(metaGlobal: metaGlobal) + storeCryptoKeys(keys: cryptoKeys) + + stateMachine = SyncStateMachine(prefs: syncPrefs, allowingStates: SyncStateMachine.OptimisticStates) + + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal"]) + XCTAssertNotNil(result.failureValue) + if let failure = result.failureValue as? DisallowedStateError { + XCTAssertEqual(failure.state, SyncStateLabel.NeedsFreshMetaGlobal) + } else { + XCTFail("SyncStatus failed, but with a different error") + } + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testHappyOptimisticStateMachine() { + // We should be able to quickly progress through a constrained (a.k.a. optimistic) state machine + let metaGlobal = MetaGlobal(syncID: "id", storageVersion: 5, engines: [String: EngineMeta](), declined: []) + let cryptoKeys = Keys.random() + storeMetaGlobal(metaGlobal: metaGlobal) + storeCryptoKeys(keys: cryptoKeys) + + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + + // Now, run through the state machine again. Nothing's changed remotely, so we should advance quickly. + // We should be able to use this 'optimistic' path in an extension. + stateMachine = SyncStateMachine(prefs: syncPrefs, allowingStates: SyncStateMachine.OptimisticStates) + + let secondExpectation = self.expectation(description: "Waiting on value.") + + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "hasMetaGlobal", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + secondExpectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testUpdatedCryptoKeys() { + // When encountering a valid meta/global and crypto/keys, advance smoothly. + let metaGlobal = MetaGlobal(syncID: "id", storageVersion: 5, engines: [String: EngineMeta](), declined: []) + let cryptoKeys = Keys.random() + cryptoKeys.collectionKeys.updateValue(KeyBundle.random(), forKey: "bookmarks") + cryptoKeys.collectionKeys.updateValue(KeyBundle.random(), forKey: "clients") + storeMetaGlobal(metaGlobal: metaGlobal) + storeCryptoKeys(keys: cryptoKeys) + + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + + // And we should have downloaded meta/global and crypto/keys. + XCTAssertEqual(ready.scratchpad.global?.value, metaGlobal) + XCTAssertEqual(ready.scratchpad.keys?.value, cryptoKeys) + + // We should have marked all local engines for reset. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), ["bookmarks", "clients", "history", "passwords", "tabs"]) + ready.clearLocalCommands() + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + + let afterFirstSync = Date.now() + + // Store a fresh crypto/keys, with the same default key, one identical collection key, and one changed collection key. + let freshCryptoKeys = Keys(defaultBundle: cryptoKeys.defaultBundle) + freshCryptoKeys.collectionKeys.updateValue(cryptoKeys.forCollection("bookmarks"), forKey: "bookmarks") + freshCryptoKeys.collectionKeys.updateValue(KeyBundle.random(), forKey: "clients") + storeCryptoKeys(keys: freshCryptoKeys) + + // Now, run through the state machine again. + let secondExpectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + // And we should have not downloaded a fresh meta/global ... + XCTAssertLessThan(ready.scratchpad.global?.timestamp ?? Timestamp.max, afterFirstSync) + // ... but we should have downloaded a fresh crypto/keys. + XCTAssertGreaterThanOrEqual(ready.scratchpad.keys?.timestamp ?? Timestamp.min, afterFirstSync) + + // We should have marked only the local engine with a changed key for reset. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), ["clients"]) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + secondExpectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + + let afterSecondSync = Date.now() + + // Store a fresh crypto/keys, with a changed default key and one identical collection key, and one changed collection key. + let freshCryptoKeys2 = Keys.random() + freshCryptoKeys2.collectionKeys.updateValue(freshCryptoKeys.forCollection("bookmarks"), forKey: "bookmarks") + freshCryptoKeys2.collectionKeys.updateValue(KeyBundle.random(), forKey: "clients") + storeCryptoKeys(keys: freshCryptoKeys2) + + // Now, run through the state machine again. + let thirdExpectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + // And we should have not downloaded a fresh meta/global ... + XCTAssertLessThan(ready.scratchpad.global?.timestamp ?? Timestamp.max, afterSecondSync) + // ... but we should have downloaded a fresh crypto/keys. + XCTAssertGreaterThanOrEqual(ready.scratchpad.keys?.timestamp ?? Timestamp.min, afterSecondSync) + + // We should have marked all local engines as needing reset, except for the engine whose key remained constant. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), ["clients", "history", "passwords", "tabs"]) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + thirdExpectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + + let afterThirdSync = Date.now() + + // Now store a random crypto/keys, with a different default key (and no bulk keys). + let randomCryptoKeys = Keys.random() + storeCryptoKeys(keys: randomCryptoKeys) + + // Now, run through the state machine again. + let fourthExpectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + // And we should have not downloaded a fresh meta/global ... + XCTAssertLessThan(ready.scratchpad.global?.timestamp ?? Timestamp.max, afterThirdSync) + // ... but we should have downloaded a fresh crypto/keys. + XCTAssertGreaterThanOrEqual(ready.scratchpad.keys?.timestamp ?? Timestamp.min, afterThirdSync) + + // We should have marked all local engines for reset. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), ["bookmarks", "clients", "history", "passwords", "tabs"]) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + fourthExpectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + private func createUnusualMetaGlobal() -> MetaGlobal { + let metaGlobal = MetaGlobal(syncID: "id", storageVersion: 5, + engines: ["bookmarks": EngineMeta(version: 1, syncID: "bookmarks"), "unknownEngine1": EngineMeta(version: 2, syncID: "engineId1")], + declined: ["clients", "forms", "unknownEngine2"]) + return metaGlobal + } + + func testEngineConfigurations() { + // When encountering a valid meta/global and crypto/keys, advance smoothly. Keep the engine configuration for re-upload. + let metaGlobal = createUnusualMetaGlobal() + let cryptoKeys = Keys.random() + storeMetaGlobal(metaGlobal: metaGlobal) + storeCryptoKeys(keys: cryptoKeys) + + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + + // We should have saved the engine configuration. + XCTAssertNotNil(ready.scratchpad.engineConfiguration) + guard let engineConfiguration = ready.scratchpad.engineConfiguration else { + return + } + XCTAssertEqual(engineConfiguration, metaGlobal.engineConfiguration()) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + + // Wipe meta/global. + server.removeAllItemsFromCollection(collection: "meta", atTime: Date.now()) + + // Now, run through the state machine again. We should produce and upload a meta/global reflecting our engine configuration. + let secondExpectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "missingMetaGlobal", "freshStartRequired", "serverConfigurationRequired", "initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + + // The downloaded meta/global should reflect our local engine configuration. + XCTAssertNotNil(ready.scratchpad.global) + guard let global = ready.scratchpad.global?.value else { + return + } + XCTAssertEqual(global.engineConfiguration(), metaGlobal.engineConfiguration()) + + // We should have the same cached engine configuration. + XCTAssertNotNil(ready.scratchpad.engineConfiguration) + guard let engineConfiguration = ready.scratchpad.engineConfiguration else { + return + } + XCTAssertEqual(engineConfiguration, metaGlobal.engineConfiguration()) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + secondExpectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } + + func testMetaGlobalModified() { + // When encountering a valid meta/global and crypto/keys, advance smoothly. + let metaGlobal = createUnusualMetaGlobal() + let cryptoKeys = Keys.random() + storeMetaGlobal(metaGlobal: metaGlobal) + storeCryptoKeys(keys: cryptoKeys) + + let expectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + + // And we should have downloaded meta/global and crypto/keys. + XCTAssertEqual(ready.scratchpad.global?.value, metaGlobal) + XCTAssertEqual(ready.scratchpad.keys?.value, cryptoKeys) + + // We should have marked all local engines for reset. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), ["bookmarks", "clients", "history", "passwords", "tabs"]) + XCTAssertEqual(ready.enginesEnabled(), []) + XCTAssertEqual(ready.enginesDisabled(), []) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + expectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + + let afterFirstSync = Date.now() + + // Store a meta/global with a new global syncID. + let newMetaGlobal = metaGlobal.withSyncID("newID") + storeMetaGlobal(metaGlobal: newMetaGlobal) + + // Now, run through the state machine again. + let secondExpectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "needsFreshCryptoKeys", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + // And we should have downloaded a fresh meta/global ... + XCTAssertGreaterThanOrEqual(ready.scratchpad.global?.timestamp ?? Timestamp.min, afterFirstSync) + // ... and we should have downloaded a fresh crypto/keys -- but its timestamp is identical to the old one! + // Therefore, the "needsFreshCryptoKeys" stage above is our test that we re-downloaded crypto/keys. + + // We should have marked all local engines for reset. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), ["bookmarks", "clients", "history", "passwords", "tabs"]) + + // And our engine configuration should be unchanged. + XCTAssertNotNil(ready.scratchpad.global) + guard let global = ready.scratchpad.global?.value else { + return + } + XCTAssertEqual(global.engineConfiguration(), metaGlobal.engineConfiguration()) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + secondExpectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + + // Now store a meta/global with a changed engine syncID, a new engine, and a new declined entry. + var engines = newMetaGlobal.engines + engines.updateValue(EngineMeta(version: 1, syncID: Bytes.generateGUID()), forKey: "bookmarks") + engines.updateValue(EngineMeta(version: 1, syncID: Bytes.generateGUID()), forKey: "forms") + engines.removeValue(forKey: "unknownEngine1") + var declined = newMetaGlobal.declined.filter({ $0 != "forms" }) + declined.append("unknownEngine1") + let secondMetaGlobal = MetaGlobal(syncID: newMetaGlobal.syncID, storageVersion: 5, engines: engines, declined: declined) + storeMetaGlobal(metaGlobal: secondMetaGlobal) + syncPrefs.removeObjectForKey("scratchpad.localCommands") + + // Now, run through the state machine again. + let thirdExpectation = self.expectation(description: "Waiting on value.") + stateMachine.toReady(authState).upon { result in + XCTAssertEqual(self.stateMachine.stateLabelSequence.map { $0.rawValue }, ["initialWithLiveToken", "initialWithLiveTokenAndInfo", "needsFreshMetaGlobal", "resolveMetaGlobalVersion", "resolveMetaGlobalContent", "hasMetaGlobal", "hasFreshCryptoKeys", "ready"]) + XCTAssertNotNil(result.successValue) + guard let ready = result.successValue else { + return + } + // And we should have downloaded a fresh meta/global ... + XCTAssertGreaterThanOrEqual(ready.scratchpad.global?.timestamp ?? Timestamp.min, afterFirstSync) + // ... and we should have downloaded a fresh crypto/keys -- but its timestamp is identical to the old one! + // Therefore, the "needsFreshCryptoKeys" stage above is our test that we re-downloaded crypto/keys. + + // We should have marked the changed engine for local reset, and identified the enabled and disabled engines. + XCTAssertEqual(ready.collectionsThatNeedLocalReset(), ["bookmarks"]) + XCTAssertEqual(ready.enginesEnabled(), ["forms"]) + XCTAssertEqual(ready.enginesDisabled(), ["unknownEngine1"]) + + // And our engine configuration should reflect the new meta/global on the server. + XCTAssertNotNil(ready.scratchpad.global) + guard let global = ready.scratchpad.global?.value else { + return + } + XCTAssertEqual(global.engineConfiguration(), secondMetaGlobal.engineConfiguration()) + + XCTAssertTrue(result.isSuccess) + XCTAssertNil(result.failureValue) + thirdExpectation.fulfill() + } + + waitForExpectations(timeout: 2000) { (error) in + XCTAssertNil(error, "Error: \(error ??? "nil")") + } + } +} diff --git a/mobile/ios/SyncTests/MockSyncServer.swift b/mobile/ios/SyncTests/MockSyncServer.swift new file mode 100644 index 0000000000..86ceaa29b5 --- /dev/null +++ b/mobile/ios/SyncTests/MockSyncServer.swift @@ -0,0 +1,453 @@ +/* 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/. */ + +import Foundation +import Shared +import GCDWebServers +import SwiftyJSON +@testable import Sync + +import XCTest + +private let log = Logger.syncLogger + +private func optTimestamp(x: AnyObject?) -> Timestamp? { + guard let str = x as? String else { + return nil + } + return decimalSecondsStringToTimestamp(str) +} + +private func optStringArray(x: AnyObject?) -> [String]? { + guard let str = x as? String else { + return nil + } + return str.components(separatedBy: ",").map { $0.trimmingCharacters(in:NSCharacterSet.whitespacesAndNewlines) } +} + +private struct SyncRequestSpec { + let collection: String + let id: String? + let ids: [String]? + let limit: Int? + let offset: String? + let sort: SortOption? + let newer: Timestamp? + let full: Bool + + static func fromRequest(request: GCDWebServerRequest) -> SyncRequestSpec? { + // Input is "/1.5/user/storage/collection", possibly with "/id" at the end. + // That means we get five or six path components here, the first being empty. + + let parts = request.path!.components(separatedBy: "/").filter { !$0.isEmpty } + let id: String? + let query = request.query as! [String: AnyObject] + let ids = optStringArray(x: query["ids"]) + let newer = optTimestamp(x: query["newer"]) + let full: Bool = query["full"] != nil + + let limit: Int? + if let lim = query["limit"] as? String { + limit = Int(lim) + } else { + limit = nil + } + + let offset = query["offset"] as? String + + let sort: SortOption? + switch query["sort"] as? String ?? "" { + case "oldest": + sort = SortOption.OldestFirst + case "newest": + sort = SortOption.NewestFirst + case "index": + sort = SortOption.Index + default: + sort = nil + } + + if parts.count < 4 { + return nil + } + + if parts[2] != "storage" { + return nil + } + + // Use dropFirst, you say! It's buggy. + switch parts.count { + case 4: + id = nil + case 5: + id = parts[4] + default: + // Uh oh. + return nil + } + return SyncRequestSpec(collection: parts[3], id: id, ids: ids, limit: limit, offset: offset, sort: sort, newer: newer, full: full) + } +} + +struct SyncDeleteRequestSpec { + let collection: String? + let id: GUID? + let ids: [GUID]? + let wholeCollection: Bool + + static func fromRequest(request: GCDWebServerRequest) -> SyncDeleteRequestSpec? { + // Input is "/1.5/user{/storage{/collection{/id}}}". + // That means we get four, five, or six path components here, the first being empty. + return SyncDeleteRequestSpec.fromPath(path: request.path!, withQuery: request.query as! [NSString : AnyObject]) + } + + static func fromPath(path: String, withQuery query: [NSString: AnyObject]) -> SyncDeleteRequestSpec? { + let parts = path.components(separatedBy: "/").filter { !$0.isEmpty } + let queryIDs: [GUID]? = (query["ids"] as? String)?.components(separatedBy: ",") + + guard [2, 4, 5].contains(parts.count) else { + return nil + } + + if parts.count == 2 { + return SyncDeleteRequestSpec(collection: nil, id: nil, ids: queryIDs, wholeCollection: true) + } + + if parts[2] != "storage" { + return nil + } + + if parts.count == 4 { + let hasIDs = queryIDs != nil + return SyncDeleteRequestSpec(collection: parts[3], id: nil, ids: queryIDs, wholeCollection: !hasIDs) + } + + return SyncDeleteRequestSpec(collection: parts[3], id: parts[4], ids: queryIDs, wholeCollection: false) + } +} + +private struct SyncPutRequestSpec { + let collection: String + let id: String + + static func fromRequest(request: GCDWebServerRequest) -> SyncPutRequestSpec? { + // Input is "/1.5/user/storage/collection/id}}}". + // That means we get six path components here, the first being empty. + + let parts = request.path!.components(separatedBy: "/").filter { !$0.isEmpty } + + guard parts.count == 5 else { + return nil + } + + if parts[2] != "storage" { + return nil + } + + return SyncPutRequestSpec(collection: parts[3], id: parts[4]) + } +} + +class MockSyncServer { + let server = GCDWebServer() + let username: String + + var offsets: Int = 0 + var continuations: [String: [EnvelopeJSON]] = [:] + var collections: [String: (modified: Timestamp, records: [String: EnvelopeJSON])] = [:] + var baseURL: String! + + init(username: String) { + self.username = username + } + + class func makeValidEnvelope(guid: GUID, modified: Timestamp) -> EnvelopeJSON { + let clientBody: [String: Any] = [ + "id": guid, + "name": "Foobar", + "commands": [], + "type": "mobile", + ] + let clientBodyString = JSON(object: clientBody).stringValue()! + let clientRecord: [String : Any] = [ + "id": guid, + "collection": "clients", + "payload": clientBodyString, + "modified": Double(modified) / 1000, + ] + return EnvelopeJSON(JSON(object: clientRecord).stringValue()!) + } + + class func withHeaders(response: GCDWebServerResponse, lastModified: Timestamp? = nil, records: Int? = nil, timestamp: Timestamp? = nil) -> GCDWebServerResponse { + let timestamp = timestamp ?? Date.now() + let xWeaveTimestamp = millisecondsToDecimalSeconds(timestamp) + response.setValue("\(xWeaveTimestamp)", forAdditionalHeader: "X-Weave-Timestamp") + + if let lastModified = lastModified { + let xLastModified = millisecondsToDecimalSeconds(lastModified) + response.setValue("\(xLastModified)", forAdditionalHeader: "X-Last-Modified") + } + + if let records = records { + response.setValue("\(records)", forAdditionalHeader: "X-Weave-Records") + } + + return response + } + + func storeRecords(records: [EnvelopeJSON], inCollection collection: String, now: Timestamp? = nil) { + let now = now ?? Date.now() + let coll = self.collections[collection] + var out = coll?.records ?? [:] + records.forEach { + out[$0.id] = $0.withModified(now) + } + let newModified = max(now, coll?.modified ?? 0) + self.collections[collection] = (modified: newModified, records: out) + } + + private func splitArray(items: [T], at: Int) -> ([T], [T]) { + return (Array(items.dropLast(items.count - at)), Array(items.dropFirst(at))) + } + + private func recordsMatchingSpec(spec: SyncRequestSpec) -> (records: [EnvelopeJSON], offsetID: String?)? { + // If we have a provided offset, handle that directly. + if let offset = spec.offset { + log.debug("Got provided offset \(offset).") + guard let remainder = self.continuations[offset] else { + log.error("Unknown offset.") + return nil + } + + // Remove the old one. + self.continuations.removeValue(forKey: offset) + + // Handle the smaller-than-limit or no-provided-limit cases. + guard let limit = spec.limit, limit < remainder.count else { + log.debug("Returning all remaining items.") + return (remainder, nil) + } + + // Record the next continuation and return the first slice of records. + let next = "\(self.offsets)" + self.offsets += 1 + let (returned, remaining) = splitArray(items: remainder, at: limit) + self.continuations[next] = remaining + log.debug("Returning \(limit) items; next continuation is \(next).") + return (returned, next) + } + + guard let records = self.collections[spec.collection]?.records.values else { + // No matching records. + return ([], nil) + } + + var items = Array(records) + log.debug("Got \(items.count) candidate records.") + + if spec.newer ?? 0 > 0 { + items = items.filter { $0.modified > spec.newer! } + } + + if let ids = spec.ids { + let ids = Set(ids) + items = items.filter { ids.contains($0.id) } + } + + if let sort = spec.sort { + switch sort { + case SortOption.NewestFirst: + items = items.sorted { $0.modified > $1.modified } + log.debug("Sorted items newest first: \(items.map { $0.modified })") + case SortOption.OldestFirst: + items = items.sorted { $0.modified < $1.modified } + log.debug("Sorted items oldest first: \(items.map { $0.modified })") + case SortOption.Index: + log.warning("Index sorting not yet supported.") + } + } + + if let limit = spec.limit, items.count > limit { + let next = "\(self.offsets)" + self.offsets += 1 + let (returned, remaining) = splitArray(items: items, at: limit) + self.continuations[next] = remaining + return (returned, next) + } + + return (items, nil) + } + + private func recordResponse(record: EnvelopeJSON) -> GCDWebServerResponse { + let body = record.asJSON().stringValue()! + let bodyData = body.utf8EncodedData + let response = GCDWebServerDataResponse(data: bodyData, contentType: "application/json") + return MockSyncServer.withHeaders(response: response!, lastModified: record.modified) + } + + private func modifiedResponse(timestamp: Timestamp) -> GCDWebServerResponse { + let body = JSON(object: ["modified": timestamp]).stringValue() + let bodyData = body?.utf8EncodedData + let response = GCDWebServerDataResponse(data: bodyData, contentType: "application/json")! + return MockSyncServer.withHeaders(response: response) + } + + func modifiedTimeForCollection(collection: String) -> Timestamp? { + return self.collections[collection]?.modified + } + + func removeAllItemsFromCollection(collection: String, atTime: Timestamp) { + if self.collections[collection] != nil { + self.collections[collection] = (atTime, [:]) + } + } + + func start() { + let basePath = "/1.5/\(self.username)" + let storagePath = "\(basePath)/storage/" + + let infoCollectionsPath = "\(basePath)/info/collections" + server?.addHandler(forMethod: "GET", path: infoCollectionsPath, request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + var ic = [String: Any]() + var lastModified: Timestamp = 0 + for collection in self.collections.keys { + if let timestamp = self.modifiedTimeForCollection(collection: collection) { + ic[collection] = Double(timestamp) / 1000 + lastModified = max(lastModified, timestamp) + } + + } + let body = JSON(object: ic).stringValue() + let bodyData = body?.utf8EncodedData + + let response = GCDWebServerDataResponse(data: bodyData, contentType: "application/json")! + return MockSyncServer.withHeaders(response: response, lastModified: lastModified, records: ic.count) + } + + let matchPut: GCDWebServerMatchBlock = { method, url, headers, path, query -> GCDWebServerRequest! in + guard method == "PUT", + path?.startsWith(basePath) ?? false else { + return nil + } + return GCDWebServerDataRequest(method: method, url: url, headers: headers, path: path, query: query) + } + + server?.addHandler(match: matchPut) { (request) -> GCDWebServerResponse! in + guard let request = request as? GCDWebServerDataRequest else { + return MockSyncServer.withHeaders(response: GCDWebServerDataResponse(statusCode: 400)) + } + + guard let spec = SyncPutRequestSpec.fromRequest(request: request) else { + return MockSyncServer.withHeaders(response: GCDWebServerDataResponse(statusCode: 400)) + } + var body = JSON(object: request.jsonObject) + body["modified"] = JSON(stringLiteral: millisecondsToDecimalSeconds(Date.now())) + let record = EnvelopeJSON(body) + + self.storeRecords(records: [record], inCollection: spec.collection) + let timestamp = self.modifiedTimeForCollection(collection: spec.collection)! + + let response = GCDWebServerDataResponse(data: millisecondsToDecimalSeconds(timestamp).utf8EncodedData, contentType: "application/json") + return MockSyncServer.withHeaders(response: response!) + } + + let matchDelete: GCDWebServerMatchBlock = { method, url, headers, path, query -> GCDWebServerRequest! in + guard method == "DELETE" && (path?.startsWith(basePath))! else { + return nil + } + return GCDWebServerRequest(method: method, url: url, headers: headers, path: path, query: query) + } + + server?.addHandler(match: matchDelete) { (request) -> GCDWebServerResponse! in + guard let spec = SyncDeleteRequestSpec.fromRequest(request: request!) else { + return GCDWebServerDataResponse(statusCode: 400) + } + + if let collection = spec.collection, let id = spec.id { + guard var items = self.collections[collection]?.records else { + // Unable to find the requested collection. + return MockSyncServer.withHeaders(response: GCDWebServerDataResponse(statusCode: 404)) + } + + guard let item = items[id] else { + // Unable to find the requested id. + return MockSyncServer.withHeaders(response: GCDWebServerDataResponse(statusCode: 404)) + } + items.removeValue(forKey: id) + return self.modifiedResponse(timestamp: item.modified) + } + + if let collection = spec.collection { + if spec.wholeCollection { + self.collections.removeValue(forKey: collection) + } else { + if let ids = spec.ids, + var map = self.collections[collection]?.records { + for id in ids { + map.removeValue(forKey: id) + } + self.collections[collection] = (Date.now(), records: map) + } + } + return self.modifiedResponse(timestamp: Date.now()) + } + + self.collections = [:] + return MockSyncServer.withHeaders(response: GCDWebServerDataResponse(data: "{}".utf8EncodedData, contentType: "application/json")) + } + + let match: GCDWebServerMatchBlock = { method, url, headers, path, query -> GCDWebServerRequest! in + guard method == "GET", path?.startsWith(storagePath) ?? false else { + return nil + } + return GCDWebServerRequest(method: method, url: url, headers: headers, path: path, query: query) + } + + server?.addHandler(match: match) { (request) -> GCDWebServerResponse! in + // 1. Decide what the URL is asking for. It might be a collection fetch or + // an individual record, and it might have query parameters. + + guard let spec = SyncRequestSpec.fromRequest(request: request!) else { + return MockSyncServer.withHeaders(response: GCDWebServerDataResponse(statusCode: 400)) + } + + // 2. Grab the matching set of records. Prune based on TTL, exclude with X-I-U-S, etc. + if let id = spec.id { + guard let collection = self.collections[spec.collection], let record = collection.records[id] else { + // Unable to find the requested collection/id. + return MockSyncServer.withHeaders(response: GCDWebServerDataResponse(statusCode: 404)) + } + + return self.recordResponse(record: record) + } + + guard let (items, offset) = self.recordsMatchingSpec(spec: spec) else { + // Unable to find the provided offset. + return MockSyncServer.withHeaders(response: GCDWebServerDataResponse(statusCode: 400)) + } + + // TODO: TTL + // TODO: X-I-U-S + + let body = JSON(object: items.map { $0.asJSON() }).stringValue() + let bodyData = body?.utf8EncodedData + let response = GCDWebServerDataResponse(data: bodyData, contentType: "application/json") + + // 3. Compute the correct set of headers: timestamps, X-Weave-Records, etc. + if let offset = offset { + response?.setValue(offset, forAdditionalHeader: "X-Weave-Next-Offset") + } + + let timestamp = self.modifiedTimeForCollection(collection: spec.collection)! + log.debug("Returning GET response with X-Last-Modified for \(items.count) records: \(timestamp).") + return MockSyncServer.withHeaders(response: response!, lastModified: timestamp, records: items.count) + } + + if server?.start(withPort: 0, bonjourName: nil) == false { + XCTFail("Can't start the GCDWebServer.") + } + + baseURL = "http://localhost:\(server!.port)\(basePath)" + } +} diff --git a/mobile/ios/SyncTests/MockSyncServerTests.swift b/mobile/ios/SyncTests/MockSyncServerTests.swift new file mode 100644 index 0000000000..83aca94ada --- /dev/null +++ b/mobile/ios/SyncTests/MockSyncServerTests.swift @@ -0,0 +1,194 @@ +/* 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/. */ + +import Shared +import Storage +@testable import Sync +import UIKit + +import XCTest + +class MockSyncServerTests: XCTestCase { + var server: MockSyncServer! + var client: Sync15StorageClient! + + override func setUp() { + server = MockSyncServer(username: "1234567") + server.start() + client = getClient(server: server) + } + + private func getClient(server: MockSyncServer) -> Sync15StorageClient? { + guard let url = server.baseURL.asURL else { + XCTFail("Couldn't get URL.") + return nil + } + + let authorizer: Authorizer = identity + let queue = DispatchQueue.global(qos: DispatchQoS.background.qosClass) + return Sync15StorageClient(serverURI: url, authorizer: authorizer, workQueue: queue, resultQueue: queue, backoff: MockBackoffStorage()) + } + + func testDeleteSpec() { + // Deletion of a collection path itself, versus trailing slash, sets the right flags. + let all = SyncDeleteRequestSpec.fromPath(path: "/1.5/123456/storage/bookmarks", withQuery: [:])! + XCTAssertTrue(all.wholeCollection) + XCTAssertNil(all.ids) + + let some = SyncDeleteRequestSpec.fromPath(path: "/1.5/123456/storage/bookmarks", withQuery: ["ids": "123456,abcdef" as AnyObject])! + XCTAssertFalse(some.wholeCollection) + XCTAssertEqual(["123456", "abcdef"], some.ids!) + + let one = SyncDeleteRequestSpec.fromPath(path: "/1.5/123456/storage/bookmarks/123456", withQuery: [:])! + XCTAssertFalse(one.wholeCollection) + XCTAssertNil(one.ids) + } + + func testInfoCollections() { + server.storeRecords(records: [MockSyncServer.makeValidEnvelope(guid: Bytes.generateGUID(), modified: 0)], inCollection: "bookmarks", now: 1326251111000) + server.storeRecords(records: [], inCollection: "tabs", now: 1326252222500) + server.storeRecords(records: [MockSyncServer.makeValidEnvelope(guid: Bytes.generateGUID(), modified: 0)], inCollection: "bookmarks", now: 1326252222000) + server.storeRecords(records: [MockSyncServer.makeValidEnvelope(guid: Bytes.generateGUID(), modified: 0)], inCollection: "clients", now: 1326253333000) + + let expectation = self.expectation(description: "Waiting for result.") + let before = decimalSecondsStringToTimestamp(millisecondsToDecimalSeconds(Date.now()))! + client.getInfoCollections().upon { result in + XCTAssertNotNil(result.successValue) + guard let response = result.successValue else { + expectation.fulfill() + return + } + let after = decimalSecondsStringToTimestamp(millisecondsToDecimalSeconds(Date.now()))! + + // JSON contents. + XCTAssertEqual(response.value.collectionNames().sorted(), ["bookmarks", "clients", "tabs"]) + XCTAssertEqual(response.value.modified("bookmarks"), 1326252222000) + XCTAssertEqual(response.value.modified("clients"), 1326253333000) + + // X-Weave-Timestamp. + XCTAssertLessThanOrEqual(before, response.metadata.timestampMilliseconds) + XCTAssertLessThanOrEqual(response.metadata.timestampMilliseconds, after) + // X-Weave-Records. + XCTAssertEqual(response.metadata.records, 3) // bookmarks, clients, tabs. + + // X-Last-Modified, max of all collection modified timestamps. + XCTAssertEqual(response.metadata.lastModifiedMilliseconds, 1326253333000) + + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testGet() { + server.storeRecords(records: [MockSyncServer.makeValidEnvelope(guid: "guid", modified: 0)], inCollection: "bookmarks", now: 1326251111000) + let collectionClient = client.clientForCollection("bookmarks", encrypter: getEncrypter()) + + let expectation = self.expectation(description: "Waiting for result.") + let before = decimalSecondsStringToTimestamp(millisecondsToDecimalSeconds(Date.now()))! + collectionClient.get("guid").upon { result in + XCTAssertNotNil(result.successValue) + guard let response = result.successValue else { + expectation.fulfill() + return + } + let after = decimalSecondsStringToTimestamp(millisecondsToDecimalSeconds(Date.now()))! + + // JSON contents. + XCTAssertEqual(response.value.id, "guid") + XCTAssertEqual(response.value.modified, 1326251111000) + + // X-Weave-Timestamp. + XCTAssertLessThanOrEqual(before, response.metadata.timestampMilliseconds) + XCTAssertLessThanOrEqual(response.metadata.timestampMilliseconds, after) + // X-Weave-Records. + XCTAssertNil(response.metadata.records) + // X-Last-Modified. + XCTAssertEqual(response.metadata.lastModifiedMilliseconds, 1326251111000) + + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + + // And now a missing record, which should produce a 404. + collectionClient.get("missing").upon { result in + XCTAssertNotNil(result.failureValue) + guard let response = result.failureValue else { + expectation.fulfill() + return + } + XCTAssertNotNil(response as? NotFound) + } + } + + func testWipeStorage() { + server.storeRecords(records: [MockSyncServer.makeValidEnvelope(guid: "a", modified: 0)], inCollection: "bookmarks", now: 1326251111000) + server.storeRecords(records: [MockSyncServer.makeValidEnvelope(guid: "b", modified: 0)], inCollection: "bookmarks", now: 1326252222000) + server.storeRecords(records: [MockSyncServer.makeValidEnvelope(guid: "c", modified: 0)], inCollection: "clients", now: 1326253333000) + server.storeRecords(records: [], inCollection: "tabs") + + // For now, only testing wiping the storage root, which is the only thing we use in practice. + let expectation = self.expectation(description: "Waiting for result.") + let before = decimalSecondsStringToTimestamp(millisecondsToDecimalSeconds(Date.now()))! + client.wipeStorage().upon { result in + XCTAssertNotNil(result.successValue) + guard let response = result.successValue else { + expectation.fulfill() + return + } + let after = decimalSecondsStringToTimestamp(millisecondsToDecimalSeconds(Date.now()))! + + // JSON contents: should be the empty object. + let jsonData = try! response.value.rawData() + let jsonString = String(data: jsonData, encoding: String.Encoding.utf8)! + XCTAssertEqual(jsonString, "{}") + + // X-Weave-Timestamp. + XCTAssertLessThanOrEqual(before, response.metadata.timestampMilliseconds) + XCTAssertLessThanOrEqual(response.metadata.timestampMilliseconds, after) + // X-Weave-Records. + XCTAssertNil(response.metadata.records) + // X-Last-Modified. + XCTAssertNil(response.metadata.lastModifiedMilliseconds) + + // And we really wiped the data. + XCTAssertTrue(self.server.collections.isEmpty) + + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testPut() { + // For now, only test uploading crypto/keys. There's nothing special about this PUT, however. + let expectation = self.expectation(description: "Waiting for result.") + let before = decimalSecondsStringToTimestamp(millisecondsToDecimalSeconds(Date.now()))! + client.uploadCryptoKeys(Keys.random(), withSyncKeyBundle: KeyBundle.random(), ifUnmodifiedSince: nil).upon { result in + XCTAssertNotNil(result.successValue) + guard let response = result.successValue else { + expectation.fulfill() + return + } + let after = decimalSecondsStringToTimestamp(millisecondsToDecimalSeconds(Date.now()))! + + // Contents: should be just the record timestamp. + XCTAssertLessThanOrEqual(before, response.value) + XCTAssertLessThanOrEqual(response.value, after) + + // X-Weave-Timestamp. + XCTAssertLessThanOrEqual(before, response.metadata.timestampMilliseconds) + XCTAssertLessThanOrEqual(response.metadata.timestampMilliseconds, after) + // X-Weave-Records. + XCTAssertNil(response.metadata.records) + // X-Last-Modified. + XCTAssertNil(response.metadata.lastModifiedMilliseconds) + + // And we really uploaded the record. + XCTAssertNotNil(self.server.collections["crypto"]) + XCTAssertNotNil(self.server.collections["crypto"]?.records["keys"]) + + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } +} diff --git a/mobile/ios/SyncTests/RecordTests.swift b/mobile/ios/SyncTests/RecordTests.swift new file mode 100644 index 0000000000..edeb6b5c15 --- /dev/null +++ b/mobile/ios/SyncTests/RecordTests.swift @@ -0,0 +1,572 @@ +/* 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/. */ + +import Shared +import Storage +@testable import Sync +import UIKit + +import XCTest +import SwiftyJSON + +class RecordTests: XCTestCase { + func testGUIDs() { + let s = Bytes.generateGUID() + print("Got GUID: \(s)", terminator: "\n") + XCTAssertEqual(12, s.lengthOfBytes(using: String.Encoding.utf8)) + } + + func testSwiftyJSONSerializingControlChars() { + let input = "{\"foo\":\"help \\u000b this\"}" + let json = JSON(parseJSON: input) + XCTAssertNil(json.error) + XCTAssertNil(json.null) + XCTAssertEqual(input, json.stringValue()) + + let pairs: [String: Any] = ["foo": "help \(Character(UnicodeScalar(11))) this"] + let built = JSON(object: pairs) + XCTAssertEqual(input, built.stringValue()) + } + + func testEnvelopeNullTTL() { + let p = CleartextPayloadJSON(JSON(object: ["id": "guid"])) + let r = Record(id: "guid", payload: p, modified: Date.now(), sortindex: 15, ttl: nil) + let k = KeyBundle.random() + let s = k.serializer({ $0.json }) + let json = s(r)! + XCTAssertEqual(json["id"].stringValue, "guid") + XCTAssertTrue(json["ttl"].isNull()) + } + + func testParsedNulls() { + // Make this a thorough test: use a real-ish blob of JSON. + // Look to see whether fields with explicit null values match isNull(). + let fullRecord = "{\"id\":\"global\"," + + "\"payload\":" + + "\"{\\\"syncID\\\":\\\"zPSQTm7WBVWB\\\"," + + "\\\"declined\\\":[\\\"bookmarks\\\"]," + + "\\\"storageVersion\\\":5," + + "\\\"engines\\\":{" + + "\\\"clients\\\":{\\\"version\\\":1,\\\"syncID\\\": null}," + + "\\\"tabs\\\":null}}\"," + + "\"username\":\"5817483\"," + + "\"modified\":1.32046073744E9}" + + let record = EnvelopeJSON(fullRecord) + let bodyJSON = JSON(parseJSON: record.payload) + + XCTAssertTrue(bodyJSON["engines"]["tabs"].isNull()) + + let clients = bodyJSON["engines"]["clients"] + + // Make sure we're really getting a value out. + XCTAssertEqual(clients["version"].int, 1) + + // An explicit null in the input has .type == null, so our .isNull works. + XCTAssertTrue(clients["syncID"].isNull()) + + // Oh, and it's a valid meta/global. + let global = MetaGlobal.fromJSON(bodyJSON) + XCTAssertTrue(global != nil) + } + + func testEnvelopeJSON() { + let e = EnvelopeJSON(JSON(parseJSON: "{}")) + XCTAssertFalse(e.isValid()) + + let ee = EnvelopeJSON("{\"id\": \"foo\"}") + XCTAssertFalse(ee.isValid()) + XCTAssertEqual(ee.id, "foo") + + let eee = EnvelopeJSON(JSON(parseJSON: "{\"id\": \"foo\", \"collection\": \"bar\", \"payload\": \"baz\"}")) + XCTAssertTrue(eee.isValid()) + XCTAssertEqual(eee.id, "foo") + XCTAssertEqual(eee.collection, "bar") + XCTAssertEqual(eee.payload, "baz") + } + + func testRecord() { + // This is malformed JSON (no closing brace). + let malformedPayload = "{\"id\": \"abcdefghijkl\", \"collection\": \"clients\", \"payload\": \"in" + + // Invalid: the payload isn't stringified JSON. + let invalidPayload = "{\"id\": \"abcdefghijkl\", \"collection\": \"clients\", \"payload\": \"invalid\"}" + + // Invalid: the payload is missing a GUID. + let emptyPayload = "{\"id\": \"abcdefghijkl\", \"collection\": \"clients\", \"payload\": \"{}\"}" + + // This one is invalid because the payload "id" isn't a string. + // (It'll also fail implicitly because the guid doesn't match the envelope.) + let badPayloadGUIDPayload: [String: Any] = ["id": 0] + let badPayloadGUIDPayloadString = JSON(object: badPayloadGUIDPayload).stringValue()! + let badPayloadGUIDRecord: [String: Any] = ["id": "abcdefghijkl", + "collection": "clients", + "payload": badPayloadGUIDPayloadString] + let badPayloadGUIDRecordString = JSON(object: badPayloadGUIDRecord).stringValue()! + + // This one is invalid because the payload doesn't contain an "id" at all, but it's non-empty. + // See also `emptyPayload` above. + // (It'll also fail implicitly because the guid doesn't match the envelope.) + let noPayloadGUIDPayload: [String: Any] = ["some": "thing"] + let noPayloadGUIDPayloadString = JSON(object: noPayloadGUIDPayload).stringValue()! + let noPayloadGUIDRecord: [String: Any] = ["id": "abcdefghijkl", + "collection": "clients", + "payload": noPayloadGUIDPayloadString] + let noPayloadGUIDRecordString = JSON(object: noPayloadGUIDRecord).stringValue()! + + // And this is a valid record. + let clientBody: [String: Any] = ["id": "abcdefghijkl", "name": "Foobar", "commands": [], "type": "mobile"] + let clientBodyString = JSON(object: clientBody).stringValue()! + let clientRecord: [String: Any] = ["id": "abcdefghijkl", "collection": "clients", "payload": clientBodyString] + let clientPayload = JSON(object: clientRecord).stringValue()! + + let cleartextClientsFactory: (String) -> ClientPayload? = { + (s: String) -> ClientPayload? in + return ClientPayload(s) + } + + let clearFactory: (String) -> CleartextPayloadJSON? = { + (s: String) -> CleartextPayloadJSON? in + return CleartextPayloadJSON(s) + } + + print(clientPayload, terminator: "\n") + + // Non-JSON malformed payloads don't even yield a value. + XCTAssertNil(Record.fromEnvelope(EnvelopeJSON(malformedPayload), payloadFactory: clearFactory)) + + // Only payloads that parse as JSON objects are valid. + XCTAssertNil(Record.fromEnvelope(EnvelopeJSON(invalidPayload), payloadFactory: clearFactory)) + + // Missing ID. + XCTAssertNil(Record.fromEnvelope(EnvelopeJSON(emptyPayload), payloadFactory: clearFactory)) + + // No ID in non-empty payload. + let noPayloadGUIDEnvelope = EnvelopeJSON(noPayloadGUIDRecordString) + + // The envelope is valid... + XCTAssertTrue(noPayloadGUIDEnvelope.isValid()) + + // ... but the payload is not. + let noID = Record.fromEnvelope(noPayloadGUIDEnvelope, payloadFactory: cleartextClientsFactory) + XCTAssertNil(noID) + + // Non-string ID in payload. + let badPayloadGUIDEnvelope = EnvelopeJSON(badPayloadGUIDRecordString) + + // The envelope is valid... + XCTAssertTrue(badPayloadGUIDEnvelope.isValid()) + + // ... but the payload is not. + let badID = Record.fromEnvelope(badPayloadGUIDEnvelope, payloadFactory: cleartextClientsFactory) + XCTAssertNil(badID) + + // Only valid ClientPayloads are valid. + XCTAssertNil(Record.fromEnvelope(EnvelopeJSON(invalidPayload), payloadFactory: cleartextClientsFactory)) + XCTAssertTrue(Record.fromEnvelope(EnvelopeJSON(clientPayload), payloadFactory: cleartextClientsFactory)!.payload.isValid()) + } + + func testEncryptedClientRecord() { + let b64E = "0A7mU5SZ/tu7ZqwXW1og4qHVHN+zgEi4Xwfwjw+vEJw=" + let b64H = "11GN34O9QWXkjR06g8t0gWE1sGgQeWL0qxxWwl8Dmxs=" + + let expectedGUID = "0-P9fabp9vJD" + let expectedSortIndex = 131 + let expectedLastModified: Timestamp = 1326254123650 + + let inputString = "{\"sortindex\": 131, \"payload\": \"{\\\"ciphertext\\\":\\\"YJB4dr0vZEIWPirfU2FCJvfzeSLiOP5QWasol2R6ILUxdHsJWuUuvTZVhxYQfTVNou6hVV67jfAvi5Cs+bqhhQsv7icZTiZhPTiTdVGt+uuMotxauVA5OryNGVEZgCCTvT3upzhDFdDbJzVd9O3/gU/b7r/CmAHykX8bTlthlbWeZ8oz6gwHJB5tPRU15nM/m/qW1vyKIw5pw/ZwtAy630AieRehGIGDk+33PWqsfyuT4EUFY9/Ly+8JlnqzxfiBCunIfuXGdLuqTjJOxgrK8mI4wccRFEdFEnmHvh5x7fjl1ID52qumFNQl8zkB75C8XK25alXqwvRR6/AQSP+BgQ==\\\",\\\"IV\\\":\\\"v/0BFgicqYQsd70T39rraA==\\\",\\\"hmac\\\":\\\"59605ed696f6e0e6e062a03510cff742bf6b50d695c042e8372a93f4c2d37dac\\\"}\", \"id\": \"0-P9fabp9vJD\", \"modified\": 1326254123.65}" + + let keyBundle = KeyBundle(encKeyB64: b64E, hmacKeyB64: b64H)! + let decryptClient = keyBundle.factory({ CleartextPayloadJSON($0) }) + let encryptClient = keyBundle.serializer({ $0.json }) // It's already a JSON. + + let toRecord = { + return Record.fromEnvelope($0, payloadFactory: decryptClient) + } + + let envelope = EnvelopeJSON(inputString) + if let r = toRecord(envelope) { + XCTAssertEqual(r.id, expectedGUID) + XCTAssertTrue(r.modified == expectedLastModified) //1326254123650 + XCTAssertEqual(r.sortindex, expectedSortIndex) + + if let ee = encryptClient(r) { + let envelopePrime = EnvelopeJSON(ee) + XCTAssertEqual(envelopePrime.id, expectedGUID) + XCTAssertEqual(envelopePrime.id, envelope.id) + XCTAssertEqual(envelopePrime.sortindex, envelope.sortindex) + XCTAssertTrue(envelopePrime.modified == 0) + + if let rPrime = toRecord(envelopePrime) { + // The payloads should be identical. + XCTAssertTrue(rPrime.equalPayloads(r)) + } else { + XCTFail("No record.") + } + } else { + XCTFail("No record.") + } + } else { + XCTFail("No record.") + } + + // Test invalid Base64. + let badInputString = "{\"sortindex\": 131, \"payload\": \"{\\\"ciphertext\\\":\\\"~~~YJB4dr0vZEIWPirfU2FCJvfzeSLiOP5QWasol2R6ILUxdHsJWuUuvTZVhxYQfTVNou6hVV67jfAvi5Cs+bqhhQsv7icZTiZhPTiTdVGt+uuMotxauVA5OryNGVEZgCCTvT3upzhDFdDbJzVd9O3/gU/b7r/CmAHykX8bTlthlbWeZ8oz6gwHJB5tPRU15nM/m/qW1vyKIw5pw/ZwtAy630AieRehGIGDk+33PWqsfyuT4EUFY9/Ly+8JlnqzxfiBCunIfuXGdLuqTjJOxgrK8mI4wccRFEdFEnmHvh5x7fjl1ID52qumFNQl8zkB75C8XK25alXqwvRR6/AQSP+BgQ==\\\",\\\"IV\\\":\\\"v/0BFgicqYQsd70T39rraA==\\\",\\\"hmac\\\":\\\"59605ed696f6e0e6e062a03510cff742bf6b50d695c042e8372a93f4c2d37dac\\\"}\", \"id\": \"0-P9fabp9vJD\", \"modified\": 1326254123.65}" + let badEnvelope = EnvelopeJSON(badInputString) + XCTAssertTrue(badEnvelope.isValid()) // It's a valid envelope containing nonsense ciphertext. + XCTAssertNil(toRecord(badEnvelope)) // Even though the envelope is valid, the payload is invalid, so we can't construct a record. + } + + func testMeta() { + let fullRecord = "{\"id\":\"global\"," + + "\"payload\":" + + "\"{\\\"syncID\\\":\\\"zPSQTm7WBVWB\\\"," + + "\\\"declined\\\":[\\\"bookmarks\\\"]," + + "\\\"storageVersion\\\":5," + + "\\\"engines\\\":{" + + "\\\"clients\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"fDg0MS5bDtV7\\\"}," + + "\\\"forms\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"GXF29AFprnvc\\\"}," + + "\\\"history\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"av75g4vm-_rp\\\"}," + + "\\\"passwords\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"LT_ACGpuKZ6a\\\"}," + + "\\\"prefs\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"-3nsksP9wSAs\\\"}," + + "\\\"tabs\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"W4H5lOMChkYA\\\"}}}\"," + + "\"username\":\"5817483\"," + + "\"modified\":1.32046073744E9}" + + let record = EnvelopeJSON(fullRecord) + XCTAssertTrue(record.isValid()) + + let global = MetaGlobal.fromJSON(JSON(parseJSON: record.payload)) + XCTAssertTrue(global != nil) + + if let global = global { + XCTAssertEqual(["bookmarks"], global.declined) + XCTAssertEqual(5, global.storageVersion) + let modified = record.modified + XCTAssertTrue(1320460737440 == modified) + let forms = global.engines["forms"] + let syncID = forms!.syncID + XCTAssertEqual("GXF29AFprnvc", syncID) + + let payload: JSON = global.asPayload().json + XCTAssertEqual("GXF29AFprnvc", payload["engines"]["forms"]["syncID"].stringValue) + XCTAssertEqual(1, payload["engines"]["forms"]["version"].intValue) + XCTAssertEqual("bookmarks", payload["declined"].arrayValue[0].stringValue) + } + } + + func testHistoryPayload() { + let payloadJSON = "{\"id\":\"--DzSJTCw-zb\",\"histUri\":\"https://bugzilla.mozilla.org/show_bug.cgi?id=1154549\",\"title\":\"1154549 – Encapsulate synced profile data within an account-centric object\",\"visits\":[{\"date\":1429061233163240,\"type\":1}]}" + let json = JSON(parseJSON: payloadJSON) + if let payload = HistoryPayload.fromJSON(json) { + XCTAssertEqual("--DzSJTCw-zb", payload["id"].stringValue) + XCTAssertEqual("1154549 – Encapsulate synced profile data within an account-centric object", payload["title"].stringValue) + XCTAssertEqual(1, payload.visits[0].type.rawValue) + XCTAssertEqual(1429061233163240, payload.visits[0].date) + + let v = payload.visits[0] + let j = v.toJSON() + XCTAssertEqual(1, j["type"] as! Int) + XCTAssertEqual(1429061233163240, j["date"] as! Int64) + } else { + XCTFail("Should have parsed.") + } + } + + func testHistoryPayloadWithNoURL() { + let payloadJSON = "{\"id\":\"--DzSJTCw-zb\",\"histUri\":null,\"visits\":[{\"date\":1429061233163240,\"type\":1}]}" + let json = JSON(parseJSON: payloadJSON) + XCTAssertNil(HistoryPayload.fromJSON(json)) + } + + func testHistoryPayloadWithNoTitle() { + let payloadJSON = "{\"id\":\"--DzSJTCw-zb\",\"histUri\":\"https://foo.com/\",\"visits\":[{\"date\":1429061233163240,\"type\":1}]}" + let json = JSON(parseJSON: payloadJSON) + if let payload = HistoryPayload.fromJSON(json) { + // Missing fields are null-valued in SwiftyJSON. + XCTAssertTrue(payload["title"].isNull()) + XCTAssertEqual("", payload.title) + } else { + XCTFail("Should have parsed.") + } + } + + func testHistoryPayloadWithNullTitle() { + let payloadJSON = "{\"id\":\"--DzSJTCw-zb\",\"histUri\":\"https://foo.com/\",\"title\":null,\"visits\":[{\"date\":1429061233163240,\"type\":1}]}" + let json = JSON(parseJSON: payloadJSON) + if let payload = HistoryPayload.fromJSON(json) { + XCTAssertEqual("", payload.title) + } else { + XCTFail("Should have parsed.") + } + } + + func testLoginPayload() { + let input = JSON([ + "id": "abcdefabcdef", + "hostname": "http://foo.com/", + "username": "foo", + "password": "bar", + "usernameField": "field", + "passwordField": "bar", + // No formSubmitURL. + "httpRealm": "", + ]) + + // fromJSON returns nil if not valid. + XCTAssertNotNil(LoginPayload.fromJSON(input)) + } + + func testSeparators() { + // Mistyped parentid. + let invalidSeparator = JSON(["type": "separator", "arentid": "toolbar", "parentName": "Bookmarks Toolbar", "pos": 3]) + let sep = BookmarkType.payloadFromJSON(invalidSeparator) + XCTAssertTrue(sep is SeparatorPayload) + XCTAssertFalse(sep!.isValid()) + + // This one's right. + let validSeparator = JSON(["id": "abcabcabcabc", "type": "separator", "parentid": "toolbar", "parentName": "Bookmarks Toolbar", "pos": 3]) + let separator = BookmarkType.payloadFromJSON(validSeparator)! + XCTAssertTrue(separator is SeparatorPayload) + XCTAssertTrue(separator.isValid()) + XCTAssertEqual(3, separator["pos"].intValue) + } + + func testFolders() { + let validFolder = JSON([ + "id": "abcabcabcabc", + "type": "folder", + "parentid": "toolbar", + "parentName": "Bookmarks Toolbar", + "title": "Sóme stüff", + "description": "", + "children": ["foo", "bar"], + ]) + let folder = BookmarkType.payloadFromJSON(validFolder)! + XCTAssertTrue(folder is FolderPayload) + XCTAssertTrue(folder.isValid()) + XCTAssertEqual((folder as! FolderPayload).children, ["foo", "bar"]) + } + +// swiftlint:disable line_length + func testMobileBookmarksFolder() { + let children = ["M87np9Vfh_2s", "-JxRyqNte-ue", "6lIQzUtbjE8O", "eOg3jPSslzXl", "1WJIi9EjQErp", "z5uRo45Rvfbd", "EK3lcNd0sUFN", "gFD3GTljgu12", "eRZGsbN1ew9-", "widfEdgGn9de", "l7eTOR4Uf6xq", "vPbxG-gpN4Rb", "4dwJ8CototFe", "zK-kw9Ii6ScW", "eDmDU-gtEFW6", "lKjqWQaL_syt", "ETVDvWgGT31Q", "3Z_bMIHPSZQ8", "Fqu4_bJOk7fT", "Uo_5K1QrA67j", "gDTXNg4m1AJZ", "zpds8P-9xews", "87zjNtVGPtEp", "ZJru8Sn3qhW7", "txVnzBBBOgLP", "JTnRqFaj_oNa", "soaMlfmM4kjR", "g8AcVBjo6IRf", "uPUDaiG4q637", "rfq2bUud_w4d", "XBGxsiuUG2UD", "-VQRnJlyAvMs", "6wu7TScKdTU7", "ZeFji2hLVpLj", "HpCn_TVizMWX", "IPR5HZwRdlwi", "00JFOGuWnhWB", "P1jb3qKt32Vg", "D6MQJ43V1Ir5", "qWSoXFteRfsq", "o2avfYqEdomL", "xRS0U0YnjK9G", "VgOgzE_xfP4w", "SwP3rMJGvoO3", "Hf2jEgI_-PWa", "AyhmBi7Cv598", "-PaMuzTJXxVk", "JMhYrg8SlY5K", "SQeySEjzyplL", "GTAwd2UkEQEe", "x3RsZj5Ilebr", "sRZWZqPi74FP", "amHR50TpygA6", "XSk782ceVNN6", "ipiMyYQzeypI", "ph2k3Nqfhau4", "m5JKC3hAEQ0H", "yTVerkmQbNxk", "7taA6FbbbUbH", "PZvpbSRuJLPs", "C8atoa25U94F", "KOfNJk_ISLc6", "Bt74lBG9tJq6", "BuHoY2rUhuKA", "XTmoWKnwfIPl", "ZATwa3oTD1m0", "e8TczN5It6Am", "6kCUYs8hQtKg", "jDD8s5aiKoex", "QmpmcrYwLU29", "nCRcekynuJ08", "resttaI4J9tu", "EKSX3HV55VU3", "2-yCz0EIsVls", "sSeeGw3VbBY-", "qfpCrU34w9y0", "RKDgzPWecD6m", "5SgXEKu_dICW", "R143WAeB5E5r", "8Ns4-NiKG62r", "4AHuZDvop5XX", "YCP1OsO1goFF", "CYYaU1mQ_N6t", "UGkzEOMK8cuU", "1RzZOarkzQBa", "qSW2Z3cZSI9c", "ooPlKEAfQsnn", "jIUScoKLiXQt", "bjNTKugzRRL1", "hR24ZVnHUZcs", "3j2IDAZgUyYi", "xnWcy-sQDJRu", "UCcgJqGk3bTV", "WSSRWeptH9tq", "4ugv47OGD2E2", "XboCZgUx-x3x", "HrmWqiqsuLrm", "OjdxvRJ3Jb6j"] + let json = JSON([ + "id": "UjAHxFOGEqU8", + "type": "folder", + "parentName": "", + "title": "mobile", + "description": JSON.null, + "children": children, + "parentid": "places", + ]) + + let bookmark = BookmarkType.payloadFromJSON(json) + XCTAssertTrue(bookmark is FolderPayload) + XCTAssertTrue(bookmark?.isValid() ?? false) + } +// swiftlint:enable line_length + + func testLivemarkMissingFields() { + let json = JSON([ + "id": "M5bwUKK8hPyF", + "type": "livemark", + "siteUri": "http://www.bbc.co.uk/go/rss/int/news/-/news/", + "feedUri": "http://fxfeeds.mozilla.com/en-US/firefox/headlines.xml", + "parentName": "Bookmarks Toolbar", + "parentid": "toolbar", + "children": ["3Qr13GucOtEh"]]) + + let bookmark = BookmarkType.payloadFromJSON(json) + XCTAssertTrue(bookmark is LivemarkPayload) + + let livemark = bookmark as! LivemarkPayload + XCTAssertTrue(livemark.isValid()) + let siteURI = "http://www.bbc.co.uk/go/rss/int/news/-/news/" + let feedURI = "http://fxfeeds.mozilla.com/en-US/firefox/headlines.xml" + XCTAssertEqual(feedURI, livemark.feedURI) + XCTAssertEqual(siteURI, livemark.siteURI) + + let m = (livemark as MirrorItemable).toMirrorItem(Date.now()) + XCTAssertEqual("http://fxfeeds.mozilla.com/en-US/firefox/headlines.xml", m.feedURI) + XCTAssertEqual("http://www.bbc.co.uk/go/rss/int/news/-/news/", m.siteURI) + } + + func testDeletedRecord() { + let json = JSON([ + "id": "abcdefghijkl", + "deleted": true, + "type": "bookmark", + ]) + + guard let payload = BookmarkType.payloadFromJSON(json) else { + XCTFail() + return + } + + XCTAssertFalse(payload is BookmarkPayload) // Only BookmarkBasePayload. + XCTAssertTrue(payload.isValid()) + } + + func testUnknownRecordType() { + // It'll return a base payload that's invalid because its type is unknown. + let json = JSON([ + "parentid": "mobile", + "tags": [], + "title": "Dispozitivul meu", + "id": "pQSMHiA7fD0Z", + "type": "something", + "parentName": "mobile", + ]) + + XCTAssertNil(BookmarkType.payloadFromJSON(json)) + + let payload = BookmarkType.somePayloadFromJSON(json) + XCTAssertFalse(payload.isValid()) // Not valid because type is unknown. + } + + func testInvalidRecordWithType() { + // It should still return the right payload type, even if it's not valid. + let json = JSON([ + "parentid": "mobile", + "bmkUri": JSON.null, + "tags": [], + "title": "Dispozitivul meu", + "id": "pQSMHiA7fD0Z", + "type": "bookmark", + "parentName": "mobile", + ]) + + guard let payload = BookmarkType.payloadFromJSON(json) else { + XCTFail() + return + } + + XCTAssertFalse(payload.isValid()) + XCTAssertTrue(payload is BookmarkPayload) + } + + func testLivemark() { + let json = JSON([ + "id": "M5bwUKK8hPyF", + "type": "livemark", + "siteUri": "http://www.bbc.co.uk/go/rss/int/news/-/news/", + "feedUri": "http://fxfeeds.mozilla.com/en-US/firefox/headlines.xml", + "parentName": "Bookmarks Toolbar", + "parentid": "toolbar", + "title": "Latest Headlines", + "description": "", + "children": + ["7oBdEZB-8BMO", "SUd1wktMNCTB", "eZe4QWzo1BcY", "YNBhGwhVnQsN", + "92Aw2SMEkFg0", "uw0uKqrVFwd-", "x7mx2P3--8FJ", "d-jVF8UuC9Ye", + "DV1XVtKLEiZ5", "g4mTaTjr837Z", "1Zi5W3lwBw8T", "FEYqlUHtbBWS", + "qQd2u7LjosCB", "VUs2djqYfbvn", "KuhYnHocu7eg", "u2gcg9ILRg-3", + "hfK_RP-EC7Ol", "Aq5qsa4E5msH", "6pZIbxuJTn-K", "k_fp0iN3yYMR", + "59YD3iNOYO8O", "01afpSdAk2iz", "Cq-kjXDEPIoP", "HtNTjt9UwWWg", + "IOU8QRSrTR--", "HJ5lSlBx6d1D", "j2dz5R5U6Khc", "5GvEjrNR0yJl", + "67ozIBF5pNVP", "r5YB0cUx6C_w", "FtmFDBNxDQ6J", "BTACeZq9eEtw", + "ll4ozQ-_VNJe", "HpImsA4_XuW7", "nJvCUQPLSXwA", "94LG-lh6TUYe", + "WHn_QoOL94Os", "l-RvjgsZYlej", "LipQ8abcRstN", "74TiLvarE3n_", + "8fCiLQpQGK1P", "Z6h4WkbwfQFa", "GgAzhqakoS6g", "qyt92T8vpMsK", + "RyOgVCe2EAOE", "bgSEhW3w6kk5", "hWODjHKGD7Ph", "Cky673aqOHbT", + "gZCYT7nx3Nwu", "iJzaJxxrM58L", "rUHCRv68aY5L", "6Jc1hNJiVrV9", + "lmNgoayZ-ym8", "R1lyXsDzlfOd", "pinrXwDnRk6g", "Sn7TmZV01vMM", + "qoXyU6tcS1dd", "TRLanED-QfBK", "xHbhMeX_FYEA", "aPqacdRlAtaW", + "E3H04Wn2RfSi", "eaSIMI6kSrcz", "rtkRxFoG5Vqi", "dectkUglV0Dz", + "B4vUE0BE15No", "qgQFW5AQrgB0", "SxAXvwOhu8Zi", "0S6cRPOg-5Z2", + "zcZZBGeLnaWW", "B0at8hkQqVZQ", "sgPtgGulbP66", "lwtwGHSCPYaQ", + "mNTdpgoRZMbW", "-L8Vci6CbkJY", "bVzudKSQERc1", "Gxl9lb4DXsmL", + "3Qr13GucOtEh"]]) + + let bookmark = BookmarkType.payloadFromJSON(json) + XCTAssertTrue(bookmark is LivemarkPayload) + + let livemark = bookmark as! LivemarkPayload + XCTAssertTrue(livemark.isValid()) + let siteURI = "http://www.bbc.co.uk/go/rss/int/news/-/news/" + let feedURI = "http://fxfeeds.mozilla.com/en-US/firefox/headlines.xml" + XCTAssertEqual(feedURI, livemark.feedURI) + XCTAssertEqual(siteURI, livemark.siteURI) + + let m = (livemark as MirrorItemable).toMirrorItem(Date.now()) + XCTAssertEqual("http://fxfeeds.mozilla.com/en-US/firefox/headlines.xml", m.feedURI) + XCTAssertEqual("http://www.bbc.co.uk/go/rss/int/news/-/news/", m.siteURI) + } + + func testMobileBookmark() { + let json = JSON([ + "id": "jIUScoKLiXQt", + "type": "bookmark", + "title": "Join the Engineering Leisure Class — Medium", + "parentName": "mobile", + "bmkUri": "https://medium.com/@chrisloer/join-the-engineering-leisure-class-b3083c09a78e", + "tags": [], + "keyword": JSON.null, + "description": JSON.null, + "loadInSidebar": false, + "parentid": "mobile", + ]) + + let bookmark = BookmarkType.payloadFromJSON(json) + XCTAssertTrue(bookmark is BookmarkPayload) + XCTAssertTrue(bookmark?.isValid() ?? false) + } + + func testQuery() { + let str = "{\"title\":\"Downloads\",\"parentName\":\"\",\"bmkUri\":\"place:transition=7&sort=4\",\"id\":\"7gdp9S1okhKf\",\"parentid\":\"rq6WHyfHkoUV\",\"type\":\"query\"}" + + let query = BookmarkType.payloadFromJSON(JSON(parseJSON: str)) + XCTAssertTrue(query is BookmarkQueryPayload) + let mirror = query?.toMirrorItem(Date.now()) + let roundtrip = mirror?.asPayload() + XCTAssertTrue(roundtrip! is BookmarkQueryPayload) + } + + func testBookmarks() { + let validBookmark = JSON([ + "id": "abcabcabcabc", + "type": "bookmark", + "parentid": "menu", + "parentName": "Bookmarks Menu", + "title": "Anøther", + "bmkUri": "http://terrible.sync/naming", + "description": "", + "tags": [], + "keyword": "", + ]) + let bookmark = BookmarkType.payloadFromJSON(validBookmark) + XCTAssertTrue(bookmark is BookmarkPayload) + + let query = JSON(parseJSON: "{\"id\":\"ShCZLGEFQMam\",\"type\":\"query\",\"title\":\"Downloads\",\"parentName\":\"\",\"bmkUri\":\"place:transition=7&sort=4\",\"tags\":[],\"keyword\":null,\"description\":null,\"loadInSidebar\":false,\"parentid\":\"T6XK5oJMU8ih\"}") + + guard let q = BookmarkType.payloadFromJSON(query) else { + XCTFail("Failed to generate payload from json: \(query)") + return + } + + XCTAssertTrue(q is BookmarkQueryPayload) + + let item = q.toMirrorItem(Date.now()) + XCTAssertEqual(6, item.type.rawValue) + XCTAssertEqual("ShCZLGEFQMam", item.guid) + + let places = JSON(parseJSON: "{\"id\":\"places\",\"type\":\"folder\",\"title\":\"\",\"description\":null,\"children\":[\"menu________\",\"toolbar_____\",\"tags________\",\"unfiled_____\",\"jKnyPDrBQSDg\",\"T6XK5oJMU8ih\"],\"parentid\":\"2hYxKgBwvkEH\"}") + guard let p = BookmarkType.payloadFromJSON(places) else { + XCTFail("Failed to generate payload from json: \(places)") + return + } + + XCTAssertTrue(p is FolderPayload) + + // Items keep their GUID until they're written into the mirror table. + XCTAssertEqual("places", p.id) + + let pMirror = p.toMirrorItem(Date.now()) + + XCTAssertEqual(2, pMirror.type.rawValue) + + // The mirror item has a translated GUID. + XCTAssertEqual(BookmarkRoots.RootGUID, pMirror.guid) + } +} diff --git a/mobile/ios/SyncTests/StateTests.swift b/mobile/ios/SyncTests/StateTests.swift new file mode 100644 index 0000000000..428c4870cd --- /dev/null +++ b/mobile/ios/SyncTests/StateTests.swift @@ -0,0 +1,68 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Sync + +import XCTest + +func compareScratchpads(tuple: (lhs: Scratchpad, rhs: Scratchpad)) { + // This one is set in the constructor! + XCTAssertEqual(tuple.lhs.syncKeyBundle, tuple.rhs.syncKeyBundle) + + XCTAssertEqual(tuple.lhs.clientName, tuple.rhs.clientName) + XCTAssertEqual(tuple.lhs.clientGUID, tuple.rhs.clientGUID) + if let lkeys = tuple.lhs.keys { + if let rkeys = tuple.rhs.keys { + XCTAssertEqual(lkeys.timestamp, rkeys.timestamp) + XCTAssertEqual(lkeys.value, rkeys.value) + } else { + XCTAssertTrue(tuple.rhs.keys != nil) + } + } else { + XCTAssertTrue(tuple.rhs.keys == nil) + } + + XCTAssertTrue(tuple.lhs.global == tuple.rhs.global) + XCTAssertEqual(tuple.lhs.localCommands, tuple.rhs.localCommands) + XCTAssertEqual(tuple.lhs.engineConfiguration, tuple.rhs.engineConfiguration) +} + +func roundtrip(s: Scratchpad) -> (Scratchpad, rhs: Scratchpad) { + let prefs = MockProfilePrefs() + let _ = s.pickle(prefs) + return (s, rhs: Scratchpad.restoreFromPrefs(prefs, syncKeyBundle: s.syncKeyBundle)!) +} + +class StateTests: XCTestCase { + func getGlobal() -> Fetched { + let g = MetaGlobal(syncID: "abcdefghiklm", storageVersion: 5, engines: ["bookmarks": EngineMeta(version: 1, syncID: "dddddddddddd")], declined: ["tabs"]) + return Fetched(value: g, timestamp: Date.now()) + } + + func getEngineConfiguration() -> EngineConfiguration { + return EngineConfiguration(enabled: ["bookmarks", "clients"], declined: ["tabs"]) + } + + func baseScratchpad() -> Scratchpad { + let syncKeyBundle = KeyBundle.fromKB(Bytes.generateRandomBytes(32)) + let keys = Fetched(value: Keys(defaultBundle: syncKeyBundle), timestamp: 1001) + let b = Scratchpad(b: syncKeyBundle, persistingTo: MockProfilePrefs()).evolve() + let _ = b.setKeys(keys) + b.localCommands = Set([ + .enableEngine(engine: "tabs"), + .disableEngine(engine: "passwords"), + .resetAllEngines(except: Set(["bookmarks", "clients"])), + .resetEngine(engine: "clients")]) + return b.build() + } + + func testPickling() { + compareScratchpads(tuple: roundtrip(s: baseScratchpad())) + compareScratchpads(tuple: roundtrip(s: baseScratchpad().evolve().setGlobal(getGlobal()).build())) + compareScratchpads(tuple: roundtrip(s: baseScratchpad().evolve().clearLocalCommands().build())) + compareScratchpads(tuple: roundtrip(s: baseScratchpad().evolve().setEngineConfiguration(getEngineConfiguration()).build())) + } +} diff --git a/mobile/ios/SyncTests/StorageClientTests.swift b/mobile/ios/SyncTests/StorageClientTests.swift new file mode 100644 index 0000000000..2d7601a428 --- /dev/null +++ b/mobile/ios/SyncTests/StorageClientTests.swift @@ -0,0 +1,108 @@ +/* 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/. */ + +import Foundation +import Shared +@testable import Sync + +import XCTest +import SwiftyJSON + +// Always return a gigantic encoded payload. +func massivify(record: Record) -> JSON? { + return JSON([ + "id": record.id, + "foo": String(repeating: "X", count: Sync15StorageClient.maxRecordSizeBytes + 1) + ]) +} + +class StorageClientTests: XCTestCase { + func testPartialJSON() { + let body = "0" + let o: Any? = try! JSONSerialization.jsonObject(with: body.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions.allowFragments) + XCTAssertTrue(JSON(object: o!).isInt()) + } + + func testPOSTResult() { + // Pulled straight from . + let r = "{" + + "\"success\": [\"GXS58IDC_12\", \"GXS58IDC_13\", \"GXS58IDC_15\"," + + "\"GXS58IDC_16\", \"GXS58IDC_18\", \"GXS58IDC_19\"]," + + "\"failed\": {\"GXS58IDC_11\": \"invalid ttl\"," + + "\"GXS58IDC_14\": \"invalid sortindex\"}" + + "}" + + let p = POSTResult.fromJSON(JSON(parseJSON: r)) + XCTAssertTrue(p != nil) + XCTAssertEqual(p!.success[0], "GXS58IDC_12") + XCTAssertEqual(p!.failed["GXS58IDC_14"]!, "invalid sortindex") + + XCTAssertTrue(nil == POSTResult.fromJSON(JSON(parseJSON: "{\"foo\": 5}"))) + } + + func testNumeric() { + let m = ResponseMetadata(status: 200, headers: [ + "X-Last-Modified": "2174380461.12", + ]) + XCTAssertTrue(m.lastModifiedMilliseconds == 2174380461120) + + XCTAssertEqual("2174380461.12", millisecondsToDecimalSeconds(2174380461120)) + } + + // Trivial test for struct semantics that we might want to pay attention to if they change, + // and for response header parsing. + func testResponseHeaders() { + let v: JSON = JSON(parseJSON: "{\"a:\": 2}") + let m = ResponseMetadata(status: 200, headers: [ + "X-Weave-Timestamp": "1274380461.12", + "X-Last-Modified": "2174380461.12", + "X-Weave-Next-Offset": "abdef", + ]) + + XCTAssertTrue(m.lastModifiedMilliseconds == 2174380461120) + XCTAssertTrue(m.timestampMilliseconds == 1274380461120) + XCTAssertTrue(m.nextOffset == "abdef") + + // Just to avoid consistent overflow allowing ==. + XCTAssertTrue(m.lastModifiedMilliseconds?.description == "2174380461120") + XCTAssertTrue(m.timestampMilliseconds.description == "1274380461120") + + let x: StorageResponse = StorageResponse(value: v, metadata: m) + + func doTesting(y: StorageResponse) { + // Make sure that reference fields in a struct are copies of the same reference, + // not references to a copy. + XCTAssertTrue(x.value == y.value) + + XCTAssertTrue(y.metadata.lastModifiedMilliseconds == x.metadata.lastModifiedMilliseconds, "lastModified is the same.") + + XCTAssertTrue(x.metadata.quotaRemaining == nil, "No quota.") + XCTAssertTrue(y.metadata.lastModifiedMilliseconds == 2174380461120, "lastModified is correct.") + XCTAssertTrue(x.metadata.timestampMilliseconds == 1274380461120, "timestamp is correct.") + XCTAssertTrue(x.metadata.nextOffset == "abdef", "nextOffset is correct.") + XCTAssertTrue(x.metadata.records == nil, "No X-Weave-Records.") + } + + doTesting(y: x) + } + + func testOverSizeRecords() { + let delegate = MockSyncDelegate() + + // We can use these useless values because we're directly injecting decrypted + // payloads; no need for real keys etc. + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let synchronizer = IndependentRecordSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled, collection: "foo") + let jA = "{\"id\":\"aaaaaa\",\"histUri\":\"http://foo.com/\",\"title\": \"ñ\",\"visits\":[{\"date\":1222222222222222,\"type\":1}]}" + let rA = Record(id: "aaaaaa", payload: CleartextPayloadJSON(JSON(parseJSON: jA)), modified: 10000, sortindex: 123, ttl: 1000000) + + let storageClient = Sync15StorageClient(serverURI: "http://example.com/".asURL!, authorizer: identity, workQueue: DispatchQueue.main, resultQueue: DispatchQueue.main, backoff: MockBackoffStorage()) + let collectionClient = storageClient.clientForCollection("foo", encrypter: RecordEncrypter(serializer: massivify, factory: { CleartextPayloadJSON($0) })) + let result = synchronizer.uploadRecords([rA], lastTimestamp: Date.now(), storageClient: collectionClient, onUpload: { _ in deferMaybe(Date.now()) }) + + XCTAssertTrue(result.value.failureValue is RecordTooLargeError) + } +} diff --git a/mobile/ios/SyncTests/SyncTests-Bridging-Header.h b/mobile/ios/SyncTests/SyncTests-Bridging-Header.h new file mode 100644 index 0000000000..a8ec25a0ed --- /dev/null +++ b/mobile/ios/SyncTests/SyncTests-Bridging-Header.h @@ -0,0 +1,9 @@ +#ifndef Client_SyncTests_Bridging_Header_h +#define Client_SyncTests_Bridging_Header_h + +#import +#import "Shared-Bridging-Header.h" +#import "Storage-Bridging-Header.h" +#import "Sync-Bridging-Header.h" + +#endif diff --git a/mobile/ios/SyncTests/TabsPayloadTests.swift b/mobile/ios/SyncTests/TabsPayloadTests.swift new file mode 100644 index 0000000000..daef0a86e6 --- /dev/null +++ b/mobile/ios/SyncTests/TabsPayloadTests.swift @@ -0,0 +1,90 @@ +/* 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/. */ + +import XCTest +@testable import Sync + +class TabsPayloadTests: XCTestCase { + + func testFromInvalidJSON() { + let tabsPayload1 = TabsPayload("") + XCTAssertFalse(tabsPayload1.isValid()) + + let tabsPayload2 = TabsPayload("null") + XCTAssertFalse(tabsPayload2.isValid()) + + let tabsPayload3 = TabsPayload("{}") + XCTAssertFalse(tabsPayload3.isValid()) + + let tabsPayload4 = TabsPayload("{\"id\": \"abc\"}") + XCTAssertFalse(tabsPayload4.isValid()) + } + + func testFromJSON() { + let tabsPayload = TabsPayload("{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": []}") + XCTAssertTrue(tabsPayload.isValid()) + } + + func testFromJSONWithInvalidRecord() { + let tabsPayload = TabsPayload("{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": null}") + XCTAssertFalse(tabsPayload.isValid()) + + let tabsPayload2 = TabsPayload("{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": 1}") + XCTAssertFalse(tabsPayload2.isValid()) + + let tabsPayload3 = TabsPayload("{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": {}}") + XCTAssertFalse(tabsPayload3.isValid()) + + let tabsPayload4 = TabsPayload("{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": true}") + XCTAssertFalse(tabsPayload4.isValid()) + } + + func testTabWithBadTabs() { + let tabsPayload1 = TabsPayload("{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{}]}") + XCTAssertTrue(tabsPayload1.isValid()) + let tabs1 = tabsPayload1.tabs + XCTAssert(tabs1.count == 0) + + let tabsPayload2 = TabsPayload("{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [null, {}, [], 123, false, true, \"\"]}") + XCTAssertTrue(tabsPayload2.isValid()) + let tabs2 = tabsPayload2.tabs + XCTAssert(tabs2.count == 0) + } + + func testTabWithCorrectTabLastUsed() { + let payloads = [ + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": 1492649651}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": \"1492316843992\"}]}" + ] + + for payload in payloads { + let tabsPayload = TabsPayload(payload) + XCTAssertTrue(tabsPayload.isValid()) + let tabs = tabsPayload.tabs + XCTAssert(tabs.count == 1) + } + } + + func testTabWithBadTabLastUsed() { + let payloads = [ + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": null}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": \"\"}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": \"cheese\"}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": true}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": false}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": 9223372036854775807}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": 123456789012345678901234567890}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": -1}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": \"123456789012345678901234567890\"}]}", + "{\"id\": \"abc\", \"deleted\": false, \"clientName\": \"Foo\", \"tabs\": [{\"title\": \"Some Title\", \"urlHistory\": [\"http://www.example.com\"], \"icon\": null, \"lastUsed\": \"-1\"}]}" + ] + + for payload in payloads { + let tabsPayload = TabsPayload(payload) + XCTAssertTrue(tabsPayload.isValid(), "Should not be valid: \(payload)") + let tabs = tabsPayload.tabs + XCTAssert(tabs.count == 0, "Should not have valid tabs: \(payload)") + } + } +} diff --git a/mobile/ios/SyncTests/TestBookmarkModel.swift b/mobile/ios/SyncTests/TestBookmarkModel.swift new file mode 100644 index 0000000000..4cb31e9b3f --- /dev/null +++ b/mobile/ios/SyncTests/TestBookmarkModel.swift @@ -0,0 +1,201 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared +@testable import Storage +@testable import Sync +import XCTest + +// Thieved mercilessly from TestSQLiteBookmarks. +private func getBrowserDBForFile(filename: String, files: FileAccessor) -> BrowserDB? { + return BrowserDB(filename: filename, schema: BrowserSchema(), files: files) +} + +class TestBookmarkModel: FailFastTestCase { + let files = MockFiles() + + override func tearDown() { + do { + try self.files.removeFilesInDirectory() + } catch { + } + super.tearDown() + } + + private func getBrowserDB(name: String) -> BrowserDB? { + let file = "TBookmarkModel\(name).db" + print("DB file named: \(file)") + return getBrowserDBForFile(filename: file, files: self.files) + } + + func getSyncableBookmarks(name: String) -> MergedSQLiteBookmarks? { + guard let db = self.getBrowserDB(name: name) else { + XCTFail("Couldn't get prepared DB.") + return nil + } + + return MergedSQLiteBookmarks(db: db) + } + + func testBookmarkEditableIfNeverSyncedAndEmptyBuffer() { + guard let bookmarks = self.getSyncableBookmarks(name: "A") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Set a local bookmark + let bookmarkURL = "http://AAA.com".asURL! + bookmarks.local.insertBookmark(bookmarkURL, title: "AAA", favicon: nil, intoFolder: BookmarkRoots.MenuFolderGUID, withTitle: "").succeeded() + + XCTAssertTrue(bookmarks.isMirrorEmpty().value.successValue!) + XCTAssertTrue(bookmarks.buffer.isEmpty().value.successValue!) + + let menuFolder = bookmarks.menuFolder() + XCTAssertEqual(menuFolder.current.count, 1) + XCTAssertTrue(menuFolder.current[0]!.isEditable) + } + + func testBookmarkEditableIfNeverSyncedWithBufferedChanges() { + guard let bookmarks = self.getSyncableBookmarks(name: "B") else { + XCTFail("Couldn't get bookmarks.") + return + } + + let bookmarkURL = "http://AAA.com".asURL! + bookmarks.local.insertBookmark(bookmarkURL, title: "AAA", favicon: nil, intoFolder: BookmarkRoots.MenuFolderGUID, withTitle: "").succeeded() + + // Add a buffer into the buffer + let mirrorDate = Date.now() - 100000 + bookmarks.applyRecords([ + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: ["BBB"]), + BookmarkMirrorItem.bookmark("BBB", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.MenuFolderGUID, parentName: "Bookmarks Menu", title: "BBB", description: nil, URI: "http://BBB.com", tags: "", keyword: nil) + ]).succeeded() + + XCTAssertFalse(bookmarks.buffer.isEmpty().value.successValue!) + XCTAssertTrue(bookmarks.isMirrorEmpty().value.successValue!) + + // Check to see if we're editable + let menuFolder = bookmarks.menuFolder() + XCTAssertEqual(menuFolder.current.count, 1) + XCTAssertTrue(menuFolder.current[0]!.isEditable) + } + + func testBookmarksEditableWithEmptyBufferAndRemoteBookmark() { + guard let bookmarks = self.getSyncableBookmarks(name: "C") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Add a bookmark to the menu folder in our mirror + let mirrorDate = Date.now() - 100000 + bookmarks.populateMirrorViaBuffer(items: [ + BookmarkMirrorItem.folder(BookmarkRoots.RootGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "", description: "", children: BookmarkRoots.RootChildren), + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: ["CCC"]), + BookmarkMirrorItem.bookmark("CCC", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.MenuFolderGUID, parentName: "Bookmarks Menu", title: "CCC", description: nil, URI: "http://CCC.com", tags: "", keyword: nil) + ], atDate: mirrorDate) + + // Set a local bookmark + let bookmarkURL = "http://AAA.com".asURL! + bookmarks.local.insertBookmark(bookmarkURL, title: "AAA", favicon: nil, intoFolder: BookmarkRoots.MenuFolderGUID, withTitle: "").succeeded() + + XCTAssertTrue(bookmarks.buffer.isEmpty().value.successValue!) + XCTAssertFalse(bookmarks.isMirrorEmpty().value.successValue!) + + // Check to see if we're editable + let menuFolder = bookmarks.menuFolder() + XCTAssertEqual(menuFolder.current.count, 2) + XCTAssertTrue(menuFolder.current[0]!.isEditable) + XCTAssertTrue(menuFolder.current[1]!.isEditable) + } + + func testBookmarksNotEditableForUnmergedChanges() { + guard let bookmarks = self.getSyncableBookmarks(name: "D") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Add a bookmark to the menu folder in our mirror + let mirrorDate = Date.now() - 100000 + bookmarks.populateMirrorViaBuffer(items: [ + BookmarkMirrorItem.folder(BookmarkRoots.RootGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "", description: "", children: BookmarkRoots.RootChildren), + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: ["EEE"]), + BookmarkMirrorItem.bookmark("EEE", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.MenuFolderGUID, parentName: "Bookmarks Menu", title: "EEE", description: nil, URI: "http://EEE.com", tags: "", keyword: nil) + ], atDate: mirrorDate) + + bookmarks.local.insertBookmark("http://AAA.com".asURL!, title: "AAA", favicon: nil, intoFolder: BookmarkRoots.MobileFolderGUID, withTitle: "Bookmarks Menu").succeeded() + + // Add some unmerged bookmarks into the menu folder in the buffer. + bookmarks.applyRecords([ + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: ["EEE", "FFF"]), + BookmarkMirrorItem.bookmark("FFF", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.MenuFolderGUID, parentName: "Bookmarks Menu", title: "FFF", description: nil, URI: "http://FFF.com", tags: "", keyword: nil) + ]).succeeded() + + XCTAssertFalse(bookmarks.buffer.isEmpty().value.successValue!) + XCTAssertFalse(bookmarks.isMirrorEmpty().value.successValue!) + + // Check to see that we can't edit these bookmarks + let menuFolder = bookmarks.menuFolder() + XCTAssertEqual(menuFolder.current.count, 1) + XCTAssertFalse(menuFolder.current[0]!.isEditable) + + } + + func testLocalBookmarksEditableWhileHavingUnmergedChangesAndEmptyMirror() { + guard let bookmarks = self.getSyncableBookmarks(name: "D") else { + XCTFail("Couldn't get bookmarks.") + return + } + + bookmarks.local.insertBookmark("http://AAA.com".asURL!, title: "AAA", favicon: nil, intoFolder: BookmarkRoots.MobileFolderGUID, withTitle: "Bookmarks Menu").succeeded() + + // Add some unmerged bookmarks into the menu folder in the buffer. + let mirrorDate = Date.now() - 100000 + bookmarks.applyRecords([ + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: ["EEE", "FFF"]), + BookmarkMirrorItem.bookmark("FFF", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.MenuFolderGUID, parentName: "Bookmarks Menu", title: "FFF", description: nil, URI: "http://FFF.com", tags: "", keyword: nil) + ]).succeeded() + + // Local bookmark should be editable + let mobileFolder = bookmarks.mobileFolder() + XCTAssertEqual(mobileFolder.current.count, 2) + XCTAssertTrue(mobileFolder.current[1]!.isEditable) + } +} + +private extension MergedSQLiteBookmarks { + func isMirrorEmpty() -> Deferred> { + return self.local.db.queryReturnsNoResults("SELECT 1 FROM \(TableBookmarksMirror)") + } + + func wipeLocal() { + self.local.db.run(["DELETE FROM \(TableBookmarksLocalStructure)", "DELETE FROM \(TableBookmarksLocal)"]).succeeded() + } + + func populateMirrorViaBuffer(items: [BookmarkMirrorItem], atDate mirrorDate: Timestamp) { + self.applyRecords(items).succeeded() + + // … and add the root relationships that will be missing (we don't do those for the buffer, + // so we need to manually add them and move them across). + self.buffer.db.run([ + "INSERT INTO \(TableBookmarksBufferStructure) (parent, child, idx) VALUES", + "('\(BookmarkRoots.RootGUID)', '\(BookmarkRoots.MenuFolderGUID)', 0),", + "('\(BookmarkRoots.RootGUID)', '\(BookmarkRoots.ToolbarFolderGUID)', 1),", + "('\(BookmarkRoots.RootGUID)', '\(BookmarkRoots.UnfiledFolderGUID)', 2),", + "('\(BookmarkRoots.RootGUID)', '\(BookmarkRoots.MobileFolderGUID)', 3)", + ].joined(separator: " ")).succeeded() + + // Move it all to the mirror. + self.local.db.moveBufferToMirrorForTesting() + } + + func menuFolder() -> BookmarksModel { + return modelFactory.value.successValue!.modelForFolder(BookmarkRoots.MenuFolderGUID).value.successValue! + } + + func mobileFolder() -> BookmarksModel { + return modelFactory.value.successValue!.modelForFolder(BookmarkRoots.MobileFolderGUID).value.successValue! + } +} diff --git a/mobile/ios/SyncTests/TestBookmarkTreeMerging.swift b/mobile/ios/SyncTests/TestBookmarkTreeMerging.swift new file mode 100644 index 0000000000..90d4873969 --- /dev/null +++ b/mobile/ios/SyncTests/TestBookmarkTreeMerging.swift @@ -0,0 +1,1100 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared +@testable import Storage +@testable import Sync +import XCTest + +extension Dictionary { + init(seq: S) where S.Iterator.Element == Element { + self.init() + for (k, v) in seq { + self[k] = v + } + } +} + +class MockLocalItemSource: LocalItemSource { + var local: [GUID: BookmarkMirrorItem] = [:] + + func getLocalItemWithGUID(_ guid: GUID) -> Deferred> { + guard let item = self.local[guid] else { + return deferMaybe(DatabaseError(description: "Couldn't find item \(guid).")) + } + return deferMaybe(item) + } + + func getLocalItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + var acc: [GUID: BookmarkMirrorItem] = [:] + guids.forEach { guid in + if let item = self.local[guid] { + acc[guid] = item + } + } + return deferMaybe(acc) + } + + func prefetchLocalItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return succeed() + } +} + +class MockMirrorItemSource: MirrorItemSource { + var mirror: [GUID: BookmarkMirrorItem] = [:] + + func getMirrorItemWithGUID(_ guid: GUID) -> Deferred> { + guard let item = self.mirror[guid] else { + return deferMaybe(DatabaseError(description: "Couldn't find item \(guid).")) + } + return deferMaybe(item) + } + + func getMirrorItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + var acc: [GUID: BookmarkMirrorItem] = [:] + guids.forEach { guid in + if let item = self.mirror[guid] { + acc[guid] = item + } + } + return deferMaybe(acc) + } + + func prefetchMirrorItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return succeed() + } +} + +class MockBufferItemSource: BufferItemSource { + var buffer: [GUID: BookmarkMirrorItem] = [:] + + func getBufferItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + var acc: [GUID: BookmarkMirrorItem] = [:] + guids.forEach { guid in + if let item = self.buffer[guid] { + acc[guid] = item + } + } + return deferMaybe(acc) + } + + func getBufferItemWithGUID(_ guid: GUID) -> Deferred> { + guard let item = self.buffer[guid] else { + return deferMaybe(DatabaseError(description: "Couldn't find item \(guid).")) + } + return deferMaybe(item) + } + + func getBufferChildrenGUIDsForParent(_ guid: GUID) -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func prefetchBufferItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return succeed() + } +} + +class MockUploader { + var deletions: Set = Set() + var added: Set = Set() + var records: [GUID: Record] = [:] + + func getStorer() -> TrivialBookmarkStorer { + return TrivialBookmarkStorer(uploader: self.doUpload) + } + + func doUpload(recs: [Record], lastTimestamp: Timestamp?, onUpload: (POSTResult, Timestamp) -> DeferredTimestamp) -> DeferredTimestamp { + var success: [GUID] = [] + recs.forEach { rec in + success.append(rec.id) + self.records[rec.id] = rec + if rec.payload.deleted { + self.deletions.insert(rec.id) + } else { + self.added.insert(rec.id) + } + } + + // Now pretend we did the upload. + return onUpload(POSTResult(success: success, failed: [:]), Date.now()) + } +} + +// Thieved mercilessly from TestSQLiteBookmarks. +private func getBrowserDBForFile(filename: String, files: FileAccessor) -> BrowserDB? { + let db = BrowserDB(filename: filename, schema: BrowserSchema(), files: files) + db.touch().succeeded() // Ensure the schema is created/updated in advance + return db +} + +class FailFastTestCase: XCTestCase { + // This is how to make an assertion failure stop the current test function + // but continue with other test functions in the same test case. + // See http://stackoverflow.com/a/27016786/22003 + override func invokeTest() { + self.continueAfterFailure = false + defer { self.continueAfterFailure = true } + super.invokeTest() + } +} + +class TestBookmarkTreeMerging: FailFastTestCase { + let files = MockFiles() + + override func tearDown() { + do { + try self.files.removeFilesInDirectory() + } catch { + } + super.tearDown() + } + + private func getBrowserDB(name: String) -> BrowserDB? { + let file = "TBookmarkTreeMerging\(name).db" + return getBrowserDBForFile(filename: file, files: self.files) + } + + private func mockStatsSessionForBookmarks() -> SyncEngineStatsSession { + let session = SyncEngineStatsSession(collection: "bookmarks") + session.start() + return session + } + + func getSyncableBookmarks(name: String) -> MergedSQLiteBookmarks? { + guard let db = self.getBrowserDB(name: name) else { + XCTFail("Couldn't get prepared DB.") + return nil + } + + return MergedSQLiteBookmarks(db: db) + } + + func getSQLiteBookmarks(name: String) -> SQLiteBookmarks? { + guard let db = self.getBrowserDB(name: name) else { + XCTFail("Couldn't get prepared DB.") + return nil + } + + return SQLiteBookmarks(db: db) + } + + func dbLocalTree(name: String) -> BookmarkTree? { + guard let bookmarks = self.getSQLiteBookmarks(name: name) else { + XCTFail("Couldn't get bookmarks.") + return nil + } + + return bookmarks.treeForLocal().value.successValue + } + + func localTree() -> BookmarkTree { + let roots = BookmarkRoots.RootChildren.map { BookmarkTreeNode.folder(guid: $0, children: []) } + let places = BookmarkTreeNode.folder(guid: BookmarkRoots.RootGUID, children: roots) + + var lookup: [GUID: BookmarkTreeNode] = [:] + var parents: [GUID: GUID] = [:] + + for n in roots { + lookup[n.recordGUID] = n + parents[n.recordGUID] = BookmarkRoots.RootGUID + } + lookup[BookmarkRoots.RootGUID] = places + + return BookmarkTree(subtrees: [places], lookup: lookup, parents: parents, orphans: Set(), deleted: Set(), modified: Set(lookup.keys), virtual: Set()) + } + + // Our synthesized tree is the same as the one we pull out of a brand new local DB. + func testLocalTreeAssumption() { + let constructed = self.localTree() + let fromDB = self.dbLocalTree(name: "A") + XCTAssertNotNil(fromDB) + XCTAssertTrue(fromDB!.isFullyRootedIn(constructed)) + XCTAssertTrue(constructed.isFullyRootedIn(fromDB!)) + XCTAssertTrue(fromDB!.virtual.isEmpty) + XCTAssertTrue(constructed.virtual.isEmpty) + } + + // This should never occur in the wild: local will never be empty. + func testMergingEmpty() { + let r = BookmarkTree.emptyTree() + let m = BookmarkTree.emptyMirrorTree() + let l = BookmarkTree.emptyTree() + let s = ItemSources(local: MockLocalItemSource(), mirror: MockMirrorItemSource(), buffer: MockBufferItemSource()) + + XCTAssertEqual(m.virtual, BookmarkRoots.Real) + let merger = ThreeWayTreeMerger(local: l, mirror: m, remote: r, itemSources: s) + guard let mergedTree = merger.produceMergedTree().value.successValue else { + XCTFail("Couldn't merge.") + return + } + + mergedTree.dump() + XCTAssertEqual(mergedTree.allGUIDs, BookmarkRoots.Real) + + guard let result = merger.produceMergeResultFromMergedTree(mergedTree).value.successValue else { + XCTFail("Couldn't produce result.") + return + } + + // We don't test the local override completion, because of course we saw mirror items. + XCTAssertTrue(result.uploadCompletion.isNoOp) + XCTAssertTrue(result.bufferCompletion.isNoOp) + } + + func getItemSourceIncludingEmptyRoots() -> ItemSources { + let local = MockLocalItemSource() + + func makeRoot(guid: GUID, _ name: String) { + local.local[guid] = BookmarkMirrorItem.folder(guid, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: name, description: nil, children: []) + } + + makeRoot(guid: BookmarkRoots.MenuFolderGUID, "Bookmarks Menu") + makeRoot(guid: BookmarkRoots.ToolbarFolderGUID, "Bookmarks Toolbar") + makeRoot(guid: BookmarkRoots.MobileFolderGUID, "Mobile Bookmarks") + makeRoot(guid: BookmarkRoots.UnfiledFolderGUID, "Unsorted Bookmarks") + makeRoot(guid: BookmarkRoots.RootGUID, "") + + return ItemSources(local: local, mirror: MockMirrorItemSource(), buffer: MockBufferItemSource()) + } + + func testMergingOnlyLocalRoots() { + let r = BookmarkTree.emptyTree() + let m = BookmarkTree.emptyMirrorTree() + let l = self.localTree() + let s = self.getItemSourceIncludingEmptyRoots() + + let merger = ThreeWayTreeMerger(local: l, mirror: m, remote: r, itemSources: s) + guard let mergedTree = merger.produceMergedTree().value.successValue else { + XCTFail("Couldn't merge.") + return + } + + mergedTree.dump() + XCTAssertEqual(mergedTree.allGUIDs, BookmarkRoots.Real) + + guard let result = merger.produceMergeResultFromMergedTree(mergedTree).value.successValue else { + XCTFail("Couldn't produce result.") + return + } + + XCTAssertFalse(result.isNoOp) + XCTAssertTrue(result.overrideCompletion.processedLocalChanges.isSuperset(of: Set(BookmarkRoots.RootChildren))) + + // We should be dropping the roots from local, and uploading roots to the server. + // The outgoing records should use Sync-style IDs. + // We never upload the places root. + let banned = Set(["places", BookmarkRoots.RootGUID]) + XCTAssertTrue(banned.isDisjoint(with: Set(result.uploadCompletion.records.map { $0.id }))) + XCTAssertTrue(banned.isDisjoint(with: result.uploadCompletion.amendChildrenFromBuffer.keys)) + XCTAssertTrue(banned.isDisjoint(with: result.uploadCompletion.amendChildrenFromMirror.keys)) + XCTAssertTrue(banned.isDisjoint(with: result.uploadCompletion.amendChildrenFromLocal.keys)) + XCTAssertEqual(Set(BookmarkRoots.RootChildren), Set(result.uploadCompletion.amendChildrenFromLocal.keys)) + XCTAssertEqual(Set(BookmarkRoots.Real), result.overrideCompletion.processedLocalChanges) + } + + func testMergingStorageLocalRootsEmptyServer() { + guard let bookmarks = self.getSyncableBookmarks(name: "B") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // The mirror is never actually empty. + let mirrorTree = bookmarks.treeForMirror().value.successValue! + XCTAssertFalse(mirrorTree.isEmpty) + XCTAssertEqual(mirrorTree.lookup.keys.count, 5) // Root and four children. + XCTAssertEqual(1, mirrorTree.subtrees.count) + + let edgesBefore = bookmarks.treesForEdges().value.successValue! + XCTAssertFalse(edgesBefore.local.isEmpty) + XCTAssertTrue(edgesBefore.buffer.isEmpty) + + let uploader = MockUploader() + let storer = uploader.getStorer() + let applier = MergeApplier(buffer: bookmarks, storage: bookmarks, client: storer, statsSession: mockStatsSessionForBookmarks(), greenLight: { true }) + applier.go().succeeded() + + // Now the local contents are replicated into the mirror, and both the buffer and local are empty. + guard let mirror = bookmarks.treeForMirror().value.successValue else { + XCTFail("Couldn't get mirror!") + return + } + + XCTAssertFalse(mirror.isEmpty) + XCTAssertTrue(mirror.subtrees[0].recordGUID == BookmarkRoots.RootGUID) + let edgesAfter = bookmarks.treesForEdges().value.successValue! + XCTAssertTrue(edgesAfter.local.isEmpty) + XCTAssertTrue(edgesAfter.buffer.isEmpty) + + XCTAssertEqual(uploader.added, Set(BookmarkRoots.RootChildren.map(BookmarkRoots.translateOutgoingRootGUID))) + } + + func testComplexOrphaning() { + // This test describes a scenario like this: + // + // [] [] [] + // [M] [T] [M] [T] [M] [T] + // | | | | | | + // [C] [A] [C] [A] [C] [A] + // | | | | + // [D] [D] [B] [B] + // | | + // F E + // + // That is: we have locally added 'E' to folder B and deleted folder D, + // and remotely added 'F' to folder D and deleted folder B. + // + // This is a fundamental conflict that would ordinarily produce orphans. + // Our resolution for this is to put those orphans _somewhere_. + // + // That place is the lowest surviving parent: walk the tree until we find + // a folder that still exists, and put the orphans there. This is a little + // better than just dumping the records into Unsorted Bookmarks, and no + // more complex than dumping them into the closest root. + // + // We expect: + // + // [] + // [M] [T] + // | | + // [C] [A] + // | | + // F E + // + guard let bookmarks = self.getSyncableBookmarks(name: "G") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Set up the mirror. + let dateAdded = Date.now() - 200000 + let mirrorDate = Date.now() - 100000 + let records = [ + BookmarkMirrorItem.folder(BookmarkRoots.RootGUID, dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "", description: "", children: BookmarkRoots.RootChildren), + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: ["folderCCCCCC"]), + BookmarkMirrorItem.folder(BookmarkRoots.UnfiledFolderGUID, dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Unsorted Bookmarks", description: "", children: []), + BookmarkMirrorItem.folder(BookmarkRoots.ToolbarFolderGUID, dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Toolbar", description: "", children: ["folderAAAAAA"]), + BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Mobile Bookmarks", description: "", children: []), + BookmarkMirrorItem.folder("folderAAAAAA", dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: "Bookmarks Toolbar", title: "A", description: "", children: ["folderBBBBBB"]), + BookmarkMirrorItem.folder("folderBBBBBB", dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: "folderAAAAAA", parentName: "A", title: "B", description: "", children: []), + BookmarkMirrorItem.folder("folderCCCCCC", dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.MenuFolderGUID, parentName: "Bookmarks Menu", title: "C", description: "", children: ["folderDDDDDD"]), + BookmarkMirrorItem.folder("folderDDDDDD", dateAdded: dateAdded, modified: mirrorDate, hasDupe: false, parentID: "folderCCCCCC", parentName: "C", title: "D", description: "", children: []), + ] + + bookmarks.populateMirrorViaBuffer(items: records, atDate: mirrorDate) + bookmarks.wipeLocal() + + // Now the buffer is empty, and the mirror tree is what we expect. + let mirrorTree = bookmarks.treeForMirror().value.successValue! + XCTAssertFalse(mirrorTree.isEmpty) + + XCTAssertEqual(mirrorTree.lookup.keys.count, 9) + XCTAssertEqual(1, mirrorTree.subtrees.count) + XCTAssertEqual(mirrorTree.find("folderAAAAAA")!.children!.map { $0.recordGUID }, ["folderBBBBBB"]) + XCTAssertEqual(mirrorTree.find("folderCCCCCC")!.children!.map { $0.recordGUID }, ["folderDDDDDD"]) + + let edgesBefore = bookmarks.treesForEdges().value.successValue! + XCTAssertTrue(edgesBefore.local.isEmpty) // Because we're fully synced. + XCTAssertTrue(edgesBefore.buffer.isEmpty) + + // Set up the buffer. + let bufferDate = Date.now() + let changedBufferRecords = [ + BookmarkMirrorItem.deleted(BookmarkNodeType.folder, guid: "folderBBBBBB", modified: bufferDate), + BookmarkMirrorItem.folder("folderAAAAAA", dateAdded: dateAdded, modified: bufferDate, hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: "Bookmarks Toolbar", title: "A", description: "", children: []), + BookmarkMirrorItem.folder("folderDDDDDD", dateAdded: dateAdded, modified: bufferDate, hasDupe: false, parentID: "folderCCCCCC", parentName: "C", title: "D", description: "", children: ["bookmarkFFFF"]), + BookmarkMirrorItem.bookmark("bookmarkFFFF", dateAdded: dateAdded, modified: bufferDate, hasDupe: false, parentID: "folderDDDDDD", parentName: "D", title: "F", description: nil, URI: "http://example.com/f", tags: "", keyword: nil), + ] + + bookmarks.applyRecords(changedBufferRecords).succeeded() + + // Make local changes. + bookmarks.local.modelFactory.value.successValue!.removeByGUID("folderDDDDDD").succeeded() + bookmarks.local.insertBookmark("http://example.com/e".asURL!, title: "E", favicon: nil, intoFolder: "folderBBBBBB", withTitle: "B").succeeded() + let insertedGUID = bookmarks.local.db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) WHERE title IS 'E'")[0] + + let edges = bookmarks.treesForEdges().value.successValue! + + XCTAssertFalse(edges.local.isEmpty) + XCTAssertFalse(edges.buffer.isEmpty) + XCTAssertTrue(edges.local.isFullyRootedIn(mirrorTree)) + XCTAssertTrue(edges.buffer.isFullyRootedIn(mirrorTree)) + XCTAssertTrue(edges.buffer.deleted.contains("folderBBBBBB")) + XCTAssertFalse(edges.buffer.deleted.contains("folderDDDDDD")) + XCTAssertFalse(edges.local.deleted.contains("folderBBBBBB")) + XCTAssertTrue(edges.local.deleted.contains("folderDDDDDD")) + + // Now merge. + let storageMerger = ThreeWayBookmarksStorageMerger(buffer: bookmarks, storage: bookmarks) + let merger = storageMerger.getMerger().value.successValue! + guard let mergedTree = merger.produceMergedTree().value.successValue else { + XCTFail("Couldn't get merge result.") + return + } + + // Dump it so we can see it. + mergedTree.dump() + + XCTAssertTrue(mergedTree.deleteLocally.contains("folderBBBBBB")) + XCTAssertTrue(mergedTree.deleteFromMirror.contains("folderBBBBBB")) + XCTAssertTrue(mergedTree.deleteRemotely.contains("folderDDDDDD")) + XCTAssertTrue(mergedTree.deleteFromMirror.contains("folderDDDDDD")) + XCTAssertTrue(mergedTree.acceptLocalDeletion.contains("folderDDDDDD")) + XCTAssertTrue(mergedTree.acceptRemoteDeletion.contains("folderBBBBBB")) + + // E and F still exist, in Menu and Toolbar respectively. + // Note that the merge itself includes asserts for this; we shouldn't even get here if + // this part will fail. + XCTAssertTrue(mergedTree.allGUIDs.contains(insertedGUID)) + XCTAssertTrue(mergedTree.allGUIDs.contains("bookmarkFFFF")) + + let menu = mergedTree.root.mergedChildren![0] // menu, toolbar, unfiled, mobile, so 0. + let toolbar = mergedTree.root.mergedChildren![1] // menu, toolbar, unfiled, mobile, so 1. + XCTAssertEqual(BookmarkRoots.MenuFolderGUID, menu.guid) + XCTAssertEqual(BookmarkRoots.ToolbarFolderGUID, toolbar.guid) + + let folderC = menu.mergedChildren![0] + let folderA = toolbar.mergedChildren![0] + XCTAssertEqual("folderCCCCCC", folderC.guid) + XCTAssertEqual("folderAAAAAA", folderA.guid) + + XCTAssertEqual(insertedGUID, folderA.mergedChildren![0].guid) + XCTAssertEqual("bookmarkFFFF", folderC.mergedChildren![0].guid) + + guard let result = merger.produceMergeResultFromMergedTree(mergedTree).value.successValue else { + XCTFail("Couldn't get merge result.") + return + } + + XCTAssertFalse(result.isNoOp) + + // Everything in local is getting dropped. + let formerLocalIDs = Set(edges.local.lookup.keys) + XCTAssertTrue(result.overrideCompletion.processedLocalChanges.isSuperset(of: formerLocalIDs)) + + // Everything in the buffer is getting dropped. + let formerBufferIDs = Set(edges.buffer.lookup.keys) + XCTAssertTrue(result.bufferCompletion.processedBufferChanges.isSuperset(of: formerBufferIDs)) + + // The mirror will now contain everything added by each side, and not the deleted folders. + XCTAssertEqual(result.overrideCompletion.mirrorItemsToDelete, Set(["folderBBBBBB", "folderDDDDDD"])) + XCTAssertTrue(result.overrideCompletion.mirrorValuesToCopyFromLocal.isEmpty) + XCTAssertTrue(result.overrideCompletion.mirrorValuesToCopyFromBuffer.isEmpty) + XCTAssertTrue(result.overrideCompletion.mirrorItemsToInsert.keys.contains(insertedGUID)) // Because it was reparented. + XCTAssertTrue(result.overrideCompletion.mirrorItemsToInsert.keys.contains("bookmarkFFFF")) // Because it was reparented. + + // The mirror now has the right structure. + XCTAssertEqual(result.overrideCompletion.mirrorStructures["folderCCCCCC"]!, ["bookmarkFFFF"]) + XCTAssertEqual(result.overrideCompletion.mirrorStructures["folderAAAAAA"]!, [insertedGUID]) + + // We're going to upload new records for C (lost a child), F (changed parent), + // insertedGUID (new local record), A (new child), and D (deleted). + + // Anything that was in the mirror and only changed structure: + let expected: [GUID: [GUID]] = ["folderCCCCCC": ["bookmarkFFFF"], "folderAAAAAA": [insertedGUID]] + let actual: [GUID: [GUID]] = result.uploadCompletion.amendChildrenFromMirror + XCTAssertEqual(actual as NSDictionary, expected as NSDictionary) + + // Anything deleted: + XCTAssertTrue(result.uploadCompletion.records.contains(where: { (($0.id == "folderDDDDDD") && ($0.payload["deleted"].bool ?? false)) })) + + // Inserted: + let uploadE = result.uploadCompletion.records.find { $0.id == insertedGUID } + XCTAssertNotNil(uploadE) + XCTAssertEqual(uploadE!.payload["title"].stringValue, "E") + + // We fixed the parent before uploading. + XCTAssertEqual(uploadE!.payload["parentid"].stringValue, "folderAAAAAA") + XCTAssertEqual(uploadE!.payload["parentName"].string ?? "", "A") + + // Reparented: + let uploadF = result.uploadCompletion.records.find { $0.id == "bookmarkFFFF" } + XCTAssertNotNil(uploadF) + XCTAssertEqual(uploadF!.payload["title"].stringValue, "F") + + // We fixed the parent before uploading. + XCTAssertEqual(uploadF!.payload["parentid"].stringValue, "folderCCCCCC") + XCTAssertEqual(uploadF!.payload["parentName"].string ?? "", "C") + } + + func testComplexMoveWithAdditions() { + // This test describes a scenario like this: + // + // [] [] [] + // [X] [Y] [X] [Y] [X] [Y] + // | | | | + // [A] C [A] [A] + // / \ / \ / | \ + // B E B C B D C + // + // That is: we have locally added 'D' to folder A, and remotely moved + // A to a different root, added 'E', and moved 'C' back to the old root. + // + // Our expected result is: + // + // [] + // [X] [Y] + // | | + // [A] C + // / | \ + // B D E + // + // … but we'll settle for any order of children for [A] that preserves B < E + // and B < D -- in other words, (B E D) and (B D E) are both acceptable. + // + guard let bookmarks = self.getSyncableBookmarks(name: "F") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Set up the mirror. + let mirrorDate = Date.now() - 100000 + let records = [ + BookmarkMirrorItem.folder(BookmarkRoots.RootGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "", description: "", children: BookmarkRoots.RootChildren), + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: ["folderAAAAAA"]), + BookmarkMirrorItem.folder(BookmarkRoots.UnfiledFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Unsorted Bookmarks", description: "", children: []), + BookmarkMirrorItem.folder(BookmarkRoots.ToolbarFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Toolbar", description: "", children: []), + BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Mobile Bookmarks", description: "", children: []), + BookmarkMirrorItem.folder("folderAAAAAA", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.MenuFolderGUID, parentName: "Bookmarks Menu", title: "A", description: "", children: ["bookmarkBBBB", "bookmarkCCCC"]), + BookmarkMirrorItem.bookmark("bookmarkBBBB", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: "folderAAAAAA", parentName: "A", title: "B", description: nil, URI: "http://example.com/b", tags: "", keyword: nil), + BookmarkMirrorItem.bookmark("bookmarkCCCC", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: "folderAAAAAA", parentName: "A", title: "C", description: nil, URI: "http://example.com/c", tags: "", keyword: nil), + ] + + bookmarks.populateMirrorViaBuffer(items: records, atDate: mirrorDate) + bookmarks.wipeLocal() + + // Now the buffer is empty, and the mirror tree is what we expect. + let mirrorTree = bookmarks.treeForMirror().value.successValue! + XCTAssertFalse(mirrorTree.isEmpty) + + XCTAssertEqual(mirrorTree.lookup.keys.count, 8) + XCTAssertEqual(1, mirrorTree.subtrees.count) + XCTAssertEqual(mirrorTree.find("folderAAAAAA")!.children!.map { $0.recordGUID }, ["bookmarkBBBB", "bookmarkCCCC"]) + + let edgesBefore = bookmarks.treesForEdges().value.successValue! + XCTAssertTrue(edgesBefore.local.isEmpty) // Because we're fully synced. + XCTAssertTrue(edgesBefore.buffer.isEmpty) + + // Set up the buffer. + let bufferDate = Date.now() + let changedBufferRecords = [ + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: bufferDate, modified: bufferDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: ["bookmarkCCCC"]), + BookmarkMirrorItem.folder(BookmarkRoots.ToolbarFolderGUID, dateAdded: bufferDate, modified: bufferDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Toolbar", description: "", children: ["folderAAAAAA"]), + BookmarkMirrorItem.folder("folderAAAAAA", dateAdded: bufferDate, modified: bufferDate, hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: "Bookmarks Toolbar", title: "A", description: "", children: ["bookmarkBBBB", "bookmarkEEEE"]), + BookmarkMirrorItem.bookmark("bookmarkCCCC", dateAdded: bufferDate, modified: bufferDate, hasDupe: false, parentID: BookmarkRoots.MenuFolderGUID, parentName: "A", title: "C", description: nil, URI: "http://example.com/c", tags: "", keyword: nil), + BookmarkMirrorItem.bookmark("bookmarkEEEE", dateAdded: bufferDate, modified: bufferDate, hasDupe: false, parentID: "folderAAAAAA", parentName: "A", title: "E", description: nil, URI: "http://example.com/e", tags: "", keyword: nil), + ] + + bookmarks.applyRecords(changedBufferRecords).succeeded() + let populatedBufferTree = bookmarks.treesForEdges().value.successValue!.buffer + XCTAssertFalse(populatedBufferTree.isEmpty) + XCTAssertTrue(populatedBufferTree.isFullyRootedIn(mirrorTree)) + XCTAssertFalse(populatedBufferTree.find("bookmarkEEEE")!.isUnknown) + XCTAssertFalse(populatedBufferTree.find("bookmarkCCCC")!.isUnknown) + XCTAssertTrue(populatedBufferTree.find("bookmarkBBBB")!.isUnknown) + + // Now let's make local changes with the API. + bookmarks.local.insertBookmark("http://example.com/d".asURL!, title: "D (local)", favicon: nil, intoFolder: "folderAAAAAA", withTitle: "A").succeeded() + + let populatedLocalTree = bookmarks.treesForEdges().value.successValue!.local + let newMirrorTree = bookmarks.treeForMirror().value.successValue! + XCTAssertEqual(1, newMirrorTree.subtrees.count) + + XCTAssertFalse(populatedLocalTree.isEmpty) + XCTAssertTrue(populatedLocalTree.isFullyRootedIn(mirrorTree)) + XCTAssertTrue(populatedLocalTree.isFullyRootedIn(newMirrorTree)) // It changed. + XCTAssertNil(populatedLocalTree.find("bookmarkEEEE")) + XCTAssertTrue(populatedLocalTree.find("bookmarkCCCC")!.isUnknown) + XCTAssertTrue(populatedLocalTree.find("bookmarkBBBB")!.isUnknown) + XCTAssertFalse(populatedLocalTree.find("folderAAAAAA")!.isUnknown) + + // Now merge. + let storageMerger = ThreeWayBookmarksStorageMerger(buffer: bookmarks, storage: bookmarks) + let merger = storageMerger.getMerger().value.successValue! + guard let mergedTree = merger.produceMergedTree().value.successValue else { + XCTFail("Couldn't get merge result.") + return + } + + // Dump it so we can see it. + mergedTree.dump() + + guard let menu = mergedTree.root.mergedChildren?[0] else { + XCTFail("Expected a child of the root.") + return + } + + XCTAssertEqual(menu.guid, BookmarkRoots.MenuFolderGUID) + XCTAssertEqual(menu.mergedChildren?[0].guid, "bookmarkCCCC") + + guard let toolbar = mergedTree.root.mergedChildren?[1] else { + XCTFail("Expected a second child of the root.") + return + } + + XCTAssertEqual(toolbar.guid, BookmarkRoots.ToolbarFolderGUID) + let toolbarChildren = toolbar.mergedChildren! + XCTAssertEqual(toolbarChildren.count, 1) // A. + let aaa = toolbarChildren[0] + XCTAssertEqual(aaa.guid, "folderAAAAAA") + let aaaChildren = aaa.mergedChildren! + + XCTAssertEqual(aaaChildren.count, 3) // B, E, new local. + XCTAssertFalse(aaaChildren.contains { $0.guid == "bookmarkCCCC" }) + } + + func testApplyingTwoEmptyFoldersDoesntSmush() { + guard let bookmarks = self.getSyncableBookmarks(name: "C") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Insert two identical folders. We mark them with hasDupe because that's the Syncy + // thing to do. + let now = Date.now() + let records = [ + BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: now, modified: now, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Mobile Bookmarks", description: "", children: ["emptyempty01", "emptyempty02"]), + BookmarkMirrorItem.folder("emptyempty01", dateAdded: now, modified: now, hasDupe: true, parentID: BookmarkRoots.MobileFolderGUID, parentName: "Mobile Bookmarks", title: "Empty", description: "", children: []), + BookmarkMirrorItem.folder("emptyempty02", dateAdded: now, modified: now, hasDupe: true, parentID: BookmarkRoots.MobileFolderGUID, parentName: "Mobile Bookmarks", title: "Empty", description: "", children: []), + ] + + bookmarks.buffer.applyRecords(records).succeeded() + + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBuffer)", int: 3) + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBufferStructure)", int: 2) + + let storageMerger = ThreeWayBookmarksStorageMerger(buffer: bookmarks, storage: bookmarks) + let merger = storageMerger.getMerger().value.successValue! + guard let mergedTree = merger.produceMergedTree().value.successValue else { + XCTFail("Couldn't get merge result.") + return + } + + // Dump it so we can see it. + mergedTree.dump() + + // Now let's look at the tree. + XCTAssertTrue(mergedTree.deleteFromMirror.isEmpty) + XCTAssertEqual(BookmarkRoots.RootGUID, mergedTree.root.guid) + XCTAssertEqual(BookmarkRoots.RootGUID, mergedTree.root.mirror?.recordGUID) + XCTAssertNil(mergedTree.root.remote) + + XCTAssertTrue(MergeState.unchanged == mergedTree.root.valueState) + XCTAssertTrue(MergeState.unchanged == mergedTree.root.structureState) + XCTAssertEqual(4, mergedTree.root.mergedChildren?.count) + + guard let mergedMobile = mergedTree.root.mergedChildren?[BookmarkRoots.RootChildren.index(of: BookmarkRoots.MobileFolderGUID) ?? -1] else { + XCTFail("Didn't get a merged mobile folder.") + return + } + + XCTAssertEqual(BookmarkRoots.MobileFolderGUID, mergedMobile.guid) + XCTAssertTrue(MergeState.remote == mergedMobile.valueState) + + // This ends up as Remote because we didn't change any of its structure + // when compared to the incoming record. + guard case MergeState.remote = mergedMobile.structureState else { + XCTFail("Didn't get expected Remote state.") + return + } + + XCTAssertEqual(["emptyempty01", "emptyempty02"], mergedMobile.remote!.children!.map { $0.recordGUID }) + XCTAssertEqual(["emptyempty01", "emptyempty02"], mergedMobile.asMergedTreeNode().children!.map { $0.recordGUID }) + XCTAssertEqual(["emptyempty01", "emptyempty02"], mergedMobile.mergedChildren!.map { $0.guid }) + let empty01 = mergedMobile.mergedChildren![0] + let empty02 = mergedMobile.mergedChildren![1] + XCTAssertNil(empty01.local) + XCTAssertNil(empty02.local) + XCTAssertNil(empty01.mirror) + XCTAssertNil(empty02.mirror) + XCTAssertNotNil(empty01.remote) + XCTAssertNotNil(empty02.remote) + XCTAssertEqual("emptyempty01", empty01.remote!.recordGUID) + XCTAssertEqual("emptyempty02", empty02.remote!.recordGUID) + XCTAssertTrue(MergeState.remote == empty01.structureState) + XCTAssertTrue(MergeState.remote == empty02.structureState) + XCTAssertTrue(MergeState.remote == empty01.valueState) + XCTAssertTrue(MergeState.remote == empty02.valueState) + XCTAssertTrue(empty01.mergedChildren?.isEmpty ?? false) + XCTAssertTrue(empty02.mergedChildren?.isEmpty ?? false) + + guard let result = merger.produceMergeResultFromMergedTree(mergedTree).value.successValue else { + XCTFail("Couldn't get merge result.") + return + } + + let uploader = MockUploader() + let storer = uploader.getStorer() + let applier = MergeApplier(buffer: bookmarks, storage: bookmarks, client: storer, statsSession: mockStatsSessionForBookmarks(), greenLight: { true }) + applier.applyResult(result).succeeded() + + guard let mirror = bookmarks.treeForMirror().value.successValue else { + XCTFail("Couldn't get mirror!") + return + } + + // After merge, the buffer and local are empty. + let edgesAfter = bookmarks.treesForEdges().value.successValue! + XCTAssertTrue(edgesAfter.local.isEmpty) + XCTAssertTrue(edgesAfter.buffer.isEmpty) + + // When merged in, we do not smush these two records together! + XCTAssertFalse(mirror.isEmpty) + XCTAssertTrue(mirror.subtrees[0].recordGUID == BookmarkRoots.RootGUID) + XCTAssertNotNil(mirror.find("emptyempty01")) + XCTAssertNotNil(mirror.find("emptyempty02")) + XCTAssertTrue(mirror.deleted.isEmpty) + guard let mobile = mirror.find(BookmarkRoots.MobileFolderGUID) else { + XCTFail("No mobile folder in mirror.") + return + } + + if case let .folder(_, children) = mobile { + XCTAssertEqual(children.map { $0.recordGUID }, ["emptyempty01", "emptyempty02"]) + } else { + XCTFail("Mobile isn't a folder.") + } + } + + /** + * Input: + * + * [M] [] [M] + * _______|_______ _____|_____ + * / | \ / \ + * [e01] [e02] [e03] [e02] [eL0] + * + * Expected output: + * + * Take remote, delete emptyemptyL0, upload the roots that + * weren't remotely present. + */ + func testApplyingTwoEmptyFoldersMatchesOnlyOne() { + guard let bookmarks = self.getSyncableBookmarks(name: "D") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Insert three identical folders. We mark them with hasDupe because that's the Syncy + // thing to do. + let now = Date.now() + let records = [ + BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: now, modified: now, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Mobile Bookmarks", description: "", children: ["emptyempty01", "emptyempty02", "emptyempty03"]), + BookmarkMirrorItem.folder("emptyempty01", dateAdded: now, modified: now, hasDupe: true, parentID: BookmarkRoots.MobileFolderGUID, parentName: "Mobile Bookmarks", title: "Empty", description: "", children: []), + BookmarkMirrorItem.folder("emptyempty02", dateAdded: now, modified: now, hasDupe: true, parentID: BookmarkRoots.MobileFolderGUID, parentName: "Mobile Bookmarks", title: "Empty", description: "", children: []), + BookmarkMirrorItem.folder("emptyempty03", dateAdded: now, modified: now, hasDupe: true, parentID: BookmarkRoots.MobileFolderGUID, parentName: "Mobile Bookmarks", title: "Empty", description: "", children: []), + ] + + bookmarks.buffer.validate().succeeded() // It's valid! Empty. + bookmarks.buffer.applyRecords(records).succeeded() + bookmarks.buffer.validate().succeeded() // It's valid! Rooted in mobile_______. + + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBuffer)", int: 4) + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBufferStructure)", int: 3) + + // Add one matching empty folder locally. + // Add one by GUID, too. This is the most complex possible case. + bookmarks.local.db.run("INSERT INTO \(TableBookmarksLocal) (guid, type, date_added, title, parentid, parentName, sync_status, local_modified) VALUES ('emptyempty02', \(BookmarkNodeType.folder.rawValue), \(now), 'Empty', '\(BookmarkRoots.MobileFolderGUID)', 'Mobile Bookmarks', \(SyncStatus.changed.rawValue), \(Date.now()))").succeeded() + bookmarks.local.db.run("INSERT INTO \(TableBookmarksLocal) (guid, type, date_added, title, parentid, parentName, sync_status, local_modified) VALUES ('emptyemptyL0', \(BookmarkNodeType.folder.rawValue), \(now), 'Empty', '\(BookmarkRoots.MobileFolderGUID)', 'Mobile Bookmarks', \(SyncStatus.new.rawValue), \(Date.now()))").succeeded() + bookmarks.local.db.run("INSERT INTO \(TableBookmarksLocalStructure) (parent, child, idx) VALUES ('\(BookmarkRoots.MobileFolderGUID)', 'emptyempty02', 0)").succeeded() + bookmarks.local.db.run("INSERT INTO \(TableBookmarksLocalStructure) (parent, child, idx) VALUES ('\(BookmarkRoots.MobileFolderGUID)', 'emptyemptyL0', 1)").succeeded() + + let uploader = MockUploader() + let storer = uploader.getStorer() + let applier = MergeApplier(buffer: bookmarks, storage: bookmarks, client: storer, statsSession: mockStatsSessionForBookmarks(), greenLight: { true }) + applier.go().succeeded() + + guard let mirror = bookmarks.treeForMirror().value.successValue else { + XCTFail("Couldn't get mirror!") + return + } + + // After merge, the buffer and local are empty. + let edgesAfter = bookmarks.treesForEdges().value.successValue! + + XCTAssertTrue(edgesAfter.local.isEmpty) + XCTAssertTrue(edgesAfter.buffer.isEmpty) + + // All of the incoming records exist. + XCTAssertFalse(mirror.isEmpty) + XCTAssertEqual(mirror.subtrees[0].recordGUID, BookmarkRoots.RootGUID) + XCTAssertNotNil(mirror.find("emptyempty01")) + XCTAssertNotNil(mirror.find("emptyempty02")) + XCTAssertNotNil(mirror.find("emptyempty03")) + + // The other roots are now in the mirror. + XCTAssertTrue(BookmarkRoots.Real.every({ mirror.find($0) != nil })) + + // And are queued for upload. + XCTAssertTrue(uploader.added.contains("toolbar")) + XCTAssertTrue(uploader.added.contains("menu")) + XCTAssertTrue(uploader.added.contains("unfiled")) + XCTAssertFalse(uploader.added.contains("mobile")) // Structure and value didn't change. + + // The local record that was smushed is not present… + XCTAssertNil(mirror.find("emptyemptyL0")) + + // … and because it was marked New, we don't bother trying to delete it. + XCTAssertFalse(uploader.deletions.contains("emptyemptyL0")) + + guard let mobile = mirror.find(BookmarkRoots.MobileFolderGUID) else { + XCTFail("No mobile folder in mirror.") + return + } + + if case let .folder(_, children) = mobile { + // This order isn't strictly specified, but try to preserve the remote order if we can. + XCTAssertEqual(children.map { $0.recordGUID }, ["emptyempty01", "emptyempty02", "emptyempty03"]) + } else { + XCTFail("Mobile isn't a folder.") + } + } + + // TODO: this test should be extended to also exercise the case of a conflict. + func testLocalRecordsKeepTheirFavicon() { + guard let bookmarks = self.getSyncableBookmarks(name: "E") else { + XCTFail("Couldn't get bookmarks.") + return + } + + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBuffer)", int: 0) + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBufferStructure)", int: 0) + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksLocal)", int: 5) + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksLocalStructure)", int: 4) + + bookmarks.local.db.run("INSERT INTO \(TableFavicons) (id, url, width, height, type, date) VALUES (11, 'http://example.org/favicon.ico', 16, 16, 0, \(Date.now()))").succeeded() + bookmarks.local.db.run("INSERT INTO \(TableBookmarksLocal) (guid, type, date_added, title, parentid, parentName, sync_status, bmkUri, faviconID) VALUES ('somebookmark', \(BookmarkNodeType.bookmark.rawValue), \(Date.now()), 'Some Bookmark', '\(BookmarkRoots.MobileFolderGUID)', 'Mobile Bookmarks', \(SyncStatus.new.rawValue), 'http://example.org/', 11)").succeeded() + bookmarks.local.db.run("INSERT INTO \(TableBookmarksLocalStructure) (parent, child, idx) VALUES ('\(BookmarkRoots.MobileFolderGUID)', 'somebookmark', 0)").succeeded() + + let uploader = MockUploader() + let storer = uploader.getStorer() + let applier = MergeApplier(buffer: bookmarks, storage: bookmarks, client: storer, statsSession: mockStatsSessionForBookmarks(), greenLight: { true }) + applier.go().succeeded() + + // After merge, the buffer and local are empty. + let edgesAfter = bookmarks.treesForEdges().value.successValue! + XCTAssertTrue(edgesAfter.local.isEmpty) + XCTAssertTrue(edgesAfter.buffer.isEmpty) + + // New record was uploaded. + XCTAssertTrue(uploader.added.contains("somebookmark")) + + // So were all the roots, with the Sync-native names. + XCTAssertTrue(uploader.added.contains("toolbar")) + XCTAssertTrue(uploader.added.contains("menu")) + XCTAssertTrue(uploader.added.contains("unfiled")) + XCTAssertTrue(uploader.added.contains("mobile")) + + // … but not the Places root. + XCTAssertFalse(uploader.added.contains("places")) + XCTAssertFalse(uploader.added.contains(BookmarkRoots.RootGUID)) + + // Their parent IDs are translated. + XCTAssertEqual(uploader.records["mobile"]?.payload["parentid"].string, "places") + XCTAssertEqual(uploader.records["somebookmark"]?.payload["parentid"].string, "mobile") + + XCTAssertTrue(uploader.deletions.isEmpty) + + // The record looks sane. + let bm = uploader.records["somebookmark"]! + XCTAssertEqual("bookmark", bm.payload["type"].string) + XCTAssertEqual("Some Bookmark", bm.payload["title"].string) + + // New record still has its icon ID in the local DB. + bookmarks.local.db.assertQueryReturns("SELECT faviconID FROM \(TableBookmarksMirror) WHERE bmkUri = 'http://example.org/'", int: 11) + } + + func testRemoteValueOnlyChange() { + guard let bookmarks = self.getSyncableBookmarks(name: "F") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Insert one folder and one child. + let now = Date.now() + let records = [ + BookmarkMirrorItem.folder(BookmarkRoots.UnfiledFolderGUID, dateAdded: Date.now(), modified: now, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Unsorted Bookmarks", description: "", children: ["folderAAAAAA"]), + BookmarkMirrorItem.folder("folderAAAAAA", dateAdded: now, modified: now, hasDupe: false, parentID: BookmarkRoots.UnfiledFolderGUID, parentName: "Unsorted Bookmarks", title: "Folder A", description: "", children: ["bookmarkBBBB"]), + BookmarkMirrorItem.bookmark("bookmarkBBBB", dateAdded: now, modified: now, hasDupe: false, parentID: "folderAAAAAA", parentName: "Folder A", title: "Initial Title", description: "No desc.", URI: "http://example.org/foo", tags: "", keyword: nil), + ] + + bookmarks.buffer.validate().succeeded() // It's valid! Empty. + bookmarks.buffer.applyRecords(records).succeeded() + bookmarks.buffer.validate().succeeded() // It's valid! Rooted in mobile_______. + + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBuffer)", int: 3) + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBufferStructure)", int: 2) + + let uploader = MockUploader() + let storer = uploader.getStorer() + let applier = MergeApplier(buffer: bookmarks, storage: bookmarks, client: storer, statsSession: mockStatsSessionForBookmarks(), greenLight: { true }) + applier.go().succeeded() + + guard let _ = bookmarks.treeForMirror().value.successValue else { + XCTFail("Couldn't get mirror!") + return + } + + // After merge, the buffer and local are empty. + let edgesAfter = bookmarks.treesForEdges().value.successValue! + + XCTAssertTrue(edgesAfter.local.isEmpty) + XCTAssertTrue(edgesAfter.buffer.isEmpty) + + // Check the title. + let folder = bookmarks.modelFactory.value.successValue! + .modelForFolder("folderAAAAAA").value.successValue!.current[0]! + XCTAssertEqual(folder.title, "Initial Title") + + // Now process an incoming change. + let changed = [ + BookmarkMirrorItem.bookmark("bookmarkBBBB", dateAdded: now, modified: now, hasDupe: false, parentID: "folderAAAAAA", parentName: "Folder A", title: "New Title", description: "No desc.", URI: "http://example.org/foo", tags: "", keyword: nil), + ] + + bookmarks.buffer.validate().succeeded() // It's valid! Empty. + bookmarks.buffer.applyRecords(changed).succeeded() + bookmarks.buffer.validate().succeeded() // It's valid! One record. + + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBuffer)", int: 1) + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBufferStructure)", int: 0) + + let uu = MockUploader() + let ss = uu.getStorer() + let changeApplier = MergeApplier(buffer: bookmarks, storage: bookmarks, client: ss, statsSession: mockStatsSessionForBookmarks(), greenLight: { true }) + changeApplier.go().succeeded() + + // The title changed. + let updatedFolder = bookmarks.modelFactory.value.successValue! + .modelForFolder("folderAAAAAA").value.successValue!.current[0]! + XCTAssertEqual(updatedFolder.title, "New Title") + + // The buffer is empty. + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBuffer)", int: 0) + bookmarks.buffer.db.assertQueryReturns("SELECT COUNT(*) FROM \(TableBookmarksBufferStructure)", int: 0) + } + + func testMergeDateAdded() { + guard let bookmarks = self.getSyncableBookmarks(name: "H") else { + XCTFail("Couldn't get bookmarks.") + return + } + + // Set up the mirror. + let mirrorDate = Date.now() - 100000 + let records = [ + BookmarkMirrorItem.folder(BookmarkRoots.RootGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "", description: "", children: BookmarkRoots.RootChildren), + BookmarkMirrorItem.folder(BookmarkRoots.MenuFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Menu", description: "", children: []), + BookmarkMirrorItem.folder(BookmarkRoots.UnfiledFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Unsorted Bookmarks", description: "", children: []), + BookmarkMirrorItem.folder(BookmarkRoots.ToolbarFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Bookmarks Toolbar", description: "", children: ["folderAAAAAA"]), + BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: "", title: "Mobile Bookmarks", description: "", children: []), + BookmarkMirrorItem.folder("folderAAAAAA", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: "Bookmarks Toolbar", title: "A", description: "", children: []), + ] + + bookmarks.populateMirrorViaBuffer(items: records, atDate: mirrorDate) + bookmarks.wipeLocal() + + // Now the buffer is empty, and the mirror tree is what we expect. + let mirrorTree = bookmarks.treeForMirror().value.successValue! + XCTAssertFalse(mirrorTree.isEmpty) + + XCTAssertEqual(mirrorTree.lookup.keys.count, 6) + XCTAssertEqual(1, mirrorTree.subtrees.count) + + let edgesBefore = bookmarks.treesForEdges().value.successValue! + XCTAssertTrue(edgesBefore.local.isEmpty) // Because we're fully synced. + XCTAssertTrue(edgesBefore.buffer.isEmpty) + + // Make local changes. + bookmarks.local.insertBookmark("http://example.com/f".asURL!, title: "F", favicon: nil, intoFolder: "folderAAAAAA", withTitle: "A").succeeded() + let insertedGUID = bookmarks.local.db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) WHERE title IS 'F'")[0] + bookmarks.local.insertBookmark("http://example.com/g".asURL!, title: "G", favicon: nil, intoFolder: "folderAAAAAA", withTitle: "A").succeeded() + let insertedGUID2 = bookmarks.local.db.getGUIDs("SELECT guid FROM \(TableBookmarksLocal) WHERE title IS 'G'")[0] + + // Set up the buffer. + let bufferDate = Date.now() - 100000 + let dateAfter = Date.now() + let changedBufferRecords = [ + BookmarkMirrorItem.folder("folderAAAAAA", dateAdded: mirrorDate, modified: mirrorDate, hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: "Bookmarks Toolbar", title: "A", description: "", children: [insertedGUID, insertedGUID2]), + BookmarkMirrorItem.bookmark(insertedGUID, dateAdded: bufferDate, modified: bufferDate, hasDupe: false, parentID: "folderAAAAAA", parentName: "A", title: "F", description: nil, URI: "http://example.com/f", tags: "", keyword: nil), + BookmarkMirrorItem.bookmark(insertedGUID2, dateAdded: dateAfter, modified: bufferDate, hasDupe: false, parentID: "folderAAAAAA", parentName: "A", title: "G", description: nil, URI: "http://example.com/g", tags: "", keyword: nil), + ] + + bookmarks.applyRecords(changedBufferRecords).succeeded() + + // Now merge. + let storageMerger = ThreeWayBookmarksStorageMerger(buffer: bookmarks, storage: bookmarks) + let merger = storageMerger.getMerger().value.successValue! + guard let mergedTree = merger.produceMergedTree().value.successValue else { + XCTFail("Couldn't get merge result.") + return + } + + mergedTree.dump() + + let folderChildren = mergedTree.root.mergedChildren!.find{ $0.guid == BookmarkRoots.ToolbarFolderGUID }!.mergedChildren!.find { $0.guid == "folderAAAAAA" }!.mergedChildren! + + if case .new(let value) = folderChildren[0].valueState { + XCTAssertEqual(value.dateAdded, bufferDate) + } else { + XCTFail() + } + + guard case .local = folderChildren[1].valueState else { + XCTFail() + return + } + } +} + +class TestMergedTree: FailFastTestCase { + func testInitialState() { + let children = BookmarkRoots.RootChildren.map { BookmarkTreeNode.unknown(guid: $0) } + let root = BookmarkTreeNode.folder(guid: BookmarkRoots.RootGUID, children: children) + let tree = MergedTree(mirrorRoot: root) + XCTAssertTrue(tree.root.hasDecidedChildren) + + if case let .folder(guid, unmergedChildren) = tree.root.asUnmergedTreeNode() { + XCTAssertEqual(guid, BookmarkRoots.RootGUID) + XCTAssertEqual(unmergedChildren, children) + } else { + XCTFail("Root should start as Folder.") + } + + // We haven't processed the children. + XCTAssertNil(tree.root.mergedChildren) + XCTAssertTrue(tree.root.asMergedTreeNode().isUnknown) + + // Simulate a merge. + let mergedRoots = children.map { MergedTreeNode(guid: $0.recordGUID, mirror: $0, structureState: MergeState.unchanged) } + tree.root.mergedChildren = mergedRoots + + // Now we have processed children. + XCTAssertNotNil(tree.root.mergedChildren) + XCTAssertFalse(tree.root.asMergedTreeNode().isUnknown) + } +} + +private extension MergedSQLiteBookmarks { + func populateMirrorViaBuffer(items: [BookmarkMirrorItem], atDate mirrorDate: Timestamp) { + self.applyRecords(items).succeeded() + + // … and add the root relationships that will be missing (we don't do those for the buffer, + // so we need to manually add them and move them across). + self.buffer.db.run([ + "INSERT INTO \(TableBookmarksBufferStructure) (parent, child, idx) VALUES", + "('\(BookmarkRoots.RootGUID)', '\(BookmarkRoots.MenuFolderGUID)', 0),", + "('\(BookmarkRoots.RootGUID)', '\(BookmarkRoots.ToolbarFolderGUID)', 1),", + "('\(BookmarkRoots.RootGUID)', '\(BookmarkRoots.UnfiledFolderGUID)', 2),", + "('\(BookmarkRoots.RootGUID)', '\(BookmarkRoots.MobileFolderGUID)', 3)", + ].joined(separator: " ")).succeeded() + + // Move it all to the mirror. + self.local.db.moveBufferToMirrorForTesting() + } + + func wipeLocal() { + self.local.db.run(["DELETE FROM \(TableBookmarksLocalStructure)", "DELETE FROM \(TableBookmarksLocal)"]).succeeded() + } +} diff --git a/mobile/ios/SyncTests/TestBookmarksRepairRequestor.swift b/mobile/ios/SyncTests/TestBookmarksRepairRequestor.swift new file mode 100644 index 0000000000..8fe96b48da --- /dev/null +++ b/mobile/ios/SyncTests/TestBookmarksRepairRequestor.swift @@ -0,0 +1,519 @@ +/* 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/. */ + +import Deferred +import Foundation +import Shared +@testable import Storage +@testable import Sync +@testable import SyncTelemetry +import SwiftyJSON + +import XCTest + +class TestBookmarksRepairRequestor: XCTestCase { + private let MockHashedDeviceID = "4b66918e184c0a9a49c4a9dc7468d3495642141a08419e69c6cb107367366176" + + private func buildMockScratchpad(prefs: Prefs) -> Scratchpad { + var scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + let b = Scratchpad.Builder(p: scratchpad) + b.hashedUID = "1234" + scratchpad = b.build() + + XCTAssertEqual(scratchpad.fxaDeviceId, "unknown_fxaDeviceId") + XCTAssertEqual(scratchpad.hashedDeviceID!, MockHashedDeviceID) + return scratchpad + } + + func testNoClients() { + let expectation = self.expectation(description: #function) + + let prefs = MockProfilePrefs() + let scratchpad = buildMockScratchpad(prefs: prefs) + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (Date.now() - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: nil, fxaDeviceId: nil) + let remoteClients = MockRemoteClientsAndTabs([ClientAndTabs(client: localClient, tabs: [])]) + let validationInfo = [BufferInconsistency.missingValues: ["mock-guid1", "mock-guid2"]] + + let requestor = BookmarksRepairRequestor(scratchpad: scratchpad, basePrefs: prefs, remoteClients: remoteClients) + requestor.startRepairs(validationInfo: validationInfo) >>== { result in + XCTAssertTrue(result) + XCTAssertEqual(remoteClients.commands.count, 1) + XCTAssertEqual(remoteClients.commands["localID"]!.count, 0) + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testOneClientNoResponse() { + let expectation = self.expectation(description: #function) + + let prefs = MockProfilePrefs() + let scratchpad = buildMockScratchpad(prefs: prefs) + + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (Date.now() - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: nil, fxaDeviceId: nil) + let remoteClient = RemoteClient(guid: "client-a", name: "Test remote client", modified: (Date.now() - OneMinuteInMilliseconds), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClients = MockRemoteClientsAndTabs([ClientAndTabs(client: localClient, tabs: []), ClientAndTabs(client: remoteClient, tabs: [])]) + let validationInfo = [BufferInconsistency.missingValues: ["mock-guid1", "mock-guid2"]] + + let mockFlowID = Bytes.generateGUID() + + // Mock telemetry events + let startedEvent = makeRepairEvent(["started", nil, ["flowID": mockFlowID, "numIDs": "2"]]) + let uploadEvent = makeRepairEvent(["request", "upload", ["flowID": mockFlowID, "deviceID": MockHashedDeviceID, "numIDs": "2"]]) + let finishedEvent = makeRepairEvent(["finished", nil, ["flowID": mockFlowID, "numIDs": "2"]]) + + let requestor = BookmarksRepairRequestor(scratchpad: scratchpad, basePrefs: prefs, remoteClients: remoteClients) + requestor.startRepairs(validationInfo: validationInfo, flowID: mockFlowID) >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent) + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + // asking it to continue stays in that state until we timeout or the command + // is removed. + return requestor.continueRepairs() + } >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent) + + // now pretend that client synced. + let _ = remoteClients.deleteCommands("client-a") + return requestor.continueRepairs() + } >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent-again") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent, uploadEvent) + + // the command should be outgoing again. + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + + // pretend that client synced again without writing a command. + let _ = remoteClients.deleteCommands("client-a") + return requestor.continueRepairs() + } >>== { result in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), nil) + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent, uploadEvent, finishedEvent) + + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testOneClientTimeout() { + let expectation = self.expectation(description: #function) + + let prefs = MockProfilePrefs() + let scratchpad = buildMockScratchpad(prefs: prefs) + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (Date.now() - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: nil, fxaDeviceId: nil) + let remoteClient = RemoteClient(guid: "client-a", name: "Test remote client", modified: (Date.now() - OneMinuteInMilliseconds), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClients = MockRemoteClientsAndTabs([ClientAndTabs(client: localClient, tabs: []), ClientAndTabs(client: remoteClient, tabs: [])]) + let validationInfo = [BufferInconsistency.missingValues: ["mock-guid1", "mock-guid2"]] + + // Mock telemetry events + let mockFlowID = Bytes.generateGUID() + let startedEvent = makeRepairEvent(["started", nil, ["flowID": mockFlowID, "numIDs": "2"]]) + let uploadEvent = makeRepairEvent(["request", "upload", ["flowID": mockFlowID, "deviceID": MockHashedDeviceID, "numIDs": "2"]]) + let abandonEvent = makeRepairEvent(["abandon", "silent", ["flowID": mockFlowID, "deviceID": MockHashedDeviceID]]) + let finishedEvent = makeRepairEvent(["finished", nil, ["flowID": mockFlowID, "numIDs": "2"]]) + + let requestor = BookmarksRepairRequestor(scratchpad: scratchpad, basePrefs: prefs, remoteClients: remoteClients) + requestor.startRepairs(validationInfo: validationInfo, flowID: mockFlowID) >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent) + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + // pretend we are now in the future (well actually, that the request was made a long time ago) + prefs.setTimestamp(0, forKey: "repairs.bookmark.when") + return requestor.continueRepairs() + } >>== { result in + // We should be finished as we gave up in disgust. + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), nil) + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent, abandonEvent, finishedEvent) + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testLatestClientUsed() { + let expectation = self.expectation(description: #function) + + let prefs = MockProfilePrefs() + let scratchpad = buildMockScratchpad(prefs: prefs) + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (Date.now() - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: nil, fxaDeviceId: nil) + let clientEarly = RemoteClient(guid: "client-early", name: "Test remote client", modified: (Date.now() - OneWeekInMilliseconds), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let clientLate = RemoteClient(guid: "client-late", name: "Test remote client", modified: (Date.now() - OneMinuteInMilliseconds), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClients = MockRemoteClientsAndTabs([ClientAndTabs(client: localClient, tabs: []), ClientAndTabs(client: clientEarly, tabs: []), ClientAndTabs(client: clientLate, tabs: [])]) + let validationInfo = [BufferInconsistency.missingValues: ["mock-guid1", "mock-guid2"]] + + // Mock telemetry events + let mockFlowID = Bytes.generateGUID() + let startedEvent = makeRepairEvent(["started", nil, ["flowID": mockFlowID, "numIDs": "2"]]) + let uploadEvent = makeRepairEvent(["request", "upload", ["flowID": mockFlowID, "deviceID": MockHashedDeviceID, "numIDs": "2"]]) + + let requestor = BookmarksRepairRequestor(scratchpad: scratchpad, basePrefs: prefs, remoteClients: remoteClients) + requestor.startRepairs(validationInfo: validationInfo, flowID: mockFlowID) >>== { result in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent) + // the repair command should be outgoing to the most-recent client. + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-late") + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testClientVanishes() { + let expectation = self.expectation(description: #function) + + let prefs = MockProfilePrefs() + let scratchpad = buildMockScratchpad(prefs: prefs) + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (Date.now() - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: nil, fxaDeviceId: nil) + let remoteClientA = RemoteClient(guid: "client-a", name: "Test remote client", modified: Date.now(), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClientB = RemoteClient(guid: "client-b", name: "Test remote client", modified: (Date.now() - OneMinuteInMilliseconds), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClients = MockRemoteClientsAndTabs([ClientAndTabs(client: remoteClientA, tabs: []), ClientAndTabs(client: localClient, tabs: []), ClientAndTabs(client: remoteClientB, tabs: [])]) + let validationInfo = [BufferInconsistency.missingValues: ["mock-guid1", "mock-guid2"]] + + // Mock telemetry events + let flowID = Bytes.generateGUID() + let startedEvent = makeRepairEvent(["started", nil, ["flowID": flowID, "numIDs": "2"]]) + let uploadEvent = makeRepairEvent(["request", "upload", ["flowID": flowID, "deviceID": MockHashedDeviceID, "numIDs": "2"]]) + let missingEvent = makeRepairEvent(["abandon", "missing", ["flowID": flowID, "deviceID": MockHashedDeviceID]]) + let responseEvent = makeRepairEvent(["response", "upload", ["flowID": flowID, "deviceID": MockHashedDeviceID, "numIDs": "2"]]) + let finishedEvent = makeRepairEvent(["finished", nil, ["flowID": flowID, "numIDs": "0"]]) + + let requestor = BookmarksRepairRequestor(scratchpad: scratchpad, basePrefs: prefs, remoteClients: remoteClients) + requestor.startRepairs(validationInfo: validationInfo, flowID: flowID) >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent) + + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + // asking it to continue stays in that state until we timeout or the command + // is removed. + return requestor.continueRepairs() + } >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent) + // the command should now be outgoing. + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + + let _ = remoteClients.deleteCommands("client-a") + // Now let's pretend the client vanished. + remoteClients.clientsAndTabs.removeFirst() + return requestor.continueRepairs() + } >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent, missingEvent, uploadEvent) + + // We should have moved on to client-b. + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-b") + + // Now let's pretend client B wrote all missing IDs. + let repairResponse = RepairResponse(collection: "bookmarks", request: "upload", flowID: flowID, clientID: "client-b", ids: ["mock-guid1", "mock-guid2"]) + return requestor.continueRepairs(response: repairResponse) + } >>== { result in + XCTAssertTrue(result) + checkRecordedEvents(fromPrefs: prefs, + expected: startedEvent, uploadEvent, missingEvent, + uploadEvent, responseEvent, finishedEvent) + // We should be finished as we got all our IDs. + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), nil) + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testMultiClients() { + let expectation = self.expectation(description: #function) + + let prefs = MockProfilePrefs() + let scratchpad = buildMockScratchpad(prefs: prefs) + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (Date.now() - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: nil, fxaDeviceId: nil) + let remoteClientA = RemoteClient(guid: "client-a", name: "Test remote client", modified: Date.now(), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClientB = RemoteClient(guid: "client-b", name: "Test remote client", modified: (Date.now() - OneMinuteInMilliseconds), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClients = MockRemoteClientsAndTabs([ClientAndTabs(client: remoteClientA, tabs: []), ClientAndTabs(client: localClient, tabs: []), ClientAndTabs(client: remoteClientB, tabs: [])]) + let validationInfo = [BufferInconsistency.missingValues: ["mock-guid1", "mock-guid2", + "mock-guid3"]] + + let flowID = Bytes.generateGUID() + + // Mock telemetry events + let startedEvent = makeRepairEvent(["started", nil, ["flowID": flowID, "numIDs": "3"]]) + let firstUploadEvent = makeRepairEvent(["request", "upload", ["flowID": flowID, "deviceID": MockHashedDeviceID, "numIDs": "3"]]) + let secondUploadEvent = makeRepairEvent(["request", "upload", ["flowID": flowID, "deviceID": MockHashedDeviceID, "numIDs": "1"]]) + let firstResponseEvent = makeRepairEvent(["response", "upload", ["flowID": flowID, "deviceID": MockHashedDeviceID, "numIDs": "2"]]) + let secondResponseEvent = makeRepairEvent(["response", "upload", ["flowID": flowID, "deviceID": MockHashedDeviceID, "numIDs": "1"]]) + let finishedEvent = makeRepairEvent(["finished", nil, ["flowID": flowID, "numIDs": "0"]]) + + let requestor = BookmarksRepairRequestor(scratchpad: scratchpad, basePrefs: prefs, remoteClients: remoteClients) + requestor.startRepairs(validationInfo: validationInfo, flowID: flowID) >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + // asking it to continue stays in that state until we timeout or the command + // is removed. + return requestor.continueRepairs() + } >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, firstUploadEvent) + + // the command should now be outgoing. + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + + let _ = remoteClients.deleteCommands("client-a") + // Now let's pretend the client wrote a response. + let repairResponse = RepairResponse(collection: "bookmarks", request: "upload", flowID: flowID, clientID: "client-a", ids: ["mock-guid1", "mock-guid2"]) + return requestor.continueRepairs(response: repairResponse) + } >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, + expected: startedEvent, firstUploadEvent, firstResponseEvent, secondUploadEvent) + + // We should have moved on to client-b. + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-b") + + let _ = remoteClients.deleteCommands("client-b") + // Now let's pretend client B write the missing ID. + let repairResponse = RepairResponse(collection: "bookmarks", request: "upload", flowID: flowID, clientID: "client-b", ids: ["mock-guid3"]) + return requestor.continueRepairs(response: repairResponse) + } >>== { result in + XCTAssertTrue(result) + + checkRecordedEvents(fromPrefs: prefs, + expected: startedEvent, firstUploadEvent, firstResponseEvent, secondUploadEvent, secondResponseEvent, finishedEvent) + // We should be finished as we got all our IDs. + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), nil) + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testAlreadyRepairingContinue() { + let expectation = self.expectation(description: #function) + + let prefs = MockProfilePrefs() + let scratchpad = buildMockScratchpad(prefs: prefs) + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (Date.now() - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: nil, fxaDeviceId: nil) + let remoteClientA = RemoteClient(guid: "client-a", name: "Test remote client", modified: Date.now(), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClientB = RemoteClient(guid: "client-b", name: "Test remote client", modified: (Date.now() - OneMinuteInMilliseconds), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClients = MockRemoteClientsAndTabs([ClientAndTabs(client: remoteClientA, tabs: []), ClientAndTabs(client: localClient, tabs: []), ClientAndTabs(client: remoteClientB, tabs: [])]) + let validationInfo = [BufferInconsistency.missingValues: ["mock-guid1", "mock-guid2", "mock-guid3"]] + + // Mock telemetry events + let flowID = Bytes.generateGUID() + let startedEvent = makeRepairEvent(["started", nil, ["flowID": flowID, "numIDs": "3"]]) + let uploadEvent = makeRepairEvent(["request", "upload", ["flowID": flowID, "deviceID": MockHashedDeviceID, "numIDs": "3"]]) + let abortedEvent = makeRepairEvent(["aborted", nil, ["flowID": flowID, "reason": "other clients repairing", "numIDs": "3"]]) + + let requestor = BookmarksRepairRequestor(scratchpad: scratchpad, basePrefs: prefs, remoteClients: remoteClients) + requestor.startRepairs(validationInfo: validationInfo, flowID: flowID) >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + // asking it to continue stays in that state until we timeout or the command + // is removed. + return requestor.continueRepairs() + } >>== { result -> Deferred> in + XCTAssertTrue(result) + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), "repair.sent") + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent) + // the command should now be outgoing. + checkOutgoingCommand(remoteClients: remoteClients, clientID: "client-a") + + let _ = remoteClients.deleteCommands("client-a") + // Now let's pretend the client wrote a response (it doesn't matter what's in here) + let repairResponse = RepairResponse(collection: "bookmarks", request: "upload", flowID: flowID, clientID: "client-a", ids: ["mock-guid1", "mock-guid2"]) + + // and another client also started a request + let otherRequest = RepairRequest(collection: "bookmarks", request: "upload", flowID: "abdc", requestor: "client-c", ids: ["bogusid"]) + let _ = remoteClients.insertCommand(otherRequest.toSyncCommand(), forClients: [remoteClientB]) + + return requestor.continueRepairs(response: repairResponse) + } >>== { result in + XCTAssertTrue(result) + + // We should have aborted now + XCTAssertEqual(prefs.stringForKey("repairs.bookmark.state"), nil) + + checkRecordedEvents(fromPrefs: prefs, expected: startedEvent, uploadEvent, abortedEvent) + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + func testSyncEventsPickledInPrefs() { + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + let localClient = RemoteClient(guid: nil, name: "Test local client", modified: (Date.now() - OneMinuteInMilliseconds), type: "mobile", formfactor: "largetablet", os: "iOS", version: nil, fxaDeviceId: nil) + let remoteClientA = RemoteClient(guid: "client-a", name: "Test remote client", modified: Date.now(), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClientB = RemoteClient(guid: "client-b", name: "Test remote client", modified: (Date.now() - OneMinuteInMilliseconds), type: "desktop", formfactor: nil, os: nil, version: "55.0.1", fxaDeviceId: nil) + let remoteClients = MockRemoteClientsAndTabs([ClientAndTabs(client: remoteClientA, tabs: []), ClientAndTabs(client: localClient, tabs: []), ClientAndTabs(client: remoteClientB, tabs: [])]) + let requestor = BookmarksRepairRequestor(scratchpad: scratchpad, basePrefs: prefs, remoteClients: remoteClients) + + let mockTimestamp = Date.now() + let mockEvent = Event(timestamp: mockTimestamp, category: "test", + method: "method", object: "object", value: "value", + extra: ["test": "value"]) + + requestor.recordTelemetry(event: mockEvent) + + let events = requestor.basePrefs.arrayForKey(PrefKeySyncEvents) as! [Data] + XCTAssertEqual(events.count, 1) + + let pickledEvent = Event.unpickle(events[0]) + XCTAssertEqual(pickledEvent!.category, mockEvent.category) + } +} + +func checkOutgoingCommand(remoteClients: MockRemoteClientsAndTabs, clientID: GUID) { + let outgoingCmds = remoteClients.commands[clientID]! + XCTAssertEqual(outgoingCmds.count, 1) + XCTAssertEqual(JSON.parse(outgoingCmds.first!.value)["command"].stringValue, "repairRequest") +} + +func checkRecordedEvents(fromPrefs prefs: Prefs, expected: Event...) { + let eventData = prefs.arrayForKey(PrefKeySyncEvents) as? [Data] ?? [] + let actualEvents = eventData.map(Event.unpickle) + XCTAssertEqual(actualEvents.count, expected.count) + expected.enumerated().forEach { offset, expected in + XCTAssertEqual(expected, actualEvents[offset]) + } +} + +func makeRepairEvent(_ values: [Any?]) -> Event { + return Event(timestamp: Date.now(), + category: "sync", + method: "repair", + object: values[0] as! String, + value: values[1] as? String, + extra: values[2] as? [String: String] + ) +} + +// Checks equivalence while ignoring the timestamp +extension Event: Equatable { + public static func ==(left: Event, right: Event) -> Bool { + let propsAreEqual = (left.category == right.category) && + (left.method == right.method) && + (left.object == right.object) && + (left.value ?? "" == right.value ?? "") && + (left.extra ?? [:] == right.extra ?? [:]) + return propsAreEqual + } +} + +open class MockRemoteClientsAndTabs: RemoteClientsAndTabs { + open var clientsAndTabs: [ClientAndTabs] + open var commands: [GUID: [SyncCommand]] + + public init(_ clientsAndTabs: [ClientAndTabs]) { + self.clientsAndTabs = clientsAndTabs + self.commands = clientsAndTabs.map { $0.client.guid ?? "localID" }.reduce([String: [SyncCommand]]()) { (dict, clientId) -> [String: [SyncCommand]] in + var dict = dict + dict[clientId] = [SyncCommand]() + return dict + } + } + + open func onRemovedAccount() -> Success { + return succeed() + } + + open func wipeClients() -> Success { + return succeed() + } + + open func wipeRemoteTabs() -> Deferred> { + return succeed() + } + + open func wipeTabs() -> Success { + return succeed() + } + + open func insertOrUpdateClients(_ clients: [RemoteClient]) -> Deferred> { + return deferMaybe(0) + } + + open func insertOrUpdateClient(_ client: RemoteClient) -> Deferred> { + return deferMaybe(0) + } + + open func insertOrUpdateTabs(_ tabs: [RemoteTab]) -> Deferred> { + return insertOrUpdateTabsForClientGUID(nil, tabs: [RemoteTab]()) + } + + open func insertOrUpdateTabsForClientGUID(_ clientGUID: String?, tabs: [RemoteTab]) -> Deferred> { + return deferMaybe(-1) + } + + open func getClientsAndTabs() -> Deferred> { + return deferMaybe(self.clientsAndTabs) + } + + open func getClients() -> Deferred> { + return deferMaybe(self.clientsAndTabs.map { $0.client }) + } + + open func getClientWithId(_ clientID: GUID) -> Deferred> { + return self.getClient(guid: clientID) + } + + open func getClient(fxaDeviceId: String) -> Deferred> { + return deferMaybe(self.clientsAndTabs.find { clientAndTabs in + return clientAndTabs.client.fxaDeviceId == fxaDeviceId + }?.client) + } + + open func getClient(guid: GUID) -> Deferred> { + return deferMaybe(self.clientsAndTabs.find { clientAndTabs in + return clientAndTabs.client.guid == guid + }?.client) + } + + open func deleteClient(guid: GUID) -> Success { + clientsAndTabs = clientsAndTabs.filter { $0.client.guid != guid } + return succeed() + } + + open func getClientGUIDs() -> Deferred>> { + return deferMaybe(Set(optFilter(self.clientsAndTabs.map { $0.client.guid }))) + } + + open func getTabsForClientWithGUID(_ guid: GUID?) -> Deferred> { + return deferMaybe(optFilter(self.clientsAndTabs.map { $0.client.guid == guid ? $0.tabs : nil })[0]) + } + + open func deleteCommands() -> Success { + self.commands = [GUID: [SyncCommand]]() + return succeed() + } + open func deleteCommands(_ clientGUID: GUID) -> Success { + self.commands[clientGUID] = [SyncCommand]() + return succeed() + } + + open func getCommands() -> Deferred> { + return deferMaybe(self.commands) + } + + open func insertCommand(_ command: SyncCommand, forClients clients: [RemoteClient]) -> Deferred> { + return self.insertCommands([command], forClients: clients) + } + open func insertCommands(_ commands: [SyncCommand], forClients clients: [RemoteClient]) -> Deferred> { + var numInserts = 0 + for client in clients where self.commands[client.guid ?? "localID"] != nil { + self.commands[client.guid ?? "localID"]! += commands + numInserts += commands.count + } + return deferMaybe(numInserts) + } +} diff --git a/mobile/ios/SyncTests/TestBookmarksSynchronizer.swift b/mobile/ios/SyncTests/TestBookmarksSynchronizer.swift new file mode 100644 index 0000000000..5b5316bef7 --- /dev/null +++ b/mobile/ios/SyncTests/TestBookmarksSynchronizer.swift @@ -0,0 +1,434 @@ +/* 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/. */ + +import Foundation +import Shared +import Deferred +@testable import Sync +@testable import Storage + +import XCTest +import SwiftyJSON + +class MockStorage: LocalItemSource, MirrorItemSource, SyncableBookmarks { + var local: [GUID: BookmarkMirrorItem] = [:] + var localAdditions: [GUID] = [] + var localDeletions: [GUID] = [] + var lastBufferUpdatedCompletionOpApplied: BufferUpdatedCompletionOp? + + // LocalItemSource methods. + + func getLocalItemWithGUID(_ guid: GUID) -> Deferred> { + guard let item = self.local[guid] else { + return deferMaybe(DatabaseError(description: "Couldn't find item \(guid).")) + } + return deferMaybe(item) + } + + func getLocalItemsWithGUIDs(_ guids: T) -> Deferred> where T.Iterator.Element == GUID { + var acc: [GUID: BookmarkMirrorItem] = [:] + guids.forEach { guid in + if let item = self.local[guid] { + acc[guid] = item + } + } + return deferMaybe(acc) + } + + func prefetchLocalItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return succeed() + } + + // MirrorItemSource methods (not implemented!). + + func getMirrorItemWithGUID(_ guid: GUID) -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func getMirrorItemsWithGUIDs(_ guids: T) -> Deferred> where T : Collection, T.Iterator.Element == GUID { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func prefetchMirrorItemsWithGUIDs(_ guids: T) -> Success where T.Iterator.Element == GUID { + return succeed() + } + + // SyncableBookmarks methods (partialy implemented!). + + func isUnchanged() -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func getLocalBookmarksModifications(limit: Int) -> Deferred> { + let deletions = Array(self.localDeletions.prefix(limit)) + let additions = Array(self.localAdditions.prefix(limit - deletions.count)).map { self.local[$0]! } + return deferMaybe((deletions: deletions, additions: additions)) + } + + func getLocalDeletions() -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func treesForEdges() -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func treeForMirror() -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func applyLocalOverrideCompletionOp(_ op: LocalOverrideCompletionOp, itemSources: ItemSources) -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func applyBufferUpdatedCompletionOp(_ op: BufferUpdatedCompletionOp) -> Success { + self.lastBufferUpdatedCompletionOpApplied = op + return succeed() + } + + // Misc methods. + + func resetClient() -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func onRemovedAccount() -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } +} + +class MockBuffer: BookmarkBufferStorage, BufferItemSource { + var buffer: [GUID: BookmarkMirrorItem] = [:] + var children: [GUID: [GUID]] = [:] + + // BufferItemSource methods. + + func getBufferItemWithGUID(_ guid: GUID) -> Deferred> { + guard let item = self.buffer[guid] else { + return deferMaybe(DatabaseError(description: "Couldn't find item \(guid).")) + } + return deferMaybe(item) + } + + func getBufferItemsWithGUIDs(_ guids: T) -> Deferred> where T : Collection, T.Iterator.Element == GUID { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func getBufferChildrenGUIDsForParent(_ guid: GUID) -> Deferred> { + guard let children = self.children[guid] else { + return deferMaybe(DatabaseError(description: "Couldn't find children for \(guid).")) + } + return deferMaybe(children) + } + + func prefetchBufferItemsWithGUIDs(_ guids: T) -> Success where T : Collection, T.Iterator.Element == GUID { + return succeed() + } + + // BookmarkBufferStorage methods. + + func isEmpty() -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func applyRecords(_ records: [BookmarkMirrorItem]) -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func doneApplyingRecordsAfterDownload() -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func validate() -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func getBufferedDeletions() -> Deferred> { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func applyBufferCompletionOp(_ op: BufferCompletionOp, itemSources: ItemSources) -> Success { + return deferMaybe(DatabaseError(description: "Not implemented")) + } + + func synchronousBufferCount() -> Int? { + return nil + } + + func getUpstreamRecordCount() -> Deferred { + return Deferred(value: nil) + } +} + +class TestBookmarksSynchronizer: XCTestCase { + func testBuildMobileRootAndChildrenRecords_noMobileRootInBuffer() { + let delegate = MockSyncDelegate() + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let buffer = MockBuffer() + let storage = MockStorage() + storage.local[BookmarkRoots.MobileFolderGUID] = BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: nil, title: "Mobile Bookmarks", description: nil, children: ["bk1"]) + storage.local["bk1"] = BookmarkMirrorItem.bookmark("bk1", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 1", description: nil, URI: "https://example.com/1", tags: "", keyword: nil) + storage.local["bk1"] = BookmarkMirrorItem.bookmark("bk1", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 1", description: nil, URI: "https://example.com/1", tags: "", keyword: nil) + let bk2 = BookmarkMirrorItem.bookmark("bk2", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 2", description: nil, URI: "https://example.com/2", tags: "", keyword: nil) + let bk3 = BookmarkMirrorItem.bookmark("bk3", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 3", description: nil, URI: "https://example.com/3", tags: "", keyword: nil) + storage.local["bk2"] = bk2 + storage.local["bk3"] = bk3 + + let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + let (mobileRootRecord, childrenRecords) = synchronizer.buildMobileRootAndChildrenRecords(storage, buffer, additionalChildren: [bk2, bk3], deletedChildren: []).value.successValue! + XCTAssertEqual(mobileRootRecord.id, BookmarkRoots.translateOutgoingRootGUID(BookmarkRoots.MobileFolderGUID)) + XCTAssertEqual(mobileRootRecord.payload.json["title"], "Mobile Bookmarks") + // We are not including bk1 in the call to buildMobileRootRecord() therefore it should NOT be included in the returned record + XCTAssertEqual(mobileRootRecord.payload.json["children"], ["bk2", "bk3"]) + + XCTAssertEqual(childrenRecords.count, 2) + XCTAssertEqual(childrenRecords[0].id, "bk2") + XCTAssertEqual(childrenRecords[1].id, "bk3") + } + + func testBuildMobileRootAndChildrenRecords_mobileRootInBuffer() { + let delegate = MockSyncDelegate() + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let buffer = MockBuffer() + buffer.buffer[BookmarkRoots.MobileFolderGUID] = BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: nil, title: "Mobile Bookmarks", description: nil, children: ["bk1", "bkmdeleteme"]) + buffer.children[BookmarkRoots.MobileFolderGUID] = ["bk1", "bkmdeleteme"] + buffer.buffer["bk1"] = BookmarkMirrorItem.bookmark("bk1", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 1", description: nil, URI: "https://example.com/1", tags: "", keyword: nil) + buffer.buffer["bkmdeleteme"] = BookmarkMirrorItem.bookmark("bkmdeleteme", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark to delete", description: nil, URI: "https://example.com/todelete", tags: "", keyword: nil) + + let storage = MockStorage() + storage.local["bk1"] = BookmarkMirrorItem.bookmark("bk1", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 1", description: nil, URI: "https://example.com/1", tags: "", keyword: nil) + let bk2 = BookmarkMirrorItem.bookmark("bk2", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 2", description: nil, URI: "https://example.com/2", tags: "", keyword: nil) + let bk3 = BookmarkMirrorItem.bookmark("bk3", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 3", description: nil, URI: "https://example.com/3", tags: "", keyword: nil) + storage.local["bk2"] = bk2 + storage.local["bk3"] = bk3 + + let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + let (mobileRootRecord, childrenRecords) = synchronizer.buildMobileRootAndChildrenRecords(storage, buffer, additionalChildren: [bk2, bk3], deletedChildren: ["bkmdeleteme"]).value.successValue! + XCTAssertEqual(mobileRootRecord.id, BookmarkRoots.translateOutgoingRootGUID(BookmarkRoots.MobileFolderGUID)) + XCTAssertEqual(mobileRootRecord.payload.json["title"], "Mobile Bookmarks") + // bk1 is a children of mobile root in the buffer, therefore it should be included here. + XCTAssertEqual(mobileRootRecord.payload.json["children"], ["bk1", "bk2", "bk3"]) + + // We are only sending the new/deleted records though! + XCTAssertEqual(childrenRecords.count, 3) + XCTAssertEqual(childrenRecords[0].id, "bk2") + XCTAssertEqual(childrenRecords[1].id, "bk3") + XCTAssertEqual(childrenRecords[2].id, "bkmdeleteme") + XCTAssertTrue(childrenRecords[2].payload.deleted) + } + + func testUploadSomeLocalRecords_batched_ok() { + let delegate = MockSyncDelegate() + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let storage = MockStorage() + let buffer = MockBuffer() + + let records = createMobileRootAndChildrenRecords(numChildren: 80) + + var numPosts = 0 + let now = Date.now() + var firstPostLastModified: Timestamp? + var secondPostLastModified: Timestamp? + let uploader: BatchUploadFunction = { lines, ifUnmodifiedSince, queryParams in + numPosts += 1 + var headers = [String: Any]() + + let result: POSTResult + if numPosts == 1 { + result = POSTResult(success: records.childrenRecords.map { $0.id } + ["mobile"], failed: [:], batchToken: "toktok") + firstPostLastModified = now + headers["X-Last-Modified"] = firstPostLastModified + } else { + XCTAssertEqual(queryParams![0].name, "batch") + XCTAssertEqual(queryParams![0].value, "toktok") + XCTAssertEqual(queryParams![1].name, "commit") + XCTAssertEqual(queryParams![1].value, "true") + result = POSTResult(success: [], failed: [:]) + secondPostLastModified = now + 5000 + headers["X-Last-Modified"] = secondPostLastModified + } + let response = StorageResponse(value: result, metadata: ResponseMetadata(status: 200, headers: headers)) + return deferMaybe(response) + } + + let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600) + let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter()) + let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks")) + + let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).succeeded() + XCTAssertEqual(storage.lastBufferUpdatedCompletionOpApplied?.bufferValuesToMoveFromLocal.count, 81) + XCTAssertEqual(numPosts, 2) + XCTAssertEqual(mirrorer.lastModified / 1000, secondPostLastModified) + } + + func testUploadSomeLocalRecords_batched_someFailed() { + let delegate = MockSyncDelegate() + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let storage = MockStorage() + let buffer = MockBuffer() + + let records = createMobileRootAndChildrenRecords(numChildren: 80) + + var numPosts = 0 + let uploader: BatchUploadFunction = { lines, ifUnmodifiedSince, queryParams in + numPosts += 1 + var headers = [String: Any]() + headers["X-Last-Modified"] = Date.now() + + let result = POSTResult(success: records.childrenRecords.map { $0.id }.dropFirst(20) + ["mobile"], failed: [:], batchToken: "toktok") + let response = StorageResponse(value: result, metadata: ResponseMetadata(status: 200, headers: headers)) + return deferMaybe(response) + } + + let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600) + let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter()) + let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks")) + + let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + let error = synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).value.failureValue! + XCTAssertTrue(error is RecordsFailedToUpload) + XCTAssertNil(storage.lastBufferUpdatedCompletionOpApplied) + XCTAssertEqual(numPosts, 1) + } + + func testUploadSomeLocalRecords_nobatch_ok() { + let delegate = MockSyncDelegate() + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let storage = MockStorage() + let buffer = MockBuffer() + + let records = createMobileRootAndChildrenRecords(numChildren: 80) + + var numPosts = 0 + let uploader: BatchUploadFunction = { lines, ifUnmodifiedSince, queryParams in + numPosts += 1 + var headers = [String: Any]() + headers["X-Last-Modified"] = Date.now() + + let result = POSTResult(success: records.childrenRecords.map { $0.id } + ["mobile"], failed: [:]) + let response = StorageResponse(value: result, metadata: ResponseMetadata(status: 200, headers: headers)) + return deferMaybe(response) + } + + let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600) + let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter()) + let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks")) + + let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).succeeded() + XCTAssertEqual(storage.lastBufferUpdatedCompletionOpApplied?.bufferValuesToMoveFromLocal.count, 81) + XCTAssertEqual(numPosts, 1) + } + + func testUploadSomeLocalRecords_nobatch_someFailed() { + let delegate = MockSyncDelegate() + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let storage = MockStorage() + let buffer = MockBuffer() + + let records = createMobileRootAndChildrenRecords(numChildren: 80) + + var numPosts = 0 + let uploader: BatchUploadFunction = { lines, ifUnmodifiedSince, queryParams in + numPosts += 1 + var headers = [String: Any]() + headers["X-Last-Modified"] = Date.now() + + let result = POSTResult(success: records.childrenRecords.map { $0.id }.dropFirst(20) + ["mobile"], failed: [:]) + let response = StorageResponse(value: result, metadata: ResponseMetadata(status: 200, headers: headers)) + return deferMaybe(response) + } + + let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600) + let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter()) + let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks")) + + let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).succeeded() + XCTAssertEqual(storage.lastBufferUpdatedCompletionOpApplied?.bufferValuesToMoveFromLocal.count, 61) + XCTAssertEqual(numPosts, 1) + } + + func testUploadSomeLocalRecords_tooManyRecords() { + let delegate = MockSyncDelegate() + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let storage = MockStorage() + let buffer = MockBuffer() + + let uploader: BatchUploadFunction = { _, _, _ in + // Should never happen + XCTFail() + return deferMaybe(NSError()) + } + + let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600) + let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter()) + let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks")) + + let records = createMobileRootAndChildrenRecords(numChildren: 120) + + let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + let error = synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).value.failureValue! + XCTAssertTrue(error is TooManyRecordsError) + } + + func testUploadSomeLocalRecords_tooBig() { + let delegate = MockSyncDelegate() + let prefs = MockProfilePrefs() + let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs) + + let storage = MockStorage() + let buffer = MockBuffer() + + let uploader: BatchUploadFunction = { _, _, _ in + // Should never happen + XCTFail() + return deferMaybe(NSError()) + } + + let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 5000, maxTotalRecords: 250, maxTotalBytes: 104_857_600) + let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter()) + let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks")) + + let records = createMobileRootAndChildrenRecords(numChildren: 80) + + let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled) + let error = synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).value.failureValue! + XCTAssertTrue(error is TooManyRecordsError) + } + + func getBookmarksEncrypter() -> RecordEncrypter { + let serializer: (Record) -> JSON? = { $0.payload.json } + let factory: (String) -> BookmarkBasePayload = { BookmarkBasePayload($0) } + return RecordEncrypter(serializer: serializer, factory: factory) + } + + func createMobileRootAndChildrenRecords(numChildren: Int) -> (mobileRootRecord: Record, childrenRecords: [Record]) { + var childrenRecords: [Record] = [] + for i in 0...numChildren { + let item = BookmarkMirrorItem.bookmark("bk1\(i)", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "bk1\(i)", description: nil, URI: "https://example.com/\(i)", tags: "", keyword: nil) + let record = Record(id: item.guid, payload: item.asPayload()) + childrenRecords.append(record) + } + let mobileRoot = BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: nil, title: "Mobile Bookmarks", description: nil, children: []) + let mobileRootRecord = Record(id: BookmarkRoots.translateOutgoingRootGUID(BookmarkRoots.MobileFolderGUID), payload: mobileRoot.asPayloadWithChildren(childrenRecords.map { $0.id })) + + return (mobileRootRecord: mobileRootRecord, childrenRecords: childrenRecords) + } +} diff --git a/mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.h b/mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.h new file mode 100644 index 0000000000..d9314fd3a3 --- /dev/null +++ b/mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.h @@ -0,0 +1,116 @@ +/* + File: UIImage+ImageEffects.h + Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2013 Apple Inc. All Rights Reserved. + + + Copyright © 2013 Apple Inc. All rights reserved. + WWDC 2013 License + + NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 + Session. Please refer to the applicable WWDC 2013 Session for further + information. + + IMPORTANT: This Apple software is supplied to you by Apple Inc. + ("Apple") in consideration of your agreement to the following terms, and + your use, installation, modification or redistribution of this Apple + software constitutes acceptance of these terms. If you do not agree with + these terms, please do not use, install, modify or redistribute this + Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a non-exclusive license, under + Apple's copyrights in this original Apple software (the "Apple + Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES + NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + EA1002 + 5/3/2013 + */ + +typedef enum { + NOBLUR, + BOXFILTER, + TENTFILTER +} BlurType; + + +@import UIKit; + +@interface UIImage (ImageEffects) + +- (UIImage *) applyLightEffect; +- (UIImage *) applyExtraLightEffect; +- (UIImage *) applyDarkEffect; +- (UIImage *) applyDarkEffectWithTent: (CGFloat) radius; +- (UIImage *) applyTintEffectWithColor:(UIColor *)tintColor; + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius blurType: (BlurType) blurType tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage; + +@end + diff --git a/mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.m b/mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.m new file mode 100644 index 0000000000..343582852b --- /dev/null +++ b/mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.m @@ -0,0 +1,288 @@ +/* + File: UIImage+ImageEffects.m + Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2013 Apple Inc. All Rights Reserved. + + + Copyright © 2013 Apple Inc. All rights reserved. + WWDC 2013 License + + NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 + Session. Please refer to the applicable WWDC 2013 Session for further + information. + + IMPORTANT: This Apple software is supplied to you by Apple Inc. + ("Apple") in consideration of your agreement to the following terms, and + your use, installation, modification or redistribution of this Apple + software constitutes acceptance of these terms. If you do not agree with + these terms, please do not use, install, modify or redistribute this + Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a non-exclusive license, under + Apple's copyrights in this original Apple software (the "Apple + Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES + NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + EA1002 + 5/3/2013 + */ + +#import "UIImage+ImageEffects.h" + +@import Accelerate; +#import + + +@implementation UIImage (ImageEffects) + + +- (UIImage *)applyLightEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; + return [self applyBlurWithRadius:30 blurType: BOXFILTER tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyExtraLightEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; + return [self applyBlurWithRadius:20 blurType: BOXFILTER tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyDarkEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; + return [self applyBlurWithRadius:10 blurType: BOXFILTER tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + +- (UIImage *) applyDarkEffectWithTent: (CGFloat) radius +{ + UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.5]; + return [self applyBlurWithRadius:radius blurType: TENTFILTER tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + +- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor +{ + const CGFloat EffectColorAlpha = 0.6; + UIColor *effectColor = tintColor; + size_t componentCount = CGColorGetNumberOfComponents(tintColor.CGColor); + if (componentCount == 2) { + CGFloat b; + if ([tintColor getWhite:&b alpha:NULL]) { + effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; + } + } + else { + CGFloat r, g, b; + if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { + effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; + } + } + return [self applyBlurWithRadius:10 blurType: BOXFILTER tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil]; +} + + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius blurType: (BlurType) blurType tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage +{ + // Check pre-conditions. + if (self.size.width < 1 || self.size.height < 1) { + NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); + return nil; + } + if (!self.CGImage) { + NSLog (@"*** error: image must be backed by a CGImage: %@", self); + return nil; + } + if (maskImage && !maskImage.CGImage) { + NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage); + return nil; + } + + CGRect imageRect = { CGPointZero, self.size }; + UIImage *effectImage = self; + + BOOL hasBlur = blurRadius > __FLT_EPSILON__ && blurType != NOBLUR; + BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; + if (hasBlur || hasSaturationChange) { + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef effectInContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(effectInContext, 1.0, -1.0); + CGContextTranslateCTM(effectInContext, 0, -self.size.height); + CGContextDrawImage(effectInContext, imageRect, self.CGImage); + + vImage_Buffer effectInBuffer; + effectInBuffer.data = CGBitmapContextGetData(effectInContext); + effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); + effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); + effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); + + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); + vImage_Buffer effectOutBuffer; + effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); + effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); + effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); + effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); + + if (hasBlur) { + // A description of how to compute the box kernel width from the Gaussian + // radius (aka standard deviation) appears in the SVG spec: + // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement + // + // For larger values of 's' (s >= 2.0), an approximation can be used: Three + // successive box-blurs build a piece-wise quadratic convolution kernel, which + // approximates the Gaussian kernel to within roughly 3%. + // + // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) + // + // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. + // + CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; + uint32_t radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); + if (radius % 2 != 1) { + radius += 1; // force radius to be odd so that the three box-blur methodology works. + } + + if (blurType == BOXFILTER) + { + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + } + else + { + vImageTentConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + } + } + BOOL effectImageBuffersAreSwapped = NO; + if (hasSaturationChange) { + CGFloat s = saturationDeltaFactor; + CGFloat floatingPointSaturationMatrix[] = { + 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, + 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, + 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, + 0, 0, 0, 1, + }; + const int32_t divisor = 256; + NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); + int16_t saturationMatrix[matrixSize]; + for (NSUInteger i = 0; i < matrixSize; ++i) { + saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); + } + if (hasBlur) { + vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + effectImageBuffersAreSwapped = YES; + } + else { + vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + } + } + if (!effectImageBuffersAreSwapped) + effectImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + if (effectImageBuffersAreSwapped) + effectImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + + // Set up output context. + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef outputContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(outputContext, 1.0, -1.0); + CGContextTranslateCTM(outputContext, 0, -self.size.height); + + // Draw effect image. + if (hasBlur) { + CGContextSaveGState(outputContext); + if (maskImage) { + CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); + } + CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); + CGContextRestoreGState(outputContext); + } + + // Add in color tint. + if (tintColor) { + CGContextSaveGState(outputContext); + CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); + CGContextFillRect(outputContext, imageRect); + CGContextRestoreGState(outputContext); + } + + // Output image is ready. + UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return outputImage; +} + +@end + diff --git a/mobile/ios/ThirdParty/Box/Box.swift b/mobile/ios/ThirdParty/Box/Box.swift new file mode 100644 index 0000000000..ce514379d4 --- /dev/null +++ b/mobile/ios/ThirdParty/Box/Box.swift @@ -0,0 +1,33 @@ +// Copyright (c) 2014 Rob Rix. All rights reserved. + +/// Wraps a type `T` in a reference type. +/// +/// Typically this is used to work around limitations of value types (for example, the lack of codegen for recursive value types and type-parameterized enums with >1 case). It is also useful for sharing a single (presumably large) value without copying it. +public final class Box: BoxType, CustomStringConvertible { + /// Initializes a `Box` with the given value. + public init(_ value: T) { + self.value = value + } + + + /// Constructs a `Box` with the given `value`. + public class func unit(_ value: T) -> Box { + return Box(value) + } + + + /// The (immutable) value wrapped by the receiver. + public let value: T + + /// Constructs a new Box by transforming `value` by `f`. + public func map(_ f: (T) -> U) -> Box { + return Box(f(value)) + } + + + // MARK: Printable + + public var description: String { + return String(describing: value) + } +} diff --git a/mobile/ios/ThirdParty/Box/BoxType.swift b/mobile/ios/ThirdParty/Box/BoxType.swift new file mode 100644 index 0000000000..a91e04d8d5 --- /dev/null +++ b/mobile/ios/ThirdParty/Box/BoxType.swift @@ -0,0 +1,46 @@ +// Copyright (c) 2014 Rob Rix. All rights reserved. + +// MARK: BoxType + +/// The type conformed to by all boxes. +public protocol BoxType { + /// The type of the wrapped value. + associatedtype Value + + /// Initializes an intance of the type with a value. + init(_ value: Value) + + /// The wrapped value. + var value: Value { get } +} + +/// The type conformed to by mutable boxes. +public protocol MutableBoxType: BoxType { + /// The (mutable) wrapped value. + var value: Value { get set } +} + + +// MARK: Equality + +/// Equality of `BoxType`s of `Equatable` types. +/// +/// We cannot declare that e.g. `Box` conforms to `Equatable`, so this is a relatively ad hoc definition. +public func == (lhs: B, rhs: B) -> Bool where B.Value: Equatable { + return lhs.value == rhs.value +} + +/// Inequality of `BoxType`s of `Equatable` types. +/// +/// We cannot declare that e.g. `Box` conforms to `Equatable`, so this is a relatively ad hoc definition. +public func != (lhs: B, rhs: B) -> Bool where B.Value: Equatable { + return lhs.value != rhs.value +} + + +// MARK: Map + +/// Maps the value of a box into a new box. +public func map(_ v: B, f: (B.Value) -> C.Value) -> C { + return C(f(v.value)) +} diff --git a/mobile/ios/ThirdParty/Box/LICENSE b/mobile/ios/ThirdParty/Box/LICENSE new file mode 100644 index 0000000000..3026ee1902 --- /dev/null +++ b/mobile/ios/ThirdParty/Box/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Rob Rix + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/mobile/ios/ThirdParty/Box/MutableBox.swift b/mobile/ios/ThirdParty/Box/MutableBox.swift new file mode 100644 index 0000000000..2fe30b6c6d --- /dev/null +++ b/mobile/ios/ThirdParty/Box/MutableBox.swift @@ -0,0 +1,27 @@ +// Copyright (c) 2014 Rob Rix. All rights reserved. + +/// Wraps a type `T` in a mutable reference type. +/// +/// While this, like `Box` could be used to work around limitations of value types, it is much more useful for sharing a single mutable value such that mutations are shared. +/// +/// As with all mutable state, this should be used carefully, for example as an optimization, rather than a default design choice. Most of the time, `Box` will suffice where any `BoxType` is needed. +public final class MutableBox: MutableBoxType, CustomStringConvertible { + /// Initializes a `MutableBox` with the given value. + public init(_ value: T) { + self.value = value + } + + /// The (mutable) value wrapped by the receiver. + public var value: T + + /// Constructs a new MutableBox by transforming `value` by `f`. + public func map(_ f: (T) -> U) -> MutableBox { + return MutableBox(f(value)) + } + + // MARK: Printable + + public var description: String { + return String(describing: value) + } +} diff --git a/mobile/ios/ThirdParty/Box/README.md b/mobile/ios/ThirdParty/Box/README.md new file mode 100644 index 0000000000..b9948a020c --- /dev/null +++ b/mobile/ios/ThirdParty/Box/README.md @@ -0,0 +1,58 @@ +# Box + +This is a Swift microframework which implements `Box` & `MutableBox`, with implementations of `==`/`!=` where `T`: `Equatable`. + +`Box` is typically used to work around limitations of value types: + +- recursive `struct`s/`enum`s +- type-parameterized `enum`s where more than one `case` has a value + +## Use + +Wrapping & unwrapping a `Box`: + +```swift +// Wrap: +let box = Box(1) + +// Unwrap: +let value = box.value +``` + +Changing the value of a `MutableBox`: + +```swift +// Mutation: +let mutableBox = MutableBox(1) +mutableBox.value = 2 +``` + +Building a recursive value type: + +```swift +struct BinaryTree { + let value: Int + let left: Box? + let right: Box? +} +``` + +Building a parameterized `enum`: + +```swift +enum Result { + case Success(Box) + case Failure(NSError) +} +``` + +See the sources for more details. + +## Integration + +1. Add this repo as a submodule in e.g. `External/Box`: + + git submodule add https://github.com/robrix/Box.git External/Box +2. Drag `Box.xcodeproj` into your `.xcworkspace`/`.xcodeproj`. +3. Add `Box.framework` to your target’s `Link Binary With Libraries` build phase. +4. You may also want to add a `Copy Files` phase which copies `Box.framework` (and any other framework dependencies you need) into your bundle’s `Frameworks` directory. If your target is a framework, you may instead want the client app to include `Box.framework`. diff --git a/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/BuddyBuildSDK b/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/BuddyBuildSDK new file mode 100644 index 0000000000..f8a850dbc2 Binary files /dev/null and b/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/BuddyBuildSDK differ diff --git a/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/Headers/BuddyBuildSDK.h b/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/Headers/BuddyBuildSDK.h new file mode 100644 index 0000000000..ca31088ac5 --- /dev/null +++ b/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/Headers/BuddyBuildSDK.h @@ -0,0 +1,147 @@ +// Copyright (c) 2015 Doe Pics Hit, Inc. All rights reserved. + +#import +#import + +typedef NSString*(^BBReturnNSStringCallback)(); +typedef BOOL (^BBReturnBooleanCallback)(); +typedef void (^BBCallback)(); + +@interface BuddyBuildSDK : NSObject + +// Deprecated ++ (void)setup:(id)bbAppDelegate; + +/** + * Initialize the SDK + * + * This should be called at (or near) the start of the appdelegate + */ ++ (void)setup; + +/* + * Associate arbitrary key/value pairs with your crash reports + * which will be visible from the buddybuild dashboard + */ ++ (void) setCrashMetadataObject:(id)object forKey:(NSString*)key; + +/* + * Programatically trigger the screenshot feedback UI without pressing the screenshot buttons + * If you have screenshot feedback disabled through the buddybuild setting, + * you can still trigger it by calling this method + */ + ++ (void)takeScreenshotAndShowFeedbackScreen; + +/* + * If you distribute a build to someone with their email address, buddybuild can + * figure out who they are and attach their info to feedback and crash reports. + * + * However, if you send out a build to a mailing list, or through TestFlight or + * the App Store we are unable to infer who they are. If you see 'Unknown User' + * this is likely the cause. + + * Often you'll know the identity of your user, for example, after they've + * logged in. You can provide buddybuild a callback to identify the current user. + */ + ++ (void)setUserDisplayNameCallback:(BBReturnNSStringCallback)bbCallback; + +/* + * You might have API keys and other secrets that your app needs to consume. + * However, you may not want to check these secrets into the source code. + * + * You can provide your secrets to buddybuild. Buddybuild can then expose them + * to you at build time through environment variables. These secrets can also be + * configured to be included into built app. We obfuscate the device keys to + * prevent unauthorized access. + */ ++ (NSString*)valueForDeviceKey:(NSString*)bbKey; + +/* + * To temporarily disable screenshot interception you can provide a callback + * here. + * + * When screenshotting is turned on through a buddybuild setting, and no + * callback is provided then screenshotting is by default on. + * + * If screenshotting is disabled through the buddybuild setting, then this + * callback has no effect + * + */ ++ (void)setScreenshotAllowedCallback:(BBReturnBooleanCallback)bbCallback; + +/* + * Once a piece of feedback is sent this callback will be called + * so you can take additional actions if necessary + */ ++ (void)setScreenshotFeedbackSentCallback:(BBCallback)bbCallback; + +/* + * Once a crash report is sent this callback will be called + * so you can take additional actions if necessary + */ ++ (void)setCrashReportSentCallback:(BBCallback)bbCallback; + +/* + * Buddybuild Build Number + */ ++ (NSString*)buildNumber; + +/* + * Scheme + */ ++ (NSString*)scheme; + +/* + * App ID + */ ++ (NSString*)appID; + +/* + * Build ID + */ ++ (NSString*)buildID; + +/* + * Build Configuration + */ + ++ (NSString*)buildConfiguration; + +/* + * Branch name for this build + */ + ++ (NSString*)branchName; + +/* + * Returns the user's email or more specifically, the email that was used to download and deploy the build. + * Returns "Unknown User" in cases where buddybuild is unable to identify the user. + * This is the same email seen in crash instances and feedbacks in the dashboard + * NOTE: To be called after [BuddyBuildSDK setup] + * this is different than the one returned in the user display name callback. +*/ ++ (NSString*)userEmail; + +/* Manually invoke the screenshot tutorial + * If you don't want it to appear on app launch, disable it in the + * dashboard by going to settings -> buddybuildSDK -> Feature Settings and turning off the screenshot tutorial + * You will be able to show it at any time from anywhere in your app + */ ++ (void) showScreenshotTutorial; + + ++(void) crash; + +@end + +@interface UIView (BuddyBuildSDK) + +// Certain features of buddybuild involve capturing the screen (either through a static screenshot, or as a video for instant replays in crash reporting or video feedback. +// Your app may contain certain sensitive customer information that you do not want to be included in the video. +// If you set this property to be true, this view will be redacted from the screen capture and blacked out + +@property (nonatomic, assign) BOOL buddybuildViewIsPrivate; + +@end diff --git a/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/build.num b/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/build.num new file mode 100644 index 0000000000..6e4f7dfb64 --- /dev/null +++ b/mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/build.num @@ -0,0 +1 @@ +d1039cf diff --git a/mobile/ios/ThirdParty/FilledPageControl.swift b/mobile/ios/ThirdParty/FilledPageControl.swift new file mode 100644 index 0000000000..7631f12c67 --- /dev/null +++ b/mobile/ios/ThirdParty/FilledPageControl.swift @@ -0,0 +1,137 @@ +// FilledPageControl +// +// Copyright (c) 2016 Kyle Zaragoza +// MIT License + +import UIKit + +@IBDesignable open class FilledPageControl: UIView { + + // MARK: - PageControl + + @IBInspectable open var pageCount: Int = 0 { + didSet { + updateNumberOfPages(pageCount) + } + } + @IBInspectable open var progress: CGFloat = 0 { + didSet { + updateActivePageIndicatorMasks(progress) + } + } + open var currentPage: Int { + return Int(round(progress)) + } + + + // MARK: - Appearance + + override open var tintColor: UIColor! { + didSet { + inactiveLayers.forEach() { $0.backgroundColor = tintColor.cgColor } + } + } + @IBInspectable open var inactiveRingWidth: CGFloat = 1 { + didSet { + updateActivePageIndicatorMasks(progress) + } + } + @IBInspectable open var indicatorPadding: CGFloat = 10 { + didSet { + layoutPageIndicators(inactiveLayers) + } + } + @IBInspectable open var indicatorRadius: CGFloat = 5 { + didSet { + layoutPageIndicators(inactiveLayers) + } + } + + fileprivate var indicatorDiameter: CGFloat { + return indicatorRadius * 2 + } + fileprivate var inactiveLayers = [CALayer]() + + + // MARK: - State Update + + fileprivate func updateNumberOfPages(_ count: Int) { + // no need to update + guard count != inactiveLayers.count else { return } + // reset current layout + inactiveLayers.forEach() { $0.removeFromSuperlayer() } + inactiveLayers = [CALayer]() + // add layers for new page count + inactiveLayers = stride(from: 0, to:count, by:1).map() { _ in + let layer = CALayer() + layer.backgroundColor = self.tintColor.cgColor + self.layer.addSublayer(layer) + return layer + } + layoutPageIndicators(inactiveLayers) + updateActivePageIndicatorMasks(progress) + self.invalidateIntrinsicContentSize() + } + + + // MARK: - Layout + + fileprivate func updateActivePageIndicatorMasks(_ progress: CGFloat) { + // ignore if progress is outside of page indicators' bounds + guard progress >= 0 && progress <= CGFloat(pageCount - 1) else { return } + + // mask rect w/ default stroke width + let insetRect = CGRect(x: 0, y: 0, width: indicatorDiameter, height: indicatorDiameter).insetBy(dx: inactiveRingWidth, dy: inactiveRingWidth) + let leftPageFloat = trunc(progress) + let leftPageInt = Int(progress) + + // inset right moving page indicator + let spaceToMove = insetRect.width / 2 + let percentPastLeftIndicator = progress - leftPageFloat + let additionalSpaceToInsetRight = spaceToMove * percentPastLeftIndicator + let closestRightInsetRect = insetRect.insetBy(dx: additionalSpaceToInsetRight, dy: additionalSpaceToInsetRight) + + // inset left moving page indicator + let additionalSpaceToInsetLeft = (1 - percentPastLeftIndicator) * spaceToMove + let closestLeftInsetRect = insetRect.insetBy(dx: additionalSpaceToInsetLeft, dy: additionalSpaceToInsetLeft) + + // adjust masks + for (idx, layer) in inactiveLayers.enumerated() { + let maskLayer = CAShapeLayer() + maskLayer.fillRule = kCAFillRuleEvenOdd + + let boundsPath = UIBezierPath(rect: layer.bounds) + let circlePath: UIBezierPath + if leftPageInt == idx { + circlePath = UIBezierPath(ovalIn: closestLeftInsetRect) + } else if leftPageInt + 1 == idx { + circlePath = UIBezierPath(ovalIn: closestRightInsetRect) + } else { + circlePath = UIBezierPath(ovalIn: insetRect) + } + boundsPath.append(circlePath) + maskLayer.path = boundsPath.cgPath + layer.mask = maskLayer + } + } + + fileprivate func layoutPageIndicators(_ layers: [CALayer]) { + let layerDiameter = indicatorRadius * 2 + var layerFrame = CGRect(x: 0, y: 0, width: layerDiameter, height: layerDiameter) + layers.forEach() { layer in + layer.cornerRadius = self.indicatorRadius + layer.frame = layerFrame + layerFrame.origin.x += layerDiameter + indicatorPadding + } + } + + override open var intrinsicContentSize: CGSize { + return sizeThatFits(CGSize.zero) + } + + override open func sizeThatFits(_ size: CGSize) -> CGSize { + let layerDiameter = indicatorRadius * 2 + return CGSize(width: CGFloat(inactiveLayers.count) * layerDiameter + CGFloat(inactiveLayers.count - 1) * indicatorPadding, + height: layerDiameter) + } +} diff --git a/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/LPInbox.h b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/LPInbox.h new file mode 100644 index 0000000000..a2339e5d1a --- /dev/null +++ b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/LPInbox.h @@ -0,0 +1,193 @@ +// +// LPInbox.h +// Leanplum +// +// Created by Aleksandar Gyorev on 05/08/15. +// Copyright (c) 2015 Leanplum, Inc. All rights reserved. +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#import + +#pragma mark - LPInboxMessage interface + +@interface LPInboxMessage : NSObject + +#pragma mark - LPInboxMessage methods + +/** + * Returns the message identifier of the inbox message. + */ +- (NSString *)messageId; + +/** + * Returns the title of the inbox message. + */ +- (NSString *)title; + +/** + * Returns the subtitle of the inbox message. + */ +- (NSString *)subtitle; + +/** + * Returns the image path of the inbox message. Can be nil. + * Use with [UIImage contentsOfFile:]. + */ +- (NSString *)imageFilePath; + +/** + * Returns the image URL of the inbox message. + * You can safely use this with prefetching enabled. + * It will return the file URL path instead if the image is in cache. + */ +- (NSURL *)imageURL; + +/** + * Returns the data of the inbox message. Advanced use only. + */ +- (NSDictionary *)data; + +/** + * Returns the delivery timestamp of the inbox message. + */ +- (NSDate *)deliveryTimestamp; + +/** + * Return the expiration timestamp of the inbox message. + */ +- (NSDate *)expirationTimestamp; + +/** + * Returns YES if the inbox message is read. + */ +- (BOOL)isRead; + +/** + * Read the inbox message, marking it as read and invoking its open action. + */ +- (void)read; + +/** + * Remove the inbox message from the inbox. + */ +- (void)remove; + +@end + +#pragma mark - LPInbox interface + +/** + * This block is used when you define a callback. + */ +typedef void (^LeanplumInboxChangedBlock)(void); +typedef void (^LeanplumInboxSyncedBlock)(BOOL success); + +@interface LPInbox : NSObject + +#pragma mark - LPInbox methods + +/** + * Returns the number of all inbox messages on the device. + */ +- (NSUInteger)count; + +/** + * Returns the number of the unread inbox messages on the device. + */ +- (NSUInteger)unreadCount; + +/** + * Returns the identifiers of all inbox messages on the device sorted in ascending + * chronological order, i.e. the id of the oldest message is the first one, and the most + * recent one is the last one in the array. + */ +- (NSArray *)messagesIds; + +/** + * Returns an array containing all of the inbox messages (as LPInboxMessage objects) + * on the device, sorted in ascending chronological order, i.e. the oldest message is the + * first one, and the most recent one is the last one in the array. + */ +- (NSArray *)allMessages; + +/** + * Returns an array containing all of the unread inbox messages on the device, sorted + * in ascending chronological order, i.e. the oldest message is the first one, and the + * most recent one is the last one in the array. + */ +- (NSArray *)unreadMessages; + +/** + * Returns the inbox messages associated with the given messageId identifier. + */ +- (LPInboxMessage *)messageForId:(NSString *)messageId; + +/** + * Call this method if you don't want Inbox images to be prefetched. + * Useful if you only want to deal with image URL. + */ +- (void)disableImagePrefetching; + +/** + * Block to call when the inbox receive new values from the server. + * This will be called on start, and also later on if the user is in an experiment + * that can update in realtime. + */ +- (void)onChanged:(LeanplumInboxChangedBlock)block; + +/** + * Block to call when forceContentUpdate was called. + * Returns true if syncing was successful. + * Note: use onChanged: for UI. + */ +- (void)onForceContentUpdate:(LeanplumInboxSyncedBlock)block; + +/** + @{ + * Adds a responder to be executed when an event happens. + * Uses NSInvocation instead of blocks. + * @see [Leanplum onStartResponse:] + */ +- (void)addInboxChangedResponder:(id)responder withSelector:(SEL)selector; +- (void)removeInboxChangedResponder:(id)responder withSelector:(SEL)selector; +/**@}*/ + +@end + +#pragma mark - LPNewsfeed for backwards compatibility +@interface LPNewsfeedMessage : LPInboxMessage + +@end + +typedef void (^LeanplumNewsfeedChangedBlock)(void); + +@interface LPNewsfeed : NSObject + ++ (LPNewsfeed *)sharedState; +- (NSUInteger)count; +- (NSUInteger)unreadCount; +- (NSArray *)messagesIds; +- (NSArray *)allMessages; +- (NSArray *)unreadMessages; +- (void)onChanged:(LeanplumNewsfeedChangedBlock)block; +- (LPNewsfeedMessage *)messageForId:(NSString *)messageId; +- (void)addNewsfeedChangedResponder:(id)responder withSelector:(SEL)selector __attribute__((deprecated)); +- (void)removeNewsfeedChangedResponder:(id)responder withSelector:(SEL)selector __attribute__((deprecated)); + +@end diff --git a/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/Leanplum.h b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/Leanplum.h new file mode 100644 index 0000000000..322df6dc04 --- /dev/null +++ b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/Leanplum.h @@ -0,0 +1,929 @@ +// +// Leanplum.h +// Leanplum iOS SDK Version 2.0.4 +// +// Copyright (c) 2012 Leanplum, Inc. All rights reserved. +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#import +#import +#import "LPInbox.h" + +#ifndef LP_NOT_TV +#define LP_NOT_TV (!defined(TARGET_OS_TV) || !TARGET_OS_TV) +#endif + +#define _LP_DEFINE_HELPER(name,val,type) LPVar* name; \ +static void __attribute__((constructor)) initialize_##name() { \ +@autoreleasepool { \ +name = [LPVar define:[@#name stringByReplacingOccurrencesOfString:@"_" withString:@"."] with##type:val]; \ +} \ +} + +/** + * @defgroup Macros Variable Macros + * Use these macros to define variables inside your app. + * Underscores within variable names will nest variables within groups. + * To define variables in a more custom way, copy and modify + * the template above in your own code. + * @see LPVar + * @{ + */ +#define DEFINE_VAR_INT(name,val) _LP_DEFINE_HELPER(name, val, Int) +#define DEFINE_VAR_BOOL(name,val) _LP_DEFINE_HELPER(name, val, Bool) +#define DEFINE_VAR_STRING(name,val) _LP_DEFINE_HELPER(name, val, String) +#define DEFINE_VAR_NUMBER(name,val) _LP_DEFINE_HELPER(name, val, Number) +#define DEFINE_VAR_FLOAT(name,val) _LP_DEFINE_HELPER(name, val, Float) +#define DEFINE_VAR_CGFLOAT(name,val) _LP_DEFINE_HELPER(name, val, CGFloat) +#define DEFINE_VAR_DOUBLE(name,val) _LP_DEFINE_HELPER(name, val, Double) +#define DEFINE_VAR_SHORT(name,val) _LP_DEFINE_HELPER(name, val, Short) +#define DEFINE_VAR_LONG(name,val) _LP_DEFINE_HELPER(name, val, Long) +#define DEFINE_VAR_CHAR(name,val) _LP_DEFINE_HELPER(name, val, Char) +#define DEFINE_VAR_LONG_LONG(name,val) _LP_DEFINE_HELPER(name, val, LongLong) +#define DEFINE_VAR_INTEGER(name,val) _LP_DEFINE_HELPER(name, val, Integer) +#define DEFINE_VAR_UINT(name,val) _LP_DEFINE_HELPER(name, val, UnsignedInt) +#define DEFINE_VAR_UCHAR(name,val) _LP_DEFINE_HELPER(name, val, UnsignedChar) +#define DEFINE_VAR_ULONG(name,val) _LP_DEFINE_HELPER(name, val, UnsignedLong) +#define DEFINE_VAR_UINTEGER(name,val) _LP_DEFINE_HELPER(name, val, UnsignedInteger) +#define DEFINE_VAR_USHORT(name,val) _LP_DEFINE_HELPER(name, val, UnsignedShort) +#define DEFINE_VAR_ULONGLONG(name,val) _LP_DEFINE_HELPER(name, val, UnsignedLongLong) +#define DEFINE_VAR_UNSIGNED_INT(name,val) _LP_DEFINE_HELPER(name, val, UnsignedInt) +#define DEFINE_VAR_UNSIGNED_INTEGER(name,val) _LP_DEFINE_HELPER(name, val, UnsignedInteger) +#define DEFINE_VAR_UNSIGNED_CHAR(name,val) _LP_DEFINE_HELPER(name, val, UnsignedChar) +#define DEFINE_VAR_UNSIGNED_LONG(name,val) _LP_DEFINE_HELPER(name, val, UnsignedLong) +#define DEFINE_VAR_UNSIGNED_LONG_LONG(name,val) _LP_DEFINE_HELPER(name, val, UnsignedLongLong) +#define DEFINE_VAR_UNSIGNED_SHORT(name,val) _LP_DEFINE_HELPER(name, val, UnsignedShort) +#define DEFINE_VAR_FILE(name,filename) _LP_DEFINE_HELPER(name, filename, File) +#define DEFINE_VAR_DICTIONARY(name,dict) _LP_DEFINE_HELPER(name, dict, Dictionary) +#define DEFINE_VAR_ARRAY(name,array) _LP_DEFINE_HELPER(name, array, Array) +#define DEFINE_VAR_COLOR(name,val) _LP_DEFINE_HELPER(name, val, Color) + +#define DEFINE_VAR_DICTIONARY_WITH_OBJECTS_AND_KEYS(name,...) LPVar* name; \ +static void __attribute__((constructor)) initialize_##name() { \ +@autoreleasepool { \ +name = [LPVar define:[@#name stringByReplacingOccurrencesOfString:@"_" withString:@"."] withDictionary:[NSDictionary dictionaryWithObjectsAndKeys:__VA_ARGS__]]; \ +} \ +} + +#define DEFINE_VAR_ARRAY_WITH_OBJECTS(name,...) LPVar* name; \ +static void __attribute__((constructor)) initialize_##name() { \ +@autoreleasepool { \ +name = [LPVar define:[@#name stringByReplacingOccurrencesOfString:@"_" withString:@"."] withArray:[NSArray arrayWithObjects:__VA_ARGS__]]; \ +} \ +} +/**@}*/ + +/** + * Use this code in development mode (or in production), to use the advertising ID. + * It's useful in development mode so that we remember your device even if you reinstall your app. + * Since it's a MACRO, this won't get compiled into your app in production, and will be safe + * to submit to Apple. + */ +#define LEANPLUM_USE_ADVERTISING_ID \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \ + id LeanplumIdentifierManager = [NSClassFromString(@"ASIdentifierManager") \ + performSelector:NSSelectorFromString(@"sharedManager")]; \ + if (floor(NSFoundationVersionNumber) <= 1299 /* NSFoundationVersionNumber_iOS_9_x_Max */ || \ + [LeanplumIdentifierManager performSelector: \ + NSSelectorFromString(@"isAdvertisingTrackingEnabled")]) { \ + /* < iOS10 || isAdvertisingTrackingEnabled */ \ + [Leanplum setDeviceId:[[LeanplumIdentifierManager performSelector: \ + NSSelectorFromString(@"advertisingIdentifier")] \ + performSelector:NSSelectorFromString(@"UUIDString")]]; \ + } \ + _Pragma("clang diagnostic pop") + +@class LPActionContext; +@class SKPaymentTransaction; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 +@class NSExtensionContext; +#endif + +/** + * @defgroup _ Callback Blocks + * Those blocks are used when you define callbacks. + * @{ + */ +typedef void (^LeanplumStartBlock)(BOOL success); +typedef void (^LeanplumVariablesChangedBlock)(void); +typedef void (^LeanplumInterfaceChangedBlock)(void); +typedef void (^LeanplumSetLocationBlock)(BOOL success); +// Returns whether the action was handled. +typedef BOOL (^LeanplumActionBlock)(LPActionContext* context); +typedef void (^LeanplumHandleNotificationBlock)(void); +typedef void (^LeanplumShouldHandleNotificationBlock)(NSDictionary *userInfo, LeanplumHandleNotificationBlock response); +typedef NSUInteger LeanplumUIBackgroundFetchResult; // UIBackgroundFetchResult +typedef void (^LeanplumFetchCompletionBlock)(LeanplumUIBackgroundFetchResult result); +typedef void (^LeanplumPushSetupBlock)(void); +/**@}*/ + +/** + * Leanplum Action Kind Message types + * This is a bit-field. To choose both kinds, use + * kLeanplumActionKindMessage | kLeanplumActionKindAction + */ +typedef enum { + kLeanplumActionKindMessage = 0b1, + kLeanplumActionKindAction = 0b10, +} LeanplumActionKind; + +#define LP_PURCHASE_EVENT @"Purchase" + +@interface Leanplum : NSObject + +/** + * Optional. Sets the API server. The API path is of the form http[s]://hostname/servletName + * @param hostName The name of the API host, such as api.leanplum.com + * @param servletName The name of the API servlet, such as api + * @param ssl Whether to use SSL + */ ++ (void)setApiHostName:(NSString *)hostName withServletName:(NSString *)servletName usingSsl:(BOOL)ssl; + +/** + * Optional. Adjusts the network timeouts. + * The default timeout is 10 seconds for requests, and 15 seconds for file downloads. + * @{ + */ ++ (void)setNetworkTimeoutSeconds:(int)seconds; ++ (void)setNetworkTimeoutSeconds:(int)seconds forDownloads:(int)downloadSeconds; +/**@}*/ + +/** + * Sets whether to show the network activity indicator in the status bar when making requests. + * Default: YES. + */ ++ (void)setNetworkActivityIndicatorEnabled:(BOOL)enabled; + +/** + * Advanced: Whether new variables can be downloaded mid-session. By default, this is disabled. + * Currently, if this is enabled, new variables can only be downloaded if a push notification is sent + * while the app is running, and the notification's metadata hasn't be downloaded yet. + */ ++ (void)setCanDownloadContentMidSessionInProductionMode:(BOOL)value; + +/** + * Modifies the file hashing setting in development mode. + * By default, Leanplum will hash file variables to determine if they're modified and need + * to be uploaded to the server if we're running in the simulator. + * Setting this to NO will reduce startup latency in development mode, but it's possible + * that Leanplum will not always have the most up-to-date versions of your resources. + */ ++ (void)setFileHashingEnabledInDevelopmentMode:(BOOL)enabled; + +/** + * Sets whether to enable verbose logging in development mode. Default: NO. + */ ++ (void)setVerboseLoggingInDevelopmentMode:(BOOL)enabled; + +/** + * Sets a custom event name for in-app purchase tracking. Default: Purchase. + */ ++ (void)setInAppPurchaseEventName:(NSString *)event; + +/** + * @{ + * Must call either this or {@link setAppId:withProductionKey:} + * before issuing any calls to the API, including start. + * @param appId Your app ID. + * @param accessKey Your development key. + */ ++ (void)setAppId:(NSString *)appId withDevelopmentKey:(NSString *)accessKey; + +/** + * Must call either this or {@link Leanplum::setAppId:withDevelopmentKey:} + * before issuing any calls to the API, including start. + * @param appId Your app ID. + * @param accessKey Your production key. + */ ++ (void)setAppId:(NSString *)appId withProductionKey:(NSString *)accessKey; +/**@}*/ + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 +/** + * Apps running as extensions need to call this before start. + * @param context The current extensionContext. You can get this from UIViewController. + */ ++ (void)setExtensionContext:(NSExtensionContext *)context; +#endif + +/** + * @{ + * Call this before start to allow your interfaces to change on the fly. + * Needed in development mode to enable the interface editor, as well as in production to allow + * changes to be applied. + */ ++ (void)allowInterfaceEditing __attribute__((deprecated("Use LeanplumUIEditor pod instead."))); + +/** + * Check if interface editing is enabled. + */ ++ (BOOL)interfaceEditingEnabled __attribute__((deprecated("Use LeanplumUIEditor pod instead."))); + +/**@}*/ + +/** + * Sets a custom device ID. For example, you may want to pass the advertising ID to do attribution. + * By default, the device ID is the identifier for vendor. + */ ++ (void)setDeviceId:(NSString *)deviceId; + +/** + * By default, Leanplum reports the version of your app using CFBundleVersion, which + * can be used for reporting and targeting on the Leanplum dashboard. + * If you wish to use CFBundleShortVersionString or any other string as the version, + * you can call this before your call to [Leanplum start] + */ ++ (void)setAppVersion:(NSString *)appVersion; + +/** + * @{ + * Syncs resources between Leanplum and the current app. + * You should only call this once, and before {@link start}. + * Deprecated. Use {@link syncResourcesAsync:} instead. + */ ++ (void)syncResources __attribute__((deprecated)); + +/** + * Syncs resources between Leanplum and the current app. + * You should only call this once, and before {@link start}. + * @param async Whether the call should be asynchronous. Resource syncing can take 1-2 seconds to + * index the app's resources. If async is set, resources may not be available immediately + * when the app starts. + */ ++ (void)syncResourcesAsync:(BOOL)async; + +/** + * Syncs resources between Leanplum and the current app. + * You should only call this once, and before {@link start}. + * Deprecated. Use {@link syncResourcePaths:excluding:async} instead. + * @param async Whether the call should be asynchronous. Resource syncing can take 1-2 seconds to + * index the app's resources. If async is set, resources may not be available immediately + * when the app starts. + * @param patternsToIncludeOrNil Limit paths to only those matching at least one pattern in this + * list. Supply nil to indicate no inclusion patterns. Paths are relative to the app's bundle. + * @param patternsToExcludeOrNil Exclude paths matching at least one of these patterns. + * Supply nil to indicate no exclusion patterns. + */ ++ (void)syncResourcePaths:(NSArray *)patternsToIncludeOrNil + excluding:(NSArray *)patternsToExcludeOrNil __attribute__((deprecated)); + +/** + * Syncs resources between Leanplum and the current app. + * You should only call this once, and before {@link start}. + * @param async Whether the call should be asynchronous. Resource syncing can take 1-2 seconds to + * index the app's resources. If async is set, resources may not be available immediately + * when the app starts. + * @param patternsToIncludeOrNil Limit paths to only those matching at least one pattern in this + * list. Supply nil to indicate no inclusion patterns. Paths are relative to the app's bundle. + * @param patternsToExcludeOrNil Exclude paths matching at least one of these patterns. + * Supply nil to indicate no exclusion patterns. + * @param async Whether the call should be asynchronous. Resource syncing can take 1-2 seconds to + * index the app's resources. If async is set, resources may not be available immediately + * when the app starts. + */ ++ (void)syncResourcePaths:(NSArray *)patternsToIncludeOrNil + excluding:(NSArray *)patternsToExcludeOrNil + async:(BOOL)async; +/**@}*/ + +/** + * @{ + * Call this when your application starts. + * This will initiate a call to Leanplum's servers to get the values + * of the variables used in your app. + */ ++ (void)start; ++ (void)startWithResponseHandler:(LeanplumStartBlock)response; ++ (void)startWithUserAttributes:(NSDictionary *)attributes; ++ (void)startWithUserId:(NSString *)userId; ++ (void)startWithUserId:(NSString *)userId responseHandler:(LeanplumStartBlock)response; ++ (void)startWithUserId:(NSString *)userId userAttributes:(NSDictionary *)attributes; ++ (void)startWithUserId:(NSString *)userId userAttributes:(NSDictionary *)attributes + responseHandler:(LeanplumStartBlock)startResponse; +/**@}*/ + +/** + * @{ + * Returns whether or not Leanplum has finished starting. + */ ++ (BOOL)hasStarted; + +/** + * Returns whether or not Leanplum has finished starting and the device is registered + * as a developer. + */ ++ (BOOL)hasStartedAndRegisteredAsDeveloper; +/**@}*/ + +/** + * Block to call when the start call finishes, and variables are returned + * back from the server. Calling this multiple times will call each block + * in succession. + */ ++ (void)onStartResponse:(LeanplumStartBlock)block; + +/** + * Block to call when the variables receive new values from the server. + * This will be called on start, and also later on if the user is in an experiment + * that can update in realtime. + */ ++ (void)onVariablesChanged:(LeanplumVariablesChangedBlock)block; + +/** + * Block to call when the interface receive new values from the server. + * This will be called on start, and also later on if the user is in an experiment + * that can update in realtime. + */ ++ (void)onInterfaceChanged:(LeanplumInterfaceChangedBlock)block; + +/** + * Block to call when no more file downloads are pending (either when + * no files needed to be downloaded or all downloads have been completed). + */ ++ (void)onVariablesChangedAndNoDownloadsPending:(LeanplumVariablesChangedBlock)block; + +/** + * Block to call ONCE when no more file downloads are pending (either when + * no files needed to be downloaded or all downloads have been completed). + */ ++ (void)onceVariablesChangedAndNoDownloadsPending:(LeanplumVariablesChangedBlock)block; + +/** + * @{ + * Defines new action and message types to be performed at points set up on the Leanplum dashboard. + */ ++ (void)defineAction:(NSString *)name ofKind:(LeanplumActionKind)kind withArguments:(NSArray *)args; ++ (void)defineAction:(NSString *)name ofKind:(LeanplumActionKind)kind withArguments:(NSArray *)args + withOptions:(NSDictionary *)options; ++ (void)defineAction:(NSString *)name ofKind:(LeanplumActionKind)kind withArguments:(NSArray *)args + withResponder:(LeanplumActionBlock)responder; ++ (void)defineAction:(NSString *)name ofKind:(LeanplumActionKind)kind withArguments:(NSArray *)args + withOptions:(NSDictionary *)options + withResponder:(LeanplumActionBlock)responder; +/**@}*/ + +/** + * Block to call when an action is received, such as to show a message to the user. + */ ++ (void)onAction:(NSString *)actionName invoke:(LeanplumActionBlock)block; + +/** + * Handles a push notification for apps that use Background Notifications. + * Without background notifications, Leanplum handles them automatically. + * Deprecated. Leanplum calls handleNotification automatically now. If you + * implement application:didReceiveRemoteNotification:fetchCompletionHandler: + * in your app delegate, you should remove any calls to [Leanplum handleNotification] + * and call the completion handler yourself. + */ ++ (void)handleNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(LeanplumFetchCompletionBlock)completionHandler + __attribute__((deprecated("Leanplum calls handleNotification automatically now. If you " + "implement application:didReceiveRemoteNotification:fetchCompletionHandler: in your app " + "delegate, you should remove any calls to [Leanplum handleNotification] and call the " + "completion handler yourself."))); + +#if LP_NOT_TV +/** + * Call this to handle custom actions for local notifications. + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-Wstrict-prototypes" ++ (void)handleActionWithIdentifier:(NSString *)identifier + forLocalNotification:(UILocalNotification *)notification + completionHandler:(void (^)())completionHandler; +#pragma clang diagnostic pop +#endif + +/** + * Call this to handle custom actions for remote notifications. + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" ++ (void)handleActionWithIdentifier:(NSString *)identifier + forRemoteNotification:(NSDictionary *)notification + completionHandler:(void (^)())completionHandler; +#pragma clang diagnostic pop + +/* + * Block to call that decides whether a notification should be displayed when it is + * received while the app is running, and the notification is not muted. + * Overrides the default behavior of showing an alert view with the notification message. + */ ++ (void)setShouldOpenNotificationHandler:(LeanplumShouldHandleNotificationBlock)block; + +/** + * @{ + * Adds a responder to be executed when an event happens. + * Similar to the methods above but uses NSInvocations instead of blocks. + * @see onStartResponse: + */ ++ (void)addStartResponseResponder:(id)responder withSelector:(SEL)selector; ++ (void)addVariablesChangedResponder:(id)responder withSelector:(SEL)selector; ++ (void)addInterfaceChangedResponder:(id)responder withSelector:(SEL)selector; ++ (void)addVariablesChangedAndNoDownloadsPendingResponder:(id)responder withSelector:(SEL)selector; ++ (void)addResponder:(id)responder withSelector:(SEL)selector forActionNamed:(NSString *)actionName; ++ (void)removeStartResponseResponder:(id)responder withSelector:(SEL)selector; ++ (void)removeVariablesChangedResponder:(id)responder withSelector:(SEL)selector; ++ (void)removeInterfaceChangedResponder:(id)responder withSelector:(SEL)selector; ++ (void)removeVariablesChangedAndNoDownloadsPendingResponder:(id)responder withSelector:(SEL)selector; ++ (void)removeResponder:(id)responder withSelector:(SEL)selector forActionNamed:(NSString *)actionName; +/**@}*/ + +/** + * Sets additional user attributes after the session has started. + * Variables retrieved by start won't be targeted based on these attributes, but + * they will count for the current session for reporting purposes. + * Only those attributes given in the dictionary will be updated. All other + * attributes will be preserved. + */ ++ (void)setUserAttributes:(NSDictionary *)attributes; + +/** + * Updates a user ID after session start. + */ ++ (void)setUserId:(NSString *)userId; + +/** + * Updates a user ID after session start with a dictionary of user attributes. + */ ++ (void)setUserId:(NSString *)userId withUserAttributes:(NSDictionary *)attributes; + +/** + * Sets the traffic source info for the current user. + * Keys in info must be one of: publisherId, publisherName, publisherSubPublisher, + * publisherSubSite, publisherSubCampaign, publisherSubAdGroup, publisherSubAd. + */ ++ (void)setTrafficSourceInfo:(NSDictionary *)info; + +/** + * @{ + * Advances to a particular state in your application. The string can be + * any value of your choosing, and will show up in the dashboard. + * A state is a section of your app that the user is currently in. + * @param state The name of the state. + */ ++ (void)advanceTo:(NSString *)state; + +/** + * Advances to a particular state in your application. The string can be + * any value of your choosing, and will show up in the dashboard. + * A state is a section of your app that the user is currently in. + * @param state The name of the state. + * @param info Anything else you want to log with the state. For example, if the state + * is watchVideo, info could be the video ID. + */ ++ (void)advanceTo:(NSString *)state withInfo:(NSString *)info; + +/** + * Advances to a particular state in your application. The string can be + * any value of your choosing, and will show up in the dashboard. + * A state is a section of your app that the user is currently in. + * You can specify up to 200 types of parameters per app across all events and state. + * The parameter keys must be strings, and values either strings or numbers. + * @param state The name of the state. + * @param params A dictionary with custom parameters. + */ ++ (void)advanceTo:(NSString *)state withParameters:(NSDictionary *)params; + +/** + * Advances to a particular state in your application. The string can be + * any value of your choosing, and will show up in the dashboard. + * A state is a section of your app that the user is currently in. + * You can specify up to 200 types of parameters per app across all events and state. + * The parameter keys must be strings, and values either strings or numbers. + * @param state The name of the state. (nullable) + * @param info Anything else you want to log with the state. For example, if the state + * is watchVideo, info could be the video ID. + * @param params A dictionary with custom parameters. + */ ++ (void)advanceTo:(NSString *)state withInfo:(NSString *)info andParameters:(NSDictionary *)params; + +/** + * Pauses the current state. + * You can use this if your game has a "pause" mode. You shouldn't call it + * when someone switches out of your app because that's done automatically. + */ ++ (void)pauseState; + +/** + * Resumes the current state. + */ ++ (void)resumeState; + +/** + * Automatically tracks all of the screens in the app as states. + * You should not use this in conjunction with advanceTo as the user can only be in + * 1 state at a time. This method requires LeanplumUIEditor module. + */ ++ (void)trackAllAppScreens; + +/** + * LPTrackScreenMode enum. + * LPTrackScreenModeDefault mans that states are the full view controller type name. + * LPTrackScreenModeStripViewController will cause the string "ViewController" to be stripped from + * the end of the state. + */ +typedef NS_ENUM(NSUInteger, LPTrackScreenMode) { + LPTrackScreenModeDefault = 0, + LPTrackScreenModeStripViewController +}; + +/** + * Automatically tracks all of the screens in the app as states. + * You should not use this in conjunction with advanceTo as the user can only be in + * 1 state at a time. This method requires LeanplumUIEditor module. + * @param trackScreenMode Choose mode for display. Default is the view controller type name. + */ ++ (void)trackAllAppScreensWithMode:(LPTrackScreenMode)trackScreenMode; + +/** + * Manually track purchase event with currency code in your application. It is advised to use + * trackInAppPurchases to automatically track IAPs. + */ ++ (void)trackPurchase:(NSString *)event withValue:(double)value + andCurrencyCode:(NSString *)currencyCode andParameters:(NSDictionary *)params; + +/** + * Automatically tracks InApp purchase and does server side receipt validation. + */ ++ (void)trackInAppPurchases; + +/** + * Manually tracks InApp purchase and does server side receipt validation. + */ ++ (void)trackInAppPurchase:(SKPaymentTransaction *)transaction; +/**@}*/ + +/** + * @{ + * Logs a particular event in your application. The string can be + * any value of your choosing, and will show up in the dashboard. + * To track a purchase, use LP_PURCHASE_EVENT. + */ ++ (void)track:(NSString *)event; ++ (void)track:(NSString *)event withValue:(double)value; ++ (void)track:(NSString *)event withInfo:(NSString *)info; ++ (void)track:(NSString *)event withValue:(double)value andInfo:(NSString *)info; + +// See above for the explanation of params. ++ (void)track:(NSString *)event withParameters:(NSDictionary *)params; ++ (void)track:(NSString *)event withValue:(double)value andParameters:(NSDictionary *)params; ++ (void)track:(NSString *)event withValue:(double)value andInfo:(NSString *)info andParameters:(NSDictionary *)params; +/**@}*/ + +/** + * @{ + * Gets the path for a particular resource. The resource can be overridden by the server. + */ ++ (NSString *)pathForResource:(NSString *)name ofType:(NSString *)extension; ++ (id)objectForKeyPath:(id)firstComponent, ... NS_REQUIRES_NIL_TERMINATION; ++ (id)objectForKeyPathComponents:(NSArray *)pathComponents; +/**@}*/ + +/** + * Gets a list of variants that are currently active for this user. + * Each variant is a dictionary containing an id. + */ ++ (NSArray *)variants; + +/** + * Returns metadata for all active in-app messages. + * Recommended only for debugging purposes and advanced use cases. + */ ++ (NSDictionary *)messageMetadata; + +/** + * Forces content to update from the server. If variables have changed, the + * appropriate callbacks will fire. Use sparingly as if the app is updated, + * you'll have to deal with potentially inconsistent state or user experience. + */ ++ (void)forceContentUpdate; + +/** + * Forces content to update from the server. If variables have changed, the + * appropriate callbacks will fire. Use sparingly as if the app is updated, + * you'll have to deal with potentially inconsistent state or user experience. + * The provided callback will always fire regardless + * of whether the variables have changed. + */ ++ (void)forceContentUpdate:(LeanplumVariablesChangedBlock)block; + +/** + * This should be your first statement in a unit test. This prevents + * Leanplum from communicating with the server. + */ ++ (void)enableTestMode; + +/** + * Used to enable or disable test mode. Test mode prevents Leanplum from + * communicating with the server. This is useful for unit tests. + */ ++ (void)setTestModeEnabled:(BOOL)isTestModeEnabled; + +/** + * Customize push setup. If this API should be called before [Leanplum start]. If this API is not + * used the default push setup from the docs will be used for "Push Ask to Ask" and + * "Register For Push". + */ ++ (void)setPushSetup:(LeanplumPushSetupBlock)block; + +/** + * Get the push setup block. + */ ++ (LeanplumPushSetupBlock)pushSetupBlock; + +/** + * Returns YES if the app existed on the device more than a day previous to a version built with + * Leanplum was installed. + */ ++ (BOOL)isPreLeanplumInstall; + +/** + * Returns the deviceId in the current Leanplum session. This should only be called after + * [Leanplum start]. + */ ++ (NSString *)deviceId; + +/** + * Returns the userId in the current Leanplum session. This should only be called after + * [Leanplum start]. + */ ++ (NSString *)userId; + +/** + * Returns an instance to the singleton LPInbox object. + */ ++ (LPInbox *)inbox; + +/** + * Returns an instance to the singleton LPNewsfeed object. + * Deprecated. Use {@link inbox} instead. + */ ++ (LPNewsfeed *)newsfeed __attribute__((deprecated("Use inbox instead."))); + +/** + * Types of location accuracy. Higher value implies better accuracy. + */ +typedef enum { + LPLocationAccuracyIP = 0, + LPLocationAccuracyCELL = 1, + LPLocationAccuracyGPS = 2 +} LPLocationAccuracyType; + +/** + * Set location manually. Calls setDeviceLocationWithLatitude:longitude:type: with cell type. + * Best if used in after calling setDeviceLocationWithLatitude:. + */ ++ (void)setDeviceLocationWithLatitude:(double)latitude + longitude:(double)longitude; + +/** + * Set location manually. Best if used in after calling setDeviceLocationWithLatitude:. + * Useful if you want to apply additional logic before sending in the location. + */ ++ (void)setDeviceLocationWithLatitude:(double)latitude + longitude:(double)longitude + type:(LPLocationAccuracyType)type; + +/** + * Set location manually. Best if used in after calling setDeviceLocationWithLatitude:. + * If you have the CLPlacemark info: city is locality, region is administrativeArea, + * and country is ISOcountryCode. + */ ++ (void)setDeviceLocationWithLatitude:(double)latitude + longitude:(double)longitude + city:(NSString *)city + region:(NSString *)region + country:(NSString *)country + type:(LPLocationAccuracyType)type; + +/** + * Disables collecting location automatically. Will do nothing if Leanplum-Location is not used. + */ ++ (void)disableLocationCollection; + +@end + +@interface LeanplumCompatibility : NSObject + +/** + * Used only for compatibility with Google Analytics. + */ ++ (void)gaTrack:(NSObject *)trackingObject; + +@end + +@class LPVar; + +/** + * Receives callbacks for {@link LPVar} + */ +@protocol LPVarDelegate +@optional +/** + * For file variables, called when the file is ready. + */ +- (void)fileIsReady:(LPVar *)var; +/** + * Called when the value of the variable changes. + */ +- (void)valueDidChange:(LPVar *)var; +@end + +/** + * A variable is any part of your application that can change from an experiment. + * Check out {@link Macros the macros} for defining variables more easily. + */ +@interface LPVar : NSObject +/** + * @{ + * Defines a {@link LPVar} + */ + ++ (LPVar *)define:(NSString *)name; ++ (LPVar *)define:(NSString *)name withInt:(int)defaultValue; ++ (LPVar *)define:(NSString *)name withFloat:(float)defaultValue; ++ (LPVar *)define:(NSString *)name withDouble:(double)defaultValue; ++ (LPVar *)define:(NSString *)name withCGFloat:(CGFloat)cgFloatValue; ++ (LPVar *)define:(NSString *)name withShort:(short)defaultValue; ++ (LPVar *)define:(NSString *)name withChar:(char)defaultValue; ++ (LPVar *)define:(NSString *)name withBool:(BOOL)defaultValue; ++ (LPVar *)define:(NSString *)name withString:(NSString *)defaultValue; ++ (LPVar *)define:(NSString *)name withNumber:(NSNumber *)defaultValue; ++ (LPVar *)define:(NSString *)name withInteger:(NSInteger)defaultValue; ++ (LPVar *)define:(NSString *)name withLong:(long)defaultValue; ++ (LPVar *)define:(NSString *)name withLongLong:(long long)defaultValue; ++ (LPVar *)define:(NSString *)name withUnsignedChar:(unsigned char)defaultValue; ++ (LPVar *)define:(NSString *)name withUnsignedInt:(unsigned int)defaultValue; ++ (LPVar *)define:(NSString *)name withUnsignedInteger:(NSUInteger)defaultValue; ++ (LPVar *)define:(NSString *)name withUnsignedLong:(unsigned long)defaultValue; ++ (LPVar *)define:(NSString *)name withUnsignedLongLong:(unsigned long long)defaultValue; ++ (LPVar *)define:(NSString *)name withUnsignedShort:(unsigned short)defaultValue; ++ (LPVar *)define:(NSString *)name withFile:(NSString *)defaultFilename; ++ (LPVar *)define:(NSString *)name withDictionary:(NSDictionary *)defaultValue; ++ (LPVar *)define:(NSString *)name withArray:(NSArray *)defaultValue; ++ (LPVar *)define:(NSString *)name withColor:(UIColor *)defaultValue; +/**@}*/ + +/** + * Returns the name of the variable. + */ +- (NSString *)name; + +/** + * Returns the components of the variable's name. + */ +- (NSArray *)nameComponents; + +/** + * Returns the default value of a variable. + */ +- (id)defaultValue; + +/** + * Returns the kind of the variable. + */ +- (NSString *)kind; + +/** + * Returns whether the variable has changed since the last time the app was run. + */ +- (BOOL)hasChanged; + +/** + * For file variables, called when the file is ready. + */ +- (void)onFileReady:(LeanplumVariablesChangedBlock)block; + +/** + * Called when the value of the variable changes. + */ +- (void)onValueChanged:(LeanplumVariablesChangedBlock)block; + +/** + * Sets the delegate of the variable in order to use + * {@link LPVarDelegate::fileIsReady:} and {@link LPVarDelegate::valueDidChange:} + */ +- (void)setDelegate:(id )delegate; + +/** + * @{ + * Accessess the value(s) of the variable + */ +- (id)objectForKey:(NSString *)key; +- (id)objectAtIndex:(NSUInteger )index; +- (id)objectForKeyPath:(id)firstComponent, ... NS_REQUIRES_NIL_TERMINATION; +- (id)objectForKeyPathComponents:(NSArray *)pathComponents; +- (NSUInteger)count; + +- (NSNumber *)numberValue; +- (NSString *)stringValue; +- (NSString *)fileValue; +- (UIImage *)imageValue; +- (int)intValue; +- (double)doubleValue; +- (CGFloat)cgFloatValue; +- (float)floatValue; +- (short)shortValue; +- (BOOL)boolValue; +- (char)charValue; +- (long)longValue; +- (long long)longLongValue; +- (NSInteger)integerValue; +- (unsigned char)unsignedCharValue; +- (unsigned short)unsignedShortValue; +- (unsigned int)unsignedIntValue; +- (NSUInteger)unsignedIntegerValue; +- (unsigned long)unsignedLongValue; +- (unsigned long long)unsignedLongLongValue; +- (UIColor *)colorValue; +/**@}*/ +@end + +@interface LPActionArg : NSObject +/** + * @{ + * Defines a Leanplum Action Argument + */ ++ (LPActionArg *)argNamed:(NSString *)name withNumber:(NSNumber *)defaultValue; ++ (LPActionArg *)argNamed:(NSString *)name withString:(NSString *)defaultValue; ++ (LPActionArg *)argNamed:(NSString *)name withBool:(BOOL)defaultValue; ++ (LPActionArg *)argNamed:(NSString *)name withFile:(NSString *)defaultValue; ++ (LPActionArg *)argNamed:(NSString *)name withDict:(NSDictionary *)defaultValue; ++ (LPActionArg *)argNamed:(NSString *)name withArray:(NSArray *)defaultValue; ++ (LPActionArg *)argNamed:(NSString *)name withAction:(NSString *)defaultValue; ++ (LPActionArg *)argNamed:(NSString *)name withColor:(UIColor *)defaultValue; +/**@}*/ +- (NSString *)name; +- (NSString *)kind; +- (id)defaultValue; + +@end + +@interface LPActionContext : NSObject + +- (NSString *)actionName; + +- (NSString *)stringNamed:(NSString *)name; +- (NSString *)fileNamed:(NSString *)name; +- (NSNumber *)numberNamed:(NSString *)name; +- (BOOL)boolNamed:(NSString *)name; +- (NSDictionary *)dictionaryNamed:(NSString *)name; +- (NSArray *)arrayNamed:(NSString *)name; +- (UIColor *)colorNamed:(NSString *)name; +- (NSString *)htmlWithTemplateNamed:(NSString *)templateName; + +/** + * Runs the action given by the "name" key. + */ +- (void)runActionNamed:(NSString *)name; + +/** + * Runs and tracks an event for the action given by the "name" key. + * This will track an event if no action is set. + */ +- (void)runTrackedActionNamed:(NSString *)name; + +/** + * Tracks an event in the context of the current message. + */ +- (void)track:(NSString *)event withValue:(double)value andParameters:(NSDictionary *)params; + +/** + * Tracks an event in the conext of the current message, with any parent actions prepended to the + * message event name. + */ +- (void)trackMessageEvent:(NSString *)event + withValue:(double)value + andInfo:(NSString *)info + andParameters:(NSDictionary *)params; + +/** + * Prevents the currently active message from appearing again in the future. + */ +- (void)muteFutureMessagesOfSameKind; + +/** + * Checks if the action context has any missing files that still need to be downloaded. + */ +- (BOOL)hasMissingFiles; + +@end diff --git a/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Info.plist b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Info.plist new file mode 100644 index 0000000000..64b91413ba Binary files /dev/null and b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Info.plist differ diff --git a/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Leanplum b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Leanplum new file mode 100644 index 0000000000..d50c85e23d Binary files /dev/null and b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Leanplum differ diff --git a/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Modules/module.modulemap b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Modules/module.modulemap new file mode 100644 index 0000000000..a296b0cec2 --- /dev/null +++ b/mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module Leanplum { + umbrella header "Leanplum.h" + + export * + module * { export * } +} diff --git a/mobile/ios/ThirdParty/Reachability.swift b/mobile/ios/ThirdParty/Reachability.swift new file mode 100644 index 0000000000..ba526a14c2 --- /dev/null +++ b/mobile/ios/ThirdParty/Reachability.swift @@ -0,0 +1,115 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Isuru Nanayakkara +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + + +import Foundation +import SystemConfiguration + + +let ReachabilityStatusChangedNotification = "ReachabilityStatusChangedNotification" + +enum ReachabilityType: CustomStringConvertible { + case wwan + case wiFi + + var description: String { + switch self { + case .wwan: return "WWAN" + case .wiFi: return "WiFi" + } + } +} + +enum ReachabilityStatus: CustomStringConvertible { + case offline + case online(ReachabilityType) + case unknown + + var description: String { + switch self { + case .offline: return "Offline" + case .online(let type): return "Online (\(type))" + case .unknown: return "Unknown" + } + } +} + +open class Reach { + + func connectionStatus() -> ReachabilityStatus { + var zeroAddress = sockaddr_in() + zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress)) + zeroAddress.sin_family = sa_family_t(AF_INET) + + guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, { + $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { + SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0) + } + }) else { + return .unknown + } + + var flags : SCNetworkReachabilityFlags = [] + if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) { + return .unknown + } + + return ReachabilityStatus(reachabilityFlags: flags) + } + + + func monitorReachabilityChanges() { + let host = "google.com" + var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) + let reachability = SCNetworkReachabilityCreateWithName(nil, host)! + + SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in + let status = ReachabilityStatus(reachabilityFlags: flags) + + NotificationCenter.default.post(name: Notification.Name(rawValue: ReachabilityStatusChangedNotification), + object: nil, + userInfo: ["Status": status.description]) + + }, &context) + + SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue) + } + +} + +extension ReachabilityStatus { + fileprivate init(reachabilityFlags flags: SCNetworkReachabilityFlags) { + let connectionRequired = flags.contains(.connectionRequired) + let isReachable = flags.contains(.reachable) + let isWWAN = flags.contains(.isWWAN) + + if !connectionRequired && isReachable { + if isWWAN { + self = .online(.wwan) + } else { + self = .online(.wiFi) + } + } else { + self = .offline + } + } +} diff --git a/mobile/ios/ThirdParty/Result/Error.swift b/mobile/ios/ThirdParty/Result/Error.swift new file mode 100644 index 0000000000..d2368e5c84 --- /dev/null +++ b/mobile/ios/ThirdParty/Result/Error.swift @@ -0,0 +1,11 @@ +// +// Error.swift +// Result +// +// Created by John Gallagher on 9/12/14. +// Copyright (c) 2014 Big Nerd Ranch. All rights reserved. +// + +import Foundation + +public typealias MaybeErrorType = Error & CustomStringConvertible diff --git a/mobile/ios/ThirdParty/Result/LICENSE b/mobile/ios/ThirdParty/Result/LICENSE new file mode 100644 index 0000000000..0bc4d34ae4 --- /dev/null +++ b/mobile/ios/ThirdParty/Result/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 John Gallagher + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/mobile/ios/ThirdParty/Result/README.md b/mobile/ios/ThirdParty/Result/README.md new file mode 100644 index 0000000000..788d118e14 --- /dev/null +++ b/mobile/ios/ThirdParty/Result/README.md @@ -0,0 +1,24 @@ +# Result + +`Result` is a Swift framework that includes the `Result` enum and an +`ErrorType` protocol. + +Both types are extremely small. I look forward to two changes in Swift's future: + +* A fix for the Swift compiler issue that requires the `Success` case of + `Result` to box its `T` type somehow. This repo uses + [Box](https://github.com/robrix/Box) as a workaround. +* (Hopefully) The inclusion of these types or their moral equivalents in the + Swift standard library, at which point this repo can be removed. + +## Integration + +Add this repository as a submodule, or use [Carthage](https://github.com/Carthage/Carthage/). + +## Author + +John Gallagher, jgallagher@bignerdranch.com + +## License + +Deferred is available under the MIT license. See the LICENSE file for more info. diff --git a/mobile/ios/ThirdParty/Result/Result.swift b/mobile/ios/ThirdParty/Result/Result.swift new file mode 100644 index 0000000000..fc47e8e527 --- /dev/null +++ b/mobile/ios/ThirdParty/Result/Result.swift @@ -0,0 +1,76 @@ +// +// Result.swift +// Result +// +// Created by John Gallagher on 9/12/14. +// Copyright (c) 2014 Big Nerd Ranch. All rights reserved. +// + +import Foundation +//import Box + +public enum Maybe { + case failure(MaybeErrorType) + + // TODO: Get rid of Box hack at some point after 6.3 + case success(Box) + + public init(failure: MaybeErrorType) { + self = .failure(failure) + } + + public init(success: T) { + self = .success(Box(success)) + } + + public var successValue: T? { + switch self { + case let .success(success): return success.value + case .failure: return nil + } + } + + public var failureValue: MaybeErrorType? { + switch self { + case .success: return nil + case let .failure(error): return error + } + } + + public var isSuccess: Bool { + switch self { + case .success: return true + case .failure: return false + } + } + + public var isFailure: Bool { + switch self { + case .success: return false + case .failure: return true + } + } + + public func map(_ f: (T) -> U) -> Maybe { + switch self { + case let .failure(error): return .failure(error) + case let .success(value): return .success(Box(f(value.value))) + } + } + + public func bind(_ f: (T) -> Maybe) -> Maybe { + switch self { + case let .failure(error): return .failure(error) + case let .success(value): return f(value.value) + } + } +} + +extension Maybe: CustomStringConvertible { + public var description: String { + switch self { + case let .failure(error): return "Result.Failure(\(error))" + case let .success(value): return "Result.Success(\(value.value))" + } + } +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/.cocoadocs.yml b/mobile/ios/ThirdParty/SQLite.swift/.cocoadocs.yml new file mode 100644 index 0000000000..2784003281 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/.cocoadocs.yml @@ -0,0 +1,2 @@ +additional_guides: + - Documentation/Index.md diff --git a/mobile/ios/ThirdParty/SQLite.swift/.gitignore b/mobile/ios/ThirdParty/SQLite.swift/.gitignore new file mode 100644 index 0000000000..5882e0cb82 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/.gitignore @@ -0,0 +1,27 @@ +# OS X +.DS_Store + +# Xcode +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate + +# Carthage +/Carthage/ + +# Swift Package Manager +.build +Packages/ diff --git a/modules/zlib/src/arch/generic/compare256_p.h b/mobile/ios/ThirdParty/SQLite.swift/.gitmodules similarity index 100% rename from modules/zlib/src/arch/generic/compare256_p.h rename to mobile/ios/ThirdParty/SQLite.swift/.gitmodules diff --git a/mobile/ios/ThirdParty/SQLite.swift/.swift-version b/mobile/ios/ThirdParty/SQLite.swift/.swift-version new file mode 100644 index 0000000000..9f55b2ccb5 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/.swift-version @@ -0,0 +1 @@ +3.0 diff --git a/mobile/ios/ThirdParty/SQLite.swift/.travis.yml b/mobile/ios/ThirdParty/SQLite.swift/.travis.yml new file mode 100644 index 0000000000..3747ac7b89 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/.travis.yml @@ -0,0 +1,26 @@ +language: objective-c +rvm: 2.2 +osx_image: xcode8.2 +env: + global: + - IOS_SIMULATOR="iPhone 6s" +matrix: + include: + - env: BUILD_SCHEME="SQLite iOS" + - env: BUILD_SCHEME="SQLite Mac" + - env: VALIDATOR_SUBSPEC="none" + - env: VALIDATOR_SUBSPEC="standard" + - env: VALIDATOR_SUBSPEC="standalone" + - env: VALIDATOR_SUBSPEC="SQLCipher" + - env: CARTHAGE_PLATFORM="iOS" + - env: CARTHAGE_PLATFORM="Mac" + - env: CARTHAGE_PLATFORM="watchOS" + - env: CARTHAGE_PLATFORM="tvOS" + - env: PACKAGE_MANAGER_COMMAND="test -Xlinker -lsqlite3" +before_install: + - gem update bundler + - gem install xcpretty --no-document + - brew update + - brew outdated carthage || brew upgrade carthage +script: + - ./run-tests.sh diff --git a/mobile/ios/ThirdParty/SQLite.swift/CHANGELOG.md b/mobile/ios/ThirdParty/SQLite.swift/CHANGELOG.md new file mode 100644 index 0000000000..f3298d68f9 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CHANGELOG.md @@ -0,0 +1,34 @@ +0.11.2 (25-12-2016), [diff][diff-0.11.2] +======================================== + +* Fixed SQLCipher integration with read-only databases ([#559][]) +* Preliminary Swift Package Manager support ([#548][], [#560][]) +* Fixed null pointer when fetching an empty BLOB ([#561][]) +* Allow `where` as alias for `filter` ([#571][]) + +0.11.1 (06-12-2016), [diff][diff-0.11.1] +======================================== + +* Integrate SQLCipher via CocoaPods ([#546][], [#553][]) +* Made lastInsertRowid consistent with other SQLite wrappers ([#532][]) +* Fix for ~= operator used with Double ranges +* Various documentation updates + +0.11.0 (19-10-2016) +=================== + +* Swift3 migration ([diff][diff-0.11.0]) + + +[diff-0.11.0]: https://github.com/stephencelis/SQLite.swift/compare/0.10.1...0.11.0 +[diff-0.11.1]: https://github.com/stephencelis/SQLite.swift/compare/0.11.0...0.11.1 +[diff-0.11.2]: https://github.com/stephencelis/SQLite.swift/compare/0.11.1...0.11.2 + +[#532]: https://github.com/stephencelis/SQLite.swift/issues/532 +[#546]: https://github.com/stephencelis/SQLite.swift/issues/546 +[#548]: https://github.com/stephencelis/SQLite.swift/pull/548 +[#553]: https://github.com/stephencelis/SQLite.swift/pull/553 +[#559]: https://github.com/stephencelis/SQLite.swift/pull/559 +[#560]: https://github.com/stephencelis/SQLite.swift/pull/560 +[#561]: https://github.com/stephencelis/SQLite.swift/issues/561 +[#571]: https://github.com/stephencelis/SQLite.swift/issues/571 diff --git a/mobile/ios/ThirdParty/SQLite.swift/CONTRIBUTING.md b/mobile/ios/ThirdParty/SQLite.swift/CONTRIBUTING.md new file mode 100644 index 0000000000..60c1837048 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CONTRIBUTING.md @@ -0,0 +1,108 @@ +# Contributing + +The where and when to open an [issue](#issues) or [pull +request](#pull-requests). + + +## Issues + +Issues are used to track **bugs** and **feature requests**. Need **help** or +have a **general question**? [Ask on Stack Overflow][] (tag `sqlite.swift`). + +Before reporting a bug or requesting a feature, [run a few searches][Search] to +see if a similar issue has already been opened and ensure you’re not submitting +a duplicate. + +If you find a similar issue, read the existing conversation and see if it +addresses everything. If it doesn’t, continue the conversation there. + +If your searches return empty, see the [bug](#bugs) or [feature +request](#feature-requests) guidelines below. + +[Ask on Stack Overflow]: http://stackoverflow.com/questions/tagged/sqlite.swift +[Search]: https://github.com/stephencelis/SQLite.swift/search?type=Issues + + +### Bugs + +Think you’ve discovered a new **bug**? Let’s try troubleshooting a few things +first. + + - **Is it an installation issue?** + + If this is your first time building SQLite.swift in your project, you may + encounter a build error, _e.g._: + + No such module 'SQLite' + + Please carefully re-read the [installation instructions][] to make sure + everything is in order. + + - **Have you read the documentation?** + + If you can’t seem to get something working, check + [the documentation][See Documentation] to see if the solution is there. + + - **Are you up-to-date?** + + If you’re perusing [the documentation][See Documentation] online and find + that an example is just not working, please upgrade to the latest version + of SQLite.swift and try again before continuing. + + - **Is it an unhelpful build error?** + + While Swift error messaging is improving with each release, complex + expressions still lend themselves to misleading errors. If you encounter an + error on a complex line, breaking it down into smaller pieces generally + yields a more understandable error. + + - **Is it an _even more_ unhelpful build error?** + + Have you updated Xcode recently? Did your project stop building out of the + blue? + + Hold down the **option** key and select **Clean Build Folder…** from the + **Product** menu (⌥⇧⌘K). + +Made it through everything above and still having trouble? Sorry! +[Open an issue][]! And _please_: + + - Be as descriptive as possible. + - Provide as much information needed to _reliably reproduce_ the issue. + - Attach screenshots if possible. + - Better yet: attach GIFs or link to video. + - Even better: link to a sample project exhibiting the issue. + - Include the SQLite.swift commit or branch experiencing the issue. + - Include devices and operating systems affected. + - Include build information: the Xcode and OS X versions affected. + +[installation instructions]: Documentation/Index.md#installation +[See Documentation]: Documentation/Index.md#sqliteswift-documentation +[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new + + +### Feature Requests + +Have an innovative **feature request**? [Open an issue][]! Be thorough! Provide +context and examples. Be open to discussion. + + +## Pull Requests + +Interested in contributing but don’t know where to start? Try the [`help +wanted`][help wanted] label. + +Ready to submit a fix or a feature? [Submit a pull request][]! And _please_: + + - If code changes, run the tests and make sure everything still works. + - Write new tests for new functionality. + - Update documentation comments where applicable. + - Maintain the existing style. + - Don’t forget to have fun. + +While we cannot guarantee a merge to every pull request, we do read each one +and love your input. + + +[help wanted]: https://github.com/stephencelis/SQLite.swift/labels/help%20wanted +[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvos/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvos/module.modulemap new file mode 100644 index 0000000000..637d993582 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvos/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvsimulator/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvsimulator/module.modulemap new file mode 100644 index 0000000000..f8b9b671a7 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvsimulator/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos-10.0/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos-10.0/module.modulemap new file mode 100644 index 0000000000..67a6c20309 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos-10.0/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos/module.modulemap new file mode 100644 index 0000000000..043db6c484 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator-10.0/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator-10.0/module.modulemap new file mode 100644 index 0000000000..c8b84ab8f4 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator-10.0/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator10.0.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator/module.modulemap new file mode 100644 index 0000000000..a7b14cbb48 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.11/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.11/module.modulemap new file mode 100644 index 0000000000..9e0912979d --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.11/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.12/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.12/module.modulemap new file mode 100644 index 0000000000..8fc958e676 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.12/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx/module.modulemap new file mode 100644 index 0000000000..cc8370ec56 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchos/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchos/module.modulemap new file mode 100644 index 0000000000..62a6c4eef0 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchos/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchsimulator/module.modulemap b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchsimulator/module.modulemap new file mode 100644 index 0000000000..086fbab2de --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchsimulator/module.modulemap @@ -0,0 +1,4 @@ +module CSQLite [system] { + header "/Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk/usr/include/sqlite3.h" + export * +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Documentation/Index.md b/mobile/ios/ThirdParty/SQLite.swift/Documentation/Index.md new file mode 100644 index 0000000000..3e13ad4efe --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Documentation/Index.md @@ -0,0 +1,1587 @@ +# SQLite.swift Documentation + + - [Installation](#installation) + - [Carthage](#carthage) + - [CocoaPods](#cocoapods) + - [Swift Package Manager](#swift-package-manager) + - [Manual](#manual) + - [Getting Started](#getting-started) + - [Connecting to a Database](#connecting-to-a-database) + - [Read-Write Databases](#read-write-databases) + - [Read-Only Databases](#read-only-databases) + - [In-Memory Databases](#in-memory-databases) + - [Thread-Safety](#thread-safety) + - [Building Type-Safe SQL](#building-type-safe-sql) + - [Expressions](#expressions) + - [Compound Expressions](#compound-expressions) + - [Queries](#queries) + - [Creating a Table](#creating-a-table) + - [Create Table Options](#create-table-options) + - [Column Constraints](#column-constraints) + - [Table Constraints](#table-constraints) + - [Inserting Rows](#inserting-rows) + - [Setters](#setters) + - [Selecting Rows](#selecting-rows) + - [Iterating and Accessing Values](#iterating-and-accessing-values) + - [Plucking Rows](#plucking-rows) + - [Building Complex Queries](#building-complex-queries) + - [Selecting Columns](#selecting-columns) + - [Joining Other Tables](#joining-other-tables) + - [Column Namespacing](#column-namespacing) + - [Table Aliasing](#table-aliasing) + - [Filtering Rows](#filtering-rows) + - [Filter Operators and Functions](#filter-operators-and-functions) + - [Sorting Rows](#sorting-rows) + - [Limiting and Paging Results](#limiting-and-paging-results) + - [Aggregation](#aggregation) + - [Updating Rows](#updating-rows) + - [Deleting Rows](#deleting-rows) + - [Transactions and Savepoints](#transactions-and-savepoints) + - [Altering the Schema](#altering-the-schema) + - [Renaming Tables](#renaming-tables) + - [Adding Columns](#adding-columns) + - [Added Column Constraints](#added-column-constraints) + - [Indexes](#indexes) + - [Creating Indexes](#creating-indexes) + - [Dropping Indexes](#dropping-indexes) + - [Dropping Tables](#dropping-tables) + - [Migrations and Schema Versioning](#migrations-and-schema-versioning) + - [Custom Types](#custom-types) + - [Date-Time Values](#date-time-values) + - [Binary Data](#binary-data) + - [Custom Type Caveats](#custom-type-caveats) + - [Other Operators](#other-operators) + - [Core SQLite Functions](#core-sqlite-functions) + - [Aggregate SQLite Functions](#aggregate-sqlite-functions) + - [Custom SQL Functions](#custom-sql-functions) + - [Custom Collations](#custom-collations) + - [Full-text Search](#full-text-search) + - [Executing Arbitrary SQL](#executing-arbitrary-sql) + - [Logging](#logging) + + +[↩]: #sqliteswift-documentation + + +## Installation + +> _Note:_ SQLite.swift requires Swift 3 (and [Xcode 8](https://developer.apple.com/xcode/downloads/)) or greater. + + +### Carthage + +[Carthage][] is a simple, decentralized dependency manager for Cocoa. To +install SQLite.swift with Carthage: + + 1. Make sure Carthage is [installed][Carthage Installation]. + + 2. Update your Cartfile to include the following: + + ``` + github "stephencelis/SQLite.swift" ~> 0.11.2 + ``` + + 3. Run `carthage update` and [add the appropriate framework][Carthage Usage]. + + +[Carthage]: https://github.com/Carthage/Carthage +[Carthage Installation]: https://github.com/Carthage/Carthage#installing-carthage +[Carthage Usage]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application + + +### CocoaPods + +[CocoaPods][] is a dependency manager for Cocoa projects. To install SQLite.swift with CocoaPods: + + 1. Verify that your copy of Xcode is installed and active in the default location (`/Applications/Xcode.app`). + + ```sh + sudo xcode-select --switch /Applications/Xcode.app + ``` + + 2. Make sure CocoaPods is [installed][CocoaPods Installation] (SQLite.swift requires version 1.0.0 or greater). + + ``` sh + # Using the default Ruby install will require you to use sudo when + # installing and updating gems. + [sudo] gem install cocoapods + ``` + + 3. Update your Podfile to include the following: + + ``` ruby + use_frameworks! + + target 'YourAppTargetName' do + pod 'SQLite.swift', '~> 0.11.2' + end + ``` + + 4. Run `pod install --repo-update`. + + +#### Requiring a specific version of SQLite + + If you want to use a more recent version of SQLite than what is provided with the OS you can require the `standalone` subspec: + +``` ruby +target 'YourAppTargetName' do + pod 'SQLite.swift/standalone', '~> 0.11.2' +end +``` + +By default this will use the most recent version of SQLite without any extras. If you want you can further customize this by adding another dependency to sqlite3 or one of its subspecs: + +``` ruby +target 'YourAppTargetName' do + pod 'SQLite.swift/standalone', '~> 0.11.2' + pod 'sqlite3/fts5', '= 3.15.0' # SQLite 3.15.0 with FTS5 enabled +end +``` + +See the [sqlite3 podspec][sqlite3pod] for more details. + +#### Using SQLite.swift with SQLCipher + +If you want to use [SQLCipher][] with SQLite.swift you can require the `SQLCipher` +subspec in your Podfile: + +``` ruby +target 'YourAppTargetName' do + pod 'SQLite.swift/SQLCipher', '~> 0.11.2' +end +``` + +This will automatically add a dependency to the SQLCipher pod as well as extend +`Connection` with methods to change the database key: + +``` swift +import SQLite + +let db = try Connection("path/to/db.sqlite3") +try db.key("secret") +try db.rekey("another secret") +``` + +[CocoaPods]: https://cocoapods.org +[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started +[sqlite3pod]: https://github.com/clemensg/sqlite3pod +[SQLCipher]: https://www.zetetic.net/sqlcipher/ + +### Swift Package Manager + +The [Swift Package Manager][] is a tool for managing the distribution of Swift code. +It’s integrated with the Swift build system to automate the process of +downloading, compiling, and linking dependencies. + +It is the recommended approach for using SQLite.swift in OSX CLI applications. + + 1. Add the following to your `Package.swift` file: + + ``` swift + dependencies: [ + .Package(url: "https://github.com/stephencelis/SQLite.swift.git", majorVersion: 0, minor: 11) + ] + ``` + + 2. Build your project: + + ``` sh + $ swift build -Xlinker -lsqlite3 + ``` + +[Swift Package Manager]: https://swift.org/package-manager + +### Manual + +To install SQLite.swift as an Xcode sub-project: + + 1. Drag the **SQLite.xcodeproj** file into your own project. ([Submodule](http://git-scm.com/book/en/Git-Tools-Submodules), clone, or [download](https://github.com/stephencelis/SQLite.swift/archive/master.zip) the project first.) + + ![Installation Screen Shot](Resources/installation@2x.png) + + 2. In your target’s **General** tab, click the **+** button under **Linked Frameworks and Libraries**. + + 3. Select the appropriate **SQLite.framework** for your platform. + + 4. **Add**. + +You should now be able to `import SQLite` from any of your target’s source files and begin using SQLite.swift. + +Some additional steps are required to install the application on an actual device: + + 5. In the **General** tab, click the **+** button under **Embedded Binaries**. + + 6. Select the appropriate **SQLite.framework** for your platform. + + 7. **Add**. + +## Getting Started + +To use SQLite.swift classes or structures in your target’s source file, first import the `SQLite` module. + +``` swift +import SQLite +``` + + +### Connecting to a Database + +Database connections are established using the `Connection` class. A connection is initialized with a path to a database. SQLite will attempt to create the database file if it does not already exist. + +``` swift +let db = try Connection("path/to/db.sqlite3") +``` + + +#### Read-Write Databases + +On iOS, you can create a writable database in your app’s **Documents** directory. + +``` swift +let path = NSSearchPathForDirectoriesInDomains( + .documentDirectory, .userDomainMask, true +).first! + +let db = try Connection("\(path)/db.sqlite3") +``` + +On OS X, you can use your app’s **Application Support** directory: + +``` swift +var path = NSSearchPathForDirectoriesInDomains( + .applicationSupportDirectory, .userDomainMask, true +).first! + Bundle.main.bundleIdentifier! + +// create parent directory iff it doesn’t exist +try FileManager.default.createDirectoryAtPath( + path, withIntermediateDirectories: true, attributes: nil +) + +let db = try Connection("\(path)/db.sqlite3") +``` + + +#### Read-Only Databases + +If you bundle a database with your app (_i.e._, you’ve copied a database file into your Xcode project and added it to your application target), you can establish a _read-only_ connection to it. + +``` swift +let path = Bundle.main.pathForResource("db", ofType: "sqlite3")! + +let db = try Connection(path, readonly: true) +``` + +> _Note:_ Signed applications cannot modify their bundle resources. If you bundle a database file with your app for the purpose of bootstrapping, copy it to a writable location _before_ establishing a connection (see [Read-Write Databases](#read-write-databases), above, for typical, writable locations). +> +> See these two Stack Overflow questions for more information about iOS apps with SQLite databases: [1](https://stackoverflow.com/questions/34609746/what-different-between-store-database-in-different-locations-in-ios), [2](https://stackoverflow.com/questions/34614968/ios-how-to-copy-pre-seeded-database-at-the-first-running-app-with-sqlite-swift). We welcome sample code to show how to successfully copy and use a bundled "seed" database for writing in an app. + +#### In-Memory Databases + +If you omit the path, SQLite.swift will provision an [in-memory database](https://www.sqlite.org/inmemorydb.html). + +``` swift +let db = try Connection() // equivalent to `Connection(.inMemory)` +``` + +To create a temporary, disk-backed database, pass an empty file name. + +``` swift +let db = try Connection(.temporary) +``` + +In-memory databases are automatically deleted when the database connection is closed. + + +#### Thread-Safety + +Every Connection comes equipped with its own serial queue for statement execution and can be safely accessed across threads. Threads that open transactions and savepoints will block other threads from executing statements while the transaction is open. + +If you maintain multiple connections for a single database, consider setting a timeout (in seconds) and/or a busy handler: + +```swift +db.busyTimeout = 5 + +db.busyHandler({ tries in + if tries >= 3 { + return false + } + return true +}) +``` + +> _Note:_ The default timeout is 0, so if you see `database is locked` errors, you may be trying to access the same database simultaneously from multiple connections. + + +## Building Type-Safe SQL + +SQLite.swift comes with a typed expression layer that directly maps [Swift types](https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/) to their [SQLite counterparts](https://www.sqlite.org/datatype3.html). + +| Swift Type | SQLite Type | +| --------------- | ----------- | +| `Int64`* | `INTEGER` | +| `Double` | `REAL` | +| `String` | `TEXT` | +| `nil` | `NULL` | +| `SQLite.Blob`† | `BLOB` | + +> *While `Int64` is the basic, raw type (to preserve 64-bit integers on 32-bit platforms), `Int` and `Bool` work transparently. +> +> †SQLite.swift defines its own `Blob` structure, which safely wraps the underlying bytes. +> +> See [Custom Types](#custom-types) for more information about extending other classes and structures to work with SQLite.swift. +> +> See [Executing Arbitrary SQL](#executing-arbitrary-sql) to forego the typed layer and execute raw SQL, instead. + +These expressions (in the form of the structure, [`Expression`](#expressions)) build on one another and, with a query ([`QueryType`](#queries)), can create and execute SQL statements. + + +### Expressions + +Expressions are generic structures associated with a type ([built-in](#building-type-safe-sql) or [custom](#custom-types)), raw SQL, and (optionally) values to bind to that SQL. Typically, you will only explicitly create expressions to describe your columns, and typically only once per column. + +``` swift +let id = Expression("id") +let email = Expression("email") +let balance = Expression("balance") +let verified = Expression("verified") +``` + +Use optional generics for expressions that can evaluate to `NULL`. + +``` swift +let name = Expression("name") +``` + +> _Note:_ The default `Expression` initializer is for [quoted identifiers](https://www.sqlite.org/lang_keywords.html) (_i.e._, column names). To build a literal SQL expression, use `init(literal:)`. + + +### Compound Expressions + +Expressions can be combined with other expressions and types using [filter operators and functions](#filter-operators-and-functions) (as well as other [non-filter operators](#other-operators) and [functions](#core-sqlite-functions)). These building blocks can create complex SQLite statements. + + +### Queries + +Queries are structures that reference a database and table name, and can be used to build a variety of statements using expressions. We can create a query by initializing a `Table`, `View`, or `VirtualTable`. + +``` swift +let users = Table("users") +``` + +Assuming [the table exists](#creating-a-table), we can immediately [insert](#inserting-rows), [select](#selecting-rows), [update](#updating-rows), and [delete](#deleting-rows) rows. + + +## Creating a Table + +We can build [`CREATE TABLE` statements](https://www.sqlite.org/lang_createtable.html) by calling the `create` function on a `Table`. The following is a basic example of SQLite.swift code (using the [expressions](#expressions) and [query](#queries) above) and the corresponding SQL it generates. + +``` swift +try db.run(users.create { t in // CREATE TABLE "users" ( + t.column(id, primaryKey: true) // "id" INTEGER PRIMARY KEY NOT NULL, + t.column(email, unique: true) // "email" TEXT UNIQUE NOT NULL, + t.column(name) // "name" TEXT +}) // ) +``` + +> _Note:_ `Expression` structures (in this case, the `id` and `email` columns), generate `NOT NULL` constraints automatically, while `Expression` structures (`name`) do not. + + +### Create Table Options + +The `Table.create` function has several default parameters we can override. + + - `temporary` adds a `TEMPORARY` clause to the `CREATE TABLE` statement (to create a temporary table that will automatically drop when the database connection closes). Default: `false`. + + ``` swift + try db.run(users.create(temporary: true) { t in /* ... */ }) + // CREATE TEMPORARY TABLE "users" -- ... + ``` + + - `ifNotExists` adds an `IF NOT EXISTS` clause to the `CREATE TABLE` statement (which will bail out gracefully if the table already exists). Default: `false`. + + ``` swift + try db.run(users.create(ifNotExists: true) { t in /* ... */ }) + // CREATE TABLE "users" IF NOT EXISTS -- ... + ``` + +### Column Constraints + +The `column` function is used for a single column definition. It takes an [expression](#expressions) describing the column name and type, and accepts several parameters that map to various column constraints and clauses. + + - `primaryKey` adds a `PRIMARY KEY` constraint to a single column. + + ``` swift + t.column(id, primaryKey: true) + // "id" INTEGER PRIMARY KEY NOT NULL + + t.column(id, primaryKey: .autoincrement) + // "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL + ``` + + > _Note:_ The `primaryKey` parameter cannot be used alongside `references`. If you need to create a column that has a default value and is also a primary and/or foreign key, use the `primaryKey` and `foreignKey` functions mentioned under [Table Constraints](#table-constraints). + > + > Primary keys cannot be optional (_e.g._, `Expression`). + > + > Only an `INTEGER PRIMARY KEY` can take `.autoincrement`. + + - `unique` adds a `UNIQUE` constraint to the column. (See the `unique` function under [Table Constraints](#table-constraints) for uniqueness over multiple columns). + + ``` swift + t.column(email, unique: true) + // "email" TEXT UNIQUE NOT NULL + ``` + + - `check` attaches a `CHECK` constraint to a column definition in the form of a boolean expression (`Expression`). Boolean expressions can be easily built using [filter operators and functions](#filter-operators-and-functions). (See also the `check` function under [Table Constraints](#table-constraints).) + + ``` swift + t.column(email, check: email.like("%@%")) + // "email" TEXT NOT NULL CHECK ("email" LIKE '%@%') + ``` + + - `defaultValue` adds a `DEFAULT` clause to a column definition and _only_ accepts a value (or expression) matching the column’s type. This value is used if none is explicitly provided during [an `INSERT`](#inserting-rows). + + ``` swift + t.column(name, defaultValue: "Anonymous") + // "name" TEXT DEFAULT 'Anonymous' + ``` + + > _Note:_ The `defaultValue` parameter cannot be used alongside `primaryKey` and `references`. If you need to create a column that has a default value and is also a primary and/or foreign key, use the `primaryKey` and `foreignKey` functions mentioned under [Table Constraints](#table-constraints). + + - `collate` adds a `COLLATE` clause to `Expression` (and `Expression`) column definitions with [a collating sequence](https://www.sqlite.org/datatype3.html#collation) defined in the `Collation` enumeration. + + ``` swift + t.column(email, collate: .nocase) + // "email" TEXT NOT NULL COLLATE "NOCASE" + + t.column(name, collate: .rtrim) + // "name" TEXT COLLATE "RTRIM" + ``` + + - `references` adds a `REFERENCES` clause to `Expression` (and `Expression`) column definitions and accepts a table (`SchemaType`) or namespaced column expression. (See the `foreignKey` function under [Table Constraints](#table-constraints) for non-integer foreign key support.) + + ``` swift + t.column(user_id, references: users, id) + // "user_id" INTEGER REFERENCES "users" ("id") + + + + > _Note:_ The `references` parameter cannot be used alongside `primaryKey` and `defaultValue`. If you need to create a column that has a default value and is also a primary and/or foreign key, use the `primaryKey` and `foreignKey` functions mentioned under [Table Constraints](#table-constraints). + + +### Table Constraints + +Additional constraints may be provided outside the scope of a single column using the following functions. + + - `primaryKey` adds a `PRIMARY KEY` constraint to the table. Unlike [the column constraint, above](#column-constraints), it supports all SQLite types, [ascending and descending orders](#sorting-rows), and composite (multiple column) keys. + + ``` swift + t.primaryKey(email.asc, name) + // PRIMARY KEY("email" ASC, "name") + ``` + + - `unique` adds a `UNIQUE` constraint to the table. Unlike [the column constraint, above](#column-constraints), it supports composite (multiple column) constraints. + + ``` swift + t.unique(local, domain) + // UNIQUE("local", "domain") + ``` + + - `check` adds a `CHECK` constraint to the table in the form of a boolean expression (`Expression`). Boolean expressions can be easily built using [filter operators and functions](#filter-operators-and-functions). (See also the `check` parameter under [Column Constraints](#column-constraints).) + + ``` swift + t.check(balance >= 0) + // CHECK ("balance" >= 0.0) + ``` + + - `foreignKey` adds a `FOREIGN KEY` constraint to the table. Unlike [the `references` constraint, above](#column-constraints), it supports all SQLite types, both [`ON UPDATE` and `ON DELETE` actions](https://www.sqlite.org/foreignkeys.html#fk_actions), and composite (multiple column) keys. + + ``` swift + t.foreignKey(user_id, references: users, id, delete: .setNull) + // FOREIGN KEY("user_id") REFERENCES "users"("id") ON DELETE SET NULL + ``` + + + + +## Inserting Rows + +We can insert rows into a table by calling a [query’s](#queries) `insert` function with a list of [setters](#setters)—typically [typed column expressions](#expressions) and values (which can also be expressions)—each joined by the `<-` operator. + +``` swift +try db.run(users.insert(email <- "alice@mac.com", name <- "Alice")) +// INSERT INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice') + +try db.run(users.insert(or: .replace, email <- "alice@mac.com", name <- "Alice B.")) +// INSERT OR REPLACE INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice B.') +``` + +The `insert` function, when run successfully, returns an `Int64` representing the inserted row’s [`ROWID`][ROWID]. + +``` swift +do { + let rowid = try db.run(users.insert(email <- "alice@mac.com")) + print("inserted id: \(rowid)") +} catch { + print("insertion failed: \(error)") +} +``` + +The [`update`](#updating-rows) and [`delete`](#deleting-rows) functions follow similar patterns. + +> _Note:_ If `insert` is called without any arguments, the statement will run with a `DEFAULT VALUES` clause. The table must not have any constraints that aren’t fulfilled by default values. +> +> ``` swift +> try db.run(timestamps.insert()) +> // INSERT INTO "timestamps" DEFAULT VALUES +> ``` + + +### Setters + +SQLite.swift typically uses the `<-` operator to set values during [inserts](#inserting-rows) and [updates](#updating-rows). + +``` swift +try db.run(counter.update(count <- 0)) +// UPDATE "counters" SET "count" = 0 WHERE ("id" = 1) +``` + +There are also a number of convenience setters that take the existing value into account using native Swift operators. + +For example, to atomically increment a column, we can use `++`: + +``` swift +try db.run(counter.update(count++)) // equivalent to `counter.update(count -> count + 1)` +// UPDATE "counters" SET "count" = "count" + 1 WHERE ("id" = 1) +``` + +To take an amount and “move” it via transaction, we can use `-=` and `+=`: + +``` swift +let amount = 100.0 +try db.transaction { + try db.run(alice.update(balance -= amount)) + try db.run(betty.update(balance += amount)) +} +// BEGIN DEFERRED TRANSACTION +// UPDATE "users" SET "balance" = "balance" - 100.0 WHERE ("id" = 1) +// UPDATE "users" SET "balance" = "balance" + 100.0 WHERE ("id" = 2) +// COMMIT TRANSACTION +``` + + +###### Infix Setters + +| Operator | Types | +| -------- | ------------------ | +| `<-` | `Value -> Value` | +| `+=` | `Number -> Number` | +| `-=` | `Number -> Number` | +| `*=` | `Number -> Number` | +| `/=` | `Number -> Number` | +| `%=` | `Int -> Int` | +| `<<=` | `Int -> Int` | +| `>>=` | `Int -> Int` | +| `&=` | `Int -> Int` | +| `||=` | `Int -> Int` | +| `^=` | `Int -> Int` | +| `+=` | `String -> String` | + + +###### Postfix Setters + +| Operator | Types | +| -------- | ------------ | +| `++` | `Int -> Int` | +| `--` | `Int -> Int` | + + +## Selecting Rows + +[Query structures](#queries) are `SELECT` statements waiting to happen. They execute via [iteration](#iterating-and-accessing-values) and [other means](#plucking-values) of sequence access. + + +### Iterating and Accessing Values + +Prepared [queries](#queries) execute lazily upon iteration. Each row is returned as a `Row` object, which can be subscripted with a [column expression](#expressions) matching one of the columns returned. + +``` swift +for user in try db.prepare(users) { + print("id: \(user[id]), email: \(user[email]), name: \(user[name])") + // id: 1, email: alice@mac.com, name: Optional("Alice") +} +// SELECT * FROM "users" +``` + +`Expression` column values are _automatically unwrapped_ (we’ve made a promise to the compiler that they’ll never be `NULL`), while `Expression` values remain wrapped. + + +### Plucking Rows + +We can pluck the first row by passing a query to the `pluck` function on a database connection. + +``` swift +if let user = try db.pluck(users) { /* ... */ } // Row +// SELECT * FROM "users" LIMIT 1 +``` + +To collect all rows into an array, we can simply wrap the sequence (though this is not always the most memory-efficient idea). + +``` swift +let all = Array(try db.prepare(users)) +// SELECT * FROM "users" +``` + + +### Building Complex Queries + +[Queries](#queries) have a number of chainable functions that can be used (with [expressions](#expressions)) to add and modify [a number of clauses](https://www.sqlite.org/lang_select.html) to the underlying statement. + +``` swift +let query = users.select(email) // SELECT "email" FROM "users" + .filter(name != nil) // WHERE "name" IS NOT NULL + .order(email.desc, name) // ORDER BY "email" DESC, "name" + .limit(5, offset: 1) // LIMIT 5 OFFSET 1 +``` + + +#### Selecting Columns + +By default, [queries](#queries) select every column of the result set (using `SELECT *`). We can use the `select` function with a list of [expressions](#expressions) to return specific columns instead. + +``` swift +for user in try db.prepare(users.select(id, email)) { + print("id: \(user[id]), email: \(user[email])") + // id: 1, email: alice@mac.com +} +// SELECT "id", "email" FROM "users" +``` + +We can access the results of more complex expressions by holding onto a reference of the expression itself. + +``` swift +let sentence = name + " is " + cast(age) as Expression + " years old!" +for user in users.select(sentence) { + print(user[sentence]) + // Optional("Alice is 30 years old!") +} +// SELECT ((("name" || ' is ') || CAST ("age" AS TEXT)) || ' years old!') FROM "users" +``` + + +#### Joining Other Tables + +We can join tables using a [query’s](#queries) `join` function. + +``` swift +users.join(posts, on: user_id == users[id]) +// SELECT * FROM "users" INNER JOIN "posts" ON ("user_id" = "users"."id") +``` + +The `join` function takes a [query](#queries) object (for the table being joined on), a join condition (`on`), and is prefixed with an optional join type (default: `.inner`). Join conditions can be built using [filter operators and functions](#filter-operators-and-functions), generally require [namespacing](#column-namespacing), and sometimes require [aliasing](#table-aliasing). + + +##### Column Namespacing + +When joining tables, column names can become ambiguous. _E.g._, both tables may have an `id` column. + +``` swift +let query = users.join(posts, on: user_id == id) +// assertion failure: ambiguous column 'id' +``` + +We can disambiguate by namespacing `id`. + +``` swift +let query = users.join(posts, on: user_id == users[id]) +// SELECT * FROM "users" INNER JOIN "posts" ON ("user_id" = "users"."id") +``` + +Namespacing is achieved by subscripting a [query](#queries) with a [column expression](#expressions) (_e.g._, `users[id]` above becomes `users.id`). + +> _Note:_ We can namespace all of a table’s columns using `*`. +> +> ``` swift +> let query = users.select(users[*]) +> // SELECT "users".* FROM "users" +> ``` + + +##### Table Aliasing + +Occasionally, we need to join a table to itself, in which case we must alias the table with another name. We can achieve this using the [query’s](#queries) `alias` function. + +``` swift +let managers = users.alias("managers") + +let query = users.join(managers, on: managers[id] == users[managerId]) +// SELECT * FROM "users" +// INNER JOIN ("users") AS "managers" ON ("managers"."id" = "users"."manager_id") +``` + +If query results can have ambiguous column names, row values should be accessed with namespaced [column expressions](#expressions). In the above case, `SELECT *` immediately namespaces all columns of the result set. + +``` swift +let user = try db.pluck(query) +user[id] // fatal error: ambiguous column 'id' + // (please disambiguate: ["users"."id", "managers"."id"]) + +user[users[id]] // returns "users"."id" +user[managers[id]] // returns "managers"."id" +``` + + +#### Filtering Rows + +SQLite.swift filters rows using a [query’s](#queries) `filter` function with a boolean [expression](#expressions) (`Expression`). + +``` swift +users.filter(id == 1) +// SELECT * FROM "users" WHERE ("id" = 1) + +users.filter([1, 2, 3, 4, 5].contains(id)) +// SELECT * FROM "users" WHERE ("id" IN (1, 2, 3, 4, 5)) + +users.filter(email.like("%@mac.com")) +// SELECT * FROM "users" WHERE ("email" LIKE '%@mac.com') + +users.filter(verified && name.lowercaseString == "alice") +// SELECT * FROM "users" WHERE ("verified" AND (lower("name") == 'alice')) + +users.filter(verified || balance >= 10_000) +// SELECT * FROM "users" WHERE ("verified" OR ("balance" >= 10000.0)) +``` + +We can build our own boolean expressions by using one of the many [filter operators and functions](#filter-operators-and-functions). + +Instead of `filter` we can also use the `where` function which is an alias: + +``` swift +users.where(id == 1) +// SELECT * FROM "users" WHERE ("id" = 1) +``` + +##### Filter Operators and Functions + +SQLite.swift defines a number of operators for building filtering predicates. Operators and functions work together in a type-safe manner, so attempting to equate or compare different types will prevent compilation. + + +###### Infix Filter Operators + +| Swift | Types | SQLite | +| ----- | -------------------------------- | -------------- | +| `==` | `Equatable -> Bool` | `=`/`IS`* | +| `!=` | `Equatable -> Bool` | `!=`/`IS NOT`* | +| `>` | `Comparable -> Bool` | `>` | +| `>=` | `Comparable -> Bool` | `>=` | +| `<` | `Comparable -> Bool` | `<` | +| `<=` | `Comparable -> Bool` | `<=` | +| `~=` | `(Interval, Comparable) -> Bool` | `BETWEEN` | +| `&&` | `Bool -> Bool` | `AND` | +| `||` | `Bool -> Bool` | `OR` | + +> *When comparing against `nil`, SQLite.swift will use `IS` and `IS NOT` accordingly. + + +###### Prefix Filter Operators + +| Swift | Types | SQLite | +| ----- | ------------------ | ------ | +| `!` | `Bool -> Bool` | `NOT` | + + +###### Filtering Functions + +| Swift | Types | SQLite | +| ---------- | ----------------------- | ------- | +| `like` | `String -> Bool` | `LIKE` | +| `glob` | `String -> Bool` | `GLOB` | +| `match` | `String -> Bool` | `MATCH` | +| `contains` | `(Array, T) -> Bool` | `IN` | + + + + + +#### Sorting Rows + +We can pre-sort returned rows using the [query’s](#queries) `order` function. + +_E.g._, to return users sorted by `email`, then `name`, in ascending order: + +``` swift +users.order(email, name) +// SELECT * FROM "users" ORDER BY "email", "name" +``` + +The `order` function takes a list of [column expressions](#expressions). + +`Expression` objects have two computed properties to assist sorting: `asc` and `desc`. These properties append the expression with `ASC` and `DESC` to mark ascending and descending order respectively. + +``` swift +users.order(email.desc, name.asc) +// SELECT * FROM "users" ORDER BY "email" DESC, "name" ASC +``` + + +#### Limiting and Paging Results + +We can limit and skip returned rows using a [query’s](#queries) `limit` function (and its optional `offset` parameter). + +``` swift +users.limit(5) +// SELECT * FROM "users" LIMIT 5 + +users.limit(5, offset: 5) +// SELECT * FROM "users" LIMIT 5 OFFSET 5 +``` + + +#### Aggregation + +[Queries](#queries) come with a number of functions that quickly return aggregate scalar values from the table. These mirror the [core aggregate functions](#aggregate-sqlite-functions) and are executed immediately against the query. + +``` swift +let count = try db.scalar(users.count) +// SELECT count(*) FROM "users" +``` + +Filtered queries will appropriately filter aggregate values. + +``` swift +let count = try db.scalar(users.filter(name != nil).count) +// SELECT count(*) FROM "users" WHERE "name" IS NOT NULL +``` + + - `count` as a computed property on a query (see examples above) returns the total number of rows matching the query. + + `count` as a computed property on a column expression returns the total number of rows where that column is not `NULL`. + + ``` swift + let count = try db.scalar(users.select(name.count)) // -> Int + // SELECT count("name") FROM "users" + ``` + + - `max` takes a comparable column expression and returns the largest value if any exists. + + ``` swift + let max = try db.scalar(users.select(id.max)) // -> Int64? + // SELECT max("id") FROM "users" + ``` + + - `min` takes a comparable column expression and returns the smallest value if any exists. + + ``` swift + let min = try db.scalar(users.select(id.min)) // -> Int64? + // SELECT min("id") FROM "users" + ``` + + - `average` takes a numeric column expression and returns the average row value (as a `Double`) if any exists. + + ``` swift + let average = try db.scalar(users.select(balance.average)) // -> Double? + // SELECT avg("balance") FROM "users" + ``` + + - `sum` takes a numeric column expression and returns the sum total of all rows if any exist. + + ``` swift + let sum = try db.scalar(users.select(balance.sum)) // -> Double? + // SELECT sum("balance") FROM "users" + ``` + + - `total`, like `sum`, takes a numeric column expression and returns the sum total of all rows, but in this case always returns a `Double`, and returns `0.0` for an empty query. + + ``` swift + let total = try db.scalar(users.select(balance.total)) // -> Double + // SELECT total("balance") FROM "users" + ``` + +> _Note:_ Expressions can be prefixed with a `DISTINCT` clause by calling the `distinct` computed property. +> +> ``` swift +> let count = try db.scalar(users.select(name.distinct.count) // -> Int +> // SELECT count(DISTINCT "name") FROM "users" +> ``` + + +## Updating Rows + +We can update a table’s rows by calling a [query’s](#queries) `update` function with a list of [setters](#setters)—typically [typed column expressions](#expressions) and values (which can also be expressions)—each joined by the `<-` operator. + +When an unscoped query calls `update`, it will update _every_ row in the table. + +``` swift +try db.run(users.update(email <- "alice@me.com")) +// UPDATE "users" SET "email" = 'alice@me.com' +``` + +Be sure to scope `UPDATE` statements beforehand using [the `filter` function](#filtering-rows). + +``` swift +let alice = users.filter(id == 1) +try db.run(alice.update(email <- "alice@me.com")) +// UPDATE "users" SET "email" = 'alice@me.com' WHERE ("id" = 1) +``` + +The `update` function returns an `Int` representing the number of updated rows. + +``` swift +do { + if try db.run(alice.update(email <- "alice@me.com")) > 0 { + print("updated alice") + } else { + print("alice not found") + } +} catch { + print("update failed: \(error)") +} +``` + + +## Deleting Rows + +We can delete rows from a table by calling a [query’s](#queries) `delete` function. + +When an unscoped query calls `delete`, it will delete _every_ row in the table. + +``` swift +try db.run(users.delete()) +// DELETE FROM "users" +``` + +Be sure to scope `DELETE` statements beforehand using [the `filter` function](#filtering-rows). + +``` swift +let alice = users.filter(id == 1) +try db.run(alice.delete()) +// DELETE FROM "users" WHERE ("id" = 1) +``` + +The `delete` function returns an `Int` representing the number of deleted rows. + +``` swift +do { + if try db.run(alice.delete()) > 0 { + print("deleted alice") + } else { + print("alice not found") + } +} catch { + print("delete failed: \(error)") +} +``` + + +## Transactions and Savepoints + +Using the `transaction` and `savepoint` functions, we can run a series of statements in a transaction. If a single statement fails or the block throws an error, the changes will be rolled back. + +``` swift +try db.transaction { + let rowid = try db.run(users.insert(email <- "betty@icloud.com")) + try db.run(users.insert(email <- "cathy@icloud.com", managerId <- rowid)) +} +// BEGIN DEFERRED TRANSACTION +// INSERT INTO "users" ("email") VALUES ('betty@icloud.com') +// INSERT INTO "users" ("email", "manager_id") VALUES ('cathy@icloud.com', 2) +// COMMIT TRANSACTION +``` + +> _Note:_ Transactions run in a serial queue. + + +## Altering the Schema + +SQLite.swift comes with several functions (in addition to `Table.create`) for altering a database schema in a type-safe manner. + + +### Renaming Tables + +We can build an `ALTER TABLE … RENAME TO` statement by calling the `rename` function on a `Table` or `VirtualTable`. + +``` swift +try db.run(users.rename(Table("users_old")) +// ALTER TABLE "users" RENAME TO "users_old" +``` + + +### Adding Columns + +We can add columns to a table by calling `addColumn` function on a `Table`. SQLite.swift enforces [the same limited subset](https://www.sqlite.org/lang_altertable.html) of `ALTER TABLE` that SQLite supports. + +``` swift +try db.run(users.addColumn(suffix)) +// ALTER TABLE "users" ADD COLUMN "suffix" TEXT +``` + + +#### Added Column Constraints + +The `addColumn` function shares several of the same [`column` function parameters](#column-constraints) used when [creating tables](#creating-a-table). + + - `check` attaches a `CHECK` constraint to a column definition in the form of a boolean expression (`Expression`). (See also the `check` function under [Table Constraints](#table-constraints).) + + ``` swift + try db.run(users.addColumn(suffix, check: ["JR", "SR"].contains(suffix))) + // ALTER TABLE "users" ADD COLUMN "suffix" TEXT CHECK ("suffix" IN ('JR', 'SR')) + ``` + + - `defaultValue` adds a `DEFAULT` clause to a column definition and _only_ accepts a value matching the column’s type. This value is used if none is explicitly provided during [an `INSERT`](#inserting-rows). + + ``` swift + try db.run(users.addColumn(suffix, defaultValue: "SR")) + // ALTER TABLE "users" ADD COLUMN "suffix" TEXT DEFAULT 'SR' + ``` + + > _Note:_ Unlike the [`CREATE TABLE` constraint](#table-constraints), default values may not be expression structures (including `CURRENT_TIME`, `CURRENT_DATE`, or `CURRENT_TIMESTAMP`). + + - `collate` adds a `COLLATE` clause to `Expression` (and `Expression`) column definitions with [a collating sequence](https://www.sqlite.org/datatype3.html#collation) defined in the `Collation` enumeration. + + ``` swift + try db.run(users.addColumn(email, collate: .nocase)) + // ALTER TABLE "users" ADD COLUMN "email" TEXT NOT NULL COLLATE "NOCASE" + + try db.run(users.addColumn(name, collate: .rtrim)) + // ALTER TABLE "users" ADD COLUMN "name" TEXT COLLATE "RTRIM" + ``` + + - `references` adds a `REFERENCES` clause to `Int64` (and `Int64?`) column definitions and accepts a table or namespaced column expression. (See the `foreignKey` function under [Table Constraints](#table-constraints) for non-integer foreign key support.) + + ``` swift + try db.run(posts.addColumn(userId, references: users, id) + // ALTER TABLE "posts" ADD COLUMN "user_id" INTEGER REFERENCES "users" ("id") + ``` + + +### Indexes + + +#### Creating Indexes + +We can build [`CREATE INDEX` statements](https://www.sqlite.org/lang_createindex.html) by calling the `createIndex` function on a `SchemaType`. + +``` swift +try db.run(users.createIndex(email)) +// CREATE INDEX "index_users_on_email" ON "users" ("email") +``` + +The index name is generated automatically based on the table and column names. + +The `createIndex` function has a couple default parameters we can override. + + - `unique` adds a `UNIQUE` constraint to the index. Default: `false`. + + ``` swift + try db.run(users.createIndex(email, unique: true)) + // CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email") + ``` + + - `ifNotExists` adds an `IF NOT EXISTS` clause to the `CREATE TABLE` statement (which will bail out gracefully if the table already exists). Default: `false`. + + ``` swift + try db.run(users.createIndex(email, ifNotExists: true)) + // CREATE INDEX IF NOT EXISTS "index_users_on_email" ON "users" ("email") + ``` + + +#### Dropping Indexes + +We can build [`DROP INDEX` statements](https://www.sqlite.org/lang_dropindex.html) by calling the `dropIndex` function on a `SchemaType`. + +``` swift +try db.run(users.dropIndex(email)) +// DROP INDEX "index_users_on_email" +``` + +The `dropIndex` function has one additional parameter, `ifExists`, which (when `true`) adds an `IF EXISTS` clause to the statement. + +``` swift +try db.run(users.dropIndex(email, ifExists: true)) +// DROP INDEX IF EXISTS "index_users_on_email" +``` + + +### Dropping Tables + +We can build [`DROP TABLE` statements](https://www.sqlite.org/lang_droptable.html) by calling the `dropTable` function on a `SchemaType`. + +``` swift +try db.run(users.drop()) +// DROP TABLE "users" +``` + +The `drop` function has one additional parameter, `ifExists`, which (when `true`) adds an `IF EXISTS` clause to the statement. + +``` swift +try db.run(users.drop(ifExists: true)) +// DROP TABLE IF EXISTS "users" +``` + + +### Migrations and Schema Versioning + +You can add a convenience property on `Connection` to query and set the [`PRAGMA user_version`](https://sqlite.org/pragma.html#pragma_user_version). + +This is a great way to manage your schema’s version over migrations. + +``` swift +extension Connection { + public var userVersion: Int32 { + get { return Int32(try! scalar("PRAGMA user_version") as! Int64)} + set { try! run("PRAGMA user_version = \(newValue)") } + } +} +``` + +Then you can conditionally run your migrations along the lines of: + +```swift +if db.userVersion == 0 { + // handle first migration + db.userVersion = 1 +} +if db.userVersion == 1 { + // handle second migration + db.userVersion = 2 +} +``` + +For more complex migration requirements check out the schema management system +[SQLiteMigrationManager.swift][]. + +## Custom Types + +SQLite.swift supports serializing and deserializing any custom type as long as it conforms to the `Value` protocol. + +> ``` swift +> protocol Value { +> typealias Datatype: Binding +> class var declaredDatatype: String { get } +> class func fromDatatypeValue(datatypeValue: Datatype) -> Self +> var datatypeValue: Datatype { get } +> } +> ``` + +The `Datatype` must be one of the basic Swift types that values are bridged through before serialization and deserialization (see [Building Type-Safe SQL](#building-type-safe-sql) for a list of types). + +> _Note:_ `Binding` is a protocol that SQLite.swift uses internally to directly map SQLite types to Swift types. **Do _not_** conform custom types to the `Binding` protocol. + +Once extended, the type can be used [_almost_](#custom-type-caveats) wherever typed expressions can be. + + +### Date-Time Values + +In SQLite, `DATETIME` columns can be treated as strings or numbers, so we can transparently bridge `Date` objects through Swift’s `String` or `Int` types. + +To serialize `Date` objects as `TEXT` values (in ISO 8601), we’ll use `String`. + +``` swift +extension Date: Value { + class var declaredDatatype: String { + return String.declaredDatatype + } + class func fromDatatypeValue(stringValue: String) -> Date { + return SQLDateFormatter.dateFromString(stringValue)! + } + var datatypeValue: String { + return SQLDateFormatter.stringFromDate(self) + } +} + +let SQLDateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS" + formatter.locale = Locale(localeIdentifier: "en_US_POSIX") + formatter.timeZone = TimeZone(forSecondsFromGMT: 0) + return formatter +}() +``` + +We can also treat them as `INTEGER` values using `Int`. + +``` swift +extension Date: Value { + class var declaredDatatype: String { + return Int.declaredDatatype + } + class func fromDatatypeValue(intValue: Int) -> Self { + return self(timeIntervalSince1970: TimeInterval(intValue)) + } + var datatypeValue: Int { + return Int(timeIntervalSince1970) + } +} +``` + +> _Note:_ SQLite’s `CURRENT_DATE`, `CURRENT_TIME`, and `CURRENT_TIMESTAMP` helpers return `TEXT` values. Because of this (and the fact that Unix time is far less human-readable when we’re faced with the raw data), we recommend using the `TEXT` extension. + +Once defined, we can use these types directly in SQLite statements. + +``` swift +let published_at = Expression("published_at") + +let published = posts.filter(published_at <= Date()) +// extension where Datatype == String: +// SELECT * FROM "posts" WHERE "published_at" <= '2014-11-18 12:45:30' +// extension where Datatype == Int: +// SELECT * FROM "posts" WHERE "published_at" <= 1416314730 +``` + + +### Binary Data + +We can bridge any type that can be initialized from and encoded to `Data`. + +``` swift +extension UIImage: Value { + public class var declaredDatatype: String { + return Blob.declaredDatatype + } + public class func fromDatatypeValue(blobValue: Blob) -> UIImage { + return UIImage(data: Data.fromDatatypeValue(blobValue))! + } + public var datatypeValue: Blob { + return UIImagePNGRepresentation(self)!.datatypeValue + } + +} +``` + +> _Note:_ See the [Archives and Serializations Programming Guide](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Archiving/Archiving.html#//apple_ref/doc/uid/10000047i) for more information on encoding and decoding custom types. + + +### Custom Type Caveats + +Swift does _not_ currently support generic subscripting, which means we cannot, by default, subscript Expressions with custom types to: + + 1. **Namespace expressions**. Use the `namespace` function, instead: + + ``` swift + let avatar = Expression("avatar") + users[avatar] // fails to compile + users.namespace(avatar) // "users"."avatar" + ``` + + 2. **Access column data**. Use the `get` function, instead: + + ``` swift + let user = users.first! + user[avatar] // fails to compile + user.get(avatar) // UIImage? + ``` + +We can, of course, write extensions, but they’re rather wordy. + +``` swift +extension Query { + subscript(column: Expression) -> Expression { + return namespace(column) + } + subscript(column: Expression) -> Expression { + return namespace(column) + } +} + +extension Row { + subscript(column: Expression) -> UIImage { + return get(column) + } + subscript(column: Expression) -> UIImage? { + return get(column) + } +} +``` + + +## Other Operators + +In addition to [filter operators](#filtering-infix-operators), SQLite.swift defines a number of operators that can modify expression values with arithmetic, bitwise operations, and concatenation. + + +###### Other Infix Operators + +| Swift | Types | SQLite | +| ----- | -------------------------------- | -------- | +| `+` | `Number -> Number` | `+` | +| `-` | `Number -> Number` | `-` | +| `*` | `Number -> Number` | `*` | +| `/` | `Number -> Number` | `/` | +| `%` | `Int -> Int` | `%` | +| `<<` | `Int -> Int` | `<<` | +| `>>` | `Int -> Int` | `>>` | +| `&` | `Int -> Int` | `&` | +| `|` | `Int -> Int` | `|` | +| `+` | `String -> String` | `||` | + +> _Note:_ SQLite.swift also defines a bitwise XOR operator, `^`, which expands the expression `lhs ^ rhs` to `~(lhs & rhs) & (lhs | rhs)`. + + +###### Other Prefix Operators + +| Swift | Types | SQLite | +| ----- | ------------------ | ------ | +| `~` | `Int -> Int` | `~` | +| `-` | `Number -> Number` | `-` | + + +## Core SQLite Functions + +Many of SQLite’s [core functions](https://www.sqlite.org/lang_corefunc.html) have been surfaced in and type-audited for SQLite.swift. + +> _Note:_ SQLite.swift aliases the `??` operator to the `ifnull` function. +> +> ``` swift +> name ?? email // ifnull("name", "email") +> ``` + + +## Aggregate SQLite Functions + +Most of SQLite’s [aggregate functions](https://www.sqlite.org/lang_aggfunc.html) have been surfaced in and type-audited for SQLite.swift. + + +## Custom SQL Functions + +We can create custom SQL functions by calling `createFunction` on a database connection. + +For example, to give queries access to [`MobileCoreServices.UTTypeConformsTo`](https://developer.apple.com/library/ios/documentation/MobileCoreServices/Reference/UTTypeRef/index.html#//apple_ref/c/func/UTTypeConformsTo), we can write the following: + +``` swift +import MobileCoreServices + +let typeConformsTo: (Expression, String) -> Expression = ( + try db.createFunction("typeConformsTo", deterministic: true) { UTI, conformsToUTI in + return UTTypeConformsTo(UTI, conformsToUTI) + } +) +``` + +> _Note:_ The optional `deterministic` parameter is an optimization that causes the function to be created with [`SQLITE_DETERMINISTIC`](https://www.sqlite.org/c3ref/create_function.html). + +Note `typeConformsTo`’s signature: + +``` swift +(Expression, String) -> Expression +``` + +Because of this, `createFunction` expects a block with the following signature: + +``` swift +(String, String) -> Bool +``` + +Once assigned, the closure can be called wherever boolean expressions are accepted. + +``` swift +let attachments = Table("attachments") +let UTI = Expression("UTI") + +let images = attachments.filter(typeConformsTo(UTI, kUTTypeImage)) +// SELECT * FROM "attachments" WHERE "typeConformsTo"("UTI", 'public.image') +``` + +> _Note:_ The return type of a function must be [a core SQL type](#building-type-safe-sql) or [conform to `Value`](#custom-types). + +We can create loosely-typed functions by handling an array of raw arguments, instead. + +``` swift +db.createFunction("typeConformsTo", deterministic: true) { args in + guard let UTI = args[0] as? String, conformsToUTI = args[1] as? String else { return nil } + return UTTypeConformsTo(UTI, conformsToUTI) +} +``` + +Creating a loosely-typed function cannot return a closure and instead must be wrapped manually or executed [using raw SQL](#executing-arbitrary-sql). + +``` swift +let stmt = try db.prepare("SELECT * FROM attachments WHERE typeConformsTo(UTI, ?)") +for row in stmt.bind(kUTTypeImage) { /* ... */ } +``` + + +## Custom Collations + +We can create custom collating sequences by calling `createCollation` on a database connection. + +``` swift +try db.createCollation("NODIACRITIC") { lhs, rhs in + return lhs.compare(rhs, options: .diacriticInsensitiveSearch) +} +``` + +We can reference a custom collation using the `Custom` member of the `Collation` enumeration. + +``` swift +restaurants.order(collate(.custom("NODIACRITIC"), name)) +// SELECT * FROM "restaurants" ORDER BY "name" COLLATE "NODIACRITIC" +``` + + +## Full-text Search + +We can create a virtual table using the [FTS4 module](http://www.sqlite.org/fts3.html) by calling `create` on a `VirtualTable`. + +``` swift +let emails = VirtualTable("emails") +let subject = Expression("subject") +let body = Expression("body") + +try db.run(emails.create(.FTS4(subject, body))) +// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body") +``` + +We can specify a [tokenizer](http://www.sqlite.org/fts3.html#tokenizer) using the `tokenize` parameter. + +``` swift +try db.run(emails.create(.FTS4([subject, body], tokenize: .Porter))) +// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body", tokenize=porter) +``` + +We can set the full range of parameters by creating a `FTS4Config` object. + +``` swift +let emails = VirtualTable("emails") +let subject = Expression("subject") +let body = Expression("body") +let config = FTS4Config() + .column(subject) + .column(body, [.unindexed]) + .languageId("lid") + .order(.desc) + +try db.run(emails.create(.FTS4(config)) +// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body", notindexed="body", languageid="lid", order="desc") +``` + +Once we insert a few rows, we can search using the `match` function, which takes a table or column as its first argument and a query string as its second. + +``` swift +try db.run(emails.insert( + subject <- "Just Checking In", + body <- "Hey, I was just wondering...did you get my last email?" +)) + +let wonderfulEmails = emails.match("wonder*") +// SELECT * FROM "emails" WHERE "emails" MATCH 'wonder*' + +let replies = emails.filter(subject.match("Re:*")) +// SELECT * FROM "emails" WHERE "subject" MATCH 'Re:*' +``` + +### FTS5 + +When linking against a version of SQLite with [FTS5](http://www.sqlite.org/fts5.html) enabled we can create the virtual table +in a similar fashion. + +```swift +let emails = VirtualTable("emails") +let subject = Expression("subject") +let body = Expression("body") +let config = FTS5Config() + .column(subject) + .column(body, [.unindexed]) + +try db.run(emails.create(.FTS5(config)) +// CREATE VIRTUAL TABLE "emails" USING fts5("subject", "body" UNINDEXED) + +// Note that FTS5 uses a different syntax to select columns, so we need to rewrite +// the last FTS4 query above as: +let replies = emails.filter(emails.match("subject:\"Re:\"*)) +// SELECT * FROM "emails" WHERE "emails" MATCH 'subject:"Re:"*' + +// https://www.sqlite.org/fts5.html#_changes_to_select_statements_ +``` + +## Executing Arbitrary SQL + +Though we recommend you stick with SQLite.swift’s [type-safe system](#building-type-safe-sql) whenever possible, it is possible to simply and safely prepare and execute raw SQL statements via a `Database` connection using the following functions. + + - `execute` runs an arbitrary number of SQL statements as a convenience. + + ``` swift + try db.execute( + "BEGIN TRANSACTION;" + + "CREATE TABLE users (" + + "id INTEGER PRIMARY KEY NOT NULL," + + "email TEXT UNIQUE NOT NULL," + + "name TEXT" + + ");" + + "CREATE TABLE posts (" + + "id INTEGER PRIMARY KEY NOT NULL," + + "title TEXT NOT NULL," + + "body TEXT NOT NULL," + + "published_at DATETIME" + + ");" + + "PRAGMA user_version = 1;" + + "COMMIT TRANSACTION;" + ) + ``` + + - `prepare` prepares a single `Statement` object from a SQL string, optionally binds values to it (using the statement’s `bind` function), and returns the statement for deferred execution. + + ``` swift + let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)") + ``` + + Once prepared, statements may be executed using `run`, binding any unbound parameters. + + ``` swift + try stmt.run("alice@mac.com") + db.changes // -> {Some 1} + ``` + + Statements with results may be iterated over, using the columnNames if useful. + + ``` swift + let stmt = try db.prepare("SELECT id, email FROM users") + for row in stmt { + for (index, name) in stmt.columnNames.enumerate() { + print ("\(name)=\(row[index]!)") + // id: Optional(1), email: Optional("alice@mac.com") + } + } + ``` + + - `run` prepares a single `Statement` object from a SQL string, optionally binds values to it (using the statement’s `bind` function), executes, and returns the statement. + + ``` swift + try db.run("INSERT INTO users (email) VALUES (?)", "alice@mac.com") + ``` + + - `scalar` prepares a single `Statement` object from a SQL string, optionally binds values to it (using the statement’s `bind` function), executes, and returns the first value of the first row. + + ``` swift + let count = try db.scalar("SELECT count(*) FROM users") as! Int64 + ``` + + Statements also have a `scalar` function, which can optionally re-bind values at execution. + + ``` swift + let stmt = try db.prepare("SELECT count (*) FROM users") + let count = try stmt.scalar() as! Int64 + ``` + + +## Logging + +We can log SQL using the database’s `trace` function. + +``` swift +#if DEBUG + db.trace(print) +#endif +``` + + +[ROWID]: https://sqlite.org/lang_createtable.html#rowid +[SQLiteMigrationManager.swift]: https://github.com/garriguv/SQLiteMigrationManager.swift diff --git a/mobile/ios/ThirdParty/SQLite.swift/Documentation/Planning.md b/mobile/ios/ThirdParty/SQLite.swift/Documentation/Planning.md new file mode 100644 index 0000000000..d814d26b06 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Documentation/Planning.md @@ -0,0 +1,24 @@ +# SQLite.swift Planning + +This document captures both near term steps (aka Roadmap) and feature requests. +The goal is to add some visibility and guidance for future additions and Pull Requests, as well as to keep the Issues list clear of enhancement requests so that bugs are more visible. + +## Roadmap + +_Lists agreed upon next steps in approximate priority order._ + +## Feature Requests + +_A gathering point for ideas for new features. In general, the corresponding issue will be closed once it is added here, with the assumption that it will be referred to when it comes time to add the corresponding feature._ + +### Features + + * encapsulate ATTACH DATABASE / DETACH DATABASE as methods, per [#30](https://github.com/stephencelis/SQLite.swift/issues/30) + * provide separate threads for update vs read, so updates don't block reads, per [#236](https://github.com/stephencelis/SQLite.swift/issues/236) + * expose triggers, per [#164](https://github.com/stephencelis/SQLite.swift/issues/164) + +## Suspended Feature Requests + +_Features that are not actively being considered, perhaps because of no clean type-safe way to implement them with the current Swift, or bugs, or just general uncertainty._ + + * provide a mechanism for INSERT INTO multiple values, per [#168](https://github.com/stephencelis/SQLite.swift/issues/168) diff --git a/mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/installation@2x.png b/mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/installation@2x.png new file mode 100644 index 0000000000..6b31f45934 Binary files /dev/null and b/mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/installation@2x.png differ diff --git a/mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/playground@2x.png b/mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/playground@2x.png new file mode 100644 index 0000000000..32646d6aa4 Binary files /dev/null and b/mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/playground@2x.png differ diff --git a/mobile/ios/ThirdParty/SQLite.swift/LICENSE.txt b/mobile/ios/ThirdParty/SQLite.swift/LICENSE.txt new file mode 100644 index 0000000000..13303c1135 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/LICENSE.txt @@ -0,0 +1,21 @@ +(The MIT License) + +Copyright (c) 2014-2015 Stephen Celis () + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mobile/ios/ThirdParty/SQLite.swift/Makefile b/mobile/ios/ThirdParty/SQLite.swift/Makefile new file mode 100644 index 0000000000..d4f51d53e3 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Makefile @@ -0,0 +1,60 @@ +BUILD_TOOL = xcodebuild +BUILD_SCHEME = SQLite Mac +IOS_SIMULATOR = iPhone 6s +IOS_VERSION = 9.3 +ifeq ($(BUILD_SCHEME),SQLite iOS) + BUILD_ARGUMENTS = -scheme "$(BUILD_SCHEME)" -destination "platform=iOS Simulator,name=$(IOS_SIMULATOR),OS=$(IOS_VERSION)" +else + BUILD_ARGUMENTS = -scheme "$(BUILD_SCHEME)" +endif + +XCPRETTY := $(shell command -v xcpretty) +SWIFTCOV := $(shell command -v swiftcov) +GCOVR := $(shell command -v gcovr) +TEST_ACTIONS := clean build build-for-testing test-without-building + +default: test + +build: + $(BUILD_TOOL) $(BUILD_ARGUMENTS) + +test: +ifdef XCPRETTY + @set -o pipefail && $(BUILD_TOOL) $(BUILD_ARGUMENTS) $(TEST_ACTIONS) | $(XCPRETTY) -c +else + $(BUILD_TOOL) $(BUILD_ARGUMENTS) $(TEST_ACTIONS) +endif + +coverage: +ifdef SWIFTCOV + $(SWIFTCOV) generate --output coverage \ + $(BUILD_TOOL) $(BUILD_ARGUMENTS) -configuration Release test \ + -- ./SQLite/*.swift +ifdef GCOVR + $(GCOVR) \ + --root . \ + --use-gcov-files \ + --html \ + --html-details \ + --output coverage/index.html \ + --keep +else + @echo gcovr must be installed for HTML output: https://github.com/gcovr/gcovr +endif +else + @echo swiftcov must be installed for coverage: https://github.com/realm/SwiftCov + @exit 1 +endif + +clean: + $(BUILD_TOOL) $(BUILD_ARGUMENTS) clean + rm -r coverage + +repl: + @$(BUILD_TOOL) $(BUILD_ARGUMENTS) -derivedDataPath $(TMPDIR)/SQLite.swift > /dev/null && \ + swift -F '$(TMPDIR)/SQLite.swift/Build/Products/Debug' + +sloc: + @zsh -c "grep -vE '^ *//|^$$' SQLite/*/*.{swift,h,m} | wc -l" + +.PHONY: test coverage clean repl sloc diff --git a/mobile/ios/ThirdParty/SQLite.swift/Package.swift b/mobile/ios/ThirdParty/SQLite.swift/Package.swift new file mode 100644 index 0000000000..fc7c5a0ed9 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Package.swift @@ -0,0 +1,17 @@ +import PackageDescription + +let package = Package( + name: "SQLite", + targets: [ + Target( + name: "SQLite", + dependencies: [ + .Target(name: "SQLiteObjc") + ]), + Target(name: "SQLiteObjc") + ], + dependencies: [ + .Package(url: "https://github.com/stephencelis/CSQLite.git", majorVersion: 0) + ], + exclude: ["Tests/CocoaPods", "Tests/Carthage"] +) diff --git a/mobile/ios/ThirdParty/SQLite.swift/README.md b/mobile/ios/ThirdParty/SQLite.swift/README.md new file mode 100644 index 0000000000..89917b36b3 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/README.md @@ -0,0 +1,263 @@ +# SQLite.swift + +[![Build Status][Badge]][Travis] [![CocoaPods Version](https://cocoapod-badges.herokuapp.com/v/SQLite.swift/badge.png)](http://cocoadocs.org/docsets/SQLite.swift) [![Swift](https://img.shields.io/badge/swift-3-orange.svg?style=flat)](https://developer.apple.com/swift/) [![Platform](https://cocoapod-badges.herokuapp.com/p/SQLite.swift/badge.png)](http://cocoadocs.org/docsets/SQLite.swift) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Join the chat at https://gitter.im/stephencelis/SQLite.swift](https://badges.gitter.im/stephencelis/SQLite.swift.svg)](https://gitter.im/stephencelis/SQLite.swift) + +A type-safe, [Swift][]-language layer over [SQLite3][]. + +[SQLite.swift][] provides compile-time confidence in SQL statement +syntax _and_ intent. + +[Badge]: https://img.shields.io/travis/stephencelis/SQLite.swift/master.svg?style=flat +[Travis]: https://travis-ci.org/stephencelis/SQLite.swift +[Swift]: https://developer.apple.com/swift/ +[SQLite3]: http://www.sqlite.org +[SQLite.swift]: https://github.com/stephencelis/SQLite.swift + + +## Features + + - A pure-Swift interface + - A type-safe, optional-aware SQL expression builder + - A flexible, chainable, lazy-executing query layer + - Automatically-typed data access + - A lightweight, uncomplicated query and parameter binding interface + - Developer-friendly error handling and debugging + - [Full-text search][] support + - [Well-documented][See Documentation] + - Extensively tested + - SQLCipher support via CocoaPods + - Active support at [StackOverflow](http://stackoverflow.com/questions/tagged/sqlite.swift), and [Gitter Chat Room](https://gitter.im/stephencelis/SQLite.swift) (_experimental_) + +[Full-text search]: Documentation/Index.md#full-text-search +[See Documentation]: Documentation/Index.md#sqliteswift-documentation + + +## Usage + +``` swift +import SQLite + +let db = try Connection("path/to/db.sqlite3") + +let users = Table("users") +let id = Expression("id") +let name = Expression("name") +let email = Expression("email") + +try db.run(users.create { t in + t.column(id, primaryKey: true) + t.column(name) + t.column(email, unique: true) +}) +// CREATE TABLE "users" ( +// "id" INTEGER PRIMARY KEY NOT NULL, +// "name" TEXT, +// "email" TEXT NOT NULL UNIQUE +// ) + +let insert = users.insert(name <- "Alice", email <- "alice@mac.com") +let rowid = try db.run(insert) +// INSERT INTO "users" ("name", "email") VALUES ('Alice', 'alice@mac.com') + +for user in try db.prepare(users) { + print("id: \(user[id]), name: \(user[name]), email: \(user[email])") + // id: 1, name: Optional("Alice"), email: alice@mac.com +} +// SELECT * FROM "users" + +let alice = users.filter(id == rowid) + +try db.run(alice.update(email <- email.replace("mac.com", with: "me.com"))) +// UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com') +// WHERE ("id" = 1) + +try db.run(alice.delete()) +// DELETE FROM "users" WHERE ("id" = 1) + +db.scalar(users.count) // 0 +// SELECT count(*) FROM "users" +``` + +SQLite.swift also works as a lightweight, Swift-friendly wrapper over the C +API. + +``` swift +let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)") +for email in ["betty@icloud.com", "cathy@icloud.com"] { + try stmt.run(email) +} + +db.totalChanges // 3 +db.changes // 1 +db.lastInsertRowid // 3 + +for row in try db.prepare("SELECT id, email FROM users") { + print("id: \(row[0]), email: \(row[1])") + // id: Optional(2), email: Optional("betty@icloud.com") + // id: Optional(3), email: Optional("cathy@icloud.com") +} + +db.scalar("SELECT count(*) FROM users") // 2 +``` + +[Read the documentation][See Documentation] or explore more, +interactively, from the Xcode project’s playground. + +![SQLite.playground Screen Shot](Documentation/Resources/playground@2x.png) + +For a more comprehensive example, see [this article](http://masteringswift.blogspot.com/2015/09/create-data-access-layer-with.html) and the [companion repository](https://github.com/hoffmanjon/SQLiteDataAccessLayer2/tree/master). + +## Installation + +> _Note:_ SQLite.swift requires Swift 3 (and [Xcode][] 8) or greater. If you absolutely +> need compatibility with Swift 2.3 you can use the [swift-2.3][] branch or older +> released versions. New development will happen exclusively on the master/Swift 3 branch. + +### Carthage + +[Carthage][] is a simple, decentralized dependency manager for Cocoa. To +install SQLite.swift with Carthage: + + 1. Make sure Carthage is [installed][Carthage Installation]. + + 2. Update your Cartfile to include the following: + + ``` + github "stephencelis/SQLite.swift" ~> 0.11.2 + ``` + + 3. Run `carthage update` and [add the appropriate framework][Carthage Usage]. + + +[Carthage]: https://github.com/Carthage/Carthage +[Carthage Installation]: https://github.com/Carthage/Carthage#installing-carthage +[Carthage Usage]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application + + +### CocoaPods + +[CocoaPods][] is a dependency manager for Cocoa projects. To install +SQLite.swift with CocoaPods: + + 1. Verify that your copy of Xcode is installed and active in the default location (`/Applications/Xcode.app`). + + ```sh + sudo xcode-select --switch /Applications/Xcode.app + ``` + + 2. Make sure CocoaPods is [installed][CocoaPods Installation]. (SQLite.swift requires version 1.0.0 or greater.) + + ``` sh + # Using the default Ruby install will require you to use sudo when + # installing and updating gems. + [sudo] gem install cocoapods + ``` + + 3. Update your Podfile to include the following: + + ``` ruby + use_frameworks! + + target 'YourAppTargetName' do + pod 'SQLite.swift', '~> 0.11.2' + end + ``` + + 4. Run `pod install --repo-update`. + +[CocoaPods]: https://cocoapods.org +[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started + +### Swift Package Manager + +The [Swift Package Manager][] is a tool for managing the distribution of Swift code. + +1. Add the following to your `Package.swift` file: + +```swift +dependencies: [ + .Package(url: "https://github.com/stephencelis/SQLite.swift.git", majorVersion: 0, minor: 11) +] +``` + +[Swift Package Manager]: https://swift.org/package-manager + +### Manual + +To install SQLite.swift as an Xcode sub-project: + + 1. Drag the **SQLite.xcodeproj** file into your own project. + ([Submodule][], clone, or [download][] the project first.) + + ![Installation Screen Shot](Documentation/Resources/installation@2x.png) + + 2. In your target’s **General** tab, click the **+** button under **Linked + Frameworks and Libraries**. + + 3. Select the appropriate **SQLite.framework** for your platform. + + 4. **Add**. + +Some additional steps are required to install the application on an actual device: + + 5. In the **General** tab, click the **+** button under **Embedded Binaries**. + + 6. Select the appropriate **SQLite.framework** for your platform. + + 7. **Add**. + + +[Xcode]: https://developer.apple.com/xcode/downloads/ +[Submodule]: http://git-scm.com/book/en/Git-Tools-Submodules +[download]: https://github.com/stephencelis/SQLite.swift/archive/master.zip + + +## Communication + +[See the planning document] for a roadmap and existing feature requests. + +[Read the contributing guidelines][]. The _TL;DR_ (but please; _R_): + + - Need **help** or have a **general question**? [Ask on Stack + Overflow][] (tag `sqlite.swift`). + - Found a **bug** or have a **feature request**? [Open an issue][]. + - Want to **contribute**? [Submit a pull request][]. + +[See the planning document]: /Documentation/Planning.md +[Read the contributing guidelines]: ./CONTRIBUTING.md#contributing +[Ask on Stack Overflow]: http://stackoverflow.com/questions/tagged/sqlite.swift +[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new +[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork + + +## Author + + - [Stephen Celis](mailto:stephen@stephencelis.com) + ([@stephencelis](https://twitter.com/stephencelis)) + + +## License + +SQLite.swift is available under the MIT license. See [the LICENSE +file](./LICENSE.txt) for more information. + +## Related + +These projects enhance or use SQLite.swift: + + - [SQLiteMigrationManager.swift](https://github.com/garriguv/SQLiteMigrationManager.swift) (inspired by [FMDBMigrationManager](https://github.com/layerhq/FMDBMigrationManager)) + + +## Alternatives + +Looking for something else? Try another Swift wrapper (or [FMDB][]): + + - [Camembert](https://github.com/remirobert/Camembert) + - [GRDB](https://github.com/groue/GRDB.swift) + - [SQLiteDB](https://github.com/FahimF/SQLiteDB) + - [Squeal](https://github.com/nerdyc/Squeal) + - [SwiftData](https://github.com/ryanfowler/SwiftData) + - [SwiftSQLite](https://github.com/chrismsimpson/SwiftSQLite) + +[FMDB]: https://github.com/ccgus/fmdb +[swift-2.3]: https://github.com/stephencelis/SQLite.swift/tree/swift-2.3 diff --git a/mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/Contents.swift b/mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/Contents.swift new file mode 100644 index 0000000000..11e13139f7 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/Contents.swift @@ -0,0 +1,43 @@ +import SQLite + +let db = try! Connection() + +db.trace { print($0) } + +let users = Table("users") + +let id = Expression("id") +let email = Expression("email") +let name = Expression("name") + +try! db.run(users.create { t in + t.column(id, primaryKey: true) + t.column(email, unique: true, check: email.like("%@%")) + t.column(name) +}) + +let rowid = try! db.run(users.insert(email <- "alice@mac.com")) +let alice = users.filter(id == rowid) + +for user in try! db.prepare(users) { + print("id: \(user[id]), email: \(user[email])") +} + +let emails = VirtualTable("emails") + +let subject = Expression("subject") +let body = Expression("body") + +try! db.run(emails.create(.FTS4(subject, body))) + +try! db.run(emails.insert( + subject <- "Hello, world!", + body <- "This is a hello world message." +)) + +let row = try! db.pluck(emails.match("hello")) + +let query = try! db.prepare(emails.match("hello")) +for row in query { + print(row[subject]) +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/contents.xcplayground b/mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/contents.xcplayground new file mode 100644 index 0000000000..fd676d5b46 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/mobile/ios/ThirdParty/SQLite.swift/SQLite.swift.podspec b/mobile/ios/ThirdParty/SQLite.swift/SQLite.swift.podspec new file mode 100644 index 0000000000..3c61aa1fe6 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/SQLite.swift.podspec @@ -0,0 +1,70 @@ +Pod::Spec.new do |s| + s.name = "SQLite.swift" + s.version = "0.11.2" + s.summary = "A type-safe, Swift-language layer over SQLite3 for iOS and OS X." + + s.description = <<-DESC + SQLite.swift provides compile-time confidence in SQL statement syntax and + intent. + DESC + + s.homepage = "https://github.com/stephencelis/SQLite.swift" + s.license = 'MIT' + s.author = { "Stephen Celis" => "stephen@stephencelis.com" } + s.source = { :git => "https://github.com/stephencelis/SQLite.swift.git", :tag => s.version.to_s } + s.social_media_url = 'https://twitter.com/stephencelis' + + s.module_name = 'SQLite' + s.ios.deployment_target = "8.0" + s.tvos.deployment_target = "9.0" + s.osx.deployment_target = "10.9" + s.watchos.deployment_target = "2.0" + s.default_subspec = 'standard' + s.pod_target_xcconfig = { + 'SWIFT_VERSION' => '3.0', + } + + s.subspec 'standard' do |ss| + ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}' + ss.exclude_files = 'Sources/**/Cipher.swift' + ss.private_header_files = 'Sources/SQLiteObjc/*.h' + + ss.library = 'sqlite3' + ss.preserve_paths = 'CocoaPods/**/*' + ss.pod_target_xcconfig = { + 'SWIFT_INCLUDE_PATHS[sdk=macosx*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/macosx', + 'SWIFT_INCLUDE_PATHS[sdk=macosx10.11]' => '$(SRCROOT)/SQLite.swift/CocoaPods/macosx-10.11', + 'SWIFT_INCLUDE_PATHS[sdk=macosx10.12]' => '$(SRCROOT)/SQLite.swift/CocoaPods/macosx-10.12', + 'SWIFT_INCLUDE_PATHS[sdk=iphoneos*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/iphoneos', + 'SWIFT_INCLUDE_PATHS[sdk=iphoneos10.0]' => '$(SRCROOT)/SQLite.swift/CocoaPods/iphoneos-10.0', + 'SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/iphonesimulator', + 'SWIFT_INCLUDE_PATHS[sdk=iphonesimulator10.0]' => '$(SRCROOT)/SQLite.swift/CocoaPods/iphonesimulator-10.0', + 'SWIFT_INCLUDE_PATHS[sdk=appletvos*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/appletvos', + 'SWIFT_INCLUDE_PATHS[sdk=appletvsimulator*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/appletvsimulator', + 'SWIFT_INCLUDE_PATHS[sdk=watchos*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/watchos', + 'SWIFT_INCLUDE_PATHS[sdk=watchsimulator*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/watchsimulator' + } + end + + s.subspec 'standalone' do |ss| + ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}' + ss.exclude_files = 'Sources/**/Cipher.swift' + ss.private_header_files = 'Sources/SQLiteObjc/*.h' + ss.xcconfig = { + 'OTHER_SWIFT_FLAGS' => '$(inherited) -DSQLITE_SWIFT_STANDALONE' + } + + ss.dependency 'sqlite3', '>= 3.14.0' + end + + s.subspec 'SQLCipher' do |ss| + ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}' + ss.private_header_files = 'Sources/SQLiteObjc/*.h' + ss.xcconfig = { + 'OTHER_SWIFT_FLAGS' => '$(inherited) -DSQLITE_SWIFT_SQLCIPHER', + 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SQLITE_HAS_CODEC=1' + } + + ss.dependency 'SQLCipher', '>= 3.4.0' + end +end diff --git a/mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.pbxproj b/mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..bd6421b88a --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.pbxproj @@ -0,0 +1,1513 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 03A65E641C6BB0F60062603F /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A65E5A1C6BB0F50062603F /* SQLite.framework */; }; + 03A65E711C6BB2CD0062603F /* usr/include/sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808B1C46E34A0038162A /* usr/include/sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 03A65E721C6BB2D30062603F /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 03A65E731C6BB2D80062603F /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; }; + 03A65E741C6BB2DA0062603F /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; }; + 03A65E751C6BB2DF0062603F /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808D1C46E5230038162A /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 03A65E761C6BB2E60062603F /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; + 03A65E771C6BB2E60062603F /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; }; + 03A65E781C6BB2EA0062603F /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */; }; + 03A65E791C6BB2EF0062603F /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */; }; + 03A65E7A1C6BB2F70062603F /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; }; + 03A65E7B1C6BB2F70062603F /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; }; + 03A65E7C1C6BB2F70062603F /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; }; + 03A65E7D1C6BB2F70062603F /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; }; + 03A65E7E1C6BB2FB0062603F /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; }; + 03A65E7F1C6BB2FB0062603F /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; }; + 03A65E801C6BB2FB0062603F /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; }; + 03A65E811C6BB2FB0062603F /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; }; + 03A65E821C6BB2FB0062603F /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; }; + 03A65E831C6BB2FB0062603F /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; }; + 03A65E841C6BB2FB0062603F /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; }; + 03A65E851C6BB2FB0062603F /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; }; + 03A65E861C6BB2FB0062603F /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; }; + 03A65E871C6BB3030062603F /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */; }; + 03A65E881C6BB3030062603F /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1B1C3F137700AE3E12 /* BlobTests.swift */; }; + 03A65E891C6BB3030062603F /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */; }; + 03A65E8A1C6BB3030062603F /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */; }; + 03A65E8B1C6BB3030062603F /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */; }; + 03A65E8C1C6BB3030062603F /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B201C3F137700AE3E12 /* ExpressionTests.swift */; }; + 03A65E8D1C6BB3030062603F /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B211C3F137700AE3E12 /* FTS4Tests.swift */; }; + 03A65E8E1C6BB3030062603F /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */; }; + 03A65E8F1C6BB3030062603F /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */; }; + 03A65E901C6BB3030062603F /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */; }; + 03A65E911C6BB3030062603F /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */; }; + 03A65E921C6BB3030062603F /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B181C3F134A00AE3E12 /* SetterTests.swift */; }; + 03A65E931C6BB3030062603F /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B321C3F142E00AE3E12 /* StatementTests.swift */; }; + 03A65E941C6BB3030062603F /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B331C3F142E00AE3E12 /* ValueTests.swift */; }; + 03A65E951C6BB3030062603F /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; }; + 03A65E971C6BB3210062603F /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A65E961C6BB3210062603F /* libsqlite3.tbd */; }; + 19A1709C3E7A406E62293B2A /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; }; + 19A1717B10CC941ACB5533D6 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; }; + 19A171E6FA242F72A308C594 /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1721B8984686B9963B45D /* FTS5Tests.swift */; }; + 19A171F12AB8B07F2FD7201A /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; }; + 19A17254FBA7894891F7297B /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1721B8984686B9963B45D /* FTS5Tests.swift */; }; + 19A17408007B182F884E3A53 /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; }; + 19A174D78559CD30679BCCCB /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1721B8984686B9963B45D /* FTS5Tests.swift */; }; + 19A1750CEE9B05267995CF3D /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; }; + 19A175DFF47B84757E547C62 /* fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 19A17E2695737FAB5D6086E3 /* fixtures */; }; + 19A177CC33F2E6A24AF90B02 /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17399EA9E61235D5D77BF /* CipherTests.swift */; }; + 19A178072B371489E6A1E839 /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; }; + 19A17835FD5886FDC5A3228F /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; }; + 19A179A0C45377CB09BB358C /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17399EA9E61235D5D77BF /* CipherTests.swift */; }; + 19A179CCF9671E345E5A9811 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; }; + 19A179E76EA6207669B60C1B /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; }; + 19A17C4B951CB054EE48AB1C /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17399EA9E61235D5D77BF /* CipherTests.swift */; }; + 19A17E04C4C0956715C5676A /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; }; + 19A17EC0D68BA8C03288ADF7 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; }; + 19A17F3E1F7ACA33BD43E138 /* fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 19A17E2695737FAB5D6086E3 /* fixtures */; }; + 19A17F60B685636D1F83C2DD /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; }; + 19A17FB80B94E882050AA908 /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; }; + 19A17FDA323BAFDEC627E76F /* fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 19A17E2695737FAB5D6086E3 /* fixtures */; }; + 3D67B3E61DB2469200A4F4C6 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */; }; + 3D67B3E71DB246BA00A4F4C6 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; + 3D67B3E81DB246BA00A4F4C6 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; }; + 3D67B3E91DB246D100A4F4C6 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; }; + 3D67B3EA1DB246D100A4F4C6 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; }; + 3D67B3EB1DB246D100A4F4C6 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; }; + 3D67B3EC1DB246D100A4F4C6 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; }; + 3D67B3ED1DB246D100A4F4C6 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; }; + 3D67B3EE1DB246D100A4F4C6 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; }; + 3D67B3EF1DB246D100A4F4C6 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; }; + 3D67B3F01DB246D100A4F4C6 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; }; + 3D67B3F11DB246D100A4F4C6 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; }; + 3D67B3F21DB246D100A4F4C6 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; }; + 3D67B3F31DB246D100A4F4C6 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; }; + 3D67B3F41DB246D100A4F4C6 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; }; + 3D67B3F51DB246D100A4F4C6 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; }; + 3D67B3F61DB246D100A4F4C6 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; }; + 3D67B3F71DB246D700A4F4C6 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; }; + 3D67B3F81DB246D700A4F4C6 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; }; + 3D67B3F91DB246E700A4F4C6 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */; }; + 3D67B3FA1DB2470600A4F4C6 /* usr/include/sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808B1C46E34A0038162A /* usr/include/sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D67B3FB1DB2470600A4F4C6 /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808D1C46E5230038162A /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D67B3FC1DB2471B00A4F4C6 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D67B3FD1DB2472D00A4F4C6 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */; }; + EE247AD71C3F04ED00AE3E12 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE247ADE1C3F04ED00AE3E12 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE247AD31C3F04ED00AE3E12 /* SQLite.framework */; }; + EE247B031C3F06E900AE3E12 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; + EE247B041C3F06E900AE3E12 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; }; + EE247B051C3F06E900AE3E12 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */; }; + EE247B061C3F06E900AE3E12 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */; }; + EE247B071C3F06E900AE3E12 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; }; + EE247B081C3F06E900AE3E12 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; }; + EE247B091C3F06E900AE3E12 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; }; + EE247B0A1C3F06E900AE3E12 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; }; + EE247B0B1C3F06E900AE3E12 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; }; + EE247B0C1C3F06E900AE3E12 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; }; + EE247B0D1C3F06E900AE3E12 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; }; + EE247B0E1C3F06E900AE3E12 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; }; + EE247B0F1C3F06E900AE3E12 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; }; + EE247B101C3F06E900AE3E12 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; }; + EE247B111C3F06E900AE3E12 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; }; + EE247B121C3F06E900AE3E12 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; }; + EE247B131C3F06E900AE3E12 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; }; + EE247B141C3F06E900AE3E12 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; }; + EE247B151C3F06E900AE3E12 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; }; + EE247B171C3F127200AE3E12 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; }; + EE247B191C3F134A00AE3E12 /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B181C3F134A00AE3E12 /* SetterTests.swift */; }; + EE247B221C3F137700AE3E12 /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */; }; + EE247B231C3F137700AE3E12 /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1B1C3F137700AE3E12 /* BlobTests.swift */; }; + EE247B251C3F137700AE3E12 /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */; }; + EE247B261C3F137700AE3E12 /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */; }; + EE247B271C3F137700AE3E12 /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */; }; + EE247B281C3F137700AE3E12 /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B201C3F137700AE3E12 /* ExpressionTests.swift */; }; + EE247B291C3F137700AE3E12 /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B211C3F137700AE3E12 /* FTS4Tests.swift */; }; + EE247B2E1C3F141E00AE3E12 /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */; }; + EE247B2F1C3F141E00AE3E12 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */; }; + EE247B301C3F141E00AE3E12 /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */; }; + EE247B311C3F141E00AE3E12 /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */; }; + EE247B341C3F142E00AE3E12 /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B321C3F142E00AE3E12 /* StatementTests.swift */; }; + EE247B351C3F142E00AE3E12 /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B331C3F142E00AE3E12 /* ValueTests.swift */; }; + EE247B461C3F3ED000AE3E12 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */; }; + EE247B531C3F3FC700AE3E12 /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */; }; + EE247B541C3F3FC700AE3E12 /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1B1C3F137700AE3E12 /* BlobTests.swift */; }; + EE247B551C3F3FC700AE3E12 /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */; }; + EE247B561C3F3FC700AE3E12 /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */; }; + EE247B571C3F3FC700AE3E12 /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */; }; + EE247B581C3F3FC700AE3E12 /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B201C3F137700AE3E12 /* ExpressionTests.swift */; }; + EE247B591C3F3FC700AE3E12 /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B211C3F137700AE3E12 /* FTS4Tests.swift */; }; + EE247B5A1C3F3FC700AE3E12 /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */; }; + EE247B5B1C3F3FC700AE3E12 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */; }; + EE247B5C1C3F3FC700AE3E12 /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */; }; + EE247B5D1C3F3FC700AE3E12 /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */; }; + EE247B5E1C3F3FC700AE3E12 /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B181C3F134A00AE3E12 /* SetterTests.swift */; }; + EE247B5F1C3F3FC700AE3E12 /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B321C3F142E00AE3E12 /* StatementTests.swift */; }; + EE247B601C3F3FC700AE3E12 /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B331C3F142E00AE3E12 /* ValueTests.swift */; }; + EE247B611C3F3FC700AE3E12 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; }; + EE247B621C3F3FDB00AE3E12 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE247B631C3F3FDB00AE3E12 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; }; + EE247B641C3F3FDB00AE3E12 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; }; + EE247B651C3F3FEC00AE3E12 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; + EE247B661C3F3FEC00AE3E12 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; }; + EE247B671C3F3FEC00AE3E12 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */; }; + EE247B681C3F3FEC00AE3E12 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */; }; + EE247B691C3F3FEC00AE3E12 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; }; + EE247B6A1C3F3FEC00AE3E12 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; }; + EE247B6B1C3F3FEC00AE3E12 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; }; + EE247B6C1C3F3FEC00AE3E12 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; }; + EE247B6D1C3F3FEC00AE3E12 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; }; + EE247B6E1C3F3FEC00AE3E12 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; }; + EE247B6F1C3F3FEC00AE3E12 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; }; + EE247B701C3F3FEC00AE3E12 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; }; + EE247B711C3F3FEC00AE3E12 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; }; + EE247B721C3F3FEC00AE3E12 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; }; + EE247B731C3F3FEC00AE3E12 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; }; + EE247B741C3F3FEC00AE3E12 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; }; + EE247B751C3F3FEC00AE3E12 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; }; + EE91808C1C46E34A0038162A /* usr/include/sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808B1C46E34A0038162A /* usr/include/sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE91808E1C46E5230038162A /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808D1C46E5230038162A /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE91808F1C46E76D0038162A /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808D1C46E5230038162A /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE9180901C46E8980038162A /* usr/include/sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808B1C46E34A0038162A /* usr/include/sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE9180941C46EA210038162A /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EE9180931C46EA210038162A /* libsqlite3.tbd */; }; + EE9180951C46EBCC0038162A /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EE9180911C46E9D30038162A /* libsqlite3.tbd */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 03A65E651C6BB0F60062603F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 03A65E591C6BB0F50062603F; + remoteInfo = "SQLite tvOS"; + }; + EE247ADF1C3F04ED00AE3E12 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EE247AD21C3F04ED00AE3E12; + remoteInfo = SQLite; + }; + EE247B471C3F3ED000AE3E12 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EE247B3B1C3F3ED000AE3E12; + remoteInfo = SQLite; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 03A65E5A1C6BB0F50062603F /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 03A65E961C6BB3210062603F /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; }; + 19A1721B8984686B9963B45D /* FTS5Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS5Tests.swift; sourceTree = ""; }; + 19A1730E4390C775C25677D1 /* FTS5.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS5.swift; sourceTree = ""; }; + 19A17399EA9E61235D5D77BF /* CipherTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CipherTests.swift; sourceTree = ""; }; + 19A178A39ACA9667A62663CC /* Cipher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cipher.swift; sourceTree = ""; }; + 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoundationTests.swift; sourceTree = ""; }; + 19A17B93B48B5560E6E51791 /* Fixtures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fixtures.swift; sourceTree = ""; }; + 19A17E2695737FAB5D6086E3 /* fixtures */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; path = fixtures; sourceTree = ""; }; + 39548A631CA63C740003E3B5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + 39548A651CA63C740003E3B5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + 39548A671CA63C740003E3B5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + 39548A691CA63C740003E3B5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + 39548A6B1CA63C740003E3B5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + 39548A6D1CA63C740003E3B5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + 39548A6F1CA63C740003E3B5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + 3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.0.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; }; + A121AC451CA35C79005A31D1 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EE247AD31C3F04ED00AE3E12 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EE247AD61C3F04ED00AE3E12 /* SQLite.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLite.h; sourceTree = ""; }; + EE247AD81C3F04ED00AE3E12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + EE247AE41C3F04ED00AE3E12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EE247AEE1C3F06E900AE3E12 /* Blob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Blob.swift; sourceTree = ""; }; + EE247AEF1C3F06E900AE3E12 /* Connection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Connection.swift; sourceTree = ""; }; + EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = ../../SQLiteObjc/fts3_tokenizer.h; sourceTree = ""; }; + EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SQLite-Bridging.m"; path = "../../SQLiteObjc/SQLite-Bridging.m"; sourceTree = ""; }; + EE247AF21C3F06E900AE3E12 /* Statement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Statement.swift; sourceTree = ""; }; + EE247AF31C3F06E900AE3E12 /* Value.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Value.swift; sourceTree = ""; }; + EE247AF51C3F06E900AE3E12 /* FTS4.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS4.swift; sourceTree = ""; }; + EE247AF61C3F06E900AE3E12 /* RTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTree.swift; sourceTree = ""; }; + EE247AF71C3F06E900AE3E12 /* Foundation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Foundation.swift; sourceTree = ""; }; + EE247AF81C3F06E900AE3E12 /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; + EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AggregateFunctions.swift; sourceTree = ""; }; + EE247AFB1C3F06E900AE3E12 /* Collation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collation.swift; sourceTree = ""; }; + EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreFunctions.swift; sourceTree = ""; }; + EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomFunctions.swift; sourceTree = ""; }; + EE247AFE1C3F06E900AE3E12 /* Expression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Expression.swift; sourceTree = ""; }; + EE247AFF1C3F06E900AE3E12 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; + EE247B001C3F06E900AE3E12 /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; + EE247B011C3F06E900AE3E12 /* Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Schema.swift; sourceTree = ""; }; + EE247B021C3F06E900AE3E12 /* Setter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Setter.swift; sourceTree = ""; }; + EE247B161C3F127200AE3E12 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; }; + EE247B181C3F134A00AE3E12 /* SetterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetterTests.swift; sourceTree = ""; }; + EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AggregateFunctionsTests.swift; sourceTree = ""; }; + EE247B1B1C3F137700AE3E12 /* BlobTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlobTests.swift; sourceTree = ""; }; + EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionTests.swift; sourceTree = ""; }; + EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreFunctionsTests.swift; sourceTree = ""; }; + EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomFunctionsTests.swift; sourceTree = ""; }; + EE247B201C3F137700AE3E12 /* ExpressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpressionTests.swift; sourceTree = ""; }; + EE247B211C3F137700AE3E12 /* FTS4Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS4Tests.swift; sourceTree = ""; }; + EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorsTests.swift; sourceTree = ""; }; + EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = ""; }; + EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTreeTests.swift; sourceTree = ""; }; + EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaTests.swift; sourceTree = ""; }; + EE247B321C3F142E00AE3E12 /* StatementTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatementTests.swift; sourceTree = ""; }; + EE247B331C3F142E00AE3E12 /* ValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValueTests.swift; sourceTree = ""; }; + EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + EE247B771C3F40D700AE3E12 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + EE247B8B1C3F820300AE3E12 /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = ""; }; + EE247B8C1C3F821200AE3E12 /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = ""; }; + EE247B8D1C3F821200AE3E12 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + EE247B8F1C3F822500AE3E12 /* Index.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Index.md; sourceTree = ""; }; + EE247B911C3F822500AE3E12 /* installation@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "installation@2x.png"; sourceTree = ""; }; + EE247B921C3F822600AE3E12 /* playground@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "playground@2x.png"; sourceTree = ""; }; + EE247B931C3F826100AE3E12 /* SQLite.swift.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = SQLite.swift.podspec; sourceTree = ""; }; + EE91808B1C46E34A0038162A /* usr/include/sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usr/include/sqlite3.h; sourceTree = SDKROOT; }; + EE91808D1C46E5230038162A /* SQLite-Bridging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SQLite-Bridging.h"; path = "../../SQLiteObjc/include/SQLite-Bridging.h"; sourceTree = ""; }; + EE9180911C46E9D30038162A /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; }; + EE9180931C46EA210038162A /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 03A65E561C6BB0F50062603F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 03A65E971C6BB3210062603F /* libsqlite3.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 03A65E601C6BB0F60062603F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 03A65E641C6BB0F60062603F /* SQLite.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A121AC411CA35C79005A31D1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D67B3E61DB2469200A4F4C6 /* libsqlite3.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247ACF1C3F04ED00AE3E12 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EE9180941C46EA210038162A /* libsqlite3.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247ADA1C3F04ED00AE3E12 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EE247ADE1C3F04ED00AE3E12 /* SQLite.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247B381C3F3ED000AE3E12 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EE9180951C46EBCC0038162A /* libsqlite3.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247B421C3F3ED000AE3E12 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EE247B461C3F3ED000AE3E12 /* SQLite.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 39548A611CA63C740003E3B5 /* CocoaPods */ = { + isa = PBXGroup; + children = ( + 39548A621CA63C740003E3B5 /* appletvos */, + 39548A641CA63C740003E3B5 /* appletvsimulator */, + 39548A661CA63C740003E3B5 /* iphoneos */, + 39548A681CA63C740003E3B5 /* iphonesimulator */, + 39548A6A1CA63C740003E3B5 /* macosx */, + 39548A6C1CA63C740003E3B5 /* watchos */, + 39548A6E1CA63C740003E3B5 /* watchsimulator */, + ); + path = CocoaPods; + sourceTree = ""; + }; + 39548A621CA63C740003E3B5 /* appletvos */ = { + isa = PBXGroup; + children = ( + 39548A631CA63C740003E3B5 /* module.modulemap */, + ); + path = appletvos; + sourceTree = ""; + }; + 39548A641CA63C740003E3B5 /* appletvsimulator */ = { + isa = PBXGroup; + children = ( + 39548A651CA63C740003E3B5 /* module.modulemap */, + ); + path = appletvsimulator; + sourceTree = ""; + }; + 39548A661CA63C740003E3B5 /* iphoneos */ = { + isa = PBXGroup; + children = ( + 39548A671CA63C740003E3B5 /* module.modulemap */, + ); + path = iphoneos; + sourceTree = ""; + }; + 39548A681CA63C740003E3B5 /* iphonesimulator */ = { + isa = PBXGroup; + children = ( + 39548A691CA63C740003E3B5 /* module.modulemap */, + ); + path = iphonesimulator; + sourceTree = ""; + }; + 39548A6A1CA63C740003E3B5 /* macosx */ = { + isa = PBXGroup; + children = ( + 39548A6B1CA63C740003E3B5 /* module.modulemap */, + ); + path = macosx; + sourceTree = ""; + }; + 39548A6C1CA63C740003E3B5 /* watchos */ = { + isa = PBXGroup; + children = ( + 39548A6D1CA63C740003E3B5 /* module.modulemap */, + ); + path = watchos; + sourceTree = ""; + }; + 39548A6E1CA63C740003E3B5 /* watchsimulator */ = { + isa = PBXGroup; + children = ( + 39548A6F1CA63C740003E3B5 /* module.modulemap */, + ); + path = watchsimulator; + sourceTree = ""; + }; + 3D67B3E41DB2469200A4F4C6 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; + EE247AC91C3F04ED00AE3E12 = { + isa = PBXGroup; + children = ( + EE247AD51C3F04ED00AE3E12 /* SQLite */, + EE247AE11C3F04ED00AE3E12 /* SQLiteTests */, + EE247B8A1C3F81D000AE3E12 /* Metadata */, + EE247AD41C3F04ED00AE3E12 /* Products */, + 3D67B3E41DB2469200A4F4C6 /* Frameworks */, + ); + indentWidth = 4; + sourceTree = ""; + tabWidth = 4; + }; + EE247AD41C3F04ED00AE3E12 /* Products */ = { + isa = PBXGroup; + children = ( + EE247AD31C3F04ED00AE3E12 /* SQLite.framework */, + EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */, + EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */, + EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */, + 03A65E5A1C6BB0F50062603F /* SQLite.framework */, + 03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */, + A121AC451CA35C79005A31D1 /* SQLite.framework */, + ); + name = Products; + sourceTree = ""; + }; + EE247AD51C3F04ED00AE3E12 /* SQLite */ = { + isa = PBXGroup; + children = ( + EE91808B1C46E34A0038162A /* usr/include/sqlite3.h */, + EE247AD61C3F04ED00AE3E12 /* SQLite.h */, + EE247AF71C3F06E900AE3E12 /* Foundation.swift */, + EE247AF81C3F06E900AE3E12 /* Helpers.swift */, + EE247AD81C3F04ED00AE3E12 /* Info.plist */, + EE247AED1C3F06E900AE3E12 /* Core */, + EE247AF41C3F06E900AE3E12 /* Extensions */, + EE247AF91C3F06E900AE3E12 /* Typed */, + ); + name = SQLite; + path = Sources/SQLite; + sourceTree = ""; + }; + EE247AE11C3F04ED00AE3E12 /* SQLiteTests */ = { + isa = PBXGroup; + children = ( + 19A17E2695737FAB5D6086E3 /* fixtures */, + EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */, + EE247B1B1C3F137700AE3E12 /* BlobTests.swift */, + EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */, + EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */, + EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */, + EE247B201C3F137700AE3E12 /* ExpressionTests.swift */, + EE247B211C3F137700AE3E12 /* FTS4Tests.swift */, + EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */, + EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */, + EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */, + EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */, + EE247B181C3F134A00AE3E12 /* SetterTests.swift */, + EE247B321C3F142E00AE3E12 /* StatementTests.swift */, + EE247B331C3F142E00AE3E12 /* ValueTests.swift */, + EE247B161C3F127200AE3E12 /* TestHelpers.swift */, + EE247AE41C3F04ED00AE3E12 /* Info.plist */, + 19A1721B8984686B9963B45D /* FTS5Tests.swift */, + 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */, + 19A17399EA9E61235D5D77BF /* CipherTests.swift */, + 19A17B93B48B5560E6E51791 /* Fixtures.swift */, + ); + name = SQLiteTests; + path = Tests/SQLiteTests; + sourceTree = ""; + }; + EE247AED1C3F06E900AE3E12 /* Core */ = { + isa = PBXGroup; + children = ( + EE91808D1C46E5230038162A /* SQLite-Bridging.h */, + EE247AEE1C3F06E900AE3E12 /* Blob.swift */, + EE247AEF1C3F06E900AE3E12 /* Connection.swift */, + EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */, + EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */, + EE247AF21C3F06E900AE3E12 /* Statement.swift */, + EE247AF31C3F06E900AE3E12 /* Value.swift */, + ); + path = Core; + sourceTree = ""; + }; + EE247AF41C3F06E900AE3E12 /* Extensions */ = { + isa = PBXGroup; + children = ( + EE247AF51C3F06E900AE3E12 /* FTS4.swift */, + EE247AF61C3F06E900AE3E12 /* RTree.swift */, + 19A1730E4390C775C25677D1 /* FTS5.swift */, + 19A178A39ACA9667A62663CC /* Cipher.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + EE247AF91C3F06E900AE3E12 /* Typed */ = { + isa = PBXGroup; + children = ( + EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */, + EE247AFB1C3F06E900AE3E12 /* Collation.swift */, + EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */, + EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */, + EE247AFE1C3F06E900AE3E12 /* Expression.swift */, + EE247AFF1C3F06E900AE3E12 /* Operators.swift */, + EE247B001C3F06E900AE3E12 /* Query.swift */, + EE247B011C3F06E900AE3E12 /* Schema.swift */, + EE247B021C3F06E900AE3E12 /* Setter.swift */, + ); + path = Typed; + sourceTree = ""; + }; + EE247B8A1C3F81D000AE3E12 /* Metadata */ = { + isa = PBXGroup; + children = ( + 39548A611CA63C740003E3B5 /* CocoaPods */, + EE247B771C3F40D700AE3E12 /* README.md */, + EE247B8B1C3F820300AE3E12 /* CONTRIBUTING.md */, + EE247B931C3F826100AE3E12 /* SQLite.swift.podspec */, + EE247B8C1C3F821200AE3E12 /* .travis.yml */, + EE247B8D1C3F821200AE3E12 /* Makefile */, + EE9180931C46EA210038162A /* libsqlite3.tbd */, + EE9180911C46E9D30038162A /* libsqlite3.tbd */, + 03A65E961C6BB3210062603F /* libsqlite3.tbd */, + EE247B8E1C3F822500AE3E12 /* Documentation */, + ); + name = Metadata; + sourceTree = ""; + }; + EE247B8E1C3F822500AE3E12 /* Documentation */ = { + isa = PBXGroup; + children = ( + EE247B8F1C3F822500AE3E12 /* Index.md */, + EE247B901C3F822500AE3E12 /* Resources */, + ); + path = Documentation; + sourceTree = ""; + }; + EE247B901C3F822500AE3E12 /* Resources */ = { + isa = PBXGroup; + children = ( + EE247B911C3F822500AE3E12 /* installation@2x.png */, + EE247B921C3F822600AE3E12 /* playground@2x.png */, + ); + path = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 03A65E571C6BB0F50062603F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 03A65E781C6BB2EA0062603F /* fts3_tokenizer.h in Headers */, + 03A65E751C6BB2DF0062603F /* SQLite-Bridging.h in Headers */, + 03A65E711C6BB2CD0062603F /* usr/include/sqlite3.h in Headers */, + 03A65E721C6BB2D30062603F /* SQLite.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A121AC421CA35C79005A31D1 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D67B3FA1DB2470600A4F4C6 /* usr/include/sqlite3.h in Headers */, + 3D67B3FB1DB2470600A4F4C6 /* SQLite-Bridging.h in Headers */, + 3D67B3FC1DB2471B00A4F4C6 /* SQLite.h in Headers */, + 3D67B3FD1DB2472D00A4F4C6 /* fts3_tokenizer.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247AD01C3F04ED00AE3E12 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EE91808E1C46E5230038162A /* SQLite-Bridging.h in Headers */, + EE247B051C3F06E900AE3E12 /* fts3_tokenizer.h in Headers */, + EE91808C1C46E34A0038162A /* usr/include/sqlite3.h in Headers */, + EE247AD71C3F04ED00AE3E12 /* SQLite.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247B391C3F3ED000AE3E12 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EE9180901C46E8980038162A /* usr/include/sqlite3.h in Headers */, + EE247B671C3F3FEC00AE3E12 /* fts3_tokenizer.h in Headers */, + EE247B621C3F3FDB00AE3E12 /* SQLite.h in Headers */, + EE91808F1C46E76D0038162A /* SQLite-Bridging.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 03A65E591C6BB0F50062603F /* SQLite tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 03A65E6F1C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLite tvOS" */; + buildPhases = ( + 03A65E551C6BB0F50062603F /* Sources */, + 03A65E561C6BB0F50062603F /* Frameworks */, + 03A65E571C6BB0F50062603F /* Headers */, + 03A65E581C6BB0F50062603F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SQLite tvOS"; + productName = "SQLite tvOS"; + productReference = 03A65E5A1C6BB0F50062603F /* SQLite.framework */; + productType = "com.apple.product-type.framework"; + }; + 03A65E621C6BB0F60062603F /* SQLiteTests tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 03A65E701C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLiteTests tvOS" */; + buildPhases = ( + 03A65E5F1C6BB0F60062603F /* Sources */, + 03A65E601C6BB0F60062603F /* Frameworks */, + 03A65E611C6BB0F60062603F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 03A65E661C6BB0F60062603F /* PBXTargetDependency */, + ); + name = "SQLiteTests tvOS"; + productName = "SQLite tvOSTests"; + productReference = 03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + A121AC441CA35C79005A31D1 /* SQLite watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = A121AC4C1CA35C79005A31D1 /* Build configuration list for PBXNativeTarget "SQLite watchOS" */; + buildPhases = ( + A121AC401CA35C79005A31D1 /* Sources */, + A121AC411CA35C79005A31D1 /* Frameworks */, + A121AC421CA35C79005A31D1 /* Headers */, + A121AC431CA35C79005A31D1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SQLite watchOS"; + productName = "SQLite watchOS"; + productReference = A121AC451CA35C79005A31D1 /* SQLite.framework */; + productType = "com.apple.product-type.framework"; + }; + EE247AD21C3F04ED00AE3E12 /* SQLite iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = EE247AE71C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLite iOS" */; + buildPhases = ( + EE247ACE1C3F04ED00AE3E12 /* Sources */, + EE247ACF1C3F04ED00AE3E12 /* Frameworks */, + EE247AD01C3F04ED00AE3E12 /* Headers */, + EE247AD11C3F04ED00AE3E12 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SQLite iOS"; + productName = SQLite; + productReference = EE247AD31C3F04ED00AE3E12 /* SQLite.framework */; + productType = "com.apple.product-type.framework"; + }; + EE247ADC1C3F04ED00AE3E12 /* SQLiteTests iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = EE247AEA1C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests iOS" */; + buildPhases = ( + EE247AD91C3F04ED00AE3E12 /* Sources */, + EE247ADA1C3F04ED00AE3E12 /* Frameworks */, + EE247ADB1C3F04ED00AE3E12 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + EE247AE01C3F04ED00AE3E12 /* PBXTargetDependency */, + ); + name = "SQLiteTests iOS"; + productName = SQLiteTests; + productReference = EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = EE247B511C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLite Mac" */; + buildPhases = ( + EE247B371C3F3ED000AE3E12 /* Sources */, + EE247B381C3F3ED000AE3E12 /* Frameworks */, + EE247B391C3F3ED000AE3E12 /* Headers */, + EE247B3A1C3F3ED000AE3E12 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SQLite Mac"; + productName = SQLite; + productReference = EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */; + productType = "com.apple.product-type.framework"; + }; + EE247B441C3F3ED000AE3E12 /* SQLiteTests Mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = EE247B521C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests Mac" */; + buildPhases = ( + EE247B411C3F3ED000AE3E12 /* Sources */, + EE247B421C3F3ED000AE3E12 /* Frameworks */, + EE247B431C3F3ED000AE3E12 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + EE247B481C3F3ED000AE3E12 /* PBXTargetDependency */, + ); + name = "SQLiteTests Mac"; + productName = SQLiteTests; + productReference = EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + EE247ACA1C3F04ED00AE3E12 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0800; + TargetAttributes = { + 03A65E591C6BB0F50062603F = { + CreatedOnToolsVersion = 7.2; + }; + 03A65E621C6BB0F60062603F = { + CreatedOnToolsVersion = 7.2; + }; + A121AC441CA35C79005A31D1 = { + CreatedOnToolsVersion = 7.3; + }; + EE247AD21C3F04ED00AE3E12 = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0820; + }; + EE247ADC1C3F04ED00AE3E12 = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; + }; + EE247B3B1C3F3ED000AE3E12 = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; + }; + EE247B441C3F3ED000AE3E12 = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; + }; + }; + }; + buildConfigurationList = EE247ACD1C3F04ED00AE3E12 /* Build configuration list for PBXProject "SQLite" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = EE247AC91C3F04ED00AE3E12; + productRefGroup = EE247AD41C3F04ED00AE3E12 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + EE247AD21C3F04ED00AE3E12 /* SQLite iOS */, + EE247ADC1C3F04ED00AE3E12 /* SQLiteTests iOS */, + EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */, + EE247B441C3F3ED000AE3E12 /* SQLiteTests Mac */, + 03A65E591C6BB0F50062603F /* SQLite tvOS */, + 03A65E621C6BB0F60062603F /* SQLiteTests tvOS */, + A121AC441CA35C79005A31D1 /* SQLite watchOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 03A65E581C6BB0F50062603F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 03A65E611C6BB0F60062603F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 19A17F3E1F7ACA33BD43E138 /* fixtures in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A121AC431CA35C79005A31D1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247AD11C3F04ED00AE3E12 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247ADB1C3F04ED00AE3E12 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 19A17FDA323BAFDEC627E76F /* fixtures in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247B3A1C3F3ED000AE3E12 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247B431C3F3ED000AE3E12 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 19A175DFF47B84757E547C62 /* fixtures in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 03A65E551C6BB0F50062603F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 03A65E801C6BB2FB0062603F /* CoreFunctions.swift in Sources */, + 03A65E761C6BB2E60062603F /* Blob.swift in Sources */, + 03A65E7D1C6BB2F70062603F /* RTree.swift in Sources */, + 03A65E791C6BB2EF0062603F /* SQLite-Bridging.m in Sources */, + 03A65E7B1C6BB2F70062603F /* Value.swift in Sources */, + 03A65E821C6BB2FB0062603F /* Expression.swift in Sources */, + 03A65E731C6BB2D80062603F /* Foundation.swift in Sources */, + 03A65E7F1C6BB2FB0062603F /* Collation.swift in Sources */, + 03A65E861C6BB2FB0062603F /* Setter.swift in Sources */, + 03A65E811C6BB2FB0062603F /* CustomFunctions.swift in Sources */, + 03A65E7A1C6BB2F70062603F /* Statement.swift in Sources */, + 03A65E741C6BB2DA0062603F /* Helpers.swift in Sources */, + 03A65E831C6BB2FB0062603F /* Operators.swift in Sources */, + 03A65E851C6BB2FB0062603F /* Schema.swift in Sources */, + 03A65E841C6BB2FB0062603F /* Query.swift in Sources */, + 03A65E7C1C6BB2F70062603F /* FTS4.swift in Sources */, + 03A65E771C6BB2E60062603F /* Connection.swift in Sources */, + 03A65E7E1C6BB2FB0062603F /* AggregateFunctions.swift in Sources */, + 19A17EC0D68BA8C03288ADF7 /* FTS5.swift in Sources */, + 19A179E76EA6207669B60C1B /* Cipher.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 03A65E5F1C6BB0F60062603F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 03A65E881C6BB3030062603F /* BlobTests.swift in Sources */, + 03A65E901C6BB3030062603F /* RTreeTests.swift in Sources */, + 03A65E941C6BB3030062603F /* ValueTests.swift in Sources */, + 03A65E8F1C6BB3030062603F /* QueryTests.swift in Sources */, + 03A65E8B1C6BB3030062603F /* CustomFunctionsTests.swift in Sources */, + 03A65E871C6BB3030062603F /* AggregateFunctionsTests.swift in Sources */, + 03A65E921C6BB3030062603F /* SetterTests.swift in Sources */, + 03A65E891C6BB3030062603F /* ConnectionTests.swift in Sources */, + 03A65E8A1C6BB3030062603F /* CoreFunctionsTests.swift in Sources */, + 03A65E931C6BB3030062603F /* StatementTests.swift in Sources */, + 03A65E911C6BB3030062603F /* SchemaTests.swift in Sources */, + 03A65E8D1C6BB3030062603F /* FTS4Tests.swift in Sources */, + 03A65E8C1C6BB3030062603F /* ExpressionTests.swift in Sources */, + 03A65E8E1C6BB3030062603F /* OperatorsTests.swift in Sources */, + 03A65E951C6BB3030062603F /* TestHelpers.swift in Sources */, + 19A17254FBA7894891F7297B /* FTS5Tests.swift in Sources */, + 19A17E04C4C0956715C5676A /* FoundationTests.swift in Sources */, + 19A179A0C45377CB09BB358C /* CipherTests.swift in Sources */, + 19A17F60B685636D1F83C2DD /* Fixtures.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A121AC401CA35C79005A31D1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D67B3F91DB246E700A4F4C6 /* SQLite-Bridging.m in Sources */, + 3D67B3F71DB246D700A4F4C6 /* Foundation.swift in Sources */, + 3D67B3F81DB246D700A4F4C6 /* Helpers.swift in Sources */, + 3D67B3E91DB246D100A4F4C6 /* Statement.swift in Sources */, + 3D67B3EA1DB246D100A4F4C6 /* Value.swift in Sources */, + 3D67B3EB1DB246D100A4F4C6 /* FTS4.swift in Sources */, + 3D67B3EC1DB246D100A4F4C6 /* RTree.swift in Sources */, + 3D67B3ED1DB246D100A4F4C6 /* FTS5.swift in Sources */, + 3D67B3EE1DB246D100A4F4C6 /* AggregateFunctions.swift in Sources */, + 3D67B3EF1DB246D100A4F4C6 /* Collation.swift in Sources */, + 3D67B3F01DB246D100A4F4C6 /* CoreFunctions.swift in Sources */, + 3D67B3F11DB246D100A4F4C6 /* CustomFunctions.swift in Sources */, + 3D67B3F21DB246D100A4F4C6 /* Expression.swift in Sources */, + 3D67B3F31DB246D100A4F4C6 /* Operators.swift in Sources */, + 3D67B3F41DB246D100A4F4C6 /* Query.swift in Sources */, + 3D67B3F51DB246D100A4F4C6 /* Schema.swift in Sources */, + 3D67B3F61DB246D100A4F4C6 /* Setter.swift in Sources */, + 3D67B3E71DB246BA00A4F4C6 /* Blob.swift in Sources */, + 3D67B3E81DB246BA00A4F4C6 /* Connection.swift in Sources */, + 19A179CCF9671E345E5A9811 /* Cipher.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247ACE1C3F04ED00AE3E12 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EE247B0F1C3F06E900AE3E12 /* CoreFunctions.swift in Sources */, + EE247B0A1C3F06E900AE3E12 /* RTree.swift in Sources */, + EE247B031C3F06E900AE3E12 /* Blob.swift in Sources */, + EE247B0B1C3F06E900AE3E12 /* Foundation.swift in Sources */, + EE247B041C3F06E900AE3E12 /* Connection.swift in Sources */, + EE247B111C3F06E900AE3E12 /* Expression.swift in Sources */, + EE247B0C1C3F06E900AE3E12 /* Helpers.swift in Sources */, + EE247B0E1C3F06E900AE3E12 /* Collation.swift in Sources */, + EE247B151C3F06E900AE3E12 /* Setter.swift in Sources */, + EE247B101C3F06E900AE3E12 /* CustomFunctions.swift in Sources */, + EE247B091C3F06E900AE3E12 /* FTS4.swift in Sources */, + EE247B081C3F06E900AE3E12 /* Value.swift in Sources */, + EE247B121C3F06E900AE3E12 /* Operators.swift in Sources */, + EE247B141C3F06E900AE3E12 /* Schema.swift in Sources */, + EE247B131C3F06E900AE3E12 /* Query.swift in Sources */, + EE247B061C3F06E900AE3E12 /* SQLite-Bridging.m in Sources */, + EE247B071C3F06E900AE3E12 /* Statement.swift in Sources */, + EE247B0D1C3F06E900AE3E12 /* AggregateFunctions.swift in Sources */, + 19A1717B10CC941ACB5533D6 /* FTS5.swift in Sources */, + 19A171F12AB8B07F2FD7201A /* Cipher.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247AD91C3F04ED00AE3E12 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EE247B261C3F137700AE3E12 /* CoreFunctionsTests.swift in Sources */, + EE247B291C3F137700AE3E12 /* FTS4Tests.swift in Sources */, + EE247B191C3F134A00AE3E12 /* SetterTests.swift in Sources */, + EE247B311C3F141E00AE3E12 /* SchemaTests.swift in Sources */, + EE247B171C3F127200AE3E12 /* TestHelpers.swift in Sources */, + EE247B281C3F137700AE3E12 /* ExpressionTests.swift in Sources */, + EE247B271C3F137700AE3E12 /* CustomFunctionsTests.swift in Sources */, + EE247B341C3F142E00AE3E12 /* StatementTests.swift in Sources */, + EE247B301C3F141E00AE3E12 /* RTreeTests.swift in Sources */, + EE247B231C3F137700AE3E12 /* BlobTests.swift in Sources */, + EE247B351C3F142E00AE3E12 /* ValueTests.swift in Sources */, + EE247B2F1C3F141E00AE3E12 /* QueryTests.swift in Sources */, + EE247B221C3F137700AE3E12 /* AggregateFunctionsTests.swift in Sources */, + EE247B2E1C3F141E00AE3E12 /* OperatorsTests.swift in Sources */, + EE247B251C3F137700AE3E12 /* ConnectionTests.swift in Sources */, + 19A171E6FA242F72A308C594 /* FTS5Tests.swift in Sources */, + 19A17FB80B94E882050AA908 /* FoundationTests.swift in Sources */, + 19A177CC33F2E6A24AF90B02 /* CipherTests.swift in Sources */, + 19A17408007B182F884E3A53 /* Fixtures.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247B371C3F3ED000AE3E12 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EE247B6F1C3F3FEC00AE3E12 /* CoreFunctions.swift in Sources */, + EE247B651C3F3FEC00AE3E12 /* Blob.swift in Sources */, + EE247B6C1C3F3FEC00AE3E12 /* RTree.swift in Sources */, + EE247B681C3F3FEC00AE3E12 /* SQLite-Bridging.m in Sources */, + EE247B6A1C3F3FEC00AE3E12 /* Value.swift in Sources */, + EE247B711C3F3FEC00AE3E12 /* Expression.swift in Sources */, + EE247B631C3F3FDB00AE3E12 /* Foundation.swift in Sources */, + EE247B6E1C3F3FEC00AE3E12 /* Collation.swift in Sources */, + EE247B751C3F3FEC00AE3E12 /* Setter.swift in Sources */, + EE247B701C3F3FEC00AE3E12 /* CustomFunctions.swift in Sources */, + EE247B691C3F3FEC00AE3E12 /* Statement.swift in Sources */, + EE247B641C3F3FDB00AE3E12 /* Helpers.swift in Sources */, + EE247B721C3F3FEC00AE3E12 /* Operators.swift in Sources */, + EE247B741C3F3FEC00AE3E12 /* Schema.swift in Sources */, + EE247B731C3F3FEC00AE3E12 /* Query.swift in Sources */, + EE247B6B1C3F3FEC00AE3E12 /* FTS4.swift in Sources */, + EE247B661C3F3FEC00AE3E12 /* Connection.swift in Sources */, + EE247B6D1C3F3FEC00AE3E12 /* AggregateFunctions.swift in Sources */, + 19A1750CEE9B05267995CF3D /* FTS5.swift in Sources */, + 19A17835FD5886FDC5A3228F /* Cipher.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EE247B411C3F3ED000AE3E12 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EE247B561C3F3FC700AE3E12 /* CoreFunctionsTests.swift in Sources */, + EE247B5A1C3F3FC700AE3E12 /* OperatorsTests.swift in Sources */, + EE247B541C3F3FC700AE3E12 /* BlobTests.swift in Sources */, + EE247B5D1C3F3FC700AE3E12 /* SchemaTests.swift in Sources */, + EE247B591C3F3FC700AE3E12 /* FTS4Tests.swift in Sources */, + EE247B531C3F3FC700AE3E12 /* AggregateFunctionsTests.swift in Sources */, + EE247B5F1C3F3FC700AE3E12 /* StatementTests.swift in Sources */, + EE247B5C1C3F3FC700AE3E12 /* RTreeTests.swift in Sources */, + EE247B571C3F3FC700AE3E12 /* CustomFunctionsTests.swift in Sources */, + EE247B601C3F3FC700AE3E12 /* ValueTests.swift in Sources */, + EE247B551C3F3FC700AE3E12 /* ConnectionTests.swift in Sources */, + EE247B611C3F3FC700AE3E12 /* TestHelpers.swift in Sources */, + EE247B581C3F3FC700AE3E12 /* ExpressionTests.swift in Sources */, + EE247B5E1C3F3FC700AE3E12 /* SetterTests.swift in Sources */, + EE247B5B1C3F3FC700AE3E12 /* QueryTests.swift in Sources */, + 19A174D78559CD30679BCCCB /* FTS5Tests.swift in Sources */, + 19A178072B371489E6A1E839 /* FoundationTests.swift in Sources */, + 19A17C4B951CB054EE48AB1C /* CipherTests.swift in Sources */, + 19A1709C3E7A406E62293B2A /* Fixtures.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 03A65E661C6BB0F60062603F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 03A65E591C6BB0F50062603F /* SQLite tvOS */; + targetProxy = 03A65E651C6BB0F60062603F /* PBXContainerItemProxy */; + }; + EE247AE01C3F04ED00AE3E12 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EE247AD21C3F04ED00AE3E12 /* SQLite iOS */; + targetProxy = EE247ADF1C3F04ED00AE3E12 /* PBXContainerItemProxy */; + }; + EE247B481C3F3ED000AE3E12 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */; + targetProxy = EE247B471C3F3ED000AE3E12 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 03A65E6B1C6BB0F60062603F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; + PRODUCT_NAME = SQLite; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + "SWIFT_INCLUDE_PATHS[sdk=appletvos*]" = "$(SRCROOT)/CocoaPods/appletvos"; + "SWIFT_INCLUDE_PATHS[sdk=appletvsimulator*]" = "$(SRCROOT)/CocoaPods/appletvsimulator"; + SWIFT_VERSION = 3.0; + TVOS_DEPLOYMENT_TARGET = 9.1; + }; + name = Debug; + }; + 03A65E6C1C6BB0F60062603F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; + PRODUCT_NAME = SQLite; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + "SWIFT_INCLUDE_PATHS[sdk=appletvos*]" = "$(SRCROOT)/CocoaPods/appletvos"; + "SWIFT_INCLUDE_PATHS[sdk=appletvsimulator*]" = "$(SRCROOT)/CocoaPods/appletvsimulator"; + SWIFT_VERSION = 3.0; + TVOS_DEPLOYMENT_TARGET = 9.1; + }; + name = Release; + }; + 03A65E6D1C6BB0F60062603F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = Tests/SQLite/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + SWIFT_VERSION = 3.0; + TVOS_DEPLOYMENT_TARGET = 9.1; + }; + name = Debug; + }; + 03A65E6E1C6BB0F60062603F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = Tests/SQLite/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + SWIFT_VERSION = 3.0; + TVOS_DEPLOYMENT_TARGET = 9.1; + }; + name = Release; + }; + A121AC4A1CA35C79005A31D1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; + PRODUCT_NAME = SQLite; + SDKROOT = watchos; + SKIP_INSTALL = YES; + "SWIFT_INCLUDE_PATHS[sdk=watchos*]" = "$(SRCROOT)/CocoaPods/watchos"; + "SWIFT_INCLUDE_PATHS[sdk=watchsimulator*]" = "$(SRCROOT)/CocoaPods/watchsimulator"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 2.2; + }; + name = Debug; + }; + A121AC4B1CA35C79005A31D1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; + PRODUCT_NAME = SQLite; + SDKROOT = watchos; + SKIP_INSTALL = YES; + "SWIFT_INCLUDE_PATHS[sdk=watchos*]" = "$(SRCROOT)/CocoaPods/watchos"; + "SWIFT_INCLUDE_PATHS[sdk=watchsimulator*]" = "$(SRCROOT)/CocoaPods/watchsimulator"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 2.2; + }; + name = Release; + }; + EE247AE51C3F04ED00AE3E12 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = ""; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2,3"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + EE247AE61C3F04ED00AE3E12 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = ""; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2,3"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + EE247AE81C3F04ED00AE3E12 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; + PRODUCT_NAME = SQLite; + SKIP_INSTALL = YES; + "SWIFT_INCLUDE_PATHS[sdk=iphoneos*]" = "$(SRCROOT)/CocoaPods/iphoneos"; + "SWIFT_INCLUDE_PATHS[sdk=iphoneos10.0]" = "$(SRCROOT)/CocoaPods/iphoneos-10.0"; + "SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]" = "$(SRCROOT)/CocoaPods/iphonesimulator"; + "SWIFT_INCLUDE_PATHS[sdk=iphonesimulator10.0]" = "$(SRCROOT)/CocoaPods/iphonesimulator-10.0"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + EE247AE91C3F04ED00AE3E12 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; + PRODUCT_NAME = SQLite; + SKIP_INSTALL = YES; + "SWIFT_INCLUDE_PATHS[sdk=iphoneos*]" = "$(SRCROOT)/CocoaPods/iphoneos"; + "SWIFT_INCLUDE_PATHS[sdk=iphoneos10.0]" = "$(SRCROOT)/CocoaPods/iphoneos-10.0"; + "SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]" = "$(SRCROOT)/CocoaPods/iphonesimulator"; + "SWIFT_INCLUDE_PATHS[sdk=iphonesimulator10.0]" = "$(SRCROOT)/CocoaPods/iphonesimulator-10.0"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + EE247AEB1C3F04ED00AE3E12 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + EE247AEC1C3F04ED00AE3E12 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + EE247B4D1C3F3ED000AE3E12 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; + PRODUCT_NAME = SQLite; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = ""; + "SWIFT_INCLUDE_PATHS[sdk=macosx*]" = "$(SRCROOT)/CocoaPods/macosx"; + "SWIFT_INCLUDE_PATHS[sdk=macosx10.11]" = "$(SRCROOT)/CocoaPods/macosx-10.11"; + "SWIFT_INCLUDE_PATHS[sdk=macosx10.12]" = "$(SRCROOT)/CocoaPods/macosx-10.12"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + EE247B4E1C3F3ED000AE3E12 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; + PRODUCT_NAME = SQLite; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = ""; + "SWIFT_INCLUDE_PATHS[sdk=macosx*]" = "$(SRCROOT)/CocoaPods/macosx"; + "SWIFT_INCLUDE_PATHS[sdk=macosx10.11]" = "$(SRCROOT)/CocoaPods/macosx-10.11"; + "SWIFT_INCLUDE_PATHS[sdk=macosx10.12]" = "$(SRCROOT)/CocoaPods/macosx-10.12"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + EE247B4F1C3F3ED000AE3E12 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + EE247B501C3F3ED000AE3E12 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 03A65E6F1C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLite tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 03A65E6B1C6BB0F60062603F /* Debug */, + 03A65E6C1C6BB0F60062603F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 03A65E701C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLiteTests tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 03A65E6D1C6BB0F60062603F /* Debug */, + 03A65E6E1C6BB0F60062603F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A121AC4C1CA35C79005A31D1 /* Build configuration list for PBXNativeTarget "SQLite watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A121AC4A1CA35C79005A31D1 /* Debug */, + A121AC4B1CA35C79005A31D1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EE247ACD1C3F04ED00AE3E12 /* Build configuration list for PBXProject "SQLite" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EE247AE51C3F04ED00AE3E12 /* Debug */, + EE247AE61C3F04ED00AE3E12 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EE247AE71C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLite iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EE247AE81C3F04ED00AE3E12 /* Debug */, + EE247AE91C3F04ED00AE3E12 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EE247AEA1C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EE247AEB1C3F04ED00AE3E12 /* Debug */, + EE247AEC1C3F04ED00AE3E12 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EE247B511C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLite Mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EE247B4D1C3F3ED000AE3E12 /* Debug */, + EE247B4E1C3F3ED000AE3E12 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EE247B521C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests Mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EE247B4F1C3F3ED000AE3E12 /* Debug */, + EE247B501C3F3ED000AE3E12 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = EE247ACA1C3F04ED00AE3E12 /* Project object */; +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..cd11dc9dd6 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Blob.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Blob.swift new file mode 100644 index 0000000000..2f5d2a14f4 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Blob.swift @@ -0,0 +1,60 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public struct Blob { + + public let bytes: [UInt8] + + public init(bytes: [UInt8]) { + self.bytes = bytes + } + + public init(bytes: UnsafeRawPointer, length: Int) { + let i8bufptr = UnsafeBufferPointer(start: bytes.assumingMemoryBound(to: UInt8.self), count: length) + self.init(bytes: [UInt8](i8bufptr)) + } + + public func toHex() -> String { + return bytes.map { + ($0 < 16 ? "0" : "") + String($0, radix: 16, uppercase: false) + }.joined(separator: "") + } + +} + +extension Blob : CustomStringConvertible { + + public var description: String { + return "x'\(toHex())'" + } + +} + +extension Blob : Equatable { + +} + +public func ==(lhs: Blob, rhs: Blob) -> Bool { + return lhs.bytes == rhs.bytes +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Connection.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Connection.swift new file mode 100644 index 0000000000..bd9ce1aa0d --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Connection.swift @@ -0,0 +1,756 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation.NSUUID +import Dispatch +#if SQLITE_SWIFT_STANDALONE +import sqlite3 +#elseif SQLITE_SWIFT_SQLCIPHER +import SQLCipher +#else +import SQLite3 +#endif + +/// A connection to SQLite. +public final class Connection { + + /// The location of a SQLite database. + public enum Location { + + /// An in-memory database (equivalent to `.URI(":memory:")`). + /// + /// See: + case inMemory + + /// A temporary, file-backed database (equivalent to `.URI("")`). + /// + /// See: + case temporary + + /// A database located at the given URI filename (or path). + /// + /// See: + /// + /// - Parameter filename: A URI filename + case uri(String) + } + + /// An SQL operation passed to update callbacks. + public enum Operation { + + /// An INSERT operation. + case insert + + /// An UPDATE operation. + case update + + /// A DELETE operation. + case delete + + fileprivate init(rawValue:Int32) { + switch rawValue { + case SQLITE_INSERT: + self = .insert + case SQLITE_UPDATE: + self = .update + case SQLITE_DELETE: + self = .delete + default: + fatalError("unhandled operation code: \(rawValue)") + } + } + } + + public var handle: OpaquePointer { return _handle! } + + fileprivate var _handle: OpaquePointer? = nil + + /// Initializes a new SQLite connection. + /// + /// - Parameters: + /// + /// - location: The location of the database. Creates a new database if it + /// doesn’t already exist (unless in read-only mode). + /// + /// Default: `.InMemory`. + /// + /// - readonly: Whether or not to open the database in a read-only state. + /// + /// Default: `false`. + /// + /// - Returns: A new database connection. + public init(_ location: Location = .inMemory, readonly: Bool = false) throws { + let flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE + try check(sqlite3_open_v2(location.description, &_handle, flags | SQLITE_OPEN_FULLMUTEX, nil)) + queue.setSpecific(key: Connection.queueKey, value: queueContext) + } + + /// Initializes a new connection to a database. + /// + /// - Parameters: + /// + /// - filename: The location of the database. Creates a new database if + /// it doesn’t already exist (unless in read-only mode). + /// + /// - readonly: Whether or not to open the database in a read-only state. + /// + /// Default: `false`. + /// + /// - Throws: `Result.Error` iff a connection cannot be established. + /// + /// - Returns: A new database connection. + public convenience init(_ filename: String, readonly: Bool = false) throws { + try self.init(.uri(filename), readonly: readonly) + } + + deinit { + sqlite3_close(handle) + } + + // MARK: - + + /// Whether or not the database was opened in a read-only state. + public var readonly: Bool { return sqlite3_db_readonly(handle, nil) == 1 } + + /// The last rowid inserted into the database via this connection. + public var lastInsertRowid: Int64 { + return sqlite3_last_insert_rowid(handle) + } + + /// The last number of changes (inserts, updates, or deletes) made to the + /// database via this connection. + public var changes: Int { + return Int(sqlite3_changes(handle)) + } + + /// The total number of changes (inserts, updates, or deletes) made to the + /// database via this connection. + public var totalChanges: Int { + return Int(sqlite3_total_changes(handle)) + } + + // MARK: - Execute + + /// Executes a batch of SQL statements. + /// + /// - Parameter SQL: A batch of zero or more semicolon-separated SQL + /// statements. + /// + /// - Throws: `Result.Error` if query execution fails. + public func execute(_ SQL: String) throws { + _ = try sync { try self.check(sqlite3_exec(self.handle, SQL, nil, nil, nil)) } + } + + // MARK: - Prepare + + /// Prepares a single SQL statement (with optional parameter bindings). + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A list of parameters to bind to the statement. + /// + /// - Returns: A prepared statement. + public func prepare(_ statement: String, _ bindings: Binding?...) throws -> Statement { + if !bindings.isEmpty { return try prepare(statement, bindings) } + return try Statement(self, statement) + } + + /// Prepares a single SQL statement and binds parameters to it. + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A list of parameters to bind to the statement. + /// + /// - Returns: A prepared statement. + public func prepare(_ statement: String, _ bindings: [Binding?]) throws -> Statement { + return try prepare(statement).bind(bindings) + } + + /// Prepares a single SQL statement and binds parameters to it. + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A dictionary of named parameters to bind to the statement. + /// + /// - Returns: A prepared statement. + public func prepare(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement { + return try prepare(statement).bind(bindings) + } + + // MARK: - Run + + /// Runs a single SQL statement (with optional parameter bindings). + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A list of parameters to bind to the statement. + /// + /// - Throws: `Result.Error` if query execution fails. + /// + /// - Returns: The statement. + @discardableResult public func run(_ statement: String, _ bindings: Binding?...) throws -> Statement { + return try run(statement, bindings) + } + + /// Prepares, binds, and runs a single SQL statement. + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A list of parameters to bind to the statement. + /// + /// - Throws: `Result.Error` if query execution fails. + /// + /// - Returns: The statement. + @discardableResult public func run(_ statement: String, _ bindings: [Binding?]) throws -> Statement { + return try prepare(statement).run(bindings) + } + + /// Prepares, binds, and runs a single SQL statement. + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A dictionary of named parameters to bind to the statement. + /// + /// - Throws: `Result.Error` if query execution fails. + /// + /// - Returns: The statement. + @discardableResult public func run(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement { + return try prepare(statement).run(bindings) + } + + // MARK: - Scalar + + /// Runs a single SQL statement (with optional parameter bindings), + /// returning the first value of the first row. + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A list of parameters to bind to the statement. + /// + /// - Returns: The first value of the first row returned. + public func scalar(_ statement: String, _ bindings: Binding?...) throws -> Binding? { + return try scalar(statement, bindings) + } + + /// Runs a single SQL statement (with optional parameter bindings), + /// returning the first value of the first row. + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A list of parameters to bind to the statement. + /// + /// - Returns: The first value of the first row returned. + public func scalar(_ statement: String, _ bindings: [Binding?]) throws -> Binding? { + return try prepare(statement).scalar(bindings) + } + + /// Runs a single SQL statement (with optional parameter bindings), + /// returning the first value of the first row. + /// + /// - Parameters: + /// + /// - statement: A single SQL statement. + /// + /// - bindings: A dictionary of named parameters to bind to the statement. + /// + /// - Returns: The first value of the first row returned. + public func scalar(_ statement: String, _ bindings: [String: Binding?]) throws -> Binding? { + return try prepare(statement).scalar(bindings) + } + + // MARK: - Transactions + + /// The mode in which a transaction acquires a lock. + public enum TransactionMode : String { + + /// Defers locking the database till the first read/write executes. + case deferred = "DEFERRED" + + /// Immediately acquires a reserved lock on the database. + case immediate = "IMMEDIATE" + + /// Immediately acquires an exclusive lock on all databases. + case exclusive = "EXCLUSIVE" + + } + + // TODO: Consider not requiring a throw to roll back? + /// Runs a transaction with the given mode. + /// + /// - Note: Transactions cannot be nested. To nest transactions, see + /// `savepoint()`, instead. + /// + /// - Parameters: + /// + /// - mode: The mode in which a transaction acquires a lock. + /// + /// Default: `.Deferred` + /// + /// - block: A closure to run SQL statements within the transaction. + /// The transaction will be committed when the block returns. The block + /// must throw to roll the transaction back. + /// + /// - Throws: `Result.Error`, and rethrows. + public func transaction(_ mode: TransactionMode = .deferred, block: @escaping () throws -> Void) throws { + try transaction("BEGIN \(mode.rawValue) TRANSACTION", block, "COMMIT TRANSACTION", or: "ROLLBACK TRANSACTION") + } + + // TODO: Consider not requiring a throw to roll back? + // TODO: Consider removing ability to set a name? + /// Runs a transaction with the given savepoint name (if omitted, it will + /// generate a UUID). + /// + /// - SeeAlso: `transaction()`. + /// + /// - Parameters: + /// + /// - savepointName: A unique identifier for the savepoint (optional). + /// + /// - block: A closure to run SQL statements within the transaction. + /// The savepoint will be released (committed) when the block returns. + /// The block must throw to roll the savepoint back. + /// + /// - Throws: `SQLite.Result.Error`, and rethrows. + public func savepoint(_ name: String = UUID().uuidString, block: @escaping () throws -> Void) throws { + let name = name.quote("'") + let savepoint = "SAVEPOINT \(name)" + + try transaction(savepoint, block, "RELEASE \(savepoint)", or: "ROLLBACK TO \(savepoint)") + } + + fileprivate func transaction(_ begin: String, _ block: @escaping () throws -> Void, _ commit: String, or rollback: String) throws { + return try sync { + try self.run(begin) + do { + try block() + } catch { + try self.run(rollback) + throw error + } + try self.run(commit) + } + } + + /// Interrupts any long-running queries. + public func interrupt() { + sqlite3_interrupt(handle) + } + + // MARK: - Handlers + + /// The number of seconds a connection will attempt to retry a statement + /// after encountering a busy signal (lock). + public var busyTimeout: Double = 0 { + didSet { + sqlite3_busy_timeout(handle, Int32(busyTimeout * 1_000)) + } + } + + /// Sets a handler to call after encountering a busy signal (lock). + /// + /// - Parameter callback: This block is executed during a lock in which a + /// busy error would otherwise be returned. It’s passed the number of + /// times it’s been called for this lock. If it returns `true`, it will + /// try again. If it returns `false`, no further attempts will be made. + public func busyHandler(_ callback: ((_ tries: Int) -> Bool)?) { + guard let callback = callback else { + sqlite3_busy_handler(handle, nil, nil) + busyHandler = nil + return + } + + let box: BusyHandler = { callback(Int($0)) ? 1 : 0 } + sqlite3_busy_handler(handle, { callback, tries in + unsafeBitCast(callback, to: BusyHandler.self)(tries) + }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self)) + busyHandler = box + } + fileprivate typealias BusyHandler = @convention(block) (Int32) -> Int32 + fileprivate var busyHandler: BusyHandler? + + /// Sets a handler to call when a statement is executed with the compiled + /// SQL. + /// + /// - Parameter callback: This block is invoked when a statement is executed + /// with the compiled SQL as its argument. + /// + /// db.trace { SQL in print(SQL) } + public func trace(_ callback: ((String) -> Void)?) { + #if SQLITE_SWIFT_SQLCIPHER + trace_v1(callback) + #else + if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) { + trace_v2(callback) + } else { + trace_v1(callback) + } + #endif + } + + fileprivate func trace_v1(_ callback: ((String) -> Void)?) { + guard let callback = callback else { + sqlite3_trace(handle, nil /* xCallback */, nil /* pCtx */) + trace = nil + return + } + let box: Trace = { (pointer: UnsafeRawPointer) in + callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self))) + } + sqlite3_trace(handle, + { + (C: UnsafeMutableRawPointer?, SQL: UnsafePointer?) in + if let C = C, let SQL = SQL { + unsafeBitCast(C, to: Trace.self)(SQL) + } + }, + unsafeBitCast(box, to: UnsafeMutableRawPointer.self) + ) + trace = box + } + + + + + fileprivate typealias Trace = @convention(block) (UnsafeRawPointer) -> Void + fileprivate var trace: Trace? + + /// Registers a callback to be invoked whenever a row is inserted, updated, + /// or deleted in a rowid table. + /// + /// - Parameter callback: A callback invoked with the `Operation` (one of + /// `.Insert`, `.Update`, or `.Delete`), database name, table name, and + /// rowid. + public func updateHook(_ callback: ((_ operation: Operation, _ db: String, _ table: String, _ rowid: Int64) -> Void)?) { + guard let callback = callback else { + sqlite3_update_hook(handle, nil, nil) + updateHook = nil + return + } + + let box: UpdateHook = { + callback( + Operation(rawValue: $0), + String(cString: $1), + String(cString: $2), + $3 + ) + } + sqlite3_update_hook(handle, { callback, operation, db, table, rowid in + unsafeBitCast(callback, to: UpdateHook.self)(operation, db!, table!, rowid) + }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self)) + updateHook = box + } + fileprivate typealias UpdateHook = @convention(block) (Int32, UnsafePointer, UnsafePointer, Int64) -> Void + fileprivate var updateHook: UpdateHook? + + /// Registers a callback to be invoked whenever a transaction is committed. + /// + /// - Parameter callback: A callback invoked whenever a transaction is + /// committed. If this callback throws, the transaction will be rolled + /// back. + public func commitHook(_ callback: (() throws -> Void)?) { + guard let callback = callback else { + sqlite3_commit_hook(handle, nil, nil) + commitHook = nil + return + } + + let box: CommitHook = { + do { + try callback() + } catch { + return 1 + } + return 0 + } + sqlite3_commit_hook(handle, { callback in + unsafeBitCast(callback, to: CommitHook.self)() + }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self)) + commitHook = box + } + fileprivate typealias CommitHook = @convention(block) () -> Int32 + fileprivate var commitHook: CommitHook? + + /// Registers a callback to be invoked whenever a transaction rolls back. + /// + /// - Parameter callback: A callback invoked when a transaction is rolled + /// back. + public func rollbackHook(_ callback: (() -> Void)?) { + guard let callback = callback else { + sqlite3_rollback_hook(handle, nil, nil) + rollbackHook = nil + return + } + + let box: RollbackHook = { callback() } + sqlite3_rollback_hook(handle, { callback in + unsafeBitCast(callback, to: RollbackHook.self)() + }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self)) + rollbackHook = box + } + fileprivate typealias RollbackHook = @convention(block) () -> Void + fileprivate var rollbackHook: RollbackHook? + + /// Creates or redefines a custom SQL function. + /// + /// - Parameters: + /// + /// - function: The name of the function to create or redefine. + /// + /// - argumentCount: The number of arguments that the function takes. If + /// `nil`, the function may take any number of arguments. + /// + /// Default: `nil` + /// + /// - deterministic: Whether or not the function is deterministic (_i.e._ + /// the function always returns the same result for a given input). + /// + /// Default: `false` + /// + /// - block: A block of code to run when the function is called. The block + /// is called with an array of raw SQL values mapped to the function’s + /// parameters and should return a raw SQL value (or nil). + public func createFunction(_ function: String, argumentCount: UInt? = nil, deterministic: Bool = false, _ block: @escaping (_ args: [Binding?]) -> Binding?) { + let argc = argumentCount.map { Int($0) } ?? -1 + let box: Function = { context, argc, argv in + let arguments: [Binding?] = (0..?) -> Void + fileprivate var functions = [String: [Int: Function]]() + + /// Defines a new collating sequence. + /// + /// - Parameters: + /// + /// - collation: The name of the collation added. + /// + /// - block: A collation function that takes two strings and returns the + /// comparison result. + public func createCollation(_ collation: String, _ block: @escaping (_ lhs: String, _ rhs: String) -> ComparisonResult) throws { + let box: Collation = { (lhs: UnsafeRawPointer, rhs: UnsafeRawPointer) in + let lstr = String(cString: lhs.assumingMemoryBound(to: UInt8.self)) + let rstr = String(cString: rhs.assumingMemoryBound(to: UInt8.self)) + return Int32(block(lstr, rstr).rawValue) + } + try check(sqlite3_create_collation_v2(handle, collation, SQLITE_UTF8, + unsafeBitCast(box, to: UnsafeMutableRawPointer.self), + { (callback: UnsafeMutableRawPointer?, _, lhs: UnsafeRawPointer?, _, rhs: UnsafeRawPointer?) in /* xCompare */ + if let lhs = lhs, let rhs = rhs { + return unsafeBitCast(callback, to: Collation.self)(lhs, rhs) + } else { + fatalError("sqlite3_create_collation_v2 callback called with NULL pointer") + } + }, nil /* xDestroy */)) + collations[collation] = box + } + fileprivate typealias Collation = @convention(block) (UnsafeRawPointer, UnsafeRawPointer) -> Int32 + fileprivate var collations = [String: Collation]() + + // MARK: - Error Handling + + func sync(_ block: @escaping () throws -> T) rethrows -> T { + var success: T? + var failure: Error? + + let box: () -> Void = { + do { + success = try block() + } catch { + failure = error + } + } + + if DispatchQueue.getSpecific(key: Connection.queueKey) == queueContext { + box() + } else { + queue.sync(execute: box) // FIXME: rdar://problem/21389236 + } + + if let failure = failure { + try { () -> Void in throw failure }() + } + + return success! + } + + @discardableResult func check(_ resultCode: Int32, statement: Statement? = nil) throws -> Int32 { + guard let error = Result(errorCode: resultCode, connection: self, statement: statement) else { + return resultCode + } + + throw error + } + + fileprivate var queue = DispatchQueue(label: "SQLite.Database", attributes: []) + + fileprivate static let queueKey = DispatchSpecificKey() + + fileprivate lazy var queueContext: Int = unsafeBitCast(self, to: Int.self) + +} + +extension Connection : CustomStringConvertible { + + public var description: String { + return String(cString: sqlite3_db_filename(handle, nil)) + } + +} + +extension Connection.Location : CustomStringConvertible { + + public var description: String { + switch self { + case .inMemory: + return ":memory:" + case .temporary: + return "" + case .uri(let URI): + return URI + } + } + +} + +public enum Result : Error { + + fileprivate static let successCodes: Set = [SQLITE_OK, SQLITE_ROW, SQLITE_DONE] + + case error(message: String, code: Int32, statement: Statement?) + + init?(errorCode: Int32, connection: Connection, statement: Statement? = nil) { + guard !Result.successCodes.contains(errorCode) else { return nil } + + let message = String(cString: sqlite3_errmsg(connection.handle)) + self = .error(message: message, code: errorCode, statement: statement) + } + +} + +extension Result : CustomStringConvertible { + + public var description: String { + switch self { + case let .error(message, errorCode, statement): + if let statement = statement { + return "\(message) (\(statement)) (code: \(errorCode))" + } else { + return "\(message) (code: \(errorCode))" + } + } + } +} + +#if !SQLITE_SWIFT_SQLCIPHER +@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) +extension Connection { + fileprivate func trace_v2(_ callback: ((String) -> Void)?) { + guard let callback = callback else { + // If the X callback is NULL or if the M mask is zero, then tracing is disabled. + sqlite3_trace_v2(handle, 0 /* mask */, nil /* xCallback */, nil /* pCtx */) + trace = nil + return + } + + let box: Trace = { (pointer: UnsafeRawPointer) in + callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self))) + } + sqlite3_trace_v2(handle, + UInt32(SQLITE_TRACE_STMT) /* mask */, + { + // A trace callback is invoked with four arguments: callback(T,C,P,X). + // The T argument is one of the SQLITE_TRACE constants to indicate why the + // callback was invoked. The C argument is a copy of the context pointer. + // The P and X arguments are pointers whose meanings depend on T. + (T: UInt32, C: UnsafeMutableRawPointer?, P: UnsafeMutableRawPointer?, X: UnsafeMutableRawPointer?) in + if let P = P, + let expandedSQL = sqlite3_expanded_sql(OpaquePointer(P)) { + unsafeBitCast(C, to: Trace.self)(expandedSQL) + sqlite3_free(expandedSQL) + } + return Int32(0) // currently ignored + }, + unsafeBitCast(box, to: UnsafeMutableRawPointer.self) /* pCtx */ + ) + trace = box + } +} +#endif diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Statement.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Statement.swift new file mode 100644 index 0000000000..b14bc13c42 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Statement.swift @@ -0,0 +1,297 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#if SQLITE_SWIFT_STANDALONE +import sqlite3 +#elseif SQLITE_SWIFT_SQLCIPHER +import SQLCipher +#else +import SQLite3 +#endif + +/// A single SQL statement. +public final class Statement { + + fileprivate var handle: OpaquePointer? = nil + + fileprivate let connection: Connection + + init(_ connection: Connection, _ SQL: String) throws { + self.connection = connection + try connection.check(sqlite3_prepare_v2(connection.handle, SQL, -1, &handle, nil)) + } + + deinit { + sqlite3_finalize(handle) + } + + public lazy var columnCount: Int = Int(sqlite3_column_count(self.handle)) + + public lazy var columnNames: [String] = (0.. Statement { + return bind(values) + } + + /// Binds a list of parameters to a statement. + /// + /// - Parameter values: A list of parameters to bind to the statement. + /// + /// - Returns: The statement object (useful for chaining). + public func bind(_ values: [Binding?]) -> Statement { + if values.isEmpty { return self } + reset() + guard values.count == Int(sqlite3_bind_parameter_count(handle)) else { + fatalError("\(sqlite3_bind_parameter_count(handle)) values expected, \(values.count) passed") + } + for idx in 1...values.count { bind(values[idx - 1], atIndex: idx) } + return self + } + + /// Binds a dictionary of named parameters to a statement. + /// + /// - Parameter values: A dictionary of named parameters to bind to the + /// statement. + /// + /// - Returns: The statement object (useful for chaining). + public func bind(_ values: [String: Binding?]) -> Statement { + reset() + for (name, value) in values { + let idx = sqlite3_bind_parameter_index(handle, name) + guard idx > 0 else { + fatalError("parameter not found: \(name)") + } + bind(value, atIndex: Int(idx)) + } + return self + } + + fileprivate func bind(_ value: Binding?, atIndex idx: Int) { + if value == nil { + sqlite3_bind_null(handle, Int32(idx)) + } else if let value = value as? Blob { + sqlite3_bind_blob(handle, Int32(idx), value.bytes, Int32(value.bytes.count), SQLITE_TRANSIENT) + } else if let value = value as? Double { + sqlite3_bind_double(handle, Int32(idx), value) + } else if let value = value as? Int64 { + sqlite3_bind_int64(handle, Int32(idx), value) + } else if let value = value as? String { + sqlite3_bind_text(handle, Int32(idx), value, -1, SQLITE_TRANSIENT) + } else if let value = value as? Int { + self.bind(value.datatypeValue, atIndex: idx) + } else if let value = value as? Bool { + self.bind(value.datatypeValue, atIndex: idx) + } else if let value = value { + fatalError("tried to bind unexpected value \(value)") + } + } + + /// - Parameter bindings: A list of parameters to bind to the statement. + /// + /// - Throws: `Result.Error` if query execution fails. + /// + /// - Returns: The statement object (useful for chaining). + @discardableResult public func run(_ bindings: Binding?...) throws -> Statement { + guard bindings.isEmpty else { + return try run(bindings) + } + + reset(clearBindings: false) + repeat {} while try step() + return self + } + + /// - Parameter bindings: A list of parameters to bind to the statement. + /// + /// - Throws: `Result.Error` if query execution fails. + /// + /// - Returns: The statement object (useful for chaining). + @discardableResult public func run(_ bindings: [Binding?]) throws -> Statement { + return try bind(bindings).run() + } + + /// - Parameter bindings: A dictionary of named parameters to bind to the + /// statement. + /// + /// - Throws: `Result.Error` if query execution fails. + /// + /// - Returns: The statement object (useful for chaining). + @discardableResult public func run(_ bindings: [String: Binding?]) throws -> Statement { + return try bind(bindings).run() + } + + /// - Parameter bindings: A list of parameters to bind to the statement. + /// + /// - Returns: The first value of the first row returned. + public func scalar(_ bindings: Binding?...) throws -> Binding? { + guard bindings.isEmpty else { + return try scalar(bindings) + } + + reset(clearBindings: false) + _ = try step() + return row[0] + } + + /// - Parameter bindings: A list of parameters to bind to the statement. + /// + /// - Returns: The first value of the first row returned. + public func scalar(_ bindings: [Binding?]) throws -> Binding? { + return try bind(bindings).scalar() + } + + + /// - Parameter bindings: A dictionary of named parameters to bind to the + /// statement. + /// + /// - Returns: The first value of the first row returned. + public func scalar(_ bindings: [String: Binding?]) throws -> Binding? { + return try bind(bindings).scalar() + } + + public func step() throws -> Bool { + return try connection.sync { try self.connection.check(sqlite3_step(self.handle)) == SQLITE_ROW } + } + + fileprivate func reset(clearBindings shouldClear: Bool = true) { + sqlite3_reset(handle) + if (shouldClear) { sqlite3_clear_bindings(handle) } + } + +} + +extension Statement : Sequence { + + public func makeIterator() -> Statement { + reset(clearBindings: false) + return self + } + +} + +extension Statement : IteratorProtocol { + + public func next() -> [Binding?]? { + return try! step() ? Array(row) : nil + } + +} + +extension Statement : CustomStringConvertible { + + public var description: String { + return String(cString: sqlite3_sql(handle)) + } + +} + +public struct Cursor { + + fileprivate let handle: OpaquePointer + + fileprivate let columnCount: Int + + fileprivate init(_ statement: Statement) { + handle = statement.handle! + columnCount = statement.columnCount + } + + public subscript(idx: Int) -> Double { + return sqlite3_column_double(handle, Int32(idx)) + } + + public subscript(idx: Int) -> Int64 { + return sqlite3_column_int64(handle, Int32(idx)) + } + + public subscript(idx: Int) -> String { + return String(cString: UnsafePointer(sqlite3_column_text(handle, Int32(idx)))) + } + + public subscript(idx: Int) -> Blob { + if let pointer = sqlite3_column_blob(handle, Int32(idx)) { + let length = Int(sqlite3_column_bytes(handle, Int32(idx))) + return Blob(bytes: pointer, length: length) + } else { + // The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. + // https://www.sqlite.org/c3ref/column_blob.html + return Blob(bytes: []) + } + } + + // MARK: - + + public subscript(idx: Int) -> Bool { + return Bool.fromDatatypeValue(self[idx]) + } + + public subscript(idx: Int) -> Int { + return Int.fromDatatypeValue(self[idx]) + } + +} + +/// Cursors provide direct access to a statement’s current row. +extension Cursor : Sequence { + + public subscript(idx: Int) -> Binding? { + switch sqlite3_column_type(handle, Int32(idx)) { + case SQLITE_BLOB: + return self[idx] as Blob + case SQLITE_FLOAT: + return self[idx] as Double + case SQLITE_INTEGER: + return self[idx] as Int64 + case SQLITE_NULL: + return nil + case SQLITE_TEXT: + return self[idx] as String + case let type: + fatalError("unsupported column type: \(type)") + } + } + + public func makeIterator() -> AnyIterator { + var idx = 0 + return AnyIterator { + if idx >= self.columnCount { + return Optional.none + } else { + idx += 1 + return self[idx - 1] + } + } + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Value.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Value.swift new file mode 100644 index 0000000000..608f0ce6fe --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Value.swift @@ -0,0 +1,132 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +/// - Warning: `Binding` is a protocol that SQLite.swift uses internally to +/// directly map SQLite types to Swift types. +/// +/// Do not conform custom types to the Binding protocol. See the `Value` +/// protocol, instead. +public protocol Binding {} + +public protocol Number : Binding {} + +public protocol Value : Expressible { // extensions cannot have inheritance clauses + + associatedtype ValueType = Self + + associatedtype Datatype : Binding + + static var declaredDatatype: String { get } + + static func fromDatatypeValue(_ datatypeValue: Datatype) -> ValueType + + var datatypeValue: Datatype { get } + +} + +extension Double : Number, Value { + + public static let declaredDatatype = "REAL" + + public static func fromDatatypeValue(_ datatypeValue: Double) -> Double { + return datatypeValue + } + + public var datatypeValue: Double { + return self + } + +} + +extension Int64 : Number, Value { + + public static let declaredDatatype = "INTEGER" + + public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int64 { + return datatypeValue + } + + public var datatypeValue: Int64 { + return self + } + +} + +extension String : Binding, Value { + + public static let declaredDatatype = "TEXT" + + public static func fromDatatypeValue(_ datatypeValue: String) -> String { + return datatypeValue + } + + public var datatypeValue: String { + return self + } + +} + +extension Blob : Binding, Value { + + public static let declaredDatatype = "BLOB" + + public static func fromDatatypeValue(_ datatypeValue: Blob) -> Blob { + return datatypeValue + } + + public var datatypeValue: Blob { + return self + } + +} + +// MARK: - + +extension Bool : Binding, Value { + + public static var declaredDatatype = Int64.declaredDatatype + + public static func fromDatatypeValue(_ datatypeValue: Int64) -> Bool { + return datatypeValue != 0 + } + + public var datatypeValue: Int64 { + return self ? 1 : 0 + } + +} + +extension Int : Number, Value { + + public static var declaredDatatype = Int64.declaredDatatype + + public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int { + return Int(datatypeValue) + } + + public var datatypeValue: Int64 { + return Int64(self) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/Cipher.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/Cipher.swift new file mode 100644 index 0000000000..6c0d465781 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/Cipher.swift @@ -0,0 +1,61 @@ +#if SQLITE_SWIFT_SQLCIPHER +import SQLCipher + + +/// Extension methods for [SQLCipher](https://www.zetetic.net/sqlcipher/). +/// @see [sqlcipher api](https://www.zetetic.net/sqlcipher/sqlcipher-api/) +extension Connection { + + /// Specify the key for an encrypted database. This routine should be + /// called right after sqlite3_open(). + /// + /// @param key The key to use.The key itself can be a passphrase, which is converted to a key + /// using [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) key derivation. The result + /// is used as the encryption key for the database. + /// + /// Alternatively, it is possible to specify an exact byte sequence using a blob literal. + /// With this method, it is the calling application's responsibility to ensure that the data + /// provided is a 64 character hex string, which will be converted directly to 32 bytes (256 bits) + /// of key data. + /// e.g. x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99' + /// @param db name of the database, defaults to 'main' + public func key(_ key: String, db: String = "main") throws { + try _key_v2(db: db, keyPointer: key, keySize: key.utf8.count) + } + + public func key(_ key: Blob, db: String = "main") throws { + try _key_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count) + } + + + /// Change the key on an open database. If the current database is not encrypted, this routine + /// will encrypt it. + /// To change the key on an existing encrypted database, it must first be unlocked with the + /// current encryption key. Once the database is readable and writeable, rekey can be used + /// to re-encrypt every page in the database with a new key. + public func rekey(_ key: String, db: String = "main") throws { + try _rekey_v2(db: db, keyPointer: key, keySize: key.utf8.count) + } + + public func rekey(_ key: Blob, db: String = "main") throws { + try _rekey_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count) + } + + // MARK: - private + private func _key_v2(db: String, keyPointer: UnsafePointer, keySize: Int) throws { + try check(sqlite3_key_v2(handle, db, keyPointer, Int32(keySize))) + try cipher_key_check() + } + + private func _rekey_v2(db: String, keyPointer: UnsafePointer, keySize: Int) throws { + try check(sqlite3_rekey_v2(handle, db, keyPointer, Int32(keySize))) + } + + // When opening an existing database, sqlite3_key_v2 will not immediately throw an error if + // the key provided is incorrect. To test that the database can be successfully opened with the + // provided key, it is necessary to perform some operation on the database (i.e. read from it). + private func cipher_key_check() throws { + try scalar("SELECT count(*) FROM sqlite_master;") + } +} +#endif diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS4.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS4.swift new file mode 100644 index 0000000000..152a29219e --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS4.swift @@ -0,0 +1,346 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#if SWIFT_PACKAGE +import SQLiteObjc +#endif + +extension Module { + + public static func FTS4(_ column: Expressible, _ more: Expressible...) -> Module { + return FTS4([column] + more) + } + + public static func FTS4(_ columns: [Expressible] = [], tokenize tokenizer: Tokenizer? = nil) -> Module { + return FTS4(FTS4Config().columns(columns).tokenizer(tokenizer)) + } + + public static func FTS4(_ config: FTS4Config) -> Module { + return Module(name: "fts4", arguments: config.arguments()) + } +} + +extension VirtualTable { + + /// Builds an expression appended with a `MATCH` query against the given + /// pattern. + /// + /// let emails = VirtualTable("emails") + /// + /// emails.filter(emails.match("Hello")) + /// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello' + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: An expression appended with a `MATCH` query against the given + /// pattern. + public func match(_ pattern: String) -> Expression { + return "MATCH".infix(tableName(), pattern) + } + + public func match(_ pattern: Expression) -> Expression { + return "MATCH".infix(tableName(), pattern) + } + + public func match(_ pattern: Expression) -> Expression { + return "MATCH".infix(tableName(), pattern) + } + + /// Builds a copy of the query with a `WHERE … MATCH` clause. + /// + /// let emails = VirtualTable("emails") + /// + /// emails.match("Hello") + /// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello' + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A query with the given `WHERE … MATCH` clause applied. + public func match(_ pattern: String) -> QueryType { + return filter(match(pattern)) + } + + public func match(_ pattern: Expression) -> QueryType { + return filter(match(pattern)) + } + + public func match(_ pattern: Expression) -> QueryType { + return filter(match(pattern)) + } + +} + +public struct Tokenizer { + + public static let Simple = Tokenizer("simple") + + public static let Porter = Tokenizer("porter") + + public static func Unicode61(removeDiacritics: Bool? = nil, tokenchars: Set = [], separators: Set = []) -> Tokenizer { + var arguments = [String]() + + if let removeDiacritics = removeDiacritics { + arguments.append("removeDiacritics=\(removeDiacritics ? 1 : 0)".quote()) + } + + if !tokenchars.isEmpty { + let joined = tokenchars.map { String($0) }.joined(separator: "") + arguments.append("tokenchars=\(joined)".quote()) + } + + if !separators.isEmpty { + let joined = separators.map { String($0) }.joined(separator: "") + arguments.append("separators=\(joined)".quote()) + } + + return Tokenizer("unicode61", arguments) + } + + public static func Custom(_ name: String) -> Tokenizer { + return Tokenizer(Tokenizer.moduleName.quote(), [name.quote()]) + } + + public let name: String + + public let arguments: [String] + + fileprivate init(_ name: String, _ arguments: [String] = []) { + self.name = name + self.arguments = arguments + } + + fileprivate static let moduleName = "SQLite.swift" + +} + +extension Tokenizer : CustomStringConvertible { + + public var description: String { + return ([name] + arguments).joined(separator: " ") + } + +} + +extension Connection { + + public func registerTokenizer(_ submoduleName: String, next: @escaping (String) -> (String, Range)?) throws { + try check(_SQLiteRegisterTokenizer(handle, Tokenizer.moduleName, submoduleName) { input, offset, length in + let string = String(cString: input) + + guard let (token, range) = next(string) else { return nil } + + let view = string.utf8 + offset.pointee += string.substring(to: range.lowerBound).utf8.count + length.pointee = Int32(view.distance(from: range.lowerBound.samePosition(in: view), to: range.upperBound.samePosition(in: view))) + return token + }) + } + +} + +/// Configuration options shared between the [FTS4](https://www.sqlite.org/fts3.html) and +/// [FTS5](https://www.sqlite.org/fts5.html) extensions. +open class FTSConfig { + public enum ColumnOption { + /// [The notindexed= option](https://www.sqlite.org/fts3.html#section_6_5) + case unindexed + } + + typealias ColumnDefinition = (Expressible, options: [ColumnOption]) + var columnDefinitions = [ColumnDefinition]() + var tokenizer: Tokenizer? + var prefixes = [Int]() + var externalContentSchema: SchemaType? + var isContentless: Bool = false + + /// Adds a column definition + @discardableResult open func column(_ column: Expressible, _ options: [ColumnOption] = []) -> Self { + self.columnDefinitions.append((column, options)) + return self + } + + @discardableResult open func columns(_ columns: [Expressible]) -> Self { + for column in columns { + self.column(column) + } + return self + } + + /// [Tokenizers](https://www.sqlite.org/fts3.html#tokenizer) + open func tokenizer(_ tokenizer: Tokenizer?) -> Self { + self.tokenizer = tokenizer + return self + } + + /// [The prefix= option](https://www.sqlite.org/fts3.html#section_6_6) + open func prefix(_ prefix: [Int]) -> Self { + self.prefixes += prefix + return self + } + + /// [The content= option](https://www.sqlite.org/fts3.html#section_6_2) + open func externalContent(_ schema: SchemaType) -> Self { + self.externalContentSchema = schema + return self + } + + /// [Contentless FTS4 Tables](https://www.sqlite.org/fts3.html#section_6_2_1) + open func contentless() -> Self { + self.isContentless = true + return self + } + + func formatColumnDefinitions() -> [Expressible] { + return columnDefinitions.map { $0.0 } + } + + func arguments() -> [Expressible] { + return options().arguments + } + + func options() -> Options { + var options = Options() + options.append(formatColumnDefinitions()) + if let tokenizer = tokenizer { + options.append("tokenize", value: Expression(literal: tokenizer.description)) + } + options.appendCommaSeparated("prefix", values:prefixes.sorted().map { String($0) }) + if isContentless { + options.append("content", value: "") + } else if let externalContentSchema = externalContentSchema { + options.append("content", value: externalContentSchema.tableName()) + } + return options + } + + struct Options { + var arguments = [Expressible]() + + @discardableResult mutating func append(_ columns: [Expressible]) -> Options { + arguments.append(contentsOf: columns) + return self + } + + @discardableResult mutating func appendCommaSeparated(_ key: String, values: [String]) -> Options { + if values.isEmpty { + return self + } else { + return append(key, value: values.joined(separator: ",")) + } + } + + @discardableResult mutating func append(_ key: String, value: CustomStringConvertible?) -> Options { + return append(key, value: value?.description) + } + + @discardableResult mutating func append(_ key: String, value: String?) -> Options { + return append(key, value: value.map { Expression($0) }) + } + + @discardableResult mutating func append(_ key: String, value: Expressible?) -> Options { + if let value = value { + arguments.append("=".join([Expression(literal: key), value])) + } + return self + } + } +} + +/// Configuration for the [FTS4](https://www.sqlite.org/fts3.html) extension. +open class FTS4Config : FTSConfig { + /// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4) + public enum MatchInfo : CustomStringConvertible { + case fts3 + public var description: String { + return "fts3" + } + } + + /// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options) + public enum Order : CustomStringConvertible { + /// Data structures are optimized for returning results in ascending order by docid (default) + case asc + /// FTS4 stores its data in such a way as to optimize returning results in descending order by docid. + case desc + + public var description: String { + switch self { + case .asc: return "asc" + case .desc: return "desc" + } + } + } + + var compressFunction: String? + var uncompressFunction: String? + var languageId: String? + var matchInfo: MatchInfo? + var order: Order? + + override public init() { + } + + /// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1) + open func compress(_ functionName: String) -> Self { + self.compressFunction = functionName + return self + } + + /// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1) + open func uncompress(_ functionName: String) -> Self { + self.uncompressFunction = functionName + return self + } + + /// [The languageid= option](https://www.sqlite.org/fts3.html#section_6_3) + open func languageId(_ columnName: String) -> Self { + self.languageId = columnName + return self + } + + /// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4) + open func matchInfo(_ matchInfo: MatchInfo) -> Self { + self.matchInfo = matchInfo + return self + } + + /// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options) + open func order(_ order: Order) -> Self { + self.order = order + return self + } + + override func options() -> Options { + var options = super.options() + for (column, _) in (columnDefinitions.filter { $0.options.contains(.unindexed) }) { + options.append("notindexed", value: column) + } + options.append("languageid", value: languageId) + options.append("compress", value: compressFunction) + options.append("uncompress", value: uncompressFunction) + options.append("matchinfo", value: matchInfo) + options.append("order", value: order) + return options + } +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS5.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS5.swift new file mode 100644 index 0000000000..763927ff48 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS5.swift @@ -0,0 +1,97 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +extension Module { + public static func FTS5(_ config: FTS5Config) -> Module { + return Module(name: "fts5", arguments: config.arguments()) + } +} + +/// Configuration for the [FTS5](https://www.sqlite.org/fts5.html) extension. +/// +/// **Note:** this is currently only applicable when using SQLite.swift together with a FTS5-enabled version +/// of SQLite. +open class FTS5Config : FTSConfig { + public enum Detail : CustomStringConvertible { + /// store rowid, column number, term offset + case full + /// store rowid, column number + case column + /// store rowid + case none + + public var description: String { + switch self { + case .full: return "full" + case .column: return "column" + case .none: return "none" + } + } + } + + var detail: Detail? + var contentRowId: Expressible? + var columnSize: Int? + + override public init() { + } + + /// [External Content Tables](https://www.sqlite.org/fts5.html#section_4_4_2) + open func contentRowId(_ column: Expressible) -> Self { + self.contentRowId = column + return self + } + + /// [The Columnsize Option](https://www.sqlite.org/fts5.html#section_4_5) + open func columnSize(_ size: Int) -> Self { + self.columnSize = size + return self + } + + /// [The Detail Option](https://www.sqlite.org/fts5.html#section_4_6) + open func detail(_ detail: Detail) -> Self { + self.detail = detail + return self + } + + override func options() -> Options { + var options = super.options() + options.append("content_rowid", value: contentRowId) + if let columnSize = columnSize { + options.append("columnsize", value: Expression(value: columnSize)) + } + options.append("detail", value: detail) + return options + } + + override func formatColumnDefinitions() -> [Expressible] { + return columnDefinitions.map { definition in + if definition.options.contains(.unindexed) { + return " ".join([definition.0, Expression(literal: "UNINDEXED")]) + } else { + return definition.0 + } + } + } +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/RTree.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/RTree.swift new file mode 100644 index 0000000000..4fc1a23539 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/RTree.swift @@ -0,0 +1,37 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +extension Module { + + public static func RTree(_ primaryKey: Expression, _ pairs: (Expression, Expression)...) -> Module where T.Datatype == Int64, U.Datatype == Double { + var arguments: [Expressible] = [primaryKey] + + for pair in pairs { + arguments.append(contentsOf: [pair.0, pair.1] as [Expressible]) + } + + return Module(name: "rtree", arguments: arguments) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Foundation.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Foundation.swift new file mode 100644 index 0000000000..5e102297b9 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Foundation.swift @@ -0,0 +1,108 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +extension Data : Value { + + public static var declaredDatatype: String { + return Blob.declaredDatatype + } + + public static func fromDatatypeValue(_ dataValue: Blob) -> Data { + return Data(bytes: dataValue.bytes) + } + + public var datatypeValue: Blob { + return withUnsafeBytes { (pointer: UnsafePointer) -> Blob in + return Blob(bytes: pointer, length: count) + } + } + +} + +extension Date : Value { + + public static var declaredDatatype: String { + return String.declaredDatatype + } + + public static func fromDatatypeValue(_ stringValue: String) -> Date { + return dateFormatter.date(from: stringValue)! + } + + public var datatypeValue: String { + return dateFormatter.string(from: self) + } + +} + +/// A global date formatter used to serialize and deserialize `NSDate` objects. +/// If multiple date formats are used in an application’s database(s), use a +/// custom `Value` type per additional format. +public var dateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS" + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter +}() + +// FIXME: rdar://problem/18673897 // subscript… + +extension QueryType { + + public subscript(column: Expression) -> Expression { + return namespace(column) + } + public subscript(column: Expression) -> Expression { + return namespace(column) + } + + public subscript(column: Expression) -> Expression { + return namespace(column) + } + public subscript(column: Expression) -> Expression { + return namespace(column) + } + +} + +extension Row { + + public subscript(column: Expression) -> Data { + return get(column) + } + public subscript(column: Expression) -> Data? { + return get(column) + } + + public subscript(column: Expression) -> Date { + return get(column) + } + public subscript(column: Expression) -> Date? { + return get(column) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Helpers.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Helpers.swift new file mode 100644 index 0000000000..27904793a2 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Helpers.swift @@ -0,0 +1,130 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#if SQLITE_SWIFT_STANDALONE +import sqlite3 +#elseif SQLITE_SWIFT_SQLCIPHER +import SQLCipher +#else +import SQLite3 +#endif + +public typealias Star = (Expression?, Expression?) -> Expression + +public func *(_: Expression?, _: Expression?) -> Expression { + return Expression(literal: "*") +} + +public protocol _OptionalType { + + associatedtype WrappedType + +} + +extension Optional : _OptionalType { + + public typealias WrappedType = Wrapped + +} + +// let SQLITE_STATIC = unsafeBitCast(0, sqlite3_destructor_type.self) +let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self) + +extension String { + + func quote(_ mark: Character = "\"") -> String { + let escaped = characters.reduce("") { string, character in + string + (character == mark ? "\(mark)\(mark)" : "\(character)") + } + return "\(mark)\(escaped)\(mark)" + } + + func join(_ expressions: [Expressible]) -> Expressible { + var (template, bindings) = ([String](), [Binding?]()) + for expressible in expressions { + let expression = expressible.expression + template.append(expression.template) + bindings.append(contentsOf: expression.bindings) + } + return Expression(template.joined(separator: self), bindings) + } + + func infix(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression { + let expression = Expression(" \(self) ".join([lhs, rhs]).expression) + guard wrap else { + return expression + } + return "".wrap(expression) + } + + func prefix(_ expressions: Expressible) -> Expressible { + return "\(self) ".wrap(expressions) as Expression + } + + func prefix(_ expressions: [Expressible]) -> Expressible { + return "\(self) ".wrap(expressions) as Expression + } + + func wrap(_ expression: Expressible) -> Expression { + return Expression("\(self)(\(expression.expression.template))", expression.expression.bindings) + } + + func wrap(_ expressions: [Expressible]) -> Expression { + return wrap(", ".join(expressions)) + } + +} + +func infix(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true, function: String = #function) -> Expression { + return function.infix(lhs, rhs, wrap: wrap) +} + +func wrap(_ expression: Expressible, function: String = #function) -> Expression { + return function.wrap(expression) +} + +func wrap(_ expressions: [Expressible], function: String = #function) -> Expression { + return function.wrap(", ".join(expressions)) +} + +func transcode(_ literal: Binding?) -> String { + guard let literal = literal else { return "NULL" } + + switch literal { + case let blob as Blob: + return blob.description + case let string as String: + return string.quote("'") + case let binding: + return "\(binding)" + } +} + +func value(_ v: Binding) -> A { + return A.fromDatatypeValue(v as! A.Datatype) as! A +} + +func value(_ v: Binding?) -> A { + return value(v!) +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Info.plist b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Info.plist new file mode 100644 index 0000000000..588139c437 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.11.2 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/SQLite.h b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/SQLite.h new file mode 100644 index 0000000000..693ce323cf --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/SQLite.h @@ -0,0 +1,6 @@ +@import Foundation; + +FOUNDATION_EXPORT double SQLiteVersionNumber; +FOUNDATION_EXPORT const unsigned char SQLiteVersionString[]; + +#import diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/AggregateFunctions.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/AggregateFunctions.swift new file mode 100644 index 0000000000..249bbe60cd --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/AggregateFunctions.swift @@ -0,0 +1,251 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +extension ExpressionType where UnderlyingType : Value { + + /// Builds a copy of the expression prefixed with the `DISTINCT` keyword. + /// + /// let name = Expression("name") + /// name.distinct + /// // DISTINCT "name" + /// + /// - Returns: A copy of the expression prefixed with the `DISTINCT` + /// keyword. + public var distinct: Expression { + return Expression("DISTINCT \(template)", bindings) + } + + /// Builds a copy of the expression wrapped with the `count` aggregate + /// function. + /// + /// let name = Expression("name") + /// name.count + /// // count("name") + /// name.distinct.count + /// // count(DISTINCT "name") + /// + /// - Returns: A copy of the expression wrapped with the `count` aggregate + /// function. + public var count: Expression { + return wrap(self) + } + +} + +extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value { + + /// Builds a copy of the expression prefixed with the `DISTINCT` keyword. + /// + /// let name = Expression("name") + /// name.distinct + /// // DISTINCT "name" + /// + /// - Returns: A copy of the expression prefixed with the `DISTINCT` + /// keyword. + public var distinct: Expression { + return Expression("DISTINCT \(template)", bindings) + } + + /// Builds a copy of the expression wrapped with the `count` aggregate + /// function. + /// + /// let name = Expression("name") + /// name.count + /// // count("name") + /// name.distinct.count + /// // count(DISTINCT "name") + /// + /// - Returns: A copy of the expression wrapped with the `count` aggregate + /// function. + public var count: Expression { + return wrap(self) + } + +} + +extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Comparable { + + /// Builds a copy of the expression wrapped with the `max` aggregate + /// function. + /// + /// let age = Expression("age") + /// age.max + /// // max("age") + /// + /// - Returns: A copy of the expression wrapped with the `max` aggregate + /// function. + public var max: Expression { + return wrap(self) + } + + /// Builds a copy of the expression wrapped with the `min` aggregate + /// function. + /// + /// let age = Expression("age") + /// age.min + /// // min("age") + /// + /// - Returns: A copy of the expression wrapped with the `min` aggregate + /// function. + public var min: Expression { + return wrap(self) + } + +} + +extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Comparable { + + /// Builds a copy of the expression wrapped with the `max` aggregate + /// function. + /// + /// let age = Expression("age") + /// age.max + /// // max("age") + /// + /// - Returns: A copy of the expression wrapped with the `max` aggregate + /// function. + public var max: Expression { + return wrap(self) + } + + /// Builds a copy of the expression wrapped with the `min` aggregate + /// function. + /// + /// let age = Expression("age") + /// age.min + /// // min("age") + /// + /// - Returns: A copy of the expression wrapped with the `min` aggregate + /// function. + public var min: Expression { + return wrap(self) + } + +} + +extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Number { + + /// Builds a copy of the expression wrapped with the `avg` aggregate + /// function. + /// + /// let salary = Expression("salary") + /// salary.average + /// // avg("salary") + /// + /// - Returns: A copy of the expression wrapped with the `min` aggregate + /// function. + public var average: Expression { + return "avg".wrap(self) + } + + /// Builds a copy of the expression wrapped with the `sum` aggregate + /// function. + /// + /// let salary = Expression("salary") + /// salary.sum + /// // sum("salary") + /// + /// - Returns: A copy of the expression wrapped with the `min` aggregate + /// function. + public var sum: Expression { + return wrap(self) + } + + /// Builds a copy of the expression wrapped with the `total` aggregate + /// function. + /// + /// let salary = Expression("salary") + /// salary.total + /// // total("salary") + /// + /// - Returns: A copy of the expression wrapped with the `min` aggregate + /// function. + public var total: Expression { + return wrap(self) + } + +} + +extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Number { + + /// Builds a copy of the expression wrapped with the `avg` aggregate + /// function. + /// + /// let salary = Expression("salary") + /// salary.average + /// // avg("salary") + /// + /// - Returns: A copy of the expression wrapped with the `min` aggregate + /// function. + public var average: Expression { + return "avg".wrap(self) + } + + /// Builds a copy of the expression wrapped with the `sum` aggregate + /// function. + /// + /// let salary = Expression("salary") + /// salary.sum + /// // sum("salary") + /// + /// - Returns: A copy of the expression wrapped with the `min` aggregate + /// function. + public var sum: Expression { + return wrap(self) + } + + /// Builds a copy of the expression wrapped with the `total` aggregate + /// function. + /// + /// let salary = Expression("salary") + /// salary.total + /// // total("salary") + /// + /// - Returns: A copy of the expression wrapped with the `min` aggregate + /// function. + public var total: Expression { + return wrap(self) + } + +} + +extension ExpressionType where UnderlyingType == Int { + + static func count(_ star: Star) -> Expression { + return wrap(star(nil, nil)) + } + +} + +/// Builds an expression representing `count(*)` (when called with the `*` +/// function literal). +/// +/// count(*) +/// // count(*) +/// +/// - Returns: An expression returning `count(*)` (when called with the `*` +/// function literal). +public func count(_ star: Star) -> Expression { + return Expression.count(star) +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Collation.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Collation.swift new file mode 100644 index 0000000000..e2ff9d1006 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Collation.swift @@ -0,0 +1,69 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +/// A collating function used to compare to strings. +/// +/// - SeeAlso: +public enum Collation { + + /// Compares string by raw data. + case binary + + /// Like binary, but folds uppercase ASCII letters into their lowercase + /// equivalents. + case nocase + + /// Like binary, but strips trailing space. + case rtrim + + /// A custom collating sequence identified by the given string, registered + /// using `Database.create(collation:…)` + case custom(String) + +} + +extension Collation : Expressible { + + public var expression: Expression { + return Expression(literal: description) + } + +} + +extension Collation : CustomStringConvertible { + + public var description : String { + switch self { + case .binary: + return "BINARY" + case .nocase: + return "NOCASE" + case .rtrim: + return "RTRIM" + case .custom(let collation): + return collation.quote() + } + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CoreFunctions.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CoreFunctions.swift new file mode 100644 index 0000000000..9d17a326bc --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CoreFunctions.swift @@ -0,0 +1,683 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation.NSData + + +extension ExpressionType where UnderlyingType : Number { + + /// Builds a copy of the expression wrapped with the `abs` function. + /// + /// let x = Expression("x") + /// x.absoluteValue + /// // abs("x") + /// + /// - Returns: A copy of the expression wrapped with the `abs` function. + public var absoluteValue : Expression { + return "abs".wrap(self) + } + +} + +extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Number { + + /// Builds a copy of the expression wrapped with the `abs` function. + /// + /// let x = Expression("x") + /// x.absoluteValue + /// // abs("x") + /// + /// - Returns: A copy of the expression wrapped with the `abs` function. + public var absoluteValue : Expression { + return "abs".wrap(self) + } + +} + +extension ExpressionType where UnderlyingType == Double { + + /// Builds a copy of the expression wrapped with the `round` function. + /// + /// let salary = Expression("salary") + /// salary.round() + /// // round("salary") + /// salary.round(2) + /// // round("salary", 2) + /// + /// - Returns: A copy of the expression wrapped with the `round` function. + public func round(_ precision: Int? = nil) -> Expression { + guard let precision = precision else { + return wrap([self]) + } + return wrap([self, Int(precision)]) + } + +} + +extension ExpressionType where UnderlyingType == Double? { + + /// Builds a copy of the expression wrapped with the `round` function. + /// + /// let salary = Expression("salary") + /// salary.round() + /// // round("salary") + /// salary.round(2) + /// // round("salary", 2) + /// + /// - Returns: A copy of the expression wrapped with the `round` function. + public func round(_ precision: Int? = nil) -> Expression { + guard let precision = precision else { + return wrap(self) + } + return wrap([self, Int(precision)]) + } + +} + +extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype == Int64 { + + /// Builds an expression representing the `random` function. + /// + /// Expression.random() + /// // random() + /// + /// - Returns: An expression calling the `random` function. + public static func random() -> Expression { + return "random".wrap([]) + } + +} + +extension ExpressionType where UnderlyingType == Data { + + /// Builds an expression representing the `randomblob` function. + /// + /// Expression.random(16) + /// // randomblob(16) + /// + /// - Parameter length: Length in bytes. + /// + /// - Returns: An expression calling the `randomblob` function. + public static func random(_ length: Int) -> Expression { + return "randomblob".wrap([]) + } + + /// Builds an expression representing the `zeroblob` function. + /// + /// Expression.allZeros(16) + /// // zeroblob(16) + /// + /// - Parameter length: Length in bytes. + /// + /// - Returns: An expression calling the `zeroblob` function. + public static func allZeros(_ length: Int) -> Expression { + return "zeroblob".wrap([]) + } + + /// Builds a copy of the expression wrapped with the `length` function. + /// + /// let data = Expression("data") + /// data.length + /// // length("data") + /// + /// - Returns: A copy of the expression wrapped with the `length` function. + public var length: Expression { + return wrap(self) + } + +} + +extension ExpressionType where UnderlyingType == Data? { + + /// Builds a copy of the expression wrapped with the `length` function. + /// + /// let data = Expression("data") + /// data.length + /// // length("data") + /// + /// - Returns: A copy of the expression wrapped with the `length` function. + public var length: Expression { + return wrap(self) + } + +} + +extension ExpressionType where UnderlyingType == String { + + /// Builds a copy of the expression wrapped with the `length` function. + /// + /// let name = Expression("name") + /// name.length + /// // length("name") + /// + /// - Returns: A copy of the expression wrapped with the `length` function. + public var length: Expression { + return wrap(self) + } + + /// Builds a copy of the expression wrapped with the `lower` function. + /// + /// let name = Expression("name") + /// name.lowercaseString + /// // lower("name") + /// + /// - Returns: A copy of the expression wrapped with the `lower` function. + public var lowercaseString: Expression { + return "lower".wrap(self) + } + + /// Builds a copy of the expression wrapped with the `upper` function. + /// + /// let name = Expression("name") + /// name.uppercaseString + /// // lower("name") + /// + /// - Returns: A copy of the expression wrapped with the `upper` function. + public var uppercaseString: Expression { + return "upper".wrap(self) + } + + /// Builds a copy of the expression appended with a `LIKE` query against the + /// given pattern. + /// + /// let email = Expression("email") + /// email.like("%@example.com") + /// // "email" LIKE '%@example.com' + /// email.like("99\\%@%", escape: "\\") + /// // "email" LIKE '99\%@%' ESCAPE '\' + /// + /// - Parameters: + /// + /// - pattern: A pattern to match. + /// + /// - escape: An (optional) character designated for escaping + /// pattern-matching characters (*i.e.*, the `%` and `_` characters). + /// + /// - Returns: A copy of the expression appended with a `LIKE` query against + /// the given pattern. + public func like(_ pattern: String, escape character: Character? = nil) -> Expression { + guard let character = character else { + return "LIKE".infix(self, pattern) + } + return Expression("(\(template) LIKE ? ESCAPE ?)", bindings + [pattern, String(character)]) + } + + /// Builds a copy of the expression appended with a `GLOB` query against the + /// given pattern. + /// + /// let path = Expression("path") + /// path.glob("*.png") + /// // "path" GLOB '*.png' + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A copy of the expression appended with a `GLOB` query against + /// the given pattern. + public func glob(_ pattern: String) -> Expression { + return "GLOB".infix(self, pattern) + } + + /// Builds a copy of the expression appended with a `MATCH` query against + /// the given pattern. + /// + /// let title = Expression("title") + /// title.match("swift AND programming") + /// // "title" MATCH 'swift AND programming' + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A copy of the expression appended with a `MATCH` query + /// against the given pattern. + public func match(_ pattern: String) -> Expression { + return "MATCH".infix(self, pattern) + } + + /// Builds a copy of the expression appended with a `REGEXP` query against + /// the given pattern. + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A copy of the expression appended with a `REGEXP` query + /// against the given pattern. + public func regexp(_ pattern: String) -> Expression { + return "REGEXP".infix(self, pattern) + } + + /// Builds a copy of the expression appended with a `COLLATE` clause with + /// the given sequence. + /// + /// let name = Expression("name") + /// name.collate(.Nocase) + /// // "name" COLLATE NOCASE + /// + /// - Parameter collation: A collating sequence. + /// + /// - Returns: A copy of the expression appended with a `COLLATE` clause + /// with the given sequence. + public func collate(_ collation: Collation) -> Expression { + return "COLLATE".infix(self, collation) + } + + /// Builds a copy of the expression wrapped with the `ltrim` function. + /// + /// let name = Expression("name") + /// name.ltrim() + /// // ltrim("name") + /// name.ltrim([" ", "\t"]) + /// // ltrim("name", ' \t') + /// + /// - Parameter characters: A set of characters to trim. + /// + /// - Returns: A copy of the expression wrapped with the `ltrim` function. + public func ltrim(_ characters: Set? = nil) -> Expression { + guard let characters = characters else { + return wrap(self) + } + return wrap([self, String(characters)]) + } + + /// Builds a copy of the expression wrapped with the `rtrim` function. + /// + /// let name = Expression("name") + /// name.rtrim() + /// // rtrim("name") + /// name.rtrim([" ", "\t"]) + /// // rtrim("name", ' \t') + /// + /// - Parameter characters: A set of characters to trim. + /// + /// - Returns: A copy of the expression wrapped with the `rtrim` function. + public func rtrim(_ characters: Set? = nil) -> Expression { + guard let characters = characters else { + return wrap(self) + } + return wrap([self, String(characters)]) + } + + /// Builds a copy of the expression wrapped with the `trim` function. + /// + /// let name = Expression("name") + /// name.trim() + /// // trim("name") + /// name.trim([" ", "\t"]) + /// // trim("name", ' \t') + /// + /// - Parameter characters: A set of characters to trim. + /// + /// - Returns: A copy of the expression wrapped with the `trim` function. + public func trim(_ characters: Set? = nil) -> Expression { + guard let characters = characters else { + return wrap([self]) + } + return wrap([self, String(characters)]) + } + + /// Builds a copy of the expression wrapped with the `replace` function. + /// + /// let email = Expression("email") + /// email.replace("@mac.com", with: "@icloud.com") + /// // replace("email", '@mac.com', '@icloud.com') + /// + /// - Parameters: + /// + /// - pattern: A pattern to match. + /// + /// - replacement: The replacement string. + /// + /// - Returns: A copy of the expression wrapped with the `replace` function. + public func replace(_ pattern: String, with replacement: String) -> Expression { + return "replace".wrap([self, pattern, replacement]) + } + + public func substring(_ location: Int, length: Int? = nil) -> Expression { + guard let length = length else { + return "substr".wrap([self, location]) + } + return "substr".wrap([self, location, length]) + } + + public subscript(range: Range) -> Expression { + return substring(range.lowerBound, length: range.upperBound - range.lowerBound) + } + +} + +extension ExpressionType where UnderlyingType == String? { + + /// Builds a copy of the expression wrapped with the `length` function. + /// + /// let name = Expression("name") + /// name.length + /// // length("name") + /// + /// - Returns: A copy of the expression wrapped with the `length` function. + public var length: Expression { + return wrap(self) + } + + /// Builds a copy of the expression wrapped with the `lower` function. + /// + /// let name = Expression("name") + /// name.lowercaseString + /// // lower("name") + /// + /// - Returns: A copy of the expression wrapped with the `lower` function. + public var lowercaseString: Expression { + return "lower".wrap(self) + } + + /// Builds a copy of the expression wrapped with the `upper` function. + /// + /// let name = Expression("name") + /// name.uppercaseString + /// // lower("name") + /// + /// - Returns: A copy of the expression wrapped with the `upper` function. + public var uppercaseString: Expression { + return "upper".wrap(self) + } + + /// Builds a copy of the expression appended with a `LIKE` query against the + /// given pattern. + /// + /// let email = Expression("email") + /// email.like("%@example.com") + /// // "email" LIKE '%@example.com' + /// email.like("99\\%@%", escape: "\\") + /// // "email" LIKE '99\%@%' ESCAPE '\' + /// + /// - Parameters: + /// + /// - pattern: A pattern to match. + /// + /// - escape: An (optional) character designated for escaping + /// pattern-matching characters (*i.e.*, the `%` and `_` characters). + /// + /// - Returns: A copy of the expression appended with a `LIKE` query against + /// the given pattern. + public func like(_ pattern: String, escape character: Character? = nil) -> Expression { + guard let character = character else { + return "LIKE".infix(self, pattern) + } + return Expression("(\(template) LIKE ? ESCAPE ?)", bindings + [pattern, String(character)]) + } + + /// Builds a copy of the expression appended with a `GLOB` query against the + /// given pattern. + /// + /// let path = Expression("path") + /// path.glob("*.png") + /// // "path" GLOB '*.png' + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A copy of the expression appended with a `GLOB` query against + /// the given pattern. + public func glob(_ pattern: String) -> Expression { + return "GLOB".infix(self, pattern) + } + + /// Builds a copy of the expression appended with a `MATCH` query against + /// the given pattern. + /// + /// let title = Expression("title") + /// title.match("swift AND programming") + /// // "title" MATCH 'swift AND programming' + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A copy of the expression appended with a `MATCH` query + /// against the given pattern. + public func match(_ pattern: String) -> Expression { + return "MATCH".infix(self, pattern) + } + + /// Builds a copy of the expression appended with a `REGEXP` query against + /// the given pattern. + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A copy of the expression appended with a `REGEXP` query + /// against the given pattern. + public func regexp(_ pattern: String) -> Expression { + return "REGEXP".infix(self, pattern) + } + + /// Builds a copy of the expression appended with a `COLLATE` clause with + /// the given sequence. + /// + /// let name = Expression("name") + /// name.collate(.Nocase) + /// // "name" COLLATE NOCASE + /// + /// - Parameter collation: A collating sequence. + /// + /// - Returns: A copy of the expression appended with a `COLLATE` clause + /// with the given sequence. + public func collate(_ collation: Collation) -> Expression { + return "COLLATE".infix(self, collation) + } + + /// Builds a copy of the expression wrapped with the `ltrim` function. + /// + /// let name = Expression("name") + /// name.ltrim() + /// // ltrim("name") + /// name.ltrim([" ", "\t"]) + /// // ltrim("name", ' \t') + /// + /// - Parameter characters: A set of characters to trim. + /// + /// - Returns: A copy of the expression wrapped with the `ltrim` function. + public func ltrim(_ characters: Set? = nil) -> Expression { + guard let characters = characters else { + return wrap(self) + } + return wrap([self, String(characters)]) + } + + /// Builds a copy of the expression wrapped with the `rtrim` function. + /// + /// let name = Expression("name") + /// name.rtrim() + /// // rtrim("name") + /// name.rtrim([" ", "\t"]) + /// // rtrim("name", ' \t') + /// + /// - Parameter characters: A set of characters to trim. + /// + /// - Returns: A copy of the expression wrapped with the `rtrim` function. + public func rtrim(_ characters: Set? = nil) -> Expression { + guard let characters = characters else { + return wrap(self) + } + return wrap([self, String(characters)]) + } + + /// Builds a copy of the expression wrapped with the `trim` function. + /// + /// let name = Expression("name") + /// name.trim() + /// // trim("name") + /// name.trim([" ", "\t"]) + /// // trim("name", ' \t') + /// + /// - Parameter characters: A set of characters to trim. + /// + /// - Returns: A copy of the expression wrapped with the `trim` function. + public func trim(_ characters: Set? = nil) -> Expression { + guard let characters = characters else { + return wrap(self) + } + return wrap([self, String(characters)]) + } + + /// Builds a copy of the expression wrapped with the `replace` function. + /// + /// let email = Expression("email") + /// email.replace("@mac.com", with: "@icloud.com") + /// // replace("email", '@mac.com', '@icloud.com') + /// + /// - Parameters: + /// + /// - pattern: A pattern to match. + /// + /// - replacement: The replacement string. + /// + /// - Returns: A copy of the expression wrapped with the `replace` function. + public func replace(_ pattern: String, with replacement: String) -> Expression { + return "replace".wrap([self, pattern, replacement]) + } + + /// Builds a copy of the expression wrapped with the `substr` function. + /// + /// let title = Expression("title") + /// title.substr(-100) + /// // substr("title", -100) + /// title.substr(0, length: 100) + /// // substr("title", 0, 100) + /// + /// - Parameters: + /// + /// - location: The substring’s start index. + /// + /// - length: An optional substring length. + /// + /// - Returns: A copy of the expression wrapped with the `substr` function. + public func substring(_ location: Int, length: Int? = nil) -> Expression { + guard let length = length else { + return "substr".wrap([self, location]) + } + return "substr".wrap([self, location, length]) + } + + /// Builds a copy of the expression wrapped with the `substr` function. + /// + /// let title = Expression("title") + /// title[0..<100] + /// // substr("title", 0, 100) + /// + /// - Parameter range: The character index range of the substring. + /// + /// - Returns: A copy of the expression wrapped with the `substr` function. + public subscript(range: Range) -> Expression { + return substring(range.lowerBound, length: range.upperBound - range.lowerBound) + } + +} + +extension Collection where Iterator.Element : Value, IndexDistance == Int { + + /// Builds a copy of the expression prepended with an `IN` check against the + /// collection. + /// + /// let name = Expression("name") + /// ["alice", "betty"].contains(name) + /// // "name" IN ('alice', 'betty') + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A copy of the expression prepended with an `IN` check against + /// the collection. + public func contains(_ expression: Expression) -> Expression { + let templates = [String](repeating: "?", count: count).joined(separator: ", ") + return "IN".infix(expression, Expression("(\(templates))", map { $0.datatypeValue })) + } + + /// Builds a copy of the expression prepended with an `IN` check against the + /// collection. + /// + /// let name = Expression("name") + /// ["alice", "betty"].contains(name) + /// // "name" IN ('alice', 'betty') + /// + /// - Parameter pattern: A pattern to match. + /// + /// - Returns: A copy of the expression prepended with an `IN` check against + /// the collection. + public func contains(_ expression: Expression) -> Expression { + let templates = [String](repeating: "?", count: count).joined(separator: ", ") + return "IN".infix(expression, Expression("(\(templates))", map { $0.datatypeValue })) + } + +} + +/// Builds a copy of the given expressions wrapped with the `ifnull` function. +/// +/// let name = Expression("name") +/// name ?? "An Anonymous Coward" +/// // ifnull("name", 'An Anonymous Coward') +/// +/// - Parameters: +/// +/// - optional: An optional expression. +/// +/// - defaultValue: A fallback value for when the optional expression is +/// `nil`. +/// +/// - Returns: A copy of the given expressions wrapped with the `ifnull` +/// function. +public func ??(optional: Expression, defaultValue: V) -> Expression { + return "ifnull".wrap([optional, defaultValue]) +} + +/// Builds a copy of the given expressions wrapped with the `ifnull` function. +/// +/// let nick = Expression("nick") +/// let name = Expression("name") +/// nick ?? name +/// // ifnull("nick", "name") +/// +/// - Parameters: +/// +/// - optional: An optional expression. +/// +/// - defaultValue: A fallback expression for when the optional expression is +/// `nil`. +/// +/// - Returns: A copy of the given expressions wrapped with the `ifnull` +/// function. +public func ??(optional: Expression, defaultValue: Expression) -> Expression { + return "ifnull".wrap([optional, defaultValue]) +} + +/// Builds a copy of the given expressions wrapped with the `ifnull` function. +/// +/// let nick = Expression("nick") +/// let name = Expression("name") +/// nick ?? name +/// // ifnull("nick", "name") +/// +/// - Parameters: +/// +/// - optional: An optional expression. +/// +/// - defaultValue: A fallback expression for when the optional expression is +/// `nil`. +/// +/// - Returns: A copy of the given expressions wrapped with the `ifnull` +/// function. +public func ??(optional: Expression, defaultValue: Expression) -> Expression { + return "ifnull".wrap([optional, defaultValue]) +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CustomFunctions.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CustomFunctions.swift new file mode 100644 index 0000000000..64b54edb75 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CustomFunctions.swift @@ -0,0 +1,136 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public extension Connection { + + /// Creates or redefines a custom SQL function. + /// + /// - Parameters: + /// + /// - function: The name of the function to create or redefine. + /// + /// - deterministic: Whether or not the function is deterministic (_i.e._ + /// the function always returns the same result for a given input). + /// + /// Default: `false` + /// + /// - block: A block of code to run when the function is called. + /// The assigned types must be explicit. + /// + /// - Returns: A closure returning an SQL expression to call the function. + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z) throws -> (() -> Expression) { + let fn = try createFunction(function, 0, deterministic) { _ in block() } + return { fn([]) } + } + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z?) throws -> (() -> Expression) { + let fn = try createFunction(function, 0, deterministic) { _ in block() } + return { fn([]) } + } + + // MARK: - + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z) throws -> ((Expression) -> Expression) { + let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) } + return { arg in fn([arg]) } + } + + public func createFunction(function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z) throws -> ((Expression) -> Expression) { + let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) } + return { arg in fn([arg]) } + } + + public func createFunction(function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z?) throws -> ((Expression) -> Expression) { + let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) } + return { arg in fn([arg]) } + } + + public func createFunction(function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z?) throws -> ((Expression) -> Expression) { + let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) } + return { arg in fn([arg]) } + } + + // MARK: - + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z) throws -> (Expression, Expression) -> Expression { + let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0]), value(args[1])) } + return { a, b in fn([a, b]) } + } + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z) throws -> (Expression, Expression) -> Expression { + let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value), value(args[1])) } + return { a, b in fn([a, b]) } + } + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z) throws -> (Expression, Expression) -> Expression { + let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0]), args[1].map(value)) } + return { a, b in fn([a, b]) } + } + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z?) throws -> (Expression, Expression) -> Expression { + let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0]), value(args[1])) } + return { a, b in fn([a, b]) } + } + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z) throws -> (Expression, Expression) -> Expression { + let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value), args[1].map(value)) } + return { a, b in fn([a, b]) } + } + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z?) throws -> (Expression, Expression) -> Expression { + let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value), value(args[1])) } + return { a, b in fn([a, b]) } + } + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z?) throws -> (Expression, Expression) -> Expression { + let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0]), args[1].map(value)) } + return { a, b in fn([a, b]) } + } + + public func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z?) throws -> (Expression, Expression) -> Expression { + let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value), args[1].map(value)) } + return { a, b in fn([a, b]) } + } + + // MARK: - + + fileprivate func createFunction(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z) throws -> (([Expressible]) -> Expression) { + createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in + block(arguments).datatypeValue + } + return { arguments in + function.quote().wrap(", ".join(arguments)) + } + } + + fileprivate func createFunction(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z?) throws -> (([Expressible]) -> Expression) { + createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in + block(arguments)?.datatypeValue + } + return { arguments in + function.quote().wrap(", ".join(arguments)) + } + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Expression.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Expression.swift new file mode 100644 index 0000000000..3198901c55 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Expression.swift @@ -0,0 +1,147 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public protocol ExpressionType : Expressible { // extensions cannot have inheritance clauses + + associatedtype UnderlyingType = Void + + var template: String { get } + var bindings: [Binding?] { get } + + init(_ template: String, _ bindings: [Binding?]) + +} + +extension ExpressionType { + + public init(literal: String) { + self.init(literal, []) + } + + public init(_ identifier: String) { + self.init(literal: identifier.quote()) + } + + public init(_ expression: U) { + self.init(expression.template, expression.bindings) + } + +} + +/// An `Expression` represents a raw SQL fragment and any associated bindings. +public struct Expression : ExpressionType { + + public typealias UnderlyingType = Datatype + + public var template: String + public var bindings: [Binding?] + + public init(_ template: String, _ bindings: [Binding?]) { + self.template = template + self.bindings = bindings + } + +} + +public protocol Expressible { + + var expression: Expression { get } + +} + +extension Expressible { + + // naïve compiler for statements that can’t be bound, e.g., CREATE TABLE + // FIXME: use @testable and make internal + public func asSQL() -> String { + let expressed = expression + var idx = 0 + return expressed.template.characters.reduce("") { template, character in + let transcoded: String + + if character == "?" { + transcoded = transcode(expressed.bindings[idx]) + idx += 1 + } else { + transcoded = String(character) + } + return template + transcoded + } + } + +} + +extension ExpressionType { + + public var expression: Expression { + return Expression(template, bindings) + } + + public var asc: Expressible { + return " ".join([self, Expression(literal: "ASC")]) + } + + public var desc: Expressible { + return " ".join([self, Expression(literal: "DESC")]) + } + +} + +extension ExpressionType where UnderlyingType : Value { + + public init(value: UnderlyingType) { + self.init("?", [value.datatypeValue]) + } + +} + +extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value { + + public static var null: Self { + return self.init(value: nil) + } + + public init(value: UnderlyingType.WrappedType?) { + self.init("?", [value?.datatypeValue]) + } + +} + +extension Value { + + public var expression: Expression { + return Expression(value: self).expression + } + +} + +public let rowid = Expression("ROWID") + +public func cast(_ expression: Expression) -> Expression { + return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings) +} + +public func cast(_ expression: Expression) -> Expression { + return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings) +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Operators.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Operators.swift new file mode 100644 index 0000000000..fdd293be71 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Operators.swift @@ -0,0 +1,541 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +// TODO: use `@warn_unused_result` by the time operator functions support it + +public func +(lhs: Expression, rhs: Expression) -> Expression { + return "||".infix(lhs, rhs) +} + +public func +(lhs: Expression, rhs: Expression) -> Expression { + return "||".infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: Expression) -> Expression { + return "||".infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: Expression) -> Expression { + return "||".infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: String) -> Expression { + return "||".infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: String) -> Expression { + return "||".infix(lhs, rhs) +} +public func +(lhs: String, rhs: Expression) -> Expression { + return "||".infix(lhs, rhs) +} +public func +(lhs: String, rhs: Expression) -> Expression { + return "||".infix(lhs, rhs) +} + +// MARK: - + +public func +(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func +(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func +(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func +(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} + +public func -(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func -(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func -(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func -(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func -(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func -(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func -(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func -(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} + +public func *(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func *(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func *(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func *(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func *(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func *(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func *(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func *(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} + +public func /(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func /(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func /(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func /(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func /(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func /(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func /(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} +public func /(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { + return infix(lhs, rhs) +} + +public prefix func -(rhs: Expression) -> Expression where V.Datatype : Number { + return wrap(rhs) +} +public prefix func -(rhs: Expression) -> Expression where V.Datatype : Number { + return wrap(rhs) +} + +// MARK: - + +public func %(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func %(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func %(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func %(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func %(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func %(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func %(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func %(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} + +public func <<(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func <<(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func <<(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func <<(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func <<(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func <<(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func <<(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func <<(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} + +public func >>(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func >>(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func >>(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func >>(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func >>(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func >>(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func >>(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func >>(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} + +public func &(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func &(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func &(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func &(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func &(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func &(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func &(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func &(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} + +public func |(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func |(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func |(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func |(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func |(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func |(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func |(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} +public func |(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return infix(lhs, rhs) +} + +public func ^(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return (~(lhs & rhs)) & (lhs | rhs) +} +public func ^(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return (~(lhs & rhs)) & (lhs | rhs) +} +public func ^(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return (~(lhs & rhs)) & (lhs | rhs) +} +public func ^(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { + return (~(lhs & rhs)) & (lhs | rhs) +} +public func ^(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return (~(lhs & rhs)) & (lhs | rhs) +} +public func ^(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { + return (~(lhs & rhs)) & (lhs | rhs) +} +public func ^(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return (~(lhs & rhs)) & (lhs | rhs) +} +public func ^(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { + return (~(lhs & rhs)) & (lhs | rhs) +} + +public prefix func ~(rhs: Expression) -> Expression where V.Datatype == Int64 { + return wrap(rhs) +} +public prefix func ~(rhs: Expression) -> Expression where V.Datatype == Int64 { + return wrap(rhs) +} + +// MARK: - + +public func ==(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { + return "=".infix(lhs, rhs) +} +public func ==(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { + return "=".infix(lhs, rhs) +} +public func ==(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { + return "=".infix(lhs, rhs) +} +public func ==(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { + return "=".infix(lhs, rhs) +} +public func ==(lhs: Expression, rhs: V) -> Expression where V.Datatype : Equatable { + return "=".infix(lhs, rhs) +} +public func ==(lhs: Expression, rhs: V?) -> Expression where V.Datatype : Equatable { + guard let rhs = rhs else { return "IS".infix(lhs, Expression(value: nil)) } + return "=".infix(lhs, rhs) +} +public func ==(lhs: V, rhs: Expression) -> Expression where V.Datatype : Equatable { + return "=".infix(lhs, rhs) +} +public func ==(lhs: V?, rhs: Expression) -> Expression where V.Datatype : Equatable { + guard let lhs = lhs else { return "IS".infix(Expression(value: nil), rhs) } + return "=".infix(lhs, rhs) +} + +public func !=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { + return infix(lhs, rhs) +} +public func !=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { + return infix(lhs, rhs) +} +public func !=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { + return infix(lhs, rhs) +} +public func !=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { + return infix(lhs, rhs) +} +public func !=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Equatable { + return infix(lhs, rhs) +} +public func !=(lhs: Expression, rhs: V?) -> Expression where V.Datatype : Equatable { + guard let rhs = rhs else { return "IS NOT".infix(lhs, Expression(value: nil)) } + return infix(lhs, rhs) +} +public func !=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Equatable { + return infix(lhs, rhs) +} +public func !=(lhs: V?, rhs: Expression) -> Expression where V.Datatype : Equatable { + guard let lhs = lhs else { return "IS NOT".infix(Expression(value: nil), rhs) } + return infix(lhs, rhs) +} + +public func >(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} + +public func >=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func >=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} + +public func <(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} + +public func <=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} +public func <=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { + return infix(lhs, rhs) +} + +public func ~=(lhs: ClosedRange, rhs: Expression) -> Expression where V.Datatype : Binding & Comparable { + return Expression("\(rhs.template) BETWEEN ? AND ?", rhs.bindings + [lhs.lowerBound as? Binding, lhs.upperBound as? Binding]) +} +public func ~=(lhs: ClosedRange, rhs: Expression) -> Expression where V.Datatype : Binding & Comparable { + return Expression("\(rhs.template) BETWEEN ? AND ?", rhs.bindings + [lhs.lowerBound as? Binding, lhs.upperBound as? Binding]) +} + +// MARK: - + +public func &&(lhs: Expression, rhs: Expression) -> Expression { + return "AND".infix(lhs, rhs) +} +public func &&(lhs: Expression, rhs: Expression) -> Expression { + return "AND".infix(lhs, rhs) +} +public func &&(lhs: Expression, rhs: Expression) -> Expression { + return "AND".infix(lhs, rhs) +} +public func &&(lhs: Expression, rhs: Expression) -> Expression { + return "AND".infix(lhs, rhs) +} +public func &&(lhs: Expression, rhs: Bool) -> Expression { + return "AND".infix(lhs, rhs) +} +public func &&(lhs: Expression, rhs: Bool) -> Expression { + return "AND".infix(lhs, rhs) +} +public func &&(lhs: Bool, rhs: Expression) -> Expression { + return "AND".infix(lhs, rhs) +} +public func &&(lhs: Bool, rhs: Expression) -> Expression { + return "AND".infix(lhs, rhs) +} + +public func ||(lhs: Expression, rhs: Expression) -> Expression { + return "OR".infix(lhs, rhs) +} +public func ||(lhs: Expression, rhs: Expression) -> Expression { + return "OR".infix(lhs, rhs) +} +public func ||(lhs: Expression, rhs: Expression) -> Expression { + return "OR".infix(lhs, rhs) +} +public func ||(lhs: Expression, rhs: Expression) -> Expression { + return "OR".infix(lhs, rhs) +} +public func ||(lhs: Expression, rhs: Bool) -> Expression { + return "OR".infix(lhs, rhs) +} +public func ||(lhs: Expression, rhs: Bool) -> Expression { + return "OR".infix(lhs, rhs) +} +public func ||(lhs: Bool, rhs: Expression) -> Expression { + return "OR".infix(lhs, rhs) +} +public func ||(lhs: Bool, rhs: Expression) -> Expression { + return "OR".infix(lhs, rhs) +} + +public prefix func !(rhs: Expression) -> Expression { + return "NOT ".wrap(rhs) +} +public prefix func !(rhs: Expression) -> Expression { + return "NOT ".wrap(rhs) +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Query.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Query.swift new file mode 100644 index 0000000000..c9d2ea9cc5 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Query.swift @@ -0,0 +1,1162 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public protocol QueryType : Expressible { + + var clauses: QueryClauses { get set } + + init(_ name: String, database: String?) + +} + +public protocol SchemaType : QueryType { + + static var identifier: String { get } + +} + +extension SchemaType { + + /// Builds a copy of the query with the `SELECT` clause applied. + /// + /// let users = Table("users") + /// let id = Expression("id") + /// let email = Expression("email") + /// + /// users.select(id, email) + /// // SELECT "id", "email" FROM "users" + /// + /// - Parameter all: A list of expressions to select. + /// + /// - Returns: A query with the given `SELECT` clause applied. + public func select(_ column1: Expressible, _ more: Expressible...) -> Self { + return select(false, [column1] + more) + } + + /// Builds a copy of the query with the `SELECT DISTINCT` clause applied. + /// + /// let users = Table("users") + /// let email = Expression("email") + /// + /// users.select(distinct: email) + /// // SELECT DISTINCT "email" FROM "users" + /// + /// - Parameter columns: A list of expressions to select. + /// + /// - Returns: A query with the given `SELECT DISTINCT` clause applied. + public func select(distinct column1: Expressible, _ more: Expressible...) -> Self { + return select(true, [column1] + more) + } + + /// Builds a copy of the query with the `SELECT` clause applied. + /// + /// let users = Table("users") + /// let id = Expression("id") + /// let email = Expression("email") + /// + /// users.select([id, email]) + /// // SELECT "id", "email" FROM "users" + /// + /// - Parameter all: A list of expressions to select. + /// + /// - Returns: A query with the given `SELECT` clause applied. + public func select(_ all: [Expressible]) -> Self { + return select(false, all) + } + + /// Builds a copy of the query with the `SELECT DISTINCT` clause applied. + /// + /// let users = Table("users") + /// let email = Expression("email") + /// + /// users.select(distinct: [email]) + /// // SELECT DISTINCT "email" FROM "users" + /// + /// - Parameter columns: A list of expressions to select. + /// + /// - Returns: A query with the given `SELECT DISTINCT` clause applied. + public func select(distinct columns: [Expressible]) -> Self { + return select(true, columns) + } + + /// Builds a copy of the query with the `SELECT *` clause applied. + /// + /// let users = Table("users") + /// + /// users.select(*) + /// // SELECT * FROM "users" + /// + /// - Parameter star: A star literal. + /// + /// - Returns: A query with the given `SELECT *` clause applied. + public func select(_ star: Star) -> Self { + return select([star(nil, nil)]) + } + + /// Builds a copy of the query with the `SELECT DISTINCT *` clause applied. + /// + /// let users = Table("users") + /// + /// users.select(distinct: *) + /// // SELECT DISTINCT * FROM "users" + /// + /// - Parameter star: A star literal. + /// + /// - Returns: A query with the given `SELECT DISTINCT *` clause applied. + public func select(distinct star: Star) -> Self { + return select(distinct: [star(nil, nil)]) + } + + /// Builds a scalar copy of the query with the `SELECT` clause applied. + /// + /// let users = Table("users") + /// let id = Expression("id") + /// + /// users.select(id) + /// // SELECT "id" FROM "users" + /// + /// - Parameter all: A list of expressions to select. + /// + /// - Returns: A query with the given `SELECT` clause applied. + public func select(_ column: Expression) -> ScalarQuery { + return select(false, [column]) + } + public func select(_ column: Expression) -> ScalarQuery { + return select(false, [column]) + } + + /// Builds a scalar copy of the query with the `SELECT DISTINCT` clause + /// applied. + /// + /// let users = Table("users") + /// let email = Expression("email") + /// + /// users.select(distinct: email) + /// // SELECT DISTINCT "email" FROM "users" + /// + /// - Parameter column: A list of expressions to select. + /// + /// - Returns: A query with the given `SELECT DISTINCT` clause applied. + public func select(distinct column: Expression) -> ScalarQuery { + return select(true, [column]) + } + public func select(distinct column: Expression) -> ScalarQuery { + return select(true, [column]) + } + + public var count: ScalarQuery { + return select(Expression.count(*)) + } + +} + +extension QueryType { + + fileprivate func select(_ distinct: Bool, _ columns: [Expressible]) -> Q { + var query = Q.init(clauses.from.name, database: clauses.from.database) + query.clauses = clauses + query.clauses.select = (distinct, columns) + return query + } + + // MARK: JOIN + + /// Adds a `JOIN` clause to the query. + /// + /// let users = Table("users") + /// let id = Expression("id") + /// let posts = Table("posts") + /// let userId = Expression("user_id") + /// + /// users.join(posts, on: posts[userId] == users[id]) + /// // SELECT * FROM "users" INNER JOIN "posts" ON ("posts"."user_id" = "users"."id") + /// + /// - Parameters: + /// + /// - table: A query representing the other table. + /// + /// - condition: A boolean expression describing the join condition. + /// + /// - Returns: A query with the given `JOIN` clause applied. + public func join(_ table: QueryType, on condition: Expression) -> Self { + return join(table, on: Expression(condition)) + } + + /// Adds a `JOIN` clause to the query. + /// + /// let users = Table("users") + /// let id = Expression("id") + /// let posts = Table("posts") + /// let userId = Expression("user_id") + /// + /// users.join(posts, on: posts[userId] == users[id]) + /// // SELECT * FROM "users" INNER JOIN "posts" ON ("posts"."user_id" = "users"."id") + /// + /// - Parameters: + /// + /// - table: A query representing the other table. + /// + /// - condition: A boolean expression describing the join condition. + /// + /// - Returns: A query with the given `JOIN` clause applied. + public func join(_ table: QueryType, on condition: Expression) -> Self { + return join(.inner, table, on: condition) + } + + /// Adds a `JOIN` clause to the query. + /// + /// let users = Table("users") + /// let id = Expression("id") + /// let posts = Table("posts") + /// let userId = Expression("user_id") + /// + /// users.join(.LeftOuter, posts, on: posts[userId] == users[id]) + /// // SELECT * FROM "users" LEFT OUTER JOIN "posts" ON ("posts"."user_id" = "users"."id") + /// + /// - Parameters: + /// + /// - type: The `JOIN` operator. + /// + /// - table: A query representing the other table. + /// + /// - condition: A boolean expression describing the join condition. + /// + /// - Returns: A query with the given `JOIN` clause applied. + public func join(_ type: JoinType, _ table: QueryType, on condition: Expression) -> Self { + return join(type, table, on: Expression(condition)) + } + + /// Adds a `JOIN` clause to the query. + /// + /// let users = Table("users") + /// let id = Expression("id") + /// let posts = Table("posts") + /// let userId = Expression("user_id") + /// + /// users.join(.LeftOuter, posts, on: posts[userId] == users[id]) + /// // SELECT * FROM "users" LEFT OUTER JOIN "posts" ON ("posts"."user_id" = "users"."id") + /// + /// - Parameters: + /// + /// - type: The `JOIN` operator. + /// + /// - table: A query representing the other table. + /// + /// - condition: A boolean expression describing the join condition. + /// + /// - Returns: A query with the given `JOIN` clause applied. + public func join(_ type: JoinType, _ table: QueryType, on condition: Expression) -> Self { + var query = self + query.clauses.join.append((type: type, query: table, condition: table.clauses.filters.map { condition && $0 } ?? condition as Expressible)) + return query + } + + // MARK: WHERE + + /// Adds a condition to the query’s `WHERE` clause. + /// + /// let users = Table("users") + /// let id = Expression("id") + /// + /// users.filter(id == 1) + /// // SELECT * FROM "users" WHERE ("id" = 1) + /// + /// - Parameter condition: A boolean expression to filter on. + /// + /// - Returns: A query with the given `WHERE` clause applied. + public func filter(_ predicate: Expression) -> Self { + return filter(Expression(predicate)) + } + + /// Adds a condition to the query’s `WHERE` clause. + /// + /// let users = Table("users") + /// let age = Expression("age") + /// + /// users.filter(age >= 35) + /// // SELECT * FROM "users" WHERE ("age" >= 35) + /// + /// - Parameter condition: A boolean expression to filter on. + /// + /// - Returns: A query with the given `WHERE` clause applied. + public func filter(_ predicate: Expression) -> Self { + var query = self + query.clauses.filters = query.clauses.filters.map { $0 && predicate } ?? predicate + return query + } + + /// Adds a condition to the query’s `WHERE` clause. + /// This is an alias for `filter(predicate)` + public func `where`(_ predicate: Expression) -> Self { + return `where`(Expression(predicate)) + } + + /// Adds a condition to the query’s `WHERE` clause. + /// This is an alias for `filter(predicate)` + public func `where`(_ predicate: Expression) -> Self { + return filter(predicate) + } + + // MARK: GROUP BY + + /// Sets a `GROUP BY` clause on the query. + /// + /// - Parameter by: A list of columns to group by. + /// + /// - Returns: A query with the given `GROUP BY` clause applied. + public func group(_ by: Expressible...) -> Self { + return group(by) + } + + /// Sets a `GROUP BY` clause on the query. + /// + /// - Parameter by: A list of columns to group by. + /// + /// - Returns: A query with the given `GROUP BY` clause applied. + public func group(_ by: [Expressible]) -> Self { + return group(by, nil) + } + + /// Sets a `GROUP BY`-`HAVING` clause on the query. + /// + /// - Parameters: + /// + /// - by: A column to group by. + /// + /// - having: A condition determining which groups are returned. + /// + /// - Returns: A query with the given `GROUP BY`–`HAVING` clause applied. + public func group(_ by: Expressible, having: Expression) -> Self { + return group([by], having: having) + } + + /// Sets a `GROUP BY`-`HAVING` clause on the query. + /// + /// - Parameters: + /// + /// - by: A column to group by. + /// + /// - having: A condition determining which groups are returned. + /// + /// - Returns: A query with the given `GROUP BY`–`HAVING` clause applied. + public func group(_ by: Expressible, having: Expression) -> Self { + return group([by], having: having) + } + + /// Sets a `GROUP BY`-`HAVING` clause on the query. + /// + /// - Parameters: + /// + /// - by: A list of columns to group by. + /// + /// - having: A condition determining which groups are returned. + /// + /// - Returns: A query with the given `GROUP BY`–`HAVING` clause applied. + public func group(_ by: [Expressible], having: Expression) -> Self { + return group(by, Expression(having)) + } + + /// Sets a `GROUP BY`-`HAVING` clause on the query. + /// + /// - Parameters: + /// + /// - by: A list of columns to group by. + /// + /// - having: A condition determining which groups are returned. + /// + /// - Returns: A query with the given `GROUP BY`–`HAVING` clause applied. + public func group(_ by: [Expressible], having: Expression) -> Self { + return group(by, having) + } + + fileprivate func group(_ by: [Expressible], _ having: Expression?) -> Self { + var query = self + query.clauses.group = (by, having) + return query + } + + // MARK: ORDER BY + + /// Sets an `ORDER BY` clause on the query. + /// + /// let users = Table("users") + /// let email = Expression("email") + /// let name = Expression("name") + /// + /// users.order(email.desc, name.asc) + /// // SELECT * FROM "users" ORDER BY "email" DESC, "name" ASC + /// + /// - Parameter by: An ordered list of columns and directions to sort by. + /// + /// - Returns: A query with the given `ORDER BY` clause applied. + public func order(_ by: Expressible...) -> Self { + return order(by) + } + + /// Sets an `ORDER BY` clause on the query. + /// + /// let users = Table("users") + /// let email = Expression("email") + /// let name = Expression("name") + /// + /// users.order([email.desc, name.asc]) + /// // SELECT * FROM "users" ORDER BY "email" DESC, "name" ASC + /// + /// - Parameter by: An ordered list of columns and directions to sort by. + /// + /// - Returns: A query with the given `ORDER BY` clause applied. + public func order(_ by: [Expressible]) -> Self { + var query = self + query.clauses.order = by + return query + } + + // MARK: LIMIT/OFFSET + + /// Sets the LIMIT clause (and resets any OFFSET clause) on the query. + /// + /// let users = Table("users") + /// + /// users.limit(20) + /// // SELECT * FROM "users" LIMIT 20 + /// + /// - Parameter length: The maximum number of rows to return (or `nil` to + /// return unlimited rows). + /// + /// - Returns: A query with the given LIMIT clause applied. + public func limit(_ length: Int?) -> Self { + return limit(length, nil) + } + + /// Sets LIMIT and OFFSET clauses on the query. + /// + /// let users = Table("users") + /// + /// users.limit(20, offset: 20) + /// // SELECT * FROM "users" LIMIT 20 OFFSET 20 + /// + /// - Parameters: + /// + /// - length: The maximum number of rows to return. + /// + /// - offset: The number of rows to skip. + /// + /// - Returns: A query with the given LIMIT and OFFSET clauses applied. + public func limit(_ length: Int, offset: Int) -> Self { + return limit(length, offset) + } + + // prevents limit(nil, offset: 5) + fileprivate func limit(_ length: Int?, _ offset: Int?) -> Self { + var query = self + query.clauses.limit = length.map { ($0, offset) } + return query + } + + // MARK: - Clauses + // + // MARK: SELECT + + // MARK: - + + fileprivate var selectClause: Expressible { + return " ".join([ + Expression(literal: clauses.select.distinct ? "SELECT DISTINCT" : "SELECT"), + ", ".join(clauses.select.columns), + Expression(literal: "FROM"), + tableName(alias: true) + ]) + } + + fileprivate var joinClause: Expressible? { + guard !clauses.join.isEmpty else { + return nil + } + + return " ".join(clauses.join.map { type, query, condition in + " ".join([ + Expression(literal: "\(type.rawValue) JOIN"), + query.tableName(alias: true), + Expression(literal: "ON"), + condition + ]) + }) + } + + fileprivate var whereClause: Expressible? { + guard let filters = clauses.filters else { + return nil + } + + return " ".join([ + Expression(literal: "WHERE"), + filters + ]) + } + + fileprivate var groupByClause: Expressible? { + guard let group = clauses.group else { + return nil + } + + let groupByClause = " ".join([ + Expression(literal: "GROUP BY"), + ", ".join(group.by) + ]) + + guard let having = group.having else { + return groupByClause + } + + return " ".join([ + groupByClause, + " ".join([ + Expression(literal: "HAVING"), + having + ]) + ]) + } + + fileprivate var orderClause: Expressible? { + guard !clauses.order.isEmpty else { + return nil + } + + return " ".join([ + Expression(literal: "ORDER BY"), + ", ".join(clauses.order) + ]) + } + + fileprivate var limitOffsetClause: Expressible? { + guard let limit = clauses.limit else { + return nil + } + + let limitClause = Expression(literal: "LIMIT \(limit.length)") + + guard let offset = limit.offset else { + return limitClause + } + + return " ".join([ + limitClause, + Expression(literal: "OFFSET \(offset)") + ]) + } + + // MARK: - + + public func alias(_ aliasName: String) -> Self { + var query = self + query.clauses.from = (clauses.from.name, aliasName, clauses.from.database) + return query + } + + // MARK: - Operations + // + // MARK: INSERT + + public func insert(_ value: Setter, _ more: Setter...) -> Insert { + return insert([value] + more) + } + + public func insert(_ values: [Setter]) -> Insert { + return insert(nil, values) + } + + public func insert(or onConflict: OnConflict, _ values: Setter...) -> Insert { + return insert(or: onConflict, values) + } + + public func insert(or onConflict: OnConflict, _ values: [Setter]) -> Insert { + return insert(onConflict, values) + } + + fileprivate func insert(_ or: OnConflict?, _ values: [Setter]) -> Insert { + let insert = values.reduce((columns: [Expressible](), values: [Expressible]())) { insert, setter in + (insert.columns + [setter.column], insert.values + [setter.value]) + } + + let clauses: [Expressible?] = [ + Expression(literal: "INSERT"), + or.map { Expression(literal: "OR \($0.rawValue)") }, + Expression(literal: "INTO"), + tableName(), + "".wrap(insert.columns) as Expression, + Expression(literal: "VALUES"), + "".wrap(insert.values) as Expression, + whereClause + ] + + return Insert(" ".join(clauses.flatMap { $0 }).expression) + } + + /// Runs an `INSERT` statement against the query with `DEFAULT VALUES`. + public func insert() -> Insert { + return Insert(" ".join([ + Expression(literal: "INSERT INTO"), + tableName(), + Expression(literal: "DEFAULT VALUES") + ]).expression) + } + + /// Runs an `INSERT` statement against the query with the results of another + /// query. + /// + /// - Parameter query: A query to `SELECT` results from. + /// + /// - Returns: The number of updated rows and statement. + public func insert(_ query: QueryType) -> Update { + return Update(" ".join([ + Expression(literal: "INSERT INTO"), + tableName(), + query.expression + ]).expression) + } + + // MARK: UPDATE + + public func update(_ values: Setter...) -> Update { + return update(values) + } + + public func update(_ values: [Setter]) -> Update { + let clauses: [Expressible?] = [ + Expression(literal: "UPDATE"), + tableName(), + Expression(literal: "SET"), + ", ".join(values.map { " = ".join([$0.column, $0.value]) }), + whereClause + ] + + return Update(" ".join(clauses.flatMap { $0 }).expression) + } + + // MARK: DELETE + + public func delete() -> Delete { + let clauses: [Expressible?] = [ + Expression(literal: "DELETE FROM"), + tableName(), + whereClause + ] + + return Delete(" ".join(clauses.flatMap { $0 }).expression) + } + + // MARK: EXISTS + + public var exists: Select { + return Select(" ".join([ + Expression(literal: "SELECT EXISTS"), + "".wrap(expression) as Expression + ]).expression) + } + + // MARK: - + + /// Prefixes a column expression with the query’s table name or alias. + /// + /// - Parameter column: A column expression. + /// + /// - Returns: A column expression namespaced with the query’s table name or + /// alias. + public func namespace(_ column: Expression) -> Expression { + return Expression(".".join([tableName(), column]).expression) + } + + // FIXME: rdar://problem/18673897 // subscript… + + public subscript(column: Expression) -> Expression { + return namespace(column) + } + public subscript(column: Expression) -> Expression { + return namespace(column) + } + + public subscript(column: Expression) -> Expression { + return namespace(column) + } + public subscript(column: Expression) -> Expression { + return namespace(column) + } + + public subscript(column: Expression) -> Expression { + return namespace(column) + } + public subscript(column: Expression) -> Expression { + return namespace(column) + } + + public subscript(column: Expression) -> Expression { + return namespace(column) + } + public subscript(column: Expression) -> Expression { + return namespace(column) + } + + public subscript(column: Expression) -> Expression { + return namespace(column) + } + public subscript(column: Expression) -> Expression { + return namespace(column) + } + + public subscript(column: Expression) -> Expression { + return namespace(column) + } + public subscript(column: Expression) -> Expression { + return namespace(column) + } + + /// Prefixes a star with the query’s table name or alias. + /// + /// - Parameter star: A literal `*`. + /// + /// - Returns: A `*` expression namespaced with the query’s table name or + /// alias. + public subscript(star: Star) -> Expression { + return namespace(star(nil, nil)) + } + + // MARK: - + + // TODO: alias support + func tableName(alias aliased: Bool = false) -> Expressible { + guard let alias = clauses.from.alias , aliased else { + return database(namespace: clauses.from.alias ?? clauses.from.name) + } + + return " ".join([ + database(namespace: clauses.from.name), + Expression(literal: "AS"), + Expression(alias) + ]) + } + + func tableName(qualified: Bool) -> Expressible { + if qualified { + return tableName() + } + return Expression(clauses.from.alias ?? clauses.from.name) + } + + func database(namespace name: String) -> Expressible { + let name = Expression(name) + + guard let database = clauses.from.database else { + return name + } + + return ".".join([Expression(database), name]) + } + + public var expression: Expression { + let clauses: [Expressible?] = [ + selectClause, + joinClause, + whereClause, + groupByClause, + orderClause, + limitOffsetClause + ] + + return " ".join(clauses.flatMap { $0 }).expression + } + +} + +// TODO: decide: simplify the below with a boxed type instead + +/// Queries a collection of chainable helper functions and expressions to build +/// executable SQL statements. +public struct Table : SchemaType { + + public static let identifier = "TABLE" + + public var clauses: QueryClauses + + public init(_ name: String, database: String? = nil) { + clauses = QueryClauses(name, alias: nil, database: database) + } + +} + +public struct View : SchemaType { + + public static let identifier = "VIEW" + + public var clauses: QueryClauses + + public init(_ name: String, database: String? = nil) { + clauses = QueryClauses(name, alias: nil, database: database) + } + +} + +public struct VirtualTable : SchemaType { + + public static let identifier = "VIRTUAL TABLE" + + public var clauses: QueryClauses + + public init(_ name: String, database: String? = nil) { + clauses = QueryClauses(name, alias: nil, database: database) + } + +} + +// TODO: make `ScalarQuery` work in `QueryType.select()`, `.filter()`, etc. + +public struct ScalarQuery : QueryType { + + public var clauses: QueryClauses + + public init(_ name: String, database: String? = nil) { + clauses = QueryClauses(name, alias: nil, database: database) + } + +} + +// TODO: decide: simplify the below with a boxed type instead + +public struct Select : ExpressionType { + + public var template: String + public var bindings: [Binding?] + + public init(_ template: String, _ bindings: [Binding?]) { + self.template = template + self.bindings = bindings + } + +} + +public struct Insert : ExpressionType { + + public var template: String + public var bindings: [Binding?] + + public init(_ template: String, _ bindings: [Binding?]) { + self.template = template + self.bindings = bindings + } + +} + +public struct Update : ExpressionType { + + public var template: String + public var bindings: [Binding?] + + public init(_ template: String, _ bindings: [Binding?]) { + self.template = template + self.bindings = bindings + } + +} + +public struct Delete : ExpressionType { + + public var template: String + public var bindings: [Binding?] + + public init(_ template: String, _ bindings: [Binding?]) { + self.template = template + self.bindings = bindings + } + +} + +extension Connection { + + public func prepare(_ query: QueryType) throws -> AnySequence { + let expression = query.expression + let statement = try prepare(expression.template, expression.bindings) + + let columnNames: [String: Int] = try { + var (columnNames, idx) = ([String: Int](), 0) + column: for each in query.clauses.select.columns { + var names = each.expression.template.characters.split { $0 == "." }.map(String.init) + let column = names.removeLast() + let namespace = names.joined(separator: ".") + + func expandGlob(_ namespace: Bool) -> ((QueryType) throws -> Void) { + return { (query: QueryType) throws -> (Void) in + var q = type(of: query).init(query.clauses.from.name, database: query.clauses.from.database) + q.clauses.select = query.clauses.select + let e = q.expression + var names = try self.prepare(e.template, e.bindings).columnNames.map { $0.quote() } + if namespace { names = names.map { "\(query.tableName().expression.template).\($0)" } } + for name in names { columnNames[name] = idx; idx += 1 } + } + } + + if column == "*" { + var select = query + select.clauses.select = (false, [Expression(literal: "*") as Expressible]) + let queries = [select] + query.clauses.join.map { $0.query } + if !namespace.isEmpty { + for q in queries { + if q.tableName().expression.template == namespace { + try expandGlob(true)(q) + continue column + } + } + fatalError("no such table: \(namespace)") + } + for q in queries { + try expandGlob(query.clauses.join.count > 0)(q) + } + continue + } + + columnNames[each.expression.template] = idx + idx += 1 + } + return columnNames + }() + + return AnySequence { + AnyIterator { statement.next().map { Row(columnNames, $0) } } + } + } + + public func scalar(_ query: ScalarQuery) throws -> V { + let expression = query.expression + return value(try scalar(expression.template, expression.bindings)) + } + + public func scalar(_ query: ScalarQuery) throws -> V.ValueType? { + let expression = query.expression + guard let value = try scalar(expression.template, expression.bindings) as? V.Datatype else { return nil } + return V.fromDatatypeValue(value) + } + + public func scalar(_ query: Select) throws -> V { + let expression = query.expression + return value(try scalar(expression.template, expression.bindings)) + } + + public func scalar(_ query: Select) throws -> V.ValueType? { + let expression = query.expression + guard let value = try scalar(expression.template, expression.bindings) as? V.Datatype else { return nil } + return V.fromDatatypeValue(value) + } + + public func pluck(_ query: QueryType) throws -> Row? { + return try prepare(query.limit(1, query.clauses.limit?.offset)).makeIterator().next() + } + + /// Runs an `Insert` query. + /// + /// - SeeAlso: `QueryType.insert(value:_:)` + /// - SeeAlso: `QueryType.insert(values:)` + /// - SeeAlso: `QueryType.insert(or:_:)` + /// - SeeAlso: `QueryType.insert()` + /// + /// - Parameter query: An insert query. + /// + /// - Returns: The insert’s rowid. + @discardableResult public func run(_ query: Insert) throws -> Int64 { + let expression = query.expression + return try sync { + try self.run(expression.template, expression.bindings) + return self.lastInsertRowid + } + } + + /// Runs an `Update` query. + /// + /// - SeeAlso: `QueryType.insert(query:)` + /// - SeeAlso: `QueryType.update(values:)` + /// + /// - Parameter query: An update query. + /// + /// - Returns: The number of updated rows. + @discardableResult public func run(_ query: Update) throws -> Int { + let expression = query.expression + return try sync { + try self.run(expression.template, expression.bindings) + return self.changes + } + } + + /// Runs a `Delete` query. + /// + /// - SeeAlso: `QueryType.delete()` + /// + /// - Parameter query: A delete query. + /// + /// - Returns: The number of deleted rows. + @discardableResult public func run(_ query: Delete) throws -> Int { + let expression = query.expression + return try sync { + try self.run(expression.template, expression.bindings) + return self.changes + } + } + +} + +public struct Row { + + fileprivate let columnNames: [String: Int] + + fileprivate let values: [Binding?] + + fileprivate init(_ columnNames: [String: Int], _ values: [Binding?]) { + self.columnNames = columnNames + self.values = values + } + + /// Returns a row’s value for the given column. + /// + /// - Parameter column: An expression representing a column selected in a Query. + /// + /// - Returns: The value for the given column. + public func get(_ column: Expression) -> V { + return get(Expression(column))! + } + public func get(_ column: Expression) -> V? { + func valueAtIndex(_ idx: Int) -> V? { + guard let value = values[idx] as? V.Datatype else { return nil } + return (V.fromDatatypeValue(value) as? V)! + } + + guard let idx = columnNames[column.template] else { + let similar = Array(columnNames.keys).filter { $0.hasSuffix(".\(column.template)") } + + switch similar.count { + case 0: + fatalError("no such column '\(column.template)' in columns: \(columnNames.keys.sorted())") + case 1: + return valueAtIndex(columnNames[similar[0]]!) + default: + fatalError("ambiguous column '\(column.template)' (please disambiguate: \(similar))") + } + } + + return valueAtIndex(idx) + } + + // FIXME: rdar://problem/18673897 // subscript… + + public subscript(column: Expression) -> Blob { + return get(column) + } + public subscript(column: Expression) -> Blob? { + return get(column) + } + + public subscript(column: Expression) -> Bool { + return get(column) + } + public subscript(column: Expression) -> Bool? { + return get(column) + } + + public subscript(column: Expression) -> Double { + return get(column) + } + public subscript(column: Expression) -> Double? { + return get(column) + } + + public subscript(column: Expression) -> Int { + return get(column) + } + public subscript(column: Expression) -> Int? { + return get(column) + } + + public subscript(column: Expression) -> Int64 { + return get(column) + } + public subscript(column: Expression) -> Int64? { + return get(column) + } + + public subscript(column: Expression) -> String { + return get(column) + } + public subscript(column: Expression) -> String? { + return get(column) + } + +} + +/// Determines the join operator for a query’s `JOIN` clause. +public enum JoinType : String { + + /// A `CROSS` join. + case cross = "CROSS" + + /// An `INNER` join. + case inner = "INNER" + + /// A `LEFT OUTER` join. + case leftOuter = "LEFT OUTER" + +} + +/// ON CONFLICT resolutions. +public enum OnConflict: String { + + case replace = "REPLACE" + + case rollback = "ROLLBACK" + + case abort = "ABORT" + + case fail = "FAIL" + + case ignore = "IGNORE" + +} + +// MARK: - Private + +public struct QueryClauses { + + var select = (distinct: false, columns: [Expression(literal: "*") as Expressible]) + + var from: (name: String, alias: String?, database: String?) + + var join = [(type: JoinType, query: QueryType, condition: Expressible)]() + + var filters: Expression? + + var group: (by: [Expressible], having: Expression?)? + + var order = [Expressible]() + + var limit: (length: Int, offset: Int?)? + + fileprivate init(_ name: String, alias: String?, database: String?) { + self.from = (name, alias, database) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Schema.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Schema.swift new file mode 100644 index 0000000000..1388170e47 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Schema.swift @@ -0,0 +1,519 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +extension SchemaType { + + // MARK: - DROP TABLE / VIEW / VIRTUAL TABLE + + public func drop(ifExists: Bool = false) -> String { + return drop("TABLE", tableName(), ifExists) + } + +} + +extension Table { + + // MARK: - CREATE TABLE + + public func create(temporary: Bool = false, ifNotExists: Bool = false, block: (TableBuilder) -> Void) -> String { + let builder = TableBuilder() + + block(builder) + + let clauses: [Expressible?] = [ + create(Table.identifier, tableName(), temporary ? .Temporary : nil, ifNotExists), + "".wrap(builder.definitions) as Expression + ] + + return " ".join(clauses.flatMap { $0 }).asSQL() + } + + public func create(_ query: QueryType, temporary: Bool = false, ifNotExists: Bool = false) -> String { + let clauses: [Expressible?] = [ + create(Table.identifier, tableName(), temporary ? .Temporary : nil, ifNotExists), + Expression(literal: "AS"), + query + ] + + return " ".join(clauses.flatMap { $0 }).asSQL() + } + + // MARK: - ALTER TABLE … ADD COLUMN + + public func addColumn(_ name: Expression, check: Expression? = nil, defaultValue: V) -> String { + return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, nil)) + } + + public func addColumn(_ name: Expression, check: Expression, defaultValue: V) -> String { + return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, nil)) + } + + public func addColumn(_ name: Expression, check: Expression? = nil, defaultValue: V? = nil) -> String { + return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, nil)) + } + + public func addColumn(_ name: Expression, check: Expression, defaultValue: V? = nil) -> String { + return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, nil)) + } + + public func addColumn(_ name: Expression, unique: Bool = false, check: Expression? = nil, references table: QueryType, _ other: Expression) -> String where V.Datatype == Int64 { + return addColumn(definition(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil)) + } + + public func addColumn(_ name: Expression, unique: Bool = false, check: Expression, references table: QueryType, _ other: Expression) -> String where V.Datatype == Int64 { + return addColumn(definition(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil)) + } + + public func addColumn(_ name: Expression, unique: Bool = false, check: Expression? = nil, references table: QueryType, _ other: Expression) -> String where V.Datatype == Int64 { + return addColumn(definition(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil)) + } + + public func addColumn(_ name: Expression, unique: Bool = false, check: Expression, references table: QueryType, _ other: Expression) -> String where V.Datatype == Int64 { + return addColumn(definition(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil)) + } + + public func addColumn(_ name: Expression, check: Expression? = nil, defaultValue: V, collate: Collation) -> String where V.Datatype == String { + return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, collate)) + } + + public func addColumn(_ name: Expression, check: Expression, defaultValue: V, collate: Collation) -> String where V.Datatype == String { + return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, collate)) + } + + public func addColumn(_ name: Expression, check: Expression? = nil, defaultValue: V? = nil, collate: Collation) -> String where V.Datatype == String { + return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, collate)) + } + + public func addColumn(_ name: Expression, check: Expression, defaultValue: V? = nil, collate: Collation) -> String where V.Datatype == String { + return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, collate)) + } + + fileprivate func addColumn(_ expression: Expressible) -> String { + return " ".join([ + Expression(literal: "ALTER TABLE"), + tableName(), + Expression(literal: "ADD COLUMN"), + expression + ]).asSQL() + } + + // MARK: - ALTER TABLE … RENAME TO + + public func rename(_ to: Table) -> String { + return rename(to: to) + } + + // MARK: - CREATE INDEX + + public func createIndex(_ columns: Expressible...) -> String { + return createIndex(columns) + } + + public func createIndex(_ columns: [Expressible], unique: Bool = false, ifNotExists: Bool = false) -> String { + let clauses: [Expressible?] = [ + create("INDEX", indexName(columns), unique ? .Unique : nil, ifNotExists), + Expression(literal: "ON"), + tableName(qualified: false), + "".wrap(columns) as Expression + ] + + return " ".join(clauses.flatMap { $0 }).asSQL() + } + + // MARK: - DROP INDEX + + public func dropIndex(_ columns: Expressible...) -> String { + return dropIndex(columns) + } + + public func dropIndex(_ columns: [Expressible], ifExists: Bool = false) -> String { + return drop("INDEX", indexName(columns), ifExists) + } + + fileprivate func indexName(_ columns: [Expressible]) -> Expressible { + let string = (["index", clauses.from.name, "on"] + columns.map { $0.expression.template }).joined(separator: " ").lowercased() + + let index = string.characters.reduce("") { underscored, character in + guard character != "\"" else { + return underscored + } + guard "a"..."z" ~= character || "0"..."9" ~= character else { + return underscored + "_" + } + return underscored + String(character) + } + + return database(namespace: index) + } + +} + +extension View { + + // MARK: - CREATE VIEW + + public func create(_ query: QueryType, temporary: Bool = false, ifNotExists: Bool = false) -> String { + let clauses: [Expressible?] = [ + create(View.identifier, tableName(), temporary ? .Temporary : nil, ifNotExists), + Expression(literal: "AS"), + query + ] + + return " ".join(clauses.flatMap { $0 }).asSQL() + } + + // MARK: - DROP VIEW + + public func drop(ifExists: Bool = false) -> String { + return drop("VIEW", tableName(), ifExists) + } + +} + +extension VirtualTable { + + // MARK: - CREATE VIRTUAL TABLE + + public func create(_ using: Module, ifNotExists: Bool = false) -> String { + let clauses: [Expressible?] = [ + create(VirtualTable.identifier, tableName(), nil, ifNotExists), + Expression(literal: "USING"), + using + ] + + return " ".join(clauses.flatMap { $0 }).asSQL() + } + + // MARK: - ALTER TABLE … RENAME TO + + public func rename(_ to: VirtualTable) -> String { + return rename(to: to) + } + +} + +public final class TableBuilder { + + fileprivate var definitions = [Expressible]() + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression? = nil) { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: V) { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression? = nil) { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: V) { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression? = nil) { + column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression) { + column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: V) { + column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression? = nil) { + column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression) { + column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: V) { + column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, primaryKey: Bool, check: Expression? = nil, defaultValue: Expression? = nil) { + column(name, V.declaredDatatype, primaryKey ? .default : nil, false, false, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, primaryKey: Bool, check: Expression, defaultValue: Expression? = nil) { + column(name, V.declaredDatatype, primaryKey ? .default : nil, false, false, check, defaultValue, nil, nil) + } + + public func column(_ name: Expression, primaryKey: PrimaryKey, check: Expression? = nil) where V.Datatype == Int64 { + column(name, V.declaredDatatype, primaryKey, false, false, check, nil, nil, nil) + } + + public func column(_ name: Expression, primaryKey: PrimaryKey, check: Expression) where V.Datatype == Int64 { + column(name, V.declaredDatatype, primaryKey, false, false, check, nil, nil, nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, references table: QueryType, _ other: Expression) where V.Datatype == Int64 { + column(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, references table: QueryType, _ other: Expression) where V.Datatype == Int64 { + column(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, references table: QueryType, _ other: Expression) where V.Datatype == Int64 { + column(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, references table: QueryType, _ other: Expression) where V.Datatype == Int64 { + column(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression? = nil, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: V, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression? = nil, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: V, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression? = nil, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: V, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression? = nil, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: V, collate: Collation) where V.Datatype == String { + column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) + } + + fileprivate func column(_ name: Expressible, _ datatype: String, _ primaryKey: PrimaryKey?, _ null: Bool, _ unique: Bool, _ check: Expressible?, _ defaultValue: Expressible?, _ references: (QueryType, Expressible)?, _ collate: Collation?) { + definitions.append(definition(name, datatype, primaryKey, null, unique, check, defaultValue, references, collate)) + } + + // MARK: - + + public func primaryKey(_ column: Expression) { + primaryKey([column]) + } + + public func primaryKey(_ compositeA: Expression, _ b: Expression) { + primaryKey([compositeA, b]) + } + + public func primaryKey(_ compositeA: Expression, _ b: Expression, _ c: Expression) { + primaryKey([compositeA, b, c]) + } + + fileprivate func primaryKey(_ composite: [Expressible]) { + definitions.append("PRIMARY KEY".prefix(composite)) + } + + public func unique(_ columns: Expressible...) { + unique(columns) + } + + public func unique(_ columns: [Expressible]) { + definitions.append("UNIQUE".prefix(columns)) + } + + public func check(_ condition: Expression) { + check(Expression(condition)) + } + + public func check(_ condition: Expression) { + definitions.append("CHECK".prefix(condition)) + } + + public enum Dependency: String { + + case noAction = "NO ACTION" + + case restrict = "RESTRICT" + + case setNull = "SET NULL" + + case setDefault = "SET DEFAULT" + + case cascade = "CASCADE" + + } + + public func foreignKey(_ column: Expression, references table: QueryType, _ other: Expression, update: Dependency? = nil, delete: Dependency? = nil) { + foreignKey(column, (table, other), update, delete) + } + + public func foreignKey(_ column: Expression, references table: QueryType, _ other: Expression, update: Dependency? = nil, delete: Dependency? = nil) { + foreignKey(column, (table, other), update, delete) + } + + public func foreignKey(_ composite: (Expression, Expression), references table: QueryType, _ other: (Expression, Expression), update: Dependency? = nil, delete: Dependency? = nil) { + let composite = ", ".join([composite.0, composite.1]) + let references = (table, ", ".join([other.0, other.1])) + + foreignKey(composite, references, update, delete) + } + + public func foreignKey(_ composite: (Expression, Expression, Expression), references table: QueryType, _ other: (Expression, Expression, Expression), update: Dependency? = nil, delete: Dependency? = nil) { + let composite = ", ".join([composite.0, composite.1, composite.2]) + let references = (table, ", ".join([other.0, other.1, other.2])) + + foreignKey(composite, references, update, delete) + } + + fileprivate func foreignKey(_ column: Expressible, _ references: (QueryType, Expressible), _ update: Dependency?, _ delete: Dependency?) { + let clauses: [Expressible?] = [ + "FOREIGN KEY".prefix(column), + reference(references), + update.map { Expression(literal: "ON UPDATE \($0.rawValue)") }, + delete.map { Expression(literal: "ON DELETE \($0.rawValue)") } + ] + + definitions.append(" ".join(clauses.flatMap { $0 })) + } + +} + +public enum PrimaryKey { + + case `default` + + case autoincrement + +} + +public struct Module { + + fileprivate let name: String + + fileprivate let arguments: [Expressible] + + public init(_ name: String, _ arguments: [Expressible]) { + self.init(name: name.quote(), arguments: arguments) + } + + init(name: String, arguments: [Expressible]) { + self.name = name + self.arguments = arguments + } + +} + +extension Module : Expressible { + + public var expression: Expression { + return name.wrap(arguments) + } + +} + +// MARK: - Private + +private extension QueryType { + + func create(_ identifier: String, _ name: Expressible, _ modifier: Modifier?, _ ifNotExists: Bool) -> Expressible { + let clauses: [Expressible?] = [ + Expression(literal: "CREATE"), + modifier.map { Expression(literal: $0.rawValue) }, + Expression(literal: identifier), + ifNotExists ? Expression(literal: "IF NOT EXISTS") : nil, + name + ] + + return " ".join(clauses.flatMap { $0 }) + } + + func rename(to: Self) -> String { + return " ".join([ + Expression(literal: "ALTER TABLE"), + tableName(), + Expression(literal: "RENAME TO"), + Expression(to.clauses.from.name) + ]).asSQL() + } + + func drop(_ identifier: String, _ name: Expressible, _ ifExists: Bool) -> String { + let clauses: [Expressible?] = [ + Expression(literal: "DROP \(identifier)"), + ifExists ? Expression(literal: "IF EXISTS") : nil, + name + ] + + return " ".join(clauses.flatMap { $0 }).asSQL() + } + +} + +private func definition(_ column: Expressible, _ datatype: String, _ primaryKey: PrimaryKey?, _ null: Bool, _ unique: Bool, _ check: Expressible?, _ defaultValue: Expressible?, _ references: (QueryType, Expressible)?, _ collate: Collation?) -> Expressible { + let clauses: [Expressible?] = [ + column, + Expression(literal: datatype), + primaryKey.map { Expression(literal: $0 == .autoincrement ? "PRIMARY KEY AUTOINCREMENT" : "PRIMARY KEY") }, + null ? nil : Expression(literal: "NOT NULL"), + unique ? Expression(literal: "UNIQUE") : nil, + check.map { " ".join([Expression(literal: "CHECK"), $0]) }, + defaultValue.map { "DEFAULT".prefix($0) }, + references.map(reference), + collate.map { " ".join([Expression(literal: "COLLATE"), $0]) } + ] + + return " ".join(clauses.flatMap { $0 }) +} + +private func reference(_ primary: (QueryType, Expressible)) -> Expressible { + return " ".join([ + Expression(literal: "REFERENCES"), + primary.0.tableName(qualified: false), + "".wrap(primary.1) as Expression + ]) +} + +private enum Modifier : String { + + case Unique = "UNIQUE" + + case Temporary = "TEMPORARY" + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Setter.swift b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Setter.swift new file mode 100644 index 0000000000..86f16fcae3 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Setter.swift @@ -0,0 +1,277 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +precedencegroup ColumnAssignment { + associativity: left + assignment: true + lowerThan: AssignmentPrecedence +} + +infix operator <- : ColumnAssignment + +public struct Setter { + + let column: Expressible + let value: Expressible + + fileprivate init(column: Expression, value: Expression) { + self.column = column + self.value = value + } + + fileprivate init(column: Expression, value: V) { + self.column = column + self.value = value + } + + fileprivate init(column: Expression, value: Expression) { + self.column = column + self.value = value + } + + fileprivate init(column: Expression, value: Expression) { + self.column = column + self.value = value + } + + fileprivate init(column: Expression, value: V?) { + self.column = column + self.value = Expression(value: value) + } + +} + +extension Setter : Expressible { + + public var expression: Expression { + return "=".infix(column, value, wrap: false) + } + +} + +public func <-(column: Expression, value: Expression) -> Setter { + return Setter(column: column, value: value) +} +public func <-(column: Expression, value: V) -> Setter { + return Setter(column: column, value: value) +} +public func <-(column: Expression, value: Expression) -> Setter { + return Setter(column: column, value: value) +} +public func <-(column: Expression, value: Expression) -> Setter { + return Setter(column: column, value: value) +} +public func <-(column: Expression, value: V?) -> Setter { + return Setter(column: column, value: value) +} + +public func +=(column: Expression, value: Expression) -> Setter { + return column <- column + value +} +public func +=(column: Expression, value: String) -> Setter { + return column <- column + value +} +public func +=(column: Expression, value: Expression) -> Setter { + return column <- column + value +} +public func +=(column: Expression, value: Expression) -> Setter { + return column <- column + value +} +public func +=(column: Expression, value: String) -> Setter { + return column <- column + value +} + +public func +=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column + value +} +public func +=(column: Expression, value: V) -> Setter where V.Datatype : Number { + return column <- column + value +} +public func +=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column + value +} +public func +=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column + value +} +public func +=(column: Expression, value: V) -> Setter where V.Datatype : Number { + return column <- column + value +} + +public func -=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column - value +} +public func -=(column: Expression, value: V) -> Setter where V.Datatype : Number { + return column <- column - value +} +public func -=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column - value +} +public func -=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column - value +} +public func -=(column: Expression, value: V) -> Setter where V.Datatype : Number { + return column <- column - value +} + +public func *=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column * value +} +public func *=(column: Expression, value: V) -> Setter where V.Datatype : Number { + return column <- column * value +} +public func *=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column * value +} +public func *=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column * value +} +public func *=(column: Expression, value: V) -> Setter where V.Datatype : Number { + return column <- column * value +} + +public func /=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column / value +} +public func /=(column: Expression, value: V) -> Setter where V.Datatype : Number { + return column <- column / value +} +public func /=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column / value +} +public func /=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { + return column <- column / value +} +public func /=(column: Expression, value: V) -> Setter where V.Datatype : Number { + return column <- column / value +} + +public func %=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column % value +} +public func %=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column % value +} +public func %=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column % value +} +public func %=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column % value +} +public func %=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column % value +} + +public func <<=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column << value +} +public func <<=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column << value +} +public func <<=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column << value +} +public func <<=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column << value +} +public func <<=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column << value +} + +public func >>=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column >> value +} +public func >>=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column >> value +} +public func >>=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column >> value +} +public func >>=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column >> value +} +public func >>=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column >> value +} + +public func &=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column & value +} +public func &=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column & value +} +public func &=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column & value +} +public func &=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column & value +} +public func &=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column & value +} + +public func |=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column | value +} +public func |=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column | value +} +public func |=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column | value +} +public func |=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column | value +} +public func |=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column | value +} + +public func ^=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column ^ value +} +public func ^=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column ^ value +} +public func ^=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column ^ value +} +public func ^=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { + return column <- column ^ value +} +public func ^=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { + return column <- column ^ value +} + +public postfix func ++(column: Expression) -> Setter where V.Datatype == Int64 { + return Expression(column) += 1 +} +public postfix func ++(column: Expression) -> Setter where V.Datatype == Int64 { + return Expression(column) += 1 +} + +public postfix func --(column: Expression) -> Setter where V.Datatype == Int64 { + return Expression(column) -= 1 +} +public postfix func --(column: Expression) -> Setter where V.Datatype == Int64 { + return Expression(column) -= 1 +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/SQLite-Bridging.m b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/SQLite-Bridging.m new file mode 100644 index 0000000000..d8fe6b683c --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/SQLite-Bridging.m @@ -0,0 +1,138 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "SQLite-Bridging.h" +#import "fts3_tokenizer.h" + +#pragma mark - FTS + +typedef struct __SQLiteTokenizer { + sqlite3_tokenizer base; + __unsafe_unretained _SQLiteTokenizerNextCallback callback; +} __SQLiteTokenizer; + +typedef struct __SQLiteTokenizerCursor { + void * base; + const char * input; + int inputOffset; + int inputLength; + int idx; +} __SQLiteTokenizerCursor; + +static NSMutableDictionary * __SQLiteTokenizerMap; + +static int __SQLiteTokenizerCreate(int argc, const char * const * argv, sqlite3_tokenizer ** ppTokenizer) { + __SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)sqlite3_malloc(sizeof(__SQLiteTokenizer)); + if (!tokenizer) { + return SQLITE_NOMEM; + } + memset(tokenizer, 0, sizeof(* tokenizer)); + + NSString * key = [NSString stringWithUTF8String:argv[0]]; + tokenizer->callback = [__SQLiteTokenizerMap objectForKey:key]; + if (!tokenizer->callback) { + return SQLITE_ERROR; + } + + *ppTokenizer = &tokenizer->base; + return SQLITE_OK; +} + +static int __SQLiteTokenizerDestroy(sqlite3_tokenizer * pTokenizer) { + sqlite3_free(pTokenizer); + return SQLITE_OK; +} + +static int __SQLiteTokenizerOpen(sqlite3_tokenizer * pTokenizer, const char * pInput, int nBytes, sqlite3_tokenizer_cursor ** ppCursor) { + __SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)sqlite3_malloc(sizeof(__SQLiteTokenizerCursor)); + if (!cursor) { + return SQLITE_NOMEM; + } + + cursor->input = pInput; + cursor->inputOffset = 0; + cursor->inputLength = 0; + cursor->idx = 0; + + *ppCursor = (sqlite3_tokenizer_cursor *)cursor; + return SQLITE_OK; +} + +static int __SQLiteTokenizerClose(sqlite3_tokenizer_cursor * pCursor) { + sqlite3_free(pCursor); + return SQLITE_OK; +} + +static int __SQLiteTokenizerNext(sqlite3_tokenizer_cursor * pCursor, const char ** ppToken, int * pnBytes, int * piStartOffset, int * piEndOffset, int * piPosition) { + __SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)pCursor; + __SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)cursor->base; + + cursor->inputOffset += cursor->inputLength; + const char * input = cursor->input + cursor->inputOffset; + const char * token = [tokenizer->callback(input, &cursor->inputOffset, &cursor->inputLength) cStringUsingEncoding:NSUTF8StringEncoding]; + if (!token) { + return SQLITE_DONE; + } + + *ppToken = token; + *pnBytes = (int)strlen(token); + *piStartOffset = cursor->inputOffset; + *piEndOffset = cursor->inputOffset + cursor->inputLength; + *piPosition = cursor->idx++; + return SQLITE_OK; +} + +static const sqlite3_tokenizer_module __SQLiteTokenizerModule = { + 0, + __SQLiteTokenizerCreate, + __SQLiteTokenizerDestroy, + __SQLiteTokenizerOpen, + __SQLiteTokenizerClose, + __SQLiteTokenizerNext +}; + +int _SQLiteRegisterTokenizer(SQLiteHandle * db, const char * moduleName, const char * submoduleName, _SQLiteTokenizerNextCallback callback) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + __SQLiteTokenizerMap = [NSMutableDictionary new]; + }); + + sqlite3_stmt * stmt; + int status = sqlite3_prepare_v2((sqlite3 *)db, "SELECT fts3_tokenizer(?, ?)", -1, &stmt, 0); + if (status != SQLITE_OK ){ + return status; + } + const sqlite3_tokenizer_module * pModule = &__SQLiteTokenizerModule; + sqlite3_bind_text(stmt, 1, moduleName, -1, SQLITE_STATIC); + sqlite3_bind_blob(stmt, 2, &pModule, sizeof(pModule), SQLITE_STATIC); + sqlite3_step(stmt); + status = sqlite3_finalize(stmt); + if (status != SQLITE_OK ){ + return status; + } + + [__SQLiteTokenizerMap setObject:[callback copy] forKey:[NSString stringWithUTF8String:submoduleName]]; + + return SQLITE_OK; +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/fts3_tokenizer.h b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/fts3_tokenizer.h new file mode 100644 index 0000000000..d8a1e44b47 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/fts3_tokenizer.h @@ -0,0 +1,161 @@ +/* +** 2006 July 10 +** +** The author disclaims copyright to this source code. +** +************************************************************************* +** Defines the interface to tokenizers used by fulltext-search. There +** are three basic components: +** +** sqlite3_tokenizer_module is a singleton defining the tokenizer +** interface functions. This is essentially the class structure for +** tokenizers. +** +** sqlite3_tokenizer is used to define a particular tokenizer, perhaps +** including customization information defined at creation time. +** +** sqlite3_tokenizer_cursor is generated by a tokenizer to generate +** tokens from a particular input. +*/ +#ifndef _FTS3_TOKENIZER_H_ +#define _FTS3_TOKENIZER_H_ + +/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. +** If tokenizers are to be allowed to call sqlite3_*() functions, then +** we will need a way to register the API consistently. +*/ +#import "sqlite3.h" + +/* +** Structures used by the tokenizer interface. When a new tokenizer +** implementation is registered, the caller provides a pointer to +** an sqlite3_tokenizer_module containing pointers to the callback +** functions that make up an implementation. +** +** When an fts3 table is created, it passes any arguments passed to +** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the +** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer +** implementation. The xCreate() function in turn returns an +** sqlite3_tokenizer structure representing the specific tokenizer to +** be used for the fts3 table (customized by the tokenizer clause arguments). +** +** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() +** method is called. It returns an sqlite3_tokenizer_cursor object +** that may be used to tokenize a specific input buffer based on +** the tokenization rules supplied by a specific sqlite3_tokenizer +** object. +*/ +typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; +typedef struct sqlite3_tokenizer sqlite3_tokenizer; +typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; + +struct sqlite3_tokenizer_module { + + /* + ** Structure version. Should always be set to 0 or 1. + */ + int iVersion; + + /* + ** Create a new tokenizer. The values in the argv[] array are the + ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL + ** TABLE statement that created the fts3 table. For example, if + ** the following SQL is executed: + ** + ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) + ** + ** then argc is set to 2, and the argv[] array contains pointers + ** to the strings "arg1" and "arg2". + ** + ** This method should return either SQLITE_OK (0), or an SQLite error + ** code. If SQLITE_OK is returned, then *ppTokenizer should be set + ** to point at the newly created tokenizer structure. The generic + ** sqlite3_tokenizer.pModule variable should not be initialized by + ** this callback. The caller will do so. + */ + int (*xCreate)( + int argc, /* Size of argv array */ + const char *const*argv, /* Tokenizer argument strings */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ + ); + + /* + ** Destroy an existing tokenizer. The fts3 module calls this method + ** exactly once for each successful call to xCreate(). + */ + int (*xDestroy)(sqlite3_tokenizer *pTokenizer); + + /* + ** Create a tokenizer cursor to tokenize an input buffer. The caller + ** is responsible for ensuring that the input buffer remains valid + ** until the cursor is closed (using the xClose() method). + */ + int (*xOpen)( + sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ + const char *pInput, int nBytes, /* Input buffer */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ + ); + + /* + ** Destroy an existing tokenizer cursor. The fts3 module calls this + ** method exactly once for each successful call to xOpen(). + */ + int (*xClose)(sqlite3_tokenizer_cursor *pCursor); + + /* + ** Retrieve the next token from the tokenizer cursor pCursor. This + ** method should either return SQLITE_OK and set the values of the + ** "OUT" variables identified below, or SQLITE_DONE to indicate that + ** the end of the buffer has been reached, or an SQLite error code. + ** + ** *ppToken should be set to point at a buffer containing the + ** normalized version of the token (i.e. after any case-folding and/or + ** stemming has been performed). *pnBytes should be set to the length + ** of this buffer in bytes. The input text that generated the token is + ** identified by the byte offsets returned in *piStartOffset and + ** *piEndOffset. *piStartOffset should be set to the index of the first + ** byte of the token in the input buffer. *piEndOffset should be set + ** to the index of the first byte just past the end of the token in + ** the input buffer. + ** + ** The buffer *ppToken is set to point at is managed by the tokenizer + ** implementation. It is only required to be valid until the next call + ** to xNext() or xClose(). + */ + /* TODO(shess) current implementation requires pInput to be + ** nul-terminated. This should either be fixed, or pInput/nBytes + ** should be converted to zInput. + */ + int (*xNext)( + sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ + const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ + int *piStartOffset, /* OUT: Byte offset of token in input buffer */ + int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ + int *piPosition /* OUT: Number of tokens returned before this one */ + ); + + /*********************************************************************** + ** Methods below this point are only available if iVersion>=1. + */ + + /* + ** Configure the language id of a tokenizer cursor. + */ + int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); +}; + +struct sqlite3_tokenizer { + const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ + /* Tokenizer implementations will typically add additional fields */ +}; + +struct sqlite3_tokenizer_cursor { + sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ + /* Tokenizer implementations will typically add additional fields */ +}; + +int fts3_global_term_cnt(int iTerm, int iCol); +int fts3_term_cnt(int iTerm, int iCol); + + +#endif /* _FTS3_TOKENIZER_H_ */ diff --git a/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/include/SQLite-Bridging.h b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/include/SQLite-Bridging.h new file mode 100644 index 0000000000..d15e8d56d6 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/include/SQLite-Bridging.h @@ -0,0 +1,37 @@ +// +// SQLite.swift +// https://github.com/stephencelis/SQLite.swift +// Copyright © 2014-2015 Stephen Celis. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +@import Foundation; + +#ifndef COCOAPODS +#import "sqlite3.h" +#endif + +typedef struct SQLiteHandle SQLiteHandle; // CocoaPods workaround + +NS_ASSUME_NONNULL_BEGIN +typedef NSString * _Nullable (^_SQLiteTokenizerNextCallback)(const char * input, int * inputOffset, int * inputLength); +int _SQLiteRegisterTokenizer(SQLiteHandle * db, const char * module, const char * tokenizer, _Nullable _SQLiteTokenizerNextCallback callback); +NS_ASSUME_NONNULL_END + diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/.gitignore b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/.gitignore new file mode 100644 index 0000000000..4cf24de2ce --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/.gitignore @@ -0,0 +1 @@ +gems/ diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile new file mode 100644 index 0000000000..94018f18bd --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +gem 'cocoapods', '~> 1.1.0' +gem 'minitest' diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile.lock b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile.lock new file mode 100644 index 0000000000..e8879f13ca --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile.lock @@ -0,0 +1,74 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (2.3.3) + activesupport (4.2.7.1) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + claide (1.0.1) + cocoapods (1.1.1) + activesupport (>= 4.0.2, < 5) + claide (>= 1.0.1, < 2.0) + cocoapods-core (= 1.1.1) + cocoapods-deintegrate (>= 1.0.1, < 2.0) + cocoapods-downloader (>= 1.1.2, < 2.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-stats (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.1.1, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored (~> 1.2) + escape (~> 0.0.4) + fourflusher (~> 2.0.1) + gh_inspector (~> 1.0) + molinillo (~> 0.5.1) + nap (~> 1.0) + xcodeproj (>= 1.3.3, < 2.0) + cocoapods-core (1.1.1) + activesupport (>= 4.0.2, < 5) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + cocoapods-deintegrate (1.0.1) + cocoapods-downloader (1.1.2) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.0) + cocoapods-stats (1.0.0) + cocoapods-trunk (1.1.1) + nap (>= 0.8, < 2.0) + netrc (= 0.7.8) + cocoapods-try (1.1.0) + colored (1.2) + escape (0.0.4) + fourflusher (2.0.1) + fuzzy_match (2.0.4) + gh_inspector (1.0.2) + i18n (0.7.0) + json (1.8.3) + minitest (5.9.1) + molinillo (0.5.4) + nanaimo (0.2.2) + nap (1.1.0) + netrc (0.7.8) + thread_safe (0.3.5) + tzinfo (1.2.2) + thread_safe (~> 0.1) + xcodeproj (1.4.1) + CFPropertyList (~> 2.3.3) + activesupport (>= 3) + claide (>= 1.0.1, < 2.0) + colored (~> 1.2) + nanaimo (~> 0.2.0) + +PLATFORMS + ruby + +DEPENDENCIES + cocoapods (~> 1.1.0) + minitest + +BUNDLED WITH + 1.13.3 diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Makefile b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Makefile new file mode 100644 index 0000000000..26163fdbe1 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Makefile @@ -0,0 +1,13 @@ +test: install repo_update + @set -e; \ + for test in *_test.rb; do \ + bundle exec ./$$test; \ + done + +repo_update: + @bundle exec pod repo update --silent + +install: + @bundle install --path gems + +.PHONY: test install diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/integration_test.rb b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/integration_test.rb new file mode 100644 index 0000000000..192aff9032 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/integration_test.rb @@ -0,0 +1,43 @@ +#!/usr/bin/env ruby + +require 'minitest/autorun' +require_relative 'test_running_validator' + +class IntegrationTest < Minitest::Test + + def test_validate_project + assert validator.validate, "validation failed: #{validator.failure_reason}" + end + + private + + def validator + @validator ||= TestRunningValidator.new(podspec, []).tap do |validator| + validator.test_files = Dir["#{project_test_dir}/**/*.swift"] + validator.test_resources = Dir["#{project_test_dir}/fixtures"] + validator.config.verbose = true + validator.no_clean = true + validator.use_frameworks = true + validator.fail_fast = true + validator.local = true + validator.allow_warnings = true + subspec = ENV['VALIDATOR_SUBSPEC'] + if subspec == 'none' + validator.no_subspecs = true + else + validator.only_subspec = subspec + end + if ENV['IOS_SIMULATOR'] + validator.ios_simulator = ENV['IOS_SIMULATOR'] + end + end + end + + def podspec + File.expand_path(File.dirname(__FILE__) + '/../../SQLite.swift.podspec') + end + + def project_test_dir + File.expand_path(File.dirname(__FILE__) + '/../SQLiteTests') + end +end diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/test_running_validator.rb b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/test_running_validator.rb new file mode 100644 index 0000000000..fcfd3c28ef --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/test_running_validator.rb @@ -0,0 +1,120 @@ +require 'cocoapods' +require 'cocoapods/validator' +require 'fileutils' + +class TestRunningValidator < Pod::Validator + APP_TARGET = 'App' + TEST_TARGET = 'Tests' + + attr_accessor :test_files + attr_accessor :test_resources + attr_accessor :ios_simulator + attr_accessor :tvos_simulator + attr_accessor :watchos_simulator + + def initialize(spec_or_path, source_urls) + super(spec_or_path, source_urls) + self.test_files = [] + self.test_resources = [] + self.ios_simulator = :oldest + self.tvos_simulator = :oldest + self.watchos_simulator = :oldest + end + + def create_app_project + super + project = Xcodeproj::Project.open(validation_dir + "#{APP_TARGET}.xcodeproj") + create_test_target(project) + project.save + end + + def add_app_project_import + super + project = Xcodeproj::Project.open(validation_dir + 'App.xcodeproj') + group = project.new_group(TEST_TARGET) + test_target = project.targets.last + test_target.add_resources(test_resources.map { |resource| group.new_file(resource) }) + test_target.add_file_references(test_files.map { |file| group.new_file(file) }) + add_swift_version(test_target) + project.save + end + + def install_pod + super + if local? + FileUtils.ln_s file.dirname, validation_dir + "Pods/#{spec.name}" + end + end + + def podfile_from_spec(*args) + super(*args).tap do |pod_file| + add_test_target(pod_file) + end + end + + def build_pod + super + Pod::UI.message "\Testing with xcodebuild.\n".yellow do + run_tests + end + end + + private + def create_test_target(project) + test_target = project.new_target(:unit_test_bundle, TEST_TARGET, consumer.platform_name, deployment_target) + create_test_scheme(project, test_target) + end + + def create_test_scheme(project, test_target) + project.recreate_user_schemes + test_scheme = Xcodeproj::XCScheme.new(test_scheme_path(project)) + test_scheme.add_test_target(test_target) + test_scheme.save! + end + + def test_scheme_path(project) + Xcodeproj::XCScheme.user_data_dir(project.path) + "#{TEST_TARGET}.xcscheme" + end + + def add_test_target(pod_file) + app_target = pod_file.target_definitions[APP_TARGET] + Pod::Podfile::TargetDefinition.new(TEST_TARGET, app_target) + end + + def run_tests + command = [ + 'clean', 'build', 'build-for-testing', 'test-without-building', + '-workspace', File.join(validation_dir, "#{APP_TARGET}.xcworkspace"), + '-scheme', TEST_TARGET, + '-configuration', 'Debug' + ] + case consumer.platform_name + when :ios + command += %w(CODE_SIGN_IDENTITY=- -sdk iphonesimulator) + command += Fourflusher::SimControl.new.destination(ios_simulator, 'iOS', deployment_target) + when :osx + command += %w(LD_RUNPATH_SEARCH_PATHS=@loader_path/../Frameworks) + when :tvos + command += %w(CODE_SIGN_IDENTITY=- -sdk appletvsimulator) + command += Fourflusher::SimControl.new.destination(tvos_simulator, 'tvOS', deployment_target) + when :watchos + # there's no XCTest on watchOS (https://openradar.appspot.com/21760513) + return + else + return + end + + output, status = _xcodebuild(command) + + unless status.success? + message = 'Returned an unsuccessful exit code.' + if config.verbose? + message += "\nXcode output: \n#{output}\n" + else + message += ' You can use `--verbose` for more information.' + end + error('xcodebuild', message) + end + output + end +end diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/AggregateFunctionsTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/AggregateFunctionsTests.swift new file mode 100644 index 0000000000..6b583ccfa8 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/AggregateFunctionsTests.swift @@ -0,0 +1,68 @@ +import XCTest +import SQLite + +class AggregateFunctionsTests : XCTestCase { + + func test_distinct_prependsExpressionsWithDistinctKeyword() { + AssertSQL("DISTINCT \"int\"", int.distinct) + AssertSQL("DISTINCT \"intOptional\"", intOptional.distinct) + AssertSQL("DISTINCT \"double\"", double.distinct) + AssertSQL("DISTINCT \"doubleOptional\"", doubleOptional.distinct) + AssertSQL("DISTINCT \"string\"", string.distinct) + AssertSQL("DISTINCT \"stringOptional\"", stringOptional.distinct) + } + + func test_count_wrapsOptionalExpressionsWithCountFunction() { + AssertSQL("count(\"intOptional\")", intOptional.count) + AssertSQL("count(\"doubleOptional\")", doubleOptional.count) + AssertSQL("count(\"stringOptional\")", stringOptional.count) + } + + func test_max_wrapsComparableExpressionsWithMaxFunction() { + AssertSQL("max(\"int\")", int.max) + AssertSQL("max(\"intOptional\")", intOptional.max) + AssertSQL("max(\"double\")", double.max) + AssertSQL("max(\"doubleOptional\")", doubleOptional.max) + AssertSQL("max(\"string\")", string.max) + AssertSQL("max(\"stringOptional\")", stringOptional.max) + AssertSQL("max(\"date\")", date.max) + AssertSQL("max(\"dateOptional\")", dateOptional.max) + } + + func test_min_wrapsComparableExpressionsWithMinFunction() { + AssertSQL("min(\"int\")", int.min) + AssertSQL("min(\"intOptional\")", intOptional.min) + AssertSQL("min(\"double\")", double.min) + AssertSQL("min(\"doubleOptional\")", doubleOptional.min) + AssertSQL("min(\"string\")", string.min) + AssertSQL("min(\"stringOptional\")", stringOptional.min) + AssertSQL("min(\"date\")", date.min) + AssertSQL("min(\"dateOptional\")", dateOptional.min) + } + + func test_average_wrapsNumericExpressionsWithAvgFunction() { + AssertSQL("avg(\"int\")", int.average) + AssertSQL("avg(\"intOptional\")", intOptional.average) + AssertSQL("avg(\"double\")", double.average) + AssertSQL("avg(\"doubleOptional\")", doubleOptional.average) + } + + func test_sum_wrapsNumericExpressionsWithSumFunction() { + AssertSQL("sum(\"int\")", int.sum) + AssertSQL("sum(\"intOptional\")", intOptional.sum) + AssertSQL("sum(\"double\")", double.sum) + AssertSQL("sum(\"doubleOptional\")", doubleOptional.sum) + } + + func test_total_wrapsNumericExpressionsWithTotalFunction() { + AssertSQL("total(\"int\")", int.total) + AssertSQL("total(\"intOptional\")", intOptional.total) + AssertSQL("total(\"double\")", double.total) + AssertSQL("total(\"doubleOptional\")", doubleOptional.total) + } + + func test_count_withStar_wrapsStarWithCountFunction() { + AssertSQL("count(*)", count(*)) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/BlobTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/BlobTests.swift new file mode 100644 index 0000000000..fbcca9bcd9 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/BlobTests.swift @@ -0,0 +1,23 @@ +import XCTest +import SQLite + +class BlobTests : XCTestCase { + + func test_toHex() { + let blob = Blob(bytes: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 250, 255]) + + XCTAssertEqual(blob.toHex(), "000a141e28323c46505a6496faff") + } + + func test_init_array() { + let blob = Blob(bytes: [42, 42, 42]) + XCTAssertEqual(blob.bytes, [42, 42, 42]) + } + + func test_init_unsafeRawPointer() { + let pointer = UnsafeMutablePointer.allocate(capacity: 3) + pointer.initialize(to: 42, count: 3) + let blob = Blob(bytes: pointer, length: 3) + XCTAssertEqual(blob.bytes, [42, 42, 42]) + } +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CipherTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CipherTests.swift new file mode 100644 index 0000000000..3ee0b13511 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CipherTests.swift @@ -0,0 +1,98 @@ +#if SQLITE_SWIFT_SQLCIPHER +import XCTest +import SQLite +import SQLCipher + +class CipherTests: XCTestCase { + + let db1 = try! Connection() + let db2 = try! Connection() + + override func setUp() { + // db + + try! db1.key("hello") + + try! db1.run("CREATE TABLE foo (bar TEXT)") + try! db1.run("INSERT INTO foo (bar) VALUES ('world')") + + // db2 + let key2 = keyData() + try! db2.key(Blob(bytes: key2.bytes, length: key2.length)) + + try! db2.run("CREATE TABLE foo (bar TEXT)") + try! db2.run("INSERT INTO foo (bar) VALUES ('world')") + + super.setUp() + } + + func test_key() { + XCTAssertEqual(1, try! db1.scalar("SELECT count(*) FROM foo") as? Int64) + } + + func test_key_blob_literal() { + let db = try! Connection() + try! db.key("x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'") + } + + func test_rekey() { + try! db1.rekey("goodbye") + XCTAssertEqual(1, try! db1.scalar("SELECT count(*) FROM foo") as? Int64) + } + + func test_data_key() { + XCTAssertEqual(1, try! db2.scalar("SELECT count(*) FROM foo") as? Int64) + } + + func test_data_rekey() { + let newKey = keyData() + try! db2.rekey(Blob(bytes: newKey.bytes, length: newKey.length)) + XCTAssertEqual(1, try! db2.scalar("SELECT count(*) FROM foo") as? Int64) + } + + func test_keyFailure() { + let path = "\(NSTemporaryDirectory())/db.sqlite3" + _ = try? FileManager.default.removeItem(atPath: path) + + let connA = try! Connection(path) + defer { try! FileManager.default.removeItem(atPath: path) } + + try! connA.key("hello") + try! connA.run("CREATE TABLE foo (bar TEXT)") + + let connB = try! Connection(path, readonly: true) + + do { + try connB.key("world") + XCTFail("expected exception") + } catch Result.error(_, let code, _) { + XCTAssertEqual(SQLITE_NOTADB, code) + } catch { + XCTFail("unexpected error: \(error)") + } + } + + func test_open_db_encrypted_with_sqlcipher() { + // $ sqlcipher SQLiteTests/fixtures/encrypted.sqlite + // sqlite> pragma key = 'sqlcipher-test'; + // sqlite> CREATE TABLE foo (bar TEXT); + // sqlite> INSERT INTO foo (bar) VALUES ('world'); + let encryptedFile = fixture("encrypted", withExtension: "sqlite") + + try! FileManager.default.setAttributes([FileAttributeKey.immutable : 1], ofItemAtPath: encryptedFile) + XCTAssertFalse(FileManager.default.isWritableFile(atPath: encryptedFile)) + + let conn = try! Connection(encryptedFile) + try! conn.key("sqlcipher-test") + XCTAssertEqual(1, try! conn.scalar("SELECT count(*) FROM foo") as? Int64) + } + + private func keyData(length: Int = 64) -> NSMutableData { + let keyData = NSMutableData(length: length)! + let result = SecRandomCopyBytes(kSecRandomDefault, length, + keyData.mutableBytes.assumingMemoryBound(to: UInt8.self)) + XCTAssertEqual(0, result) + return keyData + } +} +#endif diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ConnectionTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ConnectionTests.swift new file mode 100644 index 0000000000..0db68b0d25 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ConnectionTests.swift @@ -0,0 +1,384 @@ +import XCTest +@testable import SQLite + +#if SQLITE_SWIFT_STANDALONE +import sqlite3 +#elseif SQLITE_SWIFT_SQLCIPHER +import SQLCipher +#else +import SQLite3 +#endif + +class ConnectionTests : SQLiteTestCase { + + override func setUp() { + super.setUp() + + CreateUsersTable() + } + + func test_init_withInMemory_returnsInMemoryConnection() { + let db = try! Connection(.inMemory) + XCTAssertEqual("", db.description) + } + + func test_init_returnsInMemoryByDefault() { + let db = try! Connection() + XCTAssertEqual("", db.description) + } + + func test_init_withTemporary_returnsTemporaryConnection() { + let db = try! Connection(.temporary) + XCTAssertEqual("", db.description) + } + + func test_init_withURI_returnsURIConnection() { + let db = try! Connection(.uri("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3")) + XCTAssertEqual("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3", db.description) + } + + func test_init_withString_returnsURIConnection() { + let db = try! Connection("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3") + XCTAssertEqual("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3", db.description) + } + + func test_readonly_returnsFalseOnReadWriteConnections() { + XCTAssertFalse(db.readonly) + } + + func test_readonly_returnsTrueOnReadOnlyConnections() { + let db = try! Connection(readonly: true) + XCTAssertTrue(db.readonly) + } + + func test_changes_returnsZeroOnNewConnections() { + XCTAssertEqual(0, db.changes) + } + + func test_lastInsertRowid_returnsLastIdAfterInserts() { + try! InsertUser("alice") + XCTAssertEqual(1, db.lastInsertRowid) + } + + func test_lastInsertRowid_doesNotResetAfterError() { + XCTAssert(db.lastInsertRowid == 0) + try! InsertUser("alice") + XCTAssertEqual(1, db.lastInsertRowid) + XCTAssertThrowsError( + try db.run("INSERT INTO \"users\" (email, age, admin) values ('invalid@example.com', 12, 'invalid')") + ) { error in + if case SQLite.Result.error(_, let code, _) = error { + XCTAssertEqual(SQLITE_CONSTRAINT, code) + } else { + XCTFail("expected error") + } + } + XCTAssertEqual(1, db.lastInsertRowid) + } + + func test_changes_returnsNumberOfChanges() { + try! InsertUser("alice") + XCTAssertEqual(1, db.changes) + try! InsertUser("betsy") + XCTAssertEqual(1, db.changes) + } + + func test_totalChanges_returnsTotalNumberOfChanges() { + XCTAssertEqual(0, db.totalChanges) + try! InsertUser("alice") + XCTAssertEqual(1, db.totalChanges) + try! InsertUser("betsy") + XCTAssertEqual(2, db.totalChanges) + } + + func test_prepare_preparesAndReturnsStatements() { + _ = try! db.prepare("SELECT * FROM users WHERE admin = 0") + _ = try! db.prepare("SELECT * FROM users WHERE admin = ?", 0) + _ = try! db.prepare("SELECT * FROM users WHERE admin = ?", [0]) + _ = try! db.prepare("SELECT * FROM users WHERE admin = $admin", ["$admin": 0]) + } + + func test_run_preparesRunsAndReturnsStatements() { + try! db.run("SELECT * FROM users WHERE admin = 0") + try! db.run("SELECT * FROM users WHERE admin = ?", 0) + try! db.run("SELECT * FROM users WHERE admin = ?", [0]) + try! db.run("SELECT * FROM users WHERE admin = $admin", ["$admin": 0]) + AssertSQL("SELECT * FROM users WHERE admin = 0", 4) + } + + func test_scalar_preparesRunsAndReturnsScalarValues() { + XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = 0") as? Int64) + XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = ?", 0) as? Int64) + XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = ?", [0]) as? Int64) + XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = $admin", ["$admin": 0]) as? Int64) + AssertSQL("SELECT count(*) FROM users WHERE admin = 0", 4) + } + + func test_execute_comment() { + try! db.run("-- this is a comment\nSELECT 1") + AssertSQL("-- this is a comment", 0) + AssertSQL("SELECT 1", 0) + } + + func test_transaction_executesBeginDeferred() { + try! db.transaction(.deferred) {} + + AssertSQL("BEGIN DEFERRED TRANSACTION") + } + + func test_transaction_executesBeginImmediate() { + try! db.transaction(.immediate) {} + + AssertSQL("BEGIN IMMEDIATE TRANSACTION") + } + + func test_transaction_executesBeginExclusive() { + try! db.transaction(.exclusive) {} + + AssertSQL("BEGIN EXCLUSIVE TRANSACTION") + } + + func test_transaction_beginsAndCommitsTransactions() { + let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com") + + try! db.transaction { + try stmt.run() + } + + AssertSQL("BEGIN DEFERRED TRANSACTION") + AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')") + AssertSQL("COMMIT TRANSACTION") + AssertSQL("ROLLBACK TRANSACTION", 0) + } + + func test_transaction_beginsAndRollsTransactionsBack() { + let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com") + + do { + try db.transaction { + try stmt.run() + try stmt.run() + } + } catch { + } + + AssertSQL("BEGIN DEFERRED TRANSACTION") + AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')", 2) + AssertSQL("ROLLBACK TRANSACTION") + AssertSQL("COMMIT TRANSACTION", 0) + } + + func test_savepoint_beginsAndCommitsSavepoints() { + let db = self.db + + try! db.savepoint("1") { + try db.savepoint("2") { + try db.run("INSERT INTO users (email) VALUES (?)", "alice@example.com") + } + } + + AssertSQL("SAVEPOINT '1'") + AssertSQL("SAVEPOINT '2'") + AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')") + AssertSQL("RELEASE SAVEPOINT '2'") + AssertSQL("RELEASE SAVEPOINT '1'") + AssertSQL("ROLLBACK TO SAVEPOINT '2'", 0) + AssertSQL("ROLLBACK TO SAVEPOINT '1'", 0) + } + + func test_savepoint_beginsAndRollsSavepointsBack() { + let db = self.db + let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com") + + do { + try db.savepoint("1") { + try db.savepoint("2") { + try stmt.run() + try stmt.run() + try stmt.run() + } + try db.savepoint("2") { + try stmt.run() + try stmt.run() + try stmt.run() + } + } + } catch { + } + + AssertSQL("SAVEPOINT '1'") + AssertSQL("SAVEPOINT '2'") + AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')", 2) + AssertSQL("ROLLBACK TO SAVEPOINT '2'") + AssertSQL("ROLLBACK TO SAVEPOINT '1'") + AssertSQL("RELEASE SAVEPOINT '2'", 0) + AssertSQL("RELEASE SAVEPOINT '1'", 0) + } + + func test_updateHook_setsUpdateHook_withInsert() { + async { done in + db.updateHook { operation, db, table, rowid in + XCTAssertEqual(Connection.Operation.insert, operation) + XCTAssertEqual("main", db) + XCTAssertEqual("users", table) + XCTAssertEqual(1, rowid) + done() + } + try! InsertUser("alice") + } + } + + func test_updateHook_setsUpdateHook_withUpdate() { + try! InsertUser("alice") + async { done in + db.updateHook { operation, db, table, rowid in + XCTAssertEqual(Connection.Operation.update, operation) + XCTAssertEqual("main", db) + XCTAssertEqual("users", table) + XCTAssertEqual(1, rowid) + done() + } + try! db.run("UPDATE users SET email = 'alice@example.com'") + } + } + + func test_updateHook_setsUpdateHook_withDelete() { + try! InsertUser("alice") + async { done in + db.updateHook { operation, db, table, rowid in + XCTAssertEqual(Connection.Operation.delete, operation) + XCTAssertEqual("main", db) + XCTAssertEqual("users", table) + XCTAssertEqual(1, rowid) + done() + } + try! db.run("DELETE FROM users WHERE id = 1") + } + } + + func test_commitHook_setsCommitHook() { + async { done in + db.commitHook { + done() + } + try! db.transaction { + try self.InsertUser("alice") + } + XCTAssertEqual(1, try! db.scalar("SELECT count(*) FROM users") as? Int64) + } + } + + func test_rollbackHook_setsRollbackHook() { + async { done in + db.rollbackHook(done) + do { + try db.transaction { + try self.InsertUser("alice") + try self.InsertUser("alice") // throw + } + } catch { + } + XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users") as? Int64) + } + } + + func test_commitHook_withRollback_rollsBack() { + async { done in + db.commitHook { + throw NSError(domain: "com.stephencelis.SQLiteTests", code: 1, userInfo: nil) + } + db.rollbackHook(done) + do { + try db.transaction { + try self.InsertUser("alice") + } + } catch { + } + XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users") as? Int64) + } + } + + func test_createFunction_withArrayArguments() { + db.createFunction("hello") { $0[0].map { "Hello, \($0)!" } } + + XCTAssertEqual("Hello, world!", try! db.scalar("SELECT hello('world')") as? String) + XCTAssert(try! db.scalar("SELECT hello(NULL)") == nil) + } + + func test_createFunction_createsQuotableFunction() { + db.createFunction("hello world") { $0[0].map { "Hello, \($0)!" } } + + XCTAssertEqual("Hello, world!", try! db.scalar("SELECT \"hello world\"('world')") as? String) + XCTAssert(try! db.scalar("SELECT \"hello world\"(NULL)") == nil) + } + + func test_createCollation_createsCollation() { + try! db.createCollation("NODIACRITIC") { lhs, rhs in + return lhs.compare(rhs, options: .diacriticInsensitive) + } + XCTAssertEqual(1, try! db.scalar("SELECT ? = ? COLLATE NODIACRITIC", "cafe", "café") as? Int64) + } + + func test_createCollation_createsQuotableCollation() { + try! db.createCollation("NO DIACRITIC") { lhs, rhs in + return lhs.compare(rhs, options: .diacriticInsensitive) + } + XCTAssertEqual(1, try! db.scalar("SELECT ? = ? COLLATE \"NO DIACRITIC\"", "cafe", "café") as? Int64) + } + + func test_interrupt_interruptsLongRunningQuery() { + try! InsertUsers("abcdefghijklmnopqrstuvwxyz".characters.map { String($0) }) + db.createFunction("sleep") { args in + usleep(UInt32((args[0] as? Double ?? Double(args[0] as? Int64 ?? 1)) * 1_000_000)) + return nil + } + + let stmt = try! db.prepare("SELECT *, sleep(?) FROM users", 0.1) + try! stmt.run() + + let deadline = DispatchTime.now() + Double(Int64(10 * NSEC_PER_MSEC)) / Double(NSEC_PER_SEC) + _ = DispatchQueue.global(priority: .background).asyncAfter(deadline: deadline, execute: db.interrupt) + AssertThrows(try stmt.run()) + } + +} + + +class ResultTests : XCTestCase { + let connection = try! Connection(.inMemory) + + func test_init_with_ok_code_returns_nil() { + XCTAssertNil(Result(errorCode: SQLITE_OK, connection: connection, statement: nil) as Result?) + } + + func test_init_with_row_code_returns_nil() { + XCTAssertNil(Result(errorCode: SQLITE_ROW, connection: connection, statement: nil) as Result?) + } + + func test_init_with_done_code_returns_nil() { + XCTAssertNil(Result(errorCode: SQLITE_DONE, connection: connection, statement: nil) as Result?) + } + + func test_init_with_other_code_returns_error() { + if case .some(.error(let message, let code, let statement)) = + Result(errorCode: SQLITE_MISUSE, connection: connection, statement: nil) { + XCTAssertEqual("not an error", message) + XCTAssertEqual(SQLITE_MISUSE, code) + XCTAssertNil(statement) + XCTAssert(self.connection === connection) + } else { + XCTFail() + } + } + + func test_description_contains_error_code() { + XCTAssertEqual("not an error (code: 21)", + Result(errorCode: SQLITE_MISUSE, connection: connection, statement: nil)?.description) + } + + func test_description_contains_statement_and_error_code() { + let statement = try! Statement(connection, "SELECT 1") + XCTAssertEqual("not an error (SELECT 1) (code: 21)", + Result(errorCode: SQLITE_MISUSE, connection: connection, statement: statement)?.description) + } +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CoreFunctionsTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CoreFunctionsTests.swift new file mode 100644 index 0000000000..db37ff7ff0 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CoreFunctionsTests.swift @@ -0,0 +1,136 @@ +import XCTest +import SQLite + +class CoreFunctionsTests : XCTestCase { + + func test_round_wrapsDoubleExpressionsWithRoundFunction() { + AssertSQL("round(\"double\")", double.round()) + AssertSQL("round(\"doubleOptional\")", doubleOptional.round()) + + AssertSQL("round(\"double\", 1)", double.round(1)) + AssertSQL("round(\"doubleOptional\", 2)", doubleOptional.round(2)) + } + + func test_random_generatesExpressionWithRandomFunction() { + AssertSQL("random()", Expression.random()) + AssertSQL("random()", Expression.random()) + } + + func test_length_wrapsStringExpressionWithLengthFunction() { + AssertSQL("length(\"string\")", string.length) + AssertSQL("length(\"stringOptional\")", stringOptional.length) + } + + func test_lowercaseString_wrapsStringExpressionWithLowerFunction() { + AssertSQL("lower(\"string\")", string.lowercaseString) + AssertSQL("lower(\"stringOptional\")", stringOptional.lowercaseString) + } + + func test_uppercaseString_wrapsStringExpressionWithUpperFunction() { + AssertSQL("upper(\"string\")", string.uppercaseString) + AssertSQL("upper(\"stringOptional\")", stringOptional.uppercaseString) + } + + func test_like_buildsExpressionWithLikeOperator() { + AssertSQL("(\"string\" LIKE 'a%')", string.like("a%")) + AssertSQL("(\"stringOptional\" LIKE 'b%')", stringOptional.like("b%")) + + AssertSQL("(\"string\" LIKE '%\\%' ESCAPE '\\')", string.like("%\\%", escape: "\\")) + AssertSQL("(\"stringOptional\" LIKE '_\\_' ESCAPE '\\')", stringOptional.like("_\\_", escape: "\\")) + } + + func test_glob_buildsExpressionWithGlobOperator() { + AssertSQL("(\"string\" GLOB 'a*')", string.glob("a*")) + AssertSQL("(\"stringOptional\" GLOB 'b*')", stringOptional.glob("b*")) + } + + func test_match_buildsExpressionWithMatchOperator() { + AssertSQL("(\"string\" MATCH 'a*')", string.match("a*")) + AssertSQL("(\"stringOptional\" MATCH 'b*')", stringOptional.match("b*")) + } + + func test_regexp_buildsExpressionWithRegexpOperator() { + AssertSQL("(\"string\" REGEXP '^.+@.+\\.com$')", string.regexp("^.+@.+\\.com$")) + AssertSQL("(\"stringOptional\" REGEXP '^.+@.+\\.net$')", stringOptional.regexp("^.+@.+\\.net$")) + } + + func test_collate_buildsExpressionWithCollateOperator() { + AssertSQL("(\"string\" COLLATE BINARY)", string.collate(.binary)) + AssertSQL("(\"string\" COLLATE NOCASE)", string.collate(.nocase)) + AssertSQL("(\"string\" COLLATE RTRIM)", string.collate(.rtrim)) + AssertSQL("(\"string\" COLLATE \"CUSTOM\")", string.collate(.custom("CUSTOM"))) + + AssertSQL("(\"stringOptional\" COLLATE BINARY)", stringOptional.collate(.binary)) + AssertSQL("(\"stringOptional\" COLLATE NOCASE)", stringOptional.collate(.nocase)) + AssertSQL("(\"stringOptional\" COLLATE RTRIM)", stringOptional.collate(.rtrim)) + AssertSQL("(\"stringOptional\" COLLATE \"CUSTOM\")", stringOptional.collate(.custom("CUSTOM"))) + } + + func test_ltrim_wrapsStringWithLtrimFunction() { + AssertSQL("ltrim(\"string\")", string.ltrim()) + AssertSQL("ltrim(\"stringOptional\")", stringOptional.ltrim()) + + AssertSQL("ltrim(\"string\", ' ')", string.ltrim([" "])) + AssertSQL("ltrim(\"stringOptional\", ' ')", stringOptional.ltrim([" "])) + } + + func test_ltrim_wrapsStringWithRtrimFunction() { + AssertSQL("rtrim(\"string\")", string.rtrim()) + AssertSQL("rtrim(\"stringOptional\")", stringOptional.rtrim()) + + AssertSQL("rtrim(\"string\", ' ')", string.rtrim([" "])) + AssertSQL("rtrim(\"stringOptional\", ' ')", stringOptional.rtrim([" "])) + } + + func test_ltrim_wrapsStringWithTrimFunction() { + AssertSQL("trim(\"string\")", string.trim()) + AssertSQL("trim(\"stringOptional\")", stringOptional.trim()) + + AssertSQL("trim(\"string\", ' ')", string.trim([" "])) + AssertSQL("trim(\"stringOptional\", ' ')", stringOptional.trim([" "])) + } + + func test_replace_wrapsStringWithReplaceFunction() { + AssertSQL("replace(\"string\", '@example.com', '@example.net')", string.replace("@example.com", with: "@example.net")) + AssertSQL("replace(\"stringOptional\", '@example.net', '@example.com')", stringOptional.replace("@example.net", with: "@example.com")) + } + + func test_substring_wrapsStringWithSubstrFunction() { + AssertSQL("substr(\"string\", 1, 2)", string.substring(1, length: 2)) + AssertSQL("substr(\"stringOptional\", 2, 1)", stringOptional.substring(2, length: 1)) + } + + func test_subscriptWithRange_wrapsStringWithSubstrFunction() { + AssertSQL("substr(\"string\", 1, 2)", string[1..<3]) + AssertSQL("substr(\"stringOptional\", 2, 1)", stringOptional[2..<3]) + } + + func test_nilCoalescingOperator_wrapsOptionalsWithIfnullFunction() { + AssertSQL("ifnull(\"intOptional\", 1)", intOptional ?? 1) + // AssertSQL("ifnull(\"doubleOptional\", 1.0)", doubleOptional ?? 1) // rdar://problem/21677256 + XCTAssertEqual("ifnull(\"doubleOptional\", 1.0)", (doubleOptional ?? 1).asSQL()) + AssertSQL("ifnull(\"stringOptional\", 'literal')", stringOptional ?? "literal") + + AssertSQL("ifnull(\"intOptional\", \"int\")", intOptional ?? int) + AssertSQL("ifnull(\"doubleOptional\", \"double\")", doubleOptional ?? double) + AssertSQL("ifnull(\"stringOptional\", \"string\")", stringOptional ?? string) + + AssertSQL("ifnull(\"intOptional\", \"intOptional\")", intOptional ?? intOptional) + AssertSQL("ifnull(\"doubleOptional\", \"doubleOptional\")", doubleOptional ?? doubleOptional) + AssertSQL("ifnull(\"stringOptional\", \"stringOptional\")", stringOptional ?? stringOptional) + } + + func test_absoluteValue_wrapsNumberWithAbsFucntion() { + AssertSQL("abs(\"int\")", int.absoluteValue) + AssertSQL("abs(\"intOptional\")", intOptional.absoluteValue) + + AssertSQL("abs(\"double\")", double.absoluteValue) + AssertSQL("abs(\"doubleOptional\")", doubleOptional.absoluteValue) + } + + func test_contains_buildsExpressionWithInOperator() { + AssertSQL("(\"string\" IN ('hello', 'world'))", ["hello", "world"].contains(string)) + AssertSQL("(\"stringOptional\" IN ('hello', 'world'))", ["hello", "world"].contains(stringOptional)) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CustomFunctionsTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CustomFunctionsTests.swift new file mode 100644 index 0000000000..67150ccf20 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CustomFunctionsTests.swift @@ -0,0 +1,6 @@ +import XCTest +import SQLite + +class CustomFunctionsTests : XCTestCase { + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ExpressionTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ExpressionTests.swift new file mode 100644 index 0000000000..036e10ceb6 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ExpressionTests.swift @@ -0,0 +1,6 @@ +import XCTest +import SQLite + +class ExpressionTests : XCTestCase { + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS4Tests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS4Tests.swift new file mode 100644 index 0000000000..4373bf8b0e --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS4Tests.swift @@ -0,0 +1,208 @@ +import XCTest +import SQLite + +class FTS4Tests : XCTestCase { + + func test_create_onVirtualTable_withFTS4_compilesCreateVirtualTableExpression() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4()", + virtualTable.create(.FTS4()) + ) + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\")", + virtualTable.create(.FTS4(string)) + ) + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=simple)", + virtualTable.create(.FTS4(tokenize: .Simple)) + ) + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", tokenize=porter)", + virtualTable.create(.FTS4([string], tokenize: .Porter)) + ) + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=0\")", + virtualTable.create(.FTS4(tokenize: .Unicode61(removeDiacritics: false))) + ) + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")", + virtualTable.create(.FTS4(tokenize: .Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"]))) + ) + } + + func test_match_onVirtualTableAsExpression_compilesMatchExpression() { + AssertSQL("(\"virtual_table\" MATCH 'string')", virtualTable.match("string") as Expression) + AssertSQL("(\"virtual_table\" MATCH \"string\")", virtualTable.match(string) as Expression) + AssertSQL("(\"virtual_table\" MATCH \"stringOptional\")", virtualTable.match(stringOptional) as Expression) + } + + func test_match_onVirtualTableAsQueryType_compilesMatchExpression() { + AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH 'string')", virtualTable.match("string") as QueryType) + AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH \"string\")", virtualTable.match(string) as QueryType) + AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH \"stringOptional\")", virtualTable.match(stringOptional) as QueryType) + } + +} + +class FTS4ConfigTests : XCTestCase { + var config: FTS4Config! + + override func setUp() { + super.setUp() + config = FTS4Config() + } + + func test_empty_config() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4()", + sql(config)) + } + + func test_config_column() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\")", + sql(config.column(string))) + } + + func test_config_columns() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", \"int\")", + sql(config.columns([string, int]))) + } + + func test_config_unindexed_column() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", notindexed=\"string\")", + sql(config.column(string, [.unindexed]))) + } + + func test_external_content_view() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"view\")", + sql(config.externalContent(_view ))) + } + + func test_external_content_virtual_table() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"virtual_table\")", + sql(config.externalContent(virtualTable))) + } + + func test_tokenizer_simple() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=simple)", + sql(config.tokenizer(.Simple))) + } + + func test_tokenizer_porter() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=porter)", + sql(config.tokenizer(.Porter))) + } + + func test_tokenizer_unicode61() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61)", + sql(config.tokenizer(.Unicode61()))) + } + + func test_tokenizer_unicode61_with_options() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")", + sql(config.tokenizer(.Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"])))) + } + + func test_content_less() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"\")", + sql(config.contentless())) + } + + func test_config_matchinfo() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(matchinfo=\"fts3\")", + sql(config.matchInfo(.fts3))) + } + + func test_config_order_asc() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(order=\"asc\")", + sql(config.order(.asc))) + } + + func test_config_order_desc() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(order=\"desc\")", + sql(config.order(.desc))) + } + + func test_config_compress() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(compress=\"compress_foo\")", + sql(config.compress("compress_foo"))) + } + + func test_config_uncompress() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(uncompress=\"uncompress_foo\")", + sql(config.uncompress("uncompress_foo"))) + } + + func test_config_languageId() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(languageid=\"lid\")", + sql(config.languageId("lid"))) + } + + func test_config_all() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"int\", \"string\", \"date\", tokenize=porter, prefix=\"2,4\", content=\"table\", notindexed=\"string\", notindexed=\"date\", languageid=\"lid\", matchinfo=\"fts3\", order=\"desc\")", + sql(config + .tokenizer(.Porter) + .column(int) + .column(string, [.unindexed]) + .column(date, [.unindexed]) + .externalContent(table) + .matchInfo(.fts3) + .languageId("lid") + .order(.desc) + .prefix([2, 4])) + ) + } + + func sql(_ config: FTS4Config) -> String { + return virtualTable.create(.FTS4(config)) + } +} + +class FTS4IntegrationTests : SQLiteTestCase { +#if !SQLITE_SWIFT_STANDALONE && !SQLITE_SWIFT_SQLCIPHER + func test_registerTokenizer_registersTokenizer() { + let emails = VirtualTable("emails") + let subject = Expression("subject") + let body = Expression("body") + + let locale = CFLocaleCopyCurrent() + let tokenizerName = "tokenizer" + let tokenizer = CFStringTokenizerCreate(nil, "" as CFString!, CFRangeMake(0, 0), UInt(kCFStringTokenizerUnitWord), locale) + try! db.registerTokenizer(tokenizerName) { string in + CFStringTokenizerSetString(tokenizer, string as CFString, CFRangeMake(0, CFStringGetLength(string as CFString))) + if CFStringTokenizerAdvanceToNextToken(tokenizer).isEmpty { + return nil + } + let range = CFStringTokenizerGetCurrentTokenRange(tokenizer) + let input = CFStringCreateWithSubstring(kCFAllocatorDefault, string as CFString, range)! + let token = CFStringCreateMutableCopy(nil, range.length, input)! + CFStringLowercase(token, locale) + CFStringTransform(token, nil, kCFStringTransformStripDiacritics, false) + return (token as String, string.range(of: input as String)!) + } + + try! db.run(emails.create(.FTS4([subject, body], tokenize: .Custom(tokenizerName)))) + AssertSQL("CREATE VIRTUAL TABLE \"emails\" USING fts4(\"subject\", \"body\", tokenize=\"SQLite.swift\" \"tokenizer\")") + + try! _ = db.run(emails.insert(subject <- "Aún más cáfe!")) + XCTAssertEqual(1, try! db.scalar(emails.filter(emails.match("aun")).count)) + } +#endif +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS5Tests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS5Tests.swift new file mode 100644 index 0000000000..63d8dc4043 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS5Tests.swift @@ -0,0 +1,124 @@ +import XCTest +import SQLite + +class FTS5Tests: XCTestCase { + var config: FTS5Config! + + override func setUp() { + super.setUp() + config = FTS5Config() + } + + func test_empty_config() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5()", + sql(config)) + } + + func test_config_column() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\")", + sql(config.column(string))) + } + + func test_config_columns() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\", \"int\")", + sql(config.columns([string, int]))) + } + + func test_config_unindexed_column() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\" UNINDEXED)", + sql(config.column(string, [.unindexed]))) + } + + func test_external_content_table() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"table\")", + sql(config.externalContent(table))) + } + + func test_external_content_view() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"view\")", + sql(config.externalContent(_view))) + } + + func test_external_content_virtual_table() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"virtual_table\")", + sql(config.externalContent(virtualTable))) + } + + func test_content_less() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"\")", + sql(config.contentless())) + } + + func test_content_rowid() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content_rowid=\"string\")", + sql(config.contentRowId(string))) + } + + func test_tokenizer_porter() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=porter)", + sql(config.tokenizer(.Porter))) + } + + func test_tokenizer_unicode61() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=unicode61)", + sql(config.tokenizer(.Unicode61()))) + } + + func test_tokenizer_unicode61_with_options() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")", + sql(config.tokenizer(.Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"])))) + } + + func test_column_size() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(columnsize=1)", + sql(config.columnSize(1))) + } + + func test_detail_full() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"full\")", + sql(config.detail(.full))) + } + + func test_detail_column() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"column\")", + sql(config.detail(.column))) + } + + func test_detail_none() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"none\")", + sql(config.detail(.none))) + } + + func test_fts5_config_all() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"int\", \"string\" UNINDEXED, \"date\" UNINDEXED, tokenize=porter, prefix=\"2,4\", content=\"table\")", + sql(config + .tokenizer(.Porter) + .column(int) + .column(string, [.unindexed]) + .column(date, [.unindexed]) + .externalContent(table) + .prefix([2, 4])) + ) + } + + func sql(_ config: FTS5Config) -> String { + return virtualTable.create(.FTS5(config)) + } +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Fixtures.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Fixtures.swift new file mode 100644 index 0000000000..13f83f7715 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Fixtures.swift @@ -0,0 +1,8 @@ +import Foundation + +func fixture(_ name: String, withExtension: String?) -> String { + let testBundle = Bundle(for: SQLiteTestCase.self) + return testBundle.url( + forResource: URL(string: "fixtures")?.appendingPathComponent(name).path, + withExtension: withExtension)!.path +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FoundationTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FoundationTests.swift new file mode 100644 index 0000000000..0df746d9e5 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FoundationTests.swift @@ -0,0 +1,16 @@ +import XCTest +import SQLite + +class FoundationTests : XCTestCase { + func testDataFromBlob() { + let data = Data(bytes: [1, 2, 3]) + let blob = data.datatypeValue + XCTAssertEqual([1, 2, 3], blob.bytes) + } + + func testBlobToData() { + let blob = Blob(bytes: [1, 2, 3]) + let data = Data.fromDatatypeValue(blob) + XCTAssertEqual(Data(bytes: [1, 2, 3]), data) + } +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Info.plist b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Info.plist new file mode 100644 index 0000000000..ba72822e87 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/OperatorsTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/OperatorsTests.swift new file mode 100644 index 0000000000..f0e585cd70 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/OperatorsTests.swift @@ -0,0 +1,296 @@ +import XCTest +import SQLite + +class OperatorsTests : XCTestCase { + + func test_stringExpressionPlusStringExpression_buildsConcatenatingStringExpression() { + AssertSQL("(\"string\" || \"string\")", string + string) + AssertSQL("(\"string\" || \"stringOptional\")", string + stringOptional) + AssertSQL("(\"stringOptional\" || \"string\")", stringOptional + string) + AssertSQL("(\"stringOptional\" || \"stringOptional\")", stringOptional + stringOptional) + AssertSQL("(\"string\" || 'literal')", string + "literal") + AssertSQL("(\"stringOptional\" || 'literal')", stringOptional + "literal") + AssertSQL("('literal' || \"string\")", "literal" + string) + AssertSQL("('literal' || \"stringOptional\")", "literal" + stringOptional) + } + + func test_numberExpression_plusNumberExpression_buildsAdditiveNumberExpression() { + AssertSQL("(\"int\" + \"int\")", int + int) + AssertSQL("(\"int\" + \"intOptional\")", int + intOptional) + AssertSQL("(\"intOptional\" + \"int\")", intOptional + int) + AssertSQL("(\"intOptional\" + \"intOptional\")", intOptional + intOptional) + AssertSQL("(\"int\" + 1)", int + 1) + AssertSQL("(\"intOptional\" + 1)", intOptional + 1) + AssertSQL("(1 + \"int\")", 1 + int) + AssertSQL("(1 + \"intOptional\")", 1 + intOptional) + + AssertSQL("(\"double\" + \"double\")", double + double) + AssertSQL("(\"double\" + \"doubleOptional\")", double + doubleOptional) + AssertSQL("(\"doubleOptional\" + \"double\")", doubleOptional + double) + AssertSQL("(\"doubleOptional\" + \"doubleOptional\")", doubleOptional + doubleOptional) + AssertSQL("(\"double\" + 1.0)", double + 1) + AssertSQL("(\"doubleOptional\" + 1.0)", doubleOptional + 1) + AssertSQL("(1.0 + \"double\")", 1 + double) + AssertSQL("(1.0 + \"doubleOptional\")", 1 + doubleOptional) + } + + func test_numberExpression_minusNumberExpression_buildsSubtractiveNumberExpression() { + AssertSQL("(\"int\" - \"int\")", int - int) + AssertSQL("(\"int\" - \"intOptional\")", int - intOptional) + AssertSQL("(\"intOptional\" - \"int\")", intOptional - int) + AssertSQL("(\"intOptional\" - \"intOptional\")", intOptional - intOptional) + AssertSQL("(\"int\" - 1)", int - 1) + AssertSQL("(\"intOptional\" - 1)", intOptional - 1) + AssertSQL("(1 - \"int\")", 1 - int) + AssertSQL("(1 - \"intOptional\")", 1 - intOptional) + + AssertSQL("(\"double\" - \"double\")", double - double) + AssertSQL("(\"double\" - \"doubleOptional\")", double - doubleOptional) + AssertSQL("(\"doubleOptional\" - \"double\")", doubleOptional - double) + AssertSQL("(\"doubleOptional\" - \"doubleOptional\")", doubleOptional - doubleOptional) + AssertSQL("(\"double\" - 1.0)", double - 1) + AssertSQL("(\"doubleOptional\" - 1.0)", doubleOptional - 1) + AssertSQL("(1.0 - \"double\")", 1 - double) + AssertSQL("(1.0 - \"doubleOptional\")", 1 - doubleOptional) + } + + func test_numberExpression_timesNumberExpression_buildsMultiplicativeNumberExpression() { + AssertSQL("(\"int\" * \"int\")", int * int) + AssertSQL("(\"int\" * \"intOptional\")", int * intOptional) + AssertSQL("(\"intOptional\" * \"int\")", intOptional * int) + AssertSQL("(\"intOptional\" * \"intOptional\")", intOptional * intOptional) + AssertSQL("(\"int\" * 1)", int * 1) + AssertSQL("(\"intOptional\" * 1)", intOptional * 1) + AssertSQL("(1 * \"int\")", 1 * int) + AssertSQL("(1 * \"intOptional\")", 1 * intOptional) + + AssertSQL("(\"double\" * \"double\")", double * double) + AssertSQL("(\"double\" * \"doubleOptional\")", double * doubleOptional) + AssertSQL("(\"doubleOptional\" * \"double\")", doubleOptional * double) + AssertSQL("(\"doubleOptional\" * \"doubleOptional\")", doubleOptional * doubleOptional) + AssertSQL("(\"double\" * 1.0)", double * 1) + AssertSQL("(\"doubleOptional\" * 1.0)", doubleOptional * 1) + AssertSQL("(1.0 * \"double\")", 1 * double) + AssertSQL("(1.0 * \"doubleOptional\")", 1 * doubleOptional) + } + + func test_numberExpression_dividedByNumberExpression_buildsDivisiveNumberExpression() { + AssertSQL("(\"int\" / \"int\")", int / int) + AssertSQL("(\"int\" / \"intOptional\")", int / intOptional) + AssertSQL("(\"intOptional\" / \"int\")", intOptional / int) + AssertSQL("(\"intOptional\" / \"intOptional\")", intOptional / intOptional) + AssertSQL("(\"int\" / 1)", int / 1) + AssertSQL("(\"intOptional\" / 1)", intOptional / 1) + AssertSQL("(1 / \"int\")", 1 / int) + AssertSQL("(1 / \"intOptional\")", 1 / intOptional) + + AssertSQL("(\"double\" / \"double\")", double / double) + AssertSQL("(\"double\" / \"doubleOptional\")", double / doubleOptional) + AssertSQL("(\"doubleOptional\" / \"double\")", doubleOptional / double) + AssertSQL("(\"doubleOptional\" / \"doubleOptional\")", doubleOptional / doubleOptional) + AssertSQL("(\"double\" / 1.0)", double / 1) + AssertSQL("(\"doubleOptional\" / 1.0)", doubleOptional / 1) + AssertSQL("(1.0 / \"double\")", 1 / double) + AssertSQL("(1.0 / \"doubleOptional\")", 1 / doubleOptional) + } + + func test_numberExpression_prefixedWithMinus_buildsInvertedNumberExpression() { + AssertSQL("-(\"int\")", -int) + AssertSQL("-(\"intOptional\")", -intOptional) + + AssertSQL("-(\"double\")", -double) + AssertSQL("-(\"doubleOptional\")", -doubleOptional) + } + + func test_integerExpression_moduloIntegerExpression_buildsModuloIntegerExpression() { + AssertSQL("(\"int\" % \"int\")", int % int) + AssertSQL("(\"int\" % \"intOptional\")", int % intOptional) + AssertSQL("(\"intOptional\" % \"int\")", intOptional % int) + AssertSQL("(\"intOptional\" % \"intOptional\")", intOptional % intOptional) + AssertSQL("(\"int\" % 1)", int % 1) + AssertSQL("(\"intOptional\" % 1)", intOptional % 1) + AssertSQL("(1 % \"int\")", 1 % int) + AssertSQL("(1 % \"intOptional\")", 1 % intOptional) + } + + func test_integerExpression_bitShiftLeftIntegerExpression_buildsLeftShiftedIntegerExpression() { + AssertSQL("(\"int\" << \"int\")", int << int) + AssertSQL("(\"int\" << \"intOptional\")", int << intOptional) + AssertSQL("(\"intOptional\" << \"int\")", intOptional << int) + AssertSQL("(\"intOptional\" << \"intOptional\")", intOptional << intOptional) + AssertSQL("(\"int\" << 1)", int << 1) + AssertSQL("(\"intOptional\" << 1)", intOptional << 1) + AssertSQL("(1 << \"int\")", 1 << int) + AssertSQL("(1 << \"intOptional\")", 1 << intOptional) + } + + func test_integerExpression_bitShiftRightIntegerExpression_buildsRightShiftedIntegerExpression() { + AssertSQL("(\"int\" >> \"int\")", int >> int) + AssertSQL("(\"int\" >> \"intOptional\")", int >> intOptional) + AssertSQL("(\"intOptional\" >> \"int\")", intOptional >> int) + AssertSQL("(\"intOptional\" >> \"intOptional\")", intOptional >> intOptional) + AssertSQL("(\"int\" >> 1)", int >> 1) + AssertSQL("(\"intOptional\" >> 1)", intOptional >> 1) + AssertSQL("(1 >> \"int\")", 1 >> int) + AssertSQL("(1 >> \"intOptional\")", 1 >> intOptional) + } + + func test_integerExpression_bitwiseAndIntegerExpression_buildsAndedIntegerExpression() { + AssertSQL("(\"int\" & \"int\")", int & int) + AssertSQL("(\"int\" & \"intOptional\")", int & intOptional) + AssertSQL("(\"intOptional\" & \"int\")", intOptional & int) + AssertSQL("(\"intOptional\" & \"intOptional\")", intOptional & intOptional) + AssertSQL("(\"int\" & 1)", int & 1) + AssertSQL("(\"intOptional\" & 1)", intOptional & 1) + AssertSQL("(1 & \"int\")", 1 & int) + AssertSQL("(1 & \"intOptional\")", 1 & intOptional) + } + + func test_integerExpression_bitwiseOrIntegerExpression_buildsOredIntegerExpression() { + AssertSQL("(\"int\" | \"int\")", int | int) + AssertSQL("(\"int\" | \"intOptional\")", int | intOptional) + AssertSQL("(\"intOptional\" | \"int\")", intOptional | int) + AssertSQL("(\"intOptional\" | \"intOptional\")", intOptional | intOptional) + AssertSQL("(\"int\" | 1)", int | 1) + AssertSQL("(\"intOptional\" | 1)", intOptional | 1) + AssertSQL("(1 | \"int\")", 1 | int) + AssertSQL("(1 | \"intOptional\")", 1 | intOptional) + } + + func test_integerExpression_bitwiseExclusiveOrIntegerExpression_buildsOredIntegerExpression() { + AssertSQL("(~((\"int\" & \"int\")) & (\"int\" | \"int\"))", int ^ int) + AssertSQL("(~((\"int\" & \"intOptional\")) & (\"int\" | \"intOptional\"))", int ^ intOptional) + AssertSQL("(~((\"intOptional\" & \"int\")) & (\"intOptional\" | \"int\"))", intOptional ^ int) + AssertSQL("(~((\"intOptional\" & \"intOptional\")) & (\"intOptional\" | \"intOptional\"))", intOptional ^ intOptional) + AssertSQL("(~((\"int\" & 1)) & (\"int\" | 1))", int ^ 1) + AssertSQL("(~((\"intOptional\" & 1)) & (\"intOptional\" | 1))", intOptional ^ 1) + AssertSQL("(~((1 & \"int\")) & (1 | \"int\"))", 1 ^ int) + AssertSQL("(~((1 & \"intOptional\")) & (1 | \"intOptional\"))", 1 ^ intOptional) + } + + func test_bitwiseNot_integerExpression_buildsComplementIntegerExpression() { + AssertSQL("~(\"int\")", ~int) + AssertSQL("~(\"intOptional\")", ~intOptional) + } + + func test_equalityOperator_withEquatableExpressions_buildsBooleanExpression() { + AssertSQL("(\"bool\" = \"bool\")", bool == bool) + AssertSQL("(\"bool\" = \"boolOptional\")", bool == boolOptional) + AssertSQL("(\"boolOptional\" = \"bool\")", boolOptional == bool) + AssertSQL("(\"boolOptional\" = \"boolOptional\")", boolOptional == boolOptional) + AssertSQL("(\"bool\" = 1)", bool == true) + AssertSQL("(\"boolOptional\" = 1)", boolOptional == true) + AssertSQL("(1 = \"bool\")", true == bool) + AssertSQL("(1 = \"boolOptional\")", true == boolOptional) + + AssertSQL("(\"boolOptional\" IS NULL)", boolOptional == nil) + AssertSQL("(NULL IS \"boolOptional\")", nil == boolOptional) + } + + func test_inequalityOperator_withEquatableExpressions_buildsBooleanExpression() { + AssertSQL("(\"bool\" != \"bool\")", bool != bool) + AssertSQL("(\"bool\" != \"boolOptional\")", bool != boolOptional) + AssertSQL("(\"boolOptional\" != \"bool\")", boolOptional != bool) + AssertSQL("(\"boolOptional\" != \"boolOptional\")", boolOptional != boolOptional) + AssertSQL("(\"bool\" != 1)", bool != true) + AssertSQL("(\"boolOptional\" != 1)", boolOptional != true) + AssertSQL("(1 != \"bool\")", true != bool) + AssertSQL("(1 != \"boolOptional\")", true != boolOptional) + + AssertSQL("(\"boolOptional\" IS NOT NULL)", boolOptional != nil) + AssertSQL("(NULL IS NOT \"boolOptional\")", nil != boolOptional) + } + + func test_greaterThanOperator_withComparableExpressions_buildsBooleanExpression() { + AssertSQL("(\"bool\" > \"bool\")", bool > bool) + AssertSQL("(\"bool\" > \"boolOptional\")", bool > boolOptional) + AssertSQL("(\"boolOptional\" > \"bool\")", boolOptional > bool) + AssertSQL("(\"boolOptional\" > \"boolOptional\")", boolOptional > boolOptional) + AssertSQL("(\"bool\" > 1)", bool > true) + AssertSQL("(\"boolOptional\" > 1)", boolOptional > true) + AssertSQL("(1 > \"bool\")", true > bool) + AssertSQL("(1 > \"boolOptional\")", true > boolOptional) + } + + func test_greaterThanOrEqualToOperator_withComparableExpressions_buildsBooleanExpression() { + AssertSQL("(\"bool\" >= \"bool\")", bool >= bool) + AssertSQL("(\"bool\" >= \"boolOptional\")", bool >= boolOptional) + AssertSQL("(\"boolOptional\" >= \"bool\")", boolOptional >= bool) + AssertSQL("(\"boolOptional\" >= \"boolOptional\")", boolOptional >= boolOptional) + AssertSQL("(\"bool\" >= 1)", bool >= true) + AssertSQL("(\"boolOptional\" >= 1)", boolOptional >= true) + AssertSQL("(1 >= \"bool\")", true >= bool) + AssertSQL("(1 >= \"boolOptional\")", true >= boolOptional) + } + + func test_lessThanOperator_withComparableExpressions_buildsBooleanExpression() { + AssertSQL("(\"bool\" < \"bool\")", bool < bool) + AssertSQL("(\"bool\" < \"boolOptional\")", bool < boolOptional) + AssertSQL("(\"boolOptional\" < \"bool\")", boolOptional < bool) + AssertSQL("(\"boolOptional\" < \"boolOptional\")", boolOptional < boolOptional) + AssertSQL("(\"bool\" < 1)", bool < true) + AssertSQL("(\"boolOptional\" < 1)", boolOptional < true) + AssertSQL("(1 < \"bool\")", true < bool) + AssertSQL("(1 < \"boolOptional\")", true < boolOptional) + } + + func test_lessThanOrEqualToOperator_withComparableExpressions_buildsBooleanExpression() { + AssertSQL("(\"bool\" <= \"bool\")", bool <= bool) + AssertSQL("(\"bool\" <= \"boolOptional\")", bool <= boolOptional) + AssertSQL("(\"boolOptional\" <= \"bool\")", boolOptional <= bool) + AssertSQL("(\"boolOptional\" <= \"boolOptional\")", boolOptional <= boolOptional) + AssertSQL("(\"bool\" <= 1)", bool <= true) + AssertSQL("(\"boolOptional\" <= 1)", boolOptional <= true) + AssertSQL("(1 <= \"bool\")", true <= bool) + AssertSQL("(1 <= \"boolOptional\")", true <= boolOptional) + } + + func test_patternMatchingOperator_withComparableCountableClosedRange_buildsBetweenBooleanExpression() { + AssertSQL("\"int\" BETWEEN 0 AND 5", 0...5 ~= int) + AssertSQL("\"intOptional\" BETWEEN 0 AND 5", 0...5 ~= intOptional) + } + + func test_patternMatchingOperator_withComparableClosedRange_buildsBetweenBooleanExpression() { + AssertSQL("\"double\" BETWEEN 1.2 AND 4.5", 1.2...4.5 ~= double) + AssertSQL("\"doubleOptional\" BETWEEN 1.2 AND 4.5", 1.2...4.5 ~= doubleOptional) + } + + func test_patternMatchingOperator_withomparableClosedRangeString_buildsBetweenBooleanExpression() { + AssertSQL("\"string\" BETWEEN 'a' AND 'b'", "a"..."b" ~= string) + AssertSQL("\"stringOptional\" BETWEEN 'a' AND 'b'", "a"..."b" ~= stringOptional) + } + + func test_doubleAndOperator_withBooleanExpressions_buildsCompoundExpression() { + AssertSQL("(\"bool\" AND \"bool\")", bool && bool) + AssertSQL("(\"bool\" AND \"boolOptional\")", bool && boolOptional) + AssertSQL("(\"boolOptional\" AND \"bool\")", boolOptional && bool) + AssertSQL("(\"boolOptional\" AND \"boolOptional\")", boolOptional && boolOptional) + AssertSQL("(\"bool\" AND 1)", bool && true) + AssertSQL("(\"boolOptional\" AND 1)", boolOptional && true) + AssertSQL("(1 AND \"bool\")", true && bool) + AssertSQL("(1 AND \"boolOptional\")", true && boolOptional) + } + + func test_doubleOrOperator_withBooleanExpressions_buildsCompoundExpression() { + AssertSQL("(\"bool\" OR \"bool\")", bool || bool) + AssertSQL("(\"bool\" OR \"boolOptional\")", bool || boolOptional) + AssertSQL("(\"boolOptional\" OR \"bool\")", boolOptional || bool) + AssertSQL("(\"boolOptional\" OR \"boolOptional\")", boolOptional || boolOptional) + AssertSQL("(\"bool\" OR 1)", bool || true) + AssertSQL("(\"boolOptional\" OR 1)", boolOptional || true) + AssertSQL("(1 OR \"bool\")", true || bool) + AssertSQL("(1 OR \"boolOptional\")", true || boolOptional) + } + + func test_unaryNotOperator_withBooleanExpressions_buildsNotExpression() { + AssertSQL("NOT (\"bool\")", !bool) + AssertSQL("NOT (\"boolOptional\")", !boolOptional) + } + + func test_precedencePreserved() { + let n = Expression(value: 1) + AssertSQL("(((1 = 1) AND (1 = 1)) OR (1 = 1))", (n == n && n == n) || n == n) + AssertSQL("((1 = 1) AND ((1 = 1) OR (1 = 1)))", n == n && (n == n || n == n)) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/QueryTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/QueryTests.swift new file mode 100644 index 0000000000..2cf164c6d3 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/QueryTests.swift @@ -0,0 +1,365 @@ +import XCTest +import SQLite + +class QueryTests : XCTestCase { + + let users = Table("users") + let id = Expression("id") + let email = Expression("email") + let age = Expression("age") + let admin = Expression("admin") + let optionalAdmin = Expression("admin") + + let posts = Table("posts") + let userId = Expression("user_id") + let categoryId = Expression("category_id") + let published = Expression("published") + + let categories = Table("categories") + let tag = Expression("tag") + + func test_select_withExpression_compilesSelectClause() { + AssertSQL("SELECT \"email\" FROM \"users\"", users.select(email)) + } + + func test_select_withStarExpression_compilesSelectClause() { + AssertSQL("SELECT * FROM \"users\"", users.select(*)) + } + + func test_select_withNamespacedStarExpression_compilesSelectClause() { + AssertSQL("SELECT \"users\".* FROM \"users\"", users.select(users[*])) + } + + func test_select_withVariadicExpressions_compilesSelectClause() { + AssertSQL("SELECT \"email\", count(*) FROM \"users\"", users.select(email, count(*))) + } + + func test_select_withExpressions_compilesSelectClause() { + AssertSQL("SELECT \"email\", count(*) FROM \"users\"", users.select([email, count(*)])) + } + + func test_selectDistinct_withExpression_compilesSelectClause() { + AssertSQL("SELECT DISTINCT \"age\" FROM \"users\"", users.select(distinct: age)) + } + + func test_selectDistinct_withExpressions_compilesSelectClause() { + AssertSQL("SELECT DISTINCT \"age\", \"admin\" FROM \"users\"", users.select(distinct: [age, admin])) + } + + func test_selectDistinct_withStar_compilesSelectClause() { + AssertSQL("SELECT DISTINCT * FROM \"users\"", users.select(distinct: *)) + } + + func test_join_compilesJoinClause() { + AssertSQL( + "SELECT * FROM \"users\" INNER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", + users.join(posts, on: posts[userId] == users[id]) + ) + } + + func test_join_withExplicitType_compilesJoinClauseWithType() { + AssertSQL( + "SELECT * FROM \"users\" LEFT OUTER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", + users.join(.leftOuter, posts, on: posts[userId] == users[id]) + ) + + AssertSQL( + "SELECT * FROM \"users\" CROSS JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", + users.join(.cross, posts, on: posts[userId] == users[id]) + ) + } + + func test_join_withTableCondition_compilesJoinClauseWithTableCondition() { + AssertSQL( + "SELECT * FROM \"users\" INNER JOIN \"posts\" ON ((\"posts\".\"user_id\" = \"users\".\"id\") AND \"published\")", + users.join(posts.filter(published), on: posts[userId] == users[id]) + ) + } + + func test_join_whenChained_compilesAggregateJoinClause() { + AssertSQL( + "SELECT * FROM \"users\" " + + "INNER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\") " + + "INNER JOIN \"categories\" ON (\"categories\".\"id\" = \"posts\".\"category_id\")", + users.join(posts, on: posts[userId] == users[id]).join(categories, on: categories[id] == posts[categoryId]) + ) + } + + func test_filter_compilesWhereClause() { + AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.filter(admin == true)) + } + + func test_filter_compilesWhereClause_false() { + AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.filter(admin == false)) + } + + func test_filter_compilesWhereClause_optional() { + AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.filter(optionalAdmin == true)) + } + + func test_filter_compilesWhereClause_optional_false() { + AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.filter(optionalAdmin == false)) + } + + func test_where_compilesWhereClause() { + AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.where(admin == true)) + } + + func test_where_compilesWhereClause_false() { + AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.where(admin == false)) + } + + func test_where_compilesWhereClause_optional() { + AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.where(optionalAdmin == true)) + } + + func test_where_compilesWhereClause_optional_false() { + AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.where(optionalAdmin == false)) + } + + func test_filter_whenChained_compilesAggregateWhereClause() { + AssertSQL( + "SELECT * FROM \"users\" WHERE ((\"age\" >= 35) AND \"admin\")", + users.filter(age >= 35).filter(admin) + ) + } + + func test_group_withSingleExpressionName_compilesGroupClause() { + AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\"", + users.group(age)) + } + + func test_group_withVariadicExpressionNames_compilesGroupClause() { + AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\", \"admin\"", users.group(age, admin)) + } + + func test_group_withExpressionNameAndHavingBindings_compilesGroupClause() { + AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\" HAVING \"admin\"", users.group(age, having: admin)) + AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\" HAVING (\"age\" >= 30)", users.group(age, having: age >= 30)) + } + + func test_group_withExpressionNamesAndHavingBindings_compilesGroupClause() { + AssertSQL( + "SELECT * FROM \"users\" GROUP BY \"age\", \"admin\" HAVING \"admin\"", + users.group([age, admin], having: admin) + ) + AssertSQL( + "SELECT * FROM \"users\" GROUP BY \"age\", \"admin\" HAVING (\"age\" >= 30)", + users.group([age, admin], having: age >= 30) + ) + } + + func test_order_withSingleExpressionName_compilesOrderClause() { + AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\"", users.order(age)) + } + + func test_order_withVariadicExpressionNames_compilesOrderClause() { + AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\", \"email\"", users.order(age, email)) + } + + func test_order_withArrayExpressionNames_compilesOrderClause() { + AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\", \"email\"", users.order([age, email])) + } + + func test_order_withExpressionAndSortDirection_compilesOrderClause() { +// AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\" DESC, \"email\" ASC", users.order(age.desc, email.asc)) + } + + func test_order_whenChained_resetsOrderClause() { + AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\"", users.order(email).order(age)) + } + + func test_reverse_withoutOrder_ordersByRowIdDescending() { +// AssertSQL("SELECT * FROM \"users\" ORDER BY \"ROWID\" DESC", users.reverse()) + } + + func test_reverse_withOrder_reversesOrder() { +// AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\" DESC, \"email\" ASC", users.order(age, email.desc).reverse()) + } + + func test_limit_compilesLimitClause() { + AssertSQL("SELECT * FROM \"users\" LIMIT 5", users.limit(5)) + } + + func test_limit_withOffset_compilesOffsetClause() { + AssertSQL("SELECT * FROM \"users\" LIMIT 5 OFFSET 5", users.limit(5, offset: 5)) + } + + func test_limit_whenChained_overridesLimit() { + let query = users.limit(5) + + AssertSQL("SELECT * FROM \"users\" LIMIT 10", query.limit(10)) + AssertSQL("SELECT * FROM \"users\"", query.limit(nil)) + } + + func test_limit_whenChained_withOffset_overridesOffset() { + let query = users.limit(5, offset: 5) + + AssertSQL("SELECT * FROM \"users\" LIMIT 10 OFFSET 20", query.limit(10, offset: 20)) + AssertSQL("SELECT * FROM \"users\"", query.limit(nil)) + } + + func test_alias_aliasesTable() { + let managerId = Expression("manager_id") + + let managers = users.alias("managers") + + AssertSQL( + "SELECT * FROM \"users\" " + + "INNER JOIN \"users\" AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\")", + users.join(managers, on: managers[id] == users[managerId]) + ) + } + + func test_insert_compilesInsertExpression() { + AssertSQL( + "INSERT INTO \"users\" (\"email\", \"age\") VALUES ('alice@example.com', 30)", + users.insert(email <- "alice@example.com", age <- 30) + ) + } + + func test_insert_withOnConflict_compilesInsertOrOnConflictExpression() { + AssertSQL( + "INSERT OR REPLACE INTO \"users\" (\"email\", \"age\") VALUES ('alice@example.com', 30)", + users.insert(or: .replace, email <- "alice@example.com", age <- 30) + ) + } + + func test_insert_compilesInsertExpressionWithDefaultValues() { + AssertSQL("INSERT INTO \"users\" DEFAULT VALUES", users.insert()) + } + + func test_insert_withQuery_compilesInsertExpressionWithSelectStatement() { + let emails = Table("emails") + + AssertSQL( + "INSERT INTO \"emails\" SELECT \"email\" FROM \"users\" WHERE \"admin\"", + emails.insert(users.select(email).filter(admin)) + ) + } + + func test_update_compilesUpdateExpression() { + AssertSQL( + "UPDATE \"users\" SET \"age\" = 30, \"admin\" = 1 WHERE (\"id\" = 1)", + users.filter(id == 1).update(age <- 30, admin <- true) + ) + } + + func test_delete_compilesDeleteExpression() { + AssertSQL( + "DELETE FROM \"users\" WHERE (\"id\" = 1)", + users.filter(id == 1).delete() + ) + } + + func test_delete_compilesExistsExpression() { + AssertSQL( + "SELECT EXISTS (SELECT * FROM \"users\")", + users.exists + ) + } + + func test_count_returnsCountExpression() { + AssertSQL("SELECT count(*) FROM \"users\"", users.count) + } + + func test_scalar_returnsScalarExpression() { + AssertSQL("SELECT \"int\" FROM \"table\"", table.select(int) as ScalarQuery) + AssertSQL("SELECT \"intOptional\" FROM \"table\"", table.select(intOptional) as ScalarQuery) + AssertSQL("SELECT DISTINCT \"int\" FROM \"table\"", table.select(distinct: int) as ScalarQuery) + AssertSQL("SELECT DISTINCT \"intOptional\" FROM \"table\"", table.select(distinct: intOptional) as ScalarQuery) + } + + func test_subscript_withExpression_returnsNamespacedExpression() { + let query = Table("query") + + AssertSQL("\"query\".\"blob\"", query[data]) + AssertSQL("\"query\".\"blobOptional\"", query[dataOptional]) + + AssertSQL("\"query\".\"bool\"", query[bool]) + AssertSQL("\"query\".\"boolOptional\"", query[boolOptional]) + + AssertSQL("\"query\".\"date\"", query[date]) + AssertSQL("\"query\".\"dateOptional\"", query[dateOptional]) + + AssertSQL("\"query\".\"double\"", query[double]) + AssertSQL("\"query\".\"doubleOptional\"", query[doubleOptional]) + + AssertSQL("\"query\".\"int\"", query[int]) + AssertSQL("\"query\".\"intOptional\"", query[intOptional]) + + AssertSQL("\"query\".\"int64\"", query[int64]) + AssertSQL("\"query\".\"int64Optional\"", query[int64Optional]) + + AssertSQL("\"query\".\"string\"", query[string]) + AssertSQL("\"query\".\"stringOptional\"", query[stringOptional]) + + AssertSQL("\"query\".*", query[*]) + } + + func test_tableNamespacedByDatabase() { + let table = Table("table", database: "attached") + + AssertSQL("SELECT * FROM \"attached\".\"table\"", table) + } + +} + +class QueryIntegrationTests : SQLiteTestCase { + + let id = Expression("id") + let email = Expression("email") + + override func setUp() { + super.setUp() + + CreateUsersTable() + } + + // MARK: - + + func test_select() { + for _ in try! db.prepare(users) { + // FIXME + } + + let managerId = Expression("manager_id") + let managers = users.alias("managers") + + let alice = try! db.run(users.insert(email <- "alice@example.com")) + _ = try! db.run(users.insert(email <- "betsy@example.com", managerId <- alice)) + + for user in try! db.prepare(users.join(managers, on: managers[id] == users[managerId])) { + _ = user[users[managerId]] + } + } + + func test_scalar() { + XCTAssertEqual(0, try! db.scalar(users.count)) + XCTAssertEqual(false, try! db.scalar(users.exists)) + + try! InsertUsers("alice") + XCTAssertEqual(1, try! db.scalar(users.select(id.average))) + } + + func test_pluck() { + let rowid = try! db.run(users.insert(email <- "alice@example.com")) + XCTAssertEqual(rowid, try! db.pluck(users)![id]) + } + + func test_insert() { + let id = try! db.run(users.insert(email <- "alice@example.com")) + XCTAssertEqual(1, id) + } + + func test_update() { + let changes = try! db.run(users.update(email <- "alice@example.com")) + XCTAssertEqual(0, changes) + } + + func test_delete() { + let changes = try! db.run(users.delete()) + XCTAssertEqual(0, changes) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/RTreeTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/RTreeTests.swift new file mode 100644 index 0000000000..7147533ecb --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/RTreeTests.swift @@ -0,0 +1,17 @@ +import XCTest +import SQLite + +class RTreeTests : XCTestCase { + + func test_create_onVirtualTable_withRTree_createVirtualTableExpression() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING rtree(\"int64\", \"double\", \"double\")", + virtualTable.create(.RTree(int64, (double, double))) + ) + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING rtree(\"int64\", \"double\", \"double\", \"double\", \"double\")", + virtualTable.create(.RTree(int64, (double, double), (double, double))) + ) + } + +} \ No newline at end of file diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SchemaTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SchemaTests.swift new file mode 100644 index 0000000000..371459c757 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SchemaTests.swift @@ -0,0 +1,775 @@ +import XCTest +import SQLite + +class SchemaTests : XCTestCase { + + func test_drop_compilesDropTableExpression() { + XCTAssertEqual("DROP TABLE \"table\"", table.drop()) + XCTAssertEqual("DROP TABLE IF EXISTS \"table\"", table.drop(ifExists: true)) + } + + func test_drop_compilesDropVirtualTableExpression() { + XCTAssertEqual("DROP TABLE \"virtual_table\"", virtualTable.drop()) + XCTAssertEqual("DROP TABLE IF EXISTS \"virtual_table\"", virtualTable.drop(ifExists: true)) + } + + func test_drop_compilesDropViewExpression() { + XCTAssertEqual("DROP VIEW \"view\"", _view.drop()) + XCTAssertEqual("DROP VIEW IF EXISTS \"view\"", _view.drop(ifExists: true)) + } + + func test_create_withBuilder_compilesCreateTableExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (" + + "\"blob\" BLOB NOT NULL, " + + "\"blobOptional\" BLOB, " + + "\"double\" REAL NOT NULL, " + + "\"doubleOptional\" REAL, " + + "\"int64\" INTEGER NOT NULL, " + + "\"int64Optional\" INTEGER, " + + "\"string\" TEXT NOT NULL, " + + "\"stringOptional\" TEXT" + + ")", + table.create { t in + t.column(data) + t.column(dataOptional) + t.column(double) + t.column(doubleOptional) + t.column(int64) + t.column(int64Optional) + t.column(string) + t.column(stringOptional) + } + ) + XCTAssertEqual( + "CREATE TEMPORARY TABLE \"table\" (\"int64\" INTEGER NOT NULL)", + table.create(temporary: true) { $0.column(int64) } + ) + XCTAssertEqual( + "CREATE TABLE IF NOT EXISTS \"table\" (\"int64\" INTEGER NOT NULL)", + table.create(ifNotExists: true) { $0.column(int64) } + ) + XCTAssertEqual( + "CREATE TEMPORARY TABLE IF NOT EXISTS \"table\" (\"int64\" INTEGER NOT NULL)", + table.create(temporary: true, ifNotExists: true) { $0.column(int64) } + ) + } + + func test_create_withQuery_compilesCreateTableExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" AS SELECT \"int64\" FROM \"view\"", + table.create(_view.select(int64)) + ) + } + + // thoroughness test for ambiguity + func test_column_compilesColumnDefinitionExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL)", + table.create { t in t.column(int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE)", + table.create { t in t.column(int64, unique: true) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0))", + table.create { t in t.column(int64, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64, check: int64Optional > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL DEFAULT (\"int64\"))", + table.create { t in t.column(int64, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL DEFAULT (0))", + table.create { t in t.column(int64, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0))", + table.create { t in t.column(int64, unique: true, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64, unique: true, check: int64Optional > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE DEFAULT (\"int64\"))", + table.create { t in t.column(int64, unique: true, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE DEFAULT (0))", + table.create { t in t.column(int64, unique: true, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0))", + table.create { t in t.column(int64, unique: true, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64, unique: true, check: int64Optional > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64, unique: true, check: int64 > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64, unique: true, check: int64Optional > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) DEFAULT (0))", + table.create { t in t.column(int64, unique: true, check: int64 > 0, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (0))", + table.create { t in t.column(int64, unique: true, check: int64Optional > 0, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64, check: int64 > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64, check: int64Optional > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (0))", + table.create { t in t.column(int64, check: int64 > 0, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (0))", + table.create { t in t.column(int64, check: int64Optional > 0, defaultValue: 0) } + ) + + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0))", + table.create { t in t.column(int64, primaryKey: true, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL DEFAULT (\"int64\"))", + table.create { t in t.column(int64, primaryKey: true, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0))", + table.create { t in t.column(int64, primaryKey: true, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64, primaryKey: true, check: int64 > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0, defaultValue: int64) } + ) + + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER)", + table.create { t in t.column(int64Optional) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE)", + table.create { t in t.column(int64Optional, unique: true) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0))", + table.create { t in t.column(int64Optional, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64Optional, check: int64Optional > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (\"int64\"))", + table.create { t in t.column(int64Optional, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (\"int64Optional\"))", + table.create { t in t.column(int64Optional, defaultValue: int64Optional) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (0))", + table.create { t in t.column(int64Optional, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0))", + table.create { t in t.column(int64Optional, unique: true, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (\"int64\"))", + table.create { t in t.column(int64Optional, unique: true, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (\"int64Optional\"))", + table.create { t in t.column(int64Optional, unique: true, defaultValue: int64Optional) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (0))", + table.create { t in t.column(int64Optional, unique: true, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0))", + table.create { t in t.column(int64Optional, unique: true, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64Optional\"))", + table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: int64Optional) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64Optional\"))", + table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: int64Optional) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (0))", + table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (0))", + table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", + table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (\"int64Optional\"))", + table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: int64Optional) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (\"int64Optional\"))", + table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: int64Optional) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (0))", + table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (0))", + table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: 0) } + ) + } + + func test_column_withIntegerExpression_compilesPrimaryKeyAutoincrementColumnDefinitionExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + table.create { t in t.column(int64, primaryKey: .autoincrement) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (\"int64\" > 0))", + table.create { t in t.column(int64, primaryKey: .autoincrement, check: int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (\"int64Optional\" > 0))", + table.create { t in t.column(int64, primaryKey: .autoincrement, check: int64Optional > 0) } + ) + } + + func test_column_withIntegerExpression_compilesReferentialColumnDefinitionExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64, references: qualifiedTable, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64, unique: true, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64, check: int64 > 0, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64, check: int64Optional > 0, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64, unique: true, check: int64 > 0, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64, unique: true, check: int64Optional > 0, references: table, int64) } + ) + + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64Optional, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64Optional, unique: true, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64Optional, check: int64 > 0, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64Optional, check: int64Optional > 0, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, references: table, int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))", + table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, references: table, int64) } + ) + } + + func test_column_withStringExpression_compilesCollatedColumnDefinitionExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL COLLATE RTRIM)", + table.create { t in t.column(string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') COLLATE RTRIM)", + table.create { t in t.column(string, check: string != "", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') COLLATE RTRIM)", + table.create { t in t.column(string, check: stringOptional != "", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(string, defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(string, defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, check: string != "", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, check: stringOptional != "", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, check: string != "", defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, check: stringOptional != "", defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, check: string != "", defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(string, unique: true, check: stringOptional != "", defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(string, check: string != "", defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(string, check: stringOptional != "", defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(string, check: string != "", defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(string, check: stringOptional != "", defaultValue: "string", collate: .rtrim) } + ) + + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL COLLATE RTRIM)", + table.create { t in t.column(stringOptional, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"string\" != '') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, check: string != "", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"stringOptional\" != '') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, check: stringOptional != "", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL DEFAULT (\"stringOptional\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, defaultValue: stringOptional, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, check: string != "", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE DEFAULT (\"stringOptional\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, defaultValue: stringOptional, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: stringOptional, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: stringOptional, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, check: string != "", defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: string, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, check: string != "", defaultValue: stringOptional, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)", + table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: stringOptional, collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, check: string != "", defaultValue: "string", collate: .rtrim) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)", + table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: "string", collate: .rtrim) } + ) + } + + func test_primaryKey_compilesPrimaryKeyExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (PRIMARY KEY (\"int64\"))", + table.create { t in t.primaryKey(int64) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (PRIMARY KEY (\"int64\", \"string\"))", + table.create { t in t.primaryKey(int64, string) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (PRIMARY KEY (\"int64\", \"string\", \"double\"))", + table.create { t in t.primaryKey(int64, string, double) } + ) + } + + func test_unique_compilesUniqueExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (UNIQUE (\"int64\"))", + table.create { t in t.unique(int64) } + ) + } + + func test_check_compilesCheckExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (CHECK ((\"int64\" > 0)))", + table.create { t in t.check(int64 > 0) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (CHECK ((\"int64Optional\" > 0)))", + table.create { t in t.check(int64Optional > 0) } + ) + } + + func test_foreignKey_compilesForeignKeyExpression() { + XCTAssertEqual( + "CREATE TABLE \"table\" (FOREIGN KEY (\"string\") REFERENCES \"table\" (\"string\"))", + table.create { t in t.foreignKey(string, references: table, string) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (FOREIGN KEY (\"stringOptional\") REFERENCES \"table\" (\"string\"))", + table.create { t in t.foreignKey(stringOptional, references: table, string) } + ) + + XCTAssertEqual( + "CREATE TABLE \"table\" (FOREIGN KEY (\"string\") REFERENCES \"table\" (\"string\") ON UPDATE CASCADE ON DELETE SET NULL)", + table.create { t in t.foreignKey(string, references: table, string, update: .cascade, delete: .setNull) } + ) + + XCTAssertEqual( + "CREATE TABLE \"table\" (FOREIGN KEY (\"string\", \"string\") REFERENCES \"table\" (\"string\", \"string\"))", + table.create { t in t.foreignKey((string, string), references: table, (string, string)) } + ) + XCTAssertEqual( + "CREATE TABLE \"table\" (FOREIGN KEY (\"string\", \"string\", \"string\") REFERENCES \"table\" (\"string\", \"string\", \"string\"))", + table.create { t in t.foreignKey((string, string, string), references: table, (string, string, string)) } + ) + } + + func test_addColumn_compilesAlterTableExpression() { + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL DEFAULT (1)", + table.addColumn(int64, defaultValue: 1) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (1)", + table.addColumn(int64, check: int64 > 0, defaultValue: 1) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (1)", + table.addColumn(int64, check: int64Optional > 0, defaultValue: 1) + ) + + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER", + table.addColumn(int64Optional) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0)", + table.addColumn(int64Optional, check: int64 > 0) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0)", + table.addColumn(int64Optional, check: int64Optional > 0) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER DEFAULT (1)", + table.addColumn(int64Optional, defaultValue: 1) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (1)", + table.addColumn(int64Optional, check: int64 > 0, defaultValue: 1) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (1)", + table.addColumn(int64Optional, check: int64Optional > 0, defaultValue: 1) + ) + } + + func test_addColumn_withIntegerExpression_compilesReferentialAlterTableExpression() { + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\")", + table.addColumn(int64, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE REFERENCES \"table\" (\"int64\")", + table.addColumn(int64, unique: true, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")", + table.addColumn(int64, check: int64 > 0, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")", + table.addColumn(int64, check: int64Optional > 0, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")", + table.addColumn(int64, unique: true, check: int64 > 0, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")", + table.addColumn(int64, unique: true, check: int64Optional > 0, references: table, int64) + ) + + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER REFERENCES \"table\" (\"int64\")", + table.addColumn(int64Optional, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE REFERENCES \"table\" (\"int64\")", + table.addColumn(int64Optional, unique: true, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")", + table.addColumn(int64Optional, check: int64 > 0, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")", + table.addColumn(int64Optional, check: int64Optional > 0, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")", + table.addColumn(int64Optional, unique: true, check: int64 > 0, references: table, int64) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")", + table.addColumn(int64Optional, unique: true, check: int64Optional > 0, references: table, int64) + ) + } + + func test_addColumn_withStringExpression_compilesCollatedAlterTableExpression() { + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL DEFAULT ('string') COLLATE RTRIM", + table.addColumn(string, defaultValue: "string", collate: .rtrim) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM", + table.addColumn(string, check: string != "", defaultValue: "string", collate: .rtrim) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM", + table.addColumn(string, check: stringOptional != "", defaultValue: "string", collate: .rtrim) + ) + + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT COLLATE RTRIM", + table.addColumn(stringOptional, collate: .rtrim) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"string\" != '') COLLATE RTRIM", + table.addColumn(stringOptional, check: string != "", collate: .rtrim) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"stringOptional\" != '') COLLATE RTRIM", + table.addColumn(stringOptional, check: stringOptional != "", collate: .rtrim) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM", + table.addColumn(stringOptional, check: string != "", defaultValue: "string", collate: .rtrim) + ) + XCTAssertEqual( + "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM", + table.addColumn(stringOptional, check: stringOptional != "", defaultValue: "string", collate: .rtrim) + ) + } + + func test_rename_compilesAlterTableRenameToExpression() { + XCTAssertEqual("ALTER TABLE \"old\" RENAME TO \"table\"", Table("old").rename(table)) + } + + func test_createIndex_compilesCreateIndexExpression() { + XCTAssertEqual("CREATE INDEX \"index_table_on_int64\" ON \"table\" (\"int64\")", table.createIndex(int64)) + + XCTAssertEqual( + "CREATE UNIQUE INDEX \"index_table_on_int64\" ON \"table\" (\"int64\")", + table.createIndex([int64], unique: true) + ) + XCTAssertEqual( + "CREATE INDEX IF NOT EXISTS \"index_table_on_int64\" ON \"table\" (\"int64\")", + table.createIndex([int64], ifNotExists: true) + ) + XCTAssertEqual( + "CREATE UNIQUE INDEX IF NOT EXISTS \"index_table_on_int64\" ON \"table\" (\"int64\")", + table.createIndex([int64], unique: true, ifNotExists: true) + ) + XCTAssertEqual( + "CREATE UNIQUE INDEX IF NOT EXISTS \"main\".\"index_table_on_int64\" ON \"table\" (\"int64\")", + qualifiedTable.createIndex([int64], unique: true, ifNotExists: true) + ) + } + + func test_dropIndex_compilesCreateIndexExpression() { + XCTAssertEqual("DROP INDEX \"index_table_on_int64\"", table.dropIndex(int64)) + XCTAssertEqual("DROP INDEX IF EXISTS \"index_table_on_int64\"", table.dropIndex([int64], ifExists: true)) + } + + func test_create_onView_compilesCreateViewExpression() { + XCTAssertEqual( + "CREATE VIEW \"view\" AS SELECT \"int64\" FROM \"table\"", + _view.create(table.select(int64)) + ) + XCTAssertEqual( + "CREATE TEMPORARY VIEW \"view\" AS SELECT \"int64\" FROM \"table\"", + _view.create(table.select(int64), temporary: true) + ) + XCTAssertEqual( + "CREATE VIEW IF NOT EXISTS \"view\" AS SELECT \"int64\" FROM \"table\"", + _view.create(table.select(int64), ifNotExists: true) + ) + XCTAssertEqual( + "CREATE TEMPORARY VIEW IF NOT EXISTS \"view\" AS SELECT \"int64\" FROM \"table\"", + _view.create(table.select(int64), temporary: true, ifNotExists: true) + ) + } + + func test_create_onVirtualTable_compilesCreateVirtualTableExpression() { + XCTAssertEqual( + "CREATE VIRTUAL TABLE \"virtual_table\" USING \"custom\"('foo', 'bar')", + virtualTable.create(Module("custom", ["foo", "bar"])) + ) + } + + func test_rename_onVirtualTable_compilesAlterTableRenameToExpression() { + XCTAssertEqual( + "ALTER TABLE \"old\" RENAME TO \"virtual_table\"", + VirtualTable("old").rename(virtualTable) + ) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SetterTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SetterTests.swift new file mode 100644 index 0000000000..d4f189d7c5 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SetterTests.swift @@ -0,0 +1,137 @@ +import XCTest +import SQLite + +class SetterTests : XCTestCase { + + func test_setterAssignmentOperator_buildsSetter() { + AssertSQL("\"int\" = \"int\"", int <- int) + AssertSQL("\"int\" = 1", int <- 1) + AssertSQL("\"intOptional\" = \"int\"", intOptional <- int) + AssertSQL("\"intOptional\" = \"intOptional\"", intOptional <- intOptional) + AssertSQL("\"intOptional\" = 1", intOptional <- 1) + AssertSQL("\"intOptional\" = NULL", intOptional <- nil) + } + + func test_plusEquals_withStringExpression_buildsSetter() { + AssertSQL("\"string\" = (\"string\" || \"string\")", string += string) + AssertSQL("\"string\" = (\"string\" || 'literal')", string += "literal") + AssertSQL("\"stringOptional\" = (\"stringOptional\" || \"string\")", stringOptional += string) + AssertSQL("\"stringOptional\" = (\"stringOptional\" || \"stringOptional\")", stringOptional += stringOptional) + AssertSQL("\"stringOptional\" = (\"stringOptional\" || 'literal')", stringOptional += "literal") + } + + func test_plusEquals_withNumberExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" + \"int\")", int += int) + AssertSQL("\"int\" = (\"int\" + 1)", int += 1) + AssertSQL("\"intOptional\" = (\"intOptional\" + \"int\")", intOptional += int) + AssertSQL("\"intOptional\" = (\"intOptional\" + \"intOptional\")", intOptional += intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" + 1)", intOptional += 1) + + AssertSQL("\"double\" = (\"double\" + \"double\")", double += double) + AssertSQL("\"double\" = (\"double\" + 1.0)", double += 1) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + \"double\")", doubleOptional += double) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + \"doubleOptional\")", doubleOptional += doubleOptional) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + 1.0)", doubleOptional += 1) + } + + func test_minusEquals_withNumberExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" - \"int\")", int -= int) + AssertSQL("\"int\" = (\"int\" - 1)", int -= 1) + AssertSQL("\"intOptional\" = (\"intOptional\" - \"int\")", intOptional -= int) + AssertSQL("\"intOptional\" = (\"intOptional\" - \"intOptional\")", intOptional -= intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" - 1)", intOptional -= 1) + + AssertSQL("\"double\" = (\"double\" - \"double\")", double -= double) + AssertSQL("\"double\" = (\"double\" - 1.0)", double -= 1) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - \"double\")", doubleOptional -= double) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - \"doubleOptional\")", doubleOptional -= doubleOptional) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - 1.0)", doubleOptional -= 1) + } + + func test_timesEquals_withNumberExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" * \"int\")", int *= int) + AssertSQL("\"int\" = (\"int\" * 1)", int *= 1) + AssertSQL("\"intOptional\" = (\"intOptional\" * \"int\")", intOptional *= int) + AssertSQL("\"intOptional\" = (\"intOptional\" * \"intOptional\")", intOptional *= intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" * 1)", intOptional *= 1) + + AssertSQL("\"double\" = (\"double\" * \"double\")", double *= double) + AssertSQL("\"double\" = (\"double\" * 1.0)", double *= 1) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * \"double\")", doubleOptional *= double) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * \"doubleOptional\")", doubleOptional *= doubleOptional) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * 1.0)", doubleOptional *= 1) + } + + func test_dividedByEquals_withNumberExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" / \"int\")", int /= int) + AssertSQL("\"int\" = (\"int\" / 1)", int /= 1) + AssertSQL("\"intOptional\" = (\"intOptional\" / \"int\")", intOptional /= int) + AssertSQL("\"intOptional\" = (\"intOptional\" / \"intOptional\")", intOptional /= intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" / 1)", intOptional /= 1) + + AssertSQL("\"double\" = (\"double\" / \"double\")", double /= double) + AssertSQL("\"double\" = (\"double\" / 1.0)", double /= 1) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / \"double\")", doubleOptional /= double) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / \"doubleOptional\")", doubleOptional /= doubleOptional) + AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / 1.0)", doubleOptional /= 1) + } + + func test_moduloEquals_withIntegerExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" % \"int\")", int %= int) + AssertSQL("\"int\" = (\"int\" % 1)", int %= 1) + AssertSQL("\"intOptional\" = (\"intOptional\" % \"int\")", intOptional %= int) + AssertSQL("\"intOptional\" = (\"intOptional\" % \"intOptional\")", intOptional %= intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" % 1)", intOptional %= 1) + } + + func test_leftShiftEquals_withIntegerExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" << \"int\")", int <<= int) + AssertSQL("\"int\" = (\"int\" << 1)", int <<= 1) + AssertSQL("\"intOptional\" = (\"intOptional\" << \"int\")", intOptional <<= int) + AssertSQL("\"intOptional\" = (\"intOptional\" << \"intOptional\")", intOptional <<= intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" << 1)", intOptional <<= 1) + } + + func test_rightShiftEquals_withIntegerExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" >> \"int\")", int >>= int) + AssertSQL("\"int\" = (\"int\" >> 1)", int >>= 1) + AssertSQL("\"intOptional\" = (\"intOptional\" >> \"int\")", intOptional >>= int) + AssertSQL("\"intOptional\" = (\"intOptional\" >> \"intOptional\")", intOptional >>= intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" >> 1)", intOptional >>= 1) + } + + func test_bitwiseAndEquals_withIntegerExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" & \"int\")", int &= int) + AssertSQL("\"int\" = (\"int\" & 1)", int &= 1) + AssertSQL("\"intOptional\" = (\"intOptional\" & \"int\")", intOptional &= int) + AssertSQL("\"intOptional\" = (\"intOptional\" & \"intOptional\")", intOptional &= intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" & 1)", intOptional &= 1) + } + + func test_bitwiseOrEquals_withIntegerExpression_buildsSetter() { + AssertSQL("\"int\" = (\"int\" | \"int\")", int |= int) + AssertSQL("\"int\" = (\"int\" | 1)", int |= 1) + AssertSQL("\"intOptional\" = (\"intOptional\" | \"int\")", intOptional |= int) + AssertSQL("\"intOptional\" = (\"intOptional\" | \"intOptional\")", intOptional |= intOptional) + AssertSQL("\"intOptional\" = (\"intOptional\" | 1)", intOptional |= 1) + } + + func test_bitwiseExclusiveOrEquals_withIntegerExpression_buildsSetter() { + AssertSQL("\"int\" = (~((\"int\" & \"int\")) & (\"int\" | \"int\"))", int ^= int) + AssertSQL("\"int\" = (~((\"int\" & 1)) & (\"int\" | 1))", int ^= 1) + AssertSQL("\"intOptional\" = (~((\"intOptional\" & \"int\")) & (\"intOptional\" | \"int\"))", intOptional ^= int) + AssertSQL("\"intOptional\" = (~((\"intOptional\" & \"intOptional\")) & (\"intOptional\" | \"intOptional\"))", intOptional ^= intOptional) + AssertSQL("\"intOptional\" = (~((\"intOptional\" & 1)) & (\"intOptional\" | 1))", intOptional ^= 1) + } + + func test_postfixPlus_withIntegerValue_buildsSetter() { + AssertSQL("\"int\" = (\"int\" + 1)", int++) + AssertSQL("\"intOptional\" = (\"intOptional\" + 1)", intOptional++) + } + + func test_postfixMinus_withIntegerValue_buildsSetter() { + AssertSQL("\"int\" = (\"int\" - 1)", int--) + AssertSQL("\"intOptional\" = (\"intOptional\" - 1)", intOptional--) + } + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/StatementTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/StatementTests.swift new file mode 100644 index 0000000000..326259b223 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/StatementTests.swift @@ -0,0 +1,26 @@ +import XCTest +import SQLite + +class StatementTests : SQLiteTestCase { + override func setUp() { + super.setUp() + CreateUsersTable() + } + + func test_cursor_to_blob() { + try! InsertUsers("alice") + let statement = try! db.prepare("SELECT email FROM users") + XCTAssert(try! statement.step()) + let blob = statement.row[0] as Blob + XCTAssertEqual("alice@example.com", String(bytes: blob.bytes, encoding: .utf8)!) + } + + func test_zero_sized_blob_returns_null() { + let blobs = Table("blobs") + let blobColumn = Expression("blob_column") + try! db.run(blobs.create { $0.column(blobColumn) }) + try! db.run(blobs.insert(blobColumn <- Blob(bytes: []))) + let blobValue = try! db.scalar(blobs.select(blobColumn).limit(1, offset: 0)) + XCTAssertEqual([], blobValue.bytes) + } +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/TestHelpers.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/TestHelpers.swift new file mode 100644 index 0000000000..8c33bf6a07 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/TestHelpers.swift @@ -0,0 +1,115 @@ +import XCTest +import SQLite + +class SQLiteTestCase : XCTestCase { + + var trace = [String: Int]() + + let db = try! Connection() + + let users = Table("users") + + override func setUp() { + super.setUp() + + db.trace { SQL in + print(SQL) + self.trace[SQL] = (self.trace[SQL] ?? 0) + 1 + } + } + + func CreateUsersTable() { + try! db.execute( + "CREATE TABLE \"users\" (" + + "id INTEGER PRIMARY KEY, " + + "email TEXT NOT NULL UNIQUE, " + + "age INTEGER, " + + "salary REAL, " + + "admin BOOLEAN NOT NULL DEFAULT 0 CHECK (admin IN (0, 1)), " + + "manager_id INTEGER, " + + "FOREIGN KEY(manager_id) REFERENCES users(id)" + + ")" + ) + } + + func InsertUsers(_ names: String...) throws { + try InsertUsers(names) + } + + func InsertUsers(_ names: [String]) throws { + for name in names { try InsertUser(name) } + } + + @discardableResult func InsertUser(_ name: String, age: Int? = nil, admin: Bool = false) throws -> Statement { + return try db.run( + "INSERT INTO \"users\" (email, age, admin) values (?, ?, ?)", + "\(name)@example.com", age?.datatypeValue, admin.datatypeValue + ) + } + + func AssertSQL(_ SQL: String, _ executions: Int = 1, _ message: String? = nil, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual( + executions, trace[SQL] ?? 0, + message ?? SQL, + file: file, line: line + ) + } + + func AssertSQL(_ SQL: String, _ statement: Statement, _ message: String? = nil, file: StaticString = #file, line: UInt = #line) { + try! statement.run() + AssertSQL(SQL, 1, message, file: file, line: line) + if let count = trace[SQL] { trace[SQL] = count - 1 } + } + +// func AssertSQL(SQL: String, _ query: Query, _ message: String? = nil, file: String = __FILE__, line: UInt = __LINE__) { +// for _ in query {} +// AssertSQL(SQL, 1, message, file: file, line: line) +// if let count = trace[SQL] { trace[SQL] = count - 1 } +// } + + func async(expect description: String = "async", timeout: Double = 5, block: (@escaping () -> Void) -> Void) { + let expectation = self.expectation(description: description) + block(expectation.fulfill) + waitForExpectations(timeout: timeout, handler: nil) + } + +} + +let bool = Expression("bool") +let boolOptional = Expression("boolOptional") + +let data = Expression("blob") +let dataOptional = Expression("blobOptional") + +let date = Expression("date") +let dateOptional = Expression("dateOptional") + +let double = Expression("double") +let doubleOptional = Expression("doubleOptional") + +let int = Expression("int") +let intOptional = Expression("intOptional") + +let int64 = Expression("int64") +let int64Optional = Expression("int64Optional") + +let string = Expression("string") +let stringOptional = Expression("stringOptional") + +func AssertSQL(_ expression1: @autoclosure () -> String, _ expression2: @autoclosure () -> Expressible, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(expression1(), expression2().asSQL(), file: file, line: line) +} + +func AssertThrows(_ expression: @autoclosure () throws -> T, file: StaticString = #file, line: UInt = #line) { + do { + _ = try expression() + XCTFail("expression expected to throw", file: file, line: line) + } catch { + XCTAssert(true, file: file, line: line) + } +} + +let table = Table("table") +let qualifiedTable = Table("table", database: "main") +let virtualTable = VirtualTable("virtual_table") +let _view = View("view") // avoid Mac XCTestCase collision diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ValueTests.swift b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ValueTests.swift new file mode 100644 index 0000000000..bda2b4b380 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ValueTests.swift @@ -0,0 +1,6 @@ +import XCTest +import SQLite + +class ValueTests : XCTestCase { + +} diff --git a/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/fixtures/encrypted.sqlite b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/fixtures/encrypted.sqlite new file mode 100644 index 0000000000..4b3c4d0ec0 Binary files /dev/null and b/mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/fixtures/encrypted.sqlite differ diff --git a/mobile/ios/ThirdParty/SQLite.swift/run-tests.sh b/mobile/ios/ThirdParty/SQLite.swift/run-tests.sh new file mode 100644 index 0000000000..ddd7d67834 --- /dev/null +++ b/mobile/ios/ThirdParty/SQLite.swift/run-tests.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -ev +if [ -n "$BUILD_SCHEME" ]; then + if [ -n "$IOS_SIMULATOR" ]; then + make test BUILD_SCHEME="$BUILD_SCHEME" IOS_SIMULATOR="$IOS_SIMULATOR" + else + make test BUILD_SCHEME="$BUILD_SCHEME" + fi +elif [ -n "$VALIDATOR_SUBSPEC" ]; then + cd Tests/CocoaPods && make test +elif [ -n "$CARTHAGE_PLATFORM" ]; then + cd Tests/Carthage && make test CARTHAGE_PLATFORM="$CARTHAGE_PLATFORM" +elif [ -n "${PACKAGE_MANAGER_COMMAND}" ]; then + swift ${PACKAGE_MANAGER_COMMAND} +fi diff --git a/mobile/ios/ThirdParty/SWTableViewCell/AppDelegate.h b/mobile/ios/ThirdParty/SWTableViewCell/AppDelegate.h new file mode 100644 index 0000000000..c3982020c4 --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// SWTableViewCell +// +// Created by Chris Wendel on 9/10/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/mobile/ios/ThirdParty/SWTableViewCell/AppDelegate.m b/mobile/ios/ThirdParty/SWTableViewCell/AppDelegate.m new file mode 100644 index 0000000000..0eb3256110 --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/AppDelegate.m @@ -0,0 +1,46 @@ +// +// AppDelegate.m +// SWTableViewCell +// +// Created by Chris Wendel on 9/10/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import "AppDelegate.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + // Override point for customization after application launch. + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/mobile/ios/ThirdParty/SWTableViewCell/Default-568h@2x.png b/mobile/ios/ThirdParty/SWTableViewCell/Default-568h@2x.png new file mode 100644 index 0000000000..0891b7aabf Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/Default-568h@2x.png differ diff --git a/mobile/ios/ThirdParty/SWTableViewCell/Default.png b/mobile/ios/ThirdParty/SWTableViewCell/Default.png new file mode 100644 index 0000000000..4c8ca6f693 Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/Default.png differ diff --git a/mobile/ios/ThirdParty/SWTableViewCell/Default@2x.png b/mobile/ios/ThirdParty/SWTableViewCell/Default@2x.png new file mode 100644 index 0000000000..35b84cffeb Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/Default@2x.png differ diff --git a/mobile/ios/ThirdParty/SWTableViewCell/MI.png b/mobile/ios/ThirdParty/SWTableViewCell/MI.png new file mode 100644 index 0000000000..d1a1c077e5 Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/MI.png differ diff --git a/mobile/ios/ThirdParty/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.h b/mobile/ios/ThirdParty/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.h new file mode 100644 index 0000000000..87edf77c31 --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.h @@ -0,0 +1,25 @@ +// +// NSMutableArray+SWUtilityButtons.h +// SWTableViewCell +// +// Created by Matt Bowman on 11/27/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import + +@interface NSMutableArray (SWUtilityButtons) + +- (void)sw_addUtilityButtonWithColor:(UIColor *)color title:(NSString *)title; +- (void)sw_addUtilityButtonWithColor:(UIColor *)color attributedTitle:(NSAttributedString *)title; +- (void)sw_addUtilityButtonWithColor:(UIColor *)color icon:(UIImage *)icon; +- (void)sw_addUtilityButtonWithColor:(UIColor *)color normalIcon:(UIImage *)normalIcon selectedIcon:(UIImage *)selectedIcon; + +@end + + +@interface NSArray (SWUtilityButtons) + +- (BOOL)sw_isEqualToButtons:(NSArray *)buttons; + +@end diff --git a/mobile/ios/ThirdParty/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.m b/mobile/ios/ThirdParty/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.m new file mode 100644 index 0000000000..2d32b75298 --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/PodFiles/NSMutableArray+SWUtilityButtons.m @@ -0,0 +1,92 @@ +// +// NSMutableArray+SWUtilityButtons.m +// SWTableViewCell +// +// Created by Matt Bowman on 11/27/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import "NSMutableArray+SWUtilityButtons.h" + +@implementation NSMutableArray (SWUtilityButtons) + +- (void)sw_addUtilityButtonWithColor:(UIColor *)color title:(NSString *)title +{ + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.backgroundColor = color; + [button setTitle:title forState:UIControlStateNormal]; + [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [button.titleLabel setAdjustsFontSizeToFitWidth:YES]; + [self addObject:button]; +} + +- (void)sw_addUtilityButtonWithColor:(UIColor *)color attributedTitle:(NSAttributedString *)title +{ + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.backgroundColor = color; + [button setAttributedTitle:title forState:UIControlStateNormal]; + [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self addObject:button]; +} + +- (void)sw_addUtilityButtonWithColor:(UIColor *)color icon:(UIImage *)icon +{ + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.backgroundColor = color; + [button setImage:icon forState:UIControlStateNormal]; + [self addObject:button]; +} + +- (void)sw_addUtilityButtonWithColor:(UIColor *)color normalIcon:(UIImage *)normalIcon selectedIcon:(UIImage *)selectedIcon { + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.backgroundColor = color; + [button setImage:normalIcon forState:UIControlStateNormal]; + [button setImage:selectedIcon forState:UIControlStateHighlighted]; + [button setImage:selectedIcon forState:UIControlStateSelected]; + [self addObject:button]; +} + +@end + + +@implementation NSArray (SWUtilityButtons) + +- (BOOL)sw_isEqualToButtons:(NSArray *)buttons +{ + buttons = [buttons copy]; + if (!buttons || self.count != buttons.count) return NO; + + for (NSUInteger idx = 0; idx < self.count; idx++) { + id buttonA = self[idx]; + id buttonB = buttons[idx]; + if (![buttonA isKindOfClass:[UIButton class]] || ![buttonB isKindOfClass:[UIButton class]]) return NO; + if (![[self class] sw_button:buttonA isEqualToButton:buttonB]) return NO; + } + + return YES; +} + ++ (BOOL)sw_button:(UIButton *)buttonA isEqualToButton:(UIButton *)buttonB +{ + if (!buttonA || !buttonB) return NO; + + UIColor *backgroundColorA = buttonA.backgroundColor; + UIColor *backgroundColorB = buttonB.backgroundColor; + BOOL haveEqualBackgroundColors = (!backgroundColorA && !backgroundColorB) || [backgroundColorA isEqual:backgroundColorB]; + + NSString *titleA = [buttonA titleForState:UIControlStateNormal]; + NSString *titleB = [buttonB titleForState:UIControlStateNormal]; + BOOL haveEqualTitles = (!titleA && !titleB) || [titleA isEqualToString:titleB]; + + UIImage *normalIconA = [buttonA imageForState:UIControlStateNormal]; + UIImage *normalIconB = [buttonB imageForState:UIControlStateNormal]; + BOOL haveEqualNormalIcons = (!normalIconA && !normalIconB) || [normalIconA isEqual:normalIconB]; + + UIImage *selectedIconA = [buttonA imageForState:UIControlStateSelected]; + UIImage *selectedIconB = [buttonB imageForState:UIControlStateSelected]; + BOOL haveEqualSelectedIcons = (!selectedIconA && !selectedIconB) || [selectedIconA isEqual:selectedIconB]; + + return haveEqualBackgroundColors && haveEqualTitles && haveEqualNormalIcons && haveEqualSelectedIcons; +} + +@end diff --git a/mobile/ios/ThirdParty/SWTableViewCell/SWTableViewCell-Info.plist b/mobile/ios/ThirdParty/SWTableViewCell/SWTableViewCell-Info.plist new file mode 100644 index 0000000000..2f1980ef53 --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/SWTableViewCell-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.ChrisWendel.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UILaunchStoryboardName + MainStoryboard + UIMainStoryboardFile + MainStoryboard + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/mobile/ios/ThirdParty/SWTableViewCell/SWTableViewCell-Prefix.pch b/mobile/ios/ThirdParty/SWTableViewCell/SWTableViewCell-Prefix.pch new file mode 100644 index 0000000000..4fad5d9f4f --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/SWTableViewCell-Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header for all source files of the 'SWTableViewCell' target in the 'SWTableViewCell' project +// + +#import + +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/mobile/ios/ThirdParty/SWTableViewCell/UMTableViewCell.h b/mobile/ios/ThirdParty/SWTableViewCell/UMTableViewCell.h new file mode 100644 index 0000000000..470258884a --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/UMTableViewCell.h @@ -0,0 +1,20 @@ +// +// UMTableViewCell.h +// SWTableViewCell +// +// Created by Matt Bowman on 12/2/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import +#import "SWTableViewCell.h" + +/* + * Example of a custom cell built in Storyboard + */ +@interface UMTableViewCell : SWTableViewCell + +@property (weak, nonatomic) IBOutlet UIImageView *image; +@property (weak, nonatomic) IBOutlet UILabel *label; + +@end diff --git a/mobile/ios/ThirdParty/SWTableViewCell/UMTableViewCell.m b/mobile/ios/ThirdParty/SWTableViewCell/UMTableViewCell.m new file mode 100644 index 0000000000..23b5591d98 --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/UMTableViewCell.m @@ -0,0 +1,13 @@ +// +// UMTableViewCell.m +// SWTableViewCell +// +// Created by Matt Bowman on 12/2/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import "UMTableViewCell.h" + +@implementation UMTableViewCell + +@end diff --git a/mobile/ios/ThirdParty/SWTableViewCell/ViewController.h b/mobile/ios/ThirdParty/SWTableViewCell/ViewController.h new file mode 100644 index 0000000000..474c0c2924 --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/ViewController.h @@ -0,0 +1,14 @@ +// +// ViewController.h +// SWTableViewCell +// +// Created by Chris Wendel on 9/10/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import +#import "SWTableViewCell.h" + +@interface ViewController : UITableViewController + +@end diff --git a/mobile/ios/ThirdParty/SWTableViewCell/ViewController.m b/mobile/ios/ThirdParty/SWTableViewCell/ViewController.m new file mode 100644 index 0000000000..3efe130e3f --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/ViewController.m @@ -0,0 +1,292 @@ +// +// ViewController.m +// SWTableViewCell +// +// Created by Chris Wendel on 9/10/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import "ViewController.h" +#import "SWTableViewCell.h" +#import "UMTableViewCell.h" + +@interface ViewController () { + NSArray *_sections; + NSMutableArray *_testArray; +} + +@property (nonatomic, weak) IBOutlet UITableView *tableView; +@property (nonatomic) BOOL useCustomCells; +@property (nonatomic, weak) UIRefreshControl *refreshControl; + +@end + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.navigationItem.leftBarButtonItem = self.editButtonItem; + self.tableView.rowHeight = 90; + + self.navigationItem.title = @"Pull to Toggle Cell Type"; + + // Setup refresh control for example app + UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; + [refreshControl addTarget:self action:@selector(toggleCells:) forControlEvents:UIControlEventValueChanged]; + refreshControl.tintColor = [UIColor blueColor]; + + self.refreshControl = refreshControl; + + // If you set the seperator inset on iOS 6 you get a NSInvalidArgumentException...weird + if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) { + self.tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0); // Makes the horizontal row seperator stretch the entire length of the table view + } + + _sections = [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles]; + + _testArray = [[NSMutableArray alloc] init]; + + self.useCustomCells = NO; + + for (int i = 0; i < _sections.count; ++i) { + [_testArray addObject:[NSMutableArray array]]; + } + + for (int i = 0; i < 100; ++i) { + NSString *string = [NSString stringWithFormat:@"%d", i]; + [_testArray[i % _sections.count] addObject:string]; + } +} + +#pragma mark UITableViewDataSource + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return _testArray.count; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [_testArray[section] count]; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + NSLog(@"cell selected at index path %ld:%ld", (long)indexPath.section, (long)indexPath.row); + NSLog(@"selected cell index path is %@", [self.tableView indexPathForSelectedRow]); + + if (!tableView.isEditing) { + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + } +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { + return _sections[section]; +} + +// Show index titles + +//- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { +// return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles]; +//} +// +//- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { +// return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex:index]; +//} + +#pragma mark - UIRefreshControl Selector + +- (void)toggleCells:(UIRefreshControl*)refreshControl +{ + [refreshControl beginRefreshing]; + self.useCustomCells = !self.useCustomCells; + if (self.useCustomCells) + { + self.refreshControl.tintColor = [UIColor yellowColor]; + } + else + { + self.refreshControl.tintColor = [UIColor blueColor]; + } + [self.tableView reloadData]; + [refreshControl endRefreshing]; +} + +#pragma mark - UIScrollViewDelegate + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + if (self.useCustomCells) + { + UMTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"UMCell" forIndexPath:indexPath]; + + // optionally specify a width that each set of utility buttons will share + [cell setLeftUtilityButtons:[self leftButtons] WithButtonWidth:32.0f]; + [cell setRightUtilityButtons:[self rightButtons] WithButtonWidth:58.0f]; + cell.delegate = self; + + cell.label.text = [NSString stringWithFormat:@"Section: %ld, Seat: %ld", (long)indexPath.section, (long)indexPath.row]; + + return cell; + } + else + { + static NSString *cellIdentifier = @"Cell"; + + SWTableViewCell *cell = (SWTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; + + if (cell == nil) { + + cell = [[SWTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier]; + + cell.leftUtilityButtons = [self leftButtons]; + cell.rightUtilityButtons = [self rightButtons]; + cell.delegate = self; + } + + NSDate *dateObject = _testArray[indexPath.section][indexPath.row]; + cell.textLabel.text = [dateObject description]; + cell.textLabel.backgroundColor = [UIColor whiteColor]; + cell.detailTextLabel.backgroundColor = [UIColor whiteColor]; + cell.detailTextLabel.text = @"Some detail text"; + + return cell; + } + +} + +- (NSArray *)rightButtons +{ + NSMutableArray *rightUtilityButtons = [NSMutableArray new]; + [rightUtilityButtons sw_addUtilityButtonWithColor: + [UIColor colorWithRed:0.78f green:0.78f blue:0.8f alpha:1.0] + title:@"More"]; + [rightUtilityButtons sw_addUtilityButtonWithColor: + [UIColor colorWithRed:1.0f green:0.231f blue:0.188 alpha:1.0f] + title:@"Delete"]; + + return rightUtilityButtons; +} + +- (NSArray *)leftButtons +{ + NSMutableArray *leftUtilityButtons = [NSMutableArray new]; + + [leftUtilityButtons sw_addUtilityButtonWithColor: + [UIColor colorWithRed:0.07 green:0.75f blue:0.16f alpha:1.0] + icon:[UIImage imageNamed:@"check.png"]]; + [leftUtilityButtons sw_addUtilityButtonWithColor: + [UIColor colorWithRed:1.0f green:1.0f blue:0.35f alpha:1.0] + icon:[UIImage imageNamed:@"clock.png"]]; + [leftUtilityButtons sw_addUtilityButtonWithColor: + [UIColor colorWithRed:1.0f green:0.231f blue:0.188f alpha:1.0] + icon:[UIImage imageNamed:@"cross.png"]]; + [leftUtilityButtons sw_addUtilityButtonWithColor: + [UIColor colorWithRed:0.55f green:0.27f blue:0.07f alpha:1.0] + icon:[UIImage imageNamed:@"list.png"]]; + + return leftUtilityButtons; +} + +// Set row height on an individual basis + +//- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ +// return [self rowHeightForIndexPath:indexPath]; +//} +// +//- (CGFloat)rowHeightForIndexPath:(NSIndexPath *)indexPath { +// return ([indexPath row] * 10) + 60; +//} + +- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { + // Set background color of cell here if you don't want default white +} + +#pragma mark - SWTableViewDelegate + +- (void)swipeableTableViewCell:(SWTableViewCell *)cell scrollingToState:(SWCellState)state +{ + switch (state) { + case 0: + NSLog(@"utility buttons closed"); + break; + case 1: + NSLog(@"left utility buttons open"); + break; + case 2: + NSLog(@"right utility buttons open"); + break; + default: + break; + } +} + +- (void)swipeableTableViewCell:(SWTableViewCell *)cell didTriggerLeftUtilityButtonWithIndex:(NSInteger)index +{ + switch (index) { + case 0: + NSLog(@"left button 0 was pressed"); + break; + case 1: + NSLog(@"left button 1 was pressed"); + break; + case 2: + NSLog(@"left button 2 was pressed"); + break; + case 3: + NSLog(@"left btton 3 was pressed"); + default: + break; + } +} + +- (void)swipeableTableViewCell:(SWTableViewCell *)cell didTriggerRightUtilityButtonWithIndex:(NSInteger)index +{ + switch (index) { + case 0: + { + NSLog(@"More button was pressed"); + UIAlertView *alertTest = [[UIAlertView alloc] initWithTitle:@"Hello" message:@"More more more" delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles: nil]; + [alertTest show]; + + [cell hideUtilityButtonsAnimated:YES]; + break; + } + case 1: + { + // Delete button was pressed + NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:cell]; + + [_testArray[cellIndexPath.section] removeObjectAtIndex:cellIndexPath.row]; + [self.tableView deleteRowsAtIndexPaths:@[cellIndexPath] withRowAnimation:UITableViewRowAnimationLeft]; + break; + } + default: + break; + } +} + +- (BOOL)swipeableTableViewCellShouldHideUtilityButtonsOnSwipe:(SWTableViewCell *)cell +{ + // allow just one cell's utility button to be open at once + return YES; +} + +- (BOOL)swipeableTableViewCell:(SWTableViewCell *)cell canSwipeToState:(SWCellState)state +{ + switch (state) { + case 1: + // set to NO to disable all left utility buttons appearing + return YES; + break; + case 2: + // set to NO to disable all right utility buttons appearing + return YES; + break; + default: + break; + } + + return YES; +} + + +@end \ No newline at end of file diff --git a/mobile/ios/ThirdParty/SWTableViewCell/check@2x.png b/mobile/ios/ThirdParty/SWTableViewCell/check@2x.png new file mode 100644 index 0000000000..d3a3a6e23e Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/check@2x.png differ diff --git a/mobile/ios/ThirdParty/SWTableViewCell/clock@2x.png b/mobile/ios/ThirdParty/SWTableViewCell/clock@2x.png new file mode 100644 index 0000000000..184ad4c41d Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/clock@2x.png differ diff --git a/mobile/ios/ThirdParty/SWTableViewCell/cross@2x.png b/mobile/ios/ThirdParty/SWTableViewCell/cross@2x.png new file mode 100644 index 0000000000..053ee0d8e4 Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/cross@2x.png differ diff --git a/mobile/ios/ThirdParty/SWTableViewCell/en.lproj/InfoPlist.strings b/mobile/ios/ThirdParty/SWTableViewCell/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000..477b28ff8f --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/mobile/ios/ThirdParty/SWTableViewCell/en.lproj/MainStoryboard.storyboard b/mobile/ios/ThirdParty/SWTableViewCell/en.lproj/MainStoryboard.storyboard new file mode 100644 index 0000000000..ce553c1619 --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/en.lproj/MainStoryboard.storyboard @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/ios/ThirdParty/SWTableViewCell/list@2x.png b/mobile/ios/ThirdParty/SWTableViewCell/list@2x.png new file mode 100644 index 0000000000..b8ad135f04 Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/list@2x.png differ diff --git a/mobile/ios/ThirdParty/SWTableViewCell/main.m b/mobile/ios/ThirdParty/SWTableViewCell/main.m new file mode 100644 index 0000000000..03d31e30dd --- /dev/null +++ b/mobile/ios/ThirdParty/SWTableViewCell/main.m @@ -0,0 +1,18 @@ +// +// main.m +// SWTableViewCell +// +// Created by Chris Wendel on 9/10/13. +// Copyright (c) 2013 Chris Wendel. All rights reserved. +// + +#import + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/mobile/ios/ThirdParty/SWTableViewCell/um.png b/mobile/ios/ThirdParty/SWTableViewCell/um.png new file mode 100644 index 0000000000..cd3b85e43c Binary files /dev/null and b/mobile/ios/ThirdParty/SWTableViewCell/um.png differ diff --git a/mobile/ios/ThirdParty/UIImageColors.swift b/mobile/ios/ThirdParty/UIImageColors.swift new file mode 100644 index 0000000000..2441a003af --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageColors.swift @@ -0,0 +1,278 @@ +// +// UIImageColors.swift +// https://github.com/jathu/UIImageColors +// +// Created by Jathu Satkunarajah (@jathu) on 2015-06-11 - Toronto +// Original Cocoa version by Panic Inc. - Portland +// + +import UIKit + +public struct UIImageColors { + public var background: UIColor! + public var primary: UIColor! + public var secondary: UIColor! + public var detail: UIColor! +} + +class PCCountedColor { + let color: UIColor + let count: Int + + init(color: UIColor, count: Int) { + self.color = color + self.count = count + } +} + +extension CGColor { + var components: [CGFloat] { + get { + var red = CGFloat() + var green = CGFloat() + var blue = CGFloat() + var alpha = CGFloat() + UIColor(cgColor: self).getRed(&red, green: &green, blue: &blue, alpha: &alpha) + return [red,green,blue,alpha] + } + } +} + +extension UIColor { + + var isDarkColor: Bool { + let RGB = self.cgColor.components + return (0.2126 * RGB[0] + 0.7152 * RGB[1] + 0.0722 * RGB[2]) < 0.5 + } + + var isBlackOrWhite: Bool { + let RGB = self.cgColor.components + return (RGB[0] > 0.91 && RGB[1] > 0.91 && RGB[2] > 0.91) || (RGB[0] < 0.09 && RGB[1] < 0.09 && RGB[2] < 0.09) + } + + func isDistinct(compareColor: UIColor) -> Bool { + let bg = self.cgColor.components + let fg = compareColor.cgColor.components + let threshold: CGFloat = 0.25 + + if fabs(bg[0] - fg[0]) > threshold || fabs(bg[1] - fg[1]) > threshold || fabs(bg[2] - fg[2]) > threshold { + if fabs(bg[0] - bg[1]) < 0.03 && fabs(bg[0] - bg[2]) < 0.03 { + if fabs(fg[0] - fg[1]) < 0.03 && fabs(fg[0] - fg[2]) < 0.03 { + return false + } + } + return true + } + return false + } + + func colorWithMinimumSaturation(minSaturation: CGFloat) -> UIColor { + var hue: CGFloat = 0.0 + var saturation: CGFloat = 0.0 + var brightness: CGFloat = 0.0 + var alpha: CGFloat = 0.0 + self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) + + if saturation < minSaturation { + return UIColor(hue: hue, saturation: minSaturation, brightness: brightness, alpha: alpha) + } else { + return self + } + } + + func isContrastingColor(compareColor: UIColor) -> Bool { + let bg = self.cgColor.components + let fg = compareColor.cgColor.components + + let bgLum = 0.2126 * bg[0] + 0.7152 * bg[1] + 0.0722 * bg[2] + let fgLum = 0.2126 * fg[0] + 0.7152 * fg[1] + 0.0722 * fg[2] + + let bgGreater = bgLum > fgLum + let nom = bgGreater ? bgLum : fgLum + let denom = bgGreater ? fgLum : bgLum + let contrast = (nom + 0.05) / (denom + 0.05) + return 1.6 < contrast + } + +} + +extension UIImage { + private func resizeForUIImageColors(newSize: CGSize) -> UIImage { + UIGraphicsBeginImageContextWithOptions(newSize, false, 0) + defer { + UIGraphicsEndImageContext() + } + self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)) + guard let result = UIGraphicsGetImageFromCurrentImageContext() else { + fatalError("UIImageColors.resizeForUIImageColors failed: UIGraphicsGetImageFromCurrentImageContext returned nil") + } + + return result + } + + /** + Get `UIImageColors` from the image asynchronously (in background thread). + Discussion: Use smaller sizes for better performance at the cost of quality colors. Use larger sizes for better color sampling and quality at the cost of performance. + + - parameter scaleDownSize: Downscale size of image for sampling, if `CGSize.zero` is provided, the sample image is rescaled to a width of 250px and the aspect ratio height. + - parameter completionHandler: `UIImageColors` for this image. + */ + public func getColors(scaleDownSize: CGSize = CGSize.zero, completionHandler: @escaping (UIImageColors) -> Void) { + DispatchQueue.global().async { + let result = self.getColors(scaleDownSize: scaleDownSize) + + DispatchQueue.main.async { + completionHandler(result) + } + } + } + + /** + Get `UIImageColors` from the image synchronously (in main thread). + Discussion: Use smaller sizes for better performance at the cost of quality colors. Use larger sizes for better color sampling and quality at the cost of performance. + + - parameter scaleDownSize: Downscale size of image for sampling, if `CGSize.zero` is provided, the sample image is rescaled to a width of 250px and the aspect ratio height. + + - returns: `UIImageColors` for this image. + */ + public func getColors(scaleDownSize: CGSize = CGSize.zero) -> UIImageColors { + + var scaleDownSize = scaleDownSize + + if scaleDownSize == CGSize.zero { + let ratio = self.size.width/self.size.height + let r_width: CGFloat = 250 + scaleDownSize = CGSize(width: r_width, height: r_width/ratio) + } + + var result = UIImageColors() + + let cgImage = self.resizeForUIImageColors(newSize: scaleDownSize).cgImage! + let width: Int = cgImage.width + let height: Int = cgImage.height + + let blackColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1) + let whiteColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1) + + let randomColorsThreshold = Int(CGFloat(height)*0.01) + let sortedColorComparator: Comparator = { (main, other) -> ComparisonResult in + let m = main as! PCCountedColor, o = other as! PCCountedColor + if m.count < o.count { + return ComparisonResult.orderedDescending + } else if m.count == o.count { + return ComparisonResult.orderedSame + } else { + return ComparisonResult.orderedAscending + } + } + + guard let data = CFDataGetBytePtr(cgImage.dataProvider!.data) else { + fatalError("UIImageColors.getColors failed: could not get cgImage data") + } + + // Filter out and collect pixels from image + let imageColors = NSCountedSet(capacity: width * height) + + for x in 0.. 0.3 { + if !nextProposedEdgeColor.color.isBlackOrWhite { + proposedEdgeColor = nextProposedEdgeColor + break + } + } else { + break + } + } + } + result.background = proposedEdgeColor.color + + // Get foreground colors + enumerator = imageColors.objectEnumerator() + sortedColors.removeAllObjects() + sortedColors = NSMutableArray(capacity: imageColors.count) + let findDarkTextColor = !result.background.isDarkColor + + while var kolor = enumerator.nextObject() as? UIColor { + kolor = kolor.colorWithMinimumSaturation(minSaturation: 0.15) + if kolor.isDarkColor == findDarkTextColor { + let colorCount = imageColors.count(for: kolor) + sortedColors.add(PCCountedColor(color: kolor, count: colorCount)) + } + } + sortedColors.sort(comparator: sortedColorComparator) + + for curContainer in sortedColors { + let kolor = (curContainer as! PCCountedColor).color + + if result.primary == nil { + if kolor.isContrastingColor(compareColor: result.background) { + result.primary = kolor + } + } else if result.secondary == nil { + if !result.primary.isDistinct(compareColor: kolor) || !kolor.isContrastingColor(compareColor: result.background) { + continue + } + + result.secondary = kolor + } else if result.detail == nil { + if !result.secondary.isDistinct(compareColor: kolor) || !result.primary.isDistinct(compareColor: kolor) || !kolor.isContrastingColor(compareColor: result.background) { + continue + } + + result.detail = kolor + break + } + } + + let isDarkBackgound = result.background.isDarkColor + + if result.primary == nil { + result.primary = isDarkBackgound ? whiteColor:blackColor + } + + if result.secondary == nil { + result.secondary = isDarkBackgound ? whiteColor:blackColor + } + + if result.detail == nil { + result.detail = isDarkBackgound ? whiteColor:blackColor + } + + return result + } +} diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment.xcodeproj/project.pbxproj b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..a39ca39ba3 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment.xcodeproj/project.pbxproj @@ -0,0 +1,496 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + C027041017A6FAEC0039CEC1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C027040F17A6FAEC0039CEC1 /* Foundation.framework */; }; + C027041217A6FAEC0039CEC1 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C027041117A6FAEC0039CEC1 /* CoreGraphics.framework */; }; + C027041417A6FAEC0039CEC1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C027041317A6FAEC0039CEC1 /* UIKit.framework */; }; + C027041A17A6FAEC0039CEC1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C027041817A6FAEC0039CEC1 /* InfoPlist.strings */; }; + C027041C17A6FAEC0039CEC1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C027041B17A6FAEC0039CEC1 /* main.m */; }; + C027042017A6FAEC0039CEC1 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C027041F17A6FAEC0039CEC1 /* AppDelegate.m */; }; + C027042317A6FAEC0039CEC1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C027042117A6FAEC0039CEC1 /* Main.storyboard */; }; + C027042617A6FAEC0039CEC1 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C027042517A6FAEC0039CEC1 /* ViewController.m */; }; + C027042817A6FAEC0039CEC1 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C027042717A6FAEC0039CEC1 /* Images.xcassets */; }; + C027042F17A6FAEC0039CEC1 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C027042E17A6FAEC0039CEC1 /* XCTest.framework */; }; + C027043017A6FAEC0039CEC1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C027040F17A6FAEC0039CEC1 /* Foundation.framework */; }; + C027043117A6FAEC0039CEC1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C027041317A6FAEC0039CEC1 /* UIKit.framework */; }; + C027043917A6FAEC0039CEC1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C027043717A6FAEC0039CEC1 /* InfoPlist.strings */; }; + C027043B17A6FAEC0039CEC1 /* ImageAlignmentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C027043A17A6FAEC0039CEC1 /* ImageAlignmentTests.m */; }; + C027044717A6FB170039CEC1 /* UIImageViewAligned.m in Sources */ = {isa = PBXBuildFile; fileRef = C027044617A6FB170039CEC1 /* UIImageViewAligned.m */; }; + C027044917A6FE200039CEC1 /* melinda_landscape.jpg in Resources */ = {isa = PBXBuildFile; fileRef = C027044817A6FE200039CEC1 /* melinda_landscape.jpg */; }; + C027044B17A6FE780039CEC1 /* melinda_portrait.jpg in Resources */ = {isa = PBXBuildFile; fileRef = C027044A17A6FE780039CEC1 /* melinda_portrait.jpg */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + C027043217A6FAEC0039CEC1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C027040417A6FAEC0039CEC1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C027040B17A6FAEC0039CEC1; + remoteInfo = ImageAlignment; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + C027040C17A6FAEC0039CEC1 /* ImageAlignment.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ImageAlignment.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C027040F17A6FAEC0039CEC1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + C027041117A6FAEC0039CEC1 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + C027041317A6FAEC0039CEC1 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + C027041717A6FAEC0039CEC1 /* ImageAlignment-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ImageAlignment-Info.plist"; sourceTree = ""; }; + C027041917A6FAEC0039CEC1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + C027041B17A6FAEC0039CEC1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + C027041D17A6FAEC0039CEC1 /* ImageAlignment-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ImageAlignment-Prefix.pch"; sourceTree = ""; }; + C027041E17A6FAEC0039CEC1 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + C027041F17A6FAEC0039CEC1 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + C027042217A6FAEC0039CEC1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + C027042417A6FAEC0039CEC1 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + C027042517A6FAEC0039CEC1 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + C027042717A6FAEC0039CEC1 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + C027042D17A6FAEC0039CEC1 /* ImageAlignmentTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ImageAlignmentTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + C027042E17A6FAEC0039CEC1 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + C027043617A6FAEC0039CEC1 /* ImageAlignmentTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ImageAlignmentTests-Info.plist"; sourceTree = ""; }; + C027043817A6FAEC0039CEC1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + C027043A17A6FAEC0039CEC1 /* ImageAlignmentTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImageAlignmentTests.m; sourceTree = ""; }; + C027044517A6FB170039CEC1 /* UIImageViewAligned.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIImageViewAligned.h; sourceTree = ""; }; + C027044617A6FB170039CEC1 /* UIImageViewAligned.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIImageViewAligned.m; sourceTree = ""; }; + C027044817A6FE200039CEC1 /* melinda_landscape.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = melinda_landscape.jpg; sourceTree = ""; }; + C027044A17A6FE780039CEC1 /* melinda_portrait.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = melinda_portrait.jpg; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C027040917A6FAEC0039CEC1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C027041217A6FAEC0039CEC1 /* CoreGraphics.framework in Frameworks */, + C027041417A6FAEC0039CEC1 /* UIKit.framework in Frameworks */, + C027041017A6FAEC0039CEC1 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C027042A17A6FAEC0039CEC1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C027042F17A6FAEC0039CEC1 /* XCTest.framework in Frameworks */, + C027043117A6FAEC0039CEC1 /* UIKit.framework in Frameworks */, + C027043017A6FAEC0039CEC1 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C027040317A6FAEC0039CEC1 = { + isa = PBXGroup; + children = ( + C027041517A6FAEC0039CEC1 /* ImageAlignment */, + C027043417A6FAEC0039CEC1 /* ImageAlignmentTests */, + C027040E17A6FAEC0039CEC1 /* Frameworks */, + C027040D17A6FAEC0039CEC1 /* Products */, + ); + sourceTree = ""; + }; + C027040D17A6FAEC0039CEC1 /* Products */ = { + isa = PBXGroup; + children = ( + C027040C17A6FAEC0039CEC1 /* ImageAlignment.app */, + C027042D17A6FAEC0039CEC1 /* ImageAlignmentTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + C027040E17A6FAEC0039CEC1 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C027040F17A6FAEC0039CEC1 /* Foundation.framework */, + C027041117A6FAEC0039CEC1 /* CoreGraphics.framework */, + C027041317A6FAEC0039CEC1 /* UIKit.framework */, + C027042E17A6FAEC0039CEC1 /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + C027041517A6FAEC0039CEC1 /* ImageAlignment */ = { + isa = PBXGroup; + children = ( + C027044417A6FAFD0039CEC1 /* UIImageViewAligned */, + C027041E17A6FAEC0039CEC1 /* AppDelegate.h */, + C027041F17A6FAEC0039CEC1 /* AppDelegate.m */, + C027042117A6FAEC0039CEC1 /* Main.storyboard */, + C027042417A6FAEC0039CEC1 /* ViewController.h */, + C027042517A6FAEC0039CEC1 /* ViewController.m */, + C027042717A6FAEC0039CEC1 /* Images.xcassets */, + C027044817A6FE200039CEC1 /* melinda_landscape.jpg */, + C027044A17A6FE780039CEC1 /* melinda_portrait.jpg */, + C027041617A6FAEC0039CEC1 /* Supporting Files */, + ); + path = ImageAlignment; + sourceTree = ""; + }; + C027041617A6FAEC0039CEC1 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + C027041717A6FAEC0039CEC1 /* ImageAlignment-Info.plist */, + C027041817A6FAEC0039CEC1 /* InfoPlist.strings */, + C027041B17A6FAEC0039CEC1 /* main.m */, + C027041D17A6FAEC0039CEC1 /* ImageAlignment-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + C027043417A6FAEC0039CEC1 /* ImageAlignmentTests */ = { + isa = PBXGroup; + children = ( + C027043A17A6FAEC0039CEC1 /* ImageAlignmentTests.m */, + C027043517A6FAEC0039CEC1 /* Supporting Files */, + ); + path = ImageAlignmentTests; + sourceTree = ""; + }; + C027043517A6FAEC0039CEC1 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + C027043617A6FAEC0039CEC1 /* ImageAlignmentTests-Info.plist */, + C027043717A6FAEC0039CEC1 /* InfoPlist.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + C027044417A6FAFD0039CEC1 /* UIImageViewAligned */ = { + isa = PBXGroup; + children = ( + C027044517A6FB170039CEC1 /* UIImageViewAligned.h */, + C027044617A6FB170039CEC1 /* UIImageViewAligned.m */, + ); + name = UIImageViewAligned; + path = ../../UIImageViewAligned; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C027040B17A6FAEC0039CEC1 /* ImageAlignment */ = { + isa = PBXNativeTarget; + buildConfigurationList = C027043E17A6FAEC0039CEC1 /* Build configuration list for PBXNativeTarget "ImageAlignment" */; + buildPhases = ( + C027040817A6FAEC0039CEC1 /* Sources */, + C027040917A6FAEC0039CEC1 /* Frameworks */, + C027040A17A6FAEC0039CEC1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ImageAlignment; + productName = ImageAlignment; + productReference = C027040C17A6FAEC0039CEC1 /* ImageAlignment.app */; + productType = "com.apple.product-type.application"; + }; + C027042C17A6FAEC0039CEC1 /* ImageAlignmentTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = C027044117A6FAEC0039CEC1 /* Build configuration list for PBXNativeTarget "ImageAlignmentTests" */; + buildPhases = ( + C027042917A6FAEC0039CEC1 /* Sources */, + C027042A17A6FAEC0039CEC1 /* Frameworks */, + C027042B17A6FAEC0039CEC1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + C027043317A6FAEC0039CEC1 /* PBXTargetDependency */, + ); + name = ImageAlignmentTests; + productName = ImageAlignmentTests; + productReference = C027042D17A6FAEC0039CEC1 /* ImageAlignmentTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C027040417A6FAEC0039CEC1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0500; + ORGANIZATIONNAME = "Andrei Stanescu"; + TargetAttributes = { + C027042C17A6FAEC0039CEC1 = { + TestTargetID = C027040B17A6FAEC0039CEC1; + }; + }; + }; + buildConfigurationList = C027040717A6FAEC0039CEC1 /* Build configuration list for PBXProject "ImageAlignment" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = C027040317A6FAEC0039CEC1; + productRefGroup = C027040D17A6FAEC0039CEC1 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C027040B17A6FAEC0039CEC1 /* ImageAlignment */, + C027042C17A6FAEC0039CEC1 /* ImageAlignmentTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C027040A17A6FAEC0039CEC1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C027044917A6FE200039CEC1 /* melinda_landscape.jpg in Resources */, + C027044B17A6FE780039CEC1 /* melinda_portrait.jpg in Resources */, + C027042817A6FAEC0039CEC1 /* Images.xcassets in Resources */, + C027041A17A6FAEC0039CEC1 /* InfoPlist.strings in Resources */, + C027042317A6FAEC0039CEC1 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C027042B17A6FAEC0039CEC1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C027043917A6FAEC0039CEC1 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C027040817A6FAEC0039CEC1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C027042617A6FAEC0039CEC1 /* ViewController.m in Sources */, + C027042017A6FAEC0039CEC1 /* AppDelegate.m in Sources */, + C027041C17A6FAEC0039CEC1 /* main.m in Sources */, + C027044717A6FB170039CEC1 /* UIImageViewAligned.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C027042917A6FAEC0039CEC1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C027043B17A6FAEC0039CEC1 /* ImageAlignmentTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + C027043317A6FAEC0039CEC1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C027040B17A6FAEC0039CEC1 /* ImageAlignment */; + targetProxy = C027043217A6FAEC0039CEC1 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + C027041817A6FAEC0039CEC1 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + C027041917A6FAEC0039CEC1 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + C027042117A6FAEC0039CEC1 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + C027042217A6FAEC0039CEC1 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + C027043717A6FAEC0039CEC1 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + C027043817A6FAEC0039CEC1 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C027043C17A6FAEC0039CEC1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer: AG AG (4AJVDG7NFQ)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: AG AG (4AJVDG7NFQ)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + C027043D17A6FAEC0039CEC1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer: AG AG (4AJVDG7NFQ)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: AG AG (4AJVDG7NFQ)"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C027043F17A6FAEC0039CEC1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "ImageAlignment/ImageAlignment-Prefix.pch"; + INFOPLIST_FILE = "ImageAlignment/ImageAlignment-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + C027044017A6FAEC0039CEC1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "ImageAlignment/ImageAlignment-Prefix.pch"; + INFOPLIST_FILE = "ImageAlignment/ImageAlignment-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + C027044217A6FAEC0039CEC1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ImageAlignment.app/ImageAlignment"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + "$(SYSTEM_APPS_DIR)/Xcode5-DP3.app/Contents/Developer/Library/Frameworks", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "ImageAlignment/ImageAlignment-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = "ImageAlignmentTests/ImageAlignmentTests-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + WRAPPER_EXTENSION = xctest; + }; + name = Debug; + }; + C027044317A6FAEC0039CEC1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ImageAlignment.app/ImageAlignment"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + "$(SYSTEM_APPS_DIR)/Xcode5-DP3.app/Contents/Developer/Library/Frameworks", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "ImageAlignment/ImageAlignment-Prefix.pch"; + INFOPLIST_FILE = "ImageAlignmentTests/ImageAlignmentTests-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + WRAPPER_EXTENSION = xctest; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C027040717A6FAEC0039CEC1 /* Build configuration list for PBXProject "ImageAlignment" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C027043C17A6FAEC0039CEC1 /* Debug */, + C027043D17A6FAEC0039CEC1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C027043E17A6FAEC0039CEC1 /* Build configuration list for PBXNativeTarget "ImageAlignment" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C027043F17A6FAEC0039CEC1 /* Debug */, + C027044017A6FAEC0039CEC1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C027044117A6FAEC0039CEC1 /* Build configuration list for PBXNativeTarget "ImageAlignmentTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C027044217A6FAEC0039CEC1 /* Debug */, + C027044317A6FAEC0039CEC1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C027040417A6FAEC0039CEC1 /* Project object */; +} diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/AppDelegate.h b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/AppDelegate.h new file mode 100644 index 0000000000..adac9a0ba8 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/AppDelegate.h @@ -0,0 +1,14 @@ +// +// AppDelegate.h +// ImageAlignment +// +// Created by Andrei Stanescu on 7/29/13. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/AppDelegate.m b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/AppDelegate.m new file mode 100644 index 0000000000..27c9e72bfc --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/AppDelegate.m @@ -0,0 +1,45 @@ +// +// AppDelegate.m +// ImageAlignment +// +// Created by Andrei Stanescu on 7/29/13. +// + +#import "AppDelegate.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + // Override point for customization after application launch. + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Base.lproj/Main.storyboard b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..1b1114e388 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Base.lproj/Main.storyboard @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ImageAlignment-Info.plist b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ImageAlignment-Info.plist new file mode 100644 index 0000000000..3367744dd2 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ImageAlignment-Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.reydanro.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ImageAlignment-Prefix.pch b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ImageAlignment-Prefix.pch new file mode 100644 index 0000000000..82a2bb4507 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ImageAlignment-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Images.xcassets/AppIcon.appiconset/Contents.json b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..2f35679e07 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,18 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Images.xcassets/LaunchImage.launchimage/Contents.json b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000000..c79ebd3ada --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "subtype" : "retina4", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ViewController.h b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ViewController.h new file mode 100644 index 0000000000..bee6400276 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ViewController.h @@ -0,0 +1,30 @@ +// +// ViewController.h +// ImageAlignment +// +// Created by Andrei Stanescu on 7/29/13. +// + +#import +#import "UIImageViewAligned.h" + +@interface ViewController : UIViewController { + NSArray* _contentModeStrings; +} +@property (weak, nonatomic) IBOutlet UIImageViewAligned *alignedImageView; + +@property (weak, nonatomic) IBOutlet UISwitch *swLandscape; +@property (weak, nonatomic) IBOutlet UIButton *btnContentMode; +@property (weak, nonatomic) IBOutlet UISwitch *swAlignTop; +@property (weak, nonatomic) IBOutlet UISwitch *swAlignRight; +@property (weak, nonatomic) IBOutlet UISwitch *swAlignBottom; +@property (weak, nonatomic) IBOutlet UISwitch *swAlignLeft; + +- (IBAction)onSwitchLandscape:(id)sender; +- (IBAction)onButtonContentMode:(id)sender; +- (IBAction)onSwitchAlignTop:(id)sender; +- (IBAction)onSwitchAlignRight:(id)sender; +- (IBAction)onSwitchAlignBottom:(id)sender; +- (IBAction)onSwitchAlignLeft:(id)sender; + +@end diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ViewController.m b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ViewController.m new file mode 100644 index 0000000000..b536fd89fa --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/ViewController.m @@ -0,0 +1,79 @@ +// +// ViewController.m +// ImageAlignment +// +// Created by Andrei Stanescu on 7/29/13. +// + +#import "ViewController.h" + +@interface ViewController () + +@end + +@implementation ViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + _contentModeStrings = [NSArray arrayWithObjects: + @"UIViewContentModeScaleToFill", + @"UIViewContentModeScaleAspectFit", // contents scaled to fit with fixed aspect. remainder is transparent + @"UIViewContentModeScaleAspectFill", // contents scaled to fill with fixed aspect. some portion of content may be clipped. + @"UIViewContentModeRedraw", // redraw on bounds change (calls -setNeedsDisplay) + @"UIViewContentModeCenter", // contents remain same size. positioned adjusted. + @"UIViewContentModeTop", + @"UIViewContentModeBottom", + @"UIViewContentModeLeft", + @"UIViewContentModeRight", + @"UIViewContentModeTopLeft", + @"UIViewContentModeTopRight", + @"UIViewContentModeBottomLeft", + @"UIViewContentModeBottomRight", nil]; + + _swLandscape.on = (_alignedImageView.image != nil) && _alignedImageView.image.size.width >= _alignedImageView.image.size.height; + + _swAlignLeft.on = _alignedImageView.alignLeft; + _swAlignRight.on = _alignedImageView.alignRight; + _swAlignTop.on = _alignedImageView.alignTop; + _swAlignBottom.on = _alignedImageView.alignBottom; + + [self refreshContentModeButtonTitle]; +} + +- (IBAction)onSwitchLandscape:(id)sender { + if (_swLandscape.on) + _alignedImageView.image = [UIImage imageNamed:@"melinda_landscape.jpg"]; + else + _alignedImageView.image = [UIImage imageNamed:@"melinda_portrait.jpg"]; +} + +- (IBAction)onButtonContentMode:(id)sender +{ + _alignedImageView.contentMode = (_alignedImageView.contentMode + 1) % (UIViewContentModeBottomRight+1); // bit of hardcoding..but only for the purposes of this example + [self refreshContentModeButtonTitle]; +} + +- (IBAction)onSwitchAlignTop:(id)sender { + _alignedImageView.alignTop + = _swAlignTop.on; +} + +- (IBAction)onSwitchAlignRight:(id)sender { + _alignedImageView.alignRight = _swAlignRight.on; +} + +- (IBAction)onSwitchAlignBottom:(id)sender { + _alignedImageView.alignBottom = _swAlignBottom.on; +} + +- (IBAction)onSwitchAlignLeft:(id)sender { + _alignedImageView.alignLeft = _swAlignLeft.on; +} + +- (void)refreshContentModeButtonTitle +{ + [_btnContentMode setTitle:_contentModeStrings[_alignedImageView.contentMode] forState:UIControlStateNormal]; +} +@end diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/en.lproj/InfoPlist.strings b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000..477b28ff8f --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/main.m b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/main.m new file mode 100644 index 0000000000..a6392dbe6c --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/main.m @@ -0,0 +1,17 @@ +// +// main.m +// ImageAlignment +// +// Created by Andrei Stanescu on 7/29/13. +// + +#import + +#import "AppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/melinda_landscape.jpg b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/melinda_landscape.jpg new file mode 100644 index 0000000000..959506b7f4 Binary files /dev/null and b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/melinda_landscape.jpg differ diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/melinda_portrait.jpg b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/melinda_portrait.jpg new file mode 100644 index 0000000000..d59367fe31 Binary files /dev/null and b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignment/melinda_portrait.jpg differ diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/ImageAlignmentTests-Info.plist b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/ImageAlignmentTests-Info.plist new file mode 100644 index 0000000000..cd573a4509 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/ImageAlignmentTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.reydanro.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/ImageAlignmentTests.m b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/ImageAlignmentTests.m new file mode 100644 index 0000000000..811adf2f77 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/ImageAlignmentTests.m @@ -0,0 +1,35 @@ +// +// ImageAlignmentTests.m +// ImageAlignmentTests +// +// Created by Andrei Stanescu on 7/29/13. +// + +#import + +@interface ImageAlignmentTests : XCTestCase + +@end + +@implementation ImageAlignmentTests + +- (void)setUp +{ + [super setUp]; + + // Set-up code here. +} + +- (void)tearDown +{ + // Tear-down code here. + + [super tearDown]; +} + +- (void)testExample +{ + XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); +} + +@end diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/en.lproj/InfoPlist.strings b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000..477b28ff8f --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/Example/ImageAlignmentTests/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/LICENSE b/mobile/ios/ThirdParty/UIImageViewAligned/LICENSE new file mode 100644 index 0000000000..09c327440e --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Andrei Stanescu + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/README.md b/mobile/ios/ThirdParty/UIImageViewAligned/README.md new file mode 100644 index 0000000000..6c54117096 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/README.md @@ -0,0 +1,41 @@ +What is it? +=========== + +It is a subclass of `UIImageView` that allows you to customize the alignment of the displayed image inside the view's frame. +This works even if the `contentMode` is set to `AspectFit`, `AspectFill` or `ScaleToFill`. + + +Why a subclass of UIImageView, and not a standard UIView? +========================================================= +Because there are many cool categories built on top of UIImageView. Subclassing a standard UIView would mean losing them. + +For example, AFNetworking's async `UIImageView` category works perfectly using this container class, and you don't have to worry about a thing. + + +How does it work? +================= +When initialized, `UIImageViewAligned` will create a inner `UIImageView` which will actually hold the image displayed. +The main class then just repositions this inner `UIImageView` to achieve your desired alignment. + +At runtime, you can change the image, contentMode or alignment and the image will reposition itself correctly. + +The `image` property of UIImageViewAligned is overwritten to forward the calls to the inner `UIImageView`, so you can just drag-n-drop into your app. + +Compatibility +============= +From what I tested, it works on iOS 6.0+. +Also, it supports autorotation and will reposition the image correctly. + +Using Interface Builder +======================= +You can setup the alignment from Interface Builder using the `Identity Inspector` tab for the UIImageViewAligned. +There, you can add custom boolean properties that will be set when the view is instantiated. +The possible boolean names are: +`alignLeft` +`alignRight` +`alignTop` +`alignBottom` + +Below is a screenshot of an example. You will not get an immediate feedback in IB regarding your alignment, but it will work at runtime. + +![alt tag](https://raw.github.com/reydanro/UIImageViewAligned/master/docs/IBsetup.png) diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned.podspec b/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned.podspec new file mode 100644 index 0000000000..27699948f7 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned.podspec @@ -0,0 +1,21 @@ +Pod::Spec.new do |s| + + s.name = "UIImageViewAligned" + s.version = "0.0.1" + s.summary = "A UIImageView subclass which allows you to align the image left/right/top/bottom, even when contentMode is AspectFit." + + s.description = "It is a subclass of UIImageView that allows you to customize the alignment of the displayed image inside the view's frame. This works even if the contentMode is set to AspectFit, AspectFill or ScaleToFill." + + s.homepage = "https://github.com/reydanro/UIImageViewAligned" + s.license = { :type => "MIT", :file => "LICENSE" } + + s.author = "Andrei Stanescu" + s.social_media_url = "http://twitter.com/MTStudios_" + s.platform = :ios + + s.source = { :git => "https://github.com/reydanro/UIImageViewAligned.git", :tag => "[ADD THIS]" } + s.source_files = "UIImageViewAligned" + + s.framework = "UIKit" + +end diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned/UIImageViewAligned.h b/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned/UIImageViewAligned.h new file mode 100644 index 0000000000..8280b93be2 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned/UIImageViewAligned.h @@ -0,0 +1,49 @@ +// +// UIImageViewAligned.h +// awards +// +// Created by Andrei Stanescu on 7/29/13. +// + +#import + +typedef enum +{ + UIImageViewAlignmentMaskCenter = 0, + + UIImageViewAlignmentMaskLeft = 1, + UIImageViewAlignmentMaskRight = 2, + UIImageViewAlignmentMaskTop = 4, + UIImageViewAlignmentMaskBottom = 8, + + UIImageViewAlignmentMaskBottomLeft = UIImageViewAlignmentMaskBottom | UIImageViewAlignmentMaskLeft, + UIImageViewAlignmentMaskBottomRight = UIImageViewAlignmentMaskBottom | UIImageViewAlignmentMaskRight, + UIImageViewAlignmentMaskTopLeft = UIImageViewAlignmentMaskTop | UIImageViewAlignmentMaskLeft, + UIImageViewAlignmentMaskTopRight = UIImageViewAlignmentMaskTop | UIImageViewAlignmentMaskRight, + +}UIImageViewAlignmentMask; + +typedef UIImageViewAlignmentMask UIImageViewAignmentMask __attribute__((deprecated("Use UIImageViewAlignmentMask. Use of UIImageViewAignmentMask (misspelled) is deprecated."))); + + + +@interface UIImageViewAligned : UIImageView + +// This property holds the current alignment +@property (nonatomic) UIImageViewAlignmentMask alignment; + +// Properties needed for Interface Builder quick setup +@property (nonatomic) BOOL alignLeft; +@property (nonatomic) BOOL alignRight; +@property (nonatomic) BOOL alignTop; +@property (nonatomic) BOOL alignBottom; + +// Make the UIImageView scale only up or down +// This are used only if the content mode is Scaled +@property (nonatomic) BOOL enableScaleUp; +@property (nonatomic) BOOL enableScaleDown; + +// Just in case you need access to the inner image view +@property (nonatomic, readonly) UIImageView* realImageView; + +@end diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned/UIImageViewAligned.m b/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned/UIImageViewAligned.m new file mode 100644 index 0000000000..d1531058f3 --- /dev/null +++ b/mobile/ios/ThirdParty/UIImageViewAligned/UIImageViewAligned/UIImageViewAligned.m @@ -0,0 +1,245 @@ +// +// UIImageViewAligned.m +// awards +// +// Created by Andrei Stanescu on 7/29/13. +// + +#import "UIImageViewAligned.h" + +@implementation UIImageViewAligned + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + [self commonInit]; + } + return self; +} + + +- (id)initWithImage:(UIImage *)image +{ + self = [super initWithImage:image]; + if (self) + { + [self commonInit]; + } + return self; +} + +- (id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage +{ + self = [super initWithImage:image highlightedImage:highlightedImage]; + if (self) + [self commonInit]; + + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if (self) + [self commonInit]; + return self; +} + +- (void)commonInit +{ + _enableScaleDown = TRUE; + _enableScaleUp = TRUE; + + _alignment = UIImageViewAlignmentMaskCenter; + + _realImageView = [[UIImageView alloc] initWithFrame:self.bounds]; + _realImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _realImageView.contentMode = self.contentMode; + [self addSubview:_realImageView]; + + // Move any image we might have from this container to the real image view + if (super.image != nil) + { + UIImage* img = super.image; + super.image = nil; + self.image = img; + } +} + +- (UIImage*)image +{ + return _realImageView.image; +} + +- (void)setImage:(UIImage *)image +{ + [_realImageView setImage:image]; + [self setNeedsLayout]; +} + +- (void)setContentMode:(UIViewContentMode)contentMode +{ + [super setContentMode:contentMode]; + _realImageView.contentMode = contentMode; + [self setNeedsLayout]; +} + +- (void)setAlignment:(UIImageViewAlignmentMask)alignment +{ + if (_alignment == alignment) + return ; + + _alignment = alignment; + [self setNeedsLayout]; +} + +- (void)layoutSubviews +{ + CGSize realsize = [self realContentSize]; + + // Start centered + CGRect realframe = CGRectMake((self.bounds.size.width - realsize.width)/2, (self.bounds.size.height - realsize.height) / 2, realsize.width, realsize.height); + + if ((_alignment & UIImageViewAlignmentMaskLeft) != 0) + realframe.origin.x = 0; + else if ((_alignment & UIImageViewAlignmentMaskRight) != 0) + realframe.origin.x = CGRectGetMaxX(self.bounds) - realframe.size.width; + + if ((_alignment & UIImageViewAlignmentMaskTop) != 0) + realframe.origin.y = 0; + else if ((_alignment & UIImageViewAlignmentMaskBottom) != 0) + realframe.origin.y = CGRectGetMaxY(self.bounds) - realframe.size.height; + + _realImageView.frame = realframe; + + // Make sure we clear the contents of this container layer, since it refreshes from the image property once in a while. + self.layer.contents = nil; +} + +- (CGSize)realContentSize +{ + CGSize size = self.bounds.size; + + if (self.image == nil) + return size; + + switch (self.contentMode) + { + case UIViewContentModeScaleAspectFit: + { + float scalex = self.bounds.size.width / _realImageView.image.size.width; + float scaley = self.bounds.size.height / _realImageView.image.size.height; + float scale = MIN(scalex, scaley); + + if ((scale > 1.0f && !_enableScaleUp) || + (scale < 1.0f && !_enableScaleDown)) + scale = 1.0f; + size = CGSizeMake(_realImageView.image.size.width * scale, _realImageView.image.size.height * scale); + break; + } + + case UIViewContentModeScaleAspectFill: + { + float scalex = self.bounds.size.width / _realImageView.image.size.width; + float scaley = self.bounds.size.height / _realImageView.image.size.height; + float scale = MAX(scalex, scaley); + + if ((scale > 1.0f && !_enableScaleUp) || + (scale < 1.0f && !_enableScaleDown)) + scale = 1.0f; + + size = CGSizeMake(_realImageView.image.size.width * scale, _realImageView.image.size.height * scale); + break; + } + + case UIViewContentModeScaleToFill: + { + float scalex = self.bounds.size.width / _realImageView.image.size.width; + float scaley = self.bounds.size.height / _realImageView.image.size.height; + + if ((scalex > 1.0f && !_enableScaleUp) || + (scalex < 1.0f && !_enableScaleDown)) + scalex = 1.0f; + if ((scaley > 1.0f && !_enableScaleUp) || + (scaley < 1.0f && !_enableScaleDown)) + scaley = 1.0f; + + size = CGSizeMake(_realImageView.image.size.width * scalex, _realImageView.image.size.height * scaley); + break; + } + + default: + size = _realImageView.image.size; + break; + } + + return size; +} + + +#pragma mark - UIImageView overloads + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.layer.contents = nil; +} + +#pragma mark - Properties needed for Interface Builder + +- (BOOL)alignLeft +{ + return (_alignment & UIImageViewAlignmentMaskLeft) != 0; +} +- (void)setAlignLeft:(BOOL)alignLeft +{ + if (alignLeft) + self.alignment |= UIImageViewAlignmentMaskLeft; + else + self.alignment &= ~UIImageViewAlignmentMaskLeft; +} + +- (BOOL)alignRight +{ + return (_alignment & UIImageViewAlignmentMaskRight) != 0; +} +- (void)setAlignRight:(BOOL)alignRight +{ + if (alignRight) + self.alignment |= UIImageViewAlignmentMaskRight; + else + self.alignment &= ~UIImageViewAlignmentMaskRight; +} + + +- (BOOL)alignTop +{ + return (_alignment & UIImageViewAlignmentMaskTop) != 0; +} +- (void)setAlignTop:(BOOL)alignTop +{ + if (alignTop) + self.alignment |= UIImageViewAlignmentMaskTop; + else + self.alignment &= ~UIImageViewAlignmentMaskTop; +} + +- (BOOL)alignBottom +{ + return (_alignment & UIImageViewAlignmentMaskBottom) != 0; +} +- (void)setAlignBottom:(BOOL)alignBottom +{ + if (alignBottom) + self.alignment |= UIImageViewAlignmentMaskBottom; + else + self.alignment &= ~UIImageViewAlignmentMaskBottom; +} + +- (CGSize)sizeThatFits:(CGSize)size { + return [self.realImageView sizeThatFits:size]; +} + + +@end diff --git a/mobile/ios/ThirdParty/UIImageViewAligned/docs/IBsetup.png b/mobile/ios/ThirdParty/UIImageViewAligned/docs/IBsetup.png new file mode 100644 index 0000000000..9e076082bf Binary files /dev/null and b/mobile/ios/ThirdParty/UIImageViewAligned/docs/IBsetup.png differ diff --git a/mobile/ios/ThirdParty/ecec/CMakeLists.txt b/mobile/ios/ThirdParty/ecec/CMakeLists.txt new file mode 100644 index 0000000000..c678d9dc49 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/CMakeLists.txt @@ -0,0 +1,77 @@ +cmake_minimum_required(VERSION 3.1 FATAL_ERROR) +project(ece VERSION 0.9.0 LANGUAGES C) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_EXTENSIONS OFF) +set(C_STANDARD_REQUIRED ON) + +include(GNUInstallDirs) + +find_package(OpenSSL 1.1.0 REQUIRED) + +enable_testing() + +set(ECE_SOURCES + src/base64url.c + src/encrypt.c + src/decrypt.c + src/keys.c + src/params.c + src/trailer.c) +add_library(ece ${ECE_SOURCES}) +set_target_properties(ece PROPERTIES + OUTPUT_NAME ece + VERSION "${ECE_VERSION}") +target_include_directories(ece + PUBLIC include + PRIVATE src + PRIVATE ${OPENSSL_INCLUDE_DIR}) +target_link_libraries(ece PRIVATE ${OPENSSL_LIBRARIES}) +if(DEFINED ENV{COVERAGE}) + target_compile_options(ece PUBLIC "-fprofile-arcs;-ftest-coverage") + target_link_libraries(ece PUBLIC --coverage) +endif() + +add_executable(ece-decrypt tool/decrypt.c) +set_target_properties(ece-decrypt PROPERTIES EXCLUDE_FROM_ALL 1) +target_include_directories(ece-decrypt PRIVATE tool) +target_link_libraries(ece-decrypt PRIVATE ece) + +add_executable(ece-keygen tool/keygen.c) +set_target_properties(ece-keygen PROPERTIES EXCLUDE_FROM_ALL 1) +target_include_directories(ece-keygen PRIVATE tool) +target_link_libraries(ece-keygen PRIVATE ece) + +set(ECE_TEST_SOURCES + test/decrypt/aes128gcm.c + test/decrypt/aesgcm.c + test/encrypt/aes128gcm.c + test/encrypt/aesgcm.c + test/base64url.c + test/e2e.c + test/params.c + test/test.c) +add_executable(ece-test ${ECE_TEST_SOURCES}) +set_target_properties(ece-test PROPERTIES EXCLUDE_FROM_ALL 1) +target_include_directories(ece-test + PRIVATE test + PRIVATE ${OPENSSL_INCLUDE_DIR}) +target_link_libraries(ece-test + PRIVATE ece + PRIVATE ${OPENSSL_LIBRARIES}) +add_test(NAME ece-test COMMAND ece-test) +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} + -C $ --output-on-failure) +add_dependencies(check ece-test) + +if(MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX") + target_compile_definitions(ece PUBLIC "_CRT_SECURE_NO_WARNINGS") +else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Werror") + if(${CMAKE_C_COMPILER_ID} MATCHES "(Apple)?Clang") + # GCC's `-Wconversion` reports too many false positives; Clang's is more + # sophisticated. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion") + endif() +endif() diff --git a/mobile/ios/ThirdParty/ecec/LICENSE b/mobile/ios/ThirdParty/ecec/LICENSE new file mode 100644 index 0000000000..b7d9f590aa --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Kit Cambridge + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mobile/ios/ThirdParty/ecec/README.md b/mobile/ios/ThirdParty/ecec/README.md new file mode 100644 index 0000000000..57d5ec7e26 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/README.md @@ -0,0 +1,238 @@ +# ecec + +![GitHub version](https://badge.fury.io/gh/web-push-libs%2Fecec.svg) +[![Build Status](https://travis-ci.org/web-push-libs/ecec.svg?branch=master)](https://travis-ci.org/web-push-libs/ecec) +[![Coverage](https://img.shields.io/codecov/c/github/web-push-libs/ecec/master.svg)](https://codecov.io/github/web-push-libs/ecec) + +**ecec** is a C implementation of the [HTTP Encrypted Content-Encoding](http://httpwg.org/http-extensions/draft-ietf-httpbis-encryption-encoding.html) draft. It's a port of the reference [JavaScript implementation](https://github.com/martinthomson/encrypted-content-encoding). + +Encrypted content-coding is used to encrypt [Web Push messages](https://webpush-wg.github.io/webpush-encryption/), and can be used standalone. + +## Table of Contents + +- [Usage](#usage) + * [Generating subscription keys](#generating-subscription-keys) + * [`aes128gcm`](#aes128gcm) + * [`aesgcm`](#aesgcm) +- [Building](#building) + * [Dependencies](#dependencies) + * [macOS and \*nix](#macos-and-nix) + * [Windows](#windows) +- [What is encrypted content-coding?](#what-is-encrypted-content-coding) + * [Web Push](#web-push) + * [`aes128gcm`](#aes128gcm-1) + * [`aesgcm`](#aesgcm-1) +- [License](#license) + +## Usage + +### Generating subscription keys + +```c +#include + +int +main() { + // The subscription private key. This key should never be sent to the app + // server. It should be persisted with the endpoint and auth secret, and used + // to decrypt all messages sent to the subscription. + uint8_t rawRecvPrivKey[ECE_WEBPUSH_PRIVATE_KEY_LENGTH]; + + // The subscription public key. This key should be sent to the app server, + // and used to encrypt messages. The Push DOM API exposes the public key via + // `pushSubscription.getKey("p256dh")`. + uint8_t rawRecvPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; + + // The shared auth secret. This secret should be persisted with the + // subscription information, and sent to the app server. The DOM API exposes + // the auth secret via `pushSubscription.getKey("auth")`. + uint8_t authSecret[ECE_WEBPUSH_AUTH_SECRET_LENGTH]; + + int err = ece_webpush_generate_keys( + rawRecvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, rawRecvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, authSecret, ECE_WEBPUSH_AUTH_SECRET_LENGTH); + if (err) { + return 1; + } + return 0; +} +``` + +### `aes128gcm` + +This is the scheme from the latest version of the encrypted content-coding draft. It's not currently supported by any encryption library or browser, but will eventually replace `aesgcm`. This scheme removes the `Crypto-Key` and `Encryption` headers. Instead, the salt, record size, and sender public key are included in the payload as a binary header block. + +```c +// Assume `rawSubPrivKey` and `authSecret` contain the subscription private key +// and auth secret. +uint8_t rawSubPrivKey[ECE_WEBPUSH_PRIVATE_KEY_LENGTH] = {0}; +uint8_t authSecret[ECE_WEBPUSH_AUTH_SECRET_LENGTH] = {0}; + +// Assume `payload` points to the contents of the encrypted payload, and +// `payloadLen` specifies the length. +uint8_t* payload = NULL; +size_t payloadLen = 0; + +size_t plaintextLen = ece_aes128gcm_plaintext_max_length(payload, payloadLen); +assert(plaintextLen > 0); +uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); +assert(plaintext); + +int err = + ece_webpush_aes128gcm_decrypt(rawSubPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, + authSecret, ECE_WEBPUSH_AUTH_SECRET_LENGTH, + payload, payloadLen, plaintext, &plaintextLen); +assert(err == ECE_OK); + +// `plaintext[0..plaintextLen]` contains the decrypted message. + +free(plaintext); +``` + +### `aesgcm` + +All [Web Push libraries](https://github.com/web-push-libs) support the "aesgcm" scheme, as well as Firefox 46+ and Chrome 50+. The app server includes its public key in the `Crypto-Key` HTTP header, the salt and record size in the `Encryption` header, and the encrypted payload in the body of the `POST` request. + +* The `Crypto-Key` header comprises one or more comma-delimited parameters. The first parameter must include a `dh` name-value pair, containing the sender's Base64url-encoded public key. +* The `Encryption` header must include a `salt` name-value pair containing the sender's Base64url-encoded salt, and an optional `rs` pair specifying the record size. + +If the `Crypto-Key` header contains multiple keys, the sender must also include a `keyid` to match the encryption parameters to the key. The drafts have examples for [a single key without a `keyid`](https://tools.ietf.org/html/draft-ietf-webpush-encryption-04#section-5), and [multiple keys with `keyid`s](https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-02#section-5.6). + +```c +uint8_t rawSubPrivKey[ECE_WEBPUSH_PRIVATE_KEY_LENGTH] = {0}; +uint8_t authSecret[ECE_WEBPUSH_AUTH_SECRET_LENGTH] = {0}; + +const char* cryptoKeyHeader = "dh=..."; +const char* encryptionHeader = "salt=...; rs=..."; + +uint8_t* ciphertext = NULL; +size_t ciphertextLen = 0; + +uint8_t salt[ECE_SALT_LENGTH]; +uint8_t rawSenderPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; +uint32_t rs = 0; +int err = + ece_webpush_aesgcm_headers_extract_params(cryptoKeyHeader, encryptionHeader, + salt, ECE_SALT_LENGTH, + rawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, &rs); +assert(err == ECE_OK); + +size_t plaintextLen = ece_aesgcm_plaintext_max_length(rs, ciphertextLen); +assert(plaintextLen > 0); +uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); +assert(plaintext); + +err = ece_webpush_aesgcm_decrypt( + rawSubPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, rawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, rs, ciphertext, ciphertextLen, plaintext, + &plaintextLen); +assert(err == ECE_OK); + +// `plaintext[0..plaintextLen]` contains the decrypted message. + +free(plaintext); +``` + +## Building + +### Dependencies + +* [OpenSSL](https://www.openssl.org/) 1.1.0 or higher +* [CMake](https://cmake.org/) 3.1 or higher +* A C99-capable compiler, like [Clang](https://clang.llvm.org/) 3.4, [GCC](https://gcc.gnu.org/) 4.6, or [Visual Studio](https://www.visualstudio.com/vs/community/) 2015 + +### macOS and \*nix + +OpenSSL 1.1.0 is new, and backward-incompatible with 1.0.x. If your package manager ([MacPorts](https://www.macports.org/), [Homebrew](https://brew.sh/), [APT](https://help.ubuntu.com/community/AptGet/Howto), [DNF](https://dnf.readthedocs.io/en/latest/), [yum](http://yum.baseurl.org/)) doesn't have 1.1.0 yet, you'll need to compile it yourself. **ecec** does this to run its tests on [Travis CI](https://docs.travis-ci.com/user/ci-environment/); please see `.travis/install.sh` for the commands. + +In particular, you'll need to set the `OPENSSL_ROOT_DIR` cache entry for CMake to find your compiled version. To build the library: + +```shell +> mkdir build +> cd build +> cmake -DOPENSSL_ROOT_DIR=/usr/local .. +> make +``` + +To build the decryption tool: + +```shell +> make ece-decrypt +> ./ece-decrypt +``` + +To run the tests: + +```shell +> make check +``` + +### Windows + +[Shining Light](https://slproweb.com/products/Win32OpenSSL.html) provides OpenSSL binaries for Windows. The installer will ask if you want to copy the OpenSSL DLLs into the system directory, or the OpenSSL binaries directory. If you choose the binaries directory, you'll need to add it to your `Path`. + +To do so, right-click the Start button, navigate to "System" > "Advanced system settings" > "Environment Variables...", find `Path` under "System variables", click "Edit" > "New", and enter the directory name. This will be `C:\OpenSSL-Win64\bin` if you've installed the 64-bit version in the default location. + +You can then build the library like so: + +```powershell +> mkdir build +> cd build +> cmake -G "Visual Studio 14 2015 Win64" -DOPENSSL_ROOT_DIR=C:\OpenSSL-Win64 .. +> cmake --build . [--config Debug|Release] +``` + +To build the decryption tool: + +```powershell +> cmake --build . --target ece-decrypt [--config Debug|Release] +> .\[Debug|Release]\ece-decrypt +``` + +To run the tests: + +```powershell +> cmake --build . --target check [--config Debug|Release] +``` + +## What is encrypted content-coding? + +Like [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security), encrypted content-coding uses Diffie-Hellman key exchange to derive a shared secret, which, in turn, is used to derive a symmetric encryption key for a block cipher. This encoding uses [ECDH](https://en.wikipedia.org/wiki/Elliptic_curve_Diffie-Hellman) for key exchange, and [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) [GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode) for the block cipher. + +Key exchange is a process where a sender and a receiver generate public-private key pairs, then exchange public keys. The sender combines the receiver's public key with its own private key to obtain a secret. Meanwhile, the receiver combines the sender's public key with its private key to obtain the same secret. [Wikipedia](https://en.wikipedia.org/wiki/Diffie–Hellman_key_exchange) has a good visual explanation. + +The shared ECDH secret isn't directly usable as an encryption key. Instead, both the sender and receiver combine the shared ECDH secret with an [authentication secret](https://tools.ietf.org/html/draft-ietf-webpush-encryption-08#section-3.2), to produce a 32-byte pseudorandom key (PRK). The auth secret is a random 16-byte array generated by the receiver, and shared with the sender along with the receiver's public key. Both parties use [HKDF](https://tools.ietf.org/html/rfc5869) to derive the PRK from the ECDH secret, using the formula `PRK = HKDF-Expand(HKDF-Extract(authSecret, sharedSecret), prkInfo, 32)`. RFC 5869 describes the inputs to `HKDF-Expand` and `HKDF-Extract`, and how they work. `prkInfo` is different depending on the encryption scheme used; more on that later. + +Next, the sender and receiver combine the PRK with a random 16-byte salt. The salt is generated by the sender, and shared with the receiver as part of the message payload. The PRK undergoes two rounds of HKDF to derive the symmetric key and nonce: `key = HKDF-Expand(HKDF-Extract(salt, PRK), keyInfo, 16)`, and `nonce = HKDF-Expand(HKDF-Extract(salt, PRK), nonceInfo, 12)`. As with `prkInfo` above, `keyInfo` and `nonceInfo` are different depending on the exact scheme. + +Finally, the sender chunks the plaintext into fixed-size records, and includes this size in the message payload as the `rs`. The chunks are numbered 0 to N; this is called the sequence number (SEQ), and is used to derive the [IV](https://en.wikipedia.org/wiki/Initialization_vector). All chunks should be `rs` bytes long, but the final chunk can be smaller if needed. + +Each plaintext chunk is padded, then encrypted with AES using the 16-byte symmetric key and a 12-byte IV. The IV is [generated](https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-07#section-2.3) from the nonce by [XOR-ing](https://en.wikipedia.org/wiki/Exclusive_or) the last 6 bytes of the 12-byte nonce with the sequence number. Afterward, the sender appends the GCM authentication tag to the encrypted chunk, producing the final encrypted record. + +To decrypt the message, the receiver chunks the ciphertext into N encrypted records, decrypts each chunk, validates the auth tag, and removes the padding. + +### Web Push + +In Web Push, the app server is the sender, and the browser ("user agent") is the receiver. The browser generates a public-private ECDH key pair and 16-byte auth secret for each push subscription. These keys are static; they're used to decrypt all messages sent to this subscription. The browser exposes the subscription endpoint, public key, and auth secret to the web app via the [Push DOM API](https://w3c.github.io/push-api/). The web app then delivers the endpoint and keys to the app server. + +When the app server wants to send a push message, it generates its own public-private key pair, and computes the shared ECDH secret using the subscription public key. This key pair is ephemeral: it should be discarded after the message is sent, and a new key pair used for the next message. The app server encrypts the payload using the process outlined above, and includes the salt, sender public key, and ciphertext in a `POST` request to the endpoint. The push endpoint relays the encrypted payload to the browser. Finally, the browser decrypts the payload with the subscription private key, and delivers the plaintext to the web app. Because the endpoint doesn't know the private key, it can't decrypt or tamper with the message. + +### `aes128gcm` + +* `prkInfo` is the string `"WebPush: info\0"`, followed by the receiver and sender public keys in uncompressed form. Unlike `aesgcm`, these are not length-prefixed. +* `keyInfo` is the static string `"Content-Encoding: aes128gcm\0"`. +* `nonceInfo` is the static string `"Content-Encoding: nonce\0"`. +* Padding is at the end of each plaintext chunk. The padding block comprises the delimiter, which is `0x02` for the last chunk, and `0x01` for the other chunks. Up to `rs - 16` bytes of `0x0` padding can follow the delimiter. + +### `aesgcm` + +* `prkInfo` is the static string `"Content-Encoding: auth\0"`. +* `keyInfo` is `"Content-Encoding: aesgcm\0P-256\0"`, followed by the length-prefixed (unsigned 16-bit integers) receiver and sender public keys in uncompressed form. +* `nonceInfo` is `"Content-Encoding: nonce\0P-256\0"`, followed by the length-prefixed public keys in the same form as `keyInfo`. +* Padding is at the beginning of each plaintext chunk. The padding block comprises the number (unsigned 16-bit integer) of padding bytes, followed by that many `0x0`-valued bytes. + +## License + +MIT. diff --git a/mobile/ios/ThirdParty/ecec/include/ece.h b/mobile/ios/ThirdParty/ecec/include/ece.h new file mode 100644 index 0000000000..4b779b91b5 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/include/ece.h @@ -0,0 +1,625 @@ +#ifndef ECE_H +#define ECE_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define ECE_SALT_LENGTH 16 +#define ECE_TAG_LENGTH 16 +#define ECE_WEBPUSH_PRIVATE_KEY_LENGTH 32 +#define ECE_WEBPUSH_PUBLIC_KEY_LENGTH 65 +#define ECE_WEBPUSH_AUTH_SECRET_LENGTH 16 + +#define ECE_AES128GCM_MIN_RS 18 +#define ECE_AES128GCM_HEADER_LENGTH 21 +#define ECE_AES128GCM_MAX_KEY_ID_LENGTH 255 +#define ECE_AES128GCM_PAD_SIZE 1 + +#define ECE_AESGCM_MIN_RS 3 +#define ECE_AESGCM_PAD_SIZE 2 + +#define ECE_OK 0 +#define ECE_ERROR_OUT_OF_MEMORY -1 +#define ECE_ERROR_INVALID_PRIVATE_KEY -2 +#define ECE_ERROR_INVALID_PUBLIC_KEY -3 +#define ECE_ERROR_COMPUTE_SECRET -4 +#define ECE_ERROR_ENCODE_PUBLIC_KEY -5 +#define ECE_ERROR_DECRYPT -6 +#define ECE_ERROR_DECRYPT_PADDING -7 +#define ECE_ERROR_ZERO_PLAINTEXT -8 +#define ECE_ERROR_SHORT_BLOCK -9 +#define ECE_ERROR_SHORT_HEADER -10 +#define ECE_ERROR_ZERO_CIPHERTEXT -11 +#define ECE_ERROR_HKDF -12 +#define ECE_ERROR_INVALID_ENCRYPTION_HEADER -13 +#define ECE_ERROR_INVALID_CRYPTO_KEY_HEADER -14 +#define ECE_ERROR_INVALID_RS -15 +#define ECE_ERROR_INVALID_SALT -16 +#define ECE_ERROR_INVALID_DH -17 +#define ECE_ERROR_ENCRYPT -18 +#define ECE_ERROR_ENCRYPT_PADDING -19 +#define ECE_ERROR_INVALID_AUTH_SECRET -20 +#define ECE_ERROR_GENERATE_KEYS -21 +#define ECE_ERROR_DECRYPT_TRUNCATED -22 + +// Annotates a variable or parameter as unused to avoid compiler warnings. +#define ECE_UNUSED(x) (void) (x) + +/*! + * The policy for appending trailing "=" characters to Base64url-encoded output. + */ +typedef enum ece_base64url_encode_policy_e { + /*! Omits padding, even if the input is not a multiple of 4. */ + ECE_BASE64URL_OMIT_PADDING, + + /*! Includes padding if the input is not a multiple of 4. */ + ECE_BASE64URL_INCLUDE_PADDING, +} ece_base64url_encode_policy_t; + +/*! + * The policy for handling trailing "=" characters in Base64url-encoded input. + */ +typedef enum ece_base64url_decode_policy_e { + /*! + * Fails decoding if the input is unpadded. RFC 4648, section 3.2 requires + * padding, unless the referring specification prohibits it. + */ + ECE_BASE64URL_REQUIRE_PADDING, + + /*! Tolerates padded and unpadded input. */ + ECE_BASE64URL_IGNORE_PADDING, + + /*! + * Fails decoding if the input is padded. This follows the strict Base64url + * variant used in JWS (RFC 7515, Appendix C) and + * draft-ietf-httpbis-encryption-encoding-03. */ + ECE_BASE64URL_REJECT_PADDING, +} ece_base64url_decode_policy_t; + +/*! + * Generates a public-private ECDH key pair and authentication secret for a Web + * Push subscription. + * + * \sa ece_webpush_aes128gcm_decrypt(), + * ece_webpush_aesgcm_decrypt() + * + * \param rawRecvPrivKey[in] The subscription private key. This key should + * be stored locally, and used to decrypt incoming + * messages. + * \param rawRecvPrivKeyLen[in] The length of the subscription private key. Must + * be `ECE_WEBPUSH_PRIVATE_KEY_LENGTH`. + * \param rawRecvPubKey[in] The subscription public key, in uncompressed + * form. This key should be shared with the app + * server, and used to encrypt outgoing messages. + * \param rawRecvPubKeyLen[in] The length of the subscription public key. Must + * be `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param authSecret[in] The authentication secret. This secret should + * be stored locally and shared with the app + * server. It's used to derive the content + * encryption key and nonce. + * \param authSecretLen[in] The length of the authentication secret. Must + * be `ECE_WEBPUSH_AUTH_SECRET_LENGTH`. + * + * \return `ECE_OK` on success, or an error code if key + * generation fails. + */ +int +ece_webpush_generate_keys(uint8_t* rawRecvPrivKey, size_t rawRecvPrivKeyLen, + uint8_t* rawRecvPubKey, size_t rawRecvPubKeyLen, + uint8_t* authSecret, size_t authSecretLen); + +/*! + * Calculates the maximum "aes128gcm" plaintext length. The caller should + * allocate and pass an array of this length to the "aes128gcm" decryption + * functions. + * + * \sa ece_aes128gcm_decrypt(), + * ece_webpush_aes128gcm_decrypt() + * + * \param payload[in] The encrypted payload. + * \param payloadLen[in] The length of the encrypted payload. + * + * \return The maximum plaintext length, or 0 if the payload + * header is truncated or invalid. + */ +size_t +ece_aes128gcm_plaintext_max_length(const uint8_t* payload, size_t payloadLen); + +/*! + * Decrypts a message encrypted using the "aes128gcm" scheme, with a symmetric + * key. The key is shared out of band, and identified by the `keyId` parameter + * in the payload header. + * + * \sa ece_aes128gcm_plaintext_max_length(), + * ece_aes128gcm_payload_extract_params() + * + * \param ikm[in] The input keying material (IKM) for the content + * encryption key and nonce. + * \param ikmLen[in] The length of the IKM. + * \param payload[in] The encrypted payload. + * \param payloadLen[in] The length of the encrypted payload. + * \param plaintext[in] An empty array. Must be large enough to hold the + * full plaintext. + * \param plaintextLen[in,out] The input is the length of the empty `plaintext` + * array. On success, the output is set to the + * actual plaintext length, and + * `[0..plaintextLen]` contains the plaintext. + * + * \return `ECE_OK` on success, or an error code if + * the payload is empty or malformed. + */ +int +ece_aes128gcm_decrypt(const uint8_t* ikm, size_t ikmLen, const uint8_t* payload, + size_t payloadLen, uint8_t* plaintext, + size_t* plaintextLen); + +/*! + * Decrypts a Web Push message encrypted using the "aes128gcm" scheme. + * + * \sa ece_aes128gcm_plaintext_max_length() + * + * \param rawRecvPrivKey[in] The subscription private key. + * \param rawRecvPrivKeyLen[in] The length of the subscription private key. Must + * be `ECE_WEBPUSH_PRIVATE_KEY_LENGTH`. + * \param authSecret[in] The authentication secret. + * \param authSecretLen[in] The length of the authentication secret. Must be + * `ECE_WEBPUSH_AUTH_SECRET_LENGTH`. + * \param payload[in] The encrypted payload. + * \param payloadLen[in] The length of the encrypted payload. + * \param plaintext[in] An empty array. Must be large enough to hold the + * full plaintext. + * \param plaintextLen[in,out] The input is the length of the empty `plaintext` + * array. On success, the output is set to the + * the actual plaintext length, and + * `[0..plaintextLen]` contains the plaintext. + * + * \return `ECE_OK` on success, or an error code if + * the payload is empty or malformed. + */ +int +ece_webpush_aes128gcm_decrypt(const uint8_t* rawRecvPrivKey, + size_t rawRecvPrivKeyLen, + const uint8_t* authSecret, size_t authSecretLen, + const uint8_t* payload, size_t payloadLen, + uint8_t* plaintext, size_t* plaintextLen); + +/*! + * Calculates the maximum "aes128gcm" encrypted payload length. The caller + * should allocate and pass an array of this length to the "aes128gcm" + * encryption functions. + * + * \param rs[in] The record size. This is the length of each encrypted + * plaintext chunk, including room for the padding + * delimiter and GCM authentication tag. Must be at + * least `ECE_AES128GCM_MIN_RS`. + * \param padLen[in] The length of additional padding, used to hide the + * plaintext length. Padding is added to the plaintext + * during encryption, and discarded during decryption. + * \param plaintextLen[in] The length of the plaintext. + * + * \return The maximum payload length, or 0 if `rs` is too + * small. + */ +size_t +ece_aes128gcm_payload_max_length(uint32_t rs, size_t padLen, + size_t plaintextLen); + +/*! + * Encrypts a Web Push message using the "aes128gcm" scheme. This function + * automatically generates an ephemeral ECDH key pair and a random salt. + * + * \sa ece_aes128gcm_payload_max_length() + * + * \param rawRecvPubKey[in] The subscription public key, in uncompressed + * form. + * \param rawRecvPubKeyLen[in] The length of the subscription public key. Must + * be `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param authSecret[in] The authentication secret. + * \param authSecretLen[in] The length of the authentication secret. Must be + * `ECE_WEBPUSH_AUTH_SECRET_LENGTH`. + * \param rs[in] The record size. Must be at least + * `ECE_AES128GCM_MIN_RS`. + * \param padLen[in] The length of additional padding to include in + * the ciphertext, if any. + * \param plaintext[in] The plaintext to encrypt. + * \param plaintextLen[in] The length of the plaintext. + * \param payload[in] An empty array. Must be large enough to hold the + * full payload. + * \param payloadLen[in,out] The input is the length of the empty `payload` + * array. On success, the output is set to the + * actual payload length, and + * `payload[0..payloadLen]` contains the payload. + * + * \return `ECE_OK` on success, or an error code if + * encryption fails. + */ +int +ece_webpush_aes128gcm_encrypt(const uint8_t* rawRecvPubKey, + size_t rawRecvPubKeyLen, + const uint8_t* authSecret, size_t authSecretLen, + uint32_t rs, size_t padLen, + const uint8_t* plaintext, size_t plaintextLen, + uint8_t* payload, size_t* payloadLen); + +/*! + * Encrypts a Web Push message using the "aes128gcm" scheme, with an explicit + * sender key and salt. The sender key can be reused, but the salt *must* be + * unique to avoid deriving the same content encryption key for multiple + * messages. + * + * \warning In general, you should only use this function + * for testing. `ece_webpush_aes128gcm_encrypt` + * is safer because it doesn't risk accidental + * salt reuse. + * + * \sa ece_aes128gcm_payload_max_length(), + * ece_webpush_aes128gcm_encrypt() + * + * \param rawSenderPrivKey[in] The sender private key. + * \param rawSenderPrivKeyLen[in] The length of the sender private key. Must be + * `ECE_WEBPUSH_PRIVATE_KEY_LENGTH`. + * \param authSecret[in] The authentication secret. + * \param authSecretLen[in] The length of the authentication secret. Must + * be `ECE_WEBPUSH_AUTH_SECRET_LENGTH`. + * \param salt[in] The encryption salt. + * \param saltLen[in] The length of the salt. Must be + * `ECE_SALT_LENGTH`. + * \param rawRecvPubKey[in] The subscription public key, in uncompressed + * form. Must be `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param rawRecvPubKeyLen[in] The length of the subscription public key. + * \param rs[in] The record size. Must be at least + * `ECE_AES128GCM_MIN_RS`. + * \param padLen[in] The length of additional padding to include in + * the ciphertext, if any. + * \param plaintext[in] The plaintext to encrypt. + * \param plaintextLen[in] The length of the plaintext. + * \param payload[in] An empty array. Must be large enough to hold + * the full payload. + * \param payloadLen[in,out] The input is the length of the empty `payload` + * array. On success, the output is set to the + * actual payload length, and + * `payload[0..payloadLen]` contains the payload. + * + * \return `ECE_OK` on success, or an error code if + * encryption fails. + */ +int +ece_webpush_aes128gcm_encrypt_with_keys( + const uint8_t* rawSenderPrivKey, size_t rawSenderPrivKeyLen, + const uint8_t* authSecret, size_t authSecretLen, const uint8_t* salt, + size_t saltLen, const uint8_t* rawRecvPubKey, size_t rawRecvPubKeyLen, + uint32_t rs, size_t padLen, const uint8_t* plaintext, size_t plaintextLen, + uint8_t* payload, size_t* payloadLen); + +/*! + * Calculates the maximum "aesgcm" ciphertext length. The caller should allocate + * and pass an array of this length to `ece_webpush_aesgcm_encrypt_with_keys`. + * + * \param rs[in] The record size. Must be least `ECE_AESGCM_MIN_RS`. + * \param padLen[in] The length of additional padding. + * \param plaintextLen[in] The length of the plaintext. + * + * \return The maximum ciphertext length, or 0 if `rs` is too + * small. + */ +size_t +ece_aesgcm_ciphertext_max_length(uint32_t rs, size_t padLen, + size_t plaintextLen); + +/*! + * Encrypts a Web Push message using the "aesgcm" scheme. Like + * `ece_webpush_aes128gcm_encrypt`, this function generates a sender key pair + * and salt. + * + * \sa ece_aesgcm_ciphertext_max_length() + * + * \param rawRecvPubKey[in] The subscription public key, in uncompressed + * form. + * \param rawRecvPubKeyLen[in] The length of the subscription public key. Must + * be `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param authSecret[in] The authentication secret. + * \param authSecretLen[in] The length of the authentication secret. Must + * be `ECE_WEBPUSH_AUTH_SECRET_LENGTH`. + * \param rs[in] The record size. Must be at least + * `ECE_AES128GCM_MIN_RS`. + * \param padLen[in] The length of additional padding to include in + * the ciphertext, if any. + * \param plaintext[in] The plaintext to encrypt. + * \param plaintextLen[in] The length of the plaintext. + * \param salt[in] An empty array to hold the salt. + * \param saltLen[in] The length of the empty `salt` array. Must be + * `ECE_SALT_LENGTH`. + * \param rawSenderPubKey[in] An empty array to hold the sender public key. + * \param rawSenderPubKeyLen[in] The length of the empty `rawSenderPubKey` + * array. Must be `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param ciphertext[in] An empty array to hold the ciphertext. + * \param ciphertextLen[in, out] The input is the length of the empty + * `ciphertext` array. On success, the output is + * set to the actual ciphertext length, and + * `ciphertext[0..ciphertextLen]` contains the + * ciphertext. + * + * \return `ECE_OK` on success, or an error code if + * encryption fails. + */ +int +ece_webpush_aesgcm_encrypt(const uint8_t* rawRecvPubKey, + size_t rawRecvPubKeyLen, const uint8_t* authSecret, + size_t authSecretLen, uint32_t rs, size_t padLen, + const uint8_t* plaintext, size_t plaintextLen, + uint8_t* salt, size_t saltLen, + uint8_t* rawSenderPubKey, size_t rawSenderPubKeyLen, + uint8_t* ciphertext, size_t* ciphertextLen); + +/*! + * Encrypts a Web Push message using the "aesgcm" scheme and explicit keys. + * + * \warning `ece_webpush_aesgcm_encrypt` is safer because + * it doesn't risk accidental salt reuse. + * + * \sa ece_aesgcm_ciphertext_max_length(), + * ece_webpush_aesgcm_encrypt() + * + * \param rawSenderPrivKey[in] The sender private key. + * \param rawSenderPrivKeyLen[in] The length of the sender private key. Must be + * `ECE_WEBPUSH_PRIVATE_KEY_LENGTH`. + * \param authSecret[in] The authentication secret. + * \param authSecretLen[in] The length of the authentication secret. Must + * be `ECE_WEBPUSH_AUTH_SECRET_LENGTH`. + * \param salt[in] The encryption salt. + * \param saltLen[in] The length of the salt. Must be + * `ECE_SALT_LENGTH`. + * \param rawRecvPubKey[in] The subscription public key, in uncompressed + * form. Must be `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param rawRecvPubKeyLen[in] The length of the subscription public key. + * \param rs[in] The record size. Must be at least + * `ECE_AES128GCM_MIN_RS`. + * \param padLen[in] The length of additional padding to include in + * the ciphertext, if any. + * \param plaintext[in] The plaintext to encrypt. + * \param plaintextLen[in] The length of the plaintext. + * \param ciphertext[in] An empty array. Must be large enough to hold + * the full ciphertext. + * \param ciphertextLen[in,out] The input is the length of the empty + * `ciphertext` array. On success, the output is + * set to the actual ciphertext length, and + * `ciphertext[0..ciphertextLen]` contains the + * ciphertext. + * + * \return `ECE_OK` on success, or an error code if + * encryption fails. + */ +int +ece_webpush_aesgcm_encrypt_with_keys( + const uint8_t* rawSenderPrivKey, size_t rawSenderPrivKeyLen, + const uint8_t* authSecret, size_t authSecretLen, const uint8_t* salt, + size_t saltLen, const uint8_t* rawRecvPubKey, size_t rawRecvPubKeyLen, + uint32_t rs, size_t padLen, const uint8_t* plaintext, size_t plaintextLen, + uint8_t* ciphertext, size_t* ciphertextLen); + +/*! + * Calculates the maximum "aesgcm" plaintext length. The caller should allocate + * and pass an array of this length to `ece_webpush_aesgcm_decrypt`. + * + * \sa ece_webpush_aesgcm_decrypt() + * + * \param rs[in] The record size. Must be at least + * `ECE_AESGCM_MIN_RS`. + * \param ciphertextLen[in] The ciphertext length. + * + * \return The maximum plaintext length. + */ +size_t +ece_aesgcm_plaintext_max_length(uint32_t rs, size_t ciphertextLen); + +/*! + * Decrypts a Web Push message encrypted using the "aesgcm" scheme. + * + * \sa ece_aesgcm_plaintext_max_length() + * + * \param rawRecvPrivKey[in] The subscription private key. + * \param rawRecvPrivKeyLen[in] The length of the subscription private key. + * Must be `ECE_WEBPUSH_PRIVATE_KEY_LENGTH`. + * \param authSecret[in] The authentication secret. + * \param authSecretLen[in] The length of the authentication secret. Must + * be `ECE_WEBPUSH_AUTH_SECRET_LENGTH`. + * \param salt[in] + * \param salt[in] The salt, from the `Encryption` header. + * \param saltLen[in] The length of the salt. Must be + * `ECE_SALT_LENGTH`. + * \param rawSenderPubKey[in] The sender public key, in uncompressed form, + * from the `Crypto-Key` header. + * \param rawSenderPubKeyLen[in] The length of the sender public key. Must be + * `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param rs[in] The record size. Must be at least + * `ECE_AESGCM_MIN_RS`. + * \param ciphertext[in] The ciphertext. + * \param ciphertextLen[in] The length of the ciphertext. + * \param plaintext[in] An empty array. Must be large enough to hold + * the full plaintext. + * \param plaintextLen[in,out] The input is the length of the empty + * `plaintext` array. On success, the output is + * set to the actual plaintext length, and + * `[0..plaintextLen]` contains the plaintext. + * + * \return `ECE_OK` on success, or an error code if the + * headers or ciphertext are malformed. + */ +int +ece_webpush_aesgcm_decrypt(const uint8_t* rawRecvPrivKey, + size_t rawRecvPrivKeyLen, const uint8_t* authSecret, + size_t authSecretLen, const uint8_t* salt, + size_t saltLen, const uint8_t* rawSenderPubKey, + size_t rawSenderPubKeyLen, uint32_t rs, + const uint8_t* ciphertext, size_t ciphertextLen, + uint8_t* plaintext, size_t* plaintextLen); + +/*! + * Extracts "aes128gcm" decryption parameters from an encrypted payload. + * `salt`, `keyId`, and `ciphertext` are pointers into `payload`, and must not + * outlive it. + * + * \sa ece_aes128gcm_decrypt() + * + * \param payload[in] The encrypted payload. + * \param payloadLen[in] The length of the encrypted payload. + * \param salt[out] The encryption salt. + * \param saltLen[out] The length of the salt. + * \param keyId[out] An identifier for the keying material. + * \param keyIdLen[out] The length of the key ID. + * \param rs[out] The record size. + * \param ciphertext[out] The ciphertext. + * \param ciphertextLen[out] The length of the ciphertext. + * + * \return `ECE_OK` on success, or an error code if the + * payload header is truncated or invalid. + */ +int +ece_aes128gcm_payload_extract_params(const uint8_t* payload, size_t payloadLen, + const uint8_t** salt, size_t* saltLen, + const uint8_t** keyId, size_t* keyIdLen, + uint32_t* rs, const uint8_t** ciphertext, + size_t* ciphertextLen); + +/*! + * Extracts "aesgcm" decryption parameters from the `Crypto-Key` and + * `Encryption` headers. + * + * \sa ece_webpush_aesgcm_decrypt(), + * ece_webpush_aesgcm_headers_from_params() + * + * \param cryptoKeyHeader[in] The value of the `Crypto-Key` HTTP header. + * \param encryptionHeader[in] The value of the `Encryption` HTTP header. + * \param salt[in] An empty array to hold the encryption salt, + * extracted from the `Encryption` header. + * \param saltLen[in] The length of the empty `salt` array. Must be + * `ECE_SALT_LENGTH`. + * \param rawSenderPubKey[in] An empty array to hold the sender public key, + * in uncompressed form, extracted from the + * `Crypto-Key` header. + * \param rawSenderPubKeyLen[in] The length of the empty `rawSenderPubKey` + * array. Must be `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param rs[out] The record size. + * + * \return `ECE_OK` on success, or an error code if the + * headers are malformed. + */ +int +ece_webpush_aesgcm_headers_extract_params(const char* cryptoKeyHeader, + const char* encryptionHeader, + uint8_t* salt, size_t saltLen, + uint8_t* rawSenderPubKey, + size_t rawSenderPubKeyLen, + uint32_t* rs); + +/*! + * Builds the `Crypto-Key` and `Encryption` headers from the "aesgcm" + * encryption parameters. + * + * \sa ece_webpush_aesgcm_encrypt_with_keys(), + * ece_webpush_aesgcm_headers_extract_params() + * + * \param salt[in] The encryption salt, to include in the + * `Encryption` header. + * \param saltLen[in] The length of the salt. Must be + * `ECE_SALT_LENGTH`. + * \param rawSenderPubKey[in] The sender public key, in uncompressed + * form, to include in the `Crypto-Key` + * header. + * \param rawSenderPubKeyLen[in] The length of the sender public key. Must + * be `ECE_WEBPUSH_PUBLIC_KEY_LENGTH`. + * \param rs[in] The record size, to include in the + * `Encryption` header. + * \param cryptoKeyHeader[in] An empty array to hold the `Crypto-Key` + * header. May be `NULL` if + * `cryptoKeyHeaderLen` is 0. The header is + * *not* null-terminated; you'll need to add + * a trailing `'\0'` if you want to treat + * `cryptoKeyHeader` as a C string. + * \param cryptoKeyHeaderLen[in, out] The input is the length of the empty + * `cryptoKeyHeader` array. If 0, the output + * is set to the length required to hold + * the result. On success, + * `[0..cryptoKeyHeaderLen]` contains the + * header. + * \param encryptionHeader[in] An empty array to hold the `Encryption` + * header. May be `NULL` if + * `encryptionHeaderLen` is 0. Like + * `cryptoKeyHeader`, this header is not + * null-terminated. + * \param encryptionHeaderLen[in, out] The input is the length of the empty + * `encryptionHeader` array. If 0, the + * output is set to the length required to + * hold the result. On success, + * `[0..encryptionHeaderLen]` contains the + * header. + * + * \return `ECE_OK` on success, or an error code if + * `cryptoKeyHeaderLen` or + * `encryptionHeaderLen` is too small. + */ +int +ece_webpush_aesgcm_headers_from_params(const void* salt, size_t saltLen, + const void* rawSenderPubKey, + size_t rawSenderPubKeyLen, uint32_t rs, + char* cryptoKeyHeader, + size_t* cryptoKeyHeaderLen, + char* encryptionHeader, + size_t* encryptionHeaderLen); + +/*! + * Converts a byte array to a Base64url-encoded (RFC 4648) string. + * + * \param binary[in] The byte array to encode. + * \param binaryLen[in] The length of the byte array. + * \param paddingPolicy[in] The policy for padding the encoded output. + * \param base64[in] An empty array to hold the encoded result. May be + * `NULL` if `base64Len` is 0. This function does + * *not* null-terminate `base64`. This makes it easier + * to include Base64url-encoded substrings in larger + * strings, but means you'll need to add a trailing + * `'\0'` if you want to treat `base64` as a C string. + * \param base64Len[in] The length of the empty `base64` array. On success, + * `base64[0..base64Len]` contains the result. + * + * \return The encoded length. If `binaryLen` is 0, returns the + * length of the array required to hold the result. If + * `binaryLen` is not large enough to hold the full + * result, returns 0. + */ +size_t +ece_base64url_encode(const void* binary, size_t binaryLen, + ece_base64url_encode_policy_t paddingPolicy, char* base64, + size_t base64Len); + +/*! + * Decodes a Base64url-encoded (RFC 4648) string. + * + * \param base64[in] The encoded string. + * \param base64Len[in] The length of the encoded string. + * \param paddingPolicy[in] The policy for handling "=" padding in the encoded + * input. + * \param binary[in] An empty array to hold the decoded result. May be + * `NULL` if `binaryLen` is 0. + * \param binaryLen[in] The length of the empty `binary` array. On success, + * `binary[0..binaryLen]` contains the result. + * + * \return The actual decoded length. If `binaryLen` is 0, + * returns the length of the array + * required to hold the result. If `base64` contains + * invalid characters, or `binaryLen` is not large + * enough to hold the full result, returns 0. + */ +size_t +ece_base64url_decode(const char* base64, size_t base64Len, + ece_base64url_decode_policy_t paddingPolicy, + uint8_t* binary, size_t binaryLen); + +#ifdef __cplusplus +} +#endif +#endif /* ECE_H */ diff --git a/mobile/ios/ThirdParty/ecec/include/ece/keys.h b/mobile/ios/ThirdParty/ecec/include/ece/keys.h new file mode 100644 index 0000000000..92046e22d4 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/include/ece/keys.h @@ -0,0 +1,91 @@ +#ifndef ECE_KEYS_H +#define ECE_KEYS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define ECE_AES_KEY_LENGTH 16 +#define ECE_NONCE_LENGTH 12 + +#define ECE_WEBPUSH_IKM_LENGTH 32 + +// HKDF info strings for the "aes128gcm" scheme. Note that the lengths include +// the NUL terminator. +#define ECE_WEBPUSH_AES128GCM_IKM_INFO_PREFIX "WebPush: info\0" +#define ECE_WEBPUSH_AES128GCM_IKM_INFO_PREFIX_LENGTH 14 +#define ECE_WEBPUSH_AES128GCM_IKM_INFO_LENGTH 144 + +#define ECE_AES128GCM_KEY_INFO "Content-Encoding: aes128gcm\0" +#define ECE_AES128GCM_KEY_INFO_LENGTH 28 +#define ECE_AES128GCM_NONCE_INFO "Content-Encoding: nonce\0" +#define ECE_AES128GCM_NONCE_INFO_LENGTH 24 + +// HKDF info strings for the "aesgcm" scheme. +#define ECE_WEBPUSH_AESGCM_IKM_INFO "Content-Encoding: auth\0" +#define ECE_WEBPUSH_AESGCM_IKM_INFO_LENGTH 23 +#define ECE_WEBPUSH_AESGCM_KEY_INFO_PREFIX "Content-Encoding: aesgcm\0P-256\0" +#define ECE_WEBPUSH_AESGCM_KEY_INFO_PREFIX_LENGTH 31 +#define ECE_WEBPUSH_AESGCM_KEY_INFO_LENGTH 165 +#define ECE_WEBPUSH_AESGCM_NONCE_INFO_PREFIX "Content-Encoding: nonce\0P-256\0" +#define ECE_WEBPUSH_AESGCM_NONCE_INFO_PREFIX_LENGTH 30 +#define ECE_WEBPUSH_AESGCM_NONCE_INFO_LENGTH 164 + +// Key derivation modes. +typedef enum ece_mode_e { + ECE_MODE_ENCRYPT, + ECE_MODE_DECRYPT, +} ece_mode_t; + +typedef int (*derive_key_and_nonce_t)(ece_mode_t mode, EC_KEY* localKey, + EC_KEY* remoteKey, + const uint8_t* authSecret, + size_t authSecretLen, const uint8_t* salt, + size_t saltLen, uint8_t* key, + uint8_t* nonce); + +// Generates a 96-bit IV for decryption, 48 bits of which are populated. +void +ece_generate_iv(const uint8_t* nonce, uint64_t counter, uint8_t* iv); + +// Inflates a raw ECDH private key into an OpenSSL `EC_KEY` containing a +// private and public key pair. Returns `NULL` on error. +EC_KEY* +ece_import_private_key(const uint8_t* rawKey, size_t rawKeyLen); + +// Inflates a raw ECDH public key into an `EC_KEY` containing a public key. +// Returns `NULL` on error. +EC_KEY* +ece_import_public_key(const uint8_t* rawKey, size_t rawKeyLen); + +// Derives the "aes128gcm" content encryption key and nonce. +int +ece_aes128gcm_derive_key_and_nonce(const uint8_t* salt, size_t saltLen, + const uint8_t* ikm, size_t ikmLen, + uint8_t* key, uint8_t* nonce); + +// Derives the "aes128gcm" decryption key and nonce given the receiver private +// key, sender public key, authentication secret, and sender salt. +int +ece_webpush_aes128gcm_derive_key_and_nonce(ece_mode_t mode, EC_KEY* localKey, + EC_KEY* remoteKey, + const uint8_t* authSecret, + size_t authSecretLen, + const uint8_t* salt, size_t saltLen, + uint8_t* key, uint8_t* nonce); + +// Derives the "aesgcm" decryption key and nonce given the receiver private key, +// sender public key, authentication secret, and sender salt. +int +ece_webpush_aesgcm_derive_key_and_nonce(ece_mode_t mode, EC_KEY* recvPrivKey, + EC_KEY* senderPubKey, + const uint8_t* authSecret, + size_t authSecretLen, + const uint8_t* salt, size_t saltLen, + uint8_t* key, uint8_t* nonce); + +#ifdef __cplusplus +} +#endif +#endif /* ECE_KEYS_H */ diff --git a/mobile/ios/ThirdParty/ecec/include/ece/trailer.h b/mobile/ios/ThirdParty/ecec/include/ece/trailer.h new file mode 100644 index 0000000000..25246d8a94 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/include/ece/trailer.h @@ -0,0 +1,31 @@ +#ifndef ECE_TRAILER_H +#define ECE_TRAILER_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +typedef bool (*needs_trailer_t)(uint32_t rs, size_t ciphertextLen); + +// Adjusts the aesgcm record size to account for the authentication tag. +// aesgcm includes the size of the padding delimiter, but not the tag. +uint32_t +ece_aesgcm_rs(uint32_t rs); + +// Indicates if an "aesgcm" ciphertext is a multiple of the record size, and +// needs a padding-only trailing block to prevent truncation attacks. +bool +ece_aesgcm_needs_trailer(uint32_t rs, size_t ciphertextLen); + +// Provided for completeness, but always returns false because "aes128gcm" uses +// a padding scheme that doesn't need a trailer. +bool +ece_aes128gcm_needs_trailer(uint32_t rs, size_t ciphertextLen); + +#ifdef __cplusplus +} +#endif +#endif /* ECE_TRAILER_H */ diff --git a/mobile/ios/ThirdParty/ecec/src/base64url.c b/mobile/ios/ThirdParty/ecec/src/base64url.c new file mode 100644 index 0000000000..6643994cc4 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/src/base64url.c @@ -0,0 +1,289 @@ +#include "ece.h" + +// This file implements Base64url encoding and decoding per RFC 4648. Originally +// implemented in https://bugzilla.mozilla.org/show_bug.cgi?id=1256488 and +// https://bugzilla.mozilla.org/show_bug.cgi?id=1205137. + +#include +#include + +#define ECE_BASE64URL_INVALID_CHAR 64 +#define ECE_BASE64URL_INVALID_PADDING 3 + +// Maps an index to a character in the Base64url alphabet. +static const char ece_base64url_encode_table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +// Maps a character in the Base64url alphabet to its index, per RFC 4648, +// Table 2. Invalid characters map to 64. +static const uint8_t ece_base64url_decode_table[] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, + 63, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, +}; + +// Returns the size of the buffer required to hold the Base64url output, +// or 0 if `binaryLen` is too large. +static inline size_t +ece_base64url_base64_length(size_t binaryLen) { + if (binaryLen / 3 > SIZE_MAX / 4) { + return 0; + } + // Base64 expands each 3-byte quantum to 4 bytes. The final quantum can be + // 2 or 3 bytes. + size_t baseLen = (binaryLen / 3) * 4; + size_t finalLen = 0; + switch (binaryLen % 3) { + case 1: + finalLen = 2; + break; + + case 2: + finalLen = 3; + break; + } + if (finalLen > SIZE_MAX - baseLen) { + return 0; + } + return baseLen + finalLen; +} + +// Encodes a `binary` quantum into `base64`, and returns the number of bytes +// written. A 3-byte quantum encodes to 4 bytes, a 2-byte quantum encodes to +// 3 bytes, and a 1-byte quantum encodes to 2 bytes. +static inline int +ece_base64url_encode_quantum(const uint8_t* binary, size_t binaryLen, + char* base64) { + assert(binaryLen <= 3); + + uint32_t quantum = 0; + for (size_t i = 0; i < binaryLen; i++) { + quantum <<= 8; + quantum |= (uint32_t) binary[i]; + } + + switch (binaryLen) { + case 1: + base64[0] = ece_base64url_encode_table[(quantum >> 2) & 0x3f]; + base64[1] = ece_base64url_encode_table[(quantum << 4) & 0x3f]; + return 2; + + case 2: + base64[0] = ece_base64url_encode_table[(quantum >> 10) & 0x3f]; + base64[1] = ece_base64url_encode_table[(quantum >> 4) & 0x3f]; + base64[2] = ece_base64url_encode_table[(quantum << 2) & 0x3f]; + return 3; + + case 3: + base64[0] = ece_base64url_encode_table[(quantum >> 18) & 0x3f]; + base64[1] = ece_base64url_encode_table[(quantum >> 12) & 0x3f]; + base64[2] = ece_base64url_encode_table[(quantum >> 6) & 0x3f]; + base64[3] = ece_base64url_encode_table[quantum & 0x3f]; + return 4; + } + + return 0; +} + +// Returns the number of trailing `=` characters to remove from the end of +// `base64`, based on the `paddingPolicy`. Valid values are 0, 1, or 2; +// 3 means the input is invalid. +static inline size_t +ece_base64url_decode_pad_length(const char* base64, size_t base64Len, + ece_base64url_decode_policy_t paddingPolicy) { + // Determine whether to check for and ignore trailing padding. + bool maybePadded = false; + switch (paddingPolicy) { + case ECE_BASE64URL_REQUIRE_PADDING: + if (base64Len % 4) { + // Padded input length must be a multiple of 4. + return ECE_BASE64URL_INVALID_PADDING; + } + maybePadded = true; + break; + + case ECE_BASE64URL_IGNORE_PADDING: + // Check for padding only if the length is a multiple of 4. + maybePadded = !(base64Len % 4); + break; + + // If we're expecting unpadded input, no need for additional checks. + // `=` isn't in the decode table, so padded strings will fail to decode. + default: + // Invalid decode padding policy. + assert(false); + case ECE_BASE64URL_REJECT_PADDING: + break; + } + if (maybePadded && base64[base64Len - 1] == '=') { + base64Len--; + if (base64[base64Len - 1] == '=') { + return 2; + } + return 1; + } + return 0; +} + +// Returns the size of the buffer required to hold the binary output, or 0 if +// `base64Len` is truncated. +static inline size_t +ece_base64url_binary_length(size_t base64Len) { + size_t requiredBinaryLen = (base64Len / 4) * 3; + switch (base64Len % 4) { + case 1: + return 0; + + case 2: + requiredBinaryLen++; + break; + + case 3: + requiredBinaryLen += 2; + break; + } + return requiredBinaryLen; +} + +// Converts a Base64url character `c` to its index. +static inline uint8_t +ece_base64url_decode_byte(char b) { + return (b & ~0x7f) ? ECE_BASE64URL_INVALID_CHAR + : ece_base64url_decode_table[b & 0x7f]; +} + +// Decodes a `base64` encoded quantum into `binary`. A 4-byte quantum decodes to +// 3 bytes, a 3-byte quantum decodes to 2 bytes, and a 2-byte quantum decodes to +// 1 byte. +static inline bool +ece_base64url_decode_quantum(const char* base64, size_t base64Len, + uint8_t* binary) { + assert(base64Len <= 4); + + uint32_t quantum = 0; + for (size_t i = 0; i < base64Len; i++) { + uint8_t b = ece_base64url_decode_byte(base64[i]); + if (b == ECE_BASE64URL_INVALID_CHAR) { + return false; + } + quantum <<= 6; + quantum |= (uint32_t) b; + } + + switch (base64Len) { + case 0: + return true; + + case 2: + binary[0] = (quantum >> 4) & 0xff; + return true; + + case 3: + binary[0] = (quantum >> 10) & 0xff; + binary[1] = (quantum >> 2) & 0xff; + return true; + + case 4: + binary[0] = (quantum >> 16) & 0xff; + binary[1] = (quantum >> 8) & 0xff; + binary[2] = quantum & 0xff; + return true; + } + + return false; +} + +size_t +ece_base64url_encode(const void* binary, size_t binaryLen, + ece_base64url_encode_policy_t paddingPolicy, char* base64, + size_t base64Len) { + // Don't encode empty strings. + if (!binaryLen) { + return 0; + } + + // Ensure we have enough room to hold the output. + size_t requiredBase64Len = ece_base64url_base64_length(binaryLen); + if (!requiredBase64Len) { + return 0; + } + size_t padLen = 0; + if (paddingPolicy == ECE_BASE64URL_INCLUDE_PADDING) { + switch (requiredBase64Len % 4) { + case 2: + padLen = 2; + break; + + case 3: + padLen = 1; + break; + } + if (padLen > SIZE_MAX - requiredBase64Len) { + return 0; + } + requiredBase64Len += padLen; + } + + if (base64Len) { + if (base64Len < requiredBase64Len) { + return 0; + } + const uint8_t* input = binary; + for (; binaryLen >= 3; binaryLen -= 3) { + base64 += ece_base64url_encode_quantum(input, 3, base64); + input += 3; + } + base64 += ece_base64url_encode_quantum(input, binaryLen, base64); + if (paddingPolicy == ECE_BASE64URL_INCLUDE_PADDING) { + while (padLen) { + *base64++ = '='; + padLen--; + } + } else { + assert(paddingPolicy == ECE_BASE64URL_OMIT_PADDING); + } + } + + return requiredBase64Len; +} + +size_t +ece_base64url_decode(const char* base64, size_t base64Len, + ece_base64url_decode_policy_t paddingPolicy, + uint8_t* binary, size_t binaryLen) { + // Don't decode empty strings. + if (!base64Len) { + return 0; + } + + // Ensure we have enough room to hold the output. + size_t padLen = + ece_base64url_decode_pad_length(base64, base64Len, paddingPolicy); + if (padLen == ECE_BASE64URL_INVALID_PADDING) { + return 0; + } + base64Len -= padLen; + size_t requiredBinaryLen = ece_base64url_binary_length(base64Len); + + if (binaryLen) { + if (binaryLen < requiredBinaryLen) { + return 0; + } + for (; base64Len >= 4; base64Len -= 4) { + if (!ece_base64url_decode_quantum(base64, 4, binary)) { + return 0; + } + base64 += 4; + binary += 3; + } + if (!ece_base64url_decode_quantum(base64, base64Len, binary)) { + return 0; + } + } + + return requiredBinaryLen; +} diff --git a/mobile/ios/ThirdParty/ecec/src/decrypt.c b/mobile/ios/ThirdParty/ecec/src/decrypt.c new file mode 100644 index 0000000000..32425b7dac --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/src/decrypt.c @@ -0,0 +1,425 @@ +#include "ece.h" +#include "ece/keys.h" +#include "ece/trailer.h" + +#include +#include + +#include +#include + +typedef int (*unpad_t)(uint8_t* block, bool lastRecord, size_t* blockLen); + +// Calculates the maximum plaintext length, including room for the padding +// delimiter and padding. +static inline size_t +ece_plaintext_max_length(uint32_t rs, size_t padSize, size_t ciphertextLen) { + assert(padSize <= 2); + size_t overhead = padSize + ECE_TAG_LENGTH; + if (rs <= overhead) { + return 0; + } + size_t numRecords = ciphertextLen / rs; + if (ciphertextLen % rs) { + // If the ciphertext length doesn't fall on a record boundary, we have + // a smaller final record. + numRecords++; + } + if (numRecords > ciphertextLen / ECE_TAG_LENGTH) { + // Each record includes a trailing auth tag. If the number of records + // exceeds the number of tags, the ciphertext is truncated. + return 0; + } + return ciphertextLen - (ECE_TAG_LENGTH * numRecords); +} + +// Extracts an unsigned 16-bit integer in network byte order. +static inline uint16_t +ece_read_uint16_be(const uint8_t* bytes) { + uint16_t value = (uint16_t) bytes[1]; + value |= bytes[0] << 8; + return value; +} + +// Converts an encrypted record to a decrypted block. +static int +ece_decrypt_record(EVP_CIPHER_CTX* ctx, const uint8_t* key, const uint8_t* iv, + const uint8_t* record, size_t recordLen, uint8_t* block) { + int chunkLen = -1; + + if (EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv) != 1) { + return ECE_ERROR_DECRYPT; + } + + assert(recordLen > ECE_TAG_LENGTH); + size_t blockLen = recordLen - ECE_TAG_LENGTH; + + // The authentication tag is included at the end of the encrypted record. + uint8_t tag[ECE_TAG_LENGTH]; + memcpy(tag, &record[blockLen], ECE_TAG_LENGTH); + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, ECE_TAG_LENGTH, tag) != + 1) { + return ECE_ERROR_DECRYPT; + } + + if (blockLen > INT_MAX || + EVP_DecryptUpdate(ctx, block, &chunkLen, record, (int) blockLen) != 1) { + return ECE_ERROR_DECRYPT; + } + + // Since we're using a stream cipher, finalization shouldn't write out any + // bytes. + assert(EVP_CIPHER_CTX_block_size(ctx) == 1); + if (EVP_DecryptFinal_ex(ctx, NULL, &chunkLen) != 1) { + return ECE_ERROR_DECRYPT; + } + + if (EVP_CIPHER_CTX_reset(ctx) != 1) { + return ECE_ERROR_DECRYPT; + } + + return ECE_OK; +} + +static int +ece_decrypt_records(const uint8_t* key, const uint8_t* nonce, uint32_t rs, + size_t padSize, const uint8_t* ciphertext, + size_t ciphertextLen, unpad_t unpad, uint8_t* plaintext, + size_t* plaintextLen) { + int err = ECE_OK; + + EVP_CIPHER_CTX* ctx = NULL; + + // Make sure the plaintext array is large enough to hold the full plaintext. + size_t maxPlaintextLen = ece_plaintext_max_length(rs, padSize, ciphertextLen); + if (!maxPlaintextLen) { + err = ECE_ERROR_DECRYPT; + goto end; + } + if (*plaintextLen < maxPlaintextLen) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + + // The offset at which to start reading the ciphertext. + size_t ciphertextStart = 0; + + // The offset at which to start writing the plaintext. + size_t plaintextStart = 0; + + for (size_t counter = 0; ciphertextStart < ciphertextLen; counter++) { + size_t ciphertextEnd; + if (rs > ciphertextLen - ciphertextStart) { + // This check is equivalent to `ciphertextStart + rs > ciphertextLen`; + // it's written this way to avoid an integer overflow. + ciphertextEnd = ciphertextLen; + } else { + ciphertextEnd = ciphertextStart + rs; + } + + assert(ciphertextEnd > ciphertextStart); + + // The full length of the encrypted record. + size_t recordLen = ciphertextEnd - ciphertextStart; + if (recordLen <= ECE_TAG_LENGTH) { + err = ECE_ERROR_SHORT_BLOCK; + goto end; + } + + // Generate the IV for this record using the nonce. + uint8_t iv[ECE_NONCE_LENGTH]; + ece_generate_iv(nonce, counter, iv); + + // Decrypt the record. + err = ece_decrypt_record(ctx, key, iv, &ciphertext[ciphertextStart], + recordLen, &plaintext[plaintextStart]); + if (err) { + goto end; + } + + // `unpad` sets `blockLen` to the actual plaintext block length, without + // the padding delimiter and padding. + bool lastRecord = ciphertextEnd >= ciphertextLen; + size_t blockLen = recordLen - ECE_TAG_LENGTH; + if (blockLen < padSize) { + err = ECE_ERROR_DECRYPT_PADDING; + goto end; + } + err = unpad(&plaintext[plaintextStart], lastRecord, &blockLen); + if (err) { + goto end; + } + + ciphertextStart = ciphertextEnd; + plaintextStart += blockLen; + } + + // Finally, set the actual plaintext length. + *plaintextLen = plaintextStart; + +end: + EVP_CIPHER_CTX_free(ctx); + return err; +} + +// A generic decryption function shared by "aesgcm" and "aes128gcm". +// `deriveKeyAndNonce` and `unpad` are function pointers that change based on +// the scheme. +static int +ece_webpush_decrypt(const uint8_t* rawRecvPrivKey, size_t rawRecvPrivKeyLen, + const uint8_t* authSecret, size_t authSecretLen, + const uint8_t* salt, size_t saltLen, + const uint8_t* rawSenderPubKey, size_t rawSenderPubKeyLen, + uint32_t rs, size_t padSize, const uint8_t* ciphertext, + size_t ciphertextLen, needs_trailer_t needsTrailer, + derive_key_and_nonce_t deriveKeyAndNonce, unpad_t unpad, + uint8_t* plaintext, size_t* plaintextLen) { + int err = ECE_OK; + + EC_KEY* recvPrivKey = NULL; + EC_KEY* senderPubKey = NULL; + + if (authSecretLen != ECE_WEBPUSH_AUTH_SECRET_LENGTH) { + err = ECE_ERROR_INVALID_AUTH_SECRET; + goto end; + } + if (saltLen != ECE_SALT_LENGTH) { + err = ECE_ERROR_INVALID_SALT; + goto end; + } + if (!ciphertextLen) { + err = ECE_ERROR_ZERO_CIPHERTEXT; + goto end; + } + if (needsTrailer(rs, ciphertextLen)) { + // If we're missing a trailing block, the ciphertext is truncated. This only + // applies to "aesgcm". + err = ECE_ERROR_DECRYPT_TRUNCATED; + goto end; + } + + recvPrivKey = ece_import_private_key(rawRecvPrivKey, rawRecvPrivKeyLen); + if (!recvPrivKey) { + err = ECE_ERROR_INVALID_PRIVATE_KEY; + goto end; + } + senderPubKey = ece_import_public_key(rawSenderPubKey, rawSenderPubKeyLen); + if (!senderPubKey) { + err = ECE_ERROR_INVALID_PUBLIC_KEY; + goto end; + } + + uint8_t key[ECE_AES_KEY_LENGTH]; + uint8_t nonce[ECE_NONCE_LENGTH]; + err = deriveKeyAndNonce(ECE_MODE_DECRYPT, recvPrivKey, senderPubKey, + authSecret, authSecretLen, salt, saltLen, key, nonce); + if (err) { + goto end; + } + + err = ece_decrypt_records(key, nonce, rs, padSize, ciphertext, ciphertextLen, + unpad, plaintext, plaintextLen); + +end: + EC_KEY_free(recvPrivKey); + EC_KEY_free(senderPubKey); + return err; +} + +// Removes padding from a decrypted "aesgcm" block. +static int +ece_aesgcm_unpad(uint8_t* block, bool lastRecord, size_t* blockLen) { + ECE_UNUSED(lastRecord); + + assert(*blockLen >= ECE_AESGCM_PAD_SIZE); + + uint16_t padLen = ece_read_uint16_be(block); + if (padLen > *blockLen - ECE_AESGCM_PAD_SIZE) { + return ECE_ERROR_DECRYPT_PADDING; + } + size_t plaintextStart = ECE_AESGCM_PAD_SIZE + padLen; + + for (size_t i = ECE_AESGCM_PAD_SIZE; i < plaintextStart; i++) { + if (block[i]) { + // All padding bytes must be zero. + return ECE_ERROR_DECRYPT_PADDING; + } + } + + // Move the unpadded plaintext to the start of the block. + *blockLen -= plaintextStart; + memmove(block, &block[plaintextStart], *blockLen); + return ECE_OK; +} + +// Removes padding from a decrypted "aes128gcm" block. +static int +ece_aes128gcm_unpad(uint8_t* block, bool lastRecord, size_t* blockLen) { + // Remove trailing padding. + while (*blockLen > 0) { + (*blockLen)--; + if (!block[*blockLen]) { + continue; + } + uint8_t padDelim = lastRecord ? 2 : 1; + if (block[*blockLen] != padDelim) { + // Last record needs to start padding with a 2; preceding records need + // to start padding with a 1. + return ECE_ERROR_DECRYPT_PADDING; + } + return ECE_OK; + } + + // All zero plaintext. + return ECE_ERROR_ZERO_PLAINTEXT; +} + +int +ece_webpush_generate_keys(uint8_t* rawRecvPrivKey, size_t rawRecvPrivKeyLen, + uint8_t* rawRecvPubKey, size_t rawRecvPubKeyLen, + uint8_t* authSecret, size_t authSecretLen) { + int err = ECE_OK; + EC_KEY* subKey = NULL; + + // Generate a public-private ECDH key pair for the push subscription. + subKey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!subKey) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + if (EC_KEY_generate_key(subKey) != 1) { + err = ECE_ERROR_GENERATE_KEYS; + goto end; + } + + if (!EC_KEY_priv2oct(subKey, rawRecvPrivKey, rawRecvPrivKeyLen)) { + err = ECE_ERROR_INVALID_PRIVATE_KEY; + goto end; + } + const EC_GROUP* subGrp = EC_KEY_get0_group(subKey); + const EC_POINT* rawSubPubKeyPt = EC_KEY_get0_public_key(subKey); + if (!EC_POINT_point2oct(subGrp, rawSubPubKeyPt, POINT_CONVERSION_UNCOMPRESSED, + rawRecvPubKey, rawRecvPubKeyLen, NULL)) { + err = ECE_ERROR_INVALID_PUBLIC_KEY; + goto end; + } + + if (authSecretLen > INT_MAX || + RAND_bytes(authSecret, (int) authSecretLen) != 1) { + err = ECE_ERROR_INVALID_AUTH_SECRET; + goto end; + } + +end: + EC_KEY_free(subKey); + return err; +} + +size_t +ece_aes128gcm_plaintext_max_length(const uint8_t* payload, size_t payloadLen) { + const uint8_t* salt; + size_t saltLen; + const uint8_t* keyId; + size_t keyIdLen; + uint32_t rs; + const uint8_t* ciphertext; + size_t ciphertextLen; + int err = ece_aes128gcm_payload_extract_params( + payload, payloadLen, &salt, &saltLen, &keyId, &keyIdLen, &rs, &ciphertext, + &ciphertextLen); + if (err) { + return 0; + } + return ece_plaintext_max_length(rs, ECE_AES128GCM_PAD_SIZE, ciphertextLen); +} + +size_t +ece_aesgcm_plaintext_max_length(uint32_t rs, size_t ciphertextLen) { + rs = ece_aesgcm_rs(rs); + if (!rs) { + return 0; + } + return ece_plaintext_max_length(rs, ECE_AESGCM_PAD_SIZE, ciphertextLen); +} + +int +ece_aes128gcm_decrypt(const uint8_t* ikm, size_t ikmLen, const uint8_t* payload, + size_t payloadLen, uint8_t* plaintext, + size_t* plaintextLen) { + const uint8_t* salt; + size_t saltLen; + const uint8_t* keyId; + size_t keyIdLen; + uint32_t rs; + const uint8_t* ciphertext; + size_t ciphertextLen; + int err = ece_aes128gcm_payload_extract_params( + payload, payloadLen, &salt, &saltLen, &keyId, &keyIdLen, &rs, &ciphertext, + &ciphertextLen); + if (err) { + return err; + } + uint8_t key[ECE_AES_KEY_LENGTH]; + uint8_t nonce[ECE_NONCE_LENGTH]; + err = + ece_aes128gcm_derive_key_and_nonce(salt, saltLen, ikm, ikmLen, key, nonce); + if (err) { + return err; + } + return ece_decrypt_records(key, nonce, rs, ECE_AES128GCM_PAD_SIZE, ciphertext, + ciphertextLen, &ece_aes128gcm_unpad, plaintext, + plaintextLen); +} + +int +ece_webpush_aes128gcm_decrypt(const uint8_t* rawRecvPrivKey, + size_t rawRecvPrivKeyLen, + const uint8_t* authSecret, size_t authSecretLen, + const uint8_t* payload, size_t payloadLen, + uint8_t* plaintext, size_t* plaintextLen) { + const uint8_t* salt; + size_t saltLen; + const uint8_t* rawSenderPubKey; + size_t rawSenderPubKeyLen; + uint32_t rs; + const uint8_t* ciphertext; + size_t ciphertextLen; + int err = ece_aes128gcm_payload_extract_params( + payload, payloadLen, &salt, &saltLen, &rawSenderPubKey, &rawSenderPubKeyLen, + &rs, &ciphertext, &ciphertextLen); + if (err) { + return err; + } + return ece_webpush_decrypt( + rawRecvPrivKey, rawRecvPrivKeyLen, authSecret, authSecretLen, salt, saltLen, + rawSenderPubKey, rawSenderPubKeyLen, rs, ECE_AES128GCM_PAD_SIZE, ciphertext, + ciphertextLen, &ece_aes128gcm_needs_trailer, + &ece_webpush_aes128gcm_derive_key_and_nonce, &ece_aes128gcm_unpad, + plaintext, plaintextLen); +} + +int +ece_webpush_aesgcm_decrypt(const uint8_t* rawRecvPrivKey, + size_t rawRecvPrivKeyLen, const uint8_t* authSecret, + size_t authSecretLen, const uint8_t* salt, + size_t saltLen, const uint8_t* rawSenderPubKey, + size_t rawSenderPubKeyLen, uint32_t rs, + const uint8_t* ciphertext, size_t ciphertextLen, + uint8_t* plaintext, size_t* plaintextLen) { + rs = ece_aesgcm_rs(rs); + if (!rs) { + return 0; + } + return ece_webpush_decrypt( + rawRecvPrivKey, rawRecvPrivKeyLen, authSecret, authSecretLen, salt, saltLen, + rawSenderPubKey, rawSenderPubKeyLen, rs, ECE_AESGCM_PAD_SIZE, ciphertext, + ciphertextLen, &ece_aesgcm_needs_trailer, + &ece_webpush_aesgcm_derive_key_and_nonce, &ece_aesgcm_unpad, plaintext, + plaintextLen); +} diff --git a/mobile/ios/ThirdParty/ecec/src/encrypt.c b/mobile/ios/ThirdParty/ecec/src/encrypt.c new file mode 100644 index 0000000000..8428931b21 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/src/encrypt.c @@ -0,0 +1,617 @@ +#include "ece.h" +#include "ece/keys.h" +#include "ece/trailer.h" + +#include +#include +#include + +#include +#include +#include + +typedef size_t (*min_block_pad_length_t)(size_t padLen, size_t maxBlockLen); + +typedef int (*encrypt_block_t)(EVP_CIPHER_CTX* ctx, + const uint8_t* blockPlaintext, + size_t blockPlaintextLen, size_t blockPadLen, + bool lastRecord, uint8_t* record); + +static const uint8_t pad = 0; + +// Writes an unsigned 32-bit integer in network byte order. +static inline void +ece_write_uint32_be(uint8_t* bytes, uint32_t value) { + bytes[0] = (value >> 24) & 0xff; + bytes[1] = (value >> 16) & 0xff; + bytes[2] = (value >> 8) & 0xff; + bytes[3] = value & 0xff; +} + +// Writes an unsigned 16-bit integer in network byte order. +static inline void +ece_write_uint16_be(uint8_t* bytes, uint16_t value) { + bytes[0] = (value >> 8) & 0xff; + bytes[1] = value & 0xff; +} + +// Calculates the padding so that the block contains at least one plaintext +// byte. +static inline size_t +ece_min_block_pad_length(size_t padLen, size_t maxBlockLen) { + assert(maxBlockLen >= 1); + size_t blockPadLen = maxBlockLen - 1; + if (padLen && !blockPadLen) { + // If `maxBlockLen` is 1, we can only include 1 byte of data, so write + // the padding first. + blockPadLen++; + } + return blockPadLen > padLen ? padLen : blockPadLen; +} + +// Calculates the padding for an "aesgcm" block. We still want one plaintext +// byte per block, but the padding length must fit into a `uint16_t`. +static size_t +ece_aesgcm_min_block_pad_length(size_t padLen, size_t maxBlockLen) { + size_t blockPadLen = ece_min_block_pad_length(padLen, maxBlockLen); + return blockPadLen > UINT16_MAX ? UINT16_MAX : blockPadLen; +} + +// Calculates the maximum length of an encrypted ciphertext. This does not +// account for the "aes128gcm" header length. +static inline size_t +ece_ciphertext_max_length(uint32_t rs, size_t padSize, size_t padLen, + size_t plaintextLen, needs_trailer_t needsTrailer) { + // The per-record overhead for the padding delimiter and authentication tag. + // 17 for "aes128gcm", 18 for "aesgcm". + assert(padSize <= 2); + size_t overhead = padSize + ECE_TAG_LENGTH; + if (rs <= overhead) { + return 0; + } + if (padLen > SIZE_MAX - plaintextLen) { + return 0; + } + + // The total length of the data to encrypt, including the plaintext and + // padding. + size_t dataLen = plaintextLen + padLen; + + // The maximum length of data to include in each record, excluding the + // padding delimiter and authentication tag. + size_t maxBlockLen = rs - overhead; + + // The total number of encrypted records. + assert(maxBlockLen >= 1); + size_t numRecords = dataLen / maxBlockLen; + if (plaintextLen % rs || needsTrailer(rs, plaintextLen)) { + // If the plaintext length doesn't fall on a record boundary, or if + // we need to write an empty trailing record, allocate space to hold + // an extra padding delimiter and authentication tag. + numRecords++; + } + if (numRecords > (SIZE_MAX - dataLen) / overhead) { + return 0; + } + + return dataLen + (overhead * numRecords); +} + +// Encrypts an "aes128gcm" block into `record`. +static int +ece_aes128gcm_encrypt_block(EVP_CIPHER_CTX* ctx, const uint8_t* blockPlaintext, + size_t blockPlaintextLen, size_t blockPadLen, + bool lastRecord, uint8_t* record) { + int chunkLen = -1; + + // The plaintext block precedes the padding. + if (blockPlaintextLen > INT_MAX || + EVP_EncryptUpdate(ctx, record, &chunkLen, blockPlaintext, + (int) blockPlaintextLen) != 1) { + return ECE_ERROR_ENCRYPT; + } + + // The padding block comprises the delimiter, followed by zeros up to the end + // of the block. + uint8_t padDelim = lastRecord ? 2 : 1; + if (EVP_EncryptUpdate(ctx, &record[blockPlaintextLen], &chunkLen, &padDelim, + ECE_AES128GCM_PAD_SIZE) != 1) { + return ECE_ERROR_ENCRYPT; + } + + for (size_t i = 0; i < blockPadLen; i++) { + if (EVP_EncryptUpdate( + ctx, &record[blockPlaintextLen + ECE_AES128GCM_PAD_SIZE + i], + &chunkLen, &pad, 1) != 1) { + return ECE_ERROR_ENCRYPT; + } + } + + return ECE_OK; +} + +// Encrypts an "aesgcm" block into `record`. +static int +ece_aesgcm_encrypt_block(EVP_CIPHER_CTX* ctx, const uint8_t* blockPlaintext, + size_t plaintextLen, size_t blockPadLen, + bool lastRecord, uint8_t* record) { + ECE_UNUSED(lastRecord); + + int chunkLen = -1; + + // The padding block comprises the padding length as a 16-bit integer, + // followed by that many zeros. We checked that the length fits into a + // `uint16_t` in `ece_aesgcm_min_block_pad_length`, so this cast is safe. + uint8_t padDelim[ECE_AESGCM_PAD_SIZE]; + ece_write_uint16_be(padDelim, (uint16_t) blockPadLen); + if (EVP_EncryptUpdate(ctx, record, &chunkLen, padDelim, + ECE_AESGCM_PAD_SIZE) != 1) { + return ECE_ERROR_ENCRYPT; + } + + for (size_t i = 0; i < blockPadLen; i++) { + if (EVP_EncryptUpdate(ctx, &record[ECE_AESGCM_PAD_SIZE + i], &chunkLen, + &pad, 1) != 1) { + return ECE_ERROR_ENCRYPT; + } + } + + // The plaintext block follows the padding. + if (plaintextLen > INT_MAX || + EVP_EncryptUpdate(ctx, &record[ECE_AESGCM_PAD_SIZE + blockPadLen], + &chunkLen, blockPlaintext, (int) plaintextLen) != 1) { + return ECE_ERROR_ENCRYPT; + } + + return ECE_OK; +} + +// A generic encryption function shared by "aesgcm" and "aes128gcm". +// `deriveKeyAndNonce`, `minBlockPadLen`, `encryptBlock`, and `needsTrailer` +// change depending on the scheme. +static int +ece_webpush_encrypt_plaintext( + EC_KEY* senderPrivKey, EC_KEY* recvPubKey, const uint8_t* authSecret, + size_t authSecretLen, const uint8_t* salt, size_t saltLen, uint32_t rs, + size_t padSize, size_t padLen, const uint8_t* plaintext, size_t plaintextLen, + derive_key_and_nonce_t deriveKeyAndNonce, + min_block_pad_length_t minBlockPadLen, encrypt_block_t encryptBlock, + needs_trailer_t needsTrailer, uint8_t* ciphertext, size_t* ciphertextLen) { + + int err = ECE_OK; + + EVP_CIPHER_CTX* ctx = NULL; + + if (authSecretLen != ECE_WEBPUSH_AUTH_SECRET_LENGTH) { + err = ECE_ERROR_INVALID_AUTH_SECRET; + goto end; + } + if (saltLen != ECE_SALT_LENGTH) { + err = ECE_ERROR_INVALID_SALT; + goto end; + } + if (!plaintextLen) { + err = ECE_ERROR_ZERO_PLAINTEXT; + goto end; + } + + // Make sure the ciphertext buffer is large enough to hold the ciphertext. + size_t maxCiphertextLen = + ece_ciphertext_max_length(rs, padSize, padLen, plaintextLen, needsTrailer); + if (!maxCiphertextLen) { + err = ECE_ERROR_INVALID_RS; + goto end; + } + if (*ciphertextLen < maxCiphertextLen) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + + uint8_t key[ECE_AES_KEY_LENGTH]; + uint8_t nonce[ECE_NONCE_LENGTH]; + err = deriveKeyAndNonce(ECE_MODE_ENCRYPT, senderPrivKey, recvPubKey, + authSecret, ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, + ECE_SALT_LENGTH, key, nonce); + if (err) { + goto end; + } + + assert(padSize <= 2); + size_t overhead = padSize + ECE_TAG_LENGTH; + + // The maximum amount of plaintext and padding that will fit into a full + // block. The last block can be smaller. + assert(rs > overhead); + size_t maxBlockLen = rs - overhead; + + // The offset at which to start reading the plaintext. + size_t plaintextStart = 0; + + // The offset at which to start writing the ciphertext. + size_t ciphertextStart = 0; + + // The record sequence number, used to generate the IV. + size_t counter = 0; + + bool lastRecord = false; + while (!lastRecord) { + size_t blockPadLen = minBlockPadLen(padLen, maxBlockLen); + assert(blockPadLen <= padLen); + padLen -= blockPadLen; + + // Fill the rest of the block with plaintext. + assert(blockPadLen <= maxBlockLen); + size_t maxBlockPlaintextLen = maxBlockLen - blockPadLen; + size_t plaintextEnd; + if (maxBlockPlaintextLen >= plaintextLen - plaintextStart) { + // Equivalent to `plaintextStart + maxBlockPlaintextLen >= plaintextLen` + // without overflow. + plaintextEnd = plaintextLen; + } else { + plaintextEnd = plaintextStart + maxBlockPlaintextLen; + } + + // The length of the plaintext. + assert(plaintextEnd >= plaintextStart); + size_t blockPlaintextLen = plaintextEnd - plaintextStart; + + // The length of the plaintext and padding. This should never overflow + // because `maxBlockPlaintextLen` accounts for `blockPadLen`. + assert(blockPlaintextLen <= maxBlockPlaintextLen); + size_t blockLen = blockPlaintextLen + blockPadLen; + + // The length of the full encrypted record, including the plaintext, + // padding, padding delimiter, and auth tag. This should never overflow + // because `maxBlockLen` accounts for `overhead`. + assert(blockLen <= maxBlockLen); + size_t recordLen = blockLen + overhead; + + size_t ciphertextEnd; + if (recordLen >= maxCiphertextLen - ciphertextStart) { + // Equivalent to `ciphertextStart + recordLen >= maxCiphertextLen` + // without overflow. + ciphertextEnd = maxCiphertextLen; + } else { + ciphertextEnd = ciphertextStart + recordLen; + } + + assert(ciphertextEnd > ciphertextStart); + + bool plaintextExhausted = plaintextEnd >= plaintextLen; + if (!padLen && plaintextExhausted && !needsTrailer(rs, ciphertextEnd)) { + // We've reached the last record when the padding and plaintext are + // exhausted, and we don't need to write an empty trailing record. + lastRecord = true; + } + + if (!lastRecord && blockLen < maxBlockLen) { + // We have padding left, but not enough plaintext to form a full record. + // Writing trailing padding-only records will still leak size information, + // so we force the caller to pick a smaller padding length. + err = ECE_ERROR_ENCRYPT_PADDING; + goto end; + } + + // Generate the IV for this record using the nonce. + uint8_t iv[ECE_NONCE_LENGTH]; + ece_generate_iv(nonce, counter, iv); + + if (EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv) != 1) { + err = ECE_ERROR_ENCRYPT; + goto end; + } + + // Encrypt and pad the block. + err = encryptBlock(ctx, &plaintext[plaintextStart], blockPlaintextLen, + blockPadLen, lastRecord, &ciphertext[ciphertextStart]); + if (err) { + err = ECE_ERROR_ENCRYPT; + goto end; + } + + // OpenSSL requires us to finalize the encryption, but, since we're using a + // stream cipher, finalization shouldn't write out any bytes. + int chunkLen = -1; + assert(EVP_CIPHER_CTX_block_size(ctx) == 1); + if (EVP_EncryptFinal_ex(ctx, NULL, &chunkLen) != 1) { + err = ECE_ERROR_ENCRYPT; + goto end; + } + + // Append the authentication tag. + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, ECE_TAG_LENGTH, + &ciphertext[ciphertextEnd - ECE_TAG_LENGTH]) != 1) { + err = ECE_ERROR_ENCRYPT; + goto end; + } + + if (EVP_CIPHER_CTX_reset(ctx) != 1) { + err = ECE_ERROR_ENCRYPT; + goto end; + } + + plaintextStart = plaintextEnd; + ciphertextStart = ciphertextEnd; + counter++; + } + + // Finally, set the actual ciphertext length. + *ciphertextLen = ciphertextStart; + +end: + EVP_CIPHER_CTX_free(ctx); + return err; +} + +// Encrypts a Web Push message using the "aes128gcm" scheme. +static int +ece_webpush_aes128gcm_encrypt_plaintext( + EC_KEY* senderPrivKey, EC_KEY* recvPubKey, const uint8_t* authSecret, + size_t authSecretLen, const uint8_t* salt, size_t saltLen, uint32_t rs, + size_t padLen, const uint8_t* plaintext, size_t plaintextLen, + uint8_t* payload, size_t* payloadLen) { + + size_t headerLen = + ECE_AES128GCM_HEADER_LENGTH + ECE_WEBPUSH_PUBLIC_KEY_LENGTH; + if (*payloadLen < headerLen) { + return ECE_ERROR_OUT_OF_MEMORY; + } + + // Write the header. + memcpy(payload, salt, ECE_SALT_LENGTH); + ece_write_uint32_be(&payload[ECE_SALT_LENGTH], rs); + payload[ECE_SALT_LENGTH + 4] = ECE_WEBPUSH_PUBLIC_KEY_LENGTH; + if (!EC_POINT_point2oct( + EC_KEY_get0_group(senderPrivKey), EC_KEY_get0_public_key(senderPrivKey), + POINT_CONVERSION_UNCOMPRESSED, &payload[ECE_AES128GCM_HEADER_LENGTH], + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, NULL)) { + return ECE_ERROR_ENCODE_PUBLIC_KEY; + } + + // Write the ciphertext. + size_t ciphertextLen = *payloadLen - headerLen; + int err = ece_webpush_encrypt_plaintext( + senderPrivKey, recvPubKey, authSecret, authSecretLen, salt, saltLen, rs, + ECE_AES128GCM_PAD_SIZE, padLen, plaintext, plaintextLen, + &ece_webpush_aes128gcm_derive_key_and_nonce, &ece_min_block_pad_length, + &ece_aes128gcm_encrypt_block, &ece_aes128gcm_needs_trailer, + &payload[headerLen], &ciphertextLen); + if (err) { + return err; + } + + *payloadLen = headerLen + ciphertextLen; + return ECE_OK; +} + +size_t +ece_aes128gcm_payload_max_length(uint32_t rs, size_t padLen, + size_t plaintextLen) { + size_t ciphertextLen = + ece_ciphertext_max_length(rs, ECE_AES128GCM_PAD_SIZE, padLen, plaintextLen, + &ece_aes128gcm_needs_trailer); + if (!ciphertextLen) { + return 0; + } + size_t maxHeaderLen = + ECE_AES128GCM_HEADER_LENGTH + ECE_AES128GCM_MAX_KEY_ID_LENGTH; + if (ciphertextLen > SIZE_MAX - maxHeaderLen) { + return 0; + } + return maxHeaderLen + ciphertextLen; +} + +int +ece_webpush_aes128gcm_encrypt(const uint8_t* rawRecvPubKey, + size_t rawRecvPubKeyLen, + const uint8_t* authSecret, size_t authSecretLen, + uint32_t rs, size_t padLen, + const uint8_t* plaintext, size_t plaintextLen, + uint8_t* payload, size_t* payloadLen) { + int err = ECE_OK; + + EC_KEY* recvPubKey = NULL; + EC_KEY* senderPrivKey = NULL; + + // Generate a random salt. + uint8_t salt[ECE_SALT_LENGTH]; + if (RAND_bytes(salt, ECE_SALT_LENGTH) != 1) { + err = ECE_ERROR_INVALID_SALT; + goto end; + } + + // Import the receiver public key. + recvPubKey = ece_import_public_key(rawRecvPubKey, rawRecvPubKeyLen); + if (!recvPubKey) { + err = ECE_ERROR_INVALID_PUBLIC_KEY; + goto end; + } + + // Generate the sender ECDH key pair. + senderPrivKey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!senderPrivKey) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + if (EC_KEY_generate_key(senderPrivKey) != 1) { + err = ECE_ERROR_INVALID_PRIVATE_KEY; + goto end; + } + + // Encrypt the message. + err = ece_webpush_aes128gcm_encrypt_plaintext( + senderPrivKey, recvPubKey, authSecret, authSecretLen, salt, ECE_SALT_LENGTH, + rs, padLen, plaintext, plaintextLen, payload, payloadLen); + +end: + EC_KEY_free(recvPubKey); + EC_KEY_free(senderPrivKey); + return err; +} + +int +ece_webpush_aes128gcm_encrypt_with_keys( + const uint8_t* rawSenderPrivKey, size_t rawSenderPrivKeyLen, + const uint8_t* authSecret, size_t authSecretLen, const uint8_t* salt, + size_t saltLen, const uint8_t* rawRecvPubKey, size_t rawRecvPubKeyLen, + uint32_t rs, size_t padLen, const uint8_t* plaintext, size_t plaintextLen, + uint8_t* payload, size_t* payloadLen) { + + int err = ECE_OK; + + EC_KEY* senderPrivKey = NULL; + EC_KEY* recvPubKey = NULL; + + senderPrivKey = ece_import_private_key(rawSenderPrivKey, rawSenderPrivKeyLen); + if (!senderPrivKey) { + err = ECE_ERROR_INVALID_PRIVATE_KEY; + goto end; + } + recvPubKey = ece_import_public_key(rawRecvPubKey, rawRecvPubKeyLen); + if (!recvPubKey) { + err = ECE_ERROR_INVALID_PUBLIC_KEY; + goto end; + } + + err = ece_webpush_aes128gcm_encrypt_plaintext( + senderPrivKey, recvPubKey, authSecret, authSecretLen, salt, saltLen, rs, + padLen, plaintext, plaintextLen, payload, payloadLen); + +end: + EC_KEY_free(senderPrivKey); + EC_KEY_free(recvPubKey); + return err; +} + +size_t +ece_aesgcm_ciphertext_max_length(uint32_t rs, size_t padLen, + size_t plaintextLen) { + rs = ece_aesgcm_rs(rs); + if (!rs) { + return 0; + } + return ece_ciphertext_max_length(rs, ECE_AESGCM_PAD_SIZE, padLen, + plaintextLen, &ece_aesgcm_needs_trailer); +} + +int +ece_webpush_aesgcm_encrypt(const uint8_t* rawRecvPubKey, + size_t rawRecvPubKeyLen, const uint8_t* authSecret, + size_t authSecretLen, uint32_t rs, size_t padLen, + const uint8_t* plaintext, size_t plaintextLen, + uint8_t* salt, size_t saltLen, + uint8_t* rawSenderPubKey, size_t rawSenderPubKeyLen, + uint8_t* ciphertext, size_t* ciphertextLen) { + int err = ECE_OK; + + EC_KEY* recvPubKey = NULL; + EC_KEY* senderPrivKey = NULL; + + rs = ece_aesgcm_rs(rs); + if (!rs) { + err = ECE_ERROR_INVALID_RS; + goto end; + } + + if (saltLen != ECE_SALT_LENGTH) { + err = ECE_ERROR_INVALID_SALT; + goto end; + } + if (rawSenderPubKeyLen != ECE_WEBPUSH_PUBLIC_KEY_LENGTH) { + err = ECE_ERROR_INVALID_DH; + goto end; + } + + // Generate a random salt. + if (saltLen > INT_MAX || RAND_bytes(salt, (int) saltLen) != 1) { + err = ECE_ERROR_INVALID_SALT; + goto end; + } + + // Import the receiver public key. + recvPubKey = ece_import_public_key(rawRecvPubKey, rawRecvPubKeyLen); + if (!recvPubKey) { + err = ECE_ERROR_INVALID_PUBLIC_KEY; + goto end; + } + + // Generate the sender ECDH key pair. + senderPrivKey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!senderPrivKey) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + if (EC_KEY_generate_key(senderPrivKey) != 1) { + err = ECE_ERROR_INVALID_PRIVATE_KEY; + goto end; + } + + if (!EC_POINT_point2oct(EC_KEY_get0_group(senderPrivKey), + EC_KEY_get0_public_key(senderPrivKey), + POINT_CONVERSION_UNCOMPRESSED, rawSenderPubKey, + rawSenderPubKeyLen, NULL)) { + err = ECE_ERROR_ENCODE_PUBLIC_KEY; + goto end; + } + + err = ece_webpush_encrypt_plaintext( + senderPrivKey, recvPubKey, authSecret, authSecretLen, salt, saltLen, rs, + ECE_AESGCM_PAD_SIZE, padLen, plaintext, plaintextLen, + &ece_webpush_aesgcm_derive_key_and_nonce, &ece_aesgcm_min_block_pad_length, + &ece_aesgcm_encrypt_block, &ece_aesgcm_needs_trailer, ciphertext, + ciphertextLen); + +end: + EC_KEY_free(recvPubKey); + EC_KEY_free(senderPrivKey); + return err; +} + +int +ece_webpush_aesgcm_encrypt_with_keys( + const uint8_t* rawSenderPrivKey, size_t rawSenderPrivKeyLen, + const uint8_t* authSecret, size_t authSecretLen, const uint8_t* salt, + size_t saltLen, const uint8_t* rawRecvPubKey, size_t rawRecvPubKeyLen, + uint32_t rs, size_t padLen, const uint8_t* plaintext, size_t plaintextLen, + uint8_t* ciphertext, size_t* ciphertextLen) { + + int err = ECE_OK; + + EC_KEY* senderPrivKey = NULL; + EC_KEY* recvPubKey = NULL; + + rs = ece_aesgcm_rs(rs); + if (!rs) { + err = ECE_ERROR_INVALID_RS; + goto end; + } + + senderPrivKey = ece_import_private_key(rawSenderPrivKey, rawSenderPrivKeyLen); + if (!senderPrivKey) { + err = ECE_ERROR_INVALID_PRIVATE_KEY; + goto end; + } + recvPubKey = ece_import_public_key(rawRecvPubKey, rawRecvPubKeyLen); + if (!recvPubKey) { + err = ECE_ERROR_INVALID_PUBLIC_KEY; + goto end; + } + + err = ece_webpush_encrypt_plaintext( + senderPrivKey, recvPubKey, authSecret, authSecretLen, salt, saltLen, rs, + ECE_AESGCM_PAD_SIZE, padLen, plaintext, plaintextLen, + &ece_webpush_aesgcm_derive_key_and_nonce, &ece_aesgcm_min_block_pad_length, + &ece_aesgcm_encrypt_block, &ece_aesgcm_needs_trailer, ciphertext, + ciphertextLen); + +end: + EC_KEY_free(senderPrivKey); + EC_KEY_free(recvPubKey); + return err; +} diff --git a/mobile/ios/ThirdParty/ecec/src/keys.c b/mobile/ios/ThirdParty/ecec/src/keys.c new file mode 100644 index 0000000000..2fe03e31cd --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/src/keys.c @@ -0,0 +1,410 @@ +#include "ece/keys.h" +#include "ece.h" + +#include +#include +#include + +#include +#include + +// Writes an unsigned 16-bit integer in network byte order. +static inline void +ece_write_uint16_be(uint8_t* bytes, uint16_t value) { + bytes[0] = (value >> 8) & 0xff; + bytes[1] = value & 0xff; +} + +// Extracts an unsigned 64-bit integer in network byte order. +static inline uint64_t +ece_read_uint64_be(const uint8_t* bytes) { + uint64_t value = bytes[7]; + value |= (uint64_t) bytes[6] << 8; + value |= (uint64_t) bytes[5] << 16; + value |= (uint64_t) bytes[4] << 24; + value |= (uint64_t) bytes[3] << 32; + value |= (uint64_t) bytes[2] << 40; + value |= (uint64_t) bytes[1] << 48; + value |= (uint64_t) bytes[0] << 56; + return value; +} + +// Writes an unsigned 64-bit integer in network byte order. +static inline void +ece_write_uint64_be(uint8_t* bytes, uint64_t value) { + bytes[0] = (value >> 56) & 0xff; + bytes[1] = (value >> 48) & 0xff; + bytes[2] = (value >> 40) & 0xff; + bytes[3] = (value >> 32) & 0xff; + bytes[4] = (value >> 24) & 0xff; + bytes[5] = (value >> 16) & 0xff; + bytes[6] = (value >> 8) & 0xff; + bytes[7] = value & 0xff; +} + +void +ece_generate_iv(const uint8_t* nonce, uint64_t counter, uint8_t* iv) { + // Copy the first 4 bytes as-is, since `(x ^ 0) == x`. + size_t offset = ECE_NONCE_LENGTH - 8; + memcpy(iv, nonce, offset); + // Combine the remaining unsigned 64-bit integer with the record sequence + // number using XOR. See the "nonce derivation" section of the draft. + uint64_t mask = ece_read_uint64_be(&nonce[offset]); + ece_write_uint64_be(&iv[offset], mask ^ counter); +} + +EC_KEY* +ece_import_private_key(const uint8_t* rawKey, size_t rawKeyLen) { + EC_KEY* key = NULL; + EC_POINT* pubKeyPt = NULL; + + key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!key) { + goto error; + } + if (EC_KEY_oct2priv(key, rawKey, rawKeyLen) != 1) { + goto error; + } + const EC_GROUP* group = EC_KEY_get0_group(key); + pubKeyPt = EC_POINT_new(group); + if (!pubKeyPt) { + goto error; + } + const BIGNUM* privKey = EC_KEY_get0_private_key(key); + if (EC_POINT_mul(group, pubKeyPt, privKey, NULL, NULL, NULL) != 1) { + goto error; + } + if (EC_KEY_set_public_key(key, pubKeyPt) != 1) { + goto error; + } + goto end; + +error: + EC_KEY_free(key); + key = NULL; + +end: + EC_POINT_free(pubKeyPt); + return key; +} + +EC_KEY* +ece_import_public_key(const uint8_t* rawKey, size_t rawKeyLen) { + EC_KEY* key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!key) { + return NULL; + } + if (EC_KEY_oct2key(key, rawKey, rawKeyLen, NULL) != 1) { + EC_KEY_free(key); + return NULL; + } + return key; +} + +// HKDF from RFC 5869: `HKDF-Expand(HKDF-Extract(salt, ikm), info, length)`. +static int +ece_hkdf_sha256(const void* salt, size_t saltLen, const void* ikm, + size_t ikmLen, const void* info, size_t infoLen, + uint8_t* output, size_t outputLen) { + int err = ECE_OK; + + EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + if (!ctx) { + err = ECE_ERROR_HKDF; + goto end; + } + if (EVP_PKEY_derive_init(ctx) != 1) { + err = ECE_ERROR_HKDF; + goto end; + } + if (EVP_PKEY_CTX_set_hkdf_md(ctx, EVP_sha256()) != 1) { + err = ECE_ERROR_HKDF; + goto end; + } + if (saltLen > INT_MAX || + EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, (int) saltLen) != 1) { + err = ECE_ERROR_HKDF; + goto end; + } + if (ikmLen > INT_MAX || + EVP_PKEY_CTX_set1_hkdf_key(ctx, ikm, (int) ikmLen) != 1) { + err = ECE_ERROR_HKDF; + goto end; + } + if (infoLen > INT_MAX || + EVP_PKEY_CTX_add1_hkdf_info(ctx, info, (int) infoLen) != 1) { + err = ECE_ERROR_HKDF; + goto end; + } + if (EVP_PKEY_derive(ctx, output, &outputLen) != 1) { + err = ECE_ERROR_HKDF; + goto end; + } + +end: + EVP_PKEY_CTX_free(ctx); + return err; +} + +// Computes the ECDH shared secret, used as the input key material (IKM) for +// HKDF. +static uint8_t* +ece_compute_secret(EC_KEY* privKey, EC_KEY* pubKey, size_t* sharedSecretLen) { + uint8_t* sharedSecret = NULL; + + const EC_GROUP* group = EC_KEY_get0_group(privKey); + const EC_POINT* pubKeyPt = EC_KEY_get0_public_key(pubKey); + *sharedSecretLen = (size_t)((EC_GROUP_get_degree(group) + 7) / 8); + sharedSecret = calloc(*sharedSecretLen, sizeof(uint8_t)); + if (!sharedSecret) { + goto error; + } + if (ECDH_compute_key(sharedSecret, *sharedSecretLen, pubKeyPt, privKey, + NULL) <= 0) { + goto error; + } + goto end; + +error: + free(sharedSecret); + sharedSecret = NULL; + *sharedSecretLen = 0; + +end: + return sharedSecret; +} + +// The "aes128gcm" IKM info string is "WebPush: info\0", followed by the +// receiver and sender public keys. +static int +ece_webpush_aes128gcm_generate_info(EC_KEY* recvKey, EC_KEY* senderKey, + const char* prefix, size_t prefixLen, + uint8_t* info) { + size_t offset = 0; + + // Copy the prefix. + memcpy(info, prefix, prefixLen); + offset += prefixLen; + + // Copy the receiver public key. + const EC_GROUP* recvGrp = EC_KEY_get0_group(recvKey); + const EC_POINT* recvPubKeyPt = EC_KEY_get0_public_key(recvKey); + size_t recvPubKeyLen = + EC_POINT_point2oct(recvGrp, recvPubKeyPt, POINT_CONVERSION_UNCOMPRESSED, + &info[offset], ECE_WEBPUSH_PUBLIC_KEY_LENGTH, NULL); + if (!recvPubKeyLen) { + return ECE_ERROR_ENCODE_PUBLIC_KEY; + } + offset += recvPubKeyLen; + + // Copy the sender public key. + const EC_GROUP* senderGrp = EC_KEY_get0_group(senderKey); + const EC_POINT* senderPubKeyPt = EC_KEY_get0_public_key(senderKey); + size_t senderPubKeyLen = + EC_POINT_point2oct(senderGrp, senderPubKeyPt, POINT_CONVERSION_UNCOMPRESSED, + &info[offset], ECE_WEBPUSH_PUBLIC_KEY_LENGTH, NULL); + if (!senderPubKeyLen) { + return ECE_ERROR_ENCODE_PUBLIC_KEY; + } + + return ECE_OK; +} + +int +ece_aes128gcm_derive_key_and_nonce(const uint8_t* salt, size_t saltLen, + const uint8_t* ikm, size_t ikmLen, + uint8_t* key, uint8_t* nonce) { + int err = + ece_hkdf_sha256(salt, saltLen, ikm, ikmLen, ECE_AES128GCM_KEY_INFO, + ECE_AES128GCM_KEY_INFO_LENGTH, key, ECE_AES_KEY_LENGTH); + if (err) { + return err; + } + return ece_hkdf_sha256(salt, saltLen, ikm, ikmLen, ECE_AES128GCM_NONCE_INFO, + ECE_AES128GCM_NONCE_INFO_LENGTH, nonce, + ECE_NONCE_LENGTH); +} + +int +ece_webpush_aes128gcm_derive_key_and_nonce(ece_mode_t mode, EC_KEY* localKey, + EC_KEY* remoteKey, + const uint8_t* authSecret, + size_t authSecretLen, + const uint8_t* salt, size_t saltLen, + uint8_t* key, uint8_t* nonce) { + int err = ECE_OK; + + uint8_t* sharedSecret = NULL; + + size_t sharedSecretLen = 0; + sharedSecret = ece_compute_secret(localKey, remoteKey, &sharedSecretLen); + if (!sharedSecret) { + err = ECE_ERROR_COMPUTE_SECRET; + goto end; + } + + // The new "aes128gcm" scheme includes the sender and receiver public keys in + // the info string when deriving the Web Push IKM. + uint8_t ikmInfo[ECE_WEBPUSH_AES128GCM_IKM_INFO_LENGTH]; + switch (mode) { + case ECE_MODE_ENCRYPT: + // For encryption, the remote static public key is the receiver key, and the + // local ephemeral private key is the sender key. + err = ece_webpush_aes128gcm_generate_info( + remoteKey, localKey, ECE_WEBPUSH_AES128GCM_IKM_INFO_PREFIX, + ECE_WEBPUSH_AES128GCM_IKM_INFO_PREFIX_LENGTH, ikmInfo); + break; + + case ECE_MODE_DECRYPT: + // For decryption, the local static private key is the receiver key, and the + // remote ephemeral public key is the sender key. + err = ece_webpush_aes128gcm_generate_info( + localKey, remoteKey, ECE_WEBPUSH_AES128GCM_IKM_INFO_PREFIX, + ECE_WEBPUSH_AES128GCM_IKM_INFO_PREFIX_LENGTH, ikmInfo); + break; + + default: + assert(false); + err = ECE_ERROR_DECRYPT; + } + if (err) { + goto end; + } + uint8_t ikm[ECE_WEBPUSH_IKM_LENGTH]; + err = ece_hkdf_sha256( + authSecret, authSecretLen, sharedSecret, sharedSecretLen, ikmInfo, + ECE_WEBPUSH_AES128GCM_IKM_INFO_LENGTH, ikm, ECE_WEBPUSH_IKM_LENGTH); + if (err) { + goto end; + } + + err = ece_aes128gcm_derive_key_and_nonce(salt, saltLen, ikm, + ECE_WEBPUSH_IKM_LENGTH, key, nonce); + +end: + free(sharedSecret); + return err; +} + +// The "aesgcm" info string is "Content-Encoding: \0P-256\0", +// followed by the length-prefixed (unsigned 16-bit integers) receiver and +// sender public keys. +static int +ece_webpush_aesgcm_generate_info(EC_KEY* recvKey, EC_KEY* senderKey, + const char* prefix, size_t prefixLen, + uint8_t* info) { + size_t offset = 0; + + // Copy the prefix. + memcpy(info, prefix, prefixLen); + offset += prefixLen; + + // Copy the length-prefixed receiver public key. + ece_write_uint16_be(&info[offset], ECE_WEBPUSH_PUBLIC_KEY_LENGTH); + offset += 2; + const EC_GROUP* recvGrp = EC_KEY_get0_group(recvKey); + const EC_POINT* recvPubKeyPt = EC_KEY_get0_public_key(recvKey); + size_t recvPubKeyLen = + EC_POINT_point2oct(recvGrp, recvPubKeyPt, POINT_CONVERSION_UNCOMPRESSED, + &info[offset], ECE_WEBPUSH_PUBLIC_KEY_LENGTH, NULL); + if (!recvPubKeyLen) { + return ECE_ERROR_ENCODE_PUBLIC_KEY; + } + offset += recvPubKeyLen; + + // Copy the length-prefixed sender public key. + ece_write_uint16_be(&info[offset], ECE_WEBPUSH_PUBLIC_KEY_LENGTH); + offset += 2; + const EC_GROUP* senderGrp = EC_KEY_get0_group(senderKey); + const EC_POINT* senderPubKeyPt = EC_KEY_get0_public_key(senderKey); + size_t senderPubKeyLen = + EC_POINT_point2oct(senderGrp, senderPubKeyPt, POINT_CONVERSION_UNCOMPRESSED, + &info[offset], ECE_WEBPUSH_PUBLIC_KEY_LENGTH, NULL); + if (!senderPubKeyLen) { + return ECE_ERROR_ENCODE_PUBLIC_KEY; + } + + return ECE_OK; +} + +int +ece_webpush_aesgcm_derive_key_and_nonce(ece_mode_t mode, EC_KEY* localKey, + EC_KEY* remoteKey, + const uint8_t* authSecret, + size_t authSecretLen, + const uint8_t* salt, size_t saltLen, + uint8_t* key, uint8_t* nonce) { + ECE_UNUSED(mode); + + int err = ECE_OK; + + uint8_t* sharedSecret = NULL; + + size_t sharedSecretLen = 0; + sharedSecret = ece_compute_secret(localKey, remoteKey, &sharedSecretLen); + if (!sharedSecret) { + err = ECE_ERROR_COMPUTE_SECRET; + goto end; + } + + // The old "aesgcm" scheme uses a static info string to derive the Web Push + // IKM. + uint8_t ikm[ECE_WEBPUSH_IKM_LENGTH]; + err = ece_hkdf_sha256(authSecret, authSecretLen, sharedSecret, + sharedSecretLen, ECE_WEBPUSH_AESGCM_IKM_INFO, + ECE_WEBPUSH_AESGCM_IKM_INFO_LENGTH, ikm, + ECE_WEBPUSH_IKM_LENGTH); + if (err) { + goto end; + } + + // Next, derive the AES decryption key and nonce. We include the sender and + // receiver public keys in the info strings. + uint8_t keyInfo[ECE_WEBPUSH_AESGCM_KEY_INFO_LENGTH]; + uint8_t nonceInfo[ECE_WEBPUSH_AESGCM_NONCE_INFO_LENGTH]; + switch (mode) { + case ECE_MODE_ENCRYPT: + err = ece_webpush_aesgcm_generate_info( + remoteKey, localKey, ECE_WEBPUSH_AESGCM_KEY_INFO_PREFIX, + ECE_WEBPUSH_AESGCM_KEY_INFO_PREFIX_LENGTH, keyInfo); + if (err) { + break; + } + err = ece_webpush_aesgcm_generate_info( + remoteKey, localKey, ECE_WEBPUSH_AESGCM_NONCE_INFO_PREFIX, + ECE_WEBPUSH_AESGCM_NONCE_INFO_PREFIX_LENGTH, nonceInfo); + break; + + case ECE_MODE_DECRYPT: + err = ece_webpush_aesgcm_generate_info( + localKey, remoteKey, ECE_WEBPUSH_AESGCM_KEY_INFO_PREFIX, + ECE_WEBPUSH_AESGCM_KEY_INFO_PREFIX_LENGTH, keyInfo); + if (err) { + break; + } + err = ece_webpush_aesgcm_generate_info( + localKey, remoteKey, ECE_WEBPUSH_AESGCM_NONCE_INFO_PREFIX, + ECE_WEBPUSH_AESGCM_NONCE_INFO_PREFIX_LENGTH, nonceInfo); + break; + + default: + assert(false); + err = ECE_ERROR_DECRYPT; + } + if (err) { + goto end; + } + err = ece_hkdf_sha256(salt, saltLen, ikm, ECE_WEBPUSH_IKM_LENGTH, keyInfo, + ECE_WEBPUSH_AESGCM_KEY_INFO_LENGTH, key, + ECE_AES_KEY_LENGTH); + if (err) { + goto end; + } + err = ece_hkdf_sha256(salt, saltLen, ikm, ECE_WEBPUSH_IKM_LENGTH, nonceInfo, + ECE_WEBPUSH_AESGCM_NONCE_INFO_LENGTH, nonce, + ECE_NONCE_LENGTH); + +end: + free(sharedSecret); + return err; +} diff --git a/mobile/ios/ThirdParty/ecec/src/params.c b/mobile/ios/ThirdParty/ecec/src/params.c new file mode 100644 index 0000000000..0366d9bdf2 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/src/params.c @@ -0,0 +1,574 @@ +#include "ece.h" + +// This file implements a parser for the `Crypto-Key` and `Encryption` HTTP +// headers, used by the older "aesgcm" encoding. The newer "aes128gcm" encoding +// includes the relevant information in a binary header, directly in the +// payload. + +#include +#include +#include +#include +#include + +#define ECE_HEADER_STATE_BEGIN_PARAM 1 +#define ECE_HEADER_STATE_BEGIN_NAME 2 +#define ECE_HEADER_STATE_NAME 3 +#define ECE_HEADER_STATE_END_NAME 4 +#define ECE_HEADER_STATE_BEGIN_VALUE 5 +#define ECE_HEADER_STATE_VALUE 6 +#define ECE_HEADER_STATE_BEGIN_QUOTED_VALUE 7 +#define ECE_HEADER_STATE_QUOTED_VALUE 8 +#define ECE_HEADER_STATE_END_VALUE 9 +#define ECE_HEADER_STATE_INVALID_HEADER 10 + +#define ECE_HEADER_DH_PREFIX "dh=" +#define ECE_HEADER_DH_PREFIX_LENGTH 3 + +// Extracts an unsigned 32-bit integer in network byte order. +static inline uint32_t +ece_read_uint32_be(const uint8_t* bytes) { + uint32_t value = bytes[3]; + value |= (uint32_t) bytes[2] << 8; + value |= (uint32_t) bytes[1] << 16; + value |= (uint32_t) bytes[0] << 24; + return value; +} + +// A linked list that holds name-value pairs for a parameter in a header +// value. For example, if the parameter is `a=b; c=d; e=f`, the parser will +// allocate three `ece_header_pairs_t` structures, one for each ;-delimited +// pair. "=" separates the name and value. +typedef struct ece_header_pairs_s { + struct ece_header_pairs_s* next; + // The name and value are pointers into the backing header value; the parser + // doesn't allocate new strings. Freeing the backing string will invalidate + // all `name` and `value` references. Also, because these are not true C + // strings, it's important to use them with functions that take a length, like + // `strncmp`. Functions that assume a NUL-terminated string will read until + // the end of the backing string. + const char* name; + const char* value; + size_t nameLen; + size_t valueLen; +} ece_header_pairs_t; + +// Initializes a name-value pair node at the head of the pair list. `head` may +// be `NULL`. +static ece_header_pairs_t* +ece_header_pairs_alloc(ece_header_pairs_t* head) { + ece_header_pairs_t* pairs = malloc(sizeof(ece_header_pairs_t)); + if (!pairs) { + return NULL; + } + pairs->next = head; + pairs->name = NULL; + pairs->value = NULL; + pairs->nameLen = 0; + pairs->valueLen = 0; + return pairs; +} + +// Indicates whether a name-value pair node matches the `name`. +static inline bool +ece_header_pairs_has_name(ece_header_pairs_t* pair, const char* name) { + return !strncmp(pair->name, name, pair->nameLen); +} + +// Indicates whether a name-value pair node matches the `value`. +static inline bool +ece_header_pairs_has_value(ece_header_pairs_t* pair, const char* value) { + return !strncmp(pair->value, value, pair->valueLen); +} + +// Copies a pair node's value into a C string. +static char* +ece_header_pairs_value_to_str(ece_header_pairs_t* pair) { + char* value = malloc(pair->valueLen + 1); + if (!value) { + return NULL; + } + strncpy(value, pair->value, pair->valueLen); + value[pair->valueLen] = '\0'; + return value; +} + +// Frees a name-value pair list and all its nodes. +static void +ece_header_pairs_free(ece_header_pairs_t* pairs) { + ece_header_pairs_t* pair = pairs; + while (pair) { + ece_header_pairs_t* next = pair->next; + free(pair); + pair = next; + } +} + +// A linked list that holds parameters extracted from a header value. For +// example, if the header value is `a=b; c=d, e=f; g=h`, the parser will +// allocate two `ece_header_params_t` structures: one to hold the parameter +// `a=b; c=d`, and the other to hold `e=f; g=h`. +typedef struct ece_header_params_s { + struct ece_header_params_s* next; + ece_header_pairs_t* pairs; +} ece_header_params_t; + +// Initializes a parameter node at the head of the parameter list. `head` may be +// `NULL`. +static ece_header_params_t* +ece_header_params_alloc(ece_header_params_t* head) { + ece_header_params_t* params = malloc(sizeof(ece_header_params_t)); + if (!params) { + return NULL; + } + params->next = head; + params->pairs = NULL; + return params; +} + +// Reverses a parameter list in-place and returns a pointer to the new head. +static ece_header_params_t* +ece_header_params_reverse(ece_header_params_t* params) { + ece_header_params_t* sibling = NULL; + while (params) { + ece_header_params_t* next = params->next; + params->next = sibling; + sibling = params; + params = next; + } + return sibling; +} + +// Frees a parameter list and all its nodes. +static void +ece_header_params_free(ece_header_params_t* params) { + ece_header_params_t* param = params; + while (param) { + ece_header_pairs_free(param->pairs); + ece_header_params_t* next = param->next; + free(param); + param = next; + } +} + +// Indicates whether `c` is whitespace, per `WSP` in RFC 5234, Appendix B.1. +static inline bool +ece_header_is_space(char c) { + return c == ' ' || c == '\t'; +} + +// Indicates whether `c` can appear in a pair name. Only lowercase letters and +// numbers are allowed. +static inline bool +ece_header_is_valid_pair_name(char c) { + return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); +} + +// Indicates whether `c` can appear in a pair value. This includes all +// characters in the Base64url alphabet. +static inline bool +ece_header_is_valid_pair_value(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || c == '-' || c == '_'; +} + +// A header parameter parser. +typedef struct ece_header_parser_s { + int state; + ece_header_params_t* params; +} ece_header_parser_t; + +// Parses the next token in `input` and updates the parser state. Returns true +// if the caller should advance to the next character; false otherwise. +static bool +ece_header_parse(ece_header_parser_t* parser, const char* input) { + switch (parser->state) { + case ECE_HEADER_STATE_BEGIN_PARAM: { + ece_header_params_t* param = ece_header_params_alloc(parser->params); + if (!param) { + break; + } + parser->params = param; + parser->state = ECE_HEADER_STATE_BEGIN_NAME; + return false; + } + + case ECE_HEADER_STATE_BEGIN_NAME: + if (ece_header_is_space(*input)) { + return true; + } + if (ece_header_is_valid_pair_name(*input)) { + ece_header_pairs_t* pair = ece_header_pairs_alloc(parser->params->pairs); + if (!pair) { + break; + } + parser->params->pairs = pair; + pair->name = input; + parser->state = ECE_HEADER_STATE_NAME; + return false; + } + break; + + case ECE_HEADER_STATE_NAME: + if (ece_header_is_valid_pair_name(*input)) { + parser->params->pairs->nameLen++; + return true; + } + if (ece_header_is_space(*input) || *input == '=') { + parser->state = ECE_HEADER_STATE_END_NAME; + return false; + } + break; + + case ECE_HEADER_STATE_END_NAME: + if (ece_header_is_space(*input)) { + return true; + } + if (*input == '=') { + parser->state = ECE_HEADER_STATE_BEGIN_VALUE; + return true; + } + break; + + case ECE_HEADER_STATE_BEGIN_VALUE: + if (ece_header_is_space(*input)) { + return true; + } + if (ece_header_is_valid_pair_value(*input)) { + parser->params->pairs->value = input; + parser->state = ECE_HEADER_STATE_VALUE; + return false; + } + if (*input == '"') { + parser->state = ECE_HEADER_STATE_BEGIN_QUOTED_VALUE; + return true; + } + break; + + case ECE_HEADER_STATE_VALUE: + if (ece_header_is_space(*input) || *input == ';' || *input == ',') { + parser->state = ECE_HEADER_STATE_END_VALUE; + return false; + } + if (ece_header_is_valid_pair_value(*input)) { + parser->params->pairs->valueLen++; + return true; + } + break; + + case ECE_HEADER_STATE_BEGIN_QUOTED_VALUE: + if (ece_header_is_valid_pair_value(*input)) { + // Quoted strings allow spaces and escapes, but neither `Crypto-Key` nor + // `Encryption` accept them. We keep the parser simple by rejecting + // non-Base64url characters here. We also disallow empty quoted strings. + parser->params->pairs->value = input; + parser->params->pairs->valueLen++; + parser->state = ECE_HEADER_STATE_QUOTED_VALUE; + return true; + } + break; + + case ECE_HEADER_STATE_QUOTED_VALUE: + if (ece_header_is_valid_pair_value(*input)) { + parser->params->pairs->valueLen++; + return true; + } + if (*input == '"') { + parser->state = ECE_HEADER_STATE_END_VALUE; + return true; + } + break; + + case ECE_HEADER_STATE_END_VALUE: + if (ece_header_is_space(*input)) { + return true; + } + if (*input == ';') { + // New name-value pair for the same parameter. Advance the parser; + // `ECE_HEADER_STATE_BEGIN_NAME` will prepend a new node to the pairs + // list. + parser->state = ECE_HEADER_STATE_BEGIN_NAME; + return true; + } + if (*input == ',') { + // New parameter. Advance the parser; `ECE_HEADER_STATE_BEGIN_PARAM` will + // prepend a new node to the parameters list and begin parsing its pairs. + parser->state = ECE_HEADER_STATE_BEGIN_PARAM; + return true; + } + break; + + default: + // Unexpected parser state. + assert(false); + } + parser->state = ECE_HEADER_STATE_INVALID_HEADER; + return false; +} + +// Parses a `header` value of the form `a=b; c=d; e=f, g=h, i=j` into a +// parameter list. +static ece_header_params_t* +ece_header_extract_params(const char* header) { + ece_header_parser_t parser; + parser.state = ECE_HEADER_STATE_BEGIN_PARAM; + parser.params = NULL; + + const char* input = header; + while (*input) { + if (ece_header_parse(&parser, input)) { + input++; + } + if (parser.state == ECE_HEADER_STATE_INVALID_HEADER) { + goto error; + } + } + if (parser.state != ECE_HEADER_STATE_END_VALUE) { + // If the header ends with an unquoted value, the parser might still be in a + // non-terminal state. Try to parse an extra space to reach the terminal + // state. + ece_header_parse(&parser, " "); + if (parser.state != ECE_HEADER_STATE_END_VALUE) { + // If we're still in a non-terminal state, the header is incomplete. + goto error; + } + } + return ece_header_params_reverse(parser.params); + +error: + ece_header_params_free(parser.params); + return NULL; +} + +int +ece_aes128gcm_payload_extract_params(const uint8_t* payload, size_t payloadLen, + const uint8_t** salt, size_t* saltLen, + const uint8_t** keyId, size_t* keyIdLen, + uint32_t* rs, const uint8_t** ciphertext, + size_t* ciphertextLen) { + if (payloadLen < ECE_AES128GCM_HEADER_LENGTH) { + return ECE_ERROR_SHORT_HEADER; + } + + *saltLen = ECE_SALT_LENGTH; + + *keyIdLen = payload[ECE_SALT_LENGTH + 4]; + if (payloadLen < ECE_AES128GCM_HEADER_LENGTH + *keyIdLen) { + return ECE_ERROR_SHORT_HEADER; + } + + *rs = ece_read_uint32_be(&payload[ECE_SALT_LENGTH]); + if (*rs < ECE_AES128GCM_MIN_RS) { + return ECE_ERROR_INVALID_RS; + } + + size_t payloadStart = ECE_AES128GCM_HEADER_LENGTH + *keyIdLen; + *ciphertextLen = payloadLen - payloadStart; + if (!(*ciphertextLen)) { + return ECE_ERROR_ZERO_CIPHERTEXT; + } + + *salt = payload; + if (keyIdLen) { + *keyId = &payload[ECE_AES128GCM_HEADER_LENGTH]; + } else { + *keyId = NULL; + } + *ciphertext = &payload[payloadStart]; + + return ECE_OK; +} + +int +ece_webpush_aesgcm_headers_extract_params(const char* cryptoKeyHeader, + const char* encryptionHeader, + uint8_t* salt, size_t saltLen, + uint8_t* rawSenderPubKey, + size_t rawSenderPubKeyLen, + uint32_t* rs) { + int err = ECE_OK; + + ece_header_params_t* encryptionParams = NULL; + ece_header_params_t* cryptoKeyParams = NULL; + char* keyId = NULL; + uint32_t rsValue = 0; + size_t decodedSaltLen = 0; + size_t decodedKeyLen = 0; + + // First, extract the key ID, salt, and record size from the first key in the + // `Encryption` header. + encryptionParams = ece_header_extract_params(encryptionHeader); + if (!encryptionParams) { + err = ECE_ERROR_INVALID_ENCRYPTION_HEADER; + goto end; + } + for (ece_header_pairs_t* pair = encryptionParams->pairs; pair; + pair = pair->next) { + if (ece_header_pairs_has_name(pair, "keyid")) { + // The key ID is optional, and is used to identify the public key in the + // `Crypto-Key` header if multiple encryption keys are specified. + if (keyId) { + err = ECE_ERROR_INVALID_ENCRYPTION_HEADER; + goto end; + } + keyId = ece_header_pairs_value_to_str(pair); + if (!keyId) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + continue; + } + if (ece_header_pairs_has_name(pair, "rs")) { + // The record size is optional. + if (rsValue) { + err = ECE_ERROR_INVALID_ENCRYPTION_HEADER; + goto end; + } + char* value = ece_header_pairs_value_to_str(pair); + if (!value) { + err = ECE_ERROR_OUT_OF_MEMORY; + goto end; + } + int result = sscanf(value, "%" SCNu32, &rsValue); + free(value); + if (result <= 0 || rsValue < ECE_AESGCM_MIN_RS) { + err = ECE_ERROR_INVALID_RS; + goto end; + } + continue; + } + if (ece_header_pairs_has_name(pair, "salt")) { + // The salt is required, and must be Base64url-encoded without padding. + if (decodedSaltLen) { + err = ECE_ERROR_INVALID_ENCRYPTION_HEADER; + goto end; + } + decodedSaltLen = + ece_base64url_decode(pair->value, pair->valueLen, + ECE_BASE64URL_REJECT_PADDING, salt, saltLen); + if (!decodedSaltLen) { + break; + } + continue; + } + } + if (decodedSaltLen != saltLen) { + err = ECE_ERROR_INVALID_SALT; + goto end; + } + if (!rsValue) { + // The record size defaults to 4096 if unspecified. + rsValue = 4096; + } + *rs = rsValue; + + // Next, find the ephemeral public key in the `Crypto-Key` header. + cryptoKeyParams = ece_header_extract_params(cryptoKeyHeader); + if (!cryptoKeyParams) { + err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER; + goto end; + } + ece_header_params_t* cryptoKeyParam = cryptoKeyParams; + if (keyId) { + // If the sender specified a key ID in the `Encryption` header, find the + // matching parameter in the `Crypto-Key` header. Otherwise, we assume + // there's only one key, and use the first one we see. + while (cryptoKeyParam) { + bool keyIdMatches = false; + for (ece_header_pairs_t* pair = cryptoKeyParam->pairs; pair; + pair = pair->next) { + if (!ece_header_pairs_has_name(pair, "keyid")) { + continue; + } + keyIdMatches = ece_header_pairs_has_value(pair, keyId); + if (keyIdMatches) { + break; + } + } + if (keyIdMatches) { + break; + } + cryptoKeyParam = cryptoKeyParam->next; + } + if (!cryptoKeyParam) { + // We don't have a matching key ID with a `dh` name-value pair. + err = ECE_ERROR_INVALID_DH; + goto end; + } + } + for (ece_header_pairs_t* pair = cryptoKeyParam->pairs; pair; + pair = pair->next) { + if (!ece_header_pairs_has_name(pair, "dh")) { + continue; + } + // The sender's public key must be Base64url-encoded without padding. + decodedKeyLen = ece_base64url_decode(pair->value, pair->valueLen, + ECE_BASE64URL_REJECT_PADDING, + rawSenderPubKey, rawSenderPubKeyLen); + break; + } + if (decodedKeyLen != rawSenderPubKeyLen) { + err = ECE_ERROR_INVALID_DH; + goto end; + } + +end: + ece_header_params_free(encryptionParams); + ece_header_params_free(cryptoKeyParams); + free(keyId); + return err; +} + +int +ece_webpush_aesgcm_headers_from_params(const void* salt, size_t saltLen, + const void* rawSenderPubKey, + size_t rawSenderPubKeyLen, uint32_t rs, + char* cryptoKeyHeader, + size_t* cryptoKeyHeaderLen, + char* encryptionHeader, + size_t* encryptionHeaderLen) { + size_t b64SenderPubKeyLen = ece_base64url_encode( + rawSenderPubKey, rawSenderPubKeyLen, ECE_BASE64URL_OMIT_PADDING, NULL, 0); + if (!b64SenderPubKeyLen || + b64SenderPubKeyLen > SIZE_MAX - ECE_HEADER_DH_PREFIX_LENGTH) { + return ECE_ERROR_INVALID_DH; + } + size_t requiredCryptoKeyHeaderLen = + b64SenderPubKeyLen + ECE_HEADER_DH_PREFIX_LENGTH; + if (*cryptoKeyHeaderLen) { + if (*cryptoKeyHeaderLen < requiredCryptoKeyHeaderLen) { + return ECE_ERROR_OUT_OF_MEMORY; + } + memcpy(cryptoKeyHeader, ECE_HEADER_DH_PREFIX, ECE_HEADER_DH_PREFIX_LENGTH); + ece_base64url_encode( + rawSenderPubKey, rawSenderPubKeyLen, ECE_BASE64URL_OMIT_PADDING, + &cryptoKeyHeader[ECE_HEADER_DH_PREFIX_LENGTH], b64SenderPubKeyLen); + } + *cryptoKeyHeaderLen = requiredCryptoKeyHeaderLen; + + size_t b64SaltLen = + ece_base64url_encode(salt, saltLen, ECE_BASE64URL_OMIT_PADDING, NULL, 0); + if (!b64SaltLen) { + return ECE_ERROR_INVALID_SALT; + } + int maybeEncryptionPrefixLen = snprintf(NULL, 0, "rs=%" PRIu32 ";salt=", rs); + if (maybeEncryptionPrefixLen <= 0) { + return ECE_ERROR_INVALID_SALT; + } + size_t encryptionPrefixLen = (size_t) maybeEncryptionPrefixLen; + if (b64SaltLen > SIZE_MAX - encryptionPrefixLen) { + return ECE_ERROR_INVALID_SALT; + } + size_t requiredEncryptionHeaderLen = b64SaltLen + encryptionPrefixLen; + if (*encryptionHeaderLen) { + if (*encryptionHeaderLen < requiredEncryptionHeaderLen) { + return ECE_ERROR_OUT_OF_MEMORY; + } + sprintf(encryptionHeader, "rs=%" PRIu32 ";salt=", rs); + ece_base64url_encode(salt, saltLen, ECE_BASE64URL_OMIT_PADDING, + &encryptionHeader[encryptionPrefixLen], b64SaltLen); + } + *encryptionHeaderLen = requiredEncryptionHeaderLen; + + return ECE_OK; +} diff --git a/mobile/ios/ThirdParty/ecec/src/trailer.c b/mobile/ios/ThirdParty/ecec/src/trailer.c new file mode 100644 index 0000000000..6ab6abbcf4 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/src/trailer.c @@ -0,0 +1,19 @@ +#include "ece/trailer.h" +#include "ece.h" + +uint32_t +ece_aesgcm_rs(uint32_t rs) { + return rs > UINT32_MAX - ECE_TAG_LENGTH ? 0 : rs + ECE_TAG_LENGTH; +} + +bool +ece_aesgcm_needs_trailer(uint32_t rs, size_t ciphertextLen) { + return !(ciphertextLen % rs); +} + +bool +ece_aes128gcm_needs_trailer(uint32_t rs, size_t ciphertextLen) { + ECE_UNUSED(rs); + ECE_UNUSED(ciphertextLen); + return false; +} diff --git a/mobile/ios/ThirdParty/ecec/test/base64url.c b/mobile/ios/ThirdParty/ecec/test/base64url.c new file mode 100644 index 0000000000..f3da710fe2 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/base64url.c @@ -0,0 +1,178 @@ +#include "test.h" + +#include + +typedef struct base64url_encode_test_s { + const char* binary; + size_t binaryLen; + ece_base64url_encode_policy_t paddingPolicy; + const char* base64; + size_t base64Len; +} base64url_encode_test_t; + +static base64url_encode_test_t base64url_encode_tests[] = { + {"f", 1, ECE_BASE64URL_OMIT_PADDING, "Zg", 2}, + {"f", 1, ECE_BASE64URL_INCLUDE_PADDING, "Zg==", 4}, + + {"fo", 2, ECE_BASE64URL_OMIT_PADDING, "Zm8", 3}, + {"fo", 2, ECE_BASE64URL_INCLUDE_PADDING, "Zm8=", 4}, + + {"foo", 3, ECE_BASE64URL_OMIT_PADDING, "Zm9v", 4}, + {"foo", 3, ECE_BASE64URL_INCLUDE_PADDING, "Zm9v", 4}, + + {"foob", 4, ECE_BASE64URL_OMIT_PADDING, "Zm9vYg", 6}, + {"foob", 4, ECE_BASE64URL_INCLUDE_PADDING, "Zm9vYg==", 8}, + + {"fooba", 5, ECE_BASE64URL_OMIT_PADDING, "Zm9vYmE", 7}, + {"fooba", 5, ECE_BASE64URL_INCLUDE_PADDING, "Zm9vYmE=", 8}, + + {"foobar", 6, ECE_BASE64URL_OMIT_PADDING, "Zm9vYmFy", 8}, + {"foobar", 6, ECE_BASE64URL_INCLUDE_PADDING, "Zm9vYmFy", 8}, + + {"\x14\xfb\x9c\x03\xd9\x7e", 6, ECE_BASE64URL_OMIT_PADDING, "FPucA9l-", 8}, + {"\x14\xfb\x9c\x03\xd9\x7e", 6, ECE_BASE64URL_INCLUDE_PADDING, "FPucA9l-", 8}, + + {"\x14\xfb\x9c\x03\xd9", 5, ECE_BASE64URL_OMIT_PADDING, "FPucA9k", 7}, + {"\x14\xfb\x9c\x03\xd9", 5, ECE_BASE64URL_INCLUDE_PADDING, "FPucA9k=", 8}, + + {"\x14\xfb\x9c\x03", 4, ECE_BASE64URL_OMIT_PADDING, "FPucAw", 6}, + {"\x14\xfb\x9c\x03", 4, ECE_BASE64URL_INCLUDE_PADDING, "FPucAw==", 8}, +}; + +typedef struct base64url_decode_test_s { + const char* base64; + size_t base64Len; + ece_base64url_decode_policy_t paddingPolicy; + size_t requiredBinaryLen; + const char* binary; + size_t binaryLen; +} base64url_decode_test_t; + +static base64url_decode_test_t base64url_decode_tests[] = { + // Test vectors from RFC 4648, section 10. + {"", 0, ECE_BASE64URL_REQUIRE_PADDING, 0, NULL, 0}, + + {"Zg", 2, ECE_BASE64URL_REQUIRE_PADDING, 0, NULL, 0}, + {"Zg", 2, ECE_BASE64URL_IGNORE_PADDING, 1, "f", 1}, + {"Zg", 2, ECE_BASE64URL_REJECT_PADDING, 1, "f", 1}, + + {"Zg==", 4, ECE_BASE64URL_REQUIRE_PADDING, 1, "f", 1}, + {"Zg==", 4, ECE_BASE64URL_IGNORE_PADDING, 1, "f", 1}, + {"Zg==", 4, ECE_BASE64URL_REJECT_PADDING, 3, NULL, 0}, + + {"Zm8", 3, ECE_BASE64URL_REQUIRE_PADDING, 0, NULL, 0}, + {"Zm8", 3, ECE_BASE64URL_IGNORE_PADDING, 2, "fo", 2}, + {"Zm8", 3, ECE_BASE64URL_REJECT_PADDING, 2, "fo", 2}, + + {"Zm8=", 4, ECE_BASE64URL_REQUIRE_PADDING, 2, "fo", 2}, + {"Zm8=", 4, ECE_BASE64URL_IGNORE_PADDING, 2, "fo", 2}, + {"Zm8=", 4, ECE_BASE64URL_REJECT_PADDING, 3, NULL, 0}, + + {"Zm9v", 4, ECE_BASE64URL_REQUIRE_PADDING, 3, "foo", 3}, + {"Zm9v", 4, ECE_BASE64URL_IGNORE_PADDING, 3, "foo", 3}, + {"Zm9v", 4, ECE_BASE64URL_REJECT_PADDING, 3, "foo", 3}, + + {"Zm9vYg", 6, ECE_BASE64URL_REQUIRE_PADDING, 0, NULL, 0}, + {"Zm9vYg", 6, ECE_BASE64URL_IGNORE_PADDING, 4, "foob", 4}, + {"Zm9vYg", 6, ECE_BASE64URL_REJECT_PADDING, 4, "foob", 4}, + + {"Zm9vYg==", 8, ECE_BASE64URL_REQUIRE_PADDING, 4, "foob", 4}, + {"Zm9vYg==", 8, ECE_BASE64URL_IGNORE_PADDING, 4, "foob", 4}, + {"Zm9vYg==", 8, ECE_BASE64URL_REJECT_PADDING, 6, NULL, 0}, + + {"Zm9vYmE", 7, ECE_BASE64URL_REQUIRE_PADDING, 0, NULL, 0}, + {"Zm9vYmE", 7, ECE_BASE64URL_IGNORE_PADDING, 5, "fooba", 5}, + {"Zm9vYmE", 7, ECE_BASE64URL_REJECT_PADDING, 5, "fooba", 5}, + + {"Zm9vYmE=", 8, ECE_BASE64URL_REQUIRE_PADDING, 5, "fooba", 5}, + {"Zm9vYmE=", 8, ECE_BASE64URL_IGNORE_PADDING, 5, "fooba", 5}, + {"Zm9vYmE=", 8, ECE_BASE64URL_REJECT_PADDING, 6, NULL, 0}, + + {"Zm9vYmFy", 8, ECE_BASE64URL_REQUIRE_PADDING, 6, "foobar", 6}, + {"Zm9vYmFy", 8, ECE_BASE64URL_IGNORE_PADDING, 6, "foobar", 6}, + {"Zm9vYmFy", 8, ECE_BASE64URL_REJECT_PADDING, 6, "foobar", 6}, + + // Examples from RFC 4648, section 9. + {"FPucA9l-", 8, ECE_BASE64URL_REQUIRE_PADDING, 6, "\x14\xfb\x9c\x03\xd9\x7e", + 6}, + {"FPucA9l-", 8, ECE_BASE64URL_IGNORE_PADDING, 6, "\x14\xfb\x9c\x03\xd9\x7e", + 6}, + {"FPucA9l-", 8, ECE_BASE64URL_REJECT_PADDING, 6, "\x14\xfb\x9c\x03\xd9\x7e", + 6}, + + {"FPucA9k", 7, ECE_BASE64URL_REQUIRE_PADDING, 0, NULL, 0}, + {"FPucA9k", 7, ECE_BASE64URL_IGNORE_PADDING, 5, "\x14\xfb\x9c\x03\xd9", 5}, + {"FPucA9k", 7, ECE_BASE64URL_REJECT_PADDING, 5, "\x14\xfb\x9c\x03\xd9", 5}, + + {"FPucA9k=", 8, ECE_BASE64URL_REQUIRE_PADDING, 5, "\x14\xfb\x9c\x03\xd9", 5}, + {"FPucA9k=", 8, ECE_BASE64URL_IGNORE_PADDING, 5, "\x14\xfb\x9c\x03\xd9", 5}, + {"FPucA9k=", 8, ECE_BASE64URL_REJECT_PADDING, 6, NULL, 0}, + + {"FPucAw", 6, ECE_BASE64URL_REQUIRE_PADDING, 0, NULL, 0}, + {"FPucAw", 6, ECE_BASE64URL_IGNORE_PADDING, 4, "\x14\xfb\x9c\x03", 4}, + {"FPucAw", 6, ECE_BASE64URL_REJECT_PADDING, 4, "\x14\xfb\x9c\x03", 4}, + + {"FPucAw==", 8, ECE_BASE64URL_REQUIRE_PADDING, 4, "\x14\xfb\x9c\x03", 4}, + {"FPucAw==", 8, ECE_BASE64URL_IGNORE_PADDING, 4, "\x14\xfb\x9c\x03", 4}, + {"FPucAw==", 8, ECE_BASE64URL_REJECT_PADDING, 6, NULL, 0}, +}; + +void +test_base64url_encode(void) { + size_t tests = + sizeof(base64url_encode_tests) / sizeof(base64url_encode_test_t); + for (size_t i = 0; i < tests; i++) { + base64url_encode_test_t t = base64url_encode_tests[i]; + + size_t requiredBase64Len = + ece_base64url_encode(t.binary, t.binaryLen, t.paddingPolicy, NULL, 0); + ece_assert( + requiredBase64Len == t.base64Len, + "Got required length %zu for `%s` with padding policy %d; want %zu", + requiredBase64Len, t.base64, t.paddingPolicy, t.base64Len); + + char* base64 = malloc(requiredBase64Len + 1); + ece_assert(base64, + "Failed to allocate string for `%s` with padding policy %d", + t.base64, t.paddingPolicy); + + size_t actualBase64Len = ece_base64url_encode( + t.binary, t.binaryLen, t.paddingPolicy, base64, requiredBase64Len + 1); + ece_assert(actualBase64Len == t.base64Len, + "Got length %zu for `%s` with padding policy %d; want %zu", + actualBase64Len, t.base64, t.paddingPolicy, t.base64Len); + + free(base64); + } +} + +void +test_base64url_decode(void) { + size_t tests = + sizeof(base64url_decode_tests) / sizeof(base64url_decode_test_t); + for (size_t i = 0; i < tests; i++) { + base64url_decode_test_t t = base64url_decode_tests[i]; + + size_t requiredBinaryLen = + ece_base64url_decode(t.base64, t.base64Len, t.paddingPolicy, NULL, 0); + ece_assert(requiredBinaryLen == t.requiredBinaryLen, + "Got required length %zu for `%s` with padding %d; want %zu", + requiredBinaryLen, t.base64, t.paddingPolicy, + t.requiredBinaryLen); + + uint8_t* binary = calloc(requiredBinaryLen, sizeof(uint8_t)); + ece_assert(binary, "Failed to allocate buffer for `%s` with padding %d", + t.base64, t.paddingPolicy); + + size_t binaryLen = ece_base64url_decode( + t.base64, t.base64Len, t.paddingPolicy, binary, requiredBinaryLen); + ece_assert(binaryLen == t.binaryLen, + "Got length %zu for `%s` with padding %d; want %zu", binaryLen, + t.base64, t.paddingPolicy, t.binaryLen); + ece_assert(!memcmp(binary, t.binary, binaryLen), + "Wrong output for `%s` with padding %d", t.base64, + t.paddingPolicy); + + free(binary); + } +} diff --git a/mobile/ios/ThirdParty/ecec/test/decrypt/aes128gcm.c b/mobile/ios/ThirdParty/ecec/test/decrypt/aes128gcm.c new file mode 100644 index 0000000000..68521b68ac --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/decrypt/aes128gcm.c @@ -0,0 +1,497 @@ +#include "test.h" + +#include + +typedef struct webpush_aes128gcm_decrypt_ok_test_s { + const char* desc; + const char* plaintext; + const char* recvPrivKey; + const char* authSecret; + const char* payload; + size_t payloadLen; + size_t maxPlaintextLen; + size_t plaintextLen; +} webpush_aes128gcm_decrypt_ok_test_t; + +static webpush_aes128gcm_decrypt_ok_test_t + webpush_aes128gcm_decrypt_ok_tests[] = { + { + .desc = "rs = 24, pad = 0", + .plaintext = "I am the walrus", + .recvPrivKey = "\xc8\x99\xd1\x1d\x32\xe2\xb7\xe6\xfe\x74\x98\x78\x6f\x50" + "\xf2\x3b\x98\xac\xe5\x39\x7a\xd2\x61\xde\x39\xba\x64\x49" + "\xec\xc1\x2c\xad", + .authSecret = + "\x99\x6f\xad\x8b\x50\xaa\x2d\x02\xb8\x3f\x26\x41\x2b\x2e\x2a\xee", + .payload = "\x49\x5c\xe6\xc8\xde\x93\xa4\x53\x9e\x86\x2e\x86\x34\x99\x3c" + "\xbb\x00\x00" + "\x00\x18\x41\x04\x3c\x33\x78\xa2\xc0\xab\x95\x4e\x14\x98\x71" + "\x8e\x85\xf0" + "\x8b\xb7\x23\xfb\x7d\x25\xe1\x35\xa6\x63\xfe\x38\x58\x84\xeb" + "\x81\x92\x33" + "\x6b\xf9\x0a\x54\xed\x72\x0f\x1c\x04\x5c\x0b\x40\x5e\x9b\xbc" + "\x3a\x21\x42" + "\xb1\x6c\x89\x08\x67\x34\xc3\x74\xeb\xaf\x70\x99\xe6\x42\x7e" + "\x2d\x32\xc8" + "\xad\xa5\x01\x87\x03\xc5\x4b\x10\xb4\x81\xe1\x02\x7d\x72\x09" + "\xd8\xc6\xb4" + "\x35\x53\xfa\x13\x3a\xfa\x59\x7f\x2d\xdc\x45\xa5\xba\x81\x40" + "\x94\x4e\x64" + "\x90\xbb\x8d\x6d\x99\xba\x1d\x02\xe6\x0d\x95\xf4\x8c\xe6\x44" + "\x47\x7c\x17" + "\x23\x1d\x95\xb9\x7a\x4f\x95\xdd", + .payloadLen = 152, + .maxPlaintextLen = 18, + .plaintextLen = 15, + }, + { + .desc = "rs = 49, pad = 84; ciphertext length falls on record boundary", + .plaintext = "Hello, world", + .recvPrivKey = "\x67\x00\x4a\x4e\xa8\x20\xde\xed\x8e\x49\xdb\x5e\x94\x80" + "\xe6\x3d\x3e\xa3\xcc\xe1\xae\x8e\x1a\x60\x60\x97\x13\xd5" + "\x27\xd0\x01\xef", + .authSecret = + "\x95\xf1\x75\x70\xe5\x08\xef\x6a\x2b\x2a\xd1\xb4\xf5\xca\xde\x33", + .payload = + "\xfb\x28\x83\xce\xc1\xc4\xfc\xad\xd6\xd1\x37\x1f\x6e\xa4\x91\xe0\x00" + "\x00\x00\x31\x41\x04\x2d\x44\x1e\xe7\xf9\xff\x6a\x03\x29\xa6\x49\x27" + "\xd0\x52\x4f\xdb\xe7\xb2\x2c\x6f\xb6\x5e\x10\xab\x4f\xdc\x03\x8f\x94" + "\x42\x0a\x0c\xa3\xfa\x28\xda\xd3\x6c\x84\xec\x91\xa1\x62\xea\xe0\x78" + "\xfa\xad\x2c\x1c\xed\x78\xde\x81\x13\xe1\x96\x02\xb2\x0e\x89\x4f\x49" + "\x76\xb9\x73\xe2\xfc\xf6\x82\xfa\x0c\x8c\xcd\x9a\xf3\xd5\xbf\xf1\xed" + "\xe1\x6f\xad\x5a\x31\xce\x19\xd3\x8b\x5e\x1f\xe1\xf7\x8a\x4f\xad\x84" + "\x2b\xbc\x10\x25\x4c\x2c\x6c\xdd\x96\xa2\xb5\x52\x84\xd9\x72\xc5\x3c" + "\xad\x8c\x3b\xac\xb1\x0f\x5f\x57\xeb\x0d\x4a\x43\x33\xb6\x04\x10\x2b" + "\xa1\x17\xca\xe2\x91\x08\xfb\xd9\xf6\x29\xa8\xba\x69\x60\xdd\x01\x94" + "\x5b\x39\xed\x37\xba\x70\x6c\x43\x4a\x10\xfd\x2b\xd2\x09\x4f\xf9\x24" + "\x9b\xcd\xad\x45\x13\x5f\x5f\xe4\x5f\xcd\x38\x07\x1f\x8b\x2d\x39\x41" + "\xaf\xda\x43\x98\x10\xd7\x7a\xac\xaf\x7c\xe5\x0b\x54\x32\x5b\xf5\x8c" + "\x95\x03\x33\x7d\x07\x37\x85\xa3\x23\xdf\xa3\x43", + .payloadLen = 233, + .maxPlaintextLen = 99, + .plaintextLen = 12, + }, + { + .desc = "Example from draft-ietf-webpush-encryption-latest", + .plaintext = "When I grow up, I want to be a watermelon", + .recvPrivKey = "\xab\x57\x57\xa7\x0d\xd4\xa5\x3e\x55\x3a\x6b\xbf\x71\xff" + "\xef\xea\x28\x74\xec\x07\xa6\xb3\x79\xe3\xc4\x8f\x89\x5a" + "\x02\xdc\x33\xde", + .authSecret = + "\x05\x30\x59\x32\xa1\xc7\xea\xbe\x13\xb6\xce\xc9\xfd\xa4\x88\x82", + .payload = "\x0c\x6b\xfa\xad\xad\x67\x95\x88\x03\x09\x2d\x45\x46\x76\xf3" + "\x97\x00\x00\x10\x00\x41\x04\xfe\x33\xf4\xab\x0d\xea\x71\x91" + "\x4d\xb5\x58\x23\xf7\x3b\x54\x94\x8f\x41\x30\x6d\x92\x07\x32" + "\xdb\xb9\xa5\x9a\x53\x28\x64\x82\x20\x0e\x59\x7a\x7b\x7b\xc2" + "\x60\xba\x1c\x22\x79\x98\x58\x09\x92\xe9\x39\x73\x00\x2f\x30" + "\x12\xa2\x8a\xe8\xf0\x6b\xbb\x78\xe5\xec\x0f\xf2\x97\xde\x5b" + "\x42\x9b\xba\x71\x53\xd3\xa4\xae\x0c\xaa\x09\x1f\xd4\x25\xf3" + "\xb4\xb5\x41\x4a\xdd\x8a\xb3\x7a\x19\xc1\xbb\xb0\x5c\xf5\xcb" + "\x5b\x2a\x2e\x05\x62\xd5\x58\x63\x56\x41\xec\x52\x81\x2c\x6c" + "\x8f\xf4\x2e\x95\xcc\xb8\x6b\xe7\xcd", + .payloadLen = 144, + .maxPlaintextLen = 42, + .plaintextLen = 41, + }, + { + .desc = "rs = 18, pad = 0", + .plaintext = "1", + .recvPrivKey = "\x27\x43\x3f\xab\x89\x70\xb3\xcb\x52\x84\xb6\x11\x83\xef" + "\xb4\x62\x86\x56\x2c\xd2\xa7\x33\x0d\x8c\xae\x96\x09\x11" + "\xa5\x57\x1d\x0c", + .authSecret = + "\xd6\x5a\x04\xdf\x95\xf2\xdb\x5e\x60\x48\x39\xf7\x17\xdc\xde\x79", + .payload = "\x7c\xae\xbd\xbc\x20\x93\x8e\xe3\x40\xa9\x46\xf1\xbd\x4f\x68" + "\xf1\x00\x00\x00\x12\x41\x04\x37\xcf\xdb\x52\x23\xd9\xf9\x5e" + "\xaa\x02\xf6\xed\x94\x0f\xf2\x2e\xaf\x05\xb3\x62\x2e\x94\x9d" + "\xc3\xce\x9f\x33\x5e\x6e\xf9\xb2\x6a\xea\xac\xca\x0f\x74\x08" + "\x0a\x8b\x36\x45\x92\xf2\xcc\xc6\xd5\xed\xdd\x43\x00\x4b\x70" + "\xb9\x18\x87\xd1\x44\xd9\xfa\x93\xf1\x6c\x3b\xc7\xea\x68\xf4" + "\xfd\x54\x7a\x94\xec\xa8\x4b\x16\xe1\x38\xa6\x08\x01\x77", + .payloadLen = 104, + .maxPlaintextLen = 2, + .plaintextLen = 1, + }, +}; + +typedef struct webpush_aes128gcm_err_decrypt_test_s { + const char* desc; + const char* recvPrivKey; + const char* authSecret; + const char* payload; + size_t payloadLen; + size_t maxPlaintextLen; + int err; +} webpush_aes128gcm_err_decrypt_test_t; + +static webpush_aes128gcm_err_decrypt_test_t + webpush_aes128gcm_err_decrypt_tests[] = { + { + // Header block shorter than 21 bytes. + .desc = "Missing header block", + .recvPrivKey = "\x1b\xe8\x3f\x38\x33\x2e\xf0\x96\x81\xfa\xf3\xf3\x07\xb1" + "\xff\x2e\x10\xca\xb7\x8c\xc7\xcd\xab\x68\x3a\xc0\xee\x92" + "\xac\x3f\x6e\xe1", + .authSecret = + "\x34\x71\xbb\x98\x48\x1e\x02\x53\x3b\xf3\x95\x42\xbc\xf3\xdb\xa4", + .payload = "\x45\xb7\x4d\x2b\x69\xbe\x9b\x07\x4d\xe3\xb3\x5a\xa8\x7e\x7c" + "\x15\x61\x1d", + .payloadLen = 18, + .maxPlaintextLen = 0, + .err = ECE_ERROR_SHORT_HEADER, + }, + { + // Sender key shorter than 65 bytes. + .desc = "Truncated sender key", + .recvPrivKey = "\xce\x88\xe8\xe0\xb3\x05\x7a\x47\x52\xeb\x4c\x8f\xa9\x31" + "\xeb\x62\x1c\x30\x2d\xa5\xad\x03\xb8\x1a\xf4\x59\xcf\x67" + "\x35\x56\x0c\xae", + .authSecret = + "\x5c\x31\xe0\xd9\x6d\x9a\x13\x98\x99\xac\x09\x69\xd3\x59\xf7\x40", + .payload = "\xde\x5b\x69\x6b\x87\xf1\xa1\x5c\xb6\xad\xeb\xdd\x79\xd6\xf9" + "\x9e\x00\x00\x00\x12\x01\x00\xb6\xbc\x18\x26\xc3\x7c\x9f\x73" + "\xdd\x6b\x48\x59\xc2\xb5\x05\x18\x19\x52", + .payloadLen = 40, + .maxPlaintextLen = 2, + .err = ECE_ERROR_COMPUTE_SECRET, + }, + { + // The payload is encrypted with only the first 12 bytes of the auth + // secret. + .desc = "Truncated auth secret", + .recvPrivKey = "\x60\xc7\x63\x6a\x51\x7d\xe7\x03\x9a\x0a\xc2\xd0\xe3\x06" + "\x44\x00\x79\x4c\x78\xe7\xe0\x49\x39\x81\x29\xa2\x27\xce" + "\xe0\xf9\xa8\x01", + .authSecret = + "\x35\x5a\x38\xcd\x6d\x9b\xef\x15\x99\x0e\x2d\x33\x08\xdb\xd6\x00", + .payload = "\x81\x15\xf4\x98\x8b\x8c\x39\x2a\x7b\xac\xb4\x3c\x8f\x1a\xc5" + "\x65\x00\x00\x00\x12\x41\x04\x19\x94\x48\x3c\x54\x1e\x9b\xc3" + "\x9a\x6a\xf0\x3f\xf7\x13\xaa\x77\x45\xc2\x84\xe1\x38\xa4\x2a" + "\x24\x35\xb7\x97\xb2\x0c\x4b\x69\x8c\xf5\x11\x8b\x4f\x85\x55" + "\x31\x7c\x19\x0e\xab\xeb\xfa\xb7\x49\xc1\x64\xd3\xf6\xbd\xeb" + "\xe0\xd4\x41\x71\x91\x31\xa3\x57\xd8\x89\x0a\x13\xc4\xdb\xd4" + "\xb1\x6f\xf3\xdd\x5a\x83\xf7\xc9\x1a\xd6\xe0\x40\xac\x42\x73" + "\x0a\x7f\x0b\x3c\xd3\x24\x5e\x9f\x8d\x6f\xf3\x1c\x75\x1d\x41" + "\x0c\xfd", + .payloadLen = 122, + .maxPlaintextLen = 4, + .err = ECE_ERROR_DECRYPT, + }, + { + .desc = "Early final record", + .recvPrivKey = "\x5d\xda\x1d\x91\x8b\xc4\x07\xba\x3c\xda\x12\xcb\x80\x14" + "\xd4\x9a\xa7\xe0\x26\x90\x02\x82\x03\x04\x46\x6b\xc8\x00" + "\x34\xca\x92\x40", + .authSecret = + "\x40\xc2\x41\xfd\xe4\x26\x9e\xe1\xe6\xd7\x25\x59\x2d\x98\x27\x18", + .payload = "\xdb\xe2\x15\x50\x7d\x1a\xd3\xd2\xea\xea\xbe\xae\x6e\x87\x4d" + "\x8f\x00\x00\x00\x12\x41\x04\x7b\xc4\x34\x3f\x34\xa8\x34\x8c" + "\xdc\x4e\x46\x2f\xfc\x7c\x40\xaa\x6a\x8c\x61\xa7\x39\xc4\xc4" + "\x1d\x45\x12\x55\x05\xf7\x0e\x9f\xc5\xf9\xef\xa8\x68\x52\xdd" + "\x48\x8d\xcf\x8e\x8e\xa2\xca\xfb\x75\xe0\x7a\xbd\x5e\xe7\xc9" + "\xd5\xc0\x38\xba\xfe\xf0\x79\x57\x1b\x0b\xda\x29\x44\x11\xce" + "\x98\xc7\x6d\xd0\x31\xc0\xe5\x80\x57\x7a\x49\x80\xa3\x75\xe4" + "\x5e\xd3\x04\x29\xbe\x0e\x2e\xe9\xda\x7e\x6d\xf8\x69\x6d\x01" + "\xb8\xec", + .payloadLen = 122, + .maxPlaintextLen = 4, + .err = ECE_ERROR_DECRYPT_PADDING, + }, +}; + +typedef struct aes128gcm_ok_decrypt_test_s { + const char* desc; + const char* plaintext; + const char* ikm; + const char* payload; + size_t payloadLen; + size_t maxPlaintextLen; + size_t plaintextLen; +} aes128gcm_ok_decrypt_test_t; + +static aes128gcm_ok_decrypt_test_t aes128gcm_ok_decrypt_tests[] = { + { + .desc = "rs = 18, pad = 8", + .plaintext = "When I grow up, I want to be a watermelon", + .ikm = "\x28\xc0\x66\x11\x4a\x2d\xa5\x21\xca\x89\xf4\x21\x9d\xa8\xac\xc0", + .payload = + "\x1f\xc2\xec\x59\x4d\xbd\xa8\xc8\xab\x26\x25\x47\x04\x65\xb8\xcd\x00\x00" + "\x00\x12\x00\x92\x56\xfe\x1c\x43\x4f\x71\x8e\x85\x16\x3a\x0f\x52\x69\xc1" + "\xb8\x24\x55\x73\x60\x7d\x06\x06\xc3\x97\xfc\xfd\xc3\x27\xd5\xf9\x0c\x44" + "\x8d\x6a\x11\xa0\xc4\xb8\xd0\x51\xc8\x54\x94\xb0\x0f\xb5\xeb\xb9\xe6\x85" + "\x38\x2f\x88\xee\x5a\xce\x19\x1b\xfa\x73\x1d\xa2\xc9\xb2\x3f\x0a\xe4\xfe" + "\x4b\x9a\xd5\xf5\x4d\xf0\xec\xc8\x17\x9f\xc6\xdb\xed\x3a\x94\x33\xbe\x4f" + "\x92\xa8\xdd\xf1\x0d\x5f\x29\x9f\x76\x73\xfb\x79\x33\x69\xc9\x6b\xf5\x20" + "\x5b\x4e\xa5\x47\xef\xa3\xd4\x4b\x6c\xaa\x47\xac\x97\x9a\xa1\x69\x45\x2a" + "\xf6\xf6\x84\x65\xda\xba\x9b\x8a\xb3\x9c\xed\x91\x15\xd4\x4f\xbb\x7c\xf6" + "\xc6\xfa\x0f\x86\x71\xa2\xa1\x2c\xf6\x18\x18\x86\x94\xf1\x7c\x2f\x63\xb7" + "\x46\xe0\x6e\x9a\x51\x20\x6a\x8c\x54\xc9\x91\x54\xb1\x84\xa9\xec\x8a\x29" + "\x71\x4e\xfd\xb6\x8f\xde\xe4\xc4\x2f\x57\xb3\x2e\x48\x8d\x5c\x47\x51\x05" + "\xd0\x57\xb6\x55\x15\xc4\xa0\xeb\x59\x5b\xd6\xe8\xa7\x11\x65\x18\xad\xfb" + "\xc5\xdf\xbc\x51\x71\x01\xae\x72\x2b\x19\x14\xa1\x47\x3e\x35\xbb\x52\xa7" + "\xc9\xad\x22\x09\xc6\xea\x8f\x2b\x60\x5f\x8d\xf9\x78\x65\x4e\xd5\x2c\x71" + "\x17\x5c\x12\x4e\xb3\xa5\x6e\xfa\xfe\x64\x77\xd8\x05\x07\x4d\xd0\x29\x15" + "\x65\x37\x4b\xb1\x02\x8c\x9b\xbd\x59\xd6\x4d\x56\x27\xe7\x28\x02\x5a\x30" + "\x59\x10\x0f\x48\xe8\x88\x5f\x7f\xe4\x4e\x0d\xec\xbb\x7b\x98\x08\x3d\x85" + "\xe1\xc8\x2b\x11\x8a\x8a\xf5\xb3\x8f\x33\xb3\xb6\x7b\xa6\xd5\x8e\x58\xc1" + "\x3a\xff\xaf\x8c\x2b\x99\x9d\x4f\xc2\x09\xed\x73\x7a\x04\x74\x93\x48\x1b" + "\xfa\xfd\x71\x9d\x49\x8d\xf0\xa9\x8c\x6f\x43\x48\xc7\x24\x3a\xa6\x78\x9a" + "\xf3\x36\x85\x4b\x7e\x87\xf9\x5a\x05\x47\xcf\x73\x5e\xc3\x83\xa8\x27\x4d" + "\xdc\xf5\xd9\x76\x43\x85\x37\x36\xb4\xc6\x06\x3f\x48\x95\xab\x38\x38\xc9" + "\x99\x9c\xec\x7b\x73\x1c\xda\xcb\xd5\x0f\x8c\x06\xde\x9f\xe8\x0a\xad\xaf" + "\x91\xd1\x1b\x9a\x35\xaa\xdf\x41\xa0\x5c\x6b\xae\xda\x0c\x6d\x00\xb4\xa8" + "\xc0\xc3\x69\xf9\x8f\x4c\x6e\x6a\x97\x76\xab\x41\x7e\x28\x39\x1b\x47\x5c" + "\xe7\xfc\x01\x65\xdb\xe4\x9e\xf9\x89\x1f\x9c\xef\x82\xe2\x86\x7e\xd6\xd6" + "\x7c\x4a\x5a\x71\xda\xa1\xf7\x5d\x26\x5f\x85\x92\xa8\x1d\xb4\x8c\xbc\x92" + "\xc3\x82\xd6\x3a\x96\xf5\x80\x0f\xa8\xec\xa9\xe2\x02\x7b\xaf\xb7\x4b\xc9" + "\xe3\x3b\xdc\xd3\xb8\xf4\xd8\xe0\x5f\x36\xdd\xa5\x44\xf8\x97\x5e\xcb\xea" + "\x47\x8d\xb8\x36\x61\xa1\xdb\xc5\xfc\xcb\x7f\xeb\x05\x57\xde\xd7\x3a\x37" + "\x90\xc3\x52\x69\xfa\x59\xe4\x75\x0e\x55\xc7\x29\xa0\x08\xc9\x8c\xe9\xee" + "\x88\x82\xe0\xc2\xae\xaf\x1e\xbe\x40\x3b\xe9\x6d\xaa\x25\xb4\x2a\xc0\x1b" + "\x6a\xd4\x35\x5b\xc3\x60\xcd\xd1\x31\x10\xe3\xff\xc7\x6a\xb4\x51\xf5\x9e" + "\x04\xa8\xab\x3f\x1a\x4a\x69\xdf\x21\x91\xab\x4b\x60\xfd\x31\x76\x13\x2b" + "\x8f\x99\x1d\x3a\xb2\x96\xa0\x36\x93\x36\xb5\x35\xaa\xcc\x15\x97\x7d\x50" + "\x5b\xe2\xc5\xd4\xb6\xb7\xbc\x55\xd8\x3c\xd1\x7c\x1e\x80\x35\x7f\x4a\x21" + "\x8d\x72\x93\x3f\xa6\x09\x74\x73\x29\x6d\x7d\xdc\x30\xd7\xa1\x7b\x73\x23" + "\xac\x17\x3e\xc3\x47\x72\x45\x1a\xa6\x70\x95\xca\xcf\xbc\x87\x6c\x05\x56" + "\xa7\xae\x2f\x2c\x64\x55\x50\xd8\xab\x05\xe6\xa7\x87\xa5\x5a\x1c\x0c\xe1" + "\x59\x7b\x95\x8e\xe7\xea\xff\x10\x29\x93\x02\xd9\x9c\x35\xca\xc9\x83\xb9" + "\x6c\x0f\xec\xaf\x61\x59\x3a\x17\x66\xd3\xbc\xc7\xc2\xd5\x00\x4a\x4c\x43" + "\x91\xcb\x41\xb1\x36\x79\x35\xe3\x9d\x73\xf3\xa2\xe0\x84\x59\xd2\x83\x2c" + "\x18\x34\xf2\x60\x6a\x87\x40\x10\xd7\xcf\x17\x7e\x7b\xcf\x61\xad\x41\x3d" + "\x0f\xfc\xe3\x3d\x6b\xef\x39\xb9\x61\x39\xda\x24\xaf\xc9\xac\xe7\x94\x28" + "\x8d\x79\x75\xac\x74\xc9\x86\x66\x1d\x40\x34\x42\x25\xf7\x99\xf5\x96\x35" + "\xa9\x1f\x98\x7b\x54\x42\x3a\x5e\x10\x60\x9b\x6d\x8e\xb4\xda\xe5\xc2\xc8" + "\x2e\x53\xae\xc3\xa3\xdd\xe5\xaf\xbf\x06\x2c\x42\xe2\x95\x91\xd9\x3e\x49" + "\xe4\x54\x80\x90\xb5\x22\x7e\x13\xda\x62\x70\x14\x7e\x5d\x9d\xee\x3f\x2e" + "\x8d\x2f\x7d\xe0\xaf\x1d\xd7\x61\x27\x9d\xd3\xf2\x8a\xce\x13\x74\x73\x15" + "\x11\xf2\x1a", + .payloadLen = 903, + .maxPlaintextLen = 98, + .plaintextLen = 41, + }, +}; + +typedef struct aes128gcm_err_decrypt_test_s { + const char* desc; + const char* ikm; + const char* payload; + size_t payloadLen; + size_t maxPlaintextLen; + int err; +} aes128gcm_err_decrypt_test_t; + +static aes128gcm_err_decrypt_test_t aes128gcm_err_decrypt_tests[] = { + { + .desc = "Truncated ciphertext, rs = 18", + .ikm = "\x28\xc0\x66\x11\x4a\x2d\xa5\x21\xca\x89\xf4\x21\x9d\xa8\xac\xc0", + .payload = "\x1f\xc2\xec\x59\x4d\xbd\xa8\xc8\xab\x26\x25\x47\x04\x65\xb8" + "\xcd\x00\x00\x00\x12\x00\x92\x56\xfe\x1c\x43\x4f\x71\x8e\x85" + "\x16\x3a\x0f\x52\x69\xc1\xb8\x24\x55", + .payloadLen = 40, + .maxPlaintextLen = 0, + .err = ECE_ERROR_DECRYPT, + }, + { + .desc = "rs <= block overhead", + .ikm = "\x2f\xb1\x75\xc2\x71\xb9\x2f\x6b\x55\xe4\xf2\xa2\x52\xd1\x45\x43", + .payload = "\x76\xf9\x1d\x48\x4e\x84\x91\xda\x55\xc5\xf7\xbf\xe6\xd3\x3e" + "\x89\x00\x00\x00\x02\x00", + .payloadLen = 21, + .maxPlaintextLen = 0, + .err = ECE_ERROR_INVALID_RS, + }, + { + .desc = "Zero plaintext", + .ikm = "\x64\xc7\x0e\x64\xa7\x25\x55\x14\x51\xf2\x08\xdf\xba\xa0\xb9\x72", + .payload = "\xaa\xd2\x05\x7d\x33\x53\xb7\xff\x37\xbd\xe4\x2a\xe1\xd5\x0f" + "\xda\x00\x00\x00\x20\x00\xbb\xc7\xb9\x65\x76\x0b\xf0\x66\x2b" + "\x93\xf4\xe5\xd6\x94\xb7\x65\xf0\xcd\x15\x9b\x28\x01\xa5", + .payloadLen = 44, + .maxPlaintextLen = 7, + .err = ECE_ERROR_ZERO_PLAINTEXT, + }, + { + .desc = "Bad early padding delimiter", + .ikm = "\x64\xc7\x0e\x64\xa7\x25\x55\x14\x51\xf2\x08\xdf\xba\xa0\xb9\x72", + .payload = "\xaa\xd2\x05\x7d\x33\x53\xb7\xff\x37\xbd\xe4\x2a\xe1\xd5\x0f" + "\xda\x00\x00\x00\x20\x00\xb9\xc7\xb9\x65\x76\x0b\xf0\x9e\x42" + "\xb1\x08\x43\x38\x75\xa3\x06\xc9\x78\x06\x0a\xfc\x7c\x7d\xe9" + "\x52\x85\x91\x8b\x58\x02\x60\xf3\x45\x38\x7a\x28\xe5\x25\x66" + "\x2f\x48\xc1\xc3\x32\x04\xb1\x95\xb5\x4e\x9e\x70\xd4\x0e\x3c" + "\xf3\xef\x0c\x67\x1b\xe0\x14\x49\x7e\xdc", + .payloadLen = 85, + .maxPlaintextLen = 32, + .err = ECE_ERROR_DECRYPT_PADDING, + }, + { + .desc = "Bad final padding delimiter", + .ikm = "\x64\xc7\x0e\x64\xa7\x25\x55\x14\x51\xf2\x08\xdf\xba\xa0\xb9\x72", + .payload = "\xaa\xd2\x05\x7d\x33\x53\xb7\xff\x37\xbd\xe4\x2a\xe1\xd5\x0f" + "\xda\x00\x00\x00\x20\x00\xba\xc7\xb9\x65\x76\x0b\xf0\x9e\x42" + "\xb1\x08\x4a\x69\xe4\x50\x1b\x8d\x49\xdb\xc6\x79\x23\x4d\x47" + "\xc2\x57\x16", + .payloadLen = 48, + .maxPlaintextLen = 11, + .err = ECE_ERROR_DECRYPT_PADDING, + }, + { + .desc = "Invalid auth tag", + .ikm = "\x64\xc7\x0e\x64\xa7\x25\x55\x14\x51\xf2\x08\xdf\xba\xa0\xb9\x72", + .payload = "\xaa\xd2\x05\x7d\x33\x53\xb7\xff\x37\xbd\xe4\x2a\xe1\xd5\x0f" + "\xda\x00\x00\x00\x20\x00\xbb\xc6\xb1\x1d\x46\x3a\x7e\x0f\x07" + "\x2b\xbe\xaa\x44\xe0\xd6\x2e\x4b\xe5\xf9\x5d\x25\xe3\x86\x71" + "\xe0\x7d", + .payloadLen = 47, + .maxPlaintextLen = 10, + .err = ECE_ERROR_DECRYPT, + }, + { + // 2 records; last record is "\x00" without a delimiter. + .desc = "rs = 21, truncated padding for last record", + .ikm = "\x1a\x5c\x05\x64\x16\xdf\x83\x73\x87\x51\x01\xd1\x11\x98\x47\x83", + .payload = "\x53\x06\xdc\x45\xdd\x8e\x51\x00\x16\x53\x3c\x1e\xba\xe5\x50" + "\x53\x00\x00\x00\x15\x00\xa7\x0d\x92\x4e\xe6\x08\xd0\xc1\xc1" + "\x00\x88\x5a\xe8\x78\x1d\xd1\x47\x67\x02\x12\x63\xf7\x9d\x22" + "\xa9\x44\x8d\xb2\x33\x6e\xe0\xe5\x72\xe2\x3c\x38\x49\x70", + .payloadLen = 59, + .maxPlaintextLen = 6, + .err = ECE_ERROR_ZERO_PLAINTEXT, + }, + { + // 2 records; last record is just the auth tag. + .desc = "rs = 21, auth tag for last record", + .ikm = "\xc1\xc9\xc0\x91\x9d\x81\x0a\xe7\xd9\xe8\x0c\x45\xbc\x21\xa9\xfa", + .payload = "\xc1\xaf\x29\x07\x6f\x69\x25\x60\xde\x6d\x1f\xde\x02\x11\x69" + "\x79\x00\x00\x00\x15\x00\x46\x9f\xde\x73\xa7\x8a\x2a\x66\x1d" + "\xb0\xf1\xae\x55\xec\xec\x86\x6a\xaa\xe5\xf3\x04\xa3\x3e\xc3" + "\xb0\xbb\x16\xe9\x0a\xab\xc4\xba\xe0\xed\xbb\x73\x46", + .payloadLen = 58, + .maxPlaintextLen = 5, + .err = ECE_ERROR_SHORT_BLOCK, + }, +}; + +void +test_webpush_aes128gcm_decrypt_ok(void) { + size_t tests = sizeof(webpush_aes128gcm_decrypt_ok_tests) / + sizeof(webpush_aes128gcm_decrypt_ok_test_t); + for (size_t i = 0; i < tests; i++) { + webpush_aes128gcm_decrypt_ok_test_t t = + webpush_aes128gcm_decrypt_ok_tests[i]; + + const void* recvPrivKey = t.recvPrivKey; + const void* authSecret = t.authSecret; + const void* payload = t.payload; + + size_t plaintextLen = + ece_aes128gcm_plaintext_max_length(payload, t.payloadLen); + ece_assert(plaintextLen == t.maxPlaintextLen, + "Got plaintext max length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.maxPlaintextLen); + + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + + int err = ece_webpush_aes128gcm_decrypt( + recvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, payload, t.payloadLen, plaintext, + &plaintextLen); + ece_assert(!err, "Got %d decrypting payload for `%s`", err, t.desc); + + ece_assert(plaintextLen == t.plaintextLen, + "Got plaintext length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.plaintextLen); + ece_assert(!memcmp(plaintext, t.plaintext, plaintextLen), + "Wrong plaintext for `%s`", t.desc); + + free(plaintext); + } +} + +void +test_webpush_aes128gcm_decrypt_err(void) { + size_t tests = sizeof(webpush_aes128gcm_err_decrypt_tests) / + sizeof(webpush_aes128gcm_err_decrypt_test_t); + for (size_t i = 0; i < tests; i++) { + webpush_aes128gcm_err_decrypt_test_t t = + webpush_aes128gcm_err_decrypt_tests[i]; + + const void* recvPrivKey = t.recvPrivKey; + const void* authSecret = t.authSecret; + const void* payload = t.payload; + + size_t plaintextLen = + ece_aes128gcm_plaintext_max_length(payload, t.payloadLen); + ece_assert(plaintextLen == t.maxPlaintextLen, + "Got plaintext max length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.maxPlaintextLen); + + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + + int err = ece_webpush_aes128gcm_decrypt( + recvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, payload, t.payloadLen, plaintext, + &plaintextLen); + ece_assert(err == t.err, "Got %d decrypting payload for `%s`; want %d", err, + t.desc, t.err); + + free(plaintext); + } +} + +void +test_aes128gcm_decrypt_ok(void) { + size_t tests = + sizeof(aes128gcm_ok_decrypt_tests) / sizeof(aes128gcm_ok_decrypt_test_t); + for (size_t i = 0; i < tests; i++) { + aes128gcm_ok_decrypt_test_t t = aes128gcm_ok_decrypt_tests[i]; + + size_t plaintextLen = ece_aes128gcm_plaintext_max_length( + (const uint8_t*) t.payload, t.payloadLen); + ece_assert(plaintextLen == t.maxPlaintextLen, + "Got plaintext max length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.maxPlaintextLen); + + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + + int err = ece_aes128gcm_decrypt((const uint8_t*) t.ikm, 16, + (const uint8_t*) t.payload, t.payloadLen, + plaintext, &plaintextLen); + ece_assert(!err, "Got %d decrypting payload for `%s`", err, t.desc); + + ece_assert(plaintextLen == t.plaintextLen, + "Got plaintext length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.plaintextLen); + ece_assert(!memcmp(plaintext, t.plaintext, plaintextLen), + "Wrong plaintext for `%s`", t.desc); + + free(plaintext); + } +} + +void +test_aes128gcm_decrypt_err(void) { + size_t tests = + sizeof(aes128gcm_err_decrypt_tests) / sizeof(aes128gcm_err_decrypt_test_t); + for (size_t i = 0; i < tests; i++) { + aes128gcm_err_decrypt_test_t t = aes128gcm_err_decrypt_tests[i]; + + const void* ikm = t.ikm; + const void* payload = t.payload; + + size_t plaintextLen = + ece_aes128gcm_plaintext_max_length(payload, t.payloadLen); + ece_assert(plaintextLen == t.maxPlaintextLen, + "Got plaintext max length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.maxPlaintextLen); + + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + + int err = ece_aes128gcm_decrypt(ikm, 16, payload, t.payloadLen, plaintext, + &plaintextLen); + ece_assert(err == t.err, "Got %d decrypting payload for `%s`; want %d", err, + t.desc, t.err); + + free(plaintext); + } +} diff --git a/mobile/ios/ThirdParty/ecec/test/decrypt/aesgcm.c b/mobile/ios/ThirdParty/ecec/test/decrypt/aesgcm.c new file mode 100644 index 0000000000..fe641a64ab --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/decrypt/aesgcm.c @@ -0,0 +1,306 @@ +#include "test.h" + +#include + +typedef struct webpush_aesgcm_decrypt_ok_test_s { + const char* desc; + const char* plaintext; + const char* recvPrivKey; + const char* authSecret; + const char* ciphertext; + const char* cryptoKey; + const char* encryption; + size_t ciphertextLen; + size_t maxPlaintextLen; + size_t plaintextLen; +} webpush_aesgcm_decrypt_ok_test_t; + +typedef struct webpush_aesgcm_decrypt_err_test_s { + const char* desc; + const char* recvPrivKey; + const char* authSecret; + const char* ciphertext; + const char* cryptoKey; + const char* encryption; + size_t maxPlaintextLen; + size_t ciphertextLen; + int err; +} webpush_aesgcm_decrypt_err_test_t; + +static webpush_aesgcm_decrypt_ok_test_t webpush_aesgcm_decrypt_ok_tests[] = { + { + .desc = "rs = 24, pad = 0", + .plaintext = "Some message", + .recvPrivKey = "\xe2\x1d\xb7\x1b\xf2\xa4\x5c\x2f\x53\xbc\x14\x8a\xda\xfd" + "\x10\xec\x89\xa9\x4b\x66\x00\xb9\x17\x7c\x85\x0c\x8d\xd2" + "\xb1\x40\xc0\x18", + .authSecret = + "\x69\x30\xdc\xe8\x97\x9b\xcd\x1e\x9e\x49\xcc\xb6\xa0\xba\x38\x45", + .ciphertext = "\x3a\x8d\xf8\xc3\x61\x7d\x55\x59\xd3\x30\x57\xca\xb5\xdc" + "\x78\xf0\x06\x56\x43\xd2\xe2\xf4\xce\x83\x6a\xe5\x89\x56" + "\x05\xd4", + .cryptoKey = "dh=" + "BCHFVrflyxibGLlgztLwKelsRZp4gqX3tNfAKFaxAcBhpvYeN1yIUMrxa" + "DKiLh4LNKPtj0BOXGdr-IQ-QP82Wjo", + .encryption = "salt=zCU18Rw3A5aB_Xi-vfixmA; rs=24", + .ciphertextLen = 30, + .maxPlaintextLen = 14, + .plaintextLen = 12, + }, + { + .desc = "rs = 8, pad = 16", + .plaintext = "Yet another message", + .recvPrivKey = "\xe2\x1d\xb7\x1b\xf2\xa4\x5c\x2f\x53\xbc\x14\x8a\xda\xfd" + "\x10\xec\x89\xa9\x4b\x66\x00\xb9\x17\x7c\x85\x0c\x8d\xd2" + "\xb1\x40\xc0\x18", + .authSecret = + "\xea\x99\x70\x66\x74\xa9\x55\x46\xc5\xec\x03\xc3\x5e\xeb\x37\x51", + .ciphertext = + "\xb8\x40\xb9\x07\xfb\x51\xf9\xfb\x90\xdd\xd7\xa5\x41\xca\xf3\xac\x30" + "\xa9\xe3\x45\xba\x8a\x93\x19\x8c\x66\x7b\xf1\x44\x83\x27\x9b\x0c\x8f" + "\xee\x9b\x00\xe5\x46\xdc\x02\xba\x26\xa1\x65\xf4\x4e\x80\xa1\x68\x81" + "\x61\x8b\xcc\x65\xfc\x13\x85\x5c\x66\x0e\x7c\x3a\x44\x7b\x55\x78\xb2" + "\x85\x33\x90\xd6\x82\x5d\x44\xc2\x43\xa8\x87\x01\xf6\x12\x18\x83\x0f" + "\x48\x0c\xde\x2a\x3e\x77\xbf\x56\x2b\x33\x8f\x64\x4f\x6b\x0d\x65\x12" + "\xbf\xae\x09\xb2\xd2\x26\x49\xf5\xff\x00\x34\x1f\x00\x1a\xef\x6d\x99" + "\x1e\x69\x6c\x61\xe7\x71\x06\xe7\xd4\x0c\x38\x49\x45\x26\xa1\xee\x7b" + "\x87\x4c\x51\x1a\x6c\x31\x78", + .cryptoKey = "dh=BEaA4gzA3i0JDuirGhiLgymS4hfFX7TNTdEhSk_" + "HBlLpkjgCpjPL5c-GL9uBGIfa_fhGNKKFhXz1k9Kyens2ZpQ", + .encryption = "salt=ZFhzj0S-n29g9P2p4-I7tA; rs=8", + .ciphertextLen = 143, + .maxPlaintextLen = 47, + .plaintextLen = 19, + }, + { + .desc = "rs = 3, pad = 0", + .plaintext = "Small record size", + .recvPrivKey = "\xe2\x1d\xb7\x1b\xf2\xa4\x5c\x2f\x53\xbc\x14\x8a\xda\xfd" + "\x10\xec\x89\xa9\x4b\x66\x00\xb9\x17\x7c\x85\x0c\x8d\xd2" + "\xb1\x40\xc0\x18", + .authSecret = + "\x83\x6a\xd6\x54\x75\x02\xa5\x4c\x60\x70\xbf\x53\xcf\xbb\xf2\x79", + .ciphertext = + "\xa1\x8e\x1e\xe5\xe0\xda\xb4\x35\x6d\xd9\xfa\x50\xca\x5c\x5b\x3c\x93" + "\x3e\xde\xfa\xdf\x84\x36\xac\x7c\xf7\x3c\x43\x53\xd6\xb7\x8b\x4f\x7c" + "\xc5\x5b\xcf\xfb\x03\x34\xbf\xdc\xbe\xbd\x03\x5d\x79\x1d\x17\x34\xb5" + "\x97\x1b\x09\xb2\x3e\x79\xd1\x44\xb1\xe0\xc3\x25\xd3\x58\xa1\x8c\x89" + "\x97\x0a\x3a\xf0\xf5\x1e\x71\x16\x01\x6b\x08\x0a\x89\x0f\x71\xb0\x5c" + "\x0d\x6f\xcd\x2e\x13\xe7\x2b\xc6\x55\xb5\x29\xdd\x29\xdd\x30\x37\x53" + "\xd4\xe0\x9c\x12\x87\xd3\x9f\xb5\x42\xeb\x16\x7e\xcc\xff\x2b\xcd\x24" + "\x1f\x0c\x20\x41\xc6\x63\xd4\xec\xe2\x12\xce\xbf\x19\xe0\x7c\xb3\x14" + "\x21\x89\x78\x17\xea\x89\x9e\xf2\x51\xf3\x65\x28\x5d\x71\xe5\x46\x99" + "\xe1\x7e\xa2\x53\xf4\xd7\xc7\x92\xa5\x43\x2f\xed\xa1\x5d\x5d\x5d\x9d" + "\x9e\x10\x03\x07\x25\x47\x12\x74\x0a\xef\x07\xac\xd1\xa4\x57\x44\x23" + "\x17\x5c\x1d\xc2\x72\xa3\x50\x48\x62\x00\x18\x4c\x37\x40\x23\x2f\xff" + "\x20\x95\x42\x3d\x8f\xdb\xd8\x21\x39\x5b\xfe\xa8\x86\x56\x0a\x07\xbc" + "\x43\xc8\x7f\x20\x88\xdb\x96\x59\x70\x20\x06\x8c\xd4\x7d\x27\x0b\x51" + "\x58\xcf\x0b\x7f\x32\x25\x3a\x40\x52\x2e\xb0\xea\x95\xe0\x5d\x45\x9f" + "\x7d\xe9\xdd\x7b\x91\x6b\x79\x0a\x67\x30\x52\xf5\x2f\x81\xbe\xdf\xcc" + "\x2c\x23\xff\x88\x48\x83\xb3\x74\xef\x10\x22\xb5\xc7\xc6\x6b\x5c\xd5" + "\x2e\x71\xcd\x8b\xbc\x6c\xca\x92\x80\x28\xa7\xbc\x21\x30\x75\xe1\x85" + "\x0a\x68\xa0\x85\x18\xe3\xf2\xdd\x73\x45\x6a\x34\x0f\x5e\x2b\x1d\xb4" + "\x0b\x3d\x1f\xdb\xd4\xfe\x52\xbc\x47\x89\x4e\xd4\xbd\x36\x6d\xe2\x89" + "\xb3", + .cryptoKey = "dh=BCg6ZIGuE2ZNm2ti6Arf4CDVD_8--" + "aLXAGLYhpghwjl1xxVjTLLpb7zihuEOGGbyt8Qj0_" + "fYHBP4ObxwJNl56bk", + .encryption = "salt=5LIDBXbvkBvvb7ZdD-T4PQ; rs=3", + .ciphertextLen = 341, + .maxPlaintextLen = 53, + .plaintextLen = 17, + }, + { + .desc = "Example from draft-ietf-httpbis-encryption-encoding-02", + .plaintext = "I am the walrus", + .recvPrivKey = "\xf4\x55\xa5\xd7\x9f\xd0\x51\x00\x16\x0d\xa0\xf7\x93\x79" + "\x79\xd1\x90\x59\x40\x9e\x1a\xbb\x6e\xc5\xd5\x5e\x05\xd2" + "\xe2\xd2\x0f\xf3", + .authSecret = + "\x47\x6f\x6f\x20\x67\x6f\x6f\x20\x67\x27\x20\x6a\x6f\x6f\x62\x21", + .ciphertext = "\xea\x7a\x80\x41\x43\x04\xf2\x13\x6a\xc3\x92\x77\x92\x5f" + "\x1c\xa5\x55\x49\xca\x55\xca\x62\xa6\x4e\x7a\xc7\x99\x1b" + "\xc5\x2e\x78\xaa\x40", + .cryptoKey = "keyid=\"dhkey\"; " + "dh=" + "\"BNoRDbb84JGm8g5Z5CFxurSqsXWJ11ItfXEWYVLE85Y7CYkDjXsIEc4" + "aqxYaQ1G8BqkXCJ6DPpDrWtdWj_mugHU\"", + .encryption = "keyid=\"dhkey\"; salt=\"lngarbyKfMoi9Z75xYXmkg\"", + .ciphertextLen = 33, + .maxPlaintextLen = 17, + .plaintextLen = 15, + }, +}; + +static webpush_aesgcm_decrypt_err_test_t webpush_aesgcm_decrypt_err_tests[] = { + { + .desc = "rs = 7, no trailer", + .recvPrivKey = "\xd9\xbb\xb8\xa5\xa3\x80\x65\xb2\xf6\x79\xfd\x6e\xfb\x04" + "\xf3\x38\xdb\x93\x21\xc0\xcf\x73\x4d\x28\xd3\x35\x09\x82" + "\x0e\x3a\x5d\x37", + .authSecret = + "\x42\x80\xe2\xd2\xee\xaf\x72\xc9\x48\x54\x92\xa2\xa2\xe5\xcc\x5f", + // "O hai". The ciphertext is exactly `rs + 16`, without a trailer. + .ciphertext = "\x60\x6e\x05\xf9\xbd\x3a\xcb\x9f\x74\x85\x19\x67\x4a\xcc\x3f" + "\xbe\xe3\xb0\xeb\x65\x7d\x23\x3f", + .cryptoKey = "dh=BD_" + "bsTUpxBMvSv8eksith3vijMLj44D4jhJjO51y7wK1ytbUlsyYBBYYyB5AAe5b" + "nREA_WipTgemDVz00LiWcfM", + .encryption = "salt=xKWvs_jWWeg4KOsot_uBhA; rs=7", + .ciphertextLen = 23, + .maxPlaintextLen = 7, + .err = ECE_ERROR_DECRYPT_TRUNCATED, + }, + { + // Last block is only 1 byte; pad length prefix is 2 bytes. + .desc = "Pad size > last block length", + .recvPrivKey = "\x0a\x8b\x04\x44\x05\x57\x82\xf4\xef\xa2\x1e\xd4\x92\xb4" + "\x42\xd9\x5f\xa2\x5e\x83\x6c\xd1\xb5\xe5\x7b\xd2\x3a\xf2" + "\xac\xe4\x95\xeb", + .authSecret = + "\x42\xd1\x99\x79\x8f\x0c\x41\xf0\x9a\xab\xe5\xf0\x28\xe5\x46\x05", + .ciphertext = "\x26\xf5\xfd\x1e\xc2\x78\x94\xbe\x60\xcc\xff\x3f\xb8\x22\x9c" + "\xea\xcd\x79\x89\x12\x1a\x36\x10\xf8\xa4\x50\xa0\xab\x9f\x9d" + "\x7f\x06\xd4\xa8\x47\x0d\x52\x4a\xaf", + .cryptoKey = "dh=BBNZNEi5Ew_ID5S4Y9jWBi1NeVDje6Mjs7SDLViUn6A8VAZj-" + "6X3QAuYQ3j20BblqjwTgYst7PRnY6UGrKyLbmU", + .encryption = "salt=ot8hzbwOo6CYe6ZhdlwKtg; rs=6", + .ciphertextLen = 39, + .maxPlaintextLen = 7, + .err = ECE_ERROR_DECRYPT_PADDING, + }, + { + // Last block is 1 byte, but claims its pad length is 2. + .desc = "Padding length > last block length", + .recvPrivKey = "\xf6\x5f\x9a\x85\xc0\x4c\xf8\x8d\x32\x93\x06\xd6\x88\x34" + "\xbd\x29\x1a\xcf\x76\x1c\xaf\x4d\x9d\x12\xc4\xa8\x8f\xa6" + "\x3d\x9a\x79\xa2", + .authSecret = + "\x80\xa1\xbf\x3f\xaf\x9d\x7b\x9a\x72\xcd\x2f\x21\xc8\x7f\xcd\xc9", + .ciphertext = "\xa1\x64\x8e\x14\x0f\x94\x3b\x9a\x16\xab\xe9\x08\xef\xd4\x47" + "\x68\x57\xf0\x01\xe8\xcb\x89\x02\x78\x0b\xb7\x93\x9a\xb4\x93" + "\x06\x5e\x20\x02\xb2\xd7\x7f\x1e\xe5\x67\xe6", + .cryptoKey = "dh=BKe2IBO_cwmEzQyTVscSbQcj0Y3uBSzGZ_mHlANMciS8uGpb7U8_" + "Bw7TNdlYfpwWDLd0cxM8YYWNDbNJ_p2Rp4o", + .encryption = "salt=z7QJ6UR89SiFRkd4RsC4Vg; rs=6", + .ciphertextLen = 41, + .maxPlaintextLen = 9, + .err = ECE_ERROR_DECRYPT_PADDING, + }, + { + // First block has no padding, but claims its pad length is 1. + .desc = "Non-zero padding", + .recvPrivKey = "\x23\x3b\x9a\xc4\xba\x85\x26\x68\xd2\xbb\xc1\xa3\x2c\x2a" + "\x36\xa0\x46\x83\x66\x30\xc1\xba\xd5\xb8\x9b\x84\xf4\xab" + "\x1d\x36\x5e\xc3", + .authSecret = + "\x70\xca\x56\x41\x6e\x7c\x06\xba\x43\x6c\x9f\x0a\xa9\xb4\xbd\x8a", + .ciphertext = "\x41\xdb\xe3\x87\x42\xe4\x65\x72\xae\xff\x51\xef\xbf\x9e\x83" + "\xd2\xb3\x92\x17\xa3\x30\xc3\x7c\xb4\x17\xcc\x64\xc5\x43\x65" + "\xc1\x5b\xb6\x53\x58\x9a\x90\xe5\x14\x19\x1b", + .cryptoKey = "dh=BBicj01QI0ryiFzAaty9VpW_crgq9XbU1bOCtEZI9UNE6tuOgp4lyN_" + "UN0N905ECnLWK5v_sCPUIxnQgOuCseSo", + .encryption = "salt=SbkGHONbQBBsBcj9dLyIUw; rs=6", + .ciphertextLen = 41, + .maxPlaintextLen = 9, + .err = ECE_ERROR_DECRYPT_PADDING, + }, + { + .desc = "rs = 6, auth tag for last record", + .recvPrivKey = "\x9e\x13\x93\xf7\x5e\xf5\xc6\xea\x10\x04\x91\xa4\x89\x9d" + "\xda\xa9\x3e\x6a\xc3\xf2\x0b\x27\xde\x3f\x3c\xf8\x95\x36" + "\xed\x4b\x15\x26", + .authSecret = + "\xde\xb5\xa1\xb1\x10\x94\xfc\xa7\x5a\xa9\xf2\x8f\x6d\xdd\xf3\x05", + .ciphertext = "\x0b\xbb\xb7\x8f\x90\x0b\xe1\x8c\xe1\xdb\x26\x01\xfe\xe9\x8d" + "\xea\xdc\xeb\x54\x7c\x6b\xb7\xb0\xf9\x6d\xa4\xc4\x5b\xd0\xc4" + "\xd4\x19\x37\xba\x9f\x5f\x63\x8c", + .cryptoKey = "dh=BI38Qs_OhDmQIxbszc6Nako-MrX3FzAE_8HzxM1wgoEIG4ocxyF-" + "YAAVhfkpJUvDpRyKW2LDHIaoylaZuxQfRhE", + .encryption = "salt=QClh48OlvGpSjZ0Mg0e8rg; rs=6", + .ciphertextLen = 38, + .maxPlaintextLen = 6, + .err = ECE_ERROR_SHORT_BLOCK, + }, +}; + +void +test_webpush_aesgcm_decrypt_ok(void) { + size_t length = sizeof(webpush_aesgcm_decrypt_ok_tests) / + sizeof(webpush_aesgcm_decrypt_ok_test_t); + for (size_t i = 0; i < length; i++) { + webpush_aesgcm_decrypt_ok_test_t t = webpush_aesgcm_decrypt_ok_tests[i]; + + const void* recvPrivKey = t.recvPrivKey; + const void* authSecret = t.authSecret; + const void* ciphertext = t.ciphertext; + + uint8_t salt[ECE_SALT_LENGTH]; + uint8_t rawSenderPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; + uint32_t rs; + int err = ece_webpush_aesgcm_headers_extract_params( + t.cryptoKey, t.encryption, salt, ECE_SALT_LENGTH, rawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, &rs); + ece_assert(!err, "Got %d parsing crypto headers", err); + + size_t plaintextLen = ece_aesgcm_plaintext_max_length(rs, t.ciphertextLen); + ece_assert(plaintextLen == t.maxPlaintextLen, + "Got plaintext max length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.maxPlaintextLen); + + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + + err = ece_webpush_aesgcm_decrypt( + recvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, rawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, rs, ciphertext, t.ciphertextLen, plaintext, + &plaintextLen); + ece_assert(!err, "Got %d decrypting ciphertext for `%s`", err, t.desc); + + ece_assert(plaintextLen == t.plaintextLen, + "Got plaintext length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.plaintextLen); + ece_assert(!memcmp(plaintext, t.plaintext, plaintextLen), + "Wrong plaintext for `%s`", t.desc); + + free(plaintext); + } +} + +void +test_webpush_aesgcm_decrypt_err(void) { + size_t tests = sizeof(webpush_aesgcm_decrypt_err_tests) / + sizeof(webpush_aesgcm_decrypt_err_test_t); + for (size_t i = 0; i < tests; i++) { + webpush_aesgcm_decrypt_err_test_t t = webpush_aesgcm_decrypt_err_tests[i]; + + const void* recvPrivKey = t.recvPrivKey; + const void* authSecret = t.authSecret; + const void* ciphertext = t.ciphertext; + + uint8_t salt[ECE_SALT_LENGTH]; + uint8_t rawSenderPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; + uint32_t rs; + int err = ece_webpush_aesgcm_headers_extract_params( + t.cryptoKey, t.encryption, salt, ECE_SALT_LENGTH, rawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, &rs); + ece_assert(!err, "Got %d parsing crypto headers", err); + + size_t plaintextLen = ece_aesgcm_plaintext_max_length(rs, t.ciphertextLen); + ece_assert(plaintextLen == t.maxPlaintextLen, + "Got plaintext max length %zu for `%s`; want %zu", plaintextLen, + t.desc, t.maxPlaintextLen); + + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + + err = ece_webpush_aesgcm_decrypt( + recvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, rawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, rs, ciphertext, t.ciphertextLen, plaintext, + &plaintextLen); + ece_assert(err == t.err, "Got %d decrypting ciphertext for `%s`; want %d", + err, t.desc, t.err); + + free(plaintext); + } +} diff --git a/mobile/ios/ThirdParty/ecec/test/e2e.c b/mobile/ios/ThirdParty/ecec/test/e2e.c new file mode 100644 index 0000000000..4acdf251aa --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/e2e.c @@ -0,0 +1,134 @@ +#include "test.h" + +#include +#include + +void +test_webpush_aes128gcm_e2e(void) { + uint8_t rawRecvPrivKey[ECE_WEBPUSH_PRIVATE_KEY_LENGTH]; + uint8_t rawRecvPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; + uint8_t authSecret[ECE_WEBPUSH_AUTH_SECRET_LENGTH]; + int err = ece_webpush_generate_keys( + rawRecvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, rawRecvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, authSecret, ECE_WEBPUSH_AUTH_SECRET_LENGTH); + ece_assert(!err, "Got %d generating keys", err); + + const void* input = "When I grow up, I want to be a watermelon"; + size_t inputLen = strlen(input); + + size_t payloadLen = ece_aes128gcm_payload_max_length(4096, 0, inputLen); + ece_assert(payloadLen == 334, "Got %zu for payload max length; want 334", + payloadLen); + uint8_t* payload = calloc(payloadLen, sizeof(uint8_t)); + + err = ece_webpush_aes128gcm_encrypt(rawRecvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, 4096, 0, + input, inputLen, payload, &payloadLen); + ece_assert(!err, "Got %d encrypting plaintext", err); + ece_assert(payloadLen == 144, "Got %zu for payload length; want 144", + payloadLen); + + size_t plaintextLen = ece_aes128gcm_plaintext_max_length(payload, payloadLen); + ece_assert(plaintextLen == 42, "Got %zu for plaintext max length; want 42", + plaintextLen); + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + + err = ece_webpush_aes128gcm_decrypt( + rawRecvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, payload, payloadLen, plaintext, + &plaintextLen); + ece_assert(!err, "Got %d decrypting payload", err); + ece_assert(plaintextLen == inputLen, "Got %zu for plaintext length; want %zu", + plaintextLen, inputLen); + ece_assert(!memcmp(plaintext, input, inputLen), + "Got `%s` for plaintext; want `%s`", plaintext, input); + + free(payload); + free(plaintext); +} + +void +test_webpush_aesgcm_e2e(void) { + uint8_t rawRecvPrivKey[ECE_WEBPUSH_PRIVATE_KEY_LENGTH]; + uint8_t rawRecvPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; + uint8_t authSecret[ECE_WEBPUSH_AUTH_SECRET_LENGTH]; + int err = ece_webpush_generate_keys( + rawRecvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, rawRecvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, authSecret, ECE_WEBPUSH_AUTH_SECRET_LENGTH); + ece_assert(!err, "Got %d generating keys", err); + + const void* input = "If the wind in my sail on the sea stays behind me, one " + "day I'll know how far I'll go"; + size_t inputLen = strlen(input); + + size_t ciphertextLen = ece_aesgcm_ciphertext_max_length(26, 6, inputLen); + ece_assert(ciphertextLen == 162, + "Got %zu for ciphertext max length; want 162", ciphertextLen); + + uint8_t* ciphertext = calloc(ciphertextLen, sizeof(uint8_t)); + + uint8_t encryptSalt[ECE_SALT_LENGTH]; + uint8_t encryptRawSenderPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; + err = ece_webpush_aesgcm_encrypt( + rawRecvPubKey, ECE_WEBPUSH_PUBLIC_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, 26, 6, input, inputLen, encryptSalt, + ECE_SALT_LENGTH, encryptRawSenderPubKey, ECE_WEBPUSH_PUBLIC_KEY_LENGTH, + ciphertext, &ciphertextLen); + ece_assert(!err, "Got %d encrypting plaintext", err); + ece_assert(ciphertextLen == 162, "Got %zu for ciphertext length; want 162", + ciphertextLen); + + size_t cryptoKeyHeaderLen = 0; + size_t encryptionHeaderLen = 0; + err = ece_webpush_aesgcm_headers_from_params( + encryptSalt, ECE_SALT_LENGTH, encryptRawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, 14, NULL, &cryptoKeyHeaderLen, NULL, + &encryptionHeaderLen); + ece_assert(!err, "Got %d determining crypto header lengths", err); + + char* cryptoKeyHeader = malloc(cryptoKeyHeaderLen + 1); + char* encryptionHeader = malloc(encryptionHeaderLen + 1); + err = ece_webpush_aesgcm_headers_from_params( + encryptSalt, ECE_SALT_LENGTH, encryptRawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, 26, cryptoKeyHeader, &cryptoKeyHeaderLen, + encryptionHeader, &encryptionHeaderLen); + ece_assert(!err, "Got %d formatting crypto headers", err); + cryptoKeyHeader[cryptoKeyHeaderLen] = '\0'; + encryptionHeader[encryptionHeaderLen] = '\0'; + + uint8_t decryptSalt[ECE_SALT_LENGTH]; + uint8_t decryptRawSenderPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; + uint32_t rs; + err = ece_webpush_aesgcm_headers_extract_params( + cryptoKeyHeader, encryptionHeader, decryptSalt, ECE_SALT_LENGTH, + decryptRawSenderPubKey, ECE_WEBPUSH_PUBLIC_KEY_LENGTH, &rs); + ece_assert(!err, "Got %d extracting crypto params", err); + ece_assert(!memcmp(encryptSalt, decryptSalt, ECE_SALT_LENGTH), + "Wrong salt for `%s`", input); + ece_assert(!memcmp(encryptRawSenderPubKey, decryptRawSenderPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH), + "Wrong sender public key for `%s`", input); + ece_assert(rs == 26, "Got rs = %" PRIu32 "; want 26", rs); + + size_t plaintextLen = ece_aesgcm_plaintext_max_length(rs, ciphertextLen); + ece_assert(plaintextLen == 98, "Got %zu for plaintext max length; want 98", + plaintextLen); + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + + err = ece_webpush_aesgcm_decrypt( + rawRecvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, decryptSalt, ECE_SALT_LENGTH, + decryptRawSenderPubKey, ECE_WEBPUSH_PUBLIC_KEY_LENGTH, rs, ciphertext, + ciphertextLen, plaintext, &plaintextLen); + ece_assert(!err, "Got %d decrypting ciphertext", err); + ece_assert(plaintextLen == inputLen, "Got %zu for plaintext length; want %zu", + plaintextLen, inputLen); + ece_assert(!memcmp(plaintext, input, inputLen), + "Got `%s` for plaintext; want `%s`", plaintext, input); + + free(ciphertext); + free(cryptoKeyHeader); + free(encryptionHeader); + free(plaintext); +} diff --git a/mobile/ios/ThirdParty/ecec/test/encrypt/aes128gcm.c b/mobile/ios/ThirdParty/ecec/test/encrypt/aes128gcm.c new file mode 100644 index 0000000000..ad19acdea4 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/encrypt/aes128gcm.c @@ -0,0 +1,372 @@ +#include "test.h" + +#include + +#include + +typedef struct webpush_aes128gcm_encrypt_ok_test_s { + const char* desc; + const char* payload; + const char* senderPrivKey; + const char* recvPubKey; + const char* authSecret; + const char* salt; + const char* plaintext; + size_t plaintextLen; + size_t padLen; + size_t maxPayloadLen; + size_t payloadLen; + uint32_t rs; +} webpush_aes128gcm_encrypt_ok_test_t; + +static webpush_aes128gcm_encrypt_ok_test_t + webpush_aes128gcm_encrypt_ok_tests[] = { + { + .desc = "Example from draft-ietf-webpush-encryption-latest", + .payload = "\x0c\x6b\xfa\xad\xad\x67\x95\x88\x03\x09\x2d\x45\x46\x76\xf3" + "\x97\x00\x00\x10\x00\x41\x04\xfe\x33\xf4\xab\x0d\xea\x71\x91" + "\x4d\xb5\x58\x23\xf7\x3b\x54\x94\x8f\x41\x30\x6d\x92\x07\x32" + "\xdb\xb9\xa5\x9a\x53\x28\x64\x82\x20\x0e\x59\x7a\x7b\x7b\xc2" + "\x60\xba\x1c\x22\x79\x98\x58\x09\x92\xe9\x39\x73\x00\x2f\x30" + "\x12\xa2\x8a\xe8\xf0\x6b\xbb\x78\xe5\xec\x0f\xf2\x97\xde\x5b" + "\x42\x9b\xba\x71\x53\xd3\xa4\xae\x0c\xaa\x09\x1f\xd4\x25\xf3" + "\xb4\xb5\x41\x4a\xdd\x8a\xb3\x7a\x19\xc1\xbb\xb0\x5c\xf5\xcb" + "\x5b\x2a\x2e\x05\x62\xd5\x58\x63\x56\x41\xec\x52\x81\x2c\x6c" + "\x8f\xf4\x2e\x95\xcc\xb8\x6b\xe7\xcd", + .senderPrivKey = + "\xc9\xf5\x8f\x89\x81\x3e\x9f\x8e\x87\x2e\x71\xf4\x2a\xa6" + "\x4e\x17\x57\xc9\x25\x4d\xcc\x62\xb7\x2d\xdc\x01\x0b\xb4" + "\x04\x3e\xa1\x1c", + .recvPubKey = + "\x04\x25\x71\xb2\xbe\xcd\xfd\xe3\x60\x55\x1a\xaf\x1e\xd0\xf4" + "\xcd\x36\x6c\x11\xce\xbe\x55\x5f\x89\xbc\xb7\xb1\x86\xa5\x33" + "\x39\x17\x31\x68\xec\xe2\xeb\xe0\x18\x59\x7b\xd3\x04\x79\xb8" + "\x6e\x3c\x8f\x8e\xce\xd5\x77\xca\x59\x18\x7e\x92\x46\x99\x0d" + "\xb6\x82\x00\x8b\x0e", + .authSecret = + "\x05\x30\x59\x32\xa1\xc7\xea\xbe\x13\xb6\xce\xc9\xfd\xa4\x88\x82", + .salt = + "\x0c\x6b\xfa\xad\xad\x67\x95\x88\x03\x09\x2d\x45\x46\x76\xf3\x97", + .plaintext = "When I grow up, I want to be a watermelon", + .plaintextLen = 41, + .padLen = 0, + .maxPayloadLen = 334, + .payloadLen = 144, + .rs = 4096, + }, + { + .desc = "rs = 24, pad = 6", + .payload = "\xff\x80\x50\x30\xa1\x08\xe1\x14\xe6\xc1\x7f\xad\x61\x86\xa1" + "\xa6\x00\x00" + "\x00\x18\x41\x04\x30\xef\xcb\x1e\xb0\x43\xb8\x05\xe4\xe4\x4b" + "\xab\x35\xf8" + "\x25\x13\xc3\x3f\xed\xb2\x87\x00\xf7\xe5\x68\xac\x8b\x61\xe8" + "\xd8\x35\x66" + "\x5a\x51\xeb\x66\x79\xb2\xdb\x22\x8a\x10\xc0\xc3\xfe\x50\x77" + "\x06\x28\x48" + "\xd9\xbb\x3d\x60\x27\x9f\x93\xce\x35\x48\x47\x28\xaa\x1f\xd2" + "\xc1\x71\x39" + "\x49\xae\xc9\x8f\x05\x09\x6c\x72\x98\xfd\x3f\x51\xc4\xf8\x18" + "\xfa\xfa\x1f" + "\xe6\x15\xd8\x44\x7b\x3a\x05\x40\x60\x31\xf6\x40\x1a\xc2\x4f" + "\x2a\x77\x5c" + "\xa5\x24\x56\xa9\x21\xb8\x3b\x9e\x00\x42\xc3\xa6\x3e\x1a\xfa" + "\x1a\xe0\x12" + "\x77\x4d\x9d\x77\x5b\xe8\xd1\x94\x19\x45\x1d\x37\xff\x59\xff" + "\x59\x2e\x84" + "\xf0\x74\x40\xa6\x3f\xc1\x7f\x5c\xab\xcb\x9a\x50\xed\xda\xf7" + "\x53\x70\xdb" + "\x64\x7f\x94\x44\x7d\x3f\x16\x62\x69\xd8\x71\x1d\xf0\xf5\x7e" + "\x56\x04\x95" + "\x76\xe1\x13\x0a\x5a\x5e\x1f\x94\xba\x8a\x5d\x0b\x00\x07\xc6" + "\xc0\xfd\x29" + "\x98\x42\x9e\x7d\x63\xd4\xef\x91\x97\x98\xf4\x6e\xcf\x5f\x0b" + "\x28\xfb\x80" + "\xf5\xb2\x43\x9d\xe2\x6b\x8a\x52\x20\x0b\xc7\xd6\xaf\x7a\x48" + "\x40\x72\x1f" + "\xe8\xbe\x85\x24\xa6\x91\xb6\xef\x0e\xda\xe9\x0b\xb6\xf5\x92" + "\x78\x94\x81" + "\x9b\x83\x1b\x45\xb5\x3f\x84\x01\xfe\x02\x2d\xbb\x64\xed\x75" + "\x65\x35\x09" + "\x04\xac\x0b\x51\x71\x35\xd7\xf8\xab\xbc\x98\x12\x7f\xb1\x63" + "\x86\x4d\x4d" + "\x4a\x30\x74\x25\xb2\xcd\x43\xdb\x22\xaf\x26\x7d\x71\xc3\x71" + "\x46\x99\x4a" + "\x8c\x48\x05\xad\xc3\x41\xbf\xba\x27\xaf\x09\xfd\x80\xbd\x5e" + "\xff\x51\xd8" + "\x77\x28\x2a\x2f\xbf\xbf\xeb\x10\x19\x9e\x78\x79\xe4\xb9\xd1" + "\x3a\x46\xd5" + "\x7f\xb7\xd7\x86\x82\x48\x53\xe1\xcc\x89\xca\xfb\xaf\x14\xde" + "\x1e\x92\x4c" + "\x94\x4f\xeb\x8b\x62\x6c\xe0\x20\x7d\x6f\x9f\xa9\xd8\x49\xee" + "\xca\xc6\x9b" + "\x42\xd6\xe7\xa2\x3b\xd5\x12\x4d\x49\x62\x2b\x44\xb3\x5c\x5b" + "\x15\xfb\x0e" + "\x6a\x77\x81\xa5\x03\xf1\xa4\xe0\x62\xe0\x15\xd5\x57\xd9\x5d" + "\x44\xd9\xd8" + "\xb0\x79\x9b\x3a\xaf\xce\x83\xd5\xd4", + .senderPrivKey = + "\x0f\x28\xbe\xaf\x7e\x27\x79\x3c\x03\x63\x8d\xc2\x97\x3a" + "\x15\xb0\x01\x6e\x1b\x36\x7c\xbf\xfd\xa8\x86\x1a\xb1\x75" + "\xf3\x1b\xce\x02", + .recvPubKey = + "\x04\xc0\xd1\xa8\x12\xb2\x91\x29\x1d\xd7\xbe\xee\x35\x87\x13" + "\xc1\x26\xc5\x89\xf3\x63\x3c\x26\xd1\xa2\x01\x31\x1d\xe0\x36" + "\xdc\x10\x93\x1e\x4e\xe1\x42\xf6\x19\x21\xa3\xea\x58\x64\xe8" + "\x72\xa9\x38\x41\xa5\x29\x44\xe5\xb3\xf6\xac\xce\xcc\xe8\xc8" + "\x28\xfb\x04\xa4\xcd", + .authSecret = + "\x9d\x77\x35\xd8\xde\x19\x62\xb9\x83\x94\xb0\x7f\xfe\x28\x7e\x20", + .salt = + "\xff\x80\x50\x30\xa1\x08\xe1\x14\xe6\xc1\x7f\xad\x61\x86\xa1\xa6", + .plaintext = "I am the very model of a modern Major-General, I've " + "information vegetable, animal, and mineral", + .plaintextLen = 94, + .padLen = 6, + .maxPayloadLen = 631, + .payloadLen = 441, + .rs = 24, + }, + { + // This test is also interesting because the data length (54) is a + // multiple of rs (18). We'll allocate memory to hold 4 records, but only + // write 3. + .desc = "rs = 18, pad = 31", + .payload = "\xe4\x98\x88\xd2\xb2\x8f\x27\x7f\x84\x7b\xc5\xde\x96\xf0\xf8" + "\x1b\x00\x00" + "\x00\x12\x41\x04\x00\xb8\x33\xe4\x81\xa9\x9a\xa3\x30\xdc\xb2" + "\x77\x92\x2d" + "\x5f\x84\xaf\x2e\x9c\xe6\x11\xad\x2a\xd3\xed\x0f\x5b\x43\x19" + "\x12\xd3\x5e" + "\xa7\x2f\xc5\xbf\x76\xb7\x69\xd9\x52\x67\x78\xf5\xab\xfa\x05" + "\x86\x50\x98" + "\x8d\xa5\xe5\x31\xff\x82\xd1\xa7\x04\x37\x94\xc7\x17\x06\x3a" + "\xeb\x95\x8b" + "\xf1\x16\xbc\xcf\x50\x74\x2f\xd4\xd6\x9b\xd0\xea\x7e\x3f\x61" + "\x1c\x70\x9b" + "\xf2\xcd\xf5\xcd\x47\xc6\x42\x6c\xb8\x32\x3b\x53\x98\xc4\x3c" + "\x0d\x0b\x92" + "\xcc\x98\x2d\xa1\xc2\x4c\xe5\xfe\xe2\xb2\x03\xf7\xad\x78\xca" + "\x44\xf0\x49" + "\x0f\x34\x07\xf5\xfe\xe8\x83\x26\x6e\xe4\x70\x35\x19\x5d\xe0" + "\xfe\x6d\x8a" + "\x75\xe4\x87\xdf\x25\x6d\xb5\x97\xa7\x5e\x45\xae\x4f\xb5\x5b" + "\x82\x59\xcb" + "\x0b\x2d\x19\xe7\xb0\x57\x14\x26\x7e\xb5\x60\xae\x07\x2b\x7a" + "\x66\x59\x51" + "\x91\x7a\x06\x87\x32\xdf\x30\x9b\xe2\x56\xf9\x0f\x2a\xdd\xa3" + "\x2f\x05\xfe" + "\xaa\x5e\x9b\x06\x95\xbc\xa2\xcc\xf2\x2a\xae\xfc\x7d\xa9\xce" + "\xeb\xc5\xd4" + "\x0c\x12\xd3\x2a\xdb\x5c\x84\xcb\x32\x0a\xf9\x44\x01\x60\x95" + "\x36\x2f\xeb" + "\xba\x4f\xfa\x4a\x99\x83\x0e\x49\x58\xea\x2b\xba\x50\x8c\xb6" + "\x83\xa5\x8d" + "\x20\x27\xd4\xb7\x47\x26\xa8\x53\xb2\x4b\x47\xcc\xba\x75\x1a" + "\xbe\x9d\x9a" + "\xb2\xda\x9e\xc2\xba\x9c\x7c\xcf\x0c\xf1\x73\x05\xba\xe3\x14" + "\xd3\x8a\x68" + "\x76\x18\xb0\x77\x2f\xcb\x71\xd4\x41\x90\x27\xa4\xbf\x43\x5c" + "\xb7\x21\xaa" + "\xd7\x4e\xfc\x17\x99\x81\xb7\x16\x96\x04\xbf\x97\xec\xac\x41" + "\xe7\x38\x84" + "\x45\x69\x33\x73\x48\x18\x13\x29\x23\xb5\x6c\x15\x2d\x6c\x9e" + "\x59\xae\xf9" + "\x95\xac\xa5\x9d\xe0\xbf\x2c\x80\x3a\x07\x18\x08\x89\x67\x0a" + "\x08\xe6\x4a" + "\x20\xd2\xbf\xa8\x53\xe0\x11\x28\x72\x94\x7b\xaa\xaf\xfb\x51" + "\x0c\xc9\xe7" + "\x5d\x63\x10\xed\x6a\xac\xbd\x2e\x0b\xa3\xa2\x9b\xe4\x2c\x65" + "\x32\xea\x4e" + "\x33\x46\xe1\xf0\x57\x16\x46\x37\x1c\x71\x66\x5e\x3f\xac\x9d" + "\x76\xfa\xee" + "\x1f\x12\x2e\x64\xd4\x90\xdd\x2a\x3e\x31\x81\x6e\xab\x58\x3f" + "\x17\x28\x41" + "\xa0\x75\xd2\x05\xf3\x18\x71\x4a\x8c\x70\xce\x0f\x32\x7f\x4d" + "\x92\xb8\xc9" + "\xdc\xb8\x13\xe6\xd2\x4f\xe8\x56\x33\xf1\xa9\xc7\xc1\xe4\xa1" + "\xfb\x31\x4d" + "\xd5\xfe\x3e\x28\x0e\x39\x08\xf3\x6c\x8c\xbf\xb8\x0b\x7d\x92" + "\x43\xab\xaf" + "\xfa\x65\xc2\x16\xcf\x1a\xa8\xb8\xd6\x26\xa6\x30\xdf\xe8\x18" + "\x6c\xe9\x77" + "\xa5\xb8\xf3\x64\x9d\x37\x53\xb9\x17\x6c\x36\x7e\x4e\x07\xf2" + "\x20\xa1\x75" + "\x80\x61\x38\xe8\x88\x25\xa2\xf3\x49\x84\x20\x58\x2b\x96\x20" + "\x96\x58\xbb" + "\xfa\x8f\x2b\xa6\x93\x3a\x83\xc2\x5e\xdb\x26\x91\x87\x79\x65" + "\x42\xe2\xac" + "\x49\xb8\x07\x86\x36\xbd\xdc\x26\x8e\x11\x62\x5e\x8b\xff\x9f" + "\x0a\x34\x3d" + "\x3a\x4c\x06\x08\x0e\xf0\x80\x3b\x8d\xcd\x8e\x84\x1d\x0e\x27" + "\x59\xe4\x83" + "\xea\x19\xb9\x03\x32\x4d\x9e\xc4\xd5\x2f\x49\x1a\xce\xf3\xee" + "\xff\x44\x1c" + "\x37\x88\x1c\x75\x93\xea\xc3\x16\x21\x33\x7a\x5e\x86\x59\xf9" + "\x3e\x20\x07" + "\x9b\x0e\x26\xeb\xfe\x56\xc1\x04\x55\xd1\x09\x71\x13\x0b\xd2" + "\xa2\xc1\x59" + "\xc7\x4f\x48\xb2\xe5\x26\x53\x0a\x76\xf6\x4c\xca\x2e\xfb\x24" + "\x6e\x79\x3d" + "\x11\xfb\x75\xa6\x68\x01\x8e\x70\xc3\x10\x71\x00\xf8\x1b\xa3" + "\xb1\x6a\xe4" + "\x0a\x83\x8f\x18\xd4\xc4\x7f\x1d\x71\x32\xf1\x74\x68\x8e\xc5" + "\x38\x23\x94" + "\xe0\x11\x99\x21\x73\x1a\x16\x87\x9b\x85\x8f\xf3\x8f\x72\x85" + "\x1e\xa3\xd9" + "\xf5\x26\x3f\xec\x5a\x60\x6d\x12\x71\xa8\x9b\x84\xcc\xa5\x3e" + "\xd7\x3c\x52" + "\x54\xe2\x45\xbf\x8f\x2f\x27\xc2\xc1\xc8\x7f\x39\xee\xa7\x8c" + "\x70\x17\xc8" + "\xc6\xb5\xab\x01\x66\x30\x32\xb5\x8d\xa3\x10\x57\x28\x5e\x56" + "\xc2\x03\xf4" + "\xe4\x8d\x67\x89\xc6\x6b\x26\x95\xa9\x00\xe0\x04\x82\xbd\x84" + "\x65\x59\xec" + "\xdd\xd4\x02\x64\xb3\x8e\x27\x96\x47\xd1\xec\x0f\xcc\xdc\x18" + "\x81\x83\x8b" + "\xbe\x0c\x83\x5e\x26\x90\xef\x05\x8b\x8f\x6a\x03\xe2\x9c\xd9" + "\xeb\x95\x84" + "\xe9\x7f\xbc\x30\x97\x73\xc3\x68\x8e\x5e\x03\xf9\xd3\x8e\x3e" + "\x45\x48\x73" + "\x8a\x5f\x56\x9c\x59\x14\x7d\x3e\x82\x3c\xcc\xac\x71\xd5\xe8" + "\x82\x5d\x51" + "\x34\xce\x98\x13\xcd\x0b\x8f\x96\x27\xa3\xdb\xfa\x45\xb8\x3a" + "\x59\xc8\x3d" + "\x2b\x4d\x3a\xd4\x37\x77\x8a\x3c\xb1\xbc\x77\xba\x16\xc9\x23" + "\x06\xf4\x26" + "\x1a\x2a\x1f\x0d\x5c\x7e\xda\xec\xf9\x26\xf9\x2d\x7c\x9d\xfc" + "\xae\x87\x51" + "\x3a\x68\xb8\xc7\xef\x7c\x63\x26\x4b\x85\x87\x67\xc1\x1a\xaa" + "\x41\xd2\x7c" + "\x63\x6f\x52\xe2\x85\x51\xe9\x3a\x96\x9c\xdc\x96\xd4\x38\x67" + "\xb7\xcb\xd6" + "\x8f\xe0\x35\x7b\xd3\x34\x15\xfa\xf2\x2a\xae\xeb\xc9\x57\xf4" + "\xb5\x73\x7a" + "\x04\xab\x72\x77\xb4\xed\x40\x08\xf0\x9e\xda\xff\x5a\x6d\xb6" + "\x9f\x6c\xb0" + "\x6f\x3d\x0b\x76\x68\x89\x06\xb2\xf5\x3b\x27\xe6\x3f\x37\x28" + "\xba\x2e\xda" + "\x50\x5f\xb1\xb3\x2f\x81\xdd\xdc\x6d\x30\x5f\xd5\x94\x9e\xdd" + "\x05\x49\x0c" + "\xb1\x61\x8f\x0c\xe1\x43\x0e\x9f\x5e\xdf\x50\x01\x2d\xc3", + .senderPrivKey = + "\x78\x30\x57\x7b\xaf\xcf\xc4\x58\x28\xda\x0c\x40\xaa\xb0" + "\x9f\xb2\x27\xbf\xea\xe0\x68\xaa\xb8\xc0\x64\x22\x2a\xcb" + "\xe6\xef\xfd\x34", + .recvPubKey = + "\x04\xc3\xd7\x14\xcb\x42\xe2\xb0\xa1\xd6\xf9\x85\x99\xe2\xf1" + "\x86\xb8\xc2\xba\x6f\x6f\xab\x5e\x09\xa2\xab\xca\x86\x5c\x08" + "\x05\x89\x2b\x2c\x37\x29\x33\x0e\xf8\x3d\xc9\xdf\x4b\x44\x36" + "\x2b\x03\x9a\x06\x09\xd3\x6b\xeb\x93\x21\xa4\x31\xec\x12\x35" + "\x06\xdd\xd9\x0f\x24", + .authSecret = + "\xe4\xd7\xb7\x9d\xec\xde\xde\x12\xc3\xe9\xd9\x0d\x3e\x05\x73\x0f", + .salt = + "\xe4\x98\x88\xd2\xb2\x8f\x27\x7f\x84\x7b\xc5\xde\x96\xf0\xf8\x1b", + .plaintext = "Push the button, Frank!", + .plaintextLen = 23, + .padLen = 31, + .maxPayloadLen = 1265, + .payloadLen = 1058, + .rs = 18, + }, +}; + +void +test_webpush_aes128gcm_encrypt_ok(void) { + size_t tests = sizeof(webpush_aes128gcm_encrypt_ok_tests) / + sizeof(webpush_aes128gcm_encrypt_ok_test_t); + for (size_t i = 0; i < tests; i++) { + webpush_aes128gcm_encrypt_ok_test_t t = + webpush_aes128gcm_encrypt_ok_tests[i]; + + const void* senderPrivKey = t.senderPrivKey; + const void* authSecret = t.authSecret; + const void* salt = t.salt; + const void* recvPubKey = t.recvPubKey; + const void* plaintext = t.plaintext; + + size_t payloadLen = + ece_aes128gcm_payload_max_length(t.rs, t.padLen, t.plaintextLen); + ece_assert(payloadLen == t.maxPayloadLen, + "Got payload max length %zu for `%s`; want %zu", payloadLen, + t.desc, t.maxPayloadLen); + + uint8_t* payload = calloc(payloadLen, sizeof(uint8_t)); + + int err = ece_webpush_aes128gcm_encrypt_with_keys( + senderPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, recvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, t.rs, t.padLen, plaintext, t.plaintextLen, + payload, &payloadLen); + ece_assert(!err, "Got %d encrypting payload for `%s`", err, t.desc); + + ece_assert(payloadLen == t.payloadLen, + "Got actual payload length %zu for `%s`; want %zu", payloadLen, + t.desc, t.payloadLen); + ece_assert(!memcmp(payload, t.payload, payloadLen), + "Wrong payload for `%s`", t.desc); + + free(payload); + } +} + +void +test_webpush_aes128gcm_encrypt_pad(void) { + static const uint32_t maxRs = 128; + + const void* senderPrivKey = "\xac\xae\xc1\xc3\x7c\x30\x7c\xb9\x02\x8f\xbb\xd9" + "\xc7\xf3\xc6\x89\x26\x60\x08\x95\x9a\x5e\xd4\x03" + "\x42\x21\xb2\xda\x72\x01\x82\x8f"; + const void* authSecret = + "\x44\x29\x81\x2d\x53\x5f\xbf\xdb\xea\xc8\x6d\xb7\x14\x5c\x6a\xf2"; + const void* salt = + "\x45\x2b\xfb\xea\x8c\xc7\xa7\x57\x14\xd2\x03\xcf\xf1\x02\xe8\x76"; + const void* recvPubKey = + "\x04\x2d\x78\x8d\x3e\x8e\x82\xf2\xd7\xea\xef\xbd\xe3\xa1\xbe\xde\xa2\x1f" + "\x3b\xc9\x60\x33\x15\x73\x22\xa0\x9e\x14\x46\x55\xa3\xdf\x78\xfd\xca\xc8" + "\x10\xe3\x02\x2a\xb5\x6a\x0e\xa9\xb8\xec\x06\x73\x8a\xce\x41\x1f\x49\x54" + "\x7b\xc0\x0d\x1a\x1c\xde\x97\xce\x7b\xdd\x26"; + + // For rs = `ECE_AES128GCM_MIN_RS`, we allow any amount of padding, because we + // can only include one byte of data per record. + for (uint32_t rs = ECE_AES128GCM_MIN_RS + 1; rs <= maxRs; rs++) { + // Generate a random plaintext. + size_t plaintextLen = (size_t)(rand() % (int) (maxRs - 1) + 1); + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + int ok = RAND_bytes(plaintext, (int) plaintextLen); + ece_assert(ok == 1, "Got %d generating plaintext for rs = %d", ok, rs); + + size_t maxPadLen = (rs - ECE_AES128GCM_MIN_RS) * (plaintextLen + 1); + + // Encrypting with the maximum padding length should succeed. + size_t payloadLen = + ece_aes128gcm_payload_max_length(rs, maxPadLen, plaintextLen); + uint8_t* payload = calloc(payloadLen, sizeof(uint8_t)); + + int err = ece_webpush_aes128gcm_encrypt_with_keys( + senderPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, recvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, rs, maxPadLen, plaintext, plaintextLen, + payload, &payloadLen); + ece_assert(!err, "Got %d encrypting with rs = %d, padLen = %zu", err, rs, + maxPadLen); + + // Adding more padding should fail. + size_t badPadLen = maxPadLen + 1; + payloadLen = ece_aes128gcm_payload_max_length(rs, badPadLen, plaintextLen); + payload = realloc(payload, payloadLen); + + err = ece_webpush_aes128gcm_encrypt_with_keys( + senderPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, recvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, rs, badPadLen, plaintext, plaintextLen, + payload, &payloadLen); + ece_assert(err == ECE_ERROR_ENCRYPT_PADDING, + "Want error encrypting with rs = %d, padLen = %zu", rs, + badPadLen); + + free(plaintext); + free(payload); + } +} diff --git a/mobile/ios/ThirdParty/ecec/test/encrypt/aesgcm.c b/mobile/ios/ThirdParty/ecec/test/encrypt/aesgcm.c new file mode 100644 index 0000000000..43fe66866f --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/encrypt/aesgcm.c @@ -0,0 +1,219 @@ +#include "test.h" + +#include +#include + +#include + +typedef struct webpush_aesgcm_encrypt_ok_test_s { + const char* desc; + const char* ciphertext; + const char* senderPrivKey; + const char* recvPubKey; + const char* authSecret; + const char* salt; + const char* plaintext; + size_t plaintextLen; + size_t padLen; + size_t maxCiphertextLen; + size_t ciphertextLen; + uint32_t rs; +} webpush_aesgcm_encrypt_ok_test_t; + +static webpush_aesgcm_encrypt_ok_test_t webpush_aesgcm_encrypt_ok_tests[] = { + { + .desc = "Example from draft-ietf-webpush-encryption-04", + .ciphertext = "\xea\x7a\x80\x41\x43\x04\xf2\x13\x6a\xc3\x92\x77\x92\x5f" + "\x1c\xa5\x55\x49\xca\x55\xca\x62\xa6\x4e\x7a\xc7\x99\x1b" + "\xc5\x2e\x78\xaa\x40", + .senderPrivKey = "\x9c\x24\x9c\x7a\x4f\x90\xa4\x48\xe6\x38\xe9\x53\xfa" + "\xb4\x37\xf2\x76\x73\xbd\xd3\xe5\xa9\xad\x34\x67\x2d" + "\x22\xea\x6d\x8e\x26\xf6", + .recvPubKey = "\x04\x21\x24\x06\x3c\xcb\xf1\x9d\xc2\xfa\x88\xb6\x43\xba" + "\x04\xe6\xdd\x8d\xa7\xea\x7b\xa2\xc8\xc6\x2e\x0f\x77\xa9" + "\x43\xf4\xc2\xfa\x91\x4f\x6d\x44\x11\x6c\x9f\xd1\xc4\x03" + "\x41\xc6\xa4\x40\xca\xb3\xe2\x14\x0a\x60\xe4\x37\x8a\x5d" + "\xa7\x35\x97\x2d\xe0\x78\x00\x51\x05", + .authSecret = + "\x47\x6f\x6f\x20\x67\x6f\x6f\x20\x67\x27\x20\x6a\x6f\x6f\x62\x21", + .salt = "\x96\x78\x1a\xad\xbc\x8a\x7c\xca\x22\xf5\x9e\xf9\xc5\x85\xe6\x92", + .plaintext = "I am the walrus", + .plaintextLen = 15, + .padLen = 0, + .maxCiphertextLen = 33, + .ciphertextLen = 33, + .rs = 4096, + }, + { + .desc = "rs = 4, trailer", + .ciphertext = + "\xe8\x7d\x81\x05\x8d\x25\xd1\xdb\xfc\xf3\x1c\x5d\x52\xd4\x39\x51\xb4" + "\x7c\x63\x07\x4d\x6d\xb3\xf0\xaf\x89\xe4\xb3\xae\x64\x3d\x00\xb5\xce" + "\xda\x84\x4c\xf7\x9b\xce\xb7\xf9\x4e\xdc\x95\xa9\xf8\x78\x4d\xcf\xf0" + "\xb7\xeb\xdc\x27\x7e\x9a\x17\xdb\xd4\x62\x78\xaa\x8d\x7e\xe9\x65\x24" + "\x81\x22\xe8\x40\x81\x37\x4c\xab\xd0\x3d\xb8\x3b\x98\x39\xdb\x34\x28" + "\x88\xf9\x68\x58\x35\x26\x58\x34\xbb\x11\xe6\xdb\x1e\xb0\x95\xcd\x17" + "\x5e\x12\xc5\xf8\x3f\x1f\xb6\xed\x3a\x4a\x00\x2b\x05\x7c\x10\xeb\x97" + "\x94\x16\x6a\xc6\x1d\xc0\x00\x74\xf8\xd0\x95\xbb\xb6\x7f\xa8\x18\x35" + "\xac\x1b\xa7\x16\xc8\xde\x94\xda\x49\xfb\xdb\x0a\x74\xf6\xac\x68\x89" + "\x7b\xb3\x8d\x3f\xba\x88\x7a\x8b\xc9\x44\xa4\xc9\xdd\x83\x61\x20\x8b" + "\xc3\x82\x57\x65\xe6\xb8\xc7\x69\xd5\x4d\xa7\xa4\x6f\x26\xf0\x50\xd0" + "\xad\xc9\x5a\x16\xde\xa1\xa7\x50\xb0\xf7\xcf\x4d\x3b\xf4\xf5\x1f\xad" + "\x32\xaf\x7a\x0a\x4a\x6a\x4c\x33\x2b\xa8\x49\xe5\xcf\x78\xa3\xf7\x8b" + "\x38\x98\xdc\x3a\x8c\x95\x3c\xde\xb1\xc9\x79\x9b\x0e\xb4\x6e\xad\x37" + "\xe0\xfa\xf4\xba\xc2\xbe\xd6\x56\x58\xb4\x86\x1c\xf9\x42\xfd\x77\xf2" + "\x36\x33\xc5\xe5\xa1\x2e\xe1\x3c\xba\xd7\x64\xa2\x1a\x92\x5c\x79\x47" + "\xf1\xd3\x18\x34\x9a\x9d\x96\x10\x71\xb8\x74\xc6\xb0\xc1\x06\x66\x62" + "\x34\x97\x27\x84\x36\xa9\x3c\xd1\xa9\xa4\xe0\x32\xa9\x64\x9f\x29\x7a" + "\x4d\x8b\xa4\x59\x44\xf6\x3b\xdb\x0b\xce\x45\xce\x0d\x75\xd3\x7c\x24" + "\xa0\x69\x0f\xa0\x96\x0d\x86\x6e\x99\x2d\x61\x63\x15\xba\x01\x3b\x80" + "\xc6\xe3\xac\xfd\x97\x26\x07\x42\x4b\xec\x10\x88\x8d\xd5\x0a\x15\x13" + "\x42\xf1\x5d\x48\x18\x36\xfd\xf3\x65\x8c\x86\xe8\x58\xac\xc0\xf2\x5f" + "\x3f\xe0\xce\xe5\xc2\x29\x5f\x04\x4e\x1e\x82\x89\xbc\x52\x50\x9d\x4f" + "\x5c\x4e\xb5\x56\x5d\x4e\x62\x0a\xe5\x9c\xdb\x26\xa5\x02\x09\x63\xfc" + "\x6e\x43\xca\x0e\x7c\x45\x29\xb3\x22\x38\xfd\x3a\xf6\x0e\xda\xf6\xc5" + "\x6c\x9f\xb4\x08\x95\xb1\xe6\x01\x4a\xd7\x3b\x69\xb3\xcb\x55\x2c\xe8" + "\xc0\xa8\xbb\x14\xff\xe9\x66\xc7\x4d\x40\xfc\x28\xd2\x05\xab\xee\x5f" + "\x73\xed\x9a\x0d\xb9\x64\xe0\x69\xe4\x86\xb3\x02\xef\x58\xcc\xf6\xa3" + "\x4b\x4e", + .senderPrivKey = "\xf1\xfe\xd7\x17\xb0\xd8\x35\xd2\x9b\x9e\x4e\x4f\x4c" + "\xf8\x7d\x0c\xb9\x85\xe2\xbc\x44\xff\xd6\xd4\x37\xa4" + "\xe7\x4a\x18\x04\x55\x87", + .recvPubKey = "\x04\x09\x22\xf1\x7c\xed\x7d\x09\xd4\x55\x10\x2d\xd9\x0c" + "\x31\x46\xce\x33\x2f\x45\xd2\x34\x96\x46\xfe\x64\xca\xbb" + "\x7f\x41\x23\x03\xbe\x5c\x23\x53\x9a\xff\x5c\x30\x72\xdd" + "\x85\xa9\x0b\x76\x92\xe1\x96\x22\x09\x39\xee\xb7\x3e\x0e" + "\xf2\x47\x59\x32\xb1\xcd\xa9\x16\xc7", + .authSecret = + "\xd3\xf8\x22\xf4\x8c\x74\x74\x19\x5d\xa6\x4d\x78\x5f\x40\x8f\x26", + .salt = "\x77\x10\x67\x4b\x1e\xcd\x0b\xf7\xa7\xd3\x25\x88\xea\xe9\x53\x9c", + .plaintext = "I am the very model of a modern Major-General.", + .plaintextLen = 46, + .padLen = 0, + .maxCiphertextLen = 478, + .ciphertextLen = 478, + .rs = 4, + }, + { + .desc = "rs = 6, pad = 4", + .ciphertext = "\x54\x6d\x13\x0b\x1e\xf0\xc2\x3e\xff\x49\x87\xe5\xc6\x57\xf1" + "\x94\xb1\xb8\xad\x5a\xda\xb7\x02\x32\x3c\xf9\xc0\x7b\xd8\x28" + "\x20\x9e\x5d\xe7\x5e\x8b\xf6\x6a\xa5\xf8\xf6\x3b\x0a\x66\xd3" + "\x99\xeb\x8b\x98\x70\x6c\xfc\xa5\xa5\x3f\x8f\x50\x8c\x26\x56" + "\x5a\x34\xe4", + .senderPrivKey = "\xe3\x31\x8e\xc3\x99\xa9\xc4\x71\x7a\xa9\x4b\xa4\xed\xb3" + "\xaa\x1d\x90\x96\x5c\xe7\x6a\x57\x6b\x52\xa0\x7c\x27\x44" + "\x0c\x6d\x9b\xd1", + .recvPubKey = "\x04\xaa\xec\x79\x05\x22\xad\x2b\x70\x56\x05\x58\x99\xda\xa6" + "\x47\x7d\x55\xab\x3f\x16\x5d\x76\x00\x56\x19\xf3\xdf\xa9\x72" + "\x19\xf5\x59\x02\x5d\x09\xc0\x80\x83\x70\xc6\x06\x8a\x66\x51" + "\x81\xd4\x3d\x74\xac\x3d\x0a\xca\x28\x67\x5e\x81\x55\x9a\x20" + "\x4a\x6d\x44\xb5\x91", + .authSecret = + "\x54\x9d\xe2\xfd\x40\x52\xef\x4e\x05\x28\x45\x13\x3e\x37\x61\x3d", + .salt = "\x3a\x4b\xd3\x72\x75\x09\x5d\x71\xc9\x81\xe0\x9c\xde\x0d\xa6\x2a", + .plaintext = "Hello", + .plaintextLen = 5, + .padLen = 4, + .maxCiphertextLen = 63, + .ciphertextLen = 63, + .rs = 6, + }, +}; + +void +test_webpush_aesgcm_encrypt_ok(void) { + size_t tests = sizeof(webpush_aesgcm_encrypt_ok_tests) / + sizeof(webpush_aesgcm_encrypt_ok_test_t); + for (size_t i = 0; i < tests; i++) { + webpush_aesgcm_encrypt_ok_test_t t = webpush_aesgcm_encrypt_ok_tests[i]; + + const void* senderPrivKey = t.senderPrivKey; + const void* authSecret = t.authSecret; + const void* salt = t.salt; + const void* recvPubKey = t.recvPubKey; + const void* plaintext = t.plaintext; + + size_t ciphertextLen = + ece_aesgcm_ciphertext_max_length(t.rs, t.padLen, t.plaintextLen); + ece_assert(ciphertextLen == t.maxCiphertextLen, + "Got ciphertext max length %zu for `%s`; want %zu", + ciphertextLen, t.desc, t.maxCiphertextLen); + + uint8_t* ciphertext = calloc(ciphertextLen, sizeof(uint8_t)); + + int err = ece_webpush_aesgcm_encrypt_with_keys( + senderPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, recvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, t.rs, t.padLen, plaintext, t.plaintextLen, + ciphertext, &ciphertextLen); + ece_assert(!err, "Got %d encrypting ciphertext for `%s`", err, t.desc); + + ece_assert(ciphertextLen == t.ciphertextLen, + "Got actual ciphertext length %zu for `%s`; want %zu", + ciphertextLen, t.desc, t.ciphertextLen); + ece_assert(!memcmp(ciphertext, t.ciphertext, ciphertextLen), + "Wrong ciphertext for `%s`", t.desc); + + free(ciphertext); + } +} + +void +test_webpush_aesgcm_encrypt_pad(void) { + static const uint32_t maxRs = 128; + + const void* senderPrivKey = "\xac\xae\xc1\xc3\x7c\x30\x7c\xb9\x02\x8f\xbb\xd9" + "\xc7\xf3\xc6\x89\x26\x60\x08\x95\x9a\x5e\xd4\x03" + "\x42\x21\xb2\xda\x72\x01\x82\x8f"; + const void* authSecret = + "\x44\x29\x81\x2d\x53\x5f\xbf\xdb\xea\xc8\x6d\xb7\x14\x5c\x6a\xf2"; + const void* salt = + "\x45\x2b\xfb\xea\x8c\xc7\xa7\x57\x14\xd2\x03\xcf\xf1\x02\xe8\x76"; + const void* recvPubKey = + "\x04\x2d\x78\x8d\x3e\x8e\x82\xf2\xd7\xea\xef\xbd\xe3\xa1\xbe\xde\xa2\x1f" + "\x3b\xc9\x60\x33\x15\x73\x22\xa0\x9e\x14\x46\x55\xa3\xdf\x78\xfd\xca\xc8" + "\x10\xe3\x02\x2a\xb5\x6a\x0e\xa9\xb8\xec\x06\x73\x8a\xce\x41\x1f\x49\x54" + "\x7b\xc0\x0d\x1a\x1c\xde\x97\xce\x7b\xdd\x26"; + + for (uint32_t rs = ECE_AESGCM_MIN_RS + 1; rs <= maxRs; rs++) { + // Generate a random plaintext. + size_t plaintextLen = (size_t)(rand() % (int) (maxRs - 1) + 1); + uint8_t* plaintext = calloc(plaintextLen, sizeof(uint8_t)); + int ok = RAND_bytes(plaintext, (int) plaintextLen); + ece_assert(ok == 1, "Got %d generating plaintext for rs = %d", ok, rs); + + size_t maxPadLen = (rs - ECE_AESGCM_MIN_RS) * (plaintextLen + 1); + + // Encrypting with the maximum padding length should succeed. + size_t ciphertextLen = + ece_aesgcm_ciphertext_max_length(rs, maxPadLen, plaintextLen); + uint8_t* ciphertext = calloc(ciphertextLen, sizeof(uint8_t)); + + int err = ece_webpush_aesgcm_encrypt_with_keys( + senderPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, recvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, rs, maxPadLen, plaintext, plaintextLen, + ciphertext, &ciphertextLen); + ece_assert(!err, "Got %d encrypting with rs = %d, padLen = %zu", err, rs, + maxPadLen); + + // Adding more padding should fail. + size_t badPadLen = maxPadLen + 1; + ciphertextLen = + ece_aesgcm_ciphertext_max_length(rs, badPadLen, plaintextLen); + ciphertext = realloc(ciphertext, ciphertextLen); + + err = ece_webpush_aesgcm_encrypt_with_keys( + senderPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, salt, ECE_SALT_LENGTH, recvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, rs, badPadLen, plaintext, plaintextLen, + ciphertext, &ciphertextLen); + ece_assert(err == ECE_ERROR_ENCRYPT_PADDING, + "Want error encrypting with rs = %d, padLen = %zu", rs, + badPadLen); + + free(plaintext); + free(ciphertext); + } +} diff --git a/mobile/ios/ThirdParty/ecec/test/params.c b/mobile/ios/ThirdParty/ecec/test/params.c new file mode 100644 index 0000000000..06d7d92a04 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/params.c @@ -0,0 +1,391 @@ +#include "test.h" + +#include +#include + +typedef struct webpush_aesgcm_from_params_test_s { + const char* cryptoKey; + const char* encryption; + const char* salt; + const char* rawSenderPubKey; + size_t cryptoKeyLen; + size_t encryptionLen; + size_t saltLen; + size_t rawSenderPubKeyLen; + uint32_t rs; +} webpush_aesgcm_from_params_test_t; + +static webpush_aesgcm_from_params_test_t webpush_aesgcm_from_params_tests[] = { + { + .cryptoKey = "dh=Iy1Je2Kv11A", + .cryptoKeyLen = 14, + .encryption = "rs=7;salt=upk1yFkp1xI", + .encryptionLen = 21, + .salt = "\xba\x99\x35\xc8\x59\x29\xd7\x12", + .saltLen = 8, + .rawSenderPubKey = "\x23\x2d\x49\x7b\x62\xaf\xd7\x50", + .rawSenderPubKeyLen = 8, + .rs = 7, + }, + { + .cryptoKey = "dh=mwyOULZ4upjVbCpQLRLOeg", + .cryptoKeyLen = 25, + .encryption = "rs=4096;salt=qzqku7FRdW9Vs97w8O8DoA", + .encryptionLen = 35, + .salt = "\xab\x3a\xa4\xbb\xb1\x51\x75\x6f\x55\xb3\xde\xf0\xf0\xef\x03\xa0", + .saltLen = 16, + .rawSenderPubKey = + "\x9b\x0c\x8e\x50\xb6\x78\xba\x98\xd5\x6c\x2a\x50\x2d\x12\xce\x7a", + .rawSenderPubKeyLen = 16, + .rs = 4096, + }, +}; + +typedef struct webpush_aesgcm_extract_params_ok_test_s { + const char* desc; + const char* cryptoKey; + const char* encryption; + const char* salt; + const char* rawSenderPubKey; + uint32_t rs; +} webpush_aesgcm_extract_params_ok_test_t; + +static webpush_aesgcm_extract_params_ok_test_t + webpush_aesgcm_extract_params_ok_tests[] = { + { + .desc = "Multiple keys in Crypto-Key header", + .cryptoKey = "keyid=p256dh;dh=Iy1Je2Kv11A,p256ecdsa=o2M8QfiEKuI", + .encryption = "keyid=p256dh;salt=upk1yFkp1xI", + .salt = "\xba\x99\x35\xc8\x59\x29\xd7\x12", + .rawSenderPubKey = "\x23\x2d\x49\x7b\x62\xaf\xd7\x50", + .rs = 4096, + }, + { + .desc = "Multiple keys in both headers", + .cryptoKey = "keyid=a;dh=bX0VbuZy8HQ,dh=Iy1Je2Kv11A;keyid=p256dh", + .encryption = + "salt=upk1yFkp1xI;rs=48;keyid=p256dh,salt=U0DM1JsdIbU;keyid=a", + .salt = "\xba\x99\x35\xc8\x59\x29\xd7\x12", + .rawSenderPubKey = "\x23\x2d\x49\x7b\x62\xaf\xd7\x50", + .rs = 48, + }, + { + .desc = "Quoted key ID pair value", + .cryptoKey = "dh=\"byfHbUffc-k\"", + .encryption = "salt=C11AvAsp6Gc", + .salt = "\x0b\x5d\x40\xbc\x0b\x29\xe8\x67", + .rawSenderPubKey = "\x6f\x27\xc7\x6d\x47\xdf\x73\xe9", + .rs = 4096, + }, + { + .desc = "Quoted salt pair value and rs = 24", + .cryptoKey = "dh=ybuT4VDz-Bg", + .encryption = "rs=24; salt=\"H7U7wcIoIKs\"", + .salt = "\x1f\xb5\x3b\xc1\xc2\x28\x20\xab", + .rawSenderPubKey = "\xc9\xbb\x93\xe1\x50\xf3\xf8\x18", + .rs = 24, + }, + { + .desc = "Multiple keys, extra whitespace, strange key ID", + .cryptoKey = " dh= \"ujIToeKunCY\" ,keyid = hello ; dh = I7p5M0yyP8A ", + .encryption = "salt=ie_oYLhw7SI; keyid=\"hello\"; rs =6 , salt = " + "6NAh50bfJZc ;keyid=ujIToeKunCY ", + .salt = "\x89\xef\xe8\x60\xb8\x70\xed\x22", + .rawSenderPubKey = "\x23\xba\x79\x33\x4c\xb2\x3f\xc0", + .rs = 6, + }, + { + // Invalid, but we don't check the entire `Crypto-Key` param once we see a + // match. + .desc = "Duplicate key ID in Crypto-Key", + .cryptoKey = "keyid=a;keyid=b;dh=pbmv1QkcEDY", + .encryption = "salt=Esao8aTBfIk;keyid=b", + .salt = "\x12\xc6\xa8\xf1\xa4\xc1\x7c\x89", + .rawSenderPubKey = "\xa5\xb9\xaf\xd5\x09\x1c\x10\x36", + .rs = 4096, + }, +}; + +typedef struct webpush_aesgcm_extract_params_err_test_s { + const char* desc; + const char* cryptoKey; + const char* encryption; + int err; +} webpush_aesgcm_extract_params_err_test_t; + +static webpush_aesgcm_extract_params_err_test_t + webpush_aesgcm_extract_params_err_tests[] = { + { + .desc = "Invalid record size", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "salt=Esao8aTBfIk;rs=bad", + .err = ECE_ERROR_INVALID_RS, + }, + { + .desc = "Blank Crypto-Key header", + .cryptoKey = " \t ", + .encryption = "salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Empty Encryption header", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Crypto-Key missing pair value", + .cryptoKey = "dh=", + .encryption = "salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Encryption missing pair value with trailing whitespace", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "salt= ", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Crypto-Key pair without value", + .cryptoKey = "dh=pbmv1QkcEDY; keyid, dh=rqowftPcCVo", + .encryption = "salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Encryption pair without value", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "rs; salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Crypto-Key missing pair name", + .cryptoKey = "dh=pbmv1QkcEDY; =rqowftPcCVo", + .encryption = "salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Encryption missing pair name", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Whitespace in quoted Crypto-Key pair value", + .cryptoKey = "dh=byfHbUffc-k; param=\" \"", + .encryption = "salt=C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Empty quoted value in Encryption header", + .cryptoKey = "dh=byfHbUffc-k", + .encryption = "salt=\"\"; rs=6", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Invalid character in Crypto-Key pair value", + .cryptoKey = "dh==byfHbUffc-k", + .encryption = "salt=C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Invalid character in Encryption pair name", + .cryptoKey = "dh=byfHbUffc-k", + .encryption = "sa!t=C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Leading , in Crypto-Key header", + .cryptoKey = ",dh=byfHbUffc-k", + .encryption = "salt=C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Trailing ; in Crypto-Key header", + .cryptoKey = "dh=byfHbUffc-k;", + .encryption = "salt=C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Leading ; in Encryption header", + .cryptoKey = "dh=byfHbUffc-k", + .encryption = "; salt=C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Trailing , in Encryption header", + .cryptoKey = "dh=byfHbUffc-k", + .encryption = "salt=C11AvAsp6Gc,", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Unterminated quoted value in Encryption header", + .cryptoKey = "dh=byfHbUffc-k", + .encryption = "rs=6; salt=\"C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Invalid quoted name in Crypto-Key header", + .cryptoKey = "\"dh\"=\"byfHbUffc-k\"", + .encryption = "salt=C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Invalid quoted name in Encryption header", + .cryptoKey = "dh=byfHbUffc-k", + .encryption = "\"salt\"=C11AvAsp6Gc", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Mismatched key IDs", + .cryptoKey = "keyid=p256dh;dh=pbmv1QkcEDY", + .encryption = "keyid=different;salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_DH, + }, + { + .desc = "Multiple mismatched key IDs", + .cryptoKey = "keyid=a;dh=bX0VbuZy8HQ,dh=Iy1Je2Kv11A;keyid=b", + .encryption = "salt=upk1yFkp1xI;rs=48;keyid=c,salt=U0DM1JsdIbU;keyid=d", + .err = ECE_ERROR_INVALID_DH, + }, + { + .desc = "Key ID with matching pair value, wrong pair name", + .cryptoKey = "p256dh=p256dh;dh=pbmv1QkcEDY", + .encryption = "keyid=p256dh;salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_DH, + }, + { + .desc = "Invalid Base64url-encoded salt", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "salt=99999", + .err = ECE_ERROR_INVALID_SALT, + }, + { + .desc = "Invalid Base64url-encoded dh pair value", + .cryptoKey = "dh=zzzzz", + .encryption = "salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_DH, + }, + { + .desc = "Invalid character at end of salt pair name", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "salt !=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Invalid character at end of salt", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "salt=Esao8aTBfIk!", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Invalid character after quoted dh pair value", + .cryptoKey = "dh=\"pbmv1QkcEDY\"!", + .encryption = "salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_CRYPTO_KEY_HEADER, + }, + { + .desc = "Duplicate key ID in Encryption header", + .cryptoKey = "keyid=b;dh=pbmv1QkcEDY", + .encryption = "keyid=a;salt=Esao8aTBfIk;keyid=b", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Duplicate record size in Encryption header", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "rs=5;salt=Esao8aTBfIk;rs=10", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Duplicate salt in Encryption header", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "salt=Esao8aTBfIk; salt=Esao8aTBfIk", + .err = ECE_ERROR_INVALID_ENCRYPTION_HEADER, + }, + { + .desc = "Missing salt in Encryption header", + .cryptoKey = "dh=pbmv1QkcEDY", + .encryption = "rs=5", + .err = ECE_ERROR_INVALID_SALT, + }, +}; + +void +test_webpush_aesgcm_headers_from_params(void) { + size_t length = sizeof(webpush_aesgcm_from_params_tests) / + sizeof(webpush_aesgcm_from_params_test_t); + for (size_t i = 0; i < length; i++) { + webpush_aesgcm_from_params_test_t t = webpush_aesgcm_from_params_tests[i]; + + size_t cryptoKeyLen = 0; + size_t encryptionLen = 0; + int err = ece_webpush_aesgcm_headers_from_params( + t.salt, t.saltLen, t.rawSenderPubKey, t.rawSenderPubKeyLen, t.rs, NULL, + &cryptoKeyLen, NULL, &encryptionLen); + ece_assert(!err, "Got %d determining lengths for (%s, %s)", err, + t.cryptoKey, t.encryption); + ece_assert(cryptoKeyLen == t.cryptoKeyLen, + "Got Crypto-Key length %zu for (%s, %s); want %zu", cryptoKeyLen, + t.cryptoKey, t.encryption, t.cryptoKeyLen); + ece_assert(encryptionLen == t.encryptionLen, + "Got Encryption length %zu for (%s, %s); want %zu", + encryptionLen, t.cryptoKey, t.encryption, t.encryptionLen); + + char* cryptoKey = malloc(cryptoKeyLen + 1); + char* encryption = malloc(encryptionLen + 1); + + err = ece_webpush_aesgcm_headers_from_params( + t.salt, t.saltLen, t.rawSenderPubKey, t.rawSenderPubKeyLen, t.rs, + cryptoKey, &cryptoKeyLen, encryption, &encryptionLen); + ece_assert(!err, "Got %d formatting headers for (%s, %s)", err, t.cryptoKey, + t.encryption); + ece_assert(!memcmp(cryptoKey, t.cryptoKey, t.cryptoKeyLen), + "Wrong Crypto-Key for (%s, %s)", t.cryptoKey, t.encryption); + ece_assert(!memcmp(encryption, t.encryption, t.encryptionLen), + "Wrong Encryption for (%s, %s)", t.cryptoKey, t.encryption); + + free(cryptoKey); + free(encryption); + } +} + +void +test_webpush_aesgcm_headers_extract_params_ok(void) { + size_t length = sizeof(webpush_aesgcm_extract_params_ok_tests) / + sizeof(webpush_aesgcm_extract_params_ok_test_t); + for (size_t i = 0; i < length; i++) { + webpush_aesgcm_extract_params_ok_test_t t = + webpush_aesgcm_extract_params_ok_tests[i]; + + uint8_t salt[8]; + uint32_t rs; + uint8_t rawSenderPubKey[8]; + int err = ece_webpush_aesgcm_headers_extract_params( + t.cryptoKey, t.encryption, salt, 8, rawSenderPubKey, 8, &rs); + + ece_assert(!err, "Got %d extracting params for `%s`", err, t.desc); + ece_assert(!memcmp(salt, t.salt, 8), "Wrong salt for `%s`", t.desc); + ece_assert(rs == t.rs, "Got rs = %" PRIu32 " for `%s`; want %" PRIu32, rs, + t.desc, t.rs); + ece_assert(!memcmp(rawSenderPubKey, t.rawSenderPubKey, 8), + "Wrong public key for `%s`", t.desc); + } +} + +void +test_webpush_aesgcm_headers_extract_params_err(void) { + size_t length = sizeof(webpush_aesgcm_extract_params_err_tests) / + sizeof(webpush_aesgcm_extract_params_err_test_t); + for (size_t i = 0; i < length; i++) { + webpush_aesgcm_extract_params_err_test_t t = + webpush_aesgcm_extract_params_err_tests[i]; + + uint8_t salt[8]; + uint32_t rs; + uint8_t rawSenderPubKey[8]; + int err = ece_webpush_aesgcm_headers_extract_params( + t.cryptoKey, t.encryption, salt, 8, rawSenderPubKey, 8, &rs); + + ece_assert(err == t.err, "Got %d extracting params for `%s`; want %d", err, + t.desc, t.err); + } +} diff --git a/mobile/ios/ThirdParty/ecec/test/test.c b/mobile/ios/ThirdParty/ecec/test/test.c new file mode 100644 index 0000000000..8bd4699aa7 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/test.c @@ -0,0 +1,66 @@ +#include "test.h" + +#include +#include +#include +#include + +int +main() { + test_webpush_aesgcm_headers_from_params(); + test_webpush_aesgcm_headers_extract_params_ok(); + test_webpush_aesgcm_headers_extract_params_err(); + + test_webpush_aesgcm_encrypt_ok(); + test_webpush_aesgcm_encrypt_pad(); + test_webpush_aesgcm_decrypt_ok(); + test_webpush_aesgcm_decrypt_err(); + + test_webpush_aes128gcm_encrypt_ok(); + test_webpush_aes128gcm_encrypt_pad(); + test_webpush_aes128gcm_decrypt_ok(); + test_webpush_aes128gcm_decrypt_err(); + test_aes128gcm_decrypt_ok(); + test_aes128gcm_decrypt_err(); + + test_webpush_aes128gcm_e2e(); + test_webpush_aesgcm_e2e(); + + test_base64url_encode(); + test_base64url_decode(); + + return 0; +} + +void +ece_log(const char* funcName, int line, const char* expr, const char* format, + ...) { + char* message = NULL; + va_list args; + va_start(args, format); + + // Determine the size of the formatted message, then allocate and write to a + // buffer large enough to hold the message. `vsnprintf` mutates its argument + // list, so we make a copy for calculating the size. + va_list sizeArgs; + va_copy(sizeArgs, args); + int size = vsnprintf(NULL, 0, format, sizeArgs); + va_end(sizeArgs); + if (size < 0) { + goto error; + } + message = malloc((size_t) size + 1); + if (!message || vsprintf(message, format, args) != size) { + goto error; + } + message[size] = '\0'; + fprintf(stderr, "[%s:%d] (%s): %s\n", funcName, line, expr, message); + goto end; + +error: + fprintf(stderr, "[%s:%d]: %s\n", funcName, line, expr); + +end: + va_end(args); + free(message); +} diff --git a/mobile/ios/ThirdParty/ecec/test/test.h b/mobile/ios/ThirdParty/ecec/test/test.h new file mode 100644 index 0000000000..762309c483 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/test/test.h @@ -0,0 +1,70 @@ +#include +#include + +#include + +// This macro is similar to the standard `assert`, but accepts a format string +// with an informative failure message. +#define ece_assert(cond, format, ...) \ + do { \ + if (!(cond)) { \ + ece_log(__func__, __LINE__, #cond, format, __VA_ARGS__); \ + abort(); \ + } \ + } while (0) + +// Logs an assertion failure to standard error. +void +ece_log(const char* funcName, int line, const char* expr, const char* format, + ...); + +void +test_webpush_aesgcm_headers_from_params(void); + +void +test_webpush_aesgcm_headers_extract_params_ok(void); + +void +test_webpush_aesgcm_headers_extract_params_err(void); + +void +test_webpush_aesgcm_encrypt_ok(void); + +void +test_webpush_aesgcm_encrypt_pad(void); + +void +test_webpush_aesgcm_decrypt_ok(void); + +void +test_webpush_aesgcm_decrypt_err(void); + +void +test_webpush_aes128gcm_encrypt_ok(void); + +void +test_webpush_aes128gcm_encrypt_pad(void); + +void +test_aes128gcm_decrypt_ok(void); + +void +test_webpush_aes128gcm_decrypt_ok(void); + +void +test_aes128gcm_decrypt_err(void); + +void +test_webpush_aes128gcm_decrypt_err(void); + +void +test_webpush_aes128gcm_e2e(void); + +void +test_webpush_aesgcm_e2e(void); + +void +test_base64url_encode(void); + +void +test_base64url_decode(void); diff --git a/mobile/ios/ThirdParty/ecec/tool/decrypt.c b/mobile/ios/ThirdParty/ecec/tool/decrypt.c new file mode 100644 index 0000000000..85ac8d3279 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/tool/decrypt.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#include + +int +main(int argc, char** argv) { + if (argc < 4) { + fprintf(stderr, "Usage: %s ", + argv[0]); + return 2; + } + + int err = 0; + uint8_t* payload = NULL; + uint8_t* plaintext = NULL; + + uint8_t authSecret[ECE_WEBPUSH_AUTH_SECRET_LENGTH]; + if (!ece_base64url_decode(argv[1], strlen(argv[1]), + ECE_BASE64URL_REJECT_PADDING, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH)) { + fprintf(stderr, "Error: Failed to Base64url-decode auth secret\n"); + goto error; + } + uint8_t rawRecvPrivKey[ECE_WEBPUSH_PRIVATE_KEY_LENGTH]; + if (!ece_base64url_decode(argv[2], strlen(argv[2]), + ECE_BASE64URL_REJECT_PADDING, rawRecvPrivKey, + ECE_WEBPUSH_PRIVATE_KEY_LENGTH)) { + fprintf(stderr, "Error: Failed to Base64url-decode private key\n"); + goto error; + } + size_t payloadBase64Len = strlen(argv[3]); + size_t payloadLen = ece_base64url_decode( + argv[3], payloadBase64Len, ECE_BASE64URL_REJECT_PADDING, NULL, 0); + if (!payloadLen) { + fprintf(stderr, "Error: Empty or invalid Base64url-encoded message\n"); + goto error; + } + payload = calloc(payloadLen, sizeof(uint8_t)); + if (!payload) { + fprintf( + stderr, + "Error: Failed to allocate %zu bytes for Base64url-decoded message\n", + payloadLen); + goto error; + } + payloadLen = + ece_base64url_decode(argv[3], payloadBase64Len, + ECE_BASE64URL_REJECT_PADDING, payload, payloadLen); + if (!payloadLen) { + fprintf(stderr, "Error: Failed to Base64url-decode message\n"); + goto error; + } + + size_t plaintextLen = ece_aes128gcm_plaintext_max_length(payload, payloadLen); + if (!plaintextLen) { + fprintf(stderr, "Error: Encrypted message too short\n"); + goto error; + } + plaintextLen++; + plaintext = calloc(plaintextLen, sizeof(uint8_t)); + if (!plaintext) { + fprintf(stderr, + "Error: Failed to allocate %zu bytes for decrypted message\n", + plaintextLen); + goto error; + } + err = ece_webpush_aes128gcm_decrypt( + rawRecvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, authSecret, + ECE_WEBPUSH_AUTH_SECRET_LENGTH, payload, payloadLen, plaintext, + &plaintextLen); + if (err) { + fprintf(stderr, "Error: Failed to decrypt message: %d\n", err); + goto error; + } + plaintext[plaintextLen] = '\0'; + printf("Decrypted message: %s\n", plaintext); + goto end; + +error: + err = 1; + +end: + free(payload); + free(plaintext); + return err; +} diff --git a/mobile/ios/ThirdParty/ecec/tool/keygen.c b/mobile/ios/ThirdParty/ecec/tool/keygen.c new file mode 100644 index 0000000000..7ff4240620 --- /dev/null +++ b/mobile/ios/ThirdParty/ecec/tool/keygen.c @@ -0,0 +1,63 @@ +#include +#include + +#include + +static const char ece_keygen_hex_alphabet[] = "0123456789abcdef"; + +char* +ece_keygen_hex_encode(const uint8_t* binary, size_t binaryLen) { + if (binaryLen > SIZE_MAX / 2 - 1) { + return NULL; + } + char* encoded = malloc(binaryLen * 2 + 1); + if (!encoded) { + return NULL; + } + char* hex = encoded; + for (size_t i = 0; i < binaryLen; i++) { + *hex++ = ece_keygen_hex_alphabet[(binary[i] >> 4) & 0xf]; + *hex++ = ece_keygen_hex_alphabet[binary[i] & 0xf]; + } + *hex = '\0'; + return encoded; +} + +int +main(int argc, char** argv) { + uint8_t rawRecvPrivKey[ECE_WEBPUSH_PRIVATE_KEY_LENGTH]; + uint8_t rawRecvPubKey[ECE_WEBPUSH_PUBLIC_KEY_LENGTH]; + uint8_t authSecret[ECE_WEBPUSH_AUTH_SECRET_LENGTH]; + + int err = ece_webpush_generate_keys( + rawRecvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH, rawRecvPubKey, + ECE_WEBPUSH_PUBLIC_KEY_LENGTH, authSecret, ECE_WEBPUSH_AUTH_SECRET_LENGTH); + if (err) { + fprintf(stderr, "Error: Failed to generate subscription keys: %d\n", err); + return 1; + } + + char* hexRecvPrivKey = + ece_keygen_hex_encode(rawRecvPrivKey, ECE_WEBPUSH_PRIVATE_KEY_LENGTH); + if (hexRecvPrivKey) { + printf("Private key: %s\n", hexRecvPrivKey); + } + + char* hexRecvPubKey = + ece_keygen_hex_encode(rawRecvPubKey, ECE_WEBPUSH_PUBLIC_KEY_LENGTH); + if (hexRecvPubKey) { + printf("Public key: %s\n", hexRecvPubKey); + } + + char* hexAuthSecret = + ece_keygen_hex_encode(authSecret, ECE_WEBPUSH_AUTH_SECRET_LENGTH); + if (hexAuthSecret) { + printf("Authentication secret: %s\n", hexAuthSecret); + } + + free(hexRecvPrivKey); + free(hexRecvPubKey); + free(hexAuthSecret); + + return 0; +} diff --git a/mobile/ios/ThirdParty/sqlcipher/.gitignore b/mobile/ios/ThirdParty/sqlcipher/.gitignore new file mode 100644 index 0000000000..f68644eb92 --- /dev/null +++ b/mobile/ios/ThirdParty/sqlcipher/.gitignore @@ -0,0 +1,40 @@ +*.lo +*.o +*.mode1v3 +*.pbxuser +xcuserdata +xcuserdata/* +*.xcworkspace/* +*.xcworkspace +/Makefile +/.libs +/.target_source +/config.h +/config.log +/config.status +/keywordhash.h +/mkkeywordhash* +/opcodes.c +/opcodes.h +/parse.c +/parse.h +/parse.h.temp +/parse.out +/tsrc +/testfixture* +/lemon* +/libtool +/libsqlite3.la +/libtclsqlite3.la +/sqlite3 +/sqlite3.c +/sqlite3.h +/lempar.c +/parse.y +/shell.c +/sqlcipher +/sqlite3.pc +/sqlcipher.pc +/sqlite3ext.h +/libsqlcipher.la +/.DS_Store diff --git a/mobile/ios/ThirdParty/sqlcipher/CHANGELOG.md b/mobile/ios/ThirdParty/sqlcipher/CHANGELOG.md new file mode 100644 index 0000000000..43d6fdb511 --- /dev/null +++ b/mobile/ios/ThirdParty/sqlcipher/CHANGELOG.md @@ -0,0 +1,78 @@ +# SQLCipher Change Log +All notable changes to this project will be documented in this file. + +## [Unreleased][unreleased] + +## [3.3.0] - 2015-03-25 +### Added +- Added FIPS API calls within the OpenSSL crpyto provider +- `PRAGMA cipher_default_page_size` - support for attaching non-default page sizes + +### Changed +- Merged upstream SQLite 3.8.8.3 + +## [3.2.0] - 2014-09-30 +### Added +- Added PRAGMA cipher_store_pass + +### Changed +- Merged upstream SQLite 3.8.6 +- Renmed README to README.md + +## [3.1.0] - 2014-04-23 +### Added +- Added `PRAGMA cipher_profile` + +### Changed +- Merged upstream SQLite 3.8.4.3 + +## [3.0.1] - 2013-12-06 +### Added +- Add `PRAGMA cipher_add_random` to source external entropy + +### Changed +- Fix `PRAGMA cipher_migrate` to handle passphrases longer than 64 characters & raw keys +- Improvements to the libtomcrypt provider + +## [3.0.0] - 2013-11-05 +### Added +- Added `PRAGMA cipher_migrate` to migrate older database file formats + +### Changed +- Merged upstream SQLite 3.8.0.2 +- Remove usage of VirtualLock/Unlock on WinRT and Windows Phone +- Ignore HMAC read during Btree file copy +- Fix lib naming for pkg-config +- Use _v2 version of sqlite3_key and sqlite3_rekey +- Update xcodeproj file + +### Security +- Change KDF iteration length from 4,000 to 64,000 + +[unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.0...prerelease +[3.3.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.2.0...v3.3.0 +[3.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.1.0...v3.2.0 +[3.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.1...v3.1.0 +[3.0.1]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.0...v3.0.1 +[3.0.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.2.0...v3.0.0 +[2.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.1.1...v2.2.0 +[2.1.1]: https://github.com/sqlcipher/sqlcipher/compare/v2.1.0...v2.1.1 +[2.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.6...v2.1.0 +[2.0.6]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.5...v2.0.6 +[2.0.5]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.3...v2.0.5 +[2.0.3]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.0...v2.0.3 +[2.0.0]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.10...v2.0.0 +[1.1.10]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.9...v1.1.10 +[1.1.9]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.8...v1.1.9 +[1.1.8]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.7...v1.1.8 +[1.1.7]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.6...v1.1.7 +[1.1.6]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.4...v1.1.5 +[1.1.4]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.3...v1.1.4 +[1.1.3]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.2...v1.1.3 +[1.1.2]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.1...v1.1.1 +[1.1.1]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.0...v1.1.1 +[1.1.0]: https://github.com/sqlcipher/sqlcipher/compare/617ed01...v1.1.0 + + + diff --git a/mobile/ios/ThirdParty/sqlcipher/LICENSE b/mobile/ios/ThirdParty/sqlcipher/LICENSE new file mode 100644 index 0000000000..bebe1e7eb1 --- /dev/null +++ b/mobile/ios/ThirdParty/sqlcipher/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2008, ZETETIC LLC +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the ZETETIC LLC nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/mobile/ios/ThirdParty/sqlcipher/README.md b/mobile/ios/ThirdParty/sqlcipher/README.md new file mode 100644 index 0000000000..fc4547f4b0 --- /dev/null +++ b/mobile/ios/ThirdParty/sqlcipher/README.md @@ -0,0 +1,346 @@ +## SQLCipher + +SQLCipher is an SQLite extension that provides transparent 256-bit AES encryption of +database files. Pages are encrypted before being written to disk and are decrypted +when read back. Due to the small footprint and great performance it’s ideal for +protecting embedded application databases and is well suited for mobile development. + +The official SQLCipher software site is http://sqlcipher.net + +SQLCipher was initially developed by Stephen Lombardo at Zetetic LLC +(sjlombardo@zetetic.net) as the encrypted database layer for Strip, +an iPhone data vault and password manager (http://getstrip.com). + +## Features + +- Fast performance with as little as 5-15% overhead for encryption on many operations +- 100% of data in the database file is encrypted +- Good security practices (CBC mode, key derivation) +- Zero-configuration and application level cryptography +- Algorithms provided by the peer reviewed OpenSSL crypto library. +- Configurable crypto providers + +## Contributions + +We welcome contributions, to contribute to SQLCipher, a [contributor agreement](https://www.zetetic.net/contributions/) needs to be submitted. All submissions should be based on the `prerelease` branch. + +## Compiling + +Building SQLCipher is almost the same as compiling a regular version of +SQLite with two small exceptions: + + 1. You *must* define SQLITE_HAS_CODEC and SQLITE_TEMP_STORE=2 when building sqlcipher. + 2. You need to link against a OpenSSL's libcrypto + +Example Static linking (replace /opt/local/lib with the path to libcrypto.a). Note in this +example, --enable-tempstore=yes is setting SQLITE_TEMP_STORE=2 for the build. + + $ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ + LDFLAGS="/opt/local/lib/libcrypto.a" + $ make + +Example Dynamic linking + + $ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ + LDFLAGS="-lcrypto" + $ make + +## Encrypting a database + +To specify an encryption passphrase for the database via the SQL interface you +use a pragma. The passphrase you enter is passed through PBKDF2 key derivation to +obtain the encryption key for the database + + PRAGMA key = 'passphrase'; + +Alternately, you can specify an exact byte sequence using a blob literal. If you +use this method it is your responsibility to ensure that the data you provide a +64 character hex string, which will be converted directly to 32 bytes (256 bits) of +key data without key derivation. + + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + +To encrypt a database programatically you can use the sqlite3_key function. +The data provided in pKey is converted to an encryption key according to the +same rules as PRAGMA key. + + int sqlite3_key(sqlite3 *db, const void *pKey, int nKey); + +PRAGMA key or sqlite3_key should be called as the first operation when a database is open. + +## Changing a database key + +To change the encryption passphrase for an existing database you may use the rekey pragma +after you've supplied the correct database password; + + PRAGMA key = 'passphrase'; -- start with the existing database passphrase + PRAGMA rekey = 'new-passphrase'; -- rekey will reencrypt with the new passphrase + +The hexrekey pragma may be used to rekey to a specific binary value + + PRAGMA rekey = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + +This can be accomplished programtically by using sqlite3_rekey; + + sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) + +## Support + +The primary avenue for support and discussions is the SQLCipher users mailing list: + +http://groups.google.com/group/sqlcipher + +Issues or support questions on using SQLCipher should be entered into the +GitHub Issue tracker: + +https://github.com/sqlcipher/sqlcipher/issues + +Please DO NOT post issues, support questions, or other problems to blog +posts about SQLCipher as we do not monitor them frequently. + +If you are using SQLCipher in your own software please let us know at +support@zetetic.net! + +## License + +Copyright (c) 2008, ZETETIC LLC +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the ZETETIC LLC nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## End SQLCipher + +This directory contains source code to + + SQLite: An Embeddable SQL Database Engine + +To compile the project, first create a directory in which to place +the build products. It is recommended, but not required, that the +build directory be separate from the source directory. Cd into the +build directory and then from the build directory run the configure +script found at the root of the source tree. Then run "make". + +For example: + + tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite" + mkdir bld ;# Build will occur in a sibling directory + cd bld ;# Change to the build directory + ../sqlite/configure ;# Run the configure script + make ;# Run the makefile. + make install ;# (Optional) Install the build products + +The configure script uses autoconf 2.61 and libtool. If the configure +script does not work out for you, there is a generic makefile named +"Makefile.linux-gcc" in the top directory of the source tree that you +can copy and edit to suit your needs. Comments on the generic makefile +show what changes are needed. + +The linux binaries on the website are created using the generic makefile, +not the configure script. The windows binaries on the website are created +using MinGW32 configured as a cross-compiler running under Linux. For +details, see the ./publish.sh script at the top-level of the source tree. +The developers do not use teh configure script. + +SQLite does not require TCL to run, but a TCL installation is required +by the makefiles. SQLite contains a lot of generated code and TCL is +used to do much of that code generation. The makefile also requires +AWK. + +Contacts: + + http://www.sqlite.org/ +======= + mkdir bld + cd bld + nmake /f Makefile.msc TOP=..\sqlite + nmake /f Makefile.msc sqlite3.c TOP=..\sqlite + nmake /f Makefile.msc sqlite3.dll TOP=..\sqlite + nmake /f Makefile.msc sqlite3.exe TOP=..\sqlite + nmake /f Makefile.msc test TOP=..\sqlite + +There are several build options that can be set via the NMAKE command +line. For example, to build for WinRT, simply add "FOR_WINRT=1" argument +to the "sqlite3.dll" command line above. When debugging into the SQLite +code, adding the "DEBUG=1" argument to one of the above command lines is +recommended. + +SQLite does not require [Tcl](http://www.tcl.tk/) to run, but a Tcl installation +is required by the makefiles (including those for MSVC). SQLite contains +a lot of generated code and Tcl is used to do much of that code generation. +The makefiles also require AWK. + +## Source Code Tour + +Most of the core source files are in the **src/** subdirectory. But +src/ also contains files used to build the "testfixture" test harness; +those file all begin with "test". And src/ contains the "shell.c" file +which is the main program for the "sqlite3.exe" command-line shell and +the "tclsqlite.c" file which implements the bindings to SQLite from the +Tcl programming language. (Historical note: SQLite began as a Tcl +extension and only later escaped to the wild as an independent library.) + +Test scripts and programs are found in the **test/** subdirectory. +There are other test suites for SQLite (see +[How SQLite Is Tested](http://www.sqlite.org/testing.html)) +but those other test suites are +in separate source repositories. + +The **ext/** subdirectory contains code for extensions. The +Full-text search engine is in **ext/fts3**. The R-Tree engine is in +**ext/rtree**. The **ext/misc** subdirectory contains a number of +smaller, single-file extensions, such as a REGEXP operator. + +The **tool/** subdirectory contains various scripts and programs used +for building generated source code files or for testing or for generating +accessory programs such as "sqlite3_analyzer(.exe)". + +### Generated Source Code Files + +Several of the C-language source files used by SQLite are generated from +other sources rather than being typed in manually by a programmer. This +section will summarize those automatically-generated files. To create all +of the automatically-generated files, simply run "make target_source". +The "target_source" make target will create a subdirectory "tsrc/" and +fill it with all the source files needed to build SQLite, both +manually-edited files and automatically-generated files. + +The SQLite interface is defined by the **sqlite3.h** header file, which is +generated from src/sqlite.h.in, ./manifest.uuid, and ./VERSION. The +[Tcl script](http://www.tcl.tk) at tool/mksqlite3h.tcl does the conversion. +The manifest.uuid file contains the SHA1 hash of the particular check-in +and is used to generate the SQLITE\_SOURCE\_ID macro. The VERSION file +contains the current SQLite version number. The sqlite3.h header is really +just a copy of src/sqlite.h.in with the source-id and version number inserted +at just the right spots. Note that comment text in the sqlite3.h file is +used to generate much of the SQLite API documentation. The Tcl scripts +used to generate that documentation are in a separate source repository. + +The SQL language parser is **parse.c** which is generate from a grammar in +the src/parse.y file. The conversion of "parse.y" into "parse.c" is done +by the [lemon](./doc/lemon.html) LALR(1) parser generator. The source code +for lemon is at tool/lemon.c. Lemon uses a +template for generating its parser. A generic template is in tool/lempar.c, +but SQLite uses a slightly modified template found in src/lempar.c. + +Lemon also generates the **parse.h** header file, at the same time it +generates parse.c. But the parse.h header file is +modified further (to add additional symbols) using the ./addopcodes.awk +AWK script. + +The **opcodes.h** header file contains macros that define the numbers +corresponding to opcodes in the "VDBE" virtual machine. The opcodes.h +file is generated by the scanning the src/vdbe.c source file. The +AWK script at ./mkopcodeh.awk does this scan and generates opcodes.h. +A second AWK script, ./mkopcodec.awk, then scans opcodes.h to generate +the **opcodes.c** source file, which contains a reverse mapping from +opcode-number to opcode-name that is used for EXPLAIN output. + +The **keywordhash.h** header file contains the definition of a hash table +that maps SQL language keywords (ex: "CREATE", "SELECT", "INDEX", etc.) into +the numeric codes used by the parse.c parser. The keywordhash.h file is +generated by a C-language program at tool mkkeywordhash.c. + +### The Amalgamation + +All of the individual C source code and header files (both manually-edited +and automatically-generated) can be combined into a single big source file +**sqlite3.c** called "the amalgamation". The amalgamation is the recommended +way of using SQLite in a larger application. Combining all individual +source code files into a single big source code file allows the C compiler +to perform more cross-procedure analysis and generate better code. SQLite +runs about 5% faster when compiled from the amalgamation versus when compiled +from individual source files. + +The amalgamation is generated from the tool/mksqlite3c.tcl Tcl script. +First, all of the individual source files must be gathered into the tsrc/ +subdirectory (using the equivalent of "make target_source") then the +tool/mksqlite3c.tcl script is run to copy them all together in just the +right order while resolving internal "#include" references. + +The amalgamation source file is more than 100K lines long. Some symbolic +debuggers (most notably MSVC) are unable to deal with files longer than 64K +lines. To work around this, a separate Tcl script, tool/split-sqlite3c.tcl, +can be run on the amalgamation to break it up into a single small C file +called **sqlite3-all.c** that does #include on about five other files +named **sqlite3-1.c**, **sqlite3-2.c**, ..., **sqlite3-5.c**. In this way, +all of the source code is contained within a single translation unit so +that the compiler can do extra cross-procedure optimization, but no +individual source file exceeds 32K lines in length. + +## How It All Fits Together + +SQLite is modular in design. +See the [architectural description](http://www.sqlite.org/arch.html) +for details. Other documents that are useful in +(helping to understand how SQLite works include the +[file format](http://www.sqlite.org/fileformat2.html) description, +the [virtual machine](http://www.sqlite.org/vdbe.html) that runs +prepared statements, the description of +[how transactions work](http://www.sqlite.org/atomiccommit.html), and +the [overview of the query planner](http://www.sqlite.org/optoverview.html). + +Unfortunately, years of effort have gone into optimizating SQLite, both +for small size and high performance. And optimizations tend to result in +complex code. So there is a lot of complexity in the SQLite implementation. + +Key files: + + * **sqlite3.h** - This file defines the public interface to the SQLite + library. Readers will need to be familiar with this interface before + trying to understand how the library works internally. + + * **sqliteInt.h** - this header file defines many of the data objects + used internally by SQLite. + + * **parse.y** - This file describes the LALR(1) grammer that SQLite uses + to parse SQL statements, and the actions that are taken at each stop + in the parsing process. + + * **vdbe.c** - This file implements the virtual machine that runs + prepared statements. There are various helper files whose names + begin with "vdbe". The VDBE has access to the vdbeInt.h header file + which defines internal data objects. The rest of SQLite interacts + with the VDBE through an interface defined by vdbe.h. + + * **where.c** - This file analyzes the WHERE clause and generates + virtual machine code to run queries efficiently. This file is + sometimes called the "query optimizer". It has its own private + header file, whereInt.h, that defines data objects used internally. + + * **btree.c** - This file contains the implementation of the B-Tree + storage engine used by SQLite. + + * **pager.c** - This file contains the "pager" implementation, the + module that implements transactions. + + * **os_unix.c** and **os_win.c** - These two files implement the interface + between SQLite and the underlying operating system using the run-time + pluggable VFS interface. + + +## Contacts + +The main SQLite webpage is [http://www.sqlite.org/](http://www.sqlite.org/) +with geographically distributed backup servers at +[http://www2.sqlite.org/](http://www2.sqlite.org) and +[http://www3.sqlite.org/](http://www3.sqlite.org). diff --git a/mobile/ios/ThirdParty/sqlcipher/VERSION b/mobile/ios/ThirdParty/sqlcipher/VERSION new file mode 100644 index 0000000000..67a9eb7bd3 --- /dev/null +++ b/mobile/ios/ThirdParty/sqlcipher/VERSION @@ -0,0 +1 @@ +3.8.8.3 \ No newline at end of file diff --git a/mobile/ios/ThirdParty/sqlcipher/sqlcipher.xcodeproj/project.pbxproj b/mobile/ios/ThirdParty/sqlcipher/sqlcipher.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..d1239c50c4 --- /dev/null +++ b/mobile/ios/ThirdParty/sqlcipher/sqlcipher.xcodeproj/project.pbxproj @@ -0,0 +1,307 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 28B46E6317CD07A700672510 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28B46E6217CD07A600672510 /* Security.framework */; }; + 9069D0A30FCE1A4D0042E34C /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 28B46E6217CD07A600672510 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 9069D0A20FCE1A4D0042E34C /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = ""; }; + D2AAC046055464E500DB518D /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D289987405E68DCB004EDB86 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 28B46E6317CD07A700672510 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* sqlcipher */ = { + isa = PBXGroup; + children = ( + 28B46E6217CD07A600672510 /* Security.framework */, + 08FB7795FE84155DC02AAC07 /* Source */, + C6A0FF2B0290797F04C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = sqlcipher; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 9069D0A20FCE1A4D0042E34C /* sqlite3.c */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + D2AAC046055464E500DB518D /* libsqlcipher.a */, + ); + name = Products; + sourceTree = ""; + }; + C6A0FF2B0290797F04C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + D2AAC043055464E500DB518D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + D2AAC045055464E500DB518D /* sqlcipher */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "sqlcipher" */; + buildPhases = ( + D2AAC043055464E500DB518D /* Headers */, + D2AAC044055464E500DB518D /* Sources */, + D289987405E68DCB004EDB86 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = sqlcipher; + productName = sqlcipher; + productReference = D2AAC046055464E500DB518D /* libsqlcipher.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftMigration = 0700; + LastUpgradeCheck = 0800; + }; + buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "sqlcipher" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* sqlcipher */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D2AAC045055464E500DB518D /* sqlcipher */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + D2AAC044055464E500DB518D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9069D0A30FCE1A4D0042E34C /* sqlite3.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB91EC08733DB70010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)"; + INSTALL_PATH = /usr/local/lib; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE=2", + "-DSQLCIPHER_CRYPTO_CC", + ); + "OTHER_CFLAGS[arch=armv6]" = ( + "-mno-thumb", + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE=2", + "-DSQLCIPHER_CRYPTO_CC", + ); + OTHER_LDFLAGS = ""; + PRODUCT_NAME = sqlcipher; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "arm64 armv7 armv7s"; + }; + name = Debug; + }; + 1DEB91ED08733DB70010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)"; + INSTALL_PATH = /usr/local/lib; + "IPHONEOS_DEPLOYMENT_TARGET[sdk=iphoneos*]" = 5.1.1; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DNDEBUG", + "-DSQLITE_OS_UNIX=1", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE=2", + "-DSQLCIPHER_CRYPTO_CC", + ); + "OTHER_CFLAGS[arch=armv6]" = ( + "-mno-thumb", + "-DSQLITE_HAS_CODEC", + "-DNDEBUG", + "-DSQLITE_OS_UNIX=1", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE=2", + "-DSQLCIPHER_CRYPTO_CC", + ); + OTHER_LDFLAGS = ""; + PRODUCT_NAME = sqlcipher; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "arm64 armv7 armv7s"; + }; + name = Release; + }; + 1DEB91F008733DB70010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + "IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "arm64 armv7 armv7s"; + }; + name = Debug; + }; + 1DEB91F108733DB70010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + "IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0; + "IPHONEOS_DEPLOYMENT_TARGET[sdk=iphoneos*]" = 5.1.1; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "arm64 armv7 armv7s"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91EC08733DB70010E9CD /* Debug */, + 1DEB91ED08733DB70010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "sqlcipher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91F008733DB70010E9CD /* Debug */, + 1DEB91F108733DB70010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/mobile/ios/UITests/AuthenticationTests.swift b/mobile/ios/UITests/AuthenticationTests.swift new file mode 100644 index 0000000000..99f5b17c68 --- /dev/null +++ b/mobile/ios/UITests/AuthenticationTests.swift @@ -0,0 +1,114 @@ +/* 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/. */ + +import Foundation +import EarlGrey + +class AuthenticationTests: KIFTestCase { + fileprivate var webRoot: String! + + override func setUp() { + super.setUp() + webRoot = SimplePageServer.start() + BrowserUtils.dismissFirstRunUI() + } + + override func tearDown() { + BrowserUtils.resetToAboutHome(tester()) + BrowserUtils.clearPrivateData(tester: tester()) + super.tearDown() + } + + /** + * Tests HTTP authentication credentials and auto-fill. + */ + func testAuthentication() { + loadAuthPage() + + // Make sure that 3 invalid credentials result in authentication failure. + enterCredentials(usernameValue: "Username", passwordValue: "Password", username: "foo", password: "bar") + enterCredentials(usernameValue: "foo", passwordValue: "•••", username: "foo2", password: "bar2") + enterCredentials(usernameValue: "foo2", passwordValue: "••••", username: "foo3", password: "bar3") + + // Use KIFTest framework for checking elements within webView + tester().waitForWebViewElementWithAccessibilityLabel("auth fail") + + // Enter valid credentials and ensure the page loads. + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Reload")).perform(grey_tap()) + enterCredentials(usernameValue: "Username", passwordValue: "Password", username: "user", password: "pass") + tester().waitForWebViewElementWithAccessibilityLabel("logged in") + + // Save the credentials. + tester().tapView(withAccessibilityIdentifier: "SaveLoginPrompt.saveLoginButton") + + logOut() + loadAuthPage() + + // Make sure the credentials were saved and auto-filled. + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Log in")) + .inRoot(grey_kindOfClass(NSClassFromString("_UIAlertControllerActionView")!)) + .perform(grey_tap()) + tester().waitForWebViewElementWithAccessibilityLabel("logged in") + + // Add a private tab. + if BrowserUtils.iPad() { + EarlGrey.select(elementWithMatcher:grey_accessibilityID("TopTabsViewController.tabsButton")) + .perform(grey_tap()) + } else { + EarlGrey.select(elementWithMatcher:grey_accessibilityID("TabToolbar.tabsButton")) + .perform(grey_tap()) + } + EarlGrey.select(elementWithMatcher:grey_accessibilityID("TabTrayController.maskButton")) + .perform(grey_tap()) + EarlGrey.select(elementWithMatcher:grey_accessibilityID("TabTrayController.addTabButton")) + .perform(grey_tap()) + loadAuthPage() + + // Make sure the auth prompt is shown. + // Note that in the future, we might decide to auto-fill authentication credentials in private browsing mode, + // but that's not currently supported. We assume the username and password fields are empty. + enterCredentials(usernameValue: "Username", passwordValue: "Password", username: "user", password: "pass") + tester().waitForWebViewElementWithAccessibilityLabel("logged in") + + } + + fileprivate func loadAuthPage() { + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_replaceText("\(webRoot!)/auth.html")) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_typeText("\n")) + } + + fileprivate func logOut() { + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_replaceText("\(webRoot!)/auth.html?logout=1")) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_typeText("\n")) + // Wait until the dialog shows up + let dialogAppeared = GREYCondition(name: "Wait the login dialog to appear", block: { _ in + var errorOrNil: NSError? + let matcher = grey_allOf([grey_accessibilityLabel("Cancel"), + grey_sufficientlyVisible()]) + EarlGrey.select(elementWithMatcher: matcher) + .inRoot(grey_kindOfClass(NSClassFromString("_UIAlertControllerActionView")!)) + .assert(grey_notNil(), error: &errorOrNil) + let success = errorOrNil == nil + return success + }).wait(withTimeout: 20) + + GREYAssertTrue(dialogAppeared, reason: "Failed to display login dialog") + + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Cancel")) + .inRoot(grey_kindOfClass(NSClassFromString("_UIAlertControllerActionView")!)) + .perform(grey_tap()) + } + + fileprivate func enterCredentials(usernameValue: String, passwordValue: String, username: String, password: String) { + + // In case of IPad, Earl Grey complains that UI Loop has not been finished for password field, reverting. + let usernameField = tester().waitForViewWithAccessibilityValue(usernameValue) as! UITextField + let passwordField = tester().waitForViewWithAccessibilityValue(passwordValue) as! UITextField + usernameField.text = username + passwordField.text = password + tester().tapView(withAccessibilityLabel: "Log in") + } +} diff --git a/mobile/ios/UITests/BookmarksPanelTests.swift b/mobile/ios/UITests/BookmarksPanelTests.swift new file mode 100644 index 0000000000..a0e72093fb --- /dev/null +++ b/mobile/ios/UITests/BookmarksPanelTests.swift @@ -0,0 +1,218 @@ +/* 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/. */ + +@testable import Client +@testable import Storage +import Shared +import Foundation +import WebKit +import EarlGrey + +class BookmarksPanelTests: KIFTestCase { + + override func setUp() { + super.setUp() + BrowserUtils.dismissFirstRunUI() + } + + override func tearDown() { + super.tearDown() + BrowserUtils.resetToAboutHome(tester()) + } + + private func getAppBookmarkStorage() -> BookmarkBufferStorage? { + let application = UIApplication.shared + + guard let delegate = application.delegate as? TestAppDelegate else { + XCTFail("Couldn't get app delegate.") + return nil + } + + let profile = delegate.getProfile(application) + + guard let bookmarks = profile.bookmarks as? BookmarkBufferStorage else { + XCTFail("Couldn't get buffer storage.") + return nil + } + + return bookmarks + } + + private func createSomeBufferBookmarks() { + // Set up the buffer. + let bufferDate = Date.now() + let changedBufferRecords = [ + BookmarkMirrorItem.folder(BookmarkRoots.ToolbarFolderGUID, dateAdded: Date.now(), modified: bufferDate, hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: nil, title: "Bookmarks Toolbar", description: nil, children: ["aaa", "bbb"]), + BookmarkMirrorItem.bookmark("aaa", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: nil, title: "AAA", description: nil, URI: "http://getfirefox.com", tags: "[]", keyword: nil), + BookmarkMirrorItem.livemark("bbb", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.ToolbarFolderGUID, parentName: nil, title: "Some Livemark", description: nil, feedURI: "https://www.google.ca", siteURI: "https://www.google.ca") ] + + if let bookmarks = getAppBookmarkStorage() { + XCTAssert(bookmarks.applyRecords(changedBufferRecords).value.isSuccess) + } + } + + func testBookmarkPanelBufferOnly() { + // Insert some data into the buffer. There will be nothing in the mirror, but we can still + // show Desktop Bookmarks. + + createSomeBufferBookmarks() + + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Bookmarks")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Desktop Bookmarks")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Bookmarks Toolbar")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("AAA")) + .assert(grey_sufficientlyVisible()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Some Livemark")) + .assert(grey_sufficientlyVisible()) + + // When we tap the livemark, we load the siteURI. + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Some Livemark")).perform(grey_tap()) + + // … so we show the truncated URL. + // Strangely, earlgrey cannot find the label in buddybuild, but passes locally. + // Using KIF for this check for now. + EarlGrey.select(elementWithMatcher: grey_accessibilityValue("www.google.ca/")).assert(grey_sufficientlyVisible()) + } + + private func navigateBackInTableView() { + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Bookmarks")).inRoot(grey_kindOfClass(UITableView.self)).perform(grey_tap()) + } + + private func navigateFolder(withTitle title: String) { + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel(title)).perform(grey_tap()) + } + + private func makeBookmark(guid: GUID, parentID: GUID, title: String) -> BookmarkMirrorItem { + return BookmarkMirrorItem.bookmark(guid, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: parentID, parentName: nil, title: title, description: nil, URI: "http://unused.com", tags: "[]", keyword: nil) + } + + private func makeFolder(guid: GUID, parentID: GUID, title: String, childrenGuids: [GUID]) -> BookmarkMirrorItem { + return BookmarkMirrorItem.folder(guid, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: parentID, parentName: nil, title: title, description: nil, children: childrenGuids) + } + + private func assertRowExists(withTitle title: String) { + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel(title)).inRoot(grey_kindOfClass(UITableView.self)).assert(grey_notNil()) + } + + func testMobileBookmarks() { + verifyRootHasLocalAndBufferBookmarks() + + // Rather than an elaborate setup() step, just continue from the previous test + // as the view state is now setup for testing deletion. + verifyMobileBookmarkDelete() + } + + func verifyRootHasLocalAndBufferBookmarks() { + // Add buffer data, then later in the test verify that the buffer mobile folder is not shown in there anymore. + createSomeBufferBookmarks() + + guard let bookmarks = getAppBookmarkStorage() else { + return + } + + // TEST: Create remote mobile bookmark, and verify the bookmark appears in the root and the remote mobile folder is not shown + var applyResult = bookmarks.applyRecords([ + makeBookmark(guid: "bm-guid0", parentID: BookmarkRoots.MobileFolderGUID, title: "xyz"), + makeFolder(guid: BookmarkRoots.MobileFolderGUID, parentID: BookmarkRoots.RootGUID, title: "", childrenGuids: ["bm-guid0"]) + ]) + XCTAssert(applyResult.value.isSuccess) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Bookmarks")).perform(grey_tap()) + + // is this in the root? + assertRowExists(withTitle: "xyz") + + navigateFolder(withTitle: "Desktop Bookmarks") + // this should be missing, they are shown in the root + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Mobile Bookmarks")).assert(grey_nil()) + + // TEST: Add a local bookmark, and then navigate back to the root view (the navigation will refresh the table). + let isAdded = (bookmarks as! MergedSQLiteBookmarks).local.addToMobileBookmarks(URL(string: "http://another-unused")!, title: "123", favicon: nil) + XCTAssert(isAdded.value.isSuccess) + navigateBackInTableView() + // is this in the root? + assertRowExists(withTitle: "123") + + // TEST: Add sub-folder to MobileFolderGUID, ensure it is navigable + applyResult = bookmarks.applyRecords([ + makeBookmark(guid: "bm-guid1", parentID: "folder-guid0", title: "item-in-remote-subfolder"), + makeFolder(guid: "folder-guid0", parentID: BookmarkRoots.MobileFolderGUID, title: "remote-subfolder", childrenGuids: ["bm-guid1"]), + makeFolder(guid: BookmarkRoots.MobileFolderGUID, parentID: BookmarkRoots.RootGUID, title: "", childrenGuids: ["bm-guid0", "folder-guid0"]) + ]) + XCTAssert(applyResult.value.isSuccess) + + // refresh view + navigateFolder(withTitle: "Desktop Bookmarks") + navigateBackInTableView() + + // subfolder should now be in the root + assertRowExists(withTitle: "remote-subfolder") + + // navigate remote mobile subfolder, ensure bookmark is shown in the subfolder + navigateFolder(withTitle: "remote-subfolder") + assertRowExists(withTitle: "item-in-remote-subfolder") + } + + // This is a continuation of the above test + func verifyMobileBookmarkDelete() { + // Assert precondition that this test continues from previous state + assertRowExists(withTitle: "item-in-remote-subfolder") + + let deleteAction = GREYMatchers.matcher(forText: "Remove Bookmark") + + // Test deletion not available + + var row = EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("item-in-remote-subfolder")) + row.perform(grey_longPress()) + // verify the context menu does not have deletion option + EarlGrey.select(elementWithMatcher: deleteAction).assert(grey_nil()) + // close the context menu + EarlGrey.select(elementWithMatcher: GREYMatchers.matcher(forText: "Pin to Top Sites")).perform(grey_tap()) + + navigateBackInTableView() + + // Test successful deletion + + assertRowExists(withTitle: "xyz") + + let tv = tester().waitForView(withAccessibilityIdentifier: "Bookmarks List") as! UITableView + let rowCount = tv.numberOfRows(inSection: 0) + + row = EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("xyz")) + row.perform(grey_longPress()) + EarlGrey.select(elementWithMatcher: deleteAction).perform(grey_tap()) + + XCTAssert(tv.numberOfRows(inSection: 0) == rowCount - 1) + + EarlGrey.select(elementWithMatcher: grey_accessibilityID("goBack")).perform(grey_tap()) + } + + func testRefreshBookmarks() { + createSomeBufferBookmarks() + guard let bookmarks = getAppBookmarkStorage() else { + return + } + let applyResult = bookmarks.applyRecords([ + makeBookmark(guid: "bm-guid0", parentID: BookmarkRoots.MobileFolderGUID, title: "xyz"), + makeFolder(guid: BookmarkRoots.MobileFolderGUID, parentID: BookmarkRoots.RootGUID, title: "", childrenGuids: ["bm-guid0"]) + ]) + XCTAssert(applyResult.value.isSuccess) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Bookmarks")).perform(grey_tap()) + + // Add a bookmark + let isAdded = (bookmarks as! MergedSQLiteBookmarks).local.addToMobileBookmarks(URL(string: "http://new-bookmark")!, title: "NewBookmark", favicon: nil) + XCTAssert(isAdded.value.isSuccess) + + // Pull to refresh + assertRowExists(withTitle: "xyz") + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("xyz")).inRoot(grey_kindOfClass(NSClassFromString("UITableView")!)).perform(grey_swipeSlowInDirectionWithStartPoint(.down, 0.7, 0.7)) + + // Verify new bookmark exists + assertRowExists(withTitle: "NewBookmark") + + EarlGrey.select(elementWithMatcher: grey_accessibilityID("goBack")).perform(grey_tap()) + } +} diff --git a/mobile/ios/UITests/BrowserTests.swift b/mobile/ios/UITests/BrowserTests.swift new file mode 100644 index 0000000000..958127993a --- /dev/null +++ b/mobile/ios/UITests/BrowserTests.swift @@ -0,0 +1,56 @@ +/* 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/. */ + +import Foundation +import Storage +import EarlGrey +@testable import Client + +class BrowserTests: KIFTestCase { + + private var webRoot: String! + + override func setUp() { + super.setUp() + webRoot = SimplePageServer.start() + BrowserUtils.dismissFirstRunUI() + } + + override func tearDown() { + BrowserUtils.resetToAboutHome(tester()) + BrowserUtils.clearPrivateData(tester: tester()) + super.tearDown() + } + + // Disabled with https://bugzilla.mozilla.org/show_bug.cgi?id=1409851 + func testDisplaySharesheetWhileJSPromptOccurs() { + let url = "\(webRoot!)/JSPrompt.html" + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_replaceText(url)) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_typeText("\n")) + tester().waitForWebViewElementWithAccessibilityLabel("JS Prompt") + //EarlGrey.select(elementWithMatcher: grey_kindOfClass(NSClassFromString("_UIAlertControllerInterfaceActionGroupView")!)) + // .assert(grey_sufficientlyVisible()) + + // Show share sheet and wait for the JS prompt to fire + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Share")).perform(grey_tap()) + + if BrowserUtils.iPad() { + // iPad does not have cancel btn to close dialog + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Share")).perform(grey_tap()) + } else { + let matcher = grey_allOf([grey_accessibilityLabel("Cancel"), + grey_accessibilityTrait(UIAccessibilityTraitButton), + grey_sufficientlyVisible()]) + EarlGrey.select(elementWithMatcher: matcher).perform(grey_tap()) + } + + // Check to see if the JS Prompt is dequeued and showing + tester().waitForView(withAccessibilityLabel: "OK") + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("OK")) + .inRoot(grey_kindOfClass(NSClassFromString("_UIAlertControllerActionView")!)) + .assert(grey_enabled()) + .perform((grey_tap())) + } +} diff --git a/mobile/ios/UITests/ClearPrivateDataTests.swift b/mobile/ios/UITests/ClearPrivateDataTests.swift new file mode 100644 index 0000000000..258508e5d3 --- /dev/null +++ b/mobile/ios/UITests/ClearPrivateDataTests.swift @@ -0,0 +1,229 @@ +/* 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/. */ + +import Foundation +import Shared +import WebKit +import UIKit +import EarlGrey +import GCDWebServers + +class ClearPrivateDataTests: KIFTestCase, UITextFieldDelegate { + + fileprivate var webRoot: String! + + override func setUp() { + super.setUp() + webRoot = SimplePageServer.start() + BrowserUtils.dismissFirstRunUI() + } + + override func tearDown() { + BrowserUtils.resetToAboutHome(tester()) + } + + func visitSites(noOfSites: Int) -> [(title: String, domain: String, dispDomain: String, url: String)] { + var urls: [(title: String, domain: String, dispDomain: String, url: String)] = [] + for pageNo in 1...noOfSites { + let url = "\(webRoot!)/numberedPage.html?page=\(pageNo)" + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_replaceText(url)) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_typeText("\n")) + + tester().waitForWebViewElementWithAccessibilityLabel("Page \(pageNo)") + let dom = URL(string: url)!.normalizedHost! + let index = dom.index(dom.startIndex, offsetBy: 7) + let dispDom = dom.substring(to: index) // On IPhone, it only displays first 8 chars + let tuple: (title: String, domain: String, dispDomain: String, url: String) + = ("Page \(pageNo)", dom, dispDom, url) + urls.append(tuple) + } + BrowserUtils.resetToAboutHome(tester()) + return urls + } + + func anyDomainsExistOnTopSites(_ domains: Set, fulldomains: Set) { + if checkDomains(domains: domains) == true { + return + } else { + if checkDomains(domains: fulldomains) == true { + return + } + } + XCTFail("Couldn't find any domains in top sites.") + } + + private func checkDomains(domains: Set) -> Bool { + var errorOrNil: NSError? + + for domain in domains { + let withoutDot = domain.replacingOccurrences(of: ".", with: " ") + let matcher = grey_allOf([grey_accessibilityLabel(withoutDot), + grey_kindOfClass(NSClassFromString("Client.TopSiteItemCell")!), + grey_sufficientlyVisible()]) + EarlGrey.select(elementWithMatcher: matcher).assert(grey_notNil(), error: &errorOrNil) + + if errorOrNil == nil { + return true + } + } + return false + } + + func testRemembersToggles() { + BrowserUtils.clearPrivateData([BrowserUtils.Clearable.History], swipe:false, tester: tester()) + BrowserUtils.openClearPrivateDataDialog(false, tester: tester()) + + // Ensure the toggles match our settings. + [ + (BrowserUtils.Clearable.Cache, "0"), + (BrowserUtils.Clearable.Cookies, "0"), + (BrowserUtils.Clearable.OfflineData, "0"), + (BrowserUtils.Clearable.History, "1") + ].forEach { clearable, switchValue in + XCTAssertNotNil(tester() + .waitForView(withAccessibilityLabel: clearable.rawValue, value: switchValue, traits: UIAccessibilityTraitNone)) + } + + BrowserUtils.closeClearPrivateDataDialog(tester()) + } + + func testClearsHistoryPanel() { + let urls = visitSites(noOfSites: 2) + + let url1 = urls[0].url + let url2 = urls[1].url + tester().waitForView(withAccessibilityIdentifier: "HomePanels.History") + tester().tapView(withAccessibilityIdentifier: "HomePanels.History") + tester().waitForView(withAccessibilityLabel: url1) + tester().waitForView(withAccessibilityLabel: url2) + + BrowserUtils.clearPrivateData([BrowserUtils.Clearable.History], swipe: false, tester: tester()) + tester().tapView(withAccessibilityLabel: "Bookmarks") + tester().tapView(withAccessibilityLabel: "History") + tester().waitForAbsenceOfView(withAccessibilityLabel: url1) + tester().waitForAbsenceOfView(withAccessibilityLabel: url2) + } + + func testDisabledHistoryDoesNotClearHistoryPanel() { + let urls = visitSites(noOfSites: 2) + var errorOrNil: NSError? + + let url1 = urls[0].url + let url2 = urls[1].url + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("History")).perform(grey_tap()) + tester().waitForView(withAccessibilityLabel: url1) + tester().waitForView(withAccessibilityLabel: url2) + BrowserUtils.clearPrivateData(BrowserUtils.AllClearables.subtracting([BrowserUtils.Clearable.History]), swipe: false, tester: tester()) + + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel(url1)) + .assert(grey_notNil(), error: &errorOrNil) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel(url2)) + .assert(grey_notNil(), error: &errorOrNil) + } + + func testClearsCookies() { + let url = "\(webRoot!)/numberedPage.html?page=1" + + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_replaceText(url)) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_typeText("\n")) + tester().waitForWebViewElementWithAccessibilityLabel("Page 1") + + let webView = tester().waitForView(withAccessibilityLabel: "Web content") as! WKWebView + + // Set and verify a dummy cookie value. + setCookies(webView, cookie: "foo=bar") + var cookies = getCookies(webView) + XCTAssertEqual(cookies.cookie, "foo=bar") + XCTAssertEqual(cookies.localStorage, "foo=bar") + XCTAssertEqual(cookies.sessionStorage, "foo=bar") + + // Verify that cookies are not cleared when Cookies is deselected. + BrowserUtils.clearPrivateData(BrowserUtils.AllClearables.subtracting([BrowserUtils.Clearable.Cookies]), swipe: false, tester: tester()) + cookies = getCookies(webView) + XCTAssertEqual(cookies.cookie, "foo=bar") + XCTAssertEqual(cookies.localStorage, "foo=bar") + XCTAssertEqual(cookies.sessionStorage, "foo=bar") + + // Verify that cookies are cleared when Cookies is selected. + BrowserUtils.clearPrivateData([BrowserUtils.Clearable.Cookies], swipe: false, tester: tester()) + cookies = getCookies(webView) + XCTAssertEqual(cookies.cookie, "") + XCTAssertEqual(cookies.localStorage, "null") + XCTAssertEqual(cookies.sessionStorage, "null") + } + + func testClearsCache() { + let cachedServer = CachedPageServer() + let cacheRoot = cachedServer.start() + let url = "\(cacheRoot)/cachedPage.html" + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_replaceText(url)) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_typeText("\n")) + tester().waitForWebViewElementWithAccessibilityLabel("Cache test") + + let webView = tester().waitForView(withAccessibilityLabel: "Web content") as! WKWebView + let requests = cachedServer.requests + + // Verify that clearing non-cache items will keep the page in the cache. + BrowserUtils.clearPrivateData(BrowserUtils.AllClearables.subtracting([BrowserUtils.Clearable.Cache]), swipe: false, tester: tester()) + webView.reload() + XCTAssertEqual(cachedServer.requests, requests) + + // Verify that clearing the cache will fire a new request. + BrowserUtils.clearPrivateData([BrowserUtils.Clearable.Cache], swipe: false, tester: tester()) + webView.reload() + XCTAssertEqual(cachedServer.requests, requests + 1) + } + + fileprivate func setCookies(_ webView: WKWebView, cookie: String) { + let expectation = self.expectation(description: "Set cookie") + webView.evaluateJavaScript("document.cookie = \"\(cookie)\"; localStorage.cookie = \"\(cookie)\"; sessionStorage.cookie = \"\(cookie)\";") { result, _ in + expectation.fulfill() + } + waitForExpectations(timeout: 10, handler: nil) + } + + fileprivate func getCookies(_ webView: WKWebView) -> (cookie: String, localStorage: String?, sessionStorage: String?) { + var cookie: (String, String?, String?)! + var value: String! + let expectation = self.expectation(description: "Got cookie") + + webView.evaluateJavaScript("JSON.stringify([document.cookie, localStorage.cookie, sessionStorage.cookie])") { result, _ in + value = result as! String + expectation.fulfill() + } + + waitForExpectations(timeout: 10, handler: nil) + value = value.replacingOccurrences(of: "[", with: "") + value = value.replacingOccurrences(of: "]", with: "") + value = value.replacingOccurrences(of: "\"", with: "") + let items = value.components(separatedBy: ",") + cookie = (items[0], items[1], items[2]) + return cookie + } +} + +/// Server that keeps track of requests. +private class CachedPageServer { + var requests = 0 + + func start() -> String { + let webServer = GCDWebServer() + webServer?.addHandler(forMethod: "GET", path: "/cachedPage.html", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + self.requests += 1 + return GCDWebServerDataResponse(html: "Cached pageCache test") + } + + webServer?.start(withPort: 0, bonjourName: nil) + + // We use 127.0.0.1 explicitly here, rather than localhost, in order to avoid our + // history exclusion code (Bug 1188626). + let port = (webServer?.port)! + let webRoot = "http://127.0.0.1:\(port)" + return webRoot + } +} diff --git a/mobile/ios/UITests/DomainAutocompleteTests.swift b/mobile/ios/UITests/DomainAutocompleteTests.swift new file mode 100644 index 0000000000..4bc78a87f8 --- /dev/null +++ b/mobile/ios/UITests/DomainAutocompleteTests.swift @@ -0,0 +1,40 @@ +/* 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/. */ + +import Foundation +import Shared +import EarlGrey + +class DomainAutocompleteTests: KIFTestCase { + override func setUp() { + + super.setUp() + BrowserUtils.dismissFirstRunUI(tester()) + } + + func testAutocomplete() { + BrowserUtils.addHistoryEntry("Foo bar baz", url: URL(string: "https://foo.bar.baz.org/dingbat")!) + + tester().tapView(withAccessibilityIdentifier: "url") + let textField = tester().waitForView(withAccessibilityLabel: "Address and Search") as! UITextField + + // Multiple subdomains. + tester().enterText(intoCurrentFirstResponder: "f") + BrowserUtils.ensureAutocompletionResult(tester(), textField: textField, prefix: "f", completion: "oo.bar.baz.org") + tester().clearTextFromFirstResponder() + tester().enterText(intoCurrentFirstResponder: "b") + BrowserUtils.ensureAutocompletionResult(tester(), textField: textField, prefix: "b", completion: "ar.baz.org") + tester().enterText(intoCurrentFirstResponder: "a") + BrowserUtils.ensureAutocompletionResult(tester(), textField: textField, prefix: "ba", completion: "r.baz.org") + tester().enterText(intoCurrentFirstResponder: "z") + BrowserUtils.ensureAutocompletionResult(tester(), textField: textField, prefix: "baz", completion: ".org") + } + + override func tearDown() { + super.tearDown() + EarlGrey.select(elementWithMatcher: grey_accessibilityID("goBack")).perform(grey_tap()) + BrowserUtils.resetToAboutHome(tester()) + BrowserUtils.clearPrivateData(tester: tester()) + } +} diff --git a/mobile/ios/UITests/EarlGrey.swift b/mobile/ios/UITests/EarlGrey.swift new file mode 100644 index 0000000000..4597354609 --- /dev/null +++ b/mobile/ios/UITests/EarlGrey.swift @@ -0,0 +1,151 @@ +// +// Copyright 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import EarlGrey +import Foundation + +public func GREYAssert(_ expression: @autoclosure () -> Bool, reason: String) { + GREYAssert(expression, reason, details: "Expected expression to be true") +} + +public func GREYAssertTrue(_ expression: @autoclosure () -> Bool, reason: String) { + GREYAssert(expression(), reason, details: "Expected the boolean expression to be true") +} + +public func GREYAssertFalse(_ expression: @autoclosure () -> Bool, reason: String) { + GREYAssert(!expression(), reason, details: "Expected the boolean expression to be false") +} + +public func GREYAssertNotNil(_ expression: @autoclosure ()-> Any?, reason: String) { + GREYAssert(expression() != nil, reason, details: "Expected expression to be not nil") +} + +public func GREYAssertNil(_ expression: @autoclosure () -> Any?, reason: String) { + GREYAssert(expression() == nil, reason, details: "Expected expression to be nil") +} + +public func GREYAssertEqual(_ left: @autoclosure () -> AnyObject?, + _ right: @autoclosure () -> AnyObject?, reason: String) { + GREYAssert(left() === right(), reason, details: "Expected left term to be equal to right term") +} + +public func GREYAssertNotEqual(_ left: @autoclosure () -> AnyObject?, + _ right: @autoclosure () -> AnyObject?, reason: String) { + GREYAssert(left() !== right(), reason, details: "Expected left term to not equal the right term") +} + +public func GREYAssertEqualObjects( _ left: @autoclosure () -> T?, _ right: @autoclosure () -> T?, reason: String) { + GREYAssert(left() == right(), reason, details: "Expected object of the left term to be equal" + + " to the object of the right term") +} + +public func GREYAssertNotEqualObjects( _ left: @autoclosure () -> T?, _ right: @autoclosure () -> T?, reason: String) { + GREYAssert(left() != right(), reason, details: "Expected object of the left term to not" + + " equal the object of the right term") +} + +public func GREYFail(_ reason: String) { + EarlGrey.handle(exception: GREYFrameworkException(name: kGREYAssertionFailedException, + reason: reason), + details: "") +} + +public func GREYFailWithDetails(_ reason: String, details: String) { + EarlGrey.handle(exception: GREYFrameworkException(name: kGREYAssertionFailedException, + reason: reason), + details: details) +} + +private func GREYAssert(_ expression: @autoclosure () -> Bool, + _ reason: String, details: String) { + GREYSetCurrentAsFailable() + if !expression() { + EarlGrey.handle(exception: GREYFrameworkException(name: kGREYAssertionFailedException, + reason: reason), + details: details) + } +} + +private func GREYSetCurrentAsFailable() { + let greyFailureHandlerSelector = + #selector(GREYFailureHandler.setInvocationFile(_:andInvocationLine:)) + let greyFailureHandler = + Thread.current.threadDictionary.value(forKey: kGREYFailureHandlerKey) as! GREYFailureHandler + if greyFailureHandler.responds(to: greyFailureHandlerSelector) { + greyFailureHandler.setInvocationFile!(#file, andInvocationLine:#line) + } +} + +open class EarlGrey: NSObject { + open class func select(elementWithMatcher matcher: GREYMatcher, + file: StaticString = #file, + line: UInt = #line) -> GREYElementInteraction { + return EarlGreyImpl.invoked(fromFile: file.description, lineNumber: line) + .selectElement(with: matcher) + } + + open class func setFailureHandler(handler: GREYFailureHandler, + file: StaticString = #file, + line: UInt = #line) { + return EarlGreyImpl.invoked(fromFile: file.description, lineNumber: line) + .setFailureHandler(handler) + } + + open class func handle(exception: GREYFrameworkException, + details: String, + file: StaticString = #file, + line: UInt = #line) { + return EarlGreyImpl.invoked(fromFile: file.description, lineNumber: line) + .handle(exception, details: details) + } + + @discardableResult open class func rotateDeviceTo(orientation: UIDeviceOrientation, + errorOrNil: UnsafeMutablePointer!, + file: StaticString = #file, + line: UInt = #line) + -> Bool { + return EarlGreyImpl.invoked(fromFile: file.description, lineNumber: line) + .rotateDevice(to: orientation, + errorOrNil: errorOrNil) + } +} + +extension GREYInteraction { + @discardableResult public func assert(_ matcher: @autoclosure () -> GREYMatcher) -> Self { + return self.assert(with:matcher()) + } + + @discardableResult public func assert(_ matcher: @autoclosure () -> GREYMatcher, + error: UnsafeMutablePointer!) -> Self { + return self.assert(with: matcher(), error: error) + } + + @discardableResult public func using(searchAction: GREYAction, + onElementWithMatcher matcher: GREYMatcher) -> Self { + return self.usingSearch(searchAction, onElementWith: matcher) + } +} + +extension GREYCondition { + open func waitWithTimeout(seconds: CFTimeInterval) -> Bool { + return self.wait(withTimeout: seconds) + } + + open func waitWithTimeout(seconds: CFTimeInterval, pollInterval: CFTimeInterval) + -> Bool { + return self.wait(withTimeout: seconds, pollInterval: pollInterval) + } +} diff --git a/mobile/ios/UITests/Global.swift b/mobile/ios/UITests/Global.swift new file mode 100644 index 0000000000..e8b3bd4a88 --- /dev/null +++ b/mobile/ios/UITests/Global.swift @@ -0,0 +1,670 @@ +/* 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/. */ + +import Foundation +import GCDWebServers +import Storage +import WebKit +import SwiftKeychainWrapper +import Shared +import EarlGrey +@testable import Client + +let LabelAddressAndSearch = "Address and Search" + +extension XCTestCase { + func tester(_ file: String = #file, _ line: Int = #line) -> KIFUITestActor { + return KIFUITestActor(inFile: file, atLine: line, delegate: self) + } + + func system(_ file: String = #file, _ line: Int = #line) -> KIFSystemTestActor { + return KIFSystemTestActor(inFile: file, atLine: line, delegate: self) + } +} + +extension KIFUITestActor { + /// Looks for a view with the given accessibility hint. + func tryFindingViewWithAccessibilityHint(_ hint: String) -> Bool { + let element = UIApplication.shared.accessibilityElement { element in + return element?.accessibilityHint! == hint + } + + return element != nil + } + + func waitForViewWithAccessibilityHint(_ hint: String) -> UIView? { + var view: UIView? = nil + autoreleasepool { + wait(for: nil, view: &view, withElementMatching: NSPredicate(format: "accessibilityHint = %@", hint), tappable: false) + } + return view + } + + func viewExistsWithLabel(_ label: String) -> Bool { + do { + try self.tryFindingView(withAccessibilityLabel: label) + return true + } catch { + return false + } + } + + func viewExistsWithLabelPrefixedBy(_ prefix: String) -> Bool { + let element = UIApplication.shared.accessibilityElement { element in + return element?.accessibilityLabel?.hasPrefix(prefix) ?? false + } + return element != nil + } + + /// Waits for and returns a view with the given accessibility value. + func waitForViewWithAccessibilityValue(_ value: String) -> UIView { + var element: UIAccessibilityElement! + + run { _ in + element = UIApplication.shared.accessibilityElement { element in + return element?.accessibilityValue == value + } + + return (element == nil) ? KIFTestStepResult.wait : KIFTestStepResult.success + } + + return UIAccessibilityElement.viewContaining(element) + } + + /// Wait for and returns a view with the given accessibility label as an + /// attributed string. See the comment in ReadingListPanel.swift about + /// using attributed strings as labels. (It lets us set the pitch) + func waitForViewWithAttributedAccessibilityLabel(_ label: NSAttributedString) -> UIView { + var element: UIAccessibilityElement! + + run { _ in + element = UIApplication.shared.accessibilityElement { element in + if let elementLabel = element?.value(forKey: "accessibilityLabel") as? NSAttributedString { + return elementLabel.isEqual(to: label) + } + return false + } + + return (element == nil) ? KIFTestStepResult.wait : KIFTestStepResult.success + } + + return UIAccessibilityElement.viewContaining(element) + } + + /// There appears to be a KIF bug where waitForViewWithAccessibilityLabel returns the parent + /// UITableView instead of the UITableViewCell with the given label. + /// As a workaround, retry until KIF gives us a cell. + /// Open issue: https://github.com/kif-framework/KIF/issues/336 + func waitForCellWithAccessibilityLabel(_ label: String) -> UITableViewCell { + var cell: UITableViewCell! + + run { _ in + let view = self.waitForView(withAccessibilityLabel: label) + cell = view as? UITableViewCell + return (cell == nil) ? KIFTestStepResult.wait : KIFTestStepResult.success + } + + return cell + } + + /** + * Finding views by accessibility label doesn't currently work with WKWebView: + * https://github.com/kif-framework/KIF/issues/460 + * As a workaround, inject a KIFHelper class that iterates the document and finds + * elements with the given textContent or title. + */ + func waitForWebViewElementWithAccessibilityLabel(_ text: String) { + run { error in + if self.hasWebViewElementWithAccessibilityLabel(text) { + return KIFTestStepResult.success + } + + return KIFTestStepResult.wait + } + } + + /** + * Sets the text for a WKWebView input element with the given name. + */ + func enterText(_ text: String, intoWebViewInputWithName inputName: String) { + let webView = getWebViewWithKIFHelper() + var stepResult = KIFTestStepResult.wait + + let escaped = text.replacingOccurrences(of: "\"", with: "\\\"") + webView.evaluateJavaScript("KIFHelper.enterTextIntoInputWithName(\"\(escaped)\", \"\(inputName)\");") { success, _ in + stepResult = (success as! Bool) ? KIFTestStepResult.success : KIFTestStepResult.failure + } + + run { error in + if stepResult == KIFTestStepResult.failure { + error?.pointee = NSError(domain: "KIFHelper", code: 0, userInfo: [NSLocalizedDescriptionKey: "Input element not found in webview: \(escaped)"]) + } + return stepResult + } + } + + /** + * Clicks a WKWebView element with the given label. + */ + func tapWebViewElementWithAccessibilityLabel(_ text: String) { + let webView = getWebViewWithKIFHelper() + var stepResult = KIFTestStepResult.wait + + let escaped = text.replacingOccurrences(of: "\"", with: "\\\"") + webView.evaluateJavaScript("KIFHelper.tapElementWithAccessibilityLabel(\"\(escaped)\")") { success, _ in + stepResult = (success as! Bool) ? KIFTestStepResult.success : KIFTestStepResult.failure + } + + run { error in + if stepResult == KIFTestStepResult.failure { + error?.pointee = NSError(domain: "KIFHelper", code: 0, userInfo: [NSLocalizedDescriptionKey: "Accessibility label not found in webview: \(escaped)"]) + } + return stepResult + } + } + + /** + * Determines whether an element in the page exists. + */ + func hasWebViewElementWithAccessibilityLabel(_ text: String) -> Bool { + let webView = getWebViewWithKIFHelper() + var stepResult = KIFTestStepResult.wait + var found = false + + let escaped = text.replacingOccurrences(of: "\"", with: "\\\"") + webView.evaluateJavaScript("KIFHelper.hasElementWithAccessibilityLabel(\"\(escaped)\")") { success, _ in + found = success as? Bool ?? false + stepResult = KIFTestStepResult.success + } + + run { _ in return stepResult } + + return found + } + + fileprivate func getWebViewWithKIFHelper() -> WKWebView { + let webView = waitForView(withAccessibilityLabel: "Web content") as! WKWebView + + // Wait for the web view to stop loading. + run { _ in + return webView.isLoading ? KIFTestStepResult.wait : KIFTestStepResult.success + } + + var stepResult = KIFTestStepResult.wait + + webView.evaluateJavaScript("typeof KIFHelper") { result, _ in + if result as! String == "undefined" { + let bundle = Bundle(for: BrowserTests.self) + let path = bundle.path(forResource: "KIFHelper", ofType: "js")! + let source = try! NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) + webView.evaluateJavaScript(source as String, completionHandler: nil) + } + stepResult = KIFTestStepResult.success + } + + run { _ in return stepResult } + + return webView + } + + public func deleteCharacterFromFirstResponser() { + self.enterText(intoCurrentFirstResponder: "\u{0008}") + } +} + +class BrowserUtils { + // Needs to be in sync with Client Clearables. + enum Clearable: String { + case History = "Browsing History" + case Cache = "Cache" + case OfflineData = "Offline Website Data" + case Cookies = "Cookies" + } + internal static let AllClearables = Set([Clearable.History, Clearable.Cache, Clearable.OfflineData, Clearable.Cookies]) + + /// Close all tabs to restore the browser to startup state. + class func resetToAboutHome(_ tester: KIFUITestActor) { + + do { + try tester.tryFindingTappableView(withAccessibilityLabel: "Cancel") + tester.tapView(withAccessibilityLabel: "Cancel") + } catch _ { + } + do { + try tester.tryFindingTappableView(withAccessibilityLabel: "Show Tabs") + tester.tapView(withAccessibilityLabel: "Show Tabs") + } catch _ { + + } + let tabsView = tester.waitForView(withAccessibilityLabel: "Tabs Tray").subviews.first as! UICollectionView + + // Switch to Private Mode if we're not in it already. + do { + try tester.tryFindingTappableView(withAccessibilityLabel: "Private Mode", value: "Off", traits: UIAccessibilityTraitButton) + tester.tapView(withAccessibilityLabel: "Private Mode") + } catch _ {} + + // Clear all private tabs. + while tabsView.numberOfItems(inSection: 0) > 0 { + let cell = tabsView.cellForItem(at: IndexPath(item: 0, section: 0))! + tester.swipeView(withAccessibilityLabel: cell.accessibilityLabel, in: KIFSwipeDirection.left) + tester.waitForAbsenceOfView(withAccessibilityLabel: cell.accessibilityLabel) + } + tester.tapView(withAccessibilityLabel: "Private Mode") + + while tabsView.numberOfItems(inSection: 0) > 1 { + let oldCount = tabsView.numberOfItems(inSection: 0) + let cell = tabsView.cellForItem(at: IndexPath(item: 0, section: 0))! + tester.swipeView(withAccessibilityLabel: cell.accessibilityLabel, in: KIFSwipeDirection.left) + tester.waitForAnimationsToFinish() + XCTAssertEqual(oldCount-1, tabsView.numberOfItems(inSection: 0)) + } + + // When the last tab is closed, the tabs tray will automatically be closed + // since a new about:home tab will be selected. + if let cell = tabsView.cellForItem(at: IndexPath(item: 0, section: 0)) { + tester.swipeView(withAccessibilityLabel: cell.accessibilityLabel, in: KIFSwipeDirection.left) + tester.waitForTappableView(withAccessibilityLabel: "Show Tabs") + } + } + + //If it is a first run, first run window should be gone + class func dismissFirstRunUI(_ tester: KIFUITestActor) { + do { + try tester.tryFindingView(withAccessibilityLabel: "Intro Tour Carousel") + tester.swipeView(withAccessibilityLabel: "Intro Tour Carousel", in: KIFSwipeDirection.left) + tester.waitForTappableView(withAccessibilityLabel: "Start Browsing") + tester.tapView(withAccessibilityLabel: "Start Browsing") + } catch { + //First run dialog did not appear + } + } + + class func dismissFirstRunUI() { + var error: NSError? + + let matcher = grey_allOf([ + grey_accessibilityID("IntroViewController.scrollView"), grey_sufficientlyVisible()]) + + EarlGrey.select(elementWithMatcher: matcher).assert(grey_notNil(), error: &error) + + if error == nil { + EarlGrey.select(elementWithMatcher: matcher).perform(grey_swipeFastInDirection(GREYDirection.left)) + let buttonMatcher = grey_allOf([ + grey_accessibilityID("IntroViewController.startBrowsingButton"), grey_sufficientlyVisible()]) + + EarlGrey.select(elementWithMatcher: buttonMatcher).assert(grey_notNil(), error: &error) + + if error == nil { + EarlGrey.select(elementWithMatcher: buttonMatcher).perform(grey_tap()) + } + } + } + + class func iPad() -> Bool { + return UIDevice.current.userInterfaceIdiom == .pad + } + + /// Injects a URL and title into the browser's history database. + class func addHistoryEntry(_ title: String, url: URL) { + let notificationCenter = NotificationCenter.default + var info = [AnyHashable: Any]() + info["url"] = url + info["title"] = title + info["visitType"] = VisitType.link.rawValue + notificationCenter.post(name: Notification.Name(rawValue: "OnLocationChange"), object: self, userInfo: info) + } + + fileprivate class func clearHistoryItemAtIndex(_ index: IndexPath, tester: KIFUITestActor) { + if let row = tester.waitForCell(at: index, inTableViewWithAccessibilityIdentifier: "History List") { + tester.swipeView(withAccessibilityLabel: row.accessibilityLabel, value: row.accessibilityValue, in: KIFSwipeDirection.left) + tester.tapView(withAccessibilityLabel: "Remove") + } + } + class func openClearPrivateDataDialog(_ swipe: Bool, tester: KIFUITestActor) { + tester.tapView(withAccessibilityLabel: "Menu") + + // Need this for simulator only + if swipe { + tester.swipeView(withAccessibilityLabel: "Set Homepage", in: KIFSwipeDirection.left) + } + tester.tapView(withAccessibilityLabel: "Settings") + tester.tapView(withAccessibilityLabel: "Clear Private Data") + } + + class func closeClearPrivateDataDialog(_ tester: KIFUITestActor) { + tester.tapView(withAccessibilityLabel: "Settings") + tester.tapView(withAccessibilityLabel: "Done") + } + + fileprivate class func acceptClearPrivateData(_ tester: KIFUITestActor) { + tester.waitForView(withAccessibilityLabel: "OK") + tester.tapView(withAccessibilityLabel: "OK") + tester.waitForView(withAccessibilityLabel: "Clear Private Data") + } + + fileprivate class func cancelClearPrivateData(_ tester: KIFUITestActor) { + tester.waitForView(withAccessibilityLabel: "Clear") + tester.tapView(withAccessibilityLabel: "Cancel") + tester.waitForView(withAccessibilityLabel: "Clear Private Data") + } + + class func clearPrivateData(_ clearables: Set? = AllClearables, swipe: Bool? = false, tester: KIFUITestActor) { + let AllClearables = Set([Clearable.History, Clearable.Cache, Clearable.OfflineData, Clearable.Cookies]) + + openClearPrivateDataDialog(swipe!, tester: tester) + + // Disable all items that we don't want to clear. + for clearable in AllClearables { + // If we don't wait here, setOn:forSwitchWithAccessibilityLabel tries to use the UITableViewCell + // instead of the UISwitch. KIF bug? + tester.waitForView(withAccessibilityLabel: clearable.rawValue) +// tester.setOn(clearables!.contains(clearable), forSwitchWithAccessibilityLabel: clearable.rawValue) + let switchControl = grey_allOf([grey_accessibilityLabel(clearable.rawValue), + grey_kindOfClass(UISwitch.self)]) + EarlGrey.select(elementWithMatcher: switchControl).perform(grey_turnSwitchOn(clearables!.contains(clearable))) + } + + + + tester.waitForView(withAccessibilityLabel: "Clear Private Data") + tester.tapView(withAccessibilityLabel: "Clear Private Data", traits: UIAccessibilityTraitButton) + acceptClearPrivateData(tester) + + closeClearPrivateDataDialog(tester) + } + + class func clearHistoryItems(_ tester: KIFUITestActor, numberOfTests: Int = -1) { + resetToAboutHome(tester) + tester.tapView(withAccessibilityLabel: "History") + + let historyTable = tester.waitForView(withAccessibilityIdentifier: "History List") as! UITableView + var index = 0 + for _ in 0 ..< historyTable.numberOfSections { + for _ in 0 ..< historyTable.numberOfRows(inSection: 0) { + clearHistoryItemAtIndex(IndexPath(row: 0, section: 0), tester: tester) + if numberOfTests > -1 { + index += 1 + if index == numberOfTests { + return + } + } + } + } + tester.tapView(withAccessibilityLabel: "Top sites") + } + + class func ensureAutocompletionResult(_ tester: KIFUITestActor, textField: UITextField, prefix: String, completion: String) { + // searches are async (and debounced), so we have to wait for the results to appear. + tester.waitForViewWithAccessibilityValue(prefix + completion) + + let autocompleteFieldlabel = textField.subviews.filter { $0.accessibilityIdentifier == "autocomplete" }.first as? UILabel + + if completion == "" { + XCTAssertTrue(autocompleteFieldlabel == nil, "The autocomplete was empty but the label still exists.") + return + } + + XCTAssertTrue(autocompleteFieldlabel != nil, "The autocomplete was not found") + XCTAssertEqual(completion, autocompleteFieldlabel!.text, "Expected prefix matches actual prefix") + + } +} + +class SimplePageServer { + class func getPageData(_ name: String, ext: String = "html") -> String { + let pageDataPath = Bundle(for: self).path(forResource: name, ofType: ext)! + return (try! NSString(contentsOfFile: pageDataPath, encoding: String.Encoding.utf8.rawValue)) as String + } + + class func start() -> String { + let webServer: GCDWebServer = GCDWebServer() + + webServer.addHandler(forMethod: "GET", path: "/image.png", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + let img = UIImagePNGRepresentation(UIImage(named: "goBack")!) + return GCDWebServerDataResponse(data: img, contentType: "image/png") + } + + for page in ["findPage", "noTitle", "readablePage", "JSPrompt"] { + webServer.addHandler(forMethod: "GET", path: "/\(page).html", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + return GCDWebServerDataResponse(html: self.getPageData(page)) + } + } + + // we may create more than one of these but we need to give them uniquie accessibility ids in the tab manager so we'll pass in a page number + webServer.addHandler(forMethod: "GET", path: "/scrollablePage.html", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + var pageData = self.getPageData("scrollablePage") + let page = Int((request?.query["page"] as! String))! + pageData = pageData.replacingOccurrences(of: "{page}", with: page.description) + return GCDWebServerDataResponse(html: pageData as String) + } + + webServer.addHandler(forMethod: "GET", path: "/numberedPage.html", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + var pageData = self.getPageData("numberedPage") + + let page = Int((request?.query["page"] as! String))! + pageData = pageData.replacingOccurrences(of: "{page}", with: page.description) + + return GCDWebServerDataResponse(html: pageData as String) + } + + webServer.addHandler(forMethod: "GET", path: "/readerContent.html", request: GCDWebServerRequest.self) { (request) -> GCDWebServerResponse! in + return GCDWebServerDataResponse(html: self.getPageData("readerContent")) + } + + webServer.addHandler(forMethod: "GET", path: "/loginForm.html", request: GCDWebServerRequest.self) { _ in + return GCDWebServerDataResponse(html: self.getPageData("loginForm")) + } + + webServer.addHandler(forMethod: "GET", path: "/navigationDelegate.html", request: GCDWebServerRequest.self) { _ in + return GCDWebServerDataResponse(html: self.getPageData("navigationDelegate")) + } + + webServer.addHandler(forMethod: "GET", path: "/localhostLoad.html", request: GCDWebServerRequest.self) { _ in + return GCDWebServerDataResponse(html: self.getPageData("localhostLoad")) + } + + webServer.addHandler(forMethod: "GET", path: "/auth.html", request: GCDWebServerRequest.self) { (request: GCDWebServerRequest?) in + // "user:pass", Base64-encoded. + let expectedAuth = "Basic dXNlcjpwYXNz" + + let response: GCDWebServerDataResponse + if request?.headers["Authorization"] as? String == expectedAuth && request?.query["logout"] == nil { + response = GCDWebServerDataResponse(html: "logged in") + } else { + // Request credentials if the user isn't logged in. + response = GCDWebServerDataResponse(html: "auth fail") + response.statusCode = 401 + response.setValue("Basic realm=\"test\"", forAdditionalHeader: "WWW-Authenticate") + } + + return response + } + + func htmlForImageBlockingTest(imageURL: String) -> String{ + let html = + """ + + TEST IMAGE BLOCKING + """ + return html + } + + // Add tracking protection check page + webServer.addHandler(forMethod: "GET", path: "/tracking-protection-test.html", request: GCDWebServerRequest.self) { (request: GCDWebServerRequest?) in + return GCDWebServerDataResponse(html: htmlForImageBlockingTest(imageURL: "http://ymail.com/favicon.ico")) + } + + // Add image blocking test page + webServer.addHandler(forMethod: "GET", path: "/hide-images-test.html", request: GCDWebServerRequest.self) { (request: GCDWebServerRequest?) in + return GCDWebServerDataResponse(html: htmlForImageBlockingTest(imageURL: "https://www.mozilla.com/favicon.ico")) + } + + + if !webServer.start(withPort: 0, bonjourName: nil) { + XCTFail("Can't start the GCDWebServer") + } + + // We use 127.0.0.1 explicitly here, rather than localhost, in order to avoid our + // history exclusion code (Bug 1188626). + let webRoot = "http://127.0.0.1:\(webServer.port)" + return webRoot + } +} + +class SearchUtils { + static func navigateToSearchSettings(_ tester: KIFUITestActor) { + let engine = SearchUtils.getDefaultEngine().shortName + tester.tapView(withAccessibilityLabel: "Menu") + tester.waitForAnimationsToFinish() + tester.tapView(withAccessibilityLabel: "Settings") + tester.waitForView(withAccessibilityLabel: "Settings") + tester.tapView(withAccessibilityLabel: "Search, \(engine)") + tester.waitForView(withAccessibilityIdentifier: "Search") + } + + static func navigateFromSearchSettings(_ tester: KIFUITestActor) { + tester.tapView(withAccessibilityLabel: "Settings") + tester.tapView(withAccessibilityLabel: "Done") + } + + // Given that we're at the Search Settings sheet, select the named search engine as the default. + // Afterwards, we're still at the Search Settings sheet. + static func selectDefaultSearchEngineName(_ tester: KIFUITestActor, engineName: String) { + tester.tapView(withAccessibilityLabel: "Default Search Engine", traits: UIAccessibilityTraitButton) + tester.waitForView(withAccessibilityLabel: "Default Search Engine") + tester.tapView(withAccessibilityLabel: engineName) + tester.waitForView(withAccessibilityLabel: "Search") + } + + // Given that we're at the Search Settings sheet, return the default search engine's name. + static func getDefaultSearchEngineName(_ tester: KIFUITestActor) -> String { + let view = tester.waitForCellWithAccessibilityLabel("Default Search Engine") + return view.accessibilityValue! + } + + static func getDefaultEngine() -> OpenSearchEngine! { + guard let userProfile = (UIApplication.shared.delegate as? AppDelegate)?.profile else { + XCTFail("Unable to get a reference to the user's profile") + return nil + } + return userProfile.searchEngines.defaultEngine + } +/* + static func youTubeSearchEngine() -> OpenSearchEngine { + return mockSearchEngine("YouTube", template: "https://m.youtube.com/#/results?q={searchTerms}&sm=", icon: "youtube")! + } + + static func mockSearchEngine(_ name: String, template: String, icon: String) -> OpenSearchEngine? { + guard let imagePath = Bundle(for: self).path(forResource: icon, ofType: "ico"), + let imageData = Data(contentsOfFile: imagePath), + let image = UIImage(data: imageData) else { + XCTFail("Unable to load search engine image named \(icon).ico") + return nil + } + + return OpenSearchEngine(engineID: nil, shortName: name, image: image, searchTemplate: template, suggestTemplate: nil, isCustomEngine: true) + } +*/ + static func addCustomSearchEngine(_ engine: OpenSearchEngine) { + guard let userProfile = (UIApplication.shared.delegate as? AppDelegate)?.profile else { + XCTFail("Unable to get a reference to the user's profile") + return + } + + userProfile.searchEngines.addSearchEngine(engine) + } + + static func removeCustomSearchEngine(_ engine: OpenSearchEngine) { + guard let userProfile = (UIApplication.shared.delegate as? AppDelegate)?.profile else { + XCTFail("Unable to get a reference to the user's profile") + return + } + + userProfile.searchEngines.deleteCustomEngine(engine) + } +} + +// From iOS 10, below methods no longer works +class DynamicFontUtils { + // Need to leave time for the notification to propagate + static func bumpDynamicFontSize(_ tester: KIFUITestActor) { + let value = UIContentSizeCategory.accessibilityExtraLarge + UIApplication.shared.setValue(value, forKey: "preferredContentSizeCategory") + tester.wait(forTimeInterval: 0.3) + } + + static func lowerDynamicFontSize(_ tester: KIFUITestActor) { + let value = UIContentSizeCategory.extraSmall + UIApplication.shared.setValue(value, forKey: "preferredContentSizeCategory") + tester.wait(forTimeInterval: 0.3) + } + + static func restoreDynamicFontSize(_ tester: KIFUITestActor) { + let value = UIContentSizeCategory.medium + UIApplication.shared.setValue(value, forKey: "preferredContentSizeCategory") + tester.wait(forTimeInterval: 0.3) + } +} + +class PasscodeUtils { + static func resetPasscode() { + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(nil) + } + + static func setPasscode(_ code: String, interval: PasscodeInterval) { + let info = AuthenticationKeychainInfo(passcode: code) + info.updateRequiredPasscodeInterval(interval) + KeychainWrapper.sharedAppContainerKeychain.setAuthenticationInfo(info) + } + + static func enterPasscode(_ tester: KIFUITestActor, digits: String) { + tester.tapView(withAccessibilityLabel: String(digits.characters[digits.startIndex])) + tester.tapView(withAccessibilityLabel: String(digits.characters[digits.characters.index(digits.startIndex, offsetBy: 1)])) + tester.tapView(withAccessibilityLabel: String(digits.characters[digits.characters.index(digits.startIndex, offsetBy: 2)])) + tester.tapView(withAccessibilityLabel: String(digits.characters[digits.characters.index(digits.startIndex, offsetBy: 3)])) + } +} + +class HomePageUtils { + static func navigateToHomePageSettings(_ tester: KIFUITestActor) { + tester.waitForAnimationsToFinish() + tester.tapView(withAccessibilityLabel: "Menu") + tester.tapView(withAccessibilityLabel: "Settings") + tester.tapView(withAccessibilityIdentifier: "Homepage") + } + + static func homePageSetting(_ tester: KIFUITestActor) -> String? { + let view = tester.waitForView(withAccessibilityIdentifier: "HomePageSettingTextField") + guard let textField = view as? UITextField else { + XCTFail("View is not a textField: view is \(String(describing: view))") + return nil + } + return textField.text + } + + static func navigateFromHomePageSettings(_ tester: KIFUITestActor) { + tester.tapView(withAccessibilityLabel: "Settings") + tester.tapView(withAccessibilityLabel: "Done") + } +} diff --git a/mobile/ios/UITests/HistoryTests.swift b/mobile/ios/UITests/HistoryTests.swift new file mode 100644 index 0000000000..9e5ee32921 --- /dev/null +++ b/mobile/ios/UITests/HistoryTests.swift @@ -0,0 +1,149 @@ +/* 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/. */ + +import Foundation +import WebKit +import EarlGrey + +class HistoryTests: KIFTestCase { + fileprivate var webRoot: String! + + override func setUp() { + super.setUp() + webRoot = SimplePageServer.start() + BrowserUtils.dismissFirstRunUI() + } + + func addHistoryItemPage(_ pageNo: Int) -> String { + // Load a page + let url = "\(webRoot!)/numberedPage.html?page=\(pageNo)" + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_replaceText(url)) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_typeText("\n")) + tester().waitForWebViewElementWithAccessibilityLabel("Page \(pageNo)") + return url + } + + func addHistoryItems(_ noOfItemsToAdd: Int) -> [String] { + var urls = [String]() + for index in 1...noOfItemsToAdd { + urls.append(addHistoryItemPage(index)) + } + return urls + } + + /** + * Tests for listed history visits + */ + func testAddHistoryUI() { + _ = addHistoryItems(2) + + // Check that both appear in the history home panel + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("History")).perform(grey_tap()) + + // Wait until the dialog shows up + let listAppeared = GREYCondition(name: "Wait the history list to appear", block: { _ in + var errorOrNil: NSError? + let matcher = grey_allOf([grey_accessibilityLabel("Page 2"), + grey_sufficientlyVisible()]) + EarlGrey.select(elementWithMatcher: matcher) + .inRoot(grey_accessibilityID("History List")) + .assert(grey_notNil(), error: &errorOrNil) + return errorOrNil == nil + }).wait(withTimeout: 20) + GREYAssertTrue(listAppeared, reason: "Failed to display history") + + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Page 2")) + .inRoot(grey_accessibilityID("History List")) + .assert(grey_sufficientlyVisible()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Page 1")) + .inRoot(grey_accessibilityID("History List")) + .assert(grey_sufficientlyVisible()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("\(webRoot!)/numberedPage.html?page=2")) + .inRoot(grey_accessibilityID("History List")) + .assert(grey_sufficientlyVisible()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("\(webRoot!)/numberedPage.html?page=1")) + .inRoot(grey_accessibilityID("History List")) + .assert(grey_sufficientlyVisible()) + + EarlGrey.select(elementWithMatcher: grey_accessibilityID("goBack")).perform(grey_tap()) + } + + func testDeleteHistoryItemFromListWith2Items() { + // add 2 history items + let urls = addHistoryItems(2) + + // Check that both appear in the history home panel + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("History")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel(urls[0])) + .perform(grey_longPress()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Delete from History")) + .inRoot(grey_kindOfClass(NSClassFromString("UITableViewCellContentView")!)) + .perform(grey_tap()) + + // The second history entry still exists + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel(urls[1])) + .inRoot(grey_kindOfClass(NSClassFromString("UITableViewCellContentView")!)) + .assert(grey_notNil()) + + // check page 1 does not exist + let historyRemoved = GREYCondition(name: "Check entry is removed", block: { _ in + var errorOrNil: NSError? + let matcher = grey_allOf([grey_accessibilityLabel(urls[0]), + grey_sufficientlyVisible()]) + EarlGrey.select(elementWithMatcher: matcher).assert(grey_notNil(), error: &errorOrNil) + let success = errorOrNil != nil + return success + }).wait(withTimeout: 5) + GREYAssertTrue(historyRemoved, reason: "Failed to remove history") + + EarlGrey.select(elementWithMatcher:grey_accessibilityID("goBack")).perform(grey_tap()) + } + + func testDeleteHistoryItemFromListWithMoreThan100Items() { + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Top sites")).perform(grey_tap()) + + for pageNo in 1...102 { + BrowserUtils.addHistoryEntry("Page \(pageNo)", url: URL(string: "\(webRoot!)/numberedPage.html?page=\(pageNo)")!) + } + let urlToDelete = "\(webRoot!)/numberedPage.html?page=\(102)" + let oldestUrl = "\(webRoot!)/numberedPage.html?page=\(101)" + + EarlGrey.select(elementWithMatcher:grey_accessibilityLabel("History")) + .perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Page 102")).inRoot(grey_kindOfClass(NSClassFromString("UITableView")!)).perform(grey_swipeSlowInDirectionWithStartPoint(.left, 0.4, 0.4)) + EarlGrey.select(elementWithMatcher:grey_accessibilityLabel("Delete")) + .inRoot(grey_kindOfClass(NSClassFromString("UISwipeActionStandardButton")!)) + .perform(grey_tap()) + + // The history list still exists + EarlGrey.select(elementWithMatcher: grey_accessibilityID("History List")) + .assert(grey_notNil()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel(oldestUrl)) + .assert(grey_notNil()) + + // check page 1 does not exist + let historyRemoved = GREYCondition(name: "Check entry is removed", block: { _ in + var errorOrNil: NSError? + let matcher = grey_allOf([grey_accessibilityLabel(urlToDelete), + grey_sufficientlyVisible()]) + EarlGrey.select(elementWithMatcher:matcher).assert(grey_notNil(), error: &errorOrNil) + let success = errorOrNil != nil + return success + }).wait(withTimeout: 5) + GREYAssertTrue(historyRemoved, reason: "Failed to remove history") + + EarlGrey.select(elementWithMatcher:grey_accessibilityID("goBack")).perform(grey_tap()) + } + + override func tearDown() { + //BrowserUtils.resetToAboutHome(tester()) + BrowserUtils.clearPrivateData(tester: tester()) + super.tearDown() + } +} diff --git a/mobile/ios/UITests/Info.plist b/mobile/ios/UITests/Info.plist new file mode 100644 index 0000000000..9411e4a06e --- /dev/null +++ b/mobile/ios/UITests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/UITests/JSPrompt.html b/mobile/ios/UITests/JSPrompt.html new file mode 100644 index 0000000000..698c3cf460 --- /dev/null +++ b/mobile/ios/UITests/JSPrompt.html @@ -0,0 +1,25 @@ + + + + JS Prompt + + + + +
JS Prompt
+ +
+ Click the 'Mana' button, sit idle on the auth prompt + + This page will popup alert after 6 seconds + + Click cancel on the auth prompt when focus returns to this page +
+ + + + \ No newline at end of file diff --git a/mobile/ios/UITests/KIFHelper.js b/mobile/ios/UITests/KIFHelper.js new file mode 100644 index 0000000000..f056fca996 --- /dev/null +++ b/mobile/ios/UITests/KIFHelper.js @@ -0,0 +1,60 @@ +/* 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/. */ + +var KIFHelper = { + /** + * Determines whether an element with the given accessibility label exists. + * @return True if an element was found + */ + hasElementWithAccessibilityLabel: function (value) { + return this._getElementWithAccessibilityLabel(document.body, value) !== null; + }, + + _getElementWithAccessibilityLabel: function (el, value) { + if (el.textContent == value || el.title == value || el.value == value) { + return el; + } + + for (var i = 0; i < el.children.length; i++) { + var found = this._getElementWithAccessibilityLabel(el.children[i], value); + if (found) { + return found; + } + } + + return null; + }, + + /** + * Sets the text for an input element with the given name. + * @return True if successful + */ + enterTextIntoInputWithName: function (text, name) { + var inputs = document.getElementsByName(name); + if (inputs.length !== 1) { + return false; + } + + var input = inputs[0]; + if (input.tagName !== "INPUT") { + return false; + } + + input.value = text; + return true; + }, + + /** + * Taps an element with the given accessibility label. + * @return True if successful + */ + tapElementWithAccessibilityLabel: function (label) { + var found = this._getElementWithAccessibilityLabel(document.body, label); + if (found) { + found.click(); + return true; + } + return false; + }, +}; diff --git a/mobile/ios/UITests/LoginInputTests.swift b/mobile/ios/UITests/LoginInputTests.swift new file mode 100644 index 0000000000..df9827389f --- /dev/null +++ b/mobile/ios/UITests/LoginInputTests.swift @@ -0,0 +1,124 @@ +/* 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/. */ + +import Foundation +import EarlGrey +@testable import Client + +class LoginInputTests: KIFTestCase { + fileprivate var webRoot: String! + fileprivate var profile: Profile! + + override func setUp() { + super.setUp() + profile = (UIApplication.shared.delegate as! AppDelegate).profile! + webRoot = SimplePageServer.start() + BrowserUtils.dismissFirstRunUI() + } + + override func tearDown() { + _ = profile.logins.removeAll().value + BrowserUtils.resetToAboutHome(tester()) + BrowserUtils.clearPrivateData(tester: tester()) + super.tearDown() + } + + func enterUrl(url: String) { + EarlGrey.select(elementWithMatcher: grey_accessibilityID("url")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_replaceText(url)) + EarlGrey.select(elementWithMatcher: grey_accessibilityID("address")).perform(grey_typeText("\n")) + } + + func waitForLoginDialog(text: String, appears: Bool = true) { + var success = false + var failedReason = "Failed to display dialog" + + if appears == false { + failedReason = "Dialog still displayed" + } + + let saveLoginDialog = GREYCondition(name: "Check login dialog appears", block: { _ in + var errorOrNil: NSError? + let matcher = grey_allOf([grey_accessibilityLabel(text), + grey_sufficientlyVisible()]) + EarlGrey.select(elementWithMatcher: matcher) + .assert(grey_notNil(), error: &errorOrNil) + if appears == true { + success = errorOrNil == nil + } else { + success = errorOrNil != nil + } + return success + }).wait(withTimeout: 10) + + GREYAssertTrue(saveLoginDialog, reason: failedReason) + } + + func testLoginFormDisplaysNewSnackbar() { + let url = "\(webRoot!)/loginForm.html" + let username = "test@user.com" + + enterUrl(url: url) + tester().enterText(username, intoWebViewInputWithName: "username") + tester().enterText("password", intoWebViewInputWithName: "password") + tester().tapWebViewElementWithAccessibilityLabel("submit_btn") + + waitForLoginDialog(text: "Save login \(username) for \(self.webRoot!)?") + EarlGrey.select(elementWithMatcher: grey_accessibilityID("SaveLoginPrompt.dontSaveButton")).perform(grey_tap()) + } + + func testLoginFormDisplaysUpdateSnackbarIfPreviouslySaved() { + let url = "\(webRoot!)/loginForm.html" + let username = "test@user.com" + let password1 = "password1" + let password2 = "password2" + + enterUrl(url: url) + tester().enterText(username, intoWebViewInputWithName: "username") + tester().enterText(password1, intoWebViewInputWithName: "password") + tester().tapWebViewElementWithAccessibilityLabel("submit_btn") + waitForLoginDialog(text: "Save login \(username) for \(self.webRoot!)?") + EarlGrey.select(elementWithMatcher: grey_accessibilityID("SaveLoginPrompt.saveLoginButton")) + .perform(grey_tap()) + + tester().enterText(username, intoWebViewInputWithName: "username") + tester().enterText(password2, intoWebViewInputWithName: "password") + tester().tapWebViewElementWithAccessibilityLabel("submit_btn") + waitForLoginDialog(text: "Update login \(username) for \(self.webRoot!)?") + EarlGrey.select(elementWithMatcher: grey_accessibilityID("UpdateLoginPrompt.updateButton")) + .perform(grey_tap()) + } + + func testLoginFormDoesntOfferSaveWhenEmptyPassword() { + let url = "\(webRoot!)/loginForm.html" + let username = "test@user.com" + + enterUrl(url: url) + tester().enterText(username, intoWebViewInputWithName: "username") + tester().enterText("", intoWebViewInputWithName: "password") + tester().tapWebViewElementWithAccessibilityLabel("submit_btn") + + waitForLoginDialog(text: "Save login \(username) for \(self.webRoot!)?", appears: false) + } + + func testLoginFormDoesntOfferUpdateWhenEmptyPassword() { + let url = "\(webRoot!)/loginForm.html" + let username = "test@user.com" + let password1 = "password1" + let password2 = "" + + enterUrl(url: url) + tester().enterText(username, intoWebViewInputWithName: "username") + tester().enterText(password1, intoWebViewInputWithName: "password") + tester().tapWebViewElementWithAccessibilityLabel("submit_btn") + waitForLoginDialog(text: "Save login \(username) for \(self.webRoot!)?") + EarlGrey.select(elementWithMatcher: grey_accessibilityID("SaveLoginPrompt.saveLoginButton")) + .perform(grey_tap()) + + tester().enterText(username, intoWebViewInputWithName: "username") + tester().enterText(password2, intoWebViewInputWithName: "password") + tester().tapWebViewElementWithAccessibilityLabel("submit_btn") + waitForLoginDialog(text: "Save login \(username) for \(self.webRoot!)?", appears: false) + } +} diff --git a/mobile/ios/UITests/LoginManagerTests.swift b/mobile/ios/UITests/LoginManagerTests.swift new file mode 100644 index 0000000000..917deda0a5 --- /dev/null +++ b/mobile/ios/UITests/LoginManagerTests.swift @@ -0,0 +1,706 @@ +/* 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/. */ + +import Foundation +import Storage +import EarlGrey +@testable import Client + +class LoginManagerTests: KIFTestCase { + + fileprivate var webRoot: String! + + override func setUp() { + super.setUp() + PasscodeUtils.resetPasscode() + webRoot = SimplePageServer.start() + generateLogins() + BrowserUtils.dismissFirstRunUI() + } + + override func tearDown() { + super.tearDown() + clearLogins() + PasscodeUtils.resetPasscode() + BrowserUtils.resetToAboutHome(tester()) + } + + fileprivate func openLoginManager() { + // Wait until the dialog shows up + let menuAppeared = GREYCondition(name: "Wait the Settings dialog to appear", block: { () -> Bool in + var errorOrNil: NSError? + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Logins")).assert(grey_notNil(), error: &errorOrNil) + let success = errorOrNil == nil + return success + }) + + if BrowserUtils.iPad() { + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Menu")).perform(grey_tap()) + let settings_button = grey_allOf([grey_accessibilityLabel("Settings"), + grey_accessibilityID("menu-Settings")]) + EarlGrey.select(elementWithMatcher: settings_button).perform(grey_tap()) + } else { + let menu_button = grey_allOf([grey_accessibilityLabel("Menu"), + grey_accessibilityID("TabToolbar.menuButton")]) + EarlGrey.select(elementWithMatcher: menu_button).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_text("Settings")).perform(grey_tap()) + } + + let success = menuAppeared?.wait(withTimeout: 20) + GREYAssertTrue(success!, reason: "Failed to display settings dialog") + + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Logins")).perform(grey_tap()) + } + + fileprivate func closeLoginManager() { + tester().tapView(withAccessibilityLabel: "Settings") + tester().tapView(withAccessibilityLabel: "Done") + } + + fileprivate func generateLogins() { + let profile = (UIApplication.shared.delegate as! AppDelegate).profile! + + let prefixes = "abcdefghijk" + let numRange = (0..<20) + + let passwords = generateStringListWithFormat("password%@%d", numRange: numRange, prefixes: prefixes) + let hostnames = generateStringListWithFormat("http://%@%d.com", numRange: numRange, prefixes: prefixes) + let usernames = generateStringListWithFormat("%@%d@email.com", numRange: numRange, prefixes: prefixes) + + (0..<(numRange.count * prefixes.characters.count)).forEach { index in + let login = Login(guid: "\(index)", hostname: hostnames[index], username: usernames[index], password: passwords[index]) + login.formSubmitURL = hostnames[index] + profile.logins.addLogin(login).value + } + } + + func waitForMatcher(name: String) { + let matcher = grey_allOf([grey_accessibilityLabel(name), + grey_kindOfClass(NSClassFromString("UICalloutBarButton")!), + grey_sufficientlyVisible()]) + + let menuShown = GREYCondition(name: "Wait for " + name) { + var errorOrNil: NSError? + + EarlGrey.select(elementWithMatcher: matcher).assert(grey_notNil(), error: &errorOrNil) + let success = errorOrNil == nil + return success + } + let success = menuShown?.wait(withTimeout: 10) + GREYAssertTrue(success!, reason: name + " Menu not shown") + EarlGrey.select(elementWithMatcher: matcher).perform(grey_tap()) + } + + fileprivate func generateStringListWithFormat(_ format: String, numRange: CountableRange, prefixes: String) -> [String] { + return prefixes.characters.map { char in + + return numRange.map { num in + return String(format: format, "\(char)", num) + } + } .flatMap { $0 } + } + + fileprivate func clearLogins() { + let profile = (UIApplication.shared.delegate as! AppDelegate).profile! + profile.logins.removeAll().value + } + + func testListFiltering() { + openLoginManager() + + var list = tester().waitForView(withAccessibilityIdentifier: "Login List") as! UITableView + + // Filter by username + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "Enter Search Mode") + tester().waitForAnimationsToFinish() + + // In simulator, the typing is too fast for the screen to be updated properly + // pausing after 'password' (which all login password contains) to update the screen seems to make the test reliable + tester().enterText(intoCurrentFirstResponder: "k10") + tester().wait(forTimeInterval: 3) // Wait until the table is updated + tester().waitForAnimationsToFinish() + tester().enterText(intoCurrentFirstResponder: "@email.com") + tester().wait(forTimeInterval: 3) // Wait until the table is updated + tester().waitForAnimationsToFinish() + list = tester().waitForView(withAccessibilityIdentifier: "Login List") as! UITableView + tester().waitForView(withAccessibilityLabel: "k10@email.com") + + XCTAssertEqual(list.numberOfRows(inSection: 0), 1) + + tester().tapView(withAccessibilityLabel: "Clear Search") + // Filter by hostname + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "Enter Search Mode") + tester().waitForAnimationsToFinish() + tester().enterText(intoCurrentFirstResponder: "http://k10") + tester().waitForAnimationsToFinish() + tester().wait(forTimeInterval: 3) // Wait until the table is updated + tester().enterText(intoCurrentFirstResponder: ".com") + tester().wait(forTimeInterval: 3) // Wait until the table is updated + list = tester().waitForView(withAccessibilityIdentifier: "Login List") as! UITableView + tester().waitForView(withAccessibilityLabel: "k10@email.com") + XCTAssertEqual(list.numberOfRows(inSection: 0), 1) + + tester().tapView(withAccessibilityLabel: "Clear Search") + // Filter by password + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "Enter Search Mode") + tester().waitForAnimationsToFinish() + tester().enterText(intoCurrentFirstResponder: "password") + tester().waitForAnimationsToFinish() + tester().wait(forTimeInterval: 3) // Wait until the table is updated + tester().enterText(intoCurrentFirstResponder: "d9") + tester().waitForAnimationsToFinish() + list = tester().waitForView(withAccessibilityIdentifier: "Login List") as! UITableView + tester().waitForView(withAccessibilityLabel: "d9@email.com") + tester().wait(forTimeInterval: 3) // Wait until the table is updated + XCTAssertEqual(list.numberOfRows(inSection: 0), 1) + + tester().tapView(withAccessibilityLabel: "Clear Search") + // Filter by something that doesn't match anything + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "Enter Search Mode") + tester().enterText(intoCurrentFirstResponder: "thisdoesntmatch") + tester().waitForView(withAccessibilityIdentifier: "Login List") + + // KIFTest has a bug where waitForViewWithAccessibilityLabel causes the lists to appear again on device, + // so checking the number of rows instead + tester().waitForView(withAccessibilityLabel: "No logins found") + let loginCount = countOfRowsInTableView(list) + XCTAssertEqual(loginCount, 0) + + closeLoginManager() + } + + func testListIndexView() { + openLoginManager() + + // Swipe the index view to navigate to bottom section + tester().waitForAnimationsToFinish() + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().swipeView(withAccessibilityLabel: "table index", in: KIFSwipeDirection.down) + tester().waitForView(withAccessibilityLabel: "k0@email.com, http://k0.com") + closeLoginManager() + } + + + func testDetailPasswordMenuOptions() { + openLoginManager() + + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "a0@email.com, http://a0.com") + + tester().waitForView(withAccessibilityLabel: "password") + + var passwordField = tester().waitForView(withAccessibilityIdentifier: "passwordField") as! UITextField + XCTAssertTrue(passwordField.isSecureTextEntry) + + // Tap the ‘Reveal’ menu option + EarlGrey.select(elementWithMatcher: grey_accessibilityID("passwordField")).perform(grey_tap()) + waitForMatcher(name: "Reveal") + passwordField = tester().waitForView(withAccessibilityIdentifier: "passwordField") as! UITextField + XCTAssertFalse(passwordField.isSecureTextEntry) + + // Tap the ‘Hide’ menu option + EarlGrey.select(elementWithMatcher: grey_accessibilityID("passwordField")).perform(grey_tap()) + waitForMatcher(name: "Hide") + passwordField = tester().waitForView(withAccessibilityIdentifier: "passwordField") as! UITextField + XCTAssertTrue(passwordField.isSecureTextEntry) + + // Tap the ‘Copy’ menu option + EarlGrey.select(elementWithMatcher: grey_accessibilityID("passwordField")).perform(grey_tap()) + waitForMatcher(name: "Copy") + + tester().tapView(withAccessibilityLabel: "Logins") + closeLoginManager() + XCTAssertEqual(UIPasteboard.general.string, "passworda0") + } + + func testDetailWebsiteMenuCopy() { + openLoginManager() + + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "a0@email.com, http://a0.com") + + tester().waitForView(withAccessibilityLabel: "password") + + EarlGrey.select(elementWithMatcher: grey_accessibilityID("websiteField")).perform(grey_tap()) + waitForMatcher(name: "Copy") + + // Tap the 'Open & Fill' menu option just checks to make sure we navigate to the web page + EarlGrey.select(elementWithMatcher: grey_accessibilityID("websiteField")).perform(grey_tap()) + waitForMatcher(name: "Open & Fill") + + tester().wait(forTimeInterval: 2) + tester().waitForViewWithAccessibilityValue("a0.com/") + XCTAssertEqual(UIPasteboard.general.string, "http://a0.com") + } + + func testOpenAndFillFromNormalContext() { + openLoginManager() + + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "a0@email.com, http://a0.com") + + tester().waitForView(withAccessibilityLabel: "password") + + // Tap the 'Open & Fill' menu option just checks to make sure we navigate to the web page + EarlGrey.select(elementWithMatcher: grey_accessibilityID("websiteField")).perform(grey_tap()) + waitForMatcher(name: "Open & Fill") + + tester().wait(forTimeInterval: 5) + tester().waitForViewWithAccessibilityValue("a0.com/") + } + + func testOpenAndFillFromPrivateContext() { + if BrowserUtils.iPad() { + EarlGrey.select(elementWithMatcher: grey_accessibilityID("TopTabsViewController.tabsButton")) + .perform(grey_tap()) + } else { + EarlGrey.select(elementWithMatcher: grey_accessibilityID("TabToolbar.tabsButton")).perform(grey_tap()) + } + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Private Mode")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Add Tab")).perform(grey_tap()) + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Menu")).perform(grey_tap()) + if BrowserUtils.iPad() { + let settings_button = grey_allOf([grey_accessibilityLabel("Settings"), + grey_accessibilityID("menu-Settings")]) + EarlGrey.select(elementWithMatcher: settings_button).perform(grey_tap()) + } else { + EarlGrey.select(elementWithMatcher: grey_text("Settings")).perform(grey_tap()) + } + EarlGrey.select(elementWithMatcher: grey_accessibilityLabel("Logins")).perform(grey_tap()) + + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "a0@email.com, http://a0.com") + + tester().waitForView(withAccessibilityLabel: "password") + + // Tap the 'Open & Fill' menu option just checks to make sure we navigate to the web page + EarlGrey.select(elementWithMatcher: grey_accessibilityID("websiteField")).perform(grey_tap()) + waitForMatcher(name: "Open & Fill") + + tester().wait(forTimeInterval: 2) + tester().waitForViewWithAccessibilityValue("a0.com/") + } + + func testDetailUsernameMenuOptions() { + openLoginManager() + + tester().waitForView(withAccessibilityLabel: "a0@email.com, http://a0.com") + tester().tapView(withAccessibilityLabel: "a0@email.com, http://a0.com") + + tester().waitForView(withAccessibilityLabel: "password") + + // Tap the 'Open & Fill' menu option just checks to make sure we navigate to the web page + EarlGrey.select(elementWithMatcher: grey_accessibilityID("usernameField")).perform(grey_tap()) + waitForMatcher(name: "Copy") + + tester().tapView(withAccessibilityLabel: "Logins") + closeLoginManager() + XCTAssertEqual(UIPasteboard.general.string!, "a0@email.com") + } + + func testListSelection() { + openLoginManager() + + tester().waitForAnimationsToFinish() + tester().tapView(withAccessibilityLabel: "Edit") + tester().waitForAnimationsToFinish() + + // Select one entry + let firstIndexPath = IndexPath(row: 0, section: 0) + tester().tapRow(at: firstIndexPath, inTableViewWithAccessibilityIdentifier: "Login List") + tester().waitForView(withAccessibilityLabel: "Delete") + + let list = tester().waitForView(withAccessibilityIdentifier: "Login List") as! UITableView + let firstCell = list.cellForRow(at: firstIndexPath)! + XCTAssertTrue(firstCell.isSelected) + + // Deselect first row + tester().tapRow(at: firstIndexPath, inTableViewWithAccessibilityIdentifier: "Login List") + XCTAssertFalse(firstCell.isSelected) + + // Cancel + tester().tapView(withAccessibilityLabel: "Cancel") + tester().waitForView(withAccessibilityLabel: "Edit") + + // Select multiple logins + tester().tapView(withAccessibilityLabel: "Edit") + tester().waitForAnimationsToFinish() + + let pathsToSelect = (0..<3).map { IndexPath(row: $0, section: 0) } + pathsToSelect.forEach { path in + tester().tapRow(at: path, inTableViewWithAccessibilityIdentifier: "Login List") + } + tester().waitForView(withAccessibilityLabel: "Delete") + + pathsToSelect.forEach { path in + XCTAssertTrue(list.cellForRow(at: path)!.isSelected) + } + + // Deselect only first row + tester().tapRow(at: firstIndexPath, inTableViewWithAccessibilityIdentifier: "Login List") + XCTAssertFalse(firstCell.isSelected) + + // Make sure delete is still showing + tester().waitForView(withAccessibilityLabel: "Delete") + + // Deselect the rest + let pathsWithoutFirst = pathsToSelect[1.. Int { + var count = 0 + (0.. +#import +#import +#import +#import + +#endif diff --git a/mobile/ios/UITests/ViewMemoryLeakTests.swift b/mobile/ios/UITests/ViewMemoryLeakTests.swift new file mode 100644 index 0000000000..33838618ce --- /dev/null +++ b/mobile/ios/UITests/ViewMemoryLeakTests.swift @@ -0,0 +1,124 @@ +/* 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/. */ + +import Foundation +import WebKit + +/// This test should be disabled since getTopViewController() crashes with iOS 10 +/// ------------------------------------------------------------------------------ +/// Set of tests that wait for weak references to views to be cleared. Technically, this is +/// non-deterministic and there are no guarantees the references will be set to nil. In practice, +/// though, the references are consistently cleared, which should be good enough for testing. +class ViewMemoryLeakTests: KIFTestCase, UITextFieldDelegate { + fileprivate var webRoot: String! + + override func setUp() { + webRoot = SimplePageServer.start() + } + + override func tearDown() { + do { + try tester().tryFindingTappableView(withAccessibilityLabel: "home") + tester().tapView(withAccessibilityLabel: "home") + } catch _ { + } + BrowserUtils.resetToAboutHome(tester()) + } + /* + func testAboutHomeDisposed() { + // about:home is already active on startup; grab a reference to it. + let browserViewController = getTopViewController() + weak var aboutHomeController = getChildViewController(browserViewController, childClass: "HomePanelViewController") + + // Change the page to make about:home go away. + tester().tapViewWithAccessibilityIdentifier("url") + let url = "\(webRoot)/numberedPage.html?page=1" + + // Work around potential KIF bug. The nillification does not seem to propagate unless we use and explicit autorelease pool. + // https://github.com/kif-framework/KIF/issues/739 + autoreleasepool { + tester().clearTextFromAndThenEnterTextIntoCurrentFirstResponder("\(url)\n") + } + + tester().waitForWebViewElementWithAccessibilityLabel("Page 1") + + + tester().runBlock { _ in + return (aboutHomeController == nil) ? KIFTestStepResult.Success : KIFTestStepResult.Wait + } + XCTAssertNil(aboutHomeController, "about:home controller disposed") + } + + func testSearchViewControllerDisposed() { + // Type the URL to make the search controller appear. + tester().tapViewWithAccessibilityIdentifier("url") + tester().clearTextFromAndThenEnterTextIntoCurrentFirstResponder("foobar") + tester().waitForTimeInterval(0.1) // Wait to make sure that input has propagated through delegate methods + let browserViewController = getTopViewController() + weak var searchViewController = getChildViewController(browserViewController, childClass: "SearchViewController") + XCTAssertNotNil(searchViewController, "Got search controller reference") + + // Submit to close about:home and the search controller. + tester().enterTextIntoCurrentFirstResponder("\n") + + tester().runBlock { _ in + return (searchViewController == nil) ? KIFTestStepResult.Success : KIFTestStepResult.Wait + } + XCTAssertNil(searchViewController, "Search controller disposed") + } + + func testTabTrayDisposed() { + // Enter the tab tray. + tester().tapViewWithAccessibilityLabel("Show Tabs") + tester().waitForViewWithAccessibilityLabel("Tabs Tray") + weak var tabTrayController = getTopViewController() + weak var tabCell = tester().waitForTappableViewWithAccessibilityLabel("home") + XCTAssertNotNil(tabTrayController, "Got tab tray reference") + XCTAssertNotNil(tabCell, "Got tab cell reference") + + // Leave the tab tray. + tester().tapViewWithAccessibilityLabel("home") + + tester().runBlock { _ in + return (tabTrayController == nil) ? KIFTestStepResult.Success : KIFTestStepResult.Wait + } + XCTAssertNil(tabTrayController, "Tab tray controller disposed") + + tester().runBlock { _ in + return (tabCell == nil) ? KIFTestStepResult.Success : KIFTestStepResult.Wait + } + XCTAssertNil(tabCell, "Tab tray cell disposed") + } + + func testWebViewDisposed() { + weak var webView = tester().waitForViewWithAccessibilityLabel("Web content") + XCTAssertNotNil(webView, "webView found") + + tester().tapViewWithAccessibilityLabel("Show Tabs") + let tabsView = tester().waitForViewWithAccessibilityLabel("Tabs Tray").subviews.first as! UICollectionView + let cell = tabsView.cellForItemAtIndexPath(NSIndexPath(forItem: 0, inSection: 0))! + tester().swipeViewWithAccessibilityLabel(cell.accessibilityLabel, inDirection: KIFSwipeDirection.Left) + tester().waitForTappableViewWithAccessibilityLabel("Show Tabs") + + tester().runBlock { _ in + return (webView == nil) ? KIFTestStepResult.Success : KIFTestStepResult.Wait + } + XCTAssertNil(webView, "webView disposed") + } + + private func getTopViewController() -> UIViewController { + //return (UIApplication.sharedApplication().keyWindow!.rootViewController as! UINavigationController).topViewController! + return UIApplication.sharedApplication().keyWindow!.rootViewController! + } + + private func getChildViewController(parent: UIViewController, childClass: String) -> UIViewController { + let childControllers = parent.childViewControllers.filter { child in + let description = NSString(string: child.description) + return description.containsString(childClass) + } + XCTAssertEqual(childControllers.count, 0, "Found 1 child controller of type: \(childClass)") + return childControllers.first! + } + */ +} diff --git a/mobile/ios/UITests/findPage.html b/mobile/ios/UITests/findPage.html new file mode 100644 index 0000000000..e9ed349d48 --- /dev/null +++ b/mobile/ios/UITests/findPage.html @@ -0,0 +1,16 @@ + + + Find Page + + + +
nullam
+ +
Find Page
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ullamcorper dolor nisi, id faucibus enim tincidunt vitae. Aenean felis ex, dignissim sagittis consectetur nec, vehicula ut sem. Aliquam pulvinar egestas dolor, non sagittis sem ultricies lacinia. Praesent vulputate ullamcorper nisl, eu egestas massa laoreet in. Integer consequat, sem eget dignissim suscipit, augue odio convallis eros, in ultricies urna elit egestas purus. Etiam tempor leo justo, at laoreet sem vestibulum ac. Nullam convallis mollis elit, bibendum ultrices ipsum consequat at.

+

Vivamus ornare eros lectus, vel vulputate lorem blandit et. Fusce quis bibendum erat. Quisque pretium mollis lectus pulvinar aliquet. Vivamus ut mi tincidunt, bibendum neque eget, maximus dolor. Cras dictum elementum magna, luctus rutrum est accumsan ac. Quisque aliquam leo fermentum arcu consectetur sagittis. In arcu sapien, ornare in mi sit amet, porta volutpat turpis.

+

Suspendisse blandit enim nec justo tempus pharetra. Donec sagittis dolor malesuada lorem vulputate sagittis. Vivamus eu facilisis ligula. Integer gravida nibh sapien, ut scelerisque lectus faucibus id. Ut gravida nec lacus fringilla interdum. Proin vehicula maximus odio, id dapibus ex faucibus a. Nulla aliquam augue augue, nec lacinia tortor convallis sit amet. Donec id lacus euismod, rutrum mauris sit amet, tempus nisi. Integer a aliquet magna. Quisque non ultrices lacus. Pellentesque quis eros dictum, mollis leo ut, auctor magna. Pellentesque ex erat, eleifend ac nibh et, consequat tempor risus. Proin ornare eros sit amet magna ultricies vulputate. Sed non libero sit amet ante semper ornare. Vivamus vestibulum, mauris ac porttitor rutrum, turpis risus vestibulum mi, vel luctus arcu arcu vitae sapien. Vivamus nibh mi, porttitor vel dui eget, suscipit vulputate mi.

+

Donec nec pulvinar nunc. Sed tristique bibendum sagittis. Donec eget nisi magna. Phasellus lacinia blandit feugiat. Phasellus placerat aliquam odio, a tristique eros. Nulla at neque lectus. Mauris vel commodo odio, eu elementum nulla. Morbi euismod, lacus quis viverra volutpat, eros lacus suscipit dui, vel pretium orci urna nec enim. Integer tincidunt dui sodales consectetur euismod. Vivamus turpis eros, hendrerit sed hendrerit a, tincidunt nec nunc. Nullam quis dui ac ligula faucibus vulputate. Nullam nec dolor ut orci malesuada malesuada. Sed eros lectus, tempor non mauris id, euismod placerat lorem.

+

Quisque eu tincidunt urna. Ut et mattis est. Donec quis elementum orci, et gravida tortor. In eu sagittis mi. Sed in dapibus diam. Integer bibendum, quam in efficitur posuere, leo dui pharetra mauris, nec ultrices arcu nulla nec lorem. Aliquam fringilla leo in luctus blandit. Phasellus lacinia suscipit varius. Sed vel ultrices metus. Sed lacinia malesuada dui, imperdiet ullamcorper libero suscipit eget. Quisque a velit ut orci fringilla eleifend eu at urna. Aenean venenatis enim erat. Aliquam molestie urna non velit consequat volutpat. Sed molestie, risus vitae sodales gravida, purus lacus bibendum libero, id fermentum sem nibh ut magna. Donec facilisis vel tellus in faucibus. Cras ac rhoncus metus.

+ + diff --git a/mobile/ios/UITests/localhostLoad.html b/mobile/ios/UITests/localhostLoad.html new file mode 100644 index 0000000000..6f047dd6d7 --- /dev/null +++ b/mobile/ios/UITests/localhostLoad.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/mobile/ios/UITests/loginForm.html b/mobile/ios/UITests/loginForm.html new file mode 100644 index 0000000000..3b47a88b7d --- /dev/null +++ b/mobile/ios/UITests/loginForm.html @@ -0,0 +1,12 @@ + + + Login form + + +
+ + + +
+ + diff --git a/mobile/ios/UITests/navigationDelegate.html b/mobile/ios/UITests/navigationDelegate.html new file mode 100644 index 0000000000..9a55475641 --- /dev/null +++ b/mobile/ios/UITests/navigationDelegate.html @@ -0,0 +1,8 @@ + + + Test navigation delegate + + +
link + + diff --git a/mobile/ios/UITests/noTitle.html b/mobile/ios/UITests/noTitle.html new file mode 100644 index 0000000000..e08f0a9425 --- /dev/null +++ b/mobile/ios/UITests/noTitle.html @@ -0,0 +1,5 @@ + + +
This page has no title
+ + diff --git a/mobile/ios/UITests/numberedPage.html b/mobile/ios/UITests/numberedPage.html new file mode 100644 index 0000000000..0f6d329716 --- /dev/null +++ b/mobile/ios/UITests/numberedPage.html @@ -0,0 +1,9 @@ + + + + Page {page} + + +
Page {page}
+ + diff --git a/mobile/ios/UITests/readablePage.html b/mobile/ios/UITests/readablePage.html new file mode 100644 index 0000000000..5e12fb2841 --- /dev/null +++ b/mobile/ios/UITests/readablePage.html @@ -0,0 +1,14 @@ + + + + Readable page + + +
Readable Page
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ullamcorper dolor nisi, id faucibus enim tincidunt vitae. Aenean felis ex, dignissim sagittis consectetur nec, vehicula ut sem. Aliquam pulvinar egestas dolor, non sagittis sem ultricies lacinia. Praesent vulputate ullamcorper nisl, eu egestas massa laoreet in. Integer consequat, sem eget dignissim suscipit, augue odio convallis eros, in ultricies urna elit egestas purus. Etiam tempor leo justo, at laoreet sem vestibulum ac. Nullam convallis mollis elit, bibendum ultrices ipsum consequat at.

+

Vivamus ornare eros lectus, vel vulputate lorem blandit et. Fusce quis bibendum erat. Quisque pretium mollis lectus pulvinar aliquet. Vivamus ut mi tincidunt, bibendum neque eget, maximus dolor. Cras dictum elementum magna, luctus rutrum est accumsan ac. Quisque aliquam leo fermentum arcu consectetur sagittis. In arcu sapien, ornare in mi sit amet, porta volutpat turpis.

+

Suspendisse blandit enim nec justo tempus pharetra. Donec sagittis dolor malesuada lorem vulputate sagittis. Vivamus eu facilisis ligula. Integer gravida nibh sapien, ut scelerisque lectus faucibus id. Ut gravida nec lacus fringilla interdum. Proin vehicula maximus odio, id dapibus ex faucibus a. Nulla aliquam augue augue, nec lacinia tortor convallis sit amet. Donec id lacus euismod, rutrum mauris sit amet, tempus nisi. Integer a aliquet magna. Quisque non ultrices lacus. Pellentesque quis eros dictum, mollis leo ut, auctor magna. Pellentesque ex erat, eleifend ac nibh et, consequat tempor risus. Proin ornare eros sit amet magna ultricies vulputate. Sed non libero sit amet ante semper ornare. Vivamus vestibulum, mauris ac porttitor rutrum, turpis risus vestibulum mi, vel luctus arcu arcu vitae sapien. Vivamus nibh mi, porttitor vel dui eget, suscipit vulputate mi.

+

Donec nec pulvinar nunc. Sed tristique bibendum sagittis. Donec eget nisi magna. Phasellus lacinia blandit feugiat. Phasellus placerat aliquam odio, a tristique eros. Nulla at neque lectus. Mauris vel commodo odio, eu elementum nulla. Morbi euismod, lacus quis viverra volutpat, eros lacus suscipit dui, vel pretium orci urna nec enim. Integer tincidunt dui sodales consectetur euismod. Vivamus turpis eros, hendrerit sed hendrerit a, tincidunt nec nunc. Nullam quis dui ac ligula faucibus vulputate. Nullam nec dolor ut orci malesuada malesuada. Sed eros lectus, tempor non mauris id, euismod placerat lorem.

+

Quisque eu tincidunt urna. Ut et mattis est. Donec quis elementum orci, et gravida tortor. In eu sagittis mi. Sed in dapibus diam. Integer bibendum, quam in efficitur posuere, leo dui pharetra mauris, nec ultrices arcu nulla nec lorem. Aliquam fringilla leo in luctus blandit. Phasellus lacinia suscipit varius. Sed vel ultrices metus. Sed lacinia malesuada dui, imperdiet ullamcorper libero suscipit eget. Quisque a velit ut orci fringilla eleifend eu at urna. Aenean venenatis enim erat. Aliquam molestie urna non velit consequat volutpat. Sed molestie, risus vitae sodales gravida, purus lacus bibendum libero, id fermentum sem nibh ut magna. Donec facilisis vel tellus in faucibus. Cras ac rhoncus metus.

+ + diff --git a/mobile/ios/UITests/readerContent.html b/mobile/ios/UITests/readerContent.html new file mode 100644 index 0000000000..ca2623cfe1 --- /dev/null +++ b/mobile/ios/UITests/readerContent.html @@ -0,0 +1,31 @@ + + + + + Reader View Test + + +
+

Lorem

+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +
+

Links

+

link

+

link

+

Foo

+
+ Tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +
+
+ + \ No newline at end of file diff --git a/mobile/ios/UITests/scrollablePage.html b/mobile/ios/UITests/scrollablePage.html new file mode 100644 index 0000000000..50ad126d10 --- /dev/null +++ b/mobile/ios/UITests/scrollablePage.html @@ -0,0 +1,68 @@ + + + + Scrollable Page {page} + + +
Top
+
    +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
  • middle
  • +
+
Bottom
+ + diff --git a/mobile/ios/UITests/youtube.ico b/mobile/ios/UITests/youtube.ico new file mode 100644 index 0000000000..aa914c3301 Binary files /dev/null and b/mobile/ios/UITests/youtube.ico differ diff --git a/mobile/ios/XCUITests/ActivityStreamTest.swift b/mobile/ios/XCUITests/ActivityStreamTest.swift new file mode 100644 index 0000000000..b65073cdc9 --- /dev/null +++ b/mobile/ios/XCUITests/ActivityStreamTest.swift @@ -0,0 +1,378 @@ +/* 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/. */ + +import XCTest + +let defaultTopSite = ["topSiteLabel": "wikipedia", "bookmarkLabel": "Wikipedia"] +let newTopSite = ["url": "www.mozilla.org", "topSiteLabel": "mozilla", "bookmarkLabel": "Internet for people, not profit — Mozilla"] +let allDefaultTopSites = ["facebook", "youtube", "amazon", "wikipedia", "twitter"] + +class ActivityStreamTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + let TopSiteCellgroup = XCUIApplication().collectionViews.cells["TopSitesCell"] + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + dismissFirstRunUI() + } + + override func tearDown() { + super.tearDown() + } + + func testDefaultSites() { + // There should be 5 top sites by default + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 5) + } + + func testTopSitesAdd() { + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 5) + + loadWebPage("http://example.com") + if iPad() { + app.buttons["URLBarView.backButton"].tap() + } else { + app.buttons["TabToolbar.backButton"].tap() + } + navigator.goto(URLBarOpen) + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 6) + } + + func testTopSitesRemove() { + loadWebPage("http://example.com") + if iPad() { + app.buttons["URLBarView.backButton"].tap() + } else { + app.buttons["TabToolbar.backButton"].tap() + } + navigator.goto(URLBarOpen) + // A new site has been added to the top sites + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 6) + + TopSiteCellgroup.cells["example"].press(forDuration: 1) //example is the name of the domain. (example.com) + app.tables["Context Menu"].cells["Remove"].tap() + // A top site has been removed + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 5) + } + + func testTopSitesRemoveDefaultTopSite() { + TopSiteCellgroup.cells[defaultTopSite["topSiteLabel"]!].press(forDuration: 1) + + // Tap on Remove and check that now there should be only 4 default top sites + selectOptionFromContextMenu(option: "Remove") + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 4) + } + + func testTopSitesRemoveAllDefaultTopSitesAddNewOne() { + // Remove all default Top Sites + for i in allDefaultTopSites { + TopSiteCellgroup.cells[i].press(forDuration: 1) + selectOptionFromContextMenu(option: "Remove") + } + + let numberOfTopSites = TopSiteCellgroup.cells.matching(identifier: "TopSite").count + XCTAssertEqual(numberOfTopSites, 0, "All top sites should have been removed") + + // Open a new page and wait for the completion + navigator.nowAt(HomePanelsScreen) + navigator.goto(URLBarOpen) + app.textFields["address"].typeText(newTopSite["url"]!) + app.textFields["address"].typeText("\r") + waitUntilPageLoad() + + if iPad() { + app.buttons["URLBarView.backButton"].tap() + } else { + app.buttons["TabToolbar.backButton"].tap() + } + waitforExistence(TopSiteCellgroup.cells[newTopSite["topSiteLabel"]!]) + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 1) + } + + func testTopSitesShiftAfterRemovingOne() { + + // Check top site in first and second cell + let topSiteFirstCell = app.collectionViews.cells.collectionViews.cells.element(boundBy: 0).label + let topSiteSecondCell = app.collectionViews.cells.collectionViews.cells.element(boundBy: 1).label + + XCTAssertTrue(topSiteFirstCell == allDefaultTopSites[0]) + XCTAssertTrue(topSiteSecondCell == allDefaultTopSites[1]) + + // Remove it + let topSiteCells = TopSiteCellgroup.cells + topSiteCells[allDefaultTopSites[0]].press(forDuration: 1) + selectOptionFromContextMenu(option: "Remove") + + // Check top site in first cell now + let topSiteFirstCellAfter = app.collectionViews.cells.collectionViews.cells.element(boundBy: 0).label + XCTAssertTrue(topSiteFirstCellAfter == allDefaultTopSites[1]) + } + + func testTopSitesOpenInNewTab() { + loadWebPage("http://example.com") + if iPad() { + app.buttons["URLBarView.backButton"].tap() + } else { + app.buttons["TabToolbar.backButton"].tap() + } + navigator.goto(URLBarOpen) + TopSiteCellgroup.cells["example"].press(forDuration: 1) + app.tables["Context Menu"].cells["Open in New Tab"].tap() + XCTAssert(TopSiteCellgroup.exists) + XCTAssertFalse(app.staticTexts["example"].exists) + + //URLBarview goBack button + let goBackButton = app.children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element(boundBy: 1).children(matching: .other).element.children(matching: .button).element(boundBy: 0) + goBackButton.tap() + + if iPad() { + app.buttons["TopTabsViewController.tabsButton"].tap() + } else { + app.buttons["TabToolbar.tabsButton"].tap() + } + + app.cells.element(boundBy: 0).tap() //"Example Domain" + XCTAssertFalse(app.tables["Top sites"].exists) + + let staticTextsQuery = self.app.staticTexts.matching(identifier: "Example Domain") + if staticTextsQuery.count > 0 { + let firstText = staticTextsQuery.element(boundBy: 0) + XCTAssert(firstText.exists) + } + } + + func testTopSitesOpenInNewTabDefaultTopSite() { + // Open one of the sites from Topsites and wait until page is loaded + TopSiteCellgroup.cells[defaultTopSite["topSiteLabel"]!] + .press(forDuration: 1) + selectOptionFromContextMenu(option: "Open in New Tab") + waitUntilPageLoad() + + // Check that two tabs are open and one of them is the default top site one + navigator.goto(TabTray) + waitforExistence(app.collectionViews.cells[defaultTopSite["bookmarkLabel"]!]) + let numTabsOpen = app.collectionViews.cells.count + XCTAssertEqual(numTabsOpen, 2, "New tab not open") + } + + func testTopSitesOpenInNewPrivateTab() { + loadWebPage("http://example.com") + if iPad() { + app.buttons["URLBarView.backButton"].tap() + } else { + app.buttons["TabToolbar.backButton"].tap() + } + navigator.goto(URLBarOpen) + app.collectionViews.cells["TopSitesCell"].cells["example"].press(forDuration: 1) + app.tables["Context Menu"].cells["Open in New Private Tab"].tap() + + XCTAssert(TopSiteCellgroup.exists) + XCTAssertFalse(app.staticTexts["example"].exists) + + //URLBarview goBack button + let goBackButton = app.children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element(boundBy: 1).children(matching: .other).element.children(matching: .button).element(boundBy: 0) + goBackButton.tap() + if iPad() { + app.buttons["TopTabsViewController.tabsButton"].tap() + } else { + app.buttons["TabToolbar.tabsButton"].tap() + } + + app.buttons["TabTrayController.maskButton"].tap() + app.cells["Example Domain"].tap() + + XCTAssertFalse(TopSiteCellgroup.exists) + XCTAssert(app.staticTexts["Example Domain"].exists) + } + + func testTopSitesOpenInNewPrivateTabDefaultTopSite() { + // Open one of the sites from Topsites and wait until page is loaded + TopSiteCellgroup.cells[defaultTopSite["topSiteLabel"]!] + .press(forDuration: 1) + selectOptionFromContextMenu(option: "Open in New Private Tab") + + // Check that two tabs are open and one of them is the default top site one + navigator.goto(PrivateTabTray) + waitforExistence(app.collectionViews.cells[defaultTopSite["bookmarkLabel"]!]) + let numTabsOpen = app.collectionViews.cells.count + XCTAssertEqual(numTabsOpen, 1, "New tab not open") + } + + func testTopSitesBookmarkDefaultTopSite() { + // Bookmark a default TopSite + TopSiteCellgroup.cells[defaultTopSite["topSiteLabel"]!] + .press(forDuration: 1) + selectOptionFromContextMenu(option: "Bookmark") + + // Check that it appears under Bookmarks menu + navigator.goto(HomePanel_Bookmarks) + XCTAssertTrue(app.tables["Bookmarks List"].staticTexts[defaultTopSite["bookmarkLabel"]!].exists) + + // Check that longtapping on the TopSite gives the option to remove it + navigator.goto(HomePanel_TopSites) + TopSiteCellgroup.cells[defaultTopSite["topSiteLabel"]!] + .press(forDuration: 2) + XCTAssertTrue(app.tables["Context Menu"].cells["Remove Bookmark"].exists) + + // Unbookmark it + selectOptionFromContextMenu(option: "Remove Bookmark") + navigator.goto(HomePanel_Bookmarks) + XCTAssertFalse(app.tables["Bookmarks List"].staticTexts[defaultTopSite["bookmarkLabel"]!].exists) + } + + func testTopSitesBookmarkNewTopSite () { + // Bookmark a new TopSite + navigator.openURL(urlString: newTopSite["url"]!) + waitUntilPageLoad() + if iPad() { + app.buttons["URLBarView.backButton"].tap() + } else { + app.buttons["TabToolbar.backButton"].tap() + } + let topSiteCells = TopSiteCellgroup.cells + waitforExistence(topSiteCells[newTopSite["topSiteLabel"]!]) + topSiteCells[newTopSite["topSiteLabel"]!].press(forDuration: 1) + selectOptionFromContextMenu(option: "Bookmark") + + // Check that it appears under Bookmarks menu + navigator.nowAt(HomePanelsScreen) + navigator.goto(HomePanel_Bookmarks) + XCTAssertTrue(app.tables["Bookmarks List"].staticTexts[newTopSite["bookmarkLabel"]!].exists) + + // Check that longtapping on the TopSite gives the option to remove it + navigator.goto(HomePanel_TopSites) + TopSiteCellgroup.cells[newTopSite["topSiteLabel"]!].press(forDuration: 1) + + // Unbookmark it + selectOptionFromContextMenu(option: "Remove Bookmark") + navigator.goto(HomePanel_Bookmarks) + XCTAssertFalse(app.tables["Bookmarks List"].staticTexts[newTopSite["bookmarkLabel"]!].exists) + } + + func testTopSitesShareDefaultTopSite () { + TopSiteCellgroup.cells[defaultTopSite["topSiteLabel"]!] + .press(forDuration: 1) + + // Tap on Share option and verify that the menu is shown and it is possible to cancel it + selectOptionFromContextMenu(option: "Share") + if !iPad() { + app.buttons["Cancel"].tap() + } + } + + func testTopSitesShareNewTopSite () { + navigator.openURL(urlString: newTopSite["url"]!) + waitUntilPageLoad() + navigator.goto(TabTray) + navigator.goto(HomePanelsScreen) + let topSiteCells = TopSiteCellgroup.cells + waitforExistence(topSiteCells[newTopSite["topSiteLabel"]!]) + topSiteCells[newTopSite["topSiteLabel"]!].press(forDuration: 1) + + // Tap on Share option and verify that the menu is shown and it is possible to cancel it.... + selectOptionFromContextMenu(option: "Share") + if !iPad() { + app.buttons["Cancel"].tap() + } + } + + private func selectOptionFromContextMenu(option: String) { + XCTAssertTrue(app.tables["Context Menu"].cells[option].exists) + app.tables["Context Menu"].cells[option].tap() + } + + private func checkNumberOfExpectedTopSites(numberOfExpectedTopSites: Int) { + waitforExistence(app.cells["TopSitesCell"]) + XCTAssertTrue(app.cells["TopSitesCell"].exists) + let numberOfTopSites = TopSiteCellgroup.cells.matching(identifier: "TopSite").count + XCTAssertEqual(numberOfTopSites, UInt(numberOfExpectedTopSites), "The number of Top Sites is not correct") + } + + func testOpenTopSitesFromContextMenu () { + // Top Sites is shown by default + waitforExistence(app.cells["TopSitesCell"]) + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 5) + + // Go to a website + navigator.openURL(urlString: newTopSite["url"]!) + waitUntilPageLoad() + + // Go back to Top Sites from context menu + navigator.browserPerformAction(.openTopSitesOption) + checkNumberOfExpectedTopSites(numberOfExpectedTopSites: 6) + } + + func testActivityStreamPages() { + let pagecontrolButton = TopSiteCellgroup.buttons["Next Page"] + XCTAssertFalse(pagecontrolButton.exists, "The Page Control button must not exist. Only 5 elements should be on the page") + + navigator.openURL(urlString: "http://example.com") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "example.com") + navigator.openURL(urlString: "http://mozilla.org") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "mozilla.org") + navigator.openURL(urlString: "http://apple.com") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "apple.com") + navigator.openURL(urlString: "http://slack.com") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "slack.com") + + if iPad() { + // Test timeout on BB when loading these pages + navigator.openURL(urlString: "http://cvs.com") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "cvs.com") + navigator.openURL(urlString: "http://linkedin.com") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "linkedin.com") + navigator.openURL(urlString: "http://zara.com") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "zara.com") + navigator.openURL(urlString: "http://twitter.com") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "twitter.com") + navigator.openURL(urlString: "http://instagram.com") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "instagram.com") + } + navigator.goto(URLBarOpen) + waitforExistence(pagecontrolButton) + XCTAssert(pagecontrolButton.exists, "The Page Control button must exist") + pagecontrolButton.tap() + pagecontrolButton.tap() + let topSiteCells = TopSiteCellgroup.cells + waitforExistence(topSiteCells["example"]) + topSiteCells["example"].press(forDuration: 1) + app.tables["Context Menu"].cells["Remove"].tap() + waitforNoExistence(pagecontrolButton) + XCTAssertFalse(pagecontrolButton.exists, "The Page Control button should disappear after an item is deleted.") + } + + func testContextMenuInLandscape() { + XCUIDevice.shared().orientation = .landscapeLeft + + navigator.openURL(urlString: "http://example.com") + waitUntilPageLoad() + if app.buttons["URLBarView.backButton"].isEnabled { + app.buttons["URLBarView.backButton"].tap() + } else { + app.textFields["url"].tap() + } + TopSiteCellgroup.cells["example"].press(forDuration: 1) + + let contextMenuHeight = app.tables["Context Menu"].frame.size.height + let parentViewHeight = app.otherElements["Action Sheet"].frame.size.height + + XCTAssertLessThanOrEqual(contextMenuHeight, parentViewHeight) + + // Go back to portrait mode + XCUIDevice.shared().orientation = .portrait + } +} diff --git a/mobile/ios/XCUITests/AuthenticationTest.swift b/mobile/ios/XCUITests/AuthenticationTest.swift new file mode 100644 index 0000000000..ed64dd07bb --- /dev/null +++ b/mobile/ios/XCUITests/AuthenticationTest.swift @@ -0,0 +1,347 @@ +/* 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/. */ + +import XCTest + +extension String { + + subscript (i: Int) -> Character { + return self[self.characters.index(self.startIndex, offsetBy: i)] + } + + subscript (i: Int) -> String { + return String(self[i] as Character) + } + + subscript (r: Range) -> String { + let start = characters.index(startIndex, offsetBy: r.lowerBound) + let end = self.index(start, offsetBy: r.upperBound - r.lowerBound) + return self[Range(start ..< end)] + } +} + +class AuthenticationTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + continueAfterFailure = false + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + closeAuthenticationManager() + super.tearDown() + } + + fileprivate func typePasscode(_ passCode: String) { + app.keys[passCode[0]].tap() + app.keys[passCode[1]].tap() + app.keys[passCode[2]].tap() + app.keys[passCode[3]].tap() + app.keys[passCode[4]].tap() + app.keys[passCode[5]].tap() + } + + fileprivate func closeAuthenticationManager() { + navigator.goto(BrowserTab) + } + + fileprivate func disablePasscode(_ passCode: String) { + navigator.goto(PasscodeSettings) + + app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode Off"].tap() + waitforExistence(app.staticTexts["Enter passcode"]) + typePasscode(passCode) + waitforExistence(app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode On"]) + } + + fileprivate func enablePasscode(_ passCode: String, interval: String = "Immediately") { + let authenticationmanagerSettingstableviewTable = app.tables["AuthenticationManager.settingsTableView"] + + navigator.goto(PasscodeSettings) + app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode On"].tap() + waitforExistence(app.staticTexts["Enter a passcode"]) + typePasscode(passCode) + waitforExistence(app.staticTexts["Re-enter passcode"]) + typePasscode(passCode) + waitforExistence(app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode Off"]) + navigator.goto(PasscodeIntervalSettings) + typePasscode(passCode) + app.staticTexts[interval].tap() + navigator.goto(PasscodeSettings) + waitforExistence(authenticationmanagerSettingstableviewTable.staticTexts[interval]) + } + + // Sets the passcode and interval (set to immediately) + func testTurnOnOff() { + enablePasscode("133777") + XCTAssertTrue(app.staticTexts["Immediately"].exists) + disablePasscode("133777") + } + + func testChangePassCode() { + enablePasscode("133777") + app.staticTexts["Change Passcode"].tap() + waitforExistence(app.staticTexts["Enter passcode"]) + typePasscode("133777") + waitforExistence(app.staticTexts["Enter a new passcode"]) + typePasscode("233777") + waitforExistence(app.staticTexts["Re-enter passcode"]) + typePasscode("233777") + waitforExistence(app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode Off"]) + disablePasscode("233777") + } + + func testPromptPassCodeUponReentry() { + enablePasscode("133777") + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.tables["Login List"]) + + //send app to background, and re-enter + XCUIDevice.shared().press(.home) + app.activate() + let contentView = app.navigationBars["Client.FxAContentView"] + if contentView.exists { + app.navigationBars["Client.FxAContentView"].buttons["Settings"].tap() + } + navigator.nowAt("SettingsScreen") + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + } + + func testPromptPassCodeUponReentryWithDelay() { + enablePasscode("133777", interval: "After 5 minutes") + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.tables["Login List"]) + + //send app to background, and re-enter + XCUIDevice.shared().press(.home) + app.activate() + let contentView = app.navigationBars["Client.FxAContentView"] + if contentView.exists { + app.navigationBars["Client.FxAContentView"].buttons["Settings"].tap() + } + + navigator.nowAt("SettingsScreen") + navigator.goto(LoginsSettings) + waitforExistence(app.tables["Login List"]) + } + + func testChangePasscodeShowsErrorStates() { + enablePasscode("133777") + app.staticTexts["Change Passcode"].tap() + waitforExistence(app.staticTexts["Enter passcode"]) + typePasscode("233777") + waitforExistence(app.staticTexts["Incorrect passcode. Try again (Attempts remaining: 2)."]) + typePasscode("333777") + waitforExistence(app.staticTexts["Incorrect passcode. Try again (Attempts remaining: 1)."]) + typePasscode("133777") + waitforExistence(app.staticTexts["Enter a new passcode"]) + + // Enter same passcode as new one + typePasscode("133777") + waitforExistence(app.staticTexts["New passcode must be different than existing code."]) + + // Enter mismatched passcode + typePasscode("233777") + waitforExistence(app.staticTexts["Re-enter passcode"]) + typePasscode("333777") + waitforExistence(app.staticTexts["Passcodes didn’t match. Try again."]) + + // Put proper password + XCTAssertTrue(app.staticTexts["Enter a new passcode"].exists) + typePasscode("233777") + waitforExistence(app.staticTexts["Re-enter passcode"]) + typePasscode("233777") + waitforExistence(app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode Off"]) + + disablePasscode("233777") + } + + func testChangeRequirePasscodeInterval() { + enablePasscode("133777") + + let authenticationmanagerSettingstableviewTable = app.tables["AuthenticationManager.settingsTableView"] + navigator.goto(PasscodeIntervalSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.staticTexts["Immediately"]) + XCTAssertTrue(app.staticTexts["After 1 minute"].exists) + XCTAssertTrue(app.staticTexts["After 5 minutes"].exists) + XCTAssertTrue(app.staticTexts["After 10 minutes"].exists) + XCTAssertTrue(app.staticTexts["After 15 minutes"].exists) + XCTAssertTrue(app.staticTexts["After 1 hour"].exists) + + app.staticTexts["After 15 minutes"].tap() + navigator.goto(PasscodeSettings) + waitforExistence(authenticationmanagerSettingstableviewTable.staticTexts["After 15 minutes"]) + + // Since we set to 15 min, it shouldn't ask for password again, but it skips verification + // only when timing isn't changed. (could be due to timer reset?) + // For clarification, raised Bug 1325439 + navigator.goto(PasscodeIntervalSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + navigator.goto(PasscodeSettings) + waitforExistence(authenticationmanagerSettingstableviewTable.staticTexts["After 15 minutes"]) + disablePasscode("133777") + } + + func testEnteringLoginsUsingPasscode() { + enablePasscode("133777") + + // Enter login + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.tables["Login List"]) + navigator.goto(SettingsScreen) + + // Trying again should display passcode screen since we've set the interval to be immediately. + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.tables["Login List"]) + disablePasscode("133777") + } + + func testEnteringLoginsUsingPasscodeWithFiveMinutesInterval() { + enablePasscode("133777", interval: "After 5 minutes") + + // now we've changed the timeout, we should prompt next time for passcode. + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.tables["Login List"]) + + // Trying again should not display the passcode screen since the interval is 5 minutes + navigator.goto(SettingsScreen) + navigator.goto(LoginsSettings) + waitforExistence(app.tables["Login List"]) + + navigator.goto(PasscodeIntervalSettings) + waitforExistence(app.staticTexts["After 5 minutes"]) + + disablePasscode("133777") + } + + func testEnteringLoginsWithNoPasscode() { + // it is disabled + navigator.goto(PasscodeSettings) + waitforExistence(app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode On"]) + + navigator.goto(LoginsSettings) + waitforExistence(app.tables["Login List"]) + } + + func testWrongPasscodeDisplaysAttemptsAndMaxError() { + enablePasscode("133777") + navigator.goto(PasscodeIntervalSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.staticTexts["After 5 minutes"]) + app.staticTexts["After 5 minutes"].tap() + navigator.goto(PasscodeSettings) + waitforExistence(app.tables["AuthenticationManager.settingsTableView"].staticTexts["After 5 minutes"]) + + // Enter wrong passcode + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("233777") + waitforExistence(app.staticTexts["Incorrect passcode. Try again (Attempts remaining: 2)."]) + typePasscode("333777") + waitforExistence(app.staticTexts["Incorrect passcode. Try again (Attempts remaining: 1)."]) + typePasscode("333777") + waitforExistence(app.staticTexts["Maximum attempts reached. Please try again later."]) + } + + func testWrongPasscodeAttemptsPersistAcrossEntryAndConfirmation() { + enablePasscode("133777") + + // Enter wrong passcode on Logins + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("233777") + waitforExistence(app.staticTexts["Incorrect passcode. Try again (Attempts remaining: 2)."]) + + // Go back to Passcode, and enter a wrong passcode, notice the error count + navigator.goto(PasscodeSettings) + app.staticTexts["Change Passcode"].tap() + waitforExistence(app.staticTexts["Enter passcode"]) + typePasscode("233777") + waitforExistence(app.staticTexts["Incorrect passcode. Try again (Attempts remaining: 1)."]) + app.buttons["Cancel"].tap() + + disablePasscode("133777") + } + + func testChangedPasswordMustBeNew() { + enablePasscode("133777") + app.staticTexts["Change Passcode"].tap() + waitforExistence(app.staticTexts["Enter passcode"]) + typePasscode("133777") + waitforExistence(app.staticTexts["Enter a new passcode"]) + typePasscode("133777") + waitforExistence(app.staticTexts["New passcode must be different than existing code."]) + app.navigationBars["Change Passcode"].buttons["Cancel"].tap() + + disablePasscode("133777") + } + + func testPasscodesMustMatchWhenCreating() { + navigator.goto(PasscodeSettings) + app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode On"].tap() + waitforExistence(app.staticTexts["Enter a passcode"]) + typePasscode("133777") + waitforExistence(app.staticTexts["Re-enter passcode"]) + typePasscode("233777") + waitforExistence(app.staticTexts["Passcodes didn’t match. Try again."]) + waitforExistence(app.staticTexts["Enter a passcode"]) + app.buttons["Cancel"].tap() + } + + func testPasscodeMustBeCorrectWhenRemoving() { + enablePasscode("133777") + XCTAssertTrue(app.staticTexts["Immediately"].exists) + app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode Off"].tap() + waitforExistence(app.staticTexts["Enter passcode"]) + typePasscode("233777") + + waitforExistence(app.staticTexts["Incorrect passcode. Try again (Attempts remaining: 2)."]) + typePasscode("133777") + waitforExistence(app.tables["AuthenticationManager.settingsTableView"].staticTexts["Turn Passcode On"]) + } + + func testChangingIntervalResetsValidationTimer() { + enablePasscode("133777") + + // Enter login, since the default is 'set immediately,' it will ask for passcode + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.tables["Login List"]) + + navigator.goto(PasscodeIntervalSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + typePasscode("133777") + waitforExistence(app.staticTexts["Immediately"]) + app.staticTexts["After 15 minutes"].tap() + + navigator.goto(PasscodeSettings) + waitforExistence(app.tables["AuthenticationManager.settingsTableView"].staticTexts["After 15 minutes"]) + + // Enter login, since the interval is reset, it will ask for password again + navigator.goto(LoginsSettings) + waitforExistence(app.navigationBars["Enter Passcode"]) + disablePasscode("133777") + } +} diff --git a/mobile/ios/XCUITests/BaseTestCase.swift b/mobile/ios/XCUITests/BaseTestCase.swift new file mode 100644 index 0000000000..4889cf202d --- /dev/null +++ b/mobile/ios/XCUITests/BaseTestCase.swift @@ -0,0 +1,112 @@ +/* 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/. */ + +import XCTest + +class BaseTestCase: XCTestCase { + + override func setUp() { + super.setUp() + continueAfterFailure = false + let app = XCUIApplication() + app.terminate() + restart(app, args: [LaunchArguments.ClearProfile, LaunchArguments.SkipIntro, LaunchArguments.SkipWhatsNew]) + } + + override func tearDown() { + XCUIApplication().terminate() + super.tearDown() + } + + func restart(_ app: XCUIApplication, args: [String] = []) { + XCUIDevice.shared().press(.home) + var launchArguments = [LaunchArguments.Test] + args.forEach { arg in + launchArguments.append(arg) + } + app.launchArguments = launchArguments + app.activate() + } + + //If it is a first run, first run window should be gone + func dismissFirstRunUI() { + let firstRunUI = XCUIApplication().scrollViews["IntroViewController.scrollView"] + + if firstRunUI.exists { + firstRunUI.swipeLeft() + XCUIApplication().buttons["Start Browsing"].tap() + } + } + + func waitforExistence(_ element: XCUIElement, file: String = #file, line: UInt = #line) { + waitFor(element, with: "exists == true", file: file, line: line) + } + + func waitforNoExistence(_ element: XCUIElement, timeoutValue: TimeInterval = 5.0, file: String = #file, line: UInt = #line) { + waitFor(element, with: "exists != true", timeout: timeoutValue, file: file, line: line) + } + + func waitForValueContains(_ element: XCUIElement, value: String, file: String = #file, line: UInt = #line) { + waitFor(element, with: "value CONTAINS '\(value)'", file: file, line: line) + } + + private func waitFor(_ element: XCUIElement, with predicateString: String, description: String? = nil, timeout: TimeInterval = 5.0, file: String, line: UInt) { + let predicate = NSPredicate(format: predicateString) + let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element) + let result = XCTWaiter().wait(for: [expectation], timeout: timeout) + if result != .completed { + let message = description ?? "Expect predicate \(predicateString) for \(element.description)" + self.recordFailure(withDescription: message, inFile: file, atLine: line, expected: false) + } + } + + func loadWebPage(_ url: String, waitForLoadToFinish: Bool = true, file: String = #file, line: UInt = #line) { + let app = XCUIApplication() + UIPasteboard.general.string = url + app.textFields["url"].press(forDuration: 2.0) + app.sheets.element(boundBy: 0).buttons.element(boundBy: 0).tap() + + if waitForLoadToFinish { + let finishLoadingTimeout: TimeInterval = 30 + let progressIndicator = app.progressIndicators.element(boundBy: 0) + waitFor(progressIndicator, + with: "exists != true", + description: "Problem loading \(url)", + timeout: finishLoadingTimeout, + file: file, line: line) + } + } + + func iPad() -> Bool { + if UIDevice.current.userInterfaceIdiom == .pad { + return true + } + return false + } + + func waitUntilPageLoad() { + let app = XCUIApplication() + let progressIndicator = app.progressIndicators.element(boundBy: 0) + + waitforNoExistence(progressIndicator, timeoutValue: 20.0) + } +} + +extension BaseTestCase { + func tabTrayButton(forApp app: XCUIApplication) -> XCUIElement { + return app.buttons["TopTabsViewController.tabsButton"].exists ? app.buttons["TopTabsViewController.tabsButton"] : app.buttons["TabToolbar.tabsButton"] + } +} + +extension XCUIElement { + func tap(force: Bool) { + // There appears to be a bug with tapping elements sometimes, despite them being on-screen and tappable, due to hittable being false. + // See: http://stackoverflow.com/a/33534187/1248491 + if isHittable { + tap() + } else if force { + coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() + } + } +} diff --git a/mobile/ios/XCUITests/BookmarkingTests.swift b/mobile/ios/XCUITests/BookmarkingTests.swift new file mode 100644 index 0000000000..91ec9cec5f --- /dev/null +++ b/mobile/ios/XCUITests/BookmarkingTests.swift @@ -0,0 +1,112 @@ +/* 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/. */ + +import XCTest + +let url_1 = "www.google.com" +let url_2 = ["url": "www.mozilla.org", "bookmarkLabel": "Internet for people, not profit — Mozilla"] + +class BookmarkingTests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + private func bookmark() { + navigator.goto(PageOptionsMenu) + waitforExistence(app.tables.cells["Bookmark This Page"]) + app.tables.cells["Bookmark This Page"].tap() + navigator.nowAt(BrowserTab) + } + + private func unbookmark() { + navigator.goto(PageOptionsMenu) + waitforExistence(app.tables.cells["Remove Bookmark"]) + app.cells["Remove Bookmark"].tap() + navigator.nowAt(BrowserTab) + } + + private func checkBookmarked() { + navigator.goto(PageOptionsMenu) + waitforExistence(app.tables.cells["Remove Bookmark"]) + if iPad() { + app.otherElements["PopoverDismissRegion"].tap() + navigator.nowAt(BrowserTab) + } else { + navigator.goto(BrowserTab) + } + } + + private func checkUnbookmarked() { + navigator.goto(PageOptionsMenu) + waitforExistence(app.tables.cells["Bookmark This Page"]) + if iPad() { + app.otherElements["PopoverDismissRegion"].tap() + navigator.nowAt(BrowserTab) + } else { + navigator.goto(BrowserTab) + } + } + + func testBookmarkingUI() { + // Go to a webpage, and add to bookmarks, check it's added + navigator.createNewTab() + loadWebPage(url_1) + navigator.nowAt(BrowserTab) + bookmark() + checkBookmarked() + + // Load a different page on a new tab, check it's not bookmarked + navigator.createNewTab() + loadWebPage(url_2["url"]!) + navigator.nowAt(BrowserTab) + checkUnbookmarked() + + // Go back, check it's still bookmarked, check it's on bookmarks home panel + navigator.goto(TabTray) + app.collectionViews.cells["Google"].tap() + navigator.nowAt(BrowserTab) + checkBookmarked() + + // Open it, then unbookmark it, and check it's no longer on bookmarks home panel + unbookmark() + checkUnbookmarked() + } + + private func checkEmptyBookmarkList() { + let list = app.tables["Bookmarks List"].cells.count + XCTAssertEqual(list, 0, "There should not be any entry in the bookmarks list") + } + + private func checkItemInBookmarkList() { + let list = app.tables["Bookmarks List"].cells.count + XCTAssertEqual(list, 1, "There should be an entry in the bookmarks list") + XCTAssertTrue(app.tables["Bookmarks List"].staticTexts[url_2["bookmarkLabel"]!].exists) + } + + func testAccessBookmarksFromContextMenu() { + //First time there is not any bookmark + navigator.browserPerformAction(.openBookMarksOption) + checkEmptyBookmarkList() + navigator.nowAt(BrowserTab) + + //Add a bookmark + navigator.createNewTab() + loadWebPage(url_2["url"]!) + navigator.nowAt(BrowserTab) + bookmark() + + //There should be a bookmark + navigator.browserPerformAction(.openBookMarksOption) + checkItemInBookmarkList() + } +} diff --git a/mobile/ios/XCUITests/ClipBoardTests.swift b/mobile/ios/XCUITests/ClipBoardTests.swift new file mode 100644 index 0000000000..7e7d4ab0d4 --- /dev/null +++ b/mobile/ios/XCUITests/ClipBoardTests.swift @@ -0,0 +1,68 @@ +/* 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/. */ + +import XCTest + +class ClipBoardTests: BaseTestCase { + let url = "www.example.com" + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + navigator = nil + app = nil + super.tearDown() + } + + //Check for test url in the browser + func checkUrl() { + let urlTextField = app.textFields["url"] + waitForValueContains(urlTextField, value: "www.example") + } + + //Copy url from the browser + func copyUrl() { + navigator.goto(URLBarOpen) + app.textFields["address"].press(forDuration: 3) + waitforExistence(app.menuItems["Select All"]) + app.menuItems["Select All"].tap() + waitforExistence(app.menuItems["Copy"]) + app.menuItems["Copy"].tap() + app.typeText("\r") + navigator.nowAt(BrowserTab) + } + + //Check copied url is same as in browser + func checkCopiedUrl() { + if let myString = UIPasteboard.general.string { + var value = app.textFields["url"].value as! String + if value.hasPrefix("http") == false { + value = "http://\(value)" + } + XCTAssertNotNil(myString) + XCTAssertEqual(myString, value, "Url matches with the UIPasteboard") + } + } + + // This test is disabled in release, but can still run on master + func testClipboard() { + navigator.openURL(urlString: url) + waitUntilPageLoad() + checkUrl() + copyUrl() + checkCopiedUrl() + + navigator.createNewTab() + navigator.goto(URLBarOpen) + app.textFields["address"].press(forDuration: 3) + app.menuItems["Paste"].tap() + waitForValueContains(app.textFields["address"], value: "www.example.com") + } +} diff --git a/mobile/ios/XCUITests/CopiedLinksTests.swift b/mobile/ios/XCUITests/CopiedLinksTests.swift new file mode 100644 index 0000000000..65a155e8e8 --- /dev/null +++ b/mobile/ios/XCUITests/CopiedLinksTests.swift @@ -0,0 +1,48 @@ +/* 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/. */ + +import XCTest + +class CopiedLinksTests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + navigator = nil + app = nil + super.tearDown() + } + + // This test is enable Offer to open copied links, when opening firefox + func testCopiedLinks() { + navigator.goto(SettingsScreen) + + //Check Offer to open copied links, when opening firefox is off + let value = app.tables.cells.switches["Offer to Open Copied Links, When Opening Firefox"].value + XCTAssertEqual(value as? String, "0") + + //Switch on, Offer to open copied links, when opening firefox + app.tables.cells.switches["Offer to Open Copied Links, When Opening Firefox"].tap() + + //Check Offer to open copied links, when opening firefox is on + let value2 = app.tables.cells.switches["Offer to Open Copied Links, When Opening Firefox"].value + XCTAssertEqual(value2 as? String, "1") + + app.navigationBars["Settings"]/*@START_MENU_TOKEN@*/.buttons["Done"]/*[[".buttons[\"Done\"]",".buttons[\"AppSettingsTableViewController.navigationItem.leftBarButtonItem\"]"],[[[-1,1],[-1,0]]],[1]]@END_MENU_TOKEN@*/.tap() + + app/*@START_MENU_TOKEN@*/.buttons["TabToolbar.menuButton"]/*[[".buttons[\"Menu\"]",".buttons[\"TabToolbar.menuButton\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap() + let settingsmenuitemCell = app.tables.cells["Settings"] + settingsmenuitemCell.tap() + + //Check Offer to open copied links, when opening firefox is on + let value3 = app.tables.cells.switches["Offer to Open Copied Links, When Opening Firefox"].value + XCTAssertEqual(value3 as? String, "1") + } +} diff --git a/mobile/ios/XCUITests/DomainAutocompleteTest.swift b/mobile/ios/XCUITests/DomainAutocompleteTest.swift new file mode 100644 index 0000000000..67590df0a5 --- /dev/null +++ b/mobile/ios/XCUITests/DomainAutocompleteTest.swift @@ -0,0 +1,174 @@ +/* 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/. */ + +import XCTest + +let website = ["url": "www.mozilla.org", "value": "www.mozilla.org", "subDomain": "https://www.mozilla.org/en-US/firefox/products"] + +class DomainAutocompleteTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + func testAutocomplete() { + navigator.openURL(urlString: website["url"]!) + + // Basic autocompletion cases + navigator.goto(URLBarOpen) + app.textFields["address"].typeText("w") + + waitForValueContains(app.textFields["address"], value: website["value"]!) + let value = app.textFields["address"].value + XCTAssertEqual(value as? String, website["value"]!, "Wrong autocompletion") + + // Enter the complete website and check that there is not more text added, just what user typed + app.buttons["Clear text"].tap() + app.textFields["address"].typeText(website["value"]!) + waitForValueContains(app.textFields["address"], value: website["value"]!) + let value2 = app.textFields["address"].value + XCTAssertEqual(value2 as? String, website["value"]!, "Wrong autocompletion") + } + // Test that deleting characters works correctly with autocomplete + func testAutocompleteDeletingChars() { + navigator.openURL(urlString: website["url"]!) + navigator.goto(URLBarOpen) + app.textFields["address"].typeText("www.moz") + + // First delete the autocompleted part + app.textFields["address"].typeText("\u{0008}") + // Then remove an extra char and check that the autocompletion stops working + app.textFields["address"].typeText("\u{0008}") + waitForValueContains(app.textFields["address"], value: "mo") + // Then write another letter and the autocompletion works again + app.textFields["address"].typeText("z") + waitForValueContains(app.textFields["address"], value: "moz") + + let value = app.textFields["address"].value + XCTAssertEqual(value as? String, website["value"]!, "Wrong autocompletion") + } + // Delete the entire string and verify that the home panels are shown again. + func testDeleteEntireString() { + navigator.openURL(urlString: website["url"]!) + navigator.goto(URLBarOpen) + app.textFields["address"].typeText("www.moz") + waitforExistence(app.buttons["Clear text"]) + app.buttons["Clear text"].tap() + + // Check that the address field is empty and that the home panels are shown + let value = app.textFields["address"].value + XCTAssertEqual(value as? String, "", "The url has not been removed correctly") + + waitforExistence(app.buttons["HomePanels.TopSites"]) + XCTAssertFalse(app.buttons["HomePanels.TopSites"].isEnabled) + XCTAssertTrue(app.buttons["HomePanels.Bookmarks"].isEnabled) + } + // Ensure that the scheme is included in the autocompletion. + func testEnsureSchemeIncludedAutocompletion() { + navigator.openURL(urlString: website["url"]!) + waitUntilPageLoad() + navigator.goto(URLBarOpen) + app.textFields["address"].typeText("https") + waitForValueContains(app.textFields["address"], value: "mozilla") + let value = app.textFields["address"].value + XCTAssertEqual(value as? String, "https://www.mozilla.org", "Wrong autocompletion") + } + // Non-matches. + func testNoMatches() { + navigator.openURL(urlString: website["url"]!) + navigator.openURL(urlString: website["subDomain"]!) + navigator.goto(URLBarOpen) + app.textFields["address"].typeText("baz") + let value = app.textFields["address"].value + // Check there is not more text added, just what user typed + XCTAssertEqual(value as? String, "baz", "Wrong autocompletion") + + // Ensure we don't match against TLDs. + app.buttons["Clear text"].tap() + app.textFields["address"].typeText("org") + let value2 = app.textFields["address"].value + // Check there is not more text added, just what user typed + XCTAssertEqual(value2 as? String, "org", "Wrong autocompletion") + + // Ensure we don't match other characters ie: ., :, / + app.buttons["Clear text"].tap() + app.textFields["address"].typeText(".") + let value3 = app.textFields["address"].value + XCTAssertEqual(value3 as? String, ".", "Wrong autocompletion") + + app.buttons["Clear text"].tap() + app.textFields["address"].typeText(":") + let value4 = app.textFields["address"].value + XCTAssertEqual(value4 as? String, ":", "Wrong autocompletion") + + app.buttons["Clear text"].tap() + app.textFields["address"].typeText("/") + let value5 = app.textFields["address"].value + XCTAssertEqual(value5 as? String, "/", "Wrong autocompletion") + + // Ensure we don't match strings that don't start a word. + app.buttons["Clear text"].tap() + app.textFields["address"].typeText("ozilla") + let value6 = app.textFields["address"].value + XCTAssertEqual(value6 as? String, "ozilla", "Wrong autocompletion") + + // Ensure we don't match words outside of the domain + app.buttons["Clear text"].tap() + app.textFields["address"].typeText("products") + let value7 = app.textFields["address"].value + XCTAssertEqual(value7 as? String, "products", "Wrong autocompletion") + } + // Test default domains. + func testDefaultDomains() { + navigator.goto(URLBarOpen) + app.textFields["address"].typeText("a") + waitForValueContains(app.textFields["address"], value: ".com") + let value = app.textFields["address"].value + XCTAssertEqual(value as? String, "amazon.com", "Wrong autocompletion") + + app.buttons["Clear text"].tap() + app.textFields["address"].typeText("an") + waitForValueContains(app.textFields["address"], value: ".com") + let value2 = app.textFields["address"].value + XCTAssertEqual(value2 as? String, "answers.com", "Wrong autocompletion") + + app.buttons["Clear text"].tap() + app.textFields["address"].typeText("anc") + waitForValueContains(app.textFields["address"], value: ".com") + let value3 = app.textFields["address"].value + XCTAssertEqual(value3 as? String, "ancestry.com", "Wrong autocompletion") + } + // Test mixed case autocompletion. + func testMixedCaseAutocompletion() { + navigator.openURL(urlString: website1["url"]!) + navigator.goto(URLBarOpen) + app.textFields["address"].typeText("MoZ") + waitForValueContains(app.textFields["address"], value: ".org") + let value = app.textFields["address"].value + XCTAssertEqual(value as? String, "MoZilla.org", "Wrong autocompletion") + + // Test that leading spaces still show suggestions. + app.buttons["Clear text"].tap() + app.textFields["address"].typeText(" moz") + waitForValueContains(app.textFields["address"], value: ".org") + let value2 = app.textFields["address"].value + XCTAssertEqual(value2 as? String, " mozilla.org", "Wrong autocompletion") + + // Test that trailing spaces do *not* show suggestions. + app.buttons["Clear text"].tap() + app.textFields["address"].typeText(" moz ") + waitForValueContains(app.textFields["address"], value: "moz") + let value3 = app.textFields["address"].value + // No autocompletion, just what user typed + XCTAssertEqual(value3 as? String, " moz ", "Wrong autocompletion") + } +} diff --git a/mobile/ios/XCUITests/FindInPageTest.swift b/mobile/ios/XCUITests/FindInPageTest.swift new file mode 100644 index 0000000000..15d01121cd --- /dev/null +++ b/mobile/ios/XCUITests/FindInPageTest.swift @@ -0,0 +1,123 @@ +/* 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/. */ + +import XCTest + +class FindInPageTests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + private func openFindInPageFromMenu() { + navigator.goto(FindInPage) + + waitforExistence(app.buttons["Next in-page result"]) + waitforExistence(app.buttons["Previous in-page result"]) + XCTAssertTrue(app.textFields[""].exists) + } + + func testFindFromMenu() { + + openFindInPageFromMenu() + + // Enter some text to start finding + app.textFields[""].typeText("Book") + + // Once there are matches, test previous/next buttons + waitforExistence(app.staticTexts["1/6"]) + XCTAssertTrue(app.staticTexts["1/6"].exists) + + let nextInPageResultButton = app.buttons["Next in-page result"] + nextInPageResultButton.tap() + waitforExistence(app.staticTexts["2/6"]) + XCTAssertTrue(app.staticTexts["2/6"].exists) + + nextInPageResultButton.tap() + waitforExistence(app.staticTexts["3/6"]) + XCTAssertTrue(app.staticTexts["3/6"].exists) + + let previousInPageResultButton = app.buttons["Previous in-page result"] + previousInPageResultButton.tap() + + waitforExistence(app.staticTexts["2/6"]) + XCTAssertTrue(app.staticTexts["2/6"].exists) + + previousInPageResultButton.tap() + waitforExistence(app.staticTexts["1/6"]) + XCTAssertTrue(app.staticTexts["1/6"].exists) + + // Tapping on close dismisses the search bar + //app.buttons["Done"].tap() + navigator.goto(BrowserTab) + waitforNoExistence(app.textFields["Book"]) + } + + func testQueryWithNoMatches() { + openFindInPageFromMenu() + + // Try to find text which does not match and check that there are not results + app.textFields["FindInPage.searchField"].typeText("foo") + waitforExistence(app.staticTexts["0/0"]) + XCTAssertTrue(app.staticTexts["0/0"].exists, "There should not be any matches") + } + + func testBarDissapearsWhenReloading() { + openFindInPageFromMenu() + + // Before reloading, it is necessary to hide the keyboard + app.textFields["url"].tap() + app.textFields["address"].typeText("\n") + + // Once the page is reloaded the search bar should not appear + waitforNoExistence(app.textFields[""]) + XCTAssertFalse(app.textFields[""].exists) + } + + func testBarDissapearsWhenOpeningTabsTray() { + openFindInPageFromMenu() + + // Dismiss keyboard + app.otherElements["contentView"].tap() + navigator.nowAt(BrowserTab) + + // Going to tab tray and back to the website hides the search field. + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells["The Book of Mozilla"]) + app.collectionViews.cells["The Book of Mozilla"].tap() + XCTAssertFalse(app.textFields[""].exists) + XCTAssertFalse(app.buttons["Next in-page result"].exists) + XCTAssertFalse(app.buttons["Previous in-page result"].exists) + } + + func testFindFromSelection() { + navigator.goto(BrowserTab) + let textToFind = "from" + + // Long press on the word to be found + waitUntilPageLoad() + waitforExistence(app.webViews.staticTexts[textToFind]) + let stringToFind = app.webViews.staticTexts.matching(identifier: textToFind) + let firstStringToFind = stringToFind.element(boundBy: 0) + firstStringToFind.press(forDuration: 3) + + // Find in page is correctly launched, bar with text pre-filled and + // the buttons to find next and previous + waitforExistence(app.menuItems["Find in Page"]) + app.menuItems["Find in Page"].tap() + waitforExistence(app.textFields[textToFind]) + XCTAssertTrue(app.textFields[textToFind].exists, "The bar does not appear with the text selected to be found") + XCTAssertTrue(app.buttons["Previous in-page result"].exists, "Find previus button exists") + XCTAssertTrue(app.buttons["Next in-page result"].exists, "Find next button exists") + } +} diff --git a/mobile/ios/XCUITests/FxScreenGraph.swift b/mobile/ios/XCUITests/FxScreenGraph.swift new file mode 100644 index 0000000000..460ca6d8cb --- /dev/null +++ b/mobile/ios/XCUITests/FxScreenGraph.swift @@ -0,0 +1,476 @@ +/* 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/. */ + +import Foundation +import XCTest + +let FirstRun = "OptionalFirstRun" +let TabTray = "TabTray" +let PrivateTabTray = "PrivateTabTray" +let URLBarOpen = "URLBarOpen" +let PrivateURLBarOpen = "PrivateURLBarOpen" +let BrowserTab = "BrowserTab" +let PrivateBrowserTab = "PrivateBrowserTab" +let BrowserTabMenu = "BrowserTabMenu" +let PageOptionsMenu = "PageOptionsMenu" +let FindInPage = "FindInPage" +let SettingsScreen = "SettingsScreen" +let HomePageSettings = "HomePageSettings" +let PasscodeSettings = "PasscodeSettings" +let PasscodeIntervalSettings = "PasscodeIntervalSettings" +let SearchSettings = "SearchSettings" +let NewTabSettings = "NewTabSettings" +let ClearPrivateDataSettings = "ClearPrivateDataSettings" +let LoginsSettings = "LoginsSettings" +let OpenWithSettings = "OpenWithSettings" +let ShowTourInSettings = "ShowTourInSettings" +let Intro_FxASignin = "Intro_FxASignin" + +let allSettingsScreens = [ + SettingsScreen, + HomePageSettings, + PasscodeSettings, + SearchSettings, + NewTabSettings, + ClearPrivateDataSettings, + LoginsSettings, + OpenWithSettings +] + +let Intro_Welcome = "Intro.Welcome" +let Intro_Search = "Intro.Search" +let Intro_Private = "Intro.Private" +let Intro_Mail = "Intro.Mail" +let Intro_Sync = "Intro.Sync" + +let allIntroPages = [ + Intro_Welcome, + Intro_Search, + Intro_Private, + Intro_Mail, + Intro_Sync +] + +let HomePanelsScreen = "HomePanels" +let PrivateHomePanelsScreen = "PrivateHomePanels" +let HomePanel_TopSites = "HomePanel.TopSites.0" +let HomePanel_Bookmarks = "HomePanel.Bookmarks.1" +let HomePanel_History = "HomePanel.History.2" +let HomePanel_ReadingList = "HomePanel.ReadingList.3" +let P_HomePanel_TopSites = "P_HomePanel.TopSites.0" +let P_HomePanel_Bookmarks = "P_HomePanel.Bookmarks.1" +let P_HomePanel_History = "P_HomePanel.History.2" +let P_HomePanel_ReadingList = "P_HomePanel.ReadingList.3" + +let allHomePanels = [ + HomePanel_Bookmarks, + HomePanel_TopSites, + HomePanel_History, + HomePanel_ReadingList +] +let allPrivateHomePanels = [ + P_HomePanel_Bookmarks, + P_HomePanel_TopSites, + P_HomePanel_History, + P_HomePanel_ReadingList +] + +let ContextMenu_ReloadButton = "ContextMenu_ReloadButton" + +func createScreenGraph(_ app: XCUIApplication, url: String = "https://www.mozilla.org/en-US/book/") -> ScreenGraph { + let map = ScreenGraph() + + let startBrowsingButton = app.buttons["IntroViewController.startBrowsingButton"] + let introScrollView = app.scrollViews["IntroViewController.scrollView"] + map.createScene(FirstRun) { scene in + // We don't yet have conditional edges, so we declare an edge from this node + // to BrowserTab, and then just make it work. + if introScrollView.exists { + + scene.gesture(to: BrowserTab) { + // go find the startBrowsing button on the second page of the intro. + introScrollView.swipeLeft() + startBrowsingButton.tap() + } + + scene.noop(to: allIntroPages[0]) + } else { + scene.noop(to: HomePanelsScreen) + } + } + + // Add the intro screens. + var i = 0 + let introLast = allIntroPages.count - 1 + let introPager = app.scrollViews["IntroViewController.scrollView"] + for intro in allIntroPages { + let prev = i == 0 ? nil : allIntroPages[i - 1] + let next = i == introLast ? nil : allIntroPages[i + 1] + + map.createScene(intro) { scene in + if let prev = prev { + scene.swipeRight(introPager, to: prev) + } + + if let next = next { + scene.swipeLeft(introPager, to: next) + } + + if i > 0 { + scene.tap(startBrowsingButton, to: BrowserTab) + } + } + + i += 1 + } + + map.createScene(URLBarOpen) { scene in + // This is used for opening BrowserTab with default mozilla URL + // For custom URL, should use Navigator.openNewURL or Navigator.openURL. + scene.typeText(url + "\r", into: app.textFields["address"], to: BrowserTab) + scene.tap( app.textFields["url"], to: HomePanelsScreen) + /* + scene.backAction = { + app.buttons["goBack"].tap() + } + */ + } + + map.createScene(PrivateURLBarOpen) { scene in + // This is used for opening BrowserTab with default mozilla URL + // For custom URL, should use Navigator.openNewURL or Navigator.openURL. + scene.typeText(url + "\r", into: app.textFields["address"], to:PrivateBrowserTab) + scene.tap( app.textFields["address"], to: PrivateHomePanelsScreen) + } + + let noopAction = {} + map.createScene(HomePanelsScreen) { scene in + scene.tap(app.buttons["HomePanels.TopSites"], to: HomePanel_TopSites) + scene.tap(app.buttons["HomePanels.Bookmarks"], to: HomePanel_Bookmarks) + scene.tap(app.buttons["HomePanels.History"], to: HomePanel_History) + scene.tap(app.buttons["HomePanels.ReadingList"], to: HomePanel_ReadingList) + + scene.tap(app.textFields["url"], to: URLBarOpen) + scene.tap(app.buttons["TabToolbar.menuButton"], to: BrowserTabMenu) + if map.isiPad() { + scene.tap(app.buttons["TopTabsViewController.tabsButton"], to: TabTray) + } else { + scene.gesture(to: TabTray) { + if (app.buttons["TabToolbar.tabsButton"].exists) { + app.buttons["TabToolbar.tabsButton"].tap() + } else { + app.buttons["URLBarView.tabsButton"].tap() + } + } + } + } + + map.createScene(PrivateHomePanelsScreen) { scene in + scene.tap(app.buttons["HomePanels.TopSites"], to: P_HomePanel_TopSites) + scene.tap(app.buttons["HomePanels.Bookmarks"], to: P_HomePanel_Bookmarks) + scene.tap(app.buttons["HomePanels.History"], to: P_HomePanel_History) + scene.tap(app.buttons["HomePanels.ReadingList"], to: P_HomePanel_ReadingList) + + scene.tap(app.textFields["url"], to: PrivateURLBarOpen) + scene.tap(app.buttons["TabToolbar.menuButton"], to: BrowserTabMenu) + if map.isiPad() { + scene.tap(app.buttons["TopTabsViewController.tabsButton"], to: PrivateTabTray) + } else { + scene.gesture(to: PrivateTabTray) { + if (app.buttons["TabToolbar.tabsButton"].exists) { + app.buttons["TabToolbar.tabsButton"].tap() + } else { + app.buttons["URLBarView.tabsButton"].tap() + } + } + } + } + + allHomePanels.forEach { name in + // Tab panel means that all the home panels are available all the time, so we can + // fake this out by a noop back to the HomePanelsScreen which can get to every other panel. + map.createScene(name) { scene in + scene.backAction = noopAction + } + } + + allPrivateHomePanels.forEach { name in + // Tab panel means that all the home panels are available all the time, so we can + // fake this out by a noop back to the HomePanelsScreen which can get to every other panel. + map.createScene(name) { scene in + scene.backAction = noopAction + } + } + + let closeMenuAction = { + app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.25)).tap() + } + + let navigationControllerBackAction = { + app.navigationBars.element(boundBy: 0).buttons.element(boundBy: 0).tap() + } + + let cancelBackAction = { + if map.isiPad() { + // There is not Cancel option in iPad this way it is closed + app/*@START_MENU_TOKEN@*/.otherElements["PopoverDismissRegion"]/*[[".otherElements[\"dismiss popup\"]",".otherElements[\"PopoverDismissRegion\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap() + } else { + app.buttons["PhotonMenu.cancel"].tap() + } + } + + let backBtnBackAction = { + if map.isiPad() { + app.buttons["URLBarView.backButton"].tap() + } + else { + app.buttons["TabToolbar.backButton"].tap() + } + } + + map.createScene(SettingsScreen) { scene in + let table = app.tables["AppSettingsTableViewController.tableView"] + + scene.tap(table.cells["Search"], to: SearchSettings) + scene.tap(table.cells["NewTab"], to: NewTabSettings) + scene.tap(table.cells["Homepage"], to: HomePageSettings) + scene.tap(table.cells["TouchIDPasscode"], to: PasscodeSettings) + scene.tap(table.cells["Logins"], to: LoginsSettings) + scene.tap(table.cells["ClearPrivateData"], to: ClearPrivateDataSettings) + scene.tap(table.cells["OpenWith.Setting"], to: OpenWithSettings) + scene.tap(table.cells["ShowTour"], to: ShowTourInSettings) + + scene.backAction = navigationControllerBackAction + } + + map.createScene(SearchSettings) { scene in + scene.backAction = navigationControllerBackAction + } + + map.createScene(NewTabSettings) { scene in + scene.backAction = navigationControllerBackAction + } + + map.createScene(HomePageSettings) { scene in + scene.backAction = navigationControllerBackAction + } + + map.createScene(PasscodeSettings) { scene in + scene.backAction = navigationControllerBackAction + + scene.tap(app.tables["AuthenticationManager.settingsTableView"].staticTexts["Require Passcode"], to: PasscodeIntervalSettings) + } + + map.createScene(PasscodeIntervalSettings) { scene in + // The test is likely to know what it needs to do here. + // This screen is protected by a passcode and is essentially modal. + scene.gesture(to: PasscodeSettings) { + if app.navigationBars["Require Passcode"].exists { + // Go back, accepting modifications + app.navigationBars["Require Passcode"].buttons["Passcode For Logins"].tap() + } else { + // Cancel + app.navigationBars["Enter Passcode"].buttons["Cancel"].tap() + } + } + } + + map.createScene(LoginsSettings) { scene in + scene.gesture(to: SettingsScreen) { + let loginList = app.tables["Login List"] + if loginList.exists { + app.navigationBars["Logins"].buttons["Settings"].tap() + } else { + app.navigationBars["Enter Passcode"].buttons["Cancel"].tap() + } + } + } + + map.createScene(ClearPrivateDataSettings) { scene in + scene.backAction = navigationControllerBackAction + } + + map.createScene(OpenWithSettings) { scene in + scene.backAction = navigationControllerBackAction + } + + map.createScene(ShowTourInSettings) { scene in + scene.gesture(to: Intro_FxASignin) { + let introScrollView = app.scrollViews["IntroViewController.scrollView"] + for _ in 1...4 { + introScrollView.swipeLeft() + } + app.buttons["Sign in to Firefox"].tap() + } + scene.backAction = { + introScrollView.swipeLeft() + startBrowsingButton.tap() + } + + } + + map.createScene(Intro_FxASignin) { scene in + scene.tap(app.navigationBars["Client.FxAContentView"].buttons.element(boundBy: 0), to: HomePanelsScreen) + } + + map.createScene(PrivateTabTray) { scene in + scene.tap(app.buttons["TabTrayController.addTabButton"], to: PrivateHomePanelsScreen) + scene.tap(app.buttons["TabTrayController.maskButton"], to: TabTray) + } + + map.createScene(TabTray) { scene in + scene.tap(app.buttons["TabTrayController.addTabButton"], to: HomePanelsScreen) + scene.tap(app.buttons["TabTrayController.maskButton"], to: PrivateTabTray) + } + + map.createScene(BrowserTab) { scene in + scene.tap(app.textFields["url"], to: URLBarOpen) + scene.tap(app.buttons["TabToolbar.menuButton"], to: BrowserTabMenu) + if map.isiPad() { + scene.tap(app.buttons["TopTabsViewController.tabsButton"], to: TabTray) + } else { + scene.gesture(to: TabTray) { + if (app.buttons["TabToolbar.tabsButton"].exists) { + app.buttons["TabToolbar.tabsButton"].tap() + } else { + app.buttons["URLBarView.tabsButton"].tap() + } + } + } + scene.tap(app.buttons["TabLocationView.pageOptionsButton"], to: PageOptionsMenu) + + scene.backAction = backBtnBackAction + } + + // make sure after the menu action, navigator.nowAt() is used to set the current state + map.createScene(PageOptionsMenu) {scene in + scene.tap(app.tables["Context Menu"].cells["Find in Page"], to: FindInPage) + scene.backAction = cancelBackAction + scene.dismissOnUse = true + } + + map.createScene(FindInPage) {scene in + scene.tap(app.buttons["FindInPage.close"], to: BrowserTab) + } + + map.createScene(PrivateBrowserTab) { scene in + scene.tap(app.textFields["url"], to: URLBarOpen) + scene.tap(app.buttons["TabToolbar.menuButton"], to: BrowserTabMenu) + if map.isiPad() { + scene.tap(app.buttons["TopTabsViewController.tabsButton"], to: PrivateTabTray) + } else { + scene.gesture(to: PrivateTabTray) { + if (app.buttons["TabToolbar.tabsButton"].exists) { + app.buttons["TabToolbar.tabsButton"].tap() + } else { + app.buttons["URLBarView.tabsButton"].tap() + } + } + } + scene.tap(app.buttons["TabLocationView.pageOptionsButton"], to: PageOptionsMenu) + + scene.backAction = backBtnBackAction + } + + map.createScene(BrowserTabMenu) { scene in + scene.backAction = cancelBackAction + scene.tap(app.tables.cells["Settings"], to: SettingsScreen) + + + scene.dismissOnUse = true + } + + map.initialSceneName = FirstRun + + return map +} +extension ScreenGraph { + + // Checks whether the current device is iPad or non-iPad + func isiPad() -> Bool { + if UIDevice.current.userInterfaceIdiom == .pad { + return true + } + return false + } +} + +extension Navigator { + + // Open a URL. Will use/re-use the first BrowserTab or NewTabScreen it comes to. + func openURL(urlString: String) { + self.goto(URLBarOpen) + let app = XCUIApplication() + app.textFields["address"].typeText(urlString + "\r") + + self.nowAt(BrowserTab) + } + + // Opens a URL in a new tab. + func openNewURL(urlString: String) { + self.goto(TabTray) + createNewTab() + self.openURL(urlString: urlString) + } + + // Closes all Tabs from the option in TabTrayMenu + func closeAllTabs() { + let app = XCUIApplication() + app.buttons["TabTrayController.removeTabsButton"].tap() + app.sheets.buttons["Close All Tabs"].tap() + self.nowAt(HomePanelsScreen) + } + + // Add a new Tab from the New Tab option in Browser Tab Menu + func createNewTab() { + let app = XCUIApplication() + self.goto(TabTray) + app.buttons["TabTrayController.addTabButton"].tap() + self.nowAt(HomePanelsScreen) + } + + // Add Tab(s) from the Tab Tray + func createSeveralTabsFromTabTray(numberTabs: Int) { + for _ in 1...numberTabs { + self.goto(TabTray) + self.goto(HomePanelsScreen) + + } + } + + func browserPerformAction(_ view: BrowserPerformAction) { + let PageMenuOptions = [.toggleBookmarkOption, .addReadingListOption, .copyURLOption, .findInPageOption, .toggleDesktopOption, .pinToTopSitesOption, .sendToDeviceOption, BrowserPerformAction.shareOption] + let BrowserMenuOptions = [.openTopSitesOption, .openBookMarksOption, .openHistoryOption, .openReadingListOption, .toggleHideImages, .toggleNightMode, BrowserPerformAction.openSettingsOption] + + let app = XCUIApplication() + + if PageMenuOptions.contains(view) { + self.goto(PageOptionsMenu) + app.tables["Context Menu"].cells[view.rawValue].tap() + } else if BrowserMenuOptions.contains(view) { + self.goto(BrowserTabMenu) + app.tables["Context Menu"].cells[view.rawValue].tap() + } + } +} +enum BrowserPerformAction: String { + // Page Menu + case toggleBookmarkOption = "menu-Bookmark" + case addReadingListOption = "addToReadingList" + case copyURLOption = "menu-Copy-Link" + case findInPageOption = "menu-FindInPage" + case toggleDesktopOption = "menu-RequestDesktopSite" + case pinToTopSitesOption = "action_pin" + case sendToDeviceOption = "menu-Send-to-Device" + case shareOption = "action_share" + + // Tab Menu + case openTopSitesOption = "menu-panel-TopSites" + case openBookMarksOption = "menu-panel-Bookmarks" + case openHistoryOption = "menu-panel-History" + case openReadingListOption = "menu-panel-ReadingList" + case toggleHideImages = "menu-NoImageMode" + case toggleNightMode = "menu-NightMode" + case openSettingsOption = "menu-Settings" +} diff --git a/mobile/ios/XCUITests/HistoryTests.swift b/mobile/ios/XCUITests/HistoryTests.swift new file mode 100644 index 0000000000..7cab65bc81 --- /dev/null +++ b/mobile/ios/XCUITests/HistoryTests.swift @@ -0,0 +1,44 @@ +/* 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/. */ + +import XCTest + +let webpage = ["url": "www.mozilla.org", "label": "Internet for people, not profit — Mozilla", "value": "mozilla.org"] + +class HistoryTests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + func testEmptyHistoryListFirstTime() { + // Go to History List from Top Sites and check it is empty + navigator.goto(HomePanel_History) + waitforExistence(app.tables.cells["HistoryPanel.recentlyClosedCell"]) + XCTAssertTrue(app.tables.cells["HistoryPanel.recentlyClosedCell"].exists) + XCTAssertTrue(app.tables.cells["HistoryPanel.syncedDevicesCell"].exists) + XCTAssertFalse(app.tables.otherElements.staticTexts["Today"].exists) + } + + func testOpenHistoryFromBrowserContextMenuOptions() { + navigator.openURL(urlString: webpage["url"]!) + navigator.browserPerformAction(.openHistoryOption) + + // Go to History List from Browser context menu and there should be one entry + waitforExistence(app.tables.cells["HistoryPanel.recentlyClosedCell"]) + XCTAssertTrue(app.tables.otherElements.staticTexts["Today"].exists) + XCTAssertTrue(app.tables.cells.staticTexts[webpage["label"]!].exists) + } + + func testOpenSyncDevices() { + navigator.goto(HomePanel_History) + app.tables.cells["HistoryPanel.syncedDevicesCell"].tap() + waitforExistence(app.tables.cells.staticTexts["Firefox Sync"]) + XCTAssertTrue(app.tables/*@START_MENU_TOKEN@*/.buttons["Sign in"]/*[[".cells.buttons[\"Sign in\"]",".buttons[\"Sign in\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.exists) + } +} diff --git a/mobile/ios/XCUITests/HomePageSettingsTest.swift b/mobile/ios/XCUITests/HomePageSettingsTest.swift new file mode 100644 index 0000000000..4cfa8a8e4b --- /dev/null +++ b/mobile/ios/XCUITests/HomePageSettingsTest.swift @@ -0,0 +1,75 @@ +/* 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/. */ + +import XCTest + +class HomePageSettingsTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + // This test has moved from KIF UITest - accesses google.com instead of local webserver instance + func testCurrentPage() { + navigator.goto(BrowserTab) + + // Accessing https means that it is routed + var currentURL = app.textFields["url"].value as! String + + // Go via the menu, becuase if we go via the TabTray, then we + // won't have a current tab. + navigator.goto(HomePageSettings) + app.tables.staticTexts["Use Current Page"].tap() + + // check the value of the current homepage + let homepageURL = app.tables.textFields["HomePageSettingTextField"].value as? String + + if homepageURL?.hasPrefix("https://") == true { + currentURL = "https://\(currentURL)" + } + XCTAssertEqual(currentURL, homepageURL) + app.tables.staticTexts["Clear"].tap() + + let urlString = app.tables.textFields["HomePageSettingTextField"].value ?? "" + + if iPad() { + XCTAssertEqual("", urlString as! String) + } else { + XCTAssertEqual("Enter a webpage", urlString as! String) + } + } + + /* Disabled due to new Photon UI + // Check whether the toolbar/menu shows homepage icon + func testShowHomePageIcon() { + // Check the Homepage icon is present in menu by default + navigator.goto(BrowserTab) + var currentURL = app.textFields["url"].value as! String + navigator.goto(PageOptionsMenu) + waitforExistence(app.tables.staticTexts["Set as Homepage"]) + app.tables.staticTexts["Set as Homepage"].tap() + app.buttons["Set Homepage"].tap() + + navigator.nowAt(BrowserTab) + navigator.goto(HomePageSettings) + + if currentURL.hasPrefix("https://") == false { + currentURL = "https://\(currentURL)" + } + + // Go to settings, and check the url are matching or not + let value = app.textFields["HomePageSettingTextField"].value as! String + XCTAssertEqual(value, currentURL, + "The webpage typed does not match with the one saved") + } + */ +} diff --git a/mobile/ios/XCUITests/HomePageSettingsUITest.swift b/mobile/ios/XCUITests/HomePageSettingsUITest.swift new file mode 100644 index 0000000000..aa31ded5c6 --- /dev/null +++ b/mobile/ios/XCUITests/HomePageSettingsUITest.swift @@ -0,0 +1,107 @@ +/* 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/. */ + +import XCTest + +let websiteUrl1 = "www.mozilla.org" +let websiteUrl2 = "developer.mozilla.org" +let invalidUrl = "1-2-3" + +class HomePageSettingsUITests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + private func enterWebPageAsHomepage(text: String) { + app.textFields["HomePageSettingTextField"].tap() + app.textFields["HomePageSettingTextField"].typeText(text) + let value = app.textFields["HomePageSettingTextField"].value + XCTAssertEqual(value as? String, text, "The webpage typed does not match with the one saved") + } + + func testTyping() { + navigator.goto(HomePageSettings) + // Enter a webpage + enterWebPageAsHomepage(text: websiteUrl1) + + // Check if it is saved going back and then again to home settings menu + navigator.goto(HomePageSettings) + let valueAfter = app.textFields["HomePageSettingTextField"].value + XCTAssertEqual(valueAfter as? String, websiteUrl1) + + // Check that it is actually set by opening a different website and going to Home + navigator.openURL(urlString: websiteUrl2) + navigator.goto(BrowserTabMenu) + + //Now check open home page should load the previously saved home page + let homePageMenuItem = app.tables["Context Menu"].cells["Open Homepage"] + waitforExistence(homePageMenuItem) + homePageMenuItem.tap() + waitForValueContains(app.textFields["url"], value: websiteUrl1) + } + + func testTypingBadURL() { + navigator.goto(HomePageSettings) + // Enter an invalid Url + enterWebPageAsHomepage(text: invalidUrl) + navigator.goto(SettingsScreen) + // Check that it is not saved + navigator.goto(HomePageSettings) + let valueAfter = app.textFields["HomePageSettingTextField"].value + XCTAssertEqual("Enter a webpage", valueAfter as! String) + + // There is no option to go to Home, instead the website open has the option to be set as HomePageSettings + navigator.openURL(urlString: websiteUrl1) + navigator.goto(BrowserTabMenu) + let homePageMenuItem = app.tables["Context Menu"].cells["Open Homepage"] + XCTAssertFalse(homePageMenuItem.exists) + } + + func testClipboard() { + // Go to a website and copy the url + navigator.openURL(urlString: websiteUrl1) + app.textFields["url"].press(forDuration: 5) + app.buttons["Copy Address"].tap() + + // Go to HomePage settings and paste it using the option Used Copied Link + navigator.goto(HomePageSettings) + XCTAssertTrue(app.cells["Use Copied Link"].isEnabled) + app.cells["Use Copied Link"].tap() + + // Check that the webpage has been correclty copied into the correct field + let value = app.textFields["HomePageSettingTextField"].value + XCTAssertEqual(value as? String, "https://\(websiteUrl1)/en-US/", + "The webpage typed does not match with the one saved") + } + + func testDisabledClipboard() { + // Type an incorrect URL and copy it + navigator.goto(URLBarOpen) + app.textFields["address"].typeText(invalidUrl) + app.textFields["address"].press(forDuration: 5) + app.menuItems["Select All"].tap() + app.menuItems["Copy"].tap() + app.buttons["goBack"].tap() + + // Go to HomePage settings and check that it is not possible to copy it into the set webpage field + navigator.nowAt(BrowserTab) + navigator.goto(HomePageSettings) + waitforExistence(app.staticTexts["Use Copied Link"]) + + // Check that nothing is copied in the Set webpage field + app.cells["Use Copied Link"].tap() + let value = app.textFields["HomePageSettingTextField"].value + + XCTAssertEqual("Enter a webpage", value as! String) + } +} diff --git a/mobile/ios/XCUITests/HomePageUITest.swift b/mobile/ios/XCUITests/HomePageUITest.swift new file mode 100644 index 0000000000..3e86e083f3 --- /dev/null +++ b/mobile/ios/XCUITests/HomePageUITest.swift @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import XCTest + +class HomePageUITest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + dismissFirstRunUI() + } + + override func tearDown() { + super.tearDown() + } + + func testSetInternalURLAsHomepage() { + loadWebPage("http://en.m.wikipedia.org/wiki/Main_Page") + app.buttons["Reader View"].tap() + navigator.goto(PageOptionsMenu) + app.cells["Set as Homepage"].tap() + app.buttons["Set Homepage"].tap() + navigator.nowAt(BrowserTab) + XCTAssertTrue(app.alerts.count == 0) + } +} diff --git a/mobile/ios/XCUITests/Info.plist b/mobile/ios/XCUITests/Info.plist new file mode 100644 index 0000000000..9411e4a06e --- /dev/null +++ b/mobile/ios/XCUITests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.6 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/mobile/ios/XCUITests/NavigationTest.swift b/mobile/ios/XCUITests/NavigationTest.swift new file mode 100644 index 0000000000..b841f7944d --- /dev/null +++ b/mobile/ios/XCUITests/NavigationTest.swift @@ -0,0 +1,299 @@ +/* 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/. */ + +import XCTest + +let website_1 = ["url": "www.mozilla.org", "label": "Internet for people, not profit — Mozilla", "value": "mozilla.org"] +let website_2 = ["url": "www.example.com", "label": "Example", "value": "example"] + +let urlAddOns = "addons.mozilla.org" + +let requestMobileSiteLabel = "Request Mobile Site" +let requestDesktopSiteLabel = "Request Desktop Site" + +class NavigationTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + func testNavigation() { + navigator.goto(URLBarOpen) + let urlPlaceholder = "Search or enter address" + XCTAssert(app.textFields["url"].exists) + let defaultValuePlaceholder = app.textFields["url"].placeholderValue! + + // Check the url placeholder text and that the back and forward buttons are disabled + XCTAssert(urlPlaceholder == defaultValuePlaceholder) + if iPad() { + app.buttons["goBack"].tap() + XCTAssertFalse(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertFalse(app.buttons["Forward"].isEnabled) + app.textFields["url"].tap() + } else { + XCTAssertFalse(app.buttons["TabToolbar.backButton"].isEnabled) + XCTAssertFalse(app.buttons["TabToolbar.forwardButton"].isEnabled) + } + + // Once an url has been open, the back button is enabled but not the forward button + navigator.openURL(urlString: website_1["url"]!) + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: website_1["value"]!) + if iPad() { + XCTAssertTrue(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertFalse(app.buttons["Forward"].isEnabled) + } else { + XCTAssertTrue(app.buttons["TabToolbar.backButton"].isEnabled) + XCTAssertFalse(app.buttons["TabToolbar.forwardButton"].isEnabled) + } + + // Once a second url is open, back button is enabled but not the forward one till we go back to url_1 + navigator.openURL(urlString: website_2["url"]!) + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: website_2["value"]!) + if iPad() { + XCTAssertTrue(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertFalse(app.buttons["Forward"].isEnabled) + // Go back to previous visited web site + app.buttons["URLBarView.backButton"].tap() + } else { + XCTAssertTrue(app.buttons["TabToolbar.backButton"].isEnabled) + XCTAssertFalse(app.buttons["TabToolbar.forwardButton"].isEnabled) + // Go back to previous visited web site + app.buttons["TabToolbar.backButton"].tap() + } + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: website_1["value"]!) + + if iPad() { + app.buttons["Forward"].tap() + } else { + // Go forward to next visited web site + app.buttons["TabToolbar.forwardButton"].tap() + } + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: website_2["value"]!) + } + + func testTapSignInShowsFxAFromTour() { + // Open FxAccount from tour option in settings menu and go throughout all the screens there + navigator.goto(Intro_FxASignin) + checkFirefoxSyncScreenShown() + + // Go back to NewTabScreen + navigator.goto(HomePanelsScreen) + waitforExistence(app.buttons["HomePanels.TopSites"]) + } + + func testTapSigninShowsFxAFromSettings() { + navigator.goto(SettingsScreen) + // Open FxAccount from settings menu and check the Sign in to Firefox scren + let signInToFirefoxStaticText = app.tables["AppSettingsTableViewController.tableView"].staticTexts["Sign in to Sync"] + signInToFirefoxStaticText.tap() + checkFirefoxSyncScreenShown() + + // After that it is possible to go back to Settings + let settingsButton = app.navigationBars["Client.FxAContentView"].buttons["Settings"] + settingsButton.tap() + } + + func testTapSignInShowsFxAFromRemoteTabPanel() { + navigator.goto(HomePanel_TopSites) + // Open FxAccount from remote tab panel and check the Sign in to Firefox scren + navigator.goto(HomePanel_History) + XCTAssertTrue(app.tables["History List"].staticTexts["Synced Devices"].isEnabled) + app.tables["History List"].staticTexts["Synced Devices"].tap() + app.tables.buttons["Sign in"].tap() + checkFirefoxSyncScreenShown() + app.navigationBars["Client.FxAContentView"].buttons["Done"].tap() + navigator.nowAt(HomePanel_History) + } + + private func checkFirefoxSyncScreenShown() { + waitforExistence(app.webViews.staticTexts["Sign in"]) + XCTAssertTrue(app.webViews.textFields["Email"].exists) + XCTAssertTrue(app.webViews.secureTextFields["Password"].exists) + XCTAssertTrue(app.webViews.buttons["Sign in"].exists) + } + + func testScrollsToTopWithMultipleTabs() { + navigator.goto(TabTray) + navigator.openURL(urlString: website_1["url"]!) + waitForValueContains(app.textFields["url"], value: website_1["value"]!) + + // Element at the TOP. TBChanged once the web page is correclty shown + let topElement = app.webViews.staticTexts["Internet for people, "] + + // Element at the BOTTOM + let bottomElement = app.webViews.links.staticTexts["Contact Us"] + + // Scroll to bottom + bottomElement.tap() + waitUntilPageLoad() + if iPad() { + app.buttons["URLBarView.backButton"].tap() + } else { + app.buttons["TabToolbar.backButton"].tap() + } + waitUntilPageLoad() + + // Scroll to top + topElement.tap() + waitforExistence(topElement) + } + + private func checkMobileView() { + let mobileViewElement = app.webViews.links.staticTexts["View classic desktop site"] + waitforExistence(mobileViewElement) + XCTAssertTrue (mobileViewElement.exists, "Mobile view is not available") + } + + private func checkDesktopView() { + let desktopViewElement = app.webViews.links.staticTexts["View Mobile Site"] + waitforExistence(desktopViewElement) + XCTAssertTrue (desktopViewElement.exists, "Desktop view is not available") + } + + private func clearData() { + navigator.goto(ClearPrivateDataSettings) + app.tables.staticTexts["Clear Private Data"].tap() + app.alerts.buttons["OK"].tap() + navigator.goto(HomePanel_TopSites) + } + + func testToggleBetweenMobileAndDesktopSiteFromSite() { + clearData() + let goToDesktopFromMobile = app.webViews.links.staticTexts["View classic desktop site"] + // Open URL by default in mobile view + navigator.openURL(urlString: urlAddOns) + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: urlAddOns) + waitforExistence(goToDesktopFromMobile) + + // From the website go to Desktop view + goToDesktopFromMobile.tap() + waitUntilPageLoad() + checkDesktopView() + + // From the website go back to Mobile view + app.webViews.links.staticTexts["View Mobile Site"].tap() + waitUntilPageLoad() + checkMobileView() + } + + func testToggleBetweenMobileAndDesktopSiteFromMenu() { + clearData() + navigator.openURL(urlString: urlAddOns) + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: urlAddOns) + + // Mobile view by default, desktop view should be available + navigator.browserPerformAction(.toggleDesktopOption) + checkDesktopSite() + + // From desktop view it is posible to change to mobile view again + navigator.nowAt(BrowserTab) + navigator.browserPerformAction(.toggleDesktopOption) + checkMobileSite() + } + + private func checkMobileSite() { + app.buttons["TabLocationView.pageOptionsButton"].tap() + waitforExistence(app.tables.cells["menu-RequestDesktopSite"].staticTexts[requestDesktopSiteLabel]) + navigator.goto(BrowserTab) + } + + private func checkDesktopSite() { + app.buttons["TabLocationView.pageOptionsButton"].tap() + waitforExistence(app.tables.cells["menu-RequestDesktopSite"].staticTexts[requestMobileSiteLabel]) + navigator.goto(BrowserTab) + } + + func testNavigationPreservesDesktopSiteOnSameHost() { + clearData() + navigator.openURL(urlString: urlAddOns) + waitUntilPageLoad() + + // Mobile view by default, desktop view should be available + navigator.browserPerformAction(.toggleDesktopOption) + waitforNoExistence(app.tables["Context Menu"]) + checkDesktopView() + + // Select any link to navigate to another site and check if the view is kept in desktop view + waitforExistence(app.webViews.links["Featured ›"]) + app.webViews.links["Featured ›"].tap() + waitUntilPageLoad() + checkDesktopView() + } + + func testReloadPreservesMobileOrDesktopSite() { + clearData() + navigator.openURL(urlString: urlAddOns) + waitUntilPageLoad() + + // Mobile view by default, desktop view should be available + navigator.browserPerformAction(.toggleDesktopOption) + + // After reloading a website the desktop view should be kept + if iPad() { + app.buttons["Reload"].tap() + } else { + app.buttons["TabToolbar.stopReloadButton"].tap() + } + waitForValueContains(app.textFields["url"], value: urlAddOns) + checkDesktopView() + + // From desktop view it is posible to change to mobile view again + navigator.nowAt(BrowserTab) + navigator.browserPerformAction(.toggleDesktopOption) + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: urlAddOns) + + // After reloading a website the mobile view should be kept + if iPad() { + app.buttons["Reload"].tap() + } else { + app.buttons["TabToolbar.stopReloadButton"].tap() + } + checkMobileView() + } + + /* Disable test due to bug 1346157, the desktop view is not kept after going back and forward + func testBackForwardNavigationRestoresMobileOrDesktopSite() { + clearData() + let desktopViewElement = app.webViews.links.staticTexts["Mobile"] + + // Open first url and keep it in mobile view + navigator.openURL(urlString: urlAddOns) + waitForValueContains(app.textFields["url"], value: urlAddOns) + checkMobileView() + // Open a second url and change it to desktop view + navigator.openURL(urlString: "www.linkedin.com") + navigator.goto(PageOptionsMenu) + waitforExistence(app.tables.cells["menu-RequestDesktopSite"].staticTexts[requestDesktopSiteLabel]) + app.tables.cells["menu-RequestDesktopSite"].tap() + waitforExistence(desktopViewElement) + XCTAssertTrue (desktopViewElement.exists, "Desktop view is not available") + + // Go back to first url and check that the view is still mobile view + app.buttons["TabToolbar.backButton"].tap() + waitForValueContains(app.textFields["url"], value: urlAddOns) + checkMobileView() + + // Go forward to second url and check that the view is still desktop view + app.buttons["TabToolbar.forwardButton"].tap() + waitForValueContains(app.textFields["url"], value: "www.linkedin.com") + waitforExistence(desktopViewElement) + XCTAssertTrue (desktopViewElement.exists, "Desktop view is not available after coming from another site in mobile view") + } + */ + } diff --git a/mobile/ios/XCUITests/NightModeTests.swift b/mobile/ios/XCUITests/NightModeTests.swift new file mode 100644 index 0000000000..e485a475d2 --- /dev/null +++ b/mobile/ios/XCUITests/NightModeTests.swift @@ -0,0 +1,65 @@ +/* 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/. */ + +import XCTest +class NightModeTests: BaseTestCase { + + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + navigator = nil + app = nil + super.tearDown() + } + + private func nightModeOff() { + navigator.goto(BrowserTabMenu) + app.tables.cells["Disable Night Mode"].tap() + navigator.nowAt(BrowserTab) + } + + private func nightModeOn() { + navigator.goto(BrowserTabMenu) + app.tables.cells["Enable Night Mode"].tap() + navigator.nowAt(BrowserTab) + } + + private func checkNightModeOn() { + navigator.goto(BrowserTabMenu) + waitforExistence(app.tables.cells["Disable Night Mode"]) + navigator.goto(BrowserTab) + } + + private func checkNightModeOff() { + navigator.goto(BrowserTabMenu) + waitforExistence(app.tables.cells["Enable Night Mode"]) + navigator.goto(BrowserTab) + } + + func testNightModeUI() { + let url1 = "www.google.com" + + // Go to a webpage, and select night mode on and off, check it's applied or not + navigator.openNewURL(urlString: url1) + + //turn on the night mode + nightModeOn() + + //checking night mode on or off + checkNightModeOn() + + //turn off the night mode + nightModeOff() + + //checking night mode on or off + checkNightModeOff() + } +} diff --git a/mobile/ios/XCUITests/NoImageTests.swift b/mobile/ios/XCUITests/NoImageTests.swift new file mode 100644 index 0000000000..ae14b2a51d --- /dev/null +++ b/mobile/ios/XCUITests/NoImageTests.swift @@ -0,0 +1,65 @@ +/* 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/. */ + +import XCTest + +class NoImageTests: BaseTestCase { + + var navigator: Navigator! + var app: XCUIApplication! + static let NoImageButtonIdentifier = "menu-NoImageMode" + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + navigator = nil + app = nil + super.tearDown() + } + + private func showImages() { + navigator.goto(BrowserTabMenu) + app.tables["Context Menu"].cells["menu-NoImageMode"].tap() + navigator.nowAt(BrowserTab) + } + + private func hideImages() { + navigator.goto(BrowserTabMenu) + app.tables["Context Menu"].cells["menu-NoImageMode"].tap() + navigator.nowAt(BrowserTab) + } + + private func checkShowImages() { + navigator.goto(BrowserTabMenu) + waitforExistence(app.tables["Context Menu"].cells["menu-NoImageMode"]) + XCTAssertTrue(app.tables["Context Menu"].cells["menu-NoImageMode"].staticTexts["Show Images"].exists) + navigator.goto(BrowserTab) + } + + private func checkHideImages() { + navigator.goto(BrowserTabMenu) + waitforExistence(app.tables["Context Menu"].cells["menu-NoImageMode"]) + XCTAssertTrue(app.tables["Context Menu"].cells["menu-NoImageMode"].staticTexts["Hide Images"].exists) + navigator.goto(BrowserTab) + } + + // Functionality is tested by UITests/NoImageModeTests, here only the UI is updated properly + func testImageOnOff() { + // Go to a webpage, and select no images or hide images, check it's hidden or not + navigator.openNewURL(urlString: "www.google.com") + waitUntilPageLoad() + + // Select hide images, and check the UI is updated + hideImages() + checkShowImages() + + // Select show images, and check the UI is updated + showImages() + checkHideImages() + } +} diff --git a/mobile/ios/XCUITests/PhotonActionSheetTest.swift b/mobile/ios/XCUITests/PhotonActionSheetTest.swift new file mode 100644 index 0000000000..1e7e07bd67 --- /dev/null +++ b/mobile/ios/XCUITests/PhotonActionSheetTest.swift @@ -0,0 +1,87 @@ +/* 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/. */ + +import XCTest + +class PhotonActionSheetTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + func testPinToTop() { + navigator.openURL(urlString: "http://example.com") + waitUntilPageLoad() + // Open Action Sheet + app.buttons["TabLocationView.pageOptionsButton"].tap() + + // Pin the site + app.cells["Pin to Top Sites"].tap() + + // Verify that the site has been pinned + + // Open menu + app.buttons["Menu"].tap() + + // Navigate to top sites + app.cells["Top Sites"].tap() + + waitforExistence(app.cells["TopSite"].firstMatch) + + // Verify that the site is pinned to top + let cell = app.cells["TopSite"].firstMatch + XCTAssertEqual(cell.label, "example") + + // Remove pin + cell.press(forDuration: 2) + app.cells["Remove"].tap() + } + + func testShareOptionIsShown() { + navigator.browserPerformAction(.shareOption) + + // Wait to see the Share options sheet + waitforExistence(app.buttons["Copy"]) + } + + func testShareOptionIsShownFromShortCut() { + navigator.goto(BrowserTab) + waitUntilPageLoad() + app.buttons["TabLocationView.pageOptionsButton"].press(forDuration: 1) + // Wait to see the Share options sheet + waitforExistence(app.buttons["Copy"]) + } + + func testSendToDeviceFromPageOptionsMenu() { + // User not logged in + navigator.browserPerformAction(.sendToDeviceOption) + waitforExistence(app.images["emptySync"]) + XCTAssertTrue(app.staticTexts["You are not signed in to your Firefox Account."].exists) + } + + func testSendToDeviceFromShareOption() { + // Open and Wait to see the Share options sheet + navigator.browserPerformAction(.shareOption) + waitforExistence(app.buttons["More"]) + waitforNoExistence(app.buttons["Send Tab"]) + app.collectionViews.cells/*@START_MENU_TOKEN@*/.collectionViews.containing(.button, identifier:"Copy")/*[[".collectionViews.containing(.button, identifier:\"Create PDF\")",".collectionViews.containing(.button, identifier:\"Print\")",".collectionViews.containing(.button, identifier:\"Copy\")"],[[[-1,2],[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.buttons["More"].tap() + + // Enable Send Tab + let sendTabButton = app.tables.cells.switches["Send Tab"] + sendTabButton.tap() + app.navigationBars["Activities"].buttons["Done"].tap() + + // Send Tab option appears on the Share options sheet + waitforExistence(app.buttons["Send Tab"]) + app.buttons["Send Tab"].tap() + + // User not logged in + waitforExistence(app.images["emptySync"]) + XCTAssertTrue(app.staticTexts["You are not signed in to your Firefox Account."].exists) + } +} diff --git a/mobile/ios/XCUITests/PrivateBrowsingTest.swift b/mobile/ios/XCUITests/PrivateBrowsingTest.swift new file mode 100644 index 0000000000..b86509f149 --- /dev/null +++ b/mobile/ios/XCUITests/PrivateBrowsingTest.swift @@ -0,0 +1,166 @@ +/* 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/. */ + +import XCTest + +let url1 = "www.mozilla.org" +let url2 = "www.facebook.com" + +let url1Label = "Internet for people, not profit — Mozilla" +let url2Label = "Facebook - Log In or Sign Up" + +class PrivateBrowsingTest: BaseTestCase { + + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + func testPrivateTabDoesNotTrackHistory() { + navigator.openURL(urlString: url1) + navigator.goto(BrowserTabMenu) + // Go to History screen + waitforExistence(app.tables.cells["History"]) + app.tables.cells["History"].tap() + navigator.nowAt(BrowserTab) + waitforExistence(app.tables["History List"]) + + XCTAssertTrue(app.tables["History List"].staticTexts[url1Label].exists) + // History without counting Recently Closed and Synced devices + let history = app.tables["History List"].cells.count - 2 + + XCTAssertEqual(history, 1, "History entries in regular browsing do not match") + + // Go to Private browsing to open a website and check if it appears on History + navigator.goto(PrivateTabTray) + navigator.openURL(urlString: url2) + navigator.nowAt(PrivateBrowserTab) + waitForValueContains(app.textFields["url"], value: "facebook") + navigator.goto(BrowserTabMenu) + waitforExistence(app.tables.cells["History"]) + app.tables.cells["History"].tap() + waitforExistence(app.tables["History List"]) + XCTAssertTrue(app.tables["History List"].staticTexts[url1Label].exists) + XCTAssertFalse(app.tables["History List"].staticTexts[url2Label].exists) + + // Open one tab in private browsing and check the total number of tabs + let privateHistory = app.tables["History List"].cells.count - 2 + XCTAssertEqual(privateHistory, 1, "History entries in private browsing do not match") + } + + func testTabCountShowsOnlyNormalOrPrivateTabCount() { + // Open two tabs in normal browsing and check the number of tabs open + navigator.openNewURL(urlString: url1) + waitUntilPageLoad() + navigator.goto(TabTray) + navigator.goto(BrowserTab) + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells[url1Label]) + let numTabs = app.collectionViews.cells.count + XCTAssertEqual(numTabs, 3, "The number of regular tabs is not correct") + + // Open one tab in private browsing and check the total number of tabs + navigator.goto(PrivateTabTray) + navigator.goto(URLBarOpen) + waitUntilPageLoad() + navigator.openURL(urlString: url2) + waitUntilPageLoad() + navigator.nowAt(PrivateBrowserTab) + waitForValueContains(app.textFields["url"], value: "facebook") + + navigator.goto(PrivateTabTray) + + waitforExistence(app.collectionViews.cells[url2Label]) + let numPrivTabs = app.collectionViews.cells.count + XCTAssertEqual(numPrivTabs, 1, "The number of private tabs is not correct") + + // Go back to regular mode and check the total number of tabs + navigator.goto(TabTray) + waitforExistence(app.collectionViews.cells[url1Label]) + waitforNoExistence(app.collectionViews.cells[url2Label]) + let numRegularTabs = app.collectionViews.cells.count + XCTAssertEqual(numRegularTabs, 3, "The number of regular tabs is not correct") + } + + func testClosePrivateTabsOptionClosesPrivateTabs() { + // Check that Close Private Tabs when closing the Private Browsing Button is off by default + navigator.goto(SettingsScreen) + let settingsTableView = app.tables["AppSettingsTableViewController.tableView"] + + while settingsTableView.staticTexts["Close Private Tabs"].exists == false { + settingsTableView.swipeUp() + } + + let closePrivateTabsSwitch = settingsTableView.switches["Close Private Tabs, When Leaving Private Browsing"] + + XCTAssertFalse(closePrivateTabsSwitch.isSelected) + + // Open a Private tab + navigator.goto(PrivateTabTray) + navigator.openURL(urlString: url1) + //Wait until the page loads + waitUntilPageLoad() + navigator.nowAt(PrivateBrowserTab) + navigator.goto(PrivateTabTray) + + // Go back to regular browser + navigator.goto(TabTray) + + // Go back to private browsing and check that the tab has not been closed + navigator.goto(PrivateTabTray) + waitforExistence(app.collectionViews.cells[url1Label]) + let numPrivTabs = app.collectionViews.cells.count + XCTAssertEqual(numPrivTabs, 1, "The number of tabs is not correct, the private tab should not have been closed") + + app.collectionViews.cells[url1Label].tap() + navigator.nowAt(PrivateBrowserTab) + // Now the enable the Close Private Tabs when closing the Private Browsing Button + navigator.goto(SettingsScreen) + closePrivateTabsSwitch.tap() + navigator.goto(PrivateBrowserTab) + // Go back to regular browsing and check that the private tab has been closed and that the initial Private Browsing message appears when going back to Private Browsing + navigator.goto(PrivateTabTray) + navigator.goto(TabTray) + navigator.goto(PrivateTabTray) + waitforNoExistence(app.collectionViews.cells[url1Label]) + let numPrivTabsAfterClosing = app.collectionViews.cells.count + XCTAssertEqual(numPrivTabsAfterClosing, 0, "The number of tabs is not correct, the private tab should have been closed") + XCTAssertTrue(app.staticTexts["Private Browsing"].exists, "Private Browsing screen is not shown") + } + + func testPrivateBrowserPanelView() { + // If no private tabs are open, there should be a initial screen with label Private Browsing + navigator.goto(PrivateTabTray) + + XCTAssertTrue(app.staticTexts["Private Browsing"].exists, "Private Browsing screen is not shown") + let numPrivTabsFirstTime = app.collectionViews.cells.count + XCTAssertEqual(numPrivTabsFirstTime, 0, "The number of tabs is not correct, there should not be any private tab yet") + + // If a private tab is open Private Browsing screen is not shown anymore + navigator.goto(PrivateBrowserTab) + //Wait until the page loads + waitUntilPageLoad() + navigator.goto(PrivateTabTray) + + // Go to regular browsing + navigator.goto(TabTray) + + // Go back to private brosing + navigator.goto(PrivateTabTray) + + waitforNoExistence(app.staticTexts["Private Browsing"]) + XCTAssertFalse(app.staticTexts["Private Browsing"].exists, "Private Browsing screen is shown") + let numPrivTabsOpen = app.collectionViews.cells.count + XCTAssertEqual(numPrivTabsOpen, 1, "The number of tabs is not correct, there should be one private tab") + } +} diff --git a/mobile/ios/XCUITests/ReaderViewUITest.swift b/mobile/ios/XCUITests/ReaderViewUITest.swift new file mode 100644 index 0000000000..bee8eab6c3 --- /dev/null +++ b/mobile/ios/XCUITests/ReaderViewUITest.swift @@ -0,0 +1,143 @@ +/* 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/. */ + +import XCTest + +class ReaderViewTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + func testLoadReaderContent() { + navigator.goto(BrowserTab) + app.buttons["Reader View"].tap() + // The settings of reader view are shown as well as the content of the web site + waitforExistence(app.buttons["Display Settings"]) + XCTAssertTrue(app.webViews.staticTexts["The Book of Mozilla"].exists) + } + + private func addContentToReaderView() { + navigator.goto(BrowserTab) + waitUntilPageLoad() + app.buttons["Reader View"].tap() + waitforExistence(app.buttons["Add to Reading List"]) + app.buttons["Add to Reading List"].tap() + } + + private func checkReadingListNumberOfItems(items: Int) { + waitforExistence(app.tables["ReadingTable"]) + let list = app.tables["ReadingTable"].cells.count + XCTAssertEqual(list, UInt(items), "The number of items in the reading table is not correct") + } + + func testAddToReadingList() { + // Initially reading list is empty + navigator.goto(HomePanel_ReadingList) + + // Check the button is selected (is disabled and the rest bookmarks and so are enabled) + XCTAssertFalse(app.buttons["HomePanels.ReadingList"].isEnabled) + XCTAssertTrue(app.buttons["HomePanels.Bookmarks"].isEnabled) + + checkReadingListNumberOfItems(items: 0) + + // Add item to reading list and check that it appears + addContentToReaderView() + navigator.goto(HomePanel_ReadingList) + waitforExistence(app.buttons["HomePanels.ReadingList"]) + + // Check that there is one item + let savedToReadingList = app.tables["ReadingTable"].cells.staticTexts["The Book of Mozilla"] + XCTAssertTrue(savedToReadingList.exists) + checkReadingListNumberOfItems(items: 1) + } + + func testMarkAsReadAndUreadFromReaderView() { + addContentToReaderView() + + // Mark the content as read, so the mark as unread buttons appear + app.buttons["Mark as Read"].tap() + waitforExistence(app.buttons["Mark as Unread"]) + + // Mark the content as unread, so the mark as read button appear + app.buttons["Mark as Unread"].tap() + waitforExistence(app.buttons["Mark as Read"]) + } + + func testRemoveFromReadingView() { + addContentToReaderView() + // Once the content has been added, remove it + waitforExistence(app.buttons["Remove from Reading List"]) + app.buttons["Remove from Reading List"].tap() + + // Check that instead of the remove icon now it is shown the add to read list + waitforExistence(app.buttons["Add to Reading List"]) + + // Go to reader list view to check that there is not any item there + navigator.goto(HomePanel_ReadingList) + waitforExistence(app.buttons["HomePanels.ReadingList"]) + navigator.goto(HomePanel_ReadingList) + checkReadingListNumberOfItems(items: 0) + } + + func testMarkAsReadAndUnreadFromReadingList() { + addContentToReaderView() + navigator.goto(HomePanel_ReadingList) + waitforExistence(app.buttons["HomePanels.ReadingList"]) + navigator.goto(HomePanel_ReadingList) + + // Check that there is one item + let savedToReadingList = app.tables["ReadingTable"].cells.staticTexts["The Book of Mozilla"] + XCTAssertTrue(savedToReadingList.exists) + + // Mark it as read/unread + savedToReadingList.swipeLeft() + waitforExistence(app.buttons["Mark as Read"]) + app.buttons["Mark as Read"].tap() + savedToReadingList.swipeLeft() + waitforExistence(app.buttons["Mark as Unread"]) + } + + func testRemoveFromReadingList() { + addContentToReaderView() + navigator.goto(HomePanel_ReadingList) + waitforExistence(app.buttons["HomePanels.ReadingList"]) + navigator.goto(HomePanel_ReadingList) + + let savedToReadingList = app.tables["ReadingTable"].cells.staticTexts["The Book of Mozilla"] + savedToReadingList.swipeLeft() + waitforExistence(app.buttons["Remove"]) + + // Remove the item from reading list + app.buttons["Remove"].tap() + XCTAssertFalse(savedToReadingList.exists) + + // Reader list view should be empty + checkReadingListNumberOfItems(items: 0) + } + + func testAddToReadingListFromPageOptionsMenu() { + // First time Reading list is empty + navigator.goto(HomePanel_ReadingList) + checkReadingListNumberOfItems(items: 0) + + // Add item to Reading List from Page Options Menu + navigator.goto(BrowserTab) + waitUntilPageLoad() + navigator.browserPerformAction(.addReadingListOption) + + // Now there should be an item on the list + navigator.nowAt(BrowserTab) + navigator.browserPerformAction(.openReadingListOption) + checkReadingListNumberOfItems(items: 1) + } +} diff --git a/mobile/ios/XCUITests/ScreenGraph.swift b/mobile/ios/XCUITests/ScreenGraph.swift new file mode 100644 index 0000000000..6ff28b8954 --- /dev/null +++ b/mobile/ios/XCUITests/ScreenGraph.swift @@ -0,0 +1,388 @@ +/* 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/. */ + +/** + * ScreenGraph helps you get rid of the navigation boiler plate found in a lot of whole-application UI testing. + * + * You create a shared graph of UI 'screens' or 'scenes' for your app, and use it for every test. + * + * In your tests, you use a navigator which does the job of getting your tests from place to place in your application, + * leaving you to concentrate on testing, rather than maintaining brittle and duplicated navigation code. + * + * The shared graph may also have other uses, such as generating screen shots for the App Store or L10n translators. + * + * Under the hood, the ScreenGraph is using GameplayKit's path finding to do the heavy lifting. + */ + +import Foundation +import GameplayKit +import XCTest + +typealias Edge = (XCTestCase, String, UInt) -> Void +typealias SceneBuilder = (ScreenGraphNode) -> Void +typealias NodeVisitor = (String) -> Void + +/** + * ScreenGraph + * This is the main interface to building a graph of screens/app states and how to navigate between them. + * The ScreenGraph will be used as a map to navigate the test agent around the app. + */ +open class ScreenGraph { + var initialSceneName: String? + + var namedScenes: [String: ScreenGraphNode] = [:] + var nodedScenes: [GKGraphNode: ScreenGraphNode] = [:] + + var isReady: Bool = false + + let gkGraph: GKGraph + + init() { + self.gkGraph = GKGraph() + } +} + +extension ScreenGraph { + /** + * Method for creating a ScreenGraphNode in the graph. The node should be accompanied by a closure + * used to document the exits out of this node to other nodes. + */ + func createScene(_ name: String, file: String = #file, line: UInt = #line, builder: @escaping (ScreenGraphNode) -> Void) { + let scene = ScreenGraphNode(map: self, name: name, builder: builder) + scene.file = file + scene.line = line + namedScenes[name] = scene + nodedScenes[scene.gkNode] = scene + } +} + +extension ScreenGraph { + /** + * Create a new navigator object. Navigator objects are the main way of getting around the app. + * Typically, you'll do this in `TestCase.setUp()` + */ + func navigator(_ xcTest: XCTestCase, startingAt: String? = nil, file: String = #file, line: UInt = #line) -> Navigator { + buildGkGraph() + var current: ScreenGraphNode? + if let name = startingAt ?? initialSceneName { + current = namedScenes[name] + } + + if current == nil { + xcTest.recordFailure(withDescription: "The app's initial state couldn't be established.", + inFile: file, atLine: line, expected: false) + } + return Navigator(self, xcTest: xcTest, initialScene: current!) + } + + fileprivate func buildGkGraph() { + if isReady { + return + } + + isReady = true + + // Construct all the GKGraphNodes, and add them to the GKGraph. + let scenes = namedScenes.values + gkGraph.add(scenes.map { $0.gkNode }) + + // Now, use the scene builders to collect edge actions and destinations. + scenes.forEach { scene in + scene.builder(scene) + } + + scenes.forEach { scene in + let gkNodes = scene.edges.keys.flatMap { self.namedScenes[$0]?.gkNode } as [GKGraphNode] + scene.gkNode.addConnections(to: gkNodes, bidirectional: false) + } + } +} + +typealias Gesture = () -> Void + +/** + * The ScreenGraph is made up of nodes. It is not possible to init these directly, only by creating + * screen nodes from the ScreenGraph object. + * + * The ScreenGraphNode has all the methods needed to define edges from this node to another node, using the usual + * XCUIElement method of moving about. + */ +class ScreenGraphNode { + let name: String + fileprivate let builder: SceneBuilder + fileprivate let gkNode: GKGraphNode + fileprivate var edges: [String: Edge] = [:] + + fileprivate weak var map: ScreenGraph? + + // Iff this node has a backAction, this store temporarily stores + // the node we were at before we got to this one. This becomes the node we return to when the backAction is + // invoked. + fileprivate weak var returnNode: ScreenGraphNode? + + fileprivate var hasBack: Bool { + return backAction != nil + } + + /** + * This is an action that will cause us to go back from where we came from. + * This is most useful when the same screen is accessible from multiple places, + * and we have a back button to return to where we came from. + */ + var backAction: Gesture? + + /** + * This flag indicates that once we've moved on from this node, we can't come back to + * it via `backAction`. This is especially useful for Menus, and dialogs. + */ + var dismissOnUse: Bool = false + + var existsWhen: XCUIElement? + + fileprivate var line: UInt! + + fileprivate var file: String! + + fileprivate init(map: ScreenGraph, name: String, builder: @escaping SceneBuilder) { + self.map = map + self.name = name + self.gkNode = GKGraphNode() + self.builder = builder + } + + fileprivate func addEdge(_ dest: String, by edge: @escaping Edge) { + edges[dest] = edge + // by this time, we should've added all nodes in to the gkGraph. + + assert(map?.namedScenes[dest] != nil, "Destination scene '\(dest)' has not been created anywhere") + } +} + +private let existsPredicate = NSPredicate(format: "exists == true") +private let enabledPredicate = NSPredicate(format: "enabled == true") +private let hittablePredicate = NSPredicate(format: "hittable == true") +private let noopNodeVisitor: NodeVisitor = { _ in } + +extension ScreenGraphNode { + fileprivate func waitForElement(_ element: XCUIElement, withTest xcTest: XCTestCase, notFoundHandler: () -> Void) { + // Wait for 5 seconds for the element to exist. + let expectation = XCTNSPredicateExpectation(predicate: existsPredicate, object: element) + let result = XCTWaiter().wait(for: [expectation], timeout: 5) + if result != .completed { + notFoundHandler() + } + } +} + +// Public methods for defining edges out of this node. +extension ScreenGraphNode { + /** + * Declare that by performing the given action/gesture, then we can navigate from this node to the next. + * + * @param withElement – optional, but if provided will attempt to verify it is there before performing the action. + * @param to – the destination node. + */ + func gesture(withElement element: XCUIElement? = nil, to nodeName: String, file declFile: String = #file, line declLine: UInt = #line, g: @escaping () -> Void) { + addEdge(nodeName) { xcTest, file, line in + if let el = element { + self.waitForElement(el, withTest: xcTest) { _ in + xcTest.recordFailure(withDescription: "Cannot find \(el)", inFile: declFile, atLine: declLine, expected: false) + xcTest.recordFailure(withDescription: "Cannot get from \(self.name) to \(nodeName). See \(declFile)", inFile: file, atLine: line, expected: false) + } + } + g() + } + } + + func noop(to nodeName: String, file: String = #file, line: UInt = #line) { + self.gesture(to: nodeName, file: file, line: line) { + // NOOP. + } + } + + /** + * Declare that by tapping a given element, we should be able to navigate from this node to another. + * + * @param element - the element to tap + * @param to – the destination node. + */ + func tap(_ element: XCUIElement, to nodeName: String, file: String = #file, line: UInt = #line) { + self.gesture(withElement: element, to: nodeName, file: file, line: line) { + element.tap() + } + } + + func doubleTap(_ element: XCUIElement, to nodeName: String, file: String = #file, line: UInt = #line) { + self.gesture(withElement: element, to: nodeName, file: file, line: line) { + element.doubleTap() + } + } + + func typeText(_ text: String, into element: XCUIElement, to nodeName: String, file: String = #file, line: UInt = #line) { + self.gesture(withElement: element, to: nodeName, file: file, line: line) { + element.typeText(text) + } + } + + func swipeLeft(_ element: XCUIElement, to nodeName: String, file: String = #file, line: UInt = #line) { + self.gesture(withElement: element, to: nodeName, file: file, line: line) { + element.swipeLeft() + } + } + + func swipeRight(_ element: XCUIElement, to nodeName: String, file: String = #file, line: UInt = #line) { + self.gesture(withElement: element, to: nodeName, file: file, line: line) { + element.swipeRight() + } + } + + func swipeUp(_ element: XCUIElement, to nodeName: String, file: String = #file, line: UInt = #line) { + self.gesture(withElement: element, to: nodeName, file: file, line: line) { + element.swipeUp() + } + } + + func swipeDown(_ element: XCUIElement, to nodeName: String, file: String = #file, line: UInt = #line) { + self.gesture(withElement: element, to: nodeName, file: file, line: line) { + element.swipeDown() + } + } +} + +/** + * The Navigator provides a set of methods to navigate around the app. You can `goto` nodes, `visit` multiple nodes, + * or visit all nodes, but mostly you just goto. If you take actions that move around the app outside of the + * navigator, you can re-sync app with navigator my telling it which node it is now at, using the `nowAt` method. + */ +class Navigator { + fileprivate let map: ScreenGraph + fileprivate var currentScene: ScreenGraphNode + fileprivate var returnToRecentScene: ScreenGraphNode + fileprivate let xcTest: XCTestCase + + fileprivate init(_ map: ScreenGraph, xcTest: XCTestCase, initialScene: ScreenGraphNode) { + self.map = map + self.xcTest = xcTest + self.currentScene = initialScene + self.returnToRecentScene = initialScene + } + + /** + * Move the application to the named node. + */ + func goto(_ nodeName: String, file: String = #file, line: UInt = #line) { + goto(nodeName, file: file, line: line, visitWith: noopNodeVisitor) + } + + /** + * Move the application to the named node, wth an optional node visitor closure, which is called each time the + * node changes. + */ + func goto(_ nodeName: String, file: String = #file, line: UInt = #line, visitWith nodeVisitor: NodeVisitor) { + let gkSrc = currentScene.gkNode + guard let gkDest = map.namedScenes[nodeName]?.gkNode else { + xcTest.recordFailure(withDescription: "Cannot route to \(nodeName), because it doesn't exist", inFile: file, atLine: line, expected: false) + return + } + + var gkPath = map.gkGraph.findPath(from: gkSrc, to: gkDest) + guard gkPath.count > 0 else { + xcTest.recordFailure(withDescription: "Cannot route from \(currentScene.name) to \(nodeName)", inFile: file, atLine: line, expected: false) + return + } + + gkPath.removeFirst() + gkPath.forEach { gkNext in + if !currentScene.dismissOnUse { + returnToRecentScene = currentScene + } + + let nextScene = map.nodedScenes[gkNext]! + let action = currentScene.edges[nextScene.name]! + + // We definitely have an action, so it's save to unbox. + action(xcTest, file, line) + + if let testElement = nextScene.existsWhen { + nextScene.waitForElement(testElement, withTest: xcTest) { _ in + // TODO report error in the correct place in the graph. + self.xcTest.recordFailure(withDescription: "Cannot find \(testElement) in \(nextScene.name)", + inFile: nextScene.file, + atLine: nextScene.line, + expected: false) + } + } + + if nextScene.hasBack { + if nextScene.returnNode == nil { + nextScene.returnNode = returnToRecentScene + nextScene.gkNode.addConnections(to: [ returnToRecentScene.gkNode ], bidirectional: false) + nextScene.gesture(to: returnToRecentScene.name, g: nextScene.backAction!) + } + } + + if currentScene.hasBack { + if nextScene.name == currentScene.returnNode?.name { + currentScene.returnNode = nil + currentScene.gkNode.removeConnections(to: [ nextScene.gkNode ], bidirectional: false) + } + } + nodeVisitor(currentScene.name) + currentScene = nextScene + } + } + + /** + * Helper method when the navigator gets out of sync with the actual app. + * This should not be used too often, as it indicates you should probably have another node in your graph, + * or you should be using `scene.dismissOnUse = true`. + * Also useful if you're using XCUIElement taps directly to navigate from one node to another. + */ + func nowAt(_ nodeName: String, file: String = #file, line: UInt = #line) { + guard let newScene = map.namedScenes[nodeName] else { + xcTest.recordFailure(withDescription: "Cannot force to unknown \(nodeName). Currently at \(currentScene.name)", inFile: file, atLine: line, expected: false) + return + } + currentScene = newScene + } + + /** + * Visit the named nodes, calling the NodeVisitor the first time it is encountered. + */ + func visitNodes(_ nodes: [String], file: String = #file, line: UInt = #line, f: NodeVisitor) { + var visitedNodes = Set() + let desiredNodes = Set(nodes) + nodes.forEach { node in + if visitedNodes.contains(node) { + return + } + self.goto(node, file: file, line: line) { visitedNode in + if desiredNodes.contains(visitedNode) && !visitedNodes.contains(visitedNode) { + f(visitedNode) + } + visitedNodes.insert(visitedNode) + } + } + } + + /** + * Visit all nodes, calling the NodeVisitor the first time it is encountered. + * + * Some nodes may not be immediately available, depending on the state of the app. + */ + func visitAll(_ file: String = #file, line: UInt = #line, f: NodeVisitor) { + let nodes: [String] = self.map.namedScenes.keys.map { $0 } // keys can't be coerced into a [String] + self.visitNodes(nodes, file: file, line: line, f: f) + } + + /** + * Move the app back to its initial state. + * This may not be possible. + */ + func revert(_ file: String = #file, line: UInt = #line) { + if let initial = self.map.initialSceneName { + self.goto(initial, file: file, line: line) + } + } +} diff --git a/mobile/ios/XCUITests/SearchSettingsUITest.swift b/mobile/ios/XCUITests/SearchSettingsUITest.swift new file mode 100644 index 0000000000..30f6235f68 --- /dev/null +++ b/mobile/ios/XCUITests/SearchSettingsUITest.swift @@ -0,0 +1,123 @@ +/* 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/. */ + +import XCTest + +let defaultSearchEngine1 = "Google" +let defaultSearchEngine2 = "Amazon.com" +let customSearchEngine = ["name": "youtube", "url": "http://youtube.com/search?q=%s"] + +class SearchSettingsUITests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + func testDefaultSearchEngine() { + navigator.goto(SearchSettings) + // Check the default browser + let defaultSearchEngine = app.tables.cells.element(boundBy: 0) + waitforExistence(app.tables.cells.staticTexts[defaultSearchEngine1]) + + // Change to another browser and check it is set as default + defaultSearchEngine.tap() + let listOfEngines = app.tables + listOfEngines.staticTexts[defaultSearchEngine2].tap() + waitforExistence(app.tables.cells.staticTexts[defaultSearchEngine2]) + } + + func testCustomSearchEngineIsEditable() { + navigator.goto(SearchSettings) + // Add a custom search engine + addCustomSearchEngine() + // Check that the custom search appears on the list + waitforExistence(app.tables.cells.staticTexts[customSearchEngine["name"]!]) + + // Check that it can be edited + XCTAssertTrue(app.buttons["Edit"].isEnabled) + app.buttons["Edit"].tap() + + waitforExistence(app.tables.buttons["Delete \(customSearchEngine["name"]!)"]) + } + + private func addCustomSearchEngine() { + waitforExistence(app.tables.cells["customEngineViewButton"]) + app.tables.cells["customEngineViewButton"].tap() + waitforExistence(app.tables.cells.staticTexts["Search Engine"]) + app.tables.cells.textViews["customEngineTitle"].tap() + app.tables.cells.textViews["customEngineTitle"].typeText(customSearchEngine["name"]!) + + app.tables.cells.textViews["customEngineUrl"].tap() + app.tables.cells.textViews["customEngineUrl"].typeText(customSearchEngine["url"]!) + + app.buttons["Save"].tap() + // Check that custom engine has been added successfully + waitforExistence(app.tables.cells.staticTexts[customSearchEngine["name"]!]) + } + + func testCustomSearchEngineAsDefaultIsNotEditable() { + navigator.goto(SearchSettings) + // Edit is disabled + XCTAssertFalse(app.buttons["Edit"].isEnabled) + + addCustomSearchEngine() + // Edit is enabled + XCTAssertTrue(app.buttons["Edit"].isEnabled) + + // Select the custom engine as the default one + let defaultSearchEngine = app.tables.cells.element(boundBy: 0) + defaultSearchEngine.tap() + let listOfEngines = app.tables + listOfEngines.staticTexts[customSearchEngine["name"]!].tap() + // Edit is disabled + XCTAssertFalse(app.buttons["Edit"].isEnabled) + } + + func testNavigateToSearchPickerTurnsOffEditing() { + navigator.goto(SearchSettings) + // Edit is disabled + XCTAssertFalse(app.buttons["Edit"].isEnabled) + + addCustomSearchEngine() + // Edit is enabled + XCTAssertTrue(app.buttons["Edit"].isEnabled) + app.buttons["Edit"].tap() + XCTAssertTrue(app.buttons["Done"].isEnabled) + + // Navigate to the search engine picker and back + let defaultSearchEngine = app.tables.cells.element(boundBy: 0) + defaultSearchEngine.tap() + app.buttons["Cancel"].tap() + + // Check to see we're not in editing state, edit is enable and done does not appear + XCTAssertTrue(app.buttons["Edit"].isEnabled) + waitforNoExistence(app.buttons["Done"]) + } + + func testDeletingLastCustomEngineExitsEditing() { + navigator.goto(SearchSettings) + // Edit is disabled + XCTAssertFalse(app.buttons["Edit"].isEnabled) + // Add a custom search engine + addCustomSearchEngine() + XCTAssertTrue(app.buttons["Edit"].isEnabled) + + app.buttons["Edit"].tap() + XCTAssertTrue(app.buttons["Done"].isEnabled) + // Remove the custom search engine and check that edit is disabled + let tablesQuery = app.tables + tablesQuery.buttons["Delete \(customSearchEngine["name"]!)"].tap() + tablesQuery.buttons["Delete"].tap() + + XCTAssertFalse(app.buttons["Edit"].isEnabled) + } +} diff --git a/mobile/ios/XCUITests/SearchTest.swift b/mobile/ios/XCUITests/SearchTest.swift new file mode 100644 index 0000000000..fe02a87b43 --- /dev/null +++ b/mobile/ios/XCUITests/SearchTest.swift @@ -0,0 +1,178 @@ +/* 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/. */ + +import XCTest + +private let LabelPrompt: String = "Turn on search suggestions?" +private let SuggestedSite: String = "foobar meaning" + +class SearchTests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + private func typeOnSearchBar(text: String) { + waitforExistence(app.textFields["address"]) + app.textFields["address"].typeText(text) + } + + private func suggestionsOnOff() { + navigator.goto(SearchSettings) + app.tables.switches["Show Search Suggestions"].tap() + app.navigationBars["Search"].buttons["Settings"].tap() + app.navigationBars["Settings"].buttons["AppSettingsTableViewController.navigationItem.leftBarButtonItem"].tap() + } + + func testPromptPresence() { + // Suggestion is on by default (starting on Oct 24th 2017), so the prompt should not appear + navigator.goto(URLBarOpen) + typeOnSearchBar(text: "foobar") + waitforNoExistence(app.staticTexts[LabelPrompt]) + + // Suggestions should be shown + waitforExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + + // Disable Search suggestion + app.buttons["goBack"].tap() + navigator.nowAt(HomePanelsScreen) + suggestionsOnOff() + + // Suggestions should not be shown + waitforNoExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + navigator.nowAt(BrowserTab) + navigator.goto(URLBarOpen) + typeOnSearchBar(text: "foobar") + waitforNoExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + + // Verify that previous choice is remembered + app.buttons["goBack"].tap() + navigator.nowAt(HomePanelsScreen) + navigator.goto(URLBarOpen) + typeOnSearchBar(text: "foobar") + waitforNoExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + app.buttons["goBack"].tap() + navigator.nowAt(HomePanelsScreen) + + // Reset suggestion button, set it to on + suggestionsOnOff() + navigator.nowAt(HomePanelsScreen) + navigator.goto(URLBarOpen) + + // Suggestions prompt should appear + typeOnSearchBar(text: "foobar") + waitforExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + } + + // Promt does not appear once Search has been enabled by default, see bug: 1411184 + func testDismissPromptPresence() { + navigator.goto(URLBarOpen) + typeOnSearchBar(text: "foobar") + waitforExistence(app.staticTexts[LabelPrompt]) + + app.buttons["No"].tap() + waitforNoExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + app.buttons["Go"].tap() + navigator.nowAt(BrowserTab) + // Verify that it is possible to enable suggestions after selecting No + suggestionsOnOff() + navigator.nowAt(BrowserTab) + navigator.goto(URLBarOpen) + typeOnSearchBar(text: "foobar") + waitforExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + } + + func testDoNotShowSuggestionsWhenEnteringURL() { + // According to bug 1192155 if a string contains /, do not show suggestions, if there a space an a string, + // the suggestions are shown again + navigator.goto(URLBarOpen) + typeOnSearchBar(text: "foobar") + waitforNoExistence(app.staticTexts[LabelPrompt]) + + // Suggestions should be shown + waitforExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + + // Typing / should stop showing suggestions + app.textFields["address"].typeText("/") + waitforNoExistence(app.tables["SiteTable"].buttons[SuggestedSite]) + + // Typing space and char after / should show suggestions again + app.textFields["address"].typeText(" b") + waitforExistence(app.tables["SiteTable"].buttons["foobar burn cd"]) + } + + func testCopyPasteComplete() { + // Copy, Paste and Go to url + navigator.goto(URLBarOpen) + typeOnSearchBar(text: "www.mozilla.org") + app.textFields["address"].press(forDuration: 5) + app.menuItems["Select All"].tap() + app.menuItems["Copy"].tap() + app.buttons["goBack"].tap() + navigator.nowAt(HomePanelsScreen) + navigator.goto(URLBarOpen) + app.textFields["address"].tap() + waitforExistence(app.menuItems["Paste"]) + app.menuItems["Paste"].tap() + + // Verify that the Paste shows the search controller with prompt + waitforNoExistence(app.staticTexts[LabelPrompt]) + app.typeText("\r") + + // Check that the website is loaded + waitForValueContains(app.textFields["url"], value: "www.mozilla.org") + + // Go back, write part of moz, check the autocompletion + if iPad() { + app.buttons["URLBarView.backButton"].tap() + } else { + app.buttons["TabToolbar.backButton"].tap() + } + navigator.nowAt(HomePanelsScreen) + navigator.goto(URLBarOpen) + typeOnSearchBar(text: "moz") + waitForValueContains(app.textFields["address"], value: "mozilla.org") + let value = app.textFields["address"].value + XCTAssertEqual(value as? String, "mozilla.org") + } + + private func changeSearchEngine(searchEngine: String) { + navigator.goto(SearchSettings) + // Open the list of default search engines and select the desired + app.tables.cells.element(boundBy: 0).tap() + let tablesQuery2 = app.tables + tablesQuery2.staticTexts[searchEngine].tap() + + navigator.openURL(urlString: "foo") + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: searchEngine.lowercased()) + + // Go here so that next time it is possible to access settings + navigator.goto(BrowserTabMenu) + } + + func testSearchEngine() { + // Change to the each search engine and verify the search uses it + changeSearchEngine(searchEngine: "Bing") + changeSearchEngine(searchEngine: "DuckDuckGo") + changeSearchEngine(searchEngine: "Google") + changeSearchEngine(searchEngine: "Twitter") + changeSearchEngine(searchEngine: "Wikipedia") + changeSearchEngine(searchEngine: "Amazon.com") + changeSearchEngine(searchEngine: "Yahoo") + } + + func testDefaultSearchEngine() { + navigator.goto(SearchSettings) + XCTAssert(app.tables.staticTexts["Google"].exists) + } +} diff --git a/mobile/ios/XCUITests/SettingsTest.swift b/mobile/ios/XCUITests/SettingsTest.swift new file mode 100644 index 0000000000..4d44537d91 --- /dev/null +++ b/mobile/ios/XCUITests/SettingsTest.swift @@ -0,0 +1,39 @@ +/* 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/. */ + +import XCTest + +class SettingsTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + func testHelpOpensSUMOInTab() { + navigator.goto(SettingsScreen) + let settingsTableView = app.tables["AppSettingsTableViewController.tableView"] + + while settingsTableView.staticTexts["Help"].exists == false { + settingsTableView.swipeUp() + } + let helpMenu = settingsTableView.cells["Help"] + XCTAssertTrue(helpMenu.isEnabled) + helpMenu.tap() + + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: "support.mozilla.org") + waitforExistence(app.webViews.staticTexts["Firefox for iOS"]) + XCTAssertTrue(app.webViews.staticTexts["Firefox for iOS"].exists) + let numTabs = app.buttons["Show Tabs"].value + XCTAssertEqual("2", numTabs as? String, "Sume should be open in a different tab") + } +} diff --git a/mobile/ios/XCUITests/SiteLoadTest.swift b/mobile/ios/XCUITests/SiteLoadTest.swift new file mode 100644 index 0000000000..60c9d182dc --- /dev/null +++ b/mobile/ios/XCUITests/SiteLoadTest.swift @@ -0,0 +1,52 @@ +/* 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/. */ + +import XCTest + +// NOTE: This test should be DISABLED on XCUITEST/UITEST scheme. This test should be run in conjunction with +// XCode Profiler to measure the memory/CPU load +class SiteLoadTest: BaseTestCase { + + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + func testLoadSite() { + + let site = ["http://www.forbes.com", "http://www.amazon.com", "http://theguardian.com", "http://www.reddit.com", "http://cnn.com"] + let durationInHrs = 1 + let futureDate = Date().addingTimeInterval(TimeInterval(60 * 60 * durationInHrs)) + var counter = 0 + while Date() < futureDate { + navigator.goto(URLBarOpen) + navigator.openURL(urlString: site[counter % 5]) + sleep(5) + + navigator.nowAt(BrowserTab) + navigator.goto(TabTray) + + navigator.closeAllTabs() + navigator.goto(BrowserTab) + waitforNoExistence(app.staticTexts["1 tab(s) closed"]) + + // clear the cache + navigator.goto(ClearPrivateDataSettings) + app.tables.staticTexts["Clear Private Data"].tap() + waitforExistence(app.alerts.buttons["OK"]) + app.alerts.buttons["OK"].tap() + navigator.goto(BrowserTab) + waitforExistence(app.textFields["url"]) + counter += 1 + } + } +} diff --git a/mobile/ios/XCUITests/ThirdPartySearchTest.swift b/mobile/ios/XCUITests/ThirdPartySearchTest.swift new file mode 100644 index 0000000000..782c4acb81 --- /dev/null +++ b/mobile/ios/XCUITests/ThirdPartySearchTest.swift @@ -0,0 +1,178 @@ +/* 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/. */ + +import XCTest + +class ThirdPartySearchTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + dismissFirstRunUI() + } + + override func tearDown() { + super.tearDown() + } + + fileprivate func dismissKeyboardAssistant(forApp app: XCUIApplication) { + if iPad() { + let searchTheDocsSearchField = app.webViews.searchFields["Search the docs"] + searchTheDocsSearchField.typeText("\r") + } else { + app.buttons["Done"].tap() + } + } + + func testCustomSearchEngines() { + // Visit MDN to add a custom search engine + loadWebPage("https://developer.mozilla.org/en-US/search", waitForLoadToFinish: true) + if iPad() { + let searchTheDocsSearchField = app.webViews.searchFields["Search the docs"] + searchTheDocsSearchField.tap() + app.keyboards.buttons["Search"].tap() + searchTheDocsSearchField.tap() + } else { + app.webViews.searchFields.element(boundBy: 0).tap() + } + app.buttons["AddSearch"].tap() + app.alerts["Add Search Provider?"].buttons["OK"].tap() + XCTAssertFalse(app.buttons["AddSearch"].isEnabled) + dismissKeyboardAssistant(forApp: app) + + // Perform a search using a custom search engine + tabTrayButton(forApp: app).tap() + app.buttons["TabTrayController.addTabButton"].tap() + app.textFields["url"].tap() + app.typeText("window") + app.scrollViews.otherElements.buttons["developer.mozilla.org search"].tap() + + var url = app.textFields["url"].value as! String + if url.hasPrefix("https://") == false { + url = "https://\(url)" + } + XCTAssert(url.hasPrefix("https://developer.mozilla.org/en-US/search"), "The URL should indicate that the search was performed on MDN and not the default") + } + + func testCustomSearchEngineAsDefault() { + // Visit MDN to add a custom search engine + loadWebPage("https://developer.mozilla.org/en-US/search", waitForLoadToFinish: true) + + if iPad() { + let searchTheDocsSearchField = app.webViews.searchFields["Search the docs"] + searchTheDocsSearchField.tap() + app.keyboards.buttons["Search"].tap() + searchTheDocsSearchField.tap() + } else { + app.webViews.searchFields.element(boundBy: 0).tap() + } + app.buttons["AddSearch"].tap() + app.alerts["Add Search Provider?"].buttons["OK"].tap() + XCTAssertFalse(app.buttons["AddSearch"].isEnabled) + dismissKeyboardAssistant(forApp: app) + + // Go to settings and set MDN as the default + navigator.goto(SearchSettings) + app.tables.cells.element(boundBy: 0).tap() + app.tables.staticTexts["developer.mozilla.org"].tap() + navigator.goto(BrowserTab) + + // Perform a search to check + navigator.openNewURL(urlString:"window") + + // Ensure that the default search is MDN + var url = app.textFields["url"].value as! String + if url.hasPrefix("https://") == false { + url = "https://\(url)" + } + XCTAssert(url.hasPrefix("https://developer.mozilla.org/en-US/search"), "The URL should indicate that the search was performed on MDN and not the default") + } + + func testCustomSearchEngineDeletion() { + // Visit MDN to add a custom search engine + loadWebPage("https://developer.mozilla.org/en-US/search", waitForLoadToFinish: true) + + if iPad() { + let searchTheDocsSearchField = app.webViews.searchFields["Search the docs"] + searchTheDocsSearchField.tap() + app.keyboards.buttons["Search"].tap() + searchTheDocsSearchField.tap() + } else { + app.webViews.searchFields.element(boundBy: 0).tap() + } + app.buttons["AddSearch"].tap() + app.alerts["Add Search Provider?"].buttons["OK"].tap() + XCTAssertFalse(app.buttons["AddSearch"].isEnabled) + dismissKeyboardAssistant(forApp: app) + + let tabTrayButton = self.tabTrayButton(forApp: app) + tabTrayButton.tap() + app.buttons["TabTrayController.addTabButton"].tap() + app.textFields["url"].tap() + app.typeText("window") + + // For timing issue, we need a wait statement + waitforExistence(app.scrollViews.otherElements.buttons["developer.mozilla.org search"]) + XCTAssert(app.scrollViews.otherElements.buttons["developer.mozilla.org search"].exists) + app.typeText("\r") + + // Go to settings and set MDN as the default + navigator.goto(SearchSettings) + + app.navigationBars["Search"].buttons["Edit"].tap() + app.tables.buttons["Delete developer.mozilla.org"].tap() + app.tables.buttons["Delete"].tap() + + navigator.goto(BrowserTab) + + // Perform a search to check + tabTrayButton.tap(force: true) + app.buttons["TabTrayController.addTabButton"].tap() + + app.textFields["url"].tap() + app.typeText("window") + waitforNoExistence(app.scrollViews.otherElements.buttons["developer.mozilla.org search"]) + XCTAssertFalse(app.scrollViews.otherElements.buttons["developer.mozilla.org search"].exists) + + } + + func testCustomEngineFromCorrectTemplate() { + navigator.goto(SearchSettings) + app.tables.cells["customEngineViewButton"].tap() + + app.textViews["customEngineTitle"].tap() + app.typeText("Feeling Lucky") + app.textViews["customEngineUrl"].tap() + app.typeText("http://www.google.com/search?q=%s&btnI") + + app.navigationBars.buttons["customEngineSaveButton"].tap() + + // Perform a search using a custom search engine + navigator.goto(HomePanelsScreen) + app.textFields["url"].tap() + app.typeText("strange charm") + app.scrollViews.otherElements.buttons["Feeling Lucky search"].tap() + + // Ensure that correct search is done + let url = app.textFields["url"].value as! String + XCTAssert(url.hasSuffix("&btnI"), "The URL should indicate that the search was performed using IFL") + } + + func testCustomEngineFromIncorrectTemplate() { + navigator.goto(SearchSettings) + app.tables.cells["customEngineViewButton"].tap() + app.textViews["customEngineTitle"].tap() + app.typeText("Feeling Lucky") + app.textViews["customEngineUrl"].tap() + app.typeText("http://www.google.com/search?q=&btnI") //Occurunces of %s != 1 + + app.navigationBars.buttons["customEngineSaveButton"].tap() + + waitforExistence(app.alerts.element(boundBy: 0)) + XCTAssert(app.alerts.element(boundBy: 0).label == "Failed") + } +} diff --git a/mobile/ios/XCUITests/ToolbarTest.swift b/mobile/ios/XCUITests/ToolbarTest.swift new file mode 100644 index 0000000000..39c609ee12 --- /dev/null +++ b/mobile/ios/XCUITests/ToolbarTest.swift @@ -0,0 +1,94 @@ +/* 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/. */ + +import XCTest + +let website1: [String: String] = ["url": "www.mozilla.org", "label": "Internet for people, not profit — Mozilla", "value": "mozilla.org"] +let website2 = "yahoo.com" + +class ToolbarTests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + XCUIDevice.shared().orientation = UIDeviceOrientation.landscapeLeft + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + XCUIDevice.shared().orientation = UIDeviceOrientation.portrait + super.tearDown() + } + + /** + * Tests landscape page navigation enablement with the URL bar with tab switching. + */ + func testLandscapeNavigationWithTabSwitch() { + let urlPlaceholder = "Search or enter address" + XCTAssert(app.textFields["url"].exists) + let defaultValuePlaceholder = app.textFields["url"].placeholderValue! + + // Check the url placeholder text and that the back and forward buttons are disabled + XCTAssertTrue(urlPlaceholder == defaultValuePlaceholder, "The placeholder does not show the correct value") + XCTAssertFalse(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertFalse(app.buttons["Forward"].isEnabled) + XCTAssertFalse(app.buttons["Reload"].isEnabled) + + // Navigate to two pages and press back once so that all buttons are enabled in landscape mode. + navigator.openURL(urlString: website1["url"]!) + waitForValueContains(app.textFields["url"], value: website1["value"]!) + + XCTAssertTrue(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertFalse(app.buttons["Forward"].isEnabled) + XCTAssertTrue(app.buttons["Reload"].isEnabled) + + navigator.openURL(urlString: website2) + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: website2) + XCTAssertTrue(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertFalse(app.buttons["Forward"].isEnabled) + + app.buttons["URLBarView.backButton"].tap() + waitForValueContains(app.textFields["url"], value: website1["value"]!) + waitUntilPageLoad() + XCTAssertTrue(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertTrue(app.buttons["Forward"].isEnabled) + + // Open new tab and then go back to previous tab to test navigation buttons. + navigator.goto(TabTray) + waitforExistence(app.collectionViews.cells[website1["label"]!]) + app.collectionViews.cells[website1["label"]!].tap() + waitForValueContains(app.textFields["url"], value: website1["value"]!) + + // Test to see if all the buttons are enabled then close tab. + waitUntilPageLoad() + XCTAssertTrue(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertTrue(app.buttons["Forward"].isEnabled) + + navigator.nowAt(BrowserTab) + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells[website1["label"]!]) + app.collectionViews.cells[website1["label"]!].swipeRight() + + // Go Back to other tab to see if all buttons are disabled. + navigator.nowAt(BrowserTab) + XCTAssertFalse(app.buttons["URLBarView.backButton"].isEnabled) + XCTAssertFalse(app.buttons["Forward"].isEnabled) + } + + func testClearURLTextUsingBackspace() { + navigator.openURL(urlString: website1["url"]!) + waitForValueContains(app.textFields["url"], value: website1["value"]!) + + // Simulate pressing on backspace key should remove the text + app.textFields["url"].tap() + app.textFields["address"].typeText("\u{8}") + + let value = app.textFields["address"].value + XCTAssertEqual(value as? String, "", "The url has not been removed correctly") + } +} diff --git a/mobile/ios/XCUITests/TopTabsTest.swift b/mobile/ios/XCUITests/TopTabsTest.swift new file mode 100644 index 0000000000..fdfc6f97b6 --- /dev/null +++ b/mobile/ios/XCUITests/TopTabsTest.swift @@ -0,0 +1,178 @@ +/* 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/. */ + +import XCTest + +let url = "www.mozilla.org" +let urlLabel = "Internet for people, not profit — Mozilla" +let urlValue = "mozilla.org" + +let urlYah = "www.yahoo.com" +let urlLabelYah = "Yahoo" +let urlValueYah = "yahoo" + +let urlExample = "example.com" + +class TopTabsTest: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + super.tearDown() + } + + func testAddTabFromSettings() { + navigator.createNewTab() + navigator.openURL(urlString: url) + waitForValueContains(app.textFields["url"], value: urlValue) + waitforExistence(app.buttons["Show Tabs"]) + let numTab = app.buttons["Show Tabs"].value as? String + + XCTAssertEqual("2", numTab) + } + + func testAddTabFromTabTray() { + navigator.goto(TabTray) + navigator.openURL(urlString: url) + waitUntilPageLoad() + waitForValueContains(app.textFields["url"], value: urlValue) + // The tabs counter shows the correct number + let tabsOpen = app.buttons["Show Tabs"].value + XCTAssertEqual("2", tabsOpen as? String) + + // The tab tray shows the correct tabs + navigator.goto(TabTray) + waitforExistence(app.collectionViews.cells[urlLabel]) + } + + private func checkNumberOfTabsExpectedToBeOpen(expectedNumberOfTabsOpen: Int) { + let numTabsOpen = app.collectionViews.cells.count + XCTAssertEqual(numTabsOpen, UInt(expectedNumberOfTabsOpen), "The number of tabs open is not correct") + } + + func testAddTabFromContext() { + navigator.openURL(urlString: urlExample) + // Initially there is only one tab open + let tabsOpenInitially = app.buttons["Show Tabs"].value + XCTAssertEqual("1", tabsOpenInitially as? String) + + // Open link in a different tab and switch to it + waitforExistence(app.webViews.links.staticTexts["More information..."]) + app.webViews.links.staticTexts["More information..."].press(forDuration: 5) + app.buttons["Open in New Tab"].tap() + waitUntilPageLoad() + + // Open tab tray to check that both tabs are there + navigator.goto(TabTray) + waitforExistence(app.collectionViews.cells["Example Domain"]) + waitforExistence(app.collectionViews.cells["IANA — IANA-managed Reserved Domains"]) + + checkNumberOfTabsExpectedToBeOpen(expectedNumberOfTabsOpen: 2) + } + + // This test only runs for iPhone see bug 1409750 + func testAddTabByLongPressTabsButton() { + navigator.goto(BrowserTab) + app.buttons["TabToolbar.tabsButton"].press(forDuration: 1) + + waitforExistence(app.buttons["New Tab"]) + app.buttons["New Tab"].tap() + navigator.goto(TabTray) + + checkNumberOfTabsExpectedToBeOpen(expectedNumberOfTabsOpen: 2) + } + + // This test only runs for iPhone see bug 1409750 + func testAddPrivateTabByLongPressTabsButton() { + navigator.goto(BrowserTab) + app.buttons["TabToolbar.tabsButton"].press(forDuration: 1) + + waitforExistence(app.buttons["New Private Tab"]) + app.buttons["New Private Tab"].tap() + navigator.goto(TabTray) + + waitforExistence(app.buttons["TabTrayController.maskButton"]) + XCTAssertTrue(app.buttons["TabTrayController.maskButton"].isEnabled) + checkNumberOfTabsExpectedToBeOpen(expectedNumberOfTabsOpen: 1) + } + + func testSwitchBetweenTabs() { + // Open two urls from tab tray and switch between them + navigator.openURL(urlString: url) + navigator.goto(TabTray) + navigator.openURL(urlString: urlYah) + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells[urlLabel]) + app.collectionViews.cells[urlLabel].tap() + waitForValueContains(app.textFields["url"], value: urlValue) + + navigator.nowAt(BrowserTab) + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells[urlLabelYah]) + app.collectionViews.cells[urlLabelYah].tap() + waitForValueContains(app.textFields["url"], value: urlValueYah) + } + + func testCloseOneTab() { + navigator.openURL(urlString: url) + waitUntilPageLoad() + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells[urlLabel]) + + // 'x' button to close the tab is not visible, so closing by swiping the tab + app.collectionViews.cells[urlLabel].swipeRight() + + // After removing only one tab it automatically goes to HomepanelView + waitforExistence(app.collectionViews.cells["TopSitesCell"]) + XCTAssert(app.buttons["HomePanels.TopSites"].exists) + } + + func testCloseAllTabsUndo() { + // A different tab than home is open to do the proper checks + navigator.openURL(urlString: url) + waitUntilPageLoad() + navigator.createSeveralTabsFromTabTray (numberTabs: 3) + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells[urlLabel]) + checkNumberOfTabsExpectedToBeOpen(expectedNumberOfTabsOpen: 4) + + // Close all tabs, undo it and check that the number of tabs is correct + navigator.closeAllTabs() + app.buttons["Undo"].tap() + navigator.nowAt(BrowserTab) + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells[urlLabel]) + checkNumberOfTabsExpectedToBeOpen(expectedNumberOfTabsOpen: 4) + } + + func testCloseAllTabs() { + // A different tab than home is open to do the proper checks + navigator.openURL(urlString: url) + waitUntilPageLoad() + // Add several tabs from tab tray menu and check that the number is correct before closing all + navigator.createSeveralTabsFromTabTray (numberTabs: 3) + navigator.goto(TabTray) + + waitforExistence(app.collectionViews.cells[urlLabel]) + checkNumberOfTabsExpectedToBeOpen(expectedNumberOfTabsOpen: 4) + + // Close all tabs and check that the number of tabs is correct + navigator.closeAllTabs() + navigator.goto(TabTray) + + waitforNoExistence(app.collectionViews.cells[urlLabel]) + checkNumberOfTabsExpectedToBeOpen(expectedNumberOfTabsOpen: 1) + } +} diff --git a/mobile/ios/XCUITests/TrackingProtectionTests.swift b/mobile/ios/XCUITests/TrackingProtectionTests.swift new file mode 100644 index 0000000000..b34525f4de --- /dev/null +++ b/mobile/ios/XCUITests/TrackingProtectionTests.swift @@ -0,0 +1,65 @@ +/* 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/. */ + +import XCTest + +class TrackingProtectionTests: BaseTestCase { + var navigator: Navigator! + var app: XCUIApplication! + + override func setUp() { + super.setUp() + app = XCUIApplication() + navigator = createScreenGraph(app).navigator(self) + } + + override func tearDown() { + navigator = nil + app = nil + super.tearDown() + } + + // This test is to change the tracking protection to block known blockers + func testTrackingProtection() { + navigator.goto(SettingsScreen) + let appSettingsTableView = app.tables["AppSettingsTableViewController.tableView"] + //Scroll the table view until Tracking Proection cell is visible + while !app.staticTexts["Tracking Protection"].exists { + appSettingsTableView.swipeUp() + } + appSettingsTableView.staticTexts["Tracking Protection"].tap() + + //Check "Private Browsing Mode Only" is selected and other items are not selected + XCTAssertFalse(app.tables.cells["Always On"].isSelected) + XCTAssertTrue(app.tables.cells["Private Browsing Mode Only"].isSelected) + XCTAssertFalse(app.tables.cells["Never"].isSelected) + + //Select "Always On" + app.tables.cells["Always On"].tap() + XCTAssertTrue(app.tables.cells["Always On"].isSelected) + + app.navigationBars["Tracking Protection"].buttons["Settings"].tap() + + waitforExistence(app.navigationBars["Settings"].buttons["Done"]) + app.navigationBars["Settings"]/*@START_MENU_TOKEN@*/.buttons["Done"]/*[[".buttons[\"Done\"]",".buttons[\"AppSettingsTableViewController.navigationItem.leftBarButtonItem\"]"],[[[-1,1],[-1,0]]],[1]]@END_MENU_TOKEN@*/.tap() + + app/*@START_MENU_TOKEN@*/.buttons["TabToolbar.menuButton"]/*[[".buttons[\"Menu\"]",".buttons[\"TabToolbar.menuButton\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap() + let settingsmenuitemCell = app.tables.cells["Settings"] + settingsmenuitemCell.tap() + + let appSettingsTableView1 = app.tables["AppSettingsTableViewController.tableView"] + //Scroll the table view until Tracking Proection cell is visible + while !app.staticTexts["Tracking Protection"].exists { + appSettingsTableView1.swipeUp() + } + + appSettingsTableView1.staticTexts["Tracking Protection"].tap() + waitforExistence(app.tables.cells["Always On"]) + + //Check "Always On" is selected and other items are not selected + XCTAssertTrue(app.tables.cells["Always On"].isSelected) + XCTAssertFalse(app.tables.cells["Private Browsing Mode Only"].isSelected) + XCTAssertFalse(app.tables.cells["Never"].isSelected) + } +} diff --git a/mobile/ios/XCUITests/XCUITests-Bridging-Header.h b/mobile/ios/XCUITests/XCUITests-Bridging-Header.h new file mode 100644 index 0000000000..a7c30cbdb2 --- /dev/null +++ b/mobile/ios/XCUITests/XCUITests-Bridging-Header.h @@ -0,0 +1,14 @@ +/* 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/. */ + +#ifndef XCUITests_Bridging_Header_h +#define XCUITests_Bridging_Header_h + +#import "XCTest/XCUIApplication.h" +#import "XCTest/XCUIElement.h" +@interface XCUIApplication (Private) +- (id)initPrivateWithPath:(NSString *)path bundleID:(NSString *)bundleID; +@end + +#endif diff --git a/mobile/ios/bootstrap.sh b/mobile/ios/bootstrap.sh new file mode 100644 index 0000000000..07578f168b --- /dev/null +++ b/mobile/ios/bootstrap.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# +# 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/. */ +# +# Bootstrap the Carthage dependencies. If the Carthage directory +# already exists then nothing is done. This speeds up builds on +# CI services where the Carthage directory can be cached. +# +# Use the --force option to force a rebuild of the dependencies. +# + +if [ "$1" == "--force" ]; then + rm -rf Carthage/* + rm -rf ~/Library/Caches/org.carthage.CarthageKit +fi + +# Only enable this on the Xcode Server because it times out if it does not +# get any output for some time while building the dependencies. + +CARTHAGE_VERBOSE="" +if [ ! -z "$XCS_BOT_ID" ]; then + CARTHAGE_VERBOSE="--verbose" +fi + +carthage bootstrap $CARTHAGE_VERBOSE --platform ios --color auto --cache-builds diff --git a/mobile/ios/buddybuild_carthage_command.sh b/mobile/ios/buddybuild_carthage_command.sh new file mode 100644 index 0000000000..0fcaece8a1 --- /dev/null +++ b/mobile/ios/buddybuild_carthage_command.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# This is needed for Leanplum. Our bootstrap.sh is not run on +# BuddyBuild and the carthage command that BuddyBuild runs is +# not compatible with Leanplum for some reason. (It seems to +# have a problem with the --toolchain argument). + +carthage bootstrap --platform ios + diff --git a/mobile/ios/buddybuild_postbuild.sh b/mobile/ios/buddybuild_postbuild.sh new file mode 100644 index 0000000000..3fcf233563 --- /dev/null +++ b/mobile/ios/buddybuild_postbuild.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +chruby 2.3.1 +bundle install +bundle exec danger --fail-on-errors=false + +bash <(curl -s https://codecov.io/bash) diff --git a/mobile/ios/buddybuild_postclone.sh b/mobile/ios/buddybuild_postclone.sh new file mode 100644 index 0000000000..2ca4215d06 --- /dev/null +++ b/mobile/ios/buddybuild_postclone.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# Only setup virtualenv if we intend on localizing the app. +function setup_virtualenv { + # Install Python tooling for localizations scripts + echo password | sudo easy_install pip + echo password | sudo -S pip install --upgrade pip + echo password | sudo -S pip install virtualenv +} + +# +# Import only the shipping locales (from shipping_locales.txt) on our Beta and +# Release builds. Import all locales on Fennec_Enterprise, except for pull requests. +# + +git clone https://github.com/mozilla-mobile/ios-l10n-scripts.git || exit 1 + +if [ "$BUDDYBUILD_SCHEME" = "Firefox" ] || [ "$BUDDYBUILD_SCHEME" = "FirefoxBeta" ]; then + setup_virtualenv + ./ios-l10n-scripts/import-locales-firefox.sh --release +fi + +if [ "$BUDDYBUILD_SCHEME" = "Fennec_Enterprise" ] && [ "$BUDDYBUILD_PULL_REQUEST" = "" ]; then + setup_virtualenv + ./ios-l10n-scripts/import-locales-firefox.sh +fi diff --git a/mobile/ios/buddybuild_prebuild.sh b/mobile/ios/buddybuild_prebuild.sh new file mode 100644 index 0000000000..51de61047c --- /dev/null +++ b/mobile/ios/buddybuild_prebuild.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +# +# Add our Adjust keys to the build depending on the scheme. We use the sandbox for beta so +# that we have some insight in beta usage. +# + +if [ "$BUDDYBUILD_SCHEME" == FirefoxBeta ]; then + echo "Setting Adjust environment to SANDBOX for $BUDDYBUILD_SCHEME" + /usr/libexec/PlistBuddy -c "Set AdjustAppToken $ADJUST_KEY_BETA" "Client/Info.plist" + /usr/libexec/PlistBuddy -c "Set AdjustEnvironment production" "Client/Info.plist" +elif [ "$BUDDYBUILD_SCHEME" == Firefox ]; then + echo "Setting Adjust environment to PRODUCTION for $BUDDYBUILD_SCHEME" + /usr/libexec/PlistBuddy -c "Set AdjustAppToken $ADJUST_KEY_PRODUCTION" "Client/Info.plist" + /usr/libexec/PlistBuddy -c "Set AdjustEnvironment production" "Client/Info.plist" +fi + +# +# Enable File Sharing on all builds except release +# + +if [ "$BUDDYBUILD_SCHEME" != "Firefox" ]; then + /usr/libexec/PlistBuddy -c "Add UIFileSharingEnabled bool true" "Client/Info.plist" +fi + +# +# Leanplum is included only for the Firefox and FirefoxBeta builds. +# + +if [ "$BUDDYBUILD_SCHEME" = "Firefox" ] || [ "$BUDDYBUILD_SCHEME" = "FirefoxBeta" ]; then + echo "Setting Leanplum environment to PRODUCTION for $BUDDYBUILD_SCHEME" + /usr/libexec/PlistBuddy -c "Set LeanplumAppId $LEANPLUM_APP_ID" "Client/Info.plist" + /usr/libexec/PlistBuddy -c "Set LeanplumProductionKey $LEANPLUM_KEY_PRODUCTION" "Client/Info.plist" + /usr/libexec/PlistBuddy -c "Set LeanplumDevelopmentKey $LEANPLUM_KEY_DEVELOPMENT" "Client/Info.plist" +fi + +echo "Setting up Pocket Stories API Key" +if [ "$BUDDYBUILD_SCHEME" == Firefox ]; then + /usr/libexec/PlistBuddy -c "Set PocketEnvironmentAPIKey $POCKET_PRODUCTION_API_KEY" "Client/Info.plist" +else + /usr/libexec/PlistBuddy -c "Set PocketEnvironmentAPIKey $POCKET_STAGING_API_KEY" "Client/Info.plist" +fi + +# +# Setup Sentry. We have different DSNs for Beta and Production. +# + +if [ "$BUDDYBUILD_SCHEME" == FirefoxBeta ]; then + echo "Setting SentryDSN to $SENTRY_DSN_BETA_105" + /usr/libexec/PlistBuddy -c "Set SentryDSN $SENTRY_DSN_BETA_105" "Client/Info.plist" +elif [ "$BUDDYBUILD_SCHEME" == Firefox ]; then + echo "Setting SentryDSN to $SENTRY_DSN_RELEASE_105" + /usr/libexec/PlistBuddy -c "Set SentryDSN $SENTRY_DSN_RELEASE_105" "Client/Info.plist" +fi + +# +# Set the build number to match the Buddybuild number +# + +agvtool new-version -all "$BUDDYBUILD_BUILD_NUMBER" + diff --git a/mobile/ios/codecov.yml b/mobile/ios/codecov.yml new file mode 100644 index 0000000000..70323c2c8e --- /dev/null +++ b/mobile/ios/codecov.yml @@ -0,0 +1,23 @@ +coverage: + precision: 0 + round: down + status: + project: + default: + threshold: 100 + if_no_uploads: success + if_not_found: success + if_ci_failed: success + patch: + default: + enabled: no + threshold: 30 + if_no_uploads: success + if_not_found: success + if_ci_failed: success + changes: no +comment: false +ignore: +- "UITests/.*" +- "XCUITests/.*" +- "ThirdParty/.*" diff --git a/mobile/ios/fastlane/Fastfile b/mobile/ios/fastlane/Fastfile new file mode 100644 index 0000000000..6da5d6c7f6 --- /dev/null +++ b/mobile/ios/fastlane/Fastfile @@ -0,0 +1,26 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +fastlane_version "1.39.0" + +default_platform :ios + + +import_build_tools( + url: 'git@github.com:mozilla/firefox-ios-build-tools.git', + clone_folder: "../build-tools", +) + +#move all the build tools to the right places +clone_folder = "../../build-tools" +sh("rsync -a #{clone_folder}/scripts ../") +sh("rsync -a #{clone_folder}/fastlane/Appfile Appfile") +sh("rsync -a #{clone_folder}/fastlane/Snapfile Snapfile") +sh("rsync -a #{clone_folder}/fastlane/SnapshotHelper.swift SnapshotHelper.swift") +sh("rsync -a #{clone_folder}/fastlane/scripts .") +sh("rsync -a #{clone_folder}/fastlane/frames .") +sh("rsync -a #{clone_folder}/fastlane/templates .") + +#import the fastfile +import "#{clone_folder}/fastlane/BaseFastfile" diff --git a/mobile/ios/fastlane/actions/import_build_tools.rb b/mobile/ios/fastlane/actions/import_build_tools.rb new file mode 100644 index 0000000000..91571ca55b --- /dev/null +++ b/mobile/ios/fastlane/actions/import_build_tools.rb @@ -0,0 +1,79 @@ +module Fastlane + module Actions + + class ImportBuildToolsAction < Action + def self.run(params) + # fastlane will take care of reading in the parameter and fetching the environment variable: + Helper.log.info "Parameter URL: #{params[:url]}" + Helper.log.info "Parameter Clone Folder: #{params[:clone_folder]}" + Helper.log.info "Parameter Branch: #{params[:branch]}" + directory = params[:clone_folder] + + git_command = "" + if File.directory?(directory) + Helper.log.info("Fetching latest version of build tools from #{directory}") + branch_option = "" + branch_option = "git checkout #{params[:branch]}\n" if params[:branch] != 'HEAD' + git_command = "cd #{directory}\n \ + git checkout master\n \ + git fetch\n \ + #{branch_option} \ + git pull" + else + Helper.log.info("Cloning build tools repository") + #import from git into subdir + branch_option = "" + branch_option = "--branch #{params[:branch]}" if params[:branch] != 'HEAD' + + git_command = "git clone '#{params[:url]}' '#{directory}' #{branch_option}" + end + + Helper.log.info("Excuting #{git_command}") + Actions.sh(git_command) + end + + ##################################################### + # @!group Documentation + ##################################################### + + def self.description + "Downloads an Git repo to a given location" + end + + def self.details + "Downloads a Git repo <:url> to a given location <:clone_folder> and checks out a specific branch if <:branch> is provided" + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new(key: :url, + env_name: "FL_IMPORT_BUILD_TOOLS_URL", # The name of the environment variable + description: "URL of github repository that contains build tools", # a short description of this parameter + verify_block: proc do |value| + raise "No URL for ImportBuildToolsAction given, pass using `url: 'value'`".red unless (value and not value.empty?) + # raise "Couldn't find file at path '#{value}'".red unless File.exist?(value) + end), + FastlaneCore::ConfigItem.new(key: :clone_folder, + env_name: "FL_IMPORT_BUILD_TOOLS_CLONE_FOLDER", # The name of the environment variable + description: "path to import build tools to", # a short description of this parameter + verify_block: proc do |value| + raise "No Clone folder for ImportBuildToolsAction given, pass using `clone_folder: 'path'`".red unless (value and not value.empty?) + # raise "Couldn't find file at path '#{value}'".red unless File.exist?(value) + end), + FastlaneCore::ConfigItem.new(key: :branch, + env_name: "FL_IMPORT_BUILD_TOOLS_BRANCH", + description: "Branch of build tools to import", + default_value: "HEAD") # the default value if the user didn't provide one + ] + end + + def self.authors + ["Mozilla"] + end + + def self.is_supported?(platform) + platform == :ios + end + end + end +end diff --git a/mobile/ios/l10n-screenshots.sh b/mobile/ios/l10n-screenshots.sh new file mode 100644 index 0000000000..82a9160712 --- /dev/null +++ b/mobile/ios/l10n-screenshots.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +if [ -d l10n-screenshots ]; then + echo "The l10n-screenshots directory already exists. You decide." + exit 1 +fi + +if [ ! -d firefoxios-l10n ]; then + echo "Did not find a firefox-ios-l10n checkout. Are you running this on a localized build?" + exit 1 +fi + +mkdir l10n-screenshots + +LOCALES=$* +if [ $# -eq 0 ]; then + LOCALES="af ar ast az bg bn br bs ca cs cy da de dsb el en-GB en-US eo es es-CL es-MX eu fa fr ga-IE gd gl he hi-IN hsb hu hy-AM id is it ja kab kk km kn ko lo lt lv ml ms my nb-NO ne-NP nl nn-NO or pa-IN pl pt-BR pt-PT rm ro ru ses si sk sl sq sv-SE te th tl tn tr uk ur uz zh-CN zh-TW" +fi + +for lang in $LOCALES; do + echo "$(date) Snapshotting $lang" + mkdir "l10n-screenshots/$lang" + fastlane snapshot --project Client.xcodeproj --scheme L10nSnapshotTests \ + --skip_open_summary \ + --derived_data_path l10n-screenshots-dd \ + --erase_simulator --localize_simulator \ + --devices "iPhone 5s" --languages "$lang" \ + --output_directory "l10n-screenshots/$lang" > "l10n-screenshots/$lang/snapshot.log" 2>&1 +done diff --git a/mobile/ios/setup_build_tools.sh b/mobile/ios/setup_build_tools.sh new file mode 100644 index 0000000000..967c3079cd --- /dev/null +++ b/mobile/ios/setup_build_tools.sh @@ -0,0 +1,88 @@ +#!/bin/sh + +# +# Install all the required dependencies for building and deploying Firefox for iOS +# Assumes you already have git otherwise you wouldn't have this setup script +# +# run ./setup.sh from the command line to run +# + +# +# Check if XCode Command Line Tools are installed +# +which -s xcode-select +if [[ $? != 0 ]] ; then + echo "Installing XCode Command Line Tools" + # Install XCode Command Line Tools + xcode-select --install +else + echo "XCode Command Line Tools already installed" +fi + +# +# Check if Homebrew is installed +# +which -s brew +if [[ $? != 0 ]] ; then + # Install Homebrew + echo "Installing Homebrew" + ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +else + echo "Homebrew already installed" +fi + +# +# Check if python is installed +# +if [ ! -e $(python -c 'from distutils.sysconfig import get_makefile_filename as m; print m()') ]; then + # Install python + echo "Installing python" + brew install python +else + echo "python already installed" +fi + +# +# Check if virtualenv is installed +# +which -s virtualenv +if [[ $? != 0 ]] ; then + # Install virtualenv + echo "Installing vitualenv" + pip install virtualenv +else + echo "virtualenv already installed" +fi + +if [ ! -d /usr/local/Cellar/imagemagick ] ; then + echo "installing imagemagick" + brew install imagemagick +else + echo "imagemagick already installed" +fi + +# +# Check is Carthage is installed +# +which -s carthage +if [[ $? != 0 ]] ; then + # Install Carthage + echo "Installing Carthage" + brew install carthage +else + echo "Carthage already installed" +fi + +# +# Check if fastlane is installed +# +which -s fastlane +if [[ $? != 0 ]] ; then + # Install fastlane + echo "Installing fastlane." + sudo gem install fastlane + fastlane init +else + echo "fastlane already installed" +fi + diff --git a/mobile/ios/shipping_locales.txt b/mobile/ios/shipping_locales.txt new file mode 100644 index 0000000000..5247ff84e1 --- /dev/null +++ b/mobile/ios/shipping_locales.txt @@ -0,0 +1,73 @@ +af +ast +az +bg +bn +br +bs +ca +cs +cy +da +de +dsb +el +en-GB +en-US +eo +es +es-AR +es-CL +es-MX +eu +fr +ga-IE +gd +gl +hi-IN +hsb +hu +hy-AM +ia +id +is +it +ja +kab +kk +km +kn +ko +lo +lt +lv +ml +ms +my +nb-NO +ne-NP +nl +nn-NO +or +pa-IN +pl +pt-BR +pt-PT +rm +ro +ru +ses +si +sk +sl +sq +sv-SE +ta +te +th +tl +tr +uk +uz +zh-CN +zh-TW diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index dfdfb84b2b..54d89a7abb 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -9,7 +9,7 @@ * * Platform-specific #ifdefs at the end of this file override the generic * entries at the top. - */ + * /* * SYNTAX HINTS: @@ -639,7 +639,7 @@ pref("layout.event-regions.enabled", false); // gfx/layers/apz/src/AsyncPanZoomController.cpp. pref("apz.allow_checkerboarding", true); pref("apz.allow_immediate_handoff", true); -pref("apz.allow_zooming", false); +pref("apz.allow_zooming", true); // Whether to lock touch scrolling to one axis at a time // 0 = FREE (No locking at all) @@ -651,7 +651,7 @@ pref("apz.axis_lock.breakout_threshold", "0.03125"); // 1/32 inches pref("apz.axis_lock.breakout_angle", "0.3926991"); // PI / 8 (22.5 degrees) pref("apz.axis_lock.direct_pan_angle", "1.047197"); // PI / 3 (60 degrees) pref("apz.content_response_timeout", 400); -pref("apz.drag.enabled", false); +pref("apz.drag.enabled", true); pref("apz.danger_zone_x", 50); pref("apz.danger_zone_y", 100); pref("apz.disable_for_scroll_linked_effects", false); @@ -710,7 +710,7 @@ pref("apz.zoom_animation_duration_ms", 250); pref("apz.scale_repaint_delay_ms", 500); #if !defined(MOZ_WIDGET_UIKIT) -pref("apz.desktop.enabled", false); +pref("apz.desktop.enabled", true); #endif #ifdef XP_MACOSX @@ -1348,6 +1348,9 @@ pref("javascript.options.dynamicImport", true); // Streams API pref("javascript.options.streams", true); +// Enable garbage collection of weakrefed objects +pref("javascript.options.weakrefs", false); + // advanced prefs pref("advanced.mailftp", false); pref("image.animation_mode", "normal"); @@ -2725,6 +2728,9 @@ pref("layout.css.resizeobserver.enabled", true); // Is support for cascade layers enabled? pref("layout.css.cascade-layers.enabled", true); +// Is support for basic CSS nesting lowering enabled? +pref("layout.css.nesting.enabled", true); + // Should rules in imported style sheets be added based on the order // of appearance of their respective @import rules in the parent // style sheet? Otherwise, they are added before rules preceding @@ -3230,7 +3236,7 @@ pref("ui.mouse.radius.inputSource.touchOnly", true); #ifdef XP_WIN -// Be as uniform as possible, use Twemoji everywhere. +// Be as uniform as possible, use Twemoji everywhere. // Optional: prefix with `Segoe UI Emoji` to use Win8+ Segoe UI font emoji where available. pref("font.name-list.emoji", "Twemoji Mozilla"); @@ -4761,7 +4767,7 @@ pref("media.ondevicechange.fakeDeviceChangeEvent.enabled", false); // those platforms we don't handle touch events anyway so it's conceptually // a no-op. pref("layout.css.touch_action.enabled", true); - + // WHATWG computed intrinsic aspect ratio for an img element // https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images // Are the width and height attributes on image-like elements mapped to the @@ -5273,7 +5279,7 @@ pref("plugins.navigator_hide_disabled_flash", false); pref("dom.mozBrowserFramesEnabled", false); // Thick caret when behind CJK characters -pref("layout.cjkthickcaret", true); +pref("layout.cjkthickcaret", true); // Is support for 'color-adjust' CSS property enabled? pref("layout.css.color-adjust.enabled", true); diff --git a/modules/zlib/src/ChangeLog b/modules/zlib/src/ChangeLog new file mode 100644 index 0000000000..b27cc4f0e7 --- /dev/null +++ b/modules/zlib/src/ChangeLog @@ -0,0 +1,1515 @@ + + ChangeLog file for zlib + +Changes in 1.2.11 (15 Jan 2017) +- Fix deflate stored bug when pulling last block from window +- Permit immediate deflateParams changes before any deflate input + +Changes in 1.2.10 (2 Jan 2017) +- Avoid warnings on snprintf() return value +- Fix bug in deflate_stored() for zero-length input +- Fix bug in gzwrite.c that produced corrupt gzip files +- Remove files to be installed before copying them in Makefile.in +- Add warnings when compiling with assembler code + +Changes in 1.2.9 (31 Dec 2016) +- Fix contrib/minizip to permit unzipping with desktop API [Zouzou] +- Improve contrib/blast to return unused bytes +- Assure that gzoffset() is correct when appending +- Improve compress() and uncompress() to support large lengths +- Fix bug in test/example.c where error code not saved +- Remedy Coverity warning [Randers-Pehrson] +- Improve speed of gzprintf() in transparent mode +- Fix inflateInit2() bug when windowBits is 16 or 32 +- Change DEBUG macro to ZLIB_DEBUG +- Avoid uninitialized access by gzclose_w() +- Allow building zlib outside of the source directory +- Fix bug that accepted invalid zlib header when windowBits is zero +- Fix gzseek() problem on MinGW due to buggy _lseeki64 there +- Loop on write() calls in gzwrite.c in case of non-blocking I/O +- Add --warn (-w) option to ./configure for more compiler warnings +- Reject a window size of 256 bytes if not using the zlib wrapper +- Fix bug when level 0 used with Z_HUFFMAN or Z_RLE +- Add --debug (-d) option to ./configure to define ZLIB_DEBUG +- Fix bugs in creating a very large gzip header +- Add uncompress2() function, which returns the input size used +- Assure that deflateParams() will not switch functions mid-block +- Dramatically speed up deflation for level 0 (storing) +- Add gzfread(), duplicating the interface of fread() +- Add gzfwrite(), duplicating the interface of fwrite() +- Add deflateGetDictionary() function +- Use snprintf() for later versions of Microsoft C +- Fix *Init macros to use z_ prefix when requested +- Replace as400 with os400 for OS/400 support [Monnerat] +- Add crc32_z() and adler32_z() functions with size_t lengths +- Update Visual Studio project files [AraHaan] + +Changes in 1.2.8 (28 Apr 2013) +- Update contrib/minizip/iowin32.c for Windows RT [Vollant] +- Do not force Z_CONST for C++ +- Clean up contrib/vstudio [Ro§] +- Correct spelling error in zlib.h +- Fix mixed line endings in contrib/vstudio + +Changes in 1.2.7.3 (13 Apr 2013) +- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc + +Changes in 1.2.7.2 (13 Apr 2013) +- Change check for a four-byte type back to hexadecimal +- Fix typo in win32/Makefile.msc +- Add casts in gzwrite.c for pointer differences + +Changes in 1.2.7.1 (24 Mar 2013) +- Replace use of unsafe string functions with snprintf if available +- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink] +- Fix gzgetc undefine when Z_PREFIX set [Turk] +- Eliminate use of mktemp in Makefile (not always available) +- Fix bug in 'F' mode for gzopen() +- Add inflateGetDictionary() function +- Correct comment in deflate.h +- Use _snprintf for snprintf in Microsoft C +- On Darwin, only use /usr/bin/libtool if libtool is not Apple +- Delete "--version" file if created by "ar --version" [Richard G.] +- Fix configure check for veracity of compiler error return codes +- Fix CMake compilation of static lib for MSVC2010 x64 +- Remove unused variable in infback9.c +- Fix argument checks in gzlog_compress() and gzlog_write() +- Clean up the usage of z_const and respect const usage within zlib +- Clean up examples/gzlog.[ch] comparisons of different types +- Avoid shift equal to bits in type (caused endless loop) +- Fix uninitialized value bug in gzputc() introduced by const patches +- Fix memory allocation error in examples/zran.c [Nor] +- Fix bug where gzopen(), gzclose() would write an empty file +- Fix bug in gzclose() when gzwrite() runs out of memory +- Check for input buffer malloc failure in examples/gzappend.c +- Add note to contrib/blast to use binary mode in stdio +- Fix comparisons of differently signed integers in contrib/blast +- Check for invalid code length codes in contrib/puff +- Fix serious but very rare decompression bug in inftrees.c +- Update inflateBack() comments, since inflate() can be faster +- Use underscored I/O function names for WINAPI_FAMILY +- Add _tr_flush_bits to the external symbols prefixed by --zprefix +- Add contrib/vstudio/vc10 pre-build step for static only +- Quote --version-script argument in CMakeLists.txt +- Don't specify --version-script on Apple platforms in CMakeLists.txt +- Fix casting error in contrib/testzlib/testzlib.c +- Fix types in contrib/minizip to match result of get_crc_table() +- Simplify contrib/vstudio/vc10 with 'd' suffix +- Add TOP support to win32/Makefile.msc +- Suport i686 and amd64 assembler builds in CMakeLists.txt +- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h +- Add vc11 and vc12 build files to contrib/vstudio +- Add gzvprintf() as an undocumented function in zlib +- Fix configure for Sun shell +- Remove runtime check in configure for four-byte integer type +- Add casts and consts to ease user conversion to C++ +- Add man pages for minizip and miniunzip +- In Makefile uninstall, don't rm if preceding cd fails +- Do not return Z_BUF_ERROR if deflateParam() has nothing to write + +Changes in 1.2.7 (2 May 2012) +- Replace use of memmove() with a simple copy for portability +- Test for existence of strerror +- Restore gzgetc_ for backward compatibility with 1.2.6 +- Fix build with non-GNU make on Solaris +- Require gcc 4.0 or later on Mac OS X to use the hidden attribute +- Include unistd.h for Watcom C +- Use __WATCOMC__ instead of __WATCOM__ +- Do not use the visibility attribute if NO_VIZ defined +- Improve the detection of no hidden visibility attribute +- Avoid using __int64 for gcc or solo compilation +- Cast to char * in gzprintf to avoid warnings [Zinser] +- Fix make_vms.com for VAX [Zinser] +- Don't use library or built-in byte swaps +- Simplify test and use of gcc hidden attribute +- Fix bug in gzclose_w() when gzwrite() fails to allocate memory +- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen() +- Fix bug in test/minigzip.c for configure --solo +- Fix contrib/vstudio project link errors [Mohanathas] +- Add ability to choose the builder in make_vms.com [Schweda] +- Add DESTDIR support to mingw32 win32/Makefile.gcc +- Fix comments in win32/Makefile.gcc for proper usage +- Allow overriding the default install locations for cmake +- Generate and install the pkg-config file with cmake +- Build both a static and a shared version of zlib with cmake +- Include version symbols for cmake builds +- If using cmake with MSVC, add the source directory to the includes +- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta] +- Move obsolete emx makefile to old [Truta] +- Allow the use of -Wundef when compiling or using zlib +- Avoid the use of the -u option with mktemp +- Improve inflate() documentation on the use of Z_FINISH +- Recognize clang as gcc +- Add gzopen_w() in Windows for wide character path names +- Rename zconf.h in CMakeLists.txt to move it out of the way +- Add source directory in CMakeLists.txt for building examples +- Look in build directory for zlib.pc in CMakeLists.txt +- Remove gzflags from zlibvc.def in vc9 and vc10 +- Fix contrib/minizip compilation in the MinGW environment +- Update ./configure for Solaris, support --64 [Mooney] +- Remove -R. from Solaris shared build (possible security issue) +- Avoid race condition for parallel make (-j) running example +- Fix type mismatch between get_crc_table() and crc_table +- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler] +- Fix the path to zlib.map in CMakeLists.txt +- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe] +- Add instructions to win32/Makefile.gcc for shared install [Torri] + +Changes in 1.2.6.1 (12 Feb 2012) +- Avoid the use of the Objective-C reserved name "id" +- Include io.h in gzguts.h for Microsoft compilers +- Fix problem with ./configure --prefix and gzgetc macro +- Include gz_header definition when compiling zlib solo +- Put gzflags() functionality back in zutil.c +- Avoid library header include in crc32.c for Z_SOLO +- Use name in GCC_CLASSIC as C compiler for coverage testing, if set +- Minor cleanup in contrib/minizip/zip.c [Vollant] +- Update make_vms.com [Zinser] +- Remove unnecessary gzgetc_ function +- Use optimized byte swap operations for Microsoft and GNU [Snyder] +- Fix minor typo in zlib.h comments [Rzesniowiecki] + +Changes in 1.2.6 (29 Jan 2012) +- Update the Pascal interface in contrib/pascal +- Fix function numbers for gzgetc_ in zlibvc.def files +- Fix configure.ac for contrib/minizip [Schiffer] +- Fix large-entry detection in minizip on 64-bit systems [Schiffer] +- Have ./configure use the compiler return code for error indication +- Fix CMakeLists.txt for cross compilation [McClure] +- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes] +- Fix compilation of contrib/minizip on FreeBSD [Marquez] +- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath] +- Include io.h for Turbo C / Borland C on all platforms [Truta] +- Make version explicit in contrib/minizip/configure.ac [Bosmans] +- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant] +- Minor cleanup up contrib/minizip/unzip.c [Vollant] +- Fix bug when compiling minizip with C++ [Vollant] +- Protect for long name and extra fields in contrib/minizip [Vollant] +- Avoid some warnings in contrib/minizip [Vollant] +- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip +- Add missing libs to minizip linker command +- Add support for VPATH builds in contrib/minizip +- Add an --enable-demos option to contrib/minizip/configure +- Add the generation of configure.log by ./configure +- Exit when required parameters not provided to win32/Makefile.gcc +- Have gzputc return the character written instead of the argument +- Use the -m option on ldconfig for BSD systems [Tobias] +- Correct in zlib.map when deflateResetKeep was added + +Changes in 1.2.5.3 (15 Jan 2012) +- Restore gzgetc function for binary compatibility +- Do not use _lseeki64 under Borland C++ [Truta] +- Update win32/Makefile.msc to build test/*.c [Truta] +- Remove old/visualc6 given CMakefile and other alternatives +- Update AS400 build files and documentation [Monnerat] +- Update win32/Makefile.gcc to build test/*.c [Truta] +- Permit stronger flushes after Z_BLOCK flushes +- Avoid extraneous empty blocks when doing empty flushes +- Permit Z_NULL arguments to deflatePending +- Allow deflatePrime() to insert bits in the middle of a stream +- Remove second empty static block for Z_PARTIAL_FLUSH +- Write out all of the available bits when using Z_BLOCK +- Insert the first two strings in the hash table after a flush + +Changes in 1.2.5.2 (17 Dec 2011) +- fix ld error: unable to find version dependency 'ZLIB_1.2.5' +- use relative symlinks for shared libs +- Avoid searching past window for Z_RLE strategy +- Assure that high-water mark initialization is always applied in deflate +- Add assertions to fill_window() in deflate.c to match comments +- Update python link in README +- Correct spelling error in gzread.c +- Fix bug in gzgets() for a concatenated empty gzip stream +- Correct error in comment for gz_make() +- Change gzread() and related to ignore junk after gzip streams +- Allow gzread() and related to continue after gzclearerr() +- Allow gzrewind() and gzseek() after a premature end-of-file +- Simplify gzseek() now that raw after gzip is ignored +- Change gzgetc() to a macro for speed (~40% speedup in testing) +- Fix gzclose() to return the actual error last encountered +- Always add large file support for windows +- Include zconf.h for windows large file support +- Include zconf.h.cmakein for windows large file support +- Update zconf.h.cmakein on make distclean +- Merge vestigial vsnprintf determination from zutil.h to gzguts.h +- Clarify how gzopen() appends in zlib.h comments +- Correct documentation of gzdirect() since junk at end now ignored +- Add a transparent write mode to gzopen() when 'T' is in the mode +- Update python link in zlib man page +- Get inffixed.h and MAKEFIXED result to match +- Add a ./config --solo option to make zlib subset with no library use +- Add undocumented inflateResetKeep() function for CAB file decoding +- Add --cover option to ./configure for gcc coverage testing +- Add #define ZLIB_CONST option to use const in the z_stream interface +- Add comment to gzdopen() in zlib.h to use dup() when using fileno() +- Note behavior of uncompress() to provide as much data as it can +- Add files in contrib/minizip to aid in building libminizip +- Split off AR options in Makefile.in and configure +- Change ON macro to Z_ARG to avoid application conflicts +- Facilitate compilation with Borland C++ for pragmas and vsnprintf +- Include io.h for Turbo C / Borland C++ +- Move example.c and minigzip.c to test/ +- Simplify incomplete code table filling in inflate_table() +- Remove code from inflate.c and infback.c that is impossible to execute +- Test the inflate code with full coverage +- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw) +- Add deflateResetKeep and fix inflateResetKeep to retain dictionary +- Fix gzwrite.c to accommodate reduced memory zlib compilation +- Have inflate() with Z_FINISH avoid the allocation of a window +- Do not set strm->adler when doing raw inflate +- Fix gzeof() to behave just like feof() when read is not past end of file +- Fix bug in gzread.c when end-of-file is reached +- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF +- Document gzread() capability to read concurrently written files +- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo] + +Changes in 1.2.5.1 (10 Sep 2011) +- Update FAQ entry on shared builds (#13) +- Avoid symbolic argument to chmod in Makefile.in +- Fix bug and add consts in contrib/puff [Oberhumer] +- Update contrib/puff/zeros.raw test file to have all block types +- Add full coverage test for puff in contrib/puff/Makefile +- Fix static-only-build install in Makefile.in +- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno] +- Add libz.a dependency to shared in Makefile.in for parallel builds +- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out +- Replace $(...) with `...` in configure for non-bash sh [Bowler] +- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen] +- Add solaris* to Linux* in configure to allow gcc use [Groffen] +- Add *bsd* to Linux* case in configure [Bar-Lev] +- Add inffast.obj to dependencies in win32/Makefile.msc +- Correct spelling error in deflate.h [Kohler] +- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc +- Add test to configure for GNU C looking for gcc in output of $cc -v +- Add zlib.pc generation to win32/Makefile.gcc [Weigelt] +- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not +- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense +- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser) +- Make stronger test in zconf.h to include unistd.h for LFS +- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack] +- Fix zlib.h LFS support when Z_PREFIX used +- Add updated as400 support (removed from old) [Monnerat] +- Avoid deflate sensitivity to volatile input data +- Avoid division in adler32_combine for NO_DIVIDE +- Clarify the use of Z_FINISH with deflateBound() amount of space +- Set binary for output file in puff.c +- Use u4 type for crc_table to avoid conversion warnings +- Apply casts in zlib.h to avoid conversion warnings +- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] +- Improve inflateSync() documentation to note indeterminancy +- Add deflatePending() function to return the amount of pending output +- Correct the spelling of "specification" in FAQ [Randers-Pehrson] +- Add a check in configure for stdarg.h, use for gzprintf() +- Check that pointers fit in ints when gzprint() compiled old style +- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] +- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] +- Add debug records in assmebler code [Londer] +- Update RFC references to use http://tools.ietf.org/html/... [Li] +- Add --archs option, use of libtool to configure for Mac OS X [Borstel] + +Changes in 1.2.5 (19 Apr 2010) +- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] +- Default to libdir as sharedlibdir in configure [Nieder] +- Update copyright dates on modified source files +- Update trees.c to be able to generate modified trees.h +- Exit configure for MinGW, suggesting win32/Makefile.gcc +- Check for NULL path in gz_open [Homurlu] + +Changes in 1.2.4.5 (18 Apr 2010) +- Set sharedlibdir in configure [Torok] +- Set LDFLAGS in Makefile.in [Bar-Lev] +- Avoid mkdir objs race condition in Makefile.in [Bowler] +- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays +- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C +- Don't use hidden attribute when it is a warning generator (e.g. Solaris) + +Changes in 1.2.4.4 (18 Apr 2010) +- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok] +- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty +- Try to use bash or ksh regardless of functionality of /bin/sh +- Fix configure incompatibility with NetBSD sh +- Remove attempt to run under bash or ksh since have better NetBSD fix +- Fix win32/Makefile.gcc for MinGW [Bar-Lev] +- Add diagnostic messages when using CROSS_PREFIX in configure +- Added --sharedlibdir option to configure [Weigelt] +- Use hidden visibility attribute when available [Frysinger] + +Changes in 1.2.4.3 (10 Apr 2010) +- Only use CROSS_PREFIX in configure for ar and ranlib if they exist +- Use CROSS_PREFIX for nm [Bar-Lev] +- Assume _LARGEFILE64_SOURCE defined is equivalent to true +- Avoid use of undefined symbols in #if with && and || +- Make *64 prototypes in gzguts.h consistent with functions +- Add -shared load option for MinGW in configure [Bowler] +- Move z_off64_t to public interface, use instead of off64_t +- Remove ! from shell test in configure (not portable to Solaris) +- Change +0 macro tests to -0 for possibly increased portability + +Changes in 1.2.4.2 (9 Apr 2010) +- Add consistent carriage returns to readme.txt's in masmx86 and masmx64 +- Really provide prototypes for *64 functions when building without LFS +- Only define unlink() in minigzip.c if unistd.h not included +- Update README to point to contrib/vstudio project files +- Move projects/vc6 to old/ and remove projects/ +- Include stdlib.h in minigzip.c for setmode() definition under WinCE +- Clean up assembler builds in win32/Makefile.msc [Rowe] +- Include sys/types.h for Microsoft for off_t definition +- Fix memory leak on error in gz_open() +- Symbolize nm as $NM in configure [Weigelt] +- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt] +- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined +- Fix bug in gzeof() to take into account unused input data +- Avoid initialization of structures with variables in puff.c +- Updated win32/README-WIN32.txt [Rowe] + +Changes in 1.2.4.1 (28 Mar 2010) +- Remove the use of [a-z] constructs for sed in configure [gentoo 310225] +- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech] +- Restore "for debugging" comment on sprintf() in gzlib.c +- Remove fdopen for MVS from gzguts.h +- Put new README-WIN32.txt in win32 [Rowe] +- Add check for shell to configure and invoke another shell if needed +- Fix big fat stinking bug in gzseek() on uncompressed files +- Remove vestigial F_OPEN64 define in zutil.h +- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE +- Avoid errors on non-LFS systems when applications define LFS macros +- Set EXE to ".exe" in configure for MINGW [Kahle] +- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill] +- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev] +- Add DLL install in win32/makefile.gcc [Bar-Lev] +- Allow Linux* or linux* from uname in configure [Bar-Lev] +- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev] +- Add cross-compilation prefixes to configure [Bar-Lev] +- Match type exactly in gz_load() invocation in gzread.c +- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func +- Provide prototypes for *64 functions when building zlib without LFS +- Don't use -lc when linking shared library on MinGW +- Remove errno.h check in configure and vestigial errno code in zutil.h + +Changes in 1.2.4 (14 Mar 2010) +- Fix VER3 extraction in configure for no fourth subversion +- Update zlib.3, add docs to Makefile.in to make .pdf out of it +- Add zlib.3.pdf to distribution +- Don't set error code in gzerror() if passed pointer is NULL +- Apply destination directory fixes to CMakeLists.txt [Lowman] +- Move #cmakedefine's to a new zconf.in.cmakein +- Restore zconf.h for builds that don't use configure or cmake +- Add distclean to dummy Makefile for convenience +- Update and improve INDEX, README, and FAQ +- Update CMakeLists.txt for the return of zconf.h [Lowman] +- Update contrib/vstudio/vc9 and vc10 [Vollant] +- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc +- Apply license and readme changes to contrib/asm686 [Raiter] +- Check file name lengths and add -c option in minigzip.c [Li] +- Update contrib/amd64 and contrib/masmx86/ [Vollant] +- Avoid use of "eof" parameter in trees.c to not shadow library variable +- Update make_vms.com for removal of zlibdefs.h [Zinser] +- Update assembler code and vstudio projects in contrib [Vollant] +- Remove outdated assembler code contrib/masm686 and contrib/asm586 +- Remove old vc7 and vc8 from contrib/vstudio +- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe] +- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open() +- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant] +- Remove *64 functions from win32/zlib.def (they're not 64-bit yet) +- Fix bug in void-returning vsprintf() case in gzwrite.c +- Fix name change from inflate.h in contrib/inflate86/inffas86.c +- Check if temporary file exists before removing in make_vms.com [Zinser] +- Fix make install and uninstall for --static option +- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta] +- Update readme.txt in contrib/masmx64 and masmx86 to assemble + +Changes in 1.2.3.9 (21 Feb 2010) +- Expunge gzio.c +- Move as400 build information to old +- Fix updates in contrib/minizip and contrib/vstudio +- Add const to vsnprintf test in configure to avoid warnings [Weigelt] +- Delete zconf.h (made by configure) [Weigelt] +- Change zconf.in.h to zconf.h.in per convention [Weigelt] +- Check for NULL buf in gzgets() +- Return empty string for gzgets() with len == 1 (like fgets()) +- Fix description of gzgets() in zlib.h for end-of-file, NULL return +- Update minizip to 1.1 [Vollant] +- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c +- Note in zlib.h that gzerror() should be used to distinguish from EOF +- Remove use of snprintf() from gzlib.c +- Fix bug in gzseek() +- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant] +- Fix zconf.h generation in CMakeLists.txt [Lowman] +- Improve comments in zconf.h where modified by configure + +Changes in 1.2.3.8 (13 Feb 2010) +- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer] +- Use z_off64_t in gz_zero() and gz_skip() to match state->skip +- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t) +- Revert to Makefile.in from 1.2.3.6 (live with the clutter) +- Fix missing error return in gzflush(), add zlib.h note +- Add *64 functions to zlib.map [Levin] +- Fix signed/unsigned comparison in gz_comp() +- Use SFLAGS when testing shared linking in configure +- Add --64 option to ./configure to use -m64 with gcc +- Fix ./configure --help to correctly name options +- Have make fail if a test fails [Levin] +- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson] +- Remove assembler object files from contrib + +Changes in 1.2.3.7 (24 Jan 2010) +- Always gzopen() with O_LARGEFILE if available +- Fix gzdirect() to work immediately after gzopen() or gzdopen() +- Make gzdirect() more precise when the state changes while reading +- Improve zlib.h documentation in many places +- Catch memory allocation failure in gz_open() +- Complete close operation if seek forward in gzclose_w() fails +- Return Z_ERRNO from gzclose_r() if close() fails +- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL +- Return zero for gzwrite() errors to match zlib.h description +- Return -1 on gzputs() error to match zlib.h description +- Add zconf.in.h to allow recovery from configure modification [Weigelt] +- Fix static library permissions in Makefile.in [Weigelt] +- Avoid warnings in configure tests that hide functionality [Weigelt] +- Add *BSD and DragonFly to Linux case in configure [gentoo 123571] +- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212] +- Avoid access of uninitialized data for first inflateReset2 call [Gomes] +- Keep object files in subdirectories to reduce the clutter somewhat +- Remove default Makefile and zlibdefs.h, add dummy Makefile +- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_ +- Remove zlibdefs.h completely -- modify zconf.h instead + +Changes in 1.2.3.6 (17 Jan 2010) +- Avoid void * arithmetic in gzread.c and gzwrite.c +- Make compilers happier with const char * for gz_error message +- Avoid unused parameter warning in inflate.c +- Avoid signed-unsigned comparison warning in inflate.c +- Indent #pragma's for traditional C +- Fix usage of strwinerror() in glib.c, change to gz_strwinerror() +- Correct email address in configure for system options +- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser] +- Update zlib.map [Brown] +- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok] +- Apply various fixes to CMakeLists.txt [Lowman] +- Add checks on len in gzread() and gzwrite() +- Add error message for no more room for gzungetc() +- Remove zlib version check in gzwrite() +- Defer compression of gzprintf() result until need to +- Use snprintf() in gzdopen() if available +- Remove USE_MMAP configuration determination (only used by minigzip) +- Remove examples/pigz.c (available separately) +- Update examples/gun.c to 1.6 + +Changes in 1.2.3.5 (8 Jan 2010) +- Add space after #if in zutil.h for some compilers +- Fix relatively harmless bug in deflate_fast() [Exarevsky] +- Fix same problem in deflate_slow() +- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown] +- Add deflate_rle() for faster Z_RLE strategy run-length encoding +- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding +- Change name of "write" variable in inffast.c to avoid library collisions +- Fix premature EOF from gzread() in gzio.c [Brown] +- Use zlib header window size if windowBits is 0 in inflateInit2() +- Remove compressBound() call in deflate.c to avoid linking compress.o +- Replace use of errno in gz* with functions, support WinCE [Alves] +- Provide alternative to perror() in minigzip.c for WinCE [Alves] +- Don't use _vsnprintf on later versions of MSVC [Lowman] +- Add CMake build script and input file [Lowman] +- Update contrib/minizip to 1.1 [Svensson, Vollant] +- Moved nintendods directory from contrib to . +- Replace gzio.c with a new set of routines with the same functionality +- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above +- Update contrib/minizip to 1.1b +- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h + +Changes in 1.2.3.4 (21 Dec 2009) +- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility +- Update comments in configure and Makefile.in for default --shared +- Fix test -z's in configure [Marquess] +- Build examplesh and minigzipsh when not testing +- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h +- Import LDFLAGS from the environment in configure +- Fix configure to populate SFLAGS with discovered CFLAGS options +- Adapt make_vms.com to the new Makefile.in [Zinser] +- Add zlib2ansi script for C++ compilation [Marquess] +- Add _FILE_OFFSET_BITS=64 test to make test (when applicable) +- Add AMD64 assembler code for longest match to contrib [Teterin] +- Include options from $SFLAGS when doing $LDSHARED +- Simplify 64-bit file support by introducing z_off64_t type +- Make shared object files in objs directory to work around old Sun cc +- Use only three-part version number for Darwin shared compiles +- Add rc option to ar in Makefile.in for when ./configure not run +- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4* +- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile +- Protect against _FILE_OFFSET_BITS being defined when compiling zlib +- Rename Makefile.in targets allstatic to static and allshared to shared +- Fix static and shared Makefile.in targets to be independent +- Correct error return bug in gz_open() by setting state [Brown] +- Put spaces before ;;'s in configure for better sh compatibility +- Add pigz.c (parallel implementation of gzip) to examples/ +- Correct constant in crc32.c to UL [Leventhal] +- Reject negative lengths in crc32_combine() +- Add inflateReset2() function to work like inflateEnd()/inflateInit2() +- Include sys/types.h for _LARGEFILE64_SOURCE [Brown] +- Correct typo in doc/algorithm.txt [Janik] +- Fix bug in adler32_combine() [Zhu] +- Catch missing-end-of-block-code error in all inflates and in puff + Assures that random input to inflate eventually results in an error +- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/ +- Update ENOUGH and its usage to reflect discovered bounds +- Fix gzerror() error report on empty input file [Brown] +- Add ush casts in trees.c to avoid pedantic runtime errors +- Fix typo in zlib.h uncompress() description [Reiss] +- Correct inflate() comments with regard to automatic header detection +- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays) +- Put new version of gzlog (2.0) in examples with interruption recovery +- Add puff compile option to permit invalid distance-too-far streams +- Add puff TEST command options, ability to read piped input +- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but + _LARGEFILE64_SOURCE not defined +- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart +- Fix deflateSetDictionary() to use all 32K for output consistency +- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h) +- Clear bytes after deflate lookahead to avoid use of uninitialized data +- Change a limit in inftrees.c to be more transparent to Coverity Prevent +- Update win32/zlib.def with exported symbols from zlib.h +- Correct spelling errors in zlib.h [Willem, Sobrado] +- Allow Z_BLOCK for deflate() to force a new block +- Allow negative bits in inflatePrime() to delete existing bit buffer +- Add Z_TREES flush option to inflate() to return at end of trees +- Add inflateMark() to return current state information for random access +- Add Makefile for NintendoDS to contrib [Costa] +- Add -w in configure compile tests to avoid spurious warnings [Beucler] +- Fix typos in zlib.h comments for deflateSetDictionary() +- Fix EOF detection in transparent gzread() [Maier] + +Changes in 1.2.3.3 (2 October 2006) +- Make --shared the default for configure, add a --static option +- Add compile option to permit invalid distance-too-far streams +- Add inflateUndermine() function which is required to enable above +- Remove use of "this" variable name for C++ compatibility [Marquess] +- Add testing of shared library in make test, if shared library built +- Use ftello() and fseeko() if available instead of ftell() and fseek() +- Provide two versions of all functions that use the z_off_t type for + binary compatibility -- a normal version and a 64-bit offset version, + per the Large File Support Extension when _LARGEFILE64_SOURCE is + defined; use the 64-bit versions by default when _FILE_OFFSET_BITS + is defined to be 64 +- Add a --uname= option to configure to perhaps help with cross-compiling + +Changes in 1.2.3.2 (3 September 2006) +- Turn off silly Borland warnings [Hay] +- Use off64_t and define _LARGEFILE64_SOURCE when present +- Fix missing dependency on inffixed.h in Makefile.in +- Rig configure --shared to build both shared and static [Teredesai, Truta] +- Remove zconf.in.h and instead create a new zlibdefs.h file +- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant] +- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt] + +Changes in 1.2.3.1 (16 August 2006) +- Add watcom directory with OpenWatcom make files [Daniel] +- Remove #undef of FAR in zconf.in.h for MVS [Fedtke] +- Update make_vms.com [Zinser] +- Use -fPIC for shared build in configure [Teredesai, Nicholson] +- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen] +- Use fdopen() (not _fdopen()) for Interix in zutil.h [BŠck] +- Add some FAQ entries about the contrib directory +- Update the MVS question in the FAQ +- Avoid extraneous reads after EOF in gzio.c [Brown] +- Correct spelling of "successfully" in gzio.c [Randers-Pehrson] +- Add comments to zlib.h about gzerror() usage [Brown] +- Set extra flags in gzip header in gzopen() like deflate() does +- Make configure options more compatible with double-dash conventions + [Weigelt] +- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen] +- Fix uninstall target in Makefile.in [Truta] +- Add pkgconfig support [Weigelt] +- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt] +- Replace set_data_type() with a more accurate detect_data_type() in + trees.c, according to the txtvsbin.txt document [Truta] +- Swap the order of #include and #include "zlib.h" in + gzio.c, example.c and minigzip.c [Truta] +- Shut up annoying VS2005 warnings about standard C deprecation [Rowe, + Truta] (where?) +- Fix target "clean" from win32/Makefile.bor [Truta] +- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe] +- Update zlib www home address in win32/DLL_FAQ.txt [Truta] +- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove] +- Enable browse info in the "Debug" and "ASM Debug" configurations in + the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta] +- Add pkgconfig support [Weigelt] +- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h, + for use in win32/zlib1.rc [Polushin, Rowe, Truta] +- Add a document that explains the new text detection scheme to + doc/txtvsbin.txt [Truta] +- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta] +- Move algorithm.txt into doc/ [Truta] +- Synchronize FAQ with website +- Fix compressBound(), was low for some pathological cases [Fearnley] +- Take into account wrapper variations in deflateBound() +- Set examples/zpipe.c input and output to binary mode for Windows +- Update examples/zlib_how.html with new zpipe.c (also web site) +- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems + that gcc became pickier in 4.0) +- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain + un-versioned, the patch adds versioning only for symbols introduced in + zlib-1.2.0 or later. It also declares as local those symbols which are + not designed to be exported." [Levin] +- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure +- Do not initialize global static by default in trees.c, add a response + NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess] +- Don't use strerror() in gzio.c under WinCE [Yakimov] +- Don't use errno.h in zutil.h under WinCE [Yakimov] +- Move arguments for AR to its usage to allow replacing ar [Marot] +- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson] +- Improve inflateInit() and inflateInit2() documentation +- Fix structure size comment in inflate.h +- Change configure help option from --h* to --help [Santos] + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Add zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generate bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/modules/zlib/src/ChangeLog.moz b/modules/zlib/src/ChangeLog.moz new file mode 100644 index 0000000000..98cd9f9c79 --- /dev/null +++ b/modules/zlib/src/ChangeLog.moz @@ -0,0 +1,69 @@ + + Mozilla ChangeLog file for zlib + +Mozilla.org changes: +- 17 June 2004 + Sync'd with 1.2.1 release + see bug #226733 + +- 17 June 2004 + Add mozzconf.h + +- 17 June 2004 + Turn off ZLIB_DLL to fix static build bustage + +- 24 June 2004 + do not prototype strerror for VMS in zutil.h + +- 25 June 2004 + define NO_vsnprintf for VMS in zutil.h + +- 21 September 2004 + applied patch for DoS vulnerabililty in inflate.c + see bug #258009 + +- 02 November 2004 + Sync'ed with 1.2.2 release + (keeping '#include "mozzconf.h"' in zconf.h) + Our patches of 24, 25 June and 21 Sept are now in the zlib + distribution. + See bug #248644 + +- 24 July 2005 + Sync'ed with 1.2.3 release + (keeping '#include "mozzconf.h"' in zconf.h) + See bugs #299445 and #300349 + +- 24 July 2005 + Added treatment of HAVE_VISIBILITY_PRAGMA in mozzconf.h + +- 24 July 2005 + Updated zlib.def with new symbols in zlib version 1.2.3 + +- 13 September 2009 + Don't enable zlib's debug output when the Mozilla build is in debug mode (bug 431950) + +- 18 September 2010 + Sync'ed with 1.2.5 release + (keeping '#include "mozzconf.h"' in zconf.h) + See bug #573137 + +- 8 February 2012 + Sync'ed with 1.2.6 release + (keeping '#include "mozzconf.h"' in zconf.h) + See bug #722391 + +- 4 May 2012 + Sync'ed with 1.2.7 release + (keeping '#include "mozzconf.h"' in zconf.h) + See bug #751697 + +- 9 May 2013 + Sync'ed with 1.2.8 release + (keeping '#include "mozzconf.h"' in zconf.h) + See bug #866964 + +- 16 January 2017 + Sync'ed with 1.2.11 release + (keeping '#include "mozzconf.h"' in zconf.h) + See bug #1328099 diff --git a/modules/zlib/src/FAQ b/modules/zlib/src/FAQ new file mode 100644 index 0000000000..99b7cf92e4 --- /dev/null +++ b/modules/zlib/src/FAQ @@ -0,0 +1,368 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://zlib.net/ which may have more recent information. +The lastest zlib FAQ is at http://zlib.net/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. See the + file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the + precompiled DLL are found in the zlib web site at http://zlib.net/ . + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://marknelson.us/1997/01/01/zlib-engine/ + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress(), the length of the compressed + buffer is equal to the available size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not zero. + When setting the parameter flush equal to Z_FINISH, also make sure that + avail_out is big enough to allow processing all pending input. Note that a + Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be + made with more input or output space. A Z_BUF_ERROR may in fact be + unavoidable depending on how the functions are used, since it is not + possible to tell whether or not there is more output pending when + strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a + heavily annotated example. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h . Examples of zlib usage are in the files test/example.c + and test/minigzip.c, with more in examples/ . + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple package. + zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of zlib. + Please try to reproduce the problem with a small program and send the + corresponding source to us at zlib@gzip.org . Do not send multi-megabyte + data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + By default a shared (and a static) library is built for Unix. So: + + make distclean + ./configure + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to + it. You can check the version at the top of zlib.h or with the + ZLIB_VERSION symbol defined in zlib.h . + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See http://www.pdflib.com/ . To modify PDF forms, see + http://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip formats + use the same compressed data format internally, but have different headers + and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about a + single file, such as the name and last modification date. The zlib format + on the other hand was designed for in-memory and communication channel + applications, and has a much more compact header and trailer and uses a + faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode the + gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's *Init* functions + allow for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + Yes. It has been tested on 64-bit machines, and has no dependence on any + data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format than + does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically use + Z_FULL_FLUSH, carefully write all the pending data at those points, and + keep an index of those locations, then you can start decompression at those + points. You have to be careful to not use Z_FULL_FLUSH too often, since it + can significantly degrade compression. Alternatively, you can scan a + deflate stream once to generate an index, and then use that index for + random access. See examples/zran.c . + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + It has in the past, but we have not heard of any recent evidence. There + were working ports of zlib 1.1.4 to MVS, but those links no longer work. + If you know of recent, successful applications of zlib on these operating + systems, please let us know. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at to + understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit only + if the compiler's "long" type is 32 bits. If the compiler's "long" type is + 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib is + compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of an 8K string space (or other value as set by + gzbuffer()), other than the caller of gzprintf() assuring that the output + will not exceed 8K. On the other hand, if zlib is compiled to use + snprintf() or vsnprintf(), which should normally be the case, then there is + no vulnerability. The ./configure script will display warnings if an + insecure variation of sprintf() will be used by gzprintf(). Also the + zlibCompileFlags() function will return information on what variant of + sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability, and versions + 1.2.1 and 1.2.2 were subject to an access exception when decompressing + invalid compressed data. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://zlib.net/ . + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly as well as contradicted each other. So now, we simply + make sure that the code always works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of deflate + is not affected. This only started showing up recently since zlib 1.2.x + uses malloc() by default for allocations, whereas earlier versions used + calloc(), which zeros out the allocated memory. Even though the code was + correct, versions 1.2.4 and later was changed to not stimulate these + checkers. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very + weak and can be broken with freely available programs. To get strong + encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib + compression. For PKZIP compatible "encryption", look at + http://www.info-zip.org/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion with + the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specification in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. In + any case, the compression improvements are so modest compared to other more + modern approaches, that it's not worth the effort to implement. + +41. I'm having a problem with the zip functions in zlib, can you help? + + There are no zip functions in zlib. You are probably using minizip by + Giles Vollant, which is found in the contrib directory of zlib. It is not + part of zlib. In fact none of the stuff in contrib is part of zlib. The + files in there are not supported by the zlib authors. You need to contact + the authors of the respective contribution for help. + +42. The match.asm code in contrib is under the GNU General Public License. + Since it's part of zlib, doesn't that mean that all of zlib falls under the + GNU GPL? + + No. The files in contrib are not part of zlib. They were contributed by + other authors and are provided as a convenience to the user within the zlib + distribution. Each item in contrib has its own license. + +43. Is zlib subject to export controls? What is its ECCN? + + zlib is not subject to export controls, and so is classified as EAR99. + +44. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/modules/zlib/src/INDEX b/modules/zlib/src/INDEX new file mode 100644 index 0000000000..2ba0641204 --- /dev/null +++ b/modules/zlib/src/INDEX @@ -0,0 +1,68 @@ +CMakeLists.txt cmake build file +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile dummy Makefile that tells you to ./configure +Makefile.in template for Unix Makefile +README guess what +configure configure script for Unix +make_vms.com makefile for VMS +test/example.c zlib usages examples for build testing +test/minigzip.c minimal gzip-like functionality for build testing +test/infcover.c inf*.c code coverage for build coverage testing +treebuild.xml XML description of source file dependencies +zconf.h.cmakein zconf.h template for cmake +zconf.h.in zconf.h template for configure +zlib.3 Man page for zlib +zlib.3.pdf Man page in PDF format +zlib.map Linux symbol information +zlib.pc.in Template for pkg-config descriptor +zlib.pc.cmakein zlib.pc template for cmake +zlib2ansi perl script to convert source files for C++ compilation + +amiga/ makefiles for Amiga SAS C +as400/ makefiles for AS/400 +doc/ documentation for formats and algorithms +msdos/ makefiles for MSDOS +nintendods/ makefile for Nintendo DS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +qnx/ makefiles for QNX +watcom/ makefiles for OpenWatcom +win32/ makefiles for Windows + + zlib public header files (required for library use): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzclose.c +gzguts.h +gzlib.c +gzread.c +gzwrite.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs +See examples/README.examples + + unsupported contributions by third parties +See contrib/README.contrib diff --git a/modules/zlib/src/README b/modules/zlib/src/README new file mode 100644 index 0000000000..51106de475 --- /dev/null +++ b/modules/zlib/src/README @@ -0,0 +1,115 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.11 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and +rfc1952 (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file test/example.c which also tests that +the library is working correctly. Another example is given in the file +test/minigzip.c. The compression library itself is composed of all source +files in the root directory. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile.in. In short "./configure; make test", and if that goes +well, "make install" should work for most flavors of Unix. For Windows, use +one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use +make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available at +http://marknelson.us/1997/01/01/zlib-engine/ . + +The changes made in version 1.2.11 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory contrib/ . + +zlib is available in Java using the java.util.zip package, documented at +http://java.sun.com/developer/technicalArticles/Programming/compression/ . + +A Perl interface to zlib written by Paul Marquess is available +at CPAN (Comprehensive Perl Archive Network) sites, including +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://docs.python.org/library/zlib.html . + +zlib is built into tcl: http://wiki.tcl.tk/4610 . + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS or BEOS. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate and + zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; they + are too numerous to cite here. + +Copyright notice: + + (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/modules/zlib/src/adler32.c b/modules/zlib/src/adler32.c index 054521df26..a42f35fce2 100644 --- a/modules/zlib/src/adler32.c +++ b/modules/zlib/src/adler32.c @@ -3,75 +3,214 @@ * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" -#include "functable.h" -#include "adler32_p.h" +/* @(#) $Id$ */ -#ifdef ZLIB_COMPAT -unsigned long Z_EXPORT PREFIX(adler32_z)(unsigned long adler, const unsigned char *buf, size_t len) { - if (buf == NULL) - return ADLER32_INITIAL_VALUE; - return (unsigned long)FUNCTABLE_CALL(adler32)((uint32_t)adler, buf, len); -} +#include "zutil.h" + +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) #else -uint32_t Z_EXPORT PREFIX(adler32_z)(uint32_t adler, const unsigned char *buf, size_t len) { - if (buf == NULL) - return ADLER32_INITIAL_VALUE; - return FUNCTABLE_CALL(adler32)(adler, buf, len); -} +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +#if defined(ADLER32_SIMD_SSSE3) +#include "adler32_simd.h" +#include "x86.h" +#elif defined(ADLER32_SIMD_NEON) +#include "adler32_simd.h" #endif /* ========================================================================= */ -#ifdef ZLIB_COMPAT -unsigned long Z_EXPORT PREFIX(adler32)(unsigned long adler, const unsigned char *buf, unsigned int len) { - if (buf == NULL) - return ADLER32_INITIAL_VALUE; - return (unsigned long)FUNCTABLE_CALL(adler32)((uint32_t)adler, buf, len); -} -#else -uint32_t Z_EXPORT PREFIX(adler32)(uint32_t adler, const unsigned char *buf, uint32_t len) { - if (buf == NULL) - return ADLER32_INITIAL_VALUE; - return FUNCTABLE_CALL(adler32)(adler, buf, len); -} +uLong ZEXPORT adler32_z(adler, buf, len) + uLong adler; + const Bytef *buf; + z_size_t len; +{ + unsigned long sum2; + unsigned n; + +#if defined(ADLER32_SIMD_SSSE3) + if (x86_cpu_enable_ssse3 && buf && len >= 64) + return adler32_simd_(adler, buf, len); +#elif defined(ADLER32_SIMD_NEON) + if (buf && len >= 64) + return adler32_simd_(adler, buf, len); #endif + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + +#if defined(ADLER32_SIMD_SSSE3) + /* + * Use SSSE3 to compute the adler32. Since this routine can be + * freely used, check CPU features here. zlib convention is to + * call adler32(0, NULL, 0), before making calls to adler32(). + * So this is a good early (and infrequent) place to cache CPU + * features for those later, more interesting adler32() calls. + */ + if (buf == Z_NULL) { + if (!len) /* Assume user is calling adler32(0, NULL, 0); */ + x86_check_features(); + return 1L; + } +#else + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; +#endif + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + /* ========================================================================= */ -static uint32_t adler32_combine_(uint32_t adler1, uint32_t adler2, z_off64_t len2) { - uint32_t sum1; - uint32_t sum2; +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + return adler32_z(adler, buf, len); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) - return 0xffffffff; + return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ - len2 %= BASE; /* assumes len2 >= 0 */ + MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; - sum2 %= BASE; + MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; - if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ -#ifdef ZLIB_COMPAT -unsigned long Z_EXPORT PREFIX(adler32_combine)(unsigned long adler1, unsigned long adler2, z_off_t len2) { - return (unsigned long)adler32_combine_((uint32_t)adler1, (uint32_t)adler2, len2); -} - -unsigned long Z_EXPORT PREFIX4(adler32_combine)(unsigned long adler1, unsigned long adler2, z_off64_t len2) { - return (unsigned long)adler32_combine_((uint32_t)adler1, (uint32_t)adler2, len2); -} -#else -uint32_t Z_EXPORT PREFIX4(adler32_combine)(uint32_t adler1, uint32_t adler2, z_off64_t len2) { +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ return adler32_combine_(adler1, adler2, len2); } -#endif diff --git a/modules/zlib/src/adler32_p.h b/modules/zlib/src/adler32_p.h deleted file mode 100644 index 836029b2ab..0000000000 --- a/modules/zlib/src/adler32_p.h +++ /dev/null @@ -1,100 +0,0 @@ -/* adler32_p.h -- Private inline functions and macros shared with - * different computation of the Adler-32 checksum - * of a data stream. - * Copyright (C) 1995-2011, 2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ADLER32_P_H -#define ADLER32_P_H - -#define BASE 65521U /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ -#define NMAX_ALIGNED32 (NMAX & ~31) -/* NMAX rounded down to a multiple of 32 is 5536 */ - -#define ADLER_DO1(sum1, sum2, buf, i) {(sum1) += buf[(i)]; (sum2) += (sum1);} -#define ADLER_DO2(sum1, sum2, buf, i) {ADLER_DO1(sum1, sum2, buf, i); ADLER_DO1(sum1, sum2, buf, i+1);} -#define ADLER_DO4(sum1, sum2, buf, i) {ADLER_DO2(sum1, sum2, buf, i); ADLER_DO2(sum1, sum2, buf, i+2);} -#define ADLER_DO8(sum1, sum2, buf, i) {ADLER_DO4(sum1, sum2, buf, i); ADLER_DO4(sum1, sum2, buf, i+4);} -#define ADLER_DO16(sum1, sum2, buf) {ADLER_DO8(sum1, sum2, buf, 0); ADLER_DO8(sum1, sum2, buf, 8);} - -Z_FORCEINLINE static void adler32_copy_align(uint32_t *Z_RESTRICT adler, uint8_t *dst, const uint8_t *buf, size_t len, - uint32_t *Z_RESTRICT sum2, const int MAX_LEN, const int COPY) { - Z_UNUSED(MAX_LEN); - if (len & 1) { - if (COPY) { - *dst = *buf; - dst += 1; - } - ADLER_DO1(*adler, *sum2, buf, 0); - buf += 1; - } - if (len & 2) { - if (COPY) { - memcpy(dst, buf, 2); - dst += 2; - } - ADLER_DO2(*adler, *sum2, buf, 0); - buf += 2; - } - while (len >= 4) { - if (COPY) { - memcpy(dst, buf, 4); - dst += 4; - } - len -= 4; - ADLER_DO4(*adler, *sum2, buf, 0); - buf += 4; - } -} - -Z_FORCEINLINE static uint32_t adler32_copy_tail(uint32_t adler, uint8_t *dst, const uint8_t *buf, size_t len, - uint32_t sum2, const int REBASE, const int MAX_LEN, const int COPY) { - if (len) { - /* DO16 loop for large remainders only (scalar, risc-v). */ - if (MAX_LEN >= 32) { - while (len >= 16) { - if (COPY) { - memcpy(dst, buf, 16); - dst += 16; - } - len -= 16; - ADLER_DO16(adler, sum2, buf); - buf += 16; - } - } - /* DO4 loop avoids GCC x86 register pressure from hoisted DO8/DO16 loads. */ - while (len >= 4) { - if (COPY) { - memcpy(dst, buf, 4); - dst += 4; - } - len -= 4; - ADLER_DO4(adler, sum2, buf, 0); - buf += 4; - } - if (len & 2) { - if (COPY) { - memcpy(dst, buf, 2); - dst += 2; - } - ADLER_DO2(adler, sum2, buf, 0); - buf += 2; - } - if (len & 1) { - if (COPY) - *dst = *buf; - ADLER_DO1(adler, sum2, buf, 0); - } - } - if (REBASE) { - adler %= BASE; - sum2 %= BASE; - } - /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */ - return adler | (sum2 << 16); -} - -#endif /* ADLER32_P_H */ diff --git a/modules/zlib/src/adler32_simd.c b/modules/zlib/src/adler32_simd.c new file mode 100644 index 0000000000..1354915cc0 --- /dev/null +++ b/modules/zlib/src/adler32_simd.c @@ -0,0 +1,366 @@ +/* adler32_simd.c + * + * Copyright 2017 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the Chromium source repository LICENSE file. + * + * Per http://en.wikipedia.org/wiki/Adler-32 the adler32 A value (aka s1) is + * the sum of N input data bytes D1 ... DN, + * + * A = A0 + D1 + D2 + ... + DN + * + * where A0 is the initial value. + * + * SSE2 _mm_sad_epu8() can be used for byte sums (see http://bit.ly/2wpUOeD, + * for example) and accumulating the byte sums can use SSE shuffle-adds (see + * the "Integer" section of http://bit.ly/2erPT8t for details). Arm NEON has + * similar instructions. + * + * The adler32 B value (aka s2) sums the A values from each step: + * + * B0 + (A0 + D1) + (A0 + D1 + D2) + ... + (A0 + D1 + D2 + ... + DN) or + * + * B0 + N.A0 + N.D1 + (N-1).D2 + (N-2).D3 + ... + (N-(N-1)).DN + * + * B0 being the initial value. For 32 bytes (ideal for garden-variety SIMD): + * + * B = B0 + 32.A0 + [D1 D2 D3 ... D32] x [32 31 30 ... 1]. + * + * Adjacent blocks of 32 input bytes can be iterated with the expressions to + * compute the adler32 s1 s2 of M >> 32 input bytes [1]. + * + * As M grows, the s1 s2 sums grow. If left unchecked, they would eventually + * overflow the precision of their integer representation (bad). However, s1 + * and s2 also need to be computed modulo the adler BASE value (reduced). If + * at most NMAX bytes are processed before a reduce, s1 s2 _cannot_ overflow + * a uint32_t type (the NMAX constraint) [2]. + * + * [1] the iterative equations for s2 contain constant factors; these can be + * hoisted from the n-blocks do loop of the SIMD code. + * + * [2] zlib adler32_z() uses this fact to implement NMAX-block-based updates + * of the adler s1 s2 of uint32_t type (see adler32.c). + */ + +#include "adler32_simd.h" + +/* Definitions from adler32.c: largest prime smaller than 65536 */ +#define BASE 65521U +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ +#define NMAX 5552 + +#if defined(ADLER32_SIMD_SSSE3) + +#include + +uint32_t ZLIB_INTERNAL adler32_simd_( /* SSSE3 */ + uint32_t adler, + const unsigned char *buf, + z_size_t len) +{ + /* + * Split Adler-32 into component sums. + */ + uint32_t s1 = adler & 0xffff; + uint32_t s2 = adler >> 16; + + /* + * Process the data in blocks. + */ + const unsigned BLOCK_SIZE = 1 << 5; + + z_size_t blocks = len / BLOCK_SIZE; + len -= blocks * BLOCK_SIZE; + + while (blocks) + { + unsigned n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */ + if (n > blocks) + n = (unsigned) blocks; + blocks -= n; + + const __m128i tap1 = + _mm_setr_epi8(32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17); + const __m128i tap2 = + _mm_setr_epi8(16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + const __m128i zero = + _mm_setr_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + const __m128i ones = + _mm_set_epi16( 1, 1, 1, 1, 1, 1, 1, 1); + + /* + * Process n blocks of data. At most NMAX data bytes can be + * processed before s2 must be reduced modulo BASE. + */ + __m128i v_ps = _mm_set_epi32(0, 0, 0, s1 * n); + __m128i v_s2 = _mm_set_epi32(0, 0, 0, s2); + __m128i v_s1 = _mm_set_epi32(0, 0, 0, 0); + + do { + /* + * Load 32 input bytes. + */ + const __m128i bytes1 = _mm_loadu_si128((__m128i*)(buf)); + const __m128i bytes2 = _mm_loadu_si128((__m128i*)(buf + 16)); + + /* + * Add previous block byte sum to v_ps. + */ + v_ps = _mm_add_epi32(v_ps, v_s1); + + /* + * Horizontally add the bytes for s1, multiply-adds the + * bytes by [ 32, 31, 30, ... ] for s2. + */ + v_s1 = _mm_add_epi32(v_s1, _mm_sad_epu8(bytes1, zero)); + const __m128i mad1 = _mm_maddubs_epi16(bytes1, tap1); + v_s2 = _mm_add_epi32(v_s2, _mm_madd_epi16(mad1, ones)); + + v_s1 = _mm_add_epi32(v_s1, _mm_sad_epu8(bytes2, zero)); + const __m128i mad2 = _mm_maddubs_epi16(bytes2, tap2); + v_s2 = _mm_add_epi32(v_s2, _mm_madd_epi16(mad2, ones)); + + buf += BLOCK_SIZE; + + } while (--n); + + v_s2 = _mm_add_epi32(v_s2, _mm_slli_epi32(v_ps, 5)); + + /* + * Sum epi32 ints v_s1(s2) and accumulate in s1(s2). + */ + +#define S23O1 _MM_SHUFFLE(2,3,0,1) /* A B C D -> B A D C */ +#define S1O32 _MM_SHUFFLE(1,0,3,2) /* A B C D -> C D A B */ + + v_s1 = _mm_add_epi32(v_s1, _mm_shuffle_epi32(v_s1, S23O1)); + v_s1 = _mm_add_epi32(v_s1, _mm_shuffle_epi32(v_s1, S1O32)); + + s1 += _mm_cvtsi128_si32(v_s1); + + v_s2 = _mm_add_epi32(v_s2, _mm_shuffle_epi32(v_s2, S23O1)); + v_s2 = _mm_add_epi32(v_s2, _mm_shuffle_epi32(v_s2, S1O32)); + + s2 = _mm_cvtsi128_si32(v_s2); + +#undef S23O1 +#undef S1O32 + + /* + * Reduce. + */ + s1 %= BASE; + s2 %= BASE; + } + + /* + * Handle leftover data. + */ + if (len) { + if (len >= 16) { + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + + len -= 16; + } + + while (len--) { + s2 += (s1 += *buf++); + } + + if (s1 >= BASE) + s1 -= BASE; + s2 %= BASE; + } + + /* + * Return the recombined sums. + */ + return s1 | (s2 << 16); +} + +#elif defined(ADLER32_SIMD_NEON) + +#include + +uint32_t ZLIB_INTERNAL adler32_simd_( /* NEON */ + uint32_t adler, + const unsigned char *buf, + z_size_t len) +{ + /* + * Split Adler-32 into component sums. + */ + uint32_t s1 = adler & 0xffff; + uint32_t s2 = adler >> 16; + + /* + * Serially compute s1 & s2, until the data is 16-byte aligned. + */ + if ((uintptr_t)buf & 15) { + while ((uintptr_t)buf & 15) { + s2 += (s1 += *buf++); + --len; + } + + if (s1 >= BASE) + s1 -= BASE; + s2 %= BASE; + } + + /* + * Process the data in blocks. + */ + const unsigned BLOCK_SIZE = 1 << 5; + + z_size_t blocks = len / BLOCK_SIZE; + len -= blocks * BLOCK_SIZE; + + while (blocks) + { + unsigned n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */ + if (n > blocks) + n = (unsigned) blocks; + blocks -= n; + + /* + * Process n blocks of data. At most NMAX data bytes can be + * processed before s2 must be reduced modulo BASE. + */ + uint32x4_t v_s2 = (uint32x4_t) { 0, 0, 0, s1 * n }; + uint32x4_t v_s1 = (uint32x4_t) { 0, 0, 0, 0 }; + + uint16x8_t v_column_sum_1 = vdupq_n_u16(0); + uint16x8_t v_column_sum_2 = vdupq_n_u16(0); + uint16x8_t v_column_sum_3 = vdupq_n_u16(0); + uint16x8_t v_column_sum_4 = vdupq_n_u16(0); + + do { + /* + * Load 32 input bytes. + */ + const uint8x16_t bytes1 = vld1q_u8((uint8_t*)(buf)); + const uint8x16_t bytes2 = vld1q_u8((uint8_t*)(buf + 16)); + + /* + * Add previous block byte sum to v_s2. + */ + v_s2 = vaddq_u32(v_s2, v_s1); + + /* + * Horizontally add the bytes for s1. + */ + v_s1 = vpadalq_u16(v_s1, vpadalq_u8(vpaddlq_u8(bytes1), bytes2)); + + /* + * Vertically add the bytes for s2. + */ + v_column_sum_1 = vaddw_u8(v_column_sum_1, vget_low_u8 (bytes1)); + v_column_sum_2 = vaddw_u8(v_column_sum_2, vget_high_u8(bytes1)); + v_column_sum_3 = vaddw_u8(v_column_sum_3, vget_low_u8 (bytes2)); + v_column_sum_4 = vaddw_u8(v_column_sum_4, vget_high_u8(bytes2)); + + buf += BLOCK_SIZE; + + } while (--n); + + v_s2 = vshlq_n_u32(v_s2, 5); + + /* + * Multiply-add bytes by [ 32, 31, 30, ... ] for s2. + */ + v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_1), + (uint16x4_t) { 32, 31, 30, 29 }); + v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_1), + (uint16x4_t) { 28, 27, 26, 25 }); + v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_2), + (uint16x4_t) { 24, 23, 22, 21 }); + v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_2), + (uint16x4_t) { 20, 19, 18, 17 }); + v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_3), + (uint16x4_t) { 16, 15, 14, 13 }); + v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_3), + (uint16x4_t) { 12, 11, 10, 9 }); + v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_4), + (uint16x4_t) { 8, 7, 6, 5 }); + v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_4), + (uint16x4_t) { 4, 3, 2, 1 }); + + /* + * Sum epi32 ints v_s1(s2) and accumulate in s1(s2). + */ + uint32x2_t sum1 = vpadd_u32(vget_low_u32(v_s1), vget_high_u32(v_s1)); + uint32x2_t sum2 = vpadd_u32(vget_low_u32(v_s2), vget_high_u32(v_s2)); + uint32x2_t s1s2 = vpadd_u32(sum1, sum2); + + s1 += vget_lane_u32(s1s2, 0); + s2 += vget_lane_u32(s1s2, 1); + + /* + * Reduce. + */ + s1 %= BASE; + s2 %= BASE; + } + + /* + * Handle leftover data. + */ + if (len) { + if (len >= 16) { + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + s2 += (s1 += *buf++); + + len -= 16; + } + + while (len--) { + s2 += (s1 += *buf++); + } + + if (s1 >= BASE) + s1 -= BASE; + s2 %= BASE; + } + + /* + * Return the recombined sums. + */ + return s1 | (s2 << 16); +} + +#endif /* ADLER32_SIMD_SSSE3 */ diff --git a/modules/zlib/src/adler32_simd.h b/modules/zlib/src/adler32_simd.h new file mode 100644 index 0000000000..52bb14d167 --- /dev/null +++ b/modules/zlib/src/adler32_simd.h @@ -0,0 +1,16 @@ +/* adler32_simd.h + * + * Copyright 2017 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the Chromium source repository LICENSE file. + */ + +#include + +#include "zconf.h" +#include "zutil.h" + +uint32_t ZLIB_INTERNAL adler32_simd_( + uint32_t adler, + const unsigned char *buf, + z_size_t len); diff --git a/modules/zlib/src/arch/.gitignore b/modules/zlib/src/arch/.gitignore deleted file mode 100644 index 2c3af0a08c..0000000000 --- a/modules/zlib/src/arch/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# ignore Makefiles; they're all automatically generated -Makefile diff --git a/modules/zlib/src/arch/arm/Makefile.in b/modules/zlib/src/arch/arm/Makefile.in deleted file mode 100644 index d0bfe0e172..0000000000 --- a/modules/zlib/src/arch/arm/Makefile.in +++ /dev/null @@ -1,86 +0,0 @@ -# Makefile for zlib -# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler -# For conditions of distribution and use, see copyright notice in zlib.h - -CC= -CFLAGS= -SFLAGS= -INCLUDES= -SUFFIX= - -ARMV8FLAG= -PMULLEOR3FLAG= -NEONFLAG= -ARMV6FLAG= -NOLTOFLAG= - -SRCDIR=. -SRCTOP=../.. -TOPDIR=$(SRCTOP) - -all: \ - adler32_neon.o adler32_neon.lo \ - arm_features.o arm_features.lo \ - chunkset_neon.o chunkset_neon.lo \ - compare256_neon.o compare256_neon.lo \ - crc32_armv8.o crc32_armv8.lo \ - crc32_armv8_pmull_eor3.o crc32_armv8_pmull_eor3.lo \ - slide_hash_neon.o slide_hash_neon.lo \ - slide_hash_armv6.o slide_hash_armv6.lo \ - -adler32_neon.o: - $(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_neon.c - -adler32_neon.lo: - $(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_neon.c - -arm_features.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/arm_features.c - -arm_features.lo: - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/arm_features.c - -chunkset_neon.o: - $(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_neon.c - -chunkset_neon.lo: - $(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_neon.c - -compare256_neon.o: - $(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_neon.c - -compare256_neon.lo: - $(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_neon.c - -crc32_armv8.o: - $(CC) $(CFLAGS) $(ARMV8FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_armv8.c - -crc32_armv8.lo: - $(CC) $(SFLAGS) $(ARMV8FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_armv8.c - -crc32_armv8_pmull_eor3.o: - $(CC) $(CFLAGS) $(PMULLEOR3FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_armv8_pmull_eor3.c - -crc32_armv8_pmull_eor3.lo: - $(CC) $(SFLAGS) $(PMULLEOR3FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_armv8_pmull_eor3.c - -slide_hash_neon.o: - $(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_neon.c - -slide_hash_neon.lo: - $(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_neon.c - -slide_hash_armv6.o: - $(CC) $(CFLAGS) $(ARMV6FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_armv6.c - -slide_hash_armv6.lo: - $(CC) $(SFLAGS) $(ARMV6FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_armv6.c - -mostlyclean: clean -clean: - rm -f *.o *.lo *~ - rm -rf objs - rm -f *.gcda *.gcno *.gcov - -distclean: clean - rm -f Makefile diff --git a/modules/zlib/src/arch/arm/acle_intrins.h b/modules/zlib/src/arch/arm/acle_intrins.h deleted file mode 100644 index 16f5e2c77c..0000000000 --- a/modules/zlib/src/arch/arm/acle_intrins.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef ARM_ACLE_INTRINS_H -#define ARM_ACLE_INTRINS_H - -#include -#ifdef _MSC_VER -# include -#elif defined(HAVE_ARM_ACLE_H) -# include -#endif - -#ifdef ARM_CRC32 -#if defined(ARCH_ARM) && defined(ARCH_64BIT) -# define Z_TARGET_CRC Z_TARGET("+crc") -#else -# define Z_TARGET_CRC -#endif -#ifdef ARM_PMULL_EOR3 -# define Z_TARGET_PMULL_EOR3 Z_TARGET("+crc+crypto+sha3") -#else -# define Z_TARGET_PMULL_EOR3 -#endif - -#if !defined(ARM_CRC32_INTRIN) && !defined(_MSC_VER) -#if defined(ARCH_ARM) && defined(ARCH_64BIT) -static inline uint32_t __crc32b(uint32_t __a, uint8_t __b) { - uint32_t __c; - __asm__("crc32b %w0, %w1, %w2" : "=r" (__c) : "r"(__a), "r"(__b)); - return __c; -} - -static inline uint32_t __crc32h(uint32_t __a, uint16_t __b) { - uint32_t __c; - __asm__("crc32h %w0, %w1, %w2" : "=r" (__c) : "r"(__a), "r"(__b)); - return __c; -} - -static inline uint32_t __crc32w(uint32_t __a, uint32_t __b) { - uint32_t __c; - __asm__("crc32w %w0, %w1, %w2" : "=r" (__c) : "r"(__a), "r"(__b)); - return __c; -} - -static inline uint32_t __crc32d(uint32_t __a, uint64_t __b) { - uint32_t __c; - __asm__("crc32x %w0, %w1, %x2" : "=r" (__c) : "r"(__a), "r"(__b)); - return __c; -} -#else -static inline uint32_t __crc32b(uint32_t __a, uint8_t __b) { - uint32_t __c; - __asm__("crc32b %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b)); - return __c; -} - -static inline uint32_t __crc32h(uint32_t __a, uint16_t __b) { - uint32_t __c; - __asm__("crc32h %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b)); - return __c; -} - -static inline uint32_t __crc32w(uint32_t __a, uint32_t __b) { - uint32_t __c; - __asm__("crc32w %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b)); - return __c; -} - -static inline uint32_t __crc32d(uint32_t __a, uint64_t __b) { - return __crc32w (__crc32w (__a, __b & 0xffffffffULL), __b >> 32); -} -#endif -#endif -#endif - -#ifdef ARM_SIMD -#ifdef _MSC_VER -typedef uint32_t uint16x2_t; - -#define __uqsub16 _arm_uqsub16 -#elif !defined(ARM_SIMD_INTRIN) -typedef uint32_t uint16x2_t; - -static inline uint16x2_t __uqsub16(uint16x2_t __a, uint16x2_t __b) { - uint16x2_t __c; - __asm__("uqsub16 %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b)); - return __c; -} -#endif -#endif - -#endif // include guard ARM_ACLE_INTRINS_H diff --git a/modules/zlib/src/arch/arm/adler32_neon.c b/modules/zlib/src/arch/arm/adler32_neon.c deleted file mode 100644 index 48532e6cd1..0000000000 --- a/modules/zlib/src/arch/arm/adler32_neon.c +++ /dev/null @@ -1,346 +0,0 @@ -/* Copyright (C) 1995-2011, 2016 Mark Adler - * Copyright (C) 2017 ARM Holdings Inc. - * Authors: - * Adenilson Cavalcanti - * Adam Stylinski - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef ARM_NEON - -#include "zbuild.h" -#include "neon_intrins.h" -#include "adler32_p.h" - -static const uint16_t ALIGNED_(64) taps[64] = { - 64, 63, 62, 61, 60, 59, 58, 57, - 56, 55, 54, 53, 52, 51, 50, 49, - 48, 47, 46, 45, 44, 43, 42, 41, - 40, 39, 38, 37, 36, 35, 34, 33, - 32, 31, 30, 29, 28, 27, 26, 25, - 24, 23, 22, 21, 20, 19, 18, 17, - 16, 15, 14, 13, 12, 11, 10, 9, - 8, 7, 6, 5, 4, 3, 2, 1 }; - -Z_FORCEINLINE static void NEON_accum32_copy(uint32_t *s, uint8_t *dst, const uint8_t *buf, size_t len) { - uint32x4_t adacc = vdupq_n_u32(0); - uint32x4_t s2acc = vdupq_n_u32(0); - uint32x4_t s2acc_0 = vdupq_n_u32(0); - uint32x4_t s2acc_1 = vdupq_n_u32(0); - uint32x4_t s2acc_2 = vdupq_n_u32(0); - - adacc = vsetq_lane_u32(s[0], adacc, 0); - s2acc = vsetq_lane_u32(s[1], s2acc, 0); - - uint32x4_t s3acc = vdupq_n_u32(0); - uint32x4_t adacc_prev = adacc; - - uint16x8_t s2_0, s2_1, s2_2, s2_3; - s2_0 = s2_1 = s2_2 = s2_3 = vdupq_n_u16(0); - - uint16x8_t s2_4, s2_5, s2_6, s2_7; - s2_4 = s2_5 = s2_6 = s2_7 = vdupq_n_u16(0); - - size_t num_iter = len >> 2; - int rem = len & 3; - - for (size_t i = 0; i < num_iter; ++i) { - uint8x16_t d0 = vld1q_u8_ex(buf, 128); - uint8x16_t d1 = vld1q_u8_ex(buf + 16, 128); - uint8x16_t d2 = vld1q_u8_ex(buf + 32, 128); - uint8x16_t d3 = vld1q_u8_ex(buf + 48, 128); - - vst1q_u8(dst, d0); - vst1q_u8(dst + 16, d1); - vst1q_u8(dst + 32, d2); - vst1q_u8(dst + 48, d3); - dst += 64; - - /* Unfortunately it doesn't look like there's a direct sum 8 bit to 32 - * bit instruction, we'll have to make due summing to 16 bits first */ - uint16x8x2_t hsum, hsum_fold; - hsum.val[0] = vpaddlq_u8(d0); - hsum.val[1] = vpaddlq_u8(d1); - - hsum_fold.val[0] = vpadalq_u8(hsum.val[0], d2); - hsum_fold.val[1] = vpadalq_u8(hsum.val[1], d3); - - adacc = vpadalq_u16(adacc, hsum_fold.val[0]); - s3acc = vaddq_u32(s3acc, adacc_prev); - adacc = vpadalq_u16(adacc, hsum_fold.val[1]); - - /* If we do straight widening additions to the 16 bit values, we don't incur - * the usual penalties of a pairwise add. We can defer the multiplications - * until the very end. These will not overflow because we are incurring at - * most 408 loop iterations (NMAX / 64), and a given lane is only going to be - * summed into once. This means for the maximum input size, the largest value - * we will see is 255 * 102 = 26010, safely under uint16 max */ - s2_0 = vaddw_u8(s2_0, vget_low_u8(d0)); - s2_1 = vaddw_high_u8(s2_1, d0); - s2_2 = vaddw_u8(s2_2, vget_low_u8(d1)); - s2_3 = vaddw_high_u8(s2_3, d1); - s2_4 = vaddw_u8(s2_4, vget_low_u8(d2)); - s2_5 = vaddw_high_u8(s2_5, d2); - s2_6 = vaddw_u8(s2_6, vget_low_u8(d3)); - s2_7 = vaddw_high_u8(s2_7, d3); - - adacc_prev = adacc; - buf += 64; - } - - s3acc = vshlq_n_u32(s3acc, 6); - - if (rem) { - uint32x4_t s3acc_0 = vdupq_n_u32(0); - while (rem--) { - uint8x16_t d0 = vld1q_u8_ex(buf, 128); - vst1q_u8(dst, d0); - dst += 16; - uint16x8_t adler; - adler = vpaddlq_u8(d0); - s2_6 = vaddw_u8(s2_6, vget_low_u8(d0)); - s2_7 = vaddw_high_u8(s2_7, d0); - adacc = vpadalq_u16(adacc, adler); - s3acc_0 = vaddq_u32(s3acc_0, adacc_prev); - adacc_prev = adacc; - buf += 16; - } - - s3acc_0 = vshlq_n_u32(s3acc_0, 4); - s3acc = vaddq_u32(s3acc_0, s3acc); - } - - uint16x8x4_t t0_t3 = vld1q_u16_x4_ex(taps, 256); - uint16x8x4_t t4_t7 = vld1q_u16_x4_ex(taps + 32, 256); - - s2acc = vmlal_high_u16(s2acc, t0_t3.val[0], s2_0); - s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[0]), vget_low_u16(s2_0)); - s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[1], s2_1); - s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[1]), vget_low_u16(s2_1)); - - s2acc = vmlal_high_u16(s2acc, t0_t3.val[2], s2_2); - s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[2]), vget_low_u16(s2_2)); - s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[3], s2_3); - s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[3]), vget_low_u16(s2_3)); - - s2acc = vmlal_high_u16(s2acc, t4_t7.val[0], s2_4); - s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[0]), vget_low_u16(s2_4)); - s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[1], s2_5); - s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[1]), vget_low_u16(s2_5)); - - s2acc = vmlal_high_u16(s2acc, t4_t7.val[2], s2_6); - s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[2]), vget_low_u16(s2_6)); - s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[3], s2_7); - s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[3]), vget_low_u16(s2_7)); - - s2acc = vaddq_u32(s2acc_0, s2acc); - s2acc_2 = vaddq_u32(s2acc_1, s2acc_2); - s2acc = vaddq_u32(s2acc, s2acc_2); - - uint32x2_t adacc2, s2acc2, as; - s2acc = vaddq_u32(s2acc, s3acc); - adacc2 = vpadd_u32(vget_low_u32(adacc), vget_high_u32(adacc)); - s2acc2 = vpadd_u32(vget_low_u32(s2acc), vget_high_u32(s2acc)); - as = vpadd_u32(adacc2, s2acc2); - s[0] = vget_lane_u32(as, 0); - s[1] = vget_lane_u32(as, 1); -} - -Z_FORCEINLINE static void NEON_accum32(uint32_t *s, const uint8_t *buf, size_t len) { - uint32x4_t adacc = vdupq_n_u32(0); - uint32x4_t s2acc = vdupq_n_u32(0); - uint32x4_t s2acc_0 = vdupq_n_u32(0); - uint32x4_t s2acc_1 = vdupq_n_u32(0); - uint32x4_t s2acc_2 = vdupq_n_u32(0); - - adacc = vsetq_lane_u32(s[0], adacc, 0); - s2acc = vsetq_lane_u32(s[1], s2acc, 0); - - uint32x4_t s3acc = vdupq_n_u32(0); - uint32x4_t adacc_prev = adacc; - - uint16x8_t s2_0, s2_1, s2_2, s2_3; - s2_0 = s2_1 = s2_2 = s2_3 = vdupq_n_u16(0); - - uint16x8_t s2_4, s2_5, s2_6, s2_7; - s2_4 = s2_5 = s2_6 = s2_7 = vdupq_n_u16(0); - - size_t num_iter = len >> 2; - int rem = len & 3; - - for (size_t i = 0; i < num_iter; ++i) { - uint8x16x4_t d0_d3 = vld1q_u8_x4_ex(buf, 256); - - /* Unfortunately it doesn't look like there's a direct sum 8 bit to 32 - * bit instruction, we'll have to make due summing to 16 bits first */ - uint16x8x2_t hsum, hsum_fold; - hsum.val[0] = vpaddlq_u8(d0_d3.val[0]); - hsum.val[1] = vpaddlq_u8(d0_d3.val[1]); - - hsum_fold.val[0] = vpadalq_u8(hsum.val[0], d0_d3.val[2]); - hsum_fold.val[1] = vpadalq_u8(hsum.val[1], d0_d3.val[3]); - - adacc = vpadalq_u16(adacc, hsum_fold.val[0]); - s3acc = vaddq_u32(s3acc, adacc_prev); - adacc = vpadalq_u16(adacc, hsum_fold.val[1]); - - /* If we do straight widening additions to the 16 bit values, we don't incur - * the usual penalties of a pairwise add. We can defer the multiplications - * until the very end. These will not overflow because we are incurring at - * most 408 loop iterations (NMAX / 64), and a given lane is only going to be - * summed into once. This means for the maximum input size, the largest value - * we will see is 255 * 102 = 26010, safely under uint16 max */ - s2_0 = vaddw_u8(s2_0, vget_low_u8(d0_d3.val[0])); - s2_1 = vaddw_high_u8(s2_1, d0_d3.val[0]); - s2_2 = vaddw_u8(s2_2, vget_low_u8(d0_d3.val[1])); - s2_3 = vaddw_high_u8(s2_3, d0_d3.val[1]); - s2_4 = vaddw_u8(s2_4, vget_low_u8(d0_d3.val[2])); - s2_5 = vaddw_high_u8(s2_5, d0_d3.val[2]); - s2_6 = vaddw_u8(s2_6, vget_low_u8(d0_d3.val[3])); - s2_7 = vaddw_high_u8(s2_7, d0_d3.val[3]); - - adacc_prev = adacc; - buf += 64; - } - - s3acc = vshlq_n_u32(s3acc, 6); - - if (rem) { - uint32x4_t s3acc_0 = vdupq_n_u32(0); - while (rem--) { - uint8x16_t d0 = vld1q_u8_ex(buf, 128); - uint16x8_t adler; - adler = vpaddlq_u8(d0); - s2_6 = vaddw_u8(s2_6, vget_low_u8(d0)); - s2_7 = vaddw_high_u8(s2_7, d0); - adacc = vpadalq_u16(adacc, adler); - s3acc_0 = vaddq_u32(s3acc_0, adacc_prev); - adacc_prev = adacc; - buf += 16; - } - - s3acc_0 = vshlq_n_u32(s3acc_0, 4); - s3acc = vaddq_u32(s3acc_0, s3acc); - } - - uint16x8x4_t t0_t3 = vld1q_u16_x4_ex(taps, 256); - uint16x8x4_t t4_t7 = vld1q_u16_x4_ex(taps + 32, 256); - - s2acc = vmlal_high_u16(s2acc, t0_t3.val[0], s2_0); - s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[0]), vget_low_u16(s2_0)); - s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[1], s2_1); - s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[1]), vget_low_u16(s2_1)); - - s2acc = vmlal_high_u16(s2acc, t0_t3.val[2], s2_2); - s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[2]), vget_low_u16(s2_2)); - s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[3], s2_3); - s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[3]), vget_low_u16(s2_3)); - - s2acc = vmlal_high_u16(s2acc, t4_t7.val[0], s2_4); - s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[0]), vget_low_u16(s2_4)); - s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[1], s2_5); - s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[1]), vget_low_u16(s2_5)); - - s2acc = vmlal_high_u16(s2acc, t4_t7.val[2], s2_6); - s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[2]), vget_low_u16(s2_6)); - s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[3], s2_7); - s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[3]), vget_low_u16(s2_7)); - - s2acc = vaddq_u32(s2acc_0, s2acc); - s2acc_2 = vaddq_u32(s2acc_1, s2acc_2); - s2acc = vaddq_u32(s2acc, s2acc_2); - - uint32x2_t adacc2, s2acc2, as; - s2acc = vaddq_u32(s2acc, s3acc); - adacc2 = vpadd_u32(vget_low_u32(adacc), vget_high_u32(adacc)); - s2acc2 = vpadd_u32(vget_low_u32(s2acc), vget_high_u32(s2acc)); - as = vpadd_u32(adacc2, s2acc2); - s[0] = vget_lane_u32(as, 0); - s[1] = vget_lane_u32(as, 1); -} - -Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) { - /* split Adler-32 into component sums */ - uint32_t sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (UNLIKELY(len == 1)) - return adler32_copy_tail(adler, dst, src, 1, sum2, 1, 1, COPY); - - /* in case short lengths are provided, keep it somewhat fast */ - if (UNLIKELY(len < 16)) - return adler32_copy_tail(adler, dst, src, len, sum2, 1, 15, COPY); - - uint32_t pair[2]; - - /* Split Adler-32 into component sums, it can be supplied by - * the caller sites (e.g. in a PNG file). - */ - pair[0] = adler; - pair[1] = sum2; - - /* If memory is not SIMD aligned, do scalar sums to an aligned - * offset, provided that doing so doesn't completely eliminate - * SIMD operation. Aligned loads are still faster on ARM, even - * when there's no explicit aligned load instruction. Note: - * the code currently emits an alignment hint in the instruction - * for exactly 256 bits when supported by the compiler. Several ARM - * SIPs have small penalties for cacheline crossing loads as well (so - * really 512 bits is the optimal alignment of the buffer). 32 bytes - * should strike a balance, though. The Cortex-A8 and Cortex-A9 - * processors are documented to benefit from 128 bit and 64 bit - * alignment, but it's unclear which other SIPs will benefit from it. - * In the copying variant we use fallback to 4x loads and 4x stores, - * as ld1x4 seems to block ILP when stores are in the mix */ - size_t align_diff = MIN(ALIGN_DIFF(src, 32), len); - size_t n = NMAX_ALIGNED32; - if (align_diff) { - adler32_copy_align(&pair[0], dst, src, align_diff, &pair[1], 31, COPY); - - if (COPY) - dst += align_diff; - src += align_diff; - len -= align_diff; - n = ALIGN_DOWN(n - align_diff, 32); - } - - while (len >= 16) { - n = MIN(len, n); - - if (COPY) - NEON_accum32_copy(pair, dst, src, n >> 4); - else - NEON_accum32(pair, src, n >> 4); - - pair[0] %= BASE; - pair[1] %= BASE; - - size_t k = (n >> 4) << 4; - src += k; - if (COPY) - dst += k; - len -= k; - n = NMAX_ALIGNED32; - } - - /* Process tail (len < 16). */ - return adler32_copy_tail(pair[0], dst, src, len, pair[1], len != 0 || align_diff, 15, COPY); -} - -Z_INTERNAL uint32_t adler32_neon(uint32_t adler, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, NULL, src, len, 0); -} - -Z_INTERNAL uint32_t adler32_copy_neon(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { -#if OPTIMAL_CMP >= 32 - return adler32_copy_impl(adler, dst, src, len, 1); -#else - /* Without unaligned access, interleaved stores get decomposed into byte ops */ - adler = adler32_neon(adler, src, len); - memcpy(dst, src, len); - return adler; -#endif -} - -#endif diff --git a/modules/zlib/src/arch/arm/arm_features.c b/modules/zlib/src/arch/arm/arm_features.c deleted file mode 100644 index 8f179526ef..0000000000 --- a/modules/zlib/src/arch/arm/arm_features.c +++ /dev/null @@ -1,334 +0,0 @@ -#ifdef ARM_FEATURES - -#include "zbuild.h" -#include "arm_features.h" - -#if defined(HAVE_SYS_AUXV_H) -# include -# ifdef ARM_ASM_HWCAP -# include -# endif -#elif defined(__FreeBSD__) && defined(ARCH_64BIT) -# include -# ifndef ID_AA64ISAR0_CRC32_VAL -# define ID_AA64ISAR0_CRC32_VAL ID_AA64ISAR0_CRC32 -# endif -#elif defined(__OpenBSD__) && defined(ARCH_64BIT) -# include -# include -# include -# include -#elif defined(__APPLE__) -# if !defined(_DARWIN_C_SOURCE) -# define _DARWIN_C_SOURCE /* enable types aliases (eg u_int) */ -# endif -# include -#elif defined(_WIN32) -# include -#endif - -static int arm_has_crc32(void) { - int has_crc32 = 0; -#if defined(__ARM_FEATURE_CRC32) - /* Compile-time check */ - has_crc32 = 1; -#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP_CRC32 - has_crc32 = (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0; -# elif defined(HWCAP2_CRC32) - has_crc32 = (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0; -# endif -#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP_CRC32 - unsigned long hwcap = 0; - elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); - has_crc32 = (hwcap & HWCAP_CRC32) != 0; -# elif defined(HWCAP2_CRC32) - unsigned long hwcap2 = 0; - elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2)); - has_crc32 = (hwcap2 & HWCAP2_CRC32) != 0; -# endif -#elif defined(__FreeBSD__) && defined(ARCH_64BIT) - has_crc32 = getenv("QEMU_EMULATING") == NULL - && ID_AA64ISAR0_CRC32_VAL(READ_SPECIALREG(id_aa64isar0_el1)) >= ID_AA64ISAR0_CRC32_BASE; -#elif defined(__OpenBSD__) && defined(ARCH_64BIT) - int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 }; - uint64_t isar0 = 0; - size_t len = sizeof(isar0); - if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) != -1) { - has_crc32 = ID_AA64ISAR0_CRC32(isar0) >= ID_AA64ISAR0_CRC32_BASE; - } -#elif defined(__APPLE__) - int has_feat = 0; - size_t size = sizeof(has_feat); - has_crc32 = sysctlbyname("hw.optional.armv8_crc32", &has_feat, &size, NULL, 0) == 0 - && has_feat == 1; -#elif defined(_WIN32) - has_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); -#endif - return has_crc32; -} - -static int arm_has_pmull(void) { - int has_pmull = 0; -#if defined(__ARM_FEATURE_CRYPTO) || defined(__ARM_FEATURE_AES) - /* Compile-time check */ - has_pmull = 1; -#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP_PMULL - has_pmull = (getauxval(AT_HWCAP) & HWCAP_PMULL) != 0; -# elif defined(HWCAP_AES) - /* PMULL is part of crypto extension, check for AES as proxy */ - has_pmull = (getauxval(AT_HWCAP) & HWCAP_AES) != 0; -# endif -#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP_PMULL - unsigned long hwcap = 0; - elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); - has_pmull = (hwcap & HWCAP_PMULL) != 0; -# elif defined(HWCAP_AES) - /* PMULL is part of crypto extension, check for AES as proxy */ - unsigned long hwcap = 0; - elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); - has_pmull = (hwcap & HWCAP_AES) != 0; -# endif -#elif defined(__FreeBSD__) && defined(ARCH_64BIT) - /* Check for AES feature as PMULL is part of crypto extension */ - has_pmull = getenv("QEMU_EMULATING") == NULL - && ID_AA64ISAR0_AES_VAL(READ_SPECIALREG(id_aa64isar0_el1)) >= ID_AA64ISAR0_AES_BASE; -#elif defined(__OpenBSD__) && defined(ARCH_64BIT) - int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 }; - uint64_t isar0 = 0; - size_t len = sizeof(isar0); - if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) != -1) { - has_pmull = ID_AA64ISAR0_AES(isar0) >= ID_AA64ISAR0_AES_BASE; - } -#elif defined(__APPLE__) - int has_feat = 0; - size_t size = sizeof(has_feat); - has_pmull = sysctlbyname("hw.optional.arm.FEAT_PMULL", &has_feat, &size, NULL, 0) == 0 - && has_feat == 1; -#elif defined(_WIN32) - /* Windows checks for crypto/AES support */ -# ifdef PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE - has_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); -# endif -#endif - return has_pmull; -} - -static int arm_has_eor3(void) { - int has_eor3 = 0; -#if defined(__ARM_FEATURE_SHA3) - /* Compile-time check */ - has_eor3 = 1; -#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H) - /* EOR3 is part of SHA3 extension, check HWCAP2_SHA3 */ -# ifdef HWCAP2_SHA3 - has_eor3 = (getauxval(AT_HWCAP2) & HWCAP2_SHA3) != 0; -# elif defined(HWCAP_SHA3) - has_eor3 = (getauxval(AT_HWCAP) & HWCAP_SHA3) != 0; -# endif -#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP2_SHA3 - unsigned long hwcap2 = 0; - elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2)); - has_eor3 = (hwcap2 & HWCAP2_SHA3) != 0; -# elif defined(HWCAP_SHA3) - unsigned long hwcap = 0; - elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); - has_eor3 = (hwcap & HWCAP_SHA3) != 0; -# endif -#elif defined(__FreeBSD__) && defined(ARCH_64BIT) - /* FreeBSD: check for SHA3 in id_aa64isar0_el1 */ -# ifdef ID_AA64ISAR0_SHA3_VAL - has_eor3 = getenv("QEMU_EMULATING") == NULL - && ID_AA64ISAR0_SHA3_VAL(READ_SPECIALREG(id_aa64isar0_el1)) >= ID_AA64ISAR0_SHA3_BASE; -# endif -#elif defined(__OpenBSD__) && defined(ARCH_64BIT) -# ifdef ID_AA64ISAR0_SHA3 - int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 }; - uint64_t isar0 = 0; - size_t len = sizeof(isar0); - if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) != -1) { - has_eor3 = ID_AA64ISAR0_SHA3(isar0) >= ID_AA64ISAR0_SHA3_IMPL; - } -# endif -#elif defined(__APPLE__) - /* All Apple Silicon (M1+) has SHA3/EOR3 support */ - int has_feat = 0; - size_t size = sizeof(has_feat); - has_eor3 = sysctlbyname("hw.optional.arm.FEAT_SHA3", &has_feat, &size, NULL, 0) == 0 - && has_feat == 1; - /* Fallback to legacy name for older macOS versions */ - if (!has_eor3) { - size = sizeof(has_feat); - has_eor3 = sysctlbyname("hw.optional.armv8_2_sha3", &has_feat, &size, NULL, 0) == 0 - && has_feat == 1; - } -#elif defined(_WIN32) -# ifdef PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE - has_eor3 = IsProcessorFeaturePresent(PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE); -# endif -#endif - return has_eor3; -} - -/* AArch64 has neon. */ -#ifdef ARCH_32BIT -static inline int arm_has_neon(void) { - int has_neon = 0; -#if defined(__ARM_NEON__) || defined(__ARM_NEON) - /* Compile-time check */ - has_neon = 1; -#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP_ARM_NEON - has_neon = (getauxval(AT_HWCAP) & HWCAP_ARM_NEON) != 0; -# elif defined(HWCAP_NEON) - has_neon = (getauxval(AT_HWCAP) & HWCAP_NEON) != 0; -# endif -#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP_NEON - unsigned long hwcap = 0; - elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); - has_neon = (hwcap & HWCAP_NEON) != 0; -# endif -#elif defined(__APPLE__) - int has_feat = 0; - size_t size = sizeof(has_feat); - has_neon = sysctlbyname("hw.optional.neon", &has_feat, &size, NULL, 0) == 0 - && has_feat == 1; -#elif defined(_M_ARM) && defined(WINAPI_FAMILY_PARTITION) -# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - has_neon = 1; /* Always supported */ -# endif -#endif - return has_neon; -} -#endif - -/* AArch64 does not have ARMv6 SIMD. */ -#ifdef ARCH_32BIT -static inline int arm_has_simd(void) { - int has_simd = 0; -#if defined(__ARM_FEATURE_SIMD32) - /* Compile-time check for ARMv6 SIMD */ - has_simd = 1; -#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H) - const char *platform = (const char *)getauxval(AT_PLATFORM); - has_simd = platform - && (strncmp(platform, "v6l", 3) == 0 - || strncmp(platform, "v7l", 3) == 0 - || strncmp(platform, "v8l", 3) == 0); -#endif - return has_simd; -} -#endif - -#if defined(ARCH_64BIT) && !defined(__APPLE__) && !defined(_WIN32) -/* MIDR_EL1 bit field definitions */ -#define MIDR_IMPLEMENTOR(midr) (((midr) & (0xffU << 24)) >> 24) -#define MIDR_PARTNUM(midr) (((midr) & (0xfffU << 4)) >> 4) - -/* ARM CPU Implementer IDs */ -#define ARM_IMPLEMENTER_ARM 0x41 -#define ARM_IMPLEMENTER_QUALCOMM 0x51 -#define ARM_IMPLEMENTER_APPLE 0x61 - -/* ARM CPU Part Numbers */ - -/* Cortex-X series - Multiple PMULL lanes */ -#define ARM_PART_CORTEX_X1 0xd44 -#define ARM_PART_CORTEX_X1C 0xd4c -#define ARM_PART_CORTEX_X2 0xd48 -#define ARM_PART_CORTEX_X3 0xd4e -#define ARM_PART_CORTEX_X4 0xd82 -#define ARM_PART_CORTEX_X925 0xd85 - -/* Neoverse V/N2 series - Multiple PMULL lanes */ -#define ARM_PART_NEOVERSE_N2 0xd49 -#define ARM_PART_NEOVERSE_V1 0xd40 -#define ARM_PART_NEOVERSE_V2 0xd4f -#define ARM_PART_NEOVERSE_V3 0xd8e - -/* Snapdragon X Elite/Plus - Custom core */ -#define QUALCOMM_PART_ORYON 0x001 - -static inline int arm_has_cpuid(void) { - int has_cpuid = 0; -#if defined(__linux__) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP_CPUID - has_cpuid = (getauxval(AT_HWCAP) & HWCAP_CPUID) != 0; -# elif defined(HWCAP2_CPUID) - has_cpuid = (getauxval(AT_HWCAP2) & HWCAP2_CPUID) != 0; -# endif -#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H) -# ifdef HWCAP_CPUID - unsigned long hwcap = 0; - elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); - has_cpuid = (hwcap & HWCAP_CPUID) != 0; -# endif -#endif - return has_cpuid; -} -#endif - -/* Determine if CPU has fast PMULL (multiple execution units) */ -static inline int arm_cpu_has_fast_pmull(void) { - int has_fast_pmull = 0; -#if defined(__APPLE__) - /* On macOS, all Apple Silicon has fast PMULL */ - has_fast_pmull = 1; -#elif defined(ARCH_64BIT) && !defined(_WIN32) - /* We need CPUID feature to read MIDR register */ - if (!arm_has_cpuid()) - return has_fast_pmull; - - uint64_t midr; - __asm__ ("mrs %0, midr_el1" : "=r" (midr)); - - uint32_t implementer = MIDR_IMPLEMENTOR(midr); - uint32_t part = MIDR_PARTNUM(midr); - - if (implementer == ARM_IMPLEMENTER_APPLE) { - /* All Apple Silicon (M1+) have fast PMULL */ - has_fast_pmull = 1; - } else if (implementer == ARM_IMPLEMENTER_ARM) { - /* ARM Cortex-X and Neoverse V/N2 series have multi-lane PMULL */ - switch (part) { - case ARM_PART_CORTEX_X1: - case ARM_PART_CORTEX_X1C: - case ARM_PART_CORTEX_X2: - case ARM_PART_CORTEX_X3: - case ARM_PART_CORTEX_X4: - case ARM_PART_CORTEX_X925: - case ARM_PART_NEOVERSE_N2: - case ARM_PART_NEOVERSE_V1: - case ARM_PART_NEOVERSE_V2: - case ARM_PART_NEOVERSE_V3: - has_fast_pmull = 1; - } - } else if (implementer == ARM_IMPLEMENTER_QUALCOMM) { - /* Qualcomm Oryon (Snapdragon X Elite/Plus) has fast PMULL */ - if (part == QUALCOMM_PART_ORYON) - has_fast_pmull = 1; - } -#endif - return has_fast_pmull; -} - -void Z_INTERNAL arm_check_features(struct arm_cpu_features *features) { -#ifdef ARCH_64BIT - features->has_simd = 0; /* never available */ - features->has_neon = 1; /* always available */ -#else - features->has_simd = arm_has_simd(); - features->has_neon = arm_has_neon(); -#endif - features->has_crc32 = arm_has_crc32(); - features->has_pmull = arm_has_pmull(); - features->has_eor3 = arm_has_eor3(); - features->has_fast_pmull = features->has_pmull && arm_cpu_has_fast_pmull(); -} - -#endif diff --git a/modules/zlib/src/arch/arm/arm_features.h b/modules/zlib/src/arch/arm/arm_features.h deleted file mode 100644 index 2f17a9ddf0..0000000000 --- a/modules/zlib/src/arch/arm/arm_features.h +++ /dev/null @@ -1,19 +0,0 @@ -/* arm_features.h -- check for ARM features. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ARM_FEATURES_H_ -#define ARM_FEATURES_H_ - -struct arm_cpu_features { - int has_simd; - int has_neon; - int has_crc32; - int has_pmull; - int has_eor3; - int has_fast_pmull; -}; - -void Z_INTERNAL arm_check_features(struct arm_cpu_features *features); - -#endif /* ARM_FEATURES_H_ */ diff --git a/modules/zlib/src/arch/arm/arm_functions.h b/modules/zlib/src/arch/arm/arm_functions.h deleted file mode 100644 index 2b33443bbd..0000000000 --- a/modules/zlib/src/arch/arm/arm_functions.h +++ /dev/null @@ -1,89 +0,0 @@ -/* arm_functions.h -- ARM implementations for arch-specific functions. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ARM_FUNCTIONS_H_ -#define ARM_FUNCTIONS_H_ - -#include "arm_natives.h" - -#ifdef ARM_NEON -uint32_t adler32_neon(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_neon(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -uint8_t* chunkmemset_safe_neon(uint8_t *out, uint8_t *from, size_t len, size_t left); -uint32_t compare256_neon(const uint8_t *src0, const uint8_t *src1); -void inflate_fast_neon(PREFIX3(stream) *strm, uint32_t start); -uint32_t longest_match_neon(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_neon(deflate_state *const s, uint32_t cur_match); -void slide_hash_neon(deflate_state *s); -#endif - -#ifndef ARM_NEON_NATIVE -# define ADLER32_FALLBACK -# define CHUNKSET_FALLBACK -# define COMPARE256_FALLBACK -# ifndef ARM_SIMD_NATIVE -# define SLIDE_HASH_FALLBACK -# endif -#endif - -#ifdef ARM_CRC32 -uint32_t crc32_armv8(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_armv8(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif - -#ifdef ARM_PMULL_EOR3 -uint32_t crc32_armv8_pmull_eor3(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_armv8_pmull_eor3(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif - -#if !defined(ARM_CRC32_NATIVE) && !defined(ARM_PMULL_EOR3_NATIVE) -# define CRC32_BRAID_FALLBACK -#endif - -#ifdef ARM_SIMD -void slide_hash_armv6(deflate_state *s); -#endif - -#ifdef DISABLE_RUNTIME_CPU_DETECTION -// ARM - SIMD -# ifdef ARM_SIMD_NATIVE -# undef native_slide_hash -# define native_slide_hash slide_hash_armv6 -# endif -// ARM - NEON -# ifdef ARM_NEON_NATIVE -# undef native_adler32 -# define native_adler32 adler32_neon -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_neon -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_neon -# undef native_compare256 -# define native_compare256 compare256_neon -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_neon -# undef native_longest_match -# define native_longest_match longest_match_neon -# undef native_longest_match_roll -# define native_longest_match_roll longest_match_roll_neon -# undef native_slide_hash -# define native_slide_hash slide_hash_neon -# endif -// ARM - CRC32 -# ifdef ARM_CRC32_NATIVE -# undef native_crc32 -# define native_crc32 crc32_armv8 -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_armv8 -# endif -// ARM - PMULL EOR3 -# ifdef ARM_PMULL_EOR3_NATIVE -# undef native_crc32 -# define native_crc32 crc32_armv8_pmull_eor3 -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_armv8_pmull_eor3 -# endif -#endif - -#endif /* ARM_FUNCTIONS_H_ */ diff --git a/modules/zlib/src/arch/arm/arm_natives.h b/modules/zlib/src/arch/arm/arm_natives.h deleted file mode 100644 index 311e33e958..0000000000 --- a/modules/zlib/src/arch/arm/arm_natives.h +++ /dev/null @@ -1,31 +0,0 @@ -/* arm_natives.h -- ARM compile-time feature detection macros. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ARM_NATIVES_H_ -#define ARM_NATIVES_H_ - -#if defined(__ARM_FEATURE_SIMD32) -# ifdef ARM_SIMD -# define ARM_SIMD_NATIVE -# endif -#endif -/* NEON is guaranteed on ARM64 (like SSE2 on x86-64) */ -#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ARCH_64BIT) -# ifdef ARM_NEON -# define ARM_NEON_NATIVE -# endif -#endif -/* CRC32 is optional in ARMv8.0, mandatory in ARMv8.1+ */ -#if defined(__ARM_FEATURE_CRC32) || (defined(__ARM_ARCH) && __ARM_ARCH >= 801) -# ifdef ARM_CRC32 -# define ARM_CRC32_NATIVE -# endif -#endif -#if defined(__ARM_FEATURE_CRC32) && defined(__ARM_FEATURE_CRYPTO) && defined(__ARM_FEATURE_SHA3) -# ifdef ARM_PMULL_EOR3 -# define ARM_PMULL_EOR3_NATIVE -# endif -#endif - -#endif /* ARM_NATIVES_H_ */ diff --git a/modules/zlib/src/arch/arm/chunkset_neon.c b/modules/zlib/src/arch/arm/chunkset_neon.c deleted file mode 100644 index d8303b8195..0000000000 --- a/modules/zlib/src/arch/arm/chunkset_neon.c +++ /dev/null @@ -1,81 +0,0 @@ -/* chunkset_neon.c -- NEON inline functions to copy small data chunks. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef ARM_NEON - -#include "zbuild.h" -#include "zsanitizer.h" -#include "zmemory.h" -#include "neon_intrins.h" -#include "arch/shared/chunk_128bit_perm_idx_lut.h" - -typedef uint8x16_t chunk_t; - -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 -#define HAVE_CHUNK_MAG - - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - *chunk = vreinterpretq_u8_u16(vdupq_n_u16(zng_memread_2(from))); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - *chunk = vreinterpretq_u8_u32(vdupq_n_u32(zng_memread_4(from))); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = vreinterpretq_u8_u64(vdupq_n_u64(zng_memread_8(from))); -} - -#define CHUNKSIZE chunksize_neon -#define CHUNKCOPY chunkcopy_neon -#define CHUNKUNROLL chunkunroll_neon -#define CHUNKMEMSET chunkmemset_neon -#define CHUNKMEMSET_SAFE chunkmemset_safe_neon - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = vld1q_u8(s); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - vst1q_u8(out, *chunk); -} - -static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - *chunk_rem = lut_rem.remval; - - /* See note in chunkset_ssse3.c for why this is ok */ - __msan_unpoison(buf + dist, 16 - dist); - - /* This version of table is only available on aarch64 */ -#if defined(ARCH_ARM) && defined(ARCH_64BIT) - uint8x16_t ret_vec = vld1q_u8(buf); - - uint8x16_t perm_vec = vld1q_u8_ex(permute_table + lut_rem.idx, 128); - return vqtbl1q_u8(ret_vec, perm_vec); -#else - uint8x8_t ret0, ret1, a, b, perm_vec0, perm_vec1; - perm_vec0 = vld1_u8_ex(permute_table + lut_rem.idx, 64); - perm_vec1 = vld1_u8_ex(permute_table + lut_rem.idx + 8, 64); - a = vld1_u8(buf); - b = vld1_u8(buf + 8); - ret0 = vtbl1_u8(a, perm_vec0); - uint8x8x2_t ab; - ab.val[0] = a; - ab.val[1] = b; - ret1 = vtbl2_u8(ab, perm_vec1); - return vcombine_u8(ret0, ret1); -#endif -} - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_neon - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/arm/compare256_neon.c b/modules/zlib/src/arch/arm/compare256_neon.c deleted file mode 100644 index 00918d0628..0000000000 --- a/modules/zlib/src/arch/arm/compare256_neon.c +++ /dev/null @@ -1,56 +0,0 @@ -/* compare256_neon.c - NEON version of compare256 - * Copyright (C) 2022 Nathan Moinvaziri - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zmemory.h" -#include "deflate.h" -#include "fallback_builtins.h" - -#if defined(ARM_NEON) -#include "neon_intrins.h" - -static inline uint32_t compare256_neon_static(const uint8_t *src0, const uint8_t *src1) { - uint32_t len = 0; - - do { - uint8x16_t a, b, cmp; - uint64_t lane; - - a = vld1q_u8(src0); - b = vld1q_u8(src1); - - cmp = veorq_u8(a, b); - - lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 0); - if (lane) - return len + zng_first_diff_byte64(lane); - len += 8; - lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 1); - if (lane) - return len + zng_first_diff_byte64(lane); - len += 8; - - src0 += 16, src1 += 16; - } while (len < 256); - - return 256; -} - -Z_INTERNAL uint32_t compare256_neon(const uint8_t *src0, const uint8_t *src1) { - return compare256_neon_static(src0, src1); -} - -#define LONGEST_MATCH longest_match_neon -#define COMPARE256 compare256_neon_static - -#include "match_tpl.h" - -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_neon -#define COMPARE256 compare256_neon_static - -#include "match_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/arm/crc32_armv8.c b/modules/zlib/src/arch/arm/crc32_armv8.c deleted file mode 100644 index 5d443dc191..0000000000 --- a/modules/zlib/src/arch/arm/crc32_armv8.c +++ /dev/null @@ -1,30 +0,0 @@ -/* crc32_armv8.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler - * Copyright (C) 2016 Yang Zhang - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef ARM_CRC32 - -#include "zbuild.h" -#include "acle_intrins.h" -#include "crc32_armv8_p.h" - -#include "arch/shared/crc32_hw_copy_impl_tpl.h" - - -Z_INTERNAL Z_TARGET_CRC uint32_t crc32_armv8(uint32_t crc, const uint8_t *buf, size_t len) { - return crc32_hw_copy_impl(crc, NULL, buf, len, 0); -} - -Z_INTERNAL Z_TARGET_CRC uint32_t crc32_copy_armv8(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { -#if OPTIMAL_CMP >= 32 - return crc32_hw_copy_impl(crc, dst, src, len, 1); -#else - /* Without unaligned access, interleaved stores get decomposed into byte ops */ - crc = crc32_armv8(crc, src, len); - memcpy(dst, src, len); - return crc; -#endif -} -#endif diff --git a/modules/zlib/src/arch/arm/crc32_armv8_p.h b/modules/zlib/src/arch/arm/crc32_armv8_p.h deleted file mode 100644 index e136d59eae..0000000000 --- a/modules/zlib/src/arch/arm/crc32_armv8_p.h +++ /dev/null @@ -1,18 +0,0 @@ -/* crc32_armv8_p.h -- Private shared inline ARMv8 CRC32 functions - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef CRC32_ARMV8_P_H -#define CRC32_ARMV8_P_H - -#include "zbuild.h" -#include "acle_intrins.h" - -#define CRC32B(crc, val) __crc32b((crc), (val)) -#define CRC32H(crc, val) __crc32h((crc), (val)) -#define CRC32W(crc, val) __crc32w((crc), (val)) -#define CRC32D(crc, val) __crc32d((crc), (val)) - -#include "arch/shared/crc32_hw_common_tpl.h" - -#endif /* CRC32_ARMV8_P_H */ diff --git a/modules/zlib/src/arch/arm/crc32_armv8_pmull_eor3.c b/modules/zlib/src/arch/arm/crc32_armv8_pmull_eor3.c deleted file mode 100644 index 0e6b2bce4f..0000000000 --- a/modules/zlib/src/arch/arm/crc32_armv8_pmull_eor3.c +++ /dev/null @@ -1,366 +0,0 @@ -/* crc32_armv8_pmull_eor3.c -- ARMv8 CRC32 using PMULL + EOR3 (SHA3 extension) - * Copyright (C) 2025 Peter Cawley - * https://github.com/corsix/fast-crc32 - * For conditions of distribution and use, see copyright notice in zlib.h - * - * This uses EOR3 (3-way XOR) from ARMv8.2-A SHA3 extension to save instructions. - * Uses 3-way parallel scalar CRC + 9 PMULL vector lanes, processing 192 bytes/iter. - */ - -#ifdef ARM_PMULL_EOR3 - -#include "zbuild.h" -#include "zutil.h" -#include "acle_intrins.h" -#include "neon_intrins.h" -#include "crc32_armv8_p.h" - -/* Carryless multiply low 64 bits: a[0] * b[0] */ -static inline uint64x2_t clmul_lo(uint64x2_t a, uint64x2_t b) { -#ifdef _MSC_VER - return vreinterpretq_u64_p128(vmull_p64( - vget_low_p64(vreinterpret_p64_u64(a)), - vget_low_p64(vreinterpret_p64_u64(b)))); -#else - return vreinterpretq_u64_p128(vmull_p64( - vget_lane_p64(vreinterpret_p64_u64(vget_low_u64(a)), 0), - vget_lane_p64(vreinterpret_p64_u64(vget_low_u64(b)), 0))); -#endif -} - -/* Carryless multiply high 64 bits: a[1] * b[1] */ -static inline uint64x2_t clmul_hi(uint64x2_t a, uint64x2_t b) { - return vreinterpretq_u64_p128(vmull_high_p64(vreinterpretq_p64_u64(a), vreinterpretq_p64_u64(b))); -} - -/* Carryless multiply of two 32-bit scalars: a * b (returns 64-bit result in 128-bit vector) */ -static inline uint64x2_t clmul_scalar(uint32_t a, uint32_t b) { -#ifdef _MSC_VER - return vreinterpretq_u64_p128(vmull_p64(vdup_n_p64((poly64_t)a), vdup_n_p64((poly64_t)b))); -#else - return vreinterpretq_u64_p128(vmull_p64((poly64_t)a, (poly64_t)b)); -#endif -} - -/* Compute x^n mod P (CRC-32 polynomial) in log(n) time, where P = 0x104c11db7 */ -static uint32_t xnmodp(uint64_t n) { - uint64_t stack = ~(uint64_t)1; - uint32_t acc, low; - for (; n > 191; n = (n >> 1) - 16) { - stack = (stack << 1) + (n & 1); - } - stack = ~stack; - acc = ((uint32_t)0x80000000) >> (n & 31); - for (n >>= 5; n; --n) { - acc = __crc32w(acc, 0); - } - while ((low = stack & 1), stack >>= 1) { - poly8x8_t x = vreinterpret_p8_u64(vmov_n_u64(acc)); - uint64_t y = vgetq_lane_u64(vreinterpretq_u64_p16(vmull_p8(x, x)), 0); - acc = __crc32d(0, y << low); - } - return acc; -} - -/* Shift CRC forward by nbytes: equivalent to appending nbytes of zeros to the data stream */ -static inline uint64x2_t crc_shift(uint32_t crc, size_t nbytes) { - Assert(nbytes >= 5, "crc_shift requires nbytes >= 5"); - return clmul_scalar(crc, xnmodp(nbytes * 8 - 33)); -} - -Z_FORCEINLINE static Z_TARGET_PMULL_EOR3 uint32_t crc32_copy_impl(uint32_t crc, uint8_t *dst, const uint8_t *src, - size_t len, const int COPY) { - uint32_t crc0 = ~crc; - - if (UNLIKELY(len == 1)) { - if (COPY) - *dst = *src; - crc0 = __crc32b(crc0, *src); - return ~crc0; - } - - /* Align to 16-byte boundary for vector path */ - uintptr_t align_diff = ALIGN_DIFF(src, 16); - if (align_diff) - crc0 = crc32_hw_align(crc0, &dst, &src, &len, align_diff, COPY); - - /* 3-way scalar CRC + 9-way PMULL folding (192 bytes/iter) */ - if (len >= 192) { - size_t blk = len / 192; /* Number of 192-byte blocks */ - size_t klen = blk * 16; /* Scalar stride per CRC lane */ - const uint8_t *end = src + len; - const uint8_t *src0 = src; - const uint8_t *src1 = src + klen; - const uint8_t *src2 = src + klen * 2; - const uint8_t *srcv = src + klen * 3; /* Vector data starts after scalar lanes */ - uint32_t crc1 = 0, crc2 = 0; - uint64x2_t vc0, vc1, vc2; - uint64_t vc; - - /* Load first 9 vector chunks (144 bytes) */ - uint64x2_t x0 = vld1q_u64_ex((const uint64_t*)srcv, 128), y0; - uint64x2_t x1 = vld1q_u64_ex((const uint64_t*)(srcv + 16), 128), y1; - uint64x2_t x2 = vld1q_u64_ex((const uint64_t*)(srcv + 32), 128), y2; - uint64x2_t x3 = vld1q_u64_ex((const uint64_t*)(srcv + 48), 128), y3; - uint64x2_t x4 = vld1q_u64_ex((const uint64_t*)(srcv + 64), 128), y4; - uint64x2_t x5 = vld1q_u64_ex((const uint64_t*)(srcv + 80), 128), y5; - uint64x2_t x6 = vld1q_u64_ex((const uint64_t*)(srcv + 96), 128), y6; - uint64x2_t x7 = vld1q_u64_ex((const uint64_t*)(srcv + 112), 128), y7; - uint64x2_t x8 = vld1q_u64_ex((const uint64_t*)(srcv + 128), 128), y8; - uint64x2_t k; - /* k = {x^144 mod P, x^144+64 mod P} for 144-byte fold */ - { static const uint64_t ALIGNED_(16) k_[] = {0x26b70c3d, 0x3f41287a}; k = vld1q_u64_ex(k_, 128); } - - /* Per-region dst pointers */ - uint8_t *dst0 = dst; - uint8_t *dst1 = NULL; - uint8_t *dst2 = NULL; - uint8_t *dst_v = NULL; - - if (COPY) { - dst1 = dst + klen; - dst2 = dst + klen * 2; - dst_v = dst + klen * 3; - vst1q_u8(dst_v, vreinterpretq_u8_u64(x0)); - vst1q_u8(dst_v + 16, vreinterpretq_u8_u64(x1)); - vst1q_u8(dst_v + 32, vreinterpretq_u8_u64(x2)); - vst1q_u8(dst_v + 48, vreinterpretq_u8_u64(x3)); - vst1q_u8(dst_v + 64, vreinterpretq_u8_u64(x4)); - vst1q_u8(dst_v + 80, vreinterpretq_u8_u64(x5)); - vst1q_u8(dst_v + 96, vreinterpretq_u8_u64(x6)); - vst1q_u8(dst_v + 112, vreinterpretq_u8_u64(x7)); - vst1q_u8(dst_v + 128, vreinterpretq_u8_u64(x8)); - dst_v += 144; - } - srcv += 144; - - /* Fold 9 vectors + 3-way parallel scalar CRC */ - if (blk > 1) { - /* Only form a limit pointer when we have at least 2 blocks. */ - const uint8_t *limit = src0 + klen - 32; - while (src0 <= limit) { - /* Fold all 9 vector lanes using PMULL */ - y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k); - y1 = clmul_lo(x1, k), x1 = clmul_hi(x1, k); - y2 = clmul_lo(x2, k), x2 = clmul_hi(x2, k); - y3 = clmul_lo(x3, k), x3 = clmul_hi(x3, k); - y4 = clmul_lo(x4, k), x4 = clmul_hi(x4, k); - y5 = clmul_lo(x5, k), x5 = clmul_hi(x5, k); - y6 = clmul_lo(x6, k), x6 = clmul_hi(x6, k); - y7 = clmul_lo(x7, k), x7 = clmul_hi(x7, k); - y8 = clmul_lo(x8, k), x8 = clmul_hi(x8, k); - - /* EOR3: combine hi*k, lo*k, and new data in one instruction */ - { - uint64x2_t d0 = vld1q_u64_ex((const uint64_t*)srcv, 128); - uint64x2_t d1 = vld1q_u64_ex((const uint64_t*)(srcv + 16), 128); - uint64x2_t d2 = vld1q_u64_ex((const uint64_t*)(srcv + 32), 128); - uint64x2_t d3 = vld1q_u64_ex((const uint64_t*)(srcv + 48), 128); - uint64x2_t d4 = vld1q_u64_ex((const uint64_t*)(srcv + 64), 128); - uint64x2_t d5 = vld1q_u64_ex((const uint64_t*)(srcv + 80), 128); - uint64x2_t d6 = vld1q_u64_ex((const uint64_t*)(srcv + 96), 128); - uint64x2_t d7 = vld1q_u64_ex((const uint64_t*)(srcv + 112), 128); - uint64x2_t d8 = vld1q_u64_ex((const uint64_t*)(srcv + 128), 128); - if (COPY) { - vst1q_u8(dst_v, vreinterpretq_u8_u64(d0)); - vst1q_u8(dst_v + 16, vreinterpretq_u8_u64(d1)); - vst1q_u8(dst_v + 32, vreinterpretq_u8_u64(d2)); - vst1q_u8(dst_v + 48, vreinterpretq_u8_u64(d3)); - vst1q_u8(dst_v + 64, vreinterpretq_u8_u64(d4)); - vst1q_u8(dst_v + 80, vreinterpretq_u8_u64(d5)); - vst1q_u8(dst_v + 96, vreinterpretq_u8_u64(d6)); - vst1q_u8(dst_v + 112, vreinterpretq_u8_u64(d7)); - vst1q_u8(dst_v + 128, vreinterpretq_u8_u64(d8)); - dst_v += 144; - } - x0 = veor3q_u64(x0, y0, d0); - x1 = veor3q_u64(x1, y1, d1); - x2 = veor3q_u64(x2, y2, d2); - x3 = veor3q_u64(x3, y3, d3); - x4 = veor3q_u64(x4, y4, d4); - x5 = veor3q_u64(x5, y5, d5); - x6 = veor3q_u64(x6, y6, d6); - x7 = veor3q_u64(x7, y7, d7); - x8 = veor3q_u64(x8, y8, d8); - } - - /* 3-way parallel scalar CRC (16 bytes each) */ - { - uint64_t s0a = *(const uint64_t*)src0; - uint64_t s0b = *(const uint64_t*)(src0 + 8); - uint64_t s1a = *(const uint64_t*)src1; - uint64_t s1b = *(const uint64_t*)(src1 + 8); - uint64_t s2a = *(const uint64_t*)src2; - uint64_t s2b = *(const uint64_t*)(src2 + 8); - if (COPY) { - memcpy(dst0, &s0a, 8); - memcpy(dst0 + 8, &s0b, 8); - dst0 += 16; - memcpy(dst1, &s1a, 8); - memcpy(dst1 + 8, &s1b, 8); - dst1 += 16; - memcpy(dst2, &s2a, 8); - memcpy(dst2 + 8, &s2b, 8); - dst2 += 16; - } - crc0 = __crc32d(crc0, s0a); - crc0 = __crc32d(crc0, s0b); - crc1 = __crc32d(crc1, s1a); - crc1 = __crc32d(crc1, s1b); - crc2 = __crc32d(crc2, s2a); - crc2 = __crc32d(crc2, s2b); - } - src0 += 16; - src1 += 16; - src2 += 16; - srcv += 144; - } - } - - /* Reduce 9 vectors to 1 using tree reduction */ - /* Step 1: x0 = fold(x0, x1), shift x2..x8 down */ - { static const uint64_t ALIGNED_(16) k_[] = {0xae689191, 0xccaa009e}; k = vld1q_u64_ex(k_, 128); } - y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k); - x0 = veor3q_u64(x0, y0, x1); - x1 = x2, x2 = x3, x3 = x4, x4 = x5, x5 = x6, x6 = x7, x7 = x8; - - /* Step 2: fold pairs (x0,x1), (x2,x3), (x4,x5), (x6,x7) */ - y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k); - y2 = clmul_lo(x2, k), x2 = clmul_hi(x2, k); - y4 = clmul_lo(x4, k), x4 = clmul_hi(x4, k); - y6 = clmul_lo(x6, k), x6 = clmul_hi(x6, k); - x0 = veor3q_u64(x0, y0, x1); - x2 = veor3q_u64(x2, y2, x3); - x4 = veor3q_u64(x4, y4, x5); - x6 = veor3q_u64(x6, y6, x7); - - /* Step 3: fold pairs (x0,x2), (x4,x6) */ - { static const uint64_t ALIGNED_(16) k_[] = {0xf1da05aa, 0x81256527}; k = vld1q_u64_ex(k_, 128); } - y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k); - y4 = clmul_lo(x4, k), x4 = clmul_hi(x4, k); - x0 = veor3q_u64(x0, y0, x2); - x4 = veor3q_u64(x4, y4, x6); - - /* Step 4: final fold (x0, x4) -> x0 */ - { static const uint64_t ALIGNED_(16) k_[] = {0x8f352d95, 0x1d9513d7}; k = vld1q_u64_ex(k_, 128); } - y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k); - x0 = veor3q_u64(x0, y0, x4); - - /* Process final scalar chunk */ - { - uint64_t s0a = *(const uint64_t*)src0; - uint64_t s0b = *(const uint64_t*)(src0 + 8); - uint64_t s1a = *(const uint64_t*)src1; - uint64_t s1b = *(const uint64_t*)(src1 + 8); - uint64_t s2a = *(const uint64_t*)src2; - uint64_t s2b = *(const uint64_t*)(src2 + 8); - if (COPY) { - memcpy(dst0, &s0a, 8); - memcpy(dst0 + 8, &s0b, 8); - memcpy(dst1, &s1a, 8); - memcpy(dst1 + 8, &s1b, 8); - memcpy(dst2, &s2a, 8); - memcpy(dst2 + 8, &s2b, 8); - } - crc0 = __crc32d(crc0, s0a); - crc0 = __crc32d(crc0, s0b); - crc1 = __crc32d(crc1, s1a); - crc1 = __crc32d(crc1, s1b); - crc2 = __crc32d(crc2, s2a); - crc2 = __crc32d(crc2, s2b); - } - - /* Shift and combine 3 scalar CRCs */ - vc0 = crc_shift(crc0, klen * 2 + blk * 144); - vc1 = crc_shift(crc1, klen + blk * 144); - vc2 = crc_shift(crc2, blk * 144); - vc = vgetq_lane_u64(veor3q_u64(vc0, vc1, vc2), 0); - - /* Final reduction: 128-bit vector + scalar CRCs -> 32-bit */ - crc0 = __crc32d(0, vgetq_lane_u64(x0, 0)); - crc0 = __crc32d(crc0, vc ^ vgetq_lane_u64(x0, 1)); - if (COPY) - dst += blk * 192; - src = srcv; - len = end - srcv; - } - - /* 3-way scalar CRC (24 bytes/iter) */ - if (len >= 80) { - size_t klen = ((len - 8) / 24) * 8; /* Stride for 3-way parallel */ - const uint8_t *buf0 = src; - const uint8_t *buf1 = src + klen; - const uint8_t *buf2 = src + klen * 2; - uint32_t crc1 = 0, crc2 = 0; - uint64x2_t vc0, vc1; - uint64_t vc; - - /* Per-lane dst pointers */ - uint8_t *dst0 = dst; - uint8_t *dst1 = NULL; - uint8_t *dst2 = NULL; - if (COPY) { - dst1 = dst + klen; - dst2 = dst + klen * 2; - } - - /* 3-way parallel scalar CRC */ - do { - uint64_t v0 = *(const uint64_t*)buf0; - uint64_t v1 = *(const uint64_t*)buf1; - uint64_t v2 = *(const uint64_t*)buf2; - if (COPY) { - memcpy(dst0, &v0, 8); - dst0 += 8; - memcpy(dst1, &v1, 8); - dst1 += 8; - memcpy(dst2, &v2, 8); - dst2 += 8; - } - crc0 = __crc32d(crc0, v0); - crc1 = __crc32d(crc1, v1); - crc2 = __crc32d(crc2, v2); - buf0 += 8; - buf1 += 8; - buf2 += 8; - len -= 24; - } while (len >= 32); - - /* Combine the 3 CRCs */ - vc0 = crc_shift(crc0, klen * 2 + 8); - vc1 = crc_shift(crc1, klen + 8); - vc = vgetq_lane_u64(veorq_u64(vc0, vc1), 0); - - /* Process final 8 bytes with combined CRC */ - crc0 = crc2; - { - uint64_t vf = *(const uint64_t*)buf2; - if (COPY) - memcpy(dst2, &vf, 8); - crc0 = __crc32d(crc0, vf ^ vc); - } - src = buf2 + 8; - len -= 8; - if (COPY) - dst = dst2 + 8; - } - - /* Process remaining bytes */ - return crc32_hw_tail(crc0, dst, src, len, COPY); -} - -Z_INTERNAL Z_TARGET_PMULL_EOR3 uint32_t crc32_armv8_pmull_eor3(uint32_t crc, const uint8_t *buf, size_t len) { - return crc32_copy_impl(crc, NULL, buf, len, 0); -} - -Z_INTERNAL Z_TARGET_PMULL_EOR3 uint32_t crc32_copy_armv8_pmull_eor3(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { -#if OPTIMAL_CMP >= 32 - return crc32_copy_impl(crc, dst, src, len, 1); -#else - /* Without unaligned access, interleaved stores get decomposed into byte ops */ - crc = crc32_armv8_pmull_eor3(crc, src, len); - memcpy(dst, src, len); - return crc; -#endif -} -#endif diff --git a/modules/zlib/src/arch/arm/neon_intrins.h b/modules/zlib/src/arch/arm/neon_intrins.h deleted file mode 100644 index 449916e0b7..0000000000 --- a/modules/zlib/src/arch/arm/neon_intrins.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef ARM_NEON_INTRINS_H -#define ARM_NEON_INTRINS_H - -#if defined(_MSC_VER) && defined(ARCH_ARM) && defined(ARCH_64BIT) -/* arm64_neon.h is MSVC specific */ -# include -#else -# include -#endif - -#if defined(ARM_NEON) && defined(ARCH_ARM) && defined(ARCH_32BIT) -/* Compatibility shim for the _high family of functions */ -#define vmull_high_u8(a, b) vmull_u8(vget_high_u8(a), vget_high_u8(b)) -#define vmlal_high_u8(a, b, c) vmlal_u8(a, vget_high_u8(b), vget_high_u8(c)) -#define vmlal_high_u16(a, b, c) vmlal_u16(a, vget_high_u16(b), vget_high_u16(c)) -#define vaddw_high_u8(a, b) vaddw_u8(a, vget_high_u8(b)) -#endif - -#ifdef ARM_NEON - -#define vqsubq_u16_x4_x1(out, a, b) do { \ - out.val[0] = vqsubq_u16(a.val[0], b); \ - out.val[1] = vqsubq_u16(a.val[1], b); \ - out.val[2] = vqsubq_u16(a.val[2], b); \ - out.val[3] = vqsubq_u16(a.val[3], b); \ -} while (0) - -# if defined(ARCH_ARM) && defined(ARCH_32BIT) && defined(__clang__) && \ - (!defined(__clang_major__) || __clang_major__ < 20) -/* Clang versions before 20 have too strict of an - * alignment requirement (:256) for x4 NEON intrinsics */ -# undef ARM_NEON_HASLD4 -# undef vld1q_u16_x4 -# undef vld1q_u8_x4 -# undef vst1q_u16_x4 -# endif - -# ifndef ARM_NEON_HASLD4 - -static inline uint16x8x4_t vld1q_u16_x4(uint16_t const *a) { - uint16x8x4_t ret; - ret.val[0] = vld1q_u16(a); - ret.val[1] = vld1q_u16(a+8); - ret.val[2] = vld1q_u16(a+16); - ret.val[3] = vld1q_u16(a+24); - return ret; -} - -static inline uint8x16x4_t vld1q_u8_x4(uint8_t const *a) { - uint8x16x4_t ret; - ret.val[0] = vld1q_u8(a); - ret.val[1] = vld1q_u8(a+16); - ret.val[2] = vld1q_u8(a+32); - ret.val[3] = vld1q_u8(a+48); - return ret; -} - -static inline void vst1q_u16_x4(uint16_t *p, uint16x8x4_t a) { - vst1q_u16(p, a.val[0]); - vst1q_u16(p + 8, a.val[1]); - vst1q_u16(p + 16, a.val[2]); - vst1q_u16(p + 24, a.val[3]); -} -# endif // HASLD4 check - -# ifndef _MSC_VER -# define vld1_u8_ex(p, align) vld1_u8(HINT_ALIGNED((p), (align)/8)) -# define vld1q_u8_ex(p, align) vld1q_u8(HINT_ALIGNED((p), (align)/8)) -# define vld1q_u64_ex(p, align) vld1q_u64(HINT_ALIGNED((p), (align)/8)) -# endif -# if !defined(_MSC_VER) || !defined(ARM_NEON_HASLD4) -# define vld1q_u8_x4_ex(p, align) vld1q_u8_x4(HINT_ALIGNED((p), (align)/8)) -# define vld1q_u16_x4_ex(p, align) vld1q_u16_x4(HINT_ALIGNED((p), (align)/8)) -# define vst1q_u16_x4_ex(p, a, align) vst1q_u16_x4(HINT_ALIGNED((p), (align)/8), a) -# endif - -#endif - -#endif // include guard ARM_NEON_INTRINS_H diff --git a/modules/zlib/src/arch/arm/slide_hash_armv6.c b/modules/zlib/src/arch/arm/slide_hash_armv6.c deleted file mode 100644 index b241e6c5e6..0000000000 --- a/modules/zlib/src/arch/arm/slide_hash_armv6.c +++ /dev/null @@ -1,49 +0,0 @@ -/* slide_hash_armv6.c -- Optimized hash table shifting for ARMv6 with support for SIMD instructions - * Copyright (C) 2023 Cameron Cawley - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef ARM_SIMD - -#include "zbuild.h" -#include "acle_intrins.h" -#include "deflate.h" - -/* SIMD version of hash_chain rebase */ -static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { - Z_REGISTER uint16x2_t v; - uint16x2_t p0, p1, p2, p3; - Z_REGISTER size_t n; - - size_t size = entries*sizeof(table[0]); - Assert((size % (sizeof(uint16x2_t) * 4) == 0), "hash table size err"); - - Assert(sizeof(Pos) == 2, "Wrong Pos size"); - v = wsize | (wsize << 16); - - n = size / (sizeof(uint16x2_t) * 4); - do { - p0 = *((const uint16x2_t *)(table)); - p1 = *((const uint16x2_t *)(table+2)); - p2 = *((const uint16x2_t *)(table+4)); - p3 = *((const uint16x2_t *)(table+6)); - p0 = __uqsub16(p0, v); - p1 = __uqsub16(p1, v); - p2 = __uqsub16(p2, v); - p3 = __uqsub16(p3, v); - *((uint16x2_t *)(table)) = p0; - *((uint16x2_t *)(table+2)) = p1; - *((uint16x2_t *)(table+4)) = p2; - *((uint16x2_t *)(table+6)) = p3; - table += 8; - } while (--n); -} - -Z_INTERNAL void slide_hash_armv6(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - - slide_hash_chain(s->head, HASH_SIZE, wsize); - slide_hash_chain(s->prev, wsize, wsize); -} -#endif diff --git a/modules/zlib/src/arch/arm/slide_hash_neon.c b/modules/zlib/src/arch/arm/slide_hash_neon.c deleted file mode 100644 index 2f9e94a33d..0000000000 --- a/modules/zlib/src/arch/arm/slide_hash_neon.c +++ /dev/null @@ -1,48 +0,0 @@ -/* slide_hash_neon.c -- Optimized hash table shifting for ARM with support for NEON instructions - * Copyright (C) 2017-2020 Mika T. Lindqvist - * - * Authors: - * Mika T. Lindqvist - * Jun He - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef ARM_NEON - -#include "zbuild.h" -#include "neon_intrins.h" -#include "deflate.h" - -/* SIMD version of hash_chain rebase */ -static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { - Z_REGISTER uint16x8_t v; - uint16x8x4_t p0, p1; - Z_REGISTER size_t n; - - size_t size = entries*sizeof(table[0]); - Assert((size % sizeof(uint16x8_t) * 8 == 0), "hash table size err"); - - Assert(sizeof(Pos) == 2, "Wrong Pos size"); - v = vdupq_n_u16(wsize); - - n = size / (sizeof(uint16x8_t) * 8); - do { - p0 = vld1q_u16_x4_ex(table, 256); - p1 = vld1q_u16_x4_ex(table+32, 256); - vqsubq_u16_x4_x1(p0, p0, v); - vqsubq_u16_x4_x1(p1, p1, v); - vst1q_u16_x4_ex(table, p0, 256); - vst1q_u16_x4_ex(table+32, p1, 256); - table += 64; - } while (--n); -} - -Z_INTERNAL void slide_hash_neon(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - - slide_hash_chain(s->head, HASH_SIZE, wsize); - slide_hash_chain(s->prev, wsize, wsize); -} -#endif diff --git a/modules/zlib/src/arch/generic/Makefile.in b/modules/zlib/src/arch/generic/Makefile.in deleted file mode 100644 index 1d9cc4df5b..0000000000 --- a/modules/zlib/src/arch/generic/Makefile.in +++ /dev/null @@ -1,68 +0,0 @@ -# Makefile for zlib-ng -# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler -# Copyright (C) 2024 Hans Kristian Rosbach -# For conditions of distribution and use, see copyright notice in zlib.h - -CC= -CFLAGS= -SFLAGS= -INCLUDES= - -SRCDIR=. -SRCTOP=../.. -TOPDIR=$(SRCTOP) - -all: \ - adler32_c.o adler32_c.lo \ - chunkset_c.o chunkset_c.lo \ - compare256_c.o compare256_c.lo \ - crc32_braid_c.o crc32_braid_c.lo \ - crc32_chorba_c.o crc32_chorba_c.lo \ - slide_hash_c.o slide_hash_c.lo - - -adler32_c.o: $(SRCDIR)/adler32_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/adler32_p.h - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_c.c - -adler32_c.lo: $(SRCDIR)/adler32_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/adler32_p.h - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_c.c - -chunkset_c.o: $(SRCDIR)/chunkset_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/chunkset_tpl.h $(SRCTOP)/inffast_tpl.h - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_c.c - -chunkset_c.lo: $(SRCDIR)/chunkset_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/chunkset_tpl.h $(SRCTOP)/inffast_tpl.h - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_c.c - -compare256_c.o: $(SRCDIR)/compare256_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/zendian.h $(SRCTOP)/zmemory.h $(SRCTOP)/deflate.h $(SRCTOP)/fallback_builtins.h - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_c.c - -compare256_c.lo: $(SRCDIR)/compare256_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/zendian.h $(SRCTOP)/zmemory.h $(SRCTOP)/deflate.h $(SRCTOP)/fallback_builtins.h - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_c.c - -crc32_braid_c.o: $(SRCDIR)/crc32_braid_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_braid_c.c - -crc32_braid_c.lo: $(SRCDIR)/crc32_braid_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_braid_c.c - -crc32_chorba_c.o: $(SRCDIR)/crc32_chorba_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_chorba_c.c - -crc32_chorba_c.lo: $(SRCDIR)/crc32_chorba_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_chorba_c.c - -slide_hash_c.o: $(SRCDIR)/slide_hash_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/deflate.h - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_c.c - -slide_hash_c.lo: $(SRCDIR)/slide_hash_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/deflate.h - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_c.c - - -mostlyclean: clean -clean: - rm -f *.o *.lo *~ - rm -rf objs - rm -f *.gcda *.gcno *.gcov - -distclean: clean - rm -f Makefile diff --git a/modules/zlib/src/arch/generic/adler32_c.c b/modules/zlib/src/arch/generic/adler32_c.c deleted file mode 100644 index 8abfcd2e60..0000000000 --- a/modules/zlib/src/arch/generic/adler32_c.c +++ /dev/null @@ -1,61 +0,0 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011, 2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "arch_functions.h" - -#ifdef ADLER32_FALLBACK - -#include "functable.h" -#include "adler32_p.h" - -Z_INTERNAL uint32_t adler32_c(uint32_t adler, const uint8_t *buf, size_t len) { - uint32_t sum2; - unsigned n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (UNLIKELY(len == 1)) - return adler32_copy_tail(adler, NULL, buf, 1, sum2, 1, 1, 0); - - /* in case short lengths are provided, keep it somewhat fast */ - if (UNLIKELY(len < 16)) - return adler32_copy_tail(adler, NULL, buf, len, sum2, 1, 15, 0); - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; -#ifdef UNROLL_MORE - n = NMAX / 16; /* NMAX is divisible by 16 */ -#else - n = NMAX / 8; /* NMAX is divisible by 8 */ -#endif - do { -#ifdef UNROLL_MORE - ADLER_DO16(adler, sum2, buf); /* 16 sums unrolled */ - buf += 16; -#else - ADLER_DO8(adler, sum2, buf, 0); /* 8 sums unrolled */ - buf += 8; -#endif - } while (--n); - adler %= BASE; - sum2 %= BASE; - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - return adler32_copy_tail(adler, NULL, buf, len, sum2, len != 0, NMAX - 1, 0); -} - -Z_INTERNAL uint32_t adler32_copy_c(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - adler = FUNCTABLE_CALL(adler32)(adler, src, len); - memcpy(dst, src, len); - return adler; -} - -#endif /* ADLER32_FALLBACK */ diff --git a/modules/zlib/src/arch/generic/chunkset_c.c b/modules/zlib/src/arch/generic/chunkset_c.c deleted file mode 100644 index 5cc66977e2..0000000000 --- a/modules/zlib/src/arch/generic/chunkset_c.c +++ /dev/null @@ -1,46 +0,0 @@ -/* chunkset.c -- inline functions to copy small data chunks. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "arch_functions.h" - -#ifdef CHUNKSET_FALLBACK - -#include "zmemory.h" - -typedef uint64_t chunk_t; - -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - uint32_t tmp = zng_memread_4(from); - *chunk = tmp | ((chunk_t)tmp << 32); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = zng_memread_8(from); -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = zng_memread_8(s); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - zng_memwrite_8(out, *chunk); -} - -#define CHUNKSIZE chunksize_c -#define CHUNKCOPY chunkcopy_c -#define CHUNKUNROLL chunkunroll_c -#define CHUNKMEMSET chunkmemset_c -#define CHUNKMEMSET_SAFE chunkmemset_safe_c - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_c - -#include "inffast_tpl.h" - -#endif /* CHUNKSET_FALLBACK */ diff --git a/modules/zlib/src/arch/generic/compare256_c.c b/modules/zlib/src/arch/generic/compare256_c.c deleted file mode 100644 index da8b97112b..0000000000 --- a/modules/zlib/src/arch/generic/compare256_c.c +++ /dev/null @@ -1,92 +0,0 @@ -/* compare256.c -- 256 byte memory comparison with match length return - * Copyright (C) 2020 Nathan Moinvaziri - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "arch_functions.h" - -#ifdef COMPARE256_FALLBACK - -#include "zendian.h" -#include "deflate.h" -#include "fallback_builtins.h" - -/* 8-bit integer comparison for hardware without unaligned loads */ -static inline uint32_t compare256_8_static(const uint8_t *src0, const uint8_t *src1) { - uint32_t len = 0; - - do { - if (src0[0] != src1[0]) - return len; - if (src0[1] != src1[1]) - return len + 1; - if (src0[2] != src1[2]) - return len + 2; - if (src0[3] != src1[3]) - return len + 3; - if (src0[4] != src1[4]) - return len + 4; - if (src0[5] != src1[5]) - return len + 5; - if (src0[6] != src1[6]) - return len + 6; - if (src0[7] != src1[7]) - return len + 7; - src0 += 8, src1 += 8, len += 8; - } while (len < 256); - - return 256; -} - -/* 64-bit integer comparison for hardware with unaligned loads */ -static inline uint32_t compare256_64_static(const uint8_t *src0, const uint8_t *src1) { - uint32_t len = 0; - - do { - uint64_t sv = zng_memread_8(src0); - uint64_t mv = zng_memread_8(src1); - uint64_t diff = sv ^ mv; - if (diff) - return len + zng_first_diff_byte64(diff); - src0 += 8, src1 += 8, len += 8; - - sv = zng_memread_8(src0); - mv = zng_memread_8(src1); - diff = sv ^ mv; - if (diff) - return len + zng_first_diff_byte64(diff); - src0 += 8, src1 += 8, len += 8; - } while (len < 256); - - return 256; -} - -#if OPTIMAL_CMP == 8 -# define COMPARE256 compare256_8_static -#else -# define COMPARE256 compare256_64_static -#endif - -Z_INTERNAL uint32_t compare256_8(const uint8_t *src0, const uint8_t *src1) { - return compare256_8_static(src0, src1); -} - -Z_INTERNAL uint32_t compare256_64(const uint8_t *src0, const uint8_t *src1) { - return compare256_64_static(src0, src1); -} - -Z_INTERNAL uint32_t compare256_c(const uint8_t *src0, const uint8_t *src1) { - return COMPARE256(src0, src1); -} - -// Generate longest_match_c -#define LONGEST_MATCH longest_match_c -#include "match_tpl.h" - -// Generate longest_match_roll_c -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_c -#include "match_tpl.h" - -#endif /* COMPARE256_FALLBACK */ diff --git a/modules/zlib/src/arch/generic/crc32_braid_c.c b/modules/zlib/src/arch/generic/crc32_braid_c.c deleted file mode 100644 index 1e83543d13..0000000000 --- a/modules/zlib/src/arch/generic/crc32_braid_c.c +++ /dev/null @@ -1,220 +0,0 @@ -/* crc32_braid.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2022 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * This interleaved implementation of a CRC makes use of pipelined multiple - * arithmetic-logic units, commonly found in modern CPU cores. It is due to - * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. - */ - -#include "zbuild.h" -#include "arch_functions.h" - -/* Used by chorba fallback and by arch-specific implementations (s390 vx, risc-v zbc). */ -#ifdef CRC32_BRAID_FALLBACK - -#include "crc32_braid_p.h" -#include "crc32_braid_tbl.h" -#include "crc32_p.h" - -/* - A CRC of a message is computed on BRAID_N braids of words in the message, where - each word consists of BRAID_W bytes (4 or 8). If BRAID_N is 3, for example, then - three running sparse CRCs are calculated respectively on each braid, at these - indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... - This is done starting at a word boundary, and continues until as many blocks of - BRAID_N * BRAID_W bytes as are available have been processed. The results are - combined into a single CRC at the end. For this code, BRAID_N must be in the - range 1..6 and BRAID_W must be 4 or 8. The upper limit on BRAID_N can be increased - if desired by adding more #if blocks, extending the patterns apparent in the code. - In addition, crc32 tables would need to be regenerated, if the maximum BRAID_N - value is increased. - - BRAID_N and BRAID_W are chosen empirically by benchmarking the execution time - on a given processor. The choices for BRAID_N and BRAID_W below were based on - testing on Intel Kaby Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC - POWER9, and MIPS64 Octeon II processors. - The Intel, AMD, and ARM processors were all fastest with BRAID_N=5, BRAID_W=8. - The Sparc, PowerPC, and MIPS64 were all fastest at BRAID_N=5, BRAID_W=4. - They were all tested with either gcc or clang, all using the -O3 optimization - level. Your mileage may vary. -*/ - -/* ========================================================================= */ -#ifdef BRAID_W -/* - Return the CRC of the BRAID_W bytes in the word_t data, taking the - least-significant byte of the word as the first byte of data, without any pre - or post conditioning. This is used to combine the CRCs of each braid. - */ -# if BYTE_ORDER == LITTLE_ENDIAN -static uint32_t crc_word(z_word_t data) { - int k; - for (k = 0; k < BRAID_W; k++) - data = (data >> 8) ^ crc_table[data & 0xff]; - return (uint32_t)data; -} -# elif BYTE_ORDER == BIG_ENDIAN -static z_word_t crc_word(z_word_t data) { - int k; - for (k = 0; k < BRAID_W; k++) - data = (data << 8) ^ - crc_big_table[(data >> ((BRAID_W - 1) << 3)) & 0xff]; - return data; -} -# endif /* BYTE_ORDER */ -#endif /* BRAID_W */ - -/* ========================================================================= */ -Z_INTERNAL uint32_t crc32_braid(uint32_t crc, const uint8_t *buf, size_t len) { - crc = ~crc; - -#ifdef BRAID_W - /* If provided enough bytes, do a braided CRC calculation. */ - if (len >= BRAID_N * BRAID_W + BRAID_W - 1) { - size_t blks; - z_word_t const *words; - int k; - - /* Compute the CRC up to a z_word_t boundary. */ - size_t align_diff = (size_t)MIN(ALIGN_DIFF(buf, BRAID_W), len); - if (align_diff) { - crc = crc32_copy_small(crc, NULL, buf, align_diff, BRAID_W - 1, 0); - len -= align_diff; - buf += align_diff; - } - - /* Compute the CRC on as many BRAID_N z_word_t blocks as are available. */ - blks = len / (BRAID_N * BRAID_W); - len -= blks * BRAID_N * BRAID_W; - words = (z_word_t const *)buf; - - z_word_t crc0, word0, comb; -#if BRAID_N > 1 - z_word_t crc1, word1; -#if BRAID_N > 2 - z_word_t crc2, word2; -#if BRAID_N > 3 - z_word_t crc3, word3; -#if BRAID_N > 4 - z_word_t crc4, word4; -#if BRAID_N > 5 - z_word_t crc5, word5; -#endif -#endif -#endif -#endif -#endif - /* Initialize the CRC for each braid. */ - crc0 = Z_WORD_FROM_LE(crc); -#if BRAID_N > 1 - crc1 = 0; -#if BRAID_N > 2 - crc2 = 0; -#if BRAID_N > 3 - crc3 = 0; -#if BRAID_N > 4 - crc4 = 0; -#if BRAID_N > 5 - crc5 = 0; -#endif -#endif -#endif -#endif -#endif - /* Process the first blks-1 blocks, computing the CRCs on each braid independently. */ - while (--blks) { - /* Load the word for each braid into registers. */ - word0 = crc0 ^ words[0]; -#if BRAID_N > 1 - word1 = crc1 ^ words[1]; -#if BRAID_N > 2 - word2 = crc2 ^ words[2]; -#if BRAID_N > 3 - word3 = crc3 ^ words[3]; -#if BRAID_N > 4 - word4 = crc4 ^ words[4]; -#if BRAID_N > 5 - word5 = crc5 ^ words[5]; -#endif -#endif -#endif -#endif -#endif - words += BRAID_N; - - /* Compute and update the CRC for each word. The loop should get unrolled. */ - crc0 = BRAID_TABLE[0][word0 & 0xff]; -#if BRAID_N > 1 - crc1 = BRAID_TABLE[0][word1 & 0xff]; -#if BRAID_N > 2 - crc2 = BRAID_TABLE[0][word2 & 0xff]; -#if BRAID_N > 3 - crc3 = BRAID_TABLE[0][word3 & 0xff]; -#if BRAID_N > 4 - crc4 = BRAID_TABLE[0][word4 & 0xff]; -#if BRAID_N > 5 - crc5 = BRAID_TABLE[0][word5 & 0xff]; -#endif -#endif -#endif -#endif -#endif - for (k = 1; k < BRAID_W; k++) { - crc0 ^= BRAID_TABLE[k][(word0 >> (k << 3)) & 0xff]; -#if BRAID_N > 1 - crc1 ^= BRAID_TABLE[k][(word1 >> (k << 3)) & 0xff]; -#if BRAID_N > 2 - crc2 ^= BRAID_TABLE[k][(word2 >> (k << 3)) & 0xff]; -#if BRAID_N > 3 - crc3 ^= BRAID_TABLE[k][(word3 >> (k << 3)) & 0xff]; -#if BRAID_N > 4 - crc4 ^= BRAID_TABLE[k][(word4 >> (k << 3)) & 0xff]; -#if BRAID_N > 5 - crc5 ^= BRAID_TABLE[k][(word5 >> (k << 3)) & 0xff]; -#endif -#endif -#endif -#endif -#endif - } - } - - /* Process the last block, combining the CRCs of the BRAID_N braids at the same time. */ - comb = crc_word(crc0 ^ words[0]); -#if BRAID_N > 1 - comb = crc_word(crc1 ^ words[1] ^ comb); -#if BRAID_N > 2 - comb = crc_word(crc2 ^ words[2] ^ comb); -#if BRAID_N > 3 - comb = crc_word(crc3 ^ words[3] ^ comb); -#if BRAID_N > 4 - comb = crc_word(crc4 ^ words[4] ^ comb); -#if BRAID_N > 5 - comb = crc_word(crc5 ^ words[5] ^ comb); -#endif -#endif -#endif -#endif -#endif - words += BRAID_N; - Assert(comb <= UINT32_MAX, "comb should fit in uint32_t"); - crc = (uint32_t)Z_WORD_FROM_LE(comb); - - /* Update the pointer to the remaining bytes to process. */ - buf = (const unsigned char *)words; - } - -#endif /* BRAID_W */ - - /* Complete the computation of the CRC on any remaining bytes. */ - return ~crc32_copy_small(crc, NULL, buf, len, (BRAID_N * BRAID_W) - 1, 0); -} - -Z_INTERNAL uint32_t crc32_copy_braid(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - crc = crc32_braid(crc, src, len); - memcpy(dst, src, len); - return crc; -} - -#endif /* CRC32_BRAID_FALLBACK */ diff --git a/modules/zlib/src/arch/generic/crc32_chorba_c.c b/modules/zlib/src/arch/generic/crc32_chorba_c.c deleted file mode 100644 index ded968a8aa..0000000000 --- a/modules/zlib/src/arch/generic/crc32_chorba_c.c +++ /dev/null @@ -1,1038 +0,0 @@ -#include "zbuild.h" -#include "arch_functions.h" - -#ifdef CRC32_CHORBA_FALLBACK - -#if defined(__EMSCRIPTEN__) -# include "zutil_p.h" -#endif -#include "zmemory.h" -#include "crc32_chorba_p.h" -#include "crc32_braid_p.h" -#include "crc32_braid_tbl.h" - -/* Implement Chorba algorithm from https://arxiv.org/abs/2412.16398 */ -#define bitbuffer_size_bytes (16 * 1024 * sizeof(chorba_word_t)) -#define bitbuffer_size_zwords (bitbuffer_size_bytes / sizeof(chorba_word_t)) -#define bitbuffer_size_qwords (bitbuffer_size_bytes / sizeof(uint64_t)) - -#if defined(HAVE_MAY_ALIAS) - typedef chorba_word_t __attribute__ ((__may_alias__)) chorba_worda_t; - typedef uint64_t __attribute__ ((__may_alias__)) uint64a_t; -#else - typedef chorba_word_t chorba_worda_t; - typedef uint64_t uint64a_t; -#endif - -#define NEXT_ROUND(invec, a, b, c, d) \ - do { \ - a = ((invec) << 17) ^ ((invec) << 55); \ - b = ((invec) >> 47) ^ ((invec) >> 9) ^ ((invec) << 19); \ - c = ((invec) >> 45) ^ ((invec) << 44); \ - d = (invec) >> 20; \ - } while (0) - -#define ACCUM_ROUND(n1, n2, n3, n4, n5) \ - do { \ - n1 = n5 ^ (a3 ^ b2 ^ c1); \ - n2 = a4 ^ b3 ^ c2 ^ d1; \ - n3 = b4 ^ c3 ^ d2; \ - n4 = c4 ^ d3; \ - n5 = d4; \ - } while (0) - -/** - * Implements the Chorba algorithm for CRC32 computation (https://arxiv.org/abs/2412.16398). - * - * This implementation processes data in three phases: - * 1. Initial pass: Zeros out bitbuffer - * 2. Intermediate pass: Processes half the values - * 3. Main pass: Processes remaining data - * - * @param crc Initial CRC value - * @param input Input data buffer - * @param len Length of input data - * @return Computed CRC32 value - * - * @note Requires minimum input size of 118960 + 512 bytes - * @note Uses 128KB temporary buffer - */ -Z_INTERNAL uint32_t crc32_chorba_118960_nondestructive(uint32_t crc, const uint8_t *buf, size_t len) { -#if defined(__EMSCRIPTEN__) - chorba_worda_t *bitbuffer = (chorba_worda_t*)zng_alloc(bitbuffer_size_bytes); -#else - ALIGNED_(16) chorba_worda_t bitbuffer[bitbuffer_size_zwords]; -#endif - const uint8_t *bitbuffer_bytes = (const uint8_t*)bitbuffer; - uint64a_t *bitbuffer_qwords = (uint64a_t*)bitbuffer; - /* The calling function ensured that this is aligned correctly */ - const chorba_worda_t* input = (const chorba_worda_t*)buf; - const uint64a_t* input_qwords = (const uint64a_t*)buf; - - size_t i = 0; - - chorba_word_t next1 = CHORBA_WORD_FROM_LE(~crc); - - chorba_word_t next2 = 0; - chorba_word_t next3 = 0; - chorba_word_t next4 = 0; - chorba_word_t next5 = 0; - chorba_word_t next6 = 0; - chorba_word_t next7 = 0; - chorba_word_t next8 = 0; - chorba_word_t next9 = 0; - chorba_word_t next10 = 0; - chorba_word_t next11 = 0; - chorba_word_t next12 = 0; - chorba_word_t next13 = 0; - chorba_word_t next14 = 0; - chorba_word_t next15 = 0; - chorba_word_t next16 = 0; - chorba_word_t next17 = 0; - chorba_word_t next18 = 0; - chorba_word_t next19 = 0; - chorba_word_t next20 = 0; - chorba_word_t next21 = 0; - chorba_word_t next22 = 0; - crc = 0; - - // do a first pass to zero out bitbuffer - for (; i < (14848 * sizeof(chorba_word_t)); i += (32 * sizeof(chorba_word_t))) { - chorba_word_t in1, in2, in3, in4, in5, in6, in7, in8; - chorba_word_t in9, in10, in11, in12, in13, in14, in15, in16; - chorba_word_t in17, in18, in19, in20, in21, in22, in23, in24; - chorba_word_t in25, in26, in27, in28, in29, in30, in31, in32; - int out_offset1 = ((i / sizeof(chorba_word_t)) + 14848) % bitbuffer_size_zwords; - int out_offset2 = ((i / sizeof(chorba_word_t)) + 14880) % bitbuffer_size_zwords; - - in1 = input[i / sizeof(chorba_word_t) + 0] ^ next1; - in2 = input[i / sizeof(chorba_word_t) + 1] ^ next2; - in3 = input[i / sizeof(chorba_word_t) + 2] ^ next3; - in4 = input[i / sizeof(chorba_word_t) + 3] ^ next4; - in5 = input[i / sizeof(chorba_word_t) + 4] ^ next5; - in6 = input[i / sizeof(chorba_word_t) + 5] ^ next6; - in7 = input[i / sizeof(chorba_word_t) + 6] ^ next7; - in8 = input[i / sizeof(chorba_word_t) + 7] ^ next8 ^ in1; - in9 = input[i / sizeof(chorba_word_t) + 8] ^ next9 ^ in2; - in10 = input[i / sizeof(chorba_word_t) + 9] ^ next10 ^ in3; - in11 = input[i / sizeof(chorba_word_t) + 10] ^ next11 ^ in4; - in12 = input[i / sizeof(chorba_word_t) + 11] ^ next12 ^ in1 ^ in5; - in13 = input[i / sizeof(chorba_word_t) + 12] ^ next13 ^ in2 ^ in6; - in14 = input[i / sizeof(chorba_word_t) + 13] ^ next14 ^ in3 ^ in7; - in15 = input[i / sizeof(chorba_word_t) + 14] ^ next15 ^ in4 ^ in8; - in16 = input[i / sizeof(chorba_word_t) + 15] ^ next16 ^ in5 ^ in9; - in17 = input[i / sizeof(chorba_word_t) + 16] ^ next17 ^ in6 ^ in10; - in18 = input[i / sizeof(chorba_word_t) + 17] ^ next18 ^ in7 ^ in11; - in19 = input[i / sizeof(chorba_word_t) + 18] ^ next19 ^ in8 ^ in12; - in20 = input[i / sizeof(chorba_word_t) + 19] ^ next20 ^ in9 ^ in13; - in21 = input[i / sizeof(chorba_word_t) + 20] ^ next21 ^ in10 ^ in14; - in22 = input[i / sizeof(chorba_word_t) + 21] ^ next22 ^ in11 ^ in15; - in23 = input[i / sizeof(chorba_word_t) + 22] ^ in1 ^ in12 ^ in16; - in24 = input[i / sizeof(chorba_word_t) + 23] ^ in2 ^ in13 ^ in17; - in25 = input[i / sizeof(chorba_word_t) + 24] ^ in3 ^ in14 ^ in18; - in26 = input[i / sizeof(chorba_word_t) + 25] ^ in4 ^ in15 ^ in19; - in27 = input[i / sizeof(chorba_word_t) + 26] ^ in5 ^ in16 ^ in20; - in28 = input[i / sizeof(chorba_word_t) + 27] ^ in6 ^ in17 ^ in21; - in29 = input[i / sizeof(chorba_word_t) + 28] ^ in7 ^ in18 ^ in22; - in30 = input[i / sizeof(chorba_word_t) + 29] ^ in8 ^ in19 ^ in23; - in31 = input[i / sizeof(chorba_word_t) + 30] ^ in9 ^ in20 ^ in24; - in32 = input[i / sizeof(chorba_word_t) + 31] ^ in10 ^ in21 ^ in25; - - next1 = in11 ^ in22 ^ in26; - next2 = in12 ^ in23 ^ in27; - next3 = in13 ^ in24 ^ in28; - next4 = in14 ^ in25 ^ in29; - next5 = in15 ^ in26 ^ in30; - next6 = in16 ^ in27 ^ in31; - next7 = in17 ^ in28 ^ in32; - next8 = in18 ^ in29; - next9 = in19 ^ in30; - next10 = in20 ^ in31; - next11 = in21 ^ in32; - next12 = in22; - next13 = in23; - next14 = in24; - next15 = in25; - next16 = in26; - next17 = in27; - next18 = in28; - next19 = in29; - next20 = in30; - next21 = in31; - next22 = in32; - - bitbuffer[out_offset1 + 22] = in1; - bitbuffer[out_offset1 + 23] = in2; - bitbuffer[out_offset1 + 24] = in3; - bitbuffer[out_offset1 + 25] = in4; - bitbuffer[out_offset1 + 26] = in5; - bitbuffer[out_offset1 + 27] = in6; - bitbuffer[out_offset1 + 28] = in7; - bitbuffer[out_offset1 + 29] = in8; - bitbuffer[out_offset1 + 30] = in9; - bitbuffer[out_offset1 + 31] = in10; - bitbuffer[out_offset2 + 0] = in11; - bitbuffer[out_offset2 + 1] = in12; - bitbuffer[out_offset2 + 2] = in13; - bitbuffer[out_offset2 + 3] = in14; - bitbuffer[out_offset2 + 4] = in15; - bitbuffer[out_offset2 + 5] = in16; - bitbuffer[out_offset2 + 6] = in17; - bitbuffer[out_offset2 + 7] = in18; - bitbuffer[out_offset2 + 8] = in19; - bitbuffer[out_offset2 + 9] = in20; - bitbuffer[out_offset2 + 10] = in21; - bitbuffer[out_offset2 + 11] = in22; - bitbuffer[out_offset2 + 12] = in23; - bitbuffer[out_offset2 + 13] = in24; - bitbuffer[out_offset2 + 14] = in25; - bitbuffer[out_offset2 + 15] = in26; - bitbuffer[out_offset2 + 16] = in27; - bitbuffer[out_offset2 + 17] = in28; - bitbuffer[out_offset2 + 18] = in29; - bitbuffer[out_offset2 + 19] = in30; - bitbuffer[out_offset2 + 20] = in31; - bitbuffer[out_offset2 + 21] = in32; - } - - // one intermediate pass where we pull half the values - for (; i < (14880 * sizeof(chorba_word_t)); i += (32 * sizeof(chorba_word_t))) { - chorba_word_t in1, in2, in3, in4, in5, in6, in7, in8; - chorba_word_t in9, in10, in11, in12, in13, in14, in15, in16; - chorba_word_t in17, in18, in19, in20, in21, in22, in23, in24; - chorba_word_t in25, in26, in27, in28, in29, in30, in31, in32; - int in_offset = (i / sizeof(chorba_word_t)) % bitbuffer_size_zwords; - int out_offset1 = ((i / sizeof(chorba_word_t)) + 14848) % bitbuffer_size_zwords; - int out_offset2 = ((i / sizeof(chorba_word_t)) + 14880) % bitbuffer_size_zwords; - - in1 = input[i / sizeof(chorba_word_t) + 0] ^ next1; - in2 = input[i / sizeof(chorba_word_t) + 1] ^ next2; - in3 = input[i / sizeof(chorba_word_t) + 2] ^ next3; - in4 = input[i / sizeof(chorba_word_t) + 3] ^ next4; - in5 = input[i / sizeof(chorba_word_t) + 4] ^ next5; - in6 = input[i / sizeof(chorba_word_t) + 5] ^ next6; - in7 = input[i / sizeof(chorba_word_t) + 6] ^ next7; - in8 = input[i / sizeof(chorba_word_t) + 7] ^ next8 ^ in1; - in9 = input[i / sizeof(chorba_word_t) + 8] ^ next9 ^ in2; - in10 = input[i / sizeof(chorba_word_t) + 9] ^ next10 ^ in3; - in11 = input[i / sizeof(chorba_word_t) + 10] ^ next11 ^ in4; - in12 = input[i / sizeof(chorba_word_t) + 11] ^ next12 ^ in1 ^ in5; - in13 = input[i / sizeof(chorba_word_t) + 12] ^ next13 ^ in2 ^ in6; - in14 = input[i / sizeof(chorba_word_t) + 13] ^ next14 ^ in3 ^ in7; - in15 = input[i / sizeof(chorba_word_t) + 14] ^ next15 ^ in4 ^ in8; - in16 = input[i / sizeof(chorba_word_t) + 15] ^ next16 ^ in5 ^ in9; - in17 = input[i / sizeof(chorba_word_t) + 16] ^ next17 ^ in6 ^ in10; - in18 = input[i / sizeof(chorba_word_t) + 17] ^ next18 ^ in7 ^ in11; - in19 = input[i / sizeof(chorba_word_t) + 18] ^ next19 ^ in8 ^ in12; - in20 = input[i / sizeof(chorba_word_t) + 19] ^ next20 ^ in9 ^ in13; - in21 = input[i / sizeof(chorba_word_t) + 20] ^ next21 ^ in10 ^ in14; - in22 = input[i / sizeof(chorba_word_t) + 21] ^ next22 ^ in11 ^ in15; - in23 = input[i / sizeof(chorba_word_t) + 22] ^ in1 ^ in12 ^ in16 ^ bitbuffer[in_offset + 22]; - in24 = input[i / sizeof(chorba_word_t) + 23] ^ in2 ^ in13 ^ in17 ^ bitbuffer[in_offset + 23]; - in25 = input[i / sizeof(chorba_word_t) + 24] ^ in3 ^ in14 ^ in18 ^ bitbuffer[in_offset + 24]; - in26 = input[i / sizeof(chorba_word_t) + 25] ^ in4 ^ in15 ^ in19 ^ bitbuffer[in_offset + 25]; - in27 = input[i / sizeof(chorba_word_t) + 26] ^ in5 ^ in16 ^ in20 ^ bitbuffer[in_offset + 26]; - in28 = input[i / sizeof(chorba_word_t) + 27] ^ in6 ^ in17 ^ in21 ^ bitbuffer[in_offset + 27]; - in29 = input[i / sizeof(chorba_word_t) + 28] ^ in7 ^ in18 ^ in22 ^ bitbuffer[in_offset + 28]; - in30 = input[i / sizeof(chorba_word_t) + 29] ^ in8 ^ in19 ^ in23 ^ bitbuffer[in_offset + 29]; - in31 = input[i / sizeof(chorba_word_t) + 30] ^ in9 ^ in20 ^ in24 ^ bitbuffer[in_offset + 30]; - in32 = input[i / sizeof(chorba_word_t) + 31] ^ in10 ^ in21 ^ in25 ^ bitbuffer[in_offset + 31]; - - next1 = in11 ^ in22 ^ in26; - next2 = in12 ^ in23 ^ in27; - next3 = in13 ^ in24 ^ in28; - next4 = in14 ^ in25 ^ in29; - next5 = in15 ^ in26 ^ in30; - next6 = in16 ^ in27 ^ in31; - next7 = in17 ^ in28 ^ in32; - next8 = in18 ^ in29; - next9 = in19 ^ in30; - next10 = in20 ^ in31; - next11 = in21 ^ in32; - next12 = in22; - next13 = in23; - next14 = in24; - next15 = in25; - next16 = in26; - next17 = in27; - next18 = in28; - next19 = in29; - next20 = in30; - next21 = in31; - next22 = in32; - - bitbuffer[out_offset1 + 22] = in1; - bitbuffer[out_offset1 + 23] = in2; - bitbuffer[out_offset1 + 24] = in3; - bitbuffer[out_offset1 + 25] = in4; - bitbuffer[out_offset1 + 26] = in5; - bitbuffer[out_offset1 + 27] = in6; - bitbuffer[out_offset1 + 28] = in7; - bitbuffer[out_offset1 + 29] = in8; - bitbuffer[out_offset1 + 30] = in9; - bitbuffer[out_offset1 + 31] = in10; - bitbuffer[out_offset2 + 0] = in11; - bitbuffer[out_offset2 + 1] = in12; - bitbuffer[out_offset2 + 2] = in13; - bitbuffer[out_offset2 + 3] = in14; - bitbuffer[out_offset2 + 4] = in15; - bitbuffer[out_offset2 + 5] = in16; - bitbuffer[out_offset2 + 6] = in17; - bitbuffer[out_offset2 + 7] = in18; - bitbuffer[out_offset2 + 8] = in19; - bitbuffer[out_offset2 + 9] = in20; - bitbuffer[out_offset2 + 10] = in21; - bitbuffer[out_offset2 + 11] = in22; - bitbuffer[out_offset2 + 12] = in23; - bitbuffer[out_offset2 + 13] = in24; - bitbuffer[out_offset2 + 14] = in25; - bitbuffer[out_offset2 + 15] = in26; - bitbuffer[out_offset2 + 16] = in27; - bitbuffer[out_offset2 + 17] = in28; - bitbuffer[out_offset2 + 18] = in29; - bitbuffer[out_offset2 + 19] = in30; - bitbuffer[out_offset2 + 20] = in31; - bitbuffer[out_offset2 + 21] = in32; - } - - for (; (i + (14870 + 64) * sizeof(chorba_word_t)) < len; i += (32 * sizeof(chorba_word_t))) { - chorba_word_t in1, in2, in3, in4, in5, in6, in7, in8; - chorba_word_t in9, in10, in11, in12, in13, in14, in15, in16; - chorba_word_t in17, in18, in19, in20, in21, in22, in23, in24; - chorba_word_t in25, in26, in27, in28, in29, in30, in31, in32; - int in_offset = (i / sizeof(chorba_word_t)) % bitbuffer_size_zwords; - int out_offset1 = ((i / sizeof(chorba_word_t)) + 14848) % bitbuffer_size_zwords; - int out_offset2 = ((i / sizeof(chorba_word_t)) + 14880) % bitbuffer_size_zwords; - - in1 = input[i / sizeof(chorba_word_t) + 0] ^ next1 ^ bitbuffer[in_offset + 0]; - in2 = input[i / sizeof(chorba_word_t) + 1] ^ next2 ^ bitbuffer[in_offset + 1]; - in3 = input[i / sizeof(chorba_word_t) + 2] ^ next3 ^ bitbuffer[in_offset + 2]; - in4 = input[i / sizeof(chorba_word_t) + 3] ^ next4 ^ bitbuffer[in_offset + 3]; - in5 = input[i / sizeof(chorba_word_t) + 4] ^ next5 ^ bitbuffer[in_offset + 4]; - in6 = input[i / sizeof(chorba_word_t) + 5] ^ next6 ^ bitbuffer[in_offset + 5]; - in7 = input[i / sizeof(chorba_word_t) + 6] ^ next7 ^ bitbuffer[in_offset + 6]; - in8 = input[i / sizeof(chorba_word_t) + 7] ^ next8 ^ in1 ^ bitbuffer[in_offset + 7]; - in9 = input[i / sizeof(chorba_word_t) + 8] ^ next9 ^ in2 ^ bitbuffer[in_offset + 8]; - in10 = input[i / sizeof(chorba_word_t) + 9] ^ next10 ^ in3 ^ bitbuffer[in_offset + 9]; - in11 = input[i / sizeof(chorba_word_t) + 10] ^ next11 ^ in4 ^ bitbuffer[in_offset + 10]; - in12 = input[i / sizeof(chorba_word_t) + 11] ^ next12 ^ in1 ^ in5 ^ bitbuffer[in_offset + 11]; - in13 = input[i / sizeof(chorba_word_t) + 12] ^ next13 ^ in2 ^ in6 ^ bitbuffer[in_offset + 12]; - in14 = input[i / sizeof(chorba_word_t) + 13] ^ next14 ^ in3 ^ in7 ^ bitbuffer[in_offset + 13]; - in15 = input[i / sizeof(chorba_word_t) + 14] ^ next15 ^ in4 ^ in8 ^ bitbuffer[in_offset + 14]; - in16 = input[i / sizeof(chorba_word_t) + 15] ^ next16 ^ in5 ^ in9 ^ bitbuffer[in_offset + 15]; - in17 = input[i / sizeof(chorba_word_t) + 16] ^ next17 ^ in6 ^ in10 ^ bitbuffer[in_offset + 16]; - in18 = input[i / sizeof(chorba_word_t) + 17] ^ next18 ^ in7 ^ in11 ^ bitbuffer[in_offset + 17]; - in19 = input[i / sizeof(chorba_word_t) + 18] ^ next19 ^ in8 ^ in12 ^ bitbuffer[in_offset + 18]; - in20 = input[i / sizeof(chorba_word_t) + 19] ^ next20 ^ in9 ^ in13 ^ bitbuffer[in_offset + 19]; - in21 = input[i / sizeof(chorba_word_t) + 20] ^ next21 ^ in10 ^ in14 ^ bitbuffer[in_offset + 20]; - in22 = input[i / sizeof(chorba_word_t) + 21] ^ next22 ^ in11 ^ in15 ^ bitbuffer[in_offset + 21]; - in23 = input[i / sizeof(chorba_word_t) + 22] ^ in1 ^ in12 ^ in16 ^ bitbuffer[in_offset + 22]; - in24 = input[i / sizeof(chorba_word_t) + 23] ^ in2 ^ in13 ^ in17 ^ bitbuffer[in_offset + 23]; - in25 = input[i / sizeof(chorba_word_t) + 24] ^ in3 ^ in14 ^ in18 ^ bitbuffer[in_offset + 24]; - in26 = input[i / sizeof(chorba_word_t) + 25] ^ in4 ^ in15 ^ in19 ^ bitbuffer[in_offset + 25]; - in27 = input[i / sizeof(chorba_word_t) + 26] ^ in5 ^ in16 ^ in20 ^ bitbuffer[in_offset + 26]; - in28 = input[i / sizeof(chorba_word_t) + 27] ^ in6 ^ in17 ^ in21 ^ bitbuffer[in_offset + 27]; - in29 = input[i / sizeof(chorba_word_t) + 28] ^ in7 ^ in18 ^ in22 ^ bitbuffer[in_offset + 28]; - in30 = input[i / sizeof(chorba_word_t) + 29] ^ in8 ^ in19 ^ in23 ^ bitbuffer[in_offset + 29]; - in31 = input[i / sizeof(chorba_word_t) + 30] ^ in9 ^ in20 ^ in24 ^ bitbuffer[in_offset + 30]; - in32 = input[i / sizeof(chorba_word_t) + 31] ^ in10 ^ in21 ^ in25 ^ bitbuffer[in_offset + 31]; - - next1 = in11 ^ in22 ^ in26; - next2 = in12 ^ in23 ^ in27; - next3 = in13 ^ in24 ^ in28; - next4 = in14 ^ in25 ^ in29; - next5 = in15 ^ in26 ^ in30; - next6 = in16 ^ in27 ^ in31; - next7 = in17 ^ in28 ^ in32; - next8 = in18 ^ in29; - next9 = in19 ^ in30; - next10 = in20 ^ in31; - next11 = in21 ^ in32; - next12 = in22; - next13 = in23; - next14 = in24; - next15 = in25; - next16 = in26; - next17 = in27; - next18 = in28; - next19 = in29; - next20 = in30; - next21 = in31; - next22 = in32; - - bitbuffer[out_offset1 + 22] = in1; - bitbuffer[out_offset1 + 23] = in2; - bitbuffer[out_offset1 + 24] = in3; - bitbuffer[out_offset1 + 25] = in4; - bitbuffer[out_offset1 + 26] = in5; - bitbuffer[out_offset1 + 27] = in6; - bitbuffer[out_offset1 + 28] = in7; - bitbuffer[out_offset1 + 29] = in8; - bitbuffer[out_offset1 + 30] = in9; - bitbuffer[out_offset1 + 31] = in10; - bitbuffer[out_offset2 + 0] = in11; - bitbuffer[out_offset2 + 1] = in12; - bitbuffer[out_offset2 + 2] = in13; - bitbuffer[out_offset2 + 3] = in14; - bitbuffer[out_offset2 + 4] = in15; - bitbuffer[out_offset2 + 5] = in16; - bitbuffer[out_offset2 + 6] = in17; - bitbuffer[out_offset2 + 7] = in18; - bitbuffer[out_offset2 + 8] = in19; - bitbuffer[out_offset2 + 9] = in20; - bitbuffer[out_offset2 + 10] = in21; - bitbuffer[out_offset2 + 11] = in22; - bitbuffer[out_offset2 + 12] = in23; - bitbuffer[out_offset2 + 13] = in24; - bitbuffer[out_offset2 + 14] = in25; - bitbuffer[out_offset2 + 15] = in26; - bitbuffer[out_offset2 + 16] = in27; - bitbuffer[out_offset2 + 17] = in28; - bitbuffer[out_offset2 + 18] = in29; - bitbuffer[out_offset2 + 19] = in30; - bitbuffer[out_offset2 + 20] = in31; - bitbuffer[out_offset2 + 21] = in32; - } - - bitbuffer[(i / sizeof(chorba_word_t) + 0) % bitbuffer_size_zwords] ^= next1; - bitbuffer[(i / sizeof(chorba_word_t) + 1) % bitbuffer_size_zwords] ^= next2; - bitbuffer[(i / sizeof(chorba_word_t) + 2) % bitbuffer_size_zwords] ^= next3; - bitbuffer[(i / sizeof(chorba_word_t) + 3) % bitbuffer_size_zwords] ^= next4; - bitbuffer[(i / sizeof(chorba_word_t) + 4) % bitbuffer_size_zwords] ^= next5; - bitbuffer[(i / sizeof(chorba_word_t) + 5) % bitbuffer_size_zwords] ^= next6; - bitbuffer[(i / sizeof(chorba_word_t) + 6) % bitbuffer_size_zwords] ^= next7; - bitbuffer[(i / sizeof(chorba_word_t) + 7) % bitbuffer_size_zwords] ^= next8; - bitbuffer[(i / sizeof(chorba_word_t) + 8) % bitbuffer_size_zwords] ^= next9; - bitbuffer[(i / sizeof(chorba_word_t) + 9) % bitbuffer_size_zwords] ^= next10; - bitbuffer[(i / sizeof(chorba_word_t) + 10) % bitbuffer_size_zwords] ^= next11; - bitbuffer[(i / sizeof(chorba_word_t) + 11) % bitbuffer_size_zwords] ^= next12; - bitbuffer[(i / sizeof(chorba_word_t) + 12) % bitbuffer_size_zwords] ^= next13; - bitbuffer[(i / sizeof(chorba_word_t) + 13) % bitbuffer_size_zwords] ^= next14; - bitbuffer[(i / sizeof(chorba_word_t) + 14) % bitbuffer_size_zwords] ^= next15; - bitbuffer[(i / sizeof(chorba_word_t) + 15) % bitbuffer_size_zwords] ^= next16; - bitbuffer[(i / sizeof(chorba_word_t) + 16) % bitbuffer_size_zwords] ^= next17; - bitbuffer[(i / sizeof(chorba_word_t) + 17) % bitbuffer_size_zwords] ^= next18; - bitbuffer[(i / sizeof(chorba_word_t) + 18) % bitbuffer_size_zwords] ^= next19; - bitbuffer[(i / sizeof(chorba_word_t) + 19) % bitbuffer_size_zwords] ^= next20; - bitbuffer[(i / sizeof(chorba_word_t) + 20) % bitbuffer_size_zwords] ^= next21; - bitbuffer[(i / sizeof(chorba_word_t) + 21) % bitbuffer_size_zwords] ^= next22; - - for (int j = 14870; j < 14870 + 64; j++) { - bitbuffer[(j + (i / sizeof(chorba_word_t))) % bitbuffer_size_zwords] = 0; - } - - uint64_t next1_64 = 0; - uint64_t next2_64 = 0; - uint64_t next3_64 = 0; - uint64_t next4_64 = 0; - uint64_t next5_64 = 0; - uint64_t final[9] = {0}; - - for (; (i + 72 < len); i += 32) { - uint64_t in1; - uint64_t in2; - uint64_t in3; - uint64_t in4; - uint64_t a1, a2, a3, a4; - uint64_t b1, b2, b3, b4; - uint64_t c1, c2, c3, c4; - uint64_t d1, d2, d3, d4; - - - in1 = input_qwords[i / sizeof(uint64_t)] ^ bitbuffer_qwords[(i / sizeof(uint64_t)) % bitbuffer_size_qwords]; - in2 = input_qwords[i / sizeof(uint64_t) + 1] ^ bitbuffer_qwords[(i / sizeof(uint64_t) + 1) % bitbuffer_size_qwords]; - in1 = Z_U64_FROM_LE(in1) ^ next1_64; - in2 = Z_U64_FROM_LE(in2) ^ next2_64; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = input_qwords[i / sizeof(uint64_t) + 2] ^ bitbuffer_qwords[(i / sizeof(uint64_t) + 2) % bitbuffer_size_qwords]; - in4 = input_qwords[i / sizeof(uint64_t) + 3] ^ bitbuffer_qwords[(i / sizeof(uint64_t) + 3) % bitbuffer_size_qwords]; - in3 = Z_U64_FROM_LE(in3) ^ next3_64 ^ a1; - in4 = Z_U64_FROM_LE(in4) ^ next4_64 ^ a2 ^ b1; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1_64, next2_64, next3_64, next4_64, next5_64); - } - - memcpy(final, input_qwords + (i / sizeof(uint64_t)), len-i); - final[0] ^= Z_U64_TO_LE(next1_64); - final[1] ^= Z_U64_TO_LE(next2_64); - final[2] ^= Z_U64_TO_LE(next3_64); - final[3] ^= Z_U64_TO_LE(next4_64); - final[4] ^= Z_U64_TO_LE(next5_64); - - uint8_t *final_bytes = (uint8_t*)final; - - for (size_t j = 0; j < (len-i); j++) { - crc = crc_table[(crc ^ final_bytes[j] ^ bitbuffer_bytes[(j+i) % bitbuffer_size_bytes]) & 0xff] ^ (crc >> 8); - } - -#if defined(__EMSCRIPTEN__) - zng_free(bitbuffer); -#endif - return ~crc; -} - -# if CHORBA_W == 8 -/* Implement Chorba algorithm from https://arxiv.org/abs/2412.16398 */ -Z_INTERNAL uint32_t crc32_chorba_32768_nondestructive(uint32_t crc, const uint8_t *buf, size_t len) { - /* The calling function ensured that this is aligned correctly */ - const uint64_t* input = (const uint64_t*)buf; - uint64_t bitbuffer[32768 / sizeof(uint64_t)]; - const uint8_t *bitbuffer_bytes = (const uint8_t*)bitbuffer; - memset(bitbuffer, 0, 32768); - bitbuffer[0] = Z_U64_TO_LE(~crc); - - crc = 0; - - size_t i = 0; - - for(; i + 300*8+64 < len; i += 64) { - uint64_t in1, in2, in3, in4; - uint64_t in5, in6, in7, in8; - size_t in_offset = (i/8); - - in1 = input[i / sizeof(uint64_t) + 0] ^ bitbuffer[in_offset + 0]; - in2 = input[i / sizeof(uint64_t) + 1] ^ bitbuffer[in_offset + 1]; - in3 = input[i / sizeof(uint64_t) + 2] ^ bitbuffer[in_offset + 2]; - in4 = input[i / sizeof(uint64_t) + 3] ^ bitbuffer[in_offset + 3]; - in5 = input[i / sizeof(uint64_t) + 4] ^ bitbuffer[in_offset + 4]; - in6 = input[i / sizeof(uint64_t) + 5] ^ bitbuffer[in_offset + 5]; - in7 = input[i / sizeof(uint64_t) + 6] ^ bitbuffer[in_offset + 6]; - in8 = input[i / sizeof(uint64_t) + 7] ^ bitbuffer[in_offset + 7]; - - // [0, 145, 183, 211] - - bitbuffer[(i/8 + 0 + 145)] ^= in1; - bitbuffer[(i/8 + 1 + 145)] ^= in2; - bitbuffer[(i/8 + 2 + 145)] ^= in3; - bitbuffer[(i/8 + 3 + 145)] ^= in4; - bitbuffer[(i/8 + 4 + 145)] ^= in5; - bitbuffer[(i/8 + 5 + 145)] ^= in6; - bitbuffer[(i/8 + 6 + 145)] ^= in7; - bitbuffer[(i/8 + 7 + 145)] ^= in8; - - bitbuffer[(i/8 + 0 + 183)] ^= in1; - bitbuffer[(i/8 + 1 + 183)] ^= in2; - bitbuffer[(i/8 + 2 + 183)] ^= in3; - bitbuffer[(i/8 + 3 + 183)] ^= in4; - bitbuffer[(i/8 + 4 + 183)] ^= in5; - bitbuffer[(i/8 + 5 + 183)] ^= in6; - bitbuffer[(i/8 + 6 + 183)] ^= in7; - bitbuffer[(i/8 + 7 + 183)] ^= in8; - - bitbuffer[(i/8 + 0 + 211)] ^= in1; - bitbuffer[(i/8 + 1 + 211)] ^= in2; - bitbuffer[(i/8 + 2 + 211)] ^= in3; - bitbuffer[(i/8 + 3 + 211)] ^= in4; - bitbuffer[(i/8 + 4 + 211)] ^= in5; - bitbuffer[(i/8 + 5 + 211)] ^= in6; - bitbuffer[(i/8 + 6 + 211)] ^= in7; - bitbuffer[(i/8 + 7 + 211)] ^= in8; - - bitbuffer[(i/8 + 0 + 300)] = in1; - bitbuffer[(i/8 + 1 + 300)] = in2; - bitbuffer[(i/8 + 2 + 300)] = in3; - bitbuffer[(i/8 + 3 + 300)] = in4; - bitbuffer[(i/8 + 4 + 300)] = in5; - bitbuffer[(i/8 + 5 + 300)] = in6; - bitbuffer[(i/8 + 6 + 300)] = in7; - bitbuffer[(i/8 + 7 + 300)] = in8; - } - - uint64_t next1_64 = 0; - uint64_t next2_64 = 0; - uint64_t next3_64 = 0; - uint64_t next4_64 = 0; - uint64_t next5_64 = 0; - uint64_t final[9] = {0}; - - for (; (i + 72 < len); i += 32) { - uint64_t in1; - uint64_t in2; - uint64_t in3; - uint64_t in4; - uint64_t a1, a2, a3, a4; - uint64_t b1, b2, b3, b4; - uint64_t c1, c2, c3, c4; - uint64_t d1, d2, d3, d4; - - - in1 = input[i / sizeof(uint64_t)] ^ bitbuffer[(i / sizeof(uint64_t))]; - in2 = input[(i + 8) / sizeof(uint64_t)] ^ bitbuffer[(i / sizeof(uint64_t) + 1)]; - in1 = Z_U64_FROM_LE(in1) ^ next1_64; - in2 = Z_U64_FROM_LE(in2) ^ next2_64; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = input[(i + 16) / sizeof(uint64_t)] ^ bitbuffer[(i / sizeof(uint64_t) + 2)]; - in4 = input[(i + 24) / sizeof(uint64_t)] ^ bitbuffer[(i / sizeof(uint64_t) + 3)]; - in3 = Z_U64_FROM_LE(in3) ^ next3_64 ^ a1; - in4 = Z_U64_FROM_LE(in4) ^ next4_64 ^ a2 ^ b1; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1_64, next2_64, next3_64, next4_64, next5_64); - - } - - memcpy(final, input+(i / sizeof(uint64_t)), len-i); - final[0] ^= Z_U64_TO_LE(next1_64); - final[1] ^= Z_U64_TO_LE(next2_64); - final[2] ^= Z_U64_TO_LE(next3_64); - final[3] ^= Z_U64_TO_LE(next4_64); - final[4] ^= Z_U64_TO_LE(next5_64); - - uint8_t *final_bytes = (uint8_t*)final; - - for (size_t j = 0; j < (len-i); j++) { - crc = crc_table[(crc ^ final_bytes[j] ^ bitbuffer_bytes[(j+i)]) & 0xff] ^ (crc >> 8); - } - - return ~crc; -} - -/* Implement Chorba algorithm from https://arxiv.org/abs/2412.16398 */ -Z_INTERNAL uint32_t crc32_chorba_small_nondestructive(uint32_t crc, const uint8_t *buf, size_t len) { - /* The calling function ensured that this is aligned correctly */ - const uint64_t* input = (const uint64_t*)buf; - uint64_t final[9] = {0}; - uint64_t next1 = ~crc; - crc = 0; - uint64_t next2 = 0; - uint64_t next3 = 0; - uint64_t next4 = 0; - uint64_t next5 = 0; - - size_t i = 0; - - /* This is weird, doing for vs while drops 10% off the exec time */ - for (; (i + 256 + 40 + 32 + 32) < len; i += 32) { - uint64_t in1; - uint64_t in2; - uint64_t in3; - uint64_t in4; - uint64_t a1, a2, a3, a4; - uint64_t b1, b2, b3, b4; - uint64_t c1, c2, c3, c4; - uint64_t d1, d2, d3, d4; - - - uint64_t chorba1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1; - uint64_t chorba2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2; - uint64_t chorba3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3; - uint64_t chorba4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4; - uint64_t chorba5 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 4]) ^ next5; - uint64_t chorba6 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 5]); - uint64_t chorba7 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 6]) ^ chorba1; - uint64_t chorba8 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 7]) ^ chorba2; - - i += 8 * 8; - - /* 0-3 */ - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ chorba3; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ chorba4 ^ chorba1; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ a1 ^ chorba5 ^ chorba2 ^ chorba1; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ a2 ^ b1 ^ chorba6 ^ chorba3 ^ chorba2; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - /* chorba5 already consumed next5, clear it so ACCUM_ROUND - does not xor the stale value into next1 */ - next5 = 0; - ACCUM_ROUND(next1, next2, next3, next4, next5); - - i += 32; - - /* 4-7 */ - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1 ^ chorba7 ^ chorba4 ^ chorba3; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2 ^ chorba8 ^ chorba5 ^ chorba4; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3 ^ a1 ^ chorba6 ^ chorba5; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4 ^ a2 ^ b1 ^ chorba7 ^ chorba6; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1, next2, next3, next4, next5); - - i += 32; - - /* 8-11 */ - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1 ^ chorba8 ^ chorba7 ^ chorba1; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2 ^ chorba8 ^ chorba2; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3 ^ a1 ^ chorba3; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4 ^ a2 ^ b1 ^ chorba4; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1, next2, next3, next4, next5); - - i += 32; - - /* 12-15 */ - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1 ^ chorba5 ^ chorba1; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2 ^ chorba6 ^ chorba2 ^ chorba1; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3 ^ a1 ^ chorba7 ^ chorba3 ^ chorba2 ^ chorba1; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4 ^ a2 ^ b1 ^ chorba8 ^ chorba4 ^ chorba3 ^ chorba2; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1, next2, next3, next4, next5); - - i += 32; - - /* 16-19 */ - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1 ^ chorba5 ^ chorba4 ^ chorba3 ^ chorba1; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2 ^ chorba6 ^ chorba5 ^ chorba4 ^ chorba1 ^ chorba2; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3 ^ a1 ^ chorba7 ^ chorba6 ^ chorba5 ^ chorba2 ^ chorba3; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4 ^ a2 ^ b1 ^ chorba8 ^ chorba7 ^ chorba6 ^ chorba3 ^ chorba4 ^ chorba1; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1, next2, next3, next4, next5); - - i += 32; - - /* 20-23 */ - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1 ^ chorba8 ^ chorba7 ^ chorba4 ^ chorba5 ^ chorba2 ^ chorba1; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2 ^ chorba8 ^ chorba5 ^ chorba6 ^ chorba3 ^ chorba2; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3 ^ a1 ^ chorba7 ^ chorba6 ^ chorba4 ^ chorba3 ^ chorba1; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4 ^ a2 ^ b1 ^ chorba8 ^ chorba7 ^ chorba5 ^ chorba4 ^ chorba2 ^ chorba1; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1, next2, next3, next4, next5); - - i += 32; - - /* 24-27 */ - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1 ^ chorba8 ^ chorba6 ^ chorba5 ^ chorba3 ^ chorba2 ^ chorba1; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2 ^ chorba7 ^ chorba6 ^ chorba4 ^ chorba3 ^ chorba2; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3 ^ a1 ^ chorba8 ^ chorba7 ^ chorba5 ^ chorba4 ^ chorba3; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4 ^ a2 ^ b1 ^ chorba8 ^ chorba6 ^ chorba5 ^ chorba4; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1, next2, next3, next4, next5); - - i += 32; - - /* 28-31 */ - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1 ^ chorba7 ^ chorba6 ^ chorba5; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2 ^ chorba8 ^ chorba7 ^ chorba6; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3 ^ a1 ^ chorba8 ^ chorba7; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4 ^ a2 ^ b1 ^ chorba8; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1, next2, next3, next4, next5); - } - - for (; (i + 40 + 32) < len; i += 32) { - uint64_t in1; - uint64_t in2; - uint64_t in3; - uint64_t in4; - uint64_t a1, a2, a3, a4; - uint64_t b1, b2, b3, b4; - uint64_t c1, c2, c3, c4; - uint64_t d1, d2, d3, d4; - - - in1 = Z_U64_FROM_LE(input[i / sizeof(uint64_t)]) ^ next1; - in2 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 1]) ^ next2; - - NEXT_ROUND(in1, a1, a2, a3, a4); - - NEXT_ROUND(in2, b1, b2, b3, b4); - - in3 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 2]) ^ next3 ^ a1; - in4 = Z_U64_FROM_LE(input[i / sizeof(uint64_t) + 3]) ^ next4 ^ a2 ^ b1; - - NEXT_ROUND(in3, c1, c2, c3, c4); - - NEXT_ROUND(in4, d1, d2, d3, d4); - - ACCUM_ROUND(next1, next2, next3, next4, next5); - } - - memcpy(final, input+(i / sizeof(uint64_t)), len-i); - final[0] ^= Z_U64_TO_LE(next1); - final[1] ^= Z_U64_TO_LE(next2); - final[2] ^= Z_U64_TO_LE(next3); - final[3] ^= Z_U64_TO_LE(next4); - final[4] ^= Z_U64_TO_LE(next5); - - return crc32_braid(~crc, (uint8_t*)final, len-i); -} - -#else // CHORBA_W == 8 - -Z_INTERNAL uint32_t crc32_chorba_small_nondestructive_32bit(uint32_t crc, const uint8_t *buf, size_t len) { - /* The calling function ensured that this is aligned correctly */ - const uint32_t* input = (const uint32_t*)buf; - uint32_t final[20] = {0}; - - uint32_t next1 = ~crc; - crc = 0; - uint32_t next2 = 0; - uint32_t next3 = 0; - uint32_t next4 = 0; - uint32_t next5 = 0; - uint32_t next6 = 0; - uint32_t next7 = 0; - uint32_t next8 = 0; - uint32_t next9 = 0; - uint32_t next10 = 0; - - size_t i = 0; - for (; i + 80 < len; i += 40) { - uint32_t in1; - uint32_t in2; - uint32_t in3; - uint32_t in4; - uint32_t in5; - uint32_t in6; - uint32_t in7; - uint32_t in8; - uint32_t in9; - uint32_t in10; - - uint32_t a1, a2, a3, a4, a6, a7; - uint32_t b1, b2, b3, b4, b6, b7; - uint32_t c1, c2, c3, c4, c6, c7; - uint32_t d1, d2, d3, d4, d6, d7; - uint32_t e1, e2, e3, e4, e6, e7; - uint32_t f1, f2, f3, f4, f6, f7; - uint32_t g1, g2, g3, g4, g6, g7; - uint32_t h1, h2, h3, h4, h6, h7; - uint32_t i1, i2, i3, i4, i6, i7; - uint32_t j1, j2, j3, j4, j6, j7; - - uint32_t out1; - uint32_t out2; - uint32_t out3; - uint32_t out4; - uint32_t out5; - uint32_t out6; - uint32_t out7; - uint32_t out8; - uint32_t out9; - uint32_t out10; - - in1 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 0]) ^ next1; - in2 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 1]) ^ next2; - in3 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 2]) ^ next3; - in4 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 3]) ^ next4; - - a1 = (in1 << 17); - a2 = (in1 >> 15) ^ (in1 << 23); - a3 = (in1 >> 9) ^ (in1 << 19); - a4 = (in1 >> 13); - a6 = (in1 << 12); - a7 = (in1 >> 20); - - b1 = (in2 << 17); - b2 = (in2 >> 15) ^ (in2 << 23); - b3 = (in2 >> 9) ^ (in2 << 19); - b4 = (in2 >> 13); - b6 = (in2 << 12); - b7 = (in2 >> 20); - - c1 = (in3 << 17); - c2 = (in3 >> 15) ^ (in3 << 23); - c3 = (in3 >> 9) ^ (in3 << 19); - c4 = (in3 >> 13); - c6 = (in3 << 12); - c7 = (in3 >> 20); - - d1 = (in4 << 17); - d2 = (in4 >> 15) ^ (in4 << 23); - d3 = (in4 >> 9) ^ (in4 << 19); - d4 = (in4 >> 13); - d6 = (in4 << 12); - d7 = (in4 >> 20); - - in5 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 4]) ^ next5 ^ a1; - in6 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 5]) ^ next6 ^ a2 ^ b1; - in7 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 6]) ^ next7 ^ a3 ^ b2 ^ c1; - in8 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 7]) ^ next8 ^ a4 ^ b3 ^ c2 ^ d1; - - e1 = (in5 << 17); - e2 = (in5 >> 15) ^ (in5 << 23); - e3 = (in5 >> 9) ^ (in5 << 19); - e4 = (in5 >> 13); - e6 = (in5 << 12); - e7 = (in5 >> 20); - - f1 = (in6 << 17); - f2 = (in6 >> 15) ^ (in6 << 23); - f3 = (in6 >> 9) ^ (in6 << 19); - f4 = (in6 >> 13); - f6 = (in6 << 12); - f7 = (in6 >> 20); - - g1 = (in7 << 17); - g2 = (in7 >> 15) ^ (in7 << 23); - g3 = (in7 >> 9) ^ (in7 << 19); - g4 = (in7 >> 13); - g6 = (in7 << 12); - g7 = (in7 >> 20); - - h1 = (in8 << 17); - h2 = (in8 >> 15) ^ (in8 << 23); - h3 = (in8 >> 9) ^ (in8 << 19); - h4 = (in8 >> 13); - h6 = (in8 << 12); - h7 = (in8 >> 20); - - in9 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 8]) ^ next9 ^ b4 ^ c3 ^ d2 ^ e1; - in10 = Z_U32_FROM_LE(input[i/sizeof(uint32_t) + 9]) ^ next10 ^ a6 ^ c4 ^ d3 ^ e2 ^ f1; - - i1 = (in9 << 17); - i2 = (in9 >> 15) ^ (in9 << 23); - i3 = (in9 >> 9) ^ (in9 << 19); - i4 = (in9 >> 13); - i6 = (in9 << 12); - i7 = (in9 >> 20); - - j1 = (in10 << 17); - j2 = (in10 >> 15) ^ (in10 << 23); - j3 = (in10 >> 9) ^ (in10 << 19); - j4 = (in10 >> 13); - j6 = (in10 << 12); - j7 = (in10 >> 20); - - out1 = a7 ^ b6 ^ d4 ^ e3 ^ f2 ^ g1; - out2 = b7 ^ c6 ^ e4 ^ f3 ^ g2 ^ h1; - out3 = c7 ^ d6 ^ f4 ^ g3 ^ h2 ^ i1; - out4 = d7 ^ e6 ^ g4 ^ h3 ^ i2 ^ j1; - out5 = e7 ^ f6 ^ h4 ^ i3 ^ j2; - out6 = f7 ^ g6 ^ i4 ^ j3; - out7 = g7 ^ h6 ^ j4; - out8 = h7 ^ i6; - out9 = i7 ^ j6; - out10 = j7; - - next1 = out1; - next2 = out2; - next3 = out3; - next4 = out4; - next5 = out5; - next6 = out6; - next7 = out7; - next8 = out8; - next9 = out9; - next10 = out10; - - } - - memcpy(final, input+(i/sizeof(uint32_t)), len-i); - final[0] ^= Z_U32_TO_LE(next1); - final[1] ^= Z_U32_TO_LE(next2); - final[2] ^= Z_U32_TO_LE(next3); - final[3] ^= Z_U32_TO_LE(next4); - final[4] ^= Z_U32_TO_LE(next5); - final[5] ^= Z_U32_TO_LE(next6); - final[6] ^= Z_U32_TO_LE(next7); - final[7] ^= Z_U32_TO_LE(next8); - final[8] ^= Z_U32_TO_LE(next9); - final[9] ^= Z_U32_TO_LE(next10); - - return crc32_braid(~crc, (uint8_t*)final, len-i); -} -#endif // CHORBA_W == 8 - -Z_INTERNAL uint32_t crc32_chorba(uint32_t crc, const uint8_t *buf, size_t len) { - uintptr_t align_diff = ALIGN_DIFF(buf, 8); - if (len <= align_diff + CHORBA_SMALL_THRESHOLD) - return crc32_braid(crc, buf, len); - - if (align_diff) { - crc = crc32_braid(crc, buf, align_diff); - len -= align_diff; - buf += align_diff; - } - if (len > CHORBA_LARGE_THRESHOLD) - return crc32_chorba_118960_nondestructive(crc, buf, len); -#if CHORBA_W == 8 - if (len > CHORBA_MEDIUM_LOWER_THRESHOLD && len <= CHORBA_MEDIUM_UPPER_THRESHOLD) - return crc32_chorba_32768_nondestructive(crc, buf, len); - return crc32_chorba_small_nondestructive(crc, buf, len); -#else - return crc32_chorba_small_nondestructive_32bit(crc, buf, len); -#endif -} - -uint32_t crc32_copy_chorba(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - crc = crc32_chorba(crc, src, len); - memcpy(dst, src, len); - return crc; -} - -#endif /* CRC32_CHORBA_FALLBACK */ diff --git a/modules/zlib/src/arch/generic/generic_functions.h b/modules/zlib/src/arch/generic/generic_functions.h deleted file mode 100644 index b128a02081..0000000000 --- a/modules/zlib/src/arch/generic/generic_functions.h +++ /dev/null @@ -1,80 +0,0 @@ -/* generic_functions.h -- generic C implementations for arch-specific functions. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef GENERIC_FUNCTIONS_H_ -#define GENERIC_FUNCTIONS_H_ - -typedef uint32_t (*adler32_func)(uint32_t adler, const uint8_t *buf, size_t len); -typedef uint32_t (*adler32_copy_func)(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -typedef uint32_t (*compare256_func)(const uint8_t *src0, const uint8_t *src1); -typedef uint32_t (*crc32_func)(uint32_t crc, const uint8_t *buf, size_t len); -typedef uint32_t (*crc32_copy_func)(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -typedef void (*slide_hash_func)(deflate_state *s); - -#ifdef ADLER32_FALLBACK -uint32_t adler32_c(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_c(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -#endif -#ifdef CHUNKSET_FALLBACK -uint8_t* chunkmemset_safe_c(uint8_t *out, uint8_t *from, size_t len, size_t left); -#endif -#ifdef COMPARE256_FALLBACK -uint32_t compare256_8(const uint8_t *src0, const uint8_t *src1); -uint32_t compare256_64(const uint8_t *src0, const uint8_t *src1); -uint32_t compare256_c(const uint8_t *src0, const uint8_t *src1); -#endif - -#ifdef CRC32_BRAID_FALLBACK -uint32_t crc32_braid(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_braid(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif - -/* Chorba is available whenever braid is needed as a fallback and hasn't been disabled. */ -#if defined(CRC32_BRAID_FALLBACK) && !defined(WITHOUT_CHORBA) -# define CRC32_CHORBA_FALLBACK -#endif - -#ifdef CRC32_CHORBA_FALLBACK - uint32_t crc32_chorba(uint32_t crc, const uint8_t *buf, size_t len); - uint32_t crc32_copy_chorba(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif -#ifdef CHUNKSET_FALLBACK -void inflate_fast_c(PREFIX3(stream) *strm, uint32_t start); -#endif -#ifdef COMPARE256_FALLBACK -uint32_t longest_match_c(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_c(deflate_state *const s, uint32_t cur_match); -#endif -#ifdef SLIDE_HASH_FALLBACK -void slide_hash_c(deflate_state *s); -#endif - -#ifdef DISABLE_RUNTIME_CPU_DETECTION -// Generic fallbacks when no native implementation exists -# ifdef ADLER32_FALLBACK -# define native_adler32 adler32_c -# define native_adler32_copy adler32_copy_c -# endif -# ifdef CHUNKSET_FALLBACK -# define native_chunkmemset_safe chunkmemset_safe_c -# define native_inflate_fast inflate_fast_c -# endif -# ifdef COMPARE256_FALLBACK -# define native_compare256 compare256_c -# define native_longest_match longest_match_c -# define native_longest_match_roll longest_match_roll_c -# endif -# ifdef CRC32_CHORBA_FALLBACK -# define native_crc32 crc32_chorba -# define native_crc32_copy crc32_copy_chorba -# elif defined(CRC32_BRAID_FALLBACK) -# define native_crc32 crc32_braid -# define native_crc32_copy crc32_copy_braid -# endif -# ifdef SLIDE_HASH_FALLBACK -# define native_slide_hash slide_hash_c -# endif -#endif - -#endif diff --git a/modules/zlib/src/arch/generic/slide_hash_c.c b/modules/zlib/src/arch/generic/slide_hash_c.c deleted file mode 100644 index 8fdc478cbb..0000000000 --- a/modules/zlib/src/arch/generic/slide_hash_c.c +++ /dev/null @@ -1,58 +0,0 @@ -/* slide_hash.c -- slide hash table C implementation - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "arch_functions.h" - -#ifdef SLIDE_HASH_FALLBACK - -#include "deflate.h" - -/* =========================================================================== - * Slide the hash table when sliding the window down (could be avoided with 32 - * bit values at the expense of memory usage). We slide even when level == 0 to - * keep the hash table consistent if we switch back to level > 0 later. - */ -static inline void slide_hash_c_chain(Pos *table, uint32_t entries, uint16_t wsize) { -#ifdef NOT_TWEAK_COMPILER - table += entries; - do { - unsigned m; - m = *--table; - *table = (Pos)(m >= wsize ? m-wsize : 0); - /* If entries is not on any hash chain, prev[entries] is garbage but - * its value will never be used. - */ - } while (--entries); -#else - { - /* As of I make this change, gcc (4.8.*) isn't able to vectorize - * this hot loop using saturated-subtraction on x86-64 architecture. - * To avoid this defect, we can change the loop such that - * o. the pointer advance forward, and - * o. demote the variable 'm' to be local to the loop, and - * choose type "Pos" (instead of 'unsigned int') for the - * variable to avoid unnecessary zero-extension. - */ - unsigned int i; - Pos *q = table; - for (i = 0; i < entries; i++) { - Pos m = *q; - Pos t = (Pos)wsize; - *q++ = (Pos)(m >= t ? m-t: 0); - } - } -#endif /* NOT_TWEAK_COMPILER */ -} - -Z_INTERNAL void slide_hash_c(deflate_state *s) { - uint16_t wsize = (uint16_t)s->w_size; - - slide_hash_c_chain(s->head, HASH_SIZE, wsize); - slide_hash_c_chain(s->prev, wsize, wsize); -} - -#endif /* SLIDE_HASH_FALLBACK */ diff --git a/modules/zlib/src/arch/loongarch/Makefile.in b/modules/zlib/src/arch/loongarch/Makefile.in deleted file mode 100644 index 86baed1553..0000000000 --- a/modules/zlib/src/arch/loongarch/Makefile.in +++ /dev/null @@ -1,99 +0,0 @@ -# Makefile for zlib-ng -# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler -# Copyright (C) 2024 Hans Kristian Rosbach -# Copyright (C) 2025 Vladislav Shchapov -# For conditions of distribution and use, see copyright notice in zlib.h - -CC= -CFLAGS= -SFLAGS= -INCLUDES= -SUFFIX= - -LSXFLAG=-mlsx -LASXFLAG=-mlasx - -SRCDIR=. -SRCTOP=../.. -TOPDIR=$(SRCTOP) - -all: \ - loongarch_features.o loongarch_features.lo \ - crc32_la.o crc32_la.lo \ - adler32_lasx.o adler32_lasx.lo \ - adler32_lsx.o adler32_lsx.lo \ - chunkset_lasx.o chunkset_lasx.lo \ - chunkset_lsx.o chunkset_lsx.lo \ - compare256_lasx.o compare256_lasx.lo \ - compare256_lsx.o compare256_lsx.lo \ - slide_hash_lasx.o slide_hash_lasx.lo \ - slide_hash_lsx.o slide_hash_lsx.lo - -loongarch_features.o: $(SRCDIR)/loongarch_features.c - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/loongarch_features.c - -loongarch_features.lo: $(SRCDIR)/loongarch_features.c - $(CC) $(SFLAGS) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/loongarch_features.c - -crc32_la.o: $(SRCDIR)/crc32_la.c - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_la.c - -crc32_la.lo: $(SRCDIR)/crc32_la.c - $(CC) $(SFLAGS) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_la.c - -adler32_lasx.o: - $(CC) $(CFLAGS) $(LASXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_lasx.c - -adler32_lasx.lo: - $(CC) $(SFLAGS) $(LASXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_lasx.c - -adler32_lsx.o: - $(CC) $(CFLAGS) $(LSXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_lsx.c - -adler32_lsx.lo: - $(CC) $(SFLAGS) $(LSXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_lsx.c - -chunkset_lasx.o: - $(CC) $(CFLAGS) $(LASXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_lasx.c - -chunkset_lasx.lo: - $(CC) $(SFLAGS) $(LASXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_lasx.c - -chunkset_lsx.o: - $(CC) $(CFLAGS) $(LSXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_lsx.c - -chunkset_lsx.lo: - $(CC) $(SFLAGS) $(LSXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_lsx.c - -compare256_lasx.o: - $(CC) $(CFLAGS) $(LASXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_lasx.c - -compare256_lasx.lo: - $(CC) $(SFLAGS) $(LASXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_lasx.c - -compare256_lsx.o: - $(CC) $(CFLAGS) $(LSXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_lsx.c - -compare256_lsx.lo: - $(CC) $(SFLAGS) $(LSXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_lsx.c - -slide_hash_lasx.o: - $(CC) $(CFLAGS) $(LASXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_lasx.c - -slide_hash_lasx.lo: - $(CC) $(SFLAGS) $(LASXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_lasx.c - -slide_hash_lsx.o: - $(CC) $(CFLAGS) $(LSXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_lsx.c - -slide_hash_lsx.lo: - $(CC) $(SFLAGS) $(LSXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_lsx.c - -mostlyclean: clean -clean: - rm -f *.o *.lo *~ - rm -rf objs - rm -f *.gcda *.gcno *.gcov - -distclean: clean - rm -f Makefile diff --git a/modules/zlib/src/arch/loongarch/adler32_lasx.c b/modules/zlib/src/arch/loongarch/adler32_lasx.c deleted file mode 100644 index a7268e73ff..0000000000 --- a/modules/zlib/src/arch/loongarch/adler32_lasx.c +++ /dev/null @@ -1,154 +0,0 @@ -/* adler32_lasx.c -- compute the Adler-32 checksum of a data stream, based on Intel AVX2 implementation - * Copyright (C) 1995-2011 Mark Adler - * Copyright (C) 2022 Adam Stylinski - * Copyright (C) 2025 Vladislav Shchapov - * Authors: - * Brian Bockelman - * Adam Stylinski - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef LOONGARCH_LASX - -#include "zbuild.h" -#include "adler32_p.h" - -#include -#include "lasxintrin_ext.h" - - -/* 32 bit horizontal sum */ -static inline uint32_t hsum256(__m256i x) { - __m256i sum1 = __lasx_xvadd_w(x, __lasx_xvbsrl_v(x, 8)); - __m256i sum2 = __lasx_xvadd_w(sum1, __lasx_xvpermi_d(sum1, 0x2)); - __m256i sum3 = __lasx_xvadd_w(sum2, __lasx_xvbsrl_v(sum2, 4)); - return (uint32_t)__lasx_xvpickve2gr_wu(sum3, 0); -} - -static inline uint32_t partial_hsum256(__m256i x) { - __m256i sum1 = __lasx_xvadd_w(x, __lasx_xvbsrl_v(x, 8)); - __m256i sum2 = __lasx_xvadd_w(sum1, __lasx_xvpermi_d(sum1, 0x2)); - return (uint32_t)__lasx_xvpickve2gr_wu(sum2, 0); -} - -extern uint32_t adler32_copy_lsx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -extern uint32_t adler32_lsx(uint32_t adler, const uint8_t *src, size_t len); - -Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) { - uint32_t adler0, adler1; - adler1 = (adler >> 16) & 0xffff; - adler0 = adler & 0xffff; - -rem_peel: - if (len < 16) { - return adler32_copy_tail(adler0, dst, src, len, adler1, 1, 15, COPY); - } else if (len < 32) { - if (COPY) { - return adler32_copy_lsx(adler, dst, src, len); - } else { - return adler32_lsx(adler, src, len); - } - } - - __m256i vs1, vs2, vs2_0; - - const __m256i dot2v = (__m256i)((v32i8){ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, - 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33 }); - const __m256i dot2v_0 = (__m256i)((v32i8){ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, - 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }); - const __m256i dot3v = __lasx_xvreplgr2vr_h(1); - const __m256i zero = __lasx_xvldi(0); - - while (len >= 32) { - vs1 = __lasx_xvinsgr2vr_w(zero, adler0, 0); - vs2 = __lasx_xvinsgr2vr_w(zero, adler1, 0); - - __m256i vs1_0 = vs1; - __m256i vs3 = __lasx_xvldi(0); - vs2_0 = vs3; - - size_t k = ALIGN_DOWN(MIN(len, NMAX), 32); - len -= k; - - while (k >= 64) { - __m256i vbuf = __lasx_xvld(src, 0); - __m256i vbuf_0 = __lasx_xvld(src, 32); - src += 64; - k -= 64; - - __m256i vs1_sad = lasx_sad_bu(vbuf, zero); - __m256i vs1_sad2 = lasx_sad_bu(vbuf_0, zero); - - if (COPY) { - __lasx_xvst(vbuf, dst, 0); - __lasx_xvst(vbuf_0, dst, 32); - dst += 64; - } - - vs1 = __lasx_xvadd_w(vs1, vs1_sad); - vs3 = __lasx_xvadd_w(vs3, vs1_0); - __m256i v_short_sum2 = lasx_maddubs_w_h(vbuf, dot2v); // sum 32 uint8s to 16 shorts - __m256i v_short_sum2_0 = lasx_maddubs_w_h(vbuf_0, dot2v_0); // sum 32 uint8s to 16 shorts - __m256i vsum2 = lasx_madd_w_h(v_short_sum2, dot3v); // sum 16 shorts to 8 uint32s - __m256i vsum2_0 = lasx_madd_w_h(v_short_sum2_0, dot3v); // sum 16 shorts to 8 uint32s - vs1 = __lasx_xvadd_w(vs1_sad2, vs1); - vs2 = __lasx_xvadd_w(vsum2, vs2); - vs2_0 = __lasx_xvadd_w(vsum2_0, vs2_0); - vs1_0 = vs1; - } - - vs2 = __lasx_xvadd_w(vs2_0, vs2); - vs3 = __lasx_xvslli_w(vs3, 6); - vs2 = __lasx_xvadd_w(vs3, vs2); - vs3 = __lasx_xvldi(0); - - while (k >= 32) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 32 vs1 + sum( (32-i+1) c[i] ) - */ - __m256i vbuf = __lasx_xvld(src, 0); - src += 32; - k -= 32; - - __m256i vs1_sad = lasx_sad_bu(vbuf, zero); // Sum of abs diff, resulting in 2 x int32's - - if (COPY) { - __lasx_xvst(vbuf, dst, 0); - dst += 32; - } - - vs1 = __lasx_xvadd_w(vs1, vs1_sad); - vs3 = __lasx_xvadd_w(vs3, vs1_0); - __m256i v_short_sum2 = lasx_maddubs_w_h(vbuf, dot2v_0); // sum 32 uint8s to 16 shorts - __m256i vsum2 = lasx_madd_w_h(v_short_sum2, dot3v); // sum 16 shorts to 8 uint32s - vs2 = __lasx_xvadd_w(vsum2, vs2); - vs1_0 = vs1; - } - - /* Defer the multiplication with 32 to outside of the loop */ - vs3 = __lasx_xvslli_w(vs3, 5); - vs2 = __lasx_xvadd_w(vs2, vs3); - - adler0 = partial_hsum256(vs1) % BASE; - adler1 = hsum256(vs2) % BASE; - } - - adler = adler0 | (adler1 << 16); - - if (len) { - goto rem_peel; - } - - return adler; -} - -Z_INTERNAL uint32_t adler32_lasx(uint32_t adler, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, NULL, src, len, 0); -} - -Z_INTERNAL uint32_t adler32_copy_lasx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, dst, src, len, 1); -} - -#endif diff --git a/modules/zlib/src/arch/loongarch/adler32_lsx.c b/modules/zlib/src/arch/loongarch/adler32_lsx.c deleted file mode 100644 index 389f74c683..0000000000 --- a/modules/zlib/src/arch/loongarch/adler32_lsx.c +++ /dev/null @@ -1,147 +0,0 @@ -/* adler32_lsx.c -- compute the Adler-32 checksum of a data stream, based on Intel SSE4.2 implementation - * Copyright (C) 1995-2011 Mark Adler - * Copyright (C) 2025 Vladislav Shchapov - * Authors: - * Adam Stylinski - * Brian Bockelman - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef LOONGARCH_LSX - -#include "zbuild.h" -#include "adler32_p.h" - -#include -#include "lsxintrin_ext.h" - -static inline uint32_t partial_hsum(__m128i x) { - __m128i second_int = __lsx_vbsrl_v(x, 8); - __m128i sum = __lsx_vadd_w(x, second_int); - return __lsx_vpickve2gr_w(sum, 0); -} - -static inline uint32_t hsum(__m128i x) { - __m128i sum1 = __lsx_vilvh_d(x, x); - __m128i sum2 = __lsx_vadd_w(x, sum1); - __m128i sum3 = __lsx_vshuf4i_w(sum2, 0x01); - __m128i sum4 = __lsx_vadd_w(sum2, sum3); - return __lsx_vpickve2gr_w(sum4, 0); -} - -Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) { - uint32_t adler0, adler1; - adler1 = (adler >> 16) & 0xffff; - adler0 = adler & 0xffff; - -rem_peel: - if (len < 16) - return adler32_copy_tail(adler0, dst, src, len, adler1, 1, 15, COPY); - - __m128i vbuf, vbuf_0; - __m128i vs1_0, vs3, vs1, vs2, vs2_0, v_sad_sum1, v_short_sum2, v_short_sum2_0, - v_sad_sum2, vsum2, vsum2_0; - __m128i zero = __lsx_vldi(0); - const __m128i dot2v = (__m128i)((v16i8){ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17 }); - const __m128i dot2v_0 = (__m128i)((v16i8){ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }); - const __m128i dot3v = __lsx_vreplgr2vr_h(1); - size_t k; - - while (len >= 16) { - - k = ALIGN_DOWN(MIN(len, NMAX), 16); - len -= k; - - vs1 = __lsx_vinsgr2vr_w(zero, adler0, 0); - vs2 = __lsx_vinsgr2vr_w(zero, adler1, 0); - - vs3 = __lsx_vldi(0); - vs2_0 = __lsx_vldi(0); - vs1_0 = vs1; - - while (k >= 32) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) - */ - vbuf = __lsx_vld(src, 0); - vbuf_0 = __lsx_vld(src, 16); - src += 32; - k -= 32; - - v_sad_sum1 = lsx_sad_bu(vbuf, zero); - v_sad_sum2 = lsx_sad_bu(vbuf_0, zero); - - if (COPY) { - __lsx_vst(vbuf, dst, 0); - __lsx_vst(vbuf_0, dst, 16); - dst += 32; - } - - v_short_sum2 = __lsx_vsadd_h(__lsx_vmulwev_h_bu_b(vbuf, dot2v), __lsx_vmulwod_h_bu_b(vbuf, dot2v)); - v_short_sum2_0 = __lsx_vsadd_h(__lsx_vmulwev_h_bu_b(vbuf_0, dot2v_0), __lsx_vmulwod_h_bu_b(vbuf_0, dot2v_0)); - - vs1 = __lsx_vadd_w(v_sad_sum1, vs1); - vs3 = __lsx_vadd_w(vs1_0, vs3); - - vsum2 = __lsx_vmaddwod_w_h(__lsx_vmulwev_w_h(v_short_sum2, dot3v), v_short_sum2, dot3v); - vsum2_0 = __lsx_vmaddwod_w_h(__lsx_vmulwev_w_h(v_short_sum2_0, dot3v), v_short_sum2_0, dot3v); - vs1 = __lsx_vadd_w(v_sad_sum2, vs1); - vs2 = __lsx_vadd_w(vsum2, vs2); - vs2_0 = __lsx_vadd_w(vsum2_0, vs2_0); - vs1_0 = vs1; - } - - vs2 = __lsx_vadd_w(vs2_0, vs2); - vs3 = __lsx_vslli_w(vs3, 5); - vs2 = __lsx_vadd_w(vs3, vs2); - vs3 = __lsx_vldi(0); - - while (k >= 16) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) - */ - vbuf = __lsx_vld(src, 0); - src += 16; - k -= 16; - - v_sad_sum1 = lsx_sad_bu(vbuf, zero); - v_short_sum2 = __lsx_vsadd_h(__lsx_vmulwev_h_bu_b(vbuf, dot2v_0), __lsx_vmulwod_h_bu_b(vbuf, dot2v_0)); - - vs1 = __lsx_vadd_w(v_sad_sum1, vs1); - vs3 = __lsx_vadd_w(vs1_0, vs3); - vsum2 = __lsx_vmaddwod_w_h(__lsx_vmulwev_w_h(v_short_sum2, dot3v), v_short_sum2, dot3v); - vs2 = __lsx_vadd_w(vsum2, vs2); - vs1_0 = vs1; - - if (COPY) { - __lsx_vst(vbuf, dst, 0); - dst += 16; - } - } - - vs3 = __lsx_vslli_w(vs3, 4); - vs2 = __lsx_vadd_w(vs2, vs3); - - adler0 = partial_hsum(vs1) % BASE; - adler1 = hsum(vs2) % BASE; - } - - /* If this is true, there's fewer than 16 elements remaining */ - if (len) { - goto rem_peel; - } - - return adler0 | (adler1 << 16); -} - -Z_INTERNAL uint32_t adler32_lsx(uint32_t adler, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, NULL, src, len, 0); -} - -Z_INTERNAL uint32_t adler32_copy_lsx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, dst, src, len, 1); -} - -#endif diff --git a/modules/zlib/src/arch/loongarch/chunkset_lasx.c b/modules/zlib/src/arch/loongarch/chunkset_lasx.c deleted file mode 100644 index 7819ec4c17..0000000000 --- a/modules/zlib/src/arch/loongarch/chunkset_lasx.c +++ /dev/null @@ -1,126 +0,0 @@ -/* chunkset_lasx.c -- LASX inline functions to copy small data chunks, based on Intel AVX2 implementation - * Copyright (C) 2025 Vladislav Shchapov - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef LOONGARCH_LASX - -#include "zbuild.h" -#include "zsanitizer.h" -#include "zmemory.h" - -#include -#include "lasxintrin_ext.h" -#include "lsxintrin_ext.h" - -#include "arch/shared/chunk_256bit_perm_idx_lut.h" - -typedef __m256i chunk_t; -typedef __m128i halfchunk_t; - -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 -#define HAVE_CHUNKMEMSET_16 -#define HAVE_CHUNK_MAG -#define HAVE_HALF_CHUNK - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - *chunk = __lasx_xvreplgr2vr_h(zng_memread_2(from)); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - *chunk = __lasx_xvreplgr2vr_w(zng_memread_4(from)); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = __lasx_xvreplgr2vr_d(zng_memread_8(from)); -} - -static inline void chunkmemset_16(uint8_t *from, chunk_t *chunk) { - *chunk = lasx_broadcast_128(__lsx_vld(from, 0)); -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = __lasx_xvld(s, 0); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - __lasx_xvst(*chunk, out, 0); -} - -static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - __m256i ret_vec; - /* While technically we only need to read 4 or 8 bytes into this vector register for a lot of cases, GCC is - * compiling this to a shared load for all branches, preferring the simpler code. Given that the buf value isn't in - * GPRs to begin with the 256 bit load is _probably_ just as inexpensive */ - *chunk_rem = lut_rem.remval; - - /* See note in chunkset_ssse3.c for why this is ok */ - __msan_unpoison(buf + dist, 32 - dist); - - if (dist < 16) { - /* This simpler case still requires us to shuffle in 128 bit lanes, so we must apply a static offset after - * broadcasting the first vector register to both halves. This is _marginally_ faster than doing two separate - * shuffles and combining the halves later */ - __m256i perm_vec = __lasx_xvld(permute_table+lut_rem.idx, 0); - __m128i ret_vec0 = __lsx_vld(buf, 0); - ret_vec = __lasx_concat_128(ret_vec0, ret_vec0); - ret_vec = lasx_shuffle_b(ret_vec, perm_vec); - } else { - __m128i ret_vec0 = __lsx_vld(buf, 0); - __m128i ret_vec1 = __lsx_vld(buf, 16); - /* Take advantage of the fact that only the latter half of the 256 bit vector will actually differ */ - __m128i perm_vec1 = __lsx_vld(permute_table + lut_rem.idx, 0); - __m128i xlane_permutes = __lsx_vslt_b(perm_vec1, __lsx_vreplgr2vr_b(16)); - __m128i xlane_res = lsx_shuffle_b(ret_vec0, perm_vec1); - /* Since we can't wrap twice, we can simply keep the later half exactly how it is instead of having to _also_ - * shuffle those values */ - __m128i latter_half = __lsx_vbitsel_v(ret_vec1, xlane_res, xlane_permutes); - ret_vec = __lasx_concat_128(ret_vec0, latter_half); - } - - return ret_vec; -} - -static inline void loadhalfchunk(uint8_t const *s, halfchunk_t *chunk) { - *chunk = __lsx_vld(s, 0); -} - -static inline void storehalfchunk(uint8_t *out, halfchunk_t *chunk) { - __lsx_vst(*chunk, out, 0); -} - -static inline chunk_t halfchunk2whole(halfchunk_t *chunk) { - /* We zero extend mostly to appease some memory sanitizers. These bytes are ultimately - * unlikely to be actually written or read from */ - return lasx_zext_128(*chunk); -} - -static inline halfchunk_t GET_HALFCHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - __m128i perm_vec, ret_vec; - __msan_unpoison(buf + dist, 16 - dist); - ret_vec = __lsx_vld(buf, 0); - *chunk_rem = half_rem_vals[dist - 3]; - - perm_vec = __lsx_vld(permute_table + lut_rem.idx, 0); - ret_vec = lsx_shuffle_b(ret_vec, perm_vec); - - return ret_vec; -} - -#define CHUNKSIZE chunksize_lasx -#define CHUNKCOPY chunkcopy_lasx -#define CHUNKUNROLL chunkunroll_lasx -#define CHUNKMEMSET chunkmemset_lasx -#define CHUNKMEMSET_SAFE chunkmemset_safe_lasx - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_lasx - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/loongarch/chunkset_lsx.c b/modules/zlib/src/arch/loongarch/chunkset_lsx.c deleted file mode 100644 index 9d772cade1..0000000000 --- a/modules/zlib/src/arch/loongarch/chunkset_lsx.c +++ /dev/null @@ -1,74 +0,0 @@ -/* chunkset_lsx.c -- LSX inline functions to copy small data chunks, based on Intel SSSE3 implementation - * Copyright (C) 2025 Vladislav Shchapov - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef LOONGARCH_LSX - -#include "zbuild.h" -#include "zsanitizer.h" -#include "zmemory.h" - -#include -#include "lsxintrin_ext.h" -#include "arch/shared/chunk_128bit_perm_idx_lut.h" - -typedef __m128i chunk_t; - -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 -#define HAVE_CHUNK_MAG - - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - *chunk = __lsx_vreplgr2vr_h(zng_memread_2(from)); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - *chunk = __lsx_vreplgr2vr_w(zng_memread_4(from)); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = __lsx_vreplgr2vr_d(zng_memread_8(from)); -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = __lsx_vld(s, 0); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - __lsx_vst(*chunk, out, 0); -} - -static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - __m128i perm_vec, ret_vec; - /* Important to note: - * This is _not_ to subvert the memory sanitizer but to instead unpoison some - * bytes we willingly and purposefully load uninitialized that we swizzle over - * in a vector register, anyway. If what we assume is wrong about what is used, - * the memory sanitizer will still usefully flag it */ - __msan_unpoison(buf + dist, 16 - dist); - ret_vec = __lsx_vld(buf, 0); - *chunk_rem = lut_rem.remval; - - perm_vec = __lsx_vld(permute_table + lut_rem.idx, 0); - ret_vec = lsx_shuffle_b(ret_vec, perm_vec); - - return ret_vec; -} - -#define CHUNKSIZE chunksize_lsx -#define CHUNKMEMSET chunkmemset_lsx -#define CHUNKMEMSET_SAFE chunkmemset_safe_lsx -#define CHUNKCOPY chunkcopy_lsx -#define CHUNKUNROLL chunkunroll_lsx - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_lsx - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/loongarch/compare256_lasx.c b/modules/zlib/src/arch/loongarch/compare256_lasx.c deleted file mode 100644 index 683d866fdc..0000000000 --- a/modules/zlib/src/arch/loongarch/compare256_lasx.c +++ /dev/null @@ -1,60 +0,0 @@ -/* compare256_lasx.c -- LASX version of compare256, based on Intel AVX2 implementation - * Copyright Mika T. Lindqvist - * Copyright (C) 2025 Vladislav Shchapov - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zendian.h" -#include "zmemory.h" -#include "deflate.h" -#include "fallback_builtins.h" - -#ifdef LOONGARCH_LASX - -#include -#include "lasxintrin_ext.h" - -static inline uint32_t compare256_lasx_static(const uint8_t *src0, const uint8_t *src1) { - uint32_t len = 0; - - do { - __m256i ymm_src0, ymm_src1, ymm_cmp; - ymm_src0 = __lasx_xvld(src0, 0); - ymm_src1 = __lasx_xvld(src1, 0); - ymm_cmp = __lasx_xvseq_b(ymm_src0, ymm_src1); /* non-identical bytes = 00, identical bytes = FF */ - unsigned mask = (unsigned)lasx_movemask_b(ymm_cmp); - if (mask != 0xFFFFFFFF) - return len + zng_ctz32(~mask); /* Invert bits so identical = 0 */ - - src0 += 32, src1 += 32, len += 32; - - ymm_src0 = __lasx_xvld(src0, 0); - ymm_src1 = __lasx_xvld(src1, 0); - ymm_cmp = __lasx_xvseq_b(ymm_src0, ymm_src1); - mask = (unsigned)lasx_movemask_b(ymm_cmp); - if (mask != 0xFFFFFFFF) - return len + zng_ctz32(~mask); - - src0 += 32, src1 += 32, len += 32; - } while (len < 256); - - return 256; -} - -Z_INTERNAL uint32_t compare256_lasx(const uint8_t *src0, const uint8_t *src1) { - return compare256_lasx_static(src0, src1); -} - -#define LONGEST_MATCH longest_match_lasx -#define COMPARE256 compare256_lasx_static - -#include "match_tpl.h" - -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_lasx -#define COMPARE256 compare256_lasx_static - -#include "match_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/loongarch/compare256_lsx.c b/modules/zlib/src/arch/loongarch/compare256_lsx.c deleted file mode 100644 index 292e8837bb..0000000000 --- a/modules/zlib/src/arch/loongarch/compare256_lsx.c +++ /dev/null @@ -1,88 +0,0 @@ -/* compare256_lsx.c -- LSX version of compare256, based on Intel SSE implementation - * Copyright Adam Stylinski - * Copyright (C) 2025 Vladislav Shchapov - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zendian.h" -#include "zmemory.h" -#include "deflate.h" -#include "fallback_builtins.h" - -#ifdef LOONGARCH_LSX - -#include -#include "lsxintrin_ext.h" - -static inline uint32_t compare256_lsx_static(const uint8_t *src0, const uint8_t *src1) { - __m128i xmm_src0, xmm_src1, xmm_cmp; - - /* Do the first load unaligned, than all subsequent ones we have at least - * one aligned load. Sadly aligning both loads is probably unrealistic */ - xmm_src0 = __lsx_vld(src0, 0); - xmm_src1 = __lsx_vld(src1, 0); - xmm_cmp = __lsx_vseq_b(xmm_src0, xmm_src1); - - unsigned mask = (unsigned)lsx_movemask_b(xmm_cmp); - - /* Compiler _may_ turn this branch into a ptest + movemask, - * since a lot of those uops are shared and fused */ - if (mask != 0xFFFF) - return zng_ctz32(~mask); - - const uint8_t *last0 = src0 + 240; - const uint8_t *last1 = src1 + 240; - - int align_offset = ((uintptr_t)src0) & 15; - int align_adv = 16 - align_offset; - uint32_t len = align_adv; - - src0 += align_adv; - src1 += align_adv; - - for (int i = 0; i < 15; i++) { - xmm_src0 = __lsx_vld(src0, 0); - xmm_src1 = __lsx_vld(src1, 0); - xmm_cmp = __lsx_vseq_b(xmm_src0, xmm_src1); - - mask = (unsigned)lsx_movemask_b(xmm_cmp); - - /* Compiler _may_ turn this branch into a ptest + movemask, - * since a lot of those uops are shared and fused */ - if (mask != 0xFFFF) - return len + zng_ctz32(~mask); - - len += 16, src0 += 16, src1 += 16; - } - - if (align_offset) { - xmm_src0 = __lsx_vld(last0, 0); - xmm_src1 = __lsx_vld(last1, 0); - xmm_cmp = __lsx_vseq_b(xmm_src0, xmm_src1); - - mask = (unsigned)lsx_movemask_b(xmm_cmp); - - if (mask != 0xFFFF) - return 240 + zng_ctz32(~mask); - } - - return 256; -} - -Z_INTERNAL uint32_t compare256_lsx(const uint8_t *src0, const uint8_t *src1) { - return compare256_lsx_static(src0, src1); -} - -#define LONGEST_MATCH longest_match_lsx -#define COMPARE256 compare256_lsx_static - -#include "match_tpl.h" - -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_lsx -#define COMPARE256 compare256_lsx_static - -#include "match_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/loongarch/crc32_la.c b/modules/zlib/src/arch/loongarch/crc32_la.c deleted file mode 100644 index 6bff320aaf..0000000000 --- a/modules/zlib/src/arch/loongarch/crc32_la.c +++ /dev/null @@ -1,31 +0,0 @@ -/* crc32_la.c - LoongArch version of crc32 - * Copyright (C) 2025 Vladislav Shchapov - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef LOONGARCH_CRC - -#include "zbuild.h" - -#include - -#define Z_TARGET_CRC -#define CRC32B(crc, val) (uint32_t)__crc_w_b_w((char)(val), (int)(crc)) -#define CRC32H(crc, val) (uint32_t)__crc_w_h_w((short)(val), (int)(crc)) -#define CRC32W(crc, val) (uint32_t)__crc_w_w_w((int)(val), (int)(crc)) -#define CRC32D(crc, val) (uint32_t)__crc_w_d_w((long int)(val), (int)(crc)) - -#include "arch/shared/crc32_hw_common_tpl.h" - -#include "arch/shared/crc32_hw_copy_impl_tpl.h" - - -Z_INTERNAL uint32_t crc32_loongarch64(uint32_t crc, const uint8_t *buf, size_t len) { - return crc32_hw_copy_impl(crc, NULL, buf, len, 0); -} - -Z_INTERNAL uint32_t crc32_copy_loongarch64(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - return crc32_hw_copy_impl(crc, dst, src, len, 1); -} - -#endif diff --git a/modules/zlib/src/arch/loongarch/lasxintrin_ext.h b/modules/zlib/src/arch/loongarch/lasxintrin_ext.h deleted file mode 100644 index b1e72cff86..0000000000 --- a/modules/zlib/src/arch/loongarch/lasxintrin_ext.h +++ /dev/null @@ -1,61 +0,0 @@ -/* lasxintrin_ext.h - * Copyright (C) 2025 Vladislav Shchapov - * For conditions of distribution and use, see copyright notice in zlib.h - */ -#ifndef LASXINTRIN_EXT_H -#define LASXINTRIN_EXT_H - -#include -#include - - -static inline __m256i lasx_zext_128(__m128i src) { -#ifdef __loongarch_asx_sx_conv - return __lasx_insert_128_lo(__lasx_xvldi(0), src); -#else - __m256i dest = __lasx_xvldi(0); - __asm__ volatile ("xvpermi.q %u0,%u2,0x30\n" : "=f"(dest) : "0"(dest), "f"(src)); - return dest; -#endif -} - -#ifndef __loongarch_asx_sx_conv -static inline __m256i __lasx_concat_128(__m128i lo, __m128i hi) { - __m256i dest; - __asm__ volatile ("xvpermi.q %u0,%u2,0x02\n" : "=f"(dest) : "0"(lo), "f"(hi)); - return dest; -} -#endif - -static inline __m256i lasx_broadcast_128(__m128i in) { - return __lasx_concat_128(in, in); -} - -static inline __m256i lasx_sad_bu(__m256i a, __m256i b) { - __m256i tmp = __lasx_xvabsd_bu(a, b); - tmp = __lasx_xvhaddw_hu_bu(tmp, tmp); - tmp = __lasx_xvhaddw_wu_hu(tmp, tmp); - return __lasx_xvhaddw_du_wu(tmp, tmp); -} - -static inline __m256i lasx_maddubs_w_h(__m256i a, __m256i b) { - return __lasx_xvsadd_h(__lasx_xvmulwod_h_bu_b(a, b), __lasx_xvmulwev_h_bu_b(a, b)); -} - -static inline __m256i lasx_madd_w_h(__m256i a, __m256i b) { - return __lasx_xvmaddwod_w_h(__lasx_xvmulwev_w_h(a, b), a, b); -} - -static inline int lasx_movemask_b(__m256i v) { - v = __lasx_xvmskltz_b(v); - return __lasx_xvpickve2gr_w(v, 0) | (__lasx_xvpickve2gr_w(v, 4) << 16); -} - -/* See: lsx_shuffle_b */ -static inline __m256i lasx_shuffle_b(__m256i a, __m256i b) { - __m256i msb_mask = __lasx_xvslti_b(b, 0); - __m256i dst = __lasx_xvshuf_b(a, a, __lasx_xvandi_b(b, 0xF)); - return __lasx_xvand_v(dst, __lasx_xvnor_v(msb_mask, msb_mask)); -} - -#endif // include guard LASXINTRIN_EXT_H diff --git a/modules/zlib/src/arch/loongarch/loongarch_features.c b/modules/zlib/src/arch/loongarch/loongarch_features.c deleted file mode 100644 index bedf8499f7..0000000000 --- a/modules/zlib/src/arch/loongarch/loongarch_features.c +++ /dev/null @@ -1,31 +0,0 @@ -/* loongarch_features.c -- check for LoongArch features. - * - * Copyright (C) 2025 Vladislav Shchapov - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef LOONGARCH_FEATURES - -#include "zbuild.h" -#include "loongarch_features.h" - -#include - -/* - * https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html - * - * Word number Bit number Annotation Implication - * 0x1 25 CRC 1 indicates support for CRC instruction - * 0x1 6 LSX 1 indicates support for 128-bit vector extension - * 0x1 7 LASX 1 indicates support for 256-bit vector expansion - */ - -void Z_INTERNAL loongarch_check_features(struct loongarch_cpu_features *features) { - unsigned int w1 = __cpucfg(0x1); - features->has_crc = w1 & 0x2000000; - features->has_lsx = w1 & 0x40; - features->has_lasx = w1 & 0x80; -} - -#endif diff --git a/modules/zlib/src/arch/loongarch/loongarch_features.h b/modules/zlib/src/arch/loongarch/loongarch_features.h deleted file mode 100644 index 27c90b14b3..0000000000 --- a/modules/zlib/src/arch/loongarch/loongarch_features.h +++ /dev/null @@ -1,19 +0,0 @@ -/* loongarch_features.h -- check for LoongArch features. - * - * Copyright (C) 2025 Vladislav Shchapov - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef LOONGARCH_FEATURES_H_ -#define LOONGARCH_FEATURES_H_ - -struct loongarch_cpu_features { - int has_crc; - int has_lsx; - int has_lasx; -}; - -void Z_INTERNAL loongarch_check_features(struct loongarch_cpu_features *features); - -#endif /* LOONGARCH_FEATURES_H_ */ diff --git a/modules/zlib/src/arch/loongarch/loongarch_functions.h b/modules/zlib/src/arch/loongarch/loongarch_functions.h deleted file mode 100644 index 8a6a387c43..0000000000 --- a/modules/zlib/src/arch/loongarch/loongarch_functions.h +++ /dev/null @@ -1,97 +0,0 @@ -/* loongarch_functions.h -- LoongArch implementations for arch-specific functions. - * - * Copyright (C) 2025 Vladislav Shchapov - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef LOONGARCH_FUNCTIONS_H_ -#define LOONGARCH_FUNCTIONS_H_ - -#include "loongarch_natives.h" - -#ifdef LOONGARCH_CRC -uint32_t crc32_loongarch64(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_loongarch64(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif - -#ifndef LOONGARCH_CRC_NATIVE -# define CRC32_BRAID_FALLBACK -#endif - -#ifdef LOONGARCH_LSX -uint32_t adler32_lsx(uint32_t adler, const uint8_t *src, size_t len); -uint32_t adler32_copy_lsx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -uint8_t* chunkmemset_safe_lsx(uint8_t *out, uint8_t *from, size_t len, size_t left); -uint32_t compare256_lsx(const uint8_t *src0, const uint8_t *src1); -void inflate_fast_lsx(PREFIX3(stream) *strm, uint32_t start); -uint32_t longest_match_lsx(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_lsx(deflate_state *const s, uint32_t cur_match); -void slide_hash_lsx(deflate_state *s); -#endif - -#ifndef LOONGARCH_LSX_NATIVE -# define ADLER32_FALLBACK -# define CHUNKSET_FALLBACK -# define COMPARE256_FALLBACK -# define SLIDE_HASH_FALLBACK -#endif - -#ifdef LOONGARCH_LASX -uint32_t adler32_lasx(uint32_t adler, const uint8_t *src, size_t len); -uint32_t adler32_copy_lasx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -uint8_t* chunkmemset_safe_lasx(uint8_t *out, uint8_t *from, size_t len, size_t left); -uint32_t compare256_lasx(const uint8_t *src0, const uint8_t *src1); -void inflate_fast_lasx(PREFIX3(stream) *strm, uint32_t start); -uint32_t longest_match_lasx(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_lasx(deflate_state *const s, uint32_t cur_match); -void slide_hash_lasx(deflate_state *s); -#endif - -#ifdef DISABLE_RUNTIME_CPU_DETECTION -// LOONGARCH - CRC32 -# ifdef LOONGARCH_CRC_NATIVE -# undef native_crc32 -# define native_crc32 crc32_loongarch64 -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_loongarch64 -# endif -# ifdef LOONGARCH_LSX_NATIVE -# undef native_adler32 -# define native_adler32 adler32_lsx -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_lsx -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_lsx -# undef native_compare256 -# define native_compare256 compare256_lsx -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_lsx -# undef native_longest_match -# define native_longest_match longest_match_lsx -# undef native_longest_match_roll -# define native_longest_match_roll longest_match_roll_lsx -# undef native_slide_hash -# define native_slide_hash slide_hash_lsx -# endif -# ifdef LOONGARCH_LASX_NATIVE -# undef native_adler32 -# define native_adler32 adler32_lasx -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_lasx -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_lasx -# undef native_compare256 -# define native_compare256 compare256_lasx -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_lasx -# undef native_longest_match -# define native_longest_match longest_match_lasx -# undef native_longest_match_roll -# define native_longest_match_roll longest_match_roll_lasx -# undef native_slide_hash -# define native_slide_hash slide_hash_lasx -# endif -#endif - -#endif /* LOONGARCH_FUNCTIONS_H_ */ diff --git a/modules/zlib/src/arch/loongarch/loongarch_natives.h b/modules/zlib/src/arch/loongarch/loongarch_natives.h deleted file mode 100644 index 35f6d3c7bd..0000000000 --- a/modules/zlib/src/arch/loongarch/loongarch_natives.h +++ /dev/null @@ -1,25 +0,0 @@ -/* loongarch_natives.h -- LoongArch compile-time feature detection macros. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef LOONGARCH_NATIVES_H_ -#define LOONGARCH_NATIVES_H_ - -#if defined(__loongarch__) -// All known CPUs have crc instructions -# ifdef LOONGARCH_CRC -# define LOONGARCH_CRC_NATIVE -# endif -#endif -#if defined(__loongarch_sx) -# ifdef LOONGARCH_LSX -# define LOONGARCH_LSX_NATIVE -# endif -#endif -#if defined(__loongarch_asx) -# ifdef LOONGARCH_LASX -# define LOONGARCH_LASX_NATIVE -# endif -#endif - -#endif /* LOONGARCH_NATIVES_H_ */ diff --git a/modules/zlib/src/arch/loongarch/lsxintrin_ext.h b/modules/zlib/src/arch/loongarch/lsxintrin_ext.h deleted file mode 100644 index 0a0503b9f9..0000000000 --- a/modules/zlib/src/arch/loongarch/lsxintrin_ext.h +++ /dev/null @@ -1,33 +0,0 @@ -/* lsxintrin_ext.h - * Copyright (C) 2025 Vladislav Shchapov - * For conditions of distribution and use, see copyright notice in zlib.h - */ -#ifndef LSXINTRIN_EXT_H -#define LSXINTRIN_EXT_H - -#include - - -static inline __m128i lsx_sad_bu(__m128i a, __m128i b) { - __m128i tmp = __lsx_vabsd_bu(a, b); - tmp = __lsx_vhaddw_hu_bu(tmp, tmp); - tmp = __lsx_vhaddw_wu_hu(tmp, tmp); - return __lsx_vhaddw_du_wu(tmp, tmp); -} - -static inline int lsx_movemask_b(__m128i v) { - return __lsx_vpickve2gr_w(__lsx_vmskltz_b(v), 0); -} - -static inline __m128i lsx_shuffle_b(__m128i a, __m128i b) { - /* most significant bit is set - negative 8-bit integer */ - __m128i msb_mask = __lsx_vslti_b(b, 0); - - /* shuffle, clear msb in indices vector b */ - __m128i dst = __lsx_vshuf_b(a, a, __lsx_vandi_b(b, 0xF)); - - /* invert and apply mask - clear dst-element if b-msb is set */ - return __lsx_vand_v(dst, __lsx_vnor_v(msb_mask, msb_mask)); -} - -#endif // include guard LSXINTRIN_EXT_H diff --git a/modules/zlib/src/arch/loongarch/slide_hash_lasx.c b/modules/zlib/src/arch/loongarch/slide_hash_lasx.c deleted file mode 100644 index f464779090..0000000000 --- a/modules/zlib/src/arch/loongarch/slide_hash_lasx.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * LASX optimized hash slide, based on Intel AVX2 implementation - * - * Copyright (C) 2017 Intel Corporation - * Copyright (C) 2025 Vladislav Shchapov - * Authors: - * Arjan van de Ven - * Jim Kukunas - * Mika T. Lindqvist - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef LOONGARCH_LASX - -#include "zbuild.h" -#include "deflate.h" - -#include - -static inline void slide_hash_chain(Pos *table, uint32_t entries, const __m256i wsize) { - table += entries; - table -= 32; - - do { - __m256i value1, value2, result1, result2; - - value1 = __lasx_xvld(table, 0); - value2 = __lasx_xvld(table, 32); - result1 = __lasx_xvssub_hu(value1, wsize); - result2 = __lasx_xvssub_hu(value2, wsize); - __lasx_xvst(result1, table, 0); - __lasx_xvst(result2, table, 32); - - table -= 32; - entries -= 32; - } while (entries > 0); -} - -Z_INTERNAL void slide_hash_lasx(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - const __m256i ymm_wsize = __lasx_xvreplgr2vr_h((short)wsize); - - slide_hash_chain(s->head, HASH_SIZE, ymm_wsize); - slide_hash_chain(s->prev, wsize, ymm_wsize); -} - -#endif diff --git a/modules/zlib/src/arch/loongarch/slide_hash_lsx.c b/modules/zlib/src/arch/loongarch/slide_hash_lsx.c deleted file mode 100644 index f4c94ea70d..0000000000 --- a/modules/zlib/src/arch/loongarch/slide_hash_lsx.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * LSX optimized hash slide, based on Intel SSE implementation - * - * Copyright (C) 2017 Intel Corporation - * Copyright (C) 2025 Vladislav Shchapov - * Authors: - * Arjan van de Ven - * Jim Kukunas - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef LOONGARCH_LSX - -#include "zbuild.h" -#include "deflate.h" - -#include -#include - -static inline void slide_hash_chain(Pos *table, uint32_t entries, const __m128i wsize) { - table += entries; - table -= 16; - - /* ZALLOC allocates this pointer unless the user chose a custom allocator. - * Our alloc function is aligned to 64 byte boundaries */ - do { - __m128i value0, value1, result0, result1; - - value0 = __lsx_vld(table, 0); - value1 = __lsx_vld(table, 16); - result0 = __lsx_vssub_hu(value0, wsize); - result1 = __lsx_vssub_hu(value1, wsize); - __lsx_vst(result0, table, 0); - __lsx_vst(result1, table, 16); - - table -= 16; - entries -= 16; - } while (entries > 0); -} - -Z_INTERNAL void slide_hash_lsx(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - const __m128i xmm_wsize = __lsx_vreplgr2vr_h((short)wsize); - - assert(((uintptr_t)s->head & 15) == 0); - assert(((uintptr_t)s->prev & 15) == 0); - - slide_hash_chain(s->head, HASH_SIZE, xmm_wsize); - slide_hash_chain(s->prev, wsize, xmm_wsize); -} - -#endif diff --git a/modules/zlib/src/arch/power/Makefile.in b/modules/zlib/src/arch/power/Makefile.in deleted file mode 100644 index e2bec5e510..0000000000 --- a/modules/zlib/src/arch/power/Makefile.in +++ /dev/null @@ -1,93 +0,0 @@ -# Makefile for POWER-specific files -# Copyright (C) 2020 Matheus Castanho , IBM -# Copyright (C) 2021 Mika T. Lindqvist -# For conditions of distribution and use, see copyright notice in zlib.h - -CC= -CFLAGS= -SFLAGS= -INCLUDES= -SUFFIX= - -P8FLAGS=-mcpu=power8 -P9FLAGS=-mcpu=power9 -PPCFLAGS=-maltivec -NOLTOFLAG= - -SRCDIR=. -SRCTOP=../.. -TOPDIR=$(SRCTOP) - -all: power_features.o \ - power_features.lo \ - adler32_power8.o \ - adler32_power8.lo \ - adler32_vmx.o \ - adler32_vmx.lo \ - chunkset_power8.o \ - chunkset_power8.lo \ - compare256_power9.o \ - compare256_power9.lo \ - crc32_power8.o \ - crc32_power8.lo \ - slide_hash_power8.o \ - slide_hash_power8.lo \ - slide_hash_vmx.o \ - slide_hash_vmx.lo - -power_features.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/power_features.c - -power_features.lo: - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/power_features.c - -adler32_power8.o: - $(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_power8.c - -adler32_power8.lo: - $(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_power8.c - -adler32_vmx.o: - $(CC) $(CFLAGS) $(PPCFLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_vmx.c - -adler32_vmx.lo: - $(CC) $(SFLAGS) $(PPCFLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_vmx.c - -chunkset_power8.o: - $(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_power8.c - -chunkset_power8.lo: - $(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_power8.c - -compare256_power9.o: - $(CC) $(CFLAGS) $(P9FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_power9.c - -compare256_power9.lo: - $(CC) $(SFLAGS) $(P9FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_power9.c - -crc32_power8.o: - $(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_power8.c - -crc32_power8.lo: - $(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_power8.c - -slide_hash_power8.o: - $(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_power8.c - -slide_hash_power8.lo: - $(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_power8.c - -slide_hash_vmx.o: - $(CC) $(CFLAGS) ${PPCFLAGS} $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vmx.c - -slide_hash_vmx.lo: - $(CC) $(SFLAGS) ${PPCFLAGS} $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vmx.c - -mostlyclean: clean -clean: - rm -f *.o *.lo *~ - rm -rf objs - rm -f *.gcda *.gcno *.gcov - -distclean: clean - rm -f Makefile diff --git a/modules/zlib/src/arch/power/adler32_power8.c b/modules/zlib/src/arch/power/adler32_power8.c deleted file mode 100644 index 39b3cf399c..0000000000 --- a/modules/zlib/src/arch/power/adler32_power8.c +++ /dev/null @@ -1,160 +0,0 @@ -/* Adler32 for POWER8 using VSX instructions. - * Copyright (C) 2020 IBM Corporation - * Author: Rogerio Alves - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Calculate adler32 checksum for 16 bytes at once using POWER8+ VSX (vector) - * instructions. - * - * If adler32 do 1 byte at time on the first iteration s1 is s1_0 (_n means - * iteration n) is the initial value of adler - at start _0 is 1 unless - * adler initial value is different than 1. So s1_1 = s1_0 + c[0] after - * the first calculation. For the iteration s1_2 = s1_1 + c[1] and so on. - * Hence, for iteration N, s1_N = s1_(N-1) + c[N] is the value of s1 on - * after iteration N. - * - * Therefore, for s2 and iteration N, s2_N = s2_0 + N*s1_N + N*c[0] + - * N-1*c[1] + ... + c[N] - * - * In a more general way: - * - * s1_N = s1_0 + sum(i=1 to N)c[i] - * s2_N = s2_0 + N*s1 + sum (i=1 to N)(N-i+1)*c[i] - * - * Where s1_N, s2_N are the values for s1, s2 after N iterations. So if we - * can process N-bit at time we can do this at once. - * - * Since VSX can support 16-bit vector instructions, we can process - * 16-bit at time using N = 16 we have: - * - * s1 = s1_16 = s1_(16-1) + c[16] = s1_0 + sum(i=1 to 16)c[i] - * s2 = s2_16 = s2_0 + 16*s1 + sum(i=1 to 16)(16-i+1)*c[i] - * - * After the first iteration we calculate the adler32 checksum for 16 bytes. - * - * For more background about adler32 please check the RFC: - * https://www.ietf.org/rfc/rfc1950.txt - */ - -#ifdef POWER8_VSX - -#include "zbuild.h" -#include "adler32_p.h" - -#include - -/* Vector across sum unsigned int (saturate). */ -static inline vector unsigned int vec_sumsu(vector unsigned int __a, vector unsigned int __b) { - __b = vec_sld(__a, __a, 8); - __b = vec_add(__b, __a); - __a = vec_sld(__b, __b, 4); - __a = vec_add(__a, __b); - - return __a; -} - -Z_FORCEINLINE static uint32_t adler32_impl(uint32_t adler, const uint8_t *buf, size_t len) { - uint32_t s1 = adler & 0xffff; - uint32_t s2 = (adler >> 16) & 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (UNLIKELY(len == 1)) - return adler32_copy_tail(s1, NULL, buf, 1, s2, 1, 1, 0); - - /* This is faster than VSX code for len < 64. */ - if (len < 64) - return adler32_copy_tail(s1, NULL, buf, len, s2, 1, 63, 0); - - /* Use POWER VSX instructions for len >= 64. */ - const vector unsigned int v_zeros = { 0 }; - const vector unsigned char v_mul = {16, 15, 14, 13, 12, 11, 10, 9, 8, 7, - 6, 5, 4, 3, 2, 1}; - const vector unsigned char vsh = vec_splat_u8(4); - const vector unsigned int vmask = {0xffffffff, 0x0, 0x0, 0x0}; - vector unsigned int vs1 = { 0 }; - vector unsigned int vs2 = { 0 }; - vector unsigned int vs1_save = { 0 }; - vector unsigned int vsum1, vsum2; - vector unsigned char vbuf; - int n; - - vs1[0] = s1; - vs2[0] = s2; - - /* Do length bigger than NMAX in blocks of NMAX size. */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; - do { - vbuf = vec_xl(0, (unsigned char *) buf); - vsum1 = vec_sum4s(vbuf, v_zeros); /* sum(i=1 to 16) buf[i]. */ - /* sum(i=1 to 16) buf[i]*(16-i+1). */ - vsum2 = vec_msum(vbuf, v_mul, v_zeros); - /* Save vs1. */ - vs1_save = vec_add(vs1_save, vs1); - /* Accumulate the sums. */ - vs1 = vec_add(vsum1, vs1); - vs2 = vec_add(vsum2, vs2); - - buf += 16; - } while (--n); - /* Once each block of NMAX size. */ - vs1 = vec_sumsu(vs1, vsum1); - vs1_save = vec_sll(vs1_save, vsh); /* 16*vs1_save. */ - vs2 = vec_add(vs1_save, vs2); - vs2 = vec_sumsu(vs2, vsum2); - - /* vs1[0] = (s1_i + sum(i=1 to 16)buf[i]) mod 65521. */ - vs1[0] = vs1[0] % BASE; - /* vs2[0] = s2_i + 16*s1_save + - sum(i=1 to 16)(16-i+1)*buf[i] mod 65521. */ - vs2[0] = vs2[0] % BASE; - - vs1 = vec_and(vs1, vmask); - vs2 = vec_and(vs2, vmask); - vs1_save = v_zeros; - } - - /* len is less than NMAX one modulo is needed. */ - if (len >= 16) { - while (len >= 16) { - len -= 16; - - vbuf = vec_xl(0, (unsigned char *) buf); - - vsum1 = vec_sum4s(vbuf, v_zeros); /* sum(i=1 to 16) buf[i]. */ - /* sum(i=1 to 16) buf[i]*(16-i+1). */ - vsum2 = vec_msum(vbuf, v_mul, v_zeros); - /* Save vs1. */ - vs1_save = vec_add(vs1_save, vs1); - /* Accumulate the sums. */ - vs1 = vec_add(vsum1, vs1); - vs2 = vec_add(vsum2, vs2); - - buf += 16; - } - /* Since the size will be always less than NMAX we do this once. */ - vs1 = vec_sumsu(vs1, vsum1); - vs1_save = vec_sll(vs1_save, vsh); /* 16*vs1_save. */ - vs2 = vec_add(vs1_save, vs2); - vs2 = vec_sumsu(vs2, vsum2); - } - /* Copy result back to s1, s2 (mod 65521). */ - s1 = vs1[0] % BASE; - s2 = vs2[0] % BASE; - - /* Process tail (len < 16). */ - return adler32_copy_tail(s1, NULL, buf, len, s2, len != 0, 15, 0); -} - -Z_INTERNAL uint32_t adler32_power8(uint32_t adler, const uint8_t *buf, size_t len) { - return adler32_impl(adler, buf, len); -} - -/* VSX/VMX stores can have higher latency than optimized memcpy on POWER8+ */ -Z_INTERNAL uint32_t adler32_copy_power8(uint32_t adler, uint8_t *dst, const uint8_t *buf, size_t len) { - adler = adler32_impl(adler, buf, len); - memcpy(dst, buf, len); - return adler; -} -#endif /* POWER8_VSX */ diff --git a/modules/zlib/src/arch/power/adler32_vmx.c b/modules/zlib/src/arch/power/adler32_vmx.c deleted file mode 100644 index 5171bab35b..0000000000 --- a/modules/zlib/src/arch/power/adler32_vmx.c +++ /dev/null @@ -1,168 +0,0 @@ -/* adler32_vmx.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011 Mark Adler - * Copyright (C) 2017-2023 Mika T. Lindqvist - * Copyright (C) 2021 Adam Stylinski - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef PPC_VMX - -#include "zbuild.h" -#include "zendian.h" -#include "adler32_p.h" - -#include - -#define vmx_zero() (vec_splat_u32(0)) - -static void vmx_accum32(uint32_t *s, const uint8_t *buf, size_t len) { - /* Different taps for the separable components of sums */ - const vector unsigned char t0 = {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49}; - const vector unsigned char t1 = {48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33}; - const vector unsigned char t2 = {32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17}; - const vector unsigned char t3 = {16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; - /* As silly and inefficient as it seems, creating 1 permutation vector to permute - * a 2 element vector from a single load + a subsequent shift is just barely faster - * than doing 2 indexed insertions into zero initialized vectors from unaligned memory. */ - const vector unsigned char s0_perm = {0, 1, 2, 3, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; - const vector unsigned char shift_vec = vec_sl(vec_splat_u8(8), vec_splat_u8(2)); - vector unsigned int adacc, s2acc; - vector unsigned int pair_vec = vec_ld(0, s); - adacc = vec_perm(pair_vec, pair_vec, s0_perm); -#if BYTE_ORDER == LITTLE_ENDIAN - s2acc = vec_sro(pair_vec, shift_vec); -#else - s2acc = vec_slo(pair_vec, shift_vec); -#endif - - vector unsigned int zero = vmx_zero(); - vector unsigned int s3acc = zero; - vector unsigned int s3acc_0 = zero; - vector unsigned int adacc_prev = adacc; - vector unsigned int adacc_prev_0 = zero; - - vector unsigned int s2acc_0 = zero; - vector unsigned int s2acc_1 = zero; - vector unsigned int s2acc_2 = zero; - - /* Maintain a running sum of a second half, this might help use break yet another - * data dependency bubble in the sum */ - vector unsigned int adacc_0 = zero; - - int num_iter = len / 4; - int rem = len & 3; - - for (int i = 0; i < num_iter; ++i) { - vector unsigned char d0 = vec_ld(0, buf); - vector unsigned char d1 = vec_ld(16, buf); - vector unsigned char d2 = vec_ld(32, buf); - vector unsigned char d3 = vec_ld(48, buf); - - /* The core operation of the loop, basically - * what is being unrolled below */ - adacc = vec_sum4s(d0, adacc); - s3acc = vec_add(s3acc, adacc_prev); - s3acc_0 = vec_add(s3acc_0, adacc_prev_0); - s2acc = vec_msum(t0, d0, s2acc); - - /* interleave dependent sums in here */ - adacc_0 = vec_sum4s(d1, adacc_0); - s2acc_0 = vec_msum(t1, d1, s2acc_0); - adacc = vec_sum4s(d2, adacc); - s2acc_1 = vec_msum(t2, d2, s2acc_1); - s2acc_2 = vec_msum(t3, d3, s2acc_2); - adacc_0 = vec_sum4s(d3, adacc_0); - - adacc_prev = adacc; - adacc_prev_0 = adacc_0; - buf += 64; - } - - adacc = vec_add(adacc, adacc_0); - s3acc = vec_add(s3acc, s3acc_0); - s3acc = vec_sl(s3acc, vec_splat_u32(6)); - - if (rem) { - adacc_prev = vec_add(adacc_prev_0, adacc_prev); - adacc_prev = vec_sl(adacc_prev, vec_splat_u32(4)); - while (rem--) { - vector unsigned char d0 = vec_ld(0, buf); - adacc = vec_sum4s(d0, adacc); - s3acc = vec_add(s3acc, adacc_prev); - s2acc = vec_msum(t3, d0, s2acc); - adacc_prev = vec_sl(adacc, vec_splat_u32(4)); - buf += 16; - } - } - - - /* Sum up independent second sums */ - s2acc = vec_add(s2acc, s2acc_0); - s2acc_2 = vec_add(s2acc_1, s2acc_2); - s2acc = vec_add(s2acc, s2acc_2); - - s2acc = vec_add(s2acc, s3acc); - - adacc = vec_add(adacc, vec_sld(adacc, adacc, 8)); - s2acc = vec_add(s2acc, vec_sld(s2acc, s2acc, 8)); - adacc = vec_add(adacc, vec_sld(adacc, adacc, 4)); - s2acc = vec_add(s2acc, vec_sld(s2acc, s2acc, 4)); - - vec_ste(adacc, 0, s); - vec_ste(s2acc, 0, s+1); -} - -Z_INTERNAL uint32_t adler32_vmx(uint32_t adler, const uint8_t *buf, size_t len) { - /* Split Adler-32 into component sums */ - uint32_t sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (UNLIKELY(len == 1)) - return adler32_copy_tail(adler, NULL, buf, 1, sum2, 1, 1, 0); - - /* in case short lengths are provided, keep it somewhat fast */ - if (UNLIKELY(len < 16)) - return adler32_copy_tail(adler, NULL, buf, len, sum2, 1, 15, 0); - - uint32_t pair[4] ALIGNED_(16); - pair[0] = adler; - pair[1] = sum2; - pair[2] = 0; - pair[3] = 0; - - // Align buffer - size_t align_diff = MIN(ALIGN_DIFF(buf, 16), len); - size_t n = NMAX; - if (align_diff) { - adler32_copy_align(&pair[0], NULL, buf, align_diff, &pair[1], 15, 0); - - buf += align_diff; - len -= align_diff; - n -= align_diff; - } - - while (len >= 16) { - n = MIN(len, n); - - vmx_accum32(pair, buf, n / 16); - pair[0] %= BASE; - pair[1] %= BASE; - - size_t k = (n / 16) * 16; - buf += k; - len -= k; - n = NMAX; - } - - /* Process tail (len < 16). */ - return adler32_copy_tail(pair[0], NULL, buf, len, pair[1], len != 0 || align_diff, 15, 0); -} - -/* VMX stores can have higher latency than optimized memcpy */ -Z_INTERNAL uint32_t adler32_copy_vmx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - adler = adler32_vmx(adler, src, len); - memcpy(dst, src, len); - return adler; -} -#endif diff --git a/modules/zlib/src/arch/power/chunkset_power8.c b/modules/zlib/src/arch/power/chunkset_power8.c deleted file mode 100644 index f9855e677e..0000000000 --- a/modules/zlib/src/arch/power/chunkset_power8.c +++ /dev/null @@ -1,50 +0,0 @@ -/* chunkset_power8.c -- VSX inline functions to copy small data chunks. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef POWER8_VSX - -#include "zbuild.h" -#include "zmemory.h" - -#include - -typedef vector unsigned char chunk_t; - -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - *chunk = (vector unsigned char)vec_splats(zng_memread_2(from)); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - *chunk = (vector unsigned char)vec_splats(zng_memread_4(from)); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = (vector unsigned char)vec_splats((unsigned long long)zng_memread_8(from)); -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = vec_xl(0, s); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - vec_xst(*chunk, 0, out); -} - -#define CHUNKSIZE chunksize_power8 -#define CHUNKCOPY chunkcopy_power8 -#define CHUNKUNROLL chunkunroll_power8 -#define CHUNKMEMSET chunkmemset_power8 -#define CHUNKMEMSET_SAFE chunkmemset_safe_power8 - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_power8 - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/power/compare256_power9.c b/modules/zlib/src/arch/power/compare256_power9.c deleted file mode 100644 index c3e55beddf..0000000000 --- a/modules/zlib/src/arch/power/compare256_power9.c +++ /dev/null @@ -1,68 +0,0 @@ -/* compare256_power9.c - Power9 version of compare256 - * Copyright (C) 2019 Matheus Castanho , IBM - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef POWER9 - -#include "zbuild.h" -#include "zmemory.h" -#include "deflate.h" -#include "zendian.h" - -#include - -/* Older versions of GCC misimplemented semantics for these bit counting builtins. - * https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=3f30f2d1dbb3228b8468b26239fe60c2974ce2ac */ -#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12) -#if BYTE_ORDER == LITTLE_ENDIAN -# define zng_vec_vctzlsbb(vc, len) len = __builtin_vec_vctzlsbb(vc) -#else -# define zng_vec_vctzlsbb(vc, len) len = __builtin_vec_vclzlsbb(vc) -#endif -#else -# define zng_vec_vctzlsbb(vc, len) len = vec_cntlz_lsbb(vc) -#endif - -static inline uint32_t compare256_power9_static(const uint8_t *src0, const uint8_t *src1) { - uint32_t len = 0, cmplen; - - do { - vector unsigned char vsrc0, vsrc1, vc; - - vsrc0 = *((vector unsigned char *)src0); - vsrc1 = *((vector unsigned char *)src1); - - /* Compare 16 bytes at a time. Each byte of vc will be either - * all ones or all zeroes, depending on the result of the comparison. */ - vc = (vector unsigned char)vec_cmpne(vsrc0, vsrc1); - - /* Since the index of matching bytes will contain only zeroes - * on vc (since we used cmpne), counting the number of consecutive - * bytes where LSB == 0 is the same as counting the length of the match. */ - zng_vec_vctzlsbb(vc, cmplen); - if (cmplen != 16) - return len + cmplen; - - src0 += 16, src1 += 16, len += 16; - } while (len < 256); - - return 256; -} - -Z_INTERNAL uint32_t compare256_power9(const uint8_t *src0, const uint8_t *src1) { - return compare256_power9_static(src0, src1); -} - -#define LONGEST_MATCH longest_match_power9 -#define COMPARE256 compare256_power9_static - -#include "match_tpl.h" - -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_power9 -#define COMPARE256 compare256_power9_static - -#include "match_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/power/crc32_constants.h b/modules/zlib/src/arch/power/crc32_constants.h deleted file mode 100644 index 8c8f2153b6..0000000000 --- a/modules/zlib/src/arch/power/crc32_constants.h +++ /dev/null @@ -1,1123 +0,0 @@ -/* Constants table used by crc32_power8.c - * Copyright (C) 2021 IBM Corporation - * - * This file was automatically generated, DO NOT EDIT IT MANUALLY. - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zendian.h" -#include "zbuild.h" - -/* Reduce 262144 kbits to 1024 bits */ -static const __vector unsigned long long vcrc_const[255] ALIGNED_(16) = { -#if BYTE_ORDER == LITTLE_ENDIAN - /* x^261120 mod p(x)` << 1, x^261184 mod p(x)` << 1 */ - { 0x0000000099ea94a8, 0x00000001651797d2 }, - /* x^260096 mod p(x)` << 1, x^260160 mod p(x)` << 1 */ - { 0x00000000945a8420, 0x0000000021e0d56c }, - /* x^259072 mod p(x)` << 1, x^259136 mod p(x)` << 1 */ - { 0x0000000030762706, 0x000000000f95ecaa }, - /* x^258048 mod p(x)` << 1, x^258112 mod p(x)` << 1 */ - { 0x00000001a52fc582, 0x00000001ebd224ac }, - /* x^257024 mod p(x)` << 1, x^257088 mod p(x)` << 1 */ - { 0x00000001a4a7167a, 0x000000000ccb97ca }, - /* x^256000 mod p(x)` << 1, x^256064 mod p(x)` << 1 */ - { 0x000000000c18249a, 0x00000001006ec8a8 }, - /* x^254976 mod p(x)` << 1, x^255040 mod p(x)` << 1 */ - { 0x00000000a924ae7c, 0x000000014f58f196 }, - /* x^253952 mod p(x)` << 1, x^254016 mod p(x)` << 1 */ - { 0x00000001e12ccc12, 0x00000001a7192ca6 }, - /* x^252928 mod p(x)` << 1, x^252992 mod p(x)` << 1 */ - { 0x00000000a0b9d4ac, 0x000000019a64bab2 }, - /* x^251904 mod p(x)` << 1, x^251968 mod p(x)` << 1 */ - { 0x0000000095e8ddfe, 0x0000000014f4ed2e }, - /* x^250880 mod p(x)` << 1, x^250944 mod p(x)` << 1 */ - { 0x00000000233fddc4, 0x000000011092b6a2 }, - /* x^249856 mod p(x)` << 1, x^249920 mod p(x)` << 1 */ - { 0x00000001b4529b62, 0x00000000c8a1629c }, - /* x^248832 mod p(x)` << 1, x^248896 mod p(x)` << 1 */ - { 0x00000001a7fa0e64, 0x000000017bf32e8e }, - /* x^247808 mod p(x)` << 1, x^247872 mod p(x)` << 1 */ - { 0x00000001b5334592, 0x00000001f8cc6582 }, - /* x^246784 mod p(x)` << 1, x^246848 mod p(x)` << 1 */ - { 0x000000011f8ee1b4, 0x000000008631ddf0 }, - /* x^245760 mod p(x)` << 1, x^245824 mod p(x)` << 1 */ - { 0x000000006252e632, 0x000000007e5a76d0 }, - /* x^244736 mod p(x)` << 1, x^244800 mod p(x)` << 1 */ - { 0x00000000ab973e84, 0x000000002b09b31c }, - /* x^243712 mod p(x)` << 1, x^243776 mod p(x)` << 1 */ - { 0x000000007734f5ec, 0x00000001b2df1f84 }, - /* x^242688 mod p(x)` << 1, x^242752 mod p(x)` << 1 */ - { 0x000000007c547798, 0x00000001d6f56afc }, - /* x^241664 mod p(x)` << 1, x^241728 mod p(x)` << 1 */ - { 0x000000007ec40210, 0x00000001b9b5e70c }, - /* x^240640 mod p(x)` << 1, x^240704 mod p(x)` << 1 */ - { 0x00000001ab1695a8, 0x0000000034b626d2 }, - /* x^239616 mod p(x)` << 1, x^239680 mod p(x)` << 1 */ - { 0x0000000090494bba, 0x000000014c53479a }, - /* x^238592 mod p(x)` << 1, x^238656 mod p(x)` << 1 */ - { 0x00000001123fb816, 0x00000001a6d179a4 }, - /* x^237568 mod p(x)` << 1, x^237632 mod p(x)` << 1 */ - { 0x00000001e188c74c, 0x000000015abd16b4 }, - /* x^236544 mod p(x)` << 1, x^236608 mod p(x)` << 1 */ - { 0x00000001c2d3451c, 0x00000000018f9852 }, - /* x^235520 mod p(x)` << 1, x^235584 mod p(x)` << 1 */ - { 0x00000000f55cf1ca, 0x000000001fb3084a }, - /* x^234496 mod p(x)` << 1, x^234560 mod p(x)` << 1 */ - { 0x00000001a0531540, 0x00000000c53dfb04 }, - /* x^233472 mod p(x)` << 1, x^233536 mod p(x)` << 1 */ - { 0x0000000132cd7ebc, 0x00000000e10c9ad6 }, - /* x^232448 mod p(x)` << 1, x^232512 mod p(x)` << 1 */ - { 0x0000000073ab7f36, 0x0000000025aa994a }, - /* x^231424 mod p(x)` << 1, x^231488 mod p(x)` << 1 */ - { 0x0000000041aed1c2, 0x00000000fa3a74c4 }, - /* x^230400 mod p(x)` << 1, x^230464 mod p(x)` << 1 */ - { 0x0000000136c53800, 0x0000000033eb3f40 }, - /* x^229376 mod p(x)` << 1, x^229440 mod p(x)` << 1 */ - { 0x0000000126835a30, 0x000000017193f296 }, - /* x^228352 mod p(x)` << 1, x^228416 mod p(x)` << 1 */ - { 0x000000006241b502, 0x0000000043f6c86a }, - /* x^227328 mod p(x)` << 1, x^227392 mod p(x)` << 1 */ - { 0x00000000d5196ad4, 0x000000016b513ec6 }, - /* x^226304 mod p(x)` << 1, x^226368 mod p(x)` << 1 */ - { 0x000000009cfa769a, 0x00000000c8f25b4e }, - /* x^225280 mod p(x)` << 1, x^225344 mod p(x)` << 1 */ - { 0x00000000920e5df4, 0x00000001a45048ec }, - /* x^224256 mod p(x)` << 1, x^224320 mod p(x)` << 1 */ - { 0x0000000169dc310e, 0x000000000c441004 }, - /* x^223232 mod p(x)` << 1, x^223296 mod p(x)` << 1 */ - { 0x0000000009fc331c, 0x000000000e17cad6 }, - /* x^222208 mod p(x)` << 1, x^222272 mod p(x)` << 1 */ - { 0x000000010d94a81e, 0x00000001253ae964 }, - /* x^221184 mod p(x)` << 1, x^221248 mod p(x)` << 1 */ - { 0x0000000027a20ab2, 0x00000001d7c88ebc }, - /* x^220160 mod p(x)` << 1, x^220224 mod p(x)` << 1 */ - { 0x0000000114f87504, 0x00000001e7ca913a }, - /* x^219136 mod p(x)` << 1, x^219200 mod p(x)` << 1 */ - { 0x000000004b076d96, 0x0000000033ed078a }, - /* x^218112 mod p(x)` << 1, x^218176 mod p(x)` << 1 */ - { 0x00000000da4d1e74, 0x00000000e1839c78 }, - /* x^217088 mod p(x)` << 1, x^217152 mod p(x)` << 1 */ - { 0x000000001b81f672, 0x00000001322b267e }, - /* x^216064 mod p(x)` << 1, x^216128 mod p(x)` << 1 */ - { 0x000000009367c988, 0x00000000638231b6 }, - /* x^215040 mod p(x)` << 1, x^215104 mod p(x)` << 1 */ - { 0x00000001717214ca, 0x00000001ee7f16f4 }, - /* x^214016 mod p(x)` << 1, x^214080 mod p(x)` << 1 */ - { 0x000000009f47d820, 0x0000000117d9924a }, - /* x^212992 mod p(x)` << 1, x^213056 mod p(x)` << 1 */ - { 0x000000010d9a47d2, 0x00000000e1a9e0c4 }, - /* x^211968 mod p(x)` << 1, x^212032 mod p(x)` << 1 */ - { 0x00000000a696c58c, 0x00000001403731dc }, - /* x^210944 mod p(x)` << 1, x^211008 mod p(x)` << 1 */ - { 0x000000002aa28ec6, 0x00000001a5ea9682 }, - /* x^209920 mod p(x)` << 1, x^209984 mod p(x)` << 1 */ - { 0x00000001fe18fd9a, 0x0000000101c5c578 }, - /* x^208896 mod p(x)` << 1, x^208960 mod p(x)` << 1 */ - { 0x000000019d4fc1ae, 0x00000000dddf6494 }, - /* x^207872 mod p(x)` << 1, x^207936 mod p(x)` << 1 */ - { 0x00000001ba0e3dea, 0x00000000f1c3db28 }, - /* x^206848 mod p(x)` << 1, x^206912 mod p(x)` << 1 */ - { 0x0000000074b59a5e, 0x000000013112fb9c }, - /* x^205824 mod p(x)` << 1, x^205888 mod p(x)` << 1 */ - { 0x00000000f2b5ea98, 0x00000000b680b906 }, - /* x^204800 mod p(x)` << 1, x^204864 mod p(x)` << 1 */ - { 0x0000000187132676, 0x000000001a282932 }, - /* x^203776 mod p(x)` << 1, x^203840 mod p(x)` << 1 */ - { 0x000000010a8c6ad4, 0x0000000089406e7e }, - /* x^202752 mod p(x)` << 1, x^202816 mod p(x)` << 1 */ - { 0x00000001e21dfe70, 0x00000001def6be8c }, - /* x^201728 mod p(x)` << 1, x^201792 mod p(x)` << 1 */ - { 0x00000001da0050e4, 0x0000000075258728 }, - /* x^200704 mod p(x)` << 1, x^200768 mod p(x)` << 1 */ - { 0x00000000772172ae, 0x000000019536090a }, - /* x^199680 mod p(x)` << 1, x^199744 mod p(x)` << 1 */ - { 0x00000000e47724aa, 0x00000000f2455bfc }, - /* x^198656 mod p(x)` << 1, x^198720 mod p(x)` << 1 */ - { 0x000000003cd63ac4, 0x000000018c40baf4 }, - /* x^197632 mod p(x)` << 1, x^197696 mod p(x)` << 1 */ - { 0x00000001bf47d352, 0x000000004cd390d4 }, - /* x^196608 mod p(x)` << 1, x^196672 mod p(x)` << 1 */ - { 0x000000018dc1d708, 0x00000001e4ece95a }, - /* x^195584 mod p(x)` << 1, x^195648 mod p(x)` << 1 */ - { 0x000000002d4620a4, 0x000000001a3ee918 }, - /* x^194560 mod p(x)` << 1, x^194624 mod p(x)` << 1 */ - { 0x0000000058fd1740, 0x000000007c652fb8 }, - /* x^193536 mod p(x)` << 1, x^193600 mod p(x)` << 1 */ - { 0x00000000dadd9bfc, 0x000000011c67842c }, - /* x^192512 mod p(x)` << 1, x^192576 mod p(x)` << 1 */ - { 0x00000001ea2140be, 0x00000000254f759c }, - /* x^191488 mod p(x)` << 1, x^191552 mod p(x)` << 1 */ - { 0x000000009de128ba, 0x000000007ece94ca }, - /* x^190464 mod p(x)` << 1, x^190528 mod p(x)` << 1 */ - { 0x000000013ac3aa8e, 0x0000000038f258c2 }, - /* x^189440 mod p(x)` << 1, x^189504 mod p(x)` << 1 */ - { 0x0000000099980562, 0x00000001cdf17b00 }, - /* x^188416 mod p(x)` << 1, x^188480 mod p(x)` << 1 */ - { 0x00000001c1579c86, 0x000000011f882c16 }, - /* x^187392 mod p(x)` << 1, x^187456 mod p(x)` << 1 */ - { 0x0000000068dbbf94, 0x0000000100093fc8 }, - /* x^186368 mod p(x)` << 1, x^186432 mod p(x)` << 1 */ - { 0x000000004509fb04, 0x00000001cd684f16 }, - /* x^185344 mod p(x)` << 1, x^185408 mod p(x)` << 1 */ - { 0x00000001202f6398, 0x000000004bc6a70a }, - /* x^184320 mod p(x)` << 1, x^184384 mod p(x)` << 1 */ - { 0x000000013aea243e, 0x000000004fc7e8e4 }, - /* x^183296 mod p(x)` << 1, x^183360 mod p(x)` << 1 */ - { 0x00000001b4052ae6, 0x0000000130103f1c }, - /* x^182272 mod p(x)` << 1, x^182336 mod p(x)` << 1 */ - { 0x00000001cd2a0ae8, 0x0000000111b0024c }, - /* x^181248 mod p(x)` << 1, x^181312 mod p(x)` << 1 */ - { 0x00000001fe4aa8b4, 0x000000010b3079da }, - /* x^180224 mod p(x)` << 1, x^180288 mod p(x)` << 1 */ - { 0x00000001d1559a42, 0x000000010192bcc2 }, - /* x^179200 mod p(x)` << 1, x^179264 mod p(x)` << 1 */ - { 0x00000001f3e05ecc, 0x0000000074838d50 }, - /* x^178176 mod p(x)` << 1, x^178240 mod p(x)` << 1 */ - { 0x0000000104ddd2cc, 0x000000001b20f520 }, - /* x^177152 mod p(x)` << 1, x^177216 mod p(x)` << 1 */ - { 0x000000015393153c, 0x0000000050c3590a }, - /* x^176128 mod p(x)` << 1, x^176192 mod p(x)` << 1 */ - { 0x0000000057e942c6, 0x00000000b41cac8e }, - /* x^175104 mod p(x)` << 1, x^175168 mod p(x)` << 1 */ - { 0x000000012c633850, 0x000000000c72cc78 }, - /* x^174080 mod p(x)` << 1, x^174144 mod p(x)` << 1 */ - { 0x00000000ebcaae4c, 0x0000000030cdb032 }, - /* x^173056 mod p(x)` << 1, x^173120 mod p(x)` << 1 */ - { 0x000000013ee532a6, 0x000000013e09fc32 }, - /* x^172032 mod p(x)` << 1, x^172096 mod p(x)` << 1 */ - { 0x00000001bf0cbc7e, 0x000000001ed624d2 }, - /* x^171008 mod p(x)` << 1, x^171072 mod p(x)` << 1 */ - { 0x00000000d50b7a5a, 0x00000000781aee1a }, - /* x^169984 mod p(x)` << 1, x^170048 mod p(x)` << 1 */ - { 0x0000000002fca6e8, 0x00000001c4d8348c }, - /* x^168960 mod p(x)` << 1, x^169024 mod p(x)` << 1 */ - { 0x000000007af40044, 0x0000000057a40336 }, - /* x^167936 mod p(x)` << 1, x^168000 mod p(x)` << 1 */ - { 0x0000000016178744, 0x0000000085544940 }, - /* x^166912 mod p(x)` << 1, x^166976 mod p(x)` << 1 */ - { 0x000000014c177458, 0x000000019cd21e80 }, - /* x^165888 mod p(x)` << 1, x^165952 mod p(x)` << 1 */ - { 0x000000011b6ddf04, 0x000000013eb95bc0 }, - /* x^164864 mod p(x)` << 1, x^164928 mod p(x)` << 1 */ - { 0x00000001f3e29ccc, 0x00000001dfc9fdfc }, - /* x^163840 mod p(x)` << 1, x^163904 mod p(x)` << 1 */ - { 0x0000000135ae7562, 0x00000000cd028bc2 }, - /* x^162816 mod p(x)` << 1, x^162880 mod p(x)` << 1 */ - { 0x0000000190ef812c, 0x0000000090db8c44 }, - /* x^161792 mod p(x)` << 1, x^161856 mod p(x)` << 1 */ - { 0x0000000067a2c786, 0x000000010010a4ce }, - /* x^160768 mod p(x)` << 1, x^160832 mod p(x)` << 1 */ - { 0x0000000048b9496c, 0x00000001c8f4c72c }, - /* x^159744 mod p(x)` << 1, x^159808 mod p(x)` << 1 */ - { 0x000000015a422de6, 0x000000001c26170c }, - /* x^158720 mod p(x)` << 1, x^158784 mod p(x)` << 1 */ - { 0x00000001ef0e3640, 0x00000000e3fccf68 }, - /* x^157696 mod p(x)` << 1, x^157760 mod p(x)` << 1 */ - { 0x00000001006d2d26, 0x00000000d513ed24 }, - /* x^156672 mod p(x)` << 1, x^156736 mod p(x)` << 1 */ - { 0x00000001170d56d6, 0x00000000141beada }, - /* x^155648 mod p(x)` << 1, x^155712 mod p(x)` << 1 */ - { 0x00000000a5fb613c, 0x000000011071aea0 }, - /* x^154624 mod p(x)` << 1, x^154688 mod p(x)` << 1 */ - { 0x0000000040bbf7fc, 0x000000012e19080a }, - /* x^153600 mod p(x)` << 1, x^153664 mod p(x)` << 1 */ - { 0x000000016ac3a5b2, 0x0000000100ecf826 }, - /* x^152576 mod p(x)` << 1, x^152640 mod p(x)` << 1 */ - { 0x00000000abf16230, 0x0000000069b09412 }, - /* x^151552 mod p(x)` << 1, x^151616 mod p(x)` << 1 */ - { 0x00000001ebe23fac, 0x0000000122297bac }, - /* x^150528 mod p(x)` << 1, x^150592 mod p(x)` << 1 */ - { 0x000000008b6a0894, 0x00000000e9e4b068 }, - /* x^149504 mod p(x)` << 1, x^149568 mod p(x)` << 1 */ - { 0x00000001288ea478, 0x000000004b38651a }, - /* x^148480 mod p(x)` << 1, x^148544 mod p(x)` << 1 */ - { 0x000000016619c442, 0x00000001468360e2 }, - /* x^147456 mod p(x)` << 1, x^147520 mod p(x)` << 1 */ - { 0x0000000086230038, 0x00000000121c2408 }, - /* x^146432 mod p(x)` << 1, x^146496 mod p(x)` << 1 */ - { 0x000000017746a756, 0x00000000da7e7d08 }, - /* x^145408 mod p(x)` << 1, x^145472 mod p(x)` << 1 */ - { 0x0000000191b8f8f8, 0x00000001058d7652 }, - /* x^144384 mod p(x)` << 1, x^144448 mod p(x)` << 1 */ - { 0x000000008e167708, 0x000000014a098a90 }, - /* x^143360 mod p(x)` << 1, x^143424 mod p(x)` << 1 */ - { 0x0000000148b22d54, 0x0000000020dbe72e }, - /* x^142336 mod p(x)` << 1, x^142400 mod p(x)` << 1 */ - { 0x0000000044ba2c3c, 0x000000011e7323e8 }, - /* x^141312 mod p(x)` << 1, x^141376 mod p(x)` << 1 */ - { 0x00000000b54d2b52, 0x00000000d5d4bf94 }, - /* x^140288 mod p(x)` << 1, x^140352 mod p(x)` << 1 */ - { 0x0000000005a4fd8a, 0x0000000199d8746c }, - /* x^139264 mod p(x)` << 1, x^139328 mod p(x)` << 1 */ - { 0x0000000139f9fc46, 0x00000000ce9ca8a0 }, - /* x^138240 mod p(x)` << 1, x^138304 mod p(x)` << 1 */ - { 0x000000015a1fa824, 0x00000000136edece }, - /* x^137216 mod p(x)` << 1, x^137280 mod p(x)` << 1 */ - { 0x000000000a61ae4c, 0x000000019b92a068 }, - /* x^136192 mod p(x)` << 1, x^136256 mod p(x)` << 1 */ - { 0x0000000145e9113e, 0x0000000071d62206 }, - /* x^135168 mod p(x)` << 1, x^135232 mod p(x)` << 1 */ - { 0x000000006a348448, 0x00000000dfc50158 }, - /* x^134144 mod p(x)` << 1, x^134208 mod p(x)` << 1 */ - { 0x000000004d80a08c, 0x00000001517626bc }, - /* x^133120 mod p(x)` << 1, x^133184 mod p(x)` << 1 */ - { 0x000000014b6837a0, 0x0000000148d1e4fa }, - /* x^132096 mod p(x)` << 1, x^132160 mod p(x)` << 1 */ - { 0x000000016896a7fc, 0x0000000094d8266e }, - /* x^131072 mod p(x)` << 1, x^131136 mod p(x)` << 1 */ - { 0x000000014f187140, 0x00000000606c5e34 }, - /* x^130048 mod p(x)` << 1, x^130112 mod p(x)` << 1 */ - { 0x000000019581b9da, 0x000000019766beaa }, - /* x^129024 mod p(x)` << 1, x^129088 mod p(x)` << 1 */ - { 0x00000001091bc984, 0x00000001d80c506c }, - /* x^128000 mod p(x)` << 1, x^128064 mod p(x)` << 1 */ - { 0x000000001067223c, 0x000000001e73837c }, - /* x^126976 mod p(x)` << 1, x^127040 mod p(x)` << 1 */ - { 0x00000001ab16ea02, 0x0000000064d587de }, - /* x^125952 mod p(x)` << 1, x^126016 mod p(x)` << 1 */ - { 0x000000013c4598a8, 0x00000000f4a507b0 }, - /* x^124928 mod p(x)` << 1, x^124992 mod p(x)` << 1 */ - { 0x00000000b3735430, 0x0000000040e342fc }, - /* x^123904 mod p(x)` << 1, x^123968 mod p(x)` << 1 */ - { 0x00000001bb3fc0c0, 0x00000001d5ad9c3a }, - /* x^122880 mod p(x)` << 1, x^122944 mod p(x)` << 1 */ - { 0x00000001570ae19c, 0x0000000094a691a4 }, - /* x^121856 mod p(x)` << 1, x^121920 mod p(x)` << 1 */ - { 0x00000001ea910712, 0x00000001271ecdfa }, - /* x^120832 mod p(x)` << 1, x^120896 mod p(x)` << 1 */ - { 0x0000000167127128, 0x000000009e54475a }, - /* x^119808 mod p(x)` << 1, x^119872 mod p(x)` << 1 */ - { 0x0000000019e790a2, 0x00000000c9c099ee }, - /* x^118784 mod p(x)` << 1, x^118848 mod p(x)` << 1 */ - { 0x000000003788f710, 0x000000009a2f736c }, - /* x^117760 mod p(x)` << 1, x^117824 mod p(x)` << 1 */ - { 0x00000001682a160e, 0x00000000bb9f4996 }, - /* x^116736 mod p(x)` << 1, x^116800 mod p(x)` << 1 */ - { 0x000000007f0ebd2e, 0x00000001db688050 }, - /* x^115712 mod p(x)` << 1, x^115776 mod p(x)` << 1 */ - { 0x000000002b032080, 0x00000000e9b10af4 }, - /* x^114688 mod p(x)` << 1, x^114752 mod p(x)` << 1 */ - { 0x00000000cfd1664a, 0x000000012d4545e4 }, - /* x^113664 mod p(x)` << 1, x^113728 mod p(x)` << 1 */ - { 0x00000000aa1181c2, 0x000000000361139c }, - /* x^112640 mod p(x)` << 1, x^112704 mod p(x)` << 1 */ - { 0x00000000ddd08002, 0x00000001a5a1a3a8 }, - /* x^111616 mod p(x)` << 1, x^111680 mod p(x)` << 1 */ - { 0x00000000e8dd0446, 0x000000006844e0b0 }, - /* x^110592 mod p(x)` << 1, x^110656 mod p(x)` << 1 */ - { 0x00000001bbd94a00, 0x00000000c3762f28 }, - /* x^109568 mod p(x)` << 1, x^109632 mod p(x)` << 1 */ - { 0x00000000ab6cd180, 0x00000001d26287a2 }, - /* x^108544 mod p(x)` << 1, x^108608 mod p(x)` << 1 */ - { 0x0000000031803ce2, 0x00000001f6f0bba8 }, - /* x^107520 mod p(x)` << 1, x^107584 mod p(x)` << 1 */ - { 0x0000000024f40b0c, 0x000000002ffabd62 }, - /* x^106496 mod p(x)` << 1, x^106560 mod p(x)` << 1 */ - { 0x00000001ba1d9834, 0x00000000fb4516b8 }, - /* x^105472 mod p(x)` << 1, x^105536 mod p(x)` << 1 */ - { 0x0000000104de61aa, 0x000000018cfa961c }, - /* x^104448 mod p(x)` << 1, x^104512 mod p(x)` << 1 */ - { 0x0000000113e40d46, 0x000000019e588d52 }, - /* x^103424 mod p(x)` << 1, x^103488 mod p(x)` << 1 */ - { 0x00000001415598a0, 0x00000001180f0bbc }, - /* x^102400 mod p(x)` << 1, x^102464 mod p(x)` << 1 */ - { 0x00000000bf6c8c90, 0x00000000e1d9177a }, - /* x^101376 mod p(x)` << 1, x^101440 mod p(x)` << 1 */ - { 0x00000001788b0504, 0x0000000105abc27c }, - /* x^100352 mod p(x)` << 1, x^100416 mod p(x)` << 1 */ - { 0x0000000038385d02, 0x00000000972e4a58 }, - /* x^99328 mod p(x)` << 1, x^99392 mod p(x)` << 1 */ - { 0x00000001b6c83844, 0x0000000183499a5e }, - /* x^98304 mod p(x)` << 1, x^98368 mod p(x)` << 1 */ - { 0x0000000051061a8a, 0x00000001c96a8cca }, - /* x^97280 mod p(x)` << 1, x^97344 mod p(x)` << 1 */ - { 0x000000017351388a, 0x00000001a1a5b60c }, - /* x^96256 mod p(x)` << 1, x^96320 mod p(x)` << 1 */ - { 0x0000000132928f92, 0x00000000e4b6ac9c }, - /* x^95232 mod p(x)` << 1, x^95296 mod p(x)` << 1 */ - { 0x00000000e6b4f48a, 0x00000001807e7f5a }, - /* x^94208 mod p(x)` << 1, x^94272 mod p(x)` << 1 */ - { 0x0000000039d15e90, 0x000000017a7e3bc8 }, - /* x^93184 mod p(x)` << 1, x^93248 mod p(x)` << 1 */ - { 0x00000000312d6074, 0x00000000d73975da }, - /* x^92160 mod p(x)` << 1, x^92224 mod p(x)` << 1 */ - { 0x000000017bbb2cc4, 0x000000017375d038 }, - /* x^91136 mod p(x)` << 1, x^91200 mod p(x)` << 1 */ - { 0x000000016ded3e18, 0x00000000193680bc }, - /* x^90112 mod p(x)` << 1, x^90176 mod p(x)` << 1 */ - { 0x00000000f1638b16, 0x00000000999b06f6 }, - /* x^89088 mod p(x)` << 1, x^89152 mod p(x)` << 1 */ - { 0x00000001d38b9ecc, 0x00000001f685d2b8 }, - /* x^88064 mod p(x)` << 1, x^88128 mod p(x)` << 1 */ - { 0x000000018b8d09dc, 0x00000001f4ecbed2 }, - /* x^87040 mod p(x)` << 1, x^87104 mod p(x)` << 1 */ - { 0x00000000e7bc27d2, 0x00000000ba16f1a0 }, - /* x^86016 mod p(x)` << 1, x^86080 mod p(x)` << 1 */ - { 0x00000000275e1e96, 0x0000000115aceac4 }, - /* x^84992 mod p(x)` << 1, x^85056 mod p(x)` << 1 */ - { 0x00000000e2e3031e, 0x00000001aeff6292 }, - /* x^83968 mod p(x)` << 1, x^84032 mod p(x)` << 1 */ - { 0x00000001041c84d8, 0x000000009640124c }, - /* x^82944 mod p(x)` << 1, x^83008 mod p(x)` << 1 */ - { 0x00000000706ce672, 0x0000000114f41f02 }, - /* x^81920 mod p(x)` << 1, x^81984 mod p(x)` << 1 */ - { 0x000000015d5070da, 0x000000009c5f3586 }, - /* x^80896 mod p(x)` << 1, x^80960 mod p(x)` << 1 */ - { 0x0000000038f9493a, 0x00000001878275fa }, - /* x^79872 mod p(x)` << 1, x^79936 mod p(x)` << 1 */ - { 0x00000000a3348a76, 0x00000000ddc42ce8 }, - /* x^78848 mod p(x)` << 1, x^78912 mod p(x)` << 1 */ - { 0x00000001ad0aab92, 0x0000000181d2c73a }, - /* x^77824 mod p(x)` << 1, x^77888 mod p(x)` << 1 */ - { 0x000000019e85f712, 0x0000000141c9320a }, - /* x^76800 mod p(x)` << 1, x^76864 mod p(x)` << 1 */ - { 0x000000005a871e76, 0x000000015235719a }, - /* x^75776 mod p(x)` << 1, x^75840 mod p(x)` << 1 */ - { 0x000000017249c662, 0x00000000be27d804 }, - /* x^74752 mod p(x)` << 1, x^74816 mod p(x)` << 1 */ - { 0x000000003a084712, 0x000000006242d45a }, - /* x^73728 mod p(x)` << 1, x^73792 mod p(x)` << 1 */ - { 0x00000000ed438478, 0x000000009a53638e }, - /* x^72704 mod p(x)` << 1, x^72768 mod p(x)` << 1 */ - { 0x00000000abac34cc, 0x00000001001ecfb6 }, - /* x^71680 mod p(x)` << 1, x^71744 mod p(x)` << 1 */ - { 0x000000005f35ef3e, 0x000000016d7c2d64 }, - /* x^70656 mod p(x)` << 1, x^70720 mod p(x)` << 1 */ - { 0x0000000047d6608c, 0x00000001d0ce46c0 }, - /* x^69632 mod p(x)` << 1, x^69696 mod p(x)` << 1 */ - { 0x000000002d01470e, 0x0000000124c907b4 }, - /* x^68608 mod p(x)` << 1, x^68672 mod p(x)` << 1 */ - { 0x0000000158bbc7b0, 0x0000000018a555ca }, - /* x^67584 mod p(x)` << 1, x^67648 mod p(x)` << 1 */ - { 0x00000000c0a23e8e, 0x000000006b0980bc }, - /* x^66560 mod p(x)` << 1, x^66624 mod p(x)` << 1 */ - { 0x00000001ebd85c88, 0x000000008bbba964 }, - /* x^65536 mod p(x)` << 1, x^65600 mod p(x)` << 1 */ - { 0x000000019ee20bb2, 0x00000001070a5a1e }, - /* x^64512 mod p(x)` << 1, x^64576 mod p(x)` << 1 */ - { 0x00000001acabf2d6, 0x000000002204322a }, - /* x^63488 mod p(x)` << 1, x^63552 mod p(x)` << 1 */ - { 0x00000001b7963d56, 0x00000000a27524d0 }, - /* x^62464 mod p(x)` << 1, x^62528 mod p(x)` << 1 */ - { 0x000000017bffa1fe, 0x0000000020b1e4ba }, - /* x^61440 mod p(x)` << 1, x^61504 mod p(x)` << 1 */ - { 0x000000001f15333e, 0x0000000032cc27fc }, - /* x^60416 mod p(x)` << 1, x^60480 mod p(x)` << 1 */ - { 0x000000018593129e, 0x0000000044dd22b8 }, - /* x^59392 mod p(x)` << 1, x^59456 mod p(x)` << 1 */ - { 0x000000019cb32602, 0x00000000dffc9e0a }, - /* x^58368 mod p(x)` << 1, x^58432 mod p(x)` << 1 */ - { 0x0000000142b05cc8, 0x00000001b7a0ed14 }, - /* x^57344 mod p(x)` << 1, x^57408 mod p(x)` << 1 */ - { 0x00000001be49e7a4, 0x00000000c7842488 }, - /* x^56320 mod p(x)` << 1, x^56384 mod p(x)` << 1 */ - { 0x0000000108f69d6c, 0x00000001c02a4fee }, - /* x^55296 mod p(x)` << 1, x^55360 mod p(x)` << 1 */ - { 0x000000006c0971f0, 0x000000003c273778 }, - /* x^54272 mod p(x)` << 1, x^54336 mod p(x)` << 1 */ - { 0x000000005b16467a, 0x00000001d63f8894 }, - /* x^53248 mod p(x)` << 1, x^53312 mod p(x)` << 1 */ - { 0x00000001551a628e, 0x000000006be557d6 }, - /* x^52224 mod p(x)` << 1, x^52288 mod p(x)` << 1 */ - { 0x000000019e42ea92, 0x000000006a7806ea }, - /* x^51200 mod p(x)` << 1, x^51264 mod p(x)` << 1 */ - { 0x000000012fa83ff2, 0x000000016155aa0c }, - /* x^50176 mod p(x)` << 1, x^50240 mod p(x)` << 1 */ - { 0x000000011ca9cde0, 0x00000000908650ac }, - /* x^49152 mod p(x)` << 1, x^49216 mod p(x)` << 1 */ - { 0x00000000c8e5cd74, 0x00000000aa5a8084 }, - /* x^48128 mod p(x)` << 1, x^48192 mod p(x)` << 1 */ - { 0x0000000096c27f0c, 0x0000000191bb500a }, - /* x^47104 mod p(x)` << 1, x^47168 mod p(x)` << 1 */ - { 0x000000002baed926, 0x0000000064e9bed0 }, - /* x^46080 mod p(x)` << 1, x^46144 mod p(x)` << 1 */ - { 0x000000017c8de8d2, 0x000000009444f302 }, - /* x^45056 mod p(x)` << 1, x^45120 mod p(x)` << 1 */ - { 0x00000000d43d6068, 0x000000019db07d3c }, - /* x^44032 mod p(x)` << 1, x^44096 mod p(x)` << 1 */ - { 0x00000000cb2c4b26, 0x00000001359e3e6e }, - /* x^43008 mod p(x)` << 1, x^43072 mod p(x)` << 1 */ - { 0x0000000145b8da26, 0x00000001e4f10dd2 }, - /* x^41984 mod p(x)` << 1, x^42048 mod p(x)` << 1 */ - { 0x000000018fff4b08, 0x0000000124f5735e }, - /* x^40960 mod p(x)` << 1, x^41024 mod p(x)` << 1 */ - { 0x0000000150b58ed0, 0x0000000124760a4c }, - /* x^39936 mod p(x)` << 1, x^40000 mod p(x)` << 1 */ - { 0x00000001549f39bc, 0x000000000f1fc186 }, - /* x^38912 mod p(x)` << 1, x^38976 mod p(x)` << 1 */ - { 0x00000000ef4d2f42, 0x00000000150e4cc4 }, - /* x^37888 mod p(x)` << 1, x^37952 mod p(x)` << 1 */ - { 0x00000001b1468572, 0x000000002a6204e8 }, - /* x^36864 mod p(x)` << 1, x^36928 mod p(x)` << 1 */ - { 0x000000013d7403b2, 0x00000000beb1d432 }, - /* x^35840 mod p(x)` << 1, x^35904 mod p(x)` << 1 */ - { 0x00000001a4681842, 0x0000000135f3f1f0 }, - /* x^34816 mod p(x)` << 1, x^34880 mod p(x)` << 1 */ - { 0x0000000167714492, 0x0000000074fe2232 }, - /* x^33792 mod p(x)` << 1, x^33856 mod p(x)` << 1 */ - { 0x00000001e599099a, 0x000000001ac6e2ba }, - /* x^32768 mod p(x)` << 1, x^32832 mod p(x)` << 1 */ - { 0x00000000fe128194, 0x0000000013fca91e }, - /* x^31744 mod p(x)` << 1, x^31808 mod p(x)` << 1 */ - { 0x0000000077e8b990, 0x0000000183f4931e }, - /* x^30720 mod p(x)` << 1, x^30784 mod p(x)` << 1 */ - { 0x00000001a267f63a, 0x00000000b6d9b4e4 }, - /* x^29696 mod p(x)` << 1, x^29760 mod p(x)` << 1 */ - { 0x00000001945c245a, 0x00000000b5188656 }, - /* x^28672 mod p(x)` << 1, x^28736 mod p(x)` << 1 */ - { 0x0000000149002e76, 0x0000000027a81a84 }, - /* x^27648 mod p(x)` << 1, x^27712 mod p(x)` << 1 */ - { 0x00000001bb8310a4, 0x0000000125699258 }, - /* x^26624 mod p(x)` << 1, x^26688 mod p(x)` << 1 */ - { 0x000000019ec60bcc, 0x00000001b23de796 }, - /* x^25600 mod p(x)` << 1, x^25664 mod p(x)` << 1 */ - { 0x000000012d8590ae, 0x00000000fe4365dc }, - /* x^24576 mod p(x)` << 1, x^24640 mod p(x)` << 1 */ - { 0x0000000065b00684, 0x00000000c68f497a }, - /* x^23552 mod p(x)` << 1, x^23616 mod p(x)` << 1 */ - { 0x000000015e5aeadc, 0x00000000fbf521ee }, - /* x^22528 mod p(x)` << 1, x^22592 mod p(x)` << 1 */ - { 0x00000000b77ff2b0, 0x000000015eac3378 }, - /* x^21504 mod p(x)` << 1, x^21568 mod p(x)` << 1 */ - { 0x0000000188da2ff6, 0x0000000134914b90 }, - /* x^20480 mod p(x)` << 1, x^20544 mod p(x)` << 1 */ - { 0x0000000063da929a, 0x0000000016335cfe }, - /* x^19456 mod p(x)` << 1, x^19520 mod p(x)` << 1 */ - { 0x00000001389caa80, 0x000000010372d10c }, - /* x^18432 mod p(x)` << 1, x^18496 mod p(x)` << 1 */ - { 0x000000013db599d2, 0x000000015097b908 }, - /* x^17408 mod p(x)` << 1, x^17472 mod p(x)` << 1 */ - { 0x0000000122505a86, 0x00000001227a7572 }, - /* x^16384 mod p(x)` << 1, x^16448 mod p(x)` << 1 */ - { 0x000000016bd72746, 0x000000009a8f75c0 }, - /* x^15360 mod p(x)` << 1, x^15424 mod p(x)` << 1 */ - { 0x00000001c3faf1d4, 0x00000000682c77a2 }, - /* x^14336 mod p(x)` << 1, x^14400 mod p(x)` << 1 */ - { 0x00000001111c826c, 0x00000000231f091c }, - /* x^13312 mod p(x)` << 1, x^13376 mod p(x)` << 1 */ - { 0x00000000153e9fb2, 0x000000007d4439f2 }, - /* x^12288 mod p(x)` << 1, x^12352 mod p(x)` << 1 */ - { 0x000000002b1f7b60, 0x000000017e221efc }, - /* x^11264 mod p(x)` << 1, x^11328 mod p(x)` << 1 */ - { 0x00000000b1dba570, 0x0000000167457c38 }, - /* x^10240 mod p(x)` << 1, x^10304 mod p(x)` << 1 */ - { 0x00000001f6397b76, 0x00000000bdf081c4 }, - /* x^9216 mod p(x)` << 1, x^9280 mod p(x)` << 1 */ - { 0x0000000156335214, 0x000000016286d6b0 }, - /* x^8192 mod p(x)` << 1, x^8256 mod p(x)` << 1 */ - { 0x00000001d70e3986, 0x00000000c84f001c }, - /* x^7168 mod p(x)` << 1, x^7232 mod p(x)` << 1 */ - { 0x000000003701a774, 0x0000000064efe7c0 }, - /* x^6144 mod p(x)` << 1, x^6208 mod p(x)` << 1 */ - { 0x00000000ac81ef72, 0x000000000ac2d904 }, - /* x^5120 mod p(x)` << 1, x^5184 mod p(x)` << 1 */ - { 0x0000000133212464, 0x00000000fd226d14 }, - /* x^4096 mod p(x)` << 1, x^4160 mod p(x)` << 1 */ - { 0x00000000e4e45610, 0x000000011cfd42e0 }, - /* x^3072 mod p(x)` << 1, x^3136 mod p(x)` << 1 */ - { 0x000000000c1bd370, 0x000000016e5a5678 }, - /* x^2048 mod p(x)` << 1, x^2112 mod p(x)` << 1 */ - { 0x00000001a7b9e7a6, 0x00000001d888fe22 }, - /* x^1024 mod p(x)` << 1, x^1088 mod p(x)` << 1 */ - { 0x000000007d657a10, 0x00000001af77fcd4 } -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* x^261120 mod p(x)` << 1, x^261184 mod p(x)` << 1 */ - { 0x00000001651797d2, 0x0000000099ea94a8 }, - /* x^260096 mod p(x)` << 1, x^260160 mod p(x)` << 1 */ - { 0x0000000021e0d56c, 0x00000000945a8420 }, - /* x^259072 mod p(x)` << 1, x^259136 mod p(x)` << 1 */ - { 0x000000000f95ecaa, 0x0000000030762706 }, - /* x^258048 mod p(x)` << 1, x^258112 mod p(x)` << 1 */ - { 0x00000001ebd224ac, 0x00000001a52fc582 }, - /* x^257024 mod p(x)` << 1, x^257088 mod p(x)` << 1 */ - { 0x000000000ccb97ca, 0x00000001a4a7167a }, - /* x^256000 mod p(x)` << 1, x^256064 mod p(x)` << 1 */ - { 0x00000001006ec8a8, 0x000000000c18249a }, - /* x^254976 mod p(x)` << 1, x^255040 mod p(x)` << 1 */ - { 0x000000014f58f196, 0x00000000a924ae7c }, - /* x^253952 mod p(x)` << 1, x^254016 mod p(x)` << 1 */ - { 0x00000001a7192ca6, 0x00000001e12ccc12 }, - /* x^252928 mod p(x)` << 1, x^252992 mod p(x)` << 1 */ - { 0x000000019a64bab2, 0x00000000a0b9d4ac }, - /* x^251904 mod p(x)` << 1, x^251968 mod p(x)` << 1 */ - { 0x0000000014f4ed2e, 0x0000000095e8ddfe }, - /* x^250880 mod p(x)` << 1, x^250944 mod p(x)` << 1 */ - { 0x000000011092b6a2, 0x00000000233fddc4 }, - /* x^249856 mod p(x)` << 1, x^249920 mod p(x)` << 1 */ - { 0x00000000c8a1629c, 0x00000001b4529b62 }, - /* x^248832 mod p(x)` << 1, x^248896 mod p(x)` << 1 */ - { 0x000000017bf32e8e, 0x00000001a7fa0e64 }, - /* x^247808 mod p(x)` << 1, x^247872 mod p(x)` << 1 */ - { 0x00000001f8cc6582, 0x00000001b5334592 }, - /* x^246784 mod p(x)` << 1, x^246848 mod p(x)` << 1 */ - { 0x000000008631ddf0, 0x000000011f8ee1b4 }, - /* x^245760 mod p(x)` << 1, x^245824 mod p(x)` << 1 */ - { 0x000000007e5a76d0, 0x000000006252e632 }, - /* x^244736 mod p(x)` << 1, x^244800 mod p(x)` << 1 */ - { 0x000000002b09b31c, 0x00000000ab973e84 }, - /* x^243712 mod p(x)` << 1, x^243776 mod p(x)` << 1 */ - { 0x00000001b2df1f84, 0x000000007734f5ec }, - /* x^242688 mod p(x)` << 1, x^242752 mod p(x)` << 1 */ - { 0x00000001d6f56afc, 0x000000007c547798 }, - /* x^241664 mod p(x)` << 1, x^241728 mod p(x)` << 1 */ - { 0x00000001b9b5e70c, 0x000000007ec40210 }, - /* x^240640 mod p(x)` << 1, x^240704 mod p(x)` << 1 */ - { 0x0000000034b626d2, 0x00000001ab1695a8 }, - /* x^239616 mod p(x)` << 1, x^239680 mod p(x)` << 1 */ - { 0x000000014c53479a, 0x0000000090494bba }, - /* x^238592 mod p(x)` << 1, x^238656 mod p(x)` << 1 */ - { 0x00000001a6d179a4, 0x00000001123fb816 }, - /* x^237568 mod p(x)` << 1, x^237632 mod p(x)` << 1 */ - { 0x000000015abd16b4, 0x00000001e188c74c }, - /* x^236544 mod p(x)` << 1, x^236608 mod p(x)` << 1 */ - { 0x00000000018f9852, 0x00000001c2d3451c }, - /* x^235520 mod p(x)` << 1, x^235584 mod p(x)` << 1 */ - { 0x000000001fb3084a, 0x00000000f55cf1ca }, - /* x^234496 mod p(x)` << 1, x^234560 mod p(x)` << 1 */ - { 0x00000000c53dfb04, 0x00000001a0531540 }, - /* x^233472 mod p(x)` << 1, x^233536 mod p(x)` << 1 */ - { 0x00000000e10c9ad6, 0x0000000132cd7ebc }, - /* x^232448 mod p(x)` << 1, x^232512 mod p(x)` << 1 */ - { 0x0000000025aa994a, 0x0000000073ab7f36 }, - /* x^231424 mod p(x)` << 1, x^231488 mod p(x)` << 1 */ - { 0x00000000fa3a74c4, 0x0000000041aed1c2 }, - /* x^230400 mod p(x)` << 1, x^230464 mod p(x)` << 1 */ - { 0x0000000033eb3f40, 0x0000000136c53800 }, - /* x^229376 mod p(x)` << 1, x^229440 mod p(x)` << 1 */ - { 0x000000017193f296, 0x0000000126835a30 }, - /* x^228352 mod p(x)` << 1, x^228416 mod p(x)` << 1 */ - { 0x0000000043f6c86a, 0x000000006241b502 }, - /* x^227328 mod p(x)` << 1, x^227392 mod p(x)` << 1 */ - { 0x000000016b513ec6, 0x00000000d5196ad4 }, - /* x^226304 mod p(x)` << 1, x^226368 mod p(x)` << 1 */ - { 0x00000000c8f25b4e, 0x000000009cfa769a }, - /* x^225280 mod p(x)` << 1, x^225344 mod p(x)` << 1 */ - { 0x00000001a45048ec, 0x00000000920e5df4 }, - /* x^224256 mod p(x)` << 1, x^224320 mod p(x)` << 1 */ - { 0x000000000c441004, 0x0000000169dc310e }, - /* x^223232 mod p(x)` << 1, x^223296 mod p(x)` << 1 */ - { 0x000000000e17cad6, 0x0000000009fc331c }, - /* x^222208 mod p(x)` << 1, x^222272 mod p(x)` << 1 */ - { 0x00000001253ae964, 0x000000010d94a81e }, - /* x^221184 mod p(x)` << 1, x^221248 mod p(x)` << 1 */ - { 0x00000001d7c88ebc, 0x0000000027a20ab2 }, - /* x^220160 mod p(x)` << 1, x^220224 mod p(x)` << 1 */ - { 0x00000001e7ca913a, 0x0000000114f87504 }, - /* x^219136 mod p(x)` << 1, x^219200 mod p(x)` << 1 */ - { 0x0000000033ed078a, 0x000000004b076d96 }, - /* x^218112 mod p(x)` << 1, x^218176 mod p(x)` << 1 */ - { 0x00000000e1839c78, 0x00000000da4d1e74 }, - /* x^217088 mod p(x)` << 1, x^217152 mod p(x)` << 1 */ - { 0x00000001322b267e, 0x000000001b81f672 }, - /* x^216064 mod p(x)` << 1, x^216128 mod p(x)` << 1 */ - { 0x00000000638231b6, 0x000000009367c988 }, - /* x^215040 mod p(x)` << 1, x^215104 mod p(x)` << 1 */ - { 0x00000001ee7f16f4, 0x00000001717214ca }, - /* x^214016 mod p(x)` << 1, x^214080 mod p(x)` << 1 */ - { 0x0000000117d9924a, 0x000000009f47d820 }, - /* x^212992 mod p(x)` << 1, x^213056 mod p(x)` << 1 */ - { 0x00000000e1a9e0c4, 0x000000010d9a47d2 }, - /* x^211968 mod p(x)` << 1, x^212032 mod p(x)` << 1 */ - { 0x00000001403731dc, 0x00000000a696c58c }, - /* x^210944 mod p(x)` << 1, x^211008 mod p(x)` << 1 */ - { 0x00000001a5ea9682, 0x000000002aa28ec6 }, - /* x^209920 mod p(x)` << 1, x^209984 mod p(x)` << 1 */ - { 0x0000000101c5c578, 0x00000001fe18fd9a }, - /* x^208896 mod p(x)` << 1, x^208960 mod p(x)` << 1 */ - { 0x00000000dddf6494, 0x000000019d4fc1ae }, - /* x^207872 mod p(x)` << 1, x^207936 mod p(x)` << 1 */ - { 0x00000000f1c3db28, 0x00000001ba0e3dea }, - /* x^206848 mod p(x)` << 1, x^206912 mod p(x)` << 1 */ - { 0x000000013112fb9c, 0x0000000074b59a5e }, - /* x^205824 mod p(x)` << 1, x^205888 mod p(x)` << 1 */ - { 0x00000000b680b906, 0x00000000f2b5ea98 }, - /* x^204800 mod p(x)` << 1, x^204864 mod p(x)` << 1 */ - { 0x000000001a282932, 0x0000000187132676 }, - /* x^203776 mod p(x)` << 1, x^203840 mod p(x)` << 1 */ - { 0x0000000089406e7e, 0x000000010a8c6ad4 }, - /* x^202752 mod p(x)` << 1, x^202816 mod p(x)` << 1 */ - { 0x00000001def6be8c, 0x00000001e21dfe70 }, - /* x^201728 mod p(x)` << 1, x^201792 mod p(x)` << 1 */ - { 0x0000000075258728, 0x00000001da0050e4 }, - /* x^200704 mod p(x)` << 1, x^200768 mod p(x)` << 1 */ - { 0x000000019536090a, 0x00000000772172ae }, - /* x^199680 mod p(x)` << 1, x^199744 mod p(x)` << 1 */ - { 0x00000000f2455bfc, 0x00000000e47724aa }, - /* x^198656 mod p(x)` << 1, x^198720 mod p(x)` << 1 */ - { 0x000000018c40baf4, 0x000000003cd63ac4 }, - /* x^197632 mod p(x)` << 1, x^197696 mod p(x)` << 1 */ - { 0x000000004cd390d4, 0x00000001bf47d352 }, - /* x^196608 mod p(x)` << 1, x^196672 mod p(x)` << 1 */ - { 0x00000001e4ece95a, 0x000000018dc1d708 }, - /* x^195584 mod p(x)` << 1, x^195648 mod p(x)` << 1 */ - { 0x000000001a3ee918, 0x000000002d4620a4 }, - /* x^194560 mod p(x)` << 1, x^194624 mod p(x)` << 1 */ - { 0x000000007c652fb8, 0x0000000058fd1740 }, - /* x^193536 mod p(x)` << 1, x^193600 mod p(x)` << 1 */ - { 0x000000011c67842c, 0x00000000dadd9bfc }, - /* x^192512 mod p(x)` << 1, x^192576 mod p(x)` << 1 */ - { 0x00000000254f759c, 0x00000001ea2140be }, - /* x^191488 mod p(x)` << 1, x^191552 mod p(x)` << 1 */ - { 0x000000007ece94ca, 0x000000009de128ba }, - /* x^190464 mod p(x)` << 1, x^190528 mod p(x)` << 1 */ - { 0x0000000038f258c2, 0x000000013ac3aa8e }, - /* x^189440 mod p(x)` << 1, x^189504 mod p(x)` << 1 */ - { 0x00000001cdf17b00, 0x0000000099980562 }, - /* x^188416 mod p(x)` << 1, x^188480 mod p(x)` << 1 */ - { 0x000000011f882c16, 0x00000001c1579c86 }, - /* x^187392 mod p(x)` << 1, x^187456 mod p(x)` << 1 */ - { 0x0000000100093fc8, 0x0000000068dbbf94 }, - /* x^186368 mod p(x)` << 1, x^186432 mod p(x)` << 1 */ - { 0x00000001cd684f16, 0x000000004509fb04 }, - /* x^185344 mod p(x)` << 1, x^185408 mod p(x)` << 1 */ - { 0x000000004bc6a70a, 0x00000001202f6398 }, - /* x^184320 mod p(x)` << 1, x^184384 mod p(x)` << 1 */ - { 0x000000004fc7e8e4, 0x000000013aea243e }, - /* x^183296 mod p(x)` << 1, x^183360 mod p(x)` << 1 */ - { 0x0000000130103f1c, 0x00000001b4052ae6 }, - /* x^182272 mod p(x)` << 1, x^182336 mod p(x)` << 1 */ - { 0x0000000111b0024c, 0x00000001cd2a0ae8 }, - /* x^181248 mod p(x)` << 1, x^181312 mod p(x)` << 1 */ - { 0x000000010b3079da, 0x00000001fe4aa8b4 }, - /* x^180224 mod p(x)` << 1, x^180288 mod p(x)` << 1 */ - { 0x000000010192bcc2, 0x00000001d1559a42 }, - /* x^179200 mod p(x)` << 1, x^179264 mod p(x)` << 1 */ - { 0x0000000074838d50, 0x00000001f3e05ecc }, - /* x^178176 mod p(x)` << 1, x^178240 mod p(x)` << 1 */ - { 0x000000001b20f520, 0x0000000104ddd2cc }, - /* x^177152 mod p(x)` << 1, x^177216 mod p(x)` << 1 */ - { 0x0000000050c3590a, 0x000000015393153c }, - /* x^176128 mod p(x)` << 1, x^176192 mod p(x)` << 1 */ - { 0x00000000b41cac8e, 0x0000000057e942c6 }, - /* x^175104 mod p(x)` << 1, x^175168 mod p(x)` << 1 */ - { 0x000000000c72cc78, 0x000000012c633850 }, - /* x^174080 mod p(x)` << 1, x^174144 mod p(x)` << 1 */ - { 0x0000000030cdb032, 0x00000000ebcaae4c }, - /* x^173056 mod p(x)` << 1, x^173120 mod p(x)` << 1 */ - { 0x000000013e09fc32, 0x000000013ee532a6 }, - /* x^172032 mod p(x)` << 1, x^172096 mod p(x)` << 1 */ - { 0x000000001ed624d2, 0x00000001bf0cbc7e }, - /* x^171008 mod p(x)` << 1, x^171072 mod p(x)` << 1 */ - { 0x00000000781aee1a, 0x00000000d50b7a5a }, - /* x^169984 mod p(x)` << 1, x^170048 mod p(x)` << 1 */ - { 0x00000001c4d8348c, 0x0000000002fca6e8 }, - /* x^168960 mod p(x)` << 1, x^169024 mod p(x)` << 1 */ - { 0x0000000057a40336, 0x000000007af40044 }, - /* x^167936 mod p(x)` << 1, x^168000 mod p(x)` << 1 */ - { 0x0000000085544940, 0x0000000016178744 }, - /* x^166912 mod p(x)` << 1, x^166976 mod p(x)` << 1 */ - { 0x000000019cd21e80, 0x000000014c177458 }, - /* x^165888 mod p(x)` << 1, x^165952 mod p(x)` << 1 */ - { 0x000000013eb95bc0, 0x000000011b6ddf04 }, - /* x^164864 mod p(x)` << 1, x^164928 mod p(x)` << 1 */ - { 0x00000001dfc9fdfc, 0x00000001f3e29ccc }, - /* x^163840 mod p(x)` << 1, x^163904 mod p(x)` << 1 */ - { 0x00000000cd028bc2, 0x0000000135ae7562 }, - /* x^162816 mod p(x)` << 1, x^162880 mod p(x)` << 1 */ - { 0x0000000090db8c44, 0x0000000190ef812c }, - /* x^161792 mod p(x)` << 1, x^161856 mod p(x)` << 1 */ - { 0x000000010010a4ce, 0x0000000067a2c786 }, - /* x^160768 mod p(x)` << 1, x^160832 mod p(x)` << 1 */ - { 0x00000001c8f4c72c, 0x0000000048b9496c }, - /* x^159744 mod p(x)` << 1, x^159808 mod p(x)` << 1 */ - { 0x000000001c26170c, 0x000000015a422de6 }, - /* x^158720 mod p(x)` << 1, x^158784 mod p(x)` << 1 */ - { 0x00000000e3fccf68, 0x00000001ef0e3640 }, - /* x^157696 mod p(x)` << 1, x^157760 mod p(x)` << 1 */ - { 0x00000000d513ed24, 0x00000001006d2d26 }, - /* x^156672 mod p(x)` << 1, x^156736 mod p(x)` << 1 */ - { 0x00000000141beada, 0x00000001170d56d6 }, - /* x^155648 mod p(x)` << 1, x^155712 mod p(x)` << 1 */ - { 0x000000011071aea0, 0x00000000a5fb613c }, - /* x^154624 mod p(x)` << 1, x^154688 mod p(x)` << 1 */ - { 0x000000012e19080a, 0x0000000040bbf7fc }, - /* x^153600 mod p(x)` << 1, x^153664 mod p(x)` << 1 */ - { 0x0000000100ecf826, 0x000000016ac3a5b2 }, - /* x^152576 mod p(x)` << 1, x^152640 mod p(x)` << 1 */ - { 0x0000000069b09412, 0x00000000abf16230 }, - /* x^151552 mod p(x)` << 1, x^151616 mod p(x)` << 1 */ - { 0x0000000122297bac, 0x00000001ebe23fac }, - /* x^150528 mod p(x)` << 1, x^150592 mod p(x)` << 1 */ - { 0x00000000e9e4b068, 0x000000008b6a0894 }, - /* x^149504 mod p(x)` << 1, x^149568 mod p(x)` << 1 */ - { 0x000000004b38651a, 0x00000001288ea478 }, - /* x^148480 mod p(x)` << 1, x^148544 mod p(x)` << 1 */ - { 0x00000001468360e2, 0x000000016619c442 }, - /* x^147456 mod p(x)` << 1, x^147520 mod p(x)` << 1 */ - { 0x00000000121c2408, 0x0000000086230038 }, - /* x^146432 mod p(x)` << 1, x^146496 mod p(x)` << 1 */ - { 0x00000000da7e7d08, 0x000000017746a756 }, - /* x^145408 mod p(x)` << 1, x^145472 mod p(x)` << 1 */ - { 0x00000001058d7652, 0x0000000191b8f8f8 }, - /* x^144384 mod p(x)` << 1, x^144448 mod p(x)` << 1 */ - { 0x000000014a098a90, 0x000000008e167708 }, - /* x^143360 mod p(x)` << 1, x^143424 mod p(x)` << 1 */ - { 0x0000000020dbe72e, 0x0000000148b22d54 }, - /* x^142336 mod p(x)` << 1, x^142400 mod p(x)` << 1 */ - { 0x000000011e7323e8, 0x0000000044ba2c3c }, - /* x^141312 mod p(x)` << 1, x^141376 mod p(x)` << 1 */ - { 0x00000000d5d4bf94, 0x00000000b54d2b52 }, - /* x^140288 mod p(x)` << 1, x^140352 mod p(x)` << 1 */ - { 0x0000000199d8746c, 0x0000000005a4fd8a }, - /* x^139264 mod p(x)` << 1, x^139328 mod p(x)` << 1 */ - { 0x00000000ce9ca8a0, 0x0000000139f9fc46 }, - /* x^138240 mod p(x)` << 1, x^138304 mod p(x)` << 1 */ - { 0x00000000136edece, 0x000000015a1fa824 }, - /* x^137216 mod p(x)` << 1, x^137280 mod p(x)` << 1 */ - { 0x000000019b92a068, 0x000000000a61ae4c }, - /* x^136192 mod p(x)` << 1, x^136256 mod p(x)` << 1 */ - { 0x0000000071d62206, 0x0000000145e9113e }, - /* x^135168 mod p(x)` << 1, x^135232 mod p(x)` << 1 */ - { 0x00000000dfc50158, 0x000000006a348448 }, - /* x^134144 mod p(x)` << 1, x^134208 mod p(x)` << 1 */ - { 0x00000001517626bc, 0x000000004d80a08c }, - /* x^133120 mod p(x)` << 1, x^133184 mod p(x)` << 1 */ - { 0x0000000148d1e4fa, 0x000000014b6837a0 }, - /* x^132096 mod p(x)` << 1, x^132160 mod p(x)` << 1 */ - { 0x0000000094d8266e, 0x000000016896a7fc }, - /* x^131072 mod p(x)` << 1, x^131136 mod p(x)` << 1 */ - { 0x00000000606c5e34, 0x000000014f187140 }, - /* x^130048 mod p(x)` << 1, x^130112 mod p(x)` << 1 */ - { 0x000000019766beaa, 0x000000019581b9da }, - /* x^129024 mod p(x)` << 1, x^129088 mod p(x)` << 1 */ - { 0x00000001d80c506c, 0x00000001091bc984 }, - /* x^128000 mod p(x)` << 1, x^128064 mod p(x)` << 1 */ - { 0x000000001e73837c, 0x000000001067223c }, - /* x^126976 mod p(x)` << 1, x^127040 mod p(x)` << 1 */ - { 0x0000000064d587de, 0x00000001ab16ea02 }, - /* x^125952 mod p(x)` << 1, x^126016 mod p(x)` << 1 */ - { 0x00000000f4a507b0, 0x000000013c4598a8 }, - /* x^124928 mod p(x)` << 1, x^124992 mod p(x)` << 1 */ - { 0x0000000040e342fc, 0x00000000b3735430 }, - /* x^123904 mod p(x)` << 1, x^123968 mod p(x)` << 1 */ - { 0x00000001d5ad9c3a, 0x00000001bb3fc0c0 }, - /* x^122880 mod p(x)` << 1, x^122944 mod p(x)` << 1 */ - { 0x0000000094a691a4, 0x00000001570ae19c }, - /* x^121856 mod p(x)` << 1, x^121920 mod p(x)` << 1 */ - { 0x00000001271ecdfa, 0x00000001ea910712 }, - /* x^120832 mod p(x)` << 1, x^120896 mod p(x)` << 1 */ - { 0x000000009e54475a, 0x0000000167127128 }, - /* x^119808 mod p(x)` << 1, x^119872 mod p(x)` << 1 */ - { 0x00000000c9c099ee, 0x0000000019e790a2 }, - /* x^118784 mod p(x)` << 1, x^118848 mod p(x)` << 1 */ - { 0x000000009a2f736c, 0x000000003788f710 }, - /* x^117760 mod p(x)` << 1, x^117824 mod p(x)` << 1 */ - { 0x00000000bb9f4996, 0x00000001682a160e }, - /* x^116736 mod p(x)` << 1, x^116800 mod p(x)` << 1 */ - { 0x00000001db688050, 0x000000007f0ebd2e }, - /* x^115712 mod p(x)` << 1, x^115776 mod p(x)` << 1 */ - { 0x00000000e9b10af4, 0x000000002b032080 }, - /* x^114688 mod p(x)` << 1, x^114752 mod p(x)` << 1 */ - { 0x000000012d4545e4, 0x00000000cfd1664a }, - /* x^113664 mod p(x)` << 1, x^113728 mod p(x)` << 1 */ - { 0x000000000361139c, 0x00000000aa1181c2 }, - /* x^112640 mod p(x)` << 1, x^112704 mod p(x)` << 1 */ - { 0x00000001a5a1a3a8, 0x00000000ddd08002 }, - /* x^111616 mod p(x)` << 1, x^111680 mod p(x)` << 1 */ - { 0x000000006844e0b0, 0x00000000e8dd0446 }, - /* x^110592 mod p(x)` << 1, x^110656 mod p(x)` << 1 */ - { 0x00000000c3762f28, 0x00000001bbd94a00 }, - /* x^109568 mod p(x)` << 1, x^109632 mod p(x)` << 1 */ - { 0x00000001d26287a2, 0x00000000ab6cd180 }, - /* x^108544 mod p(x)` << 1, x^108608 mod p(x)` << 1 */ - { 0x00000001f6f0bba8, 0x0000000031803ce2 }, - /* x^107520 mod p(x)` << 1, x^107584 mod p(x)` << 1 */ - { 0x000000002ffabd62, 0x0000000024f40b0c }, - /* x^106496 mod p(x)` << 1, x^106560 mod p(x)` << 1 */ - { 0x00000000fb4516b8, 0x00000001ba1d9834 }, - /* x^105472 mod p(x)` << 1, x^105536 mod p(x)` << 1 */ - { 0x000000018cfa961c, 0x0000000104de61aa }, - /* x^104448 mod p(x)` << 1, x^104512 mod p(x)` << 1 */ - { 0x000000019e588d52, 0x0000000113e40d46 }, - /* x^103424 mod p(x)` << 1, x^103488 mod p(x)` << 1 */ - { 0x00000001180f0bbc, 0x00000001415598a0 }, - /* x^102400 mod p(x)` << 1, x^102464 mod p(x)` << 1 */ - { 0x00000000e1d9177a, 0x00000000bf6c8c90 }, - /* x^101376 mod p(x)` << 1, x^101440 mod p(x)` << 1 */ - { 0x0000000105abc27c, 0x00000001788b0504 }, - /* x^100352 mod p(x)` << 1, x^100416 mod p(x)` << 1 */ - { 0x00000000972e4a58, 0x0000000038385d02 }, - /* x^99328 mod p(x)` << 1, x^99392 mod p(x)` << 1 */ - { 0x0000000183499a5e, 0x00000001b6c83844 }, - /* x^98304 mod p(x)` << 1, x^98368 mod p(x)` << 1 */ - { 0x00000001c96a8cca, 0x0000000051061a8a }, - /* x^97280 mod p(x)` << 1, x^97344 mod p(x)` << 1 */ - { 0x00000001a1a5b60c, 0x000000017351388a }, - /* x^96256 mod p(x)` << 1, x^96320 mod p(x)` << 1 */ - { 0x00000000e4b6ac9c, 0x0000000132928f92 }, - /* x^95232 mod p(x)` << 1, x^95296 mod p(x)` << 1 */ - { 0x00000001807e7f5a, 0x00000000e6b4f48a }, - /* x^94208 mod p(x)` << 1, x^94272 mod p(x)` << 1 */ - { 0x000000017a7e3bc8, 0x0000000039d15e90 }, - /* x^93184 mod p(x)` << 1, x^93248 mod p(x)` << 1 */ - { 0x00000000d73975da, 0x00000000312d6074 }, - /* x^92160 mod p(x)` << 1, x^92224 mod p(x)` << 1 */ - { 0x000000017375d038, 0x000000017bbb2cc4 }, - /* x^91136 mod p(x)` << 1, x^91200 mod p(x)` << 1 */ - { 0x00000000193680bc, 0x000000016ded3e18 }, - /* x^90112 mod p(x)` << 1, x^90176 mod p(x)` << 1 */ - { 0x00000000999b06f6, 0x00000000f1638b16 }, - /* x^89088 mod p(x)` << 1, x^89152 mod p(x)` << 1 */ - { 0x00000001f685d2b8, 0x00000001d38b9ecc }, - /* x^88064 mod p(x)` << 1, x^88128 mod p(x)` << 1 */ - { 0x00000001f4ecbed2, 0x000000018b8d09dc }, - /* x^87040 mod p(x)` << 1, x^87104 mod p(x)` << 1 */ - { 0x00000000ba16f1a0, 0x00000000e7bc27d2 }, - /* x^86016 mod p(x)` << 1, x^86080 mod p(x)` << 1 */ - { 0x0000000115aceac4, 0x00000000275e1e96 }, - /* x^84992 mod p(x)` << 1, x^85056 mod p(x)` << 1 */ - { 0x00000001aeff6292, 0x00000000e2e3031e }, - /* x^83968 mod p(x)` << 1, x^84032 mod p(x)` << 1 */ - { 0x000000009640124c, 0x00000001041c84d8 }, - /* x^82944 mod p(x)` << 1, x^83008 mod p(x)` << 1 */ - { 0x0000000114f41f02, 0x00000000706ce672 }, - /* x^81920 mod p(x)` << 1, x^81984 mod p(x)` << 1 */ - { 0x000000009c5f3586, 0x000000015d5070da }, - /* x^80896 mod p(x)` << 1, x^80960 mod p(x)` << 1 */ - { 0x00000001878275fa, 0x0000000038f9493a }, - /* x^79872 mod p(x)` << 1, x^79936 mod p(x)` << 1 */ - { 0x00000000ddc42ce8, 0x00000000a3348a76 }, - /* x^78848 mod p(x)` << 1, x^78912 mod p(x)` << 1 */ - { 0x0000000181d2c73a, 0x00000001ad0aab92 }, - /* x^77824 mod p(x)` << 1, x^77888 mod p(x)` << 1 */ - { 0x0000000141c9320a, 0x000000019e85f712 }, - /* x^76800 mod p(x)` << 1, x^76864 mod p(x)` << 1 */ - { 0x000000015235719a, 0x000000005a871e76 }, - /* x^75776 mod p(x)` << 1, x^75840 mod p(x)` << 1 */ - { 0x00000000be27d804, 0x000000017249c662 }, - /* x^74752 mod p(x)` << 1, x^74816 mod p(x)` << 1 */ - { 0x000000006242d45a, 0x000000003a084712 }, - /* x^73728 mod p(x)` << 1, x^73792 mod p(x)` << 1 */ - { 0x000000009a53638e, 0x00000000ed438478 }, - /* x^72704 mod p(x)` << 1, x^72768 mod p(x)` << 1 */ - { 0x00000001001ecfb6, 0x00000000abac34cc }, - /* x^71680 mod p(x)` << 1, x^71744 mod p(x)` << 1 */ - { 0x000000016d7c2d64, 0x000000005f35ef3e }, - /* x^70656 mod p(x)` << 1, x^70720 mod p(x)` << 1 */ - { 0x00000001d0ce46c0, 0x0000000047d6608c }, - /* x^69632 mod p(x)` << 1, x^69696 mod p(x)` << 1 */ - { 0x0000000124c907b4, 0x000000002d01470e }, - /* x^68608 mod p(x)` << 1, x^68672 mod p(x)` << 1 */ - { 0x0000000018a555ca, 0x0000000158bbc7b0 }, - /* x^67584 mod p(x)` << 1, x^67648 mod p(x)` << 1 */ - { 0x000000006b0980bc, 0x00000000c0a23e8e }, - /* x^66560 mod p(x)` << 1, x^66624 mod p(x)` << 1 */ - { 0x000000008bbba964, 0x00000001ebd85c88 }, - /* x^65536 mod p(x)` << 1, x^65600 mod p(x)` << 1 */ - { 0x00000001070a5a1e, 0x000000019ee20bb2 }, - /* x^64512 mod p(x)` << 1, x^64576 mod p(x)` << 1 */ - { 0x000000002204322a, 0x00000001acabf2d6 }, - /* x^63488 mod p(x)` << 1, x^63552 mod p(x)` << 1 */ - { 0x00000000a27524d0, 0x00000001b7963d56 }, - /* x^62464 mod p(x)` << 1, x^62528 mod p(x)` << 1 */ - { 0x0000000020b1e4ba, 0x000000017bffa1fe }, - /* x^61440 mod p(x)` << 1, x^61504 mod p(x)` << 1 */ - { 0x0000000032cc27fc, 0x000000001f15333e }, - /* x^60416 mod p(x)` << 1, x^60480 mod p(x)` << 1 */ - { 0x0000000044dd22b8, 0x000000018593129e }, - /* x^59392 mod p(x)` << 1, x^59456 mod p(x)` << 1 */ - { 0x00000000dffc9e0a, 0x000000019cb32602 }, - /* x^58368 mod p(x)` << 1, x^58432 mod p(x)` << 1 */ - { 0x00000001b7a0ed14, 0x0000000142b05cc8 }, - /* x^57344 mod p(x)` << 1, x^57408 mod p(x)` << 1 */ - { 0x00000000c7842488, 0x00000001be49e7a4 }, - /* x^56320 mod p(x)` << 1, x^56384 mod p(x)` << 1 */ - { 0x00000001c02a4fee, 0x0000000108f69d6c }, - /* x^55296 mod p(x)` << 1, x^55360 mod p(x)` << 1 */ - { 0x000000003c273778, 0x000000006c0971f0 }, - /* x^54272 mod p(x)` << 1, x^54336 mod p(x)` << 1 */ - { 0x00000001d63f8894, 0x000000005b16467a }, - /* x^53248 mod p(x)` << 1, x^53312 mod p(x)` << 1 */ - { 0x000000006be557d6, 0x00000001551a628e }, - /* x^52224 mod p(x)` << 1, x^52288 mod p(x)` << 1 */ - { 0x000000006a7806ea, 0x000000019e42ea92 }, - /* x^51200 mod p(x)` << 1, x^51264 mod p(x)` << 1 */ - { 0x000000016155aa0c, 0x000000012fa83ff2 }, - /* x^50176 mod p(x)` << 1, x^50240 mod p(x)` << 1 */ - { 0x00000000908650ac, 0x000000011ca9cde0 }, - /* x^49152 mod p(x)` << 1, x^49216 mod p(x)` << 1 */ - { 0x00000000aa5a8084, 0x00000000c8e5cd74 }, - /* x^48128 mod p(x)` << 1, x^48192 mod p(x)` << 1 */ - { 0x0000000191bb500a, 0x0000000096c27f0c }, - /* x^47104 mod p(x)` << 1, x^47168 mod p(x)` << 1 */ - { 0x0000000064e9bed0, 0x000000002baed926 }, - /* x^46080 mod p(x)` << 1, x^46144 mod p(x)` << 1 */ - { 0x000000009444f302, 0x000000017c8de8d2 }, - /* x^45056 mod p(x)` << 1, x^45120 mod p(x)` << 1 */ - { 0x000000019db07d3c, 0x00000000d43d6068 }, - /* x^44032 mod p(x)` << 1, x^44096 mod p(x)` << 1 */ - { 0x00000001359e3e6e, 0x00000000cb2c4b26 }, - /* x^43008 mod p(x)` << 1, x^43072 mod p(x)` << 1 */ - { 0x00000001e4f10dd2, 0x0000000145b8da26 }, - /* x^41984 mod p(x)` << 1, x^42048 mod p(x)` << 1 */ - { 0x0000000124f5735e, 0x000000018fff4b08 }, - /* x^40960 mod p(x)` << 1, x^41024 mod p(x)` << 1 */ - { 0x0000000124760a4c, 0x0000000150b58ed0 }, - /* x^39936 mod p(x)` << 1, x^40000 mod p(x)` << 1 */ - { 0x000000000f1fc186, 0x00000001549f39bc }, - /* x^38912 mod p(x)` << 1, x^38976 mod p(x)` << 1 */ - { 0x00000000150e4cc4, 0x00000000ef4d2f42 }, - /* x^37888 mod p(x)` << 1, x^37952 mod p(x)` << 1 */ - { 0x000000002a6204e8, 0x00000001b1468572 }, - /* x^36864 mod p(x)` << 1, x^36928 mod p(x)` << 1 */ - { 0x00000000beb1d432, 0x000000013d7403b2 }, - /* x^35840 mod p(x)` << 1, x^35904 mod p(x)` << 1 */ - { 0x0000000135f3f1f0, 0x00000001a4681842 }, - /* x^34816 mod p(x)` << 1, x^34880 mod p(x)` << 1 */ - { 0x0000000074fe2232, 0x0000000167714492 }, - /* x^33792 mod p(x)` << 1, x^33856 mod p(x)` << 1 */ - { 0x000000001ac6e2ba, 0x00000001e599099a }, - /* x^32768 mod p(x)` << 1, x^32832 mod p(x)` << 1 */ - { 0x0000000013fca91e, 0x00000000fe128194 }, - /* x^31744 mod p(x)` << 1, x^31808 mod p(x)` << 1 */ - { 0x0000000183f4931e, 0x0000000077e8b990 }, - /* x^30720 mod p(x)` << 1, x^30784 mod p(x)` << 1 */ - { 0x00000000b6d9b4e4, 0x00000001a267f63a }, - /* x^29696 mod p(x)` << 1, x^29760 mod p(x)` << 1 */ - { 0x00000000b5188656, 0x00000001945c245a }, - /* x^28672 mod p(x)` << 1, x^28736 mod p(x)` << 1 */ - { 0x0000000027a81a84, 0x0000000149002e76 }, - /* x^27648 mod p(x)` << 1, x^27712 mod p(x)` << 1 */ - { 0x0000000125699258, 0x00000001bb8310a4 }, - /* x^26624 mod p(x)` << 1, x^26688 mod p(x)` << 1 */ - { 0x00000001b23de796, 0x000000019ec60bcc }, - /* x^25600 mod p(x)` << 1, x^25664 mod p(x)` << 1 */ - { 0x00000000fe4365dc, 0x000000012d8590ae }, - /* x^24576 mod p(x)` << 1, x^24640 mod p(x)` << 1 */ - { 0x00000000c68f497a, 0x0000000065b00684 }, - /* x^23552 mod p(x)` << 1, x^23616 mod p(x)` << 1 */ - { 0x00000000fbf521ee, 0x000000015e5aeadc }, - /* x^22528 mod p(x)` << 1, x^22592 mod p(x)` << 1 */ - { 0x000000015eac3378, 0x00000000b77ff2b0 }, - /* x^21504 mod p(x)` << 1, x^21568 mod p(x)` << 1 */ - { 0x0000000134914b90, 0x0000000188da2ff6 }, - /* x^20480 mod p(x)` << 1, x^20544 mod p(x)` << 1 */ - { 0x0000000016335cfe, 0x0000000063da929a }, - /* x^19456 mod p(x)` << 1, x^19520 mod p(x)` << 1 */ - { 0x000000010372d10c, 0x00000001389caa80 }, - /* x^18432 mod p(x)` << 1, x^18496 mod p(x)` << 1 */ - { 0x000000015097b908, 0x000000013db599d2 }, - /* x^17408 mod p(x)` << 1, x^17472 mod p(x)` << 1 */ - { 0x00000001227a7572, 0x0000000122505a86 }, - /* x^16384 mod p(x)` << 1, x^16448 mod p(x)` << 1 */ - { 0x000000009a8f75c0, 0x000000016bd72746 }, - /* x^15360 mod p(x)` << 1, x^15424 mod p(x)` << 1 */ - { 0x00000000682c77a2, 0x00000001c3faf1d4 }, - /* x^14336 mod p(x)` << 1, x^14400 mod p(x)` << 1 */ - { 0x00000000231f091c, 0x00000001111c826c }, - /* x^13312 mod p(x)` << 1, x^13376 mod p(x)` << 1 */ - { 0x000000007d4439f2, 0x00000000153e9fb2 }, - /* x^12288 mod p(x)` << 1, x^12352 mod p(x)` << 1 */ - { 0x000000017e221efc, 0x000000002b1f7b60 }, - /* x^11264 mod p(x)` << 1, x^11328 mod p(x)` << 1 */ - { 0x0000000167457c38, 0x00000000b1dba570 }, - /* x^10240 mod p(x)` << 1, x^10304 mod p(x)` << 1 */ - { 0x00000000bdf081c4, 0x00000001f6397b76 }, - /* x^9216 mod p(x)` << 1, x^9280 mod p(x)` << 1 */ - { 0x000000016286d6b0, 0x0000000156335214 }, - /* x^8192 mod p(x)` << 1, x^8256 mod p(x)` << 1 */ - { 0x00000000c84f001c, 0x00000001d70e3986 }, - /* x^7168 mod p(x)` << 1, x^7232 mod p(x)` << 1 */ - { 0x0000000064efe7c0, 0x000000003701a774 }, - /* x^6144 mod p(x)` << 1, x^6208 mod p(x)` << 1 */ - { 0x000000000ac2d904, 0x00000000ac81ef72 }, - /* x^5120 mod p(x)` << 1, x^5184 mod p(x)` << 1 */ - { 0x00000000fd226d14, 0x0000000133212464 }, - /* x^4096 mod p(x)` << 1, x^4160 mod p(x)` << 1 */ - { 0x000000011cfd42e0, 0x00000000e4e45610 }, - /* x^3072 mod p(x)` << 1, x^3136 mod p(x)` << 1 */ - { 0x000000016e5a5678, 0x000000000c1bd370 }, - /* x^2048 mod p(x)` << 1, x^2112 mod p(x)` << 1 */ - { 0x00000001d888fe22, 0x00000001a7b9e7a6 }, - /* x^1024 mod p(x)` << 1, x^1088 mod p(x)` << 1 */ - { 0x00000001af77fcd4, 0x000000007d657a10 } -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -}; - -/* Reduce final 1024-2048 bits to 64 bits, shifting 32 bits to include the trailing 32 bits of zeros */ - -static const __vector unsigned long long vcrc_short_const[16] ALIGNED_(16) = { -#if BYTE_ORDER == LITTLE_ENDIAN - /* x^1952 mod p(x) , x^1984 mod p(x) , x^2016 mod p(x) , x^2048 mod p(x) */ - { 0x99168a18ec447f11, 0xed837b2613e8221e }, - /* x^1824 mod p(x) , x^1856 mod p(x) , x^1888 mod p(x) , x^1920 mod p(x) */ - { 0xe23e954e8fd2cd3c, 0xc8acdd8147b9ce5a }, - /* x^1696 mod p(x) , x^1728 mod p(x) , x^1760 mod p(x) , x^1792 mod p(x) */ - { 0x92f8befe6b1d2b53, 0xd9ad6d87d4277e25 }, - /* x^1568 mod p(x) , x^1600 mod p(x) , x^1632 mod p(x) , x^1664 mod p(x) */ - { 0xf38a3556291ea462, 0xc10ec5e033fbca3b }, - /* x^1440 mod p(x) , x^1472 mod p(x) , x^1504 mod p(x) , x^1536 mod p(x) */ - { 0x974ac56262b6ca4b, 0xc0b55b0e82e02e2f }, - /* x^1312 mod p(x) , x^1344 mod p(x) , x^1376 mod p(x) , x^1408 mod p(x) */ - { 0x855712b3784d2a56, 0x71aa1df0e172334d }, - /* x^1184 mod p(x) , x^1216 mod p(x) , x^1248 mod p(x) , x^1280 mod p(x) */ - { 0xa5abe9f80eaee722, 0xfee3053e3969324d }, - /* x^1056 mod p(x) , x^1088 mod p(x) , x^1120 mod p(x) , x^1152 mod p(x) */ - { 0x1fa0943ddb54814c, 0xf44779b93eb2bd08 }, - /* x^928 mod p(x) , x^960 mod p(x) , x^992 mod p(x) , x^1024 mod p(x) */ - { 0xa53ff440d7bbfe6a, 0xf5449b3f00cc3374 }, - /* x^800 mod p(x) , x^832 mod p(x) , x^864 mod p(x) , x^896 mod p(x) */ - { 0xebe7e3566325605c, 0x6f8346e1d777606e }, - /* x^672 mod p(x) , x^704 mod p(x) , x^736 mod p(x) , x^768 mod p(x) */ - { 0xc65a272ce5b592b8, 0xe3ab4f2ac0b95347 }, - /* x^544 mod p(x) , x^576 mod p(x) , x^608 mod p(x) , x^640 mod p(x) */ - { 0x5705a9ca4721589f, 0xaa2215ea329ecc11 }, - /* x^416 mod p(x) , x^448 mod p(x) , x^480 mod p(x) , x^512 mod p(x) */ - { 0xe3720acb88d14467, 0x1ed8f66ed95efd26 }, - /* x^288 mod p(x) , x^320 mod p(x) , x^352 mod p(x) , x^384 mod p(x) */ - { 0xba1aca0315141c31, 0x78ed02d5a700e96a }, - /* x^160 mod p(x) , x^192 mod p(x) , x^224 mod p(x) , x^256 mod p(x) */ - { 0xad2a31b3ed627dae, 0xba8ccbe832b39da3 }, - /* x^32 mod p(x) , x^64 mod p(x) , x^96 mod p(x) , x^128 mod p(x) */ - { 0x6655004fa06a2517, 0xedb88320b1e6b092 } -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* x^1952 mod p(x) , x^1984 mod p(x) , x^2016 mod p(x) , x^2048 mod p(x) */ - { 0xed837b2613e8221e, 0x99168a18ec447f11 }, - /* x^1824 mod p(x) , x^1856 mod p(x) , x^1888 mod p(x) , x^1920 mod p(x) */ - { 0xc8acdd8147b9ce5a, 0xe23e954e8fd2cd3c }, - /* x^1696 mod p(x) , x^1728 mod p(x) , x^1760 mod p(x) , x^1792 mod p(x) */ - { 0xd9ad6d87d4277e25, 0x92f8befe6b1d2b53 }, - /* x^1568 mod p(x) , x^1600 mod p(x) , x^1632 mod p(x) , x^1664 mod p(x) */ - { 0xc10ec5e033fbca3b, 0xf38a3556291ea462 }, - /* x^1440 mod p(x) , x^1472 mod p(x) , x^1504 mod p(x) , x^1536 mod p(x) */ - { 0xc0b55b0e82e02e2f, 0x974ac56262b6ca4b }, - /* x^1312 mod p(x) , x^1344 mod p(x) , x^1376 mod p(x) , x^1408 mod p(x) */ - { 0x71aa1df0e172334d, 0x855712b3784d2a56 }, - /* x^1184 mod p(x) , x^1216 mod p(x) , x^1248 mod p(x) , x^1280 mod p(x) */ - { 0xfee3053e3969324d, 0xa5abe9f80eaee722 }, - /* x^1056 mod p(x) , x^1088 mod p(x) , x^1120 mod p(x) , x^1152 mod p(x) */ - { 0xf44779b93eb2bd08, 0x1fa0943ddb54814c }, - /* x^928 mod p(x) , x^960 mod p(x) , x^992 mod p(x) , x^1024 mod p(x) */ - { 0xf5449b3f00cc3374, 0xa53ff440d7bbfe6a }, - /* x^800 mod p(x) , x^832 mod p(x) , x^864 mod p(x) , x^896 mod p(x) */ - { 0x6f8346e1d777606e, 0xebe7e3566325605c }, - /* x^672 mod p(x) , x^704 mod p(x) , x^736 mod p(x) , x^768 mod p(x) */ - { 0xe3ab4f2ac0b95347, 0xc65a272ce5b592b8 }, - /* x^544 mod p(x) , x^576 mod p(x) , x^608 mod p(x) , x^640 mod p(x) */ - { 0xaa2215ea329ecc11, 0x5705a9ca4721589f }, - /* x^416 mod p(x) , x^448 mod p(x) , x^480 mod p(x) , x^512 mod p(x) */ - { 0x1ed8f66ed95efd26, 0xe3720acb88d14467 }, - /* x^288 mod p(x) , x^320 mod p(x) , x^352 mod p(x) , x^384 mod p(x) */ - { 0x78ed02d5a700e96a, 0xba1aca0315141c31 }, - /* x^160 mod p(x) , x^192 mod p(x) , x^224 mod p(x) , x^256 mod p(x) */ - { 0xba8ccbe832b39da3, 0xad2a31b3ed627dae }, - /* x^32 mod p(x) , x^64 mod p(x) , x^96 mod p(x) , x^128 mod p(x) */ - { 0xedb88320b1e6b092, 0x6655004fa06a2517 } -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -}; - -/* Barrett constants */ -/* 33 bit reflected Barrett constant m - (4^32)/n */ - -static const __vector unsigned long long v_Barrett_const[2] ALIGNED_(16) = { - /* x^64 div p(x) */ -#if BYTE_ORDER == LITTLE_ENDIAN - { 0x00000001f7011641, 0x0000000000000000 }, - { 0x00000001db710641, 0x0000000000000000 } -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - { 0x0000000000000000, 0x00000001f7011641 }, - { 0x0000000000000000, 0x00000001db710641 } -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -}; diff --git a/modules/zlib/src/arch/power/crc32_power8.c b/modules/zlib/src/arch/power/crc32_power8.c deleted file mode 100644 index a7a2fb7435..0000000000 --- a/modules/zlib/src/arch/power/crc32_power8.c +++ /dev/null @@ -1,593 +0,0 @@ -/* crc32 for POWER8 using VSX instructions - * Copyright (C) 2021 IBM Corporation - * - * Author: Rogerio Alves - * - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Calculate the checksum of data that is 16 byte aligned and a multiple of - * 16 bytes. - * - * The first step is to reduce it to 1024 bits. We do this in 8 parallel - * chunks in order to mask the latency of the vpmsum instructions. If we - * have more than 32 kB of data to checksum we repeat this step multiple - * times, passing in the previous 1024 bits. - * - * The next step is to reduce the 1024 bits to 64 bits. This step adds - * 32 bits of 0s to the end - this matches what a CRC does. We just - * calculate constants that land the data in this 32 bits. - * - * We then use fixed point Barrett reduction to compute a mod n over GF(2) - * for n = CRC using POWER8 instructions. We use x = 32. - * - * http://en.wikipedia.org/wiki/Barrett_reduction - * - * This code uses gcc vector builtins instead using assembly directly. - */ - -#ifdef POWER8_VSX_CRC32 - -#include "zbuild.h" -#include "zendian.h" - -#include "crc32_constants.h" -#include "crc32_braid_tbl.h" - -#include "power_intrins.h" - -#define MAX_SIZE 32768 -#define VMX_ALIGN 16 -#define VMX_ALIGN_MASK (VMX_ALIGN-1) - -static unsigned int crc32_align(unsigned int crc, const unsigned char *p, unsigned long len) { - while (len--) - crc = crc_table[(crc ^ *p++) & 0xff] ^ (crc >> 8); - return crc; -} - -static unsigned int ALIGNED_(32) __crc32_vpmsum(unsigned int crc, const void* p, unsigned long len); - -Z_INTERNAL uint32_t crc32_power8(uint32_t crc, const unsigned char *p, size_t _len) { - unsigned int prealign; - unsigned int tail; - - unsigned long len = (unsigned long) _len; - - crc ^= 0xffffffff; - - if (len < VMX_ALIGN + VMX_ALIGN_MASK) { - crc = crc32_align(crc, p, len); - goto out; - } - - if ((unsigned long)p & VMX_ALIGN_MASK) { - prealign = (unsigned int)ALIGN_DIFF(p, VMX_ALIGN); - crc = crc32_align(crc, p, prealign); - len -= prealign; - p += prealign; - } - - crc = __crc32_vpmsum(crc, p, ALIGN_DOWN(len, VMX_ALIGN)); - - tail = len & VMX_ALIGN_MASK; - if (tail) { - p += ALIGN_DOWN(len, VMX_ALIGN); - crc = crc32_align(crc, p, tail); - } - -out: - crc ^= 0xffffffff; - - return crc; -} - -Z_INTERNAL uint32_t crc32_copy_power8(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - crc = crc32_power8(crc, src, len); - memcpy(dst, src, len); - return crc; -} - -/* When we have a load-store in a single-dispatch group and address overlap - * such that forward is not allowed (load-hit-store) the group must be flushed. - * A group ending NOP prevents the flush. - */ -#define GROUP_ENDING_NOP __asm__("ori 2,2,0" ::: "memory") - -#if BYTE_ORDER == BIG_ENDIAN -#define BYTESWAP_DATA -#endif - -#ifdef BYTESWAP_DATA -#define VEC_PERM(vr, va, vb, vc) vr = vec_perm(va, vb, (__vector unsigned char) vc) -#if BYTE_ORDER == LITTLE_ENDIAN -/* Byte reverse permute constant LE. */ -static const __vector unsigned long long vperm_const ALIGNED_(16) = { 0x08090A0B0C0D0E0FUL, 0x0001020304050607UL }; -#else -static const __vector unsigned long long vperm_const ALIGNED_(16) = { 0x0F0E0D0C0B0A0908UL, 0X0706050403020100UL }; -#endif -#else -#define VEC_PERM(vr, va, vb, vc) -#endif - -static unsigned int ALIGNED_(32) __crc32_vpmsum(unsigned int crc, const void* p, unsigned long len) { - - const __vector unsigned long long vzero = {0,0}; - const __vector unsigned long long vones = {0xffffffffffffffffUL, 0xffffffffffffffffUL}; - - const __vector unsigned long long vmask_32bit = - (__vector unsigned long long)vec_sld((__vector unsigned char)vzero, (__vector unsigned char)vones, 4); - - const __vector unsigned long long vmask_64bit = - (__vector unsigned long long)vec_sld((__vector unsigned char)vzero, (__vector unsigned char)vones, 8); - - __vector unsigned long long vcrc; - - __vector unsigned long long vconst1, vconst2; - - /* vdata0-vdata7 will contain our data (p). */ - __vector unsigned long long vdata0, vdata1, vdata2, vdata3, vdata4, vdata5, vdata6, vdata7; - - /* v0-v7 will contain our checksums */ - __vector unsigned long long v0 = {0,0}; - __vector unsigned long long v1 = {0,0}; - __vector unsigned long long v2 = {0,0}; - __vector unsigned long long v3 = {0,0}; - __vector unsigned long long v4 = {0,0}; - __vector unsigned long long v5 = {0,0}; - __vector unsigned long long v6 = {0,0}; - __vector unsigned long long v7 = {0,0}; - - - /* Vector auxiliary variables. */ - __vector unsigned long long va0, va1, va2, va3, va4, va5, va6, va7; - - unsigned int offset; /* Constant table offset. */ - - unsigned long i; /* Counter. */ - unsigned long chunks; - - unsigned long block_size; - int next_block = 0; - - /* Align by 128 bits. The last 128 bit block will be processed at end. */ - unsigned long length = len & 0xFFFFFFFFFFFFFF80UL; - - vcrc = (__vector unsigned long long)__builtin_pack_vector_int128(0UL, crc); - - /* Short version. */ - if (len < 256) { - /* Calculate where in the constant table we need to start. */ - offset = 256 - len; - - vconst1 = vec_ld(offset, vcrc_short_const); - vdata0 = vec_ld(0, (__vector unsigned long long*) p); - VEC_PERM(vdata0, vdata0, vconst1, vperm_const); - - /* xor initial value */ - vdata0 = vec_xor(vdata0, vcrc); - - vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw( - (__vector unsigned int)vdata0, (__vector unsigned int)vconst1); - v0 = vec_xor(v0, vdata0); - - for (i = 16; i < len; i += 16) { - vconst1 = vec_ld(offset + i, vcrc_short_const); - vdata0 = vec_ld(i, (__vector unsigned long long*) p); - VEC_PERM(vdata0, vdata0, vconst1, vperm_const); - vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw( - (__vector unsigned int)vdata0, (__vector unsigned int)vconst1); - v0 = vec_xor(v0, vdata0); - } - } else { - - /* Load initial values. */ - vdata0 = vec_ld(0, (__vector unsigned long long*) p); - vdata1 = vec_ld(16, (__vector unsigned long long*) p); - - VEC_PERM(vdata0, vdata0, vdata0, vperm_const); - VEC_PERM(vdata1, vdata1, vdata1, vperm_const); - - vdata2 = vec_ld(32, (__vector unsigned long long*) p); - vdata3 = vec_ld(48, (__vector unsigned long long*) p); - - VEC_PERM(vdata2, vdata2, vdata2, vperm_const); - VEC_PERM(vdata3, vdata3, vdata3, vperm_const); - - vdata4 = vec_ld(64, (__vector unsigned long long*) p); - vdata5 = vec_ld(80, (__vector unsigned long long*) p); - - VEC_PERM(vdata4, vdata4, vdata4, vperm_const); - VEC_PERM(vdata5, vdata5, vdata5, vperm_const); - - vdata6 = vec_ld(96, (__vector unsigned long long*) p); - vdata7 = vec_ld(112, (__vector unsigned long long*) p); - - VEC_PERM(vdata6, vdata6, vdata6, vperm_const); - VEC_PERM(vdata7, vdata7, vdata7, vperm_const); - - /* xor in initial value */ - vdata0 = vec_xor(vdata0, vcrc); - - p = (char *)p + 128; - - do { - /* Checksum in blocks of MAX_SIZE. */ - block_size = length; - if (block_size > MAX_SIZE) { - block_size = MAX_SIZE; - } - - length = length - block_size; - - /* - * Work out the offset into the constants table to start at. Each - * constant is 16 bytes, and it is used against 128 bytes of input - * data - 128 / 16 = 8 - */ - offset = (MAX_SIZE/8) - (block_size/8); - /* We reduce our final 128 bytes in a separate step */ - chunks = (block_size/128)-1; - - vconst1 = vec_ld(offset, vcrc_const); - - va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0, - (__vector unsigned long long)vconst1); - va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1, - (__vector unsigned long long)vconst1); - va2 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata2, - (__vector unsigned long long)vconst1); - va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3, - (__vector unsigned long long)vconst1); - va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4, - (__vector unsigned long long)vconst1); - va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5, - (__vector unsigned long long)vconst1); - va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6, - (__vector unsigned long long)vconst1); - va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7, - (__vector unsigned long long)vconst1); - - if (chunks > 1) { - offset += 16; - vconst2 = vec_ld(offset, vcrc_const); - GROUP_ENDING_NOP; - - vdata0 = vec_ld(0, (__vector unsigned long long*) p); - VEC_PERM(vdata0, vdata0, vdata0, vperm_const); - - vdata1 = vec_ld(16, (__vector unsigned long long*) p); - VEC_PERM(vdata1, vdata1, vdata1, vperm_const); - - vdata2 = vec_ld(32, (__vector unsigned long long*) p); - VEC_PERM(vdata2, vdata2, vdata2, vperm_const); - - vdata3 = vec_ld(48, (__vector unsigned long long*) p); - VEC_PERM(vdata3, vdata3, vdata3, vperm_const); - - vdata4 = vec_ld(64, (__vector unsigned long long*) p); - VEC_PERM(vdata4, vdata4, vdata4, vperm_const); - - vdata5 = vec_ld(80, (__vector unsigned long long*) p); - VEC_PERM(vdata5, vdata5, vdata5, vperm_const); - - vdata6 = vec_ld(96, (__vector unsigned long long*) p); - VEC_PERM(vdata6, vdata6, vdata6, vperm_const); - - vdata7 = vec_ld(112, (__vector unsigned long long*) p); - VEC_PERM(vdata7, vdata7, vdata7, vperm_const); - - p = (char *)p + 128; - - /* - * main loop. Each iteration calculates the CRC for a 128-byte - * block. - */ - for (i = 0; i < chunks-2; i++) { - vconst1 = vec_ld(offset, vcrc_const); - offset += 16; - GROUP_ENDING_NOP; - - v0 = vec_xor(v0, va0); - va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0, - (__vector unsigned long long)vconst2); - vdata0 = vec_ld(0, (__vector unsigned long long*) p); - VEC_PERM(vdata0, vdata0, vdata0, vperm_const); - GROUP_ENDING_NOP; - - v1 = vec_xor(v1, va1); - va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1, - (__vector unsigned long long)vconst2); - vdata1 = vec_ld(16, (__vector unsigned long long*) p); - VEC_PERM(vdata1, vdata1, vdata1, vperm_const); - GROUP_ENDING_NOP; - - v2 = vec_xor(v2, va2); - va2 = __builtin_crypto_vpmsumd((__vector unsigned long long) - vdata2, (__vector unsigned long long)vconst2); - vdata2 = vec_ld(32, (__vector unsigned long long*) p); - VEC_PERM(vdata2, vdata2, vdata2, vperm_const); - GROUP_ENDING_NOP; - - v3 = vec_xor(v3, va3); - va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3, - (__vector unsigned long long)vconst2); - vdata3 = vec_ld(48, (__vector unsigned long long*) p); - VEC_PERM(vdata3, vdata3, vdata3, vperm_const); - - vconst2 = vec_ld(offset, vcrc_const); - GROUP_ENDING_NOP; - - v4 = vec_xor(v4, va4); - va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4, - (__vector unsigned long long)vconst1); - vdata4 = vec_ld(64, (__vector unsigned long long*) p); - VEC_PERM(vdata4, vdata4, vdata4, vperm_const); - GROUP_ENDING_NOP; - - v5 = vec_xor(v5, va5); - va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5, - (__vector unsigned long long)vconst1); - vdata5 = vec_ld(80, (__vector unsigned long long*) p); - VEC_PERM(vdata5, vdata5, vdata5, vperm_const); - GROUP_ENDING_NOP; - - v6 = vec_xor(v6, va6); - va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6, - (__vector unsigned long long)vconst1); - vdata6 = vec_ld(96, (__vector unsigned long long*) p); - VEC_PERM(vdata6, vdata6, vdata6, vperm_const); - GROUP_ENDING_NOP; - - v7 = vec_xor(v7, va7); - va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7, - (__vector unsigned long long)vconst1); - vdata7 = vec_ld(112, (__vector unsigned long long*) p); - VEC_PERM(vdata7, vdata7, vdata7, vperm_const); - - p = (char *)p + 128; - } - - /* First cool down */ - vconst1 = vec_ld(offset, vcrc_const); - offset += 16; - - v0 = vec_xor(v0, va0); - va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0, - (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v1 = vec_xor(v1, va1); - va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1, - (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v2 = vec_xor(v2, va2); - va2 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata2, - (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v3 = vec_xor(v3, va3); - va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3, - (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v4 = vec_xor(v4, va4); - va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4, - (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v5 = vec_xor(v5, va5); - va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5, - (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v6 = vec_xor(v6, va6); - va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6, - (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v7 = vec_xor(v7, va7); - va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7, - (__vector unsigned long long)vconst1); - }/* else */ - - /* Second cool down. */ - v0 = vec_xor(v0, va0); - v1 = vec_xor(v1, va1); - v2 = vec_xor(v2, va2); - v3 = vec_xor(v3, va3); - v4 = vec_xor(v4, va4); - v5 = vec_xor(v5, va5); - v6 = vec_xor(v6, va6); - v7 = vec_xor(v7, va7); - - /* - * vpmsumd produces a 96 bit result in the least significant bits - * of the register. Since we are bit reflected we have to shift it - * left 32 bits so it occupies the least significant bits in the - * bit reflected domain. - */ - v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, - (__vector unsigned char)vzero, 4); - v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v1, - (__vector unsigned char)vzero, 4); - v2 = (__vector unsigned long long)vec_sld((__vector unsigned char)v2, - (__vector unsigned char)vzero, 4); - v3 = (__vector unsigned long long)vec_sld((__vector unsigned char)v3, - (__vector unsigned char)vzero, 4); - v4 = (__vector unsigned long long)vec_sld((__vector unsigned char)v4, - (__vector unsigned char)vzero, 4); - v5 = (__vector unsigned long long)vec_sld((__vector unsigned char)v5, - (__vector unsigned char)vzero, 4); - v6 = (__vector unsigned long long)vec_sld((__vector unsigned char)v6, - (__vector unsigned char)vzero, 4); - v7 = (__vector unsigned long long)vec_sld((__vector unsigned char)v7, - (__vector unsigned char)vzero, 4); - - /* xor with the last 1024 bits. */ - va0 = vec_ld(0, (__vector unsigned long long*) p); - VEC_PERM(va0, va0, va0, vperm_const); - - va1 = vec_ld(16, (__vector unsigned long long*) p); - VEC_PERM(va1, va1, va1, vperm_const); - - va2 = vec_ld(32, (__vector unsigned long long*) p); - VEC_PERM(va2, va2, va2, vperm_const); - - va3 = vec_ld(48, (__vector unsigned long long*) p); - VEC_PERM(va3, va3, va3, vperm_const); - - va4 = vec_ld(64, (__vector unsigned long long*) p); - VEC_PERM(va4, va4, va4, vperm_const); - - va5 = vec_ld(80, (__vector unsigned long long*) p); - VEC_PERM(va5, va5, va5, vperm_const); - - va6 = vec_ld(96, (__vector unsigned long long*) p); - VEC_PERM(va6, va6, va6, vperm_const); - - va7 = vec_ld(112, (__vector unsigned long long*) p); - VEC_PERM(va7, va7, va7, vperm_const); - - p = (char *)p + 128; - - vdata0 = vec_xor(v0, va0); - vdata1 = vec_xor(v1, va1); - vdata2 = vec_xor(v2, va2); - vdata3 = vec_xor(v3, va3); - vdata4 = vec_xor(v4, va4); - vdata5 = vec_xor(v5, va5); - vdata6 = vec_xor(v6, va6); - vdata7 = vec_xor(v7, va7); - - /* Check if we have more blocks to process */ - next_block = 0; - if (length != 0) { - next_block = 1; - - /* zero v0-v7 */ - v0 = vec_xor(v0, v0); - v1 = vec_xor(v1, v1); - v2 = vec_xor(v2, v2); - v3 = vec_xor(v3, v3); - v4 = vec_xor(v4, v4); - v5 = vec_xor(v5, v5); - v6 = vec_xor(v6, v6); - v7 = vec_xor(v7, v7); - } - length = length + 128; - - } while (next_block); - - /* Calculate how many bytes we have left. */ - length = (len & 127); - - /* Calculate where in (short) constant table we need to start. */ - offset = 128 - length; - - v0 = vec_ld(offset, vcrc_short_const); - v1 = vec_ld(offset + 16, vcrc_short_const); - v2 = vec_ld(offset + 32, vcrc_short_const); - v3 = vec_ld(offset + 48, vcrc_short_const); - v4 = vec_ld(offset + 64, vcrc_short_const); - v5 = vec_ld(offset + 80, vcrc_short_const); - v6 = vec_ld(offset + 96, vcrc_short_const); - v7 = vec_ld(offset + 112, vcrc_short_const); - - offset += 128; - - v0 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata0, (__vector unsigned int)v0); - v1 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata1, (__vector unsigned int)v1); - v2 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata2, (__vector unsigned int)v2); - v3 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata3, (__vector unsigned int)v3); - v4 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata4, (__vector unsigned int)v4); - v5 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata5, (__vector unsigned int)v5); - v6 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata6, (__vector unsigned int)v6); - v7 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata7, (__vector unsigned int)v7); - - /* Now reduce the tail (0-112 bytes). */ - for (i = 0; i < length; i+=16) { - vdata0 = vec_ld(i,(__vector unsigned long long*)p); - VEC_PERM(vdata0, vdata0, vdata0, vperm_const); - va0 = vec_ld(offset + i,vcrc_short_const); - va0 = (__vector unsigned long long)__builtin_crypto_vpmsumw( - (__vector unsigned int)vdata0, (__vector unsigned int)va0); - v0 = vec_xor(v0, va0); - } - - /* xor all parallel chunks together. */ - v0 = vec_xor(v0, v1); - v2 = vec_xor(v2, v3); - v4 = vec_xor(v4, v5); - v6 = vec_xor(v6, v7); - - v0 = vec_xor(v0, v2); - v4 = vec_xor(v4, v6); - - v0 = vec_xor(v0, v4); - } - - /* Barrett Reduction */ - vconst1 = vec_ld(0, v_Barrett_const); - vconst2 = vec_ld(16, v_Barrett_const); - - v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, - (__vector unsigned char)v0, 8); - v0 = vec_xor(v1,v0); - - /* shift left one bit */ - __vector unsigned char vsht_splat = vec_splat_u8 (1); - v0 = (__vector unsigned long long)vec_sll((__vector unsigned char)v0, vsht_splat); - - v0 = vec_and(v0, vmask_64bit); - - /* - * The reflected version of Barrett reduction. Instead of bit - * reflecting our data (which is expensive to do), we bit reflect our - * constants and our algorithm, which means the intermediate data in - * our vector registers goes from 0-63 instead of 63-0. We can reflect - * the algorithm because we don't carry in mod 2 arithmetic. - */ - - /* bottom 32 bits of a */ - v1 = vec_and(v0, vmask_32bit); - - /* ma */ - v1 = __builtin_crypto_vpmsumd((__vector unsigned long long)v1, - (__vector unsigned long long)vconst1); - - /* bottom 32bits of ma */ - v1 = vec_and(v1, vmask_32bit); - /* qn */ - v1 = __builtin_crypto_vpmsumd((__vector unsigned long long)v1, - (__vector unsigned long long)vconst2); - /* a - qn, subtraction is xor in GF(2) */ - v0 = vec_xor (v0, v1); - - /* - * Since we are bit reflected, the result (ie the low 32 bits) is in - * the high 32 bits. We just need to shift it left 4 bytes - * V0 [ 0 1 X 3 ] - * V0 [ 0 X 2 3 ] - */ - - /* shift result into top 64 bits of */ - v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, - (__vector unsigned char)vzero, 4); - -#if BYTE_ORDER == BIG_ENDIAN - return v0[0]; -#else - return v0[1]; -#endif -} - -#endif diff --git a/modules/zlib/src/arch/power/power_features.c b/modules/zlib/src/arch/power/power_features.c deleted file mode 100644 index 148f30a974..0000000000 --- a/modules/zlib/src/arch/power/power_features.c +++ /dev/null @@ -1,54 +0,0 @@ -/* power_features.c - POWER feature check - * Copyright (C) 2020 Matheus Castanho , IBM - * Copyright (C) 2021-2024 Mika T. Lindqvist - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#if defined(PPC_FEATURES) || defined(POWER_FEATURES) - -#include "zbuild.h" -#include "power_features.h" - -#ifdef HAVE_SYS_AUXV_H -# include -#endif -#ifdef POWER_NEED_AUXVEC_H -# include -#endif -#ifdef __FreeBSD__ -# include -#endif - -void Z_INTERNAL power_check_features(struct power_cpu_features *features) { -#ifdef PPC_FEATURES - unsigned long hwcap; -#if defined(__FreeBSD__) || defined(__OpenBSD__) - elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); -#else - hwcap = getauxval(AT_HWCAP); -#endif - - if (hwcap & PPC_FEATURE_HAS_ALTIVEC) - features->has_altivec = 1; -#endif - -#ifdef POWER_FEATURES - unsigned long hwcap2; -#if defined(__FreeBSD__) || defined(__OpenBSD__) - elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2)); -#else - hwcap2 = getauxval(AT_HWCAP2); -#endif - -#ifdef POWER8_VSX - if (hwcap2 & PPC_FEATURE2_ARCH_2_07) - features->has_arch_2_07 = 1; -#endif -#ifdef POWER9 - if (hwcap2 & PPC_FEATURE2_ARCH_3_00) - features->has_arch_3_00 = 1; -#endif -#endif -} - -#endif diff --git a/modules/zlib/src/arch/power/power_features.h b/modules/zlib/src/arch/power/power_features.h deleted file mode 100644 index 1ff51de5dd..0000000000 --- a/modules/zlib/src/arch/power/power_features.h +++ /dev/null @@ -1,18 +0,0 @@ -/* power_features.h -- check for POWER CPU features - * Copyright (C) 2020 Matheus Castanho , IBM - * Copyright (C) 2021 Mika T. Lindqvist - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef POWER_FEATURES_H_ -#define POWER_FEATURES_H_ - -struct power_cpu_features { - int has_altivec; - int has_arch_2_07; - int has_arch_3_00; -}; - -void Z_INTERNAL power_check_features(struct power_cpu_features *features); - -#endif /* POWER_FEATURES_H_ */ diff --git a/modules/zlib/src/arch/power/power_functions.h b/modules/zlib/src/arch/power/power_functions.h deleted file mode 100644 index 3f89f709a6..0000000000 --- a/modules/zlib/src/arch/power/power_functions.h +++ /dev/null @@ -1,90 +0,0 @@ -/* power_functions.h -- POWER implementations for arch-specific functions. - * Copyright (C) 2020 Matheus Castanho , IBM - * Copyright (C) 2021 Mika T. Lindqvist - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef POWER_FUNCTIONS_H_ -#define POWER_FUNCTIONS_H_ - -#include "power_natives.h" - -#ifdef PPC_VMX -uint32_t adler32_vmx(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_vmx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -void slide_hash_vmx(deflate_state *s); -#endif - -#ifdef POWER8_VSX -uint32_t adler32_power8(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_power8(uint32_t adler, uint8_t *dst, const uint8_t *buf, size_t len); -uint8_t* chunkmemset_safe_power8(uint8_t *out, uint8_t *from, size_t len, size_t left); -uint32_t crc32_power8(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_power8(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -void slide_hash_power8(deflate_state *s); -void inflate_fast_power8(PREFIX3(stream) *strm, uint32_t start); -#endif - -#if !defined(PPC_VMX_NATIVE) && !defined(POWER8_VSX_NATIVE) -# define ADLER32_FALLBACK -# define SLIDE_HASH_FALLBACK -#endif - -#ifndef POWER8_VSX_NATIVE -# define CHUNKSET_FALLBACK -#endif -#ifndef POWER8_VSX_CRC32_NATIVE -# define CRC32_BRAID_FALLBACK -#endif - -#ifdef POWER9 -uint32_t compare256_power9(const uint8_t *src0, const uint8_t *src1); -uint32_t longest_match_power9(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_power9(deflate_state *const s, uint32_t cur_match); -#endif - -#ifndef POWER9_NATIVE -# define COMPARE256_FALLBACK -#endif - -#ifdef DISABLE_RUNTIME_CPU_DETECTION -// Power - VMX -# ifdef PPC_VMX_NATIVE -# undef native_adler32 -# define native_adler32 adler32_vmx -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_vmx -# undef native_slide_hash -# define native_slide_hash slide_hash_vmx -# endif -// Power8 - VSX -# ifdef POWER8_VSX_NATIVE -# undef native_adler32 -# define native_adler32 adler32_power8 -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_power8 -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_power8 -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_power8 -# undef native_slide_hash -# define native_slide_hash slide_hash_power8 -# endif -# ifdef POWER8_VSX_CRC32_NATIVE -# undef native_crc32 -# define native_crc32 crc32_power8 -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_power8 -# endif -// Power9 -# ifdef POWER9_NATIVE -# undef native_compare256 -# define native_compare256 compare256_power9 -# undef native_longest_match -# define native_longest_match longest_match_power9 -# undef native_longest_match_roll -# define native_longest_match_roll longest_match_roll_power9 -# endif -#endif - -#endif /* POWER_FUNCTIONS_H_ */ diff --git a/modules/zlib/src/arch/power/power_intrins.h b/modules/zlib/src/arch/power/power_intrins.h deleted file mode 100644 index 3efcfb9722..0000000000 --- a/modules/zlib/src/arch/power/power_intrins.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Helper functions to work around issues with clang builtins - * Copyright (C) 2021 IBM Corporation - * - * Authors: - * Daniel Black - * Rogerio Alves - * Tulio Magno Quites Machado Filho - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef POWER_INTRINS_H -#define POWER_INTRINS_H - -#include - -#if defined (__clang__) -/* - * These stubs fix clang incompatibilities with GCC builtins. - */ - -#ifndef __builtin_crypto_vpmsumw -#define __builtin_crypto_vpmsumw __builtin_crypto_vpmsumb -#endif -#ifndef __builtin_crypto_vpmsumd -#define __builtin_crypto_vpmsumd __builtin_crypto_vpmsumb -#endif - -#ifdef __VSX__ -static inline __vector unsigned long long __attribute__((overloadable)) -vec_ld(int __a, const __vector unsigned long long* __b) { - return (__vector unsigned long long)__builtin_altivec_lvx(__a, __b); -} -#endif - -#endif - -/* There's no version of this that operates over unsigned and if casted, it does - * sign extension. Let's write an endian independent version and hope the compiler - * eliminates creating another zero idiom for the zero value if one exists locally */ -static inline vector unsigned short vec_unpackl(vector unsigned char a) { - vector unsigned char zero = vec_splat_u8(0); - -#if BYTE_ORDER == BIG_ENDIAN - return (vector unsigned short)vec_mergel(zero, a); -#else - return (vector unsigned short)vec_mergel(a, zero); -#endif -} - -static inline vector unsigned short vec_unpackh(vector unsigned char a) { - vector unsigned char zero = vec_splat_u8(0); - -#if BYTE_ORDER == BIG_ENDIAN - return (vector unsigned short)vec_mergeh(zero, a); -#else - return (vector unsigned short)vec_mergeh(a, zero); -#endif -} - -#endif diff --git a/modules/zlib/src/arch/power/power_natives.h b/modules/zlib/src/arch/power/power_natives.h deleted file mode 100644 index 59ec8a8aed..0000000000 --- a/modules/zlib/src/arch/power/power_natives.h +++ /dev/null @@ -1,27 +0,0 @@ -/* power_natives.h -- POWER compile-time feature detection macros. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef POWER_NATIVES_H_ -#define POWER_NATIVES_H_ - -#if defined(__ALTIVEC__) -# ifdef PPC_VMX -# define PPC_VMX_NATIVE -# endif -#endif -#if defined(_ARCH_PWR8) && defined(__VSX__) -# ifdef POWER8_VSX -# define POWER8_VSX_NATIVE -# endif -# ifdef POWER8_VSX_CRC32 -# define POWER8_VSX_CRC32_NATIVE -# endif -#endif -#if defined(_ARCH_PWR9) -# ifdef POWER9 -# define POWER9_NATIVE -# endif -#endif - -#endif /* POWER_NATIVES_H_ */ diff --git a/modules/zlib/src/arch/power/slide_hash_power8.c b/modules/zlib/src/arch/power/slide_hash_power8.c deleted file mode 100644 index d01e0acd56..0000000000 --- a/modules/zlib/src/arch/power/slide_hash_power8.c +++ /dev/null @@ -1,12 +0,0 @@ -/* Optimized slide_hash for POWER processors - * Copyright (C) 2019-2020 IBM Corporation - * Author: Matheus Castanho - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef POWER8_VSX - -#define SLIDE_PPC slide_hash_power8 -#include "slide_ppc_tpl.h" - -#endif /* POWER8_VSX */ diff --git a/modules/zlib/src/arch/power/slide_hash_vmx.c b/modules/zlib/src/arch/power/slide_hash_vmx.c deleted file mode 100644 index 5a87ef7d9a..0000000000 --- a/modules/zlib/src/arch/power/slide_hash_vmx.c +++ /dev/null @@ -1,10 +0,0 @@ -/* Optimized slide_hash for PowerPC processors with VMX instructions - * Copyright (C) 2017-2021 Mika T. Lindqvist - * For conditions of distribution and use, see copyright notice in zlib.h - */ -#ifdef PPC_VMX - -#define SLIDE_PPC slide_hash_vmx -#include "slide_ppc_tpl.h" - -#endif /* PPC_VMX */ diff --git a/modules/zlib/src/arch/power/slide_ppc_tpl.h b/modules/zlib/src/arch/power/slide_ppc_tpl.h deleted file mode 100644 index 24629b4039..0000000000 --- a/modules/zlib/src/arch/power/slide_ppc_tpl.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Optimized slide_hash for PowerPC processors - * Copyright (C) 2017-2021 Mika T. Lindqvist - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include -#include "zbuild.h" -#include "deflate.h" - -static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { - const vector unsigned short vmx_wsize = vec_splats(wsize); - Pos *p = table; - - do { - /* Do the pointer arithmetic early to hopefully overlap the vector unit */ - Pos *q = p; - p += 32; - vector unsigned short value0, value1, value2, value3; - vector unsigned short result0, result1, result2, result3; - - value0 = vec_ld(0, q); - value1 = vec_ld(16, q); - value2 = vec_ld(32, q); - value3 = vec_ld(48, q); - result0 = vec_subs(value0, vmx_wsize); - result1 = vec_subs(value1, vmx_wsize); - result2 = vec_subs(value2, vmx_wsize); - result3 = vec_subs(value3, vmx_wsize); - vec_st(result0, 0, q); - vec_st(result1, 16, q); - vec_st(result2, 32, q); - vec_st(result3, 48, q); - - entries -= 32; - } while (entries); -} - -void Z_INTERNAL SLIDE_PPC(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - - slide_hash_chain(s->head, HASH_SIZE, wsize); - slide_hash_chain(s->prev, wsize, wsize); -} diff --git a/modules/zlib/src/arch/riscv/Makefile.in b/modules/zlib/src/arch/riscv/Makefile.in deleted file mode 100644 index 43176eee6e..0000000000 --- a/modules/zlib/src/arch/riscv/Makefile.in +++ /dev/null @@ -1,72 +0,0 @@ -# Makefile for zlib-ng -# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler -# Copyright (C) 2024 Hans Kristian Rosbach -# Copyright (C) 2025 Yin Tong , ByteDance -# For conditions of distribution and use, see copyright notice in zlib.h - -CC= -CFLAGS= -SFLAGS= -INCLUDES= -SUFFIX= - -SRCDIR=. -SRCTOP=../.. -TOPDIR=$(SRCTOP) - -RVVFLAG= -RVVZBCFLAG= -ZBCFLAG= - -all: \ - riscv_features.o riscv_features.lo \ - adler32_rvv.o adler32_rvv.lo \ - chunkset_rvv.o chunkset_rvv.lo \ - compare256_rvv.o compare256_rvv.lo \ - slide_hash_rvv.o slide_hash_rvv.lo \ - crc32_zbc.o crc32_zbc.lo - -riscv_features.o: $(SRCDIR)/riscv_features.c - $(CC) $(CFLAGS) $(RVVZBCFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/riscv_features.c - -riscv_features.lo: $(SRCDIR)/riscv_features.c - $(CC) $(SFLAGS) $(RVVZBCFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/riscv_features.c - -adler32_rvv.o: $(SRCDIR)/adler32_rvv.c - $(CC) $(CFLAGS) $(RVVFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_rvv.c - -adler32_rvv.lo: $(SRCDIR)/adler32_rvv.c - $(CC) $(SFLAGS) $(RVVFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_rvv.c - -chunkset_rvv.o: $(SRCDIR)/chunkset_rvv.c - $(CC) $(CFLAGS) $(RVVFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_rvv.c - -chunkset_rvv.lo: $(SRCDIR)/chunkset_rvv.c - $(CC) $(SFLAGS) $(RVVFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_rvv.c - -compare256_rvv.o: $(SRCDIR)/compare256_rvv.c - $(CC) $(CFLAGS) $(RVVFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_rvv.c - -compare256_rvv.lo: $(SRCDIR)/compare256_rvv.c - $(CC) $(SFLAGS) $(RVVFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_rvv.c - -slide_hash_rvv.o: $(SRCDIR)/slide_hash_rvv.c - $(CC) $(CFLAGS) $(RVVFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_rvv.c - -slide_hash_rvv.lo: $(SRCDIR)/slide_hash_rvv.c - $(CC) $(SFLAGS) $(RVVFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_rvv.c - -crc32_zbc.o: $(SRCDIR)/crc32_zbc.c - $(CC) $(CFLAGS) $(ZBCFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_zbc.c - -crc32_zbc.lo: $(SRCDIR)/crc32_zbc.c - $(CC) $(SFLAGS) $(ZBCFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_zbc.c - -mostlyclean: clean -clean: - rm -f *.o *.lo *~ - rm -rf objs - rm -f *.gcda *.gcno *.gcov - -distclean: clean - rm -f Makefile diff --git a/modules/zlib/src/arch/riscv/README.md b/modules/zlib/src/arch/riscv/README.md deleted file mode 100644 index 013095c373..0000000000 --- a/modules/zlib/src/arch/riscv/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Building RISC-V Target with Cmake # - -> **Warning** -> Runtime rvv detection (using `hwcap`) requires linux kernel 6.5 or newer. -> -> When running on older kernels, we fall back to compile-time detection, potentially this can cause crashes if rvv is enabled at compile but not supported by the target cpu. -> Therefore if older kernel support is needed, rvv should be disabled if the target cpu does not support it. -## Prerequisite: Build RISC-V Clang Toolchain and QEMU ## - -If you don't have prebuilt clang and riscv64 qemu, you can refer to the [script](https://github.com/sifive/prepare-riscv-toolchain-qemu/blob/main/prepare_riscv_toolchain_qemu.sh) to get the source. Copy the script to the zlib-ng root directory, and run it to download the source and build them. Modify the content according to your conditions (e.g., toolchain version). - -```bash -./prepare_riscv_toolchain_qemu.sh -``` - -After running script, clang & qemu are built in `build-toolchain-qemu/riscv-clang/` & `build-toolchain-qemu/riscv-qemu/`. - -`build-toolchain-qemu/riscv-clang/` is your `TOOLCHAIN_PATH`. -`build-toolchain-qemu/riscv-qemu/bin/qemu-riscv64` is your `QEMU_PATH`. - -You can also download the prebuilt toolchain & qemu from [the release page](https://github.com/sifive/prepare-riscv-toolchain-qemu/releases), and enjoy using them. - -## Cross-Compile for RISC-V Target ## - -```bash -cmake -G Ninja -B ./build-riscv \ - -D CMAKE_TOOLCHAIN_FILE=./cmake/toolchain-riscv.cmake \ - -D CMAKE_INSTALL_PREFIX=./build-riscv/install \ - -D TOOLCHAIN_PATH={TOOLCHAIN_PATH} \ - -D QEMU_PATH={QEMU_PATH} \ - . - -cmake --build ./build-riscv -``` - -Disable the option if there is no RVV support: -``` --D WITH_RVV=OFF -``` - -## Run Unittests on User Mode QEMU ## - -```bash -cd ./build-riscv && ctest --verbose -``` diff --git a/modules/zlib/src/arch/riscv/adler32_rvv.c b/modules/zlib/src/arch/riscv/adler32_rvv.c deleted file mode 100644 index e446189302..0000000000 --- a/modules/zlib/src/arch/riscv/adler32_rvv.c +++ /dev/null @@ -1,119 +0,0 @@ -/* adler32_rvv.c - RVV version of adler32 - * Copyright (C) 2023 SiFive, Inc. All rights reserved. - * Contributed by Alex Chiang - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef RISCV_RVV - -#include "zbuild.h" -#include "adler32_p.h" - -#include - -Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t* restrict dst, const uint8_t *src, size_t len, int COPY) { - /* split Adler-32 into component sums */ - uint32_t sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (UNLIKELY(len == 1)) - return adler32_copy_tail(adler, dst, src, 1, sum2, 1, 1, COPY); - - /* in case short lengths are provided, keep it somewhat fast */ - if (UNLIKELY(len < 16)) - return adler32_copy_tail(adler, dst, src, len, sum2, 1, 15, COPY); - - size_t left = len; - size_t vl = __riscv_vsetvlmax_e8m1(); - vl = MIN(vl, 256); - vuint32m4_t v_buf32_accu = __riscv_vmv_v_x_u32m4(0, vl); - vuint32m4_t v_adler32_prev_accu = __riscv_vmv_v_x_u32m4(0, vl); - vuint16m2_t v_buf16_accu; - - /* - * We accumulate 8-bit data, and to prevent overflow, we have to use a 32-bit accumulator. - * However, adding 8-bit data into a 32-bit accumulator isn't efficient. We use 16-bit & 32-bit - * accumulators to boost performance. - * - * The block_size is the largest multiple of vl that <= 256, because overflow would occur when - * vl > 256 (255 * 256 <= UINT16_MAX). - * - * We accumulate 8-bit data into a 16-bit accumulator and then - * move the data into the 32-bit accumulator at the last iteration. - */ - size_t block_size = (256 / vl) * vl; - size_t nmax_limit = (NMAX / block_size); - size_t cnt = 0; - while (left >= block_size) { - v_buf16_accu = __riscv_vmv_v_x_u16m2(0, vl); - size_t subprob = block_size; - while (subprob > 0) { - vuint8m1_t v_buf8 = __riscv_vle8_v_u8m1(src, vl); - if (COPY) __riscv_vse8_v_u8m1(dst, v_buf8, vl); - v_adler32_prev_accu = __riscv_vwaddu_wv_u32m4(v_adler32_prev_accu, v_buf16_accu, vl); - v_buf16_accu = __riscv_vwaddu_wv_u16m2(v_buf16_accu, v_buf8, vl); - src += vl; - if (COPY) dst += vl; - subprob -= vl; - } - v_adler32_prev_accu = __riscv_vmacc_vx_u32m4(v_adler32_prev_accu, block_size / vl, v_buf32_accu, vl); - v_buf32_accu = __riscv_vwaddu_wv_u32m4(v_buf32_accu, v_buf16_accu, vl); - left -= block_size; - /* do modulo once each block of NMAX size */ - if (++cnt >= nmax_limit) { - v_adler32_prev_accu = __riscv_vremu_vx_u32m4(v_adler32_prev_accu, BASE, vl); - v_buf32_accu = __riscv_vremu_vx_u32m4(v_buf32_accu, BASE, vl); - cnt = 0; - } - } - /* the left len <= 256 now, we can use 16-bit accum safely */ - v_buf16_accu = __riscv_vmv_v_x_u16m2(0, vl); - size_t res = left; - while (left >= vl) { - vuint8m1_t v_buf8 = __riscv_vle8_v_u8m1(src, vl); - if (COPY) __riscv_vse8_v_u8m1(dst, v_buf8, vl); - v_adler32_prev_accu = __riscv_vwaddu_wv_u32m4(v_adler32_prev_accu, v_buf16_accu, vl); - v_buf16_accu = __riscv_vwaddu_wv_u16m2(v_buf16_accu, v_buf8, vl); - src += vl; - if (COPY) dst += vl; - left -= vl; - } - v_adler32_prev_accu = __riscv_vmacc_vx_u32m4(v_adler32_prev_accu, res / vl, v_buf32_accu, vl); - v_adler32_prev_accu = __riscv_vremu_vx_u32m4(v_adler32_prev_accu, BASE, vl); - v_buf32_accu = __riscv_vwaddu_wv_u32m4(v_buf32_accu, v_buf16_accu, vl); - - vuint32m4_t v_seq = __riscv_vid_v_u32m4(vl); - vuint32m4_t v_rev_seq = __riscv_vrsub_vx_u32m4(v_seq, vl, vl); - vuint32m4_t v_sum32_accu = __riscv_vmul_vv_u32m4(v_buf32_accu, v_rev_seq, vl); - - v_sum32_accu = __riscv_vadd_vv_u32m4(v_sum32_accu, __riscv_vmul_vx_u32m4(v_adler32_prev_accu, vl, vl), vl); - - vuint32m1_t v_sum2_sum = __riscv_vmv_s_x_u32m1(0, vl); - v_sum2_sum = __riscv_vredsum_vs_u32m4_u32m1(v_sum32_accu, v_sum2_sum, vl); - uint32_t sum2_sum = __riscv_vmv_x_s_u32m1_u32(v_sum2_sum) % BASE; - - sum2 += (sum2_sum + adler * ((len - left) % BASE)); - - vuint32m1_t v_adler_sum = __riscv_vmv_s_x_u32m1(0, vl); - v_adler_sum = __riscv_vredsum_vs_u32m4_u32m1(v_buf32_accu, v_adler_sum, vl); - uint32_t adler_sum = __riscv_vmv_x_s_u32m1_u32(v_adler_sum) % BASE; - - adler += adler_sum; - - sum2 %= BASE; - adler %= BASE; - - /* Process tail (left < 256). */ - return adler32_copy_tail(adler, dst, src, left, sum2, left != 0, 255, COPY); -} - -Z_INTERNAL uint32_t adler32_rvv(uint32_t adler, const uint8_t *buf, size_t len) { - return adler32_copy_impl(adler, NULL, buf, len, 0); -} - -Z_INTERNAL uint32_t adler32_copy_rvv(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, dst, src, len, 1); -} - -#endif // RISCV_RVV diff --git a/modules/zlib/src/arch/riscv/chunkset_rvv.c b/modules/zlib/src/arch/riscv/chunkset_rvv.c deleted file mode 100644 index cd8ed3cfd2..0000000000 --- a/modules/zlib/src/arch/riscv/chunkset_rvv.c +++ /dev/null @@ -1,126 +0,0 @@ -/* chunkset_rvv.c - RVV version of chunkset - * Copyright (C) 2023 SiFive, Inc. All rights reserved. - * Contributed by Alex Chiang - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef RISCV_RVV - -#include "zbuild.h" - -#include - -/* - * RISC-V glibc would enable RVV optimized memcpy at runtime by IFUNC, - * so we prefer using large size chunk and copy memory as much as possible. - */ -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 - -#define CHUNK_MEMSET_RVV_IMPL(from, chunk, elen) \ -do { \ - size_t vl, len = sizeof(*chunk) / sizeof(uint##elen##_t); \ - uint##elen##_t val = *(uint##elen##_t*)from; \ - uint##elen##_t* chunk_p = (uint##elen##_t*)chunk; \ - do { \ - vl = __riscv_vsetvl_e##elen##m4(len); \ - vuint##elen##m4_t v_val = __riscv_vmv_v_x_u##elen##m4(val, vl); \ - __riscv_vse##elen##_v_u##elen##m4(chunk_p, v_val, vl); \ - len -= vl; chunk_p += vl; \ - } while (len > 0); \ -} while (0) - -/* We don't have a 32-byte datatype for RISC-V arch. */ -typedef struct chunk_s { - uint64_t data[4]; -} chunk_t; - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - CHUNK_MEMSET_RVV_IMPL(from, chunk, 16); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - CHUNK_MEMSET_RVV_IMPL(from, chunk, 32); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - CHUNK_MEMSET_RVV_IMPL(from, chunk, 64); -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - memcpy(chunk->data, (uint8_t *)s, sizeof(*chunk)); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - memcpy(out, chunk->data, sizeof(*chunk)); -} - -#define CHUNKSIZE chunksize_rvv -#define CHUNKCOPY chunkcopy_rvv -#define CHUNKUNROLL chunkunroll_rvv -#define CHUNKMEMSET chunkmemset_rvv -#define CHUNKMEMSET_SAFE chunkmemset_safe_rvv - -#define HAVE_CHUNKCOPY - -/* - * Assuming that the length is non-zero, and that `from` lags `out` by at least - * sizeof chunk_t bytes, please see the comments in chunkset_tpl.h. - * - * We load/store a single chunk once in the `CHUNKCOPY`. - * However, RISC-V glibc would enable RVV optimized memcpy at runtime by IFUNC, - * such that, we prefer copy large memory size once to make good use of the the RVV advance. - * - * To be aligned to the other platforms, we didn't modify `CHUNKCOPY` method a lot, - * but we still copy as much memory as possible for some conditions. - * - * case 1: out - from >= len (no overlap) - * We can use memcpy to copy `len` size once - * because the memory layout would be the same. - * - * case 2: overlap - * We copy N chunks using memcpy at once, aiming to achieve our goal: - * to copy as much memory as possible. - * - * After using a single memcpy to copy N chunks, we have to use series of - * loadchunk and storechunk to ensure the result is correct. - */ -static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, size_t len) { - Assert(len > 0, "chunkcopy should never have a length 0"); - size_t dist = out - from; - if (out < from || dist >= len) { - memcpy(out, from, len); - out += len; - from += len; - return out; - } - - size_t align = ((len - 1) % sizeof(chunk_t)) + 1; - memcpy(out, from, sizeof(chunk_t)); - out += align; - from += align; - len -= align; - - size_t vl = (dist / sizeof(chunk_t)) * sizeof(chunk_t); - while (len > dist) { - memcpy(out, from, vl); - out += vl; - from += vl; - len -= vl; - } - - if (len > 0) { - memcpy(out, from, len); - out += len; - } - return out; -} - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_rvv - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/riscv/compare256_rvv.c b/modules/zlib/src/arch/riscv/compare256_rvv.c deleted file mode 100644 index b9420ffd5b..0000000000 --- a/modules/zlib/src/arch/riscv/compare256_rvv.c +++ /dev/null @@ -1,48 +0,0 @@ -/* compare256_rvv.c - RVV version of compare256 - * Copyright (C) 2023 SiFive, Inc. All rights reserved. - * Contributed by Alex Chiang - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef RISCV_RVV - -#include "zbuild.h" -#include "zmemory.h" -#include "deflate.h" - -#include - -static inline uint32_t compare256_rvv_static(const uint8_t *src0, const uint8_t *src1) { - uint32_t len = 0; - size_t vl; - long found_diff; - do { - vl = __riscv_vsetvl_e8m4(256 - len); - vuint8m4_t v_src0 = __riscv_vle8_v_u8m4(src0, vl); - vuint8m4_t v_src1 = __riscv_vle8_v_u8m4(src1, vl); - vbool2_t v_mask = __riscv_vmsne_vv_u8m4_b2(v_src0, v_src1, vl); - found_diff = __riscv_vfirst_m_b2(v_mask, vl); - if (found_diff >= 0) - return len + (uint32_t)found_diff; - src0 += vl, src1 += vl, len += vl; - } while (len < 256); - - return 256; -} - -Z_INTERNAL uint32_t compare256_rvv(const uint8_t *src0, const uint8_t *src1) { - return compare256_rvv_static(src0, src1); -} - -#define LONGEST_MATCH longest_match_rvv -#define COMPARE256 compare256_rvv_static - -#include "match_tpl.h" - -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_rvv -#define COMPARE256 compare256_rvv_static - -#include "match_tpl.h" - -#endif // RISCV_RVV diff --git a/modules/zlib/src/arch/riscv/crc32_zbc.c b/modules/zlib/src/arch/riscv/crc32_zbc.c deleted file mode 100644 index cf52279b80..0000000000 --- a/modules/zlib/src/arch/riscv/crc32_zbc.c +++ /dev/null @@ -1,103 +0,0 @@ -/* crc32_zbc.c - RISCV Zbc version of crc32 - * Copyright (C) 2025 ByteDance. All rights reserved. - * Contributed by Yin Tong - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef RISCV_CRC32_ZBC - -#include "zbuild.h" -#include "arch_functions.h" - -#define CLMUL_MIN_LEN 16 // Minimum size of buffer for _crc32_clmul -#define CLMUL_CHUNK_LEN 16 // Length of chunk for clmul - -#define CONSTANT_R3 0x1751997d0ULL -#define CONSTANT_R4 0x0ccaa009eULL -#define CONSTANT_R5 0x163cd6124ULL -#define MASK32 0xFFFFFFFF -#define CRCPOLY_TRUE_LE_FULL 0x1DB710641ULL -#define CONSTANT_RU 0x1F7011641ULL - -static inline uint64_t clmul(uint64_t a, uint64_t b) { - uint64_t res; - __asm__ volatile("clmul %0, %1, %2" : "=r"(res) : "r"(a), "r"(b)); - return res; -} - -static inline uint64_t clmulh(uint64_t a, uint64_t b) { - uint64_t res; - __asm__ volatile("clmulh %0, %1, %2" : "=r"(res) : "r"(a), "r"(b)); - return res; -} - -Z_FORCEINLINE static uint32_t crc32_clmul_impl(uint64_t crc, const unsigned char *buf, uint64_t len) { - const uint64_t *buf64 = (const uint64_t *)buf; - uint64_t low = buf64[0] ^ crc; - uint64_t high = buf64[1]; - - if (len < 16) - goto finish_fold; - len -= 16; - buf64 += 2; - - // process each 16-byte block - while (len >= 16) { - uint64_t t2 = clmul(CONSTANT_R4, high); - uint64_t t3 = clmulh(CONSTANT_R4, high); - - uint64_t t0_new = clmul(CONSTANT_R3, low); - uint64_t t1_new = clmulh(CONSTANT_R3, low); - - // Combine the results and XOR with new data - low = t0_new ^ t2; - high = t1_new ^ t3; - low ^= buf64[0]; - high ^= buf64[1]; - - buf64 += 2; - len -= 16; - } - -finish_fold: - // Fold the 128-bit result into 64 bits - uint64_t fold_t3 = clmulh(low, CONSTANT_R4); - uint64_t fold_t2 = clmul(low, CONSTANT_R4); - low = high ^ fold_t2; - high = fold_t3; - - // Combine the low and high parts and perform polynomial reduction - uint64_t combined = (low >> 32) | ((high & MASK32) << 32); - uint64_t reduced_low = clmul(low & MASK32, CONSTANT_R5) ^ combined; - - // Barrett reduction step - uint64_t barrett = clmul(reduced_low & MASK32, CONSTANT_RU) & MASK32; - barrett = clmul(barrett, CRCPOLY_TRUE_LE_FULL); - uint64_t final = barrett ^ reduced_low; - - // Return the high 32 bits as the final CRC - return (uint32_t)(final >> 32); -} - -Z_INTERNAL uint32_t crc32_riscv64_zbc(uint32_t crc, const uint8_t *buf, size_t len) { - if (len < CLMUL_MIN_LEN) { - return crc32_braid(crc, buf, len); - } - - uint64_t unaligned_length = len % CLMUL_CHUNK_LEN; - if (unaligned_length) { - crc = crc32_braid(crc, buf, unaligned_length); - buf += unaligned_length; - len -= unaligned_length; - } - - crc = crc32_clmul_impl(~crc, buf, len); - return ~crc; -} - -Z_INTERNAL uint32_t crc32_copy_riscv64_zbc(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - crc = crc32_riscv64_zbc(crc, src, len); - memcpy(dst, src, len); - return crc; -} -#endif diff --git a/modules/zlib/src/arch/riscv/riscv_features.c b/modules/zlib/src/arch/riscv/riscv_features.c deleted file mode 100644 index b23f10a699..0000000000 --- a/modules/zlib/src/arch/riscv/riscv_features.c +++ /dev/null @@ -1,99 +0,0 @@ -#ifdef RISCV_FEATURES - -#define _DEFAULT_SOURCE 1 /* For syscall() */ - -#include "zbuild.h" -#include "riscv_features.h" - -#include - -#if defined(__linux__) && defined(HAVE_SYS_AUXV_H) -# include -#endif - -#if defined(__linux__) && defined(HAVE_ASM_HWPROBE_H) -# include -# include /* For __NR_riscv_hwprobe */ -# include /* For syscall() */ -#endif - -#define ISA_V_HWCAP (1 << ('v' - 'a')) -#define ISA_ZBC_HWCAP (1 << 29) - -static int riscv_check_features_runtime_hwprobe(struct riscv_cpu_features *features) { -#if defined(__NR_riscv_hwprobe) && defined(RISCV_HWPROBE_KEY_IMA_EXT_0) - struct riscv_hwprobe probes[] = { - {RISCV_HWPROBE_KEY_IMA_EXT_0, 0}, - }; - int ret; - unsigned i; - - ret = syscall(__NR_riscv_hwprobe, probes, sizeof(probes) / sizeof(probes[0]), 0, NULL, 0); - - if (ret != 0) { - /* Kernel does not support hwprobe */ - return 0; - } - - for (i = 0; i < sizeof(probes) / sizeof(probes[0]); i++) { - switch (probes[i].key) { - case RISCV_HWPROBE_KEY_IMA_EXT_0: -# ifdef RISCV_HWPROBE_IMA_V - features->has_rvv = !!(probes[i].value & RISCV_HWPROBE_IMA_V); -# endif -# ifdef RISCV_HWPROBE_EXT_ZBC - features->has_zbc = !!(probes[i].value & RISCV_HWPROBE_EXT_ZBC); -# endif - break; - } - } - - return 1; -#else - return 0; -#endif -} - -static int riscv_check_features_runtime_hwcap(struct riscv_cpu_features *features) { -#if defined(__linux__) && defined(HAVE_SYS_AUXV_H) - unsigned long hw_cap = getauxval(AT_HWCAP); - - features->has_rvv = hw_cap & ISA_V_HWCAP; - features->has_zbc = hw_cap & ISA_ZBC_HWCAP; - - return 1; -#else - return 0; -#endif -} - -static void riscv_check_features_runtime(struct riscv_cpu_features *features) { - if (riscv_check_features_runtime_hwprobe(features)) - return; - - riscv_check_features_runtime_hwcap(features); -} - -void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features) { - riscv_check_features_runtime(features); -#ifdef RISCV_RVV - if (features->has_rvv) { - size_t e8m1_vec_len; - intptr_t vtype_reg_val; - // Check that a vuint8m1_t vector is at least 16 bytes and that tail - // agnostic and mask agnostic mode are supported - // - __asm__ volatile( - "vsetvli %0, zero, e8, m1, ta, ma\n\t" - "csrr %1, vtype" - : "=r"(e8m1_vec_len), "=r"(vtype_reg_val)); - - // The RVV target is supported if the VILL bit of VTYPE (the MSB bit of - // VTYPE) is not set and the length of a vuint8m1_t vector is at least 16 - // bytes - features->has_rvv = (vtype_reg_val >= 0 && e8m1_vec_len >= 16); - } -#endif -} - -#endif diff --git a/modules/zlib/src/arch/riscv/riscv_features.h b/modules/zlib/src/arch/riscv/riscv_features.h deleted file mode 100644 index 42855a1b6b..0000000000 --- a/modules/zlib/src/arch/riscv/riscv_features.h +++ /dev/null @@ -1,19 +0,0 @@ -/* riscv_features.h -- check for riscv features. - * - * Copyright (C) 2023 SiFive, Inc. All rights reserved. - * Contributed by Alex Chiang - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef RISCV_FEATURES_H_ -#define RISCV_FEATURES_H_ - -struct riscv_cpu_features { - int has_rvv; - int has_zbc; -}; - -void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features); - -#endif /* RISCV_FEATURES_H_ */ diff --git a/modules/zlib/src/arch/riscv/riscv_functions.h b/modules/zlib/src/arch/riscv/riscv_functions.h deleted file mode 100644 index bc17c1b819..0000000000 --- a/modules/zlib/src/arch/riscv/riscv_functions.h +++ /dev/null @@ -1,69 +0,0 @@ -/* riscv_functions.h -- RISCV implementations for arch-specific functions. - * - * Copyright (C) 2023 SiFive, Inc. All rights reserved. - * Contributed by Alex Chiang - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef RISCV_FUNCTIONS_H_ -#define RISCV_FUNCTIONS_H_ - -#include "riscv_natives.h" - -#define CRC32_BRAID_FALLBACK /* used by crc32_zbc */ - -#ifdef RISCV_RVV -uint32_t adler32_rvv(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_rvv(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -uint8_t* chunkmemset_safe_rvv(uint8_t *out, uint8_t *from, size_t len, size_t left); -uint32_t compare256_rvv(const uint8_t *src0, const uint8_t *src1); - -uint32_t longest_match_rvv(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_rvv(deflate_state *const s, uint32_t cur_match); -void slide_hash_rvv(deflate_state *s); -void inflate_fast_rvv(PREFIX3(stream) *strm, uint32_t start); -#endif - -#ifndef RISCV_RVV_NATIVE -# define ADLER32_FALLBACK -# define CHUNKSET_FALLBACK -# define COMPARE256_FALLBACK -# define SLIDE_HASH_FALLBACK -#endif - -#ifdef RISCV_CRC32_ZBC -uint32_t crc32_riscv64_zbc(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_riscv64_zbc(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif - -#ifdef DISABLE_RUNTIME_CPU_DETECTION -// RISCV - RVV -# ifdef RISCV_RVV_NATIVE -# undef native_adler32 -# define native_adler32 adler32_rvv -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_rvv -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_rvv -# undef native_compare256 -# define native_compare256 compare256_rvv -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_rvv -# undef native_longest_match -# define native_longest_match longest_match_rvv -# undef native_longest_match_roll -# define native_longest_match_roll longest_match_roll_rvv -# undef native_slide_hash -# define native_slide_hash slide_hash_rvv -# endif -// RISCV - CRC32 -# ifdef RISCV_ZBC_NATIVE -# undef native_crc32 -# define native_crc32 crc32_riscv64_zbc -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_riscv64_zbc -# endif -#endif - -#endif /* RISCV_FUNCTIONS_H_ */ diff --git a/modules/zlib/src/arch/riscv/riscv_natives.h b/modules/zlib/src/arch/riscv/riscv_natives.h deleted file mode 100644 index 38d7aba648..0000000000 --- a/modules/zlib/src/arch/riscv/riscv_natives.h +++ /dev/null @@ -1,19 +0,0 @@ -/* riscv_natives.h -- RISCV compile-time feature detection macros. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef RISCV_NATIVES_H_ -#define RISCV_NATIVES_H_ - -#if defined(__riscv_v) && defined(__linux__) -# ifdef RISCV_RVV -# define RISCV_RVV_NATIVE -# endif -#endif -#if defined(__riscv_zbc) -# ifdef RISCV_CRC32_ZBC -# define RISCV_ZBC_NATIVE -# endif -#endif - -#endif /* RISCV_NATIVES_H_ */ diff --git a/modules/zlib/src/arch/riscv/slide_hash_rvv.c b/modules/zlib/src/arch/riscv/slide_hash_rvv.c deleted file mode 100644 index e794c38204..0000000000 --- a/modules/zlib/src/arch/riscv/slide_hash_rvv.c +++ /dev/null @@ -1,33 +0,0 @@ -/* slide_hash_rvv.c - RVV version of slide_hash - * Copyright (C) 2023 SiFive, Inc. All rights reserved. - * Contributed by Alex Chiang - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef RISCV_RVV - -#include "zbuild.h" -#include "deflate.h" - -#include - -static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { - size_t vl; - while (entries > 0) { - vl = __riscv_vsetvl_e16m4(entries); - vuint16m4_t v_tab = __riscv_vle16_v_u16m4(table, vl); - vuint16m4_t v_diff = __riscv_vssubu_vx_u16m4(v_tab, wsize, vl); - __riscv_vse16_v_u16m4(table, v_diff, vl); - table += vl, entries -= vl; - } -} - -Z_INTERNAL void slide_hash_rvv(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - - slide_hash_chain(s->head, HASH_SIZE, wsize); - slide_hash_chain(s->prev, wsize, wsize); -} - -#endif // RISCV_RVV diff --git a/modules/zlib/src/arch/s390/Makefile.in b/modules/zlib/src/arch/s390/Makefile.in deleted file mode 100644 index 7d07ea47f4..0000000000 --- a/modules/zlib/src/arch/s390/Makefile.in +++ /dev/null @@ -1,54 +0,0 @@ -# Makefile for zlib-ng -# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler -# For conditions of distribution and use, see copyright notice in zlib.h - -CC= -CFLAGS= -SFLAGS= -INCLUDES= -SUFFIX= -S390VXFLAG= -NOLTOFLAG= - -SRCDIR=. -SRCTOP=../.. -TOPDIR=$(SRCTOP) - -s390_features.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/s390_features.c - -s390_features.lo: - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/s390_features.c - -dfltcc_deflate.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_deflate.c - -dfltcc_deflate.lo: - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_deflate.c - -dfltcc_inflate.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_inflate.c - -dfltcc_inflate.lo: - $(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_inflate.c - -crc32_vx.o: - $(CC) $(CFLAGS) $(S390VXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vx.c - -crc32_vx.lo: - $(CC) $(SFLAGS) $(S390VXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vx.c - -slide_hash_vx.o: - $(CC) $(CFLAGS) $(S390VXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vx.c - -slide_hash_vx.lo: - $(CC) $(SFLAGS) $(S390VXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vx.c - -mostlyclean: clean -clean: - rm -f *.o *.lo *~ - rm -rf objs - rm -f *.gcda *.gcno *.gcov - -distclean: clean - rm -f Makefile diff --git a/modules/zlib/src/arch/s390/README.md b/modules/zlib/src/arch/s390/README.md deleted file mode 100644 index c56ffd7654..0000000000 --- a/modules/zlib/src/arch/s390/README.md +++ /dev/null @@ -1,265 +0,0 @@ -# Introduction - -This directory contains SystemZ deflate hardware acceleration support. -It can be enabled using the following build commands: - - $ ./configure --with-dfltcc-deflate --with-dfltcc-inflate - $ make - -or - - $ cmake -DWITH_DFLTCC_DEFLATE=1 -DWITH_DFLTCC_INFLATE=1 . - $ make - -When built like this, zlib-ng would compress using hardware on level 1, -and using software on all other levels. Decompression will always happen -in hardware. In order to enable hardware compression for levels 1-6 -(i.e. to make it used by default) one could add -`-DDFLTCC_LEVEL_MASK=0x7e` to CFLAGS when building zlib-ng. - -SystemZ deflate hardware acceleration is available on [IBM z15]( -https://www.ibm.com/products/z15) and newer machines under the name [ -"Integrated Accelerator for zEnterprise Data Compression"]( -https://www.ibm.com/support/z-content-solutions/compression/). The -programming interface to it is a machine instruction called DEFLATE -CONVERSION CALL (DFLTCC). It is documented in Chapter 26 of [Principles -of Operation](https://publibfp.dhe.ibm.com/epubs/pdf/a227832c.pdf). Both -the code and the rest of this document refer to this feature simply as -"DFLTCC". - -# Performance - -Performance figures are published [here]( -https://github.com/iii-i/zlib-ng/wiki/Performance-with-dfltcc-patch-applied-and-dfltcc-support-built-on-dfltcc-enabled-machine -). The compression speed-up can be as high as 110x and the decompression -speed-up can be as high as 15x. - -# Limitations - -Two DFLTCC compression calls with identical inputs are not guaranteed to -produce identical outputs. Therefore care should be taken when using -hardware compression when reproducible results are desired. In -particular, zlib-ng-specific `zng_deflateSetParams` call allows setting -`Z_DEFLATE_REPRODUCIBLE` parameter, which disables DFLTCC support for a -particular stream. - -DFLTCC does not support every single zlib-ng feature, in particular: - -* `inflate(Z_BLOCK)` and `inflate(Z_TREES)` -* `inflateMark()` -* `inflatePrime()` -* `inflateSyncPoint()` - -When used, these functions will either switch to software, or, in case -this is not possible, gracefully fail. - -# Code structure - -All SystemZ-specific code lives in `arch/s390` directory and is -integrated with the rest of zlib-ng using hook macros. - -## Hook macros - -DFLTCC takes as arguments a parameter block, an input buffer, an output -buffer, and a window. Parameter blocks are stored alongside zlib states; -buffers are forwarded from the caller; and window - which must be -4k-aligned and is always 64k large, is managed using the `PAD_WINDOW()`, -`WINDOW_PAD_SIZE`, `HINT_ALIGNED_WINDOW` and `DEFLATE_ADJUST_WINDOW_SIZE()` -and `INFLATE_ADJUST_WINDOW_SIZE()` hooks. - -Software and hardware window formats do not match, therefore, -`deflateSetDictionary()`, `deflateGetDictionary()`, `inflateSetDictionary()` -and `inflateGetDictionary()` need special handling, which is triggered using -`DEFLATE_SET_DICTIONARY_HOOK()`, `DEFLATE_GET_DICTIONARY_HOOK()`, -`INFLATE_SET_DICTIONARY_HOOK()` and `INFLATE_GET_DICTIONARY_HOOK()` macros. - -`deflateResetKeep()` and `inflateResetKeep()` update the DFLTCC -parameter block using `DEFLATE_RESET_KEEP_HOOK()` and -`INFLATE_RESET_KEEP_HOOK()` macros. - -`INFLATE_PRIME_HOOK()`, `INFLATE_MARK_HOOK()` and -`INFLATE_SYNC_POINT_HOOK()` macros make the respective unsupported -calls gracefully fail. - -`DEFLATE_PARAMS_HOOK()` implements switching between hardware and -software compression mid-stream using `deflateParams()`. Switching -normally entails flushing the current block, which might not be possible -in low memory situations. `deflateParams()` uses `DEFLATE_DONE()` hook -in order to detect and gracefully handle such situations. - -The algorithm implemented in hardware has different compression ratio -than the one implemented in software. `DEFLATE_BOUND_ADJUST_COMPLEN()` -and `DEFLATE_NEED_CONSERVATIVE_BOUND()` macros make `deflateBound()` -return the correct results for the hardware implementation. - -Actual compression and decompression are handled by `DEFLATE_HOOK()` and -`INFLATE_TYPEDO_HOOK()` macros. Since inflation with DFLTCC manages the -window on its own, calling `updatewindow()` is suppressed using -`INFLATE_NEED_UPDATEWINDOW()` macro. - -In addition to compression, DFLTCC computes CRC-32 and Adler-32 -checksums, therefore, whenever it's used, software checksumming is -suppressed using `DEFLATE_NEED_CHECKSUM()` and `INFLATE_NEED_CHECKSUM()` -macros. - -While software always produces reproducible compression results, this -is not the case for DFLTCC. Therefore, zlib-ng users are given the -ability to specify whether or not reproducible compression results -are required. While it is always possible to specify this setting -before the compression begins, it is not always possible to do so in -the middle of a deflate stream - the exact conditions for that are -determined by `DEFLATE_CAN_SET_REPRODUCIBLE()` macro. - -## SystemZ-specific code - -When zlib-ng is built with DFLTCC, the hooks described above are -converted to calls to functions, which are implemented in -`arch/s390/dfltcc_*` files. The functions can be grouped in three broad -categories: - -* Base DFLTCC support, e.g. wrapping the machine instruction - `dfltcc()`. -* Translating between software and hardware data formats, e.g. - `dfltcc_deflate_set_dictionary()`. -* Translating between software and hardware state machines, e.g. - `dfltcc_deflate()` and `dfltcc_inflate()`. - -The functions from the first two categories are fairly simple, however, -various quirks in both software and hardware state machines make the -functions from the third category quite complicated. - -### `dfltcc_deflate()` function - -This function is called by `deflate()` and has the following -responsibilities: - -* Checking whether DFLTCC can be used with the current stream. If this - is not the case, then it returns `0`, making `deflate()` use some - other function in order to compress in software. Otherwise it returns - `1`. -* Block management and Huffman table generation. DFLTCC ends blocks only - when explicitly instructed to do so by the software. Furthermore, - whether to use fixed or dynamic Huffman tables must also be determined - by the software. Since looking at data in order to gather statistics - would negate performance benefits, the following approach is used: the - first `DFLTCC_FIRST_FHT_BLOCK_SIZE` bytes are placed into a fixed - block, and every next `DFLTCC_BLOCK_SIZE` bytes are placed into - dynamic blocks. -* Writing EOBS. Block Closing Control bit in the parameter block - instructs DFLTCC to write EOBS, however, certain conditions need to be - met: input data length must be non-zero or Continuation Flag must be - set. To put this in simpler terms, DFLTCC will silently refuse to - write EOBS if this is the only thing that it is asked to do. Since the - code has to be able to emit EOBS in software anyway, in order to avoid - tricky corner cases Block Closing Control is never used. Whether to - write EOBS is instead controlled by `soft_bcc` variable. -* Triggering block post-processing. Depending on flush mode, `deflate()` - must perform various additional actions when a block or a stream ends. - `dfltcc_deflate()` informs `deflate()` about this using - `block_state *result` parameter. -* Converting software state fields into hardware parameter block fields, - and vice versa. For example, `wrap` and Check Value Type or `bi_valid` - and Sub-Byte Boundary. Certain fields cannot be translated and must - persist untouched in the parameter block between calls, for example, - Continuation Flag or Continuation State Buffer. -* Handling flush modes and low-memory situations. These aspects are - quite intertwined and pervasive. The general idea here is that the - code must not do anything in software - whether explicitly by e.g. - calling `send_eobs()`, or implicitly - by returning to `deflate()` - with certain return and `*result` values, when Continuation Flag is - set. -* Ending streams. When a new block is started and flush mode is - `Z_FINISH`, Block Header Final parameter block bit is used to mark - this block as final. However, sometimes an empty final block is - needed, and, unfortunately, just like with EOBS, DFLTCC will silently - refuse to do this. The general idea of DFLTCC implementation is to - rely as much as possible on the existing code. Here in order to do - this, the code pretends that it does not support DFLTCC, which makes - `deflate()` call a software compression function, which writes an - empty final block. Whether this is required is controlled by - `need_empty_block` variable. -* Error handling. This is simply converting - Operation-Ending-Supplemental Code to string. Errors can only happen - due to things like memory corruption, and therefore they don't affect - the `deflate()` return code. - -### `dfltcc_inflate()` function - -This function is called by `inflate()` from the `TYPEDO` state (that is, -when all the metadata is parsed and the stream is positioned at the type -bits of deflate block header) and it's responsible for the following: - -* Falling back to software when flush mode is `Z_BLOCK` or `Z_TREES`. - Unfortunately, there is no way to ask DFLTCC to stop decompressing on - block or tree boundary. -* `inflate()` decompression loop management. This is controlled using - the return value, which can be either `DFLTCC_INFLATE_BREAK` or - `DFLTCC_INFLATE_CONTINUE`. -* Converting software state fields into hardware parameter block fields, - and vice versa. For example, `whave` and History Length or `wnext` and - History Offset. -* Ending streams. This instructs `inflate()` to return `Z_STREAM_END` - and is controlled by `last` state field. -* Error handling. Like deflate, error handling comprises - Operation-Ending-Supplemental Code to string conversion. Unlike - deflate, errors may happen due to bad inputs, therefore they are - propagated to `inflate()` by setting `mode` field to `MEM` or `BAD`. - -# Testing - -Given complexity of DFLTCC machine instruction, it is not clear whether -QEMU TCG will ever support it. At the time of writing, one has to have -access to an IBM z15+ VM or LPAR in order to test DFLTCC support. Since -DFLTCC is a non-privileged instruction, neither special VM/LPAR -configuration nor root are required. - -zlib-ng CI uses an IBM-provided z15 self-hosted builder for the DFLTCC -testing. There is no official IBM Z GitHub Actions runner, so we build -one inspired by `anup-kodlekere/gaplib`. -Future updates to actions-runner might need an updated patch. The .net -version number patch has been separated into a separate file to avoid a -need for constantly changing the patch. - -## Configuring the builder. - -### Install prerequisites. -``` -sudo dnf install podman -``` - -### Create a config file, needs github personal access token. -Access token needs permissions; Repo Admin RW, Org Self-hosted runners RW. -For details, consult -https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-a-repository - -#### Create file /etc/actions-runner: -``` -REPO=/ -PAT_TOKEN= -``` - -#### Set permissions on /etc/actions-runner: -``` -chmod 600 /etc/actions-runner -``` - -### Add actions-runner service. -``` -sudo cp self-hosted-builder/actions-runner.service /etc/systemd/system/ -sudo systemctl daemon-reload -``` - -### Autostart actions-runner. -``` -$ sudo systemctl enable --now actions-runner -``` - -### Add auto-rebuild cronjob -``` -sudo cp self-hosted-builder/actions-runner-rebuild.sh /etc/cron.weekly/ -chmod +x /etc/cron.weekly/actions-runner-rebuild.sh -``` - -## Building / Rebuilding the container -``` -sudo /etc/cron.weekly/actions-runner-rebuild.sh -``` diff --git a/modules/zlib/src/arch/s390/crc32_vx.c b/modules/zlib/src/arch/s390/crc32_vx.c deleted file mode 100644 index 2a7099b892..0000000000 --- a/modules/zlib/src/arch/s390/crc32_vx.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Hardware-accelerated CRC-32 variants for Linux on z Systems - * - * Use the z/Architecture Vector Extension Facility to accelerate the - * computing of bitreflected CRC-32 checksums. - * - * This CRC-32 implementation algorithm is bitreflected and processes - * the least-significant bit first (Little-Endian). - * - * This code was originally written by Hendrik Brueckner - * for use in the Linux kernel and has been - * relicensed under the zlib license. - */ - -#ifdef S390_VX - -#include "zbuild.h" -#include "arch_functions.h" - -#include "vx_intrins.h" - -static uint32_t crc32_le_vgfm_16(uint32_t crc, const uint8_t *buf, size_t len) { - /* - * The CRC-32 constant block contains reduction constants to fold and - * process particular chunks of the input data stream in parallel. - * - * For the CRC-32 variants, the constants are precomputed according to - * these definitions: - * - * R1 = [(x4*128+32 mod P'(x) << 32)]' << 1 - * R2 = [(x4*128-32 mod P'(x) << 32)]' << 1 - * R3 = [(x128+32 mod P'(x) << 32)]' << 1 - * R4 = [(x128-32 mod P'(x) << 32)]' << 1 - * R5 = [(x64 mod P'(x) << 32)]' << 1 - * R6 = [(x32 mod P'(x) << 32)]' << 1 - * - * The bitreflected Barret reduction constant, u', is defined as - * the bit reversal of floor(x**64 / P(x)). - * - * where P(x) is the polynomial in the normal domain and the P'(x) is the - * polynomial in the reversed (bitreflected) domain. - * - * CRC-32 (IEEE 802.3 Ethernet, ...) polynomials: - * - * P(x) = 0x04C11DB7 - * P'(x) = 0xEDB88320 - */ - const uv16qi perm_le2be = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; /* BE->LE mask */ - const uv2di r2r1 = {0x1C6E41596, 0x154442BD4}; /* R2, R1 */ - const uv2di r4r3 = {0x0CCAA009E, 0x1751997D0}; /* R4, R3 */ - const uv2di r5 = {0, 0x163CD6124}; /* R5 */ - const uv2di ru_poly = {0, 0x1F7011641}; /* u' */ - const uv2di crc_poly = {0, 0x1DB710641}; /* P'(x) << 1 */ - - /* - * Load the initial CRC value. - * - * The CRC value is loaded into the rightmost word of the - * vector register and is later XORed with the LSB portion - * of the loaded input data. - */ - uv2di v0 = {0, 0}; - v0 = (uv2di)vec_insert(crc, (uv4si)v0, 3); - - /* Load a 64-byte data chunk and XOR with CRC */ - uv2di v1 = vec_perm(((uv2di *)buf)[0], ((uv2di *)buf)[0], perm_le2be); - uv2di v2 = vec_perm(((uv2di *)buf)[1], ((uv2di *)buf)[1], perm_le2be); - uv2di v3 = vec_perm(((uv2di *)buf)[2], ((uv2di *)buf)[2], perm_le2be); - uv2di v4 = vec_perm(((uv2di *)buf)[3], ((uv2di *)buf)[3], perm_le2be); - - v1 ^= v0; - buf += 64; - len -= 64; - - while (len >= 64) { - /* Load the next 64-byte data chunk */ - uv16qi part1 = vec_perm(((uv16qi *)buf)[0], ((uv16qi *)buf)[0], perm_le2be); - uv16qi part2 = vec_perm(((uv16qi *)buf)[1], ((uv16qi *)buf)[1], perm_le2be); - uv16qi part3 = vec_perm(((uv16qi *)buf)[2], ((uv16qi *)buf)[2], perm_le2be); - uv16qi part4 = vec_perm(((uv16qi *)buf)[3], ((uv16qi *)buf)[3], perm_le2be); - - /* - * Perform a GF(2) multiplication of the doublewords in V1 with - * the R1 and R2 reduction constants in V0. The intermediate result - * is then folded (accumulated) with the next data chunk in PART1 and - * stored in V1. Repeat this step for the register contents - * in V2, V3, and V4 respectively. - */ - v1 = (uv2di)vec_gfmsum_accum_128(r2r1, v1, part1); - v2 = (uv2di)vec_gfmsum_accum_128(r2r1, v2, part2); - v3 = (uv2di)vec_gfmsum_accum_128(r2r1, v3, part3); - v4 = (uv2di)vec_gfmsum_accum_128(r2r1, v4, part4); - - buf += 64; - len -= 64; - } - - /* - * Fold V1 to V4 into a single 128-bit value in V1. Multiply V1 with R3 - * and R4 and accumulating the next 128-bit chunk until a single 128-bit - * value remains. - */ - v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v2); - v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v3); - v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v4); - - while (len >= 16) { - /* Load next data chunk */ - v2 = vec_perm(*(uv2di *)buf, *(uv2di *)buf, perm_le2be); - - /* Fold next data chunk */ - v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v2); - - buf += 16; - len -= 16; - } - - /* - * Set up a vector register for byte shifts. The shift value must - * be loaded in bits 1-4 in byte element 7 of a vector register. - * Shift by 8 bytes: 0x40 - * Shift by 4 bytes: 0x20 - */ - uv16qi v9 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - v9 = vec_insert((unsigned char)0x40, v9, 7); - - /* - * Prepare V0 for the next GF(2) multiplication: shift V0 by 8 bytes - * to move R4 into the rightmost doubleword and set the leftmost - * doubleword to 0x1. - */ - v0 = vec_srb(r4r3, (uv2di)v9); - v0[0] = 1; - - /* - * Compute GF(2) product of V1 and V0. The rightmost doubleword - * of V1 is multiplied with R4. The leftmost doubleword of V1 is - * multiplied by 0x1 and is then XORed with rightmost product. - * Implicitly, the intermediate leftmost product becomes padded - */ - v1 = (uv2di)vec_gfmsum_128(v0, v1); - - /* - * Now do the final 32-bit fold by multiplying the rightmost word - * in V1 with R5 and XOR the result with the remaining bits in V1. - * - * To achieve this by a single VGFMAG, right shift V1 by a word - * and store the result in V2 which is then accumulated. Use the - * vector unpack instruction to load the rightmost half of the - * doubleword into the rightmost doubleword element of V1; the other - * half is loaded in the leftmost doubleword. - * The vector register with CONST_R5 contains the R5 constant in the - * rightmost doubleword and the leftmost doubleword is zero to ignore - * the leftmost product of V1. - */ - v9 = vec_insert((unsigned char)0x20, v9, 7); - v2 = vec_srb(v1, (uv2di)v9); - v1 = vec_unpackl((uv4si)v1); /* Split rightmost doubleword */ - v1 = (uv2di)vec_gfmsum_accum_128(r5, v1, (uv16qi)v2); - - /* - * Apply a Barret reduction to compute the final 32-bit CRC value. - * - * The input values to the Barret reduction are the degree-63 polynomial - * in V1 (R(x)), degree-32 generator polynomial, and the reduction - * constant u. The Barret reduction result is the CRC value of R(x) mod - * P(x). - * - * The Barret reduction algorithm is defined as: - * - * 1. T1(x) = floor( R(x) / x^32 ) GF2MUL u - * 2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x) - * 3. C(x) = R(x) XOR T2(x) mod x^32 - * - * Note: The leftmost doubleword of vector register containing - * CONST_RU_POLY is zero and, thus, the intermediate GF(2) product - * is zero and does not contribute to the final result. - */ - - /* T1(x) = floor( R(x) / x^32 ) GF2MUL u */ - v2 = vec_unpackl((uv4si)v1); - v2 = (uv2di)vec_gfmsum_128(ru_poly, v2); - - /* - * Compute the GF(2) product of the CRC polynomial with T1(x) in - * V2 and XOR the intermediate result, T2(x), with the value in V1. - * The final result is stored in word element 2 of V2. - */ - v2 = vec_unpackl((uv4si)v2); - v2 = (uv2di)vec_gfmsum_accum_128(crc_poly, v2, (uv16qi)v1); - - return ((uv4si)v2)[2]; -} - -#define VX_MIN_LEN 64 -#define VX_ALIGNMENT 16UL -#define VX_ALIGN_MASK (VX_ALIGNMENT - 1) - -uint32_t Z_INTERNAL crc32_s390_vx(uint32_t crc, const unsigned char *buf, size_t len) { - size_t prealign, aligned, remaining; - - if (len < VX_MIN_LEN + VX_ALIGN_MASK) - return crc32_braid(crc, buf, len); - - if ((uintptr_t)buf & VX_ALIGN_MASK) { - prealign = (size_t)ALIGN_DIFF(buf, VX_ALIGNMENT); - len -= prealign; - crc = crc32_braid(crc, buf, prealign); - buf += prealign; - } - aligned = ALIGN_DOWN(len, VX_ALIGNMENT); - remaining = len & VX_ALIGN_MASK; - - crc = ~crc32_le_vgfm_16(~crc, buf, aligned); - - if (remaining) - crc = crc32_braid(crc, buf + aligned, remaining); - - return crc; -} - -Z_INTERNAL uint32_t crc32_copy_s390_vx(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - crc = crc32_s390_vx(crc, src, len); - memcpy(dst, src, len); - return crc; -} - -#endif diff --git a/modules/zlib/src/arch/s390/dfltcc_common.h b/modules/zlib/src/arch/s390/dfltcc_common.h deleted file mode 100644 index a6527ab5df..0000000000 --- a/modules/zlib/src/arch/s390/dfltcc_common.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef DFLTCC_COMMON_H -#define DFLTCC_COMMON_H - -#include "zutil.h" - -/* - Parameter Block for Query Available Functions. - */ -struct dfltcc_qaf_param { - char fns[16]; - char reserved1[8]; - char fmts[2]; - char reserved2[6]; -} ALIGNED_(8); - -/* - Parameter Block for Generate Dynamic-Huffman Table, Compress and Expand. - */ -struct dfltcc_param_v0 { - uint16_t pbvn; /* Parameter-Block-Version Number */ - uint8_t mvn; /* Model-Version Number */ - uint8_t ribm; /* Reserved for IBM use */ - uint32_t reserved32 : 31; - uint32_t cf : 1; /* Continuation Flag */ - uint8_t reserved64[8]; - uint32_t nt : 1; /* New Task */ - uint32_t reserved129 : 1; - uint32_t cvt : 1; /* Check Value Type */ - uint32_t reserved131 : 1; - uint32_t htt : 1; /* Huffman-Table Type */ - uint32_t bcf : 1; /* Block-Continuation Flag */ - uint32_t bcc : 1; /* Block Closing Control */ - uint32_t bhf : 1; /* Block Header Final */ - uint32_t reserved136 : 1; - uint32_t reserved137 : 1; - uint32_t dhtgc : 1; /* DHT Generation Control */ - uint32_t reserved139 : 5; - uint32_t reserved144 : 5; - uint32_t sbb : 3; /* Sub-Byte Boundary */ - uint8_t oesc; /* Operation-Ending-Supplemental Code */ - uint32_t reserved160 : 12; - uint32_t ifs : 4; /* Incomplete-Function Status */ - uint16_t ifl; /* Incomplete-Function Length */ - uint8_t reserved192[8]; - uint8_t reserved256[8]; - uint8_t reserved320[4]; - uint16_t hl; /* History Length */ - uint32_t reserved368 : 1; - uint16_t ho : 15; /* History Offset */ - uint32_t cv; /* Check Value */ - uint32_t eobs : 15; /* End-of-block Symbol */ - uint32_t reserved431: 1; - uint8_t eobl : 4; /* End-of-block Length */ - uint32_t reserved436 : 12; - uint32_t reserved448 : 4; - uint16_t cdhtl : 12; /* Compressed-Dynamic-Huffman Table - Length */ - uint8_t reserved464[6]; - uint8_t cdht[288]; /* Compressed-Dynamic-Huffman Table */ - uint8_t reserved[24]; - uint8_t ribm2[8]; /* Reserved for IBM use */ - uint8_t csb[1152]; /* Continuation-State Buffer */ -} ALIGNED_(8); - -/* - Extension of inflate_state and deflate_state. - */ -struct dfltcc_state { - struct dfltcc_param_v0 param; /* Parameter block. */ - struct dfltcc_qaf_param af; /* Available functions. */ - char msg[64]; /* Buffer for strm->msg */ -}; - -typedef struct { - struct dfltcc_state common; - uint16_t level_mask; /* Levels on which to use DFLTCC */ - uint32_t block_size; /* New block each X bytes */ - size_t block_threshold; /* New block after total_in > X */ - uint32_t dht_threshold; /* New block only if avail_in >= X */ -} arch_deflate_state; - -typedef struct { - struct dfltcc_state common; -} arch_inflate_state; - -/* - History buffer size. - */ -#define HB_BITS 15 -#define HB_SIZE (1 << HB_BITS) - -/* - Sizes of deflate block parts. - */ -#define DFLTCC_BLOCK_HEADER_BITS 3 -#define DFLTCC_HLITS_COUNT_BITS 5 -#define DFLTCC_HDISTS_COUNT_BITS 5 -#define DFLTCC_HCLENS_COUNT_BITS 4 -#define DFLTCC_MAX_HCLENS 19 -#define DFLTCC_HCLEN_BITS 3 -#define DFLTCC_MAX_HLITS 286 -#define DFLTCC_MAX_HDISTS 30 -#define DFLTCC_MAX_HLIT_HDIST_BITS 7 -#define DFLTCC_MAX_SYMBOL_BITS 16 -#define DFLTCC_MAX_EOBS_BITS 15 -#define DFLTCC_MAX_PADDING_BITS 7 - -#define DEFLATE_BOUND_COMPLEN(source_len) \ - ((DFLTCC_BLOCK_HEADER_BITS + \ - DFLTCC_HLITS_COUNT_BITS + \ - DFLTCC_HDISTS_COUNT_BITS + \ - DFLTCC_HCLENS_COUNT_BITS + \ - DFLTCC_MAX_HCLENS * DFLTCC_HCLEN_BITS + \ - (DFLTCC_MAX_HLITS + DFLTCC_MAX_HDISTS) * DFLTCC_MAX_HLIT_HDIST_BITS + \ - (source_len) * DFLTCC_MAX_SYMBOL_BITS + \ - DFLTCC_MAX_EOBS_BITS + \ - DFLTCC_MAX_PADDING_BITS) >> 3) - -#endif diff --git a/modules/zlib/src/arch/s390/dfltcc_deflate.c b/modules/zlib/src/arch/s390/dfltcc_deflate.c deleted file mode 100644 index 5cbd700c64..0000000000 --- a/modules/zlib/src/arch/s390/dfltcc_deflate.c +++ /dev/null @@ -1,390 +0,0 @@ -/* dfltcc_deflate.c - IBM Z DEFLATE CONVERSION CALL compression support. */ - -/* - Use the following commands to build zlib-ng with DFLTCC compression support: - - $ ./configure --with-dfltcc-deflate - or - - $ cmake -DWITH_DFLTCC_DEFLATE=1 . - - and then - - $ make -*/ - -#ifdef S390_DFLTCC_DEFLATE - -#include "zbuild.h" -#include "deflate.h" -#include "deflate_p.h" -#include "trees_emit.h" -#include "dfltcc_deflate.h" -#include "dfltcc_detail.h" - -void Z_INTERNAL PREFIX(dfltcc_reset_deflate_state)(PREFIX3(streamp) strm) { - deflate_state *state = (deflate_state *)strm->state; - arch_deflate_state *dfltcc_state = &state->arch; - - dfltcc_reset_state(&dfltcc_state->common); - - /* Initialize tuning parameters */ - dfltcc_state->level_mask = DFLTCC_LEVEL_MASK; - dfltcc_state->block_size = DFLTCC_BLOCK_SIZE; - dfltcc_state->block_threshold = DFLTCC_FIRST_FHT_BLOCK_SIZE; - dfltcc_state->dht_threshold = DFLTCC_DHT_MIN_SAMPLE_SIZE; -} - -static inline int dfltcc_can_deflate_with_params(PREFIX3(streamp) strm, int level, uInt window_bits, int strategy, - int reproducible) { - deflate_state *state = (deflate_state *)strm->state; - arch_deflate_state *dfltcc_state = &state->arch; - - /* Unsupported compression settings */ - if ((dfltcc_state->level_mask & (1 << level)) == 0) - return 0; - if (window_bits != HB_BITS) - return 0; - if (strategy != Z_FIXED && strategy != Z_DEFAULT_STRATEGY) - return 0; - if (reproducible) - return 0; - - /* Unsupported hardware */ - if (!is_bit_set(dfltcc_state->common.af.fns, DFLTCC_GDHT) || - !is_bit_set(dfltcc_state->common.af.fns, DFLTCC_CMPR) || - !is_bit_set(dfltcc_state->common.af.fmts, DFLTCC_FMT0)) - return 0; - - return 1; -} - -int Z_INTERNAL PREFIX(dfltcc_can_deflate)(PREFIX3(streamp) strm) { - deflate_state *state = (deflate_state *)strm->state; - - return dfltcc_can_deflate_with_params(strm, state->level, W_BITS(state), state->strategy, state->reproducible); -} - -static inline void dfltcc_gdht(PREFIX3(streamp) strm) { - deflate_state *state = (deflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - size_t avail_in = strm->avail_in; - - dfltcc(DFLTCC_GDHT, param, NULL, NULL, &strm->next_in, &avail_in, NULL); -} - -static inline dfltcc_cc dfltcc_cmpr(PREFIX3(streamp) strm) { - deflate_state *state = (deflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - size_t avail_in = strm->avail_in; - size_t avail_out = strm->avail_out; - dfltcc_cc cc; - - cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR, - param, &strm->next_out, &avail_out, - &strm->next_in, &avail_in, state->window); - strm->total_in += (strm->avail_in - avail_in); - strm->total_out += (strm->avail_out - avail_out); - strm->avail_in = avail_in; - strm->avail_out = avail_out; - return cc; -} - -static inline void send_eobs(PREFIX3(streamp) strm, const struct dfltcc_param_v0 *param) { - deflate_state *state = (deflate_state *)strm->state; - - send_bits(state, bi_reverse((uint16_t)(param->eobs >> (15 - param->eobl)), param->eobl), - param->eobl, state->bi_buf, state->bi_valid); - - flush_pending_inline(strm); - if (state->pending != 0) { - /* The remaining data is located in pending_out[0:pending]. If someone - * calls put_byte() - this might happen in deflate() - the byte will be - * placed into pending_buf[pending], which is incorrect. Move the - * remaining data to the beginning of pending_buf so that put_byte() is - * usable again. - */ - memmove(state->pending_buf, state->pending_out, state->pending); - state->pending_out = state->pending_buf; - } -#ifdef ZLIB_DEBUG - state->compressed_len += param->eobl; -#endif -} - -int Z_INTERNAL PREFIX(dfltcc_deflate)(PREFIX3(streamp) strm, int flush, block_state *result) { - deflate_state *state = (deflate_state *)strm->state; - arch_deflate_state *dfltcc_state = &state->arch; - struct dfltcc_param_v0 *param = &dfltcc_state->common.param; - uInt masked_avail_in; - dfltcc_cc cc; - int need_empty_block; - int soft_bcc; - int no_flush; - - if (!PREFIX(dfltcc_can_deflate)(strm)) { - /* Clear history. */ - if (flush == Z_FULL_FLUSH) - param->hl = 0; - return 0; - } - -again: - masked_avail_in = 0; - soft_bcc = 0; - no_flush = flush == Z_NO_FLUSH; - - /* No input data. Return, except when Continuation Flag is set, which means - * that DFLTCC has buffered some output in the parameter block and needs to - * be called again in order to flush it. - */ - if (strm->avail_in == 0 && !param->cf) { - /* A block is still open, and the hardware does not support closing - * blocks without adding data. Thus, close it manually. - */ - if (!no_flush && param->bcf) { - send_eobs(strm, param); - param->bcf = 0; - } - /* Let one of deflate_* functions write a trailing empty block. */ - if (flush == Z_FINISH) - return 0; - /* Clear history. */ - if (flush == Z_FULL_FLUSH) - param->hl = 0; - /* Trigger block post-processing if necessary. */ - *result = no_flush ? need_more : block_done; - return 1; - } - - /* There is an open non-BFINAL block, we are not going to close it just - * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see - * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new - * DHT in order to adapt to a possibly changed input data distribution. - */ - if (param->bcf && no_flush && - strm->total_in > dfltcc_state->block_threshold && - strm->avail_in >= dfltcc_state->dht_threshold) { - if (param->cf) { - /* We need to flush the DFLTCC buffer before writing the - * End-of-block Symbol. Mask the input data and proceed as usual. - */ - masked_avail_in += strm->avail_in; - strm->avail_in = 0; - no_flush = 0; - } else { - /* DFLTCC buffer is empty, so we can manually write the - * End-of-block Symbol right away. - */ - send_eobs(strm, param); - param->bcf = 0; - dfltcc_state->block_threshold = strm->total_in + dfltcc_state->block_size; - } - } - - /* No space for compressed data. If we proceed, dfltcc_cmpr() will return - * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still - * set BCF=1, which is wrong. Avoid complications and return early. - */ - if (strm->avail_out == 0) { - *result = need_more; - return 1; - } - - /* The caller gave us too much data. Pass only one block worth of - * uncompressed data to DFLTCC and mask the rest, so that on the next - * iteration we start a new block. - */ - if (no_flush && strm->avail_in > dfltcc_state->block_size) { - masked_avail_in += (strm->avail_in - dfltcc_state->block_size); - strm->avail_in = dfltcc_state->block_size; - } - - /* When we have an open non-BFINAL deflate block and caller indicates that - * the stream is ending, we need to close an open deflate block and open a - * BFINAL one. - */ - need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf; - - /* Translate stream to parameter block */ - param->cvt = state->wrap == 2 ? CVT_CRC32 : CVT_ADLER32; - if (!no_flush) - /* We need to close a block. Always do this in software - when there is - * no input data, the hardware will not honor BCC. */ - soft_bcc = 1; - if (flush == Z_FINISH && !param->bcf) - /* We are about to open a BFINAL block, set Block Header Final bit - * until the stream ends. - */ - param->bhf = 1; - /* DFLTCC-CMPR will write to next_out, so make sure that buffers with - * higher precedence are empty. - */ - Assert(state->pending == 0, "There must be no pending bytes"); - Assert(state->bi_valid < 8, "There must be less than 8 pending bits"); - param->sbb = (unsigned int)state->bi_valid; - if (param->sbb > 0) - *strm->next_out = (unsigned char)state->bi_buf; - /* Honor history and check value */ - param->nt = 0; - if (state->wrap == 1) - param->cv = strm->adler; - else if (state->wrap == 2) - param->cv = ZSWAP32(strm->adler); - - /* When opening a block, choose a Huffman-Table Type */ - if (!param->bcf) { - if (state->strategy == Z_FIXED || (strm->total_in == 0 && dfltcc_state->block_threshold > 0)) - param->htt = HTT_FIXED; - else { - param->htt = HTT_DYNAMIC; - dfltcc_gdht(strm); - } - } - - /* Deflate */ - do { - cc = dfltcc_cmpr(strm); - if (strm->avail_in < 4096 && masked_avail_in > 0) - /* We are about to call DFLTCC with a small input buffer, which is - * inefficient. Since there is masked data, there will be at least - * one more DFLTCC call, so skip the current one and make the next - * one handle more data. - */ - break; - } while (cc == DFLTCC_CC_AGAIN); - - /* Translate parameter block to stream */ - strm->msg = oesc_msg(dfltcc_state->common.msg, param->oesc); - state->bi_valid = param->sbb; - if (state->bi_valid == 0) - state->bi_buf = 0; /* Avoid accessing next_out */ - else - state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1); - if (state->wrap == 1) - strm->adler = param->cv; - else if (state->wrap == 2) - strm->adler = ZSWAP32(param->cv); - - /* Unmask the input data */ - strm->avail_in += masked_avail_in; - masked_avail_in = 0; - - /* If we encounter an error, it means there is a bug in DFLTCC call */ - Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG"); - - /* Update Block-Continuation Flag. It will be used to check whether to call - * GDHT the next time. - */ - if (cc == DFLTCC_CC_OK) { - if (soft_bcc) { - send_eobs(strm, param); - param->bcf = 0; - dfltcc_state->block_threshold = strm->total_in + dfltcc_state->block_size; - } else - param->bcf = 1; - if (flush == Z_FINISH) { - if (need_empty_block) - /* Make the current deflate() call also close the stream */ - return 0; - else { - bi_windup(state); - *result = finish_done; - } - } else { - if (flush == Z_FULL_FLUSH) - param->hl = 0; /* Clear history */ - *result = flush == Z_NO_FLUSH ? need_more : block_done; - } - } else { - param->bcf = 1; - *result = need_more; - } - if (strm->avail_in != 0 && strm->avail_out != 0) - goto again; /* deflate() must use all input or all output */ - return 1; -} - -/* - Switching between hardware and software compression. - - DFLTCC does not support all zlib settings, e.g. generation of non-compressed - blocks or alternative window sizes. When such settings are applied on the - fly with deflateParams, we need to convert between hardware and software - window formats. -*/ -static int dfltcc_was_deflate_used(PREFIX3(streamp) strm) { - deflate_state *state = (deflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - - return strm->total_in > 0 || param->nt == 0 || param->hl > 0; -} - -int Z_INTERNAL PREFIX(dfltcc_deflate_params)(PREFIX3(streamp) strm, int level, int strategy, int *flush) { - deflate_state *state = (deflate_state *)strm->state; - int could_deflate = PREFIX(dfltcc_can_deflate)(strm); - int can_deflate = dfltcc_can_deflate_with_params(strm, level, W_BITS(state), strategy, state->reproducible); - - if (can_deflate == could_deflate) - /* We continue to work in the same mode - no changes needed */ - return Z_OK; - - if (!dfltcc_was_deflate_used(strm)) - /* DFLTCC was not used yet - no changes needed */ - return Z_OK; - - /* For now, do not convert between window formats - simply get rid of the old data instead */ - *flush = Z_FULL_FLUSH; - return Z_OK; -} - -int Z_INTERNAL PREFIX(dfltcc_deflate_done)(PREFIX3(streamp) strm, int flush) { - deflate_state *state = (deflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - - /* When deflate(Z_FULL_FLUSH) is called with small avail_out, it might - * close the block without resetting the compression state. Detect this - * situation and return that deflation is not done. - */ - if (flush == Z_FULL_FLUSH && strm->avail_out == 0) - return 0; - - /* Return that deflation is not done if DFLTCC is used and either it - * buffered some data (Continuation Flag is set), or has not written EOBS - * yet (Block-Continuation Flag is set). - */ - return !PREFIX(dfltcc_can_deflate)(strm) || (!param->cf && !param->bcf); -} - -int Z_INTERNAL PREFIX(dfltcc_can_set_reproducible)(PREFIX3(streamp) strm, int reproducible) { - deflate_state *state = (deflate_state *)strm->state; - - return reproducible != state->reproducible && !dfltcc_was_deflate_used(strm); -} - -/* - Preloading history. -*/ -int Z_INTERNAL PREFIX(dfltcc_deflate_set_dictionary)(PREFIX3(streamp) strm, - const unsigned char *dictionary, uInt dict_length) { - deflate_state *state = (deflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - - append_history(param, state->window, dictionary, dict_length); - state->strstart = 1; /* Add FDICT to zlib header */ - state->block_start = state->strstart; /* Make deflate_stored happy */ - return Z_OK; -} - -int Z_INTERNAL PREFIX(dfltcc_deflate_get_dictionary)(PREFIX3(streamp) strm, unsigned char *dictionary, uInt *dict_length) { - deflate_state *state = (deflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - - if (dictionary) - get_history(param, state->window, dictionary); - if (dict_length) - *dict_length = param->hl; - return Z_OK; -} - -#endif diff --git a/modules/zlib/src/arch/s390/dfltcc_deflate.h b/modules/zlib/src/arch/s390/dfltcc_deflate.h deleted file mode 100644 index 35e2fd3f62..0000000000 --- a/modules/zlib/src/arch/s390/dfltcc_deflate.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef DFLTCC_DEFLATE_H -#define DFLTCC_DEFLATE_H - -#include "deflate.h" -#include "dfltcc_common.h" - -void Z_INTERNAL PREFIX(dfltcc_reset_deflate_state)(PREFIX3(streamp)); -int Z_INTERNAL PREFIX(dfltcc_can_deflate)(PREFIX3(streamp) strm); -int Z_INTERNAL PREFIX(dfltcc_deflate)(PREFIX3(streamp) strm, int flush, block_state *result); -int Z_INTERNAL PREFIX(dfltcc_deflate_params)(PREFIX3(streamp) strm, int level, int strategy, int *flush); -int Z_INTERNAL PREFIX(dfltcc_deflate_done)(PREFIX3(streamp) strm, int flush); -int Z_INTERNAL PREFIX(dfltcc_can_set_reproducible)(PREFIX3(streamp) strm, int reproducible); -int Z_INTERNAL PREFIX(dfltcc_deflate_set_dictionary)(PREFIX3(streamp) strm, - const unsigned char *dictionary, uInt dict_length); -int Z_INTERNAL PREFIX(dfltcc_deflate_get_dictionary)(PREFIX3(streamp) strm, unsigned char *dictionary, uInt* dict_length); - -#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \ - do { \ - if (PREFIX(dfltcc_can_deflate)((strm))) \ - return PREFIX(dfltcc_deflate_set_dictionary)((strm), (dict), (dict_len)); \ - } while (0) - -#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \ - do { \ - if (PREFIX(dfltcc_can_deflate)((strm))) \ - return PREFIX(dfltcc_deflate_get_dictionary)((strm), (dict), (dict_len)); \ - } while (0) - -#define DEFLATE_RESET_KEEP_HOOK PREFIX(dfltcc_reset_deflate_state) - -#define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) \ - do { \ - int err; \ -\ - err = PREFIX(dfltcc_deflate_params)((strm), (level), (strategy), (hook_flush)); \ - if (err == Z_STREAM_ERROR) \ - return err; \ - } while (0) - -#define DEFLATE_DONE PREFIX(dfltcc_deflate_done) - -#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, source_len) \ - do { \ - if (deflateStateCheck((strm)) || PREFIX(dfltcc_can_deflate)((strm))) \ - (complen) = DEFLATE_BOUND_COMPLEN(source_len); \ - } while (0) - -#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) (PREFIX(dfltcc_can_deflate)((strm))) - -#define DEFLATE_HOOK PREFIX(dfltcc_deflate) - -#define DEFLATE_NEED_CHECKSUM(strm) (!PREFIX(dfltcc_can_deflate)((strm))) - -#define DEFLATE_CAN_SET_REPRODUCIBLE PREFIX(dfltcc_can_set_reproducible) - -#define DEFLATE_ADJUST_WINDOW_SIZE(n) MAX(n, HB_SIZE) - -#endif diff --git a/modules/zlib/src/arch/s390/dfltcc_detail.h b/modules/zlib/src/arch/s390/dfltcc_detail.h deleted file mode 100644 index f790735ab4..0000000000 --- a/modules/zlib/src/arch/s390/dfltcc_detail.h +++ /dev/null @@ -1,274 +0,0 @@ -#include "zbuild.h" -#include "zsanitizer.h" -#include - -#ifdef HAVE_SYS_SDT_H -#include -#endif - -/* - Tuning parameters. - */ -#ifndef DFLTCC_LEVEL_MASK -#define DFLTCC_LEVEL_MASK 0x2 -#endif -#ifndef DFLTCC_BLOCK_SIZE -#define DFLTCC_BLOCK_SIZE 1048576 -#endif -#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE -#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096 -#endif -#ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE -#define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096 -#endif -#ifndef DFLTCC_RIBM -#define DFLTCC_RIBM 0 -#endif - -#define static_assert(c, msg) __attribute__((unused)) static char static_assert_failed_ ## msg[c ? 1 : -1] - -#define DFLTCC_SIZEOF_QAF 32 -static_assert(sizeof(struct dfltcc_qaf_param) == DFLTCC_SIZEOF_QAF, qaf); - -static inline int is_bit_set(const char *bits, int n) { - return bits[n / 8] & (1 << (7 - (n % 8))); -} - -static inline void clear_bit(char *bits, int n) { - bits[n / 8] &= ~(1 << (7 - (n % 8))); -} - -#define DFLTCC_FACILITY 151 - -static inline int is_dfltcc_enabled(void) { - uint64_t facilities[(DFLTCC_FACILITY / 64) + 1]; - Z_REGISTER uint8_t r0 __asm__("r0"); - - memset(facilities, 0, sizeof(facilities)); - r0 = sizeof(facilities) / sizeof(facilities[0]) - 1; - /* STFLE is supported since z9-109 and only in z/Architecture mode. When - * compiling with -m31, gcc defaults to ESA mode, however, since the kernel - * is 64-bit, it's always z/Architecture mode at runtime. - */ - __asm__ volatile( -#ifndef __clang__ - ".machinemode push\n" - ".machinemode zarch\n" -#endif - "stfle %[facilities]\n" -#ifndef __clang__ - ".machinemode pop\n" -#endif - : [facilities] "=Q" (facilities), [r0] "+r" (r0) :: "cc"); - return is_bit_set((const char *)facilities, DFLTCC_FACILITY); -} - -#define DFLTCC_FMT0 0 - -#define CVT_CRC32 0 -#define CVT_ADLER32 1 -#define HTT_FIXED 0 -#define HTT_DYNAMIC 1 - -#define DFLTCC_SIZEOF_GDHT_V0 384 -#define DFLTCC_SIZEOF_CMPR_XPND_V0 1536 -static_assert(offsetof(struct dfltcc_param_v0, csb) == DFLTCC_SIZEOF_GDHT_V0, gdht_v0); -static_assert(sizeof(struct dfltcc_param_v0) == DFLTCC_SIZEOF_CMPR_XPND_V0, cmpr_xpnd_v0); - -static inline z_const char *oesc_msg(char *buf, int oesc) { - if (oesc == 0x00) - return NULL; /* Successful completion */ - else { - sprintf(buf, "Operation-Ending-Supplemental Code is 0x%.2X", oesc); - return buf; - } -} - -/* - C wrapper for the DEFLATE CONVERSION CALL instruction. - */ -typedef enum { - DFLTCC_CC_OK = 0, - DFLTCC_CC_OP1_TOO_SHORT = 1, - DFLTCC_CC_OP2_TOO_SHORT = 2, - DFLTCC_CC_OP2_CORRUPT = 2, - DFLTCC_CC_AGAIN = 3, -} dfltcc_cc; - -#define DFLTCC_QAF 0 -#define DFLTCC_GDHT 1 -#define DFLTCC_CMPR 2 -#define DFLTCC_XPND 4 -#define HBT_CIRCULAR (1 << 7) -#define DFLTCC_FN_MASK ((1 << 7) - 1) - -/* Return lengths of high (starting at param->ho) and low (starting at 0) fragments of the circular history buffer. */ -static inline void get_history_lengths(struct dfltcc_param_v0 *param, size_t *hl_high, size_t *hl_low) { - *hl_high = MIN(param->hl, HB_SIZE - param->ho); - *hl_low = param->hl - *hl_high; -} - -/* Notify instrumentation about an upcoming read/write access to the circular history buffer. */ -static inline void instrument_read_write_hist(struct dfltcc_param_v0 *param, void *hist) { - size_t hl_high, hl_low; - - get_history_lengths(param, &hl_high, &hl_low); - instrument_read_write(hist + param->ho, hl_high); - instrument_read_write(hist, hl_low); -} - -/* Notify MSan about a completed write to the circular history buffer. */ -static inline void msan_unpoison_hist(struct dfltcc_param_v0 *param, void *hist) { - size_t hl_high, hl_low; - - get_history_lengths(param, &hl_high, &hl_low); - __msan_unpoison(hist + param->ho, hl_high); - __msan_unpoison(hist, hl_low); -} - -static inline dfltcc_cc dfltcc(int fn, void *param, - unsigned char **op1, size_t *len1, - z_const unsigned char **op2, size_t *len2, void *hist) { - unsigned char *t2 = op1 ? *op1 : NULL; - unsigned char *orig_t2 = t2; - size_t t3 = len1 ? *len1 : 0; - z_const unsigned char *t4 = op2 ? *op2 : NULL; - size_t t5 = len2 ? *len2 : 0; - Z_REGISTER int r0 __asm__("r0"); - Z_REGISTER void *r1 __asm__("r1"); - Z_REGISTER unsigned char *r2 __asm__("r2"); - Z_REGISTER size_t r3 __asm__("r3"); - Z_REGISTER z_const unsigned char *r4 __asm__("r4"); - Z_REGISTER size_t r5 __asm__("r5"); - int cc; - - /* Insert pre-instrumentation for DFLTCC. */ - switch (fn & DFLTCC_FN_MASK) { - case DFLTCC_QAF: - instrument_write(param, DFLTCC_SIZEOF_QAF); - break; - case DFLTCC_GDHT: - instrument_read_write(param, DFLTCC_SIZEOF_GDHT_V0); - instrument_read(t4, t5); - break; - case DFLTCC_CMPR: - case DFLTCC_XPND: - instrument_read_write(param, DFLTCC_SIZEOF_CMPR_XPND_V0); - instrument_read(t4, t5); - instrument_write(t2, t3); - instrument_read_write_hist(param, hist); - break; - } - - r0 = fn; r1 = param; r2 = t2; r3 = t3; r4 = t4; r5 = t5; - __asm__ volatile( -#ifdef HAVE_SYS_SDT_H - STAP_PROBE_ASM(zlib, dfltcc_entry, STAP_PROBE_ASM_TEMPLATE(5)) -#endif - ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n" -#ifdef HAVE_SYS_SDT_H - STAP_PROBE_ASM(zlib, dfltcc_exit, STAP_PROBE_ASM_TEMPLATE(5)) -#endif - "ipm %[cc]\n" - : [r2] "+r" (r2) - , [r3] "+r" (r3) - , [r4] "+r" (r4) - , [r5] "+r" (r5) - , [cc] "=r" (cc) - : [r0] "r" (r0) - , [r1] "r" (r1) - , [hist] "r" (hist) -#ifdef HAVE_SYS_SDT_H - , STAP_PROBE_ASM_OPERANDS(5, r2, r3, r4, r5, hist) -#endif - : "cc", "memory"); - t2 = r2; t3 = r3; t4 = r4; t5 = r5; - - /* Insert post-instrumentation for DFLTCC. */ - switch (fn & DFLTCC_FN_MASK) { - case DFLTCC_QAF: - __msan_unpoison(param, DFLTCC_SIZEOF_QAF); - break; - case DFLTCC_GDHT: - __msan_unpoison(param, DFLTCC_SIZEOF_GDHT_V0); - break; - case DFLTCC_CMPR: - __msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0); - __msan_unpoison(orig_t2, t2 - orig_t2 + (((struct dfltcc_param_v0 *)param)->sbb == 0 ? 0 : 1)); - msan_unpoison_hist(param, hist); - break; - case DFLTCC_XPND: - __msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0); - __msan_unpoison(orig_t2, t2 - orig_t2); - msan_unpoison_hist(param, hist); - break; - } - - if (op1) - *op1 = t2; - if (len1) - *len1 = t3; - if (op2) - *op2 = t4; - if (len2) - *len2 = t5; - return (cc >> 28) & 3; -} - -static inline void dfltcc_reset_state(struct dfltcc_state *dfltcc_state) { - /* Initialize available functions */ - if (is_dfltcc_enabled()) { - dfltcc(DFLTCC_QAF, &dfltcc_state->param, NULL, NULL, NULL, NULL, NULL); - memmove(&dfltcc_state->af, &dfltcc_state->param, sizeof(dfltcc_state->af)); - } else - memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af)); - - /* Initialize parameter block */ - memset(&dfltcc_state->param, 0, sizeof(dfltcc_state->param)); - dfltcc_state->param.nt = 1; - dfltcc_state->param.ribm = DFLTCC_RIBM; -} - -static inline void dfltcc_copy_state(void *dst, const void *src, uInt size, uInt extension_size) { - memcpy(dst, src, ALIGN_UP(size, 8) + extension_size); -} - -static inline void append_history(struct dfltcc_param_v0 *param, unsigned char *history, - const unsigned char *buf, uInt count) { - size_t offset; - size_t n; - - /* Do not use more than 32K */ - if (count > HB_SIZE) { - buf += count - HB_SIZE; - count = HB_SIZE; - } - offset = (param->ho + param->hl) % HB_SIZE; - if (offset + count <= HB_SIZE) - /* Circular history buffer does not wrap - copy one chunk */ - memcpy(history + offset, buf, count); - else { - /* Circular history buffer wraps - copy two chunks */ - n = HB_SIZE - offset; - memcpy(history + offset, buf, n); - memcpy(history, buf + n, count - n); - } - n = param->hl + count; - if (n <= HB_SIZE) - /* All history fits into buffer - no need to discard anything */ - param->hl = n; - else { - /* History does not fit into buffer - discard extra bytes */ - param->ho = (param->ho + (n - HB_SIZE)) % HB_SIZE; - param->hl = HB_SIZE; - } -} - -static inline void get_history(struct dfltcc_param_v0 *param, const unsigned char *history, - unsigned char *buf) { - size_t hl_high, hl_low; - - get_history_lengths(param, &hl_high, &hl_low); - memcpy(buf, history + param->ho, hl_high); - memcpy(buf + hl_high, history, hl_low); -} diff --git a/modules/zlib/src/arch/s390/dfltcc_inflate.c b/modules/zlib/src/arch/s390/dfltcc_inflate.c deleted file mode 100644 index f6bc423c22..0000000000 --- a/modules/zlib/src/arch/s390/dfltcc_inflate.c +++ /dev/null @@ -1,195 +0,0 @@ -/* dfltcc_inflate.c - IBM Z DEFLATE CONVERSION CALL decompression support. */ - -/* - Use the following commands to build zlib-ng with DFLTCC decompression support: - - $ ./configure --with-dfltcc-inflate - or - - $ cmake -DWITH_DFLTCC_INFLATE=1 . - - and then - - $ make -*/ - -#ifdef S390_DFLTCC_INFLATE - -#include "zbuild.h" -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "dfltcc_inflate.h" -#include "dfltcc_detail.h" - -void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm) { - struct inflate_state *state = (struct inflate_state *)strm->state; - - dfltcc_reset_state(&state->arch.common); -} - -int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm) { - struct inflate_state *state = (struct inflate_state *)strm->state; - struct dfltcc_state *dfltcc_state = &state->arch.common; - - /* Unsupported hardware */ - return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0); -} - -static inline dfltcc_cc dfltcc_xpnd(PREFIX3(streamp) strm) { - struct inflate_state *state = (struct inflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - size_t avail_in = strm->avail_in; - size_t avail_out = strm->avail_out; - dfltcc_cc cc; - - cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR, - param, &strm->next_out, &avail_out, - &strm->next_in, &avail_in, state->window); - strm->avail_in = avail_in; - strm->avail_out = avail_out; - return cc; -} - -dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret) { - struct inflate_state *state = (struct inflate_state *)strm->state; - struct dfltcc_state *dfltcc_state = &state->arch.common; - struct dfltcc_param_v0 *param = &dfltcc_state->param; - dfltcc_cc cc; - - if (flush == Z_BLOCK || flush == Z_TREES) { - /* DFLTCC does not support stopping on block boundaries */ - if (PREFIX(dfltcc_inflate_disable)(strm)) { - *ret = Z_STREAM_ERROR; - return DFLTCC_INFLATE_BREAK; - } else - return DFLTCC_INFLATE_SOFTWARE; - } - - if (state->last) { - if (state->bits != 0) { - strm->next_in++; - strm->avail_in--; - state->bits = 0; - } - state->mode = CHECK; - return DFLTCC_INFLATE_CONTINUE; - } - - if (strm->avail_in == 0 && !param->cf) - return DFLTCC_INFLATE_BREAK; - - /* if window not in use yet, initialize */ - if (state->wsize == 0) - state->wsize = 1U << state->wbits; - - /* Translate stream to parameter block */ - param->cvt = ((state->wrap & 4) && state->flags) ? CVT_CRC32 : CVT_ADLER32; - param->sbb = state->bits; - if (param->hl) - param->nt = 0; /* Honor history for the first block */ - if (state->wrap & 4) - param->cv = state->flags ? ZSWAP32(state->check) : state->check; - - /* Inflate */ - do { - cc = dfltcc_xpnd(strm); - } while (cc == DFLTCC_CC_AGAIN); - - /* Translate parameter block to stream */ - strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); - state->last = cc == DFLTCC_CC_OK; - state->bits = param->sbb; - if (state->wrap & 4) - strm->adler = state->check = state->flags ? ZSWAP32(param->cv) : param->cv; - if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) { - /* Report an error if stream is corrupted */ - state->mode = BAD; - return DFLTCC_INFLATE_CONTINUE; - } - state->mode = TYPEDO; - /* Break if operands are exhausted, otherwise continue looping */ - return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ? - DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE; -} - -int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm) { - struct inflate_state *state = (struct inflate_state *)strm->state; - - return !state->arch.common.param.nt; -} - -/* - Rotates a circular buffer. - The implementation is based on https://cplusplus.com/reference/algorithm/rotate/ - */ -static void rotate(unsigned char *start, unsigned char *pivot, unsigned char *end) { - unsigned char *p = pivot; - unsigned char tmp; - - while (p != start) { - tmp = *start; - *start = *p; - *p = tmp; - - start++; - p++; - - if (p == end) - p = pivot; - else if (start == pivot) - pivot = p; - } -} - -int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm) { - struct inflate_state *state = (struct inflate_state *)strm->state; - struct dfltcc_state *dfltcc_state = &state->arch.common; - struct dfltcc_param_v0 *param = &dfltcc_state->param; - - if (!PREFIX(dfltcc_can_inflate)(strm)) - return 0; - if (PREFIX(dfltcc_was_inflate_used)(strm)) - /* DFLTCC has already decompressed some data. Since there is not - * enough information to resume decompression in software, the call - * must fail. - */ - return 1; - /* DFLTCC was not used yet - decompress in software */ - memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af)); - /* Convert the window from the hardware to the software format */ - rotate(state->window, state->window + param->ho, state->window + HB_SIZE); - state->whave = state->wnext = MIN(param->hl, state->wsize); - return 0; -} - -/* - Preloading history. -*/ -int Z_INTERNAL PREFIX(dfltcc_inflate_set_dictionary)(PREFIX3(streamp) strm, - const unsigned char *dictionary, uInt dict_length) { - struct inflate_state *state = (struct inflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - - /* if window not in use yet, initialize */ - if (state->wsize == 0) - state->wsize = 1U << state->wbits; - - append_history(param, state->window, dictionary, dict_length); - state->havedict = 1; - return Z_OK; -} - -int Z_INTERNAL PREFIX(dfltcc_inflate_get_dictionary)(PREFIX3(streamp) strm, - unsigned char *dictionary, uInt *dict_length) { - struct inflate_state *state = (struct inflate_state *)strm->state; - struct dfltcc_param_v0 *param = &state->arch.common.param; - - if (dictionary && state->window) - get_history(param, state->window, dictionary); - if (dict_length) - *dict_length = param->hl; - return Z_OK; -} - -#endif diff --git a/modules/zlib/src/arch/s390/dfltcc_inflate.h b/modules/zlib/src/arch/s390/dfltcc_inflate.h deleted file mode 100644 index 3623f8ed7f..0000000000 --- a/modules/zlib/src/arch/s390/dfltcc_inflate.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef DFLTCC_INFLATE_H -#define DFLTCC_INFLATE_H - -#include "dfltcc_common.h" - -void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm); -int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm); -typedef enum { - DFLTCC_INFLATE_CONTINUE, - DFLTCC_INFLATE_BREAK, - DFLTCC_INFLATE_SOFTWARE, -} dfltcc_inflate_action; -dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret); -int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm); -int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm); -int Z_INTERNAL PREFIX(dfltcc_inflate_set_dictionary)(PREFIX3(streamp) strm, - const unsigned char *dictionary, uInt dict_length); -int Z_INTERNAL PREFIX(dfltcc_inflate_get_dictionary)(PREFIX3(streamp) strm, - unsigned char *dictionary, uInt* dict_length); - -#define INFLATE_RESET_KEEP_HOOK PREFIX(dfltcc_reset_inflate_state) - -#define INFLATE_PRIME_HOOK(strm, bits, value) \ - do { if (PREFIX(dfltcc_inflate_disable)((strm))) return Z_STREAM_ERROR; } while (0) - -#define INFLATE_TYPEDO_HOOK(strm, flush) \ - if (PREFIX(dfltcc_can_inflate)((strm))) { \ - dfltcc_inflate_action action; \ -\ - RESTORE(); \ - action = PREFIX(dfltcc_inflate)((strm), (flush), &ret); \ - LOAD(); \ - if (action == DFLTCC_INFLATE_CONTINUE) \ - break; \ - else if (action == DFLTCC_INFLATE_BREAK) \ - goto inf_leave; \ - } - -#define INFLATE_NEED_CHECKSUM(strm) (!PREFIX(dfltcc_can_inflate)((strm))) - -#define INFLATE_NEED_UPDATEWINDOW(strm) (!PREFIX(dfltcc_can_inflate)((strm))) - -#define INFLATE_MARK_HOOK(strm) \ - do { \ - if (PREFIX(dfltcc_was_inflate_used)((strm))) return -(1L << 16); \ - } while (0) - -#define INFLATE_SYNC_POINT_HOOK(strm) \ - do { \ - if (PREFIX(dfltcc_was_inflate_used)((strm))) return Z_STREAM_ERROR; \ - } while (0) - -#define INFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \ - do { \ - if (PREFIX(dfltcc_can_inflate)((strm))) \ - return PREFIX(dfltcc_inflate_set_dictionary)((strm), (dict), (dict_len)); \ - } while (0) - -#define INFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \ - do { \ - if (PREFIX(dfltcc_can_inflate)((strm))) \ - return PREFIX(dfltcc_inflate_get_dictionary)((strm), (dict), (dict_len)); \ - } while (0) - -#define INFLATE_ADJUST_WINDOW_SIZE(n) MAX(n, HB_SIZE) - -#endif diff --git a/modules/zlib/src/arch/s390/s390_features.c b/modules/zlib/src/arch/s390/s390_features.c deleted file mode 100644 index dabb578a07..0000000000 --- a/modules/zlib/src/arch/s390/s390_features.c +++ /dev/null @@ -1,18 +0,0 @@ -#ifdef S390_FEATURES - -#include "zbuild.h" -#include "s390_features.h" - -#ifdef HAVE_SYS_AUXV_H -# include -#endif - -#ifndef HWCAP_S390_VXRS -#define HWCAP_S390_VXRS (1 << 11) -#endif - -void Z_INTERNAL s390_check_features(struct s390_cpu_features *features) { - features->has_vx = getauxval(AT_HWCAP) & HWCAP_S390_VXRS; -} - -#endif diff --git a/modules/zlib/src/arch/s390/s390_features.h b/modules/zlib/src/arch/s390/s390_features.h deleted file mode 100644 index fb2ac14b26..0000000000 --- a/modules/zlib/src/arch/s390/s390_features.h +++ /dev/null @@ -1,14 +0,0 @@ -/* s390_features.h -- check for s390 features. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef S390_FEATURES_H_ -#define S390_FEATURES_H_ - -struct s390_cpu_features { - int has_vx; -}; - -void Z_INTERNAL s390_check_features(struct s390_cpu_features *features); - -#endif diff --git a/modules/zlib/src/arch/s390/s390_functions.h b/modules/zlib/src/arch/s390/s390_functions.h deleted file mode 100644 index c0043a6e85..0000000000 --- a/modules/zlib/src/arch/s390/s390_functions.h +++ /dev/null @@ -1,44 +0,0 @@ -/* s390_functions.h -- s390 implementations for arch-specific functions. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef S390_FUNCTIONS_H_ -#define S390_FUNCTIONS_H_ - -#include "s390_natives.h" - -#define ADLER32_FALLBACK -#define CHUNKSET_FALLBACK -#define COMPARE256_FALLBACK -#define CRC32_BRAID_FALLBACK /* used by crc32_s390_vx */ - -#ifndef S390_VX_NATIVE -# define SLIDE_HASH_FALLBACK -#endif - -#ifdef S390_VX -uint32_t crc32_s390_vx(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_s390_vx(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -void slide_hash_vx(deflate_state *s); - -#ifdef __clang__ -# if ((__clang_major__ == 18) || (__clang_major__ == 19 && (__clang_minor__ < 1 || (__clang_minor__ == 1 && __clang_patchlevel__ < 2)))) -# error CRC32-VX optimizations are broken due to compiler bug in Clang versions: 18.0.0 <= clang_version < 19.1.2. \ - Either disable the zlib-ng S390 VX optimizations, or switch to another compiler/compiler version. -# endif -#endif - -#endif - -#ifdef DISABLE_RUNTIME_CPU_DETECTION -# ifdef S390_VX_NATIVE -# undef native_crc32 -# define native_crc32 crc32_s390_vx -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_s390_vx -# undef native_slide_hash -# define native_slide_hash slide_hash_vx -# endif -#endif - -#endif diff --git a/modules/zlib/src/arch/s390/s390_natives.h b/modules/zlib/src/arch/s390/s390_natives.h deleted file mode 100644 index 72a1ee88ea..0000000000 --- a/modules/zlib/src/arch/s390/s390_natives.h +++ /dev/null @@ -1,14 +0,0 @@ -/* s390_natives.h -- s390 compile-time feature detection macros. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef S390_NATIVES_H_ -#define S390_NATIVES_H_ - -#if defined(__zarch__) && __ARCH__ >= 11 && defined(__VX__) -# ifdef S390_VX -# define S390_VX_NATIVE -# endif -#endif - -#endif /* S390_NATIVES_H_ */ diff --git a/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner b/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner deleted file mode 100644 index aabc802547..0000000000 --- a/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# -# Ephemeral runner startup script. -# -# Expects the following environment variables: -# -# - REPO= -# - PAT_TOKEN= -# - -set -e -u - -# Validate required environment variables -if [ -z "${REPO:-}" ] || [ -z "${PAT_TOKEN:-}" ]; then - echo "Error: REPO and/or PAT_TOKEN environment variables not found" - exit 1 -fi - -# Check the cached registration token. -TOKEN_FILE=registration-token.json -if [ -f $TOKEN_FILE ]; then - set +e - EXPIRES=$(jq --raw-output .expires_at "$TOKEN_FILE" 2>/dev/null) - STATUS=$? - set -e -else - STATUS=1 - EXPIRES="" -fi - -if [[ $STATUS -ne 0 || -z "$EXPIRES" || "$EXPIRES" == "null" || $(date +%s) -ge $(date -d "$EXPIRES" +%s) ]]; then - # Refresh the cached registration token. - curl \ - -sS \ - -X POST \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $PAT_TOKEN" \ - "https://api.github.com/repos/$REPO/actions/runners/registration-token" \ - -o "$TOKEN_FILE" -fi - -REG_TOKEN=$(jq --raw-output .token "$TOKEN_FILE") -if [ $REG_TOKEN = "null" ]; then - echo "Failed to get registration token" - exit 1 -fi - -# (Re-)register the runner. -./config.sh remove --token "$REG_TOKEN" || true -set -x -./config.sh \ - --url "https://github.com/$REPO" \ - --token "$REG_TOKEN" \ - --unattended \ - --disableupdate \ - --replace \ - --labels z15 \ - --ephemeral - -# Run one job. -./run.sh diff --git a/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner-rebuild.sh b/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner-rebuild.sh deleted file mode 100644 index 7fded31785..0000000000 --- a/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner-rebuild.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/bash -set -ex - -TMPDIR="$(mktemp -d)" - -if [ -f actions-runner.Dockerfile ]; then - MODE=1 - cp actions-runner.Dockerfile actions-runner entrypoint $TMPDIR - cd $TMPDIR -else - MODE=2 - cd $TMPDIR - wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/actions-runner.Dockerfile - wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/actions-runner - wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/entrypoint -fi - -# Stop service -systemctl stop actions-runner || true - -# Delete old container -podman container rm gaplib-actions-runner || true - -# Delete old image -podman image rm localhost/zlib-ng/actions-runner || true - -# Prune all unused podman data -podman system prune -f || true - -# Build new image -podman build --squash -f actions-runner.Dockerfile --tag zlib-ng/actions-runner . 2>&1 | tee /var/log/actions-runner-build.log - -# Create new container -podman create --replace --name=gaplib-actions-runner --env-file=/etc/actions-runner --init \ - zlib-ng/actions-runner 2>&1 | tee -a /var/log/actions-runner-build.log - -# Start service -systemctl start actions-runner || true - -# Cleanup -podman image prune -af || true - -# Clean up tempfile -if [ "$MODE" == "2" ] ; then - cd $TMPDIR - rm actions-runner.Dockerfile - rm actions-runner - rm entrypoint - cd .. - rmdir $TMPDIR - echo "Deleted tempfiles." -fi diff --git a/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner.Dockerfile b/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner.Dockerfile deleted file mode 100644 index 7210caaebe..0000000000 --- a/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner.Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# Self-Hosted IBM Z Github Actions Runner. - -FROM almalinux:10 - -RUN dnf update -y -q && \ - dnf install -y -q --enablerepo=crb wget git which sudo jq sed \ - cmake make automake autoconf m4 libtool ninja-build \ - python3-pip python3-devel python3-lxml \ - gcc gcc-c++ clang llvm-toolset glibc-all-langpacks langpacks-en \ - glibc-static libstdc++-static libstdc++-devel libxslt-devel libxml2-devel - -RUN dnf install -y -q dotnet-sdk-8.0 && \ - echo "Using SDK - `dotnet --version`" - -RUN cd /tmp && \ - git clone -q https://github.com/actions/runner && \ - cd runner && \ - git checkout $(git tag --sort=-v:refname | grep '^v[0-9]' | head -n1) && \ - git log -n 1 && \ - wget https://raw.githubusercontent.com/IBM/action-runner-image-pz/refs/heads/main/patches/runner-sdk8-s390x.patch -O runner-sdk8-s390x.patch && \ - git apply --whitespace=nowarn runner-sdk8-s390x.patch && \ - - sed -i'' -e /version/s/8......\"$/$8.0.100\"/ src/global.json - -RUN cd /tmp/runner/src && \ - ./dev.sh layout && \ - ./dev.sh package && \ - rm -rf /root/.dotnet /root/.nuget - -RUN useradd -c "Action Runner" -m actions-runner && \ - usermod -L actions-runner - -RUN tar -xf /tmp/runner/_package/*.tar.gz -C /home/actions-runner && \ - chown -R actions-runner:actions-runner /home/actions-runner - -# Cleanup -RUN rm -rf /tmp/runner /var/cache/dnf/* /tmp/runner.patch /tmp/global.json && \ - dnf clean all - -USER actions-runner - -# Scripts. -COPY --chmod=555 entrypoint /usr/bin/ -COPY --chmod=555 actions-runner /usr/bin/ -WORKDIR /home/actions-runner -ENTRYPOINT ["/usr/bin/entrypoint"] -CMD ["/usr/bin/actions-runner"] diff --git a/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner.service b/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner.service deleted file mode 100644 index 79560cde18..0000000000 --- a/modules/zlib/src/arch/s390/self-hosted-builder/actions-runner.service +++ /dev/null @@ -1,18 +0,0 @@ -[Unit] -Description=Podman container: Gaplib Github Actions Runner -Wants=network-online.target -After=network-online.target -StartLimitIntervalSec=1 -RequiresMountsFor=/run/user/1001/containers - -[Service] -Environment=PODMAN_SYSTEMD_UNIT=%n -Restart=always -TimeoutStopSec=61 -ExecStart=/usr/bin/podman start gaplib-actions-runner -ExecStop=/usr/bin/podman stop -t 30 gaplib-actions-runner -ExecStopPost=/usr/bin/podman stop -t 10 gaplib-actions-runner -Type=forking - -[Install] -WantedBy=default.target diff --git a/modules/zlib/src/arch/s390/self-hosted-builder/entrypoint b/modules/zlib/src/arch/s390/self-hosted-builder/entrypoint deleted file mode 100644 index eb8772becf..0000000000 --- a/modules/zlib/src/arch/s390/self-hosted-builder/entrypoint +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# -# Container entrypoint that waits for all spawned processes. -# - -set -e -u - -# Create a FIFO and start reading from its read end. -tempdir=$(mktemp -d "/tmp/done.XXXXXXXXXX") -trap 'rm -r "$tempdir"' EXIT -done="$tempdir/pipe" -mkfifo "$done" -cat "$done" & waiter=$! - -# Start the workload. Its descendants will inherit the FIFO's write end. -status=0 -if [ "$#" -eq 0 ]; then - bash 9>"$done" || status=$? -else - "$@" 9>"$done" || status=$? -fi - -# When the workload and all of its descendants exit, the FIFO's write end will -# be closed and `cat "$done"` will exit. Wait until it happens. This is needed -# in order to handle SelfUpdater, which the workload may start in background -# before exiting. -wait "$waiter" - -exit "$status" diff --git a/modules/zlib/src/arch/s390/slide_hash_vx.c b/modules/zlib/src/arch/s390/slide_hash_vx.c deleted file mode 100644 index 0939bc984f..0000000000 --- a/modules/zlib/src/arch/s390/slide_hash_vx.c +++ /dev/null @@ -1,35 +0,0 @@ -/* slide_hash_vx.c - VX version of slide_hash for S390 processors - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef S390_VX - -#include "zbuild.h" -#include "deflate.h" - -#include "vx_intrins.h" - -static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) { - const uv8hi vmx_wsize = vec_splats(wsize); - Pos *p = table; - - do { - uv8hi value, result; - - value = vec_xl(0, p); - result = vec_sub(value, vec_min(value, vmx_wsize)); - vec_xst(result, 0, p); - - p += 8; - entries -= 8; - } while (entries > 0); -} - -Z_INTERNAL void slide_hash_vx(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - - slide_hash_chain(s->head, HASH_SIZE, wsize); - slide_hash_chain(s->prev, wsize, wsize); -} -#endif diff --git a/modules/zlib/src/arch/s390/vx_intrins.h b/modules/zlib/src/arch/s390/vx_intrins.h deleted file mode 100644 index f5b217db55..0000000000 --- a/modules/zlib/src/arch/s390/vx_intrins.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef S390_VX_INTRINS_H -#define S390_VX_INTRINS_H - -#include - -typedef unsigned char uv16qi __attribute__((vector_size(16))); -typedef unsigned short uv8hi __attribute__((vector_size(16))); -typedef unsigned int uv4si __attribute__((vector_size(16))); -typedef unsigned long long uv2di __attribute__((vector_size(16))); - -#ifndef vec_sub -#define vec_sub(a, b) ((a) - (b)) -#endif -#ifndef vec_subs -static inline uv8hi vec_subs_u16(uv8hi a, uv8hi b) { - return a - vec_min(a, b); -} -#define vec_subs(a, b) vec_subs_u16((a), (b)) -#endif - -#endif diff --git a/modules/zlib/src/arch/shared/chunk_128bit_perm_idx_lut.h b/modules/zlib/src/arch/shared/chunk_128bit_perm_idx_lut.h deleted file mode 100644 index 6e5098bf26..0000000000 --- a/modules/zlib/src/arch/shared/chunk_128bit_perm_idx_lut.h +++ /dev/null @@ -1,26 +0,0 @@ -/* chunk_128bit_perm_idx_lut.h - shared SSSE3/NEON/LSX permutation idx lut for use with chunkmemset family of functions. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef CHUNK_128BIT_PERM_IDX_LUT_H_ -#define CHUNK_128BIT_PERM_IDX_LUT_H_ - -#include "chunk_permute_table.h" - -static const lut_rem_pair perm_idx_lut[13] = { - {0, 1}, /* 3 */ - {0, 0}, /* don't care */ - {1 * 32, 1}, /* 5 */ - {2 * 32, 4}, /* 6 */ - {3 * 32, 2}, /* 7 */ - {0 * 32, 0}, /* don't care */ - {4 * 32, 7}, /* 9 */ - {5 * 32, 6}, /* 10 */ - {6 * 32, 5}, /* 11 */ - {7 * 32, 4}, /* 12 */ - {8 * 32, 3}, /* 13 */ - {9 * 32, 2}, /* 14 */ - {10 * 32, 1},/* 15 */ -}; - -#endif diff --git a/modules/zlib/src/arch/shared/chunk_256bit_perm_idx_lut.h b/modules/zlib/src/arch/shared/chunk_256bit_perm_idx_lut.h deleted file mode 100644 index 796a7df120..0000000000 --- a/modules/zlib/src/arch/shared/chunk_256bit_perm_idx_lut.h +++ /dev/null @@ -1,47 +0,0 @@ -/* chunk_256bit_perm_idx_lut.h - shared AVX512/AVX2/LASX permutation idx lut for use with chunkmemset family of functions. - * For conditions of distribution and use, see copyright notice in zlib.h - */ -#ifndef CHUNK_256BIT_PERM_IDX_LUT_H_ -#define CHUNK_256BIT_PERM_IDX_LUT_H_ - -#include "chunk_permute_table.h" - -/* Populate don't cares so that this is a direct lookup (with some indirection into the permute table), because dist can - * never be 0 - 2, we'll start with an offset, subtracting 3 from the input */ -static const lut_rem_pair perm_idx_lut[29] = { - { 0, 2}, /* 3 */ - { 0, 0}, /* don't care */ - { 1 * 32, 2}, /* 5 */ - { 2 * 32, 2}, /* 6 */ - { 3 * 32, 4}, /* 7 */ - { 0 * 32, 0}, /* don't care */ - { 4 * 32, 5}, /* 9 */ - { 5 * 32, 22}, /* 10 */ - { 6 * 32, 21}, /* 11 */ - { 7 * 32, 20}, /* 12 */ - { 8 * 32, 6}, /* 13 */ - { 9 * 32, 4}, /* 14 */ - {10 * 32, 2}, /* 15 */ - { 0 * 32, 0}, /* don't care */ - {11 * 32, 15}, /* 17 */ - {11 * 32 + 16, 14}, /* 18 */ - {11 * 32 + 16 * 2, 13}, /* 19 */ - {11 * 32 + 16 * 3, 12}, /* 20 */ - {11 * 32 + 16 * 4, 11}, /* 21 */ - {11 * 32 + 16 * 5, 10}, /* 22 */ - {11 * 32 + 16 * 6, 9}, /* 23 */ - {11 * 32 + 16 * 7, 8}, /* 24 */ - {11 * 32 + 16 * 8, 7}, /* 25 */ - {11 * 32 + 16 * 9, 6}, /* 26 */ - {11 * 32 + 16 * 10, 5}, /* 27 */ - {11 * 32 + 16 * 11, 4}, /* 28 */ - {11 * 32 + 16 * 12, 3}, /* 29 */ - {11 * 32 + 16 * 13, 2}, /* 30 */ - {11 * 32 + 16 * 14, 1} /* 31 */ -}; - -static const uint16_t half_rem_vals[13] = { - 1, 0, 1, 4, 2, 0, 7, 6, 5, 4, 3, 2, 1 -}; - -#endif diff --git a/modules/zlib/src/arch/shared/chunk_permute_table.h b/modules/zlib/src/arch/shared/chunk_permute_table.h deleted file mode 100644 index f3976b7647..0000000000 --- a/modules/zlib/src/arch/shared/chunk_permute_table.h +++ /dev/null @@ -1,53 +0,0 @@ -/* chunk_permute_table.h - shared AVX/SSSE3/NEON/LSX/LASX permutation table for use with chunkmemset family of functions. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef CHUNK_PERMUTE_TABLE_H_ -#define CHUNK_PERMUTE_TABLE_H_ - -#include "zbuild.h" - -/* Need entries for all numbers not an even modulus for 1, 2, 4, 8, 16 & 32 */ -static const ALIGNED_(32) uint8_t permute_table[26*32] = { - 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, /* dist 3 */ - 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, /* dist 5 */ - 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, /* dist 6 */ - 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, /* dist 7 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, /* dist 9 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, /* dist 10 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* dist 11 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, /* dist 12 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, /* dist 13 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1, 2, 3, /* dist 14 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 1, /* dist 15 */ - - /* Beyond dists of 15 means we have to permute from a vector > len(m128i). Because AVX couldn't permute - * beyond 128 bit lanes until AVX512 for sub 4-byte sequences, we have to do some math here for an eventual - * blend with a comparison. That means we need to wrap the indices with yet another derived table. For simplicity, - * we'll use absolute indexing here to derive a blend vector. This is actually a lot simpler with ARM's TBL, but, - * this is what we're dealt. - */ - - 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* dist 17 */ - 16, 17, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, /* dist 18 */ - 16, 17, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, /* dist 19 */ - 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* dist 20 */ - 16, 17, 18, 19, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* dist 21 */ - 16, 17, 18, 19, 20, 21, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* dist 22 */ - 16, 17, 18, 19, 20, 21, 22, 0, 1, 2, 3, 4, 5, 6, 7, 8, /* dist 23 */ - 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7, /* dist 24 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 1, 2, 3, 4, 5, 6, /* dist 25 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 1, 2, 3, 4, 5, /* dist 26 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 1, 2, 3, 4, /* dist 27 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 1, 2, 3, /* dist 28 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 1, 2, /* dist 29 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 1, /* dist 30 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 0, /* dist 31 */ -}; - -typedef struct lut_rem_pair_s { - uint16_t idx; - uint16_t remval; -} lut_rem_pair; - -#endif diff --git a/modules/zlib/src/arch/shared/crc32_hw_common_tpl.h b/modules/zlib/src/arch/shared/crc32_hw_common_tpl.h deleted file mode 100644 index 9a9c3bb645..0000000000 --- a/modules/zlib/src/arch/shared/crc32_hw_common_tpl.h +++ /dev/null @@ -1,98 +0,0 @@ -/* crc32_hw_common_tpl.h -- Private shared inline CRC32 functions for CPU with native crc instructions - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" - - -Z_FORCEINLINE static Z_TARGET_CRC uint32_t crc32_hw_align(uint32_t crc, uint8_t **dst, const uint8_t **buf, - size_t *len, uintptr_t align_diff, const int COPY) { - if (*len && (align_diff & 1)) { - uint8_t val = **buf; - if (COPY) { - **dst = val; - *dst += 1; - } - crc = CRC32B(crc, val); - *buf += 1; - *len -= 1; - } - - if (*len >= 2 && (align_diff & 2)) { - uint16_t val = *((uint16_t*)*buf); - if (COPY) { - memcpy(*dst, &val, 2); - *dst += 2; - } - crc = CRC32H(crc, val); - *buf += 2; - *len -= 2; - } - - if (*len >= 4 && (align_diff & 4)) { - uint32_t val = *((uint32_t*)*buf); - if (COPY) { - memcpy(*dst, &val, 4); - *dst += 4; - } - crc = CRC32W(crc, val); - *buf += 4; - *len -= 4; - } - - if (*len >= 8 && (align_diff & 8)) { - uint64_t val = *((uint64_t*)*buf); - if (COPY) { - memcpy(*dst, &val, 8); - *dst += 8; - } - crc = CRC32D(crc, val); - *buf += 8; - *len -= 8; - } - - return crc; -} - -Z_FORCEINLINE static Z_TARGET_CRC uint32_t crc32_hw_tail(uint32_t crc, uint8_t *dst, const uint8_t *buf, - size_t len, const int COPY) { - while (len >= 8) { - uint64_t val = *((uint64_t*)buf); - if (COPY) { - memcpy(dst, &val, 8); - dst += 8; - } - crc = CRC32D(crc, val); - buf += 8; - len -= 8; - } - - if (len & 4) { - uint32_t val = *((uint32_t*)buf); - if (COPY) { - memcpy(dst, &val, 4); - dst += 4; - } - crc = CRC32W(crc, val); - buf += 4; - } - - if (len & 2) { - uint16_t val = *((uint16_t*)buf); - if (COPY) { - memcpy(dst, &val, 2); - dst += 2; - } - crc = CRC32H(crc, val); - buf += 2; - } - - if (len & 1) { - uint8_t val = *buf; - if (COPY) - *dst = val; - crc = CRC32B(crc, val); - } - - return ~crc; -} diff --git a/modules/zlib/src/arch/shared/crc32_hw_copy_impl_tpl.h b/modules/zlib/src/arch/shared/crc32_hw_copy_impl_tpl.h deleted file mode 100644 index ffa9a5112f..0000000000 --- a/modules/zlib/src/arch/shared/crc32_hw_copy_impl_tpl.h +++ /dev/null @@ -1,62 +0,0 @@ -/* crc32_hw_copy_impl_tpl.h -- compute the CRC-32 of a data stream for CPU with native crc instructions - * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler - * Copyright (C) 2016 Yang Zhang - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" - - -Z_FORCEINLINE static Z_TARGET_CRC uint32_t crc32_hw_copy_impl(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len, - const int COPY) { - uint32_t c = ~crc; - - if (UNLIKELY(len == 1)) { - if (COPY) - *dst = *src; - c = CRC32B(c, *src); - return ~c; - } - - /* Align to 8-byte boundary for tail processing */ - uintptr_t align_diff = ALIGN_DIFF(src, 8); - if (align_diff) - c = crc32_hw_align(c, &dst, &src, &len, align_diff, COPY); - - while (len >= 64) { - uint64_t d0 = *(const uint64_t *)src; - uint64_t d1 = *(const uint64_t *)(src + 8); - uint64_t d2 = *(const uint64_t *)(src + 16); - uint64_t d3 = *(const uint64_t *)(src + 24); - uint64_t d4 = *(const uint64_t *)(src + 32); - uint64_t d5 = *(const uint64_t *)(src + 40); - uint64_t d6 = *(const uint64_t *)(src + 48); - uint64_t d7 = *(const uint64_t *)(src + 56); - - if (COPY) { - memcpy(dst, &d0, 8); - memcpy(dst + 8, &d1, 8); - memcpy(dst + 16, &d2, 8); - memcpy(dst + 24, &d3, 8); - memcpy(dst + 32, &d4, 8); - memcpy(dst + 40, &d5, 8); - memcpy(dst + 48, &d6, 8); - memcpy(dst + 56, &d7, 8); - dst += 64; - } - - c = CRC32D(c, d0); - c = CRC32D(c, d1); - c = CRC32D(c, d2); - c = CRC32D(c, d3); - c = CRC32D(c, d4); - c = CRC32D(c, d5); - c = CRC32D(c, d6); - c = CRC32D(c, d7); - - src += 64; - len -= 64; - } - - return crc32_hw_tail(c, dst, src, len, COPY); -} diff --git a/modules/zlib/src/arch/x86/Makefile.in b/modules/zlib/src/arch/x86/Makefile.in deleted file mode 100644 index f756844a9f..0000000000 --- a/modules/zlib/src/arch/x86/Makefile.in +++ /dev/null @@ -1,176 +0,0 @@ -# Makefile for zlib -# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler -# For conditions of distribution and use, see copyright notice in zlib.h - -CC= -CFLAGS= -SFLAGS= -INCLUDES= -SUFFIX= - -AVX512FLAG=-mavx512f -mavx512dq -mavx512vl -mavx512bw -mbmi2 -AVX512VNNIFLAG=-mavx512vnni -mbmi2 -AVX2FLAG=-mavx2 -mbmi2 -SSE2FLAG=-msse2 -SSSE3FLAG=-mssse3 -SSE41FLAG=-msse4.1 -SSE42FLAG=-msse4.2 -PCLMULFLAG=-mpclmul -VPCLMULFLAG=-mvpclmulqdq -XSAVEFLAG=-mxsave -NOLTOFLAG= - -SRCDIR=. -SRCTOP=../.. -TOPDIR=$(SRCTOP) - -all: \ - x86_features.o x86_features.lo \ - adler32_avx2.o adler32_avx2.lo \ - adler32_avx512.o adler32_avx512.lo \ - adler32_avx512_vnni.o adler32_avx512_vnni.lo \ - adler32_sse42.o adler32_sse42.lo \ - adler32_ssse3.o adler32_ssse3.lo \ - chunkset_avx2.o chunkset_avx2.lo \ - chunkset_avx512.o chunkset_avx512.lo \ - chunkset_sse2.o chunkset_sse2.lo \ - chunkset_ssse3.o chunkset_ssse3.lo \ - compare256_avx2.o compare256_avx2.lo \ - compare256_avx512.o compare256_avx512.lo \ - compare256_sse2.o compare256_sse2.lo \ - crc32_chorba_sse2.o crc32_chorba_sse2.lo \ - crc32_chorba_sse41.o crc32_chorba_sse41.lo \ - crc32_pclmulqdq.o crc32_pclmulqdq.lo \ - crc32_vpclmulqdq_avx2.o crc32_vpclmulqdq_avx2.lo \ - crc32_vpclmulqdq_avx512.o crc32_vpclmulqdq_avx512.lo \ - slide_hash_avx2.o slide_hash_avx2.lo \ - slide_hash_sse2.o slide_hash_sse2.lo - -x86_features.o: - $(CC) $(CFLAGS) $(XSAVEFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/x86_features.c - -x86_features.lo: - $(CC) $(SFLAGS) $(XSAVEFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/x86_features.c - -chunkset_avx2.o: - $(CC) $(CFLAGS) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_avx2.c - -chunkset_avx2.lo: - $(CC) $(SFLAGS) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_avx2.c - -chunkset_avx512.o: - $(CC) $(CFLAGS) $(AVX512FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_avx512.c - -chunkset_avx512.lo: - $(CC) $(SFLAGS) $(AVX512FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_avx512.c - -chunkset_sse2.o: - $(CC) $(CFLAGS) $(SSE2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_sse2.c - -chunkset_sse2.lo: - $(CC) $(SFLAGS) $(SSE2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_sse2.c - -chunkset_ssse3.o: - $(CC) $(CFLAGS) $(SSSE3FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_ssse3.c - -chunkset_ssse3.lo: - $(CC) $(SFLAGS) $(SSSE3FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_ssse3.c - -compare256_avx2.o: - $(CC) $(CFLAGS) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_avx2.c - -compare256_avx2.lo: - $(CC) $(SFLAGS) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_avx2.c - -compare256_avx512.o: - $(CC) $(CFLAGS) $(AVX512FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_avx512.c - -compare256_avx512.lo: - $(CC) $(SFLAGS) $(AVX512FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_avx512.c - -compare256_sse2.o: - $(CC) $(CFLAGS) $(SSE2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_sse2.c - -compare256_sse2.lo: - $(CC) $(SFLAGS) $(SSE2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_sse2.c - -crc32_chorba_sse2.o: - $(CC) $(CFLAGS) $(SSE2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_chorba_sse2.c - -crc32_chorba_sse2.lo: - $(CC) $(SFLAGS) $(SSE2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_chorba_sse2.c - -crc32_chorba_sse41.o: - $(CC) $(CFLAGS) $(SSE41FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_chorba_sse41.c - -crc32_chorba_sse41.lo: - $(CC) $(SFLAGS) $(SSE41FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_chorba_sse41.c - -crc32_pclmulqdq.o: - $(CC) $(CFLAGS) $(PCLMULFLAG) $(SSE42FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_pclmulqdq.c - -crc32_pclmulqdq.lo: - $(CC) $(SFLAGS) $(PCLMULFLAG) $(SSE42FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_pclmulqdq.c - -crc32_vpclmulqdq_avx2.o: - $(CC) $(CFLAGS) $(PCLMULFLAG) $(VPCLMULFLAG) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vpclmulqdq_avx2.c - -crc32_vpclmulqdq_avx2.lo: - $(CC) $(SFLAGS) $(PCLMULFLAG) $(VPCLMULFLAG) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vpclmulqdq_avx2.c - -crc32_vpclmulqdq_avx512.o: - $(CC) $(CFLAGS) $(PCLMULFLAG) $(VPCLMULFLAG) $(AVX512FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vpclmulqdq_avx512.c - -crc32_vpclmulqdq_avx512.lo: - $(CC) $(SFLAGS) $(PCLMULFLAG) $(VPCLMULFLAG) $(AVX512FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vpclmulqdq_avx512.c - -slide_hash_avx2.o: - $(CC) $(CFLAGS) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_avx2.c - -slide_hash_avx2.lo: - $(CC) $(SFLAGS) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_avx2.c - -slide_hash_sse2.o: - $(CC) $(CFLAGS) $(SSE2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_sse2.c - -slide_hash_sse2.lo: - $(CC) $(SFLAGS) $(SSE2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_sse2.c - -adler32_avx2.o: $(SRCDIR)/adler32_avx2.c - $(CC) $(CFLAGS) $(AVX2FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx2.c - -adler32_avx2.lo: $(SRCDIR)/adler32_avx2.c - $(CC) $(SFLAGS) $(AVX2FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx2.c - -adler32_avx512.o: $(SRCDIR)/adler32_avx512.c - $(CC) $(CFLAGS) $(AVX512FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx512.c - -adler32_avx512.lo: $(SRCDIR)/adler32_avx512.c - $(CC) $(SFLAGS) $(AVX512FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx512.c - -adler32_avx512_vnni.o: $(SRCDIR)/adler32_avx512_vnni.c - $(CC) $(CFLAGS) $(AVX512VNNIFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx512_vnni.c - -adler32_avx512_vnni.lo: $(SRCDIR)/adler32_avx512_vnni.c - $(CC) $(SFLAGS) $(AVX512VNNIFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_avx512_vnni.c - -adler32_ssse3.o: $(SRCDIR)/adler32_ssse3.c - $(CC) $(CFLAGS) $(SSSE3FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_ssse3.c - -adler32_ssse3.lo: $(SRCDIR)/adler32_ssse3.c - $(CC) $(SFLAGS) $(SSSE3FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_ssse3.c - -adler32_sse42.o: $(SRCDIR)/adler32_sse42.c - $(CC) $(CFLAGS) $(SSE42FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_sse42.c - -adler32_sse42.lo: $(SRCDIR)/adler32_sse42.c - $(CC) $(SFLAGS) $(SSE42FLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_sse42.c - -mostlyclean: clean -clean: - rm -f *.o *.lo *~ - rm -rf objs - rm -f *.gcda *.gcno *.gcov - -distclean: clean - rm -f Makefile diff --git a/modules/zlib/src/arch/x86/adler32_avx2.c b/modules/zlib/src/arch/x86/adler32_avx2.c deleted file mode 100644 index d1811b254d..0000000000 --- a/modules/zlib/src/arch/x86/adler32_avx2.c +++ /dev/null @@ -1,172 +0,0 @@ -/* adler32_avx2.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011 Mark Adler - * Copyright (C) 2022 Adam Stylinski - * Authors: - * Brian Bockelman - * Adam Stylinski - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_AVX2 - -#include "zbuild.h" -#include -#include "adler32_p.h" -#include "adler32_avx2_p.h" -#include "x86_intrins.h" - -extern uint32_t adler32_copy_sse42(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -extern uint32_t adler32_ssse3(uint32_t adler, const uint8_t *src, size_t len); - -Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) { - uint32_t adler0, adler1; - adler1 = (adler >> 16) & 0xffff; - adler0 = adler & 0xffff; - -rem_peel: - if (len < 16) { - return adler32_copy_tail(adler0, dst, src, len, adler1, 1, 15, COPY); - } else if (len < 32) { - if (COPY) { - return adler32_copy_sse42(adler, dst, src, len); - } else { - return adler32_ssse3(adler, src, len); - } - } - - __m256i vs1, vs2, vs2_0; - - const __m256i dot2v = _mm256_setr_epi8(64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, - 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33); - const __m256i dot2v_0 = _mm256_setr_epi8(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, - 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); - const __m256i dot3v = _mm256_set1_epi16(1); - const __m256i zero = _mm256_setzero_si256(); - - while (len >= 32) { - vs1 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler0)); - vs2 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler1)); - __m256i vs1_0 = vs1; - __m256i vs3 = _mm256_setzero_si256(); - vs2_0 = vs3; - - size_t k = ALIGN_DOWN(MIN(len, NMAX), 32); - len -= k; - - while (k >= 64) { - __m256i vbuf = _mm256_loadu_si256((__m256i*)src); - __m256i vbuf_0 = _mm256_loadu_si256((__m256i*)(src + 32)); - src += 64; - k -= 64; - - __m256i vs1_sad = _mm256_sad_epu8(vbuf, zero); - __m256i vs1_sad2 = _mm256_sad_epu8(vbuf_0, zero); - - if (COPY) { - _mm256_storeu_si256((__m256i*)dst, vbuf); - _mm256_storeu_si256((__m256i*)(dst + 32), vbuf_0); - dst += 64; - } - - vs1 = _mm256_add_epi32(vs1, vs1_sad); - vs3 = _mm256_add_epi32(vs3, vs1_0); - __m256i v_short_sum2 = _mm256_maddubs_epi16(vbuf, dot2v); // sum 32 uint8s to 16 shorts - __m256i v_short_sum2_0 = _mm256_maddubs_epi16(vbuf_0, dot2v_0); // sum 32 uint8s to 16 shorts - __m256i vsum2 = _mm256_madd_epi16(v_short_sum2, dot3v); // sum 16 shorts to 8 uint32s - __m256i vsum2_0 = _mm256_madd_epi16(v_short_sum2_0, dot3v); // sum 16 shorts to 8 uint32s - vs1 = _mm256_add_epi32(vs1_sad2, vs1); - vs2 = _mm256_add_epi32(vsum2, vs2); - vs2_0 = _mm256_add_epi32(vsum2_0, vs2_0); - vs1_0 = vs1; - } - - vs2 = _mm256_add_epi32(vs2_0, vs2); - vs3 = _mm256_slli_epi32(vs3, 6); - vs2 = _mm256_add_epi32(vs3, vs2); - vs3 = _mm256_setzero_si256(); - - while (k >= 32) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 32 vs1 + sum( (32-i+1) c[i] ) - */ - __m256i vbuf = _mm256_loadu_si256((__m256i*)src); - src += 32; - k -= 32; - - __m256i vs1_sad = _mm256_sad_epu8(vbuf, zero); // Sum of abs diff, resulting in 2 x int32's - - if (COPY) { - _mm256_storeu_si256((__m256i*)dst, vbuf); - dst += 32; - } - - vs1 = _mm256_add_epi32(vs1, vs1_sad); - vs3 = _mm256_add_epi32(vs3, vs1_0); - __m256i v_short_sum2 = _mm256_maddubs_epi16(vbuf, dot2v_0); // sum 32 uint8s to 16 shorts - __m256i vsum2 = _mm256_madd_epi16(v_short_sum2, dot3v); // sum 16 shorts to 8 uint32s - vs2 = _mm256_add_epi32(vsum2, vs2); - vs1_0 = vs1; - } - - /* Defer the multiplication with 32 to outside of the loop */ - vs3 = _mm256_slli_epi32(vs3, 5); - vs2 = _mm256_add_epi32(vs2, vs3); - - /* The compiler is generating the following sequence for this integer modulus - * when done the scalar way, in GPRs: - - adler = (s1_unpack[0] % BASE) + (s1_unpack[1] % BASE) + (s1_unpack[2] % BASE) + (s1_unpack[3] % BASE) + - (s1_unpack[4] % BASE) + (s1_unpack[5] % BASE) + (s1_unpack[6] % BASE) + (s1_unpack[7] % BASE); - - mov $0x80078071,%edi // move magic constant into 32 bit register %edi - ... - vmovd %xmm1,%esi // move vector lane 0 to 32 bit register %esi - mov %rsi,%rax // zero-extend this value to 64 bit precision in %rax - imul %rdi,%rsi // do a signed multiplication with magic constant and vector element - shr $0x2f,%rsi // shift right by 47 - imul $0xfff1,%esi,%esi // do a signed multiplication with value truncated to 32 bits with 0xfff1 - sub %esi,%eax // subtract lower 32 bits of original vector value from modified one above - ... - // repeats for each element with vpextract instructions - - This is tricky with AVX2 for a number of reasons: - 1.) There's no 64 bit multiplication instruction, but there is a sequence to get there - 2.) There's ways to extend vectors to 64 bit precision, but no simple way to truncate - back down to 32 bit precision later (there is in AVX512) - 3.) Full width integer multiplications aren't cheap - - We can, however, do a relatively cheap sequence for horizontal sums. - Then, we simply do the integer modulus on the resulting 64 bit GPR, on a scalar value. It was - previously thought that casting to 64 bit precision was needed prior to the horizontal sum, but - that is simply not the case, as NMAX is defined as the maximum number of scalar sums that can be - performed on the maximum possible inputs before overflow - */ - - - /* In AVX2-land, this trip through GPRs will probably be unavoidable, as there's no cheap and easy - * conversion from 64 bit integer to 32 bit (needed for the inexpensive modulus with a constant). - * This casting to 32 bit is cheap through GPRs (just register aliasing). See above for exactly - * what the compiler is doing to avoid integer divisions. */ - adler0 = partial_hsum256(vs1) % BASE; - adler1 = hsum256(vs2) % BASE; - } - - adler = adler0 | (adler1 << 16); - - if (len) { - goto rem_peel; - } - - return adler; -} - -Z_INTERNAL uint32_t adler32_avx2(uint32_t adler, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, NULL, src, len, 0); -} - -Z_INTERNAL uint32_t adler32_copy_avx2(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, dst, src, len, 1); -} - -#endif diff --git a/modules/zlib/src/arch/x86/adler32_avx2_p.h b/modules/zlib/src/arch/x86/adler32_avx2_p.h deleted file mode 100644 index f0f8a4a887..0000000000 --- a/modules/zlib/src/arch/x86/adler32_avx2_p.h +++ /dev/null @@ -1,32 +0,0 @@ -/* adler32_avx2_p.h -- adler32 avx2 utility functions - * Copyright (C) 2022 Adam Stylinski - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ADLER32_AVX2_P_H_ -#define ADLER32_AVX2_P_H_ - -#if defined(X86_AVX2) || defined(X86_AVX512VNNI) - -/* 32 bit horizontal sum, adapted from Agner Fog's vector library. */ -static inline uint32_t hsum256(__m256i x) { - __m128i sum1 = _mm_add_epi32(_mm256_extracti128_si256(x, 1), - _mm256_castsi256_si128(x)); - __m128i sum2 = _mm_add_epi32(sum1, _mm_unpackhi_epi64(sum1, sum1)); - __m128i sum3 = _mm_add_epi32(sum2, _mm_shuffle_epi32(sum2, 1)); - return (uint32_t)_mm_cvtsi128_si32(sum3); -} - -static inline uint32_t partial_hsum256(__m256i x) { - /* We need a permutation vector to extract every other integer. The - * rest are going to be zeros */ - const __m256i perm_vec = _mm256_setr_epi32(0, 2, 4, 6, 1, 1, 1, 1); - __m256i non_zero = _mm256_permutevar8x32_epi32(x, perm_vec); - __m128i non_zero_sse = _mm256_castsi256_si128(non_zero); - __m128i sum2 = _mm_add_epi32(non_zero_sse,_mm_unpackhi_epi64(non_zero_sse, non_zero_sse)); - __m128i sum3 = _mm_add_epi32(sum2, _mm_shuffle_epi32(sum2, 1)); - return (uint32_t)_mm_cvtsi128_si32(sum3); -} -#endif - -#endif diff --git a/modules/zlib/src/arch/x86/adler32_avx512.c b/modules/zlib/src/arch/x86/adler32_avx512.c deleted file mode 100644 index 8a8e165bb9..0000000000 --- a/modules/zlib/src/arch/x86/adler32_avx512.c +++ /dev/null @@ -1,102 +0,0 @@ -/* adler32_avx512.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011 Mark Adler - * Authors: - * Adam Stylinski - * Brian Bockelman - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_AVX512 - -#include "zbuild.h" -#include "adler32_p.h" -#include "arch_functions.h" -#include -#include "x86_intrins.h" -#include "adler32_avx512_p.h" - -Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) { - uint32_t adler0, adler1; - adler1 = (adler >> 16) & 0xffff; - adler0 = adler & 0xffff; - -rem_peel: - if (len < 64) { - /* This handles the remaining copies, just call normal adler checksum after this */ - if (COPY && len) { - __mmask64 storemask = (0xFFFFFFFFFFFFFFFFUL >> (64 - len)); - __m512i copy_vec = _mm512_maskz_loadu_epi8(storemask, src); - _mm512_mask_storeu_epi8(dst, storemask, copy_vec); - } - - return adler32_avx2(adler, src, len); - } - - __m512i vbuf, vs1_0, vs3; - - const __m512i dot2v = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64); - const __m512i dot3v = _mm512_set1_epi16(1); - const __m512i zero = _mm512_setzero_si512(); - - while (len >= 64) { - __m512i vs1 = _mm512_zextsi128_si512(_mm_cvtsi32_si128(adler0)); - __m512i vs2 = _mm512_zextsi128_si512(_mm_cvtsi32_si128(adler1)); - vs1_0 = vs1; - vs3 = _mm512_setzero_si512(); - - size_t k = ALIGN_DOWN(MIN(len, NMAX), 64); - len -= k; - - while (k >= 64) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 64 vs1 + sum( (64-i+1) c[i] ) - */ - vbuf = _mm512_loadu_si512(src); - - if (COPY) { - _mm512_storeu_si512(dst, vbuf); - dst += 64; - } - - src += 64; - k -= 64; - - __m512i vs1_sad = _mm512_sad_epu8(vbuf, zero); - __m512i v_short_sum2 = _mm512_maddubs_epi16(vbuf, dot2v); - vs1 = _mm512_add_epi32(vs1_sad, vs1); - vs3 = _mm512_add_epi32(vs3, vs1_0); - __m512i vsum2 = _mm512_madd_epi16(v_short_sum2, dot3v); - vs2 = _mm512_add_epi32(vsum2, vs2); - vs1_0 = vs1; - } - - vs3 = _mm512_slli_epi32(vs3, 6); - vs2 = _mm512_add_epi32(vs2, vs3); - - adler0 = partial_hsum(vs1) % BASE; - adler1 = _mm512_reduce_add_epu32(vs2) % BASE; - } - - adler = adler0 | (adler1 << 16); - - /* Process tail (len < 64). */ - if (len) { - goto rem_peel; - } - - return adler; -} - -Z_INTERNAL uint32_t adler32_avx512(uint32_t adler, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, NULL, src, len, 0); -} - -Z_INTERNAL uint32_t adler32_copy_avx512(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - return adler32_copy_impl(adler, dst, src, len, 1); -} - -#endif diff --git a/modules/zlib/src/arch/x86/adler32_avx512_p.h b/modules/zlib/src/arch/x86/adler32_avx512_p.h deleted file mode 100644 index 742269053c..0000000000 --- a/modules/zlib/src/arch/x86/adler32_avx512_p.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef AVX512_FUNCS_H -#define AVX512_FUNCS_H - -#include -#include - -/* Written because Visual C++ toolchains before v142 have constant overflow in AVX512 intrinsic macros */ -#if defined(_MSC_VER) && !defined(_MM_K0_REG8) -# undef _mm512_extracti64x4_epi64 -# define _mm512_extracti64x4_epi64(v1, e1) _mm512_maskz_extracti64x4_epi64(UINT8_MAX, v1, e1) -# undef _mm512_set1_epi16 -# define _mm512_set1_epi16(e1) _mm512_maskz_set1_epi16(UINT32_MAX, e1) -# undef _mm512_maddubs_epi16 -# define _mm512_maddubs_epi16(v1, v2) _mm512_maskz_maddubs_epi16(UINT32_MAX, v1, v2) -#endif - -/* Written because *_add_epi32(a) sets off ubsan */ -static inline uint32_t _mm512_reduce_add_epu32(__m512i x) { - __m256i a = _mm512_extracti64x4_epi64(x, 1); - __m256i b = _mm512_extracti64x4_epi64(x, 0); - - __m256i a_plus_b = _mm256_add_epi32(a, b); - __m128i c = _mm256_extracti128_si256(a_plus_b, 1); - __m128i d = _mm256_extracti128_si256(a_plus_b, 0); - __m128i c_plus_d = _mm_add_epi32(c, d); - - __m128i sum1 = _mm_unpackhi_epi64(c_plus_d, c_plus_d); - __m128i sum2 = _mm_add_epi32(sum1, c_plus_d); - __m128i sum3 = _mm_shuffle_epi32(sum2, 0x01); - __m128i sum4 = _mm_add_epi32(sum2, sum3); - - return _mm_cvtsi128_si32(sum4); -} - -static inline uint32_t partial_hsum(__m512i x) { - /* We need a permutation vector to extract every other integer. The - * rest are going to be zeros. Marking this const so the compiler stands - * a better chance of keeping this resident in a register through entire - * loop execution. We certainly have enough zmm registers (32) */ - const __m512i perm_vec = _mm512_setr_epi32(0, 2, 4, 6, 8, 10, 12, 14, - 1, 1, 1, 1, 1, 1, 1, 1); - - __m512i non_zero = _mm512_permutexvar_epi32(perm_vec, x); - - /* From here, it's a simple 256 bit wide reduction sum */ - __m256i non_zero_avx = _mm512_castsi512_si256(non_zero); - - /* See Agner Fog's vectorclass for a decent reference. Essentially, phadd is - * pretty slow, much slower than the longer instruction sequence below */ - __m128i sum1 = _mm_add_epi32(_mm256_extracti128_si256(non_zero_avx, 1), - _mm256_castsi256_si128(non_zero_avx)); - __m128i sum2 = _mm_add_epi32(sum1,_mm_unpackhi_epi64(sum1, sum1)); - __m128i sum3 = _mm_add_epi32(sum2,_mm_shuffle_epi32(sum2, 1)); - return (uint32_t)_mm_cvtsi128_si32(sum3); -} - -#endif diff --git a/modules/zlib/src/arch/x86/adler32_avx512_vnni.c b/modules/zlib/src/arch/x86/adler32_avx512_vnni.c deleted file mode 100644 index 8bebffbf88..0000000000 --- a/modules/zlib/src/arch/x86/adler32_avx512_vnni.c +++ /dev/null @@ -1,205 +0,0 @@ -/* adler32_avx512_vnni.c -- compute the Adler-32 checksum of a data stream - * Based on Brian Bockelman's AVX2 version - * Copyright (C) 1995-2011 Mark Adler - * Authors: - * Adam Stylinski - * Brian Bockelman - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_AVX512VNNI - -#include "zbuild.h" -#include "adler32_p.h" -#include "arch_functions.h" -#include -#include "x86_intrins.h" -#include "adler32_avx512_p.h" -#include "adler32_avx2_p.h" - -Z_INTERNAL uint32_t adler32_avx512_vnni(uint32_t adler, const uint8_t *src, size_t len) { - uint32_t adler0, adler1; - adler1 = (adler >> 16) & 0xffff; - adler0 = adler & 0xffff; - -rem_peel: - if (len < 32) - return adler32_ssse3(adler, src, len); - - if (len < 64) - return adler32_avx2(adler, src, len); - - const __m512i dot2v = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64); - - const __m512i zero = _mm512_setzero_si512(); - __m512i vs1, vs2; - - while (len >= 64) { - vs1 = _mm512_zextsi128_si512(_mm_cvtsi32_si128(adler0)); - vs2 = _mm512_zextsi128_si512(_mm_cvtsi32_si128(adler1)); - size_t k = ALIGN_DOWN(MIN(len, NMAX), 64); - len -= k; - __m512i vs1_0 = vs1; - __m512i vs3 = _mm512_setzero_si512(); - /* We might get a tad bit more ILP here if we sum to a second register in the loop */ - __m512i vs2_1 = _mm512_setzero_si512(); - __m512i vbuf0, vbuf1; - - /* Remainder peeling */ - if (k % 128) { - vbuf1 = _mm512_loadu_si512((__m512i*)src); - - src += 64; - k -= 64; - - __m512i vs1_sad = _mm512_sad_epu8(vbuf1, zero); - vs1 = _mm512_add_epi32(vs1, vs1_sad); - vs3 = _mm512_add_epi32(vs3, vs1_0); - vs2 = _mm512_dpbusd_epi32(vs2, vbuf1, dot2v); - vs1_0 = vs1; - } - - /* Manually unrolled this loop by 2 for an decent amount of ILP */ - while (k >= 128) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 64 vs1 + sum( (64-i+1) c[i] ) - */ - vbuf0 = _mm512_loadu_si512((__m512i*)src); - vbuf1 = _mm512_loadu_si512((__m512i*)(src + 64)); - src += 128; - k -= 128; - - __m512i vs1_sad = _mm512_sad_epu8(vbuf0, zero); - vs1 = _mm512_add_epi32(vs1, vs1_sad); - vs3 = _mm512_add_epi32(vs3, vs1_0); - /* multiply-add, resulting in 16 ints. Fuse with sum stage from prior versions, as we now have the dp - * instructions to eliminate them */ - vs2 = _mm512_dpbusd_epi32(vs2, vbuf0, dot2v); - - vs3 = _mm512_add_epi32(vs3, vs1); - vs1_sad = _mm512_sad_epu8(vbuf1, zero); - vs1 = _mm512_add_epi32(vs1, vs1_sad); - vs2_1 = _mm512_dpbusd_epi32(vs2_1, vbuf1, dot2v); - vs1_0 = vs1; - } - - vs3 = _mm512_slli_epi32(vs3, 6); - vs2 = _mm512_add_epi32(vs2, vs3); - vs2 = _mm512_add_epi32(vs2, vs2_1); - - adler0 = partial_hsum(vs1) % BASE; - adler1 = _mm512_reduce_add_epu32(vs2) % BASE; - } - - adler = adler0 | (adler1 << 16); - - /* Process tail (len < 64). */ - if (len) { - goto rem_peel; - } - - return adler; -} - -/* Use 256-bit vectors when copying because 512-bit variant is slower. */ -Z_INTERNAL uint32_t adler32_copy_avx512_vnni(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - uint32_t adler0, adler1; - adler1 = (adler >> 16) & 0xffff; - adler0 = adler & 0xffff; - -rem_peel_copy: - if (len < 32) { - /* This handles the remaining copies, just call normal adler checksum after this */ - __mmask32 storemask = (0xFFFFFFFFUL >> (32 - len)); - __m256i copy_vec = _mm256_maskz_loadu_epi8(storemask, src); - _mm256_mask_storeu_epi8(dst, storemask, copy_vec); - - return adler32_ssse3(adler, src, len); - } - - const __m256i dot2v = _mm256_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - - const __m256i zero = _mm256_setzero_si256(); - __m256i vs1, vs2; - - while (len >= 32) { - vs1 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler0)); - vs2 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler1)); - - size_t k = ALIGN_DOWN(MIN(len, NMAX), 32); - len -= k; - - __m256i vs1_0 = vs1; - __m256i vs3 = _mm256_setzero_si256(); - /* We might get a tad bit more ILP here if we sum to a second register in the loop */ - __m256i vs2_1 = _mm256_setzero_si256(); - __m256i vbuf0, vbuf1; - - /* Remainder peeling */ - if (k % 64) { - vbuf1 = _mm256_loadu_si256((__m256i*)src); - _mm256_storeu_si256((__m256i*)dst, vbuf1); - dst += 32; - - src += 32; - k -= 32; - - __m256i vs1_sad = _mm256_sad_epu8(vbuf1, zero); - vs1 = _mm256_add_epi32(vs1, vs1_sad); - vs3 = _mm256_add_epi32(vs3, vs1_0); - vs2 = _mm256_dpbusd_epi32(vs2, vbuf1, dot2v); - vs1_0 = vs1; - } - - /* Manually unrolled this loop by 2 for an decent amount of ILP */ - while (k >= 64) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 64 vs1 + sum( (64-i+1) c[i] ) - */ - vbuf0 = _mm256_loadu_si256((__m256i*)src); - vbuf1 = _mm256_loadu_si256((__m256i*)(src + 32)); - _mm256_storeu_si256((__m256i*)dst, vbuf0); - _mm256_storeu_si256((__m256i*)(dst + 32), vbuf1); - dst += 64; - src += 64; - k -= 64; - - __m256i vs1_sad = _mm256_sad_epu8(vbuf0, zero); - vs1 = _mm256_add_epi32(vs1, vs1_sad); - vs3 = _mm256_add_epi32(vs3, vs1_0); - /* multiply-add, resulting in 16 ints. Fuse with sum stage from prior versions, as we now have the dp - * instructions to eliminate them */ - vs2 = _mm256_dpbusd_epi32(vs2, vbuf0, dot2v); - - vs3 = _mm256_add_epi32(vs3, vs1); - vs1_sad = _mm256_sad_epu8(vbuf1, zero); - vs1 = _mm256_add_epi32(vs1, vs1_sad); - vs2_1 = _mm256_dpbusd_epi32(vs2_1, vbuf1, dot2v); - vs1_0 = vs1; - } - - vs3 = _mm256_slli_epi32(vs3, 5); - vs2 = _mm256_add_epi32(vs2, vs3); - vs2 = _mm256_add_epi32(vs2, vs2_1); - - adler0 = partial_hsum256(vs1) % BASE; - adler1 = hsum256(vs2) % BASE; - } - - adler = adler0 | (adler1 << 16); - - /* Process tail (len < 64). */ - if (len) { - goto rem_peel_copy; - } - - return adler; -} - -#endif diff --git a/modules/zlib/src/arch/x86/adler32_sse42.c b/modules/zlib/src/arch/x86/adler32_sse42.c deleted file mode 100644 index c2301213f0..0000000000 --- a/modules/zlib/src/arch/x86/adler32_sse42.c +++ /dev/null @@ -1,117 +0,0 @@ -/* adler32_sse42.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011 Mark Adler - * Authors: - * Adam Stylinski - * Brian Bockelman - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_SSE42 - -#include "zbuild.h" -#include "adler32_p.h" -#include "adler32_ssse3_p.h" - -#include - -Z_INTERNAL uint32_t adler32_copy_sse42(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - uint32_t adler0, adler1; - adler1 = (adler >> 16) & 0xffff; - adler0 = adler & 0xffff; - -rem_peel: - if (UNLIKELY(len < 16)) - return adler32_copy_tail(adler0, dst, src, len, adler1, 1, 15, 1); - - __m128i vbuf, vbuf_0; - __m128i vs1_0, vs3, vs1, vs2, vs2_0, v_sad_sum1, v_short_sum2, v_short_sum2_0, - v_sad_sum2, vsum2, vsum2_0; - __m128i zero = _mm_setzero_si128(); - const __m128i dot2v = _mm_setr_epi8(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17); - const __m128i dot2v_0 = _mm_setr_epi8(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); - const __m128i dot3v = _mm_set1_epi16(1); - - while (len >= 16) { - size_t k = ALIGN_DOWN(MIN(len, NMAX), 16); - len -= k; - - vs1 = _mm_cvtsi32_si128(adler0); - vs2 = _mm_cvtsi32_si128(adler1); - - vs3 = _mm_setzero_si128(); - vs2_0 = _mm_setzero_si128(); - vs1_0 = vs1; - - while (k >= 32) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) - */ - vbuf = _mm_loadu_si128((__m128i*)src); - vbuf_0 = _mm_loadu_si128((__m128i*)(src + 16)); - src += 32; - k -= 32; - - v_sad_sum1 = _mm_sad_epu8(vbuf, zero); - v_sad_sum2 = _mm_sad_epu8(vbuf_0, zero); - _mm_storeu_si128((__m128i*)dst, vbuf); - _mm_storeu_si128((__m128i*)(dst + 16), vbuf_0); - dst += 32; - - v_short_sum2 = _mm_maddubs_epi16(vbuf, dot2v); - v_short_sum2_0 = _mm_maddubs_epi16(vbuf_0, dot2v_0); - - vs1 = _mm_add_epi32(v_sad_sum1, vs1); - vs3 = _mm_add_epi32(vs1_0, vs3); - - vsum2 = _mm_madd_epi16(v_short_sum2, dot3v); - vsum2_0 = _mm_madd_epi16(v_short_sum2_0, dot3v); - vs1 = _mm_add_epi32(v_sad_sum2, vs1); - vs2 = _mm_add_epi32(vsum2, vs2); - vs2_0 = _mm_add_epi32(vsum2_0, vs2_0); - vs1_0 = vs1; - } - - vs2 = _mm_add_epi32(vs2_0, vs2); - vs3 = _mm_slli_epi32(vs3, 5); - vs2 = _mm_add_epi32(vs3, vs2); - vs3 = _mm_setzero_si128(); - - while (k >= 16) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) - */ - vbuf = _mm_loadu_si128((__m128i*)src); - src += 16; - k -= 16; - - v_sad_sum1 = _mm_sad_epu8(vbuf, zero); - v_short_sum2 = _mm_maddubs_epi16(vbuf, dot2v_0); - - vs1 = _mm_add_epi32(v_sad_sum1, vs1); - vs3 = _mm_add_epi32(vs1_0, vs3); - vsum2 = _mm_madd_epi16(v_short_sum2, dot3v); - vs2 = _mm_add_epi32(vsum2, vs2); - vs1_0 = vs1; - - _mm_storeu_si128((__m128i*)dst, vbuf); - dst += 16; - } - - vs3 = _mm_slli_epi32(vs3, 4); - vs2 = _mm_add_epi32(vs2, vs3); - - adler0 = partial_hsum(vs1) % BASE; - adler1 = hsum(vs2) % BASE; - } - - /* If this is true, there's fewer than 16 elements remaining */ - if (len) { - goto rem_peel; - } - - return adler0 | (adler1 << 16); -} - -#endif diff --git a/modules/zlib/src/arch/x86/adler32_ssse3.c b/modules/zlib/src/arch/x86/adler32_ssse3.c deleted file mode 100644 index 702db50251..0000000000 --- a/modules/zlib/src/arch/x86/adler32_ssse3.c +++ /dev/null @@ -1,149 +0,0 @@ -/* adler32_ssse3.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011 Mark Adler - * Authors: - * Adam Stylinski - * Brian Bockelman - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_SSSE3 - -#include "zbuild.h" -#include "adler32_p.h" -#include "adler32_ssse3_p.h" - -#include - -Z_INTERNAL uint32_t adler32_ssse3(uint32_t adler, const uint8_t *buf, size_t len) { - /* split Adler-32 into component sums */ - uint32_t sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (UNLIKELY(len == 1)) - return adler32_copy_tail(adler, NULL, buf, 1, sum2, 1, 1, 0); - - /* in case short lengths are provided, keep it somewhat fast */ - if (UNLIKELY(len < 16)) - return adler32_copy_tail(adler, NULL, buf, len, sum2, 1, 15, 0); - - const __m128i dot2v = _mm_setr_epi8(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17); - const __m128i dot2v_0 = _mm_setr_epi8(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); - const __m128i dot3v = _mm_set1_epi16(1); - const __m128i zero = _mm_setzero_si128(); - - __m128i vbuf, vs1_0, vs3, vs1, vs2, vs2_0, v_sad_sum1, v_short_sum2, v_short_sum2_0, - vbuf_0, v_sad_sum2, vsum2, vsum2_0; - - /* If our buffer is unaligned (likely), make the determination whether - * or not there's enough of a buffer to consume to make the scalar, aligning - * additions worthwhile or if it's worth it to just eat the cost of an unaligned - * load. This is a pretty simple test, just test if len < 32 */ - size_t n = NMAX; - size_t k = 0; - - if (len < 32) { - /* Let's eat the cost of this one unaligned load so that - * we don't completely skip over the vectorization. Doing - * 16 bytes at a time unaligned is better than 16 + <= 15 - * sums */ - vbuf = _mm_loadu_si128((__m128i*)buf); - len -= 16; - buf += 16; - vs1 = _mm_cvtsi32_si128(adler); - vs2 = _mm_cvtsi32_si128(sum2); - vs3 = _mm_setzero_si128(); - vs1_0 = vs1; - goto unaligned_jmp; - } - - size_t align_diff = MIN(ALIGN_DIFF(buf, 16), len); - if (align_diff) { - adler32_copy_align(&adler, NULL, buf, align_diff, &sum2, 15, 0); - - buf += align_diff; - len -= align_diff; - n -= align_diff; - } - - while (len >= 16) { - vs1 = _mm_cvtsi32_si128(adler); - vs2 = _mm_cvtsi32_si128(sum2); - vs3 = _mm_setzero_si128(); - vs2_0 = _mm_setzero_si128(); - vs1_0 = vs1; - - k = ALIGN_DOWN(MIN(len, n), 16); - len -= k; - - while (k >= 32) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) - */ - vbuf = _mm_load_si128((__m128i*)buf); - vbuf_0 = _mm_load_si128((__m128i*)(buf + 16)); - buf += 32; - k -= 32; - - v_sad_sum1 = _mm_sad_epu8(vbuf, zero); - v_sad_sum2 = _mm_sad_epu8(vbuf_0, zero); - vs1 = _mm_add_epi32(v_sad_sum1, vs1); - vs3 = _mm_add_epi32(vs1_0, vs3); - - vs1 = _mm_add_epi32(v_sad_sum2, vs1); - v_short_sum2 = _mm_maddubs_epi16(vbuf, dot2v); - vsum2 = _mm_madd_epi16(v_short_sum2, dot3v); - v_short_sum2_0 = _mm_maddubs_epi16(vbuf_0, dot2v_0); - vs2 = _mm_add_epi32(vsum2, vs2); - vsum2_0 = _mm_madd_epi16(v_short_sum2_0, dot3v); - vs2_0 = _mm_add_epi32(vsum2_0, vs2_0); - vs1_0 = vs1; - } - - vs2 = _mm_add_epi32(vs2_0, vs2); - vs3 = _mm_slli_epi32(vs3, 5); - vs2 = _mm_add_epi32(vs3, vs2); - vs3 = _mm_setzero_si128(); - - while (k >= 16) { - /* - vs1 = adler + sum(c[i]) - vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] ) - */ - vbuf = _mm_load_si128((__m128i*)buf); - buf += 16; - k -= 16; - -unaligned_jmp: - v_sad_sum1 = _mm_sad_epu8(vbuf, zero); - vs1 = _mm_add_epi32(v_sad_sum1, vs1); - vs3 = _mm_add_epi32(vs1_0, vs3); - v_short_sum2 = _mm_maddubs_epi16(vbuf, dot2v_0); - vsum2 = _mm_madd_epi16(v_short_sum2, dot3v); - vs2 = _mm_add_epi32(vsum2, vs2); - vs1_0 = vs1; - } - - vs3 = _mm_slli_epi32(vs3, 4); - vs2 = _mm_add_epi32(vs2, vs3); - - /* We don't actually need to do a full horizontal sum, since psadbw is actually doing - * a partial reduction sum implicitly and only summing to integers in vector positions - * 0 and 2. This saves us some contention on the shuffle port(s) */ - adler = partial_hsum(vs1) % BASE; - sum2 = hsum(vs2) % BASE; - n = NMAX; - } - - /* Process tail (len < 16). */ - return adler32_copy_tail(adler, NULL, buf, len, sum2, len != 0, 15, 0); -} - -/* SSSE3 unaligned stores have a huge penalty, so we use memcpy. */ -Z_INTERNAL uint32_t adler32_copy_ssse3(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) { - adler = adler32_ssse3(adler, src, len); - memcpy(dst, src, len); - return adler; -} -#endif diff --git a/modules/zlib/src/arch/x86/adler32_ssse3_p.h b/modules/zlib/src/arch/x86/adler32_ssse3_p.h deleted file mode 100644 index d7ec3fe0d5..0000000000 --- a/modules/zlib/src/arch/x86/adler32_ssse3_p.h +++ /dev/null @@ -1,29 +0,0 @@ -/* adler32_ssse3_p.h -- adler32 ssse3 utility functions - * Copyright (C) 2022 Adam Stylinski - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ADLER32_SSSE3_P_H_ -#define ADLER32_SSSE3_P_H_ - -#ifdef X86_SSSE3 - -#include -#include - -static inline uint32_t partial_hsum(__m128i x) { - __m128i second_int = _mm_srli_si128(x, 8); - __m128i sum = _mm_add_epi32(x, second_int); - return _mm_cvtsi128_si32(sum); -} - -static inline uint32_t hsum(__m128i x) { - __m128i sum1 = _mm_unpackhi_epi64(x, x); - __m128i sum2 = _mm_add_epi32(x, sum1); - __m128i sum3 = _mm_shuffle_epi32(sum2, 0x01); - __m128i sum4 = _mm_add_epi32(sum2, sum3); - return _mm_cvtsi128_si32(sum4); -} -#endif - -#endif diff --git a/modules/zlib/src/arch/x86/chunkset_avx2.c b/modules/zlib/src/arch/x86/chunkset_avx2.c deleted file mode 100644 index 7e9cd188ef..0000000000 --- a/modules/zlib/src/arch/x86/chunkset_avx2.c +++ /dev/null @@ -1,129 +0,0 @@ -/* chunkset_avx2.c -- AVX2 inline functions to copy small data chunks. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_AVX2 - -#include "zbuild.h" -#include "zsanitizer.h" -#include "zmemory.h" - -#include "arch/shared/chunk_256bit_perm_idx_lut.h" -#include -#include "x86_intrins.h" - -typedef __m256i chunk_t; -typedef __m128i halfchunk_t; - -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 -#define HAVE_CHUNKMEMSET_16 -#define HAVE_CHUNK_MAG -#define HAVE_HALF_CHUNK - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - *chunk = _mm256_set1_epi16(zng_memread_2(from)); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - *chunk = _mm256_set1_epi32(zng_memread_4(from)); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = _mm256_set1_epi64x(zng_memread_8(from)); -} - -static inline void chunkmemset_16(uint8_t *from, chunk_t *chunk) { - /* See explanation in chunkset_avx512.c */ -#if defined(_MSC_VER) && _MSC_VER <= 1900 - halfchunk_t half = _mm_loadu_si128((__m128i*)from); - *chunk = _mm256_inserti128_si256(_mm256_castsi128_si256(half), half, 1); -#else - *chunk = _mm256_broadcastsi128_si256(_mm_loadu_si128((__m128i*)from)); -#endif -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = _mm256_loadu_si256((__m256i *)s); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - _mm256_storeu_si256((__m256i *)out, *chunk); -} - -static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - __m256i ret_vec; - /* While technically we only need to read 4 or 8 bytes into this vector register for a lot of cases, GCC is - * compiling this to a shared load for all branches, preferring the simpler code. Given that the buf value isn't in - * GPRs to begin with the 256 bit load is _probably_ just as inexpensive */ - *chunk_rem = lut_rem.remval; - - /* See note in chunkset_ssse3.c for why this is ok */ - __msan_unpoison(buf + dist, 32 - dist); - - if (dist < 16) { - /* This simpler case still requires us to shuffle in 128 bit lanes, so we must apply a static offset after - * broadcasting the first vector register to both halves. This is _marginally_ faster than doing two separate - * shuffles and combining the halves later */ - __m256i perm_vec = _mm256_load_si256((__m256i*)(permute_table+lut_rem.idx)); - __m128i ret_vec0 = _mm_loadu_si128((__m128i*)buf); - ret_vec = _mm256_inserti128_si256(_mm256_castsi128_si256(ret_vec0), ret_vec0, 1); - ret_vec = _mm256_shuffle_epi8(ret_vec, perm_vec); - } else { - __m128i ret_vec0 = _mm_loadu_si128((__m128i*)buf); - __m128i ret_vec1 = _mm_loadu_si128((__m128i*)(buf + 16)); - /* Take advantage of the fact that only the latter half of the 256 bit vector will actually differ */ - __m128i perm_vec1 = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); - __m128i xlane_permutes = _mm_cmpgt_epi8(_mm_set1_epi8(16), perm_vec1); - __m128i xlane_res = _mm_shuffle_epi8(ret_vec0, perm_vec1); - /* Since we can't wrap twice, we can simply keep the later half exactly how it is instead of having to _also_ - * shuffle those values */ - __m128i latter_half = _mm_blendv_epi8(ret_vec1, xlane_res, xlane_permutes); - ret_vec = _mm256_inserti128_si256(_mm256_castsi128_si256(ret_vec0), latter_half, 1); - } - - return ret_vec; -} - -static inline void loadhalfchunk(uint8_t const *s, halfchunk_t *chunk) { - *chunk = _mm_loadu_si128((__m128i *)s); -} - -static inline void storehalfchunk(uint8_t *out, halfchunk_t *chunk) { - _mm_storeu_si128((__m128i *)out, *chunk); -} - -static inline chunk_t halfchunk2whole(halfchunk_t *chunk) { - /* We zero extend mostly to appease some memory sanitizers. These bytes are ultimately - * unlikely to be actually written or read from */ - return _mm256_zextsi128_si256(*chunk); -} - -static inline halfchunk_t GET_HALFCHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - __m128i perm_vec, ret_vec; - __msan_unpoison(buf + dist, 16 - dist); - ret_vec = _mm_loadu_si128((__m128i*)buf); - *chunk_rem = half_rem_vals[dist - 3]; - - perm_vec = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); - ret_vec = _mm_shuffle_epi8(ret_vec, perm_vec); - - return ret_vec; -} - -#define CHUNKSIZE chunksize_avx2 -#define CHUNKCOPY chunkcopy_avx2 -#define CHUNKUNROLL chunkunroll_avx2 -#define CHUNKMEMSET chunkmemset_avx2 -#define CHUNKMEMSET_SAFE chunkmemset_safe_avx2 - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_avx2 - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/x86/chunkset_avx512.c b/modules/zlib/src/arch/x86/chunkset_avx512.c deleted file mode 100644 index fcefd0765b..0000000000 --- a/modules/zlib/src/arch/x86/chunkset_avx512.c +++ /dev/null @@ -1,186 +0,0 @@ -/* chunkset_avx512.c -- AVX512 inline functions to copy small data chunks. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_AVX512 - -#include "zbuild.h" -#include "zmemory.h" - -#include "arch/shared/chunk_256bit_perm_idx_lut.h" -#include -#include "x86_intrins.h" - -typedef __m256i chunk_t; -typedef __m128i halfchunk_t; -typedef __mmask32 mask_t; -typedef __mmask16 halfmask_t; - -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 -#define HAVE_CHUNKMEMSET_16 -#define HAVE_CHUNK_MAG -#define HAVE_HALF_CHUNK -#define HAVE_MASKED_READWRITE -#define HAVE_CHUNKCOPY -#define HAVE_HALFCHUNKCOPY - -static inline halfmask_t gen_half_mask(size_t len) { - return (halfmask_t)_bzhi_u32(0xFFFF, (unsigned)len); -} - -static inline mask_t gen_mask(size_t len) { - return (mask_t)_bzhi_u32(0xFFFFFFFF, (unsigned)len); -} - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - *chunk = _mm256_set1_epi16(zng_memread_2(from)); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - *chunk = _mm256_set1_epi32(zng_memread_4(from)); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = _mm256_set1_epi64x(zng_memread_8(from)); -} - -static inline void chunkmemset_16(uint8_t *from, chunk_t *chunk) { - /* Unfortunately there seems to be a compiler bug in Visual Studio 2015 where - * the load is dumped to the stack with an aligned move for this memory-register - * broadcast. The vbroadcasti128 instruction is 2 fewer cycles and this dump to - * stack doesn't exist if compiled with optimizations. For the sake of working - * properly in a debugger, let's take the 2 cycle penalty */ -#if defined(_MSC_VER) && _MSC_VER <= 1900 - halfchunk_t half = _mm_loadu_si128((__m128i*)from); - *chunk = _mm256_inserti128_si256(_mm256_castsi128_si256(half), half, 1); -#else - *chunk = _mm256_broadcastsi128_si256(_mm_loadu_si128((__m128i*)from)); -#endif -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = _mm256_loadu_si256((__m256i *)s); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - _mm256_storeu_si256((__m256i *)out, *chunk); -} - -static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, size_t len) { - Assert(len > 0, "chunkcopy should never have a length 0"); - - chunk_t chunk; - size_t rem = len % sizeof(chunk_t); - - if (len < sizeof(chunk_t)) { - mask_t rem_mask = gen_mask(rem); - chunk = _mm256_maskz_loadu_epi8(rem_mask, from); - _mm256_mask_storeu_epi8(out, rem_mask, chunk); - return out + rem; - } - - loadchunk(from, &chunk); - rem = (rem == 0) ? sizeof(chunk_t) : rem; - storechunk(out, &chunk); - out += rem; - from += rem; - len -= rem; - - while (len > 0) { - loadchunk(from, &chunk); - storechunk(out, &chunk); - out += sizeof(chunk_t); - from += sizeof(chunk_t); - len -= sizeof(chunk_t); - } - - return out; -} - -/* MSVC compiler decompression bug when optimizing for size */ -#if defined(_MSC_VER) && _MSC_VER < 1943 -# pragma optimize("", off) -#endif -static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - __m256i ret_vec; - *chunk_rem = lut_rem.remval; - - /* See the AVX2 implementation for more detailed comments. This is that + some masked - * loads to avoid an out of bounds read on the heap */ - - if (dist < 16) { - __m256i perm_vec = _mm256_load_si256((__m256i*)(permute_table+lut_rem.idx)); - halfmask_t load_mask = gen_half_mask(dist); - __m128i ret_vec0 = _mm_maskz_loadu_epi8(load_mask, buf); - ret_vec = _mm256_inserti128_si256(_mm256_castsi128_si256(ret_vec0), ret_vec0, 1); - ret_vec = _mm256_shuffle_epi8(ret_vec, perm_vec); - } else { - halfmask_t load_mask = gen_half_mask(dist - 16); - __m128i ret_vec0 = _mm_loadu_si128((__m128i*)buf); - __m128i ret_vec1 = _mm_maskz_loadu_epi8(load_mask, (__m128i*)(buf + 16)); - __m128i perm_vec1 = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); - halfmask_t xlane_mask = _mm_cmp_epi8_mask(perm_vec1, _mm_set1_epi8(15), _MM_CMPINT_LE); - __m128i latter_half = _mm_mask_shuffle_epi8(ret_vec1, xlane_mask, ret_vec0, perm_vec1); - ret_vec = _mm256_inserti128_si256(_mm256_castsi128_si256(ret_vec0), latter_half, 1); - } - - return ret_vec; -} -#if defined(_MSC_VER) && _MSC_VER < 1943 -# pragma optimize("", on) -#endif - -static inline void storehalfchunk(uint8_t *out, halfchunk_t *chunk) { - _mm_storeu_si128((__m128i *)out, *chunk); -} - -static inline chunk_t halfchunk2whole(halfchunk_t *chunk) { - /* We zero extend mostly to appease some memory sanitizers. These bytes are ultimately - * unlikely to be actually written or read from */ - return _mm256_zextsi128_si256(*chunk); -} - -static inline halfchunk_t GET_HALFCHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - __m128i perm_vec, ret_vec; - halfmask_t load_mask = gen_half_mask(dist); - ret_vec = _mm_maskz_loadu_epi8(load_mask, buf); - *chunk_rem = half_rem_vals[dist - 3]; - - perm_vec = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); - ret_vec = _mm_shuffle_epi8(ret_vec, perm_vec); - - return ret_vec; -} - -static inline uint8_t* HALFCHUNKCOPY(uint8_t *out, uint8_t const *from, size_t len) { - Assert(len > 0, "chunkcopy should never have a length 0"); - halfchunk_t chunk; - - size_t rem = len % sizeof(halfchunk_t); - if (rem == 0) { - rem = sizeof(halfchunk_t); - } - - halfmask_t rem_mask = gen_half_mask(rem); - chunk = _mm_maskz_loadu_epi8(rem_mask, from); - _mm_mask_storeu_epi8(out, rem_mask, chunk); - - return out + rem; -} - -#define CHUNKSIZE chunksize_avx512 -#define CHUNKUNROLL chunkunroll_avx512 -#define CHUNKMEMSET chunkmemset_avx512 -#define CHUNKMEMSET_SAFE chunkmemset_safe_avx512 - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_avx512 - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/x86/chunkset_sse2.c b/modules/zlib/src/arch/x86/chunkset_sse2.c deleted file mode 100644 index 633ab6e64f..0000000000 --- a/modules/zlib/src/arch/x86/chunkset_sse2.c +++ /dev/null @@ -1,50 +0,0 @@ -/* chunkset_sse2.c -- SSE2 inline functions to copy small data chunks. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_SSE2 - -#include "zbuild.h" -#include "zmemory.h" - -#include - -typedef __m128i chunk_t; - -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - *chunk = _mm_set1_epi16(zng_memread_2(from)); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - *chunk = _mm_set1_epi32(zng_memread_4(from)); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = _mm_set1_epi64x(zng_memread_8(from)); -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = _mm_loadu_si128((__m128i *)s); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - _mm_storeu_si128((__m128i *)out, *chunk); -} - -#define CHUNKSIZE chunksize_sse2 -#define CHUNKCOPY chunkcopy_sse2 -#define CHUNKUNROLL chunkunroll_sse2 -#define CHUNKMEMSET chunkmemset_sse2 -#define CHUNKMEMSET_SAFE chunkmemset_safe_sse2 - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_sse2 - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/x86/chunkset_ssse3.c b/modules/zlib/src/arch/x86/chunkset_ssse3.c deleted file mode 100644 index 5939411e90..0000000000 --- a/modules/zlib/src/arch/x86/chunkset_ssse3.c +++ /dev/null @@ -1,72 +0,0 @@ -/* chunkset_ssse3.c -- SSSE3 inline functions to copy small data chunks. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_SSSE3 - -#include "zbuild.h" -#include "zsanitizer.h" -#include "zmemory.h" - -#include -#include "arch/shared/chunk_128bit_perm_idx_lut.h" - -typedef __m128i chunk_t; - -#define HAVE_CHUNKMEMSET_2 -#define HAVE_CHUNKMEMSET_4 -#define HAVE_CHUNKMEMSET_8 -#define HAVE_CHUNK_MAG - - -static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) { - *chunk = _mm_set1_epi16(zng_memread_2(from)); -} - -static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) { - *chunk = _mm_set1_epi32(zng_memread_4(from)); -} - -static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) { - *chunk = _mm_set1_epi64x(zng_memread_8(from)); -} - -static inline void loadchunk(uint8_t const *s, chunk_t *chunk) { - *chunk = _mm_loadu_si128((__m128i *)s); -} - -static inline void storechunk(uint8_t *out, chunk_t *chunk) { - _mm_storeu_si128((__m128i *)out, *chunk); -} - -static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - lut_rem_pair lut_rem = perm_idx_lut[dist - 3]; - __m128i perm_vec, ret_vec; - /* Important to note: - * This is _not_ to subvert the memory sanitizer but to instead unpoison some - * bytes we willingly and purposefully load uninitialized that we swizzle over - * in a vector register, anyway. If what we assume is wrong about what is used, - * the memory sanitizer will still usefully flag it */ - __msan_unpoison(buf + dist, 16 - dist); - ret_vec = _mm_loadu_si128((__m128i*)buf); - *chunk_rem = lut_rem.remval; - - perm_vec = _mm_load_si128((__m128i*)(permute_table + lut_rem.idx)); - ret_vec = _mm_shuffle_epi8(ret_vec, perm_vec); - - return ret_vec; -} - -#define CHUNKSIZE chunksize_ssse3 -#define CHUNKMEMSET chunkmemset_ssse3 -#define CHUNKMEMSET_SAFE chunkmemset_safe_ssse3 -#define CHUNKCOPY chunkcopy_ssse3 -#define CHUNKUNROLL chunkunroll_ssse3 - -#include "chunkset_tpl.h" - -#define INFLATE_FAST inflate_fast_ssse3 - -#include "inffast_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/x86/compare256_avx2.c b/modules/zlib/src/arch/x86/compare256_avx2.c deleted file mode 100644 index 8ae9a49f4b..0000000000 --- a/modules/zlib/src/arch/x86/compare256_avx2.c +++ /dev/null @@ -1,61 +0,0 @@ -/* compare256_avx2.c -- AVX2 version of compare256 - * Copyright Mika T. Lindqvist - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zendian.h" -#include "zmemory.h" -#include "deflate.h" -#include "fallback_builtins.h" - -#ifdef X86_AVX2 - -#include -#ifdef _MSC_VER -# include -#endif - -static inline uint32_t compare256_avx2_static(const uint8_t *src0, const uint8_t *src1) { - uint32_t len = 0; - - do { - __m256i ymm_src0, ymm_src1, ymm_cmp; - ymm_src0 = _mm256_loadu_si256((__m256i*)src0); - ymm_src1 = _mm256_loadu_si256((__m256i*)src1); - ymm_cmp = _mm256_cmpeq_epi8(ymm_src0, ymm_src1); /* non-identical bytes = 00, identical bytes = FF */ - unsigned mask = (unsigned)_mm256_movemask_epi8(ymm_cmp); - if (mask != 0xFFFFFFFF) - return len + zng_ctz32(~mask); /* Invert bits so identical = 0 */ - - src0 += 32, src1 += 32, len += 32; - - ymm_src0 = _mm256_loadu_si256((__m256i*)src0); - ymm_src1 = _mm256_loadu_si256((__m256i*)src1); - ymm_cmp = _mm256_cmpeq_epi8(ymm_src0, ymm_src1); - mask = (unsigned)_mm256_movemask_epi8(ymm_cmp); - if (mask != 0xFFFFFFFF) - return len + zng_ctz32(~mask); - - src0 += 32, src1 += 32, len += 32; - } while (len < 256); - - return 256; -} - -Z_INTERNAL uint32_t compare256_avx2(const uint8_t *src0, const uint8_t *src1) { - return compare256_avx2_static(src0, src1); -} - -#define LONGEST_MATCH longest_match_avx2 -#define COMPARE256 compare256_avx2_static - -#include "match_tpl.h" - -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_avx2 -#define COMPARE256 compare256_avx2_static - -#include "match_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/x86/compare256_avx512.c b/modules/zlib/src/arch/x86/compare256_avx512.c deleted file mode 100644 index 94039106e3..0000000000 --- a/modules/zlib/src/arch/x86/compare256_avx512.c +++ /dev/null @@ -1,87 +0,0 @@ -/* compare256_avx512.c -- AVX512 version of compare256 - * Copyright (C) 2025 Hans Kristian Rosbach - * Based on AVX2 implementation by Mika T. Lindqvist - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zendian.h" -#include "zmemory.h" -#include "deflate.h" -#include "fallback_builtins.h" - -#ifdef X86_AVX512 - -#include -#ifdef _MSC_VER -# include -#endif - -static inline uint32_t compare256_avx512_static(const uint8_t *src0, const uint8_t *src1) { - __m512i zmm_src0_4, zmm_src1_4; - __m512i zmm_src0_3, zmm_src1_3; - __m512i zmm_src0_2, zmm_src1_2; - __m512i zmm_src0_1, zmm_src1_1; - __m128i xmm_src0_0, xmm_src1_0; - uint64_t mask_1, mask_2, mask_3, mask_4; - uint32_t mask_0; - - // First do a 16byte round before increasing to 64bytes, this reduces the - // penalty for the short matches, and those are usually the most common ones. - // This requires us to overlap on the last round, giving a small penalty - // on matches of 192+ bytes (Still faster than AVX2 though). - - // 16 bytes - xmm_src0_0 = _mm_loadu_si128((__m128i*)src0); - xmm_src1_0 = _mm_loadu_si128((__m128i*)src1); - mask_0 = (uint32_t)_mm_cmpeq_epu8_mask(xmm_src0_0, xmm_src1_0); - if (mask_0 != 0x0000FFFF) - return zng_ctz32(~mask_0); /* Invert bits so identical = 0 */ - - // 64 bytes - zmm_src0_1 = _mm512_loadu_si512((__m512i*)(src0 + 16)); - zmm_src1_1 = _mm512_loadu_si512((__m512i*)(src1 + 16)); - mask_1 = _mm512_cmpeq_epu8_mask(zmm_src0_1, zmm_src1_1); - if (mask_1 != 0xFFFFFFFFFFFFFFFF) - return 16 + zng_ctz64(~mask_1); - - // 64 bytes - zmm_src0_2 = _mm512_loadu_si512((__m512i*)(src0 + 80)); - zmm_src1_2 = _mm512_loadu_si512((__m512i*)(src1 + 80)); - mask_2 = _mm512_cmpeq_epu8_mask(zmm_src0_2, zmm_src1_2); - if (mask_2 != 0xFFFFFFFFFFFFFFFF) - return 80 + zng_ctz64(~mask_2); - - // 64 bytes - zmm_src0_3 = _mm512_loadu_si512((__m512i*)(src0 + 144)); - zmm_src1_3 = _mm512_loadu_si512((__m512i*)(src1 + 144)); - mask_3 = _mm512_cmpeq_epu8_mask(zmm_src0_3, zmm_src1_3); - if (mask_3 != 0xFFFFFFFFFFFFFFFF) - return 144 + zng_ctz64(~mask_3); - - // 64 bytes (overlaps the previous 16 bytes for fast tail processing) - zmm_src0_4 = _mm512_loadu_si512((__m512i*)(src0 + 192)); - zmm_src1_4 = _mm512_loadu_si512((__m512i*)(src1 + 192)); - mask_4 = _mm512_cmpeq_epu8_mask(zmm_src0_4, zmm_src1_4); - if (mask_4 != 0xFFFFFFFFFFFFFFFF) - return 192 + zng_ctz64(~mask_4); - - return 256; -} - -Z_INTERNAL uint32_t compare256_avx512(const uint8_t *src0, const uint8_t *src1) { - return compare256_avx512_static(src0, src1); -} - -#define LONGEST_MATCH longest_match_avx512 -#define COMPARE256 compare256_avx512_static - -#include "match_tpl.h" - -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_avx512 -#define COMPARE256 compare256_avx512_static - -#include "match_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/x86/compare256_sse2.c b/modules/zlib/src/arch/x86/compare256_sse2.c deleted file mode 100644 index fa097f27dc..0000000000 --- a/modules/zlib/src/arch/x86/compare256_sse2.c +++ /dev/null @@ -1,86 +0,0 @@ -/* compare256_sse2.c -- SSE2 version of compare256 - * Copyright Adam Stylinski - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zendian.h" -#include "zmemory.h" -#include "deflate.h" -#include "fallback_builtins.h" - -#ifdef X86_SSE2 - -#include - -static inline uint32_t compare256_sse2_static(const uint8_t *src0, const uint8_t *src1) { - __m128i xmm_src0, xmm_src1, xmm_cmp; - - /* Do the first load unaligned, than all subsequent ones we have at least - * one aligned load. Sadly aligning both loads is probably unrealistic */ - xmm_src0 = _mm_loadu_si128((__m128i*)src0); - xmm_src1 = _mm_loadu_si128((__m128i*)src1); - xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1); - - unsigned mask = (unsigned)_mm_movemask_epi8(xmm_cmp); - - /* Compiler _may_ turn this branch into a ptest + movemask, - * since a lot of those uops are shared and fused */ - if (mask != 0xFFFF) - return zng_ctz32(~mask); - - const uint8_t *last0 = src0 + 240; - const uint8_t *last1 = src1 + 240; - - int align_offset = ((uintptr_t)src0) & 15; - int align_adv = 16 - align_offset; - uint32_t len = align_adv; - - src0 += align_adv; - src1 += align_adv; - - for (int i = 0; i < 15; ++i) { - xmm_src0 = _mm_load_si128((__m128i*)src0); - xmm_src1 = _mm_loadu_si128((__m128i*)src1); - xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1); - - mask = (unsigned)_mm_movemask_epi8(xmm_cmp); - - /* Compiler _may_ turn this branch into a ptest + movemask, - * since a lot of those uops are shared and fused */ - if (mask != 0xFFFF) - return len + zng_ctz32(~mask); - - len += 16, src0 += 16, src1 += 16; - } - - if (align_offset) { - xmm_src0 = _mm_loadu_si128((__m128i*)last0); - xmm_src1 = _mm_loadu_si128((__m128i*)last1); - xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1); - - mask = (unsigned)_mm_movemask_epi8(xmm_cmp); - - if (mask != 0xFFFF) - return 240 + zng_ctz32(~mask); - } - - return 256; -} - -Z_INTERNAL uint32_t compare256_sse2(const uint8_t *src0, const uint8_t *src1) { - return compare256_sse2_static(src0, src1); -} - -#define LONGEST_MATCH longest_match_sse2 -#define COMPARE256 compare256_sse2_static - -#include "match_tpl.h" - -#define LONGEST_MATCH_ROLL -#define LONGEST_MATCH longest_match_roll_sse2 -#define COMPARE256 compare256_sse2_static - -#include "match_tpl.h" - -#endif diff --git a/modules/zlib/src/arch/x86/crc32_chorba_sse2.c b/modules/zlib/src/arch/x86/crc32_chorba_sse2.c deleted file mode 100644 index 5fbdbc6efb..0000000000 --- a/modules/zlib/src/arch/x86/crc32_chorba_sse2.c +++ /dev/null @@ -1,343 +0,0 @@ -#include "zbuild.h" -#include "arch_functions.h" - -#if defined(X86_SSE2) && !defined(WITHOUT_CHORBA_SSE) && defined(CRC32_CHORBA_FALLBACK) - -#include "crc32_chorba_p.h" -#include "crc32_braid_p.h" -#include "crc32_braid_tbl.h" -#include -#include "arch/x86/x86_intrins.h" - -#define LSHIFT_QWORD(x) _mm_unpacklo_epi64(_mm_setzero_si128(), (x)) -#define RSHIFT_QWORD(x) _mm_unpackhi_epi64((x), _mm_setzero_si128()) -#define ALIGNR_QWORD(a, b) _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(a), _mm_castsi128_pd(b), 1)) - -#define READ_NEXT(in, off, a, b) \ - do { \ - a = _mm_load_si128((__m128i*)(in + off / sizeof(uint64_t))); \ - b = _mm_load_si128((__m128i*)(in + off / sizeof(uint64_t) + 2)); \ - } while (0) - -#define NEXT_ROUND(invec, a, b, c, d) \ - do { \ - a = _mm_xor_si128(_mm_slli_epi64(invec, 17), _mm_slli_epi64(invec, 55)); \ - b = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi64(invec, 47), _mm_srli_epi64(invec, 9)), _mm_slli_epi64(invec, 19)); \ - c = _mm_xor_si128(_mm_srli_epi64(invec, 45), _mm_slli_epi64(invec, 44)); \ - d = _mm_srli_epi64(invec, 20); \ - } while (0) - -#define ACCUM_ROUND() \ - do { \ - __m128i a4_ = _mm_unpacklo_epi64(next56, ab4); \ - __m128i b2c2 = ALIGNR_QWORD(ab2, cd2); \ - __m128i b4c4 = ALIGNR_QWORD(ab4, cd4); \ - __m128i d2_ = RSHIFT_QWORD(cd2); \ - next12 = _mm_xor_si128(_mm_xor_si128(a4_, ab3), cd1); \ - next12 = _mm_xor_si128(next12, b2c2); \ - next34 = _mm_xor_si128(b4c4, cd3); \ - next34 = _mm_xor_si128(next34, d2_); \ - next56 = RSHIFT_QWORD(cd4); \ - } while (0) - -Z_INTERNAL uint32_t chorba_small_nondestructive_sse2(uint32_t crc, const uint8_t *buf, size_t len) { - /* The calling function ensured that this is aligned correctly */ - const uint64_t* input = (const uint64_t*)buf; - ALIGNED_(16) uint64_t final[9] = {0}; - uint64_t next1 = ~crc; - crc = 0; - uint64_t next2, next3, next4, next5; - - __m128i next12 = _mm_cvtsi64_si128(next1); - __m128i next34 = _mm_setzero_si128(); - __m128i next56 = _mm_setzero_si128(); - __m128i ab1, ab2, ab3, ab4, cd1, cd2, cd3, cd4; - - size_t i = 0; - - /* This is weird, doing for vs while drops 10% off the exec time */ - for (; (i + 256 + 40 + 32 + 32) < len; i += 32) { - __m128i in1in2, in3in4; - - const uint64_t *input_ptr = input + (i / sizeof(uint64_t)); - const __m128i *input_ptr_128 = (__m128i*)input_ptr; - __m128i chorba12 = _mm_load_si128(input_ptr_128++); - __m128i chorba34 = _mm_load_si128(input_ptr_128++); - __m128i chorba56 = _mm_load_si128(input_ptr_128++); - __m128i chorba78 = _mm_load_si128(input_ptr_128++); - - chorba12 = _mm_xor_si128(chorba12, next12); - chorba34 = _mm_xor_si128(chorba34, next34); - chorba56 = _mm_xor_si128(chorba56, next56); - chorba78 = _mm_xor_si128(chorba78, chorba12); - __m128i chorba45 = ALIGNR_QWORD(chorba34, chorba56); - __m128i chorba23 = ALIGNR_QWORD(chorba12, chorba34); - - i += 8 * 8; - - /* 0-3 */ - READ_NEXT(input, i, in1in2, in3in4); - - __m128i chorba34xor = _mm_xor_si128(chorba34, LSHIFT_QWORD(chorba12)); - in1in2 = _mm_xor_si128(in1in2, chorba34xor); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - in3in4 = _mm_xor_si128(in3in4, ab1); - /* _hopefully_ we don't get a huge domain switching penalty for this. This seems to be the best sequence */ - __m128i chorba56xor = _mm_xor_si128(chorba56, LSHIFT_QWORD(ab2)); - - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba56xor, chorba23)); - in3in4 = _mm_xor_si128(in3in4, chorba12); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - /* chorba56 already consumed next56, clear it so ACCUM_ROUND - does not xor the stale value into next12 */ - next56 = _mm_setzero_si128(); - ACCUM_ROUND(); - - i += 32; - - /* 4-7 */ - READ_NEXT(input, i, in1in2, in3in4); - - in1in2 = _mm_xor_si128(in1in2, next12); - in1in2 = _mm_xor_si128(in1in2, chorba78); - in1in2 = _mm_xor_si128(in1in2, chorba45); - in1in2 = _mm_xor_si128(in1in2, chorba34); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - in3in4 = _mm_xor_si128(in3in4, next34); - in3in4 = _mm_xor_si128(in3in4, ab1); - in3in4 = _mm_xor_si128(in3in4, chorba56); - __m128i chorba67 = ALIGNR_QWORD(chorba56, chorba78); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba67, LSHIFT_QWORD(ab2))); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - ACCUM_ROUND(); - - i += 32; - - /* 8-11 */ - READ_NEXT(input, i, in1in2, in3in4); - - __m128i chorba80 = RSHIFT_QWORD(chorba78); - __m128i next12_chorba12 = _mm_xor_si128(next12, chorba12); - in1in2 = _mm_xor_si128(in1in2, chorba80); - in1in2 = _mm_xor_si128(in1in2, chorba78); - in1in2 = _mm_xor_si128(in1in2, next12_chorba12); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - in3in4 = _mm_xor_si128(next34, in3in4); - in3in4 = _mm_xor_si128(in3in4, ab1); - __m128i a2_ = LSHIFT_QWORD(ab2); - in3in4 = _mm_xor_si128(in3in4, chorba34); - in3in4 = _mm_xor_si128(in3in4, a2_); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - ACCUM_ROUND(); - - i += 32; - - /* 12-15 */ - READ_NEXT(input, i, in1in2, in3in4); - - in1in2 = _mm_xor_si128(in1in2, next12); - __m128i chorb56xorchorb12 = _mm_xor_si128(chorba56, chorba12); - in1in2 = _mm_xor_si128(in1in2, chorb56xorchorb12); - __m128i chorb1_ = LSHIFT_QWORD(chorba12); - in1in2 = _mm_xor_si128(in1in2, chorb1_); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - in3in4 = _mm_xor_si128(next34, in3in4); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(ab1, chorba78)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba34, chorba12)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba23, LSHIFT_QWORD(ab2))); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - ACCUM_ROUND(); - - i += 32; - - /* 16-19 */ - READ_NEXT(input, i, in1in2, in3in4); - - __m128i chorba1_ = LSHIFT_QWORD(chorba12); - in1in2 = _mm_xor_si128(_mm_xor_si128(next12, in1in2), _mm_xor_si128(chorba56, chorba45)); - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(chorba12, chorba34)); - in1in2 = _mm_xor_si128(chorba1_, in1in2); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - a2_ = LSHIFT_QWORD(ab2); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(ab1, chorba78)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba56, chorba34)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba23, chorba67)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba1_, a2_)); - in3in4 = _mm_xor_si128(in3in4, next34); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - ACCUM_ROUND(); - - i += 32; - - /* 20-23 */ - READ_NEXT(input, i, in1in2, in3in4); - - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(next12, chorba78)); - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(chorba45, chorba56)); - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(chorba23, chorba12)); - in1in2 = _mm_xor_si128(in1in2, chorba80); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - a2_ = LSHIFT_QWORD(ab2); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(next34, ab1)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba78, chorba67)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba45, chorba34)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba1_, a2_)); - in3in4 = _mm_xor_si128(in3in4, chorba12); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - ACCUM_ROUND(); - - i += 32; - - /* 24-27 */ - READ_NEXT(input, i, in1in2, in3in4); - - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(next12, chorba67)); - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(chorba56, chorba34)); - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(chorba23, chorba12)); - in1in2 = _mm_xor_si128(in1in2, chorba80); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - a2_ = LSHIFT_QWORD(ab2); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(next34, ab1)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba78, chorba56)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba45, chorba34)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba80, a2_)); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - ACCUM_ROUND(); - - i += 32; - - /* 28-31 */ - READ_NEXT(input, i, in1in2, in3in4); - - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(next12, chorba78)); - in1in2 = _mm_xor_si128(in1in2, _mm_xor_si128(chorba67, chorba56)); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - a2_ = LSHIFT_QWORD(ab2); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(next34, ab1)); - in3in4 = _mm_xor_si128(in3in4, _mm_xor_si128(chorba78, chorba80)); - in3in4 = _mm_xor_si128(a2_, in3in4); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - ACCUM_ROUND(); - } - - for (; (i + 40 + 32) < len; i += 32) { - __m128i in1in2, in3in4; - - READ_NEXT(input, i, in1in2, in3in4); - - in1in2 = _mm_xor_si128(in1in2, next12); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - __m128i a2_ = LSHIFT_QWORD(ab2); - __m128i ab1_next34 = _mm_xor_si128(next34, ab1); - in3in4 = _mm_xor_si128(in3in4, ab1_next34); - in3in4 = _mm_xor_si128(a2_, in3in4); - - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - ACCUM_ROUND(); - } - - next1 = _mm_cvtsi128_si64(next12); - next2 = _mm_cvtsi128_si64(_mm_unpackhi_epi64(next12, next12)); - next3 = _mm_cvtsi128_si64(next34); - next4 = _mm_cvtsi128_si64(_mm_unpackhi_epi64(next34, next34)); - next5 = _mm_cvtsi128_si64(next56); - - /* Skip the call to memcpy */ - size_t copy_len = len - i; - __m128i *final128 = (__m128i*)final; - __m128i *input128 = (__m128i*)(input + (i / sizeof(uint64_t))); - while (copy_len >= 64) { - _mm_store_si128(final128++, _mm_load_si128(input128++)); - _mm_store_si128(final128++, _mm_load_si128(input128++)); - _mm_store_si128(final128++, _mm_load_si128(input128++)); - _mm_store_si128(final128++, _mm_load_si128(input128++)); - copy_len -= 64; - } - - while (copy_len >= 16) { - _mm_store_si128(final128++, _mm_load_si128(input128++)); - copy_len -= 16; - } - - uint8_t *src_bytes = (uint8_t*)input128; - uint8_t *dst_bytes = (uint8_t*)final128; - while (copy_len--) { - *dst_bytes++ = *src_bytes++; - } - - final[0] ^= next1; - final[1] ^= next2; - final[2] ^= next3; - final[3] ^= next4; - final[4] ^= next5; - - /* We perform the same loop that braid_internal is doing but we'll skip - * the function call for this tiny tail */ - uint8_t *final_bytes = (uint8_t*)final; - size_t rem = len - i; - - while (rem--) { - crc = crc_table[(crc ^ *final_bytes++) & 0xff] ^ (crc >> 8); - } - - return ~crc; -} - -Z_INTERNAL uint32_t crc32_chorba_sse2(uint32_t crc, const uint8_t *buf, size_t len) { - uintptr_t align_diff = ALIGN_DIFF(buf, 16); - if (len <= align_diff + CHORBA_SMALL_THRESHOLD_64BIT) - return crc32_braid(crc, buf, len); - - if (align_diff) { - crc = crc32_braid(crc, buf, align_diff); - len -= align_diff; - buf += align_diff; - } -#if !defined(WITHOUT_CHORBA) - if (len > CHORBA_LARGE_THRESHOLD) - return crc32_chorba_118960_nondestructive(crc, buf, len); -#endif - return chorba_small_nondestructive_sse2(crc, buf, len); -} - -Z_INTERNAL uint32_t crc32_copy_chorba_sse2(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - crc = crc32_chorba_sse2(crc, src, len); - memcpy(dst, src, len); - return crc; -} -#endif diff --git a/modules/zlib/src/arch/x86/crc32_chorba_sse41.c b/modules/zlib/src/arch/x86/crc32_chorba_sse41.c deleted file mode 100644 index d8cadc93a1..0000000000 --- a/modules/zlib/src/arch/x86/crc32_chorba_sse41.c +++ /dev/null @@ -1,339 +0,0 @@ -#include "zbuild.h" -#include "arch_functions.h" - -#if defined(X86_SSE41) && !defined(WITHOUT_CHORBA_SSE) && defined(CRC32_CHORBA_FALLBACK) - -#include "crc32_chorba_p.h" -#include "crc32_braid_p.h" -#include "crc32_braid_tbl.h" -#include -#include -#include "arch/x86/x86_intrins.h" - -#define READ_NEXT(in, off, a, b) \ - do { \ - a = _mm_load_si128((__m128i*)(in + off / sizeof(uint64_t))); \ - b = _mm_load_si128((__m128i*)(in + off / sizeof(uint64_t) + 2)); \ - } while (0) - -#define NEXT_ROUND(invec, a, b, c, d) \ - do { \ - a = _mm_xor_si128(_mm_slli_epi64(invec, 17), _mm_slli_epi64(invec, 55)); \ - b = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi64(invec, 47), _mm_srli_epi64(invec, 9)), _mm_slli_epi64(invec, 19)); \ - c = _mm_xor_si128(_mm_srli_epi64(invec, 45), _mm_slli_epi64(invec, 44)); \ - d = _mm_srli_epi64(invec, 20); \ - } while (0) - -#define REALIGN_CHORBA(in0, in1, in2, in3, out0, out1, out2, out3, out4, shift) \ - do { \ - out0 = _mm_slli_si128(in0, shift); \ - out1 = _mm_alignr_epi8(in1, in0, shift); \ - out2 = _mm_alignr_epi8(in2, in1, shift); \ - out3 = _mm_alignr_epi8(in3, in2, shift); \ - out4 = _mm_srli_si128(in3, shift); \ - } while (0) - -#define STORE4(out0, out1, out2, out3, out) \ - do { \ - _mm_store_si128(out++, out0); \ - _mm_store_si128(out++, out1); \ - _mm_store_si128(out++, out2); \ - _mm_store_si128(out++, out3); \ - } while (0) - -#define READ4(out0, out1, out2, out3, in) \ - do { \ - out0 = _mm_load_si128(in++); \ - out1 = _mm_load_si128(in++); \ - out2 = _mm_load_si128(in++); \ - out3 = _mm_load_si128(in++); \ - } while (0) - -/* This is intentionally shifted one down to compensate for the deferred store from - * the last iteration */ -#define READ4_WITHXOR(out0, out1, out2, out3, xor0, xor1, xor2, xor3, in) \ - do { \ - out0 = _mm_xor_si128(in[1], xor0); \ - out1 = _mm_xor_si128(in[2], xor1); \ - out2 = _mm_xor_si128(in[3], xor2); \ - out3 = _mm_xor_si128(in[4], xor3); \ - } while (0) - -Z_FORCEINLINE static uint32_t crc32_chorba_32768_nondestructive_sse41(uint32_t crc, const uint8_t *buf, size_t len) { - /* The calling function ensured that this is aligned correctly */ - const uint64_t* input = (const uint64_t*)buf; - ALIGNED_(16) uint64_t bitbuffer[32768 / sizeof(uint64_t)]; - __m128i *bitbuffer_v = (__m128i*)bitbuffer; - const uint8_t *bitbuffer_bytes = (const uint8_t*)bitbuffer; - __m128i z = _mm_setzero_si128(); - - __m128i *bitbuf128 = &bitbuffer_v[64]; - __m128i *bitbuf144 = &bitbuffer_v[72]; - __m128i *bitbuf182 = &bitbuffer_v[91]; - __m128i *bitbuf210 = &bitbuffer_v[105]; - __m128i *bitbuf300 = &bitbuffer_v[150]; - __m128i *bitbuf0 = bitbuf128; - __m128i *inptr = (__m128i*)input; - - /* We only need to zero out the bytes between the 128'th value and the 144th - * that are actually read */ - __m128i *z_cursor = bitbuf128; - for (size_t i = 0; i < 2; ++i) { - STORE4(z, z, z, z, z_cursor); - } - - /* We only need to zero out the bytes between the 144'th value and the 182nd that - * are actually read */ - z_cursor = bitbuf144 + 8; - for (size_t i = 0; i < 11; ++i) { - _mm_store_si128(z_cursor++, z); - } - - /* We only need to zero out the bytes between the 182nd value and the 210th that - * are actually read. */ - z_cursor = bitbuf182; - for (size_t i = 0; i < 4; ++i) { - STORE4(z, z, z, z, z_cursor); - } - - /* We need to mix this in */ - __m128i init_crc = _mm_cvtsi64_si128(~crc); - crc = 0; - - size_t i = 0; - - /* Previous iteration runs carried over */ - __m128i buf144 = z; - __m128i buf182 = z; - __m128i buf210 = z; - - for (; i + 300*8+64 < len && i < 22 * 8; i += 64) { - __m128i in12, in34, in56, in78, - in_1, in23, in45, in67, in8_; - - READ4(in12, in34, in56, in78, inptr); - - if (i == 0) { - in12 = _mm_xor_si128(in12, init_crc); - } - - REALIGN_CHORBA(in12, in34, in56, in78, - in_1, in23, in45, in67, in8_, 8); - - __m128i a = _mm_xor_si128(buf144, in_1); - - STORE4(a, in23, in45, in67, bitbuf144); - buf144 = in8_; - - __m128i e = _mm_xor_si128(buf182, in_1); - STORE4(e, in23, in45, in67, bitbuf182); - buf182 = in8_; - - __m128i m = _mm_xor_si128(buf210, in_1); - STORE4(m, in23, in45, in67, bitbuf210); - buf210 = in8_; - - STORE4(in12, in34, in56, in78, bitbuf300); - } - - for (; i + 300*8+64 < len && i < 32 * 8; i += 64) { - __m128i in12, in34, in56, in78, - in_1, in23, in45, in67, in8_; - READ4(in12, in34, in56, in78, inptr); - - REALIGN_CHORBA(in12, in34, in56, in78, - in_1, in23, in45, in67, in8_, 8); - - __m128i a = _mm_xor_si128(buf144, in_1); - - STORE4(a, in23, in45, in67, bitbuf144); - buf144 = in8_; - - __m128i e, f, g, h; - e = _mm_xor_si128(buf182, in_1); - READ4_WITHXOR(f, g, h, buf182, in23, in45, in67, in8_, bitbuf182); - STORE4(e, f, g, h, bitbuf182); - - __m128i m = _mm_xor_si128(buf210, in_1); - STORE4(m, in23, in45, in67, bitbuf210); - buf210 = in8_; - - STORE4(in12, in34, in56, in78, bitbuf300); - } - - for (; i + 300*8+64 < len && i < 84 * 8; i += 64) { - __m128i in12, in34, in56, in78, - in_1, in23, in45, in67, in8_; - READ4(in12, in34, in56, in78, inptr); - - REALIGN_CHORBA(in12, in34, in56, in78, - in_1, in23, in45, in67, in8_, 8); - - __m128i a, b, c, d; - a = _mm_xor_si128(buf144, in_1); - READ4_WITHXOR(b, c, d, buf144, in23, in45, in67, in8_, bitbuf144); - STORE4(a, b, c, d, bitbuf144); - - __m128i e, f, g, h; - e = _mm_xor_si128(buf182, in_1); - READ4_WITHXOR(f, g, h, buf182, in23, in45, in67, in8_, bitbuf182); - STORE4(e, f, g, h, bitbuf182); - - __m128i m = _mm_xor_si128(buf210, in_1); - STORE4(m, in23, in45, in67, bitbuf210); - buf210 = in8_; - - STORE4(in12, in34, in56, in78, bitbuf300); - } - - for (; i + 300*8+64 < len; i += 64) { - __m128i in12, in34, in56, in78, - in_1, in23, in45, in67, in8_; - - if (i < 128 * 8) { - READ4(in12, in34, in56, in78, inptr); - } else { - in12 = _mm_xor_si128(_mm_load_si128(inptr++), _mm_load_si128(bitbuf0++)); - in34 = _mm_xor_si128(_mm_load_si128(inptr++), _mm_load_si128(bitbuf0++)); - in56 = _mm_xor_si128(_mm_load_si128(inptr++), _mm_load_si128(bitbuf0++)); - in78 = _mm_xor_si128(_mm_load_si128(inptr++), _mm_load_si128(bitbuf0++)); - } - - // [0, 145, 183, 211] - - /* Pre Penryn CPUs the unpack should be faster */ - REALIGN_CHORBA(in12, in34, in56, in78, - in_1, in23, in45, in67, in8_, 8); - - __m128i a, b, c, d; - a = _mm_xor_si128(buf144, in_1); - READ4_WITHXOR(b, c, d, buf144, in23, in45, in67, in8_, bitbuf144); - STORE4(a, b, c, d, bitbuf144); - - __m128i e, f, g, h; - e = _mm_xor_si128(buf182, in_1); - READ4_WITHXOR(f, g, h, buf182, in23, in45, in67, in8_, bitbuf182); - STORE4(e, f, g, h, bitbuf182); - - __m128i n, o, p; - __m128i m = _mm_xor_si128(buf210, in_1); - - /* Couldn't tell you why but despite knowing that this is always false, - * removing this branch with GCC makes things significantly slower. Some - * loop bodies must be being joined or something */ - if (i < 84 * 8) { - n = in23; - o = in45; - p = in67; - buf210 = in8_; - } else { - READ4_WITHXOR(n, o, p, buf210, in23, in45, in67, in8_, bitbuf210); - } - - STORE4(m, n, o, p, bitbuf210); - STORE4(in12, in34, in56, in78, bitbuf300); - } - - /* Second half of stores bubbled out */ - _mm_store_si128(bitbuf144, buf144); - _mm_store_si128(bitbuf182, buf182); - _mm_store_si128(bitbuf210, buf210); - - /* We also have to zero out the tail */ - size_t left_to_z = len - (300*8 + i); - __m128i *bitbuf_tail = (__m128i*)(bitbuffer + 300 + i/8); - while (left_to_z >= 64) { - STORE4(z, z, z, z, bitbuf_tail); - left_to_z -= 64; - } - - while (left_to_z >= 16) { - _mm_store_si128(bitbuf_tail++, z); - left_to_z -= 16; - } - - uint8_t *tail_bytes = (uint8_t*)bitbuf_tail; - while (left_to_z--) { - *tail_bytes++ = 0; - } - - ALIGNED_(16) uint64_t final[9] = {0}; - __m128i next12, next34, next56; - next12 = z; - next34 = z; - next56 = z; - - for (; (i + 72 < len); i += 32) { - __m128i in1in2, in3in4; - __m128i in1in2_, in3in4_; - __m128i ab1, ab2, ab3, ab4; - __m128i cd1, cd2, cd3, cd4; - - READ_NEXT(input, i, in1in2, in3in4); - READ_NEXT(bitbuffer, i, in1in2_, in3in4_); - - in1in2 = _mm_xor_si128(_mm_xor_si128(in1in2, in1in2_), next12); - in3in4 = _mm_xor_si128(in3in4, in3in4_); - - NEXT_ROUND(in1in2, ab1, ab2, ab3, ab4); - - __m128i a2_ = _mm_slli_si128(ab2, 8); - __m128i ab1_next34 = _mm_xor_si128(next34, ab1); - in3in4 = _mm_xor_si128(in3in4, ab1_next34); - in3in4 = _mm_xor_si128(a2_, in3in4); - NEXT_ROUND(in3in4, cd1, cd2, cd3, cd4); - - __m128i b2c2 = _mm_alignr_epi8(cd2, ab2, 8); - __m128i a4_ = _mm_slli_si128(ab4, 8); - a4_ = _mm_xor_si128(b2c2, a4_); - next12 = _mm_xor_si128(ab3, a4_); - next12 = _mm_xor_si128(next12, cd1); - - __m128i d2_ = _mm_srli_si128(cd2, 8); - __m128i b4c4 = _mm_alignr_epi8(cd4, ab4, 8); - next12 = _mm_xor_si128(next12, next56); - next34 = _mm_xor_si128(cd3, _mm_xor_si128(b4c4, d2_)); - next56 = _mm_srli_si128(cd4, 8); - } - - memcpy(final, input+(i / sizeof(uint64_t)), len-i); - __m128i *final128 = (__m128i*)final; - _mm_store_si128(final128, _mm_xor_si128(_mm_load_si128(final128), next12)); - ++final128; - _mm_store_si128(final128, _mm_xor_si128(_mm_load_si128(final128), next34)); - ++final128; - _mm_store_si128(final128, _mm_xor_si128(_mm_load_si128(final128), next56)); - - uint8_t *final_bytes = (uint8_t*)final; - - for (size_t j = 0; j < (len-i); j++) { - crc = crc_table[(crc ^ final_bytes[j] ^ bitbuffer_bytes[(j+i)]) & 0xff] ^ (crc >> 8); - } - return ~crc; -} - -Z_INTERNAL uint32_t crc32_chorba_sse41(uint32_t crc, const uint8_t *buf, size_t len) { - uintptr_t align_diff = ALIGN_DIFF(buf, 16); - if (len <= align_diff + CHORBA_SMALL_THRESHOLD_64BIT) - return crc32_braid(crc, buf, len); - - if (align_diff) { - crc = crc32_braid(crc, buf, align_diff); - len -= align_diff; - buf += align_diff; - } -#if !defined(WITHOUT_CHORBA) - if (len > CHORBA_LARGE_THRESHOLD) - return crc32_chorba_118960_nondestructive(crc, buf, len); -#endif - if (len > CHORBA_MEDIUM_LOWER_THRESHOLD && len <= CHORBA_MEDIUM_UPPER_THRESHOLD) - return crc32_chorba_32768_nondestructive_sse41(crc, buf, len); - return chorba_small_nondestructive_sse2(crc, buf, len); -} - -Z_INTERNAL uint32_t crc32_copy_chorba_sse41(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - crc = crc32_chorba_sse41(crc, src, len); - memcpy(dst, src, len); - return crc; -} -#endif diff --git a/modules/zlib/src/arch/x86/crc32_pclmulqdq.c b/modules/zlib/src/arch/x86/crc32_pclmulqdq.c deleted file mode 100644 index c8be1b43ba..0000000000 --- a/modules/zlib/src/arch/x86/crc32_pclmulqdq.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ - * instruction. - * - * A white paper describing this algorithm can be found at: - * doc/crc-pclmulqdq.pdf - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * Copyright (C) 2016 Marian Beermann (support for initial value) - * Authors: - * Wajdi Feghali - * Jim Guilford - * Vinodh Gopal - * Erdinc Ozturk - * Jim Kukunas - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_PCLMULQDQ_CRC - -#include "crc32_pclmulqdq_tpl.h" - -Z_INTERNAL uint32_t crc32_pclmulqdq(uint32_t crc, const uint8_t *buf, size_t len) { - return crc32_copy_impl(crc, NULL, buf, len, 0); -} - -Z_INTERNAL uint32_t crc32_copy_pclmulqdq(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - return crc32_copy_impl(crc, dst, src, len, 1); -} -#endif diff --git a/modules/zlib/src/arch/x86/crc32_pclmulqdq_tpl.h b/modules/zlib/src/arch/x86/crc32_pclmulqdq_tpl.h deleted file mode 100644 index 23d63035a0..0000000000 --- a/modules/zlib/src/arch/x86/crc32_pclmulqdq_tpl.h +++ /dev/null @@ -1,738 +0,0 @@ -/* crc32_pclmulqdq_tpl.h -- Compute the CRC32 using a parallelized folding - * approach with the PCLMULQDQ and VPCMULQDQ instructions. - * - * A white paper describing this algorithm can be found at: - * doc/crc-pclmulqdq.pdf - * - * Copyright (C) 2020 Wangyang Guo (wangyang.guo@intel.com) (VPCLMULQDQ support) - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * Copyright (C) 2016 Marian Beermann (support for initial value) - * Authors: - * Wajdi Feghali - * Jim Guilford - * Vinodh Gopal - * Erdinc Ozturk - * Jim Kukunas - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" - -#include -#include -#include // _mm_extract_epi32 - -#include "crc32_braid_p.h" -#include "crc32_braid_tbl.h" -#include "crc32_p.h" -#include "x86_intrins.h" - -/* 512-bit VPCLMULQDQ path requires AVX-512F */ -#if defined(X86_VPCLMULQDQ) && defined(__AVX512F__) -# if defined(_MSC_VER) && _MSC_VER < 1920 - /* Use epi32 variants for older MSVC toolchains (v141/v140) to avoid cast warnings */ -# define z512_xor3_epi64(a, b, c) _mm512_ternarylogic_epi32(a, b, c, 0x96) -# define z512_inserti64x2(a, b, imm) _mm512_inserti32x4(a, b, imm) -# define z512_extracti64x2(a, imm) _mm512_extracti32x4_epi32(a, imm) -# else -# define z512_xor3_epi64(a, b, c) _mm512_ternarylogic_epi64(a, b, c, 0x96) -# if defined(__AVX512DQ__) -# if defined(_MSC_VER) && !defined(_MM_K0_REG8) -# define z512_inserti64x2(a, b, imm) _mm512_maskz_inserti64x2(UINT8_MAX, a, b, imm) -# else -# define z512_inserti64x2(a, b, imm) _mm512_inserti64x2(a, b, imm) -# endif -# define z512_extracti64x2(a, imm) _mm512_extracti64x2_epi64(a, imm) -# else -# define z512_inserti64x2(a, b, imm) _mm512_inserti32x4(a, b, imm) -# define z512_extracti64x2(a, imm) _mm512_extracti32x4_epi32(a, imm) -# endif -# endif -# ifdef __AVX512VL__ -# define z128_xor3_epi64(a, b, c) _mm_ternarylogic_epi64(a, b, c, 0x96) -# endif -#endif -/* 256-bit VPCLMULQDQ macros (doesn't require AVX-512) */ -#if defined(X86_VPCLMULQDQ) && !defined(__AVX512F__) -# define z256_xor3_epi64(a, b, c) _mm256_xor_si256(_mm256_xor_si256(a, b), c) -#endif - -#ifndef z128_xor3_epi64 -# define z128_xor3_epi64(a, b, c) _mm_xor_si128(_mm_xor_si128(a, b), c) -#endif - -static inline void fold_state_1(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3, - const __m128i xmm_fold4) { - __m128i x_low = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); - __m128i x_high = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x10); - - *xmm_crc0 = *xmm_crc1; - *xmm_crc1 = *xmm_crc2; - *xmm_crc2 = *xmm_crc3; - *xmm_crc3 = _mm_xor_si128(x_low, x_high); -} - -static inline void fold_state_2(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3, - const __m128i xmm_fold4) { - __m128i x_low0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); - __m128i x_high0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x10); - __m128i x_low1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); - __m128i x_high1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x10); - - *xmm_crc0 = *xmm_crc2; - *xmm_crc1 = *xmm_crc3; - *xmm_crc2 = _mm_xor_si128(x_low0, x_high0); - *xmm_crc3 = _mm_xor_si128(x_low1, x_high1); -} - -static inline void fold_state_3(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3, - const __m128i xmm_fold4) { - __m128i x_low0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); - __m128i x_high0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x10); - __m128i x_low1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); - __m128i x_high1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x10); - __m128i x_low2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01); - __m128i x_high2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10); - - *xmm_crc0 = *xmm_crc3; - *xmm_crc1 = _mm_xor_si128(x_low0, x_high0); - *xmm_crc2 = _mm_xor_si128(x_low1, x_high1); - *xmm_crc3 = _mm_xor_si128(x_low2, x_high2); -} - -static inline void fold_state_4(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3, - const __m128i xmm_fold4) { - __m128i x_low0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); - __m128i x_high0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x10); - __m128i x_low1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); - __m128i x_high1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x10); - __m128i x_low2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01); - __m128i x_high2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10); - __m128i x_low3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x01); - __m128i x_high3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10); - - *xmm_crc0 = _mm_xor_si128(x_low0, x_high0); - *xmm_crc1 = _mm_xor_si128(x_low1, x_high1); - *xmm_crc2 = _mm_xor_si128(x_low2, x_high2); - *xmm_crc3 = _mm_xor_si128(x_low3, x_high3); -} - -static inline void fold_state_12(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) { - const __m128i xmm_fold12 = _mm_set_epi64x(0x596C8D81, 0xF5E48C85); - __m128i x_low0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold12, 0x01); - __m128i x_high0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold12, 0x10); - __m128i x_low1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold12, 0x01); - __m128i x_high1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold12, 0x10); - __m128i x_low2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold12, 0x01); - __m128i x_high2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold12, 0x10); - __m128i x_low3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold12, 0x01); - __m128i x_high3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold12, 0x10); - - *xmm_crc0 = _mm_xor_si128(x_low0, x_high0); - *xmm_crc1 = _mm_xor_si128(x_low1, x_high1); - *xmm_crc2 = _mm_xor_si128(x_low2, x_high2); - *xmm_crc3 = _mm_xor_si128(x_low3, x_high3); -} - -/* 512-bit fold function requires AVX-512F */ -#if defined(X86_VPCLMULQDQ) && defined(__AVX512F__) -static inline void fold_state_16(__m512i *zmm_crc0, __m512i *zmm_crc1, __m512i *zmm_crc2, __m512i *zmm_crc3, - const __m512i zmm_t0, const __m512i zmm_t1, const __m512i zmm_t2, - const __m512i zmm_t3, const __m512i zmm_fold16) { - __m512i z_low0 = _mm512_clmulepi64_epi128(*zmm_crc0, zmm_fold16, 0x01); - __m512i z_high0 = _mm512_clmulepi64_epi128(*zmm_crc0, zmm_fold16, 0x10); - __m512i z_low1 = _mm512_clmulepi64_epi128(*zmm_crc1, zmm_fold16, 0x01); - __m512i z_high1 = _mm512_clmulepi64_epi128(*zmm_crc1, zmm_fold16, 0x10); - __m512i z_low2 = _mm512_clmulepi64_epi128(*zmm_crc2, zmm_fold16, 0x01); - __m512i z_high2 = _mm512_clmulepi64_epi128(*zmm_crc2, zmm_fold16, 0x10); - __m512i z_low3 = _mm512_clmulepi64_epi128(*zmm_crc3, zmm_fold16, 0x01); - __m512i z_high3 = _mm512_clmulepi64_epi128(*zmm_crc3, zmm_fold16, 0x10); - - *zmm_crc0 = z512_xor3_epi64(z_low0, z_high0, zmm_t0); - *zmm_crc1 = z512_xor3_epi64(z_low1, z_high1, zmm_t1); - *zmm_crc2 = z512_xor3_epi64(z_low2, z_high2, zmm_t2); - *zmm_crc3 = z512_xor3_epi64(z_low3, z_high3, zmm_t3); -} - -static inline void fold_block_16(const uint8_t **src, uint8_t **dst, size_t *len, __m128i *xmm_crc0, - __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3, const int COPY) { - *len -= 256; - - __m512i zmm_crc0, zmm_crc1, zmm_crc2, zmm_crc3; - __m512i zmm_t0, zmm_t1, zmm_t2, zmm_t3; - __m512i z_low0, z_high0; - const __m512i zmm_fold4 = _mm512_set4_epi32(0x00000001, 0x54442bd4, 0x00000001, 0xc6e41596); - const __m512i zmm_fold16 = _mm512_set4_epi32(0x00000001, 0x1542778a, 0x00000001, 0x322d1430); - - zmm_crc0 = _mm512_loadu_si512((__m512i *)*src); - zmm_crc1 = _mm512_loadu_si512((__m512i *)*src + 1); - zmm_crc2 = _mm512_loadu_si512((__m512i *)*src + 2); - zmm_crc3 = _mm512_loadu_si512((__m512i *)*src + 3); - *src += 256; - if (COPY) { - _mm512_storeu_si512((__m512i *)*dst, zmm_crc0); - _mm512_storeu_si512((__m512i *)*dst + 1, zmm_crc1); - _mm512_storeu_si512((__m512i *)*dst + 2, zmm_crc2); - _mm512_storeu_si512((__m512i *)*dst + 3, zmm_crc3); - *dst += 256; - } - - // Fold existing xmm state into first 64 bytes - zmm_t0 = _mm512_castsi128_si512(*xmm_crc0); - zmm_t0 = z512_inserti64x2(zmm_t0, *xmm_crc1, 1); - zmm_t0 = z512_inserti64x2(zmm_t0, *xmm_crc2, 2); - zmm_t0 = z512_inserti64x2(zmm_t0, *xmm_crc3, 3); - - z_low0 = _mm512_clmulepi64_epi128(zmm_t0, zmm_fold4, 0x01); - z_high0 = _mm512_clmulepi64_epi128(zmm_t0, zmm_fold4, 0x10); - zmm_crc0 = z512_xor3_epi64(zmm_crc0, z_low0, z_high0); - - while (*len >= 256) { - *len -= 256; - zmm_t0 = _mm512_loadu_si512((__m512i *)*src); - zmm_t1 = _mm512_loadu_si512((__m512i *)*src + 1); - zmm_t2 = _mm512_loadu_si512((__m512i *)*src + 2); - zmm_t3 = _mm512_loadu_si512((__m512i *)*src + 3); - *src += 256; - - fold_state_16(&zmm_crc0, &zmm_crc1, &zmm_crc2, &zmm_crc3, zmm_t0, zmm_t1, zmm_t2, zmm_t3, zmm_fold16); - if (COPY) { - _mm512_storeu_si512((__m512i *)*dst, zmm_t0); - _mm512_storeu_si512((__m512i *)*dst + 1, zmm_t1); - _mm512_storeu_si512((__m512i *)*dst + 2, zmm_t2); - _mm512_storeu_si512((__m512i *)*dst + 3, zmm_t3); - *dst += 256; - } - } - - // zmm_crc[0,1,2,3] -> zmm_crc0 - z_low0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x01); - z_high0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x10); - zmm_crc0 = z512_xor3_epi64(z_low0, z_high0, zmm_crc1); - - z_low0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x01); - z_high0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x10); - zmm_crc0 = z512_xor3_epi64(z_low0, z_high0, zmm_crc2); - - z_low0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x01); - z_high0 = _mm512_clmulepi64_epi128(zmm_crc0, zmm_fold4, 0x10); - zmm_crc0 = z512_xor3_epi64(z_low0, z_high0, zmm_crc3); - - // zmm_crc0 -> xmm_crc[0, 1, 2, 3] - *xmm_crc0 = z512_extracti64x2(zmm_crc0, 0); - *xmm_crc1 = z512_extracti64x2(zmm_crc0, 1); - *xmm_crc2 = z512_extracti64x2(zmm_crc0, 2); - *xmm_crc3 = z512_extracti64x2(zmm_crc0, 3); -} -#endif -/* 256-bit fold function for VPCLMULQDQ without AVX-512 */ -#if defined(X86_VPCLMULQDQ) && !defined(__AVX512F__) -static inline void fold_state_8(__m256i *ymm_crc0, __m256i *ymm_crc1, __m256i *ymm_crc2, __m256i *ymm_crc3, - const __m256i ymm_t0, const __m256i ymm_t1, const __m256i ymm_t2, - const __m256i ymm_t3, const __m256i ymm_fold8) { - __m256i y_low0 = _mm256_clmulepi64_epi128(*ymm_crc0, ymm_fold8, 0x01); - __m256i y_high0 = _mm256_clmulepi64_epi128(*ymm_crc0, ymm_fold8, 0x10); - __m256i y_low1 = _mm256_clmulepi64_epi128(*ymm_crc1, ymm_fold8, 0x01); - __m256i y_high1 = _mm256_clmulepi64_epi128(*ymm_crc1, ymm_fold8, 0x10); - __m256i y_low2 = _mm256_clmulepi64_epi128(*ymm_crc2, ymm_fold8, 0x01); - __m256i y_high2 = _mm256_clmulepi64_epi128(*ymm_crc2, ymm_fold8, 0x10); - __m256i y_low3 = _mm256_clmulepi64_epi128(*ymm_crc3, ymm_fold8, 0x01); - __m256i y_high3 = _mm256_clmulepi64_epi128(*ymm_crc3, ymm_fold8, 0x10); - - *ymm_crc0 = z256_xor3_epi64(y_low0, y_high0, ymm_t0); - *ymm_crc1 = z256_xor3_epi64(y_low1, y_high1, ymm_t1); - *ymm_crc2 = z256_xor3_epi64(y_low2, y_high2, ymm_t2); - *ymm_crc3 = z256_xor3_epi64(y_low3, y_high3, ymm_t3); -} - -static inline void fold_block_8(const uint8_t **src, uint8_t **dst, size_t *len, __m128i *xmm_crc0, - __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3, - const __m128i xmm_fold4, const int COPY) { - *len -= 128; - - __m256i ymm_crc0, ymm_crc1, ymm_crc2, ymm_crc3; - __m256i ymm_t0, ymm_t1, ymm_t2, ymm_t3; - __m256i y_low0, y_high0; - const __m256i ymm_fold4 = _mm256_set_epi32( - 0x00000001, 0x54442bd4, 0x00000001, 0xc6e41596, - 0x00000001, 0x54442bd4, 0x00000001, 0xc6e41596); - const __m256i ymm_fold8 = _mm256_set_epi32( - 0x00000001, 0xe88ef372, 0x00000001, 0x4a7fe880, - 0x00000001, 0xe88ef372, 0x00000001, 0x4a7fe880); - - ymm_crc0 = _mm256_loadu_si256((__m256i *)*src); - ymm_crc1 = _mm256_loadu_si256((__m256i *)*src + 1); - ymm_crc2 = _mm256_loadu_si256((__m256i *)*src + 2); - ymm_crc3 = _mm256_loadu_si256((__m256i *)*src + 3); - *src += 128; - if (COPY) { - _mm256_storeu_si256((__m256i *)*dst, ymm_crc0); - _mm256_storeu_si256((__m256i *)*dst + 1, ymm_crc1); - _mm256_storeu_si256((__m256i *)*dst + 2, ymm_crc2); - _mm256_storeu_si256((__m256i *)*dst + 3, ymm_crc3); - *dst += 128; - } - - // Fold existing xmm state into first 32 bytes - ymm_t0 = _mm256_castsi128_si256(*xmm_crc0); - ymm_t0 = _mm256_inserti128_si256(ymm_t0, *xmm_crc1, 1); - - y_low0 = _mm256_clmulepi64_epi128(ymm_t0, ymm_fold4, 0x01); - y_high0 = _mm256_clmulepi64_epi128(ymm_t0, ymm_fold4, 0x10); - ymm_crc0 = z256_xor3_epi64(ymm_crc0, y_low0, y_high0); - - ymm_t0 = _mm256_castsi128_si256(*xmm_crc2); - ymm_t0 = _mm256_inserti128_si256(ymm_t0, *xmm_crc3, 1); - - y_low0 = _mm256_clmulepi64_epi128(ymm_t0, ymm_fold4, 0x01); - y_high0 = _mm256_clmulepi64_epi128(ymm_t0, ymm_fold4, 0x10); - ymm_crc1 = z256_xor3_epi64(ymm_crc1, y_low0, y_high0); - - while (*len >= 128) { - *len -= 128; - ymm_t0 = _mm256_loadu_si256((__m256i *)*src); - ymm_t1 = _mm256_loadu_si256((__m256i *)*src + 1); - ymm_t2 = _mm256_loadu_si256((__m256i *)*src + 2); - ymm_t3 = _mm256_loadu_si256((__m256i *)*src + 3); - *src += 128; - - fold_state_8(&ymm_crc0, &ymm_crc1, &ymm_crc2, &ymm_crc3, ymm_t0, ymm_t1, ymm_t2, ymm_t3, ymm_fold8); - if (COPY) { - _mm256_storeu_si256((__m256i *)*dst, ymm_t0); - _mm256_storeu_si256((__m256i *)*dst + 1, ymm_t1); - _mm256_storeu_si256((__m256i *)*dst + 2, ymm_t2); - _mm256_storeu_si256((__m256i *)*dst + 3, ymm_t3); - *dst += 128; - } - } - - // Extract 8 x 128-bit lanes from 4 x 256-bit registers - __m128i xmm_a0 = _mm256_castsi256_si128(ymm_crc0); - __m128i xmm_a1 = _mm256_extracti128_si256(ymm_crc0, 1); - __m128i xmm_a2 = _mm256_castsi256_si128(ymm_crc1); - __m128i xmm_a3 = _mm256_extracti128_si256(ymm_crc1, 1); - __m128i xmm_a4 = _mm256_castsi256_si128(ymm_crc2); - __m128i xmm_a5 = _mm256_extracti128_si256(ymm_crc2, 1); - __m128i xmm_a6 = _mm256_castsi256_si128(ymm_crc3); - __m128i xmm_a7 = _mm256_extracti128_si256(ymm_crc3, 1); - - // Fold 8 -> 4 using xmm_fold4 (fold by 64 bytes = gap between lane N and lane N+4) - __m128i x_low, x_high; - x_low = _mm_clmulepi64_si128(xmm_a0, xmm_fold4, 0x01); - x_high = _mm_clmulepi64_si128(xmm_a0, xmm_fold4, 0x10); - *xmm_crc0 = z128_xor3_epi64(x_low, x_high, xmm_a4); - - x_low = _mm_clmulepi64_si128(xmm_a1, xmm_fold4, 0x01); - x_high = _mm_clmulepi64_si128(xmm_a1, xmm_fold4, 0x10); - *xmm_crc1 = z128_xor3_epi64(x_low, x_high, xmm_a5); - - x_low = _mm_clmulepi64_si128(xmm_a2, xmm_fold4, 0x01); - x_high = _mm_clmulepi64_si128(xmm_a2, xmm_fold4, 0x10); - *xmm_crc2 = z128_xor3_epi64(x_low, x_high, xmm_a6); - - x_low = _mm_clmulepi64_si128(xmm_a3, xmm_fold4, 0x01); - x_high = _mm_clmulepi64_si128(xmm_a3, xmm_fold4, 0x10); - *xmm_crc3 = z128_xor3_epi64(x_low, x_high, xmm_a7); -} -#endif - -/* Chorba folding algorithm implemented from https://arxiv.org/abs/2412.16398 - * We interleave the PCLMUL-based folds with 8x scaled generator polynomial copies; we read - * 8x QWORDS and then XOR them into the stream at the following offsets: 6, 9, 10, 16, 20, 22, - * 24, 25, 27, 28, 30, 31, 32 - this is detailed in the paper as "generator_64_bits_unrolled_8" */ -#if !defined(X86_VPCLMULQDQ) -static inline void fold_block_chorba(const uint8_t **src, uint8_t **dst, size_t *len, __m128i *xmm_crc0, - __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3, - const __m128i xmm_fold4, const int COPY) { - __m128i xmm_t0, xmm_t1, xmm_t2, xmm_t3; - -#ifndef __AVX512VL__ - if (!COPY) - return; -#endif - while (*len >= 512 + 64 + (16 * 8)) { - __m128i chorba8 = _mm_load_si128((__m128i *)*src); - __m128i chorba7 = _mm_load_si128((__m128i *)*src + 1); - __m128i chorba6 = _mm_load_si128((__m128i *)*src + 2); - __m128i chorba5 = _mm_load_si128((__m128i *)*src + 3); - __m128i chorba4 = _mm_load_si128((__m128i *)*src + 4); - __m128i chorba3 = _mm_load_si128((__m128i *)*src + 5); - __m128i chorba2 = _mm_load_si128((__m128i *)*src + 6); - __m128i chorba1 = _mm_load_si128((__m128i *)*src + 7); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, chorba8); - _mm_storeu_si128((__m128i *)*dst + 1, chorba7); - _mm_storeu_si128((__m128i *)*dst + 2, chorba6); - _mm_storeu_si128((__m128i *)*dst + 3, chorba5); - _mm_storeu_si128((__m128i *)*dst + 4, chorba4); - _mm_storeu_si128((__m128i *)*dst + 5, chorba3); - _mm_storeu_si128((__m128i *)*dst + 6, chorba2); - _mm_storeu_si128((__m128i *)*dst + 7, chorba1); - *dst += 16 * 8; - } - - chorba2 = _mm_xor_si128(chorba2, chorba8); - chorba1 = _mm_xor_si128(chorba1, chorba7); - *src += 16 * 8; - *len -= 16 * 8; - - xmm_t0 = _mm_load_si128((__m128i *)*src); - xmm_t1 = _mm_load_si128((__m128i *)*src + 1); - xmm_t2 = _mm_load_si128((__m128i *)*src + 2); - xmm_t3 = _mm_load_si128((__m128i *)*src + 3); - - fold_state_12(xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, xmm_t0); - _mm_storeu_si128((__m128i *)*dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)*dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)*dst + 3, xmm_t3); - *dst += 64; - } - - *xmm_crc0 = z128_xor3_epi64(xmm_t0, chorba6, *xmm_crc0); - *xmm_crc1 = _mm_xor_si128(z128_xor3_epi64(xmm_t1, chorba5, chorba8), *xmm_crc1); - *xmm_crc2 = z128_xor3_epi64(z128_xor3_epi64(xmm_t2, chorba4, chorba8), chorba7, *xmm_crc2); - *xmm_crc3 = z128_xor3_epi64(z128_xor3_epi64(xmm_t3, chorba3, chorba7), chorba6, *xmm_crc3); - - xmm_t0 = _mm_load_si128((__m128i *)*src + 4); - xmm_t1 = _mm_load_si128((__m128i *)*src + 5); - xmm_t2 = _mm_load_si128((__m128i *)*src + 6); - xmm_t3 = _mm_load_si128((__m128i *)*src + 7); - - fold_state_4(xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, xmm_t0); - _mm_storeu_si128((__m128i *)*dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)*dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)*dst + 3, xmm_t3); - *dst += 64; - } - - *xmm_crc0 = z128_xor3_epi64(z128_xor3_epi64(xmm_t0, chorba2, chorba6), chorba5, *xmm_crc0); - *xmm_crc1 = z128_xor3_epi64(z128_xor3_epi64(xmm_t1, chorba1, chorba4), chorba5, *xmm_crc1); - *xmm_crc2 = _mm_xor_si128(z128_xor3_epi64(xmm_t2, chorba3, chorba4), *xmm_crc2); - *xmm_crc3 = _mm_xor_si128(z128_xor3_epi64(xmm_t3, chorba2, chorba3), *xmm_crc3); - - xmm_t0 = _mm_load_si128((__m128i *)*src + 8); - xmm_t1 = _mm_load_si128((__m128i *)*src + 9); - xmm_t2 = _mm_load_si128((__m128i *)*src + 10); - xmm_t3 = _mm_load_si128((__m128i *)*src + 11); - - fold_state_4(xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, xmm_t0); - _mm_storeu_si128((__m128i *)*dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)*dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)*dst + 3, xmm_t3); - *dst += 64; - } - - *xmm_crc0 = z128_xor3_epi64(z128_xor3_epi64(xmm_t0, chorba1, chorba2), chorba8, *xmm_crc0); - *xmm_crc1 = _mm_xor_si128(z128_xor3_epi64(xmm_t1, chorba1, chorba7), *xmm_crc1); - *xmm_crc2 = z128_xor3_epi64(xmm_t2, chorba6, *xmm_crc2); - *xmm_crc3 = z128_xor3_epi64(xmm_t3, chorba5, *xmm_crc3); - - xmm_t0 = _mm_load_si128((__m128i *)*src + 12); - xmm_t1 = _mm_load_si128((__m128i *)*src + 13); - xmm_t2 = _mm_load_si128((__m128i *)*src + 14); - xmm_t3 = _mm_load_si128((__m128i *)*src + 15); - - fold_state_4(xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, xmm_t0); - _mm_storeu_si128((__m128i *)*dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)*dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)*dst + 3, xmm_t3); - *dst += 64; - } - - *xmm_crc0 = _mm_xor_si128(z128_xor3_epi64(xmm_t0, chorba4, chorba8), *xmm_crc0); - *xmm_crc1 = z128_xor3_epi64(z128_xor3_epi64(xmm_t1, chorba3, chorba8), chorba7, *xmm_crc1); - *xmm_crc2 = _mm_xor_si128(z128_xor3_epi64(z128_xor3_epi64(xmm_t2, chorba2, chorba8), chorba7, chorba6), *xmm_crc2); - *xmm_crc3 = _mm_xor_si128(z128_xor3_epi64(z128_xor3_epi64(xmm_t3, chorba1, chorba7), chorba6, chorba5), *xmm_crc3); - - xmm_t0 = _mm_load_si128((__m128i *)*src + 16); - xmm_t1 = _mm_load_si128((__m128i *)*src + 17); - xmm_t2 = _mm_load_si128((__m128i *)*src + 18); - xmm_t3 = _mm_load_si128((__m128i *)*src + 19); - - fold_state_4(xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, xmm_t0); - _mm_storeu_si128((__m128i *)*dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)*dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)*dst + 3, xmm_t3); - *dst += 64; - } - - *xmm_crc0 = _mm_xor_si128(z128_xor3_epi64(z128_xor3_epi64(xmm_t0, chorba4, chorba8), chorba6, chorba5), *xmm_crc0); - *xmm_crc1 = z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t1, chorba3, chorba4), chorba8, chorba7), chorba5, *xmm_crc1); - *xmm_crc2 = z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t2, chorba2, chorba3), chorba4, chorba7), chorba6, *xmm_crc2); - *xmm_crc3 = _mm_xor_si128(z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t3, chorba1, chorba2), chorba3, chorba8), chorba6, chorba5), *xmm_crc3); - - xmm_t0 = _mm_load_si128((__m128i *)*src + 20); - xmm_t1 = _mm_load_si128((__m128i *)*src + 21); - xmm_t2 = _mm_load_si128((__m128i *)*src + 22); - xmm_t3 = _mm_load_si128((__m128i *)*src + 23); - - fold_state_4(xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, xmm_t0); - _mm_storeu_si128((__m128i *)*dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)*dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)*dst + 3, xmm_t3); - *dst += 64; - } - - *xmm_crc0 = _mm_xor_si128(z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t0, chorba1, chorba2), chorba4, chorba8), chorba7, chorba5), *xmm_crc0); - *xmm_crc1 = z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t1, chorba1, chorba3), chorba4, chorba7), chorba6, *xmm_crc1); - *xmm_crc2 = z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t2, chorba2, chorba3), chorba8, chorba6), chorba5, *xmm_crc2); - *xmm_crc3 = _mm_xor_si128(z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t3, chorba1, chorba2), chorba4, chorba8), chorba7, chorba5), *xmm_crc3); - - xmm_t0 = _mm_load_si128((__m128i *)*src + 24); - xmm_t1 = _mm_load_si128((__m128i *)*src + 25); - xmm_t2 = _mm_load_si128((__m128i *)*src + 26); - xmm_t3 = _mm_load_si128((__m128i *)*src + 27); - - fold_state_4(xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, xmm_t0); - _mm_storeu_si128((__m128i *)*dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)*dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)*dst + 3, xmm_t3); - *dst += 64; - } - - *xmm_crc0 = _mm_xor_si128(z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t0, chorba1, chorba3), chorba4, chorba8), chorba7, chorba6), *xmm_crc0); - *xmm_crc1 = z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t1, chorba2, chorba3), chorba7, chorba6), chorba5, *xmm_crc1); - *xmm_crc2 = z128_xor3_epi64(z128_xor3_epi64(z128_xor3_epi64(xmm_t2, chorba1, chorba2), chorba4, chorba6), chorba5, *xmm_crc2); - *xmm_crc3 = _mm_xor_si128(z128_xor3_epi64(z128_xor3_epi64(xmm_t3, chorba1, chorba3), chorba4, chorba5), *xmm_crc3); - - xmm_t0 = _mm_load_si128((__m128i *)*src + 28); - xmm_t1 = _mm_load_si128((__m128i *)*src + 29); - xmm_t2 = _mm_load_si128((__m128i *)*src + 30); - xmm_t3 = _mm_load_si128((__m128i *)*src + 31); - - fold_state_4(xmm_crc0, xmm_crc1, xmm_crc2, xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)*dst, xmm_t0); - _mm_storeu_si128((__m128i *)*dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)*dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)*dst + 3, xmm_t3); - *dst += 64; - } - - *xmm_crc0 = z128_xor3_epi64(z128_xor3_epi64(xmm_t0, chorba2, chorba3), chorba4, *xmm_crc0); - *xmm_crc1 = z128_xor3_epi64(z128_xor3_epi64(xmm_t1, chorba1, chorba2), chorba3, *xmm_crc1); - *xmm_crc2 = _mm_xor_si128(z128_xor3_epi64(xmm_t2, chorba1, chorba2), *xmm_crc2); - *xmm_crc3 = z128_xor3_epi64(xmm_t3, chorba1, *xmm_crc3); - - *len -= 512; - *src += 512; - } -} -#endif - -Z_FORCEINLINE static uint32_t crc32_copy_impl(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len, - const int COPY) { - size_t copy_len = len; - if (len >= 16) { - /* Calculate 16-byte alignment offset */ - uintptr_t align_diff = ALIGN_DIFF(src, 16); - - /* If total length is less than (alignment bytes + 16), use the faster small method. - * Handles both initially small buffers and cases where alignment would leave < 16 bytes */ - copy_len = len < align_diff + 16 ? len : align_diff; - } - - if (copy_len > 0) { - crc = ~crc32_copy_small(~crc, dst, src, copy_len, 31, COPY); - src += copy_len; - len -= copy_len; - if (COPY) { - dst += copy_len; - } - } - - if (len == 0) - return crc; - - const __m128i xmm_fold4 = _mm_set_epi32(0x00000001, 0x54442bd4, 0x00000001, 0xc6e41596); - - __m128i xmm_t0, xmm_t1, xmm_t2, xmm_t3; - __m128i xmm_crc0 = _mm_cvtsi32_si128(0x9db42487); - __m128i xmm_crc1 = _mm_setzero_si128(); - __m128i xmm_crc2 = _mm_setzero_si128(); - __m128i xmm_crc3 = _mm_setzero_si128(); - - if (crc != 0) { - // Process the first 16 bytes and handle initial CRC - len -= 16; - xmm_t0 = _mm_load_si128((__m128i *)src); - src += 16; - - fold_state_1(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)dst, xmm_t0); - dst += 16; - } - xmm_crc3 = z128_xor3_epi64(xmm_crc3, xmm_t0, _mm_cvtsi32_si128(crc)); - } - -#if defined(X86_VPCLMULQDQ) && defined(__AVX512F__) - /* 512-bit VPCLMULQDQ path requires AVX-512F */ - if (len >= 256) - fold_block_16(&src, &dst, &len, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, COPY); -#elif defined(X86_VPCLMULQDQ) - /* 256-bit VPCLMULQDQ path (doesn't require AVX-512F) */ - if (len >= 128) - fold_block_8(&src, &dst, &len, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, xmm_fold4, COPY); -#else - /* Chorba algorithm for PCLMULQDQ path (when VPCLMULQDQ not available) */ - if (len >= 512 + 64 + (16 * 8)) - fold_block_chorba(&src, &dst, &len, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, xmm_fold4, COPY); -#endif /* X86_VPCLMULQDQ */ - - while (len >= 64) { - len -= 64; - xmm_t0 = _mm_load_si128((__m128i *)src); - xmm_t1 = _mm_load_si128((__m128i *)src + 1); - xmm_t2 = _mm_load_si128((__m128i *)src + 2); - xmm_t3 = _mm_load_si128((__m128i *)src + 3); - src += 64; - - fold_state_4(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)dst, xmm_t0); - _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)dst + 2, xmm_t2); - _mm_storeu_si128((__m128i *)dst + 3, xmm_t3); - dst += 64; - } - - xmm_crc0 = _mm_xor_si128(xmm_crc0, xmm_t0); - xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t1); - xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t2); - xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t3); - } - - /* - * len = num bytes left - 64 - */ - if (len >= 48) { - len -= 48; - - xmm_t0 = _mm_load_si128((__m128i *)src); - xmm_t1 = _mm_load_si128((__m128i *)src + 1); - xmm_t2 = _mm_load_si128((__m128i *)src + 2); - src += 48; - - fold_state_3(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)dst, xmm_t0); - _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); - _mm_storeu_si128((__m128i *)dst + 2, xmm_t2); - dst += 48; - } - - xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t0); - xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t1); - xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t2); - } else if (len >= 32) { - len -= 32; - - xmm_t0 = _mm_load_si128((__m128i *)src); - xmm_t1 = _mm_load_si128((__m128i *)src + 1); - src += 32; - - fold_state_2(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)dst, xmm_t0); - _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); - dst += 32; - } - - xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t0); - xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t1); - } else if (len >= 16) { - len -= 16; - xmm_t0 = _mm_load_si128((__m128i *)src); - src += 16; - - fold_state_1(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, xmm_fold4); - if (COPY) { - _mm_storeu_si128((__m128i *)dst, xmm_t0); - dst += 16; - } - - xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t0); - } - - const __m128i k12 = _mm_set_epi32(0x00000001, 0x751997d0, 0x00000000, 0xccaa009e); - const __m128i barrett_k = _mm_set_epi32(0x00000001, 0xdb710640, 0xb4e5b025, 0xf7011641); - - /* Fold 4x128-bit into a single 128-bit value using k1/k2 constants */ - __m128i x_low0 = _mm_clmulepi64_si128(xmm_crc0, k12, 0x01); - __m128i x_high0 = _mm_clmulepi64_si128(xmm_crc0, k12, 0x10); - xmm_crc1 = z128_xor3_epi64(xmm_crc1, x_low0, x_high0); - - __m128i x_low1 = _mm_clmulepi64_si128(xmm_crc1, k12, 0x01); - __m128i x_high1 = _mm_clmulepi64_si128(xmm_crc1, k12, 0x10); - xmm_crc2 = z128_xor3_epi64(xmm_crc2, x_low1, x_high1); - - __m128i x_low2 = _mm_clmulepi64_si128(xmm_crc2, k12, 0x01); - __m128i x_high2 = _mm_clmulepi64_si128(xmm_crc2, k12, 0x10); - xmm_crc3 = z128_xor3_epi64(xmm_crc3, x_low2, x_high2); - - /* Fold remaining bytes into the 128-bit state */ - if (len) { - const __m128i xmm_mask3 = _mm_set1_epi32((int32_t)0x80808080); - const __m128i xmm_seq = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - - /* Create masks to shift bytes for partial input */ - __m128i xmm_shl = _mm_add_epi8(xmm_seq, _mm_set1_epi8((char)len - 16)); - __m128i xmm_shr = _mm_xor_si128(xmm_shl, xmm_mask3); - - /* Shift out bytes from crc3 to make space for new data */ - __m128i xmm_overflow = _mm_shuffle_epi8(xmm_crc3, xmm_shl); - xmm_crc3 = _mm_shuffle_epi8(xmm_crc3, xmm_shr); - - /* Insert the partial input into crc3 */ -#if defined(__AVX512BW__) && defined(__AVX512VL__) - __mmask16 k = (1 << len) - 1; - __m128i xmm_crc_part = _mm_maskz_loadu_epi8(k, src); - if (COPY) { - _mm_mask_storeu_epi8(dst, k, xmm_crc_part); - } -#else - __m128i xmm_crc_part = _mm_setzero_si128(); - memcpy(&xmm_crc_part, src, len); - if (COPY) { - memcpy(dst, src, len); - } -#endif - __m128i part_aligned = _mm_shuffle_epi8(xmm_crc_part, xmm_shl); - xmm_crc3 = _mm_xor_si128(xmm_crc3, part_aligned); - - /* Fold the bytes that were shifted out back into crc3 */ - __m128i ovf_low = _mm_clmulepi64_si128(xmm_overflow, k12, 0x01); - __m128i ovf_high = _mm_clmulepi64_si128(xmm_overflow, k12, 0x10); - xmm_crc3 = z128_xor3_epi64(xmm_crc3, ovf_low, ovf_high); - } - - /* Reduce 128-bits to 32-bits using two-stage Barrett reduction */ - __m128i x_tmp0 = _mm_clmulepi64_si128(xmm_crc3, barrett_k, 0x00); - __m128i x_tmp1 = _mm_clmulepi64_si128(x_tmp0, barrett_k, 0x10); - - x_tmp1 = _mm_blend_epi16(x_tmp1, _mm_setzero_si128(), 0xcf); - x_tmp0 = _mm_xor_si128(x_tmp1, xmm_crc3); - - __m128i x_res_a = _mm_clmulepi64_si128(x_tmp0, barrett_k, 0x01); - __m128i x_res_b = _mm_clmulepi64_si128(x_res_a, barrett_k, 0x10); - - crc = ((uint32_t)_mm_extract_epi32(x_res_b, 2)); - - return ~crc; -} diff --git a/modules/zlib/src/arch/x86/crc32_vpclmulqdq_avx2.c b/modules/zlib/src/arch/x86/crc32_vpclmulqdq_avx2.c deleted file mode 100644 index 1cdef13b09..0000000000 --- a/modules/zlib/src/arch/x86/crc32_vpclmulqdq_avx2.c +++ /dev/null @@ -1,17 +0,0 @@ -/* crc32_vpclmulqdq_avx2.c -- VPCLMULQDQ-based CRC32 with AVX2. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_VPCLMULQDQ_AVX2 - -#define X86_VPCLMULQDQ -#include "crc32_pclmulqdq_tpl.h" - -Z_INTERNAL uint32_t crc32_vpclmulqdq_avx2(uint32_t crc, const uint8_t *buf, size_t len) { - return crc32_copy_impl(crc, NULL, buf, len, 0); -} - -Z_INTERNAL uint32_t crc32_copy_vpclmulqdq_avx2(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - return crc32_copy_impl(crc, dst, src, len, 1); -} -#endif diff --git a/modules/zlib/src/arch/x86/crc32_vpclmulqdq_avx512.c b/modules/zlib/src/arch/x86/crc32_vpclmulqdq_avx512.c deleted file mode 100644 index a95a448f49..0000000000 --- a/modules/zlib/src/arch/x86/crc32_vpclmulqdq_avx512.c +++ /dev/null @@ -1,17 +0,0 @@ -/* crc32_vpclmulqdq_avx512.c -- VPCLMULQDQ-based CRC32 with AVX-512. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_VPCLMULQDQ_AVX512 - -#define X86_VPCLMULQDQ -#include "crc32_pclmulqdq_tpl.h" - -Z_INTERNAL uint32_t crc32_vpclmulqdq_avx512(uint32_t crc, const uint8_t *buf, size_t len) { - return crc32_copy_impl(crc, NULL, buf, len, 0); -} - -Z_INTERNAL uint32_t crc32_copy_vpclmulqdq_avx512(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - return crc32_copy_impl(crc, dst, src, len, 1); -} -#endif diff --git a/modules/zlib/src/arch/x86/slide_hash_avx2.c b/modules/zlib/src/arch/x86/slide_hash_avx2.c deleted file mode 100644 index 241ea305e3..0000000000 --- a/modules/zlib/src/arch/x86/slide_hash_avx2.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * AVX2 optimized hash slide, based on Intel's slide_sse implementation - * - * Copyright (C) 2017 Intel Corporation - * Authors: - * Arjan van de Ven - * Jim Kukunas - * Mika T. Lindqvist - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_AVX2 - -#include "zbuild.h" -#include "deflate.h" - -#include - -static inline void slide_hash_chain(Pos *table, uint32_t entries, const __m256i wsize) { - table += entries; - table -= 32; - - do { - __m256i value1, value2, result1, result2; - - value1 = _mm256_load_si256((__m256i *)table); - value2 = _mm256_load_si256((__m256i *)(table+16)); - result1 = _mm256_subs_epu16(value1, wsize); - result2 = _mm256_subs_epu16(value2, wsize); - _mm256_store_si256((__m256i *)table, result1); - _mm256_store_si256((__m256i *)(table+16), result2); - - table -= 32; - entries -= 32; - } while (entries > 0); -} - -Z_INTERNAL void slide_hash_avx2(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - const __m256i ymm_wsize = _mm256_set1_epi16((short)wsize); - - slide_hash_chain(s->head, HASH_SIZE, ymm_wsize); - slide_hash_chain(s->prev, wsize, ymm_wsize); -} - -#endif diff --git a/modules/zlib/src/arch/x86/slide_hash_sse2.c b/modules/zlib/src/arch/x86/slide_hash_sse2.c deleted file mode 100644 index 4aa8df5ee8..0000000000 --- a/modules/zlib/src/arch/x86/slide_hash_sse2.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SSE optimized hash slide - * - * Copyright (C) 2017 Intel Corporation - * Authors: - * Arjan van de Ven - * Jim Kukunas - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_SSE2 - -#include "zbuild.h" -#include "deflate.h" - -#include -#include - -static inline void slide_hash_chain(Pos *table0, Pos *table1, uint32_t entries0, - uint32_t entries1, const __m128i wsize) { - uint32_t entries; - Pos *table; - __m128i value0, value1, result0, result1; - - int on_chain = 0; - -next_chain: - table = (on_chain) ? table1 : table0; - entries = (on_chain) ? entries1 : entries0; - - table += entries; - table -= 16; - - /* ZALLOC allocates this pointer unless the user chose a custom allocator. - * Our alloc function is aligned to 64 byte boundaries */ - do { - value0 = _mm_load_si128((__m128i *)table); - value1 = _mm_load_si128((__m128i *)(table + 8)); - result0 = _mm_subs_epu16(value0, wsize); - result1 = _mm_subs_epu16(value1, wsize); - _mm_store_si128((__m128i *)table, result0); - _mm_store_si128((__m128i *)(table + 8), result1); - - table -= 16; - entries -= 16; - } while (entries > 0); - - ++on_chain; - if (on_chain > 1) { - return; - } else { - goto next_chain; - } -} - -Z_INTERNAL void slide_hash_sse2(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); - uint16_t wsize = (uint16_t)s->w_size; - const __m128i xmm_wsize = _mm_set1_epi16((short)wsize); - - assert(((uintptr_t)s->head & 15) == 0); - assert(((uintptr_t)s->prev & 15) == 0); - - slide_hash_chain(s->head, s->prev, HASH_SIZE, wsize, xmm_wsize); -} - -#endif diff --git a/modules/zlib/src/arch/x86/x86_features.c b/modules/zlib/src/arch/x86/x86_features.c deleted file mode 100644 index 5eba18bf8a..0000000000 --- a/modules/zlib/src/arch/x86/x86_features.c +++ /dev/null @@ -1,128 +0,0 @@ -/* x86_features.c - x86 feature check - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * Author: - * Jim Kukunas - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef X86_FEATURES - -#include "zbuild.h" -#include "x86_features.h" - -#if defined(HAVE_CPUID_MS) -# include -#elif defined(HAVE_CPUID_GNU) -// Newer versions of GCC and clang come with cpuid.h -# include -# ifdef X86_HAVE_XSAVE_INTRIN -# if __GNUC__ == 8 -# include -# else -# include -# endif -# endif -#endif - -static inline void cpuid(int info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) { -#if defined(HAVE_CPUID_MS) - unsigned int registers[4]; - __cpuid((int *)registers, info); - - *eax = registers[0]; - *ebx = registers[1]; - *ecx = registers[2]; - *edx = registers[3]; -#elif defined(HAVE_CPUID_GNU) - *eax = *ebx = *ecx = *edx = 0; - __cpuid(info, *eax, *ebx, *ecx, *edx); -#else - /* When using this fallback, the faster SSE/AVX code is disabled */ - *eax = *ebx = *ecx = *edx = 0; -#endif -} - -static inline void cpuidex(int info, int subinfo, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) { -#if defined(HAVE_CPUID_MS) - unsigned int registers[4]; - __cpuidex((int *)registers, info, subinfo); - - *eax = registers[0]; - *ebx = registers[1]; - *ecx = registers[2]; - *edx = registers[3]; -#elif defined(HAVE_CPUID_GNU) - *eax = *ebx = *ecx = *edx = 0; - __cpuid_count(info, subinfo, *eax, *ebx, *ecx, *edx); -#else - /* When using this fallback, the faster SSE/AVX code is disabled */ - *eax = *ebx = *ecx = *edx = 0; -#endif -} - -static inline uint64_t xgetbv(unsigned int xcr) { -#if defined(_MSC_VER) || defined(X86_HAVE_XSAVE_INTRIN) - return _xgetbv(xcr); -#elif defined(__GNUC__) - uint32_t eax, edx; - __asm__ ( ".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(xcr)); - return (uint64_t)(edx) << 32 | eax; -#else - /* When using this fallback, some of the faster code is disabled */ - return 0; -#endif -} - -void Z_INTERNAL x86_check_features(struct x86_cpu_features *features) { - unsigned eax, ebx, ecx, edx; - unsigned maxbasic; - - cpuid(0, &maxbasic, &ebx, &ecx, &edx); - cpuid(1 /*CPU_PROCINFO_AND_FEATUREBITS*/, &eax, &ebx, &ecx, &edx); - - features->has_sse2 = edx & 0x4000000; - features->has_ssse3 = ecx & 0x200; - features->has_sse41 = ecx & 0x80000; - features->has_sse42 = ecx & 0x100000; - features->has_pclmulqdq = ecx & 0x2; - - if (ecx & 0x08000000) { - uint64_t xfeature = xgetbv(0); - - features->has_os_save_ymm = ((xfeature & 0x06) == 0x06); - features->has_os_save_zmm = ((xfeature & 0xe6) == 0xe6); - } - - if (maxbasic >= 7) { - // Reference: https://software.intel.com/sites/default/files/article/405250/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family.pdf - cpuidex(7, 0, &eax, &ebx, &ecx, &edx); - - // check BMI2 bit - features->has_bmi2 = ebx & 0x100; - - // check AVX2 bit if the OS supports saving YMM registers - if (features->has_os_save_ymm) { - features->has_avx2 = ebx & 0x20; - features->has_vpclmulqdq = ecx & 0x400; - } - - // check AVX512 bits if the OS supports saving ZMM registers - if (features->has_os_save_zmm) { - features->has_avx512f = ebx & 0x00010000; - if (features->has_avx512f) { - // According to the Intel Software Developer's Manual, AVX512F must be enabled too in order to enable - // AVX512(DQ,BW,VL). - features->has_avx512dq = ebx & 0x00020000; - features->has_avx512bw = ebx & 0x40000000; - features->has_avx512vl = ebx & 0x80000000; - } - features->has_avx512_common = features->has_avx512f && features->has_avx512dq && features->has_avx512bw \ - && features->has_avx512vl && features->has_bmi2; - features->has_avx512vnni = ecx & 0x800; - } - } -} - -#endif diff --git a/modules/zlib/src/arch/x86/x86_features.h b/modules/zlib/src/arch/x86/x86_features.h deleted file mode 100644 index 2118b8e87a..0000000000 --- a/modules/zlib/src/arch/x86/x86_features.h +++ /dev/null @@ -1,30 +0,0 @@ -/* x86_features.h -- check for CPU features - * Copyright (C) 2013 Intel Corporation Jim Kukunas - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef X86_FEATURES_H_ -#define X86_FEATURES_H_ - -struct x86_cpu_features { - int has_avx2; - int has_avx512f; - int has_avx512dq; - int has_avx512bw; - int has_avx512vl; - int has_avx512_common; // Enabled when AVX512(F,DQ,BW,VL) are all enabled. - int has_avx512vnni; - int has_bmi2; - int has_sse2; - int has_ssse3; - int has_sse41; - int has_sse42; - int has_pclmulqdq; - int has_vpclmulqdq; - int has_os_save_ymm; - int has_os_save_zmm; -}; - -void Z_INTERNAL x86_check_features(struct x86_cpu_features *features); - -#endif /* X86_FEATURES_H_ */ diff --git a/modules/zlib/src/arch/x86/x86_functions.h b/modules/zlib/src/arch/x86/x86_functions.h deleted file mode 100644 index e187e21d2b..0000000000 --- a/modules/zlib/src/arch/x86/x86_functions.h +++ /dev/null @@ -1,214 +0,0 @@ -/* x86_functions.h -- x86 implementations for arch-specific functions. - * Copyright (C) 2013 Intel Corporation Jim Kukunas - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef X86_FUNCTIONS_H_ -#define X86_FUNCTIONS_H_ - -#include "x86_natives.h" - -/* So great news, your compiler is broken and causes stack smashing. Rather than - * notching out its compilation we'll just remove the assignment in the functable. - * Further context: - * https://developercommunity.visualstudio.com/t/Stack-corruption-with-v142-toolchain-whe/10853479 */ -#if defined(_MSC_VER) && defined(ARCH_32BIT) && _MSC_VER >= 1920 && _MSC_VER <= 1929 -#define NO_CHORBA_SSE -#endif - -#ifdef X86_SSE2 -uint8_t* chunkmemset_safe_sse2(uint8_t *out, uint8_t *from, size_t len, size_t left); -uint32_t compare256_sse2(const uint8_t *src0, const uint8_t *src1); -void inflate_fast_sse2(PREFIX3(stream)* strm, uint32_t start); -uint32_t longest_match_sse2(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_sse2(deflate_state *const s, uint32_t cur_match); -void slide_hash_sse2(deflate_state *s); - -# if !defined(WITHOUT_CHORBA) && !defined(WITHOUT_CHORBA_SSE) - uint32_t crc32_chorba_sse2(uint32_t crc, const uint8_t *buf, size_t len); - uint32_t crc32_copy_chorba_sse2(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); - uint32_t chorba_small_nondestructive_sse2(uint32_t crc, const uint8_t *buf, size_t len); -# endif -#endif - -#ifndef X86_SSE2_NATIVE -# define CHUNKSET_FALLBACK -# define COMPARE256_FALLBACK -# define SLIDE_HASH_FALLBACK -#endif - -#ifdef X86_SSSE3 -uint32_t adler32_ssse3(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_ssse3(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -uint8_t* chunkmemset_safe_ssse3(uint8_t *out, uint8_t *from, size_t len, size_t left); -void inflate_fast_ssse3(PREFIX3(stream) *strm, uint32_t start); -#endif - -#ifndef X86_SSSE3_NATIVE -# define ADLER32_FALLBACK -#endif - -#if defined(X86_SSE41) -# if !defined(WITHOUT_CHORBA) && !defined(WITHOUT_CHORBA_SSE) - uint32_t crc32_chorba_sse41(uint32_t crc, const uint8_t *buf, size_t len); - uint32_t crc32_copy_chorba_sse41(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -# endif -#endif - -#ifdef X86_SSE42 -uint32_t adler32_copy_sse42(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -#endif - -#ifdef X86_AVX2 -uint32_t adler32_avx2(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_avx2(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -uint8_t* chunkmemset_safe_avx2(uint8_t *out, uint8_t *from, size_t len, size_t left); -uint32_t compare256_avx2(const uint8_t *src0, const uint8_t *src1); -void inflate_fast_avx2(PREFIX3(stream)* strm, uint32_t start); -uint32_t longest_match_avx2(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_avx2(deflate_state *const s, uint32_t cur_match); -void slide_hash_avx2(deflate_state *s); -#endif -#ifdef X86_AVX512 -uint32_t adler32_avx512(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_avx512(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -uint8_t* chunkmemset_safe_avx512(uint8_t *out, uint8_t *from, size_t len, size_t left); -uint32_t compare256_avx512(const uint8_t *src0, const uint8_t *src1); -void inflate_fast_avx512(PREFIX3(stream)* strm, uint32_t start); -uint32_t longest_match_avx512(deflate_state *const s, uint32_t cur_match); -uint32_t longest_match_roll_avx512(deflate_state *const s, uint32_t cur_match); -#endif -#ifdef X86_AVX512VNNI -uint32_t adler32_avx512_vnni(uint32_t adler, const uint8_t *buf, size_t len); -uint32_t adler32_copy_avx512_vnni(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); -#endif - -#ifdef X86_PCLMULQDQ_CRC -uint32_t crc32_pclmulqdq(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_pclmulqdq(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif -#ifdef X86_VPCLMULQDQ_AVX2 -uint32_t crc32_vpclmulqdq_avx2(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_vpclmulqdq_avx2(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif -#ifdef X86_VPCLMULQDQ_AVX512 -uint32_t crc32_vpclmulqdq_avx512(uint32_t crc, const uint8_t *buf, size_t len); -uint32_t crc32_copy_vpclmulqdq_avx512(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); -#endif - -#if !defined(X86_PCLMULQDQ_NATIVE) && !defined(X86_VPCLMULQDQ_NATIVE) -# define CRC32_BRAID_FALLBACK -#endif - -#ifdef DISABLE_RUNTIME_CPU_DETECTION -// X86 - SSE2 -# ifdef X86_SSE2_NATIVE -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_sse2 -# undef native_compare256 -# define native_compare256 compare256_sse2 -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_sse2 -# undef native_longest_match -# define native_longest_match longest_match_sse2 -# undef native_longest_match_roll -# define native_longest_match_roll longest_match_roll_sse2 -# if !defined(WITHOUT_CHORBA) && !defined(WITHOUT_CHORBA_SSE) -# undef native_crc32 -# define native_crc32 crc32_chorba_sse2 -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_chorba_sse2 -# endif -# undef native_slide_hash -# define native_slide_hash slide_hash_sse2 -# endif -// X86 - SSSE3 -# ifdef X86_SSSE3_NATIVE -# undef native_adler32 -# define native_adler32 adler32_ssse3 -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_ssse3 -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_ssse3 -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_ssse3 -# endif -// X86 - SSE4.1 -# if defined(X86_SSE41_NATIVE) -# if !defined(WITHOUT_CHORBA) && !defined(WITHOUT_CHORBA_SSE) -# undef native_crc32 -# define native_crc32 crc32_chorba_sse41 -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_chorba_sse41 -# endif -# endif -// X86 - SSE4.2 -# ifdef X86_SSE42_NATIVE -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_sse42 -# endif -// X86 - PCLMUL -# ifdef X86_PCLMULQDQ_NATIVE -# undef native_crc32 -# define native_crc32 crc32_pclmulqdq -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_pclmulqdq -# endif -// X86 - AVX2 -# ifdef X86_AVX2_NATIVE -# undef native_adler32 -# define native_adler32 adler32_avx2 -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_avx2 -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_avx2 -# undef native_compare256 -# define native_compare256 compare256_avx2 -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_avx2 -# undef native_longest_match -# define native_longest_match longest_match_avx2 -# undef native_longest_match_roll -# define native_longest_match_roll longest_match_roll_avx2 -# undef native_slide_hash -# define native_slide_hash slide_hash_avx2 -# endif -// X86 - AVX512 (F,DQ,BW,Vl) -# ifdef X86_AVX512_NATIVE -# undef native_adler32 -# define native_adler32 adler32_avx512 -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_avx512 -# undef native_chunkmemset_safe -# define native_chunkmemset_safe chunkmemset_safe_avx512 -# undef native_compare256 -# define native_compare256 compare256_avx512 -# undef native_inflate_fast -# define native_inflate_fast inflate_fast_avx512 -# undef native_longest_match -# define native_longest_match longest_match_avx512 -# undef native_longest_match_roll -# define native_longest_match_roll longest_match_roll_avx512 -// X86 - AVX512 (VNNI) -# ifdef X86_AVX512VNNI_NATIVE -# undef native_adler32 -# define native_adler32 adler32_avx512_vnni -# undef native_adler32_copy -# define native_adler32_copy adler32_copy_avx512_vnni -# endif -# endif -// X86 - VPCLMULQDQ -# ifdef X86_VPCLMULQDQ_AVX512_NATIVE -# undef native_crc32 -# define native_crc32 crc32_vpclmulqdq_avx512 -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_vpclmulqdq_avx512 -# elif defined(X86_VPCLMULQDQ_AVX2_NATIVE) -# undef native_crc32 -# define native_crc32 crc32_vpclmulqdq_avx2 -# undef native_crc32_copy -# define native_crc32_copy crc32_copy_vpclmulqdq_avx2 -# endif -#endif - -#endif /* X86_FUNCTIONS_H_ */ diff --git a/modules/zlib/src/arch/x86/x86_intrins.h b/modules/zlib/src/arch/x86/x86_intrins.h deleted file mode 100644 index 1d1df5eb11..0000000000 --- a/modules/zlib/src/arch/x86/x86_intrins.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef X86_INTRINS_H -#define X86_INTRINS_H - -#ifdef __SSE2__ -#include -#endif - -/* Unfortunately GCC didn't support these things until version 10. - * Similarly, AppleClang didn't support them in Xcode 9.2 but did in 9.3. - */ -#ifdef __AVX2__ -#include - -#if (!defined(__clang__) && !defined(__NVCOMPILER) && defined(__GNUC__) && __GNUC__ < 10) \ - || (defined(__apple_build_version__) && __apple_build_version__ < 9020039) -static inline __m256i _mm256_zextsi128_si256(__m128i a) { - __m128i r; - __asm__ volatile ("vmovdqa %1,%0" : "=x" (r) : "x" (a)); - return _mm256_castsi128_si256(r); -} - -#ifdef __AVX512F__ -static inline __m512i _mm512_zextsi128_si512(__m128i a) { - __m128i r; - __asm__ volatile ("vmovdqa %1,%0" : "=x" (r) : "x" (a)); - return _mm512_castsi128_si512(r); -} -#endif // __AVX512F__ -#endif // gcc/AppleClang version test - -#endif // __AVX2__ - -/* GCC <9 is missing some AVX512 intrinsics. - */ -#ifdef __AVX512F__ -#if (!defined(__clang__) && !defined(__NVCOMPILER) && defined(__GNUC__) && __GNUC__ < 9) -#include - -#define PACK(c0, c1, c2, c3) (((int)(unsigned char)(c0) << 24) | ((int)(unsigned char)(c1) << 16) | \ - ((int)(unsigned char)(c2) << 8) | ((int)(unsigned char)(c3))) - -static inline __m512i _mm512_set_epi8(char __q63, char __q62, char __q61, char __q60, - char __q59, char __q58, char __q57, char __q56, - char __q55, char __q54, char __q53, char __q52, - char __q51, char __q50, char __q49, char __q48, - char __q47, char __q46, char __q45, char __q44, - char __q43, char __q42, char __q41, char __q40, - char __q39, char __q38, char __q37, char __q36, - char __q35, char __q34, char __q33, char __q32, - char __q31, char __q30, char __q29, char __q28, - char __q27, char __q26, char __q25, char __q24, - char __q23, char __q22, char __q21, char __q20, - char __q19, char __q18, char __q17, char __q16, - char __q15, char __q14, char __q13, char __q12, - char __q11, char __q10, char __q09, char __q08, - char __q07, char __q06, char __q05, char __q04, - char __q03, char __q02, char __q01, char __q00) { - return _mm512_set_epi32(PACK(__q63, __q62, __q61, __q60), PACK(__q59, __q58, __q57, __q56), - PACK(__q55, __q54, __q53, __q52), PACK(__q51, __q50, __q49, __q48), - PACK(__q47, __q46, __q45, __q44), PACK(__q43, __q42, __q41, __q40), - PACK(__q39, __q38, __q37, __q36), PACK(__q35, __q34, __q33, __q32), - PACK(__q31, __q30, __q29, __q28), PACK(__q27, __q26, __q25, __q24), - PACK(__q23, __q22, __q21, __q20), PACK(__q19, __q18, __q17, __q16), - PACK(__q15, __q14, __q13, __q12), PACK(__q11, __q10, __q09, __q08), - PACK(__q07, __q06, __q05, __q04), PACK(__q03, __q02, __q01, __q00)); -} - -#undef PACK - -#endif // gcc version test -#endif // __AVX512F__ - -/* Missing zero-extension AVX and AVX512 intrinsics. - * Fixed in Microsoft Visual Studio 2017 version 15.7 - * https://developercommunity.visualstudio.com/t/missing-zero-extension-avx-and-avx512-intrinsics/175737 - */ -#if defined(_MSC_VER) && _MSC_VER < 1914 -#ifdef __AVX2__ -static inline __m256i _mm256_zextsi128_si256(__m128i a) { - return _mm256_inserti128_si256(_mm256_setzero_si256(), a, 0); -} -#endif // __AVX2__ - -#ifdef __AVX512F__ -static inline __m512i _mm512_zextsi128_si512(__m128i a) { - return _mm512_inserti32x4(_mm512_setzero_si512(), a, 0); -} -#endif // __AVX512F__ -#endif // defined(_MSC_VER) && _MSC_VER < 1914 - -/* Visual C++ toolchains before v142 have constant overflow in AVX512 intrinsics */ -#if defined(_MSC_VER) && defined(__AVX512F__) && !defined(_MM_K0_REG8) -# undef _mm512_extracti32x4_epi32 -# define _mm512_extracti32x4_epi32(v1, e1) _mm512_maskz_extracti32x4_epi32(UINT8_MAX, v1, e1) -#endif - -#if defined(_MSC_VER) && !defined(__clang__) -#include -/* For whatever reason this intrinsic is 64 bit only with MSVC? - * While we don't have 64 bit GPRs, it should at least be able to move it to stack - * or shuffle it over 2 registers */ -#ifdef ARCH_32BIT -/* So, while we can't move directly to a GPR, hopefully this move to - * a stack resident variable doesn't equate to something awful */ -static inline int64_t _mm_cvtsi128_si64(__m128i a) { - union { __m128i v; int64_t i; } u; - u.v = a; - return u.i; -} - -static inline __m128i _mm_cvtsi64_si128(int64_t a) { - return _mm_set_epi64x(0, a); -} -#endif -#endif - -#if defined(__GNUC__) && defined(ARCH_X86) && defined(ARCH_32BIT) && !defined(__clang__) -static inline int64_t _mm_cvtsi128_si64(__m128i a) { - union { __m128i v; int64_t i; } u; - u.v = a; - return u.i; -} -#define _mm_cvtsi64_si128(a) _mm_set_epi64x(0, a) -#endif - -#endif // include guard X86_INTRINS_H diff --git a/modules/zlib/src/arch/x86/x86_natives.h b/modules/zlib/src/arch/x86/x86_natives.h deleted file mode 100644 index a39b7a51f0..0000000000 --- a/modules/zlib/src/arch/x86/x86_natives.h +++ /dev/null @@ -1,57 +0,0 @@ -/* x86_natives.h -- x86 compile-time feature detection macros. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef X86_NATIVES_H_ -#define X86_NATIVES_H_ - -#if defined(__SSE2__) || (defined(ARCH_X86) && defined(ARCH_64BIT)) -# ifdef X86_SSE2 -# define X86_SSE2_NATIVE -# endif -#endif -#if defined(__SSSE3__) -# ifdef X86_SSSE3 -# define X86_SSSE3_NATIVE -# endif -#endif -#if defined(__SSE4_1__) -# ifdef X86_SSE41 -# define X86_SSE41_NATIVE -# endif -#endif -#if defined(__SSE4_2__) -# ifdef X86_SSE42 -# define X86_SSE42_NATIVE -# endif -#endif -#if defined(__PCLMUL__) -# ifdef X86_PCLMULQDQ_CRC -# define X86_PCLMULQDQ_NATIVE -# endif -#endif -#if defined(__AVX2__) -# ifdef X86_AVX2 -# define X86_AVX2_NATIVE -# endif -#endif -#if defined(__AVX512F__) && defined(__AVX512DQ__) && defined(__AVX512BW__) && defined(__AVX512VL__) -# ifdef X86_AVX512 -# define X86_AVX512_NATIVE -# endif -#endif -#if defined(__AVX512VNNI__) -# ifdef X86_AVX512VNNI -# define X86_AVX512VNNI_NATIVE -# endif -#endif -#if defined(__VPCLMULQDQ__) -# if defined(X86_VPCLMULQDQ_AVX2) && defined(X86_AVX2_NATIVE) -# define X86_VPCLMULQDQ_AVX2_NATIVE -# endif -# if defined(X86_VPCLMULQDQ_AVX512) && defined(X86_AVX512_NATIVE) -# define X86_VPCLMULQDQ_AVX512_NATIVE -# endif -#endif - -#endif /* X86_NATIVES_H_ */ diff --git a/modules/zlib/src/arch_functions.h b/modules/zlib/src/arch_functions.h deleted file mode 100644 index d5b152e732..0000000000 --- a/modules/zlib/src/arch_functions.h +++ /dev/null @@ -1,56 +0,0 @@ -/* arch_functions.h -- Arch-specific function prototypes. - * Copyright (C) 2017 Hans Kristian Rosbach - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef CPU_FUNCTIONS_H_ -#define CPU_FUNCTIONS_H_ - -#include "zbuild.h" -#include "zutil.h" -#include "deflate.h" -#include "fallback_builtins.h" - -#if defined(X86_FEATURES) -# include "arch/x86/x86_functions.h" -#elif defined(ARM_FEATURES) -# include "arch/arm/arm_functions.h" -#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) -# include "arch/power/power_functions.h" -#elif defined(S390_FEATURES) -# include "arch/s390/s390_functions.h" -#elif defined(RISCV_FEATURES) -# include "arch/riscv/riscv_functions.h" -#elif defined(LOONGARCH_FEATURES) -# include "arch/loongarch/loongarch_functions.h" -#else -/* No architecture detected - all fallbacks needed */ -# ifndef WITH_ALL_FALLBACKS -# define WITH_ALL_FALLBACKS -# endif -#endif - -#ifdef WITH_ALL_FALLBACKS -# ifndef ADLER32_FALLBACK -# define ADLER32_FALLBACK -# endif -# ifndef CHUNKSET_FALLBACK -# define CHUNKSET_FALLBACK -# endif -# ifndef COMPARE256_FALLBACK -# define COMPARE256_FALLBACK -# endif -# ifndef CRC32_BRAID_FALLBACK -# define CRC32_BRAID_FALLBACK -# endif -# if !defined(CRC32_CHORBA_FALLBACK) && !defined(WITHOUT_CHORBA) -# define CRC32_CHORBA_FALLBACK -# endif -# ifndef SLIDE_HASH_FALLBACK -# define SLIDE_HASH_FALLBACK -# endif -#endif - -#include "arch/generic/generic_functions.h" - -#endif diff --git a/modules/zlib/src/arch_natives.h b/modules/zlib/src/arch_natives.h deleted file mode 100644 index 5fe44516d4..0000000000 --- a/modules/zlib/src/arch_natives.h +++ /dev/null @@ -1,24 +0,0 @@ -/* arch_natives.h -- Compile-time feature detection macros for all architectures. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ARCH_NATIVES_H_ -#define ARCH_NATIVES_H_ - -#include "zbuild.h" - -#if defined(X86_FEATURES) -# include "arch/x86/x86_natives.h" -#elif defined(ARM_FEATURES) -# include "arch/arm/arm_natives.h" -#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) -# include "arch/power/power_natives.h" -#elif defined(S390_FEATURES) -# include "arch/s390/s390_natives.h" -#elif defined(RISCV_FEATURES) -# include "arch/riscv/riscv_natives.h" -#elif defined(LOONGARCH_FEATURES) -# include "arch/loongarch/loongarch_natives.h" -#endif - -#endif /* ARCH_NATIVES_H_ */ diff --git a/modules/zlib/src/chunkcopy.h b/modules/zlib/src/chunkcopy.h new file mode 100644 index 0000000000..70a5686008 --- /dev/null +++ b/modules/zlib/src/chunkcopy.h @@ -0,0 +1,425 @@ +/* chunkcopy.h -- fast chunk copy and set operations + * Copyright (C) 2017 ARM, Inc. + * Copyright 2017 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the Chromium source repository LICENSE file. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef CHUNKCOPY_H +#define CHUNKCOPY_H + +#include +#include "zutil.h" + +#define Z_STATIC_ASSERT(name, assert) typedef char name[(assert) ? 1 : -1] + +#if __STDC_VERSION__ >= 199901L +#define Z_RESTRICT restrict +#else +#define Z_RESTRICT +#endif + +#if defined(__clang__) || defined(__GNUC__) || defined(__llvm__) +#define Z_BUILTIN_MEMCPY __builtin_memcpy +#else +#define Z_BUILTIN_MEMCPY zmemcpy +#endif + +#if defined(INFLATE_CHUNK_SIMD_NEON) +#include +typedef uint8x16_t z_vec128i_t; +#elif defined(INFLATE_CHUNK_SIMD_SSE2) +#include +typedef __m128i z_vec128i_t; +#else +#error chunkcopy.h inflate chunk SIMD is not defined for your build target +#endif + +#ifdef _MSC_VER +#if _MSC_VER < 1900 +#define inline +#endif +#endif + +/* + * chunk copy type: the z_vec128i_t type size should be exactly 128-bits + * and equal to CHUNKCOPY_CHUNK_SIZE. + */ +#define CHUNKCOPY_CHUNK_SIZE sizeof(z_vec128i_t) + +Z_STATIC_ASSERT(vector_128_bits_wide, + CHUNKCOPY_CHUNK_SIZE == sizeof(int8_t) * 16); + +/* + * Ask the compiler to perform a wide, unaligned load with a machine + * instruction appropriate for the z_vec128i_t type. + */ +static inline z_vec128i_t loadchunk( + const unsigned char FAR* s) { + z_vec128i_t v; + Z_BUILTIN_MEMCPY(&v, s, sizeof(v)); + return v; +} + +/* + * Ask the compiler to perform a wide, unaligned store with a machine + * instruction appropriate for the z_vec128i_t type. + */ +static inline void storechunk( + unsigned char FAR* d, + const z_vec128i_t v) { + Z_BUILTIN_MEMCPY(d, &v, sizeof(v)); +} + +/* + * Perform a memcpy-like operation, assuming that length is non-zero and that + * it's OK to overwrite at least CHUNKCOPY_CHUNK_SIZE bytes of output even if + * the length is shorter than this. + * + * It also guarantees that it will properly unroll the data if the distance + * between `out` and `from` is at least CHUNKCOPY_CHUNK_SIZE, which we rely on + * in chunkcopy_relaxed(). + * + * Aside from better memory bus utilisation, this means that short copies + * (CHUNKCOPY_CHUNK_SIZE bytes or fewer) will fall straight through the loop + * without iteration, which will hopefully make the branch prediction more + * reliable. + */ +static inline unsigned char FAR* chunkcopy_core( + unsigned char FAR* out, + const unsigned char FAR* from, + unsigned len) { + const int bump = (--len % CHUNKCOPY_CHUNK_SIZE) + 1; + storechunk(out, loadchunk(from)); + out += bump; + from += bump; + len /= CHUNKCOPY_CHUNK_SIZE; + while (len-- > 0) { + storechunk(out, loadchunk(from)); + out += CHUNKCOPY_CHUNK_SIZE; + from += CHUNKCOPY_CHUNK_SIZE; + } + return out; +} + +/* + * Like chunkcopy_core(), but avoid writing beyond of legal output. + * + * Accepts an additional pointer to the end of safe output. A generic safe + * copy would use (out + len), but it's normally the case that the end of the + * output buffer is beyond the end of the current copy, and this can still be + * exploited. + */ +static inline unsigned char FAR* chunkcopy_core_safe( + unsigned char FAR* out, + const unsigned char FAR* from, + unsigned len, + unsigned char FAR* limit) { + Assert(out + len <= limit, "chunk copy exceeds safety limit"); + if ((limit - out) < (ptrdiff_t)CHUNKCOPY_CHUNK_SIZE) { + const unsigned char FAR* Z_RESTRICT rfrom = from; + if (len & 8) { + Z_BUILTIN_MEMCPY(out, rfrom, 8); + out += 8; + rfrom += 8; + } + if (len & 4) { + Z_BUILTIN_MEMCPY(out, rfrom, 4); + out += 4; + rfrom += 4; + } + if (len & 2) { + Z_BUILTIN_MEMCPY(out, rfrom, 2); + out += 2; + rfrom += 2; + } + if (len & 1) { + *out++ = *rfrom++; + } + return out; + } + return chunkcopy_core(out, from, len); +} + +/* + * Perform short copies until distance can be rewritten as being at least + * CHUNKCOPY_CHUNK_SIZE. + * + * Assumes it's OK to overwrite at least the first 2*CHUNKCOPY_CHUNK_SIZE + * bytes of output even if the copy is shorter than this. This assumption + * holds within zlib inflate_fast(), which starts every iteration with at + * least 258 bytes of output space available (258 being the maximum length + * output from a single token; see inffast.c). + */ +static inline unsigned char FAR* chunkunroll_relaxed( + unsigned char FAR* out, + unsigned FAR* dist, + unsigned FAR* len) { + const unsigned char FAR* from = out - *dist; + while (*dist < *len && *dist < CHUNKCOPY_CHUNK_SIZE) { + storechunk(out, loadchunk(from)); + out += *dist; + *len -= *dist; + *dist += *dist; + } + return out; +} + +#if defined(INFLATE_CHUNK_SIMD_NEON) +/* + * v_load64_dup(): load *src as an unaligned 64-bit int and duplicate it in + * every 64-bit component of the 128-bit result (64-bit int splat). + */ +static inline z_vec128i_t v_load64_dup(const void* src) { + return vcombine_u8(vld1_u8(src), vld1_u8(src)); +} + +/* + * v_load32_dup(): load *src as an unaligned 32-bit int and duplicate it in + * every 32-bit component of the 128-bit result (32-bit int splat). + */ +static inline z_vec128i_t v_load32_dup(const void* src) { + int32_t i32; + Z_BUILTIN_MEMCPY(&i32, src, sizeof(i32)); + return vreinterpretq_u8_s32(vdupq_n_s32(i32)); +} + +/* + * v_load16_dup(): load *src as an unaligned 16-bit int and duplicate it in + * every 16-bit component of the 128-bit result (16-bit int splat). + */ +static inline z_vec128i_t v_load16_dup(const void* src) { + int16_t i16; + Z_BUILTIN_MEMCPY(&i16, src, sizeof(i16)); + return vreinterpretq_u8_s16(vdupq_n_s16(i16)); +} + +/* + * v_load8_dup(): load the 8-bit int *src and duplicate it in every 8-bit + * component of the 128-bit result (8-bit int splat). + */ +static inline z_vec128i_t v_load8_dup(const void* src) { + return vld1q_dup_u8((const uint8_t*)src); +} + +/* + * v_store_128(): store the 128-bit vec in a memory destination (that might + * not be 16-byte aligned) void* out. + */ +static inline void v_store_128(void* out, const z_vec128i_t vec) { + vst1q_u8(out, vec); +} + +#elif defined(INFLATE_CHUNK_SIMD_SSE2) +/* + * v_load64_dup(): load *src as an unaligned 64-bit int and duplicate it in + * every 64-bit component of the 128-bit result (64-bit int splat). + */ +static inline z_vec128i_t v_load64_dup(const void* src) { + int64_t i64; + Z_BUILTIN_MEMCPY(&i64, src, sizeof(i64)); +#if 0//def _WIN64 + return _mm_set1_epi64x(i64); +#else + _declspec(align(16)) uint64_t temp[2] = {i64, i64}; + return _mm_load_si128((const __m128i*)temp); +#endif +} + +/* + * v_load32_dup(): load *src as an unaligned 32-bit int and duplicate it in + * every 32-bit component of the 128-bit result (32-bit int splat). + */ +static inline z_vec128i_t v_load32_dup(const void* src) { + int32_t i32; + Z_BUILTIN_MEMCPY(&i32, src, sizeof(i32)); + return _mm_set1_epi32(i32); +} + +/* + * v_load16_dup(): load *src as an unaligned 16-bit int and duplicate it in + * every 16-bit component of the 128-bit result (16-bit int splat). + */ +static inline z_vec128i_t v_load16_dup(const void* src) { + int16_t i16; + Z_BUILTIN_MEMCPY(&i16, src, sizeof(i16)); + return _mm_set1_epi16(i16); +} + +/* + * v_load8_dup(): load the 8-bit int *src and duplicate it in every 8-bit + * component of the 128-bit result (8-bit int splat). + */ +static inline z_vec128i_t v_load8_dup(const void* src) { + return _mm_set1_epi8(*(const char*)src); +} + +/* + * v_store_128(): store the 128-bit vec in a memory destination (that might + * not be 16-byte aligned) void* out. + */ +static inline void v_store_128(void* out, const z_vec128i_t vec) { + _mm_storeu_si128((__m128i*)out, vec); +} +#endif + +/* + * Perform an overlapping copy which behaves as a memset() operation, but + * supporting periods other than one, and assume that length is non-zero and + * that it's OK to overwrite at least CHUNKCOPY_CHUNK_SIZE*3 bytes of output + * even if the length is shorter than this. + */ +static inline unsigned char FAR* chunkset_core( + unsigned char FAR* out, + unsigned period, + unsigned len) { + z_vec128i_t v; + const int bump = ((len - 1) % sizeof(v)) + 1; + + switch (period) { + case 1: + v = v_load8_dup(out - 1); + v_store_128(out, v); + out += bump; + len -= bump; + while (len > 0) { + v_store_128(out, v); + out += sizeof(v); + len -= sizeof(v); + } + return out; + case 2: + v = v_load16_dup(out - 2); + v_store_128(out, v); + out += bump; + len -= bump; + if (len > 0) { + v = v_load16_dup(out - 2); + do { + v_store_128(out, v); + out += sizeof(v); + len -= sizeof(v); + } while (len > 0); + } + return out; + case 4: + v = v_load32_dup(out - 4); + v_store_128(out, v); + out += bump; + len -= bump; + if (len > 0) { + v = v_load32_dup(out - 4); + do { + v_store_128(out, v); + out += sizeof(v); + len -= sizeof(v); + } while (len > 0); + } + return out; + case 8: + v = v_load64_dup(out - 8); + v_store_128(out, v); + out += bump; + len -= bump; + if (len > 0) { + v = v_load64_dup(out - 8); + do { + v_store_128(out, v); + out += sizeof(v); + len -= sizeof(v); + } while (len > 0); + } + return out; + } + out = chunkunroll_relaxed(out, &period, &len); + return chunkcopy_core(out, out - period, len); +} + +/* + * Perform a memcpy-like operation, but assume that length is non-zero and that + * it's OK to overwrite at least CHUNKCOPY_CHUNK_SIZE bytes of output even if + * the length is shorter than this. + * + * Unlike chunkcopy_core() above, no guarantee is made regarding the behaviour + * of overlapping buffers, regardless of the distance between the pointers. + * This is reflected in the `restrict`-qualified pointers, allowing the + * compiler to re-order loads and stores. + */ +static inline unsigned char FAR* chunkcopy_relaxed( + unsigned char FAR* Z_RESTRICT out, + const unsigned char FAR* Z_RESTRICT from, + unsigned len) { + return chunkcopy_core(out, from, len); +} + +/* + * Like chunkcopy_relaxed(), but avoid writing beyond of legal output. + * + * Unlike chunkcopy_core_safe() above, no guarantee is made regarding the + * behaviour of overlapping buffers, regardless of the distance between the + * pointers. This is reflected in the `restrict`-qualified pointers, allowing + * the compiler to re-order loads and stores. + * + * Accepts an additional pointer to the end of safe output. A generic safe + * copy would use (out + len), but it's normally the case that the end of the + * output buffer is beyond the end of the current copy, and this can still be + * exploited. + */ +static inline unsigned char FAR* chunkcopy_safe( + unsigned char FAR* out, + const unsigned char FAR* Z_RESTRICT from, + unsigned len, + unsigned char FAR* limit) { + Assert(out + len <= limit, "chunk copy exceeds safety limit"); + return chunkcopy_core_safe(out, from, len, limit); +} + +/* + * Perform chunky copy within the same buffer, where the source and destination + * may potentially overlap. + * + * Assumes that len > 0 on entry, and that it's safe to write at least + * CHUNKCOPY_CHUNK_SIZE*3 bytes to the output. + */ +static inline unsigned char FAR* chunkcopy_lapped_relaxed( + unsigned char FAR* out, + unsigned dist, + unsigned len) { + if (dist < len && dist < CHUNKCOPY_CHUNK_SIZE) { + return chunkset_core(out, dist, len); + } + return chunkcopy_core(out, out - dist, len); +} + +/* + * Behave like chunkcopy_lapped_relaxed(), but avoid writing beyond of legal + * output. + * + * Accepts an additional pointer to the end of safe output. A generic safe + * copy would use (out + len), but it's normally the case that the end of the + * output buffer is beyond the end of the current copy, and this can still be + * exploited. + */ +static inline unsigned char FAR* chunkcopy_lapped_safe( + unsigned char FAR* out, + unsigned dist, + unsigned len, + unsigned char FAR* limit) { + Assert(out + len <= limit, "chunk copy exceeds safety limit"); + if ((limit - out) < (ptrdiff_t)(3 * CHUNKCOPY_CHUNK_SIZE)) { + /* TODO(cavalcantii): try harder to optimise this */ + while (len-- > 0) { + *out = *(out - dist); + out++; + } + return out; + } + return chunkcopy_lapped_relaxed(out, dist, len); +} + +#undef Z_STATIC_ASSERT +#undef Z_RESTRICT +#undef Z_BUILTIN_MEMCPY + +#endif /* CHUNKCOPY_H */ diff --git a/modules/zlib/src/chunkset_tpl.h b/modules/zlib/src/chunkset_tpl.h deleted file mode 100644 index 82511f0e8c..0000000000 --- a/modules/zlib/src/chunkset_tpl.h +++ /dev/null @@ -1,281 +0,0 @@ -/* chunkset_tpl.h -- inline functions to copy small data chunks. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include - -/* Returns the chunk size */ -static inline size_t CHUNKSIZE(void) { - return sizeof(chunk_t); -} - -/* Behave like memcpy, but assume that it's OK to overwrite at least - chunk_t bytes of output even if the length is shorter than this, - that the length is non-zero, and that `from` lags `out` by at least - sizeof chunk_t bytes (or that they don't overlap at all or simply that - the distance is less than the length of the copy). - - Aside from better memory bus utilization, this means that short copies - (chunk_t bytes or fewer) will fall straight through the loop - without iteration, which will hopefully make the branch prediction more - reliable. */ -#ifndef HAVE_CHUNKCOPY -static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, size_t len) { - Assert(len > 0, "chunkcopy should never have a length 0"); - chunk_t chunk; - size_t align = ((len - 1) % sizeof(chunk_t)) + 1; - loadchunk(from, &chunk); - storechunk(out, &chunk); - out += align; - from += align; - len -= align; - while (len > 0) { - loadchunk(from, &chunk); - storechunk(out, &chunk); - out += sizeof(chunk_t); - from += sizeof(chunk_t); - len -= sizeof(chunk_t); - } - return out; -} -#endif - -/* Perform short copies until distance can be rewritten as being at least - sizeof chunk_t. - - This assumes that it's OK to overwrite at least the first - 2*sizeof(chunk_t) bytes of output even if the copy is shorter than this. - This assumption holds because inflate_fast() starts every iteration with at - least 258 bytes of output space available (258 being the maximum length - output from a single token; see inflate_fast()'s assumptions below). */ -static inline uint8_t* CHUNKUNROLL(uint8_t *out, unsigned *dist, unsigned *len) { - unsigned char const *from = out - *dist; - chunk_t chunk; - while (*dist < *len && *dist < sizeof(chunk_t)) { - loadchunk(from, &chunk); - storechunk(out, &chunk); - out += *dist; - *len -= *dist; - *dist += *dist; - } - return out; -} - -#ifndef HAVE_CHUNK_MAG -/* Loads a magazine to feed into memory of the pattern */ -static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) { - /* This code takes string of length dist from "from" and repeats - * it for as many times as can fit in a chunk_t (vector register) */ - size_t cpy_dist; - size_t bytes_remaining = sizeof(chunk_t); - chunk_t chunk_load; - uint8_t *cur_chunk = (uint8_t *)&chunk_load; - while (bytes_remaining) { - cpy_dist = MIN(dist, bytes_remaining); - memcpy(cur_chunk, buf, cpy_dist); - bytes_remaining -= cpy_dist; - cur_chunk += cpy_dist; - /* This allows us to bypass an expensive integer division since we're effectively - * counting in this loop, anyway */ - *chunk_rem = cpy_dist; - } - - return chunk_load; -} -#endif - -#if defined(HAVE_HALF_CHUNK) && !defined(HAVE_HALFCHUNKCOPY) -static inline uint8_t* HALFCHUNKCOPY(uint8_t *out, uint8_t const *from, size_t len) { - Assert(len > 0, "halfchunkcopy should never have a length 0"); - halfchunk_t chunk; - size_t align = ((len - 1) % sizeof(halfchunk_t)) + 1; - loadhalfchunk(from, &chunk); - storehalfchunk(out, &chunk); - out += align; - from += align; - len -= align; - while (len > 0) { - loadhalfchunk(from, &chunk); - storehalfchunk(out, &chunk); - out += sizeof(halfchunk_t); - from += sizeof(halfchunk_t); - len -= sizeof(halfchunk_t); - } - return out; -} -#endif - -/* Copy DIST bytes from OUT - DIST into OUT + DIST * k, for 0 <= k < LEN/DIST. - Return OUT + LEN. */ -static inline uint8_t* CHUNKMEMSET(uint8_t *out, uint8_t *from, size_t len) { - /* Debug performance related issues when len < sizeof(uint64_t): - Assert(len >= sizeof(uint64_t), "chunkmemset should be called on larger chunks"); */ - Assert(from != out, "chunkmemset cannot have a distance 0"); - - chunk_t chunk_load; - size_t chunk_mod = 0; - size_t adv_amount; - size_t dist = (size_t)ABS(out - from); - - /* We are supporting the case for when we are reading bytes from ahead in the buffer. - * We now have to handle this, though it wasn't _quite_ clear if this rare circumstance - * always needed to be handled here or if we're just now seeing it because we are - * dispatching to this function, more */ - if (out < from && dist < len) { -#ifdef HAVE_MASKED_READWRITE - /* We can still handle this case if we can mitigate over writing _and_ we - * fit the entirety of the copy length with one load */ - if (len <= sizeof(chunk_t)) { - /* Tempting to add a goto to the block below but hopefully most compilers - * collapse these identical code segments as one label to jump to */ - return CHUNKCOPY(out, from, len); - } -#endif - /* Here the memmove semantics match perfectly, as when this happens we are - * effectively sliding down the contents of memory by dist bytes */ - memmove(out, from, len); - return out + len; - } - - if (dist == 1) { - memset(out, *from, len); - return out + len; - } else if (dist >= sizeof(chunk_t)) { - return CHUNKCOPY(out, from, len); - } - - /* Only AVX2+ as there's 128 bit vectors and 256 bit. We allow for shorter vector - * lengths because they serve to allow more cases to fall into chunkcopy, as the - * distance of the shorter length is still deemed a safe distance. We rewrite this - * here rather than calling the ssse3 variant directly now because doing so required - * dispatching to another function and broke inlining for this function entirely. We - * also can merge an assert and some remainder peeling behavior into the same code blocks, - * making the code a little smaller. */ -#ifdef HAVE_HALF_CHUNK - if (len <= sizeof(halfchunk_t)) { - if (dist >= sizeof(halfchunk_t)) - return HALFCHUNKCOPY(out, from, len); - - if ((dist % 2) != 0 || dist == 6) { - halfchunk_t halfchunk_load = GET_HALFCHUNK_MAG(from, &chunk_mod, dist); - - if (len == sizeof(halfchunk_t)) { - storehalfchunk(out, &halfchunk_load); - len -= sizeof(halfchunk_t); - out += sizeof(halfchunk_t); - } - - chunk_load = halfchunk2whole(&halfchunk_load); - goto rem_bytes; - } - } -#endif - -#ifdef HAVE_CHUNKMEMSET_2 - if (dist == 2) { - chunkmemset_2(from, &chunk_load); - } else -#endif -#ifdef HAVE_CHUNKMEMSET_4 - if (dist == 4) { - chunkmemset_4(from, &chunk_load); - } else -#endif -#ifdef HAVE_CHUNKMEMSET_8 - if (dist == 8) { - chunkmemset_8(from, &chunk_load); - } else -#endif -#ifdef HAVE_CHUNKMEMSET_16 - if (dist == 16) { - chunkmemset_16(from, &chunk_load); - } else -#endif - chunk_load = GET_CHUNK_MAG(from, &chunk_mod, dist); - - adv_amount = sizeof(chunk_t) - chunk_mod; - - while (len >= (2 * sizeof(chunk_t))) { - storechunk(out, &chunk_load); - storechunk(out + adv_amount, &chunk_load); - out += 2 * adv_amount; - len -= 2 * adv_amount; - } - - /* If we don't have a "dist" length that divides evenly into a vector - * register, we can write the whole vector register but we need only - * advance by the amount of the whole string that fits in our chunk_t. - * If we do divide evenly into the vector length, adv_amount = chunk_t size*/ - while (len >= sizeof(chunk_t)) { - storechunk(out, &chunk_load); - len -= adv_amount; - out += adv_amount; - } - -#ifdef HAVE_HALF_CHUNK -rem_bytes: -#endif - if (len) { - memcpy(out, &chunk_load, len); - out += len; - } - - return out; -} - -Z_INTERNAL uint8_t* CHUNKMEMSET_SAFE(uint8_t *out, uint8_t *from, size_t len, size_t left) { -#if OPTIMAL_CMP < 32 - static const uintptr_t align_mask = 7; -#elif OPTIMAL_CMP == 32 - static const uintptr_t align_mask = 3; -#endif - - len = MIN(len, left); - -#if OPTIMAL_CMP < 64 - while (((uintptr_t)out & align_mask) && (len > 0)) { - *out++ = *from++; - --len; - --left; - } -#endif - -#ifndef HAVE_MASKED_READWRITE - if (UNLIKELY(left < sizeof(chunk_t))) { - while (len > 0) { - *out++ = *from++; - --len; - } - - return out; - } -#endif - - if (len) - out = CHUNKMEMSET(out, from, len); - - return out; -} - -static inline uint8_t *CHUNKCOPY_SAFE(uint8_t *out, uint8_t *from, size_t len, uint8_t *safe) -{ - if (out == from) - return out + len; - - size_t safelen = (safe - out); - len = MIN(len, safelen); - -#ifndef HAVE_MASKED_READWRITE - size_t from_dist = (size_t)ABS(safe - from); - if (UNLIKELY(from_dist < sizeof(chunk_t) || safelen < sizeof(chunk_t))) { - while (len--) { - *out++ = *from++; - } - - return out; - } -#endif - - return CHUNKMEMSET(out, from, len); -} diff --git a/modules/zlib/src/compare256_rle.h b/modules/zlib/src/compare256_rle.h deleted file mode 100644 index 37a9ab30da..0000000000 --- a/modules/zlib/src/compare256_rle.h +++ /dev/null @@ -1,61 +0,0 @@ -/* compare256_rle.h -- 256 byte run-length encoding comparison - * Copyright (C) 2022 Nathan Moinvaziri - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zendian.h" -#include "zmemory.h" -#include "fallback_builtins.h" - -typedef uint32_t (*compare256_rle_func)(const uint8_t* src0, const uint8_t* src1); - -/* 8-bit RLE comparison for hardware without unaligned loads */ -static inline uint32_t compare256_rle_8(const uint8_t *src0, const uint8_t *src1) { - uint32_t len = 0; - uint8_t val = *src0; - - do { - if (val != src1[0]) - return len; - if (val != src1[1]) - return len + 1; - if (val != src1[2]) - return len + 2; - if (val != src1[3]) - return len + 3; - if (val != src1[4]) - return len + 4; - if (val != src1[5]) - return len + 5; - if (val != src1[6]) - return len + 6; - if (val != src1[7]) - return len + 7; - src1 += 8, len += 8; - } while (len < 256); - - return 256; -} - -/* 64-bit RLE comparison for hardware with unaligned loads */ -static inline uint32_t compare256_rle_64(const uint8_t *src0, const uint8_t *src1) { - uint32_t src0_cmp32, len = 0; - uint16_t src0_cmp; - uint64_t sv, mv, diff; - - src0_cmp = zng_memread_2(src0); - src0_cmp32 = ((uint32_t)src0_cmp << 16) | src0_cmp; - sv = ((uint64_t)src0_cmp32 << 32) | src0_cmp32; - - do { - mv = zng_memread_8(src1); - diff = sv ^ mv; - if (diff) - return len + zng_first_diff_byte64(diff); - - src1 += 8, len += 8; - } while (len < 256); - - return 256; -} diff --git a/modules/zlib/src/compress.c b/modules/zlib/src/compress.c index cc6e8d9601..e2db404abf 100644 --- a/modules/zlib/src/compress.c +++ b/modules/zlib/src/compress.c @@ -3,19 +3,10 @@ * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" -#include "zutil.h" +/* @(#) $Id$ */ -/* =========================================================================== - * Architecture-specific hooks. - */ -#ifdef S390_DFLTCC_DEFLATE -# include "arch/s390/dfltcc_common.h" -#else -/* Returns the upper bound on compressed data length based on uncompressed data length, assuming default settings. - * Zero means that arch-specific deflation code behaves identically to the regular zlib-ng algorithms. */ -# define DEFLATE_BOUND_COMPLEN(source_len) 0 -#endif +#define ZLIB_INTERNAL +#include "zlib.h" /* =========================================================================== Compresses the source buffer into the destination buffer. The level @@ -28,71 +19,68 @@ memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ -z_int32_t Z_EXPORT PREFIX(compress2)(unsigned char *dest, z_uintmax_t *destLen, const unsigned char *source, - z_uintmax_t sourceLen, z_int32_t level) { - PREFIX3(stream) stream; +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; int err; - const unsigned int max = (unsigned int)-1; - z_size_t left; + const uInt max = (uInt)-1; + uLong left; left = *destLen; *destLen = 0; - stream.zalloc = NULL; - stream.zfree = NULL; - stream.opaque = NULL; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; - err = PREFIX(deflateInit)(&stream, level); - if (err != Z_OK) - return err; + err = deflateInit(&stream, level); + if (err != Z_OK) return err; stream.next_out = dest; stream.avail_out = 0; - stream.next_in = (z_const unsigned char *)source; + stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; do { if (stream.avail_out == 0) { - stream.avail_out = left > (unsigned long)max ? max : (unsigned int)left; + stream.avail_out = left > (uLong)max ? max : (uInt)left; left -= stream.avail_out; } if (stream.avail_in == 0) { - stream.avail_in = sourceLen > (unsigned long)max ? max : (unsigned int)sourceLen; + stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; sourceLen -= stream.avail_in; } - err = PREFIX(deflate)(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); + err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); } while (err == Z_OK); *destLen = stream.total_out; - PREFIX(deflateEnd)(&stream); + deflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== */ -z_int32_t Z_EXPORT PREFIX(compress)(unsigned char *dest, z_uintmax_t *destLen, const unsigned char *source, z_uintmax_t sourceLen) { - return PREFIX(compress2)(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then + If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ -z_uintmax_t Z_EXPORT PREFIX(compressBound)(z_uintmax_t sourceLen) { - z_uintmax_t complen = DEFLATE_BOUND_COMPLEN(sourceLen); - - if (complen > 0) - /* Architecture-specific code provided an upper bound. */ - return complen + ZLIB_WRAPLEN; - -#ifndef NO_QUICK_STRATEGY - return sourceLen /* The source size itself */ - + (sourceLen == 0 ? 1 : 0) /* Always at least one byte for any input */ - + (sourceLen < 9 ? 1 : 0) /* One extra byte for lengths less than 9 */ - + DEFLATE_QUICK_OVERHEAD(sourceLen) /* Source encoding overhead, padded to next full byte */ - + DEFLATE_BLOCK_OVERHEAD /* Deflate block overhead bytes */ - + ZLIB_WRAPLEN; /* zlib wrapper */ -#else - return sourceLen + (sourceLen >> 4) + 7 + ZLIB_WRAPLEN; -#endif +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; } diff --git a/modules/zlib/src/cpu_features.c b/modules/zlib/src/cpu_features.c deleted file mode 100644 index fde6519290..0000000000 --- a/modules/zlib/src/cpu_features.c +++ /dev/null @@ -1,25 +0,0 @@ -/* cpu_features.c -- CPU architecture feature check - * Copyright (C) 2017 Hans Kristian Rosbach - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "cpu_features.h" -#include - -Z_INTERNAL void cpu_check_features(struct cpu_features *features) { - memset(features, 0, sizeof(struct cpu_features)); -#if defined(X86_FEATURES) - x86_check_features(&features->x86); -#elif defined(ARM_FEATURES) - arm_check_features(&features->arm); -#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) - power_check_features(&features->power); -#elif defined(S390_FEATURES) - s390_check_features(&features->s390); -#elif defined(RISCV_FEATURES) - riscv_check_features(&features->riscv); -#elif defined(LOONGARCH_FEATURES) - loongarch_check_features(&features->loongarch); -#endif -} diff --git a/modules/zlib/src/cpu_features.h b/modules/zlib/src/cpu_features.h deleted file mode 100644 index 2b6cc4e843..0000000000 --- a/modules/zlib/src/cpu_features.h +++ /dev/null @@ -1,47 +0,0 @@ -/* cpu_features.h -- CPU architecture feature check - * Copyright (C) 2017 Hans Kristian Rosbach - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef CPU_FEATURES_H_ -#define CPU_FEATURES_H_ - -#ifndef DISABLE_RUNTIME_CPU_DETECTION - -#if defined(X86_FEATURES) -# include "arch/x86/x86_features.h" -#elif defined(ARM_FEATURES) -# include "arch/arm/arm_features.h" -#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) -# include "arch/power/power_features.h" -#elif defined(S390_FEATURES) -# include "arch/s390/s390_features.h" -#elif defined(RISCV_FEATURES) -# include "arch/riscv/riscv_features.h" -#elif defined(LOONGARCH_FEATURES) -# include "arch/loongarch/loongarch_features.h" -#endif - -struct cpu_features { -#if defined(X86_FEATURES) - struct x86_cpu_features x86; -#elif defined(ARM_FEATURES) - struct arm_cpu_features arm; -#elif defined(PPC_FEATURES) || defined(POWER_FEATURES) - struct power_cpu_features power; -#elif defined(S390_FEATURES) - struct s390_cpu_features s390; -#elif defined(RISCV_FEATURES) - struct riscv_cpu_features riscv; -#elif defined(LOONGARCH_FEATURES) - struct loongarch_cpu_features loongarch; -#else - char empty; -#endif -}; - -void cpu_check_features(struct cpu_features *features); - -#endif - -#endif diff --git a/modules/zlib/src/crc32.c b/modules/zlib/src/crc32.c index e31fff62af..eae4f721a7 100644 --- a/modules/zlib/src/crc32.c +++ b/modules/zlib/src/crc32.c @@ -1,46 +1,496 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2022 Mark Adler + * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * - * This interleaved implementation of a CRC makes use of pipelined multiple - * arithmetic-logic units, commonly found in modern CPU cores. It is due to - * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ -#include "zbuild.h" -#include "functable.h" -#include "crc32_braid_tbl.h" +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "deflate.h" +#include "x86.h" +#include "crc32_simd.h" +#include "zutil.h" /* for STDC and FAR definitions */ + +/* Definitions for doing the crc four data bytes at a time. */ +#if !defined(NOBYFOUR) && defined(Z_U4) +# define BYFOUR +#endif +#ifdef BYFOUR + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, z_size_t)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, z_size_t)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local z_crc_t FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const z_crc_t FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + z_crc_t c; + int n, k; + z_crc_t poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (z_crc_t)1 << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (z_crc_t)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = ZSWAP32(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = ZSWAP32(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const z_crc_t FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const z_crc_t FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const z_crc_t FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} /* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 -const uint32_t * Z_EXPORT PREFIX(get_crc_table)(void) { - return (const uint32_t *)crc_table; -} +/* ========================================================================= */ +unsigned long ZEXPORT crc32_z(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ +#if defined(CRC32_SIMD_SSE42_PCLMUL) + /* + * Use x86 sse4.2+pclmul SIMD to compute the crc32. Since this + * routine can be freely used, check the CPU features here. + */ + if (buf == Z_NULL) { + if (!len) /* Assume user is calling crc32(0, NULL, 0); */ + x86_check_features(); + return 0UL; + } -#ifdef ZLIB_COMPAT -unsigned long Z_EXPORT PREFIX(crc32_z)(unsigned long crc, const unsigned char *buf, size_t len) { - if (buf == NULL) - return CRC32_INITIAL_VALUE; - return (unsigned long)FUNCTABLE_CALL(crc32)((uint32_t)crc, buf, len); -} + if (x86_cpu_enable_simd && len >= Z_CRC32_SSE42_MINIMUM_LENGTH) { + /* crc32 16-byte chunks */ + z_size_t chunk_size = len & ~Z_CRC32_SSE42_CHUNKSIZE_MASK; + crc = ~crc32_sse42_simd_(buf, chunk_size, ~(uint32_t)crc); + /* check remaining data */ + len -= chunk_size; + if (!len) + return crc; + /* Fall into the default crc32 for the remaining data. */ + buf += chunk_size; + } #else -uint32_t Z_EXPORT PREFIX(crc32_z)(uint32_t crc, const unsigned char *buf, size_t len) { - if (buf == NULL) - return CRC32_INITIAL_VALUE; - return FUNCTABLE_CALL(crc32)(crc, buf, len); -} -#endif + if (buf == Z_NULL) { + return 0UL; + } +#endif /* CRC32_SIMD_SSE42_PCLMUL */ -#ifdef ZLIB_COMPAT -unsigned long Z_EXPORT PREFIX(crc32)(unsigned long crc, const unsigned char *buf, unsigned int len) { - if (buf == NULL) - return CRC32_INITIAL_VALUE; - return (unsigned long)FUNCTABLE_CALL(crc32)((uint32_t)crc, buf, len); +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + z_crc_t endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; } -#else -uint32_t Z_EXPORT PREFIX(crc32)(uint32_t crc, const unsigned char *buf, uint32_t len) { - if (buf == NULL) - return CRC32_INITIAL_VALUE; - return FUNCTABLE_CALL(crc32)(crc, buf, len); + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + return crc32_z(crc, buf, len); +} + +#ifdef BYFOUR + +/* + This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit + integer pointer type. This violates the strict aliasing rule, where a + compiler can assume, for optimization purposes, that two pointers to + fundamentally different types won't ever point to the same memory. This can + manifest as a problem only if one of the pointers is written to. This code + only reads from those pointers. So long as this code remains isolated in + this compilation unit, there won't be a problem. For this reason, this code + should not be copied and pasted into a compilation unit in which other code + writes to the buffer that is passed to these routines. + */ + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = (z_crc_t)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *buf4++; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = ZSWAP32((z_crc_t)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(ZSWAP32(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +ZLIB_INTERNAL void crc_reset(deflate_state *const s) +{ + if (x86_cpu_enable_simd) { + crc_fold_init(s); + return; + } + s->strm->adler = crc32(0L, Z_NULL, 0); +} + +ZLIB_INTERNAL void crc_finalize(deflate_state *const s) +{ + if (x86_cpu_enable_simd) + s->strm->adler = crc_fold_512to32(s); +} + +ZLIB_INTERNAL void copy_with_crc(z_streamp strm, Bytef *dst, long size) +{ + if (x86_cpu_enable_simd) { + crc_fold_copy(strm->state, dst, strm->next_in, size); + return; + } + zmemcpy(dst, strm->next_in, size); + strm->adler = crc32(strm->adler, dst, size); } -#endif diff --git a/modules/zlib/src/crc32.h b/modules/zlib/src/crc32.h new file mode 100644 index 0000000000..9e0c778102 --- /dev/null +++ b/modules/zlib/src/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/modules/zlib/src/crc32_braid_comb.c b/modules/zlib/src/crc32_braid_comb.c deleted file mode 100644 index f253ae10a2..0000000000 --- a/modules/zlib/src/crc32_braid_comb.c +++ /dev/null @@ -1,56 +0,0 @@ -/* crc32_braid_comb.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2022 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * This interleaved implementation of a CRC makes use of pipelined multiple - * arithmetic-logic units, commonly found in modern CPU cores. It is due to - * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. - */ - -#include "zutil.h" -#include "crc32_braid_p.h" -#include "crc32_braid_tbl.h" -#include "crc32_braid_comb_p.h" - -/* ========================================================================= */ -static uint32_t crc32_combine_(uint32_t crc1, uint32_t crc2, z_off64_t len2) { - return multmodp(x2nmodp(len2, 3), crc1) ^ crc2; -} -static uint32_t crc32_combine_gen_(z_off64_t len2) { - return x2nmodp(len2, 3); -} -static uint32_t crc32_combine_op_(uint32_t crc1, uint32_t crc2, const uint32_t op) { - return multmodp(op, crc1) ^ crc2; -} - -/* ========================================================================= */ - -#ifdef ZLIB_COMPAT -unsigned long Z_EXPORT PREFIX(crc32_combine)(unsigned long crc1, unsigned long crc2, z_off_t len2) { - return (unsigned long)crc32_combine_((uint32_t)crc1, (uint32_t)crc2, len2); -} -unsigned long Z_EXPORT PREFIX4(crc32_combine)(unsigned long crc1, unsigned long crc2, z_off64_t len2) { - return (unsigned long)crc32_combine_((uint32_t)crc1, (uint32_t)crc2, len2); -} -unsigned long Z_EXPORT PREFIX(crc32_combine_gen)(z_off_t len2) { - return crc32_combine_gen_(len2); -} -unsigned long Z_EXPORT PREFIX4(crc32_combine_gen)(z_off64_t len2) { - return crc32_combine_gen_(len2); -} -unsigned long Z_EXPORT PREFIX(crc32_combine_op)(unsigned long crc1, unsigned long crc2, const unsigned long op) { - return (unsigned long)crc32_combine_op_((uint32_t)crc1, (uint32_t)crc2, (uint32_t)op); -} -#else -uint32_t Z_EXPORT PREFIX4(crc32_combine)(uint32_t crc1, uint32_t crc2, z_off64_t len2) { - return crc32_combine_(crc1, crc2, len2); -} -uint32_t Z_EXPORT PREFIX(crc32_combine_gen)(z_off64_t len2) { - return crc32_combine_gen_(len2); -} -uint32_t Z_EXPORT PREFIX(crc32_combine_op)(uint32_t crc1, uint32_t crc2, const uint32_t op) { - return crc32_combine_op_(crc1, crc2, op); -} -#endif - -/* ========================================================================= */ diff --git a/modules/zlib/src/crc32_braid_comb_p.h b/modules/zlib/src/crc32_braid_comb_p.h deleted file mode 100644 index a269e7f5b7..0000000000 --- a/modules/zlib/src/crc32_braid_comb_p.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef CRC32_BRAID_COMB_P_H_ -#define CRC32_BRAID_COMB_P_H_ - -/* - Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, - reflected. For speed, this requires that a not be zero. - */ -static uint32_t multmodp(uint32_t a, uint32_t b) { - uint32_t m, p; - - m = (uint32_t)1 << 31; - p = 0; - for (;;) { - if (a & m) { - p ^= b; - if ((a & (m - 1)) == 0) - break; - } - m >>= 1; - b = b & 1 ? (b >> 1) ^ POLY : b >> 1; - } - return p; -} - -/* - Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been - initialized. - */ -static uint32_t x2nmodp(z_off64_t n, unsigned k) { - uint32_t p; - - p = (uint32_t)1 << 31; /* x^0 == 1 */ - while (n) { - if (n & 1) - p = multmodp(x2n_table[k & 31], p); - n >>= 1; - k++; - } - return p; -} - -#endif /* CRC32_BRAID_COMB_P_H_ */ diff --git a/modules/zlib/src/crc32_braid_p.h b/modules/zlib/src/crc32_braid_p.h deleted file mode 100644 index 624e22ecd9..0000000000 --- a/modules/zlib/src/crc32_braid_p.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef CRC32_BRAID_P_H_ -#define CRC32_BRAID_P_H_ - -#include "zendian.h" - -/* Define BRAID_N, valid range is 1..6 */ -#define BRAID_N 5 - -/* Define BRAID_W and the associated z_word_t type. If BRAID_W is not defined, then a braided - calculation is not used, and the associated tables and code are not compiled. - - TODO: According to crc32_braid_c.c, BRAID_N=5, BRAID_W=4 is fastest with Sparc64-VII, - PowerPC POWER9, and MIPS64 Octeon II processors. - */ -#ifdef ARCH_64BIT -# define BRAID_W 8 - typedef uint64_t z_word_t; -# define Z_WORD_FROM_LE(word) Z_U64_FROM_LE(word) -#else -# define BRAID_W 4 - typedef uint32_t z_word_t; -# define Z_WORD_FROM_LE(word) Z_U32_FROM_LE(word) -#endif - -#if BYTE_ORDER == LITTLE_ENDIAN -# define BRAID_TABLE crc_braid_table -#elif BYTE_ORDER == BIG_ENDIAN -# define BRAID_TABLE crc_braid_big_table -#else -# error "No endian defined" -#endif - -/* CRC polynomial. */ -#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ - -#endif /* CRC32_BRAID_P_H_ */ diff --git a/modules/zlib/src/crc32_chorba_p.h b/modules/zlib/src/crc32_chorba_p.h deleted file mode 100644 index 95f92af913..0000000000 --- a/modules/zlib/src/crc32_chorba_p.h +++ /dev/null @@ -1,34 +0,0 @@ -/* crc32_chorba_p.h -- crc32 chorba interface - * Copyright (C) 2021 Nathan Moinvaziri - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef CRC32_CHORBA_P_H_ -#define CRC32_CHORBA_P_H_ - -#include "zendian.h" - -/* Size thresholds for Chorba algorithm variants */ - -#define CHORBA_LARGE_THRESHOLD (sizeof(chorba_word_t) * 64 * 1024) -#define CHORBA_MEDIUM_UPPER_THRESHOLD 32768 -#define CHORBA_MEDIUM_LOWER_THRESHOLD 8192 -#define CHORBA_SMALL_THRESHOLD_64BIT 72 -#ifdef ARCH_64BIT -# define CHORBA_SMALL_THRESHOLD 72 -# define CHORBA_W 8 -# define CHORBA_WORD_FROM_LE(word) Z_U64_FROM_LE(word) - typedef uint64_t chorba_word_t; -#else -# define CHORBA_SMALL_THRESHOLD 80 -# define CHORBA_W 4 -# define CHORBA_WORD_FROM_LE(word) Z_U32_FROM_LE(word) - typedef uint32_t chorba_word_t; -#endif - -Z_INTERNAL uint32_t crc32_chorba_118960_nondestructive(uint32_t crc, const uint8_t *buf, size_t len); -Z_INTERNAL uint32_t crc32_chorba_32768_nondestructive(uint32_t crc, const uint8_t *buf, size_t len); -Z_INTERNAL uint32_t crc32_chorba_small_nondestructive(uint32_t crc, const uint8_t *buf, size_t len); -Z_INTERNAL uint32_t crc32_chorba_small_nondestructive_32bit(uint32_t crc, const uint8_t *buf, size_t len); - -#endif /* CRC32_CHORBA_P_H_ */ diff --git a/modules/zlib/src/crc32_p.h b/modules/zlib/src/crc32_p.h deleted file mode 100644 index 397464a446..0000000000 --- a/modules/zlib/src/crc32_p.h +++ /dev/null @@ -1,54 +0,0 @@ -/* crc32_p.h -- Private inline functions and macros shared with - * different computation of the CRC-32 checksum - * of a data stream. - * Copyright (C) 2026 Nathan Moinvaziri - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef CRC32_P_H -#define CRC32_P_H - -#define CRC_DO1(c, buf, i) c = crc_table[(c ^ buf[i]) & 0xff] ^ (c >> 8) -#define CRC_DO2(c, buf, i) {CRC_DO1(c, buf, i); CRC_DO1(c, buf, i+1);} -#define CRC_DO4(c, buf, i) {CRC_DO2(c, buf, i); CRC_DO2(c, buf, i+2);} -#define CRC_DO8(c, buf, i) {CRC_DO4(c, buf, i); CRC_DO4(c, buf, i+4);} - -Z_FORCEINLINE static uint32_t crc32_copy_small(uint32_t crc, uint8_t *dst, const uint8_t *buf, size_t len, - const int MAX_LEN, const int COPY) { - if (MAX_LEN >= 8) { - while (len >= 8) { - if (COPY) { - memcpy(dst, buf, 8); - dst += 8; - } - CRC_DO8(crc, buf, 0); - buf += 8; - len -= 8; - } - } - if (len & 4) { - if (COPY) { - memcpy(dst, buf, 4); - dst += 4; - } - CRC_DO4(crc, buf, 0); - buf += 4; - } - if (len & 2) { - if (COPY) { - memcpy(dst, buf, 2); - dst += 2; - } - CRC_DO2(crc, buf, 0); - buf += 2; - } - if (len & 1) { - if (COPY) - *dst = *buf; - CRC_DO1(crc, buf, 0); - } - - return crc; -} - -#endif /* CRC32_P_H */ diff --git a/modules/zlib/src/crc32_simd.c b/modules/zlib/src/crc32_simd.c new file mode 100644 index 0000000000..6538652212 --- /dev/null +++ b/modules/zlib/src/crc32_simd.c @@ -0,0 +1,157 @@ +/* crc32_simd.c + * + * Copyright 2017 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the Chromium source repository LICENSE file. + */ + +#include "crc32_simd.h" + +#if defined(CRC32_SIMD_SSE42_PCLMUL) + +/* + * crc32_sse42_simd_(): compute the crc32 of the buffer, where the buffer + * length must be at least 64, and a multiple of 16. Based on: + * + * "Fast CRC Computation for Generic Polynomials Using PCLMULQDQ Instruction" + * V. Gopal, E. Ozturk, et al., 2009, http://intel.ly/2ySEwL0 + */ + +#include +#include +#include + +uint32_t ZLIB_INTERNAL crc32_sse42_simd_( /* SSE4.2+PCLMUL */ + const unsigned char *buf, + z_size_t len, + uint32_t crc) +{ + /* + * Definitions of the bit-reflected domain constants k1,k2,k3, etc and + * the CRC32+Barrett polynomials given at the end of the paper. + */ + static const uint64_t zalign(16) k1k2[] = { 0x0154442bd4, 0x01c6e41596 }; + static const uint64_t zalign(16) k3k4[] = { 0x01751997d0, 0x00ccaa009e }; + static const uint64_t zalign(16) k5k0[] = { 0x0163cd6124, 0x0000000000 }; + static const uint64_t zalign(16) poly[] = { 0x01db710641, 0x01f7011641 }; + + __m128i x0, x1, x2, x3, x4, x5, x6, x7, x8, y5, y6, y7, y8; + + /* + * There's at least one block of 64. + */ + x1 = _mm_loadu_si128((__m128i *)(buf + 0x00)); + x2 = _mm_loadu_si128((__m128i *)(buf + 0x10)); + x3 = _mm_loadu_si128((__m128i *)(buf + 0x20)); + x4 = _mm_loadu_si128((__m128i *)(buf + 0x30)); + + x1 = _mm_xor_si128(x1, _mm_cvtsi32_si128(crc)); + + x0 = _mm_load_si128((__m128i *)k1k2); + + buf += 64; + len -= 64; + + /* + * Parallel fold blocks of 64, if any. + */ + while (len >= 64) + { + x5 = _mm_clmulepi64_si128(x1, x0, 0x00); + x6 = _mm_clmulepi64_si128(x2, x0, 0x00); + x7 = _mm_clmulepi64_si128(x3, x0, 0x00); + x8 = _mm_clmulepi64_si128(x4, x0, 0x00); + + x1 = _mm_clmulepi64_si128(x1, x0, 0x11); + x2 = _mm_clmulepi64_si128(x2, x0, 0x11); + x3 = _mm_clmulepi64_si128(x3, x0, 0x11); + x4 = _mm_clmulepi64_si128(x4, x0, 0x11); + + y5 = _mm_loadu_si128((__m128i *)(buf + 0x00)); + y6 = _mm_loadu_si128((__m128i *)(buf + 0x10)); + y7 = _mm_loadu_si128((__m128i *)(buf + 0x20)); + y8 = _mm_loadu_si128((__m128i *)(buf + 0x30)); + + x1 = _mm_xor_si128(x1, x5); + x2 = _mm_xor_si128(x2, x6); + x3 = _mm_xor_si128(x3, x7); + x4 = _mm_xor_si128(x4, x8); + + x1 = _mm_xor_si128(x1, y5); + x2 = _mm_xor_si128(x2, y6); + x3 = _mm_xor_si128(x3, y7); + x4 = _mm_xor_si128(x4, y8); + + buf += 64; + len -= 64; + } + + /* + * Fold into 128-bits. + */ + x0 = _mm_load_si128((__m128i *)k3k4); + + x5 = _mm_clmulepi64_si128(x1, x0, 0x00); + x1 = _mm_clmulepi64_si128(x1, x0, 0x11); + x1 = _mm_xor_si128(x1, x2); + x1 = _mm_xor_si128(x1, x5); + + x5 = _mm_clmulepi64_si128(x1, x0, 0x00); + x1 = _mm_clmulepi64_si128(x1, x0, 0x11); + x1 = _mm_xor_si128(x1, x3); + x1 = _mm_xor_si128(x1, x5); + + x5 = _mm_clmulepi64_si128(x1, x0, 0x00); + x1 = _mm_clmulepi64_si128(x1, x0, 0x11); + x1 = _mm_xor_si128(x1, x4); + x1 = _mm_xor_si128(x1, x5); + + /* + * Single fold blocks of 16, if any. + */ + while (len >= 16) + { + x2 = _mm_loadu_si128((__m128i *)buf); + + x5 = _mm_clmulepi64_si128(x1, x0, 0x00); + x1 = _mm_clmulepi64_si128(x1, x0, 0x11); + x1 = _mm_xor_si128(x1, x2); + x1 = _mm_xor_si128(x1, x5); + + buf += 16; + len -= 16; + } + + /* + * Fold 128-bits to 64-bits. + */ + x2 = _mm_clmulepi64_si128(x1, x0, 0x10); + x3 = _mm_setr_epi32(~0, 0, ~0, 0); + x1 = _mm_srli_si128(x1, 8); + x1 = _mm_xor_si128(x1, x2); + + x0 = _mm_loadl_epi64((__m128i*)k5k0); + + x2 = _mm_srli_si128(x1, 4); + x1 = _mm_and_si128(x1, x3); + x1 = _mm_clmulepi64_si128(x1, x0, 0x00); + x1 = _mm_xor_si128(x1, x2); + + /* + * Barret reduce to 32-bits. + */ + x0 = _mm_load_si128((__m128i*)poly); + + x2 = _mm_and_si128(x1, x3); + x2 = _mm_clmulepi64_si128(x2, x0, 0x10); + x2 = _mm_and_si128(x2, x3); + x2 = _mm_clmulepi64_si128(x2, x0, 0x00); + x1 = _mm_xor_si128(x1, x2); + + /* + * Return the crc32. + */ + return _mm_extract_epi32(x1, 1); +} + +#endif /* CRC32_SIMD_SSE42_PCLMUL */ diff --git a/modules/zlib/src/crc32_simd.h b/modules/zlib/src/crc32_simd.h new file mode 100644 index 0000000000..4e6f3268e0 --- /dev/null +++ b/modules/zlib/src/crc32_simd.h @@ -0,0 +1,27 @@ +/* crc32_simd.h + * + * Copyright 2017 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the Chromium source repository LICENSE file. + */ + +#include + +#include "zconf.h" +#include "zutil.h" + +/* + * crc32_sse42_simd_(): compute the crc32 of the buffer, where the buffer + * length must be at least 64, and a multiple of 16. + */ +uint32_t ZLIB_INTERNAL crc32_sse42_simd_( + const unsigned char *buf, + z_size_t len, + uint32_t crc); + +/* + * crc32_sse42_simd_ buffer size constraints: see the use in zlib/crc32.c + * for computing the crc32 of an arbitrary length buffer. + */ +#define Z_CRC32_SSE42_MINIMUM_LENGTH 64 +#define Z_CRC32_SSE42_CHUNKSIZE_MASK 15 diff --git a/modules/zlib/src/crc_folding.c b/modules/zlib/src/crc_folding.c new file mode 100644 index 0000000000..48d77744aa --- /dev/null +++ b/modules/zlib/src/crc_folding.c @@ -0,0 +1,493 @@ +/* + * Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ + * instruction. + * + * A white paper describing this algorithm can be found at: + * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Authors: + * Wajdi Feghali + * Jim Guilford + * Vinodh Gopal + * Erdinc Ozturk + * Jim Kukunas + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "deflate.h" + +#include +#include +#include +#include + +#define CRC_LOAD(s) \ + do { \ + __m128i xmm_crc0 = _mm_loadu_si128((__m128i *)s->crc0 + 0);\ + __m128i xmm_crc1 = _mm_loadu_si128((__m128i *)s->crc0 + 1);\ + __m128i xmm_crc2 = _mm_loadu_si128((__m128i *)s->crc0 + 2);\ + __m128i xmm_crc3 = _mm_loadu_si128((__m128i *)s->crc0 + 3);\ + __m128i xmm_crc_part = _mm_loadu_si128((__m128i *)s->crc0 + 4); + +#define CRC_SAVE(s) \ + _mm_storeu_si128((__m128i *)s->crc0 + 0, xmm_crc0);\ + _mm_storeu_si128((__m128i *)s->crc0 + 1, xmm_crc1);\ + _mm_storeu_si128((__m128i *)s->crc0 + 2, xmm_crc2);\ + _mm_storeu_si128((__m128i *)s->crc0 + 3, xmm_crc3);\ + _mm_storeu_si128((__m128i *)s->crc0 + 4, xmm_crc_part);\ + } while (0); + +ZLIB_INTERNAL void crc_fold_init(deflate_state *const s) +{ + CRC_LOAD(s) + + xmm_crc0 = _mm_cvtsi32_si128(0x9db42487); + xmm_crc1 = _mm_setzero_si128(); + xmm_crc2 = _mm_setzero_si128(); + xmm_crc3 = _mm_setzero_si128(); + + CRC_SAVE(s) + + s->strm->adler = 0; +} + +local void fold_1(deflate_state *const s, + __m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3) +{ + const __m128i xmm_fold4 = _mm_set_epi32( + 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + + __m128i x_tmp3; + __m128 ps_crc0, ps_crc3, ps_res; + + x_tmp3 = *xmm_crc3; + + *xmm_crc3 = *xmm_crc0; + *xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); + *xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10); + ps_crc0 = _mm_castsi128_ps(*xmm_crc0); + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + ps_res = _mm_xor_ps(ps_crc0, ps_crc3); + + *xmm_crc0 = *xmm_crc1; + *xmm_crc1 = *xmm_crc2; + *xmm_crc2 = x_tmp3; + *xmm_crc3 = _mm_castps_si128(ps_res); +} + +local void fold_2(deflate_state *const s, + __m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3) +{ + const __m128i xmm_fold4 = _mm_set_epi32( + 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + + __m128i x_tmp3, x_tmp2; + __m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res31, ps_res20; + + x_tmp3 = *xmm_crc3; + x_tmp2 = *xmm_crc2; + + *xmm_crc3 = *xmm_crc1; + *xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); + *xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10); + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + ps_crc1 = _mm_castsi128_ps(*xmm_crc1); + ps_res31= _mm_xor_ps(ps_crc3, ps_crc1); + + *xmm_crc2 = *xmm_crc0; + *xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); + *xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10); + ps_crc0 = _mm_castsi128_ps(*xmm_crc0); + ps_crc2 = _mm_castsi128_ps(*xmm_crc2); + ps_res20= _mm_xor_ps(ps_crc0, ps_crc2); + + *xmm_crc0 = x_tmp2; + *xmm_crc1 = x_tmp3; + *xmm_crc2 = _mm_castps_si128(ps_res20); + *xmm_crc3 = _mm_castps_si128(ps_res31); +} + +local void fold_3(deflate_state *const s, + __m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3) +{ + const __m128i xmm_fold4 = _mm_set_epi32( + 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + + __m128i x_tmp3; + __m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res32, ps_res21, ps_res10; + + x_tmp3 = *xmm_crc3; + + *xmm_crc3 = *xmm_crc2; + *xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01); + *xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10); + ps_crc2 = _mm_castsi128_ps(*xmm_crc2); + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + ps_res32 = _mm_xor_ps(ps_crc2, ps_crc3); + + *xmm_crc2 = *xmm_crc1; + *xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); + *xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10); + ps_crc1 = _mm_castsi128_ps(*xmm_crc1); + ps_crc2 = _mm_castsi128_ps(*xmm_crc2); + ps_res21= _mm_xor_ps(ps_crc1, ps_crc2); + + *xmm_crc1 = *xmm_crc0; + *xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); + *xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x10); + ps_crc0 = _mm_castsi128_ps(*xmm_crc0); + ps_crc1 = _mm_castsi128_ps(*xmm_crc1); + ps_res10= _mm_xor_ps(ps_crc0, ps_crc1); + + *xmm_crc0 = x_tmp3; + *xmm_crc1 = _mm_castps_si128(ps_res10); + *xmm_crc2 = _mm_castps_si128(ps_res21); + *xmm_crc3 = _mm_castps_si128(ps_res32); +} + +local void fold_4(deflate_state *const s, + __m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3) +{ + const __m128i xmm_fold4 = _mm_set_epi32( + 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + + __m128i x_tmp0, x_tmp1, x_tmp2, x_tmp3; + __m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3; + __m128 ps_t0, ps_t1, ps_t2, ps_t3; + __m128 ps_res0, ps_res1, ps_res2, ps_res3; + + x_tmp0 = *xmm_crc0; + x_tmp1 = *xmm_crc1; + x_tmp2 = *xmm_crc2; + x_tmp3 = *xmm_crc3; + + *xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01); + x_tmp0 = _mm_clmulepi64_si128(x_tmp0, xmm_fold4, 0x10); + ps_crc0 = _mm_castsi128_ps(*xmm_crc0); + ps_t0 = _mm_castsi128_ps(x_tmp0); + ps_res0 = _mm_xor_ps(ps_crc0, ps_t0); + + *xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01); + x_tmp1 = _mm_clmulepi64_si128(x_tmp1, xmm_fold4, 0x10); + ps_crc1 = _mm_castsi128_ps(*xmm_crc1); + ps_t1 = _mm_castsi128_ps(x_tmp1); + ps_res1 = _mm_xor_ps(ps_crc1, ps_t1); + + *xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01); + x_tmp2 = _mm_clmulepi64_si128(x_tmp2, xmm_fold4, 0x10); + ps_crc2 = _mm_castsi128_ps(*xmm_crc2); + ps_t2 = _mm_castsi128_ps(x_tmp2); + ps_res2 = _mm_xor_ps(ps_crc2, ps_t2); + + *xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x01); + x_tmp3 = _mm_clmulepi64_si128(x_tmp3, xmm_fold4, 0x10); + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + ps_t3 = _mm_castsi128_ps(x_tmp3); + ps_res3 = _mm_xor_ps(ps_crc3, ps_t3); + + *xmm_crc0 = _mm_castps_si128(ps_res0); + *xmm_crc1 = _mm_castps_si128(ps_res1); + *xmm_crc2 = _mm_castps_si128(ps_res2); + *xmm_crc3 = _mm_castps_si128(ps_res3); +} + +local const unsigned zalign(32) pshufb_shf_table[60] = { + 0x84838281,0x88878685,0x8c8b8a89,0x008f8e8d, /* shl 15 (16 - 1)/shr1 */ + 0x85848382,0x89888786,0x8d8c8b8a,0x01008f8e, /* shl 14 (16 - 3)/shr2 */ + 0x86858483,0x8a898887,0x8e8d8c8b,0x0201008f, /* shl 13 (16 - 4)/shr3 */ + 0x87868584,0x8b8a8988,0x8f8e8d8c,0x03020100, /* shl 12 (16 - 4)/shr4 */ + 0x88878685,0x8c8b8a89,0x008f8e8d,0x04030201, /* shl 11 (16 - 5)/shr5 */ + 0x89888786,0x8d8c8b8a,0x01008f8e,0x05040302, /* shl 10 (16 - 6)/shr6 */ + 0x8a898887,0x8e8d8c8b,0x0201008f,0x06050403, /* shl 9 (16 - 7)/shr7 */ + 0x8b8a8988,0x8f8e8d8c,0x03020100,0x07060504, /* shl 8 (16 - 8)/shr8 */ + 0x8c8b8a89,0x008f8e8d,0x04030201,0x08070605, /* shl 7 (16 - 9)/shr9 */ + 0x8d8c8b8a,0x01008f8e,0x05040302,0x09080706, /* shl 6 (16 -10)/shr10*/ + 0x8e8d8c8b,0x0201008f,0x06050403,0x0a090807, /* shl 5 (16 -11)/shr11*/ + 0x8f8e8d8c,0x03020100,0x07060504,0x0b0a0908, /* shl 4 (16 -12)/shr12*/ + 0x008f8e8d,0x04030201,0x08070605,0x0c0b0a09, /* shl 3 (16 -13)/shr13*/ + 0x01008f8e,0x05040302,0x09080706,0x0d0c0b0a, /* shl 2 (16 -14)/shr14*/ + 0x0201008f,0x06050403,0x0a090807,0x0e0d0c0b /* shl 1 (16 -15)/shr15*/ +}; + +local void partial_fold(deflate_state *const s, const size_t len, + __m128i *xmm_crc0, __m128i *xmm_crc1, + __m128i *xmm_crc2, __m128i *xmm_crc3, + __m128i *xmm_crc_part) +{ + + const __m128i xmm_fold4 = _mm_set_epi32( + 0x00000001, 0x54442bd4, + 0x00000001, 0xc6e41596); + const __m128i xmm_mask3 = _mm_set1_epi32(0x80808080); + + __m128i xmm_shl, xmm_shr, xmm_tmp1, xmm_tmp2, xmm_tmp3; + __m128i xmm_a0_0, xmm_a0_1; + __m128 ps_crc3, psa0_0, psa0_1, ps_res; + + xmm_shl = _mm_load_si128((__m128i *)pshufb_shf_table + (len - 1)); + xmm_shr = xmm_shl; + xmm_shr = _mm_xor_si128(xmm_shr, xmm_mask3); + + xmm_a0_0 = _mm_shuffle_epi8(*xmm_crc0, xmm_shl); + + *xmm_crc0 = _mm_shuffle_epi8(*xmm_crc0, xmm_shr); + xmm_tmp1 = _mm_shuffle_epi8(*xmm_crc1, xmm_shl); + *xmm_crc0 = _mm_or_si128(*xmm_crc0, xmm_tmp1); + + *xmm_crc1 = _mm_shuffle_epi8(*xmm_crc1, xmm_shr); + xmm_tmp2 = _mm_shuffle_epi8(*xmm_crc2, xmm_shl); + *xmm_crc1 = _mm_or_si128(*xmm_crc1, xmm_tmp2); + + *xmm_crc2 = _mm_shuffle_epi8(*xmm_crc2, xmm_shr); + xmm_tmp3 = _mm_shuffle_epi8(*xmm_crc3, xmm_shl); + *xmm_crc2 = _mm_or_si128(*xmm_crc2, xmm_tmp3); + + *xmm_crc3 = _mm_shuffle_epi8(*xmm_crc3, xmm_shr); + *xmm_crc_part = _mm_shuffle_epi8(*xmm_crc_part, xmm_shl); + *xmm_crc3 = _mm_or_si128(*xmm_crc3, *xmm_crc_part); + + xmm_a0_1 = _mm_clmulepi64_si128(xmm_a0_0, xmm_fold4, 0x10); + xmm_a0_0 = _mm_clmulepi64_si128(xmm_a0_0, xmm_fold4, 0x01); + + ps_crc3 = _mm_castsi128_ps(*xmm_crc3); + psa0_0 = _mm_castsi128_ps(xmm_a0_0); + psa0_1 = _mm_castsi128_ps(xmm_a0_1); + + ps_res = _mm_xor_ps(ps_crc3, psa0_0); + ps_res = _mm_xor_ps(ps_res, psa0_1); + + *xmm_crc3 = _mm_castps_si128(ps_res); +} + +ZLIB_INTERNAL void crc_fold_copy(deflate_state *const s, + unsigned char *dst, const unsigned char *src, long len) +{ + unsigned long algn_diff; + __m128i xmm_t0, xmm_t1, xmm_t2, xmm_t3; + + CRC_LOAD(s) + + if (len < 16) { + if (len == 0) + return; + goto partial; + } + + algn_diff = 0 - (uintptr_t)src & 0xF; + if (algn_diff) { + xmm_crc_part = _mm_loadu_si128((__m128i *)src); + _mm_storeu_si128((__m128i *)dst, xmm_crc_part); + + dst += algn_diff; + src += algn_diff; + len -= algn_diff; + + partial_fold(s, algn_diff, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, + &xmm_crc_part); + } + + while ((len -= 64) >= 0) { + xmm_t0 = _mm_load_si128((__m128i *)src); + xmm_t1 = _mm_load_si128((__m128i *)src + 1); + xmm_t2 = _mm_load_si128((__m128i *)src + 2); + xmm_t3 = _mm_load_si128((__m128i *)src + 3); + + fold_4(s, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + _mm_storeu_si128((__m128i *)dst, xmm_t0); + _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); + _mm_storeu_si128((__m128i *)dst + 2, xmm_t2); + _mm_storeu_si128((__m128i *)dst + 3, xmm_t3); + + xmm_crc0 = _mm_xor_si128(xmm_crc0, xmm_t0); + xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t1); + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t2); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t3); + + src += 64; + dst += 64; + } + + /* + * len = num bytes left - 64 + */ + if (len + 16 >= 0) { + len += 16; + + xmm_t0 = _mm_load_si128((__m128i *)src); + xmm_t1 = _mm_load_si128((__m128i *)src + 1); + xmm_t2 = _mm_load_si128((__m128i *)src + 2); + + fold_3(s, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + _mm_storeu_si128((__m128i *)dst, xmm_t0); + _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); + _mm_storeu_si128((__m128i *)dst + 2, xmm_t2); + + xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t0); + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t1); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t2); + + if (len == 0) + goto done; + + dst += 48; + src += 48; + } else if (len + 32 >= 0) { + len += 32; + + xmm_t0 = _mm_load_si128((__m128i *)src); + xmm_t1 = _mm_load_si128((__m128i *)src + 1); + + fold_2(s, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + _mm_storeu_si128((__m128i *)dst, xmm_t0); + _mm_storeu_si128((__m128i *)dst + 1, xmm_t1); + + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t0); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t1); + + if (len == 0) + goto done; + + dst += 32; + src += 32; + } else if (len + 48 >= 0) { + len += 48; + + xmm_t0 = _mm_load_si128((__m128i *)src); + + fold_1(s, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3); + + _mm_storeu_si128((__m128i *)dst, xmm_t0); + + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t0); + + if (len == 0) + goto done; + + dst += 16; + src += 16; + } else { + len += 64; + if (len == 0) + goto done; + } + +partial: + +#if defined(_MSC_VER) + /* VS does not permit the use of _mm_set_epi64x in 32-bit builds */ + { + int32_t parts[4] = {0, 0, 0, 0}; + memcpy(&parts, src, len); + xmm_crc_part = _mm_set_epi32(parts[3], parts[2], parts[1], parts[0]); + } +#else + { + int64_t parts[2] = {0, 0}; + memcpy(&parts, src, len); + xmm_crc_part = _mm_set_epi64x(parts[1], parts[0]); + } +#endif + + _mm_storeu_si128((__m128i *)dst, xmm_crc_part); + partial_fold(s, len, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, + &xmm_crc_part); +done: + CRC_SAVE(s) +} + +local const unsigned zalign(16) crc_k[] = { + 0xccaa009e, 0x00000000, /* rk1 */ + 0x751997d0, 0x00000001, /* rk2 */ + 0xccaa009e, 0x00000000, /* rk5 */ + 0x63cd6124, 0x00000001, /* rk6 */ + 0xf7011640, 0x00000001, /* rk7 */ + 0xdb710640, 0x00000001 /* rk8 */ +}; + +local const unsigned zalign(16) crc_mask[4] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 +}; + +local const unsigned zalign(16) crc_mask2[4] = { + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +}; + +unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state *const s) +{ + const __m128i xmm_mask = _mm_load_si128((__m128i *)crc_mask); + const __m128i xmm_mask2 = _mm_load_si128((__m128i *)crc_mask2); + + unsigned crc; + __m128i x_tmp0, x_tmp1, x_tmp2, crc_fold; + + CRC_LOAD(s) + + /* + * k1 + */ + crc_fold = _mm_load_si128((__m128i *)crc_k); + + x_tmp0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x10); + xmm_crc0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x01); + xmm_crc1 = _mm_xor_si128(xmm_crc1, x_tmp0); + xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_crc0); + + x_tmp1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x10); + xmm_crc1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x01); + xmm_crc2 = _mm_xor_si128(xmm_crc2, x_tmp1); + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_crc1); + + x_tmp2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x10); + xmm_crc2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x01); + xmm_crc3 = _mm_xor_si128(xmm_crc3, x_tmp2); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + + /* + * k5 + */ + crc_fold = _mm_load_si128((__m128i *)crc_k + 1); + + xmm_crc0 = xmm_crc3; + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0); + xmm_crc0 = _mm_srli_si128(xmm_crc0, 8); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0); + + xmm_crc0 = xmm_crc3; + xmm_crc3 = _mm_slli_si128(xmm_crc3, 4); + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0); + xmm_crc3 = _mm_and_si128(xmm_crc3, xmm_mask2); + + /* + * k7 + */ + xmm_crc1 = xmm_crc3; + xmm_crc2 = xmm_crc3; + crc_fold = _mm_load_si128((__m128i *)crc_k + 2); + + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + xmm_crc3 = _mm_and_si128(xmm_crc3, xmm_mask); + + xmm_crc2 = xmm_crc3; + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc1); + + crc = _mm_extract_epi32(xmm_crc3, 2); + return ~crc; + CRC_SAVE(s) +} diff --git a/modules/zlib/src/deflate.c b/modules/zlib/src/deflate.c index a0256cb01a..712d950d4d 100644 --- a/modules/zlib/src/deflate.c +++ b/modules/zlib/src/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -37,7 +37,7 @@ * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in https://tools.ietf.org/html/rfc1951 + * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. @@ -47,19 +47,13 @@ * */ -#include "zbuild.h" -#include "functable.h" +/* @(#) $Id$ */ +#include #include "deflate.h" -#include "deflate_p.h" -#include "insert_string_p.h" +#include "x86.h" -/* Avoid conflicts with zlib.h macros */ -#ifdef ZLIB_COMPAT -# undef deflateInit -# undef deflateInit2 -#endif - -const char PREFIX(deflate_copyright)[] = " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler "; +const char deflate_copyright[] = + " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -70,65 +64,104 @@ const char PREFIX(deflate_copyright)[] = " deflate 1.3.1 Copyright 1995-2024 Jea /* =========================================================================== * Function prototypes. */ -static int deflateStateCheck (PREFIX3(stream) *strm); -Z_INTERNAL block_state deflate_stored(deflate_state *s, int flush); -Z_INTERNAL block_state deflate_fast (deflate_state *s, int flush); -Z_INTERNAL block_state deflate_quick (deflate_state *s, int flush); -#ifndef NO_MEDIUM_STRATEGY -Z_INTERNAL block_state deflate_medium(deflate_state *s, int flush); +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local int deflateStateCheck OF((z_streamp strm)); +local void slide_hash OF((deflate_state *s)); +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); #endif -Z_INTERNAL block_state deflate_slow (deflate_state *s, int flush); -Z_INTERNAL block_state deflate_rle (deflate_state *s, int flush); -Z_INTERNAL block_state deflate_huff (deflate_state *s, int flush); -static void lm_set_level (deflate_state *s, int level); -static void lm_init (deflate_state *s); +local block_state deflate_rle OF((deflate_state *s, int flush)); +local block_state deflate_huff OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +unsigned ZLIB_INTERNAL deflate_read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV +# pragma message("Assembler code may have bugs -- use at your own risk") + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef ZLIB_DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* From crc32.c */ +extern void ZLIB_INTERNAL crc_reset(deflate_state *const s); +extern void ZLIB_INTERNAL crc_finalize(deflate_state *const s); +extern void ZLIB_INTERNAL copy_with_crc(z_streamp strm, Bytef *dst, long size); + +#ifdef _MSC_VER +#define INLINE __inline +#else +#define INLINE inline +#endif + +/* Inline optimisation */ +local INLINE Pos insert_string_sse(deflate_state *const s, const Pos str); /* =========================================================================== * Local data */ +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { - uint16_t good_length; /* reduce lazy search above this match length */ - uint16_t max_lazy; /* do not perform lazy search above this match length */ - uint16_t nice_length; /* quit search above this match length */ - uint16_t max_chain; - compress_func func; + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; } config; -static const config configuration_table[10] = { +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ - -#ifdef NO_QUICK_STRATEGY /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, -#else -/* 1 */ {0, 0, 0, 0, deflate_quick}, -/* 2 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -#endif - -#ifdef NO_MEDIUM_STRATEGY /* 3 */ {4, 6, 32, 32, deflate_fast}, + /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, -#else -/* 3 */ {4, 6, 16, 6, deflate_medium}, -/* 4 */ {4, 12, 32, 24, deflate_medium}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_medium}, -/* 6 */ {8, 16, 128, 128, deflate_medium}, -#endif - -/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif -/* Note: the deflate() code requires max_lazy >= STD_MIN_MATCH and max_chain >= 4 +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ @@ -136,177 +169,192 @@ static const config configuration_table[10] = { /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to UPDATE_HASH are made with consecutive input + * characters, so that a running hash key can be computed from the previous + * key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== - * Initialize the hash table. prev[] will be initialized on the fly. + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). */ -#define CLEAR_HASH(s) do { \ - memset((unsigned char *)s->head, 0, HASH_SIZE * sizeof(*s->head)); \ - } while (0) +local INLINE Pos insert_string_c(deflate_state *const s, const Pos str) +{ + Pos ret; - -#ifdef DEF_ALLOC_DEBUG -# include -# define LOGSZ(name,size) fprintf(stderr, "%s is %d bytes\n", name, size) -# define LOGSZP(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %d, padded %d\n", name, size, loc, pad) -# define LOGSZPL(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %ld, padded %d\n", name, size, loc, pad) + UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]); +#ifdef FASTEST + ret = s->head[s->ins_h]; #else -# define LOGSZ(name,size) -# define LOGSZP(name,size,loc,pad) -# define LOGSZPL(name,size,loc,pad) + ret = s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif + s->head[s->ins_h] = str; -/* =========================================================================== - * Allocate a big buffer and divide it up into the various buffers deflate needs. - * Handles alignment of allocated buffer and alignment of individual buffers. - */ -Z_INTERNAL deflate_allocs* alloc_deflate(PREFIX3(stream) *strm, int windowBits, int lit_bufsize) { - int curr_size = 0; - - /* Define sizes */ - int window_size = DEFLATE_ADJUST_WINDOW_SIZE((1 << windowBits) * 2); - int prev_size = (1 << windowBits) * (int)sizeof(Pos); - int head_size = HASH_SIZE * sizeof(Pos); - int pending_size = (lit_bufsize * LIT_BUFS) + 1; - int state_size = sizeof(deflate_state); - int alloc_size = sizeof(deflate_allocs); - - /* Calculate relative buffer positions and paddings */ - LOGSZP("window", window_size, PAD_WINDOW(curr_size), PADSZ(curr_size,WINDOW_PAD_SIZE)); - int window_pos = PAD_WINDOW(curr_size); - curr_size = window_pos + window_size; - - LOGSZP("prev", prev_size, PAD_64(curr_size), PADSZ(curr_size,64)); - int prev_pos = PAD_64(curr_size); - curr_size = prev_pos + prev_size; - - LOGSZP("head", head_size, PAD_64(curr_size), PADSZ(curr_size,64)); - int head_pos = PAD_64(curr_size); - curr_size = head_pos + head_size; - - LOGSZP("pending", pending_size, PAD_64(curr_size), PADSZ(curr_size,64)); - int pending_pos = PAD_64(curr_size); - curr_size = pending_pos + pending_size; - - LOGSZP("state", state_size, PAD_64(curr_size), PADSZ(curr_size,64)); - int state_pos = PAD_64(curr_size); - curr_size = state_pos + state_size; - - LOGSZP("alloc", alloc_size, PAD_16(curr_size), PADSZ(curr_size,16)); - int alloc_pos = PAD_16(curr_size); - curr_size = alloc_pos + alloc_size; - - /* Add 64-1 or 4096-1 to allow window alignment, and round size of buffer up to multiple of 64 */ - int total_size = PAD_64(curr_size + (WINDOW_PAD_SIZE - 1)); - - /* Allocate buffer, align to 64-byte cacheline, and zerofill the resulting buffer */ - char *original_buf = (char *)strm->zalloc(strm->opaque, 1, total_size); - if (original_buf == NULL) - return NULL; - - char *buff = (char *)HINT_ALIGNED_WINDOW((char *)PAD_WINDOW(original_buf)); - LOGSZPL("Buffer alloc", total_size, PADSZ((uintptr_t)original_buf,WINDOW_PAD_SIZE), PADSZ(curr_size,WINDOW_PAD_SIZE)); - - /* Initialize alloc_bufs */ - deflate_allocs *alloc_bufs = (struct deflate_allocs_s *)(buff + alloc_pos); - alloc_bufs->buf_start = original_buf; - alloc_bufs->zfree = strm->zfree; - - /* Assign buffers */ - alloc_bufs->window = (unsigned char *)HINT_ALIGNED_WINDOW(buff + window_pos); - alloc_bufs->prev = (Pos *)HINT_ALIGNED_64(buff + prev_pos); - alloc_bufs->head = (Pos *)HINT_ALIGNED_64(buff + head_pos); - alloc_bufs->pending_buf = (unsigned char *)HINT_ALIGNED_64(buff + pending_pos); - alloc_bufs->state = (deflate_state *)HINT_ALIGNED_16(buff + state_pos); - - memset(alloc_bufs->prev, 0, prev_size); - - return alloc_bufs; + return ret; } -/* =========================================================================== - * Free all allocated deflate buffers - */ -static inline void free_deflate(PREFIX3(stream) *strm) { - deflate_state *state = (deflate_state *)strm->state; - - if (state->alloc_bufs != NULL) { - deflate_allocs *alloc_bufs = state->alloc_bufs; - alloc_bufs->zfree(strm->opaque, alloc_bufs->buf_start); - strm->state = NULL; - } +local INLINE Pos insert_string(deflate_state *const s, const Pos str) +{ + if (x86_cpu_enable_simd) + return insert_string_sse(s, str); + return insert_string_c(s, str); } + /* =========================================================================== - * Initialize deflate state and buffers. - * This function is hidden in ZLIB_COMPAT builds. + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. */ -int32_t ZNG_CONDEXPORT PREFIX(deflateInit2)(PREFIX3(stream) *strm, int32_t level, int32_t method, int32_t windowBits, - int32_t memLevel, int32_t strategy) { - /* Todo: ignore strm->next_in if we use it as window */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +local void slide_hash(s) + deflate_state *s; +{ + unsigned n, m; + Posf *p; + uInt wsize = s->w_size; + + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + } while (--n); + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif +} + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + unsigned window_padding = 8; deflate_state *s; int wrap = 1; + static const char my_version[] = ZLIB_VERSION; - /* Initialize functable */ - FUNCTABLE_INIT; + x86_check_features(); - if (strm == NULL) - return Z_STREAM_ERROR; - - strm->msg = NULL; - if (strm->zalloc == NULL) { - strm->zalloc = PREFIX(zcalloc); - strm->opaque = NULL; + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; } - if (strm->zfree == NULL) - strm->zfree = PREFIX(zcfree); + if (strm == Z_NULL) return Z_STREAM_ERROR; - if (level == Z_DEFAULT_COMPRESSION) - level = 6; + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; - if (windowBits < -MAX_WBITS) - return Z_STREAM_ERROR; windowBits = -windowBits; + } #ifdef GZIP - } else if (windowBits > MAX_WBITS) { + else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; -#endif } - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < MIN_WBITS || - windowBits > MAX_WBITS || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED || - (windowBits == 8 && wrap != 1)) { +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { return Z_STREAM_ERROR; } - if (windowBits == 8) - windowBits = 9; /* until 256-byte window bug fixed */ - - /* Allocate buffers */ - int lit_bufsize = 1 << (memLevel + 6); - deflate_allocs *alloc_bufs = alloc_deflate(strm, windowBits, lit_bufsize); - if (alloc_bufs == NULL) - return Z_MEM_ERROR; - - s = alloc_bufs->state; - s->alloc_bufs = alloc_bufs; - s->window = alloc_bufs->window; - s->prev = alloc_bufs->prev; - s->head = alloc_bufs->head; - s->pending_buf = alloc_bufs->pending_buf; - - strm->state = (struct internal_state *)s; + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; s->strm = strm; s->status = INIT_STATE; /* to pass state test in deflateReset() */ s->wrap = wrap; - s->gzhead = NULL; - s->w_size = 1 << windowBits; + s->gzhead = Z_NULL; + s->w_bits = (uInt)windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + if (x86_cpu_enable_simd) { + s->hash_bits = 15; + } else { + s->hash_bits = memLevel + 7; + } + + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, + s->w_size + window_padding, + 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ - s->lit_bufsize = lit_bufsize; /* 16K elements by default */ + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ /* We overlay pending_buf and sym_buf. This works since the average size * for length/distance pairs over any compressed block is assured to be 31 @@ -347,16 +395,18 @@ int32_t ZNG_CONDEXPORT PREFIX(deflateInit2)(PREFIX3(stream) *strm, int32_t level * symbols from which it is being constructed. */ - s->pending_buf_size = s->lit_bufsize * 4; + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4); + s->pending_buf_size = (ulg)s->lit_bufsize * 4; -#ifdef LIT_MEM - s->d_buf = (uint16_t *)(s->pending_buf + (s->lit_bufsize << 1)); - s->l_buf = s->pending_buf + (s->lit_bufsize << 2); - s->sym_end = s->lit_bufsize - 1; -#else + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } s->sym_buf = s->pending_buf + s->lit_bufsize; s->sym_end = (s->lit_bufsize - 1) * 3; -#endif /* We avoid equality with lit_bufsize*3 because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. @@ -364,79 +414,66 @@ int32_t ZNG_CONDEXPORT PREFIX(deflateInit2)(PREFIX3(stream) *strm, int32_t level s->level = level; s->strategy = strategy; - s->block_open = 0; - s->reproducible = 0; + s->method = (Byte)method; - return PREFIX(deflateReset)(strm); -} - -#ifndef ZLIB_COMPAT -int32_t Z_EXPORT PREFIX(deflateInit)(PREFIX3(stream) *strm, int32_t level) { - return PREFIX(deflateInit2)(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); -} -#endif - -/* Function used by zlib.h and zlib-ng version 2.0 macros */ -int32_t Z_EXPORT PREFIX(deflateInit_)(PREFIX3(stream) *strm, int32_t level, const char *version, int32_t stream_size) { - if (CHECK_VER_STSIZE(version, stream_size)) - return Z_VERSION_ERROR; - return PREFIX(deflateInit2)(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); -} - -/* Function used by zlib.h and zlib-ng version 2.0 macros */ -int32_t Z_EXPORT PREFIX(deflateInit2_)(PREFIX3(stream) *strm, int32_t level, int32_t method, int32_t windowBits, - int32_t memLevel, int32_t strategy, const char *version, int32_t stream_size) { - if (CHECK_VER_STSIZE(version, stream_size)) - return Z_VERSION_ERROR; - return PREFIX(deflateInit2)(strm, level, method, windowBits, memLevel, strategy); + return deflateReset(strm); } /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ -static int deflateStateCheck(PREFIX3(stream) *strm) { +local int deflateStateCheck (strm) + z_streamp strm; +{ deflate_state *s; - if (strm == NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; s = strm->state; - if (s == NULL || s->alloc_bufs == NULL || s->strm != strm || (s->status < INIT_STATE || s->status > MAX_STATE)) + if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && +#ifdef GZIP + s->status != GZIP_STATE && +#endif + s->status != EXTRA_STATE && + s->status != NAME_STATE && + s->status != COMMENT_STATE && + s->status != HCRC_STATE && + s->status != BUSY_STATE && + s->status != FINISH_STATE)) return 1; return 0; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflateSetDictionary)(PREFIX3(stream) *strm, const uint8_t *dictionary, uint32_t dictLength) { +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ deflate_state *s; - insert_string_cb insert_string_func; - unsigned int str, n; + uInt str, n; int wrap; - uint32_t avail; - const unsigned char *next; + unsigned avail; + z_const unsigned char *next; - if (deflateStateCheck(strm) || dictionary == NULL) + if (deflateStateCheck(strm) || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) return Z_STREAM_ERROR; - if (s->level >= 9) - insert_string_func = insert_string_roll; - else - insert_string_func = insert_string; - /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) - strm->adler = FUNCTABLE_CALL(adler32)(strm->adler, dictionary, dictLength); - DEFLATE_SET_DICTIONARY_HOOK(strm, dictionary, dictLength); /* hook for IBM Z DFLTCC */ - s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in deflate_read_buf */ /* if dictionary would fill window, just replace the history */ if (dictLength >= s->w_size) { if (wrap == 0) { /* already empty otherwise */ CLEAR_HASH(s); s->strstart = 0; - s->block_start = 0; + s->block_start = 0L; s->insert = 0; } dictionary += dictLength - s->w_size; /* use the tail */ @@ -447,96 +484,108 @@ int32_t Z_EXPORT PREFIX(deflateSetDictionary)(PREFIX3(stream) *strm, const uint8 avail = strm->avail_in; next = strm->next_in; strm->avail_in = dictLength; - strm->next_in = (z_const unsigned char *)dictionary; - PREFIX(fill_window)(s); - while (s->lookahead >= STD_MIN_MATCH) { + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { str = s->strstart; - n = s->lookahead - (STD_MIN_MATCH - 1); - insert_string_func(s, str, n); - s->strstart = str + n; - s->lookahead = STD_MIN_MATCH - 1; - PREFIX(fill_window)(s); + n = s->lookahead - (MIN_MATCH-1); + do { + insert_string(s, str); + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); } s->strstart += s->lookahead; - s->block_start = (int)s->strstart; + s->block_start = (long)s->strstart; s->insert = s->lookahead; s->lookahead = 0; - s->prev_length = 0; + s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; - strm->next_in = (z_const unsigned char *)next; + strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflateGetDictionary)(PREFIX3(stream) *strm, uint8_t *dictionary, uint32_t *dictLength) { +int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) + z_streamp strm; + Bytef *dictionary; + uInt *dictLength; +{ deflate_state *s; - unsigned int len; + uInt len; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - DEFLATE_GET_DICTIONARY_HOOK(strm, dictionary, dictLength); /* hook for IBM Z DFLTCC */ s = strm->state; len = s->strstart + s->lookahead; if (len > s->w_size) len = s->w_size; - if (dictionary != NULL && len) - memcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); - if (dictLength != NULL) + if (dictionary != Z_NULL && len) + zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != Z_NULL) *dictLength = len; return Z_OK; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflateResetKeep)(PREFIX3(stream) *strm) { +int ZEXPORT deflateResetKeep (strm) + z_streamp strm; +{ deflate_state *s; - if (deflateStateCheck(strm)) + if (deflateStateCheck(strm)) { return Z_STREAM_ERROR; + } strm->total_in = strm->total_out = 0; - strm->msg = NULL; /* use zfree if we ever allocate msg dynamically */ + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; - if (s->wrap < 0) + if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - + } s->status = #ifdef GZIP s->wrap == 2 ? GZIP_STATE : #endif - INIT_STATE; - + s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = #ifdef GZIP - if (s->wrap == 2) { - strm->adler = CRC32_INITIAL_VALUE; - } else + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif - strm->adler = ADLER32_INITIAL_VALUE; - s->last_flush = -2; + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; - zng_tr_init(s); - - DEFLATE_RESET_KEEP_HOOK(strm); /* hook for IBM Z DFLTCC */ + _tr_init(s); return Z_OK; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflateReset)(PREFIX3(stream) *strm) { - int ret = PREFIX(deflateResetKeep)(strm); +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + int ret; + + ret = deflateResetKeep(strm); if (ret == Z_OK) lm_init(strm->state); return ret; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflateSetHeader)(PREFIX3(stream) *strm, PREFIX(gz_headerp) head) { +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ if (deflateStateCheck(strm) || strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; @@ -544,106 +593,111 @@ int32_t Z_EXPORT PREFIX(deflateSetHeader)(PREFIX3(stream) *strm, PREFIX(gz_heade } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflatePending)(PREFIX3(stream) *strm, uint32_t *pending, int32_t *bits) { - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; - if (pending != NULL) +int ZEXPORT deflatePending (strm, pending, bits) + unsigned *pending; + int *bits; + z_streamp strm; +{ + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + if (pending != Z_NULL) *pending = strm->state->pending; - if (bits != NULL) + if (bits != Z_NULL) *bits = strm->state->bi_valid; return Z_OK; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflatePrime)(PREFIX3(stream) *strm, int32_t bits, int32_t value) { +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ deflate_state *s; - uint64_t value64 = (uint64_t)value; - int32_t put; + int put; - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; - -#ifdef LIT_MEM - if (bits < 0 || bits > BIT_BUF_SIZE || - (unsigned char *)s->d_buf < s->pending_out + ((BIT_BUF_SIZE + 7) >> 3)) + if (bits < 0 || bits > 16 || + s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; -#else - if (bits < 0 || bits > BIT_BUF_SIZE || bits > (int32_t)(sizeof(value) << 3) || - s->sym_buf < s->pending_out + ((BIT_BUF_SIZE + 7) >> 3)) - return Z_BUF_ERROR; -#endif - do { - put = BIT_BUF_SIZE - s->bi_valid; - put = MIN(put, bits); - - if (s->bi_valid == 0) - s->bi_buf = value64; - else - s->bi_buf |= (value64 & ((UINT64_C(1) << put) - 1)) << s->bi_valid; + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); s->bi_valid += put; - zng_tr_flush_bits(s); - value64 >>= put; + _tr_flush_bits(s); + value >>= put; bits -= put; } while (bits); return Z_OK; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflateParams)(PREFIX3(stream) *strm, int32_t level, int32_t strategy) { +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ deflate_state *s; compress_func func; - int hook_flush = Z_NO_FLUSH; - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; - if (level == Z_DEFAULT_COMPRESSION) - level = 6; - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; - DEFLATE_PARAMS_HOOK(strm, level, strategy, &hook_flush); /* hook for IBM Z DFLTCC */ + } func = configuration_table[s->level].func; - if (((strategy != s->strategy || func != configuration_table[level].func) && s->last_flush != -2) - || hook_flush != Z_NO_FLUSH) { - /* Flush the last buffer. Use Z_BLOCK mode, unless the hook requests a "stronger" one. */ - int flush = RANK(hook_flush) > RANK(Z_BLOCK) ? hook_flush : Z_BLOCK; - int err = PREFIX(deflate)(strm, flush); + if ((strategy != s->strategy || func != configuration_table[level].func) && + s->high_water) { + /* Flush the last buffer: */ + int err = deflate(strm, Z_BLOCK); if (err == Z_STREAM_ERROR) return err; - if (strm->avail_in || ((int)s->strstart - s->block_start) + s->lookahead || !DEFLATE_DONE(strm, flush)) + if (strm->avail_out == 0) return Z_BUF_ERROR; } if (s->level != level) { if (s->level == 0 && s->matches != 0) { - if (s->matches == 1) { - FUNCTABLE_CALL(slide_hash)(s); - } else { + if (s->matches == 1) + slide_hash(s); + else CLEAR_HASH(s); - } s->matches = 0; } - - lm_set_level(s, level); + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return Z_OK; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflateTune)(PREFIX3(stream) *strm, int32_t good_length, int32_t max_lazy, int32_t nice_length, int32_t max_chain) { +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ deflate_state *s; - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; - s->good_match = (unsigned int)good_length; - s->max_lazy_match = (unsigned int)max_lazy; + s->good_match = (uInt)good_length; + s->max_lazy_match = (uInt)max_lazy; s->nice_match = nice_length; - s->max_chain_length = (unsigned int)max_chain; + s->max_chain_length = (uInt)max_chain; return Z_OK; } @@ -664,13 +718,16 @@ int32_t Z_EXPORT PREFIX(deflateTune)(PREFIX3(stream) *strm, int32_t good_length, * upper bound of about 14% expansion does not seem onerous for output buffer * allocation. */ -unsigned long Z_EXPORT PREFIX(deflateBound)(PREFIX3(stream) *strm, unsigned long sourceLen) { +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ deflate_state *s; - unsigned long complen, wraplen; + uLong complen, wraplen; /* conservative upper bound for compressed data */ - complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; - DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen); /* hook for IBM Z DFLTCC */ + complen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ if (deflateStateCheck(strm)) @@ -683,69 +740,82 @@ unsigned long Z_EXPORT PREFIX(deflateBound)(PREFIX3(stream) *strm, unsigned long wraplen = 0; break; case 1: /* zlib wrapper */ - wraplen = ZLIB_WRAPLEN + (s->strstart ? 4 : 0); + wraplen = 6 + (s->strstart ? 4 : 0); break; #ifdef GZIP case 2: /* gzip wrapper */ - wraplen = GZIP_WRAPLEN; - if (s->gzhead != NULL) { /* user-supplied gzip header */ - unsigned char *str; - if (s->gzhead->extra != NULL) { + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + Bytef *str; + if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; - } str = s->gzhead->name; - if (str != NULL) { + if (str != Z_NULL) do { wraplen++; } while (*str++); - } str = s->gzhead->comment; - if (str != NULL) { + if (str != Z_NULL) do { wraplen++; } while (*str++); - } if (s->gzhead->hcrc) wraplen += 2; } break; #endif default: /* for compiler happiness */ - Z_UNREACHABLE(); -#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L - wraplen = ZLIB_WRAPLEN; -#endif + wraplen = 6; } /* if not default parameters, return conservative bound */ - if (DEFLATE_NEED_CONSERVATIVE_BOUND(strm) || /* hook for IBM Z DFLTCC */ - W_BITS(s) != MAX_WBITS || HASH_BITS < 15) { - if (s->level == 0) { - /* upper bound for stored blocks with length 127 (memLevel == 1) -- - ~4% overhead plus a small constant */ - complen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + (sourceLen >> 11) + 7; - } - + if (s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; - } -#ifndef NO_QUICK_STRATEGY - return sourceLen /* The source size itself */ - + (sourceLen == 0 ? 1 : 0) /* Always at least one byte for any input */ - + (sourceLen < 9 ? 1 : 0) /* One extra byte for lengths less than 9 */ - + DEFLATE_QUICK_OVERHEAD(sourceLen) /* Source encoding overhead, padded to next full byte */ - + DEFLATE_BLOCK_OVERHEAD /* Deflate block overhead bytes */ - + wraplen; /* none, zlib or gzip wrapper */ -#else - return sourceLen + (sourceLen >> 4) + 7 + wraplen; -#endif + /* default settings: return tight bound for that case */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= - * Flush as much pending output as possible. See flush_pending_inline() + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. */ -Z_INTERNAL void PREFIX(flush_pending)(PREFIX3(stream) *strm) { - flush_pending_inline(strm); +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also deflate_read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len; + deflate_state *s = strm->state; + + _tr_flush_bits(s); + len = s->pending; + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } } /* =========================================================================== @@ -754,32 +824,36 @@ Z_INTERNAL void PREFIX(flush_pending)(PREFIX3(stream) *strm) { #define HCRC_UPDATE(beg) \ do { \ if (s->gzhead->hcrc && s->pending > (beg)) \ - strm->adler = PREFIX(crc32)(strm->adler, s->pending_buf + (beg), s->pending - (beg)); \ + strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ + s->pending - (beg)); \ } while (0) /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { - int32_t old_flush; /* value of flush param for previous deflate call */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; - if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; + } s = strm->state; - if (strm->next_out == NULL || (strm->avail_in != 0 && strm->next_in == NULL) - || (s->status == FINISH_STATE && flush != Z_FINISH)) { + if (strm->next_out == Z_NULL || + (strm->avail_in != 0 && strm->next_in == Z_NULL) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } - if (strm->avail_out == 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); old_flush = s->last_flush; s->last_flush = flush; /* Flush as much pending output as possible */ if (s->pending != 0) { - flush_pending_inline(strm); + flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and @@ -791,26 +865,25 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { return Z_OK; } - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && + flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { + if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Write the header */ - if (s->status == INIT_STATE && s->wrap == 0) - s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ - unsigned int header = (Z_DEFLATED + ((W_BITS(s)-8)<<4)) << 8; - unsigned int level_flags; + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; @@ -821,20 +894,21 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { else level_flags = 3; header |= (level_flags << 6); - if (s->strstart != 0) - header |= PRESET_DICT; + if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); - put_short_msb(s, (uint16_t)header); + putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) - put_uint32_msb(s, strm->adler); - strm->adler = ADLER32_INITIAL_VALUE; + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ - PREFIX(flush_pending)(strm); + flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; @@ -843,54 +917,67 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { #ifdef GZIP if (s->status == GZIP_STATE) { /* gzip header */ - strm->adler = CRC32_INITIAL_VALUE; + crc_reset(s); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); - if (s->gzhead == NULL) { - put_uint32(s, 0); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ - PREFIX(flush_pending)(strm); + flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } - } else { + } + else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == NULL ? 0 : 4) + - (s->gzhead->name == NULL ? 0 : 8) + - (s->gzhead->comment == NULL ? 0 : 16) + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) ); - put_uint32(s, s->gzhead->time); - put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != NULL) - put_short(s, (uint16_t)s->gzhead->extra_len); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } if (s->gzhead->hcrc) - strm->adler = PREFIX(crc32)(strm->adler, s->pending_buf, s->pending); + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != NULL) { - uint32_t beg = s->pending; /* start of bytes to update crc */ - uint32_t left = (s->gzhead->extra_len & 0xffff) - s->gzindex; - + if (s->gzhead->extra != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; while (s->pending + left > s->pending_buf_size) { - uint32_t copy = s->pending_buf_size - s->pending; - memcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, copy); + uInt copy = s->pending_buf_size - s->pending; + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, copy); s->pending = s->pending_buf_size; HCRC_UPDATE(beg); s->gzindex += copy; - PREFIX(flush_pending)(strm); + flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; @@ -898,7 +985,8 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { beg = 0; left -= copy; } - memcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, left); + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, left); s->pending += left; HCRC_UPDATE(beg); s->gzindex = 0; @@ -906,14 +994,13 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { s->status = NAME_STATE; } if (s->status == NAME_STATE) { - if (s->gzhead->name != NULL) { - uint32_t beg = s->pending; /* start of bytes to update crc */ - unsigned char val; - + if (s->gzhead->name != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; do { if (s->pending == s->pending_buf_size) { HCRC_UPDATE(beg); - PREFIX(flush_pending)(strm); + flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; @@ -929,14 +1016,13 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != NULL) { - uint32_t beg = s->pending; /* start of bytes to update crc */ - unsigned char val; - + if (s->gzhead->comment != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; do { if (s->pending == s->pending_buf_size) { HCRC_UPDATE(beg); - PREFIX(flush_pending)(strm); + flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; @@ -953,19 +1039,20 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) { - PREFIX(flush_pending)(strm); + flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } - put_short(s, (uint16_t)strm->adler); - strm->adler = CRC32_INITIAL_VALUE; + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); } s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ - flush_pending_inline(strm); + flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; @@ -975,11 +1062,11 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { /* Start a new block or continue the current one. */ - if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; - bstate = DEFLATE_HOOK(strm, flush, &bstate) ? bstate : /* hook for IBM Z DFLTCC */ - s->level == 0 ? deflate_stored(s, flush) : + bstate = s->level == 0 ? deflate_stored(s, flush) : s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush); @@ -1002,9 +1089,9 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { - zng_tr_align(s); + _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ - zng_tr_stored_block(s, NULL, 0L, 0); + _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ @@ -1012,147 +1099,444 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; - s->block_start = 0; + s->block_start = 0L; s->insert = 0; } } } - PREFIX(flush_pending)(strm); + flush_pending(strm); if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; } } } - if (flush != Z_FINISH) - return Z_OK; + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { - put_uint32(s, strm->adler); - put_uint32(s, (uint32_t)strm->total_in); - } else + crc_finalize(s); + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else #endif { - if (s->wrap == 1) - put_uint32_msb(s, strm->adler); + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); } - flush_pending_inline(strm); + flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ - if (s->wrap > 0) - s->wrap = -s->wrap; /* write the trailer only once! */ - if (s->pending == 0) { - Assert(s->bi_valid == 0, "bi_buf not flushed"); - return Z_STREAM_END; - } - return Z_OK; + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ -int32_t Z_EXPORT PREFIX(deflateEnd)(PREFIX3(stream) *strm) { - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; - int32_t status = strm->state->status; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - /* Free allocated buffers */ - free_deflate(strm); + status = strm->state->status; + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). */ -int32_t Z_EXPORT PREFIX(deflateCopy)(PREFIX3(stream) *dest, PREFIX3(stream) *source) { +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else deflate_state *ds; deflate_state *ss; - if (deflateStateCheck(source) || dest == NULL) + + if (deflateStateCheck(source) || dest == Z_NULL) { return Z_STREAM_ERROR; + } ss = source->state; - memcpy(dest, source, sizeof(PREFIX3(stream))); + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - deflate_allocs *alloc_bufs = alloc_deflate(dest, W_BITS(ss), ss->lit_bufsize); - if (alloc_bufs == NULL) - return Z_MEM_ERROR; - - ds = alloc_bufs->state; - - dest->state = (struct internal_state *) ds; - memcpy(ds, ss, sizeof(deflate_state)); + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; - ds->alloc_bufs = alloc_bufs; - ds->window = alloc_bufs->window; - ds->prev = alloc_bufs->prev; - ds->head = alloc_bufs->head; - ds->pending_buf = alloc_bufs->pending_buf; + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); - if (ds->window == NULL || ds->prev == NULL || ds->head == NULL || ds->pending_buf == NULL) { - PREFIX(deflateEnd)(dest); + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); return Z_MEM_ERROR; } - - memcpy(ds->window, ss->window, DEFLATE_ADJUST_WINDOW_SIZE(ds->w_size * 2 * sizeof(unsigned char))); - memcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - memcpy(ds->head, ss->head, HASH_SIZE * sizeof(Pos)); - memcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS); + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); -#ifdef LIT_MEM - ds->d_buf = (uint16_t *)(ds->pending_buf + (ds->lit_bufsize << 1)); - ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2); -#else ds->sym_buf = ds->pending_buf + ds->lit_bufsize; -#endif ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; +#endif /* MAXSEG_64K */ } /* =========================================================================== - * Set longest match variables based on level configuration + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). */ -static void lm_set_level(deflate_state *s, int level) { - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - s->level = level; +ZLIB_INTERNAL unsigned deflate_read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + +#ifdef GZIP + if (strm->state->wrap == 2) + copy_with_crc(strm, buf, len); + else +#endif + { + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) + strm->adler = adler32(strm->adler, buf, len); + } + strm->next_in += len; + strm->total_in += len; + + return len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ -static void lm_init(deflate_state *s) { - s->window_size = 2 * s->w_size; +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ - lm_set_level(s, s->level); + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; - s->block_start = 0; + s->block_start = 0L; s->lookahead = 0; s->insert = 0; - s->prev_length = 0; + s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; - s->match_start = 0; s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif } +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = (int)s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef ZLIB_DEBUG + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* ZLIB_DEBUG */ + /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. @@ -1163,46 +1547,56 @@ static void lm_init(deflate_state *s) { * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ +local void fill_window_c(deflate_state *s); -void Z_INTERNAL PREFIX(fill_window)(deflate_state *s) { - PREFIX3(stream) *strm = s->strm; - insert_string_cb insert_string_func; - unsigned char *window = s->window; +local void fill_window(deflate_state *s) +{ + if (x86_cpu_enable_simd) { + fill_window_sse(s); + return; + } + + fill_window_c(s); +} + +local void fill_window_c(s) + deflate_state *s; +{ unsigned n; - unsigned int more; /* Amount of free space at the end of the window. */ - unsigned int wsize = s->w_size; - int level = s->level; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - if (level >= 9) - insert_string_func = insert_string_roll; - else - insert_string_func = insert_string; - do { - more = s->window_size - s->lookahead - s->strstart; + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize+MAX_DIST(s)) { - memcpy(window, window + wsize, (unsigned)wsize); - if (s->match_start >= wsize) { - s->match_start -= wsize; - } else { - s->match_start = 0; - s->prev_length = 0; - } + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); + s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (int)wsize; - if (s->insert > s->strstart) - s->insert = s->strstart; - FUNCTABLE_CALL(slide_hash)(s); + s->block_start -= (long) wsize; + slide_hash(s); more += wsize; } - if (strm->avail_in == 0) - break; + if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && @@ -1217,41 +1611,45 @@ void Z_INTERNAL PREFIX(fill_window)(deflate_state *s) { */ Assert(more >= 2, "more < 2"); - n = read_buf(strm, window + s->strstart + s->lookahead, more); + n = deflate_read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ - if (s->lookahead + s->insert >= STD_MIN_MATCH) { - unsigned int str = s->strstart - s->insert; - if (UNLIKELY(level >= 9)) { - s->ins_h = update_hash_roll(window[str], window[str+1]); - } else if (str >= 1) { - quick_insert_string(s, str + 2 - STD_MIN_MATCH); - } - unsigned int count = s->insert; - if (UNLIKELY(s->lookahead == 1)) { - count -= 1; - } - if (count > 0) { - insert_string_func(s, str, count); - s->insert -= count; + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; } } - /* If the whole input has less than STD_MIN_MATCH bytes, ins_h is garbage, + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ - } while (s->lookahead < MIN_LOOKAHEAD && strm->avail_in != 0); + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to STD_MAX_MATCH since the longest match - * routines allow scanning to strstart + STD_MAX_MATCH, ignoring lookahead. + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { - unsigned int curr = s->strstart + s->lookahead; - unsigned int init; + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT @@ -1260,158 +1658,620 @@ void Z_INTERNAL PREFIX(fill_window)(deflate_state *s) { init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; - memset(window + curr, 0, init); + zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; - } else if (s->high_water < curr + WIN_INIT) { + } + else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ - init = curr + WIN_INIT - s->high_water; + init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; - memset(window + s->high_water, 0, init); + zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } - Assert((unsigned long)s->strstart <= s->window_size - MIN_LOOKAHEAD, + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "not enough room for search"); } -#ifndef ZLIB_COMPAT -/* ========================================================================= - * Checks whether buffer size is sufficient and whether this parameter is a duplicate. +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. */ -static int32_t deflateSetParamPre(zng_deflate_param_value **out, size_t min_size, zng_deflate_param_value *param) { - int32_t buf_error = param->size < min_size; - - if (*out != NULL) { - (*out)->status = Z_BUF_ERROR; - buf_error = 1; - } - *out = param; - return buf_error; +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ } -/* ========================================================================= */ -int32_t Z_EXPORT zng_deflateSetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count) { - size_t i; +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunites to have a single copy from next_in to next_out. + */ +local block_state deflate_stored(s, flush) deflate_state *s; - zng_deflate_param_value *new_level = NULL; - zng_deflate_param_value *new_strategy = NULL; - zng_deflate_param_value *new_reproducible = NULL; - int param_buf_error; - int version_error = 0; - int buf_error = 0; - int stream_error = 0; + int flush; +{ + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. + */ + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); - /* Initialize the statuses. */ - for (i = 0; i < count; i++) - params[i].status = Z_OK; + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. + */ + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = s->strstart - s->block_start; /* bytes left in window */ + if (len > (ulg)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + if (len > have) + len = have; /* limit len to the output */ - /* Check whether the stream state is consistent. */ - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; - s = strm->state; + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || + flush == Z_NO_FLUSH || + len != left + s->strm->avail_in)) + break; - /* Check buffer sizes and detect duplicates. */ - for (i = 0; i < count; i++) { - switch (params[i].param) { - case Z_DEFLATE_LEVEL: - param_buf_error = deflateSetParamPre(&new_level, sizeof(int), ¶ms[i]); - break; - case Z_DEFLATE_STRATEGY: - param_buf_error = deflateSetParamPre(&new_strategy, sizeof(int), ¶ms[i]); - break; - case Z_DEFLATE_REPRODUCIBLE: - param_buf_error = deflateSetParamPre(&new_reproducible, sizeof(int), ¶ms[i]); - break; - default: - params[i].status = Z_VERSION_ERROR; - version_error = 1; - param_buf_error = 0; - break; - } - if (param_buf_error) { - params[i].status = Z_BUF_ERROR; - buf_error = 1; - } - } - /* Exit early if small buffers or duplicates are detected. */ - if (buf_error) - return Z_BUF_ERROR; + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + _tr_stored_block(s, (char *)0, 0L, last); - /* Apply changes, remember if there were errors. */ - if (new_level != NULL || new_strategy != NULL) { - int ret = PREFIX(deflateParams)(strm, new_level == NULL ? s->level : *(int *)new_level->buf, - new_strategy == NULL ? s->strategy : *(int *)new_strategy->buf); - if (ret != Z_OK) { - if (new_level != NULL) - new_level->status = Z_STREAM_ERROR; - if (new_strategy != NULL) - new_strategy->status = Z_STREAM_ERROR; - stream_error = 1; - } - } - if (new_reproducible != NULL) { - int val = *(int *)new_reproducible->buf; - if (DEFLATE_CAN_SET_REPRODUCIBLE(strm, val)) { - s->reproducible = val; - } else { - new_reproducible->status = Z_STREAM_ERROR; - stream_error = 1; - } - } + /* Replace the lengths in the dummy stored block with len. */ + s->pending_buf[s->pending - 4] = len; + s->pending_buf[s->pending - 3] = len >> 8; + s->pending_buf[s->pending - 2] = ~len; + s->pending_buf[s->pending - 1] = ~len >> 8; - /* Report version errors only if there are no real errors. */ - return stream_error ? Z_STREAM_ERROR : (version_error ? Z_VERSION_ERROR : Z_OK); -} + /* Write the stored block header bytes. */ + flush_pending(s->strm); -/* ========================================================================= */ -int32_t Z_EXPORT zng_deflateGetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count) { - deflate_state *s; - size_t i; - int32_t buf_error = 0; - int32_t version_error = 0; - - /* Initialize the statuses. */ - for (i = 0; i < count; i++) - params[i].status = Z_OK; - - /* Check whether the stream state is consistent. */ - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; - s = strm->state; - - for (i = 0; i < count; i++) { - switch (params[i].param) { - case Z_DEFLATE_LEVEL: - if (params[i].size < sizeof(int)) - params[i].status = Z_BUF_ERROR; - else - *(int *)params[i].buf = s->level; - break; - case Z_DEFLATE_STRATEGY: - if (params[i].size < sizeof(int)) - params[i].status = Z_BUF_ERROR; - else - *(int *)params[i].buf = s->strategy; - break; - case Z_DEFLATE_REPRODUCIBLE: - if (params[i].size < sizeof(int)) - params[i].status = Z_BUF_ERROR; - else - *(int *)params[i].buf = s->reproducible; - break; - default: - params[i].status = Z_VERSION_ERROR; - version_error = 1; - break; - } - if (params[i].status == Z_BUF_ERROR) - buf_error = 1; - } - return buf_error ? Z_BUF_ERROR : (version_error ? Z_VERSION_ERROR : Z_OK); -} +#ifdef ZLIB_DEBUG + /* Update debugging counts for the data about to be copied. */ + s->compressed_len += len << 3; + s->bits_sent += len << 3; #endif + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) + left = len; + zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += left; + len -= left; + } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + deflate_read_buf(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; + } + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + } + else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + } + zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + } + s->block_start = s->strstart; + s->insert += MIN(used, s->w_size - s->insert); + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* If the last block was written to next_out, then done. */ + if (last) + return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && + s->strm->avail_in == 0 && (long)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart - 1; + if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { + /* Slide the window down. */ + s->block_start -= s->w_size; + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ + } + if (have > s->strm->avail_in) + have = s->strm->avail_in; + if (have) { + deflate_read_buf(s->strm, s->window + s->strstart, have); + s->strstart += have; + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = s->strstart - s->block_start; + if (left >= min_block || + ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && + s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && + len == left ? 1 : 0; + _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); + s->block_start += len; + flush_pending(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + hash_head = insert_string(s, s->strstart); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + hash_head = insert_string(s, s->strstart); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + hash_head = insert_string(s, s->strstart); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + hash_head = insert_string(s, s->strstart); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= MAX_MATCH) { + fill_window(s); + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (uInt)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* Safe to inline this as GCC/clang will use inline asm and Visual Studio will + * use intrinsic without extra params + */ +local INLINE Pos insert_string_sse(deflate_state *const s, const Pos str) +{ + Pos ret; + unsigned *ip, val, h = 0; + + ip = (unsigned *)&s->window[str]; + val = *ip; + + if (s->level >= 6) + val &= 0xFFFFFF; + +/* Windows clang should use inline asm */ +#if defined(_MSC_VER) && !defined(__clang__) + h = _mm_crc32_u32(h, val); +#elif defined(__i386__) || defined(__amd64__) + __asm__ __volatile__ ( + "crc32 %1,%0\n\t" + : "+r" (h) + : "r" (val) + ); +#else + /* This should never happen */ + assert(0); +#endif + + ret = s->head[h & s->hash_mask]; + s->head[h & s->hash_mask] = str; + s->prev[str & s->w_mask] = ret; + return ret; +} diff --git a/modules/zlib/src/deflate.h b/modules/zlib/src/deflate.h index 3f9f8f4686..6838296a0e 100644 --- a/modules/zlib/src/deflate.h +++ b/modules/zlib/src/deflate.h @@ -1,5 +1,3 @@ -#ifndef DEFLATE_H_ -#define DEFLATE_H_ /* deflate.h -- internal compression state * Copyright (C) 1995-2016 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h @@ -10,14 +8,12 @@ subject to change. Applications should only use zlib.h. */ -#include "zutil.h" -#include "zendian.h" -#include "zmemory.h" +/* @(#) $Id$ */ -#ifdef S390_DFLTCC_DEFLATE -# include "arch/s390/dfltcc_common.h" -# define HAVE_ARCH_DEFLATE_STATE -#endif +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in @@ -27,14 +23,6 @@ # define GZIP #endif -/* LIT_MEM uses separate distance/length buffers instead of the overlaid sym_buf. - This uses ~20% more memory but is 1-2% faster on platforms without fast unaligned - access. By default, LIT_MEM is only enabled when OPTIMAL_CMP < 32. Define LIT_MEM - to force separate buffers, or NO_LIT_MEM to force sym_buf usage. */ -#if !defined(LIT_MEM) && !defined(NO_LIT_MEM) && (OPTIMAL_CMP < 32) -# define LIT_MEM -#endif - /* =========================================================================== * Internal compression state. */ @@ -57,47 +45,36 @@ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ -#define BIT_BUF_SIZE 64 +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 /* size of bit buffer in bi_buf */ -#define END_BLOCK 256 -/* end of block literal code */ - -#define INIT_STATE 1 /* zlib header -> BUSY_STATE */ +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ #ifdef GZIP -# define GZIP_STATE 4 /* gzip header -> BUSY_STATE | EXTRA_STATE */ -# define EXTRA_STATE 5 /* gzip extra block -> NAME_STATE */ -# define NAME_STATE 6 /* gzip file name -> COMMENT_STATE */ -# define COMMENT_STATE 7 /* gzip comment -> HCRC_STATE */ -# define HCRC_STATE 8 /* gzip header CRC -> BUSY_STATE */ -#endif -#define BUSY_STATE 2 /* deflate -> FINISH_STATE */ -#define FINISH_STATE 3 /* stream complete */ -#ifdef GZIP -# define MAX_STATE HCRC_STATE -#else -# define MAX_STATE FINISH_STATE +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ #endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ /* Stream status */ -#define HASH_BITS 16u /* log2(HASH_SIZE) */ -#ifndef HASH_SIZE -# define HASH_SIZE 65536u /* number of elements in hash table */ -#endif -#define HASH_MASK (HASH_SIZE - 1u) /* HASH_SIZE-1 */ - /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { - uint16_t freq; /* frequency count */ - uint16_t code; /* bit string */ + ush freq; /* frequency count */ + ush code; /* bit string */ } fc; union { - uint16_t dad; /* father node in Huffman tree */ - uint16_t len; /* length of bit string */ + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ } dl; -} ct_data; +} FAR ct_data; #define Freq fc.freq #define Code fc.code @@ -107,141 +84,114 @@ typedef struct ct_data_s { typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - const static_tree_desc *stat_desc; /* the corresponding static tree */ -} tree_desc; + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; -typedef uint16_t Pos; +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. + * save space in the various tables. IPos is used only for parameter passing. */ -/* Type definitions for hash callbacks */ -typedef struct internal_state deflate_state; -typedef void (* insert_string_cb) (deflate_state *const s, uint32_t str, uint32_t count); -void insert_string (deflate_state *const s, uint32_t str, uint32_t count); -void insert_string_roll (deflate_state *const s, uint32_t str, uint32_t count); +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + ulg pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + ulg gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + unsigned zalign(16) crc0[4 * 5]; + /* used by deflate.c: */ -/* Struct for memory allocation handling */ -typedef struct deflate_allocs_s { - char *buf_start; - free_func zfree; - deflate_state *state; - unsigned char *window; - unsigned char *pending_buf; - Pos *prev; - Pos *head; -} deflate_allocs; + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ -struct ALIGNED_(64) internal_state { - /* Cacheline 0 */ - PREFIX3(stream) *strm; /* pointer back to this zlib stream */ - unsigned char *pending_buf; /* output still pending */ - unsigned char *pending_out; /* next pending byte to output to the stream */ - uint32_t pending_buf_size; /* size of pending_buf */ - uint32_t pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - uint32_t gzindex; /* where in extra, name, or comment */ - PREFIX(gz_headerp) gzhead; /* gzip header information to write */ - int status; /* as the name implies */ - int last_flush; /* value of flush param for previous deflate call */ - int reproducible; /* Whether reproducible compression results are required. */ - - unsigned int block_open; - /* Whether or not a block is currently open for the QUICK deflation scheme. - * This is set to 1 if there is an active block, or 0 if the block was just closed. - */ - - /* Cacheline 1 */ - - unsigned int lookahead; /* number of valid bytes ahead in window */ - unsigned int strstart; /* start of string to insert */ - unsigned int w_size; /* LZ77 window size (32K by default) */ - - int block_start; /* Window position at the beginning of the current output block. - * Gets negative when the window is moved backwards. */ - - unsigned int high_water; - /* High water mark offset in window for initialized bytes -- bytes above - * this are set to zero in order to avoid memory check warnings when - * longest match routines access bytes past the input. This is then - * updated to the new high water mark. - */ - - unsigned int window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - unsigned char *window; + Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of - * wSize-STD_MAX_MATCH bytes, but this ensures that IO is always + * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ - Pos *prev; + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ - Pos *head; /* Heads of the hash chains or 0. */ + Posf *head; /* Heads of the hash chains or NIL. */ - uint32_t ins_h; /* hash index of string to be inserted */ + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ - unsigned int match_length; /* length of best match */ - int match_available; /* set if previous match exists */ - uint32_t prev_match; /* previous match (used by deflate_slow) */ + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ - /* Cacheline 2 */ + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ - unsigned int match_start; /* start of matching string */ + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ - unsigned int prev_length; + uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ - unsigned int max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this length. - * A higher limit improves compression ratio but degrades the speed. + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. */ - unsigned int max_lazy_match; - /* Attempt to find a better match only when the current match is strictly smaller - * than this value. This mechanism is used only for compression levels >= 4. + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 6. + * max_insert_length is used only for compression levels <= 3. */ - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - unsigned int good_match; /* Use a faster search when the previous match is longer than this */ - int nice_match; /* Stop searching when current match exceeds this */ - unsigned int matches; /* number of string matches in current block */ - unsigned int insert; /* bytes at end of window left to insert */ + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ - uint64_t bi_buf; /* Output buffer. - * Bits are inserted starting at the bottom (least significant bits). */ - int32_t bi_valid; /* Number of valid bits in bi_buf. - * All bits above the last valid bit are always zero. */ + uInt good_match; + /* Use a faster search when the previous match is longer than this */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - - int32_t padding1[1]; - - /* Cacheline 3 */ - uint8_t ALIGNED_(16) padding4[68]; + int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to suppress compiler warning */ @@ -253,19 +203,23 @@ struct ALIGNED_(64) internal_state { struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ - uint16_t bl_count[MAX_BITS+1]; + ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ - unsigned char depth[2*L_CODES+1]; + uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ - unsigned int lit_bufsize; + uchf *sym_buf; /* buffer for distances and literals/lengths */ + + uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters @@ -285,188 +239,118 @@ struct ALIGNED_(64) internal_state { * - I can't count above 4 */ -#ifdef LIT_MEM -# define LIT_BUFS 5 - uint16_t *d_buf; /* buffer for distances */ - unsigned char *l_buf; /* buffer for literals/lengths */ -#else -# define LIT_BUFS 4 - unsigned char *sym_buf; /* buffer for distances and literals/lengths */ -#endif + uInt sym_next; /* running index in sym_buf */ + uInt sym_end; /* symbol table full when sym_next reaches this */ - unsigned int sym_next; /* running index in symbol buffer */ - unsigned int sym_end; /* symbol table full when sym_next reaches this */ + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ - unsigned int opt_len; /* bit length of current block with optimal trees */ - unsigned int static_len; /* bit length of current block with static trees */ - - deflate_allocs *alloc_bufs; - -#ifdef HAVE_ARCH_DEFLATE_STATE - arch_deflate_state arch; /* architecture-specific extensions */ -#endif - - /* compressed_len and bits_sent are only used if ZLIB_DEBUG is defined */ #ifdef ZLIB_DEBUG - unsigned long compressed_len; /* total bit length of compressed file mod 2^32 */ - unsigned long bits_sent; /* bit length of compressed data sent mod 2^32 */ + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif - /* Reserved for future use and alignment purposes */ - int32_t reserved[19]; -}; + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ -#define put_byte(s, c) { \ - s->pending_buf[s->pending++] = (unsigned char)(c); \ -} +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pending_buf. - */ -static inline void put_short(deflate_state *s, uint16_t w) { - w = Z_U16_TO_LE(w); - zng_memwrite_2(&s->pending_buf[s->pending], w); - s->pending += 2; -} -/* =========================================================================== - * Output a short MSB first on the stream. - * IN assertion: there is enough room in pending_buf. - */ -static inline void put_short_msb(deflate_state *s, uint16_t w) { - w = Z_U16_TO_BE(w); - zng_memwrite_2(&s->pending_buf[s->pending], w); - s->pending += 2; -} - -/* =========================================================================== - * Output a 32-bit unsigned int LSB first on the stream. - * IN assertion: there is enough room in pending_buf. - */ -static inline void put_uint32(deflate_state *s, uint32_t dw) { - dw = Z_U32_TO_LE(dw); - zng_memwrite_4(&s->pending_buf[s->pending], dw); - s->pending += 4; -} - -/* =========================================================================== - * Output a 32-bit unsigned int MSB first on the stream. - * IN assertion: there is enough room in pending_buf. - */ -static inline void put_uint32_msb(deflate_state *s, uint32_t dw) { - dw = Z_U32_TO_BE(dw); - zng_memwrite_4(&s->pending_buf[s->pending], dw); - s->pending += 4; -} - -/* =========================================================================== - * Output a 64-bit unsigned int LSB first on the stream. - * IN assertion: there is enough room in pending_buf. - */ -static inline void put_uint64(deflate_state *s, uint64_t lld) { - lld = Z_U64_TO_LE(lld); - zng_memwrite_8(&s->pending_buf[s->pending], lld); - s->pending += 8; -} - -#define MIN_LOOKAHEAD (STD_MAX_MATCH + STD_MIN_MATCH + 1) +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the STD_MIN_MATCH+1. + * See deflate.c for comments about the MIN_MATCH+1. */ -#define MAX_DIST(s) ((s)->w_size - MIN_LOOKAHEAD) +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ -#define W_MASK(s) ((s)->w_size - 1) -/* Window mask: w_size is always a power of 2, so w_mask = w_size - 1 */ - -#define W_BITS(s) zng_ctz32((s)->w_size) -/* Window bits: log2(w_size), computed from w_size since w_size is a power of 2 */ - -#define WIN_INIT STD_MAX_MATCH +#define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ - -void Z_INTERNAL PREFIX(fill_window)(deflate_state *s); -void Z_INTERNAL slide_hash_c(deflate_state *s); - /* in trees.c */ -void Z_INTERNAL zng_tr_init(deflate_state *s); -void Z_INTERNAL zng_tr_flush_block(deflate_state *s, unsigned char *buf, uint32_t stored_len, int last); -void Z_INTERNAL zng_tr_flush_bits(deflate_state *s); -void Z_INTERNAL zng_tr_align(deflate_state *s); -void Z_INTERNAL zng_tr_stored_block(deflate_state *s, unsigned char *buf, uint32_t stored_len, int last); -void Z_INTERNAL PREFIX(flush_pending)(PREFIX3(streamp) strm); -#define d_code(dist) ((dist) < 256 ? zng_dist_code[dist] : zng_dist_code[256+((dist)>>7)]) +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. zng_dist_code[256] and zng_dist_code[257] are never + * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ -/* Bit buffer and compress bits calculation debugging */ -#ifdef ZLIB_DEBUG -# define cmpr_bits_add(s, len) s->compressed_len += (len) -# define cmpr_bits_align(s) s->compressed_len = ALIGN_UP(s->compressed_len, 8) -# define sent_bits_add(s, bits) s->bits_sent += (bits) -# define sent_bits_align(s) s->bits_sent = ALIGN_UP(s->bits_sent, 8) +#ifndef ZLIB_DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; #else -# define cmpr_bits_add(s, len) Z_UNUSED(len) -# define cmpr_bits_align(s) -# define sent_bits_add(s, bits) Z_UNUSED(bits) -# define sent_bits_align(s) + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; #endif -/* =========================================================================== - * Architecture-specific hooks. - */ -#ifdef S390_DFLTCC_DEFLATE -# include "arch/s390/dfltcc_deflate.h" -/* DFLTCC instructions require window to be page-aligned */ -# define PAD_WINDOW PAD_4096 -# define WINDOW_PAD_SIZE 4096 -# define HINT_ALIGNED_WINDOW HINT_ALIGNED_4096 +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->sym_buf[s->sym_next++] = dist; \ + s->sym_buf[s->sym_next++] = dist >> 8; \ + s->sym_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } #else -# define PAD_WINDOW PAD_64 -# define WINDOW_PAD_SIZE 64 -# define HINT_ALIGNED_WINDOW HINT_ALIGNED_64 -/* Adjust the window size for the arch-specific deflate code. */ -# define DEFLATE_ADJUST_WINDOW_SIZE(n) (n) -/* Invoked at the beginning of deflateSetDictionary(). Useful for checking arch-specific window data. */ -# define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) -/* Invoked at the beginning of deflateGetDictionary(). Useful for adjusting arch-specific window data. */ -# define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) -/* Invoked at the end of deflateResetKeep(). Useful for initializing arch-specific extension blocks. */ -# define DEFLATE_RESET_KEEP_HOOK(strm) do {} while (0) -/* Invoked at the beginning of deflateParams(). Useful for updating arch-specific compression parameters. */ -# define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) do {} while (0) -/* Returns whether the last deflate(flush) operation did everything it's supposed to do. */ -# define DEFLATE_DONE(strm, flush) 1 -/* Adjusts the upper bound on compressed data length based on compression parameters and uncompressed data length. - * Useful when arch-specific deflation code behaves differently than regular zlib-ng algorithms. */ -# define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen) do {} while (0) -/* Returns whether an optimistic upper bound on compressed data length should *not* be used. - * Useful when arch-specific deflation code behaves differently than regular zlib-ng algorithms. */ -# define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) 0 -/* Invoked for each deflate() call. Useful for plugging arch-specific deflation code. */ -# define DEFLATE_HOOK(strm, flush, bstate) 0 -/* Returns whether zlib-ng should compute a checksum. Set to 0 if arch-specific deflation code already does that. */ -# define DEFLATE_NEED_CHECKSUM(strm) 1 -/* Returns whether reproducibility parameter can be set to a given value. */ -# define DEFLATE_CAN_SET_REPRODUCIBLE(strm, reproducible) 1 +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) #endif -#endif /* DEFLATE_H_ */ +/* Functions that are SIMD optimised on x86 */ +void ZLIB_INTERNAL crc_fold_init(deflate_state* const s); +void ZLIB_INTERNAL crc_fold_copy(deflate_state* const s, + unsigned char* dst, + const unsigned char* src, + long len); +unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state* const s); + +void ZLIB_INTERNAL fill_window_sse(deflate_state* s); + +#endif /* DEFLATE_H */ diff --git a/modules/zlib/src/deflate_fast.c b/modules/zlib/src/deflate_fast.c deleted file mode 100644 index adf0113c29..0000000000 --- a/modules/zlib/src/deflate_fast.c +++ /dev/null @@ -1,112 +0,0 @@ -/* deflate_fast.c -- compress data using the fast strategy of deflation algorithm - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zmemory.h" -#include "deflate.h" -#include "deflate_p.h" -#include "functable.h" -#include "insert_string_p.h" - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -Z_INTERNAL block_state deflate_fast(deflate_state *s, int flush) { - unsigned char *window = s->window; - int bflush = 0; /* set if current block must be flushed */ - uint32_t match_len = 0; - - for (;;) { - uint8_t lc; - - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need STD_MAX_MATCH bytes - * for the next match, plus WANT_MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - PREFIX(fill_window)(s); - if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { - return need_more; - } - if (UNLIKELY(s->lookahead == 0)) - break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= WANT_MIN_MATCH) { - uint32_t str_val = Z_U32_FROM_LE(zng_memread_4(window + s->strstart)); - uint32_t hash_head = quick_insert_value(s, s->strstart, str_val); - int64_t dist = (int64_t)s->strstart - hash_head; - lc = (uint8_t)str_val; - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match length < WANT_MIN_MATCH - */ - if (dist <= MAX_DIST(s) && dist > 0 && hash_head != 0) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - match_len = FUNCTABLE_CALL(longest_match)(s, (uint32_t)hash_head); - /* longest_match() sets match_start */ - } - } else { - lc = window[s->strstart]; - } - - if (match_len >= WANT_MIN_MATCH) { - Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); - Assert(s->match_start <= UINT16_MAX, "match_start should fit in uint16_t"); - check_match(s, s->strstart, s->match_start, match_len); - - bflush = zng_tr_tally_dist(s, s->strstart - s->match_start, match_len - STD_MIN_MATCH); - - s->lookahead -= match_len; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (match_len <= s->max_insert_length && s->lookahead >= WANT_MIN_MATCH) { - match_len--; /* string at strstart already in table */ - s->strstart++; - - insert_string_static(s, s->strstart, match_len); - s->strstart += match_len; - } else { - s->strstart += match_len; - quick_insert_string(s, s->strstart + 2 - STD_MIN_MATCH); - - /* If lookahead < STD_MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - match_len = 0; - } else { - /* No match, output a literal byte */ - bflush = zng_tr_tally_lit(s, lc); - s->lookahead--; - s->strstart++; - } - if (UNLIKELY(bflush)) - FLUSH_BLOCK(s, 0); - } - s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); - - if (UNLIKELY(flush == Z_FINISH)) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (UNLIKELY(s->sym_next)) - FLUSH_BLOCK(s, 0); - return block_done; -} diff --git a/modules/zlib/src/deflate_huff.c b/modules/zlib/src/deflate_huff.c deleted file mode 100644 index d5a234b114..0000000000 --- a/modules/zlib/src/deflate_huff.c +++ /dev/null @@ -1,45 +0,0 @@ -/* deflate_huff.c -- compress data using huffman encoding only strategy - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "deflate.h" -#include "deflate_p.h" -#include "functable.h" - -/* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ -Z_INTERNAL block_state deflate_huff(deflate_state *s, int flush) { - int bflush = 0; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we have a literal to write. */ - if (s->lookahead == 0) { - PREFIX(fill_window)(s); - if (s->lookahead == 0) { - if (flush == Z_NO_FLUSH) - return need_more; - break; /* flush the current block */ - } - } - - /* Output a literal byte */ - bflush = zng_tr_tally_lit(s, s->window[s->strstart]); - s->lookahead--; - s->strstart++; - if (bflush) - FLUSH_BLOCK(s, 0); - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->sym_next) - FLUSH_BLOCK(s, 0); - return block_done; -} diff --git a/modules/zlib/src/deflate_medium.c b/modules/zlib/src/deflate_medium.c deleted file mode 100644 index 860834d1fc..0000000000 --- a/modules/zlib/src/deflate_medium.c +++ /dev/null @@ -1,265 +0,0 @@ -/* deflate_medium.c -- The deflate_medium deflate strategy - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * Authors: - * Arjan van de Ven - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ -#ifndef NO_MEDIUM_STRATEGY -#include "zbuild.h" -#include "deflate.h" -#include "deflate_p.h" -#include "functable.h" -#include "insert_string_p.h" - -struct match { - uint16_t match_start; - uint16_t match_length; - uint16_t strstart; - uint16_t orgstart; -}; - -static int emit_match(deflate_state *s, struct match match) { - int bflush = 0; - uint32_t match_len = match.match_length; - - /* None of the below functions care about s->lookahead, so decrement it early */ - s->lookahead -= match_len; - - /* matches that are not long enough we need to emit as literals */ - if (match_len < WANT_MIN_MATCH) { - while (match_len) { - bflush += zng_tr_tally_lit(s, s->window[match.strstart]); - match_len--; - match.strstart++; - } - return bflush; - } - - check_match(s, match.strstart, match.match_start, match_len); - - bflush += zng_tr_tally_dist(s, match.strstart - match.match_start, match_len - STD_MIN_MATCH); - return bflush; -} - -/* insert_match assumes: s->lookahead > match.match_length + WANT_MIN_MATCH */ -static void insert_match(deflate_state *s, struct match match) { - uint32_t match_len = match.match_length; - uint32_t strstart = match.strstart; - - /* matches that are not long enough we need to emit as literals */ - if (LIKELY(match_len < WANT_MIN_MATCH)) { - strstart++; - match_len--; - if (UNLIKELY(match_len > 0)) { - if (strstart >= match.orgstart) { - if (strstart + match_len - 1 >= match.orgstart) { - insert_string(s, strstart, match_len); - } else { - insert_string(s, strstart, match.orgstart - strstart + 1); - } - } - } - return; - } - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (match_len <= 16 * s->max_insert_length && s->lookahead >= WANT_MIN_MATCH) { - match_len--; /* string at strstart already in table */ - strstart++; - - if (LIKELY(strstart >= match.orgstart)) { - if (LIKELY(strstart + match_len - 1 >= match.orgstart)) { - insert_string(s, strstart, match_len); - } else { - insert_string(s, strstart, match.orgstart - strstart + 1); - } - } else if (match.orgstart < strstart + match_len) { - insert_string(s, match.orgstart, strstart + match_len - match.orgstart); - } - } else { - strstart += match_len; - quick_insert_string(s, strstart + 2 - STD_MIN_MATCH); - - /* If lookahead < WANT_MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } -} - -Z_FORCEINLINE static struct match find_best_match(deflate_state *s, uint32_t hash_head) { - struct match m; - int64_t dist; - - m.strstart = (uint16_t)s->strstart; - m.orgstart = m.strstart; - - dist = (int64_t)s->strstart - hash_head; - if (dist <= MAX_DIST(s) && dist > 0 && hash_head != 0) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - m.match_length = (uint16_t)FUNCTABLE_CALL(longest_match)(s, hash_head); - m.match_start = (uint16_t)s->match_start; - if (UNLIKELY(m.match_length < WANT_MIN_MATCH)) - m.match_length = 1; - if (UNLIKELY(m.match_start >= m.strstart)) { - /* this can happen due to some restarts */ - m.match_length = 1; - } - } else { - /* Set up the match to be a 1 byte literal */ - m.match_start = 0; - m.match_length = 1; - } - - return m; -} - -/* fizzle_matches assumes: - * - current->match_length > 1 - * - (current->match_length - 1) <= next->match_start - * - (current->match_length - 1) <= next->strstart - */ -static void fizzle_matches(deflate_state *s, struct match *current, struct match *next) { - unsigned char *window = s->window; - unsigned char *match, *orig; - struct match c, n; - int changed = 0; - Pos limit; - - match = window - current->match_length + 1 + next->match_start; - orig = window - current->match_length + 1 + next->strstart; - - /* quick exit check.. if this fails then don't bother with anything else */ - if (LIKELY(*match != *orig)) - return; - - c = *current; - n = *next; - - /* step one: try to move the "next" match to the left as much as possible */ - limit = next->strstart > MAX_DIST(s) ? next->strstart - (Pos)MAX_DIST(s) : 0; - - match = window + n.match_start - 1; - orig = window + n.strstart - 1; - - while (*match == *orig) { - if (UNLIKELY(c.match_length < 1)) - break; - if (UNLIKELY(n.strstart <= limit)) - break; - if (UNLIKELY(n.match_length >= 256)) - break; - if (UNLIKELY(n.match_start <= 1)) - break; - - n.strstart--; - n.match_start--; - n.match_length++; - c.match_length--; - match--; - orig--; - changed++; - } - - if (changed && c.match_length <= 1 && n.match_length != 2) { - n.orgstart++; - *current = c; - *next = n; - } else { - return; - } -} - -Z_INTERNAL block_state deflate_medium(deflate_state *s, int flush) { - /* Align the first struct to start on a new cacheline, this allows us to fit both structs in one cacheline */ - ALIGNED_(16) struct match current_match = {0}; - struct match next_match = {0}; - - /* For levels below 5, don't check the next position for a better match */ - int early_exit = s->level < 5; - - for (;;) { - uint32_t hash_head = 0; /* head of the hash chain */ - int bflush = 0; /* set if current block must be flushed */ - - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need STD_MAX_MATCH bytes - * for the next match, plus WANT_MIN_MATCH bytes to insert the - * string following the next current_match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - PREFIX(fill_window)(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (UNLIKELY(s->lookahead == 0)) - break; /* flush the current block */ - next_match.match_length = 0; - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - - /* If we already have a future match from a previous round, just use that */ - if (!early_exit && next_match.match_length > 0) { - current_match = next_match; - next_match.match_length = 0; - } else { - hash_head = 0; - if (s->lookahead >= WANT_MIN_MATCH) { - hash_head = quick_insert_string(s, s->strstart); - } - - current_match = find_best_match(s, hash_head); - } - - if (LIKELY(s->lookahead > (unsigned int)(current_match.match_length + WANT_MIN_MATCH))) - insert_match(s, current_match); - - /* now, look ahead one */ - if (LIKELY(!early_exit && s->lookahead > MIN_LOOKAHEAD && (uint32_t)(current_match.strstart + current_match.match_length) < (s->window_size - MIN_LOOKAHEAD))) { - s->strstart = current_match.strstart + current_match.match_length; - hash_head = quick_insert_string(s, s->strstart); - - next_match = find_best_match(s, hash_head); - - uint32_t tmp_cmatch_len_sub = current_match.match_length - 1; - if (tmp_cmatch_len_sub - && next_match.match_length >= WANT_MIN_MATCH - && tmp_cmatch_len_sub <= next_match.match_start - && tmp_cmatch_len_sub <= next_match.strstart) { - fizzle_matches(s, ¤t_match, &next_match); - } - - s->strstart = current_match.strstart; - } else { - next_match.match_length = 0; - } - - /* now emit the current match */ - bflush = emit_match(s, current_match); - - /* move the "cursor" forward */ - s->strstart += current_match.match_length; - - if (UNLIKELY(bflush)) - FLUSH_BLOCK(s, 0); - } - s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (UNLIKELY(s->sym_next)) - FLUSH_BLOCK(s, 0); - - return block_done; -} -#endif diff --git a/modules/zlib/src/deflate_p.h b/modules/zlib/src/deflate_p.h deleted file mode 100644 index f60970bab3..0000000000 --- a/modules/zlib/src/deflate_p.h +++ /dev/null @@ -1,212 +0,0 @@ -/* deflate_p.h -- Private inline functions and macros shared with more than - * one deflate method - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - */ - -#ifndef DEFLATE_P_H -#define DEFLATE_P_H - -#include "functable.h" -#include "fallback_builtins.h" -#include "zmemory.h" - -/* Forward declare common non-inlined functions declared in deflate.c */ - -#ifdef ZLIB_DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -static inline void check_match(deflate_state *s, uint32_t start, uint32_t match, int length) { - /* check that the match length is valid*/ - if (length < STD_MIN_MATCH || length > STD_MAX_MATCH) { - fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); - z_error("invalid match length"); - } - /* check that the match isn't at the same position as the start string */ - if (match == start) { - fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); - z_error("invalid match position"); - } - /* check that the match is indeed a match */ - if (memcmp(s->window + match, s->window + start, length) != 0) { - int32_t i = 0; - fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); - do { - fprintf(stderr, " %03d: match [%02x] start [%02x]\n", i++, - s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr, "\\[%u,%d]", start-match, length); - do { - putc(s->window[start++], stderr); - } while (--length != 0); - } -} -#else -#define check_match(s, start, match, length) -#endif - -Z_INTERNAL void PREFIX(flush_pending)(PREFIX3(stream) *strm); - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ - -extern const unsigned char Z_INTERNAL zng_length_code[]; -extern const unsigned char Z_INTERNAL zng_dist_code[]; - -static inline int zng_tr_tally_lit(deflate_state *s, unsigned char c) { - /* c is the unmatched char */ - unsigned int sym_next = s->sym_next; -#ifdef LIT_MEM - s->d_buf[sym_next] = 0; - s->l_buf[sym_next] = c; - s->sym_next = sym_next + 1; -#else -# if OPTIMAL_CMP >= 32 - zng_memwrite_4(&s->sym_buf[sym_next], Z_U32_TO_LE((uint32_t)c << 16)); -# else - s->sym_buf[sym_next] = 0; - s->sym_buf[sym_next+1] = 0; - s->sym_buf[sym_next+2] = c; -# endif - s->sym_next = sym_next + 3; -#endif - s->dyn_ltree[c].Freq++; - Tracevv((stderr, "%c", c)); - Assert(c <= (STD_MAX_MATCH-STD_MIN_MATCH), "zng_tr_tally: bad literal"); - return (s->sym_next == s->sym_end); -} - -static inline int zng_tr_tally_dist(deflate_state* s, uint32_t dist, uint32_t len) { - /* dist: distance of matched string */ - /* len: match length-STD_MIN_MATCH */ - unsigned int sym_next = s->sym_next; -#ifdef LIT_MEM - Assert(dist <= UINT16_MAX, "dist should fit in uint16_t"); - Assert(len <= UINT8_MAX, "len should fit in uint8_t"); - s->d_buf[sym_next] = (uint16_t)dist; - s->l_buf[sym_next] = (uint8_t)len; - s->sym_next = sym_next + 1; -#else -# if OPTIMAL_CMP >= 32 - zng_memwrite_4(&s->sym_buf[sym_next], Z_U32_TO_LE(dist | ((uint32_t)len << 16))); -# else - s->sym_buf[sym_next] = (uint8_t)(dist); - s->sym_buf[sym_next+1] = (uint8_t)(dist >> 8); - s->sym_buf[sym_next+2] = (uint8_t)len; -# endif - s->sym_next = sym_next + 3; -#endif - s->matches++; - dist--; - Assert(dist < MAX_DIST(s) && (uint16_t)d_code(dist) < (uint16_t)D_CODES, - "zng_tr_tally: bad match"); - - s->dyn_ltree[zng_length_code[len] + LITERALS + 1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - return (s->sym_next == s->sym_end); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output, except for some - * deflate_stored() output, goes through this function so some applications may wish to - * modify it to avoid allocating a large strm->next_out buffer and copying into it. - * See also read_buf(). - */ -Z_FORCEINLINE static void flush_pending_inline(PREFIX3(stream) *strm) { - uint32_t len; - deflate_state *s = strm->state; - - zng_tr_flush_bits(s); - len = MIN(s->pending, strm->avail_out); - if (len == 0) - return; - - Tracev((stderr, "[FLUSH]")); - memcpy(strm->next_out, s->pending_out, len); - strm->next_out += len; - s->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; - if (s->pending == 0) - s->pending_out = s->pending_buf; -} - -/* =========================================================================== - * Reverse the first len bits of a code using bit manipulation - */ -Z_FORCEINLINE static uint16_t bi_reverse(uint16_t code, int len) { - /* code: the value to invert */ - /* len: its bit length */ - Assert(len >= 1 && len <= 15, "code length must be 1-15"); - return zng_bitreverse16(code) >> (16 - len); -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 and total number of - * bytes read. All deflate() input goes through this function so some applications may wish - * to modify it to avoid allocating a large strm->next_in buffer and copying from it. - * See also flush_pending_inline(). - */ -Z_FORCEINLINE static unsigned read_buf(PREFIX3(stream) *strm, unsigned char *buf, unsigned size) { - deflate_state *s = strm->state; - uint32_t len = MIN(strm->avail_in, size); - - if (len == 0) - return 0; - - if (!DEFLATE_NEED_CHECKSUM(strm)) { - memcpy(buf, strm->next_in, len); -#ifdef GZIP - } else if (s->wrap == 2) { - strm->adler = FUNCTABLE_CALL(crc32_copy)(strm->adler, buf, strm->next_in, len); -#endif - } else if (s->wrap == 1) { - strm->adler = FUNCTABLE_CALL(adler32_copy)(strm->adler, buf, strm->next_in, len); - } else { - memcpy(buf, strm->next_in, len); - } - - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - return len; -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, last) { \ - zng_tr_flush_block(s, (s->block_start >= 0 ? \ - &s->window[(unsigned)s->block_start] : \ - NULL), \ - (uint32_t)((int)s->strstart - s->block_start), \ - (last)); \ - s->block_start = (int)s->strstart; \ - PREFIX(flush_pending)(s->strm); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, last) { \ - FLUSH_BLOCK_ONLY(s, last); \ - if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ -} - -/* Maximum stored block length in deflate format (not including header). */ -#define MAX_STORED 65535 - -/* Compression function. Returns the block state after the call. */ -typedef block_state (*compress_func) (deflate_state *s, int flush); -/* Match function. Returns the longest match. */ -typedef uint32_t (*match_func) (deflate_state *const s, uint32_t cur_match); - -#endif diff --git a/modules/zlib/src/deflate_quick.c b/modules/zlib/src/deflate_quick.c deleted file mode 100644 index 5a066d1ea8..0000000000 --- a/modules/zlib/src/deflate_quick.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * The deflate_quick deflate strategy, designed to be used when cycles are - * at a premium. - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * Authors: - * Wajdi Feghali - * Jim Guilford - * Vinodh Gopal - * Erdinc Ozturk - * Jim Kukunas - * - * Portions are Copyright (C) 2016 12Sided Technology, LLC. - * Author: - * Phil Vachon - * - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zmemory.h" -#include "deflate.h" -#include "deflate_p.h" -#include "functable.h" -#include "trees_emit.h" -#include "insert_string_p.h" - -extern const ct_data static_ltree[L_CODES+2]; -extern const ct_data static_dtree[D_CODES]; - -Z_FORCEINLINE static void quick_start_block(deflate_state *s, int last) { - zng_tr_emit_tree(s, STATIC_TREES, last); - s->block_open = 1 + last; - s->block_start = (int)s->strstart; -} - -Z_FORCEINLINE static int quick_end_block(deflate_state *s, int last) { - if (s->block_open) { - zng_tr_emit_end_block(s, static_ltree, last); - s->block_open = 0; - s->block_start = (int)s->strstart; - PREFIX(flush_pending)(s->strm); - return (s->strm->avail_out == 0); - } - return 0; -} - -Z_INTERNAL block_state deflate_quick(deflate_state *s, int flush) { - unsigned char *window; - unsigned last = (flush == Z_FINISH) ? 1 : 0; - - if (UNLIKELY(last && s->block_open != 2)) { - /* Emit end of previous block */ - if (quick_end_block(s, 0)) - return need_more; - /* Emit start of last block */ - quick_start_block(s, last); - } else if (UNLIKELY(s->block_open == 0 && s->lookahead > 0)) { - /* Start new block only when we have lookahead data, so that if no - input data is given an empty block will not be written */ - quick_start_block(s, last); - } - - window = s->window; - - for (;;) { - uint8_t lc; - - if (UNLIKELY(s->pending + ((BIT_BUF_SIZE + 7) >> 3) >= s->pending_buf_size)) { - PREFIX(flush_pending)(s->strm); - if (s->strm->avail_out == 0) { - return (last && s->strm->avail_in == 0 && s->bi_valid == 0 && s->block_open == 0) ? finish_started : need_more; - } - } - - if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD)) { - PREFIX(fill_window)(s); - if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { - return need_more; - } - if (UNLIKELY(s->lookahead == 0)) - break; - - if (UNLIKELY(s->block_open == 0)) { - /* Start new block when we have lookahead data, so that if no - input data is given an empty block will not be written */ - quick_start_block(s, last); - } - } - - if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { - uint32_t str_val = Z_U32_FROM_LE(zng_memread_4(window + s->strstart)); - uint32_t hash_head = quick_insert_value(s, s->strstart, str_val); - int64_t dist = (int64_t)s->strstart - hash_head; - lc = (uint8_t)str_val; - - if (dist <= MAX_DIST(s) && dist > 0) { - const uint8_t *match_start = window + hash_head; - uint32_t match_val = Z_U32_FROM_LE(zng_memread_4(match_start)); - - if (str_val == match_val) { - const uint8_t *str_start = window + s->strstart; - uint32_t match_len = FUNCTABLE_CALL(compare256)(str_start+2, match_start+2) + 2; - - if (match_len >= WANT_MIN_MATCH) { - if (UNLIKELY(match_len > s->lookahead)) - match_len = s->lookahead; - - Assert(match_len <= STD_MAX_MATCH, "match too long"); - Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); - check_match(s, s->strstart, hash_head, match_len); - - zng_tr_emit_dist(s, static_ltree, static_dtree, match_len - STD_MIN_MATCH, (uint32_t)dist); - s->lookahead -= match_len; - s->strstart += match_len; - continue; - } - } - } - } else { - lc = window[s->strstart]; - } - zng_tr_emit_lit(s, static_ltree, lc); - s->strstart++; - s->lookahead--; - } - - s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); - if (UNLIKELY(last)) { - if (quick_end_block(s, 1)) - return finish_started; - return finish_done; - } - - if (quick_end_block(s, 0)) - return need_more; - return block_done; -} diff --git a/modules/zlib/src/deflate_rle.c b/modules/zlib/src/deflate_rle.c deleted file mode 100644 index b52fa2f0af..0000000000 --- a/modules/zlib/src/deflate_rle.c +++ /dev/null @@ -1,80 +0,0 @@ -/* deflate_rle.c -- compress data using RLE strategy of deflation algorithm - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "deflate.h" -#include "deflate_p.h" -#include "functable.h" -#include "compare256_rle.h" - -#if OPTIMAL_CMP == 8 -# define compare256_rle compare256_rle_8 -#else -# define compare256_rle compare256_rle_64 -#endif - -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -Z_INTERNAL block_state deflate_rle(deflate_state *s, int flush) { - int bflush = 0; /* set if current block must be flushed */ - unsigned char *scan; /* scan goes up to strend for length of run */ - uint32_t match_len = 0; - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need STD_MAX_MATCH bytes - * for the longest run, plus one for the unrolled loop. - */ - if (s->lookahead <= STD_MAX_MATCH) { - PREFIX(fill_window)(s); - if (s->lookahead <= STD_MAX_MATCH && flush == Z_NO_FLUSH) - return need_more; - if (s->lookahead == 0) - break; /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - if (s->lookahead >= STD_MIN_MATCH && s->strstart > 0) { - scan = s->window + s->strstart - 1; - if (scan[0] == scan[1] && scan[1] == scan[2]) { - match_len = compare256_rle(scan, scan+3)+2; - match_len = MIN(match_len, s->lookahead); - match_len = MIN(match_len, STD_MAX_MATCH); - } - Assert(scan+match_len <= s->window + s->window_size - 1, "wild scan"); - } - - /* Emit match if have run of STD_MIN_MATCH or longer, else emit literal */ - if (match_len >= STD_MIN_MATCH) { - Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); - check_match(s, s->strstart, s->strstart - 1, match_len); - - bflush = zng_tr_tally_dist(s, 1, match_len - STD_MIN_MATCH); - - s->lookahead -= match_len; - s->strstart += match_len; - match_len = 0; - } else { - /* No match, output a literal byte */ - bflush = zng_tr_tally_lit(s, s->window[s->strstart]); - s->lookahead--; - s->strstart++; - } - if (bflush) - FLUSH_BLOCK(s, 0); - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->sym_next) - FLUSH_BLOCK(s, 0); - return block_done; -} diff --git a/modules/zlib/src/deflate_slow.c b/modules/zlib/src/deflate_slow.c deleted file mode 100644 index e524ec1e37..0000000000 --- a/modules/zlib/src/deflate_slow.c +++ /dev/null @@ -1,151 +0,0 @@ -/* deflate_slow.c -- compress data using the slow strategy of deflation algorithm - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "deflate.h" -#include "deflate_p.h" -#include "functable.h" -#include "insert_string_p.h" - -/* =========================================================================== - * Same as deflate_medium, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -Z_INTERNAL block_state deflate_slow(deflate_state *s, int flush) { - match_func longest_match; - insert_string_cb insert_string_func; - unsigned char *window = s->window; - int bflush; /* set if current block must be flushed */ - int level = s->level; - - if (level >= 9) { - longest_match = FUNCTABLE_FPTR(longest_match_roll); - insert_string_func = insert_string_roll; - } else { - longest_match = FUNCTABLE_FPTR(longest_match); - insert_string_func = insert_string; - } - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need STD_MAX_MATCH bytes - * for the next match, plus WANT_MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - PREFIX(fill_window)(s); - if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { - return need_more; - } - if (UNLIKELY(s->lookahead == 0)) - break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - uint32_t hash_head = 0; - if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { - if (level >= 9) - hash_head = quick_insert_string_roll(s, s->strstart); - else - hash_head = quick_insert_string(s, s->strstart); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_match = s->match_start; - uint32_t match_len = STD_MIN_MATCH - 1; - int64_t dist = (int64_t)s->strstart - hash_head; - - if (dist <= MAX_DIST(s) && dist > 0 && s->prev_length < s->max_lazy_match && hash_head != 0) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - match_len = longest_match(s, hash_head); - /* longest_match() sets match_start */ - - if (match_len <= 5 && (s->strategy == Z_FILTERED)) { - /* If prev_match is also WANT_MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - match_len = STD_MIN_MATCH - 1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= STD_MIN_MATCH && match_len <= s->prev_length) { - unsigned int max_insert = s->strstart + s->lookahead - STD_MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - Assert((s->strstart-1) <= UINT16_MAX, "strstart-1 should fit in uint16_t"); - check_match(s, s->strstart - 1, s->prev_match, s->prev_length); - - bflush = zng_tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - STD_MIN_MATCH); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->prev_length -= 1; - s->lookahead -= s->prev_length; - - unsigned int mov_fwd = s->prev_length - 1; - if (max_insert > s->strstart) { - unsigned int insert_cnt = mov_fwd; - if (UNLIKELY(insert_cnt > max_insert - s->strstart)) - insert_cnt = max_insert - s->strstart; - insert_string_func(s, s->strstart + 1, insert_cnt); - } - s->prev_length = 0; - s->match_available = 0; - s->strstart += mov_fwd + 1; - - if (UNLIKELY(bflush)) - FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - bflush = zng_tr_tally_lit(s, window[s->strstart-1]); - if (UNLIKELY(bflush)) - FLUSH_BLOCK_ONLY(s, 0); - s->prev_length = match_len; - s->strstart++; - s->lookahead--; - if (UNLIKELY(s->strm->avail_out == 0)) - return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->prev_length = match_len; - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert(flush != Z_NO_FLUSH, "no flush?"); - if (UNLIKELY(s->match_available)) { - Z_UNUSED(zng_tr_tally_lit(s, window[s->strstart-1])); - s->match_available = 0; - } - s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); - if (UNLIKELY(flush == Z_FINISH)) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (UNLIKELY(s->sym_next)) - FLUSH_BLOCK(s, 0); - return block_done; -} diff --git a/modules/zlib/src/deflate_stored.c b/modules/zlib/src/deflate_stored.c deleted file mode 100644 index f912f631b2..0000000000 --- a/modules/zlib/src/deflate_stored.c +++ /dev/null @@ -1,187 +0,0 @@ -/* deflate_stored.c -- store data without compression using deflation algorithm - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "deflate.h" -#include "deflate_p.h" -#include "functable.h" - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * - * In case deflateParams() is used to later switch to a non-zero compression - * level, s->matches (otherwise unused when storing) keeps track of the number - * of hash table slides to perform. If s->matches is 1, then one hash table - * slide will be done when switching. If s->matches is 2, the maximum value - * allowed here, then the hash table will be cleared, since two or more slides - * is the same as a clear. - * - * deflate_stored() is written to minimize the number of times an input byte is - * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunities to have a single copy from next_in to next_out. - */ -Z_INTERNAL block_state deflate_stored(deflate_state *s, int flush) { - /* Smallest worthy block size when not flushing or finishing. By default - * this is 32K. This can be as small as 507 bytes for memLevel == 1. For - * large input and output buffers, the stored block size will be larger. - */ - unsigned int w_size = s->w_size; - unsigned min_block = MIN(s->pending_buf_size - 5, w_size); - - /* Copy as many min_block or larger stored blocks directly to next_out as - * possible. If flushing, copy the remaining available input to next_out as - * stored blocks, if there is enough space. - */ - unsigned len, left, have, last = 0; - unsigned used = s->strm->avail_in; - do { - /* Set len to the maximum size block that we can copy directly with the - * available input data and output space. Set left to how much of that - * would be copied from what's left in the window. - */ - len = MAX_STORED; /* maximum deflate stored block length */ - have = (s->bi_valid + 42) >> 3; /* number of header bytes */ - if (s->strm->avail_out < have) /* need room for header */ - break; - /* maximum stored block length that will fit in avail_out: */ - have = s->strm->avail_out - have; - left = (int)s->strstart - s->block_start; /* bytes left in window */ - if (len > (unsigned long)left + s->strm->avail_in) - len = left + s->strm->avail_in; /* limit len to the input */ - len = MIN(len, have); /* limit len to the output */ - - /* If the stored block would be less than min_block in length, or if - * unable to copy all of the available input when flushing, then try - * copying to the window and the pending buffer instead. Also don't - * write an empty block when flushing -- deflate() does that. - */ - if (len < min_block && ((len == 0 && flush != Z_FINISH) || flush == Z_NO_FLUSH || len != left + s->strm->avail_in)) - break; - - /* Make a dummy stored block in pending to get the header bytes, - * including any pending bits. This also updates the debugging counts. - */ - last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; - zng_tr_stored_block(s, NULL, 0L, last); - - /* Replace the lengths in the dummy stored block with len. */ - s->pending -= 4; - put_short(s, (uint16_t)len); - put_short(s, (uint16_t)~len); - - /* Write the stored block header bytes. */ - PREFIX(flush_pending)(s->strm); - - /* Update debugging counts for the data about to be copied. */ - cmpr_bits_add(s, len << 3); - sent_bits_add(s, len << 3); - - /* Copy uncompressed bytes from the window to next_out. */ - if (left) { - left = MIN(left, len); - memcpy(s->strm->next_out, s->window + s->block_start, left); - s->strm->next_out += left; - s->strm->avail_out -= left; - s->strm->total_out += left; - s->block_start += (int)left; - len -= left; - } - - /* Copy uncompressed bytes directly from next_in to next_out, updating - * the check value. - */ - if (len) { - read_buf(s->strm, s->strm->next_out, len); - s->strm->next_out += len; - s->strm->avail_out -= len; - s->strm->total_out += len; - } - } while (last == 0); - - /* Update the sliding window with the last s->w_size bytes of the copied - * data, or append all of the copied data to the existing window if less - * than s->w_size bytes were copied. Also update the number of bytes to - * insert in the hash tables, in the event that deflateParams() switches to - * a non-zero compression level. - */ - used -= s->strm->avail_in; /* number of input bytes directly copied */ - if (used) { - /* If any input was used, then no unused input remains in the window, - * therefore s->block_start == s->strstart. - */ - if (used >= w_size) { /* supplant the previous history */ - s->matches = 2; /* clear hash */ - memcpy(s->window, s->strm->next_in - w_size, w_size); - s->strstart = w_size; - s->insert = s->strstart; - } else { - if (s->window_size - s->strstart <= used) { - /* Slide the window down. */ - s->strstart -= w_size; - memcpy(s->window, s->window + w_size, s->strstart); - if (s->matches < 2) - s->matches++; /* add a pending slide_hash() */ - s->insert = MIN(s->insert, s->strstart); - } - memcpy(s->window + s->strstart, s->strm->next_in - used, used); - s->strstart += used; - s->insert += MIN(used, w_size - s->insert); - } - s->block_start = (int)s->strstart; - } - s->high_water = MAX(s->high_water, s->strstart); - - /* If the last block was written to next_out, then done. */ - if (last) - return finish_done; - - /* If flushing and all input has been consumed, then done. */ - if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (int)s->strstart == s->block_start) - return block_done; - - /* Fill the window with any remaining input. */ - have = s->window_size - s->strstart; - if (s->strm->avail_in > have && s->block_start >= (int)w_size) { - /* Slide the window down. */ - s->block_start -= (int)w_size; - s->strstart -= w_size; - memcpy(s->window, s->window + w_size, s->strstart); - if (s->matches < 2) - s->matches++; /* add a pending slide_hash() */ - have += w_size; /* more space now */ - s->insert = MIN(s->insert, s->strstart); - } - - have = MIN(have, s->strm->avail_in); - if (have) { - read_buf(s->strm, s->window + s->strstart, have); - s->strstart += have; - s->insert += MIN(have, w_size - s->insert); - } - s->high_water = MAX(s->high_water, s->strstart); - - /* There was not enough avail_out to write a complete worthy or flushed - * stored block to next_out. Write a stored block to pending instead, if we - * have enough input for a worthy block, or if flushing and there is enough - * room for the remaining input as a stored block in the pending buffer. - */ - have = (s->bi_valid + 42) >> 3; /* number of header bytes */ - /* maximum stored block length that will fit in pending: */ - have = MIN(s->pending_buf_size - have, MAX_STORED); - min_block = MIN(have, w_size); - left = (int)s->strstart - s->block_start; - if (left >= min_block || ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && s->strm->avail_in == 0 && left <= have)) { - len = MIN(left, have); - last = flush == Z_FINISH && s->strm->avail_in == 0 && len == left ? 1 : 0; - zng_tr_stored_block(s, s->window + s->block_start, len, last); - s->block_start += (int)len; - PREFIX(flush_pending)(s->strm); - } - - /* We've done all we can with the available input and output. */ - return last ? finish_started : need_more; -} diff --git a/modules/zlib/src/fallback_builtins.h b/modules/zlib/src/fallback_builtins.h deleted file mode 100644 index 16ed1e70d5..0000000000 --- a/modules/zlib/src/fallback_builtins.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef FALLBACK_BUILTINS_H -#define FALLBACK_BUILTINS_H - -#if defined(_MSC_VER) && !defined(__clang__) -# include -#endif - -/* Provide fallback for compilers that don't support __has_builtin */ -#ifndef __has_builtin -# define __has_builtin(x) 0 -#endif - -/* Count trailing zeros (CTZ) functions with portable fallback. - * - * Predicate: Input must be non-zero. The result is undefined for zero input because - * __builtin_ctz, BSF, and TZCNT all have undefined/different behavior for zero. TZCNT - * returns operand size for zero, BSF leaves destination undefined, and __builtin_ctz - * is explicitly undefined per GCC/Clang docs. */ - -Z_FORCEINLINE static uint32_t zng_ctz32(uint32_t value) { - Assert(value != 0, "Invalid input value: 0"); -#if __has_builtin(__builtin_ctz) - return (uint32_t)__builtin_ctz(value); -#elif defined(_MSC_VER) && !defined(__clang__) -# if defined(X86_FEATURES) && !(_MSC_VER < 1700) - /* tzcnt falls back to bsf on cpus without BMI1, and is equal or faster on all x86 cpus. */ - return (uint32_t)_tzcnt_u32(value); -# else - unsigned long trailing_zero; - _BitScanForward(&trailing_zero, value); - return (uint32_t)trailing_zero; -# endif -#else - /* De Bruijn CTZ for 32-bit values */ - static const uint8_t debruijn_ctz32[32] = { - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 - }; - uint32_t lsb = value & (~value + 1u); - return debruijn_ctz32[(lsb * 0x077CB531U) >> 27]; -#endif -} - -Z_FORCEINLINE static uint32_t zng_ctz64(uint64_t value) { - Assert(value != 0, "Invalid input value: 0"); -#if __has_builtin(__builtin_ctzll) - return (uint32_t)__builtin_ctzll(value); -#elif defined(_MSC_VER) && !defined(__clang__) && defined(ARCH_64BIT) -# if defined(X86_FEATURES) && !(_MSC_VER < 1700) - /* tzcnt falls back to bsf on cpus without BMI1, and is equal or faster on all x86 cpus. */ - return (uint32_t)_tzcnt_u64(value); -# else - unsigned long trailing_zero; - _BitScanForward64(&trailing_zero, value); - return (uint32_t)trailing_zero; -# endif -#else - /* De Bruijn CTZ for 64-bit values */ - static const uint8_t debruijn_ctz64[64] = { - 63, 0, 1, 52, 2, 6, 53, 26, 3, 37, 40, 7, 33, 54, 47, 27, - 61, 4, 38, 45, 43, 41, 21, 8, 23, 34, 58, 55, 48, 17, 28, 10, - 62, 51, 5, 25, 36, 39, 32, 46, 60, 44, 42, 20, 22, 57, 16, 9, - 50, 24, 35, 31, 59, 19, 56, 15, 49, 30, 18, 14, 29, 13, 12, 11 - }; - uint64_t lsb = value & (~value + 1ull); - return debruijn_ctz64[(lsb * 0x045FBAC7992A70DAULL) >> 58]; -#endif -} - -/* Count leading zeros (CLZ) functions with portable fallback. - * - * Predicate: Input must be non-zero. The result is undefined for zero input because - * __builtin_clz, BSR, and LZCNT all have undefined/different behavior for zero. LZCNT - * returns operand size for zero, BSR leaves destination undefined, and __builtin_clz - * is explicitly undefined per GCC/Clang docs. */ - -Z_FORCEINLINE static uint32_t zng_clz32(uint32_t value) { - Assert(value != 0, "Invalid input value: 0"); -#if __has_builtin(__builtin_clz) - return (uint32_t)__builtin_clz(value); -#elif defined(_MSC_VER) && !defined(__clang__) - unsigned long leading_zero; - _BitScanReverse(&leading_zero, value); - return 31u - (uint32_t)leading_zero; -#else - /* Smear the highest set bit down, isolate it, then reuse de Bruijn CTZ */ - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - return 31u - zng_ctz32((value >> 1) + 1u); -#endif -} - -Z_FORCEINLINE static uint32_t zng_clz64(uint64_t value) { - Assert(value != 0, "Invalid input value: 0"); -#if __has_builtin(__builtin_clzll) - return (uint32_t)__builtin_clzll(value); -#elif defined(_MSC_VER) && !defined(__clang__) && defined(ARCH_64BIT) - unsigned long leading_zero; - _BitScanReverse64(&leading_zero, value); - return 63u - (uint32_t)leading_zero; -#elif defined(_MSC_VER) && !defined(__clang__) - /* 32-bit MSVC fallback using two 32-bit scans */ - unsigned long leading_zero; - if (_BitScanReverse(&leading_zero, (uint32_t)(value >> 32))) - return 31u - (uint32_t)leading_zero; - _BitScanReverse(&leading_zero, (uint32_t)value); - return 63u - (uint32_t)leading_zero; -#else - /* Smear the highest set bit down, isolate it, then reuse de Bruijn CTZ */ - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value |= value >> 32; - return 63u - zng_ctz64((value >> 1) + 1ull); -#endif -} - -/* Byte-position of the first differing byte in a native-endian XOR diff, - * using CTZ on little-endian and CLZ on big-endian to avoid a byte-swap. */ -#if BYTE_ORDER == BIG_ENDIAN -# define zng_first_diff_byte32(diff) (zng_clz32(diff) / 8) -# define zng_first_diff_byte64(diff) (zng_clz64(diff) / 8) -#else -# define zng_first_diff_byte32(diff) (zng_ctz32(diff) / 8) -# define zng_first_diff_byte64(diff) (zng_ctz64(diff) / 8) -#endif - -Z_FORCEINLINE static uint16_t zng_bitreverse16(uint16_t value) { -#if __has_builtin(__builtin_bitreverse16) - return (uint16_t)__builtin_bitreverse16(value); -#elif defined(ARCH_ARM) && defined(ARCH_64BIT) && !defined(_MSC_VER) - /* ARM bit reversal for 16-bit values using rbit instruction */ - uint32_t res; -# if __has_builtin(__builtin_rbit) - res = __builtin_rbit((uint32_t)value); -# else - __asm__ volatile("rbit %w0, %w1" : "=r"(res) : "r"((uint32_t)value)); -# endif - return (uint16_t)(res >> 16); -#elif defined(ARCH_LOONGARCH) - /* LoongArch bit reversal for 16-bit values */ - uint32_t res; - __asm__ volatile("bitrev.w %0, %1" : "=r"(res) : "r"(value)); - return (uint16_t)(res >> 16); -#else - /* Bit reversal for 8-bit values using multiplication method */ -# define bitrev8(value) \ - (uint8_t)((((uint8_t)(value) * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32) - /* General purpose bit reversal for 16-bit values */ - return ((bitrev8(value >> 8) | (uint16_t)bitrev8(value) << 8)); -# undef bitrev8 -#endif -} - -#endif // include guard FALLBACK_BUILTINS_H diff --git a/modules/zlib/src/fill_window_sse.c b/modules/zlib/src/fill_window_sse.c new file mode 100644 index 0000000000..ed1e5d1d67 --- /dev/null +++ b/modules/zlib/src/fill_window_sse.c @@ -0,0 +1,177 @@ +/* + * Fill Window with SSE2-optimized hash shifting + * + * Copyright (C) 2013 Intel Corporation + * Authors: + * Arjan van de Ven + * Jim Kukunas + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include "deflate.h" + +#define UPDATE_HASH(s,h,i) \ + {\ + if (s->level < 6) { \ + h = (3483 * (s->window[i]) +\ + 23081* (s->window[i+1]) +\ + 6954 * (s->window[i+2]) +\ + 20947* (s->window[i+3])) & s->hash_mask;\ + } else {\ + h = (25881* (s->window[i]) +\ + 24674* (s->window[i+1]) +\ + 25811* (s->window[i+2])) & s->hash_mask;\ + }\ + }\ + +extern int deflate_read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); + +void fill_window_sse(deflate_state *s) +{ + const __m128i xmm_wsize = _mm_set1_epi16(s->w_size); + + register unsigned n; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + p -= 8; + do { + __m128i value, result; + + value = _mm_loadu_si128((__m128i *)p); + result = _mm_subs_epu16(value, xmm_wsize); + _mm_storeu_si128((__m128i *)p, result); + + p -= 8; + n -= 8; + } while (n > 0); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + p -= 8; + do { + __m128i value, result; + + value = _mm_loadu_si128((__m128i *)p); + result = _mm_subs_epu16(value, xmm_wsize); + _mm_storeu_si128((__m128i *)p, result); + + p -= 8; + n -= 8; + } while (n > 0); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = deflate_read_buf(s->strm, + s->window + s->strstart + s->lookahead, + more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + uInt str = s->strstart; + s->ins_h = s->window[str]; + if (str >= 1) + UPDATE_HASH(s, s->ins_h, str + 1 - (MIN_MATCH-1)); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} diff --git a/modules/zlib/src/functable.c b/modules/zlib/src/functable.c deleted file mode 100644 index b2319a7aca..0000000000 --- a/modules/zlib/src/functable.c +++ /dev/null @@ -1,516 +0,0 @@ -/* functable.c -- Choose relevant optimized functions at runtime - * Copyright (C) 2017 Hans Kristian Rosbach - * For conditions of distribution and use, see copyright notice in zlib.h - */ -#ifndef DISABLE_RUNTIME_CPU_DETECTION - -#include "zbuild.h" - -#if defined(_MSC_VER) -# include -#endif - -#include "functable.h" -#include "cpu_features.h" -#include "arch_functions.h" - -/* Platform has pointer size atomic store */ -#if defined(__GNUC__) || defined(__clang__) -# define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \ - __atomic_store(&(functable.FUNC_NAME), &(VAR.FUNC_NAME), __ATOMIC_SEQ_CST) -# define FUNCTABLE_BARRIER() __atomic_thread_fence(__ATOMIC_SEQ_CST) -#elif defined(_MSC_VER) -# define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \ - _InterlockedExchangePointer((void * volatile *)&(functable.FUNC_NAME), (void *)(VAR.FUNC_NAME)) -# ifdef ARCH_ARM -# define FUNCTABLE_BARRIER() do { \ - _ReadWriteBarrier(); \ - __dmb(0xB); /* _ARM_BARRIER_ISH */ \ - _ReadWriteBarrier(); \ -} while (0) -# else -# define FUNCTABLE_BARRIER() _ReadWriteBarrier() -# endif -#else -# warning Unable to detect atomic intrinsic support. -# define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \ - *((void * volatile *)&(functable.FUNC_NAME)) = (void *)(VAR.FUNC_NAME) -# define FUNCTABLE_BARRIER() do { /* Empty */ } while (0) -#endif - -/* Verify all pointers are valid before assigning, return 1 on failure - * This allows inflateinit/deflateinit functions to gracefully return Z_VERSION_ERROR - * if functable initialization fails. - */ -#define FUNCTABLE_VERIFY_ASSIGN(VAR, FUNC_NAME) \ - if (!VAR.FUNC_NAME) { \ - fprintf(stderr, "Zlib-ng functable failed initialization!\n"); \ - return 1; \ - } \ - FUNCTABLE_ASSIGN(VAR, FUNC_NAME); - -/* Functable init & abort on failure. - * Abort is needed because some stub functions are reachable without first - * calling any inflateinit/deflateinit functions, and have no error propagation. - */ -#define FUNCTABLE_INIT_ABORT \ - if (init_functable()) { \ - fprintf(stderr, "Zlib-ng functable failed initialization!\n"); \ - abort(); \ - }; - -// Empty stub, used when functable has already been initialized -static int force_init_empty(void) { - return 0; -} - -/* Functable initialization. - * Selects the best available optimized functions appropriate for the runtime cpu. - */ -static int init_functable(void) { - struct functable_s ft; - struct cpu_features cf; - - memset(&ft, 0, sizeof(struct functable_s)); - cpu_check_features(&cf); - ft.force_init = &force_init_empty; - - // Only use necessary generic functions when no suitable simd versions are available. -#ifdef ADLER32_FALLBACK - ft.adler32 = &adler32_c; - ft.adler32_copy = &adler32_copy_c; -#endif -#ifdef CHUNKSET_FALLBACK - ft.chunkmemset_safe = &chunkmemset_safe_c; - ft.inflate_fast = &inflate_fast_c; -#endif -#ifdef COMPARE256_FALLBACK - ft.compare256 = &compare256_c; - ft.longest_match = &longest_match_c; - ft.longest_match_roll = &longest_match_roll_c; -#endif -#ifdef CRC32_BRAID_FALLBACK - ft.crc32 = &crc32_braid; - ft.crc32_copy = &crc32_copy_braid; -#endif -#ifdef SLIDE_HASH_FALLBACK - ft.slide_hash = &slide_hash_c; -#endif - - // Select arch-optimized functions -#ifdef WITH_OPTIM - - // Chorba generic C fallback -#ifdef CRC32_CHORBA_FALLBACK - ft.crc32 = &crc32_chorba; - ft.crc32_copy = &crc32_copy_chorba; -#endif - - // X86 - SSE2 -#ifdef X86_SSE2 -# ifndef X86_SSE2_NATIVE - if (cf.x86.has_sse2) -# endif - { -# ifndef X86_AVX2_NATIVE - ft.chunkmemset_safe = &chunkmemset_safe_sse2; - ft.compare256 = &compare256_sse2; - ft.inflate_fast = &inflate_fast_sse2; - ft.longest_match = &longest_match_sse2; - ft.longest_match_roll = &longest_match_roll_sse2; - ft.slide_hash = &slide_hash_sse2; -# endif -# if !defined(WITHOUT_CHORBA_SSE) && !defined(X86_PCLMULQDQ_NATIVE) - ft.crc32 = &crc32_chorba_sse2; - ft.crc32_copy = &crc32_copy_chorba_sse2; -# endif - } -#endif - // X86 - SSSE3 -#ifdef X86_SSSE3 -# ifndef X86_SSSE3_NATIVE - if (cf.x86.has_ssse3) -# endif - { - ft.adler32 = &adler32_ssse3; - ft.adler32_copy = &adler32_copy_ssse3; -# ifndef X86_AVX2_NATIVE - ft.chunkmemset_safe = &chunkmemset_safe_ssse3; - ft.inflate_fast = &inflate_fast_ssse3; -# endif - } -#endif - - // X86 - SSE4.1 -#if defined(X86_SSE41) && !defined(X86_PCLMULQDQ_NATIVE) -# ifndef X86_SSE41_NATIVE - if (cf.x86.has_sse41) -# endif - { -# ifndef WITHOUT_CHORBA_SSE - ft.crc32 = &crc32_chorba_sse41; - ft.crc32_copy = &crc32_copy_chorba_sse41; -# endif - } -#endif - - // X86 - SSE4.2 -#if defined(X86_SSE42) && !defined(X86_AVX512_NATIVE) -# ifndef X86_SSE42_NATIVE - if (cf.x86.has_sse42) -# endif - { - ft.adler32_copy = &adler32_copy_sse42; - } -#endif - // X86 - PCLMUL -#if defined(X86_PCLMULQDQ_CRC) && !defined(X86_VPCLMULQDQ_NATIVE) -# ifndef X86_PCLMULQDQ_NATIVE - if (cf.x86.has_pclmulqdq) -# endif - { - ft.crc32 = &crc32_pclmulqdq; - ft.crc32_copy = &crc32_copy_pclmulqdq; - } -#endif - // X86 - AVX2 -#ifdef X86_AVX2 - /* BMI2 support is all but implicit with AVX2 but let's sanity check this just in case. Enabling BMI2 allows for - * flagless shifts, resulting in fewer flag stalls for the pipeline, and allows us to set destination registers - * for the shift results as an operand, eliminating several register-register moves when the original value needs - * to remain intact. They also allow for a count operand that isn't the CL register, avoiding contention there */ -# ifndef X86_AVX2_NATIVE - if (cf.x86.has_avx2 && cf.x86.has_bmi2) -# endif - { -# ifndef X86_AVX512_NATIVE - ft.adler32 = &adler32_avx2; - ft.adler32_copy = &adler32_copy_avx2; - ft.chunkmemset_safe = &chunkmemset_safe_avx2; - ft.compare256 = &compare256_avx2; - ft.inflate_fast = &inflate_fast_avx2; - ft.longest_match = &longest_match_avx2; - ft.longest_match_roll = &longest_match_roll_avx2; -# endif - ft.slide_hash = &slide_hash_avx2; - } -#endif - // X86 - AVX512 (F,DQ,BW,Vl) -#ifdef X86_AVX512 -# ifndef X86_AVX512_NATIVE - if (cf.x86.has_avx512_common) -# endif - { -# ifndef X86_AVX512VNNI_NATIVE - ft.adler32 = &adler32_avx512; - ft.adler32_copy = &adler32_copy_avx512; -# endif - ft.chunkmemset_safe = &chunkmemset_safe_avx512; - ft.compare256 = &compare256_avx512; - ft.inflate_fast = &inflate_fast_avx512; - ft.longest_match = &longest_match_avx512; - ft.longest_match_roll = &longest_match_roll_avx512; - } -#endif -#ifdef X86_AVX512VNNI -# ifndef X86_AVX512VNNI_NATIVE - if (cf.x86.has_avx512vnni) -# endif - { - ft.adler32 = &adler32_avx512_vnni; - ft.adler32_copy = &adler32_copy_avx512_vnni; - } -#endif - // X86 - VPCLMULQDQ (AVX2) -#ifdef X86_VPCLMULQDQ_AVX2 -# ifndef X86_VPCLMULQDQ_AVX2_NATIVE - if (cf.x86.has_pclmulqdq && cf.x86.has_avx2 && cf.x86.has_vpclmulqdq) -# endif - { - ft.crc32 = &crc32_vpclmulqdq_avx2; - ft.crc32_copy = &crc32_copy_vpclmulqdq_avx2; - } -#endif - // X86 - VPCLMULQDQ (AVX-512) -#ifdef X86_VPCLMULQDQ_AVX512 -# ifndef X86_VPCLMULQDQ_AVX512_NATIVE - if (cf.x86.has_pclmulqdq && cf.x86.has_avx512_common && cf.x86.has_vpclmulqdq) -# endif - { - ft.crc32 = &crc32_vpclmulqdq_avx512; - ft.crc32_copy = &crc32_copy_vpclmulqdq_avx512; - } -#endif - - - // ARM - SIMD -#if defined(ARM_SIMD) && !defined(ARM_NEON_NATIVE) -# ifndef ARM_SIMD_NATIVE - if (cf.arm.has_simd) -# endif - { - ft.slide_hash = &slide_hash_armv6; - } -#endif - // ARM - NEON -#ifdef ARM_NEON -# ifndef ARM_NEON_NATIVE - if (cf.arm.has_neon) -# endif - { - ft.adler32 = &adler32_neon; - ft.adler32_copy = &adler32_copy_neon; - ft.chunkmemset_safe = &chunkmemset_safe_neon; - ft.compare256 = &compare256_neon; - ft.inflate_fast = &inflate_fast_neon; - ft.longest_match = &longest_match_neon; - ft.longest_match_roll = &longest_match_roll_neon; - ft.slide_hash = &slide_hash_neon; - } -#endif - // ARM - CRC32 -#if defined(ARM_CRC32) && !defined(ARM_PMULL_EOR3_NATIVE) -# ifndef ARM_CRC32_NATIVE - if (cf.arm.has_crc32) -# endif - { - ft.crc32 = &crc32_armv8; - ft.crc32_copy = &crc32_copy_armv8; - } -#endif - // ARM - PMULL EOR3 -#ifdef ARM_PMULL_EOR3 -# ifndef ARM_PMULL_EOR3_NATIVE - if (cf.arm.has_crc32 && cf.arm.has_pmull && cf.arm.has_eor3 && cf.arm.has_fast_pmull) -# endif - { - ft.crc32 = &crc32_armv8_pmull_eor3; - ft.crc32_copy = &crc32_copy_armv8_pmull_eor3; - } -#endif - - // Power - VMX -#ifdef PPC_VMX -# ifndef PPC_VMX_NATIVE - if (cf.power.has_altivec) -# endif - { - ft.adler32 = &adler32_vmx; - ft.adler32_copy = &adler32_copy_vmx; - ft.slide_hash = &slide_hash_vmx; - } -#endif - // Power8 - VSX -#ifdef POWER8_VSX -# ifndef POWER8_VSX_NATIVE - if (cf.power.has_arch_2_07) -# endif - { - ft.adler32 = &adler32_power8; - ft.adler32_copy = &adler32_copy_power8; - ft.chunkmemset_safe = &chunkmemset_safe_power8; - ft.inflate_fast = &inflate_fast_power8; - ft.slide_hash = &slide_hash_power8; - } -#endif -#ifdef POWER8_VSX_CRC32 -# ifndef POWER8_VSX_CRC32_NATIVE - if (cf.power.has_arch_2_07) -# endif - { - ft.crc32 = &crc32_power8; - ft.crc32_copy = &crc32_copy_power8; - } -#endif - // Power9 -#ifdef POWER9 -# ifndef POWER9_NATIVE - if (cf.power.has_arch_3_00) -# endif - { - ft.compare256 = &compare256_power9; - ft.longest_match = &longest_match_power9; - ft.longest_match_roll = &longest_match_roll_power9; - } -#endif - - - // RISCV - RVV -#ifdef RISCV_RVV -# ifndef RISCV_RVV_NATIVE - if (cf.riscv.has_rvv) -# endif - { - ft.adler32 = &adler32_rvv; - ft.adler32_copy = &adler32_copy_rvv; - ft.chunkmemset_safe = &chunkmemset_safe_rvv; - ft.compare256 = &compare256_rvv; - ft.inflate_fast = &inflate_fast_rvv; - ft.longest_match = &longest_match_rvv; - ft.longest_match_roll = &longest_match_roll_rvv; - ft.slide_hash = &slide_hash_rvv; - } -#endif - - // RISCV - ZBC -#ifdef RISCV_CRC32_ZBC -# ifndef RISCV_ZBC_NATIVE - if (cf.riscv.has_zbc) -# endif - { - ft.crc32 = &crc32_riscv64_zbc; - ft.crc32_copy = &crc32_copy_riscv64_zbc; - } -#endif - - // S390 -#ifdef S390_VX -# ifndef S390_VX_NATIVE - if (cf.s390.has_vx) -# endif - { - ft.crc32 = &crc32_s390_vx; - ft.crc32_copy = &crc32_copy_s390_vx; - ft.slide_hash = &slide_hash_vx; - } -#endif - - // LOONGARCH -#ifdef LOONGARCH_CRC -# ifndef LOONGARCH_CRC_NATIVE - if (cf.loongarch.has_crc) -# endif - { - ft.crc32 = &crc32_loongarch64; - ft.crc32_copy = &crc32_copy_loongarch64; - } -#endif -#if defined(LOONGARCH_LSX) && !defined(LOONGARCH_LASX_NATIVE) -# ifndef LOONGARCH_LSX_NATIVE - if (cf.loongarch.has_lsx) -# endif - { - ft.adler32 = &adler32_lsx; - ft.adler32_copy = &adler32_copy_lsx; - ft.chunkmemset_safe = &chunkmemset_safe_lsx; - ft.compare256 = &compare256_lsx; - ft.inflate_fast = &inflate_fast_lsx; - ft.longest_match = &longest_match_lsx; - ft.longest_match_roll = &longest_match_roll_lsx; - ft.slide_hash = &slide_hash_lsx; - } -#endif -#ifdef LOONGARCH_LASX -# ifndef LOONGARCH_LASX_NATIVE - if (cf.loongarch.has_lasx) -# endif - { - ft.adler32 = &adler32_lasx; - ft.adler32_copy = &adler32_copy_lasx; - ft.chunkmemset_safe = &chunkmemset_safe_lasx; - ft.compare256 = &compare256_lasx; - ft.inflate_fast = &inflate_fast_lasx; - ft.longest_match = &longest_match_lasx; - ft.longest_match_roll = &longest_match_roll_lasx; - ft.slide_hash = &slide_hash_lasx; - } -#endif - -#endif // WITH_OPTIM - - // Assign function pointers individually for atomic operation - FUNCTABLE_ASSIGN(ft, force_init); - FUNCTABLE_VERIFY_ASSIGN(ft, adler32); - FUNCTABLE_VERIFY_ASSIGN(ft, adler32_copy); - FUNCTABLE_VERIFY_ASSIGN(ft, chunkmemset_safe); - FUNCTABLE_VERIFY_ASSIGN(ft, compare256); - FUNCTABLE_VERIFY_ASSIGN(ft, crc32); - FUNCTABLE_VERIFY_ASSIGN(ft, crc32_copy); - FUNCTABLE_VERIFY_ASSIGN(ft, inflate_fast); - FUNCTABLE_VERIFY_ASSIGN(ft, longest_match); - FUNCTABLE_VERIFY_ASSIGN(ft, longest_match_roll); - FUNCTABLE_VERIFY_ASSIGN(ft, slide_hash); - - // Memory barrier for weak memory order CPUs - FUNCTABLE_BARRIER(); - - return Z_OK; -} - -#if !defined(_WIN32) && (defined(__GNUC__) || defined(__clang__)) -static void __attribute__((constructor)) functable_constructor(void) { - FUNCTABLE_INIT_ABORT; -} -#endif - -/* stub functions */ -static int force_init_stub(void) { - return init_functable(); -} - -static uint32_t adler32_stub(uint32_t adler, const uint8_t* buf, size_t len) { - FUNCTABLE_INIT_ABORT; - return functable.adler32(adler, buf, len); -} - -static uint32_t adler32_copy_stub(uint32_t adler, uint8_t* dst, const uint8_t* src, size_t len) { - FUNCTABLE_INIT_ABORT; - return functable.adler32_copy(adler, dst, src, len); -} - -static uint8_t* chunkmemset_safe_stub(uint8_t* out, uint8_t *from, size_t len, size_t left) { - FUNCTABLE_INIT_ABORT; - return functable.chunkmemset_safe(out, from, len, left); -} - -static uint32_t compare256_stub(const uint8_t* src0, const uint8_t* src1) { - FUNCTABLE_INIT_ABORT; - return functable.compare256(src0, src1); -} - -static uint32_t crc32_stub(uint32_t crc, const uint8_t* buf, size_t len) { - FUNCTABLE_INIT_ABORT; - return functable.crc32(crc, buf, len); -} - -static uint32_t crc32_copy_stub(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) { - FUNCTABLE_INIT_ABORT; - return functable.crc32_copy(crc, dst, src, len); -} - -static void inflate_fast_stub(PREFIX3(stream) *strm, uint32_t start) { - FUNCTABLE_INIT_ABORT; - functable.inflate_fast(strm, start); -} - -static uint32_t longest_match_stub(deflate_state* const s, uint32_t cur_match) { - FUNCTABLE_INIT_ABORT; - return functable.longest_match(s, cur_match); -} - -static uint32_t longest_match_roll_stub(deflate_state* const s, uint32_t cur_match) { - FUNCTABLE_INIT_ABORT; - return functable.longest_match_roll(s, cur_match); -} - -static void slide_hash_stub(deflate_state* s) { - FUNCTABLE_INIT_ABORT; - functable.slide_hash(s); -} - -/* functable init */ -Z_INTERNAL struct functable_s functable = { - force_init_stub, - adler32_stub, - adler32_copy_stub, - chunkmemset_safe_stub, - compare256_stub, - crc32_stub, - crc32_copy_stub, - inflate_fast_stub, - longest_match_stub, - longest_match_roll_stub, - slide_hash_stub, -}; - -#endif diff --git a/modules/zlib/src/functable.h b/modules/zlib/src/functable.h deleted file mode 100644 index 2a0bb88e0e..0000000000 --- a/modules/zlib/src/functable.h +++ /dev/null @@ -1,50 +0,0 @@ -/* functable.h -- Struct containing function pointers to optimized functions - * Copyright (C) 2017 Hans Kristian Rosbach - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef FUNCTABLE_H_ -#define FUNCTABLE_H_ - -#include "deflate.h" - -#ifdef DISABLE_RUNTIME_CPU_DETECTION - -# include "arch_functions.h" - -/* When compiling with native instructions it is not necessary to use functable. - * Instead we use native_ macro indicating the best available variant of arch-specific - * functions for the current platform. - */ -# define FUNCTABLE_INIT ((void)0) -# define FUNCTABLE_CALL(name) native_ ## name -# define FUNCTABLE_FPTR(name) &native_ ## name - -#else - -struct functable_s { - int (* force_init) (void); - uint32_t (* adler32) (uint32_t adler, const uint8_t *buf, size_t len); - uint32_t (* adler32_copy) (uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len); - uint8_t* (* chunkmemset_safe) (uint8_t *out, uint8_t *from, size_t len, size_t left); - uint32_t (* compare256) (const uint8_t *src0, const uint8_t *src1); - uint32_t (* crc32) (uint32_t crc, const uint8_t *buf, size_t len); - uint32_t (* crc32_copy) (uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len); - void (* inflate_fast) (PREFIX3(stream) *strm, uint32_t start); - uint32_t (* longest_match) (deflate_state *const s, uint32_t cur_match); - uint32_t (* longest_match_roll) (deflate_state *const s, uint32_t cur_match); - void (* slide_hash) (deflate_state *s); -}; - -Z_INTERNAL extern struct functable_s functable; - - -/* Explicitly indicate functions are conditionally dispatched. - */ -# define FUNCTABLE_INIT if (functable.force_init()) {return Z_VERSION_ERROR;} -# define FUNCTABLE_CALL(name) functable.name -# define FUNCTABLE_FPTR(name) functable.name - -#endif - -#endif diff --git a/modules/zlib/src/gzclose.c b/modules/zlib/src/gzclose.c new file mode 100644 index 0000000000..caeb99a317 --- /dev/null +++ b/modules/zlib/src/gzclose.c @@ -0,0 +1,25 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(file) + gzFile file; +{ +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/modules/zlib/src/gzguts.h b/modules/zlib/src/gzguts.h index 67dc280df7..990a4d2514 100644 --- a/modules/zlib/src/gzguts.h +++ b/modules/zlib/src/gzguts.h @@ -1,7 +1,5 @@ -#ifndef GZGUTS_H_ -#define GZGUTS_H_ /* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004-2024 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,36 +7,39 @@ # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif -# undef _FILE_OFFSET_BITS -# undef _TIME_BITS +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif #endif -#if defined(HAVE_VISIBILITY_INTERNAL) -# define Z_INTERNAL __attribute__((visibility ("internal"))) -#elif defined(HAVE_VISIBILITY_HIDDEN) -# define Z_INTERNAL __attribute__((visibility ("hidden"))) +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else -# define Z_INTERNAL +# define ZLIB_INTERNAL #endif #include -#include -#include -#include -#include - -#if defined(ZLIB_COMPAT) -# include "zlib.h" -#else -# include "zlib-ng.h" +#include "zlib.h" +#ifdef STDC +# include +# include +# include #endif +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + #ifdef _WIN32 # include #endif -#if defined(_WIN32) +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) # define WIDECHAR #endif @@ -49,28 +50,98 @@ # define close _close #endif +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -#if !defined(STDC99) && !defined(__CYGWIN__) && !defined(__MINGW__) && defined(_WIN32) -# if !defined(vsnprintf) -# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) -# define vsnprintf _vsnprintf +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif # endif # endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif #endif /* unlike snprintf (which is required in C99), _snprintf does not guarantee - null termination of the result -- however this is only used in gzlib.c - where the result is assured to fit in the space provided */ + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ #if defined(_MSC_VER) && _MSC_VER < 1900 # define snprintf _snprintf #endif +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + /* get errno and strerror definition */ -#ifndef NO_STRERROR -# include -# define zstrerror() strerror(errno) +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else -# define zstrerror() "stdio error (consult errno)" +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); #endif /* default memLevel */ @@ -82,9 +153,7 @@ /* default i/o buffer size -- double this for output when reading (this and twice this must be able to fit in an unsigned type) */ -#ifndef GZBUFSIZE -# define GZBUFSIZE 131072 -#endif +#define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 @@ -112,7 +181,6 @@ typedef struct { unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer (double-sized when writing) */ unsigned char *out; /* output buffer (double-sized when reading) */ - unsigned char *buffers; /* Pointer to the real input/output buffer allocation */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ int how; /* 0: get header, 1: copy, 2: decompress */ @@ -122,7 +190,6 @@ typedef struct { /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ - int reset; /* true if a reset is pending after a Z_FINISH */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ @@ -130,22 +197,22 @@ typedef struct { int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ - PREFIX3(stream) strm; /* stream structure in-place (not a pointer) */ + z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; -typedef gz_state *gz_statep; +typedef gz_state FAR *gz_statep; /* shared functions */ -void Z_INTERNAL PREFIX(gz_error)(gz_state *, int, const char *); -int Z_INTERNAL gz_buffer_alloc(gz_state *state); -void Z_INTERNAL gz_buffer_free(gz_state *state); -void Z_INTERNAL gz_state_free(gz_state *state); - -#ifdef ZLIB_COMPAT -unsigned Z_INTERNAL gz_intmax(void); +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #endif + /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ -#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) - -#endif /* GZGUTS_H_ */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/modules/zlib/src/gzlib.c b/modules/zlib/src/gzlib.c index 05f46d9610..4105e6aff9 100644 --- a/modules/zlib/src/gzlib.c +++ b/modules/zlib/src/gzlib.c @@ -1,14 +1,11 @@ /* gzlib.c -- zlib functions common to reading and writing gzip files - * Copyright (C) 2004-2024 Mark Adler + * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" -#include "zutil.h" -#include "zutil_p.h" #include "gzguts.h" -#if defined(_WIN32) +#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__) # define LSEEK _lseeki64 #else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 @@ -19,96 +16,85 @@ #endif /* Local functions */ -static gzFile gz_state_init(void); -static void gz_reset(gz_state *); -static gzFile gz_open(const void *, int, const char *); +local void gz_reset OF((gz_statep)); +local gzFile gz_open OF((const void *, int, const char *)); -/* Initialize struct for gzFile state */ -static gzFile gz_state_init(void) { - /* allocate gzFile structure to return */ - gz_state *state = (gz_state *)zng_alloc(sizeof(gz_state)); - if (state == NULL) - return NULL; +#if defined UNDER_CE - state->strm.zalloc = NULL; - state->strm.zfree = NULL; - state->strm.opaque = NULL; - state->strm.next_in = NULL; +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. - state->size = 0; - state->want = GZBUFSIZE; - state->in = NULL; - state->out = NULL; - state->direct = 0; - state->mode = GZ_NONE; - state->level = Z_DEFAULT_COMPRESSION; - state->strategy = Z_DEFAULT_STRATEGY; - state->msg = NULL; - return (gzFile)state; + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; } -void Z_INTERNAL gz_state_free(gz_state *state) { - zng_free(state); -} +#endif /* UNDER_CE */ /* Reset gzip file state */ -static void gz_reset(gz_state *state) { +local void gz_reset(state) + gz_statep state; +{ state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ } - else /* for writing ... */ - state->reset = 0; /* no deflateReset pending */ state->seek = 0; /* no seek request pending */ - PREFIX(gz_error)(state, Z_OK, NULL); /* clear error */ + gz_error(state, Z_OK, NULL); /* clear error */ state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } -/* Allocate in/out buffers for gzFile */ -int Z_INTERNAL gz_buffer_alloc(gz_state *state) { - int want = state->want; - int in_size = want, out_size = want; - - if (state->mode == GZ_WRITE) { - in_size = want * 2; // double input buffer for compression (ref: gzprintf) - if (state->direct) - out_size = 0; // output buffer not needed in write + direct mode - } else if (state->mode == GZ_READ) { - out_size = want * 2; // double output buffer for decompression - } - - state->buffers = (unsigned char *)zng_alloc_aligned((in_size + out_size), 64); - state->in = state->buffers; - if (out_size) { - state->out = state->buffers + (in_size); // Outbuffer goes after inbuffer - } - - /* Return error if memory allocation failed */ - if (state->in == NULL || (out_size && state->out == NULL)) { - gz_buffer_free(state); - PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); - return -1; - } - - state->size = want; // mark state as initialized - return 0; -} - -void Z_INTERNAL gz_buffer_free(gz_state *state) { - zng_free_aligned(state->buffers); - state->buffers = NULL; - state->out = NULL; - state->in = NULL; - state->size = 0; -} - /* Open a gzip file either by name or file descriptor. */ -static gzFile gz_open(const void *path, int fd, const char *mode) { - gz_state *state; - size_t len; +local gzFile gz_open(path, fd, mode) + const void *path; + int fd; + const char *mode; +{ + gz_statep state; + z_size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; @@ -121,16 +107,23 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { if (path == NULL) return NULL; - /* Initialize gzFile state */ - state = (gz_state *)gz_state_init(); + /* allocate gzFile structure to return */ + state = (gz_statep)malloc(sizeof(gz_state)); if (state == NULL) return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; while (*mode) { - if (*mode >= '0' && *mode <= '9') { + if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; - } else { + else switch (*mode) { case 'r': state->mode = GZ_READ; @@ -144,7 +137,7 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { break; #endif case '+': /* can't read and write at the same time */ - gz_state_free(state); + free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; @@ -174,22 +167,21 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { state->direct = 1; break; default: /* could consider as an error, but just ignore */ - {} + ; } - } mode++; } /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { - gz_state_free(state); + free(state); return NULL; } /* can't force transparent read */ if (state->mode == GZ_READ) { if (state->direct) { - gz_state_free(state); + free(state); return NULL; } state->direct = 1; /* for empty file */ @@ -198,27 +190,31 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { /* save the path name for error messages */ #ifdef WIDECHAR if (fd == -2) { - len = wcstombs(NULL, (const wchar_t *)path, 0); - if (len == (size_t)-1) + len = wcstombs(NULL, path, 0); + if (len == (z_size_t)-1) len = 0; - } else + } + else #endif len = strlen((const char *)path); - state->path = malloc(len + 1); + state->path = (char *)malloc(len + 1); if (state->path == NULL) { - gz_state_free(state); + free(state); return NULL; } #ifdef WIDECHAR if (fd == -2) - if (len) { - wcstombs(state->path, (const wchar_t *)path, len + 1); - } else { + if (len) + wcstombs(state->path, path, len + 1); + else *(state->path) = 0; - } else #endif +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(state->path, len + 1, "%s", (const char *)path); +#else + strcpy(state->path, path); +#endif /* compute the flags for open() */ oflag = @@ -243,15 +239,13 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( -#if defined(_WIN32) - fd == -2 ? _wopen((const wchar_t *)path, oflag, 0666) : -#elif __CYGWIN__ - fd == -2 ? open(state->path, oflag, 0666) : +#ifdef WIDECHAR + fd == -2 ? _wopen(path, oflag, 0666) : #endif open((const char *)path, oflag, 0666)); if (state->fd == -1) { free(state->path); - gz_state_free(state); + free(state); return NULL; } if (state->mode == GZ_APPEND) { @@ -273,57 +267,62 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { } /* -- see zlib.h -- */ -gzFile Z_EXPORT PREFIX(gzopen)(const char *path, const char *mode) { +gzFile ZEXPORT gzopen(path, mode) + const char *path; + const char *mode; +{ return gz_open(path, -1, mode); } -#ifdef ZLIB_COMPAT -gzFile Z_EXPORT PREFIX4(gzopen)(const char *path, const char *mode) { - return gz_open(path, -1, mode); -} -#endif - /* -- see zlib.h -- */ -gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) { - gzFile gz; - char path[32]; /* identifier for error messages */ +gzFile ZEXPORT gzopen64(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} - if (fd == -1) +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(fd, mode) + int fd; + const char *mode; +{ + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; - (void)snprintf(path, 32, "", fd); /* for debugging */ +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); +#else + sprintf(path, "", fd); /* for debugging */ +#endif gz = gz_open(path, fd, mode); + free(path); return gz; } /* -- see zlib.h -- */ #ifdef WIDECHAR -gzFile Z_EXPORT PREFIX(gzopen_w)(const wchar_t *path, const char *mode) { +gzFile ZEXPORT gzopen_w(path, mode) + const wchar_t *path; + const char *mode; +{ return gz_open(path, -2, mode); } #endif -z_int32_t Z_EXPORT PREFIX(gzclose)(gzFile file) { -#ifndef NO_GZCOMPRESS - gz_state *state; - - if (file == NULL) - return Z_STREAM_ERROR; - state = (gz_state *)file; - - return state->mode == GZ_READ ? PREFIX(gzclose_r)(file) : PREFIX(gzclose_w)(file); -#else - return PREFIX(gzclose_r)(file); -#endif -} - /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzbuffer)(gzFile file, z_uint32_t size) { - gz_state *state; +int ZEXPORT gzbuffer(file, size) + gzFile file; + unsigned size; +{ + gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; @@ -334,23 +333,26 @@ z_int32_t Z_EXPORT PREFIX(gzbuffer)(gzFile file, z_uint32_t size) { /* check and set requested size */ if ((size << 1) < size) return -1; /* need to be able to double it */ - if (size < 8) - size = 8; /* needed to behave well with flushing */ + if (size < 2) + size = 2; /* need two bytes to check magic header */ state->want = size; return 0; } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzrewind)(gzFile file) { - gz_state *state; +int ZEXPORT gzrewind(file) + gzFile file; +{ + gz_statep state; /* get internal structure */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're reading and that there's no error */ - if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ @@ -361,15 +363,19 @@ z_int32_t Z_EXPORT PREFIX(gzrewind)(gzFile file) { } /* -- see zlib.h -- */ -z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) { +z_off64_t ZEXPORT gzseek64(file, offset, whence) + gzFile file; + z_off64_t offset; + int whence; +{ unsigned n; z_off64_t ret; - gz_state *state; + gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; @@ -389,15 +395,16 @@ z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) { state->seek = 0; /* if within raw area while reading, just go there */ - if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { - ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); + if (state->mode == GZ_READ && state->how == COPY && + state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; state->eof = 0; state->past = 0; state->seek = 0; - PREFIX(gz_error)(state, Z_OK, NULL); + gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; state->x.pos += offset; return state->x.pos; @@ -410,13 +417,14 @@ z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) { offset += state->x.pos; if (offset < 0) /* before start of file! */ return -1; - if (PREFIX(gzrewind)(file) == -1) /* rewind, then skip to offset */ + if (gzrewind(file) == -1) /* rewind, then skip to offset */ return -1; } /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { - n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; @@ -432,23 +440,27 @@ z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) { } /* -- see zlib.h -- */ -#ifdef ZLIB_COMPAT -z_off_t Z_EXPORT PREFIX(gzseek)(gzFile file, z_off_t offset, int whence) { +z_off_t ZEXPORT gzseek(file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ z_off64_t ret; - ret = PREFIX4(gzseek)(file, (z_off64_t)offset, whence); + ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } -#endif /* -- see zlib.h -- */ -z_off64_t Z_EXPORT PREFIX4(gztell)(gzFile file) { - gz_state *state; +z_off64_t ZEXPORT gztell64(file) + gzFile file; +{ + gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; @@ -457,25 +469,26 @@ z_off64_t Z_EXPORT PREFIX4(gztell)(gzFile file) { } /* -- see zlib.h -- */ -#ifdef ZLIB_COMPAT -z_off_t Z_EXPORT PREFIX(gztell)(gzFile file) { - +z_off_t ZEXPORT gztell(file) + gzFile file; +{ z_off64_t ret; - ret = PREFIX4(gztell)(file); + ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } -#endif /* -- see zlib.h -- */ -z_off64_t Z_EXPORT PREFIX4(gzoffset)(gzFile file) { +z_off64_t ZEXPORT gzoffset64(file) + gzFile file; +{ z_off64_t offset; - gz_state *state; + gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; @@ -489,23 +502,25 @@ z_off64_t Z_EXPORT PREFIX4(gzoffset)(gzFile file) { } /* -- see zlib.h -- */ -#ifdef ZLIB_COMPAT -z_off_t Z_EXPORT PREFIX(gzoffset)(gzFile file) { +z_off_t ZEXPORT gzoffset(file) + gzFile file; +{ z_off64_t ret; - ret = PREFIX4(gzoffset)(file); + ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } -#endif /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzeof)(gzFile file) { - gz_state *state; +int ZEXPORT gzeof(file) + gzFile file; +{ + gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; - state = (gz_state *)file; + state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; @@ -514,30 +529,36 @@ z_int32_t Z_EXPORT PREFIX(gzeof)(gzFile file) { } /* -- see zlib.h -- */ -const char * Z_EXPORT PREFIX(gzerror)(gzFile file, z_int32_t *errnum) { - gz_state *state; +const char * ZEXPORT gzerror(file, errnum) + gzFile file; + int *errnum; +{ + gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; - state = (gz_state *)file; + state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; - return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); + return state->err == Z_MEM_ERROR ? "out of memory" : + (state->msg == NULL ? "" : state->msg); } /* -- see zlib.h -- */ -void Z_EXPORT PREFIX(gzclearerr)(gzFile file) { - gz_state *state; +void ZEXPORT gzclearerr(file) + gzFile file; +{ + gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; - state = (gz_state *)file; + state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return; @@ -546,7 +567,7 @@ void Z_EXPORT PREFIX(gzclearerr)(gzFile file) { state->eof = 0; state->past = 0; } - PREFIX(gz_error)(state, Z_OK, NULL); + gz_error(state, Z_OK, NULL); } /* Create an error message in allocated memory and set state->err and @@ -555,7 +576,11 @@ void Z_EXPORT PREFIX(gzclearerr)(gzFile file) { memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ -void Z_INTERNAL PREFIX(gz_error)(gz_state *state, int err, const char *msg) { +void ZLIB_INTERNAL gz_error(state, err, msg) + gz_statep state; + int err; + const char *msg; +{ /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) @@ -577,15 +602,36 @@ void Z_INTERNAL PREFIX(gz_error)(gz_state *state, int err, const char *msg) { return; /* construct error message with path */ - if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == + NULL) { state->err = Z_MEM_ERROR; return; } - (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); +#else + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); +#endif } -#ifdef ZLIB_COMPAT -unsigned Z_INTERNAL gz_intmax(void) { - return INT_MAX; +#ifndef INT_MAX +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax() +{ + unsigned p, q; + + p = 1; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; } #endif diff --git a/modules/zlib/src/gzread.c b/modules/zlib/src/gzread.c index 10ed519f2c..832d3ef98c 100644 --- a/modules/zlib/src/gzread.c +++ b/modules/zlib/src/gzread.c @@ -1,60 +1,44 @@ /* gzread.c -- zlib functions for reading gzip files - * Copyright (C) 2004-2017 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" -#include "zutil_p.h" #include "gzguts.h" -#include "gzread_mangle.h" /* Local functions */ -static int gz_read_init(gz_state *state); -static int gz_load(gz_state *, unsigned char *, unsigned, unsigned *); -static int gz_avail(gz_state *); -static int gz_look(gz_state *); -static int gz_decomp(gz_state *); -static int gz_fetch(gz_state *); -static int gz_skip(gz_state *, z_off64_t); -static size_t gz_read(gz_state *, void *, size_t); - -static int gz_read_init(gz_state *state) { - /* Allocate gz buffers */ - if (gz_buffer_alloc(state) != 0) { - PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); - return -1; - } - - /* Initialize inflate state */ - int ret = PREFIX(inflateInit2)(&(state->strm), MAX_WBITS + 16); - if (ret != Z_OK) { - gz_buffer_free(state); - if (ret == Z_MEM_ERROR) { - PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); - } else { - PREFIX(gz_error)(state, Z_STREAM_ERROR, "invalid compression parameters"); - } - return -1; - } - return 0; -} +local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); +local int gz_avail OF((gz_statep)); +local int gz_look OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_fetch OF((gz_statep)); +local int gz_skip OF((gz_statep, z_off64_t)); +local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ -static int gz_load(gz_state *state, unsigned char *buf, unsigned len, unsigned *have) { - ssize_t ret; +local int gz_load(state, buf, len, have) + gz_statep state; + unsigned char *buf; + unsigned len; + unsigned *have; +{ + int ret; + unsigned get, max = ((unsigned)-1 >> 2) + 1; *have = 0; do { - ret = read(state->fd, buf + *have, len - *have); + get = len - *have; + if (get > max) + get = max; + ret = read(state->fd, buf + *have, get); if (ret <= 0) break; *have += (unsigned)ret; } while (*have < len); if (ret < 0) { - PREFIX(gz_error)(state, Z_ERRNO, zstrerror()); + gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (ret == 0) @@ -69,9 +53,11 @@ static int gz_load(gz_state *state, unsigned char *buf, unsigned len, unsigned * If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ -static int gz_avail(gz_state *state) { +local int gz_avail(state) + gz_statep state; +{ unsigned got; - PREFIX3(stream) *strm = &(state->strm); + z_streamp strm = &(state->strm); if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; @@ -84,7 +70,8 @@ static int gz_avail(gz_state *state) { *p++ = *q++; } while (--n); } - if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1) + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) return -1; strm->avail_in += got; strm->next_in = state->in; @@ -101,12 +88,38 @@ static int gz_avail(gz_state *state) { case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ -static int gz_look(gz_state *state) { - PREFIX3(stream) *strm = &(state->strm); +local int gz_look(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); - /* allocate memory if this is the first time through */ - if (state->size == 0 && gz_read_init(state) == -1) - return -1; + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = (unsigned char *)malloc(state->want); + state->out = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } /* get at least the magic bytes in the input buffer */ if (strm->avail_in < 2) { @@ -125,7 +138,7 @@ static int gz_look(gz_state *state) { single byte is sufficient indication that it is not a gzip file) */ if (strm->avail_in > 1 && strm->next_in[0] == 31 && strm->next_in[1] == 139) { - PREFIX(inflateReset)(strm); + inflateReset(strm); state->how = GZIP; state->direct = 0; return 0; @@ -144,9 +157,11 @@ static int gz_look(gz_state *state) { the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; - memcpy(state->x.next, strm->next_in, strm->avail_in); - state->x.have = strm->avail_in; - strm->avail_in = 0; + if (strm->avail_in) { + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; + } state->how = COPY; state->direct = 1; return 0; @@ -157,10 +172,12 @@ static int gz_look(gz_state *state) { data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ -static int gz_decomp(gz_state *state) { +local int gz_decomp(state) + gz_statep state; +{ int ret = Z_OK; unsigned had; - PREFIX3(stream) *strm = &(state->strm); + z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; @@ -169,22 +186,24 @@ static int gz_decomp(gz_state *state) { if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { - PREFIX(gz_error)(state, Z_BUF_ERROR, "unexpected end of file"); + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); break; } /* decompress and handle errors */ - ret = PREFIX(inflate)(strm, Z_NO_FLUSH); + ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { - PREFIX(gz_error)(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { - PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); + gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ - PREFIX(gz_error)(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); @@ -207,12 +226,13 @@ static int gz_decomp(gz_state *state) { looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ -static int gz_fetch(gz_state *state) { - PREFIX3(stream) *strm = &(state->strm); - Assert(state->x.have == 0, "Invalid state->x.have"); +local int gz_fetch(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); do { - switch (state->how) { + switch(state->how) { case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ if (gz_look(state) == -1) return -1; @@ -230,19 +250,16 @@ static int gz_fetch(gz_state *state) { strm->next_out = state->out; if (gz_decomp(state) == -1) return -1; - continue; - default: // Can't happen - Z_UNREACHABLE(); -#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L - return -1; -#endif } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ -static int gz_skip(gz_state *state, z_off64_t len) { +local int gz_skip(state, len) + gz_statep state; + z_off64_t len; +{ unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ @@ -255,11 +272,14 @@ static int gz_skip(gz_state *state, z_off64_t len) { state->x.next += n; state->x.pos += n; len -= n; - } else if (state->eof && state->strm.avail_in == 0) { - /* output buffer empty -- return if we're at the end of the input */ + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) break; - } else { - /* need more data to skip -- load up output buffer */ + + /* need more data to skip -- load up output buffer */ + else { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; @@ -271,8 +291,12 @@ static int gz_skip(gz_state *state, z_off64_t len) { input. Return the number of bytes read. If zero is returned, either the end of file was reached, or there was an error. state->err must be consulted in that case to determine which. */ -static size_t gz_read(gz_state *state, void *buf, size_t len) { - size_t got; +local z_size_t gz_read(state, buf, len) + gz_statep state; + voidp buf; + z_size_t len; +{ + z_size_t got; unsigned n; /* if len is zero, avoid unnecessary operations */ @@ -290,9 +314,9 @@ static size_t gz_read(gz_state *state, void *buf, size_t len) { got = 0; do { /* set n to the maximum amount of len that fits in an unsigned int */ - n = (unsigned)-1; + n = -1; if (n > len) - n = (unsigned)len; + n = len; /* first just try copying data from the output buffer */ if (state->x.have) { @@ -348,13 +372,17 @@ static size_t gz_read(gz_state *state, void *buf, size_t len) { } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzread)(gzFile file, void *buf, z_uint32_t len) { - gz_state *state; +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_statep state; /* get internal structure */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || @@ -363,35 +391,36 @@ z_int32_t Z_EXPORT PREFIX(gzread)(gzFile file, void *buf, z_uint32_t len) { /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ - if ((z_int32_t)len < 0) { - PREFIX(gz_error)(state, Z_STREAM_ERROR, "request does not fit in an int"); + if ((int)len < 0) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); return -1; } /* read len or fewer bytes to buf */ - len = (unsigned)gz_read(state, buf, len); + len = gz_read(state, buf, len); /* check for an error */ if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* return the number of bytes read (this is assured to fit in an int) */ - return (z_int32_t)len; + return (int)len; } /* -- see zlib.h -- */ -size_t Z_EXPORT PREFIX(gzfread)(void *buf, size_t size, size_t nitems, gzFile file) { - size_t len; - gz_state *state; - - /* Exit early if size is zero, also prevents potential division by zero */ - if (size == 0) - return 0; +z_size_t ZEXPORT gzfread(buf, size, nitems, file) + voidp buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; /* get internal structure */ if (file == NULL) return 0; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || @@ -399,28 +428,41 @@ size_t Z_EXPORT PREFIX(gzfread)(void *buf, size_t size, size_t nitems, gzFile fi return 0; /* compute bytes to read -- error on overflow */ - if (size && SIZE_MAX / size < nitems) { - PREFIX(gz_error)(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); return 0; } - len = nitems * size; /* read len or fewer bytes to buf, return the number of full items read */ return len ? gz_read(state, buf, len) / size : 0; } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzgetc)(gzFile file) { +#ifdef Z_PREFIX_SET +# undef z_gzgetc +#else +# undef gzgetc +# ifdef Z_CR_PREFIX_SET +# define gzgetc Cr_z_gzgetc +# endif +#endif + +int ZEXPORT gzgetc(file) + gzFile file; +{ + int ret; unsigned char buf[1]; - gz_state *state; + gz_statep state; /* get internal structure */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ - if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* try output buffer (no need to check for skip request) */ @@ -431,30 +473,31 @@ z_int32_t Z_EXPORT PREFIX(gzgetc)(gzFile file) { } /* nothing there -- try gz_read() */ - return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; + ret = gz_read(state, buf, 1); + return ret < 1 ? -1 : buf[0]; } -#ifdef ZLIB_COMPAT -int Z_EXPORT PREFIX(gzgetc_)(gzFile file) { - return PREFIX(gzgetc)(file); +int ZEXPORT gzgetc_(file) +gzFile file; +{ + return gzgetc(file); } -#endif /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzungetc)(z_int32_t c, gzFile file) { - gz_state *state; +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_statep state; /* get internal structure */ if (file == NULL) return -1; - state = (gz_state *)file; - - /* in case this was just opened, set up the input buffer */ - if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) - (void)gz_look(state); + state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ - if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ @@ -480,7 +523,7 @@ z_int32_t Z_EXPORT PREFIX(gzungetc)(z_int32_t c, gzFile file) { /* if no room, give up (must have already done a gzungetc()) */ if (state->x.have == (state->size << 1)) { - PREFIX(gz_error)(state, Z_DATA_ERROR, "out of room to push characters"); + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); return -1; } @@ -501,19 +544,24 @@ z_int32_t Z_EXPORT PREFIX(gzungetc)(z_int32_t c, gzFile file) { } /* -- see zlib.h -- */ -char * Z_EXPORT PREFIX(gzgets)(gzFile file, char *buf, z_int32_t len) { +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ unsigned left, n; char *str; unsigned char *eol; - gz_state *state; + gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) return NULL; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ - if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return NULL; /* process a skip request */ @@ -528,31 +576,29 @@ char * Z_EXPORT PREFIX(gzgets)(gzFile file, char *buf, z_int32_t len) { the contents, let the user worry about that) */ str = buf; left = (unsigned)len - 1; - if (left) { - do { - /* assure that something is in the output buffer */ - if (state->x.have == 0 && gz_fetch(state) == -1) - return NULL; /* error */ - if (state->x.have == 0) { /* end of file */ - state->past = 1; /* read past end */ - break; /* return what we have */ - } + if (left) do { + /* assure that something is in the output buffer */ + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } - /* look for end-of-line in current output buffer */ - n = MIN(state->x.have, left); - eol = (unsigned char *)memchr(state->x.next, '\n', n); - if (eol != NULL) - n = (unsigned)(eol - state->x.next) + 1; + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; - /* copy through end-of-line, or remainder if not found */ - memcpy(buf, state->x.next, n); - state->x.have -= n; - state->x.next += n; - state->x.pos += n; - left -= n; - buf += n; - } while (left && eol == NULL); - } + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); /* return terminated string, or if nothing, end of file */ if (buf == str) @@ -562,14 +608,15 @@ char * Z_EXPORT PREFIX(gzgets)(gzFile file, char *buf, z_int32_t len) { } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzdirect)(gzFile file) { - gz_state *state; +int ZEXPORT gzdirect(file) + gzFile file; +{ + gz_statep state; /* get internal structure */ if (file == NULL) return 0; - - state = (gz_state *)file; + state = (gz_statep)file; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ @@ -581,15 +628,16 @@ z_int32_t Z_EXPORT PREFIX(gzdirect)(gzFile file) { } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzclose_r)(gzFile file) { +int ZEXPORT gzclose_r(file) + gzFile file; +{ int ret, err; - gz_state *state; + gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; - - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) @@ -597,13 +645,14 @@ z_int32_t Z_EXPORT PREFIX(gzclose_r)(gzFile file) { /* free memory and close file */ if (state->size) { - PREFIX(inflateEnd)(&(state->strm)); - gz_buffer_free(state); + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); } err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; - PREFIX(gz_error)(state, Z_OK, NULL); + gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); - zng_free(state); + free(state); return ret ? Z_ERRNO : err; } diff --git a/modules/zlib/src/gzread_mangle.h b/modules/zlib/src/gzread_mangle.h deleted file mode 100644 index b9dc158bd3..0000000000 --- a/modules/zlib/src/gzread_mangle.h +++ /dev/null @@ -1,7 +0,0 @@ -/* gzread_mangle.h.in -- gzgetc name mangling helper - * This file undefines the macro from zlib.h/zlib-ng.h to allow the real - * function to be defined in gzread.c. This is tricky because the prefix - * is not known ahead of time, thus the need for sed or similar. - */ -#undef gzgetc -#undef zng_gzgetc diff --git a/modules/zlib/src/gzwrite.c b/modules/zlib/src/gzwrite.c index 5d1fdd7776..c7b5651d70 100644 --- a/modules/zlib/src/gzwrite.c +++ b/modules/zlib/src/gzwrite.c @@ -1,47 +1,62 @@ /* gzwrite.c -- zlib functions for writing gzip files - * Copyright (C) 2004-2019 Mark Adler + * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" -#include "zutil_p.h" -#include #include "gzguts.h" /* Local functions */ -static int gz_write_init(gz_state *); -static int gz_comp(gz_state *, int); -static int gz_zero(gz_state *, z_off64_t); -static size_t gz_write(gz_state *, void const *, size_t); +local int gz_init OF((gz_statep)); +local int gz_comp OF((gz_statep, int)); +local int gz_zero OF((gz_statep, z_off64_t)); +local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on a memory allocation failure, or 0 on success. */ -static int gz_write_init(gz_state *state) { - PREFIX3(stream) *strm = &(state->strm); +local int gz_init(state) + gz_statep state; +{ + int ret; + z_streamp strm = &(state->strm); - /* Allocate gz buffers */ - if (gz_buffer_alloc(state) != 0) { - PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); + /* allocate input buffer (double size for gzprintf) */ + state->in = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } - /* only need deflate state if compressing */ + /* only need output buffer and deflate state if compressing */ if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)malloc(state->want); + if (state->out == NULL) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + /* allocate deflate memory, set up for gzip compression */ - int ret = PREFIX(deflateInit2)(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); if (ret != Z_OK) { - gz_buffer_free(state); - if (ret == Z_MEM_ERROR) { - PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); - } else { - PREFIX(gz_error)(state, Z_STREAM_ERROR, "invalid compression parameters"); - } + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } strm->next_in = NULL; + } - /* initialize write buffer */ + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer if compressing */ + if (!state->direct) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = strm->next_out; @@ -50,65 +65,68 @@ static int gz_write_init(gz_state *state) { } /* Compress whatever is at avail_in and next_in and write to the output file. - Return -1 if there is an error writing to the output file or if gz_write_init() + Return -1 if there is an error writing to the output file or if gz_init() fails to allocate memory, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ -static int gz_comp(gz_state *state, int flush) { - int ret; - ssize_t got; - unsigned have; - PREFIX3(stream) *strm = &(state->strm); +local int gz_comp(state, flush) + gz_statep state; + int flush; +{ + int ret, writ; + unsigned have, put, max = ((unsigned)-1 >> 2) + 1; + z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ - if (state->size == 0 && gz_write_init(state) == -1) + if (state->size == 0 && gz_init(state) == -1) return -1; /* write directly if requested */ if (state->direct) { - got = write(state->fd, strm->next_in, strm->avail_in); - if (got < 0 || (unsigned)got != strm->avail_in) { - PREFIX(gz_error)(state, Z_ERRNO, zstrerror()); - return -1; + while (strm->avail_in) { + put = strm->avail_in > max ? max : strm->avail_in; + writ = write(state->fd, strm->next_in, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in -= (unsigned)writ; + strm->next_in += writ; } - strm->avail_in = 0; return 0; } - /* check for a pending reset */ - if (state->reset) { - /* don't start a new gzip member unless there is data to write */ - if (strm->avail_in == 0) - return 0; - PREFIX(deflateReset)(strm); - state->reset = 0; - } - /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ - if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { - have = (unsigned)(strm->next_out - state->x.next); - if (have && ((got = write(state->fd, state->x.next, (unsigned long)have)) < 0 || (unsigned)got != have)) { - PREFIX(gz_error)(state, Z_ERRNO, zstrerror()); - return -1; + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + while (strm->next_out > state->x.next) { + put = strm->next_out - state->x.next > (int)max ? max : + (unsigned)(strm->next_out - state->x.next); + writ = write(state->fd, state->x.next, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + state->x.next += writ; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = state->out; } - state->x.next = strm->next_out; } /* compress */ have = strm->avail_out; - ret = PREFIX(deflate)(strm, flush); + ret = deflate(strm, flush); if (ret == Z_STREAM_ERROR) { - PREFIX(gz_error)(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); return -1; } have -= strm->avail_out; @@ -116,17 +134,21 @@ static int gz_comp(gz_state *state, int flush) { /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) - state->reset = 1; + deflateReset(strm); + /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on a write error or memory allocation failure by gz_comp(), or 0 on success. */ -static int gz_zero(gz_state *state, z_off64_t len) { +local int gz_zero(state, len) + gz_statep state; + z_off64_t len; +{ int first; unsigned n; - PREFIX3(stream) *strm = &(state->strm); + z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) @@ -135,7 +157,8 @@ static int gz_zero(gz_state *state, z_off64_t len) { /* compress len zeros (len guaranteed > 0) */ first = 1; while (len) { - n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; if (first) { memset(state->in, 0, n); first = 0; @@ -152,15 +175,19 @@ static int gz_zero(gz_state *state, z_off64_t len) { /* Write len bytes from buf to file. Return the number of bytes written. If the returned value is less than len, then there was an error. */ -static size_t gz_write(gz_state *state, void const *buf, size_t len) { - size_t put = len; +local z_size_t gz_write(state, buf, len) + gz_statep state; + voidpc buf; + z_size_t len; +{ + z_size_t put = len; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ - if (state->size == 0 && gz_write_init(state) == -1) + if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ @@ -182,7 +209,7 @@ static size_t gz_write(gz_state *state, void const *buf, size_t len) { state->in); copy = state->size - have; if (copy > len) - copy = (unsigned)len; + copy = len; memcpy(state->in + have, buf, copy); state->strm.avail_in += copy; state->x.pos += copy; @@ -191,17 +218,18 @@ static size_t gz_write(gz_state *state, void const *buf, size_t len) { if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); - } else { + } + else { /* consume whatever's left in the input buffer */ if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ - state->strm.next_in = (z_const unsigned char *) buf; + state->strm.next_in = (z_const Bytef *)buf; do { unsigned n = (unsigned)-1; if (n > len) - n = (unsigned)len; + n = len; state->strm.avail_in = n; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) @@ -215,13 +243,17 @@ static size_t gz_write(gz_state *state, void const *buf, size_t len) { } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzwrite)(gzFile file, void const *buf, z_uint32_t len) { - gz_state *state; +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_statep state; /* get internal structure */ if (file == NULL) return 0; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) @@ -229,28 +261,29 @@ z_int32_t Z_EXPORT PREFIX(gzwrite)(gzFile file, void const *buf, z_uint32_t len) /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ - if ((z_int32_t)len < 0) { - PREFIX(gz_error)(state, Z_DATA_ERROR, "requested length does not fit in int"); + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } /* write len bytes from buf (the return value will fit in an int) */ - return (z_int32_t)gz_write(state, buf, len); + return (int)gz_write(state, buf, len); } /* -- see zlib.h -- */ -size_t Z_EXPORT PREFIX(gzfwrite)(void const *buf, size_t size, size_t nitems, gzFile file) { - size_t len; - gz_state *state; - - /* Exit early if size is zero, also prevents potential division by zero */ - if (size == 0) - return 0; +z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) + voidpc buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; /* get internal structure */ if (file == NULL) return 0; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) @@ -258,8 +291,8 @@ size_t Z_EXPORT PREFIX(gzfwrite)(void const *buf, size_t size, size_t nitems, gz /* compute bytes to read -- error on overflow */ len = nitems * size; - if (len / size != nitems) { - PREFIX(gz_error)(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); return 0; } @@ -268,16 +301,19 @@ size_t Z_EXPORT PREFIX(gzfwrite)(void const *buf, size_t size, size_t nitems, gz } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzputc)(gzFile file, z_int32_t c) { +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ unsigned have; unsigned char buf[1]; - gz_state *state; - PREFIX3(stream) *strm; + gz_statep state; + z_streamp strm; /* get internal structure */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ @@ -313,41 +349,45 @@ z_int32_t Z_EXPORT PREFIX(gzputc)(gzFile file, z_int32_t c) { } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzputs)(gzFile file, const char *s) { - size_t len, put; - gz_state *state; +int ZEXPORT gzputs(file, str) + gzFile file; + const char *str; +{ + int ret; + z_size_t len; + gz_statep state; /* get internal structure */ if (file == NULL) return -1; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* write string */ - len = strlen(s); - if ((int)len < 0 || (unsigned)len != len) { - PREFIX(gz_error)(state, Z_STREAM_ERROR, "string length does not fit in int"); - return -1; - } - put = gz_write(state, s, len); - return put < len ? -1 : (int)len; + len = strlen(str); + ret = gz_write(state, str, len); + return ret == 0 && len != 0 ? -1 : ret; } +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +#include + /* -- see zlib.h -- */ -z_int32_t Z_EXPORTVA PREFIX(gzvprintf)(gzFile file, const char *format, va_list va) { +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) +{ int len; unsigned left; char *next; - gz_state *state; - PREFIX3(stream) *strm; + gz_statep state; + z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; - state = (gz_state *)file; + state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ @@ -355,7 +395,7 @@ z_int32_t Z_EXPORTVA PREFIX(gzvprintf)(gzFile file, const char *format, va_list return Z_STREAM_ERROR; /* make sure we have some buffer space */ - if (state->size == 0 && gz_write_init(state) == -1) + if (state->size == 0 && gz_init(state) == -1) return state->err; /* check for seek request */ @@ -372,7 +412,22 @@ z_int32_t Z_EXPORTVA PREFIX(gzvprintf)(gzFile file, const char *format, va_list strm->next_in = state->in; next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); next[state->size - 1] = 0; +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(next, format, va); + for (len = 0; len < state->size; len++) + if (next[len] == 0) break; +# else + len = vsprintf(next, format, va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(next, state->size, format, va); + len = strlen(next); +# else len = vsnprintf(next, state->size, format, va); +# endif +#endif /* check that printf() results fit in buffer */ if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) @@ -386,31 +441,125 @@ z_int32_t Z_EXPORTVA PREFIX(gzvprintf)(gzFile file, const char *format, va_list strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; - memmove(state->in, state->in + state->size, left); + memcpy(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return len; } -z_int32_t Z_EXPORTVA PREFIX(gzprintf)(gzFile file, const char *format, ...) { +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) +{ va_list va; int ret; va_start(va, format); - ret = PREFIX(gzvprintf)(file, format, va); + ret = gzvprintf(file, format, va); va_end(va); return ret; } +#else /* !STDC && !Z_HAVE_STDARG_H */ + /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzflush)(gzFile file, z_int32_t flush) { - gz_state *state; +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + unsigned len, left; + char *next; + gz_statep state; + z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; - state = (gz_state *)file; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return Z_STREAM_ERROR; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->error; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->error; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(strm->next_in + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (next[len] == 0) + break; +# else + len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(next); +# else + len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memcpy(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return (int)len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(file, flush) + gzFile file; + int flush; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) @@ -433,18 +582,22 @@ z_int32_t Z_EXPORT PREFIX(gzflush)(gzFile file, z_int32_t flush) { } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzsetparams)(gzFile file, z_int32_t level, z_int32_t strategy) { - gz_state *state; - PREFIX3(stream) *strm; +int ZEXPORT gzsetparams(file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_statep state; + z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; - state = (gz_state *)file; + state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ - if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct) + if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ @@ -463,7 +616,7 @@ z_int32_t Z_EXPORT PREFIX(gzsetparams)(gzFile file, z_int32_t level, z_int32_t s /* flush previous input with previous parameters before changing */ if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) return state->err; - PREFIX(deflateParams)(strm, level, strategy); + deflateParams(strm, level, strategy); } state->level = level; state->strategy = strategy; @@ -471,14 +624,16 @@ z_int32_t Z_EXPORT PREFIX(gzsetparams)(gzFile file, z_int32_t level, z_int32_t s } /* -- see zlib.h -- */ -z_int32_t Z_EXPORT PREFIX(gzclose_w)(gzFile file) { +int ZEXPORT gzclose_w(file) + gzFile file; +{ int ret = Z_OK; - gz_state *state; + gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; - state = (gz_state *)file; + state = (gz_statep)file; /* check that we're writing */ if (state->mode != GZ_WRITE) @@ -496,14 +651,15 @@ z_int32_t Z_EXPORT PREFIX(gzclose_w)(gzFile file) { ret = state->err; if (state->size) { if (!state->direct) { - (void)PREFIX(deflateEnd)(&(state->strm)); + (void)deflateEnd(&(state->strm)); + free(state->out); } - gz_buffer_free(state); + free(state->in); } - PREFIX(gz_error)(state, Z_OK, NULL); + gz_error(state, Z_OK, NULL); free(state->path); if (close(state->fd) == -1) ret = Z_ERRNO; - gz_state_free(state); + free(state); return ret; } diff --git a/modules/zlib/src/infback.c b/modules/zlib/src/infback.c index 2dc15458d5..b93ef478e9 100644 --- a/modules/zlib/src/infback.c +++ b/modules/zlib/src/infback.c @@ -1,5 +1,5 @@ /* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2022 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -10,76 +10,148 @@ inflate_fast() can be used with either inflate.c or infback.c. */ -#include "zbuild.h" #include "zutil.h" #include "inftrees.h" #include "inflate.h" -#include "inflate_p.h" -#include "functable.h" +#include "inffast.h" -/* Avoid conflicts with zlib.h macros */ -#ifdef ZLIB_COMPAT -# undef inflateBackInit -#endif +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); /* strm provides memory allocation functions in zalloc and zfree, or - NULL to use the library memory allocation functions. + Z_NULL to use the library memory allocation functions. windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. - - This function is hidden in ZLIB_COMPAT builds. */ -int32_t ZNG_CONDEXPORT PREFIX(inflateBackInit)(PREFIX3(stream) *strm, int32_t windowBits, uint8_t *window) { - struct inflate_state *state; +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; - if (strm == NULL || window == NULL || windowBits < MIN_WBITS || windowBits > MAX_WBITS) + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) return Z_STREAM_ERROR; - strm->msg = NULL; /* in case we return an error */ - if (strm->zalloc == NULL) { - strm->zalloc = PREFIX(zcalloc); - strm->opaque = NULL; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif } - if (strm->zfree == NULL) - strm->zfree = PREFIX(zcfree); - - inflate_allocs *alloc_bufs = alloc_inflate(strm); - if (alloc_bufs == NULL) - return Z_MEM_ERROR; - - state = alloc_bufs->state; - state->alloc_bufs = alloc_bufs; + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); - - strm->state = (struct internal_state *)state; - state->wbits = (unsigned int)windowBits; + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits; - state->wbufsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; -#ifdef INFLATE_STRICT - state->dmax = 32768U; -#endif -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - state->sane = 1; -#endif return Z_OK; } -/* Function used by zlib.h and zlib-ng version 2.0 macros */ -int32_t Z_EXPORT PREFIX(inflateBackInit_)(PREFIX3(stream) *strm, int32_t windowBits, uint8_t *window, - const char *version, int32_t stream_size) { - if (CHECK_VER_STSIZE(version, stream_size)) - return Z_VERSION_ERROR; - return PREFIX(inflateBackInit)(strm, windowBits, window); +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; } -/* - Private macros for inflateBack() - Look in inflate_p.h for macros shared with inflate() -*/ +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) /* Assure that some input is available. If input is requested, but denied, then return a Z_BUF_ERROR from inflateBack(). */ @@ -88,7 +160,7 @@ int32_t Z_EXPORT PREFIX(inflateBackInit_)(PREFIX3(stream) *strm, int32_t windowB if (have == 0) { \ have = in(in_desc, &next); \ if (have == 0) { \ - next = NULL; \ + next = Z_NULL; \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ @@ -101,10 +173,37 @@ int32_t Z_EXPORT PREFIX(inflateBackInit_)(PREFIX3(stream) *strm, int32_t windowB do { \ PULL(); \ have--; \ - hold += ((uint64_t)(*next++) << bits); \ + hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + /* Assure that some output space is available, by writing out the window if it's full. If the write fails, return from inflateBack() with a Z_BUF_ERROR. */ @@ -141,41 +240,47 @@ int32_t Z_EXPORT PREFIX(inflateBackInit_)(PREFIX3(stream) *strm, int32_t windowB in() should return zero on failure. out() should return non-zero on failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is NULL or the state was not initialized. + are not correct, i.e. strm is Z_NULL or the state was not initialized. */ -int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in_desc, out_func out, void *out_desc) { - struct inflate_state *state; - z_const unsigned char *next; /* next input */ - unsigned char *put; /* next output */ - unsigned have, left; /* available input and output */ - uint64_t hold; /* bit buffer */ - bits_t bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char *from; /* where to copy match bytes from */ - code here; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int32_t ret; /* return code */ - static const uint16_t order[19] = /* permutation of code lengths */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* Check that the strm exists and that the state was initialized */ - if (strm == NULL || strm->state == NULL) + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; + state = (struct inflate_state FAR *)strm->state; /* Reset the state */ - strm->msg = NULL; + strm->msg = Z_NULL; state->mode = TYPE; state->last = 0; state->whave = 0; next = strm->next_in; - have = next != NULL ? strm->avail_in : 0; + have = next != Z_NULL ? strm->avail_in : 0; hold = 0; bits = 0; put = state->window; @@ -196,20 +301,24 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ - PREFIX(fixedtables)(state); - Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); state->mode = LEN; /* decode codes */ break; case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: - SET_BAD("invalid block type"); + strm->msg = (char *)"invalid block type"; + state->mode = BAD; } DROPBITS(2); break; @@ -219,11 +328,13 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - SET_BAD("invalid stored block lengths"); + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; break; } - state->length = (uint16_t)hold; - Tracev((stderr, "inflate: stored length %u\n", state->length)); + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); INITBITS(); /* copy stored block from input to output */ @@ -231,9 +342,9 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in copy = state->length; PULL(); ROOM(); - copy = MIN(copy, have); - copy = MIN(copy, left); - memcpy(put, next, copy); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; @@ -255,60 +366,67 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { - SET_BAD("too many length or distance symbols"); + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; /* get code length code lengths (not a typo) */ + state->have = 0; while (state->have < state->ncode) { NEEDBITS(3); - state->lens[order[state->have++]] = (uint16_t)BITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; - state->lencode = (const code *)(state->next); + state->lencode = (code const FAR *)(state->next); state->lenbits = 7; - ret = zng_inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); if (ret) { - SET_BAD("invalid code lengths set"); + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; /* get length and distance code code lengths */ + state->have = 0; while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; - if (here.bits <= bits) break; + if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; - } else { + } + else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { - SET_BAD("invalid bit length repeat"); + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; break; } - len = state->lens[state->have - 1]; + len = (unsigned)(state->lens[state->have - 1]); copy = 3 + BITS(2); DROPBITS(2); - } else if (here.val == 17) { + } + else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); - } else { + } + else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; @@ -316,48 +434,49 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { - SET_BAD("invalid bit length repeat"); + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; break; } - while (copy) { - --copy; - state->lens[state->have++] = (uint16_t)len; - } + while (copy--) + state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ - if (state->mode == BAD) - break; + if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { - SET_BAD("invalid code -- missing end-of-block"); + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits - values here (10 and 9) without reading the comments in inftrees.h + values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; - state->lencode = (const code *)(state->next); - state->lenbits = 10; - ret = zng_inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); if (ret) { - SET_BAD("invalid literal/lengths set"); + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; break; } - state->distcode = (const code *)(state->next); - state->distbits = 9; - ret = zng_inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); if (ret) { - SET_BAD("invalid distances set"); + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; - Z_FALLTHROUGH; case LEN: /* use inflate_fast() if we have enough input and output */ @@ -366,7 +485,7 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in RESTORE(); if (state->whave < state->wsize) state->whave = state->wsize - left; - FUNCTABLE_CALL(inflate_fast)(strm, state->wsize); + inflate_fast(strm, state->wsize); LOAD(); break; } @@ -374,28 +493,27 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; - if (CODE_BITS(here) <= bits) - break; + if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { - unsigned last_bits; last = here; - last_bits = CODE_BITS(last); for (;;) { - here = state->lencode[last.val + (BITS(last_bits + (last.op & 15)) >> last_bits)]; - if (last_bits + CODE_BITS(here) <= bits) - break; + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } - DROPBITS(last_bits); + DROPBITS(last.bits); } - DROPBITS(CODE_BITS(here)); - state->length = here.val; + DROPBITS(here.bits); + state->length = (unsigned)here.val; /* process literal */ - if ((int)(here.op) == 0) { - TRACE_LITERAL(here.val); + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); ROOM(); *put++ = (unsigned char)(state->length); left--; @@ -405,66 +523,65 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in /* process end of block */ if (here.op & 32) { - TRACE_END_OF_BLOCK(); + Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } /* invalid code */ if (here.op & 64) { - SET_BAD("invalid literal/length code"); + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; break; } /* length code -- get extra bits, if any */ - state->extra = CODE_EXTRA(here); - if (state->extra) { + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); } - TRACE_LENGTH(state->length); + Tracevv((stderr, "inflate: length %u\n", state->length)); /* get distance code */ for (;;) { here = state->distcode[BITS(state->distbits)]; - if (CODE_BITS(here) <= bits) - break; + if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { - unsigned last_bits; last = here; - last_bits = CODE_BITS(last); for (;;) { - here = state->distcode[last.val + (BITS(last_bits + (last.op & 15)) >> last_bits)]; - if (last_bits + CODE_BITS(here) <= bits) - break; + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } - DROPBITS(last_bits); + DROPBITS(last.bits); } - DROPBITS(CODE_BITS(here)); + DROPBITS(here.bits); if (here.op & 64) { - SET_BAD("invalid distance code"); + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; break; } - state->offset = here.val; - state->extra = CODE_EXTRA(here); + state->offset = (unsigned)here.val; /* get distance extra bits, if any */ - if (state->extra) { + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); } -#ifdef INFLATE_STRICT - if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { - SET_BAD("invalid distance too far back"); + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; break; } -#endif - TRACE_DISTANCE(state->offset); + Tracevv((stderr, "inflate: distance %u\n", state->offset)); /* copy match from window to output */ do { @@ -473,11 +590,12 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in if (copy < left) { from = put + copy; copy = left - copy; - } else { + } + else { from = put - state->offset; copy = left; } - copy = MIN(copy, state->length); + if (copy > state->length) copy = state->length; state->length -= copy; left -= copy; do { @@ -487,8 +605,12 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in break; case DONE: - /* inflate stream terminated properly */ + /* inflate stream terminated properly -- write leftover output */ ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } goto inf_leave; case BAD: @@ -500,25 +622,20 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in goto inf_leave; } - /* Write leftover output and return unused input */ + /* Return unused input */ inf_leave: - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left) && (ret == Z_STREAM_END)) { - ret = Z_BUF_ERROR; - } - } strm->next_in = next; strm->avail_in = have; return ret; } -int32_t Z_EXPORT PREFIX(inflateBackEnd)(PREFIX3(stream) *strm) { - if (strm == NULL || strm->state == NULL || strm->zfree == NULL) +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; - - /* Free allocated buffers */ - free_inflate(strm); - + ZFREE(strm, strm->state); + strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } diff --git a/modules/zlib/src/inffast.c b/modules/zlib/src/inffast.c new file mode 100644 index 0000000000..66c0d02494 --- /dev/null +++ b/modules/zlib/src/inffast.c @@ -0,0 +1,326 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= INFLATE_FAST_MIN_HAVE + strm->avail_out >= INFLATE_FAST_MIN_LEFT + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - (INFLATE_FAST_MIN_HAVE - 1)); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - (INFLATE_FAST_MIN_LEFT - 1)); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + *out++ = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? + (INFLATE_FAST_MIN_HAVE - 1) + (last - in) : + (INFLATE_FAST_MIN_HAVE - 1) - (in - last)); + strm->avail_out = (unsigned)(out < end ? + (INFLATE_FAST_MIN_LEFT - 1) + (end - out) : + (INFLATE_FAST_MIN_LEFT - 1) - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/modules/zlib/src/inffast.h b/modules/zlib/src/inffast.h new file mode 100644 index 0000000000..ec9272aa0f --- /dev/null +++ b/modules/zlib/src/inffast.h @@ -0,0 +1,25 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* INFLATE_FAST_MIN_LEFT is the minimum number of output bytes that are left, + so that we can call inflate_fast safely with only one up front bounds check. + One length-distance code pair can copy up to 258 bytes. + */ +#define INFLATE_FAST_MIN_LEFT 258 + +/* INFLATE_FAST_MIN_HAVE is the minimum number of input bytes that we have, so + that we can call inflate_fast safely with only one up front bounds check. + One length-distance code pair (as two Huffman encoded values of up to 15 + bits each) plus any additional bits (up to 5 for length and 13 for distance) + can require reading up to 48 bits, or 6 bytes. + */ +#define INFLATE_FAST_MIN_HAVE 6 + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/modules/zlib/src/inffast_chunk.c b/modules/zlib/src/inffast_chunk.c new file mode 100644 index 0000000000..a86cfea605 --- /dev/null +++ b/modules/zlib/src/inffast_chunk.c @@ -0,0 +1,318 @@ +/* inffast_chunk.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast_chunk.h" +#include "chunkcopy.h" + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate() execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= INFLATE_FAST_MIN_INPUT (6 bytes) + strm->avail_out >= INFLATE_FAST_MIN_OUTPUT (258 bytes) + start >= strm->avail_out + state->bits < 8 + strm->next_out[0..strm->avail_out] does not overlap with + strm->next_in[0..strm->avail_in] + strm->state->window is allocated with an additional + CHUNKCOPY_CHUNK_SIZE-1 bytes of padding beyond strm->state->wsize + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + INFLATE_FAST_MIN_INPUT 6 bytes + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + INFLATE_FAST_MIN_OUTPUT 258 bytes + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + available output space while decoding. + */ +void ZLIB_INTERNAL inflate_fast_chunk_(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned char FAR *limit; /* safety limit for chunky copies */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - (INFLATE_FAST_MIN_INPUT - 1)); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - (INFLATE_FAST_MIN_OUTPUT - 1)); + limit = out + strm->avail_out; +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = (state->wnext == 0 && whave >= wsize) ? wsize : state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + *out++ = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext >= op) { /* contiguous in window */ + from += wnext - op; + } + else { /* wrap around window */ + op -= wnext; + from += wsize - op; + if (op < len) { /* some from end of window */ + len -= op; + out = chunkcopy_safe(out, from, op, limit); + from = window; /* more from start of window */ + op = wnext; + /* This (rare) case can create a situation where + the first chunkcopy below must be checked. + */ + } + } + if (op < len) { /* still need some from output */ + out = chunkcopy_safe(out, from, op, limit); + len -= op; + /* When dist is small the amount of data that can be + copied from the window is also small, and progress + towards the dangerous end of the output buffer is + also small. This means that for trivial memsets and + for chunkunroll_relaxed() a safety check is + unnecessary. However, these conditions may not be + entered at all, and in that case it's possible that + the main copy is near the end. + */ + out = chunkunroll_relaxed(out, &dist, &len); + out = chunkcopy_safe(out, out - dist, len, limit); + } else { + /* from points to window, so there is no risk of + overlapping pointers requiring memset-like behaviour + */ + out = chunkcopy_safe(out, from, len, limit); + } + } + else { + /* Whole reference is in range of current output. No + range checks are necessary because we start with room + for at least 258 bytes of output, so unroll and roundoff + operations can write beyond `out+len` so long as they + stay within 258 bytes of `out`. + */ + out = chunkcopy_lapped_relaxed(out, dist, len); + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? + (INFLATE_FAST_MIN_INPUT - 1) + (last - in) : + (INFLATE_FAST_MIN_INPUT - 1) - (in - last)); + strm->avail_out = (unsigned)(out < end ? + (INFLATE_FAST_MIN_OUTPUT - 1) + (end - out) : + (INFLATE_FAST_MIN_OUTPUT - 1) - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/modules/zlib/src/inffast_chunk.h b/modules/zlib/src/inffast_chunk.h new file mode 100644 index 0000000000..5cd1eac359 --- /dev/null +++ b/modules/zlib/src/inffast_chunk.h @@ -0,0 +1,27 @@ +/* inffast_chunk.h -- header to use inffast_chunk.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * Copyright (C) 2017 ARM, Inc. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* INFLATE_FAST_MIN_INPUT: the minimum number of input bytes needed so that + we can safely call inflate_fast() with only one up-front bounds check. One + length/distance code pair (15 bits for the length code, 5 bits for length + extra, 15 bits for the distance code, 13 bits for distance extra) requires + reading up to 48 input bits (6 bytes). +*/ +#define INFLATE_FAST_MIN_INPUT 6 + +/* INFLATE_FAST_MIN_OUTPUT: the minimum number of output bytes needed so that + we can safely call inflate_fast() with only one up-front bounds check. One + length/distance code pair can output up to 258 bytes, which is the maximum + length that can be coded. + */ +#define INFLATE_FAST_MIN_OUTPUT 258 + +void ZLIB_INTERNAL inflate_fast_chunk_ OF((z_streamp strm, unsigned start)); diff --git a/modules/zlib/src/inffast_tpl.h b/modules/zlib/src/inffast_tpl.h deleted file mode 100644 index 368dde58e7..0000000000 --- a/modules/zlib/src/inffast_tpl.h +++ /dev/null @@ -1,343 +0,0 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2017 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zbuild.h" -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inflate_p.h" -#include "functable.h" - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= INFLATE_FAST_MIN_HAVE - strm->avail_out >= INFLATE_FAST_MIN_LEFT - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - On some architectures, it can be significantly faster (e.g. up to 1.2x - faster on x86_64) to load from strm->next_in 64 bits, or 8 bytes, at a - time, so INFLATE_FAST_MIN_HAVE == 8. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void Z_INTERNAL INFLATE_FAST(PREFIX3(stream) *strm, uint32_t start) { - /* start: inflate()'s starting value for strm->avail_out */ - struct inflate_state *state; - z_const unsigned char *in; /* local strm->next_in */ - const unsigned char *last; /* have enough input while in < last */ - unsigned char *out; /* local strm->next_out */ - unsigned char *beg; /* inflate()'s initial strm->next_out */ - unsigned char *end; /* while out < end, enough space available */ - unsigned char *safe; /* can use chunkcopy provided out < safe */ - unsigned char *window; /* allocated sliding window, if wsize != 0 */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned wnext; /* window write index */ - - /* hold is a local copy of strm->hold. By default, hold satisfies the same - invariants that strm->hold does, namely that (hold >> bits) == 0. This - invariant is kept by loading bits into hold one byte at a time, like: - - hold |= next_byte_of_input << bits; in++; bits += 8; - - If we need to ensure that bits >= 15 then this code snippet is simply - repeated. Over one iteration of the outermost do/while loop, this - happens up to six times (48 bits of input), as described in the NOTES - above. - - However, on some little endian architectures, it can be significantly - faster to load 64 bits once instead of 8 bits six times: - - if (bits <= 16) { - hold |= next_8_bytes_of_input << bits; in += 6; bits += 48; - } - - Unlike the simpler one byte load, shifting the next_8_bytes_of_input - by bits will overflow and lose those high bits, up to 2 bytes' worth. - The conservative estimate is therefore that we have read only 6 bytes - (48 bits). Again, as per the NOTES above, 48 bits is sufficient for the - rest of the iteration, and we will not need to load another 8 bytes. - - Inside this function, we no longer satisfy (hold >> bits) == 0, but - this is not problematic, even if that overflow does not land on an 8 bit - byte boundary. Those excess bits will eventually shift down lower as the - Huffman decoder consumes input, and when new input bits need to be loaded - into the bits variable, the same input bits will be or'ed over those - existing bits. A bitwise or is idempotent: (a | b | b) equals (a | b). - Note that we therefore write that load operation as "hold |= etc" and not - "hold += etc". - - Outside that loop, at the end of the function, hold is bitwise and'ed - with (1<hold >> state->bits) == 0. - */ - bits_t bits; /* local strm->bits */ - uint64_t hold; /* local strm->hold */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code const *lcode; /* local strm->lencode */ - code const *dcode; /* local strm->distcode */ - code here; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned char *from; /* where to copy match from */ - unsigned dist; /* match distance */ - unsigned extra_safe; /* copy chunks safely in all cases */ - uint64_t old; /* look-behind buffer for extra bits */ - - /* copy state to local variables */ - state = (struct inflate_state *)strm->state; - in = strm->next_in; - last = in + (strm->avail_in - (INFLATE_FAST_MIN_HAVE - 1)); - out = strm->next_out; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - (INFLATE_FAST_MIN_LEFT - 1)); - safe = out + strm->avail_out; - wsize = state->wsize; - whave = state->whave; - wnext = state->wnext; - window = state->window; - hold = state->hold; - bits = (bits_t)state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* Detect if out and window point to the same memory allocation. In this instance it is - necessary to use safe chunk copy functions to prevent overwriting the window. If the - window is overwritten then future matches with far distances will fail to copy correctly. */ - extra_safe = (wsize != 0 && out >= window && out + INFLATE_FAST_MIN_LEFT <= window + state->wbufsize); - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - REFILL(); - here = lcode[hold & lmask]; - Z_TOUCH(here); - old = hold; - DROPBITS(here.bits); - if (LIKELY(here.op == 0)) { - TRACE_LITERAL(here.val); - *out++ = (unsigned char)(here.val); - here = lcode[hold & lmask]; - Z_TOUCH(here); - old = hold; - DROPBITS(here.bits); - if (LIKELY(here.op == 0)) { - TRACE_LITERAL(here.val); - *out++ = (unsigned char)(here.val); - here = lcode[hold & lmask]; - Z_TOUCH(here); - dolen: - old = hold; - DROPBITS(here.bits); - if (LIKELY(here.op == 0)) { - TRACE_LITERAL(here.val); - *out++ = (unsigned char)(here.val); - continue; - } - } - } - op = here.op; - if (LIKELY(op & 16)) { /* length base */ - len = here.val + EXTRA_BITS(old, here, op); - TRACE_LENGTH(len); - here = dcode[hold & dmask]; - Z_TOUCH(here); - if (UNLIKELY(bits < MAX_BITS + MAX_DIST_EXTRA_BITS)) { - REFILL(); - } - dodist: - old = hold; - DROPBITS(here.bits); - op = here.op; - if (LIKELY(op & 16)) { /* distance base */ - dist = here.val + EXTRA_BITS(old, here, op); -#ifdef INFLATE_STRICT - if (UNLIKELY(dist > state->dmax)) { - SET_BAD("invalid distance too far back"); - break; - } -#endif - TRACE_DISTANCE(dist); - op = (unsigned)(out - beg); /* max distance in output */ - if (UNLIKELY(dist > op)) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (UNLIKELY(op > whave)) { -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - if (LIKELY(state->sane)) { - SET_BAD("invalid distance too far back"); - break; - } - unsigned gap = op - whave; - unsigned zeros = MIN(len, gap); - memset(out, 0, zeros); /* fill missing bytes with zeros */ - out += zeros; - len -= zeros; - if (UNLIKELY(len == 0)) - continue; - op = whave; - if (UNLIKELY(op == 0)) {/* copy from already-decoded output */ - out = chunkcopy_safe(out, out - dist, len, safe); - continue; - } -#else - SET_BAD("invalid distance too far back"); - break; -#endif - } - from = window; - if (LIKELY(wnext == 0)) { /* very common case */ - from += wsize - op; - } else if (LIKELY(wnext >= op)) { /* contiguous in window */ - from += wnext - op; - } else { /* wrap around window */ - op -= wnext; - from += wsize - op; - if (UNLIKELY(op < len)) { /* some from end of window */ - len -= op; - out = CHUNKCOPY_SAFE(out, from, op, safe); - from = window; /* more from start of window */ - op = wnext; - /* This (rare) case can create a situation where - the first chunkcopy below must be checked. - */ - } - } - if (UNLIKELY(op < len)) { /* still need some from output */ - len -= op; - if (LIKELY(!extra_safe)) { - out = CHUNKCOPY_SAFE(out, from, op, safe); - out = CHUNKUNROLL(out, &dist, &len); - out = CHUNKCOPY_SAFE(out, out - dist, len, safe); - } else { - out = chunkcopy_safe(out, from, op, safe); - out = chunkcopy_safe(out, out - dist, len, safe); - } - } else { -#ifndef HAVE_MASKED_READWRITE - if (UNLIKELY(extra_safe)) - out = chunkcopy_safe(out, from, len, safe); - else -#endif - out = CHUNKCOPY_SAFE(out, from, len, safe); - } -#ifndef HAVE_MASKED_READWRITE - } else if (UNLIKELY(extra_safe)) { - /* Whole reference is in range of current output. */ - out = chunkcopy_safe(out, out - dist, len, safe); -#endif - } else { - /* Whole reference is in range of current output. No range checks are - necessary because we start with room for at least 258 bytes of output, - so unroll and roundoff operations can write beyond `out+len` so long - as they stay within 258 bytes of `out`. - */ - if (LIKELY(dist >= len || dist >= CHUNKSIZE())) - out = CHUNKCOPY(out, out - dist, len); - else - out = CHUNKMEMSET(out, out - dist, len); - } - } else if (UNLIKELY((op & 64) == 0)) { /* 2nd level distance code */ - here = dcode[here.val + BITS(op)]; - Z_TOUCH(here); - goto dodist; - } else { - SET_BAD("invalid distance code"); - break; - } - } else if (UNLIKELY((op & 64) == 0)) { /* 2nd level length code */ - here = lcode[here.val + BITS(op)]; - Z_TOUCH(here); - goto dolen; - } else if (UNLIKELY(op & 32)) { /* end-of-block */ - TRACE_END_OF_BLOCK(); - state->mode = TYPE; - break; - } else { - SET_BAD("invalid literal/length code"); - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= (bits_t)(len << 3); - hold &= (UINT64_C(1) << bits) - 1; - - /* update state and return */ - strm->next_in = in; - strm->next_out = out; - strm->avail_in = (unsigned)(in < last ? (INFLATE_FAST_MIN_HAVE - 1) + (last - in) - : (INFLATE_FAST_MIN_HAVE - 1) - (in - last)); - strm->avail_out = (unsigned)(out < end ? (INFLATE_FAST_MIN_LEFT - 1) + (end - out) - : (INFLATE_FAST_MIN_LEFT - 1) - (out - end)); - - Assert(bits <= 32, "Remaining bits greater than 32"); - state->hold = (uint32_t)hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and wnext == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - - // Cleanup -#undef CHUNKCOPY -#undef CHUNKMEMSET -#undef CHUNKMEMSET_SAFE -#undef CHUNKSIZE -#undef CHUNKUNROLL -#undef HAVE_CHUNKCOPY -#undef HAVE_CHUNKMEMSET_2 -#undef HAVE_CHUNKMEMSET_4 -#undef HAVE_CHUNKMEMSET_8 -#undef HAVE_CHUNKMEMSET_16 -#undef HAVE_CHUNK_MAG -#undef HAVE_HALFCHUNKCOPY -#undef HAVE_HALF_CHUNK -#undef HAVE_MASKED_READWRITE -#undef INFLATE_FAST diff --git a/modules/zlib/src/inffixed.h b/modules/zlib/src/inffixed.h new file mode 100644 index 0000000000..d628327769 --- /dev/null +++ b/modules/zlib/src/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/modules/zlib/src/inffixed_tbl.h b/modules/zlib/src/inffixed_tbl.h deleted file mode 100644 index 5f8647bf59..0000000000 --- a/modules/zlib/src/inffixed_tbl.h +++ /dev/null @@ -1,94 +0,0 @@ -/* inffixed_tbl.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - -/* WARNING: this file should *not* be used by applications. - * It is part of the implementation of this library and is - * subject to change. Applications should only use zlib.h. - */ - -static const code lenfix[512] = { - {7,96,0},{8,0,80},{8,0,16},{12,24,115},{9,23,31},{8,0,112},{8,0,48}, - {9,0,192},{7,23,10},{8,0,96},{8,0,32},{9,0,160},{8,0,0},{8,0,128}, - {8,0,64},{9,0,224},{7,23,6},{8,0,88},{8,0,24},{9,0,144},{10,23,59}, - {8,0,120},{8,0,56},{9,0,208},{8,23,17},{8,0,104},{8,0,40},{9,0,176}, - {8,0,8},{8,0,136},{8,0,72},{9,0,240},{7,23,4},{8,0,84},{8,0,20}, - {13,24,227},{10,23,43},{8,0,116},{8,0,52},{9,0,200},{8,23,13},{8,0,100}, - {8,0,36},{9,0,168},{8,0,4},{8,0,132},{8,0,68},{9,0,232},{7,23,8}, - {8,0,92},{8,0,28},{9,0,152},{11,23,83},{8,0,124},{8,0,60},{9,0,216}, - {9,23,23},{8,0,108},{8,0,44},{9,0,184},{8,0,12},{8,0,140},{8,0,76}, - {9,0,248},{7,23,3},{8,0,82},{8,0,18},{13,24,163},{10,23,35},{8,0,114}, - {8,0,50},{9,0,196},{8,23,11},{8,0,98},{8,0,34},{9,0,164},{8,0,2}, - {8,0,130},{8,0,66},{9,0,228},{7,23,7},{8,0,90},{8,0,26},{9,0,148}, - {11,23,67},{8,0,122},{8,0,58},{9,0,212},{9,23,19},{8,0,106},{8,0,42}, - {9,0,180},{8,0,10},{8,0,138},{8,0,74},{9,0,244},{7,23,5},{8,0,86}, - {8,0,22},{19,64,0},{10,23,51},{8,0,118},{8,0,54},{9,0,204},{8,23,15}, - {8,0,102},{8,0,38},{9,0,172},{8,0,6},{8,0,134},{8,0,70},{9,0,236}, - {7,23,9},{8,0,94},{8,0,30},{9,0,156},{11,23,99},{8,0,126},{8,0,62}, - {9,0,220},{9,23,27},{8,0,110},{8,0,46},{9,0,188},{8,0,14},{8,0,142}, - {8,0,78},{9,0,252},{7,96,0},{8,0,81},{8,0,17},{13,24,131},{9,23,31}, - {8,0,113},{8,0,49},{9,0,194},{7,23,10},{8,0,97},{8,0,33},{9,0,162}, - {8,0,1},{8,0,129},{8,0,65},{9,0,226},{7,23,6},{8,0,89},{8,0,25}, - {9,0,146},{10,23,59},{8,0,121},{8,0,57},{9,0,210},{8,23,17},{8,0,105}, - {8,0,41},{9,0,178},{8,0,9},{8,0,137},{8,0,73},{9,0,242},{7,23,4}, - {8,0,85},{8,0,21},{8,24,258},{10,23,43},{8,0,117},{8,0,53},{9,0,202}, - {8,23,13},{8,0,101},{8,0,37},{9,0,170},{8,0,5},{8,0,133},{8,0,69}, - {9,0,234},{7,23,8},{8,0,93},{8,0,29},{9,0,154},{11,23,83},{8,0,125}, - {8,0,61},{9,0,218},{9,23,23},{8,0,109},{8,0,45},{9,0,186},{8,0,13}, - {8,0,141},{8,0,77},{9,0,250},{7,23,3},{8,0,83},{8,0,19},{13,24,195}, - {10,23,35},{8,0,115},{8,0,51},{9,0,198},{8,23,11},{8,0,99},{8,0,35}, - {9,0,166},{8,0,3},{8,0,131},{8,0,67},{9,0,230},{7,23,7},{8,0,91}, - {8,0,27},{9,0,150},{11,23,67},{8,0,123},{8,0,59},{9,0,214},{9,23,19}, - {8,0,107},{8,0,43},{9,0,182},{8,0,11},{8,0,139},{8,0,75},{9,0,246}, - {7,23,5},{8,0,87},{8,0,23},{21,64,0},{10,23,51},{8,0,119},{8,0,55}, - {9,0,206},{8,23,15},{8,0,103},{8,0,39},{9,0,174},{8,0,7},{8,0,135}, - {8,0,71},{9,0,238},{7,23,9},{8,0,95},{8,0,31},{9,0,158},{11,23,99}, - {8,0,127},{8,0,63},{9,0,222},{9,23,27},{8,0,111},{8,0,47},{9,0,190}, - {8,0,15},{8,0,143},{8,0,79},{9,0,254},{7,96,0},{8,0,80},{8,0,16}, - {12,24,115},{9,23,31},{8,0,112},{8,0,48},{9,0,193},{7,23,10},{8,0,96}, - {8,0,32},{9,0,161},{8,0,0},{8,0,128},{8,0,64},{9,0,225},{7,23,6}, - {8,0,88},{8,0,24},{9,0,145},{10,23,59},{8,0,120},{8,0,56},{9,0,209}, - {8,23,17},{8,0,104},{8,0,40},{9,0,177},{8,0,8},{8,0,136},{8,0,72}, - {9,0,241},{7,23,4},{8,0,84},{8,0,20},{13,24,227},{10,23,43},{8,0,116}, - {8,0,52},{9,0,201},{8,23,13},{8,0,100},{8,0,36},{9,0,169},{8,0,4}, - {8,0,132},{8,0,68},{9,0,233},{7,23,8},{8,0,92},{8,0,28},{9,0,153}, - {11,23,83},{8,0,124},{8,0,60},{9,0,217},{9,23,23},{8,0,108},{8,0,44}, - {9,0,185},{8,0,12},{8,0,140},{8,0,76},{9,0,249},{7,23,3},{8,0,82}, - {8,0,18},{13,24,163},{10,23,35},{8,0,114},{8,0,50},{9,0,197},{8,23,11}, - {8,0,98},{8,0,34},{9,0,165},{8,0,2},{8,0,130},{8,0,66},{9,0,229}, - {7,23,7},{8,0,90},{8,0,26},{9,0,149},{11,23,67},{8,0,122},{8,0,58}, - {9,0,213},{9,23,19},{8,0,106},{8,0,42},{9,0,181},{8,0,10},{8,0,138}, - {8,0,74},{9,0,245},{7,23,5},{8,0,86},{8,0,22},{19,64,0},{10,23,51}, - {8,0,118},{8,0,54},{9,0,205},{8,23,15},{8,0,102},{8,0,38},{9,0,173}, - {8,0,6},{8,0,134},{8,0,70},{9,0,237},{7,23,9},{8,0,94},{8,0,30}, - {9,0,157},{11,23,99},{8,0,126},{8,0,62},{9,0,221},{9,23,27},{8,0,110}, - {8,0,46},{9,0,189},{8,0,14},{8,0,142},{8,0,78},{9,0,253},{7,96,0}, - {8,0,81},{8,0,17},{13,24,131},{9,23,31},{8,0,113},{8,0,49},{9,0,195}, - {7,23,10},{8,0,97},{8,0,33},{9,0,163},{8,0,1},{8,0,129},{8,0,65}, - {9,0,227},{7,23,6},{8,0,89},{8,0,25},{9,0,147},{10,23,59},{8,0,121}, - {8,0,57},{9,0,211},{8,23,17},{8,0,105},{8,0,41},{9,0,179},{8,0,9}, - {8,0,137},{8,0,73},{9,0,243},{7,23,4},{8,0,85},{8,0,21},{8,24,258}, - {10,23,43},{8,0,117},{8,0,53},{9,0,203},{8,23,13},{8,0,101},{8,0,37}, - {9,0,171},{8,0,5},{8,0,133},{8,0,69},{9,0,235},{7,23,8},{8,0,93}, - {8,0,29},{9,0,155},{11,23,83},{8,0,125},{8,0,61},{9,0,219},{9,23,23}, - {8,0,109},{8,0,45},{9,0,187},{8,0,13},{8,0,141},{8,0,77},{9,0,251}, - {7,23,3},{8,0,83},{8,0,19},{13,24,195},{10,23,35},{8,0,115},{8,0,51}, - {9,0,199},{8,23,11},{8,0,99},{8,0,35},{9,0,167},{8,0,3},{8,0,131}, - {8,0,67},{9,0,231},{7,23,7},{8,0,91},{8,0,27},{9,0,151},{11,23,67}, - {8,0,123},{8,0,59},{9,0,215},{9,23,19},{8,0,107},{8,0,43},{9,0,183}, - {8,0,11},{8,0,139},{8,0,75},{9,0,247},{7,23,5},{8,0,87},{8,0,23}, - {21,64,0},{10,23,51},{8,0,119},{8,0,55},{9,0,207},{8,23,15},{8,0,103}, - {8,0,39},{9,0,175},{8,0,7},{8,0,135},{8,0,71},{9,0,239},{7,23,9}, - {8,0,95},{8,0,31},{9,0,159},{11,23,99},{8,0,127},{8,0,63},{9,0,223}, - {9,23,27},{8,0,111},{8,0,47},{9,0,191},{8,0,15},{8,0,143},{8,0,79}, - {9,0,255} -}; - -static const code distfix[32] = { - {5,21,1},{12,21,257},{8,21,17},{16,21,4097},{6,21,5},{14,21,1025}, - {10,21,65},{18,21,16385},{5,21,3},{13,21,513},{9,21,33},{17,21,8193}, - {7,21,9},{15,21,2049},{11,21,129},{5,64,0},{5,21,2},{12,21,385}, - {8,21,25},{16,21,6145},{6,21,7},{14,21,1537},{10,21,97},{18,21,24577}, - {5,21,4},{13,21,769},{9,21,49},{17,21,12289},{7,21,13},{15,21,3073}, - {11,21,193},{5,64,0} -}; diff --git a/modules/zlib/src/inflate.c b/modules/zlib/src/inflate.c index 3aab872258..5c40cf1ee0 100644 --- a/modules/zlib/src/inflate.c +++ b/modules/zlib/src/inflate.c @@ -1,313 +1,385 @@ /* inflate.c -- zlib decompression - * Copyright (C) 1995-2022 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" -#include "zsanitizer.h" +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + #include "zutil.h" #include "inftrees.h" #include "inflate.h" -#include "inflate_p.h" -#include "inffixed_tbl.h" -#include "functable.h" +#include "inffast.h" -/* Avoid conflicts with zlib.h macros */ -#ifdef ZLIB_COMPAT -# undef inflateInit -# undef inflateInit2 +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif #endif /* function prototypes */ -static int inflateStateCheck(PREFIX3(stream) *strm); -static void updatewindow(PREFIX3(stream) *strm, const uint8_t *end, uint32_t len, int32_t cksum); -static uint32_t syncsearch(uint32_t *have, const unsigned char *buf, uint32_t len); - -static inline void inf_chksum_cpy(PREFIX3(stream) *strm, uint8_t *dst, - const uint8_t *src, uint32_t copy) { - if (!copy) return; - struct inflate_state *state = (struct inflate_state*)strm->state; -#ifdef GUNZIP - if (state->flags) { - strm->adler = state->check = FUNCTABLE_CALL(crc32_copy)(state->check, dst, src, copy); - } else +local int inflateStateCheck OF((z_streamp strm)); +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); +#ifdef BUILDFIXED + void makefixed OF((void)); #endif - { - strm->adler = state->check = FUNCTABLE_CALL(adler32_copy)(state->check, dst, src, copy); - } -} +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); -static inline void inf_chksum(PREFIX3(stream) *strm, const uint8_t *src, uint32_t len) { - struct inflate_state *state = (struct inflate_state*)strm->state; -#ifdef GUNZIP - if (state->flags) { - strm->adler = state->check = FUNCTABLE_CALL(crc32)(state->check, src, len); - } else -#endif - { - strm->adler = state->check = FUNCTABLE_CALL(adler32)(state->check, src, len); - } -} - -static int inflateStateCheck(PREFIX3(stream) *strm) { - struct inflate_state *state; - if (strm == NULL || strm->zalloc == NULL || strm->zfree == NULL) +local int inflateStateCheck(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; - state = (struct inflate_state *)strm->state; - if (state == NULL || state->alloc_bufs == NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC) + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) return 1; return 0; } -int32_t Z_EXPORT PREFIX(inflateResetKeep)(PREFIX3(stream) *strm) { - struct inflate_state *state; +int ZEXPORT inflateResetKeep(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; - strm->msg = NULL; + strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; - state->check = ADLER32_INITIAL_VALUE; state->last = 0; state->havedict = 0; - state->flags = -1; - state->head = NULL; + state->dmax = 32768U; + state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; - state->back = -1; -#ifdef INFLATE_STRICT - state->dmax = 32768U; -#endif -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR state->sane = 1; -#endif - INFLATE_RESET_KEEP_HOOK(strm); /* hook for IBM Z DFLTCC */ + state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } -int32_t Z_EXPORT PREFIX(inflateReset)(PREFIX3(stream) *strm) { - struct inflate_state *state; +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; - return PREFIX(inflateResetKeep)(strm); + return inflateResetKeep(strm); } -int32_t Z_EXPORT PREFIX(inflateReset2)(PREFIX3(stream) *strm, int32_t windowBits) { +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ int wrap; - struct inflate_state *state; + struct inflate_state FAR *state; /* get the state */ - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; - if (windowBits < -MAX_WBITS) - return Z_STREAM_ERROR; windowBits = -windowBits; - } else { + } + else { wrap = (windowBits >> 4) + 5; #ifdef GUNZIP if (windowBits < 48) - windowBits &= MAX_WBITS; + windowBits &= 15; #endif } - /* set number of window bits */ - if (windowBits && (windowBits < MIN_WBITS || windowBits > MAX_WBITS)) + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; - return PREFIX(inflateReset)(strm); + return inflateReset(strm); } -#ifdef INF_ALLOC_DEBUG -# include -# define LOGSZ(name,size) fprintf(stderr, "%s is %d bytes\n", name, size) -# define LOGSZP(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %d, padded %d\n", name, size, loc, pad) -# define LOGSZPL(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %ld, padded %d\n", name, size, loc, pad) -#else -# define LOGSZ(name,size) -# define LOGSZP(name,size,loc,pad) -# define LOGSZPL(name,size,loc,pad) -#endif +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; -/* =========================================================================== - * Allocate a big buffer and divide it up into the various buffers inflate needs. - * Handles alignment of allocated buffer and alignment of individual buffers. - */ -Z_INTERNAL inflate_allocs* alloc_inflate(PREFIX3(stream) *strm) { - int curr_size = 0; - - /* Define sizes */ - int window_size = INFLATE_ADJUST_WINDOW_SIZE((1 << MAX_WBITS) + 64); /* 64B padding for chunksize */ - int state_size = sizeof(inflate_state); - int alloc_size = sizeof(inflate_allocs); - - /* Calculate relative buffer positions and paddings */ - LOGSZP("window", window_size, PAD_WINDOW(curr_size), PADSZ(curr_size,WINDOW_PAD_SIZE)); - int window_pos = PAD_WINDOW(curr_size); - curr_size = window_pos + window_size; - - LOGSZP("state", state_size, PAD_64(curr_size), PADSZ(curr_size,64)); - int state_pos = PAD_64(curr_size); - curr_size = state_pos + state_size; - - LOGSZP("alloc", alloc_size, PAD_16(curr_size), PADSZ(curr_size,16)); - int alloc_pos = PAD_16(curr_size); - curr_size = alloc_pos + alloc_size; - - /* Add 64-1 or 4096-1 to allow window alignment, and round size of buffer up to multiple of 64 */ - int total_size = PAD_64(curr_size + (WINDOW_PAD_SIZE - 1)); - - /* Allocate buffer, align to 64-byte cacheline, and zerofill the resulting buffer */ - char *original_buf = (char *)strm->zalloc(strm->opaque, 1, total_size); - if (original_buf == NULL) - return NULL; - - char *buff = (char *)HINT_ALIGNED_WINDOW((char *)PAD_WINDOW(original_buf)); - LOGSZPL("Buffer alloc", total_size, PADSZ((uintptr_t)original_buf,WINDOW_PAD_SIZE), PADSZ(curr_size,WINDOW_PAD_SIZE)); - - /* Initialize alloc_bufs */ - inflate_allocs *alloc_bufs = (struct inflate_allocs_s *)(buff + alloc_pos); - alloc_bufs->buf_start = original_buf; - alloc_bufs->zfree = strm->zfree; - - alloc_bufs->window = (unsigned char *)HINT_ALIGNED_WINDOW((buff + window_pos)); - alloc_bufs->state = (inflate_state *)HINT_ALIGNED_64((buff + state_pos)); - -#ifdef Z_MEMORY_SANITIZER - /* This is _not_ to subvert the memory sanitizer but to instead unposion some - data we willingly and purposefully load uninitialized into vector registers - in order to safely read the last < chunksize bytes of the window. */ - __msan_unpoison(alloc_bufs->window + window_size, 64); -#endif - - return alloc_bufs; -} - -/* =========================================================================== - * Free all allocated inflate buffers - */ -Z_INTERNAL void free_inflate(PREFIX3(stream) *strm) { - struct inflate_state *state = (struct inflate_state *)strm->state; - - if (state->alloc_bufs != NULL) { - inflate_allocs *alloc_bufs = state->alloc_bufs; - alloc_bufs->zfree(strm->opaque, alloc_bufs->buf_start); - strm->state = NULL; - } -} - -/* =========================================================================== - * Initialize inflate state and buffers. - * This function is hidden in ZLIB_COMPAT builds. - */ -int32_t ZNG_CONDEXPORT PREFIX(inflateInit2)(PREFIX3(stream) *strm, int32_t windowBits) { - struct inflate_state *state; - int32_t ret; - - /* Initialize functable */ - FUNCTABLE_INIT; - - if (strm == NULL) + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO return Z_STREAM_ERROR; - strm->msg = NULL; /* in case we return an error */ - if (strm->zalloc == NULL) { - strm->zalloc = PREFIX(zcalloc); - strm->opaque = NULL; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif } - if (strm->zfree == NULL) - strm->zfree = PREFIX(zcfree); - - inflate_allocs *alloc_bufs = alloc_inflate(strm); - if (alloc_bufs == NULL) - return Z_MEM_ERROR; - - state = alloc_bufs->state; - state->window = alloc_bufs->window; - state->alloc_bufs = alloc_bufs; - state->wbufsize = INFLATE_ADJUST_WINDOW_SIZE((1 << MAX_WBITS) + 64); + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); - - strm->state = (struct internal_state *)state; + strm->state = (struct internal_state FAR *)state; state->strm = strm; + state->window = Z_NULL; state->mode = HEAD; /* to pass state test in inflateReset2() */ - ret = PREFIX(inflateReset2)(strm, windowBits); + state->check = 1L; /* 1L is the result of adler32() zero length data */ + ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { - free_inflate(strm); + ZFREE(strm, state); + strm->state = Z_NULL; } return ret; } -#ifndef ZLIB_COMPAT -int32_t Z_EXPORT PREFIX(inflateInit)(PREFIX3(stream) *strm) { - return PREFIX(inflateInit2)(strm, DEF_WBITS); -} -#endif - -/* Function used by zlib.h and zlib-ng version 2.0 macros */ -int32_t Z_EXPORT PREFIX(inflateInit_)(PREFIX3(stream) *strm, const char *version, int32_t stream_size) { - if (CHECK_VER_STSIZE(version, stream_size)) - return Z_VERSION_ERROR; - return PREFIX(inflateInit2)(strm, DEF_WBITS); +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); } -/* Function used by zlib.h and zlib-ng version 2.0 macros */ -int32_t Z_EXPORT PREFIX(inflateInit2_)(PREFIX3(stream) *strm, int32_t windowBits, const char *version, int32_t stream_size) { - if (CHECK_VER_STSIZE(version, stream_size)) - return Z_VERSION_ERROR; - return PREFIX(inflateInit2)(strm, windowBits); -} +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; -int32_t Z_EXPORT PREFIX(inflatePrime)(PREFIX3(stream) *strm, int32_t bits, int32_t value) { - struct inflate_state *state; - - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - if (bits == 0) - return Z_OK; - INFLATE_PRIME_HOOK(strm, bits, value); /* hook for IBM Z DFLTCC */ - state = (struct inflate_state *)strm->state; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } - if (bits > 16 || state->bits + (unsigned int)bits > 32) - return Z_STREAM_ERROR; + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; - state->hold += (uint64_t)value << state->bits; - state->bits += (unsigned int)bits; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to - fixed code decoding. This returns fixed tables from inffixed_tbl.h. + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; -void Z_INTERNAL PREFIX(fixedtables)(struct inflate_state *state) { + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called @@ -322,75 +394,150 @@ void Z_INTERNAL PREFIX(fixedtables)(struct inflate_state *state) { output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ -static void updatewindow(PREFIX3(stream) *strm, const uint8_t *end, uint32_t len, int32_t cksum) { - struct inflate_state *state; - uint32_t dist; +local int updatewindow(strm, end, copy) +z_streamp strm; +const Bytef *end; +unsigned copy; +{ + struct inflate_state FAR *state; + unsigned dist; - state = (struct inflate_state *)strm->state; + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } /* if window not in use yet, initialize */ - if (state->wsize == 0) + if (state->wsize == 0) { state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } - /* len state->wsize or less output bytes into the circular window */ - if (len >= state->wsize) { - /* Only do this if the caller specifies to checksum bytes AND the platform requires - * it (s/390 being the primary exception to this) */ - if (INFLATE_NEED_CHECKSUM(strm) && cksum) { - /* We have to split the checksum over non-copied and copied bytes */ - if (len > state->wsize) - inf_chksum(strm, end - len, len - state->wsize); - inf_chksum_cpy(strm, state->window, end - state->wsize, state->wsize); - } else { - memcpy(state->window, end - state->wsize, state->wsize); - } - + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; - } else { + } + else { dist = state->wsize - state->wnext; - /* Only do this if the caller specifies to checksum bytes AND the platform requires - * We need to maintain the correct order here for the checksum */ - dist = MIN(dist, len); - if (INFLATE_NEED_CHECKSUM(strm) && cksum) { - inf_chksum_cpy(strm, state->window + state->wnext, end - len, dist); - } else { - memcpy(state->window + state->wnext, end - len, dist); - } - len -= dist; - if (len) { - if (INFLATE_NEED_CHECKSUM(strm) && cksum) { - inf_chksum_cpy(strm, state->window, end - len, len); - } else { - memcpy(state->window, end - len, len); - } - - state->wnext = len; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; state->whave = state->wsize; - } else { + } + else { state->wnext += dist; - if (state->wnext == state->wsize) - state->wnext = 0; - if (state->whave < state->wsize) - state->whave += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; } } + return 0; } -/* - Private macros for inflate() - Look in inflate_p.h for macros shared with inflateBack() -*/ +/* Macros for inflate(): */ -/* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ - hold += ((uint64_t)(*next++) << bits); \ + hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is @@ -473,31 +620,35 @@ static void updatewindow(PREFIX3(stream) *strm, const uint8_t *end, uint32_t len will return Z_BUF_ERROR if it has not reached the end of the stream. */ -int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { - struct inflate_state *state; - const unsigned char *next; /* next input */ - unsigned char *put; /* next output */ - unsigned char *from; /* where to copy match bytes from */ +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ - uint64_t hold; /* bit buffer */ - bits_t bits; /* bits in bit buffer */ - uint32_t in, out; /* save starting available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ - unsigned code_bits; /* bits in current/parent code */ - int32_t ret; /* return code */ - static const uint16_t order[19] = /* permutation of code lengths */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - if (inflateStateCheck(strm) || strm->next_out == NULL || - (strm->next_in == NULL && strm->avail_in != 0)) + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; - if (state->mode == TYPE) /* skip check */ - state->mode = TYPEDO; + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; @@ -513,78 +664,76 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ if (state->wbits == 0) - state->wbits = MAX_WBITS; - state->check = CRC32_INITIAL_VALUE; + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } - if (state->head != NULL) + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { - SET_BAD("incorrect header check"); + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { - SET_BAD("unknown compression method"); + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; - if (len > MAX_WBITS || len > state->wbits) { - SET_BAD("invalid window size"); + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; break; } -#ifdef INFLATE_STRICT state->dmax = 1U << len; -#endif - state->flags = 0; /* indicate zlib header */ Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = ADLER32_INITIAL_VALUE; + strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP - case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { - SET_BAD("unknown compression method"); + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; break; } if (state->flags & 0xe000) { - SET_BAD("unknown header flags set"); + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; break; } - if (state->head != NULL) + if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = TIME; - Z_FALLTHROUGH; - case TIME: NEEDBITS(32); - if (state->head != NULL) - state->head->time = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->time = hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC4(state->check, hold); INITBITS(); state->mode = OS; - Z_FALLTHROUGH; - case OS: NEEDBITS(16); - if (state->head != NULL) { + if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } @@ -592,138 +741,115 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; - Z_FALLTHROUGH; - case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); - state->length = (uint16_t)hold; - if (state->head != NULL) - state->head->extra_len = (uint16_t)hold; + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); - } else if (state->head != NULL) { - state->head->extra = NULL; } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; state->mode = EXTRA; - Z_FALLTHROUGH; - case EXTRA: if (state->flags & 0x0400) { copy = state->length; - if (copy > have) - copy = have; + if (copy > have) copy = have; if (copy) { - if (state->head != NULL && state->head->extra != NULL) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; - if (len < state->head->extra_max) { - memcpy(state->head->extra + len, next, - len + copy > state->head->extra_max ? - state->head->extra_max - len : copy); - } - } - if ((state->flags & 0x0200) && (state->wrap & 4)) { - state->check = PREFIX(crc32)(state->check, next, copy); + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } - if (state->length) - goto inf_leave; + if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; - Z_FALLTHROUGH; - case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); - if (state->head != NULL && state->head->name != NULL && state->length < state->head->name_max) - state->head->name[state->length++] = (unsigned char)len; + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) - state->check = PREFIX(crc32)(state->check, next, copy); + state->check = crc32(state->check, next, copy); have -= copy; next += copy; - if (len) - goto inf_leave; - } else if (state->head != NULL) { - state->head->name = NULL; + if (len) goto inf_leave; } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; - Z_FALLTHROUGH; - case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); - if (state->head != NULL && state->head->comment != NULL - && state->length < state->head->comm_max) - state->head->comment[state->length++] = (unsigned char)len; + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) - state->check = PREFIX(crc32)(state->check, next, copy); + state->check = crc32(state->check, next, copy); have -= copy; next += copy; - if (len) - goto inf_leave; - } else if (state->head != NULL) { - state->head->comment = NULL; + if (len) goto inf_leave; } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; state->mode = HCRC; - Z_FALLTHROUGH; - case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if ((state->wrap & 4) && hold != (state->check & 0xffff)) { - SET_BAD("header crc mismatch"); + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; break; } INITBITS(); } - if (state->head != NULL) { + if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } - /* compute crc32 checksum if not in raw mode */ - if ((state->wrap & 4) && state->flags) - strm->adler = state->check = CRC32_INITIAL_VALUE; + strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); - strm->adler = state->check = ZSWAP32((unsigned)hold); + strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; - Z_FALLTHROUGH; - case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } - strm->adler = state->check = ADLER32_INITIAL_VALUE; + strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; - Z_FALLTHROUGH; - case TYPE: - if (flush == Z_BLOCK || flush == Z_TREES) - goto inf_leave; - Z_FALLTHROUGH; - + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: - /* determine and dispatch block type */ - INFLATE_TYPEDO_HOOK(strm, flush); /* hook for IBM Z DFLTCC */ if (state->last) { BYTEBITS(); state->mode = CHECK; @@ -734,12 +860,14 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ - PREFIX(fixedtables)(state); - Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); @@ -747,44 +875,39 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { } break; case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: - SET_BAD("invalid block type"); + strm->msg = (char *)"invalid block type"; + state->mode = BAD; } DROPBITS(2); break; - case STORED: - /* get and verify stored block length */ BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - SET_BAD("invalid stored block lengths"); + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; break; } - state->length = (uint16_t)hold; - Tracev((stderr, "inflate: stored length %u\n", state->length)); + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); INITBITS(); state->mode = COPY_; - if (flush == Z_TREES) - goto inf_leave; - Z_FALLTHROUGH; - + if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; - Z_FALLTHROUGH; - case COPY: - /* copy stored block from input to output */ copy = state->length; if (copy) { - copy = MIN(copy, have); - copy = MIN(copy, left); - if (copy == 0) - goto inf_leave; - memcpy(put, next, copy); + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; @@ -795,9 +918,7 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; - case TABLE: - /* get dynamic table entries descriptor */ NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); @@ -807,66 +928,67 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { - SET_BAD("too many length or distance symbols"); + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; - Z_FALLTHROUGH; - case LENLENS: - /* get code length code lengths (not a typo) */ while (state->have < state->ncode) { NEEDBITS(3); - state->lens[order[state->have++]] = (uint16_t)BITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; - state->lencode = (const code *)(state->next); + state->lencode = (const code FAR *)(state->next); state->lenbits = 7; - ret = zng_inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); if (ret) { - SET_BAD("invalid code lengths set"); + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; - Z_FALLTHROUGH; - case CODELENS: - /* get length and distance code code lengths */ while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; - if (here.bits <= bits) break; + if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; - } else { + } + else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { - SET_BAD("invalid bit length repeat"); + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); - } else if (here.val == 17) { + } + else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); - } else { + } + else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; @@ -874,166 +996,140 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { - SET_BAD("invalid bit length repeat"); + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; break; } - while (copy) { - --copy; - state->lens[state->have++] = (uint16_t)len; - } + while (copy--) + state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ - if (state->mode == BAD) - break; + if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { - SET_BAD("invalid code -- missing end-of-block"); + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits - values here (10 and 9) without reading the comments in inftrees.h + values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; - state->lencode = (const code *)(state->next); - state->lenbits = 10; - ret = zng_inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); if (ret) { - SET_BAD("invalid literal/lengths set"); + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; break; } - state->distcode = (const code *)(state->next); - state->distbits = 9; - ret = zng_inflate_table(DISTS, state->lens + state->nlen, state->ndist, + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { - SET_BAD("invalid distances set"); + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; - if (flush == Z_TREES) - goto inf_leave; - Z_FALLTHROUGH; - + if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; - Z_FALLTHROUGH; - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= INFLATE_FAST_MIN_HAVE && left >= INFLATE_FAST_MIN_LEFT) { + if (have >= INFLATE_FAST_MIN_HAVE && + left >= INFLATE_FAST_MIN_LEFT) { RESTORE(); - FUNCTABLE_CALL(inflate_fast)(strm, out); + inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; - - /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; - if (CODE_BITS(here) <= bits) - break; + if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { - unsigned last_bits; last = here; - last_bits = CODE_BITS(last); for (;;) { - here = state->lencode[last.val + (BITS(last_bits + (last.op & 15)) >> last_bits)]; - if (last_bits + CODE_BITS(here) <= bits) - break; + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } - DROPBITS(last_bits); - state->back += last_bits; + DROPBITS(last.bits); + state->back += last.bits; } - code_bits = CODE_BITS(here); - DROPBITS(code_bits); - state->back += code_bits; - state->length = here.val; - - /* process literal */ + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; if ((int)(here.op) == 0) { - TRACE_LITERAL(here.val); + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } - - /* process end of block */ if (here.op & 32) { - TRACE_END_OF_BLOCK(); + Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } - - /* invalid code */ if (here.op & 64) { - SET_BAD("invalid literal/length code"); + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; break; } - - /* length code */ - state->extra = CODE_EXTRA(here); + state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; - Z_FALLTHROUGH; - case LENEXT: - /* get extra bits, if any */ if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } - TRACE_LENGTH(state->length); + Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; - Z_FALLTHROUGH; - case DIST: - /* get distance code */ for (;;) { here = state->distcode[BITS(state->distbits)]; - if (CODE_BITS(here) <= bits) - break; + if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { - unsigned last_bits; last = here; - last_bits = CODE_BITS(last); for (;;) { - here = state->distcode[last.val + (BITS(last_bits + (last.op & 15)) >> last_bits)]; - if (last_bits + CODE_BITS(here) <= bits) - break; + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } - DROPBITS(last_bits); - state->back += last_bits; + DROPBITS(last.bits); + state->back += last.bits; } - code_bits = CODE_BITS(here); - DROPBITS(code_bits); - state->back += code_bits; + DROPBITS(here.bits); + state->back += here.bits; if (here.op & 64) { - SET_BAD("invalid distance code"); + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; break; } - state->offset = here.val; - state->extra = CODE_EXTRA(here); + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; - Z_FALLTHROUGH; - case DISTEXT: - /* get distance extra bits, if any */ if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); @@ -1042,92 +1138,81 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { - SET_BAD("invalid distance too far back"); + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; break; } #endif - TRACE_DISTANCE(state->offset); + Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; - Z_FALLTHROUGH; - case MATCH: - /* copy match from window to output */ - if (left == 0) - goto inf_leave; + if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (state->sane) { - SET_BAD("invalid distance too far back"); + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; break; } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; - copy = MIN(copy, state->length); - copy = MIN(copy, left); + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); - if (state->length == 0) - state->mode = LEN; -#else - SET_BAD("invalid distance too far back"); -#endif + if (state->length == 0) state->mode = LEN; break; +#endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); - } else { - from = state->window + (state->wnext - copy); } - copy = MIN(copy, state->length); - copy = MIN(copy, left); - - put = chunkcopy_safe(put, from, copy, put + left); - } else { - copy = MIN(state->length, left); - - put = FUNCTABLE_CALL(chunkmemset_safe)(put, put - state->offset, copy, left); + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; left -= copy; state->length -= copy; - if (state->length == 0) - state->mode = LEN; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; break; - case LIT: - if (left == 0) - goto inf_leave; + if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; - case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; - - /* compute crc32 checksum if not in raw mode */ - if (INFLATE_NEED_CHECKSUM(strm) && state->wrap & 4) { - if (out) { - inf_chksum(strm, put - out, out); - } - } + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); out = left; if ((state->wrap & 4) && ( #ifdef GUNZIP state->flags ? hold : #endif - ZSWAP32((unsigned)hold)) != state->check) { - SET_BAD("incorrect data check"); + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; break; } INITBITS(); @@ -1135,13 +1220,12 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { } #ifdef GUNZIP state->mode = LENGTH; - Z_FALLTHROUGH; - case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); - if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { - SET_BAD("incorrect length check"); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; break; } INITBITS(); @@ -1149,20 +1233,16 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { } #endif state->mode = DONE; - Z_FALLTHROUGH; - case DONE: - /* inflate stream terminated properly */ ret = Z_STREAM_END; goto inf_leave; - case BAD: ret = Z_DATA_ERROR; goto inf_leave; - + case MEM: + return Z_MEM_ERROR; case SYNC: - - default: /* can't happen, but makes compilers happy */ + default: return Z_STREAM_ERROR; } @@ -1170,103 +1250,114 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); - uint32_t check_bytes = out - strm->avail_out; - if (INFLATE_NEED_UPDATEWINDOW(strm) && - (state->wsize || (out != strm->avail_out && state->mode < BAD && - (state->mode < CHECK || flush != Z_FINISH)))) { - /* update sliding window with respective checksum if not in "raw" mode */ - updatewindow(strm, strm->next_out, check_bytes, state->wrap & 4); - } + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; - + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) { - /* when no sliding window is used, hash the output bytes if no CHECK state */ - if (INFLATE_NEED_CHECKSUM(strm) && !state->wsize && flush == Z_FINISH) { - inf_chksum(strm, put - check_bytes, check_bytes); - } + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; - } return ret; } -int32_t Z_EXPORT PREFIX(inflateEnd)(PREFIX3(stream) *strm) { +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - - /* Free allocated buffers */ - free_inflate(strm); - + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } -int32_t Z_EXPORT PREFIX(inflateGetDictionary)(PREFIX3(stream) *strm, uint8_t *dictionary, uint32_t *dictLength) { - struct inflate_state *state; +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) +z_streamp strm; +Bytef *dictionary; +uInt *dictLength; +{ + struct inflate_state FAR *state; /* check state */ - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; - - INFLATE_GET_DICTIONARY_HOOK(strm, dictionary, dictLength); /* hook for IBM Z DFLTCC */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ - if (state->whave && dictionary != NULL) { - memcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); - memcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); } - if (dictLength != NULL) + if (dictLength != Z_NULL) *dictLength = state->whave; return Z_OK; } -int32_t Z_EXPORT PREFIX(inflateSetDictionary)(PREFIX3(stream) *strm, const uint8_t *dictionary, uint32_t dictLength) { - struct inflate_state *state; +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; unsigned long dictid; + int ret; /* check state */ - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary identifier */ if (state->mode == DICT) { - dictid = FUNCTABLE_CALL(adler32)(ADLER32_INITIAL_VALUE, dictionary, dictLength); + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; } - INFLATE_SET_DICTIONARY_HOOK(strm, dictionary, dictLength); /* hook for IBM Z DFLTCC */ - /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ - updatewindow(strm, dictionary + dictLength, dictLength, 0); - + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } -int32_t Z_EXPORT PREFIX(inflateGetHeader)(PREFIX3(stream) *strm, PREFIX(gz_headerp) head) { - struct inflate_state *state; +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; /* check state */ - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; - if ((state->wrap & 2) == 0) - return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; @@ -1285,8 +1376,13 @@ int32_t Z_EXPORT PREFIX(inflateGetHeader)(PREFIX3(stream) *strm, PREFIX(gz_heade called again with more data and the *have state. *have is initialized to zero for the first call. */ -static uint32_t syncsearch(uint32_t *have, const uint8_t *buf, uint32_t len) { - uint32_t got, next; +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +const unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; got = *have; next = 0; @@ -1303,24 +1399,23 @@ static uint32_t syncsearch(uint32_t *have, const uint8_t *buf, uint32_t len) { return next; } -int32_t Z_EXPORT PREFIX(inflateSync)(PREFIX3(stream) *strm) { - struct inflate_state *state; - size_t in, out; /* temporary to save total_in and total_out */ +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ unsigned len; /* number of bytes to look at or looked at */ - int flags; /* temporary to save header status */ + unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; /* check parameters */ - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) - return Z_BUF_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; - state->hold >>= state->bits & 7; + state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { @@ -1339,19 +1434,10 @@ int32_t Z_EXPORT PREFIX(inflateSync)(PREFIX3(stream) *strm) { strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) - return Z_DATA_ERROR; - if (state->flags == -1) - state->wrap = 0; /* if no header yet, treat as raw */ - else - state->wrap &= ~4; /* no point in computing a check value now */ - flags = state->flags; - in = strm->total_in; - out = strm->total_out; - PREFIX(inflateReset)(strm); - strm->total_in = (z_uintmax_t)in; /* Can't use z_size_t here as it will overflow on 64-bit Windows */ - strm->total_out = (z_uintmax_t)out; - state->flags = flags; + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } @@ -1364,97 +1450,114 @@ int32_t Z_EXPORT PREFIX(inflateSync)(PREFIX3(stream) *strm) { block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ -int32_t Z_EXPORT PREFIX(inflateSyncPoint)(PREFIX3(stream) *strm) { - struct inflate_state *state; +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - INFLATE_SYNC_POINT_HOOK(strm); - state = (struct inflate_state *)strm->state; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } -int32_t Z_EXPORT PREFIX(inflateCopy)(PREFIX3(stream) *dest, PREFIX3(stream) *source) { - struct inflate_state *state; - struct inflate_state *copy; +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; /* check input */ - if (inflateStateCheck(source) || dest == NULL) + if (inflateStateCheck(source) || dest == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state *)source->state; - - /* copy stream */ - memcpy(dest, source, sizeof(PREFIX3(stream))); + state = (struct inflate_state FAR *)source->state; /* allocate space */ - inflate_allocs *alloc_bufs = alloc_inflate(dest); - if (alloc_bufs == NULL) - return Z_MEM_ERROR; - copy = alloc_bufs->state; + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } /* copy state */ - memcpy(copy, state, sizeof(struct inflate_state)); + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); copy->strm = dest; - if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); - copy->window = alloc_bufs->window; - copy->alloc_bufs = alloc_bufs; - - /* window */ - memcpy(copy->window, state->window, INFLATE_ADJUST_WINDOW_SIZE((size_t)state->wsize)); - - dest->state = (struct internal_state *)copy; + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; return Z_OK; } -int32_t Z_EXPORT PREFIX(inflateUndermine)(PREFIX3(stream) *strm, int32_t subvert) { -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - struct inflate_state *state; +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR state->sane = !subvert; return Z_OK; #else - Z_UNUSED(strm); - Z_UNUSED(subvert); + (void)subvert; + state->sane = 1; return Z_DATA_ERROR; #endif } -int32_t Z_EXPORT PREFIX(inflateValidate)(PREFIX3(stream) *strm, int32_t check) { - struct inflate_state *state; +int ZEXPORT inflateValidate(strm, check) +z_streamp strm; +int check; +{ + struct inflate_state FAR *state; - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; - if (check && state->wrap) + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check) state->wrap |= 4; else state->wrap &= ~4; return Z_OK; } -long Z_EXPORT PREFIX(inflateMark)(PREFIX3(stream) *strm) { - struct inflate_state *state; +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; if (inflateStateCheck(strm)) - return -65536; - INFLATE_MARK_HOOK(strm); /* hook for IBM Z DFLTCC */ - state = (struct inflate_state *)strm->state; + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } -unsigned long Z_EXPORT PREFIX(inflateCodesUsed)(PREFIX3(stream) *strm) { - struct inflate_state *state; - if (strm == NULL || strm->state == NULL) - return (unsigned long)-1; - state = (struct inflate_state *)strm->state; +unsigned long ZEXPORT inflateCodesUsed(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; return (unsigned long)(state->next - state->codes); } diff --git a/modules/zlib/src/inflate.h b/modules/zlib/src/inflate.h index 224d688c5e..a46cce6b6d 100644 --- a/modules/zlib/src/inflate.h +++ b/modules/zlib/src/inflate.h @@ -1,5 +1,5 @@ /* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2019 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -8,17 +8,10 @@ subject to change. Applications should only use zlib.h. */ -#ifndef INFLATE_H_ -#define INFLATE_H_ - -#ifdef S390_DFLTCC_INFLATE -# include "arch/s390/dfltcc_common.h" -# define HAVE_ARCH_INFLATE_STATE -#endif - -/* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). - NO_GZIP would be used to avoid linking in the crc code when it is not needed. - For shared libraries, gzip decoding should be left enabled. */ +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif @@ -55,13 +48,14 @@ typedef enum { LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - - (most modes can go to BAD on error -- not shown for clarity) + (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) @@ -82,88 +76,50 @@ typedef enum { Process trailer: CHECK -> LENGTH -> DONE */ -typedef struct inflate_state inflate_state; - -/* Struct for memory allocation handling */ -typedef struct inflate_allocs_s { - char *buf_start; - free_func zfree; - inflate_state *state; - unsigned char *window; -} inflate_allocs; /* State maintained between inflate() calls -- approximately 7K bytes, not including the allocated sliding window, which is up to 32K bytes. */ -struct ALIGNED_(64) inflate_state { - PREFIX3(stream) *strm; /* pointer back to this zlib stream */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags, 0 if zlib, or - -1 if raw or no header yet */ - unsigned was; /* initial length of match, for inflateMark */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ - PREFIX(gz_headerp) head; /* where to save gzip header information */ - int back; /* bits back of last unprocessed length/lit */ - + gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ - uint32_t wsize; /* window size or zero if not using window */ - uint32_t wbufsize; /* real size of the allocated window buffer, including padding */ - uint32_t whave; /* valid bytes in the window */ - uint32_t wnext; /* window write index */ - unsigned char *window; /* allocated sliding window, if needed */ - + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ /* bit accumulator */ - uint64_t hold; /* input bit accumulator */ + unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ - /* fixed and dynamic code tables */ - unsigned lenbits; /* index bits for lencode */ - code const *lencode; /* starting table for length/literal codes */ - code const *distcode; /* starting table for distance codes */ - unsigned distbits; /* index bits for distcode */ /* for string and stored block copying */ - uint32_t length; /* literal or length of data to copy */ + unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ - uint32_t have; /* number of code lengths in lens[] */ - code *next; /* next available space in codes[] */ - -#ifdef ARCH_32BIT - uint32_t padding[1]; -#endif - uint8_t ALIGNED_(16) padding4[68]; - - uint16_t lens[320]; /* temporary storage for code lengths */ - uint16_t work[288]; /* work area for code table building */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ - - inflate_allocs *alloc_bufs; /* struct for handling memory allocations */ - -#ifdef INFLATE_STRICT - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ -#endif -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR int sane; /* if false, allow invalid distance too far */ -#endif -#ifdef HAVE_ARCH_INFLATE_STATE - arch_inflate_state arch; /* architecture-specific extensions */ -#endif -#ifdef ARCH_32BIT - int padding2[8]; -#endif + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ }; - -void Z_INTERNAL PREFIX(fixedtables)(struct inflate_state *state); -Z_INTERNAL inflate_allocs* alloc_inflate(PREFIX3(stream) *strm); -Z_INTERNAL void free_inflate(PREFIX3(stream) *strm); - -#endif /* INFLATE_H_ */ diff --git a/modules/zlib/src/inflate_p.h b/modules/zlib/src/inflate_p.h deleted file mode 100644 index 0d04f72bb8..0000000000 --- a/modules/zlib/src/inflate_p.h +++ /dev/null @@ -1,267 +0,0 @@ -/* inflate_p.h -- Private inline functions and macros shared with more than one deflate method - * - */ - -#ifndef INFLATE_P_H -#define INFLATE_P_H - -#include - -#include "zendian.h" -#include "zmemory.h" - -/* Architecture-specific hooks. */ -#ifdef S390_DFLTCC_INFLATE -# include "arch/s390/dfltcc_inflate.h" -/* DFLTCC instructions require window to be page-aligned */ -# define PAD_WINDOW PAD_4096 -# define WINDOW_PAD_SIZE 4096 -# define HINT_ALIGNED_WINDOW HINT_ALIGNED_4096 -#else -# define PAD_WINDOW PAD_64 -# define WINDOW_PAD_SIZE 64 -# define HINT_ALIGNED_WINDOW HINT_ALIGNED_64 -/* Adjust the window size for the arch-specific inflate code. */ -# define INFLATE_ADJUST_WINDOW_SIZE(n) (n) -/* Invoked at the end of inflateResetKeep(). Useful for initializing arch-specific extension blocks. */ -# define INFLATE_RESET_KEEP_HOOK(strm) do {} while (0) -/* Invoked at the beginning of inflatePrime(). Useful for updating arch-specific buffers. */ -# define INFLATE_PRIME_HOOK(strm, bits, value) do {} while (0) -/* Invoked at the beginning of each block. Useful for plugging arch-specific inflation code. */ -# define INFLATE_TYPEDO_HOOK(strm, flush) do {} while (0) -/* Returns whether zlib-ng should compute a checksum. Set to 0 if arch-specific inflation code already does that. */ -# define INFLATE_NEED_CHECKSUM(strm) 1 -/* Returns whether zlib-ng should update a window. Set to 0 if arch-specific inflation code already does that. */ -# define INFLATE_NEED_UPDATEWINDOW(strm) 1 -/* Invoked at the beginning of inflateMark(). Useful for updating arch-specific pointers and offsets. */ -# define INFLATE_MARK_HOOK(strm) do {} while (0) -/* Invoked at the beginning of inflateSyncPoint(). Useful for performing arch-specific state checks. */ -# define INFLATE_SYNC_POINT_HOOK(strm) do {} while (0) -/* Invoked at the beginning of inflateSetDictionary(). Useful for checking arch-specific window data. */ -# define INFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) -/* Invoked at the beginning of inflateGetDictionary(). Useful for adjusting arch-specific window data. */ -# define INFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) -#endif - -/* - * Macros shared by inflate() and inflateBack() - */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? PREFIX(crc32)(check, buf, len) : FUNCTABLE_CALL(adler32)(check, buf, len)) -#else -# define UPDATE(check, buf, len) FUNCTABLE_CALL(adler32)(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - uint16_t tmp = Z_U16_TO_LE((uint16_t)(word)); \ - check = PREFIX(crc32)(check, (const unsigned char *)&tmp, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - uint32_t tmp = Z_U32_TO_LE((uint32_t)(word)); \ - check = PREFIX(crc32)(check, (const unsigned char *)&tmp, 4); \ - } while (0) -#endif - -/* Compiler optimization for bit accumulator on x86 architectures */ -#ifdef ARCH_X86 -typedef uint8_t bits_t; -#else -typedef unsigned bits_t; -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = (bits_t)state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = (z_const unsigned char *)next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Refill to have at least 56 bits in the bit accumulator */ -#define REFILL() do { \ - hold |= load_64_bits(in, bits); \ - in += (63 ^ bits) >> 3; \ - bits |= 56; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Ensure that there is at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate()/inflateBack(). */ -#define NEEDBITS(n) \ - do { \ - unsigned u = (unsigned)(n); \ - while (bits < (bits_t)u) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - (hold & ((1U << (unsigned)(n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - unsigned u = (unsigned)(n); \ - hold >>= u; \ - bits -= (bits_t)u; \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Set mode=BAD and prepare error message */ -#define SET_BAD(errmsg) \ - do { \ - state->mode = BAD; \ - strm->msg = (char *)errmsg; \ - } while (0) - -/* Huffman code table entry format for length/distance codes (op & 16 set): - * bits = code_bits + extra_bits (combined for single-shift decode) - * op = 16 | code_bits - * val = base value - * - * For literals (op == 0): bits = code_bits, val = literal byte - */ - -/* Extract code size from a Huffman table entry */ -#define CODE_BITS(here) \ - ((unsigned)((here.op & 16) ? (here.op & 15) : here.bits)) - -/* Extract extra bits count from a length/distance code entry */ -#define CODE_EXTRA(here) \ - ((unsigned)((here.op & 16) ? (here.bits - (here.op & 15)) : 0)) - -/* Extract extra bits value from saved bit accumulator */ -#define EXTRA_BITS(old, here, op) \ - ((old & (((uint64_t)1 << here.bits) - 1)) >> (op & MAX_BITS)) - -/* Build combined op field: preserves extra if not len/dist, else combines with code_bits */ -#define COMBINE_OP(extra, code_bits) \ - ((unsigned char)((extra) & 16 ? (code_bits) | 16 : (extra))) - -/* Build combined bits field: code_bits + extra_bits from extra's low nibble */ -#define COMBINE_BITS(code_bits, extra) \ - ((unsigned char)((code_bits) + ((extra) & 15))) - -/* Trace macros for debugging */ -#define TRACE_LITERAL(val) \ - Tracevv((stderr, val >= 0x20 && val < 0x7f ? \ - "inflate: literal '%c'\n" : \ - "inflate: literal 0x%02x\n", val)) - -#define TRACE_LENGTH(len) \ - Tracevv((stderr, "inflate: length %u\n", len)) - -#define TRACE_DISTANCE(dist) \ - Tracevv((stderr, "inflate: distance %u\n", dist)) - -#define TRACE_END_OF_BLOCK() \ - Tracevv((stderr, "inflate: end of block\n")) - -#define INFLATE_FAST_MIN_HAVE 15 -#define INFLATE_FAST_MIN_LEFT 260 - -/* Load 64 bits from IN and place the bytes at offset BITS in the result. */ -static inline uint64_t load_64_bits(const unsigned char *in, unsigned bits) { - uint64_t chunk = zng_memread_8(in); - return Z_U64_FROM_LE(chunk) << bits; -} - -/* Behave like chunkcopy, but avoid writing beyond of legal output. */ -static inline uint8_t* chunkcopy_safe(uint8_t *out, uint8_t *from, size_t len, uint8_t *safe) { - size_t safelen = safe - out; - len = MIN(len, safelen); - int32_t olap_src = from >= out && from < out + len; - int32_t olap_dst = out >= from && out < from + len; - size_t tocopy; - - /* For all cases without overlap, memcpy is ideal */ - if (!(olap_src || olap_dst)) { - memcpy(out, from, len); - return out + len; - } - - /* Complete overlap: Source == destination */ - if (out == from) { - return out + len; - } - - /* We are emulating a self-modifying copy loop here. To do this in a way that doesn't produce undefined behavior, - * we have to get a bit clever. First if the overlap is such that src falls between dst and dst+len, we can do the - * initial bulk memcpy of the nonoverlapping region. Then, we can leverage the size of this to determine the safest - * atomic memcpy size we can pick such that we have non-overlapping regions. This effectively becomes a safe look - * behind or lookahead distance. */ - size_t non_olap_size = (size_t)ABS(from - out); - - /* So this doesn't give use a worst case scenario of function calls in a loop, - * we want to instead break this down into copy blocks of fixed lengths - * - * TODO: The memcpy calls aren't inlined on architectures with strict memory alignment - */ - while (len) { - tocopy = MIN(non_olap_size, len); - len -= tocopy; - - while (tocopy >= 16) { - memcpy(out, from, 16); - out += 16; - from += 16; - tocopy -= 16; - } - - if (tocopy >= 8) { - memcpy(out, from, 8); - out += 8; - from += 8; - tocopy -= 8; - } - - if (tocopy >= 4) { - memcpy(out, from, 4); - out += 4; - from += 4; - tocopy -= 4; - } - - while (tocopy--) { - *out++ = *from++; - } - } - - return out; -} - -#endif diff --git a/modules/zlib/src/inflate_simd.c b/modules/zlib/src/inflate_simd.c new file mode 100644 index 0000000000..490688974c --- /dev/null +++ b/modules/zlib/src/inflate_simd.c @@ -0,0 +1,1583 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast_chunk.h" +#include "chunkcopy.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local int inflateStateCheck OF((z_streamp strm)); +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); + +local int inflateStateCheck(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int ZEXPORT inflateResetKeep(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->strm = strm; + state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + state->check = 1L; /* 1L is the result of adler32() zero length data */ + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, end, copy) +z_streamp strm; +const Bytef *end; +unsigned copy; +{ + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + unsigned wsize = 1U << state->wbits; + state->window = (unsigned char FAR *) + ZALLOC(strm, wsize + CHUNKCOPY_CHUNK_SIZE, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; +#ifdef INFLATE_CLEAR_UNUSED_UNDEFINED + /* Copies from the overflow portion of this buffer are undefined and + may cause analysis tools to raise a warning if we don't initialize + it. However, this undefined data overwrites other undefined data + and is subsequently either overwritten or left deliberately + undefined at the end of decode; so there's really no point. + */ + zmemzero(state->window + wsize, CHUNKCOPY_CHUNK_SIZE); +#endif + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + case COPY_: + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + case LEN_: + state->mode = LEN; + case LEN: + if (have >= INFLATE_FAST_MIN_INPUT && + left >= INFLATE_FAST_MIN_OUTPUT) { + RESTORE(); + inflate_fast_chunk_(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + put = chunkcopy_safe(put, from, copy, put + left); + } + else { /* copy from output */ + copy = state->length; + if (copy > left) copy = left; + put = chunkcopy_lapped_safe(put, state->offset, copy, put + left); + } + left -= copy; + state->length -= copy; + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + /* We write a defined value in the unused space to help mark + * where the stream has ended. We don't use zeros as that can + * mislead clients relying on undefined behavior (i.e. assuming + * that the data is over when the buffer has a zero/null value). + */ + if (left >= CHUNKCOPY_CHUNK_SIZE) + memset(put, 0x55, CHUNKCOPY_CHUNK_SIZE); + else + memset(put, 0x55, left); + + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) +z_streamp strm; +Bytef *dictionary; +uInt *dictLength; +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +const unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +int ZEXPORT inflateValidate(strm, check) +z_streamp strm; +int check; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/modules/zlib/src/inftrees.c b/modules/zlib/src/inftrees.c index d65e6a9ce5..2ea08fc13e 100644 --- a/modules/zlib/src/inftrees.c +++ b/modules/zlib/src/inftrees.c @@ -1,23 +1,15 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2024 Mark Adler + * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" #include "zutil.h" #include "inftrees.h" -#include "inflate_p.h" -#include "fallback_builtins.h" -#if defined(__SSE2__) -# include "arch/x86/x86_intrins.h" -#elif defined(__ARM_NEON) || defined(__ARM_NEON__) -# include "arch/arm/neon_intrins.h" -#elif defined(__ALTIVEC__) -# include "arch/power/power_intrins.h" -#endif +#define MAXBITS 15 -const char PREFIX(inflate_copyright)[] = " inflate 1.3.1 Copyright 1995-2024 Mark Adler "; +const char inflate_copyright[] = + " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -25,110 +17,6 @@ const char PREFIX(inflate_copyright)[] = " inflate 1.3.1 Copyright 1995-2024 Mar copyright string in the executable of your product. */ -/* Count number of codes for each code length. */ -static inline void count_lengths(uint16_t *lens, int codes, uint16_t *count) { - /* IBM...made some weird choices for VSX/VMX. Basically vec_ld has an inherent - * endianness but we don't want to force VSX to be needed */ - static const ALIGNED_(16) uint8_t one[256] = { - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 - }; - -#if defined(__ALTIVEC__) - vector unsigned char s1 = vec_splat_u8(0); - vector unsigned char s2 = vec_splat_u8(0); - - if (codes & 1) { - s1 = vec_ld(16 * lens[0], one); - --codes; - ++lens; - } - - while (codes) { - s1 = vec_add(s1, vec_ld(16 * lens[0], one)); - s2 = vec_add(s2, vec_ld(16 * lens[1], one)); - codes -= 2; - lens += 2; - } - - vector unsigned short sum_lo = vec_add(vec_unpackh(s1), vec_unpackh(s2)); - vector unsigned short sum_hi = vec_add(vec_unpackl(s1), vec_unpackl(s2)); - - vec_st(sum_lo, 0, &count[0]); - vec_st(sum_hi, 0, &count[8]); - -#elif defined(__ARM_NEON) || defined(__ARM_NEON__) - int sym; - uint8x16_t s1 = vdupq_n_u8(0); - uint8x16_t s2 = vdupq_n_u8(0); - - if (codes & 1) { - s1 = vld1q_u8(&one[16 * lens[0]]); - } - for (sym = codes & 1; sym < codes; sym += 2) { - s1 = vaddq_u8(s1, vld1q_u8(&one[16 * lens[sym]])); - s2 = vaddq_u8(s2, vld1q_u8(&one[16 * lens[sym+1]])); - } - - vst1q_u16(&count[0], vaddl_u8(vget_low_u8(s1), vget_low_u8(s2))); - vst1q_u16(&count[8], vaddl_u8(vget_high_u8(s1), vget_high_u8(s2))); - -#elif defined(__SSE2__) - int sym; - __m128i s1 = _mm_setzero_si128(); - __m128i s2 = _mm_setzero_si128(); - - if (codes & 1) { - s1 = _mm_load_si128((const __m128i*)&one[16 * lens[0]]); - } - for (sym = codes & 1; sym < codes; sym += 2) { - s1 = _mm_add_epi8(s1, _mm_load_si128((const __m128i*)&one[16 * lens[sym]])); // vaddq_u8 - s2 = _mm_add_epi8(s2, _mm_load_si128((const __m128i*)&one[16 * lens[sym+1]])); - } - -# if defined(__AVX2__) - __m256i w1 = _mm256_cvtepu8_epi16(s1); - __m256i w2 = _mm256_cvtepu8_epi16(s2); - __m256i sum = _mm256_add_epi16(w1, w2); - - _mm256_storeu_si256((__m256i*)&count[0], sum); -# else - __m128i zero = _mm_setzero_si128(); - - __m128i s1_lo = _mm_unpacklo_epi8(s1, zero); - __m128i s2_lo = _mm_unpacklo_epi8(s2, zero); - __m128i sum_lo = _mm_add_epi16(s1_lo, s2_lo); - _mm_storeu_si128((__m128i*)&count[0], sum_lo); - - __m128i s1_hi = _mm_unpackhi_epi8(s1, zero); - __m128i s2_hi = _mm_unpackhi_epi8(s2, zero); - __m128i sum_hi = _mm_add_epi16(s1_hi, s2_hi); - _mm_storeu_si128((__m128i*)&count[8], sum_hi); -# endif -#else - int len, sym; - for (len = 0; len <= MAX_BITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - Z_UNUSED(one); -#endif -} - /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, @@ -141,8 +29,14 @@ static inline void count_lengths(uint16_t *lens, int codes, uint16_t *count) { table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ -int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, - code * *table, unsigned *bits, uint16_t *work) { +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ @@ -151,30 +45,29 @@ int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ - uint16_t rhuff; /* Reversed huffman code */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ - code *next; /* next available space in table */ - const uint16_t *base; /* base value table to use */ - const uint16_t *extra; /* extra bits table to use */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ unsigned match; /* use base and extra for symbol >= match */ - uint16_t ALIGNED_(16) count[MAX_BITS+1]; /* number of codes of each length */ - uint16_t offs[MAX_BITS+1]; /* offsets in table for each length */ - static const uint16_t lbase[31] = { /* Length codes 257..285 base */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const uint16_t lext[31] = { /* Length codes 257..285 extra */ + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77}; - static const uint16_t dbase[32] = { /* Distance codes 0..29 base */ + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; - static const uint16_t dext[32] = { /* Distance codes 0..29 extra */ + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; @@ -211,17 +104,20 @@ int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - count_lengths(lens, codes, count); + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; - for (max = MAX_BITS; max >= 1; max--) + for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; - root = MIN(root, max); - if (UNLIKELY(max == 0)) { /* no symbols to code at all */ + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; - here.val = (uint16_t)0; + here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; @@ -229,11 +125,11 @@ int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, } for (min = 1; min < max; min++) if (count[min] != 0) break; - root = MAX(root, min); + if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; - for (len = 1; len <= MAX_BITS; len++) { + for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ @@ -243,12 +139,12 @@ int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; - for (len = 1; len < MAX_BITS; len++) + for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (uint16_t)sym; + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being @@ -299,7 +195,6 @@ int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, } /* initialize state for loop */ - rhuff = 0; /* starting code, reversed */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ @@ -319,15 +214,15 @@ int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); - if (LIKELY(work[sym] >= match)) { - unsigned op = extra[work[sym] - match]; - here.op = COMBINE_OP(op, here.bits); - here.bits = COMBINE_BITS(here.bits, op); - here.val = base[work[sym] - match]; - } else if (work[sym] + 1U < match) { + if (work[sym] + 1U < match) { here.op = (unsigned char)0; here.val = work[sym]; - } else { + } + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } @@ -342,14 +237,20 @@ int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, } while (fill != 0); /* backwards increment the len-bit code huff */ - rhuff = (uint16_t)(rhuff + (0x8000u >> (len - 1))); - huff = zng_bitreverse16(rhuff); + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { - if (len == max) - break; + if (len == max) break; len = lens[work[sym]]; } @@ -367,32 +268,32 @@ int Z_INTERNAL zng_inflate_table(codetype type, uint16_t *lens, unsigned codes, left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; - if (left <= 0) - break; + if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; - if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (uint16_t)(next - *table); + (*table)[low].val = (unsigned short)(next - *table); } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ - if (UNLIKELY(huff != 0)) { + if (huff != 0) { here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); - here.val = (uint16_t)0; + here.val = (unsigned short)0; next[huff] = here; } diff --git a/modules/zlib/src/inftrees.h b/modules/zlib/src/inftrees.h index 6e38c45b26..baa53a0b1a 100644 --- a/modules/zlib/src/inftrees.h +++ b/modules/zlib/src/inftrees.h @@ -1,8 +1,5 @@ -#ifndef INFTREES_H_ -#define INFTREES_H_ - /* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2022 Mark Adler + * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -25,31 +22,31 @@ of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { - unsigned char bits; /* bits in this part of the code */ - unsigned char op; /* operation, extra bits, table bits */ - uint16_t val; /* offset in table or code value */ + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of non-extra bits + 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is - 1924, which is the sum of 1332 for literal/length codes and 592 for distance + 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distributions. The arguments to that + examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the - maximum bit length of a code. "enough 286 10 15" for literal/length codes - returns 1332, and "enough 30 9 15" for distance codes returns 592. - The initial root table size (10 or 9) is found in the fifth argument of the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ -#define ENOUGH_LENS 1332 +#define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) @@ -60,7 +57,6 @@ typedef enum { DISTS } codetype; -int Z_INTERNAL zng_inflate_table (codetype type, uint16_t *lens, unsigned codes, - code * *table, unsigned *bits, uint16_t *work); - -#endif /* INFTREES_H_ */ +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/modules/zlib/src/insert_string.c b/modules/zlib/src/insert_string.c deleted file mode 100644 index dd1960fbe6..0000000000 --- a/modules/zlib/src/insert_string.c +++ /dev/null @@ -1,18 +0,0 @@ -/* insert_string.c -- make insert_string functions from static inlined functions - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - */ - -#include "zbuild.h" -#include "deflate.h" -#include "insert_string_p.h" - -void insert_string(deflate_state *const s, uint32_t str, uint32_t count) { - insert_string_static(s, str, count); -} - -void insert_string_roll(deflate_state *const s, uint32_t str, uint32_t count) { - insert_string_roll_static(s, str, count); -} diff --git a/modules/zlib/src/insert_string_p.h b/modules/zlib/src/insert_string_p.h deleted file mode 100644 index e768b3eab1..0000000000 --- a/modules/zlib/src/insert_string_p.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef INSERT_STRING_P_H_ -#define INSERT_STRING_P_H_ - -/* insert_string_p.h -- insert_string function generator - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - */ - -// Normal insert_string, levels 1-8 -#define HASH_SLIDE 16 - -#define HASH_CALC(h, val) h = ((val * 2654435761U) >> HASH_SLIDE); -#define HASH_CALC_MASK HASH_MASK -#define HASH_CALC_VAR h -#define HASH_CALC_VAR_INIT uint32_t h -#define HASH_CALC_OFFSET 0 - -#define UPDATE_HASH update_hash -#define INSERT_STRING insert_string_static -#define QUICK_INSERT_STRING quick_insert_string -#define QUICK_INSERT_VALUE quick_insert_value - -#include "insert_string_tpl.h" - -// Rolling insert_string, level 9 -#define HASH_SLIDE 5 - -#define HASH_CALC(h, val) h = ((h << HASH_SLIDE) ^ ((uint8_t)val)) -#define HASH_CALC_VAR s->ins_h -#define HASH_CALC_VAR_INIT -#define HASH_CALC_READ val = strstart[0] -#define HASH_CALC_MASK (32768u - 1u) -#define HASH_CALC_OFFSET (STD_MIN_MATCH-1) - -#define UPDATE_HASH update_hash_roll -#define INSERT_STRING insert_string_roll_static -#define QUICK_INSERT_STRING quick_insert_string_roll -#define QUICK_INSERT_VALUE quick_insert_value_roll - -#include "insert_string_tpl.h" - -#endif diff --git a/modules/zlib/src/insert_string_tpl.h b/modules/zlib/src/insert_string_tpl.h deleted file mode 100644 index f8318e4e00..0000000000 --- a/modules/zlib/src/insert_string_tpl.h +++ /dev/null @@ -1,126 +0,0 @@ -/* insert_string_tpl.h -- Private insert_string functions shared with more than - * one insert string implementation - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * Authors: - * Wajdi Feghali - * Jim Guilford - * Vinodh Gopal - * Erdinc Ozturk - * Jim Kukunas - * - * Portions are Copyright (C) 2016 12Sided Technology, LLC. - * Author: - * Phil Vachon - * - * For conditions of distribution and use, see copyright notice in zlib.h - * - */ - -#ifndef HASH_CALC_READ -# define HASH_CALC_READ val = Z_U32_FROM_LE(zng_memread_4(strstart)); -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -Z_FORCEINLINE static uint32_t UPDATE_HASH(uint32_t h, uint32_t val) { - HASH_CALC(h, val); - return h & HASH_CALC_MASK; -} - -/* =========================================================================== - * Quick insert string str in the dictionary using a pre-read value and set match_head - * to the previous head of the hash chain (the most recent string with same hash key). - * Return the previous length of the hash chain. - */ -Z_FORCEINLINE static uint32_t QUICK_INSERT_VALUE(deflate_state *const s, uint32_t str, uint32_t val) { - uint32_t hm, head; - - HASH_CALC_VAR_INIT; - HASH_CALC(HASH_CALC_VAR, val); - HASH_CALC_VAR &= HASH_CALC_MASK; - hm = HASH_CALC_VAR; - - head = s->head[hm]; - if (LIKELY(head != str)) { - s->prev[str & W_MASK(s)] = (Pos)head; - s->head[hm] = (Pos)str; - } - return head; -} - -/* =========================================================================== - * Quick insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - */ -Z_FORCEINLINE static uint32_t QUICK_INSERT_STRING(deflate_state *const s, uint32_t str) { - uint8_t *strstart = s->window + str + HASH_CALC_OFFSET; - uint32_t val, hm, head; - - HASH_CALC_VAR_INIT; - HASH_CALC_READ; - HASH_CALC(HASH_CALC_VAR, val); - HASH_CALC_VAR &= HASH_CALC_MASK; - hm = HASH_CALC_VAR; - - head = s->head[hm]; - if (LIKELY(head != str)) { - s->prev[str & W_MASK(s)] = (Pos)head; - s->head[hm] = (Pos)str; - } - return head; -} - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * IN assertion: all calls to INSERT_STRING are made with consecutive - * input characters and the first STD_MIN_MATCH bytes of str are valid - * (except for the last STD_MIN_MATCH-1 bytes of the input file). - */ -Z_FORCEINLINE static void INSERT_STRING(deflate_state *const s, uint32_t str, uint32_t count) { - uint8_t *strstart = s->window + str + HASH_CALC_OFFSET; - uint8_t *strend = strstart + count; - - /* Local pointers to avoid indirection */ - Pos *headp = s->head; - Pos *prevp = s->prev; - const unsigned int w_mask = W_MASK(s); - - for (uint32_t idx = str; strstart < strend; idx++, strstart++) { - uint32_t val, hm, head; - - HASH_CALC_VAR_INIT; - HASH_CALC_READ; - HASH_CALC(HASH_CALC_VAR, val); - HASH_CALC_VAR &= HASH_CALC_MASK; - hm = HASH_CALC_VAR; - - head = headp[hm]; - if (LIKELY(head != idx)) { - prevp[idx & w_mask] = (Pos)head; - headp[hm] = (Pos)idx; - } - } -} - -// Cleanup -#undef HASH_SLIDE -#undef HASH_CALC -#undef HASH_CALC_READ -#undef HASH_CALC_MASK -#undef HASH_CALC_OFFSET -#undef HASH_CALC_VAR -#undef HASH_CALC_VAR_INIT -#undef UPDATE_HASH -#undef INSERT_STRING -#undef QUICK_INSERT_STRING -#undef QUICK_INSERT_VALUE diff --git a/modules/zlib/src/match_tpl.h b/modules/zlib/src/match_tpl.h deleted file mode 100644 index df9230df85..0000000000 --- a/modules/zlib/src/match_tpl.h +++ /dev/null @@ -1,253 +0,0 @@ -/* match_tpl.h -- find longest match template for compare256 variants - * - * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Portions copyright (C) 2014-2021 Konstantin Nosov - * Fast-zlib optimized longest_match - * https://github.com/gildor2/fast_zlib - */ - -#include "insert_string_p.h" - -#define EARLY_EXIT_TRIGGER_LEVEL 5 - -#define GOTO_NEXT_CHAIN \ - if (--chain_length && (cur_match = prev[cur_match & wmask]) > limit) \ - continue; \ - return best_len; - -/* Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is garbage. - * - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >=1 - * OUT assertion: the match length is not greater than s->lookahead - */ -Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) { - const unsigned wmask = W_MASK(s); - unsigned int strstart = s->strstart; - const unsigned char *window = s->window; - const Pos *prev = s->prev; -#ifdef LONGEST_MATCH_ROLL - const Pos *head = s->head; -#endif - const unsigned char *scan; - const unsigned char *mbase_start = window; - const unsigned char *mbase_end; - uint32_t limit; -#ifdef LONGEST_MATCH_ROLL - uint32_t limit_base; -#else - int32_t early_exit; -#endif - uint32_t chain_length = s->max_chain_length; - uint32_t nice_match = (uint32_t)s->nice_match; - uint32_t best_len, offset; - uint32_t lookahead = s->lookahead; - uint32_t match_offset = 0; - uint64_t scan_start; - uint64_t scan_end; - - /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */ - Assert(STD_MAX_MATCH == 258, "Code too clever"); - - scan = window + strstart; - best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1; - - /* Calculate read offset which should only extend an extra byte - * to find the next best match length. - */ - offset = best_len-1; - if (best_len >= sizeof(uint32_t)) { - offset -= 2; - if (best_len >= sizeof(uint64_t)) - offset -= 4; - } - - scan_start = zng_memread_8(scan); - scan_end = zng_memread_8(scan+offset); - mbase_end = (mbase_start+offset); - - /* Do not waste too much time if we already have a good match */ - if (best_len >= s->good_match) - chain_length >>= 2; - - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0 - */ - limit = strstart > MAX_DIST(s) ? (strstart - MAX_DIST(s)) : 0; -#ifdef LONGEST_MATCH_ROLL - limit_base = limit; - if (best_len >= STD_MIN_MATCH) { - /* We're continuing search (lazy evaluation). */ - uint32_t hash; - uint32_t pos; - - /* Find a most distant chain starting from scan with index=1 (index=0 corresponds - * to cur_match). We cannot use s->prev[strstart+1,...] immediately, because - * these strings are not yet inserted into the hash table. - */ - // use update_hash_roll for deflate_slow - hash = update_hash_roll(0, scan[1]); - hash = update_hash_roll(hash, scan[2]); - - for (uint32_t i = 3; i <= best_len; i++) { - // use update_hash_roll for deflate_slow - hash = update_hash_roll(hash, scan[i]); - /* If we're starting with best_len >= 3, we can use offset search. */ - pos = head[hash]; - if (pos < cur_match) { - match_offset = i - 2; - cur_match = pos; - } - } - - /* Update offset-dependent variables */ - limit = limit_base+match_offset; - if (cur_match <= limit) - goto break_matching; - mbase_start -= match_offset; - mbase_end -= match_offset; - } -#else - early_exit = s->level < EARLY_EXIT_TRIGGER_LEVEL; -#endif - Assert((unsigned long)strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead"); - for (;;) { - if (cur_match >= strstart) - break; - - /* Skip to next match if the match length cannot increase or if the match length is - * less than 2. Note that the checks below for insufficient lookahead only occur - * occasionally for performance reasons. - * Therefore uninitialized memory will be accessed and conditional jumps will be made - * that depend on those values. However the length of the match is limited to the - * lookahead, so the output of deflate is not affected by the uninitialized values. - */ - if (best_len < sizeof(uint32_t)) { - for (;;) { - if (zng_memcmp_2(mbase_end+cur_match, &scan_end) == 0 && - zng_memcmp_2(mbase_start+cur_match, &scan_start) == 0) - break; - GOTO_NEXT_CHAIN; - } - } else if (best_len >= sizeof(uint64_t)) { - for (;;) { - if (zng_memcmp_8(mbase_end+cur_match, &scan_end) == 0 && - zng_memcmp_8(mbase_start+cur_match, &scan_start) == 0) - break; - GOTO_NEXT_CHAIN; - } - } else { - for (;;) { - if (zng_memcmp_4(mbase_end+cur_match, &scan_end) == 0 && - zng_memcmp_4(mbase_start+cur_match, &scan_start) == 0) - break; - GOTO_NEXT_CHAIN; - } - } - uint32_t len = COMPARE256(scan+2, mbase_start+cur_match+2) + 2; - Assert(scan+len <= window+(unsigned)(s->window_size-1), "wild scan"); - - if (len > best_len) { - uint32_t match_start = cur_match - match_offset; - s->match_start = match_start; - - /* Do not look for better matches if the current match reaches - * or exceeds the end of the input. - */ - if (len >= lookahead) - return lookahead; - if (len >= nice_match) - return len; - - best_len = len; - - offset = best_len-1; - if (best_len >= sizeof(uint32_t)) { - offset -= 2; - if (best_len >= sizeof(uint64_t)) - offset -= 4; - } - - scan_end = zng_memread_8(scan+offset); - -#ifdef LONGEST_MATCH_ROLL - /* Look for a better string offset */ - if (UNLIKELY(len > STD_MIN_MATCH && match_start + len < strstart)) { - const unsigned char *scan_endstr; - uint32_t hash; - uint32_t pos, next_pos; - - /* Go back to offset 0 */ - cur_match -= match_offset; - match_offset = 0; - next_pos = cur_match; - for (uint32_t i = 0; i <= len - STD_MIN_MATCH; i++) { - pos = prev[(cur_match + i) & wmask]; - if (pos < next_pos) { - /* Hash chain is more distant, use it */ - if (pos <= limit_base + i) - goto break_matching; - next_pos = pos; - match_offset = i; - } - } - /* Switch cur_match to next_pos chain */ - cur_match = next_pos; - - /* Try hash head at len-(STD_MIN_MATCH-1) position to see if we could get - * a better cur_match at the end of string. Using (STD_MIN_MATCH-1) lets - * us include one more byte into hash - the byte which will be checked - * in main loop now, and which allows to grow match by 1. - */ - scan_endstr = scan + len - (STD_MIN_MATCH+1); - - // use update_hash_roll for deflate_slow - hash = update_hash_roll(0, scan_endstr[0]); - hash = update_hash_roll(hash, scan_endstr[1]); - hash = update_hash_roll(hash, scan_endstr[2]); - - pos = head[hash]; - if (pos < cur_match) { - match_offset = len - (STD_MIN_MATCH+1); - if (pos <= limit_base + match_offset) - goto break_matching; - cur_match = pos; - } - - /* Update offset-dependent variables */ - limit = limit_base+match_offset; - mbase_start = window-match_offset; - mbase_end = (mbase_start+offset); - continue; - } -#endif - mbase_end = (mbase_start+offset); - } -#ifndef LONGEST_MATCH_ROLL - else if (UNLIKELY(early_exit)) { - /* The probability of finding a match later if we here is pretty low, so for - * performance it's best to outright stop here for the lower compression levels - */ - break; - } -#endif - GOTO_NEXT_CHAIN; - } - return best_len; - -#ifdef LONGEST_MATCH_ROLL -break_matching: - - if (best_len < lookahead) - return best_len; - - return lookahead; -#endif -} - -#undef LONGEST_MATCH_ROLL -#undef LONGEST_MATCH diff --git a/modules/zlib/src/moz.build b/modules/zlib/src/moz.build index 99035b889a..df181cb0d4 100644 --- a/modules/zlib/src/moz.build +++ b/modules/zlib/src/moz.build @@ -7,98 +7,60 @@ EXPORTS += [ 'mozzconf.h', 'zconf.h', 'zlib.h', - 'zlib_name_mangling.h', ] -DEFINES['ZLIB_COMPAT'] = True -DEFINES['WITH_GZFILEOP'] = True -DEFINES['WITH_OPTIM'] = True -DEFINES['WITH_NEW_STRATEGIES'] = True +if CONFIG['CPU_ARCH'] == 'arm': + DEFINES['ADLER32_SIMD_NEON'] = True + DEFINES['INFLATE_CHUNK_SIMD_NEON'] = True + SOURCES += [ + 'adler32_simd.c', + 'inffast_chunk.c', + 'inflate_simd.c', + ] -# Keep the integration simple and portable across this tree's mixed toolchains: -# use zlib-ng generic fallbacks and disable runtime CPU dispatch here. -DEFINES['DISABLE_RUNTIME_CPU_DETECTION'] = True -DEFINES['WITH_ALL_FALLBACKS'] = True +if CONFIG['INTEL_ARCHITECTURE']: + DEFINES['ADLER32_SIMD_SSSE3'] = True + DEFINES['INFLATE_CHUNK_SIMD_SSE2'] = True + DEFINES['CRC32_SIMD_SSE42_PCLMUL'] = True + SOURCES += [ + 'adler32_simd.c', + 'crc32_simd.c', + 'crc_folding.c', + 'fill_window_sse.c', + 'inffast_chunk.c', + 'inflate_simd.c', + 'x86.c', + ] +else: + SOURCES += [ + 'simd_stub.c', + ] + +if CONFIG['CPU_ARCH'] != 'arm' and not CONFIG['INTEL_ARCHITECTURE']: + SOURCES += [ + 'inflate.c', + ] if CONFIG['ZLIB_IN_MOZGLUE']: FINAL_LIBRARY = 'mozglue' DEFINES['IMPL_MFBT'] = True else: + # The final library is in config/external/zlib FINAL_LIBRARY = 'zlib' SOURCES += [ 'adler32.c', - 'arch/generic/adler32_c.c', - 'arch/generic/chunkset_c.c', - 'arch/generic/compare256_c.c', - 'arch/generic/crc32_braid_c.c', - 'arch/generic/crc32_chorba_c.c', - 'arch/generic/slide_hash_c.c', 'compress.c', 'crc32.c', - 'crc32_braid_comb.c', 'deflate.c', - 'deflate_fast.c', - 'deflate_huff.c', - 'deflate_medium.c', - 'deflate_quick.c', - 'deflate_rle.c', - 'deflate_slow.c', - 'deflate_stored.c', + 'gzclose.c', 'gzlib.c', 'gzread.c', 'gzwrite.c', 'infback.c', - 'inflate.c', + 'inffast.c', 'inftrees.c', - 'insert_string.c', 'trees.c', 'uncompr.c', 'zutil.c', ] - -if CONFIG['CPU_ARCH'].startswith('x86'): - DEFINES['X86_AVX2'] = True - DEFINES['X86_FEATURES'] = True - DEFINES['X86_PCLMULQDQ_CRC'] = True - DEFINES['X86_SSE2'] = True - DEFINES['X86_SSE41'] = True - DEFINES['X86_SSE42'] = True - DEFINES['X86_SSSE3'] = True - - SOURCES += [ - 'arch/x86/adler32_avx2.c', - 'arch/x86/adler32_sse42.c', - 'arch/x86/adler32_ssse3.c', - 'arch/x86/chunkset_avx2.c', - 'arch/x86/chunkset_sse2.c', - 'arch/x86/chunkset_ssse3.c', - 'arch/x86/compare256_avx2.c', - 'arch/x86/compare256_sse2.c', - 'arch/x86/crc32_chorba_sse2.c', - 'arch/x86/crc32_chorba_sse41.c', - 'arch/x86/crc32_pclmulqdq.c', - 'arch/x86/slide_hash_avx2.c', - 'arch/x86/slide_hash_sse2.c', - ] - - if CONFIG['GNU_CC']: - SOURCES['arch/x86/adler32_avx2.c'].flags += ['-mavx2', '-mbmi2'] - SOURCES['arch/x86/adler32_sse42.c'].flags += ['-msse4.2'] - SOURCES['arch/x86/adler32_ssse3.c'].flags += ['-mssse3'] - SOURCES['arch/x86/chunkset_avx2.c'].flags += ['-mavx2', '-mbmi2'] - SOURCES['arch/x86/chunkset_sse2.c'].flags += ['-msse2'] - SOURCES['arch/x86/chunkset_ssse3.c'].flags += ['-mssse3'] - SOURCES['arch/x86/compare256_avx2.c'].flags += ['-mavx2', '-mbmi2'] - SOURCES['arch/x86/compare256_sse2.c'].flags += ['-msse2'] - SOURCES['arch/x86/crc32_chorba_sse2.c'].flags += ['-msse2'] - SOURCES['arch/x86/crc32_chorba_sse41.c'].flags += ['-msse4.1'] - SOURCES['arch/x86/crc32_pclmulqdq.c'].flags += ['-msse4.2', '-mpclmul'] - SOURCES['arch/x86/slide_hash_avx2.c'].flags += ['-mavx2', '-mbmi2'] - SOURCES['arch/x86/slide_hash_sse2.c'].flags += ['-msse2'] - elif CONFIG['_MSC_VER']: - SOURCES['arch/x86/adler32_avx2.c'].flags += ['/arch:AVX2'] - SOURCES['arch/x86/chunkset_avx2.c'].flags += ['/arch:AVX2'] - SOURCES['arch/x86/compare256_avx2.c'].flags += ['/arch:AVX2'] - SOURCES['arch/x86/crc32_pclmulqdq.c'].flags += ['/arch:AVX2'] - SOURCES['arch/x86/slide_hash_avx2.c'].flags += ['/arch:AVX2'] \ No newline at end of file diff --git a/modules/zlib/src/simd_stub.c b/modules/zlib/src/simd_stub.c new file mode 100644 index 0000000000..c6d4605149 --- /dev/null +++ b/modules/zlib/src/simd_stub.c @@ -0,0 +1,35 @@ +/* simd_stub.c -- stub implementations +* Copyright (C) 2014 Intel Corporation +* For conditions of distribution and use, see copyright notice in zlib.h +*/ +#include + +#include "deflate.h" +#include "x86.h" + +int ZLIB_INTERNAL x86_cpu_enable_simd = 0; + +void ZLIB_INTERNAL crc_fold_init(deflate_state *const s) { + assert(0); +} + +void ZLIB_INTERNAL crc_fold_copy(deflate_state *const s, + unsigned char *dst, + const unsigned char *src, + long len) { + assert(0); +} + +unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state *const s) { + assert(0); + return 0; +} + +void ZLIB_INTERNAL fill_window_sse(deflate_state *s) +{ + assert(0); +} + +void x86_check_features(void) +{ +} diff --git a/modules/zlib/src/trees.c b/modules/zlib/src/trees.c index a12ed385c2..5f89d056ef 100644 --- a/modules/zlib/src/trees.c +++ b/modules/zlib/src/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2024 Jean-loup Gailly + * Copyright (C) 1995-2017 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -30,13 +30,46 @@ * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ -#include "zbuild.h" -#include "deflate.h" -#include "deflate_p.h" -#include "trees.h" -#include "trees_emit.h" -#include "trees_tbl.h" +/* @(#) $Id$ */ +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef ZLIB_DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ @@ -45,42 +78,309 @@ * Local data. These are initialized only once. */ +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const int *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - unsigned int max_length; /* max bit length for the codes */ + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ }; -static const static_tree_desc static_l_desc = +local const static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; -static const static_tree_desc static_d_desc = +local const static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; -static const static_tree_desc static_bl_desc = +local const static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ -static void init_block (deflate_state *s); -static inline void pqdownheap (unsigned char *depth, int *heap, const int heap_len, ct_data *tree, int k); -static void build_tree (deflate_state *s, tree_desc *desc); -static void gen_bitlen (deflate_state *s, tree_desc *desc); -static void scan_tree (deflate_state *s, ct_data *tree, int max_code); -static void send_tree (deflate_state *s, ct_data *tree, int max_code); -static int build_bl_tree (deflate_state *s); -static void send_all_trees (deflate_state *s, int lcodes, int dcodes, int blcodes); -static void compress_block (deflate_state *s, const ct_data *ltree, const ct_data *dtree); -static int detect_data_type (deflate_state *s); +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, const ct_data *ltree, + const ct_data *dtree)); +local int detect_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef ZLIB_DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* !ZLIB_DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef ZLIB_DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !ZLIB_DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = (int)value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* ZLIB_DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef ZLIB_DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ -void Z_INTERNAL zng_tr_init(deflate_state *s) { +void ZLIB_INTERNAL _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; @@ -104,19 +404,18 @@ void Z_INTERNAL zng_tr_init(deflate_state *s) { /* =========================================================================== * Initialize a new block. */ -static void init_block(deflate_state *s) { +local void init_block(s) + deflate_state *s; +{ int n; /* iterates over tree elements */ /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) - s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) - s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) - s->bl_tree[n].Freq = 0; + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0; + s->opt_len = s->static_len = 0L; s->sym_next = s->matches = 0; } @@ -124,148 +423,54 @@ static void init_block(deflate_state *s) { /* Index within the heap array of least frequent node in the Huffman tree */ +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. Used by build_tree(). - */ -#define pqremove(s, depth, heap, tree, top) { \ - top = heap[SMALLEST]; \ - heap[SMALLEST] = heap[s->heap_len--]; \ - pqdownheap(depth, heap, s->heap_len, tree, SMALLEST); \ -} + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its - * two sons). Used by build_tree(). + * two sons). */ -static inline void pqdownheap(unsigned char *depth, int *heap, const int heap_len, ct_data *tree, int k) { - /* tree: the tree to restore */ - /* k: node to move down */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; int j = k << 1; /* left son of k */ - const int v = heap[k]; - - while (j <= heap_len) { + while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ - if (j < heap_len && smaller(tree, heap[j+1], heap[j], depth)) { + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ - if (smaller(tree, v, heap[j], depth)) - break; + if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ - heap[k] = heap[j]; - k = j; + s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } - heap[k] = v; -} - -/* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ -static void build_tree(deflate_state *s, tree_desc *desc) { - /* desc: the tree descriptor */ - unsigned char *depth = s->depth; - int *heap = s->heap; - ct_data *tree = desc->dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0; - s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - heap[++(s->heap_len)] = max_code = n; - depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - depth[node] = 0; - s->opt_len--; - if (stree) - s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) - pqdownheap(depth, heap, s->heap_len, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, depth, heap, tree, n); /* n = node of least frequency */ - m = heap[SMALLEST]; /* m = node of next least frequency */ - - heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - depth[node] = (unsigned char)((depth[n] >= depth[m] ? - depth[n] : depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (uint16_t)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - heap[SMALLEST] = node++; - pqdownheap(depth, heap, s->heap_len, tree, SMALLEST); - } while (s->heap_len >= 2); - - heap[--(s->heap_max)] = heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes((ct_data *)tree, max_code, s->bl_count); + s->heap[k] = v; } /* =========================================================================== @@ -276,66 +481,59 @@ static void build_tree(deflate_state *s, tree_desc *desc) { * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is - * not null. Used by build_tree(). + * not null. */ -static void gen_bitlen(deflate_state *s, tree_desc *desc) { - /* desc: the tree descriptor */ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const int *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - unsigned int max_length = desc->stat_desc->max_length; +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ - unsigned int bits; /* bit length */ + int bits; /* bit length */ int xbits; /* extra bits */ - uint16_t f; /* frequency */ + ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ - for (bits = 0; bits <= MAX_BITS; bits++) - s->bl_count[bits] = 0; + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1u; - if (bits > max_length){ - bits = max_length; - overflow++; - } - tree[n].Len = (uint16_t)bits; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ - if (n > max_code) /* not a leaf node */ - continue; + if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; - if (n >= base) - xbits = extra[n-base]; + if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; - s->opt_len += (unsigned int)f * (unsigned int)(bits + xbits); - if (stree) - s->static_len += (unsigned int)f * (unsigned int)(stree[n].Len + xbits); + s->opt_len += (ulg)f * (unsigned)(bits + xbits); + if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); } - if (overflow == 0) - return; + if (overflow == 0) return; - Tracev((stderr, "\nbit length overflow\n")); + Tracev((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { - bits = max_length - 1; - while (s->bl_count[bits] == 0) - bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2u; /* move one overflow item as its brother */ + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] @@ -352,13 +550,11 @@ static void gen_bitlen(deflate_state *s, tree_desc *desc) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; - if (m > max_code) - continue; - if (tree[m].Len != bits) { - Tracev((stderr, "code %d bits %d->%u\n", m, tree[m].Len, bits)); - s->opt_len += (unsigned int)(bits * tree[m].Freq); - s->opt_len -= (unsigned int)(tree[m].Len * tree[m].Freq); - tree[m].Len = (uint16_t)bits; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; + tree[m].Len = (ush)bits; } n--; } @@ -371,80 +567,170 @@ static void gen_bitlen(deflate_state *s, tree_desc *desc) { * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non - * zero code length. Used by build_tree(). + * zero code length. */ -Z_INTERNAL void gen_codes(ct_data *tree, int max_code, uint16_t *bl_count) { - /* tree: the tree to decorate */ - /* max_code: largest code with non zero frequency */ - /* bl_count: number of codes at each bit length */ - uint16_t next_code[MAX_BITS+1]; /* next code value for each bit length */ - uint16_t code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { code = (code + bl_count[bits-1]) << 1; - next_code[bits] = code; + next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ - Assert(code + bl_count[MAX_BITS]-1 == (1 << MAX_BITS)-1, "inconsistent bit counts"); - Tracev((stderr, "\ngen_codes: max_code %d ", max_code)); + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -static void scan_tree(deflate_state *s, ct_data *tree, int max_code) { - /* tree: the tree to be scanned */ - /* max_code: and its largest code of non zero frequency */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ - uint16_t count = 0; /* repeat count of the current code */ - uint16_t max_count = 7; /* max repeat count */ - uint16_t min_count = 4; /* min repeat count */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ - if (nextlen == 0) - max_count = 138, min_count = 3; - - tree[max_code+1].Len = (uint16_t)0xffff; /* guard */ + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { - if (curlen != prevlen) - s->bl_tree[curlen].Freq++; + if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } - count = 0; - prevlen = curlen; + count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { @@ -459,9 +745,11 @@ static void scan_tree(deflate_state *s, ct_data *tree, int max_code) { * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -static void send_tree(deflate_state *s, ct_data *tree, int max_code) { - /* tree: the tree to be scanned */ - /* max_code and its largest code of non zero frequency */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -471,42 +759,29 @@ static void send_tree(deflate_state *s, ct_data *tree, int max_code) { int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) - max_count = 138, min_count = 3; - - // Temp local variables - uint32_t bi_valid = s->bi_valid; - uint64_t bi_buf = s->bi_buf; + if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { - do { - send_code(s, curlen, s->bl_tree, bi_buf, bi_valid); - } while (--count != 0); + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree, bi_buf, bi_valid); - count--; + send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree, bi_buf, bi_valid); - send_bits(s, count-3, 2, bi_buf, bi_valid); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree, bi_buf, bi_valid); - send_bits(s, count-3, 3, bi_buf, bi_valid); + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { - send_code(s, REPZ_11_138, s->bl_tree, bi_buf, bi_valid); - send_bits(s, count-11, 7, bi_buf, bi_valid); + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } - count = 0; - prevlen = curlen; + count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { @@ -515,17 +790,15 @@ static void send_tree(deflate_state *s, ct_data *tree, int max_code) { max_count = 7, min_count = 4; } } - - // Store back temp variables - s->bi_buf = bi_buf; - s->bi_valid = bi_valid; } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ -static int build_bl_tree(deflate_state *s) { +local int build_bl_tree(s) + deflate_state *s; +{ int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ @@ -543,12 +816,12 @@ static int build_bl_tree(deflate_state *s) { * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) - break; + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((unsigned int)max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %u, stat %u", s->opt_len, s->static_len)); + s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); return max_blindex; } @@ -558,96 +831,107 @@ static int build_bl_tree(deflate_state *s) { * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ -static void send_all_trees(deflate_state *s, int lcodes, int dcodes, int blcodes) { +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ int rank; /* index in bl_order */ - Assert(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert(lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); - - // Temp local variables - uint32_t bi_valid = s->bi_valid; - uint64_t bi_buf = s->bi_buf; - + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5, bi_buf, bi_valid); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5, bi_buf, bi_valid); - send_bits(s, blcodes-4, 4, bi_buf, bi_valid); /* not -3 as stated in appnote.txt */ + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2u ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3, bi_buf, bi_valid); + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } - Tracev((stderr, "\nbl tree: sent %lu", s->bits_sent)); - - // Store back temp variables - s->bi_buf = bi_buf; - s->bi_valid = bi_valid; + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %lu", s->bits_sent)); + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %lu", s->bits_sent)); + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ -void Z_INTERNAL zng_tr_stored_block(deflate_state *s, unsigned char *buf, uint32_t stored_len, int last) { - /* buf: input block */ - /* stored_len: length of input block */ - /* last: one if this is the last block for a file */ - zng_tr_emit_tree(s, STORED_BLOCK, last); /* send block type */ - zng_tr_emit_align(s); /* align on byte boundary */ - cmpr_bits_align(s); - put_short(s, (uint16_t)stored_len); - put_short(s, (uint16_t)~stored_len); - cmpr_bits_add(s, 32); - sent_bits_add(s, 32); - if (stored_len) { - memcpy(s->pending_buf + s->pending, buf, stored_len); - s->pending += stored_len; - cmpr_bits_add(s, stored_len << 3); - sent_bits_add(s, stored_len << 3); - } +void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ + bi_windup(s); /* align on byte boundary */ + put_short(s, (ush)stored_len); + put_short(s, (ush)~stored_len); + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + s->pending += stored_len; +#ifdef ZLIB_DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + s->bits_sent += 2*16; + s->bits_sent += stored_len<<3; +#endif +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(s) + deflate_state *s; +{ + bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ -void Z_INTERNAL zng_tr_align(deflate_state *s) { - zng_tr_emit_tree(s, STATIC_TREES, 0); - zng_tr_emit_end_block(s, static_ltree, 0); - zng_tr_flush_bits(s); +void ZLIB_INTERNAL _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef ZLIB_DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and write out the encoded block. */ -void Z_INTERNAL zng_tr_flush_block(deflate_state *s, unsigned char *buf, uint32_t stored_len, int last) { - /* buf: input block, or NULL if too old */ - /* stored_len: length of input block */ - /* last: one if this is the last block for a file */ - unsigned int opt_lenb, static_lenb; /* opt_len and static_len in bytes */ +void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ - if (UNLIKELY(s->sym_next == 0)) { - /* Emit an empty static tree block with no codes */ - opt_lenb = static_lenb = 0; - s->static_len = 7; - } else if (s->level > 0) { + if (s->level > 0) { + /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %u, stat %u", s->opt_len, s->static_len)); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %u, stat %u", s->opt_len, s->static_len)); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ @@ -658,175 +942,240 @@ void Z_INTERNAL zng_tr_flush_block(deflate_state *s, unsigned char *buf, uint32_ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len + 3 + 7) >> 3; - static_lenb = (s->static_len + 3 + 7) >> 3; + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; - Tracev((stderr, "\nopt %u(%u) stat %u(%u) stored %u lit %u ", + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->sym_next / 3)); - if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) - opt_lenb = static_lenb; + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { - Assert(buf != NULL, "lost buf"); + Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } - if (stored_len+4 <= opt_lenb && buf != NULL) { - /* 4: two words for the lengths - * The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ - zng_tr_stored_block(s, buf, stored_len, last); + _tr_stored_block(s, buf, stored_len, last); - } else if (static_lenb == opt_lenb) { - zng_tr_emit_tree(s, STATIC_TREES, last); - compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); - cmpr_bits_add(s, s->static_len); +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+last, 3); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->static_len; +#endif } else { - zng_tr_emit_tree(s, DYN_TREES, last); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); - compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); - cmpr_bits_add(s, s->opt_len); + send_bits(s, (DYN_TREES<<1)+last, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->opt_len; +#endif } - Assert(s->compressed_len == s->bits_sent, "bad compressed size"); + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB - * and unsigned long implemented on 32 bits. + * and uLong implemented on 32 bits. */ init_block(s); if (last) { - zng_tr_emit_align(s); + bi_windup(s); +#ifdef ZLIB_DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif } - Tracev((stderr, "\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->sym_buf[s->sym_next++] = dist; + s->sym_buf[s->sym_next++] = dist >> 8; + s->sym_buf[s->sym_next++] = lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + return (s->sym_next == s->sym_end); } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ -static void compress_block(deflate_state *s, const ct_data *ltree, const ct_data *dtree) { - /* ltree: literal tree */ - /* dtree: distance tree */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + const ct_data *ltree; /* literal tree */ + const ct_data *dtree; /* distance tree */ +{ unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ - unsigned sx = 0; /* running index in symbol buffers */ + unsigned sx = 0; /* running index in sym_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ - /* Local pointers to avoid indirection */ - const unsigned int sym_next = s->sym_next; -#ifdef LIT_MEM - uint16_t *d_buf = s->d_buf; - unsigned char *l_buf = s->l_buf; -#else - unsigned char *sym_buf = s->sym_buf; -#endif + if (s->sym_next != 0) do { + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); - /* Keep bi_buf and bi_valid in registers across the entire loop */ - uint64_t bi_buf = s->bi_buf; - uint32_t bi_valid = s->bi_valid; + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ - if (sym_next != 0) { - do { -#ifdef LIT_MEM - dist = d_buf[sx]; - lc = l_buf[sx++]; -#else -# if OPTIMAL_CMP >= 32 - uint32_t val = Z_U32_FROM_LE(zng_memread_4(&sym_buf[sx])); - dist = val & 0xffff; - lc = (val >> 16) & 0xff; -# else - dist = sym_buf[sx] + ((unsigned)sym_buf[sx + 1] << 8); - lc = sym_buf[sx + 2]; -# endif - sx += 3; -#endif - if (dist == 0) { - zng_emit_lit(s, ltree, lc, &bi_buf, &bi_valid); - } else { - zng_emit_dist(s, ltree, dtree, lc, dist, &bi_buf, &bi_valid); - } /* literal or match pair ? */ + /* Check that the overlay between pending_buf and sym_buf is ok: */ + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); - /* Check for no overlay of pending_buf on needed symbols */ -#ifdef LIT_MEM - Assert(s->pending < 2 * (s->lit_bufsize + sx), "pending_buf overflow"); -#else - Assert(s->pending < s->lit_bufsize + sx, "pending_buf overflow"); -#endif - } while (sx < sym_next); - } + } while (sx < s->sym_next); - zng_emit_end_block(s, ltree, 0, &bi_buf, &bi_valid); - - /* Write back to state */ - s->bi_buf = bi_buf; - s->bi_valid = bi_valid; + send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the - * "block list" (0..6, 14..25, 28..31). + * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the - * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ -static int detect_data_type(deflate_state *s) { - /* block_mask is the bit mask of block-listed bytes +local int detect_data_type(s) + deflate_state *s; +{ + /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ - unsigned long block_mask = 0xf3ffc07fUL; + unsigned long black_mask = 0xf3ffc07fUL; int n; - /* Check for non-textual ("block-listed") bytes. */ - for (n = 0; n <= 31; n++, block_mask >>= 1) - if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>= 1) + if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; - /* Check for textual ("allow-listed") bytes. */ - if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) + /* Check for textual ("white-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; - /* There are no "block-listed" or "allow-listed" bytes: + /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ -void Z_INTERNAL zng_tr_flush_bits(deflate_state *s) { - if (s->bi_valid >= 48) { - put_uint32(s, (uint32_t)s->bi_buf); - put_short(s, (uint16_t)(s->bi_buf >> 32)); - s->bi_buf >>= 48; - s->bi_valid -= 48; - } else if (s->bi_valid >= 32) { - put_uint32(s, (uint32_t)s->bi_buf); - s->bi_buf >>= 32; - s->bi_valid -= 32; - } - if (s->bi_valid >= 16) { - put_short(s, (uint16_t)s->bi_buf); - s->bi_buf >>= 16; - s->bi_valid -= 16; - } - if (s->bi_valid >= 8) { - put_byte(s, s->bi_buf); +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} diff --git a/modules/zlib/src/trees.h b/modules/zlib/src/trees.h index e57f926489..d35639d82a 100644 --- a/modules/zlib/src/trees.h +++ b/modules/zlib/src/trees.h @@ -1,40 +1,128 @@ -#ifndef TREES_H_ -#define TREES_H_ +/* header created automatically with -DGEN_TREES_H */ -/* Constants */ +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; -#define DIST_CODE_LEN 512 -/* see definition of array dist_code in trees.c */ +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; -static const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -static const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static const int extra_blbits[BL_CODES] /* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -static const unsigned char bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; - /* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - - -/* Function definitions */ -void gen_codes (ct_data *tree, int max_code, uint16_t *bl_count); - -#endif diff --git a/modules/zlib/src/trees_emit.h b/modules/zlib/src/trees_emit.h deleted file mode 100644 index 365aac0768..0000000000 --- a/modules/zlib/src/trees_emit.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef TREES_EMIT_H_ -#define TREES_EMIT_H_ - -#include "zbuild.h" -#include "trees.h" - -#ifdef ZLIB_DEBUG -# include -# include -#endif - - -/* trees.h */ -extern Z_INTERNAL const ct_data static_ltree[L_CODES+2]; -extern Z_INTERNAL const ct_data static_dtree[D_CODES]; - -extern const unsigned char Z_INTERNAL zng_dist_code[DIST_CODE_LEN]; -extern const unsigned char Z_INTERNAL zng_length_code[STD_MAX_MATCH-STD_MIN_MATCH+1]; - -/* Combined base + extra_bits tables for single-lookup optimization */ -extern Z_INTERNAL const uint16_t lbase_extra[LENGTH_CODES]; -extern Z_INTERNAL const uint32_t dbase_extra[D_CODES]; - -/* Bit buffer and deflate code stderr tracing */ -#ifdef ZLIB_DEBUG -# define send_bits_trace(s, value, length) { \ - Tracevv((stderr, " l %2d v %4llx ", (int)(length), (long long)(value))); \ - Assert(length > 0 && length <= BIT_BUF_SIZE, "invalid length"); \ - } -# define send_code_trace(s, c) \ - if (z_verbose > 2) { \ - fprintf(stderr, "\ncd %3d ", (c)); \ - } -#else -# define send_bits_trace(s, value, length) -# define send_code_trace(s, c) -#endif - -/* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (64 - bi_valid) bits from value, leaving (width - (64-bi_valid)) - * unused bits in value. - * - * NOTE: Static analyzers can't evaluate value of total_bits, so we - * also need to make sure bi_valid is within acceptable range, - * otherwise the shifts will overflow. - */ -#define send_bits(s, t_val, t_len, bi_buf, bi_valid) {\ - uint64_t val = (uint64_t)t_val;\ - uint32_t len = (uint32_t)t_len;\ - uint32_t total_bits = bi_valid + len;\ - send_bits_trace(s, val, len);\ - sent_bits_add(s, len);\ - if (total_bits < BIT_BUF_SIZE && bi_valid < BIT_BUF_SIZE) {\ - bi_buf |= val << bi_valid;\ - bi_valid = total_bits;\ - } else if (bi_valid >= BIT_BUF_SIZE) {\ - put_uint64(s, bi_buf);\ - bi_buf = val;\ - bi_valid = len;\ - } else {\ - bi_buf |= val << bi_valid;\ - put_uint64(s, bi_buf);\ - bi_buf = val >> (BIT_BUF_SIZE - bi_valid);\ - bi_valid = total_bits - BIT_BUF_SIZE;\ - }\ -} - -/* Send a code of the given tree. c and tree must not have side effects */ -#ifdef ZLIB_DEBUG -# define send_code(s, c, tree, bi_buf, bi_valid) { \ - send_code_trace(s, c); \ - send_bits(s, tree[c].Code, tree[c].Len, bi_buf, bi_valid); \ -} -#else -# define send_code(s, c, tree, bi_buf, bi_valid) \ - send_bits(s, tree[c].Code, tree[c].Len, bi_buf, bi_valid) -#endif - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -static inline void bi_windup(deflate_state *s) { - if (s->bi_valid > 56) { - put_uint64(s, s->bi_buf); - } else { - if (s->bi_valid > 24) { - put_uint32(s, (uint32_t)s->bi_buf); - s->bi_buf >>= 32; - s->bi_valid -= 32; - } - if (s->bi_valid > 8) { - put_short(s, (uint16_t)s->bi_buf); - s->bi_buf >>= 16; - s->bi_valid -= 16; - } - if (s->bi_valid > 0) { - put_byte(s, s->bi_buf); - } - } - s->bi_buf = 0; - s->bi_valid = 0; -} - -/* =========================================================================== - * Emit literal code - */ -static inline void zng_emit_lit(deflate_state *s, const ct_data *ltree, unsigned c, - uint64_t *bi_buf, uint32_t *bi_valid) { - send_code(s, c, ltree, *bi_buf, *bi_valid); - Tracecv(isgraph(c & 0xff), (stderr, " '%c' ", c)); -} - -/* =========================================================================== - * Emit match distance/length code - */ -static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, const ct_data *dtree, - uint32_t lc, uint32_t dist, uint64_t *bi_buf, uint32_t *bi_valid) { - uint32_t c, extra, lext; - uint8_t code; - uint64_t match_bits; - uint32_t match_bits_len; - - /* Send the length code, len is the match length - STD_MIN_MATCH */ - code = zng_length_code[lc]; - c = code+LITERALS+1; - Assert(c < L_CODES, "bad l_code"); - send_code_trace(s, c); - - match_bits = ltree[c].Code; - match_bits_len = ltree[c].Len; - /* Get extra bits count and subtract base length from match length */ - lext = lbase_extra[code]; - extra = lext >> 8; - lc -= lext & 0xff; - match_bits |= ((uint64_t)(lc & ((1U << extra) - 1)) << match_bits_len); - match_bits_len += extra; - - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert(code < D_CODES, "bad d_code"); - send_code_trace(s, code); - - /* Send the distance code */ - match_bits |= ((uint64_t)dtree[code].Code << match_bits_len); - match_bits_len += dtree[code].Len; - /* Get extra bits count and subtract base distance */ - lext = dbase_extra[code]; - extra = lext >> 16; - dist -= lext & 0xffff; - match_bits |= ((uint64_t)(dist & ((1U << extra) - 1)) << match_bits_len); - match_bits_len += extra; - - send_bits(s, match_bits, match_bits_len, *bi_buf, *bi_valid); - - return match_bits_len; -} - -/* =========================================================================== - * Emit end block - */ -static inline void zng_emit_end_block(deflate_state *s, const ct_data *ltree, const int last, - uint64_t *bi_buf, uint32_t *bi_valid) { - send_code(s, END_BLOCK, ltree, *bi_buf, *bi_valid); - Tracev((stderr, "\n+++ Emit End Block: Last: %u Pending: %u Total Out: %" PRIu64 "\n", - last, s->pending, (uint64_t)s->strm->total_out)); - Z_UNUSED(last); -} - -/* =========================================================================== - * Emit literal and count bits - */ -static inline void zng_tr_emit_lit(deflate_state *s, const ct_data *ltree, unsigned c) { - uint64_t bi_buf = s->bi_buf; - uint32_t bi_valid = s->bi_valid; - zng_emit_lit(s, ltree, c, &bi_buf, &bi_valid); - s->bi_buf = bi_buf; - s->bi_valid = bi_valid; - cmpr_bits_add(s, ltree[c].Len); -} - -/* =========================================================================== - * Emit match and count bits - */ -static inline void zng_tr_emit_dist(deflate_state *s, const ct_data *ltree, const ct_data *dtree, - uint32_t lc, uint32_t dist) { - uint64_t bi_buf = s->bi_buf; - uint32_t bi_valid = s->bi_valid; - uint32_t bits = zng_emit_dist(s, ltree, dtree, lc, dist, &bi_buf, &bi_valid); - s->bi_buf = bi_buf; - s->bi_valid = bi_valid; - cmpr_bits_add(s, bits); -} - -/* =========================================================================== - * Emit start of block - */ -static inline void zng_tr_emit_tree(deflate_state *s, int type, const int last) { - uint32_t bi_valid = s->bi_valid; - uint64_t bi_buf = s->bi_buf; - uint32_t header_bits = (type << 1) + last; - send_bits(s, header_bits, 3, bi_buf, bi_valid); - cmpr_bits_add(s, 3); - s->bi_valid = bi_valid; - s->bi_buf = bi_buf; - Tracev((stderr, "\n--- Emit Tree: Last: %u\n", last)); -} - -/* =========================================================================== - * Align bit buffer on a byte boundary and count bits - */ -static inline void zng_tr_emit_align(deflate_state *s) { - bi_windup(s); /* align on byte boundary */ - sent_bits_align(s); -} - -/* =========================================================================== - * Emit an end block and align bit buffer if last block - */ -static inline void zng_tr_emit_end_block(deflate_state *s, const ct_data *ltree, const int last) { - uint64_t bi_buf = s->bi_buf; - uint32_t bi_valid = s->bi_valid; - zng_emit_end_block(s, ltree, last, &bi_buf, &bi_valid); - s->bi_buf = bi_buf; - s->bi_valid = bi_valid; - cmpr_bits_add(s, 7); - if (last) - zng_tr_emit_align(s); -} - -#endif diff --git a/modules/zlib/src/trees_tbl.h b/modules/zlib/src/trees_tbl.h deleted file mode 100644 index 16a47450b7..0000000000 --- a/modules/zlib/src/trees_tbl.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef TREES_TBL_H_ -#define TREES_TBL_H_ - -/* header created automatically with maketrees.c */ - -Z_INTERNAL const ct_data static_ltree[L_CODES+2] = { -{{ 12},{8}}, {{140},{8}}, {{ 76},{8}}, {{204},{8}}, {{ 44},{8}}, -{{172},{8}}, {{108},{8}}, {{236},{8}}, {{ 28},{8}}, {{156},{8}}, -{{ 92},{8}}, {{220},{8}}, {{ 60},{8}}, {{188},{8}}, {{124},{8}}, -{{252},{8}}, {{ 2},{8}}, {{130},{8}}, {{ 66},{8}}, {{194},{8}}, -{{ 34},{8}}, {{162},{8}}, {{ 98},{8}}, {{226},{8}}, {{ 18},{8}}, -{{146},{8}}, {{ 82},{8}}, {{210},{8}}, {{ 50},{8}}, {{178},{8}}, -{{114},{8}}, {{242},{8}}, {{ 10},{8}}, {{138},{8}}, {{ 74},{8}}, -{{202},{8}}, {{ 42},{8}}, {{170},{8}}, {{106},{8}}, {{234},{8}}, -{{ 26},{8}}, {{154},{8}}, {{ 90},{8}}, {{218},{8}}, {{ 58},{8}}, -{{186},{8}}, {{122},{8}}, {{250},{8}}, {{ 6},{8}}, {{134},{8}}, -{{ 70},{8}}, {{198},{8}}, {{ 38},{8}}, {{166},{8}}, {{102},{8}}, -{{230},{8}}, {{ 22},{8}}, {{150},{8}}, {{ 86},{8}}, {{214},{8}}, -{{ 54},{8}}, {{182},{8}}, {{118},{8}}, {{246},{8}}, {{ 14},{8}}, -{{142},{8}}, {{ 78},{8}}, {{206},{8}}, {{ 46},{8}}, {{174},{8}}, -{{110},{8}}, {{238},{8}}, {{ 30},{8}}, {{158},{8}}, {{ 94},{8}}, -{{222},{8}}, {{ 62},{8}}, {{190},{8}}, {{126},{8}}, {{254},{8}}, -{{ 1},{8}}, {{129},{8}}, {{ 65},{8}}, {{193},{8}}, {{ 33},{8}}, -{{161},{8}}, {{ 97},{8}}, {{225},{8}}, {{ 17},{8}}, {{145},{8}}, -{{ 81},{8}}, {{209},{8}}, {{ 49},{8}}, {{177},{8}}, {{113},{8}}, -{{241},{8}}, {{ 9},{8}}, {{137},{8}}, {{ 73},{8}}, {{201},{8}}, -{{ 41},{8}}, {{169},{8}}, {{105},{8}}, {{233},{8}}, {{ 25},{8}}, -{{153},{8}}, {{ 89},{8}}, {{217},{8}}, {{ 57},{8}}, {{185},{8}}, -{{121},{8}}, {{249},{8}}, {{ 5},{8}}, {{133},{8}}, {{ 69},{8}}, -{{197},{8}}, {{ 37},{8}}, {{165},{8}}, {{101},{8}}, {{229},{8}}, -{{ 21},{8}}, {{149},{8}}, {{ 85},{8}}, {{213},{8}}, {{ 53},{8}}, -{{181},{8}}, {{117},{8}}, {{245},{8}}, {{ 13},{8}}, {{141},{8}}, -{{ 77},{8}}, {{205},{8}}, {{ 45},{8}}, {{173},{8}}, {{109},{8}}, -{{237},{8}}, {{ 29},{8}}, {{157},{8}}, {{ 93},{8}}, {{221},{8}}, -{{ 61},{8}}, {{189},{8}}, {{125},{8}}, {{253},{8}}, {{ 19},{9}}, -{{275},{9}}, {{147},{9}}, {{403},{9}}, {{ 83},{9}}, {{339},{9}}, -{{211},{9}}, {{467},{9}}, {{ 51},{9}}, {{307},{9}}, {{179},{9}}, -{{435},{9}}, {{115},{9}}, {{371},{9}}, {{243},{9}}, {{499},{9}}, -{{ 11},{9}}, {{267},{9}}, {{139},{9}}, {{395},{9}}, {{ 75},{9}}, -{{331},{9}}, {{203},{9}}, {{459},{9}}, {{ 43},{9}}, {{299},{9}}, -{{171},{9}}, {{427},{9}}, {{107},{9}}, {{363},{9}}, {{235},{9}}, -{{491},{9}}, {{ 27},{9}}, {{283},{9}}, {{155},{9}}, {{411},{9}}, -{{ 91},{9}}, {{347},{9}}, {{219},{9}}, {{475},{9}}, {{ 59},{9}}, -{{315},{9}}, {{187},{9}}, {{443},{9}}, {{123},{9}}, {{379},{9}}, -{{251},{9}}, {{507},{9}}, {{ 7},{9}}, {{263},{9}}, {{135},{9}}, -{{391},{9}}, {{ 71},{9}}, {{327},{9}}, {{199},{9}}, {{455},{9}}, -{{ 39},{9}}, {{295},{9}}, {{167},{9}}, {{423},{9}}, {{103},{9}}, -{{359},{9}}, {{231},{9}}, {{487},{9}}, {{ 23},{9}}, {{279},{9}}, -{{151},{9}}, {{407},{9}}, {{ 87},{9}}, {{343},{9}}, {{215},{9}}, -{{471},{9}}, {{ 55},{9}}, {{311},{9}}, {{183},{9}}, {{439},{9}}, -{{119},{9}}, {{375},{9}}, {{247},{9}}, {{503},{9}}, {{ 15},{9}}, -{{271},{9}}, {{143},{9}}, {{399},{9}}, {{ 79},{9}}, {{335},{9}}, -{{207},{9}}, {{463},{9}}, {{ 47},{9}}, {{303},{9}}, {{175},{9}}, -{{431},{9}}, {{111},{9}}, {{367},{9}}, {{239},{9}}, {{495},{9}}, -{{ 31},{9}}, {{287},{9}}, {{159},{9}}, {{415},{9}}, {{ 95},{9}}, -{{351},{9}}, {{223},{9}}, {{479},{9}}, {{ 63},{9}}, {{319},{9}}, -{{191},{9}}, {{447},{9}}, {{127},{9}}, {{383},{9}}, {{255},{9}}, -{{511},{9}}, {{ 0},{7}}, {{ 64},{7}}, {{ 32},{7}}, {{ 96},{7}}, -{{ 16},{7}}, {{ 80},{7}}, {{ 48},{7}}, {{112},{7}}, {{ 8},{7}}, -{{ 72},{7}}, {{ 40},{7}}, {{104},{7}}, {{ 24},{7}}, {{ 88},{7}}, -{{ 56},{7}}, {{120},{7}}, {{ 4},{7}}, {{ 68},{7}}, {{ 36},{7}}, -{{100},{7}}, {{ 20},{7}}, {{ 84},{7}}, {{ 52},{7}}, {{116},{7}}, -{{ 3},{8}}, {{131},{8}}, {{ 67},{8}}, {{195},{8}}, {{ 35},{8}}, -{{163},{8}}, {{ 99},{8}}, {{227},{8}} -}; - -Z_INTERNAL const ct_data static_dtree[D_CODES] = { -{{ 0},{5}}, {{16},{5}}, {{ 8},{5}}, {{24},{5}}, {{ 4},{5}}, -{{20},{5}}, {{12},{5}}, {{28},{5}}, {{ 2},{5}}, {{18},{5}}, -{{10},{5}}, {{26},{5}}, {{ 6},{5}}, {{22},{5}}, {{14},{5}}, -{{30},{5}}, {{ 1},{5}}, {{17},{5}}, {{ 9},{5}}, {{25},{5}}, -{{ 5},{5}}, {{21},{5}}, {{13},{5}}, {{29},{5}}, {{ 3},{5}}, -{{19},{5}}, {{11},{5}}, {{27},{5}}, {{ 7},{5}}, {{23},{5}} -}; - -const unsigned char Z_INTERNAL zng_dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const unsigned char Z_INTERNAL zng_length_code[STD_MAX_MATCH-STD_MIN_MATCH+1] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -/* Combined base + extra_bits tables for single-lookup optimization. - * Length table: bits 0-7 = base_length, bits 8-11 = extra_lbits - * Distance table: bits 0-15 = base_dist, bits 16-19 = extra_dbits - */ -#define LBASE_EXTRA(base, extra) ((extra) << 8 | (base)) -#define DBASE_EXTRA(base, extra) ((extra) << 16 | (base)) - -Z_INTERNAL const uint16_t lbase_extra[LENGTH_CODES] = { -LBASE_EXTRA( 0, 0), LBASE_EXTRA( 1, 0), LBASE_EXTRA( 2, 0), LBASE_EXTRA( 3, 0), -LBASE_EXTRA( 4, 0), LBASE_EXTRA( 5, 0), LBASE_EXTRA( 6, 0), LBASE_EXTRA( 7, 0), -LBASE_EXTRA( 8, 1), LBASE_EXTRA( 10, 1), LBASE_EXTRA( 12, 1), LBASE_EXTRA( 14, 1), -LBASE_EXTRA( 16, 2), LBASE_EXTRA( 20, 2), LBASE_EXTRA( 24, 2), LBASE_EXTRA( 28, 2), -LBASE_EXTRA( 32, 3), LBASE_EXTRA( 40, 3), LBASE_EXTRA( 48, 3), LBASE_EXTRA( 56, 3), -LBASE_EXTRA( 64, 4), LBASE_EXTRA( 80, 4), LBASE_EXTRA( 96, 4), LBASE_EXTRA(112, 4), -LBASE_EXTRA(128, 5), LBASE_EXTRA(160, 5), LBASE_EXTRA(192, 5), LBASE_EXTRA(224, 5), -LBASE_EXTRA( 0, 0) -}; - -Z_INTERNAL const uint32_t dbase_extra[D_CODES] = { -DBASE_EXTRA( 0, 0), DBASE_EXTRA( 1, 0), DBASE_EXTRA( 2, 0), DBASE_EXTRA( 3, 0), -DBASE_EXTRA( 4, 1), DBASE_EXTRA( 6, 1), DBASE_EXTRA( 8, 2), DBASE_EXTRA( 12, 2), -DBASE_EXTRA( 16, 3), DBASE_EXTRA( 24, 3), DBASE_EXTRA( 32, 4), DBASE_EXTRA( 48, 4), -DBASE_EXTRA( 64, 5), DBASE_EXTRA( 96, 5), DBASE_EXTRA( 128, 6), DBASE_EXTRA( 192, 6), -DBASE_EXTRA( 256, 7), DBASE_EXTRA( 384, 7), DBASE_EXTRA( 512, 8), DBASE_EXTRA( 768, 8), -DBASE_EXTRA( 1024, 9), DBASE_EXTRA( 1536, 9), DBASE_EXTRA( 2048, 10), DBASE_EXTRA( 3072, 10), -DBASE_EXTRA( 4096, 11), DBASE_EXTRA( 6144, 11), DBASE_EXTRA( 8192, 12), DBASE_EXTRA(12288, 12), -DBASE_EXTRA(16384, 13), DBASE_EXTRA(24576, 13) -}; - -#endif /* TREES_TBL_H_ */ diff --git a/modules/zlib/src/uncompr.c b/modules/zlib/src/uncompr.c index 1db4d26a72..f03a1a865e 100644 --- a/modules/zlib/src/uncompr.c +++ b/modules/zlib/src/uncompr.c @@ -1,10 +1,12 @@ /* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler. + * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" -#include "zutil.h" +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" /* =========================================================================== Decompresses the source buffer into the destination buffer. *sourceLen is @@ -22,29 +24,35 @@ Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ -z_int32_t Z_EXPORT PREFIX(uncompress2)(unsigned char *dest, z_uintmax_t *destLen, const unsigned char *source, z_uintmax_t *sourceLen) { - PREFIX3(stream) stream; +int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong *sourceLen; +{ + z_stream stream; int err; - const unsigned int max = (unsigned int)-1; - z_uintmax_t len, left; - unsigned char buf[1]; /* for detection of incomplete stream when *destLen == 0 */ + const uInt max = (uInt)-1; + uLong len, left; + Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ len = *sourceLen; if (*destLen) { left = *destLen; *destLen = 0; - } else { + } + else { left = 1; dest = buf; } - stream.next_in = (z_const unsigned char *)source; + stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; - stream.zalloc = NULL; - stream.zfree = NULL; - stream.opaque = NULL; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; - err = PREFIX(inflateInit)(&stream); + err = inflateInit(&stream); if (err != Z_OK) return err; stream.next_out = dest; @@ -52,29 +60,34 @@ z_int32_t Z_EXPORT PREFIX(uncompress2)(unsigned char *dest, z_uintmax_t *destLen do { if (stream.avail_out == 0) { - stream.avail_out = left > (unsigned long)max ? max : (unsigned int)left; + stream.avail_out = left > (uLong)max ? max : (uInt)left; left -= stream.avail_out; } if (stream.avail_in == 0) { - stream.avail_in = len > (unsigned long)max ? max : (unsigned int)len; + stream.avail_in = len > (uLong)max ? max : (uInt)len; len -= stream.avail_in; } - err = PREFIX(inflate)(&stream, Z_NO_FLUSH); + err = inflate(&stream, Z_NO_FLUSH); } while (err == Z_OK); *sourceLen -= len + stream.avail_in; if (dest != buf) - *destLen = (z_size_t)stream.total_out; + *destLen = stream.total_out; else if (stream.total_out && err == Z_BUF_ERROR) left = 1; - PREFIX(inflateEnd)(&stream); + inflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err == Z_NEED_DICT ? Z_DATA_ERROR : err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : err; } -z_int32_t Z_EXPORT PREFIX(uncompress)(unsigned char *dest, z_uintmax_t *destLen, const unsigned char *source, z_uintmax_t sourceLen) { - return PREFIX(uncompress2)(dest, destLen, source, &sourceLen); +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return uncompress2(dest, destLen, source, &sourceLen); } diff --git a/modules/zlib/src/x86.c b/modules/zlib/src/x86.c new file mode 100644 index 0000000000..714dfdc420 --- /dev/null +++ b/modules/zlib/src/x86.c @@ -0,0 +1,122 @@ +/* + * x86 feature check + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Author: + * Jim Kukunas + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "x86.h" +#include "zutil.h" + +int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0; +int ZLIB_INTERNAL x86_cpu_enable_simd = 0; + +static void _x86_check_features(void); + +#ifndef _MSC_VER +#include + +pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT; + +void x86_check_features(void) +{ + pthread_once(&cpu_check_inited_once, _x86_check_features); +} + +static void _x86_check_features(void) +{ + int x86_cpu_has_sse2; + int x86_cpu_has_ssse3; + int x86_cpu_has_sse42; + int x86_cpu_has_pclmulqdq; + unsigned eax, ebx, ecx, edx; + + eax = 1; +#ifdef __i386__ + __asm__ __volatile__ ( + "xchg %%ebx, %1\n\t" + "cpuid\n\t" + "xchg %1, %%ebx\n\t" + : "+a" (eax), "=S" (ebx), "=c" (ecx), "=d" (edx) + ); +#else + __asm__ __volatile__ ( + "cpuid\n\t" + : "+a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + ); +#endif /* (__i386__) */ + + x86_cpu_has_sse2 = edx & 0x4000000; + x86_cpu_has_ssse3 = ecx & 0x000200; + x86_cpu_has_sse42 = ecx & 0x100000; + x86_cpu_has_pclmulqdq = ecx & 0x2; + + x86_cpu_enable_ssse3 = x86_cpu_has_ssse3; + + x86_cpu_enable_simd = x86_cpu_has_sse2 && + x86_cpu_has_sse42 && + x86_cpu_has_pclmulqdq; +} +#else +#include +#include +#include + +static volatile int32_t once_control = 0; +static int fake_pthread_once(volatile int32_t *once_control, + void (*init_routine)(void)); + +void x86_check_features(void) +{ + fake_pthread_once(&once_control, _x86_check_features); +} + +/* Copied from "perftools_pthread_once" in tcmalloc */ +static int fake_pthread_once(volatile int32_t *once_control, + void (*init_routine)(void)) { + // Try for a fast path first. Note: this should be an acquire semantics read + // It is on x86 and x64, where Windows runs. + if (*once_control != 1) { + while (1) { + switch (InterlockedCompareExchange(once_control, 2, 0)) { + case 0: + init_routine(); + InterlockedExchange(once_control, 1); + return 0; + case 1: + // The initializer has already been executed + return 0; + default: + // The initializer is being processed by another thread + SwitchToThread(); + } + } + } + return 0; +} + +static void _x86_check_features(void) +{ + int x86_cpu_has_sse2; + int x86_cpu_has_ssse3; + int x86_cpu_has_sse42; + int x86_cpu_has_pclmulqdq; + int regs[4]; + + __cpuid(regs, 1); + + x86_cpu_has_sse2 = regs[3] & 0x4000000; + x86_cpu_has_ssse3 = regs[2] & 0x000200; + x86_cpu_has_sse42 = regs[2] & 0x100000; + x86_cpu_has_pclmulqdq = regs[2] & 0x2; + + x86_cpu_enable_ssse3 = x86_cpu_has_ssse3; + + x86_cpu_enable_simd = x86_cpu_has_sse2 && + x86_cpu_has_sse42 && + x86_cpu_has_pclmulqdq; +} +#endif /* _MSC_VER */ diff --git a/modules/zlib/src/x86.h b/modules/zlib/src/x86.h new file mode 100644 index 0000000000..7205d50265 --- /dev/null +++ b/modules/zlib/src/x86.h @@ -0,0 +1,16 @@ +/* x86.h -- check for x86 CPU features +* Copyright (C) 2013 Intel Corporation Jim Kukunas +* For conditions of distribution and use, see copyright notice in zlib.h +*/ + +#ifndef X86_H +#define X86_H + +#include "zlib.h" + +extern int x86_cpu_enable_ssse3; +extern int x86_cpu_enable_simd; + +void x86_check_features(void); + +#endif /* X86_H */ diff --git a/modules/zlib/src/zarch.h b/modules/zlib/src/zarch.h deleted file mode 100644 index 6fdcfaba55..0000000000 --- a/modules/zlib/src/zarch.h +++ /dev/null @@ -1,209 +0,0 @@ -/* zarch.h -- Detect compiler architecture and define ARCH_* macros - * Copyright (C) 2019 Hans Kristian Rosbach - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ZARCH_H -#define ZARCH_H - -#define ZARCH_STRINGIZE(X) ZARCH_DOSTRINGIZE(X) -#define ZARCH_DOSTRINGIZE(X) #X - -/* ARM64EC defines both _M_ARM64EC and _M_AMD64/_M_X64, so check for ARM first. */ - -/* ARM 64-bit */ -#if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC) -# define ARCH_ARM -# define ARCH_64BIT -# define ARCH_NAME "aarch64" - -/* ARM 32-bit */ -#elif defined(__arm__) || defined(__arm) || defined(_M_ARM) || defined(__TARGET_ARCH_ARM) -# define ARCH_ARM -# define ARCH_32BIT -# if defined(__ARM64_ARCH_8__) || defined(__ARM_ARCH_8A__) || defined(__ARMv8__) || defined(__ARMv8_A__) -# define ARCH_NAME "armv8" -# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) -# define ARCH_NAME "armv7" -# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6T2__) || \ - defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) || \ - defined(__ARM_ARCH_6M__) -# define ARCH_NAME "armv6" -# elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__) -# define ARCH_NAME "armv5" -# elif defined(__ARM_ARCH_4T__) -# define ARCH_NAME "armv4" -# elif defined(__ARM_ARCH_3__) -# define ARCH_NAME "armv3" -# elif defined(__ARM_ARCH_2__) -# define ARCH_NAME "armv2" -# else -# define ARCH_NAME "arm" -# endif - -/* x86_64 */ -#elif defined(__x86_64__) || defined(_M_X64) -# define ARCH_X86 -# define ARCH_64BIT -# define ARCH_NAME "x86_64" - -/* x86 (32-bit) */ -#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || \ - defined(__i386) || defined(_M_IX86) -# define ARCH_X86 -# define ARCH_32BIT -# define ARCH_NAME "i686" - -/* PowerPC */ -#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) -# define ARCH_POWER -# if defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) -# define ARCH_64BIT -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define ARCH_NAME "powerpc64le" -# else -# define ARCH_NAME "powerpc64" -# endif -# else -# define ARCH_32BIT -# define ARCH_NAME "powerpc" -# endif - -/* --------------- Less common architectures alphabetically below --------------- */ - -/* ALPHA */ -#elif defined(__alpha__) || defined(__alpha) -# define ARCH_ALPHA -# define ARCH_64BIT -# define ARCH_NAME "alpha" - -/* Blackfin */ -#elif defined(__BFIN__) -# define ARCH_BLACKFIN -# define ARCH_32BIT -# define ARCH_NAME "blackfin" - -/* Itanium */ -#elif defined(__ia64) || defined(_M_IA64) -# define ARCH_IA64 -# define ARCH_64BIT -# define ARCH_NAME "ia64" - -/* MIPS */ -#elif defined(__mips__) || defined(__mips) -# define ARCH_MIPS -# if defined(__mips64) || defined(__mips64__) -# define ARCH_64BIT -# define ARCH_NAME "mips64" -# else -# define ARCH_32BIT -# define ARCH_NAME "mips" -# endif - -/* Motorola 68000-series */ -#elif defined(__m68k__) -# define ARCH_M68K -# define ARCH_32BIT -# define ARCH_NAME "m68k" - -/* SuperH */ -#elif defined(__sh__) -# define ARCH_SH -# define ARCH_32BIT -# define ARCH_NAME "sh" - -/* SPARC */ -#elif defined(__sparc__) || defined(__sparc) -# define ARCH_SPARC -# if defined(__sparcv9) || defined(__sparc_v9__) || defined(__sparc64__) -# define ARCH_64BIT -# define ARCH_NAME "sparc9" -# elif defined(__sparcv8) || defined(__sparc_v8__) -# define ARCH_32BIT -# define ARCH_NAME "sparc8" -# else -# define ARCH_32BIT -# define ARCH_NAME "sparc" -# endif - -/* SystemZ / S390 */ -#elif defined(__s390x) || defined(__zarch__) -# define ARCH_S390 -# define ARCH_64BIT -# define ARCH_NAME "s390x" -#elif defined(__s390__) -# define ARCH_S390 -# define ARCH_32BIT -# define ARCH_NAME "s390" -#elif defined(__370__) -# define ARCH_S390 -# define ARCH_32BIT -# define ARCH_NAME "s370" - -/* PARISC */ -#elif defined(__hppa__) -# define ARCH_PARISC -# if defined(__hppa64__) || defined(__LP64__) -# define ARCH_64BIT -# define ARCH_NAME "parisc64" -# else -# define ARCH_32BIT -# define ARCH_NAME "parisc" -# endif - -/* RS-6000 */ -#elif defined(__THW_RS6000) -# define ARCH_RS6000 -# define ARCH_32BIT -# define ARCH_NAME "rs6000" - -/* RISC-V */ -#elif defined(__riscv) -# define ARCH_RISCV -# if __riscv_xlen == 64 -# define ARCH_64BIT -# define ARCH_NAME "riscv64" -# elif __riscv_xlen == 32 -# define ARCH_32BIT -# define ARCH_NAME "riscv32" -# else -# define ARCH_NAME "riscv" -# endif - -/* LOONGARCH */ -#elif defined(__loongarch_lp64) -# define ARCH_LOONGARCH -# define ARCH_64BIT -# define ARCH_NAME "loongarch64" - -/* Emscripten (WebAssembly) */ -#elif defined(__EMSCRIPTEN__) -# define ARCH_WASM -# if defined(__wasm64__) -# define ARCH_64BIT -# define ARCH_NAME "wasm64" -# else -# define ARCH_32BIT -# define ARCH_NAME "wasm32" -# endif - -/* Elbrus 2000 (aka e2k) */ -#elif defined(__e2k__) -# define ARCH_E2K -/* e2k reuse x86 optimizations */ -# define ARCH_X86 -# define ARCH_64BIT -# define ARCH_NAME "e2k" -# define ARCH_VERSION_STR ZARCH_STRINGIZE(__iset__) - -/* Unrecognized architecture */ -#else -# if defined(__LP64__) || defined(_LP64) || defined(_WIN64) -# define ARCH_64BIT -# else -# define ARCH_32BIT -# endif -# define ARCH_NAME "unrecognized" -#endif - -#endif /* ZARCH_H */ diff --git a/modules/zlib/src/zbuild.h b/modules/zlib/src/zbuild.h deleted file mode 100644 index 16a9d0d774..0000000000 --- a/modules/zlib/src/zbuild.h +++ /dev/null @@ -1,352 +0,0 @@ -#ifndef _ZBUILD_H -#define _ZBUILD_H - -#define _POSIX_SOURCE 1 /* fileno */ -#ifndef _POSIX_C_SOURCE -# define _POSIX_C_SOURCE 200809L /* snprintf, posix_memalign, strdup */ -#endif -#ifndef _ISOC11_SOURCE -# define _ISOC11_SOURCE 1 /* aligned_alloc */ -#endif -#ifdef __OpenBSD__ -# define _BSD_SOURCE 1 -#endif - -#include -#include -#include -#include -#include - -#include "zarch.h" - -/* Determine compiler version of C Standard */ -#ifdef __STDC_VERSION__ -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -# if __STDC_VERSION__ >= 201112L -# ifndef STDC11 -# define STDC11 -# endif -# endif -#endif - -#ifndef Z_HAS_ATTRIBUTE -# if defined(__has_attribute) -# define Z_HAS_ATTRIBUTE(a) __has_attribute(a) -# else -# define Z_HAS_ATTRIBUTE(a) 0 -# endif -#endif - -#ifndef Z_FALLTHROUGH -# if Z_HAS_ATTRIBUTE(__fallthrough__) || (defined(__GNUC__) && (__GNUC__ >= 7)) -# define Z_FALLTHROUGH __attribute__((__fallthrough__)) -# else -# define Z_FALLTHROUGH do {} while(0) /* fallthrough */ -# endif -#endif - -/* Hint to compiler that a block of code is unreachable, typically in a switch default condition */ -#ifndef Z_UNREACHABLE -# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L -# if !defined(unreachable) && defined(_MSC_VER) -# define Z_UNREACHABLE() __assume(0) -# else -# define Z_UNREACHABLE() unreachable() // C23 approach -# endif -# elif (defined(__GNUC__) && (__GNUC__ >= 5)) || defined(__clang__) -# define Z_UNREACHABLE() __builtin_unreachable() -# else -# define Z_UNREACHABLE() -# endif -#endif - -#ifndef Z_TARGET -# if Z_HAS_ATTRIBUTE(__target__) -# define Z_TARGET(x) __attribute__((__target__(x))) -# else -# define Z_TARGET(x) -# endif -#endif - -/* This has to be first include that defines any types */ -#if defined(_MSC_VER) -# if defined(_WIN64) - typedef __int64 ssize_t; -# else - typedef long ssize_t; -# endif - -# if defined(_WIN64) - #define SSIZE_MAX _I64_MAX -# else - #define SSIZE_MAX LONG_MAX -# endif -#endif - -/* A forced inline decorator */ -#if defined(_MSC_VER) -# define Z_FORCEINLINE __forceinline -#elif defined(__GNUC__) -# define Z_FORCEINLINE inline __attribute__((always_inline)) -#else - /* It won't actually force inlining but it will suggest it */ -# define Z_FORCEINLINE inline -#endif - -/* MS Visual Studio does not allow inline in C, only C++. - But it provides __inline instead, so use that. */ -#if defined(_MSC_VER) && !defined(inline) && !defined(__cplusplus) -# define inline __inline -#endif - -#if defined(ZLIB_COMPAT) -# define PREFIX(x) x -# define PREFIX2(x) ZLIB_ ## x -# define PREFIX3(x) z_ ## x -# define PREFIX4(x) x ## 64 -# define zVersion zlibVersion -#else -# define PREFIX(x) zng_ ## x -# define PREFIX2(x) ZLIBNG_ ## x -# define PREFIX3(x) zng_ ## x -# define PREFIX4(x) zng_ ## x -# define zVersion zlibng_version -# define z_size_t size_t -#endif - -/* In zlib-compat some functions and types use unsigned long, but zlib-ng use size_t */ -#if defined(ZLIB_COMPAT) -# define z_uintmax_t unsigned long -#else -# define z_uintmax_t size_t -#endif - -/* In zlib-compat headers some function return values and parameter types use int or unsigned, but zlib-ng headers use - int32_t and uint32_t, which will cause type mismatch when compiling zlib-ng if int32_t is long and uint32_t is - unsigned long */ -#if defined(ZLIB_COMPAT) -# define z_int32_t int -# define z_uint32_t unsigned int -#else -# define z_int32_t int32_t -# define z_uint32_t uint32_t -#endif - -/* Minimum of a and b. */ -#define MIN(a, b) ((a) > (b) ? (b) : (a)) -/* Maximum of a and b. */ -#define MAX(a, b) ((a) < (b) ? (b) : (a)) -/* Absolute value of a. */ -#define ABS(a) ((a) < 0 ? -(a) : (a)) -/* Ignore unused variable warning */ -#define Z_UNUSED(var) (void)(var) - -/* Force the compiler to treat variable as modified. Empty asm statement with a "+r" constraint prevents - the compiler from reordering or eliminating loads into the variable. This can help keep critical latency - chains in the hot path from being shortened or optimized away. */ -#if (defined(__GNUC__) || defined(__clang__)) && \ - (defined(ARCH_X86) || (defined(ARCH_ARM) && defined(ARCH_64BIT))) -# define Z_TOUCH(var) __asm__ ("" : "+r"(var)) -#else -# define Z_TOUCH(var) (void)(var) -#endif - -#if defined(HAVE_VISIBILITY_INTERNAL) -# define Z_INTERNAL __attribute__((visibility ("internal"))) -#elif defined(HAVE_VISIBILITY_HIDDEN) -# define Z_INTERNAL __attribute__((visibility ("hidden"))) -#else -# define Z_INTERNAL -#endif - -/* Symbol versioning helpers, allowing multiple versions of a function to exist. - * Functions using this must also be added to zlib-ng.map for each version. - * Double @@ means this is the default for newly compiled applications to link against. - * Single @ means this is kept for backwards compatibility. - * This is only used for Zlib-ng native API, and only on platforms supporting this. - */ -#if defined(HAVE_SYMVER) -# define ZSYMVER(func,alias,ver) __asm__(".symver " func ", " alias "@ZLIB_NG_" ver); -# define ZSYMVER_DEF(func,alias,ver) __asm__(".symver " func ", " alias "@@ZLIB_NG_" ver); -#else -# define ZSYMVER(func,alias,ver) -# define ZSYMVER_DEF(func,alias,ver) -#endif - -#ifndef __cplusplus -# define Z_REGISTER register -#else -# define Z_REGISTER -#endif - -#if defined(_MSC_VER) -# define Z_RESTRICT __restrict -#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -# define Z_RESTRICT restrict -#else -# define Z_RESTRICT __restrict__ -#endif - -/* Reverse the bytes in a value. Use compiler intrinsics when - possible to take advantage of hardware implementations. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) -# include -# pragma intrinsic(_byteswap_ulong) -# define ZSWAP16(q) _byteswap_ushort(q) -# define ZSWAP32(q) _byteswap_ulong(q) -# define ZSWAP64(q) _byteswap_uint64(q) - -#elif defined(__clang__) || (defined(__GNUC__) && \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) -# define ZSWAP16(q) __builtin_bswap16(q) -# define ZSWAP32(q) __builtin_bswap32(q) -# define ZSWAP64(q) __builtin_bswap64(q) - -#elif defined(__GNUC__) && (__GNUC__ >= 2) && defined(__linux__) -# include -# define ZSWAP16(q) bswap_16(q) -# define ZSWAP32(q) bswap_32(q) -# define ZSWAP64(q) bswap_64(q) - -#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) -# include -# define ZSWAP16(q) bswap16(q) -# define ZSWAP32(q) bswap32(q) -# define ZSWAP64(q) bswap64(q) -#elif defined(__OpenBSD__) -# include -# define ZSWAP16(q) swap16(q) -# define ZSWAP32(q) swap32(q) -# define ZSWAP64(q) swap64(q) -#elif defined(__INTEL_COMPILER) -/* ICC does not provide a two byte swap. */ -# define ZSWAP16(q) ((((q) & 0xff) << 8) | (((q) & 0xff00) >> 8)) -# define ZSWAP32(q) _bswap(q) -# define ZSWAP64(q) _bswap64(q) - -#else -# define ZSWAP16(q) ((((q) & 0xff) << 8) | (((q) & 0xff00) >> 8)) -# define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) -# define ZSWAP64(q) \ - (((q & 0xFF00000000000000u) >> 56u) | \ - ((q & 0x00FF000000000000u) >> 40u) | \ - ((q & 0x0000FF0000000000u) >> 24u) | \ - ((q & 0x000000FF00000000u) >> 8u) | \ - ((q & 0x00000000FF000000u) << 8u) | \ - ((q & 0x0000000000FF0000u) << 24u) | \ - ((q & 0x000000000000FF00u) << 40u) | \ - ((q & 0x00000000000000FFu) << 56u)) -#endif - -/* Only enable likely/unlikely if the compiler is known to support it */ -#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__INTEL_COMPILER) || defined(__clang__) -# define LIKELY_NULL(x) __builtin_expect((x) != 0, 0) -# define LIKELY(x) __builtin_expect(!!(x), 1) -# define UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -# define LIKELY_NULL(x) x -# define LIKELY(x) x -# define UNLIKELY(x) x -#endif /* (un)likely */ - -#if defined(HAVE_ATTRIBUTE_ALIGNED) -# define ALIGNED_(x) __attribute__ ((aligned(x))) -#elif defined(_MSC_VER) -# define ALIGNED_(x) __declspec(align(x)) -#else -/* TODO: Define ALIGNED_ for your compiler */ -# define ALIGNED_(x) -#endif - -#ifdef HAVE_BUILTIN_ASSUME_ALIGNED -# define HINT_ALIGNED(p,n) __builtin_assume_aligned((void *)(p),(n)) -#else -# define HINT_ALIGNED(p,n) (p) -#endif -#define HINT_ALIGNED_16(p) HINT_ALIGNED((p),16) -#define HINT_ALIGNED_64(p) HINT_ALIGNED((p),64) -#define HINT_ALIGNED_4096(p) HINT_ALIGNED((p),4096) - -/* Number of bytes needed to align ptr to the next alignment boundary */ -#define ALIGN_DIFF(ptr, align) \ - (((uintptr_t)(align) - ((uintptr_t)(ptr) & ((align) - 1))) & ((align) - 1)) - -/* Round up value to the nearest multiple of align (align must be power of 2) */ -#define ALIGN_UP(value, align) \ - (((value) + ((align) - 1)) & ~((align) - 1)) - -/* Round down value to the nearest multiple of align (align must be power of 2) */ -#define ALIGN_DOWN(value, align) \ - ((value) & ~((align) - 1)) - -/* PADSZ returns needed bytes to pad bpos to pad size - * PAD_NN calculates pad size and adds it to bpos, returning the result. - * All take an integer or a pointer as bpos input. - */ -#define PADSZ(bpos, pad) (((pad) - ((uintptr_t)(bpos) % (pad))) % (pad)) -#define PAD_16(bpos) ((bpos) + PADSZ((bpos),16)) -#define PAD_64(bpos) ((bpos) + PADSZ((bpos),64)) -#define PAD_4096(bpos) ((bpos) + PADSZ((bpos),4096)) - -/* Diagnostic functions */ -#ifdef ZLIB_DEBUG - extern int Z_INTERNAL z_verbose; - extern void Z_INTERNAL z_error(const char *m); -# define Assert(cond, msg) {int _cond = (cond); if (!(_cond)) z_error(msg);} -# define Trace(x) {if (z_verbose >= 0) fprintf x;} -# define Tracev(x) {if (z_verbose > 0) fprintf x;} -# define Tracevv(x) {if (z_verbose > 1) fprintf x;} -# define Tracec(c, x) {if (z_verbose > 0 && (c)) fprintf x;} -# define Tracecv(c, x) {if (z_verbose > 1 && (c)) fprintf x;} -#else -# define Assert(cond, msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c, x) -# define Tracecv(c, x) -#endif - -/* OPTIMAL_CMP values determine the comparison width: - * 64: Best for 64-bit architectures with unaligned access - * 32: Best for 32-bit architectures with unaligned access - * 16: Safe default for unknown architectures - * 8: Safe fallback for architectures without unaligned access - * Note: The unaligned access mentioned is cpu-support, this allows compiler or - * separate unaligned intrinsics to utilize safe unaligned access, without - * utilizing unaligned C pointers that are known to have undefined behavior. - */ -#if !defined(OPTIMAL_CMP) -# ifdef ARCH_64BIT -# ifdef ARCH_ARM -# if defined(__ARM_FEATURE_UNALIGNED) || defined(_WIN32) -# define OPTIMAL_CMP 64 -# else -# define OPTIMAL_CMP 8 -# endif -# else -# define OPTIMAL_CMP 64 -# endif -# elif defined(ARCH_32BIT) -# ifdef ARCH_ARM -# if defined(__ARM_FEATURE_UNALIGNED) || defined(_WIN32) -# define OPTIMAL_CMP 32 -# else -# define OPTIMAL_CMP 8 -# endif -# else -# define OPTIMAL_CMP 32 -# endif -# endif -#endif -#if !defined(OPTIMAL_CMP) -# define OPTIMAL_CMP 16 -#endif - -#endif diff --git a/modules/zlib/src/zconf.h b/modules/zlib/src/zconf.h index c0df900e40..e8ccda91c7 100644 --- a/modules/zlib/src/zconf.h +++ b/modules/zlib/src/zconf.h @@ -1,207 +1,536 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ZCONF_H -#define ZCONF_H - -#include "mozzconf.h" -#include "zlib_name_mangling.h" - -#if !defined(_WIN32) && defined(__WIN32__) -# define _WIN32 -#endif - -/* Clang macro for detecting declspec support - * https://clang.llvm.org/docs/LanguageExtensions.html#has-declspec-attribute - */ -#ifndef __has_declspec_attribute -# define __has_declspec_attribute(x) 0 -#endif - -#if defined(ZLIB_CONST) && !defined(z_const) -# define z_const const -#else -# define z_const -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# define MAX_MEM_LEVEL 9 -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MIN_WBITS -# define MIN_WBITS 8 /* 256 LZ77 window */ -#endif -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus about 7 kilobytes - for small objects. -*/ - -/* Type declarations */ - - -#ifndef OF /* function prototypes */ -# define OF(args) args -#endif - -#ifdef ZLIB_INTERNAL -# define Z_INTERNAL ZLIB_INTERNAL -#endif - -/* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -#if defined(ZLIB_DLL) && (defined(_WIN32) || (__has_declspec_attribute(dllexport) && __has_declspec_attribute(dllimport))) -# ifdef Z_INTERNAL -# define Z_EXTERN extern __declspec(dllexport) -# else -# define Z_EXTERN extern __declspec(dllimport) -# endif -#endif - -/* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -#if defined(ZLIB_WINAPI) && defined(_WIN32) -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define Z_EXPORT WINAPI -# define Z_EXPORTVA WINAPIV -#endif - -#ifndef Z_EXTERN -# define Z_EXTERN extern -#endif -#ifndef Z_EXPORT -# define Z_EXPORT -#endif -#ifndef Z_EXPORTVA -# define Z_EXPORTVA -#endif - -/* Conditional exports */ -#define ZNG_CONDEXPORT Z_INTERNAL - -/* For backwards compatibility */ - -#ifndef ZEXTERN -# define ZEXTERN Z_EXTERN -#endif -#ifndef ZEXPORT -# define ZEXPORT Z_EXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA Z_EXPORTVA -#endif -#ifndef FAR -# define FAR -#endif - -/* Legacy zlib typedefs for backwards compatibility. Don't assume stdint.h is defined. */ -typedef unsigned char Byte; -typedef Byte Bytef; - -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -typedef char charf; -typedef int intf; -typedef uInt uIntf; -typedef uLong uLongf; - -typedef void const *voidpc; -typedef void *voidpf; -typedef void *voidp; - -typedef unsigned int z_crc_t; - -#if !defined(_WIN32) /* was set by configure/cmake; avoid on MSVC */ -# define Z_HAVE_UNISTD_H -#endif - -#ifdef NEED_PTRDIFF_T /* may be set to #if 1 by configure/cmake/etc */ -typedef PTRDIFF_TYPE ptrdiff_t; -#endif - -#include /* for off_t */ - -#include /* for wchar_t and NULL */ - -/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and - * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even - * though the former does not conform to the LFS document), but considering - * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as - * equivalently requesting no 64-bit operations - */ -#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 -# undef _LARGEFILE64_SOURCE -#endif - -#if defined(Z_HAVE_UNISTD_H) -# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ -# ifndef z_off_t -# define z_off_t off_t -# endif -#endif - -#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 -# define Z_LFS64 -#endif - -#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) -# define Z_LARGE64 -#endif - -#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) -# define Z_WANT64 -#endif - -#if !defined(SEEK_SET) -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif - -#ifndef z_off_t -# define z_off_t long -#endif - -#if !defined(_WIN32) && defined(Z_LARGE64) -# define z_off64_t off64_t -#else -# if defined(__MSYS__) -# define z_off64_t _off64_t -# elif defined(_WIN32) && !defined(__GNUC__) -# define z_off64_t __int64 -# else -# define z_off64_t z_off_t -# endif -#endif - -typedef size_t z_size_t; - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +#include "mozzconf.h" + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#if !defined(_WIN32) +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/modules/zlib/src/zendian.h b/modules/zlib/src/zendian.h deleted file mode 100644 index c72ee28ab9..0000000000 --- a/modules/zlib/src/zendian.h +++ /dev/null @@ -1,90 +0,0 @@ -/* zendian.h -- define BYTE_ORDER for endian tests - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ENDIAN_H_ -#define ENDIAN_H_ - -/* First check whether the compiler knows the target __BYTE_ORDER__. */ -#if defined(__BYTE_ORDER__) -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# if !defined(LITTLE_ENDIAN) -# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ -# endif -# if !defined(BYTE_ORDER) -# define BYTE_ORDER LITTLE_ENDIAN -# endif -# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# if !defined(BIG_ENDIAN) -# define BIG_ENDIAN __ORDER_BIG_ENDIAN__ -# endif -# if !defined(BYTE_ORDER) -# define BYTE_ORDER BIG_ENDIAN -# endif -# endif -#elif defined(__MINGW32__) -# include -#elif defined(_WIN32) -# define LITTLE_ENDIAN 1234 -# define BIG_ENDIAN 4321 -# if defined(ARCH_X86) || defined(ARCH_IA64) || defined(ARCH_ARM) -# define BYTE_ORDER LITTLE_ENDIAN -# else -# error Unknown endianness! -# endif -#elif defined(__linux__) -# include -#elif defined(__APPLE__) -# include -#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) -# include -#elif defined(__sun) || defined(sun) -# include -# if !defined(LITTLE_ENDIAN) -# define LITTLE_ENDIAN 4321 -# endif -# if !defined(BIG_ENDIAN) -# define BIG_ENDIAN 1234 -# endif -# if !defined(BYTE_ORDER) -# if defined(_BIG_ENDIAN) -# define BYTE_ORDER BIG_ENDIAN -# else -# define BYTE_ORDER LITTLE_ENDIAN -# endif -# endif -#else -# include -#endif - -#if BYTE_ORDER == LITTLE_ENDIAN -# define Z_U16_TO_LE(x) (x) -# define Z_U32_TO_LE(x) (x) -# define Z_U64_TO_LE(x) (x) -# define Z_U16_FROM_LE(x) (x) -# define Z_U32_FROM_LE(x) (x) -# define Z_U64_FROM_LE(x) (x) -# define Z_U16_TO_BE(x) ZSWAP16(x) -# define Z_U32_TO_BE(x) ZSWAP32(x) -# define Z_U64_TO_BE(x) ZSWAP64(x) -# define Z_U16_FROM_BE(x) ZSWAP16(x) -# define Z_U32_FROM_BE(x) ZSWAP32(x) -# define Z_U64_FROM_BE(x) ZSWAP64(x) -#elif BYTE_ORDER == BIG_ENDIAN -# define Z_U16_TO_LE(x) ZSWAP16(x) -# define Z_U32_TO_LE(x) ZSWAP32(x) -# define Z_U64_TO_LE(x) ZSWAP64(x) -# define Z_U16_FROM_LE(x) ZSWAP16(x) -# define Z_U32_FROM_LE(x) ZSWAP32(x) -# define Z_U64_FROM_LE(x) ZSWAP64(x) -# define Z_U16_TO_BE(x) (x) -# define Z_U32_TO_BE(x) (x) -# define Z_U64_TO_BE(x) (x) -# define Z_U16_FROM_BE(x) (x) -# define Z_U32_FROM_BE(x) (x) -# define Z_U64_FROM_BE(x) (x) -#else -# error "Unknown byte order" -#endif - -#endif diff --git a/modules/zlib/src/zlib.h b/modules/zlib/src/zlib.h index 8ce88e4f3e..99fd467f6b 100644 --- a/modules/zlib/src/zlib.h +++ b/modules/zlib/src/zlib.h @@ -1,1859 +1,1935 @@ -#ifndef ZLIB_H_ -#define ZLIB_H_ -/* zlib.h -- interface of the 'zlib-ng' compression library - Forked from and compatible with zlib 1.3.1 - - Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files https://tools.ietf.org/html/rfc1950 - (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). -*/ - -#ifdef ZNGLIB_H_ -# error Include zlib-ng.h for zlib-ng API or zlib.h for zlib-compat API but not both -#endif - -#ifndef RC_INVOKED -#include -#include - -#include "zconf.h" - -#ifndef ZCONF_H -# error Missing zconf.h add binary output directory to include directories -#endif -#endif /* RC_INVOKED */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIBNG_VERSION "2.3.90" -#define ZLIBNG_VERNUM 0x02039000L /* MMNNRRSM: major minor revision status modified */ -#define ZLIBNG_VER_MAJOR 2 -#define ZLIBNG_VER_MINOR 3 -#define ZLIBNG_VER_REVISION 90 -#define ZLIBNG_VER_STATUS 0 /* 0=devel, 1-E=beta, F=Release (DEPRECATED) */ -#define ZLIBNG_VER_STATUSH 0x0 /* Hex values: 0=devel, 1-9=beta, A-E=Release Candidate, F=Release */ -#define ZLIBNG_VER_MODIFIED 0 /* non-zero if modified externally from zlib-ng */ - -#define ZLIB_VERSION "1.3.1.zlib-ng" -#define ZLIB_VERNUM 0x131f -#define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 3 -#define ZLIB_VER_REVISION 1 -#define ZLIB_VER_SUBREVISION 15 /* 15=fork (0xf) */ - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed data. - This version of the library supports only one compression method (deflation) - but other algorithms will be added later and will have the same stream - interface. - - Compression can be done in a single step if the buffers are large enough, - or can be done by repeated calls of the compression function. In the latter - case, the application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip and raw deflate streams in - memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never crash - even in the case of corrupted input. -*/ - -typedef void *(*alloc_func) (void *opaque, unsigned int items, unsigned int size); -typedef void (*free_func) (void *opaque, void *address); - -struct internal_state; - -typedef struct z_stream_s { - z_const unsigned char *next_in; /* next input byte */ - uint32_t avail_in; /* number of bytes available at next_in */ - unsigned long total_in; /* total number of input bytes read so far */ - - unsigned char *next_out; /* next output byte will go here */ - uint32_t avail_out; /* remaining free space at next_out */ - unsigned long total_out; /* total number of bytes output so far */ - - z_const char *msg; /* last error message, NULL if no error */ - struct internal_state *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - void *opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text - for deflate, or the decoding state for inflate */ - unsigned long adler; /* Adler-32 or CRC-32 value of the uncompressed data */ - unsigned long reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream *z_streamp; /* Obsolete type, retained for compatibility only */ - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - unsigned long time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - unsigned char *extra; /* pointer to extra field or NULL if none */ - unsigned int extra_len; /* extra field length (valid if extra != NULL) */ - unsigned int extra_max; /* space at extra (only when reading header) */ - unsigned char *name; /* pointer to zero-terminated file name or NULL */ - unsigned int name_max; /* space at name (only when reading header) */ - unsigned char *comment; /* pointer to zero-terminated comment or NULL */ - unsigned int comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used when writing a gzip file) */ -} gz_header; - -typedef gz_header *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has dropped - to zero. It must update next_out and avail_out when avail_out has dropped - to zero. The application must initialize zalloc, zfree and opaque before - calling the init function. All other fields are set by the compression - library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. In that case, zlib is thread-safe. When zalloc and zfree are - Z_NULL on entry to the initialization function, they are set to internal - routines that use the standard library functions malloc() and free(). - - The fields total_in and total_out can be used for statistics or progress - reports. After compression, total_in holds the total size of the - uncompressed data and may be saved for use by the decompressor (particularly - if the decompressor wants to decompress everything in a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -#define Z_TREES 6 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field for deflate() */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for compatibility with zlib, was for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - - /* basic functions */ - -Z_EXTERN const char * Z_EXPORT zlibVersion(void); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is not - compatible with the zlib.h header file used by the application. This check - is automatically made by deflateInit and inflateInit. - */ - -/* -Z_EXTERN int Z_EXPORT deflateInit (z_stream *strm, int level); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. If - zalloc and zfree are set to Z_NULL, deflateInit updates them to use default - allocation functions. total_in, total_out, adler, and msg are initialized. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at all - (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION - requests a default compromise between speed and compression (currently - equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if level is not a valid compression level, or - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). msg is set to null - if there is no error message. deflateInit does not perform any compression: - this will be done by deflate(). -*/ - - -Z_EXTERN int Z_EXPORT deflate(z_stream *strm, int flush); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Generate more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary. Some output may be provided even if - flush is zero. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming more - output, and updating avail_in or avail_out accordingly; avail_out should - never be zero before the call. The application can consume the compressed - output when it wants, for example when the output buffer is full (avail_out - == 0), or after each call of deflate(). If deflate returns Z_OK and with - zero avail_out, it must be called again after making room in the output - buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more output - in that case. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumulate before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In - particular avail_in is zero after the call if enough output space has been - provided before the call.) Flushing may degrade compression for some - compression algorithms and so it should be used only when necessary. This - completes the current deflate block and follows it with an empty stored block - that is three bits plus filler bits to the next byte, followed by four bytes - (00 00 ff ff). - - If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the - output buffer, but the output is not aligned to a byte boundary. All of the - input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. - This completes the current deflate block and follows it with an empty fixed - codes block that is 10 bits long. This assures that enough bytes are output - in order for the decompressor to finish the block before the empty fixed - codes block. - - If flush is set to Z_BLOCK, a deflate block is completed and emitted, as - for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to - seven bits of the current block are held to be written as the next byte after - the next deflate block is completed. In this case, the decompressor may not - be provided enough bits at this point in order to complete decompression of - the data provided so far to the compressor. It may need to wait for the next - block to be emitted. This is for advanced applications that need to control - the emission of deflate blocks. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six when the flush marker begins, in order to avoid - repeated flush markers upon calling deflate() again when avail_out == 0. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there was - enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this - function must be called again with Z_FINISH and more output space (updated - avail_out) but no more input data, until it returns with Z_STREAM_END or an - error. After deflate has returned Z_STREAM_END, the only possible operations - on the stream are deflateReset or deflateEnd. - - Z_FINISH can be used in the first deflate call after deflateInit if all the - compression is to be done in a single step. In order to complete in one - call, avail_out must be at least the value returned by deflateBound (see - below). Then deflate is guaranteed to return Z_STREAM_END. If not enough - output space is provided, deflate will not return Z_STREAM_END, and it must - be called again as described above. - - deflate() sets strm->adler to the Adler-32 checksum of all input read - so far (that is, total_in bytes). If a gzip stream is being generated, then - strm->adler will be the CRC-32 checksum of the input read so far. (See - deflateInit2 below.) - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is - considered binary. This field is only for information purposes and does not - affect the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL) or the state was inadvertently written over - by the application), or Z_BUF_ERROR if no progress is possible (for example - avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and - deflate() can be called again with more input and more output space to - continue compressing. -*/ - - -Z_EXTERN int Z_EXPORT deflateEnd(z_stream *strm); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any pending - output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, msg - may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -Z_EXTERN int Z_EXPORT inflateInit (z_stream *strm); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. In the current version of inflate, the provided input is not - read or consumed. The allocation of a sliding window will be deferred to - the first call of inflate (if the decompression does not complete on the - first call). If zalloc and zfree are set to Z_NULL, inflateInit updates - them to use default allocation functions. total_in, total_out, adler, and - msg are initialized. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller, or Z_STREAM_ERROR if the parameters are - invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit does not perform any decompression. - Actual decompression will be done by inflate(). So next_in, and avail_in, - next_out, and avail_out are unused and unchanged. The current - implementation of inflateInit() does not process any header information -- - that is deferred until inflate() is called. -*/ - - -Z_EXTERN int Z_EXPORT inflate(z_stream *strm, int flush); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), then next_in and avail_in are updated - accordingly, and processing will resume at this point for the next call of - inflate(). - - - Generate more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there is - no more input data or no more space in the output buffer (see below about - the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming more - output, and updating the next_* and avail_* values accordingly. If the - caller of inflate() does not provide both available input and available - output space, it is possible that there will be no progress made. The - application can consume the uncompressed output when it wants, for example - when the output buffer is full (avail_out == 0), or after each call of - inflate(). If inflate returns Z_OK and with zero avail_out, it must be - called again after making room in the output buffer because there might be - more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, - Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() - stop if and when it gets to the next deflate block boundary. When decoding - the zlib or gzip format, this will cause inflate() to return immediately - after the header and before the first block. When doing a raw inflate, - inflate() will go ahead and process the first block, and will return when it - gets to the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - To assist in this, on return inflate() always sets strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 if - inflate() is currently decoding the last block in the deflate stream, plus - 128 if inflate() returned immediately after decoding an end-of-block code or - decoding the complete header up to just before the first byte of the deflate - stream. The end-of-block will not be indicated until all of the uncompressed - data from that block has been written to strm->next_out. The number of - unused bits may in general be greater than seven, except when bit 7 of - data_type is set, in which case the number of unused bits will be less than - eight. data_type is set as noted here every time inflate() returns for all - flush options, and so can be used to determine the amount of currently - consumed input in bits. - - The Z_TREES option behaves as Z_BLOCK does, but it also returns when the - end of each deflate block header is reached, before any actual data in that - block is decoded. This allows the caller to determine the length of the - deflate block header for later use in random access within a deflate block. - 256 is added to the value of strm->data_type when inflate() returns - immediately after reaching the end of the deflate block header. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step (a - single call of inflate), the parameter flush should be set to Z_FINISH. In - this case all pending input is processed and all pending output is flushed; - avail_out must be large enough to hold all of the uncompressed data for the - operation to complete. (The size of the uncompressed data may have been - saved by the compressor for this purpose.) The use of Z_FINISH is not - required to perform an inflation in one step. However it may be used to - inform inflate that a faster approach can be used for the single inflate() - call. Z_FINISH also informs inflate to not maintain a sliding window if the - stream completes, which reduces inflate's memory footprint. If the stream - does not complete, either because not all of the stream is provided or not - enough output space is provided, then a sliding window will be allocated and - inflate() can be called again to continue the operation as if Z_NO_FLUSH had - been used. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the effects of the flush parameter in this implementation are - on the return value of inflate() as noted below, when inflate() returns early - when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of - memory for a sliding window when Z_FINISH is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the Adler-32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the Adler-32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed Adler-32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() can decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically, if requested when - initializing with inflateInit2(). Any information contained in the gzip - header is not retained unless inflateGetHeader() is used. When processing - gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output - produced so far. The CRC-32 is checked against the gzip trailer, as is the - uncompressed length, modulo 2^32. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value, in which case strm->msg points to a string with a more specific - error), Z_STREAM_ERROR if the stream structure was inconsistent (for example - next_in or next_out was NULL, or the state was inadvertently written over - by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR - if no progress is possible or if there was not enough room in the output - buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may - then call inflateSync() to look for a good compression block if a partial - recovery of the data is to be attempted. -*/ - - -Z_EXTERN int Z_EXPORT inflateEnd(z_stream *strm); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any pending - output. - - inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state - was inconsistent. -*/ - - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -Z_EXTERN int Z_EXPORT deflateInit2 (z_stream *strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy); - - This is another version of deflateInit with more compression options. The - fields zalloc, zfree and opaque must be initialized before by the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - For the current implementation of deflate(), a windowBits value of 8 (a - window size of 256 bytes) is not supported. As a result, a request for 8 - will result in 9 (a 512-byte window). In that case, providing 8 to - inflateInit2() will result in an error when the zlib header with 9 is - checked against the initialization of inflate(). The remedy is to not use 8 - with deflateInit2() with this initialization, or at least in that case use 9 - with inflateInit2(). - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute a check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), no - header crc, and the operating system will be set to the appropriate value, - if the operating system was determined at compile time. If a gzip stream is - being written, strm->adler is a CRC-32 instead of an Adler-32. - - For raw deflate or gzip encoding, a request for a 256-byte window is - rejected as invalid, since only the zlib header provides a means of - transmitting the window size to the decompressor. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but is - slow and reduces compression ratio; memLevel=9 uses maximum memory for - optimal speed. The default value is 8. See zconf.h for total memory usage - as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as - fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The - strategy parameter only affects the compression ratio but not the - correctness of the compressed output even if it is not set appropriately. - Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler - decoder for special applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid - method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is - incompatible with the version assumed by the caller (ZLIB_VERSION). msg is - set to null if there is no error message. deflateInit2 does not perform any - compression: this will be done by deflate(). -*/ - -Z_EXTERN int Z_EXPORT deflateSetDictionary(z_stream *strm, - const unsigned char *dictionary, - unsigned int dictLength); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. When using the zlib format, this - function must be called immediately after deflateInit, deflateInit2 or - deflateReset, and before any call of deflate. When doing raw deflate, this - function must be called either before any call of deflate, or immediately - after the completion of a deflate block, i.e. after all input has been - consumed and all output has been delivered when using any of the flush - options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The - compressor and decompressor must use exactly the same dictionary (see - inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size - provided in deflateInit or deflateInit2. Thus the strings most likely to be - useful should be put at the end of the dictionary, not at the front. In - addition, the current implementation of deflate will use at most the window - size minus 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the Adler-32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler-32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - Adler-32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (e.g. dictionary being NULL) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if not at a block boundary for raw deflate). deflateSetDictionary does - not perform any compression: this will be done by deflate(). -*/ - -Z_EXTERN int Z_EXPORT deflateGetDictionary (z_stream *strm, unsigned char *dictionary, unsigned int *dictLength); -/* - Returns the sliding dictionary being maintained by deflate. dictLength is - set to the number of bytes in the dictionary, and that many bytes are copied - to dictionary. dictionary must have enough space, where 32768 bytes is - always enough. If deflateGetDictionary() is called with dictionary equal to - Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similarly, if dictLength is Z_NULL, then it is not set. - - deflateGetDictionary() may return a length less than the window size, even - when more than the window size in input has been provided. It may return up - to 258 bytes less in that case, due to how zlib's implementation of deflate - manages the sliding window and lookahead for matches, where matches can be - up to 258 bytes long. If the application needs the last window-size bytes of - input, then that would need to be saved by the application outside of zlib. - - deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the - stream state is inconsistent. -*/ - -Z_EXTERN int Z_EXPORT deflateCopy(z_stream *dest, z_stream *source); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and can - consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -Z_EXTERN int Z_EXPORT deflateReset(z_stream *strm); -/* - This function is equivalent to deflateEnd followed by deflateInit, but - does not free and reallocate the internal compression state. The stream - will leave the compression level and any other attributes that may have been - set unchanged. total_in, total_out, adler, and msg are initialized. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -Z_EXTERN int Z_EXPORT deflateParams(z_stream *strm, int level, int strategy); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2(). This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different strategy. - If the compression approach (which is a function of the level) or the - strategy is changed, and if there have been any deflate() calls since the - state was initialized or reset, then the input available so far is - compressed with the old level and strategy using deflate(strm, Z_BLOCK). - There are three approaches for the compression levels 0, 1..3, and 4..9 - respectively. The new level and strategy will take effect at the next call - of deflate(). - - If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does - not have enough output space to complete, then the parameter change will not - take effect. In this case, deflateParams() can be called again with the - same parameters and more output space to try again. - - In order to assure a change in the parameters on the first try, the - deflate stream should be flushed using deflate() with Z_BLOCK or other flush - request until strm.avail_out is not zero, before calling deflateParams(). - Then no more input data should be provided before the deflateParams() call. - If this is done, the old level and strategy will be applied to the data - compressed before deflateParams(), and the new level and strategy will be - applied to the data compressed after deflateParams(). - - deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream - state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if - there was not enough output space to complete the compression of the - available input data before a change in the strategy or approach. Note that - in the case of a Z_BUF_ERROR, the parameters are not changed. A return - value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be - retried with more output space. -*/ - -Z_EXTERN int Z_EXPORT deflateTune(z_stream *strm, int good_length, int max_lazy, int nice_length, int max_chain); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -Z_EXTERN unsigned long Z_EXPORT deflateBound(z_stream *strm, unsigned long sourceLen); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() or - deflateInit2(), and after deflateSetHeader(), if used. This would be used - to allocate an output buffer for deflation in a single pass, and so would be - called before deflate(). If that first deflate() call is provided the - sourceLen input bytes, an output buffer allocated to the size returned by - deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed - to return Z_STREAM_END. Note that it is possible for the compressed size to - be larger than the value returned by deflateBound() if flush options other - than Z_FINISH or Z_NO_FLUSH are used. -*/ - -Z_EXTERN int Z_EXPORT deflatePending(z_stream *strm, uint32_t *pending, int *bits); -/* - deflatePending() returns the number of bytes and bits of output that have - been generated, but not yet provided in the available output. The bytes not - provided would be due to the available output space having being consumed. - The number of bits of output not provided are between 0 and 7, where they - await more bits to join them in order to fill out a full byte. If pending - or bits are NULL, then those values are not set. - - deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. - */ - -Z_EXTERN int Z_EXPORT deflatePrime(z_stream *strm, int bits, int value); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the bits - leftover from a previous deflate stream when appending to it. As such, this - function can only be used for raw deflate, and must be used before the first - deflate() call after a deflateInit2() or deflateReset(). bits must be less - than or equal to 16, and that many of the least significant bits of value - will be inserted in the output. - - deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough - room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the - source stream state was inconsistent. -*/ - -Z_EXTERN int Z_EXPORT deflateSetHeader(z_stream *strm, gz_headerp head); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not NULL, name and comment are terminated with - a zero byte, and that if extra is not NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to the current operating system, with no - extra, name, or comment fields. The gzip header is returned to the default - state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -Z_EXTERN int Z_EXPORT inflateInit2(z_stream *strm, int windowBits); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be zero to request that inflate use the window size in - the zlib header of the compressed stream. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an Adler-32 or a CRC-32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a - CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see - below), inflate() will *not* automatically decode concatenated gzip members. - inflate() will return Z_STREAM_END at the end of the gzip member. The state - would need to be reset to continue decoding a subsequent gzip member. This - *must* be done if there is more data after a gzip member, in order for the - decompression to be compliant with the gzip standard (RFC 1952). - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller, or Z_STREAM_ERROR if the parameters are - invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit2 does not perform any decompression - apart from possibly reading the zlib header if present: actual decompression - will be done by inflate(). (So next_in and avail_in may be modified, but - next_out and avail_out are unused and unchanged.) The current implementation - of inflateInit2() does not process any header information -- that is - deferred until inflate() is called. -*/ - -Z_EXTERN int Z_EXPORT inflateSetDictionary(z_stream *strm, const unsigned char *dictionary, unsigned int dictLength); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler-32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called at any - time to set the dictionary. If the provided dictionary is smaller than the - window and there is already data in the window, then the provided dictionary - will amend what's there. The application must ensure that the dictionary - that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (e.g. dictionary being NULL) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler-32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -Z_EXTERN int Z_EXPORT inflateGetDictionary(z_stream *strm, unsigned char *dictionary, unsigned int *dictLength); -/* - Returns the sliding dictionary being maintained by inflate. dictLength is - set to the number of bytes in the dictionary, and that many bytes are copied - to dictionary. dictionary must have enough space, where 32768 bytes is - always enough. If inflateGetDictionary() is called with dictionary equal to - NULL, then only the dictionary length is returned, and nothing is copied. - Similarly, if dictLength is NULL, then it is not set. - - inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the - stream state is inconsistent. -*/ - -Z_EXTERN int Z_EXPORT inflateSync(z_stream *strm); -/* - Skips invalid compressed data until a possible full flush point (see above - for the description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync searches for a 00 00 FF FF pattern in the compressed data. - All full flush points have this pattern, but not all occurrences of this - pattern are full flush points. - - inflateSync returns Z_OK if a possible full flush point has been found, - Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point - has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. - In the success case, the application may save the current value of - total_in which indicates where valid compressed data was found. In the - error case, the application may repeatedly call inflateSync, providing more - input each time, until success or end of the input data. -*/ - -Z_EXTERN int Z_EXPORT inflateCopy(z_stream *dest, z_stream *source); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -Z_EXTERN int Z_EXPORT inflateReset(z_stream *strm); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate the internal decompression state. The - stream will keep attributes that may have been set by inflateInit2. - total_in, total_out, adler, and msg are initialized. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -Z_EXTERN int Z_EXPORT inflateReset2(z_stream *strm, int windowBits); -/* - This function is the same as inflateReset, but it also permits changing - the wrap and window size requests. The windowBits parameter is interpreted - the same as it is for inflateInit2. If the window size is changed, then the - memory allocated for the window is freed, and the window will be reallocated - by inflate() if needed. - - inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL), or if - the windowBits parameter is invalid. -*/ - -Z_EXTERN int Z_EXPORT inflatePrime(z_stream *strm, int bits, int value); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - If bits is negative, then the input stream bit buffer is emptied. Then - inflatePrime() can be called again to put bits in the buffer. This is used - to clear out bits leftover after feeding inflate a block description prior - to feeding inflate codes. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -Z_EXTERN long Z_EXPORT inflateMark(z_stream *strm); -/* - This function returns two values, one in the lower 16 bits of the return - value, and the other in the remaining upper bits, obtained by shifting the - return value down 16 bits. If the upper value is -1 and the lower value is - zero, then inflate() is currently decoding information outside of a block. - If the upper value is -1 and the lower value is non-zero, then inflate is in - the middle of a stored block, with the lower value equaling the number of - bytes from the input remaining to copy. If the upper value is not -1, then - it is the number of bits back from the current bit position in the input of - the code (literal or length/distance pair) currently being processed. In - that case the lower value is the number of bytes already emitted for that - code. - - A code is being processed if inflate is waiting for more input to complete - decoding of the code, or if it has completed decoding but is waiting for - more output space to write the literal or match data. - - inflateMark() is used to mark locations in the input data for random - access, which may be at bit positions, and to note those cases where the - output of a code may span boundaries of random access blocks. The current - location in the input stream can be determined from avail_in and data_type - as noted in the description for the Z_BLOCK flush parameter for inflate. - - inflateMark returns the value noted above, or -65536 if the provided - source stream state was inconsistent. -*/ - -Z_EXTERN int Z_EXPORT inflateGetHeader(z_stream *strm, gz_headerp head); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be - used to force inflate() to return immediately after header processing is - complete and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When any - of extra, name, or comment are not NULL and the respective field is not - present in the header, then that field is set to NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -Z_EXTERN int Z_EXPORT inflateBackInit (z_stream *strm, int windowBits, unsigned char *window); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the parameters are invalid, Z_MEM_ERROR if the internal state could not be - allocated, or Z_VERSION_ERROR if the version of the library does not match - the version of the header file. -*/ - -typedef uint32_t (*in_func) (void *, z_const unsigned char * *); -typedef int (*out_func) (void *, unsigned char *, uint32_t); - -Z_EXTERN int Z_EXPORT inflateBack(z_stream *strm, in_func in, void *in_desc, out_func out, void *out_desc); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is potentially more efficient than - inflate() for file i/o applications, in that it avoids copying between the - output and the sliding window by simply making the window itself the output - buffer. inflate() can be faster on modern CPUs when used with large - buffers. inflateBack() trusts the application to not change the output - buffer passed by the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free the - allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects only - the raw deflate stream to decompress. This is different from the default - behavior of inflate(), which expects a zlib header and trailer around the - deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero -- buf is ignored in that - case -- and inflateBack() will return a buffer error. inflateBack() will - call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. - out() should return zero on success, or non-zero on failure. If out() - returns non-zero, inflateBack() will return with an error. Neither in() nor - out() are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is NULL, then in() will be called - immediately for input. If strm->next_in is not NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format error - in the deflate stream (in which case strm->msg is set to indicate the nature - of the error), or Z_STREAM_ERROR if the stream was not properly initialized. - In the case of Z_BUF_ERROR, an input or output error can be distinguished - using strm->next_in which will be NULL only if in() returned an error. If - strm->next_in is not NULL, then the Z_BUF_ERROR was due to out() returning - non-zero. (in() will always be called before out(), so strm->next_in is - assured to be defined if out() returns non-zero.) Note that inflateBack() - cannot return Z_OK. -*/ - -Z_EXTERN int Z_EXPORT inflateBackEnd(z_stream *strm); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -Z_EXTERN unsigned long Z_EXPORT zlibCompileFlags(void); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of unsigned int - 3.2: size of unsigned long - 5.4: size of void * (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: ZLIB_DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed (not supported by zlib-ng) - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - -#ifndef Z_SOLO - - /* utility functions */ - -/* - The following utility functions are implemented on top of the basic - stream-oriented functions. To simplify the interface, some default options - are assumed (compression level and memory usage, standard memory allocation - functions). The source code of these utility functions can be modified if - you need special options. -*/ - -Z_EXTERN int Z_EXPORT compress(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total size - of the destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed data. compress() is equivalent to compress2() with a level - parameter of Z_DEFAULT_COMPRESSION. - - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -Z_EXTERN int Z_EXPORT compress2(unsigned char *dest, unsigned long *destLen, const unsigned char *source, - unsigned long sourceLen, int level); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed data. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -Z_EXTERN unsigned long Z_EXPORT compressBound(unsigned long sourceLen); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before a - compress() or compress2() call to allocate the destination buffer. -*/ - -Z_EXTERN int Z_EXPORT uncompress(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total size - of the destination buffer, which must be large enough to hold the entire - uncompressed data. (The size of the uncompressed data must have been saved - previously by the compressor and transmitted to the decompressor by some - mechanism outside the scope of this compression library.) Upon exit, destLen - is the actual size of the uncompressed data. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In - the case where there is not enough room, uncompress() will fill the output - buffer with the uncompressed data up to that point. -*/ - - -Z_EXTERN int Z_EXPORT uncompress2 (unsigned char *dest, unsigned long *destLen, - const unsigned char *source, unsigned long *sourceLen); -/* - Same as uncompress, except that sourceLen is a pointer, where the - length of the source is *sourceLen. On return, *sourceLen is the number of - source bytes consumed. -*/ - - - /* gzip file access functions */ - -/* - This library supports reading and writing files in gzip (.gz) format with - an interface similar to that of stdio, using the functions that start with - "gz". The gzip format is different from the zlib format. gzip is a gzip - wrapper, documented in RFC 1952, wrapped around a deflate stream. -*/ - -typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ - -/* -Z_EXTERN gzFile Z_EXPORT gzopen(const char *path, const char *mode); - - Open the gzip (.gz) file at path for reading and decompressing, or - compressing and writing. The mode parameter is as in fopen ("rb" or "wb") - but can also include a compression level ("wb9") or a strategy: 'f' for - filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", - 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression - as in "wb9F". (See the description of deflateInit2 for more information - about the strategy parameter.) 'T' will request transparent writing or - appending with no compression and not using the gzip format. - - "a" can be used instead of "w" to request that the gzip stream that will - be written be appended to the file. "+" will result in an error, since - reading and writing to the same gzip file is not supported. The addition of - "x" when writing will create the file exclusively, which fails if the file - already exists. On systems that support it, the addition of "e" when - reading or writing will set the flag to close the file on an execve() call. - - These functions, as well as gzip, will read and decode a sequence of gzip - streams in a file. The append function of gzopen() can be used to create - such a file. (Also see gzflush() for another way to do this.) When - appending, gzopen does not test whether the file begins with a gzip stream, - nor does it look for the end of the gzip streams to begin appending. gzopen - will simply append a gzip stream to the existing file. - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. When - reading, this will be detected automatically by looking for the magic two- - byte gzip header. - - gzopen returns NULL if the file could not be opened, if there was - insufficient memory to allocate the gzFile state, or if an invalid mode was - specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). - errno can be checked to determine if the reason gzopen failed was that the - file could not be opened. -*/ - -Z_EXTERN gzFile Z_EXPORT gzdopen(int fd, const char *mode); -/* - Associate a gzFile with the file descriptor fd. File descriptors are - obtained from calls like open, dup, creat, pipe or fileno (if the file has - been previously opened with fopen). The mode parameter is as in gzopen. - - The next call of gzclose on the returned gzFile will also close the file - descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor - fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, - mode);. The duplicated descriptor should be saved to avoid a leak, since - gzdopen does not close fd if it fails. If you are using fileno() to get the - file descriptor from a FILE *, then you will have to use dup() to avoid - double-close()ing the file descriptor. Both gzclose() and fclose() will - close the associated file descriptor, so they need to have different file - descriptors. - - gzdopen returns NULL if there was insufficient memory to allocate the - gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not - provided, or '+' was provided), or if fd is -1. The file descriptor is not - used until the next gz* read, write, seek, or close operation, so gzdopen - will not detect if fd is invalid (unless fd is -1). -*/ - -Z_EXTERN int Z_EXPORT gzbuffer(gzFile file, unsigned size); -/* - Set the internal buffer size used by this library's functions for file to - size. The default buffer size is 8192 bytes. This function must be called - after gzopen() or gzdopen(), and before any other calls that read or write - the file. The buffer memory allocation is always deferred to the first read - or write. Three times that size in buffer space is allocated. A larger - buffer size of, for example, 64K or 128K bytes will noticeably increase the - speed of decompression (reading). - - The new buffer size also affects the maximum length for gzprintf(). - - gzbuffer() returns 0 on success, or -1 on failure, such as being called - too late. -*/ - -Z_EXTERN int Z_EXPORT gzsetparams(gzFile file, int level, int strategy); -/* - Dynamically update the compression level and strategy for file. See the - description of deflateInit2 for the meaning of these parameters. Previously - provided data is flushed before applying the parameter changes. - - gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not - opened for writing, Z_ERRNO if there is an error writing the flushed data, - or Z_MEM_ERROR if there is a memory allocation error. -*/ - -Z_EXTERN int Z_EXPORT gzread(gzFile file, void *buf, unsigned len); -/* - Read and decompress up to len uncompressed bytes from file into buf. If - the input file is not in gzip format, gzread copies the given number of - bytes into the buffer directly from the file. - - After reaching the end of a gzip stream in the input, gzread will continue - to read, looking for another gzip stream. Any number of gzip streams may be - concatenated in the input file, and will all be decompressed by gzread(). - If something other than a gzip stream is encountered after a gzip stream, - that remaining trailing garbage is ignored (and no error is returned). - - gzread can be used to read a gzip file that is being concurrently written. - Upon reaching the end of the input, gzread will return with the available - data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then - gzclearerr can be used to clear the end of file indicator in order to permit - gzread to be tried again. Z_OK indicates that a gzip stream was completed - on the last gzread. Z_BUF_ERROR indicates that the input file ended in the - middle of a gzip stream. Note that gzread does not return -1 in the event - of an incomplete gzip stream. This error is deferred until gzclose(), which - will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip - stream. Alternatively, gzerror can be used before gzclose to detect this - case. - - gzread returns the number of uncompressed bytes actually read, less than - len for end of file, or -1 for error. If len is too large to fit in an int, - then nothing is read, -1 is returned, and the error state is set to - Z_STREAM_ERROR. -*/ - -Z_EXTERN size_t Z_EXPORT gzfread (void *buf, size_t size, size_t nitems, gzFile file); -/* - Read and decompress up to nitems items of size size from file into buf, - otherwise operating as gzread() does. This duplicates the interface of - stdio's fread(), with size_t request and return types. If the library - defines size_t, then z_size_t is identical to size_t. If not, then z_size_t - is an unsigned integer type that can contain a pointer. - - gzfread() returns the number of full items read of size size, or zero if - the end of the file was reached and a full item could not be read, or if - there was an error. gzerror() must be consulted if zero is returned in - order to determine if there was an error. If the multiplication of size and - nitems overflows, i.e. the product does not fit in a size_t, then nothing - is read, zero is returned, and the error state is set to Z_STREAM_ERROR. - - In the event that the end of file is reached and only a partial item is - available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevertheless read into buf - and the end-of-file flag is set. The length of the partial item read is not - provided, but could be inferred from the result of gztell(). This behavior - is the same as the behavior of fread() implementations in common libraries, - but it prevents the direct use of gzfread() to read a concurrently written - file, resetting and retrying on end-of-file, when size is not 1. -*/ - -Z_EXTERN int Z_EXPORT gzwrite(gzFile file, void const *buf, unsigned len); -/* - Compress and write the len uncompressed bytes at buf to file. gzwrite - returns the number of uncompressed bytes written or 0 in case of error. -*/ - -Z_EXTERN size_t Z_EXPORT gzfwrite(void const *buf, size_t size, size_t nitems, gzFile file); -/* - Compress and write nitems items of size size from buf to file, duplicating - the interface of stdio's fwrite(), with size_t request and return types. - - gzfwrite() returns the number of full items written of size size, or zero - if there was an error. If the multiplication of size and nitems overflows, - i.e. the product does not fit in a size_t, then nothing is written, zero - is returned, and the error state is set to Z_STREAM_ERROR. -*/ - -Z_EXTERN int Z_EXPORTVA gzprintf(gzFile file, const char *format, ...); -/* - Convert, format, compress, and write the arguments (...) to file under - control of the string format, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written, or a negative zlib error code in case - of error. The number of uncompressed bytes written is limited to 8191, or - one less than the buffer size given to gzbuffer(). The caller should assure - that this limit is not exceeded. If it is exceeded, then gzprintf() will - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf(), - because the secure snprintf() or vsnprintf() functions were not available. - This can be determined using zlibCompileFlags(). -*/ - -Z_EXTERN int Z_EXPORT gzputs(gzFile file, const char *s); -/* - Compress and write the given null-terminated string s to file, excluding - the terminating null character. - - gzputs returns the number of characters written, or -1 in case of error. -*/ - -Z_EXTERN char * Z_EXPORT gzgets(gzFile file, char *buf, int len); -/* - Read and decompress bytes from file into buf, until len-1 characters are - read, or until a newline character is read and transferred to buf, or an - end-of-file condition is encountered. If any characters are read or if len - is one, the string is terminated with a null character. If no characters - are read due to an end-of-file or len is less than one, then the buffer is - left untouched. - - gzgets returns buf which is a null-terminated string, or it returns NULL - for end-of-file or in case of error. If there was an error, the contents at - buf are indeterminate. -*/ - -Z_EXTERN int Z_EXPORT gzputc(gzFile file, int c); -/* - Compress and write c, converted to an unsigned char, into file. gzputc - returns the value that was written, or -1 in case of error. -*/ - -Z_EXTERN int Z_EXPORT gzgetc(gzFile file); -/* - Read and decompress one byte from file. gzgetc returns this byte or -1 - in case of end of file or error. This is implemented as a macro for speed. - As such, it does not do all of the checking the other functions do. I.e. - it does not check to see if file is NULL, nor whether the structure file - points to has been clobbered or not. -*/ - -Z_EXTERN int Z_EXPORT gzungetc(int c, gzFile file); -/* - Push c back onto the stream for file to be read as the first character on - the next read. At least one character of push-back is always allowed. - gzungetc() returns the character pushed, or -1 on failure. gzungetc() will - fail if c is -1, and may fail if a character has been pushed but not read - yet. If gzungetc is used immediately after gzopen or gzdopen, at least the - output buffer size of pushed characters is allowed. (See gzbuffer above.) - The pushed character will be discarded if the stream is repositioned with - gzseek() or gzrewind(). -*/ - -Z_EXTERN int Z_EXPORT gzflush(gzFile file, int flush); -/* - Flush all pending output to file. The parameter flush is as in the - deflate() function. The return value is the zlib error number (see function - gzerror below). gzflush is only permitted when writing. - - If the flush parameter is Z_FINISH, the remaining data is written and the - gzip stream is completed in the output. If gzwrite() is called again, a new - gzip stream will be started in the output. gzread() is able to read such - concatenated gzip streams. - - gzflush should be called only when strictly necessary because it will - degrade compression if called too often. -*/ - -/* -Z_EXTERN z_off_t Z_EXPORT gzseek (gzFile file, z_off_t offset, int whence); - - Set the starting position to offset relative to whence for the next gzread - or gzwrite on file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -Z_EXTERN int Z_EXPORT gzrewind(gzFile file); -/* - Rewind file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). -*/ - -/* -Z_EXTERN z_off_t Z_EXPORT gztell(gzFile file); - - Return the starting position for the next gzread or gzwrite on file. - This position represents a number of bytes in the uncompressed data stream, - and is zero when starting, even if appending or reading a gzip stream from - the middle of a file using gzdopen(). - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -/* -Z_EXTERN z_off_t Z_EXPORT gzoffset(gzFile file); - - Return the current compressed (actual) read or write offset of file. This - offset includes the count of bytes that precede the gzip stream, for example - when appending or when using gzdopen() for reading. When reading, the - offset does not include as yet unused buffered input. This information can - be used for a progress indicator. On error, gzoffset() returns -1. -*/ - -Z_EXTERN int Z_EXPORT gzeof(gzFile file); -/* - Return true (1) if the end-of-file indicator for file has been set while - reading, false (0) otherwise. Note that the end-of-file indicator is set - only if the read tried to go past the end of the input, but came up short. - Therefore, just like feof(), gzeof() may return false even if there is no - more data to read, in the event that the last read request was for the exact - number of bytes remaining in the input file. This will happen if the input - file size is an exact multiple of the buffer size. - - If gzeof() returns true, then the read functions will return no more data, - unless the end-of-file indicator is reset by gzclearerr() and the input file - has grown since the previous end of file was detected. -*/ - -Z_EXTERN int Z_EXPORT gzdirect(gzFile file); -/* - Return true (1) if file is being copied directly while reading, or false - (0) if file is a gzip stream being decompressed. - - If the input file is empty, gzdirect() will return true, since the input - does not contain a gzip stream. - - If gzdirect() is used immediately after gzopen() or gzdopen() it will - cause buffers to be allocated to allow reading the file to determine if it - is a gzip file. Therefore if gzbuffer() is used, it should be called before - gzdirect(). - - When writing, gzdirect() returns true (1) if transparent writing was - requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: - gzdirect() is not needed when writing. Transparent writing must be - explicitly requested, so the application already knows the answer. When - linking statically, using gzdirect() will include all of the zlib code for - gzip file reading and decompression, which may not be desired.) -*/ - -Z_EXTERN int Z_EXPORT gzclose(gzFile file); -/* - Flush all pending output for file, if necessary, close file and - deallocate the (de)compression state. Note that once file is closed, you - cannot call gzerror with file, since its structures have been deallocated. - gzclose must not be called more than once on the same file, just as free - must not be called more than once on the same allocation. - - gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a - file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the - last read ended in the middle of a gzip stream, or Z_OK on success. -*/ - -Z_EXTERN int Z_EXPORT gzclose_r(gzFile file); -Z_EXTERN int Z_EXPORT gzclose_w(gzFile file); -/* - Same as gzclose(), but gzclose_r() is only for use when reading, and - gzclose_w() is only for use when writing or appending. The advantage to - using these instead of gzclose() is that they avoid linking in zlib - compression or decompression code that is not used when only reading or only - writing respectively. If gzclose() is used, then both compression and - decompression code will be included the application when linking to a static - zlib library. -*/ - -Z_EXTERN const char * Z_EXPORT gzerror(gzFile file, int *errnum); -/* - Return the error message for the last error which occurred on file. - errnum is set to zlib error number. If an error occurred in the file system - and not in the compression library, errnum is set to Z_ERRNO and the - application may consult errno to get the exact error code. - - The application must not modify the returned string. Future calls to - this function may invalidate the previously returned string. If file is - closed, then the string previously returned by gzerror will no longer be - available. - - gzerror() should be used to distinguish errors from end-of-file for those - functions above that do not distinguish those cases in their return values. -*/ - -Z_EXTERN void Z_EXPORT gzclearerr(gzFile file); -/* - Clear the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - -#endif - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the compression - library. -*/ - -Z_EXTERN unsigned long Z_EXPORT adler32(unsigned long adler, const unsigned char *buf, unsigned int len); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. An Adler-32 value is in the range of a 32-bit - unsigned integer. If buf is Z_NULL, this function returns the required - initial value for the checksum. - - An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed - much faster. - - Usage example: - - uint32_t adler = adler32(0L, NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -Z_EXTERN unsigned long Z_EXPORT adler32_z(unsigned long adler, const unsigned char *buf, size_t len); -/* - Same as adler32(), but with a size_t length. -*/ - -/* -Z_EXTERN unsigned long Z_EXPORT adler32_combine(unsigned long adler1, unsigned long adler2, z_off_t len2); - - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note - that the z_off_t type (like off_t) is a signed integer. If len2 is - negative, the result has no meaning or utility. -*/ - -Z_EXTERN unsigned long Z_EXPORT crc32(unsigned long crc, const unsigned char *buf, unsigned int len); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. - If buf is Z_NULL, this function returns the required initial value for the - crc. Pre- and post-conditioning (one's complement) is performed within this - function so it shouldn't be done by the application. - - Usage example: - - uint32_t crc = crc32(0L, NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -Z_EXTERN unsigned long Z_EXPORT crc32_z(unsigned long crc, const unsigned char *buf, size_t len); -/* - Same as crc32(), but with a size_t length. -*/ - -/* -Z_EXTERN unsigned long Z_EXPORT crc32_combine(unsigned long crc1, unsigned long crc2, z_off64_t len2); - - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. len2 must be non-negative. -*/ - -/* -Z_EXTERN unsigned long Z_EXPORT crc32_combine_gen(z_off_t len2); - - Return the operator corresponding to length len2, to be used with - crc32_combine_op(). len2 must be non-negative. -*/ - -Z_EXTERN unsigned long Z_EXPORT crc32_combine_op(unsigned long crc1, unsigned long crc2, - const unsigned long op); -/* - Give the same result as crc32_combine(), using op in place of len2. op is - is generated from len2 by crc32_combine_gen(). This will be faster than - crc32_combine() if the generated op is used more than once. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -Z_EXTERN int Z_EXPORT deflateInit_(z_stream *strm, int level, const char *version, int stream_size); -Z_EXTERN int Z_EXPORT inflateInit_(z_stream *strm, const char *version, int stream_size); -Z_EXTERN int Z_EXPORT deflateInit2_(z_stream *strm, int level, int method, int windowBits, int memLevel, - int strategy, const char *version, int stream_size); -Z_EXTERN int Z_EXPORT inflateInit2_(z_stream *strm, int windowBits, const char *version, int stream_size); -Z_EXTERN int Z_EXPORT inflateBackInit_(z_stream *strm, int windowBits, unsigned char *window, - const char *version, int stream_size); -#define deflateInit(strm, level) deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateInit(strm) inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm), (level), (method), (windowBits), (memLevel), \ - (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateInit2(strm, windowBits) inflateInit2_((strm), (windowBits), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), ZLIB_VERSION, (int)sizeof(z_stream)) - - -#ifndef Z_SOLO -/* gzgetc() macro and its supporting function and exposed data structure. Note - * that the real internal state is much larger than the exposed structure. - * This abbreviated structure exposes just enough for the gzgetc() macro. The - * user should not mess with these exposed elements, since their names or - * behavior could change in the future, perhaps even capriciously. They can - * only be used by the gzgetc() macro. You have been warned. - */ -struct gzFile_s { - unsigned have; - unsigned char *next; - z_off64_t pos; -}; -Z_EXTERN int Z_EXPORT gzgetc_(gzFile file); /* backward compatibility */ -# define gzgetc(g) ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) - -/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or - * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if - * both are true, the application gets the *64 functions, and the regular - * functions are changed to 64 bits) -- in case these are set on systems - * without large file support, _LFS64_LARGEFILE must also be true - */ -#ifdef Z_LARGE64 - Z_EXTERN gzFile Z_EXPORT gzopen64(const char *, const char *); - Z_EXTERN z_off64_t Z_EXPORT gzseek64(gzFile, z_off64_t, int); - Z_EXTERN z_off64_t Z_EXPORT gztell64(gzFile); - Z_EXTERN z_off64_t Z_EXPORT gzoffset64(gzFile); - Z_EXTERN unsigned long Z_EXPORT adler32_combine64(unsigned long, unsigned long, z_off64_t); - Z_EXTERN unsigned long Z_EXPORT crc32_combine64(unsigned long, unsigned long, z_off64_t); - Z_EXTERN unsigned long Z_EXPORT crc32_combine_gen64(z_off64_t); -#endif -#endif - -#if !defined(Z_SOLO) && !defined(Z_INTERNAL) && defined(Z_WANT64) -# define gzopen gzopen64 -# define gzseek gzseek64 -# define gztell gztell64 -# define gzoffset gzoffset64 -# define adler32_combine adler32_combine64 -# define crc32_combine crc32_combine64 -# define crc32_combine_gen crc32_combine_gen64 -# ifndef Z_LARGE64 - Z_EXTERN gzFile Z_EXPORT gzopen64(const char *, const char *); - Z_EXTERN z_off_t Z_EXPORT gzseek64(gzFile, z_off_t, int); - Z_EXTERN z_off_t Z_EXPORT gztell64(gzFile); - Z_EXTERN z_off_t Z_EXPORT gzoffset64(gzFile); - Z_EXTERN unsigned long Z_EXPORT adler32_combine64(unsigned long, unsigned long, z_off_t); - Z_EXTERN unsigned long Z_EXPORT crc32_combine64(unsigned long, unsigned long, z_off_t); - Z_EXTERN unsigned long Z_EXPORT crc32_combine_gen64(z_off64_t); -# endif -#else -# ifndef Z_SOLO - Z_EXTERN gzFile Z_EXPORT gzopen(const char *, const char *); - Z_EXTERN z_off_t Z_EXPORT gzseek(gzFile, z_off_t, int); - Z_EXTERN z_off_t Z_EXPORT gztell(gzFile); - Z_EXTERN z_off_t Z_EXPORT gzoffset(gzFile); -# endif - Z_EXTERN unsigned long Z_EXPORT adler32_combine(unsigned long, unsigned long, z_off_t); - Z_EXTERN unsigned long Z_EXPORT crc32_combine(unsigned long, unsigned long, z_off_t); - Z_EXTERN unsigned long Z_EXPORT crc32_combine_gen(z_off_t); -#endif - -/* undocumented functions */ -Z_EXTERN const char * Z_EXPORT zError (int); -Z_EXTERN int Z_EXPORT inflateSyncPoint (z_stream *); -Z_EXTERN const uint32_t * Z_EXPORT get_crc_table (void); -Z_EXTERN int Z_EXPORT inflateUndermine (z_stream *, int); -Z_EXTERN int Z_EXPORT inflateValidate (z_stream *, int); -Z_EXTERN unsigned long Z_EXPORT inflateCodesUsed (z_stream *); -Z_EXTERN int Z_EXPORT inflateResetKeep (z_stream *); -Z_EXTERN int Z_EXPORT deflateResetKeep (z_stream *); - -#ifndef Z_SOLO -#if defined(_WIN32) - Z_EXTERN gzFile Z_EXPORT gzopen_w(const wchar_t *path, const char *mode); -#endif -Z_EXTERN int Z_EXPORTVA gzvprintf(gzFile file, const char *format, va_list va); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H_ */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.11, January 15th, 2017 + + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.11" +#define ZLIB_VERNUM 0x12b0 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 11 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more ouput + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if any input has been consumed in a previous + deflate() call, then the input available so far is compressed with the old + level and strategy using deflate(strm, Z_BLOCK). There are three approaches + for the compression levels 0, 1..3, and 4..9 respectively. The new level + and strategy will take effect at the next call of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will not automatically decode concatenated gzip streams. + inflate() will return Z_STREAM_END at the end of the gzip stream. The state + would need to be reset to continue decoding a subsequent gzip stream. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen)); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Three times that size in buffer space is allocated. A larger buffer + size of, for example, 64K or 128K bytes will noticeably increase the speed + of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. Previously provided + data is flushed before the parameter change. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, + gzFile file)); +/* + Read up to nitems items of size size from file to buf, otherwise operating + as gzread() does. This duplicates the interface of stdio's fread(), with + size_t request and return types. If the library defines size_t, then + z_size_t is identical to size_t. If not, then z_size_t is an unsigned + integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevetheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, reseting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, + z_size_t nitems, gzFile file)); +/* + gzfwrite() writes nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#elif defined(Z_CR_PREFIX_SET) +# undef gzgetc +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) \ + : (Cr_z_gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# ifdef gzopen +# undef gzopen +# endif +# define gzopen gzopen64 +# ifdef gzseek +# undef gzseek +# endif +# define gzseek gzseek64 +# ifdef gztell +# undef gztell +# endif +# define gztell gztell64 +# ifdef gzoffset +# undef gzoffset +# endif +# define gzoffset gzoffset64 +# ifdef adler32_combine +# undef adler32_combine +# endif +# define adler32_combine adler32_combine64 +# ifdef crc32_combine +# undef crc32_combine +# endif +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/modules/zlib/src/zlib_name_mangling.h b/modules/zlib/src/zlib_name_mangling.h deleted file mode 100644 index b24cb834a6..0000000000 --- a/modules/zlib/src/zlib_name_mangling.h +++ /dev/null @@ -1,8 +0,0 @@ -/* zlib_name_mangling.h has been automatically generated from - * zlib_name_mangling.h.empty because ZLIB_SYMBOL_PREFIX was NOT set. - */ - -#ifndef ZLIB_NAME_MANGLING_H -#define ZLIB_NAME_MANGLING_H - -#endif /* ZLIB_NAME_MANGLING_H */ diff --git a/modules/zlib/src/zmemory.h b/modules/zlib/src/zmemory.h deleted file mode 100644 index fc850a7227..0000000000 --- a/modules/zlib/src/zmemory.h +++ /dev/null @@ -1,99 +0,0 @@ -/* zmemory.h -- Private inline functions used internally in zlib-ng - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef _ZMEMORY_H -#define _ZMEMORY_H - -#if defined(__GNUC__) && (__GNUC__ >= 4) -# define HAVE_MAY_ALIAS -#endif - -static inline uint16_t zng_memread_2(const void *ptr) { -#if defined(HAVE_MAY_ALIAS) - typedef struct { uint16_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint16_t; - return ((const unaligned_uint16_t *)ptr)->val; -#else - uint16_t val; - memcpy(&val, ptr, sizeof(val)); - return val; -#endif -} - -static inline uint32_t zng_memread_4(const void *ptr) { -#if defined(HAVE_MAY_ALIAS) - typedef struct { uint32_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint32_t; - return ((const unaligned_uint32_t *)ptr)->val; -#else - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - return val; -#endif -} - -static inline uint64_t zng_memread_8(const void *ptr) { -#if defined(HAVE_MAY_ALIAS) - typedef struct { uint64_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint64_t; - return ((const unaligned_uint64_t *)ptr)->val; -#else - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - return val; -#endif -} - -static inline void zng_memwrite_2(void *ptr, uint16_t val) { -#if defined(HAVE_MAY_ALIAS) - typedef struct { uint16_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint16_t; - ((unaligned_uint16_t *)ptr)->val = val; -#else - memcpy(ptr, &val, sizeof(val)); -#endif -} - -static inline void zng_memwrite_4(void *ptr, uint32_t val) { -#if defined(HAVE_MAY_ALIAS) - typedef struct { uint32_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint32_t; - ((unaligned_uint32_t *)ptr)->val = val; -#else - memcpy(ptr, &val, sizeof(val)); -#endif -} - -static inline void zng_memwrite_8(void *ptr, uint64_t val) { -#if defined(HAVE_MAY_ALIAS) - typedef struct { uint64_t val; } __attribute__ ((__packed__, __may_alias__)) unaligned_uint64_t; - ((unaligned_uint64_t *)ptr)->val = val; -#else - memcpy(ptr, &val, sizeof(val)); -#endif -} - -/* Use zng_memread_* instead of memcmp to avoid older compilers not converting memcmp - calls to unaligned comparisons when unaligned access is supported. Use memcmp only when - unaligned support is not available to avoid an extra call to memcpy. */ -static inline int32_t zng_memcmp_2(const void *src0, const void *src1) { -#if defined(HAVE_MAY_ALIAS) - return zng_memread_2(src0) != zng_memread_2(src1); -#else - return memcmp(src0, src1, 2); -#endif -} - -static inline int32_t zng_memcmp_4(const void *src0, const void *src1) { -#if defined(HAVE_MAY_ALIAS) - return zng_memread_4(src0) != zng_memread_4(src1); -#else - return memcmp(src0, src1, 4); -#endif -} - -static inline int32_t zng_memcmp_8(const void *src0, const void *src1) { -#if defined(HAVE_MAY_ALIAS) - return zng_memread_8(src0) != zng_memread_8(src1); -#else - return memcmp(src0, src1, 8); -#endif -} - -#endif diff --git a/modules/zlib/src/zsanitizer.h b/modules/zlib/src/zsanitizer.h deleted file mode 100644 index 2c55f9dacf..0000000000 --- a/modules/zlib/src/zsanitizer.h +++ /dev/null @@ -1,71 +0,0 @@ -/* zsanitizer.h -- sanitizer instrumentation for deliberate OOB and uninitialized memory access. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ZSANITIZER_H -#define ZSANITIZER_H - -/* Detect sanitizer availability */ -#if defined(__has_feature) -# if __has_feature(address_sanitizer) -# define Z_ADDRESS_SANITIZER 1 -# endif -# if __has_feature(memory_sanitizer) -# define Z_MEMORY_SANITIZER 1 -# endif -#elif defined(__SANITIZE_ADDRESS__) /* GCC supports ASAN only */ -# define Z_ADDRESS_SANITIZER 1 -#endif - -/* Include sanitizer headers */ -#ifdef Z_MEMORY_SANITIZER -# include -#endif - -/* - * __asan_loadN() and __asan_storeN() calls are inserted by compilers in order to check memory accesses. - * They can be called manually too, with the following caveats: - * gcc says: "warning: implicit declaration of function '...'" - * g++ says: "error: new declaration '...' ambiguates built-in declaration '...'" - * Accommodate both. - */ -#ifdef Z_ADDRESS_SANITIZER -# ifndef __cplusplus -void __asan_loadN(uintptr_t, uintptr_t); -void __asan_storeN(uintptr_t, uintptr_t); -# endif -#else -# define __asan_loadN(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0) -# define __asan_storeN(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0) -#endif - -/* Handle intentional uninitialized memory access */ -#ifndef Z_MEMORY_SANITIZER -# define __msan_check_mem_is_initialized(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0) -# define __msan_unpoison(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0) -#endif - -/* Notify sanitizer runtime about an upcoming read access. */ -#define instrument_read(a, size) do { \ - uintptr_t __a = (uintptr_t)(a); \ - uintptr_t __size = size; \ - __asan_loadN(__a, __size); \ - __msan_check_mem_is_initialized((void *)__a, __size); \ -} while (0) - -/* Notify sanitizer runtime about an upcoming write access. */ -#define instrument_write(a, size) do { \ - uintptr_t __a = (uintptr_t)(a); \ - uintptr_t __size = size; \ - __asan_storeN(__a, __size); \ -} while (0) - -/* Notify sanitizer runtime about an upcoming read/write access. */ -#define instrument_read_write(a, size) do { \ - uintptr_t __a = (uintptr_t)(a); \ - uintptr_t __size = size; \ - __asan_storeN(__a, __size); \ - __msan_check_mem_is_initialized((void *)__a, __size); \ -} while (0) - -#endif diff --git a/modules/zlib/src/zutil.c b/modules/zlib/src/zutil.c index 402862ffb0..a76c6b0c7e 100644 --- a/modules/zlib/src/zutil.c +++ b/modules/zlib/src/zutil.c @@ -3,11 +3,14 @@ * For conditions of distribution and use, see copyright notice in zlib.h */ -#include "zbuild.h" -#include "zutil_p.h" -#include "zutil.h" +/* @(#) $Id$ */ -z_const char * const PREFIX(z_errmsg)[10] = { +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +z_const char * const z_errmsg[10] = { (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ (z_const char *)"stream end", /* Z_STREAM_END 1 */ (z_const char *)"", /* Z_OK 0 */ @@ -20,42 +23,36 @@ z_const char * const PREFIX(z_errmsg)[10] = { (z_const char *)"" }; -const char PREFIX3(vstring)[] = - " zlib-ng 2.3.90 devel"; -#ifdef ZLIB_COMPAT -const char * Z_EXPORT zlibVersion(void) { +const char * ZEXPORT zlibVersion() +{ return ZLIB_VERSION; } -#else -const char * Z_EXPORT zlibng_version(void) { - return ZLIBNG_VERSION; -} -#endif -unsigned long Z_EXPORT PREFIX(zlibCompileFlags)(void) { - unsigned long flags; +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; flags = 0; - switch (sizeof(unsigned int)) { + switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } - switch (sizeof(unsigned long)) { + switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } - switch (sizeof(void *)) { + switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } - switch (sizeof(z_off_t)) { + switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; @@ -64,10 +61,18 @@ unsigned long Z_EXPORT PREFIX(zlibCompileFlags)(void) { #ifdef ZLIB_DEBUG flags += 1 << 8; #endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif #ifdef ZLIB_WINAPI flags += 1 << 10; #endif - /* Bit 13 reserved for DYNAMIC_CRC_TABLE */ +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif @@ -76,18 +81,47 @@ unsigned long Z_EXPORT PREFIX(zlibCompileFlags)(void) { #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif #endif return flags; } #ifdef ZLIB_DEBUG -# include +#include # ifndef verbose # define verbose 0 # endif -int Z_INTERNAL z_verbose = verbose; +int ZLIB_INTERNAL z_verbose = verbose; -void Z_INTERNAL z_error(const char *m) { +void ZLIB_INTERNAL z_error (m) + char *m; +{ fprintf(stderr, "%s\n", m); exit(1); } @@ -96,56 +130,196 @@ void Z_INTERNAL z_error(const char *m) { /* exported to allow conversion of error code to string for compress() and * uncompress() */ -const char * Z_EXPORT PREFIX(zError)(z_int32_t err) { +const char * ZEXPORT zError(err) + int err; +{ return ERR_MSG(err); } -// Zlib-ng's default alloc/free implementation, used unless -// application supplies its own alloc/free functions. -void Z_INTERNAL *PREFIX(zcalloc)(void *opaque, unsigned items, unsigned size) { - Z_UNUSED(opaque); - return zng_alloc((size_t)items * (size_t)size); +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); } -void Z_INTERNAL PREFIX(zcfree)(void *opaque, void *ptr) { - Z_UNUSED(opaque); - zng_free(ptr); +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; } -/* Provide aligned allocations, only used by gz* code */ -void Z_INTERNAL *zng_alloc_aligned(unsigned size, unsigned align) { - uintptr_t return_ptr, original_ptr, align_diff; - uint32_t alloc_size; - void *ptr; +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif - /* Allocate enough memory for proper alignment and to store the original memory pointer */ - alloc_size = sizeof(void *) + size + align; - ptr = zng_alloc(alloc_size); - if (!ptr) - return NULL; +#ifndef Z_SOLO - /* Calculate return pointer address with space enough to store original pointer */ - align_diff = ALIGN_DIFF(ptr, align); - return_ptr = (uintptr_t)ptr + align_diff; - if (align_diff < sizeof(void *)) - return_ptr += align; +#ifdef SYS16BIT - /* Store the original pointer for free() */ - original_ptr = return_ptr - sizeof(void *); - memcpy((void *)original_ptr, &ptr, sizeof(void *)); +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ - /* Return properly aligned pointer in allocation */ - return (void *)return_ptr; +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf; + ulg bsize = (ulg)items*size; + + (void)opaque; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; } -void Z_INTERNAL zng_free_aligned(void *ptr) { - if (!ptr) +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + int n; + + (void)opaque; + + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; - /* Calculate offset to original memory allocation pointer */ - void *original_ptr = (void *)((uintptr_t)ptr - sizeof(void *)); - void *free_ptr = *(void **)original_ptr; - - /* Free original memory allocation */ - zng_free(free_ptr); + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + Assert(0, "zcfree: ptr not found"); } + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +{ + (void)opaque; + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + (void)opaque; + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + (void)opaque; + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + (void)opaque; + free(ptr); +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/modules/zlib/src/zutil.h b/modules/zlib/src/zutil.h index 9017c687f1..4425bcf75e 100644 --- a/modules/zlib/src/zutil.h +++ b/modules/zlib/src/zutil.h @@ -1,7 +1,5 @@ -#ifndef ZUTIL_H_ -#define ZUTIL_H_ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -10,23 +8,66 @@ subject to change. Applications should only use zlib.h. */ -#include "zbuild.h" -#ifdef ZLIB_COMPAT -# include "zlib.h" +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else -# include "zlib-ng.h" +# define ZLIB_INTERNAL #endif -typedef unsigned char uch; /* Included for compatibility with external code only */ -typedef uint16_t ush; /* Included for compatibility with external code only */ -typedef unsigned long ulg; +#include "zlib.h" -extern z_const char * const PREFIX(z_errmsg)[10]; /* indexed by 2-zlib_error */ +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ -#define ERR_MSG(err) PREFIX(z_errmsg)[(err) < -6 || (err) > 2 ? 9 : 2 - (err)] +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] -#define ERR_RETURN(strm, err) return (strm->msg = ERR_MSG(err), (err)) +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ @@ -36,11 +77,6 @@ extern z_const char * const PREFIX(z_errmsg)[10]; /* indexed by 2-zlib_error */ #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ -#define MAX_BITS 15 -/* all codes must not exceed MAX_BITS bits */ -#define MAX_DIST_EXTRA_BITS 13 -/* maximum number of extra distance bits */ - #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else @@ -53,38 +89,41 @@ extern z_const char * const PREFIX(z_errmsg)[10]; /* indexed by 2-zlib_error */ #define DYN_TREES 2 /* The three kinds of block type */ -#define STD_MIN_MATCH 3 -#define STD_MAX_MATCH 258 -/* The minimum and maximum match lengths mandated by the deflate standard */ - -#define WANT_MIN_MATCH 4 -/* The minimum wanted match length, affects deflate_quick, deflate_fast, deflate_medium and deflate_slow */ +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ -#define ADLER32_INITIAL_VALUE 1 /* initial adler-32 hash value */ -#define CRC32_INITIAL_VALUE 0 /* initial crc-32 hash value */ - -#define ZLIB_WRAPLEN 6 /* zlib format overhead */ -#define GZIP_WRAPLEN 18 /* gzip format overhead */ - -#define DEFLATE_HEADER_BITS 3 -#define DEFLATE_EOBS_BITS 15 -#define DEFLATE_PAD_BITS 6 -#define DEFLATE_BLOCK_OVERHEAD ((DEFLATE_HEADER_BITS + DEFLATE_EOBS_BITS + DEFLATE_PAD_BITS) >> 3) -/* deflate block overhead: 3 bits for block start + 15 bits for block end + padding to nearest byte */ - -#define DEFLATE_QUICK_LIT_MAX_BITS 9 -#define DEFLATE_QUICK_OVERHEAD(x) ((x * (DEFLATE_QUICK_LIT_MAX_BITS - 8) + 7) >> 3) -/* deflate_quick worst-case overhead: 9 bits per literal, round up to next byte (+7) */ - - /* target dependencies */ +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + #ifdef AMIGA # define OS_CODE 1 #endif +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + #ifdef __370__ # if __TARGET_LIB__ < 0x20000000 # define OS_CODE 4 @@ -101,42 +140,153 @@ extern z_const char * const PREFIX(z_errmsg)[10]; /* indexed by 2-zlib_error */ #ifdef OS2 # define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif #endif -#if defined(MACOS) +#if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 7 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif #endif #ifdef __acorn # define OS_CODE 13 #endif -#if defined(_WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) && !defined(__CYGWIN__) # define OS_CODE 10 #endif +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + #ifdef __APPLE__ # define OS_CODE 19 #endif +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + /* common defaults */ #ifndef OS_CODE -# define OS_CODE 3 /* assume Unix */ +# define OS_CODE 3 /* assume Unix */ #endif - /* macros */ +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif -#define CHECK_VER_STSIZE(_ver,_stsize) ((_ver) == NULL || (_ver)[0] != PREFIX2(VERSION)[0] || (_stsize) != (int32_t)sizeof(PREFIX3(stream))) + /* functions */ - /* memory allocation functions */ +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif -void Z_INTERNAL *PREFIX(zcalloc)(void *opaque, unsigned items, unsigned size); -void Z_INTERNAL PREFIX(zcfree)(void *opaque, void *ptr); -void Z_INTERNAL *zng_alloc_aligned(unsigned size, unsigned align); -void Z_INTERNAL zng_free_aligned(void *ptr); +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif -typedef void *zng_calloc_func(void *opaque, unsigned items, unsigned size); -typedef void zng_cfree_func(void *opaque, void *ptr); +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif -#endif /* ZUTIL_H_ */ +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#ifdef _MSC_VER +#define zalign(x) __declspec(align(x)) +#else +#define zalign(x) __attribute__((aligned((x)))) +#endif + +#endif /* ZUTIL_H */ diff --git a/modules/zlib/src/zutil_p.h b/modules/zlib/src/zutil_p.h deleted file mode 100644 index 9615956350..0000000000 --- a/modules/zlib/src/zutil_p.h +++ /dev/null @@ -1,20 +0,0 @@ -/* zutil_p.h -- Private inline functions used internally in zlib-ng - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef ZUTIL_P_H -#define ZUTIL_P_H - -#include - -// Zlib-ng's default alloc/free implementation, used unless -// application supplies its own alloc/free functions. -static inline void *zng_alloc(size_t size) { - return malloc(size); -} - -static inline void zng_free(void *ptr) { - free(ptr); -} - -#endif diff --git a/mozconfigs/linux/uxp-linux-loongarch64 b/mozconfigs/linux/uxp-linux-loongarch64-clang similarity index 100% rename from mozconfigs/linux/uxp-linux-loongarch64 rename to mozconfigs/linux/uxp-linux-loongarch64-clang diff --git a/mozconfigs/linux/uxp-linux-x64-clang b/mozconfigs/linux/uxp-linux-x64-clang new file mode 100644 index 0000000000..5ad57494a6 --- /dev/null +++ b/mozconfigs/linux/uxp-linux-x64-clang @@ -0,0 +1,67 @@ +# Set GTK Version to 2 or 3 +_GTK_VERSION=3 + +# 16 jobs for 16 cores +mk_add_options MOZ_MAKE_FLAGS="-j6" + +# Use clang/llvm toolchain +export CC="/usr/bin/clang" +export CXX="/usr/bin/clang++" +export AR="/usr/bin/llvm-ar" +export NM="/usr/bin/llvm-nm" +export RANLIB="/usr/bin/llvm-ranlib" +export LD=ld.lld + +# Force LLVM for HOST tools as well +export HOST_CC=/usr/bin/clang +export HOST_CXX=/usr/bin/clang++ +export HOST_AR=/usr/bin/llvm-ar +export HOST_RANLIB=/usr/bin/llvm-ranlib +export HOST_NM=/usr/bin/llvm-nm +export HOST_LD=ld.lld + +# Ensure static archives always get a symbol table (__.SYMDEF). +# Older Mozilla/UXP build logic assumes ar creates this implicitly, +# but with ThinLTO + LLVM bitcode that is no longer guaranteed. +# Without the 's' flag, ld/lld will fail with: +# "archive has no index; run ranlib to add one" +# This is especially critical for HOST tools (mbsdiff, mar, etc.). +export ARFLAGS=crs +export HOST_ARFLAGS=crs +export ARFLAGS=crs +export HOST_ARFLAGS=crs + +# ThinLTO with Clang/LLVM. -Wl,--undefined-version is needed due to differences between GNU ld and lld +export LDFLAGS="-flto=thin -fuse-ld=lld -Wl,--undefined-version" + +# O3 for maximum optimization, -w to suppress all warnings, -flto=thin for ThinLTO +ac_add_options --enable-optimize="-O3 -w -flto=thin" + +# Standard build options for Basilisk +ac_add_options --enable-application=basilisk +ac_add_options --enable-default-toolkit=cairo-gtk$_GTK_VERSION +ac_add_options --enable-jemalloc +ac_add_options --enable-strip +ac_add_options --enable-devtools +ac_add_options --enable-av1 +ac_add_options --enable-webrtc +ac_add_options --enable-gamepad +ac_add_options --enable-pie +ac_add_options --enable-update-channel=release +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-necko-wifi +ac_add_options --disable-updater +ac_add_options --with-pthreads +ac_add_options --disable-official-branding + +export MOZILLA_OFFICIAL=1 + +ac_add_options --x-libraries=/usr/lib64 + +export MOZ_PKG_SPECIAL=gtk$_GTK_VERSION + +export CC="clang -std=gnu89 -Wno-error=implicit-int -Wno-error=implicit-function-declaration" +export CXX="clang++ -std=gnu++17" + +export MOZ_SOURCE_CHANGESET=iloveneedingtobodgechangesetfornoreason diff --git a/mozconfigs/linux/uxp-linux-x64 b/mozconfigs/linux/uxp-linux-x64-gcc similarity index 100% rename from mozconfigs/linux/uxp-linux-x64 rename to mozconfigs/linux/uxp-linux-x64-gcc diff --git a/mozconfigs/windows/uxp-win32-mingw32 b/mozconfigs/windows/uxp-win32-gcc similarity index 85% rename from mozconfigs/windows/uxp-win32-mingw32 rename to mozconfigs/windows/uxp-win32-gcc index d81cb1b072..023f82053c 100644 --- a/mozconfigs/windows/uxp-win32-mingw32 +++ b/mozconfigs/windows/uxp-win32-gcc @@ -11,6 +11,8 @@ ac_add_options --target=i686-pc-mingw32 WIN32_REDIST_DIR=$VCINSTALLDIR/Redist/MSVC/14.16.27012/x86 WIN_UCRT_REDIST_DIR=$WINDOWSSDKDIR/Redist/10.0.19041.0/ucrt/DLLs/r86 +# Force compiler + linker + tools + CC=gcc CXX=g++ LD=g++ @@ -18,6 +20,11 @@ AR=ar AS=as RANLIB=ranlib +export GCC=/c/mingw32/bin + +# Force PATH so UXP thinks only GCC is there +export PATH="$GCC:$PATH" + # Build only Hydra ac_add_options --enable-application=basilisk ac_add_options --disable-artifact-builds @@ -37,7 +44,7 @@ ac_add_options --enable-devtools #ac_add_options --enable-install-strip ac_add_options --enable-jemalloc ac_add_options --enable-js-lto -ac_add_options --enable-optimize="-O2" +ac_add_options --enable-optimize="-O2 -w -march=pentium3 -mtune=pentium3 -msse -mno-sse2 -fno-tree-vectorize" ac_add_options --enable-phoenix-extensions ac_add_options --enable-release ac_add_options --enable-shared-js @@ -49,7 +56,7 @@ export MOZILLA_OFFICIAL=1 export STRIP_FLAGS="--strip-debug --strip-unneeded" # Media settings -ac_add_options --enable-av1 +ac_add_options --disable-av1 ac_add_options --enable-jxl ac_add_options --enable-raw ac_add_options --disable-webrtc diff --git a/mozconfigs/windows/uxp-win32-msvc b/mozconfigs/windows/uxp-win32-msvc index cb0f4dae00..9d4c9b5e45 100644 --- a/mozconfigs/windows/uxp-win32-msvc +++ b/mozconfigs/windows/uxp-win32-msvc @@ -1,78 +1,74 @@ -## UXP mozconfig thing based off roytam1's config and r3dfox config - -##Uncomment PGO for release build - -# 16 jobs for 16 cores -mk_add_options MOZ_MAKE_FLAGS="-j16" - -# x86 build -ac_add_options --host=i686-pc-mingw32 -ac_add_options --target=i686-pc-mingw32 -WIN32_REDIST_DIR=$VCINSTALLDIR/Redist/MSVC/14.16.27012/x86 -WIN_UCRT_REDIST_DIR=$WINDOWSSDKDIR/Redist/10.0.19041.0/ucrt/DLLs/r86 - -# Build only Hydra -ac_add_options --enable-application=basilisk -ac_add_options --disable-artifact-builds - -# Updater stuffs -ac_add_options --disable-updater -# Enable if update server and signatures are figured out -#ac_add_options --enable-nss-mar - -# Optimization settings -ac_add_options --disable-accessibility -ac_add_options --disable-debug -ac_add_options --disable-debug-js-modules -ac_add_options --disable-debug-symbols -ac_add_options --disable-tests -ac_add_options --enable-devtools -#ac_add_options --enable-install-strip -ac_add_options --enable-jemalloc -ac_add_options --enable-js-lto -ac_add_options --enable-optimize="-O2 -Ob2ity -GS- -GFAT -Qpar -Qfast_transcendentals -openmp" -ac_add_options --enable-phoenix-extensions -ac_add_options --enable-release -ac_add_options --enable-shared-js -ac_add_options --enable-strip -MOZ_OPTIMIZE=1 -export MOZ_OPTIMIZE=1 -mk_add_options MOZ_OPTIMIZE=1 -export MOZILLA_OFFICIAL=1 -export STRIP_FLAGS="--strip-debug --strip-unneeded" - -# Media settings -ac_add_options --enable-av1 -ac_add_options --enable-jxl -ac_add_options --enable-raw -ac_add_options --enable-webrtc - -# Client settings -ac_add_options --disable-crashreporter -ac_add_options --disable-eme -ac_add_options --disable-maintenance-service -ac_add_options --disable-parental-controls -mk_add_options MOZ_SERVICES_HEALTHREPORT=0 -export CROSS_COMPILE=0 -export MOZ_CRASHREPORTER=0 -export MOZ_DATA_REPORTING=0 -export MOZ_INCLUDE_SOURCE_INFO=1 -export MOZ_REQUIRE_SIGNING= -export MOZ_SOURCE_CHANGESET=iloveneedingtobodgechangesetfornoreason -export MOZ_TELEMETRY_REPORTING= -export MOZ_PACKAGE_JSSHELL=1 - -# Set -Copt-level=3 -export OPT_LEVEL="3" -ac_add_options OPT_LEVEL="3" - -# Enable LTO -export MOZ_LTO=1 -ac_add_options MOZ_LTO=1 - -# Compiler and Linker flags -export CFLAGS="-O2" -export CPPFLAGS="-O2" -export CXXFLAGS="-O2" -export POLLY="-mllvm -polly -mllvm -polly-2nd-level-tiling -mllvm -polly-loopfusion-greedy -mllvm -polly-pattern-matching-based-opts -mllvm -polly-position=before-vectorizer -mllvm -polly-vectorizer=stripmine" -export VERBOSE=1 +## UXP mozconfig thing based off roytam1's config and r3dfox config + +##Uncomment PGO for release build + +# 16 jobs for 16 cores +mk_add_options MOZ_MAKE_FLAGS="-j6" + +# x86 build +ac_add_options --host=i686-pc-mingw32 +ac_add_options --target=i686-pc-mingw32 +WIN32_REDIST_DIR=$VCINSTALLDIR/Redist/MSVC/14.16.27012/x86 + +# Build only Hydra +ac_add_options --enable-application=basilisk +ac_add_options --disable-artifact-builds + +# Updater stuffs +ac_add_options --disable-updater +# Enable if update server and signatures are figured out +#ac_add_options --enable-nss-mar + +# Optimization settings +ac_add_options --disable-accessibility +ac_add_options --disable-debug +ac_add_options --disable-debug-js-modules +ac_add_options --disable-debug-symbols +ac_add_options --disable-tests +ac_add_options --enable-devtools +ac_add_options --disable-jemalloc +ac_add_options --enable-js-lto +ac_add_options --enable-phoenix-extensions +ac_add_options --enable-release +ac_add_options --enable-shared-js +ac_add_options --enable-strip +MOZ_OPTIMIZE=1 +export MOZ_OPTIMIZE=1 +mk_add_options MOZ_OPTIMIZE=1 +export MOZILLA_OFFICIAL=1 + +# Media settings +ac_add_options --disable-av1 +ac_add_options --enable-jxl +ac_add_options --enable-raw +ac_add_options --disable-webrtc + +# Client settings +ac_add_options --disable-crashreporter +ac_add_options --disable-eme +ac_add_options --disable-maintenance-service +ac_add_options --disable-parental-controls +mk_add_options MOZ_SERVICES_HEALTHREPORT=0 +export CROSS_COMPILE=0 +export MOZ_CRASHREPORTER=0 +export MOZ_DATA_REPORTING=0 +export MOZ_INCLUDE_SOURCE_INFO=1 +export MOZ_REQUIRE_SIGNING= +export MOZ_SOURCE_CHANGESET=iloveneedingtobodgechangesetfornoreason +export MOZ_TELEMETRY_REPORTING= +export MOZ_PACKAGE_JSSHELL=1 + +# Set -Copt-level=3 +export OPT_LEVEL="3" +ac_add_options OPT_LEVEL="3" + +# Enable LTO +export MOZ_LTO=1 +ac_add_options MOZ_LTO=1 + +# Linker flags +ac_add_options --enable-optimize="-O2 -Ob2ity- -GS- -Qpar -Qfast_transcendentals -openmp -Oi -Gy -Gw -GF -GT -fp:precise -Zc:inline -Zc:throwingNew -Zc:__cplusplus -arch:SSE2 -std:c++17 -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS" +mk_add_options "LDFLAGS=-OPT:REF,ICF,WIN64,LBR -OPT:ICF=3 -INCREMENTAL:NO -LTCG:NO -DYNAMICBASE -NXCOMPAT -MACHINE:X64 -SUBSYSTEM:WINDOWS,5.1 -Brepro -FUNCTIONPADMIN -ALIGN:4096 -RELEASE" +export POLLY="-mllvm -polly -mllvm -polly-2nd-level-tiling -mllvm -polly-loopfusion-greedy -mllvm -polly-pattern-matching-based-opts -mllvm -polly-position=before-vectorizer -mllvm -polly-vectorizer=stripmine" +export STRIP_FLAGS="--strip-all --remove-section=.comment --remove-section=.note --remove-section=.eh_frame" +export VERBOSE=1 diff --git a/mozconfigs/windows/uxp-win64 b/mozconfigs/windows/uxp-win64-clang similarity index 79% rename from mozconfigs/windows/uxp-win64 rename to mozconfigs/windows/uxp-win64-clang index e4800f0493..d452f8d2a5 100644 --- a/mozconfigs/windows/uxp-win64 +++ b/mozconfigs/windows/uxp-win64-clang @@ -1,15 +1,28 @@ ## UXP mozconfig thing based off roytam1's config and r3dfox config +# ============================ +# Force clang-cl toolchain +# ============================ + +export CLANG=/c/clang/bin + +# Force compiler + linker + tools +export CC="clang-cl.exe" +export MT="llvm-mt.exe" +export LD="lld-link.exe" +export LIB="lib.exe" + +# Force PATH so UXP thinks only Clang is there +export PATH="$CLANG:$PATH" + ##Uncomment PGO for release build # 16 jobs for 16 cores -mk_add_options MOZ_MAKE_FLAGS="-j16" +mk_add_options MOZ_MAKE_FLAGS="-j6" # x64 build ac_add_options --host=x86_64-pc-mingw32 ac_add_options --target=x86_64-pc-mingw32 -WIN32_REDIST_DIR=$VCINSTALLDIR/Redist/MSVC/14.16.27012/x64 -WIN_UCRT_REDIST_DIR=$WINDOWSSDKDIR/Redist/10.0.19041.0/ucrt/DLLs/r64 # Build only Hydra ac_add_options --enable-application=basilisk @@ -30,7 +43,7 @@ ac_add_options --enable-devtools #ac_add_options --enable-install-strip ac_add_options --enable-jemalloc ac_add_options --enable-js-lto -ac_add_options --enable-optimize="-O2 -Ob2ity -GS- -GFAT -Qpar -Qfast_transcendentals -openmp" +ac_add_options --enable-optimize="-O2 -Ob2ity -openmp -arch:AVX -w0 -w" ac_add_options --enable-phoenix-extensions ac_add_options --enable-release ac_add_options --enable-shared-js @@ -52,6 +65,7 @@ ac_add_options --disable-crashreporter ac_add_options --disable-eme ac_add_options --disable-maintenance-service ac_add_options --disable-parental-controls +ac_add_options --disable-ctypes mk_add_options MOZ_SERVICES_HEALTHREPORT=0 export CROSS_COMPILE=0 export MOZ_CRASHREPORTER=0 @@ -71,8 +85,5 @@ export MOZ_LTO=1 ac_add_options MOZ_LTO=1 # Compiler and Linker flags -export CFLAGS="-O2" -export CPPFLAGS="-O2" -export CXXFLAGS="-O2" export POLLY="-mllvm -polly -mllvm -polly-2nd-level-tiling -mllvm -polly-loopfusion-greedy -mllvm -polly-pattern-matching-based-opts -mllvm -polly-position=before-vectorizer -mllvm -polly-vectorizer=stripmine" export VERBOSE=1 diff --git a/mozconfigs/windows/uxp-win64-msvc b/mozconfigs/windows/uxp-win64-msvc new file mode 100644 index 0000000000..07b583d00b --- /dev/null +++ b/mozconfigs/windows/uxp-win64-msvc @@ -0,0 +1,69 @@ +# 16 jobs for 16 cores +mk_add_options MOZ_MAKE_FLAGS="-j16" + +# x64 build +ac_add_options --host=x86_64-pc-mingw32 +ac_add_options --target=x86_64-pc-mingw32 + +# Build only Dactyloidae +ac_add_options --enable-application=browser +ac_add_options --disable-artifact-builds + +# Updater stuffs +ac_add_options --disable-updater +# Enable if update server and signatures are figured out +#ac_add_options --enable-nss-mar + +# Optimization settings +ac_add_options --disable-accessibility +ac_add_options --disable-debug +ac_add_options --disable-debug-js-modules +ac_add_options --disable-debug-symbols +ac_add_options --disable-tests +ac_add_options --enable-devtools +#ac_add_options --enable-install-strip +ac_add_options --enable-jemalloc +ac_add_options --enable-js-lto +ac_add_options --enable-phoenix-extensions +ac_add_options --enable-release +ac_add_options --enable-shared-js +ac_add_options --enable-strip +MOZ_OPTIMIZE=1 +export MOZ_OPTIMIZE=1 +mk_add_options MOZ_OPTIMIZE=1 +export MOZILLA_OFFICIAL=1 + +# Media settings +ac_add_options --disable-av1 +ac_add_options --enable-jxl +ac_add_options --enable-raw +ac_add_options --disable-webrtc + +# Client settings +ac_add_options --disable-crashreporter +ac_add_options --disable-eme +ac_add_options --disable-maintenance-service +ac_add_options --disable-parental-controls +mk_add_options MOZ_SERVICES_HEALTHREPORT=0 +export CROSS_COMPILE=0 +export MOZ_CRASHREPORTER=0 +export MOZ_DATA_REPORTING=0 +export MOZ_INCLUDE_SOURCE_INFO=1 +export MOZ_REQUIRE_SIGNING= +export MOZ_SOURCE_CHANGESET=iloveneedingtobodgechangesetfornoreason +export MOZ_TELEMETRY_REPORTING= +export MOZ_PACKAGE_JSSHELL=1 + +# Set -Copt-level=3 +export OPT_LEVEL="3" +ac_add_options OPT_LEVEL="3" + +# Compiler and Linker flags +export CFLAGS="-O2" +export CPPFLAGS="-O2" +export CXXFLAGS="-O2" +ac_add_options --enable-optimize="-O2 -Ob2ity -GS- -Qpar -Qfast_transcendentals -openmp -Oi -Gy -Gw -GF -GT -fp:precise -Zc:inline -Zc:throwingNew -Zc:__cplusplus -arch:SSE2 -std:c++17 -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS" +mk_add_options "LDFLAGS=-OPT:REF,ICF,WIN64,LBR -OPT:ICF=3 -INCREMENTAL:NO -LTCG:NO -DYNAMICBASE -NXCOMPAT -MACHINE:X64 -SUBSYSTEM:WINDOWS,5.2 -Brepro -FUNCTIONPADMIN -ALIGN:4096 -RELEASE" +export POLLY="-mllvm -polly -mllvm -polly-2nd-level-tiling -mllvm -polly-loopfusion-greedy -mllvm -polly-pattern-matching-based-opts -mllvm -polly-position=before-vectorizer -mllvm -polly-vectorizer=stripmine" +export STRIP_FLAGS="--strip-all --remove-section=.comment --remove-section=.note --remove-section=.eh_frame" +export VERBOSE=1 diff --git a/mozglue/build/Makefile.in b/mozglue/build/Makefile.in index 1cfa41ea04..2e484a92a9 100644 --- a/mozglue/build/Makefile.in +++ b/mozglue/build/Makefile.in @@ -8,7 +8,7 @@ include $(topsrcdir)/config/config.mk ifeq (WINNT,$(OS_TARGET)) mozglue.def: mozglue.def.in $(GLOBAL_DEPS) - $(call py_action,preprocessor,$(if $(MOZ_REPLACE_MALLOC),-DMOZ_REPLACE_MALLOC) $(ACDEFINES) $< -o $@) + $(call py_action,preprocessor,$(if $(MOZ_REPLACE_MALLOC),-DMOZ_REPLACE_MALLOC) $(if $(GNU_CC),-DGNU_CC) $(ACDEFINES) $< -o $@) GARBAGE += mozglue.def endif diff --git a/mozglue/misc/StackWalk.cpp b/mozglue/misc/StackWalk.cpp index 141e2eb41b..ab29ba25a9 100644 --- a/mozglue/misc/StackWalk.cpp +++ b/mozglue/misc/StackWalk.cpp @@ -851,7 +851,12 @@ MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails) pSymbol->MaxNameLen = MAX_SYM_NAME; DWORD64 displacement; +#ifdef __MINGW32__ + // SymFromAddr is not available in MinGW dbghelp.dll + ok = FALSE; +#else ok = SymFromAddr(myProcess, addr, &displacement, pSymbol); +#endif if (ok) { strncpy(aDetails->function, pSymbol->Name, diff --git a/netwerk/base/ThrottleQueue.cpp b/netwerk/base/ThrottleQueue.cpp index 8f07186235..233a95b15a 100644 --- a/netwerk/base/ThrottleQueue.cpp +++ b/netwerk/base/ThrottleQueue.cpp @@ -30,6 +30,8 @@ public: NS_DECL_NSIASYNCINPUTSTREAM void AllowInput(); + bool IsQueued() const; + void SetQueued(bool aQueued); private: @@ -41,6 +43,7 @@ private: nsCOMPtr mCallback; nsCOMPtr mEventTarget; + bool mIsQueued; }; NS_IMPL_ISUPPORTS(ThrottleInputStream, nsIAsyncInputStream, nsIInputStream, nsISeekableStream) @@ -49,6 +52,7 @@ ThrottleInputStream::ThrottleInputStream(nsIInputStream *aStream, ThrottleQueue* : mStream(aStream) , mQueue(aQueue) , mClosedStatus(NS_OK) + , mIsQueued(false) { MOZ_ASSERT(aQueue != nullptr); } @@ -233,6 +237,18 @@ ThrottleInputStream::AllowInput() callbackEvent->OnInputStreamReady(this); } +bool +ThrottleInputStream::IsQueued() const +{ + return mIsQueued; +} + +void +ThrottleInputStream::SetQueued(bool aQueued) +{ + mIsQueued = aQueued; +} + //----------------------------------------------------------------------------- NS_IMPL_ISUPPORTS(ThrottleQueue, nsIInputChannelThrottleQueue, nsITimerCallback) @@ -348,6 +364,7 @@ ThrottleQueue::Notify(nsITimer* aTimer) // Optimistically notify all the waiting readers, and then let them // requeue if there isn't enough bandwidth. for (size_t i = 0; i < events.Length(); ++i) { + events[i]->SetQueued(false); events[i]->AllowInput(); } @@ -359,7 +376,8 @@ void ThrottleQueue::QueueStream(ThrottleInputStream* aStream) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); - if (mAsyncEvents.IndexOf(aStream) == mAsyncEvents.NoIndex) { + if (!aStream->IsQueued()) { + aStream->SetQueued(true); mAsyncEvents.AppendElement(aStream); if (!mTimerArmed) { @@ -386,7 +404,12 @@ void ThrottleQueue::DequeueStream(ThrottleInputStream* aStream) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + if (!aStream->IsQueued()) { + return; + } + mAsyncEvents.RemoveElement(aStream); + aStream->SetQueued(false); } } diff --git a/old-configure.in b/old-configure.in index a57bc7f5b9..ed4c8f2997 100644 --- a/old-configure.in +++ b/old-configure.in @@ -195,11 +195,6 @@ case "$target" in MSVC_CMP_RUNTIME_DLL=vcomp140.dll MSVC_CXX_RUNTIME_DLL=msvcp140.dll - MOZ_CHECK_HEADER(dia2.h, MSVC_HAS_DIA_SDK=1) - if test -n "$MSVC_HAS_DIA_SDK"; then - AC_DEFINE(MSVC_HAS_DIA_SDK) - fi - # C5026: move constructor was implicitly defined as deleted CXXFLAGS="$CXXFLAGS -wd5026" @@ -255,13 +250,6 @@ case "$target" in WIN32_REDIST_DIR=`cd "$WIN32_REDIST_DIR" && pwd -W` fi - # Check linker version - _LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` - _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'` - if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then - AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION, does not match the compiler suite version, $_CC_SUITE.]) - fi - INCREMENTAL_LINKER=1 # Set midl environment @@ -901,12 +889,18 @@ case "$target" in IMPORT_LIB_SUFFIX=lib MKSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' MKCSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' - dnl Set subsystem version 5 for Windows XP. + dnl Set subsystem version 4 for NT4/9x, version 5 for XP x64 + dnl Due to MSVC, set subsystem to 5 for XP x86 if test "$CPU_ARCH" = "x86"; then - WIN32_SUBSYSTEM_VERSION=5.01 + if test "$CC_TYPE" = "msvc"; then + WIN32_SUBSYSTEM_VERSION=5.01 + else + WIN32_SUBSYSTEM_VERSION=4.00 + fi else WIN32_SUBSYSTEM_VERSION=5.02 fi + WIN32_CONSOLE_EXE_LDFLAGS=-SUBSYSTEM:CONSOLE,$WIN32_SUBSYSTEM_VERSION WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION DSO_LDOPTS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION @@ -2838,7 +2832,7 @@ fi AC_SUBST(MOZ_RAW) dnl ======================================================== -dnl = Enable Libaom AV1 Codec +dnl = Enable dav1d AV1 Codec dnl ======================================================== MOZ_ARG_ENABLE_BOOL(av1, [ --enable-av1 Enable libaom for av1 video support], diff --git a/other-licenses/7zstub/dactyloidae/7zSD.sfx b/other-licenses/7zstub/dactyloidae/7zSD.sfx new file mode 100644 index 0000000000..01163de64a Binary files /dev/null and b/other-licenses/7zstub/dactyloidae/7zSD.sfx differ diff --git a/parser/html/java/htmlparser/src/nu/validator/htmlparser/impl/ElementName.java b/parser/html/java/htmlparser/src/nu/validator/htmlparser/impl/ElementName.java index 4b87d3fde2..4e5e482dae 100644 --- a/parser/html/java/htmlparser/src/nu/validator/htmlparser/impl/ElementName.java +++ b/parser/html/java/htmlparser/src/nu/validator/htmlparser/impl/ElementName.java @@ -2162,7 +2162,7 @@ public final class ElementName public static final ElementName SELECT = new ElementName("select", "select", // CPPONLY: NS_NewHTMLSelectElement, // CPPONLY: NS_NewSVGUnknownElement, - TreeBuilder.SELECT | SPECIAL); + TreeBuilder.SELECT | SPECIAL | SCOPING); public static final ElementName SCALARPRODUCT = new ElementName("scalarproduct", "scalarproduct", // CPPONLY: NS_NewHTMLUnknownElement, // CPPONLY: NS_NewSVGUnknownElement, diff --git a/parser/html/nsHtml5ElementName.cpp b/parser/html/nsHtml5ElementName.cpp index ecdfb102d4..4af8f7f289 100644 --- a/parser/html/nsHtml5ElementName.cpp +++ b/parser/html/nsHtml5ElementName.cpp @@ -866,7 +866,7 @@ nsHtml5ElementName::initializeStatics() ELT_RECT = new nsHtml5ElementName(nsHtml5Atoms::rect, nsHtml5Atoms::rect, NS_NewHTMLUnknownElement, NS_NewSVGRectElement, nsHtml5TreeBuilder::OTHER); ELT_RADIALGRADIENT = new nsHtml5ElementName(nsHtml5Atoms::radialgradient, nsHtml5Atoms::radialGradient, NS_NewHTMLUnknownElement, NS_NewSVGRadialGradientElement, nsHtml5TreeBuilder::OTHER); ELT_ROOT = new nsHtml5ElementName(nsHtml5Atoms::root, nsHtml5Atoms::root, NS_NewHTMLUnknownElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::OTHER); - ELT_SELECT = new nsHtml5ElementName(nsHtml5Atoms::select, nsHtml5Atoms::select, NS_NewHTMLSelectElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::SELECT | SPECIAL); + ELT_SELECT = new nsHtml5ElementName(nsHtml5Atoms::select, nsHtml5Atoms::select, NS_NewHTMLSelectElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::SELECT | SPECIAL | SCOPING); ELT_SCALARPRODUCT = new nsHtml5ElementName(nsHtml5Atoms::scalarproduct, nsHtml5Atoms::scalarproduct, NS_NewHTMLUnknownElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::OTHER); ELT_SUBSET = new nsHtml5ElementName(nsHtml5Atoms::subset, nsHtml5Atoms::subset, NS_NewHTMLUnknownElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::OTHER); ELT_SLOT = new nsHtml5ElementName(nsHtml5Atoms::slot, nsHtml5Atoms::slot, NS_NewHTMLSlotElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::OTHER); diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp index 76a2398f52..e7f6b591af 100644 --- a/parser/html/nsHtml5TreeBuilder.cpp +++ b/parser/html/nsHtml5TreeBuilder.cpp @@ -1216,6 +1216,14 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu } case HR: { implicitlyCloseP(); + if (findLastInScope(nsHtml5Atoms::select) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + generateImpliedEndTags(); + if (!!MOZ_UNLIKELY(mViewSource) && + (findLastInScope(nsHtml5Atoms::option) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK || + findLastInScope(nsHtml5Atoms::optgroup) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK)) { + errUnclosedElements(currentPtr, name); + } + } appendVoidElementToCurrentMayFoster(elementName, attributes); selfClosing = false; attributes = nullptr; @@ -1229,6 +1237,19 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu case IMG: case KEYGEN: case INPUT: { + if (fragment && nsHtml5Atoms::select == contextName) { + errStartTagWithSelectOpen(name); + NS_HTML5_BREAK(starttagloop); + } + eltPos = findLastInScope(nsHtml5Atoms::select); + if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + errStartTagWithSelectOpen(name); + while (currentPtr >= eltPos) { + pop(); + } + resetTheInsertionMode(); + NS_HTML5_CONTINUE(starttagloop); + } reconstructTheActiveFormattingElements(); appendVoidElementToCurrentMayFoster(elementName, attributes, formPointer); selfClosing = false; @@ -1313,33 +1334,54 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu NS_HTML5_BREAK(starttagloop); } case SELECT: { + if (fragment && nsHtml5Atoms::select == contextName) { + errStartSelectWhereEndSelectExpected(); + NS_HTML5_BREAK(starttagloop); + } + eltPos = findLastInScope(nsHtml5Atoms::select); + if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + errStartSelectWhereEndSelectExpected(); + while (currentPtr >= eltPos) { + pop(); + } + NS_HTML5_BREAK(starttagloop); + } reconstructTheActiveFormattingElements(); appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer); - switch(mode) { - case IN_TABLE: - case IN_CAPTION: - case IN_COLUMN_GROUP: - case IN_TABLE_BODY: - case IN_ROW: - case IN_CELL: { - mode = IN_SELECT_IN_TABLE; - break; - } - default: { - mode = IN_SELECT; - break; - } - } + framesetOk = false; attributes = nullptr; NS_HTML5_BREAK(starttagloop); } - case OPTGROUP: case OPTION: { - if (isCurrent(nsHtml5Atoms::option)) { + if (findLastInScope(nsHtml5Atoms::select) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + generateImpliedEndTagsExceptFor(nsHtml5Atoms::optgroup); + eltPos = findLastInScope(nsHtml5Atoms::option); + if (!!MOZ_UNLIKELY(mViewSource) && eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + errUnclosedElements(eltPos, name); + } + } else { + if (isCurrent(nsHtml5Atoms::option)) { + pop(); + } + } + reconstructTheActiveFormattingElements(); + appendToCurrentNodeAndPushElement(elementName, attributes); + attributes = nullptr; + NS_HTML5_BREAK(starttagloop); + } + case OPTGROUP: { + if (findLastInScope(nsHtml5Atoms::select) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + generateImpliedEndTags(); + if (!!MOZ_UNLIKELY(mViewSource) && + (findLastInScope(nsHtml5Atoms::option) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK || + findLastInScope(nsHtml5Atoms::optgroup) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK)) { + errUnclosedElements(currentPtr, name); + } + } else if (isCurrent(nsHtml5Atoms::option)) { pop(); } reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); + appendToCurrentNodeAndPushElement(elementName, attributes); attributes = nullptr; NS_HTML5_BREAK(starttagloop); } @@ -2697,6 +2739,21 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) case TEMPLATE: { break; } + case SELECT: { + eltPos = findLastInScope(name); + if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + errStrayEndTag(name); + } else { + generateImpliedEndTags(); + if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { + errUnclosedElements(eltPos, name); + } + while (currentPtr >= eltPos) { + pop(); + } + } + NS_HTML5_BREAK(endtagloop); + } case AREA_OR_WBR: #ifdef ENABLE_VOID_MENUITEM case MENUITEM: @@ -2712,7 +2769,6 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) case IFRAME: case NOEMBED: case NOFRAMES: - case SELECT: case TABLE: case TEXTAREA: { errStrayEndTag(name); @@ -3335,23 +3391,7 @@ nsHtml5TreeBuilder::resetTheInsertionMode() return; } } - if (nsHtml5Atoms::select == name) { - int32_t ancestorIndex = i; - while (ancestorIndex > 0) { - nsHtml5StackNode* ancestor = stack[ancestorIndex--]; - if (kNameSpaceID_XHTML == ancestor->ns) { - if (nsHtml5Atoms::template_ == ancestor->name) { - break; - } - if (nsHtml5Atoms::table == ancestor->name) { - mode = IN_SELECT_IN_TABLE; - return; - } - } - } - mode = IN_SELECT; - return; - } else if (nsHtml5Atoms::td == name || nsHtml5Atoms::th == name) { + if (nsHtml5Atoms::td == name || nsHtml5Atoms::th == name) { mode = IN_CELL; return; } else if (nsHtml5Atoms::tr == name) { diff --git a/parser/htmlparser/tests/mochitest/mochitest.ini b/parser/htmlparser/tests/mochitest/mochitest.ini index dcb30d6e80..0d089e9b02 100644 --- a/parser/htmlparser/tests/mochitest/mochitest.ini +++ b/parser/htmlparser/tests/mochitest/mochitest.ini @@ -147,3 +147,4 @@ skip-if = toolkit == 'android' #TIMED_OUT # Disable test due to frequent orange on Mac # test_bug534293.html [test_bug1209658.html] +[test_select_parser_relaxed.html] diff --git a/parser/htmlparser/tests/mochitest/test_select_parser_relaxed.html b/parser/htmlparser/tests/mochitest/test_select_parser_relaxed.html new file mode 100644 index 0000000000..d78947dc5b --- /dev/null +++ b/parser/htmlparser/tests/mochitest/test_select_parser_relaxed.html @@ -0,0 +1,54 @@ + + + + + + Test for relaxed select parser rules + + + + +
+
+
+ + diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py index ef9406ea5b..4fdca1365b 100644 --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -1803,6 +1803,17 @@ VARIABLES = { If yasm is not available on this system, or does not support the current target architecture, an error will be raised. """), + + 'USE_NASM': (bool, bool, + """Use the nasm assembler to assemble assembly files from SOURCES. + + By default, the build will use the toolchain assembler, $(AS), to + assemble source files in assembly language (.s or .asm files). Setting + this value to ``True`` will cause it to use nasm instead. + + If nasm is not available on this system, or does not support the + current target architecture, an error will be raised. + """), } # Sanity check: we don't want any variable above to have a list as storage type. diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index 6220cd4b4b..051ed1c030 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -1005,24 +1005,13 @@ class TreeMetadataEmitter(LoggingMixin): passthru.variables['AS'] = yasm passthru.variables['ASFLAGS'] = context.config.substs.get('YASM_ASFLAGS') passthru.variables['AS_DASH_C_FLAG'] = '' - - for (symbol, cls) in [ - ('ANDROID_RES_DIRS', AndroidResDirs), - ('ANDROID_EXTRA_RES_DIRS', AndroidExtraResDirs), - ('ANDROID_ASSETS_DIRS', AndroidAssetsDirs)]: - paths = context.get(symbol) - if not paths: - continue - for p in paths: - if isinstance(p, SourcePath) and not os.path.isdir(p.full_path): - raise SandboxValidationError('Directory listed in ' - '%s is not a directory: \'%s\'' % - (symbol, p.full_path), context) - yield cls(context, paths) - - android_extra_packages = context.get('ANDROID_EXTRA_PACKAGES') - if android_extra_packages: - yield AndroidExtraPackages(context, android_extra_packages) + if context.get('USE_NASM') is True: + nasm = context.config.substs.get('NASM') + if not nasm or not context.config.substs.get('HAVE_NASM'): + raise SandboxValidationError('nasm 2.14 or later is not available', context) + passthru.variables['AS'] = nasm + passthru.variables['ASFLAGS'] = context.config.substs.get('NASM_ASFLAGS') + passthru.variables['AS_DASH_C_FLAG'] = '' if passthru.variables: yield passthru diff --git a/security/nss/lib/softoken/lowpbe.c b/security/nss/lib/softoken/lowpbe.c index 55808f0f7d..c71f7f82e8 100644 --- a/security/nss/lib/softoken/lowpbe.c +++ b/security/nss/lib/softoken/lowpbe.c @@ -604,6 +604,7 @@ sftk_clearPBECommonCacheItemsLocked(KDFCacheItem *item) } } +static SECStatus sftk_setPBECommonCacheItemsKDFLocked(KDFCacheItem *cacheItem, const SECItem *hash, const NSSPKCS5PBEParameter *pbe_param, @@ -615,6 +616,8 @@ sftk_setPBECommonCacheItemsKDFLocked(KDFCacheItem *cacheItem, cacheItem->keyLen = pbe_param->keyLen; cacheItem->salt = SECITEM_DupItem(&pbe_param->salt); cacheItem->pwItem = SECITEM_DupItem(pwItem); + + return SECSuccess; } static void diff --git a/security/nss/lib/util/quickder.c b/security/nss/lib/util/quickder.c index 70ae42b270..e8047c13df 100644 --- a/security/nss/lib/util/quickder.c +++ b/security/nss/lib/util/quickder.c @@ -8,7 +8,6 @@ #include "secerr.h" #include "secasn1.h" /* for SEC_ASN1GetSubtemplate */ -#include "secitem.h" /* * simple definite-length ASN.1 decoder diff --git a/toolkit/fonts/moz.build b/toolkit/fonts/moz.build index bfdff9e075..129a7737c6 100644 --- a/toolkit/fonts/moz.build +++ b/toolkit/fonts/moz.build @@ -3,5 +3,4 @@ # 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/. -if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'): - FINAL_TARGET_FILES.fonts += ['TwemojiMozilla.ttf'] +FINAL_TARGET_FILES.fonts += ['TwemojiMozilla.ttf'] diff --git a/widget/milsko/README.md b/widget/milsko/README.md new file mode 100644 index 0000000000..0f08d8d270 --- /dev/null +++ b/widget/milsko/README.md @@ -0,0 +1,4 @@ +Dactyloidae Milsko Toolkit (WIP) + +This is a modified version of Milsko 1.4 (latest release as of 28/7/26, DD/MM/YY), +adapted for use on you know, a web browser. diff --git a/widget/milsko/milskosrc/.clang-format b/widget/milsko/milskosrc/.clang-format new file mode 100644 index 0000000000..eb9d30cc5a --- /dev/null +++ b/widget/milsko/milskosrc/.clang-format @@ -0,0 +1,24 @@ +--- +UseTab: Always +TabWidth: 8 +AlignConsecutiveAssignments: + Enabled: true +AlignConsecutiveDeclarations: + Enabled: true +AccessModifierOffset: -4 +NamespaceIndentation: All +IndentWidth: 8 +PointerAlignment: Left +ColumnLimit: 0 +AllowShortIfStatementsOnASingleLine: Always +AllowShortBlocksOnASingleLine: Never +AllowShortFunctionsOnASingleLine: Empty +AllowShortLoopsOnASingleLine: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: true +SpaceBeforeParens: Never +AlignEscapedNewlines: DontAlign +SortIncludes: false +AllowShortEnumsOnASingleLine: false +#IndentPPDirectives: AfterHash diff --git a/widget/milsko/milskosrc/.clangd b/widget/milsko/milskosrc/.clangd new file mode 100644 index 0000000000..1058f6f19f --- /dev/null +++ b/widget/milsko/milskosrc/.clangd @@ -0,0 +1,3 @@ +Completion: + HeaderInsertion: Never +ClangFormat: Tab diff --git a/widget/milsko/milskosrc/.gitattributes b/widget/milsko/milskosrc/.gitattributes new file mode 100644 index 0000000000..b43059cfd1 --- /dev/null +++ b/widget/milsko/milskosrc/.gitattributes @@ -0,0 +1,17 @@ +/external/*.h linguist-generated +/external/*.c linguist-generated +/external/libjpeg/include/*.h linguist-generated +/external/libjpeg/src/*.c linguist-generated +/external/libjpeg/src/*.h linguist-generated +/external/libz/include/*.h linguist-generated +/external/libz/src/*.c linguist-generated +/external/libz/src/*.h linguist-generated +/external/libpng/include/*.h linguist-generated +/external/libpng/src/*.c linguist-generated +/external/libpng/src/*.h linguist-generated +/resource/doxygen-theme/* linguist-generated +/src/icon/*.c linguist-generated +/src/font/*.c linguist-generated +/BorMakefile linguist-generated +/WatMakefile linguist-generated +/NTMakefile linguist-generated diff --git a/widget/milsko/milskosrc/.gitignore b/widget/milsko/milskosrc/.gitignore new file mode 100644 index 0000000000..58b172adaa --- /dev/null +++ b/widget/milsko/milskosrc/.gitignore @@ -0,0 +1,33 @@ +examples/* +examples/*.exe +examples/*/* +examples/*/*.exe +!examples/*/ +!examples/*.* +!examples/*/*.* +*.exe +*.o +*.obj +*.core +*.so +*.dll +*.lib +*.dylib +*.a +/Makefile +/build +compile_flags.txt +.cache +.DS_Store +/vms +/BorMakefile +*.err +*.zip + +*.pef +*.dsk +*.bin +*.rsrc +*.finf +*.gdb + diff --git a/widget/milsko/milskosrc/CHANGELOG.txt b/widget/milsko/milskosrc/CHANGELOG.txt new file mode 100644 index 0000000000..83daed86b4 --- /dev/null +++ b/widget/milsko/milskosrc/CHANGELOG.txt @@ -0,0 +1,17 @@ +========================= 1.4 ========================= +- CMakeLists.txt downgraded to version 3.13 to allow compiling on Windows XP +- CMake build now generates a pkgconfig file. +- GDI backend now natively uses GDI for text rendering +- Widgets can now be disabled with MwNdisabled +- Added `MwTabFocus` for letting a tab widget steal focus. +- New table widget (`MwTableClass`). +- Added `MwWindowShouldClose` for letting custom loops know when a window should close. +- Remove VMS build files +- Entry widgets now have blinking cursor that appears only when you hover over the widget. +- Wayland backend: + - Can now create layer surfaces (Use `MwLLMakeToolWindow` on a parentless window) + - Now properly handles keys being held down + - has drastically improved CSD (functionality wise) + - Uses KMSDRM directly for the OpenGL widget instead of wl_egl for a smoother experience + - Various overall performance improvements putting it on the same level as the X11 backend finally + - Menu widget works better under compositors that use CSD. diff --git a/widget/milsko/milskosrc/CMakeLists.txt b/widget/milsko/milskosrc/CMakeLists.txt new file mode 100644 index 0000000000..b9e90d0f79 --- /dev/null +++ b/widget/milsko/milskosrc/CMakeLists.txt @@ -0,0 +1,508 @@ +cmake_minimum_required(VERSION 3.13) +project( + milsko +) + +include(CheckIncludeFiles) + +include(GNUInstallDirs) +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +if(WIN32) + set(CMAKE_STATIC_LIBRARY_PREFIX "") + set(CMAKE_SHARED_LIBRARY_PREFIX "") +endif() + +option(MW_CLASSIC_THEME "Use classic theme" OFF) +option(MW_BUILD_EXAMPLES "Build examples" OFF) +option(MW_USE_STB_IMAGE "Use stb_image" ON) +option(MW_USE_STB_TRUETYPE "Use stb_truetype" OFF) + +if(${CMAKE_SYSTEM_NAME} MATCHES Retro) + option(MW_BUILD_SHARED "Build a shared library" OFF) + option(MW_BUILD_STATIC "Build a static library" ON) + option(MW_TRY_OPENGL "Try to compile OpenGL widget or not" OFF) + option(MW_TRY_VULKAN "Try to compile Vulkan widget or not" OFF) +else() + option(MW_BUILD_SHARED "Build a shared library" ON) + option(MW_BUILD_STATIC "Build a static library" OFF) + option(MW_TRY_OPENGL "Try to compile OpenGL widget or not" ON) + option(MW_TRY_VULKAN "Try to compile Vulkan widget or not" ON) +endif() + +option(MW_INSTALL_HEADERS "Install headers" ON) + +if( ${CMAKE_SYSTEM_NAME} STREQUAL Darwin + OR ${CMAKE_SYSTEM_NAME} MATCHES Retro + OR ${CMAKE_SYSTEM_NAME} MATCHES Windows) + option(MW_USE_FREETYPE2 "Use FreeType 2" OFF) +else() + option(MW_USE_FREETYPE2 "Use FreeType 2" ON) +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL Windows) + option(MW_USE_GDI_TEXT "Use GDI for text rendering" ON) +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL Linux OR ${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD) + option(MW_USE_WAYLAND "Enable Wayland backend" ON) +endif() + +file( + GLOB + SOURCES + external/libz/src/*.c src/*.c src/cursor/*.c src/icon/*.c src/widget/*.c src/text/*.c src/text/font/*.c src/dialog/*.c src/abstract/*.c external/*.c +) + +if(NOT MW_USE_STB_IMAGE) + list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_image.c") +endif() + +if(NOT MW_USE_STB_TRUETYPE) + list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_truetype.c") +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") + list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/X11R7/include") + list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/pkg/include") +endif() + +if(MW_TRY_OPENGL) + find_package(OpenGL) + if(OpenGL_FOUND AND NOT APPLE) + set(MW_BUILD_OPENGL ON) + message(STATUS "OpenGL widget has been enabled") + else() + message(WARNING "OpenGL widget has been disabled") + endif() +endif() + +if(MW_TRY_VULKAN) + find_package(Vulkan) + if(${Vulkan_FOUND}) + set(MW_BUILD_VULKAN ON) + message(STATUS "Vulkan widget has been enabled") + else() + message(WARNING "Vulkan widget has been disabled") + endif() +endif() + +if(MW_BUILD_STATIC) + message(STATUS "Building Milsko as a static library") + add_library( + Mw + ${SOURCES} +) +elseif(MW_BUILD_SHARED) + message(STATUS "Building Milsko as a shared library") + add_library( + Mw + SHARED + ${SOURCES} +) +else() + message(ERROR "Must either build a shared library or a static library") +endif() + +if(MW_USE_STB_IMAGE) + target_compile_definitions( + Mw + PRIVATE + USE_STB_IMAGE + ) +else() + file( + GLOB + IMAGE_SOURCES + external/libjpeg/src/*.c external/libpng/src/*.c + ) + target_sources( + Mw + PRIVATE + ${MW_IMAGE_SOURCES} + ) + target_include_directories( + Mw + PRIVATE + external/libjpeg/include external/libpng/include + ) +endif() + +if(MW_USE_STB_TRUETYPE) + target_compile_definitions( + Mw + PRIVATE + USE_STB_TRUETYPE + ) +endif() + +if(MW_USE_FREETYPE2) + find_package(Freetype) + if(Freetype_FOUND) + message(STATUS "FreeType2 found") + target_compile_definitions( + Mw + PRIVATE + USE_FREETYPE2 + ) + + list(APPEND INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${FREETYPE_LIBRARY_DIRS}) + else() + message(WARNING "FreeType2 not found") + endif() +endif() + + +if(MW_USE_GDI_TEXT) + target_compile_definitions( + Mw + PRIVATE + USE_GDI_TEXT + ) +endif() + +if(MW_USE_WAYLAND) + function(scan_wayland_protocol_core) + execute_process( + COMMAND wayland-scanner private-code /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-core-protocol.c + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + target_sources( + Mw + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-core-protocol.c + ) + execute_process( + COMMAND wayland-scanner client-header /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/wayland-core-protocol.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + endfunction() + + function(scan_wayland_protocol tier proto ver) + SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-${proto}-protocol.c) + execute_process( + COMMAND wayland-scanner private-code /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${proto_c} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + target_sources( + Mw + PRIVATE + ${proto_c} + ) + execute_process( + COMMAND wayland-scanner client-header /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/${proto}-client-protocol.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + endfunction() + + function(scan_wayland_protocol_from_file proto file) + SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland/wayland-${proto}-protocol.c) + execute_process( + COMMAND wayland-scanner private-code ${CMAKE_CURRENT_SOURCE_DIR}/resource/wayland/${file} ${proto_c} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + target_sources( + Mw + PRIVATE + ${proto_c} + ) + execute_process( + COMMAND wayland-scanner client-header ${CMAKE_CURRENT_SOURCE_DIR}/resource/wayland/${file} ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/${proto}-client-protocol.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + endfunction() + + check_include_files(wayland-client.h HAVE_WL_H) + check_include_files(xkbcommon/xkbcommon.h HAVE_XKBCOMMON_H) + check_include_files(cairo/cairo.h HAVE_CAIRO_H) + if(HAVE_WL_H) + if(HAVE_XKBCOMMON_H) + if(HAVE_CAIRO_H) + scan_wayland_protocol_core() + scan_wayland_protocol("stable" "xdg-shell" "") + scan_wayland_protocol("stable" "viewporter" "") + scan_wayland_protocol("stable" "tablet" "-v2") + scan_wayland_protocol("staging" "xdg-toplevel-icon" "-v1") + scan_wayland_protocol("staging" "cursor-shape" "-v1") + scan_wayland_protocol("unstable" "xdg-decoration" "-unstable-v1") + scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") + scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") + scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1") + scan_wayland_protocol_from_file("wlr-layer-shell" "wlr-layer-shell-unstable-v1.xml") + + target_sources( + Mw + PRIVATE + src/backend/cairo.c + src/backend/wayland/wayland.c + src/backend/wayland/buffer.c + src/backend/wayland/interfaces.c + src/backend/wayland/region.c + ) + target_compile_definitions( + Mw + PRIVATE + USE_WAYLAND + ) + message(STATUS "Wayland backend has been enabled") + else() + message(WARNING "Wayland backend has been disabled") + endif() + else() + message(WARNING "Wayland backend has been disabled") + endif() + else() + message(WARNING "Wayland backend has been disabled") + endif() +endif() + +if(APPLE AND MW_BUILD_OPENGL) + target_compile_definitions( + Mw + PRIVATE + GL_SILENCE_DEPRECATION + ) +endif() + +target_include_directories( + Mw + PRIVATE + external/libz/include +) + +target_include_directories( + Mw + PUBLIC + include +) + +if(MW_CLASSIC_THEME) + target_compile_definitions( + Mw + PRIVATE + USE_CLASSIC_THEME + ) +endif() + +message("Building Milsko for ${CMAKE_SYSTEM_NAME}") +if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME STREQUAL "MSYS") + target_sources( + Mw + PRIVATE + src/backend/gdi.c + ) + target_compile_definitions( + Mw + PRIVATE + USE_GDI + ) + list(APPEND LIBRARIES gdi32 winmm) + target_link_options( + Mw + PRIVATE + -static-libgcc + ) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # target_sources( + # Mw + # PRIVATE + # src/backend/cocoa.m + # ) + target_sources( + Mw + PRIVATE + src/backend/nococoa.m +) + # target_compile_definitions( + # Mw + # PRIVATE + # USE_COCOA + # ) + list(APPEND LIBRARIES objc) + target_link_options( + Mw + PRIVATE + -framework Cocoa + ) +elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") + + target_sources( + Mw + PRIVATE + src/backend/classicmacos.c + ) + if(PLATFORM MATCHES retroppc) + set_target_properties(Mw PROPERTIES COMPILE_FLAGS "-ffunction-sections -mcpu=601 -Os -Wall -Wextra -Wno-unused-parameter") + set_target_properties(Mw PROPERTIES LINK_FLAGS "-Wl,-gc-sections") + endif() + + list(APPEND LIBRARIES InterfaceLib WindowsLib ThreadsLib) + + target_compile_definitions( + Mw + PRIVATE + CLASSIC_MAC_OS + ) +else() + + find_package(PkgConfig) + find_package(X11) + pkg_check_modules(DBUS dbus-1) + + target_sources( + Mw + PRIVATE + src/backend/x11.c + ) + + if(${X11_FOUND}) + list(APPEND INCLUDE_DIRS ${X11_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${X11_LIBRARY_DIRS}) + target_compile_definitions( + Mw + PRIVATE + USE_X11 + ) + endif() + if(${X11_Xrender_FOUND}) + list(APPEND INCLUDE_DIRS ${XRENDER_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${XRENDER_LIBRARY_DIRS}) + target_compile_definitions( + Mw + PRIVATE + USE_XRENDER + ) + endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND LIBRARIES dl) + endif() + + find_package(DBus1) + + if(${DBus1_FOUND}) + list(APPEND INCLUDE_DIRS ${DBUS_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${DBUS_LIBRARY_DIRS}) + target_compile_definitions( + Mw + PRIVATE + USE_DBUS + ) + endif() +endif() + + + +if(UNIX) + list(APPEND LIBRARIES m) +endif() + +target_include_directories( + Mw + PRIVATE + ${INCLUDE_DIRS} +) +target_link_directories( + Mw + PRIVATE + ${LIBRARY_DIRS} +) +target_link_libraries( + Mw + PRIVATE + ${LIBRARIES} +) + +if(MW_BUILD_OPENGL) + target_compile_definitions( + Mw + PRIVATE + MW_OPENGL + ) +endif() + +if(MW_BUILD_VULKAN) + check_include_files(vulkan/vk_enum_string_helper.h HAS_VK_ENUM_STRING_HELPER) + if(HAS_VK_ENUM_STRING_HELPER) + target_compile_definitions( + Mw + PRIVATE + HAS_VK_ENUM_STRING_HELPER + ) + endif() + + target_compile_definitions( + Mw + PRIVATE + MW_VULKAN + ) +endif() + +target_compile_definitions( + Mw + PRIVATE + _MILSKO _MILSKO_BUILD +) + +install( + TARGETS Mw + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/resource/${PROJECT_NAME}.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + @ONLY + ) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION $ENV{MINGW_PREFIX}/${CMAKE_INSTALL_DATADIR}/pkgconfig + ) + +if(MW_INSTALL_HEADERS) + install( + DIRECTORY include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h" + ) +endif() + +if(MW_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/widget/milsko/milskosrc/Doxyfile b/widget/milsko/milskosrc/Doxyfile new file mode 100644 index 0000000000..f413308118 --- /dev/null +++ b/widget/milsko/milskosrc/Doxyfile @@ -0,0 +1,26 @@ +PROJECT_LOGO = resource/logo/logo64.png +PROJECT_NAME = Milsko +PROJECT_BRIEF = "Lightweight and fast GUI toolkit" +OUTPUT_DIRECTORY = doxygen +TAB_SIZE = 8 +OPTIMIZE_OUTPUT_FOR_C = YES +MARKDOWN_SUPPORT = YES +FILE_PATTERNS = *.h *.md +INPUT = include/Mw +INPUT += doc +RECURSIVE = YES +SOURCE_BROWSER = YES +HTML_DYNAMIC_MENUS = YES +GENERATE_TREEVIEW = YES +FULL_SIDEBAR = NO +DISABLE_INDEX = NO +HAVE_DOT = YES +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = include/ doc/ +ENABLED_SECTIONS = YES +OUTPUT_LANGUAGE = English +GENERATE_LATEX = NO +EXTRACT_ALL = YES + +HTML_EXTRA_STYLESHEET = resource/doxygen-theme/doxygen-awesome.css +HTML_COLORSTYLE = LIGHT diff --git a/widget/milsko/milskosrc/Jenkinsfile b/widget/milsko/milskosrc/Jenkinsfile new file mode 100644 index 0000000000..6c1637e8cb --- /dev/null +++ b/widget/milsko/milskosrc/Jenkinsfile @@ -0,0 +1,105 @@ +pipeline { + agent { + label "built-in" + } + stages { + stage("Build document") { + when { + branch "master" + } + agent { + label "built-in" + } + steps { + sh("rm -rf include/Mw/LowLevel/Wayland") + sh("doxygen") + sh("rm -rf /var/www/milsko-doxygen") + sh("mv doxygen/html /var/www/milsko-doxygen") + } + post { + always { + notifyDiscord() + } + } + } + stage("Build") { + parallel { + stage("Build for Linux 64-bit") { + agent { + label "built-in" + } + steps { + sh("git clean -dfx") + sh("./configure --enable-opengl --enable-vulkan --without-vulkan-string-helper") + sh("make -j4") + sh("mv src/libMw.so libMw64.so") + archiveArtifacts("libMw64.so") + } + } + stage("Build for Windows 32-bit") { + agent { + label "built-in" + } + steps { + sh("git clean -dfx") + sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32") + sh("make -j4") + sh("mv src/Mw.dll Mw32.dll") + sh("mv src/libMw.dll.a libMw32.dll.a") + archiveArtifacts("Mw32.dll,libMw32.dll.a") + } + } + stage("Build for Windows 64-bit") { + agent { + label "built-in" + } + steps { + sh("git clean -dfx") + sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32") + sh("make -j4") + sh("mv src/Mw.dll Mw64.dll") + sh("mv src/libMw.dll.a libMw64.dll.a") + archiveArtifacts("Mw64.dll,libMw64.dll.a") + } + } + stage("Build for Windows 32-bit (MSVC)") { + agent { + label "2012r2" + } + steps { + bat("git clean -dfx") + bat("nmake -f NTMakefile") + bat("move /y src\\Mw.dll MwMSVC32.dll") + bat("move /y src\\Mw.lib MwMSVC32.lib") + archiveArtifacts("MwMSVC32.dll,MwMSVC32.lib") + } + } + stage("Build for Windows 32-bit (Watcom)") { + agent { + label "built-in" + } + environment { + WATCOM = "/usr/watcom" + INCLUDE = "/usr/watcom/h:/usr/watcom/h/nt" + PATH = "/usr/watcom/binl64:${env.PATH}" + } + steps { + sh("git clean -dfx") + sh("wmake -f WatMakefile") + sh("mv src/Mw.dll MwWat32.dll") + sh("mv src/Mw.lib MwWat32.lib") + archiveArtifacts("MwWat32.dll,MwWat32.lib") + sh("./tools/watcom-pack.sh") + sh("mv milsko-examples.zip milsko-examples-win32.zip") + archiveArtifacts("milsko-examples-win32.zip") + } + } + } + post { + always { + notifyDiscord() + } + } + } + } +} diff --git a/widget/milsko/milskosrc/LICENSE b/widget/milsko/milskosrc/LICENSE new file mode 100644 index 0000000000..a7729adbf9 --- /dev/null +++ b/widget/milsko/milskosrc/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2025-2026, Pyrite development team +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/widget/milsko/milskosrc/NTMakefile b/widget/milsko/milskosrc/NTMakefile new file mode 100644 index 0000000000..a3fc76a36a --- /dev/null +++ b/widget/milsko/milskosrc/NTMakefile @@ -0,0 +1,328 @@ +CC = cl /TC /c /nologo +LD = link /nologo + +MW_CFLAGS = /Iinclude /Iexternal\libz\include /D_MILSKO /D_MILSKO_BUILD /DUSE_GDI /DUSE_STB_IMAGE /DSTBI_NO_SIMD /DUSE_GDI_TEXT +MW_LDFLAGS = /DLL +EXE_CFLAGS = /Iinclude +EXE_LDFLAGS = +.SUFFIXES: .obj .c +all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +lib: src\Mw.dll +examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +clean: + del /f /q external\libz\src\adler32.obj + del /f /q external\libz\src\compress.obj + del /f /q external\libz\src\crc32.obj + del /f /q external\libz\src\deflate.obj + del /f /q external\libz\src\gzclose.obj + del /f /q external\libz\src\gzlib.obj + del /f /q external\libz\src\gzread.obj + del /f /q external\libz\src\gzwrite.obj + del /f /q external\libz\src\infback.obj + del /f /q external\libz\src\inffast.obj + del /f /q external\libz\src\inflate.obj + del /f /q external\libz\src\inftrees.obj + del /f /q external\libz\src\trees.obj + del /f /q external\libz\src\uncompr.obj + del /f /q external\libz\src\zutil.obj + del /f /q external\stb_ds.obj + del /f /q external\stb_image.obj + del /f /q external\stb_truetype.obj + del /f /q src\abstract\charset.obj + del /f /q src\abstract\directory.obj + del /f /q src\abstract\dynamic.obj + del /f /q src\abstract\time.obj + del /f /q src\backend\gdi.obj + del /f /q src\color.obj + del /f /q src\core.obj + del /f /q src\cursor\arrow.obj + del /f /q src\cursor\cross.obj + del /f /q src\cursor\default.obj + del /f /q src\cursor\hidden.obj + del /f /q src\cursor\text.obj + del /f /q src\default.obj + del /f /q src\dialog\colorpicker.obj + del /f /q src\dialog\directorychooser.obj + del /f /q src\dialog\filechooser.obj + del /f /q src\dialog\messagebox.obj + del /f /q src\draw.obj + del /f /q src\icon\back.obj + del /f /q src\icon\clock.obj + del /f /q src\icon\computer.obj + del /f /q src\icon\directory.obj + del /f /q src\icon\down.obj + del /f /q src\icon\error.obj + del /f /q src\icon\file.obj + del /f /q src\icon\forward.obj + del /f /q src\icon\info.obj + del /f /q src\icon\left.obj + del /f /q src\icon\news.obj + del /f /q src\icon\note.obj + del /f /q src\icon\right.obj + del /f /q src\icon\search.obj + del /f /q src\icon\up.obj + del /f /q src\icon\warning.obj + del /f /q src\lowlevel.obj + del /f /q src\string.obj + del /f /q src\text\font\boldfont.obj + del /f /q src\text\font\boldmonottf.obj + del /f /q src\text\font\boldttf.obj + del /f /q src\text\font\font.obj + del /f /q src\text\font\monottf.obj + del /f /q src\text\font\ttf.obj + del /f /q src\text\ft2.obj + del /f /q src\text\gdi.obj + del /f /q src\text\stbtt.obj + del /f /q src\text\text.obj + del /f /q src\truetype.obj + del /f /q src\unicode.obj + del /f /q src\widget\box.obj + del /f /q src\widget\button.obj + del /f /q src\widget\calendar.obj + del /f /q src\widget\checkbox.obj + del /f /q src\widget\combobox.obj + del /f /q src\widget\entry.obj + del /f /q src\widget\frame.obj + del /f /q src\widget\image.obj + del /f /q src\widget\label.obj + del /f /q src\widget\listbox.obj + del /f /q src\widget\menu.obj + del /f /q src\widget\numberentry.obj + del /f /q src\widget\opengl.obj + del /f /q src\widget\progressbar.obj + del /f /q src\widget\radiobox.obj + del /f /q src\widget\scrollbar.obj + del /f /q src\widget\separator.obj + del /f /q src\widget\submenu.obj + del /f /q src\widget\subwindow.obj + del /f /q src\widget\tab.obj + del /f /q src\widget\table.obj + del /f /q src\widget\treeview.obj + del /f /q src\widget\viewport.obj + del /f /q src\widget\window.obj + del /f /q src\Mw.dll + del /f /q src\Mw.lib + del /f /q examples\basic\box.obj + del /f /q examples\basic\calculator.obj + del /f /q examples\basic\checkbox.obj + del /f /q examples\basic\clipboard.obj + del /f /q examples\basic\colorpicker.obj + del /f /q examples\basic\combobox.obj + del /f /q examples\basic\example.obj + del /f /q examples\basic\filechooser.obj + del /f /q examples\basic\image.obj + del /f /q examples\basic\listbox.obj + del /f /q examples\basic\messagebox.obj + del /f /q examples\basic\periodic.obj + del /f /q examples\basic\progressbar.obj + del /f /q examples\basic\radiobox.obj + del /f /q examples\basic\rotate.obj + del /f /q examples\basic\scrollbar.obj + del /f /q examples\basic\sevensegment.obj + del /f /q examples\basic\subwindow.obj + del /f /q examples\basic\tab.obj + del /f /q examples\basic\treeview.obj + del /f /q examples\basic\viewport.obj + del /f /q examples\gldemos\boing.obj + del /f /q examples\gldemos\clock.obj + del /f /q examples\gldemos\cube.obj + del /f /q examples\gldemos\gears.obj + del /f /q examples\gldemos\triangle.obj + del /f /q examples\gldemos\tripaint.obj + del /f /q examples\basic\box.exe + del /f /q examples\basic\calculator.exe + del /f /q examples\basic\checkbox.exe + del /f /q examples\basic\clipboard.exe + del /f /q examples\basic\colorpicker.exe + del /f /q examples\basic\combobox.exe + del /f /q examples\basic\example.exe + del /f /q examples\basic\filechooser.exe + del /f /q examples\basic\image.exe + del /f /q examples\basic\listbox.exe + del /f /q examples\basic\messagebox.exe + del /f /q examples\basic\periodic.exe + del /f /q examples\basic\progressbar.exe + del /f /q examples\basic\radiobox.exe + del /f /q examples\basic\rotate.exe + del /f /q examples\basic\scrollbar.exe + del /f /q examples\basic\sevensegment.exe + del /f /q examples\basic\subwindow.exe + del /f /q examples\basic\tab.exe + del /f /q examples\basic\treeview.exe + del /f /q examples\basic\viewport.exe + del /f /q examples\gldemos\boing.exe + del /f /q examples\gldemos\clock.exe + del /f /q examples\gldemos\cube.exe + del /f /q examples\gldemos\gears.exe + del /f /q examples\gldemos\triangle.exe + del /f /q examples\gldemos\tripaint.exe + +examples\basic\box.exe: examples\basic\box.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\box.obj src\Mw.lib + +examples\basic\box.obj: examples/basic/box.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/box.c + +examples\basic\calculator.exe: examples\basic\calculator.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\calculator.obj src\Mw.lib + +examples\basic\calculator.obj: examples/basic/calculator.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/calculator.c + +examples\basic\checkbox.exe: examples\basic\checkbox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\checkbox.obj src\Mw.lib + +examples\basic\checkbox.obj: examples/basic/checkbox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/checkbox.c + +examples\basic\clipboard.exe: examples\basic\clipboard.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\clipboard.obj src\Mw.lib + +examples\basic\clipboard.obj: examples/basic/clipboard.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/clipboard.c + +examples\basic\colorpicker.exe: examples\basic\colorpicker.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\colorpicker.obj src\Mw.lib + +examples\basic\colorpicker.obj: examples/basic/colorpicker.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/colorpicker.c + +examples\basic\combobox.exe: examples\basic\combobox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\combobox.obj src\Mw.lib + +examples\basic\combobox.obj: examples/basic/combobox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/combobox.c + +examples\basic\example.exe: examples\basic\example.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\example.obj src\Mw.lib + +examples\basic\example.obj: examples/basic/example.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/example.c + +examples\basic\filechooser.exe: examples\basic\filechooser.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\filechooser.obj src\Mw.lib + +examples\basic\filechooser.obj: examples/basic/filechooser.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/filechooser.c + +examples\basic\image.exe: examples\basic\image.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\image.obj src\Mw.lib + +examples\basic\image.obj: examples/basic/image.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/image.c + +examples\basic\listbox.exe: examples\basic\listbox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\listbox.obj src\Mw.lib + +examples\basic\listbox.obj: examples/basic/listbox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/listbox.c + +examples\basic\messagebox.exe: examples\basic\messagebox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\messagebox.obj src\Mw.lib + +examples\basic\messagebox.obj: examples/basic/messagebox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/messagebox.c + +examples\basic\periodic.exe: examples\basic\periodic.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\periodic.obj src\Mw.lib + +examples\basic\periodic.obj: examples/basic/periodic.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/periodic.c + +examples\basic\progressbar.exe: examples\basic\progressbar.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\progressbar.obj src\Mw.lib + +examples\basic\progressbar.obj: examples/basic/progressbar.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/progressbar.c + +examples\basic\radiobox.exe: examples\basic\radiobox.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\radiobox.obj src\Mw.lib + +examples\basic\radiobox.obj: examples/basic/radiobox.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/radiobox.c + +examples\basic\rotate.exe: examples\basic\rotate.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\rotate.obj src\Mw.lib + +examples\basic\rotate.obj: examples/basic/rotate.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/rotate.c + +examples\basic\scrollbar.exe: examples\basic\scrollbar.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\scrollbar.obj src\Mw.lib + +examples\basic\scrollbar.obj: examples/basic/scrollbar.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/scrollbar.c + +examples\basic\sevensegment.exe: examples\basic\sevensegment.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\sevensegment.obj src\Mw.lib + +examples\basic\sevensegment.obj: examples/basic/sevensegment.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/sevensegment.c + +examples\basic\subwindow.exe: examples\basic\subwindow.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\subwindow.obj src\Mw.lib + +examples\basic\subwindow.obj: examples/basic/subwindow.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/subwindow.c + +examples\basic\tab.exe: examples\basic\tab.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\tab.obj src\Mw.lib + +examples\basic\tab.obj: examples/basic/tab.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/tab.c + +examples\basic\treeview.exe: examples\basic\treeview.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\treeview.obj src\Mw.lib + +examples\basic\treeview.obj: examples/basic/treeview.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/treeview.c + +examples\basic\viewport.exe: examples\basic\viewport.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\viewport.obj src\Mw.lib + +examples\basic\viewport.obj: examples/basic/viewport.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/viewport.c + +examples\gldemos\boing.exe: examples\gldemos\boing.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\boing.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\boing.obj: examples/gldemos/boing.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/boing.c + +examples\gldemos\clock.exe: examples\gldemos\clock.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\clock.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\clock.obj: examples/gldemos/clock.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/clock.c + +examples\gldemos\cube.exe: examples\gldemos\cube.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\cube.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\cube.obj: examples/gldemos/cube.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/cube.c + +examples\gldemos\gears.exe: examples\gldemos\gears.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\gears.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\gears.obj: examples/gldemos/gears.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/gears.c + +examples\gldemos\triangle.exe: examples\gldemos\triangle.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\triangle.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\triangle.obj: examples/gldemos/triangle.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/triangle.c + +examples\gldemos\tripaint.exe: examples\gldemos\tripaint.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\gldemos\tripaint.obj src\Mw.lib opengl32.lib glu32.lib + +examples\gldemos\tripaint.obj: examples/gldemos/tripaint.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/gldemos/tripaint.c + + +src\Mw.dll: external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(MW_LDFLAGS) /OUT:$@ external\libz\src\adler32.obj external\libz\src\compress.obj external\libz\src\crc32.obj external\libz\src\deflate.obj external\libz\src\gzclose.obj external\libz\src\gzlib.obj external\libz\src\gzread.obj external\libz\src\gzwrite.obj external\libz\src\infback.obj external\libz\src\inffast.obj external\libz\src\inflate.obj external\libz\src\inftrees.obj external\libz\src\trees.obj external\libz\src\uncompr.obj external\libz\src\zutil.obj external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\charset.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldmonottf.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\monottf.obj src\text\font\ttf.obj src\text\ft2.obj src\text\gdi.obj src\text\stbtt.obj src\text\text.obj src\truetype.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\calendar.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\subwindow.obj src\widget\tab.obj src\widget\table.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib winmm.lib user32.lib advapi32.lib + + +.c.obj: + $(CC) $(MW_CFLAGS) /Fo$@ $< diff --git a/widget/milsko/milskosrc/README.txt b/widget/milsko/milskosrc/README.txt new file mode 100644 index 0000000000..0f57f905df --- /dev/null +++ b/widget/milsko/milskosrc/README.txt @@ -0,0 +1,72 @@ + +Greetings - Welcome to the Milsko GUI Toolkit (Version 1.4) + + This document contains a brief summary of the contents of this source +distributions and building instructions for Milsko GUI Toolkit. + + Requirements + + Milsko requires either + * A Windows environment with GDI (so anything NT or 9x) + * A Unix-like environment with Wayland and/or X11 for runtime. + + To build Milsko for Windows, you must have one of following compilers: + * Visual C++ 6.0 or newer + * Borland C++ 5.5 or newer + * Open Watcom 2.0 or newer + * MinGW-w64 + + and for Unix-like and MacOS: + * GNU C Compiler + * Clang + + + Contents + + At the top level of this hierarchy there are seven directories: + + src - Contains the source for Milsko library + + include - Contains the headers for Milsko + + doc - Contains the documentation for Milsko + + external - Contains the external dependency that Milsko uses + + resource - Contains the resources used by maintainers + + tools - Contains the tools used by maintainers + + + Building Milsko + + Building Milsko depends on the platform you use, and the compiler you use. + +A. Visual C++ +------------- + +1) Run `nmake -f NTMakefile'. + +B. Borland C++ +-------------- + +1) Run `make -f BorMakefile'. + +C. Open Watcom +-------------- + +1) Run `wmake -f WatMakefile'. + +D. MinGW-w64/GCC/Clang +---------------------- + +1) Determine if you need Vulkan and/or OpenGL. + +2) Either: + a.) Run `./configure'. For help, run `./configure --help'. + b.) Use CMake; i.e. `cmake -B build`. (if contributing, name the build +folder build as that's what's included in the .gitignore) + +3) Run `make'. + + -- Nishi (nishi@nishi.boats) diff --git a/widget/milsko/milskosrc/WatMakefile b/widget/milsko/milskosrc/WatMakefile new file mode 100644 index 0000000000..afeb560618 --- /dev/null +++ b/widget/milsko/milskosrc/WatMakefile @@ -0,0 +1,506 @@ +CC = wcc386 -bt=nt -q +LD = wlink option quiet + +MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -dUSE_GDI -dUSE_STB_IMAGE -dSTBI_NO_SIMD -dUSE_GDI_TEXT +MW_LDFLAGS = system nt_dll +EXE_CFLAGS = -i=include +EXE_LDFLAGS = system nt +all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +lib: src/Mw.dll +examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +clean: .SYMBOLIC + %erase external/libz/src/adler32.obj + %erase external/libz/src/compress.obj + %erase external/libz/src/crc32.obj + %erase external/libz/src/deflate.obj + %erase external/libz/src/gzclose.obj + %erase external/libz/src/gzlib.obj + %erase external/libz/src/gzread.obj + %erase external/libz/src/gzwrite.obj + %erase external/libz/src/infback.obj + %erase external/libz/src/inffast.obj + %erase external/libz/src/inflate.obj + %erase external/libz/src/inftrees.obj + %erase external/libz/src/trees.obj + %erase external/libz/src/uncompr.obj + %erase external/libz/src/zutil.obj + %erase external/stb_ds.obj + %erase external/stb_image.obj + %erase external/stb_truetype.obj + %erase src/abstract/charset.obj + %erase src/abstract/directory.obj + %erase src/abstract/dynamic.obj + %erase src/abstract/time.obj + %erase src/backend/gdi.obj + %erase src/color.obj + %erase src/core.obj + %erase src/cursor/arrow.obj + %erase src/cursor/cross.obj + %erase src/cursor/default.obj + %erase src/cursor/hidden.obj + %erase src/cursor/text.obj + %erase src/default.obj + %erase src/dialog/colorpicker.obj + %erase src/dialog/directorychooser.obj + %erase src/dialog/filechooser.obj + %erase src/dialog/messagebox.obj + %erase src/draw.obj + %erase src/icon/back.obj + %erase src/icon/clock.obj + %erase src/icon/computer.obj + %erase src/icon/directory.obj + %erase src/icon/down.obj + %erase src/icon/error.obj + %erase src/icon/file.obj + %erase src/icon/forward.obj + %erase src/icon/info.obj + %erase src/icon/left.obj + %erase src/icon/news.obj + %erase src/icon/note.obj + %erase src/icon/right.obj + %erase src/icon/search.obj + %erase src/icon/up.obj + %erase src/icon/warning.obj + %erase src/lowlevel.obj + %erase src/string.obj + %erase src/text/font/boldfont.obj + %erase src/text/font/boldmonottf.obj + %erase src/text/font/boldttf.obj + %erase src/text/font/font.obj + %erase src/text/font/monottf.obj + %erase src/text/font/ttf.obj + %erase src/text/ft2.obj + %erase src/text/gdi.obj + %erase src/text/stbtt.obj + %erase src/text/text.obj + %erase src/truetype.obj + %erase src/unicode.obj + %erase src/widget/box.obj + %erase src/widget/button.obj + %erase src/widget/calendar.obj + %erase src/widget/checkbox.obj + %erase src/widget/combobox.obj + %erase src/widget/entry.obj + %erase src/widget/frame.obj + %erase src/widget/image.obj + %erase src/widget/label.obj + %erase src/widget/listbox.obj + %erase src/widget/menu.obj + %erase src/widget/numberentry.obj + %erase src/widget/opengl.obj + %erase src/widget/progressbar.obj + %erase src/widget/radiobox.obj + %erase src/widget/scrollbar.obj + %erase src/widget/separator.obj + %erase src/widget/submenu.obj + %erase src/widget/subwindow.obj + %erase src/widget/tab.obj + %erase src/widget/table.obj + %erase src/widget/treeview.obj + %erase src/widget/viewport.obj + %erase src/widget/window.obj + %erase src/Mw.dll + %erase src/Mw.lib + %erase examples/basic/box.obj + %erase examples/basic/calculator.obj + %erase examples/basic/checkbox.obj + %erase examples/basic/clipboard.obj + %erase examples/basic/colorpicker.obj + %erase examples/basic/combobox.obj + %erase examples/basic/example.obj + %erase examples/basic/filechooser.obj + %erase examples/basic/image.obj + %erase examples/basic/listbox.obj + %erase examples/basic/messagebox.obj + %erase examples/basic/periodic.obj + %erase examples/basic/progressbar.obj + %erase examples/basic/radiobox.obj + %erase examples/basic/rotate.obj + %erase examples/basic/scrollbar.obj + %erase examples/basic/sevensegment.obj + %erase examples/basic/subwindow.obj + %erase examples/basic/tab.obj + %erase examples/basic/treeview.obj + %erase examples/basic/viewport.obj + %erase examples/gldemos/boing.obj + %erase examples/gldemos/clock.obj + %erase examples/gldemos/cube.obj + %erase examples/gldemos/gears.obj + %erase examples/gldemos/triangle.obj + %erase examples/gldemos/tripaint.obj + %erase examples/basic/box.exe + %erase examples/basic/calculator.exe + %erase examples/basic/checkbox.exe + %erase examples/basic/clipboard.exe + %erase examples/basic/colorpicker.exe + %erase examples/basic/combobox.exe + %erase examples/basic/example.exe + %erase examples/basic/filechooser.exe + %erase examples/basic/image.exe + %erase examples/basic/listbox.exe + %erase examples/basic/messagebox.exe + %erase examples/basic/periodic.exe + %erase examples/basic/progressbar.exe + %erase examples/basic/radiobox.exe + %erase examples/basic/rotate.exe + %erase examples/basic/scrollbar.exe + %erase examples/basic/sevensegment.exe + %erase examples/basic/subwindow.exe + %erase examples/basic/tab.exe + %erase examples/basic/treeview.exe + %erase examples/basic/viewport.exe + %erase examples/gldemos/boing.exe + %erase examples/gldemos/clock.exe + %erase examples/gldemos/cube.exe + %erase examples/gldemos/gears.exe + %erase examples/gldemos/triangle.exe + %erase examples/gldemos/tripaint.exe + +examples/basic/box.exe: examples/basic/box.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/box.obj library clib3r.lib library src/Mw.lib + +examples/basic/box.obj: examples/basic/box.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/box.c + +examples/basic/calculator.exe: examples/basic/calculator.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/calculator.obj library clib3r.lib library src/Mw.lib + +examples/basic/calculator.obj: examples/basic/calculator.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/calculator.c + +examples/basic/checkbox.exe: examples/basic/checkbox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/checkbox.obj library clib3r.lib library src/Mw.lib + +examples/basic/checkbox.obj: examples/basic/checkbox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/checkbox.c + +examples/basic/clipboard.exe: examples/basic/clipboard.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/clipboard.obj library clib3r.lib library src/Mw.lib + +examples/basic/clipboard.obj: examples/basic/clipboard.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/clipboard.c + +examples/basic/colorpicker.exe: examples/basic/colorpicker.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/colorpicker.obj library clib3r.lib library src/Mw.lib + +examples/basic/colorpicker.obj: examples/basic/colorpicker.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/colorpicker.c + +examples/basic/combobox.exe: examples/basic/combobox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/combobox.obj library clib3r.lib library src/Mw.lib + +examples/basic/combobox.obj: examples/basic/combobox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/combobox.c + +examples/basic/example.exe: examples/basic/example.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/example.obj library clib3r.lib library src/Mw.lib + +examples/basic/example.obj: examples/basic/example.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/example.c + +examples/basic/filechooser.exe: examples/basic/filechooser.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/filechooser.obj library clib3r.lib library src/Mw.lib + +examples/basic/filechooser.obj: examples/basic/filechooser.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/filechooser.c + +examples/basic/image.exe: examples/basic/image.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/image.obj library clib3r.lib library src/Mw.lib + +examples/basic/image.obj: examples/basic/image.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/image.c + +examples/basic/listbox.exe: examples/basic/listbox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/listbox.obj library clib3r.lib library src/Mw.lib + +examples/basic/listbox.obj: examples/basic/listbox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/listbox.c + +examples/basic/messagebox.exe: examples/basic/messagebox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/messagebox.obj library clib3r.lib library src/Mw.lib + +examples/basic/messagebox.obj: examples/basic/messagebox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/messagebox.c + +examples/basic/periodic.exe: examples/basic/periodic.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/periodic.obj library clib3r.lib library src/Mw.lib + +examples/basic/periodic.obj: examples/basic/periodic.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/periodic.c + +examples/basic/progressbar.exe: examples/basic/progressbar.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/progressbar.obj library clib3r.lib library src/Mw.lib + +examples/basic/progressbar.obj: examples/basic/progressbar.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/progressbar.c + +examples/basic/radiobox.exe: examples/basic/radiobox.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/radiobox.obj library clib3r.lib library src/Mw.lib + +examples/basic/radiobox.obj: examples/basic/radiobox.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/radiobox.c + +examples/basic/rotate.exe: examples/basic/rotate.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/rotate.obj library clib3r.lib library src/Mw.lib + +examples/basic/rotate.obj: examples/basic/rotate.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/rotate.c + +examples/basic/scrollbar.exe: examples/basic/scrollbar.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/scrollbar.obj library clib3r.lib library src/Mw.lib + +examples/basic/scrollbar.obj: examples/basic/scrollbar.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/scrollbar.c + +examples/basic/sevensegment.exe: examples/basic/sevensegment.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/sevensegment.obj library clib3r.lib library src/Mw.lib + +examples/basic/sevensegment.obj: examples/basic/sevensegment.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/sevensegment.c + +examples/basic/subwindow.exe: examples/basic/subwindow.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/subwindow.obj library clib3r.lib library src/Mw.lib + +examples/basic/subwindow.obj: examples/basic/subwindow.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/subwindow.c + +examples/basic/tab.exe: examples/basic/tab.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/tab.obj library clib3r.lib library src/Mw.lib + +examples/basic/tab.obj: examples/basic/tab.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/tab.c + +examples/basic/treeview.exe: examples/basic/treeview.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/treeview.obj library clib3r.lib library src/Mw.lib + +examples/basic/treeview.obj: examples/basic/treeview.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/treeview.c + +examples/basic/viewport.exe: examples/basic/viewport.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/viewport.obj library clib3r.lib library src/Mw.lib + +examples/basic/viewport.obj: examples/basic/viewport.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/viewport.c + +examples/gldemos/boing.exe: examples/gldemos/boing.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/boing.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/boing.obj: examples/gldemos/boing.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/boing.c + +examples/gldemos/clock.exe: examples/gldemos/clock.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/clock.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/clock.obj: examples/gldemos/clock.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/clock.c + +examples/gldemos/cube.exe: examples/gldemos/cube.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/cube.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/cube.obj: examples/gldemos/cube.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/cube.c + +examples/gldemos/gears.exe: examples/gldemos/gears.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/gears.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/gears.obj: examples/gldemos/gears.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/gears.c + +examples/gldemos/triangle.exe: examples/gldemos/triangle.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/triangle.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/triangle.obj: examples/gldemos/triangle.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/triangle.c + +examples/gldemos/tripaint.exe: examples/gldemos/tripaint.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/gldemos/tripaint.obj library clib3r.lib library src/Mw.lib library opengl32.lib library glu32.lib + +examples/gldemos/tripaint.obj: examples/gldemos/tripaint.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/gldemos/tripaint.c + + +src/Mw.dll: external/libz/src/adler32.obj external/libz/src/compress.obj external/libz/src/crc32.obj external/libz/src/deflate.obj external/libz/src/gzclose.obj external/libz/src/gzlib.obj external/libz/src/gzread.obj external/libz/src/gzwrite.obj external/libz/src/infback.obj external/libz/src/inffast.obj external/libz/src/inflate.obj external/libz/src/inftrees.obj external/libz/src/trees.obj external/libz/src/uncompr.obj external/libz/src/zutil.obj external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/charset.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldmonottf.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/monottf.obj src/text/font/ttf.obj src/text/ft2.obj src/text/gdi.obj src/text/stbtt.obj src/text/text.obj src/truetype.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/calendar.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/subwindow.obj src/widget/tab.obj src/widget/table.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj + $(LD) $(MW_LDFLAGS) option implib=src/Mw.lib name $@ file external/libz/src/adler32.obj file external/libz/src/compress.obj file external/libz/src/crc32.obj file external/libz/src/deflate.obj file external/libz/src/gzclose.obj file external/libz/src/gzlib.obj file external/libz/src/gzread.obj file external/libz/src/gzwrite.obj file external/libz/src/infback.obj file external/libz/src/inffast.obj file external/libz/src/inflate.obj file external/libz/src/inftrees.obj file external/libz/src/trees.obj file external/libz/src/uncompr.obj file external/libz/src/zutil.obj file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/charset.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldmonottf.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/monottf.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/gdi.obj file src/text/stbtt.obj file src/text/text.obj file src/truetype.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/calendar.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/subwindow.obj file src/widget/tab.obj file src/widget/table.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library winmm.lib library user32.lib library advapi32.lib + + + +external/libz/src/adler32.obj: external/libz/src/adler32.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/adler32.c +external/libz/src/compress.obj: external/libz/src/compress.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/compress.c +external/libz/src/crc32.obj: external/libz/src/crc32.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/crc32.c +external/libz/src/deflate.obj: external/libz/src/deflate.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/deflate.c +external/libz/src/gzclose.obj: external/libz/src/gzclose.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzclose.c +external/libz/src/gzlib.obj: external/libz/src/gzlib.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzlib.c +external/libz/src/gzread.obj: external/libz/src/gzread.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzread.c +external/libz/src/gzwrite.obj: external/libz/src/gzwrite.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/gzwrite.c +external/libz/src/infback.obj: external/libz/src/infback.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/infback.c +external/libz/src/inffast.obj: external/libz/src/inffast.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inffast.c +external/libz/src/inflate.obj: external/libz/src/inflate.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inflate.c +external/libz/src/inftrees.obj: external/libz/src/inftrees.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/inftrees.c +external/libz/src/trees.obj: external/libz/src/trees.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/trees.c +external/libz/src/uncompr.obj: external/libz/src/uncompr.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/uncompr.c +external/libz/src/zutil.obj: external/libz/src/zutil.c + $(CC) $(MW_CFLAGS) -fo=$@ external/libz/src/zutil.c +external/stb_ds.obj: external/stb_ds.c + $(CC) $(MW_CFLAGS) -fo=$@ external/stb_ds.c +external/stb_image.obj: external/stb_image.c + $(CC) $(MW_CFLAGS) -fo=$@ external/stb_image.c +external/stb_truetype.obj: external/stb_truetype.c + $(CC) $(MW_CFLAGS) -fo=$@ external/stb_truetype.c +src/abstract/charset.obj: src/abstract/charset.c + $(CC) $(MW_CFLAGS) -fo=$@ src/abstract/charset.c +src/abstract/directory.obj: src/abstract/directory.c + $(CC) $(MW_CFLAGS) -fo=$@ src/abstract/directory.c +src/abstract/dynamic.obj: src/abstract/dynamic.c + $(CC) $(MW_CFLAGS) -fo=$@ src/abstract/dynamic.c +src/abstract/time.obj: src/abstract/time.c + $(CC) $(MW_CFLAGS) -fo=$@ src/abstract/time.c +src/backend/gdi.obj: src/backend/gdi.c + $(CC) $(MW_CFLAGS) -fo=$@ src/backend/gdi.c +src/color.obj: src/color.c + $(CC) $(MW_CFLAGS) -fo=$@ src/color.c +src/core.obj: src/core.c + $(CC) $(MW_CFLAGS) -fo=$@ src/core.c +src/cursor/arrow.obj: src/cursor/arrow.c + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/arrow.c +src/cursor/cross.obj: src/cursor/cross.c + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/cross.c +src/cursor/default.obj: src/cursor/default.c + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/default.c +src/cursor/hidden.obj: src/cursor/hidden.c + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/hidden.c +src/cursor/text.obj: src/cursor/text.c + $(CC) $(MW_CFLAGS) -fo=$@ src/cursor/text.c +src/default.obj: src/default.c + $(CC) $(MW_CFLAGS) -fo=$@ src/default.c +src/dialog/colorpicker.obj: src/dialog/colorpicker.c + $(CC) $(MW_CFLAGS) -fo=$@ src/dialog/colorpicker.c +src/dialog/directorychooser.obj: src/dialog/directorychooser.c + $(CC) $(MW_CFLAGS) -fo=$@ src/dialog/directorychooser.c +src/dialog/filechooser.obj: src/dialog/filechooser.c + $(CC) $(MW_CFLAGS) -fo=$@ src/dialog/filechooser.c +src/dialog/messagebox.obj: src/dialog/messagebox.c + $(CC) $(MW_CFLAGS) -fo=$@ src/dialog/messagebox.c +src/draw.obj: src/draw.c + $(CC) $(MW_CFLAGS) -fo=$@ src/draw.c +src/icon/back.obj: src/icon/back.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/back.c +src/icon/clock.obj: src/icon/clock.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/clock.c +src/icon/computer.obj: src/icon/computer.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/computer.c +src/icon/directory.obj: src/icon/directory.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/directory.c +src/icon/down.obj: src/icon/down.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/down.c +src/icon/error.obj: src/icon/error.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/error.c +src/icon/file.obj: src/icon/file.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/file.c +src/icon/forward.obj: src/icon/forward.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/forward.c +src/icon/info.obj: src/icon/info.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/info.c +src/icon/left.obj: src/icon/left.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/left.c +src/icon/news.obj: src/icon/news.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/news.c +src/icon/note.obj: src/icon/note.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/note.c +src/icon/right.obj: src/icon/right.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/right.c +src/icon/search.obj: src/icon/search.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/search.c +src/icon/up.obj: src/icon/up.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/up.c +src/icon/warning.obj: src/icon/warning.c + $(CC) $(MW_CFLAGS) -fo=$@ src/icon/warning.c +src/lowlevel.obj: src/lowlevel.c + $(CC) $(MW_CFLAGS) -fo=$@ src/lowlevel.c +src/string.obj: src/string.c + $(CC) $(MW_CFLAGS) -fo=$@ src/string.c +src/text/font/boldfont.obj: src/text/font/boldfont.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldfont.c +src/text/font/boldmonottf.obj: src/text/font/boldmonottf.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldmonottf.c +src/text/font/boldttf.obj: src/text/font/boldttf.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/boldttf.c +src/text/font/font.obj: src/text/font/font.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/font.c +src/text/font/monottf.obj: src/text/font/monottf.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/monottf.c +src/text/font/ttf.obj: src/text/font/ttf.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/font/ttf.c +src/text/ft2.obj: src/text/ft2.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/ft2.c +src/text/gdi.obj: src/text/gdi.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/gdi.c +src/text/stbtt.obj: src/text/stbtt.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/stbtt.c +src/text/text.obj: src/text/text.c + $(CC) $(MW_CFLAGS) -fo=$@ src/text/text.c +src/truetype.obj: src/truetype.c + $(CC) $(MW_CFLAGS) -fo=$@ src/truetype.c +src/unicode.obj: src/unicode.c + $(CC) $(MW_CFLAGS) -fo=$@ src/unicode.c +src/widget/box.obj: src/widget/box.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/box.c +src/widget/button.obj: src/widget/button.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/button.c +src/widget/calendar.obj: src/widget/calendar.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/calendar.c +src/widget/checkbox.obj: src/widget/checkbox.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/checkbox.c +src/widget/combobox.obj: src/widget/combobox.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/combobox.c +src/widget/entry.obj: src/widget/entry.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/entry.c +src/widget/frame.obj: src/widget/frame.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/frame.c +src/widget/image.obj: src/widget/image.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/image.c +src/widget/label.obj: src/widget/label.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/label.c +src/widget/listbox.obj: src/widget/listbox.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/listbox.c +src/widget/menu.obj: src/widget/menu.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/menu.c +src/widget/numberentry.obj: src/widget/numberentry.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/numberentry.c +src/widget/opengl.obj: src/widget/opengl.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/opengl.c +src/widget/progressbar.obj: src/widget/progressbar.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/progressbar.c +src/widget/radiobox.obj: src/widget/radiobox.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/radiobox.c +src/widget/scrollbar.obj: src/widget/scrollbar.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/scrollbar.c +src/widget/separator.obj: src/widget/separator.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/separator.c +src/widget/submenu.obj: src/widget/submenu.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/submenu.c +src/widget/subwindow.obj: src/widget/subwindow.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/subwindow.c +src/widget/tab.obj: src/widget/tab.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/tab.c +src/widget/table.obj: src/widget/table.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/table.c +src/widget/treeview.obj: src/widget/treeview.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/treeview.c +src/widget/viewport.obj: src/widget/viewport.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/viewport.c +src/widget/window.obj: src/widget/window.c + $(CC) $(MW_CFLAGS) -fo=$@ src/widget/window.c diff --git a/widget/milsko/milskosrc/configure b/widget/milsko/milskosrc/configure new file mode 100644 index 0000000000..44db66d802 --- /dev/null +++ b/widget/milsko/milskosrc/configure @@ -0,0 +1,363 @@ +#!/usr/bin/env perl +our $target = `uname -s`; +$target =~ s/\r?\n$//; + +# MSYS with MinGW gives us some other shit idk +if (index($target, "MINGW") != -1) { + $target = "Windows"; +} + +foreach my $l (@ARGV) { + if ($l =~ /^--.+$/) { + } + elsif ($l =~ /^(.+)=(.+)$/) { + $ENV{$1} = $2; + } +} + +our $prefix = "/usr/local"; +our $cc = defined($ENV{CC}) ? $ENV{CC} : "*host*gcc"; +our $cxx = defined($ENV{CXX}) ? $ENV{CXX} : "*host*g++"; +our $ar = defined($ENV{AR}) ? $ENV{AR} : "*host*ar"; +our $incdir = "-I include"; +our $incdir2 = ""; +our $cflags = "-fPIC -D_MILSKO -D_MILSKO_BUILD -fvisibility=hidden"; +our $libdir = ""; +our $ldflags = ""; +our $math = "-lm"; +our @shared = "-shared"; +our @backends = (); + +our $library_prefix = "lib"; +our $library_suffix = ".so"; +our $object_suffix = ".o"; +our $executable_suffix = ""; + +our @library_targets = (); +our @examples_targets = (); +our %examples_libs = (); + +our $cross = 0; +our $host = ""; + +require("./pl/utils.pl"); + +param_set("classic-theme", 0); +param_set("stb-image", 1); +param_set("opengl", 0); +param_set("vulkan", 0); +param_set("vulkan-string-helper", 1); +param_set("shared", 1); +param_set("static", 1); +param_set("examples", 1); + +# (option that only makes sense on x11) +param_set("allow-sloppy-focus", 0); + +my %features = ( + "classic-theme" => "use classic theme", + "stb-image" => "use stb_image, instead use libjpeg/libpng", + "stb-truetype" => "use stb_truetype", + "freetype2" => "use FreeType2", + "gdi-text" => "(Windows only) use GDI Text", + "xrender" => "(X11 only) use XRender", + "opengl" => "build OpenGL widget", + "vulkan" => "build Vulkan widget", + "vulkan-string-helper" => "use Vulkan string helper", + "shared" => "build shared library", + "static" => "build static library", + "wayland" => "enable wayland backend", + "gnustep" => "use gnustep", + "dbus" => "use DBus on supported platform", + "allow-sloppy-focus" => "prevent the x11 backend from using XSetInputFocus to enforce click-to-focus" +); +my @features_keys = ( + "1classic-theme", "1stb-image", + "1stb-truetype", "1freetype2", "1gdi-text", + "1opengl", "2xrender", + "1vulkan", "2vulkan-string-helper", + "1shared", "1static", + "1wayland", "1gnustep", + "1dbus" +); + +sub def_platform { + if($target eq "Windows") { + param_set("freetype2", 0); + param_set("stb-truetype", 0); + } elsif($target ne "Darwin" and $target ne "ClassicMacOS" and $target ne "Haiku") { + param_set("freetype2", 1); + param_set("stb-truetype", 0); + } else { + param_set("freetype2", 0); + param_set("stb-truetype", 1); + } + if($target eq "Linux" || $target eq "FreeBSD") { + param_set("x11", 1); + param_set("xrender", 1); + if(!param_get("tiny")){ + param_set("wayland", 1); + } + param_set("dbus", 1); + } + if($target eq "NetBSD" || $target eq "OpenBSD") { + param_set("x11", 1); + } + if($target eq "Windows") { + param_set("gdi-text", 1); + } else { + param_set("gdi-text", 0); + } +} + +foreach my $l (@ARGV) { + if ($l =~ /^--target=(.+)$/) { + $target = $1; + } +} + +def_platform(); + + +foreach my $l (@ARGV) { + if ($l =~ /^--with-([^=]+)=(.+)$/) { + param_set($1, $2); + } + elsif ($l =~ /^--(?:with|enable)-(.+)$/) { + param_set($1, 1); + } + elsif ($l =~ /^--(?:without|disable)-(.+)$/) { + param_set($1, 0); + } + elsif ($l =~ /^--host=(.+)$/) { + $host = $1 . "-"; + } + elsif ($l =~ /^--cflags=(.+)$/) { + add_cflags($1); + } + elsif ($l eq "--cross") { + $cross = 1; + } + elsif ($l eq "--tiny") { + param_set("tiny",1); + } + elsif (($l eq "-h") or ($l eq "--help")) { + print("Milsko Toolkit Configuration Utility\n"); + print("\n"); + print("Usage: $0 [options]\n"); + print("\n"); + print("Options:\n"); + print(" -h --help Display this help\n"); + print(" --prefix=PREFIX Installation prefix\n"); + print(" --host=TARGET Host for compiler/archiver\n"); + print(" --target=TARGET Specify target\n"); + print(" --cflags=CFLAGS Add cflags\n"); + print(" --tiny Build smallest possible library\n"); + print(" --cross Indicate cross compilation\n"); + print("\n"); + print("Features:\n"); + print(" --enable-FEATURE Use FEATURE\n"); + print(" --with-FEATURE Use FEATURE\n"); + print(" --disable-FEATURE Do not use FEATURE\n"); + print(" --without-FEATURE Do not use FEATURE\n"); + + foreach my $l (@features_keys) { + my $flag = ( + (substr($l, 0, 1) eq '1') + ? (param_get(substr($l, 1)) ? "--disable-" : "--enable-") + : (param_get(substr($l, 1)) ? "--without-" : "--with-") + ) . substr($l, 1); + my $do = param_get(substr($l, 1)) ? "Do not " : ""; + my $feat = $features{ substr($l, 1) }; + if (not(param_get(substr($l, 1)))) { + $feat = uc(substr($feat, 0, 1)) . substr($feat, 1); + } + print(" $flag" . (" " x (32 - length($flag))) . "${do}${feat}\n"); + } + exit(0); + } +} + +if (-f "./pl/ostype/${target}.pl") { + require("./pl/ostype/${target}.pl"); +} +else { + print( +"Perl file (pl/ostype/${target}.pl) was not found for your target. Please add one.\n" + ); + exit(1); +} + +require("./pl/rules.pl"); + +print("Target : " . $target . "\n"); + +my @l = (); +foreach my $e (param_list()) { + if (not(param_get($e))) { + next; + } + if (($e eq "vulkan-string-helper") and param_get("vulkan")) { + push(@l, $e); + } + elsif (($e eq "xrender") and ($backend eq "x11")) { + push(@l, $e); + } + elsif (not($e eq "vulkan-string-helper") and not($e eq "xrender")) { + push(@l, $e); + } +} +print("Enabled: " . join(" ", @l) . "\n"); + +$cc =~ s/\*host\*/$host/; +$cxx =~ s/\*host\*/$host/; +$ar =~ s/\*host\*/$host/; + +open(OUT, ">", "Makefile"); +print(OUT "PREFIX = ${prefix}\n"); +print(OUT "AR = ${ar}\n"); +print(OUT "CC = ${cc}\n"); +print(OUT "CXX = ${cxx}\n"); +print(OUT "INCDIR = ${incdir} ${incdir2}\n"); +print(OUT "CFLAGS = ${cflags}\n"); +print(OUT "LIBDIR = ${libdir}\n"); +print(OUT "LDFLAGS = ${ldflags}\n"); +print(OUT "LIBS = ${math} ${libs}\n"); +print(OUT "MATH = ${math}\n"); +print(OUT "SHARED = @{shared}\n"); +print(OUT "\n"); +print(OUT ".PHONY: all format clean distclean lib examples install\n"); +print(OUT "\n"); +print(OUT "all: lib examples\n"); +print(OUT "\n"); +print(OUT "install: lib\n"); +print(OUT + " mkdir -p \$(DESTDIR)\$(PREFIX)/lib \$(DESTDIR)\$(PREFIX)/include\n"); +print(OUT +" -cp src/${library_prefix}Mw${library_suffix} \$(DESTDIR)\$(PREFIX)/lib/\n" +); +print(OUT " -cp src/libMw.a \$(DESTDIR)\$(PREFIX)/lib/\n"); +print(OUT " cp -rf include \$(DESTDIR)\$(PREFIX)/\n"); +print(OUT "\n"); +print(OUT "format:\n"); +print(OUT +" clang-format --verbose -i `find tools src include examples \"(\" -name \"*.c\" -or -name \"*.cc\" -or -name \"*.h\" -or -name \"*.m\" \")\" -and -not -name \"*ttf.c\"`\n" +); +print(OUT +" perltidy -b -bext=\"/\" --paren-tightness=2 `find tools pl configure -name \"*.pl\"`\n" +); +print(OUT "\n"); +print(OUT "lib:"); + +if (param_get("shared")) { + print(OUT " src/${library_prefix}Mw${library_suffix}"); +} +if (param_get("static")) { + print(OUT " src/libMw.a"); +} +print(OUT "\n"); +print(OUT "\n"); +if (param_get("shared")) { + my $linker = "CC"; +if (grep(/^haiku$/, @backends)) { + $linker = "CXX"; +} + print( OUT "src/${library_prefix}Mw${library_suffix}: " + . join(" ", @library_targets) + . "\n"); + print(OUT +" \$($linker) \$(SHARED) \$(LDFLAGS\) \$(LIBDIR) -o src/${library_prefix}Mw${library_suffix} " + . join(" ", @library_targets) + . " \$(LIBS)\n"); + print(OUT "\n"); +} +if (param_get("static")) { + print(OUT "src/libMw.a: " . join(" ", @library_targets) . "\n"); + print(OUT " \$(AR) rcs src/libMw.a " . join(" ", @library_targets) . "\n"); +} + +foreach my $l (@library_targets) { + my $warn = "-Wall -Wextra -Wno-sign-compare -Wno-unused-value"; + my $s = $l; + my $compiler = "CC"; + my $o = $object_suffix; + $o =~ s/\./\\\./g; + + if ($l =~ /cocoa/) { + $s =~ s/$o$/.m/; + } + elsif ($l =~ /haiku/) { + $s =~ s/$o$/.cc/; + $compiler = "CXX"; + } + else { + $s =~ s/$o$/.c/; + } + + if ($l =~ /^external\//) { + $warn = ""; + } + + print(OUT "${l}: ${s}\n"); + print(OUT " \$($compiler) $warn \$\(INCDIR) \$(CFLAGS\) -c -o ${l} ${s}\n"); +} +print(OUT "\n"); +print(OUT "\n"); +if (param_get("examples")) { + print(OUT "examples: " . join(" ", @examples_targets) . "\n"); + print(OUT "\n"); + foreach my $l (@examples_targets) { + my $libs = ""; + my $s = $l; + my $o = $executable_suffix; + $o =~ s/\./\\\./g; + $s =~ s/$o$//; + + if (defined($examples_libs{$l})) { + $libs = $examples_libs{$l}; + } + + if (param_get("shared")) { + print(OUT + "${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n" + ); + } else { + print(OUT + "${l}: ${s}${object_suffix} src/${library_prefix}Mw.a\n" + ); + } + if (grep(/^cocoa$/, @backends)) { + print(OUT +" \$(CC) -L./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" + ); + } + else { + print(OUT +" \$(CC) -L src -Wl,-R./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" + ); + } + + if($target eq "ClassicMacOS") { + print(OUT +" ".$ENV{RETRO68_TOOLCHAIN_PATH}."/bin/MakePEF ${l} -o ${s}.pef\n"); + print(OUT +" Rez -I ".$ENV{RETRO68_TOOLCHAIN_PATH}."/RIncludes ".$ENV{RETRO68_TOOLCHAIN_PATH}."/RIncludes/Retro68APPL.r -DCFRAG_NAME=\"example\" --data ${l}.pef --cc ${l}.dsk -t APPL\n" + ); + } + + print(OUT "${s}${object_suffix}: ${s}.c\n"); + print(OUT +" \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n" + ); + } +} +print(OUT "\n"); +print(OUT "clean:\n"); +print(OUT +" rm -f */*.o */*/*.o */*/*/*.o */*.exe */*/*.exe */*/*/*.exe src/*.so src/*.dll src/*.dylib src/*.a " + . join(" ", @examples_targets) + . "\n"); +print(OUT "\n"); +print(OUT "distclean: clean\n"); +print(OUT " rm -f Makefile\n"); +close(OUT); diff --git a/widget/milsko/milskosrc/doc/BACKENDDEV.md b/widget/milsko/milskosrc/doc/BACKENDDEV.md new file mode 100644 index 0000000000..85f61f4fb9 --- /dev/null +++ b/widget/milsko/milskosrc/doc/BACKENDDEV.md @@ -0,0 +1,25 @@ +# Backend dev + +The basic process of creating a new Milsko backend is + +- Adding a new include header into `include/Mw/LowLevel`. It must include; + - `struct _MwLLBackendName`: Any details about a window or a subwidget + - `struct _MwLLBackendNameColor`: An 8-bit RGB Color. You'll probably never impl this, this is for platforms like X11/GDI where they have a secondary color representation that can be stored. + - `struct _MwLLBackendNamePixmap`: Self-explanatory. This is also used for the soft gradients in the modern theme. + - `MwLLBackendNameCallInitImpl(void)` called by `MwLibraryInit` to address and platform globals. + - Note that all of those structs are actually unions. They should all start with their `MwLLCommon...` equivalants. +- Fill out `Mw/LowLevel.h` appopriately, adding an include to your new file and the structs in the appropriate unions. These need to be guarded by a `USE_BACKENDNAME` macro which you'll define later when you modify the build system. +- Creating a new impl file in `src/backend` + - Backends actually return a table of function pointers that you have to implement with static functions. Your file should end with `#include "call.c"` and then `CALL(BackendName);`, and somewhere you should have the impl for `MwLLBackendNameCallInitImpl(void)`. + - Prefer to keep the backend file to one file if you can, though obviously exceptions like the Wayland backend exist because it's simply too complex to sanely stuff into one file. +- Add `MwLLBackendNameCallInitImpl` to the `MwLibraryInit` impl in `src/core.c`. +- Add a new enum variation to `MwLLBackends` in `Mw/Include/LowLevel.h`; your impl of `MwLLCreateImpl` will set `common.type` to this so the user can check which backend they're on (important for platforms with multiple supported backends). +- Either + - a.) Modify `CMakeLists.txt` for your platform. + - b.) Add a new perl file in `pl/ostype` that `./configure` can reference, and modify `pl/rules.pl`; If you don't know how to use perl it's fine, just copy a file like the `Linux.pl` or `Windows.pl`, the functions you'll have to change for your platform are self explanatory. Ensure it ends with `1;`. + - c.) Both. + - Both are recommended, but some platforms like Classic Mac OS can't be used with the `./configure` script, and that's fine. + +The functions you'll have to impl are too many to list here so you should start by just copying `x11.c` and then replacing all the function impls with your own. + +\*\*Pay attention to some of these functions' comments in LowLevel.h as they might not be as you expect; for example, `MwLLSetDarkThemeImpl` is for setting the accent color to dark theme on platforms like modern Windows (dark theme itself is set with `MwSetInteger(handle, MwNdarktheme, 1)`). diff --git a/widget/milsko/milskosrc/doc/NEWWIDGET.md b/widget/milsko/milskosrc/doc/NEWWIDGET.md new file mode 100644 index 0000000000..ab9cfb789b --- /dev/null +++ b/widget/milsko/milskosrc/doc/NEWWIDGET.md @@ -0,0 +1,7 @@ +# Writing a new widget +@warning This is mainly for developers + +1. Create new file in src/widget with lower case +2. Create new header in include/Mw/Widget with pascal case +3. Add the header include to include/Mw/Milsko.h, if new widget does not require some extension (like OpenGL and Vulkan) +4. See another widget for example diff --git a/widget/milsko/milskosrc/doc/TIERS.md b/widget/milsko/milskosrc/doc/TIERS.md new file mode 100644 index 0000000000..c94cd6a6e9 --- /dev/null +++ b/widget/milsko/milskosrc/doc/TIERS.md @@ -0,0 +1,20 @@ +# Tiers + +Ports of Milsko are grouped into three "tiers" in terms of their support. + +- **Tier 1**: Before every new release of Milsko, these platforms will be tested to make sure they have full support, and the CI will test them. +- **Tier 2**: These might be outdated or not updated in awhile, they might only compile under a specific version/commit of Milsko. Authors of these backends will be made aware of these updates. +- **Tier 3**: These are outright unfinished. Only use these if you're a developer. + +Currently, the Tier 1 backends are: + +- Windows 9x+/NT 4.0+ +- Any Unix/Linux system that supports X11 or Wayland. + +There are currently no Tier 2 backends. + +Tier 3 backends are: + +- Mac OS X 10.4+ with Cocoa +- Mac OS 7-9, PowerPC (68k support not planned). +- Haiku diff --git a/widget/milsko/milskosrc/doc/TINYCONFIG.md b/widget/milsko/milskosrc/doc/TINYCONFIG.md new file mode 100644 index 0000000000..024edf605d --- /dev/null +++ b/widget/milsko/milskosrc/doc/TINYCONFIG.md @@ -0,0 +1,9 @@ +# Tiny Config + +Milsko's configure script supports the `--tiny` option for building the tiniest possible Milsko library (~400kb as of writing). Currently, what it does is: + +- Add `-Oz` to the cflags +- (clang only) add `-flto=thin` to the cflags and linker flags +- Build stb-image with `STB_IMAGE_STATIC` (this is why you get warnings with stb_image when you use it) +- (Linux) Disable the Wayland backend +- (Linux) Disable dbus integration diff --git a/widget/milsko/milskosrc/examples/CMakeLists.txt b/widget/milsko/milskosrc/examples/CMakeLists.txt new file mode 100644 index 0000000000..5baed4a883 --- /dev/null +++ b/widget/milsko/milskosrc/examples/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(basic) +if(${MW_TRY_OPENGL}) +add_subdirectory(gldemos) +endif() +if(${MW_TRY_VULKAN}) +add_subdirectory(vkdemos) +endif() diff --git a/widget/milsko/milskosrc/examples/basic/CMakeLists.txt b/widget/milsko/milskosrc/examples/basic/CMakeLists.txt new file mode 100644 index 0000000000..e69c4ae552 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/CMakeLists.txt @@ -0,0 +1,26 @@ +file( + GLOB + EXAMPLES_BASIC_SOURCES + *.c +) + +foreach(PATH IN LISTS EXAMPLES_BASIC_SOURCES) + get_filename_component(TARGET ${PATH} NAME_WE) + if(CMAKE_SYSTEM_NAME MATCHES Retro) + add_application(${TARGET} ${PATH}) + else() + add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) + endif() + target_link_libraries( + ${TARGET} + PRIVATE + Mw + ) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_libraries( + ${TARGET} + PRIVATE + m + ) + endif() +endforeach() diff --git a/widget/milsko/milskosrc/examples/basic/box.c b/widget/milsko/milskosrc/examples/basic/box.c new file mode 100644 index 0000000000..e14b9f5746 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/box.c @@ -0,0 +1,74 @@ +#include + +MwWidget window, box; + +void MWAPI resize(MwWidget handle, void* user, void* client) { + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + + (void)user; + (void)client; + + MwVaApply(box, + MwNwidth, ww, + MwNheight, wh, + NULL); +} + +int main() { + MwWidget box2, box3, box4; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 600, 200, + MwNtitle, "box", + NULL); + + box = MwVaCreateWidget(MwBoxClass, "box", window, 0, 0, 0, 0, + MwNpadding, 10, + MwNmargin, 10, + NULL); + + box2 = MwVaCreateWidget(MwBoxClass, "box2", box, 0, 0, 0, 0, + MwNmargin, 10, + MwNorientation, MwVERTICAL, + NULL); + + box3 = MwVaCreateWidget(MwBoxClass, "box3", box, 0, 0, 0, 0, + MwNmargin, 10, + MwNorientation, MwVERTICAL, + NULL); + + box4 = MwVaCreateWidget(MwBoxClass, "box4", box, 0, 0, 0, 0, + MwNmargin, 10, + MwNorientation, MwVERTICAL, + MwNfixedSize, 40, + NULL); + + MwVaCreateWidget(MwButtonClass, "btn1", box2, 0, 0, 0, 0, + MwNbackground, "#a00", + NULL); + + MwVaCreateWidget(MwButtonClass, "btn2", box2, 0, 0, 0, 0, + MwNbackground, "#0a0", + MwNratio, 2, + NULL); + + MwVaCreateWidget(MwButtonClass, "btn3", box2, 0, 0, 0, 0, + MwNbackground, "#00a", + NULL); + + MwVaCreateWidget(MwButtonClass, "btn4", box3, 0, 0, 0, 0, + MwNbackground, "#a0a", + NULL); + + MwVaCreateWidget(MwButtonClass, "btn5", box4, 0, 0, 0, 0, + MwNbackground, "#0aa", + NULL); + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + + resize(window, NULL, NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/calculator.c b/widget/milsko/milskosrc/examples/basic/calculator.c new file mode 100644 index 0000000000..8889e97d37 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/calculator.c @@ -0,0 +1,185 @@ +#include + +MwWidget widgets[18]; +MwWidget inp; + +/* probably enough for most tasks */ +double stack[512]; +int sp = 0; + +static void MWAPI resize(MwWidget handle, void* client, void* user) { + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight) - MwGetInteger(inp, MwNheight); + int i; + + MwVaApply(inp, + MwNwidth, ww, + NULL); + + for(i = 0; i < sizeof(widgets) / sizeof(widgets[0]); i++) { + int x = i % 4; + int y = i / 4; + if(widgets[i] != NULL) { + MwVaApply(widgets[i], + MwNwidth, ww / 4, + MwNheight, wh / 5, + MwNx, ww / 4 * x, + MwNy, wh / 5 * y + MwGetInteger(inp, MwNheight), + NULL); + } + } +} + +static void MWAPI activate(MwWidget handle, void* client, void* user) { + const char* n = MwGetText(handle, MwNtext); + + if(('0' <= n[0] && n[0] <= '9') || n[0] == '.') { + const char* s = MwGetText(inp, MwNtext); + char* r; + + if(n[0] == '.' && s != NULL) { + int i; + for(i = 0; s[i] != 0; i++) { + if(s[i] == '.') return; + } + } + + if(s == NULL) s = ""; + + r = MwStringConcat(s, n); + MwVaApply(inp, + MwNtext, r, + NULL); + free(r); + } else if(n[0] == 'E') { + const char* s = MwGetText(inp, MwNtext); + + if(s != NULL) { + stack[sp++] = atof(s); + + MwVaApply(inp, + MwNtext, "", + NULL); + } + } else if(n[0] == 'C') { + MwVaApply(inp, + MwNtext, "", + NULL); + } else if(n[0] == '+' || n[0] == '-' || n[0] == '*' || n[0] == '/') { + if(sp >= 2) { + double sv = stack[--sp]; + double fv = stack[--sp]; + double v; + char buf[256]; + + if(n[0] == '+') { + v = fv + sv; + } else if(n[0] == '-') { + v = fv - sv; + } else if(n[0] == '*') { + v = fv * sv; + } else if(n[0] == '/') { + v = fv / sv; + } + + MwStringPrintIntoBuffer(buf, 256, "%g", v); + + MwVaApply(inp, + MwNtext, buf, + NULL); + } + } +} + +int main() { + MwWidget w; + int i; + + for(i = 0; i < sizeof(widgets) / sizeof(widgets[0]); i++) widgets[i] = NULL; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 150, 150, + MwNtitle, "Calculator", + NULL); + + inp = MwCreateWidget(MwEntryClass, "entry", w, 0, 0, 0, 24); + + widgets[0] = MwVaCreateWidget(MwButtonClass, "7", w, 0, 0, 0, 0, + MwNtext, "7", + NULL); + + widgets[1] = MwVaCreateWidget(MwButtonClass, "8", w, 0, 0, 0, 0, + MwNtext, "8", + NULL); + + widgets[2] = MwVaCreateWidget(MwButtonClass, "9", w, 0, 0, 0, 0, + MwNtext, "9", + NULL); + + widgets[3] = MwVaCreateWidget(MwButtonClass, "/", w, 0, 0, 0, 0, + MwNtext, "/", + NULL); + + widgets[4] = MwVaCreateWidget(MwButtonClass, "4", w, 0, 0, 0, 0, + MwNtext, "4", + NULL); + + widgets[5] = MwVaCreateWidget(MwButtonClass, "5", w, 0, 0, 0, 0, + MwNtext, "5", + NULL); + + widgets[6] = MwVaCreateWidget(MwButtonClass, "6", w, 0, 0, 0, 0, + MwNtext, "6", + NULL); + + widgets[7] = MwVaCreateWidget(MwButtonClass, "*", w, 0, 0, 0, 0, + MwNtext, "*", + NULL); + + widgets[8] = MwVaCreateWidget(MwButtonClass, "1", w, 0, 0, 0, 0, + MwNtext, "1", + NULL); + + widgets[9] = MwVaCreateWidget(MwButtonClass, "2", w, 0, 0, 0, 0, + MwNtext, "2", + NULL); + + widgets[10] = MwVaCreateWidget(MwButtonClass, "3", w, 0, 0, 0, 0, + MwNtext, "3", + NULL); + + widgets[11] = MwVaCreateWidget(MwButtonClass, "-", w, 0, 0, 0, 0, + MwNtext, "-", + NULL); + + widgets[12] = MwVaCreateWidget(MwButtonClass, "0", w, 0, 0, 0, 0, + MwNtext, "0", + NULL); + + widgets[13] = MwVaCreateWidget(MwButtonClass, ".", w, 0, 0, 0, 0, + MwNtext, ".", + NULL); + + widgets[16] = MwVaCreateWidget(MwButtonClass, "E", w, 0, 0, 0, 0, + MwNtext, "E", + NULL); + + widgets[15] = MwVaCreateWidget(MwButtonClass, "+", w, 0, 0, 0, 0, + MwNtext, "+", + NULL); + + widgets[17] = MwVaCreateWidget(MwButtonClass, "C", w, 0, 0, 0, 0, + MwNtext, "C", + NULL); + + for(i = 0; i < sizeof(widgets) / sizeof(widgets[0]); i++) { + if(widgets[i] != NULL) MwAddUserHandler(widgets[i], MwNactivateHandler, activate, NULL); + } + + MwAddUserHandler(w, MwNresizeHandler, resize, NULL); + + resize(w, NULL, NULL); + + MwLoop(w); +} diff --git a/widget/milsko/milskosrc/examples/basic/checkbox.c b/widget/milsko/milskosrc/examples/basic/checkbox.c new file mode 100644 index 0000000000..c66f06687d --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/checkbox.c @@ -0,0 +1,28 @@ +#include + +int main() { + MwWidget window; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "test", NULL, MwDEFAULT, MwDEFAULT, 8 + 16 + 8 + 16 * 10 + 8, 8 + 16 + 8 + 16 + 8, + MwNtitle, "checkbox", + NULL); + + MwVaCreateWidget(MwCheckBoxClass, "cb1", window, 8, 8, 16, 16, + NULL); + MwVaCreateWidget(MwCheckBoxClass, "cb2", window, 8, 8 + 16 + 8, 16, 16, + MwNchecked, 1, + NULL); + + MwVaCreateWidget(MwLabelClass, "lab1", window, 8 + 16 + 8, 8, 16 * 10, 16, + MwNtext, "lorem ipsum 1", + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + MwVaCreateWidget(MwLabelClass, "lab2", window, 8 + 16 + 8, 8 + 16 + 8, 16 * 10, 16, + MwNtext, "lorem ipsum 2", + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/clipboard.c b/widget/milsko/milskosrc/examples/basic/clipboard.c new file mode 100644 index 0000000000..9d060c31a9 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/clipboard.c @@ -0,0 +1,78 @@ +#include + +MwWidget window, instructions, text1, text2, cur_text; + +static void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { + unsigned int w, h; + + (void)user_data; + (void)call_data; + + w = MwGetInteger(handle, MwNwidth); + h = MwGetInteger(handle, MwNheight); + + MwVaApply(instructions, + MwNy, 50, + MwNwidth, w - 50 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); + + MwVaApply(text1, + MwNy, 150, + MwNwidth, w - 25 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); + MwVaApply(text2, + MwNy, 250, + MwNwidth, w - 25 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); +} +static void MWAPI clipboard(MwWidget handle, void* user_data, void* call_data) { + char* clipboard = call_data; + + (void)handle; + (void)user_data; + + if(clipboard != NULL) { + MwVaApply(cur_text, MwNtext, clipboard, NULL); + MwForceRender(cur_text); + } +} + +static void MWAPI tick(MwWidget handle, void* user_data, void* call_data) { + cur_text = text1; + MwGetClipboard(handle, MwCLIPBOARD_MAIN); + cur_text = text2; + MwGetClipboard(handle, MwCLIPBOARD_PRIMARY); + MwForceRender(window); +} + +int main() { + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, + MwNtitle, "clipboard", + NULL); + instructions = MwVaCreateWidget(MwLabelClass, "button", window, 50, 50, 300, 125, + MwNtext, "clipboard contents will show up below.", + NULL); + text1 = MwVaCreateWidget(MwLabelClass, "label", window, 25, 150, 300, 75, + MwNtext, "", + NULL); + text2 = MwVaCreateWidget(MwLabelClass, "label2", window, 25, 250, 300, 75, + MwNtext, "", + NULL); + + cur_text = text1; + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(window, MwNclipboardHandler, clipboard, NULL); + MwAddUserHandler(instructions, MwNclipboardHandler, clipboard, NULL); + MwAddUserHandler(cur_text, MwNclipboardHandler, clipboard, NULL); + MwAddUserHandler(window, MwNtickHandler, tick, NULL); + + resize(window, NULL, NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/colorpicker.c b/widget/milsko/milskosrc/examples/basic/colorpicker.c new file mode 100644 index 0000000000..dbce7fe2b7 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/colorpicker.c @@ -0,0 +1,48 @@ +#include + +MwWidget fpicker; +MwWidget window; +MwWidget button; + +void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { + char hexColor[8]; + MwRGB* rgb = call_data; + + (void)handle; + (void)user_data; + + rgb->red &= 0xff; + rgb->green &= 0xff; + rgb->blue &= 0xff; + MwStringPrintIntoBuffer(hexColor, 8, "#%02X%02X%02X", rgb->red, rgb->green, rgb->blue); + MwSetText(window, MwNbackground, hexColor); +} + +void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { + MwWidget cpicker = MwColorPicker(window, "cpicker"); + + (void)handle; + (void)user_data; + (void)call_data; + + MwAddUserHandler(cpicker, MwNcolorChosenHandler, file_callback, NULL); + + MwSetText(cpicker, MwNbackground, MwGetInteger(cpicker, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); +} + +int main() { + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, + MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); + MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + + button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, + MwNtext, "change window background", + NULL); + MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + + MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/combobox.c b/widget/milsko/milskosrc/examples/basic/combobox.c new file mode 100644 index 0000000000..0816466a29 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/combobox.c @@ -0,0 +1,22 @@ +#include + +int main() { + MwWidget w, cb; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 5 + 320 + 5, 5 + 24 + 5, + MwNtitle, "combobox", + NULL); + + cb = MwCreateWidget(MwComboBoxClass, "combobox", w, 5, 5, 320, 24); + + MwComboBoxAdd(cb, -1, "wow!"); + MwComboBoxAdd(cb, -1, "insert"); + MwComboBoxAdd(cb, -1, "cool"); + MwComboBoxAdd(cb, -1, "text"); + MwComboBoxAdd(cb, -1, "here"); + MwComboBoxAdd(cb, -1, "!!!"); + + MwLoop(w); +} diff --git a/widget/milsko/milskosrc/examples/basic/example.c b/widget/milsko/milskosrc/examples/basic/example.c new file mode 100644 index 0000000000..8fe38da78e --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/example.c @@ -0,0 +1,160 @@ +#include + +MwWidget window, menu, button, button2, button3, button4, button5, button6, button7; + +void MWAPI handler(MwWidget handle, void* user_data, void* call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + printf("hello world!\n"); +} + +void MWAPI handler_theme(MwWidget handle, void* user_data, void* call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + MwVaApply(window, + MwNdarkTheme, MwGetInteger(window, MwNdarkTheme) == 0 ? 1 : 0, + NULL); +} + +void MWAPI handler_look(MwWidget handle, void* user_data, void* call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + MwVaApply(window, + MwNmodernLook, MwGetInteger(window, MwNmodernLook) == 0 ? 1 : 0, + NULL); +} + +void MWAPI handler_font(MwWidget handle, void* user_data, void* call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + MwVaApply(window, + MwNbitmapFont, MwGetInteger(window, MwNbitmapFont) == 0 ? 1 : 0, + NULL); +} + +void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { + unsigned int w, h, mh; + + (void)user_data; + (void)call_data; + + w = MwGetInteger(handle, MwNwidth); + h = MwGetInteger(handle, MwNheight) - (mh = MwGetInteger(menu, MwNheight)); + + MwVaApply(button, + MwNy, 50 + mh, + MwNwidth, (w - 50 * 2) / 4, + MwNheight, h - 125 - 50 * 3, + NULL); + + MwVaApply(button2, + MwNx, 50 + (w - 50 * 2) / 4, + MwNy, 50 + mh, + MwNwidth, (w - 50 * 2) / 4, + MwNheight, h - 125 - 50 * 3, + NULL); + + MwVaApply(button3, + MwNx, 50 + (w - 50 * 2) / 4 * 2, + MwNy, 50 + mh, + MwNwidth, (w - 50 * 2) / 4, + MwNheight, h - 125 - 50 * 3, + NULL); + MwVaApply(button7, + MwNx, 50 + (w - 50 * 2) / 4 * 3, + MwNy, 50 + mh, + MwNwidth, (w - 50 * 2) / 4, + MwNheight, h - 125 - 50 * 3, + NULL); + MwVaApply(button4, + MwNx, 50 + (w - 50 * 2) / 3 * 0, + MwNy, h - 50 - 125 + mh, + MwNwidth, (w - 50 * 2) / 3, + NULL); + + MwVaApply(button5, + MwNx, 50 + (w - 50 * 2) / 3 * 1, + MwNy, h - 50 - 125 + mh, + MwNwidth, (w - 50 * 2) / 3, + NULL); + + MwVaApply(button6, + MwNx, 50 + (w - 50 * 2) / 3 * 2, + MwNy, h - 50 - 125 + mh, + MwNwidth, (w - 50 * 2) / 3, + NULL); +} + +int main() { + MwMenu m, m2; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, + MwNtitle, "hello world", + NULL); + menu = MwCreateWidget(MwMenuClass, "menu", window, 0, 0, 0, 0); + button = MwVaCreateWidget(MwButtonClass, "button", window, 50, 50, 100, 125, + MwNtext, "theme", + NULL); + button2 = MwVaCreateWidget(MwButtonClass, "button", window, 150, 50, 100, 125, + MwNtext, "look", + NULL); + button3 = MwVaCreateWidget(MwButtonClass, "button", window, 250, 50, 100, 125, + MwNtext, "font", + NULL); + button4 = MwVaCreateWidget(MwButtonClass, "button", window, 50, 225, 100, 125, + MwNtext, "lorem ipsum", + MwNbackground, "#f66", + MwNforeground, "#000", + NULL); + button5 = MwVaCreateWidget(MwButtonClass, "button", window, 150, 225, 100, 125, + MwNtext, "lorem ipsum", + MwNbackground, "#6f6", + MwNforeground, "#000", + NULL); + button6 = MwVaCreateWidget(MwButtonClass, "button", window, 250, 225, 100, 125, + MwNtext, "lorem ipsum", + MwNbackground, "#66f", + MwNforeground, "#000", + NULL); + button7 = MwVaCreateWidget(MwButtonClass, "button", window, 250, 50, 100, 125, + MwNtext, "disabled", + MwNdisabled, 1, + NULL); + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(button, MwNactivateHandler, handler_theme, NULL); + MwAddUserHandler(button2, MwNactivateHandler, handler_look, NULL); + MwAddUserHandler(button3, MwNactivateHandler, handler_font, NULL); + MwAddUserHandler(button4, MwNactivateHandler, handler, NULL); + MwAddUserHandler(button5, MwNactivateHandler, handler, NULL); + MwAddUserHandler(button6, MwNactivateHandler, handler, NULL); + + resize(window, NULL, NULL); + + m = MwMenuAdd(menu, NULL, "test 1"); + m2 = MwMenuAdd(menu, m, "test 2"); + MwMenuAdd(menu, m2, "test 3"); + MwMenuAdd(menu, m2, "test 4"); + MwMenuAdd(menu, m2, "test 5"); + m2 = MwMenuAdd(menu, m, "test 6"); + MwMenuAdd(menu, m2, "test 7"); + MwMenuAdd(menu, m2, "test 8"); + m2 = MwMenuAdd(menu, m, "test 9"); + MwMenuAdd(menu, m2, "test 10"); + m2 = MwMenuAdd(menu, m2, "test 11"); + MwMenuAdd(menu, m2, "test 12"); + MwMenuAdd(menu, m2, "test 13"); + MwMenuAdd(menu, NULL, "?test 14"); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/filechooser.c b/widget/milsko/milskosrc/examples/basic/filechooser.c new file mode 100644 index 0000000000..2637f86f8b --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/filechooser.c @@ -0,0 +1,70 @@ +#include + +MwWidget fpicker; +MwWidget window; +MwWidget button; +MwWidget mb; + +MwBool fpicker_wait = MwFALSE; +MwBool msgbox_wait = MwFALSE; + +void MWAPI ok(MwWidget handle, void* user, void* call) { + (void)handle; + (void)call; + msgbox_wait = MwFALSE; +} + +void MWAPI file_callback(MwWidget handle, void* user_data, void* call_data) { + mb = MwMessageBox(handle, call_data, "File chosen", MwMB_ICONERROR | MwMB_BUTTONOK); + + (void)user_data; + + MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); + MwAddUserHandler(mb, MwNcloseHandler, ok, mb); + + msgbox_wait = MwTRUE; + + while(msgbox_wait) { + MwStep(mb); + } + + fpicker_wait = MwFALSE; +} + +void MWAPI file_picker(MwWidget handle, void* user_data, void* call_data) { + fpicker = MwFileChooserEx(handle, "file chooser", 0); + + (void)handle; + (void)user_data; + (void)call_data; + + MwAddUserHandler(fpicker, MwNfileChosenHandler, file_callback, NULL); + + MwSetText(fpicker, MwNbackground, MwGetInteger(fpicker, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); + + fpicker_wait = MwTRUE; + + while(fpicker_wait) { + MwStep(fpicker); + } + + MwDestroyWidget(fpicker); + MwDestroyWidget(mb); +} + +int main() { + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, + MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); + MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + + button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, + MwNtext, "select file", + NULL); + MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); + + MwAddUserHandler(button, MwNactivateHandler, file_picker, NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/image.c b/widget/milsko/milskosrc/examples/basic/image.c new file mode 100644 index 0000000000..7d7f55a2de --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/image.c @@ -0,0 +1,42 @@ +#include + +int main() { + MwWidget window, image, image2, image3; + MwLLPixmap px, px2, px3; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "window", NULL, MwDEFAULT, MwDEFAULT, 500, 500, + MwNtitle, "image image", + NULL); + image = MwCreateWidget(MwImageClass, "image", window, 50, 50, 200, 400); + image2 = MwCreateWidget(MwImageClass, "image", window, 250, 50, 200, 200); + image3 = MwCreateWidget(MwImageClass, "image", window, 250, 250, 200, 200); + px = MwLoadImage(window, "examples/picture.png"); + px2 = MwLoadImage(window, "examples/picture.jpg"); + px3 = MwLoadImage(window, "resource/logo/logo.png"); + + if(px == NULL) px = MwLoadImage(window, "../examples/picture.png"); + if(px2 == NULL) px2 = MwLoadImage(window, "../examples/picture.jpg"); + if(px3 == NULL) px3 = MwLoadImage(window, "../resource/logo/logo.png"); + + if(px == NULL) px = MwLoadImage(window, "picture.png"); + if(px2 == NULL) px2 = MwLoadImage(window, "picture.jpg"); + if(px3 == NULL) px3 = MwLoadImage(window, "logo.png"); + + MwVaApply(window, + MwNiconPixmap, px, + NULL); + + MwVaApply(image, + MwNpixmap, px, + NULL); + MwVaApply(image2, + MwNpixmap, px2, + NULL); + MwVaApply(image3, + MwNpixmap, px3, + NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/listbox.c b/widget/milsko/milskosrc/examples/basic/listbox.c new file mode 100644 index 0000000000..0ec9fe7cd4 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/listbox.c @@ -0,0 +1,61 @@ +#include + +#include "../harvard.c" + +MwWidget w_main; + +void MWAPI destroy(MwWidget handle, void* user, void* call) { + (void)handle; + (void)call; + MwDestroyWidget(user); +} + +void MWAPI activate(MwWidget handle, void* user, void* call) { + char msg[256]; + MwWidget msgbox; + + (void)user; + + MwStringPrintIntoBuffer(msg, 256, "You pressed: %s", MwListBoxGet(handle, *(int*)call)); + + msgbox = MwMessageBox(w_main, msg, "wow", MwMB_ICONINFO | MwMB_BUTTONOK); + MwAddUserHandler(MwMessageBoxGetChild(msgbox, MwMB_BUTTONOK), MwNactivateHandler, destroy, msgbox); +} + +int main() { + MwWidget lb; + int len = sizeof(harvard) / sizeof(harvard[0]) - 1; + int i; + int index; + MwLLPixmap px; + + MwLibraryInit(); + + w_main = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, + MwNtitle, "listbox", + NULL); + lb = MwCreateWidget(MwListBoxClass, "listbox", w_main, 5, 5, 630, 470); + + px = MwLoadIcon(lb, MwIconInfo); + + MwSetInteger(lb, MwNleftPadding, 20); + + index = MwListBoxSet(lb, -1, 0, "Harvard sentence"); + MwListBoxSet(lb, index, -1, "Length"); + + for(i = 0; i < len; i++) { + char sz[16]; + MwStringPrintIntoBuffer(sz, 16, "%d", (int)strlen(harvard[i])); + index = MwListBoxSet(lb, -1, 0, harvard[i]); + MwListBoxSet(lb, index, -1, sz); + MwListBoxSetIcon(lb, index, px); + } + + MwAddUserHandler(lb, MwNlistBoxActivateHandler, activate, NULL); + MwVaApply(lb, + MwNhasHeading, 1, + NULL); + MwListBoxSetWidth(lb, 0, -128); + + MwLoop(w_main); +} diff --git a/widget/milsko/milskosrc/examples/basic/messagebox.c b/widget/milsko/milskosrc/examples/basic/messagebox.c new file mode 100644 index 0000000000..8c617d7b0a --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/messagebox.c @@ -0,0 +1,57 @@ +#include + +void MWAPI ok(MwWidget handle, void* user, void* call) { + (void)handle; + (void)call; + MwDestroyWidget(user); +} + +void MWAPI spawn(MwWidget handle, void* user, void* call) { + MwWidget mb = MwMessageBox(user, "news has arrived!", "title", MwMB_ICONNEWS | MwMB_BUTTONOK); + + (void)handle; + (void)call; + + MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); + MwAddUserHandler(mb, MwNcloseHandler, ok, mb); +} + +void MWAPI spawn2(MwWidget handle, void* user, void* call) { + MwWidget mb = MwMessageBox(user, "something went wrong!", "title", MwMB_ICONERROR | MwMB_BUTTONOK); + + (void)handle; + (void)call; + + MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); + MwAddUserHandler(mb, MwNcloseHandler, ok, mb); +} + +void MWAPI spawn3(MwWidget handle, void* user, void* call) { + int i; + + (void)handle; + (void)call; + + for(i = 0; i <= MwMB_ICONCLOCK; i++) { + MwWidget mb = MwMessageBox(user, "messagebox test", "title", i | MwMB_BUTTONOK); + MwAddUserHandler(MwMessageBoxGetChild(mb, MwMB_BUTTONOK), MwNactivateHandler, ok, mb); + MwAddUserHandler(mb, MwNcloseHandler, ok, mb); + } +} + +int main() { + MwWidget msg, btn, btn2, btn3; + + MwLibraryInit(); + + msg = MwVaCreateWidget(MwWindowClass, "test", NULL, MwDEFAULT, MwDEFAULT, 300, 100, MwNtitle, "test", NULL); + btn = MwVaCreateWidget(MwButtonClass, "button", msg, 8, 8, 300 - 16, (100 - 16) / 2, MwNtext, "press me!", NULL); + btn2 = MwVaCreateWidget(MwButtonClass, "button", msg, 8, 8 + (100 - 16) / 2, (300 - 16) / 2, (100 - 16) / 2, MwNtext, "press me!", NULL); + btn3 = MwVaCreateWidget(MwButtonClass, "button", msg, 8 + (300 - 16) / 2, 8 + (100 - 16) / 2, (300 - 16) / 2, (100 - 16) / 2, MwNtext, "press me!", NULL); + + MwAddUserHandler(btn, MwNactivateHandler, spawn, msg); + MwAddUserHandler(btn2, MwNactivateHandler, spawn2, msg); + MwAddUserHandler(btn3, MwNactivateHandler, spawn3, msg); + + MwLoop(msg); +} diff --git a/widget/milsko/milskosrc/examples/basic/periodic.c b/widget/milsko/milskosrc/examples/basic/periodic.c new file mode 100644 index 0000000000..92dab70a35 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/periodic.c @@ -0,0 +1,326 @@ +#include + +#include + +#define Columns 5 +#define Padding 20 +#define PaddingContent 2 + +MwWidget window, menu, table; +MwMenu e; + +static void MWAPI resize(MwWidget handle, void* user, void* call) { + int w = MwGetInteger(window, MwNwidth); + int h = MwGetInteger(window, MwNheight); + + MwVaApply(table, + MwNx, Padding, + MwNy, MwGetInteger(menu, MwNheight) + Padding, + MwNwidth, w - Padding * 2, + MwNheight, h - MwGetInteger(menu, MwNheight) - Padding * 2, + NULL); +} + +static void MWAPI resize_content(MwWidget handle, void* user, void* call) { + MwWidget* ws = MwGetChildren(handle); + if(ws != NULL) { + int pw = MwGetInteger(ws[0], "IpWidth"); + int ph = MwGetInteger(ws[0], "IpHeight"); + + if(pw < 0) { + pw += MwGetInteger(handle, MwNwidth); + } else if(pw == 0) { + pw = MwGetInteger(handle, MwNwidth); + } + + if(ph < 0) { + ph += MwGetInteger(handle, MwNheight); + } else if(ph == 0) { + ph = MwGetInteger(handle, MwNheight); + } + + MwVaApply(ws[0], + MwNx, (MwGetInteger(handle, MwNwidth) - pw) / 2, + MwNy, (MwGetInteger(handle, MwNheight) - ph) / 2, + MwNwidth, pw, + MwNheight, ph, + NULL); + + free(ws); + } +} + +static void MWAPI resize_frame(MwWidget handle, void* user, void* call) { + MwWidget* ws = MwGetChildren(handle); + if(ws != NULL) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + + if(ws[0] != NULL) { + MwVaApply(ws[0], + MwNx, MwDefaultBorderWidth(handle) + PaddingContent, + MwNy, MwDefaultBorderWidth(handle) + PaddingContent, + MwNwidth, w - (MwDefaultBorderWidth(handle) + PaddingContent) * 2, + MwNheight, h - (MwDefaultBorderWidth(handle) + PaddingContent) * 2, + NULL); + } + free(ws); + } +} + +static MwWidget frame(const char* name, int width, int height, MwClass cl, ...) { + MwWidget f = MwVaCreateWidget(MwFrameClass, "frame", table, 0, 0, 0, 0, + MwNhasBorder, 1, + MwNinverted, 1, + NULL); + MwWidget table = MwVaCreateWidget(MwBoxClass, "table", f, 0, 0, 0, 0, + MwNorientation, MwVERTICAL, + NULL); + MwWidget label = MwVaCreateWidget(MwLabelClass, "label", table, 0, 0, 0, 0, + MwNtext, name, + MwNalignment, MwALIGNMENT_BEGINNING, + MwNfixedSize, 20, + NULL); + va_list va; + + if(cl != NULL) { + MwWidget frame = MwCreateWidget(MwFrameClass, "frame", table, 0, 0, 0, 0); + MwWidget w; + + va_start(va, cl); + w = MwVaListCreateWidget(cl, "widget", frame, 0, 0, 0, 0, va); + va_end(va); + + MwVaApply(w, + "IpWidth", width, + "IpHeight", height, + NULL); + + MwAddUserHandler(frame, MwNresizeHandler, resize_content, NULL); + + MwVaApply(f, + "VhandledWidget", w, + MwNcolumnSpan, MwGetInteger(w, MwNcolumnSpan), + MwNrowSpan, MwGetInteger(w, MwNrowSpan), + NULL); + } + + MwAddUserHandler(f, MwNresizeHandler, resize_frame, NULL); + + resize_frame(f, NULL, NULL); + + return f; +} + +static MwWidget child(MwWidget w) { + return MwGetVoid(w, "VhandledWidget"); +} + +static void MWAPI menu_handler(MwWidget handle, void* user, void* call) { + if(call == e) MwDestroyWidget(window); +} + +int main() { + int i, j; + MwWidget f, w, b; + MwLLPixmap px; + int index; + MwMenu m, m2; + void* v; + MwRect rc; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "window", NULL, MwDEFAULT, MwDEFAULT, 800, 800, + MwNtitle, "Milsko Periodic Table", + NULL); + + MwGetScreenSize(window, &rc); + if(rc.height < 800) { + MwVaApply(window, + MwNx, (rc.width - (rc.height - 64)) / 2, + MwNy, (rc.height - (rc.height - 64)) / 2, + MwNwidth, rc.height - 64, + MwNheight, rc.height - 64, + NULL); + } + + px = MwLoadIcon(window, MwIconError); + + menu = MwCreateWidget(MwMenuClass, "menu", window, 0, 0, 0, 0); + + m = MwMenuAdd(menu, NULL, "File"); + MwMenuAdd(menu, m, "New"); + MwMenuAdd(menu, m, "Open"); + MwMenuAdd(menu, m, "Save"); + MwMenuAdd(menu, m, "Save As"); + MwMenuAdd(menu, m, "Print"); + e = MwMenuAdd(menu, m, "Exit"); + + m = MwMenuAdd(menu, NULL, "Edit"); + MwMenuAdd(menu, m, "Undo"); + MwMenuAdd(menu, m, "----"); + MwMenuAdd(menu, m, "Cut"); + MwMenuAdd(menu, m, "Copy"); + MwMenuAdd(menu, m, "Paste"); + MwMenuAdd(menu, m, "----"); + MwMenuAdd(menu, m, "Clear"); + MwMenuAdd(menu, m, "Delete"); + + m = MwMenuAdd(menu, NULL, "View"); + MwMenuAdd(menu, m, "Stack"); + MwMenuAdd(menu, m, "Tile"); + MwMenuAdd(menu, m, "----"); + MwMenuAdd(menu, m, "Day"); + MwMenuAdd(menu, m, "Week"); + MwMenuAdd(menu, m, "Month"); + MwMenuAdd(menu, m, "Year"); + + m = MwMenuAdd(menu, NULL, "Options"); + m2 = MwMenuAdd(menu, m, "Font"); + MwMenuAdd(menu, m2, "Small"); + MwMenuAdd(menu, m2, "Medium"); + MwMenuAdd(menu, m2, "Large"); + m2 = MwMenuAdd(menu, m, "Direction"); + MwMenuAdd(menu, m2, "Up"); + MwMenuAdd(menu, m2, "Down"); + MwMenuAdd(menu, m2, "Left"); + MwMenuAdd(menu, m2, "Right"); + MwMenuAdd(menu, m, "Case Sensitive"); + MwMenuAdd(menu, m, "Word Wrap"); + + m = MwMenuAdd(menu, NULL, "?Help"); + MwMenuAdd(menu, m, "On Context"); + MwMenuAdd(menu, m, "On Window"); + MwMenuAdd(menu, m, "Tutorial"); + MwMenuAdd(menu, m, "On Version"); + + MwAddUserHandler(menu, MwNmenuHandler, menu_handler, NULL); + + table = MwVaCreateWidget(MwTableClass, "table", window, 0, 0, 0, 0, + MwNwaitLayout, 1, + MwNcolumns, 5, + NULL); + + f = frame("Button", -PaddingContent, -PaddingContent, MwBoxClass, + MwNorientation, MwVERTICAL, + NULL); + b = MwVaCreateWidget(MwButtonClass, "btn", child(f), 0, 0, 0, 0, + MwNtext, "Press me", + NULL); + b = MwVaCreateWidget(MwButtonClass, "btn_disabled", child(f), 0, 0, 0, 0, + MwNtext, "Cannot press me", + MwNdisabled, 1, + NULL); + + MwVaCreateWidget(MwLabelClass, "label", table, 0, 0, 0, 0, + MwNbold, 1, + MwNtext, "The Periodic Table of Milsko Widgets", + MwNcolumnSpan, Columns - 2, + NULL); + + for(i = 0; i < 2; i++) { + f = frame(i == 0 ? "CheckBox" : "RadioBox", -PaddingContent, -PaddingContent, MwBoxClass, + MwNmargin, PaddingContent, + NULL); + w = child(f); + b = MwVaCreateWidget(MwBoxClass, "table1", w, 0, 0, 0, 0, + MwNorientation, MwVERTICAL, + MwNfixedSize, 16, + NULL); + for(j = 0; j < 6; j++) MwVaCreateWidget(i == 0 ? MwCheckBoxClass : MwRadioBoxClass, i == 0 ? "cb" : "rb", b, 0, 0, 0, 0, MwNdisabled, (j == 5) ? 1 : 0, NULL); + b = MwVaCreateWidget(MwBoxClass, "table1", w, 0, 0, 0, 0, + MwNorientation, MwVERTICAL, + NULL); + for(j = 0; j < 6; j++) { + char buf[32]; + sprintf(buf, "%sBox %d", i == 0 ? "Check" : "Radio", j + 1); + MwVaCreateWidget(MwLabelClass, "label", b, 0, 0, 0, 0, + MwNtext, buf, + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + } + } + + f = frame("Calendar", -PaddingContent, -PaddingContent, MwCalendarClass, + MwNscale, 1, + NULL); + + f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); + w = child(f); + MwComboBoxAdd(w, -1, "Hello!"); + + f = frame("Entry", -PaddingContent, 24, MwEntryClass, NULL); + + f = frame("Image", -PaddingContent, -PaddingContent, MwImageClass, + MwNpixmap, px, + NULL); + + f = frame("Label", -PaddingContent, -PaddingContent, MwLabelClass, + MwNtext, "Epic text\nNewline can be used too!", + NULL); + + f = frame("ListBox", -PaddingContent, -PaddingContent, MwListBoxClass, + MwNhasHeading, 1, + NULL); + w = child(f); + index = MwListBoxSet(w, -1, 0, "Epic title..."); + index = MwListBoxSet(w, -1, 0, "Hello"); + + f = frame("NumberEntry", -PaddingContent, 24, MwNumberEntryClass, NULL); + + f = frame("ProgressBar", -PaddingContent, 24, MwProgressBarClass, + MwNvalue, 25, + NULL); + + f = frame("ScrollBar", -PaddingContent, 16, MwScrollBarClass, + MwNorientation, MwHORIZONTAL, + NULL); + + f = frame("Separator", -PaddingContent, -PaddingContent, MwSeparatorClass, NULL); + + f = frame("SubWindow", -PaddingContent, -PaddingContent, MwViewportClass, + MwNcolumnSpan, 2, + NULL); + w = child(f); + MwViewportSetSize(w, 512, 512); + MwVaCreateWidget(MwSubWindowClass, "swnd", MwViewportGetViewport(w), 32, 32, 256, 128, + MwNtitle, "Sub window", + NULL); + MwVaCreateWidget(MwSubWindowClass, "swnd", MwViewportGetViewport(w), 64, 64, 256, 128, + MwNtitle, "Sub window 2", + NULL); + + f = frame("Tab", -PaddingContent, -PaddingContent, MwTabClass, + MwNcolumnSpan, 2, + NULL); + w = child(f); + MwSetText(MwTabAdd(w, "ABC"), MwNbackground, "#f00"); + MwSetText(MwTabAdd(w, "DEF"), MwNbackground, "#0f0"); + MwSetText(MwTabAdd(w, "GHI"), MwNbackground, "#00f"); + + f = frame("TreeView", -PaddingContent, -PaddingContent, MwTreeViewClass, NULL); + w = child(f); + v = MwTreeViewAdd(w, NULL, NULL, "abc"); + v = MwTreeViewAdd(w, v, NULL, "def"); + v = MwTreeViewAdd(w, v, NULL, "ghi"); + + f = frame("Viewport", -PaddingContent, -PaddingContent, MwViewportClass, NULL); + w = child(f); + MwViewportSetSize(w, 256, 256); + MwVaCreateWidget(MwButtonClass, "btn", MwViewportGetViewport(w), 64, 64, 128, 128, + MwNtext, "Thing", + NULL); + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + + resize(window, NULL, NULL); + + MwVaApply(table, + MwNwaitLayout, 0, + NULL); + + MwLoop(window); + + MwLLDestroyPixmap(px); +} diff --git a/widget/milsko/milskosrc/examples/basic/progressbar.c b/widget/milsko/milskosrc/examples/basic/progressbar.c new file mode 100644 index 0000000000..4048a6e781 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/progressbar.c @@ -0,0 +1,18 @@ +#include + +int main() { + MwWidget w, p; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 5 + 640 + 5, 5 + 32 + 5, + MwNtitle, "progress bar", + NULL); + p = MwVaCreateWidget(MwProgressBarClass, "progress", w, 5, 5, 640, 32, + MwNvalue, 25, + NULL); + + (void)p; + + MwLoop(w); +} diff --git a/widget/milsko/milskosrc/examples/basic/radiobox.c b/widget/milsko/milskosrc/examples/basic/radiobox.c new file mode 100644 index 0000000000..168f10138c --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/radiobox.c @@ -0,0 +1,28 @@ +#include + +int main() { + MwWidget window; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "test", NULL, MwDEFAULT, MwDEFAULT, 8 + 16 + 8 + 16 * 10 + 8, 8 + 16 + 8 + 16 + 8, + MwNtitle, "radiobox", + NULL); + + MwVaCreateWidget(MwRadioBoxClass, "cb1", window, 8, 8, 16, 16, + NULL); + MwVaCreateWidget(MwRadioBoxClass, "cb2", window, 8, 8 + 16 + 8, 16, 16, + MwNchecked, 1, + NULL); + + MwVaCreateWidget(MwLabelClass, "lab1", window, 8 + 16 + 8, 8, 16 * 10, 16, + MwNtext, "lorem ipsum 1", + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + MwVaCreateWidget(MwLabelClass, "lab2", window, 8 + 16 + 8, 8 + 16 + 8, 16 * 10, 16, + MwNtext, "lorem ipsum 2", + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/rotate.c b/widget/milsko/milskosrc/examples/basic/rotate.c new file mode 100644 index 0000000000..dbf9c5e154 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/rotate.c @@ -0,0 +1,95 @@ +/* this demo does not work well on windows */ +#include + +#include + +#ifndef M_PI +#define M_PI 3.14159265 +#endif + +#define SIZE 100 + +MwWidget buttons[6]; +double deg = 0; + +int ww, wh; + +void MWAPI handler(MwWidget w, void* user, void* client) { + int i; + double cdeg = deg; + + (void)w; + (void)user; + (void)client; + + for(i = 0; i < (int)(sizeof(buttons) / sizeof(buttons[0])); i++) { + double rad = cdeg / 180 * M_PI; + int x = ww / 2; + int y = wh / 2; + + x += cos(rad) * (ww / 2 - SIZE / 2); + y += sin(rad) * (wh / 2 - SIZE / 2); + + x -= SIZE / 2; + y -= SIZE / 2; + + MwVaApply(buttons[i], + MwNx, x, + MwNy, y, + NULL); + + cdeg += 360 / (sizeof(buttons) / sizeof(buttons[0])); + } + + deg += 120.0 / (1000.0 / MwWaitMS); +} + +void MWAPI resize(MwWidget w, void* user, void* client) { + (void)w; + (void)user; + (void)client; + + ww = MwGetInteger(w, MwNwidth); + wh = MwGetInteger(w, MwNheight); +} + +int main() { + MwWidget window; + int i; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "window", NULL, MwDEFAULT, MwDEFAULT, (ww = 500), (wh = 500), + MwNtitle, "rotate", + NULL); + + for(i = 0; i < (int)(sizeof(buttons) / sizeof(buttons[0])); i++) { + const char* color = ""; + char fgcolor[5]; + int j; + + if(i == 0) color = "#f66"; + if(i == 1) color = "#6f6"; + if(i == 2) color = "#ff6"; + if(i == 3) color = "#66f"; + if(i == 4) color = "#f6f"; + if(i == 5) color = "#6ff"; + + fgcolor[0] = '#'; + fgcolor[4] = 0; + for(j = 0; j < 3; j++) { + fgcolor[j + 1] = color[j + 1] == 'f' ? '6' : 'f'; + } + + buttons[i] = MwVaCreateWidget(MwButtonClass, "button", window, 0, 0, SIZE, SIZE, + MwNbackground, color, + MwNforeground, fgcolor, + MwNtext, "fancy", + NULL); + } + + MwAddUserHandler(window, MwNtickHandler, handler, NULL); + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/scrollbar.c b/widget/milsko/milskosrc/examples/basic/scrollbar.c new file mode 100644 index 0000000000..dbaae9a01f --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/scrollbar.c @@ -0,0 +1,20 @@ +#include + +int main() { + MwWidget window; + int i; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 500, 500, + MwNtitle, "main", + NULL); + + for(i = 0; i < 500 / 16; i++) { + MwVaCreateWidget(MwScrollBarClass, "scroll", window, 16 * i, 0, 16, 500, + MwNorientation, MwVERTICAL, + NULL); + } + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/basic/sevensegment.c b/widget/milsko/milskosrc/examples/basic/sevensegment.c new file mode 100644 index 0000000000..08149a9fd2 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/sevensegment.c @@ -0,0 +1,23 @@ +#include + +int main() { + MwWidget wnd, label; + int W = 480, H = 40; + + MwLibraryInit(); + + wnd = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, W, H, + MwNtitle, "seven segment", + NULL); + + label = MwVaCreateWidget(MwLabelClass, "label", wnd, 0, 0, W, H, + MwNtext, " 123456:78.90 abcdef", + MwNsevenSegment, 1, + MwNalignment, MwALIGNMENT_BEGINNING, + MwNlength, 8, + NULL); + + MwLabelSetSevenSegment(label, 0, (1 << 0) | (1 << 3) | (1 << 6)); + + MwLoop(wnd); +} diff --git a/widget/milsko/milskosrc/examples/basic/subwindow.c b/widget/milsko/milskosrc/examples/basic/subwindow.c new file mode 100644 index 0000000000..93145923d6 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/subwindow.c @@ -0,0 +1,52 @@ +#include + +#define Shift 16 + +static void MWAPI resize(MwWidget handle, void* user, void* client) { + MwWidget f = MwSubWindowGetFrame(handle); + MwVaApply(user, + MwNwidth, MwGetInteger(f, MwNwidth), + MwNheight, MwGetInteger(f, MwNheight), + NULL); +} + +int main() { + MwWidget w; + int i; + MwLLPixmap px[6]; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 800, 600, + MwNtitle, "subwindow", + NULL); + + px[0] = MwLoadIcon(w, MwIconClock); + px[1] = MwLoadIcon(w, MwIconError); + px[2] = MwLoadIcon(w, MwIconInfo); + px[3] = MwLoadIcon(w, MwIconNews); + px[4] = MwLoadIcon(w, MwIconNote); + px[5] = MwLoadIcon(w, MwIconWarning); + + for(i = 0; i < 16; i++) { + char buf[32]; + MwWidget sw, f, img; + + sprintf(buf, "Sub window %d", i); + + sw = MwVaCreateWidget(MwSubWindowClass, "swnd", w, i * Shift, i * Shift, 128, 128, + MwNtitle, buf, + MwNiconPixmap, px[rand() % 6], + NULL); + + f = MwSubWindowGetFrame(sw); + + img = MwVaCreateWidget(MwImageClass, "img", f, 0, 0, MwGetInteger(f, MwNwidth), MwGetInteger(f, MwNheight), + MwNpixmap, px[rand() % 6], + NULL); + + MwAddUserHandler(sw, MwNresizeHandler, resize, img); + } + + MwLoop(w); +} diff --git a/widget/milsko/milskosrc/examples/basic/tab.c b/widget/milsko/milskosrc/examples/basic/tab.c new file mode 100644 index 0000000000..8ae16c04de --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/tab.c @@ -0,0 +1,43 @@ +#include + +MwWidget tab; + +static void MWAPI resize(MwWidget handle, void* user, void* client) { + MwVaApply(tab, + MwNwidth, MwGetInteger(handle, MwNwidth), + MwNheight, MwGetInteger(handle, MwNheight), + NULL); +} + +int main() { + MwWidget w; + int i; + MwLLPixmap px[6]; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 800, 600, + MwNtitle, "subwindow", + NULL); + + tab = MwCreateWidget(MwTabClass, "tab", w, 0, 0, 800, 600); + + for(i = 0; i < 16; i++) { + char buf[32]; + MwWidget sw, f, img; + + sprintf(buf, "Tab %d", i); + + MwTabAdd(tab, buf); + } + + MwVaApply(MwTabGetFrame(tab, "Tab 1"), + MwNiconPixmap, MwLoadIcon(tab, MwIconWarning), + NULL); + + MwAddUserHandler(w, MwNresizeHandler, resize, NULL); + + resize(w, NULL, NULL); + + MwLoop(w); +} diff --git a/widget/milsko/milskosrc/examples/basic/treeview.c b/widget/milsko/milskosrc/examples/basic/treeview.c new file mode 100644 index 0000000000..273dd3e2a3 --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/treeview.c @@ -0,0 +1,50 @@ +#include + +MwWidget wmain; + +void MWAPI destroy(MwWidget handle, void* user, void* call) { + (void)handle; + (void)call; + MwDestroyWidget(user); +} + +void MWAPI activate(MwWidget handle, void* user, void* call) { + char msg[256]; + MwWidget msgbox; + + (void)user; + + MwStringPrintIntoBuffer(msg, 256, "You pressed: %s", MwTreeViewGet(handle, call)); + + msgbox = MwMessageBox(wmain, msg, "wow", MwMB_ICONINFO | MwMB_BUTTONOK); + MwAddUserHandler(MwMessageBoxGetChild(msgbox, MwMB_BUTTONOK), MwNactivateHandler, destroy, msgbox); +} + +int main() { + MwWidget tv; + MwLLPixmap px; + int i; + void * p = NULL, *r; + + MwLibraryInit(); + + wmain = MwCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 5 + 640 + 5, 5 + 480 + 5); + tv = MwCreateWidget(MwTreeViewClass, "tree", wmain, 5, 5, 640, 480); + + px = MwLoadIcon(tv, MwIconInfo); + + MwSetInteger(tv, MwNleftPadding, 16); + + MwAddUserHandler(tv, MwNactivateHandler, activate, NULL); + + for(i = 0; i < 10; i++) { + void* old = p; + + MwTreeViewAdd(tv, old, px, "World"); + p = MwTreeViewAdd(tv, old, px, "Hello"); + if(i == 5) r = p; + MwTreeViewAdd(tv, old, px, "Goodbye"); + } + + MwLoop(wmain); +} diff --git a/widget/milsko/milskosrc/examples/basic/viewport.c b/widget/milsko/milskosrc/examples/basic/viewport.c new file mode 100644 index 0000000000..930488d9ee --- /dev/null +++ b/widget/milsko/milskosrc/examples/basic/viewport.c @@ -0,0 +1,42 @@ +#include + +MwWidget vp; + +static void MWAPI resize(MwWidget handle, void* user, void* call) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + + (void)user; + (void)call; + + MwVaApply(vp, + MwNwidth, w - 10 - 100, + MwNheight, h - 10 - 100, + NULL); +} + +int main() { + MwWidget w; + MwLLPixmap px; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, MwNtitle, "test", NULL); + + vp = MwCreateWidget(MwViewportClass, "vp", w, 5 + 50, 5 + 50, 640 - 10 - 100, 480 - 10 - 100); + + px = MwLoadImage(vp, "examples/picture.png"); + + if(px == NULL) px = MwLoadImage(vp, "../examples/picture.png"); + + if(px == NULL) px = MwLoadImage(vp, "picture.png"); + + MwVaCreateWidget(MwImageClass, "image", MwViewportGetViewport(vp), 0, 0, 1024, 1024, + MwNpixmap, px, + NULL); + MwViewportSetSize(vp, 1024, 1024); + + MwAddUserHandler(w, MwNresizeHandler, resize, NULL); + + MwLoop(w); +} diff --git a/widget/milsko/milskosrc/examples/gldemos/CMakeLists.txt b/widget/milsko/milskosrc/examples/gldemos/CMakeLists.txt new file mode 100644 index 0000000000..0a8fa78e69 --- /dev/null +++ b/widget/milsko/milskosrc/examples/gldemos/CMakeLists.txt @@ -0,0 +1,27 @@ +file( + GLOB + EXAMPLES_GL_SOURCES + *.c +) +find_package(OpenGL) + +foreach(PATH IN LISTS EXAMPLES_GL_SOURCES) + get_filename_component(TARGET ${PATH} NAME_WE) + if(${TARGET} STREQUAL "glutlayer") + continue() + endif() + add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) + target_link_libraries( + ${TARGET} + PRIVATE + Mw + OpenGL::GL OpenGL::GLU + ) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_libraries( + ${TARGET} + PRIVATE + m + ) + endif() +endforeach() diff --git a/widget/milsko/milskosrc/examples/gldemos/boing.c b/widget/milsko/milskosrc/examples/gldemos/boing.c new file mode 100644 index 0000000000..8682996d3c --- /dev/null +++ b/widget/milsko/milskosrc/examples/gldemos/boing.c @@ -0,0 +1,158 @@ +#define TITLE "boing" +#include "glutlayer.c" + +/* + * Bouncing ball demo. + * + * This program is in the public domain + * + * Brian Paul + */ + +#include +#include + +#define COS(X) cos((X) * 3.14159 / 180.0) +#define SIN(X) sin((X) * 3.14159 / 180.0) + +#define RED 1.0, 0.0, 0.0 +#define WHITE 1.0, 1.0, 1.0 +#define CYAN 0.0, 1.0, 1.0 + +GLuint Ball; +GLenum Mode; +GLfloat Zrot = 0.0, Zstep = 6.0; +GLfloat Xpos = 0.0, Ypos = 1.0; +GLfloat Xvel = 0.2, Yvel = 0.0; +GLfloat Xmin = -4.0, Xmax = 4.0; +GLfloat Ymin = -3.8, Ymax = 4.0; +GLfloat G = -0.1; + +static GLuint make_ball(void) { + GLuint list; + GLfloat a, b; + GLfloat da = 18.0, db = 18.0; + GLfloat radius = 1.0; + GLuint color; + GLfloat x, y, z; + + list = glGenLists(1); + + glNewList(list, GL_COMPILE); + + color = 0; + for(a = -90.0; a + da <= 90.0; a += da) { + + glBegin(GL_QUAD_STRIP); + for(b = 0.0; b <= 360.0; b += db) { + + if(color) { + glColor3f(RED); + } else { + glColor3f(WHITE); + } + + x = COS(b) * COS(a); + y = SIN(b) * COS(a); + z = SIN(a); + glVertex3f(x, y, z); + + x = radius * COS(b) * COS(a + da); + y = radius * SIN(b) * COS(a + da); + z = radius * SIN(a + da); + glVertex3f(x, y, z); + + color = 1 - color; + } + glEnd(); + } + + glEndList(); + + return list; +} + +static void reshape(int width, int height) { + glViewport(0, 0, (GLint)width, (GLint)height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-6.0, 6.0, -6.0, 6.0, -6.0, 6.0); + glMatrixMode(GL_MODELVIEW); +} + +static void draw(void) { + GLint i; + + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(CYAN); + glBegin(GL_LINES); + for(i = -5; i <= 5; i++) { + glVertex2i(i, -5); + glVertex2i(i, 5); + } + for(i = -5; i <= 5; i++) { + glVertex2i(-5, i); + glVertex2i(5, i); + } + for(i = -5; i <= 5; i++) { + glVertex2i(i, -5); + glVertex2f(i * 1.15, -5.9); + } + glVertex2f(-5.3, -5.35); + glVertex2f(5.3, -5.35); + glVertex2f(-5.75, -5.9); + glVertex2f(5.75, -5.9); + glEnd(); + + glPushMatrix(); + glTranslatef(Xpos, Ypos, 0.0); + glScalef(2.0, 2.0, 2.0); + glRotatef(8.0, 0.0, 0.0, 1.0); + glRotatef(90.0, 1.0, 0.0, 0.0); + glRotatef(Zrot, 0.0, 0.0, 1.0); + + glCallList(Ball); + + glPopMatrix(); + + glFlush(); +} + +static void idle(void) { + static float vel0 = -100.0; + + Zrot += Zstep; + + Xpos += Xvel; + if(Xpos >= Xmax) { + Xpos = Xmax; + Xvel = -Xvel; + Zstep = -Zstep; + } + if(Xpos <= Xmin) { + Xpos = Xmin; + Xvel = -Xvel; + Zstep = -Zstep; + } + Ypos += Yvel; + Yvel += G; + if(Ypos < Ymin) { + Ypos = Ymin; + if(vel0 == -100.0) + vel0 = fabs(Yvel); + Yvel = vel0; + } +} + +static void init(void) { + Ball = make_ball(); + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + glDisable(GL_DITHER); + glShadeModel(GL_FLAT); +} + +static void key(int k) { + (void)k; +} diff --git a/widget/milsko/milskosrc/examples/gldemos/clock.c b/widget/milsko/milskosrc/examples/gldemos/clock.c new file mode 100644 index 0000000000..9f683b507b --- /dev/null +++ b/widget/milsko/milskosrc/examples/gldemos/clock.c @@ -0,0 +1,169 @@ +#include +#include + +#include + +MwWidget window, opengl, ldate, ltime; +time_t last = 0; +struct tm* tm; +int br, bg, bb; +int fr, fg, fb; + +double deg2rad(double deg) { + return (360.0 - deg) / 180.0 * M_PI; +} + +void MWAPI tick(MwWidget handle, void* user, void* call) { + time_t t = time(NULL); + int i; + double rad; + int render = 0; + int w = MwGetInteger(opengl, MwNwidth); + int h = MwGetInteger(opengl, MwNheight); + + (void)handle; + (void)user; + (void)call; + + if(last != t) { + char* wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + char* mon[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + char buf[512]; + tm = localtime(&t); + + MwStringPrintIntoBuffer(buf, 512, "%s %02d %s", mon[tm->tm_mon], tm->tm_mday, wday[tm->tm_wday]); + MwSetText(ldate, MwNtext, buf); + + MwStringPrintIntoBuffer(buf, 512, "%02d:%02d %s", tm->tm_hour % 12, tm->tm_min, tm->tm_hour >= 12 ? "PM" : "AM"); + MwSetText(ltime, MwNtext, buf); + + render = 1; + + last = t; + } + + MwOpenGLMakeCurrent(opengl); + + glClearColor(br / 255.0, bg / 255.0, bb / 255.0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1, 1, -1, 1, 0, 100); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glLineWidth(2); + for(i = 0; i < 12; i++) { + rad = deg2rad(30.0 * i); + glPointSize((i % 3) ? 2 : 5); + glBegin(GL_POINTS); + glColor3f(fr / 255.0, fg / 255.0, fb / 255.0); + glVertex2f(cos(rad) * 0.85, sin(rad) * 0.85); + glEnd(); + } + + rad = deg2rad((tm->tm_hour % 12) * 30 + (tm->tm_min / 2) - 90); + glBegin(GL_LINES); + glVertex2f(0, 0); + glVertex2f(cos(rad) * 0.3, sin(rad) * 0.3); + glEnd(); + + rad = deg2rad(tm->tm_min * 6 - 90); + glBegin(GL_LINES); + glVertex2f(0, 0); + glVertex2f(cos(rad) * 0.5, sin(rad) * 0.5); + glEnd(); + + if(render && w > 0 && h > 0) { + unsigned char* buffer = malloc(w * h * 4); + MwLLPixmap px; + int j; + + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + for(i = 0; i < h / 2; i++) { + for(j = 0; j < w * 4; j++) { + unsigned char b = buffer[i * w * 4 + j]; + + buffer[i * w * 4 + j] = buffer[(h - i - 1) * w * 4 + j]; + buffer[(h - i - 1) * w * 4 + j] = b; + } + } + + px = MwLoadRaw(window, buffer, w, h); + MwVaApply(window, + MwNiconPixmap, px, + NULL); + MwLLDestroyPixmap(px); + + free(buffer); + } + + MwOpenGLSwapBuffer(opengl); +} + +void MWAPI resize(MwWidget handle, void* user, void* call) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + + (void)user; + (void)call; + + MwVaApply(opengl, + MwNwidth, w / 5 * 2, + MwNheight, h, + NULL); + + MwVaApply(ldate, + MwNx, w / 5 * 2, + MwNwidth, w - w / 5 * 2, + MwNheight, h / 2, + NULL); + + MwVaApply(ltime, + MwNx, w / 5 * 2, + MwNy, h / 2, + MwNwidth, w - w / 5 * 2, + MwNheight, h / 2, + NULL); + + glViewport(0, 0, w / 5 * 2, h); +} + +int main() { + MwLLColor bgcolor, fgcolor; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 250, 100, + MwNtitle, "clock", + NULL); + + bgcolor = MwParseColor(window, MwGetText(window, MwNbackground)); + MwColorGet(bgcolor, &br, &bg, &bb); + + fgcolor = MwParseColor(window, MwGetText(window, MwNforeground)); + MwColorGet(fgcolor, &fr, &fg, &fb); + + opengl = MwCreateWidget(MwOpenGLClass, "clock", window, 0, 0, 100, 100); + + ldate = MwVaCreateWidget(MwLabelClass, "date", window, 100, 0, 150, 50, + MwNbold, 1, + NULL); + ltime = MwVaCreateWidget(MwLabelClass, "time", window, 100, 50, 150, 50, + MwNbold, 1, + NULL); + + MwAddUserHandler(window, MwNtickHandler, tick, NULL); + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + + resize(window, NULL, NULL); + tick(window, NULL, NULL); + + MwLoop(window); + + MwLLFreeColor(fgcolor); + MwLLFreeColor(bgcolor); +} diff --git a/widget/milsko/milskosrc/examples/gldemos/cube.c b/widget/milsko/milskosrc/examples/gldemos/cube.c new file mode 100644 index 0000000000..de0b840786 --- /dev/null +++ b/widget/milsko/milskosrc/examples/gldemos/cube.c @@ -0,0 +1,93 @@ +#define TITLE "cube" +#include "glutlayer.c" + +#if defined(__APPLE__) +#include +#include +#else +#include +#include +#endif + +static double deg = 0; + +static void draw(void) { + int i; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(deg, 1, 0, 0); + glRotatef(deg, 0, 1, 0); + glRotatef(deg, 0, 0, 1); + + for(i = 0; i < 6; i++) { + if(i == 0) + glColor3f(1, 0, 0); + if(i == 1) + glColor3f(0, 1, 0); + if(i == 2) + glColor3f(1, 1, 0); + if(i == 3) + glColor3f(0, 0, 1); + if(i == 4) + glColor3f(1, 0, 1); + if(i == 5) + glColor3f(0, 1, 1); + + glBegin(GL_QUADS); + glNormal3f(0, 1, 0); + glVertex3f(-1, 1, -1); + glVertex3f(-1, 1, 1); + glVertex3f(1, 1, 1); + glVertex3f(1, 1, -1); + glEnd(); + + if(i < 3) + glRotatef(90, 0, 0, 1); + if(i == 3) + glRotatef(90, 1, 0, 0); + if(i == 4) + glRotatef(180, 0, 0, 1); + } + glPopMatrix(); +} + +static void idle(void) { + deg += 1.0; +} + +static void reshape(int width, int height) { + GLfloat lpos[4]; + + lpos[0] = 1; + lpos[1] = 1; + lpos[2] = 1; + lpos[3] = 0; + + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60, (double)width / height, 1, 100); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(2, 2, 2, 0, 0, 0, 0, 1, 0); + + glLightfv(GL_LIGHT0, GL_POSITION, lpos); +} + +static void init(void) { + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_COLOR_MATERIAL); + glEnable(GL_CULL_FACE); + glEnable(GL_NORMALIZE); + + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); +} + +static void key(int k) { + (void)k; +} diff --git a/widget/milsko/milskosrc/examples/gldemos/gears.c b/widget/milsko/milskosrc/examples/gldemos/gears.c new file mode 100644 index 0000000000..5d06b067bf --- /dev/null +++ b/widget/milsko/milskosrc/examples/gldemos/gears.c @@ -0,0 +1,243 @@ +#define TITLE "gears" +#include "glutlayer.c" + +/* + * 3-D gear wheels. This program is in the public domain. + * + * Brian Paul + */ + +/* Conversion to GLUT by Mark J. Kilgard */ + +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265 +#endif + +/** + + Draw a gear wheel. You'll probably want to call this function when + building a display list since we do a lot of trig here. + + Input: inner_radius - radius of hole at center + outer_radius - radius at center of teeth + width - width of gear + teeth - number of teeth + tooth_depth - depth of tooth + + **/ + +static void gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) { + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth / 2.0; + r2 = outer_radius + tooth_depth / 2.0; + + da = 2.0 * M_PI / teeth / 4.0; + + glShadeModel(GL_FLAT); + + glNormal3f(0.0, 0.0, 1.0); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for(i = 0; i <= teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.0 * M_PI / teeth / 4.0; + for(i = 0; i < teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + + glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); + } + glEnd(); + + glNormal3f(0.0, 0.0, -1.0); + + /* draw back face */ + glBegin(GL_QUAD_STRIP); + for(i = 0; i <= teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); + } + glEnd(); + + /* draw back sides of teeth */ + glBegin(GL_QUADS); + da = 2.0 * M_PI / teeth / 4.0; + for(i = 0; i < teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); + } + glEnd(); + + /* draw outward faces of teeth */ + glBegin(GL_QUAD_STRIP); + for(i = 0; i < teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + + glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); + u = r2 * cos(angle + da) - r1 * cos(angle); + v = r2 * sin(angle + da) - r1 * sin(angle); + len = sqrt(u * u + v * v); + u /= len; + v /= len; + glNormal3f(v, -u, 0.0); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); + glNormal3f(cos(angle), sin(angle), 0.0); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); + u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); + v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); + glNormal3f(v, -u, 0.0); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); + glNormal3f(cos(angle), sin(angle), 0.0); + } + + glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); + glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); + + glEnd(); + + glShadeModel(GL_SMOOTH); + + /* draw inside radius cylinder */ + glBegin(GL_QUAD_STRIP); + for(i = 0; i <= teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + + glNormal3f(-cos(angle), -sin(angle), 0.0); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); + } + glEnd(); +} + +static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; +static GLint gear1, gear2, gear3; +static GLfloat angle = 0.0; + +static void draw(void) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(view_rotx, 1.0, 0.0, 0.0); + glRotatef(view_roty, 0.0, 1.0, 0.0); + glRotatef(view_rotz, 0.0, 0.0, 1.0); + + glPushMatrix(); + glTranslatef(-3.0, -2.0, 0.0); + glRotatef(angle, 0.0, 0.0, 1.0); + glCallList(gear1); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(3.1, -2.0, 0.0); + glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0); + glCallList(gear2); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-3.1, 4.2, 0.0); + glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0); + glCallList(gear3); + glPopMatrix(); + + glPopMatrix(); +} + +static void idle(void) { + angle += 2.0; +} + +/* new window size or exposure */ +static void reshape(int width, int height) { + GLfloat h = (GLfloat)height / (GLfloat)width; + + glViewport(0, 0, (GLint)width, (GLint)height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -40.0); +} + +static void init(void) { + static GLfloat pos[4] = + {5.0, 5.0, 10.0, 0.0}; + static GLfloat red[4] = + {0.8, 0.1, 0.0, 1.0}; + static GLfloat green[4] = + {0.0, 0.8, 0.2, 1.0}; + static GLfloat blue[4] = + {0.2, 0.2, 1.0, 1.0}; + + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + + /* make the gears */ + gear1 = glGenLists(1); + glNewList(gear1, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); + gear(1.0, 4.0, 1.0, 20, 0.7); + glEndList(); + + gear2 = glGenLists(1); + glNewList(gear2, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); + gear(0.5, 2.0, 2.0, 10, 0.7); + glEndList(); + + gear3 = glGenLists(1); + glNewList(gear3, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); + gear(1.3, 2.0, 0.5, 10, 0.7); + glEndList(); + + glEnable(GL_NORMALIZE); +} + +static void key(int k) { + (void)k; + + if(k == MwKEY_LEFT) { + view_roty += 5.0; + } else if(k == MwKEY_RIGHT) { + view_roty -= 5.0; + } else if(k == MwKEY_UP) { + view_rotx += 5.0; + } else if(k == MwKEY_DOWN) { + view_rotx -= 5.0; + } +} diff --git a/widget/milsko/milskosrc/examples/gldemos/glutlayer.c b/widget/milsko/milskosrc/examples/gldemos/glutlayer.c new file mode 100644 index 0000000000..8746b94008 --- /dev/null +++ b/widget/milsko/milskosrc/examples/gldemos/glutlayer.c @@ -0,0 +1,73 @@ +#include +#include + +MwWidget opengl; + +static void draw(void); +static void idle(void); +static void reshape(int width, int height); +static void init(void); +static void key(int k); + +static void MWAPI tick(MwWidget handle, void* user, void* client) { + (void)handle; + (void)user; + (void)client; + + draw(); + idle(); + + MwOpenGLSwapBuffer(opengl); +} + +static void MWAPI resize(MwWidget handle, void* user, void* client) { + int ww, wh; + + (void)user; + (void)client; + + ww = MwGetInteger(handle, MwNwidth) - 100; + wh = MwGetInteger(handle, MwNheight) - 100; + + MwVaApply(opengl, + MwNwidth, ww, + MwNheight, wh, + NULL); + + reshape(ww, wh); +} + +static void MWAPI key_pressed(MwWidget handle, void* user, void* client) { + (void)handle; + (void)user; + + key(*(int*)client); +} + +int main() { + MwWidget window; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 500, 500, + MwNtitle, TITLE, + NULL); + opengl = MwCreateWidget(MwOpenGLClass, "opengl", window, 50, 50, 400, 400); + if(!opengl) { + MwMessageBox(NULL, "Unable to create OpenGL window.", "Error", MwMB_ICONERROR); + } else { + MwOpenGLMakeCurrent(opengl); + + init(); + reshape(400, 400); + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(opengl, MwNtickHandler, tick, NULL); + + MwAddTickList(opengl); + + MwAddUserHandler(opengl, MwNkeyHandler, key_pressed, NULL); + } + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/gldemos/triangle.c b/widget/milsko/milskosrc/examples/gldemos/triangle.c new file mode 100644 index 0000000000..702fca057d --- /dev/null +++ b/widget/milsko/milskosrc/examples/gldemos/triangle.c @@ -0,0 +1,88 @@ +#include +#include + +MwWidget window, opengl, button; +int ow, oh; +double deg = 0; +double dir = 1; + +void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { + unsigned int w, h; + + (void)user_data; + (void)call_data; + + w = MwGetInteger(handle, MwNwidth); + h = MwGetInteger(handle, MwNheight); + + MwVaApply(opengl, + MwNwidth, (ow = w - 100), + MwNheight, (oh = h - 150), + NULL); + + MwVaApply(button, + MwNy, h - 50 - 50, + MwNwidth, ow, + MwNheight, 50, + NULL); +} + +void MWAPI tick(MwWidget handle, void* user_data, void* call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + MwOpenGLMakeCurrent(opengl); + + glViewport(0, 0, ow, oh); + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1, 1, -1, 1, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glPushMatrix(); + glRotatef(deg, 0, 0, 1); + glBegin(GL_TRIANGLES); + glColor3f(1, 0, 0); + glVertex2f(0, 0.8); + glColor3f(0, 1, 0); + glVertex2f(-0.8, -0.8); + glColor3f(0, 0, 1); + glVertex2f(0.8, -0.8); + glEnd(); + glPopMatrix(); + + MwOpenGLSwapBuffer(opengl); + + deg += 120.0 / (1000.0 / MwWaitMS) * dir; +} + +void MWAPI activate(MwWidget handle, void* user_data, void* call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + dir = dir == 1 ? -1 : 1; +} + +int main() { + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 450, + MwNtitle, "hello world", + NULL); + opengl = MwCreateWidget(MwOpenGLClass, "opengl", window, 50, 50, (ow = 300), (oh = 300)); + button = MwVaCreateWidget(MwButtonClass, "button", window, 50, 350, 300, 50, + MwNtext, "Reverse", + NULL); + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(window, MwNtickHandler, tick, NULL); + MwAddUserHandler(button, MwNactivateHandler, activate, NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/gldemos/tripaint.c b/widget/milsko/milskosrc/examples/gldemos/tripaint.c new file mode 100644 index 0000000000..11eaffd50b --- /dev/null +++ b/widget/milsko/milskosrc/examples/gldemos/tripaint.c @@ -0,0 +1,138 @@ +#include +#include + +#include + +MwWidget opengl; + +typedef struct triangle { + int points[3 * 2]; + double r; + double g; + double b; +} triangle_t; + +triangle_t* t = NULL; +int ct = 0; +int click = 0; +int mx, my; + +static void MWAPI tick(MwWidget handle, void* user, void* call) { + int i; + int w = MwGetInteger(opengl, MwNwidth); + int h = MwGetInteger(opengl, MwNheight); + + (void)handle; + (void)user; + (void)call; + + MwOpenGLMakeCurrent(opengl); + + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, w, h, 0, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + for(i = 0; i < ct + (click == 2 ? 1 : 0); i++) { + int j; + glBegin(GL_TRIANGLES); + glColor3d(t[i].r, t[i].g, t[i].b); + for(j = 0; j < 3; j++) { + glVertex2d(t[i].points[j * 2 + 0], t[i].points[j * 2 + 1]); + } + glEnd(); + } + + MwOpenGLSwapBuffer(opengl); +} + +static void MWAPI mouse(MwWidget handle, void* user, void* call) { + MwMouse* mouse = call; + + (void)handle; + (void)user; + + if(mouse->button == MwMOUSE_LEFT) { + t[ct].points[click * 2 + 0] = mouse->point.x; + t[ct].points[click * 2 + 1] = mouse->point.y; + click++; + if(click == 1) { + t[ct].r = rand() % 65536; + t[ct].g = rand() % 65536; + t[ct].b = rand() % 65536; + + t[ct].r /= 65535; + t[ct].g /= 65535; + t[ct].b /= 65535; + } else if(click == 2) { + t[ct].points[2 * 2 + 0] = mx; + t[ct].points[2 * 2 + 1] = my; + } else if(click == 3) { + triangle_t* old = t; + int i; + + click = 0; + ct++; + + t = malloc(sizeof(*t) * (ct + 1)); + for(i = 0; i < ct; i++) t[i] = old[i]; + free(old); + } + } else if(mouse->button == MwMOUSE_RIGHT) { + if(click > 0) { + click = 0; + } else if(ct > 0) { + ct--; + } + } +} + +static void MWAPI mouse_move(MwWidget handle, void* user, void* call) { + MwPoint* point = call; + + (void)handle; + (void)user; + + mx = point->x; + my = point->y; + + if(click == 2) { + t[ct].points[2 * 2 + 0] = point->x; + t[ct].points[2 * 2 + 1] = point->y; + } +} + +int main() { + MwSizeHints hints; + MwWidget window, viewport; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, + MwNtitle, "tripaint", + NULL); + viewport = MwCreateWidget(MwViewportClass, "viewport", window, 5, 5, 630, 470 - 16 - 5); + + hints.min_width = hints.max_width = 640; + hints.min_height = hints.max_height = 480; + MwVaApply(window, MwNsizeHints, &hints, NULL); + + MwVaCreateWidget(MwLabelClass, "label", window, 5, 470 - 16 + 5, 630, 16, + MwNtext, "Press left click to draw triangle, right click to undo", + NULL); + + t = malloc(sizeof(*t)); + + opengl = MwCreateWidget(MwOpenGLClass, "opengl", viewport, 0, 0, 1024, 768); + + MwAddUserHandler(window, MwNtickHandler, tick, NULL); + MwAddUserHandler(opengl, MwNtickHandler, tick, NULL); + MwAddUserHandler(opengl, MwNmouseDownHandler, mouse, NULL); + MwAddUserHandler(opengl, MwNmouseMoveHandler, mouse_move, NULL); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/examples/harvard.c b/widget/milsko/milskosrc/examples/harvard.c new file mode 100644 index 0000000000..af5da28dae --- /dev/null +++ b/widget/milsko/milskosrc/examples/harvard.c @@ -0,0 +1,722 @@ +const char* harvard[] = { + "The birch canoe slid on the smooth planks. ", + "Glue the sheet to the dark blue background.", + "It's easy to tell the depth of a well. ", + "These days a chicken leg is a rare dish. ", + "Rice is often served in round bowls.", + "The juice of lemons makes fine punch. ", + "The box was thrown beside the parked truck. ", + "The hogs were fed chopped corn and garbage. ", + "Four hours of steady work faced us. ", + "A large size in stockings is hard to sell. ", + "The boy was there when the sun rose.", + "A rod is used to catch pink salmon. ", + "The source of the huge river is the clear spring. ", + "Kick the ball straight and follow through.", + "Help the woman get back to her feet. ", + "A pot of tea helps to pass the evening. ", + "Smoky fires lack flame and heat. ", + "The soft cushion broke the man's fall. ", + "The salt breeze came across from the sea. ", + "The girl at the booth sold fifty bonds. ", + "The small pup gnawed a hole in the sock. ", + "The fish twisted and turned on the bent hook. ", + "Press the pants and sew a button on the vest. ", + "The swan dive was far short of perfect. ", + "The beauty of the view stunned the young boy. ", + "Two blue fish swam in the tank. ", + "Her purse was full of useless trash. ", + "The colt reared and threw the tall rider. ", + "It snowed, rained, and hailed the same morning. ", + "Read verse out loud for pleasure.", + "Hoist the load to your left shoulder. ", + "Take the winding path to reach the lake. ", + "Note closely the size of the gas tank. ", + "Wipe the grease off his dirty face. ", + "Mend the coat before you go out. ", + "The wrist was badly strained and hung limp. ", + "The stray cat gave birth to kittens. ", + "The young girl gave no clear response. ", + "The meal was cooked before the bell rang.", + "What joy there is in living. ", + "A king ruled the state in the early days. ", + "The ship was torn apart on the sharp reef. ", + "Sickness kept him home the third week. ", + "The wide road shimmered in the hot sun. ", + "The lazy cow lay in the cool grass. ", + "Lift the square stone over the fence. ", + "The rope will bind the seven books at once. ", + "Hop over the fence and plunge in. ", + "The friendly gang left the drug store. ", + "Mesh wire keeps chicks inside. ", + "The frosty air passed through the coat. ", + "The crooked maze failed to fool the mouse. ", + "Adding fast leads to wrong sums. ", + "The show was a flop from the very start. ", + "A saw is a tool used for making boards.", + "The wagon moved on well oiled wheels.", + "March the soldiers past the next hill. ", + "A cup of sugar makes sweet fudge. ", + "Place a rosebush near the porch steps. ", + "Both lost their lives in the raging storm. ", + "We talked of the side show in the circus.", + "Use a pencil to write the first draft.", + "He ran half way to the hardware store. ", + "The clock struck to mark the third period.", + "A small creek cut across the field.", + "Cars and busses stalled in snow drifts.", + "The set of china hit the floor with a crash. ", + "This is a grand season for hikes on the road.", + "The dune rose from the edge of the water. ", + "Those words were the cue for the actor to leave.", + "A yacht slid around the point into the bay.", + "The two met while playing on the sand.", + "The ink stain dried on the finished page.", + "The walled town was seized without a fight. ", + "The lease ran out in sixteen weeks. ", + "A tame squirrel makes a nice pet. ", + "The horn of the car woke the sleeping cop. ", + "The heart beat strongly and with firm strokes. ", + "The pearl was worn in a thin silver ring. ", + "The fruit peel was cut in thick slices.", + "The Navy attacked the big task force.", + "See the cat glaring at the scared mouse. ", + "There are more than two factors here.", + "The hat brim was wide and too droopy.", + "The lawyer tried to lose his case.", + "The grass curled around the fence post.", + "Cut the pie into large parts.", + "Men strive but seldom get rich. ", + "Always close the barn door tight.", + "He lay prone and hardly moved a limb.", + "The slush lay deep along the street. ", + "A wisp of cloud hung in the blue air. ", + "A pound of sugar costs more than eggs.", + "The fin was sharp and cut the clear water.", + "The play seems dull and quite stupid.", + "Bail the boat to stop it from sinking.", + "The term ended in late june that year.", + "A Tusk is used to make costly gifts.", + "Ten pins were set in order.", + "The bill was paid every third week.", + "Oak is strong and also gives shade.", + "Cats and Dogs each hate the other.", + "The pipe began to rust while new.", + "Open the crate but don't break the glass.", + "Add the sum to the product of these three.", + "Thieves who rob friends deserve jail.", + "The ripe taste of cheese improves with age.", + "Act on these orders with great speed.", + "The hog crawled under the high fence.", + "Move the vat over the hot fire.", + "The bark of the pine tree was shiny and dark.", + "Leaves turn brown and yellow in the fall. ", + "The pennant waved when the wind blew.", + "Split the log with a quick, sharp blow.", + "Burn peat after the logs give out.", + "He ordered peach pie with ice cream.", + "Weave the carpet on the right hand side.", + "Hemp is a weed found in parts of the tropics.", + "A lame back kept his score low.", + "We find joy in the simplest things.", + "Type out three lists of orders.", + "The harder he tried the less he got done.", + "The boss ran the show with a watchful eye.", + "The cup cracked and spilled its contents.", + "Paste can cleanse the most dirty brass.", + "The slang word for raw whiskey is booze.", + "It caught its hind paw in a rusty trap.", + "The wharf could be seen at the farther shore.", + "Feel the heat of the weak dying flame.", + "The tiny girl took off her hat.", + "A cramp is no small danger on a swim.", + "He said the same phrase thirty times.", + "Pluck the bright rose without leaves.", + "Two plus seven is less than ten.", + "The glow deepened in the eyes of the sweet girl.", + "Bring your problems to the wise chief.", + "Write a fond note to the friend you cherish.", + "Clothes and lodging are free to new men.", + "We frown when events take a bad turn.", + "Port is a strong wine with a smoky taste.", + "The young kid jumped the rusty gate.", + "Guess the result from the first scores. ", + "A salt pickle tastes fine with ham.", + "The just claim got the right verdict.", + "Those thistles bend in a high wind.", + "Pure bred poodles have curls.", + "The tree top waved in a graceful way. ", + "The spot on the blotter was made by green ink. ", + "Mud was spattered on the front of his white shirt.", + "The cigar burned a hole in the desk top. ", + "The empty flask stood on the tin tray.", + "A speedy man can beat this track mark. ", + "He broke a new shoelace that day.", + "The coffee stand is too high for the couch. ", + "The urge to write short stories is rare. ", + "The pencils have all been used.", + "The pirates seized the crew of the lost ship.", + "We tried to replace the coin but failed. ", + "She sewed the torn coat quite neatly. ", + "The sofa cushion is red and of light weight.", + "The jacket hung on the back of the wide chair.", + "At that high level the air is pure.", + "Drop the two when you add the figures.", + "A filing case is now hard to buy.", + "An abrupt start does not win the prize. ", + "Wood is best for making toys and blocks.", + "The office paint was a dull, sad tan.", + "He knew the skill of the great young actress.", + "A rag will soak up spilled water.", + "A shower of dirt fell from the hot pipes.", + "Steam hissed from the broken valve. ", + "The child almost hurt the small dog.", + "There was a sound of dry leaves outside.", + "The sky that morning was clear and bright blue.", + "Torn scraps littered the stone floor.", + "Sunday is the best part of the week. ", + "The doctor cured him with these pills.", + "The new girl was fired today at noon.", + "They felt gay when the ship arrived in port.", + "Add the store's account to the last cent.", + "Acid burns holes in wool cloth.", + "Fairy tales should be fun to write.", + "Eight miles of woodland burned to waste.", + "The third act was dull and tired the players.", + "A young child should not suffer fright.", + "Add the column and put the sum here.", + "We admire and love a good cook.", + "There the flood mark is ten inches.", + "He carved a head from the round block of marble.", + "She has a smart way of wearing clothes.", + "The fruit of a fig tree is apple shaped.", + "Corn cobs can be used to kindle a fire. ", + "Where were they when the noise started.", + "The paper box is full of thumb tacks.", + "Sell your gift to a buyer at a good gain.", + "The tongs lay beside the ice pail.", + "The petals fall with the next puff of wind.", + "Bring your best compass to the third class.", + "They could laugh although they were sad.", + "Farmers came in to thresh the oat crop.", + "The brown house was on fire to the attic.", + "The lure is used to catch trout and flounder.", + "Float the soap on top of the bath water.", + "A blue crane is a tall wading bird.", + "A fresh start will work such wonders.", + "The club rented the rink for the fifth night.", + "After the dance, they went straight home.", + "The hostess taught the new maid to serve.", + "He wrote his last novel there at the inn.", + "Even the worst will beat his low score.", + "The cement had dried when he moved it.", + "The loss of the second ship was hard to take.", + "The fly made its way along the wall.", + "Do that with a wooden stick.", + "Live wires should be kept covered.", + "The large house had hot water taps.", + "It is hard to erase blue or red ink.", + "Write at once or you may forget it.", + "The doorknob was made of bright clean brass.", + "The wreck occurred by the bank on Main Street.", + "A pencil with black lead writes best.", + "Coax a young calf to drink from a bucket.", + "Schools for ladies teach charm and grace.", + "The lamp shone with a steady green flame.", + "They took the axe and the saw to the forest.", + "The ancient coin was quite dull and worn.", + "The shaky barn fell with a loud crash. ", + "Jazz and swing fans like fast music.", + "Rake the rubbish up and then burn it.", + "Slash the gold cloth into fine ribbons.", + "Try to have the court decide the case.", + "They are pushed back each time they attack.", + "He broke his ties with groups of former friends.", + "They floated on the raft to sun their white backs.", + "The map had an X that meant nothing.", + "Whitings are small fish caught in nets.", + "Some ads serve to cheat buyers.", + "Jerk the rope and the bell rings weakly.", + "A waxed floor makes us lose balance.", + "Madam, this is the best brand of corn.", + "On the islands the sea breeze is soft and mild.", + "The play began as soon as we sat down.", + "This will lead the world to more sound and fury.", + "Add salt before you fry the egg.", + "The rush for funds reached its peak Tuesday.", + "The birch looked stark white and lonesome.", + "The box is held by a bright red snapper.", + "To make pure ice, you freeze water.", + "The first worm gets snapped early.", + "Jump the fence and hurry up the bank.", + "Yell and clap as the curtain slides back.", + "They are men who walk the middle of the road.", + "Both brothers wear the same size.", + "In some form or other we need fun.", + "The prince ordered his head chopped off.", + "The houses are built of red clay bricks.", + "Ducks fly north but lack a compass.", + "Fruit flavors are used in fizz drinks.", + "These pills do less good than others.", + "Canned pears lack full flavor.", + "The dark pot hung in the front closet.", + "Carry the pail to the wall and spill it there.", + "The train brought our hero to the big town.", + "We are sure that one war is enough.", + "Gray paint stretched for miles around.", + "The rude laugh filled the empty room.", + "High seats are best for football fans.", + "Tea served from the brown jug is tasty.", + "A dash of pepper spoils beef stew.", + "A zestful food is the hot-cross bun.", + "The horse trotted around the field at a brisk pace.", + "Find the twin who stole the pearl necklace.", + "Cut the cord that binds the box tightly.", + "The red tape bound the smuggled food.", + "Look in the corner to find the tan shirt.", + "The cold drizzle will halt the bond drive.", + "Nine men were hired to dig the ruins.", + "The junk yard had a mouldy smell.", + "The flint sputtered and lit a pine torch.", + "Soak the cloth and drown the sharp odor.", + "The shelves were bare of both jam or crackers.", + "A joy to every child is the swan boat.", + "All sat frozen and watched the screen.", + "A cloud of dust stung his tender eyes.", + "To reach the end he needs much courage.", + "Shape the clay gently into block form.", + "A ridge on a smooth surface is a bump or flaw.", + "Hedge apples may stain your hands green.", + "Quench your thirst, then eat the crackers.", + "Tight curls get limp on rainy days.", + "The mute muffled the high tones of the horn.", + "The gold ring fits only a pierced ear.", + "The old pan was covered with hard fudge.", + "Watch the log float in the wide river.", + "The node on the stalk of wheat grew daily.", + "The heap of fallen leaves was set on fire.", + "Write fast if you want to finish early.", + "His shirt was clean but one button was gone.", + "The barrel of beer was a brew of malt and hops.", + "Tin cans are absent from store shelves.", + "Slide the box into that empty space.", + "The plant grew large and green in the window.", + "The beam dropped down on the workman's head.", + "Pink clouds floated with the breeze.", + "She danced like a swan, tall and graceful.", + "The tube was blown and the tire flat and useless.", + "It is late morning on the old wall clock.", + "Let's all join as we sing the last chorus.", + "The last switch cannot be turned off.", + "The fight will end in just six minutes.", + "The store walls were lined with colored frocks.", + "The peace league met to discuss their plans. ", + "The rise to fame of a person takes luck.", + "Paper is scarce, so write with much care.", + "The quick fox jumped on the sleeping cat.", + "The nozzle of the fire hose was bright brass.", + "Screw the round cap on as tight as needed.", + "Time brings us many changes.", + "The purple tie was ten years old.", + "Men think and plan and sometimes act.", + "Fill the ink jar with sticky glue.", + "He smoke a big pipe with strong contents.", + "We need grain to keep our mules healthy.", + "Pack the records in a neat thin case.", + "The crunch of feet in the snow was the only sound.", + "The copper bowl shone in the sun's rays.", + "Boards will warp unless kept dry. ", + "The plush chair leaned against the wall. ", + "Glass will clink when struck by metal.", + "Bathe and relax in the cool green grass.", + "Nine rows of soldiers stood in a line.", + "The beach is dry and shallow at low tide.", + "The idea is to sew both edges straight.", + "The kitten chased the dog down the street.", + "Pages bound in cloth make a book.", + "Try to trace the fine lines of the painting.", + "Women form less than half of the group. ", + "The zones merge in the central part of town.", + "A gem in the rough needs work to polish.", + "Code is used when secrets are sent.", + "Most of the news is easy for us to hear.", + "He used the lathe to make brass objects.", + "The vane on top of the pole revolved in the wind.", + "Mince pie is a dish served to children.", + "The clan gathered on each dull night.", + "Let it burn, it gives us warmth and comfort.", + "A castle built from sand fails to endure.", + "A child's wit saved the day for us.", + "Tack the strip of carpet to the worn floor.", + "Next Tuesday we must vote.", + "Pour the stew from the pot into the plate.", + "Each penny shone like new.", + "The man went to the woods to gather sticks.", + "The dirt piles were lines along the road.", + "The logs fell and tumbled into the clear stream.", + "Just hoist it up and take it away.", + "A ripe plum is fit for a king's palate.", + "Our plans right now are hazy. ", + "Brass rings are sold by these natives.", + "It takes a good trap to capture a bear.", + "Feed the white mouse some flower seeds.", + "The thaw came early and freed the stream.", + "He took the lead and kept it the whole distance.", + "The key you designed will fit the lock.", + "Plead to the council to free the poor thief.", + "Better hash is made of rare beef.", + "This plank was made for walking on .", + "The lake sparkled in the red hot sun.", + "He crawled with care along the ledge.", + "Tend the sheep while the dog wanders.", + "It takes a lot of help to finish these.", + "Mark the spot with a sign painted red.", + "Take two shares as a fair profit. ", + "The fur of cats goes by many names.", + "North winds bring colds and fevers.", + "He asks no person to vouch for him.", + "Go now and come here later.", + "A sash of gold silk will trim her dress.", + "Soap can wash most dirt away.", + "That move means the game is over.", + "He wrote down a long list of items.", + "A siege will crack the strong defense.", + "Grape juice and water mix well.", + "Roads are paved with sticky tar.", + "Fake stones shine but cost little.", + "The drip of the rain made a pleasant sound. ", + "Smoke poured out of every crack. ", + "Serve the hot rum to the tired heroes.", + "Much of the story makes good sense. ", + "The sun came up to light the eastern sky.", + "Heave the line over the port side.", + "A lathe cuts and trims any wood.", + "It's a dense crowd in two distinct ways.", + "His hip struck the knee of the next player.", + "The stale smell of old beer lingers.", + "The desk was firm on the shaky floor.", + "It takes heat to bring out the odor.", + "Beef is scarcer than some lamb.", + "Raise the sail and steer the ship northward.", + "A cone costs five cents on Mondays.", + "A pod is what peas always grow in.", + "Jerk that dart from the cork target.", + "No cement will hold hard wood.", + "We now have a new base for shipping.", + "A list of names is carved around the base.", + "The sheep were led home by a dog.", + "Three for a dime, the young peddler cried.", + "The sense of smell is better than that of touch.", + "No hardship seemed to make him sad.", + "Grace makes up for lack of beauty.", + "Nudge gently but wake her now.", + "The news struck doubt into restless minds.", + "Once we stood beside the shore.", + "A chink in the wall allowed a draft to blow.", + "Fasten two pins on each side.", + "A cold dip restores health and zest.", + "He takes the oath of office each March.", + "The sand drifts over the sills of the old house.", + "The point of the steel pen was bent and twisted.", + "There is a lag between thought and act.", + "Seed is needed to plant the spring corn.", + "Draw the chart with heavy black lines.", + "The boy owed his pal thirty cents.", + "The chap slipped into the crowd and was lost.", + "Hats are worn to tea and not to dinner.", + "The ramp led up to the wide highway.", + "Beat the dust from the rug onto the lawn.", + "Say it slowly but make it ring clear.", + "The straw nest housed five robins.", + "Screen the porch with woven straw mats.", + "This horse will nose his way to the finish.", + "The dry wax protects the deep scratch.", + "He picked up the dice for a second roll.", + "These coins will be needed to pay his debt.", + "The nag pulled the frail cart along.", + "Twist the valve and release hot steam.", + "The vamp of the shoe had a gold buckle.", + "The smell of burned rags itches my nose.", + "New pants lack cuffs and pockets.", + "The marsh will freeze when cold enough.", + "They slice the sausage thin with a knife.", + "The bloom of the rose lasts a few days.", + "A gray mare walked before the colt.", + "Breakfast buns are fine with a hot drink.", + "Bottles hold four kinds of rum.", + "The man wore a feather in his felt hat.", + "He wheeled the bike past the winding road.", + "Drop the ashes on the worn old rug.", + "The desk and both chairs were painted tan.", + "Throw out the used paper cup and plate.", + "A clean neck means a neat collar.", + "The couch cover and hall drapes were blue.", + "The stems of the tall glasses cracked and broke.", + "The wall phone rang loud and often.", + "The clothes dried on a thin wooden rack.", + "Turn out the lantern which gives us light.", + "The cleat sank deeply into the soft turf.", + "The bills were mailed promptly on the tenth of the month.", + "To have is better than to wait and hope.", + "The price is fair for a good antique clock.", + "The music played on while they talked.", + "Dispense with a vest on a day like this.", + "The bunch of grapes was pressed into wine.", + "He sent the figs, but kept the ripe cherries.", + "The hinge on the door creaked with old age.", + "The screen before the fire kept in the sparks.", + "Fly by night and you waste little time.", + "Thick glasses helped him read the print.", + "Birth and death marks the limits of life.", + "The chair looked strong but had no bottom.", + "The kite flew wildly in the high wind.", + "A fur muff is stylish once more.", + "The tin box held priceless stones.", + "We need an end of all such matter.", + "The case was puzzling to the old and wise.", + "The bright lanterns were gay on the dark lawn.", + "We don't get much money but we have fun.", + "The youth drove with zest, but little skill.", + "Five years he lived with a shaggy dog.", + "A fence cuts through the corner lot.", + "The way to save money is not to spend much.", + "Shut the hatch before the waves push it in.", + "The odor of spring makes young hearts jump.", + "Crack the walnut with your sharp side teeth.", + "He offered proof in the form of a large chart.", + "Send the stuff in a thick paper bag.", + "A quart of milk is water for the most part.", + "They told wild tales to frighten him.", + "The three story house was built of stone.", + "In the rear of the ground floor was a large passage.", + "A man in a blue sweater sat at the desk.", + "Oats are a food eaten by horse and man.", + "Their eyelids droop for want of sleep.", + "A sip of tea revives his tired friend.", + "There are many ways to do these things.", + "Tuck the sheet under the edge of the mat.", + "A force equal to that would move the earth.", + "We like to see clear weather.", + "The work of the tailor is seen on each side.", + "Take a chance and win a china doll.", + "Shake the dust from your shoes, stranger.", + "She was kind to sick old people.", + "The square wooden crate was packed to be shipped.", + "The dusty bench stood by the stone wall.", + "We dress to suit the weather of most days.", + "Smile when you say nasty words.", + "A bowl of rice is free with chicken stew.", + "The water in this well is a source of good health.", + "Take shelter in this tent, but keep still.", + "That guy is the writer of a few banned books.", + "The little tales they tell are false.", + "The door was barred, locked, and bolted as well.", + "Ripe pears are fit for a queen's table.", + "A big wet stain was on the round carpet.", + "The kite dipped and swayed, but stayed aloft.", + "The pleasant hours fly by much too soon.", + "The room was crowded with a wild mob.", + "This strong arm shall shield your honor.", + "She blushed when he gave her a white orchid.", + "The beetle droned in the hot June sun.", + "Press the pedal with your left foot.", + "Neat plans fail without luck.", + "The black trunk fell from the landing.", + "The bank pressed for payment of the debt.", + "The theft of the pearl pin was kept secret.", + "Shake hands with this friendly child.", + "The vast space stretched into the far distance.", + "A rich farm is rare in this sandy waste.", + "His wide grin earned many friends.", + "Flax makes a fine brand of paper.", + "Hurdle the pit with the aid of a long pole.", + "A strong bid may scare your partner stiff.", + "Even a just cause needs power to win.", + "Peep under the tent and see the clowns.", + "The leaf drifts along with a slow spin.", + "Cheap clothes are flashy but don't last.", + "A thing of small note can cause despair.", + "Flood the mails with requests for this book.", + "A thick coat of black paint covered all.", + "The pencil was cut to be sharp at both ends.", + "Those last words were a strong statement.", + "He wrote his name boldly at the top of the sheet.", + "Dill pickles are sour but taste fine.", + "Down that road is the way to the grain farmer.", + "Either mud or dust are found at all times.", + "The best method is to fix it in place with clips.", + "If you mumble your speech will be lost.", + "At night the alarm roused him from a deep sleep.", + "Read just what the meter says.", + "Fill your pack with bright trinkets for the poor.", + "The small red neon lamp went out.", + "Clams are small, round, soft, and tasty.", + "The fan whirled its round blades softly.", + "The line where the edges join was clean.", + "Breathe deep and smell the piny air.", + "It matters not if he reads these words or those.", + "A brown leather bag hung from its strap.", + "A toad and a frog are hard to tell apart.", + "A white silk jacket goes with any shoes.", + "A break in the dam almost caused a flood.", + "Paint the sockets in the wall dull green.", + "The child crawled into the dense grass.", + "Bribes fail where honest men work.", + "Trample the spark, else the flames will spread.", + "The hilt of the sword was carved with fine designs.", + "A round hole was drilled through the thin board.", + "Footprints showed the path he took up the beach.", + "She was waiting at my front lawn.", + "A vent near the edge brought in fresh air.", + "Prod the old mule with a crooked stick.", + "It is a band of steel three inches wide.", + "The pipe ran almost the length of the ditch.", + "It was hidden from sight by a mass of leaves and shrubs.", + "The weight of the package was seen on the high scale.", + "Wake and rise, and step into the green outdoors.", + "The green light in the brown box flickered.", + "The brass tube circled the high wall.", + "The lobes of her ears were pierced to hold rings.", + "Hold the hammer near the end to drive the nail.", + "Next Sunday is the twelfth of the month.", + "Every word and phrase he speaks is true.", + "He put his last cartridge into the gun and fired.", + "They took their kids from the public school.", + "Drive the screw straight into the wood.", + "Keep the hatch tight and the watch constant.", + "Sever the twine with a quick snip of the knife.", + "Paper will dry out when wet.", + "Slide the catch back and open the desk.", + "Help the weak to preserve their strength.", + "A sullen smile gets few friends.", + "Stop whistling and watch the boys march.", + "Jerk the cord, and out tumbles the gold.", + "Slide the tray across the glass top.", + "The cloud moved in a stately way and was gone.", + "Light maple makes for a swell room.", + "Set the piece here and say nothing.", + "Dull stories make her laugh.", + "A stiff cord will do to fasten your shoe.", + "Get the trust fund to the bank early.", + "Choose between the high road and the low.", + "A plea for funds seems to come again.", + "He lent his coat to the tall gaunt stranger.", + "There is a strong chance it will happen once more.", + "The duke left the park in a silver coach.", + "Greet the new guests and leave quickly.", + "When the frost has come it is time for turkey.", + "Sweet words work better than fierce.", + "A thin stripe runs down the middle.", + "A six comes up more often than a ten.", + "Lush ferns grow on the lofty rocks.", + "The ram scared the school children off.", + "The team with the best timing looks good.", + "The farmer swapped his horse for a brown ox.", + "Sit on the perch and tell the others what to do.", + "A steep trail is painful for our feet.", + "The early phase of life moves fast.", + "Green moss grows on the northern side.", + "Tea in thin china has a sweet taste.", + "Pitch the straw through the door of the stable.", + "The latch on the back gate needed a nail.", + "The goose was brought straight from the old market.", + "The sink is the thing in which we pile dishes.", + "A whiff of it will cure the most stubborn cold.", + "The facts don't always show who is right.", + "She flaps her cape as she parades the street.", + "The loss of the cruiser was a blow to the fleet.", + "Loop the braid to the left and then over.", + "Plead with the lawyer to drop the lost cause.", + "Calves thrive on tender spring grass.", + "Post no bills on this office wall.", + "Tear a thin sheet from the yellow pad.", + "A cruise in warm waters in a sleek yacht is fun.", + "A streak of color ran down the left edge.", + "It was done before the boy could see it.", + "Crouch before you jump or miss the mark.", + "Pack the kits and don't forget the salt.", + "The square peg will settle in the round hole.", + "Fine soap saves tender skin.", + "Poached eggs and tea must suffice.", + "Bad nerves are jangled by a door slam.", + "Ship maps are different from those for planes.", + "Dimes showered down from all sides.", + "They sang the same tunes at each party.", + "The sky in the west is tinged with orange red.", + "The pods of peas ferment in bare fields.", + "The horse balked and threw the tall rider.", + "The hitch between the horse and cart broke.", + "Pile the coal high in the shed corner.", + "A gold vase is both rare and costly.", + "The knife was hung inside its bright sheath.", + "The rarest spice comes from the far East.", + "The roof should be tilted at a sharp slant.", + "A smatter of French is worse than none.", + "The mule trod the treadmill day and night.", + "The aim of the contest is to raise a great fund.", + "To send it now in large amounts is bad.", + "There is a fine hard tang in salty air.", + "Cod is the main business of the north shore.", + "The slab was hewn from heavy blocks of slate.", + "Dunk the stale biscuits into strong drink.", + "Hang tinsel from both branches.", + "Cap the jar with a tight brass cover.", + "The poor boy missed the boat again.", + "Be sure to set that lamp firmly in the hole.", + "Pick a card and slip it under the pack.", + "A round mat will cover the dull spot.", + "The first part of the plan needs changing.", + "A good book informs of what we ought to know.", + "The mail comes in three batches per day.", + "You cannot brew tea in a cold pot.", + "Dots of light betrayed the black cat.", + "Put the chart on the mantel and tack it down.", + "The night shift men rate extra pay.", + "The red paper brightened the dim stage.", + "See the player scoot to third base.", + "Slide the bill between the two leaves.", + "Many hands help get the job done.", + "We don't like to admit our small faults.", + "No doubt about the way the wind blows.", + "Dig deep in the earth for pirate's gold.", + "The steady drip is worse than a drenching rain.", + "A flat pack takes less luggage space.", + "Green ice frosted the punch bowl.", + "A stuffed chair slipped from the moving van.", + "The stitch will serve but needs to be shortened.", + "A thin book fits in the side pocket.", + "The gloss on top made it unfit to read.", + "The hail pattered on the burnt brown grass.", + "Seven seals were stamped on great sheets.", + "Our troops are set to strike heavy blows.", + "The store was jammed before the sale could start.", + "It was a bad error on the part of the new judge.", + "One step more and the board will collapse.", + "Take the match and strike it against your shoe.", + "The pot boiled but the contents failed to jell.", + "The baby puts his right foot in his mouth.", + "The bombs left most of the town in ruins.", + "Stop and stare at the hard working man.", + "The streets are narrow and full of sharp turns.", + "The pup jerked the leash as he saw a feline shape.", + "Open your book to the first page.", + "Fish evade the net and swim off.", + "Dip the pail once and let it settle.", + "Will you please answer that phone.", + "The big red apple fell to the ground.", + "The curtain rose and the show was on.", + "The young prince became heir to the throne.", + "He sent the boy on a short errand.", + "Leave now and you will arrive on time.", + "The corner store was robbed last night.", + "A gold ring will please most any girl.", + "The long journey home took a year.", + "She saw a cat in the neighbor's house.", + "A pink shell was found on the sandy beach.", + "Small children came to see him.", + "The grass and bushes were wet with dew.", + "The blind man counted his old coins.", + "A severe storm tore down the barn.", + "She called his name many times.", + "When you hear the bell, come quickly.", + NULL}; diff --git a/widget/milsko/milskosrc/examples/picture.jpg b/widget/milsko/milskosrc/examples/picture.jpg new file mode 100644 index 0000000000..7c664079cb Binary files /dev/null and b/widget/milsko/milskosrc/examples/picture.jpg differ diff --git a/widget/milsko/milskosrc/examples/picture.png b/widget/milsko/milskosrc/examples/picture.png new file mode 100644 index 0000000000..01b9e45479 Binary files /dev/null and b/widget/milsko/milskosrc/examples/picture.png differ diff --git a/widget/milsko/milskosrc/examples/vkdemos/CMakeLists.txt b/widget/milsko/milskosrc/examples/vkdemos/CMakeLists.txt new file mode 100644 index 0000000000..9f37e0f711 --- /dev/null +++ b/widget/milsko/milskosrc/examples/vkdemos/CMakeLists.txt @@ -0,0 +1,30 @@ +file( + GLOB + EXAMPLES_VULKAN_SOURCES + *.c +) +find_package(Vulkan) + +if(${Vulkan_FOUND}) + foreach(PATH IN LISTS EXAMPLES_VULKAN_SOURCES) + get_filename_component(TARGET ${PATH} NAME_WE) + add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) + target_include_directories( + ${TARGET} + PRIVATE + ${Vulkan_INCLUDE_DIR} + ) + target_link_libraries( + ${TARGET} + PRIVATE + Mw + ) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_libraries( + ${TARGET} + PRIVATE + m + ) + endif() + endforeach() +endif() diff --git a/widget/milsko/milskosrc/examples/vkdemos/triangle.frag.spv b/widget/milsko/milskosrc/examples/vkdemos/triangle.frag.spv new file mode 100644 index 0000000000..a664e83b28 Binary files /dev/null and b/widget/milsko/milskosrc/examples/vkdemos/triangle.frag.spv differ diff --git a/widget/milsko/milskosrc/examples/vkdemos/triangle.vert.spv b/widget/milsko/milskosrc/examples/vkdemos/triangle.vert.spv new file mode 100644 index 0000000000..0855f65644 Binary files /dev/null and b/widget/milsko/milskosrc/examples/vkdemos/triangle.vert.spv differ diff --git a/widget/milsko/milskosrc/examples/vkdemos/vulkan.c b/widget/milsko/milskosrc/examples/vkdemos/vulkan.c new file mode 100644 index 0000000000..9060a970f3 --- /dev/null +++ b/widget/milsko/milskosrc/examples/vkdemos/vulkan.c @@ -0,0 +1,629 @@ +#include +#include + +#include +#include +#ifdef HAS_VK_ENUM_STRING_HELPER +#include +#else +char buffer[512]; + +char* string_VkResult(VkResult res) { + MwStringPrintIntoBuffer(buffer, 512, "%d", res); + + return &buffer[0]; +} +#endif + +MwWidget window, vulkan; +int ow = 300; +int oh = 250; + +double timer = 0; + +PFN_vkGetInstanceProcAddr _vkGetInstanceProcAddr; +VkInstance instance; +VkDevice device; +VkPhysicalDevice physicalDevice; +VkSurfaceKHR surface; +VkQueue graphicsQueue; +VkQueue presentQueue; +uint32_t* graphicsQueueIndex; +uint32_t* presentQueueIndex; + +VkSwapchainKHR swapchain; +VkImage* swapchainImages; +VkImageView* swapchainImageView; +uint32_t swapchainImageViewCount; +uint32_t currentImageIndex; +uint32_t frameNumber; + +VkFence* fences; +VkSemaphore* renderFinishedSemaphores; +VkSemaphore* imageAvaliableSemaphores; + +VkFramebuffer* framebuffers; + +VkPipeline pipeline; +VkCommandBuffer* cmdBuffers; +VkRenderPass renderPass; + +VkResult res; + +VkSwapchainCreateInfoKHR swapchainCreateInfo = {}; + +#define MAX_FRAMES_IN_FLIGHT swapchainImageViewCount + +// convienence macro for loading a vulkan function pointer into memory +#define LOAD_VK_FUNCTION(name) \ + PFN_##name _##name = (PFN_##name)_vkGetInstanceProcAddr(instance, #name); \ + assert(_##name); + +void MWAPI tick(MwWidget handle, void* user_data, void* call_data) { + (void)handle; + (void)user_data; + (void)call_data; + + VkCommandBufferBeginInfo beginInfo = {}; + VkRenderPassBeginInfo renderPassInfo = {}; + VkSubmitInfo submitInfo = {}; + VkPresentInfoKHR presentInfo = {}; + + VkClearValue clearColor = {{{sin(timer) / 10., cos(timer) / 10., atan(timer) / 10., 1.0f}}}; + uint32_t vertexCount = 3; + uint32_t instanceCount = 1; + timer += (float)(rand() % 1000) / 1000.; + + VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT}; + + LOAD_VK_FUNCTION(vkCreateFence); + LOAD_VK_FUNCTION(vkWaitForFences); + LOAD_VK_FUNCTION(vkResetFences); + LOAD_VK_FUNCTION(vkResetCommandBuffer); + LOAD_VK_FUNCTION(vkBeginCommandBuffer); + LOAD_VK_FUNCTION(vkEndCommandBuffer); + LOAD_VK_FUNCTION(vkQueueSubmit); + LOAD_VK_FUNCTION(vkAcquireNextImageKHR); + LOAD_VK_FUNCTION(vkQueuePresentKHR); + LOAD_VK_FUNCTION(vkCreateSwapchainKHR); + + LOAD_VK_FUNCTION(vkCmdBeginRenderPass); + LOAD_VK_FUNCTION(vkCmdEndRenderPass); + LOAD_VK_FUNCTION(vkCmdDraw); + LOAD_VK_FUNCTION(vkCmdBindPipeline); + + if((res = _vkWaitForFences(device, 1, &fences[frameNumber], VK_TRUE, UINT64_MAX)) != VK_SUCCESS) { + printf("error waiting on fence: %s\n", string_VkResult(res)); + exit(0); + } + + if((res = _vkResetFences(device, 1, &fences[frameNumber])) != VK_SUCCESS) { + printf("error resetting fence: %s\n", string_VkResult(res)); + exit(0); + } + +swapchainRetry: + if((res = _vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, imageAvaliableSemaphores[frameNumber], NULL, ¤tImageIndex)) != VK_SUCCESS) { + if(res == VK_ERROR_OUT_OF_DATE_KHR) { + if(_vkCreateSwapchainKHR(device, &swapchainCreateInfo, NULL, &swapchain) != VK_SUCCESS) { + printf("failed to create swapchain: %s\n", string_VkResult(res)); + exit(0); + }; + goto swapchainRetry; + } + }; + + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.pNext = NULL; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + beginInfo.pInheritanceInfo = NULL; + + if((res = _vkResetCommandBuffer(cmdBuffers[frameNumber], 0)) != VK_SUCCESS) { + printf("error beginning command buffer record: %s\n", string_VkResult(res)); + exit(0); + } + + if((res = _vkBeginCommandBuffer(cmdBuffers[frameNumber], &beginInfo)) != VK_SUCCESS) { + printf("error beginning command buffer record: %s\n", string_VkResult(res)); + exit(0); + } + + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.pNext = NULL; + renderPassInfo.renderPass = renderPass; + renderPassInfo.framebuffer = framebuffers[frameNumber]; + renderPassInfo.renderArea.offset = (VkOffset2D){0, 0}; + renderPassInfo.renderArea.extent = (VkExtent2D){(uint32_t)ow, (uint32_t)oh}; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearColor; + + _vkCmdBeginRenderPass(cmdBuffers[frameNumber], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + _vkCmdBindPipeline(cmdBuffers[frameNumber], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + + _vkCmdDraw(cmdBuffers[frameNumber], vertexCount, instanceCount, 0, 0); + + _vkCmdEndRenderPass(cmdBuffers[frameNumber]); + + if((res = _vkEndCommandBuffer(cmdBuffers[frameNumber])) != VK_SUCCESS) { + printf("error recording command buffer: %s\n", string_VkResult(res)); + exit(0); + } + + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = NULL; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &imageAvaliableSemaphores[frameNumber]; + submitInfo.pWaitDstStageMask = waitStages; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &cmdBuffers[frameNumber]; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &renderFinishedSemaphores[frameNumber]; + + if((res = _vkQueueSubmit(graphicsQueue, 1, &submitInfo, fences[frameNumber])) != VK_SUCCESS) { + printf("error submitting command buffer: %s\n", string_VkResult(res)); + exit(0); + } + + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &renderFinishedSemaphores[frameNumber]; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapchain; + presentInfo.pImageIndices = ¤tImageIndex; + + presentInfo.pResults = NULL; // Optional + + _vkQueuePresentKHR(presentQueue, &presentInfo); + + // frameNumber = currentImageIndex; + frameNumber = (frameNumber + 1) % (MAX_FRAMES_IN_FLIGHT); +} + +void vulkan_setup(MwWidget handle) { + FILE* vertFile; + FILE* fragFile; + void* vertBuf; + void* fragBuf; + size_t vertFileSize; + size_t fragFileSize; + size_t amountRead; + + uint32_t i; + VkViewport viewport = {}; + VkRect2D scissor = {}; + VkCommandPool cmdPool = VK_NULL_HANDLE; + VkResult res = 0; + VkShaderModule fragShaderModule; + VkShaderModule vertShaderModule; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VkAttachmentDescription colorAttachment = {}; + VkAttachmentReference colorAttachmentRef = {}; + VkSubpassDescription subpass = {}; + + VkRenderPassCreateInfo renderPassInfo = {}; + VkShaderModuleCreateInfo vertInfo = {}; + VkShaderModuleCreateInfo fragInfo = {}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; + VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; + VkPipelineShaderStageCreateInfo shaderStages[2] = {}; + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + VkPipelineViewportStateCreateInfo viewportState = {}; + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + VkPipelineMultisampleStateCreateInfo multisampling = {}; + VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + VkFramebufferCreateInfo framebufferInfo = {}; + VkCommandBufferAllocateInfo allocInfo = {}; + VkCommandPoolCreateInfo poolInfo = {}; + VkImageViewCreateInfo imageViewCreateInfo = {}; + VkSemaphoreCreateInfo semaphoreInfo = {}; + VkFenceCreateInfo fenceInfo = {}; + + int err = 0; + _vkGetInstanceProcAddr = MwVulkanGetField(handle, MwVULKANFIELD_GETINSTANCEPROCADDR, &err); + instance = MwVulkanGetField(handle, MwVULKANFIELD_INSTANCE, &err); + device = MwVulkanGetField(handle, MwVULKANFIELD_LOGICALDEVICE, &err); + physicalDevice = MwVulkanGetField(handle, MwVULKANFIELD_PHYSICALDEVICE, &err); + graphicsQueue = MwVulkanGetField(handle, MwVULKANFIELD_GRAPHICSQUEUE, &err); + presentQueue = MwVulkanGetField(handle, MwVULKANFIELD_PRESENTQUEUE, &err); + surface = MwVulkanGetField(handle, MwVULKANFIELD_SURFACE, &err); + presentQueueIndex = MwVulkanGetField(handle, MwVULKANFIELD_PRESENTQUEUEINDEX, &err); + graphicsQueueIndex = MwVulkanGetField(handle, MwVULKANFIELD_GRAPHICSQUEUEINDEX, &err); + + LOAD_VK_FUNCTION(vkCreateShaderModule); + LOAD_VK_FUNCTION(vkCreatePipelineLayout); + LOAD_VK_FUNCTION(vkCreateGraphicsPipelines); + LOAD_VK_FUNCTION(vkCreateCommandPool); + LOAD_VK_FUNCTION(vkCreateFramebuffer); + LOAD_VK_FUNCTION(vkAllocateCommandBuffers); + LOAD_VK_FUNCTION(vkCreateFence); + LOAD_VK_FUNCTION(vkCreateSemaphore); + LOAD_VK_FUNCTION(vkCreateSwapchainKHR); + LOAD_VK_FUNCTION(vkGetSwapchainImagesKHR); + LOAD_VK_FUNCTION(vkCreateImageView); + LOAD_VK_FUNCTION(vkCreateRenderPass); + + // create a swapchain + swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchainCreateInfo.surface = surface; + swapchainCreateInfo.minImageCount = 3; + swapchainCreateInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; + swapchainCreateInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + swapchainCreateInfo.imageExtent = (VkExtent2D){.width = ow, .height = oh}, + swapchainCreateInfo.imageArrayLayers = 1, + swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; + // th is how we specify no transformation. + swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchainCreateInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + // we don't care about the color of pixels that are obscured. + swapchainCreateInfo.clipped = VK_TRUE; + swapchainCreateInfo.oldSwapchain = NULL; + + if(*graphicsQueueIndex != *presentQueueIndex) { + swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchainCreateInfo.queueFamilyIndexCount = 2; + + uint32_t indices[] = { + *graphicsQueueIndex, + *presentQueueIndex, + }; + swapchainCreateInfo.pQueueFamilyIndices = indices; + } else { + swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchainCreateInfo.queueFamilyIndexCount = 0; + swapchainCreateInfo.pQueueFamilyIndices = NULL; + } + + if(_vkCreateSwapchainKHR(device, &swapchainCreateInfo, NULL, &swapchain) != VK_SUCCESS) { + printf("failed to create swapchain: %s\n", string_VkResult(res)); + exit(0); + }; + + imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.format = swapchainCreateInfo.imageFormat; + imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R; + imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G; + imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B; + imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A; + imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageViewCreateInfo.subresourceRange.baseMipLevel = 0; + imageViewCreateInfo.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; + imageViewCreateInfo.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + + if(_vkGetSwapchainImagesKHR(device, swapchain, &swapchainImageViewCount, NULL) != VK_SUCCESS) { + printf("failed to get swapchain images: %s\n", string_VkResult(res)); + exit(0); + } + swapchainImages = malloc(sizeof(VkImage) * MAX_FRAMES_IN_FLIGHT); + swapchainImageView = malloc(sizeof(VkImageView) * MAX_FRAMES_IN_FLIGHT); + _vkGetSwapchainImagesKHR(device, swapchain, &swapchainImageViewCount, swapchainImages); + for(i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + imageViewCreateInfo.image = swapchainImages[i]; + if(_vkCreateImageView(device, &imageViewCreateInfo, NULL, &swapchainImageView[i]) != VK_SUCCESS) { + printf("failed to get swapchain images: %s\n", string_VkResult(res)); + exit(0); + } + } + + // Create a Render Pass. + colorAttachment.flags = 0; + colorAttachment.format = swapchainCreateInfo.imageFormat; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = NULL; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + subpass.pResolveAttachments = NULL; + subpass.pDepthStencilAttachment = NULL; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = NULL; + + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.pNext = NULL; + renderPassInfo.flags = 0; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 0; + renderPassInfo.pDependencies = NULL; + + if((res = _vkCreateRenderPass(device, &renderPassInfo, NULL, &renderPass)) != VK_SUCCESS) { + printf("error creating the render pass: %s\n", string_VkResult(res)); + exit(0); + } + + // Create the Vertex Shader Module. + vertFile = fopen("triangle.vert.spv", "rb"); + if(vertFile == NULL) vertFile = fopen("examples/vkdemos/triangle.vert.spv", "rb"); + fragFile = fopen("triangle.frag.spv", "rb"); + if(fragFile == NULL) fragFile = fopen("examples/vkdemos/triangle.frag.spv", "rb"); + + fseek(vertFile, 0L, SEEK_END); + vertFileSize = ftell(vertFile); + rewind(vertFile); + vertBuf = malloc(vertFileSize); + memset(vertBuf, 0, vertFileSize); + amountRead = fread(vertBuf, 1, vertFileSize, vertFile); + printf("triangle.vert.spv: read %zu bytes\n", amountRead); + + vertInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + vertInfo.pNext = NULL; + vertInfo.flags = 0; + vertInfo.codeSize = amountRead; + vertInfo.pCode = vertBuf; + + if(_vkCreateShaderModule(device, &vertInfo, NULL, &vertShaderModule) != VK_SUCCESS) { + printf("failed to create the shader module: %s\n", string_VkResult(res)); + exit(0); + } + + // Create the Fragment Shader Module. + fseek(fragFile, 0L, SEEK_END); + fragFileSize = ftell(fragFile); + rewind(fragFile); + fragBuf = malloc(fragFileSize); + memset(fragBuf, 0, fragFileSize); + amountRead = fread(fragBuf, 1, fragFileSize, fragFile); + printf("triangle.frag.spv: read %zu bytes\n", amountRead); + + fragInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + fragInfo.pNext = NULL; + fragInfo.flags = 0; + fragInfo.codeSize = amountRead; + fragInfo.pCode = fragBuf; + + if(_vkCreateShaderModule(device, &fragInfo, NULL, &fragShaderModule) != VK_SUCCESS) { + printf("error creating the shader module: %s\n", string_VkResult(res)); + exit(0); + } + + // Create Pipeline Layout. + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pNext = NULL; + pipelineLayoutInfo.flags = 0; + pipelineLayoutInfo.setLayoutCount = 0; + pipelineLayoutInfo.pSetLayouts = NULL; + pipelineLayoutInfo.pushConstantRangeCount = 0; + + if((res = _vkCreatePipelineLayout(device, &pipelineLayoutInfo, NULL, &pipelineLayout)) != VK_SUCCESS) { + printf("error creating the pipeline layout: %s\n", string_VkResult(res)); + exit(0); + } + + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.pNext = NULL; + vertShaderStageInfo.flags = 0; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = vertShaderModule; + vertShaderStageInfo.pName = "main"; + vertShaderStageInfo.pSpecializationInfo = NULL; + + fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragShaderStageInfo.pNext = NULL; + fragShaderStageInfo.flags = 0; + fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragShaderStageInfo.module = fragShaderModule; + fragShaderStageInfo.pName = "main"; + fragShaderStageInfo.pSpecializationInfo = NULL; + + shaderStages[0] = vertShaderStageInfo; + shaderStages[1] = fragShaderStageInfo; + + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.pNext = NULL; + vertexInputInfo.flags = 0; + vertexInputInfo.vertexBindingDescriptionCount = 0; + vertexInputInfo.pVertexBindingDescriptions = NULL; + vertexInputInfo.vertexAttributeDescriptionCount = 0; + vertexInputInfo.pVertexAttributeDescriptions = NULL; + + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.pNext = NULL; + inputAssembly.flags = 0; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = (float)ow; + viewport.height = (float)oh; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + scissor.offset = (VkOffset2D){0, 0}; + scissor.extent = (VkExtent2D){(uint32_t)viewport.width, (uint32_t)viewport.height}; + + viewportState = (VkPipelineViewportStateCreateInfo){}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = NULL; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0; + rasterizer.depthBiasClamp = 0.0; + rasterizer.depthBiasSlopeFactor = 0.0; + rasterizer.lineWidth = 1.0f; + + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.pNext = NULL; + multisampling.flags = 0; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 0.0; + multisampling.pSampleMask = NULL; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + colorBlendAttachment.blendEnable = VK_FALSE; + colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.pNext = NULL; + colorBlending.flags = 0; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.logicOp = VK_LOGIC_OP_COPY; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.blendConstants[0] = 0.0f; + colorBlending.blendConstants[1] = 0.0f; + colorBlending.blendConstants[2] = 0.0f; + colorBlending.blendConstants[3] = 0.0f; + + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.pNext = NULL; + pipelineInfo.flags = 0; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shaderStages; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pTessellationState = NULL; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pDepthStencilState = NULL; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = NULL; + pipelineInfo.layout = pipelineLayout; + pipelineInfo.renderPass = renderPass; + pipelineInfo.subpass = 0; + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + pipelineInfo.basePipelineIndex = 0; + + if((res = _vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, &pipeline)) != VK_SUCCESS) { + printf("failed to create graphics pipeline: %s\n", string_VkResult(res)); + exit(0); + } + + framebuffers = malloc(sizeof(VkFramebuffer) * MAX_FRAMES_IN_FLIGHT); + + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.pNext = NULL; + framebufferInfo.flags = 0; + framebufferInfo.renderPass = renderPass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.width = ow; + framebufferInfo.height = oh; + framebufferInfo.layers = 1; + for(i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + framebufferInfo.pAttachments = &swapchainImageView[i]; + if((res = _vkCreateFramebuffer(device, &framebufferInfo, NULL, &framebuffers[i])) != VK_SUCCESS) { + printf("error creating the frame buffer: %s\n", string_VkResult(res)); + exit(0); + } + } + + // Create Command Pool. + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.pNext = NULL; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + poolInfo.queueFamilyIndex = *graphicsQueueIndex; + + if((res = _vkCreateCommandPool(device, &poolInfo, NULL, &cmdPool)) != VK_SUCCESS) { + printf("error creating the command pool: %s\n", string_VkResult(res)); + exit(0); + } + + // Create Command Buffer to record draw commands. + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.pNext = NULL; + allocInfo.commandPool = cmdPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = 1; + + cmdBuffers = malloc(sizeof(VkCommandBuffer) * MAX_FRAMES_IN_FLIGHT); + + for(i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + if((res = _vkAllocateCommandBuffers(device, &allocInfo, &cmdBuffers[i])) != VK_SUCCESS) { + printf("error allocating the command buffers: %s\n", string_VkResult(res)); + exit(0); + } + } + + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.pNext = 0; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphoreInfo.pNext = 0; + semaphoreInfo.flags = VK_SEMAPHORE_TYPE_BINARY; + + imageAvaliableSemaphores = malloc(sizeof(VkSemaphore) * MAX_FRAMES_IN_FLIGHT); + renderFinishedSemaphores = malloc(sizeof(VkSemaphore) * MAX_FRAMES_IN_FLIGHT); + fences = malloc(sizeof(VkFence) * MAX_FRAMES_IN_FLIGHT); + + for(i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + if(_vkCreateSemaphore(device, &semaphoreInfo, NULL, &imageAvaliableSemaphores[i]) != VK_SUCCESS) { + printf("error creating fence: %s\n", string_VkResult(res)); + exit(0); + } + if(_vkCreateSemaphore(device, &semaphoreInfo, NULL, &renderFinishedSemaphores[i]) != VK_SUCCESS) { + printf("error creating fence: %s\n", string_VkResult(res)); + exit(0); + } + if(_vkCreateFence(device, &fenceInfo, NULL, &fences[i]) != VK_SUCCESS) { + printf("error creating fence: %s\n", string_VkResult(res)); + exit(0); + } + } +} + +int main() { + MwLibraryInit(); + + if(!MwVulkanSupported()) { + printf("Vulkan not found or unsupported on target platform.\n"); + return 1; + } + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 450, + MwNtitle, "hello world", + NULL); + + vulkan = MwVaCreateWidget(MwVulkanClass, "vulkan", window, 50, 50, ow, oh, + MwNvulkanExtension, VK_KHR_SWAPCHAIN_EXTENSION_NAME, + NULL); + + MwAddUserHandler(window, MwNtickHandler, tick, NULL); + + vulkan_setup(vulkan); + + MwLoop(window); +} diff --git a/widget/milsko/milskosrc/external/libjpeg/README b/widget/milsko/milskosrc/external/libjpeg/README new file mode 100644 index 0000000000..0f4ee15228 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/README @@ -0,0 +1,374 @@ +The Independent JPEG Group's JPEG software +========================================== + +README for release 9f of 14-Jan-2024 +==================================== + +This distribution contains the ninth public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. + +This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone, +Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson, +John Korejwa, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, +Ge' Weijers, and other members of the Independent JPEG Group. + +IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee +(previously known as JPEG, together with ITU-T SG16). + + +DOCUMENTATION ROADMAP +===================== + +This file contains the following sections: + +OVERVIEW General description of JPEG and the IJG software. +LEGAL ISSUES Copyright, lack of warranty, terms of distribution. +REFERENCES Where to learn more about JPEG. +ARCHIVE LOCATIONS Where to find newer versions of this software. +ACKNOWLEDGMENTS Special thanks. +FILE FORMAT WARS Software *not* to get. +TO DO Plans for future IJG releases. + +Other documentation files in the distribution are: + +User documentation: + install.txt How to configure and install the IJG software. + usage.txt Usage instructions for cjpeg, djpeg, jpegtran, + rdjpgcom, and wrjpgcom. + *.1 Unix-style man pages for programs (same info as usage.txt). + wizard.txt Advanced usage instructions for JPEG wizards only. + cdaltui.txt Description of alternate user interface for cjpeg/djpeg. + change.log Version-to-version change highlights. +Programmer and internal documentation: + libjpeg.txt How to use the JPEG library in your own programs. + example.c Sample code for calling the JPEG library. + structure.txt Overview of the JPEG library's internal structure. + filelist.txt Road map of IJG files. + coderules.txt Coding style rules --- please read if you contribute code. + +Please read at least the files install.txt and usage.txt. Some information +can also be found in the JPEG FAQ (Frequently Asked Questions) article. See +ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. + +If you want to understand how the JPEG code works, we suggest reading one or +more of the REFERENCES, then looking at the documentation files (in roughly +the order listed) before diving into the code. + + +OVERVIEW +======== + +This package contains C software to implement JPEG image encoding, decoding, +and transcoding. JPEG (pronounced "jay-peg") is a standardized compression +method for full-color and grayscale images. + +This software implements JPEG baseline, extended-sequential, and progressive +compression processes. Provision is made for supporting all variants of these +processes, although some uncommon parameter settings aren't implemented yet. +We have made no provision for supporting the hierarchical or lossless +processes defined in the standard. + +We provide a set of library routines for reading and writing JPEG image files, +plus two sample applications "cjpeg" and "djpeg", which use the library to +perform conversion between JPEG and some other popular image file formats. +The library is intended to be reused in other applications. + +In order to support file conversion and viewing software, we have included +considerable functionality beyond the bare JPEG coding/decoding capability; +for example, the color quantization modules are not strictly part of JPEG +decoding, but they are essential for output to colormapped file formats or +colormapped displays. These extra functions can be compiled out of the +library if not required for a particular application. + +We have also included "jpegtran", a utility for lossless transcoding between +different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple +applications for inserting and extracting textual comments in JFIF files. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. In particular, +the software is not intended to be read as a tutorial on JPEG. (See the +REFERENCES section for introductory material.) Rather, it is intended to +be reliable, portable, industrial-strength code. We do not claim to have +achieved that goal in every aspect of the software, but we strive for it. + +We welcome the use of this software as a component of commercial products. +No royalty is required, but we do ask for an acknowledgement in product +documentation, as described under LEGAL ISSUES. + + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-2024, Thomas G. Lane, Guido Vollbeding. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltmain.sh). Another support script, install-sh, is copyright by X Consortium +but is also freely distributable. + + +REFERENCES +========== + +We recommend reading one or more of these references before trying to +understand the innards of the JPEG software. + +The best short technical introduction to the JPEG compression algorithm is + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) If you don't have the CACM issue +handy, a PDF file containing a revised version of Wallace's article is +available at https://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually +a preprint for an article that appeared in IEEE Trans. Consumer Electronics) +omits the sample images that appeared in CACM, but it includes corrections +and some added material. Note: the Wallace article is copyright ACM and IEEE, +and it may not be used for commercial purposes. + +A somewhat less technical, more leisurely introduction to JPEG can be found in +"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by +M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides +good explanations and example C code for a multitude of compression methods +including JPEG. It is an excellent source if you are comfortable reading C +code but don't know much about data compression in general. The book's JPEG +sample code is far from industrial-strength, but when you are ready to look +at a full implementation, you've got one here... + +The best currently available description of JPEG is the textbook "JPEG Still +Image Data Compression Standard" by William B. Pennebaker and Joan L. +Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. +Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG +standards (DIS 10918-1 and draft DIS 10918-2). +Although this is by far the most detailed and comprehensive exposition of +JPEG publicly available, we point out that it is still missing an explanation +of the most essential properties and algorithms of the underlying DCT +technology. +If you think that you know about DCT-based JPEG after reading this book, +then you are in delusion. The real fundamentals and corresponding potential +of DCT-based JPEG are not publicly known so far, and that is the reason for +all the mistaken developments taking place in the image coding domain. + +The original JPEG standard is divided into two parts, Part 1 being the actual +specification, while Part 2 covers compliance testing methods. Part 1 is +titled "Digital Compression and Coding of Continuous-tone Still Images, +Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS +10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of +Continuous-tone Still Images, Part 2: Compliance testing" and has document +numbers ISO/IEC IS 10918-2, ITU-T T.83. +IJG JPEG 8 introduced an implementation of the JPEG SmartScale extension +which is specified in two documents: A contributed document at ITU and ISO +with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced +Image Coding", April 2006, Geneva, Switzerland. The latest version of this +document is Revision 3. And a contributed document ISO/IEC JTC1/SC29/WG1 N +5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany. +IJG JPEG 9 introduces a reversible color transform for improved lossless +compression which is described in a contributed document ISO/IEC JTC1/SC29/ +WG1 N 6080 with title "JPEG 9 Lossless Coding", June/July 2012, Paris, France. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, version 2. +JFIF version 1 has been adopted as Recommendation ITU-T T.871 (05/2011) : +Information technology - Digital compression and coding of continuous-tone +still images: JPEG File Interchange Format (JFIF). It is available as a +free download in PDF file format from https://www.itu.int/rec/T-REC-T.871. +A PDF file of the older JFIF document is available at +https://www.w3.org/Graphics/JPEG/jfif3.pdf. + +The TIFF 6.0 file format specification can be obtained by FTP from +ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme +found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. +IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). +Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 +(Compression tag 7). Copies of this Note can be obtained from +https://www.ijg.org/files/. It is expected that the next revision +of the TIFF spec will replace the 6.0 JPEG design with the Note's design. +Although IJG's own code does not support TIFF/JPEG, the free libtiff library +uses our library to implement TIFF/JPEG per the Note. + + +ARCHIVE LOCATIONS +================= + +The "official" archive site for this software is www.ijg.org. +The most recent released version can always be found there in +directory "files". This particular version will be archived +in Windows-compatible "zip" archive format as +https://www.ijg.org/files/jpegsr9f.zip, and +in Unix-compatible "tar.gz" archive format as +https://www.ijg.org/files/jpegsrc.v9f.tar.gz. + +The JPEG FAQ (Frequently Asked Questions) article is a source of some +general information about JPEG. +It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ +and other news.answers archive sites, including the official news.answers +archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. +If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu +with body + send usenet/news.answers/jpeg-faq/part1 + send usenet/news.answers/jpeg-faq/part2 + + +ACKNOWLEDGMENTS +=============== + +Thank to Juergen Bruder for providing me with a copy of the common DCT +algorithm article, only to find out that I had come to the same result +in a more direct and comprehensible way with a more generative approach. + +Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the +ITU JPEG (Study Group 16) meeting in Geneva, Switzerland. + +Thank to Thomas Wiegand and Gary Sullivan for inviting me to the +Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland. + +Thank to Thomas Richter and Daniel Lee for inviting me to the +ISO/IEC JTC1/SC29/WG1 (previously known as JPEG, together with ITU-T SG16) +meeting in Berlin, Germany. + +Thank to John Korejwa and Massimo Ballerini for inviting me to +fruitful consultations in Boston, MA and Milan, Italy. + +Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther +Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel +for corresponding business development. + +Thank to Nico Zschach and Dirk Stelling of the technical support team +at the Digital Images company in Halle for providing me with extra +equipment for configuration tests. + +Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful +communication about JPEG configuration in Sigma Photo Pro software. + +Thank to Andrew Finkenstadt for hosting the ijg.org site. + +Thank to Thomas G. Lane for the original design and development +of this singular software package. + +Thank to Lars Goehler, Andreas Heinecke, Sebastian Fuss, +Yvonne Roebert, Andrej Werner, Ulf-Dietrich Braumann, +and Nina Ssymank for support and public relations. + + +FILE FORMAT WARS +================ + +The ISO/IEC JTC1/SC29/WG1 standards committee (previously known as JPEG, +together with ITU-T SG16) currently promotes different formats containing +the name "JPEG" which is misleading because these formats are incompatible +with original DCT-based JPEG and are based on faulty technologies. +IJG therefore does not and will not support such momentary mistakes +(see REFERENCES). +There exist also distributions under the name "OpenJPEG" promoting such +kind of formats which is misleading because they don't support original +JPEG images. +We have no sympathy for the promotion of inferior formats. Indeed, one of +the original reasons for developing this free software was to help force +convergence on common, interoperable format standards for JPEG files. +Don't use an incompatible file format! +(In any case, our decoder will remain capable of reading existing JPEG +image files indefinitely.) + +The ISO committee pretends to be "responsible for the popular JPEG" in their +public reports which is not true because they don't respond to actual +requirements for the maintenance of the original JPEG specification. +Furthermore, the ISO committee pretends to "ensure interoperability" with +their standards which is not true because their "standards" support only +application-specific and proprietary use cases and contain mathematically +incorrect code. + +There are currently different distributions in circulation containing the +name "libjpeg" which is misleading because they don't have the features and +are incompatible with formats supported by actual IJG libjpeg distributions. +One of those fakes is released by members of the ISO committee and just uses +the name of libjpeg for misdirection of people, similar to the abuse of the +name JPEG as described above, while having nothing in common with actual IJG +libjpeg distributions and containing mathematically incorrect code. +The other one claims to be a "derivative" or "fork" of the original libjpeg, +but violates the license conditions as described under LEGAL ISSUES above +and violates basic C programming properties. +We have no sympathy for the release of misleading, incorrect and illegal +distributions derived from obsolete code bases. +Don't use an obsolete code base! + +According to the UCC (Uniform Commercial Code) law, IJG has the lawful and +legal right to foreclose on certain standardization bodies and other +institutions or corporations that knowingly perform substantial and +systematic deceptive acts and practices, fraud, theft, and damaging of the +value of the people of this planet without their knowing, willing and +intentional consent. +The titles, ownership, and rights of these institutions and all their assets +are now duly secured and held in trust for the free people of this planet. +People of the planet, on every country, may have a financial interest in +the assets of these former principals, agents, and beneficiaries of the +foreclosed institutions and corporations. +IJG asserts what is: that each man, woman, and child has unalienable value +and rights granted and deposited in them by the Creator and not any one of +the people is subordinate to any artificial principality, corporate fiction +or the special interest of another without their appropriate knowing, +willing and intentional consent made by contract or accommodation agreement. +IJG expresses that which already was. +The people have already determined and demanded that public administration +entities, national governments, and their supporting judicial systems must +be fully transparent, accountable, and liable. +IJG has secured the value for all concerned free people of the planet. + +A partial list of foreclosed institutions and corporations ("Hall of Shame") +is currently prepared and will be published later. + + +TO DO +===== + +Version 9 is the second release of a new generation JPEG standard +to overcome the limitations of the original JPEG specification, +and is the first true source reference JPEG codec. +More features are being prepared for coming releases... + +Please send bug reports, offers of help, etc. to jpeg-info@ijg.org. diff --git a/widget/milsko/milskosrc/external/libjpeg/include/cderror.h b/widget/milsko/milskosrc/external/libjpeg/include/cderror.h new file mode 100644 index 0000000000..bb45b06647 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/cderror.h @@ -0,0 +1,136 @@ +/* + * cderror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 2009-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the cjpeg/djpeg + * applications. These strings are not needed as part of the JPEG library + * proper. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef CDERROR_H +#define CDERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* CDERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */ + +#ifdef BMP_SUPPORTED +JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format") +JMESSAGE(JERR_BMP_BADDEPTH, "Only 8-, 24-, and 32-bit BMP files are supported") +JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length") +JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1") +JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB") +JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported") +JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM") +JMESSAGE(JERR_BMP_OUTOFRANGE, "Numeric value out of range in BMP file") +JMESSAGE(JTRC_BMP, "%ux%u %d-bit BMP image") +JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image") +JMESSAGE(JTRC_BMP_OS2, "%ux%u %d-bit OS2 BMP image") +JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image") +#endif /* BMP_SUPPORTED */ + +#ifdef GIF_SUPPORTED +JMESSAGE(JERR_GIF_BUG, "GIF output got confused") +JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d") +JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB") +JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file") +JMESSAGE(JERR_GIF_NOT, "Not a GIF file") +JMESSAGE(JERR_GIF_OUTOFRANGE, "Numeric value out of range in GIF file") +JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image") +JMESSAGE(JTRC_GIF_BADVERSION, + "Warning: unexpected GIF version number '%c%c%c'") +JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x") +JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input") +JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file") +JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring") +JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image") +JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits") +#endif /* GIF_SUPPORTED */ + +#ifdef PPM_SUPPORTED +JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB") +JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file") +JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file") +JMESSAGE(JERR_PPM_OUTOFRANGE, "Numeric value out of range in PPM file") +JMESSAGE(JTRC_PGM, "%ux%u PGM image") +JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image") +JMESSAGE(JTRC_PPM, "%ux%u PPM image") +JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image") +#endif /* PPM_SUPPORTED */ + +#ifdef RLE_SUPPORTED +JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library") +JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB") +JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE") +JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file") +JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header") +JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header") +JMESSAGE(JERR_RLE_NOT, "Not an RLE file") +JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE") +JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup") +JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file") +JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d") +JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file") +JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d") +JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d") +#endif /* RLE_SUPPORTED */ + +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format") +JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file") +JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB") +JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image") +JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image") +JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image") +#else +JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled") +#endif /* TARGA_SUPPORTED */ + +JMESSAGE(JERR_BAD_CMAP_FILE, + "Color map file is invalid or of unsupported format") +JMESSAGE(JERR_TOO_MANY_COLORS, + "Output file format cannot handle %d colormap entries") +JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed") +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_UNKNOWN_FORMAT, + "Unrecognized input file format --- perhaps you need -targa") +#else +JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format") +#endif +JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTADDONCODE +} ADDON_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE diff --git a/widget/milsko/milskosrc/external/libjpeg/include/cdjpeg.h b/widget/milsko/milskosrc/external/libjpeg/include/cdjpeg.h new file mode 100644 index 0000000000..524ab3a27e --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/cdjpeg.h @@ -0,0 +1,189 @@ +/* + * cdjpeg.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common declarations for the sample applications + * cjpeg and djpeg. It is NOT used by the core JPEG library. + */ + +#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */ +#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" /* get library error codes too */ +#include "cderror.h" /* get application-specific error codes */ + + +/* + * Object interface for cjpeg's source file decoding modules + */ + +typedef struct cjpeg_source_struct * cjpeg_source_ptr; + +struct cjpeg_source_struct { + JMETHOD(void, start_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(void, finish_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + + FILE *input_file; + + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * Object interface for djpeg's output file encoding modules + */ + +typedef struct djpeg_dest_struct * djpeg_dest_ptr; + +struct djpeg_dest_struct { + /* start_output is called after jpeg_start_decompress finishes. + * The color map will be ready at this time, if one is needed. + */ + JMETHOD(void, start_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + /* Emit the specified number of pixel rows from the buffer. */ + JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + /* Finish up at the end of the image. */ + JMETHOD(void, finish_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + + /* Target file spec; filled in by djpeg.c after object is created. */ + FILE * output_file; + + /* Output pixel-row buffer. Created by module init or start_output. + * Width is cinfo->output_width * cinfo->output_components; + * height is buffer_height. + */ + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * cjpeg/djpeg may need to perform extra passes to convert to or from + * the source/destination file format. The JPEG library does not know + * about these passes, but we'd like them to be counted by the progress + * monitor. We use an expanded progress monitor object to hold the + * additional pass count. + */ + +struct cdjpeg_progress_mgr { + struct jpeg_progress_mgr pub; /* fields known to JPEG library */ + int completed_extra_passes; /* extra passes completed */ + int total_extra_passes; /* total extra */ + /* last printed percentage stored here to avoid multiple printouts */ + int percent_done; +}; + +typedef struct cdjpeg_progress_mgr * cd_progress_ptr; + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_read_bmp jIRdBMP +#define jinit_write_bmp jIWrBMP +#define jinit_read_gif jIRdGIF +#define jinit_write_gif jIWrGIF +#define jinit_read_ppm jIRdPPM +#define jinit_write_ppm jIWrPPM +#define jinit_read_rle jIRdRLE +#define jinit_write_rle jIWrRLE +#define jinit_read_targa jIRdTarga +#define jinit_write_targa jIWrTarga +#define read_quant_tables RdQTables +#define read_scan_script RdScnScript +#define set_quality_ratings SetQRates +#define set_quant_slots SetQSlots +#define set_sample_factors SetSFacts +#define read_color_map RdCMap +#define enable_signal_catcher EnSigCatcher +#define start_progress_monitor StProgMon +#define end_progress_monitor EnProgMon +#define read_stdin RdStdin +#define write_stdout WrStdout +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Module selection routines for I/O modules. */ + +EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo, + boolean is_os2)); +EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo, + boolean is_lzw)); +EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo)); + +/* cjpeg support routines (in rdswitch.c) */ + +EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename, + boolean force_baseline)); +EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename)); +EXTERN(boolean) set_quality_ratings JPP((j_compress_ptr cinfo, char *arg, + boolean force_baseline)); +EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg)); +EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg)); + +/* djpeg support routines (in rdcolmap.c) */ + +EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* common support routines (in cdjpeg.c) */ + +EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo)); +EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo, + cd_progress_ptr progress)); +EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo)); +EXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars)); +EXTERN(FILE *) read_stdin JPP((void)); +EXTERN(FILE *) write_stdout JPP((void)); + +/* miscellaneous useful macros */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif +#ifndef EXIT_WARNING +#ifdef VMS +#define EXIT_WARNING 1 /* VMS is very nonstandard */ +#else +#define EXIT_WARNING 2 +#endif +#endif diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jconfig.h b/widget/milsko/milskosrc/external/libjpeg/include/jconfig.h new file mode 100644 index 0000000000..eb36ad04b2 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jconfig.h @@ -0,0 +1,64 @@ +/* jconfig.h. Generated from jconfig.cfg by configure. */ +/* jconfig.cfg --- source file edited by configure script */ +/* see jconfig.txt for explanations */ + +#define HAVE_PROTOTYPES 1 +#define HAVE_UNSIGNED_CHAR 1 +#define HAVE_UNSIGNED_SHORT 1 +/* #undef void */ +/* #undef const */ +/* #undef CHAR_IS_UNSIGNED */ +#define HAVE_STDDEF_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_LOCALE_H 1 +/* #undef NEED_BSD_STRINGS */ +/* #undef NEED_SYS_TYPES_H */ +/* #undef NEED_FAR_POINTERS */ +/* #undef NEED_SHORT_EXTERNAL_NAMES */ +/* Define this if you get warnings about undefined structures. */ +/* #undef INCOMPLETE_TYPES_BROKEN */ + +/* Define "boolean" as unsigned char, not enum, on Windows systems. */ +#ifdef _WIN32 +#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ +typedef unsigned char boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +#endif + +#ifdef JPEG_INTERNALS + +/* #undef RIGHT_SHIFT_IS_UNSIGNED */ +#ifdef __WATCOMC__ +#define INLINE +#else +#define INLINE __inline__ +#endif +/* These are for configuring the JPEG memory manager. */ +/* #undef DEFAULT_MAX_MEM */ +/* #undef NO_MKTEMP */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +/* #undef RLE_SUPPORTED */ +#define TARGA_SUPPORTED /* Targa image file format */ + +/* #undef TWO_FILE_COMMANDLINE */ +/* #undef NEED_SIGNAL_CATCHER */ +/* #undef DONT_USE_B_MODE */ + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +/* #undef PROGRESS_REPORT */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jdct.h b/widget/milsko/milskosrc/external/libjpeg/include/jdct.h new file mode 100644 index 0000000000..0f251590c4 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jdct.h @@ -0,0 +1,409 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2002-2023 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to an input sample array and + * a pointer to a work area of type DCTELEM[]; the DCT is to be performed + * in-place in that buffer. Type DCTELEM is int for 8-bit samples, INT32 + * for 12-bit samples. (NOTE: Floating-point DCT implementations use an + * array of type FAST_FLOAT, instead.) + * The input data is to be fetched from the sample array starting at a + * specified column. (Any row offset needed will be applied to the array + * pointer before it is passed to the FDCT code.) + * Note that the number of samples fetched by the FDCT routine is + * DCT_h_scaled_size * DCT_v_scaled_size. + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data, + JSAMPARRAY sample_data, + JDIMENSION start_col)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data, + JSAMPARRAY sample_data, + JDIMENSION start_col)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_h_scaled_size * DCT_v_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly, assuming that RANGE_CENTER + * (defined in jpegint.h) is a power of 2. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define RANGE_MASK (RANGE_CENTER * 2 - 1) +#define RANGE_SUBSET (RANGE_CENTER - CENTERJSAMPLE) + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit - RANGE_SUBSET) + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_fdct_7x7 jFD7x7 +#define jpeg_fdct_6x6 jFD6x6 +#define jpeg_fdct_5x5 jFD5x5 +#define jpeg_fdct_4x4 jFD4x4 +#define jpeg_fdct_3x3 jFD3x3 +#define jpeg_fdct_2x2 jFD2x2 +#define jpeg_fdct_1x1 jFD1x1 +#define jpeg_fdct_9x9 jFD9x9 +#define jpeg_fdct_10x10 jFD10x10 +#define jpeg_fdct_11x11 jFD11x11 +#define jpeg_fdct_12x12 jFD12x12 +#define jpeg_fdct_13x13 jFD13x13 +#define jpeg_fdct_14x14 jFD14x14 +#define jpeg_fdct_15x15 jFD15x15 +#define jpeg_fdct_16x16 jFD16x16 +#define jpeg_fdct_16x8 jFD16x8 +#define jpeg_fdct_14x7 jFD14x7 +#define jpeg_fdct_12x6 jFD12x6 +#define jpeg_fdct_10x5 jFD10x5 +#define jpeg_fdct_8x4 jFD8x4 +#define jpeg_fdct_6x3 jFD6x3 +#define jpeg_fdct_4x2 jFD4x2 +#define jpeg_fdct_2x1 jFD2x1 +#define jpeg_fdct_8x16 jFD8x16 +#define jpeg_fdct_7x14 jFD7x14 +#define jpeg_fdct_6x12 jFD6x12 +#define jpeg_fdct_5x10 jFD5x10 +#define jpeg_fdct_4x8 jFD4x8 +#define jpeg_fdct_3x6 jFD3x6 +#define jpeg_fdct_2x4 jFD2x4 +#define jpeg_fdct_1x2 jFD1x2 +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_7x7 jRD7x7 +#define jpeg_idct_6x6 jRD6x6 +#define jpeg_idct_5x5 jRD5x5 +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_3x3 jRD3x3 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#define jpeg_idct_9x9 jRD9x9 +#define jpeg_idct_10x10 jRD10x10 +#define jpeg_idct_11x11 jRD11x11 +#define jpeg_idct_12x12 jRD12x12 +#define jpeg_idct_13x13 jRD13x13 +#define jpeg_idct_14x14 jRD14x14 +#define jpeg_idct_15x15 jRD15x15 +#define jpeg_idct_16x16 jRD16x16 +#define jpeg_idct_16x8 jRD16x8 +#define jpeg_idct_14x7 jRD14x7 +#define jpeg_idct_12x6 jRD12x6 +#define jpeg_idct_10x5 jRD10x5 +#define jpeg_idct_8x4 jRD8x4 +#define jpeg_idct_6x3 jRD6x3 +#define jpeg_idct_4x2 jRD4x2 +#define jpeg_idct_2x1 jRD2x1 +#define jpeg_idct_8x16 jRD8x16 +#define jpeg_idct_7x14 jRD7x14 +#define jpeg_idct_6x12 jRD6x12 +#define jpeg_idct_5x10 jRD5x10 +#define jpeg_idct_4x8 jRD4x8 +#define jpeg_idct_3x6 jRD3x6 +#define jpeg_idct_2x4 jRD2x4 +#define jpeg_idct_1x2 jRD1x2 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_ifast + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_float + JPP((FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_7x7 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_6x6 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_5x5 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_4x4 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_3x3 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_2x2 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_1x1 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_9x9 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_10x10 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_11x11 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_12x12 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_13x13 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_14x14 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_15x15 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_16x16 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_16x8 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_14x7 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_12x6 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_10x5 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_8x4 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_6x3 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_4x2 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_2x1 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_8x16 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_7x14 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_6x12 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_5x10 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_4x8 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_3x6 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_2x4 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_1x2 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_7x7 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_6x6 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_5x5 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_3x3 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_9x9 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_10x10 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_11x11 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_12x12 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_13x13 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_14x14 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_15x15 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_16x16 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_16x8 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_14x7 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_12x6 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_10x5 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_8x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_6x3 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_8x16 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_7x14 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_6x12 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_5x10 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x8 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_3x6 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif + +/* Like RIGHT_SHIFT, but applies to a DCTELEM. + * We assume that int right shift is unsigned if INT32 right shift is. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS DCTELEM ishift_temp; +#if BITS_IN_JSAMPLE == 8 +#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ +#else +#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ +#endif +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jerror.h b/widget/milsko/milskosrc/external/libjpeg/include/jerror.h new file mode 100644 index 0000000000..db608b9c09 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jerror.h @@ -0,0 +1,304 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 1997-2018 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "DCT scaled block size %dx%d not supported") +JMESSAGE(JERR_BAD_DROP_SAMPLING, + "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OUTOFBOUNDS, "Huffman code size table out of bounds") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_BEFORE, "Invalid JPEG file structure: %s before SOF") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT6(cinfo,code,p1,p2,p3,p4,p5,p6) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (cinfo)->err->msg_parm.i[4] = (p5), \ + (cinfo)->err->msg_parm.i[5] = (p6), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jinclude.h b/widget/milsko/milskosrc/external/libjpeg/include/jinclude.h new file mode 100644 index 0000000000..12ea8cd2fd --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jinclude.h @@ -0,0 +1,157 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * Modified 2017-2022 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using + * the JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + * + * Furthermore, macros are provided for fflush() and ferror() in order + * to facilitate adaption by applications using an own FILE class. + * + * You can define your own custom file I/O functions in jconfig.h and + * #define JPEG_HAVE_FILE_IO_CUSTOM there to prevent redefinition here. + * + * You can #define JPEG_USE_FILE_IO_CUSTOM in jconfig.h to use custom file + * I/O functions implemented in Delphi VCL (Visual Component Library) + * in Vcl.Imaging.jpeg.pas for the TJPEGImage component utilizing + * the Delphi RTL (Run-Time Library) TMemoryStream component: + * + * procedure jpeg_stdio_src(var cinfo: jpeg_decompress_struct; + * input_file: TStream); external; + * + * procedure jpeg_stdio_dest(var cinfo: jpeg_compress_struct; + * output_file: TStream); external; + * + * function jfread(var buf; recsize, reccount: Integer; S: TStream): Integer; + * begin + * Result := S.Read(buf, recsize * reccount); + * end; + * + * function jfwrite(const buf; recsize, reccount: Integer; S: TStream): Integer; + * begin + * Result := S.Write(buf, recsize * reccount); + * end; + * + * function jfflush(S: TStream): Integer; + * begin + * Result := 0; + * end; + * + * function jferror(S: TStream): Integer; + * begin + * Result := 0; + * end; + * + * TMemoryStream of Delphi RTL has the distinctive feature to provide dynamic + * memory buffer management with a file/stream-based interface, particularly for + * the write (output) operation, which is easier to apply compared with direct + * implementations as given in jdatadst.c for memory destination. Those direct + * implementations of dynamic memory write tend to be more difficult to use, + * so providing an option like TMemoryStream may be a useful alternative. + * + * The CFile/CMemFile classes of the Microsoft Foundation Class (MFC) Library + * may be used in a similar fashion. + */ + +#ifndef JPEG_HAVE_FILE_IO_CUSTOM +#ifdef JPEG_USE_FILE_IO_CUSTOM +extern size_t jfread(void * __ptr, size_t __size, size_t __n, FILE * __stream); +extern size_t jfwrite(const void * __ptr, size_t __size, size_t __n, FILE * __stream); +extern int jfflush(FILE * __stream); +extern int jferror(FILE * __fp); + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) jfread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) jfwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFFLUSH(file) jfflush(file) +#define JFERROR(file) jferror(file) +#else +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFFLUSH(file) fflush(file) +#define JFERROR(file) ferror(file) +#endif +#endif diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jmemsys.h b/widget/milsko/milskosrc/external/libjpeg/include/jmemsys.h new file mode 100644 index 0000000000..6c3c6d348f --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jmorecfg.h b/widget/milsko/milskosrc/external/libjpeg/include/jmorecfg.h new file mode 100644 index 0000000000..4638d6af2d --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jmorecfg.h @@ -0,0 +1,457 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2022 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 9 for 9-bit sample values + * 10 for 10-bit sample values + * 11 for 11-bit sample values + * 12 for 12-bit sample values + * Only 8, 9, 10, 11, and 12 bits sample data precision are supported for + * full-feature DCT processing. Further depths up to 16-bit may be added + * later for the lossless modes of operation. + * Run-time selection and conversion of data precision will be added later + * and are currently not supported, sorry. + * Exception: The transcoding part (jpegtran) supports all settings in a + * single instance, since it operates on the level of DCT coefficients and + * not sample values. The DCT coefficients are of the same type (16 bits) + * in all cases (see below). + */ + +#define BITS_IN_JSAMPLE 8 /* use 8, 9, 10, 11, or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 9 +/* JSAMPLE should be the smallest type that will hold the values 0..511. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 511 +#define CENTERJSAMPLE 256 + +#endif /* BITS_IN_JSAMPLE == 9 */ + + +#if BITS_IN_JSAMPLE == 10 +/* JSAMPLE should be the smallest type that will hold the values 0..1023. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 1023 +#define CENTERJSAMPLE 512 + +#endif /* BITS_IN_JSAMPLE == 10 */ + + +#if BITS_IN_JSAMPLE == 11 +/* JSAMPLE should be the smallest type that will hold the values 0..2047. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 2047 +#define CENTERJSAMPLE 1024 + +#endif /* BITS_IN_JSAMPLE == 11 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */ +#ifndef _BASETSD_H /* MinGW is slightly different */ +#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */ +typedef long INT32; +#endif +#endif +#endif +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* The noreturn type identifier is used to declare functions + * which cannot return. + * Compilers can thus create more optimized code and perform + * better checks for warnings and errors. + * Static analyzer tools can make improved inferences about + * execution paths and are prevented from giving false alerts. + * + * Unfortunately, the proposed specifications of corresponding + * extensions in the Dec 2011 ISO C standard revision (C11), + * GCC, MSVC, etc. are not viable. + * Thus we introduce a user defined type to declare noreturn + * functions at least for clarity. A proper compiler would + * have a suitable noreturn type to match in place of void. + */ + +#ifndef HAVE_NORETURN_T +typedef void noreturn_t; +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifndef FAR +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +#if defined FALSE || defined TRUE || defined QGLOBAL_H +/* Qt3 defines FALSE and TRUE as "const" variables in qglobal.h */ +typedef int boolean; +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#else +typedef enum { FALSE = 0, TRUE = 1 } boolean; +#endif +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#define C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN) */ +#define DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW) */ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected more than 8-bit data precision, it is dangerous to + * turn off ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only + * good for 8-bit precision, so arithmetic coding is recommended for higher + * precision. The Huffman encoder normally uses entropy optimization to + * compute usable tables for higher precision. Otherwise, you'll have to + * supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#define D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? (Requires DCT_ISLOW) */ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * #define JPEG_USE_RGB_CUSTOM in jconfig.h, or define your own custom + * order in jconfig.h and #define JPEG_HAVE_RGB_CUSTOM. + * You can also deal with formats such as R,G,B,X (one extra byte per pixel) + * by changing RGB_PIXELSIZE. + * Note that changing the offsets will also change + * the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). + * So you can't use color quantization if you change that value. + */ + +#ifndef JPEG_HAVE_RGB_CUSTOM +#ifdef JPEG_USE_RGB_CUSTOM +#define RGB_RED 2 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 0 /* Offset of Blue */ +#else +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#endif +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ +#endif + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jpegint.h b/widget/milsko/milskosrc/external/libjpeg/include/jpegint.h new file mode 100644 index 0000000000..3528bff5b7 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jpegint.h @@ -0,0 +1,445 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +typedef JMETHOD(void, forward_DCT_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_col, JDIMENSION num_blocks)); + +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* It is useful to allow each component to have a separate FDCT method. */ + forward_DCT_ptr forward_DCT[MAX_COMPONENTS]; +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Definition of range extension bits for decompression processes. + * See the comments with prepare_range_limit_table (in jdmaster.c) + * for more info. + * The recommended default value for normal applications is 2. + * Applications with special requirements may use a different value. + * For example, Ghostscript wants to use 3 for proper handling of + * wacky images with oversize coefficient values. + */ + +#define RANGE_BITS 2 +#define RANGE_CENTER (CENTERJSAMPLE << RANGE_BITS) + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + ((INT32) 1 << ((n)-1)), n) + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_arith_encoder jIAEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_arith_decoder jIADecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jzero_far jZeroFar +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#define jpeg_natural_order7 jZAG7Table +#define jpeg_natural_order6 jZAG6Table +#define jpeg_natural_order5 jZAG5Table +#define jpeg_natural_order4 jZAG4Table +#define jpeg_natural_order3 jZAG3Table +#define jpeg_natural_order2 jZAG2Table +#define jpeg_aritab jAriTab +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines in jutils.c do it the hard way. + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */ +#define FMEMZERO(target,size) MEMZERO(target,size) +#else /* 80x86 case */ +#ifdef USE_FMEM +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) +#else +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +#define FMEMZERO(target,size) jzero_far(target, size) +#endif +#endif + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, + JSAMPARRAY output_array, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ +extern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */ +extern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */ +extern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */ +extern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */ +extern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */ +extern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */ + +/* Arithmetic coding probability estimation tables in jaricom.c */ +extern const INT32 jpeg_aritab[]; + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jpeglib.h b/widget/milsko/milskosrc/external/libjpeg/include/jpeglib.h new file mode 100644 index 0000000000..e7e15ab2cd --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jpeglib.h @@ -0,0 +1,1183 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2002-2022 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +extern "C" { +#endif +#endif + +/* Version IDs for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 90". + */ + +#define JPEG_LIB_VERSION 90 /* Compatibility version 9.0 */ +#define JPEG_LIB_VERSION_MAJOR 9 +#define JPEG_LIB_VERSION_MINOR 6 + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, + * so don't change them if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 coefficients */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples, + * reflecting any scaling we choose to apply during the DCT step. + * Values from 1 to 16 are supported. + * Note that different components may receive different DCT scalings. + */ + int DCT_h_scaled_size; + int DCT_v_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface); + * DCT scaling is included, so + * downsampled_width = + * ceil(image_width * Hi/Hmax * DCT_h_scaled_size/block_size) + * and similarly for height. + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* For decompression, in cases where some of the components will be + * ignored (eg grayscale output from YCbCr image), we can skip most + * computations for the unused components. + * For compression, some of the components will need further quantization + * scale by factor of 2 after DCT (eg BG_YCC output from normal RGB input). + * The field is first set TRUE for decompression, FALSE for compression + * in initial_setup, and then adapted in color conversion setup. + */ + boolean component_needed; + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples: MCU_width * DCT_h_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue, standard RGB (sRGB) */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV), standard YCC */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK, /* Y/Cb/Cr/K */ + JCS_BG_RGB, /* big gamut red/green/blue, bg-sRGB */ + JCS_BG_YCC /* big gamut Y/Cb/Cr, bg-sYCC */ +} J_COLOR_SPACE; + +/* Supported color transforms. */ + +typedef enum { + JCT_NONE = 0, + JCT_SUBTRACT_GREEN = 1 +} J_COLOR_TRANSFORM; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + JDIMENSION jpeg_width; /* scaled JPEG image width */ + JDIMENSION jpeg_height; /* scaled JPEG image height */ + /* Dimensions of actual JPEG image that will be written to file, + * derived from input dimensions by scaling factors above. + * These fields are computed by jpeg_start_compress(). + * You can also use jpeg_calc_jpeg_dimensions() to determine these values + * in advance of calling jpeg_start_compress(). + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + int q_scale_factor[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined, + * and corresponding scale factors (percentage, initialized 100). + */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + J_COLOR_TRANSFORM color_transform; + /* Color transform identifier, writes LSE marker if nonzero */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCT_v_scaled_size sample rows of each component + * in an "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + J_COLOR_TRANSFORM color_transform; + /* Color transform identifier derived from LSE marker, otherwise zero */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor * DCT_v_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* These fields are derived from Se of first SOS marker. + */ + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array for entropy decode */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(noreturn_t, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_mem_dest jMemDest +#define jpeg_mem_src jMemSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_default_qtables jDefQTables +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_std_huff_table jStdHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_calc_jpeg_dimensions jCjpegDimensions +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_core_output_dimensions jCoreDimensions +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Data source and destination managers: memory buffers. */ +EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo, + unsigned char ** outbuffer, + size_t * outsize)); +EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, + const unsigned char * inbuffer, + size_t insize)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_std_huff_table JPP((j_common_ptr cinfo, + boolean isDC, int tblno)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Precalculate JPEG dimensions for current compression parameters. */ +EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.txt concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +} +#endif +#endif + +#endif /* JPEGLIB_H */ diff --git a/widget/milsko/milskosrc/external/libjpeg/include/jversion.h b/widget/milsko/milskosrc/external/libjpeg/include/jversion.h new file mode 100644 index 0000000000..df53ef5e55 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-2024, Thomas G. Lane, Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "9f 14-Jan-2024" + +#define JCOPYRIGHT "Copyright (C) 2024, Thomas G. Lane, Guido Vollbeding" diff --git a/widget/milsko/milskosrc/external/libjpeg/include/transupp.h b/widget/milsko/milskosrc/external/libjpeg/include/transupp.h new file mode 100644 index 0000000000..a8ba16ad7f --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/include/transupp.h @@ -0,0 +1,230 @@ +/* + * transupp.h + * + * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for image transformation routines and + * other utility code used by the jpegtran sample application. These are + * NOT part of the core JPEG library. But we keep these routines separate + * from jpegtran.c to ease the task of maintaining jpegtran-like programs + * that have other user interfaces. + * + * NOTE: all the routines declared here have very specific requirements + * about when they are to be executed during the reading and writing of the + * source and destination files. See the comments in transupp.c, or see + * jpegtran.c for an example of correct usage. + */ + +/* If you happen not to want the image transform support, disable it here */ +#ifndef TRANSFORMS_SUPPORTED +#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ +#endif + +/* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images + * whose dimensions aren't multiples of the iMCU size. The right and bottom + * image edges are padded out to the next iMCU boundary with junk data; but + * no padding is possible at the top and left edges. If we were to flip + * the whole image including the pad data, then pad garbage would become + * visible at the top and/or left, and real pixels would disappear into the + * pad margins --- perhaps permanently, since encoders & decoders may not + * bother to preserve DCT blocks that appear to be completely outside the + * nominal image area. So, we have to exclude any partial iMCUs from the + * basic transformation. + * + * Transpose is the only transformation that can handle partial iMCUs at the + * right and bottom edges completely cleanly. flip_h can flip partial iMCUs + * at the bottom, but leaves any partial iMCUs at the right edge untouched. + * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. + * The other transforms are defined as combinations of these basic transforms + * and process edge blocks in a way that preserves the equivalence. + * + * The "trim" option causes untransformable partial iMCUs to be dropped; + * this is not strictly lossless, but it usually gives the best-looking + * result for odd-size images. Note that when this option is active, + * the expected mathematical equivalences between the transforms may not hold. + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * + * We also offer a lossless-crop option, which discards data outside a given + * image region but losslessly preserves what is inside. Like the rotate and + * flip transforms, lossless crop is restricted by the current JPEG format: the + * upper left corner of the selected region must fall on an iMCU boundary. If + * this does not hold for the given crop parameters, we silently move the upper + * left corner up and/or left to make it so, simultaneously increasing the + * region dimensions to keep the lower right crop corner unchanged. (Thus, the + * output image covers at least the requested region, but may cover more.) + * The adjustment of the region dimensions may be optionally disabled. + * + * A complementary lossless-wipe option is provided to discard (gray out) data + * inside a given image region while losslessly preserving what is outside. + * Another option is lossless-drop, which replaces data at a given image + * position by another image. Both source images must have the same + * subsampling values. It is best if they also have the same quantization, + * otherwise quantization adaption occurs. The trim option can be used with + * the drop option to requantize the drop file to the source file. + * + * We also provide a lossless-resize option, which is kind of a lossless-crop + * operation in the DCT coefficient block domain - it discards higher-order + * coefficients and losslessly preserves lower-order coefficients of a + * sub-block. + * + * Rotate/flip transform, resize, and crop can be requested together in a + * single invocation. The crop is applied last --- that is, the crop region + * is specified in terms of the destination image after transform/resize. + * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of + * thing as the rotate/flip transformations, but it's convenient to handle it + * as part of this package, mainly because the transformation routines have to + * be aware of the option to know how many components to work on. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jtransform_parse_crop_spec jTrParCrop +#define jtransform_request_workspace jTrRequest +#define jtransform_adjust_parameters jTrAdjust +#define jtransform_execute_transform jTrExec +#define jtransform_perfect_transform jTrPerfect +#define jcopy_markers_setup jCMrkSetup +#define jcopy_markers_execute jCMrkExec +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * Codes for supported types of image transformations. + */ + +typedef enum { + JXFORM_NONE, /* no transformation */ + JXFORM_FLIP_H, /* horizontal flip */ + JXFORM_FLIP_V, /* vertical flip */ + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ + JXFORM_ROT_90, /* 90-degree clockwise rotation */ + JXFORM_ROT_180, /* 180-degree rotation */ + JXFORM_ROT_270, /* 270-degree clockwise (or 90 ccw) */ + JXFORM_WIPE, /* wipe */ + JXFORM_DROP /* drop */ +} JXFORM_CODE; + +/* + * Codes for crop parameters, which can individually be unspecified, + * positive or negative for xoffset or yoffset, + * positive or force or reflect for width or height. + */ + +typedef enum { + JCROP_UNSET, + JCROP_POS, + JCROP_NEG, + JCROP_FORCE, + JCROP_REFLECT +} JCROP_CODE; + +/* + * Transform parameters struct. + * NB: application must not change any elements of this struct after + * calling jtransform_request_workspace. + */ + +typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ + boolean perfect; /* if TRUE, fail if partial MCUs are requested */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ + boolean crop; /* if TRUE, crop or wipe source image, or drop */ + + /* Crop parameters: application need not set these unless crop is TRUE. + * These can be filled in by jtransform_parse_crop_spec(). + */ + JDIMENSION crop_width; /* Width of selected region */ + JCROP_CODE crop_width_set; /* (force disables adjustment) */ + JDIMENSION crop_height; /* Height of selected region */ + JCROP_CODE crop_height_set; /* (force disables adjustment) */ + JDIMENSION crop_xoffset; /* X offset of selected region */ + JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ + JDIMENSION crop_yoffset; /* Y offset of selected region */ + JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ + + /* Drop parameters: set by caller for drop request */ + j_decompress_ptr drop_ptr; + jvirt_barray_ptr * drop_coef_arrays; + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ + JDIMENSION output_width; /* cropped destination dimensions */ + JDIMENSION output_height; + JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ + JDIMENSION y_crop_offset; + JDIMENSION drop_width; /* drop/wipe dimensions measured in iMCUs */ + JDIMENSION drop_height; + int iMCU_sample_width; /* destination iMCU size */ + int iMCU_sample_height; +} jpeg_transform_info; + + +#if TRANSFORMS_SUPPORTED + +/* Parse a crop specification (written in X11 geometry style) */ +EXTERN(boolean) jtransform_parse_crop_spec + JPP((jpeg_transform_info *info, const char *spec)); +/* Request any required workspace */ +EXTERN(boolean) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +/* Adjust output image parameters */ +EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Execute the actual transformation, if any */ +EXTERN(void) jtransform_execute_transform + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Determine whether lossless transformation is perfectly + * possible for a specified image and transformation. + */ +EXTERN(boolean) jtransform_perfect_transform + JPP((JDIMENSION image_width, JDIMENSION image_height, + int MCU_width, int MCU_height, + JXFORM_CODE transform)); + +/* jtransform_execute_transform used to be called + * jtransform_execute_transformation, but some compilers complain about + * routine names that long. This macro is here to avoid breaking any + * old source code that uses the original name... + */ +#define jtransform_execute_transformation jtransform_execute_transform + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* + * Support for copying optional markers from source to destination file. + */ + +typedef enum { + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL /* copy all optional markers */ +} JCOPY_OPTION; + +#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ + +/* Setup decompression object to save desired markers in memory */ +EXTERN(void) jcopy_markers_setup + JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); +/* Copy markers saved in the given source object to the destination object */ +EXTERN(void) jcopy_markers_execute + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option)); diff --git a/widget/milsko/milskosrc/external/libjpeg/src/cdjpeg.c b/widget/milsko/milskosrc/external/libjpeg/src/cdjpeg.c new file mode 100644 index 0000000000..b6250ff97c --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/cdjpeg.c @@ -0,0 +1,181 @@ +/* + * cdjpeg.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common support routines used by the IJG application + * programs (cjpeg, djpeg, jpegtran). + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include /* to declare isupper(), tolower() */ +#ifdef NEED_SIGNAL_CATCHER +#include /* to declare signal() */ +#endif +#ifdef USE_SETMODE +#include /* to declare setmode()'s parameter macros */ +/* If you have setmode() but not , just delete this line: */ +#include /* to declare setmode() */ +#endif + + +/* + * Signal catcher to ensure that temporary files are removed before aborting. + * NB: for Amiga Manx C this is actually a global routine named _abort(); + * we put "#define signal_catcher _abort" in jconfig.h. Talk about bogus... + */ + +#ifdef NEED_SIGNAL_CATCHER + +static j_common_ptr sig_cinfo; + +void /* must be global for Manx C */ +signal_catcher (int signum) +{ + if (sig_cinfo != NULL) { + if (sig_cinfo->err != NULL) /* turn off trace output */ + sig_cinfo->err->trace_level = 0; + jpeg_destroy(sig_cinfo); /* clean up memory allocation & temp files */ + } + exit(EXIT_FAILURE); +} + + +GLOBAL(void) +enable_signal_catcher (j_common_ptr cinfo) +{ + sig_cinfo = cinfo; +#ifdef SIGINT /* not all systems have SIGINT */ + signal(SIGINT, signal_catcher); +#endif +#ifdef SIGTERM /* not all systems have SIGTERM */ + signal(SIGTERM, signal_catcher); +#endif +} + +#endif + + +/* + * Optional progress monitor: display a percent-done figure on stderr. + */ + +#ifdef PROGRESS_REPORT + +METHODDEF(void) +progress_monitor (j_common_ptr cinfo) +{ + cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress; + int total_passes = prog->pub.total_passes + prog->total_extra_passes; + int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit); + + if (percent_done != prog->percent_done) { + prog->percent_done = percent_done; + if (total_passes > 1) { + fprintf(stderr, "\rPass %d/%d: %3d%% ", + prog->pub.completed_passes + prog->completed_extra_passes + 1, + total_passes, percent_done); + } else { + fprintf(stderr, "\r %3d%% ", percent_done); + } + fflush(stderr); + } +} + + +GLOBAL(void) +start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress) +{ + /* Enable progress display, unless trace output is on */ + if (cinfo->err->trace_level == 0) { + progress->pub.progress_monitor = progress_monitor; + progress->completed_extra_passes = 0; + progress->total_extra_passes = 0; + progress->percent_done = -1; + cinfo->progress = &progress->pub; + } +} + + +GLOBAL(void) +end_progress_monitor (j_common_ptr cinfo) +{ + /* Clear away progress display */ + if (cinfo->err->trace_level == 0) { + fprintf(stderr, "\r \r"); + fflush(stderr); + } +} + +#endif + + +/* + * Case-insensitive matching of possibly-abbreviated keyword switches. + * keyword is the constant keyword (must be lower case already), + * minchars is length of minimum legal abbreviation. + */ + +GLOBAL(boolean) +keymatch (char * arg, const char * keyword, int minchars) +{ + register int ca, ck; + register int nmatched = 0; + + while ((ca = *arg++) != '\0') { + if ((ck = *keyword++) == '\0') + return FALSE; /* arg longer than keyword, no good */ + if (isupper(ca)) /* force arg to lcase (assume ck is already) */ + ca = tolower(ca); + if (ca != ck) + return FALSE; /* no good */ + nmatched++; /* count matched characters */ + } + /* reached end of argument; fail if it's too short for unique abbrev */ + if (nmatched < minchars) + return FALSE; + return TRUE; /* A-OK */ +} + + +/* + * Routines to establish binary I/O mode for stdin and stdout. + * Non-Unix systems often require some hacking to get out of text mode. + */ + +GLOBAL(FILE *) +read_stdin (void) +{ + FILE * input_file = stdin; + +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdin), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) { + fprintf(stderr, "Cannot reopen stdin\n"); + exit(EXIT_FAILURE); + } +#endif + return input_file; +} + + +GLOBAL(FILE *) +write_stdout (void) +{ + FILE * output_file = stdout; + +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdout), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { + fprintf(stderr, "Cannot reopen stdout\n"); + exit(EXIT_FAILURE); + } +#endif + return output_file; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jaricom.c b/widget/milsko/milskosrc/external/libjpeg/src/jaricom.c new file mode 100644 index 0000000000..690068861f --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jaricom.c @@ -0,0 +1,153 @@ +/* + * jaricom.c + * + * Developed 1997-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains probability estimation tables for common use in + * arithmetic entropy encoding and decoding routines. + * + * This data represents Table D.3 in the JPEG spec (D.2 in the draft), + * ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81, and Table 24 + * in the JBIG spec, ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +/* The following #define specifies the packing of the four components + * into the compact INT32 representation. + * Note that this formula must match the actual arithmetic encoder + * and decoder implementation. The implementation has to be changed + * if this formula is changed. + * The current organization is leaned on Markus Kuhn's JBIG + * implementation (jbig_tab.c). + */ + +#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b) + +const INT32 jpeg_aritab[113+1] = { +/* + * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS + */ + V( 0, 0x5a1d, 1, 1, 1 ), + V( 1, 0x2586, 14, 2, 0 ), + V( 2, 0x1114, 16, 3, 0 ), + V( 3, 0x080b, 18, 4, 0 ), + V( 4, 0x03d8, 20, 5, 0 ), + V( 5, 0x01da, 23, 6, 0 ), + V( 6, 0x00e5, 25, 7, 0 ), + V( 7, 0x006f, 28, 8, 0 ), + V( 8, 0x0036, 30, 9, 0 ), + V( 9, 0x001a, 33, 10, 0 ), + V( 10, 0x000d, 35, 11, 0 ), + V( 11, 0x0006, 9, 12, 0 ), + V( 12, 0x0003, 10, 13, 0 ), + V( 13, 0x0001, 12, 13, 0 ), + V( 14, 0x5a7f, 15, 15, 1 ), + V( 15, 0x3f25, 36, 16, 0 ), + V( 16, 0x2cf2, 38, 17, 0 ), + V( 17, 0x207c, 39, 18, 0 ), + V( 18, 0x17b9, 40, 19, 0 ), + V( 19, 0x1182, 42, 20, 0 ), + V( 20, 0x0cef, 43, 21, 0 ), + V( 21, 0x09a1, 45, 22, 0 ), + V( 22, 0x072f, 46, 23, 0 ), + V( 23, 0x055c, 48, 24, 0 ), + V( 24, 0x0406, 49, 25, 0 ), + V( 25, 0x0303, 51, 26, 0 ), + V( 26, 0x0240, 52, 27, 0 ), + V( 27, 0x01b1, 54, 28, 0 ), + V( 28, 0x0144, 56, 29, 0 ), + V( 29, 0x00f5, 57, 30, 0 ), + V( 30, 0x00b7, 59, 31, 0 ), + V( 31, 0x008a, 60, 32, 0 ), + V( 32, 0x0068, 62, 33, 0 ), + V( 33, 0x004e, 63, 34, 0 ), + V( 34, 0x003b, 32, 35, 0 ), + V( 35, 0x002c, 33, 9, 0 ), + V( 36, 0x5ae1, 37, 37, 1 ), + V( 37, 0x484c, 64, 38, 0 ), + V( 38, 0x3a0d, 65, 39, 0 ), + V( 39, 0x2ef1, 67, 40, 0 ), + V( 40, 0x261f, 68, 41, 0 ), + V( 41, 0x1f33, 69, 42, 0 ), + V( 42, 0x19a8, 70, 43, 0 ), + V( 43, 0x1518, 72, 44, 0 ), + V( 44, 0x1177, 73, 45, 0 ), + V( 45, 0x0e74, 74, 46, 0 ), + V( 46, 0x0bfb, 75, 47, 0 ), + V( 47, 0x09f8, 77, 48, 0 ), + V( 48, 0x0861, 78, 49, 0 ), + V( 49, 0x0706, 79, 50, 0 ), + V( 50, 0x05cd, 48, 51, 0 ), + V( 51, 0x04de, 50, 52, 0 ), + V( 52, 0x040f, 50, 53, 0 ), + V( 53, 0x0363, 51, 54, 0 ), + V( 54, 0x02d4, 52, 55, 0 ), + V( 55, 0x025c, 53, 56, 0 ), + V( 56, 0x01f8, 54, 57, 0 ), + V( 57, 0x01a4, 55, 58, 0 ), + V( 58, 0x0160, 56, 59, 0 ), + V( 59, 0x0125, 57, 60, 0 ), + V( 60, 0x00f6, 58, 61, 0 ), + V( 61, 0x00cb, 59, 62, 0 ), + V( 62, 0x00ab, 61, 63, 0 ), + V( 63, 0x008f, 61, 32, 0 ), + V( 64, 0x5b12, 65, 65, 1 ), + V( 65, 0x4d04, 80, 66, 0 ), + V( 66, 0x412c, 81, 67, 0 ), + V( 67, 0x37d8, 82, 68, 0 ), + V( 68, 0x2fe8, 83, 69, 0 ), + V( 69, 0x293c, 84, 70, 0 ), + V( 70, 0x2379, 86, 71, 0 ), + V( 71, 0x1edf, 87, 72, 0 ), + V( 72, 0x1aa9, 87, 73, 0 ), + V( 73, 0x174e, 72, 74, 0 ), + V( 74, 0x1424, 72, 75, 0 ), + V( 75, 0x119c, 74, 76, 0 ), + V( 76, 0x0f6b, 74, 77, 0 ), + V( 77, 0x0d51, 75, 78, 0 ), + V( 78, 0x0bb6, 77, 79, 0 ), + V( 79, 0x0a40, 77, 48, 0 ), + V( 80, 0x5832, 80, 81, 1 ), + V( 81, 0x4d1c, 88, 82, 0 ), + V( 82, 0x438e, 89, 83, 0 ), + V( 83, 0x3bdd, 90, 84, 0 ), + V( 84, 0x34ee, 91, 85, 0 ), + V( 85, 0x2eae, 92, 86, 0 ), + V( 86, 0x299a, 93, 87, 0 ), + V( 87, 0x2516, 86, 71, 0 ), + V( 88, 0x5570, 88, 89, 1 ), + V( 89, 0x4ca9, 95, 90, 0 ), + V( 90, 0x44d9, 96, 91, 0 ), + V( 91, 0x3e22, 97, 92, 0 ), + V( 92, 0x3824, 99, 93, 0 ), + V( 93, 0x32b4, 99, 94, 0 ), + V( 94, 0x2e17, 93, 86, 0 ), + V( 95, 0x56a8, 95, 96, 1 ), + V( 96, 0x4f46, 101, 97, 0 ), + V( 97, 0x47e5, 102, 98, 0 ), + V( 98, 0x41cf, 103, 99, 0 ), + V( 99, 0x3c3d, 104, 100, 0 ), + V( 100, 0x375e, 99, 93, 0 ), + V( 101, 0x5231, 105, 102, 0 ), + V( 102, 0x4c0f, 106, 103, 0 ), + V( 103, 0x4639, 107, 104, 0 ), + V( 104, 0x415e, 103, 99, 0 ), + V( 105, 0x5627, 105, 106, 1 ), + V( 106, 0x50e7, 108, 107, 0 ), + V( 107, 0x4b85, 109, 103, 0 ), + V( 108, 0x5597, 110, 109, 0 ), + V( 109, 0x504f, 111, 107, 0 ), + V( 110, 0x5a10, 110, 111, 1 ), + V( 111, 0x5522, 112, 109, 0 ), + V( 112, 0x59eb, 112, 111, 1 ), +/* + * This last entry is used for fixed probability estimate of 0.5 + * as suggested in Section 10.3 Table 5 of ITU-T Rec. T.851. + */ + V( 113, 0x5a1d, 113, 113, 0 ) +}; diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcapimin.c b/widget/milsko/milskosrc/external/libjpeg/src/jcapimin.c new file mode 100644 index 0000000000..639ce86f44 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcapimin.c @@ -0,0 +1,288 @@ +/* + * jcapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * Modified 2003-2010 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-compression case or the transcoding-only + * case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jcapistd.c. But also see jcparam.c for + * parameter-setup helper routines, jcomapi.c for routines shared by + * compression and decompression, and jctrans.c for the transcoding case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG compression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_compress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_compress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = FALSE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->dest = NULL; + + cinfo->comp_info = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + cinfo->quant_tbl_ptrs[i] = NULL; + cinfo->q_scale_factor[i] = 100; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Must do it here for emit_dqt in case jpeg_write_tables is used */ + cinfo->block_size = DCTSIZE; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + + cinfo->script_space = NULL; + + cinfo->input_gamma = 1.0; /* in case application forgets */ + + /* OK, I'm ready */ + cinfo->global_state = CSTATE_START; +} + + +/* + * Destruction of a JPEG compression object + */ + +GLOBAL(void) +jpeg_destroy_compress (j_compress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG compression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_compress (j_compress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Forcibly suppress or un-suppress all quantization and Huffman tables. + * Marks all currently defined tables as already written (if suppress) + * or not written (if !suppress). This will control whether they get emitted + * by a subsequent jpeg_start_compress call. + * + * This routine is exported for use by applications that want to produce + * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but + * since it is called by jpeg_start_compress, we put it here --- otherwise + * jcparam.o would be linked whether the application used it or not. + */ + +GLOBAL(void) +jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress) +{ + int i; + JQUANT_TBL * qtbl; + JHUFF_TBL * htbl; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL) + qtbl->sent_table = suppress; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + } +} + + +/* + * Finish JPEG compression. + * + * If a multipass operating mode was selected, this may do a great deal of + * work including most of the actual output. + */ + +GLOBAL(void) +jpeg_finish_compress (j_compress_ptr cinfo) +{ + JDIMENSION iMCU_row; + + if (cinfo->global_state == CSTATE_SCANNING || + cinfo->global_state == CSTATE_RAW_OK) { + /* Terminate first pass */ + if (cinfo->next_scanline < cinfo->image_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_pass) (cinfo); + } else if (cinfo->global_state != CSTATE_WRCOEFS) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any remaining passes */ + while (! cinfo->master->is_last_pass) { + (*cinfo->master->prepare_for_pass) (cinfo); + for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) { + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) iMCU_row; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* We bypass the main controller and invoke coef controller directly; + * all work is being done from the coefficient buffer. + */ + if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + (*cinfo->master->finish_pass) (cinfo); + } + /* Write EOI, do final cleanup */ + (*cinfo->marker->write_file_trailer) (cinfo); + (*cinfo->dest->term_destination) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); +} + + +/* + * Write a special marker. + * This is only recommended for writing COM or APPn markers. + * Must be called after jpeg_start_compress() and before + * first call to jpeg_write_scanlines() or jpeg_write_raw_data(). + */ + +GLOBAL(void) +jpeg_write_marker (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen) +{ + JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val)); + + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); + write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */ + while (datalen--) { + (*write_marker_byte) (cinfo, *dataptr); + dataptr++; + } +} + +/* Same, but piecemeal. */ + +GLOBAL(void) +jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +{ + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); +} + +GLOBAL(void) +jpeg_write_m_byte (j_compress_ptr cinfo, int val) +{ + (*cinfo->marker->write_marker_byte) (cinfo, val); +} + + +/* + * Alternate compression function: just write an abbreviated table file. + * Before calling this, all parameters and a data destination must be set up. + * + * To produce a pair of files containing abbreviated tables and abbreviated + * image data, one would proceed as follows: + * + * initialize JPEG object + * set JPEG parameters + * set destination to table file + * jpeg_write_tables(cinfo); + * set destination to image file + * jpeg_start_compress(cinfo, FALSE); + * write data... + * jpeg_finish_compress(cinfo); + * + * jpeg_write_tables has the side effect of marking all tables written + * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress + * will not re-emit the tables unless it is passed write_all_tables=TRUE. + */ + +GLOBAL(void) +jpeg_write_tables (j_compress_ptr cinfo) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Initialize the marker writer ... bit of a crock to do it here. */ + jinit_marker_writer(cinfo); + /* Write them tables! */ + (*cinfo->marker->write_tables_only) (cinfo); + /* And clean up. */ + (*cinfo->dest->term_destination) (cinfo); + /* + * In library releases up through v6a, we called jpeg_abort() here to free + * any working memory allocated by the destination manager and marker + * writer. Some applications had a problem with that: they allocated space + * of their own from the library memory manager, and didn't want it to go + * away during write_tables. So now we do nothing. This will cause a + * memory leak if an app calls write_tables repeatedly without doing a full + * compression cycle or otherwise resetting the JPEG object. However, that + * seems less bad than unexpectedly freeing memory in the normal case. + * An app that prefers the old behavior can call jpeg_abort for itself after + * each call to jpeg_write_tables(). + */ +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcapistd.c b/widget/milsko/milskosrc/external/libjpeg/src/jcapistd.c new file mode 100644 index 0000000000..0917afa97d --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcapistd.c @@ -0,0 +1,162 @@ +/* + * jcapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2013 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-compression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_compress, it will end up linking in the entire compressor. + * We thus must separate this file from jcapimin.c to avoid linking the + * whole compression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Compression initialization. + * Before calling this, all parameters and a data destination must be set up. + * + * We require a write_all_tables parameter as a failsafe check when writing + * multiple datastreams from the same compression object. Since prior runs + * will have left all the tables marked sent_table=TRUE, a subsequent run + * would emit an abbreviated stream (no tables) by default. This may be what + * is wanted, but for safety's sake it should not be the default behavior: + * programmers should have to make a deliberate choice to emit abbreviated + * images. Therefore the documentation and examples should encourage people + * to pass write_all_tables=TRUE; then it will take active thought to do the + * wrong thing. + */ + +GLOBAL(void) +jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (write_all_tables) + jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + jinit_compress_master(cinfo); + /* Set up for the first pass */ + (*cinfo->master->prepare_for_pass) (cinfo); + /* Ready for application to drive first pass through jpeg_write_scanlines + * or jpeg_write_raw_data. + */ + cinfo->next_scanline = 0; + cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); +} + + +/* + * Write some scanlines of data to the JPEG compressor. + * + * The return value will be the number of lines actually written. + * This should be less than the supplied num_lines only in case that + * the data destination module has requested suspension of the compressor, + * or if more than image_height scanlines are passed in. + * + * Note: we warn about excess calls to jpeg_write_scanlines() since + * this likely signals an application programmer error. However, + * excess scanlines passed in the last valid call are *silently* ignored, + * so that the application need not adjust num_lines for end-of-image + * when using a multiple-scanline buffer. + */ + +GLOBAL(JDIMENSION) +jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION num_lines) +{ + JDIMENSION row_ctr, rows_left; + + if (cinfo->global_state != CSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_scanlines. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_scanlines. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Ignore any extra scanlines at bottom of image. */ + rows_left = cinfo->image_height - cinfo->next_scanline; + if (num_lines > rows_left) + num_lines = rows_left; + + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); + cinfo->next_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to write raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION num_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != CSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_raw_data. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_raw_data. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Verify that at least one iMCU row has been passed. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size; + if (num_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Directly compress the row. */ + if (! (*cinfo->coef->compress_data) (cinfo, data)) { + /* If compressor did not consume the whole row, suspend processing. */ + return 0; + } + + /* OK, we processed one iMCU row. */ + cinfo->next_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcarith.c b/widget/milsko/milskosrc/external/libjpeg/src/jcarith.c new file mode 100644 index 0000000000..1b45089a3a --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcarith.c @@ -0,0 +1,945 @@ +/* + * jcarith.c + * + * Developed 1997-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains portable arithmetic entropy encoding routines for JPEG + * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81). + * + * Both sequential and progressive modes are supported in this single module. + * + * Suspension is not currently supported in this module. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Expanded entropy encoder object for arithmetic encoding. */ + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */ + INT32 a; /* A register, normalized size of coding interval */ + INT32 sc; /* counter for stacked 0xFF values which might overflow */ + INT32 zc; /* counter for pending 0x00 output values which might * + * be discarded at the end ("Pacman" termination) */ + int ct; /* bit shift counter, determines when next byte will be written */ + int buffer; /* buffer for most recent output byte != 0xFF */ + + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to statistics areas (these workspaces have image lifespan) */ + unsigned char * dc_stats[NUM_ARITH_TBLS]; + unsigned char * ac_stats[NUM_ARITH_TBLS]; + + /* Statistics bin for coding with fixed probability 0.5 */ + unsigned char fixed_bin[4]; +} arith_entropy_encoder; + +typedef arith_entropy_encoder * arith_entropy_ptr; + +/* The following two definitions specify the allocation chunk size + * for the statistics area. + * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least + * 49 statistics bins for DC, and 245 statistics bins for AC coding. + * + * We use a compact representation with 1 byte per statistics bin, + * thus the numbers directly represent byte sizes. + * This 1 byte per statistics bin contains the meaning of the MPS + * (more probable symbol) in the highest bit (mask 0x80), and the + * index into the probability estimation state machine table + * in the lower bits (mask 0x7F). + */ + +#define DC_STAT_BINS 64 +#define AC_STAT_BINS 256 + +/* NOTE: Uncomment the following #define if you want to use the + * given formula for calculating the AC conditioning parameter Kx + * for spectral selection progressive coding in section G.1.3.2 + * of the spec (Kx = Kmin + SRL (8 + Se - Kmin) 4). + * Although the spec and P&M authors claim that this "has proven + * to give good results for 8 bit precision samples", I'm not + * convinced yet that this is really beneficial. + * Early tests gave only very marginal compression enhancements + * (a few - around 5 or so - bytes even for very large files), + * which would turn out rather negative if we'd suppress the + * DAC (Define Arithmetic Conditioning) marker segments for + * the default parameters in the future. + * Note that currently the marker writing module emits 12-byte + * DAC segments for a full-component scan in a color image. + * This is not worth worrying about IMHO. However, since the + * spec defines the default values to be used if the tables + * are omitted (unlike Huffman tables, which are required + * anyway), one might optimize this behaviour in the future, + * and then it would be disadvantageous to use custom tables if + * they don't provide sufficient gain to exceed the DAC size. + * + * On the other hand, I'd consider it as a reasonable result + * that the conditioning has no significant influence on the + * compression performance. This means that the basic + * statistical model is already rather stable. + * + * Thus, at the moment, we use the default conditioning values + * anyway, and do not use the custom formula. + * +#define CALCULATE_SPECTRAL_CONDITIONING + */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +LOCAL(void) +emit_byte (int val, j_compress_ptr cinfo) +/* Write next output byte; we do not support suspension in this module. */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *dest->next_output_byte++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); +} + + +/* + * Finish up at the end of an arithmetic-compressed scan. + */ + +METHODDEF(void) +finish_pass (j_compress_ptr cinfo) +{ + arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy; + INT32 temp; + + /* Section D.1.8: Termination of encoding */ + + /* Find the e->c in the coding interval with the largest + * number of trailing zero bits */ + if ((temp = (e->a - 1 + e->c) & 0xFFFF0000L) < e->c) + e->c = temp + 0x8000L; + else + e->c = temp; + /* Send remaining bytes to output */ + e->c <<= e->ct; + if (e->c & 0xF8000000L) { + /* One final overflow has to be handled */ + if (e->buffer >= 0) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte(e->buffer + 1, cinfo); + if (e->buffer + 1 == 0xFF) + emit_byte(0x00, cinfo); + } + e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */ + e->sc = 0; + } else { + if (e->buffer == 0) + ++e->zc; + else if (e->buffer >= 0) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte(e->buffer, cinfo); + } + if (e->sc) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + do { + emit_byte(0xFF, cinfo); + emit_byte(0x00, cinfo); + } while (--e->sc); + } + } + /* Output final bytes only if they are not 0x00 */ + if (e->c & 0x7FFF800L) { + if (e->zc) /* output final pending zero bytes */ + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte((int) ((e->c >> 19) & 0xFF), cinfo); + if (((e->c >> 19) & 0xFF) == 0xFF) + emit_byte(0x00, cinfo); + if (e->c & 0x7F800L) { + emit_byte((int) ((e->c >> 11) & 0xFF), cinfo); + if (((e->c >> 11) & 0xFF) == 0xFF) + emit_byte(0x00, cinfo); + } + } +} + + +/* + * The core arithmetic encoding routine (common in JPEG and JBIG). + * This needs to go as fast as possible. + * Machine-dependent optimization facilities + * are not utilized in this portable implementation. + * However, this code should be fairly efficient and + * may be a good base for further optimizations anyway. + * + * Parameter 'val' to be encoded may be 0 or 1 (binary decision). + * + * Note: I've added full "Pacman" termination support to the + * byte output routines, which is equivalent to the optional + * Discard_final_zeros procedure (Figure D.15) in the spec. + * Thus, we always produce the shortest possible output + * stream compliant to the spec (no trailing zero bytes, + * except for FF stuffing). + * + * I've also introduced a new scheme for accessing + * the probability estimation state machine table, + * derived from Markus Kuhn's JBIG implementation. + */ + +LOCAL(void) +arith_encode (j_compress_ptr cinfo, unsigned char *st, int val) +{ + register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy; + register unsigned char nl, nm; + register INT32 qe, temp; + register int sv; + + /* Fetch values from our compact representation of Table D.3(D.2): + * Qe values and probability estimation state machine + */ + sv = *st; + qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */ + nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */ + nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */ + + /* Encode & estimation procedures per sections D.1.4 & D.1.5 */ + e->a -= qe; + if (val != (sv >> 7)) { + /* Encode the less probable symbol */ + if (e->a >= qe) { + /* If the interval size (qe) for the less probable symbol (LPS) + * is larger than the interval size for the MPS, then exchange + * the two symbols for coding efficiency, otherwise code the LPS + * as usual: */ + e->c += e->a; + e->a = qe; + } + *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ + } else { + /* Encode the more probable symbol */ + if (e->a >= 0x8000L) + return; /* A >= 0x8000 -> ready, no renormalization required */ + if (e->a < qe) { + /* If the interval size (qe) for the less probable symbol (LPS) + * is larger than the interval size for the MPS, then exchange + * the two symbols for coding efficiency: */ + e->c += e->a; + e->a = qe; + } + *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ + } + + /* Renormalization & data output per section D.1.6 */ + do { + e->a <<= 1; + e->c <<= 1; + if (--e->ct == 0) { + /* Another byte is ready for output */ + temp = e->c >> 19; + if (temp > 0xFF) { + /* Handle overflow over all stacked 0xFF bytes */ + if (e->buffer >= 0) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte(e->buffer + 1, cinfo); + if (e->buffer + 1 == 0xFF) + emit_byte(0x00, cinfo); + } + e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */ + e->sc = 0; + /* Note: The 3 spacer bits in the C register guarantee + * that the new buffer byte can't be 0xFF here + * (see page 160 in the P&M JPEG book). */ + /* New output byte, might overflow later */ + e->buffer = (int) (temp & 0xFF); + } else if (temp == 0xFF) { + ++e->sc; /* stack 0xFF byte (which might overflow later) */ + } else { + /* Output all stacked 0xFF bytes, they will not overflow any more */ + if (e->buffer == 0) + ++e->zc; + else if (e->buffer >= 0) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte(e->buffer, cinfo); + } + if (e->sc) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + do { + emit_byte(0xFF, cinfo); + emit_byte(0x00, cinfo); + } while (--e->sc); + } + /* New output byte (can still overflow) */ + e->buffer = (int) (temp & 0xFF); + } + e->c &= 0x7FFFFL; + e->ct += 8; + } + } while (e->a < 0x8000L); +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(void) +emit_restart (j_compress_ptr cinfo, int restart_num) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + int ci; + jpeg_component_info * compptr; + + finish_pass(cinfo); + + emit_byte(0xFF, cinfo); + emit_byte(JPEG_RST0 + restart_num, cinfo); + + /* Re-initialize statistics areas */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) { + MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS); + /* Reset DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + entropy->dc_context[ci] = 0; + } + /* AC needs no table when not present */ + if (cinfo->Se) { + MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS); + } + } + + /* Reset arithmetic encoding variables */ + entropy->c = 0; + entropy->a = 0x10000L; + entropy->sc = 0; + entropy->zc = 0; + entropy->ct = 11; + entropy->buffer = -1; /* empty */ +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + unsigned char *st; + int blkn, ci, tbl; + int v, v2, m; + ISHIFT_TEMPS + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + tbl = cinfo->cur_comp_info[ci]->dc_tbl_no; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + m = IRIGHT_SHIFT((int) (MCU_data[blkn][0][0]), cinfo->Al); + + /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */ + + /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ + st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; + + /* Figure F.4: Encode_DC_DIFF */ + if ((v = m - entropy->last_dc_val[ci]) == 0) { + arith_encode(cinfo, st, 0); + entropy->dc_context[ci] = 0; /* zero diff category */ + } else { + entropy->last_dc_val[ci] = m; + arith_encode(cinfo, st, 1); + /* Figure F.6: Encoding nonzero value v */ + /* Figure F.7: Encoding the sign of v */ + if (v > 0) { + arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */ + st += 2; /* Table F.4: SP = S0 + 2 */ + entropy->dc_context[ci] = 4; /* small positive diff category */ + } else { + v = -v; + arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */ + st += 3; /* Table F.4: SN = S0 + 3 */ + entropy->dc_context[ci] = 8; /* small negative diff category */ + } + /* Figure F.8: Encoding the magnitude category of v */ + m = 0; + if (v -= 1) { + arith_encode(cinfo, st, 1); + m = 1; + v2 = v; + st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ + while (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st += 1; + } + } + arith_encode(cinfo, st, 0); + /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ + if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) + entropy->dc_context[ci] = 0; /* zero diff category */ + else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) + entropy->dc_context[ci] += 8; /* large diff category */ + /* Figure F.9: Encoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + arith_encode(cinfo, st, (m & v) ? 1 : 0); + } + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + const int * natural_order; + JBLOCKROW block; + unsigned char *st; + int tbl, k, ke; + int v, v2, m; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + natural_order = cinfo->natural_order; + + /* Encode the MCU data block */ + block = MCU_data[0]; + tbl = cinfo->cur_comp_info[0]->ac_tbl_no; + + /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */ + + /* Establish EOB (end-of-block) index */ + ke = cinfo->Se; + do { + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if ((v = (*block)[natural_order[ke]]) >= 0) { + if (v >>= cinfo->Al) break; + } else { + v = -v; + if (v >>= cinfo->Al) break; + } + } while (--ke); + + /* Figure F.5: Encode_AC_Coefficients */ + for (k = cinfo->Ss - 1; k < ke;) { + st = entropy->ac_stats[tbl] + 3 * k; + arith_encode(cinfo, st, 0); /* EOB decision */ + for (;;) { + if ((v = (*block)[natural_order[++k]]) >= 0) { + if (v >>= cinfo->Al) { + arith_encode(cinfo, st + 1, 1); + arith_encode(cinfo, entropy->fixed_bin, 0); + break; + } + } else { + v = -v; + if (v >>= cinfo->Al) { + arith_encode(cinfo, st + 1, 1); + arith_encode(cinfo, entropy->fixed_bin, 1); + break; + } + } + arith_encode(cinfo, st + 1, 0); + st += 3; + } + st += 2; + /* Figure F.8: Encoding the magnitude category of v */ + m = 0; + if (v -= 1) { + arith_encode(cinfo, st, 1); + m = 1; + v2 = v; + if (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st = entropy->ac_stats[tbl] + + (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); + while (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st += 1; + } + } + } + arith_encode(cinfo, st, 0); + /* Figure F.9: Encoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + arith_encode(cinfo, st, (m & v) ? 1 : 0); + } + /* Encode EOB decision only if k < cinfo->Se */ + if (k < cinfo->Se) { + st = entropy->ac_stats[tbl] + 3 * k; + arith_encode(cinfo, st, 1); + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, + * although the spec is not very clear on the point. + */ + +METHODDEF(boolean) +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + unsigned char *st; + int Al, blkn; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + st = entropy->fixed_bin; /* use fixed probability estimation */ + Al = cinfo->Al; + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + /* We simply emit the Al'th bit of the DC coefficient value. */ + arith_encode(cinfo, st, (MCU_data[blkn][0][0] >> Al) & 1); + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + const int * natural_order; + JBLOCKROW block; + unsigned char *st; + int tbl, k, ke, kex; + int v; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + natural_order = cinfo->natural_order; + + /* Encode the MCU data block */ + block = MCU_data[0]; + tbl = cinfo->cur_comp_info[0]->ac_tbl_no; + + /* Section G.1.3.3: Encoding of AC coefficients */ + + /* Establish EOB (end-of-block) index */ + ke = cinfo->Se; + do { + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if ((v = (*block)[natural_order[ke]]) >= 0) { + if (v >>= cinfo->Al) break; + } else { + v = -v; + if (v >>= cinfo->Al) break; + } + } while (--ke); + + /* Establish EOBx (previous stage end-of-block) index */ + for (kex = ke; kex > 0; kex--) + if ((v = (*block)[natural_order[kex]]) >= 0) { + if (v >>= cinfo->Ah) break; + } else { + v = -v; + if (v >>= cinfo->Ah) break; + } + + /* Figure G.10: Encode_AC_Coefficients_SA */ + for (k = cinfo->Ss - 1; k < ke;) { + st = entropy->ac_stats[tbl] + 3 * k; + if (k >= kex) + arith_encode(cinfo, st, 0); /* EOB decision */ + for (;;) { + if ((v = (*block)[natural_order[++k]]) >= 0) { + if (v >>= cinfo->Al) { + if (v >> 1) /* previously nonzero coef */ + arith_encode(cinfo, st + 2, (v & 1)); + else { /* newly nonzero coef */ + arith_encode(cinfo, st + 1, 1); + arith_encode(cinfo, entropy->fixed_bin, 0); + } + break; + } + } else { + v = -v; + if (v >>= cinfo->Al) { + if (v >> 1) /* previously nonzero coef */ + arith_encode(cinfo, st + 2, (v & 1)); + else { /* newly nonzero coef */ + arith_encode(cinfo, st + 1, 1); + arith_encode(cinfo, entropy->fixed_bin, 1); + } + break; + } + } + arith_encode(cinfo, st + 1, 0); + st += 3; + } + } + /* Encode EOB decision only if k < cinfo->Se */ + if (k < cinfo->Se) { + st = entropy->ac_stats[tbl] + 3 * k; + arith_encode(cinfo, st, 1); + } + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of arithmetic-compressed coefficients. + */ + +METHODDEF(boolean) +encode_mcu (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + const int * natural_order; + JBLOCKROW block; + unsigned char *st; + int tbl, k, ke; + int v, v2, m; + int blkn, ci; + jpeg_component_info * compptr; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + natural_order = cinfo->natural_order; + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */ + + tbl = compptr->dc_tbl_no; + + /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ + st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; + + /* Figure F.4: Encode_DC_DIFF */ + if ((v = (*block)[0] - entropy->last_dc_val[ci]) == 0) { + arith_encode(cinfo, st, 0); + entropy->dc_context[ci] = 0; /* zero diff category */ + } else { + entropy->last_dc_val[ci] = (*block)[0]; + arith_encode(cinfo, st, 1); + /* Figure F.6: Encoding nonzero value v */ + /* Figure F.7: Encoding the sign of v */ + if (v > 0) { + arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */ + st += 2; /* Table F.4: SP = S0 + 2 */ + entropy->dc_context[ci] = 4; /* small positive diff category */ + } else { + v = -v; + arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */ + st += 3; /* Table F.4: SN = S0 + 3 */ + entropy->dc_context[ci] = 8; /* small negative diff category */ + } + /* Figure F.8: Encoding the magnitude category of v */ + m = 0; + if (v -= 1) { + arith_encode(cinfo, st, 1); + m = 1; + v2 = v; + st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ + while (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st += 1; + } + } + arith_encode(cinfo, st, 0); + /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ + if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) + entropy->dc_context[ci] = 0; /* zero diff category */ + else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) + entropy->dc_context[ci] += 8; /* large diff category */ + /* Figure F.9: Encoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + arith_encode(cinfo, st, (m & v) ? 1 : 0); + } + + /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */ + + if ((ke = cinfo->lim_Se) == 0) continue; + tbl = compptr->ac_tbl_no; + + /* Establish EOB (end-of-block) index */ + do { + if ((*block)[natural_order[ke]]) break; + } while (--ke); + + /* Figure F.5: Encode_AC_Coefficients */ + for (k = 0; k < ke;) { + st = entropy->ac_stats[tbl] + 3 * k; + arith_encode(cinfo, st, 0); /* EOB decision */ + while ((v = (*block)[natural_order[++k]]) == 0) { + arith_encode(cinfo, st + 1, 0); + st += 3; + } + arith_encode(cinfo, st + 1, 1); + /* Figure F.6: Encoding nonzero value v */ + /* Figure F.7: Encoding the sign of v */ + if (v > 0) { + arith_encode(cinfo, entropy->fixed_bin, 0); + } else { + v = -v; + arith_encode(cinfo, entropy->fixed_bin, 1); + } + st += 2; + /* Figure F.8: Encoding the magnitude category of v */ + m = 0; + if (v -= 1) { + arith_encode(cinfo, st, 1); + m = 1; + v2 = v; + if (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st = entropy->ac_stats[tbl] + + (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); + while (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st += 1; + } + } + } + arith_encode(cinfo, st, 0); + /* Figure F.9: Encoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + arith_encode(cinfo, st, (m & v) ? 1 : 0); + } + /* Encode EOB decision only if k < cinfo->lim_Se */ + if (k < cinfo->lim_Se) { + st = entropy->ac_stats[tbl] + 3 * k; + arith_encode(cinfo, st, 1); + } + } + + return TRUE; +} + + +/* + * Initialize for an arithmetic-compressed scan. + */ + +METHODDEF(void) +start_pass (j_compress_ptr cinfo, boolean gather_statistics) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + int ci, tbl; + jpeg_component_info * compptr; + + if (gather_statistics) + /* Make sure to avoid that in the master control logic! + * We are fully adaptive here and need no extra + * statistics gathering pass! + */ + ERREXIT(cinfo, JERR_NOT_COMPILED); + + /* We assume jcmaster.c already validated the progressive scan parameters. */ + + /* Select execution routines */ + if (cinfo->progressive_mode) { + if (cinfo->Ah == 0) { + if (cinfo->Ss == 0) + entropy->pub.encode_mcu = encode_mcu_DC_first; + else + entropy->pub.encode_mcu = encode_mcu_AC_first; + } else { + if (cinfo->Ss == 0) + entropy->pub.encode_mcu = encode_mcu_DC_refine; + else + entropy->pub.encode_mcu = encode_mcu_AC_refine; + } + } else + entropy->pub.encode_mcu = encode_mcu; + + /* Allocate & initialize requested statistics areas */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) { + tbl = compptr->dc_tbl_no; + if (tbl < 0 || tbl >= NUM_ARITH_TBLS) + ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); + if (entropy->dc_stats[tbl] == NULL) + entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS); + MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS); + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + entropy->dc_context[ci] = 0; + } + /* AC needs no table when not present */ + if (cinfo->Se) { + tbl = compptr->ac_tbl_no; + if (tbl < 0 || tbl >= NUM_ARITH_TBLS) + ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); + if (entropy->ac_stats[tbl] == NULL) + entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS); + MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS); +#ifdef CALCULATE_SPECTRAL_CONDITIONING + if (cinfo->progressive_mode) + /* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */ + cinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4); +#endif + } + } + + /* Initialize arithmetic encoding variables */ + entropy->c = 0; + entropy->a = 0x10000L; + entropy->sc = 0; + entropy->zc = 0; + entropy->ct = 11; + entropy->buffer = -1; /* empty */ + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* + * Module initialization routine for arithmetic entropy encoding. + */ + +GLOBAL(void) +jinit_arith_encoder (j_compress_ptr cinfo) +{ + arith_entropy_ptr entropy; + int i; + + entropy = (arith_entropy_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(arith_entropy_encoder)); + cinfo->entropy = &entropy->pub; + entropy->pub.start_pass = start_pass; + entropy->pub.finish_pass = finish_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + entropy->dc_stats[i] = NULL; + entropy->ac_stats[i] = NULL; + } + + /* Initialize index for fixed probability estimation */ + entropy->fixed_bin[0] = 113; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jccoefct.c b/widget/milsko/milskosrc/external/libjpeg/src/jccoefct.c new file mode 100644 index 0000000000..494aa22988 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jccoefct.c @@ -0,0 +1,456 @@ +/* + * jccoefct.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 2003-2022 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for compression. + * This controller is the top level of the JPEG compressor proper. + * The coefficient buffer lies between forward-DCT and entropy encoding steps. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* We use a full-image coefficient buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the DCT + * step is run during the first pass, and subsequent passes need only read + * the buffered coefficients. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* For single-pass compression, it's sufficient to buffer just one MCU + * (although this may prove a bit slow in practice). + * We append a workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, + * and reuse it for each MCU constructed and sent. + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays. + */ + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; + + /* Workspace for single-pass compression (omitted otherwise). */ + JBLOCK blk_buffer[C_MAX_BLOCKS_IN_MCU]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +/* Forward declarations */ +METHODDEF(boolean) compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_COEF_BUFFER_SUPPORTED +METHODDEF(boolean) compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF(boolean) compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (coef->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_data; + break; +#ifdef FULL_COEF_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + } +} + + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(boolean) +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int ci, xindex, yindex, yoffset, blockcnt; + JBLOCKROW blkp; + JSAMPARRAY input_ptr; + JDIMENSION xpos; + jpeg_component_info *compptr; + forward_DCT_ptr forward_DCT; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Determine where data comes from in input_buf and do the DCT thing. + * Each call on forward_DCT processes a horizontal row of DCT blocks as + * wide as an MCU. Dummy blocks at the right or bottom edge are filled in + * specially. The data in them does not matter for image reconstruction, + * so we fill them with values that will encode to the smallest amount of + * data, viz: all zeroes in the AC entries, DC entries equal to previous + * block's DC value. (Thanks to Thomas Kinsman for this idea.) + */ + blkp = coef->blk_buffer; /* pointer to current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + forward_DCT = cinfo->fdct->forward_DCT[compptr->component_index]; + input_ptr = input_buf[compptr->component_index] + + yoffset * compptr->DCT_v_scaled_size; + /* ypos == (yoffset + yindex) * compptr->DCT_v_scaled_size */ + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + xpos = MCU_col_num * compptr->MCU_sample_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yoffset + yindex < compptr->last_row_height) { + (*forward_DCT) (cinfo, compptr, input_ptr, blkp, + xpos, (JDIMENSION) blockcnt); + input_ptr += compptr->DCT_v_scaled_size; + blkp += blockcnt; + /* Dummy blocks at right edge */ + if ((xindex = compptr->MCU_width - blockcnt) == 0) + continue; + } else { + /* At bottom of image, need a whole row of dummy blocks */ + xindex = compptr->MCU_width; + } + /* Fill in any dummy blocks needed in this row */ + MEMZERO(blkp, xindex * SIZEOF(JBLOCK)); + do { + blkp[0][0] = blkp[-1][0]; + blkp++; + } while (--xindex); + } + } + /* Try to write the MCU. In event of a suspension failure, we will + * re-DCT the MCU on restart (a bit inefficient, could be fixed...) + */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_COEF_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * This amount of data is read from the source buffer, DCT'd and quantized, + * and saved into the virtual arrays. We also generate suitable dummy blocks + * as needed at the right and lower edges. (The dummy blocks are constructed + * in the virtual arrays, which have been padded appropriately.) This makes + * it possible for subsequent passes not to worry about real vs. dummy blocks. + * + * We must also emit the data to the entropy encoder. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All + * components are DCT'd and loaded into the virtual arrays in this pass. + * However, it may be that only a subset of the components are emitted to + * the entropy encoder during this first pass; be careful about looking + * at the scan-dependent variables (MCU dimensions, etc). + */ + +METHODDEF(boolean) +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION blocks_across, MCUs_across, MCUindex; + int bi, ci, h_samp_factor, block_row, block_rows, ndummy; + JCOEF lastDC; + jpeg_component_info *compptr; + JBLOCKARRAY buffer; + JBLOCKROW thisblockrow, lastblockrow; + JSAMPARRAY input_ptr; + forward_DCT_ptr forward_DCT; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (coef->iMCU_row_num < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + blocks_across = compptr->width_in_blocks; + h_samp_factor = compptr->h_samp_factor; + /* Count number of dummy blocks to be added at the right margin. */ + ndummy = (int) (blocks_across % h_samp_factor); + if (ndummy > 0) + ndummy = h_samp_factor - ndummy; + forward_DCT = cinfo->fdct->forward_DCT[ci]; + input_ptr = input_buf[ci]; + /* Perform DCT for all non-dummy blocks in this iMCU row. Each call + * on forward_DCT processes a complete horizontal row of DCT blocks. + */ + for (block_row = 0; block_row < block_rows; block_row++) { + thisblockrow = buffer[block_row]; + (*forward_DCT) (cinfo, compptr, input_ptr, thisblockrow, + (JDIMENSION) 0, blocks_across); + input_ptr += compptr->DCT_v_scaled_size; + if (ndummy > 0) { + /* Create dummy blocks at the right edge of the image. */ + thisblockrow += blocks_across; /* => first dummy block */ + FMEMZERO((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK)); + lastDC = thisblockrow[-1][0]; + for (bi = 0; bi < ndummy; bi++) { + thisblockrow[bi][0] = lastDC; + } + } + } + /* If at end of image, create dummy block rows as needed. + * The tricky part here is that within each MCU, we want the DC values + * of the dummy blocks to match the last real block's DC value. + * This squeezes a few more bytes out of the resulting file... + */ + if (block_row < compptr->v_samp_factor) { + blocks_across += ndummy; /* include lower right corner */ + MCUs_across = blocks_across / h_samp_factor; + do { + thisblockrow = buffer[block_row]; + lastblockrow = buffer[block_row-1]; + FMEMZERO((void FAR *) thisblockrow, + (size_t) blocks_across * SIZEOF(JBLOCK)); + for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) { + lastDC = lastblockrow[h_samp_factor-1][0]; + for (bi = 0; bi < h_samp_factor; bi++) { + thisblockrow[bi][0] = lastDC; + } + thisblockrow += h_samp_factor; /* advance to next MCU in row */ + lastblockrow += h_samp_factor; + } + } while (++block_row < compptr->v_samp_factor); + } + } + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the entropy encoder, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY blkp; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkp = coef->MCU_buffer; /* pointer to current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yoffset + yindex] + start_col; + xindex = compptr->MCU_width; + do { + *blkp++ = buffer_ptr++; + } while (--xindex); + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + +#endif /* FULL_COEF_BUFFER_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + if (need_full_buffer) { +#ifdef FULL_COEF_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + int ci; + jpeg_component_info *compptr; + + coef = (my_coef_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller) - SIZEOF(coef->blk_buffer)); + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKARRAY blkp; + JBLOCKROW buffer_ptr; + int bi; + + coef = (my_coef_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_coef_controller)); + blkp = coef->MCU_buffer; + buffer_ptr = coef->blk_buffer; + bi = C_MAX_BLOCKS_IN_MCU; + do { + *blkp++ = buffer_ptr++; + } while (--bi); + coef->whole_image[0] = NULL; /* flag for no virtual arrays */ + } + + coef->pub.start_pass = start_pass_coef; + cinfo->coef = &coef->pub; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jccolor.c b/widget/milsko/milskosrc/external/libjpeg/src/jccolor.c new file mode 100644 index 0000000000..c028dd9db3 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jccolor.c @@ -0,0 +1,598 @@ +/* + * jccolor.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2011-2023 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_converter pub; /* public fields */ + + /* Private state for RGB->YCC conversion */ + INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */ +} my_color_converter; + +typedef my_color_converter * my_cconvert_ptr; + + +/**************** RGB -> YCbCr conversion: most common case **************/ + +/* + * YCbCr is defined per Recommendation ITU-R BT.601-7 (03/2011), + * previously known as Recommendation CCIR 601-1, except that Cb and Cr + * are normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * sRGB (standard RGB color space) is defined per IEC 61966-2-1:1999. + * sYCC (standard luma-chroma-chroma color space with extended gamut) + * is defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex F. + * bg-sRGB and bg-sYCC (big gamut standard color spaces) + * are defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex G. + * Note that the derived conversion coefficients given in some of these + * documents are imprecise. The general conversion equations are + * Y = Kr * R + (1 - Kr - Kb) * G + Kb * B + * Cb = (B - Y) / (1 - Kb) / K + * Cr = (R - Y) / (1 - Kr) / K + * With Kr = 0.299 and Kb = 0.114 (derived according to SMPTE RP 177-1993 + * from the 1953 FCC NTSC primaries and CIE Illuminant C), K = 2 for sYCC, + * the conversion equations to be implemented are therefore + * Y = 0.299 * R + 0.587 * G + 0.114 * B + * Cb = -0.168735892 * R - 0.331264108 * G + 0.5 * B + CENTERJSAMPLE + * Cr = 0.5 * R - 0.418687589 * G - 0.081312411 * B + CENTERJSAMPLE + * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, + * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and + * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) + * were not represented exactly. Now we sacrifice exact representation of + * maximum red and maximum blue in order to get exact grayscales. + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times R,G,B for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 9-bit to 12-bit samples it is still acceptable. It's not very + * reasonable for 16-bit samples, but if you want lossless storage + * you shouldn't be changing colorspace anyway. + * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included + * in the tables to save adding them separately in the inner loop. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS) +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L< Y section */ +#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ +#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ +#define R_CB_OFF (3*(MAXJSAMPLE+1)) +#define G_CB_OFF (4*(MAXJSAMPLE+1)) +#define B_CB_OFF (5*(MAXJSAMPLE+1)) +#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */ +#define G_CR_OFF (6*(MAXJSAMPLE+1)) +#define B_CR_OFF (7*(MAXJSAMPLE+1)) +#define TABLE_SIZE (8*(MAXJSAMPLE+1)) + + +/* + * Initialize for RGB->YCC colorspace conversion. + */ + +METHODDEF(void) +rgb_ycc_start (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 * rgb_ycc_tab; + INT32 i; + + /* Allocate and fill in the conversion tables. */ + cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + TABLE_SIZE * SIZEOF(INT32)); + + for (i = 0; i <= MAXJSAMPLE; i++) { + rgb_ycc_tab[i+R_Y_OFF] = FIX(0.299) * i; + rgb_ycc_tab[i+G_Y_OFF] = FIX(0.587) * i; + rgb_ycc_tab[i+B_Y_OFF] = FIX(0.114) * i + ONE_HALF; + rgb_ycc_tab[i+R_CB_OFF] = (- FIX(0.168735892)) * i; + rgb_ycc_tab[i+G_CB_OFF] = (- FIX(0.331264108)) * i; + /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. + * This ensures that the maximum output will round to MAXJSAMPLE + * not MAXJSAMPLE+1, and thus that we don't have to range-limit. + */ + rgb_ycc_tab[i+B_CB_OFF] = (i << (SCALEBITS-1)) + CBCR_OFFSET + ONE_HALF-1; +/* B=>Cb and R=>Cr tables are the same + rgb_ycc_tab[i+R_CR_OFF] = (i << (SCALEBITS-1)) + CBCR_OFFSET + ONE_HALF-1; +*/ + rgb_ycc_tab[i+G_CR_OFF] = (- FIX(0.418687589)) * i; + rgb_ycc_tab[i+B_CR_OFF] = (- FIX(0.081312411)) * i; + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * + * Note that we change from the application's interleaved-pixel format + * to our internal noninterleaved, one-plane-per-component format. The + * input buffer is therefore three times as wide as the output buffer. + * + * A starting row offset is provided only for the output buffer. The + * caller can easily adjust the passed input_buf value to accommodate + * any row offset required on that side. + */ + +METHODDEF(void) +rgb_ycc_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/**************** Cases other than RGB -> YCbCr **************/ + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles RGB->grayscale conversion, + * which is the same as the RGB->Y portion of RGB->YCbCr. + * We assume rgb_ycc_start has been called (we only use the Y tables). + */ + +METHODDEF(void) +rgb_gray_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register INT32 y; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row++]; + for (col = 0; col < num_cols; col++) { + y = ctab[R_Y_OFF + GETJSAMPLE(inptr[RGB_RED])]; + y += ctab[G_Y_OFF + GETJSAMPLE(inptr[RGB_GREEN])]; + y += ctab[B_Y_OFF + GETJSAMPLE(inptr[RGB_BLUE])]; + inptr += RGB_PIXELSIZE; + outptr[col] = (JSAMPLE) (y >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles Adobe-style CMYK->YCCK conversion, + * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the + * same conversion as above, while passing K (black) unchanged. + * We assume rgb_ycc_start has been called. + */ + +METHODDEF(void) +cmyk_ycck_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2, outptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + outptr3 = output_buf[3][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = MAXJSAMPLE - GETJSAMPLE(inptr[0]); + g = MAXJSAMPLE - GETJSAMPLE(inptr[1]); + b = MAXJSAMPLE - GETJSAMPLE(inptr[2]); + /* K passes through as-is */ + outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */ + inptr += 4; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * [R,G,B] to [R-G,G,B-G] conversion with modulo calculation + * (forward reversible color transform). + * This can be seen as an adaption of the general RGB->YCbCr + * conversion equation with Kr = Kb = 0, while replacing the + * normalization by modulo calculation. + */ + +METHODDEF(void) +rgb_rgb1_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register int r, g, b; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD + * (modulo) operator is equivalent to the bitmask operator AND. + */ + outptr0[col] = (JSAMPLE) ((r - g + CENTERJSAMPLE) & MAXJSAMPLE); + outptr1[col] = (JSAMPLE) g; + outptr2[col] = (JSAMPLE) ((b - g + CENTERJSAMPLE) & MAXJSAMPLE); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles grayscale output with no conversion. + * The source can be either plain grayscale or YCC (since Y == gray). + */ + +METHODDEF(void) +grayscale_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION count; + register int instride = cinfo->input_components; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row++]; + for (count = num_cols; count > 0; count--) { + *outptr++ = *inptr; /* don't need GETJSAMPLE() here */ + inptr += instride; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * No colorspace conversion, but change from interleaved + * to separate-planes representation. + */ + +METHODDEF(void) +rgb_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr0[col] = inptr[RGB_RED]; + outptr1[col] = inptr[RGB_GREEN]; + outptr2[col] = inptr[RGB_BLUE]; + inptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + * We assume input_components == num_components. + */ + +METHODDEF(void) +null_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION count; + register int num_comps = cinfo->num_components; + JDIMENSION num_cols = cinfo->image_width; + int ci; + + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + for (ci = 0; ci < num_comps; ci++) { + inptr = input_buf[0] + ci; + outptr = output_buf[ci][output_row]; + for (count = num_cols; count > 0; count--) { + *outptr++ = *inptr; /* don't need GETJSAMPLE() here */ + inptr += num_comps; + } + } + input_buf++; + output_row++; + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +null_method (j_compress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for input colorspace conversion. + */ + +GLOBAL(void) +jinit_color_converter (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + + cconvert = (my_cconvert_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_color_converter)); + cinfo->cconvert = &cconvert->pub; + /* set start_pass to null method until we find out differently */ + cconvert->pub.start_pass = null_method; + + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_RGB: + case JCS_BG_RGB: +#if RGB_PIXELSIZE != 3 + if (cinfo->input_components != RGB_PIXELSIZE) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; +#endif /* else share code with YCbCr */ + + case JCS_YCbCr: + case JCS_BG_YCC: + if (cinfo->input_components != 3) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->input_components != 4) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->input_components < 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + } + + /* Support color transform only for RGB colorspaces */ + if (cinfo->color_transform && + cinfo->jpeg_color_space != JCS_RGB && + cinfo->jpeg_color_space != JCS_BG_RGB) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + case JCS_YCbCr: + case JCS_BG_YCC: + cconvert->pub.color_convert = grayscale_convert; + break; + case JCS_RGB: + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_gray_convert; + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + + case JCS_RGB: + case JCS_BG_RGB: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space != cinfo->jpeg_color_space) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + switch (cinfo->color_transform) { + case JCT_NONE: + cconvert->pub.color_convert = rgb_convert; + break; + case JCT_SUBTRACT_GREEN: + cconvert->pub.color_convert = rgb_rgb1_convert; + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + switch (cinfo->in_color_space) { + case JCS_RGB: + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_ycc_convert; + break; + case JCS_YCbCr: + cconvert->pub.color_convert = null_convert; + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + + case JCS_BG_YCC: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + switch (cinfo->in_color_space) { + case JCS_RGB: + /* For conversion from normal RGB input to BG_YCC representation, + * the Cb/Cr values are first computed as usual, and then + * quantized further after DCT processing by a factor of + * 2 in reference to the nominal quantization factor. + */ + /* need quantization scale by factor of 2 after DCT */ + cinfo->comp_info[1].component_needed = TRUE; + cinfo->comp_info[2].component_needed = TRUE; + /* compute normal YCC first */ + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_ycc_convert; + break; + case JCS_YCbCr: + /* need quantization scale by factor of 2 after DCT */ + cinfo->comp_info[1].component_needed = TRUE; + cinfo->comp_info[2].component_needed = TRUE; + /*FALLTHROUGH*/ + case JCS_BG_YCC: + /* Pass through for BG_YCC input */ + cconvert->pub.color_convert = null_convert; + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + + case JCS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space != JCS_CMYK) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cconvert->pub.color_convert = null_convert; + break; + + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + switch (cinfo->in_color_space) { + case JCS_CMYK: + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = cmyk_ycck_convert; + break; + case JCS_YCCK: + cconvert->pub.color_convert = null_convert; + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + + default: /* allow null conversion of JCS_UNKNOWN */ + if (cinfo->jpeg_color_space != cinfo->in_color_space || + cinfo->num_components != cinfo->input_components) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cconvert->pub.color_convert = null_convert; + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcdctmgr.c b/widget/milsko/milskosrc/external/libjpeg/src/jcdctmgr.c new file mode 100644 index 0000000000..a48ccd8147 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcdctmgr.c @@ -0,0 +1,466 @@ +/* + * jcdctmgr.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2003-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the forward-DCT management logic. + * This code selects a particular DCT implementation to be used, + * and it performs related housekeeping chores including coefficient + * quantization. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_forward_dct pub; /* public fields */ + + /* Pointer to the DCT routine actually in use */ + forward_DCT_method_ptr do_dct[MAX_COMPONENTS]; + +#ifdef DCT_FLOAT_SUPPORTED + /* Same as above for the floating-point case. */ + float_DCT_method_ptr do_float_dct[MAX_COMPONENTS]; +#endif +} my_fdct_controller; + +typedef my_fdct_controller * my_fdct_ptr; + + +/* The allocated post-DCT divisor tables -- big enough for any + * supported variant and not identical to the quant table entries, + * because of scaling (especially for an unnormalized DCT) -- + * are pointed to by dct_table in the per-component comp_info + * structures. Each table is given in normal array order. + */ + +typedef union { + DCTELEM int_array[DCTSIZE2]; +#ifdef DCT_FLOAT_SUPPORTED + FAST_FLOAT float_array[DCTSIZE2]; +#endif +} divisor_table; + + +/* The current scaled-DCT routines require ISLOW-style divisor tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef DCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Perform forward DCT on one or more blocks of a component. + * + * The input samples are taken from the sample_data[] array starting at + * position start_col, and moving to the right for any additional blocks. + * The quantized coefficients are returned in coef_blocks[]. + */ + +METHODDEF(void) +forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_col, JDIMENSION num_blocks) +/* This version is used for integer DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + forward_DCT_method_ptr do_dct = fdct->do_dct[compptr->component_index]; + DCTELEM * divisors = (DCTELEM *) compptr->dct_table; + DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) { + /* Perform the DCT */ + (*do_dct) (workspace, sample_data, start_col); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register DCTELEM temp, qval; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + qval = divisors[i]; + temp = workspace[i]; + /* Divide the coefficient value by qval, ensuring proper rounding. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * + * In most files, at least half of the output values will be zero + * (at default quantization settings, more like three-quarters...) + * so we should ensure that this case is fast. On many machines, + * a comparison is enough cheaper than a divide to make a special test + * a win. Since both inputs will be nonnegative, we need only test + * for a < b to discover whether a/b is 0. + * If your machine's division is fast enough, define FAST_DIVIDE. + */ +#ifdef FAST_DIVIDE +#define DIVIDE_BY(a,b) a /= b +#else +#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 +#endif + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + } + output_ptr[i] = (JCOEF) temp; + } + } + } +} + + +#ifdef DCT_FLOAT_SUPPORTED + +METHODDEF(void) +forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_col, JDIMENSION num_blocks) +/* This version is used for floating-point DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + float_DCT_method_ptr do_dct = fdct->do_float_dct[compptr->component_index]; + FAST_FLOAT * divisors = (FAST_FLOAT *) compptr->dct_table; + FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) { + /* Perform the DCT */ + (*do_dct) (workspace, sample_data, start_col); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register FAST_FLOAT temp; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + /* Apply the quantization and scaling factor */ + temp = workspace[i] * divisors[i]; + /* Round to nearest integer. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * The maximum coefficient size is +-16K (for 12-bit data), so this + * code should work for either 16-bit or 32-bit ints. + */ + output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384); + } + } + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ + + +/* + * Initialize for a processing pass. + * Verify that all referenced Q-tables are present, and set up + * the divisor table for each one. + * In the current implementation, DCT of all components is done during + * the first pass, even if only some components will be output in the + * first scan. Hence all components should be examined here. + */ + +METHODDEF(void) +start_pass_fdctmgr (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + int ci, qtblno, i; + jpeg_component_info *compptr; + int method = 0; + JQUANT_TBL * qtbl; + DCTELEM * dtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper DCT routine for this component's scaling */ + switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) { +#ifdef DCT_SCALING_SUPPORTED + case ((1 << 8) + 1): + fdct->do_dct[ci] = jpeg_fdct_1x1; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((2 << 8) + 2): + fdct->do_dct[ci] = jpeg_fdct_2x2; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((3 << 8) + 3): + fdct->do_dct[ci] = jpeg_fdct_3x3; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((4 << 8) + 4): + fdct->do_dct[ci] = jpeg_fdct_4x4; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((5 << 8) + 5): + fdct->do_dct[ci] = jpeg_fdct_5x5; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((6 << 8) + 6): + fdct->do_dct[ci] = jpeg_fdct_6x6; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((7 << 8) + 7): + fdct->do_dct[ci] = jpeg_fdct_7x7; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((9 << 8) + 9): + fdct->do_dct[ci] = jpeg_fdct_9x9; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((10 << 8) + 10): + fdct->do_dct[ci] = jpeg_fdct_10x10; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((11 << 8) + 11): + fdct->do_dct[ci] = jpeg_fdct_11x11; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((12 << 8) + 12): + fdct->do_dct[ci] = jpeg_fdct_12x12; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((13 << 8) + 13): + fdct->do_dct[ci] = jpeg_fdct_13x13; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((14 << 8) + 14): + fdct->do_dct[ci] = jpeg_fdct_14x14; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((15 << 8) + 15): + fdct->do_dct[ci] = jpeg_fdct_15x15; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((16 << 8) + 16): + fdct->do_dct[ci] = jpeg_fdct_16x16; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((16 << 8) + 8): + fdct->do_dct[ci] = jpeg_fdct_16x8; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((14 << 8) + 7): + fdct->do_dct[ci] = jpeg_fdct_14x7; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((12 << 8) + 6): + fdct->do_dct[ci] = jpeg_fdct_12x6; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((10 << 8) + 5): + fdct->do_dct[ci] = jpeg_fdct_10x5; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((8 << 8) + 4): + fdct->do_dct[ci] = jpeg_fdct_8x4; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((6 << 8) + 3): + fdct->do_dct[ci] = jpeg_fdct_6x3; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((4 << 8) + 2): + fdct->do_dct[ci] = jpeg_fdct_4x2; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((2 << 8) + 1): + fdct->do_dct[ci] = jpeg_fdct_2x1; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((8 << 8) + 16): + fdct->do_dct[ci] = jpeg_fdct_8x16; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((7 << 8) + 14): + fdct->do_dct[ci] = jpeg_fdct_7x14; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((6 << 8) + 12): + fdct->do_dct[ci] = jpeg_fdct_6x12; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((5 << 8) + 10): + fdct->do_dct[ci] = jpeg_fdct_5x10; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((4 << 8) + 8): + fdct->do_dct[ci] = jpeg_fdct_4x8; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((3 << 8) + 6): + fdct->do_dct[ci] = jpeg_fdct_3x6; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((2 << 8) + 4): + fdct->do_dct[ci] = jpeg_fdct_2x4; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((1 << 8) + 2): + fdct->do_dct[ci] = jpeg_fdct_1x2; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; +#endif + case ((DCTSIZE << 8) + DCTSIZE): + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + fdct->do_dct[ci] = jpeg_fdct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + fdct->do_dct[ci] = jpeg_fdct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + fdct->do_float_dct[ci] = jpeg_fdct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + break; + default: + ERREXIT2(cinfo, JERR_BAD_DCTSIZE, + compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size); + } + qtblno = compptr->quant_tbl_no; + /* Make sure specified quantization table is present */ + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + qtbl = cinfo->quant_tbl_ptrs[qtblno]; + /* Create divisor table from quant table */ + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + /* For LL&M IDCT method, divisors are equal to raw quantization + * coefficients multiplied by 8 (to counteract scaling). + */ + dtbl = (DCTELEM *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = + ((DCTELEM) qtbl->quantval[i]) << (compptr->component_needed ? 4 : 3); + } + fdct->pub.forward_DCT[ci] = forward_DCT; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + */ +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + dtbl = (DCTELEM *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = (DCTELEM) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + compptr->component_needed ? CONST_BITS-4 : CONST_BITS-3); + } + } + fdct->pub.forward_DCT[ci] = forward_DCT; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + * What's actually stored is 1/divisor so that the inner loop can + * use a multiplication rather than a division. + */ + FAST_FLOAT * fdtbl = (FAST_FLOAT *) compptr->dct_table; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fdtbl[i] = (FAST_FLOAT) + (1.0 / ((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col] * + (compptr->component_needed ? 16.0 : 8.0))); + i++; + } + } + } + fdct->pub.forward_DCT[ci] = forward_DCT_float; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + } +} + + +/* + * Initialize FDCT manager. + */ + +GLOBAL(void) +jinit_forward_dct (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct; + int ci; + jpeg_component_info *compptr; + + fdct = (my_fdct_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_fdct_controller)); + cinfo->fdct = &fdct->pub; + fdct->pub.start_pass = start_pass_fdctmgr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate a divisor table for each component */ + compptr->dct_table = (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(divisor_table)); + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jchuff.c b/widget/milsko/milskosrc/external/libjpeg/src/jchuff.c new file mode 100644 index 0000000000..1f527b2182 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jchuff.c @@ -0,0 +1,1656 @@ +/* + * jchuff.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2006-2023 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines. + * Both sequential and progressive modes are supported in this single module. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + * + * We do not support output suspension for the progressive JPEG mode, since + * the library currently does not allow multiple-scan files to be written + * with output suspension. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit sample data precision; + * -16384 .. +16383 for 12-bit sample data precision. + * Hence the magnitude should always fit in sample data precision + 2 bits. + */ + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + savable_state saved; /* Bit buffer & DC state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + + /* Statistics tables for optimization */ + long * dc_count_ptrs[NUM_HUFF_TBLS]; + long * ac_count_ptrs[NUM_HUFF_TBLS]; + + /* Following fields used only in progressive mode */ + + /* Mode flag: TRUE for optimization, FALSE for actual data output */ + boolean gather_statistics; + + /* next_output_byte/free_in_buffer are local copies of cinfo->dest fields. + */ + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */ + + /* Coding status for AC components */ + int ac_tbl_no; /* the table number of the single component */ + unsigned int EOBRUN; /* run length of EOBs */ + unsigned int BE; /* # of buffered correction bits before MCU */ + char * bit_buffer; /* buffer for correction bits (1 per char) */ + /* packing correction bits tightly would save some space but cost time... */ +} huff_entropy_encoder; + +typedef huff_entropy_encoder * huff_entropy_ptr; + +/* Working state while writing an MCU (sequential mode). + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + +/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit + * buffer can hold. Larger sizes may slightly improve compression, but + * 1000 is already well into the realm of overkill. + * The minimum safe size is 64 bits. + */ + +#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + */ + +LOCAL(void) +jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + c_derived_tbl *dtbl; + int p, i, l, lastp, si, maxsymbol; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + htbl = jpeg_std_huff_table((j_common_ptr) cinfo, isDC, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (c_derived_tbl *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(c_derived_tbl)); + dtbl = *pdtbl; + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + */ + if (((INT32) code) >= (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure C.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + /* Set all codeless symbols to have code length 0; + * this lets us detect duplicate VAL entries here, and later + * allows emit_bits to detect any attempt to emit such symbols. + */ + MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); + + /* This is also a convenient place to check for out-of-range + * and duplicated VAL entries. We allow 0..255 for AC symbols + * but only 0..15 for DC. (We could constrain them further + * based on data depth and mode, but this seems enough.) + */ + maxsymbol = isDC ? 15 : 255; + + for (p = 0; p < lastp; p++) { + i = htbl->huffval[p]; + if (i < 0 || i > maxsymbol || dtbl->ehufsi[i]) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + dtbl->ehufco[i] = huffcode[p]; + dtbl->ehufsi[i] = huffsize[p]; + } +} + + +/* Outputting bytes to the file. + * NB: these must be called only when actually outputting, + * that is, entropy->gather_statistics == FALSE. + */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte_s(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer_s(state)) \ + { action; } } + +/* Emit a byte */ +#define emit_byte_e(entropy,val) \ + { *(entropy)->next_output_byte++ = (JOCTET) (val); \ + if (--(entropy)->free_in_buffer == 0) \ + dump_buffer_e(entropy); } + + +LOCAL(boolean) +dump_buffer_s (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +LOCAL(void) +dump_buffer_e (huff_entropy_ptr entropy) +/* Empty the output buffer; we do not support suspension in this case. */ +{ + struct jpeg_destination_mgr * dest = entropy->cinfo->dest; + + if (! (*dest->empty_output_buffer) (entropy->cinfo)) + ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND); + /* After a successful buffer dump, must reset buffer pointers */ + entropy->next_output_byte = dest->next_output_byte; + entropy->free_in_buffer = dest->free_in_buffer; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(boolean) +emit_bits_s (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer; + register int put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + /* mask off any extra bits in code */ + put_buffer = ((INT32) code) & ((((INT32) 1) << size) - 1); + + /* new number of bits in buffer */ + put_bits = size + state->cur.put_bits; + + put_buffer <<= 24 - put_bits; /* align incoming bits */ + + /* and merge with old buffer contents */ + put_buffer |= state->cur.put_buffer; + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte_s(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte_s(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +INLINE +LOCAL(void) +emit_bits_e (huff_entropy_ptr entropy, unsigned int code, int size) +/* Emit some bits, unless we are in gather mode */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer; + register int put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + if (entropy->gather_statistics) + return; /* do nothing if we're only getting stats */ + + /* mask off any extra bits in code */ + put_buffer = ((INT32) code) & ((((INT32) 1) << size) - 1); + + /* new number of bits in buffer */ + put_bits = size + entropy->saved.put_bits; + + put_buffer <<= 24 - put_bits; /* align incoming bits */ + + /* and merge with old buffer contents */ + put_buffer |= entropy->saved.put_buffer; + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte_e(entropy, c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte_e(entropy, 0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + entropy->saved.put_buffer = put_buffer; /* update variables */ + entropy->saved.put_bits = put_bits; +} + + +LOCAL(boolean) +flush_bits_s (working_state * state) +{ + if (! emit_bits_s(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +LOCAL(void) +flush_bits_e (huff_entropy_ptr entropy) +{ + emit_bits_e(entropy, 0x7F, 7); /* fill any partial byte with ones */ + entropy->saved.put_buffer = 0; /* and reset bit-buffer to empty */ + entropy->saved.put_bits = 0; +} + + +/* + * Emit (or just count) a Huffman symbol. + */ + +INLINE +LOCAL(void) +emit_dc_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->dc_count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->dc_derived_tbls[tbl_no]; + emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +INLINE +LOCAL(void) +emit_ac_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->ac_count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->ac_derived_tbls[tbl_no]; + emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +/* + * Emit bits from a correction bit buffer. + */ + +LOCAL(void) +emit_buffered_bits (huff_entropy_ptr entropy, char * bufstart, + unsigned int nbits) +{ + if (entropy->gather_statistics) + return; /* no real work */ + + while (nbits > 0) { + emit_bits_e(entropy, (unsigned int) (*bufstart), 1); + bufstart++; + nbits--; + } +} + + +/* + * Emit any pending EOBRUN symbol. + */ + +LOCAL(void) +emit_eobrun (huff_entropy_ptr entropy) +{ + register int temp, nbits; + + if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */ + temp = entropy->EOBRUN; + nbits = 0; + while ((temp >>= 1)) + nbits++; + /* safety check: shouldn't happen given limited correction-bit buffer */ + if (nbits > 14) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + emit_ac_symbol(entropy, entropy->ac_tbl_no, nbits << 4); + if (nbits) + emit_bits_e(entropy, entropy->EOBRUN, nbits); + + entropy->EOBRUN = 0; + + /* Emit any buffered correction bits */ + emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE); + entropy->BE = 0; + } +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(boolean) +emit_restart_s (working_state * state, int restart_num) +{ + int ci; + + if (! flush_bits_s(state)) + return FALSE; + + emit_byte_s(state, 0xFF, return FALSE); + emit_byte_s(state, JPEG_RST0 + restart_num, return FALSE); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < state->cinfo->comps_in_scan; ci++) + state->cur.last_dc_val[ci] = 0; + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +LOCAL(void) +emit_restart_e (huff_entropy_ptr entropy, int restart_num) +{ + int ci; + + emit_eobrun(entropy); + + if (! entropy->gather_statistics) { + flush_bits_e(entropy); + emit_byte_e(entropy, 0xFF); + emit_byte_e(entropy, JPEG_RST0 + restart_num); + } + + if (entropy->cinfo->Ss == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + } else { + /* Re-initialize all AC-related fields to 0 */ + entropy->EOBRUN = 0; + entropy->BE = 0; + } +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + int max_coef_bits; + int blkn, ci, tbl; + ISHIFT_TEMPS + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart_e(entropy, entropy->next_restart_num); + + /* Since we're encoding a difference, the range limit is twice as much. */ + max_coef_bits = cinfo->data_precision + 3; + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + tbl = cinfo->cur_comp_info[ci]->dc_tbl_no; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + temp = IRIGHT_SHIFT((int) (MCU_data[blkn][0][0]), cinfo->Al); + + /* DC differences are figured on the point-transformed values. */ + if ((temp2 = temp - entropy->saved.last_dc_val[ci]) == 0) { + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_dc_symbol(entropy, tbl, 0); + + continue; + } + + entropy->saved.last_dc_val[ci] = temp; + + /* Encode the DC coefficient difference per section G.1.2.1 */ + if ((temp = temp2) < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values */ + if (nbits > max_coef_bits) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_dc_symbol(entropy, tbl, nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + emit_bits_e(entropy, (unsigned int) temp2, nbits); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + const int * natural_order; + JBLOCKROW block; + register int temp, temp2; + register int nbits; + register int r, k; + int Se, Al, max_coef_bits; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart_e(entropy, entropy->next_restart_num); + + Se = cinfo->Se; + Al = cinfo->Al; + natural_order = cinfo->natural_order; + max_coef_bits = cinfo->data_precision + 2; + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ + + r = 0; /* r = run length of zeros */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = (*block)[natural_order[k]]) == 0) { + r++; + continue; + } + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value; so the code is + * interwoven with finding the abs value (temp) and output bits (temp2). + */ + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* Apply the point transform, and watch out for case */ + /* that nonzero coef is zero after point transform. */ + if ((temp >>= Al) == 0) { + r++; + continue; + } + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + temp2 = ~temp; + } else { + /* Apply the point transform, and watch out for case */ + /* that nonzero coef is zero after point transform. */ + if ((temp >>= Al) == 0) { + r++; + continue; + } + temp2 = temp; + } + + /* Emit any pending EOBRUN */ + if (entropy->EOBRUN > 0) + emit_eobrun(entropy); + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values */ + if (nbits > max_coef_bits) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + emit_bits_e(entropy, (unsigned int) temp2, nbits); + + r = 0; /* reset zero run length */ + } + + if (r > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + if (entropy->EOBRUN == 0x7FFF) + emit_eobrun(entropy); /* force it out to avoid overflow */ + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, + * although the spec is not very clear on the point. + */ + +METHODDEF(boolean) +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int Al, blkn; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart_e(entropy, entropy->next_restart_num); + + Al = cinfo->Al; + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + /* We simply emit the Al'th bit of the DC coefficient value. */ + emit_bits_e(entropy, (unsigned int) (MCU_data[blkn][0][0] >> Al), 1); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + const int * natural_order; + JBLOCKROW block; + register int temp; + register int r, k; + int Se, Al; + int EOB; + char *BR_buffer; + unsigned int BR; + int absvalues[DCTSIZE2]; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart_e(entropy, entropy->next_restart_num); + + Se = cinfo->Se; + Al = cinfo->Al; + natural_order = cinfo->natural_order; + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* It is convenient to make a pre-pass to determine the transformed + * coefficients' absolute values and the EOB position. + */ + EOB = 0; + for (k = cinfo->Ss; k <= Se; k++) { + temp = (*block)[natural_order[k]]; + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + absvalues[k] = temp; /* save abs value for main pass */ + if (temp == 1) + EOB = k; /* EOB = index of last newly-nonzero coef */ + } + + /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ + + r = 0; /* r = run length of zeros */ + BR = 0; /* BR = count of buffered bits added now */ + BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = absvalues[k]) == 0) { + r++; + continue; + } + + /* Emit any required ZRLs, but not if they can be folded into EOB */ + while (r > 15 && k <= EOB) { + /* emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + /* Emit ZRL */ + emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + /* Emit buffered correction bits that must be associated with ZRL */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + } + + /* If the coef was previously nonzero, it only needs a correction bit. + * NOTE: a straight translation of the spec's figure G.7 would suggest + * that we also need to test r > 15. But if r > 15, we can only get here + * if k > EOB, which implies that this coefficient is not 1. + */ + if (temp > 1) { + /* The correction bit is the next bit of the absolute value. */ + BR_buffer[BR++] = (char) (temp & 1); + continue; + } + + /* Emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1); + + /* Emit output bit for newly-nonzero coef */ + temp = ((*block)[natural_order[k]] < 0) ? 0 : 1; + emit_bits_e(entropy, (unsigned int) temp, 1); + + /* Emit buffered correction bits that must be associated with this code */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + r = 0; /* reset zero run length */ + } + + if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + entropy->BE += BR; /* concat my correction bits to older ones */ + /* We force out the EOB if we risk either: + * 1. overflow of the EOB counter; + * 2. overflow of the correction bit buffer during the next MCU. + */ + if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1)) + emit_eobrun(entropy); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* Encode a single block's worth of coefficients */ + +LOCAL(boolean) +encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, + c_derived_tbl *dctbl, c_derived_tbl *actbl) +{ + register int temp, temp2; + register int nbits; + register int r, k; + int Se = state->cinfo->lim_Se; + int max_coef_bits = state->cinfo->data_precision + 3; + const int * natural_order = state->cinfo->natural_order; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + if ((temp = block[0] - last_dc_val) == 0) { + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits_s(state, dctbl->ehufco[0], dctbl->ehufsi[0])) + return FALSE; + } else { + if ((temp2 = temp) < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > max_coef_bits) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits_s(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits_s(state, (unsigned int) temp2, nbits)) + return FALSE; + } + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k <= Se; k++) { + if ((temp = block[natural_order[k]]) == 0) { + r++; + continue; + } + + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + if (! emit_bits_s(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) + return FALSE; + r -= 16; + } + + if ((temp2 = temp) < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values. + * Use ">=" instead of ">" so can use the + * same one larger limit from DC check here. + */ + if (nbits >= max_coef_bits) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit Huffman symbol for run length / number of bits */ + temp = (r << 4) + nbits; + if (! emit_bits_s(state, actbl->ehufco[temp], actbl->ehufsi[temp])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits_s(state, (unsigned int) temp2, nbits)) + return FALSE; + + r = 0; /* reset zero run length */ + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + if (! emit_bits_s(state, actbl->ehufco[0], actbl->ehufsi[0])) + return FALSE; + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF(boolean) +encode_mcu_huff (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + int blkn, ci; + jpeg_component_info * compptr; + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart_s(&state, entropy->next_restart_num)) + return FALSE; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + if (! encode_one_block(&state, + MCU_data[blkn][0], state.cur.last_dc_val[ci], + entropy->dc_derived_tbls[compptr->dc_tbl_no], + entropy->ac_derived_tbls[compptr->ac_tbl_no])) + return FALSE; + /* Update last_dc_val */ + state.cur.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + + if (cinfo->progressive_mode) { + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Flush out any buffered data */ + emit_eobrun(entropy); + flush_bits_e(entropy); + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + } else { + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits_s(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + } +} + + +/* + * Huffman coding optimization. + * + * We first scan the supplied data and count the number of uses of each symbol + * that is to be Huffman-coded. (This process MUST agree with the code above.) + * Then we build a Huffman coding tree for the observed counts. + * Symbols which are not needed at all for the particular image are not + * assigned any code, which saves space in the DHT marker as well as in + * the compressed data. + */ + + +/* Process a single block's worth of coefficients */ + +LOCAL(void) +htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, + long dc_counts[], long ac_counts[]) +{ + register int temp; + register int nbits; + register int r, k; + int Se = cinfo->lim_Se; + int max_coef_bits = cinfo->data_precision + 3; + const int * natural_order = cinfo->natural_order; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + if ((temp = block[0] - last_dc_val) == 0) { + /* Count the Huffman symbol for the number of bits */ + dc_counts[0]++; + } else { + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > max_coef_bits) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + } + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k <= Se; k++) { + if ((temp = block[natural_order[k]]) == 0) { + r++; + continue; + } + + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values. + * Use ">=" instead of ">" so can use the + * same one larger limit from DC check here. + */ + if (nbits >= max_coef_bits) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; /* reset zero run length */ + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF(boolean) +encode_mcu_gather (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci], + entropy->dc_count_ptrs[compptr->dc_tbl_no], + entropy->ac_count_ptrs[compptr->ac_tbl_no]); + entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + return TRUE; +} + + +/* + * Generate the best Huffman code table for the given counts, fill htbl. + * + * The JPEG standard requires that no symbol be assigned a codeword of all + * one bits (so that padding bits added at the end of a compressed segment + * can't look like a valid code). Because of the canonical ordering of + * codewords, this just means that there must be an unused slot in the + * longest codeword length category. Section K.2 of the JPEG spec suggests + * reserving such a slot by pretending that symbol 256 is a valid symbol + * with count 1. In theory that's not optimal; giving it count zero but + * including it in the symbol set anyway should give a better Huffman code. + * But the theoretically better code actually seems to come out worse in + * practice, because it produces more all-ones bytes (which incur stuffed + * zero bytes in the final file). In any case the difference is tiny. + * + * The JPEG standard requires Huffman codes to be no more than 16 bits long. + * If some symbols have a very small but nonzero probability, the Huffman tree + * must be adjusted to meet the code length restriction. We currently use + * the adjustment method suggested in JPEG section K.2. This method is *not* + * optimal; it may not choose the best possible limited-length code. But + * typically only very-low-frequency symbols will be given less-than-optimal + * lengths, so the code is almost optimal. Experimental comparisons against + * an optimal limited-length-code algorithm indicate that the difference is + * microscopic --- usually less than a hundredth of a percent of total size. + * So the extra complexity of an optimal algorithm doesn't seem worthwhile. + */ + +LOCAL(void) +jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]) +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + int codesize[257]; /* codesize[k] = code length of symbol k */ + int others[257]; /* next symbol in current branch of tree */ + int c1, c2, i, j; + UINT8 *p; + long v; + + freq[256] = 1; /* make sure 256 has a nonzero count */ + /* Including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed last in the largest codeword category. + * In the symbol list build procedure this element serves as sentinel + * for the zero run loop. + */ + +#ifndef DONT_USE_FANCY_HUFF_OPT + + /* Build list of symbols sorted in order of descending frequency */ + /* This approach has several benefits (thank to John Korejwa for the idea): + * 1. + * If a codelength category is split during the length limiting procedure + * below, the feature that more frequent symbols are assigned shorter + * codewords remains valid for the adjusted code. + * 2. + * To reduce consecutive ones in a Huffman data stream (thus reducing the + * number of stuff bytes in JPEG) it is preferable to follow 0 branches + * (and avoid 1 branches) as much as possible. This is easily done by + * assigning symbols to leaves of the Huffman tree in order of decreasing + * frequency, with no secondary sort based on codelengths. + * 3. + * The symbol list can be built independently from the assignment of code + * lengths by the Huffman procedure below. + * Note: The symbol list build procedure must be performed first, because + * the Huffman procedure assigning the codelengths clobbers the frequency + * counts! + */ + + /* Here we use the others array as a linked list of nonzero frequencies + * to be sorted. Already sorted elements are removed from the list. + */ + + /* Building list */ + + /* This item does not correspond to a valid symbol frequency and is used + * as starting index. + */ + j = 256; + + for (i = 0;; i++) { + if (freq[i] == 0) /* skip zero frequencies */ + continue; + if (i > 255) + break; + others[j] = i; /* this symbol value */ + j = i; /* previous symbol value */ + } + others[j] = -1; /* mark end of list */ + + /* Sorting list */ + + p = htbl->huffval; + while ((c1 = others[256]) >= 0) { + v = freq[c1]; + i = c1; /* first symbol value */ + j = 256; /* pseudo symbol value for starting index */ + while ((c2 = others[c1]) >= 0) { + if (freq[c2] > v) { + v = freq[c2]; + i = c2; /* this symbol value */ + j = c1; /* previous symbol value */ + } + c1 = c2; + } + others[j] = others[i]; /* remove this symbol i from list */ + *p++ = (UINT8) i; + } + +#endif /* DONT_USE_FANCY_HUFF_OPT */ + + /* This algorithm is explained in section K.2 of the JPEG standard */ + + MEMZERO(bits, SIZEOF(bits)); + MEMZERO(codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo, JERR_HUFF_CLEN_OUTOFBOUNDS); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) { + if (j == 0) + ERREXIT(cinfo, JERR_HUFF_CLEN_OUTOFBOUNDS); + j--; + } + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); + +#ifdef DONT_USE_FANCY_HUFF_OPT + + /* Return a list of the symbols sorted by code length */ + /* Note: Due to the codelength changes made above, it can happen + * that more frequent symbols are assigned longer codewords. + */ + p = htbl->huffval; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + *p++ = (UINT8) j; + } + } + } + +#endif /* DONT_USE_FANCY_HUFF_OPT */ + + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + htbl->sent_table = FALSE; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, tbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + boolean did_ac[NUM_HUFF_TBLS]; + + if (cinfo->progressive_mode) + /* Flush out buffered data (all we care about is counting the EOB symbol) */ + emit_eobrun(entropy); + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did_dc, SIZEOF(did_dc)); + MEMZERO(did_ac, SIZEOF(did_ac)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) { + tbl = compptr->dc_tbl_no; + if (! did_dc[tbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[tbl]); + did_dc[tbl] = TRUE; + } + } + /* AC needs no table when not present */ + if (cinfo->Se) { + tbl = compptr->ac_tbl_no; + if (! did_ac[tbl]) { + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[tbl]); + did_ac[tbl] = TRUE; + } + } + } +} + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF(void) +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, tbl; + jpeg_component_info * compptr; + + if (gather_statistics) + entropy->pub.finish_pass = finish_pass_gather; + else + entropy->pub.finish_pass = finish_pass_huff; + + if (cinfo->progressive_mode) { + entropy->cinfo = cinfo; + entropy->gather_statistics = gather_statistics; + + /* We assume jcmaster.c already validated the scan parameters. */ + + /* Select execution routine */ + if (cinfo->Ah == 0) { + if (cinfo->Ss == 0) + entropy->pub.encode_mcu = encode_mcu_DC_first; + else + entropy->pub.encode_mcu = encode_mcu_AC_first; + } else { + if (cinfo->Ss == 0) + entropy->pub.encode_mcu = encode_mcu_DC_refine; + else { + entropy->pub.encode_mcu = encode_mcu_AC_refine; + /* AC refinement needs a correction bit buffer */ + if (entropy->bit_buffer == NULL) + entropy->bit_buffer = (char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, MAX_CORR_BITS * SIZEOF(char)); + } + } + + /* Initialize AC stuff */ + entropy->ac_tbl_no = cinfo->cur_comp_info[0]->ac_tbl_no; + entropy->EOBRUN = 0; + entropy->BE = 0; + } else { + if (gather_statistics) + entropy->pub.encode_mcu = encode_mcu_gather; + else + entropy->pub.encode_mcu = encode_mcu_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) { + tbl = compptr->dc_tbl_no; + if (gather_statistics) { + /* Check for invalid table index */ + /* (make_c_derived_tbl does this in the other path) */ + if (tbl < 0 || tbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->dc_count_ptrs[tbl] == NULL) + entropy->dc_count_ptrs[tbl] = (long *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, 257 * SIZEOF(long)); + MEMZERO(entropy->dc_count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, TRUE, tbl, + & entropy->dc_derived_tbls[tbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + /* AC needs no table when not present */ + if (cinfo->Se) { + tbl = compptr->ac_tbl_no; + if (gather_statistics) { + if (tbl < 0 || tbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + if (entropy->ac_count_ptrs[tbl] == NULL) + entropy->ac_count_ptrs[tbl] = (long *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, 257 * SIZEOF(long)); + MEMZERO(entropy->ac_count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + jpeg_make_c_derived_tbl(cinfo, FALSE, tbl, + & entropy->ac_derived_tbls[tbl]); + } + } + } + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_huff_encoder (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(huff_entropy_encoder)); + cinfo->entropy = &entropy->pub; + entropy->pub.start_pass = start_pass_huff; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL; + } + + if (cinfo->progressive_mode) + entropy->bit_buffer = NULL; /* needed only in AC refinement scan */ +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcinit.c b/widget/milsko/milskosrc/external/libjpeg/src/jcinit.c new file mode 100644 index 0000000000..2aea7ca2a1 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcinit.c @@ -0,0 +1,249 @@ +/* + * jcinit.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2003-2017 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains initialization logic for the JPEG compressor. + * This routine is in charge of selecting the modules to be executed and + * making an initialization call to each one. + * + * Logically, this code belongs in jcmaster.c. It's split out because + * linking this routine implies linking the entire compression library. + * For a transcoding-only application, we want to be able to use jcmaster.c + * without linking in the whole library. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Compute JPEG image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + */ + +GLOBAL(void) +jpeg_calc_jpeg_dimensions (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + /* Sanity check on input image dimensions to prevent overflow in + * following calculations. + * We do check jpeg_width and jpeg_height in initial_setup in jcmaster.c, + * but image_width and image_height can come from arbitrary data, + * and we need some space for multiplication by block_size. + */ + if (((long) cinfo->image_width >> 24) || ((long) cinfo->image_height >> 24)) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + +#ifdef DCT_SCALING_SUPPORTED + + /* Compute actual JPEG image dimensions and DCT scaling choices. */ + if (cinfo->scale_num >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/1 scaling */ + cinfo->jpeg_width = cinfo->image_width * cinfo->block_size; + cinfo->jpeg_height = cinfo->image_height * cinfo->block_size; + cinfo->min_DCT_h_scaled_size = 1; + cinfo->min_DCT_v_scaled_size = 1; + } else if (cinfo->scale_num * 2 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/2 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 2L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 2L); + cinfo->min_DCT_h_scaled_size = 2; + cinfo->min_DCT_v_scaled_size = 2; + } else if (cinfo->scale_num * 3 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/3 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 3L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 3L); + cinfo->min_DCT_h_scaled_size = 3; + cinfo->min_DCT_v_scaled_size = 3; + } else if (cinfo->scale_num * 4 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/4 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 4L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 4L); + cinfo->min_DCT_h_scaled_size = 4; + cinfo->min_DCT_v_scaled_size = 4; + } else if (cinfo->scale_num * 5 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/5 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 5L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 5L); + cinfo->min_DCT_h_scaled_size = 5; + cinfo->min_DCT_v_scaled_size = 5; + } else if (cinfo->scale_num * 6 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/6 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 6L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 6L); + cinfo->min_DCT_h_scaled_size = 6; + cinfo->min_DCT_v_scaled_size = 6; + } else if (cinfo->scale_num * 7 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/7 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 7L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 7L); + cinfo->min_DCT_h_scaled_size = 7; + cinfo->min_DCT_v_scaled_size = 7; + } else if (cinfo->scale_num * 8 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/8 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 8L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 8L); + cinfo->min_DCT_h_scaled_size = 8; + cinfo->min_DCT_v_scaled_size = 8; + } else if (cinfo->scale_num * 9 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/9 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 9L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 9L); + cinfo->min_DCT_h_scaled_size = 9; + cinfo->min_DCT_v_scaled_size = 9; + } else if (cinfo->scale_num * 10 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/10 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 10L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 10L); + cinfo->min_DCT_h_scaled_size = 10; + cinfo->min_DCT_v_scaled_size = 10; + } else if (cinfo->scale_num * 11 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/11 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 11L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 11L); + cinfo->min_DCT_h_scaled_size = 11; + cinfo->min_DCT_v_scaled_size = 11; + } else if (cinfo->scale_num * 12 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/12 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 12L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 12L); + cinfo->min_DCT_h_scaled_size = 12; + cinfo->min_DCT_v_scaled_size = 12; + } else if (cinfo->scale_num * 13 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/13 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 13L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 13L); + cinfo->min_DCT_h_scaled_size = 13; + cinfo->min_DCT_v_scaled_size = 13; + } else if (cinfo->scale_num * 14 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/14 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 14L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 14L); + cinfo->min_DCT_h_scaled_size = 14; + cinfo->min_DCT_v_scaled_size = 14; + } else if (cinfo->scale_num * 15 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/15 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 15L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 15L); + cinfo->min_DCT_h_scaled_size = 15; + cinfo->min_DCT_v_scaled_size = 15; + } else { + /* Provide block_size/16 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 16L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 16L); + cinfo->min_DCT_h_scaled_size = 16; + cinfo->min_DCT_v_scaled_size = 16; + } + +#else /* !DCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->jpeg_width = cinfo->image_width; + cinfo->jpeg_height = cinfo->image_height; + cinfo->min_DCT_h_scaled_size = DCTSIZE; + cinfo->min_DCT_v_scaled_size = DCTSIZE; + +#endif /* DCT_SCALING_SUPPORTED */ +} + + +/* + * Master selection of compression modules. + * This is done once at the start of processing an image. We determine + * which modules will be used and give them appropriate initialization calls. + */ + +GLOBAL(void) +jinit_compress_master (j_compress_ptr cinfo) +{ + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Sanity check on input image dimensions */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 || + cinfo->input_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Width of an input scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Compute JPEG image dimensions and related values. */ + jpeg_calc_jpeg_dimensions(cinfo); + + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, FALSE /* full compression */); + + /* Preprocessing */ + if (! cinfo->raw_data_in) { + jinit_color_converter(cinfo); + jinit_downsampler(cinfo); + jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); + } + /* Forward DCT */ + jinit_forward_dct(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) + jinit_arith_encoder(cinfo); + else { + jinit_huff_encoder(cinfo); + } + + /* Need a full-image coefficient buffer in any multi-pass mode. */ + jinit_c_coef_controller(cinfo, + (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding)); + jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcmainct.c b/widget/milsko/milskosrc/external/libjpeg/src/jcmainct.c new file mode 100644 index 0000000000..39b97902e8 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcmainct.c @@ -0,0 +1,297 @@ +/* + * jcmainct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2003-2012 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for compression. + * The main buffer lies between the pre-processor and the JPEG + * compressor proper; it holds downsampled data in the JPEG colorspace. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Note: currently, there is no operating mode in which a full-image buffer + * is needed at this step. If there were, that mode could not be used with + * "raw data" input, since this module is bypassed in that case. However, + * we've left the code here for possible use in special applications. + */ +#undef FULL_MAIN_BUFFER_SUPPORTED + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_main_controller pub; /* public fields */ + + JDIMENSION cur_iMCU_row; /* number of current iMCU row */ + JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ + boolean suspended; /* remember if we suspended output */ + J_BUF_MODE pass_mode; /* current operating mode */ + + /* If using just a strip buffer, this points to the entire set of buffers + * (we allocate one for each component). In the full-image case, this + * points to the currently accessible strips of the virtual arrays. + */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* If using full-image storage, this array holds pointers to virtual-array + * control blocks for each component. Unused if not full-image storage. + */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#ifdef FULL_MAIN_BUFFER_SUPPORTED +METHODDEF(void) process_data_buffer_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + + /* Do nothing in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + mainp->cur_iMCU_row = 0; /* initialize counters */ + mainp->rowgroup_ctr = 0; + mainp->suspended = FALSE; + mainp->pass_mode = pass_mode; /* save mode for use by process_data */ + + switch (pass_mode) { + case JBUF_PASS_THRU: +#ifdef FULL_MAIN_BUFFER_SUPPORTED + if (mainp->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + mainp->pub.process_data = process_data_simple_main; + break; +#ifdef FULL_MAIN_BUFFER_SUPPORTED + case JBUF_SAVE_SOURCE: + case JBUF_CRANK_DEST: + case JBUF_SAVE_AND_PASS: + if (mainp->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + mainp->pub.process_data = process_data_buffer_main; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This routine handles the simple pass-through mode, + * where we have only a strip buffer. + */ + +METHODDEF(void) +process_data_simple_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + + while (mainp->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Read input data if we haven't filled the main buffer yet */ + if (mainp->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size) + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + mainp->buffer, &mainp->rowgroup_ctr, + (JDIMENSION) cinfo->min_DCT_v_scaled_size); + + /* If we don't have a full iMCU row buffered, return to application for + * more data. Note that preprocessor will always pad to fill the iMCU row + * at the bottom of the image. + */ + if (mainp->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size) + return; + + /* Send the completed row to the compressor */ + if (! (*cinfo->coef->compress_data) (cinfo, mainp->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! mainp->suspended) { + (*in_row_ctr)--; + mainp->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (mainp->suspended) { + (*in_row_ctr)++; + mainp->suspended = FALSE; + } + mainp->rowgroup_ctr = 0; + mainp->cur_iMCU_row++; + } +} + + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + +/* + * Process some data. + * This routine handles all of the modes that use a full-size buffer. + */ + +METHODDEF(void) +process_data_buffer_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + int ci; + jpeg_component_info *compptr; + boolean writing = (mainp->pass_mode != JBUF_CRANK_DEST); + + while (mainp->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Realign the virtual buffers if at the start of an iMCU row. */ + if (mainp->rowgroup_ctr == 0) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainp->buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, mainp->whole_image[ci], mainp->cur_iMCU_row * + ((JDIMENSION) (compptr->v_samp_factor * cinfo->min_DCT_v_scaled_size)), + (JDIMENSION) (compptr->v_samp_factor * cinfo->min_DCT_v_scaled_size), + writing); + } + /* In a read pass, pretend we just read some source data. */ + if (! writing) { + *in_row_ctr += (JDIMENSION) + (cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size); + mainp->rowgroup_ctr = (JDIMENSION) cinfo->min_DCT_v_scaled_size; + } + } + + /* If a write pass, read input data until the current iMCU row is full. */ + /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ + if (writing) { + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + mainp->buffer, &mainp->rowgroup_ctr, + (JDIMENSION) cinfo->min_DCT_v_scaled_size); + /* Return to application if we need more data to fill the iMCU row. */ + if (mainp->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size) + return; + } + + /* Emit data, unless this is a sink-only pass. */ + if (mainp->pass_mode != JBUF_SAVE_SOURCE) { + if (! (*cinfo->coef->compress_data) (cinfo, mainp->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! mainp->suspended) { + (*in_row_ctr)--; + mainp->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (mainp->suspended) { + (*in_row_ctr)++; + mainp->suspended = FALSE; + } + } + + /* If get here, we are done with this iMCU row. Mark buffer empty. */ + mainp->rowgroup_ctr = 0; + mainp->cur_iMCU_row++; + } +} + +#endif /* FULL_MAIN_BUFFER_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr mainp; + int ci; + jpeg_component_info *compptr; + + mainp = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = &mainp->pub; + mainp->pub.start_pass = start_pass_main; + + /* We don't need to create a buffer in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + /* Create the buffer. It holds downsampled data, so each component + * may be of a different size. + */ + if (need_full_buffer) { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component */ + /* Note we pad the bottom to a multiple of the iMCU height */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainp->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size), + ((JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor)) * + ((JDIMENSION) cinfo->min_DCT_v_scaled_size), + (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size)); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + mainp->whole_image[0] = NULL; /* flag for no virtual arrays */ +#endif + /* Allocate a strip buffer for each component */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainp->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size), + (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size)); + } + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcmarker.c b/widget/milsko/milskosrc/external/libjpeg/src/jcmarker.c new file mode 100644 index 0000000000..8874cd8670 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcmarker.c @@ -0,0 +1,717 @@ +/* + * jcmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2003-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write JPEG datastream markers. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG8 = 0xf8, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_writer pub; /* public fields */ + + unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */ +} my_marker_writer; + +typedef my_marker_writer * my_marker_ptr; + + +/* + * Basic output routines. + * + * Note that we do not support suspension while writing a marker. + * Therefore, an application using suspension must ensure that there is + * enough buffer space for the initial markers (typ. 600-700 bytes) before + * calling jpeg_start_compress, and enough space to write the trailing EOI + * (a few bytes) before calling jpeg_finish_compress. Multipass compression + * modes are not supported at all with suspension, so those two are the only + * points where markers will be written. + */ + +LOCAL(void) +emit_byte (j_compress_ptr cinfo, int val) +/* Emit a byte */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *(dest->next_output_byte)++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) { + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } +} + + +LOCAL(void) +emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, (int) mark); +} + + +LOCAL(void) +emit_2bytes (j_compress_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +/* + * Routines to write specific marker types. + */ + +LOCAL(int) +emit_dqt (j_compress_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index]; + int prec; + int i; + + if (qtbl == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index); + + prec = 0; + for (i = 0; i <= cinfo->lim_Se; i++) { + if (qtbl->quantval[cinfo->natural_order[i]] > 255) + prec = 1; + } + + if (! qtbl->sent_table) { + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, + prec ? cinfo->lim_Se * 2 + 2 + 1 + 2 : cinfo->lim_Se + 1 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i <= cinfo->lim_Se; i++) { + /* The table entries must be emitted in zigzag order. */ + unsigned int qval = qtbl->quantval[cinfo->natural_order[i]]; + if (prec) + emit_byte(cinfo, (int) (qval >> 8)); + emit_byte(cinfo, (int) (qval & 0xFF)); + } + + qtbl->sent_table = TRUE; + } + + return prec; +} + + +LOCAL(void) +emit_dht (j_compress_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + JHUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index); + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL(void) +emit_dac (j_compress_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ +#ifdef C_ARITH_CODING_SUPPORTED + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + jpeg_component_info *compptr; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) + dc_in_use[compptr->dc_tbl_no] = 1; + /* AC needs no table when not present */ + if (cinfo->Se) + ac_in_use[compptr->ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + if (length) { + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } + } +#endif /* C_ARITH_CODING_SUPPORTED */ +} + + +LOCAL(void) +emit_dri (j_compress_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL(void) +emit_lse_ict (j_compress_ptr cinfo) +/* Emit an LSE inverse color transform specification marker */ +{ + /* Support only 1 transform */ + if (cinfo->color_transform != JCT_SUBTRACT_GREEN || + cinfo->num_components < 3) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + + emit_marker(cinfo, M_JPG8); + + emit_2bytes(cinfo, 24); /* fixed length */ + + emit_byte(cinfo, 0x0D); /* ID inverse transform specification */ + emit_2bytes(cinfo, MAXJSAMPLE); /* MAXTRANS */ + emit_byte(cinfo, 3); /* Nt=3 */ + emit_byte(cinfo, cinfo->comp_info[1].component_id); + emit_byte(cinfo, cinfo->comp_info[0].component_id); + emit_byte(cinfo, cinfo->comp_info[2].component_id); + emit_byte(cinfo, 0x80); /* F1: CENTER1=1, NORM1=0 */ + emit_2bytes(cinfo, 0); /* A(1,1)=0 */ + emit_2bytes(cinfo, 0); /* A(1,2)=0 */ + emit_byte(cinfo, 0); /* F2: CENTER2=0, NORM2=0 */ + emit_2bytes(cinfo, 1); /* A(2,1)=1 */ + emit_2bytes(cinfo, 0); /* A(2,2)=0 */ + emit_byte(cinfo, 0); /* F3: CENTER3=0, NORM3=0 */ + emit_2bytes(cinfo, 1); /* A(3,1)=1 */ + emit_2bytes(cinfo, 0); /* A(3,2)=0 */ +} + + +LOCAL(void) +emit_sof (j_compress_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int ci; + jpeg_component_info *compptr; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + /* Make sure image isn't bigger than SOF field can handle */ + if ((long) cinfo->jpeg_height > 65535L || + (long) cinfo->jpeg_width > 65535L) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535); + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->jpeg_height); + emit_2bytes(cinfo, (int) cinfo->jpeg_width); + + emit_byte(cinfo, cinfo->num_components); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + emit_byte(cinfo, compptr->component_id); + emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor); + emit_byte(cinfo, compptr->quant_tbl_no); + } +} + + +LOCAL(void) +emit_sos (j_compress_ptr cinfo) +/* Emit a SOS marker */ +{ + int i, td, ta; + jpeg_component_info *compptr; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + emit_byte(cinfo, compptr->component_id); + + /* We emit 0 for unused field(s); this is recommended by the P&M text + * but does not seem to be specified in the standard. + */ + + /* DC needs no table for refinement scan */ + td = cinfo->Ss == 0 && cinfo->Ah == 0 ? compptr->dc_tbl_no : 0; + /* AC needs no table when not present */ + ta = cinfo->Se ? compptr->ac_tbl_no : 0; + + emit_byte(cinfo, (td << 4) + ta); + } + + emit_byte(cinfo, cinfo->Ss); + emit_byte(cinfo, cinfo->Se); + emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al); +} + + +LOCAL(void) +emit_pseudo_sos (j_compress_ptr cinfo) +/* Emit a pseudo SOS marker */ +{ + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 + 1 + 3); /* length */ + + emit_byte(cinfo, 0); /* Ns */ + + emit_byte(cinfo, 0); /* Ss */ + emit_byte(cinfo, cinfo->block_size * cinfo->block_size - 1); /* Se */ + emit_byte(cinfo, 0); /* Ah/Al */ +} + + +LOCAL(void) +emit_jfif_app0 (j_compress_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - major first) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */ + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0x49); + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0); + emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */ + emit_byte(cinfo, cinfo->JFIF_minor_version); + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +LOCAL(void) +emit_adobe_app14 (j_compress_ptr cinfo) +/* Emit an Adobe APP14 marker */ +{ + /* + * Length of APP14 block (2 bytes) + * Block ID (5 bytes - ASCII "Adobe") + * Version Number (2 bytes - currently 100) + * Flags0 (2 bytes - currently 0) + * Flags1 (2 bytes - currently 0) + * Color transform (1 byte) + * + * Although Adobe TN 5116 mentions Version = 101, all the Adobe files + * now in circulation seem to use Version = 100, so that's what we write. + * + * We write the color transform byte as 1 if the JPEG color space is + * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with + * whether the encoder performed a transformation, which is pretty useless. + */ + + emit_marker(cinfo, M_APP14); + + emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */ + + emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */ + emit_byte(cinfo, 0x64); + emit_byte(cinfo, 0x6F); + emit_byte(cinfo, 0x62); + emit_byte(cinfo, 0x65); + emit_2bytes(cinfo, 100); /* Version */ + emit_2bytes(cinfo, 0); /* Flags0 */ + emit_2bytes(cinfo, 0); /* Flags1 */ + switch (cinfo->jpeg_color_space) { + case JCS_YCbCr: + emit_byte(cinfo, 1); /* Color transform = 1 */ + break; + case JCS_YCCK: + emit_byte(cinfo, 2); /* Color transform = 2 */ + break; + default: + emit_byte(cinfo, 0); /* Color transform = 0 */ + } +} + + +/* + * These routines allow writing an arbitrary marker with parameters. + * The only intended use is to emit COM or APPn markers after calling + * write_file_header and before calling write_frame_header. + * Other uses are not guaranteed to produce desirable results. + * Counting the parameter bytes properly is the caller's responsibility. + */ + +METHODDEF(void) +write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +/* Emit an arbitrary marker header */ +{ + if (datalen > (unsigned int) 65533) /* safety check */ + ERREXIT(cinfo, JERR_BAD_LENGTH); + + emit_marker(cinfo, (JPEG_MARKER) marker); + + emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */ +} + +METHODDEF(void) +write_marker_byte (j_compress_ptr cinfo, int val) +/* Emit one byte of marker parameters following write_marker_header */ +{ + emit_byte(cinfo, val); +} + + +/* + * Write datastream header. + * This consists of an SOI and optional APPn markers. + * We recommend use of the JFIF marker, but not the Adobe marker, + * when using YCbCr or grayscale data. The JFIF marker is also used + * for other standard JPEG colorspaces. The Adobe marker is helpful + * to distinguish RGB, CMYK, and YCCK colorspaces. + * Note that an application can write additional header markers after + * jpeg_start_compress returns. + */ + +METHODDEF(void) +write_file_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + emit_marker(cinfo, M_SOI); /* first the SOI */ + + /* SOI is defined to reset restart interval to 0 */ + marker->last_restart_interval = 0; + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */ + emit_adobe_app14(cinfo); +} + + +/* + * Write frame header. + * This consists of DQT and SOFn markers, + * a conditional LSE marker and a conditional pseudo SOS marker. + * Note that we do not emit the SOF until we have emitted the DQT(s). + * This avoids compatibility problems with incorrect implementations that + * try to error-check the quant table numbers as soon as they see the SOF. + */ + +METHODDEF(void) +write_frame_header (j_compress_ptr cinfo) +{ + int ci, prec; + boolean is_baseline; + jpeg_component_info *compptr; + + /* Emit DQT for each quantization table. + * Note that emit_dqt() suppresses any duplicate tables. + */ + prec = 0; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prec += emit_dqt(cinfo, compptr->quant_tbl_no); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + + /* Check for a non-baseline specification. + * Note we assume that Huffman table numbers won't be changed later. + */ + if (cinfo->arith_code || cinfo->progressive_mode || + cinfo->data_precision != 8 || cinfo->block_size != DCTSIZE) { + is_baseline = FALSE; + } else { + is_baseline = TRUE; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo, 0, JTRC_16BIT_TABLES); + } + } + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) { + if (cinfo->progressive_mode) + emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */ + else + emit_sof(cinfo, M_SOF9); /* SOF code for sequential arithmetic */ + } else { + if (cinfo->progressive_mode) + emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ + } + + /* Check to emit LSE inverse color transform specification marker */ + if (cinfo->color_transform) + emit_lse_ict(cinfo); + + /* Check to emit pseudo SOS marker */ + if (cinfo->progressive_mode && cinfo->block_size != DCTSIZE) + emit_pseudo_sos(cinfo); +} + + +/* + * Write scan header. + * This consists of DHT or DAC markers, optional DRI, and SOS. + * Compressed data will be written following the SOS. + */ + +METHODDEF(void) +write_scan_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + int i; + jpeg_component_info *compptr; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We may have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. + * Note that emit_dht() suppresses any duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + /* AC needs no table when not present */ + if (cinfo->Se) + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } + + /* Emit DRI if required --- note that DRI value could change for each scan. + * We avoid wasting space with unnecessary DRIs, however. + */ + if (cinfo->restart_interval != marker->last_restart_interval) { + emit_dri(cinfo); + marker->last_restart_interval = cinfo->restart_interval; + } + + emit_sos(cinfo); +} + + +/* + * Write datastream trailer. + */ + +METHODDEF(void) +write_file_trailer (j_compress_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); +} + + +/* + * Write an abbreviated table-specification datastream. + * This consists of SOI, DQT and DHT tables, and EOI. + * Any table that is defined and not marked sent_table = TRUE will be + * emitted. Note that all tables will be marked sent_table = TRUE at exit. + */ + +METHODDEF(void) +write_tables_only (j_compress_ptr cinfo) +{ + int i; + + emit_marker(cinfo, M_SOI); + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (cinfo->quant_tbl_ptrs[i] != NULL) + (void) emit_dqt(cinfo, i); + } + + if (! cinfo->arith_code) { + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if (cinfo->dc_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, FALSE); + if (cinfo->ac_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, TRUE); + } + } + + emit_marker(cinfo, M_EOI); +} + + +/* + * Initialize the marker writer module. + */ + +GLOBAL(void) +jinit_marker_writer (j_compress_ptr cinfo) +{ + my_marker_ptr marker; + + /* Create the subobject */ + marker = (my_marker_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_marker_writer)); + cinfo->marker = &marker->pub; + /* Initialize method pointers */ + marker->pub.write_file_header = write_file_header; + marker->pub.write_frame_header = write_frame_header; + marker->pub.write_scan_header = write_scan_header; + marker->pub.write_file_trailer = write_file_trailer; + marker->pub.write_tables_only = write_tables_only; + marker->pub.write_marker_header = write_marker_header; + marker->pub.write_marker_byte = write_marker_byte; + /* Initialize private state */ + marker->last_restart_interval = 0; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcmaster.c b/widget/milsko/milskosrc/external/libjpeg/src/jcmaster.c new file mode 100644 index 0000000000..a70af0c020 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcmaster.c @@ -0,0 +1,675 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2003-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG compressor. + * These routines are concerned with parameter validation, initial setup, + * and inter-pass control (determining the number of passes and the work + * to be done in each pass). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef enum { + main_pass, /* input data, also do first output step */ + huff_opt_pass, /* Huffman code optimization pass */ + output_pass /* data output pass */ +} c_pass_type; + +typedef struct { + struct jpeg_comp_master pub; /* public fields */ + + c_pass_type pass_type; /* the type of the current pass */ + + int pass_number; /* # of passes completed */ + int total_passes; /* total # of passes needed */ + + int scan_number; /* current index in scan_info[] */ +} my_comp_master; + +typedef my_comp_master * my_master_ptr; + + +/* + * Support routines that do various essential calculations. + */ + +LOCAL(void) +initial_setup (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + int ci, ssize; + jpeg_component_info *compptr; + + /* Sanity check on block_size */ + if (cinfo->block_size < 1 || cinfo->block_size > 16) + ERREXIT2(cinfo, JERR_BAD_DCTSIZE, cinfo->block_size, cinfo->block_size); + + /* Derive natural_order from block_size */ + switch (cinfo->block_size) { + case 2: cinfo->natural_order = jpeg_natural_order2; break; + case 3: cinfo->natural_order = jpeg_natural_order3; break; + case 4: cinfo->natural_order = jpeg_natural_order4; break; + case 5: cinfo->natural_order = jpeg_natural_order5; break; + case 6: cinfo->natural_order = jpeg_natural_order6; break; + case 7: cinfo->natural_order = jpeg_natural_order7; break; + default: cinfo->natural_order = jpeg_natural_order; + } + + /* Derive lim_Se from block_size */ + cinfo->lim_Se = cinfo->block_size < DCTSIZE ? + cinfo->block_size * cinfo->block_size - 1 : DCTSIZE2-1; + + /* Sanity check on image dimensions */ + if (cinfo->jpeg_height <= 0 || cinfo->jpeg_width <= 0 || + cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->jpeg_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->jpeg_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Only 8 to 12 bits data precision are supported for DCT based JPEG */ + if (cinfo->data_precision < 8 || cinfo->data_precision > 12) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Fill in the correct component_index value; don't rely on application */ + compptr->component_index = ci; + /* In selecting the actual DCT scaling for each component, we try to + * scale down the chroma components via DCT scaling rather than downsampling. + * This saves time if the downsampler gets to use 1:1 scaling. + * Note this code adapts subsampling ratios which are powers of 2. + */ + ssize = 1; +#ifdef DCT_SCALING_SUPPORTED + if (! cinfo->raw_data_in) + while (cinfo->min_DCT_h_scaled_size * ssize <= + (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) && + (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == + 0) { + ssize = ssize * 2; + } +#endif + compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize; + ssize = 1; +#ifdef DCT_SCALING_SUPPORTED + if (! cinfo->raw_data_in) + while (cinfo->min_DCT_v_scaled_size * ssize <= + (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) && + (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == + 0) { + ssize = ssize * 2; + } +#endif + compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize; + + /* We don't support DCT ratios larger than 2. */ + if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2) + compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2; + else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2) + compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2; + + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_width * + (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size), + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_height * + (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size), + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + /* Don't need quantization scale after DCT, + * until color conversion says otherwise. + */ + compptr->component_needed = FALSE; + } + + /* Compute number of fully interleaved MCU rows (number of times that + * main controller will call coefficient controller). + */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_height, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); +} + + +#ifdef C_MULTISCAN_FILES_SUPPORTED + +LOCAL(void) +validate_script (j_compress_ptr cinfo) +/* Verify that the scan script in cinfo->scan_info[] is valid; also + * determine whether it uses progressive JPEG, and set cinfo->progressive_mode. + */ +{ + const jpeg_scan_info * scanptr; + int scanno, ncomps, ci, coefi, thisi; + int Ss, Se, Ah, Al; + boolean component_sent[MAX_COMPONENTS]; +#ifdef C_PROGRESSIVE_SUPPORTED + int * last_bitpos_ptr; + int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; + /* -1 until that coefficient has been seen; then last Al for it */ +#endif + + if (cinfo->num_scans <= 0) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0); + + /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; + * for progressive JPEG, no scan can have this. + */ + scanptr = cinfo->scan_info; + if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { +#ifdef C_PROGRESSIVE_SUPPORTED + cinfo->progressive_mode = TRUE; + last_bitpos_ptr = & last_bitpos[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (coefi = 0; coefi < DCTSIZE2; coefi++) + *last_bitpos_ptr++ = -1; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; + } + + for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) { + /* Validate component indexes */ + ncomps = scanptr->comps_in_scan; + if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (thisi < 0 || thisi >= cinfo->num_components) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + /* Components must appear in SOF order within each scan */ + if (ci > 0 && thisi <= scanptr->component_index[ci-1]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + } + /* Validate progression parameters */ + Ss = scanptr->Ss; + Se = scanptr->Se; + Ah = scanptr->Ah; + Al = scanptr->Al; + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that + * seems wrong: the upper bound ought to depend on data precision. + * Perhaps they really meant 0..N+1 for N-bit precision. + * Here we allow 0..10 for 8-bit data; Al larger than 10 results in + * out-of-range reconstructed DC values during the first DC scan, + * which might cause problems for some decoders. + */ + if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || + Ah < 0 || Ah > (cinfo->data_precision > 8 ? 13 : 10) || + Al < 0 || Al > (cinfo->data_precision > 8 ? 13 : 10)) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + if (Ss == 0) { + if (Se != 0) /* DC and AC together not OK */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + if (ncomps != 1) /* AC scans must be for only one component */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + for (ci = 0; ci < ncomps; ci++) { + last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0]; + if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + for (coefi = Ss; coefi <= Se; coefi++) { + if (last_bitpos_ptr[coefi] < 0) { + /* first scan of this coefficient */ + if (Ah != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + /* not first scan */ + if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + last_bitpos_ptr[coefi] = Al; + } + } +#endif + } else { + /* For sequential JPEG, all progression parameters must be these: */ + if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } + } + } + + /* Now verify that everything got sent. */ + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* For progressive mode, we only check that at least some DC data + * got sent for each component; the spec does not require that all bits + * of all coefficients be transmitted. Would it be wiser to enforce + * transmission of all coefficient bits?? + */ + for (ci = 0; ci < cinfo->num_components; ci++) { + if (last_bitpos[ci][0] < 0) + ERREXIT(cinfo, JERR_MISSING_DATA); + } +#endif + } else { + for (ci = 0; ci < cinfo->num_components; ci++) { + if (! component_sent[ci]) + ERREXIT(cinfo, JERR_MISSING_DATA); + } + } +} + + +LOCAL(void) +reduce_script (j_compress_ptr cinfo) +/* Adapt scan script for use with reduced block size; + * assume that script has been validated before. + */ +{ + jpeg_scan_info * scanptr; + int idxout, idxin; + + /* Circumvent const declaration for this function */ + scanptr = (jpeg_scan_info *) cinfo->scan_info; + idxout = 0; + + for (idxin = 0; idxin < cinfo->num_scans; idxin++) { + /* After skipping, idxout becomes smaller than idxin */ + if (idxin != idxout) + /* Copy rest of data; + * note we stay in given chunk of allocated memory. + */ + scanptr[idxout] = scanptr[idxin]; + if (scanptr[idxout].Ss > cinfo->lim_Se) + /* Entire scan out of range - skip this entry */ + continue; + if (scanptr[idxout].Se > cinfo->lim_Se) + /* Limit scan to end of block */ + scanptr[idxout].Se = cinfo->lim_Se; + idxout++; + } + + cinfo->num_scans = idxout; +} + +#endif /* C_MULTISCAN_FILES_SUPPORTED */ + + +LOCAL(void) +select_scan_parameters (j_compress_ptr cinfo) +/* Set up the scan parameters for the current scan */ +{ + int ci; + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (cinfo->scan_info != NULL) { + /* Prepare for current scan --- the script is already validated */ + my_master_ptr master = (my_master_ptr) cinfo->master; + const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number; + + cinfo->comps_in_scan = scanptr->comps_in_scan; + for (ci = 0; ci < scanptr->comps_in_scan; ci++) { + cinfo->cur_comp_info[ci] = + &cinfo->comp_info[scanptr->component_index[ci]]; + } + if (cinfo->progressive_mode) { + cinfo->Ss = scanptr->Ss; + cinfo->Se = scanptr->Se; + cinfo->Ah = scanptr->Ah; + cinfo->Al = scanptr->Al; + return; + } + } + else +#endif + { + /* Prepare for single sequential-JPEG scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + } + cinfo->Ss = 0; + cinfo->Se = cinfo->block_size * cinfo->block_size - 1; + cinfo->Ah = 0; + cinfo->Al = 0; +} + + +LOCAL(void) +per_scan_setup (j_compress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = compptr->DCT_h_scaled_size; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_width, + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + cinfo->MCU_rows_in_scan = cinfo->total_iMCU_rows; + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } + + /* Convert restart specified in rows to actual MCU count. */ + /* Note that count must fit in 16 bits, so we provide limiting. */ + if (cinfo->restart_in_rows > 0) { + long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; + cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); + } +} + + +/* + * Per-pass setup. + * This is called at the beginning of each pass. We determine which modules + * will be active during this pass and give them appropriate start_pass calls. + * We also set is_last_pass to indicate whether any more passes will be + * required. + */ + +METHODDEF(void) +prepare_for_pass (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + switch (master->pass_type) { + case main_pass: + /* Initial pass: will collect input data, and do either Huffman + * optimization or data output for the first scan. + */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (! cinfo->raw_data_in) { + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->downsample->start_pass) (cinfo); + (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); + } + (*cinfo->fdct->start_pass) (cinfo); + (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding); + (*cinfo->coef->start_pass) (cinfo, + (master->total_passes > 1 ? + JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + if (cinfo->optimize_coding) { + /* No immediate data output; postpone writing frame/scan headers */ + master->pub.call_pass_startup = FALSE; + } else { + /* Will write frame/scan headers at first jpeg_write_scanlines call */ + master->pub.call_pass_startup = TRUE; + } + break; +#ifdef ENTROPY_OPT_SUPPORTED + case huff_opt_pass: + /* Do Huffman optimization for a scan after the first one. */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (cinfo->Ss != 0 || cinfo->Ah == 0) { + (*cinfo->entropy->start_pass) (cinfo, TRUE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + master->pub.call_pass_startup = FALSE; + break; + } + /* Special case: Huffman DC refinement scans need no Huffman table + * and therefore we can skip the optimization pass for them. + */ + master->pass_type = output_pass; + master->pass_number++; + /*FALLTHROUGH*/ +#endif + case output_pass: + /* Do a data-output pass. */ + /* We need not repeat per-scan setup if prior optimization pass did it. */ + if (! cinfo->optimize_coding) { + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + } + (*cinfo->entropy->start_pass) (cinfo, FALSE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + /* We emit frame/scan headers now */ + if (master->scan_number == 0) + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); + master->pub.call_pass_startup = FALSE; + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + + master->pub.is_last_pass = (master->pass_number == master->total_passes-1); + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->total_passes; + } +} + + +/* + * Special start-of-pass hook. + * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. + * In single-pass processing, we need this hook because we don't want to + * write frame/scan headers during jpeg_start_compress; we want to let the + * application write COM markers etc. between jpeg_start_compress and the + * jpeg_write_scanlines loop. + * In multi-pass processing, this routine is not used. + */ + +METHODDEF(void) +pass_startup (j_compress_ptr cinfo) +{ + cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ + + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); +} + + +/* + * Finish up at end of pass. + */ + +METHODDEF(void) +finish_pass_master (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* The entropy coder always needs an end-of-pass call, + * either to analyze statistics or to flush its output buffer. + */ + (*cinfo->entropy->finish_pass) (cinfo); + + /* Update state for next pass */ + switch (master->pass_type) { + case main_pass: + /* next pass is either output of scan 0 (after optimization) + * or output of scan 1 (if no optimization). + */ + master->pass_type = output_pass; + if (! cinfo->optimize_coding) + master->scan_number++; + break; + case huff_opt_pass: + /* next pass is always output of current scan */ + master->pass_type = output_pass; + break; + case output_pass: + /* next pass is either optimization or output of next scan */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + master->scan_number++; + break; + } + + master->pass_number++; +} + + +/* + * Initialize master compression control. + */ + +GLOBAL(void) +jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) +{ + my_master_ptr master; + + master = (my_master_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_comp_master)); + cinfo->master = &master->pub; + master->pub.prepare_for_pass = prepare_for_pass; + master->pub.pass_startup = pass_startup; + master->pub.finish_pass = finish_pass_master; + master->pub.is_last_pass = FALSE; + + /* Validate parameters, determine derived values */ + initial_setup(cinfo); + + if (cinfo->scan_info != NULL) { +#ifdef C_MULTISCAN_FILES_SUPPORTED + validate_script(cinfo); + if (cinfo->block_size < DCTSIZE) + reduce_script(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + cinfo->num_scans = 1; + } + + if (cinfo->optimize_coding) + cinfo->arith_code = FALSE; /* disable arithmetic coding */ + else if (! cinfo->arith_code && + (cinfo->progressive_mode || + (cinfo->block_size > 1 && cinfo->block_size < DCTSIZE))) + /* TEMPORARY HACK ??? */ + /* assume default tables no good for progressive or reduced AC mode */ + cinfo->optimize_coding = TRUE; /* force Huffman optimization */ + + /* Initialize my private state */ + if (transcode_only) { + /* no main pass in transcoding */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + else + master->pass_type = output_pass; + } else { + /* for normal compression, first pass is always this type: */ + master->pass_type = main_pass; + } + master->scan_number = 0; + master->pass_number = 0; + if (cinfo->optimize_coding) + master->total_passes = cinfo->num_scans * 2; + else + master->total_passes = cinfo->num_scans; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcomapi.c b/widget/milsko/milskosrc/external/libjpeg/src/jcomapi.c new file mode 100644 index 0000000000..678c5d12d0 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcomapi.c @@ -0,0 +1,244 @@ +/* + * jcomapi.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface routines that are used for both + * compression and decompression. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Abort processing of a JPEG compression or decompression operation, + * but don't destroy the object itself. + * + * For this, we merely clean up all the nonpermanent memory pools. + * Note that temp files (virtual arrays) are not allowed to belong to + * the permanent pool, so we will be able to close all temp files here. + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_abort (j_common_ptr cinfo) +{ + int pool; + + /* Do nothing if called on a not-initialized or destroyed JPEG object. */ + if (cinfo->mem == NULL) + return; + + /* Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { + (*cinfo->mem->free_pool) (cinfo, pool); + } + + /* Reset overall state for possible reuse of object */ + if (cinfo->is_decompressor) { + cinfo->global_state = DSTATE_START; + /* Try to keep application from accessing now-deleted marker list. + * A bit kludgy to do it here, but this is the most central place. + */ + ((j_decompress_ptr) cinfo)->marker_list = NULL; + } else { + cinfo->global_state = CSTATE_START; + } +} + + +/* + * Destruction of a JPEG object. + * + * Everything gets deallocated except the master jpeg_compress_struct itself + * and the error manager struct. Both of these are supplied by the application + * and must be freed, if necessary, by the application. (Often they are on + * the stack and so don't need to be freed anyway.) + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_destroy (j_common_ptr cinfo) +{ + /* We need only tell the memory manager to release everything. */ + /* NB: mem pointer is NULL if memory mgr failed to initialize. */ + if (cinfo->mem != NULL) + (*cinfo->mem->self_destruct) (cinfo); + cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ + cinfo->global_state = 0; /* mark it destroyed */ +} + + +/* + * Convenience routines for allocating quantization and Huffman tables. + * (Would jutils.c be a more reasonable place to put these?) + */ + +GLOBAL(JQUANT_TBL *) +jpeg_alloc_quant_table (j_common_ptr cinfo) +{ + JQUANT_TBL *tbl; + + tbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} + + +GLOBAL(JHUFF_TBL *) +jpeg_alloc_huff_table (j_common_ptr cinfo) +{ + JHUFF_TBL *tbl; + + tbl = (JHUFF_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} + + +/* + * Set up the standard Huffman tables (cf. JPEG standard section K.3). + * IMPORTANT: these are only valid for 8-bit data precision! + * (Would jutils.c be a more reasonable place to put this?) + */ + +GLOBAL(JHUFF_TBL *) +jpeg_std_huff_table (j_common_ptr cinfo, boolean isDC, int tblno) +{ + JHUFF_TBL **htblptr, *htbl; + const UINT8 *bits, *val; + int nsymbols, len; + + static const UINT8 bits_dc_luminance[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_luminance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_dc_chrominance[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_chrominance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_ac_luminance[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 val_ac_luminance[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 bits_ac_chrominance[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 val_ac_chrominance[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + if (cinfo->is_decompressor) { + if (isDC) + htblptr = ((j_decompress_ptr) cinfo)->dc_huff_tbl_ptrs; + else + htblptr = ((j_decompress_ptr) cinfo)->ac_huff_tbl_ptrs; + } else { + if (isDC) + htblptr = ((j_compress_ptr) cinfo)->dc_huff_tbl_ptrs; + else + htblptr = ((j_compress_ptr) cinfo)->ac_huff_tbl_ptrs; + } + + switch (tblno) { + case 0: + if (isDC) { + bits = bits_dc_luminance; + val = val_dc_luminance; + } else { + bits = bits_ac_luminance; + val = val_ac_luminance; + } + break; + case 1: + if (isDC) { + bits = bits_dc_chrominance; + val = val_dc_chrominance; + } else { + bits = bits_ac_chrominance; + val = val_ac_chrominance; + } + break; + default: + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + return NULL; /* avoid compiler warnings for uninitialized variables */ + } + + if (htblptr[tblno] == NULL) + htblptr[tblno] = jpeg_alloc_huff_table(cinfo); + + htbl = htblptr[tblno]; + + /* Copy the number-of-symbols-of-each-code-length counts */ + MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); + + /* Validate the counts. We do this here mainly so we can copy the right + * number of symbols from the val[] array, without risking marching off + * the end of memory. jxhuff.c will do a more thorough test later. + */ + nsymbols = 0; + for (len = 1; len <= 16; len++) + nsymbols += bits[len]; + if (nsymbols > 256) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + if (nsymbols > 0) + MEMCOPY(htbl->huffval, val, nsymbols * SIZEOF(UINT8)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + htbl->sent_table = FALSE; + + return htbl; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcparam.c b/widget/milsko/milskosrc/external/libjpeg/src/jcparam.c new file mode 100644 index 0000000000..261ae86ca0 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcparam.c @@ -0,0 +1,591 @@ +/* + * jcparam.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2003-2022 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + * Applications do not have to use this file, but those that don't use it + * must know a lot more about the innards of the JPEG code. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Quantization table setup routines + */ + +GLOBAL(void) +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) +/* Define a quantization table equal to the basic_table times + * a scale factor (given as a percentage). + * If force_baseline is TRUE, the computed quantization table entries + * are limited to 1..255 for JPEG baseline compatibility. + */ +{ + JQUANT_TBL ** qtblptr; + int i; + long temp; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl); + + qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; + if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */ + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)->quantval[i] = (UINT16) temp; + } + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*qtblptr)->sent_table = FALSE; +} + + +/* These are the sample quantization tables given in JPEG spec section K.1. + * NOTE: chrominance DC value is changed from 17 to 16 for lossless support. + * The spec says that the values given produce "good" quality, + * and when divided by 2, "very good" quality. + */ +static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 +}; +static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { + 16, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + + +GLOBAL(void) +jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and straight percentage-scaling quality scales. + * This entry point allows different scalings for luminance and chrominance. + */ +{ + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + cinfo->q_scale_factor[0], force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + cinfo->q_scale_factor[1], force_baseline); +} + + +GLOBAL(void) +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and a straight percentage-scaling quality scale. In most cases it's better + * to use jpeg_set_quality (below); this entry point is provided for + * applications that insist on a linear percentage scaling. + */ +{ + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + scale_factor, force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + scale_factor, force_baseline); +} + + +GLOBAL(int) +jpeg_quality_scaling (int quality) +/* Convert a user-specified quality rating to a percentage scaling factor + * for an underlying quantization table, using our recommended scaling curve. + * The input 'quality' factor should be 0 (terrible) to 100 (very good). + */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table + * to make all the table entries 1 (hence, minimum quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + return quality; +} + + +GLOBAL(void) +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables. + * This is the standard quality-adjusting entry point for typical user + * interfaces; only those who want detailed control over quantization tables + * would use the preceding routines directly. + */ +{ + /* Convert user 0-100 rating to percentage scaling */ + quality = jpeg_quality_scaling(quality); + + /* Set up standard quality tables */ + jpeg_set_linear_quality(cinfo, quality, force_baseline); +} + + +/* + * Reset standard Huffman tables + */ + +LOCAL(void) +std_huff_tables (j_compress_ptr cinfo) +{ + if (cinfo->dc_huff_tbl_ptrs[0] != NULL) + (void) jpeg_std_huff_table((j_common_ptr) cinfo, TRUE, 0); + + if (cinfo->ac_huff_tbl_ptrs[0] != NULL) + (void) jpeg_std_huff_table((j_common_ptr) cinfo, FALSE, 0); + + if (cinfo->dc_huff_tbl_ptrs[1] != NULL) + (void) jpeg_std_huff_table((j_common_ptr) cinfo, TRUE, 1); + + if (cinfo->ac_huff_tbl_ptrs[1] != NULL) + (void) jpeg_std_huff_table((j_common_ptr) cinfo, FALSE, 1); +} + + +/* + * Default parameter setup for compression. + * + * Applications that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. This + * is the recommended approach since, if we add any new parameters, + * your code will still work (they'll be set to reasonable defaults). + */ + +GLOBAL(void) +jpeg_set_defaults (j_compress_ptr cinfo) +{ + int i; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Allocate comp_info array large enough for maximum component count. + * Array is made permanent in case application wants to compress + * multiple images at same param settings. + */ + if (cinfo->comp_info == NULL) + cinfo->comp_info = (jpeg_component_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + MAX_COMPONENTS * SIZEOF(jpeg_component_info)); + + /* Initialize everything not dependent on the color space */ + + cinfo->scale_num = 1; /* 1:1 scaling */ + cinfo->scale_denom = 1; + cinfo->data_precision = BITS_IN_JSAMPLE; + /* Set up two quantization tables using default quality of 75 */ + jpeg_set_quality(cinfo, 75, TRUE); + /* Reset standard Huffman tables */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Default is no multiple-scan output */ + cinfo->scan_info = NULL; + cinfo->num_scans = 0; + + /* Expect normal source image, not raw downsampled data */ + cinfo->raw_data_in = FALSE; + + /* The standard Huffman tables are only valid for 8-bit data precision. + * If the precision is higher, use arithmetic coding. + * (Alternatively, using Huffman coding would be possible with forcing + * optimization on so that usable tables will be computed, or by + * supplying default tables that are valid for the desired precision.) + * Otherwise, use Huffman coding by default. + */ + cinfo->arith_code = cinfo->data_precision > 8 ? TRUE : FALSE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* By default, apply fancy downsampling */ + cinfo->do_fancy_downsampling = TRUE; + + /* No input smoothing */ + cinfo->smoothing_factor = 0; + + /* DCT algorithm preference */ + cinfo->dct_method = JDCT_DEFAULT; + + /* No restart markers */ + cinfo->restart_interval = 0; + cinfo->restart_in_rows = 0; + + /* Fill in default JFIF marker parameters. Note that whether the marker + * will actually be written is determined by jpeg_set_colorspace. + * + * By default, the library emits JFIF version code 1.01. + * An application that wants to emit JFIF 1.02 extension markers should set + * JFIF_minor_version to 2. We could probably get away with just defaulting + * to 1.02, but there may still be some decoders in use that will complain + * about that; saying 1.01 should minimize compatibility problems. + * + * For wide gamut colorspaces (BG_RGB and BG_YCC), the major version will be + * overridden by jpeg_set_colorspace and set to 2. + */ + cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + /* No color transform */ + cinfo->color_transform = JCT_NONE; + + /* Choose JPEG colorspace based on input space, set defaults accordingly */ + + jpeg_default_colorspace(cinfo); +} + + +/* + * Select an appropriate JPEG colorspace for in_color_space. + */ + +GLOBAL(void) +jpeg_default_colorspace (j_compress_ptr cinfo) +{ + switch (cinfo->in_color_space) { + case JCS_UNKNOWN: + jpeg_set_colorspace(cinfo, JCS_UNKNOWN); + break; + case JCS_GRAYSCALE: + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + break; + case JCS_RGB: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_YCbCr: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_CMYK: + jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */ + break; + case JCS_YCCK: + jpeg_set_colorspace(cinfo, JCS_YCCK); + break; + case JCS_BG_RGB: + /* No translation for now -- conversion to BG_YCC not yet supportet */ + jpeg_set_colorspace(cinfo, JCS_BG_RGB); + break; + case JCS_BG_YCC: + jpeg_set_colorspace(cinfo, JCS_BG_YCC); + break; + default: + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + } +} + + +/* + * Set the JPEG colorspace, and choose colorspace-dependent default values. + */ + +GLOBAL(void) +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) +{ + jpeg_component_info * compptr; + int ci; + +#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \ + (compptr = &cinfo->comp_info[index], \ + compptr->component_id = (id), \ + compptr->h_samp_factor = (hsamp), \ + compptr->v_samp_factor = (vsamp), \ + compptr->quant_tbl_no = (quant), \ + compptr->dc_tbl_no = (dctbl), \ + compptr->ac_tbl_no = (actbl) ) + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* For all colorspaces, we use Q and Huff tables 0 for luminance components, + * tables 1 for chrominance components. + */ + + cinfo->jpeg_color_space = colorspace; + + cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */ + cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */ + + switch (colorspace) { + case JCS_UNKNOWN: + cinfo->num_components = cinfo->input_components; + if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + for (ci = 0; ci < cinfo->num_components; ci++) { + SET_COMP(ci, ci, 1,1, 0, 0,0); + } + break; + case JCS_GRAYSCALE: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 1; + /* JFIF specifies component ID 1 */ + SET_COMP(0, 0x01, 1,1, 0, 0,0); + break; + case JCS_RGB: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */ + cinfo->num_components = 3; + SET_COMP(0, 0x52 /* 'R' */, 1,1, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0); + SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0); + SET_COMP(2, 0x42 /* 'B' */, 1,1, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0); + break; + case JCS_YCbCr: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 3; + /* JFIF specifies component IDs 1,2,3 */ + /* We default to 2x2 subsamples of chrominance */ + SET_COMP(0, 0x01, 2,2, 0, 0,0); + SET_COMP(1, 0x02, 1,1, 1, 1,1); + SET_COMP(2, 0x03, 1,1, 1, 1,1); + break; + case JCS_CMYK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ + cinfo->num_components = 4; + SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0); + SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0); + SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0); + SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0); + break; + case JCS_YCCK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ + cinfo->num_components = 4; + SET_COMP(0, 0x01, 2,2, 0, 0,0); + SET_COMP(1, 0x02, 1,1, 1, 1,1); + SET_COMP(2, 0x03, 1,1, 1, 1,1); + SET_COMP(3, 0x04, 2,2, 0, 0,0); + break; + case JCS_BG_RGB: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->JFIF_major_version = 2; /* Set JFIF major version = 2 */ + cinfo->num_components = 3; + /* Add offset 0x20 to the normal R/G/B component IDs */ + SET_COMP(0, 0x72 /* 'r' */, 1,1, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0); + SET_COMP(1, 0x67 /* 'g' */, 1,1, 0, 0,0); + SET_COMP(2, 0x62 /* 'b' */, 1,1, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0, + cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0); + break; + case JCS_BG_YCC: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->JFIF_major_version = 2; /* Set JFIF major version = 2 */ + cinfo->num_components = 3; + /* Add offset 0x20 to the normal Cb/Cr component IDs */ + /* We default to 2x2 subsamples of chrominance */ + SET_COMP(0, 0x01, 2,2, 0, 0,0); + SET_COMP(1, 0x22, 1,1, 1, 1,1); + SET_COMP(2, 0x23, 1,1, 1, 1,1); + break; + default: + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + } +} + + +#ifdef C_PROGRESSIVE_SUPPORTED + +LOCAL(jpeg_scan_info *) +fill_a_scan (jpeg_scan_info * scanptr, int ci, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for specified component */ +{ + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_scans (jpeg_scan_info * scanptr, int ncomps, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for each component */ +{ + int ci; + + for (ci = 0; ci < ncomps; ci++) { + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) +/* Support routine: generate interleaved DC scan if possible, else N scans */ +{ + int ci; + + if (ncomps <= MAX_COMPS_IN_SCAN) { + /* Single interleaved DC scan */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = scanptr->Se = 0; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } else { + /* Noninterleaved DC scan for each component */ + scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al); + } + return scanptr; +} + + +/* + * Create a recommended progressive-JPEG script. + * cinfo->num_components and cinfo->jpeg_color_space must be correct. + */ + +GLOBAL(void) +jpeg_simple_progression (j_compress_ptr cinfo) +{ + int ncomps = cinfo->num_components; + int nscans; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Figure space needed for script. Calculation must match code below! */ + if (ncomps == 3 && + (cinfo->jpeg_color_space == JCS_YCbCr || + cinfo->jpeg_color_space == JCS_BG_YCC)) { + /* Custom script for YCC color images. */ + nscans = 10; + } else { + /* All-purpose script for other color spaces. */ + if (ncomps > MAX_COMPS_IN_SCAN) + nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */ + else + nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */ + } + + /* Allocate space for script. + * We need to put it in the permanent pool in case the application performs + * multiple compressions without changing the settings. To avoid a memory + * leak if jpeg_simple_progression is called repeatedly for the same JPEG + * object, we try to re-use previously allocated space, and we allocate + * enough space to handle YCC even if initially asked for grayscale. + */ + if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { + cinfo->script_space_size = MAX(nscans, 10); + cinfo->script_space = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + cinfo->script_space_size * SIZEOF(jpeg_scan_info)); + } + scanptr = cinfo->script_space; + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + if (ncomps == 3 && + (cinfo->jpeg_color_space == JCS_YCbCr || + cinfo->jpeg_color_space == JCS_BG_YCC)) { + /* Custom script for YCC color images. */ + /* Initial DC scan */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + /* Initial AC scan: get some luma data out in a hurry */ + scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2); + /* Chroma data is too small to be worth expending many scans on */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1); + /* Complete spectral selection for luma AC */ + scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2); + /* Refine next bit of luma AC */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1); + /* Finish DC successive approximation */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + /* Finish AC successive approximation */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0); + /* Luma bottom bit comes last since it's usually largest scan */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0); + } else { + /* All-purpose script for other color spaces. */ + /* Successive approximation first pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2); + scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2); + /* Successive approximation second pass */ + scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1); + /* Successive approximation final pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0); + } +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcprepct.c b/widget/milsko/milskosrc/external/libjpeg/src/jcprepct.c new file mode 100644 index 0000000000..586964bd44 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcprepct.c @@ -0,0 +1,358 @@ +/* + * jcprepct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2003-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the compression preprocessing controller. + * This controller manages the color conversion, downsampling, + * and edge expansion steps. + * + * Most of the complexity here is associated with buffering input rows + * as required by the downsampler. See the comments at the head of + * jcsample.c for the downsampler's needs. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* At present, jcsample.c can request context rows only for smoothing. + * In the future, we might also need context rows for CCIR601 sampling + * or other more-complex downsampling procedures. The code to support + * context rows should be compiled only if needed. + */ +#ifdef INPUT_SMOOTHING_SUPPORTED +#define CONTEXT_ROWS_SUPPORTED +#endif + + +/* + * For the simple (no-context-row) case, we just need to buffer one + * row group's worth of pixels for the downsampling step. At the bottom of + * the image, we pad to a full row group by replicating the last pixel row. + * The downsampler's last output row is then replicated if needed to pad + * out to a full iMCU row. + * + * When providing context rows, we must buffer three row groups' worth of + * pixels. Three row groups are physically allocated, but the row pointer + * arrays are made five row groups high, with the extra pointers above and + * below "wrapping around" to point to the last and first real row groups. + * This allows the downsampler to access the proper context rows. + * At the top and bottom of the image, we create dummy context rows by + * copying the first or last real pixel row. This copying could be avoided + * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the + * trouble on the compression side. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_prep_controller pub; /* public fields */ + + /* Downsampling input buffer. This buffer holds color-converted data + * until we have enough to do a downsample step. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + JDIMENSION rows_to_go; /* counts rows remaining in source image */ + int next_buf_row; /* index of next row to store in color_buf */ + +#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */ + int this_row_group; /* starting row index of group to process */ + int next_buf_stop; /* downsample when we reach this index */ +#endif +} my_prep_controller; + +typedef my_prep_controller * my_prep_ptr; + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + + if (pass_mode != JBUF_PASS_THRU) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Initialize total-height counter for detecting bottom of image */ + prep->rows_to_go = cinfo->image_height; + /* Mark the conversion buffer empty */ + prep->next_buf_row = 0; +#ifdef CONTEXT_ROWS_SUPPORTED + /* Preset additional state variables for context mode. + * These aren't used in non-context mode, so we needn't test which mode. + */ + prep->this_row_group = 0; + /* Set next_buf_stop to stop after two row groups have been read in. */ + prep->next_buf_stop = 2 * cinfo->max_v_samp_factor; +#endif +} + + +/* + * Expand an image vertically from height input_rows to height output_rows, + * by duplicating the bottom row. + */ + +LOCAL(void) +expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, + int input_rows, int output_rows) +{ + register int row; + + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(image_data + input_rows - 1, + image_data + row, + 1, num_cols); + } +} + + +/* + * Process some data in the simple no-context case. + * + * Preprocessor output data is counted in "row groups". A row group + * is defined to be v_samp_factor sample rows of each component. + * Downsampling will produce this much data from each max_v_samp_factor + * input rows. + */ + +METHODDEF(void) +pre_process_data (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + JDIMENSION inrows; + jpeg_component_info * compptr; + + while (*in_row_ctr < in_rows_avail && + *out_row_group_ctr < out_row_groups_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = cinfo->max_v_samp_factor - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + /* If at bottom of image, pad to fill the conversion buffer. */ + if (prep->rows_to_go == 0 && + prep->next_buf_row < cinfo->max_v_samp_factor) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, cinfo->max_v_samp_factor); + } + prep->next_buf_row = cinfo->max_v_samp_factor; + } + /* If we've filled the conversion buffer, empty it. */ + if (prep->next_buf_row == cinfo->max_v_samp_factor) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, (JDIMENSION) 0, + output_buf, *out_row_group_ctr); + prep->next_buf_row = 0; + (*out_row_group_ctr)++; + } + /* If at bottom of image, pad the output to a full iMCU height. + * Note we assume the caller is providing a one-iMCU-height output buffer! + */ + if (prep->rows_to_go == 0 && + *out_row_group_ctr < out_row_groups_avail) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + numrows = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; + expand_bottom_edge(output_buf[ci], + compptr->width_in_blocks * compptr->DCT_h_scaled_size, + (int) (*out_row_group_ctr * numrows), + (int) (out_row_groups_avail * numrows)); + } + *out_row_group_ctr = out_row_groups_avail; + break; /* can exit outer loop without test */ + } + } +} + + +#ifdef CONTEXT_ROWS_SUPPORTED + +/* + * Process some data in the context case. + */ + +METHODDEF(void) +pre_process_context (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + int buf_height = cinfo->max_v_samp_factor * 3; + JDIMENSION inrows; + + while (*out_row_group_ctr < out_row_groups_avail) { + if (*in_row_ctr < in_rows_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = prep->next_buf_stop - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + /* Pad at top of image, if first time through */ + if (prep->rows_to_go == cinfo->image_height) { + for (ci = 0; ci < cinfo->num_components; ci++) { + int row; + for (row = 1; row <= cinfo->max_v_samp_factor; row++) { + jcopy_sample_rows(prep->color_buf[ci], + prep->color_buf[ci] - row, + 1, cinfo->image_width); + } + } + } + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + } else { + /* Return for more data, unless we are at the bottom of the image. */ + if (prep->rows_to_go != 0) + break; + /* When at bottom of image, pad to fill the conversion buffer. */ + if (prep->next_buf_row < prep->next_buf_stop) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, prep->next_buf_stop); + } + prep->next_buf_row = prep->next_buf_stop; + } + } + /* If we've gotten enough data, downsample a row group. */ + if (prep->next_buf_row == prep->next_buf_stop) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, + (JDIMENSION) prep->this_row_group, + output_buf, *out_row_group_ctr); + (*out_row_group_ctr)++; + /* Advance pointers with wraparound as necessary. */ + prep->this_row_group += cinfo->max_v_samp_factor; + if (prep->this_row_group >= buf_height) + prep->this_row_group = 0; + if (prep->next_buf_row >= buf_height) + prep->next_buf_row = 0; + prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; + } + } +} + + +/* + * Create the wrapped-around downsampling input buffer needed for context mode. + */ + +LOCAL(void) +create_context_buffer (j_compress_ptr cinfo) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int rgroup_height = cinfo->max_v_samp_factor; + int ci, i; + jpeg_component_info * compptr; + JSAMPARRAY true_buffer, fake_buffer; + + /* Grab enough space for fake row pointers for all the components; + * we need five row groups' worth of pointers for each component. + */ + fake_buffer = (JSAMPARRAY) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (cinfo->num_components * 5 * rgroup_height) * SIZEOF(JSAMPROW)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate the actual buffer space (3 row groups) for this component. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + true_buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * + cinfo->min_DCT_h_scaled_size * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) (3 * rgroup_height)); + /* Copy true buffer row pointers into the middle of the fake row array */ + MEMCOPY(fake_buffer + rgroup_height, true_buffer, + 3 * rgroup_height * SIZEOF(JSAMPROW)); + /* Fill in the above and below wraparound pointers */ + for (i = 0; i < rgroup_height; i++) { + fake_buffer[i] = true_buffer[2 * rgroup_height + i]; + fake_buffer[4 * rgroup_height + i] = true_buffer[i]; + } + prep->color_buf[ci] = fake_buffer + rgroup_height; + fake_buffer += 5 * rgroup_height; /* point to space for next component */ + } +} + +#endif /* CONTEXT_ROWS_SUPPORTED */ + + +/* + * Initialize preprocessing controller. + */ + +GLOBAL(void) +jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_prep_ptr prep; + int ci; + jpeg_component_info * compptr; + + if (need_full_buffer) /* safety check */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + prep = (my_prep_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_prep_controller)); + cinfo->prep = &prep->pub; + prep->pub.start_pass = start_pass_prep; + + /* Allocate the color conversion buffer. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + if (cinfo->downsample->need_context_rows) { + /* Set up to provide context rows */ +#ifdef CONTEXT_ROWS_SUPPORTED + prep->pub.pre_process_data = pre_process_context; + create_context_buffer(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* No context, just make it tall enough for one row group */ + prep->pub.pre_process_data = pre_process_data; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * + cinfo->min_DCT_h_scaled_size * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jcsample.c b/widget/milsko/milskosrc/external/libjpeg/src/jcsample.c new file mode 100644 index 0000000000..2372c4173f --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jcsample.c @@ -0,0 +1,545 @@ +/* + * jcsample.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2003-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains downsampling routines. + * + * Downsampling input data is counted in "row groups". A row group + * is defined to be max_v_samp_factor pixel rows of each component, + * from which the downsampler produces v_samp_factor sample rows. + * A single row group is processed in each call to the downsampler module. + * + * The downsampler is responsible for edge-expansion of its output data + * to fill an integral number of DCT blocks horizontally. The source buffer + * may be modified if it is helpful for this purpose (the source buffer is + * allocated wide enough to correspond to the desired output width). + * The caller (the prep controller) is responsible for vertical padding. + * + * The downsampler may request "context rows" by setting need_context_rows + * during startup. In this case, the input arrays will contain at least + * one row group's worth of pixels above and below the passed-in data; + * the caller will create dummy rows at image top and bottom by replicating + * the first or last real pixel row. + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + * + * The downsampling algorithm used here is a simple average of the source + * pixels covered by the output pixel. The hi-falutin sampling literature + * refers to this as a "box filter". In general the characteristics of a box + * filter are not very good, but for the specific cases we normally use (1:1 + * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not + * nearly so bad. If you intend to use other sampling ratios, you'd be well + * advised to improve this code. + * + * A simple input-smoothing capability is provided. This is mainly intended + * for cleaning up color-dithered GIF input files (if you find it inadequate, + * we suggest using an external filtering program such as pnmconvol). When + * enabled, each input pixel P is replaced by a weighted sum of itself and its + * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, + * where SF = (smoothing_factor / 1024). + * Currently, smoothing is only supported for 2h2v sampling factors. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to downsample a single component */ +typedef JMETHOD(void, downsample1_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +/* Private subobject */ + +typedef struct { + struct jpeg_downsampler pub; /* public fields */ + + /* Downsampling method pointers, one per component */ + downsample1_ptr methods[MAX_COMPONENTS]; + + /* Height of an output row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_downsample need not + * recompute them each time. They are unused for other downsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_downsampler; + +typedef my_downsampler * my_downsample_ptr; + + +/* + * Initialize for a downsampling pass. + */ + +METHODDEF(void) +start_pass_downsample (j_compress_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Expand a component horizontally from width input_cols to width output_cols, + * by duplicating the rightmost samples. + */ + +LOCAL(void) +expand_right_edge (JSAMPARRAY image_data, int num_rows, + JDIMENSION input_cols, JDIMENSION output_cols) +{ + register JSAMPROW ptr; + register JSAMPLE pixval; + register int count; + int row; + int numcols = (int) (output_cols - input_cols); + + if (numcols > 0) { + for (row = 0; row < num_rows; row++) { + ptr = image_data[row] + input_cols; + pixval = ptr[-1]; /* don't need GETJSAMPLE() here */ + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } +} + + +/* + * Do downsampling for a whole row group (all components). + * + * In this version we simply downsample each component independently. + */ + +METHODDEF(void) +sep_downsample (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, JDIMENSION out_row_group_index) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int ci; + jpeg_component_info * compptr; + JSAMPARRAY in_ptr, out_ptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + in_ptr = input_buf[ci] + in_row_index; + out_ptr = output_buf[ci] + + (out_row_group_index * downsample->rowgroup_height[ci]); + (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr); + } +} + + +/* + * Downsample pixel values of a single component. + * One row group is processed per call. + * This version handles arbitrary integral sampling ratios, without smoothing. + * Note that this version is not actually used for customary sampling ratios. + */ + +METHODDEF(void) +int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + JSAMPROW inptr, outptr; + INT32 outvalue; + + h_expand = downsample->h_expand[compptr->component_index]; + v_expand = downsample->v_expand[compptr->component_index]; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * h_expand); + + inrow = outrow = 0; + while (inrow < cinfo->max_v_samp_factor) { + outptr = output_data[outrow]; + for (outcol = 0, outcol_h = 0; outcol < output_cols; + outcol++, outcol_h += h_expand) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + outcol_h; + for (h = 0; h < h_expand; h++) { + outvalue += (INT32) GETJSAMPLE(*inptr++); + } + } + *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix); + } + inrow += v_expand; + outrow++; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * without smoothing. + */ + +METHODDEF(void) +fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + /* Copy the data */ + jcopy_sample_rows(input_data, output_data, + cinfo->max_v_samp_factor, cinfo->image_width); + /* Edge-expand */ + expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width, + compptr->width_in_blocks * compptr->DCT_h_scaled_size); +} + + +/* + * Downsample pixel values of a single component. + * This version handles the common case of 2:1 horizontal and 1:1 vertical, + * without smoothing. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + register JSAMPROW inptr, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + outptr = output_data[inrow]; + inptr = input_data[inrow]; + bias = 0; /* bias = 0,1,0,1,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) + + bias) >> 1); + bias ^= 1; /* 0=>1, 1=>0 */ + inptr += 2; + } + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * without smoothing. + */ + +METHODDEF(void) +h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + register JSAMPROW inptr0, inptr1, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + inrow = outrow = 0; + while (inrow < cinfo->max_v_samp_factor) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + bias = 1; /* bias = 1,2,1,2,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) + + bias) >> 2); + bias ^= 3; /* 1=>2, 2=>1 */ + inptr0 += 2; inptr1 += 2; + } + inrow += 2; + outrow++; + } +} + + +#ifdef INPUT_SMOOTHING_SUPPORTED + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols * 2); + + /* We don't bother to form the individual "smoothed" input pixel values; + * we can directly compute the output which is the average of the four + * smoothed values. Each of the four member pixels contributes a fraction + * (1-8*SF) to its own smoothed image and a fraction SF to each of the three + * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final + * output. The four corner-adjacent neighbor pixels contribute a fraction + * SF to just one smoothed pixel, or SF/4 to the final output; while the + * eight edge-adjacent neighbors contribute SF to each of two smoothed + * pixels, or SF/2 overall. In order to use integer arithmetic, these + * factors are scaled by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ + neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */ + + inrow = outrow = 0; + while (inrow < cinfo->max_v_samp_factor) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+2]; + + /* Special case for first column: pretend column -1 is same as column 0 */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]); + neighsum += neighsum; + neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + /* sum of pixels directly mapped to this output element */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + /* sum of edge-neighbor pixels */ + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]); + /* The edge-neighbors count twice as much as corner-neighbors */ + neighsum += neighsum; + /* Add in the corner-neighbors */ + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]); + /* form final output scaled up by 2^16 */ + membersum = membersum * memberscale + neighsum * neighscale; + /* round, descale and output it */ + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]); + neighsum += neighsum; + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + inrow += 2; + outrow++; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + register JSAMPROW inptr, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + int colsum, lastcolsum, nextcolsum; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols); + + /* Each of the eight neighbor pixels contributes a fraction SF to the + * smoothed pixel, while the main pixel contributes (1-8*SF). In order + * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ + neighscale = cinfo->smoothing_factor * 64; /* scaled SF */ + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + outptr = output_data[inrow]; + inptr = input_data[inrow]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+1]; + + /* Special case for first column */ + colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) + + GETJSAMPLE(*inptr); + membersum = GETJSAMPLE(*inptr++); + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = colsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + membersum = GETJSAMPLE(*inptr++); + above_ptr++; below_ptr++; + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + colsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + } +} + +#endif /* INPUT_SMOOTHING_SUPPORTED */ + + +/* + * Module initialization routine for downsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL(void) +jinit_downsampler (j_compress_ptr cinfo) +{ + my_downsample_ptr downsample; + int ci; + jpeg_component_info * compptr; + boolean smoothok = TRUE; + int h_in_group, v_in_group, h_out_group, v_out_group; + + downsample = (my_downsample_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_downsampler)); + cinfo->downsample = &downsample->pub; + downsample->pub.start_pass = start_pass_downsample; + downsample->pub.downsample = sep_downsample; + downsample->pub.need_context_rows = FALSE; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, and set up method pointers */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Compute size of an "output group" for DCT scaling. This many samples + * are to be converted from max_h_samp_factor * max_v_samp_factor pixels. + */ + h_out_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) / + cinfo->min_DCT_h_scaled_size; + v_out_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; + h_in_group = cinfo->max_h_samp_factor; + v_in_group = cinfo->max_v_samp_factor; + downsample->rowgroup_height[ci] = v_out_group; /* save for use later */ + if (h_in_group == h_out_group && v_in_group == v_out_group) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = fullsize_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = fullsize_downsample; + } else if (h_in_group == h_out_group * 2 && + v_in_group == v_out_group) { + smoothok = FALSE; + downsample->methods[ci] = h2v1_downsample; + } else if (h_in_group == h_out_group * 2 && + v_in_group == v_out_group * 2) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = h2v2_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = h2v2_downsample; + } else if ((h_in_group % h_out_group) == 0 && + (v_in_group % v_out_group) == 0) { + smoothok = FALSE; + downsample->methods[ci] = int_downsample; + downsample->h_expand[ci] = (UINT8) (h_in_group / h_out_group); + downsample->v_expand[ci] = (UINT8) (v_in_group / v_out_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + } + +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor && !smoothok) + TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL); +#endif +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jctrans.c b/widget/milsko/milskosrc/external/libjpeg/src/jctrans.c new file mode 100644 index 0000000000..261dd2996e --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jctrans.c @@ -0,0 +1,399 @@ +/* + * jctrans.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * Modified 2000-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding compression, + * that is, writing raw DCT coefficient arrays to an output JPEG file. + * The routines in jcapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(void) transencode_master_selection + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL(void) transencode_coef_controller + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); + + +/* + * Compression initialization for writing raw-coefficient data. + * Before calling this, all parameters and a data destination must be set up. + * Call jpeg_finish_compress() to actually write the data. + * + * The number of passed virtual arrays must match cinfo->num_components. + * Note that the virtual arrays need not be filled or even realized at + * the time write_coefficients is called; indeed, if the virtual arrays + * were requested from this compression object's memory manager, they + * typically will be realized during this routine and filled afterwards. + */ + +GLOBAL(void) +jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Mark all tables to be written */ + jpeg_suppress_tables(cinfo, FALSE); + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + transencode_master_selection(cinfo, coef_arrays); + /* Wait for jpeg_finish_compress() call */ + cinfo->next_scanline = 0; /* so jpeg_write_marker works */ + cinfo->global_state = CSTATE_WRCOEFS; +} + + +/* + * Initialize the compression object with default parameters, + * then copy from the source object all parameters needed for lossless + * transcoding. Parameters that can be varied without loss (such as + * scan script and Huffman optimization) are left in their default states. + */ + +GLOBAL(void) +jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo) +{ + JQUANT_TBL ** qtblptr; + jpeg_component_info *incomp, *outcomp; + JQUANT_TBL *c_quant, *slot_quant; + int tblno, ci, coefi; + + /* Safety check to ensure start_compress not called yet. */ + if (dstinfo->global_state != CSTATE_START) + ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); + /* Copy fundamental image dimensions */ + dstinfo->image_width = srcinfo->image_width; + dstinfo->image_height = srcinfo->image_height; + dstinfo->input_components = srcinfo->num_components; + dstinfo->in_color_space = srcinfo->jpeg_color_space; + dstinfo->jpeg_width = srcinfo->output_width; + dstinfo->jpeg_height = srcinfo->output_height; + dstinfo->min_DCT_h_scaled_size = srcinfo->min_DCT_h_scaled_size; + dstinfo->min_DCT_v_scaled_size = srcinfo->min_DCT_v_scaled_size; + /* Initialize all parameters to default values */ + jpeg_set_defaults(dstinfo); + /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. + * Fix it to get the right header markers for the image colorspace. + * Note: Entropy table assignment in jpeg_set_colorspace + * depends on color_transform. + * Adaption is also required for setting the appropriate + * entropy coding mode dependent on image data precision. + */ + dstinfo->color_transform = srcinfo->color_transform; + jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); + dstinfo->data_precision = srcinfo->data_precision; + dstinfo->arith_code = srcinfo->data_precision > 8 ? TRUE : FALSE; + dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; + /* Copy the source's quantization tables. */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { + qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); + MEMCOPY((*qtblptr)->quantval, + srcinfo->quant_tbl_ptrs[tblno]->quantval, + SIZEOF((*qtblptr)->quantval)); + (*qtblptr)->sent_table = FALSE; + } + } + /* Copy the source's per-component info. + * Note we assume jpeg_set_defaults has allocated the dest comp_info array. + */ + dstinfo->num_components = srcinfo->num_components; + if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) + ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, + MAX_COMPONENTS); + for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; + ci < dstinfo->num_components; ci++, incomp++, outcomp++) { + outcomp->component_id = incomp->component_id; + outcomp->h_samp_factor = incomp->h_samp_factor; + outcomp->v_samp_factor = incomp->v_samp_factor; + outcomp->quant_tbl_no = incomp->quant_tbl_no; + /* Make sure saved quantization table for component matches the qtable + * slot. If not, the input file re-used this qtable slot. + * IJG encoder currently cannot duplicate this. + */ + tblno = outcomp->quant_tbl_no; + if (tblno < 0 || tblno >= NUM_QUANT_TBLS || + srcinfo->quant_tbl_ptrs[tblno] == NULL) + ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); + slot_quant = srcinfo->quant_tbl_ptrs[tblno]; + c_quant = incomp->quant_table; + if (c_quant != NULL) { + for (coefi = 0; coefi < DCTSIZE2; coefi++) { + if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) + ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); + } + } + /* Note: we do not copy the source's entropy table assignments; + * instead we rely on jpeg_set_colorspace to have made a suitable choice. + */ + } + /* Also copy JFIF version and resolution information, if available. + * Strictly speaking this isn't "critical" info, but it's nearly + * always appropriate to copy it if available. In particular, + * if the application chooses to copy JFIF 1.02 extension markers from + * the source file, we need to copy the version to make sure we don't + * emit a file that has 1.02 extensions but a claimed version of 1.01. + */ + if (srcinfo->saw_JFIF_marker) { + if (srcinfo->JFIF_major_version == 1 || + srcinfo->JFIF_major_version == 2) { + dstinfo->JFIF_major_version = srcinfo->JFIF_major_version; + dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version; + } + dstinfo->density_unit = srcinfo->density_unit; + dstinfo->X_density = srcinfo->X_density; + dstinfo->Y_density = srcinfo->Y_density; + } +} + + +LOCAL(void) +jpeg_calc_trans_dimensions (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + if (cinfo->min_DCT_h_scaled_size != cinfo->min_DCT_v_scaled_size) + ERREXIT2(cinfo, JERR_BAD_DCTSIZE, + cinfo->min_DCT_h_scaled_size, cinfo->min_DCT_v_scaled_size); + + cinfo->block_size = cinfo->min_DCT_h_scaled_size; +} + + +/* + * Master selection of compression modules for transcoding. + * This substitutes for jcinit.c's initialization of the full compressor. + */ + +LOCAL(void) +transencode_master_selection (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + /* Do computations that are needed before master selection phase */ + jpeg_calc_trans_dimensions(cinfo); + + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, TRUE /* transcode only */); + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) + jinit_arith_encoder(cinfo); + else { + jinit_huff_encoder(cinfo); + } + + /* We need a special coefficient buffer controller. */ + transencode_coef_controller(cinfo, coef_arrays); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI, JFIF) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} + + +/* + * The rest of this file is a special implementation of the coefficient + * buffer controller. This is similar to jccoefct.c, but it handles only + * output from presupplied virtual arrays. Furthermore, we generate any + * dummy padding blocks on-the-fly rather than expecting them to be present + * in the arrays. + */ + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* Virtual block array for each component. */ + jvirt_barray_ptr * whole_image; + + /* Workspace for constructing dummy blocks at right/bottom edges. */ + JBLOCK dummy_buffer[C_MAX_BLOCKS_IN_MCU]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + if (pass_mode != JBUF_CRANK_DEST) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); +} + + +/* + * Process some data. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, blockcnt; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yoffset + yindex < compptr->last_row_height) { + /* Fill in pointers to real blocks in this row */ + buffer_ptr = buffer[ci][yoffset + yindex] + start_col; + xindex = blockcnt; + do { + MCU_buffer[blkn++] = buffer_ptr++; + } while (--xindex); + /* Dummy blocks at right edge */ + if ((xindex = compptr->MCU_width - blockcnt) == 0) + continue; + } else { + /* At bottom of image, need a whole row of dummy blocks */ + xindex = compptr->MCU_width; + } + /* Fill in any dummy blocks needed in this row. + * Dummy blocks are filled in the same way as in jccoefct.c: + * all zeroes in the AC entries, DC entries equal to previous + * block's DC value. The init routine has already zeroed the + * AC entries, so we need only set the DC entries correctly. + */ + buffer_ptr = coef->dummy_buffer + blkn; + do { + buffer_ptr[0][0] = MCU_buffer[blkn-1][0][0]; + MCU_buffer[blkn++] = buffer_ptr++; + } while (--xindex); + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +/* + * Initialize coefficient buffer controller. + * + * Each passed coefficient array must be the right size for that + * coefficient: width_in_blocks wide and height_in_blocks high, + * with unitheight at least v_samp_factor. + */ + +LOCAL(void) +transencode_coef_controller (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_coef_controller)); + cinfo->coef = &coef->pub; + coef->pub.start_pass = start_pass_coef; + coef->pub.compress_data = compress_output; + + /* Save pointer to virtual arrays */ + coef->whole_image = coef_arrays; + + /* Pre-zero space for dummy DCT blocks */ + MEMZERO(coef->dummy_buffer, SIZEOF(coef->dummy_buffer)); +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdapimin.c b/widget/milsko/milskosrc/external/libjpeg/src/jdapimin.c new file mode 100644 index 0000000000..785e527226 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdapimin.c @@ -0,0 +1,412 @@ +/* + * jdapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * Modified 2009-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-decompression case or the + * transcoding-only case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jdapistd.c. But also see jcomapi.c for routines + * shared by compression and decompression, and jdtrans.c for the transcoding + * case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG decompression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_decompress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = TRUE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->src = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Initialize marker processor so application can override methods + * for COM, APPn markers before calling jpeg_read_header. + */ + cinfo->marker_list = NULL; + jinit_marker_reader(cinfo); + + /* And initialize the overall input controller. */ + jinit_input_controller(cinfo); + + /* OK, I'm ready */ + cinfo->global_state = DSTATE_START; +} + + +/* + * Destruction of a JPEG decompression object + */ + +GLOBAL(void) +jpeg_destroy_decompress (j_decompress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG decompression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_decompress (j_decompress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Set default decompression parameters. + */ + +LOCAL(void) +default_decompress_parms (j_decompress_ptr cinfo) +{ + int cid0, cid1, cid2, cid3; + + /* Guess the input colorspace, and set output colorspace accordingly. */ + /* Note application may override our guesses. */ + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = JCS_GRAYSCALE; + cinfo->out_color_space = JCS_GRAYSCALE; + break; + + case 3: + cid0 = cinfo->comp_info[0].component_id; + cid1 = cinfo->comp_info[1].component_id; + cid2 = cinfo->comp_info[2].component_id; + + /* For robust detection of standard colorspaces + * regardless of the presence of special markers, + * check component IDs from SOF marker first. + */ + if (cid0 == 0x01 && cid1 == 0x02 && cid2 == 0x03) + cinfo->jpeg_color_space = JCS_YCbCr; + else if (cid0 == 0x01 && cid1 == 0x22 && cid2 == 0x23) + cinfo->jpeg_color_space = JCS_BG_YCC; + else if (cid0 == 0x52 && cid1 == 0x47 && cid2 == 0x42) + cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ + else if (cid0 == 0x72 && cid1 == 0x67 && cid2 == 0x62) + cinfo->jpeg_color_space = JCS_BG_RGB; /* ASCII 'r', 'g', 'b' */ + else if (cinfo->saw_JFIF_marker) + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + else if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_RGB; + break; + case 1: + cinfo->jpeg_color_space = JCS_YCbCr; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + } + } else { + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + } + /* Always guess RGB is proper output colorspace. */ + cinfo->out_color_space = JCS_RGB; + break; + + case 4: + cid0 = cinfo->comp_info[0].component_id; + cid1 = cinfo->comp_info[1].component_id; + cid2 = cinfo->comp_info[2].component_id; + cid3 = cinfo->comp_info[3].component_id; + + /* For robust detection of standard colorspaces + * regardless of the presence of special markers, + * check component IDs from SOF marker first. + */ + if (cid0 == 0x01 && cid1 == 0x02 && cid2 == 0x03 && cid3 == 0x04) + cinfo->jpeg_color_space = JCS_YCCK; + else if (cid0 == 0x43 && cid1 == 0x4D && cid2 == 0x59 && cid3 == 0x4B) + cinfo->jpeg_color_space = JCS_CMYK; /* ASCII 'C', 'M', 'Y', 'K' */ + else if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_CMYK; + break; + case 2: + cinfo->jpeg_color_space = JCS_YCCK; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ + } + } else { + /* Unknown IDs and no special markers, assume straight CMYK. */ + cinfo->jpeg_color_space = JCS_CMYK; + } + cinfo->out_color_space = JCS_CMYK; + break; + + default: + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->out_color_space = JCS_UNKNOWN; + } + + /* Set defaults for other decompression parameters. */ + cinfo->scale_num = cinfo->block_size; /* 1:1 scaling */ + cinfo->scale_denom = cinfo->block_size; + cinfo->output_gamma = 1.0; + cinfo->buffered_image = FALSE; + cinfo->raw_data_out = FALSE; + cinfo->dct_method = JDCT_DEFAULT; + cinfo->do_fancy_upsampling = TRUE; + cinfo->do_block_smoothing = TRUE; + cinfo->quantize_colors = FALSE; + /* We set these in case application only sets quantize_colors. */ + cinfo->dither_mode = JDITHER_FS; +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; +#else + cinfo->two_pass_quantize = FALSE; +#endif + cinfo->desired_number_of_colors = 256; + cinfo->colormap = NULL; + /* Initialize for no mode change in buffered-image mode. */ + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; +} + + +/* + * Decompression startup: read start of JPEG datastream to see what's there. + * Need only initialize JPEG object and supply a data source before calling. + * + * This routine will read as far as the first SOS marker (ie, actual start of + * compressed data), and will save all tables and parameters in the JPEG + * object. It will also initialize the decompression parameters to default + * values, and finally return JPEG_HEADER_OK. On return, the application may + * adjust the decompression parameters and then call jpeg_start_decompress. + * (Or, if the application only wanted to determine the image parameters, + * the data need not be decompressed. In that case, call jpeg_abort or + * jpeg_destroy to release any temporary space.) + * If an abbreviated (tables only) datastream is presented, the routine will + * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then + * re-use the JPEG object to read the abbreviated image datastream(s). + * It is unnecessary (but OK) to call jpeg_abort in this case. + * The JPEG_SUSPENDED return code only occurs if the data source module + * requests suspension of the decompressor. In this case the application + * should load more source data and then re-call jpeg_read_header to resume + * processing. + * If a non-suspending data source is used and require_image is TRUE, then the + * return code need not be inspected since only JPEG_HEADER_OK is possible. + * + * This routine is now just a front end to jpeg_consume_input, with some + * extra error checking. + */ + +GLOBAL(int) +jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) +{ + int retcode; + + if (cinfo->global_state != DSTATE_START && + cinfo->global_state != DSTATE_INHEADER) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + retcode = jpeg_consume_input(cinfo); + + switch (retcode) { + case JPEG_REACHED_SOS: + retcode = JPEG_HEADER_OK; + break; + case JPEG_REACHED_EOI: + if (require_image) /* Complain if application wanted an image */ + ERREXIT(cinfo, JERR_NO_IMAGE); + /* Reset to start state; it would be safer to require the application to + * call jpeg_abort, but we can't change it now for compatibility reasons. + * A side effect is to free any temporary memory (there shouldn't be any). + */ + jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ + retcode = JPEG_HEADER_TABLES_ONLY; + break; + case JPEG_SUSPENDED: + /* no work */ + break; + } + + return retcode; +} + + +/* + * Consume data in advance of what the decompressor requires. + * This can be called at any time once the decompressor object has + * been created and a data source has been set up. + * + * This routine is essentially a state machine that handles a couple + * of critical state-transition actions, namely initial setup and + * transition from header scanning to ready-for-start_decompress. + * All the actual input is done via the input controller's consume_input + * method. + */ + +GLOBAL(int) +jpeg_consume_input (j_decompress_ptr cinfo) +{ + int retcode = JPEG_SUSPENDED; + + /* NB: every possible DSTATE value should be listed in this switch */ + switch (cinfo->global_state) { + case DSTATE_START: + /* Start-of-datastream actions: reset appropriate modules */ + (*cinfo->inputctl->reset_input_controller) (cinfo); + /* Initialize application's data source module */ + (*cinfo->src->init_source) (cinfo); + cinfo->global_state = DSTATE_INHEADER; + /*FALLTHROUGH*/ + case DSTATE_INHEADER: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ + /* Set up default parameters based on header data */ + default_decompress_parms(cinfo); + /* Set global state: ready for start_decompress */ + cinfo->global_state = DSTATE_READY; + } + break; + case DSTATE_READY: + /* Can't advance past first SOS until start_decompress is called */ + retcode = JPEG_REACHED_SOS; + break; + case DSTATE_PRELOAD: + case DSTATE_PRESCAN: + case DSTATE_SCANNING: + case DSTATE_RAW_OK: + case DSTATE_BUFIMAGE: + case DSTATE_BUFPOST: + case DSTATE_STOPPING: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + break; + default: + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + return retcode; +} + + +/* + * Have we finished reading the input file? + */ + +GLOBAL(boolean) +jpeg_input_complete (j_decompress_ptr cinfo) +{ + /* Check for valid jpeg object */ + if (cinfo->global_state < DSTATE_START || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->eoi_reached; +} + + +/* + * Is there more than one scan? + */ + +GLOBAL(boolean) +jpeg_has_multiple_scans (j_decompress_ptr cinfo) +{ + /* Only valid after jpeg_read_header completes */ + if (cinfo->global_state < DSTATE_READY || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->has_multiple_scans; +} + + +/* + * Finish JPEG decompression. + * + * This will normally just verify the file trailer and release temp storage. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_decompress (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { + /* Terminate final pass of non-buffered mode */ + if (cinfo->output_scanline < cinfo->output_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state == DSTATE_BUFIMAGE) { + /* Finishing after a buffered-image operation */ + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state != DSTATE_STOPPING) { + /* STOPPING = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read until EOI */ + while (! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + /* Do final cleanup */ + (*cinfo->src->term_source) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); + return TRUE; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdapistd.c b/widget/milsko/milskosrc/external/libjpeg/src/jdapistd.c new file mode 100644 index 0000000000..7f3a78b25a --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdapistd.c @@ -0,0 +1,276 @@ +/* + * jdapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2002-2013 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-decompression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_decompress, it will end up linking in the entire decompressor. + * We thus must separate this file from jdapimin.c to avoid linking the + * whole decompression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); + + +/* + * Decompression initialization. + * jpeg_read_header must be completed before calling this. + * + * If a multipass operating mode was selected, this will do all but the + * last pass, and thus may take a great deal of time. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_start_decompress (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize master control, select active modules */ + jinit_master_decompress(cinfo); + if (cinfo->buffered_image) { + /* No more work here; expecting jpeg_start_output next */ + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; + } + cinfo->global_state = DSTATE_PRELOAD; + } + if (cinfo->global_state == DSTATE_PRELOAD) { + /* If file has multiple scans, absorb them all into the coef buffer */ + if (cinfo->inputctl->has_multiple_scans) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* jdmaster underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + } + cinfo->output_scan_number = cinfo->input_scan_number; + } else if (cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any dummy output passes, and set up for the final pass */ + return output_pass_setup(cinfo); +} + + +/* + * Set up for an output pass, and perform any dummy pass(es) needed. + * Common subroutine for jpeg_start_decompress and jpeg_start_output. + * Entry: global_state = DSTATE_PRESCAN only if previously suspended. + * Exit: If done, returns TRUE and sets global_state for proper output mode. + * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. + */ + +LOCAL(boolean) +output_pass_setup (j_decompress_ptr cinfo) +{ + if (cinfo->global_state != DSTATE_PRESCAN) { + /* First call: do pass setup */ + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; + cinfo->global_state = DSTATE_PRESCAN; + } + /* Loop over any required dummy passes */ + while (cinfo->master->is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Crank through the dummy pass */ + while (cinfo->output_scanline < cinfo->output_height) { + JDIMENSION last_scanline; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* Process some data */ + last_scanline = cinfo->output_scanline; + (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, + &cinfo->output_scanline, (JDIMENSION) 0); + if (cinfo->output_scanline == last_scanline) + return FALSE; /* No progress made, must suspend */ + } + /* Finish up dummy pass, and set up for another one */ + (*cinfo->master->finish_output_pass) (cinfo); + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } + /* Ready for application to drive output pass through + * jpeg_read_scanlines or jpeg_read_raw_data. + */ + cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; + return TRUE; +} + + +/* + * Read some scanlines of data from the JPEG decompressor. + * + * The return value will be the number of lines actually read. + * This may be less than the number requested in several cases, + * including bottom of image, data source suspension, and operating + * modes that emit multiple scanlines at a time. + * + * Note: we warn about excess calls to jpeg_read_scanlines() since + * this likely signals an application programmer error. However, + * an oversize buffer (max_lines > scanlines remaining) is not an error. + */ + +GLOBAL(JDIMENSION) +jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION max_lines) +{ + JDIMENSION row_ctr; + + if (cinfo->global_state != DSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Process some data */ + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); + cinfo->output_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to read raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION max_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != DSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Verify that at least one iMCU row can be returned. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size; + if (max_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Decompress directly into user's buffer. */ + if (! (*cinfo->coef->decompress_data) (cinfo, data)) + return 0; /* suspension forced, can do nothing more */ + + /* OK, we processed one iMCU row. */ + cinfo->output_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} + + +/* Additional entry points for buffered-image mode. */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Initialize for an output pass in buffered-image mode. + */ + +GLOBAL(boolean) +jpeg_start_output (j_decompress_ptr cinfo, int scan_number) +{ + if (cinfo->global_state != DSTATE_BUFIMAGE && + cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Limit scan number to valid range */ + if (scan_number <= 0) + scan_number = 1; + if (cinfo->inputctl->eoi_reached && + scan_number > cinfo->input_scan_number) + scan_number = cinfo->input_scan_number; + cinfo->output_scan_number = scan_number; + /* Perform any dummy output passes, and set up for the real pass */ + return output_pass_setup(cinfo); +} + + +/* + * Finish up after an output pass in buffered-image mode. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_output (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { + /* Terminate this pass. */ + /* We do not require the whole pass to have been completed. */ + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_BUFPOST; + } else if (cinfo->global_state != DSTATE_BUFPOST) { + /* BUFPOST = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read markers looking for SOS or EOI */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdarith.c b/widget/milsko/milskosrc/external/libjpeg/src/jdarith.c new file mode 100644 index 0000000000..2c9abe23f2 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdarith.c @@ -0,0 +1,796 @@ +/* + * jdarith.c + * + * Developed 1997-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains portable arithmetic entropy decoding routines for JPEG + * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81). + * + * Both sequential and progressive modes are supported in this single module. + * + * Suspension is not currently supported in this module. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Expanded entropy decoder object for arithmetic decoding. */ + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + INT32 c; /* C register, base of coding interval + input bit buffer */ + INT32 a; /* A register, normalized size of coding interval */ + int ct; /* bit shift counter, # of bits left in bit buffer part of C */ + /* init: ct = -16 */ + /* run: ct = 0..7 */ + /* error: ct = -1 */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to statistics areas (these workspaces have image lifespan) */ + unsigned char * dc_stats[NUM_ARITH_TBLS]; + unsigned char * ac_stats[NUM_ARITH_TBLS]; + + /* Statistics bin for coding with fixed probability 0.5 */ + unsigned char fixed_bin[4]; +} arith_entropy_decoder; + +typedef arith_entropy_decoder * arith_entropy_ptr; + +/* The following two definitions specify the allocation chunk size + * for the statistics area. + * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least + * 49 statistics bins for DC, and 245 statistics bins for AC coding. + * + * We use a compact representation with 1 byte per statistics bin, + * thus the numbers directly represent byte sizes. + * This 1 byte per statistics bin contains the meaning of the MPS + * (more probable symbol) in the highest bit (mask 0x80), and the + * index into the probability estimation state machine table + * in the lower bits (mask 0x7F). + */ + +#define DC_STAT_BINS 64 +#define AC_STAT_BINS 256 + + +LOCAL(int) +get_byte (j_decompress_ptr cinfo) +/* Read next input byte; we do not support suspension in this module. */ +{ + struct jpeg_source_mgr * src = cinfo->src; + + if (src->bytes_in_buffer == 0) + if (! (*src->fill_input_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + src->bytes_in_buffer--; + return GETJOCTET(*src->next_input_byte++); +} + + +/* + * The core arithmetic decoding routine (common in JPEG and JBIG). + * This needs to go as fast as possible. + * Machine-dependent optimization facilities + * are not utilized in this portable implementation. + * However, this code should be fairly efficient and + * may be a good base for further optimizations anyway. + * + * Return value is 0 or 1 (binary decision). + * + * Note: I've changed the handling of the code base & bit + * buffer register C compared to other implementations + * based on the standards layout & procedures. + * While it also contains both the actual base of the + * coding interval (16 bits) and the next-bits buffer, + * the cut-point between these two parts is floating + * (instead of fixed) with the bit shift counter CT. + * Thus, we also need only one (variable instead of + * fixed size) shift for the LPS/MPS decision, and + * we can do away with any renormalization update + * of C (except for new data insertion, of course). + * + * I've also introduced a new scheme for accessing + * the probability estimation state machine table, + * derived from Markus Kuhn's JBIG implementation. + */ + +LOCAL(int) +arith_decode (j_decompress_ptr cinfo, unsigned char *st) +{ + register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy; + register unsigned char nl, nm; + register INT32 qe, temp; + register int sv, data; + + /* Renormalization & data input per section D.2.6 */ + while (e->a < 0x8000L) { + if (--e->ct < 0) { + /* Need to fetch next data byte */ + if (cinfo->unread_marker) + data = 0; /* stuff zero data */ + else { + data = get_byte(cinfo); /* read next input byte */ + if (data == 0xFF) { /* zero stuff or marker code */ + do data = get_byte(cinfo); + while (data == 0xFF); /* swallow extra 0xFF bytes */ + if (data == 0) + data = 0xFF; /* discard stuffed zero byte */ + else { + /* Note: Different from the Huffman decoder, hitting + * a marker while processing the compressed data + * segment is legal in arithmetic coding. + * The convention is to supply zero data + * then until decoding is complete. + */ + cinfo->unread_marker = data; + data = 0; + } + } + } + e->c = (e->c << 8) | data; /* insert data into C register */ + if ((e->ct += 8) < 0) /* update bit shift counter */ + /* Need more initial bytes */ + if (++e->ct == 0) + /* Got 2 initial bytes -> re-init A and exit loop */ + e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */ + } + e->a <<= 1; + } + + /* Fetch values from our compact representation of Table D.3(D.2): + * Qe values and probability estimation state machine + */ + sv = *st; + qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */ + nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */ + nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */ + + /* Decode & estimation procedures per sections D.2.4 & D.2.5 */ + temp = e->a - qe; + e->a = temp; + temp <<= e->ct; + if (e->c >= temp) { + e->c -= temp; + /* Conditional LPS (less probable symbol) exchange */ + if (e->a < qe) { + e->a = qe; + *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ + } else { + e->a = qe; + *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ + sv ^= 0x80; /* Exchange LPS/MPS */ + } + } else if (e->a < 0x8000L) { + /* Conditional MPS (more probable symbol) exchange */ + if (e->a < qe) { + *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ + sv ^= 0x80; /* Exchange LPS/MPS */ + } else { + *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ + } + } + + return sv >> 7; +} + + +/* + * Check for a restart marker & resynchronize decoder. + */ + +LOCAL(void) +process_restart (j_decompress_ptr cinfo) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + int ci; + jpeg_component_info * compptr; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Re-initialize statistics areas */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) { + MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS); + /* Reset DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + entropy->dc_context[ci] = 0; + } + if ((! cinfo->progressive_mode && cinfo->lim_Se) || + (cinfo->progressive_mode && cinfo->Ss)) { + MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS); + } + } + + /* Reset arithmetic decoding variables */ + entropy->c = 0; + entropy->a = 0; + entropy->ct = -16; /* force reading 2 initial bytes to fill C */ + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Arithmetic MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * arithmetic-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + unsigned char *st; + int blkn, ci, tbl, sign; + int v, m; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + if (entropy->ct == -1) return TRUE; /* if error do nothing */ + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + tbl = cinfo->cur_comp_info[ci]->dc_tbl_no; + + /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */ + + /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ + st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; + + /* Figure F.19: Decode_DC_DIFF */ + if (arith_decode(cinfo, st) == 0) + entropy->dc_context[ci] = 0; + else { + /* Figure F.21: Decoding nonzero value v */ + /* Figure F.22: Decoding the sign of v */ + sign = arith_decode(cinfo, st + 1); + st += 2; st += sign; + /* Figure F.23: Decoding the magnitude category of v */ + if ((m = arith_decode(cinfo, st)) != 0) { + st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ + while (arith_decode(cinfo, st)) { + if ((m <<= 1) == (int) 0x8000U) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* magnitude overflow */ + return TRUE; + } + st += 1; + } + } + /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ + if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) + entropy->dc_context[ci] = 0; /* zero diff category */ + else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) + entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */ + else + entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */ + v = m; + /* Figure F.24: Decoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + if (arith_decode(cinfo, st)) v |= m; + v += 1; if (sign) v = -v; + entropy->last_dc_val[ci] += v; + } + + /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al); + } + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + unsigned char *st; + int tbl, sign, k; + int v, m; + const int * natural_order; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + if (entropy->ct == -1) return TRUE; /* if error do nothing */ + + natural_order = cinfo->natural_order; + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = cinfo->cur_comp_info[0]->ac_tbl_no; + + /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ + + /* Figure F.20: Decode_AC_coefficients */ + k = cinfo->Ss - 1; + do { + st = entropy->ac_stats[tbl] + 3 * k; + if (arith_decode(cinfo, st)) break; /* EOB flag */ + for (;;) { + k++; + if (arith_decode(cinfo, st + 1)) break; + st += 3; + if (k >= cinfo->Se) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* spectral overflow */ + return TRUE; + } + } + /* Figure F.21: Decoding nonzero value v */ + /* Figure F.22: Decoding the sign of v */ + sign = arith_decode(cinfo, entropy->fixed_bin); + st += 2; + /* Figure F.23: Decoding the magnitude category of v */ + if ((m = arith_decode(cinfo, st)) != 0) { + if (arith_decode(cinfo, st)) { + m <<= 1; + st = entropy->ac_stats[tbl] + + (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); + while (arith_decode(cinfo, st)) { + if ((m <<= 1) == (int) 0x8000U) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* magnitude overflow */ + return TRUE; + } + st += 1; + } + } + } + v = m; + /* Figure F.24: Decoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + if (arith_decode(cinfo, st)) v |= m; + v += 1; if (sign) v = -v; + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[natural_order[k]] = (JCOEF) (v << cinfo->Al); + } while (k < cinfo->Se); + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, + * although the spec is not very clear on the point. + */ + +METHODDEF(boolean) +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + unsigned char *st; + JCOEF p1; + int blkn; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + st = entropy->fixed_bin; /* use fixed probability estimation */ + p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + /* Encoded data is simply the next bit of the two's-complement DC value */ + if (arith_decode(cinfo, st)) + MCU_data[blkn][0][0] |= p1; + } + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + JCOEFPTR thiscoef; + unsigned char *st; + int tbl, k, kex; + JCOEF p1, m1; + const int * natural_order; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + if (entropy->ct == -1) return TRUE; /* if error do nothing */ + + natural_order = cinfo->natural_order; + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = cinfo->cur_comp_info[0]->ac_tbl_no; + + p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + m1 = -p1; /* -1 in the bit position being coded */ + + /* Establish EOBx (previous stage end-of-block) index */ + kex = cinfo->Se; + do { + if ((*block)[natural_order[kex]]) break; + } while (--kex); + + k = cinfo->Ss - 1; + do { + st = entropy->ac_stats[tbl] + 3 * k; + if (k >= kex) + if (arith_decode(cinfo, st)) break; /* EOB flag */ + for (;;) { + thiscoef = *block + natural_order[++k]; + if (*thiscoef) { /* previously nonzero coef */ + if (arith_decode(cinfo, st + 2)) { + if (*thiscoef < 0) + *thiscoef += m1; + else + *thiscoef += p1; + } + break; + } + if (arith_decode(cinfo, st + 1)) { /* newly nonzero coef */ + if (arith_decode(cinfo, entropy->fixed_bin)) + *thiscoef = m1; + else + *thiscoef = p1; + break; + } + st += 3; + if (k >= cinfo->Se) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* spectral overflow */ + return TRUE; + } + } + } while (k < cinfo->Se); + + return TRUE; +} + + +/* + * Decode one MCU's worth of arithmetic-compressed coefficients. + */ + +METHODDEF(boolean) +decode_mcu (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + jpeg_component_info * compptr; + JBLOCKROW block; + unsigned char *st; + int blkn, ci, tbl, sign, k; + int v, m; + const int * natural_order; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + if (entropy->ct == -1) return TRUE; /* if error do nothing */ + + natural_order = cinfo->natural_order; + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */ + + tbl = compptr->dc_tbl_no; + + /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ + st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; + + /* Figure F.19: Decode_DC_DIFF */ + if (arith_decode(cinfo, st) == 0) + entropy->dc_context[ci] = 0; + else { + /* Figure F.21: Decoding nonzero value v */ + /* Figure F.22: Decoding the sign of v */ + sign = arith_decode(cinfo, st + 1); + st += 2; st += sign; + /* Figure F.23: Decoding the magnitude category of v */ + if ((m = arith_decode(cinfo, st)) != 0) { + st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ + while (arith_decode(cinfo, st)) { + if ((m <<= 1) == (int) 0x8000U) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* magnitude overflow */ + return TRUE; + } + st += 1; + } + } + /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ + if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) + entropy->dc_context[ci] = 0; /* zero diff category */ + else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) + entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */ + else + entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */ + v = m; + /* Figure F.24: Decoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + if (arith_decode(cinfo, st)) v |= m; + v += 1; if (sign) v = -v; + entropy->last_dc_val[ci] += v; + } + + (*block)[0] = (JCOEF) entropy->last_dc_val[ci]; + + /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ + + if (cinfo->lim_Se == 0) continue; + tbl = compptr->ac_tbl_no; + k = 0; + + /* Figure F.20: Decode_AC_coefficients */ + do { + st = entropy->ac_stats[tbl] + 3 * k; + if (arith_decode(cinfo, st)) break; /* EOB flag */ + for (;;) { + k++; + if (arith_decode(cinfo, st + 1)) break; + st += 3; + if (k >= cinfo->lim_Se) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* spectral overflow */ + return TRUE; + } + } + /* Figure F.21: Decoding nonzero value v */ + /* Figure F.22: Decoding the sign of v */ + sign = arith_decode(cinfo, entropy->fixed_bin); + st += 2; + /* Figure F.23: Decoding the magnitude category of v */ + if ((m = arith_decode(cinfo, st)) != 0) { + if (arith_decode(cinfo, st)) { + m <<= 1; + st = entropy->ac_stats[tbl] + + (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); + while (arith_decode(cinfo, st)) { + if ((m <<= 1) == (int) 0x8000U) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* magnitude overflow */ + return TRUE; + } + st += 1; + } + } + } + v = m; + /* Figure F.24: Decoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + if (arith_decode(cinfo, st)) v |= m; + v += 1; if (sign) v = -v; + (*block)[natural_order[k]] = (JCOEF) v; + } while (k < cinfo->lim_Se); + } + + return TRUE; +} + + +/* + * Initialize for an arithmetic-compressed scan. + */ + +METHODDEF(void) +start_pass (j_decompress_ptr cinfo) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + int ci, tbl; + jpeg_component_info * compptr; + + if (cinfo->progressive_mode) { + /* Validate progressive scan parameters */ + if (cinfo->Ss == 0) { + if (cinfo->Se != 0) + goto bad; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se) + goto bad; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + goto bad; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Ah-1 != cinfo->Al) + goto bad; + } + if (cinfo->Al > 13) { /* need not check for < 0 */ + bad: + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + } + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int coefi, cindex = cinfo->cur_comp_info[ci]->component_index; + int *coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (cinfo->Ss == 0) + entropy->pub.decode_mcu = decode_mcu_DC_first; + else + entropy->pub.decode_mcu = decode_mcu_AC_first; + } else { + if (cinfo->Ss == 0) + entropy->pub.decode_mcu = decode_mcu_DC_refine; + else + entropy->pub.decode_mcu = decode_mcu_AC_refine; + } + } else { + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning. + */ + if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 || + (cinfo->Se < DCTSIZE2 && cinfo->Se != cinfo->lim_Se)) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + /* Select MCU decoding routine */ + entropy->pub.decode_mcu = decode_mcu; + } + + /* Allocate & initialize requested statistics areas */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) { + tbl = compptr->dc_tbl_no; + if (tbl < 0 || tbl >= NUM_ARITH_TBLS) + ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); + if (entropy->dc_stats[tbl] == NULL) + entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS); + MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS); + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + entropy->dc_context[ci] = 0; + } + if ((! cinfo->progressive_mode && cinfo->lim_Se) || + (cinfo->progressive_mode && cinfo->Ss)) { + tbl = compptr->ac_tbl_no; + if (tbl < 0 || tbl >= NUM_ARITH_TBLS) + ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); + if (entropy->ac_stats[tbl] == NULL) + entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS); + MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS); + } + } + + /* Initialize arithmetic decoding variables */ + entropy->c = 0; + entropy->a = 0; + entropy->ct = -16; /* force reading 2 initial bytes to fill C */ + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Finish up at the end of an arithmetic-compressed scan. + */ + +METHODDEF(void) +finish_pass (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Module initialization routine for arithmetic entropy decoding. + */ + +GLOBAL(void) +jinit_arith_decoder (j_decompress_ptr cinfo) +{ + arith_entropy_ptr entropy; + int i; + + entropy = (arith_entropy_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(arith_entropy_decoder)); + cinfo->entropy = &entropy->pub; + entropy->pub.start_pass = start_pass; + entropy->pub.finish_pass = finish_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + entropy->dc_stats[i] = NULL; + entropy->ac_stats[i] = NULL; + } + + /* Initialize index for fixed probability estimation */ + entropy->fixed_bin[0] = 113; + + if (cinfo->progressive_mode) { + /* Create progression status table */ + int *coef_bit_ptr, ci; + cinfo->coef_bits = (int (*)[DCTSIZE2]) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * DCTSIZE2 * SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdatadst.c b/widget/milsko/milskosrc/external/libjpeg/src/jdatadst.c new file mode 100644 index 0000000000..b3b4798ea4 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdatadst.c @@ -0,0 +1,263 @@ +/* + * jdatadst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2009-2022 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to memory or to a file (or any stdio stream). + * While these routines are sufficient for most applications, + * some will want to use a different destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + + +/* Expanded data destination object for stdio output */ + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + FILE * outfile; /* target stream */ + JOCTET buffer[OUTPUT_BUF_SIZE]; /* output buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + + +/* Expanded data destination object for memory output */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + unsigned char ** outbuffer; /* target buffer */ + size_t * outsize; + unsigned char * newbuffer; /* newly allocated buffer */ + JOCTET * buffer; /* start of buffer */ + size_t bufsize; +} my_mem_destination_mgr; + +typedef my_mem_destination_mgr * my_mem_dest_ptr; + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +METHODDEF(void) +init_mem_destination (j_compress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + (size_t) OUTPUT_BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + +METHODDEF(boolean) +empty_mem_output_buffer (j_compress_ptr cinfo) +{ + size_t nextsize; + JOCTET * nextbuffer; + my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest; + + /* Try to allocate new buffer with double size */ + nextsize = dest->bufsize * 2; + nextbuffer = (JOCTET *) malloc(nextsize); + + if (nextbuffer == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 11); + + MEMCOPY(nextbuffer, dest->buffer, dest->bufsize); + + if (dest->newbuffer != NULL) + free(dest->newbuffer); + + dest->newbuffer = nextbuffer; + + dest->pub.next_output_byte = nextbuffer + dest->bufsize; + dest->pub.free_in_buffer = dest->bufsize; + + dest->buffer = nextbuffer; + dest->bufsize = nextsize; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + JFFLUSH(dest->outfile); + /* Make sure we wrote the output file OK */ + if (JFERROR(dest->outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + +METHODDEF(void) +term_mem_destination (j_compress_ptr cinfo) +{ + my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest; + + *dest->outbuffer = dest->buffer; + *dest->outsize = dest->bufsize - dest->pub.free_in_buffer; +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, + * and is responsible for closing it after finishing compression. + */ + +GLOBAL(void) +jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} + + +/* + * Prepare for output to a memory buffer. + * The caller may supply an own initial buffer with appropriate size. + * Otherwise, or when the actual data output exceeds the given size, + * the library adapts the buffer size as necessary. + * The standard library functions malloc/free are used for allocating + * larger memory, so the buffer is available to the application after + * finishing compression, and then the application is responsible for + * freeing the requested memory. + * Note: An initial buffer supplied by the caller is expected to be + * managed by the application. The library does not free such buffer + * when allocating a larger buffer. + */ + +GLOBAL(void) +jpeg_mem_dest (j_compress_ptr cinfo, + unsigned char ** outbuffer, size_t * outsize) +{ + my_mem_dest_ptr dest; + + if (outbuffer == NULL || outsize == NULL) /* sanity check */ + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same buffer without re-executing jpeg_mem_dest. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_mem_destination_mgr)); + } + + dest = (my_mem_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_mem_destination; + dest->pub.empty_output_buffer = empty_mem_output_buffer; + dest->pub.term_destination = term_mem_destination; + dest->outbuffer = outbuffer; + dest->outsize = outsize; + dest->newbuffer = NULL; + + if (*outbuffer == NULL || *outsize == 0) { + /* Allocate initial buffer */ + dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE); + if (dest->newbuffer == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); + *outsize = OUTPUT_BUF_SIZE; + } + + dest->pub.next_output_byte = dest->buffer = *outbuffer; + dest->pub.free_in_buffer = dest->bufsize = *outsize; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdatasrc.c b/widget/milsko/milskosrc/external/libjpeg/src/jdatasrc.c new file mode 100644 index 0000000000..fd7a1a594b --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdatasrc.c @@ -0,0 +1,271 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2009-2022 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from memory or from a file (or any stdio stream). + * While these routines are sufficient for most applications, + * some will want to use a different source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data source object for stdio input */ + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE * infile; /* source stream */ + JOCTET buffer[INPUT_BUF_SIZE]; /* input buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + +METHODDEF(void) +init_mem_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + +METHODDEF(boolean) +fill_mem_input_buffer (j_decompress_ptr cinfo) +{ + static const JOCTET mybuffer[4] = { + (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0 + }; + + /* The whole JPEG data is expected to reside in the supplied memory + * buffer, so any request for more data beyond the given buffer size + * is treated as an error. + */ + WARNMS(cinfo, JWRN_JPEG_EOF); + + /* Insert a fake EOI marker */ + + cinfo->src->next_input_byte = mybuffer; + cinfo->src->bytes_in_buffer = 2; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + struct jpeg_source_mgr * src = cinfo->src; + size_t nbytes; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + nbytes = (size_t) num_bytes; + while (nbytes > src->bytes_in_buffer) { + nbytes -= src->bytes_in_buffer; + (void) (*src->fill_input_buffer) (cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->next_input_byte += nbytes; + src->bytes_in_buffer -= nbytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, + * and is responsible for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) +{ + my_src_ptr src; + + /* The source object including the input buffer is made permanent so that + * a series of JPEG images can be read from the same file by calling + * jpeg_stdio_src only before the first one. (If we discarded the buffer + * at the end of one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_source_mgr)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + + +/* + * Prepare for input from a supplied memory buffer. + * The buffer must contain the whole JPEG data. + */ + +GLOBAL(void) +jpeg_mem_src (j_decompress_ptr cinfo, + const unsigned char * inbuffer, size_t insize) +{ + struct jpeg_source_mgr * src; + + if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + + /* The source object is made permanent so that a series of JPEG images + * can be read from the same buffer by calling jpeg_mem_src only before + * the first one. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(struct jpeg_source_mgr)); + } + + src = cinfo->src; + src->init_source = init_mem_source; + src->fill_input_buffer = fill_mem_input_buffer; + src->skip_input_data = skip_input_data; + src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->term_source = term_source; + src->bytes_in_buffer = insize; + src->next_input_byte = (const JOCTET *) inbuffer; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdcoefct.c b/widget/milsko/milskosrc/external/libjpeg/src/jdcoefct.c new file mode 100644 index 0000000000..79ba420140 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdcoefct.c @@ -0,0 +1,744 @@ +/* + * jdcoefct.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 2002-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for decompression. + * This controller is the top level of the JPEG decompressor proper. + * The coefficient buffer lies between entropy decoding and inverse-DCT steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + * Also, the input side (only) is used when reading a file for transcoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Block smoothing is only applicable for progressive JPEG, so: */ +#ifndef D_PROGRESSIVE_SUPPORTED +#undef BLOCK_SMOOTHING_SUPPORTED +#endif + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_coef_controller pub; /* public fields */ + + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + /* In single-pass modes, it's sufficient to buffer just one MCU. + * We append a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, + * and let the entropy decoder write into that workspace each time. + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays; it is used only by the input side. + */ + JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* When doing block smoothing, we latch coefficient Al values here */ + int * coef_bits_latch; +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ +#endif + + /* Workspace for single-pass modes (omitted otherwise). */ + JBLOCK blk_buffer[D_MAX_BLOCKS_IN_MCU]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +/* Forward declarations */ +METHODDEF(int) decompress_onepass + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF(int) decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif +#ifdef BLOCK_SMOOTHING_SUPPORTED +LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo)); +METHODDEF(int) decompress_smooth_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ +#ifdef BLOCK_SMOOTHING_SUPPORTED + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* If multipass, check to see whether to use block smoothing on this pass */ + if (coef->pub.coef_arrays != NULL) { + if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) + coef->pub.decompress_data = decompress_smooth_data; + else + coef->pub.decompress_data = decompress_data; + } +#endif + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the single-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(int) +decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int ci, xindex, yindex, yoffset, useful_width; + JBLOCKROW blkp; + JSAMPARRAY output_ptr; + JDIMENSION start_col, output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + blkp = coef->blk_buffer; /* pointer to current DCT block within MCU */ + /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ + if (cinfo->lim_Se) /* can bypass in DC only case */ + MEMZERO(blkp, cinfo->blocks_in_MCU * SIZEOF(JBLOCK)); + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + /* Determine where data should go in output_buf and do the IDCT thing. + * We skip dummy blocks at the right and bottom edges (but blkp gets + * incremented past them!). + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) { + blkp += compptr->MCU_blocks; + continue; + } + inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index]; + output_ptr = output_buf[compptr->component_index] + + yoffset * compptr->DCT_v_scaled_size; + useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + start_col = MCU_col_num * compptr->MCU_sample_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (cinfo->input_iMCU_row < last_iMCU_row || + yoffset + yindex < compptr->last_row_height) { + output_col = start_col; + for (xindex = 0; xindex < useful_width; xindex++) { + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) (blkp + xindex), + output_ptr, output_col); + output_col += compptr->DCT_h_scaled_size; + } + output_ptr += compptr->DCT_v_scaled_size; + } + blkp += compptr->MCU_width; + } + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + cinfo->output_iMCU_row++; + if (++(cinfo->input_iMCU_row) <= last_iMCU_row) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF(int) +dummy_consume_data (j_decompress_ptr cinfo) +{ + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image coefficient buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor block rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF(int) +consume_data (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY blkp; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Note: entropy decoder expects buffer to be zeroed, + * but this is handled automatically by the memory manager + * because we requested a pre-zeroed array. + */ + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkp = coef->MCU_buffer; /* pointer to current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yoffset + yindex] + start_col; + xindex = compptr->MCU_width; + do { + *blkp++ = buffer_ptr++; + } while (--xindex); + } + } + /* Try to fetch the MCU. */ + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Decompress and return some data in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF(int) +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num; + int ci, block_row, block_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + output_col = 0; + for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, + output_ptr, output_col); + buffer_ptr++; + output_col += compptr->DCT_h_scaled_size; + } + output_ptr += compptr->DCT_v_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) <= last_iMCU_row) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + +/* + * This code applies interblock smoothing as described by section K.8 + * of the JPEG standard: the first 5 AC coefficients are estimated from + * the DC values of a DCT block and its 8 neighboring blocks. + * We apply smoothing only for progressive JPEG decoding, and only if + * the coefficients it can estimate are not yet known to full precision. + */ + +/* Natural-order array positions of the first 5 zigzag-order coefficients */ +#define Q01_POS 1 +#define Q10_POS 8 +#define Q20_POS 16 +#define Q11_POS 9 +#define Q02_POS 2 + +/* + * Determine whether block smoothing is applicable and safe. + * We also latch the current states of the coef_bits[] entries for the + * AC coefficients; otherwise, if the input side of the decompressor + * advances into a new scan, we might think the coefficients are known + * more accurately than they really are. + */ + +LOCAL(boolean) +smoothing_ok (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + boolean smoothing_useful = FALSE; + int ci, coefi; + jpeg_component_info *compptr; + JQUANT_TBL * qtable; + int * coef_bits; + int * coef_bits_latch; + + if (! cinfo->progressive_mode || cinfo->coef_bits == NULL) + return FALSE; + + /* Allocate latch area if not already done */ + if (coef->coef_bits_latch == NULL) + coef->coef_bits_latch = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * (SAVED_COEFS * SIZEOF(int))); + coef_bits_latch = coef->coef_bits_latch; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* All components' quantization values must already be latched. */ + if ((qtable = compptr->quant_table) == NULL) + return FALSE; + /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ + if (qtable->quantval[0] == 0 || + qtable->quantval[Q01_POS] == 0 || + qtable->quantval[Q10_POS] == 0 || + qtable->quantval[Q20_POS] == 0 || + qtable->quantval[Q11_POS] == 0 || + qtable->quantval[Q02_POS] == 0) + return FALSE; + /* DC values must be at least partly known for all components. */ + coef_bits = cinfo->coef_bits[ci]; + if (coef_bits[0] < 0) + return FALSE; + /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ + for (coefi = 1; coefi <= 5; coefi++) { + coef_bits_latch[coefi] = coef_bits[coefi]; + if (coef_bits[coefi] != 0) + smoothing_useful = TRUE; + } + coef_bits_latch += SAVED_COEFS; + } + + return smoothing_useful; +} + + +/* + * Variant of decompress_data for use when doing block smoothing. + */ + +METHODDEF(int) +decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num, last_block_column; + int ci, block_row, block_rows, access_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr, prev_block_row, next_block_row; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + boolean first_row, last_row; + JBLOCK workspace; + int *coef_bits; + JQUANT_TBL *quanttbl; + INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; + int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; + int Al, pred; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if (cinfo->input_scan_number == cinfo->output_scan_number) { + /* If input is working on current scan, we ordinarily want it to + * have completed the current row. But if input scan is DC, + * we want it to keep one row ahead so that next block row's DC + * values are up to date. + */ + JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; + if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) + break; + } + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) { + block_rows = compptr->v_samp_factor; + access_rows = block_rows * 2; /* this and next iMCU row */ + last_row = FALSE; + } else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + access_rows = block_rows; /* this iMCU row only */ + last_row = TRUE; + } + /* Align the virtual buffer for this component. */ + if (cinfo->output_iMCU_row > 0) { + access_rows += compptr->v_samp_factor; /* prior iMCU row too */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, + (JDIMENSION) access_rows, FALSE); + buffer += compptr->v_samp_factor; /* point to current iMCU row */ + first_row = FALSE; + } else { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); + first_row = TRUE; + } + /* Fetch component-dependent info */ + coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); + quanttbl = compptr->quant_table; + Q00 = quanttbl->quantval[0]; + Q01 = quanttbl->quantval[Q01_POS]; + Q10 = quanttbl->quantval[Q10_POS]; + Q20 = quanttbl->quantval[Q20_POS]; + Q11 = quanttbl->quantval[Q11_POS]; + Q02 = quanttbl->quantval[Q02_POS]; + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + if (first_row && block_row == 0) + prev_block_row = buffer_ptr; + else + prev_block_row = buffer[block_row-1]; + if (last_row && block_row == block_rows-1) + next_block_row = buffer_ptr; + else + next_block_row = buffer[block_row+1]; + /* We fetch the surrounding DC values using a sliding-register approach. + * Initialize all nine here so as to do the right thing on narrow pics. + */ + DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; + DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; + DC7 = DC8 = DC9 = (int) next_block_row[0][0]; + output_col = 0; + last_block_column = compptr->width_in_blocks - 1; + for (block_num = 0; block_num <= last_block_column; block_num++) { + /* Fetch current DCT block into workspace so we can modify it. */ + jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); + /* Update DC values */ + if (block_num < last_block_column) { + DC3 = (int) prev_block_row[1][0]; + DC6 = (int) buffer_ptr[1][0]; + DC9 = (int) next_block_row[1][0]; + } + /* Compute coefficient estimates per K.8. + * An estimate is applied only if coefficient is still zero, + * and is not known to be fully accurate. + */ + /* AC01 */ + if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { + num = 36 * Q00 * (DC4 - DC6); + if (num >= 0) { + pred = (int) (((Q01<<7) + num) / (Q01<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q10<<7) + num) / (Q10<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q20<<7) + num) / (Q20<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q11<<7) + num) / (Q11<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q02<<7) + num) / (Q02<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_h_scaled_size; + } + output_ptr += compptr->DCT_v_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) <= last_iMCU_row) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + /* Note we ask for a pre-zeroed array. */ + int ci, access_rows; + jpeg_component_info *compptr; + + coef = (my_coef_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller) - SIZEOF(coef->blk_buffer)); + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* If block smoothing could be used, need a bigger window */ + if (cinfo->progressive_mode) + access_rows *= 3; +#endif + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + coef->pub.consume_data = consume_data; + coef->pub.decompress_data = decompress_data; + coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKARRAY blkp; + JBLOCKROW buffer_ptr; + int bi; + + coef = (my_coef_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_coef_controller)); + buffer_ptr = coef->blk_buffer; + if (cinfo->lim_Se == 0) /* DC only case: want to bypass later */ + MEMZERO(buffer_ptr, SIZEOF(coef->blk_buffer)); + blkp = coef->MCU_buffer; + bi = D_MAX_BLOCKS_IN_MCU; + do { + *blkp++ = buffer_ptr++; + } while (--bi); + coef->pub.consume_data = dummy_consume_data; + coef->pub.decompress_data = decompress_onepass; + coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ + } + + coef->pub.start_input_pass = start_input_pass; + coef->pub.start_output_pass = start_output_pass; +#ifdef BLOCK_SMOOTHING_SUPPORTED + coef->coef_bits_latch = NULL; +#endif + cinfo->coef = &coef->pub; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdcolor.c b/widget/milsko/milskosrc/external/libjpeg/src/jdcolor.c new file mode 100644 index 0000000000..6b40fb5340 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdcolor.c @@ -0,0 +1,769 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2011-2023 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +#if RANGE_BITS < 2 + /* Deliberate syntax err */ + Sorry, this code requires 2 or more range extension bits. +#endif + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_deconverter pub; /* public fields */ + + /* Private state for YCbCr->RGB and BG_YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* Private state for RGB->Y conversion */ + INT32 * R_y_tab; /* => table for R to Y conversion */ + INT32 * G_y_tab; /* => table for G to Y conversion */ + INT32 * B_y_tab; /* => table for B to Y conversion */ +} my_color_deconverter; + +typedef my_color_deconverter * my_cconvert_ptr; + + +/*************** YCbCr -> RGB conversion: most common case **************/ +/*************** BG_YCC -> RGB conversion: less common case **************/ +/*************** RGB -> Y conversion: less common case **************/ + +/* + * YCbCr is defined per Recommendation ITU-R BT.601-7 (03/2011), + * previously known as Recommendation CCIR 601-1, except that Cb and Cr + * are normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * sRGB (standard RGB color space) is defined per IEC 61966-2-1:1999. + * sYCC (standard luma-chroma-chroma color space with extended gamut) + * is defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex F. + * bg-sRGB and bg-sYCC (big gamut standard color spaces) + * are defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex G. + * Note that the derived conversion coefficients given in some of these + * documents are imprecise. The general conversion equations are + * + * R = Y + K * (1 - Kr) * Cr + * G = Y - K * (Kb * (1 - Kb) * Cb + Kr * (1 - Kr) * Cr) / (1 - Kr - Kb) + * B = Y + K * (1 - Kb) * Cb + * + * Y = Kr * R + (1 - Kr - Kb) * G + Kb * B + * + * With Kr = 0.299 and Kb = 0.114 (derived according to SMPTE RP 177-1993 + * from the 1953 FCC NTSC primaries and CIE Illuminant C), K = 2 for sYCC, + * the conversion equations to be implemented are therefore + * + * R = Y + 1.402 * Cr + * G = Y - 0.344136286 * Cb - 0.714136286 * Cr + * B = Y + 1.772 * Cb + * + * Y = 0.299 * R + 0.587 * G + 0.114 * B + * + * where Cb and Cr represent the incoming values less CENTERJSAMPLE. + * For bg-sYCC, with K = 4, the equations are + * + * R = Y + 2.804 * Cr + * G = Y - 0.688272572 * Cb - 1.428272572 * Cr + * B = Y + 3.544 * Cb + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * Notice that Y, being an integral input, does not contribute any fraction + * so it need not participate in the rounding. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times Cb and Cr for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 9-bit to 12-bit samples it is still acceptable. It's not very + * reasonable for 16-bit samples, but if you want lossless storage + * you shouldn't be changing colorspace anyway. + * The Cr=>R and Cb=>B values can be rounded to integers in advance; + * the values for the G calculation are left scaled up, + * since we must add them together before rounding. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB and BG_YCC->RGB colorspace conversion. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +/* Normal case, sYCC */ +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + int i; + INT32 x; + SHIFT_TEMPS + + cconvert->Cr_r_tab = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cb_b_tab = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.402 * x */ + cconvert->Cr_r_tab[i] = (int) DESCALE(FIX(1.402) * x, SCALEBITS); + /* Cb=>B value is nearest int to 1.772 * x */ + cconvert->Cb_b_tab[i] = (int) DESCALE(FIX(1.772) * x, SCALEBITS); + /* Cr=>G value is scaled-up -0.714136286 * x */ + cconvert->Cr_g_tab[i] = (- FIX(0.714136286)) * x; + /* Cb=>G value is scaled-up -0.344136286 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + cconvert->Cb_g_tab[i] = (- FIX(0.344136286)) * x + ONE_HALF; + } +} + + +LOCAL(void) +build_bg_ycc_rgb_table (j_decompress_ptr cinfo) +/* Wide gamut case, bg-sYCC */ +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + int i; + INT32 x; + SHIFT_TEMPS + + cconvert->Cr_r_tab = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cb_b_tab = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 2.804 * x */ + cconvert->Cr_r_tab[i] = (int) DESCALE(FIX(2.804) * x, SCALEBITS); + /* Cb=>B value is nearest int to 3.544 * x */ + cconvert->Cb_b_tab[i] = (int) DESCALE(FIX(3.544) * x, SCALEBITS); + /* Cr=>G value is scaled-up -1.428272572 * x */ + cconvert->Cr_g_tab[i] = (- FIX(1.428272572)) * x; + /* Cb=>G value is scaled-up -0.688272572 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + cconvert->Cb_g_tab[i] = (- FIX(0.688272572)) * x + ONE_HALF; + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * + * Note that we change from noninterleaved, one-plane-per-component format + * to interleaved-pixel format. The output buffer is therefore three times + * as wide as the input buffer. + * + * A starting row offset is provided only for the input buffer. The caller + * can easily adjust the passed output_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +ycc_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses, + * for extended gamut (sYCC) and wide gamut (bg-sYCC) encodings. + */ + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/**************** Cases other than YCC -> RGB ****************/ + + +/* + * Initialize for RGB->grayscale colorspace conversion. + */ + +LOCAL(void) +build_rgb_y_table (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 i; + + cconvert->R_y_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->G_y_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->B_y_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0; i <= MAXJSAMPLE; i++) { + cconvert->R_y_tab[i] = FIX(0.299) * i; + cconvert->G_y_tab[i] = FIX(0.587) * i; + cconvert->B_y_tab[i] = FIX(0.114) * i + ONE_HALF; + } +} + + +/* + * Convert RGB to grayscale. + */ + +METHODDEF(void) +rgb_gray_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register INT32 y; + register INT32 * Rytab = cconvert->R_y_tab; + register INT32 * Gytab = cconvert->G_y_tab; + register INT32 * Bytab = cconvert->B_y_tab; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = Rytab[GETJSAMPLE(inptr0[col])]; + y += Gytab[GETJSAMPLE(inptr1[col])]; + y += Bytab[GETJSAMPLE(inptr2[col])]; + outptr[col] = (JSAMPLE) (y >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * [R-G,G,B-G] to [R,G,B] conversion with modulo calculation + * (inverse color transform). + * This can be seen as an adaption of the general YCbCr->RGB + * conversion equation with Kr = Kb = 0, while replacing the + * normalization by modulo calculation. + */ + +METHODDEF(void) +rgb1_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register int r, g, b; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr0[col]); + g = GETJSAMPLE(inptr1[col]); + b = GETJSAMPLE(inptr2[col]); + /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD + * (modulo) operator is equivalent to the bitmask operator AND. + */ + outptr[RGB_RED] = (JSAMPLE) ((r + g - CENTERJSAMPLE) & MAXJSAMPLE); + outptr[RGB_GREEN] = (JSAMPLE) g; + outptr[RGB_BLUE] = (JSAMPLE) ((b + g - CENTERJSAMPLE) & MAXJSAMPLE); + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * [R-G,G,B-G] to grayscale conversion with modulo calculation + * (inverse color transform). + */ + +METHODDEF(void) +rgb1_gray_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 y; + register INT32 * Rytab = cconvert->R_y_tab; + register INT32 * Gytab = cconvert->G_y_tab; + register INT32 * Bytab = cconvert->B_y_tab; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr0[col]); + g = GETJSAMPLE(inptr1[col]); + b = GETJSAMPLE(inptr2[col]); + /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD + * (modulo) operator is equivalent to the bitmask operator AND. + */ + y = Rytab[(r + g - CENTERJSAMPLE) & MAXJSAMPLE]; + y += Gytab[g]; + y += Bytab[(b + g - CENTERJSAMPLE) & MAXJSAMPLE]; + outptr[col] = (JSAMPLE) (y >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * No colorspace change, but conversion from separate-planes + * to interleaved representation. + */ + +METHODDEF(void) +rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr[RGB_RED] = inptr0[col]; + outptr[RGB_GREEN] = inptr1[col]; + outptr[RGB_BLUE] = inptr2[col]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Color conversion for no colorspace change: just copy the data, + * converting from separate-planes to interleaved representation. + * Note: Omit uninteresting components in output buffer. + */ + +METHODDEF(void) +null_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW outptr; + register JSAMPROW inptr; + register JDIMENSION count; + register int out_comps = cinfo->out_color_components; + JDIMENSION num_cols = cinfo->output_width; + JSAMPROW startptr; + int ci; + jpeg_component_info *compptr; + + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + startptr = *output_buf++; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (! compptr->component_needed) + continue; /* skip uninteresting component */ + inptr = input_buf[ci][input_row]; + outptr = startptr++; + for (count = num_cols; count > 0; count--) { + *outptr = *inptr++; /* don't need GETJSAMPLE() here */ + outptr += out_comps; + } + } + input_row++; + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCC -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF(void) +grayscale_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + jcopy_sample_rows(input_buf[0] + input_row, output_buf, + num_rows, cinfo->output_width); +} + + +/* + * Convert grayscale to RGB: just duplicate the graylevel three times. + * This is provided to support applications that don't want to cope + * with grayscale as a separate case. + */ + +METHODDEF(void) +gray_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW outptr; + register JSAMPROW inptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr = input_buf[0][input_row++]; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * This version handles Adobe-style YCCK->CMYK conversion, + * where we convert YCbCr to R=1-C, G=1-M, and B=1-Y using the + * same conversion as above, while passing K (black) unchanged. + * We assume build_ycc_rgb_table has been called. + */ + +METHODDEF(void) +ycck_cmyk_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses, + * and for extended gamut encodings (sYCC). + */ + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)))]; + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + /* K passes through unchanged */ + outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ + outptr += 4; + } + } +} + + +/* + * Convert CMYK to YK part of YCCK for colorless output. + * We assume build_rgb_y_table has been called. + */ + +METHODDEF(void) +cmyk_yk_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register INT32 y; + register INT32 * Rytab = cconvert->R_y_tab; + register INT32 * Gytab = cconvert->G_y_tab; + register INT32 * Bytab = cconvert->B_y_tab; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = Rytab[MAXJSAMPLE - GETJSAMPLE(inptr0[col])]; + y += Gytab[MAXJSAMPLE - GETJSAMPLE(inptr1[col])]; + y += Bytab[MAXJSAMPLE - GETJSAMPLE(inptr2[col])]; + outptr[0] = (JSAMPLE) (y >> SCALEBITS); + /* K passes through unchanged */ + outptr[1] = inptr3[col]; /* don't need GETJSAMPLE here */ + outptr += 2; + } + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +start_pass_dcolor (j_decompress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for output colorspace conversion. + */ + +GLOBAL(void) +jinit_color_deconverter (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + int ci, i; + + cconvert = (my_cconvert_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_color_deconverter)); + cinfo->cconvert = &cconvert->pub; + cconvert->pub.start_pass = start_pass_dcolor; + + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_RGB: + case JCS_YCbCr: + case JCS_BG_RGB: + case JCS_BG_YCC: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->num_components < 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + } + + /* Support color transform only for RGB colorspaces */ + if (cinfo->color_transform && + cinfo->jpeg_color_space != JCS_RGB && + cinfo->jpeg_color_space != JCS_BG_RGB) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + + /* Set out_color_components and conversion method based on requested space. + * Also adjust the component_needed flags for any unused components, + * so that earlier pipeline stages can avoid useless computation. + */ + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + case JCS_YCbCr: + case JCS_BG_YCC: + cconvert->pub.color_convert = grayscale_convert; + /* For color->grayscale conversion, only the Y (0) component is needed */ + for (ci = 1; ci < cinfo->num_components; ci++) + cinfo->comp_info[ci].component_needed = FALSE; + break; + case JCS_RGB: + switch (cinfo->color_transform) { + case JCT_NONE: + cconvert->pub.color_convert = rgb_gray_convert; + break; + case JCT_SUBTRACT_GREEN: + cconvert->pub.color_convert = rgb1_gray_convert; + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + build_rgb_y_table(cinfo); + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + + case JCS_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + cconvert->pub.color_convert = gray_rgb_convert; + break; + case JCS_YCbCr: + cconvert->pub.color_convert = ycc_rgb_convert; + build_ycc_rgb_table(cinfo); + break; + case JCS_BG_YCC: + cconvert->pub.color_convert = ycc_rgb_convert; + build_bg_ycc_rgb_table(cinfo); + break; + case JCS_RGB: + switch (cinfo->color_transform) { + case JCT_NONE: + cconvert->pub.color_convert = rgb_convert; + break; + case JCT_SUBTRACT_GREEN: + cconvert->pub.color_convert = rgb1_rgb_convert; + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + + case JCS_BG_RGB: + if (cinfo->jpeg_color_space != JCS_BG_RGB) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cinfo->out_color_components = RGB_PIXELSIZE; + switch (cinfo->color_transform) { + case JCT_NONE: + cconvert->pub.color_convert = rgb_convert; + break; + case JCT_SUBTRACT_GREEN: + cconvert->pub.color_convert = rgb1_rgb_convert; + break; + default: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + + case JCS_CMYK: + if (cinfo->jpeg_color_space != JCS_YCCK) + goto def_label; + cinfo->out_color_components = 4; + cconvert->pub.color_convert = ycck_cmyk_convert; + build_ycc_rgb_table(cinfo); + break; + + case JCS_YCCK: + if (cinfo->jpeg_color_space != JCS_CMYK || + /* Support only YK part of YCCK for colorless output */ + ! cinfo->comp_info[0].component_needed || + cinfo->comp_info[1].component_needed || + cinfo->comp_info[2].component_needed || + ! cinfo->comp_info[3].component_needed) + goto def_label; + cinfo->out_color_components = 2; + /* Need all components on input side */ + cinfo->comp_info[1].component_needed = TRUE; + cinfo->comp_info[2].component_needed = TRUE; + cconvert->pub.color_convert = cmyk_yk_convert; + build_rgb_y_table(cinfo); + break; + + default: def_label: /* permit null conversion to same output space */ + if (cinfo->out_color_space != cinfo->jpeg_color_space) + /* unsupported non-null conversion */ + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + i = 0; + for (ci = 0; ci < cinfo->num_components; ci++) + if (cinfo->comp_info[ci].component_needed) + i++; /* count output color components */ + cinfo->out_color_components = i; + cconvert->pub.color_convert = null_convert; + } + + if (cinfo->quantize_colors) + cinfo->output_components = 1; /* single colormapped output component */ + else + cinfo->output_components = cinfo->out_color_components; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jddctmgr.c b/widget/milsko/milskosrc/external/libjpeg/src/jddctmgr.c new file mode 100644 index 0000000000..9ecfbb5107 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jddctmgr.c @@ -0,0 +1,384 @@ +/* + * jddctmgr.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2002-2013 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the inverse-DCT management logic. + * This code selects a particular IDCT implementation to be used, + * and it performs related housekeeping chores. No code in this file + * is executed per IDCT step, only during output pass setup. + * + * Note that the IDCT routines are responsible for performing coefficient + * dequantization as well as the IDCT proper. This module sets up the + * dequantization multiplier table needed by the IDCT routine. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* + * The decompressor input side (jdinput.c) saves away the appropriate + * quantization table for each component at the start of the first scan + * involving that component. (This is necessary in order to correctly + * decode files that reuse Q-table slots.) + * When we are ready to make an output pass, the saved Q-table is converted + * to a multiplier table that will actually be used by the IDCT routine. + * The multiplier table contents are IDCT-method-dependent. To support + * application changes in IDCT method between scans, we can remake the + * multiplier tables if necessary. + * In buffered-image mode, the first output pass may occur before any data + * has been seen for some components, and thus before their Q-tables have + * been saved away. To handle this case, multiplier tables are preset + * to zeroes; the result of the IDCT will be a neutral gray level. + */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_inverse_dct pub; /* public fields */ + + /* This array contains the IDCT method code that each multiplier table + * is currently set up for, or -1 if it's not yet set up. + * The actual multiplier tables are pointed to by dct_table in the + * per-component comp_info structures. + */ + int cur_method[MAX_COMPONENTS]; +} my_idct_controller; + +typedef my_idct_controller * my_idct_ptr; + + +/* Allocated multiplier tables: big enough for any supported variant */ + +typedef union { + ISLOW_MULT_TYPE islow_array[DCTSIZE2]; +#ifdef DCT_IFAST_SUPPORTED + IFAST_MULT_TYPE ifast_array[DCTSIZE2]; +#endif +#ifdef DCT_FLOAT_SUPPORTED + FLOAT_MULT_TYPE float_array[DCTSIZE2]; +#endif +} multiplier_table; + + +/* The current scaled-IDCT routines require ISLOW-style multiplier tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef IDCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Prepare for an output pass. + * Here we select the proper IDCT routine for each component and build + * a matching multiplier table. + */ + +METHODDEF(void) +start_pass (j_decompress_ptr cinfo) +{ + my_idct_ptr idct = (my_idct_ptr) cinfo->idct; + int ci, i; + jpeg_component_info *compptr; + int method = 0; + inverse_DCT_method_ptr method_ptr = NULL; + JQUANT_TBL * qtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper IDCT routine for this component's scaling */ + switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) { +#ifdef IDCT_SCALING_SUPPORTED + case ((1 << 8) + 1): + method_ptr = jpeg_idct_1x1; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((2 << 8) + 2): + method_ptr = jpeg_idct_2x2; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((3 << 8) + 3): + method_ptr = jpeg_idct_3x3; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((4 << 8) + 4): + method_ptr = jpeg_idct_4x4; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((5 << 8) + 5): + method_ptr = jpeg_idct_5x5; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((6 << 8) + 6): + method_ptr = jpeg_idct_6x6; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((7 << 8) + 7): + method_ptr = jpeg_idct_7x7; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((9 << 8) + 9): + method_ptr = jpeg_idct_9x9; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((10 << 8) + 10): + method_ptr = jpeg_idct_10x10; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((11 << 8) + 11): + method_ptr = jpeg_idct_11x11; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((12 << 8) + 12): + method_ptr = jpeg_idct_12x12; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((13 << 8) + 13): + method_ptr = jpeg_idct_13x13; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((14 << 8) + 14): + method_ptr = jpeg_idct_14x14; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((15 << 8) + 15): + method_ptr = jpeg_idct_15x15; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((16 << 8) + 16): + method_ptr = jpeg_idct_16x16; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((16 << 8) + 8): + method_ptr = jpeg_idct_16x8; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((14 << 8) + 7): + method_ptr = jpeg_idct_14x7; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((12 << 8) + 6): + method_ptr = jpeg_idct_12x6; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((10 << 8) + 5): + method_ptr = jpeg_idct_10x5; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((8 << 8) + 4): + method_ptr = jpeg_idct_8x4; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((6 << 8) + 3): + method_ptr = jpeg_idct_6x3; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((4 << 8) + 2): + method_ptr = jpeg_idct_4x2; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((2 << 8) + 1): + method_ptr = jpeg_idct_2x1; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((8 << 8) + 16): + method_ptr = jpeg_idct_8x16; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((7 << 8) + 14): + method_ptr = jpeg_idct_7x14; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((6 << 8) + 12): + method_ptr = jpeg_idct_6x12; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((5 << 8) + 10): + method_ptr = jpeg_idct_5x10; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((4 << 8) + 8): + method_ptr = jpeg_idct_4x8; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((3 << 8) + 6): + method_ptr = jpeg_idct_3x6; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((2 << 8) + 4): + method_ptr = jpeg_idct_2x4; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((1 << 8) + 2): + method_ptr = jpeg_idct_1x2; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; +#endif + case ((DCTSIZE << 8) + DCTSIZE): + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + method_ptr = jpeg_idct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + method_ptr = jpeg_idct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + method_ptr = jpeg_idct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + break; + default: + ERREXIT2(cinfo, JERR_BAD_DCTSIZE, + compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size); + break; + } + idct->pub.inverse_DCT[ci] = method_ptr; + /* Create multiplier table from quant table. + * However, we can skip this if the component is uninteresting + * or if we already built the table. Also, if no quant table + * has yet been saved for the component, we leave the + * multiplier table all-zero; we'll be reading zeroes from the + * coefficient controller's buffer anyway. + */ + if (! compptr->component_needed || idct->cur_method[ci] == method) + continue; + qtbl = compptr->quant_table; + if (qtbl == NULL) /* happens if no data yet for component */ + continue; + idct->cur_method[ci] = method; + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + { + /* For LL&M IDCT method, multipliers are equal to raw quantization + * coefficients, but are stored as ints to ensure access efficiency. + */ + ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i]; + } + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * For integer operation, the multiplier table is to be scaled by + * IFAST_SCALE_BITS. + */ + IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + for (i = 0; i < DCTSIZE2; i++) { + ifmtbl[i] = (IFAST_MULT_TYPE) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-IFAST_SCALE_BITS); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 1/8. + */ + FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fmtbl[i] = (FLOAT_MULT_TYPE) + ((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col] * 0.125); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Initialize IDCT manager. + */ + +GLOBAL(void) +jinit_inverse_dct (j_decompress_ptr cinfo) +{ + my_idct_ptr idct; + int ci; + jpeg_component_info *compptr; + + idct = (my_idct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_idct_controller)); + cinfo->idct = &idct->pub; + idct->pub.start_pass = start_pass; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate and pre-zero a multiplier table for each component */ + compptr->dct_table = + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(multiplier_table)); + MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); + /* Mark multiplier table not yet set up for any method */ + idct->cur_method[ci] = -1; + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdhuff.c b/widget/milsko/milskosrc/external/libjpeg/src/jdhuff.c new file mode 100644 index 0000000000..f175f0c323 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdhuff.c @@ -0,0 +1,1559 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2006-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines. + * Both sequential and progressive modes are supported in this single module. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & BIT_MASK(nbits)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & BIT_MASK(nbits)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + + +/* + * Expanded entropy decoder object for Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).EOBRUN = (src).EOBRUN, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + boolean insufficient_data; /* set TRUE after emitting warning */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Following two fields used only in progressive mode */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ + + /* Following fields used only in sequential mode */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + + /* Precalculated info set up by start_pass for use in decode_mcu: */ + + /* Pointers to derived tables to be used for each block within an MCU */ + d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU]; + d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU]; + /* Whether we care about the DC and AC coefficient values for each block */ + int coef_limit[D_MAX_BLOCKS_IN_MCU]; +} huff_entropy_decoder; + +typedef huff_entropy_decoder * huff_entropy_ptr; + + +static const int jpeg_zigzag_order[8][8] = { + { 0, 1, 5, 6, 14, 15, 27, 28 }, + { 2, 4, 7, 13, 16, 26, 29, 42 }, + { 3, 8, 12, 17, 25, 30, 41, 43 }, + { 9, 11, 18, 24, 31, 40, 44, 53 }, + { 10, 19, 23, 32, 39, 45, 52, 54 }, + { 20, 22, 33, 38, 46, 51, 55, 60 }, + { 21, 34, 37, 47, 50, 56, 59, 61 }, + { 35, 36, 48, 49, 57, 58, 62, 63 } +}; + +static const int jpeg_zigzag_order7[7][7] = { + { 0, 1, 5, 6, 14, 15, 27 }, + { 2, 4, 7, 13, 16, 26, 28 }, + { 3, 8, 12, 17, 25, 29, 38 }, + { 9, 11, 18, 24, 30, 37, 39 }, + { 10, 19, 23, 31, 36, 40, 45 }, + { 20, 22, 32, 35, 41, 44, 46 }, + { 21, 33, 34, 42, 43, 47, 48 } +}; + +static const int jpeg_zigzag_order6[6][6] = { + { 0, 1, 5, 6, 14, 15 }, + { 2, 4, 7, 13, 16, 25 }, + { 3, 8, 12, 17, 24, 26 }, + { 9, 11, 18, 23, 27, 32 }, + { 10, 19, 22, 28, 31, 33 }, + { 20, 21, 29, 30, 34, 35 } +}; + +static const int jpeg_zigzag_order5[5][5] = { + { 0, 1, 5, 6, 14 }, + { 2, 4, 7, 13, 15 }, + { 3, 8, 12, 16, 21 }, + { 9, 11, 17, 20, 22 }, + { 10, 18, 19, 23, 24 } +}; + +static const int jpeg_zigzag_order4[4][4] = { + { 0, 1, 5, 6 }, + { 2, 4, 7, 12 }, + { 3, 8, 11, 13 }, + { 9, 10, 14, 15 } +}; + +static const int jpeg_zigzag_order3[3][3] = { + { 0, 1, 5 }, + { 2, 4, 6 }, + { 3, 7, 8 } +}; + +static const int jpeg_zigzag_order2[2][2] = { + { 0, 1 }, + { 2, 3 } +}; + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + */ + +LOCAL(void) +jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno, + d_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + d_derived_tbl *dtbl; + int p, i, l, si, numsymbols; + int lookbits, ctr; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + htbl = jpeg_std_huff_table((j_common_ptr) cinfo, isDC, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (d_derived_tbl *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(d_derived_tbl)); + dtbl = *pdtbl; + dtbl->pub = htbl; /* fill in back link */ + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + numsymbols = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + */ + if (((INT32) code) >= (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure F.15: generate decoding tables for bit-sequential decoding */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + /* valoffset[l] = huffval[] index of 1st symbol of code length l, + * minus the minimum code of length l + */ + dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p]; + p += htbl->bits[l]; + dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ + } + } + dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ + + /* Compute lookahead tables to speed up decoding. + * First we set all the table entries to 0, indicating "too long"; + * then we iterate through the Huffman codes that are short enough and + * fill in all the entries that correspond to bit sequences starting + * with that code. + */ + + MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); + + p = 0; + for (l = 1; l <= HUFF_LOOKAHEAD; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { + /* l = current code's length, p = its index in huffcode[] & huffval[]. */ + /* Generate left-justified code followed by all possible bit sequences */ + lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); + for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { + dtbl->look_nbits[lookbits] = l; + dtbl->look_sym[lookbits] = htbl->huffval[p]; + lookbits++; + } + } + } + + /* Validate symbols as being reasonable. + * For AC tables, we make no check, but accept all byte values 0..255. + * For DC tables, we require the symbols to be in range 0..15. + * (Tighter bounds could be applied depending on the data depth and mode, + * but this is sufficient to ensure safe decoding.) + */ + if (isDC) { + for (i = 0; i < numsymbols; i++) { + int sym = htbl->huffval[i]; + if (sym < 0 || sym > 15) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + } + } +} + + +/* + * Out-of-line code for bit fetching. + * Note: current values of get_buffer and bits_left are passed as parameters, + * but are returned in the corresponding fields of the state struct. + * + * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width + * of get_buffer to be used. (On machines with wider words, an even larger + * buffer could be used.) However, on some machines 32-bit shifts are + * quite slow and take time proportional to the number of places shifted. + * (This is true with most PC compilers, for instance.) In this case it may + * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the + * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. + */ + +#ifdef SLOW_SHIFT_32 +#define MIN_GET_BITS 15 /* minimum allowable value */ +#else +#define MIN_GET_BITS (BIT_BUF_SIZE-7) +#endif + + +LOCAL(boolean) +jpeg_fill_bit_buffer (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits) +/* Load up the bit buffer to a depth of at least nbits */ +{ + /* Copy heavily used state fields into locals (hopefully registers) */ + register const JOCTET * next_input_byte = state->next_input_byte; + register size_t bytes_in_buffer = state->bytes_in_buffer; + j_decompress_ptr cinfo = state->cinfo; + + /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ + /* (It is assumed that no request will be for more than that many bits.) */ + /* We fail to do so only if we hit a marker or are forced to suspend. */ + + if (cinfo->unread_marker == 0) { /* cannot advance past a marker */ + while (bits_left < MIN_GET_BITS) { + register int c; + + /* Attempt to read a byte */ + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xFF) { + /* Loop here to discard any padding FF's on terminating marker, + * so that we can save a valid unread_marker value. NOTE: we will + * accept multiple FF's followed by a 0 as meaning a single FF data + * byte. This data pattern is not valid according to the standard. + */ + do { + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + } while (c == 0xFF); + + if (c == 0) { + /* Found FF/00, which represents an FF data byte */ + c = 0xFF; + } else { + /* Oops, it's actually a marker indicating end of compressed data. + * Save the marker code for later use. + * Fine point: it might appear that we should save the marker into + * bitread working state, not straight into permanent state. But + * once we have hit a marker, we cannot need to suspend within the + * current MCU, because we will read no more bytes from the data + * source. So it is OK to update permanent state right away. + */ + cinfo->unread_marker = c; + /* See if we need to insert some fake zero bits. */ + goto no_more_bytes; + } + } + + /* OK, load c into get_buffer */ + get_buffer = (get_buffer << 8) | c; + bits_left += 8; + } /* end while */ + } else { + no_more_bytes: + /* We get here if we've read the marker that terminates the compressed + * data segment. There should be enough bits in the buffer register + * to satisfy the request; if so, no problem. + */ + if (nbits > bits_left) { + /* Uh-oh. Report corrupted data to user and stuff zeroes into + * the data stream, so that we can produce some kind of image. + * We use a nonvolatile flag to ensure that only one warning message + * appears per data segment. + */ + if (! ((huff_entropy_ptr) cinfo->entropy)->insufficient_data) { + WARNMS(cinfo, JWRN_HIT_MARKER); + ((huff_entropy_ptr) cinfo->entropy)->insufficient_data = TRUE; + } + /* Fill the buffer with zero bits */ + get_buffer <<= MIN_GET_BITS - bits_left; + bits_left = MIN_GET_BITS; + } + } + + /* Unload the local registers */ + state->next_input_byte = next_input_byte; + state->bytes_in_buffer = bytes_in_buffer; + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + return TRUE; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and sub will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define BIT_MASK(nbits) ((1<<(nbits))-1) +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) - ((1<<(s))-1) : (x)) + +#else + +#define BIT_MASK(nbits) bmask[nbits] +#define HUFF_EXTEND(x,s) ((x) <= bmask[(s) - 1] ? (x) - bmask[s] : (x)) + +static const int bmask[16] = /* bmask[n] is mask for n rightmost bits */ + { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF }; + +#endif /* AVOID_TABLES */ + + +/* + * Out-of-line code for Huffman code decoding. + */ + +LOCAL(int) +jpeg_huff_decode (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits) +{ + register int l = min_bits; + register INT32 code; + + /* HUFF_DECODE has determined that the code is at least min_bits */ + /* bits long, so fetch that many bits in one swoop. */ + + CHECK_BIT_BUFFER(*state, l, return -1); + code = GET_BITS(l); + + /* Collect the rest of the Huffman code one bit at a time. */ + /* This is per Figure F.16 in the JPEG spec. */ + + while (code > htbl->maxcode[l]) { + code <<= 1; + CHECK_BIT_BUFFER(*state, 1, return -1); + code |= GET_BITS(1); + l++; + } + + /* Unload the local registers */ + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + /* With garbage input we may reach the sentinel value l = 17. */ + + if (l > 16) { + WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); + return 0; /* fake a zero as the safest result */ + } + + return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; +} + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci; + + finish_pass_huff(cinfo); + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Re-init EOB run count, too */ + entropy->saved.EOBRUN = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Huffman MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + * (Wholesale zeroing is usually a little faster than retail...) + * + * We return FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * spectral selection, since we'll just re-assign them on the next call. + * Successive approximation AC refinement has to be more careful, however.) + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int Al = cinfo->Al; + register int s, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * tbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo, entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + tbl = entropy->derived_tbls[compptr->dc_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, tbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (s << Al); + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo, entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval if using restarts */ + if (cinfo->restart_interval) + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int s, k, r; + unsigned int EOBRUN; + int Se, Al; + const int * natural_order; + JBLOCKROW block; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state. + * We can avoid loading/saving bitread state if in an EOB run. + */ + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + + if (EOBRUN) /* if it's a band of zeroes... */ + EOBRUN--; /* ...process it now (we do nothing) */ + else { + BITREAD_LOAD_STATE(cinfo, entropy->bitstate); + Se = cinfo->Se; + Al = cinfo->Al; + natural_order = cinfo->natural_order; + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + for (k = cinfo->Ss; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, return FALSE, label2); + r = s >> 4; + s &= 15; + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[natural_order[k]] = (JCOEF) (s << Al); + } else { + if (r != 15) { /* EOBr, run length is 2^r + appended bits */ + if (r) { /* EOBr, r > 0 */ + EOBRUN = 1 << r; + CHECK_BIT_BUFFER(br_state, r, return FALSE); + r = GET_BITS(r); + EOBRUN += r; + EOBRUN--; /* this band is processed at this moment */ + } + break; /* force end-of-band */ + } + k += 15; /* ZRL: skip 15 zeroes in band */ + } + } + + BITREAD_SAVE_STATE(cinfo, entropy->bitstate); + } + + /* Completed MCU, so update state */ + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval if using restarts */ + if (cinfo->restart_interval) + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, + * although the spec is not very clear on the point. + */ + +METHODDEF(boolean) +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + JCOEF p1; + int blkn; + BITREAD_STATE_VARS; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Not worth the cycles to check insufficient_data here, + * since we will not change the data anyway if we read zeroes. + */ + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo, entropy->bitstate); + + p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + /* Encoded data is simply the next bit of the two's-complement DC value */ + CHECK_BIT_BUFFER(br_state, 1, return FALSE); + if (GET_BITS(1)) + MCU_data[blkn][0][0] |= p1; + /* Note: since we use |=, repeating the assignment later is safe */ + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo, entropy->bitstate); + + /* Account for restart interval if using restarts */ + if (cinfo->restart_interval) + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int s, k, r; + unsigned int EOBRUN; + int Se; + JCOEF p1, m1; + const int * natural_order; + JBLOCKROW block; + JCOEFPTR thiscoef; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + int num_newnz; + int newnz_pos[DCTSIZE2]; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, don't modify the MCU. + */ + if (! entropy->insufficient_data) { + + Se = cinfo->Se; + p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + m1 = -p1; /* -1 in the bit position being coded */ + natural_order = cinfo->natural_order; + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo, entropy->bitstate); + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + /* If we are forced to suspend, we must undo the assignments to any newly + * nonzero coefficients in the block, because otherwise we'd get confused + * next time about which coefficients were already nonzero. + * But we need not undo addition of bits to already-nonzero coefficients; + * instead, we can test the current bit to see if we already did it. + */ + num_newnz = 0; + + /* initialize coefficient loop counter to start of band */ + k = cinfo->Ss; + + if (EOBRUN == 0) { + do { + HUFF_DECODE(s, br_state, tbl, goto undoit, label3); + r = s >> 4; + s &= 15; + if (s) { + if (s != 1) /* size of new coef should always be 1 */ + WARNMS(cinfo, JWRN_HUFF_BAD_CODE); + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) + s = p1; /* newly nonzero coef is positive */ + else + s = m1; /* newly nonzero coef is negative */ + } else { + if (r != 15) { + EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ + if (r) { + CHECK_BIT_BUFFER(br_state, r, goto undoit); + r = GET_BITS(r); + EOBRUN += r; + } + break; /* rest of block is handled by EOB logic */ + } + /* note s = 0 for processing ZRL */ + } + /* Advance over already-nonzero coefs and r still-zero coefs, + * appending correction bits to the nonzeroes. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + do { + thiscoef = *block + natural_order[k]; + if (*thiscoef) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } else { + if (--r < 0) + break; /* reached target zero coefficient */ + } + k++; + } while (k <= Se); + if (s) { + int pos = natural_order[k]; + /* Output newly nonzero coefficient */ + (*block)[pos] = (JCOEF) s; + /* Remember its position in case we have to suspend */ + newnz_pos[num_newnz++] = pos; + } + k++; + } while (k <= Se); + } + + if (EOBRUN) { + /* Scan any remaining coefficient positions after the end-of-band + * (the last newly nonzero coefficient, if any). Append a correction + * bit to each already-nonzero coefficient. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + do { + thiscoef = *block + natural_order[k]; + if (*thiscoef) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } + k++; + } while (k <= Se); + /* Count one block completed in EOB run */ + EOBRUN--; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo, entropy->bitstate); + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval if using restarts */ + if (cinfo->restart_interval) + entropy->restarts_to_go--; + + return TRUE; + +undoit: + /* Re-zero any output coefficients that we made newly nonzero */ + while (num_newnz) + (*block)[newnz_pos[--num_newnz]] = 0; + + return FALSE; +} + + +/* + * Decode one MCU's worth of Huffman-compressed coefficients, + * partial blocks. + */ + +METHODDEF(boolean) +decode_mcu_sub (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + const int * natural_order; + int Se, blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + natural_order = cinfo->natural_order; + Se = cinfo->lim_Se; + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo, entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + JBLOCKROW block = MCU_data[blkn]; + d_derived_tbl * htbl; + register int s, k, r; + int coef_limit, ci; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + htbl = entropy->dc_cur_tbls[blkn]; + HUFF_DECODE(s, br_state, htbl, return FALSE, label1); + + htbl = entropy->ac_cur_tbls[blkn]; + k = 1; + coef_limit = entropy->coef_limit[blkn]; + if (coef_limit) { + /* Convert DC difference to actual value, update last_dc_val */ + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient */ + (*block)[0] = (JCOEF) s; + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (; k < coef_limit; k++) { + HUFF_DECODE(s, br_state, htbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in natural_order[] will save us + * if k > Se, which could happen if the data is corrupted. + */ + (*block)[natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + goto EndOfBlock; + k += 15; + } + } + } else { + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } + } + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (; k <= Se; k++) { + HUFF_DECODE(s, br_state, htbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + EndOfBlock: ; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo, entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval if using restarts */ + if (cinfo->restart_interval) + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Decode one MCU's worth of Huffman-compressed coefficients, + * full-size blocks. + */ + +METHODDEF(boolean) +decode_mcu (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo, entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + JBLOCKROW block = MCU_data[blkn]; + d_derived_tbl * htbl; + register int s, k, r; + int coef_limit, ci; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + htbl = entropy->dc_cur_tbls[blkn]; + HUFF_DECODE(s, br_state, htbl, return FALSE, label1); + + htbl = entropy->ac_cur_tbls[blkn]; + k = 1; + coef_limit = entropy->coef_limit[blkn]; + if (coef_limit) { + /* Convert DC difference to actual value, update last_dc_val */ + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient */ + (*block)[0] = (JCOEF) s; + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (; k < coef_limit; k++) { + HUFF_DECODE(s, br_state, htbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in jpeg_natural_order[] will save us + * if k >= DCTSIZE2, which could happen if the data is corrupted. + */ + (*block)[jpeg_natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + goto EndOfBlock; + k += 15; + } + } + } else { + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } + } + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, htbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + EndOfBlock: ; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo, entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval if using restarts */ + if (cinfo->restart_interval) + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, blkn, tbl, i; + jpeg_component_info * compptr; + + if (cinfo->progressive_mode) { + /* Validate progressive scan parameters */ + if (cinfo->Ss == 0) { + if (cinfo->Se != 0) + goto bad; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se) + goto bad; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + goto bad; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Ah-1 != cinfo->Al) + goto bad; + } + if (cinfo->Al > 13) { /* need not check for < 0 */ + /* Arguably the maximum Al value should be less than 13 for 8-bit + * precision, but the spec doesn't say so, and we try to be liberal + * about what we accept. Note: large Al values could result in + * out-of-range DC coefficients during early scans, leading to bizarre + * displays due to overflows in the IDCT math. But we won't crash. + */ + bad: + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + } + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int coefi, cindex = cinfo->cur_comp_info[ci]->component_index; + int *coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (cinfo->Ss == 0) + entropy->pub.decode_mcu = decode_mcu_DC_first; + else + entropy->pub.decode_mcu = decode_mcu_AC_first; + } else { + if (cinfo->Ss == 0) + entropy->pub.decode_mcu = decode_mcu_DC_refine; + else + entropy->pub.decode_mcu = decode_mcu_AC_refine; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present, and compute derived tables. + * We may build same derived table more than once, but it's not expensive. + */ + if (cinfo->Ss == 0) { + if (cinfo->Ah == 0) { /* DC refinement needs no table */ + tbl = compptr->dc_tbl_no; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, + & entropy->derived_tbls[tbl]); + } + } else { + tbl = compptr->ac_tbl_no; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, + & entropy->derived_tbls[tbl]); + /* remember the single active table */ + entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize private state variables */ + entropy->saved.EOBRUN = 0; + } else { + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning because + * there are some baseline files out there with all zeroes in these bytes. + */ + if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 || + ((cinfo->is_baseline || cinfo->Se < DCTSIZE2) && + cinfo->Se != cinfo->lim_Se)) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + + /* Select MCU decoding routine */ + /* We retain the hard-coded case for full-size blocks. + * This is not necessary, but it appears that this version is slightly + * more performant in the given implementation. + * With an improved implementation we would prefer a single optimized + * function. + */ + if (cinfo->lim_Se != DCTSIZE2-1) + entropy->pub.decode_mcu = decode_mcu_sub; + else + entropy->pub.decode_mcu = decode_mcu; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + tbl = compptr->dc_tbl_no; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, + & entropy->dc_derived_tbls[tbl]); + if (cinfo->lim_Se) { /* AC needs no table when not present */ + tbl = compptr->ac_tbl_no; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, + & entropy->ac_derived_tbls[tbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Precalculate decoding info for each block in an MCU of this scan */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* Precalculate which table to use for each block */ + entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no]; + entropy->ac_cur_tbls[blkn] = /* AC needs no table when not present */ + cinfo->lim_Se ? entropy->ac_derived_tbls[compptr->ac_tbl_no] : NULL; + /* Decide whether we really care about the coefficient values */ + if (compptr->component_needed) { + ci = compptr->DCT_v_scaled_size; + i = compptr->DCT_h_scaled_size; + switch (cinfo->lim_Se) { + case (1*1-1): + entropy->coef_limit[blkn] = 1; + break; + case (2*2-1): + if (ci <= 0 || ci > 2) ci = 2; + if (i <= 0 || i > 2) i = 2; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order2[ci - 1][i - 1]; + break; + case (3*3-1): + if (ci <= 0 || ci > 3) ci = 3; + if (i <= 0 || i > 3) i = 3; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order3[ci - 1][i - 1]; + break; + case (4*4-1): + if (ci <= 0 || ci > 4) ci = 4; + if (i <= 0 || i > 4) i = 4; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order4[ci - 1][i - 1]; + break; + case (5*5-1): + if (ci <= 0 || ci > 5) ci = 5; + if (i <= 0 || i > 5) i = 5; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order5[ci - 1][i - 1]; + break; + case (6*6-1): + if (ci <= 0 || ci > 6) ci = 6; + if (i <= 0 || i > 6) i = 6; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order6[ci - 1][i - 1]; + break; + case (7*7-1): + if (ci <= 0 || ci > 7) ci = 7; + if (i <= 0 || i > 7) i = 7; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order7[ci - 1][i - 1]; + break; + default: + if (ci <= 0 || ci > 8) ci = 8; + if (i <= 0 || i > 8) i = 8; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order[ci - 1][i - 1]; + } + } else { + entropy->coef_limit[blkn] = 0; + } + } + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->insufficient_data = FALSE; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Module initialization routine for Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(huff_entropy_decoder)); + cinfo->entropy = &entropy->pub; + entropy->pub.start_pass = start_pass_huff_decoder; + entropy->pub.finish_pass = finish_pass_huff; + + if (cinfo->progressive_mode) { + /* Create progression status table */ + int *coef_bit_ptr, ci; + cinfo->coef_bits = (int (*)[DCTSIZE2]) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * DCTSIZE2 * SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; + + /* Mark derived tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } + } else { + /* Mark derived tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdinput.c b/widget/milsko/milskosrc/external/libjpeg/src/jdinput.c new file mode 100644 index 0000000000..29fbef90bf --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdinput.c @@ -0,0 +1,657 @@ +/* + * jdinput.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2002-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input control logic for the JPEG decompressor. + * These routines are concerned with controlling the decompressor's input + * processing (marker reading and coefficient decoding). The actual input + * reading is done in jdmarker.c, jdhuff.c, and jdarith.c. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_input_controller pub; /* public fields */ + + int inheaders; /* Nonzero until first SOS is reached */ +} my_input_controller; + +typedef my_input_controller * my_inputctl_ptr; + + +/* Forward declarations */ +METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); + + +/* + * Routines to calculate various quantities related to the size of the image. + */ + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + */ + +GLOBAL(void) +jpeg_core_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase. + * This function is used for transcoding and full decompression. + */ +{ +#ifdef IDCT_SCALING_SUPPORTED + int ci; + jpeg_component_info *compptr; + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom) { + /* Provide 1/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 1; + cinfo->min_DCT_v_scaled_size = 1; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 2) { + /* Provide 2/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 2L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 2L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 2; + cinfo->min_DCT_v_scaled_size = 2; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 3) { + /* Provide 3/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 3L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 3L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 3; + cinfo->min_DCT_v_scaled_size = 3; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 4) { + /* Provide 4/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 4L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 4L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 4; + cinfo->min_DCT_v_scaled_size = 4; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 5) { + /* Provide 5/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 5L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 5L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 5; + cinfo->min_DCT_v_scaled_size = 5; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 6) { + /* Provide 6/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 6L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 6L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 6; + cinfo->min_DCT_v_scaled_size = 6; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 7) { + /* Provide 7/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 7L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 7L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 7; + cinfo->min_DCT_v_scaled_size = 7; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 8) { + /* Provide 8/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 8L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 8L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 8; + cinfo->min_DCT_v_scaled_size = 8; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 9) { + /* Provide 9/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 9L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 9L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 9; + cinfo->min_DCT_v_scaled_size = 9; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 10) { + /* Provide 10/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 10L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 10L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 10; + cinfo->min_DCT_v_scaled_size = 10; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 11) { + /* Provide 11/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 11L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 11L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 11; + cinfo->min_DCT_v_scaled_size = 11; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 12) { + /* Provide 12/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 12L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 12L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 12; + cinfo->min_DCT_v_scaled_size = 12; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 13) { + /* Provide 13/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 13L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 13L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 13; + cinfo->min_DCT_v_scaled_size = 13; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 14) { + /* Provide 14/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 14L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 14L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 14; + cinfo->min_DCT_v_scaled_size = 14; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 15) { + /* Provide 15/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 15L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 15L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 15; + cinfo->min_DCT_v_scaled_size = 15; + } else { + /* Provide 16/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 16L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 16L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 16; + cinfo->min_DCT_v_scaled_size = 16; + } + + /* Recompute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size; + compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size; + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* initial_setup has already initialized DCT_scaled_size, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ +} + + +LOCAL(void) +initial_setup (j_decompress_ptr cinfo) +/* Called once, when first SOS marker is reached */ +{ + int ci; + jpeg_component_info *compptr; + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Only 8 to 12 bits data precision are supported for DCT based JPEG */ + if (cinfo->data_precision < 8 || cinfo->data_precision > 12) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Derive block_size, natural_order, and lim_Se */ + if (cinfo->is_baseline || (cinfo->progressive_mode && + cinfo->comps_in_scan)) { /* no pseudo SOS marker */ + cinfo->block_size = DCTSIZE; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + } else + switch (cinfo->Se) { + case (1*1-1): + cinfo->block_size = 1; + cinfo->natural_order = jpeg_natural_order; /* not needed */ + cinfo->lim_Se = cinfo->Se; + break; + case (2*2-1): + cinfo->block_size = 2; + cinfo->natural_order = jpeg_natural_order2; + cinfo->lim_Se = cinfo->Se; + break; + case (3*3-1): + cinfo->block_size = 3; + cinfo->natural_order = jpeg_natural_order3; + cinfo->lim_Se = cinfo->Se; + break; + case (4*4-1): + cinfo->block_size = 4; + cinfo->natural_order = jpeg_natural_order4; + cinfo->lim_Se = cinfo->Se; + break; + case (5*5-1): + cinfo->block_size = 5; + cinfo->natural_order = jpeg_natural_order5; + cinfo->lim_Se = cinfo->Se; + break; + case (6*6-1): + cinfo->block_size = 6; + cinfo->natural_order = jpeg_natural_order6; + cinfo->lim_Se = cinfo->Se; + break; + case (7*7-1): + cinfo->block_size = 7; + cinfo->natural_order = jpeg_natural_order7; + cinfo->lim_Se = cinfo->Se; + break; + case (8*8-1): + cinfo->block_size = 8; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (9*9-1): + cinfo->block_size = 9; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (10*10-1): + cinfo->block_size = 10; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (11*11-1): + cinfo->block_size = 11; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (12*12-1): + cinfo->block_size = 12; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (13*13-1): + cinfo->block_size = 13; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (14*14-1): + cinfo->block_size = 14; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (15*15-1): + cinfo->block_size = 15; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (16*16-1): + cinfo->block_size = 16; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + default: + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + } + + /* We initialize DCT_scaled_size and min_DCT_scaled_size to block_size. + * In the full decompressor, + * this will be overridden by jpeg_calc_output_dimensions in jdmaster.c; + * but in the transcoder, + * jpeg_calc_output_dimensions is not used, so we must do it here. + */ + cinfo->min_DCT_h_scaled_size = cinfo->block_size; + cinfo->min_DCT_v_scaled_size = cinfo->block_size; + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->DCT_h_scaled_size = cinfo->block_size; + compptr->DCT_v_scaled_size = cinfo->block_size; + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + /* downsampled_width and downsampled_height will also be overridden by + * jdmaster.c if we are doing full decompression. The transcoder library + * doesn't use these values, but the calling application might. + */ + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed, until color conversion says otherwise */ + compptr->component_needed = TRUE; + /* Mark no quantization table yet saved for component */ + compptr->quant_table = NULL; + } + + /* Compute number of fully interleaved MCU rows. */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + + /* Decide whether file contains multiple scans */ + if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode) + cinfo->inputctl->has_multiple_scans = TRUE; + else + cinfo->inputctl->has_multiple_scans = FALSE; +} + + +LOCAL(void) +per_scan_setup (j_decompress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = compptr->DCT_h_scaled_size; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + cinfo->MCU_rows_in_scan = cinfo->total_iMCU_rows; + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } +} + + +/* + * Save away a copy of the Q-table referenced by each component present + * in the current scan, unless already saved during a prior scan. + * + * In a multiple-scan JPEG file, the encoder could assign different components + * the same Q-table slot number, but change table definitions between scans + * so that each component uses a different Q-table. (The IJG encoder is not + * currently capable of doing this, but other encoders might.) Since we want + * to be able to dequantize all the components at the end of the file, this + * means that we have to save away the table actually used for each component. + * We do this by copying the table at the start of the first scan containing + * the component. + * The JPEG spec prohibits the encoder from changing the contents of a Q-table + * slot between scans of a component using that slot. If the encoder does so + * anyway, this decoder will simply use the Q-table values that were current + * at the start of the first scan for the component. + * + * The decompressor output side looks only at the saved quant tables, + * not at the current Q-table slots. + */ + +LOCAL(void) +latch_quant_tables (j_decompress_ptr cinfo) +{ + int ci, qtblno; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* No work if we already saved Q-table for this component */ + if (compptr->quant_table != NULL) + continue; + /* Make sure specified quantization table is present */ + qtblno = compptr->quant_tbl_no; + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + /* OK, save away the quantization table */ + qtbl = (JQUANT_TBL *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(JQUANT_TBL)); + MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); + compptr->quant_table = qtbl; + } +} + + +/* + * Initialize the input modules to read a scan of compressed data. + * The first call to this is done by jdmaster.c after initializing + * the entire decompressor (during jpeg_start_decompress). + * Subsequent calls come from consume_markers, below. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); + latch_quant_tables(cinfo); + (*cinfo->entropy->start_pass) (cinfo); + (*cinfo->coef->start_input_pass) (cinfo); + cinfo->inputctl->consume_input = cinfo->coef->consume_data; +} + + +/* + * Finish up after inputting a compressed-data scan. + * This is called by the coefficient controller after it's read all + * the expected data of the scan. + */ + +METHODDEF(void) +finish_input_pass (j_decompress_ptr cinfo) +{ + (*cinfo->entropy->finish_pass) (cinfo); + cinfo->inputctl->consume_input = consume_markers; +} + + +/* + * Read JPEG markers before, between, or after compressed-data scans. + * Change state as necessary when a new scan is reached. + * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * The consume_input method pointer points either here or to the + * coefficient controller's consume_data routine, depending on whether + * we are reading a compressed data segment or inter-segment markers. + * + * Note: This function should NOT return a pseudo SOS marker (with zero + * component number) to the caller. A pseudo marker received by + * read_markers is processed and then skipped for other markers. + */ + +METHODDEF(int) +consume_markers (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + int val; + + if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ + return JPEG_REACHED_EOI; + + for (;;) { /* Loop to pass pseudo SOS marker */ + val = (*cinfo->marker->read_markers) (cinfo); + + switch (val) { + case JPEG_REACHED_SOS: /* Found SOS */ + if (inputctl->inheaders) { /* 1st SOS */ + if (inputctl->inheaders == 1) + initial_setup(cinfo); + if (cinfo->comps_in_scan == 0) { /* pseudo SOS marker */ + inputctl->inheaders = 2; + break; + } + inputctl->inheaders = 0; + /* Note: start_input_pass must be called by jdmaster.c + * before any more input can be consumed. jdapimin.c is + * responsible for enforcing this sequencing. + */ + } else { /* 2nd or later SOS marker */ + if (! inputctl->pub.has_multiple_scans) + ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ + if (cinfo->comps_in_scan == 0) /* unexpected pseudo SOS marker */ + break; + start_input_pass(cinfo); + } + return val; + case JPEG_REACHED_EOI: /* Found EOI */ + inputctl->pub.eoi_reached = TRUE; + if (inputctl->inheaders) { /* Tables-only datastream, apparently */ + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_NO_SOS); + } else { + /* Prevent infinite loop in coef ctlr's decompress_data routine + * if user set output_scan_number larger than number of scans. + */ + if (cinfo->output_scan_number > cinfo->input_scan_number) + cinfo->output_scan_number = cinfo->input_scan_number; + } + return val; + case JPEG_SUSPENDED: + return val; + default: + return val; + } + } +} + + +/* + * Reset state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + + inputctl->pub.consume_input = consume_markers; + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = 1; + /* Reset other modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->marker->reset_marker_reader) (cinfo); + /* Reset progression state -- would be cleaner if entropy decoder did this */ + cinfo->coef_bits = NULL; +} + + +/* + * Initialize the input controller module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl; + + /* Create subobject in permanent pool */ + inputctl = (my_inputctl_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_input_controller)); + cinfo->inputctl = &inputctl->pub; + /* Initialize method pointers */ + inputctl->pub.consume_input = consume_markers; + inputctl->pub.reset_input_controller = reset_input_controller; + inputctl->pub.start_input_pass = start_input_pass; + inputctl->pub.finish_input_pass = finish_input_pass; + /* Initialize state: can't use reset_input_controller since we don't + * want to try to reset other modules yet. + */ + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = 1; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdmainct.c b/widget/milsko/milskosrc/external/libjpeg/src/jdmainct.c new file mode 100644 index 0000000000..1cd66d853b --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdmainct.c @@ -0,0 +1,511 @@ +/* + * jdmainct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2002-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for decompression. + * The main buffer lies between the JPEG decompressor proper and the + * post-processor; it holds downsampled data in the JPEG colorspace. + * + * Note that this code is bypassed in raw-data mode, since the application + * supplies the equivalent of the main buffer in that case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * In the current system design, the main buffer need never be a full-image + * buffer; any full-height buffers will be found inside the coefficient or + * postprocessing controllers. Nonetheless, the main controller is not + * trivial. Its responsibility is to provide context rows for upsampling/ + * rescaling, and doing this in an efficient fashion is a bit tricky. + * + * Postprocessor input data is counted in "row groups". A row group is + * defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size) + * sample rows of each component. (We require DCT_scaled_size values to be + * chosen such that these numbers are integers. In practice DCT_scaled_size + * values will likely be powers of two, so we actually have the stronger + * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) + * Upsampling will typically produce max_v_samp_factor pixel rows from each + * row group (times any additional scale factor that the upsampler is + * applying). + * + * The coefficient controller will deliver data to us one iMCU row at a time; + * each iMCU row contains v_samp_factor * DCT_v_scaled_size sample rows, or + * exactly min_DCT_v_scaled_size row groups. (This amount of data corresponds + * to one row of MCUs when the image is fully interleaved.) Note that the + * number of sample rows varies across components, but the number of row + * groups does not. Some garbage sample rows may be included in the last iMCU + * row at the bottom of the image. + * + * Depending on the vertical scaling algorithm used, the upsampler may need + * access to the sample row(s) above and below its current input row group. + * The upsampler is required to set need_context_rows TRUE at global selection + * time if so. When need_context_rows is FALSE, this controller can simply + * obtain one iMCU row at a time from the coefficient controller and dole it + * out as row groups to the postprocessor. + * + * When need_context_rows is TRUE, this controller guarantees that the buffer + * passed to postprocessing contains at least one row group's worth of samples + * above and below the row group(s) being processed. Note that the context + * rows "above" the first passed row group appear at negative row offsets in + * the passed buffer. At the top and bottom of the image, the required + * context rows are manufactured by duplicating the first or last real sample + * row; this avoids having special cases in the upsampling inner loops. + * + * The amount of context is fixed at one row group just because that's a + * convenient number for this controller to work with. The existing + * upsamplers really only need one sample row of context. An upsampler + * supporting arbitrary output rescaling might wish for more than one row + * group of context when shrinking the image; tough, we don't handle that. + * (This is justified by the assumption that downsizing will be handled mostly + * by adjusting the DCT_scaled_size values, so that the actual scale factor at + * the upsample step needn't be much less than one.) + * + * To provide the desired context, we have to retain the last two row groups + * of one iMCU row while reading in the next iMCU row. (The last row group + * can't be processed until we have another row group for its below-context, + * and so we have to save the next-to-last group too for its above-context.) + * We could do this most simply by copying data around in our buffer, but + * that'd be very slow. We can avoid copying any data by creating a rather + * strange pointer structure. Here's how it works. We allocate a workspace + * consisting of M+2 row groups (where M = min_DCT_v_scaled_size is the number + * of row groups per iMCU row). We create two sets of redundant pointers to + * the workspace. Labeling the physical row groups 0 to M+1, the synthesized + * pointer lists look like this: + * M+1 M-1 + * master pointer --> 0 master pointer --> 0 + * 1 1 + * ... ... + * M-3 M-3 + * M-2 M + * M-1 M+1 + * M M-2 + * M+1 M-1 + * 0 0 + * We read alternate iMCU rows using each master pointer; thus the last two + * row groups of the previous iMCU row remain un-overwritten in the workspace. + * The pointer lists are set up so that the required context rows appear to + * be adjacent to the proper places when we pass the pointer lists to the + * upsampler. + * + * The above pictures describe the normal state of the pointer lists. + * At top and bottom of the image, we diddle the pointer lists to duplicate + * the first or last sample row as necessary (this is cheaper than copying + * sample rows around). + * + * This scheme breaks down if M < 2, ie, min_DCT_v_scaled_size is 1. In that + * situation each iMCU row provides only one row group so the buffering logic + * must be different (eg, we must read two iMCU rows before we can emit the + * first row group). For now, we simply do not support providing context + * rows when min_DCT_v_scaled_size is 1. That combination seems unlikely to + * be worth providing --- if someone wants a 1/8th-size preview, they probably + * want it quick and dirty, so a context-free upsampler is sufficient. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_main_controller pub; /* public fields */ + + /* Pointer to allocated workspace (M or M+2 row groups). */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + + /* Remaining fields are only used in the context case. */ + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + + /* These are the master pointers to the funny-order pointer lists. */ + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + int whichptr; /* indicates which pointer set is now in use */ + int context_state; /* process_data state machine status */ + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + +/* context_state values: */ +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +METHODDEF(void) process_data_context_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) process_data_crank_post + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#endif + + +LOCAL(void) +alloc_funny_pointers (j_decompress_ptr cinfo) +/* Allocate space for the funny pointer lists. + * This is done only once, not once per pass. + */ +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + int ci, rgroup; + int M = cinfo->min_DCT_v_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + /* Get top-level space for component array pointers. + * We alloc both arrays with one call to save a few cycles. + */ + mainp->xbuffer[0] = (JSAMPIMAGE) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + mainp->xbuffer[1] = mainp->xbuffer[0] + cinfo->num_components; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (! compptr->component_needed) + continue; /* skip uninteresting component */ + rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ + /* Get space for pointer lists --- M+4 row groups in each list. + * We alloc both pointer lists with one call to save a few cycles. + */ + xbuf = (JSAMPARRAY) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, + JPOOL_IMAGE, 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + xbuf += rgroup; /* want one row group at negative offsets */ + mainp->xbuffer[0][ci] = xbuf; + xbuf += rgroup * (M + 4); + mainp->xbuffer[1][ci] = xbuf; + } +} + + +LOCAL(void) +make_funny_pointers (j_decompress_ptr cinfo) +/* Create the funny pointer lists discussed in the comments above. + * The actual workspace is already allocated (in mainp->buffer), + * and the space for the pointer lists is allocated too. + * This routine just fills in the curiously ordered lists. + * This will be repeated at the beginning of each pass. + */ +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_v_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY buf, xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (! compptr->component_needed) + continue; /* skip uninteresting component */ + rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ + xbuf0 = mainp->xbuffer[0][ci]; + xbuf1 = mainp->xbuffer[1][ci]; + /* First copy the workspace pointers as-is */ + buf = mainp->buffer[ci]; + for (i = 0; i < rgroup * (M + 2); i++) { + xbuf0[i] = xbuf1[i] = buf[i]; + } + /* In the second list, put the last four row groups in swapped order */ + for (i = 0; i < rgroup * 2; i++) { + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + } + /* The wraparound pointers at top and bottom will be filled later + * (see set_wraparound_pointers, below). Initially we want the "above" + * pointers to duplicate the first actual data line. This only needs + * to happen in xbuffer[0]. + */ + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[0]; + } + } +} + + +LOCAL(void) +set_wraparound_pointers (j_decompress_ptr cinfo) +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + * This changes the pointer list state from top-of-image to the normal state. + */ +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_v_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (! compptr->component_needed) + continue; /* skip uninteresting component */ + rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ + xbuf0 = mainp->xbuffer[0][ci]; + xbuf1 = mainp->xbuffer[1][ci]; + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + } + } +} + + +LOCAL(void) +set_bottom_pointers (j_decompress_ptr cinfo) +/* Change the pointer lists to duplicate the last sample row at the bottom + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + */ +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + int ci, i, rgroup, iMCUheight, rows_left; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (! compptr->component_needed) + continue; /* skip uninteresting component */ + /* Count sample rows in one iMCU row and in one row group */ + iMCUheight = compptr->v_samp_factor * compptr->DCT_v_scaled_size; + rgroup = iMCUheight / cinfo->min_DCT_v_scaled_size; + /* Count nondummy sample rows remaining for this component */ + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + if (rows_left == 0) rows_left = iMCUheight; + /* Count nondummy row groups. Should get same answer for each component, + * so we need only do it once. + */ + if (ci == 0) { + mainp->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + } + /* Duplicate the last real sample row rgroup*2 times; this pads out the + * last partial rowgroup and ensures at least one full rowgroup of context. + */ + xbuf = mainp->xbuffer[mainp->whichptr][ci]; + for (i = 0; i < rgroup * 2; i++) { + xbuf[rows_left + i] = xbuf[rows_left-1]; + } + } +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->upsample->need_context_rows) { + mainp->pub.process_data = process_data_context_main; + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + mainp->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + mainp->context_state = CTX_PREPARE_FOR_IMCU; + mainp->iMCU_row_ctr = 0; + mainp->buffer_full = FALSE; /* Mark buffer empty */ + } else { + /* Simple case with no context needed */ + mainp->pub.process_data = process_data_simple_main; + mainp->rowgroup_ctr = mainp->rowgroups_avail; /* Mark buffer empty */ + } + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_CRANK_DEST: + /* For last pass of 2-pass quantization, just crank the postprocessor */ + mainp->pub.process_data = process_data_crank_post; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + } +} + + +/* + * Process some data. + * This handles the simple case where no context is required. + */ + +METHODDEF(void) +process_data_simple_main (j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + + /* Read input data if we haven't filled the main buffer yet */ + if (mainp->rowgroup_ctr >= mainp->rowgroups_avail) { + if (! (*cinfo->coef->decompress_data) (cinfo, mainp->buffer)) + return; /* suspension forced, can do nothing more */ + mainp->rowgroup_ctr = 0; /* OK, we have an iMCU row to work with */ + } + + /* Note: at the bottom of the image, we may pass extra garbage row groups + * to the postprocessor. The postprocessor has to check for bottom + * of image anyway (at row resolution), so no point in us doing it too. + */ + + /* Feed the postprocessor */ + (*cinfo->post->post_process_data) (cinfo, mainp->buffer, + &mainp->rowgroup_ctr, mainp->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); +} + + +/* + * Process some data. + * This handles the case where context rows must be provided. + */ + +METHODDEF(void) +process_data_context_main (j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) +{ + my_main_ptr mainp = (my_main_ptr) cinfo->main; + + /* Read input data if we haven't filled the main buffer yet */ + if (! mainp->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, + mainp->xbuffer[mainp->whichptr])) + return; /* suspension forced, can do nothing more */ + mainp->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + mainp->iMCU_row_ctr++; /* count rows received */ + } + + /* Postprocessor typically will not swallow all the input data it is handed + * in one call (due to filling the output buffer first). Must be prepared + * to exit and restart. This switch lets us keep track of how far we got. + * Note that each case falls through to the next on successful completion. + */ + switch (mainp->context_state) { + case CTX_POSTPONED_ROW: + /* Call postprocessor using previously set pointers for postponed row */ + (*cinfo->post->post_process_data) (cinfo, mainp->xbuffer[mainp->whichptr], + &mainp->rowgroup_ctr, mainp->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (mainp->rowgroup_ctr < mainp->rowgroups_avail) + return; /* Need to suspend */ + mainp->context_state = CTX_PREPARE_FOR_IMCU; + if (*out_row_ctr >= out_rows_avail) + return; /* Postprocessor exactly filled output buf */ + /*FALLTHROUGH*/ + case CTX_PREPARE_FOR_IMCU: + /* Prepare to process first M-1 row groups of this iMCU row */ + mainp->rowgroup_ctr = 0; + mainp->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1); + /* Check for bottom of image: if so, tweak pointers to "duplicate" + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + */ + if (mainp->iMCU_row_ctr == cinfo->total_iMCU_rows) + set_bottom_pointers(cinfo); + mainp->context_state = CTX_PROCESS_IMCU; + /*FALLTHROUGH*/ + case CTX_PROCESS_IMCU: + /* Call postprocessor using previously set pointers */ + (*cinfo->post->post_process_data) (cinfo, mainp->xbuffer[mainp->whichptr], + &mainp->rowgroup_ctr, mainp->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (mainp->rowgroup_ctr < mainp->rowgroups_avail) + return; /* Need to suspend */ + /* After the first iMCU, change wraparound pointers to normal state */ + if (mainp->iMCU_row_ctr == 1) + set_wraparound_pointers(cinfo); + /* Prepare to load new iMCU row using other xbuffer list */ + mainp->whichptr ^= 1; /* 0=>1 or 1=>0 */ + mainp->buffer_full = FALSE; + /* Still need to process last row group of this iMCU row, */ + /* which is saved at index M+1 of the other xbuffer */ + mainp->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1); + mainp->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2); + mainp->context_state = CTX_POSTPONED_ROW; + } +} + + +/* + * Process some data. + * Final pass of two-pass quantization: just call the postprocessor. + * Source data will be the postprocessor controller's internal buffer. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF(void) +process_data_crank_post (j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) +{ + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + (JDIMENSION *) NULL, (JDIMENSION) 0, + output_buf, out_row_ctr, out_rows_avail); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr mainp; + int ci, rgroup, ngroups; + jpeg_component_info *compptr; + + mainp = (my_main_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_main_controller)); + cinfo->main = &mainp->pub; + mainp->pub.start_pass = start_pass_main; + + if (need_full_buffer) /* shouldn't happen */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Allocate the workspace. + * ngroups is the number of row groups we need. + */ + if (cinfo->upsample->need_context_rows) { + if (cinfo->min_DCT_v_scaled_size < 2) /* unsupported, see comments above */ + ERREXIT(cinfo, JERR_NOTIMPL); + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + ngroups = cinfo->min_DCT_v_scaled_size + 2; + } else { + /* There are always min_DCT_v_scaled_size row groups in an iMCU row. */ + ngroups = cinfo->min_DCT_v_scaled_size; + mainp->rowgroups_avail = (JDIMENSION) ngroups; + } + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (! compptr->component_needed) + continue; /* skip uninteresting component */ + rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ + mainp->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size), + (JDIMENSION) (rgroup * ngroups)); + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdmarker.c b/widget/milsko/milskosrc/external/libjpeg/src/jdmarker.c new file mode 100644 index 0000000000..c10fde6053 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdmarker.c @@ -0,0 +1,1505 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2009-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG8 = 0xf8, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_reader pub; /* public fields */ + + /* Application-overridable marker processing methods */ + jpeg_marker_parser_method process_COM; + jpeg_marker_parser_method process_APPn[16]; + + /* Limit on marker data length to save for each marker type */ + unsigned int length_limit_COM; + unsigned int length_limit_APPn[16]; + + /* Status of COM/APPn marker saving */ + jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ + unsigned int bytes_read; /* data bytes read so far in marker */ + /* Note: cur_marker is not linked into marker_list until it's all read. */ +} my_marker_reader; + +typedef my_marker_reader * my_marker_ptr; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V += GETJOCTET(*next_input_byte++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters + * can fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments + * that might not fit. If we are simply dropping such a marker, we use + * skip_input_data to get past it, and thereby put the problem on the + * source manager's shoulders. If we are saving the marker's contents + * into memory, we use a slightly different convention: when forced to + * suspend, the marker processor updates the restart point to the end of + * what it's consumed (ie, the end of the buffer) before returning FALSE. + * On resumption, cinfo->unread_marker still contains the marker code, + * but the data source will point to the next chunk of marker data. + * The marker processor must retain internal state to deal with this. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL(boolean) +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->color_transform = JCT_NONE; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL(boolean) +get_sof (j_decompress_ptr cinfo, boolean is_baseline, boolean is_prog, + boolean is_arith) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci, i; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->is_baseline = is_baseline; + cinfo->progressive_mode = is_prog; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 || + cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0; ci < cinfo->num_components; ci++) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Check to see whether component id has already been seen */ + /* (in violation of the spec, but unfortunately seen in some */ + /* files). If so, create "fake" component id equal to the */ + /* max id seen so far + 1. */ + for (i = 0, compptr = cinfo->comp_info; i < ci; i++, compptr++) { + if (c == compptr->component_id) { + compptr = cinfo->comp_info; + c = compptr->component_id; + compptr++; + for (i = 1; i < ci; i++, compptr++) { + if (compptr->component_id > c) c = compptr->component_id; + } + c++; + break; + } + } + compptr->component_id = c; + compptr->component_index = ci; + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int c, ci, i, n; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXITS(cinfo, JERR_SOF_BEFORE, "SOS"); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + if (length != (n * 2 + 6) || n > MAX_COMPS_IN_SCAN || + (n == 0 && !cinfo->progressive_mode)) + /* pseudo SOS marker only allowed in progressive mode */ + ERREXIT(cinfo, JERR_BAD_LENGTH); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, c, return FALSE); + + /* Detect the case where component id's are not unique, and, if so, */ + /* create a fake component id using the same logic as in get_sof. */ + /* Note: This also ensures that all of the SOF components are */ + /* referenced in the single scan case, which prevents access to */ + /* uninitialized memory in later decoding stages. */ + for (ci = 0; ci < i; ci++) { + if (c == cinfo->cur_comp_info[ci]->component_id) { + c = cinfo->cur_comp_info[0]->component_id; + for (ci = 1; ci < i; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (compptr->component_id > c) c = compptr->component_id; + } + c++; + break; + } + } + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (c == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, c); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + INPUT_BYTE(cinfo, c, return FALSE); + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, compptr->component_id, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another (non-pseudo) SOS marker */ + if (n) cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +#ifdef D_ARITH_CODING_SUPPORTED + +LOCAL(boolean) +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + +#else /* ! D_ARITH_CODING_SUPPORTED */ + +#define get_dac(cinfo) skip_variable(cinfo) + +#endif /* D_ARITH_CODING_SUPPORTED */ + + +LOCAL(boolean) +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 16) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + /* Here we just do minimal validation of the counts to avoid walking + * off the end of our table space. jdhuff.c will check more carefully. + */ + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + if (count > 0) + MEMCOPY((*htblptr)->huffval, huffval, count * SIZEOF(UINT8)); + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length, count, i; + int n, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + const int *natural_order; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + length--; + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + if (prec) { + if (length < DCTSIZE2 * 2) { + /* Initialize full table for safety. */ + for (i = 0; i < DCTSIZE2; i++) { + quant_ptr->quantval[i] = 1; + } + count = length >> 1; + } else + count = DCTSIZE2; + } else { + if (length < DCTSIZE2) { + /* Initialize full table for safety. */ + for (i = 0; i < DCTSIZE2; i++) { + quant_ptr->quantval[i] = 1; + } + count = length; + } else + count = DCTSIZE2; + } + + switch ((int) count) { + case (2*2): natural_order = jpeg_natural_order2; break; + case (3*3): natural_order = jpeg_natural_order3; break; + case (4*4): natural_order = jpeg_natural_order4; break; + case (5*5): natural_order = jpeg_natural_order5; break; + case (6*6): natural_order = jpeg_natural_order6; break; + case (7*7): natural_order = jpeg_natural_order7; break; + default: natural_order = jpeg_natural_order; + } + + for (i = 0; i < count; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + /* We convert the zigzag-order table to natural array order. */ + quant_ptr->quantval[natural_order[i]] = (UINT16) tmp; + } + + if (cinfo->err->trace_level >= 2) { + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + } + + length -= count; + if (prec) length -= count; + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_lse (j_decompress_ptr cinfo) +/* Process an LSE marker */ +{ + INT32 length; + unsigned int tmp; + int cid; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXITS(cinfo, JERR_SOF_BEFORE, "LSE"); + + if (cinfo->num_components < 3) goto bad; + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 24) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_BYTE(cinfo, tmp, return FALSE); + if (tmp != 0x0D) /* ID inverse transform specification */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + INPUT_2BYTES(cinfo, tmp, return FALSE); + if (tmp != MAXJSAMPLE) goto bad; /* MAXTRANS */ + INPUT_BYTE(cinfo, tmp, return FALSE); + if (tmp != 3) goto bad; /* Nt=3 */ + INPUT_BYTE(cinfo, cid, return FALSE); + if (cid != cinfo->comp_info[1].component_id) goto bad; + INPUT_BYTE(cinfo, cid, return FALSE); + if (cid != cinfo->comp_info[0].component_id) goto bad; + INPUT_BYTE(cinfo, cid, return FALSE); + if (cid != cinfo->comp_info[2].component_id) goto bad; + INPUT_BYTE(cinfo, tmp, return FALSE); + if (tmp != 0x80) goto bad; /* F1: CENTER1=1, NORM1=0 */ + INPUT_2BYTES(cinfo, tmp, return FALSE); + if (tmp != 0) goto bad; /* A(1,1)=0 */ + INPUT_2BYTES(cinfo, tmp, return FALSE); + if (tmp != 0) goto bad; /* A(1,2)=0 */ + INPUT_BYTE(cinfo, tmp, return FALSE); + if (tmp != 0) goto bad; /* F2: CENTER2=0, NORM2=0 */ + INPUT_2BYTES(cinfo, tmp, return FALSE); + if (tmp != 1) goto bad; /* A(2,1)=1 */ + INPUT_2BYTES(cinfo, tmp, return FALSE); + if (tmp != 0) goto bad; /* A(2,2)=0 */ + INPUT_BYTE(cinfo, tmp, return FALSE); + if (tmp != 0) goto bad; /* F3: CENTER3=0, NORM3=0 */ + INPUT_2BYTES(cinfo, tmp, return FALSE); + if (tmp != 1) goto bad; /* A(3,1)=1 */ + INPUT_2BYTES(cinfo, tmp, return FALSE); + if (tmp != 0) { /* A(3,2)=0 */ + bad: + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + + /* OK, valid transform that we can handle. */ + cinfo->color_transform = JCT_SUBTRACT_GREEN; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Routines for processing APPn and COM markers. + * These are either saved in memory or discarded, per application request. + * APP0 and APP14 are specially checked to see if they are + * JFIF and Adobe markers, respectively. + */ + +#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */ +#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */ +#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */ + + +LOCAL(void) +examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP0. + * Take appropriate action if it is a JFIF marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + INT32 totallen = (INT32) datalen + remaining; + + if (datalen >= APP0_DATA_LEN && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x49 && + GETJOCTET(data[3]) == 0x46 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF APP0 marker: save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->JFIF_major_version = GETJOCTET(data[5]); + cinfo->JFIF_minor_version = GETJOCTET(data[6]); + cinfo->density_unit = GETJOCTET(data[7]); + cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]); + cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]); + /* Check version. + * Major version must be 1 or 2, anything else signals an incompatible + * change. + * (We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec.) + * Minor version should be 0..2, but process anyway if newer. + */ + if (cinfo->JFIF_major_version != 1 && cinfo->JFIF_major_version != 2) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version); + /* Generate trace messages */ + TRACEMS5(cinfo, 1, JTRC_JFIF, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + /* Validate thumbnail dimensions and issue appropriate messages */ + if (GETJOCTET(data[12]) | GETJOCTET(data[13])) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, + GETJOCTET(data[12]), GETJOCTET(data[13])); + totallen -= APP0_DATA_LEN; + if (totallen != + ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen); + } else if (datalen >= 6 && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x58 && + GETJOCTET(data[3]) == 0x58 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF "JFXX" extension APP0 marker */ + /* The library doesn't actually do anything with these, + * but we try to produce a helpful trace message. + */ + switch (GETJOCTET(data[5])) { + case 0x10: + TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen); + break; + case 0x11: + TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen); + break; + case 0x13: + TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen); + break; + default: + TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, + GETJOCTET(data[5]), (int) totallen); + } + } else { + /* Start of APP0 does not match "JFIF" or "JFXX", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen); + } +} + + +LOCAL(void) +examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP14. + * Take appropriate action if it is an Adobe marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + unsigned int version, flags0, flags1, transform; + + if (datalen >= APP14_DATA_LEN && + GETJOCTET(data[0]) == 0x41 && + GETJOCTET(data[1]) == 0x64 && + GETJOCTET(data[2]) == 0x6F && + GETJOCTET(data[3]) == 0x62 && + GETJOCTET(data[4]) == 0x65) { + /* Found Adobe APP14 marker */ + version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]); + flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]); + flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]); + transform = GETJOCTET(data[11]); + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining)); + } +} + + +METHODDEF(boolean) +get_interesting_appn (j_decompress_ptr cinfo) +/* Process an APP0 or APP14 marker without saving it */ +{ + INT32 length; + JOCTET b[APPN_DATA_LEN]; + unsigned int i, numtoread; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* get the interesting part of the marker data */ + if (length >= APPN_DATA_LEN) + numtoread = APPN_DATA_LEN; + else if (length > 0) + numtoread = (unsigned int) length; + else + numtoread = 0; + for (i = 0; i < numtoread; i++) + INPUT_BYTE(cinfo, b[i], return FALSE); + length -= numtoread; + + /* process it */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + case M_APP14: + examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + default: + /* can't get here unless jpeg_save_markers chooses wrong processor */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +#ifdef SAVE_MARKERS_SUPPORTED + +METHODDEF(boolean) +save_marker (j_decompress_ptr cinfo) +/* Save an APPn or COM marker into the marker list */ +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + jpeg_saved_marker_ptr cur_marker = marker->cur_marker; + unsigned int bytes_read, data_length; + JOCTET FAR * data; + INT32 length = 0; + INPUT_VARS(cinfo); + + if (cur_marker == NULL) { + /* begin reading a marker */ + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + if (length >= 0) { /* watch out for bogus length word */ + /* figure out how much we want to save */ + unsigned int limit; + if (cinfo->unread_marker == (int) M_COM) + limit = marker->length_limit_COM; + else + limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0]; + if ((unsigned int) length < limit) + limit = (unsigned int) length; + /* allocate and initialize the marker item */ + cur_marker = (jpeg_saved_marker_ptr) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(struct jpeg_marker_struct) + limit); + cur_marker->next = NULL; + cur_marker->marker = (UINT8) cinfo->unread_marker; + cur_marker->original_length = (unsigned int) length; + cur_marker->data_length = limit; + /* data area is just beyond the jpeg_marker_struct */ + data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1); + marker->cur_marker = cur_marker; + marker->bytes_read = 0; + bytes_read = 0; + data_length = limit; + } else { + /* deal with bogus length word */ + bytes_read = data_length = 0; + data = NULL; + } + } else { + /* resume reading a marker */ + bytes_read = marker->bytes_read; + data_length = cur_marker->data_length; + data = cur_marker->data + bytes_read; + } + + while (bytes_read < data_length) { + INPUT_SYNC(cinfo); /* move the restart point to here */ + marker->bytes_read = bytes_read; + /* If there's not at least one byte in buffer, suspend */ + MAKE_BYTE_AVAIL(cinfo, return FALSE); + /* Copy bytes with reasonable rapidity */ + while (bytes_read < data_length && bytes_in_buffer > 0) { + *data++ = *next_input_byte++; + bytes_in_buffer--; + bytes_read++; + } + } + + /* Done reading what we want to read */ + if (cur_marker != NULL) { /* will be NULL if bogus length word */ + /* Add new marker to end of list */ + if (cinfo->marker_list == NULL) { + cinfo->marker_list = cur_marker; + } else { + jpeg_saved_marker_ptr prev = cinfo->marker_list; + while (prev->next != NULL) + prev = prev->next; + prev->next = cur_marker; + } + /* Reset pointer & calc remaining data length */ + data = cur_marker->data; + length = cur_marker->original_length - data_length; + } + /* Reset to initial state for next marker */ + marker->cur_marker = NULL; + + /* Process the marker if interesting; else just make a generic trace msg */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, data, data_length, length); + break; + case M_APP14: + examine_app14(cinfo, data, data_length, length); + break; + default: + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, + (int) (data_length + length)); + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +METHODDEF(boolean) +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL(boolean) +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * Note: This function may return a pseudo SOS marker (with zero + * component number) for treat by input controller's consume_input. + * consume_input itself should filter out (skip) the pseudo marker + * after processing for the caller. + */ + +METHODDEF(int) +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + if (! get_sof(cinfo, TRUE, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, FALSE, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, FALSE, TRUE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, FALSE, FALSE, TRUE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, FALSE, TRUE, TRUE)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_JPG8: + if (! get_lse(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[ + cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF(boolean) +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL(boolean) +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + marker->pub.saw_SOI = FALSE; /* set internal state too */ + marker->pub.saw_SOF = FALSE; + marker->pub.discarded_bytes = 0; + marker->cur_marker = NULL; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker; + int i; + + /* Create subobject in permanent pool */ + marker = (my_marker_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_marker_reader)); + cinfo->marker = &marker->pub; + /* Initialize public method pointers */ + marker->pub.reset_marker_reader = reset_marker_reader; + marker->pub.read_markers = read_markers; + marker->pub.read_restart_marker = read_restart_marker; + /* Initialize COM/APPn processing. + * By default, we examine and then discard APP0 and APP14, + * but simply discard COM and all other APPn. + */ + marker->process_COM = skip_variable; + marker->length_limit_COM = 0; + for (i = 0; i < 16; i++) { + marker->process_APPn[i] = skip_variable; + marker->length_limit_APPn[i] = 0; + } + marker->process_APPn[0] = get_interesting_appn; + marker->process_APPn[14] = get_interesting_appn; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} + + +/* + * Control saving of COM and APPn markers into marker_list. + */ + +#ifdef SAVE_MARKERS_SUPPORTED + +GLOBAL(void) +jpeg_save_markers (j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + long maxlength; + jpeg_marker_parser_method processor; + + /* Length limit mustn't be larger than what we can allocate + * (should only be a concern in a 16-bit environment). + */ + maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct); + if (((long) length_limit) > maxlength) + length_limit = (unsigned int) maxlength; + + /* Choose processor routine to use. + * APP0/APP14 have special requirements. + */ + if (length_limit) { + processor = save_marker; + /* If saving APP0/APP14, save at least enough for our internal use. */ + if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN) + length_limit = APP0_DATA_LEN; + else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN) + length_limit = APP14_DATA_LEN; + } else { + processor = skip_variable; + /* If discarding APP0/APP14, use our regular on-the-fly processor. */ + if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14) + processor = get_interesting_appn; + } + + if (marker_code == (int) M_COM) { + marker->process_COM = processor; + marker->length_limit_COM = length_limit; + } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) { + marker->process_APPn[marker_code - (int) M_APP0] = processor; + marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit; + } else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +/* + * Install a special processing method for COM or APPn markers. + */ + +GLOBAL(void) +jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + if (marker_code == (int) M_COM) + marker->process_COM = routine; + else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) + marker->process_APPn[marker_code - (int) M_APP0] = routine; + else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdmaster.c b/widget/milsko/milskosrc/external/libjpeg/src/jdmaster.c new file mode 100644 index 0000000000..3070b7bb41 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdmaster.c @@ -0,0 +1,532 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2002-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL(boolean) +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling. */ + /* The following condition is only needed if fancy shall select + * a different upsampling method. In our current implementation + * fancy only affects the DCT scaling, thus we can use fancy + * upsampling and merged upsample simultaneously, in particular + * with scaled DCT sizes larger than the default DCTSIZE. + */ +#if 0 + if (cinfo->do_fancy_upsampling) + return FALSE; +#endif + if (cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if ((cinfo->jpeg_color_space != JCS_YCbCr && + cinfo->jpeg_color_space != JCS_BG_YCC) || + cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE || + cinfo->color_transform) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if we've scaled the IDCTs differently */ + if (cinfo->comp_info[0].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || + cinfo->comp_info[1].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || + cinfo->comp_info[2].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || + cinfo->comp_info[0].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size || + cinfo->comp_info[1].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size || + cinfo->comp_info[2].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL(void) +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase. + * This function is used for full decompression. + */ +{ + int ci, i; + jpeg_component_info *compptr; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Compute core output image dimensions and DCT scaling choices. */ + jpeg_core_output_dimensions(cinfo); + +#ifdef IDCT_SCALING_SUPPORTED + + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code adapts subsampling ratios which are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = 1; + if (! cinfo->raw_data_out) + while (cinfo->min_DCT_h_scaled_size * ssize <= + (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) && + (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == + 0) { + ssize = ssize * 2; + } + compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize; + ssize = 1; + if (! cinfo->raw_data_out) + while (cinfo->min_DCT_v_scaled_size * ssize <= + (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) && + (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == + 0) { + ssize = ssize * 2; + } + compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize; + + /* We don't support IDCT ratios larger than 2. */ + if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2) + compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2; + else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2) + compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2; + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size), + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size), + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + } + +#endif /* IDCT_SCALING_SUPPORTED */ + + /* Report number of components in selected colorspace. */ + /* This should correspond to the actual code in the color conversion module. */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: + case JCS_BG_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + break; + default: /* YCCK <=> CMYK conversion or same colorspace as in file */ + i = 0; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) + if (compptr->component_needed) + i++; /* count output color components */ + cinfo->out_color_components = i; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within 2*(MAXJSAMPLE+1) of the legal range, so a table running + * from -2*(MAXJSAMPLE+1) to 3*MAXJSAMPLE+2 is sufficient. But for the + * initial limiting step (just after the IDCT), a wildly out-of-range value + * is possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = (sample_range_limit - SUBSET)[(x + CENTER) & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * This is accomplished with SUBSET = CENTER - CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL(void) +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, + JPOOL_IMAGE, (RANGE_CENTER * 2 + MAXJSAMPLE + 1) * SIZEOF(JSAMPLE)); + /* First segment of range limit table: limit[x] = 0 for x < 0 */ + MEMZERO(table, RANGE_CENTER * SIZEOF(JSAMPLE)); + table += RANGE_CENTER; /* allow negative subscripts of table */ + cinfo->sample_range_limit = table; + /* Main part of range limit table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + /* End of range limit table: limit[x] = MAXJSAMPLE for x > MAXJSAMPLE */ + for (; i <= MAXJSAMPLE + RANGE_CENTER; i++) + table[i] = MAXJSAMPLE; +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL(void) +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + boolean use_c_buffer; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Sanity check on image dimensions */ + if (cinfo->output_height <= 0 || cinfo->output_width <= 0 || + cinfo->out_color_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) + jinit_arith_decoder(cinfo); + else { + jinit_huff_decoder(cinfo); + } + + /* Initialize principal buffer controllers. */ + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapistd.c will crank the pass to completion.) + */ + +METHODDEF(void) +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->idct->start_pass) (cinfo); + (*cinfo->coef->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF(void) +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL(void) +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL(void) +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_decomp_master)); + cinfo->master = &master->pub; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdmerge.c b/widget/milsko/milskosrc/external/libjpeg/src/jdmerge.c new file mode 100644 index 0000000000..0d16821bed --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdmerge.c @@ -0,0 +1,437 @@ +/* + * jdmerge.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2013-2022 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains code for merged upsampling/color conversion. + * + * This file combines functions from jdsample.c and jdcolor.c; + * read those files first to understand what's going on. + * + * When the chroma components are to be upsampled by simple replication + * (ie, box filtering), we can save some work in color conversion by + * calculating all the output pixels corresponding to a pair of chroma + * samples at one time. In the conversion equations + * R = Y + K1 * Cr + * G = Y + K2 * Cb + K3 * Cr + * B = Y + K4 * Cb + * only the Y term varies among the group of pixels corresponding to a pair + * of chroma samples, so the rest of the terms can be calculated just once. + * At typical sampling ratios, this eliminates half or three-quarters + * of the multiplications needed for color conversion. + * + * This file currently provides implementations for the following cases: + * YCC => RGB color conversion only (YCbCr or BG_YCC). + * Sampling ratios of 2h1v or 2h2v. + * No scaling needed at upsample time. + * Corner-aligned (non-CCIR601) sampling alignment. + * Other special cases could be added, but in most applications these + * are the only common cases. (For uncommon cases we fall back on + * the more general code in jdsample.c and jdcolor.c.) + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef UPSAMPLE_MERGING_SUPPORTED + + +#if RANGE_BITS < 2 + /* Deliberate syntax err */ + Sorry, this code requires 2 or more range extension bits. +#endif + + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Pointer to routine to do actual upsampling/conversion of one row group */ + JMETHOD(void, upmethod, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf)); + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* For 2:1 vertical sampling, we produce two output rows at a time. + * We need a "spare" row buffer to hold the second output row if the + * application provides just a one-row buffer; we also use the spare + * to discard the dummy last row if the image height is odd. + */ + JSAMPROW spare_row; + boolean spare_full; /* T if spare buffer is occupied */ + + JDIMENSION out_row_width; /* samples per output row */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB and BG_YCC->RGB colorspace conversion. + * This is taken directly from jdcolor.c; see that file for more info. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +/* Normal case, sYCC */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i; + INT32 x; + SHIFT_TEMPS + + upsample->Cr_r_tab = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cb_b_tab = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + upsample->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.402 * x */ + upsample->Cr_r_tab[i] = (int) DESCALE(FIX(1.402) * x, SCALEBITS); + /* Cb=>B value is nearest int to 1.772 * x */ + upsample->Cb_b_tab[i] = (int) DESCALE(FIX(1.772) * x, SCALEBITS); + /* Cr=>G value is scaled-up -0.714136286 * x */ + upsample->Cr_g_tab[i] = (- FIX(0.714136286)) * x; + /* Cb=>G value is scaled-up -0.344136286 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + upsample->Cb_g_tab[i] = (- FIX(0.344136286)) * x + ONE_HALF; + } +} + + +LOCAL(void) +build_bg_ycc_rgb_table (j_decompress_ptr cinfo) +/* Wide gamut case, bg-sYCC */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i; + INT32 x; + SHIFT_TEMPS + + upsample->Cr_r_tab = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cb_b_tab = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + upsample->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 2.804 * x */ + upsample->Cr_r_tab[i] = (int) DESCALE(FIX(2.804) * x, SCALEBITS); + /* Cb=>B value is nearest int to 3.544 * x */ + upsample->Cb_b_tab[i] = (int) DESCALE(FIX(3.544) * x, SCALEBITS); + /* Cr=>G value is scaled-up -1.428272572 * x */ + upsample->Cr_g_tab[i] = (- FIX(1.428272572)) * x; + /* Cb=>G value is scaled-up -0.688272572 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + upsample->Cb_g_tab[i] = (- FIX(0.688272572)) * x + ONE_HALF; + } +} + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_merged_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the spare buffer empty */ + upsample->spare_full = FALSE; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * The control routine just handles the row buffering considerations. + */ + +METHODDEF(void) +merged_2v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 2:1 vertical sampling case: may need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ + + if (upsample->spare_full) { + /* If we have a spare row saved from a previous cycle, just return it. */ + jcopy_sample_rows(& upsample->spare_row, output_buf + *out_row_ctr, + 1, upsample->out_row_width); + num_rows = 1; + upsample->spare_full = FALSE; + } else { + /* Figure number of rows to return to caller. */ + num_rows = 2; + /* Not more than the distance to the end of the image. */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + /* Create output pointer array for upsampler. */ + work_ptrs[0] = output_buf[*out_row_ctr]; + if (num_rows > 1) { + work_ptrs[1] = output_buf[*out_row_ctr + 1]; + } else { + work_ptrs[1] = upsample->spare_row; + upsample->spare_full = TRUE; + } + /* Now do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); + } + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (! upsample->spare_full) + (*in_row_group_ctr)++; +} + + +METHODDEF(void) +merged_1v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 1:1 vertical sampling case: much easier, never need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Just do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, + output_buf + *out_row_ctr); + /* Adjust counts */ + (*out_row_ctr)++; + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by the control routines to do + * the actual upsampling/conversion. One row group is processed per call. + * + * Note: since we may be writing directly into application-supplied buffers, + * we have to be honest about the output width; we can't assume the buffer + * has been rounded up to an even width. + */ + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. + */ + +METHODDEF(void) +h2v1_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + cred = Crrtab[cr]; + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + y = GETJSAMPLE(*inptr0); + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + } +} + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. + */ + +METHODDEF(void) +h2v2_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + cred = Crrtab[cr]; + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + cred = Crrtab[cr]; + y = GETJSAMPLE(*inptr00); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + y = GETJSAMPLE(*inptr01); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Module initialization routine for merged upsampling/color conversion. + * + * NB: this is called under the conditions determined by use_merged_upsample() + * in jdmaster.c. That routine MUST correspond to the actual capabilities + * of this module; no safety checks are made here. + */ + +GLOBAL(void) +jinit_merged_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + + upsample = (my_upsample_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_upsampler)); + cinfo->upsample = &upsample->pub; + upsample->pub.start_pass = start_pass_merged_upsample; + upsample->pub.need_context_rows = FALSE; + + upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; + + if (cinfo->max_v_samp_factor == 2) { + upsample->pub.upsample = merged_2v_upsample; + upsample->upmethod = h2v2_merged_upsample; + /* Allocate a spare row buffer */ + upsample->spare_row = (JSAMPROW) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) upsample->out_row_width * SIZEOF(JSAMPLE)); + } else { + upsample->pub.upsample = merged_1v_upsample; + upsample->upmethod = h2v1_merged_upsample; + /* No spare row needed */ + upsample->spare_row = NULL; + } + + if (cinfo->jpeg_color_space == JCS_BG_YCC) + build_bg_ycc_rgb_table(cinfo); + else + build_ycc_rgb_table(cinfo); +} + +#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdpostct.c b/widget/milsko/milskosrc/external/libjpeg/src/jdpostct.c new file mode 100644 index 0000000000..571563d728 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdpostct.c @@ -0,0 +1,290 @@ +/* + * jdpostct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the decompression postprocessing controller. + * This controller manages the upsampling, color conversion, and color + * quantization/reduction steps; specifically, it controls the buffering + * between upsample/color conversion and color quantization/reduction. + * + * If no color quantization/reduction is required, then this module has no + * work to do, and it just hands off to the upsample/color conversion code. + * An integrated upsample/convert/quantize process would replace this module + * entirely. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_post_controller pub; /* public fields */ + + /* Color quantization source buffer: this holds output data from + * the upsample/color conversion step to be passed to the quantizer. + * For two-pass color quantization, we need a full-image buffer; + * for one-pass operation, a strip buffer is sufficient. + */ + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + JDIMENSION strip_height; /* buffer size in rows */ + /* for two-pass mode only: */ + JDIMENSION starting_row; /* row # of first row in current strip */ + JDIMENSION next_row; /* index of next row to fill/empty in strip */ +} my_post_controller; + +typedef my_post_controller * my_post_ptr; + + +/* Forward declarations */ +METHODDEF(void) post_process_1pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) post_process_prepass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +METHODDEF(void) post_process_2pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->quantize_colors) { + /* Single-pass processing with color quantization. */ + post->pub.post_process_data = post_process_1pass; + /* We could be doing buffered-image output before starting a 2-pass + * color quantization; in that case, jinit_d_post_controller did not + * allocate a strip buffer. Use the virtual-array buffer as workspace. + */ + if (post->buffer == NULL) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + (JDIMENSION) 0, post->strip_height, TRUE); + } + } else { + /* For single-pass processing without color quantization, + * I have no work to do; just call the upsampler directly. + */ + post->pub.post_process_data = cinfo->upsample->upsample; + } + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_SAVE_AND_PASS: + /* First pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_prepass; + break; + case JBUF_CRANK_DEST: + /* Second pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_2pass; + break; +#endif /* QUANT_2PASS_SUPPORTED */ + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } + post->starting_row = post->next_row = 0; +} + + +/* + * Process some data in the one-pass (strip buffer) case. + * This is used for color precision reduction as well as one-pass quantization. + */ + +METHODDEF(void) +post_process_1pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Fill the buffer, but not more than what we can dump out in one go. */ + /* Note we rely on the upsampler to detect bottom of image. */ + max_rows = out_rows_avail - *out_row_ctr; + if (max_rows > post->strip_height) + max_rows = post->strip_height; + num_rows = 0; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &num_rows, max_rows); + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + *out_row_ctr += num_rows; +} + + +#ifdef QUANT_2PASS_SUPPORTED + +/* + * Process some data in the first pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_prepass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, TRUE); + } + + /* Upsample some data (up to a strip height's worth). */ + old_next_row = post->next_row; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &post->next_row, post->strip_height); + + /* Allow quantizer to scan new data. No data is emitted, */ + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + if (post->next_row > old_next_row) { + num_rows = post->next_row - old_next_row; + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + (JSAMPARRAY) NULL, (int) num_rows); + *out_row_ctr += num_rows; + } + + /* Advance if we filled the strip. */ + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + + +/* + * Process some data in the second pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_2pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, FALSE); + } + + /* Determine number of rows to emit. */ + num_rows = post->strip_height - post->next_row; /* available in strip */ + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + if (num_rows > max_rows) + num_rows = max_rows; + /* We have to check bottom of image here, can't depend on upsampler. */ + max_rows = cinfo->output_height - post->starting_row; + if (num_rows > max_rows) + num_rows = max_rows; + + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer + post->next_row, output_buf + *out_row_ctr, + (int) num_rows); + *out_row_ctr += num_rows; + + /* Advance if we filled the strip. */ + post->next_row += num_rows; + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize postprocessing controller. + */ + +GLOBAL(void) +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_post_ptr post; + + post = (my_post_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_post_controller)); + cinfo->post = (struct jpeg_d_post_controller *) post; + post->pub.start_pass = start_pass_dpost; + post->whole_image = NULL; /* flag for no virtual arrays */ + post->buffer = NULL; /* flag for no strip buffer */ + + /* Create the quantization buffer, if needed */ + if (cinfo->quantize_colors) { + /* The buffer strip height is max_v_samp_factor, which is typically + * an efficient number of rows for upsampling to return. + * (In the presence of output rescaling, we might want to be smarter?) + */ + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + if (need_full_buffer) { + /* Two-pass color quantization: need full-image storage. */ + /* We round up the number of rows to a multiple of the strip height. */ +#ifdef QUANT_2PASS_SUPPORTED + post->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + cinfo->output_width * cinfo->out_color_components, + (JDIMENSION) jround_up((long) cinfo->output_height, + (long) post->strip_height), + post->strip_height); +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + /* One-pass color quantization: just make a strip buffer. */ + post->buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->out_color_components, + post->strip_height); + } + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdsample.c b/widget/milsko/milskosrc/external/libjpeg/src/jdsample.c new file mode 100644 index 0000000000..15afeafe3d --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdsample.c @@ -0,0 +1,341 @@ +/* + * jdsample.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2002-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains upsampling routines. + * + * Upsampling input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size) + * sample rows of each component. Upsampling will normally produce + * max_v_samp_factor pixel rows from each row group (but this could vary + * if the upsampler is applying a scale factor of its own). + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to upsample a single component */ +typedef JMETHOD(void, upsample1_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr)); + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Color conversion buffer. When using separate upsampling and color + * conversion steps, this buffer holds one upsampled row group until it + * has been color converted and output. + * Note: we do not allocate any storage for component(s) which are full-size, + * ie do not need rescaling. The corresponding entry of color_buf[] is + * simply set to point to the input data array, thereby avoiding copying. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + /* Per-component upsampling method pointers */ + upsample1_ptr methods[MAX_COMPONENTS]; + + int next_row_out; /* counts rows emitted from color_buf */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + /* Height of an input row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_expand need not + * recompute them each time. They are unused for other upsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the conversion buffer empty */ + upsample->next_row_out = cinfo->max_v_samp_factor; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * In this version we upsample each component independently. + * We upsample one row group into the conversion buffer, then apply + * color conversion a row at a time. + */ + +METHODDEF(void) +sep_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; + JDIMENSION num_rows; + + /* Fill the conversion buffer, if it's empty */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to upsample an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Invoke per-component upsample method. Notice we pass a POINTER + * to color_buf[ci], so that fullsize_upsample can change it. + */ + (*upsample->methods[ci]) (cinfo, compptr, + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + upsample->color_buf + ci); + } + upsample->next_row_out = 0; + } + + /* Color-convert and emit rows */ + + /* How many we have in the buffer: */ + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + /* Not more than the distance to the end of the image. Need this test + * in case the image height is not a multiple of max_v_samp_factor: + */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + (JDIMENSION) upsample->next_row_out, + output_buf + *out_row_ctr, + (int) num_rows); + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + upsample->next_row_out += num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by sep_upsample to upsample pixel values + * of a single component. One row group is processed per call. + */ + + +/* + * For full-size components, we just make color_buf[ci] point at the + * input buffer, and thus avoid copying any data. Note that this is + * safe only because sep_upsample doesn't declare the input row group + * "consumed" until we are done color converting and emitting it. + */ + +METHODDEF(void) +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr) +{ + *output_data_ptr = input_data; +} + + +/* + * This version handles any integral sampling ratios. + * This is not used for typical JPEG files, so it need not be fast. + * Nor, for that matter, is it particularly accurate: the algorithm is + * simple replication of the input pixel onto the corresponding output + * pixels. The hi-falutin sampling literature refers to this as a + * "box filter". A box filter tends to introduce visible artifacts, + * so if you are actually going to use 3:1 or 4:1 sampling ratios + * you would be well advised to improve this code. + */ + +METHODDEF(void) +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPARRAY output_data, output_end; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + register int h; + JSAMPROW outend; + int h_expand, v_expand; + + h_expand = upsample->h_expand[compptr->component_index]; + v_expand = upsample->v_expand[compptr->component_index]; + + output_data = *output_data_ptr; + output_end = output_data + cinfo->max_v_samp_factor; + for (; output_data < output_end; output_data += v_expand) { + /* Generate one output row with proper horizontal expansion */ + inptr = *input_data++; + outptr = *output_data; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + for (h = h_expand; h > 0; h--) { + *outptr++ = invalue; + } + } + /* Generate any additional output rows by duplicating the first one */ + if (v_expand > 1) { + jcopy_sample_rows(output_data, output_data + 1, + v_expand - 1, cinfo->output_width); + } + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int outrow; + + for (outrow = 0; outrow < cinfo->max_v_samp_factor; outrow++) { + inptr = input_data[outrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr) +{ + JSAMPARRAY output_data, output_end; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + + output_data = *output_data_ptr; + output_end = output_data + cinfo->max_v_samp_factor; + for (; output_data < output_end; output_data += 2) { + inptr = *input_data++; + outptr = *output_data; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + jcopy_sample_rows(output_data, output_data + 1, + 1, cinfo->output_width); + } +} + + +/* + * Module initialization routine for upsampling. + */ + +GLOBAL(void) +jinit_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + int ci; + jpeg_component_info * compptr; + int h_in_group, v_in_group, h_out_group, v_out_group; + + upsample = (my_upsample_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_upsampler)); + cinfo->upsample = &upsample->pub; + upsample->pub.start_pass = start_pass_upsample; + upsample->pub.upsample = sep_upsample; + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, select per-component methods, + * and create storage as needed. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to upsample an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Compute size of an "input group" after IDCT scaling. This many samples + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + */ + h_in_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) / + cinfo->min_DCT_h_scaled_size; + v_in_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; + h_out_group = cinfo->max_h_samp_factor; + v_out_group = cinfo->max_v_samp_factor; + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + if (h_in_group == h_out_group && v_in_group == v_out_group) { + /* Fullsize components can be processed without any work. */ + upsample->methods[ci] = fullsize_upsample; + continue; /* don't need to allocate buffer */ + } + if (h_in_group * 2 == h_out_group && v_in_group == v_out_group) { + /* Special case for 2h1v upsampling */ + upsample->methods[ci] = h2v1_upsample; + } else if (h_in_group * 2 == h_out_group && + v_in_group * 2 == v_out_group) { + /* Special case for 2h2v upsampling */ + upsample->methods[ci] = h2v2_upsample; + } else if ((h_out_group % h_in_group) == 0 && + (v_out_group % v_in_group) == 0) { + /* Generic integral-factors upsampling method */ + upsample->methods[ci] = int_upsample; + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) cinfo->output_width, + (long) cinfo->max_h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jdtrans.c b/widget/milsko/milskosrc/external/libjpeg/src/jdtrans.c new file mode 100644 index 0000000000..22dd47fb5c --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jdtrans.c @@ -0,0 +1,140 @@ +/* + * jdtrans.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * Modified 2000-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding decompression, + * that is, reading raw DCT coefficient arrays from an input JPEG file. + * The routines in jdapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + +/* + * Read the coefficient arrays from a JPEG file. + * jpeg_read_header must be completed before calling this. + * + * The entire image is read into a set of virtual coefficient-block arrays, + * one per component. The return value is a pointer to the array of + * virtual-array descriptors. These can be manipulated directly via the + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + * To release the memory occupied by the virtual arrays, call + * jpeg_finish_decompress() when done with the data. + * + * An alternative usage is to simply obtain access to the coefficient arrays + * during a buffered-image-mode decompression operation. This is allowed + * after any jpeg_finish_output() call. The arrays can be accessed until + * jpeg_finish_decompress() is called. (Note that any call to the library + * may reposition the arrays, so don't rely on access_virt_barray() results + * to stay valid across library calls.) + * + * Returns NULL if suspended. This case need be checked only if + * a suspending data source is used. + */ + +GLOBAL(jvirt_barray_ptr *) +jpeg_read_coefficients (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return NULL; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return cinfo->coef->coef_arrays; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return NULL; /* keep compiler happy */ +} + + +/* + * Master selection of decompression modules for transcoding. + * This substitutes for jdmaster.c's initialization of the full decompressor. + */ + +LOCAL(void) +transdecode_master_selection (j_decompress_ptr cinfo) +{ + /* This is effectively a buffered-image operation. */ + cinfo->buffered_image = TRUE; + + /* Compute output image dimensions and related values. */ + jpeg_core_output_dimensions(cinfo); + + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) + jinit_arith_decoder(cinfo); + else { + jinit_huff_decoder(cinfo); + } + + /* Always get a full-image coefficient buffer. */ + jinit_d_coef_controller(cinfo, TRUE); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + + /* Initialize progress monitoring. */ + if (cinfo->progress != NULL) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else if (cinfo->inputctl->has_multiple_scans) { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } else { + nscans = 1; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = 1; + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jerror.c b/widget/milsko/milskosrc/external/libjpeg/src/jerror.c new file mode 100644 index 0000000000..7163af699c --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jerror.c @@ -0,0 +1,253 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2012-2015 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile, + * you get a Windows-specific hack to display error messages in a dialog box. + * It ain't much, but it beats dropping error messages into the bit bucket, + * which is what happens to output to stderr under most Windows C compilers. + * + * These routines are used by both the compression and decompression code. + */ + +#ifdef USE_WINDOWS_MESSAGEBOX +#include +#endif + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF(noreturn_t) +error_exit (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + exit(EXIT_FAILURE); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + * + * On Windows, printing to stderr is generally completely useless, + * so we provide optional code to produce an error-dialog popup. + * Most Windows applications will still prefer to override this routine, + * but if they don't, it'll do something at least marginally useful. + * + * NOTE: to use the library in an environment that doesn't support the + * C stdio library, you may have to delete the call to fprintf() entirely, + * not just not use this routine. + */ + +METHODDEF(void) +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + +#ifdef USE_WINDOWS_MESSAGEBOX + /* Display it in a message dialog box */ + MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", + MB_OK | MB_ICONERROR); +#else + /* Send it to stderr, adding a newline */ + fprintf(stderr, "%s\n", buffer); +#endif +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF(void) +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF(void) +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF(void) +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL(struct jpeg_error_mgr *) +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jfdctflt.c b/widget/milsko/milskosrc/external/libjpeg/src/jfdctflt.c new file mode 100644 index 0000000000..013f29e0ca --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jfdctflt.c @@ -0,0 +1,176 @@ +/* + * jfdctflt.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2003-2017 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * forward DCT (Discrete Cosine Transform). + * + * This implementation should be more accurate than either of the integer + * DCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ +#endif + + +/* + * Perform the forward DCT on one block of samples. + * + * cK represents cos(K*pi/16). + */ + +GLOBAL(void) +jpeg_fdct_float (FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + FAST_FLOAT *dataptr; + JSAMPROW elemptr; + int ctr; + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Load data into workspace */ + tmp0 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7])); + tmp7 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7])); + tmp1 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6])); + tmp6 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6])); + tmp2 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5])); + tmp5 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5])); + tmp3 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4])); + tmp4 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4])); + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Apply unsigned->signed conversion. */ + dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jfdctfst.c b/widget/milsko/milskosrc/external/libjpeg/src/jfdctfst.c new file mode 100644 index 0000000000..5e4e017225 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jfdctfst.c @@ -0,0 +1,232 @@ +/* + * jfdctfst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2003-2017 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jfdctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * Again to save a few shifts, the intermediate results between pass 1 and + * pass 2 are not upscaled, but are represented only to integral precision. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#define CONST_BITS 8 + + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */ +#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */ +#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */ +#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */ +#else +#define FIX_0_382683433 FIX(0.382683433) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_707106781 FIX(0.707106781) +#define FIX_1_306562965 FIX(1.306562965) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* + * Perform the forward DCT on one block of samples. + * + * cK represents cos(K*pi/16). + */ + +GLOBAL(void) +jpeg_fdct_ifast (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z1, z2, z3, z4, z5, z11, z13; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Load data into workspace */ + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]); + tmp7 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]); + tmp6 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]); + tmp5 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]); + tmp4 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]); + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Apply unsigned->signed conversion. */ + dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jfdctint.c b/widget/milsko/milskosrc/external/libjpeg/src/jfdctint.c new file mode 100644 index 0000000000..05df4750bb --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jfdctint.c @@ -0,0 +1,4415 @@ +/* + * jfdctint.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modification developed 2003-2018 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + * + * We also provide FDCT routines with various input sample block sizes for + * direct resolution reduction or enlargement and for direct resolving the + * common 2x1 and 1x2 subsampling cases without additional resampling: NxN + * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 output DCT block. + * + * For N<8 we fill the remaining block coefficients with zero. + * For N>8 we apply a partial N-point FDCT on the input samples, computing + * just the lower 8 frequency coefficients and discarding the rest. + * + * We must scale the output coefficients of the N-point FDCT appropriately + * to the standard 8-point FDCT level by 8/N per 1-D pass. This scaling + * is folded into the constant multipliers (pass 2) and/or final/initial + * shifting. + * + * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases + * since there would be too many additional constants to pre-calculate. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D DCT step produces outputs which are a factor of sqrt(N) + * larger than the true DCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D DCT, + * because the y0 and y4 outputs need not be divided by sqrt(N). + * In the IJG code, this factor of 8 is removed by the quantization step + * (in jcdctmgr.c), NOT in this module. + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (For 12-bit sample data, the intermediate + * array is INT32 anyway.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_islow (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * cK represents sqrt(2) * cos(K*pi/16). + */ + + dataptr = data; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "c1" should be "c6". + */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]); + + tmp10 = tmp0 + tmp3; + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + + dataptr[2] = (DCTELEM) + RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* -c3+c5 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + tmp12 += z1; + tmp13 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp0 += z1 + tmp12; + tmp3 += z1 + tmp13; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp1 += z1 + tmp13; + tmp2 += z1 + tmp12; + + dataptr[1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * cK represents sqrt(2) * cos(K*pi/16). + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "c1" should be "c6". + */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + + /* Add fudge factor here for final descale. */ + tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1)); + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS+PASS1_BITS-1); + + dataptr[DCTSIZE*2] = (DCTELEM) + RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */ + CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS+PASS1_BITS-1); + + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* -c3+c5 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + tmp12 += z1; + tmp13 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp0 += z1 + tmp12; + tmp3 += z1 + tmp13; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp1 += z1 + tmp13; + tmp2 += z1 + tmp12; + + dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + +#ifdef DCT_SCALING_SUPPORTED + + +/* + * Perform the forward DCT on a 7x7 sample block. + */ + +GLOBAL(void) +jpeg_fdct_7x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * cK represents sqrt(2) * cos(K*pi/14). + */ + + dataptr = data; + for (ctr = 0; ctr < 7; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]); + tmp3 = GETJSAMPLE(elemptr[3]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]); + + z1 = tmp0 + tmp2; + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS); + tmp3 += tmp3; + z1 -= tmp3; + z1 -= tmp3; + z1 = MULTIPLY(z1, FIX(0.353553391)); /* (c2+c6-c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002)); /* (c2+c4-c6)/2 */ + z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123)); /* c6 */ + dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS); + z1 -= z2; + z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734)); /* c4 */ + dataptr[4] = (DCTELEM) + DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */ + tmp1 += tmp2; + tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268)); /* c5 */ + tmp0 += tmp3; + tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693)); /* c3+c1-c5 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/7)**2 = 64/49, which we fold + * into the constant multipliers: + * cK now represents sqrt(2) * cos(K*pi/14) * 64/49. + */ + + dataptr = data; + for (ctr = 0; ctr < 7; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4]; + tmp3 = dataptr[DCTSIZE*3]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5]; + tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4]; + + z1 = tmp0 + tmp2; + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */ + CONST_BITS+PASS1_BITS); + tmp3 += tmp3; + z1 -= tmp3; + z1 -= tmp3; + z1 = MULTIPLY(z1, FIX(0.461784020)); /* (c2+c6-c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084)); /* (c2+c4-c6)/2 */ + z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS); + z1 -= z2; + z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509)); /* c4 */ + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */ + tmp1 += tmp2; + tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310)); /* c5 */ + tmp0 += tmp3; + tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355)); /* c3+c1-c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 6x6 sample block. + */ + +GLOBAL(void) +jpeg_fdct_6x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + INT32 tmp10, tmp11, tmp12; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * cK represents sqrt(2) * cos(K*pi/12). + */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]); + tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */ + CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */ + CONST_BITS-PASS1_BITS); + + dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS)); + dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS); + dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS)); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/6)**2 = 16/9, which we fold + * into the constant multipliers: + * cK now represents sqrt(2) * cos(K*pi/12) * 16/9. + */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5]; + tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3]; + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 5x5 sample block. + */ + +GLOBAL(void) +jpeg_fdct_5x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + INT32 tmp10, tmp11; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * We scale the results further by 2 as part of output adaption + * scaling for different DCT size. + * cK represents sqrt(2) * cos(K*pi/10). + */ + + dataptr = data; + for (ctr = 0; ctr < 5; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]); + tmp2 = GETJSAMPLE(elemptr[2]); + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << (PASS1_BITS+1)); + tmp11 = MULTIPLY(tmp11, FIX(0.790569415)); /* (c2+c4)/2 */ + tmp10 -= tmp2 << 2; + tmp10 = MULTIPLY(tmp10, FIX(0.353553391)); /* (c2-c4)/2 */ + dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS-1); + dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS-1); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876)); /* c3 */ + + dataptr[1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */ + CONST_BITS-PASS1_BITS-1); + dataptr[3] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */ + CONST_BITS-PASS1_BITS-1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/5)**2 = 64/25, which we partially + * fold into the constant multipliers (other part was done in pass 1): + * cK now represents sqrt(2) * cos(K*pi/10) * 32/25. + */ + + dataptr = data; + for (ctr = 0; ctr < 5; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3]; + tmp2 = dataptr[DCTSIZE*2]; + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)), /* 32/25 */ + CONST_BITS+PASS1_BITS); + tmp11 = MULTIPLY(tmp11, FIX(1.011928851)); /* (c2+c4)/2 */ + tmp10 -= tmp2 << 2; + tmp10 = MULTIPLY(tmp10, FIX(0.452548340)); /* (c2-c4)/2 */ + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961)); /* c3 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 4x4 sample block. + */ + +GLOBAL(void) +jpeg_fdct_4x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1; + INT32 tmp10, tmp11; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * We must also scale the output by (8/4)**2 = 2**2, which we add here. + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. + */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+2)); + dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+2)); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-3); + + dataptr[1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS-2); + dataptr[3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS-2); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. + */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1)); + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS+PASS1_BITS-1); + + dataptr[DCTSIZE*1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 3x3 sample block. + */ + +GLOBAL(void) +jpeg_fdct_3x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * We scale the results further by 2**2 as part of output adaption + * scaling for different DCT size. + * cK represents sqrt(2) * cos(K*pi/6). + */ + + dataptr = data; + for (ctr = 0; ctr < 3; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]); + tmp1 = GETJSAMPLE(elemptr[1]); + + tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+2)); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */ + CONST_BITS-PASS1_BITS-2); + + /* Odd part */ + + dataptr[1] = (DCTELEM) + DESCALE(MULTIPLY(tmp2, FIX(1.224744871)), /* c1 */ + CONST_BITS-PASS1_BITS-2); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/3)**2 = 64/9, which we partially + * fold into the constant multipliers (other part was done in pass 1): + * cK now represents sqrt(2) * cos(K*pi/6) * 16/9. + */ + + dataptr = data; + for (ctr = 0; ctr < 3; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2]; + tmp1 = dataptr[DCTSIZE*1]; + + tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(MULTIPLY(tmp2, FIX(2.177324216)), /* c1 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 2x2 sample block. + */ + +GLOBAL(void) +jpeg_fdct_2x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3; + JSAMPROW elemptr; + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT. + */ + + /* Row 0 */ + elemptr = sample_data[0] + start_col; + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]); + tmp1 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]); + + /* Row 1 */ + elemptr = sample_data[1] + start_col; + + tmp2 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]); + tmp3 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]); + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/2)**2 = 2**4. + */ + + /* Column 0 */ + /* Apply unsigned->signed conversion. */ + data[DCTSIZE*0] = (tmp0 + tmp2 - 4 * CENTERJSAMPLE) << 4; + data[DCTSIZE*1] = (tmp0 - tmp2) << 4; + + /* Column 1 */ + data[DCTSIZE*0+1] = (tmp1 + tmp3) << 4; + data[DCTSIZE*1+1] = (tmp1 - tmp3) << 4; +} + + +/* + * Perform the forward DCT on a 1x1 sample block. + */ + +GLOBAL(void) +jpeg_fdct_1x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + DCTELEM dcval; + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + dcval = GETJSAMPLE(sample_data[0][start_col]); + + /* We leave the result scaled up by an overall factor of 8. */ + /* We must also scale the output by (8/1)**2 = 2**6. */ + /* Apply unsigned->signed conversion. */ + data[0] = (dcval - CENTERJSAMPLE) << 6; +} + + +/* + * Perform the forward DCT on a 9x9 sample block. + */ + +GLOBAL(void) +jpeg_fdct_9x9 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2; + DCTELEM workspace[8]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * we scale the results further by 2 as part of output adaption + * scaling for different DCT size. + * cK represents sqrt(2) * cos(K*pi/18). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[8]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[7]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[6]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[5]); + tmp4 = GETJSAMPLE(elemptr[4]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[8]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[7]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[6]); + tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[5]); + + z1 = tmp0 + tmp2 + tmp3; + z2 = tmp1 + tmp4; + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) ((z1 + z2 - 9 * CENTERJSAMPLE) << 1); + dataptr[6] = (DCTELEM) + DESCALE(MULTIPLY(z1 - z2 - z2, FIX(0.707106781)), /* c6 */ + CONST_BITS-1); + z1 = MULTIPLY(tmp0 - tmp2, FIX(1.328926049)); /* c2 */ + z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(0.707106781)); /* c6 */ + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.083350441)) /* c4 */ + + z1 + z2, CONST_BITS-1); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.245575608)) /* c8 */ + + z1 - z2, CONST_BITS-1); + + /* Odd part */ + + dataptr[3] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.224744871)), /* c3 */ + CONST_BITS-1); + + tmp11 = MULTIPLY(tmp11, FIX(1.224744871)); /* c3 */ + tmp0 = MULTIPLY(tmp10 + tmp12, FIX(0.909038955)); /* c5 */ + tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.483689525)); /* c7 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS-1); + + tmp2 = MULTIPLY(tmp12 - tmp13, FIX(1.392728481)); /* c1 */ + + dataptr[5] = (DCTELEM) DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS-1); + dataptr[7] = (DCTELEM) DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS-1); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 9) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/9)**2 = 64/81, which we partially + * fold into the constant multipliers and final/initial shifting: + * cK now represents sqrt(2) * cos(K*pi/18) * 128/81. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*0]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*7]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*6]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*5]; + tmp4 = dataptr[DCTSIZE*4]; + + tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*0]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*7]; + tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*6]; + tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*5]; + + z1 = tmp0 + tmp2 + tmp3; + z2 = tmp1 + tmp4; + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(z1 + z2, FIX(1.580246914)), /* 128/81 */ + CONST_BITS+2); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(MULTIPLY(z1 - z2 - z2, FIX(1.117403309)), /* c6 */ + CONST_BITS+2); + z1 = MULTIPLY(tmp0 - tmp2, FIX(2.100031287)); /* c2 */ + z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(1.117403309)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.711961190)) /* c4 */ + + z1 + z2, CONST_BITS+2); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.388070096)) /* c8 */ + + z1 - z2, CONST_BITS+2); + + /* Odd part */ + + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.935399303)), /* c3 */ + CONST_BITS+2); + + tmp11 = MULTIPLY(tmp11, FIX(1.935399303)); /* c3 */ + tmp0 = MULTIPLY(tmp10 + tmp12, FIX(1.436506004)); /* c5 */ + tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.764348879)); /* c7 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS+2); + + tmp2 = MULTIPLY(tmp12 - tmp13, FIX(2.200854883)); /* c1 */ + + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) + DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 10x10 sample block. + */ + +GLOBAL(void) +jpeg_fdct_10x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + DCTELEM workspace[8*2]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * we scale the results further by 2 as part of output adaption + * scaling for different DCT size. + * cK represents sqrt(2) * cos(K*pi/20). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]); + tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]); + + tmp10 = tmp0 + tmp4; + tmp13 = tmp0 - tmp4; + tmp11 = tmp1 + tmp3; + tmp14 = tmp1 - tmp3; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << 1); + tmp12 += tmp12; + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */ + MULTIPLY(tmp11 - tmp12, FIX(0.437016024)), /* c8 */ + CONST_BITS-1); + tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876)); /* c6 */ + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)), /* c2-c6 */ + CONST_BITS-1); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)), /* c2+c6 */ + CONST_BITS-1); + + /* Odd part */ + + tmp10 = tmp0 + tmp4; + tmp11 = tmp1 - tmp3; + dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << 1); + tmp2 <<= CONST_BITS; + dataptr[1] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) + /* c1 */ + MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 + /* c3 */ + MULTIPLY(tmp3, FIX(0.642039522)) + /* c7 */ + MULTIPLY(tmp4, FIX(0.221231742)), /* c9 */ + CONST_BITS-1); + tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) - /* (c3+c7)/2 */ + MULTIPLY(tmp1 + tmp3, FIX(0.587785252)); /* (c1-c9)/2 */ + tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) + /* (c3-c7)/2 */ + (tmp11 << (CONST_BITS - 1)) - tmp2; + dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-1); + dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-1); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 10) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/10)**2 = 16/25, which we partially + * fold into the constant multipliers and final/initial shifting: + * cK now represents sqrt(2) * cos(K*pi/20) * 32/25. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0]; + tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5]; + + tmp10 = tmp0 + tmp4; + tmp13 = tmp0 - tmp4; + tmp11 = tmp1 + tmp3; + tmp14 = tmp1 - tmp3; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6]; + tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */ + CONST_BITS+2); + tmp12 += tmp12; + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */ + MULTIPLY(tmp11 - tmp12, FIX(0.559380511)), /* c8 */ + CONST_BITS+2); + tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)), /* c2-c6 */ + CONST_BITS+2); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)), /* c2+c6 */ + CONST_BITS+2); + + /* Odd part */ + + tmp10 = tmp0 + tmp4; + tmp11 = tmp1 - tmp3; + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)), /* 32/25 */ + CONST_BITS+2); + tmp2 = MULTIPLY(tmp2, FIX(1.28)); /* 32/25 */ + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) + /* c1 */ + MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 + /* c3 */ + MULTIPLY(tmp3, FIX(0.821810588)) + /* c7 */ + MULTIPLY(tmp4, FIX(0.283176630)), /* c9 */ + CONST_BITS+2); + tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) - /* (c3+c7)/2 */ + MULTIPLY(tmp1 + tmp3, FIX(0.752365123)); /* (c1-c9)/2 */ + tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) + /* (c3-c7)/2 */ + MULTIPLY(tmp11, FIX(0.64)) - tmp2; /* 16/25 */ + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on an 11x11 sample block. + */ + +GLOBAL(void) +jpeg_fdct_11x11 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 z1, z2, z3; + DCTELEM workspace[8*3]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * we scale the results further by 2 as part of output adaption + * scaling for different DCT size. + * cK represents sqrt(2) * cos(K*pi/22). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[10]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[9]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[8]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[7]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[6]); + tmp5 = GETJSAMPLE(elemptr[5]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[10]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[9]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[8]); + tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[7]); + tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[6]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - 11 * CENTERJSAMPLE) << 1); + tmp5 += tmp5; + tmp0 -= tmp5; + tmp1 -= tmp5; + tmp2 -= tmp5; + tmp3 -= tmp5; + tmp4 -= tmp5; + z1 = MULTIPLY(tmp0 + tmp3, FIX(1.356927976)) + /* c2 */ + MULTIPLY(tmp2 + tmp4, FIX(0.201263574)); /* c10 */ + z2 = MULTIPLY(tmp1 - tmp3, FIX(0.926112931)); /* c6 */ + z3 = MULTIPLY(tmp0 - tmp1, FIX(1.189712156)); /* c4 */ + dataptr[2] = (DCTELEM) + DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.018300590)) /* c2+c8-c6 */ + - MULTIPLY(tmp4, FIX(1.390975730)), /* c4+c10 */ + CONST_BITS-1); + dataptr[4] = (DCTELEM) + DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.062335650)) /* c4-c6-c10 */ + - MULTIPLY(tmp2, FIX(1.356927976)) /* c2 */ + + MULTIPLY(tmp4, FIX(0.587485545)), /* c8 */ + CONST_BITS-1); + dataptr[6] = (DCTELEM) + DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.620527200)) /* c2+c4-c6 */ + - MULTIPLY(tmp2, FIX(0.788749120)), /* c8+c10 */ + CONST_BITS-1); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.286413905)); /* c3 */ + tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.068791298)); /* c5 */ + tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.764581576)); /* c7 */ + tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.719967871)) /* c7+c5+c3-c1 */ + + MULTIPLY(tmp14, FIX(0.398430003)); /* c9 */ + tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.764581576)); /* -c7 */ + tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.399818907)); /* -c1 */ + tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.276416582)) /* c9+c7+c1-c3 */ + - MULTIPLY(tmp14, FIX(1.068791298)); /* c5 */ + tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.398430003)); /* c9 */ + tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(1.989053629)) /* c9+c5+c3-c7 */ + + MULTIPLY(tmp14, FIX(1.399818907)); /* c1 */ + tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.305598626)) /* c1+c5-c9-c7 */ + - MULTIPLY(tmp14, FIX(1.286413905)); /* c3 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-1); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-1); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-1); + dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-1); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 11) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/11)**2 = 64/121, which we partially + * fold into the constant multipliers and final/initial shifting: + * cK now represents sqrt(2) * cos(K*pi/22) * 128/121. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*2]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*1]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*0]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*7]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*6]; + tmp5 = dataptr[DCTSIZE*5]; + + tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*2]; + tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*1]; + tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*0]; + tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*7]; + tmp14 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*6]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5, + FIX(1.057851240)), /* 128/121 */ + CONST_BITS+2); + tmp5 += tmp5; + tmp0 -= tmp5; + tmp1 -= tmp5; + tmp2 -= tmp5; + tmp3 -= tmp5; + tmp4 -= tmp5; + z1 = MULTIPLY(tmp0 + tmp3, FIX(1.435427942)) + /* c2 */ + MULTIPLY(tmp2 + tmp4, FIX(0.212906922)); /* c10 */ + z2 = MULTIPLY(tmp1 - tmp3, FIX(0.979689713)); /* c6 */ + z3 = MULTIPLY(tmp0 - tmp1, FIX(1.258538479)); /* c4 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.077210542)) /* c2+c8-c6 */ + - MULTIPLY(tmp4, FIX(1.471445400)), /* c4+c10 */ + CONST_BITS+2); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.065941844)) /* c4-c6-c10 */ + - MULTIPLY(tmp2, FIX(1.435427942)) /* c2 */ + + MULTIPLY(tmp4, FIX(0.621472312)), /* c8 */ + CONST_BITS+2); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.714276708)) /* c2+c4-c6 */ + - MULTIPLY(tmp2, FIX(0.834379234)), /* c8+c10 */ + CONST_BITS+2); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.360834544)); /* c3 */ + tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.130622199)); /* c5 */ + tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.808813568)); /* c7 */ + tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.819470145)) /* c7+c5+c3-c1 */ + + MULTIPLY(tmp14, FIX(0.421479672)); /* c9 */ + tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.808813568)); /* -c7 */ + tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.480800167)); /* -c1 */ + tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.350258864)) /* c9+c7+c1-c3 */ + - MULTIPLY(tmp14, FIX(1.130622199)); /* c5 */ + tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.421479672)); /* c9 */ + tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(2.104122847)) /* c9+c5+c3-c7 */ + + MULTIPLY(tmp14, FIX(1.480800167)); /* c1 */ + tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.381129125)) /* c1+c5-c9-c7 */ + - MULTIPLY(tmp14, FIX(1.360834544)); /* c3 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 12x12 sample block. + */ + +GLOBAL(void) +jpeg_fdct_12x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + DCTELEM workspace[8*4]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT. + * cK represents sqrt(2) * cos(K*pi/24). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]); + + tmp10 = tmp0 + tmp5; + tmp13 = tmp0 - tmp5; + tmp11 = tmp1 + tmp4; + tmp14 = tmp1 - tmp4; + tmp12 = tmp2 + tmp3; + tmp15 = tmp2 - tmp3; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) (tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE); + dataptr[6] = (DCTELEM) (tmp13 - tmp14 - tmp15); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */ + CONST_BITS); + dataptr[2] = (DCTELEM) + DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */ + CONST_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100); /* c9 */ + tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865); /* c3-c9 */ + tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065); /* c3+c9 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054)); /* c5 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669)); /* c7 */ + tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */ + + MULTIPLY(tmp5, FIX(0.184591911)); /* c11 */ + tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */ + tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */ + + MULTIPLY(tmp5, FIX(0.860918669)); /* c7 */ + tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */ + - MULTIPLY(tmp5, FIX(1.121971054)); /* c5 */ + tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */ + - MULTIPLY(tmp2 + tmp5, FIX_0_541196100); /* c9 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 12) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/12)**2 = 4/9, which we partially + * fold into the constant multipliers and final shifting: + * cK now represents sqrt(2) * cos(K*pi/24) * 8/9. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7]; + tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6]; + + tmp10 = tmp0 + tmp5; + tmp13 = tmp0 - tmp5; + tmp11 = tmp1 + tmp4; + tmp14 = tmp1 - tmp4; + tmp12 = tmp2 + tmp3; + tmp15 = tmp2 - tmp3; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0]; + tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7]; + tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */ + CONST_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */ + CONST_BITS+1); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)), /* c4 */ + CONST_BITS+1); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) + /* 8/9 */ + MULTIPLY(tmp13 + tmp15, FIX(1.214244803)), /* c2 */ + CONST_BITS+1); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200)); /* c9 */ + tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102)); /* c3-c9 */ + tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502)); /* c3+c9 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603)); /* c5 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039)); /* c7 */ + tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */ + + MULTIPLY(tmp5, FIX(0.164081699)); /* c11 */ + tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */ + tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */ + + MULTIPLY(tmp5, FIX(0.765261039)); /* c7 */ + tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */ + - MULTIPLY(tmp5, FIX(0.997307603)); /* c5 */ + tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */ + - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+1); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+1); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 13x13 sample block. + */ + +GLOBAL(void) +jpeg_fdct_13x13 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 z1, z2; + DCTELEM workspace[8*5]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT. + * cK represents sqrt(2) * cos(K*pi/26). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[12]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[11]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[10]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[9]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[8]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[7]); + tmp6 = GETJSAMPLE(elemptr[6]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[12]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[11]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[10]); + tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[9]); + tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[8]); + tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[7]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + (tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 - 13 * CENTERJSAMPLE); + tmp6 += tmp6; + tmp0 -= tmp6; + tmp1 -= tmp6; + tmp2 -= tmp6; + tmp3 -= tmp6; + tmp4 -= tmp6; + tmp5 -= tmp6; + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.373119086)) + /* c2 */ + MULTIPLY(tmp1, FIX(1.058554052)) + /* c6 */ + MULTIPLY(tmp2, FIX(0.501487041)) - /* c10 */ + MULTIPLY(tmp3, FIX(0.170464608)) - /* c12 */ + MULTIPLY(tmp4, FIX(0.803364869)) - /* c8 */ + MULTIPLY(tmp5, FIX(1.252223920)), /* c4 */ + CONST_BITS); + z1 = MULTIPLY(tmp0 - tmp2, FIX(1.155388986)) - /* (c4+c6)/2 */ + MULTIPLY(tmp3 - tmp4, FIX(0.435816023)) - /* (c2-c10)/2 */ + MULTIPLY(tmp1 - tmp5, FIX(0.316450131)); /* (c8-c12)/2 */ + z2 = MULTIPLY(tmp0 + tmp2, FIX(0.096834934)) - /* (c4-c6)/2 */ + MULTIPLY(tmp3 + tmp4, FIX(0.937303064)) + /* (c2+c10)/2 */ + MULTIPLY(tmp1 + tmp5, FIX(0.486914739)); /* (c8+c12)/2 */ + + dataptr[4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.322312651)); /* c3 */ + tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.163874945)); /* c5 */ + tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.937797057)) + /* c7 */ + MULTIPLY(tmp14 + tmp15, FIX(0.338443458)); /* c11 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(tmp10, FIX(2.020082300)) + /* c3+c5+c7-c1 */ + MULTIPLY(tmp14, FIX(0.318774355)); /* c9-c11 */ + tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.937797057)) - /* c7 */ + MULTIPLY(tmp11 + tmp12, FIX(0.338443458)); /* c11 */ + tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.163874945)); /* -c5 */ + tmp1 += tmp4 + tmp5 + + MULTIPLY(tmp11, FIX(0.837223564)) - /* c5+c9+c11-c3 */ + MULTIPLY(tmp14, FIX(2.341699410)); /* c1+c7 */ + tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.657217813)); /* -c9 */ + tmp2 += tmp4 + tmp6 - + MULTIPLY(tmp12, FIX(1.572116027)) + /* c1+c5-c9-c11 */ + MULTIPLY(tmp15, FIX(2.260109708)); /* c3+c7 */ + tmp3 += tmp5 + tmp6 + + MULTIPLY(tmp13, FIX(2.205608352)) - /* c3+c5+c9-c7 */ + MULTIPLY(tmp15, FIX(1.742345811)); /* c1+c11 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 13) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/13)**2 = 64/169, which we partially + * fold into the constant multipliers and final shifting: + * cK now represents sqrt(2) * cos(K*pi/26) * 128/169. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*3]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*2]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*1]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*0]; + tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*7]; + tmp6 = dataptr[DCTSIZE*6]; + + tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*4]; + tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*3]; + tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*2]; + tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*1]; + tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*0]; + tmp15 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*7]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6, + FIX(0.757396450)), /* 128/169 */ + CONST_BITS+1); + tmp6 += tmp6; + tmp0 -= tmp6; + tmp1 -= tmp6; + tmp2 -= tmp6; + tmp3 -= tmp6; + tmp4 -= tmp6; + tmp5 -= tmp6; + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.039995521)) + /* c2 */ + MULTIPLY(tmp1, FIX(0.801745081)) + /* c6 */ + MULTIPLY(tmp2, FIX(0.379824504)) - /* c10 */ + MULTIPLY(tmp3, FIX(0.129109289)) - /* c12 */ + MULTIPLY(tmp4, FIX(0.608465700)) - /* c8 */ + MULTIPLY(tmp5, FIX(0.948429952)), /* c4 */ + CONST_BITS+1); + z1 = MULTIPLY(tmp0 - tmp2, FIX(0.875087516)) - /* (c4+c6)/2 */ + MULTIPLY(tmp3 - tmp4, FIX(0.330085509)) - /* (c2-c10)/2 */ + MULTIPLY(tmp1 - tmp5, FIX(0.239678205)); /* (c8-c12)/2 */ + z2 = MULTIPLY(tmp0 + tmp2, FIX(0.073342435)) - /* (c4-c6)/2 */ + MULTIPLY(tmp3 + tmp4, FIX(0.709910013)) + /* (c2+c10)/2 */ + MULTIPLY(tmp1 + tmp5, FIX(0.368787494)); /* (c8+c12)/2 */ + + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS+1); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.001514908)); /* c3 */ + tmp2 = MULTIPLY(tmp10 + tmp12, FIX(0.881514751)); /* c5 */ + tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.710284161)) + /* c7 */ + MULTIPLY(tmp14 + tmp15, FIX(0.256335874)); /* c11 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(tmp10, FIX(1.530003162)) + /* c3+c5+c7-c1 */ + MULTIPLY(tmp14, FIX(0.241438564)); /* c9-c11 */ + tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.710284161)) - /* c7 */ + MULTIPLY(tmp11 + tmp12, FIX(0.256335874)); /* c11 */ + tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(0.881514751)); /* -c5 */ + tmp1 += tmp4 + tmp5 + + MULTIPLY(tmp11, FIX(0.634110155)) - /* c5+c9+c11-c3 */ + MULTIPLY(tmp14, FIX(1.773594819)); /* c1+c7 */ + tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.497774438)); /* -c9 */ + tmp2 += tmp4 + tmp6 - + MULTIPLY(tmp12, FIX(1.190715098)) + /* c1+c5-c9-c11 */ + MULTIPLY(tmp15, FIX(1.711799069)); /* c3+c7 */ + tmp3 += tmp5 + tmp6 + + MULTIPLY(tmp13, FIX(1.670519935)) - /* c3+c5+c9-c7 */ + MULTIPLY(tmp15, FIX(1.319646532)); /* c1+c11 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+1); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+1); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 14x14 sample block. + */ + +GLOBAL(void) +jpeg_fdct_14x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + DCTELEM workspace[8*6]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT. + * cK represents sqrt(2) * cos(K*pi/28). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]); + tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]); + + tmp10 = tmp0 + tmp6; + tmp14 = tmp0 - tmp6; + tmp11 = tmp1 + tmp5; + tmp15 = tmp1 - tmp5; + tmp12 = tmp2 + tmp4; + tmp16 = tmp2 - tmp4; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]); + tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + (tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE); + tmp13 += tmp13; + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */ + MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */ + MULTIPLY(tmp12 - tmp13, FIX(0.881747734)), /* c8 */ + CONST_BITS); + + tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686)); /* c6 */ + + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590)) /* c2-c6 */ + + MULTIPLY(tmp16, FIX(0.613604268)), /* c10 */ + CONST_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954)) /* c6+c10 */ + - MULTIPLY(tmp16, FIX(1.378756276)), /* c2 */ + CONST_BITS); + + /* Odd part */ + + tmp10 = tmp1 + tmp2; + tmp11 = tmp5 - tmp4; + dataptr[7] = (DCTELEM) (tmp0 - tmp10 + tmp3 - tmp11 - tmp6); + tmp3 <<= CONST_BITS; + tmp10 = MULTIPLY(tmp10, - FIX(0.158341681)); /* -c13 */ + tmp11 = MULTIPLY(tmp11, FIX(1.405321284)); /* c1 */ + tmp10 += tmp11 - tmp3; + tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) + /* c5 */ + MULTIPLY(tmp4 + tmp6, FIX(0.752406978)); /* c9 */ + dataptr[5] = (DCTELEM) + DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */ + + MULTIPLY(tmp4, FIX(1.119999435)), /* c1+c11-c9 */ + CONST_BITS); + tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) + /* c3 */ + MULTIPLY(tmp5 - tmp6, FIX(0.467085129)); /* c11 */ + dataptr[3] = (DCTELEM) + DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */ + - MULTIPLY(tmp5, FIX(3.069855259)), /* c1+c5+c11 */ + CONST_BITS); + dataptr[1] = (DCTELEM) + DESCALE(tmp11 + tmp12 + tmp3 + tmp6 - + MULTIPLY(tmp0 + tmp6, FIX(1.126980169)), /* c3+c5-c1 */ + CONST_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 14) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/14)**2 = 16/49, which we partially + * fold into the constant multipliers and final shifting: + * cK now represents sqrt(2) * cos(K*pi/28) * 32/49. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3]; + tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0]; + tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7]; + + tmp10 = tmp0 + tmp6; + tmp14 = tmp0 - tmp6; + tmp11 = tmp1 + tmp5; + tmp15 = tmp1 - tmp5; + tmp12 = tmp2 + tmp4; + tmp16 = tmp2 - tmp4; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2]; + tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1]; + tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0]; + tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13, + FIX(0.653061224)), /* 32/49 */ + CONST_BITS+1); + tmp13 += tmp13; + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */ + MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */ + MULTIPLY(tmp12 - tmp13, FIX(0.575835255)), /* c8 */ + CONST_BITS+1); + + tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570)); /* c6 */ + + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691)) /* c2-c6 */ + + MULTIPLY(tmp16, FIX(0.400721155)), /* c10 */ + CONST_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725)) /* c6+c10 */ + - MULTIPLY(tmp16, FIX(0.900412262)), /* c2 */ + CONST_BITS+1); + + /* Odd part */ + + tmp10 = tmp1 + tmp2; + tmp11 = tmp5 - tmp4; + dataptr[DCTSIZE*7] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6, + FIX(0.653061224)), /* 32/49 */ + CONST_BITS+1); + tmp3 = MULTIPLY(tmp3 , FIX(0.653061224)); /* 32/49 */ + tmp10 = MULTIPLY(tmp10, - FIX(0.103406812)); /* -c13 */ + tmp11 = MULTIPLY(tmp11, FIX(0.917760839)); /* c1 */ + tmp10 += tmp11 - tmp3; + tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) + /* c5 */ + MULTIPLY(tmp4 + tmp6, FIX(0.491367823)); /* c9 */ + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */ + + MULTIPLY(tmp4, FIX(0.731428202)), /* c1+c11-c9 */ + CONST_BITS+1); + tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) + /* c3 */ + MULTIPLY(tmp5 - tmp6, FIX(0.305035186)); /* c11 */ + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */ + - MULTIPLY(tmp5, FIX(2.004803435)), /* c1+c5+c11 */ + CONST_BITS+1); + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp11 + tmp12 + tmp3 + - MULTIPLY(tmp0, FIX(0.735987049)) /* c3+c5-c1 */ + - MULTIPLY(tmp6, FIX(0.082925825)), /* c9-c11-c13 */ + CONST_BITS+1); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 15x15 sample block. + */ + +GLOBAL(void) +jpeg_fdct_15x15 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 z1, z2, z3; + DCTELEM workspace[8*7]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT. + * cK represents sqrt(2) * cos(K*pi/30). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[14]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[13]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[12]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[11]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[10]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[9]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[8]); + tmp7 = GETJSAMPLE(elemptr[7]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[14]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[13]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[12]); + tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[11]); + tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[10]); + tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[9]); + tmp16 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[8]); + + z1 = tmp0 + tmp4 + tmp5; + z2 = tmp1 + tmp3 + tmp6; + z3 = tmp2 + tmp7; + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) (z1 + z2 + z3 - 15 * CENTERJSAMPLE); + z3 += z3; + dataptr[6] = (DCTELEM) + DESCALE(MULTIPLY(z1 - z3, FIX(1.144122806)) - /* c6 */ + MULTIPLY(z2 - z3, FIX(0.437016024)), /* c12 */ + CONST_BITS); + tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7; + z1 = MULTIPLY(tmp3 - tmp2, FIX(1.531135173)) - /* c2+c14 */ + MULTIPLY(tmp6 - tmp2, FIX(2.238241955)); /* c4+c8 */ + z2 = MULTIPLY(tmp5 - tmp2, FIX(0.798468008)) - /* c8-c14 */ + MULTIPLY(tmp0 - tmp2, FIX(0.091361227)); /* c2-c4 */ + z3 = MULTIPLY(tmp0 - tmp3, FIX(1.383309603)) + /* c2 */ + MULTIPLY(tmp6 - tmp5, FIX(0.946293579)) + /* c8 */ + MULTIPLY(tmp1 - tmp4, FIX(0.790569415)); /* (c6+c12)/2 */ + + dataptr[2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS); + dataptr[4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS); + + /* Odd part */ + + tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16, + FIX(1.224744871)); /* c5 */ + tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.344997024)) + /* c3 */ + MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.831253876)); /* c9 */ + tmp12 = MULTIPLY(tmp12, FIX(1.224744871)); /* c5 */ + tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.406466353)) + /* c1 */ + MULTIPLY(tmp11 + tmp14, FIX(1.344997024)) + /* c3 */ + MULTIPLY(tmp13 + tmp15, FIX(0.575212477)); /* c11 */ + tmp0 = MULTIPLY(tmp13, FIX(0.475753014)) - /* c7-c11 */ + MULTIPLY(tmp14, FIX(0.513743148)) + /* c3-c9 */ + MULTIPLY(tmp16, FIX(1.700497885)) + tmp4 + tmp12; /* c1+c13 */ + tmp3 = MULTIPLY(tmp10, - FIX(0.355500862)) - /* -(c1-c7) */ + MULTIPLY(tmp11, FIX(2.176250899)) - /* c3+c9 */ + MULTIPLY(tmp15, FIX(0.869244010)) + tmp4 - tmp12; /* c11+c13 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 15) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/15)**2 = 64/225, which we partially + * fold into the constant multipliers and final shifting: + * cK now represents sqrt(2) * cos(K*pi/30) * 256/225. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*6]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*5]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*4]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*3]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*2]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*1]; + tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*0]; + tmp7 = dataptr[DCTSIZE*7]; + + tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*6]; + tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*5]; + tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*4]; + tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*3]; + tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*2]; + tmp15 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*1]; + tmp16 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*0]; + + z1 = tmp0 + tmp4 + tmp5; + z2 = tmp1 + tmp3 + tmp6; + z3 = tmp2 + tmp7; + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(z1 + z2 + z3, FIX(1.137777778)), /* 256/225 */ + CONST_BITS+2); + z3 += z3; + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(MULTIPLY(z1 - z3, FIX(1.301757503)) - /* c6 */ + MULTIPLY(z2 - z3, FIX(0.497227121)), /* c12 */ + CONST_BITS+2); + tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7; + z1 = MULTIPLY(tmp3 - tmp2, FIX(1.742091575)) - /* c2+c14 */ + MULTIPLY(tmp6 - tmp2, FIX(2.546621957)); /* c4+c8 */ + z2 = MULTIPLY(tmp5 - tmp2, FIX(0.908479156)) - /* c8-c14 */ + MULTIPLY(tmp0 - tmp2, FIX(0.103948774)); /* c2-c4 */ + z3 = MULTIPLY(tmp0 - tmp3, FIX(1.573898926)) + /* c2 */ + MULTIPLY(tmp6 - tmp5, FIX(1.076671805)) + /* c8 */ + MULTIPLY(tmp1 - tmp4, FIX(0.899492312)); /* (c6+c12)/2 */ + + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS+2); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS+2); + + /* Odd part */ + + tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16, + FIX(1.393487498)); /* c5 */ + tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.530307725)) + /* c3 */ + MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.945782187)); /* c9 */ + tmp12 = MULTIPLY(tmp12, FIX(1.393487498)); /* c5 */ + tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.600246161)) + /* c1 */ + MULTIPLY(tmp11 + tmp14, FIX(1.530307725)) + /* c3 */ + MULTIPLY(tmp13 + tmp15, FIX(0.654463974)); /* c11 */ + tmp0 = MULTIPLY(tmp13, FIX(0.541301207)) - /* c7-c11 */ + MULTIPLY(tmp14, FIX(0.584525538)) + /* c3-c9 */ + MULTIPLY(tmp16, FIX(1.934788705)) + tmp4 + tmp12; /* c1+c13 */ + tmp3 = MULTIPLY(tmp10, - FIX(0.404480980)) - /* -(c1-c7) */ + MULTIPLY(tmp11, FIX(2.476089912)) - /* c3+c9 */ + MULTIPLY(tmp15, FIX(0.989006518)) + tmp4 - tmp12; /* c11+c13 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 16x16 sample block. + */ + +GLOBAL(void) +jpeg_fdct_16x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17; + DCTELEM workspace[DCTSIZE2]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * cK represents sqrt(2) * cos(K*pi/32). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]); + tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]); + + tmp10 = tmp0 + tmp7; + tmp14 = tmp0 - tmp7; + tmp11 = tmp1 + tmp6; + tmp15 = tmp1 - tmp6; + tmp12 = tmp2 + tmp5; + tmp16 = tmp2 - tmp5; + tmp13 = tmp3 + tmp4; + tmp17 = tmp3 - tmp4; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]); + tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]); + tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */ + MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */ + CONST_BITS-PASS1_BITS); + + tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */ + MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */ + + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */ + + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */ + - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */ + MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */ + MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */ + MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */ + tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */ + MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */ + tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */ + MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */ + tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */ + MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */ + MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */ + tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */ + - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */ + tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */ + + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */ + tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */ + + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == DCTSIZE * 2) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/16)**2 = 1/2**2. + * cK represents sqrt(2) * cos(K*pi/32). + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2]; + tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1]; + tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0]; + + tmp10 = tmp0 + tmp7; + tmp14 = tmp0 - tmp7; + tmp11 = tmp1 + tmp6; + tmp15 = tmp1 - tmp6; + tmp12 = tmp2 + tmp5; + tmp16 = tmp2 - tmp5; + tmp13 = tmp3 + tmp4; + tmp17 = tmp3 - tmp4; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3]; + tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2]; + tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1]; + tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+2); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */ + MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */ + CONST_BITS+PASS1_BITS+2); + + tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */ + MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */ + + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */ + + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+10 */ + CONST_BITS+PASS1_BITS+2); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */ + - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */ + CONST_BITS+PASS1_BITS+2); + + /* Odd part */ + + tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */ + MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */ + MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */ + MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */ + tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */ + MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */ + tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */ + MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */ + tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */ + MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */ + MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */ + tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */ + - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */ + tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */ + + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */ + tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */ + + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+2); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+2); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 16x8 sample block. + * + * 16-point FDCT in pass 1 (rows), 8-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_16x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17; + INT32 z1; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32). + */ + + dataptr = data; + ctr = 0; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]); + tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]); + + tmp10 = tmp0 + tmp7; + tmp14 = tmp0 - tmp7; + tmp11 = tmp1 + tmp6; + tmp15 = tmp1 - tmp6; + tmp12 = tmp2 + tmp5; + tmp16 = tmp2 - tmp5; + tmp13 = tmp3 + tmp4; + tmp17 = tmp3 - tmp4; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]); + tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]); + tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */ + MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */ + CONST_BITS-PASS1_BITS); + + tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */ + MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */ + + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */ + + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */ + - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */ + MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */ + MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */ + MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */ + tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */ + MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */ + tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */ + MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */ + tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */ + MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */ + MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */ + tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */ + - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */ + tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */ + + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */ + tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */ + + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by 8/16 = 1/2. + * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "c1" should be "c6". + */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + + tmp10 = tmp0 + tmp3; + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS+1); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS+1); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */ + CONST_BITS+PASS1_BITS+1); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* -c3+c5 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + tmp12 += z1; + tmp13 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp0 += z1 + tmp12; + tmp3 += z1 + tmp13; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp1 += z1 + tmp13; + tmp2 += z1 + tmp12; + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+PASS1_BITS+1); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 14x7 sample block. + * + * 14-point FDCT in pass 1 (rows), 7-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_14x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 z1, z2, z3; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Zero bottom row of output coefficient block. */ + MEMZERO(&data[DCTSIZE*7], SIZEOF(DCTELEM) * DCTSIZE); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28). + */ + + dataptr = data; + for (ctr = 0; ctr < 7; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]); + tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]); + + tmp10 = tmp0 + tmp6; + tmp14 = tmp0 - tmp6; + tmp11 = tmp1 + tmp5; + tmp15 = tmp1 - tmp5; + tmp12 = tmp2 + tmp4; + tmp16 = tmp2 - tmp4; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]); + tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE) << PASS1_BITS); + tmp13 += tmp13; + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */ + MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */ + MULTIPLY(tmp12 - tmp13, FIX(0.881747734)), /* c8 */ + CONST_BITS-PASS1_BITS); + + tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686)); /* c6 */ + + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590)) /* c2-c6 */ + + MULTIPLY(tmp16, FIX(0.613604268)), /* c10 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954)) /* c6+c10 */ + - MULTIPLY(tmp16, FIX(1.378756276)), /* c2 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = tmp1 + tmp2; + tmp11 = tmp5 - tmp4; + dataptr[7] = (DCTELEM) ((tmp0 - tmp10 + tmp3 - tmp11 - tmp6) << PASS1_BITS); + tmp3 <<= CONST_BITS; + tmp10 = MULTIPLY(tmp10, - FIX(0.158341681)); /* -c13 */ + tmp11 = MULTIPLY(tmp11, FIX(1.405321284)); /* c1 */ + tmp10 += tmp11 - tmp3; + tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) + /* c5 */ + MULTIPLY(tmp4 + tmp6, FIX(0.752406978)); /* c9 */ + dataptr[5] = (DCTELEM) + DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */ + + MULTIPLY(tmp4, FIX(1.119999435)), /* c1+c11-c9 */ + CONST_BITS-PASS1_BITS); + tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) + /* c3 */ + MULTIPLY(tmp5 - tmp6, FIX(0.467085129)); /* c11 */ + dataptr[3] = (DCTELEM) + DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */ + - MULTIPLY(tmp5, FIX(3.069855259)), /* c1+c5+c11 */ + CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) + DESCALE(tmp11 + tmp12 + tmp3 + tmp6 - + MULTIPLY(tmp0 + tmp6, FIX(1.126980169)), /* c3+c5-c1 */ + CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/14)*(8/7) = 32/49, which we + * partially fold into the constant multipliers and final shifting: + * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14) * 64/49. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4]; + tmp3 = dataptr[DCTSIZE*3]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5]; + tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4]; + + z1 = tmp0 + tmp2; + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */ + CONST_BITS+PASS1_BITS+1); + tmp3 += tmp3; + z1 -= tmp3; + z1 -= tmp3; + z1 = MULTIPLY(z1, FIX(0.461784020)); /* (c2+c6-c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084)); /* (c2+c4-c6)/2 */ + z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS+1); + z1 -= z2; + z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509)); /* c4 */ + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS+1); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */ + tmp1 += tmp2; + tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310)); /* c5 */ + tmp0 += tmp3; + tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355)); /* c3+c1-c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 12x6 sample block. + * + * 12-point FDCT in pass 1 (rows), 6-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_12x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Zero 2 bottom rows of output coefficient block. */ + MEMZERO(&data[DCTSIZE*6], SIZEOF(DCTELEM) * DCTSIZE * 2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24). + */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]); + + tmp10 = tmp0 + tmp5; + tmp13 = tmp0 - tmp5; + tmp11 = tmp1 + tmp4; + tmp14 = tmp1 - tmp4; + tmp12 = tmp2 + tmp3; + tmp15 = tmp2 - tmp3; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[6] = (DCTELEM) ((tmp13 - tmp14 - tmp15) << PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */ + CONST_BITS-PASS1_BITS); + dataptr[2] = (DCTELEM) + DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100); /* c9 */ + tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865); /* c3-c9 */ + tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065); /* c3+c9 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054)); /* c5 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669)); /* c7 */ + tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */ + + MULTIPLY(tmp5, FIX(0.184591911)); /* c11 */ + tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */ + tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */ + + MULTIPLY(tmp5, FIX(0.860918669)); /* c7 */ + tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */ + - MULTIPLY(tmp5, FIX(1.121971054)); /* c5 */ + tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */ + - MULTIPLY(tmp2 + tmp5, FIX_0_541196100); /* c9 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/12)*(8/6) = 8/9, which we + * partially fold into the constant multipliers and final shifting: + * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5]; + tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3]; + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */ + CONST_BITS+PASS1_BITS+1); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS+1); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 10x5 sample block. + * + * 10-point FDCT in pass 1 (rows), 5-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_10x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Zero 3 bottom rows of output coefficient block. */ + MEMZERO(&data[DCTSIZE*5], SIZEOF(DCTELEM) * DCTSIZE * 3); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20). + */ + + dataptr = data; + for (ctr = 0; ctr < 5; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]); + tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]); + + tmp10 = tmp0 + tmp4; + tmp13 = tmp0 - tmp4; + tmp11 = tmp1 + tmp3; + tmp14 = tmp1 - tmp3; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << PASS1_BITS); + tmp12 += tmp12; + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */ + MULTIPLY(tmp11 - tmp12, FIX(0.437016024)), /* c8 */ + CONST_BITS-PASS1_BITS); + tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876)); /* c6 */ + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)), /* c2-c6 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)), /* c2+c6 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = tmp0 + tmp4; + tmp11 = tmp1 - tmp3; + dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << PASS1_BITS); + tmp2 <<= CONST_BITS; + dataptr[1] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) + /* c1 */ + MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 + /* c3 */ + MULTIPLY(tmp3, FIX(0.642039522)) + /* c7 */ + MULTIPLY(tmp4, FIX(0.221231742)), /* c9 */ + CONST_BITS-PASS1_BITS); + tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) - /* (c3+c7)/2 */ + MULTIPLY(tmp1 + tmp3, FIX(0.587785252)); /* (c1-c9)/2 */ + tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) + /* (c3-c7)/2 */ + (tmp11 << (CONST_BITS - 1)) - tmp2; + dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/10)*(8/5) = 32/25, which we + * fold into the constant multipliers: + * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10) * 32/25. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3]; + tmp2 = dataptr[DCTSIZE*2]; + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)), /* 32/25 */ + CONST_BITS+PASS1_BITS); + tmp11 = MULTIPLY(tmp11, FIX(1.011928851)); /* (c2+c4)/2 */ + tmp10 -= tmp2 << 2; + tmp10 = MULTIPLY(tmp10, FIX(0.452548340)); /* (c2-c4)/2 */ + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961)); /* c3 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on an 8x4 sample block. + * + * 8-point FDCT in pass 1 (rows), 4-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_8x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Zero 4 bottom rows of output coefficient block. */ + MEMZERO(&data[DCTSIZE*4], SIZEOF(DCTELEM) * DCTSIZE * 4); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * We must also scale the output by 8/4 = 2, which we add here. + * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "c1" should be "c6". + */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]); + + tmp10 = tmp0 + tmp3; + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << (PASS1_BITS+1)); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << (PASS1_BITS+1)); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-2); + + dataptr[2] = (DCTELEM) + RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS-1); + dataptr[6] = (DCTELEM) + RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS-1); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-2); + + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* -c3+c5 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + tmp12 += z1; + tmp13 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp0 += z1 + tmp12; + tmp3 += z1 + tmp13; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp1 += z1 + tmp13; + tmp2 += z1 + tmp12; + + dataptr[1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS-PASS1_BITS-1); + dataptr[3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS-PASS1_BITS-1); + dataptr[5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS-1); + dataptr[7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS-PASS1_BITS-1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * 4-point FDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1)); + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS+PASS1_BITS-1); + + dataptr[DCTSIZE*1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 6x3 sample block. + * + * 6-point FDCT in pass 1 (rows), 3-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_6x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + INT32 tmp10, tmp11, tmp12; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * We scale the results further by 2 as part of output adaption + * scaling for different DCT size. + * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + + dataptr = data; + for (ctr = 0; ctr < 3; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]); + tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << (PASS1_BITS+1)); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */ + CONST_BITS-PASS1_BITS-1); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */ + CONST_BITS-PASS1_BITS-1); + + /* Odd part */ + + tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */ + CONST_BITS-PASS1_BITS-1); + + dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << (PASS1_BITS+1))); + dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << (PASS1_BITS+1)); + dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << (PASS1_BITS+1))); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially + * fold into the constant multipliers (other part was done in pass 1): + * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6) * 16/9. + */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2]; + tmp1 = dataptr[DCTSIZE*1]; + + tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(MULTIPLY(tmp2, FIX(2.177324216)), /* c1 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 4x2 sample block. + * + * 4-point FDCT in pass 1 (rows), 2-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_4x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + DCTELEM tmp0, tmp2, tmp10, tmp12, tmp4, tmp5; + INT32 tmp1, tmp3, tmp11, tmp13; + INT32 z1, z2, z3; + JSAMPROW elemptr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT. + * 4-point FDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. + */ + + /* Row 0 */ + elemptr = sample_data[0] + start_col; + + /* Even part */ + + tmp4 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]); + tmp5 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]); + + tmp0 = tmp4 + tmp5; + tmp2 = tmp4 - tmp5; + + /* Odd part */ + + z2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]); + z3 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-3-1); + tmp1 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Row 1 */ + elemptr = sample_data[1] + start_col; + + /* Even part */ + + tmp4 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]); + tmp5 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]); + + tmp10 = tmp4 + tmp5; + tmp12 = tmp4 - tmp5; + + /* Odd part */ + + z2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]); + z3 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp11 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/4)*(8/2) = 2**3. + */ + + /* Column 0 */ + /* Apply unsigned->signed conversion. */ + data[DCTSIZE*0] = (tmp0 + tmp10 - 8 * CENTERJSAMPLE) << 3; + data[DCTSIZE*1] = (tmp0 - tmp10) << 3; + + /* Column 1 */ + data[DCTSIZE*0+1] = (DCTELEM) RIGHT_SHIFT(tmp1 + tmp11, CONST_BITS-3); + data[DCTSIZE*1+1] = (DCTELEM) RIGHT_SHIFT(tmp1 - tmp11, CONST_BITS-3); + + /* Column 2 */ + data[DCTSIZE*0+2] = (tmp2 + tmp12) << 3; + data[DCTSIZE*1+2] = (tmp2 - tmp12) << 3; + + /* Column 3 */ + data[DCTSIZE*0+3] = (DCTELEM) RIGHT_SHIFT(tmp3 + tmp13, CONST_BITS-3); + data[DCTSIZE*1+3] = (DCTELEM) RIGHT_SHIFT(tmp3 - tmp13, CONST_BITS-3); +} + + +/* + * Perform the forward DCT on a 2x1 sample block. + * + * 2-point FDCT in pass 1 (rows), 1-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_2x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + DCTELEM tmp0, tmp1; + JSAMPROW elemptr; + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + elemptr = sample_data[0] + start_col; + + tmp0 = GETJSAMPLE(elemptr[0]); + tmp1 = GETJSAMPLE(elemptr[1]); + + /* We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/2)*(8/1) = 2**5. + */ + + /* Even part */ + + /* Apply unsigned->signed conversion. */ + data[0] = (tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5; + + /* Odd part */ + + data[1] = (tmp0 - tmp1) << 5; +} + + +/* + * Perform the forward DCT on an 8x16 sample block. + * + * 8-point FDCT in pass 1 (rows), 16-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_8x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17; + INT32 z1; + DCTELEM workspace[DCTSIZE2]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "c1" should be "c6". + */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]); + + tmp10 = tmp0 + tmp3; + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); /* c6 */ + dataptr[2] = (DCTELEM) + DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* -c3+c5 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + tmp12 += z1; + tmp13 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp0 += z1 + tmp12; + tmp3 += z1 + tmp13; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp1 += z1 + tmp13; + tmp2 += z1 + tmp12; + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-PASS1_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == DCTSIZE * 2) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by 8/16 = 1/2. + * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32). + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2]; + tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1]; + tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0]; + + tmp10 = tmp0 + tmp7; + tmp14 = tmp0 - tmp7; + tmp11 = tmp1 + tmp6; + tmp15 = tmp1 - tmp6; + tmp12 = tmp2 + tmp5; + tmp16 = tmp2 - tmp5; + tmp13 = tmp3 + tmp4; + tmp17 = tmp3 - tmp4; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3]; + tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2]; + tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1]; + tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+1); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */ + MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */ + CONST_BITS+PASS1_BITS+1); + + tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */ + MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */ + + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */ + + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */ + - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */ + CONST_BITS+PASS1_BITS+1); + + /* Odd part */ + + tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */ + MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */ + MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */ + MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */ + tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */ + MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */ + tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */ + MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */ + tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */ + MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */ + MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */ + tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */ + - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */ + tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */ + + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */ + tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */ + + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+1); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 7x14 sample block. + * + * 7-point FDCT in pass 1 (rows), 14-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_7x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 z1, z2, z3; + DCTELEM workspace[8*6]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]); + tmp3 = GETJSAMPLE(elemptr[3]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]); + + z1 = tmp0 + tmp2; + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS); + tmp3 += tmp3; + z1 -= tmp3; + z1 -= tmp3; + z1 = MULTIPLY(z1, FIX(0.353553391)); /* (c2+c6-c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002)); /* (c2+c4-c6)/2 */ + z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123)); /* c6 */ + dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS); + z1 -= z2; + z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734)); /* c4 */ + dataptr[4] = (DCTELEM) + DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */ + tmp1 += tmp2; + tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268)); /* c5 */ + tmp0 += tmp3; + tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693)); /* c3+c1-c5 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 14) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/7)*(8/14) = 32/49, which we + * fold into the constant multipliers: + * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28) * 32/49. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3]; + tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0]; + tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7]; + + tmp10 = tmp0 + tmp6; + tmp14 = tmp0 - tmp6; + tmp11 = tmp1 + tmp5; + tmp15 = tmp1 - tmp5; + tmp12 = tmp2 + tmp4; + tmp16 = tmp2 - tmp4; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2]; + tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1]; + tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0]; + tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13, + FIX(0.653061224)), /* 32/49 */ + CONST_BITS+PASS1_BITS); + tmp13 += tmp13; + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */ + MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */ + MULTIPLY(tmp12 - tmp13, FIX(0.575835255)), /* c8 */ + CONST_BITS+PASS1_BITS); + + tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570)); /* c6 */ + + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691)) /* c2-c6 */ + + MULTIPLY(tmp16, FIX(0.400721155)), /* c10 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725)) /* c6+c10 */ + - MULTIPLY(tmp16, FIX(0.900412262)), /* c2 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = tmp1 + tmp2; + tmp11 = tmp5 - tmp4; + dataptr[DCTSIZE*7] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6, + FIX(0.653061224)), /* 32/49 */ + CONST_BITS+PASS1_BITS); + tmp3 = MULTIPLY(tmp3 , FIX(0.653061224)); /* 32/49 */ + tmp10 = MULTIPLY(tmp10, - FIX(0.103406812)); /* -c13 */ + tmp11 = MULTIPLY(tmp11, FIX(0.917760839)); /* c1 */ + tmp10 += tmp11 - tmp3; + tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) + /* c5 */ + MULTIPLY(tmp4 + tmp6, FIX(0.491367823)); /* c9 */ + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */ + + MULTIPLY(tmp4, FIX(0.731428202)), /* c1+c11-c9 */ + CONST_BITS+PASS1_BITS); + tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) + /* c3 */ + MULTIPLY(tmp5 - tmp6, FIX(0.305035186)); /* c11 */ + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */ + - MULTIPLY(tmp5, FIX(2.004803435)), /* c1+c5+c11 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp11 + tmp12 + tmp3 + - MULTIPLY(tmp0, FIX(0.735987049)) /* c3+c5-c1 */ + - MULTIPLY(tmp6, FIX(0.082925825)), /* c9-c11-c13 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 6x12 sample block. + * + * 6-point FDCT in pass 1 (rows), 12-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_6x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + DCTELEM workspace[8*4]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]); + tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */ + CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */ + CONST_BITS-PASS1_BITS); + + dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS)); + dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS); + dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS)); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 12) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/6)*(8/12) = 8/9, which we + * fold into the constant multipliers: + * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24) * 8/9. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7]; + tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6]; + + tmp10 = tmp0 + tmp5; + tmp13 = tmp0 - tmp5; + tmp11 = tmp1 + tmp4; + tmp14 = tmp1 - tmp4; + tmp12 = tmp2 + tmp3; + tmp15 = tmp2 - tmp3; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0]; + tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7]; + tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)), /* c4 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) + /* 8/9 */ + MULTIPLY(tmp13 + tmp15, FIX(1.214244803)), /* c2 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200)); /* c9 */ + tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102)); /* c3-c9 */ + tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502)); /* c3+c9 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603)); /* c5 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039)); /* c7 */ + tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */ + + MULTIPLY(tmp5, FIX(0.164081699)); /* c11 */ + tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */ + tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */ + + MULTIPLY(tmp5, FIX(0.765261039)); /* c7 */ + tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */ + - MULTIPLY(tmp5, FIX(0.997307603)); /* c5 */ + tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */ + - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 5x10 sample block. + * + * 5-point FDCT in pass 1 (rows), 10-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_5x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + DCTELEM workspace[8*2]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10). + */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]); + tmp2 = GETJSAMPLE(elemptr[2]); + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << PASS1_BITS); + tmp11 = MULTIPLY(tmp11, FIX(0.790569415)); /* (c2+c4)/2 */ + tmp10 -= tmp2 << 2; + tmp10 = MULTIPLY(tmp10, FIX(0.353553391)); /* (c2-c4)/2 */ + dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876)); /* c3 */ + + dataptr[1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */ + CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */ + CONST_BITS-PASS1_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 10) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/5)*(8/10) = 32/25, which we + * fold into the constant multipliers: + * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20) * 32/25. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0]; + tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5]; + + tmp10 = tmp0 + tmp4; + tmp13 = tmp0 - tmp4; + tmp11 = tmp1 + tmp3; + tmp14 = tmp1 - tmp3; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6]; + tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */ + CONST_BITS+PASS1_BITS); + tmp12 += tmp12; + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */ + MULTIPLY(tmp11 - tmp12, FIX(0.559380511)), /* c8 */ + CONST_BITS+PASS1_BITS); + tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)), /* c2-c6 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)), /* c2+c6 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = tmp0 + tmp4; + tmp11 = tmp1 - tmp3; + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)), /* 32/25 */ + CONST_BITS+PASS1_BITS); + tmp2 = MULTIPLY(tmp2, FIX(1.28)); /* 32/25 */ + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) + /* c1 */ + MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 + /* c3 */ + MULTIPLY(tmp3, FIX(0.821810588)) + /* c7 */ + MULTIPLY(tmp4, FIX(0.283176630)), /* c9 */ + CONST_BITS+PASS1_BITS); + tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) - /* (c3+c7)/2 */ + MULTIPLY(tmp1 + tmp3, FIX(0.752365123)); /* (c1-c9)/2 */ + tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) + /* (c3-c7)/2 */ + MULTIPLY(tmp11, FIX(0.64)) - tmp2; /* 16/25 */ + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 4x8 sample block. + * + * 4-point FDCT in pass 1 (rows), 8-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_4x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * We must also scale the output by 8/4 = 2, which we add here. + * 4-point FDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. + */ + + dataptr = data; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+1)); + dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+1)); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-2); + + dataptr[1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS-1); + dataptr[3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS-1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "c1" should be "c6". + */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + + /* Add fudge factor here for final descale. */ + tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1)); + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS+PASS1_BITS-1); + + dataptr[DCTSIZE*2] = (DCTELEM) + RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */ + CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS+PASS1_BITS-1); + + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* -c3+c5 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + tmp12 += z1; + tmp13 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp0 += z1 + tmp12; + tmp3 += z1 + tmp13; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp1 += z1 + tmp13; + tmp2 += z1 + tmp12; + + dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 3x6 sample block. + * + * 3-point FDCT in pass 1 (rows), 6-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_3x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + INT32 tmp10, tmp11, tmp12; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * We scale the results further by 2 as part of output adaption + * scaling for different DCT size. + * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6). + */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]); + tmp1 = GETJSAMPLE(elemptr[1]); + + tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+1)); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */ + CONST_BITS-PASS1_BITS-1); + + /* Odd part */ + + dataptr[1] = (DCTELEM) + DESCALE(MULTIPLY(tmp2, FIX(1.224744871)), /* c1 */ + CONST_BITS-PASS1_BITS-1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially + * fold into the constant multipliers (other part was done in pass 1): + * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9. + */ + + dataptr = data; + for (ctr = 0; ctr < 3; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5]; + tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3]; + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 2x4 sample block. + * + * 2-point FDCT in pass 1 (rows), 4-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_2x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1; + INT32 tmp10, tmp11; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. + * Note results are scaled up by sqrt(8) compared to a true DCT. + */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]); + tmp1 = GETJSAMPLE(elemptr[1]); + + /* Apply unsigned->signed conversion. */ + dataptr[0] = (DCTELEM) (tmp0 + tmp1 - 2 * CENTERJSAMPLE); + + /* Odd part */ + + dataptr[1] = (DCTELEM) (tmp0 - tmp1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/2)*(8/4) = 2**3. + * 4-point FDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. + */ + + dataptr = data; + for (ctr = 0; ctr < 2; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp1) << 3); + dataptr[DCTSIZE*2] = (DCTELEM) ((tmp0 - tmp1) << 3); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-3-1); + + dataptr[DCTSIZE*1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-3); + dataptr[DCTSIZE*3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-3); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 1x2 sample block. + * + * 1-point FDCT in pass 1 (rows), 2-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_1x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + DCTELEM tmp0, tmp1; + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: empty. */ + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/1)*(8/2) = 2**5. + */ + + /* Even part */ + + tmp0 = GETJSAMPLE(sample_data[0][start_col]); + tmp1 = GETJSAMPLE(sample_data[1][start_col]); + + /* Apply unsigned->signed conversion. */ + data[DCTSIZE*0] = (tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5; + + /* Odd part */ + + data[DCTSIZE*1] = (tmp0 - tmp1) << 5; +} + +#endif /* DCT_SCALING_SUPPORTED */ +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jidctflt.c b/widget/milsko/milskosrc/external/libjpeg/src/jidctflt.c new file mode 100644 index 0000000000..e33a2b5e42 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jidctflt.c @@ -0,0 +1,238 @@ +/* + * jidctflt.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * Modified 2010-2017 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * This implementation should be more accurate than either of the integer + * IDCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a float result. + */ + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + * + * cK represents cos(K*pi/16). + */ + +GLOBAL(void) +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z5, z10, z11, z12, z13; + JCOEFPTR inptr; + FLOAT_MULT_TYPE * quantptr; + FAST_FLOAT * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */ + tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 - tmp5; + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + wsptr[DCTSIZE*7] = tmp0 - tmp7; + wsptr[DCTSIZE*1] = tmp1 + tmp6; + wsptr[DCTSIZE*6] = tmp1 - tmp6; + wsptr[DCTSIZE*2] = tmp2 + tmp5; + wsptr[DCTSIZE*5] = tmp2 - tmp5; + wsptr[DCTSIZE*3] = tmp3 + tmp4; + wsptr[DCTSIZE*4] = tmp3 - tmp4; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * And testing floats for zero is relatively expensive, so we don't bother. + */ + + /* Even part */ + + /* Prepare range-limit and float->int conversion */ + z5 = wsptr[0] + (((FAST_FLOAT) RANGE_CENTER) + ((FAST_FLOAT) 0.5)); + tmp10 = z5 + wsptr[4]; + tmp11 = z5 - wsptr[4]; + + tmp13 = wsptr[2] + wsptr[6]; + tmp12 = (wsptr[2] - wsptr[6]) * + ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = wsptr[5] + wsptr[3]; + z10 = wsptr[5] - wsptr[3]; + z11 = wsptr[1] + wsptr[7]; + z12 = wsptr[1] - wsptr[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */ + tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 - tmp5; + + /* Final output stage: float->int conversion and range-limit */ + + outptr[0] = range_limit[(int) (tmp0 + tmp7) & RANGE_MASK]; + outptr[7] = range_limit[(int) (tmp0 - tmp7) & RANGE_MASK]; + outptr[1] = range_limit[(int) (tmp1 + tmp6) & RANGE_MASK]; + outptr[6] = range_limit[(int) (tmp1 - tmp6) & RANGE_MASK]; + outptr[2] = range_limit[(int) (tmp2 + tmp5) & RANGE_MASK]; + outptr[5] = range_limit[(int) (tmp2 - tmp5) & RANGE_MASK]; + outptr[3] = range_limit[(int) (tmp3 + tmp4) & RANGE_MASK]; + outptr[4] = range_limit[(int) (tmp3 - tmp4) & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jidctfst.c b/widget/milsko/milskosrc/external/libjpeg/src/jidctfst.c new file mode 100644 index 0000000000..1ac3e39cb7 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jidctfst.c @@ -0,0 +1,351 @@ +/* + * jidctfst.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * Modified 2015-2017 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jidctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * The dequantized coefficients are not integers because the AA&N scaling + * factors have been incorporated. We represent them scaled up by PASS1_BITS, + * so that the first and second IDCT rounds have the same input scaling. + * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to + * avoid a descaling shift; this compromises accuracy rather drastically + * for small quantization table entries, but it saves a lot of shifts. + * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, + * so we use a much larger scaling factor to preserve accuracy. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 8 +#define PASS1_BITS 2 +#else +#define CONST_BITS 8 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ +#else +#define FIX_1_082392200 FIX(1.082392200) +#define FIX_1_414213562 FIX(1.414213562) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_613125930 FIX(2.613125930) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 + * multiplication will do. For 12-bit data, the multiplier table is + * declared INT32, so a 32-bit multiply will be used. + */ + +#if BITS_IN_JSAMPLE == 8 +#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) +#else +#define DEQUANTIZE(coef,quantval) \ + DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) +#endif + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + * + * cK represents cos(K*pi/16). + */ + +GLOBAL(void) +jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z5, z10, z11, z12, z13; + JCOEFPTR inptr; + IFAST_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS /* for DESCALE */ + ISHIFT_TEMPS /* for IRIGHT_SHIFT */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = z5 - MULTIPLY(z12, FIX_1_082392200); /* 2*(c2-c6) */ + tmp12 = z5 - MULTIPLY(z10, FIX_2_613125930); /* 2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 - tmp5; + + wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); + wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); + wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); + wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); + wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); + wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); + wsptr[DCTSIZE*3] = (int) (tmp3 + tmp4); + wsptr[DCTSIZE*4] = (int) (tmp3 - tmp4); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. + * Note that we must descale the results by a factor of 8 == 2**3, + * and also undo the PASS1_BITS scaling. + */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Add range center and fudge factor for final descale and range-limit. */ + z5 = (DCTELEM) wsptr[0] + + ((((DCTELEM) RANGE_CENTER) << (PASS1_BITS+3)) + + (1 << (PASS1_BITS+2))); + + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) IRIGHT_SHIFT(z5, PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = z5 + (DCTELEM) wsptr[4]; + tmp11 = z5 - (DCTELEM) wsptr[4]; + + tmp13 = (DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]; + tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], + FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; + z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; + z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; + z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = z5 - MULTIPLY(z12, FIX_1_082392200); /* 2*(c2-c6) */ + tmp12 = z5 - MULTIPLY(z10, FIX_2_613125930); /* 2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 - tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp1 + tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) IRIGHT_SHIFT(tmp1 - tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) IRIGHT_SHIFT(tmp2 + tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) IRIGHT_SHIFT(tmp2 - tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) IRIGHT_SHIFT(tmp3 + tmp4, PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) IRIGHT_SHIFT(tmp3 - tmp4, PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jidctint.c b/widget/milsko/milskosrc/external/libjpeg/src/jidctint.c new file mode 100644 index 0000000000..e30ec8c8a4 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jidctint.c @@ -0,0 +1,5240 @@ +/* + * jidctint.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modification developed 2002-2018 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + * + * We also provide IDCT routines with various output sample block sizes for + * direct resolution reduction or enlargement and for direct resolving the + * common 2x1 and 1x2 subsampling cases without additional resampling: NxN + * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 input DCT block. + * + * For N<8 we simply take the corresponding low-frequency coefficients of + * the 8x8 input DCT block and apply an NxN point IDCT on the sub-block + * to yield the downscaled outputs. + * This can be seen as direct low-pass downsampling from the DCT domain + * point of view rather than the usual spatial domain point of view, + * yielding significant computational savings and results at least + * as good as common bilinear (averaging) spatial downsampling. + * + * For N>8 we apply a partial NxN IDCT on the 8 input coefficients as + * lower frequencies and higher frequencies assumed to be zero. + * It turns out that the computational effort is similar to the 8x8 IDCT + * regarding the output size. + * Furthermore, the scaling and descaling is the same for all IDCT sizes. + * + * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases + * since there would be too many additional constants to pre-calculate. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + * + * Optimized algorithm with 12 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/16). + */ + +GLOBAL(void) +jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * Note results are scaled up by sqrt(8) compared to a true IDCT; + * furthermore, we scale the results by 2**PASS1_BITS. + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. + * The rotator is c(-6). + */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 <<= CONST_BITS; + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z2 += ONE << (CONST_BITS-PASS1_BITS-1); + + tmp0 = z2 + z3; + tmp1 = z2 - z3; + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. + * Note that we must descale the results by a factor of 8 == 2**3, + * and also undo the PASS1_BITS scaling. + */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Add range center and fudge factor for final descale and range-limit. */ + z2 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) RIGHT_SHIFT(z2, PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. + * The rotator is c(-6). + */ + + z3 = (INT32) wsptr[4]; + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#ifdef IDCT_SCALING_SUPPORTED + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 7x7 output block. + * + * Optimized algorithm with 12 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/14). + */ + +GLOBAL(void) +jpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[7*7]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp13 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp13 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp13 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ + tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ + tmp0 = z1 + z3; + z2 -= tmp0; + tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */ + tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ + tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ + tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + + tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ + tmp1 += tmp2; + z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ + tmp0 += z2; + tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ + + /* Final output stage */ + + wsptr[7*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[7*6] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[7*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[7*5] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[7*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[7*4] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[7*3] = (int) RIGHT_SHIFT(tmp13, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 7 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp13 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp13 <<= CONST_BITS; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[4]; + z3 = (INT32) wsptr[6]; + + tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ + tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ + tmp0 = z1 + z3; + z2 -= tmp0; + tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */ + tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ + tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ + tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + + tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ + tmp1 += tmp2; + z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ + tmp0 += z2; + tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 7; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 6x6 output block. + * + * Optimized algorithm with 3 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/12). + */ + +GLOBAL(void) +jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[6*6]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ + tmp1 = tmp0 + tmp10; + tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS); + tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ + tmp10 = tmp1 + tmp0; + tmp12 = tmp1 - tmp0; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); + tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); + tmp1 = (z1 - z2 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[6*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[6*1] = (int) (tmp11 + tmp1); + wsptr[6*4] = (int) (tmp11 - tmp1); + wsptr[6*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[6*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 6 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp0 <<= CONST_BITS; + tmp2 = (INT32) wsptr[4]; + tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ + tmp1 = tmp0 + tmp10; + tmp11 = tmp0 - tmp10 - tmp10; + tmp10 = (INT32) wsptr[2]; + tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ + tmp10 = tmp1 + tmp0; + tmp12 = tmp1 - tmp0; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); + tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); + tmp1 = (z1 - z2 - z3) << CONST_BITS; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 6; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 5x5 output block. + * + * Optimized algorithm with 5 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/10). + */ + +GLOBAL(void) +jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[5*5]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp12 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp12 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp0 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */ + z3 = tmp12 + z2; + tmp10 = z3 + z1; + tmp11 = z3 - z1; + tmp12 -= z2 << 2; + + /* Odd part */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ + tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ + tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ + + /* Final output stage */ + + wsptr[5*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[5*4] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[5*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[5*3] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[5*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 5 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp12 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp12 <<= CONST_BITS; + tmp0 = (INT32) wsptr[2]; + tmp1 = (INT32) wsptr[4]; + z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */ + z3 = tmp12 + z2; + tmp10 = z3 + z1; + tmp11 = z3 - z1; + tmp12 -= z2 << 2; + + /* Odd part */ + + z2 = (INT32) wsptr[1]; + z3 = (INT32) wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ + tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ + tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 5; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 4x4 output block. + * + * Optimized algorithm with 3 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. + */ + +GLOBAL(void) +jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[4*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + + tmp10 = (tmp0 + tmp2) << PASS1_BITS; + tmp12 = (tmp0 - tmp2) << PASS1_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS); + tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS); + + /* Final output stage */ + + wsptr[4*0] = (int) (tmp10 + tmp0); + wsptr[4*3] = (int) (tmp10 - tmp0); + wsptr[4*1] = (int) (tmp12 + tmp2); + wsptr[4*2] = (int) (tmp12 - tmp2); + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp2 = (INT32) wsptr[2]; + + tmp10 = (tmp0 + tmp2) << CONST_BITS; + tmp12 = (tmp0 - tmp2) << CONST_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = (INT32) wsptr[1]; + z3 = (INT32) wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 4; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 3x3 output block. + * + * Optimized algorithm with 2 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/6). + */ + +GLOBAL(void) +jpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[3*3]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ + tmp10 = tmp0 + tmp12; + tmp2 = tmp0 - tmp12 - tmp12; + + /* Odd part */ + + tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ + + /* Final output stage */ + + wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[3*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[3*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 3 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 3; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp0 <<= CONST_BITS; + tmp2 = (INT32) wsptr[2]; + tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ + tmp10 = tmp0 + tmp12; + tmp2 = tmp0 - tmp12 - tmp12; + + /* Odd part */ + + tmp12 = (INT32) wsptr[1]; + tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 3; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 2x2 output block. + * + * Multiplication-less algorithm. + */ + +GLOBAL(void) +jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + ISLOW_MULT_TYPE * quantptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + ISHIFT_TEMPS + + /* Pass 1: process columns from input. */ + + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + + /* Column 0 */ + tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]); + /* Add range center and fudge factor for final descale and range-limit. */ + tmp4 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2); + + tmp0 = tmp4 + tmp5; + tmp2 = tmp4 - tmp5; + + /* Column 1 */ + tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0+1], quantptr[DCTSIZE*0+1]); + tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1+1], quantptr[DCTSIZE*1+1]); + + tmp1 = tmp4 + tmp5; + tmp3 = tmp4 - tmp5; + + /* Pass 2: process 2 rows, store into output array. */ + + /* Row 0 */ + outptr = output_buf[0] + output_col; + + outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK]; + outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK]; + + /* Row 1 */ + outptr = output_buf[1] + output_col; + + outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp2 + tmp3, 3) & RANGE_MASK]; + outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp2 - tmp3, 3) & RANGE_MASK]; +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 1x1 output block. + * + * We hardly need an inverse DCT routine for this: just take the + * average pixel value, which is one-eighth of the DC coefficient. + */ + +GLOBAL(void) +jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM dcval; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + ISHIFT_TEMPS + + /* 1x1 is trivial: just take the DC coefficient divided by 8. */ + + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + + dcval = DEQUANTIZE(coef_block[0], quantptr[0]); + /* Add range center and fudge factor for descale and range-limit. */ + dcval += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2); + + output_buf[0][output_col] = + range_limit[(int) IRIGHT_SHIFT(dcval, 3) & RANGE_MASK]; +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 9x9 output block. + * + * Optimized algorithm with 10 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/18). + */ + +GLOBAL(void) +jpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*9]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */ + tmp1 = tmp0 + tmp3; + tmp2 = tmp0 - tmp3 - tmp3; + + tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */ + tmp11 = tmp2 + tmp0; + tmp14 = tmp2 - tmp0 - tmp0; + + tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */ + tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */ + tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */ + + tmp10 = tmp1 + tmp0 - tmp3; + tmp12 = tmp1 - tmp0 + tmp2; + tmp13 = tmp1 - tmp2 + tmp3; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */ + + tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */ + tmp0 = tmp2 + tmp3 - z2; + tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */ + tmp2 += z2 - tmp1; + tmp3 += z2 + tmp1; + tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp13 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp13 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp14, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 9 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 9; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp0 <<= CONST_BITS; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[4]; + z3 = (INT32) wsptr[6]; + + tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */ + tmp1 = tmp0 + tmp3; + tmp2 = tmp0 - tmp3 - tmp3; + + tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */ + tmp11 = tmp2 + tmp0; + tmp14 = tmp2 - tmp0 - tmp0; + + tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */ + tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */ + tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */ + + tmp10 = tmp1 + tmp0 - tmp3; + tmp12 = tmp1 - tmp0 + tmp2; + tmp13 = tmp1 - tmp2 + tmp3; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */ + + tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */ + tmp0 = tmp2 + tmp3 - z2; + tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */ + tmp2 += z2 - tmp1; + tmp3 += z2 + tmp1; + tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 10x10 output block. + * + * Optimized algorithm with 12 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/20). + */ + +GLOBAL(void) +jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*10]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z3 += ONE << (CONST_BITS-PASS1_BITS-1); + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ + z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ + tmp10 = z3 + z1; + tmp11 = z3 - z2; + + tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */ + CONST_BITS-PASS1_BITS); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ + tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ + + tmp20 = tmp10 + tmp12; + tmp24 = tmp10 - tmp12; + tmp21 = tmp11 + tmp13; + tmp23 = tmp11 - tmp13; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z2 + z4; + tmp13 = z2 - z4; + + tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ + z5 = z3 << CONST_BITS; + + z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ + z4 = z5 + tmp12; + + tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ + tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ + + z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ + z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1)); + + tmp12 = (z1 - tmp13 - z3) << PASS1_BITS; + + tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ + tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) (tmp22 + tmp12); + wsptr[8*7] = (int) (tmp22 - tmp12); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 10 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 10; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z3 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z3 <<= CONST_BITS; + z4 = (INT32) wsptr[4]; + z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ + z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ + tmp10 = z3 + z1; + tmp11 = z3 - z2; + + tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ + tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ + + tmp20 = tmp10 + tmp12; + tmp24 = tmp10 - tmp12; + tmp21 = tmp11 + tmp13; + tmp23 = tmp11 - tmp13; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z3 <<= CONST_BITS; + z4 = (INT32) wsptr[7]; + + tmp11 = z2 + z4; + tmp13 = z2 - z4; + + tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ + + z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ + z4 = z3 + tmp12; + + tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ + tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ + + z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ + z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1)); + + tmp12 = ((z1 - tmp13) << CONST_BITS) - z3; + + tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ + tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing an 11x11 output block. + * + * Optimized algorithm with 24 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/22). + */ + +GLOBAL(void) +jpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*11]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp10 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */ + tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */ + z4 = z1 + z3; + tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */ + z4 -= z2; + tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */ + tmp21 = tmp20 + tmp23 + tmp25 - + MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */ + tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */ + tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */ + tmp24 += tmp25; + tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */ + tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */ + MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */ + tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z1 + z2; + tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */ + tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */ + tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */ + z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */ + tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */ + tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */ + z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */ + tmp11 += z1; + tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */ + tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */ + MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */ + MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 11 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 11; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp10 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp10 <<= CONST_BITS; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[4]; + z3 = (INT32) wsptr[6]; + + tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */ + tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */ + z4 = z1 + z3; + tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */ + z4 -= z2; + tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */ + tmp21 = tmp20 + tmp23 + tmp25 - + MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */ + tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */ + tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */ + tmp24 += tmp25; + tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */ + tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */ + MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */ + tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = z1 + z2; + tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */ + tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */ + tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */ + z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */ + tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */ + tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */ + z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */ + tmp11 += z1; + tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */ + tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */ + MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */ + MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 12x12 output block. + * + * Optimized algorithm with 15 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/24). + */ + +GLOBAL(void) +jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*12]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z3 += ONE << (CONST_BITS-PASS1_BITS-1); + + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ + z1 <<= CONST_BITS; + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + z2 <<= CONST_BITS; + + tmp12 = z1 - z2; + + tmp21 = z3 + tmp12; + tmp24 = z3 - tmp12; + + tmp12 = z4 + z2; + + tmp20 = tmp10 + tmp12; + tmp25 = tmp10 - tmp12; + + tmp12 = z4 - z1 - z2; + + tmp22 = tmp11 + tmp12; + tmp23 = tmp11 - tmp12; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ + tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ + + tmp10 = z1 + z3; + tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ + tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ + tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ + tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ + tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ + tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ + tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ + MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ + + z1 -= z4; + z2 -= z3; + z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ + tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ + tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 12 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 12; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z3 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z3 <<= CONST_BITS; + + z4 = (INT32) wsptr[4]; + z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + z1 = (INT32) wsptr[2]; + z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ + z1 <<= CONST_BITS; + z2 = (INT32) wsptr[6]; + z2 <<= CONST_BITS; + + tmp12 = z1 - z2; + + tmp21 = z3 + tmp12; + tmp24 = z3 - tmp12; + + tmp12 = z4 + z2; + + tmp20 = tmp10 + tmp12; + tmp25 = tmp10 - tmp12; + + tmp12 = z4 - z1 - z2; + + tmp22 = tmp11 + tmp12; + tmp23 = tmp11 - tmp12; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ + tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ + + tmp10 = z1 + z3; + tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ + tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ + tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ + tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ + tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ + tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ + tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ + MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ + + z1 -= z4; + z2 -= z3; + z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ + tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ + tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 13x13 output block. + * + * Optimized algorithm with 29 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/26). + */ + +GLOBAL(void) +jpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*13]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z1 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */ + + tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */ + tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */ + + tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */ + + tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */ + tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */ + + tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */ + + tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */ + tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */ + + tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */ + tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */ + tmp15 = z1 + z4; + tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */ + tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */ + tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */ + tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */ + tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */ + tmp11 += tmp14; + tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */ + tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */ + tmp12 += tmp14; + tmp13 += tmp14; + tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */ + tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */ + MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */ + z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */ + tmp14 += z1; + tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */ + MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 13 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 13; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z1 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z1 <<= CONST_BITS; + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[4]; + z4 = (INT32) wsptr[6]; + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */ + + tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */ + tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */ + + tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */ + + tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */ + tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */ + + tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */ + + tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */ + tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */ + + tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */ + tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */ + tmp15 = z1 + z4; + tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */ + tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */ + tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */ + tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */ + tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */ + tmp11 += tmp14; + tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */ + tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */ + tmp12 += tmp14; + tmp13 += tmp14; + tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */ + tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */ + MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */ + z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */ + tmp14 += z1; + tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */ + MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 14x14 output block. + * + * Optimized algorithm with 20 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/28). + */ + +GLOBAL(void) +jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*14]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z1 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ + z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ + z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ + + tmp10 = z1 + z2; + tmp11 = z1 + z3; + tmp12 = z1 - z4; + + tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */ + CONST_BITS-PASS1_BITS); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ + + tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ + tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ + tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ + MULTIPLY(z2, FIX(1.378756276)); /* c2 */ + + tmp20 = tmp10 + tmp13; + tmp26 = tmp10 - tmp13; + tmp21 = tmp11 + tmp14; + tmp25 = tmp11 - tmp14; + tmp22 = tmp12 + tmp15; + tmp24 = tmp12 - tmp15; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp13 = z4 << CONST_BITS; + + tmp14 = z1 + z3; + tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ + tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ + tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ + tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ + tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ + z1 -= z2; + tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */ + tmp16 += tmp15; + z1 += z4; + z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */ + tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ + tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ + z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ + tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ + tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ + + tmp13 = (z1 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) (tmp23 + tmp13); + wsptr[8*10] = (int) (tmp23 - tmp13); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 14 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 14; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z1 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z1 <<= CONST_BITS; + z4 = (INT32) wsptr[4]; + z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ + z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ + z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ + + tmp10 = z1 + z2; + tmp11 = z1 + z3; + tmp12 = z1 - z4; + + tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */ + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[6]; + + z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ + + tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ + tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ + tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ + MULTIPLY(z2, FIX(1.378756276)); /* c2 */ + + tmp20 = tmp10 + tmp13; + tmp26 = tmp10 - tmp13; + tmp21 = tmp11 + tmp14; + tmp25 = tmp11 - tmp14; + tmp22 = tmp12 + tmp15; + tmp24 = tmp12 - tmp15; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + z4 <<= CONST_BITS; + + tmp14 = z1 + z3; + tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ + tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ + tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ + tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ + tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ + z1 -= z2; + tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */ + tmp16 += tmp15; + tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */ + tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ + tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ + tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ + tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ + tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ + + tmp13 = ((z1 - z3) << CONST_BITS) + z4; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 15x15 output block. + * + * Optimized algorithm with 22 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/30). + */ + +GLOBAL(void) +jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*15]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z1 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */ + tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */ + + tmp12 = z1 - tmp10; + tmp13 = z1 + tmp11; + z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */ + + z4 = z2 - z3; + z3 += z2; + tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */ + z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */ + + tmp20 = tmp13 + tmp10 + tmp11; + tmp23 = tmp12 - tmp10 + tmp11 + z2; + + tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */ + + tmp25 = tmp13 - tmp10 - tmp11; + tmp26 = tmp12 + tmp10 - tmp11 - z2; + + tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */ + + tmp21 = tmp12 + tmp10 + tmp11; + tmp24 = tmp13 - tmp10 + tmp11; + tmp11 += tmp11; + tmp22 = z1 + tmp11; /* c10 = c6-c12 */ + tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z4 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */ + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp13 = z2 - z4; + tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */ + tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */ + tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */ + + tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */ + tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */ + z2 = z1 - z4; + tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */ + + tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */ + tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */ + tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */ + z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */ + tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */ + tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*14] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*13] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp27, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 15 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 15; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z1 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z1 <<= CONST_BITS; + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[4]; + z4 = (INT32) wsptr[6]; + + tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */ + tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */ + + tmp12 = z1 - tmp10; + tmp13 = z1 + tmp11; + z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */ + + z4 = z2 - z3; + z3 += z2; + tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */ + z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */ + + tmp20 = tmp13 + tmp10 + tmp11; + tmp23 = tmp12 - tmp10 + tmp11 + z2; + + tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */ + + tmp25 = tmp13 - tmp10 - tmp11; + tmp26 = tmp12 + tmp10 - tmp11 - z2; + + tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */ + + tmp21 = tmp12 + tmp10 + tmp11; + tmp24 = tmp13 - tmp10 + tmp11; + tmp11 += tmp11; + tmp22 = z1 + tmp11; /* c10 = c6-c12 */ + tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z4 = (INT32) wsptr[5]; + z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */ + z4 = (INT32) wsptr[7]; + + tmp13 = z2 - z4; + tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */ + tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */ + tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */ + + tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */ + tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */ + z2 = z1 - z4; + tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */ + + tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */ + tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */ + tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */ + z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */ + tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */ + tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 16x16 output block. + * + * Optimized algorithm with 28 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/32). + */ + +GLOBAL(void) +jpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*16]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ + tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + tmp12 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + z3 = z1 - z2; + z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ + z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ + + tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ + tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ + tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ + tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ + + tmp20 = tmp10 + tmp0; + tmp27 = tmp10 - tmp0; + tmp21 = tmp12 + tmp1; + tmp26 = tmp12 - tmp1; + tmp22 = tmp13 + tmp2; + tmp25 = tmp13 - tmp2; + tmp23 = tmp11 + tmp3; + tmp24 = tmp11 - tmp3; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z1 + z3; + + tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ + tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ + tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ + tmp13 = tmp10 + tmp11 + tmp12 - + MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ + z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ + tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ + tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ + z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ + tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ + tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ + z2 += z4; + z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ + tmp1 += z1; + tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ + z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ + tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ + tmp12 += z2; + z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ + tmp2 += z2; + tmp3 += z2; + z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ + tmp10 += z2; + tmp11 += z2; + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 16 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 16; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp0 <<= CONST_BITS; + + z1 = (INT32) wsptr[4]; + tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ + tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + tmp12 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[6]; + z3 = z1 - z2; + z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ + z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ + + tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ + tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ + tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ + tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ + + tmp20 = tmp10 + tmp0; + tmp27 = tmp10 - tmp0; + tmp21 = tmp12 + tmp1; + tmp26 = tmp12 - tmp1; + tmp22 = tmp13 + tmp2; + tmp25 = tmp13 - tmp2; + tmp23 = tmp11 + tmp3; + tmp24 = tmp11 - tmp3; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = z1 + z3; + + tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ + tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ + tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ + tmp13 = tmp10 + tmp11 + tmp12 - + MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ + z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ + tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ + tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ + z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ + tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ + tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ + z2 += z4; + z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ + tmp1 += z1; + tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ + z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ + tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ + tmp12 += z2; + z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ + tmp2 += z2; + tmp3 += z2; + z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ + tmp10 += z2; + tmp11 += z2; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 16x8 output block. + * + * 8-point IDCT in pass 1 (columns), 16-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_16x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*8]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * Note results are scaled up by sqrt(8) compared to a true IDCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. + * The rotator is c(-6). + */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 <<= CONST_BITS; + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z2 += ONE << (CONST_BITS-PASS1_BITS-1); + + tmp0 = z2 + z3; + tmp1 = z2 - z3; + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process 8 rows from work array, store into output array. + * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp0 <<= CONST_BITS; + + z1 = (INT32) wsptr[4]; + tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ + tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + tmp12 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[6]; + z3 = z1 - z2; + z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ + z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ + + tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ + tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ + tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ + tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ + + tmp20 = tmp10 + tmp0; + tmp27 = tmp10 - tmp0; + tmp21 = tmp12 + tmp1; + tmp26 = tmp12 - tmp1; + tmp22 = tmp13 + tmp2; + tmp25 = tmp13 - tmp2; + tmp23 = tmp11 + tmp3; + tmp24 = tmp11 - tmp3; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = z1 + z3; + + tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ + tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ + tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ + tmp13 = tmp10 + tmp11 + tmp12 - + MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ + z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ + tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ + tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ + z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ + tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ + tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ + z2 += z4; + z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ + tmp1 += z1; + tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ + z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ + tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ + tmp12 += z2; + z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ + tmp2 += z2; + tmp3 += z2; + z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ + tmp10 += z2; + tmp11 += z2; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 14x7 output block. + * + * 7-point IDCT in pass 1 (columns), 14-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_14x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*7]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp23 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp23 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp23 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ + tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ + tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ + tmp10 = z1 + z3; + z2 -= tmp10; + tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */ + tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ + tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ + tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + + tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp10 = tmp11 - tmp12; + tmp11 += tmp12; + tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ + tmp11 += tmp12; + z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ + tmp10 += z2; + tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 7 rows from work array, store into output array. + * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z1 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z1 <<= CONST_BITS; + z4 = (INT32) wsptr[4]; + z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ + z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ + z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ + + tmp10 = z1 + z2; + tmp11 = z1 + z3; + tmp12 = z1 - z4; + + tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */ + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[6]; + + z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ + + tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ + tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ + tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ + MULTIPLY(z2, FIX(1.378756276)); /* c2 */ + + tmp20 = tmp10 + tmp13; + tmp26 = tmp10 - tmp13; + tmp21 = tmp11 + tmp14; + tmp25 = tmp11 - tmp14; + tmp22 = tmp12 + tmp15; + tmp24 = tmp12 - tmp15; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + z4 <<= CONST_BITS; + + tmp14 = z1 + z3; + tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ + tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ + tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ + tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ + tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ + z1 -= z2; + tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */ + tmp16 += tmp15; + tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */ + tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ + tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ + tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ + tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ + tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ + + tmp13 = ((z1 - z3) << CONST_BITS) + z4; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 12x6 output block. + * + * 6-point IDCT in pass 1 (columns), 12-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_12x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*6]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp10 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp12 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */ + tmp11 = tmp10 + tmp20; + tmp21 = RIGHT_SHIFT(tmp10 - tmp20 - tmp20, CONST_BITS-PASS1_BITS); + tmp20 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */ + tmp20 = tmp11 + tmp10; + tmp22 = tmp11 - tmp10; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp10 = tmp11 + ((z1 + z2) << CONST_BITS); + tmp12 = tmp11 + ((z3 - z2) << CONST_BITS); + tmp11 = (z1 - z2 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) (tmp21 + tmp11); + wsptr[8*4] = (int) (tmp21 - tmp11); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 6 rows from work array, store into output array. + * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z3 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z3 <<= CONST_BITS; + + z4 = (INT32) wsptr[4]; + z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + z1 = (INT32) wsptr[2]; + z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ + z1 <<= CONST_BITS; + z2 = (INT32) wsptr[6]; + z2 <<= CONST_BITS; + + tmp12 = z1 - z2; + + tmp21 = z3 + tmp12; + tmp24 = z3 - tmp12; + + tmp12 = z4 + z2; + + tmp20 = tmp10 + tmp12; + tmp25 = tmp10 - tmp12; + + tmp12 = z4 - z1 - z2; + + tmp22 = tmp11 + tmp12; + tmp23 = tmp11 - tmp12; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ + tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ + + tmp10 = z1 + z3; + tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ + tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ + tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ + tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ + tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ + tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ + tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ + MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ + + z1 -= z4; + z2 -= z3; + z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ + tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ + tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 10x5 output block. + * + * 5-point IDCT in pass 1 (columns), 10-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_10x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*5]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp12 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp12 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp13 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp14 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */ + z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */ + z3 = tmp12 + z2; + tmp10 = z3 + z1; + tmp11 = z3 - z1; + tmp12 -= z2 << 2; + + /* Odd part */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ + tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ + tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp10 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp11 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 5 rows from work array, store into output array. + * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z3 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z3 <<= CONST_BITS; + z4 = (INT32) wsptr[4]; + z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ + z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ + tmp10 = z3 + z1; + tmp11 = z3 - z2; + + tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ + tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ + + tmp20 = tmp10 + tmp12; + tmp24 = tmp10 - tmp12; + tmp21 = tmp11 + tmp13; + tmp23 = tmp11 - tmp13; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z3 <<= CONST_BITS; + z4 = (INT32) wsptr[7]; + + tmp11 = z2 + z4; + tmp13 = z2 - z4; + + tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ + + z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ + z4 = z3 + tmp12; + + tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ + tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ + + z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ + z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1)); + + tmp12 = ((z1 - tmp13) << CONST_BITS) - z3; + + tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ + tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing an 8x4 output block. + * + * 4-point IDCT in pass 1 (columns), 8-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_8x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 4-point IDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + + tmp10 = (tmp0 + tmp2) << PASS1_BITS; + tmp12 = (tmp0 - tmp2) << PASS1_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS); + tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS); + + /* Final output stage */ + + wsptr[8*0] = (int) (tmp10 + tmp0); + wsptr[8*3] = (int) (tmp10 - tmp0); + wsptr[8*1] = (int) (tmp12 + tmp2); + wsptr[8*2] = (int) (tmp12 - tmp2); + } + + /* Pass 2: process rows from work array, store into output array. + * Note that we must descale the results by a factor of 8 == 2**3, + * and also undo the PASS1_BITS scaling. + * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part: reverse the even part of the forward DCT. + * The rotator is c(-6). + */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z2 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z3 = (INT32) wsptr[4]; + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 6x3 output block. + * + * 3-point IDCT in pass 1 (columns), 6-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_6x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[6*3]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ + tmp10 = tmp0 + tmp12; + tmp2 = tmp0 - tmp12 - tmp12; + + /* Odd part */ + + tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ + + /* Final output stage */ + + wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[6*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[6*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 3 rows from work array, store into output array. + * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 3; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp0 <<= CONST_BITS; + tmp2 = (INT32) wsptr[4]; + tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ + tmp1 = tmp0 + tmp10; + tmp11 = tmp0 - tmp10 - tmp10; + tmp10 = (INT32) wsptr[2]; + tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ + tmp10 = tmp1 + tmp0; + tmp12 = tmp1 - tmp0; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); + tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); + tmp1 = (z1 - z2 - z3) << CONST_BITS; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 6; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 4x2 output block. + * + * 2-point IDCT in pass 1 (columns), 4-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_4x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + INT32 * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + INT32 workspace[4*2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + /* Odd part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + /* Final output stage */ + + wsptr[4*0] = tmp10 + tmp0; + wsptr[4*1] = tmp10 - tmp0; + } + + /* Pass 2: process 2 rows from work array, store into output array. + * 4-point IDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. + */ + + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = wsptr[0] + ((((INT32) RANGE_CENTER) << 3) + (ONE << 2)); + tmp2 = wsptr[2]; + + tmp10 = (tmp0 + tmp2) << CONST_BITS; + tmp12 = (tmp0 - tmp2) << CONST_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = wsptr[1]; + z3 = wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+3) + & RANGE_MASK]; + + wsptr += 4; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 2x1 output block. + * + * 1-point IDCT in pass 1 (columns), 2-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_2x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1; + ISLOW_MULT_TYPE * quantptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + ISHIFT_TEMPS + + /* Pass 1: empty. */ + + /* Pass 2: process 1 row from input, store into output array. */ + + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + outptr = output_buf[0] + output_col; + + /* Even part */ + + tmp0 = DEQUANTIZE(coef_block[0], quantptr[0]); + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2); + + /* Odd part */ + + tmp1 = DEQUANTIZE(coef_block[1], quantptr[1]); + + /* Final output stage */ + + outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK]; + outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK]; +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing an 8x16 output block. + * + * 16-point IDCT in pass 1 (columns), 8-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_8x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*16]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ + tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + tmp12 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + z3 = z1 - z2; + z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ + z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ + + tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ + tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ + tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ + tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ + + tmp20 = tmp10 + tmp0; + tmp27 = tmp10 - tmp0; + tmp21 = tmp12 + tmp1; + tmp26 = tmp12 - tmp1; + tmp22 = tmp13 + tmp2; + tmp25 = tmp13 - tmp2; + tmp23 = tmp11 + tmp3; + tmp24 = tmp11 - tmp3; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z1 + z3; + + tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ + tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ + tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ + tmp13 = tmp10 + tmp11 + tmp12 - + MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ + z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ + tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ + tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ + z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ + tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ + tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ + z2 += z4; + z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ + tmp1 += z1; + tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ + z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ + tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ + tmp12 += z2; + z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ + tmp2 += z2; + tmp3 += z2; + z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ + tmp10 += z2; + tmp11 += z2; + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process rows from work array, store into output array. + * Note that we must descale the results by a factor of 8 == 2**3, + * and also undo the PASS1_BITS scaling. + * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 16; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part: reverse the even part of the forward DCT. + * The rotator is c(-6). + */ + + /* Add range center and fudge factor for final descale and range-limit. */ + z2 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + z3 = (INT32) wsptr[4]; + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 7x14 output block. + * + * 14-point IDCT in pass 1 (columns), 7-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_7x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[7*14]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z1 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ + z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ + z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ + + tmp10 = z1 + z2; + tmp11 = z1 + z3; + tmp12 = z1 - z4; + + tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */ + CONST_BITS-PASS1_BITS); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ + + tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ + tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ + tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ + MULTIPLY(z2, FIX(1.378756276)); /* c2 */ + + tmp20 = tmp10 + tmp13; + tmp26 = tmp10 - tmp13; + tmp21 = tmp11 + tmp14; + tmp25 = tmp11 - tmp14; + tmp22 = tmp12 + tmp15; + tmp24 = tmp12 - tmp15; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp13 = z4 << CONST_BITS; + + tmp14 = z1 + z3; + tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ + tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ + tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ + tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ + tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ + z1 -= z2; + tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */ + tmp16 += tmp15; + z1 += z4; + z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */ + tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ + tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ + z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ + tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ + tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ + + tmp13 = (z1 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[7*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[7*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[7*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[7*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[7*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[7*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[7*3] = (int) (tmp23 + tmp13); + wsptr[7*10] = (int) (tmp23 - tmp13); + wsptr[7*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[7*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[7*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[7*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + wsptr[7*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); + wsptr[7*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 14 rows from work array, store into output array. + * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 14; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp23 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp23 <<= CONST_BITS; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[4]; + z3 = (INT32) wsptr[6]; + + tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ + tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ + tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ + tmp10 = z1 + z3; + z2 -= tmp10; + tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */ + tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ + tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ + tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + + tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp10 = tmp11 - tmp12; + tmp11 += tmp12; + tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ + tmp11 += tmp12; + z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ + tmp10 += z2; + tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 7; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 6x12 output block. + * + * 12-point IDCT in pass 1 (columns), 6-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_6x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[6*12]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z3 += ONE << (CONST_BITS-PASS1_BITS-1); + + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ + z1 <<= CONST_BITS; + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + z2 <<= CONST_BITS; + + tmp12 = z1 - z2; + + tmp21 = z3 + tmp12; + tmp24 = z3 - tmp12; + + tmp12 = z4 + z2; + + tmp20 = tmp10 + tmp12; + tmp25 = tmp10 - tmp12; + + tmp12 = z4 - z1 - z2; + + tmp22 = tmp11 + tmp12; + tmp23 = tmp11 - tmp12; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ + tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ + + tmp10 = z1 + z3; + tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ + tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ + tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ + tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ + tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ + tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ + tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ + MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ + + z1 -= z4; + z2 -= z3; + z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ + tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ + tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ + + /* Final output stage */ + + wsptr[6*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[6*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[6*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[6*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[6*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[6*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[6*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[6*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[6*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[6*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[6*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[6*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 12 rows from work array, store into output array. + * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 12; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp10 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp10 <<= CONST_BITS; + tmp12 = (INT32) wsptr[4]; + tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */ + tmp11 = tmp10 + tmp20; + tmp21 = tmp10 - tmp20 - tmp20; + tmp20 = (INT32) wsptr[2]; + tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */ + tmp20 = tmp11 + tmp10; + tmp22 = tmp11 - tmp10; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp10 = tmp11 + ((z1 + z2) << CONST_BITS); + tmp12 = tmp11 + ((z3 - z2) << CONST_BITS); + tmp11 = (z1 - z2 - z3) << CONST_BITS; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 6; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 5x10 output block. + * + * 10-point IDCT in pass 1 (columns), 5-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_5x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[5*10]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z3 += ONE << (CONST_BITS-PASS1_BITS-1); + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ + z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ + tmp10 = z3 + z1; + tmp11 = z3 - z2; + + tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */ + CONST_BITS-PASS1_BITS); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ + tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ + + tmp20 = tmp10 + tmp12; + tmp24 = tmp10 - tmp12; + tmp21 = tmp11 + tmp13; + tmp23 = tmp11 - tmp13; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z2 + z4; + tmp13 = z2 - z4; + + tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ + z5 = z3 << CONST_BITS; + + z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ + z4 = z5 + tmp12; + + tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ + tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ + + z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ + z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1)); + + tmp12 = (z1 - tmp13 - z3) << PASS1_BITS; + + tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ + tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ + + /* Final output stage */ + + wsptr[5*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[5*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[5*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[5*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[5*2] = (int) (tmp22 + tmp12); + wsptr[5*7] = (int) (tmp22 - tmp12); + wsptr[5*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[5*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[5*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[5*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 10 rows from work array, store into output array. + * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 10; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp12 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp12 <<= CONST_BITS; + tmp13 = (INT32) wsptr[2]; + tmp14 = (INT32) wsptr[4]; + z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */ + z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */ + z3 = tmp12 + z2; + tmp10 = z3 + z1; + tmp11 = z3 - z1; + tmp12 -= z2 << 2; + + /* Odd part */ + + z2 = (INT32) wsptr[1]; + z3 = (INT32) wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ + tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ + tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 5; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 4x8 output block. + * + * 8-point IDCT in pass 1 (columns), 4-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_4x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[4*8]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * Note results are scaled up by sqrt(8) compared to a true IDCT; + * furthermore, we scale the results by 2**PASS1_BITS. + * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 4; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[4*0] = dcval; + wsptr[4*1] = dcval; + wsptr[4*2] = dcval; + wsptr[4*3] = dcval; + wsptr[4*4] = dcval; + wsptr[4*5] = dcval; + wsptr[4*6] = dcval; + wsptr[4*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. + * The rotator is c(-6). + */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 <<= CONST_BITS; + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z2 += ONE << (CONST_BITS-PASS1_BITS-1); + + tmp0 = z2 + z3; + tmp1 = z2 - z3; + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[4*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[4*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[4*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[4*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[4*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[4*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[4*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[4*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process 8 rows from work array, store into output array. + * 4-point IDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. + */ + + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp2 = (INT32) wsptr[2]; + + tmp10 = (tmp0 + tmp2) << CONST_BITS; + tmp12 = (tmp0 - tmp2) << CONST_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = (INT32) wsptr[1]; + z3 = (INT32) wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 4; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 3x6 output block. + * + * 6-point IDCT in pass 1 (columns), 3-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_3x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[3*6]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ + tmp1 = tmp0 + tmp10; + tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS); + tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ + tmp10 = tmp1 + tmp0; + tmp12 = tmp1 - tmp0; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); + tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); + tmp1 = (z1 - z2 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[3*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[3*1] = (int) (tmp11 + tmp1); + wsptr[3*4] = (int) (tmp11 - tmp1); + wsptr[3*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[3*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 6 rows from work array, store into output array. + * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6). + */ + + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 = (INT32) wsptr[0] + + ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + + (ONE << (PASS1_BITS+2))); + tmp0 <<= CONST_BITS; + tmp2 = (INT32) wsptr[2]; + tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ + tmp10 = tmp0 + tmp12; + tmp2 = tmp0 - tmp12 - tmp12; + + /* Odd part */ + + tmp12 = (INT32) wsptr[1]; + tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 3; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 2x4 output block. + * + * 4-point IDCT in pass 1 (columns), 2-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_2x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + INT32 * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + INT32 workspace[2*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 4-point IDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. + */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + + tmp10 = (tmp0 + tmp2) << CONST_BITS; + tmp12 = (tmp0 - tmp2) << CONST_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Final output stage */ + + wsptr[2*0] = tmp10 + tmp0; + wsptr[2*3] = tmp10 - tmp0; + wsptr[2*1] = tmp12 + tmp2; + wsptr[2*2] = tmp12 - tmp2; + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add range center and fudge factor for final descale and range-limit. */ + tmp10 = wsptr[0] + + ((((INT32) RANGE_CENTER) << (CONST_BITS+3)) + + (ONE << (CONST_BITS+2))); + + /* Odd part */ + + tmp0 = wsptr[1]; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS+3) + & RANGE_MASK]; + + wsptr += 2; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 1x2 output block. + * + * 2-point IDCT in pass 1 (columns), 1-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_1x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + ISHIFT_TEMPS + + /* Process 1 column from input, store into output array. */ + + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + + /* Even part */ + + tmp0 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]); + /* Add range center and fudge factor for final descale and range-limit. */ + tmp0 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2); + + /* Odd part */ + + tmp1 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]); + + /* Final output stage */ + + output_buf[0][output_col] = + range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK]; + output_buf[1][output_col] = + range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK]; +} + +#endif /* IDCT_SCALING_SUPPORTED */ +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jmemmgr.c b/widget/milsko/milskosrc/external/libjpeg/src/jmemmgr.c new file mode 100644 index 0000000000..40377de470 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jmemmgr.c @@ -0,0 +1,1115 @@ +/* + * jmemmgr.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2011-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the JPEG system-independent memory management + * routines. This code is usable across a wide variety of machines; most + * of the system dependencies have been isolated in a separate file. + * The major functions provided here are: + * * pool-based allocation and freeing of memory; + * * policy decisions about how to divide available memory among the + * virtual arrays; + * * control logic for swapping virtual arrays between main memory and + * backing storage. + * The separate system-dependent file provides the actual backing-storage + * access code, and it contains the policy decision about how much total + * main memory to use. + * This file is system-dependent in the sense that some of its functions + * are unnecessary in some systems. For example, if there is enough virtual + * memory so that backing storage will never be used, much of the virtual + * array control logic could be removed. (Of course, if you have that much + * memory then you shouldn't care about a little bit of unused code...) + */ + +#define JPEG_INTERNALS +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef NO_GETENV +#ifndef HAVE_STDLIB_H /* should declare getenv() */ +extern char * getenv JPP((const char * name)); +#endif +#endif + + +/* + * Some important notes: + * The allocation routines provided here must never return NULL. + * They should exit to error_exit if unsuccessful. + * + * It's not a good idea to try to merge the sarray and barray routines, + * even though they are textually almost the same, because samples are + * usually stored as bytes while coefficients are shorts or ints. Thus, + * in machines where byte pointers have a different representation from + * word pointers, the resulting machine code could not be the same. + */ + + +/* + * Many machines require storage alignment: longs must start on 4-byte + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + * always returns pointers that are multiples of the worst-case alignment + * requirement, and we had better do so too. + * There isn't any really portable way to determine the worst-case alignment + * requirement. This module assumes that the alignment requirement is + * multiples of sizeof(ALIGN_TYPE). + * By default, we define ALIGN_TYPE as double. This is necessary on some + * workstations (where doubles really do need 8-byte alignment) and will work + * fine on nearly everything. If your machine has lesser alignment needs, + * you can save a few bytes by making ALIGN_TYPE smaller. + * The only place I know of where this will NOT work is certain Macintosh + * 680x0 compilers that define double as a 10-byte IEEE extended float. + * Doing 10-byte alignment is counterproductive because longwords won't be + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + * such a compiler. + */ + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ +#define ALIGN_TYPE double +#endif + + +/* + * We allocate objects from "pools", where each pool is gotten with a single + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + * overhead within a pool, except for alignment padding. Each pool has a + * header with a link to the next pool of the same class. + * Small and large pool headers are identical except that the latter's + * link pointer must be FAR on 80x86 machines. + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + * of the alignment requirement of ALIGN_TYPE. + */ + +typedef union small_pool_struct * small_pool_ptr; + +typedef union small_pool_struct { + struct { + small_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} small_pool_hdr; + +typedef union large_pool_struct FAR * large_pool_ptr; + +typedef union large_pool_struct { + struct { + large_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} large_pool_hdr; + + +/* + * Here is the full definition of a memory manager object. + */ + +typedef struct { + struct jpeg_memory_mgr pub; /* public fields */ + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + /* Since we only have one lifetime class of virtual arrays, only one + * linked list is necessary (for each datatype). Note that the virtual + * array control blocks being linked together are actually stored somewhere + * in the small-pool list. + */ + jvirt_sarray_ptr virt_sarray_list; + jvirt_barray_ptr virt_barray_list; + + /* This counts total space obtained from jpeg_get_small/large */ + size_t total_space_allocated; + + /* alloc_sarray and alloc_barray set this value for use by virtual + * array routines. + */ + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ +} my_memory_mgr; + +typedef my_memory_mgr * my_mem_ptr; + + +/* + * The control blocks for virtual arrays. + * Note that these blocks are allocated in the "small" pool area. + * System-dependent info for the associated backing store (if any) is hidden + * inside the backing_store_info struct. + */ + +struct jvirt_sarray_control { + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + +struct jvirt_barray_control { + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_barray_ptr next; /* link to next virtual barray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +LOCAL(void) +print_mem_stats (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + + /* Since this is only a debugging stub, we can cheat a little by using + * fprintf directly rather than going through the trace message code. + * This is helpful because message parm array can't handle longs. + */ + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + pool_id, (long) mem->total_space_allocated); + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + lhdr_ptr = lhdr_ptr->hdr.next) { + fprintf(stderr, " Large chunk used %ld\n", + (long) lhdr_ptr->hdr.bytes_used); + } + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + shdr_ptr = shdr_ptr->hdr.next) { + fprintf(stderr, " Small chunk used %ld free %ld\n", + (long) shdr_ptr->hdr.bytes_used, + (long) shdr_ptr->hdr.bytes_left); + } +} + +#endif /* MEM_STATS */ + + +LOCAL(noreturn_t) +out_of_memory (j_common_ptr cinfo, int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ +#endif + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); +} + + +/* + * Allocation of "small" objects. + * + * For these, we use pooled storage. When a new pool must be created, + * we try to get enough space for the current request plus a "slop" factor, + * where the slop will be the amount of leftover space in the new pool. + * The speed vs. space tradeoff is largely determined by the slop values. + * A different slop value is provided for each pool class (lifetime), + * and we also distinguish the first pool of a class from later ones. + * NOTE: the values given work fairly well on both 16- and 32-bit-int + * machines, but may be too small if longs are 64 bits or more. + */ + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = +{ + 1600, /* first PERMANENT pool */ + 16000 /* first IMAGE pool */ +}; + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = +{ + 0, /* additional PERMANENT pools */ + 5000 /* additional IMAGE pools */ +}; + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + +METHODDEF(void *) +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "small" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr hdr_ptr, prev_hdr_ptr; + size_t odd_bytes, min_request, slop; + char * data_ptr; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) MAX_ALLOC_CHUNK - SIZEOF(small_pool_hdr)) + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* See if space is available in any existing pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + prev_hdr_ptr = NULL; + hdr_ptr = mem->small_list[pool_id]; + while (hdr_ptr != NULL) { + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + break; /* found pool with enough space */ + prev_hdr_ptr = hdr_ptr; + hdr_ptr = hdr_ptr->hdr.next; + } + + /* Time to make a new pool? */ + if (hdr_ptr == NULL) { + /* min_request is what we need now, slop is what will be leftover */ + min_request = sizeofobject + SIZEOF(small_pool_hdr); + if (prev_hdr_ptr == NULL) /* first pool in class? */ + slop = first_pool_slop[pool_id]; + else + slop = extra_pool_slop[pool_id]; + /* Don't ask for more than MAX_ALLOC_CHUNK */ + if (slop > (size_t) MAX_ALLOC_CHUNK - min_request) + slop = (size_t) MAX_ALLOC_CHUNK - min_request; + /* Try to get space, if fail reduce slop and try again */ + for (;;) { + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + if (hdr_ptr != NULL) + break; + slop /= 2; + if (slop < MIN_SLOP) /* give up when it gets real small */ + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + } + mem->total_space_allocated += min_request + slop; + /* Success, initialize the new pool header and add to end of list */ + hdr_ptr->hdr.next = NULL; + hdr_ptr->hdr.bytes_used = 0; + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + if (prev_hdr_ptr == NULL) /* first pool in class? */ + mem->small_list[pool_id] = hdr_ptr; + else + prev_hdr_ptr->hdr.next = hdr_ptr; + } + + /* OK, allocate the object from the current pool */ + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + hdr_ptr->hdr.bytes_used += sizeofobject; + hdr_ptr->hdr.bytes_left -= sizeofobject; + + return (void *) data_ptr; +} + + +/* + * Allocation of "large" objects. + * + * The external semantics of these are the same as "small" objects, + * except that FAR pointers are used on 80x86. However the pool + * management heuristics are quite different. We assume that each + * request is large enough that it may as well be passed directly to + * jpeg_get_large; the pool management just links everything together + * so that we can free it all on demand. + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + * structures. The routines that create these structures (see below) + * deliberately bunch rows together to ensure a large request size. + */ + +METHODDEF(void FAR *) +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "large" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + large_pool_ptr hdr_ptr; + size_t odd_bytes; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) MAX_ALLOC_CHUNK - SIZEOF(large_pool_hdr)) + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* Always make a new pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + SIZEOF(large_pool_hdr)); + if (hdr_ptr == NULL) + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + /* Success, initialize the new pool header and add to list */ + hdr_ptr->hdr.next = mem->large_list[pool_id]; + /* We maintain space counts in each pool header for statistical purposes, + * even though they are not needed for allocation. + */ + hdr_ptr->hdr.bytes_used = sizeofobject; + hdr_ptr->hdr.bytes_left = 0; + mem->large_list[pool_id] = hdr_ptr; + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ +} + + +/* + * Creation of 2-D sample arrays. + * The pointers are in near heap, the samples themselves in FAR heap. + * + * To minimize allocation overhead and to allow I/O of large contiguous + * blocks, we allocate the sample rows in groups of as many rows as possible + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + * NB: the virtual array control routines, later in this file, know about + * this chunking of rows. The rowsperchunk value is left in the mem manager + * object so that it can be saved away if this sarray is the workspace for + * a virtual array. + */ + +METHODDEF(JSAMPARRAY) +alloc_sarray (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +/* Allocate a 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JSAMPARRAY result; + JSAMPROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK - SIZEOF(large_pool_hdr)) / + ((long) samplesperrow * SIZEOF(JSAMPLE)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + (size_t) numrows * SIZEOF(JSAMPROW)); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + (size_t) rowsperchunk * (size_t) samplesperrow * SIZEOF(JSAMPLE)); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += samplesperrow; + } + } + + return result; +} + + +/* + * Creation of 2-D coefficient-block arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF(JBLOCKARRAY) +alloc_barray (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, JDIMENSION numrows) +/* Allocate a 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JBLOCKARRAY result; + JBLOCKROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK - SIZEOF(large_pool_hdr)) / + ((long) blocksperrow * SIZEOF(JBLOCK)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + (size_t) numrows * SIZEOF(JBLOCKROW)); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + (size_t) rowsperchunk * (size_t) blocksperrow * SIZEOF(JBLOCK)); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += blocksperrow; + } + } + + return result; +} + + +/* + * About virtual array management: + * + * The above "normal" array routines are only used to allocate strip buffers + * (as wide as the image, but just a few rows high). Full-image-sized buffers + * are handled as "virtual" arrays. The array is still accessed a strip at a + * time, but the memory manager must save the whole array for repeated + * accesses. The intended implementation is that there is a strip buffer in + * memory (as high as is possible given the desired memory limit), plus a + * backing file that holds the rest of the array. + * + * The request_virt_array routines are told the total size of the image and + * the maximum number of rows that will be accessed at once. The in-memory + * buffer must be at least as large as the maxaccess value. + * + * The request routines create control blocks but not the in-memory buffers. + * That is postponed until realize_virt_arrays is called. At that time the + * total amount of space needed is known (approximately, anyway), so free + * memory can be divided up fairly. + * + * The access_virt_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. The access routines are also responsible for pre-zeroing + * any newly accessed rows, if pre-zeroing was requested. + * + * In current usage, the access requests are usually for nonoverlapping + * strips; that is, successive access start_row numbers differ by exactly + * num_rows = maxaccess. This means we can get good performance with simple + * buffer dump/reload logic, by making the in-memory buffer be a multiple + * of the access height; then there will never be accesses across bufferload + * boundaries. The code will still work with overlapping access requests, + * but it doesn't handle bufferload overlaps very efficiently. + */ + + +METHODDEF(jvirt_sarray_ptr) +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION samplesperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_sarray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_sarray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->samplesperrow = samplesperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + mem->virt_sarray_list = result; + + return result; +} + + +METHODDEF(jvirt_barray_ptr) +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_barray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_barray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->blocksperrow = blocksperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + mem->virt_barray_list = result; + + return result; +} + + +METHODDEF(void) +realize_virt_arrays (j_common_ptr cinfo) +/* Allocate the in-memory buffers for any unrealized virtual arrays */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + long bytesperrow, space_per_minheight, maximum_space; + long avail_mem, minheights, max_minheights; + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + /* Compute the minimum space needed (maxaccess rows in each buffer) + * and the maximum space needed (full image height in each buffer). + * These may be of use to the system-dependent jpeg_mem_available routine. + */ + space_per_minheight = 0; + maximum_space = 0; + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + bytesperrow = (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + space_per_minheight += (long) sptr->maxaccess * bytesperrow; + maximum_space += (long) sptr->rows_in_array * bytesperrow; + } + } + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + bytesperrow = (long) bptr->blocksperrow * SIZEOF(JBLOCK); + space_per_minheight += (long) bptr->maxaccess * bytesperrow; + maximum_space += (long) bptr->rows_in_array * bytesperrow; + } + } + + if (space_per_minheight <= 0) + return; /* no unrealized arrays, no work */ + + /* Determine amount of memory to actually use; this is system-dependent. */ + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + (long) mem->total_space_allocated); + + /* If the maximum space needed is available, make all the buffers full + * height; otherwise parcel it out with the same number of minheights + * in each buffer. + */ + if (avail_mem >= maximum_space) + max_minheights = 1000000000L; + else { + max_minheights = avail_mem / space_per_minheight; + /* If there doesn't seem to be enough space, try to get the minimum + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + */ + if (max_minheights <= 0) + max_minheights = 1; + } + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + sptr->rows_in_mem = sptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + (long) sptr->rows_in_array * + (long) sptr->samplesperrow * + (long) SIZEOF(JSAMPLE)); + sptr->b_s_open = TRUE; + } + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + sptr->samplesperrow, sptr->rows_in_mem); + sptr->rowsperchunk = mem->last_rowsperchunk; + sptr->cur_start_row = 0; + sptr->first_undef_row = 0; + sptr->dirty = FALSE; + } + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + bptr->rows_in_mem = bptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + (long) bptr->rows_in_array * + (long) bptr->blocksperrow * + (long) SIZEOF(JBLOCK)); + bptr->b_s_open = TRUE; + } + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + bptr->blocksperrow, bptr->rows_in_mem); + bptr->rowsperchunk = mem->last_rowsperchunk; + bptr->cur_start_row = 0; + bptr->first_undef_row = 0; + bptr->dirty = FALSE; + } + } +} + + +LOCAL(void) +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual sample array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + file_offset = (long) ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +LOCAL(void) +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual coefficient-block array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + file_offset = (long) ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +METHODDEF(JSAMPARRAY) +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual sample array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row + ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_sarray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_sarray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +METHODDEF(JBLOCKARRAY) +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual block array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row + ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_barray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_barray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +/* + * Release all objects belonging to a specified pool. + */ + +METHODDEF(void) +free_pool (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + size_t space_freed; + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + +#ifdef MEM_STATS + if (cinfo->err->trace_level > 1) + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ +#endif + + /* If freeing IMAGE pool, close any virtual arrays first */ + if (pool_id == JPOOL_IMAGE) { + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->b_s_open) { /* there may be no backing store */ + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + } + } + mem->virt_sarray_list = NULL; + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->b_s_open) { /* there may be no backing store */ + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + } + } + mem->virt_barray_list = NULL; + } + + /* Release large objects */ + lhdr_ptr = mem->large_list[pool_id]; + mem->large_list[pool_id] = NULL; + + while (lhdr_ptr != NULL) { + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + space_freed = lhdr_ptr->hdr.bytes_used + + lhdr_ptr->hdr.bytes_left + + SIZEOF(large_pool_hdr); + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + lhdr_ptr = next_lhdr_ptr; + } + + /* Release small objects */ + shdr_ptr = mem->small_list[pool_id]; + mem->small_list[pool_id] = NULL; + + while (shdr_ptr != NULL) { + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + space_freed = shdr_ptr->hdr.bytes_used + + shdr_ptr->hdr.bytes_left + + SIZEOF(small_pool_hdr); + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + shdr_ptr = next_shdr_ptr; + } +} + + +/* + * Close up shop entirely. + * Note that this cannot be called unless cinfo->mem is non-NULL. + */ + +METHODDEF(void) +self_destruct (j_common_ptr cinfo) +{ + int pool; + + /* Close all backing store, release all memory. + * Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + free_pool(cinfo, pool); + } + + /* Release the memory manager control block too. */ + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + cinfo->mem = NULL; /* ensures I will be called only once */ + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ +} + + +/* + * Memory manager initialization. + * When this is called, only the error manager pointer is valid in cinfo! + */ + +GLOBAL(void) +jinit_memory_mgr (j_common_ptr cinfo) +{ + my_mem_ptr mem; + long max_to_use; + int pool; + size_t test_mac; + + cinfo->mem = NULL; /* for safety if init fails */ + + /* Check for configuration errors. + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + * doesn't reflect any real hardware alignment requirement. + * The test is a little tricky: for X>0, X and X-1 have no one-bits + * in common if and only if X is a power of 2, ie has only one one-bit. + * Some compilers may give an "unreachable code" warning here; ignore it. + */ + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + * a multiple of SIZEOF(ALIGN_TYPE). + * Again, an "unreachable code" warning may be ignored here. + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + */ + test_mac = (size_t) MAX_ALLOC_CHUNK; + if ((long) test_mac != MAX_ALLOC_CHUNK || + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + /* Attempt to allocate memory manager's control block */ + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + if (mem == NULL) { + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + } + + /* OK, fill in the method pointers */ + mem->pub.alloc_small = alloc_small; + mem->pub.alloc_large = alloc_large; + mem->pub.alloc_sarray = alloc_sarray; + mem->pub.alloc_barray = alloc_barray; + mem->pub.request_virt_sarray = request_virt_sarray; + mem->pub.request_virt_barray = request_virt_barray; + mem->pub.realize_virt_arrays = realize_virt_arrays; + mem->pub.access_virt_sarray = access_virt_sarray; + mem->pub.access_virt_barray = access_virt_barray; + mem->pub.free_pool = free_pool; + mem->pub.self_destruct = self_destruct; + + /* Make MAX_ALLOC_CHUNK accessible to other modules */ + mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK; + + /* Initialize working state */ + mem->pub.max_memory_to_use = max_to_use; + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + mem->small_list[pool] = NULL; + mem->large_list[pool] = NULL; + } + mem->virt_sarray_list = NULL; + mem->virt_barray_list = NULL; + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + /* Declare ourselves open for business */ + cinfo->mem = &mem->pub; + + /* Check for an environment variable JPEGMEM; if found, override the + * default max_memory setting from jpeg_mem_init. Note that the + * surrounding application may again override this value. + * If your system doesn't support getenv(), define NO_GETENV to disable + * this feature. + */ +#ifndef NO_GETENV + { char * memenv; + + if ((memenv = getenv("JPEGMEM")) != NULL) { + char ch = 'x'; + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + if (ch == 'm' || ch == 'M') + max_to_use *= 1000L; + mem->pub.max_memory_to_use = max_to_use * 1000L; + } + } + } +#endif + +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jmemnobs.c b/widget/milsko/milskosrc/external/libjpeg/src/jmemnobs.c new file mode 100644 index 0000000000..a364cd8223 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jmemnobs.c @@ -0,0 +1,113 @@ +/* + * jmemnobs.c + * + * Copyright (C) 1992-1996, Thomas G. Lane. + * Modified 2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a really simple implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that no backing-store files are needed: all required space + * can be obtained from malloc(). + * This is very portable in the sense that it'll compile on almost anything, + * but you'd better have lots of main memory (or virtual memory) if you want + * to process big images. + * Note that the max_memory_to_use option is respected by this implementation. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + */ + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + if (cinfo->mem->max_memory_to_use) + return cinfo->mem->max_memory_to_use - already_allocated; + + /* Here we say, "we got all you want bud!" */ + return max_bytes_needed; +} + + +/* + * Backing store (temporary file) management. + * Since jpeg_mem_available always promised the moon, + * this should never be called and we can just error out. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + ERREXIT(cinfo, JERR_NO_BACKING_STORE); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. Here, there isn't any. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + return 0; /* just set max_memory_to_use to 0 */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jquant1.c b/widget/milsko/milskosrc/external/libjpeg/src/jquant1.c new file mode 100644 index 0000000000..60b1843e73 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jquant1.c @@ -0,0 +1,851 @@ +/* + * jquant1.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2011-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines provide mapping to a fixed color map using equally spaced + * color values. Optional Floyd-Steinberg or ordered dithering is available. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * The main purpose of 1-pass quantization is to provide a fast, if not very + * high quality, colormapped output capability. A 2-pass quantizer usually + * gives better visual quality; however, for quantized grayscale output this + * quantizer is perfectly adequate. Dithering is highly recommended with this + * quantizer, though you can turn it off if you really want to. + * + * In 1-pass quantization the colormap must be chosen in advance of seeing the + * image. We use a map consisting of all combinations of Ncolors[i] color + * values for the i'th component. The Ncolors[] values are chosen so that + * their product, the total number of colors, is no more than that requested. + * (In most cases, the product will be somewhat less.) + * + * Since the colormap is orthogonal, the representative value for each color + * component can be determined without considering the other components; + * then these indexes can be combined into a colormap index by a standard + * N-dimensional-array-subscript calculation. Most of the arithmetic involved + * can be precalculated and stored in the lookup table colorindex[]. + * colorindex[i][j] maps pixel value j in component i to the nearest + * representative value (grid plane) for that component; this index is + * multiplied by the array stride for component i, so that the + * index of the colormap entry closest to a given pixel value is just + * sum( colorindex[component-number][pixel-component-value] ) + * Aside from being fast, this scheme allows for variable spacing between + * representative values with no additional lookup cost. + * + * If gamma correction has been applied in color conversion, it might be wise + * to adjust the color grid spacing so that the representative colors are + * equidistant in linear space. At this writing, gamma correction is not + * implemented by jdcolor, so nothing is done here. + */ + + +/* Declarations for ordered dithering. + * + * We use a standard 16x16 ordered dither array. The basic concept of ordered + * dithering is described in many references, for instance Dale Schumacher's + * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). + * In place of Schumacher's comparisons against a "threshold" value, we add a + * "dither" value to the input pixel and then round the result to the nearest + * output value. The dither value is equivalent to (0.5 - threshold) times + * the distance between output values. For ordered dithering, we assume that + * the output colors are equally spaced; if not, results will probably be + * worse, since the dither may be too much or too little at a given point. + * + * The normal calculation would be to form pixel value + dither, range-limit + * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. + * We can skip the separate range-limiting step by extending the colorindex + * table in both directions. + */ + +#define ODITHER_SIZE 16 /* dimension of dither matrix */ +/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ +#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ +#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ + +typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; +typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; + +static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { + /* Bayer's order-4 dither array. Generated by the code given in + * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. + * The values in this array must range from 0 to ODITHER_CELLS-1. + */ + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, + { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, + { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, + { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, + { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, + { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, + { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, + { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, + { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, + { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, + { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, + { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, + { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, + { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, + { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, + { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } +}; + + +/* Declarations for Floyd-Steinberg dithering. + * + * Errors are accumulated into the array fserrors[], at a resolution of + * 1/16th of a pixel count. The error at a given pixel is propagated + * to its not-yet-processed neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * We can get away with a single array (holding one row's worth of errors) + * by using it to store the current row's errors at pixel columns not yet + * processed, but the next row's errors at columns already processed. We + * need only a few extra variables to hold the errors immediately around the + * current column. (If we are lucky, those variables are in registers, but + * even if not, they're probably cheaper to access than array elements are.) + * + * The fserrors[] array is indexed [component#][position]. + * We provide (#columns + 2) entries per component; the extra entry at each + * end saves us from special-casing the first and last pixels. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error array; so it is allocated with alloc_large. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef INT16 FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits */ +typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + + +/* Private subobject */ + +#define MAX_Q_COMPS 4 /* max components I can handle */ + +typedef struct { + struct jpeg_color_quantizer pub; /* public fields */ + + /* Initially allocated colormap is saved here */ + JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ + int sv_actual; /* number of entries in use */ + + JSAMPARRAY colorindex; /* Precomputed mapping for speed */ + /* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied as described above. Since colormap indexes must fit into + * JSAMPLEs, the entries of this array will too. + */ + boolean is_padded; /* is the colorindex padded for odither? */ + + int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ + + /* Variables for ordered dithering */ + int row_index; /* cur row's vertical index in dither matrix */ + ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ + + /* Variables for Floyd-Steinberg dithering */ + FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ + boolean on_odd_row; /* flag to remember which row we are on */ +} my_cquantizer; + +typedef my_cquantizer * my_cquantize_ptr; + + +/* + * Policy-making subroutines for create_colormap and create_colorindex. + * These routines determine the colormap to be used. The rest of the module + * only assumes that the colormap is orthogonal. + * + * * select_ncolors decides how to divvy up the available colors + * among the components. + * * output_value defines the set of representative values for a component. + * * largest_input_value defines the mapping from input values to + * representative values for a component. + * Note that the latter two routines may impose different policies for + * different components, though this is not currently done. + */ + + +LOCAL(int) +select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) +/* Determine allocation of desired colors to components, */ +/* and fill in Ncolors[] array to indicate choice. */ +/* Return value is total number of colors (product of Ncolors[] values). */ +{ + int nc = cinfo->out_color_components; /* number of color components */ + int max_colors = cinfo->desired_number_of_colors; + int total_colors, iroot, i, j; + boolean changed; + long temp; + static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; + + /* We can allocate at least the nc'th root of max_colors per component. */ + /* Compute floor(nc'th root of max_colors). */ + iroot = 1; + do { + iroot++; + temp = iroot; /* set temp = iroot ** nc */ + for (i = 1; i < nc; i++) + temp *= iroot; + } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ + iroot--; /* now iroot = floor(root) */ + + /* Must have at least 2 color values per component */ + if (iroot < 2) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); + + /* Initialize to iroot color values for each component */ + total_colors = 1; + for (i = 0; i < nc; i++) { + Ncolors[i] = iroot; + total_colors *= iroot; + } + /* We may be able to increment the count for one or more components without + * exceeding max_colors, though we know not all can be incremented. + * Sometimes, the first component can be incremented more than once! + * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) + * In RGB colorspace, try to increment G first, then R, then B. + */ + do { + changed = FALSE; + for (i = 0; i < nc; i++) { + j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); + /* calculate new total_colors if Ncolors[j] is incremented */ + temp = total_colors / Ncolors[j]; + temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ + if (temp > (long) max_colors) + break; /* won't fit, done with this pass */ + Ncolors[j]++; /* OK, apply the increment */ + total_colors = (int) temp; + changed = TRUE; + } + } while (changed); + + return total_colors; +} + + +LOCAL(int) +output_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return j'th output value, where j will range from 0 to maxj */ +/* The output values must fall in 0..MAXJSAMPLE in increasing order */ +{ + /* We always provide values 0 and MAXJSAMPLE for each component; + * any additional values are equally spaced between these limits. + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ + return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); +} + + +LOCAL(int) +largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return largest input value that should map to j'th output value */ +/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ +{ + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); +} + + +/* + * Create the colormap. + */ + +LOCAL(void) +create_colormap (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colormap; /* Created colormap */ + int total_colors; /* Number of distinct output colors */ + int i,j,k, nci, blksize, blkdist, ptr, val; + + /* Select number of colors for each component */ + total_colors = select_ncolors(cinfo, cquantize->Ncolors); + + /* Report selected color counts */ + if (cinfo->out_color_components == 3) + TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, + total_colors, cquantize->Ncolors[0], + cquantize->Ncolors[1], cquantize->Ncolors[2]); + else + TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); + + /* Allocate and fill in the colormap. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colormap entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + /* Compute j'th output value (out of nci) for component */ + val = output_value(cinfo, i, j, nci-1); + /* Fill in all colormap entries that have this value of this component */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = (JSAMPLE) val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + } + + /* Save the colormap in private storage, + * where it will survive color quantization mode changes. + */ + cquantize->sv_colormap = colormap; + cquantize->sv_actual = total_colors; +} + + +/* + * Create the color index table. + */ + +LOCAL(void) +create_colorindex (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPROW indexptr; + int i,j,k, nci, blksize, val, pad; + + /* For ordered dither, we pad the color index tables by MAXJSAMPLE in + * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). + * This is not necessary in the other dithering modes. However, we + * flag whether it was done in case user changes dithering mode. + */ + if (cinfo->dither_mode == JDITHER_ORDERED) { + pad = MAXJSAMPLE*2; + cquantize->is_padded = TRUE; + } else { + pad = 0; + cquantize->is_padded = FALSE; + } + + cquantize->colorindex = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1 + pad), + (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + blksize = cquantize->sv_actual; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colorindex entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blksize / nci; + + /* adjust colorindex pointers to provide padding at negative indexes. */ + if (pad) + cquantize->colorindex[i] += MAXJSAMPLE; + + /* in loop, val = index of current output value, */ + /* and k = largest j that maps to current val */ + indexptr = cquantize->colorindex[i]; + val = 0; + k = largest_input_value(cinfo, i, 0, nci-1); + for (j = 0; j <= MAXJSAMPLE; j++) { + while (j > k) /* advance val if past boundary */ + k = largest_input_value(cinfo, i, ++val, nci-1); + /* premultiply so that no multiplication needed in main processing */ + indexptr[j] = (JSAMPLE) (val * blksize); + } + /* Pad at both ends if necessary */ + if (pad) + for (j = 1; j <= MAXJSAMPLE; j++) { + indexptr[-j] = indexptr[0]; + indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; + } + } +} + + +/* + * Create an ordered-dither array for a component having ncolors + * distinct output values. + */ + +LOCAL(ODITHER_MATRIX_PTR) +make_odither_array (j_decompress_ptr cinfo, int ncolors) +{ + ODITHER_MATRIX_PTR odither; + int j,k; + INT32 num,den; + + odither = (ODITHER_MATRIX_PTR) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(ODITHER_MATRIX)); + /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). + * Hence the dither value for the matrix cell with fill order f + * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). + * On 16-bit-int machine, be careful to avoid overflow. + */ + den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); + for (j = 0; j < ODITHER_SIZE; j++) { + for (k = 0; k < ODITHER_SIZE; k++) { + num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) + * MAXJSAMPLE; + /* Ensure round towards zero despite C's lack of consistency + * about rounding negative values in integer division... + */ + odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); + } + } + return odither; +} + + +/* + * Create the ordered-dither tables. + * Components having the same number of representative colors may + * share a dither table. + */ + +LOCAL(void) +create_odither_tables (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + ODITHER_MATRIX_PTR odither; + int i, j, nci; + + for (i = 0; i < cinfo->out_color_components; i++) { + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + odither = NULL; /* search for matching prior component */ + for (j = 0; j < i; j++) { + if (nci == cquantize->Ncolors[j]) { + odither = cquantize->odither[j]; + break; + } + } + if (odither == NULL) /* need a new table? */ + odither = make_odither_array(cinfo, nci); + cquantize->odither[i] = odither; + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colorindex = cquantize->colorindex; + register int pixcode, ci; + register JSAMPROW ptrin, ptrout; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + register int nc = cinfo->out_color_components; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); + } + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW ptrin, ptrout; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + int * dither; /* points to active row of dither matrix */ + int row_index, col_index; /* current indexes into dither matrix */ + int nc = cinfo->out_color_components; + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + FMEMZERO((void FAR *) output_buf[row], (size_t) width * SIZEOF(JSAMPLE)); + row_index = cquantize->row_index; + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + colorindex_ci = cquantize->colorindex[ci]; + dither = cquantize->odither[ci][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, + * select output value, accumulate into output code for this pixel. + * Range-limiting need not be done explicitly, as we have extended + * the colorindex table to produce the right answers for out-of-range + * inputs. The maximum dither is +- MAXJSAMPLE; this sets the + * required amount of padding. + */ + *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; + input_ptr += nc; + output_ptr++; + col_index = (col_index + 1) & ODITHER_MASK; + } + } + /* Advance row index for next row */ + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int * dither0; /* points to active row of dither matrix */ + int * dither1; + int * dither2; + int row_index, col_index; /* current indexes into dither matrix */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + row_index = cquantize->row_index; + input_ptr = input_buf[row]; + output_ptr = output_buf[row]; + dither0 = cquantize->odither[0][row_index]; + dither1 = cquantize->odither[1][row_index]; + dither2 = cquantize->odither[2][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + + dither0[col_index]]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + + dither1[col_index]]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + + dither2[col_index]]); + *output_ptr++ = (JSAMPLE) pixcode; + col_index = (col_index + 1) & ODITHER_MASK; + } + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register LOCFSERROR cur; /* current error or pixel value */ + LOCFSERROR belowerr; /* error for pixel below cur */ + LOCFSERROR bpreverr; /* error for below/prev col */ + LOCFSERROR bnexterr; /* error for below/next col */ + LOCFSERROR delta; + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + JSAMPROW colormap_ci; + int pixcode; + int nc = cinfo->out_color_components; + int dir; /* 1 for left-to-right, -1 for right-to-left */ + int dirnc; /* dir * nc */ + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + FMEMZERO((void FAR *) output_buf[row], (size_t) width * SIZEOF(JSAMPLE)); + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + input_ptr += (width-1) * nc; /* so point to rightmost pixel */ + output_ptr += width-1; + dir = -1; + dirnc = -nc; + errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ + } else { + /* work left to right in this row */ + dir = 1; + dirnc = nc; + errorptr = cquantize->fserrors[ci]; /* => entry before first column */ + } + colorindex_ci = cquantize->colorindex[ci]; + colormap_ci = cquantize->sv_colormap[ci]; + /* Preset error values: no error propagated to first pixel from left */ + cur = 0; + /* and no error propagated to row below yet */ + belowerr = bpreverr = 0; + + for (col = width; col > 0; col--) { + /* cur holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE; this sets the required size + * of the range_limit array. + */ + cur += GETJSAMPLE(*input_ptr); + cur = GETJSAMPLE(range_limit[cur]); + /* Select output value, accumulate into output code for this pixel */ + pixcode = GETJSAMPLE(colorindex_ci[cur]); + *output_ptr += (JSAMPLE) pixcode; + /* Compute actual representation error at this pixel */ + /* Note: we can do this even though we don't have the final */ + /* pixel code, because the colormap is orthogonal. */ + cur -= GETJSAMPLE(colormap_ci[pixcode]); + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + bnexterr = cur; + delta = cur * 2; + cur += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr + cur); + cur += delta; /* form error * 5 */ + bpreverr = belowerr + cur; + belowerr = bnexterr; + cur += delta; /* form error * 7 */ + /* At this point cur contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + input_ptr += dirnc; /* advance input ptr to next column */ + output_ptr += dir; /* advance output ptr to next column */ + errorptr += dir; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error value into the + * final fserrors[] entry. Note we need not unload belowerr because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ + } + cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); + } +} + + +/* + * Allocate workspace for Floyd-Steinberg errors. + */ + +LOCAL(void) +alloc_fs_workspace (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + arraysize = ((size_t) cinfo->output_width + (size_t) 2) * SIZEOF(FSERROR); + for (i = 0; i < cinfo->out_color_components; i++) { + cquantize->fserrors[i] = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + } +} + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF(void) +start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + /* Install my colormap. */ + cinfo->colormap = cquantize->sv_colormap; + cinfo->actual_number_of_colors = cquantize->sv_actual; + + /* Initialize for desired dithering mode. */ + switch (cinfo->dither_mode) { + case JDITHER_NONE: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = color_quantize3; + else + cquantize->pub.color_quantize = color_quantize; + break; + case JDITHER_ORDERED: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = quantize3_ord_dither; + else + cquantize->pub.color_quantize = quantize_ord_dither; + cquantize->row_index = 0; /* initialize state for ordered dither */ + /* If user changed to ordered dither from another mode, + * we must recreate the color index table with padding. + * This will cost extra space, but probably isn't very likely. + */ + if (! cquantize->is_padded) + create_colorindex(cinfo); + /* Create ordered-dither tables if we didn't already. */ + if (cquantize->odither[0] == NULL) + create_odither_tables(cinfo); + break; + case JDITHER_FS: + cquantize->pub.color_quantize = quantize_fs_dither; + cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ + /* Allocate Floyd-Steinberg workspace if didn't already. */ + if (cquantize->fserrors[0] == NULL) + alloc_fs_workspace(cinfo); + /* Initialize the propagated errors to zero. */ + arraysize = ((size_t) cinfo->output_width + (size_t) 2) * SIZEOF(FSERROR); + for (i = 0; i < cinfo->out_color_components; i++) + FMEMZERO((void FAR *) cquantize->fserrors[i], arraysize); + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } +} + + +/* + * Finish up at the end of the pass. + */ + +METHODDEF(void) +finish_pass_1_quant (j_decompress_ptr cinfo) +{ + /* no work in 1-pass case */ +} + + +/* + * Switch to a new external colormap between output passes. + * Shouldn't get to this module! + */ + +METHODDEF(void) +new_color_map_1_quant (j_decompress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + + +/* + * Module initialization routine for 1-pass color quantization. + */ + +GLOBAL(void) +jinit_1pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + + cquantize = (my_cquantize_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_cquantizer)); + cinfo->cquantize = &cquantize->pub; + cquantize->pub.start_pass = start_pass_1_quant; + cquantize->pub.finish_pass = finish_pass_1_quant; + cquantize->pub.new_color_map = new_color_map_1_quant; + cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ + cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ + + /* Make sure my internal arrays won't overflow */ + if (cinfo->out_color_components > MAX_Q_COMPS) + ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); + + /* Create the colormap and color index table. */ + create_colormap(cinfo); + create_colorindex(cinfo); + + /* Allocate Floyd-Steinberg workspace now if requested. + * We do this now since it is FAR storage and may affect the memory + * manager's space calculations. If the user changes to FS dither + * mode in a later pass, we will allocate the space then, and will + * possibly overrun the max_memory_to_use setting. + */ + if (cinfo->dither_mode == JDITHER_FS) + alloc_fs_workspace(cinfo); +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jquant2.c b/widget/milsko/milskosrc/external/libjpeg/src/jquant2.c new file mode 100644 index 0000000000..662b9bcef3 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jquant2.c @@ -0,0 +1,1311 @@ +/* + * jquant2.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2011-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +LOCAL(boxptr) +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +LOCAL(boxptr) +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +LOCAL(void) +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +LOCAL(int) +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if (numboxes*2 <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +LOCAL(void) +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +LOCAL(void) +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +LOCAL(void) +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +LOCAL(void) +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +METHODDEF(void) +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = FALSE; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = TRUE; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +LOCAL(void) +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +METHODDEF(void) +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = TRUE; +} + + +METHODDEF(void) +finish_pass2 (j_decompress_ptr cinfo) +{ + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +METHODDEF(void) +start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int i; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = TRUE; /* Always zero histogram */ + } else { + /* Set up method pointers */ + if (cinfo->dither_mode == JDITHER_FS) + cquantize->pub.color_quantize = pass2_fs_dither; + else + cquantize->pub.color_quantize = pass2_no_dither; + cquantize->pub.finish_pass = finish_pass2; + + /* Make sure color count is acceptable */ + i = cinfo->actual_number_of_colors; + if (i < 1) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); + if (i > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + + if (cinfo->dither_mode == JDITHER_FS) { + size_t arraysize = ((size_t) cinfo->output_width + (size_t) 2) + * (3 * SIZEOF(FSERROR)); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + /* Initialize the propagated errors to zero. */ + FMEMZERO((void FAR *) cquantize->fserrors, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = FALSE; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (i = 0; i < HIST_C0_ELEMS; i++) { + FMEMZERO((void FAR *) histogram[i], + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = FALSE; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +METHODDEF(void) +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = TRUE; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +GLOBAL(void) +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_cquantizer)); + cinfo->cquantize = &cquantize->pub; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + /* Make sure jdmaster didn't give me a case I can't handle */ + if (cinfo->out_color_components != 3) + ERREXIT(cinfo, JERR_NOTIMPL); + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is FAR storage and may affect + * the memory manager's space calculations. + */ + if (cinfo->enable_2pass_quant) { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ + if (desired < 8) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (desired > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) desired, (JDIMENSION) 3); + cquantize->desired = desired; + } else + cquantize->sv_colormap = NULL; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is FAR storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + if (cinfo->dither_mode == JDITHER_FS) { + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + ((size_t) cinfo->output_width + (size_t) 2) * (3 * SIZEOF(FSERROR))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/jutils.c b/widget/milsko/milskosrc/external/libjpeg/src/jutils.c new file mode 100644 index 0000000000..31e16dfb53 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/jutils.c @@ -0,0 +1,224 @@ +/* + * jutils.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2009-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains tables and miscellaneous utility routines needed + * for both compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + * of a DCT block read in natural order (left to right, top to bottom). + */ + +#if 0 /* This table is not actually needed in v6a */ + +const int jpeg_zigzag_order[DCTSIZE2] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +#endif + +/* + * jpeg_natural_order[i] is the natural-order position of the i'th element + * of zigzag order. + * + * When reading corrupted data, the Huffman decoders could attempt + * to reference an entry beyond the end of this array (if the decoded + * zero run length reaches past the end of the block). To prevent + * wild stores without adding an inner-loop test, we put some extra + * "63"s after the real entries. This will cause the extra coefficient + * to be stored in location 63 of the block, not somewhere random. + * The worst case would be a run-length of 15, which means we need 16 + * fake entries. + */ + +const int jpeg_natural_order[DCTSIZE2+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order7[7*7+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 14, 21, 28, 35, + 42, 49, 50, 43, 36, 29, 22, 30, + 37, 44, 51, 52, 45, 38, 46, 53, + 54, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order6[6*6+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 41, 34, 27, + 20, 13, 21, 28, 35, 42, 43, 36, + 29, 37, 44, 45, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order5[5*5+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 12, + 19, 26, 33, 34, 27, 20, 28, 35, + 36, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order4[4*4+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 25, 18, 11, 19, 26, 27, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order3[3*3+16] = { + 0, 1, 8, 16, 9, 2, 10, 17, + 18, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order2[2*2+16] = { + 0, 1, 8, 9, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + + +/* + * Arithmetic utilities + */ + +GLOBAL(long) +jdiv_round_up (long a, long b) +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ +/* Assumes a >= 0, b > 0 */ +{ + return (a + b - 1L) / b; +} + + +GLOBAL(long) +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ +/* Assumes a >= 0, b > 0 */ +{ + a += b - 1L; + return a - (a % b); +} + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines below do it the hard way. (The performance cost + * is not all that great, because these routines aren't very heavily used.) + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */ +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) +#else /* 80x86 case, define if we can */ +#ifdef USE_FMEM +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) +#else +/* This function is for use by the FMEMZERO macro defined in jpegint.h. + * Do not call this function directly, use the FMEMZERO macro instead. + */ +GLOBAL(void) +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_large data. */ +{ + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +} +#endif +#endif + + +GLOBAL(void) +jcopy_sample_rows (JSAMPARRAY input_array, + JSAMPARRAY output_array, + int num_rows, JDIMENSION num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from *input_array++ to *output_array++; + * these areas may overlap for duplication. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + register JSAMPROW inptr, outptr; +#ifdef FMEMCOPY + register size_t count = (size_t) num_cols * SIZEOF(JSAMPLE); +#else + register JDIMENSION count; +#endif + register int row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef FMEMCOPY + FMEMCOPY(outptr, inptr, count); +#else + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#endif + } +} + + +GLOBAL(void) +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ +#ifdef FMEMCOPY + FMEMCOPY(output_row, input_row, (size_t) num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); +#else + register JCOEFPTR inptr, outptr; + register long count; + + inptr = (JCOEFPTR) input_row; + outptr = (JCOEFPTR) output_row; + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + *outptr++ = *inptr++; + } +#endif +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/rdbmp.c b/widget/milsko/milskosrc/external/libjpeg/src/rdbmp.c new file mode 100644 index 0000000000..6749ea0146 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/rdbmp.c @@ -0,0 +1,469 @@ +/* + * rdbmp.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2009-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Microsoft "BMP" + * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors). + * Currently, only 8-, 24-, and 32-bit images are supported, not 1-bit or + * 4-bit (feeding such low-depth images into JPEG would be silly anyway). + * Also, we don't support RLE-compressed files. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed BMP format). + * + * This code contributed by James Arthur Boucher. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef BMP_SUPPORTED + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +typedef char U_CHAR; +#ifdef CHAR_IS_UNSIGNED +#define UCH(x) ((int) (x)) +#else +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* Private version of data source object */ + +typedef struct _bmp_source_struct * bmp_source_ptr; + +typedef struct _bmp_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + j_compress_ptr cinfo; /* back link saves passing separate parm */ + + JSAMPARRAY colormap; /* BMP colormap (converted to my format) */ + + jvirt_sarray_ptr whole_image; /* Needed to reverse row order */ + JDIMENSION source_row; /* Current source row number */ + JDIMENSION row_width; /* Physical width of scanlines in file */ + + int bits_per_pixel; /* remembers 8-, 24-, or 32-bit format */ + int cmap_length; /* colormap length */ +} bmp_source_struct; + + +LOCAL(int) +read_byte (bmp_source_ptr sinfo) +/* Read next byte from BMP file */ +{ + register FILE *infile = sinfo->pub.input_file; + register int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); + return c; +} + + +LOCAL(void) +read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize) +/* Read the colormap from a BMP file */ +{ + int i; + + switch (mapentrysize) { + case 3: + /* BGR format (occurs in OS/2 files) */ + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + } + break; + case 4: + /* BGR0 format (occurs in MS Windows files) */ + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + (void) read_byte(sinfo); + } + break; + default: + ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP); + } +} + + +/* + * Read one row of pixels. + * The image has been read into the whole_image array, but is otherwise + * unprocessed. We must read it out in top-to-bottom row order, and if + * it is an 8-bit image, we must expand colormapped pixels to 24bit format. + */ + +METHODDEF(JDIMENSION) +get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit colormap indexes */ +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + register JSAMPROW inptr, outptr; + register JSAMPARRAY colormap; + register JDIMENSION col; + register int t; + int cmaplen; + + /* Fetch next row from virtual array */ + source->source_row--; + inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + source->whole_image, source->source_row, (JDIMENSION) 1, FALSE); + + /* Expand the colormap indexes to real data */ + outptr = source->pub.buffer[0]; + colormap = source->colormap; + cmaplen = source->cmap_length; + for (col = cinfo->image_width; col > 0; col--) { + t = GETJSAMPLE(*inptr++); + if (t >= cmaplen) + ERREXIT(cinfo, JERR_BMP_OUTOFRANGE); + *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */ + *outptr++ = colormap[1][t]; + *outptr++ = colormap[2][t]; + } + + return 1; +} + +METHODDEF(JDIMENSION) +get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 24-bit pixels */ +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + + /* Fetch next row from virtual array */ + source->source_row--; + inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + source->whole_image, source->source_row, (JDIMENSION) 1, FALSE); + + /* Transfer data. Note source values are in BGR order + * (even though Microsoft's own documents say the opposite). + */ + outptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + outptr += 3; + } + + return 1; +} + +METHODDEF(JDIMENSION) +get_32bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 32-bit pixels */ +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + + /* Fetch next row from virtual array */ + source->source_row--; + inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + source->whole_image, source->source_row, (JDIMENSION) 1, FALSE); + + /* Transfer data. Note source values are in BGR order + * (even though Microsoft's own documents say the opposite). + */ + outptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + inptr++; /* skip the 4th byte (Alpha channel) */ + outptr += 3; + } + + return 1; +} + + +/* + * This method loads the image into whole_image during the first call on + * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call + * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls. + */ + +METHODDEF(JDIMENSION) +preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + register FILE *infile = source->pub.input_file; + register int c; + register JSAMPROW out_ptr; + JDIMENSION row, col; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Read the data into a virtual array in input-file row order. */ + for (row = 0; row < cinfo->image_height; row++) { + if (progress != NULL) { + progress->pub.pass_counter = (long) row; + progress->pub.pass_limit = (long) cinfo->image_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + out_ptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + source->whole_image, row, (JDIMENSION) 1, TRUE); + for (col = source->row_width; col > 0; col--) { + /* inline copy of read_byte() for speed */ + if ((c = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_INPUT_EOF); + *out_ptr++ = (JSAMPLE) c; + } + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Set up to read from the virtual array in top-to-bottom order */ + switch (source->bits_per_pixel) { + case 8: + source->pub.get_pixel_rows = get_8bit_row; + break; + case 24: + source->pub.get_pixel_rows = get_24bit_row; + break; + case 32: + source->pub.get_pixel_rows = get_32bit_row; + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + } + source->source_row = cinfo->image_height; + + /* And read the first row */ + return (*source->pub.get_pixel_rows) (cinfo, sinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + U_CHAR bmpfileheader[14]; + U_CHAR bmpinfoheader[64]; +#define GET_2B(array, offset) ((unsigned int) UCH(array[offset]) + \ + (((unsigned int) UCH(array[offset+1])) << 8)) +#define GET_4B(array, offset) ((INT32) UCH(array[offset]) + \ + (((INT32) UCH(array[offset+1])) << 8) + \ + (((INT32) UCH(array[offset+2])) << 16) + \ + (((INT32) UCH(array[offset+3])) << 24)) + INT32 bfOffBits; + INT32 headerSize; + INT32 biWidth; + INT32 biHeight; + unsigned int biPlanes; + INT32 biCompression; + INT32 biXPelsPerMeter,biYPelsPerMeter; + INT32 biClrUsed = 0; + int mapentrysize = 0; /* 0 indicates no colormap */ + INT32 bPad; + JDIMENSION row_width; + + /* Read and verify the bitmap file header */ + if (! ReadOK(source->pub.input_file, bmpfileheader, 14)) + ERREXIT(cinfo, JERR_INPUT_EOF); + if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */ + ERREXIT(cinfo, JERR_BMP_NOT); + bfOffBits = GET_4B(bmpfileheader, 10); + /* We ignore the remaining fileheader fields */ + + /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows), + * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which. + */ + if (! ReadOK(source->pub.input_file, bmpinfoheader, 4)) + ERREXIT(cinfo, JERR_INPUT_EOF); + headerSize = GET_4B(bmpinfoheader, 0); + if (headerSize < 12 || headerSize > 64) + ERREXIT(cinfo, JERR_BMP_BADHEADER); + if (! ReadOK(source->pub.input_file, bmpinfoheader + 4, headerSize - 4)) + ERREXIT(cinfo, JERR_INPUT_EOF); + + switch ((int) headerSize) { + case 12: + /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */ + biWidth = (INT32) GET_2B(bmpinfoheader, 4); + biHeight = (INT32) GET_2B(bmpinfoheader, 6); + biPlanes = GET_2B(bmpinfoheader, 8); + source->bits_per_pixel = (int) GET_2B(bmpinfoheader, 10); + + switch (source->bits_per_pixel) { + case 8: /* colormapped image */ + mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */ + TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight); + break; + case 24: /* RGB image */ + case 32: /* RGB image + Alpha channel */ + TRACEMS3(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight, + source->bits_per_pixel); + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + } + break; + case 40: + case 64: + /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */ + /* or OS/2 2.x header, which has additional fields that we ignore */ + biWidth = GET_4B(bmpinfoheader, 4); + biHeight = GET_4B(bmpinfoheader, 8); + biPlanes = GET_2B(bmpinfoheader, 12); + source->bits_per_pixel = (int) GET_2B(bmpinfoheader, 14); + biCompression = GET_4B(bmpinfoheader, 16); + biXPelsPerMeter = GET_4B(bmpinfoheader, 24); + biYPelsPerMeter = GET_4B(bmpinfoheader, 28); + biClrUsed = GET_4B(bmpinfoheader, 32); + /* biSizeImage, biClrImportant fields are ignored */ + + switch (source->bits_per_pixel) { + case 8: /* colormapped image */ + mapentrysize = 4; /* Windows uses RGBQUAD colormap */ + TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight); + break; + case 24: /* RGB image */ + case 32: /* RGB image + Alpha channel */ + TRACEMS3(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight, + source->bits_per_pixel); + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + } + if (biCompression != 0) + ERREXIT(cinfo, JERR_BMP_COMPRESSED); + + if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) { + /* Set JFIF density parameters from the BMP data */ + cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */ + cinfo->Y_density = (UINT16) (biYPelsPerMeter/100); + cinfo->density_unit = 2; /* dots/cm */ + } + break; + default: + ERREXIT(cinfo, JERR_BMP_BADHEADER); + return; /* avoid compiler warnings for uninitialized variables */ + } + + if (biPlanes != 1) + ERREXIT(cinfo, JERR_BMP_BADPLANES); + /* Sanity check for buffer allocation below */ + if (biWidth <= 0 || biHeight <= 0 || (biWidth >> 24) || (biHeight >> 24)) + ERREXIT(cinfo, JERR_BMP_OUTOFRANGE); + + /* Compute distance to bitmap data --- will adjust for colormap below */ + bPad = bfOffBits - (headerSize + 14); + + /* Read the colormap, if any */ + if (mapentrysize > 0) { + if (biClrUsed <= 0) + biClrUsed = 256; /* assume it's 256 */ + else if (biClrUsed > 256) + ERREXIT(cinfo, JERR_BMP_BADCMAP); + /* Allocate space to store the colormap */ + source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, + JPOOL_IMAGE, (JDIMENSION) biClrUsed, (JDIMENSION) 3); + source->cmap_length = (int) biClrUsed; + /* and read it from the file */ + read_colormap(source, (int) biClrUsed, mapentrysize); + /* account for size of colormap */ + bPad -= biClrUsed * mapentrysize; + } + + /* Skip any remaining pad bytes */ + if (bPad < 0) /* incorrect bfOffBits value? */ + ERREXIT(cinfo, JERR_BMP_BADHEADER); + while (--bPad >= 0) { + (void) read_byte(source); + } + + /* Compute row width in file, including padding to 4-byte boundary */ + if (source->bits_per_pixel == 24) + row_width = (JDIMENSION) (biWidth * 3); + else if (source->bits_per_pixel == 32) + row_width = (JDIMENSION) (biWidth * 4); + else + row_width = (JDIMENSION) biWidth; + while ((row_width & 3) != 0) row_width++; + source->row_width = row_width; + + /* Allocate space for inversion array, prepare for preload pass */ + source->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + row_width, (JDIMENSION) biHeight, (JDIMENSION) 1); + source->pub.get_pixel_rows = preload_image; + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + + /* Allocate one-row buffer for returned data */ + source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, + JPOOL_IMAGE, (JDIMENSION) (biWidth * 3), (JDIMENSION) 1); + source->pub.buffer_height = 1; + + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = 3; + cinfo->data_precision = 8; + cinfo->image_width = (JDIMENSION) biWidth; + cinfo->image_height = (JDIMENSION) biHeight; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for BMP format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_bmp (j_compress_ptr cinfo) +{ + bmp_source_ptr source; + + /* Create module interface object */ + source = (bmp_source_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_source_struct)); + source->cinfo = cinfo; /* make back link for subroutines */ + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_bmp; + source->pub.finish_input = finish_input_bmp; + + return &source->pub; +} + +#endif /* BMP_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/rdcolmap.c b/widget/milsko/milskosrc/external/libjpeg/src/rdcolmap.c new file mode 100644 index 0000000000..42b343763b --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/rdcolmap.c @@ -0,0 +1,253 @@ +/* + * rdcolmap.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file implements djpeg's "-map file" switch. It reads a source image + * and constructs a colormap to be supplied to the JPEG decompressor. + * + * Currently, these file formats are supported for the map file: + * GIF: the contents of the GIF's global colormap are used. + * PPM (either text or raw flavor): the entire file is read and + * each unique pixel value is entered in the map. + * Note that reading a large PPM file will be horrendously slow. + * Typically, a PPM-format map file should contain just one pixel + * of each desired color. Such a file can be extracted from an + * ordinary image PPM file with ppmtomap(1). + * + * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not + * currently implemented. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */ + +/* Portions of this code are based on the PBMPLUS library, which is: +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + + +/* + * Add a (potentially) new color to the color map. + */ + +LOCAL(void) +add_map_entry (j_decompress_ptr cinfo, int R, int G, int B) +{ + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + int ncolors = cinfo->actual_number_of_colors; + int index; + + /* Check for duplicate color. */ + for (index = 0; index < ncolors; index++) { + if (GETJSAMPLE(colormap0[index]) == R && + GETJSAMPLE(colormap1[index]) == G && + GETJSAMPLE(colormap2[index]) == B) + return; /* color is already in map */ + } + + /* Check for map overflow. */ + if (ncolors >= (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1)); + + /* OK, add color to map. */ + colormap0[ncolors] = (JSAMPLE) R; + colormap1[ncolors] = (JSAMPLE) G; + colormap2[ncolors] = (JSAMPLE) B; + cinfo->actual_number_of_colors++; +} + + +/* + * Extract color map from a GIF file. + */ + +LOCAL(void) +read_gif_map (j_decompress_ptr cinfo, FILE * infile) +{ + int header[13]; + int i, colormaplen; + int R, G, B; + + /* Initial 'G' has already been read by read_color_map */ + /* Read the rest of the GIF header and logical screen descriptor */ + for (i = 1; i < 13; i++) { + if ((header[i] = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + } + + /* Verify GIF Header */ + if (header[1] != 'I' || header[2] != 'F') + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* There must be a global color map. */ + if ((header[10] & 0x80) == 0) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* OK, fetch it. */ + colormaplen = 2 << (header[10] & 0x07); + + for (i = 0; i < colormaplen; i++) { + R = getc(infile); + G = getc(infile); + B = getc(infile); + if (R == EOF || G == EOF || B == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + add_map_entry(cinfo, + R << (BITS_IN_JSAMPLE-8), + G << (BITS_IN_JSAMPLE-8), + B << (BITS_IN_JSAMPLE-8)); + } +} + + +/* Support routines for reading PPM */ + + +LOCAL(int) +pbm_getc (FILE * infile) +/* Read next char, skipping over any comments */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(infile); + if (ch == '#') { + do { + ch = getc(infile); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(unsigned int) +read_pbm_integer (j_decompress_ptr cinfo, FILE * infile) +/* Read an unsigned decimal integer from the PPM file */ +/* Swallows one trailing character after the integer */ +/* Note that on a 16-bit-int machine, only values up to 64k can be read. */ +/* This should not be a problem in practice. */ +{ + register int ch; + register unsigned int val; + + /* Skip any leading whitespace */ + do { + ch = pbm_getc(infile); + if (ch == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if (ch < '0' || ch > '9') + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + val = ch - '0'; + while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') { + val *= 10; + val += ch - '0'; + } + return val; +} + + +/* + * Extract color map from a PPM file. + */ + +LOCAL(void) +read_ppm_map (j_decompress_ptr cinfo, FILE * infile) +{ + int c; + unsigned int w, h, maxval, row, col; + int R, G, B; + + /* Initial 'P' has already been read by read_color_map */ + c = getc(infile); /* save format discriminator for a sec */ + + /* while we fetch the remaining header info */ + w = read_pbm_integer(cinfo, infile); + h = read_pbm_integer(cinfo, infile); + maxval = read_pbm_integer(cinfo, infile); + + if (w <= 0 || h <= 0 || maxval <= 0) /* error check */ + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* For now, we don't support rescaling from an unusual maxval. */ + if (maxval != (unsigned int) MAXJSAMPLE) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + switch (c) { + case '3': /* it's a text-format PPM file */ + for (row = 0; row < h; row++) { + for (col = 0; col < w; col++) { + R = read_pbm_integer(cinfo, infile); + G = read_pbm_integer(cinfo, infile); + B = read_pbm_integer(cinfo, infile); + add_map_entry(cinfo, R, G, B); + } + } + break; + + case '6': /* it's a raw-format PPM file */ + for (row = 0; row < h; row++) { + for (col = 0; col < w; col++) { + R = getc(infile); + G = getc(infile); + B = getc(infile); + if (R == EOF || G == EOF || B == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + add_map_entry(cinfo, R, G, B); + } + } + break; + + default: + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + break; + } +} + + +/* + * Main entry point from djpeg.c. + * Input: opened input file (from file name argument on command line). + * Output: colormap and actual_number_of_colors fields are set in cinfo. + */ + +GLOBAL(void) +read_color_map (j_decompress_ptr cinfo, FILE * infile) +{ + /* Allocate space for a color map of maximum supported size. */ + cinfo->colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3); + cinfo->actual_number_of_colors = 0; /* initialize map to empty */ + + /* Read first byte to determine file format */ + switch (getc(infile)) { + case 'G': + read_gif_map(cinfo, infile); + break; + case 'P': + read_ppm_map(cinfo, infile); + break; + default: + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + break; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/rdgif.c b/widget/milsko/milskosrc/external/libjpeg/src/rdgif.c new file mode 100644 index 0000000000..5d2339ca2b --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/rdgif.c @@ -0,0 +1,679 @@ +/* + * rdgif.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2019-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in GIF format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed GIF format). + */ + +/* + * This code is loosely based on giftoppm from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * +-------------------------------------------------------------------+ + * | Copyright 1990, David Koblas. | + * | Permission to use, copy, modify, and distribute this software | + * | and its documentation for any purpose and without fee is hereby | + * | granted, provided that the above copyright notice appear in all | + * | copies and that both that copyright notice and this permission | + * | notice appear in supporting documentation. This software is | + * | provided "as is" without express or implied warranty. | + * +-------------------------------------------------------------------+ + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef GIF_SUPPORTED + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +typedef char U_CHAR; +#ifdef CHAR_IS_UNSIGNED +#define UCH(x) ((int) (x)) +#else +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +#define MAXCOLORMAPSIZE 256 /* max # of colors in a GIF colormap */ +#define NUMCOLORS 3 /* # of colors */ +#define CM_RED 0 /* color component numbers */ +#define CM_GREEN 1 +#define CM_BLUE 2 + +#define MAX_LZW_BITS 12 /* maximum LZW code size */ +#define LZW_TABLE_SIZE (1< table of prefix symbols */ + UINT8 FAR *symbol_tail; /* => table of suffix bytes */ + UINT8 FAR *symbol_stack; /* => stack for symbol expansions */ + UINT8 FAR *sp; /* stack pointer */ + + /* State for interlaced image processing */ + boolean is_interlaced; /* TRUE if have interlaced image */ + jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */ + JDIMENSION cur_row_number; /* need to know actual row number */ + JDIMENSION pass2_offset; /* # of pixel rows in pass 1 */ + JDIMENSION pass3_offset; /* # of pixel rows in passes 1&2 */ + JDIMENSION pass4_offset; /* # of pixel rows in passes 1,2,3 */ +} gif_source_struct; + +typedef gif_source_struct * gif_source_ptr; + + +/* Forward declarations */ +METHODDEF(JDIMENSION) get_pixel_rows + JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo)); +METHODDEF(JDIMENSION) load_interlaced_image + JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo)); +METHODDEF(JDIMENSION) get_interlaced_row + JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo)); + + +LOCAL(int) +ReadByte (gif_source_ptr sinfo) +/* Read next byte from GIF file */ +{ + register FILE *infile = sinfo->pub.input_file; + register int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); + return c; +} + + +LOCAL(int) +GetDataBlock (gif_source_ptr sinfo, U_CHAR *buf) +/* Read a GIF data block, which has a leading count byte */ +/* A zero-length block marks the end of a data block sequence */ +{ + int count; + + count = ReadByte(sinfo); + if (count > 0) { + if (! ReadOK(sinfo->pub.input_file, buf, count)) + ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); + } + return count; +} + + +LOCAL(void) +SkipDataBlocks (gif_source_ptr sinfo) +/* Skip a series of data blocks, until a block terminator is found */ +{ + U_CHAR buf[256]; + + while (GetDataBlock(sinfo, buf) > 0) + /* skip */; +} + + +LOCAL(void) +ReInitLZW (gif_source_ptr sinfo) +/* (Re)initialize LZW state; shared code for startup and Clear processing */ +{ + sinfo->code_size = sinfo->input_code_size + 1; + sinfo->limit_code = sinfo->clear_code << 1; /* 2^code_size */ + sinfo->max_code = sinfo->clear_code + 2; /* first unused code value */ + sinfo->sp = sinfo->symbol_stack; /* init stack to empty */ +} + + +LOCAL(void) +InitLZWCode (gif_source_ptr sinfo) +/* Initialize for a series of LZWReadByte (and hence GetCode) calls */ +{ + /* GetCode initialization */ + sinfo->last_byte = 2; /* make safe to "recopy last two bytes" */ + sinfo->code_buf[0] = 0; + sinfo->code_buf[1] = 0; + sinfo->last_bit = 0; /* nothing in the buffer */ + sinfo->cur_bit = 0; /* force buffer load on first call */ + sinfo->first_time = TRUE; + sinfo->out_of_blocks = FALSE; + + /* LZWReadByte initialization: */ + /* compute special code values (note that these do not change later) */ + sinfo->clear_code = 1 << sinfo->input_code_size; + sinfo->end_code = sinfo->clear_code + 1; + ReInitLZW(sinfo); +} + + +LOCAL(int) +GetCode (gif_source_ptr sinfo) +/* Fetch the next code_size bits from the GIF data */ +/* We assume code_size is less than 16 */ +{ + register INT32 accum; + int offs, count; + + while (sinfo->cur_bit + sinfo->code_size > sinfo->last_bit) { + /* Time to reload the buffer */ + /* First time, share code with Clear case */ + if (sinfo->first_time) { + sinfo->first_time = FALSE; + return sinfo->clear_code; + } + if (sinfo->out_of_blocks) { + WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA); + return sinfo->end_code; /* fake something useful */ + } + /* preserve last two bytes of what we have -- assume code_size <= 16 */ + sinfo->code_buf[0] = sinfo->code_buf[sinfo->last_byte-2]; + sinfo->code_buf[1] = sinfo->code_buf[sinfo->last_byte-1]; + /* Load more bytes; set flag if we reach the terminator block */ + if ((count = GetDataBlock(sinfo, &sinfo->code_buf[2])) == 0) { + sinfo->out_of_blocks = TRUE; + WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA); + return sinfo->end_code; /* fake something useful */ + } + /* Reset counters */ + sinfo->cur_bit = (sinfo->cur_bit - sinfo->last_bit) + 16; + sinfo->last_byte = 2 + count; + sinfo->last_bit = sinfo->last_byte * 8; + } + + /* Form up next 24 bits in accum */ + offs = sinfo->cur_bit >> 3; /* byte containing cur_bit */ + accum = (INT32) UCH(sinfo->code_buf[offs+2]); + accum <<= 8; + accum |= (INT32) UCH(sinfo->code_buf[offs+1]); + accum <<= 8; + accum |= (INT32) UCH(sinfo->code_buf[offs]); + + /* Right-align cur_bit in accum, then mask off desired number of bits */ + accum >>= (sinfo->cur_bit & 7); + sinfo->cur_bit += sinfo->code_size; + return ((int) accum) & ((1 << sinfo->code_size) - 1); +} + + +LOCAL(int) +LZWReadByte (gif_source_ptr sinfo) +/* Read an LZW-compressed byte */ +{ + register int code; /* current working code */ + int incode; /* saves actual input code */ + + /* If any codes are stacked from a previously read symbol, return them */ + if (sinfo->sp > sinfo->symbol_stack) + return (int) *(-- sinfo->sp); + + /* Time to read a new symbol */ + code = GetCode(sinfo); + + if (code == sinfo->clear_code) { + /* Reinit state, swallow any extra Clear codes, and */ + /* return next code, which is expected to be a raw byte. */ + ReInitLZW(sinfo); + do { + code = GetCode(sinfo); + } while (code == sinfo->clear_code); + if (code > sinfo->clear_code) { /* make sure it is a raw byte */ + WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA); + code = 0; /* use something valid */ + } + /* make firstcode, oldcode valid! */ + sinfo->firstcode = sinfo->oldcode = code; + return code; + } + + if (code == sinfo->end_code) { + /* Skip the rest of the image, unless GetCode already read terminator */ + if (! sinfo->out_of_blocks) { + SkipDataBlocks(sinfo); + sinfo->out_of_blocks = TRUE; + } + /* Complain that there's not enough data */ + WARNMS(sinfo->cinfo, JWRN_GIF_ENDCODE); + /* Pad data with 0's */ + return 0; /* fake something usable */ + } + + /* Got normal raw byte or LZW symbol */ + incode = code; /* save for a moment */ + + if (code >= sinfo->max_code) { /* special case for not-yet-defined symbol */ + /* code == max_code is OK; anything bigger is bad data */ + if (code > sinfo->max_code) { + WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA); + incode = 0; /* prevent creation of loops in symbol table */ + } + /* this symbol will be defined as oldcode/firstcode */ + *(sinfo->sp++) = (UINT8) sinfo->firstcode; + code = sinfo->oldcode; + } + + /* If it's a symbol, expand it into the stack */ + while (code >= sinfo->clear_code) { + *(sinfo->sp++) = sinfo->symbol_tail[code]; /* tail is a byte value */ + code = sinfo->symbol_head[code]; /* head is another LZW symbol */ + } + /* At this point code just represents a raw byte */ + sinfo->firstcode = code; /* save for possible future use */ + + /* If there's room in table... */ + if ((code = sinfo->max_code) < LZW_TABLE_SIZE) { + /* Define a new symbol = prev sym + head of this sym's expansion */ + sinfo->symbol_head[code] = (UINT16) sinfo->oldcode; + sinfo->symbol_tail[code] = (UINT8) sinfo->firstcode; + sinfo->max_code++; + /* Is it time to increase code_size? */ + if (sinfo->max_code >= sinfo->limit_code && + sinfo->code_size < MAX_LZW_BITS) { + sinfo->code_size++; + sinfo->limit_code <<= 1; /* keep equal to 2^code_size */ + } + } + + sinfo->oldcode = incode; /* save last input symbol for future use */ + return sinfo->firstcode; /* return first byte of symbol's expansion */ +} + + +LOCAL(void) +ReadColorMap (gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap) +/* Read a GIF colormap */ +{ + int i; + + for (i = 0; i < cmaplen; i++) { +#if BITS_IN_JSAMPLE == 8 +#define UPSCALE(x) (x) +#else +#define UPSCALE(x) ((x) << (BITS_IN_JSAMPLE-8)) +#endif + cmap[CM_RED ][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo)); + cmap[CM_GREEN][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo)); + cmap[CM_BLUE ][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo)); + } +} + + +LOCAL(void) +DoExtension (gif_source_ptr sinfo) +/* Process an extension block */ +/* Currently we ignore 'em all */ +{ + int extlabel; + + /* Read extension label byte */ + extlabel = ReadByte(sinfo); + TRACEMS1(sinfo->cinfo, 1, JTRC_GIF_EXTENSION, extlabel); + /* Skip the data block(s) associated with the extension */ + SkipDataBlocks(sinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_gif (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + gif_source_ptr source = (gif_source_ptr) sinfo; + U_CHAR hdrbuf[10]; /* workspace for reading control blocks */ + unsigned int width, height; /* image dimensions */ + int colormaplen, aspectRatio; + int c; + + /* Read and verify GIF Header */ + if (! ReadOK(source->pub.input_file, hdrbuf, 6)) + ERREXIT(cinfo, JERR_GIF_NOT); + if (hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F') + ERREXIT(cinfo, JERR_GIF_NOT); + /* Check for expected version numbers. + * If unknown version, give warning and try to process anyway; + * this is per recommendation in GIF89a standard. + */ + if ((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') && + (hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a')) + TRACEMS3(cinfo, 1, JTRC_GIF_BADVERSION, hdrbuf[3], hdrbuf[4], hdrbuf[5]); + + /* Read and decipher Logical Screen Descriptor */ + if (! ReadOK(source->pub.input_file, hdrbuf, 7)) + ERREXIT(cinfo, JERR_INPUT_EOF); + width = LM_to_uint(hdrbuf, 0); + height = LM_to_uint(hdrbuf, 2); + /* we ignore the color resolution, sort flag, and background color index */ + aspectRatio = UCH(hdrbuf[6]); + if (aspectRatio != 0 && aspectRatio != 49) + TRACEMS(cinfo, 1, JTRC_GIF_NONSQUARE); + + /* Allocate space to store the colormap */ + source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, + JPOOL_IMAGE, (JDIMENSION) MAXCOLORMAPSIZE, (JDIMENSION) NUMCOLORS); + colormaplen = 0; /* indicate initialization */ + + /* Read global colormap if header indicates it is present */ + if (BitSet(hdrbuf[4], COLORMAPFLAG)) { + colormaplen = 2 << (hdrbuf[4] & 0x07); + ReadColorMap(source, colormaplen, source->colormap); + } + + /* Scan until we reach start of desired image. + * We don't currently support skipping images, but could add it easily. + */ + for (;;) { + c = ReadByte(source); + + if (c == ';') /* GIF terminator?? */ + ERREXIT(cinfo, JERR_GIF_IMAGENOTFOUND); + + if (c == '!') { /* Extension */ + DoExtension(source); + continue; + } + + if (c != ',') { /* Not an image separator? */ + WARNMS1(cinfo, JWRN_GIF_CHAR, c); + continue; + } + + /* Read and decipher Local Image Descriptor */ + if (! ReadOK(source->pub.input_file, hdrbuf, 9)) + ERREXIT(cinfo, JERR_INPUT_EOF); + /* we ignore top/left position info, also sort flag */ + width = LM_to_uint(hdrbuf, 4); + height = LM_to_uint(hdrbuf, 6); + if (width <= 0 || height <= 0) + ERREXIT(cinfo, JERR_GIF_OUTOFRANGE); + source->is_interlaced = (BitSet(hdrbuf[8], INTERLACE) != 0); + + /* Read local colormap if header indicates it is present */ + /* Note: if we wanted to support skipping images, */ + /* we'd need to skip rather than read colormap for ignored images */ + if (BitSet(hdrbuf[8], COLORMAPFLAG)) { + colormaplen = 2 << (hdrbuf[8] & 0x07); + ReadColorMap(source, colormaplen, source->colormap); + } + + source->input_code_size = ReadByte(source); /* get min-code-size byte */ + if (source->input_code_size < 2 || source->input_code_size > 8) + ERREXIT1(cinfo, JERR_GIF_CODESIZE, source->input_code_size); + + /* Reached desired image, so break out of loop */ + /* If we wanted to skip this image, */ + /* we'd call SkipDataBlocks and then continue the loop */ + break; + } + + /* Prepare to read selected image: first initialize LZW decompressor */ + source->symbol_head = (UINT16 FAR *) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT16)); + source->symbol_tail = (UINT8 FAR *) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT8)); + source->symbol_stack = (UINT8 FAR *) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT8)); + InitLZWCode(source); + + /* + * If image is interlaced, we read it into a full-size sample array, + * decompressing as we go; then get_interlaced_row selects rows from the + * sample array in the proper order. + */ + if (source->is_interlaced) { + /* We request the virtual array now, but can't access it until virtual + * arrays have been allocated. Hence, the actual work of reading the + * image is postponed until the first call to get_pixel_rows. + */ + source->interlaced_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) width, (JDIMENSION) height, (JDIMENSION) 1); + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + source->pub.get_pixel_rows = load_interlaced_image; + } else { + source->pub.get_pixel_rows = get_pixel_rows; + } + + /* Create compressor input buffer. */ + source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, + JPOOL_IMAGE, (JDIMENSION) width * NUMCOLORS, (JDIMENSION) 1); + source->pub.buffer_height = 1; + + /* Pad colormap for safety. */ + for (c = colormaplen; c < source->clear_code; c++) { + source->colormap[CM_RED ][c] = + source->colormap[CM_GREEN][c] = + source->colormap[CM_BLUE ][c] = CENTERJSAMPLE; + } + + /* Return info about the image. */ + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = NUMCOLORS; + cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */ + cinfo->image_width = width; + cinfo->image_height = height; + + TRACEMS3(cinfo, 1, JTRC_GIF, width, height, colormaplen); +} + + +/* + * Read one row of pixels. + * This version is used for noninterlaced GIF images: + * we read directly from the GIF file. + */ + +METHODDEF(JDIMENSION) +get_pixel_rows (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + gif_source_ptr source = (gif_source_ptr) sinfo; + register int c; + register JSAMPROW ptr; + register JDIMENSION col; + register JSAMPARRAY colormap = source->colormap; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + c = LZWReadByte(source); + *ptr++ = colormap[CM_RED ][c]; + *ptr++ = colormap[CM_GREEN][c]; + *ptr++ = colormap[CM_BLUE ][c]; + } + return 1; +} + + +/* + * Read one row of pixels. + * This version is used for the first call on get_pixel_rows when + * reading an interlaced GIF file: we read the whole image into memory. + */ + +METHODDEF(JDIMENSION) +load_interlaced_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + gif_source_ptr source = (gif_source_ptr) sinfo; + register JSAMPROW sptr; + register JDIMENSION col; + JDIMENSION row; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Read the interlaced image into the virtual array we've created. */ + for (row = 0; row < cinfo->image_height; row++) { + if (progress != NULL) { + progress->pub.pass_counter = (long) row; + progress->pub.pass_limit = (long) cinfo->image_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + sptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + source->interlaced_image, row, (JDIMENSION) 1, TRUE); + for (col = cinfo->image_width; col > 0; col--) { + *sptr++ = (JSAMPLE) LZWReadByte(source); + } + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Replace method pointer so subsequent calls don't come here. */ + source->pub.get_pixel_rows = get_interlaced_row; + /* Initialize for get_interlaced_row, and perform first call on it. */ + source->cur_row_number = 0; + source->pass2_offset = (cinfo->image_height + 7) / 8; + source->pass3_offset = source->pass2_offset + (cinfo->image_height + 3) / 8; + source->pass4_offset = source->pass3_offset + (cinfo->image_height + 1) / 4; + + return get_interlaced_row(cinfo, sinfo); +} + + +/* + * Read one row of pixels. + * This version is used for interlaced GIF images: + * we read from the virtual array. + */ + +METHODDEF(JDIMENSION) +get_interlaced_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + gif_source_ptr source = (gif_source_ptr) sinfo; + register int c; + register JSAMPROW sptr, ptr; + register JDIMENSION col; + register JSAMPARRAY colormap = source->colormap; + JDIMENSION irow; + + /* Figure out which row of interlaced image is needed, and access it. */ + switch ((int) (source->cur_row_number & 7)) { + case 0: /* first-pass row */ + irow = source->cur_row_number >> 3; + break; + case 4: /* second-pass row */ + irow = (source->cur_row_number >> 3) + source->pass2_offset; + break; + case 2: /* third-pass row */ + case 6: + irow = (source->cur_row_number >> 2) + source->pass3_offset; + break; + default: /* fourth-pass row */ + irow = (source->cur_row_number >> 1) + source->pass4_offset; + } + sptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + source->interlaced_image, irow, (JDIMENSION) 1, FALSE); + /* Scan the row, expand colormap, and output */ + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + c = GETJSAMPLE(*sptr++); + *ptr++ = colormap[CM_RED ][c]; + *ptr++ = colormap[CM_GREEN][c]; + *ptr++ = colormap[CM_BLUE ][c]; + } + source->cur_row_number++; /* for next time */ + return 1; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_gif (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for GIF format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_gif (j_compress_ptr cinfo) +{ + gif_source_ptr source; + + /* Create module interface object */ + source = (gif_source_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(gif_source_struct)); + source->cinfo = cinfo; /* make back link for subroutines */ + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_gif; + source->pub.finish_input = finish_input_gif; + + return &source->pub; +} + +#endif /* GIF_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/rdppm.c b/widget/milsko/milskosrc/external/libjpeg/src/rdppm.c new file mode 100644 index 0000000000..ca6386786d --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/rdppm.c @@ -0,0 +1,501 @@ +/* + * rdppm.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2009-2020 by Bill Allombert, Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in PPM/PGM format. + * The extended 2-byte-per-sample raw PPM/PGM formats are supported. + * The PBMPLUS library is NOT required to compile this software + * (but it is highly useful as a set of PPM image manipulation programs). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed PPM format). + */ + +/* Portions of this code are based on the PBMPLUS library, which is: +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef PPM_SUPPORTED + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +typedef char U_CHAR; +#ifdef CHAR_IS_UNSIGNED +#define UCH(x) ((int) (x)) +#else +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* + * On most systems, reading individual bytes with getc() is drastically less + * efficient than buffering a row at a time with fread(). On PCs, we must + * allocate the buffer in near data space, because we are assuming small-data + * memory model, wherein fread() can't reach far memory. If you need to + * process very wide images on a PC, you might have to compile in large-memory + * model, or else replace fread() with a getc() loop --- which will be much + * slower. + */ + + +/* Private version of data source object */ + +typedef struct { + struct cjpeg_source_struct pub; /* public fields */ + + /* Usually these two pointers point to the same place: */ + U_CHAR *iobuffer; /* fread's I/O buffer */ + JSAMPROW pixrow; /* compressor input buffer */ + size_t buffer_width; /* width of I/O buffer */ + JSAMPLE *rescale; /* => maxval-remapping array, or NULL */ + unsigned int maxval; +} ppm_source_struct; + +typedef ppm_source_struct * ppm_source_ptr; + + +LOCAL(int) +pbm_getc (FILE * infile) +/* Read next char, skipping over any comments */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(infile); + if (ch == '#') { + do { + ch = getc(infile); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(unsigned int) +read_pbm_integer (j_compress_ptr cinfo, FILE * infile) +/* Read an unsigned decimal integer from the PPM file */ +/* Swallows one trailing character after the integer */ +/* Note that on a 16-bit-int machine, only values up to 64k can be read. */ +/* This should not be a problem in practice. */ +{ + register int ch; + register unsigned int val; + + /* Skip any leading whitespace */ + do { + ch = pbm_getc(infile); + if (ch == EOF) + ERREXIT(cinfo, JERR_INPUT_EOF); + } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if (ch < '0' || ch > '9') + ERREXIT(cinfo, JERR_PPM_NONNUMERIC); + + val = ch - '0'; + while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') { + val *= 10; + val += ch - '0'; + } + return val; +} + + +/* + * Read one row of pixels. + * + * We provide several different versions depending on input file format. + * In all cases, input is scaled to the size of JSAMPLE. + * + * A really fast path is provided for reading byte/sample raw files with + * maxval = MAXJSAMPLE, which is the normal case for 8-bit data. + */ + + +METHODDEF(JDIMENSION) +get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading text-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + FILE * infile = source->pub.input_file; + register JSAMPROW ptr; + register JSAMPLE *rescale = source->rescale; + unsigned int maxval = source->maxval; + JDIMENSION col; + + ptr = source->pixrow; + for (col = cinfo->image_width; col > 0; col--) { + register unsigned int temp; + temp = read_pbm_integer(cinfo, infile); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading text-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + FILE * infile = source->pub.input_file; + register JSAMPROW ptr; + register JSAMPLE *rescale = source->rescale; + unsigned int maxval = source->maxval; + JDIMENSION col; + + ptr = source->pixrow; + for (col = cinfo->image_width; col > 0; col--) { + register unsigned int temp; + temp = read_pbm_integer(cinfo, infile); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + temp = read_pbm_integer(cinfo, infile); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + temp = read_pbm_integer(cinfo, infile); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + unsigned int maxval = source->maxval; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pixrow; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + register unsigned int temp; + temp = (unsigned int) UCH(*bufferptr++); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + unsigned int maxval = source->maxval; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pixrow; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + register unsigned int temp; + temp = (unsigned int) UCH(*bufferptr++); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + temp = (unsigned int) UCH(*bufferptr++); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + temp = (unsigned int) UCH(*bufferptr++); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE. + * In this case we just read right into the JSAMPLE buffer! + * Note that same code works for PPM and PGM files. + */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + return 1; +} + + +METHODDEF(JDIMENSION) +get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-word-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + unsigned int maxval = source->maxval; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pixrow; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + register unsigned int temp; + temp = ((unsigned int) UCH(*bufferptr++)) << 8; + temp |= (unsigned int) UCH(*bufferptr++); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-word-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + unsigned int maxval = source->maxval; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pixrow; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + register unsigned int temp; + temp = ((unsigned int) UCH(*bufferptr++)) << 8; + temp |= (unsigned int) UCH(*bufferptr++); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + temp = ((unsigned int) UCH(*bufferptr++)) << 8; + temp |= (unsigned int) UCH(*bufferptr++); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + temp = ((unsigned int) UCH(*bufferptr++)) << 8; + temp |= (unsigned int) UCH(*bufferptr++); + if (temp > maxval) + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + *ptr++ = rescale[temp]; + } + return 1; +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + int c; + unsigned int w, h, maxval; + boolean need_iobuffer, use_raw_buffer, need_rescale; + + if (getc(source->pub.input_file) != 'P') + ERREXIT(cinfo, JERR_PPM_NOT); + + c = getc(source->pub.input_file); /* subformat discriminator character */ + + /* detect unsupported variants (ie, PBM) before trying to read header */ + switch (c) { + case '2': /* it's a text-format PGM file */ + case '3': /* it's a text-format PPM file */ + case '5': /* it's a raw-format PGM file */ + case '6': /* it's a raw-format PPM file */ + break; + default: + ERREXIT(cinfo, JERR_PPM_NOT); + } + + /* fetch the remaining header info */ + w = read_pbm_integer(cinfo, source->pub.input_file); + h = read_pbm_integer(cinfo, source->pub.input_file); + maxval = read_pbm_integer(cinfo, source->pub.input_file); + + if (w <= 0 || h <= 0 || maxval <= 0) /* error check */ + ERREXIT(cinfo, JERR_PPM_NOT); + + if (((long) w >> 24) || /* sanity check for buffer allocation below */ + ((long) maxval >> 16)) /* support max 16-bit (2-byte) sample values */ + ERREXIT(cinfo, JERR_PPM_OUTOFRANGE); + + cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */ + cinfo->image_width = (JDIMENSION) w; + cinfo->image_height = (JDIMENSION) h; + source->maxval = maxval; + + /* initialize flags to most common settings */ + need_iobuffer = TRUE; /* do we need an I/O buffer? */ + use_raw_buffer = FALSE; /* do we map input buffer onto I/O buffer? */ + need_rescale = TRUE; /* do we need a rescale array? */ + + switch (c) { + case '2': /* it's a text-format PGM file */ + cinfo->input_components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h); + source->pub.get_pixel_rows = get_text_gray_row; + need_iobuffer = FALSE; + break; + + case '3': /* it's a text-format PPM file */ + cinfo->input_components = 3; + cinfo->in_color_space = JCS_RGB; + TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h); + source->pub.get_pixel_rows = get_text_rgb_row; + need_iobuffer = FALSE; + break; + + case '5': /* it's a raw-format PGM file */ + cinfo->input_components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_PGM, w, h); + if (maxval > 255) { + source->pub.get_pixel_rows = get_word_gray_row; + } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) { + source->pub.get_pixel_rows = get_raw_row; + use_raw_buffer = TRUE; + need_rescale = FALSE; + } else { + source->pub.get_pixel_rows = get_scaled_gray_row; + } + break; + + case '6': /* it's a raw-format PPM file */ + cinfo->input_components = 3; + cinfo->in_color_space = JCS_RGB; + TRACEMS2(cinfo, 1, JTRC_PPM, w, h); + if (maxval > 255) { + source->pub.get_pixel_rows = get_word_rgb_row; + } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) { + source->pub.get_pixel_rows = get_raw_row; + use_raw_buffer = TRUE; + need_rescale = FALSE; + } else { + source->pub.get_pixel_rows = get_scaled_rgb_row; + } + break; + } + + /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */ + if (need_iobuffer) { + source->buffer_width = (size_t) w * (size_t) cinfo->input_components * + ((maxval <= 255) ? SIZEOF(U_CHAR) : (2 * SIZEOF(U_CHAR))); + source->iobuffer = (U_CHAR *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, source->buffer_width); + } + + /* Create compressor input buffer. */ + if (use_raw_buffer) { + /* For unscaled raw-input case, we can just map it onto the I/O buffer. */ + /* Cast here implies near->far pointer conversion on PCs */ + source->pixrow = (JSAMPROW) source->iobuffer; + } else { + /* Need to translate anyway, so make a separate sample buffer. */ + source->pixrow = (JSAMPROW) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (size_t) w * + (size_t) cinfo->input_components * SIZEOF(JSAMPLE)); + } + /* Synthesize a JSAMPARRAY pointer structure */ + source->pub.buffer = & source->pixrow; + source->pub.buffer_height = 1; + + /* Compute the rescaling array if required. */ + if (need_rescale) { + INT32 val, half_maxval; + + /* On 16-bit-int machines we have to be careful of maxval = 65535 */ + source->rescale = (JSAMPLE *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, + JPOOL_IMAGE, ((size_t) maxval + (size_t) 1) * SIZEOF(JSAMPLE)); + half_maxval = maxval / 2; + for (val = 0; val <= (INT32) maxval; val++) { + /* The multiplication here must be done in 32 bits to avoid overflow */ + source->rescale[val] = (JSAMPLE) ((val * MAXJSAMPLE + half_maxval) / maxval); + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for PPM format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_ppm (j_compress_ptr cinfo) +{ + ppm_source_ptr source; + + /* Create module interface object */ + source = (ppm_source_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(ppm_source_struct)); + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_ppm; + source->pub.finish_input = finish_input_ppm; + + return &source->pub; +} + +#endif /* PPM_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/rdrle.c b/widget/milsko/milskosrc/external/libjpeg/src/rdrle.c new file mode 100644 index 0000000000..06f2e8aad4 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/rdrle.c @@ -0,0 +1,380 @@ +/* + * rdrle.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Utah RLE format. + * The Utah Raster Toolkit library is required (version 3.1 or later). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed RLE format). + * + * Based on code contributed by Mike Lijewski, + * with updates from Robert Hutchinson. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef RLE_SUPPORTED + +/* rle.h is provided by the Utah Raster Toolkit. */ + +#include + +/* + * We assume that JSAMPLE has the same representation as rle_pixel, + * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * We support the following types of RLE files: + * + * GRAYSCALE - 8 bits, no colormap + * MAPPEDGRAY - 8 bits, 1 channel colomap + * PSEUDOCOLOR - 8 bits, 3 channel colormap + * TRUECOLOR - 24 bits, 3 channel colormap + * DIRECTCOLOR - 24 bits, no colormap + * + * For now, we ignore any alpha channel in the image. + */ + +typedef enum + { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind; + + +/* + * Since RLE stores scanlines bottom-to-top, we have to invert the image + * to conform to JPEG's top-to-bottom order. To do this, we read the + * incoming image into a virtual array on the first get_pixel_rows call, + * then fetch the required row from the virtual array on subsequent calls. + */ + +typedef struct _rle_source_struct * rle_source_ptr; + +typedef struct _rle_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + rle_kind visual; /* actual type of input file */ + jvirt_sarray_ptr image; /* virtual array to hold the image */ + JDIMENSION row; /* current row # in the virtual array */ + rle_hdr header; /* Input file information */ + rle_pixel **rle_row; /* holds a row returned by rle_getrow() */ + +} rle_source_struct; + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JDIMENSION width, height; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* Use RLE library routine to get the header info */ + source->header = *rle_hdr_init(NULL); + source->header.rle_file = source->pub.input_file; + switch (rle_get_setup(&(source->header))) { + case RLE_SUCCESS: + /* A-OK */ + break; + case RLE_NOT_RLE: + ERREXIT(cinfo, JERR_RLE_NOT); + case RLE_NO_SPACE: + ERREXIT(cinfo, JERR_RLE_MEM); + case RLE_EMPTY: + ERREXIT(cinfo, JERR_RLE_EMPTY); + case RLE_EOF: + ERREXIT(cinfo, JERR_RLE_EOF); + default: + ERREXIT(cinfo, JERR_RLE_BADERROR); + } + + /* Figure out what we have, set private vars and return values accordingly */ + + width = source->header.xmax - source->header.xmin + 1; + height = source->header.ymax - source->header.ymin + 1; + source->header.xmin = 0; /* realign horizontally */ + source->header.xmax = width-1; + + cinfo->image_width = width; + cinfo->image_height = height; + cinfo->data_precision = 8; /* we can only handle 8 bit data */ + + if (source->header.ncolors == 1 && source->header.ncmap == 0) { + source->visual = GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height); + } else if (source->header.ncolors == 1 && source->header.ncmap == 1) { + source->visual = MAPPEDGRAY; + TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 1 && source->header.ncmap == 3) { + source->visual = PSEUDOCOLOR; + TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 3 && source->header.ncmap == 3) { + source->visual = TRUECOLOR; + TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 3 && source->header.ncmap == 0) { + source->visual = DIRECTCOLOR; + TRACEMS2(cinfo, 1, JTRC_RLE, width, height); + } else + ERREXIT(cinfo, JERR_RLE_UNSUPPORTED); + + if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) { + cinfo->in_color_space = JCS_GRAYSCALE; + cinfo->input_components = 1; + } else { + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = 3; + } + + /* + * A place to hold each scanline while it's converted. + * (GRAYSCALE scanlines don't need converting) + */ + if (source->visual != GRAYSCALE) { + source->rle_row = (rle_pixel **) (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + width, (JDIMENSION) cinfo->input_components); + } + + /* request a virtual array to hold the image */ + source->image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + width * (JDIMENSION) source->header.ncolors, height, (JDIMENSION) 1); + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + /* count file input as separate pass */ + progress->total_extra_passes++; + } +#endif + + source->pub.buffer_height = 1; +} + + +/* + * Read one row of pixels. + * Called only after load_image has read the image into the virtual array. + * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images. + */ + +METHODDEF(JDIMENSION) +get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + + source->row--; + source->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE); + + return 1; +} + +/* + * Read one row of pixels. + * Called only after load_image has read the image into the virtual array. + * Used for PSEUDOCOLOR images. + */ + +METHODDEF(JDIMENSION) +get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JSAMPROW src_row, dest_row; + JDIMENSION col; + rle_map *colormap; + int val; + + colormap = source->header.cmap; + dest_row = source->pub.buffer[0]; + source->row--; + src_row = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE); + + for (col = cinfo->image_width; col > 0; col--) { + val = GETJSAMPLE(*src_row++); + *dest_row++ = (JSAMPLE) (colormap[val ] >> 8); + *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8); + *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8); + } + + return 1; +} + + +/* + * Load the image into a virtual array. We have to do this because RLE + * files start at the lower left while the JPEG standard has them starting + * in the upper left. This is called the first time we want to get a row + * of input. What we do is load the RLE data into the array and then call + * the appropriate routine to read one row from the array. Before returning, + * we set source->pub.get_pixel_rows so that subsequent calls go straight to + * the appropriate row-reading routine. + */ + +METHODDEF(JDIMENSION) +load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JDIMENSION row, col; + JSAMPROW scanline, red_ptr, green_ptr, blue_ptr; + rle_pixel **rle_row; + rle_map *colormap; + char channel; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* Read the RLE data into our virtual array. + * We assume here that (a) rle_pixel is represented the same as JSAMPLE, + * and (b) we are not on a machine where FAR pointers differ from regular. + */ + RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */ + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_limit = cinfo->image_height; + progress->pub.pass_counter = 0; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + + switch (source->visual) { + + case GRAYSCALE: + case PSEUDOCOLOR: + for (row = 0; row < cinfo->image_height; row++) { + rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + rle_getrow(&source->header, rle_row); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + break; + + case MAPPEDGRAY: + case TRUECOLOR: + rle_row = source->rle_row; + colormap = source->header.cmap; + for (row = 0; row < cinfo->image_height; row++) { + rle_getrow(&source->header, rle_row); + scanline = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + + for (col = 0; col < cinfo->image_width; col++) { + for (channel = 0; channel < source->header.ncolors; channel++) { + *scanline++ = (JSAMPLE) + (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8); + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + break; + + case DIRECTCOLOR: + rle_row = source->rle_row; + for (row = 0; row < cinfo->image_height; row++) { + rle_getrow(&source->header, rle_row); + scanline = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + + red_ptr = rle_row[0]; + green_ptr = rle_row[1]; + blue_ptr = rle_row[2]; + + for (col = cinfo->image_width; col > 0; col--) { + *scanline++ = *red_ptr++; + *scanline++ = *green_ptr++; + *scanline++ = *blue_ptr++; + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) + progress->completed_extra_passes++; +#endif + + /* Set up to call proper row-extraction routine in future */ + if (source->visual == PSEUDOCOLOR) { + source->pub.buffer = source->rle_row; + source->pub.get_pixel_rows = get_pseudocolor_row; + } else { + source->pub.get_pixel_rows = get_rle_row; + } + source->row = cinfo->image_height; + + /* And fetch the topmost (bottommost) row */ + return (*source->pub.get_pixel_rows) (cinfo, sinfo); +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for RLE format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_rle (j_compress_ptr cinfo) +{ + rle_source_ptr source; + + /* Create module interface object */ + source = (rle_source_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(rle_source_struct)); + /* Fill in method ptrs */ + source->pub.start_input = start_input_rle; + source->pub.finish_input = finish_input_rle; + source->pub.get_pixel_rows = load_image; + + return &source->pub; +} + +#endif /* RLE_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/rdswitch.c b/widget/milsko/milskosrc/external/libjpeg/src/rdswitch.c new file mode 100644 index 0000000000..8a6675dbc6 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/rdswitch.c @@ -0,0 +1,363 @@ +/* + * rdswitch.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2003-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to process some of cjpeg's more complicated + * command-line switches. Switches processed here are: + * -qtables file Read quantization tables from text file + * -scans file Read scan script from text file + * -quality N[,N,...] Set quality ratings + * -qslots N[,N,...] Set component quantization table selectors + * -sample HxV[,HxV,...] Set component sampling factors + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include /* to declare isdigit(), isspace() */ + + +LOCAL(int) +text_getc (FILE * file) +/* Read next char, skipping over any comments (# to end of line) */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(file); + if (ch == '#') { + do { + ch = getc(file); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(boolean) +read_text_integer (FILE * file, long * result, int * termchar) +/* Read an unsigned decimal integer from a file, store it in result */ +/* Reads one trailing character after the integer; returns it in termchar */ +{ + register int ch; + register long val; + + /* Skip any leading whitespace, detect EOF */ + do { + ch = text_getc(file); + if (ch == EOF) { + *termchar = ch; + return FALSE; + } + } while (isspace(ch)); + + if (! isdigit(ch)) { + *termchar = ch; + return FALSE; + } + + val = ch - '0'; + while ((ch = text_getc(file)) != EOF) { + if (! isdigit(ch)) + break; + val *= 10; + val += ch - '0'; + } + *result = val; + *termchar = ch; + return TRUE; +} + + +GLOBAL(boolean) +read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline) +/* Read a set of quantization tables from the specified file. + * The file is plain ASCII text: decimal numbers with whitespace between. + * Comments preceded by '#' may be included in the file. + * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values. + * The tables are implicitly numbered 0,1,etc. + * NOTE: does not affect the qslots mapping, which will default to selecting + * table 0 for luminance (or primary) components, 1 for chrominance components. + * You must use -qslots if you want a different component->table mapping. + */ +{ + FILE * fp; + int tblno, i, termchar; + long val; + unsigned int table[DCTSIZE2]; + + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Can't open table file %s\n", filename); + return FALSE; + } + tblno = 0; + + while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */ + if (tblno >= NUM_QUANT_TBLS) { + fprintf(stderr, "Too many tables in file %s\n", filename); + fclose(fp); + return FALSE; + } + table[0] = (unsigned int) val; + for (i = 1; i < DCTSIZE2; i++) { + if (! read_text_integer(fp, &val, &termchar)) { + fprintf(stderr, "Invalid table data in file %s\n", filename); + fclose(fp); + return FALSE; + } + table[i] = (unsigned int) val; + } + jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno], + force_baseline); + tblno++; + } + + if (termchar != EOF) { + fprintf(stderr, "Non-numeric data in file %s\n", filename); + fclose(fp); + return FALSE; + } + + fclose(fp); + return TRUE; +} + + +#ifdef C_MULTISCAN_FILES_SUPPORTED + +LOCAL(boolean) +read_scan_integer (FILE * file, long * result, int * termchar) +/* Variant of read_text_integer that always looks for a non-space termchar; + * this simplifies parsing of punctuation in scan scripts. + */ +{ + register int ch; + + if (! read_text_integer(file, result, termchar)) + return FALSE; + ch = *termchar; + while (ch != EOF && isspace(ch)) + ch = text_getc(file); + if (isdigit(ch)) { /* oops, put it back */ + if (ungetc(ch, file) == EOF) + return FALSE; + ch = ' '; + } else { + /* Any separators other than ';' and ':' are ignored; + * this allows user to insert commas, etc, if desired. + */ + if (ch != EOF && ch != ';' && ch != ':') + ch = ' '; + } + *termchar = ch; + return TRUE; +} + + +GLOBAL(boolean) +read_scan_script (j_compress_ptr cinfo, char * filename) +/* Read a scan script from the specified text file. + * Each entry in the file defines one scan to be emitted. + * Entries are separated by semicolons ';'. + * An entry contains one to four component indexes, + * optionally followed by a colon ':' and four progressive-JPEG parameters. + * The component indexes denote which component(s) are to be transmitted + * in the current scan. The first component has index 0. + * Sequential JPEG is used if the progressive-JPEG parameters are omitted. + * The file is free format text: any whitespace may appear between numbers + * and the ':' and ';' punctuation marks. Also, other punctuation (such + * as commas or dashes) can be placed between numbers if desired. + * Comments preceded by '#' may be included in the file. + * Note: we do very little validity checking here; + * jcmaster.c will validate the script parameters. + */ +{ + FILE * fp; + int scanno, ncomps, termchar; + long val; + jpeg_scan_info * scanptr; +#define MAX_SCANS 100 /* quite arbitrary limit */ + jpeg_scan_info scans[MAX_SCANS]; + + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Can't open scan definition file %s\n", filename); + return FALSE; + } + scanptr = scans; + scanno = 0; + + while (read_scan_integer(fp, &val, &termchar)) { + if (scanno >= MAX_SCANS) { + fprintf(stderr, "Too many scans defined in file %s\n", filename); + fclose(fp); + return FALSE; + } + scanptr->component_index[0] = (int) val; + ncomps = 1; + while (termchar == ' ') { + if (ncomps >= MAX_COMPS_IN_SCAN) { + fprintf(stderr, "Too many components in one scan in file %s\n", + filename); + fclose(fp); + return FALSE; + } + if (! read_scan_integer(fp, &val, &termchar)) + goto bogus; + scanptr->component_index[ncomps] = (int) val; + ncomps++; + } + scanptr->comps_in_scan = ncomps; + if (termchar == ':') { + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Ss = (int) val; + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Se = (int) val; + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Ah = (int) val; + if (! read_scan_integer(fp, &val, &termchar)) + goto bogus; + scanptr->Al = (int) val; + } else { + /* set non-progressive parameters */ + scanptr->Ss = 0; + scanptr->Se = DCTSIZE2-1; + scanptr->Ah = 0; + scanptr->Al = 0; + } + if (termchar != ';' && termchar != EOF) { +bogus: + fprintf(stderr, "Invalid scan entry format in file %s\n", filename); + fclose(fp); + return FALSE; + } + scanptr++, scanno++; + } + + if (termchar != EOF) { + fprintf(stderr, "Non-numeric data in file %s\n", filename); + fclose(fp); + return FALSE; + } + + if (scanno > 0) { + /* Stash completed scan list in cinfo structure. + * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data, + * but if you want to compress multiple images you'd want JPOOL_PERMANENT. + */ + scanptr = (jpeg_scan_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, scanno * SIZEOF(jpeg_scan_info)); + MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info)); + cinfo->scan_info = scanptr; + cinfo->num_scans = scanno; + } + + fclose(fp); + return TRUE; +} + +#endif /* C_MULTISCAN_FILES_SUPPORTED */ + + +GLOBAL(boolean) +set_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline) +/* Process a quality-ratings parameter string, of the form + * N[,N,...] + * If there are more q-table slots than parameters, the last value is replicated. + */ +{ + int val = 75; /* default value */ + int tblno; + char ch; + + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + if (*arg) { + ch = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c", &val, &ch) < 1) + return FALSE; + if (ch != ',') /* syntax check */ + return FALSE; + /* Convert user 0-100 rating to percentage scaling */ + cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val); + while (*arg && *arg++ != ','); /* advance to next segment of arg string */ + } else { + /* reached end of parameter, set remaining factors to last value */ + cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val); + } + } + jpeg_default_qtables(cinfo, force_baseline); + return TRUE; +} + + +GLOBAL(boolean) +set_quant_slots (j_compress_ptr cinfo, char *arg) +/* Process a quantization-table-selectors parameter string, of the form + * N[,N,...] + * If there are more components than parameters, the last value is replicated. + */ +{ + int val = 0; /* default table # */ + int ci; + char ch; + + for (ci = 0; ci < MAX_COMPONENTS; ci++) { + if (*arg) { + ch = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c", &val, &ch) < 1) + return FALSE; + if (ch != ',') /* syntax check */ + return FALSE; + if (val < 0 || val >= NUM_QUANT_TBLS) { + fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n", + NUM_QUANT_TBLS-1); + return FALSE; + } + cinfo->comp_info[ci].quant_tbl_no = val; + while (*arg && *arg++ != ','); /* advance to next segment of arg string */ + } else { + /* reached end of parameter, set remaining components to last table */ + cinfo->comp_info[ci].quant_tbl_no = val; + } + } + return TRUE; +} + + +GLOBAL(boolean) +set_sample_factors (j_compress_ptr cinfo, char *arg) +/* Process a sample-factors parameter string, of the form + * HxV[,HxV,...] + * If there are more components than parameters, "1x1" is assumed for the rest. + */ +{ + int ci, val1, val2; + char ch1, ch2; + + for (ci = 0; ci < MAX_COMPONENTS; ci++) { + if (*arg) { + ch2 = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3) + return FALSE; + if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */ + return FALSE; + if (val1 <= 0 || val1 > MAX_SAMP_FACTOR || + val2 <= 0 || val2 > MAX_SAMP_FACTOR) { + fprintf(stderr, "JPEG sampling factors must be 1..%d\n", MAX_SAMP_FACTOR); + return FALSE; + } + cinfo->comp_info[ci].h_samp_factor = val1; + cinfo->comp_info[ci].v_samp_factor = val2; + while (*arg && *arg++ != ','); /* advance to next segment of arg string */ + } else { + /* reached end of parameter, set remaining components to 1x1 sampling */ + cinfo->comp_info[ci].h_samp_factor = 1; + cinfo->comp_info[ci].v_samp_factor = 1; + } + } + return TRUE; +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/rdtarga.c b/widget/milsko/milskosrc/external/libjpeg/src/rdtarga.c new file mode 100644 index 0000000000..c72ad73f6c --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/rdtarga.c @@ -0,0 +1,500 @@ +/* + * rdtarga.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2017-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Targa format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed Targa format). + * + * Based on code contributed by Lee Daniel Crocker. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef TARGA_SUPPORTED + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +typedef char U_CHAR; +#ifdef CHAR_IS_UNSIGNED +#define UCH(x) ((int) (x)) +#else +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* Private version of data source object */ + +typedef struct _tga_source_struct * tga_source_ptr; + +typedef struct _tga_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + j_compress_ptr cinfo; /* back link saves passing separate parm */ + + JSAMPARRAY colormap; /* Targa colormap (converted to my format) */ + + jvirt_sarray_ptr whole_image; /* Needed if funny input row order */ + JDIMENSION current_row; /* Current logical row number to read */ + + /* Pointer to routine to extract next Targa pixel from input file */ + JMETHOD(void, read_pixel, (tga_source_ptr sinfo)); + + /* Result of read_pixel is delivered here: */ + U_CHAR tga_pixel[4]; + + int pixel_size; /* Bytes per Targa pixel (1 to 4) */ + int cmap_length; /* colormap length */ + + /* State info for reading RLE-coded pixels; both counts must be init to 0 */ + int block_count; /* # of pixels remaining in RLE block */ + int dup_pixel_count; /* # of times to duplicate previous pixel */ + + /* This saves the correct pixel-row-expansion method for preload_image */ + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); +} tga_source_struct; + + +/* For expanding 5-bit pixel values to 8-bit with best rounding */ + +static const UINT8 c5to8bits[32] = { + 0, 8, 16, 25, 33, 41, 49, 58, + 66, 74, 82, 90, 99, 107, 115, 123, + 132, 140, 148, 156, 165, 173, 181, 189, + 197, 206, 214, 222, 230, 239, 247, 255 +}; + + + +LOCAL(int) +read_byte (tga_source_ptr sinfo) +/* Read next byte from Targa file */ +{ + register FILE *infile = sinfo->pub.input_file; + register int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); + return c; +} + + +LOCAL(void) +read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize) +/* Read the colormap from a Targa file */ +{ + int i; + + /* Presently only handles 24-bit BGR format */ + if (mapentrysize != 24) + ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP); + + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + } +} + + +/* + * read_pixel methods: get a single pixel from Targa file into tga_pixel[] + */ + +METHODDEF(void) +read_non_rle_pixel (tga_source_ptr sinfo) +/* Read one Targa pixel from the input file; no RLE expansion */ +{ + register int i; + + for (i = 0; i < sinfo->pixel_size; i++) { + sinfo->tga_pixel[i] = (U_CHAR) read_byte(sinfo); + } +} + +METHODDEF(void) +read_rle_pixel (tga_source_ptr sinfo) +/* Read one Targa pixel from the input file, expanding RLE data as needed */ +{ + register int i; + + /* Duplicate previously read pixel? */ + if (sinfo->dup_pixel_count > 0) { + sinfo->dup_pixel_count--; + return; + } + + /* Time to read RLE block header? */ + if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */ + i = read_byte(sinfo); + if (i & 0x80) { /* Start of duplicate-pixel block? */ + sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */ + sinfo->block_count = 0; /* then read new block header */ + } else { + sinfo->block_count = i & 0x7F; /* number of pixels after this one */ + } + } + + /* Read next pixel */ + for (i = 0; i < sinfo->pixel_size; i++) { + sinfo->tga_pixel[i] = (U_CHAR) read_byte(sinfo); + } +} + + +/* + * Read one row of pixels. + * + * We provide several different versions depending on input file format. + */ + +METHODDEF(JDIMENSION) +get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit grayscale pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]); + } + return 1; +} + +METHODDEF(JDIMENSION) +get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit colormap indexes */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register JSAMPROW ptr; + register JSAMPARRAY colormap; + register JDIMENSION col; + register int t; + int cmaplen; + + ptr = source->pub.buffer[0]; + colormap = source->colormap; + cmaplen = source->cmap_length; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + t = UCH(source->tga_pixel[0]); + if (t >= cmaplen) + ERREXIT(cinfo, JERR_TGA_BADPARMS); + *ptr++ = colormap[0][t]; + *ptr++ = colormap[1][t]; + *ptr++ = colormap[2][t]; + } + return 1; +} + +METHODDEF(JDIMENSION) +get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 16-bit pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register int t; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + t = UCH(source->tga_pixel[0]); + t += UCH(source->tga_pixel[1]) << 8; + /* We expand 5 bit data to 8 bit sample width. + * The format of the 16-bit (LSB first) input word is + * xRRRRRGGGGGBBBBB + */ + ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F]; + t >>= 5; + ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F]; + t >>= 5; + ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F]; + ptr += 3; + } + return 1; +} + +METHODDEF(JDIMENSION) +get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 24-bit pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]); + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]); + } + return 1; +} + +/* + * Targa also defines a 32-bit pixel format with order B,G,R,A. + * We presently ignore the attribute byte, so the code for reading + * these pixels is identical to the 24-bit routine above. + * This works because the actual pixel length is only known to read_pixel. + */ + +#define get_32bit_row get_24bit_row + + +/* + * This method is for re-reading the input data in standard top-down + * row order. The entire image has already been read into whole_image + * with proper conversion of pixel format, but it's in a funny row order. + */ + +METHODDEF(JDIMENSION) +get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + JDIMENSION source_row; + + /* Compute row of source that maps to current_row of normal order */ + /* For now, assume image is bottom-up and not interlaced. */ + /* NEEDS WORK to support interlaced images! */ + source_row = cinfo->image_height - source->current_row - 1; + + /* Fetch that row from virtual array */ + source->pub.buffer = (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + source->whole_image, source_row, (JDIMENSION) 1, FALSE); + + source->current_row++; + return 1; +} + + +/* + * This method loads the image into whole_image during the first call on + * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call + * get_memory_row on subsequent calls. + */ + +METHODDEF(JDIMENSION) +preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + JDIMENSION row; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Read the data into a virtual array in input-file row order. */ + for (row = 0; row < cinfo->image_height; row++) { + if (progress != NULL) { + progress->pub.pass_counter = (long) row; + progress->pub.pass_limit = (long) cinfo->image_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + source->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE); + (*source->get_pixel_rows) (cinfo, sinfo); + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Set up to read from the virtual array in unscrambled order */ + source->pub.get_pixel_rows = get_memory_row; + source->current_row = 0; + /* And read the first row */ + return get_memory_row(cinfo, sinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + U_CHAR targaheader[18]; + int idlen, cmaptype, subtype, flags, interlace_type, components; + unsigned int width, height, maplen; + boolean is_bottom_up; + +#define GET_2B(offset) ((unsigned int) UCH(targaheader[offset]) + \ + (((unsigned int) UCH(targaheader[offset+1])) << 8)) + + if (! ReadOK(source->pub.input_file, targaheader, 18)) + ERREXIT(cinfo, JERR_INPUT_EOF); + + /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */ + if (targaheader[16] == 15) + targaheader[16] = 16; + + idlen = UCH(targaheader[0]); + cmaptype = UCH(targaheader[1]); + subtype = UCH(targaheader[2]); + maplen = GET_2B(5); + width = GET_2B(12); + height = GET_2B(14); + source->pixel_size = UCH(targaheader[16]) >> 3; + flags = UCH(targaheader[17]); /* Image Descriptor byte */ + + is_bottom_up = ((flags & 0x20) == 0); /* bit 5 set => top-down */ + interlace_type = flags >> 6; /* bits 6/7 are interlace code */ + + if (cmaptype > 1 || /* cmaptype must be 0 or 1 */ + width <= 0 || height <= 0 || + source->pixel_size < 1 || source->pixel_size > 4 || + (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */ + interlace_type != 0) /* currently don't allow interlaced image */ + ERREXIT(cinfo, JERR_TGA_BADPARMS); + + if (subtype > 8) { + /* It's an RLE-coded file */ + source->read_pixel = read_rle_pixel; + source->block_count = source->dup_pixel_count = 0; + subtype -= 8; + } else { + /* Non-RLE file */ + source->read_pixel = read_non_rle_pixel; + } + + /* Now should have subtype 1, 2, or 3 */ + components = 3; /* until proven different */ + cinfo->in_color_space = JCS_RGB; + + switch (subtype) { + case 1: /* Colormapped image */ + if (source->pixel_size == 1 && cmaptype == 1) + source->get_pixel_rows = get_8bit_row; + else + ERREXIT(cinfo, JERR_TGA_BADPARMS); + TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height); + break; + case 2: /* RGB image */ + switch (source->pixel_size) { + case 2: + source->get_pixel_rows = get_16bit_row; + break; + case 3: + source->get_pixel_rows = get_24bit_row; + break; + case 4: + source->get_pixel_rows = get_32bit_row; + break; + default: + ERREXIT(cinfo, JERR_TGA_BADPARMS); + } + TRACEMS2(cinfo, 1, JTRC_TGA, width, height); + break; + case 3: /* Grayscale image */ + components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + if (source->pixel_size == 1) + source->get_pixel_rows = get_8bit_gray_row; + else + ERREXIT(cinfo, JERR_TGA_BADPARMS); + TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height); + break; + default: + ERREXIT(cinfo, JERR_TGA_BADPARMS); + } + + if (is_bottom_up) { + /* Create a virtual array to buffer the upside-down image. */ + source->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1); + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + /* source->pub.buffer will point to the virtual array. */ + source->pub.buffer_height = 1; /* in case anyone looks at it */ + source->pub.get_pixel_rows = preload_image; + } else { + /* Don't need a virtual array, but do need a one-row input buffer. */ + source->whole_image = NULL; + source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, + JPOOL_IMAGE, (JDIMENSION) width * components, (JDIMENSION) 1); + source->pub.buffer_height = 1; + source->pub.get_pixel_rows = source->get_pixel_rows; + } + + while (idlen--) /* Throw away ID field */ + (void) read_byte(source); + + if (maplen > 0) { + if (maplen > 256 || GET_2B(3) != 0) + ERREXIT(cinfo, JERR_TGA_BADCMAP); + /* Allocate space to store the colormap */ + source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, + JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3); + source->cmap_length = (int) maplen; + /* and read it from the file */ + read_colormap(source, (int) maplen, UCH(targaheader[7])); + } else { + if (cmaptype) /* but you promised a cmap! */ + ERREXIT(cinfo, JERR_TGA_BADPARMS); + source->colormap = NULL; + source->cmap_length = 0; + } + + cinfo->input_components = components; + cinfo->data_precision = 8; + cinfo->image_width = width; + cinfo->image_height = height; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for Targa format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_targa (j_compress_ptr cinfo) +{ + tga_source_ptr source; + + /* Create module interface object */ + source = (tga_source_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(tga_source_struct)); + source->cinfo = cinfo; /* make back link for subroutines */ + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_tga; + source->pub.finish_input = finish_input_tga; + + return &source->pub; +} + +#endif /* TARGA_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/transupp.c b/widget/milsko/milskosrc/external/libjpeg/src/transupp.c new file mode 100644 index 0000000000..22c369b7e5 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/transupp.c @@ -0,0 +1,2433 @@ +/* + * transupp.c + * + * Copyright (C) 1997-2023, Thomas G. Lane, Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains image transformation routines and other utility code + * used by the jpegtran sample application. These are NOT part of the core + * JPEG library. But we keep these routines separate from jpegtran.c to + * ease the task of maintaining jpegtran-like programs that have other user + * interfaces. + */ + +/* Although this file really shouldn't have access to the library internals, + * it's helpful to let it call jround_up() and jcopy_block_row(). + * Also, the (switchable) virtual memory adaptation code for + * the drop feature has dependencies on library internals. + */ +#define JPEG_INTERNALS + +#include "jinclude.h" +#include "jpeglib.h" +#include "transupp.h" /* My own external interface */ +#include /* to declare isdigit() */ + + +#if TRANSFORMS_SUPPORTED + +/* + * Lossless image transformation routines. These routines work on DCT + * coefficient arrays and thus do not require any lossy decompression + * or recompression of the image. + * Thanks to Guido Vollbeding for the initial design and code of this feature, + * and to Ben Jackson for introducing the cropping feature. + * + * Horizontal flipping is done in-place, using a single top-to-bottom + * pass through the virtual source array. It will thus be much the + * fastest option for images larger than main memory. + * + * The other routines require a set of destination virtual arrays, so they + * need twice as much memory as jpegtran normally does. The destination + * arrays are always written in normal scan order (top to bottom) because + * the virtual array manager expects this. The source arrays will be scanned + * in the corresponding order, which means multiple passes through the source + * arrays for most of the transforms. That could result in much thrashing + * if the image is larger than main memory. + * + * If cropping or trimming is involved, the destination arrays may be smaller + * than the source arrays. Note it is not possible to do horizontal flip + * in-place when a nonzero Y crop offset is specified, since we'd have to move + * data from one block row to another but the virtual array manager doesn't + * guarantee we can touch more than one row at a time. So in that case, + * we have to use a separate destination array. + * + * Some notes about the operating environment of the individual transform + * routines: + * 1. Both the source and destination virtual arrays are allocated from the + * source JPEG object, and therefore should be manipulated by calling the + * source's memory manager. + * 2. The destination's component count should be used. It may be smaller + * than the source's when forcing to grayscale. + * 3. Likewise the destination's sampling factors should be used. When + * forcing to grayscale the destination's sampling factors will be all 1, + * and we may as well take that as the effective iMCU size. + * 4. When "trim" is in effect, the destination's dimensions will be the + * trimmed values but the source's will be untrimmed. + * 5. When "crop" is in effect, the destination's dimensions will be the + * cropped values but the source's will be uncropped. Each transform + * routine is responsible for picking up source data starting at the + * correct X and Y offset for the crop region. (The X and Y offsets + * passed to the transform routines are measured in iMCU blocks of the + * destination.) + * 6. All the routines assume that the source and destination buffers are + * padded out to a full iMCU boundary. This is true, although for the + * source buffer it is an undocumented property of jdcoefct.c. + */ + + +/* Drop code may be used with or without virtual memory adaptation code. + * This code has some dependencies on internal library behavior, so you + * may choose to disable it. For example, it doesn't make a difference + * if you only use jmemnobs anyway. + */ +#ifndef DROP_REQUEST_FROM_SRC +#define DROP_REQUEST_FROM_SRC 1 /* 0 disables adaptation */ +#endif + + +#if DROP_REQUEST_FROM_SRC +/* Force jpeg_read_coefficients to request + * the virtual coefficient arrays from + * the source decompression object. + */ +METHODDEF(jvirt_barray_ptr) +drop_request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +{ + j_common_ptr srcinfo = (j_common_ptr) cinfo->client_data; + + return (*srcinfo->mem->request_virt_barray) + (srcinfo, pool_id, pre_zero, + blocksperrow, numrows, maxaccess); +} + + +/* Force jpeg_read_coefficients to return + * after requesting and before accessing + * the virtual coefficient arrays. + */ +METHODDEF(int) +drop_consume_input (j_decompress_ptr cinfo) +{ + return JPEG_SUSPENDED; +} + + +METHODDEF(void) +drop_start_input_pass (j_decompress_ptr cinfo) +{ + cinfo->inputctl->consume_input = drop_consume_input; +} + + +LOCAL(void) +drop_request_from_src (j_decompress_ptr dropinfo, j_decompress_ptr srcinfo) +{ + void *save_client_data; + JMETHOD(jvirt_barray_ptr, save_request_virt_barray, + (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, JDIMENSION maxaccess)); + JMETHOD(void, save_start_input_pass, (j_decompress_ptr cinfo)); + + /* Set custom method pointers, save original pointers */ + save_client_data = dropinfo->client_data; + dropinfo->client_data = (void *) srcinfo; + save_request_virt_barray = dropinfo->mem->request_virt_barray; + dropinfo->mem->request_virt_barray = drop_request_virt_barray; + save_start_input_pass = dropinfo->inputctl->start_input_pass; + dropinfo->inputctl->start_input_pass = drop_start_input_pass; + + /* Execute only initialization part. + * Requested coefficient arrays will be realized later by the srcinfo object. + * Next call to the same function will then do the actual data reading. + * NB: since we request the coefficient arrays from another object, + * the inherent realization call is effectively a no-op. + */ + (void) jpeg_read_coefficients(dropinfo); + + /* Reset method pointers */ + dropinfo->client_data = save_client_data; + dropinfo->mem->request_virt_barray = save_request_virt_barray; + dropinfo->inputctl->start_input_pass = save_start_input_pass; + /* Do input initialization for first scan now, + * which also resets the consume_input method. + */ + (*save_start_input_pass)(dropinfo); +} +#endif /* DROP_REQUEST_FROM_SRC */ + + +LOCAL(void) +dequant_comp (j_decompress_ptr cinfo, jpeg_component_info *compptr, + jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1) +{ + JDIMENSION blk_x, blk_y; + int offset_y, k; + JQUANT_TBL *qtblptr; + JBLOCKARRAY buffer; + JBLOCKROW block; + JCOEFPTR ptr; + + qtblptr = compptr->quant_table; + for (blk_y = 0; blk_y < compptr->height_in_blocks; + blk_y += compptr->v_samp_factor) { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef_array, blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + block = buffer[offset_y]; + for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { + ptr = block[blk_x]; + for (k = 0; k < DCTSIZE2; k++) + if (qtblptr->quantval[k] != qtblptr1->quantval[k]) + ptr[k] *= qtblptr->quantval[k] / qtblptr1->quantval[k]; + } + } + } +} + + +LOCAL(void) +requant_comp (j_decompress_ptr cinfo, jpeg_component_info *compptr, + jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1) +{ + JDIMENSION blk_x, blk_y; + int offset_y, k, temp, qval; + JQUANT_TBL *qtblptr; + JBLOCKARRAY buffer; + JBLOCKROW block; + JCOEFPTR ptr; + + qtblptr = compptr->quant_table; + for (blk_y = 0; blk_y < compptr->height_in_blocks; + blk_y += compptr->v_samp_factor) { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef_array, blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + block = buffer[offset_y]; + for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { + ptr = block[blk_x]; + for (k = 0; k < DCTSIZE2; k++) { + qval = qtblptr1->quantval[k]; + if (qval == 0) continue; + temp = qtblptr->quantval[k]; + if (temp == qval) continue; + temp *= ptr[k]; + /* The following quantization code is a copy from jcdctmgr.c */ +#ifdef FAST_DIVIDE +#define DIVIDE_BY(a,b) a /= b +#else +#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 +#endif + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + } + ptr[k] = (JCOEF) temp; + } + } + } + } +} + + +/* Calculate largest common denominator with Euclid's algorithm. + */ +LOCAL(JCOEF) +largest_common_denominator(JCOEF a, JCOEF b) +{ + JCOEF c; + + while (b) { + c = a % b; + a = b; + b = c; + } + + return a; +} + + +LOCAL(void) +adjust_quant(j_decompress_ptr srcinfo, jvirt_barray_ptr *src_coef_arrays, + j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays, + boolean trim, j_compress_ptr dstinfo) +{ + jpeg_component_info *compptr1, *compptr2; + JQUANT_TBL *qtblptr1, *qtblptr2, *qtblptr3; + int ci, k; + + for (ci = 0; ci < dstinfo->num_components && + ci < dropinfo->num_components; ci++) { + compptr1 = srcinfo->comp_info + ci; + compptr2 = dropinfo->comp_info + ci; + qtblptr1 = compptr1->quant_table; + qtblptr2 = compptr2->quant_table; + for (k = 0; k < DCTSIZE2; k++) { + if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) { + if (trim) + requant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr1); + else { + qtblptr3 = dstinfo->quant_tbl_ptrs[compptr1->quant_tbl_no]; + for (k = 0; k < DCTSIZE2; k++) + if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) + qtblptr3->quantval[k] = largest_common_denominator + (qtblptr1->quantval[k], qtblptr2->quantval[k]); + dequant_comp(srcinfo, compptr1, src_coef_arrays[ci], qtblptr3); + dequant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr3); + } + break; + } + } + } +} + + +LOCAL(void) +do_drop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays, + JDIMENSION drop_width, JDIMENSION drop_height) +/* Drop. If the dropinfo component number is smaller than the destination's, + * we fill in the remaining components with zero. This provides the feature + * of dropping grayscale into (arbitrarily sampled) color images. + */ +{ + JDIMENSION comp_width, comp_height; + JDIMENSION blk_y, x_drop_blocks, y_drop_blocks; + int ci, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + jpeg_component_info *compptr; + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = drop_width * compptr->h_samp_factor; + comp_height = drop_height * compptr->v_samp_factor; + x_drop_blocks = x_crop_offset * compptr->h_samp_factor; + y_drop_blocks = y_crop_offset * compptr->v_samp_factor; + for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y + y_drop_blocks, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (ci < dropinfo->num_components) { +#if DROP_REQUEST_FROM_SRC + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, drop_coef_arrays[ci], blk_y, +#else + src_buffer = (*dropinfo->mem->access_virt_barray) + ((j_common_ptr) dropinfo, drop_coef_arrays[ci], blk_y, +#endif + (JDIMENSION) compptr->v_samp_factor, FALSE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + jcopy_block_row(src_buffer[offset_y], + dst_buffer[offset_y] + x_drop_blocks, + comp_width); + } + } else { + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + FMEMZERO(dst_buffer[offset_y] + x_drop_blocks, + comp_width * SIZEOF(JBLOCK)); + } + } + } + } +} + + +LOCAL(void) +do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Crop. This is only used when no rotate/flip is requested with the crop. */ +{ + JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + jpeg_component_info *compptr; + + /* We simply have to copy the right amount of data (the destination's + * image size) starting at the given X and Y offsets in the source. + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, + dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } +} + + +LOCAL(void) +do_crop_ext_zero (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Crop. This is only used when no rotate/flip is requested with the crop. + * Extension: If the destination size is larger than the source, we fill in + * the extra area with zero (neutral gray). Note we also have to zero partial + * iMCUs at the right and bottom edge of the source image area in this case. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height; + JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + jpeg_component_info *compptr; + + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + MCU_rows = srcinfo->output_height / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dstinfo->jpeg_height > srcinfo->output_height) { + if (dst_blk_y < y_crop_blocks || + dst_blk_y >= y_crop_blocks + comp_height) { + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + FMEMZERO(dst_buffer[offset_y], + compptr->width_in_blocks * SIZEOF(JBLOCK)); + } + continue; + } + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y - y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (dstinfo->jpeg_width > srcinfo->output_width) { + if (x_crop_blocks > 0) { + FMEMZERO(dst_buffer[offset_y], + x_crop_blocks * SIZEOF(JBLOCK)); + } + jcopy_block_row(src_buffer[offset_y], + dst_buffer[offset_y] + x_crop_blocks, + comp_width); + if (compptr->width_in_blocks > x_crop_blocks + comp_width) { + FMEMZERO(dst_buffer[offset_y] + + x_crop_blocks + comp_width, + (compptr->width_in_blocks - + x_crop_blocks - comp_width) * SIZEOF(JBLOCK)); + } + } else { + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, + dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } + } +} + + +LOCAL(void) +do_crop_ext_flat (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Crop. This is only used when no rotate/flip is requested with the crop. + * Extension: The destination width is larger than the source and we fill in + * the extra area with the DC of the adjacent block. Note we also have to + * fill partial iMCUs at the right and bottom edge of the source image area + * in this case. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height; + JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, offset_y; + JCOEF dc; + JBLOCKARRAY src_buffer, dst_buffer; + jpeg_component_info *compptr; + + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + MCU_rows = srcinfo->output_height / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dstinfo->jpeg_height > srcinfo->output_height) { + if (dst_blk_y < y_crop_blocks || + dst_blk_y >= y_crop_blocks + comp_height) { + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + FMEMZERO(dst_buffer[offset_y], + compptr->width_in_blocks * SIZEOF(JBLOCK)); + } + continue; + } + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y - y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (x_crop_blocks > 0) { + FMEMZERO(dst_buffer[offset_y], + x_crop_blocks * SIZEOF(JBLOCK)); + dc = src_buffer[offset_y][0][0]; + for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) { + dst_buffer[offset_y][dst_blk_x][0] = dc; + } + } + jcopy_block_row(src_buffer[offset_y], + dst_buffer[offset_y] + x_crop_blocks, + comp_width); + if (compptr->width_in_blocks > x_crop_blocks + comp_width) { + FMEMZERO(dst_buffer[offset_y] + + x_crop_blocks + comp_width, + (compptr->width_in_blocks - + x_crop_blocks - comp_width) * SIZEOF(JBLOCK)); + dc = src_buffer[offset_y][comp_width - 1][0]; + for (dst_blk_x = x_crop_blocks + comp_width; + dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_buffer[offset_y][dst_blk_x][0] = dc; + } + } + } + } + } +} + + +LOCAL(void) +do_crop_ext_reflect (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Crop. This is only used when no rotate/flip is requested with the crop. + * Extension: The destination width is larger than the source and we fill in + * the extra area with repeated reflections of the source region. Note we + * also have to fill partial iMCUs at the right and bottom edge of the source + * image area in this case. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, src_blk_x; + JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, k, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + MCU_rows = srcinfo->output_height / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dstinfo->jpeg_height > srcinfo->output_height) { + if (dst_blk_y < y_crop_blocks || + dst_blk_y >= y_crop_blocks + comp_height) { + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + FMEMZERO(dst_buffer[offset_y], + compptr->width_in_blocks * SIZEOF(JBLOCK)); + } + continue; + } + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y - y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + /* Copy source region */ + jcopy_block_row(src_buffer[offset_y], + dst_buffer[offset_y] + x_crop_blocks, + comp_width); + if (x_crop_blocks > 0) { + /* Reflect to left */ + dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks; + for (dst_blk_x = x_crop_blocks; dst_blk_x > 0;) { + src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */ + for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0; + src_blk_x--, dst_blk_x--) { + dst_ptr = *--dst_row_ptr; /* destination goes left */ + src_ptr = *src_row_ptr++; /* source goes right */ + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + *dst_ptr++ = *src_ptr++; /* copy even column */ + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ + } + } + } + } + if (compptr->width_in_blocks > x_crop_blocks + comp_width) { + /* Reflect to right */ + dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks + comp_width; + for (dst_blk_x = compptr->width_in_blocks - x_crop_blocks - comp_width; + dst_blk_x > 0;) { + src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */ + for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0; + src_blk_x--, dst_blk_x--) { + dst_ptr = *dst_row_ptr++; /* destination goes right */ + src_ptr = *--src_row_ptr; /* source goes left */ + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + *dst_ptr++ = *src_ptr++; /* copy even column */ + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ + } + } + } + } + } + } + } +} + + +LOCAL(void) +do_wipe (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + JDIMENSION drop_width, JDIMENSION drop_height) +/* Wipe - drop content of specified area, fill with zero (neutral gray) */ +{ + JDIMENSION x_wipe_blocks, wipe_width; + JDIMENSION y_wipe_blocks, wipe_bottom; + int ci, offset_y; + JBLOCKARRAY buffer; + jpeg_component_info *compptr; + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + x_wipe_blocks = x_crop_offset * compptr->h_samp_factor; + wipe_width = drop_width * compptr->h_samp_factor; + y_wipe_blocks = y_crop_offset * compptr->v_samp_factor; + wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks; + for (; y_wipe_blocks < wipe_bottom; + y_wipe_blocks += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + FMEMZERO(buffer[offset_y] + x_wipe_blocks, + wipe_width * SIZEOF(JBLOCK)); + } + } + } +} + + +LOCAL(void) +do_flatten (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + JDIMENSION drop_width, JDIMENSION drop_height) +/* Flatten - drop content of specified area, similar to wipe, + * but fill with average of adjacent blocks, instead of zero. + */ +{ + JDIMENSION x_wipe_blocks, wipe_width, wipe_right; + JDIMENSION y_wipe_blocks, wipe_bottom, blk_x; + int ci, offset_y, dc_left_value, dc_right_value, average; + JBLOCKARRAY buffer; + jpeg_component_info *compptr; + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + x_wipe_blocks = x_crop_offset * compptr->h_samp_factor; + wipe_width = drop_width * compptr->h_samp_factor; + wipe_right = wipe_width + x_wipe_blocks; + y_wipe_blocks = y_crop_offset * compptr->v_samp_factor; + wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks; + for (; y_wipe_blocks < wipe_bottom; + y_wipe_blocks += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + FMEMZERO(buffer[offset_y] + x_wipe_blocks, + wipe_width * SIZEOF(JBLOCK)); + if (x_wipe_blocks > 0) { + dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0]; + if (wipe_right < compptr->width_in_blocks) { + dc_right_value = buffer[offset_y][wipe_right][0]; + average = (dc_left_value + dc_right_value) >> 1; + } else { + average = dc_left_value; + } + } else if (wipe_right < compptr->width_in_blocks) { + average = buffer[offset_y][wipe_right][0]; + } else continue; + for (blk_x = x_wipe_blocks; blk_x < wipe_right; blk_x++) { + buffer[offset_y][blk_x][0] = (JCOEF) average; + } + } + } + } +} + + +LOCAL(void) +do_reflect (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + JDIMENSION drop_width, JDIMENSION drop_height) +/* Reflect - drop content of specified area, similar to wipe, but + * fill with repeated reflections of the outside area, instead of zero. + * NB: y_crop_offset is assumed to be zero. + */ +{ + JDIMENSION x_wipe_blocks, wipe_width; + JDIMENSION y_wipe_blocks, wipe_bottom; + JDIMENSION src_blk_x, dst_blk_x; + int ci, k, offset_y; + JBLOCKARRAY buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + x_wipe_blocks = x_crop_offset * compptr->h_samp_factor; + wipe_width = drop_width * compptr->h_samp_factor; + wipe_bottom = drop_height * compptr->v_samp_factor; + for (y_wipe_blocks = 0; y_wipe_blocks < wipe_bottom; + y_wipe_blocks += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (x_wipe_blocks > 0) { + /* Reflect from left */ + dst_row_ptr = buffer[offset_y] + x_wipe_blocks; + for (dst_blk_x = wipe_width; dst_blk_x > 0;) { + src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */ + for (src_blk_x = x_wipe_blocks; + src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) { + dst_ptr = *dst_row_ptr++; /* destination goes right */ + src_ptr = *--src_row_ptr; /* source goes left */ + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + *dst_ptr++ = *src_ptr++; /* copy even column */ + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ + } + } + } + } else if (compptr->width_in_blocks > x_wipe_blocks + wipe_width) { + /* Reflect from right */ + dst_row_ptr = buffer[offset_y] + x_wipe_blocks + wipe_width; + for (dst_blk_x = wipe_width; dst_blk_x > 0;) { + src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */ + src_blk_x = compptr->width_in_blocks - x_wipe_blocks - wipe_width; + for (; src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) { + dst_ptr = *--dst_row_ptr; /* destination goes left */ + src_ptr = *src_row_ptr++; /* source goes right */ + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + *dst_ptr++ = *src_ptr++; /* copy even column */ + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ + } + } + } + } else { + FMEMZERO(buffer[offset_y] + x_wipe_blocks, + wipe_width * SIZEOF(JBLOCK)); + } + } + } + } +} + + +LOCAL(void) +do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, + jvirt_barray_ptr *src_coef_arrays) +/* Horizontal flip; done in-place, so no separate dest array is required. + * NB: this only works when y_crop_offset is zero. + */ +{ + JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; + int ci, k, offset_y; + JBLOCKARRAY buffer; + JCOEFPTR ptr1, ptr2; + JCOEF temp1, temp2; + jpeg_component_info *compptr; + + /* Horizontal mirroring of DCT blocks is accomplished by swapping + * pairs of blocks in-place. Within a DCT block, we perform horizontal + * mirroring by changing the signs of odd-numbered columns. + * Partial iMCUs at the right edge are left untouched. + */ + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + for (blk_y = 0; blk_y < compptr->height_in_blocks; + blk_y += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + /* Do the mirroring */ + for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { + ptr1 = buffer[offset_y][blk_x]; + ptr2 = buffer[offset_y][comp_width - blk_x - 1]; + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + temp1 = *ptr1; /* swap even column */ + temp2 = *ptr2; + *ptr1++ = temp2; + *ptr2++ = temp1; + temp1 = *ptr1; /* swap odd column with sign change */ + temp2 = *ptr2; + *ptr1++ = -temp2; + *ptr2++ = -temp1; + } + } + if (x_crop_blocks > 0) { + /* Now left-justify the portion of the data to be kept. + * We can't use a single jcopy_block_row() call because that routine + * depends on memcpy(), whose behavior is unspecified for overlapping + * source and destination areas. Sigh. + */ + for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { + jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, + buffer[offset_y] + blk_x, + (JDIMENSION) 1); + } + } + } + } + } +} + + +LOCAL(void) +do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Horizontal flip in general cropping case */ +{ + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, k, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Here we must output into a separate array because we can't touch + * different rows of a single virtual array simultaneously. Otherwise, + * this is essentially the same as the routine above. + */ + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[offset_y]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Do the mirrorable blocks */ + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + *dst_ptr++ = *src_ptr++; /* copy even column */ + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ + } + } else { + /* Copy last partial block(s) verbatim */ + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, + dst_row_ptr + dst_blk_x, + (JDIMENSION) 1); + } + } + } + } + } +} + + +LOCAL(void) +do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Vertical flip */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* We output into a separate array because we can't touch different + * rows of the source virtual array simultaneously. Otherwise, this + * is a pretty straightforward analog of horizontal flip. + * Within a DCT block, vertical mirroring is done by changing the signs + * of odd-numbered rows. + * Partial iMCUs at the bottom edge are copied verbatim. + */ + MCU_rows = srcinfo->output_height / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - y_crop_blocks - dst_blk_y - + (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge blocks will be copied verbatim. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + src_row_ptr += x_crop_blocks; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + /* copy even row */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + /* copy odd row with sign change */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } else { + /* Just copy row verbatim. */ + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, + dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } + } +} + + +LOCAL(void) +do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transpose source into destination */ +{ + JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Transposing pixels within a block just requires transposing the + * DCT coefficients. + * Partial iMCUs at the edges require no special treatment; we simply + * process all the available DCT blocks for every component. + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } +} + + +LOCAL(void) +do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 90 degree rotation is equivalent to + * 1. Transposing the image; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) right edge properly. They just get transposed and + * not mirrored. + */ + MCU_cols = srcinfo->output_height / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_width - x_crop_blocks - dst_blk_x - + (JDIMENSION) compptr->h_samp_factor, + (JDIMENSION) compptr->h_samp_factor, FALSE); + } else { + /* Edge blocks are transposed but not mirrored. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + } + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* Edge blocks are transposed but not mirrored. */ + src_ptr = src_buffer[offset_x] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 270 degree rotation is equivalent to + * 1. Horizontal mirroring; + * 2. Transposing the image. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) bottom edge properly. They just get transposed and + * not mirrored. + */ + MCU_rows = srcinfo->output_width / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[offset_x] + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Edge blocks are transposed but not mirrored. */ + src_ptr = src_buffer[offset_x] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 180 degree rotation is equivalent to + * 1. Vertical mirroring; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + MCU_rows = srcinfo->output_height / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the vertically mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - y_crop_blocks - dst_blk_y - + (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge rows are only mirrored horizontally. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + dst_row_ptr = dst_buffer[offset_y]; + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Process the blocks that can be mirrored both ways. */ + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE; i += 2) { + /* For even row, negate every odd column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + /* For odd row, negate every even column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = - *src_ptr++; + *dst_ptr++ = *src_ptr++; + } + } + } else { + /* Any remaining right-edge blocks are only mirrored vertically. */ + src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } + } else { + /* Remaining rows are just mirrored horizontally. */ + src_row_ptr = src_buffer[offset_y]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Process the blocks that can be mirrored. */ + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE2; i += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + } else { + /* Any remaining right-edge blocks are only copied. */ + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, + dst_row_ptr + dst_blk_x, + (JDIMENSION) 1); + } + } + } + } + } + } +} + + +LOCAL(void) +do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transverse transpose is equivalent to + * 1. 180 degree rotation; + * 2. Transposition; + * or + * 1. Horizontal mirroring; + * 2. Transposition; + * 3. Horizontal mirroring. + * These steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = srcinfo->output_height / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + MCU_rows = srcinfo->output_width / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_width - x_crop_blocks - dst_blk_x - + (JDIMENSION) compptr->h_samp_factor, + (JDIMENSION) compptr->h_samp_factor, FALSE); + } else { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + } + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (y_crop_blocks + dst_blk_y < comp_height) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + i++; + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Right-edge blocks are mirrored in y only */ + src_ptr = src_buffer[offset_x] + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } + } else { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Bottom-edge blocks are mirrored in x only */ + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* At lower right corner, just transpose, no mirroring */ + src_ptr = src_buffer[offset_x] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } + } +} + + +/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. + * Returns TRUE if valid integer found, FALSE if not. + * *strptr is advanced over the digit string, and *result is set to its value. + */ + +LOCAL(boolean) +jt_read_integer (const char ** strptr, JDIMENSION * result) +{ + const char * ptr = *strptr; + JDIMENSION val = 0; + + for (; isdigit((int)*ptr); ptr++) { + val = val * 10 + (JDIMENSION) (*ptr - '0'); + } + *result = val; + if (ptr == *strptr) + return FALSE; /* oops, no digits */ + *strptr = ptr; + return TRUE; +} + + +/* Parse a crop specification (written in X11 geometry style). + * The routine returns TRUE if the spec string is valid, FALSE if not. + * + * The crop spec string should have the format + * [{fr}]x[{fr}]{+-}{+-} + * where width, height, xoffset, and yoffset are unsigned integers. + * Each of the elements can be omitted to indicate a default value. + * (A weakness of this style is that it is not possible to omit xoffset + * while specifying yoffset, since they look alike.) + * + * This code is loosely based on XParseGeometry from the X11 distribution. + */ + +GLOBAL(boolean) +jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) +{ + info->crop = FALSE; + info->crop_width_set = JCROP_UNSET; + info->crop_height_set = JCROP_UNSET; + info->crop_xoffset_set = JCROP_UNSET; + info->crop_yoffset_set = JCROP_UNSET; + + if (isdigit((int)*spec)) { + /* fetch width */ + if (! jt_read_integer(&spec, &info->crop_width)) + return FALSE; + if (*spec == 'f' || *spec == 'F') { + spec++; + info->crop_width_set = JCROP_FORCE; + } else if (*spec == 'r' || *spec == 'R') { + spec++; + info->crop_width_set = JCROP_REFLECT; + } else + info->crop_width_set = JCROP_POS; + } + if (*spec == 'x' || *spec == 'X') { + /* fetch height */ + spec++; + if (! jt_read_integer(&spec, &info->crop_height)) + return FALSE; + if (*spec == 'f' || *spec == 'F') { + spec++; + info->crop_height_set = JCROP_FORCE; + } else if (*spec == 'r' || *spec == 'R') { + spec++; + info->crop_height_set = JCROP_REFLECT; + } else + info->crop_height_set = JCROP_POS; + } + if (*spec == '+' || *spec == '-') { + /* fetch xoffset */ + info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; + spec++; + if (! jt_read_integer(&spec, &info->crop_xoffset)) + return FALSE; + } + if (*spec == '+' || *spec == '-') { + /* fetch yoffset */ + info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; + spec++; + if (! jt_read_integer(&spec, &info->crop_yoffset)) + return FALSE; + } + /* We had better have gotten to the end of the string. */ + if (*spec != '\0') + return FALSE; + info->crop = TRUE; + return TRUE; +} + + +/* Trim off any partial iMCUs on the indicated destination edge */ + +LOCAL(void) +trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) +{ + JDIMENSION MCU_cols; + + MCU_cols = info->output_width / info->iMCU_sample_width; + if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == + full_width / info->iMCU_sample_width) + info->output_width = MCU_cols * info->iMCU_sample_width; +} + +LOCAL(void) +trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) +{ + JDIMENSION MCU_rows; + + MCU_rows = info->output_height / info->iMCU_sample_height; + if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == + full_height / info->iMCU_sample_height) + info->output_height = MCU_rows * info->iMCU_sample_height; +} + + +/* Request any required workspace. + * + * This routine figures out the size that the output image will be + * (which implies that all the transform parameters must be set before + * it is called). + * + * We allocate the workspace virtual arrays from the source decompression + * object, so that all the arrays (both the original data and the workspace) + * will be taken into account while making memory management decisions. + * Hence, this routine must be called after jpeg_read_header (which reads + * the image dimensions) and before jpeg_read_coefficients (which realizes + * the source's virtual arrays). + * + * This function returns FALSE right away if -perfect is given + * and transformation is not perfect. Otherwise returns TRUE. + */ + +GLOBAL(boolean) +jtransform_request_workspace (j_decompress_ptr srcinfo, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *coef_arrays; + boolean need_workspace, transpose_it; + jpeg_component_info *compptr; + JDIMENSION xoffset, yoffset, dtemp; + JDIMENSION width_in_iMCUs, height_in_iMCUs; + JDIMENSION width_in_blocks, height_in_blocks; + int itemp, ci, h_samp_factor, v_samp_factor; + + /* Determine number of components in output image */ + if (info->force_grayscale && + (srcinfo->jpeg_color_space == JCS_YCbCr || + srcinfo->jpeg_color_space == JCS_BG_YCC) && + srcinfo->num_components == 3) + /* We'll only process the first component */ + info->num_components = 1; + else + /* Process all the components */ + info->num_components = srcinfo->num_components; + + /* Compute output image dimensions and related values. */ + jpeg_core_output_dimensions(srcinfo); + + /* Return right away if -perfect is given and transformation is not perfect. + */ + if (info->perfect) { + if (info->num_components == 1) { + if (!jtransform_perfect_transform(srcinfo->output_width, + srcinfo->output_height, + srcinfo->min_DCT_h_scaled_size, + srcinfo->min_DCT_v_scaled_size, + info->transform)) + return FALSE; + } else { + if (!jtransform_perfect_transform(srcinfo->output_width, + srcinfo->output_height, + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size, + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size, + info->transform)) + return FALSE; + } + } + + /* If there is only one output component, force the iMCU size to be 1; + * else use the source iMCU size. (This allows us to do the right thing + * when reducing color to grayscale, and also provides a handy way of + * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) + */ + switch (info->transform) { + case JXFORM_TRANSPOSE: + case JXFORM_TRANSVERSE: + case JXFORM_ROT_90: + case JXFORM_ROT_270: + info->output_width = srcinfo->output_height; + info->output_height = srcinfo->output_width; + if (info->num_components == 1) { + info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size; + info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size; + } else { + info->iMCU_sample_width = + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; + info->iMCU_sample_height = + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; + } + break; + default: + info->output_width = srcinfo->output_width; + info->output_height = srcinfo->output_height; + if (info->num_components == 1) { + info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size; + info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size; + } else { + info->iMCU_sample_width = + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; + info->iMCU_sample_height = + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; + } + } + + /* If cropping has been requested, compute the crop area's position and + * dimensions, ensuring that its upper left corner falls at an iMCU boundary. + */ + if (info->crop) { + /* Insert default values for unset crop parameters */ + if (info->crop_xoffset_set == JCROP_UNSET) + info->crop_xoffset = 0; /* default to +0 */ + if (info->crop_yoffset_set == JCROP_UNSET) + info->crop_yoffset = 0; /* default to +0 */ + if (info->crop_width_set == JCROP_UNSET) { + if (info->crop_xoffset >= info->output_width) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + info->crop_width = info->output_width - info->crop_xoffset; + } else { + /* Check for crop extension */ + if (info->crop_width > info->output_width) { + /* Crop extension does not work when transforming! */ + if (info->transform != JXFORM_NONE || + info->crop_xoffset >= info->crop_width || + info->crop_xoffset > info->crop_width - info->output_width) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + } else { + if (info->crop_xoffset >= info->output_width || + info->crop_width <= 0 || + info->crop_xoffset > info->output_width - info->crop_width) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + } + } + if (info->crop_height_set == JCROP_UNSET) { + if (info->crop_yoffset >= info->output_height) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + info->crop_height = info->output_height - info->crop_yoffset; + } else { + /* Check for crop extension */ + if (info->crop_height > info->output_height) { + /* Crop extension does not work when transforming! */ + if (info->transform != JXFORM_NONE || + info->crop_yoffset >= info->crop_height || + info->crop_yoffset > info->crop_height - info->output_height) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + } else { + if (info->crop_yoffset >= info->output_height || + info->crop_height <= 0 || + info->crop_yoffset > info->output_height - info->crop_height) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + } + } + /* Convert negative crop offsets into regular offsets */ + if (info->crop_xoffset_set != JCROP_NEG) + xoffset = info->crop_xoffset; + else if (info->crop_width > info->output_width) /* crop extension */ + xoffset = info->crop_width - info->output_width - info->crop_xoffset; + else + xoffset = info->output_width - info->crop_width - info->crop_xoffset; + if (info->crop_yoffset_set != JCROP_NEG) + yoffset = info->crop_yoffset; + else if (info->crop_height > info->output_height) /* crop extension */ + yoffset = info->crop_height - info->output_height - info->crop_yoffset; + else + yoffset = info->output_height - info->crop_height - info->crop_yoffset; + /* Now adjust so that upper left corner falls at an iMCU boundary */ + switch (info->transform) { + case JXFORM_DROP: + /* Ensure the effective drop region will not exceed the requested */ + itemp = info->iMCU_sample_width; + dtemp = itemp - 1 - ((xoffset + itemp - 1) % itemp); + xoffset += dtemp; + if (info->crop_width <= dtemp) + info->drop_width = 0; + else if (xoffset + info->crop_width - dtemp == info->output_width) + /* Matching right edge: include partial iMCU */ + info->drop_width = (info->crop_width - dtemp + itemp - 1) / itemp; + else + info->drop_width = (info->crop_width - dtemp) / itemp; + itemp = info->iMCU_sample_height; + dtemp = itemp - 1 - ((yoffset + itemp - 1) % itemp); + yoffset += dtemp; + if (info->crop_height <= dtemp) + info->drop_height = 0; + else if (yoffset + info->crop_height - dtemp == info->output_height) + /* Matching bottom edge: include partial iMCU */ + info->drop_height = (info->crop_height - dtemp + itemp - 1) / itemp; + else + info->drop_height = (info->crop_height - dtemp) / itemp; + /* Check if sampling factors match for dropping */ + if (info->drop_width != 0 && info->drop_height != 0) + for (ci = 0; ci < info->num_components && + ci < info->drop_ptr->num_components; ci++) { + if (info->drop_ptr->comp_info[ci].h_samp_factor * + srcinfo->max_h_samp_factor != + srcinfo->comp_info[ci].h_samp_factor * + info->drop_ptr->max_h_samp_factor) + ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci, + info->drop_ptr->comp_info[ci].h_samp_factor, + info->drop_ptr->max_h_samp_factor, + srcinfo->comp_info[ci].h_samp_factor, + srcinfo->max_h_samp_factor, 'h'); + if (info->drop_ptr->comp_info[ci].v_samp_factor * + srcinfo->max_v_samp_factor != + srcinfo->comp_info[ci].v_samp_factor * + info->drop_ptr->max_v_samp_factor) + ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci, + info->drop_ptr->comp_info[ci].v_samp_factor, + info->drop_ptr->max_v_samp_factor, + srcinfo->comp_info[ci].v_samp_factor, + srcinfo->max_v_samp_factor, 'v'); + } + break; + case JXFORM_WIPE: + /* Ensure the effective wipe region will cover the requested */ + info->drop_width = (JDIMENSION) jdiv_round_up + ((long) (info->crop_width + (xoffset % info->iMCU_sample_width)), + (long) info->iMCU_sample_width); + info->drop_height = (JDIMENSION) jdiv_round_up + ((long) (info->crop_height + (yoffset % info->iMCU_sample_height)), + (long) info->iMCU_sample_height); + break; + default: + /* Ensure the effective crop region will cover the requested */ + if (info->crop_width_set == JCROP_FORCE || + info->crop_width > info->output_width) + info->output_width = info->crop_width; + else + info->output_width = + info->crop_width + (xoffset % info->iMCU_sample_width); + if (info->crop_height_set == JCROP_FORCE || + info->crop_height > info->output_height) + info->output_height = info->crop_height; + else + info->output_height = + info->crop_height + (yoffset % info->iMCU_sample_height); + } + /* Save x/y offsets measured in iMCUs */ + info->x_crop_offset = xoffset / info->iMCU_sample_width; + info->y_crop_offset = yoffset / info->iMCU_sample_height; + } else { + info->x_crop_offset = 0; + info->y_crop_offset = 0; + } + + /* Figure out whether we need workspace arrays, + * and if so whether they are transposed relative to the source. + */ + need_workspace = FALSE; + transpose_it = FALSE; + switch (info->transform) { + case JXFORM_NONE: + if (info->x_crop_offset != 0 || info->y_crop_offset != 0 || + info->output_width > srcinfo->output_width || + info->output_height > srcinfo->output_height) + need_workspace = TRUE; + /* No workspace needed if neither cropping nor transforming */ + break; + case JXFORM_FLIP_H: + if (info->trim) + trim_right_edge(info, srcinfo->output_width); + if (info->y_crop_offset != 0) + need_workspace = TRUE; + /* do_flip_h_no_crop doesn't need a workspace array */ + break; + case JXFORM_FLIP_V: + if (info->trim) + trim_bottom_edge(info, srcinfo->output_height); + /* Need workspace arrays having same dimensions as source image. */ + need_workspace = TRUE; + break; + case JXFORM_TRANSPOSE: + /* transpose does NOT have to trim anything */ + /* Need workspace arrays having transposed dimensions. */ + need_workspace = TRUE; + transpose_it = TRUE; + break; + case JXFORM_TRANSVERSE: + if (info->trim) { + trim_right_edge(info, srcinfo->output_height); + trim_bottom_edge(info, srcinfo->output_width); + } + /* Need workspace arrays having transposed dimensions. */ + need_workspace = TRUE; + transpose_it = TRUE; + break; + case JXFORM_ROT_90: + if (info->trim) + trim_right_edge(info, srcinfo->output_height); + /* Need workspace arrays having transposed dimensions. */ + need_workspace = TRUE; + transpose_it = TRUE; + break; + case JXFORM_ROT_180: + if (info->trim) { + trim_right_edge(info, srcinfo->output_width); + trim_bottom_edge(info, srcinfo->output_height); + } + /* Need workspace arrays having same dimensions as source image. */ + need_workspace = TRUE; + break; + case JXFORM_ROT_270: + if (info->trim) + trim_bottom_edge(info, srcinfo->output_width); + /* Need workspace arrays having transposed dimensions. */ + need_workspace = TRUE; + transpose_it = TRUE; + break; + case JXFORM_WIPE: + break; + case JXFORM_DROP: +#if DROP_REQUEST_FROM_SRC + drop_request_from_src(info->drop_ptr, srcinfo); +#endif + break; + } + + /* Allocate workspace if needed. + * Note that we allocate arrays padded out to the next iMCU boundary, + * so that transform routines need not worry about missing edge blocks. + */ + if (need_workspace) { + coef_arrays = (jvirt_barray_ptr *) (*srcinfo->mem->alloc_small) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, + SIZEOF(jvirt_barray_ptr) * info->num_components); + width_in_iMCUs = (JDIMENSION) jdiv_round_up + ((long) info->output_width, (long) info->iMCU_sample_width); + height_in_iMCUs = (JDIMENSION) jdiv_round_up + ((long) info->output_height, (long) info->iMCU_sample_height); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; + if (info->num_components == 1) { + /* we're going to force samp factors to 1x1 in this case */ + h_samp_factor = v_samp_factor = 1; + } else if (transpose_it) { + h_samp_factor = compptr->v_samp_factor; + v_samp_factor = compptr->h_samp_factor; + } else { + h_samp_factor = compptr->h_samp_factor; + v_samp_factor = compptr->v_samp_factor; + } + width_in_blocks = width_in_iMCUs * h_samp_factor; + height_in_blocks = height_in_iMCUs * v_samp_factor; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, + width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); + } + info->workspace_coef_arrays = coef_arrays; + } else + info->workspace_coef_arrays = NULL; + + return TRUE; +} + + +/* Transpose destination image parameters */ + +LOCAL(void) +transpose_critical_parameters (j_compress_ptr dstinfo) +{ + int tblno, i, j, ci, itemp; + jpeg_component_info *compptr; + JQUANT_TBL *qtblptr; + JDIMENSION jtemp; + UINT16 qtemp; + + /* Transpose image dimensions */ + jtemp = dstinfo->image_width; + dstinfo->image_width = dstinfo->image_height; + dstinfo->image_height = jtemp; + itemp = dstinfo->min_DCT_h_scaled_size; + dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size; + dstinfo->min_DCT_v_scaled_size = itemp; + + /* Transpose sampling factors */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + itemp = compptr->h_samp_factor; + compptr->h_samp_factor = compptr->v_samp_factor; + compptr->v_samp_factor = itemp; + } + + /* Transpose quantization tables */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + qtblptr = dstinfo->quant_tbl_ptrs[tblno]; + if (qtblptr != NULL) { + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < i; j++) { + qtemp = qtblptr->quantval[i*DCTSIZE+j]; + qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; + qtblptr->quantval[j*DCTSIZE+i] = qtemp; + } + } + } + } +} + + +/* Adjust Exif image parameters. + * + * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. + */ + +LOCAL(void) +adjust_exif_parameters (JOCTET FAR * data, unsigned int length, + JDIMENSION new_width, JDIMENSION new_height) +{ + boolean is_motorola; /* Flag for byte order */ + unsigned int number_of_tags, tagnum; + unsigned int firstoffset, offset; + JDIMENSION new_value; + + if (length < 12) return; /* Length of an IFD entry */ + + /* Discover byte order */ + if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) + is_motorola = FALSE; + else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) + is_motorola = TRUE; + else + return; + + /* Check Tag Mark */ + if (is_motorola) { + if (GETJOCTET(data[2]) != 0) return; + if (GETJOCTET(data[3]) != 0x2A) return; + } else { + if (GETJOCTET(data[3]) != 0) return; + if (GETJOCTET(data[2]) != 0x2A) return; + } + + /* Get first IFD offset (offset to IFD0) */ + if (is_motorola) { + if (GETJOCTET(data[4]) != 0) return; + if (GETJOCTET(data[5]) != 0) return; + firstoffset = GETJOCTET(data[6]); + firstoffset <<= 8; + firstoffset += GETJOCTET(data[7]); + } else { + if (GETJOCTET(data[7]) != 0) return; + if (GETJOCTET(data[6]) != 0) return; + firstoffset = GETJOCTET(data[5]); + firstoffset <<= 8; + firstoffset += GETJOCTET(data[4]); + } + if (firstoffset > length - 2) return; /* check end of data segment */ + + /* Get the number of directory entries contained in this IFD */ + if (is_motorola) { + number_of_tags = GETJOCTET(data[firstoffset]); + number_of_tags <<= 8; + number_of_tags += GETJOCTET(data[firstoffset+1]); + } else { + number_of_tags = GETJOCTET(data[firstoffset+1]); + number_of_tags <<= 8; + number_of_tags += GETJOCTET(data[firstoffset]); + } + if (number_of_tags == 0) return; + firstoffset += 2; + + /* Search for ExifSubIFD offset Tag in IFD0 */ + for (;;) { + if (firstoffset > length - 12) return; /* check end of data segment */ + /* Get Tag number */ + if (is_motorola) { + tagnum = GETJOCTET(data[firstoffset]); + tagnum <<= 8; + tagnum += GETJOCTET(data[firstoffset+1]); + } else { + tagnum = GETJOCTET(data[firstoffset+1]); + tagnum <<= 8; + tagnum += GETJOCTET(data[firstoffset]); + } + if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ + if (--number_of_tags == 0) return; + firstoffset += 12; + } + + /* Get the ExifSubIFD offset */ + if (is_motorola) { + if (GETJOCTET(data[firstoffset+8]) != 0) return; + if (GETJOCTET(data[firstoffset+9]) != 0) return; + offset = GETJOCTET(data[firstoffset+10]); + offset <<= 8; + offset += GETJOCTET(data[firstoffset+11]); + } else { + if (GETJOCTET(data[firstoffset+11]) != 0) return; + if (GETJOCTET(data[firstoffset+10]) != 0) return; + offset = GETJOCTET(data[firstoffset+9]); + offset <<= 8; + offset += GETJOCTET(data[firstoffset+8]); + } + if (offset > length - 2) return; /* check end of data segment */ + + /* Get the number of directory entries contained in this SubIFD */ + if (is_motorola) { + number_of_tags = GETJOCTET(data[offset]); + number_of_tags <<= 8; + number_of_tags += GETJOCTET(data[offset+1]); + } else { + number_of_tags = GETJOCTET(data[offset+1]); + number_of_tags <<= 8; + number_of_tags += GETJOCTET(data[offset]); + } + if (number_of_tags < 2) return; + offset += 2; + + /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ + do { + if (offset > length - 12) return; /* check end of data segment */ + /* Get Tag number */ + if (is_motorola) { + tagnum = GETJOCTET(data[offset]); + tagnum <<= 8; + tagnum += GETJOCTET(data[offset+1]); + } else { + tagnum = GETJOCTET(data[offset+1]); + tagnum <<= 8; + tagnum += GETJOCTET(data[offset]); + } + if (tagnum == 0xA002 || tagnum == 0xA003) { + if (tagnum == 0xA002) + new_value = new_width; /* ExifImageWidth Tag */ + else + new_value = new_height; /* ExifImageHeight Tag */ + if (is_motorola) { + data[offset+2] = 0; /* Format = unsigned long (4 octets) */ + data[offset+3] = 4; + data[offset+4] = 0; /* Number Of Components = 1 */ + data[offset+5] = 0; + data[offset+6] = 0; + data[offset+7] = 1; + data[offset+8] = 0; + data[offset+9] = 0; + data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); + data[offset+11] = (JOCTET)(new_value & 0xFF); + } else { + data[offset+2] = 4; /* Format = unsigned long (4 octets) */ + data[offset+3] = 0; + data[offset+4] = 1; /* Number Of Components = 1 */ + data[offset+5] = 0; + data[offset+6] = 0; + data[offset+7] = 0; + data[offset+8] = (JOCTET)(new_value & 0xFF); + data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); + data[offset+10] = 0; + data[offset+11] = 0; + } + } + offset += 12; + } while (--number_of_tags); +} + + +/* Adjust output image parameters as needed. + * + * This must be called after jpeg_copy_critical_parameters() + * and before jpeg_write_coefficients(). + * + * The return value is the set of virtual coefficient arrays to be written + * (either the ones allocated by jtransform_request_workspace, or the + * original source data arrays). The caller will need to pass this value + * to jpeg_write_coefficients(). + */ + +GLOBAL(jvirt_barray_ptr *) +jtransform_adjust_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + /* If force-to-grayscale is requested, adjust destination parameters */ + if (info->force_grayscale) { + /* First, ensure we have YCC or grayscale data, and that the source's + * Y channel is full resolution. (No reasonable person would make Y + * be less than full resolution, so actually coping with that case + * isn't worth extra code space. But we check it to avoid crashing.) + */ + if ((((dstinfo->jpeg_color_space == JCS_YCbCr || + dstinfo->jpeg_color_space == JCS_BG_YCC) && + dstinfo->num_components == 3) || + (dstinfo->jpeg_color_space == JCS_GRAYSCALE && + dstinfo->num_components == 1)) && + srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && + srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { + /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed + * properly. Among other things, it sets the target h_samp_factor & + * v_samp_factor to 1, which typically won't match the source. + * We have to preserve the source's quantization table number, however. + */ + int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; + jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); + dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; + } else { + /* Sorry, can't do it */ + ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); + } + } else if (info->num_components == 1) { + /* For a single-component source, we force the destination sampling factors + * to 1x1, with or without force_grayscale. This is useful because some + * decoders choke on grayscale images with other sampling factors. + */ + dstinfo->comp_info[0].h_samp_factor = 1; + dstinfo->comp_info[0].v_samp_factor = 1; + } + + /* Correct the destination's image dimensions as necessary + * for rotate/flip, resize, and crop operations. + */ + dstinfo->jpeg_width = info->output_width; + dstinfo->jpeg_height = info->output_height; + + /* Transpose destination image parameters, adjust quantization */ + switch (info->transform) { + case JXFORM_TRANSPOSE: + case JXFORM_TRANSVERSE: + case JXFORM_ROT_90: + case JXFORM_ROT_270: + transpose_critical_parameters(dstinfo); + break; + case JXFORM_DROP: + if (info->drop_width != 0 && info->drop_height != 0) + adjust_quant(srcinfo, src_coef_arrays, + info->drop_ptr, info->drop_coef_arrays, + info->trim, dstinfo); + break; + default: + break; + } + + /* Adjust Exif properties */ + if (srcinfo->marker_list != NULL && + srcinfo->marker_list->marker == JPEG_APP0+1 && + srcinfo->marker_list->data_length >= 6 && + GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && + GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && + GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && + GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && + GETJOCTET(srcinfo->marker_list->data[4]) == 0 && + GETJOCTET(srcinfo->marker_list->data[5]) == 0) { + /* Suppress output of JFIF marker */ + dstinfo->write_JFIF_header = FALSE; + /* Adjust Exif image parameters */ + if (dstinfo->jpeg_width != srcinfo->image_width || + dstinfo->jpeg_height != srcinfo->image_height) + /* Align data segment to start of TIFF structure for parsing */ + adjust_exif_parameters(srcinfo->marker_list->data + 6, + srcinfo->marker_list->data_length - 6, + dstinfo->jpeg_width, dstinfo->jpeg_height); + } + + /* Return the appropriate output data set */ + if (info->workspace_coef_arrays != NULL) + return info->workspace_coef_arrays; + return src_coef_arrays; +} + + +/* Execute the actual transformation, if any. + * + * This must be called *after* jpeg_write_coefficients, because it depends + * on jpeg_write_coefficients to have computed subsidiary values such as + * the per-component width and height fields in the destination object. + * + * Note that some transformations will modify the source data arrays! + */ + +GLOBAL(void) +jtransform_execute_transform (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; + + /* Note: conditions tested here should match those in switch statement + * in jtransform_request_workspace() + */ + switch (info->transform) { + case JXFORM_NONE: + if (info->output_width > srcinfo->output_width || + info->output_height > srcinfo->output_height) { + if (info->output_width > srcinfo->output_width && + info->crop_width_set == JCROP_REFLECT) + do_crop_ext_reflect(srcinfo, dstinfo, + info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + else if (info->output_width > srcinfo->output_width && + info->crop_width_set == JCROP_FORCE) + do_crop_ext_flat(srcinfo, dstinfo, + info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + else + do_crop_ext_zero(srcinfo, dstinfo, + info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + } else if (info->x_crop_offset != 0 || info->y_crop_offset != 0) + do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_FLIP_H: + if (info->y_crop_offset != 0) + do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + else + do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, + src_coef_arrays); + break; + case JXFORM_FLIP_V: + do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSPOSE: + do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSVERSE: + do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_90: + do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_180: + do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_270: + do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_WIPE: + if (info->crop_width_set == JCROP_REFLECT && + info->y_crop_offset == 0 && info->drop_height == + (JDIMENSION) jdiv_round_up + ((long) info->output_height, (long) info->iMCU_sample_height) && + (info->x_crop_offset == 0 || + info->x_crop_offset + info->drop_width == + (JDIMENSION) jdiv_round_up + ((long) info->output_width, (long) info->iMCU_sample_width))) + do_reflect(srcinfo, dstinfo, info->x_crop_offset, + src_coef_arrays, info->drop_width, info->drop_height); + else if (info->crop_width_set == JCROP_FORCE) + do_flatten(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, info->drop_width, info->drop_height); + else + do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, info->drop_width, info->drop_height); + break; + case JXFORM_DROP: + if (info->drop_width != 0 && info->drop_height != 0) + do_drop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, info->drop_ptr, info->drop_coef_arrays, + info->drop_width, info->drop_height); + break; + } +} + +/* jtransform_perfect_transform + * + * Determine whether lossless transformation is perfectly + * possible for a specified image and transformation. + * + * Inputs: + * image_width, image_height: source image dimensions. + * MCU_width, MCU_height: pixel dimensions of MCU. + * transform: transformation identifier. + * Parameter sources from initialized jpeg_struct + * (after reading source header): + * image_width = cinfo.image_width + * image_height = cinfo.image_height + * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size + * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size + * Result: + * TRUE = perfect transformation possible + * FALSE = perfect transformation not possible + * (may use custom action then) + */ + +GLOBAL(boolean) +jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, + int MCU_width, int MCU_height, + JXFORM_CODE transform) +{ + boolean result = TRUE; /* initialize TRUE */ + + switch (transform) { + case JXFORM_FLIP_H: + case JXFORM_ROT_270: + if (image_width % (JDIMENSION) MCU_width) + result = FALSE; + break; + case JXFORM_FLIP_V: + case JXFORM_ROT_90: + if (image_height % (JDIMENSION) MCU_height) + result = FALSE; + break; + case JXFORM_TRANSVERSE: + case JXFORM_ROT_180: + if (image_width % (JDIMENSION) MCU_width) + result = FALSE; + if (image_height % (JDIMENSION) MCU_height) + result = FALSE; + break; + default: + break; + } + + return result; +} + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* Setup decompression object to save desired markers in memory. + * This must be called before jpeg_read_header() to have the desired effect. + */ + +GLOBAL(void) +jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) +{ +#ifdef SAVE_MARKERS_SUPPORTED + int m; + + /* Save comments except under NONE option */ + if (option != JCOPYOPT_NONE) { + jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); + } + /* Save all types of APPn markers iff ALL option */ + if (option == JCOPYOPT_ALL) { + for (m = 0; m < 16; m++) + jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); + } +#endif /* SAVE_MARKERS_SUPPORTED */ +} + +/* Copy markers saved in the given source object to the destination object. + * This should be called just after jpeg_start_compress() or + * jpeg_write_coefficients(). + * Note that those routines will have written the SOI, and also the + * JFIF APP0 or Adobe APP14 markers if selected. + */ + +GLOBAL(void) +jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option) +{ + jpeg_saved_marker_ptr marker; + + /* In the current implementation, we don't actually need to examine the + * option flag here; we just copy everything that got saved. + * But to avoid confusion, we do not output JFIF and Adobe APP14 markers + * if the encoder library already wrote one. + */ + for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { + if (dstinfo->write_JFIF_header && + marker->marker == JPEG_APP0 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x4A && + GETJOCTET(marker->data[1]) == 0x46 && + GETJOCTET(marker->data[2]) == 0x49 && + GETJOCTET(marker->data[3]) == 0x46 && + GETJOCTET(marker->data[4]) == 0) + continue; /* reject duplicate JFIF */ + if (dstinfo->write_Adobe_marker && + marker->marker == JPEG_APP0+14 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x41 && + GETJOCTET(marker->data[1]) == 0x64 && + GETJOCTET(marker->data[2]) == 0x6F && + GETJOCTET(marker->data[3]) == 0x62 && + GETJOCTET(marker->data[4]) == 0x65) + continue; /* reject duplicate Adobe */ +#ifdef NEED_FAR_POINTERS + /* We could use jpeg_write_marker if the data weren't FAR... */ + { + unsigned int i; + jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); + for (i = 0; i < marker->data_length; i++) + jpeg_write_m_byte(dstinfo, marker->data[i]); + } +#else + jpeg_write_marker(dstinfo, marker->marker, + marker->data, marker->data_length); +#endif + } +} diff --git a/widget/milsko/milskosrc/external/libjpeg/src/wrbmp.c b/widget/milsko/milskosrc/external/libjpeg/src/wrbmp.c new file mode 100644 index 0000000000..bed699ff40 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/wrbmp.c @@ -0,0 +1,437 @@ +/* + * wrbmp.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2017-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in Microsoft "BMP" + * format (MS Windows 3.x and OS/2 1.x flavors). + * Either 8-bit colormapped or 24-bit full-color format can be written. + * No compression is supported. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * This code contributed by James Arthur Boucher. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef BMP_SUPPORTED + + +/* + * To support 12-bit JPEG data, we'd have to scale output down to 8 bits. + * This is not yet implemented. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * Since BMP stores scanlines bottom-to-top, we have to invert the image + * from JPEG's top-to-bottom order. To do this, we save the outgoing data + * in a virtual array during put_pixel_row calls, then actually emit the + * BMP file during finish_output. The virtual array contains one JSAMPLE per + * pixel if the output is grayscale or colormapped, three if it is full color. + */ + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + boolean is_os2; /* saves the OS2 format request flag */ + + jvirt_sarray_ptr whole_image; /* needed to reverse row order */ + JDIMENSION data_width; /* JSAMPLEs per row */ + JDIMENSION row_width; /* physical width of one row in the BMP file */ + int pad_bytes; /* number of padding bytes needed per row */ + JDIMENSION cur_output_row; /* next row# to write to virtual array */ +} bmp_dest_struct; + +typedef bmp_dest_struct * bmp_dest_ptr; + + +/* Forward declarations */ +LOCAL(void) write_colormap + JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest, + int map_colors, int map_entry_size)); + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* This version is for writing 24-bit pixels */ +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + int pad; + + /* Access next row in virtual array */ + outptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE); + dest->cur_output_row++; + + /* Transfer data. Note destination values must be in BGR order + * (even though Microsoft's own documents say the opposite). + */ + inptr = dest->pub.buffer[0]; + for (col = cinfo->output_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + outptr += 3; + } + + /* Zero out the pad bytes. */ + pad = dest->pad_bytes; + while (--pad >= 0) + *outptr++ = 0; +} + +METHODDEF(void) +put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* This version is for grayscale OR quantized color output */ +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + int pad; + + /* Access next row in virtual array */ + outptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE); + dest->cur_output_row++; + + /* Transfer data. */ + inptr = dest->pub.buffer[0]; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */ + } + + /* Zero out the pad bytes. */ + pad = dest->pad_bytes; + while (--pad >= 0) + *outptr++ = 0; +} + + +/* + * Startup: normally writes the file header. + * In this module we may as well postpone everything until finish_output. + */ + +METHODDEF(void) +start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* no work here */ +} + + +/* + * Finish up at the end of the file. + * + * Here is where we really output the BMP file. + * + * First, routines to write the Windows and OS/2 variants of the file header. + */ + +LOCAL(void) +write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) +/* Write a Windows-style BMP file header, including colormap if needed */ +{ + char bmpfileheader[14]; + char bmpinfoheader[40]; +#define PUT_2B(array, offset, value) \ + (array[offset] = (char) ((value) & 0xFF), \ + array[offset+1] = (char) (((value) >> 8) & 0xFF)) +#define PUT_4B(array, offset, value) \ + (array[offset] = (char) ((value) & 0xFF), \ + array[offset+1] = (char) (((value) >> 8) & 0xFF), \ + array[offset+2] = (char) (((value) >> 16) & 0xFF), \ + array[offset+3] = (char) (((value) >> 24) & 0xFF)) + INT32 headersize, bfSize; + int bits_per_pixel, cmap_entries; + + /* Compute colormap size and total file size */ + if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* Colormapped RGB */ + bits_per_pixel = 8; + cmap_entries = 256; + } else { + /* Unquantized, full color RGB */ + bits_per_pixel = 24; + cmap_entries = 0; + } + } else { + /* Grayscale output. We need to fake a 256-entry colormap. */ + bits_per_pixel = 8; + cmap_entries = 256; + } + /* File size */ + headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */ + bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height; + + /* Set unused fields of header to 0 */ + MEMZERO(bmpfileheader, SIZEOF(bmpfileheader)); + MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader)); + + /* Fill the file header */ + bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ + bmpfileheader[1] = 0x4D; + PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */ + /* we leave bfReserved1 & bfReserved2 = 0 */ + PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */ + + /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */ + PUT_2B(bmpinfoheader, 0, 40); /* biSize */ + PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */ + PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */ + PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */ + PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */ + /* we leave biCompression = 0, for none */ + /* we leave biSizeImage = 0; this is correct for uncompressed data */ + if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */ + PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */ + PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */ + } + PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */ + /* we leave biClrImportant = 0 */ + + if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14) + ERREXIT(cinfo, JERR_FILE_WRITE); + if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if (cmap_entries > 0) + write_colormap(cinfo, dest, cmap_entries, 4); +} + + +LOCAL(void) +write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) +/* Write an OS2-style BMP file header, including colormap if needed */ +{ + char bmpfileheader[14]; + char bmpcoreheader[12]; + INT32 headersize, bfSize; + int bits_per_pixel, cmap_entries; + + /* Compute colormap size and total file size */ + if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* Colormapped RGB */ + bits_per_pixel = 8; + cmap_entries = 256; + } else { + /* Unquantized, full color RGB */ + bits_per_pixel = 24; + cmap_entries = 0; + } + } else { + /* Grayscale output. We need to fake a 256-entry colormap. */ + bits_per_pixel = 8; + cmap_entries = 256; + } + /* File size */ + headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */ + bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height; + + /* Set unused fields of header to 0 */ + MEMZERO(bmpfileheader, SIZEOF(bmpfileheader)); + MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader)); + + /* Fill the file header */ + bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ + bmpfileheader[1] = 0x4D; + PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */ + /* we leave bfReserved1 & bfReserved2 = 0 */ + PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */ + + /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */ + PUT_2B(bmpcoreheader, 0, 12); /* bcSize */ + PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */ + PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */ + PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */ + PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */ + + if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14) + ERREXIT(cinfo, JERR_FILE_WRITE); + if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if (cmap_entries > 0) + write_colormap(cinfo, dest, cmap_entries, 3); +} + + +/* + * Write the colormap. + * Windows uses BGR0 map entries; OS/2 uses BGR entries. + */ + +LOCAL(void) +write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest, + int map_colors, int map_entry_size) +{ + JSAMPARRAY colormap = cinfo->colormap; + int num_colors = cinfo->actual_number_of_colors; + FILE * outfile = dest->pub.output_file; + int i; + + if (colormap != NULL) { + if (cinfo->out_color_components == 3) { + /* Normal case with RGB colormap */ + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(colormap[2][i]), outfile); + putc(GETJSAMPLE(colormap[1][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } else { + /* Grayscale colormap (only happens with grayscale quantization) */ + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(colormap[0][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } + } else { + /* If no colormap, must be grayscale data. Generate a linear "map". */ + for (i = 0; i < 256; i++) { + putc(i, outfile); + putc(i, outfile); + putc(i, outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } + /* Pad colormap to ensure specified number of colormap entries */ + if (i > map_colors) + ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i); + for (; i < map_colors; i++) { + putc(CENTERJSAMPLE, outfile); + putc(CENTERJSAMPLE, outfile); + putc(CENTERJSAMPLE, outfile); + if (map_entry_size == 4) + putc(0, outfile); + } +} + + +METHODDEF(void) +finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + register FILE * outfile = dest->pub.output_file; + register JSAMPROW data_ptr; + JDIMENSION row; + register JDIMENSION col; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Write the header and colormap */ + if (dest->is_os2) + write_os2_header(cinfo, dest); + else + write_bmp_header(cinfo, dest); + + /* Write the file body from our virtual array */ + for (row = cinfo->output_height; row > 0; row--) { + if (progress != NULL) { + progress->pub.pass_counter = (long) (cinfo->output_height - row); + progress->pub.pass_limit = (long) cinfo->output_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + data_ptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, + dest->whole_image, row - 1, (JDIMENSION) 1, FALSE); + for (col = dest->row_width; col > 0; col--) { + putc(GETJSAMPLE(*data_ptr), outfile); + data_ptr++; + } + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Make sure we wrote the output file OK */ + JFFLUSH(outfile); + if (JFERROR(outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for BMP format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2) +{ + bmp_dest_ptr dest; + JDIMENSION row_width; + + /* Create module interface object, fill in method pointers */ + dest = (bmp_dest_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_dest_struct)); + dest->pub.start_output = start_output_bmp; + dest->pub.finish_output = finish_output_bmp; + dest->is_os2 = is_os2; + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + dest->pub.put_pixel_rows = put_gray_rows; + break; + case JCS_RGB: + if (cinfo->quantize_colors) + dest->pub.put_pixel_rows = put_gray_rows; + else + dest->pub.put_pixel_rows = put_pixel_rows; + break; + default: + ERREXIT(cinfo, JERR_BMP_COLORSPACE); + } + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Determine width of rows in the BMP file (padded to 4-byte boundary). */ + row_width = cinfo->output_width * cinfo->output_components; + dest->data_width = row_width; + while ((row_width & 3) != 0) row_width++; + dest->row_width = row_width; + dest->pad_bytes = (int) (row_width - dest->data_width); + + /* Allocate space for inversion array, prepare for write pass */ + dest->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + row_width, cinfo->output_height, (JDIMENSION) 1); + dest->cur_output_row = 0; + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return &dest->pub; +} + +#endif /* BMP_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/wrgif.c b/widget/milsko/milskosrc/external/libjpeg/src/wrgif.c new file mode 100644 index 0000000000..9d472de106 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/wrgif.c @@ -0,0 +1,566 @@ +/* + * wrgif.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2015-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in GIF format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + */ + +/* + * This code is loosely based on ppmtogif from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * Based on GIFENCODE by David Rowley . + * Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al. + * Copyright (C) 1989 by Jef Poskanzer. + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef GIF_SUPPORTED + + +#define MAX_LZW_BITS 12 /* maximum LZW code size (4096 symbols) */ + +typedef INT16 code_int; /* must hold -1 .. 2**MAX_LZW_BITS */ + +#define LZW_TABLE_SIZE ((code_int) 1 << MAX_LZW_BITS) + +#define HSIZE 5003 /* hash table size for 80% occupancy */ + +typedef int hash_int; /* must hold -2*HSIZE..2*HSIZE */ + +#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1) + + +/* + * The LZW hash table consists of two parallel arrays: + * hash_code[i] code of symbol in slot i, or 0 if empty slot + * hash_value[i] symbol's value; undefined if empty slot + * where slot values (i) range from 0 to HSIZE-1. The symbol value is + * its prefix symbol's code concatenated with its suffix character. + * + * Algorithm: use open addressing double hashing (no chaining) on the + * prefix code / suffix character combination. We do a variant of Knuth's + * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime + * secondary probe. + * + * The hash_value[] table is allocated from FAR heap space since it would + * use up rather a lot of the near data space in a PC. + */ + +typedef INT32 hash_entry; /* must hold (code_int<<8) | byte */ + +#define HASH_ENTRY(prefix, suffix) ((((hash_entry) (prefix)) << 8) | (suffix)) + + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + j_decompress_ptr cinfo; /* back link saves passing separate parm */ + + /* State for packing variable-width codes into a bitstream */ + int n_bits; /* current number of bits/code */ + code_int maxcode; /* maximum code, given n_bits */ + int init_bits; /* initial n_bits ... restored after clear */ + INT32 cur_accum; /* holds bits not yet output */ + int cur_bits; /* # of bits in cur_accum */ + + /* LZW string construction */ + code_int waiting_code; /* symbol not yet output; may be extendable */ + boolean first_byte; /* if TRUE, waiting_code is not valid */ + + /* State for GIF code assignment */ + code_int ClearCode; /* clear code (doesn't change) */ + code_int EOFCode; /* EOF code (ditto) */ + code_int free_code; /* LZW: first not-yet-used symbol code */ + code_int code_counter; /* not LZW: counts output symbols */ + + /* LZW hash table */ + code_int *hash_code; /* => hash table of symbol codes */ + hash_entry FAR *hash_value; /* => hash table of symbol values */ + + /* GIF data packet construction buffer */ + int bytesinpkt; /* # of bytes in current packet */ + char packetbuf[256]; /* workspace for accumulating packet */ + +} gif_dest_struct; + +typedef gif_dest_struct * gif_dest_ptr; + + +/* + * Routines to package finished data bytes into GIF data blocks. + * A data block consists of a count byte (1..255) and that many data bytes. + */ + +LOCAL(void) +flush_packet (gif_dest_ptr dinfo) +/* flush any accumulated data */ +{ + if (dinfo->bytesinpkt > 0) { /* never write zero-length packet */ + dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++; + if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt) + != (size_t) dinfo->bytesinpkt) + ERREXIT(dinfo->cinfo, JERR_FILE_WRITE); + dinfo->bytesinpkt = 0; + } +} + + +/* Add a character to current packet; flush to disk if necessary */ +#define CHAR_OUT(dinfo, c) \ + { (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c); \ + if ((dinfo)->bytesinpkt >= 255) \ + flush_packet(dinfo); \ + } + + +/* Routine to convert variable-width codes into a byte stream */ + +LOCAL(void) +output (gif_dest_ptr dinfo, code_int code) +/* Emit a code of n_bits bits */ +/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */ +{ + dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits; + dinfo->cur_bits += dinfo->n_bits; + + while (dinfo->cur_bits >= 8) { + CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF); + dinfo->cur_accum >>= 8; + dinfo->cur_bits -= 8; + } + + /* + * If the next entry is going to be too big for the code size, + * then increase it, if possible. We do this here to ensure + * that it's done in sync with the decoder's codesize increases. + */ + if (dinfo->free_code > dinfo->maxcode) { + dinfo->n_bits++; + if (dinfo->n_bits == MAX_LZW_BITS) + dinfo->maxcode = LZW_TABLE_SIZE; /* free_code will never exceed this */ + else + dinfo->maxcode = MAXCODE(dinfo->n_bits); + } +} + + +/* Compression initialization & termination */ + + +LOCAL(void) +clear_hash (gif_dest_ptr dinfo) +/* Fill the hash table with empty entries */ +{ + /* It's sufficient to zero hash_code[] */ + MEMZERO(dinfo->hash_code, HSIZE * SIZEOF(code_int)); +} + + +LOCAL(void) +clear_block (gif_dest_ptr dinfo) +/* Reset compressor and issue a Clear code */ +{ + clear_hash(dinfo); /* delete all the symbols */ + dinfo->free_code = dinfo->ClearCode + 2; + output(dinfo, dinfo->ClearCode); /* inform decoder */ + dinfo->n_bits = dinfo->init_bits; /* reset code size */ + dinfo->maxcode = MAXCODE(dinfo->n_bits); +} + + +LOCAL(void) +compress_init (gif_dest_ptr dinfo, int i_bits) +/* Initialize compressor */ +{ + /* init all the state variables */ + dinfo->n_bits = dinfo->init_bits = i_bits; + dinfo->maxcode = MAXCODE(dinfo->n_bits); + dinfo->ClearCode = ((code_int) 1 << (i_bits - 1)); + dinfo->EOFCode = dinfo->ClearCode + 1; + dinfo->code_counter = dinfo->free_code = dinfo->ClearCode + 2; + dinfo->first_byte = TRUE; /* no waiting symbol yet */ + /* init output buffering vars */ + dinfo->bytesinpkt = 0; + dinfo->cur_accum = 0; + dinfo->cur_bits = 0; + /* clear hash table */ + if (dinfo->hash_code != NULL) + clear_hash(dinfo); + /* GIF specifies an initial Clear code */ + output(dinfo, dinfo->ClearCode); +} + + +LOCAL(void) +compress_term (gif_dest_ptr dinfo) +/* Clean up at end */ +{ + /* Flush out the buffered LZW code */ + if (! dinfo->first_byte) + output(dinfo, dinfo->waiting_code); + /* Send an EOF code */ + output(dinfo, dinfo->EOFCode); + /* Flush the bit-packing buffer */ + if (dinfo->cur_bits > 0) { + CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF); + } + /* Flush the packet buffer */ + flush_packet(dinfo); +} + + +/* GIF header construction */ + + +LOCAL(void) +put_word (gif_dest_ptr dinfo, unsigned int w) +/* Emit a 16-bit word, LSB first */ +{ + putc(w & 0xFF, dinfo->pub.output_file); + putc((w >> 8) & 0xFF, dinfo->pub.output_file); +} + + +LOCAL(void) +put_3bytes (gif_dest_ptr dinfo, int val) +/* Emit 3 copies of same byte value --- handy subr for colormap construction */ +{ + putc(val, dinfo->pub.output_file); + putc(val, dinfo->pub.output_file); + putc(val, dinfo->pub.output_file); +} + + +LOCAL(void) +emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap) +/* Output the GIF file header, including color map */ +/* If colormap == NULL, synthesize a grayscale colormap */ +{ + int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte; + int cshift = dinfo->cinfo->data_precision - 8; + int i; + + if (num_colors > 256) + ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors); + /* Compute bits/pixel and related values */ + BitsPerPixel = 1; + while (num_colors > (1 << BitsPerPixel)) + BitsPerPixel++; + ColorMapSize = 1 << BitsPerPixel; + if (BitsPerPixel <= 1) + InitCodeSize = 2; + else + InitCodeSize = BitsPerPixel; + /* + * Write the GIF header. + * Note that we generate a plain GIF87 header for maximum compatibility. + */ + putc('G', dinfo->pub.output_file); + putc('I', dinfo->pub.output_file); + putc('F', dinfo->pub.output_file); + putc('8', dinfo->pub.output_file); + putc('7', dinfo->pub.output_file); + putc('a', dinfo->pub.output_file); + /* Write the Logical Screen Descriptor */ + put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); + put_word(dinfo, (unsigned int) dinfo->cinfo->output_height); + FlagByte = 0x80; /* Yes, there is a global color table */ + FlagByte |= (BitsPerPixel - 1) << 4; /* color resolution */ + FlagByte |= (BitsPerPixel - 1); /* size of global color table */ + putc(FlagByte, dinfo->pub.output_file); + putc(0, dinfo->pub.output_file); /* Background color index */ + putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */ + /* Write the Global Color Map */ + /* If the color map is more than 8 bits precision, */ + /* we reduce it to 8 bits by shifting */ + for (i = 0; i < ColorMapSize; i++) { + if (i < num_colors) { + if (colormap != NULL) { + if (dinfo->cinfo->out_color_space == JCS_RGB) { + /* Normal case: RGB color map */ + putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file); + putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file); + putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file); + } else { + /* Grayscale "color map": possible if quantizing grayscale image */ + put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift); + } + } else { + /* Create a grayscale map of num_colors values, range 0..255 */ + put_3bytes(dinfo, (i * 255 + (num_colors - 1) / 2) / (num_colors - 1)); + } + } else { + /* fill out the map to a power of 2 */ + put_3bytes(dinfo, CENTERJSAMPLE >> cshift); + } + } + /* Write image separator and Image Descriptor */ + putc(',', dinfo->pub.output_file); /* separator */ + put_word(dinfo, 0); /* left/top offset */ + put_word(dinfo, 0); + put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */ + put_word(dinfo, (unsigned int) dinfo->cinfo->output_height); + /* flag byte: not interlaced, no local color map */ + putc(0x00, dinfo->pub.output_file); + /* Write Initial Code Size byte */ + putc(InitCodeSize, dinfo->pub.output_file); + + /* Initialize for compression of image data */ + compress_init(dinfo, InitCodeSize + 1); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + + if (cinfo->quantize_colors) + emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap); + else + emit_header(dest, 256, (JSAMPARRAY) NULL); +} + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + + +/* + * The LZW algorithm proper + */ + +METHODDEF(void) +put_LZW_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + register JSAMPROW ptr; + register JDIMENSION col; + code_int c; + register hash_int i; + register hash_int disp; + register hash_entry probe_value; + + ptr = dest->pub.buffer[0]; + for (col = cinfo->output_width; col > 0; col--) { + /* Accept and compress one 8-bit byte */ + c = (code_int) GETJSAMPLE(*ptr++); + + if (dest->first_byte) { /* need to initialize waiting_code */ + dest->waiting_code = c; + dest->first_byte = FALSE; + continue; + } + + /* Probe hash table to see if a symbol exists for + * waiting_code followed by c. + * If so, replace waiting_code by that symbol and continue. + */ + i = ((hash_int) c << (MAX_LZW_BITS-8)) + dest->waiting_code; + /* i is less than twice 2**MAX_LZW_BITS, therefore less than twice HSIZE */ + if (i >= HSIZE) + i -= HSIZE; + + probe_value = HASH_ENTRY(dest->waiting_code, c); + + if (dest->hash_code[i] == 0) { + /* hit empty slot; desired symbol not in table */ + output(dest, dest->waiting_code); + if (dest->free_code < LZW_TABLE_SIZE) { + dest->hash_code[i] = dest->free_code++; /* add symbol to hashtable */ + dest->hash_value[i] = probe_value; + } else + clear_block(dest); + dest->waiting_code = c; + continue; + } + if (dest->hash_value[i] == probe_value) { + dest->waiting_code = dest->hash_code[i]; + continue; + } + + if (i == 0) /* secondary hash (after G. Knott) */ + disp = 1; + else + disp = HSIZE - i; + for (;;) { + i -= disp; + if (i < 0) + i += HSIZE; + if (dest->hash_code[i] == 0) { + /* hit empty slot; desired symbol not in table */ + output(dest, dest->waiting_code); + if (dest->free_code < LZW_TABLE_SIZE) { + dest->hash_code[i] = dest->free_code++; /* add symbol to hashtable */ + dest->hash_value[i] = probe_value; + } else + clear_block(dest); + dest->waiting_code = c; + break; + } + if (dest->hash_value[i] == probe_value) { + dest->waiting_code = dest->hash_code[i]; + break; + } + } + } +} + + +/* + * The pseudo-compression algorithm. + * + * In this version we simply output each pixel value as a separate symbol; + * thus, no compression occurs. In fact, there is expansion of one bit per + * pixel, because we use a symbol width one bit wider than the pixel width. + * + * GIF ordinarily uses variable-width symbols, and the decoder will expect + * to ratchet up the symbol width after a fixed number of symbols. + * To simplify the logic and keep the expansion penalty down, we emit a + * GIF Clear code to reset the decoder just before the width would ratchet up. + * Thus, all the symbols in the output file will have the same bit width. + * Note that emitting the Clear codes at the right times is a mere matter of + * counting output symbols and is in no way dependent on the LZW algorithm. + * + * With a small basic pixel width (low color count), Clear codes will be + * needed very frequently, causing the file to expand even more. So this + * simplistic approach wouldn't work too well on bilevel images, for example. + * But for output of JPEG conversions the pixel width will usually be 8 bits + * (129 to 256 colors), so the overhead added by Clear symbols is only about + * one symbol in every 256. + */ + +METHODDEF(void) +put_raw_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + register JSAMPROW ptr; + register JDIMENSION col; + code_int c; + + ptr = dest->pub.buffer[0]; + for (col = cinfo->output_width; col > 0; col--) { + c = (code_int) GETJSAMPLE(*ptr++); + /* Accept and output one pixel value. + * The given value must be less than n_bits wide. + */ + + /* Output the given pixel value as a symbol. */ + output(dest, c); + /* Issue Clear codes often enough to keep the reader from ratcheting up + * its symbol size. + */ + if (dest->code_counter < dest->maxcode) { + dest->code_counter++; + } else { + output(dest, dest->ClearCode); + dest->code_counter = dest->ClearCode + 2; /* reset the counter */ + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + + /* Flush compression mechanism */ + compress_term(dest); + /* Write a zero-length data block to end the series */ + putc(0, dest->pub.output_file); + /* Write the GIF terminator mark */ + putc(';', dest->pub.output_file); + /* Make sure we wrote the output file OK */ + JFFLUSH(dest->pub.output_file); + if (JFERROR(dest->pub.output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for GIF format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_gif (j_decompress_ptr cinfo, boolean is_lzw) +{ + gif_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (gif_dest_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(gif_dest_struct)); + dest->cinfo = cinfo; /* make back link for subroutines */ + dest->pub.start_output = start_output_gif; + dest->pub.finish_output = finish_output_gif; + + if (cinfo->out_color_space != JCS_GRAYSCALE && + cinfo->out_color_space != JCS_RGB) + ERREXIT(cinfo, JERR_GIF_COLORSPACE); + + /* Force quantization if color or if > 8 bits input */ + if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) { + /* Force quantization to at most 256 colors */ + cinfo->quantize_colors = TRUE; + if (cinfo->desired_number_of_colors > 256) + cinfo->desired_number_of_colors = 256; + } + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + if (cinfo->output_components != 1) /* safety check: just one component? */ + ERREXIT(cinfo, JERR_GIF_BUG); + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + if (is_lzw) { + dest->pub.put_pixel_rows = put_LZW_pixel_rows; + /* Allocate space for hash table */ + dest->hash_code = (code_int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HSIZE * SIZEOF(code_int)); + dest->hash_value = (hash_entry FAR *) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HSIZE * SIZEOF(hash_entry)); + } else { + dest->pub.put_pixel_rows = put_raw_pixel_rows; + /* Mark tables unused */ + dest->hash_code = NULL; + dest->hash_value = NULL; + } + + return &dest->pub; +} + +#endif /* GIF_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/wrppm.c b/widget/milsko/milskosrc/external/libjpeg/src/wrppm.c new file mode 100644 index 0000000000..c9e03ad10d --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/wrppm.c @@ -0,0 +1,264 @@ +/* + * wrppm.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2009-2020 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in PPM/PGM format. + * The extended 2-byte-per-sample raw PPM/PGM formats are supported. + * The PBMPLUS library is NOT required to compile this software + * (but it is highly useful as a set of PPM image manipulation programs). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef PPM_SUPPORTED + + +/* + * For 12-bit JPEG data, we either downscale the values to 8 bits + * (to write standard byte-per-sample PPM/PGM files), or output + * nonstandard word-per-sample PPM/PGM files. Downscaling is done + * if PPM_NORAWWORD is defined (this can be done in the Makefile + * or in jconfig.h). + * (When the core library supports data precision reduction, a cleaner + * implementation will be to ask for that instead.) + */ + +#if BITS_IN_JSAMPLE == 8 +#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) (v) +#define BYTESPERSAMPLE 1 +#define PPM_MAXVAL 255 +#else +#ifdef PPM_NORAWWORD +#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8)) +#define BYTESPERSAMPLE 1 +#define PPM_MAXVAL 255 +#else +/* The word-per-sample format always puts the MSB first. */ +#define PUTPPMSAMPLE(ptr,v) \ + { register int val_ = v; \ + *ptr++ = (char) ((val_ >> 8) & 0xFF); \ + *ptr++ = (char) (val_ & 0xFF); \ + } +#define BYTESPERSAMPLE 2 +#define PPM_MAXVAL ((1<pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * This code is used when we have to copy the data and apply a pixel + * format translation. Typically this only happens in 12-bit mode. + */ + +METHODDEF(void) +copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = dest->pixrow; + bufferptr = dest->iobuffer; + for (col = dest->samples_per_row; col > 0; col--) { + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++)); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Write some pixel data when color quantization is in effect. + * We have to demap the color index values to straight data. + */ + +METHODDEF(void) +put_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register int pixval; + register JSAMPROW ptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JSAMPROW color_map1 = cinfo->colormap[1]; + register JSAMPROW color_map2 = cinfo->colormap[2]; + register JDIMENSION col; + + ptr = dest->pixrow; + bufferptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + pixval = GETJSAMPLE(*ptr++); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval])); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval])); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval])); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + +METHODDEF(void) +put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register JSAMPROW ptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JDIMENSION col; + + ptr = dest->pixrow; + bufferptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[GETJSAMPLE(*ptr++)])); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Emit file header */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + /* emit header for raw PGM format */ + fprintf(dinfo->output_file, "P5\n%ld %ld\n%d\n", + (long) cinfo->output_width, (long) cinfo->output_height, + PPM_MAXVAL); + break; + case JCS_RGB: + /* emit header for raw PPM format */ + fprintf(dinfo->output_file, "P6\n%ld %ld\n%d\n", + (long) cinfo->output_width, (long) cinfo->output_height, + PPM_MAXVAL); + break; + default: + ERREXIT(cinfo, JERR_PPM_COLORSPACE); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Make sure we wrote the output file OK */ + JFFLUSH(dinfo->output_file); + if (JFERROR(dinfo->output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for PPM format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_ppm (j_decompress_ptr cinfo) +{ + ppm_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (ppm_dest_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(ppm_dest_struct)); + dest->pub.start_output = start_output_ppm; + dest->pub.finish_output = finish_output_ppm; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Create physical I/O buffer. Note we make this near on a PC. */ + dest->samples_per_row = cinfo->output_width * cinfo->out_color_components; + dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * SIZEOF(char)); + dest->iobuffer = (char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width); + + if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 || + SIZEOF(JSAMPLE) != SIZEOF(char)) { + /* When quantizing, we need an output buffer for colormap indexes + * that's separate from the physical I/O buffer. We also need a + * separate buffer if pixel format translation must take place. + */ + dest->pixrow = (JSAMPROW) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (size_t) cinfo->output_width * + (size_t) cinfo->output_components * SIZEOF(JSAMPLE)); + if (! cinfo->quantize_colors) + dest->pub.put_pixel_rows = copy_pixel_rows; + else if (cinfo->out_color_space == JCS_GRAYSCALE) + dest->pub.put_pixel_rows = put_demapped_gray; + else + dest->pub.put_pixel_rows = put_demapped_rgb; + } else { + /* We will fwrite() directly from decompressor output buffer. */ + /* Cast here implies near->far pointer conversion on PCs */ + dest->pixrow = (JSAMPROW) dest->iobuffer; + dest->pub.put_pixel_rows = put_pixel_rows; + } + /* Synthesize a JSAMPARRAY pointer structure */ + dest->pub.buffer = & dest->pixrow; + dest->pub.buffer_height = 1; + + return &dest->pub; +} + +#endif /* PPM_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/wrrle.c b/widget/milsko/milskosrc/external/libjpeg/src/wrrle.c new file mode 100644 index 0000000000..dc2fadb887 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/wrrle.c @@ -0,0 +1,306 @@ +/* + * wrrle.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2017-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in RLE format. + * The Utah Raster Toolkit library is required (version 3.1 or later). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * Based on code contributed by Mike Lijewski, + * with updates from Robert Hutchinson. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef RLE_SUPPORTED + +/* rle.h is provided by the Utah Raster Toolkit. */ + +#include + +/* + * We assume that JSAMPLE has the same representation as rle_pixel, + * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + + +/* + * Since RLE stores scanlines bottom-to-top, we have to invert the image + * from JPEG's top-to-bottom order. To do this, we save the outgoing data + * in a virtual array during put_pixel_row calls, then actually emit the + * RLE file during finish_output. + */ + + +/* + * For now, if we emit an RLE color map then it is always 256 entries long, + * though not all of the entries need be used. + */ + +#define CMAPBITS 8 +#define CMAPLENGTH (1<<(CMAPBITS)) + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + jvirt_sarray_ptr image; /* virtual array to store the output image */ + rle_map *colormap; /* RLE-style color map, or NULL if none */ + rle_pixel **rle_row; /* To pass rows to rle_putrow() */ + +} rle_dest_struct; + +typedef rle_dest_struct * rle_dest_ptr; + + +/* Forward declarations */ +METHODDEF(void) rle_put_pixel_rows + JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + + +/* + * Write the file header. + * + * In this module it's easier to wait till finish_output to write anything. + */ + +METHODDEF(void) +start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + size_t cmapsize; + int ci, i; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* + * Make sure the image can be stored in RLE format. + * + * - RLE stores image dimensions as *signed* 16 bit integers. JPEG + * uses unsigned, so we have to check the width. + * + * - Colorspace is expected to be grayscale or RGB. + * + * - The number of channels (components) is expected to be 1 (grayscale/ + * pseudocolor) or 3 (truecolor/directcolor). + * (could be 2 or 4 if using an alpha channel, but we aren't) + */ + + if (cinfo->output_width > 32767 || cinfo->output_height > 32767) + ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width, + cinfo->output_height); + + if (cinfo->out_color_space != JCS_GRAYSCALE && + cinfo->out_color_space != JCS_RGB) + ERREXIT(cinfo, JERR_RLE_COLORSPACE); + + if (cinfo->output_components != 1 && cinfo->output_components != 3) + ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components); + + /* Convert colormap, if any, to RLE format. */ + + dest->colormap = NULL; + + if (cinfo->quantize_colors) { + /* Allocate storage for RLE-style cmap, zero any extra entries */ + cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map); + dest->colormap = (rle_map *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize); + MEMZERO(dest->colormap, cmapsize); + + /* Save away data in RLE format --- note 8-bit left shift! */ + /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */ + for (ci = 0; ci < cinfo->out_color_components; ci++) { + for (i = 0; i < cinfo->actual_number_of_colors; i++) { + dest->colormap[ci * CMAPLENGTH + i] = + GETJSAMPLE(cinfo->colormap[ci][i]) << 8; + } + } + } + + /* Set the output buffer to the first row */ + dest->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE); + dest->pub.buffer_height = 1; + + dest->pub.put_pixel_rows = rle_put_pixel_rows; + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->total_extra_passes++; /* count file writing as separate pass */ + } +#endif +} + + +/* + * Write some pixel data. + * + * This routine just saves the data away in a virtual array. + */ + +METHODDEF(void) +rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + + if (cinfo->output_scanline < cinfo->output_height) { + dest->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + cinfo->output_scanline, (JDIMENSION) 1, TRUE); + } +} + + +/* + * Finish up at the end of the file. + * + * Here is where we really output the RLE file. + */ + +METHODDEF(void) +finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + rle_hdr header; /* Output file information */ + rle_pixel **rle_row, *red_ptr, *green_ptr, *blue_ptr; + JSAMPROW output_row; + char cmapcomment[80]; + int row, col; + int ci; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* Initialize the header info */ + header = *rle_hdr_init(NULL); + header.rle_file = dest->pub.output_file; + header.xmin = 0; + header.xmax = cinfo->output_width - 1; + header.ymin = 0; + header.ymax = cinfo->output_height - 1; + header.alpha = 0; + header.ncolors = cinfo->output_components; + for (ci = 0; ci < cinfo->output_components; ci++) { + RLE_SET_BIT(header, ci); + } + if (cinfo->quantize_colors) { + header.ncmap = cinfo->out_color_components; + header.cmaplen = CMAPBITS; + header.cmap = dest->colormap; + /* Add a comment to the output image with the true colormap length. */ + sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors); + rle_putcom(cmapcomment, &header); + } + + /* Emit the RLE header and color map (if any) */ + rle_put_setup(&header); + + /* Now output the RLE data from our virtual array. + * We assume here that (a) rle_pixel is represented the same as JSAMPLE, + * and (b) we are not on a machine where FAR pointers differ from regular. + */ + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_limit = cinfo->output_height; + progress->pub.pass_counter = 0; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + + if (cinfo->output_components == 1) { + for (row = cinfo->output_height - 1; row >= 0; row--) { + rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + (JDIMENSION) row, (JDIMENSION) 1, FALSE); + rle_putrow(rle_row, (int) cinfo->output_width, &header); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } else { + for (row = cinfo->output_height - 1; row >= 0; row--) { + output_row = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + (JDIMENSION) row, (JDIMENSION) 1, FALSE); + rle_row = dest->rle_row; + red_ptr = rle_row[0]; + green_ptr = rle_row[1]; + blue_ptr = rle_row[2]; + for (col = cinfo->output_width; col > 0; col--) { + *red_ptr++ = GETJSAMPLE(*output_row++); + *green_ptr++ = GETJSAMPLE(*output_row++); + *blue_ptr++ = GETJSAMPLE(*output_row++); + } + rle_putrow(rle_row, (int) cinfo->output_width, &header); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) + progress->completed_extra_passes++; +#endif + + /* Emit file trailer */ + rle_puteof(&header); + JFFLUSH(dest->pub.output_file); + if (JFERROR(dest->pub.output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for RLE format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_rle (j_decompress_ptr cinfo) +{ + rle_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (rle_dest_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(rle_dest_struct)); + dest->pub.start_output = start_output_rle; + dest->pub.finish_output = finish_output_rle; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Allocate a work array for output to the RLE library. */ + dest->rle_row = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, + JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) cinfo->output_components); + + /* Allocate a virtual array to hold the image. */ + dest->image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + cinfo->output_width * (JDIMENSION) cinfo->output_components, + cinfo->output_height, (JDIMENSION) 1); + + return &dest->pub; +} + +#endif /* RLE_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libjpeg/src/wrtarga.c b/widget/milsko/milskosrc/external/libjpeg/src/wrtarga.c new file mode 100644 index 0000000000..8ded5183c4 --- /dev/null +++ b/widget/milsko/milskosrc/external/libjpeg/src/wrtarga.c @@ -0,0 +1,254 @@ +/* + * wrtarga.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2015-2019 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in Targa format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * Based on code contributed by Lee Daniel Crocker. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef TARGA_SUPPORTED + + +/* + * To support 12-bit JPEG data, we'd have to scale output down to 8 bits. + * This is not yet implemented. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * The output buffer needs to be writable by fwrite(). On PCs, we must + * allocate the buffer in near data space, because we are assuming small-data + * memory model, wherein fwrite() can't reach far memory. If you need to + * process very wide images on a PC, you might have to compile in large-memory + * model, or else replace fwrite() with a putc() loop --- which will be much + * slower. + */ + + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + char *iobuffer; /* physical I/O buffer */ + JDIMENSION buffer_width; /* width of one row */ +} tga_dest_struct; + +typedef tga_dest_struct * tga_dest_ptr; + + +LOCAL(void) +write_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors) +/* Create and write a Targa header */ +{ + char targaheader[18]; + + /* Set unused fields of header to 0 */ + MEMZERO(targaheader, SIZEOF(targaheader)); + + if (num_colors > 0) { + targaheader[1] = 1; /* color map type 1 */ + targaheader[5] = (char) (num_colors & 0xFF); + targaheader[6] = (char) (num_colors >> 8); + targaheader[7] = 24; /* 24 bits per cmap entry */ + } + + targaheader[12] = (char) (cinfo->output_width & 0xFF); + targaheader[13] = (char) (cinfo->output_width >> 8); + targaheader[14] = (char) (cinfo->output_height & 0xFF); + targaheader[15] = (char) (cinfo->output_height >> 8); + targaheader[17] = 0x20; /* Top-down, non-interlaced */ + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + targaheader[2] = 3; /* image type = uncompressed grayscale */ + targaheader[16] = 8; /* bits per pixel */ + } else { /* must be RGB */ + if (num_colors > 0) { + targaheader[2] = 1; /* image type = colormapped RGB */ + targaheader[16] = 8; + } else { + targaheader[2] = 2; /* image type = uncompressed RGB */ + targaheader[16] = 24; + } + } + + if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* used for unquantized full-color output */ +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */ + outptr[1] = (char) GETJSAMPLE(inptr[1]); + outptr[2] = (char) GETJSAMPLE(inptr[0]); + inptr += 3, outptr += 3; + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + +METHODDEF(void) +put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* used for grayscale OR quantized color output */ +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = (char) GETJSAMPLE(*inptr++); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Write some demapped pixel data when color quantization is in effect. + * For Targa, this is only applied to grayscale data. + */ + +METHODDEF(void) +put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + int num_colors, i; + FILE *outfile; + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + /* Targa doesn't have a mapped grayscale format, so we will */ + /* demap quantized gray output. Never emit a colormap. */ + write_header(cinfo, dinfo, 0); + if (cinfo->quantize_colors) + dinfo->put_pixel_rows = put_demapped_gray; + else + dinfo->put_pixel_rows = put_gray_rows; + break; + case JCS_RGB: + if (cinfo->quantize_colors) { + /* We only support 8-bit colormap indexes, so only 256 colors */ + num_colors = cinfo->actual_number_of_colors; + if (num_colors > 256) + ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors); + write_header(cinfo, dinfo, num_colors); + /* Write the colormap. Note Targa uses BGR byte order */ + outfile = dinfo->output_file; + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(cinfo->colormap[2][i]), outfile); + putc(GETJSAMPLE(cinfo->colormap[1][i]), outfile); + putc(GETJSAMPLE(cinfo->colormap[0][i]), outfile); + } + dinfo->put_pixel_rows = put_gray_rows; + } else { + write_header(cinfo, dinfo, 0); + dinfo->put_pixel_rows = put_pixel_rows; + } + break; + default: + ERREXIT(cinfo, JERR_TGA_COLORSPACE); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Make sure we wrote the output file OK */ + JFFLUSH(dinfo->output_file); + if (JFERROR(dinfo->output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for Targa format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_targa (j_decompress_ptr cinfo) +{ + tga_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (tga_dest_ptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(tga_dest_struct)); + dest->pub.start_output = start_output_tga; + dest->pub.finish_output = finish_output_tga; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Create I/O buffer. Note we make this near on a PC. */ + dest->buffer_width = cinfo->output_width * cinfo->output_components; + dest->iobuffer = (char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, + JPOOL_IMAGE, (size_t) dest->buffer_width * SIZEOF(char)); + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, + JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return &dest->pub; +} + +#endif /* TARGA_SUPPORTED */ diff --git a/widget/milsko/milskosrc/external/libpng/.appveyor.yml b/widget/milsko/milskosrc/external/libpng/.appveyor.yml new file mode 100644 index 0000000000..70d5e00d44 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/.appveyor.yml @@ -0,0 +1,81 @@ +version: 1.6.x-{build} + +branches: + except: + - /libpng[0-1][0-8]/ + - /v[0-1][.][0-8][.][0-9]+/ + +image: + - Visual Studio 2022 + +shallow_clone: true + +environment: + matrix: + - TOOLCHAIN: vstudio + AUTOMATION: cmake + ARCH: x86 + - TOOLCHAIN: vstudio + AUTOMATION: cmake + ARCH: x64 + - TOOLCHAIN: vstudio + AUTOMATION: cmake + ARCH: arm64 + - TOOLCHAIN: llvm + AUTOMATION: cmake + ARCH: x64 + - TOOLCHAIN: msys2 + AUTOMATION: cmake + ARCH: i686 + - TOOLCHAIN: msys2 + AUTOMATION: cmake + ARCH: x86_64 + - TOOLCHAIN: msys2 + AUTOMATION: configure + ARCH: i686 + - TOOLCHAIN: msys2 + AUTOMATION: configure + ARCH: x86_64 + - TOOLCHAIN: msys2 + AUTOMATION: makefiles + ARCH: i686 + - TOOLCHAIN: msys2 + AUTOMATION: makefiles + ARCH: x86_64 + +install: + - 'if "%TOOLCHAIN%"=="vstudio" C:\tools\vcpkg\vcpkg.exe install zlib:%ARCH%-windows' + - 'if "%TOOLCHAIN%"=="vstudio" C:\tools\vcpkg\vcpkg.exe integrate install' + - 'if "%TOOLCHAIN%"=="llvm" C:\tools\vcpkg\vcpkg.exe install zlib:%ARCH%-windows' + - 'if "%TOOLCHAIN%"=="llvm" C:\tools\vcpkg\vcpkg.exe integrate install' + - 'if "%TOOLCHAIN%"=="msys2" if "%AUTOMATION%"=="cmake" C:\msys64\usr\bin\pacman.exe -S --noconfirm mingw-w64-%ARCH%-cmake mingw-w64-%ARCH%-ninja' + +before_build: + - 'if "%TOOLCHAIN%"=="vstudio" set CI_CMAKE_GENERATOR=Visual Studio 17 2022' + - 'if "%TOOLCHAIN%"=="vstudio" set CI_CMAKE_TOOLCHAIN_FILE=C:\tools\vcpkg\scripts\buildsystems\vcpkg.cmake' + - 'if "%TOOLCHAIN%"=="vstudio" if "%ARCH%"=="x86" set CI_CMAKE_GENERATOR_PLATFORM=Win32' + - 'if "%TOOLCHAIN%"=="vstudio" if "%ARCH%"=="x64" set CI_CMAKE_GENERATOR_PLATFORM=x64' + - 'if "%TOOLCHAIN%"=="vstudio" if "%ARCH%"=="arm64" set CI_CMAKE_GENERATOR_PLATFORM=ARM64' + - 'if "%TOOLCHAIN%"=="vstudio" if "%ARCH%"=="arm64" set CI_CMAKE_VARS=-DPNG_TESTS=0' + - 'if "%TOOLCHAIN%"=="llvm" set CI_CMAKE_GENERATOR=Ninja' + - 'if "%TOOLCHAIN%"=="llvm" set CI_CMAKE_TOOLCHAIN_FILE=C:\tools\vcpkg\scripts\buildsystems\vcpkg.cmake' + - 'if "%TOOLCHAIN%"=="llvm" set CI_CC=clang' + - 'if "%TOOLCHAIN%"=="msys2" set CI_CMAKE_GENERATOR=Ninja' + - 'if "%TOOLCHAIN%"=="msys2" set CI_CC=gcc' + - 'if "%TOOLCHAIN%"=="msys2" if "%ARCH%"=="i686" set MSYSTEM=MINGW32' + - 'if "%TOOLCHAIN%"=="msys2" if "%ARCH%"=="x86_64" set MSYSTEM=MINGW64' + - 'set CI_CMAKE_BUILD_FLAGS=-j2' + - 'set CI_CTEST_FLAGS=-j2' + - 'set CI_MAKE_FLAGS=-j2' + - 'set CI_MAKEFILES=scripts/makefile.gcc scripts/makefile.msys scripts/makefile.std' + +build_script: + - 'if "%TOOLCHAIN%"=="vstudio" C:\msys64\usr\bin\bash.exe -l "%APPVEYOR_BUILD_FOLDER%\ci\ci_verify_cmake.sh"' + - 'if "%TOOLCHAIN%"=="llvm" C:\msys64\usr\bin\bash.exe -l "%APPVEYOR_BUILD_FOLDER%\ci\ci_verify_cmake.sh"' + - 'if "%TOOLCHAIN%"=="msys2" if "%AUTOMATION%"=="cmake" C:\msys64\usr\bin\bash.exe -l "%APPVEYOR_BUILD_FOLDER%\ci\ci_verify_cmake.sh"' + - 'if "%TOOLCHAIN%"=="msys2" if "%AUTOMATION%"=="configure" C:\msys64\usr\bin\bash.exe -l "%APPVEYOR_BUILD_FOLDER%\ci\ci_verify_configure.sh"' + - 'if "%TOOLCHAIN%"=="msys2" if "%AUTOMATION%"=="makefiles" C:\msys64\usr\bin\bash.exe -l "%APPVEYOR_BUILD_FOLDER%\ci\ci_verify_makefiles.sh"' + +cache: + - 'C:\tools\vcpkg\installed' + - 'C:\msys64\var\cache\pacman' diff --git a/widget/milsko/milskosrc/external/libpng/.cmake-format.yaml b/widget/milsko/milskosrc/external/libpng/.cmake-format.yaml new file mode 100644 index 0000000000..67c53d2db1 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/.cmake-format.yaml @@ -0,0 +1,94 @@ +# https://pypi.org/project/cmakelang +# https://github.com/cheshirekow/cmake_format + +# ---------------------- +# Options for formatting +# ---------------------- + +# How wide to allow formatted cmake files +# TODO: Reflow the CMake files to allow setting the maximum line width to 100. +line_width: 255 + +# How many spaces to tab for indent +tab_size: 2 + +# If true, lines are indented using tab characters (utf-8 0x09) instead of +# space characters (utf-8 0x20). In cases where the layout would +# require a fractional tab character, the behavior of the fractional +# indentation is governed by +use_tabchars: false + +# If is True, then the value of this variable indicates how +# fractional indentions are handled during whitespace replacement. If set to +# 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set +# to `round-up` fractional indentation is replaced with a single tab character +# (utf-8 0x09) effectively shifting the column to the next tabstop +fractional_tab_policy: "use-space" + +# Enable comment markup parsing and reflow +enable_markup: false + +# ------------------- +# Options for linting +# ------------------- + +# Lint codes to disable +disabled_codes: [ + # TODO: + # Reconcile the CMake variable names with the patterns below, then + # re-enable the "invalid variable name XXX" messages. + "C0103", + + # TODO: + # Add brief COMMENT arguments to the `add_custom_target` commands. + "C0113", +] + +# Regular expression pattern describing valid function names +function_pattern: "[0-9a-z_]+" + +# Regular expression pattern describing valid macro names +macro_pattern: "[0-9A-Z_]+" + +# Regular expression pattern describing valid names for variables with global +# (cache) scope +global_var_pattern: "[A-Z][0-9A-Z_]+" + +# Regular expression pattern describing valid names for variables with global +# scope (but internal semantic) +internal_var_pattern: "_[A-Z][0-9A-Z_]+" + +# Regular expression pattern describing valid names for variables with local +# scope +local_var_pattern: "[a-z][a-z0-9_]+" + +# Regular expression pattern describing valid names for privatedirectory +# variables +private_var_pattern: "_[0-9a-z_]+" + +# Regular expression pattern describing valid names for public directory +# variables +public_var_pattern: "[A-Z][0-9A-Z_]+" + +# Regular expression pattern describing valid names for function/macro +# arguments and loop variables. +argument_var_pattern: "[a-z][a-z0-9_]+" + +# Regular expression pattern describing valid names for keywords used in +# functions or macros +keyword_pattern: "[A-Z][0-9A-Z_]+" + +# In the heuristic for C0201, how many conditionals to match within a loop in +# before considering the loop a parser +max_conditionals_custom_parser: 2 + +# Require at least this many newlines between statements; +# require no more than this many newlines between statements; +# etc. +min_statement_spacing: 1 +max_statement_spacing: 2 +max_returns: 6 +max_branches: 12 +max_arguments: 5 +max_localvars: 15 +max_statements: 50 diff --git a/widget/milsko/milskosrc/external/libpng/.editorconfig b/widget/milsko/milskosrc/external/libpng/.editorconfig new file mode 100644 index 0000000000..4181a3796b --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/.editorconfig @@ -0,0 +1,55 @@ +# https://editorconfig.org + +root = true + +[*] +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.txt] +indent_size = unset +indent_style = space + +[*.[chS]] +indent_size = 3 +indent_style = space +max_doc_length = 80 +max_line_length = 80 + +[*.dfa] +indent_size = 3 +indent_style = space +max_doc_length = 80 +max_line_length = 80 + +[*.awk] +indent_size = 3 +indent_style = space +max_doc_length = 80 +max_line_length = 100 + +[*.cmake] +indent_size = 2 +indent_style = space +max_doc_length = 80 +max_line_length = 100 + +[*.sh] +indent_size = 4 +indent_style = space +max_doc_length = 100 +max_line_length = 100 + +[{Makefile.in,aclocal.m4,ltmain.sh}] +indent_size = unset +indent_style = unset +insert_final_newline = unset +max_doc_length = unset +max_line_length = unset +trim_trailing_whitespace = unset + +[COMMIT_EDITMSG] +indent_style = space +max_doc_length = unset +max_line_length = 72 diff --git a/widget/milsko/milskosrc/external/libpng/.editorconfig-checker.json b/widget/milsko/milskosrc/external/libpng/.editorconfig-checker.json new file mode 100644 index 0000000000..ef08e0801e --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/.editorconfig-checker.json @@ -0,0 +1,9 @@ +{ + "Disable": { + "IndentSize": true + }, + "Exclude": [ + ".git/", + "out/" + ] +} diff --git a/widget/milsko/milskosrc/external/libpng/.yamllint.yml b/widget/milsko/milskosrc/external/libpng/.yamllint.yml new file mode 100644 index 0000000000..9b7af5f2c3 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/.yamllint.yml @@ -0,0 +1,7 @@ +extends: default +rules: + document-start: disable + document-end: disable + line-length: disable + truthy: + check-keys: false diff --git a/widget/milsko/milskosrc/external/libpng/LICENSE b/widget/milsko/milskosrc/external/libpng/LICENSE new file mode 100644 index 0000000000..ea6df986cb --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/LICENSE @@ -0,0 +1,134 @@ +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE +========================================= + +PNG Reference Library License version 2 +--------------------------------------- + + * Copyright (c) 1995-2025 The PNG Reference Library Authors. + * Copyright (c) 2018-2025 Cosmin Truta. + * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. + * Copyright (c) 1996-1997 Andreas Dilger. + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +The software is supplied "as is", without warranty of any kind, +express or implied, including, without limitation, the warranties +of merchantability, fitness for a particular purpose, title, and +non-infringement. In no event shall the Copyright owners, or +anyone distributing the software, be liable for any damages or +other liability, whether in contract, tort or otherwise, arising +from, out of, or in connection with the software, or the use or +other dealings in the software, even if advised of the possibility +of such damage. + +Permission is hereby granted to use, copy, modify, and distribute +this software, or portions hereof, for any purpose, without fee, +subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you + use this software in a product, an acknowledgment in the product + documentation would be appreciated, but is not required. + + 2. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + + +PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) +----------------------------------------------------------------------- + +libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are +Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are +derived from libpng-1.0.6, and are distributed according to the same +disclaimer and license as libpng-1.0.6 with the following individuals +added to the list of Contributing Authors: + + Simon-Pierre Cadieux + Eric S. Raymond + Mans Rullgard + Cosmin Truta + Gilles Vollant + James Yu + Mandar Sahastrabuddhe + Google Inc. + Vadim Barkov + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of + the library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is + with the user. + +Some files in the "contrib" directory and some configure-generated +files that are distributed with libpng have other copyright owners, and +are released under other open source licenses. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from +libpng-0.96, and are distributed according to the same disclaimer and +license as libpng-0.96, with the following individuals added to the +list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, +and are distributed according to the same disclaimer and license as +libpng-0.88, with the following individuals added to the list of +Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +Some files in the "scripts" directory have other copyright owners, +but are released under this license. + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing +Authors and Group 42, Inc. disclaim all warranties, expressed or +implied, including, without limitation, the warranties of +merchantability and of fitness for any purpose. The Contributing +Authors and Group 42, Inc. assume no liability for direct, indirect, +incidental, special, exemplary, or consequential damages, which may +result from the use of the PNG Reference Library, even if advised of +the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + + 1. The origin of this source code must not be misrepresented. + + 2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, +without fee, and encourage the use of this source code as a component +to supporting the PNG file format in commercial products. If you use +this source code in a product, acknowledgment is not required but would +be appreciated. diff --git a/widget/milsko/milskosrc/external/libpng/README b/widget/milsko/milskosrc/external/libpng/README new file mode 100644 index 0000000000..2eb633ac0f --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/README @@ -0,0 +1,184 @@ +README for libpng version 1.6.50 +================================ + +See the note about version numbers near the top of `png.h`. +See `INSTALL` for instructions on how to install libpng. + +Libpng comes in several distribution formats. Get `libpng-*.tar.gz` +or `libpng-*.tar.xz` if you want UNIX-style line endings in the text +files, or `lpng*.7z` or `lpng*.zip` if you want DOS-style line endings. + +For a detailed description on using libpng, read `libpng-manual.txt`. +For examples of libpng in a program, see `example.c` and `pngtest.c`. +For usage information and restrictions (what little they are) on libpng, +see `png.h`. For a description on using zlib (the compression library +used by libpng) and zlib's restrictions, see `zlib.h`. + +You should use zlib 1.0.4 or later to run this, but it _may_ work with +versions as old as zlib 0.95. Even so, there are bugs in older zlib +versions which can cause the output of invalid compression streams for +some images. + +You should also note that zlib is a compression library that is useful +for more things than just PNG files. You can use zlib as a drop-in +replacement for `fread()` and `fwrite()`, if you are so inclined. + +zlib should be available at the same place that libpng is, or at +https://zlib.net . + +You may also want a copy of the PNG specification. It is available +as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find +these at http://www.libpng.org/pub/png/pngdocs.html . + +This code is currently being archived at https://libpng.sourceforge.io +in the download area, and at http://libpng.download/src . + +This release, based in a large way on Glenn's, Guy's and Andreas' +earlier work, was created and will be supported by myself and the PNG +development group. + +Send comments, corrections and commendations to `png-mng-implement` +at `lists.sourceforge.net`. (Subscription is required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe.) + +Send general questions about the PNG specification to `png-mng-misc` +at `lists.sourceforge.net`. (Subscription is required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-misc +to subscribe.) + +Historical notes +---------------- + +The libpng library has been in extensive use and testing since mid-1995. +Version 0.89, published a year later, was the first official release. +By late 1997, it had finally gotten to the stage where there hadn't +been significant changes to the API in some time, and people have a bad +feeling about libraries with versions below 1.0. Version 1.0.0 was +released in March 1998. + +Note that some of the changes to the `png_info` structure render this +version of the library binary incompatible with libpng-0.89 or +earlier versions if you are using a shared library. The type of the +`filler` parameter for `png_set_filler()` has changed from `png_byte` +to `png_uint_32`, which will affect shared-library applications that +use this function. + +To avoid problems with changes to the internals of the `info_struct`, +new APIs have been made available in 0.95 to avoid direct application +access to `info_ptr`. These functions are the `png_set_` and +`png_get_` functions. These functions should be used when +accessing/storing the `info_struct` data, rather than manipulating it +directly, to avoid such problems in the future. + +It is important to note that the APIs did not make current programs +that access the info struct directly incompatible with the new +library, through libpng-1.2.x. In libpng-1.4.x, which was meant to +be a transitional release, members of the `png_struct` and the +`info_struct` can still be accessed, but the compiler will issue a +warning about deprecated usage. Since libpng-1.5.0, direct access +to these structs is not allowed, and the definitions of the structs +reside in private `pngstruct.h` and `pnginfo.h` header files that are +not accessible to applications. It is strongly suggested that new +programs use the new APIs (as shown in `example.c` and `pngtest.c`), +and older programs be converted to the new format, to facilitate +upgrades in the future. + +The additions since 0.89 include the ability to read from a PNG stream +which has had some (or all) of the signature bytes read by the calling +application. This also allows the reading of embedded PNG streams that +do not have the PNG file signature. As well, it is now possible to set +the library action on the detection of chunk CRC errors. It is possible +to set different actions based on whether the CRC error occurred in a +critical or an ancillary chunk. + +The additions since 0.90 include the ability to compile libpng as a +Windows DLL, and new APIs for accessing data in the `info_struct`. +Experimental functions included the ability to set weighting and cost +factors for row filter selection, direct reads of integers from buffers +on big-endian processors that support misaligned data access, faster +methods of doing alpha composition, and more accurate 16-to-8 bit color +conversion. Some of these experimental functions, such as the weighted +filter heuristics, have since been removed. + +Files included in this distribution +----------------------------------- + + ANNOUNCE => Announcement of this version, with recent changes + AUTHORS => List of contributing authors + CHANGES => Description of changes between libpng versions + INSTALL => Instructions to install libpng + LICENSE => License to use and redistribute libpng + README => This file + TODO => Things not implemented in the current library + TRADEMARK => Trademark information + example.c => Example code for using libpng functions + libpng.3 => Manual page for libpng (includes libpng-manual.txt) + libpng-manual.txt => Description of libpng and its functions + libpngpf.3 => Manual page for libpng's private functions (deprecated) + png.5 => Manual page for the PNG format + png.c => Basic interface functions common to library + png.h => Library function and interface declarations (public) + pngpriv.h => Library function and interface declarations (private) + pngconf.h => System specific library configuration (public) + pngstruct.h => png_struct declaration (private) + pnginfo.h => png_info struct declaration (private) + pngdebug.h => debugging macros (private) + pngerror.c => Error/warning message I/O functions + pngget.c => Functions for retrieving info from struct + pngmem.c => Memory handling functions + pngbar.png => PNG logo, 88x31 + pngnow.png => PNG logo, 98x31 + pngpread.c => Progressive reading functions + pngread.c => Read data/helper high-level functions + pngrio.c => Lowest-level data read I/O functions + pngrtran.c => Read data transformation functions + pngrutil.c => Read data utility functions + pngset.c => Functions for storing data into the info_struct + pngtest.c => Library test program + pngtest.png => Library test sample image + pngtrans.c => Common data transformation functions + pngwio.c => Lowest-level write I/O functions + pngwrite.c => High-level write functions + pngwtran.c => Write data transformations + pngwutil.c => Write utility functions + arm/ => Optimized code for ARM Neon + intel/ => Optimized code for INTEL SSE2 + loongarch/ => Optimized code for LoongArch LSX + mips/ => Optimized code for MIPS MSA and MIPS MMI + powerpc/ => Optimized code for PowerPC VSX + riscv/ => Optimized code for the RISC-V platform + ci/ => Scripts for continuous integration + contrib/ => External contributions + arm-neon/ => Optimized code for the ARM-NEON platform + mips-msa/ => Optimized code for the MIPS-MSA platform + powerpc-vsx/ => Optimized code for the POWERPC-VSX platform + examples/ => Examples of libpng usage + gregbook/ => Source code for PNG reading and writing, from + "PNG: The Definitive Guide" by Greg Roelofs, + O'Reilly, 1999 + libtests/ => Test programs + pngexif/ => Program to inspect the EXIF information in PNG files + pngminim/ => Minimal decoder, encoder, and progressive decoder + programs demonstrating the use of pngusr.dfa + pngminus/ => Simple pnm2png and png2pnm programs + pngsuite/ => Test images + riscv-rvv/ => Optimized code for the RISC-V Vector platform + testpngs/ => Test images + tools/ => Various tools + visupng/ => VisualPng, a Windows viewer for PNG images + projects/ => Project files and workspaces for various IDEs + owatcom/ => OpenWatcom project + visualc71/ => Microsoft Visual C++ 7.1 workspace + vstudio/ => Microsoft Visual Studio workspace + scripts/ => Scripts and makefiles for building libpng + (see scripts/README.txt for the complete list) + tests/ => Test scripts + +Good luck, and happy coding! + + * Cosmin Truta (current maintainer, since 2018) + * Glenn Randers-Pehrson (former maintainer, 1998-2018) + * Andreas Eric Dilger (former maintainer, 1996-1997) + * Guy Eric Schalnat (original author and former maintainer, 1995-1996) + (formerly of Group 42, Inc.) diff --git a/widget/milsko/milskosrc/external/libpng/include/config.h b/widget/milsko/milskosrc/external/libpng/include/config.h new file mode 100644 index 0000000000..ff2e3aad41 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/include/config.h @@ -0,0 +1,138 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the 'feenableexcept' function. */ +#undef HAVE_FEENABLEEXCEPT + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the 'm' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the 'z' library (-lz). */ +#undef HAVE_LIBZ + +/* Define to 1 if you have the 'pow' function. */ +#undef HAVE_POW + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Turn on ARM Neon optimizations at run-time */ +#undef PNG_ARM_NEON_API_SUPPORTED + +/* Check for ARM Neon support at run-time */ +#undef PNG_ARM_NEON_CHECK_SUPPORTED + +/* Enable ARM Neon optimizations */ +#undef PNG_ARM_NEON_OPT + +/* Enable Intel SSE optimizations */ +#undef PNG_INTEL_SSE_OPT + +/* Enable LOONGARCH LSX optimizations */ +#undef PNG_LOONGARCH_LSX_OPT + +/* Turn on MIPS MMI optimizations at run-time */ +#undef PNG_MIPS_MMI_API_SUPPORTED + +/* Check for MIPS MMI support at run-time */ +#undef PNG_MIPS_MMI_CHECK_SUPPORTED + +/* Enable MIPS MMI optimizations */ +#undef PNG_MIPS_MMI_OPT + +/* Turn on MIPS MSA optimizations at run-time */ +#undef PNG_MIPS_MSA_API_SUPPORTED + +/* Check for MIPS MSA support at run-time */ +#undef PNG_MIPS_MSA_CHECK_SUPPORTED + +/* Enable MIPS MSA optimizations */ +#undef PNG_MIPS_MSA_OPT + +/* Turn on POWERPC VSX optimizations at run-time */ +#undef PNG_POWERPC_VSX_API_SUPPORTED + +/* Check for POWERPC VSX support at run-time */ +#undef PNG_POWERPC_VSX_CHECK_SUPPORTED + +/* Enable POWERPC VSX optimizations */ +#undef PNG_POWERPC_VSX_OPT + +/* Enable RISCV RVV optimizations */ +#undef PNG_RISCV_RVV_OPT + +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#undef STDC_HEADERS + +/* Define to 1 if your declares 'struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported only directly. */ +#undef restrict +/* Work around a bug in older versions of Sun C++, which did not + #define __restrict__ or support _Restrict or __restrict__ + even though the corresponding Sun C compiler ended up with + "#define restrict _Restrict" or "#define restrict __restrict__" + in the previous line. This workaround can be removed once + we assume Oracle Developer Studio 12.5 (2016) or later. */ +#if defined __SUNPRO_CC && !defined __RESTRICT && !defined __restrict__ +# define _Restrict +# define __restrict__ +#endif diff --git a/widget/milsko/milskosrc/external/libpng/include/png.h b/widget/milsko/milskosrc/external/libpng/include/png.h new file mode 100644 index 0000000000..b9985e8168 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/include/png.h @@ -0,0 +1,3377 @@ +/* png.h - header file for PNG reference library + * + * libpng version 1.6.50 + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. (See LICENSE, below.) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.6.35, July 2018: + * Glenn Randers-Pehrson + * libpng versions 1.6.36, December 2018, through 1.6.50, July 2025: + * Cosmin Truta + * See also "Contributing Authors", below. + */ + +/* + * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE + * ========================================= + * + * PNG Reference Library License version 2 + * --------------------------------------- + * + * * Copyright (c) 1995-2025 The PNG Reference Library Authors. + * * Copyright (c) 2018-2025 Cosmin Truta. + * * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. + * * Copyright (c) 1996-1997 Andreas Dilger. + * * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * The software is supplied "as is", without warranty of any kind, + * express or implied, including, without limitation, the warranties + * of merchantability, fitness for a particular purpose, title, and + * non-infringement. In no event shall the Copyright owners, or + * anyone distributing the software, be liable for any damages or + * other liability, whether in contract, tort or otherwise, arising + * from, out of, or in connection with the software, or the use or + * other dealings in the software, even if advised of the possibility + * of such damage. + * + * Permission is hereby granted to use, copy, modify, and distribute + * this software, or portions hereof, for any purpose, without fee, + * subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you + * use this software in a product, an acknowledgment in the product + * documentation would be appreciated, but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * + * 3. This Copyright notice may not be removed or altered from any + * source or altered source distribution. + * + * + * PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) + * ----------------------------------------------------------------------- + * + * libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are + * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are + * derived from libpng-1.0.6, and are distributed according to the same + * disclaimer and license as libpng-1.0.6 with the following individuals + * added to the list of Contributing Authors: + * + * Simon-Pierre Cadieux + * Eric S. Raymond + * Mans Rullgard + * Cosmin Truta + * Gilles Vollant + * James Yu + * Mandar Sahastrabuddhe + * Google Inc. + * Vadim Barkov + * + * and with the following additions to the disclaimer: + * + * There is no warranty against interference with your enjoyment of + * the library or against infringement. There is no warranty that our + * efforts or the library will fulfill any of your particular purposes + * or needs. This library is provided with all faults, and the entire + * risk of satisfactory quality, performance, accuracy, and effort is + * with the user. + * + * Some files in the "contrib" directory and some configure-generated + * files that are distributed with libpng have other copyright owners, and + * are released under other open source licenses. + * + * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are + * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from + * libpng-0.96, and are distributed according to the same disclaimer and + * license as libpng-0.96, with the following individuals added to the + * list of Contributing Authors: + * + * Tom Lane + * Glenn Randers-Pehrson + * Willem van Schaik + * + * libpng versions 0.89, June 1996, through 0.96, May 1997, are + * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, + * and are distributed according to the same disclaimer and license as + * libpng-0.88, with the following individuals added to the list of + * Contributing Authors: + * + * John Bowler + * Kevin Bracey + * Sam Bushell + * Magnus Holmgren + * Greg Roelofs + * Tom Tanner + * + * Some files in the "scripts" directory have other copyright owners, + * but are released under this license. + * + * libpng versions 0.5, May 1995, through 0.88, January 1996, are + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * For the purposes of this copyright and license, "Contributing Authors" + * is defined as the following set of individuals: + * + * Andreas Dilger + * Dave Martindale + * Guy Eric Schalnat + * Paul Schmidt + * Tim Wegner + * + * The PNG Reference Library is supplied "AS IS". The Contributing + * Authors and Group 42, Inc. disclaim all warranties, expressed or + * implied, including, without limitation, the warranties of + * merchantability and of fitness for any purpose. The Contributing + * Authors and Group 42, Inc. assume no liability for direct, indirect, + * incidental, special, exemplary, or consequential damages, which may + * result from the use of the PNG Reference Library, even if advised of + * the possibility of such damage. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * source code, or portions hereof, for any purpose, without fee, subject + * to the following restrictions: + * + * 1. The origin of this source code must not be misrepresented. + * + * 2. Altered versions must be plainly marked as such and must not + * be misrepresented as being the original source. + * + * 3. This Copyright notice may not be removed or altered from any + * source or altered source distribution. + * + * The Contributing Authors and Group 42, Inc. specifically permit, + * without fee, and encourage the use of this source code as a component + * to supporting the PNG file format in commercial products. If you use + * this source code in a product, acknowledgment is not required but would + * be appreciated. + * + * END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. + * + * TRADEMARK + * ========= + * + * The name "libpng" has not been registered by the Copyright owners + * as a trademark in any jurisdiction. However, because libpng has + * been distributed and maintained world-wide, continually since 1995, + * the Copyright owners claim "common-law trademark protection" in any + * jurisdiction where common-law trademark is recognized. + */ + +/* + * A "png_get_copyright" function is available, for convenient use in "about" + * boxes and the like: + * + * printf("%s", png_get_copyright(NULL)); + * + * Also, the PNG logo (in PNG format, of course) is supplied in the + * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + */ + +/* + * The contributing authors would like to thank all those who helped + * with testing, bug fixes, and patience. This wouldn't have been + * possible without all of you. + * + * Thanks to Frank J. T. Wojcik for helping with the documentation. + */ + +/* Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * ... + * 1.0.69 10 10069 10.so.0.69[.0] + * ... + * 1.2.59 13 10259 12.so.0.59[.0] + * ... + * 1.4.20 14 10420 14.so.0.20[.0] + * ... + * 1.5.30 15 10530 15.so.15.30[.0] + * ... + * 1.6.50 16 10650 16.so.16.50[.0] + * + * Henceforth the source version will match the shared-library major and + * minor numbers; the shared-library major version number will be used for + * changes in backward compatibility, as it is intended. + * The PNG_LIBPNG_VER macro, which is not used within libpng but is + * available for applications, is an unsigned integer of the form XYYZZ + * corresponding to the source version X.Y.Z (leading zeros in Y and Z). + * Beta versions were given the previous public release number plus a + * letter, until version 1.0.6j; from then on they were given the upcoming + * public release number plus "betaNN" or "rcNN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * See libpng.txt or libpng.3 for more information. The PNG specification + * is available as a W3C Recommendation and as an ISO/IEC Standard; see + * + */ + +#ifndef PNG_H +#define PNG_H + +/* This is not the place to learn how to use libpng. The file libpng-manual.txt + * describes how to use libpng, and the file example.c summarizes it + * with some code on which to build. This file is useful for looking + * at the actual function definitions and structure components. If that + * file has been stripped from your copy of libpng, you can find it at + * + * + * If you just need to read a PNG file and don't want to read the documentation + * skip to the end of this file and read the section entitled 'simplified API'. + */ + +/* Version information for png.h - this should match the version in png.c */ +#define PNG_LIBPNG_VER_STRING "1.6.50" +#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n" + +/* The versions of shared library builds should stay in sync, going forward */ +#define PNG_LIBPNG_VER_SHAREDLIB 16 +#define PNG_LIBPNG_VER_SONUM PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */ +#define PNG_LIBPNG_VER_DLLNUM PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */ + +/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ +#define PNG_LIBPNG_VER_MAJOR 1 +#define PNG_LIBPNG_VER_MINOR 6 +#define PNG_LIBPNG_VER_RELEASE 50 + +/* This should be zero for a public release, or non-zero for a + * development version. + */ +#define PNG_LIBPNG_VER_BUILD 0 + +/* Release Status */ +#define PNG_LIBPNG_BUILD_ALPHA 1 +#define PNG_LIBPNG_BUILD_BETA 2 +#define PNG_LIBPNG_BUILD_RC 3 +#define PNG_LIBPNG_BUILD_STABLE 4 +#define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7 + +/* Release-Specific Flags */ +#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with + PNG_LIBPNG_BUILD_STABLE only */ +#define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with + PNG_LIBPNG_BUILD_SPECIAL */ +#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with + PNG_LIBPNG_BUILD_PRIVATE */ + +#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE + +/* Careful here. At one time, Guy wanted to use 082, but that + * would be octal. We must not include leading zeros. + * Versions 0.7 through 1.0.0 were in the range 0 to 100 here + * (only version 1.0.0 was mis-numbered 100 instead of 10000). + * From version 1.0.1 it is: + * XXYYZZ, where XX=major, YY=minor, ZZ=release + */ +#define PNG_LIBPNG_VER 10650 /* 1.6.50 */ + +/* Library configuration: these options cannot be changed after + * the library has been built. + */ +#ifndef PNGLCONF_H +/* If pnglibconf.h is missing, you can + * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h + */ +# include "pnglibconf.h" +#endif + +#ifndef PNG_VERSION_INFO_ONLY +/* Machine specific configuration. */ +# include "pngconf.h" +#endif + +/* + * Added at libpng-1.2.8 + * + * Ref MSDN: Private as priority over Special + * VS_FF_PRIVATEBUILD File *was not* built using standard release + * procedures. If this value is given, the StringFileInfo block must + * contain a PrivateBuild string. + * + * VS_FF_SPECIALBUILD File *was* built by the original company using + * standard release procedures but is a variation of the standard + * file of the same version number. If this value is given, the + * StringFileInfo block must contain a SpecialBuild string. + */ + +#ifdef PNG_USER_PRIVATEBUILD /* From pnglibconf.h */ +# define PNG_LIBPNG_BUILD_TYPE \ + (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE) +#else +# ifdef PNG_LIBPNG_SPECIALBUILD +# define PNG_LIBPNG_BUILD_TYPE \ + (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL) +# else +# define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE) +# endif +#endif + +#ifndef PNG_VERSION_INFO_ONLY + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Version information for C files, stored in png.c. This had better match + * the version above. + */ +#define png_libpng_ver png_get_header_ver(NULL) + +/* This file is arranged in several sections: + * + * 1. [omitted] + * 2. Any configuration options that can be specified by for the application + * code when it is built. (Build time configuration is in pnglibconf.h) + * 3. Type definitions (base types are defined in pngconf.h), structure + * definitions. + * 4. Exported library functions. + * 5. Simplified API. + * 6. Implementation options. + * + * The library source code has additional files (principally pngpriv.h) that + * allow configuration of the library. + */ + +/* Section 1: [omitted] */ + +/* Section 2: run time configuration + * See pnglibconf.h for build time configuration + * + * Run time configuration allows the application to choose between + * implementations of certain arithmetic APIs. The default is set + * at build time and recorded in pnglibconf.h, but it is safe to + * override these (and only these) settings. Note that this won't + * change what the library does, only application code, and the + * settings can (and probably should) be made on a per-file basis + * by setting the #defines before including png.h + * + * Use macros to read integers from PNG data or use the exported + * functions? + * PNG_USE_READ_MACROS: use the macros (see below) Note that + * the macros evaluate their argument multiple times. + * PNG_NO_USE_READ_MACROS: call the relevant library function. + * + * Use the alternative algorithm for compositing alpha samples that + * does not use division? + * PNG_READ_COMPOSITE_NODIV_SUPPORTED: use the 'no division' + * algorithm. + * PNG_NO_READ_COMPOSITE_NODIV: use the 'division' algorithm. + * + * How to handle benign errors if PNG_ALLOW_BENIGN_ERRORS is + * false? + * PNG_ALLOW_BENIGN_ERRORS: map calls to the benign error + * APIs to png_warning. + * Otherwise the calls are mapped to png_error. + */ + +/* Section 3: type definitions, including structures and compile time + * constants. + * See pngconf.h for base types that vary by machine/system + */ + +/* This triggers a compiler error in png.c, if png.c and png.h + * do not agree upon the version number. + */ +typedef char* png_libpng_version_1_6_50; + +/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. + * + * png_struct is the cache of information used while reading or writing a single + * PNG file. One of these is always required, although the simplified API + * (below) hides the creation and destruction of it. + */ +typedef struct png_struct_def png_struct; +typedef const png_struct * png_const_structp; +typedef png_struct * png_structp; +typedef png_struct * * png_structpp; + +/* png_info contains information read from or to be written to a PNG file. One + * or more of these must exist while reading or creating a PNG file. The + * information is not used by libpng during read but is used to control what + * gets written when a PNG file is created. "png_get_" function calls read + * information during read and "png_set_" functions calls write information + * when creating a PNG. + * been moved into a separate header file that is not accessible to + * applications. Read libpng-manual.txt or libpng.3 for more info. + */ +typedef struct png_info_def png_info; +typedef png_info * png_infop; +typedef const png_info * png_const_infop; +typedef png_info * * png_infopp; + +/* Types with names ending 'p' are pointer types. The corresponding types with + * names ending 'rp' are identical pointer types except that the pointer is + * marked 'restrict', which means that it is the only pointer to the object + * passed to the function. Applications should not use the 'restrict' types; + * it is always valid to pass 'p' to a pointer with a function argument of the + * corresponding 'rp' type. Different compilers have different rules with + * regard to type matching in the presence of 'restrict'. For backward + * compatibility libpng callbacks never have 'restrict' in their parameters and, + * consequentially, writing portable application code is extremely difficult if + * an attempt is made to use 'restrict'. + */ +typedef png_struct * PNG_RESTRICT png_structrp; +typedef const png_struct * PNG_RESTRICT png_const_structrp; +typedef png_info * PNG_RESTRICT png_inforp; +typedef const png_info * PNG_RESTRICT png_const_inforp; + +/* Three color definitions. The order of the red, green, and blue, (and the + * exact size) is not important, although the size of the fields need to + * be png_byte or png_uint_16 (as defined below). + */ +typedef struct png_color_struct +{ + png_byte red; + png_byte green; + png_byte blue; +} png_color; +typedef png_color * png_colorp; +typedef const png_color * png_const_colorp; +typedef png_color * * png_colorpp; + +typedef struct png_color_16_struct +{ + png_byte index; /* used for palette files */ + png_uint_16 red; /* for use in red green blue files */ + png_uint_16 green; + png_uint_16 blue; + png_uint_16 gray; /* for use in grayscale files */ +} png_color_16; +typedef png_color_16 * png_color_16p; +typedef const png_color_16 * png_const_color_16p; +typedef png_color_16 * * png_color_16pp; + +typedef struct png_color_8_struct +{ + png_byte red; /* for use in red green blue files */ + png_byte green; + png_byte blue; + png_byte gray; /* for use in grayscale files */ + png_byte alpha; /* for alpha channel files */ +} png_color_8; +typedef png_color_8 * png_color_8p; +typedef const png_color_8 * png_const_color_8p; +typedef png_color_8 * * png_color_8pp; + +/* + * The following two structures are used for the in-core representation + * of sPLT chunks. + */ +typedef struct png_sPLT_entry_struct +{ + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + png_uint_16 alpha; + png_uint_16 frequency; +} png_sPLT_entry; +typedef png_sPLT_entry * png_sPLT_entryp; +typedef const png_sPLT_entry * png_const_sPLT_entryp; +typedef png_sPLT_entry * * png_sPLT_entrypp; + +/* When the depth of the sPLT palette is 8 bits, the color and alpha samples + * occupy the LSB of their respective members, and the MSB of each member + * is zero-filled. The frequency member always occupies the full 16 bits. + */ + +typedef struct png_sPLT_struct +{ + png_charp name; /* palette name */ + png_byte depth; /* depth of palette samples */ + png_sPLT_entryp entries; /* palette entries */ + png_int_32 nentries; /* number of palette entries */ +} png_sPLT_t; +typedef png_sPLT_t * png_sPLT_tp; +typedef const png_sPLT_t * png_const_sPLT_tp; +typedef png_sPLT_t * * png_sPLT_tpp; + +#ifdef PNG_TEXT_SUPPORTED +/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, + * and whether that contents is compressed or not. The "key" field + * points to a regular zero-terminated C string. The "text" fields can be a + * regular C string, an empty string, or a NULL pointer. + * However, the structure returned by png_get_text() will always contain + * the "text" field as a regular zero-terminated C string (possibly + * empty), never a NULL pointer, so it can be safely used in printf() and + * other string-handling functions. Note that the "itxt_length", "lang", and + * "lang_key" members of the structure only exist when the library is built + * with iTXt chunk support. Prior to libpng-1.4.0 the library was built by + * default without iTXt support. Also note that when iTXt *is* supported, + * the "lang" and "lang_key" fields contain NULL pointers when the + * "compression" field contains * PNG_TEXT_COMPRESSION_NONE or + * PNG_TEXT_COMPRESSION_zTXt. Note that the "compression value" is not the + * same as what appears in the PNG tEXt/zTXt/iTXt chunk's "compression flag" + * which is always 0 or 1, or its "compression method" which is always 0. + */ +typedef struct png_text_struct +{ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ + png_charp key; /* keyword, 1-79 character description of "text" */ + png_charp text; /* comment, may be an empty string (ie "") + or a NULL pointer */ + size_t text_length; /* length of the text string */ + size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 0-79 characters + or a NULL pointer */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars or a NULL pointer */ +} png_text; +typedef png_text * png_textp; +typedef const png_text * png_const_textp; +typedef png_text * * png_textpp; +#endif + +/* Supported compression types for text in PNG files (tEXt, and zTXt). + * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */ +#define PNG_TEXT_COMPRESSION_NONE_WR -3 +#define PNG_TEXT_COMPRESSION_zTXt_WR -2 +#define PNG_TEXT_COMPRESSION_NONE -1 +#define PNG_TEXT_COMPRESSION_zTXt 0 +#define PNG_ITXT_COMPRESSION_NONE 1 +#define PNG_ITXT_COMPRESSION_zTXt 2 +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ + +/* png_time is a way to hold the time in an machine independent way. + * Two conversions are provided, both from time_t and struct tm. There + * is no portable way to convert to either of these structures, as far + * as I know. If you know of a portable way, send it to me. As a side + * note - PNG has always been Year 2000 compliant! + */ +typedef struct png_time_struct +{ + png_uint_16 year; /* full year, as in, 1995 */ + png_byte month; /* month of year, 1 - 12 */ + png_byte day; /* day of month, 1 - 31 */ + png_byte hour; /* hour of day, 0 - 23 */ + png_byte minute; /* minute of hour, 0 - 59 */ + png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ +} png_time; +typedef png_time * png_timep; +typedef const png_time * png_const_timep; +typedef png_time * * png_timepp; + +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_USER_CHUNKS_SUPPORTED) +/* png_unknown_chunk is a structure to hold queued chunks for which there is + * no specific support. The idea is that we can use this to queue + * up private chunks for output even though the library doesn't actually + * know about their semantics. + * + * The data in the structure is set by libpng on read and used on write. + */ +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; /* Textual chunk name with '\0' terminator */ + png_byte *data; /* Data, should not be modified on read! */ + size_t size; + + /* On write 'location' must be set using the flag values listed below. + * Notice that on read it is set by libpng however the values stored have + * more bits set than are listed below. Always treat the value as a + * bitmask. On write set only one bit - setting multiple bits may cause the + * chunk to be written in multiple places. + */ + png_byte location; /* mode of operation at read time */ +} +png_unknown_chunk; + +typedef png_unknown_chunk * png_unknown_chunkp; +typedef const png_unknown_chunk * png_const_unknown_chunkp; +typedef png_unknown_chunk * * png_unknown_chunkpp; +#endif + +/* Flag values for the unknown chunk location byte. */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_AFTER_IDAT 0x08 + +/* Maximum positive integer used in PNG is (2^31)-1 */ +#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) +#define PNG_UINT_32_MAX ((png_uint_32)(-1)) +#define PNG_SIZE_MAX ((size_t)(-1)) + +/* These are constants for fixed point values encoded in the + * PNG specification manner (x100000) + */ +#define PNG_FP_1 100000 +#define PNG_FP_HALF 50000 +#define PNG_FP_MAX ((png_fixed_point)0x7fffffffL) +#define PNG_FP_MIN (-PNG_FP_MAX) + +/* These describe the color_type field in png_info. */ +/* color type masks */ +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +/* color types. Note that not all combinations are legal */ +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) +/* aliases */ +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA +#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA + +/* This is for compression type. PNG 1.0-1.2 only define the single type. */ +#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ +#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE + +/* This is for filter type. PNG 1.0-1.2 only define the single type. */ +#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ +#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ +#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE + +/* These are for the interlacing type. These values should NOT be changed. */ +#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ +#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ +#define PNG_INTERLACE_LAST 2 /* Not a valid value */ + +/* These are for the oFFs chunk. These values should NOT be changed. */ +#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ +#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ +#define PNG_OFFSET_LAST 2 /* Not a valid value */ + +/* These are for the pCAL chunk. These values should NOT be changed. */ +#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ +#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ +#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ +#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ +#define PNG_EQUATION_LAST 4 /* Not a valid value */ + +/* These are for the sCAL chunk. These values should NOT be changed. */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ + +/* These are for the pHYs chunk. These values should NOT be changed. */ +#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ +#define PNG_RESOLUTION_METER 1 /* pixels/meter */ +#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ + +/* These are for the sRGB chunk. These values should NOT be changed. */ +#define PNG_sRGB_INTENT_PERCEPTUAL 0 +#define PNG_sRGB_INTENT_RELATIVE 1 +#define PNG_sRGB_INTENT_SATURATION 2 +#define PNG_sRGB_INTENT_ABSOLUTE 3 +#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ + +/* This is for text chunks */ +#define PNG_KEYWORD_MAX_LENGTH 79 + +/* Maximum number of entries in PLTE/sPLT/tRNS arrays */ +#define PNG_MAX_PALETTE_LENGTH 256 + +/* These determine if an ancillary chunk's data has been successfully read + * from the PNG header, or if the application has filled in the corresponding + * data in the info_struct to be written into the output file. The values + * of the PNG_INFO_ defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001U +#define PNG_INFO_sBIT 0x0002U +#define PNG_INFO_cHRM 0x0004U +#define PNG_INFO_PLTE 0x0008U +#define PNG_INFO_tRNS 0x0010U +#define PNG_INFO_bKGD 0x0020U +#define PNG_INFO_hIST 0x0040U +#define PNG_INFO_pHYs 0x0080U +#define PNG_INFO_oFFs 0x0100U +#define PNG_INFO_tIME 0x0200U +#define PNG_INFO_pCAL 0x0400U +#define PNG_INFO_sRGB 0x0800U /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000U /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000U /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */ +#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */ +#define PNG_INFO_cICP 0x20000U /* PNGv3: 1.6.45 */ +#define PNG_INFO_cLLI 0x40000U /* PNGv3: 1.6.45 */ +#define PNG_INFO_mDCV 0x80000U /* PNGv3: 1.6.45 */ +/* APNG: these chunks are stored as unknown, these flags are never set + * however they are provided as a convenience for implementors of APNG and + * avoids any merge conflicts. + * + * Private chunks: these chunk names violate the chunk name recommendations + * because the chunk definitions have no signature and because the private + * chunks with these names have been reserved. Private definitions should + * avoid them. + */ +#define PNG_INFO_acTL 0x100000U /* PNGv3: 1.6.45: unknown */ +#define PNG_INFO_fcTL 0x200000U /* PNGv3: 1.6.45: unknown */ +#define PNG_INFO_fdAT 0x400000U /* PNGv3: 1.6.45: unknown */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + size_t rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info * png_row_infop; +typedef png_row_info * * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. Note that the 'write' function must not + * modify the buffer it is passed. The 'read' function, on the other hand, is + * expected to return the read data in the buffer. + */ +typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); +typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, size_t)); +typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); +typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, + int)); +typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); +typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); + +/* The following callback receives png_uint_32 row_number, int pass for the + * png_bytep data of the row. When transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, + png_bytep)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, + png_unknown_chunkp)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +/* not used anywhere */ +/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */ +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This must match the function definition in , and the application + * must include this before png.h to obtain the definition of jmp_buf. The + * function is required to be PNG_NORETURN, but this is not checked. If the + * function does return the application will crash via an abort() or similar + * system level call. + * + * If you get a warning here while building the library you may need to make + * changes to ensure that pnglibconf.h records the calling convention used by + * your compiler. This may be very difficult - try using a different compiler + * to build the library! + */ +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), (jmp_buf, int), typedef); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */ +/* Added to libpng-1.2.34 */ +#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER +#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ +/* Added to libpng-1.4.0 */ +#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ +/* Added to libpng-1.5.4 */ +#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ +#if ~0U > 0xffffU /* or else this might break on a 16-bit machine */ +#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ +#endif + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +/* NOTE: prior to 1.5 these functions had no 'API' style declaration, + * this allowed the zlib default functions to be used on Windows + * platforms. In 1.5 the zlib default malloc (which just calls malloc and + * ignores the first argument) should be completely compatible with the + * following. + */ +typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, + png_alloc_size_t)); +typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); + +/* Section 4: exported functions + * Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng-manual.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + * + * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in + * pngconf.h and in the *.dfn files in the scripts directory. + * + * PNG_EXPORT(ordinal, type, name, (args)); + * + * ordinal: ordinal that is used while building + * *.def files. The ordinal value is only + * relevant when preprocessing png.h with + * the *.dfn files for building symbol table + * entries, and are removed by pngconf.h. + * type: return type of the function + * name: function name + * args: function arguments, with types + * + * When we wish to append attributes to a function prototype we use + * the PNG_EXPORTA() macro instead. + * + * PNG_EXPORTA(ordinal, type, name, (args), attributes); + * + * ordinal, type, name, and args: same as in PNG_EXPORT(). + * attributes: function attributes + */ + +/* Returns the version number of the library */ +PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (i.e. return non-zero). + */ +PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, size_t start, + size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := (png_sig_cmp(sig, 0, n) == 0). + */ +#define png_check_sig(sig, n) (png_sig_cmp((sig), 0, (n)) == 0) /* DEPRECATED */ + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +PNG_EXPORTA(4, png_structp, png_create_read_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn), + PNG_ALLOCATED); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +PNG_EXPORTA(5, png_structp, png_create_write_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn), + PNG_ALLOCATED); + +PNG_EXPORT(6, size_t, png_get_compression_buffer_size, + (png_const_structrp png_ptr)); + +PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, + size_t size)); + +/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp + * match up. + */ +#ifdef PNG_SETJMP_SUPPORTED +/* This function returns the jmp_buf built in to *png_ptr. It must be + * supplied with an appropriate 'longjmp' function to use on that jmp_buf + * unless the default error function is overridden in which case NULL is + * acceptable. The size of the jmp_buf is checked against the actual size + * allocated by the library - the call will return NULL on a mismatch + * indicating an ABI mismatch. + */ +PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, + png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); +# define png_jmpbuf(png_ptr) \ + (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) +#endif +/* This function should be used by libpng applications in place of + * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it + * will use it; otherwise it will call PNG_ABORT(). This function was + * added in libpng-1.5.0. + */ +PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), + PNG_NORETURN); + +#ifdef PNG_READ_SUPPORTED +/* Reset the compression stream */ +PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); +#endif + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(11, png_structp, png_create_read_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +PNG_EXPORTA(12, png_structp, png_create_write_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +#endif + +/* Write the PNG file signature. */ +PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep + chunk_name, png_const_bytep data, size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, + png_const_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, + png_const_bytep data, size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); + +/* Allocate and initialize the info structure */ +PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), + PNG_ALLOCATED); + +/* DEPRECATED: this function allowed init structures to be created using the + * default allocation method (typically malloc). Use is deprecated in 1.6.0 and + * the API will be removed in the future. + */ +PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, + size_t png_info_struct_size), PNG_DEPRECATED); + +/* Writes all the PNG information before the image. */ +PNG_EXPORT(20, void, png_write_info_before_PLTE, + (png_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(21, void, png_write_info, + (png_structrp png_ptr, png_const_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. */ +PNG_EXPORT(22, void, png_read_info, + (png_structrp png_ptr, png_inforp info_ptr)); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* Convert to a US string format: there is no localization support in this + * routine. The original implementation used a 29 character buffer in + * png_struct, this will be removed in future versions. + */ +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ +PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, + png_const_timep ptime),PNG_DEPRECATED); +#endif +PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], + png_const_timep ptime)); +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* Convert from a struct tm to png_time */ +PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, + const struct tm * ttime)); + +/* Convert from time_t to png_time. Uses gmtime() */ +PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); +#endif /* CONVERT_tIME */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); +PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); +PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); +PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion + * of a tRNS chunk if present. + */ +PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand the grayscale to 24-bit RGB if necessary. */ +PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB to grayscale. */ +#define PNG_ERROR_ACTION_NONE 1 +#define PNG_ERROR_ACTION_WARN 2 +#define PNG_ERROR_ACTION_ERROR 3 +#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ + +PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, + int error_action, double red, double green)) +PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green)) + +PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp + png_ptr)); +#endif + +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, + png_colorp palette)); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* How the alpha channel is interpreted - this affects how the color channels + * of a PNG file are returned to the calling application when an alpha channel, + * or a tRNS chunk in a palette file, is present. + * + * This has no effect on the way pixels are written into a PNG output + * datastream. The color samples in a PNG datastream are never premultiplied + * with the alpha samples. + * + * The default is to return data according to the PNG specification: the alpha + * channel is a linear measure of the contribution of the pixel to the + * corresponding composited pixel, and the color channels are unassociated + * (not premultiplied). The gamma encoded color channels must be scaled + * according to the contribution and to do this it is necessary to undo + * the encoding, scale the color values, perform the composition and re-encode + * the values. This is the 'PNG' mode. + * + * The alternative is to 'associate' the alpha with the color information by + * storing color channel values that have been scaled by the alpha. + * image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes + * (the latter being the two common names for associated alpha color channels). + * + * For the 'OPTIMIZED' mode, a pixel is treated as opaque only if the alpha + * value is equal to the maximum value. + * + * The final choice is to gamma encode the alpha channel as well. This is + * broken because, in practice, no implementation that uses this choice + * correctly undoes the encoding before handling alpha composition. Use this + * choice only if other serious errors in the software or hardware you use + * mandate it; the typical serious error is for dark halos to appear around + * opaque areas of the composited PNG image because of arithmetic overflow. + * + * The API function png_set_alpha_mode specifies which of these choices to use + * with an enumerated 'mode' value and the gamma of the required output: + */ +#define PNG_ALPHA_PNG 0 /* according to the PNG standard */ +#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ +#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ +#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ +#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ +#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ + +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, + double output_gamma)) +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, + int mode, png_fixed_point output_gamma)) +#endif + +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* The output_gamma value is a screen gamma in libpng terminology: it expresses + * how to decode the output values, not how they are encoded. + */ +#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ +#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ +#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ +#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ +#endif + +/* The following are examples of calls to png_set_alpha_mode to achieve the + * required overall gamma correction and, where necessary, alpha + * premultiplication. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * This is the default libpng handling of the alpha channel - it is not + * pre-multiplied into the color components. In addition the call states + * that the output is for a sRGB system and causes all PNG files without gAMA + * chunks to be assumed to be encoded using sRGB. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * In this case the output is assumed to be something like an sRGB conformant + * display preceded by a power-law lookup table of power 1.45. This is how + * early Mac systems behaved. + * + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + * This is the classic Jim Blinn approach and will work in academic + * environments where everything is done by the book. It has the shortcoming + * of assuming that input PNG data with no gamma information is linear - this + * is unlikely to be correct unless the PNG files where generated locally. + * Most of the time the output precision will be so low as to show + * significant banding in dark areas of the image. + * + * png_set_expand_16(pp); + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + * This is a somewhat more realistic Jim Blinn inspired approach. PNG files + * are assumed to have the sRGB encoding if not marked with a gamma value and + * the output is always 16 bits per component. This permits accurate scaling + * and processing of the data. If you know that your input PNG files were + * generated locally you might need to replace PNG_DEFAULT_sRGB with the + * correct value for your system. + * + * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + * If you just need to composite the PNG image onto an existing background + * and if you control the code that does this you can use the optimization + * setting. In this case you just copy completely opaque pixels to the + * output. For pixels that are not completely transparent (you just skip + * those) you do the composition math using png_composite or png_composite_16 + * below then encode the resultant 8-bit or 16-bit values to match the output + * encoding. + * + * Other cases + * If neither the PNG nor the standard linear encoding work for you because + * of the software or hardware you use then you have a big problem. The PNG + * case will probably result in halos around the image. The linear encoding + * will probably result in a washed out, too bright, image (it's actually too + * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably + * substantially reduce the halos. Alternatively try: + * + * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + * This option will also reduce the halos, but there will be slight dark + * halos round the opaque parts of the image where the background is light. + * In the OPTIMIZED mode the halos will be light halos where the background + * is dark. Take your pick - the halos are unavoidable unless you can get + * your hardware/software fixed! (The OPTIMIZED approach is slightly + * faster.) + * + * When the default gamma of PNG files doesn't match the output gamma. + * If you have PNG files with no gamma information png_set_alpha_mode allows + * you to provide a default gamma, but it also sets the output gamma to the + * matching value. If you know your PNG files have a gamma that doesn't + * match the output you can take advantage of the fact that + * png_set_alpha_mode always sets the output gamma but only sets the PNG + * default if it is not already set: + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * The first call sets both the default and the output gamma values, the + * second call overrides the output gamma without changing the default. This + * is easier than achieving the same effect with png_set_gamma. You must use + * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will + * fire if more than one call to png_set_alpha_mode and png_set_background is + * made in the same read operation, however multiple calls with PNG_ALPHA_PNG + * are ignored. + */ + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */ +PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler, + int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +# define PNG_FILLER_BEFORE 0 +# define PNG_FILLER_AFTER 1 +/* Add an alpha byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */ +PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, + png_uint_32 filler, int flags)); +#endif /* READ_FILLER || WRITE_FILLER */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p + true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. + * MUST be called before png_read_update_info or png_start_read_image, + * otherwise it will not have the desired effect. Note that it is still + * necessary to call png_read_row or png_read_rows png_get_image_height + * times for each pass. +*/ +PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS by replacing with a background color. Prior to + * libpng-1.5.4 this API must not be called before the PNG file header has been + * read. Doing so will result in unexpected behavior and possible warnings or + * errors if the PNG file contains a bKGD chunk. + */ +PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)) +PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma)) +#endif +#ifdef PNG_READ_BACKGROUND_SUPPORTED +# define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +# define PNG_BACKGROUND_GAMMA_SCREEN 1 +# define PNG_BACKGROUND_GAMMA_FILE 2 +# define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale a 16-bit depth file down to 8-bit, accurately. */ +PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_16_TO_8_SUPPORTED /* Name prior to 1.5.4 */ +/* Strip the second byte of information from a 16-bit depth file. */ +PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Turn on quantizing, and reduce the palette to the number of colors + * available. + */ +PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_const_uint_16p histogram, int full_quantize)); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The threshold on gamma processing is configurable but hard-wired into the + * library. The following is the floating point variant. + */ +#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) + +/* Handle gamma correction. Screen_gamma=(display_exponent). + * NOTE: this API simply sets the screen and file gamma values. It will + * therefore override the value for gamma in a PNG file if it is called after + * the file header has been read - use with care - call before reading the PNG + * file for best results! + * + * These routines accept the same gamma values as png_set_alpha_mode (described + * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either + * API (floating point or fixed.) Notice, however, that the 'file_gamma' value + * is the inverse of a 'screen gamma' value. + */ +PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, + double screen_gamma, double override_file_gamma)) +PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, + png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set how many lines between output flushes - 0 for no flushing */ +PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); +#endif + +/* Optional update palette with requested transformations */ +PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); + +/* Optional call to update the users info structure */ +PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, + png_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. */ +PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read a row of data. */ +PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, + png_bytep display_row)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the whole image into memory at once. */ +PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); +#endif + +/* Write a row of image data */ +PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, + png_const_bytep row)); + +/* Write a few rows of image data: (*row) is not written; however, the type + * is declared as writeable to maintain compatibility with previous versions + * of libpng and to allow the 'display_row' array from read_rows to be passed + * unchanged to write_rows. + */ +PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows)); + +/* Write the image data */ +PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); + +/* Write the end of the PNG file. */ +PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, + png_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. */ +PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); +#endif + +/* Free any memory associated with the png_info_struct */ +PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, + png_infopp info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr)); + +/* Set the libpng method of handling chunk CRC errors */ +PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, + int ancil_action)); + +/* Values for png_set_crc_action() say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +#ifdef PNG_WRITE_SUPPORTED +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explanation of the compression functions. + */ + +/* Set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, + int filters)); +#endif /* WRITE */ + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_FAST_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP) +#define PNG_ALL_FILTERS (PNG_FAST_FILTERS | PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ +PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, + int heuristic_method, int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs)) +PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, + (png_structrp png_ptr, int heuristic_method, int num_weights, + png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs)) +#endif /* WRITE_WEIGHTED_FILTER */ + +/* The following are no longer used and will be removed from libpng-1.7: */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer calculations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, + int window_bits)); + +PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, + int method)); +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ + +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +/* Also set zlib parameters for compressing non-IDAT chunks */ +PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(225, void, png_set_text_compression_window_bits, + (png_structrp png_ptr, int window_bits)); + +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, + int method)); +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +#endif /* WRITE */ + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng-manual.txt for + * more information. + */ + +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the input/output for the PNG file to the default functions. */ +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, FILE *fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + * It is probably a mistake to use NULL for output_flush_fn if + * write_data_fn is not also NULL unless you have built libpng with + * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's + * default flush function, which uses the standard *FILE structure, will + * be used. + */ +PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); + +PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, + png_read_status_ptr read_row_fn)); + +PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr read_user_transform_fn)); +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr write_user_transform_fn)); +#endif + +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr, + png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, + (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +/* Return information about the row currently being processed. Note that these + * APIs do not fail but will return unexpected results if called outside a user + * transform callback. Also note that when transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); +PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +/* This callback is called only for *unknown* chunks. If + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known + * chunks to be treated as unknown, however in this case the callback must do + * any processing required by the chunk (e.g. by calling the appropriate + * png_set_ APIs.) + * + * There is no write support - on write, by default, all the chunks in the + * 'unknown' list are written in the specified position. + * + * The integer return from the callback function is interpreted thus: + * + * negative: An error occurred; png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be saved. A critical + * chunk will cause an error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + * + * See "INTERACTION WITH USER CHUNK CALLBACKS" below for important notes about + * how this behavior will change in libpng 1.7 + */ +PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr, + png_voidp progressive_ptr, png_progressive_info_ptr info_fn, + png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); + +/* Returns the user pointer associated with the push read functions */ +PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, + (png_const_structrp png_ptr)); + +/* Function to be called when data becomes available */ +PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, + png_inforp info_ptr, png_bytep buffer, size_t buffer_size)); + +/* A function which may be called *only* within png_process_data to stop the + * processing of any more data. The function returns the number of bytes + * remaining, excluding any that libpng has cached internally. A subsequent + * call to png_process_data must supply these bytes again. If the argument + * 'save' is set to true the routine will first save all the pending data and + * will always return 0. + */ +PNG_EXPORT(219, size_t, png_process_data_pause, (png_structrp, int save)); + +/* A function which may be called *only* outside (after) a call to + * png_process_data. It returns the number of bytes of data to skip in the + * input. Normally it will return 0, but if it returns a non-zero value the + * application must skip than number of bytes of input data and pass the + * following data to the next call to png_process_data. + */ +PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); + +/* Function that combines rows. 'new_row' is a flag that should come from + * the callback and be non-NULL if anything needs to be done; the library + * stores its own version of the new data internally and ignores the passed + * in value. + */ +PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, + png_bytep old_row, png_const_bytep new_row)); +#endif /* PROGRESSIVE_READ */ + +PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); +/* Added at libpng version 1.4.0 */ +PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Added at libpng version 1.2.4 */ +PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Frees a pointer allocated by png_malloc() */ +PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); + +/* Free data that was allocated internally */ +PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 free_me, int num)); + +/* Reassign the responsibility for freeing existing data, whether allocated + * by libpng or by the application; this works on the png_info structure passed + * in, without changing the state for other png_info structures. + */ +PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr, + png_inforp info_ptr, int freer, png_uint_32 mask)); + +/* Assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008U +#define PNG_FREE_ICCP 0x0010U +#define PNG_FREE_SPLT 0x0020U +#define PNG_FREE_ROWS 0x0040U +#define PNG_FREE_PCAL 0x0080U +#define PNG_FREE_SCAL 0x0100U +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_FREE_UNKN 0x0200U +#endif +/* PNG_FREE_LIST 0x0400U removed in 1.6.0 because it is ignored */ +#define PNG_FREE_PLTE 0x1000U +#define PNG_FREE_TRNS 0x2000U +#define PNG_FREE_TEXT 0x4000U +#define PNG_FREE_EXIF 0x8000U /* Added at libpng-1.6.31 */ +#define PNG_FREE_ALL 0xffffU +#define PNG_FREE_MUL 0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); +PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, + png_voidp ptr), PNG_DEPRECATED); +#endif + +#ifdef PNG_ERROR_TEXT_SUPPORTED +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +/* The same, but the chunk name is prepended to the error string. */ +PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +#else +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); +# define png_error(s1,s2) png_err(s1) +# define png_chunk_error(s1,s2) png_err(s1) +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#else +# define png_warning(s1,s2) ((void)(s1)) +# define png_chunk_warning(s1,s2) ((void)(s1)) +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Benign error in libpng. Can continue, but may have a problem. + * User can choose whether to handle as a fatal error or as a warning. */ +PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); + +#ifdef PNG_READ_SUPPORTED +/* Same, chunk name is prepended to message (only during read) */ +PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif + +PNG_EXPORT(109, void, png_set_benign_errors, + (png_structrp png_ptr, int allowed)); +#else +# ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +# else +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif +#endif + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +PNG_EXPORT(111, size_t, png_get_rowbytes, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* Returns row_pointers, which is an array of pointers to scanlines that was + * returned from png_read_png(). + */ +PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Set row_pointers, which is an array of pointers to scanlines for use + * by png_write_png(). + */ +PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image height in pixels. */ +PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image bit_depth. */ +PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image color_type. */ +PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image filter_type. */ +PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image interlace_type. */ +PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image compression_type. */ +PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +#endif /* EASY_ACCESS */ + +#ifdef PNG_READ_SUPPORTED +/* Returns pointer to signature string read from PNG header */ +PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_16p *background)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_16p background)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)) +PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, + double *green_X, double *green_Y, double *green_Z, double *blue_X, + double *blue_Y, double *blue_Z)) +PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_white_x, png_fixed_point *int_white_y, + png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, + png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)) +PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z)) +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, double green_x, + double green_y, double blue_x, double blue_y)) +PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, + png_inforp info_ptr, double red_X, double red_Y, double red_Z, + double green_X, double green_Y, double green_Z, double blue_X, + double blue_Y, double blue_Z)) +PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_white_x, + png_fixed_point int_white_y, png_fixed_point int_red_x, + png_fixed_point int_red_y, png_fixed_point int_green_x, + png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)) +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z)) +#endif + +#ifdef PNG_cICP_SUPPORTED +PNG_EXPORT(250, png_uint_32, png_get_cICP, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_bytep colour_primaries, + png_bytep transfer_function, png_bytep matrix_coefficients, + png_bytep video_full_range_flag)); +#endif + +#ifdef PNG_cICP_SUPPORTED +PNG_EXPORT(251, void, png_set_cICP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_byte colour_primaries, + png_byte transfer_function, png_byte matrix_coefficients, + png_byte video_full_range_flag)); +#endif + +#ifdef PNG_cLLI_SUPPORTED +PNG_FP_EXPORT(252, png_uint_32, png_get_cLLI, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *maximum_content_light_level, + double *maximum_frame_average_light_level)) +PNG_FIXED_EXPORT(253, png_uint_32, png_get_cLLI_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + /* The values below are in cd/m2 (nits) and are scaled by 10,000; not + * 100,000 as in the case of png_fixed_point. + */ + png_uint_32p maximum_content_light_level_scaled_by_10000, + png_uint_32p maximum_frame_average_light_level_scaled_by_10000)) +#endif + +#ifdef PNG_cLLI_SUPPORTED +PNG_FP_EXPORT(254, void, png_set_cLLI, (png_const_structrp png_ptr, + png_inforp info_ptr, double maximum_content_light_level, + double maximum_frame_average_light_level)) +PNG_FIXED_EXPORT(255, void, png_set_cLLI_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, + /* The values below are in cd/m2 (nits) and are scaled by 10,000; not + * 100,000 as in the case of png_fixed_point. + */ + png_uint_32 maximum_content_light_level_scaled_by_10000, + png_uint_32 maximum_frame_average_light_level_scaled_by_10000)) +#endif + +#ifdef PNG_eXIf_SUPPORTED +PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *exif)); +PNG_EXPORT(247, void, png_set_eXIf, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep exif)); + +PNG_EXPORT(248, png_uint_32, png_get_eXIf_1, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *num_exif, png_bytep *exif)); +PNG_EXPORT(249, void, png_set_eXIf_1, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 num_exif, png_bytep exif)); +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *file_gamma)) +PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_file_gamma)) +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, + png_inforp info_ptr, double file_gamma)) +PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_file_gamma)) +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_16p *hist)); +PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_uint_16p hist)); +#endif + +PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#ifdef PNG_mDCV_SUPPORTED +PNG_FP_EXPORT(256, png_uint_32, png_get_mDCV, (png_const_structrp png_ptr, + png_const_inforp info_ptr, + /* The chromaticities of the mastering display. As cHRM, but independent of + * the encoding endpoints in cHRM, or cICP, or iCCP. These values will + * always be in the range 0 to 1.3107. + */ + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y, + /* Mastering display luminance in cd/m2 (nits). */ + double *mastering_display_maximum_luminance, + double *mastering_display_minimum_luminance)) + +PNG_FIXED_EXPORT(257, png_uint_32, png_get_mDCV_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_white_x, png_fixed_point *int_white_y, + png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, + png_fixed_point *int_blue_x, png_fixed_point *int_blue_y, + /* Mastering display luminance in cd/m2 (nits) multiplied (scaled) by + * 10,000. + */ + png_uint_32p mastering_display_maximum_luminance_scaled_by_10000, + png_uint_32p mastering_display_minimum_luminance_scaled_by_10000)) +#endif + +#ifdef PNG_mDCV_SUPPORTED +PNG_FP_EXPORT(258, void, png_set_mDCV, (png_const_structrp png_ptr, + png_inforp info_ptr, + /* The chromaticities of the mastering display. As cHRM, but independent of + * the encoding endpoints in cHRM, or cICP, or iCCP. + */ + double white_x, double white_y, double red_x, double red_y, double green_x, + double green_y, double blue_x, double blue_y, + /* Mastering display luminance in cd/m2 (nits). */ + double mastering_display_maximum_luminance, + double mastering_display_minimum_luminance)) + +PNG_FIXED_EXPORT(259, void, png_set_mDCV_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, + /* The admissible range of these values is not the full range of a PNG + * fixed point value. Negative values cannot be encoded and the maximum + * value is about 1.3 */ + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, + png_fixed_point int_green_x, png_fixed_point int_green_y, + png_fixed_point int_blue_x, png_fixed_point int_blue_y, + /* These are PNG unsigned 4 byte values: 31-bit unsigned values. The MSB + * must be zero. + */ + png_uint_32 mastering_display_maximum_luminance_scaled_by_10000, + png_uint_32 mastering_display_minimum_luminance_scaled_by_10000)) +#endif + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, + png_int_32 *X1, int *type, int *nparams, png_charp *units, + png_charpp *params)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_const_charp units, png_charpp params)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, + png_inforp info_ptr, png_colorp *palette, int *num_palette)); + +PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, + png_inforp info_ptr, png_const_colorp palette, int num_palette)); + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_8p *sig_bit)); +#endif + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_8p sig_bit)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *file_srgb_intent)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_sPLT_tpp entries)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); +#endif + +#ifdef PNG_TEXT_SUPPORTED +/* png_get_text also returns the number of text chunks in *num_text */ +PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#ifdef PNG_TEXT_SUPPORTED +PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_timep *mod_time)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_timep mod_time)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, + png_color_16p *trans_color)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, + png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, + png_const_color_16p trans_color)); +#endif + +#ifdef PNG_sCAL_SUPPORTED +PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *unit, double *width, double *height)) +#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* NOTE: this API is currently implemented using floating point arithmetic, + * consequently it can only be used on systems with floating point support. + * In any case the range of values supported by png_fixed_point is small and it + * is highly recommended that png_get_sCAL_s be used instead. + */ +PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_fixed_point *width, png_fixed_point *height)) +#endif +PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_charpp swidth, png_charpp sheight)); + +PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, double width, double height)) +PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, png_fixed_point width, + png_fixed_point height)) +PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, + png_const_charp swidth, png_const_charp sheight)); +#endif /* sCAL */ + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +/* Provide the default handling for all unknown chunks or, optionally, for + * specific unknown chunks. + * + * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was + * ignored and the default was used, the per-chunk setting only had an effect on + * write. If you wish to have chunk-specific handling on read in code that must + * work on earlier versions you must use a user chunk callback to specify the + * desired handling (keep or discard.) + * + * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The + * parameter is interpreted as follows: + * + * READ: + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Known chunks: do normal libpng processing, do not keep the chunk (but + * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED) + * Unknown chunks: for a specific chunk use the global default, when used + * as the default discard the chunk data. + * PNG_HANDLE_CHUNK_NEVER: + * Discard the chunk data. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Keep the chunk data if the chunk is not critical else raise a chunk + * error. + * PNG_HANDLE_CHUNK_ALWAYS: + * Keep the chunk data. + * + * If the chunk data is saved it can be retrieved using png_get_unknown_chunks, + * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent + * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks + * it simply resets the behavior to the libpng default. + * + * INTERACTION WITH USER CHUNK CALLBACKS: + * The per-chunk handling is always used when there is a png_user_chunk_ptr + * callback and the callback returns 0; the chunk is then always stored *unless* + * it is critical and the per-chunk setting is other than ALWAYS. Notice that + * the global default is *not* used in this case. (In effect the per-chunk + * value is incremented to at least IF_SAFE.) + * + * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and + * per-chunk defaults will be honored. If you want to preserve the current + * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE + * as the default - if you don't do this libpng 1.6 will issue a warning. + * + * If you want unhandled unknown chunks to be discarded in libpng 1.6 and + * earlier simply return '1' (handled). + * + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED: + * If this is *not* set known chunks will always be handled by libpng and + * will never be stored in the unknown chunk list. Known chunks listed to + * png_set_keep_unknown_chunks will have no effect. If it is set then known + * chunks listed with a keep other than AS_DEFAULT will *never* be processed + * by libpng, in addition critical chunks must either be processed by the + * callback or saved. + * + * The IHDR and IEND chunks must not be listed. Because this turns off the + * default handling for chunks that would otherwise be recognized the + * behavior of libpng transformations may well become incorrect! + * + * WRITE: + * When writing chunks the options only apply to the chunks specified by + * png_set_unknown_chunks (below), libpng will *always* write known chunks + * required by png_set_ calls and will always write the core critical chunks + * (as required for PLTE). + * + * Each chunk in the png_set_unknown_chunks list is looked up in the + * png_set_keep_unknown_chunks list to find the keep setting, this is then + * interpreted as follows: + * + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Write safe-to-copy chunks and write other chunks if the global + * default is set to _ALWAYS, otherwise don't write this chunk. + * PNG_HANDLE_CHUNK_NEVER: + * Do not write the chunk. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Write the chunk if it is safe-to-copy, otherwise do not write it. + * PNG_HANDLE_CHUNK_ALWAYS: + * Write the chunk. + * + * Note that the default behavior is effectively the opposite of the read case - + * in read unknown chunks are not stored by default, in write they are written + * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different + * - on write the safe-to-copy bit is checked, on read the critical bit is + * checked and on read if the chunk is critical an error will be raised. + * + * num_chunks: + * =========== + * If num_chunks is positive, then the "keep" parameter specifies the manner + * for handling only those chunks appearing in the chunk_list array, + * otherwise the chunk list array is ignored. + * + * If num_chunks is 0 the "keep" parameter specifies the default behavior for + * unknown chunks, as described above. + * + * If num_chunks is negative, then the "keep" parameter specifies the manner + * for handling all unknown chunks plus all chunks recognized by libpng + * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to + * be processed by libpng. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, + int keep, png_const_bytep chunk_list, int num_chunks)); +#endif /* HANDLE_AS_UNKNOWN */ + +/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; + * the result is therefore true (non-zero) if special handling is required, + * false for the default handling. + */ +PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, + png_const_bytep chunk_name)); +#endif /* SET_UNKNOWN_CHUNKS */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, + int num_unknowns)); + /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added + * unknowns to the location currently stored in the png_struct. This is + * invariably the wrong value on write. To fix this call the following API + * for each chunk in the list with the correct location. If you know your + * code won't be compiled on earlier versions you can rely on + * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing + * the correct thing. + */ + +PNG_EXPORT(175, void, png_set_unknown_chunk_location, + (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); + +PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_unknown_chunkpp entries)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + * If you need to turn it off for a chunk that your application has freed, + * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); + */ +PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, + png_inforp info_ptr, int mask)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* The "params" pointer is currently not used and is for future expansion. */ +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +#endif +#ifdef PNG_WRITE_SUPPORTED +PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +#endif +#endif + +PNG_EXPORT(180, png_const_charp, png_get_copyright, + (png_const_structrp png_ptr)); +PNG_EXPORT(181, png_const_charp, png_get_header_ver, + (png_const_structrp png_ptr)); +PNG_EXPORT(182, png_const_charp, png_get_header_version, + (png_const_structrp png_ptr)); +PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, + (png_const_structrp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, + png_uint_32 mng_features_permitted)); +#endif + +/* For use in png_set_keep_unknown, added to version 1.2.6 */ +#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 +#define PNG_HANDLE_CHUNK_NEVER 1 +#define PNG_HANDLE_CHUNK_IF_SAFE 2 +#define PNG_HANDLE_CHUNK_ALWAYS 3 +#define PNG_HANDLE_CHUNK_LAST 4 + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. + */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, + png_uint_32 strip_mode)); +#endif + +/* Added in libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, + png_uint_32 user_width_max, png_uint_32 user_height_max)); +PNG_EXPORT(187, png_uint_32, png_get_user_width_max, + (png_const_structrp png_ptr)); +PNG_EXPORT(188, png_uint_32, png_get_user_height_max, + (png_const_structrp png_ptr)); +/* Added in libpng-1.4.0 */ +PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, + png_uint_32 user_chunk_cache_max)); +PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, + (png_const_structrp png_ptr)); +/* Added in libpng-1.4.1 */ +PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, + png_alloc_size_t user_chunk_cache_max)); +PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, + (png_const_structrp png_ptr)); +#endif + +#if defined(PNG_INCH_CONVERSIONS_SUPPORTED) +PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_FP_EXPORT(196, float, png_get_x_offset_inches, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif + +PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, + png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif + +# ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +# endif /* pHYs */ +#endif /* INCH_CONVERSIONS */ + +/* Added in libpng-1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); + +/* Removed from libpng 1.6; use png_get_io_chunk_type. */ +PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), + PNG_DEPRECATED) + +PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, + (png_const_structrp png_ptr)); + +/* The flags returned by png_get_io_state() are the following: */ +# define PNG_IO_NONE 0x0000 /* no I/O at this moment */ +# define PNG_IO_READING 0x0001 /* currently reading */ +# define PNG_IO_WRITING 0x0002 /* currently writing */ +# define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ +# define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ +# define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ +# define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ +# define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ +# define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ +#endif /* IO_STATE */ + +/* Interlace support. The following macros are always defined so that if + * libpng interlace handling is turned off the macros may be used to handle + * interlaced images within the application. + */ +#define PNG_INTERLACE_ADAM7_PASSES 7 + +/* Two macros to return the first row and first column of the original, + * full, image which appears in a given pass. 'pass' is in the range 0 + * to 6 and the result is in the range 0 to 7. + */ +#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7) + +/* A macro to return the offset between pixels in the output row for a pair of + * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that + * follows. Note that ROW_OFFSET is the offset from one row to the next whereas + * COL_OFFSET is from one column to the next, within a row. + */ +#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8) +#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1)) + +/* Two macros to help evaluate the number of rows or columns in each + * pass. This is expressed as a shift - effectively log2 of the number or + * rows or columns in each 8x8 tile of the original image. + */ +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) + +/* Hence two macros to determine the number of rows or columns in a given + * pass of an image given its height or width. In fact these macros may + * return non-zero even though the sub-image is empty, because the other + * dimension may be empty for a small image. + */ +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) + +/* For the reader row callbacks (both progressive and sequential) it is + * necessary to find the row in the output image given a row in an interlaced + * image, so two more macros: + */ +#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \ + (((y_in)<>(((7-(off))-(pass))<<2)) & 0xF) | \ + ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0)) + +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { \ + png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ + * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 \ + - (png_uint_16)(alpha)) + 128); \ + (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); \ + } + +# define png_composite_16(composite, fg, alpha, bg) \ + { \ + png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ + * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(65535 \ + - (png_uint_32)(alpha)) + 32768); \ + (composite) = (png_uint_16)(0xffff & ((temp + (temp >> 16)) >> 16)); \ + } + +#else /* Standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = \ + (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 127) / 255)) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = \ + (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535)) +#endif /* READ_COMPOSITE_NODIV */ + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); +PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); +PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); +#endif + +PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, + png_const_bytep buf)); +/* No png_get_int_16 -- may be added if there's a real need for it. */ + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); +#endif +#ifdef PNG_SAVE_INT_32_SUPPORTED +PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); +/* No png_save_int_16 -- may be added if there's a real need for it. */ +#endif + +#ifdef PNG_USE_READ_MACROS +/* Inline macros to do direct reads of bytes from the input buffer. + * The png_get_int_32() routine assumes we are using two's complement + * format for negative values, which is almost certainly true. + */ +# define PNG_get_uint_32(buf) \ + (((png_uint_32)(*(buf)) << 24) + \ + ((png_uint_32)(*((buf) + 1)) << 16) + \ + ((png_uint_32)(*((buf) + 2)) << 8) + \ + ((png_uint_32)(*((buf) + 3)))) + + /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the + * function) incorrectly returned a value of type png_uint_32. + */ +# define PNG_get_uint_16(buf) \ + ((png_uint_16) \ + (((unsigned int)(*(buf)) << 8) + \ + ((unsigned int)(*((buf) + 1))))) + +# define PNG_get_int_32(buf) \ + ((png_int_32)((*(buf) & 0x80) \ + ? -((png_int_32)(((png_get_uint_32(buf)^0xffffffffU)+1U)&0x7fffffffU)) \ + : (png_int_32)png_get_uint_32(buf))) + +/* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, + * but defining a macro name prefixed with PNG_PREFIX. + */ +# ifndef PNG_PREFIX +# define png_get_uint_32(buf) PNG_get_uint_32(buf) +# define png_get_uint_16(buf) PNG_get_uint_16(buf) +# define png_get_int_32(buf) PNG_get_int_32(buf) +# endif +#else +# ifdef PNG_PREFIX + /* No macros; revert to the (redefined) function */ +# define PNG_get_uint_32 (png_get_uint_32) +# define PNG_get_uint_16 (png_get_uint_16) +# define PNG_get_int_32 (png_get_int_32) +# endif +#endif + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +PNG_EXPORT(242, void, png_set_check_for_invalid_index, + (png_structrp png_ptr, int allowed)); +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, + png_const_infop info_ptr)); +# endif +#endif /* CHECK_FOR_INVALID_INDEX */ + +/******************************************************************************* + * Section 5: SIMPLIFIED API + ******************************************************************************* + * + * Please read the documentation in libpng-manual.txt (TODO: write said + * documentation) if you don't understand what follows. + * + * The simplified API hides the details of both libpng and the PNG file format + * itself. It allows PNG files to be read into a very limited number of + * in-memory bitmap formats or to be written from the same formats. If these + * formats do not accommodate your needs then you can, and should, use the more + * sophisticated APIs above - these support a wide variety of in-memory formats + * and a wide variety of sophisticated transformations to those formats as well + * as a wide variety of APIs to manipulate ancillary information. + * + * To read a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure (see below) on the stack, set the + * version field to PNG_IMAGE_VERSION and the 'opaque' pointer to NULL + * (this is REQUIRED, your program may crash if you don't do it.) + * 2) Call the appropriate png_image_begin_read... function. + * 3) Set the png_image 'format' member to the required sample format. + * 4) Allocate a buffer for the image and, if required, the color-map. + * 5) Call png_image_finish_read to read the image and, if required, the + * color-map into your buffers. + * + * There are no restrictions on the format of the PNG input itself; all valid + * color types, bit depths, and interlace methods are acceptable, and the + * input image is transformed as necessary to the requested in-memory format + * during the png_image_finish_read() step. The only caveat is that if you + * request a color-mapped image from a PNG that is full-color or makes + * complex use of an alpha channel the transformation is extremely lossy and the + * result may look terrible. + * + * To write a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure on the stack and memset() it to all zero. + * 2) Initialize the members of the structure that describe the image, setting + * the 'format' member to the format of the image samples. + * 3) Call the appropriate png_image_write... function with a pointer to the + * image and, if necessary, the color-map to write the PNG data. + * + * png_image is a structure that describes the in-memory format of an image + * when it is being read or defines the in-memory format of an image that you + * need to write: + */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) + +#define PNG_IMAGE_VERSION 1 + +typedef struct png_control *png_controlp; +typedef struct +{ + png_controlp opaque; /* Initialize to NULL, free with png_image_free */ + png_uint_32 version; /* Set to PNG_IMAGE_VERSION */ + png_uint_32 width; /* Image width in pixels (columns) */ + png_uint_32 height; /* Image height in pixels (rows) */ + png_uint_32 format; /* Image format as defined below */ + png_uint_32 flags; /* A bit mask containing informational flags */ + png_uint_32 colormap_entries; + /* Number of entries in the color-map */ + + /* In the event of an error or warning the following field will be set to a + * non-zero value and the 'message' field will contain a '\0' terminated + * string with the libpng error or warning message. If both warnings and + * an error were encountered, only the error is recorded. If there + * are multiple warnings, only the first one is recorded. + * + * The upper 30 bits of this value are reserved, the low two bits contain + * a value as follows: + */ +# define PNG_IMAGE_WARNING 1 +# define PNG_IMAGE_ERROR 2 + /* + * The result is a two-bit code such that a value more than 1 indicates + * a failure in the API just called: + * + * 0 - no warning or error + * 1 - warning + * 2 - error + * 3 - error preceded by warning + */ +# define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1) + + png_uint_32 warning_or_error; + + char message[64]; +} png_image, *png_imagep; + +/* The samples of the image have one to four channels whose components have + * original values in the range 0 to 1.0: + * + * 1: A single gray or luminance channel (G). + * 2: A gray/luminance channel and an alpha channel (GA). + * 3: Three red, green, blue color channels (RGB). + * 4: Three color channels and an alpha channel (RGBA). + * + * The components are encoded in one of two ways: + * + * a) As a small integer, value 0..255, contained in a single byte. For the + * alpha channel the original value is simply value/255. For the color or + * luminance channels the value is encoded according to the sRGB specification + * and matches the 8-bit format expected by typical display devices. + * + * The color/gray channels are not scaled (pre-multiplied) by the alpha + * channel and are suitable for passing to color management software. + * + * b) As a value in the range 0..65535, contained in a 2-byte integer. All + * channels can be converted to the original value by dividing by 65535; all + * channels are linear. Color channels use the RGB encoding (RGB end-points) of + * the sRGB specification. This encoding is identified by the + * PNG_FORMAT_FLAG_LINEAR flag below. + * + * When the simplified API needs to convert between sRGB and linear colorspaces, + * the actual sRGB transfer curve defined in the sRGB specification (see the + * article at ) is used, not the gamma=1/2.2 + * approximation used elsewhere in libpng. + * + * When an alpha channel is present it is expected to denote pixel coverage + * of the color or luminance channels and is returned as an associated alpha + * channel: the color/gray channels are scaled (pre-multiplied) by the alpha + * value. + * + * The samples are either contained directly in the image data, between 1 and 8 + * bytes per pixel according to the encoding, or are held in a color-map indexed + * by bytes in the image data. In the case of a color-map the color-map entries + * are individual samples, encoded as above, and the image data has one byte per + * pixel to select the relevant sample from the color-map. + */ + +/* PNG_FORMAT_* + * + * #defines to be used in png_image::format. Each #define identifies a + * particular layout of sample data and, if present, alpha values. There are + * separate defines for each of the two component encodings. + * + * A format is built up using single bit flag values. All combinations are + * valid. Formats can be built up from the flag values or you can use one of + * the predefined values below. When testing formats always use the FORMAT_FLAG + * macros to test for individual features - future versions of the library may + * add new flags. + * + * When reading or writing color-mapped images the format should be set to the + * format of the entries in the color-map then png_image_{read,write}_colormap + * called to read or write the color-map and set the format correctly for the + * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + * + * NOTE: libpng can be built with particular features disabled. If you see + * compiler errors because the definition of one of the following flags has been + * compiled out it is because libpng does not have the required support. It is + * possible, however, for the libpng configuration to enable the format on just + * read or just write; in that case you may see an error at run time. You can + * guard against this by checking for the definition of the appropriate + * "_SUPPORTED" macro, one of: + * + * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + */ +#define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ +#define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ +#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2-byte channels else 1-byte */ +#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ + +#ifdef PNG_FORMAT_BGR_SUPPORTED +# define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */ +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ +#endif + +#define PNG_FORMAT_FLAG_ASSOCIATED_ALPHA 0x40U /* alpha channel is associated */ + +/* Commonly used formats have predefined macros. + * + * First the single byte (sRGB) formats: + */ +#define PNG_FORMAT_GRAY 0 +#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA +#define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR +#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) +#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) + +/* Then the linear 2-byte formats. When naming these "Y" is used to + * indicate a luminance (gray) channel. + */ +#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR +#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) +#define PNG_FORMAT_LINEAR_RGB_ALPHA \ + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA) + +/* With color-mapped formats the image data is one byte for each pixel, the byte + * is an index into the color-map which is formatted as above. To obtain a + * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP + * to one of the above definitions, or you can use one of the definitions below. + */ +#define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP) + +/* PNG_IMAGE macros + * + * These are convenience macros to derive information from a png_image + * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the + * actual image sample values - either the entries in the color-map or the + * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values + * for the pixels and will always return 1 for color-mapped formats. The + * remaining macros return information about the rows in the image and the + * complete image. + * + * NOTE: All the macros that take a png_image::format parameter are compile time + * constants if the format parameter is, itself, a constant. Therefore these + * macros can be used in array declarations and case labels where required. + * Similarly the macros are also pre-processor constants (sizeof is not used) so + * they can be used in #if tests. + * + * First the information about the samples. + */ +#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\ + (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1) + /* Return the total number of channels in a given format: 1..4 */ + +#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\ + ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1) + /* Return the size in bytes of a single component of a pixel or color-map + * entry (as appropriate) in the image: 1 or 2. + */ + +#define PNG_IMAGE_SAMPLE_SIZE(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)) + /* This is the size of the sample data for one sample. If the image is + * color-mapped it is the size of one color-map entry (and image pixels are + * one byte in size), otherwise it is the size of one image pixel. + */ + +#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) + /* The maximum size of the color-map required by the format expressed in a + * count of components. This can be used to compile-time allocate a + * color-map: + * + * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + * + * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + * + * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + * information from one of the png_image_begin_read_ APIs and dynamically + * allocate the required memory. + */ + +/* Corresponding information about the pixels */ +#define PNG_IMAGE_PIXEL_(test,fmt)\ + (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt)) + +#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt) + /* The number of separate channels (components) in a pixel; 1 for a + * color-mapped image. + */ + +#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt) + /* The size, in bytes, of each component in a pixel; 1 for a color-mapped + * image. + */ + +#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt) + /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */ + +/* Information about the whole row, or whole image */ +#define PNG_IMAGE_ROW_STRIDE(image)\ + (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) + /* Return the total number of components in a single row of the image; this + * is the minimum 'row stride', the minimum count of components between each + * row. For a color-mapped image this is the minimum number of bytes in a + * row. + * + * WARNING: this macro overflows for some images with more than one component + * and very large image widths. libpng will refuse to process an image where + * this macro would overflow. + */ + +#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ + (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) + /* Return the size, in bytes, of an image buffer given a png_image and a row + * stride - the number of components to leave space for in each row. + * + * WARNING: this macro overflows a 32-bit integer for some large PNG images, + * libpng will refuse to process an image where such an overflow would occur. + */ + +#define PNG_IMAGE_SIZE(image)\ + PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) + /* Return the size, in bytes, of the image in memory given just a png_image; + * the row stride is the minimum stride required for the image. + */ + +#define PNG_IMAGE_COLORMAP_SIZE(image)\ + (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries) + /* Return the size, in bytes, of the color-map of this image. If the image + * format is not a color-map format this will return a size sufficient for + * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if + * you don't want to allocate a color-map in this case. + */ + +/* PNG_IMAGE_FLAG_* + * + * Flags containing additional information about the image are held in the + * 'flags' field of png_image. + */ +#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 + /* This indicates that the RGB values of the in-memory bitmap do not + * correspond to the red, green and blue end-points defined by sRGB. + */ + +#define PNG_IMAGE_FLAG_FAST 0x02 + /* On write emphasise speed over compression; the resultant PNG file will be + * larger but will be produced significantly faster, particular for large + * images. Do not use this option for images which will be distributed, only + * used it when producing intermediate files that will be read back in + * repeatedly. For a typical 24-bit image the option will double the read + * speed at the cost of increasing the image size by 25%, however for many + * more compressible images the PNG file can be 10 times larger with only a + * slight speed gain. + */ + +#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 + /* On read if the image is a 16-bit per component image and there is no gAMA + * or sRGB chunk assume that the components are sRGB encoded. Notice that + * images output by the simplified API always have gamma information; setting + * this flag only affects the interpretation of 16-bit images from an + * external source. It is recommended that the application expose this flag + * to the user; the user can normally easily recognize the difference between + * linear and sRGB encoding. This flag has no effect on write - the data + * passed to the write APIs must have the correct encoding (as defined + * above.) + * + * If the flag is not set (the default) input 16-bit per component data is + * assumed to be linear. + * + * NOTE: the flag can only be set after the png_image_begin_read_ call, + * because that call initializes the 'flags' field. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* READ APIs + * --------- + * + * The png_image passed to the read APIs must have been initialized by setting + * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) + */ +#ifdef PNG_STDIO_SUPPORTED +PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, + const char *file_name)); + /* The named file is opened for read and the image header is filled in + * from the PNG header in the file. + */ + +PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, + FILE *file)); + /* The PNG header is read from the stdio FILE object. */ +#endif /* STDIO */ + +PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, + png_const_voidp memory, size_t size)); + /* The PNG header is read from the given memory buffer. */ + +PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, + png_const_colorp background, void *buffer, png_int_32 row_stride, + void *colormap)); + /* Finish reading the image into the supplied buffer and clean up the + * png_image structure. + * + * row_stride is the step, in byte or 2-byte units as appropriate, + * between adjacent rows. A positive stride indicates that the top-most row + * is first in the buffer - the normal top-down arrangement. A negative + * stride indicates that the bottom-most row is first in the buffer. + * + * background need only be supplied if an alpha channel must be removed from + * a png_byte format and the removal is to be done by compositing on a solid + * color; otherwise it may be NULL and any composition will be done directly + * onto the buffer. The value is an sRGB color to use for the background, + * for grayscale output the green channel is used. + * + * background must be supplied when an alpha channel must be removed from a + * single byte color-mapped output format, in other words if: + * + * 1) The original format from png_image_begin_read_from_* had + * PNG_FORMAT_FLAG_ALPHA set. + * 2) The format set by the application does not. + * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and + * PNG_FORMAT_FLAG_LINEAR *not* set. + * + * For linear output removing the alpha channel is always done by compositing + * on black and background is ignored. + * + * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must + * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. + * image->colormap_entries will be updated to the actual number of entries + * written to the colormap; this may be less than the original value. + */ + +PNG_EXPORT(238, void, png_image_free, (png_imagep image)); + /* Free any data allocated by libpng in image->opaque, setting the pointer to + * NULL. May be called at any time after the structure is initialized. + */ +#endif /* SIMPLIFIED_READ */ + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +/* WRITE APIS + * ---------- + * For write you must initialize a png_image structure to describe the image to + * be written. To do this use memset to set the whole structure to 0 then + * initialize fields describing your image. + * + * version: must be set to PNG_IMAGE_VERSION + * opaque: must be initialized to NULL + * width: image width in pixels + * height: image height in rows + * format: the format of the data (image and color-map) you wish to write + * flags: set to 0 unless one of the defined flags applies; set + * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB + * values do not correspond to the colors in sRGB. + * colormap_entries: set to the number of entries in the color-map (0 to 256) + */ +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + /* Write the image to the named file. */ + +PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, png_int_32 row_stride, + const void *colormap)); + /* Write the image to the given FILE object. */ +#endif /* SIMPLIFIED_WRITE_STDIO */ + +/* With all write APIs if image is in one of the linear formats with 16-bit + * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG + * gamma encoded according to the sRGB specification, otherwise a 16-bit linear + * encoded PNG file is written. + * + * With color-mapped data formats the colormap parameter point to a color-map + * with at least image->colormap_entries encoded in the specified format. If + * the format is linear the written PNG color-map will be converted to sRGB + * regardless of the convert_to_8_bit flag. + * + * With all APIs row_stride is handled as in the read APIs - it is the spacing + * from one row to the next in component sized units (1 or 2 bytes) and if + * negative indicates a bottom-up row layout in the buffer. If row_stride is + * zero, libpng will calculate it for you from the image width and number of + * channels. + * + * Note that the write API does not support interlacing, sub-8-bit pixels or + * most ancillary chunks. If you need to write text chunks (e.g. for copyright + * notices) you need to use one of the other APIs. + */ + +PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory, + png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8_bit, + const void *buffer, png_int_32 row_stride, const void *colormap)); + /* Write the image to the given memory buffer. The function both writes the + * whole PNG data stream to *memory and updates *memory_bytes with the count + * of bytes written. + * + * 'memory' may be NULL. In this case *memory_bytes is not read however on + * success the number of bytes which would have been written will still be + * stored in *memory_bytes. On failure *memory_bytes will contain 0. + * + * If 'memory' is not NULL it must point to memory[*memory_bytes] of + * writeable memory. + * + * If the function returns success memory[*memory_bytes] (if 'memory' is not + * NULL) contains the written PNG data. *memory_bytes will always be less + * than or equal to the original value. + * + * If the function returns false and *memory_bytes was not changed an error + * occurred during write. If *memory_bytes was changed, or is not 0 if + * 'memory' was NULL, the write would have succeeded but for the memory + * buffer being too small. *memory_bytes contains the required number of + * bytes and will be bigger that the original value. + */ + +#define png_image_write_get_memory_size(image, size, convert_to_8_bit, buffer,\ + row_stride, colormap)\ + png_image_write_to_memory(&(image), 0, &(size), convert_to_8_bit, buffer,\ + row_stride, colormap) + /* Return the amount of memory in 'size' required to compress this image. + * The png_image structure 'image' must be filled in as in the above + * function and must not be changed before the actual write call, the buffer + * and all other parameters must also be identical to that in the final + * write call. The 'size' variable need not be initialized. + * + * NOTE: the macro returns true/false, if false is returned 'size' will be + * set to zero and the write failed and probably will fail if tried again. + */ + +/* You can pre-allocate the buffer by making sure it is of sufficient size + * regardless of the amount of compression achieved. The buffer size will + * always be bigger than the original image and it will never be filled. The + * following macros are provided to assist in allocating the buffer. + */ +#define PNG_IMAGE_DATA_SIZE(image) (PNG_IMAGE_SIZE(image)+(image).height) + /* The number of uncompressed bytes in the PNG byte encoding of the image; + * uncompressing the PNG IDAT data will give this number of bytes. + * + * NOTE: while PNG_IMAGE_SIZE cannot overflow for an image in memory this + * macro can because of the extra bytes used in the PNG byte encoding. You + * need to avoid this macro if your image size approaches 2^30 in width or + * height. The same goes for the remainder of these macros; they all produce + * bigger numbers than the actual in-memory image size. + */ +#ifndef PNG_ZLIB_MAX_SIZE +# define PNG_ZLIB_MAX_SIZE(b) ((b)+(((b)+7U)>>3)+(((b)+63U)>>6)+11U) + /* An upper bound on the number of compressed bytes given 'b' uncompressed + * bytes. This is based on deflateBounds() in zlib; different + * implementations of zlib compression may conceivably produce more data so + * if your zlib implementation is not zlib itself redefine this macro + * appropriately. + */ +#endif + +#define PNG_IMAGE_COMPRESSED_SIZE_MAX(image)\ + PNG_ZLIB_MAX_SIZE((png_alloc_size_t)PNG_IMAGE_DATA_SIZE(image)) + /* An upper bound on the size of the data in the PNG IDAT chunks. */ + +#define PNG_IMAGE_PNG_SIZE_MAX_(image, image_size)\ + ((8U/*sig*/+25U/*IHDR*/+16U/*gAMA*/+44U/*cHRM*/+12U/*IEND*/+\ + (((image).format&PNG_FORMAT_FLAG_COLORMAP)?/*colormap: PLTE, tRNS*/\ + 12U+3U*(image).colormap_entries/*PLTE data*/+\ + (((image).format&PNG_FORMAT_FLAG_ALPHA)?\ + 12U/*tRNS*/+(image).colormap_entries:0U):0U)+\ + 12U)+(12U*((image_size)/PNG_ZBUF_SIZE))/*IDAT*/+(image_size)) + /* A helper for the following macro; if your compiler cannot handle the + * following macro use this one with the result of + * PNG_IMAGE_COMPRESSED_SIZE_MAX(image) as the second argument (most + * compilers should handle this just fine.) + */ + +#define PNG_IMAGE_PNG_SIZE_MAX(image)\ + PNG_IMAGE_PNG_SIZE_MAX_(image, PNG_IMAGE_COMPRESSED_SIZE_MAX(image)) + /* An upper bound on the total length of the PNG data stream for 'image'. + * The result is of type png_alloc_size_t, on 32-bit systems this may + * overflow even though PNG_IMAGE_DATA_SIZE does not overflow; the write will + * run out of buffer space but return a corrected size which should work. + */ +#endif /* SIMPLIFIED_WRITE */ +/******************************************************************************* + * END OF SIMPLIFIED API + ******************************************************************************/ +#endif /* SIMPLIFIED_{READ|WRITE} */ + +/******************************************************************************* + * Section 6: IMPLEMENTATION OPTIONS + ******************************************************************************* + * + * Support for arbitrary implementation-specific optimizations. The API allows + * particular options to be turned on or off. 'Option' is the number of the + * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given + * by the PNG_OPTION_ defines below. + * + * HARDWARE: normally hardware capabilities, such as the Intel SSE instructions, + * are detected at run time, however sometimes it may be impossible + * to do this in user mode, in which case it is necessary to discover + * the capabilities in an OS specific way. Such capabilities are + * listed here when libpng has support for them and must be turned + * ON by the application if present. + * + * SOFTWARE: sometimes software optimizations actually result in performance + * decrease on some architectures or systems, or with some sets of + * PNG images. 'Software' options allow such optimizations to be + * selected at run time. + */ +#ifdef PNG_SET_OPTION_SUPPORTED + +/* HARDWARE: ARM Neon SIMD instructions supported */ +#ifdef PNG_ARM_NEON_API_SUPPORTED +# define PNG_ARM_NEON 0 +#endif + +/* SOFTWARE: Force maximum window */ +#define PNG_MAXIMUM_INFLATE_WINDOW 2 + +/* SOFTWARE: Check ICC profile for sRGB */ +#define PNG_SKIP_sRGB_CHECK_PROFILE 4 + +/* HARDWARE: MIPS MSA SIMD instructions supported */ +#ifdef PNG_MIPS_MSA_API_SUPPORTED +# define PNG_MIPS_MSA 6 +#endif + +/* SOFTWARE: Disable Adler32 check on IDAT */ +#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED +# define PNG_IGNORE_ADLER32 8 +#endif + +/* HARDWARE: PowerPC VSX SIMD instructions supported */ +#ifdef PNG_POWERPC_VSX_API_SUPPORTED +# define PNG_POWERPC_VSX 10 +#endif + +/* HARDWARE: MIPS MMI SIMD instructions supported */ +#ifdef PNG_MIPS_MMI_API_SUPPORTED +# define PNG_MIPS_MMI 12 +#endif + +/* HARDWARE: RISC-V RVV SIMD instructions supported */ +#ifdef PNG_RISCV_RVV_API_SUPPORTED +# define PNG_RISCV_RVV 14 +#endif + +/* Next option - numbers must be even */ +#define PNG_OPTION_NEXT 16 + +/* Return values: NOTE: there are four values and 'off' is *not* zero */ +#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ +#define PNG_OPTION_INVALID 1 /* Option number out of range */ +#define PNG_OPTION_OFF 2 +#define PNG_OPTION_ON 3 + +PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, + int onoff)); +#endif /* SET_OPTION */ + +/******************************************************************************* + * END OF HARDWARE AND SOFTWARE OPTIONS + ******************************************************************************/ + +/* Maintainer: Put new public prototypes here ^, in libpng.3, in project + * defs, and in scripts/symbols.def. + */ + +/* The last ordinal number (this is the *last* one already used; the next + * one to use is one more than this.) + */ +#ifdef PNG_EXPORT_LAST_ORDINAL + PNG_EXPORT_LAST_ORDINAL(259); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* Do not put anything past this line */ +#endif /* PNG_H */ diff --git a/widget/milsko/milskosrc/external/libpng/include/pngconf.h b/widget/milsko/milskosrc/external/libpng/include/pngconf.h new file mode 100644 index 0000000000..d1081b54dd --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/include/pngconf.h @@ -0,0 +1,615 @@ +/* pngconf.h - machine-configurable file for libpng + * + * libpng version 1.6.50 + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ + +/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C + * compiler for correct compilation. The following header files are required by + * the standard. If your compiler doesn't provide these header files, or they + * do not match the standard, you will need to provide/improve them. + */ +#include +#include + +/* Library header files. These header files are all defined by ISOC90; libpng + * expects conformant implementations, however, an ISOC90 conformant system need + * not provide these header files if the functionality cannot be implemented. + * In this case it will be necessary to disable the relevant parts of libpng in + * the build of pnglibconf.h. + * + * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not + * include this unnecessary header file. + */ + +#ifdef PNG_STDIO_SUPPORTED + /* Required for the definition of FILE: */ +# include +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Required for the definition of jmp_buf and the declaration of longjmp: */ +# include +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED + /* Required for struct tm: */ +# include +#endif + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +/* Prior to 1.6.0, it was possible to turn off 'const' in declarations, + * using PNG_NO_CONST. This is no longer supported. + */ +#define PNG_CONST const /* backward compatibility only */ + +/* This controls optimization of the reading of 16-bit and 32-bit + * values from PNG files. It can be set on a per-app-file basis: it + * just changes whether a macro is used when the function is called. + * The library builder sets the default; if read functions are not + * built into the library the macro implementation is forced on. + */ +#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED +# define PNG_USE_READ_MACROS +#endif +#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +# if PNG_DEFAULT_READ_MACROS +# define PNG_USE_READ_MACROS +# endif +#endif + +/* COMPILER SPECIFIC OPTIONS. + * + * These options are provided so that a variety of difficult compilers + * can be used. Some are fixed at build time (e.g. PNG_API_RULE + * below) but still have compiler specific implementations, others + * may be changed on a per-file basis when compiling against libpng. + */ + +/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect + * against legacy (pre ISOC90) compilers that did not understand function + * prototypes. [Deprecated.] + */ +#ifndef PNGARG +# define PNGARG(arglist) arglist +#endif + +/* Function calling conventions. + * ============================= + * Normally it is not necessary to specify to the compiler how to call + * a function - it just does it - however on x86 systems derived from + * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems + * and some others) there are multiple ways to call a function and the + * default can be changed on the compiler command line. For this reason + * libpng specifies the calling convention of every exported function and + * every function called via a user supplied function pointer. This is + * done in this file by defining the following macros: + * + * PNGAPI Calling convention for exported functions. + * PNGCBAPI Calling convention for user provided (callback) functions. + * PNGCAPI Calling convention used by the ANSI-C library (required + * for longjmp callbacks and sometimes used internally to + * specify the calling convention for zlib). + * + * These macros should never be overridden. If it is necessary to + * change calling convention in a private build this can be done + * by setting PNG_API_RULE (which defaults to 0) to one of the values + * below to select the correct 'API' variants. + * + * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. + * This is correct in every known environment. + * PNG_API_RULE=1 Use the operating system convention for PNGAPI and + * the 'C' calling convention (from PNGCAPI) for + * callbacks (PNGCBAPI). This is no longer required + * in any known environment - if it has to be used + * please post an explanation of the problem to the + * libpng mailing list. + * + * These cases only differ if the operating system does not use the C + * calling convention, at present this just means the above cases + * (x86 DOS/Windows systems) and, even then, this does not apply to + * Cygwin running on those systems. + * + * Note that the value must be defined in pnglibconf.h so that what + * the application uses to call the library matches the conventions + * set when building the library. + */ + +/* Symbol export + * ============= + * When building a shared library it is almost always necessary to tell + * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' + * is used to mark the symbols. On some systems these symbols can be + * extracted at link time and need no special processing by the compiler, + * on other systems the symbols are flagged by the compiler and just + * the declaration requires a special tag applied (unfortunately) in a + * compiler dependent way. Some systems can do either. + * + * A small number of older systems also require a symbol from a DLL to + * be flagged to the program that calls it. This is a problem because + * we do not know in the header file included by application code that + * the symbol will come from a shared library, as opposed to a statically + * linked one. For this reason the application must tell us by setting + * the magic flag PNG_USE_DLL to turn on the special processing before + * it includes png.h. + * + * Four additional macros are used to make this happen: + * + * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from + * the build or imported if PNG_USE_DLL is set - compiler + * and system specific. + * + * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to + * 'type', compiler specific. + * + * PNG_DLL_EXPORT Set to the magic to use during a libpng build to + * make a symbol exported from the DLL. Not used in the + * public header files; see pngpriv.h for how it is used + * in the libpng build. + * + * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come + * from a DLL - used to define PNG_IMPEXP when + * PNG_USE_DLL is set. + */ + +/* System specific discovery. + * ========================== + * This code is used at build time to find PNG_IMPEXP, the API settings + * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL + * import processing is possible. On Windows systems it also sets + * compiler-specific macros to the values required to change the calling + * conventions of the various functions. + */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \ + defined(__CYGWIN__) + /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or + * MinGW on any architecture currently supported by Windows. Also includes + * Watcom builds but these need special treatment because they are not + * compatible with GCC or Visual C because of different calling conventions. + */ +# if PNG_API_RULE == 2 + /* If this line results in an error, either because __watcall is not + * understood or because of a redefine just below you cannot use *this* + * build of the library with the compiler you are using. *This* build was + * build using Watcom and applications must also be built using Watcom! + */ +# define PNGCAPI __watcall +# endif + +# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) +# define PNGCAPI __cdecl +# if PNG_API_RULE == 1 + /* If this line results in an error __stdcall is not understood and + * PNG_API_RULE should not have been set to '1'. + */ +# define PNGAPI __stdcall +# endif +# else + /* An older compiler, or one not detected (erroneously) above, + * if necessary override on the command line to get the correct + * variants for the compiler. + */ +# ifndef PNGCAPI +# define PNGCAPI _cdecl +# endif +# if PNG_API_RULE == 1 && !defined(PNGAPI) +# define PNGAPI _stdcall +# endif +# endif /* compiler/api */ + + /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ + +# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) +# error PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed +# endif + +# define PNG_DLL_EXPORT __declspec(dllexport) +# ifndef PNG_DLL_IMPORT +# define PNG_DLL_IMPORT __declspec(dllimport) +# endif + +#else /* !Windows */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# else /* !Windows/x86 && !OS/2 */ + /* Use the defaults, or define PNG*API on the command line (but + * this will have to be done for every compile!) + */ +# endif /* other system, !OS/2 */ +#endif /* !Windows/x86 */ + +/* Now do all the defaulting . */ +#ifndef PNGCAPI +# define PNGCAPI +#endif +#ifndef PNGCBAPI +# define PNGCBAPI PNGCAPI +#endif +#ifndef PNGAPI +# define PNGAPI PNGCAPI +#endif + +/* PNG_IMPEXP may be set on the compilation system command line or (if not set) + * then in an internal header file when building the library, otherwise (when + * using the library) it is set here. + */ +#ifndef PNG_IMPEXP +# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) + /* This forces use of a DLL, disallowing static linking */ +# define PNG_IMPEXP PNG_DLL_IMPORT +# endif + +# ifndef PNG_IMPEXP +# define PNG_IMPEXP +# endif +#endif + +/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat + * 'attributes' as a storage class - the attributes go at the start of the + * function definition, and attributes are always appended regardless of the + * compiler. This considerably simplifies these macros but may cause problems + * if any compilers both need function attributes and fail to handle them as + * a storage class (this is unlikely.) + */ +#ifndef PNG_FUNCTION +# define PNG_FUNCTION(type, name, args, attributes) attributes type name args +#endif + +#ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type +#endif + + /* The ordinal value is only relevant when preprocessing png.h for symbol + * table entries, so we discard it here. See the .dfn files in the + * scripts directory. + */ + +#ifndef PNG_EXPORTA +# define PNG_EXPORTA(ordinal, type, name, args, attributes) \ + PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), args, \ + PNG_LINKAGE_API attributes) +#endif + +/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, + * so make something non-empty to satisfy the requirement: + */ +#define PNG_EMPTY /*empty list*/ + +#define PNG_EXPORT(ordinal, type, name, args) \ + PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) + +/* Use PNG_REMOVED to comment out a removed interface. */ +#ifndef PNG_REMOVED +# define PNG_REMOVED(ordinal, type, name, args, attributes) +#endif + +#ifndef PNG_CALLBACK +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) args +#endif + +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. + * + * Added at libpng-1.2.41. + */ + +#ifndef PNG_NO_PEDANTIC_WARNINGS +# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED +# define PNG_PEDANTIC_WARNINGS_SUPPORTED +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED + /* Support for compiler specific function attributes. These are used + * so that where compiler support is available, incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. Disabling these removes the warnings but may also produce + * less efficient code. + */ +# if defined(__clang__) && defined(__has_attribute) + /* Clang defines both __clang__ and __GNUC__. Check __clang__ first. */ +# if !defined(PNG_USE_RESULT) && __has_attribute(__warn_unused_result__) +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# if !defined(PNG_NORETURN) && __has_attribute(__noreturn__) +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if !defined(PNG_ALLOCATED) && __has_attribute(__malloc__) +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# if !defined(PNG_DEPRECATED) && __has_attribute(__deprecated__) +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# if !defined(PNG_PRIVATE) +# ifdef __has_extension +# if __has_extension(attribute_unavailable_with_message) +# define PNG_PRIVATE __attribute__((__unavailable__(\ + "This function is not exported by libpng."))) +# endif +# endif +# endif +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif + +# elif defined(__GNUC__) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if __GNUC__ >= 3 +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif +# if ((__GNUC__ > 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* __GNUC__.__GNUC_MINOR__ > 3.0 */ +# endif /* __GNUC__ >= 3 */ + +# elif defined(_MSC_VER) && (_MSC_VER >= 1300) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* not supported */ +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __declspec(noreturn) +# endif +# ifndef PNG_ALLOCATED +# if (_MSC_VER >= 1400) +# define PNG_ALLOCATED __declspec(restrict) +# endif +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __declspec(deprecated) +# endif +# ifndef PNG_PRIVATE +# define PNG_PRIVATE __declspec(deprecated) +# endif +# ifndef PNG_RESTRICT +# if (_MSC_VER >= 1400) +# define PNG_RESTRICT __restrict +# endif +# endif + +# elif defined(__WATCOMC__) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif +#endif /* PNG_PEDANTIC_WARNINGS */ + +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED /* Use of this function is deprecated */ +#endif +#ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* The result of this function must be checked */ +#endif +#ifndef PNG_NORETURN +# define PNG_NORETURN /* This function does not return */ +#endif +#ifndef PNG_ALLOCATED +# define PNG_ALLOCATED /* The result of the function is new memory */ +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE /* This is a private libpng function */ +#endif +#ifndef PNG_RESTRICT +# define PNG_RESTRICT /* The C99 "restrict" feature */ +#endif + +#ifndef PNG_FP_EXPORT /* A floating point API. */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No floating point APIs */ +# define PNG_FP_EXPORT(ordinal, type, name, args) +# endif +#endif +#ifndef PNG_FIXED_EXPORT /* A fixed point API. */ +# ifdef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No fixed point APIs */ +# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE +/* Some typedefs to get us started. These should be safe on most of the common + * platforms. + * + * png_uint_32 and png_int_32 may, currently, be larger than required to hold a + * 32-bit value however this is not normally advisable. + * + * png_uint_16 and png_int_16 should always be two bytes in size - this is + * verified at library build time. + * + * png_byte must always be one byte in size. + * + * The checks below use constants from limits.h, as defined by the ISOC90 + * standard. + */ +#if CHAR_BIT == 8 && UCHAR_MAX == 255 + typedef unsigned char png_byte; +#else +# error libpng requires 8-bit bytes +#endif + +#if INT_MIN == -32768 && INT_MAX == 32767 + typedef int png_int_16; +#elif SHRT_MIN == -32768 && SHRT_MAX == 32767 + typedef short png_int_16; +#else +# error libpng requires a signed 16-bit integer type +#endif + +#if UINT_MAX == 65535 + typedef unsigned int png_uint_16; +#elif USHRT_MAX == 65535 + typedef unsigned short png_uint_16; +#else +# error libpng requires an unsigned 16-bit integer type +#endif + +#if INT_MIN < -2147483646 && INT_MAX > 2147483646 + typedef int png_int_32; +#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 + typedef long int png_int_32; +#else +# error libpng requires a signed 32-bit (or longer) integer type +#endif + +#if UINT_MAX > 4294967294U + typedef unsigned int png_uint_32; +#elif ULONG_MAX > 4294967294U + typedef unsigned long int png_uint_32; +#else +# error libpng requires an unsigned 32-bit (or longer) integer type +#endif + +/* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t. + * From 1.6.0 onwards, an ISO C90 compiler, as well as a standard-compliant + * behavior of sizeof and ptrdiff_t are required. + * The legacy typedefs are provided here for backwards compatibility. + */ +typedef size_t png_size_t; +typedef ptrdiff_t png_ptrdiff_t; + +/* libpng needs to know the maximum value of 'size_t' and this controls the + * definition of png_alloc_size_t, below. This maximum value of size_t limits + * but does not control the maximum allocations the library makes - there is + * direct application control of this through png_set_user_limits(). + */ +#ifndef PNG_SMALL_SIZE_T + /* Compiler specific tests for systems where size_t is known to be less than + * 32 bits (some of these systems may no longer work because of the lack of + * 'far' support; see above.) + */ +# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ + (defined(_MSC_VER) && defined(MAXSEG_64K)) +# define PNG_SMALL_SIZE_T +# endif +#endif + +/* png_alloc_size_t is guaranteed to be no smaller than size_t, and no smaller + * than png_uint_32. Casts from size_t or png_uint_32 to png_alloc_size_t are + * not necessary; in fact, it is recommended not to use them at all, so that + * the compiler can complain when something turns out to be problematic. + * + * Casts in the other direction (from png_alloc_size_t to size_t or + * png_uint_32) should be explicitly applied; however, we do not expect to + * encounter practical situations that require such conversions. + * + * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than + * 4294967295 - i.e. less than the maximum value of png_uint_32. + */ +#ifdef PNG_SMALL_SIZE_T + typedef png_uint_32 png_alloc_size_t; +#else + typedef size_t png_alloc_size_t; +#endif + +/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler + * implementations of Intel CPU specific support of user-mode segmented address + * spaces, where 16-bit pointers address more than 65536 bytes of memory using + * separate 'segment' registers. The implementation requires two different + * types of pointer (only one of which includes the segment value.) + * + * If required this support is available in version 1.2 of libpng and may be + * available in versions through 1.5, although the correctness of the code has + * not been verified recently. + */ + +/* Typedef for floating-point numbers that are converted to fixed-point with a + * multiple of 100,000, e.g., gamma + */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void * png_voidp; +typedef const void * png_const_voidp; +typedef png_byte * png_bytep; +typedef const png_byte * png_const_bytep; +typedef png_uint_32 * png_uint_32p; +typedef const png_uint_32 * png_const_uint_32p; +typedef png_int_32 * png_int_32p; +typedef const png_int_32 * png_const_int_32p; +typedef png_uint_16 * png_uint_16p; +typedef const png_uint_16 * png_const_uint_16p; +typedef png_int_16 * png_int_16p; +typedef const png_int_16 * png_const_int_16p; +typedef char * png_charp; +typedef const char * png_const_charp; +typedef png_fixed_point * png_fixed_point_p; +typedef const png_fixed_point * png_const_fixed_point_p; +typedef size_t * png_size_tp; +typedef const size_t * png_const_size_tp; + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * png_doublep; +typedef const double * png_const_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte * * png_bytepp; +typedef png_uint_32 * * png_uint_32pp; +typedef png_int_32 * * png_int_32pp; +typedef png_uint_16 * * png_uint_16pp; +typedef png_int_16 * * png_int_16pp; +typedef const char * * png_const_charpp; +typedef char * * png_charpp; +typedef png_fixed_point * * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char * * * png_charppp; + +#ifdef PNG_STDIO_SUPPORTED +/* With PNG_STDIO_SUPPORTED it was possible to use I/O streams that were + * not necessarily stdio FILE streams, to allow building Windows applications + * before Win32 and Windows CE applications before WinCE 3.0, but that kind + * of support has long been discontinued. + */ +typedef FILE * png_FILE_p; /* [Deprecated] */ +#endif + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +#endif /* PNGCONF_H */ diff --git a/widget/milsko/milskosrc/external/libpng/include/pngdebug.h b/widget/milsko/milskosrc/external/libpng/include/pngdebug.h new file mode 100644 index 0000000000..af1ae9e821 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/include/pngdebug.h @@ -0,0 +1,156 @@ +/* pngdebug.h - internal debugging macros for libpng + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#ifndef PNGPRIV_H +# error This file must not be included by applications; please include +#endif + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + * + * png_debug[1-2]?(level, message ,arg{0-2}) + * Expands to a statement (either a simple expression or a compound + * do..while(0) statement) that outputs a message with parameter + * substitution if PNG_DEBUG is defined to 2 or more. If PNG_DEBUG + * is undefined, 0 or 1 every png_debug expands to a simple expression + * (actually ((void)0)). + * + * level: level of detail of message, starting at 0. A level 'n' + * message is preceded by 'n' 3-space indentations (not implemented + * on Microsoft compilers unless PNG_DEBUG_FILE is also + * defined, to allow debug DLL compilation with no standard IO). + * message: a printf(3) style text string. A trailing '\n' is added + * to the message. + * arg: 0 to 2 arguments for printf(3) style substitution in message. + */ +#ifndef PNGDEBUG_H +#define PNGDEBUG_H +/* These settings control the formatting of messages in png.c and pngerror.c */ +/* Moved to pngdebug.h at 1.5.0 */ +# ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +# endif +# ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET +# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b +# endif +# ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET +# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d +# endif +# ifndef PNG_STRING_NEWLINE +# define PNG_STRING_NEWLINE "\n" +# endif + +#ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +# include +# if (PNG_DEBUG > 1) +# ifndef _DEBUG +# define _DEBUG +# endif +# ifndef png_debug +# define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) +# endif +# endif +# else /* PNG_DEBUG_FILE || !_MSC_VER */ +# ifndef PNG_STDIO_SUPPORTED +# include /* not included yet */ +# endif +# ifndef PNG_DEBUG_FILE +# define PNG_DEBUG_FILE stderr +# endif /* PNG_DEBUG_FILE */ + +# if (PNG_DEBUG > 1) +# ifdef __STDC__ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : "")))); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1,p2);\ + } while (0) +# endif +# else /* __STDC __ */ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1,p2); \ + } while (0) +# endif +# endif /* __STDC __ */ +# endif /* (PNG_DEBUG > 1) */ + +# endif /* _MSC_VER */ +# endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +# define png_debug(l, m) ((void)0) +#endif +#ifndef png_debug1 +# define png_debug1(l, m, p1) ((void)0) +#endif +#ifndef png_debug2 +# define png_debug2(l, m, p1, p2) ((void)0) +#endif +#endif /* PNGDEBUG_H */ diff --git a/widget/milsko/milskosrc/external/libpng/include/pnginfo.h b/widget/milsko/milskosrc/external/libpng/include/pnginfo.h new file mode 100644 index 0000000000..584a42f956 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/include/pnginfo.h @@ -0,0 +1,263 @@ +/* pnginfo.h - internal structures for libpng + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2013,2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#ifndef PNGPRIV_H +# error This file must not be included by applications; please include +#endif + +/* INTERNAL, PRIVATE definition of a PNG. + * + * png_info is a modifiable description of a PNG datastream. The fields inside + * this structure are accessed through png_get_() functions and modified + * using png_set_() functions. + * + * Some functions in libpng do directly access members of png_info. However, + * this should be avoided. png_struct objects contain members which hold + * caches, sometimes optimised, of the values from png_info objects, and + * png_info is not passed to the functions which read and write image data. + */ +#ifndef PNGINFO_H +#define PNGINFO_H + +struct png_info_def +{ + /* The following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + size_t rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following are set by png_set_IHDR, called from the application on + * write, but the are never actually used by the write code. + */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + +#ifdef PNG_READ_SUPPORTED + /* This is never set during write */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ +#endif + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ + +#ifdef PNG_cICP_SUPPORTED + /* cICP chunk data */ + png_byte cicp_colour_primaries; + png_byte cicp_transfer_function; + png_byte cicp_matrix_coefficients; + png_byte cicp_video_full_range_flag; +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_bytep iccp_profile; /* International Color Consortium profile data */ + png_uint_32 iccp_proflen; /* ICC profile data length */ +#endif + +#ifdef PNG_cLLI_SUPPORTED + png_uint_32 maxCLL; /* cd/m2 (nits) * 10,000 */ + png_uint_32 maxFALL; +#endif + +#ifdef PNG_mDCV_SUPPORTED + png_uint_16 mastering_red_x; /* CIE (xy) x * 50,000 */ + png_uint_16 mastering_red_y; + png_uint_16 mastering_green_x; + png_uint_16 mastering_green_y; + png_uint_16 mastering_blue_x; + png_uint_16 mastering_blue_y; + png_uint_16 mastering_white_x; + png_uint_16 mastering_white_y; + png_uint_32 mastering_maxDL; /* cd/m2 (nits) * 10,000 */ + png_uint_32 mastering_minDL; +#endif + +#ifdef PNG_TEXT_SUPPORTED + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read or comments to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read or comments to write */ +#endif /* TEXT */ + +#ifdef PNG_tIME_SUPPORTED + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; +#endif + +#ifdef PNG_sBIT_SUPPORTED + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ +defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans_alpha; /* alpha values for paletted image */ + png_color_16 trans_color; /* transparent color for non-palette image */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; +#endif + +#ifdef PNG_oFFs_SUPPORTED + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif + +#ifdef PNG_pHYs_SUPPORTED + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ +#endif + +#ifdef PNG_eXIf_SUPPORTED + png_uint_32 num_exif; /* Added at libpng-1.6.31 */ + png_bytep exif; +#endif + +#ifdef PNG_hIST_SUPPORTED + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ +#endif + +/* New members added in libpng-1.0.6 */ + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + + /* The type of this field is limited by the type of + * png_struct::user_chunk_cache_max, else overflow can occur. + */ + int unknown_chunks_num; +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + int splt_palettes_num; /* Match type returned by png_get API */ +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponding to one pixel + * in the image. Data values are valid if (valid & PNG_INFO_sCAL) is + * non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) + non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ +#endif + +#ifdef PNG_cHRM_SUPPORTED + png_xy cHRM; +#endif + +#ifdef PNG_gAMA_SUPPORTED + png_fixed_point gamma; +#endif + +#ifdef PNG_sRGB_SUPPORTED + int rendering_intent; +#endif +}; +#endif /* PNGINFO_H */ diff --git a/widget/milsko/milskosrc/external/libpng/include/pnglibconf.h b/widget/milsko/milskosrc/external/libpng/include/pnglibconf.h new file mode 100644 index 0000000000..52fab8bfe3 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/include/pnglibconf.h @@ -0,0 +1,237 @@ +/* pnglibconf.h - library build configuration */ + +/* libpng version 1.6.50 */ + +/* Copyright (c) 2018-2025 Cosmin Truta */ +/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */ + +/* This code is released under the libpng license. */ +/* For conditions of distribution and use, see the disclaimer */ +/* and license in png.h */ + +/* pnglibconf.h */ +/* Machine generated file: DO NOT EDIT */ +/* Derived from: scripts/pnglibconf.dfa */ +#ifndef PNGLCONF_H +#define PNGLCONF_H +/* options */ +#define PNG_16BIT_SUPPORTED +#define PNG_ALIGNED_MEMORY_SUPPORTED +/*#undef PNG_ARM_NEON_API_SUPPORTED*/ +/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ +#define PNG_BENIGN_ERRORS_SUPPORTED +#define PNG_BENIGN_READ_ERRORS_SUPPORTED +/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ +#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_COLORSPACE_SUPPORTED +#define PNG_CONSOLE_IO_SUPPORTED +#define PNG_CONVERT_tIME_SUPPORTED +/*#undef PNG_DISABLE_ADLER32_CHECK_SUPPORTED*/ +#define PNG_EASY_ACCESS_SUPPORTED +/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ +#define PNG_ERROR_TEXT_SUPPORTED +#define PNG_FIXED_POINT_SUPPORTED +#define PNG_FLOATING_ARITHMETIC_SUPPORTED +#define PNG_FLOATING_POINT_SUPPORTED +#define PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_BGR_SUPPORTED +#define PNG_GAMMA_SUPPORTED +#define PNG_GET_PALETTE_MAX_SUPPORTED +#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +#define PNG_INCH_CONVERSIONS_SUPPORTED +#define PNG_INFO_IMAGE_SUPPORTED +#define PNG_IO_STATE_SUPPORTED +/*#undef PNG_MIPS_MMI_API_SUPPORTED*/ +/*#undef PNG_MIPS_MMI_CHECK_SUPPORTED*/ +/*#undef PNG_MIPS_MSA_API_SUPPORTED*/ +/*#undef PNG_MIPS_MSA_CHECK_SUPPORTED*/ +#define PNG_MNG_FEATURES_SUPPORTED +#define PNG_POINTER_INDEXING_SUPPORTED +/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/ +/*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/ +#define PNG_PROGRESSIVE_READ_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED +#define PNG_READ_ALPHA_MODE_SUPPORTED +#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_READ_BACKGROUND_SUPPORTED +#define PNG_READ_BGR_SUPPORTED +#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_READ_COMPOSITE_NODIV_SUPPORTED +#define PNG_READ_COMPRESSED_TEXT_SUPPORTED +#define PNG_READ_EXPAND_16_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED +#define PNG_READ_FILLER_SUPPORTED +#define PNG_READ_GAMMA_SUPPORTED +#define PNG_READ_GET_PALETTE_MAX_SUPPORTED +#define PNG_READ_GRAY_TO_RGB_SUPPORTED +#define PNG_READ_INTERLACING_SUPPORTED +#define PNG_READ_INT_FUNCTIONS_SUPPORTED +#define PNG_READ_INVERT_ALPHA_SUPPORTED +#define PNG_READ_INVERT_SUPPORTED +#define PNG_READ_OPT_PLTE_SUPPORTED +#define PNG_READ_PACKSWAP_SUPPORTED +#define PNG_READ_PACK_SUPPORTED +#define PNG_READ_QUANTIZE_SUPPORTED +#define PNG_READ_RGB_TO_GRAY_SUPPORTED +#define PNG_READ_SCALE_16_TO_8_SUPPORTED +#define PNG_READ_SHIFT_SUPPORTED +#define PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED +#define PNG_READ_SUPPORTED +#define PNG_READ_SWAP_ALPHA_SUPPORTED +#define PNG_READ_SWAP_SUPPORTED +#define PNG_READ_TEXT_SUPPORTED +#define PNG_READ_TRANSFORMS_SUPPORTED +#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_READ_USER_CHUNKS_SUPPORTED +#define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_bKGD_SUPPORTED +#define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_cICP_SUPPORTED +#define PNG_READ_cLLI_SUPPORTED +#define PNG_READ_eXIf_SUPPORTED +#define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_hIST_SUPPORTED +#define PNG_READ_iCCP_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED +#define PNG_READ_mDCV_SUPPORTED +#define PNG_READ_oFFs_SUPPORTED +#define PNG_READ_pCAL_SUPPORTED +#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_sBIT_SUPPORTED +#define PNG_READ_sCAL_SUPPORTED +#define PNG_READ_sPLT_SUPPORTED +#define PNG_READ_sRGB_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED +#define PNG_READ_tIME_SUPPORTED +#define PNG_READ_tRNS_SUPPORTED +#define PNG_READ_zTXt_SUPPORTED +#define PNG_SAVE_INT_32_SUPPORTED +#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SEQUENTIAL_READ_SUPPORTED +#define PNG_SETJMP_SUPPORTED +#define PNG_SET_OPTION_SUPPORTED +#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SET_USER_LIMITS_SUPPORTED +#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED +#define PNG_SIMPLIFIED_READ_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_SUPPORTED +#define PNG_STDIO_SUPPORTED +#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_TEXT_SUPPORTED +#define PNG_TIME_RFC1123_SUPPORTED +#define PNG_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_USER_CHUNKS_SUPPORTED +#define PNG_USER_LIMITS_SUPPORTED +#define PNG_USER_MEM_SUPPORTED +#define PNG_USER_TRANSFORM_INFO_SUPPORTED +#define PNG_USER_TRANSFORM_PTR_SUPPORTED +#define PNG_WARNINGS_SUPPORTED +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_WRITE_BGR_SUPPORTED +#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +#define PNG_WRITE_FILLER_SUPPORTED +#define PNG_WRITE_FILTER_SUPPORTED +#define PNG_WRITE_FLUSH_SUPPORTED +#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED +#define PNG_WRITE_INTERLACING_SUPPORTED +#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED +#define PNG_WRITE_INVERT_ALPHA_SUPPORTED +#define PNG_WRITE_INVERT_SUPPORTED +#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED +#define PNG_WRITE_PACKSWAP_SUPPORTED +#define PNG_WRITE_PACK_SUPPORTED +#define PNG_WRITE_SHIFT_SUPPORTED +#define PNG_WRITE_SUPPORTED +#define PNG_WRITE_SWAP_ALPHA_SUPPORTED +#define PNG_WRITE_SWAP_SUPPORTED +#define PNG_WRITE_TEXT_SUPPORTED +#define PNG_WRITE_TRANSFORMS_SUPPORTED +#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_WRITE_USER_TRANSFORM_SUPPORTED +#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#define PNG_WRITE_bKGD_SUPPORTED +#define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_cICP_SUPPORTED +#define PNG_WRITE_cLLI_SUPPORTED +#define PNG_WRITE_eXIf_SUPPORTED +#define PNG_WRITE_gAMA_SUPPORTED +#define PNG_WRITE_hIST_SUPPORTED +#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_WRITE_mDCV_SUPPORTED +#define PNG_WRITE_oFFs_SUPPORTED +#define PNG_WRITE_pCAL_SUPPORTED +#define PNG_WRITE_pHYs_SUPPORTED +#define PNG_WRITE_sBIT_SUPPORTED +#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_sPLT_SUPPORTED +#define PNG_WRITE_sRGB_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_WRITE_tIME_SUPPORTED +#define PNG_WRITE_tRNS_SUPPORTED +#define PNG_WRITE_zTXt_SUPPORTED +#define PNG_bKGD_SUPPORTED +#define PNG_cHRM_SUPPORTED +#define PNG_cICP_SUPPORTED +#define PNG_cLLI_SUPPORTED +#define PNG_eXIf_SUPPORTED +#define PNG_gAMA_SUPPORTED +#define PNG_hIST_SUPPORTED +#define PNG_iCCP_SUPPORTED +#define PNG_iTXt_SUPPORTED +#define PNG_mDCV_SUPPORTED +#define PNG_oFFs_SUPPORTED +#define PNG_pCAL_SUPPORTED +#define PNG_pHYs_SUPPORTED +#define PNG_sBIT_SUPPORTED +#define PNG_sCAL_SUPPORTED +#define PNG_sPLT_SUPPORTED +#define PNG_sRGB_SUPPORTED +#define PNG_tEXt_SUPPORTED +#define PNG_tIME_SUPPORTED +#define PNG_tRNS_SUPPORTED +#define PNG_zTXt_SUPPORTED +/* end of options */ +/* settings */ +#ifdef __WATCOMC__ +#define PNG_API_RULE 2 +#else +#define PNG_API_RULE 0 +#endif +#define PNG_DEFAULT_READ_MACROS 1 +#define PNG_GAMMA_THRESHOLD_FIXED 5000 +#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE +#define PNG_INFLATE_BUF_SIZE 1024 +#define PNG_LINKAGE_API extern +#define PNG_LINKAGE_CALLBACK extern +#define PNG_LINKAGE_DATA extern +#define PNG_LINKAGE_FUNCTION extern +#define PNG_MAX_GAMMA_8 11 +#define PNG_QUANTIZE_BLUE_BITS 5 +#define PNG_QUANTIZE_GREEN_BITS 5 +#define PNG_QUANTIZE_RED_BITS 5 +#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) +#define PNG_TEXT_Z_DEFAULT_STRATEGY 0 +#define PNG_USER_CHUNK_CACHE_MAX 1000 +#define PNG_USER_CHUNK_MALLOC_MAX 8000000 +#define PNG_USER_HEIGHT_MAX 1000000 +#define PNG_USER_WIDTH_MAX 1000000 +#define PNG_ZBUF_SIZE 8192 +#define PNG_ZLIB_VERNUM 0 /* unknown */ +#define PNG_Z_DEFAULT_COMPRESSION (-1) +#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 +#define PNG_Z_DEFAULT_STRATEGY 1 +#define PNG_sCAL_PRECISION 5 +#define PNG_sRGB_PROFILE_CHECKS 2 +/* end of settings */ +#endif /* PNGLCONF_H */ diff --git a/widget/milsko/milskosrc/external/libpng/include/pngpriv.h b/widget/milsko/milskosrc/external/libpng/include/pngpriv.h new file mode 100644 index 0000000000..e3054b90aa --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/include/pngpriv.h @@ -0,0 +1,2217 @@ +/* pngpriv.h - private declarations for use inside libpng + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* The symbols declared in this file (including the functions declared + * as extern) are PRIVATE. They are not part of the libpng public + * interface, and are not recommended for use by regular applications. + * Some of them may become public in the future; others may stay private, + * change in an incompatible way, or even disappear. + * Although the libpng users are not forbidden to include this header, + * they should be well aware of the issues that may arise from doing so. + */ + + +/* pngpriv.h must be included first in each translation unit inside libpng. + * On the other hand, it must not be included at all, directly or indirectly, + * by any application code that uses the libpng API. + */ +#ifndef PNGPRIV_H +# define PNGPRIV_H +#else +# error Duplicate inclusion of pngpriv.h; please check the libpng source files +#endif + +#if defined(PNG_H) || defined(PNGCONF_H) || defined(PNGLCONF_H) +# error This file must not be included by applications; please include +#endif + +/* Feature Test Macros. The following are defined here to ensure that correctly + * implemented libraries reveal the APIs libpng needs to build and hide those + * that are not needed and potentially damaging to the compilation. + * + * Feature Test Macros must be defined before any system header is included (see + * POSIX 1003.1 2.8.2 "POSIX Symbols." + * + * These macros only have an effect if the operating system supports either + * POSIX 1003.1 or C99, or both. On other operating systems (particularly + * Windows/Visual Studio) there is no effect; the OS specific tests below are + * still required (as of 2011-05-02.) + */ +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ +#endif + +#ifndef PNG_VERSION_INFO_ONLY +/* Standard library headers not required by png.h: */ +# include +# include +#endif + +#define PNGLIB_BUILD /*libpng is being built, not used*/ + +/* If HAVE_CONFIG_H is defined during the build then the build system must + * provide an appropriate "config.h" file on the include path. The header file + * must provide definitions as required below (search for "HAVE_CONFIG_H"); + * see configure.ac for more details of the requirements. The macro + * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on + * 'configure'; define this macro to prevent the configure build including the + * configure generated config.h. Libpng is expected to compile without *any* + * special build system support on a reasonably ANSI-C compliant system. + */ +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include + /* Pick up the definition of 'restrict' from config.h if it was read: */ +# define PNG_RESTRICT restrict +#endif + +/* To support symbol prefixing it is necessary to know *before* including png.h + * whether the fixed point (and maybe other) APIs are exported, because if they + * are not internal definitions may be required. This is handled below just + * before png.h is included, but load the configuration now if it is available. + */ +#include "pnglibconf.h" + +/* Local renames may change non-exported API functions from png.h */ +#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) +# include "pngprefix.h" +#endif + +#ifdef PNG_USER_CONFIG +# include "pngusr.h" + /* These should have been defined in pngusr.h */ +# ifndef PNG_USER_PRIVATEBUILD +# define PNG_USER_PRIVATEBUILD "Custom libpng build" +# endif +# ifndef PNG_USER_DLLFNAME_POSTFIX +# define PNG_USER_DLLFNAME_POSTFIX "Cb" +# endif +#endif + +/* Compile time options. + * ===================== + * In a multi-arch build the compiler may compile the code several times for the + * same object module, producing different binaries for different architectures. + * When this happens configure-time setting of the target host options cannot be + * done and this interferes with the handling of the ARM NEON optimizations, and + * possibly other similar optimizations. Put additional tests here; in general + * this is needed when the same option can be changed at both compile time and + * run time depending on the target OS (i.e. iOS vs Android.) + * + * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because + * this is not possible with certain compilers (Oracle SUN OS CC), as a result + * it is necessary to ensure that all extern functions that *might* be used + * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__ + * below is one example of this behavior because it is controlled by the + * presence or not of -mfpu=neon on the GCC command line, it is possible to do + * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely + * do this. + */ +#ifndef PNG_ARM_NEON_OPT + /* ARM NEON optimizations are being controlled by the compiler settings, + * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon + * with GCC) then the compiler will define __ARM_NEON__ and we can rely + * unconditionally on NEON instructions not crashing, otherwise we must + * disable use of NEON instructions. + * + * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they + * can only be turned on automatically if that is supported too. If + * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail + * to compile with an appropriate #error if ALIGNED_MEMORY has been turned + * off. + * + * Note that gcc-4.9 defines __ARM_NEON instead of the deprecated + * __ARM_NEON__, so we check both variants. + * + * To disable ARM_NEON optimizations entirely, and skip compiling the + * associated assembler code, pass --enable-arm-neon=no to configure + * or put -DPNG_ARM_NEON_OPT=0 in CPPFLAGS. + */ +# if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \ + defined(PNG_ALIGNED_MEMORY_SUPPORTED) +# define PNG_ARM_NEON_OPT 2 +# else +# define PNG_ARM_NEON_OPT 0 +# endif +#endif + +#ifndef PNG_RISCV_RVV_OPT + /* RISCV_RVV optimizations are being controlled by the compiler settings, + * typically the target compiler will define __riscv but the rvv extension + * availability has to be explicitly stated. This is why if no + * PNG_RISCV_RVV_OPT was defined then a runtime check will be executed. + * + * To enable RISCV_RVV optimizations unconditionally, and compile the + * associated code, pass --enable-riscv-rvv=yes or --enable-riscv-rvv=on + * to configure or put -DPNG_RISCV_RVV_OPT=2 in CPPFLAGS. + */ + +# define PNG_RISCV_RVV_OPT 0 +#endif + +#if PNG_ARM_NEON_OPT > 0 + /* NEON optimizations are to be at least considered by libpng, so enable the + * callbacks to do this. + */ +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon +# ifndef PNG_ARM_NEON_IMPLEMENTATION + /* Use the intrinsics code by default. */ +# define PNG_ARM_NEON_IMPLEMENTATION 1 +# endif +#else /* PNG_ARM_NEON_OPT == 0 */ +# define PNG_ARM_NEON_IMPLEMENTATION 0 +#endif /* PNG_ARM_NEON_OPT > 0 */ + +#ifndef PNG_MIPS_MSA_OPT +# if defined(__mips_msa) && (__mips_isa_rev >= 5) && \ + defined(PNG_ALIGNED_MEMORY_SUPPORTED) +# define PNG_MIPS_MSA_OPT 2 +# else +# define PNG_MIPS_MSA_OPT 0 +# endif +#endif + +#ifndef PNG_MIPS_MMI_OPT +# ifdef PNG_MIPS_MMI +# if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64) && \ + defined(PNG_ALIGNED_MEMORY_SUPPORTED) +# define PNG_MIPS_MMI_OPT 1 +# else +# define PNG_MIPS_MMI_OPT 0 +# endif +# else +# define PNG_MIPS_MMI_OPT 0 +# endif +#endif + +#ifndef PNG_POWERPC_VSX_OPT +# if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__) +# define PNG_POWERPC_VSX_OPT 2 +# else +# define PNG_POWERPC_VSX_OPT 0 +# endif +#endif + +#ifndef PNG_LOONGARCH_LSX_OPT +# if defined(__loongarch_sx) +# define PNG_LOONGARCH_LSX_OPT 1 +# else +# define PNG_LOONGARCH_LSX_OPT 0 +# endif +#endif + +#ifndef PNG_INTEL_SSE_OPT +# ifdef PNG_INTEL_SSE + /* Only check for SSE if the build configuration has been modified to + * enable SSE optimizations. This means that these optimizations will + * be off by default. See contrib/intel for more details. + */ +# if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \ + defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP >= 2) +# define PNG_INTEL_SSE_OPT 1 +# else +# define PNG_INTEL_SSE_OPT 0 +# endif +# else +# define PNG_INTEL_SSE_OPT 0 +# endif +#endif + +#if PNG_INTEL_SSE_OPT > 0 +# ifndef PNG_INTEL_SSE_IMPLEMENTATION +# if defined(__SSE4_1__) || defined(__AVX__) + /* We are not actually using AVX, but checking for AVX is the best + way we can detect SSE4.1 and SSSE3 on MSVC. + */ +# define PNG_INTEL_SSE_IMPLEMENTATION 3 +# elif defined(__SSSE3__) +# define PNG_INTEL_SSE_IMPLEMENTATION 2 +# elif defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP >= 2) +# define PNG_INTEL_SSE_IMPLEMENTATION 1 +# else +# define PNG_INTEL_SSE_IMPLEMENTATION 0 +# endif +# endif + +# if PNG_INTEL_SSE_IMPLEMENTATION > 0 +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_sse2 +# endif +#else +# define PNG_INTEL_SSE_IMPLEMENTATION 0 +#endif + +#if PNG_MIPS_MSA_OPT > 0 +# ifndef PNG_MIPS_MSA_IMPLEMENTATION +# if defined(__mips_msa) +# if defined(__clang__) +# elif defined(__GNUC__) +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) +# define PNG_MIPS_MSA_IMPLEMENTATION 2 +# endif /* no GNUC support */ +# endif /* __GNUC__ */ +# else /* !defined __mips_msa */ +# define PNG_MIPS_MSA_IMPLEMENTATION 2 +# endif /* __mips_msa */ +# endif /* !PNG_MIPS_MSA_IMPLEMENTATION */ + +# ifndef PNG_MIPS_MSA_IMPLEMENTATION +# define PNG_MIPS_MSA_IMPLEMENTATION 1 +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips +# endif +#else +# define PNG_MIPS_MSA_IMPLEMENTATION 0 +#endif /* PNG_MIPS_MSA_OPT > 0 */ + +#if PNG_MIPS_MMI_OPT > 0 +# ifndef PNG_MIPS_MMI_IMPLEMENTATION +# if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64) +# define PNG_MIPS_MMI_IMPLEMENTATION 2 +# else /* !defined __mips_loongson_mmi || _MIPS_SIM != _ABI64 */ +# define PNG_MIPS_MMI_IMPLEMENTATION 0 +# endif /* __mips_loongson_mmi && _MIPS_SIM == _ABI64 */ +# endif /* !PNG_MIPS_MMI_IMPLEMENTATION */ + +# if PNG_MIPS_MMI_IMPLEMENTATION > 0 +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips +# endif +#else +# define PNG_MIPS_MMI_IMPLEMENTATION 0 +#endif /* PNG_MIPS_MMI_OPT > 0 */ + +#if PNG_POWERPC_VSX_OPT > 0 +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx +# define PNG_POWERPC_VSX_IMPLEMENTATION 1 +#else +# define PNG_POWERPC_VSX_IMPLEMENTATION 0 +#endif + +#if PNG_LOONGARCH_LSX_OPT > 0 +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_lsx +# define PNG_LOONGARCH_LSX_IMPLEMENTATION 1 +#else +# define PNG_LOONGARCH_LSX_IMPLEMENTATION 0 +#endif + +#if PNG_RISCV_RVV_OPT > 0 +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_rvv +# ifndef PNG_RISCV_RVV_IMPLEMENTATION + /* Use the intrinsics code by default. */ +# define PNG_RISCV_RVV_IMPLEMENTATION 1 +# endif +#else +# define PNG_RISCV_RVV_IMPLEMENTATION 0 +#endif + +/* Is this a build of a DLL where compilation of the object modules requires + * different preprocessor settings to those required for a simple library? If + * so PNG_BUILD_DLL must be set. + * + * If libpng is used inside a DLL but that DLL does not export the libpng APIs + * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a + * static library of libpng then link the DLL against that. + */ +#ifndef PNG_BUILD_DLL +# ifdef DLL_EXPORT + /* This is set by libtool when files are compiled for a DLL; libtool + * always compiles twice, even on systems where it isn't necessary. Set + * PNG_BUILD_DLL in case it is necessary: + */ +# define PNG_BUILD_DLL +# else +# ifdef _WINDLL + /* This is set by the Microsoft Visual Studio IDE in projects that + * build a DLL. It can't easily be removed from those projects (it + * isn't visible in the Visual Studio UI) so it is a fairly reliable + * indication that PNG_IMPEXP needs to be set to the DLL export + * attributes. + */ +# define PNG_BUILD_DLL +# else +# ifdef __DLL__ + /* This is set by the Borland C system when compiling for a DLL + * (as above.) + */ +# define PNG_BUILD_DLL +# else + /* Add additional compiler cases here. */ +# endif +# endif +# endif +#endif /* Setting PNG_BUILD_DLL if required */ + +/* See pngconf.h for more details: the builder of the library may set this on + * the command line to the right thing for the specific compilation system or it + * may be automagically set above (at present we know of no system where it does + * need to be set on the command line.) + * + * PNG_IMPEXP must be set here when building the library to prevent pngconf.h + * setting it to the "import" setting for a DLL build. + */ +#ifndef PNG_IMPEXP +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP PNG_DLL_EXPORT +# else + /* Not building a DLL, or the DLL doesn't require specific export + * definitions. + */ +# define PNG_IMPEXP +# endif +#endif + +/* No warnings for private or deprecated functions in the build: */ +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE +#endif + +/* Symbol preprocessing support. + * + * To enable listing global, but internal, symbols the following macros should + * always be used to declare an extern data or function object in this file. + */ +#ifndef PNG_INTERNAL_DATA +# define PNG_INTERNAL_DATA(type, name, array) PNG_LINKAGE_DATA type name array +#endif + +#ifndef PNG_INTERNAL_FUNCTION +# define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ + PNG_LINKAGE_FUNCTION PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) +#endif + +#ifndef PNG_INTERNAL_CALLBACK +# define PNG_INTERNAL_CALLBACK(type, name, args, attributes)\ + PNG_LINKAGE_CALLBACK PNG_FUNCTION(type, (PNGCBAPI name), args,\ + PNG_EMPTY attributes) +#endif + +/* If floating or fixed point APIs are disabled they may still be compiled + * internally. To handle this make sure they are declared as the appropriate + * internal extern function (otherwise the symbol prefixing stuff won't work and + * the functions will be used without definitions.) + * + * NOTE: although all the API functions are declared here they are not all + * actually built! Because the declarations are still made it is necessary to + * fake out types that they depend on. + */ +#ifndef PNG_FP_EXPORT +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# ifndef PNG_VERSION_INFO_ONLY + typedef struct png_incomplete png_double; + typedef png_double* png_doublep; + typedef const png_double* png_const_doublep; + typedef png_double** png_doublepp; +# endif +# endif +#endif +#ifndef PNG_FIXED_EXPORT +# ifndef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# endif +#endif + +#include "png.h" + +/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ +#ifndef PNG_DLL_EXPORT +# define PNG_DLL_EXPORT +#endif + +/* This is a global switch to set the compilation for an installed system + * (a release build). It can be set for testing debug builds to ensure that + * they will compile when the build type is switched to RC or STABLE, the + * default is just to use PNG_LIBPNG_BUILD_BASE_TYPE. Set this in CPPFLAGS + * with either: + * + * -DPNG_RELEASE_BUILD Turns on the release compile path + * -DPNG_RELEASE_BUILD=0 Turns it off + * or in your pngusr.h with + * #define PNG_RELEASE_BUILD=1 Turns on the release compile path + * #define PNG_RELEASE_BUILD=0 Turns it off + */ +#ifndef PNG_RELEASE_BUILD +# define PNG_RELEASE_BUILD (PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC) +#endif + +/* SECURITY and SAFETY: + * + * libpng is built with support for internal limits on image dimensions and + * memory usage. These are documented in scripts/pnglibconf.dfa of the + * source and recorded in the machine generated header file pnglibconf.h. + */ + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. + * + * zlib provides 'MAXSEG_64K' which, if defined, indicates the + * same limit and pngconf.h (already included) sets the limit + * if certain operating systems are detected. + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +#ifndef PNG_UNUSED +/* Unused formal parameter warnings are silenced using the following macro + * which is expected to have no bad effects on performance (optimizing + * compilers will probably remove it entirely). Note that if you replace + * it with something other than whitespace, you must include the terminating + * semicolon. + */ +# define PNG_UNUSED(param) (void)param; +#endif + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536L +#endif + +/* If warnings or errors are turned off the code is disabled or redirected here. + * From 1.5.4 functions have been added to allow very limited formatting of + * error and warning messages - this code will also be disabled here. + */ +#ifdef PNG_WARNINGS_SUPPORTED +# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; +#else +# define png_warning_parameter(p,number,string) ((void)0) +# define png_warning_parameter_unsigned(p,number,format,value) ((void)0) +# define png_warning_parameter_signed(p,number,format,value) ((void)0) +# define png_formatted_warning(pp,p,message) ((void)(pp)) +# define PNG_WARNING_PARAMETERS(p) +#endif +#ifndef PNG_ERROR_TEXT_SUPPORTED +# define png_fixed_error(s1,s2) png_err(s1) +#endif + +/* Some fixed point APIs are still required even if not exported because + * they get used by the corresponding floating point APIs. This magic + * deals with this: + */ +#ifdef PNG_FIXED_POINT_SUPPORTED +# define PNGFAPI PNGAPI +#else +# define PNGFAPI /* PRIVATE */ +#endif + +#ifndef PNG_VERSION_INFO_ONLY +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ + +/* C allows up-casts from (void*) to any pointer and (const void*) to any + * pointer to a const object. C++ regards this as a type error and requires an + * explicit, static, cast and provides the static_cast<> rune to ensure that + * const is not cast away. + */ +#ifdef __cplusplus +# define png_voidcast(type, value) static_cast(value) +# define png_constcast(type, value) const_cast(value) +# define png_aligncast(type, value) \ + static_cast(static_cast(value)) +# define png_aligncastconst(type, value) \ + static_cast(static_cast(value)) +#else +# define png_voidcast(type, value) (value) +# define png_constcast(type, value) ((type)(void*)(const void*)(value)) +# define png_aligncast(type, value) ((void*)(value)) +# define png_aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) + /* png.c requires the following ANSI-C constants if the conversion of + * floating point to ASCII is implemented therein: + * + * DBL_DIG Maximum number of decimal digits (can be set to any constant) + * DBL_MIN Smallest normalized fp number (can be set to an arbitrary value) + * DBL_MAX Maximum floating point number (can be set to an arbitrary value) + */ +# include + +# include + +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* This provides the non-ANSI (far) memory allocation routines. */ +#if defined(__TURBOC__) && defined(__MSDOS__) +# include +# include +#endif + +#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +# include +#endif +#endif /* PNG_VERSION_INFO_ONLY */ + +/* Moved here around 1.5.0beta36 from pngconf.h */ +/* Users may want to use these so they are not private. Any library + * functions that are passed far data must be model-independent. + */ + +/* Platform-independent functions */ +#ifndef PNG_ABORT +# define PNG_ABORT() abort() +#endif + +/* These macros may need to be architecture dependent. */ +#define PNG_ALIGN_NONE 0 /* do not use data alignment */ +#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ +#ifdef offsetof +# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ +#else +# define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ +#endif +#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ + +#ifndef PNG_ALIGN_TYPE + /* Default to using aligned access optimizations and requiring alignment to a + * multiple of the data type size. Override in a compiler specific fashion + * if necessary by inserting tests here: + */ +# define PNG_ALIGN_TYPE PNG_ALIGN_SIZE +#endif + +#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE + /* This is used because in some compiler implementations non-aligned + * structure members are supported, so the offsetof approach below fails. + * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access + * is good for performance. Do not do this unless you have tested the + * result and understand it. + */ +# define png_alignof(type) (sizeof(type)) +#else +# if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET +# define png_alignof(type) offsetof(struct{char c; type t;}, t) +# else +# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS +# define png_alignof(type) 1 +# endif + /* Else leave png_alignof undefined to prevent use thereof */ +# endif +#endif + +/* This implicitly assumes alignment is always a multiple of 2. */ +#ifdef png_alignof +# define png_isaligned(ptr, type) \ + (((type)(size_t)((const void*)(ptr)) & (type)(png_alignof(type)-1)) == 0) +#else +# define png_isaligned(ptr, type) 0 +#endif + +/* End of memory model/platform independent support */ +/* End of 1.5.0beta36 move from pngconf.h */ + +/* CONSTANTS and UTILITY MACROS + * These are used internally by libpng and not exposed in the API + */ + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. Three of these + * are defined in png.h because they need to be visible to applications + * that call png_set_unknown_chunk(). + */ +/* #define PNG_HAVE_IHDR 0x01U (defined in png.h) */ +/* #define PNG_HAVE_PLTE 0x02U (defined in png.h) */ +#define PNG_HAVE_IDAT 0x04U +/* #define PNG_AFTER_IDAT 0x08U (defined in png.h) */ +#define PNG_HAVE_IEND 0x10U + /* 0x20U (unused) */ + /* 0x40U (unused) */ + /* 0x80U (unused) */ +#define PNG_HAVE_CHUNK_HEADER 0x100U +#define PNG_WROTE_tIME 0x200U +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400U +#define PNG_BACKGROUND_IS_GRAY 0x800U +#define PNG_HAVE_PNG_SIGNATURE 0x1000U +#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */ +#define PNG_WROTE_eXIf 0x4000U +#define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */ + +/* Flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001U +#define PNG_INTERLACE 0x0002U +#define PNG_PACK 0x0004U +#define PNG_SHIFT 0x0008U +#define PNG_SWAP_BYTES 0x0010U +#define PNG_INVERT_MONO 0x0020U +#define PNG_QUANTIZE 0x0040U +#define PNG_COMPOSE 0x0080U /* Was PNG_BACKGROUND */ +#define PNG_BACKGROUND_EXPAND 0x0100U +#define PNG_EXPAND_16 0x0200U /* Added to libpng 1.5.2 */ +#define PNG_16_TO_8 0x0400U /* Becomes 'chop' in 1.5.4 */ +#define PNG_RGBA 0x0800U +#define PNG_EXPAND 0x1000U +#define PNG_GAMMA 0x2000U +#define PNG_GRAY_TO_RGB 0x4000U +#define PNG_FILLER 0x8000U +#define PNG_PACKSWAP 0x10000U +#define PNG_SWAP_ALPHA 0x20000U +#define PNG_STRIP_ALPHA 0x40000U +#define PNG_INVERT_ALPHA 0x80000U +#define PNG_USER_TRANSFORM 0x100000U +#define PNG_RGB_TO_GRAY_ERR 0x200000U +#define PNG_RGB_TO_GRAY_WARN 0x400000U +#define PNG_RGB_TO_GRAY 0x600000U /* two bits, RGB_TO_GRAY_ERR|WARN */ +#define PNG_ENCODE_ALPHA 0x800000U /* Added to libpng-1.5.4 */ +#define PNG_ADD_ALPHA 0x1000000U /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000U /* Added to libpng-1.2.9 */ +#define PNG_SCALE_16_TO_8 0x4000000U /* Added to libpng-1.5.4 */ + /* 0x8000000U unused */ + /* 0x10000000U unused */ + /* 0x20000000U unused */ + /* 0x40000000U unused */ +/* Flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001U +#define PNG_STRUCT_INFO 0x0002U + +/* Flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001U +#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002U /* Added to libpng-1.6.0 */ + /* 0x0004U unused */ +#define PNG_FLAG_ZSTREAM_ENDED 0x0008U /* Added to libpng-1.6.0 */ + /* 0x0010U unused */ + /* 0x0020U unused */ +#define PNG_FLAG_ROW_INIT 0x0040U +#define PNG_FLAG_FILLER_AFTER 0x0080U +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100U +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200U +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400U +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800U +/* PNG_FLAG_ASSUME_sRGB unused 0x1000U * Added to libpng-1.5.4 */ +#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000U /* Added to libpng-1.5.4 */ +#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000U /* Added to libpng-1.5.4 */ +/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000U */ +/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000U */ +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000U +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000U +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000U +#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000U /* Added to libpng-1.4.0 */ +#define PNG_FLAG_APP_WARNINGS_WARN 0x200000U /* Added to libpng-1.6.0 */ +#define PNG_FLAG_APP_ERRORS_WARN 0x400000U /* Added to libpng-1.6.0 */ + /* 0x800000U unused */ + /* 0x1000000U unused */ + /* 0x2000000U unused */ + /* 0x4000000U unused */ + /* 0x8000000U unused */ + /* 0x10000000U unused */ + /* 0x20000000U unused */ + /* 0x40000000U unused */ + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* Save typing and make code easier to understand */ + +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255 + * by dividing by 257 *with rounding*. This macro is exact for the given range. + * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the + * macro were established by experiment (modifying the added value). The macro + * has a second variant that takes a value already scaled by 255 and divides by + * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it + * only gives off-by-one errors and only for 0.5% (1 in 200) of the values. + */ +#define PNG_DIV65535(v24) (((v24) + 32895) >> 16) +#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255) + +/* Added to libpng-1.2.6 JB */ +#define PNG_ROWBYTES(pixel_bits, width) \ + ((pixel_bits) >= 8 ? \ + ((size_t)(width) * (((size_t)(pixel_bits)) >> 3)) : \ + (( ((size_t)(width) * ((size_t)(pixel_bits))) + 7) >> 3) ) + +/* This returns the number of trailing bits in the last byte of a row, 0 if the + * last byte is completely full of pixels. It is, in principle, (pixel_bits x + * width) % 8, but that would overflow for large 'width'. The second macro is + * the same except that it returns the number of unused bits in the last byte; + * (8-TRAILBITS), but 0 when TRAILBITS is 0. + * + * NOTE: these macros are intended to be self-evidently correct and never + * overflow on the assumption that pixel_bits is in the range 0..255. The + * arguments are evaluated only once and they can be signed (e.g. as a result of + * the integral promotions). The result of the expression always has type + * (png_uint_32), however the compiler always knows it is in the range 0..7. + */ +#define PNG_TRAILBITS(pixel_bits, width) \ + (((pixel_bits) * ((width) % (png_uint_32)8)) % 8) + +#define PNG_PADBITS(pixel_bits, width) \ + ((8 - PNG_TRAILBITS(pixel_bits, width)) % 8) + +/* PNG_OUT_OF_RANGE returns true if value is outside the range + * ideal-delta..ideal+delta. Each argument is evaluated twice. + * "ideal" and "delta" should be constants, normally simple + * integers, "value" a variable. Added to libpng-1.2.6 JB + */ +#define PNG_OUT_OF_RANGE(value, ideal, delta) \ + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + +/* Conversions between fixed and floating point, only defined if + * required (to make sure the code doesn't accidentally use float + * when it is supposedly disabled.) + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* The floating point conversion can't overflow, though it can and + * does lose accuracy relative to the original fixed point value. + * In practice this doesn't matter because png_fixed_point only + * stores numbers with very low precision. The png_ptr and s + * arguments are unused by default but are there in case error + * checking becomes a requirement. + */ +#define png_float(png_ptr, fixed, s) (.00001 * (fixed)) + +/* The fixed point conversion performs range checking and evaluates + * its argument multiple times, so must be used with care. The + * range checking uses the PNG specification values for a signed + * 32-bit fixed point value except that the values are deliberately + * rounded-to-zero to an integral value - 21474 (21474.83 is roughly + * (2^31-1) * 100000). 's' is a string that describes the value being + * converted. + * + * NOTE: this macro will raise a png_error if the range check fails, + * therefore it is normally only appropriate to use this on values + * that come from API calls or other sources where an out of range + * error indicates a programming error, not a data error! + * + * NOTE: by default this is off - the macro is not used - because the + * function call saves a lot of code. + */ +#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED +#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ + ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) +#define png_fixed_ITU(png_ptr, fp, s) ((fp) <= 214748 && (fp) >= 0 ?\ + ((png_uint_32)(10000 * (fp))) : (png_fixed_error(png_ptr, s),0)) +#endif +/* else the corresponding function is defined below, inside the scope of the + * cplusplus test. + */ +#endif + +/* Constants for known chunk types. If you need to add a chunk, define the name + * here. For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. + * + * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values + * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string + * to be generated if required. + * + * PNG_32b correctly produces a value shifted by up to 24 bits, even on + * architectures where (int) is only 16 bits. + * + * 1.6.47: PNG_32b was made into a preprocessor evaluable macro by replacing the + * static_cast with a promoting binary operation using a guaranteed 32-bit + * (minimum) unsigned value. + */ +#define PNG_32b(b,s) (((0xFFFFFFFFU)&(b)) << (s)) +#define PNG_U32(b1,b2,b3,b4) \ + (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) + +/* Chunk name validation. When using these macros all the arguments should be + * constants, otherwise code bloat may well occur. The macros are provided + * primarily for use in #if checks. + * + * PNG_32to8 produces a byte value with the right shift; used to extract the + * byte value from a chunk name. + */ +#define PNG_32to8(cn,s) (((cn) >> (s)) & 0xffU) +#define PNG_CN_VALID_UPPER(b) ((b) >= 65 && (b) <= 90) /* upper-case ASCII */ +#define PNG_CN_VALID_ASCII(b) PNG_CN_VALID_UPPER((b) & ~32U) +#define PNG_CHUNK_NAME_VALID(cn) (\ + PNG_CN_VALID_ASCII(PNG_32to8(cn,24)) && /* critical, !ancillary */\ + PNG_CN_VALID_ASCII(PNG_32to8(cn,16)) && /* public, !privately defined */\ + PNG_CN_VALID_UPPER(PNG_32to8(cn, 8)) && /* VALID, !reserved */\ + PNG_CN_VALID_ASCII(PNG_32to8(cn, 0)) /* data-dependent, !copy ok */) + +/* Constants for known chunk types. + * + * MAINTAINERS: If you need to add a chunk, define the name here. + * For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. Please keep the list sorted. + * + * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk + * type. In fact the specification does not express chunk types this way, + * however using a 32-bit value means that the chunk type can be read from the + * stream using exactly the same code as used for a 32-bit unsigned value and + * can be examined far more efficiently (using one arithmetic compare). + * + * Prior to 1.5.6 the chunk type constants were expressed as C strings. The + * libpng API still uses strings for 'unknown' chunks and a macro, + * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice + * that for portable code numeric values must still be used; the string "IHDR" + * is not portable and neither is PNG_U32('I', 'H', 'D', 'R'). + * + * In 1.7.0 the definitions will be made public in png.h to avoid having to + * duplicate the same definitions in application code. + */ +#define png_IDAT PNG_U32( 73, 68, 65, 84) +#define png_IEND PNG_U32( 73, 69, 78, 68) +#define png_IHDR PNG_U32( 73, 72, 68, 82) +#define png_PLTE PNG_U32( 80, 76, 84, 69) +#define png_acTL PNG_U32( 97, 99, 84, 76) /* PNGv3: APNG */ +#define png_bKGD PNG_U32( 98, 75, 71, 68) +#define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_cICP PNG_U32( 99, 73, 67, 80) /* PNGv3 */ +#define png_cLLI PNG_U32( 99, 76, 76, 73) /* PNGv3 */ +#define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */ +#define png_fcTL PNG_U32(102, 99, 84, 76) /* PNGv3: APNG */ +#define png_fdAT PNG_U32(102, 100, 65, 84) /* PNGv3: APNG */ +#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ +#define png_gAMA PNG_U32(103, 65, 77, 65) +#define png_gIFg PNG_U32(103, 73, 70, 103) +#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ +#define png_gIFx PNG_U32(103, 73, 70, 120) +#define png_hIST PNG_U32(104, 73, 83, 84) +#define png_iCCP PNG_U32(105, 67, 67, 80) +#define png_iTXt PNG_U32(105, 84, 88, 116) +#define png_mDCV PNG_U32(109, 68, 67, 86) /* PNGv3 */ +#define png_oFFs PNG_U32(111, 70, 70, 115) +#define png_pCAL PNG_U32(112, 67, 65, 76) +#define png_pHYs PNG_U32(112, 72, 89, 115) +#define png_sBIT PNG_U32(115, 66, 73, 84) +#define png_sCAL PNG_U32(115, 67, 65, 76) +#define png_sPLT PNG_U32(115, 80, 76, 84) +#define png_sRGB PNG_U32(115, 82, 71, 66) +#define png_sTER PNG_U32(115, 84, 69, 82) +#define png_tEXt PNG_U32(116, 69, 88, 116) +#define png_tIME PNG_U32(116, 73, 77, 69) +#define png_tRNS PNG_U32(116, 82, 78, 83) +#define png_zTXt PNG_U32(122, 84, 88, 116) + +/* The following will work on (signed char*) strings, whereas the get_uint_32 + * macro will fail on top-bit-set values because of the sign extension. + */ +#define PNG_CHUNK_FROM_STRING(s)\ + PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3]) + +/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is + * signed and the argument is a (char[]) This macro will fail miserably on + * systems where (char) is more than 8 bits. + */ +#define PNG_STRING_FROM_CHUNK(s,c)\ + (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \ + ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\ + ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \ + ((char*)(s))[3]=(char)((c & 0xff))) + +/* Do the same but terminate with a null character. */ +#define PNG_CSTRING_FROM_CHUNK(s,c)\ + (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0) + +/* Test on flag values as defined in the spec (section 5.4): */ +#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) +#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) +#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) +#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) +#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) + +/* Known chunks. All supported chunks must be listed here. The macro PNG_CHUNK + * contains the four character ASCII name by which the chunk is identified. The + * macro is implemented as required to build tables or switch statements which + * require entries for every known chunk. The macro also contains an index + * value which should be in order (this is checked in png.c). + * + * Notice that "known" does not require "SUPPORTED"; tables should be built in + * such a way that chunks unsupported in a build require no more than the table + * entry (which should be small.) In particular function pointers for + * unsupported chunks should be NULL. + * + * At present these index values are not exported (not part of the public API) + * so can be changed at will. For convenience the names are in lexical sort + * order but with the critical chunks at the start in the order of occurence in + * a PNG. + * + * PNG_INFO_ values do not exist for every one of these chunk handles; for + * example PNG_INFO_{IDAT,IEND,tEXt,iTXt,zTXt} and possibly other chunks in the + * future. + */ +#define PNG_KNOWN_CHUNKS\ + PNG_CHUNK(IHDR, 0)\ + PNG_CHUNK(PLTE, 1)\ + PNG_CHUNK(IDAT, 2)\ + PNG_CHUNK(IEND, 3)\ + PNG_CHUNK(acTL, 4)\ + PNG_CHUNK(bKGD, 5)\ + PNG_CHUNK(cHRM, 6)\ + PNG_CHUNK(cICP, 7)\ + PNG_CHUNK(cLLI, 8)\ + PNG_CHUNK(eXIf, 9)\ + PNG_CHUNK(fcTL, 10)\ + PNG_CHUNK(fdAT, 11)\ + PNG_CHUNK(gAMA, 12)\ + PNG_CHUNK(hIST, 13)\ + PNG_CHUNK(iCCP, 14)\ + PNG_CHUNK(iTXt, 15)\ + PNG_CHUNK(mDCV, 16)\ + PNG_CHUNK(oFFs, 17)\ + PNG_CHUNK(pCAL, 18)\ + PNG_CHUNK(pHYs, 19)\ + PNG_CHUNK(sBIT, 20)\ + PNG_CHUNK(sCAL, 21)\ + PNG_CHUNK(sPLT, 22)\ + PNG_CHUNK(sRGB, 23)\ + PNG_CHUNK(tEXt, 24)\ + PNG_CHUNK(tIME, 25)\ + PNG_CHUNK(tRNS, 26)\ + PNG_CHUNK(zTXt, 27) + +/* Gamma values (new at libpng-1.5.4): */ +#define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ +#define PNG_GAMMA_MAC_INVERSE 65909 +#define PNG_GAMMA_sRGB_INVERSE 45455 + +/* gamma sanity check. libpng cannot implement gamma transforms outside a + * certain limit because of its use of 16-bit fixed point intermediate values. + * Gamma values that are too large or too small will zap the 16-bit values all + * to 0 or 65535 resulting in an obvious 'bad' image. + * + * In libpng 1.6.0 the limits were changed from 0.07..3 to 0.01..100 to + * accommodate the optimal 16-bit gamma of 36 and its reciprocal. + * + * These are png_fixed_point integral values: + */ +#define PNG_LIB_GAMMA_MIN 1000 +#define PNG_LIB_GAMMA_MAX 10000000 + +/* Almost everything below is C specific; the #defines above can be used in + * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. + */ +#ifndef PNG_VERSION_INFO_ONLY + +#include "pngstruct.h" +#include "pnginfo.h" + +/* Validate the include paths - the include path used to generate pnglibconf.h + * must match that used in the build, or we must be using pnglibconf.h.prebuilt: + */ +#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM +# error The include path of is incorrect + /* When pnglibconf.h was built, the copy of zlib.h that it used was not the + * same as the one being used here. Considering how libpng makes decisions + * to use the zlib API based on the zlib version number, the -I options must + * match. + * + * A possible cause of this mismatch is that you passed an -I option in + * CFLAGS, which is unlikely to work. All the preprocessor options, and all + * the -I options in particular, should be in CPPFLAGS. + */ +#endif + +/* This is used for 16-bit gamma tables -- only the top level pointers are + * const; this could be changed: + */ +typedef const png_uint_16p * png_const_uint_16pp; + +/* Added to libpng-1.5.7: sRGB conversion tables */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); + /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value, + * 0..65535. This table gives the closest 16-bit answers (no errors). + */ +#endif + +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); +PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); + +#define PNG_sRGB_FROM_LINEAR(linear) \ + ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \ + + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8))) + /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB + * encoded value with maximum error 0.646365. Note that the input is not a + * 16-bit value; it has been multiplied by 255! */ +#endif /* SIMPLIFIED_READ/WRITE */ + + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Internal functions; these are not exported from a DLL however because they + * are used within several of the C source files they have to be C extern. + * + * All of these functions must be declared with PNG_INTERNAL_FUNCTION. + */ +/* Zlib support */ +#define PNG_UNEXPECTED_ZLIB_RETURN (-7) +PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), + PNG_EMPTY); + /* Used by the zlib handling functions to ensure that z_stream::msg is always + * set before they return. + */ + +#ifdef PNG_WRITE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, + png_compression_bufferp *list),PNG_EMPTY); + /* Free the buffer list used by the compressed write code. */ +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_mDCV_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, + double fp, png_const_charp text),PNG_EMPTY); +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED)) +PNG_INTERNAL_FUNCTION(png_uint_32,png_fixed_ITU,(png_const_structrp png_ptr, + double fp, png_const_charp text),PNG_EMPTY); +#endif + +/* Check the user version string for compatibility, returns false if the version + * numbers aren't compatible. + */ +PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, + png_const_charp user_png_ver),PNG_EMPTY); + +#ifdef PNG_READ_SUPPORTED /* should only be used on read */ +/* Security: read limits on the largest allocations while reading a PNG. This + * avoids very large allocations caused by PNG files with damaged or altered + * chunk 'length' fields. + */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED /* run-time limit */ +# define png_chunk_max(png_ptr) ((png_ptr)->user_chunk_malloc_max) + +#elif PNG_USER_CHUNK_MALLOC_MAX > 0 /* compile-time limit */ +# define png_chunk_max(png_ptr) ((void)png_ptr, PNG_USER_CHUNK_MALLOC_MAX) + +#elif (defined PNG_MAX_MALLOC_64K) /* legacy system limit */ +# define png_chunk_max(png_ptr) ((void)png_ptr, 65536U) + +#else /* modern system limit SIZE_MAX (C99) */ +# define png_chunk_max(png_ptr) ((void)png_ptr, PNG_SIZE_MAX) +#endif +#endif /* READ */ + +/* Internal base allocator - no messages, NULL on failure to allocate. This + * does, however, call the application provided allocator and that could call + * png_error (although that would be a bug in the application implementation.) + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, + png_alloc_size_t size),PNG_ALLOCATED); + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* Internal array allocator, outputs no error or warning messages on failure, + * just returns NULL. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, + int nelements, size_t element_size),PNG_ALLOCATED); + +/* The same but an existing array is extended by add_elements. This function + * also memsets the new elements to 0 and copies the old elements. The old + * array is not freed or altered. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, + png_const_voidp array, int old_elements, int add_elements, + size_t element_size),PNG_ALLOCATED); +#endif /* text, sPLT or unknown chunks */ + +/* Magic to create a struct when there is no struct to call the user supplied + * memory allocators. Because error handling has not been set up the memory + * handlers can't safely call png_error, but this is an obscure and undocumented + * restriction so libpng has to assume that the 'free' handler, at least, might + * call png_error. + */ +PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, + png_free_ptr free_fn),PNG_ALLOCATED); + +/* Free memory from internal libpng struct */ +PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), + PNG_EMPTY); + +/* Free an allocated jmp_buf (always succeeds) */ +PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); + +/* Function to allocate memory for zlib. PNGAPI is disallowed. */ +PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), + PNG_ALLOCATED); + +/* Function to free memory for zlib. PNGAPI is disallowed. */ +PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); + +/* Next four functions are used internally as callbacks. PNGCBAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to + * PNGCBAPI at 1.5.0 + */ + +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, + png_bytep data, size_t length),PNG_EMPTY); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, + png_bytep buffer, size_t length),PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, + png_bytep data, size_t length),PNG_EMPTY); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), + PNG_EMPTY); +# endif +#endif + +/* Reset the CRC variable */ +PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); + +/* Write the "data" buffer to whatever output you are using */ +PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, + png_const_bytep data, size_t length),PNG_EMPTY); + +/* Read and check the PNG file signature */ +PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); + +/* Read the chunk header (length + type name) */ +PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), + PNG_EMPTY); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, + size_t length),PNG_EMPTY); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, + png_uint_32 length),PNG_EMPTY); + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, + png_uint_32 skip),PNG_EMPTY); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, + png_const_bytep ptr, size_t length),PNG_EMPTY); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); +#endif + +/* Write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, + int compression_method, int filter_method, int interlace_method),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, + png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, + png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); + +#ifdef PNG_WRITE_gAMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, + png_fixed_point file_gamma),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, + png_const_color_8p sbit, int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, + const png_xy *xy), PNG_EMPTY); + /* The xy value must have been previously validated */ +#endif + +#ifdef PNG_WRITE_cICP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_cICP,(png_structrp png_ptr, + png_byte colour_primaries, png_byte transfer_function, + png_byte matrix_coefficients, png_byte video_full_range_flag), PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_cLLI_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_cLLI_fixed,(png_structrp png_ptr, + png_uint_32 maxCLL, png_uint_32 maxFALL), PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_mDCV_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_mDCV_fixed,(png_structrp png_ptr, + png_uint_16 red_x, png_uint_16 red_y, + png_uint_16 green_x, png_uint_16 green_y, + png_uint_16 blue_x, png_uint_16 blue_y, + png_uint_16 white_x, png_uint_16 white_y, + png_uint_32 maxDL, png_uint_32 minDL), PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, + int intent),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_eXIf_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_eXIf,(png_structrp png_ptr, + png_bytep exif, int num_exif),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, + png_const_charp name, png_const_bytep profile, png_uint_32 proflen), + PNG_EMPTY); + /* Writes a previously 'set' profile. The profile argument is **not** + * compressed. + */ +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, + png_const_sPLT_tp palette),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, + png_const_bytep trans, png_const_color_16p values, int number, + int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, + png_const_color_16p values, int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, + png_const_uint_16p hist, int num_hist),PNG_EMPTY); +#endif + +/* Chunks that have keywords */ +#ifdef PNG_WRITE_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, + png_const_charp key, png_const_charp text, size_t text_len),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp + key, png_const_charp text, int compression),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, + int compression, png_const_charp key, png_const_charp lang, + png_const_charp lang_key, png_const_charp text),PNG_EMPTY); +#endif + +#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ +PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_const_charp units, png_charpp params),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, + png_const_timep mod_time),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, + int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); +#endif + +/* Called when finished processing a row of data */ +PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + +/* Internal use only. Called before first row of data */ +PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), + PNG_EMPTY); + +/* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an + * array of png_ptr->width pixels. If the image is not interlaced or this + * is the final pass this just does a memcpy, otherwise the "display" flag + * is used to determine whether to copy pixels that are not in the current pass. + * + * Because 'png_do_read_interlace' (below) replicates pixels this allows this + * function to achieve the documented 'blocky' appearance during interlaced read + * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row' + * are not changed if they are not in the current pass, when display is 0. + * + * 'display' must be 0 or 1, otherwise the memcpy will be done regardless. + * + * The API always reads from the png_struct row buffer and always assumes that + * it is full width (png_do_read_interlace has already been called.) + * + * This function is only ever used to write to row buffers provided by the + * caller of the relevant libpng API and the row must have already been + * transformed by the read transformations. + * + * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed + * bitmasks for use within the code, otherwise runtime generated masks are used. + * The default is compile time masks. + */ +#ifndef PNG_USE_COMPILE_TIME_MASKS +# define PNG_USE_COMPILE_TIME_MASKS 1 +#endif +PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, + png_bytep row, int display),PNG_EMPTY); + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Expand an interlaced row: the 'row_info' describes the pass data that has + * been read in and must correspond to the pixels in 'row', the pixels are + * expanded (moved apart) in 'row' to match the final layout, when doing this + * the pixels are *replicated* to the intervening space. This is essential for + * the correct operation of png_combine_row, above. + */ +PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Grab pixels out of a row for an interlaced pass */ +PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, + png_bytep row, int pass),PNG_EMPTY); +#endif + +/* Unfilter a row: check the filter value before calling this, there is no point + * calling it for PNG_FILTER_VALUE_NONE. + */ +PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop + row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); + +#if PNG_ARM_NEON_OPT > 0 +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +#endif + +#if PNG_MIPS_MSA_IMPLEMENTATION == 1 +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_msa,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_msa,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_msa,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_msa,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_msa,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_msa,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_msa,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +#endif + +#if PNG_MIPS_MMI_IMPLEMENTATION > 0 +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_mmi,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_mmi,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_mmi,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_mmi,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_mmi,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_mmi,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_mmi,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +#endif + +#if PNG_POWERPC_VSX_OPT > 0 +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_vsx,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_vsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_vsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_vsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_vsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_vsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_vsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +#endif + +#if PNG_INTEL_SSE_IMPLEMENTATION > 0 +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_sse2,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_sse2,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_sse2,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_sse2,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_sse2,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +#endif + +#if PNG_LOONGARCH_LSX_IMPLEMENTATION == 1 +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_lsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_lsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_lsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_lsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_lsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_lsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +#endif + +#if PNG_RISCV_RVV_OPT > 0 +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_rvv,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_rvv,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_rvv,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_rvv,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_rvv,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_rvv,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_rvv,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +#endif + +/* Choose the best filter to use and filter the row data */ +PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, + png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); + /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer + * is NULL the function checks, instead, for the end of the stream. In this + * case a benign error will be issued if the stream end is not found or if + * extra data has to be consumed. + */ +PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), + PNG_EMPTY); + /* This cleans up when the IDAT LZ stream does not end when the last image + * byte is read; there is still some pending input. + */ + +PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + /* Finish a row while reading, dealing with interlacing passes, etc. */ +#endif /* SEQUENTIAL_READ */ + +/* Initialize the row buffers, etc. */ +PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); + +#if ZLIB_VERNUM >= 0x1240 +PNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush), + PNG_EMPTY); +# define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush) +#else /* Zlib < 1.2.4 */ +# define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush) +#endif /* Zlib < 1.2.4 */ + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Optional call to update the users info structure */ +PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +#endif + +/* Shared transform functions, defined in pngtran.c */ +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, + png_bytep row, int at_start),PNG_EMPTY); +#endif + +#ifdef PNG_16BIT_SUPPORTED +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ +typedef enum +{ + /* Result of a call to png_handle_chunk made to handle the current chunk + * png_struct::chunk_name on read. Always informational, either the stream + * is read for the next chunk or the routine will call png_error. + * + * NOTE: order is important internally. handled_saved and above are regarded + * as handling the chunk. + */ + handled_error = 0, /* bad crc or known and bad format or too long */ + handled_discarded, /* not saved in the unknown chunk list */ + handled_saved, /* saved in the unknown chunk list */ + handled_ok /* known, supported and handled without error */ +} png_handle_result_code; + +PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_unknown, + (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep), + PNG_EMPTY); + /* This is the function that gets called for unknown chunks. The 'keep' + * argument is either non-zero for a known chunk that has been set to be + * handled as unknown or zero for an unknown chunk. By default the function + * just skips the chunk or errors out if it is critical. + */ + +PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_chunk, + (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); + /* This handles the current chunk png_ptr->chunk_name with unread + * data[length] and returns one of the above result codes. + */ + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, + (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); + /* Exactly as the API png_handle_as_unknown() except that the argument is a + * 32-bit chunk name, not a string. + */ +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ + +/* Handle the transformations for reading and writing */ +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), + PNG_EMPTY); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, + png_bytep buffer, size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, + png_bytep buffer, size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), + PNG_EMPTY); +#endif /* PROGRESSIVE_READ */ + +#ifdef PNG_iCCP_SUPPORTED +/* Routines for checking parts of an ICC profile. */ +#ifdef PNG_READ_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, + png_const_charp name, png_uint_32 profile_length), PNG_EMPTY); +#endif /* READ_iCCP */ +PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile /* first 132 bytes only */, int color_type), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_set_rgb_coefficients, (png_structrp png_ptr), + PNG_EMPTY); + /* Set the rgb_to_gray coefficients from the cHRM Y values (if unset) */ +#endif /* READ_RGB_TO_GRAY */ + +/* Added at libpng version 1.4.0 */ +PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type),PNG_EMPTY); + +/* Added at libpng version 1.5.10 */ +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, + (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, + png_const_charp name),PNG_NORETURN); +#endif + +/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite + * the end. Always leaves the buffer nul terminated. Never errors out (and + * there is no error code.) + */ +PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, + size_t pos, png_const_charp string),PNG_EMPTY); + +/* Various internal functions to handle formatted warning messages, currently + * only implemented for warnings. + */ +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. This utility only + * does unsigned values. + */ +PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, + png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); + +/* Convenience macro that takes an array: */ +#define PNG_FORMAT_NUMBER(buffer,format,number) \ + png_format_number(buffer, buffer + (sizeof buffer), format, number) + +/* Suggested size for a number buffer (enough for 64 bits and a sign!) */ +#define PNG_NUMBER_BUFFER_SIZE 24 + +/* These are the integer formats currently supported, the name is formed from + * the standard printf(3) format string. + */ +#define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */ +#define PNG_NUMBER_FORMAT_02u 2 +#define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */ +#define PNG_NUMBER_FORMAT_02d 2 +#define PNG_NUMBER_FORMAT_x 3 +#define PNG_NUMBER_FORMAT_02x 4 +#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */ +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* New defines and members adding in libpng-1.5.4 */ +# define PNG_WARNING_PARAMETER_SIZE 32 +# define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */ + +/* An l-value of this type has to be passed to the APIs below to cache the + * values of the parameters to a formatted warning message. + */ +typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ + PNG_WARNING_PARAMETER_SIZE]; + +PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, + int number, png_const_charp string),PNG_EMPTY); + /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, + * including the trailing '\0'. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, + (png_warning_parameters p, int number, int format, png_alloc_size_t value), + PNG_EMPTY); + /* Use png_alloc_size_t because it is an unsigned type as big as any we + * need to output. Use the following for a signed value. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, + (png_warning_parameters p, int number, int format, png_int_32 value), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, + png_warning_parameters p, png_const_charp message),PNG_EMPTY); + /* 'message' follows the X/Open approach of using @1, @2 to insert + * parameters previously supplied using the above functions. Errors in + * specifying the parameters will simply result in garbage substitutions. + */ +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Application errors (new in 1.6); use these functions (declared below) for + * errors in the parameters or order of API function calls on read. The + * 'warning' should be used for an error that can be handled completely; the + * 'error' for one which can be handled safely but which may lose application + * information or settings. + * + * By default these both result in a png_error call prior to release, while in a + * released version the 'warning' is just a warning. However if the application + * explicitly disables benign errors (explicitly permitting the code to lose + * information) they both turn into warnings. + * + * If benign errors aren't supported they end up as the corresponding base call + * (png_warning or png_error.) + */ +PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* The application provided invalid parameters to an API function or called + * an API function at the wrong time, libpng can completely recover. + */ + +PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* As above but libpng will ignore the call, or attempt some other partial + * recovery from the error. + */ +#else +# define png_app_warning(pp,s) png_warning(pp,s) +# define png_app_error(pp,s) png_error(pp,s) +#endif + +PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, + png_const_charp message, int error),PNG_EMPTY); + /* Report a recoverable issue in chunk data. On read this is used to report + * a problem found while reading a particular chunk and the + * png_chunk_benign_error or png_chunk_warning function is used as + * appropriate. On write this is used to report an error that comes from + * data set via an application call to a png_set_ API and png_app_error or + * png_app_warning is used as appropriate. + * + * The 'error' parameter must have one of the following values: + */ +#define PNG_CHUNK_WARNING 0 /* never an error */ +#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */ +#define PNG_CHUNK_ERROR 2 /* always an error */ + +/* ASCII to FP interfaces, currently only implemented if sCAL + * support is required. + */ +#if defined(PNG_sCAL_SUPPORTED) +/* MAX_DIGITS is actually the maximum number of characters in an sCAL + * width or height, derived from the precision (number of significant + * digits - a build time settable option) and assumptions about the + * maximum ridiculous exponent. + */ +#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) + +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, + png_charp ascii, size_t size, double fp, unsigned int precision), + PNG_EMPTY); +#endif /* FLOATING_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, + png_charp ascii, size_t size, png_fixed_point fp),PNG_EMPTY); +#endif /* FIXED_POINT */ +#endif /* sCAL */ + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* An internal API to validate the format of a floating point number. + * The result is the index of the next character. If the number is + * not valid it will be the index of a character in the supposed number. + * + * The format of a number is defined in the PNG extensions specification + * and this API is strictly conformant to that spec, not anyone elses! + * + * The format as a regular expression is: + * + * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)? + * + * or: + * + * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)? + * + * The complexity is that either integer or fraction must be present and the + * fraction is permitted to have no digits only if the integer is present. + * + * NOTE: The dangling E problem. + * There is a PNG valid floating point number in the following: + * + * PNG floating point numbers are not greedy. + * + * Working this out requires *TWO* character lookahead (because of the + * sign), the parser does not do this - it will fail at the 'r' - this + * doesn't matter for PNG sCAL chunk values, but it requires more care + * if the value were ever to be embedded in something more complex. Use + * ANSI-C strtod if you need the lookahead. + */ +/* State table for the parser. */ +#define PNG_FP_INTEGER 0 /* before or in integer */ +#define PNG_FP_FRACTION 1 /* before or in fraction */ +#define PNG_FP_EXPONENT 2 /* before or in exponent */ +#define PNG_FP_STATE 3 /* mask for the above */ +#define PNG_FP_SAW_SIGN 4 /* Saw +/- in current state */ +#define PNG_FP_SAW_DIGIT 8 /* Saw a digit in current state */ +#define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */ +#define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */ +#define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */ + +/* These three values don't affect the parser. They are set but not used. + */ +#define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */ +#define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */ +#define PNG_FP_NONZERO 256 /* A non-zero value */ +#define PNG_FP_STICKY 448 /* The above three flags */ + +/* This is available for the caller to store in 'state' if required. Do not + * call the parser after setting it (the parser sometimes clears it.) + */ +#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ + +/* Result codes for the parser (boolean - true means ok, false means + * not ok yet.) + */ +#define PNG_FP_MAYBE 0 /* The number may be valid in the future */ +#define PNG_FP_OK 1 /* The number is valid */ + +/* Tests on the sticky non-zero and negative flags. To pass these checks + * the state must also indicate that the whole number is valid - this is + * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this + * is equivalent to PNG_FP_OK above.) + */ +#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO) + /* NZ_MASK: the string is valid and a non-zero negative value */ +#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO) + /* Z MASK: the string is valid and a non-zero value. */ + /* PNG_FP_SAW_DIGIT: the string is valid. */ +#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) +#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) +#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) + +/* The actual parser. This can be called repeatedly. It updates + * the index into the string and the state variable (which must + * be initialized to 0). It returns a result code, as above. There + * is no point calling the parser any more if it fails to advance to + * the end of the string - it is stuck on an invalid character (or + * terminated by '\0'). + * + * Note that the pointer will consume an E or even an E+ and then leave + * a 'maybe' state even though a preceding integer.fraction is valid. + * The PNG_FP_WAS_VALID flag indicates that a preceding substring was + * a valid number. It's possible to recover from this by calling + * the parser again (from the start, with state 0) but with a string + * that omits the last character (i.e. set the size to the index of + * the problem character.) This has not been tested within libpng. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, + size_t size, int *statep, size_t *whereami),PNG_EMPTY); + +/* This is the same but it checks a complete string and returns true + * only if it just contains a floating point number. As of 1.5.4 this + * function also returns the state at the end of parsing the number if + * it was valid (otherwise it returns 0.) This can be used for testing + * for negative or zero values using the sticky flag. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, + size_t size),PNG_EMPTY); +#endif /* pCAL || sCAL */ + +#if defined(PNG_READ_GAMMA_SUPPORTED) ||\ + defined(PNG_COLORSPACE_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) ||\ + defined(PNG_READ_pHYs_SUPPORTED) +/* Added at libpng version 1.5.0 */ +/* This is a utility to provide a*times/div (rounded) and indicate + * if there is an overflow. The result is a boolean - false (0) + * for overflow, true (1) if no overflow, in which case *res + * holds the result. + */ +PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, + png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); + +/* Calculate a reciprocal - used for gamma values. This returns + * 0 if the argument is 0 in order to maintain an undefined value; + * there are no warnings. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), + PNG_EMPTY); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The same but gives a reciprocal of the product of two fixed point + * values. Accuracy is suitable for gamma calculations but this is + * not exact - use png_muldiv for that. Only required at present on read. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, + png_fixed_point b),PNG_EMPTY); + +/* Return true if the gamma value is significantly different from 1.0 */ +PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), + PNG_EMPTY); + +/* PNGv3: 'resolve' the file gamma according to the new PNGv3 rules for colour + * space information. + * + * NOTE: this uses precisely those chunks that libpng supports. For example it + * doesn't use iCCP and it can only use cICP for known and manageable + * transforms. For this reason a gamma specified by png_set_gamma always takes + * precedence. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_resolve_file_gamma, + (png_const_structrp png_ptr),PNG_EMPTY); + +/* Internal fixed point gamma correction. These APIs are called as + * required to convert single values - they don't need to be fast, + * they are not used when processing image pixel values. + * + * While the input is an 'unsigned' value it must actually be the + * correct bit value - 0..255 or 0..65535 as required. + */ +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, + unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, + int bit_depth),PNG_EMPTY); +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Set the RGB coefficients if not already set by png_set_rgb_to_gray */ +PNG_INTERNAL_FUNCTION(void,png_set_rgb_coefficients,(png_structrp png_ptr), + PNG_EMPTY); +#endif + +#if defined(PNG_cHRM_SUPPORTED) || defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +PNG_INTERNAL_FUNCTION(int,png_XYZ_from_xy,(png_XYZ *XYZ, const png_xy *xy), + PNG_EMPTY); +#endif /* cHRM || READ_RGB_TO_GRAY */ + +#ifdef PNG_COLORSPACE_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_xy_from_XYZ,(png_xy *xy, const png_XYZ *XYZ), + PNG_EMPTY); +#endif + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* The internal structure that png_image::opaque points to. */ +typedef struct png_control +{ + png_structp png_ptr; + png_infop info_ptr; + png_voidp error_buf; /* Always a jmp_buf at present. */ + + png_const_bytep memory; /* Memory buffer. */ + size_t size; /* Size of the memory buffer. */ + + unsigned int for_write :1; /* Otherwise it is a read structure */ + unsigned int owned_file :1; /* We own the file in io_ptr */ +} png_control; + +/* Return the pointer to the jmp_buf from a png_control: necessary because C + * does not reveal the type of the elements of jmp_buf. + */ +#ifdef __cplusplus +# define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0]) +#else +# define png_control_jmp_buf(pc) ((pc)->error_buf) +#endif + +/* Utility to safely execute a piece of libpng code catching and logging any + * errors that might occur. Returns true on success, false on failure (either + * of the function or as a result of a png_error.) + */ +PNG_INTERNAL_CALLBACK(void,png_safe_error,(png_structp png_ptr, + png_const_charp error_message),PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +PNG_INTERNAL_CALLBACK(void,png_safe_warning,(png_structp png_ptr, + png_const_charp warning_message),PNG_EMPTY); +#else +# define png_safe_warning 0/*dummy argument*/ +#endif + +PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, + int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); + +/* Utility to log an error; this also cleans up the png_image; the function + * always returns 0 (false). + */ +PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, + png_const_charp error_message),PNG_EMPTY); + +#ifndef PNG_SIMPLIFIED_READ_SUPPORTED +/* png_image_free is used by the write code but not exported */ +PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); +#endif /* !SIMPLIFIED_READ */ + +#endif /* SIMPLIFIED READ/WRITE */ + +/* These are initialization functions for hardware specific PNG filter + * optimizations; list these here then select the appropriate one at compile + * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined + * the generic code is used. + */ +#ifdef PNG_FILTER_OPTIMIZATIONS +PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, + unsigned int bpp), PNG_EMPTY); + /* Just declare the optimization that will be used */ +#else + /* List *all* the possible optimizations here - this branch is required if + * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in + * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. + */ +# if PNG_ARM_NEON_OPT > 0 +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +#endif + +#if PNG_MIPS_MSA_IMPLEMENTATION == 1 +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +#endif + +# if PNG_MIPS_MMI_IMPLEMENTATION > 0 +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +# endif + +# if PNG_INTEL_SSE_IMPLEMENTATION > 0 +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +# endif +#endif + +#if PNG_LOONGARCH_LSX_OPT > 0 +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +#endif + +# if PNG_RISCV_RVV_OPT > 0 +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_rvv, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr, + png_const_charp key, png_bytep new_key), PNG_EMPTY); + +#if PNG_ARM_NEON_IMPLEMENTATION == 1 +PNG_INTERNAL_FUNCTION(void, + png_riffle_palette_neon, + (png_structrp), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int, + png_do_expand_palette_rgba8_neon, + (png_structrp, + png_row_infop, + png_const_bytep, + const png_bytepp, + const png_bytepp), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int, + png_do_expand_palette_rgb8_neon, + (png_structrp, + png_row_infop, + png_const_bytep, + const png_bytepp, + const png_bytepp), + PNG_EMPTY); +#endif + +/* Maintainer: Put new private prototypes here ^ */ + +#include "pngdebug.h" + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ diff --git a/widget/milsko/milskosrc/external/libpng/include/pngstruct.h b/widget/milsko/milskosrc/external/libpng/include/pngstruct.h new file mode 100644 index 0000000000..084422bc1e --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/include/pngstruct.h @@ -0,0 +1,465 @@ +/* pngstruct.h - internal structures for libpng + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#ifndef PNGPRIV_H +# error This file must not be included by applications; please include +#endif + +#ifndef PNGSTRUCT_H +#define PNGSTRUCT_H +/* zlib.h defines the structure z_stream, an instance of which is included + * in this structure and is required for decompressing the LZ compressed + * data in PNG files. + */ +#ifndef ZLIB_CONST + /* We must ensure that zlib uses 'const' in declarations. */ +# define ZLIB_CONST +#endif +#include "zlib.h" +#ifdef const + /* zlib.h sometimes #defines const to nothing, undo this. */ +# undef const +#endif + +/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility + * with older builds. + */ +#if ZLIB_VERNUM < 0x1260 +# define PNGZ_MSG_CAST(s) png_constcast(char*,s) +# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) +#else +# define PNGZ_MSG_CAST(s) (s) +# define PNGZ_INPUT_CAST(b) (b) +#endif + +/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib + * can handle at once. This type need be no larger than 16 bits (so maximum of + * 65535), this define allows us to discover how big it is, but limited by the + * maximum for size_t. The value can be overridden in a library build + * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably + * lower value (e.g. 255 works). A lower value may help memory usage (slightly) + * and may even improve performance on some systems (and degrade it on others.) + */ +#ifndef ZLIB_IO_MAX +# define ZLIB_IO_MAX ((uInt)-1) +#endif + +#ifdef PNG_WRITE_SUPPORTED +/* The type of a compression buffer list used by the write code. */ +typedef struct png_compression_buffer +{ + struct png_compression_buffer *next; + png_byte output[1]; /* actually zbuf_size */ +} png_compression_buffer, *png_compression_bufferp; + +#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ + (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) +#endif + +/* Colorspace support; structures used in png_struct, png_info and in internal + * functions to hold and communicate information about the color space. + */ +/* The chromaticities of the red, green and blue colorants and the chromaticity + * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). + */ +typedef struct png_xy +{ + png_fixed_point redx, redy; + png_fixed_point greenx, greeny; + png_fixed_point bluex, bluey; + png_fixed_point whitex, whitey; +} png_xy; + +/* The same data as above but encoded as CIE XYZ values. When this data comes + * from chromaticities the sum of the Y values is assumed to be 1.0 + */ +typedef struct png_XYZ +{ + png_fixed_point red_X, red_Y, red_Z; + png_fixed_point green_X, green_Y, green_Z; + png_fixed_point blue_X, blue_Y, blue_Z; +} png_XYZ; + +/* Chunk index values as an enum, PNG_INDEX_unknown is also a count of the + * number of chunks. + */ +#define PNG_CHUNK(cHNK, i) PNG_INDEX_ ## cHNK = (i), +typedef enum +{ + PNG_KNOWN_CHUNKS + PNG_INDEX_unknown +} png_index; +#undef PNG_CHUNK + +/* Chunk flag values. These are (png_uint_32 values) with exactly one bit set + * and can be combined into a flag set with bitwise 'or'. + * + * TODO: C23: convert these macros to C23 inlines (which are static). + */ +#define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i))) + /* The flag coresponding to the given png_index enum value. This is defined + * for png_unknown as well (until it reaches the value 32) but this should + * not be relied on. + */ + +#define png_file_has_chunk(png_ptr, i)\ + (((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0) + /* The chunk has been recorded in png_struct */ + +#define png_file_add_chunk(pnt_ptr, i)\ + ((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i))) + /* Record the chunk in the png_struct */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ + png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ + jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ + size_t jmp_buf_size; /* size of the above, if allocated */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ +#ifdef PNG_WARNINGS_SUPPORTED + png_error_ptr warning_fn; /* function for printing warnings */ +#endif + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions */ + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr write_user_transform_fn; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ + z_stream zstream; /* decompression structure */ + +#ifdef PNG_WRITE_SUPPORTED + png_compression_bufferp zbuffer_list; /* Created on demand during write */ + uInt zbuffer_size; /* size of the actual buffer */ + + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ +#endif +/* Added at libpng 1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + int zlib_text_level; /* holds zlib compression level */ + int zlib_text_method; /* holds zlib compression method */ + int zlib_text_window_bits; /* holds zlib compression window bits */ + int zlib_text_mem_level; /* holds zlib compression memory level */ + int zlib_text_strategy; /* holds zlib compression strategy */ +#endif +/* End of material added at libpng 1.5.4 */ +/* Added at libpng 1.6.0 */ +#ifdef PNG_WRITE_SUPPORTED + int zlib_set_level; /* Actual values set into the zstream on write */ + int zlib_set_method; + int zlib_set_window_bits; + int zlib_set_mem_level; + int zlib_set_strategy; +#endif + + png_uint_32 chunks; /* PNG_CF_ for every chunk read or (NYI) written */ +# define png_has_chunk(png_ptr, cHNK)\ + png_file_has_chunk(png_ptr, PNG_INDEX_ ## cHNK) + /* Convenience accessor - use this to check for a known chunk by name */ + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + size_t rowbytes; /* size of row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row. + * While reading this is a pointer into + * big_prev_row; while writing it is separately + * allocated if needed. + */ + png_bytep row_buf; /* buffer to save current (unfiltered) row. + * While reading, this is a pointer into + * big_row_buf; while writing it is separately + * allocated. + */ +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_bytep try_row; /* buffer to save trial row when filtering */ + png_bytep tst_row; /* buffer to save best trial row when filtering */ +#endif + size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + +/* Added at libpng-1.5.10 */ +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + int num_palette_max; /* maximum palette index found in IDAT */ +#endif + + png_uint_16 num_trans; /* number of transparency values */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ in png.h ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row: write only */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ +#ifdef PNG_WRITE_SUPPORTED + png_byte usr_channels; /* channels at start of write: write only */ +#endif + png_byte sig_bytes; /* magic bytes read/written from start of file */ + png_byte maximum_pixel_depth; + /* pixel depth used for the row buffers */ + png_byte transformed_pixel_depth; + /* pixel depth after read/write transforms */ +#if ZLIB_VERNUM >= 0x1240 + png_byte zstream_start; /* at start of an input zlib stream */ +#endif /* Zlib >= 1.2.4 */ +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + png_byte background_gamma_type; + png_fixed_point background_gamma; + png_color_16 background; /* background color in screen gamma space */ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif /* bKGD */ + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_flush_ptr output_flush_fn; /* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_xy chromaticities; /* From mDVC, cICP, [iCCP], sRGB or cHRM */ +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ + png_fixed_point screen_gamma; /* screen gamma value (display exponent) */ + png_fixed_point file_gamma; /* file gamma value (encoding exponent) */ + png_fixed_point chunk_gamma; /* from cICP, iCCP, sRGB or gAMA */ + png_fixed_point default_gamma;/* from png_set_alpha_mode */ + + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +#endif /* READ_GAMMA */ + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit transformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans_alpha; /* alpha values for paletted files */ + png_color_16 trans_color; /* transparent color for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after a prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + size_t save_buffer_size; /* amount of data now in save_buffer */ + size_t save_buffer_max; /* total size of save_buffer */ + size_t buffer_size; /* total amount of available input data */ + size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ +#endif /* PROGRESSIVE_READ */ + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_bytep palette_lookup; /* lookup table for quantizing */ + png_bytep quantize_index; /* index translation for palette files */ +#endif + +/* Options */ +#ifdef PNG_SET_OPTION_SUPPORTED + png_uint_32 options; /* On/off state (up to 16 options) */ +#endif + +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng-1.7 */ +#ifdef PNG_TIME_RFC1123_SUPPORTED + char time_buffer[29]; /* String to hold RFC 1123 time text */ +#endif /* TIME_RFC1123 */ +#endif /* LIBPNG_VER < 10700 */ + +/* New members added in libpng-1.0.6 */ + + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_USER_CHUNKS_SUPPORTED + png_voidp user_chunk_ptr; +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif /* READ_USER_CHUNKS */ +#endif /* USER_CHUNKS */ + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int unknown_default; /* As PNG_HANDLE_* */ + unsigned int num_chunk_list; /* Number of entries in the list */ + png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name + * followed by a PNG_HANDLE_* byte */ +#endif + +/* New members added in libpng-1.0.3 */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_byte rgb_to_gray_status; + /* Added in libpng 1.5.5 to record setting of coefficients: */ + png_byte rgb_to_gray_coefficients_set; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ +#endif + +/* New member added in libpng-1.6.36 */ +#if defined(PNG_READ_EXPAND_SUPPORTED) && \ + (defined(PNG_ARM_NEON_IMPLEMENTATION) || \ + defined(PNG_RISCV_RVV_IMPLEMENTATION)) + png_bytep riffled_palette; /* buffer for accelerated palette expansion */ +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) +/* Changed from png_byte to png_uint_32 at version 1.2.0 */ + png_uint_32 mng_features_permitted; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_byte filter_type; +#endif + +/* New members added in libpng-1.2.0 */ + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep quantize_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is + in the palette */ + png_bytep palette_to_index; /* which original index points to this + palette color */ +#endif + +/* New members added in libpng-1.0.16 and 1.2.6 */ + png_byte compression_type; + +#ifdef PNG_USER_LIMITS_SUPPORTED + png_uint_32 user_width_max; + png_uint_32 user_height_max; + + /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown + * chunks that can be stored (0 means unlimited). + */ + png_uint_32 user_chunk_cache_max; + + /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk + * can occupy when decompressed. 0 means unlimited. + */ + png_alloc_size_t user_chunk_malloc_max; +#endif + +/* New member added in libpng-1.0.25 and 1.2.17 */ +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* Temporary storage for unknown chunk that the library doesn't recognize, + * used while reading the chunk. + */ + png_unknown_chunk unknown_chunk; +#endif + +/* New member added in libpng-1.2.26 */ + size_t old_big_row_buf_size; + +#ifdef PNG_READ_SUPPORTED +/* New member added in libpng-1.2.30 */ + png_bytep read_buffer; /* buffer for reading chunk data */ + png_alloc_size_t read_buffer_size; /* current size of the buffer */ +#endif +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + uInt IDAT_read_size; /* limit on read buffer size for IDAT */ +#endif + +#ifdef PNG_IO_STATE_SUPPORTED +/* New member added in libpng-1.4.0 */ + png_uint_32 io_state; +#endif + +/* New member added in libpng-1.5.6 */ + png_bytep big_prev_row; + +/* New member added in libpng-1.5.7 */ + void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row); +}; +#endif /* PNGSTRUCT_H */ diff --git a/widget/milsko/milskosrc/external/libpng/src/png.c b/widget/milsko/milskosrc/external/libpng/src/png.c new file mode 100644 index 0000000000..6e21915c40 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/png.c @@ -0,0 +1,4039 @@ +/* png.c - location for general purpose libpng functions + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef png_libpng_version_1_6_50 Your_png_h_is_not_version_1_6_50; + +/* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the + * corresponding macro definitions. This causes a compile time failure if + * something is wrong but generates no code. + * + * (1) The first check is that the PNG_CHUNK(cHNK, index) 'index' values must + * increment from 0 to the last value. + */ +#define PNG_CHUNK(cHNK, index) != (index) || ((index)+1) + +#if 0 PNG_KNOWN_CHUNKS < 0 +# error PNG_KNOWN_CHUNKS chunk definitions are not in order +#endif + +#undef PNG_CHUNK + +/* (2) The chunk name macros, png_cHNK, must all be valid and defined. Since + * this is a preprocessor test undefined pp-tokens come out as zero and will + * fail this test. + */ +#define PNG_CHUNK(cHNK, index) !PNG_CHUNK_NAME_VALID(png_ ## cHNK) || + +#if PNG_KNOWN_CHUNKS 0 +# error png_cHNK not defined for some known cHNK +#endif + +#undef PNG_CHUNK + +/* Tells libpng that we have already handled the first "num_bytes" bytes + * of the PNG file signature. If the PNG data is embedded into another + * stream we can set num_bytes = 8 so that libpng will not attempt to read + * or write any of the magic bytes before it starts on the IHDR. + */ + +#ifdef PNG_READ_SUPPORTED +void PNGAPI +png_set_sig_bytes(png_structrp png_ptr, int num_bytes) +{ + unsigned int nb = (unsigned int)num_bytes; + + png_debug(1, "in png_set_sig_bytes"); + + if (png_ptr == NULL) + return; + + if (num_bytes < 0) + nb = 0; + + if (nb > 8) + png_error(png_ptr, "Too many bytes for PNG signature"); + + png_ptr->sig_bytes = (png_byte)nb; +} + +/* Checks whether the supplied bytes match the PNG signature. We allow + * checking less than the full 8-byte signature so that those apps that + * already read the first few bytes of a file to determine the file type + * can simply check the remaining bytes for extra assurance. Returns + * an integer less than, equal to, or greater than zero if sig is found, + * respectively, to be less than, to match, or be greater than the correct + * PNG signature (this is the same behavior as strcmp, memcmp, etc). + */ +int PNGAPI +png_sig_cmp(png_const_bytep sig, size_t start, size_t num_to_check) +{ + static const png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + + if (num_to_check > 8) + num_to_check = 8; + + else if (num_to_check < 1) + return -1; + + if (start > 7) + return -1; + + if (start + num_to_check > 8) + num_to_check = 8 - start; + + return memcmp(&sig[start], &png_signature[start], num_to_check); +} + +#endif /* READ */ + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Function to allocate memory for zlib */ +PNG_FUNCTION(voidpf /* PRIVATE */, +png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED) +{ + png_alloc_size_t num_bytes = size; + + if (png_ptr == NULL) + return NULL; + + if (items >= (~(png_alloc_size_t)0)/size) + { + png_warning (png_voidcast(png_structrp, png_ptr), + "Potential overflow in png_zalloc()"); + return NULL; + } + + num_bytes *= items; + return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes); +} + +/* Function to free memory for zlib */ +void /* PRIVATE */ +png_zfree(voidpf png_ptr, voidpf ptr) +{ + png_free(png_voidcast(png_const_structrp,png_ptr), ptr); +} + +/* Reset the CRC variable to 32 bits of 1's. Care must be taken + * in case CRC is > 32 bits to leave the top bits 0. + */ +void /* PRIVATE */ +png_reset_crc(png_structrp png_ptr) +{ + /* The cast is safe because the crc is a 32-bit value. */ + png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); +} + +/* Calculate the CRC over a section of data. We can only pass as + * much data to this routine as the largest single buffer size. We + * also check that this data will actually be used before going to the + * trouble of calculating it. + */ +void /* PRIVATE */ +png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, size_t length) +{ + int need_crc = 1; + + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + + else /* critical */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) + need_crc = 0; + } + + /* 'uLong' is defined in zlib.h as unsigned long; this means that on some + * systems it is a 64-bit value. crc32, however, returns 32 bits so the + * following cast is safe. 'uInt' may be no more than 16 bits, so it is + * necessary to perform a loop here. + */ + if (need_crc != 0 && length > 0) + { + uLong crc = png_ptr->crc; /* Should never issue a warning */ + + do + { + uInt safe_length = (uInt)length; +#ifndef __COVERITY__ + if (safe_length == 0) + safe_length = (uInt)-1; /* evil, but safe */ +#endif + + crc = crc32(crc, ptr, safe_length); + + /* The following should never issue compiler warnings; if they do the + * target system has characteristics that will probably violate other + * assumptions within the libpng code. + */ + ptr += safe_length; + length -= safe_length; + } + while (length > 0); + + /* And the following is always safe because the crc is only 32 bits. */ + png_ptr->crc = (png_uint_32)crc; + } +} + +/* Check a user supplied version number, called from both read and write + * functions that create a png_struct. + */ +int +png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) +{ + /* Libpng versions 1.0.0 and later are binary compatible if the version + * string matches through the second '.'; we must recompile any + * applications that use any older library version. + */ + + if (user_png_ver != NULL) + { + int i = -1; + int found_dots = 0; + + do + { + i++; + if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + if (user_png_ver[i] == '.') + found_dots++; + } while (found_dots < 2 && user_png_ver[i] != 0 && + PNG_LIBPNG_VER_STRING[i] != 0); + } + + else + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + + if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0) + { +#ifdef PNG_WARNINGS_SUPPORTED + size_t pos = 0; + char m[128]; + + pos = png_safecat(m, (sizeof m), pos, + "Application built with libpng-"); + pos = png_safecat(m, (sizeof m), pos, user_png_ver); + pos = png_safecat(m, (sizeof m), pos, " but running with "); + pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING); + PNG_UNUSED(pos) + + png_warning(png_ptr, m); +#endif + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + + return 0; + } + + /* Success return. */ + return 1; +} + +/* Generic function to create a png_struct for either read or write - this + * contains the common initialization. + */ +PNG_FUNCTION(png_structp /* PRIVATE */, +png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_struct create_struct; +# ifdef PNG_SETJMP_SUPPORTED + jmp_buf create_jmp_buf; +# endif + + /* This temporary stack-allocated structure is used to provide a place to + * build enough context to allow the user provided memory allocator (if any) + * to be called. + */ + memset(&create_struct, 0, (sizeof create_struct)); + +# ifdef PNG_USER_LIMITS_SUPPORTED + create_struct.user_width_max = PNG_USER_WIDTH_MAX; + create_struct.user_height_max = PNG_USER_HEIGHT_MAX; + +# ifdef PNG_USER_CHUNK_CACHE_MAX + create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; +# endif + +# if PNG_USER_CHUNK_MALLOC_MAX > 0 /* default to compile-time limit */ + create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; + + /* No compile-time limit, so initialize to the system limit: */ +# elif defined PNG_MAX_MALLOC_64K /* legacy system limit */ + create_struct.user_chunk_malloc_max = 65536U; + +# else /* modern system limit SIZE_MAX (C99) */ + create_struct.user_chunk_malloc_max = PNG_SIZE_MAX; +# endif +# endif + + /* The following two API calls simply set fields in png_struct, so it is safe + * to do them now even though error handling is not yet set up. + */ +# ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn); +# else + PNG_UNUSED(mem_ptr) + PNG_UNUSED(malloc_fn) + PNG_UNUSED(free_fn) +# endif + + /* (*error_fn) can return control to the caller after the error_ptr is set, + * this will result in a memory leak unless the error_fn does something + * extremely sophisticated. The design lacks merit but is implicit in the + * API. + */ + png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn); + +# ifdef PNG_SETJMP_SUPPORTED + if (!setjmp(create_jmp_buf)) +# endif + { +# ifdef PNG_SETJMP_SUPPORTED + /* Temporarily fake out the longjmp information until we have + * successfully completed this function. This only works if we have + * setjmp() support compiled in, but it is safe - this stuff should + * never happen. + */ + create_struct.jmp_buf_ptr = &create_jmp_buf; + create_struct.jmp_buf_size = 0; /*stack allocation*/ + create_struct.longjmp_fn = longjmp; +# endif + /* Call the general version checker (shared with read and write code): + */ + if (png_user_version_check(&create_struct, user_png_ver) != 0) + { + png_structrp png_ptr = png_voidcast(png_structrp, + png_malloc_warn(&create_struct, (sizeof *png_ptr))); + + if (png_ptr != NULL) + { + /* png_ptr->zstream holds a back-pointer to the png_struct, so + * this can only be done now: + */ + create_struct.zstream.zalloc = png_zalloc; + create_struct.zstream.zfree = png_zfree; + create_struct.zstream.opaque = png_ptr; + +# ifdef PNG_SETJMP_SUPPORTED + /* Eliminate the local error handling: */ + create_struct.jmp_buf_ptr = NULL; + create_struct.jmp_buf_size = 0; + create_struct.longjmp_fn = 0; +# endif + + *png_ptr = create_struct; + + /* This is the successful return point */ + return png_ptr; + } + } + } + + /* A longjmp because of a bug in the application storage allocator or a + * simple failure to allocate the png_struct. + */ + return NULL; +} + +/* Allocate the memory for an info_struct for the application. */ +PNG_FUNCTION(png_infop,PNGAPI +png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED) +{ + png_inforp info_ptr; + + png_debug(1, "in png_create_info_struct"); + + if (png_ptr == NULL) + return NULL; + + /* Use the internal API that does not (or at least should not) error out, so + * that this call always returns ok. The application typically sets up the + * error handling *after* creating the info_struct because this is the way it + * has always been done in 'example.c'. + */ + info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr, + (sizeof *info_ptr))); + + if (info_ptr != NULL) + memset(info_ptr, 0, (sizeof *info_ptr)); + + return info_ptr; +} + +/* This function frees the memory associated with a single info struct. + * Normally, one would use either png_destroy_read_struct() or + * png_destroy_write_struct() to free an info struct, but this may be + * useful for some applications. From libpng 1.6.0 this function is also used + * internally to implement the png_info release part of the 'struct' destroy + * APIs. This ensures that all possible approaches free the same data (all of + * it). + */ +void PNGAPI +png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr) +{ + png_inforp info_ptr = NULL; + + png_debug(1, "in png_destroy_info_struct"); + + if (png_ptr == NULL) + return; + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + /* Do this first in case of an error below; if the app implements its own + * memory management this can lead to png_free calling png_error, which + * will abort this routine and return control to the app error handler. + * An infinite loop may result if it then tries to free the same info + * ptr. + */ + *info_ptr_ptr = NULL; + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + memset(info_ptr, 0, (sizeof *info_ptr)); + png_free(png_ptr, info_ptr); + } +} + +/* Initialize the info structure. This is now an internal function (0.89) + * and applications using it are urged to use png_create_info_struct() + * instead. Use deprecated in 1.6.0, internal use removed (used internally it + * is just a memset). + * + * NOTE: it is almost inconceivable that this API is used because it bypasses + * the user-memory mechanism and the user error handling/warning mechanisms in + * those cases where it does anything other than a memset. + */ +PNG_FUNCTION(void,PNGAPI +png_info_init_3,(png_infopp ptr_ptr, size_t png_info_struct_size), + PNG_DEPRECATED) +{ + png_inforp info_ptr = *ptr_ptr; + + png_debug(1, "in png_info_init_3"); + + if (info_ptr == NULL) + return; + + if ((sizeof (png_info)) > png_info_struct_size) + { + *ptr_ptr = NULL; + /* The following line is why this API should not be used: */ + free(info_ptr); + info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL, + (sizeof *info_ptr))); + if (info_ptr == NULL) + return; + *ptr_ptr = info_ptr; + } + + /* Set everything to 0 */ + memset(info_ptr, 0, (sizeof *info_ptr)); +} + +void PNGAPI +png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, + int freer, png_uint_32 mask) +{ + png_debug(1, "in png_data_freer"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (freer == PNG_DESTROY_WILL_FREE_DATA) + info_ptr->free_me |= mask; + + else if (freer == PNG_USER_WILL_FREE_DATA) + info_ptr->free_me &= ~mask; + + else + png_error(png_ptr, "Unknown freer parameter in png_data_freer"); +} + +void PNGAPI +png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, + int num) +{ + png_debug(1, "in png_free_data"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_TEXT_SUPPORTED + /* Free text item num or (if num == -1) all text items */ + if (info_ptr->text != NULL && + ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0) + { + if (num != -1) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } + + else + { + int i; + + for (i = 0; i < info_ptr->num_text; i++) + png_free(png_ptr, info_ptr->text[i].key); + + png_free(png_ptr, info_ptr->text); + info_ptr->text = NULL; + info_ptr->num_text = 0; + info_ptr->max_text = 0; + } + } +#endif + +#ifdef PNG_tRNS_SUPPORTED + /* Free any tRNS entry */ + if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0) + { + info_ptr->valid &= ~PNG_INFO_tRNS; + png_free(png_ptr, info_ptr->trans_alpha); + info_ptr->trans_alpha = NULL; + info_ptr->num_trans = 0; + } +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* Free any sCAL entry */ + if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->scal_s_width); + png_free(png_ptr, info_ptr->scal_s_height); + info_ptr->scal_s_width = NULL; + info_ptr->scal_s_height = NULL; + info_ptr->valid &= ~PNG_INFO_sCAL; + } +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* Free any pCAL entry */ + if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->pcal_purpose); + png_free(png_ptr, info_ptr->pcal_units); + info_ptr->pcal_purpose = NULL; + info_ptr->pcal_units = NULL; + + if (info_ptr->pcal_params != NULL) + { + int i; + + for (i = 0; i < info_ptr->pcal_nparams; i++) + png_free(png_ptr, info_ptr->pcal_params[i]); + + png_free(png_ptr, info_ptr->pcal_params); + info_ptr->pcal_params = NULL; + } + info_ptr->valid &= ~PNG_INFO_pCAL; + } +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* Free any profile entry */ + if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->iccp_name); + png_free(png_ptr, info_ptr->iccp_profile); + info_ptr->iccp_name = NULL; + info_ptr->iccp_profile = NULL; + info_ptr->valid &= ~PNG_INFO_iCCP; + } +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ + if (info_ptr->splt_palettes != NULL && + ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0) + { + if (num != -1) + { + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; + } + + else + { + int i; + + for (i = 0; i < info_ptr->splt_palettes_num; i++) + { + png_free(png_ptr, info_ptr->splt_palettes[i].name); + png_free(png_ptr, info_ptr->splt_palettes[i].entries); + } + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; + info_ptr->valid &= ~PNG_INFO_sPLT; + } + } +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks != NULL && + ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0) + { + if (num != -1) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } + + else + { + int i; + + for (i = 0; i < info_ptr->unknown_chunks_num; i++) + png_free(png_ptr, info_ptr->unknown_chunks[i].data); + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; + } + } +#endif + +#ifdef PNG_eXIf_SUPPORTED + /* Free any eXIf entry */ + if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0) + { + if (info_ptr->exif) + { + png_free(png_ptr, info_ptr->exif); + info_ptr->exif = NULL; + } + info_ptr->valid &= ~PNG_INFO_eXIf; + } +#endif + +#ifdef PNG_hIST_SUPPORTED + /* Free any hIST entry */ + if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->hist); + info_ptr->hist = NULL; + info_ptr->valid &= ~PNG_INFO_hIST; + } +#endif + + /* Free any PLTE entry that was internally allocated */ + if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->palette); + info_ptr->palette = NULL; + info_ptr->valid &= ~PNG_INFO_PLTE; + info_ptr->num_palette = 0; + } + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Free any image bits attached to the info structure */ + if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0) + { + if (info_ptr->row_pointers != NULL) + { + png_uint_32 row; + for (row = 0; row < info_ptr->height; row++) + png_free(png_ptr, info_ptr->row_pointers[row]); + + png_free(png_ptr, info_ptr->row_pointers); + info_ptr->row_pointers = NULL; + } + info_ptr->valid &= ~PNG_INFO_IDAT; + } +#endif + + if (num != -1) + mask &= ~PNG_FREE_MUL; + + info_ptr->free_me &= ~mask; +} +#endif /* READ || WRITE */ + +/* This function returns a pointer to the io_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy() or png_read_destroy() are called. + */ +png_voidp PNGAPI +png_get_io_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return png_ptr->io_ptr; +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +# ifdef PNG_STDIO_SUPPORTED +/* Initialize the default input/output functions for the PNG file. If you + * use your own read or write routines, you can call either png_set_read_fn() + * or png_set_write_fn() instead of png_init_io(). If you have defined + * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a + * function of your own because "FILE *" isn't necessarily available. + */ +void PNGAPI +png_init_io(png_structrp png_ptr, FILE *fp) +{ + png_debug(1, "in png_init_io"); + + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = (png_voidp)fp; +} +# endif + +# ifdef PNG_SAVE_INT_32_SUPPORTED +/* PNG signed integers are saved in 32-bit 2's complement format. ANSI C-90 + * defines a cast of a signed integer to an unsigned integer either to preserve + * the value, if it is positive, or to calculate: + * + * (UNSIGNED_MAX+1) + integer + * + * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the + * negative integral value is added the result will be an unsigned value + * corresponding to the 2's complement representation. + */ +void PNGAPI +png_save_int_32(png_bytep buf, png_int_32 i) +{ + png_save_uint_32(buf, (png_uint_32)i); +} +# endif + +# ifdef PNG_TIME_RFC1123_SUPPORTED +/* Convert the supplied time into an RFC 1123 string suitable for use in + * a "Creation Time" or other text-based time string. + */ +int PNGAPI +png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) +{ + static const char short_months[12][4] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if (out == NULL) + return 0; + + if (ptime->year > 9999 /* RFC1123 limitation */ || + ptime->month == 0 || ptime->month > 12 || + ptime->day == 0 || ptime->day > 31 || + ptime->hour > 23 || ptime->minute > 59 || + ptime->second > 60) + return 0; + + { + size_t pos = 0; + char number_buf[5] = {0, 0, 0, 0, 0}; /* enough for a four-digit year */ + +# define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string)) +# define APPEND_NUMBER(format, value)\ + APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value))) +# define APPEND(ch) if (pos < 28) out[pos++] = (ch) + + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day); + APPEND(' '); + APPEND_STRING(short_months[(ptime->month - 1)]); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second); + APPEND_STRING(" +0000"); /* This reliably terminates the buffer */ + PNG_UNUSED (pos) + +# undef APPEND +# undef APPEND_NUMBER +# undef APPEND_STRING + } + + return 1; +} + +# if PNG_LIBPNG_VER < 10700 +/* To do: remove the following from libpng-1.7 */ +/* Original API that uses a private buffer in png_struct. + * Deprecated because it causes png_struct to carry a spurious temporary + * buffer (png_struct::time_buffer), better to have the caller pass this in. + */ +png_const_charp PNGAPI +png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) +{ + if (png_ptr != NULL) + { + /* The only failure above if png_ptr != NULL is from an invalid ptime */ + if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0) + png_warning(png_ptr, "Ignoring invalid time value"); + + else + return png_ptr->time_buffer; + } + + return NULL; +} +# endif /* LIBPNG_VER < 10700 */ +# endif /* TIME_RFC1123 */ + +#endif /* READ || WRITE */ + +png_const_charp PNGAPI +png_get_copyright(png_const_structrp png_ptr) +{ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ +#ifdef PNG_STRING_COPYRIGHT + return PNG_STRING_COPYRIGHT +#else + return PNG_STRING_NEWLINE \ + "libpng version 1.6.50" PNG_STRING_NEWLINE \ + "Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \ + PNG_STRING_NEWLINE \ + "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ + "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ + PNG_STRING_NEWLINE; +#endif +} + +/* The following return the library version as a short string in the + * format 1.0.0 through 99.99.99zz. To get the version of *.h files + * used with your application, print out PNG_LIBPNG_VER_STRING, which + * is defined in png.h. + * Note: now there is no difference between png_get_libpng_ver() and + * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, + * it is guaranteed that png.c uses the correct version of png.h. + */ +png_const_charp PNGAPI +png_get_libpng_ver(png_const_structrp png_ptr) +{ + /* Version of *.c files used when building libpng */ + return png_get_header_ver(png_ptr); +} + +png_const_charp PNGAPI +png_get_header_ver(png_const_structrp png_ptr) +{ + /* Version of *.h files used when building libpng */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ + return PNG_LIBPNG_VER_STRING; +} + +png_const_charp PNGAPI +png_get_header_version(png_const_structrp png_ptr) +{ + /* Returns longer string containing both version and date */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ +#ifdef __STDC__ + return PNG_HEADER_VERSION_STRING +# ifndef PNG_READ_SUPPORTED + " (NO READ SUPPORT)" +# endif + PNG_STRING_NEWLINE; +#else + return PNG_HEADER_VERSION_STRING; +#endif +} + +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +/* NOTE: this routine is not used internally! */ +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. This API is not used internally. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette"); + + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + + case 2: + num_palette = 4; + color_inc = 0x55; + break; + + case 4: + num_palette = 16; + color_inc = 0x11; + break; + + case 8: + num_palette = 256; + color_inc = 1; + break; + + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)(v & 0xff); + palette[i].green = (png_byte)(v & 0xff); + palette[i].blue = (png_byte)(v & 0xff); + } +} +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +int PNGAPI +png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) +{ + /* Check chunk_name and return "keep" value if it's on the list, else 0 */ + png_const_bytep p, p_end; + + if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0) + return PNG_HANDLE_CHUNK_AS_DEFAULT; + + p_end = png_ptr->chunk_list; + p = p_end + png_ptr->num_chunk_list*5; /* beyond end */ + + /* The code is the fifth byte after each four byte string. Historically this + * code was always searched from the end of the list, this is no longer + * necessary because the 'set' routine handles duplicate entries correctly. + */ + do /* num_chunk_list > 0, so at least one */ + { + p -= 5; + + if (memcmp(chunk_name, p, 4) == 0) + return p[4]; + } + while (p > p_end); + + /* This means that known chunks should be processed and unknown chunks should + * be handled according to the value of png_ptr->unknown_default; this can be + * confusing because, as a result, there are two levels of defaulting for + * unknown chunks. + */ + return PNG_HANDLE_CHUNK_AS_DEFAULT; +} + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +int /* PRIVATE */ +png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) +{ + png_byte chunk_string[5]; + + PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name); + return png_handle_as_unknown(png_ptr, chunk_string); +} +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ +#endif /* SET_UNKNOWN_CHUNKS */ + +#ifdef PNG_READ_SUPPORTED +/* This function, added to libpng-1.0.6g, is untested. */ +int PNGAPI +png_reset_zstream(png_structrp png_ptr) +{ + if (png_ptr == NULL) + return Z_STREAM_ERROR; + + /* WARNING: this resets the window bits to the maximum! */ + return inflateReset(&png_ptr->zstream); +} +#endif /* READ */ + +/* This function was added to libpng-1.0.7 */ +png_uint_32 PNGAPI +png_access_version_number(void) +{ + /* Version of *.c files used when building libpng */ + return (png_uint_32)PNG_LIBPNG_VER; +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Ensure that png_ptr->zstream.msg holds some appropriate error message string. + * If it doesn't 'ret' is used to set it to something appropriate, even in cases + * like Z_OK or Z_STREAM_END where the error code is apparently a success code. + */ +void /* PRIVATE */ +png_zstream_error(png_structrp png_ptr, int ret) +{ + /* Translate 'ret' into an appropriate error string, priority is given to the + * one in zstream if set. This always returns a string, even in cases like + * Z_OK or Z_STREAM_END where the error code is a success code. + */ + if (png_ptr->zstream.msg == NULL) switch (ret) + { + default: + case Z_OK: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); + break; + + case Z_STREAM_END: + /* Normal exit */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); + break; + + case Z_NEED_DICT: + /* This means the deflate stream did not have a dictionary; this + * indicates a bogus PNG. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); + break; + + case Z_ERRNO: + /* gz APIs only: should not happen */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error"); + break; + + case Z_STREAM_ERROR: + /* internal libpng error */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib"); + break; + + case Z_DATA_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); + break; + + case Z_MEM_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); + break; + + case Z_BUF_ERROR: + /* End of input or output; not a problem if the caller is doing + * incremental read or write. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); + break; + + case Z_VERSION_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); + break; + + case PNG_UNEXPECTED_ZLIB_RETURN: + /* Compile errors here mean that zlib now uses the value co-opted in + * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above + * and change pngpriv.h. Note that this message is "... return", + * whereas the default/Z_OK one is "... return code". + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return"); + break; + } +} + +#ifdef PNG_COLORSPACE_SUPPORTED +static png_int_32 +png_fp_add(png_int_32 addend0, png_int_32 addend1, int *error) +{ + /* Safely add two fixed point values setting an error flag and returning 0.5 + * on overflow. + * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore + * relying on addition of two positive values producing a negative one is not + * safe. + */ + if (addend0 > 0) + { + if (0x7fffffff - addend0 >= addend1) + return addend0+addend1; + } + else if (addend0 < 0) + { + if (-0x7fffffff - addend0 <= addend1) + return addend0+addend1; + } + else + return addend1; + + *error = 1; + return PNG_FP_1/2; +} + +static png_int_32 +png_fp_sub(png_int_32 addend0, png_int_32 addend1, int *error) +{ + /* As above but calculate addend0-addend1. */ + if (addend1 > 0) + { + if (-0x7fffffff + addend1 <= addend0) + return addend0-addend1; + } + else if (addend1 < 0) + { + if (0x7fffffff + addend1 >= addend0) + return addend0-addend1; + } + else + return addend0; + + *error = 1; + return PNG_FP_1/2; +} + +static int +png_safe_add(png_int_32 *addend0_and_result, png_int_32 addend1, + png_int_32 addend2) +{ + /* Safely add three integers. Returns 0 on success, 1 on overflow. Does not + * set the result on overflow. + */ + int error = 0; + int result = png_fp_add(*addend0_and_result, + png_fp_add(addend1, addend2, &error), + &error); + if (!error) *addend0_and_result = result; + return error; +} + +/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for + * cHRM, as opposed to using chromaticities. These internal APIs return + * non-zero on a parameter error. The X, Y and Z values are required to be + * positive and less than 1.0. + */ +int /* PRIVATE */ +png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) +{ + /* NOTE: returns 0 on success, 1 means error. */ + png_int_32 d, dred, dgreen, dblue, dwhite, whiteX, whiteY; + + /* 'd' in each of the blocks below is just X+Y+Z for each component, + * x, y and z are X,Y,Z/(X+Y+Z). + */ + d = XYZ->red_X; + if (png_safe_add(&d, XYZ->red_Y, XYZ->red_Z)) + return 1; + dred = d; + if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, dred) == 0) + return 1; + if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, dred) == 0) + return 1; + + d = XYZ->green_X; + if (png_safe_add(&d, XYZ->green_Y, XYZ->green_Z)) + return 1; + dgreen = d; + if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, dgreen) == 0) + return 1; + if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, dgreen) == 0) + return 1; + + d = XYZ->blue_X; + if (png_safe_add(&d, XYZ->blue_Y, XYZ->blue_Z)) + return 1; + dblue = d; + if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, dblue) == 0) + return 1; + if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, dblue) == 0) + return 1; + + /* The reference white is simply the sum of the end-point (X,Y,Z) vectors so + * the fillowing calculates (X+Y+Z) of the reference white (media white, + * encoding white) itself: + */ + d = dblue; + if (png_safe_add(&d, dred, dgreen)) + return 1; + dwhite = d; + + /* Find the white X,Y values from the sum of the red, green and blue X,Y + * values. + */ + d = XYZ->red_X; + if (png_safe_add(&d, XYZ->green_X, XYZ->blue_X)) + return 1; + whiteX = d; + + d = XYZ->red_Y; + if (png_safe_add(&d, XYZ->green_Y, XYZ->blue_Y)) + return 1; + whiteY = d; + + if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0) + return 1; + if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0) + return 1; + + return 0; +} + +int /* PRIVATE */ +png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) +{ + /* NOTE: returns 0 on success, 1 means error. */ + png_fixed_point red_inverse, green_inverse, blue_scale; + png_fixed_point left, right, denominator; + + /* Check xy and, implicitly, z. Note that wide gamut color spaces typically + * have end points with 0 tristimulus values (these are impossible end + * points, but they are used to cover the possible colors). We check + * xy->whitey against 5, not 0, to avoid a possible integer overflow. + * + * The limits here will *not* accept ACES AP0, where bluey is -7700 + * (-0.0770) because the PNG spec itself requires the xy values to be + * unsigned. whitey is also required to be 5 or more to avoid overflow. + * + * Instead the upper limits have been relaxed to accomodate ACES AP1 where + * redz ends up as -600 (-0.006). ProPhotoRGB was already "in range." + * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy. + */ + const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10); + if (xy->redx < 0 || xy->redx > fpLimit) return 1; + if (xy->redy < 0 || xy->redy > fpLimit-xy->redx) return 1; + if (xy->greenx < 0 || xy->greenx > fpLimit) return 1; + if (xy->greeny < 0 || xy->greeny > fpLimit-xy->greenx) return 1; + if (xy->bluex < 0 || xy->bluex > fpLimit) return 1; + if (xy->bluey < 0 || xy->bluey > fpLimit-xy->bluex) return 1; + if (xy->whitex < 0 || xy->whitex > fpLimit) return 1; + if (xy->whitey < 5 || xy->whitey > fpLimit-xy->whitex) return 1; + + /* The reverse calculation is more difficult because the original tristimulus + * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 + * derived values were recorded in the cHRM chunk; + * (red,green,blue,white)x(x,y). This loses one degree of freedom and + * therefore an arbitrary ninth value has to be introduced to undo the + * original transformations. + * + * Think of the original end-points as points in (X,Y,Z) space. The + * chromaticity values (c) have the property: + * + * C + * c = --------- + * X + Y + Z + * + * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the + * three chromaticity values (x,y,z) for each end-point obey the + * relationship: + * + * x + y + z = 1 + * + * This describes the plane in (X,Y,Z) space that intersects each axis at the + * value 1.0; call this the chromaticity plane. Thus the chromaticity + * calculation has scaled each end-point so that it is on the x+y+z=1 plane + * and chromaticity is the intersection of the vector from the origin to the + * (X,Y,Z) value with the chromaticity plane. + * + * To fully invert the chromaticity calculation we would need the three + * end-point scale factors, (red-scale, green-scale, blue-scale), but these + * were not recorded. Instead we calculated the reference white (X,Y,Z) and + * recorded the chromaticity of this. The reference white (X,Y,Z) would have + * given all three of the scale factors since: + * + * color-C = color-c * color-scale + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * But cHRM records only white-x and white-y, so we have lost the white scale + * factor: + * + * white-C = white-c*white-scale + * + * To handle this the inverse transformation makes an arbitrary assumption + * about white-scale: + * + * Assume: white-Y = 1.0 + * Hence: white-scale = 1/white-y + * Or: red-Y + green-Y + blue-Y = 1.0 + * + * Notice the last statement of the assumption gives an equation in three of + * the nine values we want to calculate. 8 more equations come from the + * above routine as summarised at the top above (the chromaticity + * calculation): + * + * Given: color-x = color-X / (color-X + color-Y + color-Z) + * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0 + * + * This is 9 simultaneous equations in the 9 variables "color-C" and can be + * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix + * determinants, however this is not as bad as it seems because only 28 of + * the total of 90 terms in the various matrices are non-zero. Nevertheless + * Cramer's rule is notoriously numerically unstable because the determinant + * calculation involves the difference of large, but similar, numbers. It is + * difficult to be sure that the calculation is stable for real world values + * and it is certain that it becomes unstable where the end points are close + * together. + * + * So this code uses the perhaps slightly less optimal but more + * understandable and totally obvious approach of calculating color-scale. + * + * This algorithm depends on the precision in white-scale and that is + * (1/white-y), so we can immediately see that as white-y approaches 0 the + * accuracy inherent in the cHRM chunk drops off substantially. + * + * libpng arithmetic: a simple inversion of the above equations + * ------------------------------------------------------------ + * + * white_scale = 1/white-y + * white-X = white-x * white-scale + * white-Y = 1.0 + * white-Z = (1 - white-x - white-y) * white_scale + * + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * This gives us three equations in (red-scale,green-scale,blue-scale) where + * all the coefficients are now known: + * + * red-x*red-scale + green-x*green-scale + blue-x*blue-scale + * = white-x/white-y + * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1 + * red-z*red-scale + green-z*green-scale + blue-z*blue-scale + * = (1 - white-x - white-y)/white-y + * + * In the last equation color-z is (1 - color-x - color-y) so we can add all + * three equations together to get an alternative third: + * + * red-scale + green-scale + blue-scale = 1/white-y = white-scale + * + * So now we have a Cramer's rule solution where the determinants are just + * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve + * multiplication of three coefficients so we can't guarantee to avoid + * overflow in the libpng fixed point representation. Using Cramer's rule in + * floating point is probably a good choice here, but it's not an option for + * fixed point. Instead proceed to simplify the first two equations by + * eliminating what is likely to be the largest value, blue-scale: + * + * blue-scale = white-scale - red-scale - green-scale + * + * Hence: + * + * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale = + * (white-x - blue-x)*white-scale + * + * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale = + * 1 - blue-y*white-scale + * + * And now we can trivially solve for (red-scale,green-scale): + * + * green-scale = + * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale + * ----------------------------------------------------------- + * green-x - blue-x + * + * red-scale = + * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale + * --------------------------------------------------------- + * red-y - blue-y + * + * Hence: + * + * red-scale = + * ( (green-x - blue-x) * (white-y - blue-y) - + * (green-y - blue-y) * (white-x - blue-x) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * green-scale = + * ( (red-y - blue-y) * (white-x - blue-x) - + * (red-x - blue-x) * (white-y - blue-y) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * Accuracy: + * The input values have 5 decimal digits of accuracy. + * + * In the previous implementation the values were all in the range 0 < value + * < 1, so simple products are in the same range but may need up to 10 + * decimal digits to preserve the original precision and avoid underflow. + * Because we are using a 32-bit signed representation we cannot match this; + * the best is a little over 9 decimal digits, less than 10. + * + * This range has now been extended to allow values up to 1.1, or 110,000 in + * fixed point. + * + * The approach used here is to preserve the maximum precision within the + * signed representation. Because the red-scale calculation above uses the + * difference between two products of values that must be in the range + * -1.1..+1.1 it is sufficient to divide the product by 8; + * ceil(121,000/32767*2). The factor is irrelevant in the calculation + * because it is applied to both numerator and denominator. + * + * Note that the values of the differences of the products of the + * chromaticities in the above equations tend to be small, for example for + * the sRGB chromaticities they are: + * + * red numerator: -0.04751 + * green numerator: -0.08788 + * denominator: -0.2241 (without white-y multiplication) + * + * The resultant Y coefficients from the chromaticities of some widely used + * color space definitions are (to 15 decimal places): + * + * sRGB + * 0.212639005871510 0.715168678767756 0.072192315360734 + * Kodak ProPhoto + * 0.288071128229293 0.711843217810102 0.000085653960605 + * Adobe RGB + * 0.297344975250536 0.627363566255466 0.075291458493998 + * Adobe Wide Gamut RGB + * 0.258728243040113 0.724682314948566 0.016589442011321 + */ + { + int error = 0; + + /* By the argument above overflow should be impossible here, however the + * code now simply returns a failure code. The xy subtracts in the + * arguments to png_muldiv are *not* checked for overflow because the + * checks at the start guarantee they are in the range 0..110000 and + * png_fixed_point is a 32-bit signed number. + */ + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 8) == 0) + return 1; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 8) == + 0) + return 1; + denominator = png_fp_sub(left, right, &error); + if (error) return 1; + + /* Now find the red numerator. */ + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 8) == 0) + return 1; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 8) == + 0) + return 1; + + /* Overflow is possible here and it indicates an extreme set of PNG cHRM + * chunk values. This calculation actually returns the reciprocal of the + * scale value because this allows us to delay the multiplication of + * white-y into the denominator, which tends to produce a small number. + */ + if (png_muldiv(&red_inverse, xy->whitey, denominator, + png_fp_sub(left, right, &error)) == 0 || error || + red_inverse <= xy->whitey /* r+g+b scales = white scale */) + return 1; + + /* Similarly for green_inverse: */ + if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 8) == 0) + return 1; + if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 8) == 0) + return 1; + if (png_muldiv(&green_inverse, xy->whitey, denominator, + png_fp_sub(left, right, &error)) == 0 || error || + green_inverse <= xy->whitey) + return 1; + + /* And the blue scale, the checks above guarantee this can't overflow but + * it can still produce 0 for extreme cHRM values. + */ + blue_scale = png_fp_sub(png_fp_sub(png_reciprocal(xy->whitey), + png_reciprocal(red_inverse), &error), + png_reciprocal(green_inverse), &error); + if (error || blue_scale <= 0) + return 1; + } + + /* And fill in the png_XYZ. Again the subtracts are safe because of the + * checks on the xy values at the start (the subtracts just calculate the + * corresponding z values.) + */ + if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, + red_inverse) == 0) + return 1; + + if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, + green_inverse) == 0) + return 1; + + if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, + PNG_FP_1) == 0) + return 1; + + return 0; /*success*/ +} +#endif /* COLORSPACE */ + +#ifdef PNG_READ_iCCP_SUPPORTED +/* Error message generation */ +static char +png_icc_tag_char(png_uint_32 byte) +{ + byte &= 0xff; + if (byte >= 32 && byte <= 126) + return (char)byte; + else + return '?'; +} + +static void +png_icc_tag_name(char *name, png_uint_32 tag) +{ + name[0] = '\''; + name[1] = png_icc_tag_char(tag >> 24); + name[2] = png_icc_tag_char(tag >> 16); + name[3] = png_icc_tag_char(tag >> 8); + name[4] = png_icc_tag_char(tag ); + name[5] = '\''; +} + +static int +is_ICC_signature_char(png_alloc_size_t it) +{ + return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) || + (it >= 97 && it <= 122); +} + +static int +is_ICC_signature(png_alloc_size_t it) +{ + return is_ICC_signature_char(it >> 24) /* checks all the top bits */ && + is_ICC_signature_char((it >> 16) & 0xff) && + is_ICC_signature_char((it >> 8) & 0xff) && + is_ICC_signature_char(it & 0xff); +} + +static int +png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name, + png_alloc_size_t value, png_const_charp reason) +{ + size_t pos; + char message[196]; /* see below for calculation */ + + pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */ + pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */ + pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */ + if (is_ICC_signature(value) != 0) + { + /* So 'value' is at most 4 bytes and the following cast is safe */ + png_icc_tag_name(message+pos, (png_uint_32)value); + pos += 6; /* total +8; less than the else clause */ + message[pos++] = ':'; + message[pos++] = ' '; + } +# ifdef PNG_WARNINGS_SUPPORTED + else + { + char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */ + + pos = png_safecat(message, (sizeof message), pos, + png_format_number(number, number+(sizeof number), + PNG_NUMBER_FORMAT_x, value)); + pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */ + } +# endif + /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ + pos = png_safecat(message, (sizeof message), pos, reason); + PNG_UNUSED(pos) + + png_chunk_benign_error(png_ptr, message); + + return 0; +} + +/* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value + * is XYZ(0.9642,1.0,0.8249), which scales to: + * + * (63189.8112, 65536, 54060.6464) + */ +static const png_byte D50_nCIEXYZ[12] = + { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d }; + +static int /* bool */ +icc_check_length(png_const_structrp png_ptr, png_const_charp name, + png_uint_32 profile_length) +{ + if (profile_length < 132) + return png_icc_profile_error(png_ptr, name, profile_length, "too short"); + return 1; +} + +int /* PRIVATE */ +png_icc_check_length(png_const_structrp png_ptr, png_const_charp name, + png_uint_32 profile_length) +{ + if (!icc_check_length(png_ptr, name, profile_length)) + return 0; + + /* This needs to be here because the 'normal' check is in + * png_decompress_chunk, yet this happens after the attempt to + * png_malloc_base the required data. We only need this on read; on write + * the caller supplies the profile buffer so libpng doesn't allocate it. See + * the call to icc_check_length below (the write case). + */ + if (profile_length > png_chunk_max(png_ptr)) + return png_icc_profile_error(png_ptr, name, profile_length, + "profile too long"); + + return 1; +} + +int /* PRIVATE */ +png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile/* first 132 bytes only */, int color_type) +{ + png_uint_32 temp; + + /* Length check; this cannot be ignored in this code because profile_length + * is used later to check the tag table, so even if the profile seems over + * long profile_length from the caller must be correct. The caller can fix + * this up on read or write by just passing in the profile header length. + */ + temp = png_get_uint_32(profile); + if (temp != profile_length) + return png_icc_profile_error(png_ptr, name, temp, + "length does not match profile"); + + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_length & 3)) + return png_icc_profile_error(png_ptr, name, profile_length, + "invalid length"); + + temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */ + if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */ + profile_length < 132+12*temp) /* truncated tag table */ + return png_icc_profile_error(png_ptr, name, temp, + "tag count too large"); + + /* The 'intent' must be valid or we can't store it, ICC limits the intent to + * 16 bits. + */ + temp = png_get_uint_32(profile+64); + if (temp >= 0xffff) /* The ICC limit */ + return png_icc_profile_error(png_ptr, name, temp, + "invalid rendering intent"); + + /* This is just a warning because the profile may be valid in future + * versions. + */ + if (temp >= PNG_sRGB_INTENT_LAST) + (void)png_icc_profile_error(png_ptr, name, temp, + "intent outside defined range"); + + /* At this point the tag table can't be checked because it hasn't necessarily + * been loaded; however, various header fields can be checked. These checks + * are for values permitted by the PNG spec in an ICC profile; the PNG spec + * restricts the profiles that can be passed in an iCCP chunk (they must be + * appropriate to processing PNG data!) + */ + + /* Data checks (could be skipped). These checks must be independent of the + * version number; however, the version number doesn't accommodate changes in + * the header fields (just the known tags and the interpretation of the + * data.) + */ + temp = png_get_uint_32(profile+36); /* signature 'ascp' */ + if (temp != 0x61637370) + return png_icc_profile_error(png_ptr, name, temp, + "invalid signature"); + + /* Currently the PCS illuminant/adopted white point (the computational + * white point) are required to be D50, + * however the profile contains a record of the illuminant so perhaps ICC + * expects to be able to change this in the future (despite the rationale in + * the introduction for using a fixed PCS adopted white.) Consequently the + * following is just a warning. + */ + if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0) + (void)png_icc_profile_error(png_ptr, name, 0/*no tag value*/, + "PCS illuminant is not D50"); + + /* The PNG spec requires this: + * "If the iCCP chunk is present, the image samples conform to the colour + * space represented by the embedded ICC profile as defined by the + * International Color Consortium [ICC]. The colour space of the ICC profile + * shall be an RGB colour space for colour images (PNG colour types 2, 3, and + * 6), or a greyscale colour space for greyscale images (PNG colour types 0 + * and 4)." + * + * This checking code ensures the embedded profile (on either read or write) + * conforms to the specification requirements. Notice that an ICC 'gray' + * color-space profile contains the information to transform the monochrome + * data to XYZ or L*a*b (according to which PCS the profile uses) and this + * should be used in preference to the standard libpng K channel replication + * into R, G and B channels. + * + * Previously it was suggested that an RGB profile on grayscale data could be + * handled. However it it is clear that using an RGB profile in this context + * must be an error - there is no specification of what it means. Thus it is + * almost certainly more correct to ignore the profile. + */ + temp = png_get_uint_32(profile+16); /* data colour space field */ + switch (temp) + { + case 0x52474220: /* 'RGB ' */ + if ((color_type & PNG_COLOR_MASK_COLOR) == 0) + return png_icc_profile_error(png_ptr, name, temp, + "RGB color space not permitted on grayscale PNG"); + break; + + case 0x47524159: /* 'GRAY' */ + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + return png_icc_profile_error(png_ptr, name, temp, + "Gray color space not permitted on RGB PNG"); + break; + + default: + return png_icc_profile_error(png_ptr, name, temp, + "invalid ICC profile color space"); + } + + /* It is up to the application to check that the profile class matches the + * application requirements; the spec provides no guidance, but it's pretty + * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer + * ('prtr') or 'spac' (for generic color spaces). Issue a warning in these + * cases. Issue an error for device link or abstract profiles - these don't + * contain the records necessary to transform the color-space to anything + * other than the target device (and not even that for an abstract profile). + * Profiles of these classes may not be embedded in images. + */ + temp = png_get_uint_32(profile+12); /* profile/device class */ + switch (temp) + { + case 0x73636e72: /* 'scnr' */ + case 0x6d6e7472: /* 'mntr' */ + case 0x70727472: /* 'prtr' */ + case 0x73706163: /* 'spac' */ + /* All supported */ + break; + + case 0x61627374: /* 'abst' */ + /* May not be embedded in an image */ + return png_icc_profile_error(png_ptr, name, temp, + "invalid embedded Abstract ICC profile"); + + case 0x6c696e6b: /* 'link' */ + /* DeviceLink profiles cannot be interpreted in a non-device specific + * fashion, if an app uses the AToB0Tag in the profile the results are + * undefined unless the result is sent to the intended device, + * therefore a DeviceLink profile should not be found embedded in a + * PNG. + */ + return png_icc_profile_error(png_ptr, name, temp, + "unexpected DeviceLink ICC profile class"); + + case 0x6e6d636c: /* 'nmcl' */ + /* A NamedColor profile is also device specific, however it doesn't + * contain an AToB0 tag that is open to misinterpretation. Almost + * certainly it will fail the tests below. + */ + (void)png_icc_profile_error(png_ptr, name, temp, + "unexpected NamedColor ICC profile class"); + break; + + default: + /* To allow for future enhancements to the profile accept unrecognized + * profile classes with a warning, these then hit the test below on the + * tag content to ensure they are backward compatible with one of the + * understood profiles. + */ + (void)png_icc_profile_error(png_ptr, name, temp, + "unrecognized ICC profile class"); + break; + } + + /* For any profile other than a device link one the PCS must be encoded + * either in XYZ or Lab. + */ + temp = png_get_uint_32(profile+20); + switch (temp) + { + case 0x58595a20: /* 'XYZ ' */ + case 0x4c616220: /* 'Lab ' */ + break; + + default: + return png_icc_profile_error(png_ptr, name, temp, + "unexpected ICC PCS encoding"); + } + + return 1; +} + +int /* PRIVATE */ +png_icc_check_tag_table(png_const_structrp png_ptr, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */) +{ + png_uint_32 tag_count = png_get_uint_32(profile+128); + png_uint_32 itag; + png_const_bytep tag = profile+132; /* The first tag */ + + /* First scan all the tags in the table and add bits to the icc_info value + * (temporarily in 'tags'). + */ + for (itag=0; itag < tag_count; ++itag, tag += 12) + { + png_uint_32 tag_id = png_get_uint_32(tag+0); + png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */ + png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */ + + /* The ICC specification does not exclude zero length tags, therefore the + * start might actually be anywhere if there is no data, but this would be + * a clear abuse of the intent of the standard so the start is checked for + * being in range. All defined tag types have an 8 byte header - a 4 byte + * type signature then 0. + */ + + /* This is a hard error; potentially it can cause read outside the + * profile. + */ + if (tag_start > profile_length || tag_length > profile_length - tag_start) + return png_icc_profile_error(png_ptr, name, tag_id, + "ICC profile tag outside profile"); + + if ((tag_start & 3) != 0) + { + /* CNHP730S.icc shipped with Microsoft Windows 64 violates this; it is + * only a warning here because libpng does not care about the + * alignment. + */ + (void)png_icc_profile_error(png_ptr, name, tag_id, + "ICC profile tag start not a multiple of 4"); + } + } + + return 1; /* success, maybe with warnings */ +} +#endif /* READ_iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +#if (defined PNG_READ_mDCV_SUPPORTED) || (defined PNG_READ_cHRM_SUPPORTED) +static int +have_chromaticities(png_const_structrp png_ptr) +{ + /* Handle new PNGv3 chunks and the precedence rules to determine whether + * png_struct::chromaticities must be processed. Only required for RGB to + * gray. + * + * mDCV: this is the mastering colour space and it is independent of the + * encoding so it needs to be used regardless of the encoded space. + * + * cICP: first in priority but not yet implemented - the chromaticities come + * from the 'primaries'. + * + * iCCP: not supported by libpng (so ignored) + * + * sRGB: the defaults match sRGB + * + * cHRM: calculate the coefficients + */ +# ifdef PNG_READ_mDCV_SUPPORTED + if (png_has_chunk(png_ptr, mDCV)) + return 1; +# define check_chromaticities 1 +# endif /*mDCV*/ + +# ifdef PNG_READ_sRGB_SUPPORTED + if (png_has_chunk(png_ptr, sRGB)) + return 0; +# endif /*sRGB*/ + +# ifdef PNG_READ_cHRM_SUPPORTED + if (png_has_chunk(png_ptr, cHRM)) + return 1; +# define check_chromaticities 1 +# endif /*cHRM*/ + + return 0; /* sRGB defaults */ +} +#endif /* READ_mDCV || READ_cHRM */ + +void /* PRIVATE */ +png_set_rgb_coefficients(png_structrp png_ptr) +{ + /* Set the rgb_to_gray coefficients from the colorspace if available. Note + * that '_set' means that png_rgb_to_gray was called **and** it successfully + * set up the coefficients. + */ + if (png_ptr->rgb_to_gray_coefficients_set == 0) + { +# if check_chromaticities + png_XYZ xyz; + + if (have_chromaticities(png_ptr) && + png_XYZ_from_xy(&xyz, &png_ptr->chromaticities) == 0) + { + /* png_set_rgb_to_gray has not set the coefficients, get them from the + * Y * values of the colorspace colorants. + */ + png_fixed_point r = xyz.red_Y; + png_fixed_point g = xyz.green_Y; + png_fixed_point b = xyz.blue_Y; + png_fixed_point total = r+g+b; + + if (total > 0 && + r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && + g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && + b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && + r+g+b <= 32769) + { + /* We allow 0 coefficients here. r+g+b may be 32769 if two or + * all of the coefficients were rounded up. Handle this by + * reducing the *largest* coefficient by 1; this matches the + * approach used for the default coefficients in pngrtran.c + */ + int add = 0; + + if (r+g+b > 32768) + add = -1; + else if (r+g+b < 32768) + add = 1; + + if (add != 0) + { + if (g >= r && g >= b) + g += add; + else if (r >= g && r >= b) + r += add; + else + b += add; + } + + /* Check for an internal error. */ + if (r+g+b != 32768) + png_error(png_ptr, + "internal error handling cHRM coefficients"); + + else + { + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; + } + } + } + else +# endif /* check_chromaticities */ + { + /* Use the historical REC 709 (etc) values: */ + png_ptr->rgb_to_gray_red_coeff = 6968; + png_ptr->rgb_to_gray_green_coeff = 23434; + /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ + } + } +} +#endif /* READ_RGB_TO_GRAY */ + +void /* PRIVATE */ +png_check_IHDR(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + int error = 0; + + /* Check for width and height valid values */ + if (width == 0) + { + png_warning(png_ptr, "Image width is zero in IHDR"); + error = 1; + } + + if (width > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image width in IHDR"); + error = 1; + } + + /* The bit mask on the first line below must be at least as big as a + * png_uint_32. "~7U" is not adequate on 16-bit systems because it will + * be an unsigned 16-bit value. Casting to (png_alloc_size_t) makes the + * type of the result at least as bit (in bits) as the RHS of the > operator + * which also avoids a common warning on 64-bit systems that the comparison + * of (png_uint_32) against the constant value on the RHS will always be + * false. + */ + if (((width + 7) & ~(png_alloc_size_t)7) > + (((PNG_SIZE_MAX + - 48 /* big_row_buf hack */ + - 1) /* filter byte */ + / 8) /* 8-byte RGBA pixels */ + - 1)) /* extra max_pixel_depth pad */ + { + /* The size of the row must be within the limits of this architecture. + * Because the read code can perform arbitrary transformations the + * maximum size is checked here. Because the code in png_read_start_row + * adds extra space "for safety's sake" in several places a conservative + * limit is used here. + * + * NOTE: it would be far better to check the size that is actually used, + * but the effect in the real world is minor and the changes are more + * extensive, therefore much more dangerous and much more difficult to + * write in a way that avoids compiler warnings. + */ + png_warning(png_ptr, "Image width is too large for this architecture"); + error = 1; + } + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max) +#else + if (width > PNG_USER_WIDTH_MAX) +#endif + { + png_warning(png_ptr, "Image width exceeds user limit in IHDR"); + error = 1; + } + + if (height == 0) + { + png_warning(png_ptr, "Image height is zero in IHDR"); + error = 1; + } + + if (height > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image height in IHDR"); + error = 1; + } + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (height > png_ptr->user_height_max) +#else + if (height > PNG_USER_HEIGHT_MAX) +#endif + { + png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + error = 1; + } + + /* Check other values */ + if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && + bit_depth != 8 && bit_depth != 16) + { + png_warning(png_ptr, "Invalid bit depth in IHDR"); + error = 1; + } + + if (color_type < 0 || color_type == 1 || + color_type == 5 || color_type > 6) + { + png_warning(png_ptr, "Invalid color type in IHDR"); + error = 1; + } + + if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || + ((color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) + { + png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR"); + error = 1; + } + + if (interlace_type >= PNG_INTERLACE_LAST) + { + png_warning(png_ptr, "Unknown interlace method in IHDR"); + error = 1; + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Unknown compression method in IHDR"); + error = 1; + } + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Accept filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not read a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && + png_ptr->mng_features_permitted != 0) + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + + if (filter_type != PNG_FILTER_TYPE_BASE) + { + if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA))) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } + + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0) + { + png_warning(png_ptr, "Invalid filter method in IHDR"); + error = 1; + } + } + +#else + if (filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } +#endif + + if (error == 1) + png_error(png_ptr, "Invalid IHDR data"); +} + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* ASCII to fp functions */ +/* Check an ASCII formatted floating point value, see the more detailed + * comments in pngpriv.h + */ +/* The following is used internally to preserve the sticky flags */ +#define png_fp_add(state, flags) ((state) |= (flags)) +#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY)) + +int /* PRIVATE */ +png_check_fp_number(png_const_charp string, size_t size, int *statep, + size_t *whereami) +{ + int state = *statep; + size_t i = *whereami; + + while (i < size) + { + int type; + /* First find the type of the next character */ + switch (string[i]) + { + case 43: type = PNG_FP_SAW_SIGN; break; + case 45: type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break; + case 46: type = PNG_FP_SAW_DOT; break; + case 48: type = PNG_FP_SAW_DIGIT; break; + case 49: case 50: case 51: case 52: + case 53: case 54: case 55: case 56: + case 57: type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break; + case 69: + case 101: type = PNG_FP_SAW_E; break; + default: goto PNG_FP_End; + } + + /* Now deal with this type according to the current + * state, the type is arranged to not overlap the + * bits of the PNG_FP_STATE. + */ + switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) + { + case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: + if ((state & PNG_FP_SAW_ANY) != 0) + goto PNG_FP_End; /* not a part of the number */ + + png_fp_add(state, type); + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_DOT: + /* Ok as trailer, ok as lead of fraction. */ + if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */ + goto PNG_FP_End; + + else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */ + png_fp_add(state, type); + + else + png_fp_set(state, PNG_FP_FRACTION | type); + + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: + if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */ + png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); + + png_fp_add(state, type | PNG_FP_WAS_VALID); + + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_E: + if ((state & PNG_FP_SAW_DIGIT) == 0) + goto PNG_FP_End; + + png_fp_set(state, PNG_FP_EXPONENT); + + break; + + /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN: + goto PNG_FP_End; ** no sign in fraction */ + + /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT: + goto PNG_FP_End; ** Because SAW_DOT is always set */ + + case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT: + png_fp_add(state, type | PNG_FP_WAS_VALID); + break; + + case PNG_FP_FRACTION + PNG_FP_SAW_E: + /* This is correct because the trailing '.' on an + * integer is handled above - so we can only get here + * with the sequence ".E" (with no preceding digits). + */ + if ((state & PNG_FP_SAW_DIGIT) == 0) + goto PNG_FP_End; + + png_fp_set(state, PNG_FP_EXPONENT); + + break; + + case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: + if ((state & PNG_FP_SAW_ANY) != 0) + goto PNG_FP_End; /* not a part of the number */ + + png_fp_add(state, PNG_FP_SAW_SIGN); + + break; + + /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT: + goto PNG_FP_End; */ + + case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT: + png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID); + + break; + + /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E: + goto PNG_FP_End; */ + + default: goto PNG_FP_End; /* I.e. break 2 */ + } + + /* The character seems ok, continue. */ + ++i; + } + +PNG_FP_End: + /* Here at the end, update the state and return the correct + * return code. + */ + *statep = state; + *whereami = i; + + return (state & PNG_FP_SAW_DIGIT) != 0; +} + + +/* The same but for a complete string. */ +int +png_check_fp_string(png_const_charp string, size_t size) +{ + int state=0; + size_t char_index=0; + + if (png_check_fp_number(string, size, &state, &char_index) != 0 && + (char_index == size || string[char_index] == 0)) + return state /* must be non-zero - see above */; + + return 0; /* i.e. fail */ +} +#endif /* pCAL || sCAL */ + +#ifdef PNG_sCAL_SUPPORTED +# ifdef PNG_FLOATING_POINT_SUPPORTED +/* Utility used below - a simple accurate power of ten from an integral + * exponent. + */ +static double +png_pow10(int power) +{ + int recip = 0; + double d = 1; + + /* Handle negative exponent with a reciprocal at the end because + * 10 is exact whereas .1 is inexact in base 2 + */ + if (power < 0) + { + if (power < DBL_MIN_10_EXP) return 0; + recip = 1; power = -power; + } + + if (power > 0) + { + /* Decompose power bitwise. */ + double mult = 10; + do + { + if (power & 1) d *= mult; + mult *= mult; + power >>= 1; + } + while (power > 0); + + if (recip != 0) d = 1/d; + } + /* else power is 0 and d is 1 */ + + return d; +} + +/* Function to format a floating point value in ASCII with a given + * precision. + */ +void /* PRIVATE */ +png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, + double fp, unsigned int precision) +{ + /* We use standard functions from math.h, but not printf because + * that would require stdio. The caller must supply a buffer of + * sufficient size or we will png_error. The tests on size and + * the space in ascii[] consumed are indicated below. + */ + if (precision < 1) + precision = DBL_DIG; + + /* Enforce the limit of the implementation precision too. */ + if (precision > DBL_DIG+1) + precision = DBL_DIG+1; + + /* Basic sanity checks */ + if (size >= precision+5) /* See the requirements below. */ + { + if (fp < 0) + { + fp = -fp; + *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */ + --size; + } + + if (fp >= DBL_MIN && fp <= DBL_MAX) + { + int exp_b10; /* A base 10 exponent */ + double base; /* 10^exp_b10 */ + + /* First extract a base 10 exponent of the number, + * the calculation below rounds down when converting + * from base 2 to base 10 (multiply by log10(2) - + * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to + * be increased. Note that the arithmetic shift + * performs a floor() unlike C arithmetic - using a + * C multiply would break the following for negative + * exponents. + */ + (void)frexp(fp, &exp_b10); /* exponent to base 2 */ + + exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */ + + /* Avoid underflow here. */ + base = png_pow10(exp_b10); /* May underflow */ + + while (base < DBL_MIN || base < fp) + { + /* And this may overflow. */ + double test = png_pow10(exp_b10+1); + + if (test <= DBL_MAX) + { + ++exp_b10; base = test; + } + + else + break; + } + + /* Normalize fp and correct exp_b10, after this fp is in the + * range [.1,1) and exp_b10 is both the exponent and the digit + * *before* which the decimal point should be inserted + * (starting with 0 for the first digit). Note that this + * works even if 10^exp_b10 is out of range because of the + * test on DBL_MAX above. + */ + fp /= base; + while (fp >= 1) + { + fp /= 10; ++exp_b10; + } + + /* Because of the code above fp may, at this point, be + * less than .1, this is ok because the code below can + * handle the leading zeros this generates, so no attempt + * is made to correct that here. + */ + + { + unsigned int czero, clead, cdigits; + char exponent[10]; + + /* Allow up to two leading zeros - this will not lengthen + * the number compared to using E-n. + */ + if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */ + { + czero = 0U-exp_b10; /* PLUS 2 digits: TOTAL 3 */ + exp_b10 = 0; /* Dot added below before first output. */ + } + else + czero = 0; /* No zeros to add */ + + /* Generate the digit list, stripping trailing zeros and + * inserting a '.' before a digit if the exponent is 0. + */ + clead = czero; /* Count of leading zeros */ + cdigits = 0; /* Count of digits in list. */ + + do + { + double d; + + fp *= 10; + /* Use modf here, not floor and subtract, so that + * the separation is done in one step. At the end + * of the loop don't break the number into parts so + * that the final digit is rounded. + */ + if (cdigits+czero+1 < precision+clead) + fp = modf(fp, &d); + + else + { + d = floor(fp + .5); + + if (d > 9) + { + /* Rounding up to 10, handle that here. */ + if (czero > 0) + { + --czero; d = 1; + if (cdigits == 0) --clead; + } + else + { + while (cdigits > 0 && d > 9) + { + int ch = *--ascii; + + if (exp_b10 != (-1)) + ++exp_b10; + + else if (ch == 46) + { + ch = *--ascii; ++size; + /* Advance exp_b10 to '1', so that the + * decimal point happens after the + * previous digit. + */ + exp_b10 = 1; + } + + --cdigits; + d = ch - 47; /* I.e. 1+(ch-48) */ + } + + /* Did we reach the beginning? If so adjust the + * exponent but take into account the leading + * decimal point. + */ + if (d > 9) /* cdigits == 0 */ + { + if (exp_b10 == (-1)) + { + /* Leading decimal point (plus zeros?), if + * we lose the decimal point here it must + * be reentered below. + */ + int ch = *--ascii; + + if (ch == 46) + { + ++size; exp_b10 = 1; + } + + /* Else lost a leading zero, so 'exp_b10' is + * still ok at (-1) + */ + } + else + ++exp_b10; + + /* In all cases we output a '1' */ + d = 1; + } + } + } + fp = 0; /* Guarantees termination below. */ + } + + if (d == 0) + { + ++czero; + if (cdigits == 0) ++clead; + } + else + { + /* Included embedded zeros in the digit count. */ + cdigits += czero - clead; + clead = 0; + + while (czero > 0) + { + /* exp_b10 == (-1) means we just output the decimal + * place - after the DP don't adjust 'exp_b10' any + * more! + */ + if (exp_b10 != (-1)) + { + if (exp_b10 == 0) + { + *ascii++ = 46; --size; + } + /* PLUS 1: TOTAL 4 */ + --exp_b10; + } + *ascii++ = 48; --czero; + } + + if (exp_b10 != (-1)) + { + if (exp_b10 == 0) + { + *ascii++ = 46; --size; /* counted above */ + } + + --exp_b10; + } + *ascii++ = (char)(48 + (int)d); ++cdigits; + } + } + while (cdigits+czero < precision+clead && fp > DBL_MIN); + + /* The total output count (max) is now 4+precision */ + + /* Check for an exponent, if we don't need one we are + * done and just need to terminate the string. At this + * point, exp_b10==(-1) is effectively a flag: it got + * to '-1' because of the decrement, after outputting + * the decimal point above. (The exponent required is + * *not* -1.) + */ + if (exp_b10 >= (-1) && exp_b10 <= 2) + { + /* The following only happens if we didn't output the + * leading zeros above for negative exponent, so this + * doesn't add to the digit requirement. Note that the + * two zeros here can only be output if the two leading + * zeros were *not* output, so this doesn't increase + * the output count. + */ + while (exp_b10-- > 0) *ascii++ = 48; + + *ascii = 0; + + /* Total buffer requirement (including the '\0') is + * 5+precision - see check at the start. + */ + return; + } + + /* Here if an exponent is required, adjust size for + * the digits we output but did not count. The total + * digit output here so far is at most 1+precision - no + * decimal point and no leading or trailing zeros have + * been output. + */ + size -= cdigits; + + *ascii++ = 69; --size; /* 'E': PLUS 1 TOTAL 2+precision */ + + /* The following use of an unsigned temporary avoids ambiguities in + * the signed arithmetic on exp_b10 and permits GCC at least to do + * better optimization. + */ + { + unsigned int uexp_b10; + + if (exp_b10 < 0) + { + *ascii++ = 45; --size; /* '-': PLUS 1 TOTAL 3+precision */ + uexp_b10 = 0U-exp_b10; + } + + else + uexp_b10 = 0U+exp_b10; + + cdigits = 0; + + while (uexp_b10 > 0) + { + exponent[cdigits++] = (char)(48 + uexp_b10 % 10); + uexp_b10 /= 10; + } + } + + /* Need another size check here for the exponent digits, so + * this need not be considered above. + */ + if (size > cdigits) + { + while (cdigits > 0) *ascii++ = exponent[--cdigits]; + + *ascii = 0; + + return; + } + } + } + else if (!(fp >= DBL_MIN)) + { + *ascii++ = 48; /* '0' */ + *ascii = 0; + return; + } + else + { + *ascii++ = 105; /* 'i' */ + *ascii++ = 110; /* 'n' */ + *ascii++ = 102; /* 'f' */ + *ascii = 0; + return; + } + } + + /* Here on buffer too small. */ + png_error(png_ptr, "ASCII conversion buffer too small"); +} +# endif /* FLOATING_POINT */ + +# ifdef PNG_FIXED_POINT_SUPPORTED +/* Function to format a fixed point value in ASCII. + */ +void /* PRIVATE */ +png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, + size_t size, png_fixed_point fp) +{ + /* Require space for 10 decimal digits, a decimal point, a minus sign and a + * trailing \0, 13 characters: + */ + if (size > 12) + { + png_uint_32 num; + + /* Avoid overflow here on the minimum integer. */ + if (fp < 0) + { + *ascii++ = 45; num = (png_uint_32)(-fp); + } + else + num = (png_uint_32)fp; + + if (num <= 0x80000000) /* else overflowed */ + { + unsigned int ndigits = 0, first = 16 /* flag value */; + char digits[10] = {0}; + + while (num) + { + /* Split the low digit off num: */ + unsigned int tmp = num/10; + num -= tmp*10; + digits[ndigits++] = (char)(48 + num); + /* Record the first non-zero digit, note that this is a number + * starting at 1, it's not actually the array index. + */ + if (first == 16 && num > 0) + first = ndigits; + num = tmp; + } + + if (ndigits > 0) + { + while (ndigits > 5) *ascii++ = digits[--ndigits]; + /* The remaining digits are fractional digits, ndigits is '5' or + * smaller at this point. It is certainly not zero. Check for a + * non-zero fractional digit: + */ + if (first <= 5) + { + unsigned int i; + *ascii++ = 46; /* decimal point */ + /* ndigits may be <5 for small numbers, output leading zeros + * then ndigits digits to first: + */ + i = 5; + while (ndigits < i) + { + *ascii++ = 48; --i; + } + while (ndigits >= first) *ascii++ = digits[--ndigits]; + /* Don't output the trailing zeros! */ + } + } + else + *ascii++ = 48; + + /* And null terminate the string: */ + *ascii = 0; + return; + } + } + + /* Here on buffer too small. */ + png_error(png_ptr, "ASCII conversion buffer too small"); +} +# endif /* FIXED_POINT */ +#endif /* SCAL */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +png_fixed_point +png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) +{ + double r = floor(100000 * fp + .5); + + if (r > 2147483647. || r < -2147483648.) + png_fixed_error(png_ptr, text); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(text) +# endif + + return (png_fixed_point)r; +} +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED)) +png_uint_32 +png_fixed_ITU(png_const_structrp png_ptr, double fp, png_const_charp text) +{ + double r = floor(10000 * fp + .5); + + if (r > 2147483647. || r < 0) + png_fixed_error(png_ptr, text); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(text) +# endif + + return (png_uint_32)r; +} +#endif + + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) +/* muldiv functions */ +/* This API takes signed arguments and rounds the result to the nearest + * integer (or, for a fixed point number - the standard argument - to + * the nearest .00001). Overflow and divide by zero are signalled in + * the result, a boolean - true on success, false on overflow. + */ +int /* PRIVATE */ +png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, + png_int_32 divisor) +{ + /* Return a * times / divisor, rounded. */ + if (divisor != 0) + { + if (a == 0 || times == 0) + { + *res = 0; + return 1; + } + else + { +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = a; + r *= times; + r /= divisor; + r = floor(r+.5); + + /* A png_fixed_point is a 32-bit integer. */ + if (r <= 2147483647. && r >= -2147483648.) + { + *res = (png_fixed_point)r; + return 1; + } +#else + int negative = 0; + png_uint_32 A, T, D; + png_uint_32 s16, s32, s00; + + if (a < 0) + negative = 1, A = -a; + else + A = a; + + if (times < 0) + negative = !negative, T = -times; + else + T = times; + + if (divisor < 0) + negative = !negative, D = -divisor; + else + D = divisor; + + /* Following can't overflow because the arguments only + * have 31 bits each, however the result may be 32 bits. + */ + s16 = (A >> 16) * (T & 0xffff) + + (A & 0xffff) * (T >> 16); + /* Can't overflow because the a*times bit is only 30 + * bits at most. + */ + s32 = (A >> 16) * (T >> 16) + (s16 >> 16); + s00 = (A & 0xffff) * (T & 0xffff); + + s16 = (s16 & 0xffff) << 16; + s00 += s16; + + if (s00 < s16) + ++s32; /* carry */ + + if (s32 < D) /* else overflow */ + { + /* s32.s00 is now the 64-bit product, do a standard + * division, we know that s32 < D, so the maximum + * required shift is 31. + */ + int bitshift = 32; + png_fixed_point result = 0; /* NOTE: signed */ + + while (--bitshift >= 0) + { + png_uint_32 d32, d00; + + if (bitshift > 0) + d32 = D >> (32-bitshift), d00 = D << bitshift; + + else + d32 = 0, d00 = D; + + if (s32 > d32) + { + if (s00 < d00) --s32; /* carry */ + s32 -= d32, s00 -= d00, result += 1<= d00) + s32 = 0, s00 -= d00, result += 1<= (D >> 1)) + ++result; + + if (negative != 0) + result = -result; + + /* Check for overflow. */ + if ((negative != 0 && result <= 0) || + (negative == 0 && result >= 0)) + { + *res = result; + return 1; + } + } +#endif + } + } + + return 0; +} + +/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ +png_fixed_point +png_reciprocal(png_fixed_point a) +{ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = floor(1E10/a+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + png_fixed_point res; + + if (png_muldiv(&res, 100000, 100000, a) != 0) + return res; +#endif + + return 0; /* error/overflow */ +} +#endif /* READ_GAMMA || COLORSPACE || INCH_CONVERSIONS || READ_pHYS */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* This is the shared test on whether a gamma value is 'significant' - whether + * it is worth doing gamma correction. + */ +int /* PRIVATE */ +png_gamma_significant(png_fixed_point gamma_val) +{ + /* sRGB: 1/2.2 == 0.4545(45) + * AdobeRGB: 1/(2+51/256) ~= 0.45471 5dp + * + * So the correction from AdobeRGB to sRGB (output) is: + * + * 2.2/(2+51/256) == 1.00035524 + * + * I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/- + * 23). Note that the Adobe choice seems to be something intended to give an + * exact number with 8 binary fractional digits - it is the closest to 2.2 + * that is possible a base 2 .8p representation. + */ + return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || + gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; +} + +#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED +/* A local convenience routine. */ +static png_fixed_point +png_product2(png_fixed_point a, png_fixed_point b) +{ + /* The required result is a * b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Should now be unused */ + double r = a * 1E-5; + r *= b; + r = floor(r+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + png_fixed_point res; + + if (png_muldiv(&res, a, b, 100000) != 0) + return res; +#endif + + return 0; /* overflow */ +} +#endif /* FLOATING_ARITHMETIC */ + +png_fixed_point +png_reciprocal2(png_fixed_point a, png_fixed_point b) +{ + /* The required result is 1/a * 1/b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + if (a != 0 && b != 0) + { + double r = 1E15/a; + r /= b; + r = floor(r+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; + } +#else + /* This may overflow because the range of png_fixed_point isn't symmetric, + * but this API is only used for the product of file and screen gamma so it + * doesn't matter that the smallest number it can produce is 1/21474, not + * 1/100000 + */ + png_fixed_point res = png_product2(a, b); + + if (res != 0) + return png_reciprocal(res); +#endif + + return 0; /* overflow */ +} +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */ +#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED +/* Fixed point gamma. + * + * The code to calculate the tables used below can be found in the shell script + * contrib/tools/intgamma.sh + * + * To calculate gamma this code implements fast log() and exp() calls using only + * fixed point arithmetic. This code has sufficient precision for either 8-bit + * or 16-bit sample values. + * + * The tables used here were calculated using simple 'bc' programs, but C double + * precision floating point arithmetic would work fine. + * + * 8-bit log table + * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to + * 255, so it's the base 2 logarithm of a normalized 8-bit floating point + * mantissa. The numbers are 32-bit fractions. + */ +static const png_uint_32 +png_8bit_l2[128] = +{ + 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U, + 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U, + 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U, + 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U, + 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U, + 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U, + 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U, + 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U, + 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U, + 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U, + 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U, + 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U, + 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U, + 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U, + 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U, + 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U, + 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U, + 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U, + 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U, + 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U, + 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, + 24347096U, 0U + +#if 0 + /* The following are the values for 16-bit tables - these work fine for the + * 8-bit conversions but produce very slightly larger errors in the 16-bit + * log (about 1.2 as opposed to 0.7 absolute error in the final value). To + * use these all the shifts below must be adjusted appropriately. + */ + 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054, + 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803, + 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068, + 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782, + 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887, + 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339, + 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098, + 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132, + 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415, + 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523, + 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495, + 1119, 744, 372 +#endif +}; + +static png_int_32 +png_log8bit(unsigned int x) +{ + unsigned int lg2 = 0; + /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log, + * because the log is actually negate that means adding 1. The final + * returned value thus has the range 0 (for 255 input) to 7.994 (for 1 + * input), return -1 for the overflow (log 0) case, - so the result is + * always at most 19 bits. + */ + if ((x &= 0xff) == 0) + return -1; + + if ((x & 0xf0) == 0) + lg2 = 4, x <<= 4; + + if ((x & 0xc0) == 0) + lg2 += 2, x <<= 2; + + if ((x & 0x80) == 0) + lg2 += 1, x <<= 1; + + /* result is at most 19 bits, so this cast is safe: */ + return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16)); +} + +/* The above gives exact (to 16 binary places) log2 values for 8-bit images, + * for 16-bit images we use the most significant 8 bits of the 16-bit value to + * get an approximation then multiply the approximation by a correction factor + * determined by the remaining up to 8 bits. This requires an additional step + * in the 16-bit case. + * + * We want log2(value/65535), we have log2(v'/255), where: + * + * value = v' * 256 + v'' + * = v' * f + * + * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128 + * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less + * than 258. The final factor also needs to correct for the fact that our 8-bit + * value is scaled by 255, whereas the 16-bit values must be scaled by 65535. + * + * This gives a final formula using a calculated value 'x' which is value/v' and + * scaling by 65536 to match the above table: + * + * log2(x/257) * 65536 + * + * Since these numbers are so close to '1' we can use simple linear + * interpolation between the two end values 256/257 (result -368.61) and 258/257 + * (result 367.179). The values used below are scaled by a further 64 to give + * 16-bit precision in the interpolation: + * + * Start (256): -23591 + * Zero (257): 0 + * End (258): 23499 + */ +#ifdef PNG_16BIT_SUPPORTED +static png_int_32 +png_log16bit(png_uint_32 x) +{ + unsigned int lg2 = 0; + + /* As above, but now the input has 16 bits. */ + if ((x &= 0xffff) == 0) + return -1; + + if ((x & 0xff00) == 0) + lg2 = 8, x <<= 8; + + if ((x & 0xf000) == 0) + lg2 += 4, x <<= 4; + + if ((x & 0xc000) == 0) + lg2 += 2, x <<= 2; + + if ((x & 0x8000) == 0) + lg2 += 1, x <<= 1; + + /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional + * value. + */ + lg2 <<= 28; + lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4; + + /* Now we need to interpolate the factor, this requires a division by the top + * 8 bits. Do this with maximum precision. + */ + x = ((x << 16) + (x >> 9)) / (x >> 8); + + /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24, + * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly + * 16 bits to interpolate to get the low bits of the result. Round the + * answer. Note that the end point values are scaled by 64 to retain overall + * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust + * the overall scaling by 6-12. Round at every step. + */ + x -= 1U << 24; + + if (x <= 65536U) /* <= '257' */ + lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12); + + else + lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12); + + /* Safe, because the result can't have more than 20 bits: */ + return (png_int_32)((lg2 + 2048) >> 12); +} +#endif /* 16BIT */ + +/* The 'exp()' case must invert the above, taking a 20-bit fixed point + * logarithmic value and returning a 16 or 8-bit number as appropriate. In + * each case only the low 16 bits are relevant - the fraction - since the + * integer bits (the top 4) simply determine a shift. + * + * The worst case is the 16-bit distinction between 65535 and 65534. This + * requires perhaps spurious accuracy in the decoding of the logarithm to + * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance + * of getting this accuracy in practice. + * + * To deal with this the following exp() function works out the exponent of the + * fractional part of the logarithm by using an accurate 32-bit value from the + * top four fractional bits then multiplying in the remaining bits. + */ +static const png_uint_32 +png_32bit_exp[16] = +{ + /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ + 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, + 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, + 2553802834U, 2445529972U, 2341847524U, 2242560872U +}; + +/* Adjustment table; provided to explain the numbers in the code below. */ +#if 0 +for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} + 11 44937.64284865548751208448 + 10 45180.98734845585101160448 + 9 45303.31936980687359311872 + 8 45364.65110595323018870784 + 7 45395.35850361789624614912 + 6 45410.72259715102037508096 + 5 45418.40724413220722311168 + 4 45422.25021786898173001728 + 3 45424.17186732298419044352 + 2 45425.13273269940811464704 + 1 45425.61317555035558641664 + 0 45425.85339951654943850496 +#endif + +static png_uint_32 +png_exp(png_fixed_point x) +{ + if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ + { + /* Obtain a 4-bit approximation */ + png_uint_32 e = png_32bit_exp[(x >> 12) & 0x0f]; + + /* Incorporate the low 12 bits - these decrease the returned value by + * multiplying by a number less than 1 if the bit is set. The multiplier + * is determined by the above table and the shift. Notice that the values + * converge on 45426 and this is used to allow linear interpolation of the + * low bits. + */ + if (x & 0x800) + e -= (((e >> 16) * 44938U) + 16U) >> 5; + + if (x & 0x400) + e -= (((e >> 16) * 45181U) + 32U) >> 6; + + if (x & 0x200) + e -= (((e >> 16) * 45303U) + 64U) >> 7; + + if (x & 0x100) + e -= (((e >> 16) * 45365U) + 128U) >> 8; + + if (x & 0x080) + e -= (((e >> 16) * 45395U) + 256U) >> 9; + + if (x & 0x040) + e -= (((e >> 16) * 45410U) + 512U) >> 10; + + /* And handle the low 6 bits in a single block. */ + e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9; + + /* Handle the upper bits of x. */ + e >>= x >> 16; + return e; + } + + /* Check for overflow */ + if (x <= 0) + return png_32bit_exp[0]; + + /* Else underflow */ + return 0; +} + +static png_byte +png_exp8bit(png_fixed_point lg2) +{ + /* Get a 32-bit value: */ + png_uint_32 x = png_exp(lg2); + + /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the + * second, rounding, step can't overflow because of the first, subtraction, + * step. + */ + x -= x >> 8; + return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff); +} + +#ifdef PNG_16BIT_SUPPORTED +static png_uint_16 +png_exp16bit(png_fixed_point lg2) +{ + /* Get a 32-bit value: */ + png_uint_32 x = png_exp(lg2); + + /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */ + x -= x >> 16; + return (png_uint_16)((x + 32767U) >> 16); +} +#endif /* 16BIT */ +#endif /* FLOATING_ARITHMETIC */ + +png_byte +png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) +{ + if (value > 0 && value < 255) + { +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly + * convert this to a floating point value. This includes values that + * would overflow if 'value' were to be converted to 'int'. + * + * Apparently GCC, however, does an intermediate conversion to (int) + * on some (ARM) but not all (x86) platforms, possibly because of + * hardware FP limitations. (E.g. if the hardware conversion always + * assumes the integer register contains a signed value.) This results + * in ANSI-C undefined behavior for large values. + * + * Other implementations on the same machine might actually be ANSI-C90 + * conformant and therefore compile spurious extra code for the large + * values. + * + * We can be reasonably sure that an unsigned to float conversion + * won't be faster than an int to float one. Therefore this code + * assumes responsibility for the undefined behavior, which it knows + * can't happen because of the check above. + * + * Note the argument to this routine is an (unsigned int) because, on + * 16-bit platforms, it is assigned a value which might be out of + * range for an (int); that would result in undefined behavior in the + * caller if the *argument* ('value') were to be declared (int). + */ + double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5); + return (png_byte)r; +# else + png_int_32 lg2 = png_log8bit(value); + png_fixed_point res; + + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) + return png_exp8bit(res); + + /* Overflow. */ + value = 0; +# endif + } + + return (png_byte)(value & 0xff); +} + +#ifdef PNG_16BIT_SUPPORTED +png_uint_16 +png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) +{ + if (value > 0 && value < 65535) + { +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* The same (unsigned int)->(double) constraints apply here as above, + * however in this case the (unsigned int) to (int) conversion can + * overflow on an ANSI-C90 compliant system so the cast needs to ensure + * that this is not possible. + */ + double r = floor(65535*pow((png_int_32)value/65535., + gamma_val*.00001)+.5); + return (png_uint_16)r; +# else + png_int_32 lg2 = png_log16bit(value); + png_fixed_point res; + + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) + return png_exp16bit(res); + + /* Overflow. */ + value = 0; +# endif + } + + return (png_uint_16)value; +} +#endif /* 16BIT */ + +/* This does the right thing based on the bit_depth field of the + * png_struct, interpreting values as 8-bit or 16-bit. While the result + * is nominally a 16-bit value if bit depth is 8 then the result is + * 8-bit (as are the arguments.) + */ +png_uint_16 /* PRIVATE */ +png_gamma_correct(png_structrp png_ptr, unsigned int value, + png_fixed_point gamma_val) +{ + if (png_ptr->bit_depth == 8) + return png_gamma_8bit_correct(value, gamma_val); + +#ifdef PNG_16BIT_SUPPORTED + else + return png_gamma_16bit_correct(value, gamma_val); +#else + /* should not reach this */ + return 0; +#endif /* 16BIT */ +} + +#ifdef PNG_16BIT_SUPPORTED +/* Internal function to build a single 16-bit table - the table consists of + * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount + * to shift the input values right (or 16-number_of_signifiant_bits). + * + * The caller is responsible for ensuring that the table gets cleaned up on + * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument + * should be somewhere that will be cleaned. + */ +static void +png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, + unsigned int shift, png_fixed_point gamma_val) +{ + /* Various values derived from 'shift': */ + unsigned int num = 1U << (8U - shift); +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* CSE the division and work round wacky GCC warnings (see the comments + * in png_gamma_8bit_correct for where these come from.) + */ + double fmax = 1.0 / (((png_int_32)1 << (16U - shift)) - 1); +#endif + unsigned int max = (1U << (16U - shift)) - 1U; + unsigned int max_by_2 = 1U << (15U - shift); + unsigned int i; + + png_uint_16pp table = *ptable = + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); + + for (i = 0; i < num; i++) + { + png_uint_16p sub_table = table[i] = + (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16))); + + /* The 'threshold' test is repeated here because it can arise for one of + * the 16-bit tables even if the others don't hit it. + */ + if (png_gamma_significant(gamma_val) != 0) + { + /* The old code would overflow at the end and this would cause the + * 'pow' function to return a result >1, resulting in an + * arithmetic error. This code follows the spec exactly; ig is + * the recovered input sample, it always has 8-16 bits. + * + * We want input * 65535/max, rounded, the arithmetic fits in 32 + * bits (unsigned) so long as max <= 32767. + */ + unsigned int j; + for (j = 0; j < 256; j++) + { + png_uint_32 ig = (j << (8-shift)) + i; +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* Inline the 'max' scaling operation: */ + /* See png_gamma_8bit_correct for why the cast to (int) is + * required here. + */ + double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5); + sub_table[j] = (png_uint_16)d; +# else + if (shift != 0) + ig = (ig * 65535U + max_by_2)/max; + + sub_table[j] = png_gamma_16bit_correct(ig, gamma_val); +# endif + } + } + else + { + /* We must still build a table, but do it the fast way. */ + unsigned int j; + + for (j = 0; j < 256; j++) + { + png_uint_32 ig = (j << (8-shift)) + i; + + if (shift != 0) + ig = (ig * 65535U + max_by_2)/max; + + sub_table[j] = (png_uint_16)ig; + } + } + } +} + +/* NOTE: this function expects the *inverse* of the overall gamma transformation + * required. + */ +static void +png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, + unsigned int shift, png_fixed_point gamma_val) +{ + unsigned int num = 1U << (8U - shift); + unsigned int max = (1U << (16U - shift))-1U; + unsigned int i; + png_uint_32 last; + + png_uint_16pp table = *ptable = + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); + + /* 'num' is the number of tables and also the number of low bits of low + * bits of the input 16-bit value used to select a table. Each table is + * itself indexed by the high 8 bits of the value. + */ + for (i = 0; i < num; i++) + table[i] = (png_uint_16p)png_malloc(png_ptr, + 256 * (sizeof (png_uint_16))); + + /* 'gamma_val' is set to the reciprocal of the value calculated above, so + * pow(out,g) is an *input* value. 'last' is the last input value set. + * + * In the loop 'i' is used to find output values. Since the output is + * 8-bit there are only 256 possible values. The tables are set up to + * select the closest possible output value for each input by finding + * the input value at the boundary between each pair of output values + * and filling the table up to that boundary with the lower output + * value. + * + * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit + * values the code below uses a 16-bit value in i; the values start at + * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last + * entries are filled with 255). Start i at 128 and fill all 'last' + * table entries <= 'max' + */ + last = 0; + for (i = 0; i < 255; ++i) /* 8-bit output value */ + { + /* Find the corresponding maximum input value */ + png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */ + + /* Find the boundary value in 16 bits: */ + png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val); + + /* Adjust (round) to (16-shift) bits: */ + bound = (bound * max + 32768U)/65535U + 1U; + + while (last < bound) + { + table[last & (0xffU >> shift)][last >> (8U - shift)] = out; + last++; + } + } + + /* And fill in the final entries. */ + while (last < (num << 8)) + { + table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U; + last++; + } +} +#endif /* 16BIT */ + +/* Build a single 8-bit table: same as the 16-bit case but much simpler (and + * typically much faster). Note that libpng currently does no sBIT processing + * (apparently contrary to the spec) so a 256-entry table is always generated. + */ +static void +png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, + png_fixed_point gamma_val) +{ + unsigned int i; + png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256); + + if (png_gamma_significant(gamma_val) != 0) + for (i=0; i<256; i++) + table[i] = png_gamma_8bit_correct(i, gamma_val); + + else + for (i=0; i<256; ++i) + table[i] = (png_byte)(i & 0xff); +} + +/* Used from png_read_destroy and below to release the memory used by the gamma + * tables. + */ +void /* PRIVATE */ +png_destroy_gamma_table(png_structrp png_ptr) +{ + png_free(png_ptr, png_ptr->gamma_table); + png_ptr->gamma_table = NULL; + +#ifdef PNG_16BIT_SUPPORTED + if (png_ptr->gamma_16_table != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_table[i]); + } + png_free(png_ptr, png_ptr->gamma_16_table); + png_ptr->gamma_16_table = NULL; + } +#endif /* 16BIT */ + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_free(png_ptr, png_ptr->gamma_from_1); + png_ptr->gamma_from_1 = NULL; + png_free(png_ptr, png_ptr->gamma_to_1); + png_ptr->gamma_to_1 = NULL; + +#ifdef PNG_16BIT_SUPPORTED + if (png_ptr->gamma_16_from_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_from_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_from_1); + png_ptr->gamma_16_from_1 = NULL; + } + if (png_ptr->gamma_16_to_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_to_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_to_1); + png_ptr->gamma_16_to_1 = NULL; + } +#endif /* 16BIT */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +} + +/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit + * tables, we don't make a full table if we are reducing to 8-bit in + * the future. Note also how the gamma_16 tables are segmented so that + * we don't need to allocate > 64K chunks for a full 16-bit table. + * + * TODO: move this to pngrtran.c and make it static. Better yet create + * pngcolor.c and put all the PNG_COLORSPACE stuff in there. + */ +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +# define GAMMA_TRANSFORMS 1 /* #ifdef CSE */ +#else +# define GAMMA_TRANSFORMS 0 +#endif + +void /* PRIVATE */ +png_build_gamma_table(png_structrp png_ptr, int bit_depth) +{ + png_fixed_point file_gamma, screen_gamma; + png_fixed_point correction; +# if GAMMA_TRANSFORMS + png_fixed_point file_to_linear, linear_to_screen; +# endif + + png_debug(1, "in png_build_gamma_table"); + + /* Remove any existing table; this copes with multiple calls to + * png_read_update_info. The warning is because building the gamma tables + * multiple times is a performance hit - it's harmless but the ability to + * call png_read_update_info() multiple times is new in 1.5.6 so it seems + * sensible to warn if the app introduces such a hit. + */ + if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL) + { + png_warning(png_ptr, "gamma table being rebuilt"); + png_destroy_gamma_table(png_ptr); + } + + /* The following fields are set, finally, in png_init_read_transformations. + * If file_gamma is 0 (unset) nothing can be done otherwise if screen_gamma + * is 0 (unset) there is no gamma correction but to/from linear is possible. + */ + file_gamma = png_ptr->file_gamma; + screen_gamma = png_ptr->screen_gamma; +# if GAMMA_TRANSFORMS + file_to_linear = png_reciprocal(file_gamma); +# endif + + if (screen_gamma > 0) + { +# if GAMMA_TRANSFORMS + linear_to_screen = png_reciprocal(screen_gamma); +# endif + correction = png_reciprocal2(screen_gamma, file_gamma); + } + else /* screen gamma unknown */ + { +# if GAMMA_TRANSFORMS + linear_to_screen = file_gamma; +# endif + correction = PNG_FP_1; + } + + if (bit_depth <= 8) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_table, correction); + +#if GAMMA_TRANSFORMS + if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, file_to_linear); + + png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, + linear_to_screen); + } +#endif /* GAMMA_TRANSFORMS */ + } +#ifdef PNG_16BIT_SUPPORTED + else + { + png_byte shift, sig_bit; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + sig_bit = png_ptr->sig_bit.red; + + if (png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + + if (png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + sig_bit = png_ptr->sig_bit.gray; + + /* 16-bit gamma code uses this equation: + * + * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] + * + * Where 'iv' is the input color value and 'ov' is the output value - + * pow(iv, gamma). + * + * Thus the gamma table consists of up to 256 256-entry tables. The table + * is selected by the (8-gamma_shift) most significant of the low 8 bits + * of the color value then indexed by the upper 8 bits: + * + * table[low bits][high 8 bits] + * + * So the table 'n' corresponds to all those 'iv' of: + * + * ..<(n+1 << gamma_shift)-1> + * + */ + if (sig_bit > 0 && sig_bit < 16U) + /* shift == insignificant bits */ + shift = (png_byte)((16U - sig_bit) & 0xff); + + else + shift = 0; /* keep all 16 bits */ + + if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) + { + /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively + * the significant bits in the *input* when the output will + * eventually be 8 bits. By default it is 11. + */ + if (shift < (16U - PNG_MAX_GAMMA_8)) + shift = (16U - PNG_MAX_GAMMA_8); + } + + if (shift > 8U) + shift = 8U; /* Guarantees at least one table! */ + + png_ptr->gamma_shift = shift; + + /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now + * PNG_COMPOSE). This effectively smashed the background calculation for + * 16-bit output because the 8-bit table assumes the result will be + * reduced to 8 bits. + */ + if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) + png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, + png_reciprocal(correction)); + else + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift, + correction); + +# if GAMMA_TRANSFORMS + if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) + { + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, + file_to_linear); + + /* Notice that the '16 from 1' table should be full precision, however + * the lookup on this table still uses gamma_shift, so it can't be. + * TODO: fix this. + */ + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, + linear_to_screen); + } +#endif /* GAMMA_TRANSFORMS */ + } +#endif /* 16BIT */ +} +#endif /* READ_GAMMA */ + +/* HARDWARE OR SOFTWARE OPTION SUPPORT */ +#ifdef PNG_SET_OPTION_SUPPORTED +int PNGAPI +png_set_option(png_structrp png_ptr, int option, int onoff) +{ + if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && + (option & 1) == 0) + { + png_uint_32 mask = 3U << option; + png_uint_32 setting = (2U + (onoff != 0)) << option; + png_uint_32 current = png_ptr->options; + + png_ptr->options = (png_uint_32)((current & ~mask) | setting); + + return (int)(current & mask) >> option; + } + + return PNG_OPTION_INVALID; +} +#endif + +/* sRGB support */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* sRGB conversion tables; these are machine generated with the code in + * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the + * specification (see the article at https://en.wikipedia.org/wiki/SRGB) + * is used, not the gamma=1/2.2 approximation use elsewhere in libpng. + * The sRGB to linear table is exact (to the nearest 16-bit linear fraction). + * The inverse (linear to sRGB) table has accuracies as follows: + * + * For all possible (255*65535+1) input values: + * + * error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact + * + * For the input values corresponding to the 65536 16-bit values: + * + * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact + * + * In all cases the inexact readings are only off by one. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* The convert-to-sRGB table is only currently required for read. */ +const png_uint_16 png_sRGB_table[256] = +{ + 0,20,40,60,80,99,119,139, + 159,179,199,219,241,264,288,313, + 340,367,396,427,458,491,526,562, + 599,637,677,718,761,805,851,898, + 947,997,1048,1101,1156,1212,1270,1330, + 1391,1453,1517,1583,1651,1720,1790,1863, + 1937,2013,2090,2170,2250,2333,2418,2504, + 2592,2681,2773,2866,2961,3058,3157,3258, + 3360,3464,3570,3678,3788,3900,4014,4129, + 4247,4366,4488,4611,4736,4864,4993,5124, + 5257,5392,5530,5669,5810,5953,6099,6246, + 6395,6547,6700,6856,7014,7174,7335,7500, + 7666,7834,8004,8177,8352,8528,8708,8889, + 9072,9258,9445,9635,9828,10022,10219,10417, + 10619,10822,11028,11235,11446,11658,11873,12090, + 12309,12530,12754,12980,13209,13440,13673,13909, + 14146,14387,14629,14874,15122,15371,15623,15878, + 16135,16394,16656,16920,17187,17456,17727,18001, + 18277,18556,18837,19121,19407,19696,19987,20281, + 20577,20876,21177,21481,21787,22096,22407,22721, + 23038,23357,23678,24002,24329,24658,24990,25325, + 25662,26001,26344,26688,27036,27386,27739,28094, + 28452,28813,29176,29542,29911,30282,30656,31033, + 31412,31794,32179,32567,32957,33350,33745,34143, + 34544,34948,35355,35764,36176,36591,37008,37429, + 37852,38278,38706,39138,39572,40009,40449,40891, + 41337,41785,42236,42690,43147,43606,44069,44534, + 45002,45473,45947,46423,46903,47385,47871,48359, + 48850,49344,49841,50341,50844,51349,51858,52369, + 52884,53401,53921,54445,54971,55500,56032,56567, + 57105,57646,58190,58737,59287,59840,60396,60955, + 61517,62082,62650,63221,63795,64372,64952,65535 +}; +#endif /* SIMPLIFIED_READ */ + +/* The base/delta tables are required for both read and write (but currently + * only the simplified versions.) + */ +const png_uint_16 png_sRGB_base[512] = +{ + 128,1782,3383,4644,5675,6564,7357,8074, + 8732,9346,9921,10463,10977,11466,11935,12384, + 12816,13233,13634,14024,14402,14769,15125,15473, + 15812,16142,16466,16781,17090,17393,17690,17981, + 18266,18546,18822,19093,19359,19621,19879,20133, + 20383,20630,20873,21113,21349,21583,21813,22041, + 22265,22487,22707,22923,23138,23350,23559,23767, + 23972,24175,24376,24575,24772,24967,25160,25352, + 25542,25730,25916,26101,26284,26465,26645,26823, + 27000,27176,27350,27523,27695,27865,28034,28201, + 28368,28533,28697,28860,29021,29182,29341,29500, + 29657,29813,29969,30123,30276,30429,30580,30730, + 30880,31028,31176,31323,31469,31614,31758,31902, + 32045,32186,32327,32468,32607,32746,32884,33021, + 33158,33294,33429,33564,33697,33831,33963,34095, + 34226,34357,34486,34616,34744,34873,35000,35127, + 35253,35379,35504,35629,35753,35876,35999,36122, + 36244,36365,36486,36606,36726,36845,36964,37083, + 37201,37318,37435,37551,37668,37783,37898,38013, + 38127,38241,38354,38467,38580,38692,38803,38915, + 39026,39136,39246,39356,39465,39574,39682,39790, + 39898,40005,40112,40219,40325,40431,40537,40642, + 40747,40851,40955,41059,41163,41266,41369,41471, + 41573,41675,41777,41878,41979,42079,42179,42279, + 42379,42478,42577,42676,42775,42873,42971,43068, + 43165,43262,43359,43456,43552,43648,43743,43839, + 43934,44028,44123,44217,44311,44405,44499,44592, + 44685,44778,44870,44962,45054,45146,45238,45329, + 45420,45511,45601,45692,45782,45872,45961,46051, + 46140,46229,46318,46406,46494,46583,46670,46758, + 46846,46933,47020,47107,47193,47280,47366,47452, + 47538,47623,47709,47794,47879,47964,48048,48133, + 48217,48301,48385,48468,48552,48635,48718,48801, + 48884,48966,49048,49131,49213,49294,49376,49458, + 49539,49620,49701,49782,49862,49943,50023,50103, + 50183,50263,50342,50422,50501,50580,50659,50738, + 50816,50895,50973,51051,51129,51207,51285,51362, + 51439,51517,51594,51671,51747,51824,51900,51977, + 52053,52129,52205,52280,52356,52432,52507,52582, + 52657,52732,52807,52881,52956,53030,53104,53178, + 53252,53326,53400,53473,53546,53620,53693,53766, + 53839,53911,53984,54056,54129,54201,54273,54345, + 54417,54489,54560,54632,54703,54774,54845,54916, + 54987,55058,55129,55199,55269,55340,55410,55480, + 55550,55620,55689,55759,55828,55898,55967,56036, + 56105,56174,56243,56311,56380,56448,56517,56585, + 56653,56721,56789,56857,56924,56992,57059,57127, + 57194,57261,57328,57395,57462,57529,57595,57662, + 57728,57795,57861,57927,57993,58059,58125,58191, + 58256,58322,58387,58453,58518,58583,58648,58713, + 58778,58843,58908,58972,59037,59101,59165,59230, + 59294,59358,59422,59486,59549,59613,59677,59740, + 59804,59867,59930,59993,60056,60119,60182,60245, + 60308,60370,60433,60495,60558,60620,60682,60744, + 60806,60868,60930,60992,61054,61115,61177,61238, + 61300,61361,61422,61483,61544,61605,61666,61727, + 61788,61848,61909,61969,62030,62090,62150,62211, + 62271,62331,62391,62450,62510,62570,62630,62689, + 62749,62808,62867,62927,62986,63045,63104,63163, + 63222,63281,63340,63398,63457,63515,63574,63632, + 63691,63749,63807,63865,63923,63981,64039,64097, + 64155,64212,64270,64328,64385,64443,64500,64557, + 64614,64672,64729,64786,64843,64900,64956,65013, + 65070,65126,65183,65239,65296,65352,65409,65465 +}; + +const png_byte png_sRGB_delta[512] = +{ + 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54, + 52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36, + 35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28, + 28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24, + 23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21, + 21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19, + 19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17, + 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; +#endif /* SIMPLIFIED READ/WRITE sRGB support */ + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +static int +png_image_free_function(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_controlp cp = image->opaque; + png_control c; + + /* Double check that we have a png_ptr - it should be impossible to get here + * without one. + */ + if (cp->png_ptr == NULL) + return 0; + + /* First free any data held in the control structure. */ +# ifdef PNG_STDIO_SUPPORTED + if (cp->owned_file != 0) + { + FILE *fp = png_voidcast(FILE *, cp->png_ptr->io_ptr); + cp->owned_file = 0; + + /* Ignore errors here. */ + if (fp != NULL) + { + cp->png_ptr->io_ptr = NULL; + (void)fclose(fp); + } + } +# endif + + /* Copy the control structure so that the original, allocated, version can be + * safely freed. Notice that a png_error here stops the remainder of the + * cleanup, but this is probably fine because that would indicate bad memory + * problems anyway. + */ + c = *cp; + image->opaque = &c; + png_free(c.png_ptr, cp); + + /* Then the structures, calling the correct API. */ + if (c.for_write != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED + png_destroy_write_struct(&c.png_ptr, &c.info_ptr); +# else + png_error(c.png_ptr, "simplified write not supported"); +# endif + } + else + { +# ifdef PNG_SIMPLIFIED_READ_SUPPORTED + png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL); +# else + png_error(c.png_ptr, "simplified read not supported"); +# endif + } + + /* Success. */ + return 1; +} + +void PNGAPI +png_image_free(png_imagep image) +{ + /* Safely call the real function, but only if doing so is safe at this point + * (if not inside an error handling context). Otherwise assume + * png_safe_execute will call this API after the return. + */ + if (image != NULL && image->opaque != NULL && + image->opaque->error_buf == NULL) + { + png_image_free_function(image); + image->opaque = NULL; + } +} + +int /* PRIVATE */ +png_image_error(png_imagep image, png_const_charp error_message) +{ + /* Utility to log an error. */ + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + png_image_free(image); + return 0; +} + +#endif /* SIMPLIFIED READ/WRITE */ +#endif /* READ || WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngerror.c b/widget/milsko/milskosrc/external/libpng/src/pngerror.c new file mode 100644 index 0000000000..01a7ef5347 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngerror.c @@ -0,0 +1,971 @@ +/* pngerror.c - stub functions for i/o and memory allocation + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all error handling. Users who + * need special error handling are expected to write replacement functions + * and use png_set_error_fn() to use those functions. See the instructions + * at each function. + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +static PNG_FUNCTION(void /* PRIVATE */, +png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +static void /* PRIVATE */ +png_default_warning(png_const_structrp png_ptr, + png_const_charp warning_message); +#endif /* WARNINGS */ + +/* This function is called whenever there is a fatal error. This function + * should not be changed. If there is a need to handle errors differently, + * you should supply a replacement error function and use png_set_error_fn() + * to replace the error function at run-time. + */ +#ifdef PNG_ERROR_TEXT_SUPPORTED +PNG_FUNCTION(void,PNGAPI +png_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + char msg[16]; + if (png_ptr != NULL) + { + if ((png_ptr->flags & + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) + { + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + for (offset = 1; offset<15; offset++) + if (error_message[offset] == ' ') + break; + + if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) + { + int i; + for (i = 0; i < offset - 1; i++) + msg[i] = error_message[i + 1]; + msg[i - 1] = '\0'; + error_message = msg; + } + + else + error_message += offset; + } + + else + { + if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) + { + msg[0] = '0'; + msg[1] = '\0'; + error_message = msg; + } + } + } + } +#endif + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), + error_message); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, error_message); +} +#else +PNG_FUNCTION(void,PNGAPI +png_err,(png_const_structrp png_ptr),PNG_NORETURN) +{ + /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed + * erroneously as '\0', instead of the empty string "". This was + * apparently an error, introduced in libpng-1.2.20, and png_default_error + * will crash in this case. + */ + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), ""); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, ""); +} +#endif /* ERROR_TEXT */ + +/* Utility to safely appends strings to a buffer. This never errors out so + * error checking is not required in the caller. + */ +size_t +png_safecat(png_charp buffer, size_t bufsize, size_t pos, + png_const_charp string) +{ + if (buffer != NULL && pos < bufsize) + { + if (string != NULL) + while (*string != '\0' && pos < bufsize-1) + buffer[pos++] = *string++; + + buffer[pos] = '\0'; + } + + return pos; +} + +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. + */ +png_charp +png_format_number(png_const_charp start, png_charp end, int format, + png_alloc_size_t number) +{ + int count = 0; /* number of digits output */ + int mincount = 1; /* minimum number required */ + int output = 0; /* digit output (for the fixed point format) */ + + *--end = '\0'; + + /* This is written so that the loop always runs at least once, even with + * number zero. + */ + while (end > start && (number != 0 || count < mincount)) + { + + static const char digits[] = "0123456789ABCDEF"; + + switch (format) + { + case PNG_NUMBER_FORMAT_fixed: + /* Needs five digits (the fraction) */ + mincount = 5; + if (output != 0 || number % 10 != 0) + { + *--end = digits[number % 10]; + output = 1; + } + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02u: + /* Expects at least 2 digits. */ + mincount = 2; + /* FALLTHROUGH */ + + case PNG_NUMBER_FORMAT_u: + *--end = digits[number % 10]; + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02x: + /* This format expects at least two digits */ + mincount = 2; + /* FALLTHROUGH */ + + case PNG_NUMBER_FORMAT_x: + *--end = digits[number & 0xf]; + number >>= 4; + break; + + default: /* an error */ + number = 0; + break; + } + + /* Keep track of the number of digits added */ + ++count; + + /* Float a fixed number here: */ + if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start)) + { + /* End of the fraction, but maybe nothing was output? In that case + * drop the decimal point. If the number is a true zero handle that + * here. + */ + if (output != 0) + *--end = '.'; + else if (number == 0) /* and !output */ + *--end = '0'; + } + } + + return end; +} +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called whenever there is a non-fatal error. This function + * should not be changed. If there is a need to handle warnings differently, + * you should supply a replacement warning function and use + * png_set_error_fn() to replace the warning function at run-time. + */ +void PNGAPI +png_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ + int offset = 0; + if (png_ptr != NULL) + { +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if ((png_ptr->flags & + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) +#endif + { + if (*warning_message == PNG_LITERAL_SHARP) + { + for (offset = 1; offset < 15; offset++) + if (warning_message[offset] == ' ') + break; + } + } + } + if (png_ptr != NULL && png_ptr->warning_fn != NULL) + (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), + warning_message + offset); + else + png_default_warning(png_ptr, warning_message + offset); +} + +/* These functions support 'formatted' warning messages with up to + * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter + * is introduced by @, where 'number' starts at 1. This follows the + * standard established by X/Open for internationalizable error messages. + */ +void +png_warning_parameter(png_warning_parameters p, int number, + png_const_charp string) +{ + if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) + (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); +} + +void +png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, + png_alloc_size_t value) +{ + char buffer[PNG_NUMBER_BUFFER_SIZE] = {0}; + png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); +} + +void +png_warning_parameter_signed(png_warning_parameters p, int number, int format, + png_int_32 value) +{ + png_alloc_size_t u; + png_charp str; + char buffer[PNG_NUMBER_BUFFER_SIZE] = {0}; + + /* Avoid overflow by doing the negate in a png_alloc_size_t: */ + u = (png_alloc_size_t)value; + if (value < 0) + u = ~u + 1; + + str = PNG_FORMAT_NUMBER(buffer, format, u); + + if (value < 0 && str > buffer) + *--str = '-'; + + png_warning_parameter(p, number, str); +} + +void +png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, + png_const_charp message) +{ + /* The internal buffer is just 192 bytes - enough for all our messages, + * overflow doesn't happen because this code checks! If someone figures + * out how to send us a message longer than 192 bytes, all that will + * happen is that the message will be truncated appropriately. + */ + size_t i = 0; /* Index in the msg[] buffer: */ + char msg[192]; + + /* Each iteration through the following loop writes at most one character + * to msg[i++] then returns here to validate that there is still space for + * the trailing '\0'. It may (in the case of a parameter) read more than + * one character from message[]; it must check for '\0' and continue to the + * test if it finds the end of string. + */ + while (i<(sizeof msg)-1 && *message != '\0') + { + /* '@' at end of string is now just printed (previously it was skipped); + * it is an error in the calling code to terminate the string with @. + */ + if (p != NULL && *message == '@' && message[1] != '\0') + { + int parameter_char = *++message; /* Consume the '@' */ + static const char valid_parameters[] = "123456789"; + int parameter = 0; + + /* Search for the parameter digit, the index in the string is the + * parameter to use. + */ + while (valid_parameters[parameter] != parameter_char && + valid_parameters[parameter] != '\0') + ++parameter; + + /* If the parameter digit is out of range it will just get printed. */ + if (parameter < PNG_WARNING_PARAMETER_COUNT) + { + /* Append this parameter */ + png_const_charp parm = p[parameter]; + png_const_charp pend = p[parameter] + (sizeof p[parameter]); + + /* No need to copy the trailing '\0' here, but there is no guarantee + * that parm[] has been initialized, so there is no guarantee of a + * trailing '\0': + */ + while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend) + msg[i++] = *parm++; + + /* Consume the parameter digit too: */ + ++message; + continue; + } + + /* else not a parameter and there is a character after the @ sign; just + * copy that. This is known not to be '\0' because of the test above. + */ + } + + /* At this point *message can't be '\0', even in the bad parameter case + * above where there is a lone '@' at the end of the message string. + */ + msg[i++] = *message++; + } + + /* i is always less than (sizeof msg), so: */ + msg[i] = '\0'; + + /* And this is the formatted message. It may be larger than + * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these + * are not (currently) formatted. + */ + png_warning(png_ptr, msg); +} +#endif /* WARNINGS */ + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_warning(png_ptr, error_message); + else +# endif + png_warning(png_ptr, error_message); + } + + else + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_error(png_ptr, error_message); + else +# endif + png_error(png_ptr, error_message); + } + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} + +void /* PRIVATE */ +png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} + +void /* PRIVATE */ +png_app_error(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} +#endif /* BENIGN_ERRORS */ + +#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */ +#if defined(PNG_WARNINGS_SUPPORTED) || \ + (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)) +/* These utilities are used internally to build an error message that relates + * to the current chunk. The chunk name comes from png_ptr->chunk_name, + * which is used to prefix the message. The message is limited in length + * to 63 bytes. The name characters are output as hex digits wrapped in [] + * if the character is invalid. + */ +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) +static const char png_digit[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + +static void /* PRIVATE */ +png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp + error_message) +{ + png_uint_32 chunk_name = png_ptr->chunk_name; + int iout = 0, ishift = 24; + + while (ishift >= 0) + { + int c = (int)(chunk_name >> ishift) & 0xff; + + ishift -= 8; + if (isnonalpha(c) != 0) + { + buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; + buffer[iout++] = png_digit[(c & 0xf0) >> 4]; + buffer[iout++] = png_digit[c & 0x0f]; + buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; + } + + else + { + buffer[iout++] = (char)c; + } + } + + if (error_message == NULL) + buffer[iout] = '\0'; + + else + { + int iin = 0; + + buffer[iout++] = ':'; + buffer[iout++] = ' '; + + while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') + buffer[iout++] = error_message[iin++]; + + /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ + buffer[iout] = '\0'; + } +} +#endif /* WARNINGS || ERROR_TEXT */ + +#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_FUNCTION(void,PNGAPI +png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_error(png_ptr, error_message); + + else + { + png_format_buffer(png_ptr, msg, error_message); + png_error(png_ptr, msg); + } +} +#endif /* READ && ERROR_TEXT */ + +#ifdef PNG_WARNINGS_SUPPORTED +void PNGAPI +png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_warning(png_ptr, warning_message); + + else + { + png_format_buffer(png_ptr, msg, warning_message); + png_warning(png_ptr, msg); + } +} +#endif /* WARNINGS */ + +#ifdef PNG_READ_SUPPORTED +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp + error_message) +{ + if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + png_chunk_warning(png_ptr, error_message); + + else + png_chunk_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} +#endif +#endif /* READ */ + +void /* PRIVATE */ +png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) +{ +# ifndef PNG_WARNINGS_SUPPORTED + PNG_UNUSED(message) +# endif + + /* This is always supported, but for just read or just write it + * unconditionally does the right thing. + */ +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) +# endif + +# ifdef PNG_READ_SUPPORTED + { + if (error < PNG_CHUNK_ERROR) + png_chunk_warning(png_ptr, message); + + else + png_chunk_benign_error(png_ptr, message); + } +# endif + +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) +# endif + +# ifdef PNG_WRITE_SUPPORTED + { + if (error < PNG_CHUNK_WRITE_ERROR) + png_app_warning(png_ptr, message); + + else + png_app_error(png_ptr, message); + } +# endif +} + +#ifdef PNG_ERROR_TEXT_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_FUNCTION(void, +png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) +{ +# define fixed_message "fixed point overflow in " +# define fixed_message_ln ((sizeof fixed_message)-1) + unsigned int iin; + char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; + memcpy(msg, fixed_message, fixed_message_ln); + iin = 0; + if (name != NULL) + while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) + { + msg[fixed_message_ln + iin] = name[iin]; + ++iin; + } + msg[fixed_message_ln + iin] = 0; + png_error(png_ptr, msg); +} +#endif +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This API only exists if ANSI-C style error handling is used, + * otherwise it is necessary for png_default_error to be overridden. + */ +jmp_buf* PNGAPI +png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, + size_t jmp_buf_size) +{ + /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value + * and it must not change after that. Libpng doesn't care how big the + * buffer is, just that it doesn't change. + * + * If the buffer size is no *larger* than the size of jmp_buf when libpng is + * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0 + * semantics that this call will not fail. If the size is larger, however, + * the buffer is allocated and this may fail, causing the function to return + * NULL. + */ + if (png_ptr == NULL) + return NULL; + + if (png_ptr->jmp_buf_ptr == NULL) + { + png_ptr->jmp_buf_size = 0; /* not allocated */ + + if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local)) + png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; + + else + { + png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, + png_malloc_warn(png_ptr, jmp_buf_size)); + + if (png_ptr->jmp_buf_ptr == NULL) + return NULL; /* new NULL return on OOM */ + + png_ptr->jmp_buf_size = jmp_buf_size; + } + } + + else /* Already allocated: check the size */ + { + size_t size = png_ptr->jmp_buf_size; + + if (size == 0) + { + size = (sizeof png_ptr->jmp_buf_local); + if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local) + { + /* This is an internal error in libpng: somehow we have been left + * with a stack allocated jmp_buf when the application regained + * control. It's always possible to fix this up, but for the moment + * this is a png_error because that makes it easy to detect. + */ + png_error(png_ptr, "Libpng jmp_buf still allocated"); + /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */ + } + } + + if (size != jmp_buf_size) + { + png_warning(png_ptr, "Application jmp_buf size changed"); + return NULL; /* caller will probably crash: no choice here */ + } + } + + /* Finally fill in the function, now we have a satisfactory buffer. It is + * valid to change the function on every call. + */ + png_ptr->longjmp_fn = longjmp_fn; + return png_ptr->jmp_buf_ptr; +} + +void /* PRIVATE */ +png_free_jmpbuf(png_structrp png_ptr) +{ + if (png_ptr != NULL) + { + jmp_buf *jb = png_ptr->jmp_buf_ptr; + + /* A size of 0 is used to indicate a local, stack, allocation of the + * pointer; used here and in png.c + */ + if (jb != NULL && png_ptr->jmp_buf_size > 0) + { + + /* This stuff is so that a failure to free the error control structure + * does not leave libpng in a state with no valid error handling: the + * free always succeeds, if there is an error it gets ignored. + */ + if (jb != &png_ptr->jmp_buf_local) + { + /* Make an internal, libpng, jmp_buf to return here */ + jmp_buf free_jmp_buf; + + if (!setjmp(free_jmp_buf)) + { + png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */ + png_ptr->jmp_buf_size = 0; /* stack allocation */ + png_ptr->longjmp_fn = longjmp; + png_free(png_ptr, jb); /* Return to setjmp on error */ + } + } + } + + /* *Always* cancel everything out: */ + png_ptr->jmp_buf_size = 0; + png_ptr->jmp_buf_ptr = NULL; + png_ptr->longjmp_fn = 0; + } +} +#endif + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static PNG_FUNCTION(void /* PRIVATE */, +png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + /* Check on NULL only added in 1.5.4 */ + if (error_message != NULL && *error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + char error_number[16]; + for (offset = 0; offset<15; offset++) + { + error_number[offset] = error_message[offset + 1]; + if (error_message[offset] == ' ') + break; + } + + if ((offset > 1) && (offset < 15)) + { + error_number[offset - 1] = '\0'; + fprintf(stderr, "libpng error no. %s: %s", + error_number, error_message + offset + 1); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng error: %s, offset=%d", + error_message, offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +#endif + { + fprintf(stderr, "libpng error: %s", error_message ? error_message : + "undefined"); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#else + PNG_UNUSED(error_message) /* Make compiler happy */ +#endif + png_longjmp(png_ptr, 1); +} + +PNG_FUNCTION(void,PNGAPI +png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN) +{ +#ifdef PNG_SETJMP_SUPPORTED + if (png_ptr != NULL && png_ptr->longjmp_fn != NULL && + png_ptr->jmp_buf_ptr != NULL) + png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(val) +#endif + + /* If control reaches this point, png_longjmp() must not return. The only + * choice is to terminate the whole process (or maybe the thread); to do + * this the ANSI-C abort() function is used unless a different method is + * implemented by overriding the default configuration setting for + * PNG_ABORT(). + */ + PNG_ABORT(); +} + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want them to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void /* PRIVATE */ +png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +# ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*warning_message == PNG_LITERAL_SHARP) + { + int offset; + char warning_number[16]; + for (offset = 0; offset < 15; offset++) + { + warning_number[offset] = warning_message[offset + 1]; + if (warning_message[offset] == ' ') + break; + } + + if ((offset > 1) && (offset < 15)) + { + warning_number[offset + 1] = '\0'; + fprintf(stderr, "libpng warning no. %s: %s", + warning_number, warning_message + offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng warning: %s", + warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +# endif + + { + fprintf(stderr, "libpng warning: %s", warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#else + PNG_UNUSED(warning_message) /* Make compiler happy */ +#endif + PNG_UNUSED(png_ptr) /* Make compiler happy */ +} +#endif /* WARNINGS */ + +/* This function is called when the application wants to use another method + * of handling errors and warnings. Note that the error function MUST NOT + * return to the calling routine or serious problems will occur. The return + * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1) + */ +void PNGAPI +png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->error_ptr = error_ptr; + png_ptr->error_fn = error_fn; +#ifdef PNG_WARNINGS_SUPPORTED + png_ptr->warning_fn = warning_fn; +#else + PNG_UNUSED(warning_fn) +#endif +} + + +/* This function returns a pointer to the error_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_error_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return (png_voidp)png_ptr->error_ptr; +} + + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +void PNGAPI +png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) +{ + if (png_ptr != NULL) + { + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS | + PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); + } +} +#endif + +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) + /* Currently the above both depend on SETJMP_SUPPORTED, however it would be + * possible to implement without setjmp support just so long as there is some + * way to handle the error return here: + */ +PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI +png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), + PNG_NORETURN) +{ + png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* An error is always logged here, overwriting anything (typically a warning) + * that is already there: + */ + if (image != NULL) + { + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + + /* Retrieve the jmp_buf from within the png_control, making this work for + * C++ compilation too is pretty tricky: C++ wants a pointer to the first + * element of a jmp_buf, but C doesn't tell us the type of that. + */ + if (image->opaque != NULL && image->opaque->error_buf != NULL) + longjmp(png_control_jmp_buf(image->opaque), 1); + + /* Missing longjmp buffer, the following is to help debugging: */ + { + size_t pos = png_safecat(image->message, (sizeof image->message), 0, + "bad longjmp: "); + png_safecat(image->message, (sizeof image->message), pos, + error_message); + } + } + + /* Here on an internal programming error. */ + abort(); +} + +#ifdef PNG_WARNINGS_SUPPORTED +void /* PRIVATE */ PNGCBAPI +png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) +{ + png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* A warning is only logged if there is no prior warning or error. */ + if (image->warning_or_error == 0) + { + png_safecat(image->message, (sizeof image->message), 0, warning_message); + image->warning_or_error |= PNG_IMAGE_WARNING; + } +} +#endif + +int /* PRIVATE */ +png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg) +{ + const png_voidp saved_error_buf = image->opaque->error_buf; + jmp_buf safe_jmpbuf; + + /* Safely execute function(arg), with png_error returning back here. */ + if (setjmp(safe_jmpbuf) == 0) + { + int result; + + image->opaque->error_buf = safe_jmpbuf; + result = function(arg); + image->opaque->error_buf = saved_error_buf; + + if (result) + return 1; /* success */ + } + + /* The function failed either because of a caught png_error and a regular + * return of false above or because of an uncaught png_error from the + * function itself. Ensure that the error_buf is always set back to the + * value saved above: + */ + image->opaque->error_buf = saved_error_buf; + + /* On the final false return, when about to return control to the caller, the + * image is freed (png_image_free does this check but it is duplicated here + * for clarity: + */ + if (saved_error_buf == NULL) + png_image_free(image); + + return 0; /* failure */ +} +#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */ +#endif /* READ || WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngget.c b/widget/milsko/milskosrc/external/libpng/src/pngget.c new file mode 100644 index 0000000000..1ebb1144ff --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngget.c @@ -0,0 +1,1370 @@ +/* pngget.c - retrieval of values from info struct + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +png_uint_32 PNGAPI +png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 flag) +{ + if (png_ptr != NULL && info_ptr != NULL) + { +#ifdef PNG_READ_tRNS_SUPPORTED + /* png_handle_PLTE() may have canceled a valid tRNS chunk but left the + * 'valid' flag for the detection of duplicate chunks. Do not report a + * valid tRNS chunk in this case. + */ + if (flag == PNG_INFO_tRNS && png_ptr->num_trans == 0) + return 0; +#endif + + return info_ptr->valid & flag; + } + + return 0; +} + +size_t PNGAPI +png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->rowbytes; + + return 0; +} + +#ifdef PNG_INFO_IMAGE_SUPPORTED +png_bytepp PNGAPI +png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->row_pointers; + + return 0; +} +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Easy access to info, added in libpng-0.99 */ +png_uint_32 PNGAPI +png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->width; + + return 0; +} + +png_uint_32 PNGAPI +png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->height; + + return 0; +} + +png_byte PNGAPI +png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->bit_depth; + + return 0; +} + +png_byte PNGAPI +png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->color_type; + + return 0; +} + +png_byte PNGAPI +png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->filter_type; + + return 0; +} + +png_byte PNGAPI +png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->interlace_type; + + return 0; +} + +png_byte PNGAPI +png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->compression_type; + + return 0; +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + png_debug(1, "in png_get_x_pixels_per_meter"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return info_ptr->x_pixels_per_unit; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + png_debug(1, "in png_get_y_pixels_per_meter"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return info_ptr->y_pixels_per_unit; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} + +png_uint_32 PNGAPI +png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + png_debug(1, "in png_get_pixels_per_meter"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER && + info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit) + return info_ptr->x_pixels_per_unit; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_READ_pHYs_SUPPORTED + png_debug(1, "in png_get_pixel_aspect_ratio"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + if (info_ptr->x_pixels_per_unit != 0) + return (float)info_ptr->y_pixels_per_unit + / (float)info_ptr->x_pixels_per_unit; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return (float)0.0; +} +#endif + +#ifdef PNG_FIXED_POINT_SUPPORTED +png_fixed_point PNGAPI +png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ +#ifdef PNG_READ_pHYs_SUPPORTED + png_debug(1, "in png_get_pixel_aspect_ratio_fixed"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0 && + info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 && + info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX && + info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) + { + png_fixed_point res; + + /* The following casts work because a PNG 4 byte integer only has a valid + * range of 0..2^31-1; otherwise the cast might overflow. + */ + if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1, + (png_int_32)info_ptr->x_pixels_per_unit) != 0) + return res; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} +#endif + +png_int_32 PNGAPI +png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + png_debug(1, "in png_get_x_offset_microns"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) + return info_ptr->x_offset; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} + +png_int_32 PNGAPI +png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + png_debug(1, "in png_get_y_offset_microns"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) + return info_ptr->y_offset; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} + +png_int_32 PNGAPI +png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + png_debug(1, "in png_get_x_offset_pixels"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) + return info_ptr->x_offset; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} + +png_int_32 PNGAPI +png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + png_debug(1, "in png_get_y_offset_pixels"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) + return info_ptr->y_offset; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} + +#ifdef PNG_INCH_CONVERSIONS_SUPPORTED +static png_uint_32 +ppi_from_ppm(png_uint_32 ppm) +{ +#if 0 + /* The conversion is *(2.54/100), in binary (32 digits): + * .00000110100000001001110101001001 + */ + png_uint_32 t1001, t1101; + ppm >>= 1; /* .1 */ + t1001 = ppm + (ppm >> 3); /* .1001 */ + t1101 = t1001 + (ppm >> 1); /* .1101 */ + ppm >>= 20; /* .000000000000000000001 */ + t1101 += t1101 >> 15; /* .1101000000000001101 */ + t1001 >>= 11; /* .000000000001001 */ + t1001 += t1001 >> 12; /* .000000000001001000000001001 */ + ppm += t1001; /* .000000000001001000001001001 */ + ppm += t1101; /* .110100000001001110101001001 */ + return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */ +#else + /* The argument is a PNG unsigned integer, so it is not permitted + * to be bigger than 2^31. + */ + png_fixed_point result; + if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127, + 5000) != 0) + return (png_uint_32)result; + + /* Overflow. */ + return 0; +#endif +} + +png_uint_32 PNGAPI +png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr)); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr)); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr)); +} + +#ifdef PNG_FIXED_POINT_SUPPORTED +static png_fixed_point +png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns) +{ + /* Convert from meters * 1,000,000 to inches * 100,000, meters to + * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127. + * Notice that this can overflow - a warning is output and 0 is + * returned. + */ + png_fixed_point result; + + if (png_muldiv(&result, microns, 500, 127) != 0) + return result; + + png_warning(png_ptr, "fixed point overflow ignored"); + return 0; +} + +png_fixed_point PNGAPI +png_get_x_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ + return png_fixed_inches_from_microns(png_ptr, + png_get_x_offset_microns(png_ptr, info_ptr)); +} +#endif /* FIXED_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +png_fixed_point PNGAPI +png_get_y_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ + return png_fixed_inches_from_microns(png_ptr, + png_get_y_offset_microns(png_ptr, info_ptr)); +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + /* To avoid the overflow do the conversion directly in floating + * point. + */ + return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937); +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + /* To avoid the overflow do the conversion directly in floating + * point. + */ + return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937); +} +#endif + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + + if (*unit_type == 1) + { + if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); + if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); + } + } + } + + return retval; +} +#endif /* pHYs */ +#endif /* INCH_CONVERSIONS */ + +/* png_get_channels really belongs in here, too, but it's been around longer */ + +#endif /* EASY_ACCESS */ + + +png_byte PNGAPI +png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->channels; + + return 0; +} + +#ifdef PNG_READ_SUPPORTED +png_const_bytep PNGAPI +png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->signature; + + return NULL; +} +#endif + +#ifdef PNG_bKGD_SUPPORTED +png_uint_32 PNGAPI +png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, + png_color_16p *background) +{ + png_debug1(1, "in %s retrieval function", "bKGD"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_bKGD) != 0 && + background != NULL) + { + *background = &(info_ptr->background); + return PNG_INFO_bKGD; + } + + return 0; +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the + * same time to correct the rgb grayscale coefficient defaults obtained from the + * cHRM chunk in 1.5.4 + */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *whitex, double *whitey, double *redx, double *redy, + double *greenx, double *greeny, double *bluex, double *bluey) +{ + png_debug1(1, "in %s retrieval function", "cHRM"); + + /* PNGv3: this just returns the values store from the cHRM, if any. */ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cHRM) != 0) + { + if (whitex != NULL) + *whitex = png_float(png_ptr, info_ptr->cHRM.whitex, "cHRM wx"); + if (whitey != NULL) + *whitey = png_float(png_ptr, info_ptr->cHRM.whitey, "cHRM wy"); + if (redx != NULL) + *redx = png_float(png_ptr, info_ptr->cHRM.redx, "cHRM rx"); + if (redy != NULL) + *redy = png_float(png_ptr, info_ptr->cHRM.redy, "cHRM ry"); + if (greenx != NULL) + *greenx = png_float(png_ptr, info_ptr->cHRM.greenx, "cHRM gx"); + if (greeny != NULL) + *greeny = png_float(png_ptr, info_ptr->cHRM.greeny, "cHRM gy"); + if (bluex != NULL) + *bluex = png_float(png_ptr, info_ptr->cHRM.bluex, "cHRM bx"); + if (bluey != NULL) + *bluey = png_float(png_ptr, info_ptr->cHRM.bluey, "cHRM by"); + return PNG_INFO_cHRM; + } + + return 0; +} + +png_uint_32 PNGAPI +png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *red_X, double *red_Y, double *red_Z, double *green_X, + double *green_Y, double *green_Z, double *blue_X, double *blue_Y, + double *blue_Z) +{ + png_XYZ XYZ; + png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cHRM) != 0 && + png_XYZ_from_xy(&XYZ, &info_ptr->cHRM) == 0) + { + if (red_X != NULL) + *red_X = png_float(png_ptr, XYZ.red_X, "cHRM red X"); + if (red_Y != NULL) + *red_Y = png_float(png_ptr, XYZ.red_Y, "cHRM red Y"); + if (red_Z != NULL) + *red_Z = png_float(png_ptr, XYZ.red_Z, "cHRM red Z"); + if (green_X != NULL) + *green_X = png_float(png_ptr, XYZ.green_X, "cHRM green X"); + if (green_Y != NULL) + *green_Y = png_float(png_ptr, XYZ.green_Y, "cHRM green Y"); + if (green_Z != NULL) + *green_Z = png_float(png_ptr, XYZ.green_Z, "cHRM green Z"); + if (blue_X != NULL) + *blue_X = png_float(png_ptr, XYZ.blue_X, "cHRM blue X"); + if (blue_Y != NULL) + *blue_Y = png_float(png_ptr, XYZ.blue_Y, "cHRM blue Y"); + if (blue_Z != NULL) + *blue_Z = png_float(png_ptr, XYZ.blue_Z, "cHRM blue Z"); + return PNG_INFO_cHRM; + } + + return 0; +} +# endif + +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z) +{ + png_XYZ XYZ; + png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cHRM) != 0U && + png_XYZ_from_xy(&XYZ, &info_ptr->cHRM) == 0) + { + if (int_red_X != NULL) *int_red_X = XYZ.red_X; + if (int_red_Y != NULL) *int_red_Y = XYZ.red_Y; + if (int_red_Z != NULL) *int_red_Z = XYZ.red_Z; + if (int_green_X != NULL) *int_green_X = XYZ.green_X; + if (int_green_Y != NULL) *int_green_Y = XYZ.green_Y; + if (int_green_Z != NULL) *int_green_Z = XYZ.green_Z; + if (int_blue_X != NULL) *int_blue_X = XYZ.blue_X; + if (int_blue_Y != NULL) *int_blue_Y = XYZ.blue_Y; + if (int_blue_Z != NULL) *int_blue_Z = XYZ.blue_Z; + return PNG_INFO_cHRM; + } + + return 0; +} + +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *whitex, png_fixed_point *whitey, png_fixed_point *redx, + png_fixed_point *redy, png_fixed_point *greenx, png_fixed_point *greeny, + png_fixed_point *bluex, png_fixed_point *bluey) +{ + png_debug1(1, "in %s retrieval function", "cHRM"); + + /* PNGv3: this just returns the values store from the cHRM, if any. */ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cHRM) != 0) + { + if (whitex != NULL) *whitex = info_ptr->cHRM.whitex; + if (whitey != NULL) *whitey = info_ptr->cHRM.whitey; + if (redx != NULL) *redx = info_ptr->cHRM.redx; + if (redy != NULL) *redy = info_ptr->cHRM.redy; + if (greenx != NULL) *greenx = info_ptr->cHRM.greenx; + if (greeny != NULL) *greeny = info_ptr->cHRM.greeny; + if (bluex != NULL) *bluex = info_ptr->cHRM.bluex; + if (bluey != NULL) *bluey = info_ptr->cHRM.bluey; + return PNG_INFO_cHRM; + } + + return 0; +} +# endif +#endif + +#ifdef PNG_gAMA_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA"); + + /* PNGv3 compatibility: only report gAMA if it is really present. */ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_gAMA) != 0) + { + if (file_gamma != NULL) *file_gamma = info_ptr->gamma; + return PNG_INFO_gAMA; + } + + return 0; +} +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA(float)"); + + /* PNGv3 compatibility: only report gAMA if it is really present. */ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_gAMA) != 0) + { + if (file_gamma != NULL) + *file_gamma = png_float(png_ptr, info_ptr->gamma, "gAMA"); + + return PNG_INFO_gAMA; + } + + return 0; +} +# endif +#endif + +#ifdef PNG_sRGB_SUPPORTED +png_uint_32 PNGAPI +png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *file_srgb_intent) +{ + png_debug1(1, "in %s retrieval function", "sRGB"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sRGB) != 0) + { + if (file_srgb_intent != NULL) + *file_srgb_intent = info_ptr->rendering_intent; + return PNG_INFO_sRGB; + } + + return 0; +} +#endif + +#ifdef PNG_iCCP_SUPPORTED +png_uint_32 PNGAPI +png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, + png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen) +{ + png_debug1(1, "in %s retrieval function", "iCCP"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_iCCP) != 0 && + name != NULL && profile != NULL && proflen != NULL) + { + *name = info_ptr->iccp_name; + *profile = info_ptr->iccp_profile; + *proflen = png_get_uint_32(info_ptr->iccp_profile); + /* This is somewhat irrelevant since the profile data returned has + * actually been uncompressed. + */ + if (compression_type != NULL) + *compression_type = PNG_COMPRESSION_TYPE_BASE; + return PNG_INFO_iCCP; + } + + return 0; + +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +int PNGAPI +png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, + png_sPLT_tpp spalettes) +{ + png_debug1(1, "in %s retrieval function", "sPLT"); + + if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) + { + *spalettes = info_ptr->splt_palettes; + return info_ptr->splt_palettes_num; + } + + return 0; +} +#endif + +#ifdef PNG_cICP_SUPPORTED +png_uint_32 PNGAPI +png_get_cICP(png_const_structrp png_ptr, + png_const_inforp info_ptr, png_bytep colour_primaries, + png_bytep transfer_function, png_bytep matrix_coefficients, + png_bytep video_full_range_flag) +{ + png_debug1(1, "in %s retrieval function", "cICP"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cICP) != 0 && + colour_primaries != NULL && transfer_function != NULL && + matrix_coefficients != NULL && video_full_range_flag != NULL) + { + *colour_primaries = info_ptr->cicp_colour_primaries; + *transfer_function = info_ptr->cicp_transfer_function; + *matrix_coefficients = info_ptr->cicp_matrix_coefficients; + *video_full_range_flag = info_ptr->cicp_video_full_range_flag; + return (PNG_INFO_cICP); + } + + return 0; +} +#endif + +#ifdef PNG_cLLI_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cLLI_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32p maxCLL, + png_uint_32p maxFALL) +{ + png_debug1(1, "in %s retrieval function", "cLLI"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cLLI) != 0) + { + if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL; + if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL; + return PNG_INFO_cLLI; + } + + return 0; +} +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cLLI(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *maxCLL, double *maxFALL) +{ + png_debug1(1, "in %s retrieval function", "cLLI(float)"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cLLI) != 0) + { + if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL * .0001; + if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL * .0001; + return PNG_INFO_cLLI; + } + + return 0; +} +# endif +#endif /* cLLI */ + +#ifdef PNG_mDCV_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_mDCV_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *white_x, png_fixed_point *white_y, + png_fixed_point *red_x, png_fixed_point *red_y, + png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y, + png_uint_32p mastering_maxDL, png_uint_32p mastering_minDL) +{ + png_debug1(1, "in %s retrieval function", "mDCV"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_mDCV) != 0) + { + if (white_x != NULL) *white_x = info_ptr->mastering_white_x * 2; + if (white_y != NULL) *white_y = info_ptr->mastering_white_y * 2; + if (red_x != NULL) *red_x = info_ptr->mastering_red_x * 2; + if (red_y != NULL) *red_y = info_ptr->mastering_red_y * 2; + if (green_x != NULL) *green_x = info_ptr->mastering_green_x * 2; + if (green_y != NULL) *green_y = info_ptr->mastering_green_y * 2; + if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * 2; + if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * 2; + if (mastering_maxDL != NULL) *mastering_maxDL = info_ptr->mastering_maxDL; + if (mastering_minDL != NULL) *mastering_minDL = info_ptr->mastering_minDL; + return PNG_INFO_mDCV; + } + + return 0; +} +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_mDCV(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y, + double *mastering_maxDL, double *mastering_minDL) +{ + png_debug1(1, "in %s retrieval function", "mDCV(float)"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_mDCV) != 0) + { + if (white_x != NULL) *white_x = info_ptr->mastering_white_x * .00002; + if (white_y != NULL) *white_y = info_ptr->mastering_white_y * .00002; + if (red_x != NULL) *red_x = info_ptr->mastering_red_x * .00002; + if (red_y != NULL) *red_y = info_ptr->mastering_red_y * .00002; + if (green_x != NULL) *green_x = info_ptr->mastering_green_x * .00002; + if (green_y != NULL) *green_y = info_ptr->mastering_green_y * .00002; + if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * .00002; + if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * .00002; + if (mastering_maxDL != NULL) + *mastering_maxDL = info_ptr->mastering_maxDL * .0001; + if (mastering_minDL != NULL) + *mastering_minDL = info_ptr->mastering_minDL * .0001; + return PNG_INFO_mDCV; + } + + return 0; +} +# endif /* FLOATING_POINT */ +#endif /* mDCV */ + +#ifdef PNG_eXIf_SUPPORTED +png_uint_32 PNGAPI +png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytep *exif) +{ + png_warning(png_ptr, "png_get_eXIf does not work; use png_get_eXIf_1"); + PNG_UNUSED(info_ptr) + PNG_UNUSED(exif) + return 0; +} + +png_uint_32 PNGAPI +png_get_eXIf_1(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *num_exif, png_bytep *exif) +{ + png_debug1(1, "in %s retrieval function", "eXIf"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_eXIf) != 0 && exif != NULL) + { + *num_exif = info_ptr->num_exif; + *exif = info_ptr->exif; + return PNG_INFO_eXIf; + } + + return 0; +} +#endif + +#ifdef PNG_hIST_SUPPORTED +png_uint_32 PNGAPI +png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_16p *hist) +{ + png_debug1(1, "in %s retrieval function", "hIST"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL) + { + *hist = info_ptr->hist; + return PNG_INFO_hIST; + } + + return 0; +} +#endif + +png_uint_32 PNGAPI +png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *width, png_uint_32 *height, int *bit_depth, + int *color_type, int *interlace_type, int *compression_type, + int *filter_type) +{ + png_debug1(1, "in %s retrieval function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL) + return 0; + + if (width != NULL) + *width = info_ptr->width; + + if (height != NULL) + *height = info_ptr->height; + + if (bit_depth != NULL) + *bit_depth = info_ptr->bit_depth; + + if (color_type != NULL) + *color_type = info_ptr->color_type; + + if (compression_type != NULL) + *compression_type = info_ptr->compression_type; + + if (filter_type != NULL) + *filter_type = info_ptr->filter_type; + + if (interlace_type != NULL) + *interlace_type = info_ptr->interlace_type; + + /* This is redundant if we can be sure that the info_ptr values were all + * assigned in png_set_IHDR(). We do the check anyhow in case an + * application has ignored our advice not to mess with the members + * of info_ptr directly. + */ + png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + return 1; +} + +#ifdef PNG_oFFs_SUPPORTED +png_uint_32 PNGAPI +png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) +{ + png_debug1(1, "in %s retrieval function", "oFFs"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0 && + offset_x != NULL && offset_y != NULL && unit_type != NULL) + { + *offset_x = info_ptr->x_offset; + *offset_y = info_ptr->y_offset; + *unit_type = (int)info_ptr->offset_unit_type; + return PNG_INFO_oFFs; + } + + return 0; +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +png_uint_32 PNGAPI +png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, + png_charp *units, png_charpp *params) +{ + png_debug1(1, "in %s retrieval function", "pCAL"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pCAL) != 0 && + purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + nparams != NULL && units != NULL && params != NULL) + { + *purpose = info_ptr->pcal_purpose; + *X0 = info_ptr->pcal_X0; + *X1 = info_ptr->pcal_X1; + *type = (int)info_ptr->pcal_type; + *nparams = (int)info_ptr->pcal_nparams; + *units = info_ptr->pcal_units; + *params = info_ptr->pcal_params; + return PNG_INFO_pCAL; + } + + return 0; +} +#endif + +#ifdef PNG_sCAL_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +# if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) +png_uint_32 PNGAPI +png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, png_fixed_point *width, png_fixed_point *height) +{ + png_debug1(1, "in %s retrieval function", "sCAL"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + /*TODO: make this work without FP support; the API is currently eliminated + * if neither floating point APIs nor internal floating point arithmetic + * are enabled. + */ + *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width"); + *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height), + "sCAL height"); + return PNG_INFO_sCAL; + } + + return 0; +} +# endif /* FLOATING_ARITHMETIC */ +# endif /* FIXED_POINT */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, double *width, double *height) +{ + png_debug1(1, "in %s retrieval function", "sCAL(float)"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + *width = atof(info_ptr->scal_s_width); + *height = atof(info_ptr->scal_s_height); + return PNG_INFO_sCAL; + } + + return 0; +} +# endif /* FLOATING POINT */ +png_uint_32 PNGAPI +png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + png_debug1(1, "in %s retrieval function", "sCAL(str)"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return PNG_INFO_sCAL; + } + + return 0; +} +#endif /* sCAL */ + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + } + } + + return retval; +} +#endif /* pHYs */ + +png_uint_32 PNGAPI +png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr, + png_colorp *palette, int *num_palette) +{ + png_debug1(1, "in %s retrieval function", "PLTE"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_PLTE) != 0 && palette != NULL) + { + *palette = info_ptr->palette; + *num_palette = info_ptr->num_palette; + png_debug1(3, "num_palette = %d", *num_palette); + return PNG_INFO_PLTE; + } + + return 0; +} + +#ifdef PNG_sBIT_SUPPORTED +png_uint_32 PNGAPI +png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, + png_color_8p *sig_bit) +{ + png_debug1(1, "in %s retrieval function", "sBIT"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL) + { + *sig_bit = &(info_ptr->sig_bit); + return PNG_INFO_sBIT; + } + + return 0; +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +int PNGAPI +png_get_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_textp *text_ptr, int *num_text) +{ + if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) + { + png_debug1(1, "in text retrieval function, chunk typeid = 0x%lx", + (unsigned long)png_ptr->chunk_name); + + if (text_ptr != NULL) + *text_ptr = info_ptr->text; + + if (num_text != NULL) + *num_text = info_ptr->num_text; + + return info_ptr->num_text; + } + + if (num_text != NULL) + *num_text = 0; + + return 0; +} +#endif + +#ifdef PNG_tIME_SUPPORTED +png_uint_32 PNGAPI +png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_timep *mod_time) +{ + png_debug1(1, "in %s retrieval function", "tIME"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL) + { + *mod_time = &(info_ptr->mod_time); + return PNG_INFO_tIME; + } + + return 0; +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +png_uint_32 PNGAPI +png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) +{ + png_uint_32 retval = 0; + + png_debug1(1, "in %s retrieval function", "tRNS"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_tRNS) != 0) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (trans_alpha != NULL) + { + *trans_alpha = info_ptr->trans_alpha; + retval |= PNG_INFO_tRNS; + } + + if (trans_color != NULL) + *trans_color = &(info_ptr->trans_color); + } + + else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ + { + if (trans_color != NULL) + { + *trans_color = &(info_ptr->trans_color); + retval |= PNG_INFO_tRNS; + } + + if (trans_alpha != NULL) + *trans_alpha = NULL; + } + + if (num_trans != NULL) + { + *num_trans = info_ptr->num_trans; + retval |= PNG_INFO_tRNS; + } + } + + return retval; +} +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +int PNGAPI +png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, + png_unknown_chunkpp unknowns) +{ + if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) + { + *unknowns = info_ptr->unknown_chunks; + return info_ptr->unknown_chunks_num; + } + + return 0; +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +png_byte PNGAPI +png_get_rgb_to_gray_status(png_const_structrp png_ptr) +{ + return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); +} +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +png_voidp PNGAPI +png_get_user_chunk_ptr(png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_ptr : NULL); +} +#endif + +size_t PNGAPI +png_get_compression_buffer_size(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return 0; + +#ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) +#endif + { +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + return png_ptr->IDAT_read_size; +#else + return PNG_IDAT_READ_SIZE; +#endif + } + +#ifdef PNG_WRITE_SUPPORTED + else + return png_ptr->zbuffer_size; +#endif +} + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* These functions were added to libpng 1.2.6 and were enabled + * by default in libpng-1.4.0 */ +png_uint_32 PNGAPI +png_get_user_width_max(png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_width_max : 0); +} + +png_uint_32 PNGAPI +png_get_user_height_max(png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_height_max : 0); +} + +/* This function was added to libpng 1.4.0 */ +png_uint_32 PNGAPI +png_get_chunk_cache_max(png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_cache_max : 0); +} + +/* This function was added to libpng 1.4.1 */ +png_alloc_size_t PNGAPI +png_get_chunk_malloc_max(png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); +} +#endif /* SET_USER_LIMITS */ + +/* These functions were added to libpng 1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +png_uint_32 PNGAPI +png_get_io_state(png_const_structrp png_ptr) +{ + return png_ptr->io_state; +} + +png_uint_32 PNGAPI +png_get_io_chunk_type(png_const_structrp png_ptr) +{ + return png_ptr->chunk_name; +} +#endif /* IO_STATE */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +int PNGAPI +png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return png_ptr->num_palette_max; + + return -1; +} +# endif +#endif + +#endif /* READ || WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngmem.c b/widget/milsko/milskosrc/external/libpng/src/pngmem.c new file mode 100644 index 0000000000..71e61c99f7 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngmem.c @@ -0,0 +1,282 @@ +/* pngmem.c - stub functions for memory allocation + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all memory allocation. Users who + * need special memory handling are expected to supply replacement + * functions for png_malloc() and png_free(), and to use + * png_create_read_struct_2() and png_create_write_struct_2() to + * identify the replacement functions. + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Free a png_struct */ +void /* PRIVATE */ +png_destroy_png_struct(png_structrp png_ptr) +{ + if (png_ptr != NULL) + { + /* png_free might call png_error and may certainly call + * png_get_mem_ptr, so fake a temporary png_struct to support this. + */ + png_struct dummy_struct = *png_ptr; + memset(png_ptr, 0, (sizeof *png_ptr)); + png_free(&dummy_struct, png_ptr); + +# ifdef PNG_SETJMP_SUPPORTED + /* We may have a jmp_buf left to deallocate. */ + png_free_jmpbuf(&dummy_struct); +# endif + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more than 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +{ + png_voidp ret; + + ret = png_malloc(png_ptr, size); + + if (ret != NULL) + memset(ret, 0, size); + + return ret; +} + +/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of + * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED. + * Checking and error handling must happen outside this routine; it returns NULL + * if the allocation cannot be done (for any reason.) + */ +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) +{ + /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS + * allocators have also been removed in 1.6.0, so any 16-bit system now has + * to implement a user memory handler. This checks to be sure it isn't + * called with big numbers. + */ +# ifdef PNG_MAX_MALLOC_64K + /* This is support for legacy systems which had segmented addressing + * limiting the maximum allocation size to 65536. It takes precedence + * over PNG_SIZE_MAX which is set to 65535 on true 16-bit systems. + * + * TODO: libpng-1.8: finally remove both cases. + */ + if (size > 65536U) return NULL; +# endif + + /* This is checked too because the system malloc call below takes a (size_t). + */ + if (size > PNG_SIZE_MAX) return NULL; + +# ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr != NULL && png_ptr->malloc_fn != NULL) + return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size); +# else + PNG_UNUSED(png_ptr) +# endif + + /* Use the system malloc */ + return malloc((size_t)/*SAFE*/size); /* checked for truncation above */ +} + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7 + * that arises because of the checks in png_realloc_array that are repeated in + * png_malloc_array. + */ +static png_voidp +png_malloc_array_checked(png_const_structrp png_ptr, int nelements, + size_t element_size) +{ + png_alloc_size_t req = (png_alloc_size_t)nelements; /* known to be > 0 */ + + if (req <= PNG_SIZE_MAX/element_size) + return png_malloc_base(png_ptr, req * element_size); + + /* The failure case when the request is too large */ + return NULL; +} + +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_array,(png_const_structrp png_ptr, int nelements, + size_t element_size),PNG_ALLOCATED) +{ + if (nelements <= 0 || element_size == 0) + png_error(png_ptr, "internal error: array alloc"); + + return png_malloc_array_checked(png_ptr, nelements, element_size); +} + +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, + int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED) +{ + /* These are internal errors: */ + if (add_elements <= 0 || element_size == 0 || old_elements < 0 || + (old_array == NULL && old_elements > 0)) + png_error(png_ptr, "internal error: array realloc"); + + /* Check for overflow on the elements count (so the caller does not have to + * check.) + */ + if (add_elements <= INT_MAX - old_elements) + { + png_voidp new_array = png_malloc_array_checked(png_ptr, + old_elements+add_elements, element_size); + + if (new_array != NULL) + { + /* Because png_malloc_array worked the size calculations below cannot + * overflow. + */ + if (old_elements > 0) + memcpy(new_array, old_array, element_size*(unsigned)old_elements); + + memset((char*)new_array + element_size*(unsigned)old_elements, 0, + element_size*(unsigned)add_elements); + + return new_array; + } + } + + return NULL; /* error */ +} +#endif /* TEXT || sPLT || STORE_UNKNOWN_CHUNKS */ + +/* Various functions that have different error handling are derived from this. + * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate + * function png_malloc_default is also provided. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +{ + png_voidp ret; + + if (png_ptr == NULL) + return NULL; + + ret = png_malloc_base(png_ptr, size); + + if (ret == NULL) + png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */ + + return ret; +} + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED PNG_DEPRECATED) +{ + png_voidp ret; + + if (png_ptr == NULL) + return NULL; + + /* Passing 'NULL' here bypasses the application provided memory handler. */ + ret = png_malloc_base(NULL/*use malloc*/, size); + + if (ret == NULL) + png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */ + + return ret; +} +#endif /* USER_MEM */ + +/* This function was added at libpng version 1.2.3. The png_malloc_warn() + * function will issue a png_warning and return NULL instead of issuing a + * png_error, if it fails to allocate the requested memory. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) +{ + if (png_ptr != NULL) + { + png_voidp ret = png_malloc_base(png_ptr, size); + + if (ret != NULL) + return ret; + + png_warning(png_ptr, "Out of memory"); + } + + return NULL; +} + +/* Free a pointer allocated by png_malloc(). If ptr is NULL, return + * without taking any action. + */ +void PNGAPI +png_free(png_const_structrp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr); + + else + png_free_default(png_ptr, ptr); +} + +PNG_FUNCTION(void,PNGAPI +png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED) +{ + if (png_ptr == NULL || ptr == NULL) + return; +#endif /* USER_MEM */ + + free(ptr); +} + +#ifdef PNG_USER_MEM_SUPPORTED +/* This function is called when the application wants to use another method + * of allocating and freeing memory. + */ +void PNGAPI +png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr + malloc_fn, png_free_ptr free_fn) +{ + if (png_ptr != NULL) + { + png_ptr->mem_ptr = mem_ptr; + png_ptr->malloc_fn = malloc_fn; + png_ptr->free_fn = free_fn; + } +} + +/* This function returns a pointer to the mem_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_mem_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return png_ptr->mem_ptr; +} +#endif /* USER_MEM */ +#endif /* READ || WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngpread.c b/widget/milsko/milskosrc/external/libpng/src/pngpread.c new file mode 100644 index 0000000000..37aa432aec --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngpread.c @@ -0,0 +1,945 @@ +/* pngpread.c - read a png file in push mode + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + +/* Push model modes */ +#define PNG_READ_SIG_MODE 0 +#define PNG_READ_CHUNK_MODE 1 +#define PNG_READ_IDAT_MODE 2 +#define PNG_READ_tEXt_MODE 4 +#define PNG_READ_zTXt_MODE 5 +#define PNG_READ_DONE_MODE 6 +#define PNG_READ_iTXt_MODE 7 +#define PNG_ERROR_MODE 8 + +#define PNG_PUSH_SAVE_BUFFER_IF_FULL \ +if (png_ptr->push_length + 4 > png_ptr->buffer_size) \ + { png_push_save_buffer(png_ptr); return; } +#define PNG_PUSH_SAVE_BUFFER_IF_LT(N) \ +if (png_ptr->buffer_size < N) \ + { png_push_save_buffer(png_ptr); return; } + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ + +/* Start of interlace block */ +static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; +/* Offset to next interlace block */ +static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +/* Start of interlace block in the y direction */ +static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; +/* Offset to next interlace block in the y direction */ +static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + +/* TODO: Move these arrays to a common utility module to avoid duplication. */ +#endif + +void PNGAPI +png_process_data(png_structrp png_ptr, png_inforp info_ptr, + png_bytep buffer, size_t buffer_size) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_push_restore_buffer(png_ptr, buffer, buffer_size); + + while (png_ptr->buffer_size) + { + png_process_some_data(png_ptr, info_ptr); + } +} + +size_t PNGAPI +png_process_data_pause(png_structrp png_ptr, int save) +{ + if (png_ptr != NULL) + { + /* It's easiest for the caller if we do the save; then the caller doesn't + * have to supply the same data again: + */ + if (save != 0) + png_push_save_buffer(png_ptr); + else + { + /* This includes any pending saved bytes: */ + size_t remaining = png_ptr->buffer_size; + png_ptr->buffer_size = 0; + + /* So subtract the saved buffer size, unless all the data + * is actually 'saved', in which case we just return 0 + */ + if (png_ptr->save_buffer_size < remaining) + return remaining - png_ptr->save_buffer_size; + } + } + + return 0; +} + +png_uint_32 PNGAPI +png_process_data_skip(png_structrp png_ptr) +{ +/* TODO: Deprecate and remove this API. + * Somewhere the implementation of this seems to have been lost, + * or abandoned. It was only to support some internal back-door access + * to png_struct) in libpng-1.4.x. + */ + png_app_warning(png_ptr, +"png_process_data_skip is not implemented in any current version of libpng"); + return 0; +} + +/* What we do with the incoming data depends on what we were previously + * doing before we ran out of data... + */ +void /* PRIVATE */ +png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr == NULL) + return; + + switch (png_ptr->process_mode) + { + case PNG_READ_SIG_MODE: + { + png_push_read_sig(png_ptr, info_ptr); + break; + } + + case PNG_READ_CHUNK_MODE: + { + png_push_read_chunk(png_ptr, info_ptr); + break; + } + + case PNG_READ_IDAT_MODE: + { + png_push_read_IDAT(png_ptr); + break; + } + + default: + { + png_ptr->buffer_size = 0; + break; + } + } +} + +/* Read any remaining signature bytes from the stream and compare them with + * the correct PNG signature. It is possible that this routine is called + * with bytes already read from the signature, either because they have been + * checked by the calling application, or because of multiple calls to this + * routine. + */ +void /* PRIVATE */ +png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) +{ + size_t num_checked = png_ptr->sig_bytes; /* SAFE, does not exceed 8 */ + size_t num_to_check = 8 - num_checked; + + if (png_ptr->buffer_size < num_to_check) + { + num_to_check = png_ptr->buffer_size; + } + + png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), + num_to_check); + png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0) + png_error(png_ptr, "Not a PNG file"); + + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + else + { + if (png_ptr->sig_bytes >= 8) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + } +} + +void /* PRIVATE */ +png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) +{ + png_uint_32 chunk_name; +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; /* unknown handling method */ +#endif + + /* First we make sure we have enough data for the 4-byte chunk name + * and the 4-byte chunk length before proceeding with decoding the + * chunk data. To fully decode each of these chunks, we also make + * sure we have enough data in the buffer for the 4-byte CRC at the + * end of every chunk (except IDAT, which is handled separately). + */ + if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) + { + PNG_PUSH_SAVE_BUFFER_IF_LT(8) + png_ptr->push_length = png_read_chunk_header(png_ptr); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + } + + chunk_name = png_ptr->chunk_name; + + if (chunk_name == png_IDAT) + { + if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + /* If we reach an IDAT chunk, this means we have read all of the + * header chunks, and we can start reading the image (or if this + * is called after the image has been read - we have an error). + */ + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->process_mode = PNG_READ_IDAT_MODE; + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0) + if (png_ptr->push_length == 0) + return; + + png_ptr->mode |= PNG_HAVE_IDAT; + + if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_benign_error(png_ptr, "Too many IDATs found"); + } + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + /* These flags must be set consistently for all non-IDAT chunks, + * including the unknown chunks. + */ + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT; + } + + if (chunk_name == png_IHDR) + { + if (png_ptr->push_length != 13) + png_error(png_ptr, "Invalid IHDR length"); + + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (chunk_name == png_IEND) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length); + + png_ptr->process_mode = PNG_READ_DONE_MODE; + png_push_have_end(png_ptr, info_ptr); + } + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); + + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = png_ptr->push_length; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + png_push_have_info(png_ptr, info_ptr); + png_ptr->zstream.avail_out = + (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + png_ptr->zstream.next_out = png_ptr->row_buf; + return; + } + + else + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length); + } + + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; +} + +void PNGCBAPI +png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, size_t length) +{ + png_bytep ptr; + + if (png_ptr == NULL) + return; + + ptr = buffer; + if (png_ptr->save_buffer_size != 0) + { + size_t save_size; + + if (length < png_ptr->save_buffer_size) + save_size = length; + + else + save_size = png_ptr->save_buffer_size; + + memcpy(ptr, png_ptr->save_buffer_ptr, save_size); + length -= save_size; + ptr += save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (length != 0 && png_ptr->current_buffer_size != 0) + { + size_t save_size; + + if (length < png_ptr->current_buffer_size) + save_size = length; + + else + save_size = png_ptr->current_buffer_size; + + memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } +} + +void /* PRIVATE */ +png_push_save_buffer(png_structrp png_ptr) +{ + if (png_ptr->save_buffer_size != 0) + { + if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) + { + size_t i, istop; + png_bytep sp; + png_bytep dp; + + istop = png_ptr->save_buffer_size; + for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; + i < istop; i++, sp++, dp++) + { + *dp = *sp; + } + } + } + if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > + png_ptr->save_buffer_max) + { + size_t new_max; + png_bytep old_buffer; + + if (png_ptr->save_buffer_size > PNG_SIZE_MAX - + (png_ptr->current_buffer_size + 256)) + { + png_error(png_ptr, "Potential overflow of save_buffer"); + } + + new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; + old_buffer = png_ptr->save_buffer; + png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, + (size_t)new_max); + + if (png_ptr->save_buffer == NULL) + { + png_free(png_ptr, old_buffer); + png_error(png_ptr, "Insufficient memory for save_buffer"); + } + + if (old_buffer) + memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + else if (png_ptr->save_buffer_size) + png_error(png_ptr, "save_buffer error"); + png_free(png_ptr, old_buffer); + png_ptr->save_buffer_max = new_max; + } + if (png_ptr->current_buffer_size) + { + memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); + png_ptr->save_buffer_size += png_ptr->current_buffer_size; + png_ptr->current_buffer_size = 0; + } + png_ptr->save_buffer_ptr = png_ptr->save_buffer; + png_ptr->buffer_size = 0; +} + +void /* PRIVATE */ +png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, + size_t buffer_length) +{ + png_ptr->current_buffer = buffer; + png_ptr->current_buffer_size = buffer_length; + png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; + png_ptr->current_buffer_ptr = png_ptr->current_buffer; +} + +void /* PRIVATE */ +png_push_read_IDAT(png_structrp png_ptr) +{ + if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) + { + png_byte chunk_length[4]; + png_byte chunk_tag[4]; + + /* TODO: this code can be commoned up with the same code in push_read */ + PNG_PUSH_SAVE_BUFFER_IF_LT(8) + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, chunk_tag, 4); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + + if (png_ptr->chunk_name != png_IDAT) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + png_error(png_ptr, "Not enough compressed data"); + + return; + } + + png_ptr->idat_size = png_ptr->push_length; + } + + if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0) + { + size_t save_size = png_ptr->save_buffer_size; + png_uint_32 idat_size = png_ptr->idat_size; + + /* We want the smaller of 'idat_size' and 'current_buffer_size', but they + * are of different types and we don't know which variable has the fewest + * bits. Carefully select the smaller and cast it to the type of the + * larger - this cannot overflow. Do not cast in the following test - it + * will break on either 16-bit or 64-bit platforms. + */ + if (idat_size < save_size) + save_size = (size_t)idat_size; + + else + idat_size = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->idat_size -= idat_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + + if (png_ptr->idat_size != 0 && png_ptr->current_buffer_size != 0) + { + size_t save_size = png_ptr->current_buffer_size; + png_uint_32 idat_size = png_ptr->idat_size; + + /* We want the smaller of 'idat_size' and 'current_buffer_size', but they + * are of different types and we don't know which variable has the fewest + * bits. Carefully select the smaller and cast it to the type of the + * larger - this cannot overflow. + */ + if (idat_size < save_size) + save_size = (size_t)idat_size; + + else + idat_size = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->idat_size -= idat_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + + if (png_ptr->idat_size == 0) + { + PNG_PUSH_SAVE_BUFFER_IF_LT(4) + png_crc_finish(png_ptr, 0); + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->zowner = 0; + } +} + +void /* PRIVATE */ +png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, + size_t buffer_length) +{ + /* The caller checks for a non-zero buffer length. */ + if (!(buffer_length > 0) || buffer == NULL) + png_error(png_ptr, "No IDAT data (internal error)"); + + /* This routine must process all the data it has been given + * before returning, calling the row callback as required to + * handle the uncompressed results. + */ + png_ptr->zstream.next_in = buffer; + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ + png_ptr->zstream.avail_in = (uInt)buffer_length; + + /* Keep going until the decompressed data is all processed + * or the stream marked as finished. + */ + while (png_ptr->zstream.avail_in > 0 && + (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + int ret; + + /* We have data for zlib, but we must check that zlib + * has someplace to put the results. It doesn't matter + * if we don't expect any results -- it may be the input + * data is just the LZ end code. + */ + if (!(png_ptr->zstream.avail_out > 0)) + { + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ + png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1); + + png_ptr->zstream.next_out = png_ptr->row_buf; + } + + /* Using Z_SYNC_FLUSH here means that an unterminated + * LZ stream (a stream with a missing end code) can still + * be handled, otherwise (Z_NO_FLUSH) a future zlib + * implementation might defer output and therefore + * change the current behavior (see comments in inflate.c + * for why this doesn't happen at present with zlib 1.2.5). + */ + ret = PNG_INFLATE(png_ptr, Z_SYNC_FLUSH); + + /* Check for any failure before proceeding. */ + if (ret != Z_OK && ret != Z_STREAM_END) + { + /* Terminate the decompression. */ + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; + + /* This may be a truncated stream (missing or + * damaged end code). Treat that as a warning. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + png_warning(png_ptr, "Truncated compressed data in IDAT"); + + else + { + if (ret == Z_DATA_ERROR) + png_benign_error(png_ptr, "IDAT: ADLER32 checksum mismatch"); + else + png_error(png_ptr, "Decompression error in IDAT"); + } + + /* Skip the check on unprocessed input */ + return; + } + + /* Did inflate output any data? */ + if (png_ptr->zstream.next_out != png_ptr->row_buf) + { + /* Is this unexpected data after the last row? + * If it is, artificially terminate the LZ output + * here. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + { + /* Extra data. */ + png_warning(png_ptr, "Extra compressed data in IDAT"); + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; + + /* Do no more processing; skip the unprocessed + * input check below. + */ + return; + } + + /* Do we have a complete row? */ + if (png_ptr->zstream.avail_out == 0) + png_push_process_row(png_ptr); + } + + /* And check for the end of the stream. */ + if (ret == Z_STREAM_END) + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + + /* All the data should have been processed, if anything + * is left at this point we have bytes of IDAT data + * after the zlib end code. + */ + if (png_ptr->zstream.avail_in > 0) + png_warning(png_ptr, "Extra compression data in IDAT"); +} + +void /* PRIVATE */ +png_push_process_row(png_structrp png_ptr) +{ + /* 1.5.6: row_info moved out of png_struct to a local here. */ + png_row_info row_info; + + row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ + row_info.color_type = png_ptr->color_type; + row_info.bit_depth = png_ptr->bit_depth; + row_info.channels = png_ptr->channels; + row_info.pixel_depth = png_ptr->pixel_depth; + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + + if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) + { + if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) + png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, + png_ptr->prev_row + 1, png_ptr->row_buf[0]); + else + png_error(png_ptr, "bad adaptive filter value"); + } + + /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before + * 1.5.6, while the buffer really is this big in current versions of libpng + * it may not be in the future, so this was changed just to copy the + * interlaced row count: + */ + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + if (png_ptr->transformations != 0) + png_do_read_transformations(png_ptr, &row_info); +#endif + + /* The transformed pixel depth should match the depth now in row_info. */ + if (png_ptr->transformed_pixel_depth == 0) + { + png_ptr->transformed_pixel_depth = row_info.pixel_depth; + if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) + png_error(png_ptr, "progressive row overflow"); + } + + else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) + png_error(png_ptr, "internal progressive row size calculation error"); + + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Expand interlaced rows to full size */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + if (png_ptr->pass < 6) + png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, + png_ptr->transformations); + + switch (png_ptr->pass) + { + case 0: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 0; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ + } + + if (png_ptr->pass == 2) /* Pass 1 might be empty */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 4 && png_ptr->height <= 4) + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 6 && png_ptr->height <= 4) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 1: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 1; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 2) /* Skip top 4 generated rows */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 2: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Pass 3 might be empty */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 3: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 3; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Skip top two generated rows */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 4: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Pass 5 might be empty */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 5: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 5; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Skip top generated row */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + default: + case 6: + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + + if (png_ptr->pass != 6) + break; + + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + } + else +#endif + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } +} + +void /* PRIVATE */ +png_read_push_finish_row(png_structrp png_ptr) +{ + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced != 0) + { + png_ptr->row_number = 0; + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + do + { + png_ptr->pass++; + if ((png_ptr->pass == 1 && png_ptr->width < 5) || + (png_ptr->pass == 3 && png_ptr->width < 3) || + (png_ptr->pass == 5 && png_ptr->width < 2)) + png_ptr->pass++; + + if (png_ptr->pass > 7) + png_ptr->pass--; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if ((png_ptr->transformations & PNG_INTERLACE) != 0) + break; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); + } +#endif /* READ_INTERLACING */ +} + +void /* PRIVATE */ +png_push_have_info(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr->info_fn != NULL) + (*(png_ptr->info_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_end(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr->end_fn != NULL) + (*(png_ptr->end_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_row(png_structrp png_ptr, png_bytep row) +{ + if (png_ptr->row_fn != NULL) + (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, + (int)png_ptr->pass); +} + +#ifdef PNG_READ_INTERLACING_SUPPORTED +void PNGAPI +png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, + png_const_bytep new_row) +{ + if (png_ptr == NULL) + return; + + /* new_row is a flag here - if it is NULL then the app callback was called + * from an empty row (see the calls to png_struct::row_fn below), otherwise + * it must be png_ptr->row_buf+1 + */ + if (new_row != NULL) + png_combine_row(png_ptr, old_row, 1/*blocky display*/); +} +#endif /* READ_INTERLACING */ + +void PNGAPI +png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->info_fn = info_fn; + png_ptr->row_fn = row_fn; + png_ptr->end_fn = end_fn; + + png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); +} + +png_voidp PNGAPI +png_get_progressive_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return png_ptr->io_ptr; +} +#endif /* PROGRESSIVE_READ */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngread.c b/widget/milsko/milskosrc/external/libpng/src/pngread.c new file mode 100644 index 0000000000..212afb7d21 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngread.c @@ -0,0 +1,4098 @@ +/* pngread.c - read a PNG file + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that an application calls directly to + * read a PNG file or stream. + */ + +#include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif + +#ifdef PNG_READ_SUPPORTED + +/* Create a PNG structure for reading, and allocate any memory needed. */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) +{ +#ifndef PNG_USER_MEM_SUPPORTED + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_read_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); +} + +/* Alternate create PNG structure for reading, and allocate any memory + * needed. + */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ + + if (png_ptr != NULL) + { + png_ptr->mode = PNG_IS_READ_STRUCT; + + /* Added in libpng-1.6.0; this can be used to detect a read structure if + * required (it will be zero in a write structure.) + */ +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE; +# endif + +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + + /* In stable builds only warn if an application error can be completely + * handled. + */ +# if PNG_RELEASE_BUILD + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +# endif +# endif + + /* TODO: delay this, it can be done in png_init_io (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_read_fn(png_ptr, NULL, NULL); + } + + return png_ptr; +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. This has been + * changed in v0.90 to allow reading a file that already has the magic + * bytes read from the stream. You can tell libpng how many bytes have + * been read from the beginning of the stream (up to the maximum of 8) + * via png_set_sig_bytes(), and we will only check the remaining bytes + * here. The application can then have access to the signature bytes we + * read if it is determined that this isn't a valid PNG file. + */ +void PNGAPI +png_read_info(png_structrp png_ptr, png_inforp info_ptr) +{ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + + png_debug(1, "in png_read_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Read and check the PNG file signature. */ + png_read_sig(png_ptr, info_ptr); + + for (;;) + { + png_uint_32 length = png_read_chunk_header(png_ptr); + png_uint_32 chunk_name = png_ptr->chunk_name; + + /* IDAT logic needs to happen here to simplify getting the two flags + * right. + */ + if (chunk_name == png_IDAT) + { + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + png_chunk_error(png_ptr, "Missing PLTE before IDAT"); + + else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_chunk_benign_error(png_ptr, "Too many IDATs found"); + + png_ptr->mode |= PNG_HAVE_IDAT; + } + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + png_ptr->mode |= PNG_AFTER_IDAT; + } + + if (chunk_name == png_IHDR) + png_handle_chunk(png_ptr, info_ptr, length); + + else if (chunk_name == png_IEND) + png_handle_chunk(png_ptr, info_ptr, length); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + png_handle_unknown(png_ptr, info_ptr, length, keep); + + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = 0; /* It has been consumed */ + break; + } + } +#endif + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = length; + break; + } + + else + png_handle_chunk(png_ptr, info_ptr, length); + } +} +#endif /* SEQUENTIAL_READ */ + +/* Optional call to update the users info_ptr structure */ +void PNGAPI +png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_read_update_info"); + + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + png_read_start_row(png_ptr); + +# ifdef PNG_READ_TRANSFORMS_SUPPORTED + png_read_transform_info(png_ptr, info_ptr); +# else + PNG_UNUSED(info_ptr) +# endif + } + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_read_update_info/png_start_read_image: duplicate call"); + } +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Initialize palette, background, etc, after transformations + * are set, but before any reading takes place. This allows + * the user to obtain a gamma-corrected palette, for example. + * If the user doesn't call this, we will do it ourselves. + */ +void PNGAPI +png_start_read_image(png_structrp png_ptr) +{ + png_debug(1, "in png_start_read_image"); + + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + png_read_start_row(png_ptr); + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_start_read_image/png_read_update_info: duplicate call"); + } +} +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing, + * NOTE: this is apparently only supported in the 'sequential' reader. + */ +static void +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_intrapixel"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); + *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (s0 + s1 + 65536) & 0xffff; + png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp + 1) = (png_byte)(red & 0xff); + *(rp + 4) = (png_byte)((blue >> 8) & 0xff); + *(rp + 5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* MNG_FEATURES */ + +void PNGAPI +png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) +{ + png_row_info row_info; + + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_read_row (row %lu, pass %d)", + (unsigned long)png_ptr->row_number, png_ptr->pass); + + /* png_read_start_row sets the information (in particular iwidth) for this + * interlace pass. + */ + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + png_read_start_row(png_ptr); + + /* 1.5.6: row_info moved out of png_struct to a local here. */ + row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ + row_info.color_type = png_ptr->color_type; + row_info.bit_depth = png_ptr->bit_depth; + row_info.channels = png_ptr->channels; + row_info.pixel_depth = png_ptr->pixel_depth; + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + +#ifdef PNG_WARNINGS_SUPPORTED + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Check for transforms that have been set but were defined out */ +#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + !defined(PNG_READ_PACKSWAP_SUPPORTED) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) != 0) + png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) + if ((png_ptr->transformations & PNG_BGR) != 0) + png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); +#endif + } +#endif /* WARNINGS */ + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* If interlaced and we do not need a new row, combine row and return. + * Notice that the pixels we have from previous rows have been transformed + * already; we can only combine like with like (transformed or + * untransformed) and, because of the libpng API for interlaced images, this + * means we must transform before de-interlacing. + */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + png_read_finish_row(png_ptr); + return; + } + break; + + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + if (dsp_row != NULL && (png_ptr->row_number & 4)) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 3: + if ((png_ptr->row_number & 3) || png_ptr->width < 3) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 4: + if ((png_ptr->row_number & 3) != 2) + { + if (dsp_row != NULL && (png_ptr->row_number & 2)) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 5: + if ((png_ptr->row_number & 1) || png_ptr->width < 2) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + default: + case 6: + if ((png_ptr->row_number & 1) == 0) + { + png_read_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) + png_error(png_ptr, "Invalid attempt to read row data"); + + /* Fill the row with IDAT data: */ + png_ptr->row_buf[0]=255; /* to force error if no data was found */ + png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); + + if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) + { + if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) + png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, + png_ptr->prev_row + 1, png_ptr->row_buf[0]); + else + png_error(png_ptr, "bad adaptive filter value"); + } + + /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before + * 1.5.6, while the buffer really is this big in current versions of libpng + * it may not be in the future, so this was changed just to copy the + * interlaced count: + */ + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1); + } +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + if (png_ptr->transformations +# ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + || png_ptr->num_palette_max >= 0 +# endif + ) + png_do_read_transformations(png_ptr, &row_info); +#endif + + /* The transformed pixel depth should match the depth now in row_info. */ + if (png_ptr->transformed_pixel_depth == 0) + { + png_ptr->transformed_pixel_depth = row_info.pixel_depth; + if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) + png_error(png_ptr, "sequential row overflow"); + } + + else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) + png_error(png_ptr, "internal sequential row size calculation error"); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Expand interlaced rows to full size */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + if (png_ptr->pass < 6) + png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, + png_ptr->transformations); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + if (row != NULL) + png_combine_row(png_ptr, row, 0/*row*/); + } + + else +#endif + { + if (row != NULL) + png_combine_row(png_ptr, row, -1/*ignored*/); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, -1/*ignored*/); + } + png_read_finish_row(png_ptr); + + if (png_ptr->read_row_fn != NULL) + (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); + +} +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. If the image is interlaced, + * and png_set_interlace_handling() has been called, the rows need to + * contain the contents of the rows from the previous pass. If the + * image has alpha or transparency, and png_handle_alpha()[*] has been + * called, the rows contents must be initialized to the contents of the + * screen. + * + * "row" holds the actual image, and pixels are placed in it + * as they arrive. If the image is displayed after each pass, it will + * appear to "sparkle" in. "display_row" can be used to display a + * "chunky" progressive image, with finer detail added as it becomes + * available. If you do not want this "chunky" display, you may pass + * NULL for display_row. If you do not want the sparkle display, and + * you have not called png_handle_alpha(), you may pass NULL for rows. + * If you have called png_handle_alpha(), and the image has either an + * alpha channel or a transparency chunk, you must provide a buffer for + * rows. In this case, you do not have to provide a display_row buffer + * also, but you may. If the image is not interlaced, or if you have + * not called png_set_interlace_handling(), the display_row buffer will + * be ignored, so pass NULL to it. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ + +void PNGAPI +png_read_rows(png_structrp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows) +{ + png_uint_32 i; + png_bytepp rp; + png_bytepp dp; + + png_debug(1, "in png_read_rows"); + + if (png_ptr == NULL) + return; + + rp = row; + dp = display_row; + if (rp != NULL && dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp++; + png_bytep dptr = *dp++; + + png_read_row(png_ptr, rptr, dptr); + } + + else if (rp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp; + png_read_row(png_ptr, rptr, NULL); + rp++; + } + + else if (dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep dptr = *dp; + png_read_row(png_ptr, NULL, dptr); + dp++; + } +} +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the entire image. If the image has an alpha channel or a tRNS + * chunk, and you have called png_handle_alpha()[*], you will need to + * initialize the image to the current image that PNG will be overlaying. + * We set the num_rows again here, in case it was incorrectly set in + * png_read_start_row() by a call to png_read_update_info() or + * png_start_read_image() if png_set_interlace_handling() wasn't called + * prior to either of these functions like it should have been. You can + * only call this function once. If you desire to have an image for + * each pass of a interlaced image, use png_read_rows() instead. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ +void PNGAPI +png_read_image(png_structrp png_ptr, png_bytepp image) +{ + png_uint_32 i, image_height; + int pass, j; + png_bytepp rp; + + png_debug(1, "in png_read_image"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + pass = png_set_interlace_handling(png_ptr); + /* And make sure transforms are initialized. */ + png_start_read_image(png_ptr); + } + else + { + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) == 0) + { + /* Caller called png_start_read_image or png_read_update_info without + * first turning on the PNG_INTERLACE transform. We can fix this here, + * but the caller should do it! + */ + png_warning(png_ptr, "Interlace handling should be turned on when " + "using png_read_image"); + /* Make sure this is set correctly */ + png_ptr->num_rows = png_ptr->height; + } + + /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in + * the above error case. + */ + pass = png_set_interlace_handling(png_ptr); + } +#else + if (png_ptr->interlaced) + png_error(png_ptr, + "Cannot read interlaced image -- interlace handler disabled"); + + pass = 1; +#endif + + image_height=png_ptr->height; + + for (j = 0; j < pass; j++) + { + rp = image; + for (i = 0; i < image_height; i++) + { + png_read_row(png_ptr, *rp, NULL); + rp++; + } + } +} +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. Will not read past the end of the + * file, will verify the end is accurate, and will read any comments + * or time information at the end of the file, if info is not NULL. + */ +void PNGAPI +png_read_end(png_structrp png_ptr, png_inforp info_ptr) +{ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + + png_debug(1, "in png_read_end"); + + if (png_ptr == NULL) + return; + + /* If png_read_end is called in the middle of reading the rows there may + * still be pending IDAT data and an owned zstream. Deal with this here. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0) +#endif + png_read_finish_IDAT(png_ptr); + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Report invalid palette index; added at libng-1.5.10 */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= png_ptr->num_palette) + png_benign_error(png_ptr, "Read palette index exceeding num_palette"); +#endif + + do + { + png_uint_32 length = png_read_chunk_header(png_ptr); + png_uint_32 chunk_name = png_ptr->chunk_name; + + if (chunk_name != png_IDAT) + { + /* These flags must be set consistently for all non-IDAT chunks, + * including the unknown chunks. + */ + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT; + } + + if (chunk_name == png_IEND) + png_handle_chunk(png_ptr, info_ptr, length); + + else if (chunk_name == png_IHDR) + png_handle_chunk(png_ptr, info_ptr, length); + + else if (info_ptr == NULL) + png_crc_finish(png_ptr, length); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + if (chunk_name == png_IDAT) + { + if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) + png_benign_error(png_ptr, ".Too many IDATs found"); + } + png_handle_unknown(png_ptr, info_ptr, length, keep); + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + + else if (chunk_name == png_IDAT) + { + /* Zero length IDATs are legal after the last IDAT has been + * read, but not after other chunks have been read. 1.6 does not + * always read all the deflate data; specifically it cannot be relied + * upon to read the Adler32 at the end. If it doesn't ignore IDAT + * chunks which are longer than zero as well: + */ + if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) + png_benign_error(png_ptr, "..Too many IDATs found"); + + png_crc_finish(png_ptr, length); + } + + else + png_handle_chunk(png_ptr, info_ptr, length); + } while ((png_ptr->mode & PNG_HAVE_IEND) == 0); +} +#endif /* SEQUENTIAL_READ */ + +/* Free all memory used in the read struct */ +static void +png_read_destroy(png_structrp png_ptr) +{ + png_debug(1, "in png_read_destroy"); + +#ifdef PNG_READ_GAMMA_SUPPORTED + png_destroy_gamma_table(png_ptr); +#endif + + png_free(png_ptr, png_ptr->big_row_buf); + png_ptr->big_row_buf = NULL; + png_free(png_ptr, png_ptr->big_prev_row); + png_ptr->big_prev_row = NULL; + png_free(png_ptr, png_ptr->read_buffer); + png_ptr->read_buffer = NULL; + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_free(png_ptr, png_ptr->palette_lookup); + png_ptr->palette_lookup = NULL; + png_free(png_ptr, png_ptr->quantize_index); + png_ptr->quantize_index = NULL; +#endif + + if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) + { + png_zfree(png_ptr, png_ptr->palette); + png_ptr->palette = NULL; + } + png_ptr->free_me &= ~PNG_FREE_PLTE; + +#if defined(PNG_tRNS_SUPPORTED) || \ + defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) + { + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; + } + png_ptr->free_me &= ~PNG_FREE_TRNS; +#endif + + inflateEnd(&png_ptr->zstream); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_free(png_ptr, png_ptr->save_buffer); + png_ptr->save_buffer = NULL; +#endif + +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) && \ + (defined(PNG_ARM_NEON_IMPLEMENTATION) || \ + defined(PNG_RISCV_RVV_IMPLEMENTATION)) + png_free(png_ptr, png_ptr->riffled_palette); + png_ptr->riffled_palette = NULL; +#endif + + /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error + * callbacks are still set at this point. They are required to complete the + * destruction of the png_struct itself. + */ +} + +/* Free all memory used by the read */ +void PNGAPI +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr_ptr) +{ + png_structrp png_ptr = NULL; + + png_debug(1, "in png_destroy_read_struct"); + + if (png_ptr_ptr != NULL) + png_ptr = *png_ptr_ptr; + + if (png_ptr == NULL) + return; + + /* libpng 1.6.0: use the API to destroy info structs to ensure consistent + * behavior. Prior to 1.6.0 libpng did extra 'info' destruction in this API. + * The extra was, apparently, unnecessary yet this hides memory leak bugs. + */ + png_destroy_info_struct(png_ptr, end_info_ptr_ptr); + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_read_destroy(png_ptr); + png_destroy_png_struct(png_ptr); +} + +void PNGAPI +png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->read_row_fn = read_row_fn; +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_read_png(png_structrp png_ptr, png_inforp info_ptr, + int transforms, voidp params) +{ + png_debug(1, "in png_read_png"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). + */ + png_read_info(png_ptr, info_ptr); + if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep))) + png_error(png_ptr, "Image is too high to process with png_read_png()"); + + /* -------------- image transformations start here ------------------- */ + /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM + * is not implemented. This will only happen in de-configured (non-default) + * libpng builds. The results can be unexpected - png_read_png may return + * short or mal-formed rows because the transform is skipped. + */ + + /* Tell libpng to strip 16-bit/color files down to 8 bits per color. + */ + if ((transforms & PNG_TRANSFORM_SCALE_16) != 0) + /* Added at libpng-1.5.4. "strip_16" produces the same result that it + * did in earlier versions, while "scale_16" is now more accurate. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SCALE_16 not supported"); +#endif + + /* If both SCALE and STRIP are required pngrtran will effectively cancel the + * latter by doing SCALE first. This is ok and allows apps not to check for + * which is supported to get the right answer. + */ + if ((transforms & PNG_TRANSFORM_STRIP_16) != 0) +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + png_set_strip_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_16 not supported"); +#endif + + /* Strip alpha bytes from the input data without combining with + * the background (not recommended). + */ + if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0) +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + png_set_strip_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_ALPHA not supported"); +#endif + + /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + if ((transforms & PNG_TRANSFORM_PACKING) != 0) +#ifdef PNG_READ_PACK_SUPPORTED + png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); +#endif + + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). + */ + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) +#ifdef PNG_READ_PACKSWAP_SUPPORTED + png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); +#endif + + /* Expand paletted colors into true RGB triplets + * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel + * Expand paletted or RGB images with transparency to full alpha + * channels so the data will be available as RGBA quartets. + */ + if ((transforms & PNG_TRANSFORM_EXPAND) != 0) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_set_expand(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND not supported"); +#endif + + /* We don't handle background color or gamma transformation or quantizing. + */ + + /* Invert monochrome files to have 0 as white and 1 as black + */ + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) +#ifdef PNG_READ_INVERT_SUPPORTED + png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); +#endif + + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); +#endif + + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ + if ((transforms & PNG_TRANSFORM_BGR) != 0) +#ifdef PNG_READ_BGR_SUPPORTED + png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); +#endif + + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); +#endif + + /* Swap bytes of 16-bit files to least significant byte first */ + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) +#ifdef PNG_READ_SWAP_SUPPORTED + png_set_swap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); +#endif + +/* Added at libpng-1.2.41 */ + /* Invert the alpha channel from opacity to transparency */ + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); +#endif + +/* Added at libpng-1.2.41 */ + /* Expand grayscale image to RGB */ + if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0) +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + png_set_gray_to_rgb(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_GRAY_TO_RGB not supported"); +#endif + +/* Added at libpng-1.5.4 */ + if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0) +#ifdef PNG_READ_EXPAND_16_SUPPORTED + png_set_expand_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND_16 not supported"); +#endif + + /* We don't handle adding filler bytes */ + + /* We use png_read_image and rely on that for interlace handling, but we also + * call png_read_update_info therefore must turn on interlace handling now: + */ + (void)png_set_interlace_handling(png_ptr); + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (i.e., you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* -------------- image transformations end here ------------------- */ + + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + if (info_ptr->row_pointers == NULL) + { + png_uint_32 iptr; + + info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr, + info_ptr->height * (sizeof (png_bytep)))); + + for (iptr=0; iptrheight; iptr++) + info_ptr->row_pointers[iptr] = NULL; + + info_ptr->free_me |= PNG_FREE_ROWS; + + for (iptr = 0; iptr < info_ptr->height; iptr++) + info_ptr->row_pointers[iptr] = png_voidcast(png_bytep, + png_malloc(png_ptr, info_ptr->rowbytes)); + } + + png_read_image(png_ptr, info_ptr->row_pointers); + info_ptr->valid |= PNG_INFO_IDAT; + + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); + + PNG_UNUSED(params) +} +#endif /* INFO_IMAGE */ +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* SIMPLIFIED READ + * + * This code currently relies on the sequential reader, though it could easily + * be made to work with the progressive one. + */ +/* Arguments to png_image_finish_read: */ + +/* Encoding of PNG data (used by the color-map code) */ +# define P_NOTSET 0 /* File encoding not yet known */ +# define P_sRGB 1 /* 8-bit encoded to sRGB gamma */ +# define P_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ +# define P_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ +# define P_LINEAR8 4 /* 8-bit linear: only from a file value */ + +/* Color-map processing: after libpng has run on the PNG image further + * processing may be needed to convert the data to color-map indices. + */ +#define PNG_CMAP_NONE 0 +#define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */ +#define PNG_CMAP_TRANS 2 /* Process GA data to a background index */ +#define PNG_CMAP_RGB 3 /* Process RGB data */ +#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */ + +/* The following document where the background is for each processing case. */ +#define PNG_CMAP_NONE_BACKGROUND 256 +#define PNG_CMAP_GA_BACKGROUND 231 +#define PNG_CMAP_TRANS_BACKGROUND 254 +#define PNG_CMAP_RGB_BACKGROUND 256 +#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216 + +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_voidp buffer; + png_int_32 row_stride; + png_voidp colormap; + png_const_colorp background; + /* Local variables: */ + png_voidp local_row; + png_voidp first_row; + ptrdiff_t row_bytes; /* step between rows */ + int file_encoding; /* E_ values above */ + png_fixed_point gamma_to_linear; /* For P_FILE, reciprocal of gamma */ + int colormap_processing; /* PNG_CMAP_ values above */ +} png_image_read_control; + +/* Do all the *safe* initialization - 'safe' means that png_error won't be + * called, so setting up the jmp_buf is not required. This means that anything + * called from here must *not* call png_malloc - it has to call png_malloc_warn + * instead so that control is returned safely back to this routine. + */ +static int +png_image_read_init(png_imagep image) +{ + if (image->opaque == NULL) + { + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + /* And set the rest of the structure to NULL to ensure that the various + * fields are consistent. + */ + memset(image, 0, (sizeof *image)); + image->version = PNG_IMAGE_VERSION; + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 0; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_read_struct(&png_ptr, NULL, NULL); + } + + return png_image_error(image, "png_image_read: out of memory"); + } + + return png_image_error(image, "png_image_read: opaque pointer not NULL"); +} + +/* Utility to find the base format of a PNG file from a png_struct. */ +static png_uint_32 +png_image_format(png_structrp png_ptr) +{ + png_uint_32 format = 0; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + format |= PNG_FORMAT_FLAG_COLOR; + + if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS + * sets the png_struct fields; that's all we are interested in here. The + * precise interaction with an app call to png_set_tRNS and PNG file reading + * is unclear. + */ + else if (png_ptr->num_trans > 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + if (png_ptr->bit_depth == 16) + format |= PNG_FORMAT_FLAG_LINEAR; + + if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0) + format |= PNG_FORMAT_FLAG_COLORMAP; + + return format; +} + +static int +chromaticities_match_sRGB(const png_xy *xy) +{ +# define sRGB_TOLERANCE 1000 + static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ + { + /* color x y */ + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000, + /* white */ 31270, 32900 + }; + + if (PNG_OUT_OF_RANGE(xy->whitex, sRGB_xy.whitex,sRGB_TOLERANCE) || + PNG_OUT_OF_RANGE(xy->whitey, sRGB_xy.whitey,sRGB_TOLERANCE) || + PNG_OUT_OF_RANGE(xy->redx, sRGB_xy.redx, sRGB_TOLERANCE) || + PNG_OUT_OF_RANGE(xy->redy, sRGB_xy.redy, sRGB_TOLERANCE) || + PNG_OUT_OF_RANGE(xy->greenx, sRGB_xy.greenx,sRGB_TOLERANCE) || + PNG_OUT_OF_RANGE(xy->greeny, sRGB_xy.greeny,sRGB_TOLERANCE) || + PNG_OUT_OF_RANGE(xy->bluex, sRGB_xy.bluex, sRGB_TOLERANCE) || + PNG_OUT_OF_RANGE(xy->bluey, sRGB_xy.bluey, sRGB_TOLERANCE)) + return 0; + return 1; +} + +/* Is the given gamma significantly different from sRGB? The test is the same + * one used in pngrtran.c when deciding whether to do gamma correction. The + * arithmetic optimizes the division by using the fact that the inverse of the + * file sRGB gamma is 2.2 + */ +static int +png_gamma_not_sRGB(png_fixed_point g) +{ + /* 1.6.47: use the same sanity checks as used in pngrtran.c */ + if (g < PNG_LIB_GAMMA_MIN || g > PNG_LIB_GAMMA_MAX) + return 0; /* Includes the uninitialized value 0 */ + + return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); +} + +/* Do the main body of a 'png_image_begin_read' function; read the PNG file + * header and fill in all the information. This is executed in a safe context, + * unlike the init routine above. + */ +static int +png_image_is_not_sRGB(png_const_structrp png_ptr) +{ + /* Does the colorspace **not** match sRGB? The flag is only set if the + * answer can be determined reliably. + * + * png_struct::chromaticities always exists since the simplified API + * requires rgb-to-gray. The mDCV, cICP and cHRM chunks may all set it to + * a non-sRGB value, so it needs to be checked but **only** if one of + * those chunks occured in the file. + */ + /* Highest priority: check to be safe. */ + if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV)) + return !chromaticities_match_sRGB(&png_ptr->chromaticities); + + /* If the image is marked as sRGB then it is... */ + if (png_has_chunk(png_ptr, sRGB)) + return 0; + + /* Last stop: cHRM, must check: */ + if (png_has_chunk(png_ptr, cHRM)) + return !chromaticities_match_sRGB(&png_ptr->chromaticities); + + /* Else default to sRGB */ + return 0; +} + +static int +png_image_read_header(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED + png_set_benign_errors(png_ptr, 1/*warn*/); +#endif + png_read_info(png_ptr, info_ptr); + + /* Do this the fast way; just read directly out of png_struct. */ + image->width = png_ptr->width; + image->height = png_ptr->height; + + { + png_uint_32 format = png_image_format(png_ptr); + + image->format = format; + + /* Greyscale images don't (typically) have colour space information and + * using it is pretty much impossible, so use sRGB for grayscale (it + * doesn't matter r==g==b so the transform is irrelevant.) + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && + png_image_is_not_sRGB(png_ptr)) + image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB; + } + + /* We need the maximum number of entries regardless of the format the + * application sets here. + */ + { + png_uint_32 cmap_entries; + + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + cmap_entries = 1U << png_ptr->bit_depth; + break; + + case PNG_COLOR_TYPE_PALETTE: + cmap_entries = (png_uint_32)png_ptr->num_palette; + break; + + default: + cmap_entries = 256; + break; + } + + if (cmap_entries > 256) + cmap_entries = 256; + + image->colormap_entries = cmap_entries; + } + + return 1; +} + +#ifdef PNG_STDIO_SUPPORTED +int PNGAPI +png_image_begin_read_from_stdio(png_imagep image, FILE *file) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_read_init(image) != 0) + { + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +int PNGAPI +png_image_begin_read_from_file(png_imagep image, const char *file_name) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "rb"); + + if (fp != NULL) + { + if (png_image_read_init(image) != 0) + { + image->opaque->png_ptr->io_ptr = fp; + image->opaque->owned_file = 1; + return png_safe_execute(image, png_image_read_header, image); + } + + /* Clean up: just the opened file. */ + (void)fclose(fp); + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_begin_read_from_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); + + return 0; +} +#endif /* STDIO */ + +static void PNGCBAPI +png_image_memory_read(png_structp png_ptr, png_bytep out, size_t need) +{ + if (png_ptr != NULL) + { + png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr); + if (image != NULL) + { + png_controlp cp = image->opaque; + if (cp != NULL) + { + png_const_bytep memory = cp->memory; + size_t size = cp->size; + + if (memory != NULL && size >= need) + { + memcpy(out, memory, need); + cp->memory = memory + need; + cp->size = size - need; + return; + } + + png_error(png_ptr, "read beyond end of data"); + } + } + + png_error(png_ptr, "invalid memory read"); + } +} + +int PNGAPI png_image_begin_read_from_memory(png_imagep image, + png_const_voidp memory, size_t size) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (memory != NULL && size > 0) + { + if (png_image_read_init(image) != 0) + { + /* Now set the IO functions to read from the memory buffer and + * store it into io_ptr. Again do this in-place to avoid calling a + * libpng function that requires error handling. + */ + image->opaque->memory = png_voidcast(png_const_bytep, memory); + image->opaque->size = size; + image->opaque->png_ptr->io_ptr = image; + image->opaque->png_ptr->read_data_fn = png_image_memory_read; + + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_memory: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +/* Utility function to skip chunks that are not used by the simplified image + * read functions and an appropriate macro to call it. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static void +png_image_skip_unused_chunks(png_structrp png_ptr) +{ + /* Prepare the reader to ignore all recognized chunks whose data will not + * be used, i.e., all chunks recognized by libpng except for those + * involved in basic image reading: + * + * IHDR, PLTE, IDAT, IEND + * + * Or image data handling: + * + * tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT. + * + * This provides a small performance improvement and eliminates any + * potential vulnerability to security problems in the unused chunks. + * + * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored + * too. This allows the simplified API to be compiled without iCCP support. + */ + { + static const png_byte chunks_to_process[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 99, 73, 67, 80, '\0', /* cICP */ + 103, 65, 77, 65, '\0', /* gAMA */ + 109, 68, 67, 86, '\0', /* mDCV */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 82, 71, 66, '\0', /* sRGB */ + }; + + /* Ignore unknown chunks and all other chunks except for the + * IHDR, PLTE, tRNS, IDAT, and IEND chunks. + */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, + NULL, -1); + + /* But do not ignore image data handling chunks */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT, + chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5); + } +} + +# define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p) +#else +# define PNG_SKIP_CHUNKS(p) ((void)0) +#endif /* HANDLE_AS_UNKNOWN */ + +/* The following macro gives the exact rounded answer for all values in the + * range 0..255 (it actually divides by 51.2, but the rounding still generates + * the correct numbers 0..5 + */ +#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8) + +/* Utility functions to make particular color-maps */ +static void +set_file_encoding(png_image_read_control *display) +{ + png_structrp png_ptr = display->image->opaque->png_ptr; + png_fixed_point g = png_resolve_file_gamma(png_ptr); + + /* PNGv3: the result may be 0 however the 'default_gamma' should have been + * set before this is called so zero is an error: + */ + if (g == 0) + png_error(png_ptr, "internal: default gamma not set"); + + if (png_gamma_significant(g) != 0) + { + if (png_gamma_not_sRGB(g) != 0) + { + display->file_encoding = P_FILE; + display->gamma_to_linear = png_reciprocal(g); + } + + else + display->file_encoding = P_sRGB; + } + + else + display->file_encoding = P_LINEAR8; +} + +static unsigned int +decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) +{ + if (encoding == P_FILE) /* double check */ + encoding = display->file_encoding; + + if (encoding == P_NOTSET) /* must be the file encoding */ + { + set_file_encoding(display); + encoding = display->file_encoding; + } + + switch (encoding) + { + case P_FILE: + value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); + break; + + case P_sRGB: + value = png_sRGB_table[value]; + break; + + case P_LINEAR: + break; + + case P_LINEAR8: + value *= 257; + break; + +#ifdef __GNUC__ + default: + png_error(display->image->opaque->png_ptr, + "unexpected encoding (internal error)"); +#endif + } + + return value; +} + +static png_uint_32 +png_colormap_compose(png_image_read_control *display, + png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, + png_uint_32 background, int encoding) +{ + /* The file value is composed on the background, the background has the given + * encoding and so does the result, the file is encoded with P_FILE and the + * file and alpha are 8-bit values. The (output) encoding will always be + * P_LINEAR or P_sRGB. + */ + png_uint_32 f = decode_gamma(display, foreground, foreground_encoding); + png_uint_32 b = decode_gamma(display, background, encoding); + + /* The alpha is always an 8-bit value (it comes from the palette), the value + * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires. + */ + f = f * alpha + b * (255-alpha); + + if (encoding == P_LINEAR) + { + /* Scale to 65535; divide by 255, approximately (in fact this is extremely + * accurate, it divides by 255.00000005937181414556, with no overflow.) + */ + f *= 257; /* Now scaled by 65535 */ + f += f >> 16; + f = (f+32768) >> 16; + } + + else /* P_sRGB */ + f = PNG_sRGB_FROM_LINEAR(f); + + return f; +} + +/* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must + * be 8-bit. + */ +static void +png_create_colormap_entry(png_image_read_control *display, + png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, + png_uint_32 alpha, int encoding) +{ + png_imagep image = display->image; + int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ? + P_LINEAR : P_sRGB; + int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && + (red != green || green != blue); + + if (ip > 255) + png_error(image->opaque->png_ptr, "color-map index out of range"); + + /* Update the cache with whether the file gamma is significantly different + * from sRGB. + */ + if (encoding == P_FILE) + { + if (display->file_encoding == P_NOTSET) + set_file_encoding(display); + + /* Note that the cached value may be P_FILE too, but if it is then the + * gamma_to_linear member has been set. + */ + encoding = display->file_encoding; + } + + if (encoding == P_FILE) + { + png_fixed_point g = display->gamma_to_linear; + + red = png_gamma_16bit_correct(red*257, g); + green = png_gamma_16bit_correct(green*257, g); + blue = png_gamma_16bit_correct(blue*257, g); + + if (convert_to_Y != 0 || output_encoding == P_LINEAR) + { + alpha *= 257; + encoding = P_LINEAR; + } + + else + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + encoding = P_sRGB; + } + } + + else if (encoding == P_LINEAR8) + { + /* This encoding occurs quite frequently in test cases because PngSuite + * includes a gAMA 1.0 chunk with most images. + */ + red *= 257; + green *= 257; + blue *= 257; + alpha *= 257; + encoding = P_LINEAR; + } + + else if (encoding == P_sRGB && + (convert_to_Y != 0 || output_encoding == P_LINEAR)) + { + /* The values are 8-bit sRGB values, but must be converted to 16-bit + * linear. + */ + red = png_sRGB_table[red]; + green = png_sRGB_table[green]; + blue = png_sRGB_table[blue]; + alpha *= 257; + encoding = P_LINEAR; + } + + /* This is set if the color isn't gray but the output is. */ + if (encoding == P_LINEAR) + { + if (convert_to_Y != 0) + { + /* NOTE: these values are copied from png_do_rgb_to_gray */ + png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green + + (png_uint_32)2366 * blue; + + if (output_encoding == P_LINEAR) + y = (y + 16384) >> 15; + + else + { + /* y is scaled by 32768, we need it scaled by 255: */ + y = (y + 128) >> 8; + y *= 255; + y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); + alpha = PNG_DIV257(alpha); + encoding = P_sRGB; + } + + blue = red = green = y; + } + + else if (output_encoding == P_sRGB) + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + alpha = PNG_DIV257(alpha); + encoding = P_sRGB; + } + } + + if (encoding != output_encoding) + png_error(image->opaque->png_ptr, "bad encoding (internal error)"); + + /* Store the value. */ + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif +# ifdef PNG_FORMAT_BGR_SUPPORTED + int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + if (output_encoding == P_LINEAR) + { + png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + /* The linear 16-bit values must be pre-multiplied by the alpha channel + * value, if less than 65535 (this is, effectively, composite on black + * if the alpha channel is removed.) + */ + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_uint_16)alpha; + /* FALLTHROUGH */ + + case 3: + if (alpha < 65535) + { + if (alpha > 0) + { + blue = (blue * alpha + 32767U)/65535U; + green = (green * alpha + 32767U)/65535U; + red = (red * alpha + 32767U)/65535U; + } + + else + red = green = blue = 0; + } + entry[afirst + (2 ^ bgr)] = (png_uint_16)blue; + entry[afirst + 1] = (png_uint_16)green; + entry[afirst + bgr] = (png_uint_16)red; + break; + + case 2: + entry[1 ^ afirst] = (png_uint_16)alpha; + /* FALLTHROUGH */ + + case 1: + if (alpha < 65535) + { + if (alpha > 0) + green = (green * alpha + 32767U)/65535U; + + else + green = 0; + } + entry[afirst] = (png_uint_16)green; + break; + + default: + break; + } + } + + else /* output encoding is P_sRGB */ + { + png_bytep entry = png_voidcast(png_bytep, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_byte)alpha; + /* FALLTHROUGH */ + case 3: + entry[afirst + (2 ^ bgr)] = (png_byte)blue; + entry[afirst + 1] = (png_byte)green; + entry[afirst + bgr] = (png_byte)red; + break; + + case 2: + entry[1 ^ afirst] = (png_byte)alpha; + /* FALLTHROUGH */ + case 1: + entry[afirst] = (png_byte)green; + break; + + default: + break; + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + } +} + +static int +make_gray_file_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, P_FILE); + + return (int)i; +} + +static int +make_gray_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB); + + return (int)i; +} +#define PNG_GRAY_COLORMAP_ENTRIES 256 + +static int +make_ga_colormap(png_image_read_control *display) +{ + unsigned int i, a; + + /* Alpha is retained, the output will be a color-map with entries + * selected by six levels of alpha. One transparent entry, 6 gray + * levels for all the intermediate alpha values, leaving 230 entries + * for the opaque grays. The color-map entries are the six values + * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the + * relevant entry. + * + * if (alpha > 229) // opaque + * { + * // The 231 entries are selected to make the math below work: + * base = 0; + * entry = (231 * gray + 128) >> 8; + * } + * else if (alpha < 26) // transparent + * { + * base = 231; + * entry = 0; + * } + * else // partially opaque + * { + * base = 226 + 6 * PNG_DIV51(alpha); + * entry = PNG_DIV51(gray); + * } + */ + i = 0; + while (i < 231) + { + unsigned int gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB); + } + + /* 255 is used here for the component values for consistency with the code + * that undoes premultiplication in pngwrite.c. + */ + png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB); + + for (a=1; a<5; ++a) + { + unsigned int g; + + for (g=0; g<6; ++g) + png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51, + P_sRGB); + } + + return (int)i; +} + +#define PNG_GA_COLORMAP_ENTRIES 256 + +static int +make_rgb_colormap(png_image_read_control *display) +{ + unsigned int i, r; + + /* Build a 6x6x6 opaque RGB cube */ + for (i=r=0; r<6; ++r) + { + unsigned int g; + + for (g=0; g<6; ++g) + { + unsigned int b; + + for (b=0; b<6; ++b) + png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255, + P_sRGB); + } + } + + return (int)i; +} + +#define PNG_RGB_COLORMAP_ENTRIES 216 + +/* Return a palette index to the above palette given three 8-bit sRGB values. */ +#define PNG_RGB_INDEX(r,g,b) \ + ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b))) + +static int +png_image_read_colormap(png_voidp argument) +{ + png_image_read_control *display = + png_voidcast(png_image_read_control*, argument); + png_imagep image = display->image; + + png_structrp png_ptr = image->opaque->png_ptr; + png_uint_32 output_format = image->format; + int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ? + P_LINEAR : P_sRGB; + + unsigned int cmap_entries; + unsigned int output_processing; /* Output processing option */ + unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */ + + /* Background information; the background color and the index of this color + * in the color-map if it exists (else 256). + */ + unsigned int background_index = 256; + png_uint_32 back_r, back_g, back_b; + + /* Flags to accumulate things that need to be done to the input. */ + int expand_tRNS = 0; + + /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is + * very difficult to do, the results look awful, and it is difficult to see + * what possible use it is because the application can't control the + * color-map. + */ + if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 || + png_ptr->num_trans > 0) /* alpha in input */ && + ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */) + { + if (output_encoding == P_LINEAR) /* compose on black */ + back_b = back_g = back_r = 0; + + else if (display->background == NULL /* no way to remove it */) + png_error(png_ptr, + "background color must be supplied to remove alpha/transparency"); + + /* Get a copy of the background color (this avoids repeating the checks + * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the + * output format. + */ + else + { + back_g = display->background->green; + if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0) + { + back_r = display->background->red; + back_b = display->background->blue; + } + else + back_b = back_r = back_g; + } + } + + else if (output_encoding == P_LINEAR) + back_b = back_r = back_g = 65535; + + else + back_b = back_r = back_g = 255; + + /* Default the input file gamma if required - this is necessary because + * libpng assumes that if no gamma information is present the data is in the + * output format, but the simplified API deduces the gamma from the input + * format. The 'default' gamma value is also set by png_set_alpha_mode, but + * this is happening before any such call, so: + * + * TODO: should be an internal API and all this code should be copied into a + * single common gamma+colorspace file. + */ + if (png_ptr->bit_depth == 16 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + png_ptr->default_gamma = PNG_GAMMA_LINEAR; + + else + png_ptr->default_gamma = PNG_GAMMA_sRGB_INVERSE; + + /* Decide what to do based on the PNG color type of the input data. The + * utility function png_create_colormap_entry deals with most aspects of the + * output transformations; this code works out how to produce bytes of + * color-map entries from the original format. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth <= 8) + { + /* There at most 256 colors in the output, regardless of + * transparency. + */ + unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0; + + cmap_entries = 1U << png_ptr->bit_depth; + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "gray[8] color-map: too few entries"); + + step = 255 / (cmap_entries - 1); + output_processing = PNG_CMAP_NONE; + + /* If there is a tRNS chunk then this either selects a transparent + * value or, if the output has no alpha, the background color. + */ + if (png_ptr->num_trans > 0) + { + trans = png_ptr->trans_color.gray; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) + back_alpha = output_encoding == P_LINEAR ? 65535 : 255; + } + + /* png_create_colormap_entry just takes an RGBA and writes the + * corresponding color-map entry using the format from 'image', + * including the required conversion to sRGB or linear as + * appropriate. The input values are always either sRGB (if the + * gamma correction flag is 0) or 0..255 scaled file encoded values + * (if the function must gamma correct them). + */ + for (i=val=0; ibit_depth < 8) + png_set_packing(png_ptr); + } + + else /* bit depth is 16 */ + { + /* The 16-bit input values can be converted directly to 8-bit gamma + * encoded values; however, if a tRNS chunk is present 257 color-map + * entries are required. This means that the extra entry requires + * special processing; add an alpha channel, sacrifice gray level + * 254 and convert transparent (alpha==0) entries to that. + * + * Use libpng to chop the data to 8 bits. Convert it to sRGB at the + * same time to minimize quality loss. If a tRNS chunk is present + * this means libpng must handle it too; otherwise it is impossible + * to do the exact match on the 16-bit value. + * + * If the output has no alpha channel *and* the background color is + * gray then it is possible to let libpng handle the substitution by + * ensuring that the corresponding gray level matches the background + * color exactly. + */ + data_encoding = P_sRGB; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray[16] color-map: too few entries"); + + cmap_entries = (unsigned int)make_gray_colormap(display); + + if (png_ptr->num_trans > 0) + { + unsigned int back_alpha; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + back_alpha = 0; + + else + { + if (back_r == back_g && back_g == back_b) + { + /* Background is gray; no special processing will be + * required. + */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry + * matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, P_LINEAR); + } + + /* The background passed to libpng, however, must be the + * sRGB value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: does this work without expanding tRNS to alpha? + * It should be the color->gray case below apparently + * doesn't. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + break; + } +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ + back_alpha = 255; +#else + back_alpha = output_encoding == P_LINEAR ? 65535 : 255; +#endif + } + + /* output_processing means that the libpng-processed row will be + * 8-bit GA and it has to be processing to single byte color-map + * values. Entry 254 is replaced by either a completely + * transparent entry or by the background color at full + * precision (and the background color is not a simple gray + * level in this case.) + */ + expand_tRNS = 1; + output_processing = PNG_CMAP_TRANS; + background_index = 254; + + /* And set (overwrite) color-map entry 254 to the actual + * background color at full precision. + */ + png_create_colormap_entry(display, 254, back_r, back_g, back_b, + back_alpha, output_encoding); + } + + else + output_processing = PNG_CMAP_NONE; + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + /* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum + * of 65536 combinations. If, however, the alpha channel is to be + * removed there are only 256 possibilities if the background is gray. + * (Otherwise there is a subset of the 65536 possibilities defined by + * the triangle between black, white and the background color.) + * + * Reduce 16-bit files to 8-bit and sRGB encode the result. No need to + * worry about tRNS matching - tRNS is ignored if there is an alpha + * channel. + */ + data_encoding = P_sRGB; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray+alpha color-map: too few entries"); + + cmap_entries = (unsigned int)make_ga_colormap(display); + + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else /* alpha is removed */ + { + /* Alpha must be removed as the PNG data is processed when the + * background is a color because the G and A channels are + * independent and the vector addition (non-parallel vectors) is a + * 2-D problem. + * + * This can be reduced to the same algorithm as above by making a + * colormap containing gray levels (for the opaque grays), a + * background entry (for a transparent pixel) and a set of four six + * level color values, one set for each intermediate alpha value. + * See the comments in make_ga_colormap for how this works in the + * per-pixel processing. + * + * If the background is gray, however, we only need a 256 entry gray + * level color map. It is sufficient to make the entry generated + * for the background color be exactly the color specified. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 || + (back_r == back_g && back_g == back_b)) + { + /* Background is gray; no special processing will be required. */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray-alpha color-map: too few entries"); + + cmap_entries = (unsigned int)make_gray_colormap(display); + + if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, P_LINEAR); + } + + /* The background passed to libpng, however, must be the sRGB + * value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + } + + else + { + png_uint_32 i, a; + + /* This is the same as png_make_ga_colormap, above, except that + * the entries are all opaque. + */ + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "ga-alpha color-map: too few entries"); + + i = 0; + while (i < 231) + { + png_uint_32 gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, + 255, P_sRGB); + } + + /* NOTE: this preserves the full precision of the application + * background color. + */ + background_index = i; + png_create_colormap_entry(display, i++, back_r, back_g, back_b, +#ifdef __COVERITY__ + /* Coverity claims that output_encoding + * cannot be 2 (P_LINEAR) here. + */ 255U, +#else + output_encoding == P_LINEAR ? 65535U : 255U, +#endif + output_encoding); + + /* For non-opaque input composite on the sRGB background - this + * requires inverting the encoding for each component. The input + * is still converted to the sRGB encoding because this is a + * reasonable approximate to the logarithmic curve of human + * visual sensitivity, at least over the narrow range which PNG + * represents. Consequently 'G' is always sRGB encoded, while + * 'A' is linear. We need the linear background colors. + */ + if (output_encoding == P_sRGB) /* else already linear */ + { + /* This may produce a value not exactly matching the + * background, but that's ok because these numbers are only + * used when alpha != 0 + */ + back_r = png_sRGB_table[back_r]; + back_g = png_sRGB_table[back_g]; + back_b = png_sRGB_table[back_b]; + } + + for (a=1; a<5; ++a) + { + unsigned int g; + + /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled + * by an 8-bit alpha value (0..255). + */ + png_uint_32 alpha = 51 * a; + png_uint_32 back_rx = (255-alpha) * back_r; + png_uint_32 back_gx = (255-alpha) * back_g; + png_uint_32 back_bx = (255-alpha) * back_b; + + for (g=0; g<6; ++g) + { + png_uint_32 gray = png_sRGB_table[g*51] * alpha; + + png_create_colormap_entry(display, i++, + PNG_sRGB_FROM_LINEAR(gray + back_rx), + PNG_sRGB_FROM_LINEAR(gray + back_gx), + PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB); + } + } + + cmap_entries = i; + output_processing = PNG_CMAP_GA; + } + } + break; + + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + /* Exclude the case where the output is gray; we can always handle this + * with the cases above. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0) + { + /* The color-map will be grayscale, so we may as well convert the + * input RGB values to a simple grayscale and use the grayscale + * code above. + * + * NOTE: calling this apparently damages the recognition of the + * transparent color in background color handling; call + * png_set_tRNS_to_alpha before png_set_background_fixed. + */ + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1, + -1); + data_encoding = P_sRGB; + + /* The output will now be one or two 8-bit gray or gray+alpha + * channels. The more complex case arises when the input has alpha. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + (output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Both input and output have an alpha channel, so no background + * processing is required; just map the GA bytes to the right + * color-map entry. + */ + expand_tRNS = 1; + + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[ga] color-map: too few entries"); + + cmap_entries = (unsigned int)make_ga_colormap(display); + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else + { + const png_fixed_point gamma = png_resolve_file_gamma(png_ptr); + + /* Either the input or the output has no alpha channel, so there + * will be no non-opaque pixels in the color-map; it will just be + * grayscale. + */ + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[gray] color-map: too few entries"); + + /* Ideally this code would use libpng to do the gamma correction, + * but if an input alpha channel is to be removed we will hit the + * libpng bug in gamma+compose+rgb-to-gray (the double gamma + * correction bug). Fix this by dropping the gamma correction in + * this case and doing it in the palette; this will result in + * duplicate palette entries, but that's better than the + * alternative of double gamma correction. + * + * NOTE: PNGv3: check the resolved result of all the potentially + * different colour space chunks. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + png_gamma_not_sRGB(gamma) != 0) + { + cmap_entries = (unsigned int)make_gray_file_colormap(display); + data_encoding = P_FILE; + } + + else + cmap_entries = (unsigned int)make_gray_colormap(display); + + /* But if the input has alpha or transparency it must be removed + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + png_color_16 c; + png_uint_32 gray = back_g; + + /* We need to ensure that the application background exists in + * the colormap and that completely transparent pixels map to + * it. Achieve this simply by ensuring that the entry + * selected for the background really is the background color. + */ + if (data_encoding == P_FILE) /* from the fixup above */ + { + /* The app supplied a gray which is in output_encoding, we + * need to convert it to a value of the input (P_FILE) + * encoding then set this palette entry to the required + * output encoding. + */ + if (output_encoding == P_sRGB) + gray = png_sRGB_table[gray]; /* now P_LINEAR */ + + gray = PNG_DIV257(png_gamma_16bit_correct(gray, gamma)); + /* now P_FILE */ + + /* And make sure the corresponding palette entry contains + * exactly the required sRGB value. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, output_encoding); + } + + else if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, P_LINEAR); + } + + /* The background passed to libpng, however, must be the + * output (normally sRGB) value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: the following is apparently a bug in libpng. Without + * it the transparent color recognition in + * png_set_background_fixed seems to go wrong. + */ + expand_tRNS = 1; + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + output_processing = PNG_CMAP_NONE; + } + } + + else /* output is color */ + { + /* We could use png_quantize here so long as there is no transparent + * color or alpha; png_quantize ignores alpha. Easier overall just + * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube. + * Consequently we always want libpng to produce sRGB data. + */ + data_encoding = P_sRGB; + + /* Is there any transparency or alpha? */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + /* Is there alpha in the output too? If so all four channels are + * processed into a special RGB cube with alpha support. + */ + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_uint_32 r; + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb+alpha color-map: too few entries"); + + cmap_entries = (unsigned int)make_rgb_colormap(display); + + /* Add a transparent entry. */ + png_create_colormap_entry(display, cmap_entries, 255, 255, + 255, 0, P_sRGB); + + /* This is stored as the background index for the processing + * algorithm. + */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with alpha 0.5. */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + png_uint_32 g; + + for (g=0; g<256; g = (g << 1) | 0x7f) + { + png_uint_32 b; + + /* This generates components with the values 0, 127 and + * 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + r, g, b, 128, P_sRGB); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else + { + /* Alpha/transparency must be removed. The background must + * exist in the color map (achieved by setting adding it after + * the 666 color-map). If the standard processing code will + * pick up this entry automatically that's all that is + * required; libpng can be called to do the background + * processing. + */ + unsigned int sample_size = + PNG_IMAGE_SAMPLE_SIZE(output_format); + png_uint_32 r, g, b; /* sRGB background */ + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb-alpha color-map: too few entries"); + + cmap_entries = (unsigned int)make_rgb_colormap(display); + + png_create_colormap_entry(display, cmap_entries, back_r, + back_g, back_b, 0/*unused*/, output_encoding); + + if (output_encoding == P_LINEAR) + { + r = PNG_sRGB_FROM_LINEAR(back_r * 255); + g = PNG_sRGB_FROM_LINEAR(back_g * 255); + b = PNG_sRGB_FROM_LINEAR(back_b * 255); + } + + else + { + r = back_r; + g = back_g; + b = back_g; + } + + /* Compare the newly-created color-map entry with the one the + * PNG_CMAP_RGB algorithm will use. If the two entries don't + * match, add the new one and set this as the background + * index. + */ + if (memcmp((png_const_bytep)display->colormap + + sample_size * cmap_entries, + (png_const_bytep)display->colormap + + sample_size * PNG_RGB_INDEX(r,g,b), + sample_size) != 0) + { + /* The background color must be added. */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with created by composing with + * the background at alpha 0.5. + */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + for (g=0; g<256; g = (g << 1) | 0x7f) + { + /* This generates components with the values 0, 127 + * and 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + png_colormap_compose(display, r, P_sRGB, 128, + back_r, output_encoding), + png_colormap_compose(display, g, P_sRGB, 128, + back_g, output_encoding), + png_colormap_compose(display, b, P_sRGB, 128, + back_b, output_encoding), + 0/*unused*/, output_encoding); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else /* background color is in the standard color-map */ + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = (png_uint_16)back_r; + c.gray = c.green = (png_uint_16)back_g; + c.blue = (png_uint_16)back_b; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_RGB; + } + } + } + + else /* no alpha or transparency in the input */ + { + /* Alpha in the output is irrelevant, simply map the opaque input + * pixels to the 6x6x6 color-map. + */ + if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb color-map: too few entries"); + + cmap_entries = (unsigned int)make_rgb_colormap(display); + output_processing = PNG_CMAP_RGB; + } + } + break; + + case PNG_COLOR_TYPE_PALETTE: + /* It's already got a color-map. It may be necessary to eliminate the + * tRNS entries though. + */ + { + unsigned int num_trans = png_ptr->num_trans; + png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL; + png_const_colorp colormap = png_ptr->palette; + int do_background = trans != NULL && + (output_format & PNG_FORMAT_FLAG_ALPHA) == 0; + unsigned int i; + + /* Just in case: */ + if (trans == NULL) + num_trans = 0; + + output_processing = PNG_CMAP_NONE; + data_encoding = P_FILE; /* Don't change from color-map indices */ + cmap_entries = (unsigned int)png_ptr->num_palette; + if (cmap_entries > 256) + cmap_entries = 256; + + if (cmap_entries > (unsigned int)image->colormap_entries) + png_error(png_ptr, "palette color-map: too few entries"); + + for (i=0; i < cmap_entries; ++i) + { + if (do_background != 0 && i < num_trans && trans[i] < 255) + { + if (trans[i] == 0) + png_create_colormap_entry(display, i, back_r, back_g, + back_b, 0, output_encoding); + + else + { + /* Must compose the PNG file color in the color-map entry + * on the sRGB color in 'back'. + */ + png_create_colormap_entry(display, i, + png_colormap_compose(display, colormap[i].red, + P_FILE, trans[i], back_r, output_encoding), + png_colormap_compose(display, colormap[i].green, + P_FILE, trans[i], back_g, output_encoding), + png_colormap_compose(display, colormap[i].blue, + P_FILE, trans[i], back_b, output_encoding), + output_encoding == P_LINEAR ? trans[i] * 257U : + trans[i], + output_encoding); + } + } + + else + png_create_colormap_entry(display, i, colormap[i].red, + colormap[i].green, colormap[i].blue, + i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/); + } + + /* The PNG data may have indices packed in fewer than 8 bits, it + * must be expanded if so. + */ + if (png_ptr->bit_depth < 8) + png_set_packing(png_ptr); + } + break; + + default: + png_error(png_ptr, "invalid PNG color type"); + /*NOT REACHED*/ + } + + /* Now deal with the output processing */ + if (expand_tRNS != 0 && png_ptr->num_trans > 0 && + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) + png_set_tRNS_to_alpha(png_ptr); + + switch (data_encoding) + { + case P_sRGB: + /* Change to 8-bit sRGB */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); + /* FALLTHROUGH */ + + case P_FILE: + if (png_ptr->bit_depth > 8) + png_set_scale_16(png_ptr); + break; + +#ifdef __GNUC__ + default: + png_error(png_ptr, "bad data option (internal error)"); +#endif + } + + if (cmap_entries > 256 || cmap_entries > image->colormap_entries) + png_error(png_ptr, "color map overflow (BAD internal error)"); + + image->colormap_entries = cmap_entries; + + /* Double check using the recorded background index */ + switch (output_processing) + { + case PNG_CMAP_NONE: + if (background_index != PNG_CMAP_NONE_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_GA: + if (background_index != PNG_CMAP_GA_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_TRANS: + if (background_index >= cmap_entries || + background_index != PNG_CMAP_TRANS_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB: + if (background_index != PNG_CMAP_RGB_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB_ALPHA: + if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND) + goto bad_background; + break; + + default: + png_error(png_ptr, "bad processing option (internal error)"); + + bad_background: + png_error(png_ptr, "bad background index (internal error)"); + } + + display->colormap_processing = (int)output_processing; + + return 1/*ok*/; +} + +/* The final part of the color-map read called from png_image_finish_read. */ +static int +png_image_read_and_map(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + /* Called when the libpng data must be transformed into the color-mapped + * form. There is a local row buffer in display->local and this routine must + * do the interlace handling. + */ + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int proc = display->colormap_processing; + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read read the libpng data into the temporary buffer. */ + png_read_row(png_ptr, inrow, NULL); + + /* Now process the row according to the processing option, note + * that the caller verifies that the format of the libpng output + * data is as required. + */ + outrow += startx; + switch (proc) + { + case PNG_CMAP_GA: + for (; outrow < end_row; outrow += stepx) + { + /* The data is always in the PNG order */ + unsigned int gray = *inrow++; + unsigned int alpha = *inrow++; + unsigned int entry; + + /* NOTE: this code is copied as a comment in + * make_ga_colormap above. Please update the + * comment if you change this code! + */ + if (alpha > 229) /* opaque */ + { + entry = (231 * gray + 128) >> 8; + } + else if (alpha < 26) /* transparent */ + { + entry = 231; + } + else /* partially opaque */ + { + entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray); + } + + *outrow = (png_byte)entry; + } + break; + + case PNG_CMAP_TRANS: + for (; outrow < end_row; outrow += stepx) + { + png_byte gray = *inrow++; + png_byte alpha = *inrow++; + + if (alpha == 0) + *outrow = PNG_CMAP_TRANS_BACKGROUND; + + else if (gray != PNG_CMAP_TRANS_BACKGROUND) + *outrow = gray; + + else + *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1); + } + break; + + case PNG_CMAP_RGB: + for (; outrow < end_row; outrow += stepx) + { + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); + inrow += 3; + } + break; + + case PNG_CMAP_RGB_ALPHA: + for (; outrow < end_row; outrow += stepx) + { + unsigned int alpha = inrow[3]; + + /* Because the alpha entries only hold alpha==0.5 values + * split the processing at alpha==0.25 (64) and 0.75 + * (196). + */ + + if (alpha >= 196) + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], + inrow[2]); + + else if (alpha < 64) + *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND; + + else + { + /* Likewise there are three entries for each of r, g + * and b. We could select the entry by popcount on + * the top two bits on those architectures that + * support it, this is what the code below does, + * crudely. + */ + unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1; + + /* Here are how the values map: + * + * 0x00 .. 0x3f -> 0 + * 0x40 .. 0xbf -> 1 + * 0xc0 .. 0xff -> 2 + * + * So, as above with the explicit alpha checks, the + * breakpoints are at 64 and 196. + */ + if (inrow[0] & 0x80) back_i += 9; /* red */ + if (inrow[0] & 0x40) back_i += 9; + if (inrow[0] & 0x80) back_i += 3; /* green */ + if (inrow[0] & 0x40) back_i += 3; + if (inrow[0] & 0x80) back_i += 1; /* blue */ + if (inrow[0] & 0x40) back_i += 1; + + *outrow = (png_byte)back_i; + } + + inrow += 4; + } + break; + + default: + break; + } + } + } + } + + return 1; +} + +static int +png_image_read_colormapped(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_controlp control = image->opaque; + png_structrp png_ptr = control->png_ptr; + png_inforp info_ptr = control->info_ptr; + + int passes = 0; /* As a flag */ + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + */ + if (display->colormap_processing == PNG_CMAP_NONE) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + /* The expected output can be deduced from the colormap_processing option. */ + switch (display->colormap_processing) + { + case PNG_CMAP_NONE: + /* Output must be one channel and one byte per pixel, the output + * encoding can be anything. + */ + if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY) && + info_ptr->bit_depth == 8) + break; + + goto bad_output; + + case PNG_CMAP_TRANS: + case PNG_CMAP_GA: + /* Output must be two channels and the 'G' one must be sRGB, the latter + * can be checked with an exact number because it should have been set + * to this number above! + */ + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 256) + break; + + goto bad_output; + + case PNG_CMAP_RGB: + /* Output must be 8-bit sRGB encoded RGB */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 216) + break; + + goto bad_output; + + case PNG_CMAP_RGB_ALPHA: + /* Output must be 8-bit sRGB encoded RGBA */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 244 /* 216 + 1 + 27 */) + break; + + goto bad_output; + + default: + bad_output: + png_error(png_ptr, "bad color-map processing (internal error)"); + } + + /* Now read the rows. Do this here if it is possible to read directly into + * the output buffer, otherwise allocate a local row buffer of the maximum + * size libpng requires and call the relevant processing routine safely. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (passes == 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_and_map, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + for (; y > 0; --y) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +/* Just the row reading part of png_image_read. */ +static int +png_image_read_composite(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + ptrdiff_t step_row = display->row_bytes; + unsigned int channels = + (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * channels; + stepx = PNG_PASS_COL_OFFSET(pass) * channels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = channels; + stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow; + png_const_bytep end_row; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + outrow = png_voidcast(png_bytep, display->first_row); + outrow += y * step_row; + end_row = outrow + width * channels; + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[channels]; + + if (alpha > 0) /* else no change to the output */ + { + unsigned int c; + + for (c=0; cimage; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int pass, passes; + + /* Double check the convoluted logic below. We expect to get here with + * libpng doing rgb to gray and gamma correction but background processing + * left to the png_image_read_background function. The rows libpng produce + * might be 8 or 16-bit but should always have two channels; gray plus alpha. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) + png_error(png_ptr, "lost rgb to gray"); + + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_error(png_ptr, "unexpected compose"); + + if (png_get_channels(png_ptr, info_ptr) != 2) + png_error(png_ptr, "lost/gained channels"); + + /* Expect the 8-bit case to always remove the alpha channel */ + if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_error(png_ptr, "unexpected 8-bit transformation"); + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + /* Use direct access to info_ptr here because otherwise the simplified API + * would require PNG_EASY_ACCESS_SUPPORTED (just for this.) Note this is + * checking the value after libpng expansions, not the original value in the + * PNG. + */ + switch (info_ptr->bit_depth) + { + case 8: + /* 8-bit sRGB gray values with an alpha channel; the alpha channel is + * to be removed by composing on a background: either the row if + * display->background is NULL or display->background->green if not. + * Unlike the code above ALPHA_OPTIMIZED has *not* been done. + */ + { + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + if (display->background == NULL) + { + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else no change to the output */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + /* Since PNG_OPTIMIZED_ALPHA was not set it is + * necessary to invert the sRGB transfer + * function and multiply the alpha out. + */ + component = png_sRGB_table[component] * alpha; + component += png_sRGB_table[outrow[0]] * + (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + inrow += 2; /* gray and alpha channel */ + } + } + } + + else /* constant background value */ + { + png_byte background8 = display->background->green; + png_uint_16 background = png_sRGB_table[background8]; + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else use background */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + component = png_sRGB_table[component] * alpha; + component += background * (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + else + outrow[0] = background8; + + inrow += 2; /* gray and alpha channel */ + } + } + } + } + } + break; + + case 16: + /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must + * still be done and, maybe, the alpha channel removed. This code also + * handles the alpha-first option. + */ + { + png_uint_16p first_row = png_voidcast(png_uint_16p, + display->first_row); + /* The division by two is safe because the caller passed in a + * stride which was multiplied by 2 (below) to get row_bytes. + */ + ptrdiff_t step_row = display->row_bytes / 2; + unsigned int preserve_alpha = (image->format & + PNG_FORMAT_FLAG_ALPHA) != 0; + unsigned int outchannels = 1U+preserve_alpha; + int swap_alpha = 0; + +# ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED + if (preserve_alpha != 0 && + (image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + swap_alpha = 1; +# endif + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + /* The 'x' start and step are adjusted to output components here. + */ + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * outchannels; + stepx = PNG_PASS_COL_OFFSET(pass) * outchannels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = outchannels; + stepy = 1; + } + + for (; ylocal_row), NULL); + inrow = png_voidcast(png_const_uint_16p, display->local_row); + + /* Now do the pre-multiplication on each pixel in this row. + */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_uint_32 component = inrow[0]; + png_uint_16 alpha = inrow[1]; + + if (alpha > 0) /* else 0 */ + { + if (alpha < 65535) /* else just use component */ + { + component *= alpha; + component += 32767; + component /= 65535; + } + } + + else + component = 0; + + outrow[swap_alpha] = (png_uint_16)component; + if (preserve_alpha != 0) + outrow[1 ^ swap_alpha] = alpha; + + inrow += 2; /* components and alpha channel */ + } + } + } + } + break; + +#ifdef __GNUC__ + default: + png_error(png_ptr, "unexpected bit depth"); +#endif + } + + return 1; +} + +/* The guts of png_image_finish_read as a png_safe_execute callback. */ +static int +png_image_read_direct(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_uint_32 format = image->format; + int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; + int do_local_compose = 0; + int do_local_background = 0; /* to avoid double gamma correction bug */ + int passes = 0; + + /* Add transforms to ensure the correct output format is produced then check + * that the required implementation support is there. Always expand; always + * need 8 bits minimum, no palette and expanded tRNS. + */ + png_set_expand(png_ptr); + + /* Now check the format to see if it was modified. */ + { + png_uint_32 base_format = png_image_format(png_ptr) & + ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */; + png_uint_32 change = format ^ base_format; + png_fixed_point output_gamma; + int mode; /* alpha mode */ + + /* Do this first so that we have a record if rgb to gray is happening. */ + if ((change & PNG_FORMAT_FLAG_COLOR) != 0) + { + /* gray<->color transformation required. */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_gray_to_rgb(png_ptr); + + else + { + /* libpng can't do both rgb to gray and + * background/pre-multiplication if there is also significant gamma + * correction, because both operations require linear colors and + * the code only supports one transform doing the gamma correction. + * Handle this by doing the pre-multiplication or background + * operation in this code, if necessary. + * + * TODO: fix this by rewriting pngrtran.c (!) + * + * For the moment (given that fixing this in pngrtran.c is an + * enormous change) 'do_local_background' is used to indicate that + * the problem exists. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + do_local_background = 1/*maybe*/; + + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, + PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); + } + + change &= ~PNG_FORMAT_FLAG_COLOR; + } + + /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise. + */ + { + /* This is safe but should no longer be necessary as + * png_ptr->default_gamma should have been set after the + * info-before-IDAT was read in png_image_read_header. + * + * TODO: 1.8: remove this and see what happens. + */ + png_fixed_point input_gamma_default; + + if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + input_gamma_default = PNG_GAMMA_LINEAR; + else + input_gamma_default = PNG_DEFAULT_sRGB; + + /* Call png_set_alpha_mode to set the default for the input gamma; the + * output gamma is set by a second call below. + */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default); + } + + if (linear != 0) + { + /* If there *is* an alpha channel in the input it must be multiplied + * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + mode = PNG_ALPHA_STANDARD; /* associated alpha */ + + else + mode = PNG_ALPHA_PNG; + + output_gamma = PNG_GAMMA_LINEAR; + } + + else + { + mode = PNG_ALPHA_PNG; + output_gamma = PNG_DEFAULT_sRGB; + } + + if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) + { + mode = PNG_ALPHA_OPTIMIZED; + change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA; + } + + /* If 'do_local_background' is set check for the presence of gamma + * correction; this is part of the work-round for the libpng bug + * described above. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background != 0) + { + png_fixed_point gtest; + + /* This is 'png_gamma_threshold' from pngrtran.c; the test used for + * gamma correction, the screen gamma hasn't been set on png_struct + * yet; it's set below. png_struct::gamma, however, is set to the + * final value. + */ + if (png_muldiv(>est, output_gamma, + png_resolve_file_gamma(png_ptr), PNG_FP_1) != 0 && + png_gamma_significant(gtest) == 0) + do_local_background = 0; + + else if (mode == PNG_ALPHA_STANDARD) + { + do_local_background = 2/*required*/; + mode = PNG_ALPHA_PNG; /* prevent libpng doing it */ + } + + /* else leave as 1 for the checks below */ + } + + /* If the bit-depth changes then handle that here. */ + if ((change & PNG_FORMAT_FLAG_LINEAR) != 0) + { + if (linear != 0 /*16-bit output*/) + png_set_expand_16(png_ptr); + + else /* 8-bit output */ + png_set_scale_16(png_ptr); + + change &= ~PNG_FORMAT_FLAG_LINEAR; + } + + /* Now the background/alpha channel changes. */ + if ((change & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Removing an alpha channel requires composition for the 8-bit + * formats; for the 16-bit it is already done, above, by the + * pre-multiplication and the channel just needs to be stripped. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* If RGB->gray is happening the alpha channel must be left and the + * operation completed locally. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background != 0) + do_local_background = 2/*required*/; + + /* 16-bit output: just remove the channel */ + else if (linear != 0) /* compose on black (well, pre-multiply) */ + png_set_strip_alpha(png_ptr); + + /* 8-bit output: do an appropriate compose */ + else if (display->background != NULL) + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = display->background->red; + c.green = display->background->green; + c.blue = display->background->blue; + c.gray = display->background->green; + + /* This is always an 8-bit sRGB value, using the 'green' channel + * for gray is much better than calculating the luminance here; + * we can get off-by-one errors in that calculation relative to + * the app expectations and that will show up in transparent + * pixels. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + else /* compose on row: implemented below. */ + { + do_local_compose = 1; + /* This leaves the alpha channel in the output, so it has to be + * removed by the code below. Set the encoding to the 'OPTIMIZE' + * one so the code only has to hack on the pixels that require + * composition. + */ + mode = PNG_ALPHA_OPTIMIZED; + } + } + + else /* output needs an alpha channel */ + { + /* This is tricky because it happens before the swap operation has + * been accomplished; however, the swap does *not* swap the added + * alpha channel (weird API), so it must be added in the correct + * place. + */ + png_uint_32 filler; /* opaque filler */ + int where; + + if (linear != 0) + filler = 65535; + + else + filler = 255; + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + where = PNG_FILLER_BEFORE; + change &= ~PNG_FORMAT_FLAG_AFIRST; + } + + else +#endif + where = PNG_FILLER_AFTER; + + png_set_add_alpha(png_ptr, filler, where); + } + + /* This stops the (irrelevant) call to swap_alpha below. */ + change &= ~PNG_FORMAT_FLAG_ALPHA; + } + + /* Now set the alpha mode correctly; this is always done, even if there is + * no alpha channel in either the input or the output because it correctly + * sets the output gamma. + */ + png_set_alpha_mode_fixed(png_ptr, mode, output_gamma); + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if ((change & PNG_FORMAT_FLAG_BGR) != 0) + { + /* Check only the output format; PNG is never BGR; don't do this if + * the output is gray, but fix up the 'format' value in that case. + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + + else + format &= ~PNG_FORMAT_FLAG_BGR; + + change &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((change & PNG_FORMAT_FLAG_AFIRST) != 0) + { + /* Only relevant if there is an alpha channel - it's particularly + * important to handle this correctly because do_local_compose may + * be set above and then libpng will keep the alpha channel for this + * code to remove. + */ + if ((format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Disable this if doing a local background, + * TODO: remove this when local background is no longer required. + */ + if (do_local_background != 2) + png_set_swap_alpha(png_ptr); + } + + else + format &= ~PNG_FORMAT_FLAG_AFIRST; + + change &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If the *output* is 16-bit then we need to check for a byte-swap on this + * architecture. + */ + if (linear != 0) + { + png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + + /* If change is not now 0 some transformation is missing - error out. */ + if (change != 0) + png_error(png_ptr, "png_read_image: unsupported transformation"); + } + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + * + * TODO: remove the do_local_background fixup below. + */ + if (do_local_compose == 0 && do_local_background != 2) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + { + png_uint_32 info_format = 0; + + if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + info_format |= PNG_FORMAT_FLAG_COLOR; + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + /* do_local_compose removes this channel below. */ + if (do_local_compose == 0) + { + /* do_local_background does the same if required. */ + if (do_local_background != 2 || + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + info_format |= PNG_FORMAT_FLAG_ALPHA; + } + } + + else if (do_local_compose != 0) /* internal error */ + png_error(png_ptr, "png_image_read: alpha channel lost"); + + if ((format & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) { + info_format |= PNG_FORMAT_FLAG_ASSOCIATED_ALPHA; + } + + if (info_ptr->bit_depth == 16) + info_format |= PNG_FORMAT_FLAG_LINEAR; + +#ifdef PNG_FORMAT_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + info_format |= PNG_FORMAT_FLAG_BGR; +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (do_local_background == 2) + { + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + info_format |= PNG_FORMAT_FLAG_AFIRST; + } + + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 || + ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 && + (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0)) + { + if (do_local_background == 2) + png_error(png_ptr, "unexpected alpha swap transformation"); + + info_format |= PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* This is actually an internal error. */ + if (info_format != format) + png_error(png_ptr, "png_read_image: invalid transformations"); + } + + /* Now read the rows. If do_local_compose is set then it is necessary to use + * a local row buffer. The output will be GA, RGBA or BGRA and must be + * converted to G, RGB or BGR as appropriate. The 'local_row' member of the + * display acts as a flag. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= 2; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (do_local_compose != 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_composite, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else if (do_local_background == 2) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_background, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + for (; y > 0; --y) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +int PNGAPI +png_image_finish_read(png_imagep image, png_const_colorp background, + void *buffer, png_int_32 row_stride, void *colormap) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + /* Check for row_stride overflow. This check is not performed on the + * original PNG format because it may not occur in the output PNG format + * and libpng deals with the issues of reading the original. + */ + unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); + + /* The following checks just the 'row_stride' calculation to ensure it + * fits in a signed 32-bit value. Because channels/components can be + * either 1 or 2 bytes in size the length of a row can still overflow 32 + * bits; this is just to verify that the 'row_stride' argument can be + * represented. + */ + if (image->width <= 0x7fffffffU/channels) /* no overflow */ + { + png_uint_32 check; + png_uint_32 png_row_stride = image->width * channels; + + if (row_stride == 0) + row_stride = (png_int_32)/*SAFE*/png_row_stride; + + if (row_stride < 0) + check = (png_uint_32)(-row_stride); + + else + check = (png_uint_32)row_stride; + + /* This verifies 'check', the absolute value of the actual stride + * passed in and detects overflow in the application calculation (i.e. + * if the app did actually pass in a non-zero 'row_stride'. + */ + if (image->opaque != NULL && buffer != NULL && check >= png_row_stride) + { + /* Now check for overflow of the image buffer calculation; this + * limits the whole image size to 32 bits for API compatibility with + * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. + * + * The PNG_IMAGE_BUFFER_SIZE macro is: + * + * (PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)*height*(row_stride)) + * + * And the component size is always 1 or 2, so make sure that the + * number of *bytes* that the application is saying are available + * does actually fit into a 32-bit number. + * + * NOTE: this will be changed in 1.7 because PNG_IMAGE_BUFFER_SIZE + * will be changed to use png_alloc_size_t; bigger images can be + * accommodated on 64-bit systems. + */ + if (image->height <= + 0xffffffffU/PNG_IMAGE_PIXEL_COMPONENT_SIZE(image->format)/check) + { + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || + (image->colormap_entries > 0 && colormap != NULL)) + { + int result; + png_image_read_control display; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.background = background; + display.local_row = NULL; + + /* Choose the correct 'end' routine; for the color-map case + * all the setup has already been done. + */ + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) + result = + png_safe_execute(image, + png_image_read_colormap, &display) && + png_safe_execute(image, + png_image_read_colormapped, &display); + + else + result = + png_safe_execute(image, + png_image_read_direct, &display); + + png_image_free(image); + return result; + } + + else + return png_image_error(image, + "png_image_finish_read[color-map]: no color-map"); + } + + else + return png_image_error(image, + "png_image_finish_read: image too large"); + } + + else + return png_image_error(image, + "png_image_finish_read: invalid argument"); + } + + else + return png_image_error(image, + "png_image_finish_read: row_stride too large"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_finish_read: damaged PNG_IMAGE_VERSION"); + + return 0; +} + +#endif /* SIMPLIFIED_READ */ +#endif /* READ */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngrio.c b/widget/milsko/milskosrc/external/libpng/src/pngrio.c new file mode 100644 index 0000000000..b4a216161b --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngrio.c @@ -0,0 +1,119 @@ +/* pngrio.c - functions for data input + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all input. Users who need + * special handling are expected to write a function that has the same + * arguments as this and performs a similar function, but that possibly + * has a different input method. Note that you shouldn't change this + * function, but rather write a replacement function and then make + * libpng use it at run time with png_set_read_fn(...). + */ + +#include "pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +/* Read the data from whatever input you are using. The default routine + * reads from a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered reads. This should never be asked + * to read more than 64K on a 16-bit machine. + */ +void /* PRIVATE */ +png_read_data(png_structrp png_ptr, png_bytep data, size_t length) +{ + png_debug1(4, "reading %d bytes", (int)length); + + if (png_ptr->read_data_fn != NULL) + (*(png_ptr->read_data_fn))(png_ptr, data, length); + + else + png_error(png_ptr, "Call to NULL read function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual reading of data. If you are + * not reading from a standard C stream, you should create a replacement + * read_data function and use it at run time with png_set_read_fn(), rather + * than changing the library. + */ +void PNGCBAPI +png_default_read_data(png_structp png_ptr, png_bytep data, size_t length) +{ + size_t check; + + if (png_ptr == NULL) + return; + + /* fread() returns 0 on error, so it is OK to store this in a size_t + * instead of an int, which is what fread() actually returns. + */ + check = fread(data, 1, length, png_voidcast(FILE *, png_ptr->io_ptr)); + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#endif + +/* This function allows the application to supply a new input function + * for libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * + * png_ptr - pointer to a png input data structure + * + * io_ptr - pointer to user supplied structure containing info about + * the input functions. May be NULL. + * + * read_data_fn - pointer to a new input function that takes as its + * arguments a pointer to a png_struct, a pointer to + * a location where input data can be stored, and a 32-bit + * unsigned int that is the number of bytes to be read. + * To exit and output any fatal error messages the new write + * function should call png_error(png_ptr, "Error msg"). + * May be NULL, in which case libpng's default function will + * be used. + */ +void PNGAPI +png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (read_data_fn != NULL) + png_ptr->read_data_fn = read_data_fn; + + else + png_ptr->read_data_fn = png_default_read_data; +#else + png_ptr->read_data_fn = read_data_fn; +#endif + +#ifdef PNG_WRITE_SUPPORTED + /* It is an error to write to a read device */ + if (png_ptr->write_data_fn != NULL) + { + png_ptr->write_data_fn = NULL; + png_warning(png_ptr, + "Can't set both read_data_fn and write_data_fn in the" + " same structure"); + } +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->output_flush_fn = NULL; +#endif +} +#endif /* READ */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngrtran.c b/widget/milsko/milskosrc/external/libpng/src/pngrtran.c new file mode 100644 index 0000000000..1809db7047 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngrtran.c @@ -0,0 +1,5124 @@ +/* pngrtran.c - transforms the data in a row for PNG readers + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains functions optionally called by an application + * in order to tell libpng how to handle data when reading a PNG. + * Transformations that are used in both reading and writing are + * in pngtrans.c. + */ + +#include "pngpriv.h" + +#ifdef PNG_ARM_NEON_IMPLEMENTATION +# if PNG_ARM_NEON_IMPLEMENTATION == 1 +# define PNG_ARM_NEON_INTRINSICS_AVAILABLE +# if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64) +# include +# else +# include +# endif +# endif +#endif + +#ifdef PNG_RISCV_RVV_IMPLEMENTATION +# if PNG_RISCV_RVV_IMPLEMENTATION == 1 +# define PNG_RISCV_RVV_INTRINSICS_AVAILABLE +# endif +#endif + +#ifdef PNG_READ_SUPPORTED + +/* Set the action on getting a CRC error for an ancillary or critical chunk. */ +void PNGAPI +png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) +{ + png_debug(1, "in png_set_crc_action"); + + if (png_ptr == NULL) + return; + + /* Tell libpng how we react to CRC errors in critical chunks */ + switch (crit_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | + PNG_FLAG_CRC_CRITICAL_IGNORE; + break; + + case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ + png_warning(png_ptr, + "Can't discard critical data on CRC error"); + /* FALLTHROUGH */ + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + break; + } + + /* Tell libpng how we react to CRC errors in ancillary chunks */ + switch (ancil_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | + PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + break; + } +} + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Is it OK to set a transformation now? Only if png_start_read_image or + * png_read_update_info have not been called. It is not necessary for the IHDR + * to have been read in all cases; the need_IHDR parameter allows for this + * check too. + */ +static int +png_rtran_ok(png_structrp png_ptr, int need_IHDR) +{ + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + png_app_error(png_ptr, + "invalid after png_start_read_image or png_read_update_info"); + + else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_app_error(png_ptr, "invalid before the PNG header has been read"); + + else + { + /* Turn on failure to initialize correctly for all transforms. */ + png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; + + return 1; /* Ok */ + } + } + + return 0; /* no png_error possible! */ +} +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS via a background color */ +void PNGFAPI +png_set_background_fixed(png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma) +{ + png_debug(1, "in png_set_background_fixed"); + + if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL) + return; + + if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) + { + png_warning(png_ptr, "Application must supply a known background gamma"); + return; + } + + png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + png_ptr->background = *background_color; + png_ptr->background_gamma = background_gamma; + png_ptr->background_gamma_type = (png_byte)(background_gamma_code); + if (need_expand != 0) + png_ptr->transformations |= PNG_BACKGROUND_EXPAND; + else + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_background(png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma) +{ + png_set_background_fixed(png_ptr, background_color, background_gamma_code, + need_expand, png_fixed(png_ptr, background_gamma, "png_set_background")); +} +# endif /* FLOATING_POINT */ +#endif /* READ_BACKGROUND */ + +/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the + * one that pngrtran does first (scale) happens. This is necessary to allow the + * TRANSFORM and API behavior to be somewhat consistent, and it's simpler. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +void PNGAPI +png_set_scale_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_scale_16"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_SCALE_16_TO_8; +} +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +/* Chop 16-bit depth files to 8-bit depth */ +void PNGAPI +png_set_strip_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_strip_16"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_16_TO_8; +} +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +void PNGAPI +png_set_strip_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_strip_alpha"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_STRIP_ALPHA; +} +#endif + +#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) +/* PNGv3 conformance: this private API exists to resolve the now mandatory error + * resolution when multiple conflicting sources of gamma or colour space + * information are available. + * + * Terminology (assuming power law, "gamma", encodings): + * "screen" gamma: a power law imposed by the output device when digital + * samples are converted to visible light output. The EOTF - volage to + * luminance on output. + * + * "file" gamma: a power law used to encode luminance levels from the input + * data (the scene or the mastering display system) into digital voltages. + * The OETF - luminance to voltage on input. + * + * gamma "correction": a power law matching the **inverse** of the overall + * transfer function from input luminance levels to output levels. The + * **inverse** of the OOTF; the correction "corrects" for the OOTF by aiming + * to make the overall OOTF (including the correction) linear. + * + * It is important to understand this terminology because the defined terms are + * scattered throughout the libpng code and it is very easy to end up with the + * inverse of the power law required. + * + * Variable and struct::member names: + * file_gamma OETF how the PNG data was encoded + * + * screen_gamma EOTF how the screen will decode digital levels + * + * -- not used -- OOTF the net effect OETF x EOTF + * gamma_correction the inverse of OOTF to make the result linear + * + * All versions of libpng require a call to "png_set_gamma" to establish the + * "screen" gamma, the power law representing the EOTF. png_set_gamma may also + * set or default the "file" gamma; the OETF. gamma_correction is calculated + * internally. + * + * The earliest libpng versions required file_gamma to be supplied to set_gamma. + * Later versions started allowing png_set_gamma and, later, png_set_alpha_mode, + * to cause defaulting from the file data. + * + * PNGv3 mandated a particular form for this defaulting, one that is compatible + * with what libpng did except that if libpng detected inconsistencies it marked + * all the chunks as "invalid". PNGv3 effectively invalidates this prior code. + * + * Behaviour implemented below: + * translate_gamma_flags(gamma, is_screen) + * The libpng-1.6 API for the gamma parameters to libpng APIs + * (png_set_gamma and png_set_alpha_mode at present). This allows the + * 'gamma' value to be passed as a png_fixed_point number or as one of a + * set of integral values for specific "well known" examples of transfer + * functions. This is compatible with PNGv3. + */ +static png_fixed_point +translate_gamma_flags(png_fixed_point output_gamma, int is_screen) +{ + /* Check for flag values. The main reason for having the old Mac value as a + * flag is that it is pretty near impossible to work out what the correct + * value is from Apple documentation - a working Mac system is needed to + * discover the value! + */ + if (output_gamma == PNG_DEFAULT_sRGB || + output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB) + { + if (is_screen != 0) + output_gamma = PNG_GAMMA_sRGB; + else + output_gamma = PNG_GAMMA_sRGB_INVERSE; + } + + else if (output_gamma == PNG_GAMMA_MAC_18 || + output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) + { + if (is_screen != 0) + output_gamma = PNG_GAMMA_MAC_OLD; + else + output_gamma = PNG_GAMMA_MAC_INVERSE; + } + + return output_gamma; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +static png_fixed_point +convert_gamma_value(png_structrp png_ptr, double output_gamma) +{ + /* The following silently ignores cases where fixed point (times 100,000) + * gamma values are passed to the floating point API. This is safe and it + * means the fixed point constants work just fine with the floating point + * API. The alternative would just lead to undetected errors and spurious + * bug reports. Negative values fail inside the _fixed API unless they + * correspond to the flag values. + */ + if (output_gamma > 0 && output_gamma < 128) + output_gamma *= PNG_FP_1; + + /* This preserves -1 and -2 exactly: */ + output_gamma = floor(output_gamma + .5); + + if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN) + png_fixed_error(png_ptr, "gamma value"); + + return (png_fixed_point)output_gamma; +} +# endif + +static int +unsupported_gamma(png_structrp png_ptr, png_fixed_point gamma, int warn) +{ + /* Validate a gamma value to ensure it is in a reasonable range. The value + * is expected to be 1 or greater, but this range test allows for some + * viewing correction values. The intent is to weed out the API users + * who might use the inverse of the gamma value accidentally! + * + * 1.6.47: apply the test in png_set_gamma as well but only warn and return + * false if it fires. + * + * TODO: 1.8: make this an app_error in png_set_gamma as well. + */ + if (gamma < PNG_LIB_GAMMA_MIN || gamma > PNG_LIB_GAMMA_MAX) + { +# define msg "gamma out of supported range" + if (warn) + png_app_warning(png_ptr, msg); + else + png_app_error(png_ptr, msg); + return 1; +# undef msg + } + + return 0; +} +#endif /* READ_ALPHA_MODE || READ_GAMMA */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +void PNGFAPI +png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, + png_fixed_point output_gamma) +{ + png_fixed_point file_gamma; + int compose = 0; + + png_debug(1, "in png_set_alpha_mode_fixed"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + output_gamma = translate_gamma_flags(output_gamma, 1/*screen*/); + if (unsupported_gamma(png_ptr, output_gamma, 0/*error*/)) + return; + + /* The default file gamma is the inverse of the output gamma; the output + * gamma may be changed below so get the file value first. The default_gamma + * is set here and from the simplified API (which uses a different algorithm) + * so don't overwrite a set value: + */ + file_gamma = png_ptr->default_gamma; + if (file_gamma == 0) + { + file_gamma = png_reciprocal(output_gamma); + png_ptr->default_gamma = file_gamma; + } + + /* There are really 8 possibilities here, composed of any combination + * of: + * + * premultiply the color channels + * do not encode non-opaque pixels + * encode the alpha as well as the color channels + * + * The differences disappear if the input/output ('screen') gamma is 1.0, + * because then the encoding is a no-op and there is only the choice of + * premultiplying the color channels or not. + * + * png_set_alpha_mode and png_set_background interact because both use + * png_compose to do the work. Calling both is only useful when + * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along + * with a default gamma value. Otherwise PNG_COMPOSE must not be set. + */ + switch (mode) + { + case PNG_ALPHA_PNG: /* default: png standard */ + /* No compose, but it may be set by png_set_background! */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + /* The output is linear: */ + output_gamma = PNG_FP_1; + break; + + case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA; + /* output_gamma records the encoding of opaque pixels! */ + break; + + case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */ + compose = 1; + png_ptr->transformations |= PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + default: + png_error(png_ptr, "invalid alpha mode"); + } + + /* Set the screen gamma values: */ + png_ptr->screen_gamma = output_gamma; + + /* Finally, if pre-multiplying, set the background fields to achieve the + * desired result. + */ + if (compose != 0) + { + /* And obtain alpha pre-multiplication by composing on black: */ + memset(&png_ptr->background, 0, (sizeof png_ptr->background)); + png_ptr->background_gamma = file_gamma; /* just in case */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; + + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_error(png_ptr, + "conflicting calls to set alpha mode and background"); + + png_ptr->transformations |= PNG_COMPOSE; + } +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) +{ + png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, + output_gamma)); +} +# endif +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Dither file to 8-bit. Supply a palette, the current number + * of elements in the palette, the maximum number of elements + * allowed, and a histogram if possible. If the current number + * of colors is greater than the maximum number, the palette will be + * modified to fit in the maximum number. "full_quantize" indicates + * whether we need a quantizing cube set up for RGB images, or if we + * simply are reducing the number of colors in a paletted image. + */ + +typedef struct png_dsort_struct +{ + struct png_dsort_struct * next; + png_byte left; + png_byte right; +} png_dsort; +typedef png_dsort * png_dsortp; +typedef png_dsort * * png_dsortpp; + +void PNGAPI +png_set_quantize(png_structrp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_const_uint_16p histogram, + int full_quantize) +{ + png_debug(1, "in png_set_quantize"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_QUANTIZE; + + if (full_quantize == 0) + { + int i; + + png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)num_palette); + for (i = 0; i < num_palette; i++) + png_ptr->quantize_index[i] = (png_byte)i; + } + + if (num_palette > maximum_colors) + { + if (histogram != NULL) + { + /* This is easy enough, just throw out the least used colors. + * Perhaps not the best solution, but good enough. + */ + + int i; + + /* Initialize an array to sort colors */ + png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)num_palette); + + /* Initialize the quantize_sort array */ + for (i = 0; i < num_palette; i++) + png_ptr->quantize_sort[i] = (png_byte)i; + + /* Find the least used palette entries by starting a + * bubble sort, and running it until we have sorted + * out enough colors. Note that we don't care about + * sorting all the colors, just finding which are + * least used. + */ + + for (i = num_palette - 1; i >= maximum_colors; i--) + { + int done; /* To stop early if the list is pre-sorted */ + int j; + + done = 1; + for (j = 0; j < i; j++) + { + if (histogram[png_ptr->quantize_sort[j]] + < histogram[png_ptr->quantize_sort[j + 1]]) + { + png_byte t; + + t = png_ptr->quantize_sort[j]; + png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1]; + png_ptr->quantize_sort[j + 1] = t; + done = 0; + } + } + + if (done != 0) + break; + } + + /* Swap the palette around, and set up a table, if necessary */ + if (full_quantize != 0) + { + int j = num_palette; + + /* Put all the useful colors within the max, but don't + * move the others. + */ + for (i = 0; i < maximum_colors; i++) + { + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) + { + do + j--; + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + + palette[i] = palette[j]; + } + } + } + else + { + int j = num_palette; + + /* Move all the used colors inside the max limit, and + * develop a translation table. + */ + for (i = 0; i < maximum_colors; i++) + { + /* Only move the colors we need to */ + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) + { + png_color tmp_color; + + do + j--; + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + + tmp_color = palette[j]; + palette[j] = palette[i]; + palette[i] = tmp_color; + /* Indicate where the color went */ + png_ptr->quantize_index[j] = (png_byte)i; + png_ptr->quantize_index[i] = (png_byte)j; + } + } + + /* Find closest color for those colors we are not using */ + for (i = 0; i < num_palette; i++) + { + if ((int)png_ptr->quantize_index[i] >= maximum_colors) + { + int min_d, k, min_k, d_index; + + /* Find the closest color to one we threw out */ + d_index = png_ptr->quantize_index[i]; + min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); + for (k = 1, min_k = 0; k < maximum_colors; k++) + { + int d; + + d = PNG_COLOR_DIST(palette[d_index], palette[k]); + + if (d < min_d) + { + min_d = d; + min_k = k; + } + } + /* Point to closest color */ + png_ptr->quantize_index[i] = (png_byte)min_k; + } + } + } + png_free(png_ptr, png_ptr->quantize_sort); + png_ptr->quantize_sort = NULL; + } + else + { + /* This is much harder to do simply (and quickly). Perhaps + * we need to go through a median cut routine, but those + * don't always behave themselves with only a few colors + * as input. So we will just find the closest two colors, + * and throw out one of them (chosen somewhat randomly). + * [We don't understand this at all, so if someone wants to + * work on improving it, be our guest - AED, GRP] + */ + int i; + int max_d; + int num_new_palette; + png_dsortp t; + png_dsortpp hash; + + t = NULL; + + /* Initialize palette index arrays */ + png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)num_palette); + png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)num_palette); + + /* Initialize the sort array */ + for (i = 0; i < num_palette; i++) + { + png_ptr->index_to_palette[i] = (png_byte)i; + png_ptr->palette_to_index[i] = (png_byte)i; + } + + hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 * + (sizeof (png_dsortp)))); + + num_new_palette = num_palette; + + /* Initial wild guess at how far apart the farthest pixel + * pair we will be eliminating will be. Larger + * numbers mean more areas will be allocated, Smaller + * numbers run the risk of not saving enough data, and + * having to do this all over again. + * + * I have not done extensive checking on this number. + */ + max_d = 96; + + while (num_new_palette > maximum_colors) + { + for (i = 0; i < num_new_palette - 1; i++) + { + int j; + + for (j = i + 1; j < num_new_palette; j++) + { + int d; + + d = PNG_COLOR_DIST(palette[i], palette[j]); + + if (d <= max_d) + { + + t = (png_dsortp)png_malloc_warn(png_ptr, + (png_alloc_size_t)(sizeof (png_dsort))); + + if (t == NULL) + break; + + t->next = hash[d]; + t->left = (png_byte)i; + t->right = (png_byte)j; + hash[d] = t; + } + } + if (t == NULL) + break; + } + + if (t != NULL) + for (i = 0; i <= max_d; i++) + { + if (hash[i] != NULL) + { + png_dsortp p; + + for (p = hash[i]; p; p = p->next) + { + if ((int)png_ptr->index_to_palette[p->left] + < num_new_palette && + (int)png_ptr->index_to_palette[p->right] + < num_new_palette) + { + int j, next_j; + + if (num_new_palette & 0x01) + { + j = p->left; + next_j = p->right; + } + else + { + j = p->right; + next_j = p->left; + } + + num_new_palette--; + palette[png_ptr->index_to_palette[j]] + = palette[num_new_palette]; + if (full_quantize == 0) + { + int k; + + for (k = 0; k < num_palette; k++) + { + if (png_ptr->quantize_index[k] == + png_ptr->index_to_palette[j]) + png_ptr->quantize_index[k] = + png_ptr->index_to_palette[next_j]; + + if ((int)png_ptr->quantize_index[k] == + num_new_palette) + png_ptr->quantize_index[k] = + png_ptr->index_to_palette[j]; + } + } + + png_ptr->index_to_palette[png_ptr->palette_to_index + [num_new_palette]] = png_ptr->index_to_palette[j]; + + png_ptr->palette_to_index[png_ptr->index_to_palette[j]] + = png_ptr->palette_to_index[num_new_palette]; + + png_ptr->index_to_palette[j] = + (png_byte)num_new_palette; + + png_ptr->palette_to_index[num_new_palette] = + (png_byte)j; + } + if (num_new_palette <= maximum_colors) + break; + } + if (num_new_palette <= maximum_colors) + break; + } + } + + for (i = 0; i < 769; i++) + { + if (hash[i] != NULL) + { + png_dsortp p = hash[i]; + while (p) + { + t = p->next; + png_free(png_ptr, p); + p = t; + } + } + hash[i] = 0; + } + max_d += 96; + } + png_free(png_ptr, hash); + png_free(png_ptr, png_ptr->palette_to_index); + png_free(png_ptr, png_ptr->index_to_palette); + png_ptr->palette_to_index = NULL; + png_ptr->index_to_palette = NULL; + } + num_palette = maximum_colors; + } + if (png_ptr->palette == NULL) + { + png_ptr->palette = palette; + } + png_ptr->num_palette = (png_uint_16)num_palette; + + if (full_quantize != 0) + { + int i; + png_bytep distance; + int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS + + PNG_QUANTIZE_BLUE_BITS; + int num_red = (1 << PNG_QUANTIZE_RED_BITS); + int num_green = (1 << PNG_QUANTIZE_GREEN_BITS); + int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS); + size_t num_entries = ((size_t)1 << total_bits); + + png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr, + (png_alloc_size_t)(num_entries)); + + distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)num_entries); + + memset(distance, 0xff, num_entries); + + for (i = 0; i < num_palette; i++) + { + int ir, ig, ib; + int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS)); + int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS)); + int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS)); + + for (ir = 0; ir < num_red; ir++) + { + /* int dr = abs(ir - r); */ + int dr = ((ir > r) ? ir - r : r - ir); + int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS + + PNG_QUANTIZE_GREEN_BITS)); + + for (ig = 0; ig < num_green; ig++) + { + /* int dg = abs(ig - g); */ + int dg = ((ig > g) ? ig - g : g - ig); + int dt = dr + dg; + int dm = ((dr > dg) ? dr : dg); + int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS); + + for (ib = 0; ib < num_blue; ib++) + { + int d_index = index_g | ib; + /* int db = abs(ib - b); */ + int db = ((ib > b) ? ib - b : b - ib); + int dmax = ((dm > db) ? dm : db); + int d = dmax + dt + db; + + if (d < (int)distance[d_index]) + { + distance[d_index] = (png_byte)d; + png_ptr->palette_lookup[d_index] = (png_byte)i; + } + } + } + } + } + + png_free(png_ptr, distance); + } +} +#endif /* READ_QUANTIZE */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +void PNGFAPI +png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, + png_fixed_point file_gamma) +{ + png_debug(1, "in png_set_gamma_fixed"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + /* New in libpng-1.5.4 - reserve particular negative values as flags. */ + scrn_gamma = translate_gamma_flags(scrn_gamma, 1/*screen*/); + file_gamma = translate_gamma_flags(file_gamma, 0/*file*/); + + /* Checking the gamma values for being >0 was added in 1.5.4 along with the + * premultiplied alpha support; this actually hides an undocumented feature + * of the previous implementation which allowed gamma processing to be + * disabled in background handling. There is no evidence (so far) that this + * was being used; however, png_set_background itself accepted and must still + * accept '0' for the gamma value it takes, because it isn't always used. + * + * Since this is an API change (albeit a very minor one that removes an + * undocumented API feature) the following checks were only enabled in + * libpng-1.6.0. + */ + if (file_gamma <= 0) + png_app_error(png_ptr, "invalid file gamma in png_set_gamma"); + if (scrn_gamma <= 0) + png_app_error(png_ptr, "invalid screen gamma in png_set_gamma"); + + if (unsupported_gamma(png_ptr, file_gamma, 1/*warn*/) || + unsupported_gamma(png_ptr, scrn_gamma, 1/*warn*/)) + return; + + /* 1.6.47: png_struct::file_gamma and png_struct::screen_gamma are now only + * written by this API. This removes dependencies on the order of API calls + * and allows the complex gamma checks to be delayed until needed. + */ + png_ptr->file_gamma = file_gamma; + png_ptr->screen_gamma = scrn_gamma; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) +{ + png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), + convert_gamma_value(png_ptr, file_gamma)); +} +# endif /* FLOATING_POINT */ +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ +void PNGAPI +png_set_expand(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} + +/* GRR 19990627: the following three functions currently are identical + * to png_set_expand(). However, it is entirely reasonable that someone + * might wish to expand an indexed image to RGB but *not* expand a single, + * fully transparent palette entry to a full alpha channel--perhaps instead + * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace + * the transparent color with a particular RGB value, or drop tRNS entirely. + * IOW, a future version of the library may make the transformations flag + * a bit more fine-grained, with separate bits for each of these three + * functions. + * + * More to the point, these functions make it obvious what libpng will be + * doing, whereas "expand" can (and does) mean any number of things. + * + * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified + * to expand only the sample depth but not to expand the tRNS to alpha + * and its name was changed to png_set_expand_gray_1_2_4_to_8(). + */ + +/* Expand paletted images to RGB. */ +void PNGAPI +png_set_palette_to_rgb(png_structrp png_ptr) +{ + png_debug(1, "in png_set_palette_to_rgb"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} + +/* Expand grayscale images of less than 8-bit depth to 8 bits. */ +void PNGAPI +png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_EXPAND; +} + +/* Expand tRNS chunks to alpha channels. */ +void PNGAPI +png_set_tRNS_to_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_tRNS_to_alpha"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} +#endif /* READ_EXPAND */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise + * it may not work correctly.) + */ +void PNGAPI +png_set_expand_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand_16"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); +} +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +void PNGAPI +png_set_gray_to_rgb(png_structrp png_ptr) +{ + png_debug(1, "in png_set_gray_to_rgb"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + /* Because rgb must be 8 bits or more: */ + png_set_expand_gray_1_2_4_to_8(png_ptr); + png_ptr->transformations |= PNG_GRAY_TO_RGB; +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void PNGFAPI +png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, + png_fixed_point red, png_fixed_point green) +{ + png_debug(1, "in png_set_rgb_to_gray_fixed"); + + /* Need the IHDR here because of the check on color_type below. */ + /* TODO: fix this */ + if (png_rtran_ok(png_ptr, 1) == 0) + return; + + switch (error_action) + { + case PNG_ERROR_ACTION_NONE: + png_ptr->transformations |= PNG_RGB_TO_GRAY; + break; + + case PNG_ERROR_ACTION_WARN: + png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; + break; + + case PNG_ERROR_ACTION_ERROR: + png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; + break; + + default: + png_error(png_ptr, "invalid error action to rgb_to_gray"); + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_ptr->transformations |= PNG_EXPAND; +#else + { + /* Make this an error in 1.6 because otherwise the application may assume + * that it just worked and get a memory overwrite. + */ + png_error(png_ptr, + "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); + + /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */ + } +#endif + { + if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) + { + png_uint_16 red_int, green_int; + + /* NOTE: this calculation does not round, but this behavior is retained + * for consistency; the inaccuracy is very small. The code here always + * overwrites the coefficients, regardless of whether they have been + * defaulted or set already. + */ + red_int = (png_uint_16)(((png_uint_32)red*32768)/100000); + green_int = (png_uint_16)(((png_uint_32)green*32768)/100000); + + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_coefficients_set = 1; + } + + else if (red >= 0 && green >= 0) + png_app_warning(png_ptr, + "ignoring out of range rgb_to_gray coefficients"); + } +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* Convert a RGB image to a grayscale of the same width. This allows us, + * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. + */ + +void PNGAPI +png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, + double green) +{ + png_set_rgb_to_gray_fixed(png_ptr, error_action, + png_fixed(png_ptr, red, "rgb to gray red coefficient"), + png_fixed(png_ptr, green, "rgb to gray green coefficient")); +} +#endif /* FLOATING POINT */ + +#endif /* RGB_TO_GRAY */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + read_user_transform_fn) +{ + png_debug(1, "in png_set_read_user_transform_fn"); + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->read_user_transform_fn = read_user_transform_fn; +#endif +} +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +/* In the case of gamma transformations only do transformations on images where + * the [file] gamma and screen_gamma are not close reciprocals, otherwise it + * slows things down slightly, and also needlessly introduces small errors. + */ +static int /* PRIVATE */ +png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) +{ + /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma + * correction as a difference of the overall transform from 1.0 + * + * We want to compare the threshold with s*f - 1, if we get + * overflow here it is because of wacky gamma values so we + * turn on processing anyway. + */ + png_fixed_point gtest; + return !png_muldiv(>est, screen_gamma, file_gamma, PNG_FP_1) || + png_gamma_significant(gtest); +} +#endif + +/* Initialize everything needed for the read. This includes modifying + * the palette. + */ + +/* For the moment 'png_init_palette_transformations' and + * 'png_init_rgb_transformations' only do some flag canceling optimizations. + * The intent is that these two routines should have palette or rgb operations + * extracted from 'png_init_read_transformations'. + */ +static void /* PRIVATE */ +png_init_palette_transformations(png_structrp png_ptr) +{ + /* Called to handle the (input) palette case. In png_do_read_transformations + * the first step is to expand the palette if requested, so this code must + * take care to only make changes that are invariant with respect to the + * palette expansion, or only do them if there is no expansion. + * + * STRIP_ALPHA has already been handled in the caller (by setting num_trans + * to 0.) + */ + int input_has_alpha = 0; + int input_has_transparency = 0; + + if (png_ptr->num_trans > 0) + { + int i; + + /* Ignore if all the entries are opaque (unlikely!) */ + for (i=0; inum_trans; ++i) + { + if (png_ptr->trans_alpha[i] == 255) + continue; + else if (png_ptr->trans_alpha[i] == 0) + input_has_transparency = 1; + else + { + input_has_transparency = 1; + input_has_alpha = 1; + break; + } + } + } + + /* If no alpha we can optimize. */ + if (input_has_alpha == 0) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + if (input_has_transparency == 0) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) + { + { + png_ptr->background.red = + png_ptr->palette[png_ptr->background.index].red; + png_ptr->background.green = + png_ptr->palette[png_ptr->background.index].green; + png_ptr->background.blue = + png_ptr->palette[png_ptr->background.index].blue; + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + { + if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) + { + /* Invert the alpha channel (in tRNS) unless the pixels are + * going to be expanded, in which case leave it for later + */ + int i, istop = png_ptr->num_trans; + + for (i = 0; i < istop; i++) + png_ptr->trans_alpha[i] = + (png_byte)(255 - png_ptr->trans_alpha[i]); + } + } +#endif /* READ_INVERT_ALPHA */ + } + } /* background expand and (therefore) no alpha association. */ +#endif /* READ_EXPAND && READ_BACKGROUND */ +} + +static void /* PRIVATE */ +png_init_rgb_transformations(png_structrp png_ptr) +{ + /* Added to libpng-1.5.4: check the color type to determine whether there + * is any alpha or transparency in the image and simply cancel the + * background and alpha mode stuff if there isn't. + */ + int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0; + int input_has_transparency = png_ptr->num_trans > 0; + + /* If no alpha we can optimize. */ + if (input_has_alpha == 0) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ +# ifdef PNG_READ_ALPHA_MODE_SUPPORTED + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; +# endif + + if (input_has_transparency == 0) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0 && + (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + /* i.e., GRAY or GRAY_ALPHA */ + { + { + /* Expand background and tRNS chunks */ + int gray = png_ptr->background.gray; + int trans_gray = png_ptr->trans_color.gray; + + switch (png_ptr->bit_depth) + { + case 1: + gray *= 0xff; + trans_gray *= 0xff; + break; + + case 2: + gray *= 0x55; + trans_gray *= 0x55; + break; + + case 4: + gray *= 0x11; + trans_gray *= 0x11; + break; + + default: + + case 8: + /* FALLTHROUGH */ /* (Already 8 bits) */ + + case 16: + /* Already a full 16 bits */ + break; + } + + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = (png_uint_16)gray; + + if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) + { + png_ptr->trans_color.red = png_ptr->trans_color.green = + png_ptr->trans_color.blue = (png_uint_16)trans_gray; + } + } + } /* background expand and (therefore) no alpha association. */ +#endif /* READ_EXPAND && READ_BACKGROUND */ +} + +#ifdef PNG_READ_GAMMA_SUPPORTED +png_fixed_point /* PRIVATE */ +png_resolve_file_gamma(png_const_structrp png_ptr) +{ + png_fixed_point file_gamma; + + /* The file gamma is determined by these precedence rules, in this order + * (i.e. use the first value found): + * + * png_set_gamma; png_struct::file_gammma if not zero, then: + * png_struct::chunk_gamma if not 0 (determined the PNGv3 rules), then: + * png_set_gamma; 1/png_struct::screen_gamma if not zero + * + * 0 (i.e. do no gamma handling) + */ + file_gamma = png_ptr->file_gamma; + if (file_gamma != 0) + return file_gamma; + + file_gamma = png_ptr->chunk_gamma; + if (file_gamma != 0) + return file_gamma; + + file_gamma = png_ptr->default_gamma; + if (file_gamma != 0) + return file_gamma; + + /* If png_reciprocal oveflows it returns 0 which indicates to the caller that + * there is no usable file gamma. (The checks added to png_set_gamma and + * png_set_alpha_mode should prevent a screen_gamma which would overflow.) + */ + if (png_ptr->screen_gamma != 0) + file_gamma = png_reciprocal(png_ptr->screen_gamma); + + return file_gamma; +} + +static int +png_init_gamma_values(png_structrp png_ptr) +{ + /* The following temporary indicates if overall gamma correction is + * required. + */ + int gamma_correction = 0; + png_fixed_point file_gamma, screen_gamma; + + /* Resolve the file_gamma. See above: if png_ptr::screen_gamma is set + * file_gamma will always be set here: + */ + file_gamma = png_resolve_file_gamma(png_ptr); + screen_gamma = png_ptr->screen_gamma; + + if (file_gamma > 0) /* file has been set */ + { + if (screen_gamma > 0) /* screen set too */ + gamma_correction = png_gamma_threshold(file_gamma, screen_gamma); + + else + /* Assume the output matches the input; a long time default behavior + * of libpng, although the standard has nothing to say about this. + */ + screen_gamma = png_reciprocal(file_gamma); + } + + else /* both unset, prevent corrections: */ + file_gamma = screen_gamma = PNG_FP_1; + + png_ptr->file_gamma = file_gamma; + png_ptr->screen_gamma = screen_gamma; + return gamma_correction; + +} +#endif /* READ_GAMMA */ + +void /* PRIVATE */ +png_init_read_transformations(png_structrp png_ptr) +{ + png_debug(1, "in png_init_read_transformations"); + + /* This internal function is called from png_read_start_row in pngrutil.c + * and it is called before the 'rowbytes' calculation is done, so the code + * in here can change or update the transformations flags. + * + * First do updates that do not depend on the details of the PNG image data + * being processed. + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds + * png_set_alpha_mode and this is another source for a default file gamma so + * the test needs to be performed later - here. In addition prior to 1.5.4 + * the tests were repeated for the PALETTE color type here - this is no + * longer necessary (and doesn't seem to have been necessary before.) + * + * PNGv3: the new mandatory precedence/priority rules for colour space chunks + * are handled here (by calling the above function). + * + * Turn the gamma transformation on or off as appropriate. Notice that + * PNG_GAMMA just refers to the file->screen correction. Alpha composition + * may independently cause gamma correction because it needs linear data + * (e.g. if the file has a gAMA chunk but the screen gamma hasn't been + * specified.) In any case this flag may get turned off in the code + * immediately below if the transform can be handled outside the row loop. + */ + if (png_init_gamma_values(png_ptr) != 0) + png_ptr->transformations |= PNG_GAMMA; + + else + png_ptr->transformations &= ~PNG_GAMMA; +#endif + + /* Certain transformations have the effect of preventing other + * transformations that happen afterward in png_do_read_transformations; + * resolve the interdependencies here. From the code of + * png_do_read_transformations the order is: + * + * 1) PNG_EXPAND (including PNG_EXPAND_tRNS) + * 2) PNG_STRIP_ALPHA (if no compose) + * 3) PNG_RGB_TO_GRAY + * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY + * 5) PNG_COMPOSE + * 6) PNG_GAMMA + * 7) PNG_STRIP_ALPHA (if compose) + * 8) PNG_ENCODE_ALPHA + * 9) PNG_SCALE_16_TO_8 + * 10) PNG_16_TO_8 + * 11) PNG_QUANTIZE (converts to palette) + * 12) PNG_EXPAND_16 + * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY + * 14) PNG_INVERT_MONO + * 15) PNG_INVERT_ALPHA + * 16) PNG_SHIFT + * 17) PNG_PACK + * 18) PNG_BGR + * 19) PNG_PACKSWAP + * 20) PNG_FILLER (includes PNG_ADD_ALPHA) + * 21) PNG_SWAP_ALPHA + * 22) PNG_SWAP_BYTES + * 23) PNG_USER_TRANSFORM [must be last] + */ +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0) + { + /* Stripping the alpha channel happens immediately after the 'expand' + * transformations, before all other transformation, so it cancels out + * the alpha handling. It has the side effect negating the effect of + * PNG_EXPAND_tRNS too: + */ + png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA | + PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen + * so transparency information would remain just so long as it wasn't + * expanded. This produces unexpected API changes if the set of things + * that do PNG_EXPAND_tRNS changes (perfectly possible given the + * documentation - which says ask for what you want, accept what you + * get.) This makes the behavior consistent from 1.5.4: + */ + png_ptr->num_trans = 0; + } +#endif /* STRIP_ALPHA supported, no COMPOSE */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA + * settings will have no effect. + */ + if (png_gamma_significant(png_ptr->screen_gamma) == 0) + { + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + } +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Make sure the coefficients for the rgb to gray conversion are set + * appropriately. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + png_set_rgb_coefficients(png_ptr); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* Detect gray background and attempt to enable optimization for + * gray --> RGB case. + * + * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or + * RGB_ALPHA (in which case need_expand is superfluous anyway), the + * background color might actually be gray yet not be flagged as such. + * This is not a problem for the current code, which uses + * PNG_BACKGROUND_IS_GRAY only to decide when to do the + * png_do_gray_to_rgb() transformation. + * + * TODO: this code needs to be revised to avoid the complexity and + * interdependencies. The color type of the background should be recorded in + * png_set_background, along with the bit depth, then the code has a record + * of exactly what color space the background is currently in. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0) + { + /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if + * the file was grayscale the background value is gray. + */ + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + } + + else if ((png_ptr->transformations & PNG_COMPOSE) != 0) + { + /* PNG_COMPOSE: png_set_background was called with need_expand false, + * so the color is in the color space of the output or png_set_alpha_mode + * was called and the color is black. Ignore RGB_TO_GRAY because that + * happens before GRAY_TO_RGB. + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + { + if (png_ptr->background.red == png_ptr->background.green && + png_ptr->background.red == png_ptr->background.blue) + { + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + png_ptr->background.gray = png_ptr->background.red; + } + } + } +#endif /* READ_EXPAND && READ_BACKGROUND */ +#endif /* READ_GRAY_TO_RGB */ + + /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations + * can be performed directly on the palette, and some (such as rgb to gray) + * can be optimized inside the palette. This is particularly true of the + * composite (background and alpha) stuff, which can be pretty much all done + * in the palette even if the result is expanded to RGB or gray afterward. + * + * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and + * earlier and the palette stuff is actually handled on the first row. This + * leads to the reported bug that the palette returned by png_get_PLTE is not + * updated. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_init_palette_transformations(png_ptr); + + else + png_init_rgb_transformations(png_ptr); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_EXPAND_16_SUPPORTED) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth != 16) + { + /* TODO: fix this. Because the expand_16 operation is after the compose + * handling the background color must be 8, not 16, bits deep, but the + * application will supply a 16-bit value so reduce it here. + * + * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at + * present, so that case is ok (until do_expand_16 is moved.) + * + * NOTE: this discards the low 16 bits of the user supplied background + * color, but until expand_16 works properly there is no choice! + */ +# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x)) + CHOP(png_ptr->background.red); + CHOP(png_ptr->background.green); + CHOP(png_ptr->background.blue); + CHOP(png_ptr->background.gray); +# undef CHOP + } +#endif /* READ_BACKGROUND && READ_EXPAND_16 */ + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ + defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) + if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth == 16) + { + /* On the other hand, if a 16-bit file is to be reduced to 8-bits per + * component this will also happen after PNG_COMPOSE and so the background + * color must be pre-expanded here. + * + * TODO: fix this too. + */ + png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257); + png_ptr->background.green = + (png_uint_16)(png_ptr->background.green * 257); + png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257); + png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257); + } +#endif + + /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the + * background support (see the comments in scripts/pnglibconf.dfa), this + * allows pre-multiplication of the alpha channel to be implemented as + * compositing on black. This is probably sub-optimal and has been done in + * 1.5.4 betas simply to enable external critique and testing (i.e. to + * implement the new API quickly, without lots of internal changes.) + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +# ifdef PNG_READ_BACKGROUND_SUPPORTED + /* Includes ALPHA_MODE */ + png_ptr->background_1 = png_ptr->background; +# endif + + /* This needs to change - in the palette image case a whole set of tables are + * built when it would be quicker to just calculate the correct value for + * each palette entry directly. Also, the test is too tricky - why check + * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that + * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the + * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction + * the gamma tables will not be built even if composition is required on a + * gamma encoded value. + * + * In 1.5.4 this is addressed below by an additional check on the individual + * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the + * tables. + */ + if ((png_ptr->transformations & PNG_GAMMA) != 0 || + ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 && + (png_gamma_significant(png_ptr->file_gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0)) || + ((png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_gamma_significant(png_ptr->file_gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0 +# ifdef PNG_READ_BACKGROUND_SUPPORTED + || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE && + png_gamma_significant(png_ptr->background_gamma) != 0) +# endif + )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + png_gamma_significant(png_ptr->screen_gamma) != 0)) + { + png_build_gamma_table(png_ptr, png_ptr->bit_depth); + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + { + /* Issue a warning about this combination: because RGB_TO_GRAY is + * optimized to do the gamma transform if present yet do_background has + * to do the same thing if both options are set a + * double-gamma-correction happens. This is true in all versions of + * libpng to date. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + png_warning(png_ptr, + "libpng does not support gamma+background+rgb_to_gray"); + + if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0) + { + /* We don't get to here unless there is a tRNS chunk with non-opaque + * entries - see the checking code at the start of this function. + */ + png_color back, back_1; + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + png_fixed_point g, gs; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = PNG_FP_1; + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = png_reciprocal(png_ptr->file_gamma); + gs = png_reciprocal2(png_ptr->file_gamma, + png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = png_reciprocal(png_ptr->background_gamma); + gs = png_reciprocal2(png_ptr->background_gamma, + png_ptr->screen_gamma); + break; + default: + g = PNG_FP_1; /* back_1 */ + gs = PNG_FP_1; /* back */ + break; + } + + if (png_gamma_significant(gs) != 0) + { + back.red = png_gamma_8bit_correct(png_ptr->background.red, + gs); + back.green = png_gamma_8bit_correct(png_ptr->background.green, + gs); + back.blue = png_gamma_8bit_correct(png_ptr->background.blue, + gs); + } + + else + { + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + } + + if (png_gamma_significant(g) != 0) + { + back_1.red = png_gamma_8bit_correct(png_ptr->background.red, + g); + back_1.green = png_gamma_8bit_correct( + png_ptr->background.green, g); + back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, + g); + } + + else + { + back_1.red = (png_byte)png_ptr->background.red; + back_1.green = (png_byte)png_ptr->background.green; + back_1.blue = (png_byte)png_ptr->background.blue; + } + } + + for (i = 0; i < num_palette; i++) + { + if (i < (int)png_ptr->num_trans && + png_ptr->trans_alpha[i] != 0xff) + { + if (png_ptr->trans_alpha[i] == 0) + { + palette[i] = back; + } + else /* if (png_ptr->trans_alpha[i] != 0xff) */ + { + png_byte v, w; + + v = png_ptr->gamma_to_1[palette[i].red]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].green]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].blue]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + + /* Prevent the transformations being done again. + * + * NOTE: this is highly dubious; it removes the transformations in + * place. This seems inconsistent with the general treatment of the + * transformations elsewhere. + */ + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); + } /* color_type == PNG_COLOR_TYPE_PALETTE */ + + /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ + else /* color_type != PNG_COLOR_TYPE_PALETTE */ + { + int gs_sig, g_sig; + png_fixed_point g = PNG_FP_1; /* Correction to linear */ + png_fixed_point gs = PNG_FP_1; /* Correction to screen */ + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = png_ptr->screen_gamma; + /* gs = PNG_FP_1; */ + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = png_reciprocal(png_ptr->file_gamma); + gs = png_reciprocal2(png_ptr->file_gamma, + png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = png_reciprocal(png_ptr->background_gamma); + gs = png_reciprocal2(png_ptr->background_gamma, + png_ptr->screen_gamma); + break; + + default: + png_error(png_ptr, "invalid background gamma type"); + } + + g_sig = png_gamma_significant(g); + gs_sig = png_gamma_significant(gs); + + if (g_sig != 0) + png_ptr->background_1.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, g); + + if (gs_sig != 0) + png_ptr->background.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, gs); + + if ((png_ptr->background.red != png_ptr->background.green) || + (png_ptr->background.red != png_ptr->background.blue) || + (png_ptr->background.red != png_ptr->background.gray)) + { + /* RGB or RGBA with color background */ + if (g_sig != 0) + { + png_ptr->background_1.red = png_gamma_correct(png_ptr, + png_ptr->background.red, g); + + png_ptr->background_1.green = png_gamma_correct(png_ptr, + png_ptr->background.green, g); + + png_ptr->background_1.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, g); + } + + if (gs_sig != 0) + { + png_ptr->background.red = png_gamma_correct(png_ptr, + png_ptr->background.red, gs); + + png_ptr->background.green = png_gamma_correct(png_ptr, + png_ptr->background.green, gs); + + png_ptr->background.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, gs); + } + } + + else + { + /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ + png_ptr->background_1.red = png_ptr->background_1.green + = png_ptr->background_1.blue = png_ptr->background_1.gray; + + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + } + + /* The background is now in screen gamma: */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN; + } /* color_type != PNG_COLOR_TYPE_PALETTE */ + }/* png_ptr->transformations & PNG_BACKGROUND */ + + else + /* Transformation does not include PNG_BACKGROUND */ +#endif /* READ_BACKGROUND */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ + && ((png_ptr->transformations & PNG_EXPAND) == 0 || + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) +#endif + ) + { + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + + /* NOTE: there are other transformations that should probably be in + * here too. + */ + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + + /* Done the gamma correction. */ + png_ptr->transformations &= ~PNG_GAMMA; + } /* color_type == PALETTE && !PNG_BACKGROUND transformation */ + } +#ifdef PNG_READ_BACKGROUND_SUPPORTED + else +#endif +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + /* No GAMMA transformation (see the hanging else 4 lines above) */ + if ((png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = (int)png_ptr->num_trans; + png_color back; + png_colorp palette = png_ptr->palette; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < istop; i++) + { + if (png_ptr->trans_alpha[i] == 0) + { + palette[i] = back; + } + + else if (png_ptr->trans_alpha[i] != 0xff) + { + /* The png_composite() macro is defined in png.h */ + png_composite(palette[i].red, palette[i].red, + png_ptr->trans_alpha[i], back.red); + + png_composite(palette[i].green, palette[i].green, + png_ptr->trans_alpha[i], back.green); + + png_composite(palette[i].blue, palette[i].blue, + png_ptr->trans_alpha[i], back.blue); + } + } + + png_ptr->transformations &= ~PNG_COMPOSE; + } +#endif /* READ_BACKGROUND */ + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0 && + (png_ptr->transformations & PNG_EXPAND) == 0 && + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = png_ptr->num_palette; + int shift = 8 - png_ptr->sig_bit.red; + + png_ptr->transformations &= ~PNG_SHIFT; + + /* significant bits can be in the range 1 to 7 for a meaningful result, if + * the number of significant bits is 0 then no shift is done (this is an + * error condition which is silently ignored.) + */ + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].red; + + component >>= shift; + png_ptr->palette[i].red = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.green; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].green; + + component >>= shift; + png_ptr->palette[i].green = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.blue; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].blue; + + component >>= shift; + png_ptr->palette[i].blue = (png_byte)component; + } + } +#endif /* READ_SHIFT */ +} + +/* Modify the info structure to reflect the transformations. The + * info should be updated so a PNG file could be written with it, + * assuming the transformations result in valid PNG data. + */ +void /* PRIVATE */ +png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_read_transform_info"); + +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + /* This check must match what actually happens in + * png_do_expand_palette; if it ever checks the tRNS chunk to see if + * it is all opaque we must do the same (at present it does not.) + */ + if (png_ptr->num_trans > 0) + info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + + else + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + + if (png_ptr->palette == NULL) + png_error (png_ptr, "Palette is NULL in indexed image"); + } + else + { + if (png_ptr->num_trans != 0) + { + if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } + if (info_ptr->bit_depth < 8) + info_ptr->bit_depth = 8; + + info_ptr->num_trans = 0; + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* The following is almost certainly wrong unless the background value is in + * the screen space! + */ + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + info_ptr->background = png_ptr->background; +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4), + * however it seems that the code in png_init_read_transformations, which has + * been called before this from png_read_update_info->png_read_start_row + * sometimes does the gamma transform and cancels the flag. + * + * TODO: this is confusing. It only changes the result of png_get_gAMA and, + * yes, it does return the value that the transformed data effectively has + * but does any app really understand this? + */ + info_ptr->gamma = png_ptr->file_gamma; +#endif + + if (info_ptr->bit_depth == 16) + { +# ifdef PNG_READ_16BIT_SUPPORTED +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + info_ptr->bit_depth = 8; +# endif + +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_16_TO_8) != 0) + info_ptr->bit_depth = 8; +# endif + +# else + /* No 16-bit support: force chopping 16-bit input down to 8, in this case + * the app program can chose if both APIs are available by setting the + * correct scaling to use. + */ +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* For compatibility with previous versions use the strip method by + * default. This code works because if PNG_SCALE_16_TO_8 is already + * set the code below will do that in preference to the chop. + */ + png_ptr->transformations |= PNG_16_TO_8; + info_ptr->bit_depth = 8; +# else + +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_ptr->transformations |= PNG_SCALE_16_TO_8; + info_ptr->bit_depth = 8; +# else + + CONFIGURATION ERROR: you must enable at least one 16 to 8 method +# endif +# endif +#endif /* !READ_16BIT */ + } + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + info_ptr->color_type = (png_byte)(info_ptr->color_type | + PNG_COLOR_MASK_COLOR); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_COLOR); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) + { + if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && + png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8) + { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + info_ptr->bit_depth = 16; + } +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0 && + (info_ptr->bit_depth < 8)) + info_ptr->bit_depth = 8; +#endif + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + info_ptr->channels = 3; + + else + info_ptr->channels = 1; + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0) + { + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_ALPHA); + info_ptr->num_trans = 0; + } +#endif + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + info_ptr->channels++; + +#ifdef PNG_READ_FILLER_SUPPORTED + /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ + if ((png_ptr->transformations & PNG_FILLER) != 0 && + (info_ptr->color_type == PNG_COLOR_TYPE_RGB || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY)) + { + info_ptr->channels++; + /* If adding a true alpha channel not just filler */ + if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } +#endif + +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ +defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + if (png_ptr->user_transform_depth != 0) + info_ptr->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels != 0) + info_ptr->channels = png_ptr->user_transform_channels; + } +#endif + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * + info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); + + /* Adding in 1.5.4: cache the above value in png_struct so that we can later + * check in png_rowbytes that the user buffer won't get overwritten. Note + * that the field is not always set - if png_read_update_info isn't called + * the application has to either not do any transforms or get the calculation + * right itself. + */ + png_ptr->info_rowbytes = info_ptr->rowbytes; + +#ifndef PNG_READ_EXPAND_SUPPORTED + if (png_ptr != NULL) + return; +#endif +} + +#ifdef PNG_READ_PACK_SUPPORTED +/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, + * without changing the actual values. Thus, if you had a row with + * a bit depth of 1, you would end up with bytes that only contained + * the numbers 0 or 1. If you would rather they contain 0 and 255, use + * png_do_shift() after this. + */ +static void +png_do_unpack(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_unpack"); + + if (row_info->bit_depth < 8) + { + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + switch (row_info->bit_depth) + { + case 1: + { + png_bytep sp = row + (size_t)((row_width - 1) >> 3); + png_bytep dp = row + (size_t)row_width - 1; + png_uint_32 shift = 7U - ((row_width + 7U) & 0x07); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x01); + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + + png_bytep sp = row + (size_t)((row_width - 1) >> 2); + png_bytep dp = row + (size_t)row_width - 1; + png_uint_32 shift = ((3U - ((row_width + 3U) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x03); + + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + png_bytep sp = row + (size_t)((row_width - 1) >> 1); + png_bytep dp = row + (size_t)row_width - 1; + png_uint_32 shift = ((1U - ((row_width + 1U) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x0f); + + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift = 4; + + dp--; + } + break; + } + + default: + break; + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +/* Reverse the effects of png_do_shift. This routine merely shifts the + * pixels back to their significant bits values. Thus, if you have + * a row of bit depth 8, but only 5 are significant, this will shift + * the values back to 0 through 31. + */ +static void +png_do_unshift(png_row_infop row_info, png_bytep row, + png_const_color_8p sig_bits) +{ + int color_type; + + png_debug(1, "in png_do_unshift"); + + /* The palette case has already been handled in the _init routine. */ + color_type = row_info->color_type; + + if (color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift[4]; + int channels = 0; + int bit_depth = row_info->bit_depth; + + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + { + shift[channels++] = bit_depth - sig_bits->red; + shift[channels++] = bit_depth - sig_bits->green; + shift[channels++] = bit_depth - sig_bits->blue; + } + + else + { + shift[channels++] = bit_depth - sig_bits->gray; + } + + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + shift[channels++] = bit_depth - sig_bits->alpha; + } + + { + int c, have_shift; + + for (c = have_shift = 0; c < channels; ++c) + { + /* A shift of more than the bit depth is an error condition but it + * gets ignored here. + */ + if (shift[c] <= 0 || shift[c] >= bit_depth) + shift[c] = 0; + + else + have_shift = 1; + } + + if (have_shift == 0) + return; + } + + switch (bit_depth) + { + default: + /* Must be 1bpp gray: should not be here! */ + /* NOTREACHED */ + break; + + case 2: + /* Must be 2bpp gray */ + /* assert(channels == 1 && shift[0] == 1) */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + + while (bp < bp_end) + { + int b = (*bp >> 1) & 0x55; + *bp++ = (png_byte)b; + } + break; + } + + case 4: + /* Must be 4bpp gray */ + /* assert(channels == 1) */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int gray_shift = shift[0]; + int mask = 0xf >> gray_shift; + + mask |= mask << 4; + + while (bp < bp_end) + { + int b = (*bp >> gray_shift) & mask; + *bp++ = (png_byte)b; + } + break; + } + + case 8: + /* Single byte components, G, GA, RGB, RGBA */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; + + while (bp < bp_end) + { + int b = *bp >> shift[channel]; + if (++channel >= channels) + channel = 0; + *bp++ = (png_byte)b; + } + break; + } + +#ifdef PNG_READ_16BIT_SUPPORTED + case 16: + /* Double byte components, G, GA, RGB, RGBA */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; + + while (bp < bp_end) + { + int value = (bp[0] << 8) + bp[1]; + + value >>= shift[channel]; + if (++channel >= channels) + channel = 0; + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)value; + } + break; + } +#endif + } + } +} +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale rows of bit depth 16 down to 8 accurately */ +static void +png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_scale_16_to_8"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destination */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ + + while (sp < ep) + { + /* The input is an array of 16-bit components, these must be scaled to + * 8 bits each. For a 16-bit value V the required value (from the PNG + * specification) is: + * + * (V * 255) / 65535 + * + * This reduces to round(V / 257), or floor((V + 128.5)/257) + * + * Represent V as the two byte value vhi.vlo. Make a guess that the + * result is the top byte of V, vhi, then the correction to this value + * is: + * + * error = floor(((V-vhi.vhi) + 128.5) / 257) + * = floor(((vlo-vhi) + 128.5) / 257) + * + * This can be approximated using integer arithmetic (and a signed + * shift): + * + * error = (vlo-vhi+128) >> 8; + * + * The approximate differs from the exact answer only when (vlo-vhi) is + * 128; it then gives a correction of +1 when the exact correction is + * 0. This gives 128 errors. The exact answer (correct for all 16-bit + * input values) is: + * + * error = (vlo-vhi+128)*65535 >> 24; + * + * An alternative arithmetic calculation which also gives no errors is: + * + * (V * 255 + 32895) >> 16 + */ + + png_int_32 tmp = *sp++; /* must be signed! */ + tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24; + *dp++ = (png_byte)tmp; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +static void +/* Simply discard the low byte. This was the default behavior prior + * to libpng-1.5.4. + */ +png_do_chop(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_chop"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destination */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ + + while (sp < ep) + { + *dp++ = *sp; + sp += 2; /* skip low byte */ + } + + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +static void +png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_read_swap_alpha"); + + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from RGBA to ARGB */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This converts from RRGGBBAA to AARRGGBB */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } +#endif + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from GA to AG */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This converts from GGAA to AAGG */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } +#endif + } +} +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +static void +png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_uint_32 row_width; + png_debug(1, "in png_do_read_invert_alpha"); + + row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in RGBA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=3; + dp=sp; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=6; + dp=sp; + } + } +#endif + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in GA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = *(--sp); + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in GGAA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); +/* + *(--dp) = *(--sp); + *(--dp) = *(--sp); +*/ + sp-=2; + dp=sp; + } + } +#endif + } +} +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED +/* Add filler channel if we have RGB color */ +static void +png_do_read_filler(png_row_infop row_info, png_bytep row, + png_uint_32 filler, png_uint_32 flags) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + +#ifdef PNG_READ_16BIT_SUPPORTED + png_byte hi_filler = (png_byte)(filler>>8); +#endif + png_byte lo_filler = (png_byte)filler; + + png_debug(1, "in png_do_read_filler"); + + if ( + row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + { + /* This changes the data from G to GX */ + png_bytep sp = row + (size_t)row_width; + png_bytep dp = sp + (size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + + else + { + /* This changes the data from G to XG */ + png_bytep sp = row + (size_t)row_width; + png_bytep dp = sp + (size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + { + /* This changes the data from GG to GGXX */ + png_bytep sp = row + (size_t)row_width * 2; + png_bytep dp = sp + (size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = hi_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + *(--dp) = hi_filler; + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + + else + { + /* This changes the data from GG to XXGG */ + png_bytep sp = row + (size_t)row_width * 2; + png_bytep dp = sp + (size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + *(--dp) = hi_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } +#endif + } /* COLOR_TYPE == GRAY */ + else if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + { + /* This changes the data from RGB to RGBX */ + png_bytep sp = row + (size_t)row_width * 3; + png_bytep dp = sp + (size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + + else + { + /* This changes the data from RGB to XRGB */ + png_bytep sp = row + (size_t)row_width * 3; + png_bytep dp = sp + (size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + { + /* This changes the data from RRGGBB to RRGGBBXX */ + png_bytep sp = row + (size_t)row_width * 6; + png_bytep dp = sp + (size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = hi_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + *(--dp) = hi_filler; + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + + else + { + /* This changes the data from RRGGBB to XXRRGGBB */ + png_bytep sp = row + (size_t)row_width * 6; + png_bytep dp = sp + (size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + *(--dp) = hi_filler; + } + + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + } +#endif + } /* COLOR_TYPE == RGB */ +} +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand grayscale files to RGB, with or without alpha */ +static void +png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_gray_to_rgb"); + + if (row_info->bit_depth >= 8 && + (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0) + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + /* This changes G to RGB */ + png_bytep sp = row + (size_t)row_width - 1; + png_bytep dp = sp + (size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + + else + { + /* This changes GG to RRGGBB */ + png_bytep sp = row + (size_t)row_width * 2 - 1; + png_bytep dp = sp + (size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This changes GA to RGBA */ + png_bytep sp = row + (size_t)row_width * 2 - 1; + png_bytep dp = sp + (size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + + else + { + /* This changes GGAA to RRGGBBAA */ + png_bytep sp = row + (size_t)row_width * 4 - 1; + png_bytep dp = sp + (size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + row_info->channels = (png_byte)(row_info->channels + 2); + row_info->color_type |= PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB files to grayscale, with or without alpha + * using the equation given in Poynton's ColorFAQ of 1998-01-04 at + * (THIS LINK IS DEAD June 2008 but + * versions dated 1998 through November 2002 have been archived at + * https://web.archive.org/web/20000816232553/www.inforamp.net/ + * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) + * Charles Poynton poynton at poynton.com + * + * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + * + * which can be expressed with integers as + * + * Y = (6969 * R + 23434 * G + 2365 * B)/32768 + * + * Poynton's current link (as of January 2003 through July 2011): + * + * has changed the numbers slightly: + * + * Y = 0.2126*R + 0.7152*G + 0.0722*B + * + * which can be expressed with integers as + * + * Y = (6966 * R + 23436 * G + 2366 * B)/32768 + * + * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 + * end point chromaticities and the D65 white point. Depending on the + * precision used for the D65 white point this produces a variety of different + * numbers, however if the four decimal place value used in ITU-R Rec 709 is + * used (0.3127,0.3290) the Y calculation would be: + * + * Y = (6968 * R + 23435 * G + 2366 * B)/32768 + * + * While this is correct the rounding results in an overflow for white, because + * the sum of the rounded coefficients is 32769, not 32768. Consequently + * libpng uses, instead, the closest non-overflowing approximation: + * + * Y = (6968 * R + 23434 * G + 2366 * B)/32768 + * + * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk + * (including an sRGB chunk) then the chromaticities are used to calculate the + * coefficients. See the chunk handling in pngrutil.c for more information. + * + * In all cases the calculation is to be done in a linear colorspace. If no + * gamma information is available to correct the encoding of the original RGB + * values this results in an implicit assumption that the original PNG RGB + * values were linear. + * + * Other integer coefficients can be used via png_set_rgb_to_gray(). Because + * the API takes just red and green coefficients the blue coefficient is + * calculated to make the sum 32768. This will result in different rounding + * to that used above. + */ +static int +png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) +{ + int rgb_error = 0; + + png_debug(1, "in png_do_rgb_to_gray"); + + if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 && + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + png_uint_32 bc = 32768 - rc - gc; + png_uint_32 row_width = row_info->width; + int have_alpha = (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; + + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Notice that gamma to/from 1 are not necessarily inverses (if + * there is an overall gamma correction). Prior to 1.5.5 this code + * checked the linearized values for equality; this doesn't match + * the documentation, the original values must be checked. + */ + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + + if (red != green || red != blue) + { + red = png_ptr->gamma_to_1[red]; + green = png_ptr->gamma_to_1[green]; + blue = png_ptr->gamma_to_1[blue]; + + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red + gc*green + bc*blue + 16384)>>15]; + } + + else + { + /* If there is no overall correction the table will not be + * set. + */ + if (png_ptr->gamma_table != NULL) + red = png_ptr->gamma_table[red]; + + *(dp++) = red; + } + + if (have_alpha != 0) + *(dp++) = *(sp++); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + + if (red != green || red != blue) + { + rgb_error |= 1; + /* NOTE: this is the historical approach which simply + * truncates the results. + */ + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + } + + else + *(dp++) = red; + + if (have_alpha != 0) + *(dp++) = *(sp++); + } + } + } + + else /* RGB bit_depth == 16 */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + png_byte hi,lo; + + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); + + if (red == green && red == blue) + { + if (png_ptr->gamma_16_table != NULL) + w = png_ptr->gamma_16_table[(red & 0xff) + >> png_ptr->gamma_shift][red >> 8]; + + else + w = red; + } + + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red & 0xff) + >> png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = + png_ptr->gamma_16_to_1[(green & 0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue & 0xff) + >> png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + + bc*blue_1 + 16384)>>15); + w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + + if (have_alpha != 0) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + } + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + png_byte hi,lo; + + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); + + if (red != green || red != blue) + rgb_error |= 1; + + /* From 1.5.5 in the 16-bit case do the accurate conversion even + * in the 'fast' case - this is because this is where the code + * ends up when handling linear 16-bit data. + */ + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> + 15); + *(dp++) = (png_byte)((gray16 >> 8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + + if (have_alpha != 0) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + } + } + } + } + + row_info->channels = (png_byte)(row_info->channels - 2); + row_info->color_type = (png_byte)(row_info->color_type & + ~PNG_COLOR_MASK_COLOR); + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + return rgb_error; +} +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* Replace any alpha or transparency with the supplied background color. + * "background" is already in the screen gamma, while "background_1" is + * at a gamma of 1.0. Paletted files have already been taken care of. + */ +static void +png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_bytep gamma_from_1 = png_ptr->gamma_from_1; + png_const_bytep gamma_to_1 = png_ptr->gamma_to_1; + png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table; + png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; + png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; + int gamma_shift = png_ptr->gamma_shift; + int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; +#endif + + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + int shift; + + png_debug(1, "in png_do_compose"); + + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_GRAY: + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row; + shift = 7; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x01) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); + tmp |= + (unsigned int)(png_ptr->background.gray << shift); + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 7; + sp++; + } + + else + shift--; + } + break; + } + + case 2: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= + (unsigned int)png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + else + { + unsigned int p = (*sp >> shift) & 0x03; + unsigned int g = (gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03; + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= (unsigned int)(g << shift); + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 6; + sp++; + } + + else + shift -= 2; + } + } + + else +#endif + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= + (unsigned int)png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 6; + sp++; + } + + else + shift -= 2; + } + } + break; + } + + case 4: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); + tmp |= + (unsigned int)(png_ptr->background.gray << shift); + *sp = (png_byte)(tmp & 0xff); + } + + else + { + unsigned int p = (*sp >> shift) & 0x0f; + unsigned int g = (gamma_table[p | (p << 4)] >> 4) & + 0x0f; + unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); + tmp |= (unsigned int)(g << shift); + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 4; + sp++; + } + + else + shift -= 4; + } + } + + else +#endif + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); + tmp |= + (unsigned int)(png_ptr->background.gray << shift); + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 4; + sp++; + } + + else + shift -= 4; + } + } + break; + } + + case 8: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + + else + *sp = gamma_table[*sp]; + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + } + } + break; + } + + case 16: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + if (v == png_ptr->trans_color.gray) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); + } + + else + { + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + if (v == png_ptr->trans_color.gray) + { + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); + } + } + } + break; + } + + default: + break; + } + break; + } + + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else + { + png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) + { + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 a = *(sp + 1); + + if (a == 0xff) + *sp = gamma_table[*sp]; + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)png_ptr->background.gray; + } + + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, png_ptr->background_1.gray); + if (optimize == 0) + w = gamma_from_1[w]; + *sp = w; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_byte a = *(sp + 1); + + if (a == 0) + *sp = (png_byte)png_ptr->background.gray; + + else if (a < 0xff) + png_composite(*sp, *sp, a, png_ptr->background.gray); + } + } + } + else /* if (png_ptr->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + } + + else + { + png_uint_16 g, v, w; + + g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(v, g, a, png_ptr->background_1.gray); + if (optimize != 0) + w = v; + else + w = gamma_16_from_1[(v & 0xff) >> + gamma_shift][v >> 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + if (a == 0) + { + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + } + + else if (a < 0xffff) + { + png_uint_16 g, v; + + g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_composite_16(v, g, a, png_ptr->background.gray); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, png_ptr->background_1.red); + if (optimize == 0) w = gamma_from_1[w]; + *sp = w; + + v = gamma_to_1[*(sp + 1)]; + png_composite(w, v, a, png_ptr->background_1.green); + if (optimize == 0) w = gamma_from_1[w]; + *(sp + 1) = w; + + v = gamma_to_1[*(sp + 2)]; + png_composite(w, v, a, png_ptr->background_1.blue); + if (optimize == 0) w = gamma_from_1[w]; + *(sp + 2) = w; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_byte a = *(sp + 3); + + if (a == 0) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else if (a < 0xff) + { + png_composite(*sp, *sp, a, png_ptr->background.red); + + png_composite(*(sp + 1), *(sp + 1), a, + png_ptr->background.green); + + png_composite(*(sp + 2), *(sp + 2), a, + png_ptr->background.blue); + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 8) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else + { + png_uint_16 v, w; + + v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(w, v, a, png_ptr->background_1.red); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); + + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; + png_composite_16(w, v, a, png_ptr->background_1.green); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 2) = (png_byte)((w >> 8) & 0xff); + *(sp + 3) = (png_byte)(w & 0xff); + + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; + png_composite_16(w, v, a, png_ptr->background_1.blue); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 4) = (png_byte)((w >> 8) & 0xff); + *(sp + 5) = (png_byte)(w & 0xff); + } + } + } + + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 8) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == 0) + { + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else if (a < 0xffff) + { + png_uint_16 v; + + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + png_composite_16(v, r, a, png_ptr->background.red); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + png_composite_16(v, g, a, png_ptr->background.green); + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + png_composite_16(v, b, a, png_ptr->background.blue); + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + + default: + break; + } +} +#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Gamma correct the image, avoiding the alpha channel. Make sure + * you do this after you deal with the transparency issue on grayscale + * or RGB images. If your bit depth is 8, use gamma_table, if it + * is 16, use gamma_16_table and gamma_shift. Build these with + * build_gamma_table(). + */ +static void +png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; + int gamma_shift = png_ptr->gamma_shift; + + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_gamma"); + + if (((row_info->bit_depth <= 8 && gamma_table != NULL) || + (row_info->bit_depth == 16 && gamma_16_table != NULL))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + + *sp = gamma_table[*sp]; + sp++; + + *sp = gamma_table[*sp]; + sp++; + + sp++; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp += 2; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY: + { + if (row_info->bit_depth == 2) + { + sp = row; + for (i = 0; i < row_width; i += 4) + { + int a = *sp & 0xc0; + int b = *sp & 0x30; + int c = *sp & 0x0c; + int d = *sp & 0x03; + + *sp = (png_byte)( + ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| + ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| + ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| + ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); + sp++; + } + } + + if (row_info->bit_depth == 4) + { + sp = row; + for (i = 0; i < row_width; i += 2) + { + int msb = *sp & 0xf0; + int lsb = *sp & 0x0f; + + *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) + | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); + sp++; + } + } + + else if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + } + } + + else if (row_info->bit_depth == 16) + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + + default: + break; + } + } +} +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* Encode the alpha channel to the output gamma (the input channel is always + * linear.) Called only with color types that have an alpha channel. Needs the + * from_1 tables. + */ +static void +png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_encode_alpha"); + + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + if (row_info->bit_depth == 8) + { + png_bytep table = png_ptr->gamma_from_1; + + if (table != NULL) + { + int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; + + /* The alpha channel is the last component: */ + row += step - 1; + + for (; row_width > 0; --row_width, row += step) + *row = table[*row]; + + return; + } + } + + else if (row_info->bit_depth == 16) + { + png_uint_16pp table = png_ptr->gamma_16_from_1; + int gamma_shift = png_ptr->gamma_shift; + + if (table != NULL) + { + int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; + + /* The alpha channel is the last component: */ + row += step - 2; + + for (; row_width > 0; --row_width, row += step) + { + png_uint_16 v; + + v = table[*(row + 1) >> gamma_shift][*row]; + *row = (png_byte)((v >> 8) & 0xff); + *(row + 1) = (png_byte)(v & 0xff); + } + + return; + } + } + } + + /* Only get to here if called with a weird row_info; no harm has been done, + * so just issue a warning. + */ + png_warning(png_ptr, "png_do_encode_alpha: unexpected call"); +} +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expands a palette row to an RGB or RGBA row depending + * upon whether you supply trans and num_trans. + */ +static void +png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, + png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha, + int num_trans) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand_palette"); + + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row + (size_t)((row_width - 1) >> 3); + dp = row + (size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 1; + + else + *dp = 0; + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + sp = row + (size_t)((row_width - 1) >> 2); + dp = row + (size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)value; + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + sp = row + (size_t)((row_width - 1) >> 1); + dp = row + (size_t)row_width - 1; + shift = (int)((row_width & 0x01) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)value; + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift += 4; + + dp--; + } + break; + } + + default: + break; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (row_info->bit_depth == 8) + { + { + if (num_trans > 0) + { + sp = row + (size_t)row_width - 1; + dp = row + ((size_t)row_width << 2) - 1; + + i = 0; +#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE + if (png_ptr->riffled_palette != NULL) + { + /* The RGBA optimization works with png_ptr->bit_depth == 8 + * but sometimes row_info->bit_depth has been changed to 8. + * In these cases, the palette hasn't been riffled. + */ + i = png_do_expand_palette_rgba8_neon(png_ptr, row_info, row, + &sp, &dp); + } +#else + PNG_UNUSED(png_ptr) +#endif + + for (; i < row_width; i++) + { + if ((int)(*sp) >= num_trans) + *dp-- = 0xff; + else + *dp-- = trans_alpha[*sp]; + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + row_info->color_type = 6; + row_info->channels = 4; + } + + else + { + sp = row + (size_t)row_width - 1; + dp = row + (size_t)(row_width * 3) - 1; + i = 0; +#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE + i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row, + &sp, &dp); +#else + PNG_UNUSED(png_ptr) +#endif + + for (; i < row_width; i++) + { + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + row_info->color_type = 2; + row_info->channels = 3; + } + } + } + } +} + +/* If the bit depth < 8, it is expanded to 8. Also, if the already + * expanded transparency value is supplied, an alpha channel is built. + */ +static void +png_do_expand(png_row_infop row_info, png_bytep row, + png_const_color_16p trans_color) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand"); + + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + unsigned int gray = trans_color != NULL ? trans_color->gray : 0; + + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + gray = (gray & 0x01) * 0xff; + sp = row + (size_t)((row_width - 1) >> 3); + dp = row + (size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 0xff; + + else + *dp = 0; + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + gray = (gray & 0x03) * 0x55; + sp = row + (size_t)((row_width - 1) >> 2); + dp = row + (size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)(value | (value << 2) | (value << 4) | + (value << 6)); + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + gray = (gray & 0x0f) * 0x11; + sp = row + (size_t)((row_width - 1) >> 1); + dp = row + (size_t)row_width - 1; + shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)(value | (value << 4)); + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift = 4; + + dp--; + } + break; + } + + default: + break; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (trans_color != NULL) + { + if (row_info->bit_depth == 8) + { + gray = gray & 0xff; + sp = row + (size_t)row_width - 1; + dp = row + ((size_t)row_width << 1) - 1; + + for (i = 0; i < row_width; i++) + { + if ((*sp & 0xffU) == gray) + *dp-- = 0; + + else + *dp-- = 0xff; + + *dp-- = *sp--; + } + } + + else if (row_info->bit_depth == 16) + { + unsigned int gray_high = (gray >> 8) & 0xff; + unsigned int gray_low = gray & 0xff; + sp = row + row_info->rowbytes - 1; + dp = row + (row_info->rowbytes << 1) - 1; + for (i = 0; i < row_width; i++) + { + if ((*(sp - 1) & 0xffU) == gray_high && + (*(sp) & 0xffU) == gray_low) + { + *dp-- = 0; + *dp-- = 0; + } + + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + + *dp-- = *sp--; + *dp-- = *sp--; + } + } + + row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + row_info->channels = 2; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_width); + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && + trans_color != NULL) + { + if (row_info->bit_depth == 8) + { + png_byte red = (png_byte)(trans_color->red & 0xff); + png_byte green = (png_byte)(trans_color->green & 0xff); + png_byte blue = (png_byte)(trans_color->blue & 0xff); + sp = row + (size_t)row_info->rowbytes - 1; + dp = row + ((size_t)row_width << 2) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) + *dp-- = 0; + + else + *dp-- = 0xff; + + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); + png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); + png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); + png_byte red_low = (png_byte)(trans_color->red & 0xff); + png_byte green_low = (png_byte)(trans_color->green & 0xff); + png_byte blue_low = (png_byte)(trans_color->blue & 0xff); + sp = row + row_info->rowbytes - 1; + dp = row + ((size_t)row_width << 3) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 5) == red_high && + *(sp - 4) == red_low && + *(sp - 3) == green_high && + *(sp - 2) == green_low && + *(sp - 1) == blue_high && + *(sp ) == blue_low) + { + *dp-- = 0; + *dp-- = 0; + } + + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + row_info->channels = 4; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } +} +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* If the bit depth is 8 and the color type is not a palette type expand the + * whole row to 16 bits. Has no effect otherwise. + */ +static void +png_do_expand_16(png_row_infop row_info, png_bytep row) +{ + if (row_info->bit_depth == 8 && + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + /* The row have a sequence of bytes containing [0..255] and we need + * to turn it into another row containing [0..65535], to do this we + * calculate: + * + * (input / 255) * 65535 + * + * Which happens to be exactly input * 257 and this can be achieved + * simply by byte replication in place (copying backwards). + */ + png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */ + png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */ + while (dp > sp) + { + dp[-2] = dp[-1] = *--sp; dp -= 2; + } + + row_info->rowbytes *= 2; + row_info->bit_depth = 16; + row_info->pixel_depth = (png_byte)(row_info->channels * 16); + } +} +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +static void +png_do_quantize(png_row_infop row_info, png_bytep row, + png_const_bytep palette_lookup, png_const_bytep quantize_lookup) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_quantize"); + + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + + /* This looks real messy, but the compiler will reduce + * it down to a reasonable formula. For example, with + * 5 bits per color, we get: + * p = (((r >> 3) & 0x1f) << 10) | + * (((g >> 3) & 0x1f) << 5) | + * ((b >> 3) & 0x1f); + */ + p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + palette_lookup != NULL) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + sp++; + + p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + + else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + quantize_lookup) + { + sp = row; + + for (i = 0; i < row_width; i++, sp++) + { + *sp = quantize_lookup[*sp]; + } + } + } +} +#endif /* READ_QUANTIZE */ + +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ +void /* PRIVATE */ +png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_read_transformations"); + + if (png_ptr->row_buf == NULL) + { + /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this + * error is incredibly rare and incredibly easy to debug without this + * information. + */ + png_error(png_ptr, "NULL row buffer"); + } + + /* The following is debugging; prior to 1.5.4 the code was never compiled in; + * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro + * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for + * all transformations, however in practice the ROW_INIT always gets done on + * demand, if necessary. + */ + if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + /* Application has failed to call either png_read_start_image() or + * png_read_update_info() after setting transforms that expand pixels. + * This check added to libpng-1.2.19 (but not enabled until 1.5.4). + */ + png_error(png_ptr, "Uninitialized row"); + } + +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { +#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE + if ((png_ptr->num_trans > 0) && (png_ptr->bit_depth == 8)) + { + if (png_ptr->riffled_palette == NULL) + { + /* Initialize the accelerated palette expansion. */ + png_ptr->riffled_palette = + (png_bytep)png_malloc(png_ptr, 256 * 4); + png_riffle_palette_neon(png_ptr); + } + } +#endif + png_do_expand_palette(png_ptr, row_info, png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); + } + + else + { + if (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + png_do_expand(row_info, png_ptr->row_buf + 1, + &(png_ptr->trans_color)); + + else + png_do_expand(row_info, png_ptr->row_buf + 1, NULL); + } + } +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, row_info, + png_ptr->row_buf + 1); + + if (rgb_error != 0) + { + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + } + } +#endif + +/* From Andreas Dilger e-mail to png-implement, 26 March 1998: + * + * In most cases, the "simple transparency" should be done prior to doing + * gray-to-RGB, or you will have to test 3x as many bytes to check if a + * pixel is transparent. You would also need to make sure that the + * transparency information is upgraded to RGB. + * + * To summarize, the current flow is: + * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + * with background "in place" if transparent, + * convert to RGB if necessary + * - Gray + alpha -> composite with gray background and remove alpha bytes, + * convert to RGB if necessary + * + * To support RGB backgrounds for gray images we need: + * - Gray + simple transparency -> convert to RGB + simple transparency, + * compare 3 or 6 bytes and composite with + * background "in place" if transparent + * (3x compare/pixel compared to doing + * composite with gray bkgrnd) + * - Gray + alpha -> convert to RGB + alpha, composite with background and + * remove alpha bytes (3x float + * operations/pixel compared with composite + * on gray background) + * + * Greg's change will do this. The reason it wasn't done before is for + * performance, as this increases the per-pixel operations. If we would check + * in advance if the background was gray or RGB, and position the gray-to-RGB + * transform appropriately, then it would save a lot of work/time. + */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) != 0 && +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Because RGB_TO_GRAY does the gamma transform. */ + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 && +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* Because PNG_COMPOSE does the gamma transform if there is something to + * do (if there is an alpha channel or transparency.) + */ + !((png_ptr->transformations & PNG_COMPOSE) != 0 && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) && +#endif + /* Because png_init_read_transformations transforms the palette, unless + * RGB_TO_GRAY will do the transform. + */ + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* There is no harm in doing both of these because only one has any effect, + * by putting the 'scale' option first if the app asks for scale (either by + * calling the API or in a TRANSFORM flag) this is what happens. + */ + if ((png_ptr->transformations & PNG_16_TO_8) != 0) + png_do_chop(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) + { + png_do_quantize(row_info, png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); + + if (row_info->rowbytes == 0) + png_error(png_ptr, "png_do_quantize returned rowbytes=0"); + } +#endif /* READ_QUANTIZE */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + /* Do the expansion now, after all the arithmetic has been done. Notice + * that previous transformations can handle the PNG_EXPAND_16 flag if this + * is efficient (particularly true in the case of gamma correction, where + * better accuracy results faster!) + */ + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) + png_do_expand_16(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* NOTE: moved here in 1.5.4 (from much later in this list.) */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_unshift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_unpack(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Added at libpng-1.5.10 */ + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, row_info); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_read_filler(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_16BIT_SUPPORTED +#ifdef PNG_READ_SWAP_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth != 0) + row_info->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels != 0) + row_info->channels = png_ptr->user_transform_channels; +#endif + row_info->pixel_depth = (png_byte)(row_info->bit_depth * + row_info->channels); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); + } +#endif +} + +#endif /* READ_TRANSFORMS */ +#endif /* READ */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngrutil.c b/widget/milsko/milskosrc/external/libpng/src/pngrutil.c new file mode 100644 index 0000000000..e7c7bbe48e --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngrutil.c @@ -0,0 +1,4695 @@ +/* pngrutil.c - utilities to read a PNG file + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that are only called from within + * libpng itself during the course of reading an image. + */ + +#include "pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +/* The minimum 'zlib' stream is assumed to be just the 2 byte header, 5 bytes + * minimum 'deflate' stream, and the 4 byte checksum. + */ +#define LZ77Min (2U+5U+4U) + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ + +/* Start of interlace block */ +static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; +/* Offset to next interlace block */ +static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +/* Start of interlace block in the y direction */ +static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; +/* Offset to next interlace block in the y direction */ +static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + +/* TODO: Move these arrays to a common utility module to avoid duplication. */ +#endif + +png_uint_32 PNGAPI +png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + + if (uval > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range"); + + return uval; +} + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +/* NOTE: the read macros will obscure these definitions, so that if + * PNG_USE_READ_MACROS is set the library will not use them internally, + * but the APIs will still be available externally. + * + * The parentheses around "PNGAPI function_name" in the following three + * functions are necessary because they allow the macros to co-exist with + * these (unused but exported) functions. + */ + +/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ +png_uint_32 (PNGAPI +png_get_uint_32)(png_const_bytep buf) +{ + png_uint_32 uval = + ((png_uint_32)(*(buf )) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + ((png_uint_32)(*(buf + 3)) ) ; + + return uval; +} + +/* Grab a signed 32-bit integer from a buffer in big-endian format. The + * data is stored in the PNG file in two's complement format and there + * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore + * the following code does a two's complement to native conversion. + */ +png_int_32 (PNGAPI +png_get_int_32)(png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + if ((uval & 0x80000000) == 0) /* non-negative */ + return (png_int_32)uval; + + uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ + if ((uval & 0x80000000) == 0) /* no overflow */ + return -(png_int_32)uval; + /* The following has to be safe; this function only gets called on PNG data + * and if we get here that data is invalid. 0 is the most safe value and + * if not then an attacker would surely just generate a PNG with 0 instead. + */ + return 0; +} + +/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ +png_uint_16 (PNGAPI +png_get_uint_16)(png_const_bytep buf) +{ + /* ANSI-C requires an int value to accommodate at least 16 bits so this + * works and allows the compiler not to worry about possible narrowing + * on 32-bit systems. (Pre-ANSI systems did not make integers smaller + * than 16 bits either.) + */ + unsigned int val = + ((unsigned int)(*buf) << 8) + + ((unsigned int)(*(buf + 1))); + + return (png_uint_16)val; +} + +#endif /* READ_INT_FUNCTIONS */ + +/* Read and check the PNG file signature */ +void /* PRIVATE */ +png_read_sig(png_structrp png_ptr, png_inforp info_ptr) +{ + size_t num_checked, num_to_check; + + /* Exit if the user application does not expect a signature. */ + if (png_ptr->sig_bytes >= 8) + return; + + num_checked = png_ptr->sig_bytes; + num_to_check = 8 - num_checked; + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; +#endif + + /* The signature must be serialized in a single I/O call. */ + png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); + png_ptr->sig_bytes = 8; + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + if (num_checked < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +/* This function is called to verify that a chunk name is valid. + * Do this using the bit-whacking approach from contrib/tools/pngfix.c + * + * Copied from libpng 1.7. + */ +static int +check_chunk_name(png_uint_32 name) +{ + png_uint_32 t; + + /* Remove bit 5 from all but the reserved byte; this means + * every 8-bit unit must be in the range 65-90 to be valid. + * So bit 5 must be zero, bit 6 must be set and bit 7 zero. + */ + name &= ~PNG_U32(32,32,0,32); + t = (name & ~0x1f1f1f1fU) ^ 0x40404040U; + + /* Subtract 65 for each 8-bit quantity, this must not + * overflow and each byte must then be in the range 0-25. + */ + name -= PNG_U32(65,65,65,65); + t |= name; + + /* Subtract 26, handling the overflow which should set the + * top three bits of each byte. + */ + name -= PNG_U32(25,25,25,26); + t |= ~name; + + return (t & 0xe0e0e0e0U) == 0U; +} + +/* Read the chunk header (length + type name). + * Put the type name into png_ptr->chunk_name, and return the length. + */ +png_uint_32 /* PRIVATE */ +png_read_chunk_header(png_structrp png_ptr) +{ + png_byte buf[8]; + png_uint_32 chunk_name, length; + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; +#endif + + /* Read the length and the chunk name. png_struct::chunk_name is immediately + * updated even if they are detectably wrong. This aids error message + * handling by allowing png_chunk_error to be used. + */ + png_read_data(png_ptr, buf, 8); + length = png_get_uint_31(png_ptr, buf); + png_ptr->chunk_name = chunk_name = PNG_CHUNK_FROM_STRING(buf+4); + + /* Reset the crc and run it over the chunk name. */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, buf + 4, 4); + + png_debug2(0, "Reading chunk typeid = 0x%lx, length = %lu", + (unsigned long)png_ptr->chunk_name, (unsigned long)length); + + /* Sanity check the length (first by <= 0x80) and the chunk name. An error + * here indicates a broken stream and libpng has no recovery from this. + */ + if (buf[0] >= 0x80U) + png_chunk_error(png_ptr, "bad header (invalid length)"); + + /* Check to see if chunk name is valid. */ + if (!check_chunk_name(chunk_name)) + png_chunk_error(png_ptr, "bad header (invalid type)"); + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; +#endif + + return length; +} + +/* Read data, and (optionally) run it through the CRC. */ +void /* PRIVATE */ +png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) +{ + if (png_ptr == NULL) + return; + + png_read_data(png_ptr, buf, length); + png_calculate_crc(png_ptr, buf, length); +} + +/* Compare the CRC stored in the PNG file with that calculated by libpng from + * the data it has read thus far. + */ +static int +png_crc_error(png_structrp png_ptr, int handle_as_ancillary) +{ + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + /* There are four flags two for ancillary and two for critical chunks. The + * default setting of these flags is all zero. + * + * PNG_FLAG_CRC_ANCILLARY_USE + * PNG_FLAG_CRC_ANCILLARY_NOWARN + * USE+NOWARN: no CRC calculation (implemented here), else; + * NOWARN: png_chunk_error on error (implemented in png_crc_finish) + * else: png_chunk_warning on error (implemented in png_crc_finish) + * This is the default. + * + * I.e. NOWARN without USE produces png_chunk_error. The default setting + * where neither are set does the same thing. + * + * PNG_FLAG_CRC_CRITICAL_USE + * PNG_FLAG_CRC_CRITICAL_IGNORE + * IGNORE: no CRC calculation (implemented here), else; + * USE: png_chunk_warning on error (implemented in png_crc_finish) + * else: png_chunk_error on error (implemented in png_crc_finish) + * This is the default. + * + * This arose because of original mis-implementation and has persisted for + * compatibility reasons. + * + * TODO: the flag names are internal so maybe this can be changed to + * something comprehensible. + */ + if (handle_as_ancillary || PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + + else /* critical */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) + need_crc = 0; + } + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; +#endif + + /* The chunk CRC must be serialized in a single I/O call. */ + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc != 0) + { + crc = png_get_uint_32(crc_bytes); + return crc != png_ptr->crc; + } + + else + return 0; +} + +/* Optionally skip data and then check the CRC. Depending on whether we + * are reading an ancillary or critical chunk, and how the program has set + * things up, we may calculate the CRC on the data and print a message. + * Returns '1' if there was a CRC error, '0' otherwise. + * + * There is one public version which is used in most places and another which + * takes the value for the 'critical' flag to check. This allows PLTE and IEND + * handling code to ignore the CRC error and removes some confusing code + * duplication. + */ +static int +png_crc_finish_critical(png_structrp png_ptr, png_uint_32 skip, + int handle_as_ancillary) +{ + /* The size of the local buffer for inflate is a good guess as to a + * reasonable size to use for buffering reads from the application. + */ + while (skip > 0) + { + png_uint_32 len; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + len = (sizeof tmpbuf); + if (len > skip) + len = skip; + skip -= len; + + png_crc_read(png_ptr, tmpbuf, len); + } + + /* If 'handle_as_ancillary' has been requested and this is a critical chunk + * but PNG_FLAG_CRC_CRITICAL_IGNORE was set then png_read_crc did not, in + * fact, calculate the CRC so the ANCILLARY settings should not be used + * instead. + */ + if (handle_as_ancillary && + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) + handle_as_ancillary = 0; + + /* TODO: this might be more comprehensible if png_crc_error was inlined here. + */ + if (png_crc_error(png_ptr, handle_as_ancillary) != 0) + { + /* See above for the explanation of how the flags work. */ + if (handle_as_ancillary || PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ? + (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 : + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0) + png_chunk_warning(png_ptr, "CRC error"); + + else + png_chunk_error(png_ptr, "CRC error"); + + return 1; + } + + return 0; +} + +int /* PRIVATE */ +png_crc_finish(png_structrp png_ptr, png_uint_32 skip) +{ + return png_crc_finish_critical(png_ptr, skip, 0/*critical handling*/); +} + +#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ + defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\ + defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\ + defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_eXIf_SUPPORTED) ||\ + defined(PNG_SEQUENTIAL_READ_SUPPORTED) +/* Manage the read buffer; this simply reallocates the buffer if it is not small + * enough (or if it is not allocated). The routine returns a pointer to the + * buffer; if an error occurs and 'warn' is set the routine returns NULL, else + * it will call png_error on failure. + */ +static png_bytep +png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size) +{ + png_bytep buffer = png_ptr->read_buffer; + + if (new_size > png_chunk_max(png_ptr)) return NULL; + + if (buffer != NULL && new_size > png_ptr->read_buffer_size) + { + png_ptr->read_buffer = NULL; + png_ptr->read_buffer_size = 0; + png_free(png_ptr, buffer); + buffer = NULL; + } + + if (buffer == NULL) + { + buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size)); + + if (buffer != NULL) + { +# ifndef PNG_NO_MEMZERO /* for detecting UIM bugs **only** */ + memset(buffer, 0, new_size); /* just in case */ +# endif + png_ptr->read_buffer = buffer; + png_ptr->read_buffer_size = new_size; + } + } + + return buffer; +} +#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|eXIf|SEQUENTIAL_READ */ + +/* png_inflate_claim: claim the zstream for some nefarious purpose that involves + * decompression. Returns Z_OK on success, else a zlib error code. It checks + * the owner but, in final release builds, just issues a warning if some other + * chunk apparently owns the stream. Prior to release it does a png_error. + */ +static int +png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) +{ + if (png_ptr->zowner != 0) + { + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); +#if PNG_RELEASE_BUILD + png_chunk_warning(png_ptr, msg); + png_ptr->zowner = 0; +#else + png_chunk_error(png_ptr, msg); +#endif + } + + /* Implementation note: unlike 'png_deflate_claim' this internal function + * does not take the size of the data as an argument. Some efficiency could + * be gained by using this when it is known *if* the zlib stream itself does + * not record the number; however, this is an illusion: the original writer + * of the PNG may have selected a lower window size, and we really must + * follow that because, for systems with with limited capabilities, we + * would otherwise reject the application's attempts to use a smaller window + * size (zlib doesn't have an interface to say "this or lower"!). + * + * inflateReset2 was added to zlib 1.2.4; before this the window could not be + * reset, therefore it is necessary to always allocate the maximum window + * size with earlier zlibs just in case later compressed chunks need it. + */ + { + int ret; /* zlib return code */ +#if ZLIB_VERNUM >= 0x1240 + int window_bits = 0; + +# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW) + if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == + PNG_OPTION_ON) + { + window_bits = 15; + png_ptr->zstream_start = 0; /* fixed window size */ + } + + else + { + png_ptr->zstream_start = 1; + } +# endif + +#endif /* ZLIB_VERNUM >= 0x1240 */ + + /* Set this for safety, just in case the previous owner left pointers to + * memory allocations. + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + { +#if ZLIB_VERNUM >= 0x1240 + ret = inflateReset2(&png_ptr->zstream, window_bits); +#else + ret = inflateReset(&png_ptr->zstream); +#endif + } + + else + { +#if ZLIB_VERNUM >= 0x1240 + ret = inflateInit2(&png_ptr->zstream, window_bits); +#else + ret = inflateInit(&png_ptr->zstream); +#endif + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + +#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED + if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON) + /* Turn off validation of the ADLER32 checksum in IDAT chunks */ + ret = inflateValidate(&png_ptr->zstream, 0); +#endif + + if (ret == Z_OK) + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } + +#ifdef window_bits +# undef window_bits +#endif +} + +#if ZLIB_VERNUM >= 0x1240 +/* Handle the start of the inflate stream if we called inflateInit2(strm,0); + * in this case some zlib versions skip validation of the CINFO field and, in + * certain circumstances, libpng may end up displaying an invalid image, in + * contrast to implementations that call zlib in the normal way (e.g. libpng + * 1.5). + */ +int /* PRIVATE */ +png_zlib_inflate(png_structrp png_ptr, int flush) +{ + if (png_ptr->zstream_start && png_ptr->zstream.avail_in > 0) + { + if ((*png_ptr->zstream.next_in >> 4) > 7) + { + png_ptr->zstream.msg = "invalid window size (libpng)"; + return Z_DATA_ERROR; + } + + png_ptr->zstream_start = 0; + } + + return inflate(&png_ptr->zstream, flush); +} +#endif /* Zlib >= 1.2.4 */ + +#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED +#if defined(PNG_READ_zTXt_SUPPORTED) || defined (PNG_READ_iTXt_SUPPORTED) +/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to + * allow the caller to do multiple calls if required. If the 'finish' flag is + * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must + * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and + * Z_OK or Z_STREAM_END will be returned on success. + * + * The input and output sizes are updated to the actual amounts of data consumed + * or written, not the amount available (as in a z_stream). The data pointers + * are not changed, so the next input is (data+input_size) and the next + * available output is (output+output_size). + */ +static int +png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, + /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr, + /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr) +{ + if (png_ptr->zowner == owner) /* Else not claimed */ + { + int ret; + png_alloc_size_t avail_out = *output_size_ptr; + png_uint_32 avail_in = *input_size_ptr; + + /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it + * can't even necessarily handle 65536 bytes) because the type uInt is + * "16 bits or more". Consequently it is necessary to chunk the input to + * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the + * maximum value that can be stored in a uInt.) It is possible to set + * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have + * a performance advantage, because it reduces the amount of data accessed + * at each step and that may give the OS more time to page it in. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + /* avail_in and avail_out are set below from 'size' */ + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.avail_out = 0; + + /* Read directly into the output if it is available (this is set to + * a local buffer below if output is NULL). + */ + if (output != NULL) + png_ptr->zstream.next_out = output; + + do + { + uInt avail; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + + /* zlib INPUT BUFFER */ + /* The setting of 'avail_in' used to be outside the loop; by setting it + * inside it is possible to chunk the input to zlib and simply rely on + * zlib to advance the 'next_in' pointer. This allows arbitrary + * amounts of data to be passed through zlib at the unavoidable cost of + * requiring a window save (memcpy of up to 32768 output bytes) + * every ZLIB_IO_MAX input bytes. + */ + avail_in += png_ptr->zstream.avail_in; /* not consumed last time */ + + avail = ZLIB_IO_MAX; + + if (avail_in < avail) + avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */ + + avail_in -= avail; + png_ptr->zstream.avail_in = avail; + + /* zlib OUTPUT BUFFER */ + avail_out += png_ptr->zstream.avail_out; /* not written last time */ + + avail = ZLIB_IO_MAX; /* maximum zlib can process */ + + if (output == NULL) + { + /* Reset the output buffer each time round if output is NULL and + * make available the full buffer, up to 'remaining_space' + */ + png_ptr->zstream.next_out = local_buffer; + if ((sizeof local_buffer) < avail) + avail = (sizeof local_buffer); + } + + if (avail_out < avail) + avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */ + + png_ptr->zstream.avail_out = avail; + avail_out -= avail; + + /* zlib inflate call */ + /* In fact 'avail_out' may be 0 at this point, that happens at the end + * of the read when the final LZ end code was not passed at the end of + * the previous chunk of input data. Tell zlib if we have reached the + * end of the output buffer. + */ + ret = PNG_INFLATE(png_ptr, avail_out > 0 ? Z_NO_FLUSH : + (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } while (ret == Z_OK); + + /* For safety kill the local buffer pointer now */ + if (output == NULL) + png_ptr->zstream.next_out = NULL; + + /* Claw back the 'size' and 'remaining_space' byte counts. */ + avail_in += png_ptr->zstream.avail_in; + avail_out += png_ptr->zstream.avail_out; + + /* Update the input and output sizes; the updated values are the amount + * consumed or written, effectively the inverse of what zlib uses. + */ + if (avail_out > 0) + *output_size_ptr -= avail_out; + + if (avail_in > 0) + *input_size_ptr -= avail_in; + + /* Ensure png_ptr->zstream.msg is set (even in the success case!) */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + /* This is a bad internal error. The recovery assigns to the zstream msg + * pointer, which is not owned by the caller, but this is safe; it's only + * used on errors! + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } +} + +/* + * Decompress trailing data in a chunk. The assumption is that read_buffer + * points at an allocated area holding the contents of a chunk with a + * trailing compressed part. What we get back is an allocated area + * holding the original prefix part and an uncompressed version of the + * trailing part (the malloc area passed in is freed). + */ +static int +png_decompress_chunk(png_structrp png_ptr, + png_uint_32 chunklength, png_uint_32 prefix_size, + png_alloc_size_t *newlength /* must be initialized to the maximum! */, + int terminate /*add a '\0' to the end of the uncompressed data*/) +{ + /* TODO: implement different limits for different types of chunk. + * + * The caller supplies *newlength set to the maximum length of the + * uncompressed data, but this routine allocates space for the prefix and + * maybe a '\0' terminator too. We have to assume that 'prefix_size' is + * limited only by the maximum chunk size. + */ + png_alloc_size_t limit = png_chunk_max(png_ptr); + + if (limit >= prefix_size + (terminate != 0)) + { + int ret; + + limit -= prefix_size + (terminate != 0); + + if (limit < *newlength) + *newlength = limit; + + /* Now try to claim the stream. */ + ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); + + if (ret == Z_OK) + { + png_uint_32 lzsize = chunklength - prefix_size; + + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, + /* output: */ NULL, newlength); + + if (ret == Z_STREAM_END) + { + /* Use 'inflateReset' here, not 'inflateReset2' because this + * preserves the previously decided window size (otherwise it would + * be necessary to store the previous window size.) In practice + * this doesn't matter anyway, because png_inflate will call inflate + * with Z_FINISH in almost all cases, so the window will not be + * maintained. + */ + if (inflateReset(&png_ptr->zstream) == Z_OK) + { + /* Because of the limit checks above we know that the new, + * expanded, size will fit in a size_t (let alone an + * png_alloc_size_t). Use png_malloc_base here to avoid an + * extra OOM message. + */ + png_alloc_size_t new_size = *newlength; + png_alloc_size_t buffer_size = prefix_size + new_size + + (terminate != 0); + png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, + buffer_size)); + + if (text != NULL) + { + memset(text, 0, buffer_size); + + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + png_ptr->read_buffer + prefix_size, &lzsize, + text + prefix_size, newlength); + + if (ret == Z_STREAM_END) + { + if (new_size == *newlength) + { + if (terminate != 0) + text[prefix_size + *newlength] = 0; + + if (prefix_size > 0) + memcpy(text, png_ptr->read_buffer, prefix_size); + + { + png_bytep old_ptr = png_ptr->read_buffer; + + png_ptr->read_buffer = text; + png_ptr->read_buffer_size = buffer_size; + text = old_ptr; /* freed below */ + } + } + + else + { + /* The size changed on the second read, there can be no + * guarantee that anything is correct at this point. + * The 'msg' pointer has been set to "unexpected end of + * LZ stream", which is fine, but return an error code + * that the caller won't accept. + */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */ + + /* Free the text pointer (this is the old read_buffer on + * success) + */ + png_free(png_ptr, text); + + /* This really is very benign, but it's still an error because + * the extra space may otherwise be used as a Trojan Horse. + */ + if (ret == Z_STREAM_END && + chunklength - prefix_size != lzsize) + png_chunk_benign_error(png_ptr, "extra compressed data"); + } + + else + { + /* Out of memory allocating the buffer */ + ret = Z_MEM_ERROR; + png_zstream_error(png_ptr, Z_MEM_ERROR); + } + } + + else + { + /* inflateReset failed, store the error message */ + png_zstream_error(png_ptr, ret); + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + /* Release the claimed stream */ + png_ptr->zowner = 0; + } + + else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + return ret; + } + + else + { + /* Application/configuration limits exceeded */ + png_zstream_error(png_ptr, Z_MEM_ERROR); + return Z_MEM_ERROR; + } +} +#endif /* READ_zTXt || READ_iTXt */ +#endif /* READ_COMPRESSED_TEXT */ + +#ifdef PNG_READ_iCCP_SUPPORTED +/* Perform a partial read and decompress, producing 'avail_out' bytes and + * reading from the current chunk as required. + */ +static int +png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, + png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, + int finish) +{ + if (png_ptr->zowner == png_ptr->chunk_name) + { + int ret; + + /* next_in and avail_in must have been initialized by the caller. */ + png_ptr->zstream.next_out = next_out; + png_ptr->zstream.avail_out = 0; /* set in the loop */ + + do + { + if (png_ptr->zstream.avail_in == 0) + { + if (read_size > *chunk_bytes) + read_size = (uInt)*chunk_bytes; + *chunk_bytes -= read_size; + + if (read_size > 0) + png_crc_read(png_ptr, read_buffer, read_size); + + png_ptr->zstream.next_in = read_buffer; + png_ptr->zstream.avail_in = read_size; + } + + if (png_ptr->zstream.avail_out == 0) + { + uInt avail = ZLIB_IO_MAX; + if (avail > *out_size) + avail = (uInt)*out_size; + *out_size -= avail; + + png_ptr->zstream.avail_out = avail; + } + + /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all + * the available output is produced; this allows reading of truncated + * streams. + */ + ret = PNG_INFLATE(png_ptr, *chunk_bytes > 0 ? + Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } + while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); + + *out_size += png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ + + /* Ensure the error message pointer is always set: */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } +} +#endif /* READ_iCCP */ + +/* CHUNK HANDLING */ +/* Read and check the IDHR chunk */ +static png_handle_result_code +png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[13]; + png_uint_32 width, height; + int bit_depth, color_type, compression_type, filter_type; + int interlace_type; + + png_debug(1, "in png_handle_IHDR"); + + /* Length and position are checked by the caller. */ + + png_ptr->mode |= PNG_HAVE_IHDR; + + png_crc_read(png_ptr, buf, 13); + png_crc_finish(png_ptr, 0); + + width = png_get_uint_31(png_ptr, buf); + height = png_get_uint_31(png_ptr, buf + 4); + bit_depth = buf[8]; + color_type = buf[9]; + compression_type = buf[10]; + filter_type = buf[11]; + interlace_type = buf[12]; + + /* Set internal variables */ + png_ptr->width = width; + png_ptr->height = height; + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->interlaced = (png_byte)interlace_type; + png_ptr->color_type = (png_byte)color_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + + /* Find number of channels */ + switch (png_ptr->color_type) + { + default: /* invalid, png_set_IHDR calls png_error */ + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + png_ptr->channels = 1; + break; + + case PNG_COLOR_TYPE_RGB: + png_ptr->channels = 3; + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_ptr->channels = 2; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + png_ptr->channels = 4; + break; + } + + /* Set up other useful info */ + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); + png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); + png_debug1(3, "channels = %d", png_ptr->channels); + png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes); + + /* Rely on png_set_IHDR to completely validate the data and call png_error if + * it's wrong. + */ + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + color_type, interlace_type, compression_type, filter_type); + + return handled_ok; + PNG_UNUSED(length) +} + +/* Read and check the palette */ +/* TODO: there are several obvious errors in this code when handling + * out-of-place chunks and there is much over-complexity caused by trying to + * patch up the problems. + */ +static png_handle_result_code +png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_const_charp errmsg = NULL; + + png_debug(1, "in png_handle_PLTE"); + + /* 1.6.47: consistency. This used to be especially treated as a critical + * error even in an image which is not colour mapped, there isn't a good + * justification for treating some errors here one way and others another so + * everything uses the same logic. + */ + if ((png_ptr->mode & PNG_HAVE_PLTE) != 0) + errmsg = "duplicate"; + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + errmsg = "out of place"; + + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + errmsg = "ignored in grayscale PNG"; + + else if (length > 3*PNG_MAX_PALETTE_LENGTH || (length % 3) != 0) + errmsg = "invalid"; + + /* This drops PLTE in favour of tRNS or bKGD because both of those chunks + * can have an effect on the rendering of the image whereas PLTE only matters + * in the case of an 8-bit display with a decoder which controls the palette. + * + * The alternative here is to ignore the error and store the palette anyway; + * destroying the tRNS will definately cause problems. + * + * NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because + * the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and + * hIST all check for a preceding PLTE in these cases. + */ + else if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE && + (png_has_chunk(png_ptr, tRNS) || png_has_chunk(png_ptr, bKGD))) + errmsg = "out of place"; + + else + { + /* If the palette has 256 or fewer entries but is too large for the bit + * depth we don't issue an error to preserve the behavior of previous + * libpng versions. We silently truncate the unused extra palette entries + * here. + */ + const unsigned max_palette_length = + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + 1U << png_ptr->bit_depth : PNG_MAX_PALETTE_LENGTH; + + /* The cast is safe because 'length' is less than + * 3*PNG_MAX_PALETTE_LENGTH + */ + const unsigned num = (length > 3U*max_palette_length) ? + max_palette_length : (unsigned)length / 3U; + + unsigned i, j; + png_byte buf[3*PNG_MAX_PALETTE_LENGTH]; + png_color palette[PNG_MAX_PALETTE_LENGTH]; + + /* Read the chunk into the buffer then read to the end of the chunk. */ + png_crc_read(png_ptr, buf, num*3U); + png_crc_finish_critical(png_ptr, length - 3U*num, + /* Handle as ancillary if PLTE is optional: */ + png_ptr->color_type != PNG_COLOR_TYPE_PALETTE); + + for (i = 0U, j = 0U; i < num; i++) + { + palette[i].red = buf[j++]; + palette[i].green = buf[j++]; + palette[i].blue = buf[j++]; + } + + /* A valid PLTE chunk has been read */ + png_ptr->mode |= PNG_HAVE_PLTE; + + /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to + * its own copy of the palette. This has the side effect that when + * png_start_row is called (this happens after any call to + * png_read_update_info) the info_ptr palette gets changed. This is + * extremely unexpected and confusing. + * + * REVIEW: there have been consistent bugs in the past about gamma and + * similar transforms to colour mapped images being useless because the + * modified palette cannot be accessed because of the above. + * + * CONSIDER: Fix this by not sharing the palette in this way. But does + * this completely fix the problem? + */ + png_set_PLTE(png_ptr, info_ptr, palette, num); + return handled_ok; + } + + /* Here on error: errmsg is non NULL. */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_crc_finish(png_ptr, length); + png_chunk_error(png_ptr, errmsg); + } + + else /* not critical to this image */ + { + png_crc_finish_critical(png_ptr, length, 1/*handle as ancillary*/); + png_chunk_benign_error(png_ptr, errmsg); + } + + /* Because PNG_UNUSED(errmsg) does not work if all the uses are compiled out + * (this does happen). + */ + return errmsg != NULL ? handled_error : handled_error; +} + +/* On read the IDAT chunk is always handled specially, even if marked for + * unknown handling (this is allowed), so: + */ +#define png_handle_IDAT NULL + +static png_handle_result_code +png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_debug(1, "in png_handle_IEND"); + + png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + + if (length != 0) + png_chunk_benign_error(png_ptr, "invalid"); + + png_crc_finish_critical(png_ptr, length, 1/*handle as ancillary*/); + + return handled_ok; + PNG_UNUSED(info_ptr) +} + +#ifdef PNG_READ_gAMA_SUPPORTED +static png_handle_result_code +png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_uint_32 ugamma; + png_byte buf[4]; + + png_debug(1, "in png_handle_gAMA"); + + png_crc_read(png_ptr, buf, 4); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + ugamma = png_get_uint_32(buf); + + if (ugamma > PNG_UINT_31_MAX) + { + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + png_set_gAMA_fixed(png_ptr, info_ptr, (png_fixed_point)/*SAFE*/ugamma); + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. gAMA is + * at the end of the chain so simply check for an unset value. + */ + if (png_ptr->chunk_gamma == 0) + png_ptr->chunk_gamma = (png_fixed_point)/*SAFE*/ugamma; +#endif /*READ_GAMMA*/ + + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_gAMA NULL +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int truelen, i; + png_byte sample_depth; + png_byte buf[4]; + + png_debug(1, "in png_handle_sBIT"); + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + truelen = 3; + sample_depth = 8; + } + + else + { + truelen = png_ptr->channels; + sample_depth = png_ptr->bit_depth; + } + + if (length != truelen) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "bad length"); + return handled_error; + } + + buf[0] = buf[1] = buf[2] = buf[3] = sample_depth; + png_crc_read(png_ptr, buf, truelen); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + for (i=0; i sample_depth) + { + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[1]; + png_ptr->sig_bit.blue = buf[2]; + png_ptr->sig_bit.alpha = buf[3]; + } + + else /* grayscale */ + { + png_ptr->sig_bit.gray = buf[0]; + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[0]; + png_ptr->sig_bit.blue = buf[0]; + png_ptr->sig_bit.alpha = buf[1]; + } + + png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); + return handled_ok; +} +#else +# define png_handle_sBIT NULL +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +static png_int_32 +png_get_int_32_checked(png_const_bytep buf, int *error) +{ + png_uint_32 uval = png_get_uint_32(buf); + if ((uval & 0x80000000) == 0) /* non-negative */ + return (png_int_32)uval; + + uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ + if ((uval & 0x80000000) == 0) /* no overflow */ + return -(png_int_32)uval; + + /* This version of png_get_int_32 has a way of returning the error to the + * caller, so: + */ + *error = 1; + return 0; /* Safe */ +} + +static png_handle_result_code /* PRIVATE */ +png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + int error = 0; + png_xy xy; + png_byte buf[32]; + + png_debug(1, "in png_handle_cHRM"); + + png_crc_read(png_ptr, buf, 32); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + xy.whitex = png_get_int_32_checked(buf + 0, &error); + xy.whitey = png_get_int_32_checked(buf + 4, &error); + xy.redx = png_get_int_32_checked(buf + 8, &error); + xy.redy = png_get_int_32_checked(buf + 12, &error); + xy.greenx = png_get_int_32_checked(buf + 16, &error); + xy.greeny = png_get_int_32_checked(buf + 20, &error); + xy.bluex = png_get_int_32_checked(buf + 24, &error); + xy.bluey = png_get_int_32_checked(buf + 28, &error); + + if (error) + { + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + /* png_set_cHRM may complain about some of the values but this doesn't matter + * because it was a cHRM and it did have vaguely (if, perhaps, ridiculous) + * values. Ridiculousity will be checked if the values are used later. + */ + png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy, + xy.greenx, xy.greeny, xy.bluex, xy.bluey); + + /* We only use 'chromaticities' for RGB to gray */ +# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* There is no need to check sRGB here, cICP is NYI and iCCP is not + * supported so just check mDCV. + */ + if (!png_has_chunk(png_ptr, mDCV)) + { + png_ptr->chromaticities = xy; + } +# endif /* READ_RGB_TO_GRAY */ + + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_cHRM NULL +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte intent; + + png_debug(1, "in png_handle_sRGB"); + + png_crc_read(png_ptr, &intent, 1); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + /* This checks the range of the "rendering intent" because it is specified in + * the PNG spec itself; the "reserved" values will result in the chunk not + * being accepted, just as they do with the various "reserved" values in + * IHDR. + */ + if (intent > 3/*PNGv3 spec*/) + { + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + png_set_sRGB(png_ptr, info_ptr, intent); + /* NOTE: png_struct::chromaticities is not set here because the RGB to gray + * coefficients are known without a need for the chromaticities. + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. iCCP is + * not supported by libpng so the only requirement is to check for cICP + * setting the gamma (this is NYI, but this check is safe.) + */ + if (!png_has_chunk(png_ptr, cICP) || png_ptr->chunk_gamma == 0) + png_ptr->chunk_gamma = PNG_GAMMA_sRGB_INVERSE; +#endif /*READ_GAMMA*/ + + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_sRGB NULL +#endif /* READ_sRGB */ + +#ifdef PNG_READ_iCCP_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle profiles that are > 64K under DOS */ +{ + png_const_charp errmsg = NULL; /* error message output, or no error */ + int finished = 0; /* crc checked */ + + png_debug(1, "in png_handle_iCCP"); + + /* PNGv3: allow PNG files with both sRGB and iCCP because the PNG spec only + * ever said that there "should" be only one, not "shall" and the PNGv3 + * colour chunk precedence rules give a handling for this case anyway. + */ + { + uInt read_length, keyword_length; + char keyword[81]; + + /* Find the keyword; the keyword plus separator and compression method + * bytes can be at most 81 characters long. + */ + read_length = 81; /* maximum */ + if (read_length > length) + read_length = (uInt)/*SAFE*/length; + + png_crc_read(png_ptr, (png_bytep)keyword, read_length); + length -= read_length; + + if (length < LZ77Min) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too short"); + return handled_error; + } + + keyword_length = 0; + while (keyword_length < 80 && keyword_length < read_length && + keyword[keyword_length] != 0) + ++keyword_length; + + /* TODO: make the keyword checking common */ + if (keyword_length >= 1 && keyword_length <= 79) + { + /* We only understand '0' compression - deflate - so if we get a + * different value we can't safely decode the chunk. + */ + if (keyword_length+1 < read_length && + keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE) + { + read_length -= keyword_length+2; + + if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) + { + Byte profile_header[132]={0}; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + png_alloc_size_t size = (sizeof profile_header); + + png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); + png_ptr->zstream.avail_in = read_length; + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, profile_header, &size, + 0/*finish: don't, because the output is too small*/); + + if (size == 0) + { + /* We have the ICC profile header; do the basic header checks. + */ + png_uint_32 profile_length = png_get_uint_32(profile_header); + + if (png_icc_check_length(png_ptr, keyword, profile_length) != + 0) + { + /* The length is apparently ok, so we can check the 132 + * byte header. + */ + if (png_icc_check_header(png_ptr, keyword, profile_length, + profile_header, png_ptr->color_type) != 0) + { + /* Now read the tag table; a variable size buffer is + * needed at this point, allocate one for the whole + * profile. The header check has already validated + * that none of this stuff will overflow. + */ + png_uint_32 tag_count = + png_get_uint_32(profile_header + 128); + png_bytep profile = png_read_buffer(png_ptr, + profile_length); + + if (profile != NULL) + { + memcpy(profile, profile_header, + (sizeof profile_header)); + + size = 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header), &size, 0); + + /* Still expect a buffer error because we expect + * there to be some tag data! + */ + if (size == 0) + { + if (png_icc_check_tag_table(png_ptr, + keyword, profile_length, profile) != 0) + { + /* The profile has been validated for basic + * security issues, so read the whole thing in. + */ + size = profile_length - (sizeof profile_header) + - 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header) + + 12 * tag_count, &size, 1/*finish*/); + + if (length > 0 && !(png_ptr->flags & + PNG_FLAG_BENIGN_ERRORS_WARN)) + errmsg = "extra compressed data"; + + /* But otherwise allow extra data: */ + else if (size == 0) + { + if (length > 0) + { + /* This can be handled completely, so + * keep going. + */ + png_chunk_warning(png_ptr, + "extra compressed data"); + } + + png_crc_finish(png_ptr, length); + finished = 1; + + /* Steal the profile for info_ptr. */ + if (info_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, + PNG_FREE_ICCP, 0); + + info_ptr->iccp_name = png_voidcast(char*, + png_malloc_base(png_ptr, + keyword_length+1)); + if (info_ptr->iccp_name != NULL) + { + memcpy(info_ptr->iccp_name, keyword, + keyword_length+1); + info_ptr->iccp_proflen = + profile_length; + info_ptr->iccp_profile = profile; + png_ptr->read_buffer = NULL; /*steal*/ + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; + } + + else + errmsg = "out of memory"; + } + + /* else the profile remains in the read + * buffer which gets reused for subsequent + * chunks. + */ + + if (errmsg == NULL) + { + png_ptr->zowner = 0; + return handled_ok; + } + } + if (errmsg == NULL) + errmsg = png_ptr->zstream.msg; + } + /* else png_icc_check_tag_table output an error */ + } + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "out of memory"; + } + + /* else png_icc_check_header output an error */ + } + + /* else png_icc_check_length output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + + /* Release the stream */ + png_ptr->zowner = 0; + } + + else /* png_inflate_claim failed */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "bad compression method"; /* or missing */ + } + + else + errmsg = "bad keyword"; + } + + /* Failure: the reason is in 'errmsg' */ + if (finished == 0) + png_crc_finish(png_ptr, length); + + if (errmsg != NULL) /* else already output */ + png_chunk_benign_error(png_ptr, errmsg); + + return handled_error; +} +#else +# define png_handle_iCCP NULL +#endif /* READ_iCCP */ + +#ifdef PNG_READ_sPLT_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_bytep entry_start, buffer; + png_sPLT_t new_palette; + png_sPLT_entryp pp; + png_uint_32 data_length; + int entry_size, i; + png_uint_32 skip = 0; + png_uint_32 dl; + size_t max_dl; + + png_debug(1, "in png_handle_sPLT"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return handled_error; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for sPLT"); + png_crc_finish(png_ptr, length); + return handled_error; + } + } +#endif + + buffer = png_read_buffer(png_ptr, length+1); + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; + } + + + /* WARNING: this may break if size_t is less than 32 bits; it is assumed + * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a + * potential breakage point if the types in pngconf.h aren't exactly right. + */ + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip) != 0) + return handled_error; + + buffer[length] = 0; + + for (entry_start = buffer; *entry_start; entry_start++) + /* Empty loop to find end of name */ ; + + ++entry_start; + + /* A sample depth should follow the separator, and we should be on it */ + if (length < 2U || entry_start > buffer + (length - 2U)) + { + png_warning(png_ptr, "malformed sPLT chunk"); + return handled_error; + } + + new_palette.depth = *entry_start++; + entry_size = (new_palette.depth == 8 ? 6 : 10); + /* This must fit in a png_uint_32 because it is derived from the original + * chunk data length. + */ + data_length = length - (png_uint_32)(entry_start - buffer); + + /* Integrity-check the data length */ + if ((data_length % (unsigned int)entry_size) != 0) + { + png_warning(png_ptr, "sPLT chunk has bad length"); + return handled_error; + } + + dl = (png_uint_32)(data_length / (unsigned int)entry_size); + max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); + + if (dl > max_dl) + { + png_warning(png_ptr, "sPLT chunk too long"); + return handled_error; + } + + new_palette.nentries = (png_int_32)(data_length / (unsigned int)entry_size); + + new_palette.entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, + (png_alloc_size_t) new_palette.nentries * (sizeof (png_sPLT_entry))); + + if (new_palette.entries == NULL) + { + png_warning(png_ptr, "sPLT chunk requires too much memory"); + return handled_error; + } + + for (i = 0; i < new_palette.nentries; i++) + { + pp = new_palette.entries + i; + + if (new_palette.depth == 8) + { + pp->red = *entry_start++; + pp->green = *entry_start++; + pp->blue = *entry_start++; + pp->alpha = *entry_start++; + } + + else + { + pp->red = png_get_uint_16(entry_start); entry_start += 2; + pp->green = png_get_uint_16(entry_start); entry_start += 2; + pp->blue = png_get_uint_16(entry_start); entry_start += 2; + pp->alpha = png_get_uint_16(entry_start); entry_start += 2; + } + + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } + + /* Discard all chunk data except the name and stash that */ + new_palette.name = (png_charp)buffer; + + png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); + + png_free(png_ptr, new_palette.entries); + return handled_ok; +} +#else +# define png_handle_sPLT NULL +#endif /* READ_sPLT */ + +#ifdef PNG_READ_tRNS_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_tRNS"); + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + png_byte buf[2]; + + if (length != 2) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + png_crc_read(png_ptr, buf, 2); + png_ptr->num_trans = 1; + png_ptr->trans_color.gray = png_get_uint_16(buf); + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_byte buf[6]; + + if (length != 6) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + png_crc_read(png_ptr, buf, length); + png_ptr->num_trans = 1; + png_ptr->trans_color.red = png_get_uint_16(buf); + png_ptr->trans_color.green = png_get_uint_16(buf + 2); + png_ptr->trans_color.blue = png_get_uint_16(buf + 4); + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return handled_error; + } + + if (length > (unsigned int) png_ptr->num_palette || + length > (unsigned int) PNG_MAX_PALETTE_LENGTH || + length == 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + png_crc_read(png_ptr, readbuf, length); + png_ptr->num_trans = (png_uint_16)length; + } + + else + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid with alpha channel"); + return handled_error; + } + + if (png_crc_finish(png_ptr, 0) != 0) + { + png_ptr->num_trans = 0; + return handled_error; + } + + /* TODO: this is a horrible side effect in the palette case because the + * png_struct ends up with a pointer to the tRNS buffer owned by the + * png_info. Fix this. + */ + png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, + &(png_ptr->trans_color)); + return handled_ok; +} +#else +# define png_handle_tRNS NULL +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int truelen; + png_byte buf[6]; + png_color_16 background; + + png_debug(1, "in png_handle_bKGD"); + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return handled_error; + } + + truelen = 1; + } + + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + truelen = 6; + + else + truelen = 2; + + if (length != truelen) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + png_crc_read(png_ptr, buf, truelen); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + /* We convert the index value into RGB components so that we can allow + * arbitrary RGB values for background when we have transparency, and + * so it is easy to determine the RGB values of the background color + * from the info_ptr struct. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + background.index = buf[0]; + + if (info_ptr != NULL && info_ptr->num_palette != 0) + { + if (buf[0] >= info_ptr->num_palette) + { + png_chunk_benign_error(png_ptr, "invalid index"); + return handled_error; + } + + background.red = (png_uint_16)png_ptr->palette[buf[0]].red; + background.green = (png_uint_16)png_ptr->palette[buf[0]].green; + background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue; + } + + else + background.red = background.green = background.blue = 0; + + background.gray = 0; + } + + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */ + { + if (png_ptr->bit_depth <= 8) + { + if (buf[0] != 0 || buf[1] >= (unsigned int)(1 << png_ptr->bit_depth)) + { + png_chunk_benign_error(png_ptr, "invalid gray level"); + return handled_error; + } + } + + background.index = 0; + background.red = + background.green = + background.blue = + background.gray = png_get_uint_16(buf); + } + + else + { + if (png_ptr->bit_depth <= 8) + { + if (buf[0] != 0 || buf[2] != 0 || buf[4] != 0) + { + png_chunk_benign_error(png_ptr, "invalid color"); + return handled_error; + } + } + + background.index = 0; + background.red = png_get_uint_16(buf); + background.green = png_get_uint_16(buf + 2); + background.blue = png_get_uint_16(buf + 4); + background.gray = 0; + } + + png_set_bKGD(png_ptr, info_ptr, &background); + return handled_ok; +} +#else +# define png_handle_bKGD NULL +#endif + +#ifdef PNG_READ_cICP_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_cICP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[4]; + + png_debug(1, "in png_handle_cICP"); + + png_crc_read(png_ptr, buf, 4); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + png_set_cICP(png_ptr, info_ptr, buf[0], buf[1], buf[2], buf[3]); + + /* We only use 'chromaticities' for RGB to gray */ +# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if (!png_has_chunk(png_ptr, mDCV)) + { + /* TODO: png_ptr->chromaticities = chromaticities; */ + } +# endif /* READ_RGB_TO_GRAY */ + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. cICP is + * at the head so simply set the gamma if it can be determined. If not + * chunk_gamma remains unchanged; sRGB and gAMA handling check it for + * being zero. + */ + /* TODO: set png_struct::chunk_gamma when possible */ +#endif /*READ_GAMMA*/ + + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_cICP NULL +#endif + +#ifdef PNG_READ_cLLI_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_cLLI(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[8]; + + png_debug(1, "in png_handle_cLLI"); + + png_crc_read(png_ptr, buf, 8); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + /* The error checking happens here, this puts it in just one place: */ + png_set_cLLI_fixed(png_ptr, info_ptr, png_get_uint_32(buf), + png_get_uint_32(buf+4)); + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_cLLI NULL +#endif + +#ifdef PNG_READ_mDCV_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_mDCV(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_xy chromaticities; + png_byte buf[24]; + + png_debug(1, "in png_handle_mDCV"); + + png_crc_read(png_ptr, buf, 24); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + /* The error checking happens here, this puts it in just one place. The + * odd /50000 scaling factor makes it more difficult but the (x.y) values are + * only two bytes so a <<1 is safe. + * + * WARNING: the PNG specification defines the cHRM chunk to **start** with + * the white point (x,y). The W3C PNG v3 specification puts the white point + * **after* R,G,B. The x,y values in mDCV are also scaled by 50,000 and + * stored in just two bytes, whereas those in cHRM are scaled by 100,000 and + * stored in four bytes. This is very, very confusing. These APIs remove + * the confusion by copying the existing, well established, API. + */ + chromaticities.redx = png_get_uint_16(buf+ 0U) << 1; /* red x */ + chromaticities.redy = png_get_uint_16(buf+ 2U) << 1; /* red y */ + chromaticities.greenx = png_get_uint_16(buf+ 4U) << 1; /* green x */ + chromaticities.greeny = png_get_uint_16(buf+ 6U) << 1; /* green y */ + chromaticities.bluex = png_get_uint_16(buf+ 8U) << 1; /* blue x */ + chromaticities.bluey = png_get_uint_16(buf+10U) << 1; /* blue y */ + chromaticities.whitex = png_get_uint_16(buf+12U) << 1; /* white x */ + chromaticities.whitey = png_get_uint_16(buf+14U) << 1; /* white y */ + + png_set_mDCV_fixed(png_ptr, info_ptr, + chromaticities.whitex, chromaticities.whitey, + chromaticities.redx, chromaticities.redy, + chromaticities.greenx, chromaticities.greeny, + chromaticities.bluex, chromaticities.bluey, + png_get_uint_32(buf+16U), /* peak luminance */ + png_get_uint_32(buf+20U));/* minimum perceivable luminance */ + + /* We only use 'chromaticities' for RGB to gray */ +# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_ptr->chromaticities = chromaticities; +# endif /* READ_RGB_TO_GRAY */ + + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_mDCV NULL +#endif + +#ifdef PNG_READ_eXIf_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_bytep buffer = NULL; + + png_debug(1, "in png_handle_eXIf"); + + buffer = png_read_buffer(png_ptr, length); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + /* PNGv3: the code used to check the byte order mark at the start for MM or + * II, however PNGv3 states that the the first 4 bytes should be checked. + * The caller ensures that there are four bytes available. + */ + { + png_uint_32 header = png_get_uint_32(buffer); + + /* These numbers are copied from the PNGv3 spec: */ + if (header != 0x49492A00 && header != 0x4D4D002A) + { + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + } + + png_set_eXIf_1(png_ptr, info_ptr, length, buffer); + return handled_ok; +} +#else +# define png_handle_eXIf NULL +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int num, i; + png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_hIST"); + + /* This cast is safe because the chunk definition limits the length to a + * maximum of 1024 bytes. + * + * TODO: maybe use png_uint_32 anyway, not unsigned int, to reduce the + * casts. + */ + num = (unsigned int)length / 2 ; + + if (length != num * 2 || + num != (unsigned int)png_ptr->num_palette || + num > (unsigned int)PNG_MAX_PALETTE_LENGTH) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + for (i = 0; i < num; i++) + { + png_byte buf[2]; + + png_crc_read(png_ptr, buf, 2); + readbuf[i] = png_get_uint_16(buf); + } + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + png_set_hIST(png_ptr, info_ptr, readbuf); + return handled_ok; +} +#else +# define png_handle_hIST NULL +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_uint_32 res_x, res_y; + int unit_type; + + png_debug(1, "in png_handle_pHYs"); + + png_crc_read(png_ptr, buf, 9); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + res_x = png_get_uint_32(buf); + res_y = png_get_uint_32(buf + 4); + unit_type = buf[8]; + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_pHYs NULL +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_int_32 offset_x, offset_y; + int unit_type; + + png_debug(1, "in png_handle_oFFs"); + + png_crc_read(png_ptr, buf, 9); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + offset_x = png_get_int_32(buf); + offset_y = png_get_int_32(buf + 4); + unit_type = buf[8]; + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_oFFs NULL +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +/* Read the pCAL chunk (described in the PNG Extensions document) */ +static png_handle_result_code /* PRIVATE */ +png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_int_32 X0, X1; + png_byte type, nparams; + png_bytep buffer, buf, units, endptr; + png_charpp params; + int i; + + png_debug(1, "in png_handle_pCAL"); + png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", + length + 1); + + buffer = png_read_buffer(png_ptr, length+1); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + buffer[length] = 0; /* Null terminate the last string */ + + png_debug(3, "Finding end of pCAL purpose string"); + for (buf = buffer; *buf; buf++) + /* Empty loop */ ; + + endptr = buffer + length; + + /* We need to have at least 12 bytes after the purpose string + * in order to get the parameter information. + */ + if (endptr - buf <= 12) + { + png_chunk_benign_error(png_ptr, "invalid"); + return handled_error; + } + + png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); + X0 = png_get_int_32((png_bytep)buf+1); + X1 = png_get_int_32((png_bytep)buf+5); + type = buf[9]; + nparams = buf[10]; + units = buf + 11; + + png_debug(3, "Checking pCAL equation type and number of parameters"); + /* Check that we have the right number of parameters for known + * equation types. + */ + if ((type == PNG_EQUATION_LINEAR && nparams != 2) || + (type == PNG_EQUATION_BASE_E && nparams != 3) || + (type == PNG_EQUATION_ARBITRARY && nparams != 3) || + (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) + { + png_chunk_benign_error(png_ptr, "invalid parameter count"); + return handled_error; + } + + else if (type >= PNG_EQUATION_LAST) + { + png_chunk_benign_error(png_ptr, "unrecognized equation type"); + } + + for (buf = units; *buf; buf++) + /* Empty loop to move past the units string. */ ; + + png_debug(3, "Allocating pCAL parameters array"); + + params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + nparams * (sizeof (png_charp)))); + + if (params == NULL) + { + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; + } + + /* Get pointers to the start of each parameter string. */ + for (i = 0; i < nparams; i++) + { + buf++; /* Skip the null string terminator from previous parameter. */ + + png_debug1(3, "Reading pCAL parameter %d", i); + + for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++) + /* Empty loop to move past each parameter string */ ; + + /* Make sure we haven't run out of data yet */ + if (buf > endptr) + { + png_free(png_ptr, params); + png_chunk_benign_error(png_ptr, "invalid data"); + return handled_error; + } + } + + png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, + (png_charp)units, params); + + /* TODO: BUG: png_set_pCAL calls png_chunk_report which, in this case, calls + * png_benign_error and that can error out. + * + * png_read_buffer needs to be allocated with space for both nparams and the + * parameter strings. Not hard to do. + */ + png_free(png_ptr, params); + return handled_ok; +} +#else +# define png_handle_pCAL NULL +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +/* Read the sCAL chunk */ +static png_handle_result_code /* PRIVATE */ +png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_bytep buffer; + size_t i; + int state; + + png_debug(1, "in png_handle_sCAL"); + png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", + length + 1); + + buffer = png_read_buffer(png_ptr, length+1); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; + } + + png_crc_read(png_ptr, buffer, length); + buffer[length] = 0; /* Null terminate the last string */ + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + /* Validate the unit. */ + if (buffer[0] != 1 && buffer[0] != 2) + { + png_chunk_benign_error(png_ptr, "invalid unit"); + return handled_error; + } + + /* Validate the ASCII numbers, need two ASCII numbers separated by + * a '\0' and they need to fit exactly in the chunk data. + */ + i = 1; + state = 0; + + if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 || + i >= length || buffer[i++] != 0) + png_chunk_benign_error(png_ptr, "bad width format"); + + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive width"); + + else + { + size_t heighti = i; + + state = 0; + if (png_check_fp_number((png_const_charp)buffer, length, + &state, &i) == 0 || i != length) + png_chunk_benign_error(png_ptr, "bad height format"); + + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive height"); + + else + { + /* This is the (only) success case. */ + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], + (png_charp)buffer+1, (png_charp)buffer+heighti); + return handled_ok; + } + } + + return handled_error; +} +#else +# define png_handle_sCAL NULL +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +static png_handle_result_code /* PRIVATE */ +png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[7]; + png_time mod_time; + + png_debug(1, "in png_handle_tIME"); + + /* TODO: what is this doing here? It should be happened in pngread.c and + * pngpread.c, although it could be moved to png_handle_chunk below and + * thereby avoid some code duplication. + */ + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + png_ptr->mode |= PNG_AFTER_IDAT; + + png_crc_read(png_ptr, buf, 7); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + mod_time.second = buf[6]; + mod_time.minute = buf[5]; + mod_time.hour = buf[4]; + mod_time.day = buf[3]; + mod_time.month = buf[2]; + mod_time.year = png_get_uint_16(buf); + + png_set_tIME(png_ptr, info_ptr, &mod_time); + return handled_ok; + PNG_UNUSED(length) +} +#else +# define png_handle_tIME NULL +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +/* Note: this does not properly handle chunks that are > 64K under DOS */ +static png_handle_result_code /* PRIVATE */ +png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_text text_info; + png_bytep buffer; + png_charp key; + png_charp text; + png_uint_32 skip = 0; + + png_debug(1, "in png_handle_tEXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return handled_error; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return handled_error; + } + } +#endif + + buffer = png_read_buffer(png_ptr, length+1); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip) != 0) + return handled_error; + + key = (png_charp)buffer; + key[length] = 0; + + for (text = key; *text; text++) + /* Empty loop to find end of key */ ; + + if (text != key + length) + text++; + + text_info.compression = PNG_TEXT_COMPRESSION_NONE; + text_info.key = key; + text_info.lang = NULL; + text_info.lang_key = NULL; + text_info.itxt_length = 0; + text_info.text = text; + text_info.text_length = strlen(text); + + if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) == 0) + return handled_ok; + + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; +} +#else +# define png_handle_tEXt NULL +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +static png_handle_result_code /* PRIVATE */ +png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 keyword_length; + + png_debug(1, "in png_handle_zTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return handled_error; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return handled_error; + } + } +#endif + + /* Note, "length" is sufficient here; we won't be adding + * a null terminator later. The limit check in png_handle_chunk should be + * sufficient. + */ + buffer = png_read_buffer(png_ptr, length); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + /* TODO: also check that the keyword contents match the spec! */ + for (keyword_length = 0; + keyword_length < length && buffer[keyword_length] != 0; + ++keyword_length) + /* Empty loop to find end of name */ ; + + if (keyword_length > 79 || keyword_length < 1) + errmsg = "bad keyword"; + + /* zTXt must have some LZ data after the keyword, although it may expand to + * zero bytes; we need a '\0' at the end of the keyword, the compression type + * then the LZ data: + */ + else if (keyword_length + 3 > length) + errmsg = "truncated"; + + else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE) + errmsg = "unknown compression type"; + + else + { + png_alloc_size_t uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for iCCP + * and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, keyword_length+2, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + { + png_text text; + + if (png_ptr->read_buffer == NULL) + errmsg="Read failure in png_handle_zTXt"; + else + { + /* It worked; png_ptr->read_buffer now looks like a tEXt chunk + * except for the extra compression type byte and the fact that + * it isn't necessarily '\0' terminated. + */ + buffer = png_ptr->read_buffer; + buffer[uncompressed_length+(keyword_length+2)] = 0; + + text.compression = PNG_TEXT_COMPRESSION_zTXt; + text.key = (png_charp)buffer; + text.text = (png_charp)(buffer + keyword_length+2); + text.text_length = uncompressed_length; + text.itxt_length = 0; + text.lang = NULL; + text.lang_key = NULL; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) == 0) + return handled_ok; + + errmsg = "out of memory"; + } + } + + else + errmsg = png_ptr->zstream.msg; + } + + png_chunk_benign_error(png_ptr, errmsg); + return handled_error; +} +#else +# define png_handle_zTXt NULL +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +static png_handle_result_code /* PRIVATE */ +png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 prefix_length; + + png_debug(1, "in png_handle_iTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return handled_error; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return handled_error; + } + } +#endif + + buffer = png_read_buffer(png_ptr, length+1); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return handled_error; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) + return handled_error; + + /* First the keyword. */ + for (prefix_length=0; + prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* Perform a basic check on the keyword length here. */ + if (prefix_length > 79 || prefix_length < 1) + errmsg = "bad keyword"; + + /* Expect keyword, compression flag, compression type, language, translated + * keyword (both may be empty but are 0 terminated) then the text, which may + * be empty. + */ + else if (prefix_length + 5 > length) + errmsg = "truncated"; + + else if (buffer[prefix_length+1] == 0 || + (buffer[prefix_length+1] == 1 && + buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE)) + { + int compressed = buffer[prefix_length+1] != 0; + png_uint_32 language_offset, translated_keyword_offset; + png_alloc_size_t uncompressed_length = 0; + + /* Now the language tag */ + prefix_length += 3; + language_offset = prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* WARNING: the length may be invalid here, this is checked below. */ + translated_keyword_offset = ++prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* prefix_length should now be at the trailing '\0' of the translated + * keyword, but it may already be over the end. None of this arithmetic + * can overflow because chunks are at most 2^31 bytes long, but on 16-bit + * systems the available allocation may overflow. + */ + ++prefix_length; + + if (compressed == 0 && prefix_length <= length) + uncompressed_length = length - prefix_length; + + else if (compressed != 0 && prefix_length < length) + { + uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for + * iCCP and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, prefix_length, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + buffer = png_ptr->read_buffer; + + else + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "truncated"; + + if (errmsg == NULL) + { + png_text text; + + buffer[uncompressed_length+prefix_length] = 0; + + if (compressed == 0) + text.compression = PNG_ITXT_COMPRESSION_NONE; + + else + text.compression = PNG_ITXT_COMPRESSION_zTXt; + + text.key = (png_charp)buffer; + text.lang = (png_charp)buffer + language_offset; + text.lang_key = (png_charp)buffer + translated_keyword_offset; + text.text = (png_charp)buffer + prefix_length; + text.text_length = 0; + text.itxt_length = uncompressed_length; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) == 0) + return handled_ok; + + errmsg = "out of memory"; + } + } + + else + errmsg = "bad compression info"; + + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); + return handled_error; +} +#else +# define png_handle_iTXt NULL +#endif + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ +static int +png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) +{ + const png_alloc_size_t limit = png_chunk_max(png_ptr); + + if (png_ptr->unknown_chunk.data != NULL) + { + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + + if (length <= limit) + { + PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); + /* The following is safe because of the PNG_SIZE_MAX init above */ + png_ptr->unknown_chunk.size = (size_t)length/*SAFE*/; + /* 'mode' is a flag array, only the bottom four bits matter here */ + png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; + + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + + else + { + /* Do a 'warn' here - it is handled below. */ + png_ptr->unknown_chunk.data = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, length)); + } + } + + if (png_ptr->unknown_chunk.data == NULL && length > 0) + { + /* This is benign because we clean up correctly */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits"); + return 0; + } + + else + { + if (length > 0) + png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); + png_crc_finish(png_ptr, 0); + return 1; + } +} +#endif /* READ_UNKNOWN_CHUNKS */ + +/* Handle an unknown, or known but disabled, chunk */ +png_handle_result_code /*PRIVATE*/ +png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, + png_uint_32 length, int keep) +{ + png_handle_result_code handled = handled_discarded; /* the default */ + + png_debug(1, "in png_handle_unknown"); + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing + * the bug which meant that setting a non-default behavior for a specific + * chunk would be ignored (the default was always used unless a user + * callback was installed). + * + * 'keep' is the value from the png_chunk_unknown_handling, the setting for + * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it + * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here. + * This is just an optimization to avoid multiple calls to the lookup + * function. + */ +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); +# endif +# endif + + /* One of the following methods will read the chunk or skip it (at least one + * of these is always defined because this is the only way to switch on + * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + */ +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* The user callback takes precedence over the chunk keep value, but the + * keep value is still required to validate a save of a critical chunk. + */ + if (png_ptr->read_user_chunk_fn != NULL) + { + if (png_cache_unknown_chunk(png_ptr, length) != 0) + { + /* Callback to user unknown chunk handler */ + int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, + &png_ptr->unknown_chunk); + + /* ret is: + * negative: An error occurred; png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be discarded + * unless png_set_keep_unknown_chunks has been used to set + * a 'keep' behavior for this particular chunk, in which + * case that will be used. A critical chunk will cause an + * error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + */ + if (ret < 0) /* handled_error */ + png_chunk_error(png_ptr, "error in user chunk"); + + else if (ret == 0) + { + /* If the keep value is 'default' or 'never' override it, but + * still error out on critical chunks unless the keep value is + * 'always' While this is weird it is the behavior in 1.4.12. + * A possible improvement would be to obey the value set for the + * chunk, but this would be an API change that would probably + * damage some applications. + * + * The png_app_warning below catches the case that matters, where + * the application has not set specific save or ignore for this + * chunk or global save or ignore. + */ + if (keep < PNG_HANDLE_CHUNK_IF_SAFE) + { +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) + { + png_chunk_warning(png_ptr, "Saving unknown chunk:"); + png_app_warning(png_ptr, + "forcing save of an unhandled chunk;" + " please call png_set_keep_unknown_chunks"); + /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ + } +# endif + keep = PNG_HANDLE_CHUNK_IF_SAFE; + } + } + + else /* chunk was handled */ + { + handled = handled_ok; + /* Critical chunks can be safely discarded at this point. */ + keep = PNG_HANDLE_CHUNK_NEVER; + } + } + + else + keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ + } + + else + /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ +# endif /* READ_USER_CHUNKS */ + +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + { + /* keep is currently just the per-chunk setting, if there was no + * setting change it to the global default now (not that this may + * still be AS_DEFAULT) then obtain the cache of the chunk if required, + * if not simply skip the chunk. + */ + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + keep = png_ptr->unknown_default; + + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { + if (png_cache_unknown_chunk(png_ptr, length) == 0) + keep = PNG_HANDLE_CHUNK_NEVER; + } + + else + png_crc_finish(png_ptr, length); + } +# else +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED +# error no method to support READ_UNKNOWN_CHUNKS +# endif + + { + /* If here there is no read callback pointer set and no support is + * compiled in to just save the unknown chunks, so simply skip this + * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then + * the app has erroneously asked for unknown chunk saving when there + * is no support. + */ + if (keep > PNG_HANDLE_CHUNK_NEVER) + png_app_error(png_ptr, "no unknown chunk support available"); + + png_crc_finish(png_ptr, length); + } +# endif + +# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Now store the chunk in the chunk list if appropriate, and if the limits + * permit it. + */ + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { +# ifdef PNG_USER_LIMITS_SUPPORTED + switch (png_ptr->user_chunk_cache_max) + { + case 2: + png_ptr->user_chunk_cache_max = 1; + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + /* FALLTHROUGH */ + case 1: + /* NOTE: prior to 1.6.0 this case resulted in an unknown critical + * chunk being skipped, now there will be a hard error below. + */ + break; + + default: /* not at limit */ + --(png_ptr->user_chunk_cache_max); + /* FALLTHROUGH */ + case 0: /* no limit */ +# endif /* USER_LIMITS */ + /* Here when the limit isn't reached or when limits are compiled + * out; store the chunk. + */ + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + handled = handled_saved; +# ifdef PNG_USER_LIMITS_SUPPORTED + break; + } +# endif + } +# else /* no store support: the chunk must be handled by the user callback */ + PNG_UNUSED(info_ptr) +# endif + + /* Regardless of the error handling below the cached data (if any) can be + * freed now. Notice that the data is not freed if there is a png_error, but + * it will be freed by destroy_read_struct. + */ + if (png_ptr->unknown_chunk.data != NULL) + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + +#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ + /* There is no support to read an unknown chunk, so just skip it. */ + png_crc_finish(png_ptr, length); + PNG_UNUSED(info_ptr) + PNG_UNUSED(keep) +#endif /* !READ_UNKNOWN_CHUNKS */ + + /* Check for unhandled critical chunks */ + if (handled < handled_saved && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) + png_chunk_error(png_ptr, "unhandled critical chunk"); + + return handled; +} + +/* APNG handling: the minimal implementation of APNG handling in libpng 1.6 + * requires that those significant applications which already handle APNG not + * get hosed. To do this ensure the code here will have to ensure than APNG + * data by default (at least in 1.6) gets stored in the unknown chunk list. + * Maybe this can be relaxed in a few years but at present it's just the only + * safe way. + * + * ATM just cause unknown handling for all three chunks: + */ +#define png_handle_acTL NULL +#define png_handle_fcTL NULL +#define png_handle_fdAT NULL + +/* + * 1.6.47: This is the new table driven interface to all the chunk handling. + * + * The table describes the PNG standard rules for **reading** known chunks - + * every chunk which has an entry in PNG_KNOWN_CHUNKS. The table contains an + * entry for each PNG_INDEX_cHNK describing the rules. + * + * In this initial version the only information in the entry is the + * png_handle_cHNK function for the chunk in question. When chunk support is + * compiled out the entry will be NULL. + */ +static const struct +{ + png_handle_result_code (*handler)( + png_structrp, png_inforp, png_uint_32 length); + /* A chunk-specific 'handler', NULL if the chunk is not supported in this + * build. + */ + + /* Crushing these values helps on modern 32-bit architectures because the + * pointer and the following bit fields both end up requiring 32 bits. + * Typically this will halve the table size. On 64-bit architectures the + * table entries will typically be 8 bytes. + */ + png_uint_32 max_length :12; /* Length min, max in bytes */ + png_uint_32 min_length :8; + /* Length errors on critical chunks have special handling to preserve the + * existing behaviour in libpng 1.6. Anciallary chunks are checked below + * and produce a 'benign' error. + */ + png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */ + png_uint_32 pos_after :4; /* PNG_HAVE_ values chunk must follow */ + /* NOTE: PLTE, tRNS and bKGD require special handling which depends on + * the colour type of the base image. + */ + png_uint_32 multiple :1; /* Multiple occurences permitted */ + /* This is enabled for PLTE because PLTE may, in practice, be optional */ +} +read_chunks[PNG_INDEX_unknown] = +{ + /* Definitions as above but done indirectly by #define so that + * PNG_KNOWN_CHUNKS can be used safely to build the table in order. + * + * Each CDcHNK definition lists the values for the parameters **after** + * the first, 'handler', function. 'handler' is NULL when the chunk has no + * compiled in support. + */ +# define NoCheck 0x801U /* Do not check the maximum length */ +# define Limit 0x802U /* Limit to png_chunk_max bytes */ +# define LKMin 3U+LZ77Min /* Minimum length of keyword+LZ77 */ + +#define hIHDR PNG_HAVE_IHDR +#define hPLTE PNG_HAVE_PLTE +#define hIDAT PNG_HAVE_IDAT + /* For the two chunks, tRNS and bKGD which can occur in PNGs without a PLTE + * but must occur after the PLTE use this and put the check in the handler + * routine for colour mapped images were PLTE is required. Also put a check + * in PLTE for other image types to drop the PLTE if tRNS or bKGD have been + * seen. + */ +#define hCOL (PNG_HAVE_PLTE|PNG_HAVE_IDAT) + /* Used for the decoding chunks which must be before PLTE. */ +#define aIDAT PNG_AFTER_IDAT + + /* Chunks from W3C PNG v3: */ + /* cHNK max_len, min, before, after, multiple */ +# define CDIHDR 13U, 13U, hIHDR, 0, 0 +# define CDPLTE NoCheck, 0U, 0, hIHDR, 1 + /* PLTE errors are only critical for colour-map images, consequently the + * hander does all the checks. + */ +# define CDIDAT NoCheck, 0U, aIDAT, hIHDR, 1 +# define CDIEND NoCheck, 0U, 0, aIDAT, 0 + /* Historically data was allowed in IEND */ +# define CDtRNS 256U, 0U, hIDAT, hIHDR, 0 +# define CDcHRM 32U, 32U, hCOL, hIHDR, 0 +# define CDgAMA 4U, 4U, hCOL, hIHDR, 0 +# define CDiCCP NoCheck, LKMin, hCOL, hIHDR, 0 +# define CDsBIT 4U, 1U, hCOL, hIHDR, 0 +# define CDsRGB 1U, 1U, hCOL, hIHDR, 0 +# define CDcICP 4U, 4U, hCOL, hIHDR, 0 +# define CDmDCV 24U, 24U, hCOL, hIHDR, 0 +# define CDeXIf Limit, 4U, 0, hIHDR, 0 +# define CDcLLI 8U, 8U, hCOL, hIHDR, 0 +# define CDtEXt NoCheck, 2U, 0, hIHDR, 1 + /* Allocates 'length+1'; checked in the handler */ +# define CDzTXt Limit, LKMin, 0, hIHDR, 1 +# define CDiTXt NoCheck, 6U, 0, hIHDR, 1 + /* Allocates 'length+1'; checked in the handler */ +# define CDbKGD 6U, 1U, hIDAT, hIHDR, 0 +# define CDhIST 1024U, 0U, hPLTE, hIHDR, 0 +# define CDpHYs 9U, 9U, hIDAT, hIHDR, 0 +# define CDsPLT NoCheck, 3U, hIDAT, hIHDR, 1 + /* Allocates 'length+1'; checked in the handler */ +# define CDtIME 7U, 7U, 0, hIHDR, 0 +# define CDacTL 8U, 8U, hIDAT, hIHDR, 0 +# define CDfcTL 25U, 26U, 0, hIHDR, 1 +# define CDfdAT Limit, 4U, hIDAT, hIHDR, 1 + /* Supported chunks from PNG extensions 1.5.0, NYI so limit */ +# define CDoFFs 9U, 9U, hIDAT, hIHDR, 0 +# define CDpCAL NoCheck, 14U, hIDAT, hIHDR, 0 + /* Allocates 'length+1'; checked in the handler */ +# define CDsCAL Limit, 4U, hIDAT, hIHDR, 0 + /* Allocates 'length+1'; checked in the handler */ + +# define PNG_CHUNK(cHNK, index) { png_handle_ ## cHNK, CD ## cHNK }, + PNG_KNOWN_CHUNKS +# undef PNG_CHUNK +}; + + +static png_index +png_chunk_index_from_name(png_uint_32 chunk_name) +{ + /* For chunk png_cHNK return PNG_INDEX_cHNK. Return PNG_INDEX_unknown if + * chunk_name is not known. Notice that in a particular build "known" does + * not necessarily mean "supported", although the inverse applies. + */ + switch (chunk_name) + { +# define PNG_CHUNK(cHNK, index)\ + case png_ ## cHNK: return PNG_INDEX_ ## cHNK; /* == index */ + + PNG_KNOWN_CHUNKS + +# undef PNG_CHUNK + + default: return PNG_INDEX_unknown; + } +} + +png_handle_result_code /*PRIVATE*/ +png_handle_chunk(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + /* CSE: these things don't change, these autos are just to save typing and + * make the code more clear. + */ + const png_uint_32 chunk_name = png_ptr->chunk_name; + const png_index chunk_index = png_chunk_index_from_name(chunk_name); + + png_handle_result_code handled = handled_error; + png_const_charp errmsg = NULL; + + /* Is this a known chunk? If not there are no checks performed here; + * png_handle_unknown does the correct checks. This means that the values + * for known but unsupported chunks in the above table are not used here + * however the chunks_seen fields in png_struct are still set. + */ + if (chunk_index == PNG_INDEX_unknown || + read_chunks[chunk_index].handler == NULL) + { + handled = png_handle_unknown( + png_ptr, info_ptr, length, PNG_HANDLE_CHUNK_AS_DEFAULT); + } + + /* First check the position. The first check is historical; the stream must + * start with IHDR and anything else causes libpng to give up immediately. + */ + else if (chunk_index != PNG_INDEX_IHDR && + (png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); /* NORETURN */ + + /* Before all the pos_before chunks, after all the pos_after chunks. */ + else if (((png_ptr->mode & read_chunks[chunk_index].pos_before) != 0) || + ((png_ptr->mode & read_chunks[chunk_index].pos_after) != + read_chunks[chunk_index].pos_after)) + { + errmsg = "out of place"; + } + + /* Now check for duplicates: duplicated critical chunks also produce a + * full error. + */ + else if (read_chunks[chunk_index].multiple == 0 && + png_file_has_chunk(png_ptr, chunk_index)) + { + errmsg = "duplicate"; + } + + else if (length < read_chunks[chunk_index].min_length) + errmsg = "too short"; + else + { + /* NOTE: apart from IHDR the critical chunks (PLTE, IDAT and IEND) are set + * up above not to do any length checks. + * + * The png_chunk_max check ensures that the variable length chunks are + * always checked at this point for being within the system allocation + * limits. + */ + unsigned max_length = read_chunks[chunk_index].max_length; + + switch (max_length) + { + case Limit: + /* png_read_chunk_header has already png_error'ed chunks with a + * length exceeding the 31-bit PNG limit, so just check the memory + * limit: + */ + if (length <= png_chunk_max(png_ptr)) + goto MeetsLimit; + + errmsg = "length exceeds libpng limit"; + break; + + default: + if (length <= max_length) + goto MeetsLimit; + + errmsg = "too long"; + break; + + case NoCheck: + MeetsLimit: + handled = read_chunks[chunk_index].handler( + png_ptr, info_ptr, length); + break; + } + } + + /* If there was an error or the chunk was simply skipped it is not counted as + * 'seen'. + */ + if (errmsg != NULL) + { + if (PNG_CHUNK_CRITICAL(chunk_name)) /* stop immediately */ + png_chunk_error(png_ptr, errmsg); + else /* ancillary chunk */ + { + /* The chunk data is skipped: */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, errmsg); + } + } + + else if (handled >= handled_saved) + { + if (chunk_index != PNG_INDEX_unknown) + png_file_add_chunk(png_ptr, chunk_index); + } + + return handled; +} + +/* Combines the row recently read in with the existing pixels in the row. This + * routine takes care of alpha and transparency if requested. This routine also + * handles the two methods of progressive display of interlaced images, + * depending on the 'display' value; if 'display' is true then the whole row + * (dp) is filled from the start by replicating the available pixels. If + * 'display' is false only those pixels present in the pass are filled in. + */ +void /* PRIVATE */ +png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) +{ + unsigned int pixel_depth = png_ptr->transformed_pixel_depth; + png_const_bytep sp = png_ptr->row_buf + 1; + png_alloc_size_t row_width = png_ptr->width; + unsigned int pass = png_ptr->pass; + png_bytep end_ptr = 0; + png_byte end_byte = 0; + unsigned int end_mask; + + png_debug(1, "in png_combine_row"); + + /* Added in 1.5.6: it should not be possible to enter this routine until at + * least one row has been read from the PNG data and transformed. + */ + if (pixel_depth == 0) + png_error(png_ptr, "internal row logic error"); + + /* Added in 1.5.4: the pixel depth should match the information returned by + * any call to png_read_update_info at this point. Do not continue if we got + * this wrong. + */ + if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes != + PNG_ROWBYTES(pixel_depth, row_width)) + png_error(png_ptr, "internal row size calculation error"); + + /* Don't expect this to ever happen: */ + if (row_width == 0) + png_error(png_ptr, "internal row width error"); + + /* Preserve the last byte in cases where only part of it will be overwritten, + * the multiply below may overflow, we don't care because ANSI-C guarantees + * we get the low bits. + */ + end_mask = (pixel_depth * row_width) & 7; + if (end_mask != 0) + { + /* end_ptr == NULL is a flag to say do nothing */ + end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; + end_byte = *end_ptr; +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + /* little-endian byte */ + end_mask = (unsigned int)(0xff << end_mask); + + else /* big-endian byte */ +# endif + end_mask = 0xff >> end_mask; + /* end_mask is now the bits to *keep* from the destination row */ + } + + /* For non-interlaced images this reduces to a memcpy(). A memcpy() + * will also happen if interlacing isn't supported or if the application + * does not call png_set_interlace_handling(). In the latter cases the + * caller just gets a sequence of the unexpanded rows from each interlace + * pass. + */ +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0 && + pass < 6 && (display == 0 || + /* The following copies everything for 'display' on passes 0, 2 and 4. */ + (display == 1 && (pass & 1) != 0))) + { + /* Narrow images may have no bits in a pass; the caller should handle + * this, but this test is cheap: + */ + if (row_width <= PNG_PASS_START_COL(pass)) + return; + + if (pixel_depth < 8) + { + /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit + * into 32 bits, then a single loop over the bytes using the four byte + * values in the 32-bit mask can be used. For the 'display' option the + * expanded mask may also not require any masking within a byte. To + * make this work the PACKSWAP option must be taken into account - it + * simply requires the pixels to be reversed in each byte. + * + * The 'regular' case requires a mask for each of the first 6 passes, + * the 'display' case does a copy for the even passes in the range + * 0..6. This has already been handled in the test above. + * + * The masks are arranged as four bytes with the first byte to use in + * the lowest bits (little-endian) regardless of the order (PACKSWAP or + * not) of the pixels in each byte. + * + * NOTE: the whole of this logic depends on the caller of this function + * only calling it on rows appropriate to the pass. This function only + * understands the 'x' logic; the 'y' logic is handled by the caller. + * + * The following defines allow generation of compile time constant bit + * masks for each pixel depth and each possibility of swapped or not + * swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index, + * is in the range 0..7; and the result is 1 if the pixel is to be + * copied in the pass, 0 if not. 'S' is for the sparkle method, 'B' + * for the block method. + * + * With some compilers a compile time expression of the general form: + * + * (shift >= 32) ? (a >> (shift-32)) : (b >> shift) + * + * Produces warnings with values of 'shift' in the range 33 to 63 + * because the right hand side of the ?: expression is evaluated by + * the compiler even though it isn't used. Microsoft Visual C (various + * versions) and the Intel C compiler are known to do this. To avoid + * this the following macros are used in 1.5.6. This is a temporary + * solution to avoid destabilizing the code during the release process. + */ +# if PNG_USE_COMPILE_TIME_MASKS +# define PNG_LSR(x,s) ((x)>>((s) & 0x1f)) +# define PNG_LSL(x,s) ((x)<<((s) & 0x1f)) +# else +# define PNG_LSR(x,s) ((x)>>(s)) +# define PNG_LSL(x,s) ((x)<<(s)) +# endif +# define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1) +# define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1) + + /* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is + * little endian - the first pixel is at bit 0 - however the extra + * parameter 's' can be set to cause the mask position to be swapped + * within each byte, to match the PNG format. This is done by XOR of + * the shift with 7, 6 or 4 for bit depths 1, 2 and 4. + */ +# define PIXEL_MASK(p,x,d,s) \ + (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0)))) + + /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask. + */ +# define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) +# define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) + + /* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp + * cases the result needs replicating, for the 4-bpp case the above + * generates a full 32 bits. + */ +# define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1))) + +# define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\ + S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\ + S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d) + +# define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\ + B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\ + B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d) + +#if PNG_USE_COMPILE_TIME_MASKS + /* Utility macros to construct all the masks for a depth/swap + * combination. The 's' parameter says whether the format is PNG + * (big endian bytes) or not. Only the three odd-numbered passes are + * required for the display/block algorithm. + */ +# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ + S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } + +# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) } + +# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) + + /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and + * then pass: + */ + static const png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = + { + /* Little-endian byte masks for PACKSWAP */ + { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) } + }; + + /* display_mask has only three entries for the odd passes, so index by + * pass>>1. + */ + static const png_uint_32 display_mask[2][3][3] = + { + /* Little-endian byte masks for PACKSWAP */ + { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) } + }; + +# define MASK(pass,depth,display,png)\ + ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\ + row_mask[png][DEPTH_INDEX(depth)][pass]) + +#else /* !PNG_USE_COMPILE_TIME_MASKS */ + /* This is the runtime alternative: it seems unlikely that this will + * ever be either smaller or faster than the compile time approach. + */ +# define MASK(pass,depth,display,png)\ + ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) +#endif /* !USE_COMPILE_TIME_MASKS */ + + /* Use the appropriate mask to copy the required bits. In some cases + * the byte mask will be 0 or 0xff; optimize these cases. row_width is + * the number of pixels, but the code copies bytes, so it is necessary + * to special case the end. + */ + png_uint_32 pixels_per_byte = 8 / pixel_depth; + png_uint_32 mask; + +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + mask = MASK(pass, pixel_depth, display, 0); + + else +# endif + mask = MASK(pass, pixel_depth, display, 1); + + for (;;) + { + png_uint_32 m; + + /* It doesn't matter in the following if png_uint_32 has more than + * 32 bits because the high bits always match those in m<<24; it is, + * however, essential to use OR here, not +, because of this. + */ + m = mask; + mask = (m >> 8) | (m << 24); /* rotate right to good compilers */ + m &= 0xff; + + if (m != 0) /* something to copy */ + { + if (m != 0xff) + *dp = (png_byte)((*dp & ~m) | (*sp & m)); + else + *dp = *sp; + } + + /* NOTE: this may overwrite the last byte with garbage if the image + * is not an exact number of bytes wide; libpng has always done + * this. + */ + if (row_width <= pixels_per_byte) + break; /* May need to restore part of the last byte */ + + row_width -= pixels_per_byte; + ++dp; + ++sp; + } + } + + else /* pixel_depth >= 8 */ + { + unsigned int bytes_to_copy, bytes_to_jump; + + /* Validate the depth - it must be a multiple of 8 */ + if (pixel_depth & 7) + png_error(png_ptr, "invalid user transform pixel depth"); + + pixel_depth >>= 3; /* now in bytes */ + row_width *= pixel_depth; + + /* Regardless of pass number the Adam 7 interlace always results in a + * fixed number of pixels to copy then to skip. There may be a + * different number of pixels to skip at the start though. + */ + { + unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth; + + row_width -= offset; + dp += offset; + sp += offset; + } + + /* Work out the bytes to copy. */ + if (display != 0) + { + /* When doing the 'block' algorithm the pixel in the pass gets + * replicated to adjacent pixels. This is why the even (0,2,4,6) + * passes are skipped above - the entire expanded row is copied. + */ + bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth; + + /* But don't allow this number to exceed the actual row width. */ + if (bytes_to_copy > row_width) + bytes_to_copy = (unsigned int)/*SAFE*/row_width; + } + + else /* normal row; Adam7 only ever gives us one pixel to copy. */ + bytes_to_copy = pixel_depth; + + /* In Adam7 there is a constant offset between where the pixels go. */ + bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth; + + /* And simply copy these bytes. Some optimization is possible here, + * depending on the value of 'bytes_to_copy'. Special case the low + * byte counts, which we know to be frequent. + * + * Notice that these cases all 'return' rather than 'break' - this + * avoids an unnecessary test on whether to restore the last byte + * below. + */ + switch (bytes_to_copy) + { + case 1: + for (;;) + { + *dp = *sp; + + if (row_width <= bytes_to_jump) + return; + + dp += bytes_to_jump; + sp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + case 2: + /* There is a possibility of a partial copy at the end here; this + * slows the code down somewhat. + */ + do + { + dp[0] = sp[0]; dp[1] = sp[1]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + while (row_width > 1); + + /* And there can only be one byte left at this point: */ + *dp = *sp; + return; + + case 3: + /* This can only be the RGB case, so each copy is exactly one + * pixel and it is not necessary to check for a partial copy. + */ + for (;;) + { + dp[0] = sp[0]; dp[1] = sp[1]; dp[2] = sp[2]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + default: +#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE + /* Check for double byte alignment and, if possible, use a + * 16-bit copy. Don't attempt this for narrow images - ones that + * are less than an interlace panel wide. Don't attempt it for + * wide bytes_to_copy either - use the memcpy there. + */ + if (bytes_to_copy < 16 /*else use memcpy*/ && + png_isaligned(dp, png_uint_16) && + png_isaligned(sp, png_uint_16) && + bytes_to_copy % (sizeof (png_uint_16)) == 0 && + bytes_to_jump % (sizeof (png_uint_16)) == 0) + { + /* Everything is aligned for png_uint_16 copies, but try for + * png_uint_32 first. + */ + if (png_isaligned(dp, png_uint_32) && + png_isaligned(sp, png_uint_32) && + bytes_to_copy % (sizeof (png_uint_32)) == 0 && + bytes_to_jump % (sizeof (png_uint_32)) == 0) + { + png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); + png_const_uint_32p sp32 = png_aligncastconst( + png_const_uint_32p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_32)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp32++ = *sp32++; + c -= (sizeof (png_uint_32)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp32 += skip; + sp32 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* Get to here when the row_width truncates the final copy. + * There will be 1-3 bytes left to copy, so don't try the + * 16-bit loop below. + */ + dp = (png_bytep)dp32; + sp = (png_const_bytep)sp32; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + + /* Else do it in 16-bit quantities, but only if the size is + * not too large. + */ + else + { + png_uint_16p dp16 = png_aligncast(png_uint_16p, dp); + png_const_uint_16p sp16 = png_aligncastconst( + png_const_uint_16p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_16)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp16++ = *sp16++; + c -= (sizeof (png_uint_16)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp16 += skip; + sp16 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* End of row - 1 byte left, bytes_to_copy > row_width: */ + dp = (png_bytep)dp16; + sp = (png_const_bytep)sp16; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + } +#endif /* ALIGN_TYPE code */ + + /* The true default - use a memcpy: */ + for (;;) + { + memcpy(dp, sp, bytes_to_copy); + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + if (bytes_to_copy > row_width) + bytes_to_copy = (unsigned int)/*SAFE*/row_width; + } + } + + /* NOT REACHED*/ + } /* pixel_depth >= 8 */ + + /* Here if pixel_depth < 8 to check 'end_ptr' below. */ + } + else +#endif /* READ_INTERLACING */ + + /* If here then the switch above wasn't used so just memcpy the whole row + * from the temporary row buffer (notice that this overwrites the end of the + * destination row if it is a partial byte.) + */ + memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); + + /* Restore the overwritten bits from the last byte if necessary. */ + if (end_ptr != NULL) + *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask)); +} + +#ifdef PNG_READ_INTERLACING_SUPPORTED +void /* PRIVATE */ +png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations /* Because these may affect the byte layout */) +{ + png_debug(1, "in png_do_read_interlace"); + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp = row + (size_t)((row_info->width - 1) >> 3); + png_bytep dp = row + (size_t)((final_width - 1) >> 3); + unsigned int sshift, dshift; + unsigned int s_start, s_end; + int s_inc; + int jstop = (int)png_pass_inc[pass]; + png_byte v; + png_uint_32 i; + int j; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((transformations & PNG_PACKSWAP) != 0) + { + sshift = ((row_info->width + 7) & 0x07); + dshift = ((final_width + 7) & 0x07); + s_start = 7; + s_end = 0; + s_inc = -1; + } + + else +#endif + { + sshift = 7 - ((row_info->width + 7) & 0x07); + dshift = 7 - ((final_width + 7) & 0x07); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = 0; i < row_info->width; i++) + { + v = (png_byte)((*sp >> sshift) & 0x01); + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); + tmp |= (unsigned int)(v << dshift); + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift = (unsigned int)((int)dshift + s_inc); + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift = (unsigned int)((int)sshift + s_inc); + } + break; + } + + case 2: + { + png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); + png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); + unsigned int sshift, dshift; + unsigned int s_start, s_end; + int s_inc; + int jstop = (int)png_pass_inc[pass]; + png_uint_32 i; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((transformations & PNG_PACKSWAP) != 0) + { + sshift = (((row_info->width + 3) & 0x03) << 1); + dshift = (((final_width + 3) & 0x03) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + + else +#endif + { + sshift = ((3 - ((row_info->width + 3) & 0x03)) << 1); + dshift = ((3 - ((final_width + 3) & 0x03)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x03); + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); + tmp |= (unsigned int)(v << dshift); + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift = (unsigned int)((int)dshift + s_inc); + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift = (unsigned int)((int)sshift + s_inc); + } + break; + } + + case 4: + { + png_bytep sp = row + (size_t)((row_info->width - 1) >> 1); + png_bytep dp = row + (size_t)((final_width - 1) >> 1); + unsigned int sshift, dshift; + unsigned int s_start, s_end; + int s_inc; + png_uint_32 i; + int jstop = (int)png_pass_inc[pass]; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((transformations & PNG_PACKSWAP) != 0) + { + sshift = (((row_info->width + 1) & 0x01) << 2); + dshift = (((final_width + 1) & 0x01) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + + else +#endif + { + sshift = ((1 - ((row_info->width + 1) & 0x01)) << 2); + dshift = ((1 - ((final_width + 1) & 0x01)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v = (png_byte)((*sp >> sshift) & 0x0f); + int j; + + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); + tmp |= (unsigned int)(v << dshift); + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift = (unsigned int)((int)dshift + s_inc); + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift = (unsigned int)((int)sshift + s_inc); + } + break; + } + + default: + { + size_t pixel_bytes = (row_info->pixel_depth >> 3); + + png_bytep sp = row + (size_t)(row_info->width - 1) + * pixel_bytes; + + png_bytep dp = row + (size_t)(final_width - 1) * pixel_bytes; + + int jstop = (int)png_pass_inc[pass]; + png_uint_32 i; + + for (i = 0; i < row_info->width; i++) + { + png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */ + int j; + + memcpy(v, sp, pixel_bytes); + + for (j = 0; j < jstop; j++) + { + memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + + sp -= pixel_bytes; + } + break; + } + } + + row_info->width = final_width; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); + } +#ifndef PNG_READ_PACKSWAP_SUPPORTED + PNG_UNUSED(transformations) /* Silence compiler warning */ +#endif +} +#endif /* READ_INTERLACING */ + +static void +png_read_filter_row_sub(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + size_t i; + size_t istop = row_info->rowbytes; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + + PNG_UNUSED(prev_row) + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_up(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + size_t i; + size_t istop = row_info->rowbytes; + png_bytep rp = row; + png_const_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_avg(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + size_t i; + png_bytep rp = row; + png_const_bytep pp = prev_row; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + size_t istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } +} + +static void +png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp_end = row + row_info->rowbytes; + int a, c; + + /* First pixel/byte */ + c = *prev_row++; + a = *row + c; + *row++ = (png_byte)a; + + /* Remainder */ + while (row < rp_end) + { + int b, pa, pb, pc, p; + + a &= 0xff; /* From previous iteration or start */ + b = *prev_row++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* Find the best predictor, the least of pa, pb, pc favoring the earlier + * ones in the case of a tie. + */ + if (pb < pa) + { + pa = pb; a = b; + } + if (pc < pa) a = c; + + /* Calculate the current pixel in a, and move the previous row pixel to c + * for the next time round the loop + */ + c = b; + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp_end = row + bpp; + + /* Process the first pixel in the row completely (this is the same as 'up' + * because there is only one candidate predictor for the first row). + */ + while (row < rp_end) + { + int a = *row + *prev_row++; + *row++ = (png_byte)a; + } + + /* Remainder */ + rp_end = rp_end + (row_info->rowbytes - bpp); + + while (row < rp_end) + { + int a, b, c, pa, pb, pc, p; + + c = *(prev_row - bpp); + a = *(row - bpp); + b = *prev_row++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + if (pb < pa) + { + pa = pb; a = b; + } + if (pc < pa) a = c; + + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_init_filter_functions(png_structrp pp) + /* This function is called once for every PNG image (except for PNG images + * that only use PNG_FILTER_VALUE_NONE for all rows) to set the + * implementations required to reverse the filtering of PNG rows. Reversing + * the filter is the first transformation performed on the row data. It is + * performed in place, therefore an implementation can be selected based on + * the image pixel format. If the implementation depends on image width then + * take care to ensure that it works correctly if the image is interlaced - + * interlacing causes the actual row width to vary. + */ +{ + unsigned int bpp = (pp->pixel_depth + 7) >> 3; + + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub; + pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg; + if (bpp == 1) + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_1byte_pixel; + else + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_multibyte_pixel; + +#ifdef PNG_FILTER_OPTIMIZATIONS + /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to + * call to install hardware optimizations for the above functions; simply + * replace whatever elements of the pp->read_filter[] array with a hardware + * specific (or, for that matter, generic) optimization. + * + * To see an example of this examine what configure.ac does when + * --enable-arm-neon is specified on the command line. + */ + PNG_FILTER_OPTIMIZATIONS(pp, bpp); +#endif +} + +void /* PRIVATE */ +png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, + png_const_bytep prev_row, int filter) +{ + /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define + * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic + * implementations. See png_init_filter_functions above. + */ + if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) + { + if (pp->read_filter[0] == NULL) + png_init_filter_functions(pp); + + pp->read_filter[filter-1](row_info, row, prev_row); + } +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +void /* PRIVATE */ +png_read_IDAT_data(png_structrp png_ptr, png_bytep output, + png_alloc_size_t avail_out) +{ + /* Loop reading IDATs and decompressing the result into output[avail_out] */ + png_ptr->zstream.next_out = output; + png_ptr->zstream.avail_out = 0; /* safety: set below */ + + if (output == NULL) + avail_out = 0; + + do + { + int ret; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + if (png_ptr->zstream.avail_in == 0) + { + uInt avail_in; + png_bytep buffer; + + while (png_ptr->idat_size == 0) + { + png_crc_finish(png_ptr, 0); + + png_ptr->idat_size = png_read_chunk_header(png_ptr); + /* This is an error even in the 'check' case because the code just + * consumed a non-IDAT header. + */ + if (png_ptr->chunk_name != png_IDAT) + png_error(png_ptr, "Not enough image data"); + } + + avail_in = png_ptr->IDAT_read_size; + + if (avail_in > png_chunk_max(png_ptr)) + avail_in = (uInt)/*SAFE*/png_chunk_max(png_ptr); + + if (avail_in > png_ptr->idat_size) + avail_in = (uInt)png_ptr->idat_size; + + /* A PNG with a gradually increasing IDAT size will defeat this attempt + * to minimize memory usage by causing lots of re-allocs, but + * realistically doing IDAT_read_size re-allocs is not likely to be a + * big problem. + * + * An error here corresponds to the system being out of memory. + */ + buffer = png_read_buffer(png_ptr, avail_in); + + if (buffer == NULL) + png_chunk_error(png_ptr, "out of memory"); + + png_crc_read(png_ptr, buffer, avail_in); + png_ptr->idat_size -= avail_in; + + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = avail_in; + } + + /* And set up the output side. */ + if (output != NULL) /* standard read */ + { + uInt out = ZLIB_IO_MAX; + + if (out > avail_out) + out = (uInt)avail_out; + + avail_out -= out; + png_ptr->zstream.avail_out = out; + } + + else /* after last row, checking for end */ + { + png_ptr->zstream.next_out = tmpbuf; + png_ptr->zstream.avail_out = (sizeof tmpbuf); + } + + /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the + * process. If the LZ stream is truncated the sequential reader will + * terminally damage the stream, above, by reading the chunk header of the + * following chunk (it then exits with png_error). + * + * TODO: deal more elegantly with truncated IDAT lists. + */ + ret = PNG_INFLATE(png_ptr, Z_NO_FLUSH); + + /* Take the unconsumed output back. */ + if (output != NULL) + avail_out += png_ptr->zstream.avail_out; + + else /* avail_out counts the extra bytes */ + avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out; + + png_ptr->zstream.avail_out = 0; + + if (ret == Z_STREAM_END) + { + /* Do this for safety; we won't read any more into this row. */ + png_ptr->zstream.next_out = NULL; + + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + + if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) + png_chunk_benign_error(png_ptr, "Extra compressed data"); + break; + } + + if (ret != Z_OK) + { + png_zstream_error(png_ptr, ret); + + if (output != NULL) + png_chunk_error(png_ptr, png_ptr->zstream.msg); + + else /* checking */ + { + png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); + return; + } + } + } while (avail_out > 0); + + if (avail_out > 0) + { + /* The stream ended before the image; this is the same as too few IDATs so + * should be handled the same way. + */ + if (output != NULL) + png_error(png_ptr, "Not enough image data"); + + else /* the deflate stream contained extra data */ + png_chunk_benign_error(png_ptr, "Too much image data"); + } +} + +void /* PRIVATE */ +png_read_finish_IDAT(png_structrp png_ptr) +{ + /* We don't need any more data and the stream should have ended, however the + * LZ end code may actually not have been processed. In this case we must + * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk + * may still remain to be consumed. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in + * the compressed stream, but the stream may be damaged too, so even after + * this call we may need to terminate the zstream ownership. + */ + png_read_IDAT_data(png_ptr, NULL, 0); + png_ptr->zstream.next_out = NULL; /* safety */ + + /* Now clear everything out for safety; the following may not have been + * done. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + } + + /* If the zstream has not been released do it now *and* terminate the reading + * of the final IDAT chunk. + */ + if (png_ptr->zowner == png_IDAT) + { + /* Always do this; the pointers otherwise point into the read buffer. */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + + /* Now we no longer own the zstream. */ + png_ptr->zowner = 0; + + /* The slightly weird semantics of the sequential IDAT reading is that we + * are always in or at the end of an IDAT chunk, so we always need to do a + * crc_finish here. If idat_size is non-zero we also need to read the + * spurious bytes at the end of the chunk now. + */ + (void)png_crc_finish(png_ptr, png_ptr->idat_size); + } +} + +void /* PRIVATE */ +png_read_finish_row(png_structrp png_ptr) +{ + png_debug(1, "in png_read_finish_row"); + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + + if (png_ptr->interlaced != 0) + { + png_ptr->row_number = 0; + + /* TO DO: don't do this if prev_row isn't needed (requires + * read-ahead of the next row's filter byte. + */ + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + do + { + png_ptr->pass++; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if ((png_ptr->transformations & PNG_INTERLACE) == 0) + { + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + } + + else /* if (png_ptr->transformations & PNG_INTERLACE) */ + break; /* libpng deinterlacing sees every row */ + + } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0); + + if (png_ptr->pass < 7) + return; + } + + /* Here after at the end of the last row of the last pass. */ + png_read_finish_IDAT(png_ptr); +} +#endif /* SEQUENTIAL_READ */ + +void /* PRIVATE */ +png_read_start_row(png_structrp png_ptr) +{ + unsigned int max_pixel_depth; + size_t row_bytes; + + png_debug(1, "in png_read_start_row"); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + png_init_read_transformations(png_ptr); +#endif + if (png_ptr->interlaced != 0) + { + if ((png_ptr->transformations & PNG_INTERLACE) == 0) + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + + else + png_ptr->num_rows = png_ptr->height; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + } + + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->iwidth = png_ptr->width; + } + + max_pixel_depth = (unsigned int)png_ptr->pixel_depth; + + /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of + * calculations to calculate the final pixel depth, then + * png_do_read_transforms actually does the transforms. This means that the + * code which effectively calculates this value is actually repeated in three + * separate places. They must all match. Innocent changes to the order of + * transformations can and will break libpng in a way that causes memory + * overwrites. + * + * TODO: fix this. + */ +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8) + max_pixel_depth = 8; +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans != 0) + max_pixel_depth = 32; + + else + max_pixel_depth = 24; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth < 8) + max_pixel_depth = 8; + + if (png_ptr->num_trans != 0) + max_pixel_depth *= 2; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (png_ptr->num_trans != 0) + { + max_pixel_depth *= 4; + max_pixel_depth /= 3; + } + } + } +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) + { +# ifdef PNG_READ_EXPAND_SUPPORTED + /* In fact it is an error if it isn't supported, but checking is + * the safe way. + */ + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (png_ptr->bit_depth < 16) + max_pixel_depth *= 2; + } + else +# endif + png_ptr->transformations &= ~PNG_EXPAND_16; + } +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if ((png_ptr->transformations & (PNG_FILLER)) != 0) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth <= 8) + max_pixel_depth = 16; + + else + max_pixel_depth = 32; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB || + png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (max_pixel_depth <= 32) + max_pixel_depth = 32; + + else + max_pixel_depth = 64; + } + } +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + { + if ( +#ifdef PNG_READ_EXPAND_SUPPORTED + (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) || +#endif +#ifdef PNG_READ_FILLER_SUPPORTED + (png_ptr->transformations & (PNG_FILLER)) != 0 || +#endif + png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (max_pixel_depth <= 16) + max_pixel_depth = 32; + + else + max_pixel_depth = 64; + } + + else + { + if (max_pixel_depth <= 8) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 32; + + else + max_pixel_depth = 24; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 64; + + else + max_pixel_depth = 48; + } + } +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ +defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + unsigned int user_pixel_depth = png_ptr->user_transform_depth * + png_ptr->user_transform_channels; + + if (user_pixel_depth > max_pixel_depth) + max_pixel_depth = user_pixel_depth; + } +#endif + + /* This value is stored in png_struct and double checked in the row read + * code. + */ + png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth; + png_ptr->transformed_pixel_depth = 0; /* calculated on demand */ + + /* Align the width on the next larger 8 pixels. Mainly used + * for interlacing + */ + row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); + /* Calculate the maximum bytes needed, adding a byte and a pixel + * for safety's sake + */ + row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + + 1 + ((max_pixel_depth + 7) >> 3U); + +#ifdef PNG_MAX_MALLOC_64K + if (row_bytes > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + + if (row_bytes + 48 > png_ptr->old_big_row_buf_size) + { + png_free(png_ptr, png_ptr->big_row_buf); + png_free(png_ptr, png_ptr->big_prev_row); + + if (png_ptr->interlaced != 0) + png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, + row_bytes + 48); + + else + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + + png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + +#ifdef PNG_ALIGNED_MEMORY_SUPPORTED + /* Use 16-byte aligned memory for row_buf with at least 16 bytes + * of padding before and after row_buf; treat prev_row similarly. + * NOTE: the alignment is to the start of the pixels, one beyond the start + * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this + * was incorrect; the filter byte was aligned, which had the exact + * opposite effect of that intended. + */ + { + png_bytep temp = png_ptr->big_row_buf + 32; + size_t extra = (size_t)temp & 0x0f; + png_ptr->row_buf = temp - extra - 1/*filter byte*/; + + temp = png_ptr->big_prev_row + 32; + extra = (size_t)temp & 0x0f; + png_ptr->prev_row = temp - extra - 1/*filter byte*/; + } +#else + /* Use 31 bytes of padding before and 17 bytes after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 31; + png_ptr->prev_row = png_ptr->big_prev_row + 31; +#endif + png_ptr->old_big_row_buf_size = row_bytes + 48; + } + +#ifdef PNG_MAX_MALLOC_64K + if (png_ptr->rowbytes > 65535) + png_error(png_ptr, "This image requires a row greater than 64KB"); + +#endif + if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1)) + png_error(png_ptr, "Row has too many bytes to allocate in memory"); + + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + png_debug1(3, "width = %u,", png_ptr->width); + png_debug1(3, "height = %u,", png_ptr->height); + png_debug1(3, "iwidth = %u,", png_ptr->iwidth); + png_debug1(3, "num_rows = %u,", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu", + (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + + /* The sequential reader needs a buffer for IDAT, but the progressive reader + * does not, so free the read buffer now regardless; the sequential reader + * reallocates it on demand. + */ + if (png_ptr->read_buffer != NULL) + { + png_bytep buffer = png_ptr->read_buffer; + + png_ptr->read_buffer_size = 0; + png_ptr->read_buffer = NULL; + png_free(png_ptr, buffer); + } + + /* Finally claim the zstream for the inflate of the IDAT data, use the bits + * value from the stream (note that this will result in a fatal error if the + * IDAT stream has a bogus deflate header window_bits value, but this should + * not be happening any longer!) + */ + if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + png_ptr->flags |= PNG_FLAG_ROW_INIT; +} +#endif /* READ */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngset.c b/widget/milsko/milskosrc/external/libpng/src/pngset.c new file mode 100644 index 0000000000..3e63c2724e --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngset.c @@ -0,0 +1,1986 @@ +/* pngset.c - storage of image information into info struct + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * The functions here are used during reads to store data from the file + * into the info struct, and during writes to store application data + * into the info struct for writing into the file. This abstracts the + * info struct and allows us to change the structure in the future. + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +#ifdef PNG_bKGD_SUPPORTED +void PNGAPI +png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_color_16p background) +{ + png_debug1(1, "in %s storage function", "bKGD"); + + if (png_ptr == NULL || info_ptr == NULL || background == NULL) + return; + + info_ptr->background = *background; + info_ptr->valid |= PNG_INFO_bKGD; +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +void PNGFAPI +png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + png_debug1(1, "in %s storage function", "cHRM fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->cHRM.redx = red_x; + info_ptr->cHRM.redy = red_y; + info_ptr->cHRM.greenx = green_x; + info_ptr->cHRM.greeny = green_y; + info_ptr->cHRM.bluex = blue_x; + info_ptr->cHRM.bluey = blue_y; + info_ptr->cHRM.whitex = white_x; + info_ptr->cHRM.whitey = white_y; + + info_ptr->valid |= PNG_INFO_cHRM; +} + +void PNGFAPI +png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z) +{ + png_XYZ XYZ; + png_xy xy; + + png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + XYZ.red_X = int_red_X; + XYZ.red_Y = int_red_Y; + XYZ.red_Z = int_red_Z; + XYZ.green_X = int_green_X; + XYZ.green_Y = int_green_Y; + XYZ.green_Z = int_green_Z; + XYZ.blue_X = int_blue_X; + XYZ.blue_Y = int_blue_Y; + XYZ.blue_Z = int_blue_Z; + + if (png_xy_from_XYZ(&xy, &XYZ) == 0) + { + info_ptr->cHRM = xy; + info_ptr->valid |= PNG_INFO_cHRM; + } + + else + png_app_error(png_ptr, "invalid cHRM XYZ"); +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, + double green_x, double green_y, double blue_x, double blue_y) +{ + png_set_cHRM_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, white_x, "cHRM White X"), + png_fixed(png_ptr, white_y, "cHRM White Y"), + png_fixed(png_ptr, red_x, "cHRM Red X"), + png_fixed(png_ptr, red_y, "cHRM Red Y"), + png_fixed(png_ptr, green_x, "cHRM Green X"), + png_fixed(png_ptr, green_y, "cHRM Green Y"), + png_fixed(png_ptr, blue_x, "cHRM Blue X"), + png_fixed(png_ptr, blue_y, "cHRM Blue Y")); +} + +void PNGAPI +png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, + double red_Y, double red_Z, double green_X, double green_Y, double green_Z, + double blue_X, double blue_Y, double blue_Z) +{ + png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, red_X, "cHRM Red X"), + png_fixed(png_ptr, red_Y, "cHRM Red Y"), + png_fixed(png_ptr, red_Z, "cHRM Red Z"), + png_fixed(png_ptr, green_X, "cHRM Green X"), + png_fixed(png_ptr, green_Y, "cHRM Green Y"), + png_fixed(png_ptr, green_Z, "cHRM Green Z"), + png_fixed(png_ptr, blue_X, "cHRM Blue X"), + png_fixed(png_ptr, blue_Y, "cHRM Blue Y"), + png_fixed(png_ptr, blue_Z, "cHRM Blue Z")); +} +# endif /* FLOATING_POINT */ + +#endif /* cHRM */ + +#ifdef PNG_cICP_SUPPORTED +void PNGAPI +png_set_cICP(png_const_structrp png_ptr, png_inforp info_ptr, + png_byte colour_primaries, png_byte transfer_function, + png_byte matrix_coefficients, png_byte video_full_range_flag) +{ + png_debug1(1, "in %s storage function", "cICP"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->cicp_colour_primaries = colour_primaries; + info_ptr->cicp_transfer_function = transfer_function; + info_ptr->cicp_matrix_coefficients = matrix_coefficients; + info_ptr->cicp_video_full_range_flag = video_full_range_flag; + + if (info_ptr->cicp_matrix_coefficients != 0) + { + png_warning(png_ptr, "Invalid cICP matrix coefficients"); + return; + } + + info_ptr->valid |= PNG_INFO_cICP; +} +#endif /* cICP */ + +#ifdef PNG_cLLI_SUPPORTED +void PNGFAPI +png_set_cLLI_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + /* The values below are in cd/m2 (nits) and are scaled by 10,000; not + * 100,000 as in the case of png_fixed_point. + */ + png_uint_32 maxCLL, png_uint_32 maxFALL) +{ + png_debug1(1, "in %s storage function", "cLLI"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Check the light level range: */ + if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU) + { + /* The limit is 200kcd/m2; somewhat bright but not inconceivable because + * human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2. + * + * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is + * 2kcd/m2. + */ + png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit", + PNG_CHUNK_WRITE_ERROR); + return; + } + + info_ptr->maxCLL = maxCLL; + info_ptr->maxFALL = maxFALL; + info_ptr->valid |= PNG_INFO_cLLI; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cLLI(png_const_structrp png_ptr, png_inforp info_ptr, + double maxCLL, double maxFALL) +{ + png_set_cLLI_fixed(png_ptr, info_ptr, + png_fixed_ITU(png_ptr, maxCLL, "png_set_cLLI(maxCLL)"), + png_fixed_ITU(png_ptr, maxFALL, "png_set_cLLI(maxFALL)")); +} +# endif /* FLOATING_POINT */ +#endif /* cLLI */ + +#ifdef PNG_mDCV_SUPPORTED +static png_uint_16 +png_ITU_fixed_16(int *error, png_fixed_point v) +{ + /* Return a safe uint16_t value scaled according to the ITU H273 rules for + * 16-bit display chromaticities. Functions like the corresponding + * png_fixed() internal function with regard to errors: it's an error on + * write, a chunk_benign_error on read: See the definition of + * png_chunk_report in pngpriv.h. + */ + v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */ + if (v > 65535 || v < 0) + { + *error = 1; + return 0; + } + + return (png_uint_16)/*SAFE*/v; +} + +void PNGAPI +png_set_mDCV_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point white_x, png_fixed_point white_y, + png_fixed_point red_x, png_fixed_point red_y, + png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y, + png_uint_32 maxDL, + png_uint_32 minDL) +{ + png_uint_16 rx, ry, gx, gy, bx, by, wx, wy; + int error; + + png_debug1(1, "in %s storage function", "mDCV"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Check the input values to ensure they are in the expected range: */ + error = 0; + rx = png_ITU_fixed_16(&error, red_x); + ry = png_ITU_fixed_16(&error, red_y); + gx = png_ITU_fixed_16(&error, green_x); + gy = png_ITU_fixed_16(&error, green_y); + bx = png_ITU_fixed_16(&error, blue_x); + by = png_ITU_fixed_16(&error, blue_y); + wx = png_ITU_fixed_16(&error, white_x); + wy = png_ITU_fixed_16(&error, white_y); + + if (error) + { + png_chunk_report(png_ptr, + "mDCV chromaticities outside representable range", + PNG_CHUNK_WRITE_ERROR); + return; + } + + /* Check the light level range: */ + if (maxDL > 0x7FFFFFFFU || minDL > 0x7FFFFFFFU) + { + /* The limit is 200kcd/m2; somewhat bright but not inconceivable because + * human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2. + * + * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is + * 2kcd/m2. + */ + png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit", + PNG_CHUNK_WRITE_ERROR); + return; + } + + /* All values are safe, the settings are accepted. + * + * IMPLEMENTATION NOTE: in practice the values can be checked and assigned + * but the result is confusing if a writing app calls png_set_mDCV more than + * once, the second time with an invalid value. This approach is more + * obviously correct at the cost of typing and a very slight machine + * overhead. + */ + info_ptr->mastering_red_x = rx; + info_ptr->mastering_red_y = ry; + info_ptr->mastering_green_x = gx; + info_ptr->mastering_green_y = gy; + info_ptr->mastering_blue_x = bx; + info_ptr->mastering_blue_y = by; + info_ptr->mastering_white_x = wx; + info_ptr->mastering_white_y = wy; + info_ptr->mastering_maxDL = maxDL; + info_ptr->mastering_minDL = minDL; + info_ptr->valid |= PNG_INFO_mDCV; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_mDCV(png_const_structrp png_ptr, png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, double green_x, + double green_y, double blue_x, double blue_y, + double maxDL, double minDL) +{ + png_set_mDCV_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"), + png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"), + png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"), + png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"), + png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"), + png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"), + png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"), + png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"), + png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"), + png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)")); +} +# endif /* FLOATING_POINT */ +#endif /* mDCV */ + +#ifdef PNG_eXIf_SUPPORTED +void PNGAPI +png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytep exif) +{ + png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1"); + PNG_UNUSED(info_ptr) + PNG_UNUSED(exif) +} + +void PNGAPI +png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_32 num_exif, png_bytep exif) +{ + png_bytep new_exif; + + png_debug1(1, "in %s storage function", "eXIf"); + + if (png_ptr == NULL || info_ptr == NULL || + (png_ptr->mode & PNG_WROTE_eXIf) != 0) + return; + + new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif)); + + if (new_exif == NULL) + { + png_warning(png_ptr, "Insufficient memory for eXIf chunk data"); + return; + } + + memcpy(new_exif, exif, (size_t)num_exif); + + png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0); + + info_ptr->num_exif = num_exif; + info_ptr->exif = new_exif; + info_ptr->free_me |= PNG_FREE_EXIF; + info_ptr->valid |= PNG_INFO_eXIf; +} +#endif /* eXIf */ + +#ifdef PNG_gAMA_SUPPORTED +void PNGFAPI +png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point file_gamma) +{ + png_debug1(1, "in %s storage function", "gAMA"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->gamma = file_gamma; + info_ptr->valid |= PNG_INFO_gAMA; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) +{ + png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, + "png_set_gAMA")); +} +# endif +#endif + +#ifdef PNG_hIST_SUPPORTED +void PNGAPI +png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_uint_16p hist) +{ + int i; + + png_debug1(1, "in %s storage function", "hIST"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->num_palette == 0 || info_ptr->num_palette + > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, + "Invalid palette size, hIST allocation skipped"); + + return; + } + + png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); + + /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in + * version 1.2.1 + */ + info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); + + if (info_ptr->hist == NULL) + { + png_warning(png_ptr, "Insufficient memory for hIST chunk data"); + return; + } + + for (i = 0; i < info_ptr->num_palette; i++) + info_ptr->hist[i] = hist[i]; + + info_ptr->free_me |= PNG_FREE_HIST; + info_ptr->valid |= PNG_INFO_hIST; +} +#endif + +void PNGAPI +png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + png_debug1(1, "in %s storage function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->width = width; + info_ptr->height = height; + info_ptr->bit_depth = (png_byte)bit_depth; + info_ptr->color_type = (png_byte)color_type; + info_ptr->compression_type = (png_byte)compression_type; + info_ptr->filter_type = (png_byte)filter_type; + info_ptr->interlace_type = (png_byte)interlace_type; + + png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + info_ptr->channels = 3; + + else + info_ptr->channels = 1; + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + info_ptr->channels++; + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); +} + +#ifdef PNG_oFFs_SUPPORTED +void PNGAPI +png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "oFFs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_offset = offset_x; + info_ptr->y_offset = offset_y; + info_ptr->offset_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_oFFs; +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +void PNGAPI +png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, + int nparams, png_const_charp units, png_charpp params) +{ + size_t length; + int i; + + png_debug1(1, "in %s storage function", "pCAL"); + + if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL + || (nparams > 0 && params == NULL)) + return; + + length = strlen(purpose) + 1; + png_debug1(3, "allocating purpose for info (%lu bytes)", + (unsigned long)length); + + /* TODO: validate format of calibration name and unit name */ + + /* Check that the type matches the specification. */ + if (type < 0 || type > 3) + { + png_chunk_report(png_ptr, "Invalid pCAL equation type", + PNG_CHUNK_WRITE_ERROR); + return; + } + + if (nparams < 0 || nparams > 255) + { + png_chunk_report(png_ptr, "Invalid pCAL parameter count", + PNG_CHUNK_WRITE_ERROR); + return; + } + + /* Validate params[nparams] */ + for (i=0; ipcal_purpose = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); + + if (info_ptr->pcal_purpose == NULL) + { + png_chunk_report(png_ptr, "Insufficient memory for pCAL purpose", + PNG_CHUNK_WRITE_ERROR); + return; + } + + memcpy(info_ptr->pcal_purpose, purpose, length); + + info_ptr->free_me |= PNG_FREE_PCAL; + + png_debug(3, "storing X0, X1, type, and nparams in info"); + info_ptr->pcal_X0 = X0; + info_ptr->pcal_X1 = X1; + info_ptr->pcal_type = (png_byte)type; + info_ptr->pcal_nparams = (png_byte)nparams; + + length = strlen(units) + 1; + png_debug1(3, "allocating units for info (%lu bytes)", + (unsigned long)length); + + info_ptr->pcal_units = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); + + if (info_ptr->pcal_units == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL units"); + return; + } + + memcpy(info_ptr->pcal_units, units, length); + + info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + (size_t)(((unsigned int)nparams + 1) * (sizeof (png_charp))))); + + if (info_ptr->pcal_params == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL params"); + return; + } + + memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) * + (sizeof (png_charp))); + + for (i = 0; i < nparams; i++) + { + length = strlen(params[i]) + 1; + png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, + (unsigned long)length); + + info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); + + if (info_ptr->pcal_params[i] == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL parameter"); + return; + } + + memcpy(info_ptr->pcal_params[i], params[i], length); + } + + info_ptr->valid |= PNG_INFO_pCAL; +} +#endif + +#ifdef PNG_sCAL_SUPPORTED +void PNGAPI +png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, + int unit, png_const_charp swidth, png_const_charp sheight) +{ + size_t lengthw = 0, lengthh = 0; + + png_debug1(1, "in %s storage function", "sCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Double check the unit (should never get here with an invalid + * unit unless this is an API call.) + */ + if (unit != 1 && unit != 2) + png_error(png_ptr, "Invalid sCAL unit"); + + if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || + swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) + png_error(png_ptr, "Invalid sCAL width"); + + if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || + sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) + png_error(png_ptr, "Invalid sCAL height"); + + info_ptr->scal_unit = (png_byte)unit; + + ++lengthw; + + png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); + + info_ptr->scal_s_width = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthw)); + + if (info_ptr->scal_s_width == NULL) + { + png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + + return; + } + + memcpy(info_ptr->scal_s_width, swidth, lengthw); + + ++lengthh; + + png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); + + info_ptr->scal_s_height = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthh)); + + if (info_ptr->scal_s_height == NULL) + { + png_free(png_ptr, info_ptr->scal_s_width); + info_ptr->scal_s_width = NULL; + + png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; + } + + memcpy(info_ptr->scal_s_height, sheight, lengthh); + + info_ptr->free_me |= PNG_FREE_SCAL; + info_ptr->valid |= PNG_INFO_sCAL; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + double width, double height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + /* Check the arguments. */ + if (width <= 0) + png_warning(png_ptr, "Invalid sCAL width ignored"); + + else if (height <= 0) + png_warning(png_ptr, "Invalid sCAL height ignored"); + + else + { + /* Convert 'width' and 'height' to ASCII. */ + char swidth[PNG_sCAL_MAX_DIGITS+1]; + char sheight[PNG_sCAL_MAX_DIGITS+1]; + + png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, + PNG_sCAL_PRECISION); + png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, + PNG_sCAL_PRECISION); + + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); + } +} +# endif + +# ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + png_fixed_point width, png_fixed_point height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + /* Check the arguments. */ + if (width <= 0) + png_warning(png_ptr, "Invalid sCAL width ignored"); + + else if (height <= 0) + png_warning(png_ptr, "Invalid sCAL height ignored"); + + else + { + /* Convert 'width' and 'height' to ASCII. */ + char swidth[PNG_sCAL_MAX_DIGITS+1]; + char sheight[PNG_sCAL_MAX_DIGITS+1]; + + png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); + png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); + + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); + } +} +# endif +#endif + +#ifdef PNG_pHYs_SUPPORTED +void PNGAPI +png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "pHYs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_pixels_per_unit = res_x; + info_ptr->y_pixels_per_unit = res_y; + info_ptr->phys_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_pHYs; +} +#endif + +void PNGAPI +png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, + png_const_colorp palette, int num_palette) +{ + + png_uint_32 max_palette_length; + + png_debug1(1, "in %s storage function", "PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; + + if (num_palette < 0 || num_palette > (int) max_palette_length) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Invalid palette length"); + + else + { + png_warning(png_ptr, "Invalid palette length"); + + return; + } + } + + if ((num_palette > 0 && palette == NULL) || + (num_palette == 0 +# ifdef PNG_MNG_FEATURES_SUPPORTED + && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 +# endif + )) + { + png_error(png_ptr, "Invalid palette"); + } + + /* It may not actually be necessary to set png_ptr->palette here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + * + * 1.6.0: the above statement appears to be incorrect; something has to set + * the palette inside png_struct on read. + */ + png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); + + /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead + * of num_palette entries, in case of an invalid PNG file or incorrect + * call to png_set_PLTE() with too-large sample values. + */ + png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + + if (num_palette > 0) + memcpy(png_ptr->palette, palette, (unsigned int)num_palette * + (sizeof (png_color))); + + info_ptr->palette = png_ptr->palette; + info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; + info_ptr->free_me |= PNG_FREE_PLTE; + info_ptr->valid |= PNG_INFO_PLTE; +} + +#ifdef PNG_sBIT_SUPPORTED +void PNGAPI +png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_color_8p sig_bit) +{ + png_debug1(1, "in %s storage function", "sBIT"); + + if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) + return; + + info_ptr->sig_bit = *sig_bit; + info_ptr->valid |= PNG_INFO_sBIT; +} +#endif + +#ifdef PNG_sRGB_SUPPORTED +void PNGAPI +png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) +{ + png_debug1(1, "in %s storage function", "sRGB"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->rendering_intent = srgb_intent; + info_ptr->valid |= PNG_INFO_sRGB; +} + +void PNGAPI +png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, + int srgb_intent) +{ + png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_set_sRGB(png_ptr, info_ptr, srgb_intent); + +# ifdef PNG_gAMA_SUPPORTED + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); +# endif /* gAMA */ + +# ifdef PNG_cHRM_SUPPORTED + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000); +# endif /* cHRM */ +} +#endif /* sRGB */ + + +#ifdef PNG_iCCP_SUPPORTED +void PNGAPI +png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen) +{ + png_charp new_iccp_name; + png_bytep new_iccp_profile; + size_t length; + + png_debug1(1, "in %s storage function", "iCCP"); + + if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) + return; + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_app_error(png_ptr, "Invalid iCCP compression method"); + + length = strlen(name)+1; + new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); + + if (new_iccp_name == NULL) + { + png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); + + return; + } + + memcpy(new_iccp_name, name, length); + new_iccp_profile = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, proflen)); + + if (new_iccp_profile == NULL) + { + png_free(png_ptr, new_iccp_name); + png_benign_error(png_ptr, + "Insufficient memory to process iCCP profile"); + + return; + } + + memcpy(new_iccp_profile, profile, proflen); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); + + info_ptr->iccp_proflen = proflen; + info_ptr->iccp_name = new_iccp_name; + info_ptr->iccp_profile = new_iccp_profile; + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +void PNGAPI +png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) +{ + int ret; + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); + + if (ret != 0) + png_error(png_ptr, "Insufficient memory to store text"); +} + +int /* PRIVATE */ +png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) +{ + int i; + + png_debug1(1, "in text storage function, chunk typeid = 0x%lx", + png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name); + + if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) + return 0; + + /* Make sure we have enough space in the "text" array in info_struct + * to hold all of the incoming text_ptr objects. This compare can't overflow + * because max_text >= num_text (anyway, subtract of two positive integers + * can't overflow in any case.) + */ + if (num_text > info_ptr->max_text - info_ptr->num_text) + { + int old_num_text = info_ptr->num_text; + int max_text; + png_textp new_text = NULL; + + /* Calculate an appropriate max_text, checking for overflow. */ + max_text = old_num_text; + if (num_text <= INT_MAX - max_text) + { + max_text += num_text; + + /* Round up to a multiple of 8 */ + if (max_text < INT_MAX-8) + max_text = (max_text + 8) & ~0x7; + + else + max_text = INT_MAX; + + /* Now allocate a new array and copy the old members in; this does all + * the overflow checks. + */ + new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, + info_ptr->text, old_num_text, max_text-old_num_text, + sizeof *new_text)); + } + + if (new_text == NULL) + { + png_chunk_report(png_ptr, "too many text chunks", + PNG_CHUNK_WRITE_ERROR); + + return 1; + } + + png_free(png_ptr, info_ptr->text); + + info_ptr->text = new_text; + info_ptr->free_me |= PNG_FREE_TEXT; + info_ptr->max_text = max_text; + /* num_text is adjusted below as the entries are copied in */ + + png_debug1(3, "allocated %d entries for info_ptr->text", max_text); + } + + for (i = 0; i < num_text; i++) + { + size_t text_length, key_len; + size_t lang_len, lang_key_len; + png_textp textp = &(info_ptr->text[info_ptr->num_text]); + + if (text_ptr[i].key == NULL) + continue; + + if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE || + text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) + { + png_chunk_report(png_ptr, "text compression mode is out of range", + PNG_CHUNK_WRITE_ERROR); + continue; + } + + key_len = strlen(text_ptr[i].key); + + if (text_ptr[i].compression <= 0) + { + lang_len = 0; + lang_key_len = 0; + } + + else +# ifdef PNG_iTXt_SUPPORTED + { + /* Set iTXt data */ + + if (text_ptr[i].lang != NULL) + lang_len = strlen(text_ptr[i].lang); + + else + lang_len = 0; + + if (text_ptr[i].lang_key != NULL) + lang_key_len = strlen(text_ptr[i].lang_key); + + else + lang_key_len = 0; + } +# else /* iTXt */ + { + png_chunk_report(png_ptr, "iTXt chunk not supported", + PNG_CHUNK_WRITE_ERROR); + continue; + } +# endif + + if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') + { + text_length = 0; +# ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + textp->compression = PNG_ITXT_COMPRESSION_NONE; + + else +# endif + textp->compression = PNG_TEXT_COMPRESSION_NONE; + } + + else + { + text_length = strlen(text_ptr[i].text); + textp->compression = text_ptr[i].compression; + } + + textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, + key_len + text_length + lang_len + lang_key_len + 4)); + + if (textp->key == NULL) + { + png_chunk_report(png_ptr, "text chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + + return 1; + } + + png_debug2(2, "Allocated %lu bytes at %p in png_set_text", + (unsigned long)(png_uint_32) + (key_len + lang_len + lang_key_len + text_length + 4), + textp->key); + + memcpy(textp->key, text_ptr[i].key, key_len); + *(textp->key + key_len) = '\0'; + + if (text_ptr[i].compression > 0) + { + textp->lang = textp->key + key_len + 1; + memcpy(textp->lang, text_ptr[i].lang, lang_len); + *(textp->lang + lang_len) = '\0'; + textp->lang_key = textp->lang + lang_len + 1; + memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + *(textp->lang_key + lang_key_len) = '\0'; + textp->text = textp->lang_key + lang_key_len + 1; + } + + else + { + textp->lang=NULL; + textp->lang_key=NULL; + textp->text = textp->key + key_len + 1; + } + + if (text_length != 0) + memcpy(textp->text, text_ptr[i].text, text_length); + + *(textp->text + text_length) = '\0'; + +# ifdef PNG_iTXt_SUPPORTED + if (textp->compression > 0) + { + textp->text_length = 0; + textp->itxt_length = text_length; + } + + else +# endif + { + textp->text_length = text_length; + textp->itxt_length = 0; + } + + info_ptr->num_text++; + png_debug1(3, "transferred text chunk %d", info_ptr->num_text); + } + + return 0; +} +#endif + +#ifdef PNG_tIME_SUPPORTED +void PNGAPI +png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_timep mod_time) +{ + png_debug1(1, "in %s storage function", "tIME"); + + if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || + (png_ptr->mode & PNG_WROTE_tIME) != 0) + return; + + if (mod_time->month == 0 || mod_time->month > 12 || + mod_time->day == 0 || mod_time->day > 31 || + mod_time->hour > 23 || mod_time->minute > 59 || + mod_time->second > 60) + { + png_warning(png_ptr, "Ignoring invalid time value"); + + return; + } + + info_ptr->mod_time = *mod_time; + info_ptr->valid |= PNG_INFO_tIME; +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +void PNGAPI +png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, + png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) +{ + png_debug1(1, "in %s storage function", "tRNS"); + + if (png_ptr == NULL || info_ptr == NULL) + + return; + + if (trans_alpha != NULL) + { + /* It may not actually be necessary to set png_ptr->trans_alpha here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + * + * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively + * relies on png_set_tRNS storing the information in png_struct + * (otherwise it won't be there for the code in pngrtran.c). + */ + + png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); + + if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) + { + /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ + info_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); + memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans); + + info_ptr->free_me |= PNG_FREE_TRNS; + info_ptr->valid |= PNG_INFO_tRNS; + } + png_ptr->trans_alpha = info_ptr->trans_alpha; + } + + if (trans_color != NULL) + { +#ifdef PNG_WARNINGS_SUPPORTED + if (info_ptr->bit_depth < 16) + { + int sample_max = (1 << info_ptr->bit_depth) - 1; + + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + trans_color->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + (trans_color->red > sample_max || + trans_color->green > sample_max || + trans_color->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); + } +#endif + + info_ptr->trans_color = *trans_color; + + if (num_trans == 0) + num_trans = 1; + } + + info_ptr->num_trans = (png_uint_16)num_trans; + + if (num_trans != 0) + { + info_ptr->free_me |= PNG_FREE_TRNS; + info_ptr->valid |= PNG_INFO_tRNS; + } +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +void PNGAPI +png_set_sPLT(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) +/* + * entries - array of png_sPLT_t structures + * to be added to the list of palettes + * in the info structure. + * + * nentries - number of palette structures to be + * added. + */ +{ + png_sPLT_tp np; + + png_debug1(1, "in %s storage function", "sPLT"); + + if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) + return; + + /* Use the internal realloc function, which checks for all the possible + * overflows. Notice that the parameters are (int) and (size_t) + */ + np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, + info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, + sizeof *np)); + + if (np == NULL) + { + /* Out of memory or too many chunks */ + png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); + return; + } + + png_free(png_ptr, info_ptr->splt_palettes); + + info_ptr->splt_palettes = np; + info_ptr->free_me |= PNG_FREE_SPLT; + + np += info_ptr->splt_palettes_num; + + do + { + size_t length; + + /* Skip invalid input entries */ + if (entries->name == NULL || entries->entries == NULL) + { + /* png_handle_sPLT doesn't do this, so this is an app error */ + png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); + /* Just skip the invalid entry */ + continue; + } + + np->depth = entries->depth; + + /* In the event of out-of-memory just return - there's no point keeping + * on trying to add sPLT chunks. + */ + length = strlen(entries->name) + 1; + np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); + + if (np->name == NULL) + break; + + memcpy(np->name, entries->name, length); + + /* IMPORTANT: we have memory now that won't get freed if something else + * goes wrong; this code must free it. png_malloc_array produces no + * warnings; use a png_chunk_report (below) if there is an error. + */ + np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, + entries->nentries, sizeof (png_sPLT_entry))); + + if (np->entries == NULL) + { + png_free(png_ptr, np->name); + np->name = NULL; + break; + } + + np->nentries = entries->nentries; + /* This multiply can't overflow because png_malloc_array has already + * checked it when doing the allocation. + */ + memcpy(np->entries, entries->entries, + (unsigned int)entries->nentries * sizeof (png_sPLT_entry)); + + /* Note that 'continue' skips the advance of the out pointer and out + * count, so an invalid entry is not added. + */ + info_ptr->valid |= PNG_INFO_sPLT; + ++(info_ptr->splt_palettes_num); + ++np; + ++entries; + } + while (--nentries); + + if (nentries > 0) + png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); +} +#endif /* sPLT */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +static png_byte +check_location(png_const_structrp png_ptr, int location) +{ + location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); + + /* New in 1.6.0; copy the location and check it. This is an API + * change; previously the app had to use the + * png_set_unknown_chunk_location API below for each chunk. + */ + if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + /* Write struct, so unknown chunks come from the app */ + png_app_warning(png_ptr, + "png_set_unknown_chunks now expects a valid location"); + /* Use the old behavior */ + location = (png_byte)(png_ptr->mode & + (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); + } + + /* This need not be an internal error - if the app calls + * png_set_unknown_chunks on a read pointer it must get the location right. + */ + if (location == 0) + png_error(png_ptr, "invalid location in png_set_unknown_chunks"); + + /* Now reduce the location to the top-most set bit by removing each least + * significant bit in turn. + */ + while (location != (location & -location)) + location &= ~(location & -location); + + /* The cast is safe because 'location' is a bit mask and only the low four + * bits are significant. + */ + return (png_byte)location; +} + +void PNGAPI +png_set_unknown_chunks(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) +{ + png_unknown_chunkp np; + + if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || + unknowns == NULL) + return; + + /* Check for the failure cases where support has been disabled at compile + * time. This code is hardly ever compiled - it's here because + * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this + * code) but may be meaningless if the read or write handling of unknown + * chunks is not compiled in. + */ +# if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_app_error(png_ptr, "no unknown chunk support on read"); + + return; + } +# endif +# if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + png_app_error(png_ptr, "no unknown chunk support on write"); + + return; + } +# endif + + /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that + * unknown critical chunks could be lost with just a warning resulting in + * undefined behavior. Now png_chunk_report is used to provide behavior + * appropriate to read or write. + */ + np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, + info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, + sizeof *np)); + + if (np == NULL) + { + png_chunk_report(png_ptr, "too many unknown chunks", + PNG_CHUNK_WRITE_ERROR); + return; + } + + png_free(png_ptr, info_ptr->unknown_chunks); + + info_ptr->unknown_chunks = np; /* safe because it is initialized */ + info_ptr->free_me |= PNG_FREE_UNKN; + + np += info_ptr->unknown_chunks_num; + + /* Increment unknown_chunks_num each time round the loop to protect the + * just-allocated chunk data. + */ + for (; num_unknowns > 0; --num_unknowns, ++unknowns) + { + memcpy(np->name, unknowns->name, (sizeof np->name)); + np->name[(sizeof np->name)-1] = '\0'; + np->location = check_location(png_ptr, unknowns->location); + + if (unknowns->size == 0) + { + np->data = NULL; + np->size = 0; + } + + else + { + np->data = png_voidcast(png_bytep, + png_malloc_base(png_ptr, unknowns->size)); + + if (np->data == NULL) + { + png_chunk_report(png_ptr, "unknown chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + /* But just skip storing the unknown chunk */ + continue; + } + + memcpy(np->data, unknowns->data, unknowns->size); + np->size = unknowns->size; + } + + /* These increments are skipped on out-of-memory for the data - the + * unknown chunk entry gets overwritten if the png_chunk_report returns. + * This is correct in the read case (the chunk is just dropped.) + */ + ++np; + ++(info_ptr->unknown_chunks_num); + } +} + +void PNGAPI +png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, + int chunk, int location) +{ + /* This API is pretty pointless in 1.6.0 because the location can be set + * before the call to png_set_unknown_chunks. + * + * TODO: add a png_app_warning in 1.7 + */ + if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && + chunk < info_ptr->unknown_chunks_num) + { + if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) + { + png_app_error(png_ptr, "invalid unknown chunk location"); + /* Fake out the pre 1.6.0 behavior: */ + if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */ + location = PNG_AFTER_IDAT; + + else + location = PNG_HAVE_IHDR; /* also undocumented */ + } + + info_ptr->unknown_chunks[chunk].location = + check_location(png_ptr, location); + } +} +#endif /* STORE_UNKNOWN_CHUNKS */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +png_uint_32 PNGAPI +png_permit_mng_features(png_structrp png_ptr, png_uint_32 mng_features) +{ + png_debug(1, "in png_permit_mng_features"); + + if (png_ptr == NULL) + return 0; + + png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; + + return png_ptr->mng_features_permitted; +} +#endif + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static unsigned int +add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) +{ + unsigned int i; + + /* Utility function: update the 'keep' state of a chunk if it is already in + * the list, otherwise add it to the list. + */ + for (i=0; i= PNG_HANDLE_CHUNK_LAST) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); + + return; + } + + if (num_chunks_in <= 0) + { + png_ptr->unknown_default = keep; + + /* '0' means just set the flags, so stop here */ + if (num_chunks_in == 0) + return; + } + + if (num_chunks_in < 0) + { + /* Ignore all unknown chunks and all chunks recognized by + * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND + */ + static const png_byte chunks_to_ignore[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 99, 73, 67, 80, '\0', /* cICP */ + 99, 76, 76, 73, '\0', /* cLLI */ + 101, 88, 73, 102, '\0', /* eXIf */ + 103, 65, 77, 65, '\0', /* gAMA */ + 104, 73, 83, 84, '\0', /* hIST */ + 105, 67, 67, 80, '\0', /* iCCP */ + 105, 84, 88, 116, '\0', /* iTXt */ + 109, 68, 67, 86, '\0', /* mDCV */ + 111, 70, 70, 115, '\0', /* oFFs */ + 112, 67, 65, 76, '\0', /* pCAL */ + 112, 72, 89, 115, '\0', /* pHYs */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 67, 65, 76, '\0', /* sCAL */ + 115, 80, 76, 84, '\0', /* sPLT */ + 115, 84, 69, 82, '\0', /* sTER */ + 115, 82, 71, 66, '\0', /* sRGB */ + 116, 69, 88, 116, '\0', /* tEXt */ + 116, 73, 77, 69, '\0', /* tIME */ + 122, 84, 88, 116, '\0' /* zTXt */ + }; + + chunk_list = chunks_to_ignore; + num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U; + } + + else /* num_chunks_in > 0 */ + { + if (chunk_list == NULL) + { + /* Prior to 1.6.0 this was silently ignored, now it is an app_error + * which can be switched off. + */ + png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); + + return; + } + + num_chunks = (unsigned int)num_chunks_in; + } + + old_num_chunks = png_ptr->num_chunk_list; + if (png_ptr->chunk_list == NULL) + old_num_chunks = 0; + + /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. + */ + if (num_chunks + old_num_chunks > UINT_MAX/5) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); + + return; + } + + /* If these chunks are being reset to the default then no more memory is + * required because add_one_chunk above doesn't extend the list if the 'keep' + * parameter is the default. + */ + if (keep != 0) + { + new_list = png_voidcast(png_bytep, png_malloc(png_ptr, + 5 * (num_chunks + old_num_chunks))); + + if (old_num_chunks > 0) + memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); + } + + else if (old_num_chunks > 0) + new_list = png_ptr->chunk_list; + + else + new_list = NULL; + + /* Add the new chunks together with each one's handling code. If the chunk + * already exists the code is updated, otherwise the chunk is added to the + * end. (In libpng 1.6.0 order no longer matters because this code enforces + * the earlier convention that the last setting is the one that is used.) + */ + if (new_list != NULL) + { + png_const_bytep inlist; + png_bytep outlist; + unsigned int i; + + for (i=0; ichunk_list != new_list) + png_free(png_ptr, new_list); + + new_list = NULL; + } + } + + else + num_chunks = 0; + + png_ptr->num_chunk_list = num_chunks; + + if (png_ptr->chunk_list != new_list) + { + if (png_ptr->chunk_list != NULL) + png_free(png_ptr, png_ptr->chunk_list); + + png_ptr->chunk_list = new_list; + } +} +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +void PNGAPI +png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr, + png_user_chunk_ptr read_user_chunk_fn) +{ + png_debug(1, "in png_set_read_user_chunk_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->read_user_chunk_fn = read_user_chunk_fn; + png_ptr->user_chunk_ptr = user_chunk_ptr; +} +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytepp row_pointers) +{ + png_debug(1, "in png_set_rows"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->row_pointers != NULL && + (info_ptr->row_pointers != row_pointers)) + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + + info_ptr->row_pointers = row_pointers; + + if (row_pointers != NULL) + info_ptr->valid |= PNG_INFO_IDAT; +} +#endif + +void PNGAPI +png_set_compression_buffer_size(png_structrp png_ptr, size_t size) +{ + png_debug(1, "in png_set_compression_buffer_size"); + + if (png_ptr == NULL) + return; + + if (size == 0 || size > PNG_UINT_31_MAX) + png_error(png_ptr, "invalid compression buffer size"); + +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ + return; + } +# endif + +# ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + if (png_ptr->zowner != 0) + { + png_warning(png_ptr, + "Compression buffer size cannot be changed because it is in use"); + + return; + } + +#ifndef __COVERITY__ + /* Some compilers complain that this is always false. However, it + * can be true when integer overflow happens. + */ + if (size > ZLIB_IO_MAX) + { + png_warning(png_ptr, + "Compression buffer size limited to system maximum"); + size = ZLIB_IO_MAX; /* must fit */ + } +#endif + + if (size < 6) + { + /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH + * if this is permitted. + */ + png_warning(png_ptr, + "Compression buffer size cannot be reduced below 6"); + + return; + } + + if (png_ptr->zbuffer_size != size) + { + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_ptr->zbuffer_size = (uInt)size; + } + } +# endif +} + +void PNGAPI +png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) +{ + if (png_ptr != NULL && info_ptr != NULL) + info_ptr->valid &= (unsigned int)(~mask); +} + + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* This function was added to libpng 1.2.6 */ +void PNGAPI +png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max, + png_uint_32 user_height_max) +{ + png_debug(1, "in png_set_user_limits"); + + /* Images with dimensions larger than these limits will be + * rejected by png_set_IHDR(). To accept any PNG datastream + * regardless of dimensions, set both limits to 0x7fffffff. + */ + if (png_ptr == NULL) + return; + + png_ptr->user_width_max = user_width_max; + png_ptr->user_height_max = user_height_max; +} + +/* This function was added to libpng 1.4.0 */ +void PNGAPI +png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max) +{ + png_debug(1, "in png_set_chunk_cache_max"); + + if (png_ptr != NULL) + png_ptr->user_chunk_cache_max = user_chunk_cache_max; +} + +/* This function was added to libpng 1.4.1 */ +void PNGAPI +png_set_chunk_malloc_max(png_structrp png_ptr, + png_alloc_size_t user_chunk_malloc_max) +{ + png_debug(1, "in png_set_chunk_malloc_max"); + + /* pngstruct::user_chunk_malloc_max is initialized to a non-zero value in + * png.c. This API supports '0' for unlimited, make sure the correct + * (unlimited) value is set here to avoid a need to check for 0 everywhere + * the parameter is used. + */ + if (png_ptr != NULL) + { + if (user_chunk_malloc_max == 0U) /* unlimited */ + { +# ifdef PNG_MAX_MALLOC_64K + png_ptr->user_chunk_malloc_max = 65536U; +# else + png_ptr->user_chunk_malloc_max = PNG_SIZE_MAX; +# endif + } + else + png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; + } +} +#endif /* ?SET_USER_LIMITS */ + + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_set_benign_errors(png_structrp png_ptr, int allowed) +{ + png_debug(1, "in png_set_benign_errors"); + + /* If allowed is 1, png_benign_error() is treated as a warning. + * + * If allowed is 0, png_benign_error() is treated as an error (which + * is the default behavior if png_set_benign_errors() is not called). + */ + + if (allowed != 0) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; + + else + png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); +} +#endif /* BENIGN_ERRORS */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Whether to report invalid palette index; added at libng-1.5.10. + * It is possible for an indexed (color-type==3) PNG file to contain + * pixels with invalid (out-of-range) indexes if the PLTE chunk has + * fewer entries than the image's bit-depth would allow. We recover + * from this gracefully by filling any incomplete palette with zeros + * (opaque black). By default, when this occurs libpng will issue + * a benign error. This API can be used to override that behavior. + */ +void PNGAPI +png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) +{ + png_debug(1, "in png_set_check_for_invalid_index"); + + if (allowed > 0) + png_ptr->num_palette_max = 0; + + else + png_ptr->num_palette_max = -1; +} +#endif + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \ + defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The 'new_key' buffer must be 80 characters in size (for the keyword plus a + * trailing '\0'). If this routine returns 0 then there was no keyword, or a + * valid one could not be generated, and the caller must png_error. + */ +png_uint_32 /* PRIVATE */ +png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) +{ +#ifdef PNG_WARNINGS_SUPPORTED + png_const_charp orig_key = key; +#endif + png_uint_32 key_len = 0; + int bad_character = 0; + int space = 1; + + png_debug(1, "in png_check_keyword"); + + if (key == NULL) + { + *new_key = 0; + return 0; + } + + while (*key && key_len < 79) + { + png_byte ch = (png_byte)*key++; + + if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) + { + *new_key++ = ch; ++key_len; space = 0; + } + + else if (space == 0) + { + /* A space or an invalid character when one wasn't seen immediately + * before; output just a space. + */ + *new_key++ = 32; ++key_len; space = 1; + + /* If the character was not a space then it is invalid. */ + if (ch != 32) + bad_character = ch; + } + + else if (bad_character == 0) + bad_character = ch; /* just skip it, record the first error */ + } + + if (key_len > 0 && space != 0) /* trailing space */ + { + --key_len; --new_key; + if (bad_character == 0) + bad_character = 32; + } + + /* Terminate the keyword */ + *new_key = 0; + + if (key_len == 0) + return 0; + +#ifdef PNG_WARNINGS_SUPPORTED + /* Try to only output one warning per keyword: */ + if (*key != 0) /* keyword too long */ + png_warning(png_ptr, "keyword truncated"); + + else if (bad_character != 0) + { + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter(p, 1, orig_key); + png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); + + png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); + } +#else /* !WARNINGS */ + PNG_UNUSED(png_ptr) +#endif /* !WARNINGS */ + + return key_len; +} +#endif /* TEXT || pCAL || iCCP || sPLT */ +#endif /* READ || WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngtrans.c b/widget/milsko/milskosrc/external/libpng/src/pngtrans.c new file mode 100644 index 0000000000..222b4987f9 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngtrans.c @@ -0,0 +1,867 @@ +/* pngtrans.c - transforms the data in a row (used by both readers and writers) + * + * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Turn on BGR-to-RGB mapping */ +void PNGAPI +png_set_bgr(png_structrp png_ptr) +{ + png_debug(1, "in png_set_bgr"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_BGR; +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Turn on 16-bit byte swapping */ +void PNGAPI +png_set_swap(png_structrp png_ptr) +{ + png_debug(1, "in png_set_swap"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth == 16) + png_ptr->transformations |= PNG_SWAP_BYTES; +} +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Turn on pixel packing */ +void PNGAPI +png_set_packing(png_structrp png_ptr) +{ + png_debug(1, "in png_set_packing"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth < 8) + { + png_ptr->transformations |= PNG_PACK; +# ifdef PNG_WRITE_SUPPORTED + png_ptr->usr_bit_depth = 8; +# endif + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Turn on packed pixel swapping */ +void PNGAPI +png_set_packswap(png_structrp png_ptr) +{ + png_debug(1, "in png_set_packswap"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth < 8) + png_ptr->transformations |= PNG_PACKSWAP; +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +void PNGAPI +png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) +{ + png_debug(1, "in png_set_shift"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_SHIFT; + png_ptr->shift = *true_bits; +} +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +int PNGAPI +png_set_interlace_handling(png_structrp png_ptr) +{ + png_debug(1, "in png_set_interlace handling"); + + if (png_ptr != 0 && png_ptr->interlaced != 0) + { + png_ptr->transformations |= PNG_INTERLACE; + return 7; + } + + return 1; +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte on read, or remove a filler or alpha byte on write. + * The filler type has changed in v0.95 to allow future 2-byte fillers + * for 48-bit input data, as well as to avoid problems with some compilers + * that don't like bytes as parameters. + */ +void PNGAPI +png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_filler"); + + if (png_ptr == NULL) + return; + + /* In libpng 1.6 it is possible to determine whether this is a read or write + * operation and therefore to do more checking here for a valid call. + */ + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { +# ifdef PNG_READ_FILLER_SUPPORTED + /* On read png_set_filler is always valid, regardless of the base PNG + * format, because other transformations can give a format where the + * filler code can execute (basically an 8 or 16-bit component RGB or G + * format.) + * + * NOTE: usr_channels is not used by the read code! (This has led to + * confusion in the past.) The filler is only used in the read code. + */ + png_ptr->filler = (png_uint_16)filler; +# else + png_app_error(png_ptr, "png_set_filler not supported on read"); + PNG_UNUSED(filler) /* not used in the write case */ + return; +# endif + } + + else /* write */ + { +# ifdef PNG_WRITE_FILLER_SUPPORTED + /* On write the usr_channels parameter must be set correctly at the + * start to record the number of channels in the app-supplied data. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_RGB: + png_ptr->usr_channels = 4; + break; + + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + break; + } + + else + { + /* There simply isn't any code in libpng to strip out bits + * from bytes when the components are less than a byte in + * size! + */ + png_app_error(png_ptr, + "png_set_filler is invalid for" + " low bit depth gray output"); + return; + } + + default: + png_app_error(png_ptr, + "png_set_filler: inappropriate color type"); + return; + } +# else + png_app_error(png_ptr, "png_set_filler not supported on write"); + return; +# endif + } + + /* Here on success - libpng supports the operation, set the transformation + * and the flag to say where the filler channel is. + */ + png_ptr->transformations |= PNG_FILLER; + + if (filler_loc == PNG_FILLER_AFTER) + png_ptr->flags |= PNG_FLAG_FILLER_AFTER; + + else + png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; +} + +/* Added to libpng-1.2.7 */ +void PNGAPI +png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_add_alpha"); + + if (png_ptr == NULL) + return; + + png_set_filler(png_ptr, filler, filler_loc); + /* The above may fail to do anything. */ + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_ptr->transformations |= PNG_ADD_ALPHA; +} + +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void PNGAPI +png_set_swap_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_swap_alpha"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_SWAP_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void PNGAPI +png_set_invert_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_invert_alpha"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_INVERT_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +void PNGAPI +png_set_invert_mono(png_structrp png_ptr) +{ + png_debug(1, "in png_set_invert_mono"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_INVERT_MONO; +} + +/* Invert monochrome grayscale data */ +void /* PRIVATE */ +png_do_invert(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_invert"); + + /* This test removed from libpng version 1.0.13 and 1.2.0: + * if (row_info->bit_depth == 1 && + */ + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_bytep rp = row; + size_t i; + size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(~(*rp)); + rp++; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 8) + { + png_bytep rp = row; + size_t i; + size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i += 2) + { + *rp = (png_byte)(~(*rp)); + rp += 2; + } + } + +#ifdef PNG_16BIT_SUPPORTED + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 16) + { + png_bytep rp = row; + size_t i; + size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i += 4) + { + *rp = (png_byte)(~(*rp)); + *(rp + 1) = (png_byte)(~(*(rp + 1))); + rp += 4; + } + } +#endif +} +#endif + +#ifdef PNG_16BIT_SUPPORTED +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swaps byte order on 16-bit depth images */ +void /* PRIVATE */ +png_do_swap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_swap"); + + if (row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop= row_info->width * row_info->channels; + + for (i = 0; i < istop; i++, rp += 2) + { +#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED + /* Feature added to libpng-1.6.11 for testing purposes, not + * enabled by default. + */ + *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp); +#else + png_byte t = *rp; + *rp = *(rp + 1); + *(rp + 1) = t; +#endif + } + } +} +#endif +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +static const png_byte onebppswaptable[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; + +static const png_byte twobppswaptable[256] = { + 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, + 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, + 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, + 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, + 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, + 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, + 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, + 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, + 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, + 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, + 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, + 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, + 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, + 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, + 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, + 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, + 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, + 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, + 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, + 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, + 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, + 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, + 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, + 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, + 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, + 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, + 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, + 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, + 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, + 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, + 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, + 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF +}; + +static const png_byte fourbppswaptable[256] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, + 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, + 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, + 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, + 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, + 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, + 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, + 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, + 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, + 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, + 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, + 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, + 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, + 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF +}; + +/* Swaps pixel packing order within bytes */ +void /* PRIVATE */ +png_do_packswap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_packswap"); + + if (row_info->bit_depth < 8) + { + png_bytep rp; + png_const_bytep end, table; + + end = row + row_info->rowbytes; + + if (row_info->bit_depth == 1) + table = onebppswaptable; + + else if (row_info->bit_depth == 2) + table = twobppswaptable; + + else if (row_info->bit_depth == 4) + table = fourbppswaptable; + + else + return; + + for (rp = row; rp < end; rp++) + *rp = table[*rp]; + } +} +#endif /* PACKSWAP || WRITE_PACKSWAP */ + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +/* Remove a channel - this used to be 'png_do_strip_filler' but it used a + * somewhat weird combination of flags to determine what to do. All the calls + * to png_do_strip_filler are changed in 1.5.2 to call this instead with the + * correct arguments. + * + * The routine isn't general - the channel must be the channel at the start or + * end (not in the middle) of each pixel. + */ +void /* PRIVATE */ +png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) +{ + png_bytep sp = row; /* source pointer */ + png_bytep dp = row; /* destination pointer */ + png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */ + + png_debug(1, "in png_do_strip_channel"); + + /* At the start sp will point to the first byte to copy and dp to where + * it is copied to. ep always points just beyond the end of the row, so + * the loop simply copies (channels-1) channels until sp reaches ep. + * + * at_start: 0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc. + * nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc. + */ + + /* GA, GX, XG cases */ + if (row_info->channels == 2) + { + if (row_info->bit_depth == 8) + { + if (at_start != 0) /* Skip initial filler */ + ++sp; + else /* Skip initial channel and, for sp, the filler */ + { + sp += 2; ++dp; + } + + /* For a 1 pixel wide image there is nothing to do */ + while (sp < ep) + { + *dp++ = *sp; sp += 2; + } + + row_info->pixel_depth = 8; + } + + else if (row_info->bit_depth == 16) + { + if (at_start != 0) /* Skip initial filler */ + sp += 2; + else /* Skip initial channel and, for sp, the filler */ + { + sp += 4; dp += 2; + } + + while (sp < ep) + { + *dp++ = *sp++; *dp++ = *sp; sp += 3; + } + + row_info->pixel_depth = 16; + } + + else + return; /* bad bit depth */ + + row_info->channels = 1; + + /* Finally fix the color type if it records an alpha channel */ + if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + row_info->color_type = PNG_COLOR_TYPE_GRAY; + } + + /* RGBA, RGBX, XRGB cases */ + else if (row_info->channels == 4) + { + if (row_info->bit_depth == 8) + { + if (at_start != 0) /* Skip initial filler */ + ++sp; + else /* Skip initial channels and, for sp, the filler */ + { + sp += 4; dp += 3; + } + + /* Note that the loop adds 3 to dp and 4 to sp each time. */ + while (sp < ep) + { + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp; sp += 2; + } + + row_info->pixel_depth = 24; + } + + else if (row_info->bit_depth == 16) + { + if (at_start != 0) /* Skip initial filler */ + sp += 2; + else /* Skip initial channels and, for sp, the filler */ + { + sp += 8; dp += 6; + } + + while (sp < ep) + { + /* Copy 6 bytes, skip 2 */ + *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp; sp += 3; + } + + row_info->pixel_depth = 48; + } + + else + return; /* bad bit depth */ + + row_info->channels = 3; + + /* Finally fix the color type if it records an alpha channel */ + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + row_info->color_type = PNG_COLOR_TYPE_RGB; + } + + else + return; /* The filler channel has gone already */ + + /* Fix the rowbytes value. */ + row_info->rowbytes = (size_t)(dp-row); +} +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Swaps red and blue bytes within a pixel */ +void /* PRIVATE */ +png_do_bgr(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_bgr"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 3) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 4) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + } + +#ifdef PNG_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 6) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 8) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + } +#endif + } +} +#endif /* READ_BGR || WRITE_BGR */ + +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +/* Added at libpng-1.5.10 */ +void /* PRIVATE */ +png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_check_palette_indexes"); + + if (png_ptr->num_palette < (1 << row_info->bit_depth) && + png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ + { + /* Calculations moved outside switch in an attempt to stop different + * compiler warnings. 'padding' is in *bits* within the last byte, it is + * an 'int' because pixel_depth becomes an 'int' in the expression below, + * and this calculation is used because it avoids warnings that other + * forms produced on either GCC or MSVC. + */ + int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width); + png_bytep rp = png_ptr->row_buf + row_info->rowbytes; + + switch (row_info->bit_depth) + { + case 1: + { + /* in this case, all bytes must be 0 so we don't need + * to unpack the pixels except for the rightmost one. + */ + for (; rp > png_ptr->row_buf; rp--) + { + if ((*rp >> padding) != 0) + png_ptr->num_palette_max = 1; + padding = 0; + } + + break; + } + + case 2: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 2) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 6) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 4: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 8: + { + for (; rp > png_ptr->row_buf; rp--) + { + if (*rp > png_ptr->num_palette_max) + png_ptr->num_palette_max = (int) *rp; + } + + break; + } + + default: + break; + } + } +} +#endif /* CHECK_FOR_INVALID_INDEX */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +void PNGAPI +png_set_user_transform_info(png_structrp png_ptr, png_voidp + user_transform_ptr, int user_transform_depth, int user_transform_channels) +{ + png_debug(1, "in png_set_user_transform_info"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + { + png_app_error(png_ptr, + "info change after png_start_read_image or png_read_update_info"); + return; + } +#endif + + png_ptr->user_transform_ptr = user_transform_ptr; + png_ptr->user_transform_depth = (png_byte)user_transform_depth; + png_ptr->user_transform_channels = (png_byte)user_transform_channels; +} +#endif + +/* This function returns a pointer to the user_transform_ptr associated with + * the user transform functions. The application should free any memory + * associated with this pointer before png_write_destroy and png_read_destroy + * are called. + */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +png_voidp PNGAPI +png_get_user_transform_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return png_ptr->user_transform_ptr; +} +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +png_uint_32 PNGAPI +png_get_current_row_number(png_const_structrp png_ptr) +{ + /* See the comments in png.h - this is the sub-image row when reading an + * interlaced image. + */ + if (png_ptr != NULL) + return png_ptr->row_number; + + return PNG_UINT_32_MAX; /* help the app not to fail silently */ +} + +png_byte PNGAPI +png_get_current_pass_number(png_const_structrp png_ptr) +{ + if (png_ptr != NULL) + return png_ptr->pass; + return 8; /* invalid */ +} +#endif /* USER_TRANSFORM_INFO */ +#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */ +#endif /* READ || WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngwio.c b/widget/milsko/milskosrc/external/libpng/src/pngwio.c new file mode 100644 index 0000000000..96a3187ff0 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngwio.c @@ -0,0 +1,167 @@ +/* pngwio.c - functions for data output + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2014,2016,2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all output. Users who need + * special handling are expected to write functions that have the same + * arguments as these and perform similar functions, but that possibly + * use different output methods. Note that you shouldn't change these + * functions, but rather write replacement functions and then change + * them at run time with png_set_write_fn(...). + */ + +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED + +/* Write the data to whatever output you are using. The default routine + * writes to a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered writes. This should never be asked + * to write more than 64K on a 16-bit machine. + */ + +void /* PRIVATE */ +png_write_data(png_structrp png_ptr, png_const_bytep data, size_t length) +{ + /* NOTE: write_data_fn must not change the buffer! */ + if (png_ptr->write_data_fn != NULL ) + (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), + length); + + else + png_error(png_ptr, "Call to NULL write function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual writing of data. If you are + * not writing to a standard C stream, you should create a replacement + * write_data function and use it at run time with png_set_write_fn(), rather + * than changing the library. + */ +void PNGCBAPI +png_default_write_data(png_structp png_ptr, png_bytep data, size_t length) +{ + size_t check; + + if (png_ptr == NULL) + return; + + check = fwrite(data, 1, length, (FILE *)png_ptr->io_ptr); + + if (check != length) + png_error(png_ptr, "Write Error"); +} +#endif + +/* This function is called to output any data pending writing (normally + * to disk). After png_flush is called, there should be no data pending + * writing in any buffers. + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void /* PRIVATE */ +png_flush(png_structrp png_ptr) +{ + if (png_ptr->output_flush_fn != NULL) + (*(png_ptr->output_flush_fn))(png_ptr); +} + +# ifdef PNG_STDIO_SUPPORTED +void PNGCBAPI +png_default_flush(png_structp png_ptr) +{ + FILE *io_ptr; + + if (png_ptr == NULL) + return; + + io_ptr = png_voidcast(FILE *, png_ptr->io_ptr); + fflush(io_ptr); +} +# endif +#endif + +/* This function allows the application to supply new output functions for + * libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * png_ptr - pointer to a png output data structure + * io_ptr - pointer to user supplied structure containing info about + * the output functions. May be NULL. + * write_data_fn - pointer to a new output function that takes as its + * arguments a pointer to a png_struct, a pointer to + * data to be written, and a 32-bit unsigned int that is + * the number of bytes to be written. The new write + * function should call png_error(png_ptr, "Error msg") + * to exit and output any fatal error messages. May be + * NULL, in which case libpng's default function will + * be used. + * flush_data_fn - pointer to a new flush function that takes as its + * arguments a pointer to a png_struct. After a call to + * the flush function, there should be no data in any buffers + * or pending transmission. If the output method doesn't do + * any buffering of output, a function prototype must still be + * supplied although it doesn't have to do anything. If + * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile + * time, output_flush_fn will be ignored, although it must be + * supplied for compatibility. May be NULL, in which case + * libpng's default function will be used, if + * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not + * a good idea if io_ptr does not point to a standard + * *FILE structure. + */ +void PNGAPI +png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (write_data_fn != NULL) + png_ptr->write_data_fn = write_data_fn; + + else + png_ptr->write_data_fn = png_default_write_data; +#else + png_ptr->write_data_fn = write_data_fn; +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED + + if (output_flush_fn != NULL) + png_ptr->output_flush_fn = output_flush_fn; + + else + png_ptr->output_flush_fn = png_default_flush; + +# else + png_ptr->output_flush_fn = output_flush_fn; +# endif +#else + PNG_UNUSED(output_flush_fn) +#endif /* WRITE_FLUSH */ + +#ifdef PNG_READ_SUPPORTED + /* It is an error to read while writing a png file */ + if (png_ptr->read_data_fn != NULL) + { + png_ptr->read_data_fn = NULL; + + png_warning(png_ptr, + "Can't set both read_data_fn and write_data_fn in the" + " same structure"); + } +#endif +} +#endif /* WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngwrite.c b/widget/milsko/milskosrc/external/libpng/src/pngwrite.c new file mode 100644 index 0000000000..35a5d17b60 --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngwrite.c @@ -0,0 +1,2449 @@ +/* pngwrite.c - general routines to write a PNG file + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +# include +#endif /* SIMPLIFIED_WRITE_STDIO */ + +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +/* Write out all the unknown chunks for the current given location */ +static void +write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, + unsigned int where) +{ + if (info_ptr->unknown_chunks_num != 0) + { + png_const_unknown_chunkp up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + ++up) + if ((up->location & where) != 0) + { + /* If per-chunk unknown chunk handling is enabled use it, otherwise + * just write the chunks the application has set. + */ +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int keep = png_handle_as_unknown(png_ptr, up->name); + + /* NOTE: this code is radically different from the read side in the + * matter of handling an ancillary unknown chunk. In the read side + * the default behavior is to discard it, in the code below the default + * behavior is to write it. Critical chunks are, however, only + * written if explicitly listed or if the default is set to write all + * unknown chunks. + * + * The default handling is also slightly weird - it is not possible to + * stop the writing of all unsafe-to-copy chunks! + * + * TODO: REVIEW: this would seem to be a bug. + */ + if (keep != PNG_HANDLE_CHUNK_NEVER && + ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || + keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && + png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) +#endif + { + /* TODO: review, what is wrong with a zero length unknown chunk? */ + if (up->size == 0) + png_warning(png_ptr, "Writing zero-length unknown chunk"); + + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +} +#endif /* WRITE_UNKNOWN_CHUNKS */ + +/* Writes all the PNG information. This is the suggested way to use the + * library. If you have a new chunk to add, make a function to write it, + * and put it in the correct location here. If you want the chunk written + * after the image data, put it in png_write_end(). I strongly encourage + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before + * writing the chunk, as that will keep the code from breaking if you want + * to just write a plain PNG file. If you have long comments, I suggest + * writing them in png_write_end(), and compressing them. + */ +void PNGAPI +png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) +{ + png_debug(1, "in png_write_info_before_PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) + { + /* Write PNG signature */ + png_write_sig(png_ptr); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \ + png_ptr->mng_features_permitted != 0) + { + png_warning(png_ptr, + "MNG features are not allowed in a PNG datastream"); + png_ptr->mng_features_permitted = 0; + } +#endif + + /* Write IHDR information. */ + png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + info_ptr->interlace_type +#else + 0 +#endif + ); + + /* The rest of these check to see if the valid field has the appropriate + * flag set, and if it does, writes the chunk. + * + * 1.6.0: COLORSPACE support controls the writing of these chunks too, and + * the chunks will be written if the WRITE routine is there and + * information * is available in the COLORSPACE. (See + * png_colorspace_sync_info in png.c for where the valid flags get set.) + * + * Under certain circumstances the colorspace can be invalidated without + * syncing the info_struct 'valid' flags; this happens if libpng detects + * an error and calls png_error while the color space is being set, yet + * the application continues writing the PNG. So check the 'invalid' + * flag here too. + */ +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + /* Write unknown chunks first; PNG v3 establishes a precedence order + * for colourspace chunks. It is certain therefore that new + * colourspace chunks will have a precedence and very likely it will be + * higher than all known so far. Writing the unknown chunks here is + * most likely to present the chunks in the most convenient order. + * + * FUTURE: maybe write chunks in the order the app calls png_set_chnk + * to give the app control. + */ + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED + /* PNG v3: a streaming app will need to see this before cICP because + * the information is helpful in handling HLG encoding (which is + * natively 10 bits but gets expanded to 16 in PNG.) + * + * The app shouldn't care about the order ideally, but it might have + * no choice. In PNG v3, apps are allowed to reject PNGs where the + * APNG chunks are out of order so it behooves libpng to be nice here. + */ + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#endif + + /* PNG v3: the July 2004 version of the TR introduced the concept of colour + * space priority. As above it therefore behooves libpng to write the colour + * space chunks in the priority order so that a streaming app need not buffer + * them. + * + * PNG v3: Chunks mDCV and cLLI provide ancillary information for the + * interpretation of the colourspace chunkgs but do not require support for + * those chunks so are outside the "COLORSPACE" check but before the write of + * the colourspace chunks themselves. + */ +#ifdef PNG_WRITE_cLLI_SUPPORTED + if ((info_ptr->valid & PNG_INFO_cLLI) != 0) + { + png_write_cLLI_fixed(png_ptr, info_ptr->maxCLL, info_ptr->maxFALL); + } +#endif +#ifdef PNG_WRITE_mDCV_SUPPORTED + if ((info_ptr->valid & PNG_INFO_mDCV) != 0) + { + png_write_mDCV_fixed(png_ptr, + info_ptr->mastering_red_x, info_ptr->mastering_red_y, + info_ptr->mastering_green_x, info_ptr->mastering_green_y, + info_ptr->mastering_blue_x, info_ptr->mastering_blue_y, + info_ptr->mastering_white_x, info_ptr->mastering_white_y, + info_ptr->mastering_maxDL, info_ptr->mastering_minDL); + } +#endif + +# ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */ + if ((info_ptr->valid & PNG_INFO_cICP) != 0) + { + png_write_cICP(png_ptr, + info_ptr->cicp_colour_primaries, + info_ptr->cicp_transfer_function, + info_ptr->cicp_matrix_coefficients, + info_ptr->cicp_video_full_range_flag); + } +# endif + +# ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */ + if ((info_ptr->valid & PNG_INFO_iCCP) != 0) + { + png_write_iCCP(png_ptr, info_ptr->iccp_name, + info_ptr->iccp_profile, info_ptr->iccp_proflen); + } +# endif + +# ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */ + if ((info_ptr->valid & PNG_INFO_sRGB) != 0) + png_write_sRGB(png_ptr, info_ptr->rendering_intent); +# endif /* WRITE_sRGB */ + +# ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */ + if ((info_ptr->valid & PNG_INFO_gAMA) != 0) + png_write_gAMA_fixed(png_ptr, info_ptr->gamma); +# endif + +# ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */ + if ((info_ptr->valid & PNG_INFO_cHRM) != 0) + png_write_cHRM_fixed(png_ptr, &info_ptr->cHRM); +# endif + + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; + } +} + +void PNGAPI +png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) +{ +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) + int i; +#endif + + png_debug(1, "in png_write_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_write_info_before_PLTE(png_ptr, info_ptr); + + if ((info_ptr->valid & PNG_INFO_PLTE) != 0) + png_write_PLTE(png_ptr, info_ptr->palette, + (png_uint_32)info_ptr->num_palette); + + else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Valid palette required for paletted images"); + +#ifdef PNG_WRITE_tRNS_SUPPORTED + if ((info_ptr->valid & PNG_INFO_tRNS) !=0) + { +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel (in tRNS) */ + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && + info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + int j, jend; + + jend = info_ptr->num_trans; + if (jend > PNG_MAX_PALETTE_LENGTH) + jend = PNG_MAX_PALETTE_LENGTH; + + for (j = 0; jtrans_alpha[j] = + (png_byte)(255 - info_ptr->trans_alpha[j]); + } +#endif + png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), + info_ptr->num_trans, info_ptr->color_type); + } +#endif +#ifdef PNG_WRITE_bKGD_SUPPORTED + if ((info_ptr->valid & PNG_INFO_bKGD) != 0) + png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); +#endif + +#ifdef PNG_WRITE_eXIf_SUPPORTED + if ((info_ptr->valid & PNG_INFO_eXIf) != 0) + { + png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif); + png_ptr->mode |= PNG_WROTE_eXIf; + } +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED + if ((info_ptr->valid & PNG_INFO_hIST) != 0) + png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED + if ((info_ptr->valid & PNG_INFO_oFFs) != 0) + png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, + info_ptr->offset_unit_type); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED + if ((info_ptr->valid & PNG_INFO_pCAL) != 0) + png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, + info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, + info_ptr->pcal_units, info_ptr->pcal_params); +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sCAL) != 0) + png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_s_width, info_ptr->scal_s_height); +#endif /* sCAL */ + +#ifdef PNG_WRITE_pHYs_SUPPORTED + if ((info_ptr->valid & PNG_INFO_pHYs) != 0) + png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, + info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); +#endif /* pHYs */ + +#ifdef PNG_WRITE_tIME_SUPPORTED + if ((info_ptr->valid & PNG_INFO_tIME) != 0) + { + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + png_ptr->mode |= PNG_WROTE_tIME; + } +#endif /* tIME */ + +#ifdef PNG_WRITE_sPLT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sPLT) != 0) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); +#endif /* sPLT */ + +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Check to see if we need to write text chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing header text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + } + + /* If we want a compressed text chunk */ + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + } + + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, + 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; +#else + /* Can't get here */ + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + } + } +#endif /* tEXt */ + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); +#endif +} + +/* Writes the end of the PNG file. If you don't want to write comments or + * time information, you can pass NULL for info. If you already wrote these + * in png_write_info(), do not write them again here. If you have long + * comments, I suggest writing them here, and compressing them. + */ +void PNGAPI +png_write_end(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_write_end"); + + if (png_ptr == NULL) + return; + + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) + png_error(png_ptr, "No IDATs written into file"); + +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= png_ptr->num_palette) + png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); +#endif + + /* See if user wants us to write information chunks */ + if (info_ptr != NULL) + { +#ifdef PNG_WRITE_TEXT_SUPPORTED + int i; /* local index variable */ +#endif +#ifdef PNG_WRITE_tIME_SUPPORTED + /* Check to see if user has supplied a time chunk */ + if ((info_ptr->valid & PNG_INFO_tIME) != 0 && + (png_ptr->mode & PNG_WROTE_tIME) == 0) + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + +#endif +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Loop through comment chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing trailer text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + } + + else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + } + + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; +#else + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + } + } +#endif + +#ifdef PNG_WRITE_eXIf_SUPPORTED + if ((info_ptr->valid & PNG_INFO_eXIf) != 0 && + (png_ptr->mode & PNG_WROTE_eXIf) == 0) + png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif); +#endif + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); +#endif + } + + png_ptr->mode |= PNG_AFTER_IDAT; + + /* Write end of PNG file */ + png_write_IEND(png_ptr); + + /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, + * and restored again in libpng-1.2.30, may cause some applications that + * do not set png_ptr->output_flush_fn to crash. If your application + * experiences a problem, please try building libpng with + * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to + * png-mng-implement at lists.sf.net . + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED + png_flush(png_ptr); +# endif +#endif +} + +#ifdef PNG_CONVERT_tIME_SUPPORTED +void PNGAPI +png_convert_from_struct_tm(png_timep ptime, const struct tm * ttime) +{ + png_debug(1, "in png_convert_from_struct_tm"); + + ptime->year = (png_uint_16)(1900 + ttime->tm_year); + ptime->month = (png_byte)(ttime->tm_mon + 1); + ptime->day = (png_byte)ttime->tm_mday; + ptime->hour = (png_byte)ttime->tm_hour; + ptime->minute = (png_byte)ttime->tm_min; + ptime->second = (png_byte)ttime->tm_sec; +} + +void PNGAPI +png_convert_from_time_t(png_timep ptime, time_t ttime) +{ + struct tm *tbuf; + + png_debug(1, "in png_convert_from_time_t"); + + tbuf = gmtime(&ttime); + if (tbuf == NULL) + { + /* TODO: add a safe function which takes a png_ptr argument and raises + * a png_error if the ttime argument is invalid and the call to gmtime + * fails as a consequence. + */ + memset(ptime, 0, sizeof(*ptime)); + return; + } + + png_convert_from_struct_tm(ptime, tbuf); +} +#endif + +/* Initialize png_ptr structure, and allocate any memory needed */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) +{ +#ifndef PNG_USER_MEM_SUPPORTED + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); +} + +/* Alternate initialize png_ptr structure, and allocate any memory needed */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ + if (png_ptr != NULL) + { + /* Set the zlib control values to defaults; they can be overridden by the + * application after the struct has been created. + */ + png_ptr->zbuffer_size = PNG_ZBUF_SIZE; + + /* The 'zlib_strategy' setting is irrelevant because png_default_claim in + * pngwutil.c defaults it according to whether or not filters will be + * used, and ignores this setting. + */ + png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; + png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_mem_level = 8; + png_ptr->zlib_window_bits = 15; + png_ptr->zlib_method = 8; + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED + png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; + png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_text_mem_level = 8; + png_ptr->zlib_text_window_bits = 15; + png_ptr->zlib_text_method = 8; +#endif /* WRITE_COMPRESSED_TEXT */ + + /* This is a highly dubious configuration option; by default it is off, + * but it may be appropriate for private builds that are testing + * extensions not conformant to the current specification, or of + * applications that must not fail to write at all costs! + */ +#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + /* In stable builds only warn if an application error can be completely + * handled. + */ + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; +#endif + + /* App warnings are warnings in release (or release candidate) builds but + * are errors during development. + */ +#if PNG_RELEASE_BUILD + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +#endif + + /* TODO: delay this, it can be done in png_init_io() (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_write_fn(png_ptr, NULL, NULL, NULL); + } + + return png_ptr; +} + + +/* Write a few rows of image data. If the image is interlaced, + * either you will have to write the 7 sub images, or, if you + * have called png_set_interlace_handling(), you will have to + * "write" the image seven times. + */ +void PNGAPI +png_write_rows(png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows) +{ + png_uint_32 i; /* row counter */ + png_bytepp rp; /* row pointer */ + + png_debug(1, "in png_write_rows"); + + if (png_ptr == NULL) + return; + + /* Loop through the rows */ + for (i = 0, rp = row; i < num_rows; i++, rp++) + { + png_write_row(png_ptr, *rp); + } +} + +/* Write the image. You only need to call this function once, even + * if you are writing an interlaced image. + */ +void PNGAPI +png_write_image(png_structrp png_ptr, png_bytepp image) +{ + png_uint_32 i; /* row index */ + int pass, num_pass; /* pass variables */ + png_bytepp rp; /* points to current row */ + + if (png_ptr == NULL) + return; + + png_debug(1, "in png_write_image"); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Initialize interlace handling. If image is not interlaced, + * this will set pass to 1 + */ + num_pass = png_set_interlace_handling(png_ptr); +#else + num_pass = 1; +#endif + /* Loop through passes */ + for (pass = 0; pass < num_pass; pass++) + { + /* Loop through image */ + for (i = 0, rp = image; i < png_ptr->height; i++, rp++) + { + png_write_row(png_ptr, *rp); + } + } +} + +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Performs intrapixel differencing */ +static void +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)(*rp - *(rp + 1)); + *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)(red >> 8); + *(rp + 1) = (png_byte)red; + *(rp + 4) = (png_byte)(blue >> 8); + *(rp + 5) = (png_byte)blue; + } + } +#endif /* WRITE_16BIT */ + } +} +#endif /* MNG_FEATURES */ + +/* Called by user to write a row of image data */ +void PNGAPI +png_write_row(png_structrp png_ptr, png_const_bytep row) +{ + /* 1.5.6: moved from png_struct to be a local structure: */ + png_row_info row_info; + + png_debug2(1, "in png_write_row (row %u, pass %d)", + png_ptr->row_number, png_ptr->pass); + + if (png_ptr == NULL) + return; + + /* Initialize transformations and other stuff if first time */ + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Make sure we wrote the header info */ + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) + png_error(png_ptr, + "png_write_info was never called before png_write_row"); + + /* Check for transforms that have been set but were defined out */ +#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + defined(PNG_READ_PACKSWAP_SUPPORTED) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_warning(png_ptr, + "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) != 0) + png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) + if ((png_ptr->transformations & PNG_BGR) != 0) + png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); +#endif + + png_write_start_row(png_ptr); + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced and not interested in row, return */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + switch (png_ptr->pass) + { + case 0: + if ((png_ptr->row_number & 0x07) != 0) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 1: + if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 3: + if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 4: + if ((png_ptr->row_number & 0x03) != 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 5: + if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 6: + if ((png_ptr->row_number & 0x01) == 0) + { + png_write_finish_row(png_ptr); + return; + } + break; + + default: /* error: ignore it */ + break; + } + } +#endif + + /* Set up row info for transformations */ + row_info.color_type = png_ptr->color_type; + row_info.width = png_ptr->usr_width; + row_info.channels = png_ptr->usr_channels; + row_info.bit_depth = png_ptr->usr_bit_depth; + row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + + png_debug1(3, "row_info->color_type = %d", row_info.color_type); + png_debug1(3, "row_info->width = %u", row_info.width); + png_debug1(3, "row_info->channels = %d", row_info.channels); + png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); + + /* Copy user's row into buffer, leaving room for filter byte. */ + memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Handle interlacing */ + if (png_ptr->interlaced && png_ptr->pass < 6 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); + /* This should always get caught above, but still ... */ + if (row_info.width == 0) + { + png_write_finish_row(png_ptr); + return; + } + } +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED + /* Handle other transformations */ + if (png_ptr->transformations != 0) + png_do_write_transformations(png_ptr, &row_info); +#endif + + /* At this point the row_info pixel depth must match the 'transformed' depth, + * which is also the output depth. + */ + if (row_info.pixel_depth != png_ptr->pixel_depth || + row_info.pixel_depth != png_ptr->transformed_pixel_depth) + png_error(png_ptr, "internal write transform logic error"); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); + } +#endif + +/* Added at libpng-1.5.10 */ +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Check for out-of-range palette index */ + if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, &row_info); +#endif + + /* Find a filter if necessary, filter the row and write it out. */ + png_write_find_filter(png_ptr, &row_info); + + if (png_ptr->write_row_fn != NULL) + (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set the automatic flush interval or 0 to turn flushing off */ +void PNGAPI +png_set_flush(png_structrp png_ptr, int nrows) +{ + png_debug(1, "in png_set_flush"); + + if (png_ptr == NULL) + return; + + png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows); +} + +/* Flush the current output buffers now */ +void PNGAPI +png_write_flush(png_structrp png_ptr) +{ + png_debug(1, "in png_write_flush"); + + if (png_ptr == NULL) + return; + + /* We have already written out all of the data */ + if (png_ptr->row_number >= png_ptr->num_rows) + return; + + png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); + png_ptr->flush_rows = 0; + png_flush(png_ptr); +} +#endif /* WRITE_FLUSH */ + +/* Free any memory used in png_ptr struct without freeing the struct itself. */ +static void +png_write_destroy(png_structrp png_ptr) +{ + png_debug(1, "in png_write_destroy"); + + /* Free any memory zlib uses */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + deflateEnd(&png_ptr->zstream); + + /* Free our memory. png_free checks NULL for us. */ + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_free(png_ptr, png_ptr->row_buf); + png_ptr->row_buf = NULL; +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->try_row); + png_free(png_ptr, png_ptr->tst_row); + png_ptr->prev_row = NULL; + png_ptr->try_row = NULL; + png_ptr->tst_row = NULL; +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; +#endif + + /* The error handling and memory handling information is left intact at this + * point: the jmp_buf may still have to be freed. See png_destroy_png_struct + * for how this happens. + */ +} + +/* Free all memory used by the write. + * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for + * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free + * the passed in info_structs but it would quietly fail to free any of the data + * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it + * has no png_ptr.) + */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_debug(1, "in png_destroy_write_struct"); + + if (png_ptr_ptr != NULL) + { + png_structrp png_ptr = *png_ptr_ptr; + + if (png_ptr != NULL) /* added in libpng 1.6.0 */ + { + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_write_destroy(png_ptr); + png_destroy_png_struct(png_ptr); + } + } +} + +/* Allow the application to select one or more row filters to use. */ +void PNGAPI +png_set_filter(png_structrp png_ptr, int method, int filters) +{ + png_debug(1, "in png_set_filter"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (method == PNG_INTRAPIXEL_DIFFERENCING)) + method = PNG_FILTER_TYPE_BASE; + +#endif + if (method == PNG_FILTER_TYPE_BASE) + { + switch (filters & (PNG_ALL_FILTERS | 0x07)) + { +#ifdef PNG_WRITE_FILTER_SUPPORTED + case 5: + case 6: + case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); +#endif /* WRITE_FILTER */ + /* FALLTHROUGH */ + case PNG_FILTER_VALUE_NONE: + png_ptr->do_filter = PNG_FILTER_NONE; break; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + case PNG_FILTER_VALUE_SUB: + png_ptr->do_filter = PNG_FILTER_SUB; break; + + case PNG_FILTER_VALUE_UP: + png_ptr->do_filter = PNG_FILTER_UP; break; + + case PNG_FILTER_VALUE_AVG: + png_ptr->do_filter = PNG_FILTER_AVG; break; + + case PNG_FILTER_VALUE_PAETH: + png_ptr->do_filter = PNG_FILTER_PAETH; break; + + default: + png_ptr->do_filter = (png_byte)filters; break; +#else + default: + png_app_error(png_ptr, "Unknown row filter for method 0"); +#endif /* WRITE_FILTER */ + } + +#ifdef PNG_WRITE_FILTER_SUPPORTED + /* If we have allocated the row_buf, this means we have already started + * with the image and we should have allocated all of the filter buffers + * that have been selected. If prev_row isn't already allocated, then + * it is too late to start using the filters that need it, since we + * will be missing the data in the previous row. If an application + * wants to start and stop using particular filters during compression, + * it should start out with all of the filters, and then remove them + * or add them back after the start of compression. + * + * NOTE: this is a nasty constraint on the code, because it means that the + * prev_row buffer must be maintained even if there are currently no + * 'prev_row' requiring filters active. + */ + if (png_ptr->row_buf != NULL) + { + int num_filters; + png_alloc_size_t buf_size; + + /* Repeat the checks in png_write_start_row; 1 pixel high or wide + * images cannot benefit from certain filters. If this isn't done here + * the check below will fire on 1 pixel high images. + */ + if (png_ptr->height == 1) + filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + if (png_ptr->width == 1) + filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0 + && png_ptr->prev_row == NULL) + { + /* This is the error case, however it is benign - the previous row + * is not available so the filter can't be used. Just warn here. + */ + png_app_warning(png_ptr, + "png_set_filter: UP/AVG/PAETH cannot be added after start"); + filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); + } + + num_filters = 0; + + if (filters & PNG_FILTER_SUB) + num_filters++; + + if (filters & PNG_FILTER_UP) + num_filters++; + + if (filters & PNG_FILTER_AVG) + num_filters++; + + if (filters & PNG_FILTER_PAETH) + num_filters++; + + /* Allocate needed row buffers if they have not already been + * allocated. + */ + buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth, + png_ptr->width) + 1; + + if (png_ptr->try_row == NULL) + png_ptr->try_row = png_voidcast(png_bytep, + png_malloc(png_ptr, buf_size)); + + if (num_filters > 1) + { + if (png_ptr->tst_row == NULL) + png_ptr->tst_row = png_voidcast(png_bytep, + png_malloc(png_ptr, buf_size)); + } + } + png_ptr->do_filter = (png_byte)filters; +#endif + } + else + png_error(png_ptr, "Unknown custom filter method"); +} + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ +/* Provide floating and fixed point APIs */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, + int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs) +{ + PNG_UNUSED(png_ptr) + PNG_UNUSED(heuristic_method) + PNG_UNUSED(num_weights) + PNG_UNUSED(filter_weights) + PNG_UNUSED(filter_costs) +} +#endif /* FLOATING_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, + int num_weights, png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs) +{ + PNG_UNUSED(png_ptr) + PNG_UNUSED(heuristic_method) + PNG_UNUSED(num_weights) + PNG_UNUSED(filter_weights) + PNG_UNUSED(filter_costs) +} +#endif /* FIXED_POINT */ +#endif /* WRITE_WEIGHTED_FILTER */ + +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +void PNGAPI +png_set_compression_level(png_structrp png_ptr, int level) +{ + png_debug(1, "in png_set_compression_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_level = level; +} + +void PNGAPI +png_set_compression_mem_level(png_structrp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_compression_mem_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_mem_level = mem_level; +} + +void PNGAPI +png_set_compression_strategy(png_structrp png_ptr, int strategy) +{ + png_debug(1, "in png_set_compression_strategy"); + + if (png_ptr == NULL) + return; + + /* The flag setting here prevents the libpng dynamic selection of strategy. + */ + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; + png_ptr->zlib_strategy = strategy; +} + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +void PNGAPI +png_set_compression_window_bits(png_structrp png_ptr, int window_bits) +{ + png_debug(1, "in png_set_compression_window_bits"); + + if (png_ptr == NULL) + return; + + /* Prior to 1.6.0 this would warn but then set the window_bits value. This + * meant that negative window bits values could be selected that would cause + * libpng to write a non-standard PNG file with raw deflate or gzip + * compressed IDAT or ancillary chunks. Such files can be read and there is + * no warning on read, so this seems like a very bad idea. + */ + if (window_bits > 15) + { + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } + + else if (window_bits < 8) + { + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } + + png_ptr->zlib_window_bits = window_bits; +} + +void PNGAPI +png_set_compression_method(png_structrp png_ptr, int method) +{ + png_debug(1, "in png_set_compression_method"); + + if (png_ptr == NULL) + return; + + /* This would produce an invalid PNG file if it worked, but it doesn't and + * deflate will fault it, so it is harmless to just warn here. + */ + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + + png_ptr->zlib_method = method; +} +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ + +/* The following were added to libpng-1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +void PNGAPI +png_set_text_compression_level(png_structrp png_ptr, int level) +{ + png_debug(1, "in png_set_text_compression_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_level = level; +} + +void PNGAPI +png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_text_compression_mem_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_mem_level = mem_level; +} + +void PNGAPI +png_set_text_compression_strategy(png_structrp png_ptr, int strategy) +{ + png_debug(1, "in png_set_text_compression_strategy"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_strategy = strategy; +} + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +void PNGAPI +png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) +{ + png_debug(1, "in png_set_text_compression_window_bits"); + + if (png_ptr == NULL) + return; + + if (window_bits > 15) + { + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } + + else if (window_bits < 8) + { + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } + + png_ptr->zlib_text_window_bits = window_bits; +} + +void PNGAPI +png_set_text_compression_method(png_structrp png_ptr, int method) +{ + png_debug(1, "in png_set_text_compression_method"); + + if (png_ptr == NULL) + return; + + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + + png_ptr->zlib_text_method = method; +} +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +/* end of API added to libpng-1.5.4 */ + +void PNGAPI +png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) +{ + png_debug(1, "in png_set_write_status_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->write_row_fn = write_row_fn; +} + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +void PNGAPI +png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + write_user_transform_fn) +{ + png_debug(1, "in png_set_write_user_transform_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->write_user_transform_fn = write_user_transform_fn; +} +#endif + + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_write_png(png_structrp png_ptr, png_inforp info_ptr, + int transforms, voidp params) +{ + png_debug(1, "in png_write_png"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if ((info_ptr->valid & PNG_INFO_IDAT) == 0) + { + png_app_error(png_ptr, "no rows for png_write_image to write"); + return; + } + + /* Write the file header information. */ + png_write_info(png_ptr, info_ptr); + + /* ------ these transformations don't touch the info structure ------- */ + + /* Invert monochrome pixels */ + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) +#ifdef PNG_WRITE_INVERT_SUPPORTED + png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); +#endif + + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); +#endif + + /* Pack pixels into bytes */ + if ((transforms & PNG_TRANSFORM_PACKING) != 0) +#ifdef PNG_WRITE_PACK_SUPPORTED + png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); +#endif + + /* Swap location of alpha bytes from ARGB to RGBA */ + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); +#endif + + /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into + * RGB, note that the code expects the input color type to be G or RGB; no + * alpha channel. + */ + if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER| + PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0) + { +#ifdef PNG_WRITE_FILLER_SUPPORTED + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0) + { + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_app_error(png_ptr, + "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported"); + + /* Continue if ignored - this is the pre-1.6.10 behavior */ + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + } + + else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported"); +#endif + } + + /* Flip BGR pixels to RGB */ + if ((transforms & PNG_TRANSFORM_BGR) != 0) +#ifdef PNG_WRITE_BGR_SUPPORTED + png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); +#endif + + /* Swap bytes of 16-bit files to most significant byte first */ + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) +#ifdef PNG_WRITE_SWAP_SUPPORTED + png_set_swap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); +#endif + + /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */ + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); +#endif + + /* Invert the alpha channel from opacity to transparency */ + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); +#endif + + /* ----------------------- end of transformations ------------------- */ + + /* Write the bits */ + png_write_image(png_ptr, info_ptr->row_pointers); + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + + PNG_UNUSED(params) +} +#endif + + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +/* Initialize the write structure - general purpose utility. */ +static int +png_image_write_init(png_imagep image) +{ + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 1; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_write_struct(&png_ptr, NULL); + } + + return png_image_error(image, "png_image_write_: out of memory"); +} + +/* Arguments to png_image_write_main: */ +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_const_voidp buffer; + png_int_32 row_stride; + png_const_voidp colormap; + int convert_to_8bit; + /* Local variables: */ + png_const_voidp first_row; + ptrdiff_t row_bytes; + png_voidp local_row; + /* Byte count for memory writing */ + png_bytep memory; + png_alloc_size_t memory_bytes; /* not used for STDIO */ + png_alloc_size_t output_bytes; /* running total */ +} png_image_write_control; + +/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to + * do any necessary byte swapping. The component order is defined by the + * png_image format value. + */ +static int +png_write_image_16bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); + png_uint_16p row_end; + unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? + 3 : 1; + int aindex = 0; + png_uint_32 y = image->height; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + else + aindex = (int)channels; +# else + aindex = (int)channels; +# endif + } + + else + png_error(png_ptr, "png_write_image: internal call error"); + + /* Work out the output row end and count over this, note that the increment + * above to 'row' means that row_end can actually be beyond the end of the + * row; this is correct. + */ + row_end = output_row + image->width * (channels+1); + + for (; y > 0; --y) + { + png_const_uint_16p in_ptr = input_row; + png_uint_16p out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_16 alpha = in_ptr[aindex]; + png_uint_32 reciprocal = 0; + int c; + + out_ptr[aindex] = alpha; + + /* Calculate a reciprocal. The correct calculation is simply + * component/alpha*65535 << 15. (I.e. 15 bits of precision); this + * allows correct rounding by adding .5 before the shift. 'reciprocal' + * is only initialized when required. + */ + if (alpha > 0 && alpha < 65535) + reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; + + c = (int)channels; + do /* always at least one channel */ + { + png_uint_16 component = *in_ptr++; + + /* The following gives 65535 for an alpha of 0, which is fine, + * otherwise if 0/0 is represented as some other value there is more + * likely to be a discontinuity which will probably damage + * compression when moving from a fully transparent area to a + * nearly transparent one. (The assumption here is that opaque + * areas tend not to be 0 intensity.) + */ + if (component >= alpha) + component = 65535; + + /* component 0 && alpha < 65535) + { + png_uint_32 calc = component * reciprocal; + calc += 16384; /* round to nearest */ + component = (png_uint_16)(calc >> 15); + } + + *out_ptr++ = component; + } + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } + + png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); + input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); + } + + return 1; +} + +/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel + * is present it must be removed from the components, the components are then + * written in sRGB encoding. No components are added or removed. + * + * Calculate an alpha reciprocal to reverse pre-multiplication. As above the + * calculation can be done to 15 bits of accuracy; however, the output needs to + * be scaled in the range 0..255*65535, so include that scaling here. + */ +# define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+((alpha)>>1))/(alpha)) + +static png_byte +png_unpremultiply(png_uint_32 component, png_uint_32 alpha, + png_uint_32 reciprocal/*from the above macro*/) +{ + /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 + * is represented as some other value there is more likely to be a + * discontinuity which will probably damage compression when moving from a + * fully transparent area to a nearly transparent one. (The assumption here + * is that opaque areas tend not to be 0 intensity.) + * + * There is a rounding problem here; if alpha is less than 128 it will end up + * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the + * output change for this too. + */ + if (component >= alpha || alpha < 128) + return 255; + + /* component 0) + { + /* The test is that alpha/257 (rounded) is less than 255, the first value + * that becomes 255 is 65407. + * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, + * be exact!) [Could also test reciprocal != 0] + */ + if (alpha < 65407) + { + component *= reciprocal; + component += 64; /* round to nearest */ + component >>= 7; + } + + else + component *= 255; + + /* Convert the component to sRGB. */ + return (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + else + return 0; +} + +static int +png_write_image_8bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_bytep output_row = png_voidcast(png_bytep, display->local_row); + png_uint_32 y = image->height; + unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? + 3 : 1; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_bytep row_end; + int aindex; + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else +# endif + aindex = (int)channels; + + /* Use row_end in place of a loop counter: */ + row_end = output_row + image->width * (channels+1); + + for (; y > 0; --y) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_16 alpha = in_ptr[aindex]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + int c; + + /* Scale and write the alpha channel. */ + out_ptr[aindex] = alphabyte; + + if (alphabyte > 0 && alphabyte < 255) + reciprocal = UNP_RECIPROCAL(alpha); + + c = (int)channels; + do /* always at least one channel */ + *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } /* while out_ptr < row_end */ + + png_write_row(png_ptr, png_voidcast(png_const_bytep, + display->local_row)); + input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); + } /* while y */ + } + + else + { + /* No alpha channel, so the row_end really is the end of the row and it + * is sufficient to loop over the components one by one. + */ + png_bytep row_end = output_row + image->width * channels; + + for (; y > 0; --y) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_32 component = *in_ptr++; + + component *= 255; + *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + png_write_row(png_ptr, output_row); + input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); + } + } + + return 1; +} + +static void +png_image_set_PLTE(png_image_write_control *display) +{ + png_imagep image = display->image; + const void *cmap = display->colormap; + int entries = image->colormap_entries > 256 ? 256 : + (int)image->colormap_entries; + + /* NOTE: the caller must check for cmap != NULL and entries != 0 */ + png_uint_32 format = image->format; + unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); + +# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\ + defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED) + int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif + +# ifdef PNG_FORMAT_BGR_SUPPORTED + int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + int i, num_trans; + png_color palette[256]; + png_byte tRNS[256]; + + memset(tRNS, 255, (sizeof tRNS)); + memset(palette, 0, (sizeof palette)); + + for (i=num_trans=0; i= 3) /* RGB */ + { + palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[(2 ^ bgr)]); + palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[1]); + palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[bgr]); + } + + else /* Gray */ + palette[i].blue = palette[i].red = palette[i].green = + (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); + } + + else /* alpha */ + { + png_uint_16 alpha = entry[afirst ? 0 : channels-1]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + + /* Calculate a reciprocal, as in the png_write_image_8bit code above + * this is designed to produce a value scaled to 255*65535 when + * divided by 128 (i.e. asr 7). + */ + if (alphabyte > 0 && alphabyte < 255) + reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; + + tRNS[i] = alphabyte; + if (alphabyte < 255) + num_trans = i+1; + + if (channels >= 3) /* RGB */ + { + palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], + alpha, reciprocal); + palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, + reciprocal); + palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, + reciprocal); + } + + else /* gray */ + palette[i].blue = palette[i].red = palette[i].green = + png_unpremultiply(entry[afirst], alpha, reciprocal); + } + } + + else /* Color-map has sRGB values */ + { + png_const_bytep entry = png_voidcast(png_const_bytep, cmap); + + entry += (unsigned int)i * channels; + + switch (channels) + { + case 4: + tRNS[i] = entry[afirst ? 0 : 3]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALLTHROUGH */ + case 3: + palette[i].blue = entry[afirst + (2 ^ bgr)]; + palette[i].green = entry[afirst + 1]; + palette[i].red = entry[afirst + bgr]; + break; + + case 2: + tRNS[i] = entry[1 ^ afirst]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALLTHROUGH */ + case 1: + palette[i].blue = palette[i].red = palette[i].green = + entry[afirst]; + break; + + default: + break; + } + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + + png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, + entries); + + if (num_trans > 0) + png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, + num_trans, NULL); + + image->colormap_entries = (png_uint_32)entries; +} + +static int +png_image_write_main(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 format = image->format; + + /* The following four ints are actually booleans */ + int colormap = (format & PNG_FORMAT_FLAG_COLORMAP); + int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */ + int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA); + int write_16bit = linear && (display->convert_to_8bit == 0); + +# ifdef PNG_BENIGN_ERRORS_SUPPORTED + /* Make sure we error out on any bad situation */ + png_set_benign_errors(png_ptr, 0/*error*/); +# endif + + /* Default the 'row_stride' parameter if required, also check the row stride + * and total image size to ensure that they are within the system limits. + */ + { + unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); + + if (image->width <= 0x7fffffffU/channels) /* no overflow */ + { + png_uint_32 check; + png_uint_32 png_row_stride = image->width * channels; + + if (display->row_stride == 0) + display->row_stride = (png_int_32)/*SAFE*/png_row_stride; + + if (display->row_stride < 0) + check = (png_uint_32)(-display->row_stride); + + else + check = (png_uint_32)display->row_stride; + + if (check >= png_row_stride) + { + /* Now check for overflow of the image buffer calculation; this + * limits the whole image size to 32 bits for API compatibility with + * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. + */ + if (image->height > 0xffffffffU/png_row_stride) + png_error(image->opaque->png_ptr, "memory image too large"); + } + + else + png_error(image->opaque->png_ptr, "supplied row stride too small"); + } + + else + png_error(image->opaque->png_ptr, "image row stride too large"); + } + + /* Set the required transforms then write the rows in the correct order. */ + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) + { + if (display->colormap != NULL && image->colormap_entries > 0) + { + png_uint_32 entries = image->colormap_entries; + + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), + PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_image_set_PLTE(display); + } + + else + png_error(image->opaque->png_ptr, + "no color-map for color-mapped image"); + } + + else + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + write_16bit ? 16 : 8, + ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + + ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Counter-intuitively the data transformations must be called *after* + * png_write_info, not before as in the read code, but the 'set' functions + * must still be called before. Just set the color space information, never + * write an interlaced image. + */ + + if (write_16bit != 0) + { + /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); + + if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 + ); + } + + else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); + + /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit + * space must still be gamma encoded. + */ + else + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); + + /* Write the file header. */ + png_write_info(png_ptr, info_ptr); + + /* Now set up the data transformations (*after* the header is written), + * remove the handled transformations from the 'format' flags for checking. + * + * First check for a little endian system if writing 16-bit files. + */ + if (write_16bit != 0) + { + png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + +# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED + if ((format & PNG_FORMAT_FLAG_BGR) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + format &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_set_swap_alpha(png_ptr); + format &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If there are 16 or fewer color-map entries we wrote a lower bit depth + * above, but the application data is still byte packed. + */ + if (colormap != 0 && image->colormap_entries <= 16) + png_set_packing(png_ptr); + + /* That should have handled all (both) the transforms. */ + if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | + PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) + png_error(png_ptr, "png_write_image: unsupported transformation"); + + { + png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= (sizeof (png_uint_16)); + + if (row_bytes < 0) + row += (image->height-1) * (-row_bytes); + + display->first_row = row; + display->row_bytes = row_bytes; + } + + /* Apply 'fast' options if the flag is set. */ + if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) + { + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); + /* NOTE: determined by experiment using pngstest, this reflects some + * balance between the time to write the image once and the time to read + * it about 50 times. The speed-up in pngstest was about 10-20% of the + * total (user) time on a heavily loaded system. + */ +# ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED + png_set_compression_level(png_ptr, 3); +# endif + } + + /* Check for the cases that currently require a pre-transform on the row + * before it is written. This only applies when the input is 16-bit and + * either there is an alpha channel or it is converted to 8-bit. + */ + if ((linear != 0 && alpha != 0 ) || + (colormap == 0 && display->convert_to_8bit != 0)) + { + png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr))); + int result; + + display->local_row = row; + if (write_16bit != 0) + result = png_safe_execute(image, png_write_image_16bit, display); + else + result = png_safe_execute(image, png_write_image_8bit, display); + display->local_row = NULL; + + png_free(png_ptr, row); + + /* Skip the 'write_end' on error: */ + if (result == 0) + return 0; + } + + /* Otherwise this is the case where the input is in a format currently + * supported by the rest of the libpng write code; call it directly. + */ + else + { + png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); + ptrdiff_t row_bytes = display->row_bytes; + png_uint_32 y = image->height; + + for (; y > 0; --y) + { + png_write_row(png_ptr, row); + row += row_bytes; + } + } + + png_write_end(png_ptr, info_ptr); + return 1; +} + + +static void (PNGCBAPI +image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/); + png_alloc_size_t ob = display->output_bytes; + + /* Check for overflow; this should never happen: */ + if (size <= ((png_alloc_size_t)-1) - ob) + { + /* I don't think libpng ever does this, but just in case: */ + if (size > 0) + { + if (display->memory_bytes >= ob+size) /* writing */ + memcpy(display->memory+ob, data, size); + + /* Always update the size: */ + display->output_bytes = ob+size; + } + } + + else + png_error(png_ptr, "png_image_write_to_memory: PNG too big"); +} + +static void (PNGCBAPI +image_memory_flush)(png_structp png_ptr) +{ + PNG_UNUSED(png_ptr) +} + +static int +png_image_write_memory(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + + /* The rest of the memory-specific init and write_main in an error protected + * environment. This case needs to use callbacks for the write operations + * since libpng has no built in support for writing to memory. + */ + png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/, + image_memory_write, image_memory_flush); + + return png_image_write_main(display); +} + +int PNGAPI +png_image_write_to_memory(png_imagep image, void *memory, + png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given buffer, or count the bytes if it is NULL */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (memory_bytes != NULL && buffer != NULL) + { + /* This is to give the caller an easier error detection in the NULL + * case and guard against uninitialized variable problems: + */ + if (memory == NULL) + *memory_bytes = 0; + + if (png_image_write_init(image) != 0) + { + png_image_write_control display; + int result; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + display.memory = png_voidcast(png_bytep, memory); + display.memory_bytes = *memory_bytes; + display.output_bytes = 0; + + result = png_safe_execute(image, png_image_write_memory, &display); + png_image_free(image); + + /* write_memory returns true even if we ran out of buffer. */ + if (result) + { + /* On out-of-buffer this function returns '0' but still updates + * memory_bytes: + */ + if (memory != NULL && display.output_bytes > *memory_bytes) + result = 0; + + *memory_bytes = display.output_bytes; + } + + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_memory: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_memory: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +int PNGAPI +png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given FILE object. */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL && buffer != NULL) + { + if (png_image_write_init(image) != 0) + { + png_image_write_control display; + int result; + + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + + result = png_safe_execute(image, png_image_write_main, &display); + png_image_free(image); + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +int PNGAPI +png_image_write_to_file(png_imagep image, const char *file_name, + int convert_to_8bit, const void *buffer, png_int_32 row_stride, + const void *colormap) +{ + /* Write the image to the named file. */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL && buffer != NULL) + { + FILE *fp = fopen(file_name, "wb"); + + if (fp != NULL) + { + if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, + row_stride, colormap) != 0) + { + int error; /* from fflush/fclose */ + + /* Make sure the file is flushed correctly. */ + if (fflush(fp) == 0 && ferror(fp) == 0) + { + if (fclose(fp) == 0) + return 1; + + error = errno; /* from fclose */ + } + + else + { + error = errno; /* from fflush or ferror */ + (void)fclose(fp); + } + + (void)remove(file_name); + /* The image has already been cleaned up; this is just used to + * set the error (because the original write succeeded). + */ + return png_image_error(image, strerror(error)); + } + + else + { + /* Clean up: just the opened file. */ + (void)fclose(fp); + (void)remove(file_name); + return 0; + } + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_write_to_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} +#endif /* SIMPLIFIED_WRITE_STDIO */ +#endif /* SIMPLIFIED_WRITE */ +#endif /* WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngwtran.c b/widget/milsko/milskosrc/external/libpng/src/pngwtran.c new file mode 100644 index 0000000000..a20847023f --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngwtran.c @@ -0,0 +1,574 @@ +/* pngwtran.c - transforms the data in a row for PNG writers + * + * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED + +#ifdef PNG_WRITE_PACK_SUPPORTED +/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The + * row_info bit depth should be 8 (one pixel per byte). The channels + * should be 1 (this only happens on grayscale and paletted images). + */ +static void +png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) +{ + png_debug(1, "in png_do_pack"); + + if (row_info->bit_depth == 8 && + row_info->channels == 1) + { + switch ((int)bit_depth) + { + case 1: + { + png_bytep sp, dp; + int mask, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + mask = 0x80; + v = 0; + + for (i = 0; i < row_width; i++) + { + if (*sp != 0) + v |= mask; + + sp++; + + if (mask > 1) + mask >>= 1; + + else + { + mask = 0x80; + *dp = (png_byte)v; + dp++; + v = 0; + } + } + + if (mask != 0x80) + *dp = (png_byte)v; + + break; + } + + case 2: + { + png_bytep sp, dp; + unsigned int shift; + int v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 6; + v = 0; + + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x03); + v |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp = (png_byte)v; + dp++; + v = 0; + } + + else + shift -= 2; + + sp++; + } + + if (shift != 6) + *dp = (png_byte)v; + + break; + } + + case 4: + { + png_bytep sp, dp; + unsigned int shift; + int v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 4; + v = 0; + + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x0f); + v |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp = (png_byte)v; + dp++; + v = 0; + } + + else + shift -= 4; + + sp++; + } + + if (shift != 4) + *dp = (png_byte)v; + + break; + } + + default: + break; + } + + row_info->bit_depth = (png_byte)bit_depth; + row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +/* Shift pixel values to take advantage of whole range. Pass the + * true number of bits in bit_depth. The row should be packed + * according to row_info->bit_depth. Thus, if you had a row of + * bit depth 4, but the pixels only had values from 0 to 7, you + * would pass 3 as bit_depth, and this routine would translate the + * data to 0 to 15. + */ +static void +png_do_shift(png_row_infop row_info, png_bytep row, + png_const_color_8p bit_depth) +{ + png_debug(1, "in png_do_shift"); + + if (row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift_start[4], shift_dec[4]; + unsigned int channels = 0; + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + shift_start[channels] = row_info->bit_depth - bit_depth->red; + shift_dec[channels] = bit_depth->red; + channels++; + + shift_start[channels] = row_info->bit_depth - bit_depth->green; + shift_dec[channels] = bit_depth->green; + channels++; + + shift_start[channels] = row_info->bit_depth - bit_depth->blue; + shift_dec[channels] = bit_depth->blue; + channels++; + } + + else + { + shift_start[channels] = row_info->bit_depth - bit_depth->gray; + shift_dec[channels] = bit_depth->gray; + channels++; + } + + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + shift_start[channels] = row_info->bit_depth - bit_depth->alpha; + shift_dec[channels] = bit_depth->alpha; + channels++; + } + + /* With low row depths, could only be grayscale, so one channel */ + if (row_info->bit_depth < 8) + { + png_bytep bp = row; + size_t i; + unsigned int mask; + size_t row_bytes = row_info->rowbytes; + + if (bit_depth->gray == 1 && row_info->bit_depth == 2) + mask = 0x55; + + else if (row_info->bit_depth == 4 && bit_depth->gray == 3) + mask = 0x11; + + else + mask = 0xff; + + for (i = 0; i < row_bytes; i++, bp++) + { + int j; + unsigned int v, out; + + v = *bp; + out = 0; + + for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) + { + if (j > 0) + out |= v << j; + + else + out |= (v >> (-j)) & mask; + } + + *bp = (png_byte)(out & 0xff); + } + } + + else if (row_info->bit_depth == 8) + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (i = 0; i < istop; i++, bp++) + { + unsigned int c = i%channels; + int j; + unsigned int v, out; + + v = *bp; + out = 0; + + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + out |= v << j; + + else + out |= v >> (-j); + } + + *bp = (png_byte)(out & 0xff); + } + } + + else + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (bp = row, i = 0; i < istop; i++) + { + unsigned int c = i%channels; + int j; + unsigned int value, v; + + v = png_get_uint_16(bp); + value = 0; + + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + value |= v << j; + + else + value |= v >> (-j); + } + *bp++ = (png_byte)((value >> 8) & 0xff); + *bp++ = (png_byte)(value & 0xff); + } + } + } +} +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +static void +png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_swap_alpha"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This converts from ARGB to RGBA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This converts from AARRGGBB to RRGGBBAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } +#endif /* WRITE_16BIT */ + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This converts from AG to GA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This converts from AAGG to GGAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } +#endif /* WRITE_16BIT */ + } + } +} +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +static void +png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_invert_alpha"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in RGBA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=3; dp = sp; + *dp = (png_byte)(255 - *(sp++)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in RRGGBBAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=6; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *dp = (png_byte)(255 - *(sp++)); + } + } +#endif /* WRITE_16BIT */ + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in GA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in GGAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=2; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *dp = (png_byte)(255 - *(sp++)); + } + } +#endif /* WRITE_16BIT */ + } + } +} +#endif + +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ +void /* PRIVATE */ +png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_write_transformations"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif + +#ifdef PNG_WRITE_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); +#endif + +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_pack(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif + +#ifdef PNG_WRITE_SWAP_SUPPORTED +# ifdef PNG_16BIT_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +# endif +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_shift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif +} +#endif /* WRITE_TRANSFORMS */ +#endif /* WRITE */ diff --git a/widget/milsko/milskosrc/external/libpng/src/pngwutil.c b/widget/milsko/milskosrc/external/libpng/src/pngwutil.c new file mode 100644 index 0000000000..863ffe8c2f --- /dev/null +++ b/widget/milsko/milskosrc/external/libpng/src/pngwutil.c @@ -0,0 +1,2825 @@ +/* pngwutil.c - utilities to write a PNG file + * + * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson + * Copyright (c) 1996-1997 Andreas Dilger + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that are only called from within + * libpng itself during the course of writing an image. + */ + +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ + +/* Start of interlace block */ +static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; +/* Offset to next interlace block */ +static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +/* Start of interlace block in the y direction */ +static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; +/* Offset to next interlace block in the y direction */ +static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + +/* TODO: Move these arrays to a common utility module to avoid duplication. */ +#endif + +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +/* Place a 32-bit number into a buffer in PNG byte order. We work + * with unsigned numbers for convenience, although one supported + * ancillary chunk uses signed (two's complement) numbers. + */ +void PNGAPI +png_save_uint_32(png_bytep buf, png_uint_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xffU); + buf[1] = (png_byte)((i >> 16) & 0xffU); + buf[2] = (png_byte)((i >> 8) & 0xffU); + buf[3] = (png_byte)( i & 0xffU); +} + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +void PNGAPI +png_save_uint_16(png_bytep buf, unsigned int i) +{ + buf[0] = (png_byte)((i >> 8) & 0xffU); + buf[1] = (png_byte)( i & 0xffU); +} +#endif + +/* Simple function to write the signature. If we have already written + * the magic bytes of the signature, or more likely, the PNG stream is + * being embedded into another stream and doesn't need its own signature, + * we should call png_set_sig_bytes() to tell libpng how many of the + * bytes have already been written. + */ +void PNGAPI +png_write_sig(png_structrp png_ptr) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the signature is being written */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE; +#endif + + /* Write the rest of the 8 byte signature */ + png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], + (size_t)(8 - png_ptr->sig_bytes)); + + if (png_ptr->sig_bytes < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +/* Write the start of a PNG chunk. The type is the chunk type. + * The total_length is the sum of the lengths of all the data you will be + * passing in png_write_chunk_data(). + */ +static void +png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, + png_uint_32 length) +{ + png_byte buf[8]; + +#if defined(PNG_DEBUG) && (PNG_DEBUG > 0) + PNG_CSTRING_FROM_CHUNK(buf, chunk_name); + png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length); +#endif + + if (png_ptr == NULL) + return; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk header is being written. + * PNG_IO_CHUNK_HDR requires a single I/O call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR; +#endif + + /* Write the length and the chunk name */ + png_save_uint_32(buf, length); + png_save_uint_32(buf + 4, chunk_name); + png_write_data(png_ptr, buf, 8); + + /* Put the chunk name into png_ptr->chunk_name */ + png_ptr->chunk_name = chunk_name; + + /* Reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + + png_calculate_crc(png_ptr, buf + 4, 4); + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that chunk data will (possibly) be written. + * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA; +#endif +} + +void PNGAPI +png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, + png_uint_32 length) +{ + png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length); +} + +/* Write the data of a PNG chunk started with png_write_chunk_header(). + * Note that multiple calls to this function are allowed, and that the + * sum of the lengths from these calls *must* add up to the total_length + * given to png_write_chunk_header(). + */ +void PNGAPI +png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, size_t length) +{ + /* Write the data, and run the CRC over it */ + if (png_ptr == NULL) + return; + + if (data != NULL && length > 0) + { + png_write_data(png_ptr, data, length); + + /* Update the CRC after writing the data, + * in case the user I/O routine alters it. + */ + png_calculate_crc(png_ptr, data, length); + } +} + +/* Finish a chunk started with png_write_chunk_header(). */ +void PNGAPI +png_write_chunk_end(png_structrp png_ptr) +{ + png_byte buf[4]; + + if (png_ptr == NULL) return; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk CRC is being written. + * PNG_IO_CHUNK_CRC requires a single I/O function call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC; +#endif + + /* Write the crc in a single operation */ + png_save_uint_32(buf, png_ptr->crc); + + png_write_data(png_ptr, buf, 4); +} + +/* Write a PNG chunk all at once. The type is an array of ASCII characters + * representing the chunk name. The array must be at least 4 bytes in + * length, and does not need to be null terminated. To be safe, pass the + * pre-defined chunk names here, and if you need a new one, define it + * where the others are defined. The length is the length of the data. + * All the data must be present. If that is not possible, use the + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() + * functions instead. + */ +static void +png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, + png_const_bytep data, size_t length) +{ + if (png_ptr == NULL) + return; + + /* On 64-bit architectures 'length' may not fit in a png_uint_32. */ + if (length > PNG_UINT_31_MAX) + png_error(png_ptr, "length exceeds PNG maximum"); + + png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, length); + png_write_chunk_end(png_ptr); +} + +/* This is the API that calls the internal function above. */ +void PNGAPI +png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, + png_const_bytep data, size_t length) +{ + png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, + length); +} + +/* This is used below to find the size of an image to pass to png_deflate_claim, + * so it only needs to be accurate if the size is less than 16384 bytes (the + * point at which a lower LZ window size can be used.) + */ +static png_alloc_size_t +png_image_size(png_structrp png_ptr) +{ + /* Only return sizes up to the maximum of a png_uint_32; do this by limiting + * the width and height used to 15 bits. + */ + png_uint_32 h = png_ptr->height; + + if (png_ptr->rowbytes < 32768 && h < 32768) + { + if (png_ptr->interlaced != 0) + { + /* Interlacing makes the image larger because of the replication of + * both the filter byte and the padding to a byte boundary. + */ + png_uint_32 w = png_ptr->width; + unsigned int pd = png_ptr->pixel_depth; + png_alloc_size_t cb_base; + int pass; + + for (cb_base=0, pass=0; pass<=6; ++pass) + { + png_uint_32 pw = PNG_PASS_COLS(w, pass); + + if (pw > 0) + cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); + } + + return cb_base; + } + + else + return (png_ptr->rowbytes+1) * h; + } + + else + return 0xffffffffU; +} + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* This is the code to hack the first two bytes of the deflate stream (the + * deflate header) to correct the windowBits value to match the actual data + * size. Note that the second argument is the *uncompressed* size but the + * first argument is the *compressed* data (and it must be deflate + * compressed.) + */ +static void +optimize_cmf(png_bytep data, png_alloc_size_t data_size) +{ + /* Optimize the CMF field in the zlib stream. The resultant zlib stream is + * still compliant to the stream specification. + */ + if (data_size <= 16384) /* else windowBits must be 15 */ + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + unsigned int z_cinfo; + unsigned int half_z_window_size; + + z_cinfo = z_cmf >> 4; + half_z_window_size = 1U << (z_cinfo + 7); + + if (data_size <= half_z_window_size) /* else no change */ + { + unsigned int tmp; + + do + { + half_z_window_size >>= 1; + --z_cinfo; + } + while (z_cinfo > 0 && data_size <= half_z_window_size); + + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + + data[0] = (png_byte)z_cmf; + tmp = data[1] & 0xe0; + tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; + data[1] = (png_byte)tmp; + } + } + } +} +#endif /* WRITE_OPTIMIZE_CMF */ + +/* Initialize the compressor for the appropriate type of compression. */ +static int +png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, + png_alloc_size_t data_size) +{ + if (png_ptr->zowner != 0) + { +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, owner); + msg[4] = ':'; + msg[5] = ' '; + PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); +#endif +#if PNG_RELEASE_BUILD + png_warning(png_ptr, msg); + + /* Attempt sane error recovery */ + if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */ + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); + return Z_STREAM_ERROR; + } + + png_ptr->zowner = 0; +#else + png_error(png_ptr, msg); +#endif + } + + { + int level = png_ptr->zlib_level; + int method = png_ptr->zlib_method; + int windowBits = png_ptr->zlib_window_bits; + int memLevel = png_ptr->zlib_mem_level; + int strategy; /* set below */ + int ret; /* zlib return code */ + + if (owner == png_IDAT) + { + if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0) + strategy = png_ptr->zlib_strategy; + + else if (png_ptr->do_filter != PNG_FILTER_NONE) + strategy = PNG_Z_DEFAULT_STRATEGY; + + else + strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY; + } + + else + { +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + level = png_ptr->zlib_text_level; + method = png_ptr->zlib_text_method; + windowBits = png_ptr->zlib_text_window_bits; + memLevel = png_ptr->zlib_text_mem_level; + strategy = png_ptr->zlib_text_strategy; +#else + /* If customization is not supported the values all come from the + * IDAT values except for the strategy, which is fixed to the + * default. (This is the pre-1.6.0 behavior too, although it was + * implemented in a very different way.) + */ + strategy = Z_DEFAULT_STRATEGY; +#endif + } + + /* Adjust 'windowBits' down if larger than 'data_size'; to stop this + * happening just pass 32768 as the data_size parameter. Notice that zlib + * requires an extra 262 bytes in the window in addition to the data to be + * able to see the whole of the data, so if data_size+262 takes us to the + * next windowBits size we need to fix up the value later. (Because even + * though deflate needs the extra window, inflate does not!) + */ + if (data_size <= 16384) + { + /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to + * work round a Microsoft Visual C misbehavior which, contrary to C-90, + * widens the result of the following shift to 64-bits if (and, + * apparently, only if) it is used in a test. + */ + unsigned int half_window_size = 1U << (windowBits-1); + + while (data_size + 262 <= half_window_size) + { + half_window_size >>= 1; + --windowBits; + } + } + + /* Check against the previous initialized values, if any. */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 && + (png_ptr->zlib_set_level != level || + png_ptr->zlib_set_method != method || + png_ptr->zlib_set_window_bits != windowBits || + png_ptr->zlib_set_mem_level != memLevel || + png_ptr->zlib_set_strategy != strategy)) + { + if (deflateEnd(&png_ptr->zstream) != Z_OK) + png_warning(png_ptr, "deflateEnd failed (ignored)"); + + png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* For safety clear out the input and output pointers (currently zlib + * doesn't use them on Init, but it might in the future). + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + /* Now initialize if required, setting the new parameters, otherwise just + * do a simple reset to the previous parameters. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + ret = deflateReset(&png_ptr->zstream); + + else + { + ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, + memLevel, strategy); + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* The return code is from either deflateReset or deflateInit2; they have + * pretty much the same set of error codes. + */ + if (ret == Z_OK) + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } +} + +/* Clean up (or trim) a linked list of compression buffers. */ +void /* PRIVATE */ +png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) +{ + png_compression_bufferp list = *listp; + + if (list != NULL) + { + *listp = NULL; + + do + { + png_compression_bufferp next = list->next; + + png_free(png_ptr, list); + list = next; + } + while (list != NULL); + } +} + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +/* This pair of functions encapsulates the operation of (a) compressing a + * text string, and (b) issuing it later as a series of chunk data writes. + * The compression_state structure is shared context for these functions + * set up by the caller to allow access to the relevant local variables. + * + * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size + * temporary buffers. From 1.6.0 it is retained in png_struct so that it will + * be correctly freed in the event of a write error (previous implementations + * just leaked memory.) + */ +typedef struct +{ + png_const_bytep input; /* The uncompressed input data */ + png_alloc_size_t input_len; /* Its length */ + png_uint_32 output_len; /* Final compressed length */ + png_byte output[1024]; /* First block of output */ +} compression_state; + +static void +png_text_compress_init(compression_state *comp, png_const_bytep input, + png_alloc_size_t input_len) +{ + comp->input = input; + comp->input_len = input_len; + comp->output_len = 0; +} + +/* Compress the data in the compression state input */ +static int +png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, + compression_state *comp, png_uint_32 prefix_len) +{ + int ret; + + /* To find the length of the output it is necessary to first compress the + * input. The result is buffered rather than using the two-pass algorithm + * that is used on the inflate side; deflate is assumed to be slower and a + * PNG writer is assumed to have more memory available than a PNG reader. + * + * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an + * upper limit on the output size, but it is always bigger than the input + * size so it is likely to be more efficient to use this linked-list + * approach. + */ + ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len); + + if (ret != Z_OK) + return ret; + + /* Set up the compression buffers, we need a loop here to avoid overflowing a + * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited + * by the output buffer size, so there is no need to check that. Since this + * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits + * in size. + */ + { + png_compression_bufferp *end = &png_ptr->zbuffer_list; + png_alloc_size_t input_len = comp->input_len; /* may be zero! */ + png_uint_32 output_len; + + /* zlib updates these for us: */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input); + png_ptr->zstream.avail_in = 0; /* Set below */ + png_ptr->zstream.next_out = comp->output; + png_ptr->zstream.avail_out = (sizeof comp->output); + + output_len = png_ptr->zstream.avail_out; + + do + { + uInt avail_in = ZLIB_IO_MAX; + + if (avail_in > input_len) + avail_in = (uInt)input_len; + + input_len -= avail_in; + + png_ptr->zstream.avail_in = avail_in; + + if (png_ptr->zstream.avail_out == 0) + { + png_compression_buffer *next; + + /* Chunk data is limited to 2^31 bytes in length, so the prefix + * length must be counted here. + */ + if (output_len + prefix_len > PNG_UINT_31_MAX) + { + ret = Z_MEM_ERROR; + break; + } + + /* Need a new (malloc'ed) buffer, but there may be one present + * already. + */ + next = *end; + if (next == NULL) + { + next = png_voidcast(png_compression_bufferp, png_malloc_base + (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + + if (next == NULL) + { + ret = Z_MEM_ERROR; + break; + } + + /* Link in this buffer (so that it will be freed later) */ + next->next = NULL; + *end = next; + } + + png_ptr->zstream.next_out = next->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + output_len += png_ptr->zstream.avail_out; + + /* Move 'end' to the next buffer pointer. */ + end = &next->next; + } + + /* Compress the data */ + ret = deflate(&png_ptr->zstream, + input_len > 0 ? Z_NO_FLUSH : Z_FINISH); + + /* Claw back input data that was not consumed (because avail_in is + * reset above every time round the loop). + */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; /* safety */ + } + while (ret == Z_OK); + + /* There may be some space left in the last output buffer. This needs to + * be subtracted from output_len. + */ + output_len -= png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* safety */ + comp->output_len = output_len; + + /* Now double check the output length, put in a custom message if it is + * too long. Otherwise ensure the z_stream::msg pointer is set to + * something. + */ + if (output_len + prefix_len >= PNG_UINT_31_MAX) + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long"); + ret = Z_MEM_ERROR; + } + + else + png_zstream_error(png_ptr, ret); + + /* Reset zlib for another zTXt/iTXt or image data */ + png_ptr->zowner = 0; + + /* The only success case is Z_STREAM_END, input_len must be 0; if not this + * is an internal error. + */ + if (ret == Z_STREAM_END && input_len == 0) + { +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* Fix up the deflate header, if required */ + optimize_cmf(comp->output, comp->input_len); +#endif + /* But Z_OK is returned, not Z_STREAM_END; this allows the claim + * function above to return Z_STREAM_END on an error (though it never + * does in the current versions of zlib.) + */ + return Z_OK; + } + + else + return ret; + } +} + +/* Ship the compressed text out via chunk writes */ +static void +png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) +{ + png_uint_32 output_len = comp->output_len; + png_const_bytep output = comp->output; + png_uint_32 avail = (sizeof comp->output); + png_compression_buffer *next = png_ptr->zbuffer_list; + + for (;;) + { + if (avail > output_len) + avail = output_len; + + png_write_chunk_data(png_ptr, output, avail); + + output_len -= avail; + + if (output_len == 0 || next == NULL) + break; + + avail = png_ptr->zbuffer_size; + output = next->output; + next = next->next; + } + + /* This is an internal error; 'next' must have been NULL! */ + if (output_len > 0) + png_error(png_ptr, "error writing ancillary chunked compressed data"); +} +#endif /* WRITE_COMPRESSED_TEXT */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. Note that the rest of this code depends upon this + * information being correct. + */ +void /* PRIVATE */ +png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, + int bit_depth, int color_type, int compression_type, int filter_type, + int interlace_type) +{ + png_byte buf[13]; /* Buffer to store the IHDR info */ + int is_invalid_depth; + + png_debug(1, "in png_write_IHDR"); + + /* Check that we have valid input data from the application info */ + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: +#ifdef PNG_WRITE_16BIT_SUPPORTED + case 16: +#endif + png_ptr->channels = 1; break; + + default: + png_error(png_ptr, + "Invalid bit depth for grayscale image"); + } + break; + + case PNG_COLOR_TYPE_RGB: + is_invalid_depth = (bit_depth != 8); +#ifdef PNG_WRITE_16BIT_SUPPORTED + is_invalid_depth = (is_invalid_depth && bit_depth != 16); +#endif + if (is_invalid_depth) + png_error(png_ptr, "Invalid bit depth for RGB image"); + + png_ptr->channels = 3; + break; + + case PNG_COLOR_TYPE_PALETTE: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: + png_ptr->channels = 1; + break; + + default: + png_error(png_ptr, "Invalid bit depth for paletted image"); + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + is_invalid_depth = (bit_depth != 8); +#ifdef PNG_WRITE_16BIT_SUPPORTED + is_invalid_depth = (is_invalid_depth && bit_depth != 16); +#endif + if (is_invalid_depth) + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); + + png_ptr->channels = 2; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + is_invalid_depth = (bit_depth != 8); +#ifdef PNG_WRITE_16BIT_SUPPORTED + is_invalid_depth = (is_invalid_depth && bit_depth != 16); +#endif + if (is_invalid_depth) + png_error(png_ptr, "Invalid bit depth for RGBA image"); + + png_ptr->channels = 4; + break; + + default: + png_error(png_ptr, "Invalid image color type specified"); + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Invalid compression type specified"); + compression_type = PNG_COMPRESSION_TYPE_BASE; + } + + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && +#endif + filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Invalid filter type specified"); + filter_type = PNG_FILTER_TYPE_BASE; + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + if (interlace_type != PNG_INTERLACE_NONE && + interlace_type != PNG_INTERLACE_ADAM7) + { + png_warning(png_ptr, "Invalid interlace type specified"); + interlace_type = PNG_INTERLACE_ADAM7; + } +#else + interlace_type=PNG_INTERLACE_NONE; +#endif + + /* Save the relevant information */ + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->color_type = (png_byte)color_type; + png_ptr->interlaced = (png_byte)interlace_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + png_ptr->width = width; + png_ptr->height = height; + + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); + /* Set the usr info, so any transformations can modify it */ + png_ptr->usr_width = png_ptr->width; + png_ptr->usr_bit_depth = png_ptr->bit_depth; + png_ptr->usr_channels = png_ptr->channels; + + /* Pack the header information into the buffer */ + png_save_uint_32(buf, width); + png_save_uint_32(buf + 4, height); + buf[8] = (png_byte)bit_depth; + buf[9] = (png_byte)color_type; + buf[10] = (png_byte)compression_type; + buf[11] = (png_byte)filter_type; + buf[12] = (png_byte)interlace_type; + + /* Write the chunk */ + png_write_complete_chunk(png_ptr, png_IHDR, buf, 13); + + if ((png_ptr->do_filter) == PNG_NO_FILTERS) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + png_ptr->bit_depth < 8) + png_ptr->do_filter = PNG_FILTER_NONE; + + else + png_ptr->do_filter = PNG_ALL_FILTERS; + } + + png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ +} + +/* Write the palette. We are careful not to trust png_color to be in the + * correct order for PNG, so people can redefine it to any convenient + * structure. + */ +void /* PRIVATE */ +png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, + png_uint_32 num_pal) +{ + png_uint_32 max_palette_length, i; + png_const_colorp pal_ptr; + png_byte buf[3]; + + png_debug(1, "in png_write_PLTE"); + + max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; + + if (( +#ifdef PNG_MNG_FEATURES_SUPPORTED + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 && +#endif + num_pal == 0) || num_pal > max_palette_length) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_error(png_ptr, "Invalid number of colors in palette"); + } + + else + { + png_warning(png_ptr, "Invalid number of colors in palette"); + return; + } + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + { + png_warning(png_ptr, + "Ignoring request to write a PLTE chunk in grayscale PNG"); + + return; + } + + png_ptr->num_palette = (png_uint_16)num_pal; + png_debug1(3, "num_palette = %d", png_ptr->num_palette); + + png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); +#ifdef PNG_POINTER_INDEXING_SUPPORTED + + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) + { + buf[0] = pal_ptr->red; + buf[1] = pal_ptr->green; + buf[2] = pal_ptr->blue; + png_write_chunk_data(png_ptr, buf, 3); + } + +#else + /* This is a little slower but some buggy compilers need to do this + * instead + */ + pal_ptr=palette; + + for (i = 0; i < num_pal; i++) + { + buf[0] = pal_ptr[i].red; + buf[1] = pal_ptr[i].green; + buf[2] = pal_ptr[i].blue; + png_write_chunk_data(png_ptr, buf, 3); + } + +#endif + png_write_chunk_end(png_ptr); + png_ptr->mode |= PNG_HAVE_PLTE; +} + +/* This is similar to png_text_compress, above, except that it does not require + * all of the data at once and, instead of buffering the compressed result, + * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out + * because it calls the write interface. As a result it does its own error + * reporting and does not return an error code. In the event of error it will + * just call png_error. The input data length may exceed 32-bits. The 'flush' + * parameter is exactly the same as that to deflate, with the following + * meanings: + * + * Z_NO_FLUSH: normal incremental output of compressed data + * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush + * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up + * + * The routine manages the acquire and release of the png_ptr->zstream by + * checking and (at the end) clearing png_ptr->zowner; it does some sanity + * checks on the 'mode' flags while doing this. + */ +void /* PRIVATE */ +png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, + png_alloc_size_t input_len, int flush) +{ + if (png_ptr->zowner != png_IDAT) + { + /* First time. Ensure we have a temporary buffer for compression and + * trim the buffer list if it has more than one entry to free memory. + * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been + * created at this point, but the check here is quick and safe. + */ + if (png_ptr->zbuffer_list == NULL) + { + png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, + png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + png_ptr->zbuffer_list->next = NULL; + } + + else + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); + + /* It is a terminal error if we can't claim the zstream. */ + if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* The output state is maintained in png_ptr->zstream, so it must be + * initialized here after the claim. + */ + png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + } + + /* Now loop reading and writing until all the input is consumed or an error + * terminates the operation. The _out values are maintained across calls to + * this function, but the input must be reset each time. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + png_ptr->zstream.avail_in = 0; /* set below */ + for (;;) + { + int ret; + + /* INPUT: from the row data */ + uInt avail = ZLIB_IO_MAX; + + if (avail > input_len) + avail = (uInt)input_len; /* safe because of the check */ + + png_ptr->zstream.avail_in = avail; + input_len -= avail; + + ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); + + /* Include as-yet unconsumed input */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; + + /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note + * that these two zstream fields are preserved across the calls, therefore + * there is no need to set these up on entry to the loop. + */ + if (png_ptr->zstream.avail_out == 0) + { + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size; + + /* Write an IDAT containing the data then reset the buffer. The + * first IDAT may need deflate header optimization. + */ +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + if (size > 0) + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->mode |= PNG_HAVE_IDAT; + + png_ptr->zstream.next_out = data; + png_ptr->zstream.avail_out = size; + + /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with + * the same flush parameter until it has finished output, for NO_FLUSH + * it doesn't matter. + */ + if (ret == Z_OK && flush != Z_NO_FLUSH) + continue; + } + + /* The order of these checks doesn't matter much; it just affects which + * possible error might be detected if multiple things go wrong at once. + */ + if (ret == Z_OK) /* most likely return code! */ + { + /* If all the input has been consumed then just return. If Z_FINISH + * was used as the flush parameter something has gone wrong if we get + * here. + */ + if (input_len == 0) + { + if (flush == Z_FINISH) + png_error(png_ptr, "Z_OK on Z_FINISH with output space"); + + return; + } + } + + else if (ret == Z_STREAM_END && flush == Z_FINISH) + { + /* This is the end of the IDAT data; any pending output must be + * flushed. For small PNG files we may still be at the beginning. + */ + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + if (size > 0) + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->zstream.avail_out = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; + + png_ptr->zowner = 0; /* Release the stream */ + return; + } + + else + { + /* This is an error condition. */ + png_zstream_error(png_ptr, ret); + png_error(png_ptr, png_ptr->zstream.msg); + } + } +} + +/* Write an IEND chunk */ +void /* PRIVATE */ +png_write_IEND(png_structrp png_ptr) +{ + png_debug(1, "in png_write_IEND"); + + png_write_complete_chunk(png_ptr, png_IEND, NULL, 0); + png_ptr->mode |= PNG_HAVE_IEND; +} + +#ifdef PNG_WRITE_gAMA_SUPPORTED +/* Write a gAMA chunk */ +void /* PRIVATE */ +png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) +{ + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA"); + + /* file_gamma is saved in 1/100,000ths */ + png_save_uint_32(buf, (png_uint_32)file_gamma); + png_write_complete_chunk(png_ptr, png_gAMA, buf, 4); +} +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +/* Write a sRGB chunk */ +void /* PRIVATE */ +png_write_sRGB(png_structrp png_ptr, int srgb_intent) +{ + png_byte buf[1]; + + png_debug(1, "in png_write_sRGB"); + + if (srgb_intent >= PNG_sRGB_INTENT_LAST) + png_warning(png_ptr, + "Invalid sRGB rendering intent specified"); + + buf[0]=(png_byte)srgb_intent; + png_write_complete_chunk(png_ptr, png_sRGB, buf, 1); +} +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +/* Write an iCCP chunk */ +void /* PRIVATE */ +png_write_iCCP(png_structrp png_ptr, png_const_charp name, + png_const_bytep profile, png_uint_32 profile_len) +{ + png_uint_32 name_len; + png_byte new_name[81]; /* 1 byte for the compression byte */ + compression_state comp; + png_uint_32 temp; + + png_debug(1, "in png_write_iCCP"); + + /* These are all internal problems: the profile should have been checked + * before when it was stored. + */ + if (profile == NULL) + png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ + + if (profile_len < 132) + png_error(png_ptr, "ICC profile too short"); + + if (png_get_uint_32(profile) != profile_len) + png_error(png_ptr, "Incorrect data in iCCP"); + + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_len & 0x03)) + png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); + + { + png_uint_32 embedded_profile_len = png_get_uint_32(profile); + + if (profile_len != embedded_profile_len) + png_error(png_ptr, "Profile length does not match profile"); + } + + name_len = png_check_keyword(png_ptr, name, new_name); + + if (name_len == 0) + png_error(png_ptr, "iCCP: invalid keyword"); + + new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE; + + /* Make sure we include the NULL after the name and the compression type */ + ++name_len; + + png_text_compress_init(&comp, profile, profile_len); + + /* Allow for keyword terminator and compression byte */ + if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len); + + png_write_chunk_data(png_ptr, new_name, name_len); + + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +/* Write a sPLT chunk */ +void /* PRIVATE */ +png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) +{ + png_uint_32 name_len; + png_byte new_name[80]; + png_byte entrybuf[10]; + size_t entry_size = (spalette->depth == 8 ? 6 : 10); + size_t palette_size = entry_size * (size_t)spalette->nentries; + png_sPLT_entryp ep; +#ifndef PNG_POINTER_INDEXING_SUPPORTED + int i; +#endif + + png_debug(1, "in png_write_sPLT"); + + name_len = png_check_keyword(png_ptr, spalette->name, new_name); + + if (name_len == 0) + png_error(png_ptr, "sPLT: invalid keyword"); + + /* Make sure we include the NULL after the name */ + png_write_chunk_header(png_ptr, png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); + + png_write_chunk_data(png_ptr, (png_bytep)new_name, (size_t)(name_len + 1)); + + png_write_chunk_data(png_ptr, &spalette->depth, 1); + + /* Loop through each palette entry, writing appropriately */ +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (ep = spalette->entries; epentries + spalette->nentries; ep++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep->red; + entrybuf[1] = (png_byte)ep->green; + entrybuf[2] = (png_byte)ep->blue; + entrybuf[3] = (png_byte)ep->alpha; + png_save_uint_16(entrybuf + 4, ep->frequency); + } + + else + { + png_save_uint_16(entrybuf + 0, ep->red); + png_save_uint_16(entrybuf + 2, ep->green); + png_save_uint_16(entrybuf + 4, ep->blue); + png_save_uint_16(entrybuf + 6, ep->alpha); + png_save_uint_16(entrybuf + 8, ep->frequency); + } + + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#else + ep=spalette->entries; + for (i = 0; i>spalette->nentries; i++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep[i].red; + entrybuf[1] = (png_byte)ep[i].green; + entrybuf[2] = (png_byte)ep[i].blue; + entrybuf[3] = (png_byte)ep[i].alpha; + png_save_uint_16(entrybuf + 4, ep[i].frequency); + } + + else + { + png_save_uint_16(entrybuf + 0, ep[i].red); + png_save_uint_16(entrybuf + 2, ep[i].green); + png_save_uint_16(entrybuf + 4, ep[i].blue); + png_save_uint_16(entrybuf + 6, ep[i].alpha); + png_save_uint_16(entrybuf + 8, ep[i].frequency); + } + + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#endif + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +/* Write the sBIT chunk */ +void /* PRIVATE */ +png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) +{ + png_byte buf[4]; + size_t size; + + png_debug(1, "in png_write_sBIT"); + + /* Make sure we don't depend upon the order of PNG_COLOR_8 */ + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_byte maxbits; + + maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : + png_ptr->usr_bit_depth); + + if (sbit->red == 0 || sbit->red > maxbits || + sbit->green == 0 || sbit->green > maxbits || + sbit->blue == 0 || sbit->blue > maxbits) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[0] = sbit->red; + buf[1] = sbit->green; + buf[2] = sbit->blue; + size = 3; + } + + else + { + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[0] = sbit->gray; + size = 1; + } + + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[size++] = sbit->alpha; + } + + png_write_complete_chunk(png_ptr, png_sBIT, buf, size); +} +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +/* Write the cHRM chunk */ +void /* PRIVATE */ +png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy) +{ + png_byte buf[32]; + + png_debug(1, "in png_write_cHRM"); + + /* Each value is saved in 1/100,000ths */ + png_save_int_32(buf, xy->whitex); + png_save_int_32(buf + 4, xy->whitey); + + png_save_int_32(buf + 8, xy->redx); + png_save_int_32(buf + 12, xy->redy); + + png_save_int_32(buf + 16, xy->greenx); + png_save_int_32(buf + 20, xy->greeny); + + png_save_int_32(buf + 24, xy->bluex); + png_save_int_32(buf + 28, xy->bluey); + + png_write_complete_chunk(png_ptr, png_cHRM, buf, 32); +} +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +/* Write the tRNS chunk */ +void /* PRIVATE */ +png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, + png_const_color_16p tran, int num_trans, int color_type) +{ + png_byte buf[6]; + + png_debug(1, "in png_write_tRNS"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) + { + png_app_warning(png_ptr, + "Invalid number of transparent colors specified"); + return; + } + + /* Write the chunk out as it is */ + png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, + (size_t)num_trans); + } + + else if (color_type == PNG_COLOR_TYPE_GRAY) + { + /* One 16-bit value */ + if (tran->gray >= (1 << png_ptr->bit_depth)) + { + png_app_warning(png_ptr, + "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); + + return; + } + + png_save_uint_16(buf, tran->gray); + png_write_complete_chunk(png_ptr, png_tRNS, buf, 2); + } + + else if (color_type == PNG_COLOR_TYPE_RGB) + { + /* Three 16-bit values */ + png_save_uint_16(buf, tran->red); + png_save_uint_16(buf + 2, tran->green); + png_save_uint_16(buf + 4, tran->blue); +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) +#else + if ((buf[0] | buf[2] | buf[4]) != 0) +#endif + { + png_app_warning(png_ptr, + "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); + return; + } + + png_write_complete_chunk(png_ptr, png_tRNS, buf, 6); + } + + else + { + png_app_warning(png_ptr, "Can't write tRNS with an alpha channel"); + } +} +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +/* Write the background chunk */ +void /* PRIVATE */ +png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) +{ + png_byte buf[6]; + + png_debug(1, "in png_write_bKGD"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + (png_ptr->num_palette != 0 || + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) && +#endif + back->index >= png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid background palette index"); + return; + } + + buf[0] = back->index; + png_write_complete_chunk(png_ptr, png_bKGD, buf, 1); + } + + else if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_save_uint_16(buf, back->red); + png_save_uint_16(buf + 2, back->green); + png_save_uint_16(buf + 4, back->blue); +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) +#else + if ((buf[0] | buf[2] | buf[4]) != 0) +#endif + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit bKGD chunk " + "when bit_depth is 8"); + + return; + } + + png_write_complete_chunk(png_ptr, png_bKGD, buf, 6); + } + + else + { + if (back->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); + + return; + } + + png_save_uint_16(buf, back->gray); + png_write_complete_chunk(png_ptr, png_bKGD, buf, 2); + } +} +#endif + +#ifdef PNG_WRITE_cICP_SUPPORTED +/* Write the cICP data */ +void /* PRIVATE */ +png_write_cICP(png_structrp png_ptr, + png_byte colour_primaries, png_byte transfer_function, + png_byte matrix_coefficients, png_byte video_full_range_flag) +{ + png_byte buf[4]; + + png_debug(1, "in png_write_cICP"); + + png_write_chunk_header(png_ptr, png_cICP, 4); + + buf[0] = colour_primaries; + buf[1] = transfer_function; + buf[2] = matrix_coefficients; + buf[3] = video_full_range_flag; + png_write_chunk_data(png_ptr, buf, 4); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_cLLI_SUPPORTED +void /* PRIVATE */ +png_write_cLLI_fixed(png_structrp png_ptr, png_uint_32 maxCLL, + png_uint_32 maxFALL) +{ + png_byte buf[8]; + + png_debug(1, "in png_write_cLLI_fixed"); + + png_save_uint_32(buf, maxCLL); + png_save_uint_32(buf + 4, maxFALL); + + png_write_complete_chunk(png_ptr, png_cLLI, buf, 8); +} +#endif + +#ifdef PNG_WRITE_mDCV_SUPPORTED +void /* PRIVATE */ +png_write_mDCV_fixed(png_structrp png_ptr, + png_uint_16 red_x, png_uint_16 red_y, + png_uint_16 green_x, png_uint_16 green_y, + png_uint_16 blue_x, png_uint_16 blue_y, + png_uint_16 white_x, png_uint_16 white_y, + png_uint_32 maxDL, png_uint_32 minDL) +{ + png_byte buf[24]; + + png_debug(1, "in png_write_mDCV_fixed"); + + png_save_uint_16(buf + 0, red_x); + png_save_uint_16(buf + 2, red_y); + png_save_uint_16(buf + 4, green_x); + png_save_uint_16(buf + 6, green_y); + png_save_uint_16(buf + 8, blue_x); + png_save_uint_16(buf + 10, blue_y); + png_save_uint_16(buf + 12, white_x); + png_save_uint_16(buf + 14, white_y); + png_save_uint_32(buf + 16, maxDL); + png_save_uint_32(buf + 20, minDL); + + png_write_complete_chunk(png_ptr, png_mDCV, buf, 24); +} +#endif + +#ifdef PNG_WRITE_eXIf_SUPPORTED +/* Write the Exif data */ +void /* PRIVATE */ +png_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif) +{ + int i; + png_byte buf[1]; + + png_debug(1, "in png_write_eXIf"); + + png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif)); + + for (i = 0; i < num_exif; i++) + { + buf[0] = exif[i]; + png_write_chunk_data(png_ptr, buf, 1); + } + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +/* Write the histogram */ +void /* PRIVATE */ +png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) +{ + int i; + png_byte buf[3]; + + png_debug(1, "in png_write_hIST"); + + if (num_hist > (int)png_ptr->num_palette) + { + png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, + png_ptr->num_palette); + + png_warning(png_ptr, "Invalid number of histogram entries specified"); + return; + } + + png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2)); + + for (i = 0; i < num_hist; i++) + { + png_save_uint_16(buf, hist[i]); + png_write_chunk_data(png_ptr, buf, 2); + } + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_tEXt_SUPPORTED +/* Write a tEXt chunk */ +void /* PRIVATE */ +png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + size_t text_len) +{ + png_uint_32 key_len; + png_byte new_key[80]; + + png_debug(1, "in png_write_tEXt"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "tEXt: invalid keyword"); + + if (text == NULL || *text == '\0') + text_len = 0; + + else + text_len = strlen(text); + + if (text_len > PNG_UINT_31_MAX - (key_len+1)) + png_error(png_ptr, "tEXt: text too long"); + + /* Make sure we include the 0 after the key */ + png_write_chunk_header(png_ptr, png_tEXt, + (png_uint_32)/*checked above*/(key_len + text_len + 1)); + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, new_key, key_len + 1); + + if (text_len != 0) + png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +/* Write a compressed text chunk */ +void /* PRIVATE */ +png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + int compression) +{ + png_uint_32 key_len; + png_byte new_key[81]; + compression_state comp; + + png_debug(1, "in png_write_zTXt"); + + if (compression == PNG_TEXT_COMPRESSION_NONE) + { + png_write_tEXt(png_ptr, key, text, 0); + return; + } + + if (compression != PNG_TEXT_COMPRESSION_zTXt) + png_error(png_ptr, "zTXt: invalid compression type"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "zTXt: invalid keyword"); + + /* Add the compression method and 1 for the keyword separator. */ + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; + + /* Compute the compressed data; do it now for the length */ + png_text_compress_init(&comp, (png_const_bytep)text, + text == NULL ? 0 : strlen(text)); + + if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* Write start of chunk */ + png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len); + + /* Write key */ + png_write_chunk_data(png_ptr, new_key, key_len); + + /* Write the compressed data */ + png_write_compressed_data_out(png_ptr, &comp); + + /* Close the chunk */ + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +/* Write an iTXt chunk */ +void /* PRIVATE */ +png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, + png_const_charp lang, png_const_charp lang_key, png_const_charp text) +{ + png_uint_32 key_len, prefix_len; + size_t lang_len, lang_key_len; + png_byte new_key[82]; + compression_state comp; + + png_debug(1, "in png_write_iTXt"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "iTXt: invalid keyword"); + + /* Set the compression flag */ + switch (compression) + { + case PNG_ITXT_COMPRESSION_NONE: + case PNG_TEXT_COMPRESSION_NONE: + compression = new_key[++key_len] = 0; /* no compression */ + break; + + case PNG_TEXT_COMPRESSION_zTXt: + case PNG_ITXT_COMPRESSION_zTXt: + compression = new_key[++key_len] = 1; /* compressed */ + break; + + default: + png_error(png_ptr, "iTXt: invalid compression"); + } + + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; /* for the keywod separator */ + + /* We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG, however, + * specifies that the text is UTF-8 and this really doesn't require any + * checking. + * + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + * + * TODO: validate the language tag correctly (see the spec.) + */ + if (lang == NULL) lang = ""; /* empty language is valid */ + lang_len = strlen(lang)+1; + if (lang_key == NULL) lang_key = ""; /* may be empty */ + lang_key_len = strlen(lang_key)+1; + if (text == NULL) text = ""; /* may be empty */ + + prefix_len = key_len; + if (lang_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_len); + + if (lang_key_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_key_len); + + png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); + + if (compression != 0) + { + if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + } + + else + { + if (comp.input_len > PNG_UINT_31_MAX-prefix_len) + png_error(png_ptr, "iTXt: uncompressed text too long"); + + /* So the string will fit in a chunk: */ + comp.output_len = (png_uint_32)/*SAFE*/comp.input_len; + } + + png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len); + + png_write_chunk_data(png_ptr, new_key, key_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); + + if (compression != 0) + png_write_compressed_data_out(png_ptr, &comp); + + else + png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +/* Write the oFFs chunk */ +void /* PRIVATE */ +png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, + int unit_type) +{ + png_byte buf[9]; + + png_debug(1, "in png_write_oFFs"); + + if (unit_type >= PNG_OFFSET_LAST) + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); + + png_save_int_32(buf, x_offset); + png_save_int_32(buf + 4, y_offset); + buf[8] = (png_byte)unit_type; + + png_write_complete_chunk(png_ptr, png_oFFs, buf, 9); +} +#endif +#ifdef PNG_WRITE_pCAL_SUPPORTED +/* Write the pCAL chunk (described in the PNG extensions document) */ +void /* PRIVATE */ +png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, + png_int_32 X1, int type, int nparams, png_const_charp units, + png_charpp params) +{ + png_uint_32 purpose_len; + size_t units_len, total_len; + size_t *params_len; + png_byte buf[10]; + png_byte new_purpose[80]; + int i; + + png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); + + if (type >= PNG_EQUATION_LAST) + png_error(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, new_purpose); + + if (purpose_len == 0) + png_error(png_ptr, "pCAL: invalid keyword"); + + ++purpose_len; /* terminator */ + + png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); + units_len = strlen(units) + (nparams == 0 ? 0 : 1); + png_debug1(3, "pCAL units length = %d", (int)units_len); + total_len = purpose_len + units_len + 10; + + params_len = (size_t *)png_malloc(png_ptr, + (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (size_t)))); + + /* Find the length of each parameter, making sure we don't count the + * null terminator for the last parameter. + */ + for (i = 0; i < nparams; i++) + { + params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + png_debug2(3, "pCAL parameter %d length = %lu", i, + (unsigned long)params_len[i]); + total_len += params_len[i]; + } + + png_debug1(3, "pCAL total length = %d", (int)total_len); + png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, new_purpose, purpose_len); + png_save_int_32(buf, X0); + png_save_int_32(buf + 4, X1); + buf[8] = (png_byte)type; + buf[9] = (png_byte)nparams; + png_write_chunk_data(png_ptr, buf, 10); + png_write_chunk_data(png_ptr, (png_const_bytep)units, (size_t)units_len); + + for (i = 0; i < nparams; i++) + { + png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]); + } + + png_free(png_ptr, params_len); + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +/* Write the sCAL chunk */ +void /* PRIVATE */ +png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, + png_const_charp height) +{ + png_byte buf[64]; + size_t wlen, hlen, total_len; + + png_debug(1, "in png_write_sCAL_s"); + + wlen = strlen(width); + hlen = strlen(height); + total_len = wlen + hlen + 2; + + if (total_len > 64) + { + png_warning(png_ptr, "Can't write sCAL (buffer too small)"); + return; + } + + buf[0] = (png_byte)unit; + memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ + memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ + + png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); + png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len); +} +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +/* Write the pHYs chunk */ +void /* PRIVATE */ +png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, + png_uint_32 y_pixels_per_unit, + int unit_type) +{ + png_byte buf[9]; + + png_debug(1, "in png_write_pHYs"); + + if (unit_type >= PNG_RESOLUTION_LAST) + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); + + png_save_uint_32(buf, x_pixels_per_unit); + png_save_uint_32(buf + 4, y_pixels_per_unit); + buf[8] = (png_byte)unit_type; + + png_write_complete_chunk(png_ptr, png_pHYs, buf, 9); +} +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +/* Write the tIME chunk. Use either png_convert_from_struct_tm() + * or png_convert_from_time_t(), or fill in the structure yourself. + */ +void /* PRIVATE */ +png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) +{ + png_byte buf[7]; + + png_debug(1, "in png_write_tIME"); + + if (mod_time->month > 12 || mod_time->month < 1 || + mod_time->day > 31 || mod_time->day < 1 || + mod_time->hour > 23 || mod_time->second > 60) + { + png_warning(png_ptr, "Invalid time specified for tIME chunk"); + return; + } + + png_save_uint_16(buf, mod_time->year); + buf[2] = mod_time->month; + buf[3] = mod_time->day; + buf[4] = mod_time->hour; + buf[5] = mod_time->minute; + buf[6] = mod_time->second; + + png_write_complete_chunk(png_ptr, png_tIME, buf, 7); +} +#endif + +/* Initializes the row writing capability of libpng */ +void /* PRIVATE */ +png_write_start_row(png_structrp png_ptr) +{ + png_alloc_size_t buf_size; + int usr_pixel_depth; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_byte filters; +#endif + + png_debug(1, "in png_write_start_row"); + + usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; + buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1; + + /* 1.5.6: added to allow checking in the row write code. */ + png_ptr->transformed_pixel_depth = png_ptr->pixel_depth; + png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; + + /* Set up row buffer */ + png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); + + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + filters = png_ptr->do_filter; + + if (png_ptr->height == 1) + filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + if (png_ptr->width == 1) + filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + if (filters == 0) + filters = PNG_FILTER_NONE; + + png_ptr->do_filter = filters; + + if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG | + PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL) + { + int num_filters = 0; + + png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); + + if (filters & PNG_FILTER_SUB) + num_filters++; + + if (filters & PNG_FILTER_UP) + num_filters++; + + if (filters & PNG_FILTER_AVG) + num_filters++; + + if (filters & PNG_FILTER_PAETH) + num_filters++; + + if (num_filters > 1) + png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr, + buf_size)); + } + + /* We only need to keep the previous row if we are using one of the following + * filters. + */ + if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0) + png_ptr->prev_row = png_voidcast(png_bytep, + png_calloc(png_ptr, buf_size)); +#endif /* WRITE_FILTER */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, we need to set up width and height of pass */ + if (png_ptr->interlaced != 0) + { + if ((png_ptr->transformations & PNG_INTERLACE) == 0) + { + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + + png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - + png_pass_start[0]) / png_pass_inc[0]; + } + + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + } + + else +#endif + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } +} + +/* Internal use only. Called when finished processing a row of data. */ +void /* PRIVATE */ +png_write_finish_row(png_structrp png_ptr) +{ + png_debug(1, "in png_write_finish_row"); + + /* Next row */ + png_ptr->row_number++; + + /* See if we are done */ + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, go to next pass */ + if (png_ptr->interlaced != 0) + { + png_ptr->row_number = 0; + if ((png_ptr->transformations & PNG_INTERLACE) != 0) + { + png_ptr->pass++; + } + + else + { + /* Loop until we find a non-zero width or height pass */ + do + { + png_ptr->pass++; + + if (png_ptr->pass >= 7) + break; + + png_ptr->usr_width = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + if ((png_ptr->transformations & PNG_INTERLACE) != 0) + break; + + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); + + } + + /* Reset the row above the image for the next pass */ + if (png_ptr->pass < 7) + { + if (png_ptr->prev_row != NULL) + memset(png_ptr->prev_row, 0, + PNG_ROWBYTES(png_ptr->usr_channels * + png_ptr->usr_bit_depth, png_ptr->width) + 1); + + return; + } + } +#endif + + /* If we get here, we've just written the last row, so we need + to flush the compressor */ + png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH); +} + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Pick out the correct pixels for the interlace pass. + * The basic idea here is to go through the row with a source + * pointer and a destination pointer (sp and dp), and copy the + * correct pixels for the pass. As the row gets compacted, + * sp will always be >= dp, so we should never overwrite anything. + * See the default: case for the easiest code to understand. + */ +void /* PRIVATE */ +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) +{ + png_debug(1, "in png_do_write_interlace"); + + /* We don't have to do anything on the last pass (6) */ + if (pass < 6) + { + /* Each pixel depth is handled separately */ + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + unsigned int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + d = 0; + shift = 7; + + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (size_t)(i >> 3); + value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; + d |= (value << shift); + + if (shift == 0) + { + shift = 7; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift--; + + } + if (shift != 7) + *dp = (png_byte)d; + + break; + } + + case 2: + { + png_bytep sp; + png_bytep dp; + unsigned int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 6; + d = 0; + + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (size_t)(i >> 2); + value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; + d |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift -= 2; + } + if (shift != 6) + *dp = (png_byte)d; + + break; + } + + case 4: + { + png_bytep sp; + png_bytep dp; + unsigned int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 4; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (size_t)(i >> 1); + value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; + d |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift -= 4; + } + if (shift != 4) + *dp = (png_byte)d; + + break; + } + + default: + { + png_bytep sp; + png_bytep dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + size_t pixel_bytes; + + /* Start at the beginning */ + dp = row; + + /* Find out how many bytes each pixel takes up */ + pixel_bytes = (row_info->pixel_depth >> 3); + + /* Loop through the row, only looking at the pixels that matter */ + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + /* Find out where the original pixel is */ + sp = row + (size_t)i * pixel_bytes; + + /* Move the pixel */ + if (dp != sp) + memcpy(dp, sp, pixel_bytes); + + /* Next pixel */ + dp += pixel_bytes; + } + break; + } + } + /* Set new row width */ + row_info->width = (row_info->width + + png_pass_inc[pass] - 1 - + png_pass_start[pass]) / + png_pass_inc[pass]; + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + + +/* This filters the row, chooses which filter to use, if it has not already + * been specified by the application, and then writes the row out with the + * chosen filter. + */ +static void /* PRIVATE */ +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + size_t row_bytes); + +#ifdef PNG_WRITE_FILTER_SUPPORTED +static size_t /* PRIVATE */ +png_setup_sub_row(png_structrp png_ptr, png_uint_32 bpp, + size_t row_bytes, size_t lmins) +{ + png_bytep rp, dp, lp; + size_t i; + size_t sum = 0; + unsigned int v; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; +#ifdef PNG_USE_ABS + sum += 128 - abs((int)v - 128); +#else + sum += (v < 128) ? v : 256 - v; +#endif + } + + for (lp = png_ptr->row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); +#ifdef PNG_USE_ABS + sum += 128 - abs((int)v - 128); +#else + sum += (v < 128) ? v : 256 - v; +#endif + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + + return sum; +} + +static void /* PRIVATE */ +png_setup_sub_row_only(png_structrp png_ptr, png_uint_32 bpp, + size_t row_bytes) +{ + png_bytep rp, dp, lp; + size_t i; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp; + i++, rp++, dp++) + { + *dp = *rp; + } + + for (lp = png_ptr->row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + } +} + +static size_t /* PRIVATE */ +png_setup_up_row(png_structrp png_ptr, size_t row_bytes, size_t lmins) +{ + png_bytep rp, dp, pp; + size_t i; + size_t sum = 0; + unsigned int v; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_UP; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); +#ifdef PNG_USE_ABS + sum += 128 - abs((int)v - 128); +#else + sum += (v < 128) ? v : 256 - v; +#endif + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + + return sum; +} +static void /* PRIVATE */ +png_setup_up_row_only(png_structrp png_ptr, size_t row_bytes) +{ + png_bytep rp, dp, pp; + size_t i; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_UP; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + } +} + +static size_t /* PRIVATE */ +png_setup_avg_row(png_structrp png_ptr, png_uint_32 bpp, + size_t row_bytes, size_t lmins) +{ + png_bytep rp, dp, pp, lp; + png_uint_32 i; + size_t sum = 0; + unsigned int v; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + +#ifdef PNG_USE_ABS + sum += 128 - abs((int)v - 128); +#else + sum += (v < 128) ? v : 256 - v; +#endif + } + + for (lp = png_ptr->row_buf + 1; i < row_bytes; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + +#ifdef PNG_USE_ABS + sum += 128 - abs((int)v - 128); +#else + sum += (v < 128) ? v : 256 - v; +#endif + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + + return sum; +} +static void /* PRIVATE */ +png_setup_avg_row_only(png_structrp png_ptr, png_uint_32 bpp, + size_t row_bytes) +{ + png_bytep rp, dp, pp, lp; + png_uint_32 i; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + } + + for (lp = png_ptr->row_buf + 1; i < row_bytes; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + } +} + +static size_t /* PRIVATE */ +png_setup_paeth_row(png_structrp png_ptr, png_uint_32 bpp, + size_t row_bytes, size_t lmins) +{ + png_bytep rp, dp, pp, cp, lp; + size_t i; + size_t sum = 0; + unsigned int v; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + +#ifdef PNG_USE_ABS + sum += 128 - abs((int)v - 128); +#else + sum += (v < 128) ? v : 256 - v; +#endif + } + + for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes; + i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + +#ifdef PNG_USE_ABS + sum += 128 - abs((int)v - 128); +#else + sum += (v < 128) ? v : 256 - v; +#endif + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + + return sum; +} +static void /* PRIVATE */ +png_setup_paeth_row_only(png_structrp png_ptr, png_uint_32 bpp, + size_t row_bytes) +{ + png_bytep rp, dp, pp, cp, lp; + size_t i; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + } + + for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes; + i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + } +} +#endif /* WRITE_FILTER */ + +void /* PRIVATE */ +png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) +{ +#ifndef PNG_WRITE_FILTER_SUPPORTED + png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1); +#else + unsigned int filter_to_do = png_ptr->do_filter; + png_bytep row_buf; + png_bytep best_row; + png_uint_32 bpp; + size_t mins; + size_t row_bytes = row_info->rowbytes; + + png_debug(1, "in png_write_find_filter"); + + /* Find out how many bytes offset each pixel is */ + bpp = (row_info->pixel_depth + 7) >> 3; + + row_buf = png_ptr->row_buf; + mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the + running sum */; + + /* The prediction method we use is to find which method provides the + * smallest value when summing the absolute values of the distances + * from zero, using anything >= 128 as negative numbers. This is known + * as the "minimum sum of absolute differences" heuristic. Other + * heuristics are the "weighted minimum sum of absolute differences" + * (experimental and can in theory improve compression), and the "zlib + * predictive" method (not implemented yet), which does test compressions + * of lines using different filter methods, and then chooses the + * (series of) filter(s) that give minimum compressed data size (VERY + * computationally expensive). + * + * GRR 980525: consider also + * + * (1) minimum sum of absolute differences from running average (i.e., + * keep running sum of non-absolute differences & count of bytes) + * [track dispersion, too? restart average if dispersion too large?] + * + * (1b) minimum sum of absolute differences from sliding average, probably + * with window size <= deflate window (usually 32K) + * + * (2) minimum sum of squared differences from zero or running average + * (i.e., ~ root-mean-square approach) + */ + + + /* We don't need to test the 'no filter' case if this is the only filter + * that has been chosen, as it doesn't actually do anything to the data. + */ + best_row = png_ptr->row_buf; + + if (PNG_SIZE_MAX/128 <= row_bytes) + { + /* Overflow can occur in the calculation, just select the lowest set + * filter. + */ + filter_to_do &= 0U-filter_to_do; + } + else if ((filter_to_do & PNG_FILTER_NONE) != 0 && + filter_to_do != PNG_FILTER_NONE) + { + /* Overflow not possible and multiple filters in the list, including the + * 'none' filter. + */ + png_bytep rp; + size_t sum = 0; + size_t i; + unsigned int v; + + { + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) + { + v = *rp; +#ifdef PNG_USE_ABS + sum += 128 - abs((int)v - 128); +#else + sum += (v < 128) ? v : 256 - v; +#endif + } + } + + mins = sum; + } + + /* Sub filter */ + if (filter_to_do == PNG_FILTER_SUB) + /* It's the only filter so no testing is needed */ + { + png_setup_sub_row_only(png_ptr, bpp, row_bytes); + best_row = png_ptr->try_row; + } + + else if ((filter_to_do & PNG_FILTER_SUB) != 0) + { + size_t sum; + size_t lmins = mins; + + sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins); + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->try_row; + if (png_ptr->tst_row != NULL) + { + png_ptr->try_row = png_ptr->tst_row; + png_ptr->tst_row = best_row; + } + } + } + + /* Up filter */ + if (filter_to_do == PNG_FILTER_UP) + { + png_setup_up_row_only(png_ptr, row_bytes); + best_row = png_ptr->try_row; + } + + else if ((filter_to_do & PNG_FILTER_UP) != 0) + { + size_t sum; + size_t lmins = mins; + + sum = png_setup_up_row(png_ptr, row_bytes, lmins); + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->try_row; + if (png_ptr->tst_row != NULL) + { + png_ptr->try_row = png_ptr->tst_row; + png_ptr->tst_row = best_row; + } + } + } + + /* Avg filter */ + if (filter_to_do == PNG_FILTER_AVG) + { + png_setup_avg_row_only(png_ptr, bpp, row_bytes); + best_row = png_ptr->try_row; + } + + else if ((filter_to_do & PNG_FILTER_AVG) != 0) + { + size_t sum; + size_t lmins = mins; + + sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins); + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->try_row; + if (png_ptr->tst_row != NULL) + { + png_ptr->try_row = png_ptr->tst_row; + png_ptr->tst_row = best_row; + } + } + } + + /* Paeth filter */ + if (filter_to_do == PNG_FILTER_PAETH) + { + png_setup_paeth_row_only(png_ptr, bpp, row_bytes); + best_row = png_ptr->try_row; + } + + else if ((filter_to_do & PNG_FILTER_PAETH) != 0) + { + size_t sum; + size_t lmins = mins; + + sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins); + + if (sum < mins) + { + best_row = png_ptr->try_row; + if (png_ptr->tst_row != NULL) + { + png_ptr->try_row = png_ptr->tst_row; + png_ptr->tst_row = best_row; + } + } + } + + /* Do the actual writing of the filtered row data from the chosen filter. */ + png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); + +#endif /* WRITE_FILTER */ +} + + +/* Do the actual writing of a previously filtered row. */ +static void +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + size_t full_row_length/*includes filter byte*/) +{ + png_debug(1, "in png_write_filtered_row"); + + png_debug1(2, "filter = %d", filtered_row[0]); + + png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); + +#ifdef PNG_WRITE_FILTER_SUPPORTED + /* Swap the current and previous rows */ + if (png_ptr->prev_row != NULL) + { + png_bytep tptr; + + tptr = png_ptr->prev_row; + png_ptr->prev_row = png_ptr->row_buf; + png_ptr->row_buf = tptr; + } +#endif /* WRITE_FILTER */ + + /* Finish row - updates counters and flushes zlib if last row */ + png_write_finish_row(png_ptr); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->flush_rows++; + + if (png_ptr->flush_dist > 0 && + png_ptr->flush_rows >= png_ptr->flush_dist) + { + png_write_flush(png_ptr); + } +#endif /* WRITE_FLUSH */ +} +#endif /* WRITE */ diff --git a/widget/milsko/milskosrc/external/libz/LICENSE b/widget/milsko/milskosrc/external/libz/LICENSE new file mode 100644 index 0000000000..ab8ee6f714 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/LICENSE @@ -0,0 +1,22 @@ +Copyright notice: + + (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu diff --git a/widget/milsko/milskosrc/external/libz/README b/widget/milsko/milskosrc/external/libz/README new file mode 100644 index 0000000000..c5f917540b --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/README @@ -0,0 +1,117 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.3.1 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and +rfc1952 (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file test/example.c which also tests that +the library is working correctly. Another example is given in the file +test/minigzip.c. The compression library itself is composed of all source +files in the root directory. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile.in. In short "./configure; make test", and if that goes +well, "make install" should work for most flavors of Unix. For Windows, use +one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use +make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available at +https://marknelson.us/posts/1997/01/01/zlib-engine.html . + +The changes made in version 1.3.1 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory contrib/ . + +zlib is available in Java using the java.util.zip package. Follow the API +Documentation link at: https://docs.oracle.com/search/?q=java.util.zip . + +A Perl interface to zlib and bzip2 written by Paul Marquess +can be found at https://github.com/pmqs/IO-Compress . + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://docs.python.org/library/zlib.html . + +zlib is built into tcl: http://wiki.tcl.tk/4610 . + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formerly OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS or BEOS. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate and + zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; they + are too numerous to cite here. + +Copyright notice: + + (C) 1995-2024 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. We make all +contributions to and distributions of this project solely in our personal +capacity, and are not conveying any rights to any intellectual property of +any third parties. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/modules/zlib/src/crc32_braid_tbl.h b/widget/milsko/milskosrc/external/libz/include/crc32.h similarity index 99% rename from modules/zlib/src/crc32_braid_tbl.h rename to widget/milsko/milskosrc/external/libz/include/crc32.h index 5e39a1c493..137df68d61 100644 --- a/modules/zlib/src/crc32_braid_tbl.h +++ b/widget/milsko/milskosrc/external/libz/include/crc32.h @@ -1,11 +1,8 @@ -#ifndef CRC32_BRAID_TBL_H_ -#define CRC32_BRAID_TBL_H_ - -/* crc32_braid_tbl.h -- tables for braided CRC calculation - * Generated automatically by makecrct.c +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c */ -static const uint32_t crc_table[] = { +local const z_crc_t FAR crc_table[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, @@ -59,10 +56,11 @@ static const uint32_t crc_table[] = { 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; -#ifdef BRAID_W -# if BRAID_W == 8 +#ifdef W -static const z_word_t crc_big_table[] = { +#if W == 8 + +local const z_word_t FAR crc_big_table[] = { 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, @@ -150,9 +148,9 @@ static const z_word_t crc_big_table[] = { 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, 0x8def022d00000000}; -# else /* BRAID_W == 4 */ +#else /* W == 4 */ -static const z_word_t crc_big_table[] = { +local const z_word_t FAR crc_big_table[] = { 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, @@ -206,13 +204,13 @@ static const z_word_t crc_big_table[] = { 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, 0x8def022d}; -# endif -#endif /* BRAID_W */ +#endif -#if BRAID_N == 1 -# if BRAID_W == 8 +#if N == 1 -static const uint32_t crc_braid_table[][256] = { +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, @@ -630,7 +628,7 @@ static const uint32_t crc_braid_table[][256] = { 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, @@ -1320,9 +1318,9 @@ static const z_word_t crc_braid_big_table[][256] = { 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, 0xe6064b2600000000}}; -# else /* BRAID_W == 4 */ +#else /* W == 4 */ -static const uint32_t crc_braid_table[][256] = { +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, @@ -1532,7 +1530,7 @@ static const uint32_t crc_braid_table[][256] = { 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, @@ -1742,12 +1740,15 @@ static const z_word_t crc_braid_big_table[][256] = { 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, 0xf10605de}}; -# endif /* BRAID_W */ -#endif /* BRAID_N == 1 */ -#if BRAID_N == 2 -# if BRAID_W == 8 +#endif -static const uint32_t crc_braid_table[][256] = { +#endif + +#if N == 2 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, @@ -2165,7 +2166,7 @@ static const uint32_t crc_braid_table[][256] = { 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, 0x494f0c4b}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, @@ -2855,9 +2856,9 @@ static const z_word_t crc_braid_big_table[][256] = { 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, 0xd739710d00000000}}; -# else /* BRAID_W == 4 */ +#else /* W == 4 */ -static const uint32_t crc_braid_table[][256] = { +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, @@ -3067,7 +3068,7 @@ static const uint32_t crc_braid_table[][256] = { 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, 0xca64c78c}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, @@ -3277,12 +3278,15 @@ static const z_word_t crc_braid_big_table[][256] = { 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, 0xe6064b26}}; -# endif /* BRAID_W */ -#endif /* BRAID_N == 2 */ -#if BRAID_N == 3 -# if BRAID_W == 8 +#endif -static const uint32_t crc_braid_table[][256] = { +#endif + +#if N == 3 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, @@ -3700,7 +3704,7 @@ static const uint32_t crc_braid_table[][256] = { 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, 0x18ba364e}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, @@ -4390,9 +4394,9 @@ static const z_word_t crc_braid_big_table[][256] = { 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, 0x5185cd0900000000}}; -# else /* BRAID_W == 4 */ +#else /* W == 4 */ -static const uint32_t crc_braid_table[][256] = { +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, @@ -4602,7 +4606,7 @@ static const uint32_t crc_braid_table[][256] = { 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, 0x494f0c4b}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, @@ -4812,12 +4816,15 @@ static const z_word_t crc_braid_big_table[][256] = { 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, 0x65711936}}; -# endif /* BRAID_W */ -#endif /* BRAID_N == 3 */ -#if BRAID_N == 4 -# if BRAID_W == 8 +#endif -static const uint32_t crc_braid_table[][256] = { +#endif + +#if N == 4 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, @@ -5235,7 +5242,7 @@ static const uint32_t crc_braid_table[][256] = { 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, 0x1c65ace7}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, @@ -5925,9 +5932,9 @@ static const z_word_t crc_braid_big_table[][256] = { 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, 0x1659c4e300000000}}; -# else /* BRAID_W == 4 */ +#else /* W == 4 */ -static const uint32_t crc_braid_table[][256] = { +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, @@ -6137,7 +6144,7 @@ static const uint32_t crc_braid_table[][256] = { 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, 0x3dee8ca6}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, @@ -6347,12 +6354,15 @@ static const z_word_t crc_braid_big_table[][256] = { 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, 0xd739710d}}; -# endif /* BRAID_W */ -#endif /* BRAID_N == 4 */ -#if BRAID_N == 5 -# if BRAID_W == 8 +#endif -static const uint32_t crc_braid_table[][256] = { +#endif + +#if N == 5 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, @@ -6770,7 +6780,7 @@ static const uint32_t crc_braid_table[][256] = { 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, 0xf4377108}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, @@ -7460,9 +7470,9 @@ static const z_word_t crc_braid_big_table[][256] = { 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, 0x657594e900000000}}; -# else /* BRAID_W == 4 */ +#else /* W == 4 */ -static const uint32_t crc_braid_table[][256] = { +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, @@ -7672,7 +7682,7 @@ static const uint32_t crc_braid_table[][256] = { 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, 0x18ba364e}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, @@ -7882,12 +7892,15 @@ static const z_word_t crc_braid_big_table[][256] = { 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, 0x356bacd8}}; -# endif /* BRAID_W */ -#endif /* BRAID_N == 5 */ -#if BRAID_N == 6 -# if BRAID_W == 8 +#endif -static const uint32_t crc_braid_table[][256] = { +#endif + +#if N == 6 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, @@ -8305,7 +8318,7 @@ static const uint32_t crc_braid_table[][256] = { 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, 0x3d3101a2}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, @@ -8995,9 +9008,9 @@ static const z_word_t crc_braid_big_table[][256] = { 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, 0xa8a0688500000000}}; -# else /* BRAID_W == 4 */ +#else /* W == 4 */ -static const uint32_t crc_braid_table[][256] = { +local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, @@ -9207,7 +9220,7 @@ static const uint32_t crc_braid_table[][256] = { 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, 0x566b6848}}; -static const z_word_t crc_braid_big_table[][256] = { +local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, @@ -9417,10 +9430,13 @@ static const z_word_t crc_braid_big_table[][256] = { 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, 0x5185cd09}}; -# endif /* BRAID_W */ -#endif /* BRAID_N == 6 */ +#endif -static const uint32_t x2n_table[] = { +#endif + +#endif + +local const z_crc_t FAR x2n_table[] = { 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, @@ -9428,5 +9444,3 @@ static const uint32_t x2n_table[] = { 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, 0xc40ba6d0, 0xc4e22c3c}; - -#endif /* CRC32_BRAID_TBL_H_ */ diff --git a/widget/milsko/milskosrc/external/libz/include/deflate.h b/widget/milsko/milskosrc/external/libz/include/deflate.h new file mode 100644 index 0000000000..300c6ada62 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/deflate.h @@ -0,0 +1,377 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2024 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at + the cost of a larger memory footprint */ +/* #define LIT_MEM */ + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +#endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + ulg pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + ulg gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + +#ifdef LIT_MEM +# define LIT_BUFS 5 + ushf *d_buf; /* buffer for distances */ + uchf *l_buf; /* buffer for literals/lengths */ +#else +# define LIT_BUFS 4 + uchf *sym_buf; /* buffer for distances and literals/lengths */ +#endif + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt sym_next; /* running index in symbol buffer */ + uInt sym_end; /* symbol table full when sym_next reaches this */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ + +#ifdef ZLIB_DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init(deflate_state *s); +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc); +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last); +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s); +void ZLIB_INTERNAL _tr_align(deflate_state *s); +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef ZLIB_DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +#ifdef LIT_MEM +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->sym_next] = 0; \ + s->l_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->d_buf[s->sym_next] = dist; \ + s->l_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +#else +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ + s->sym_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +#endif +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/widget/milsko/milskosrc/external/libz/include/gzguts.h b/widget/milsko/milskosrc/external/libz/include/gzguts.h new file mode 100644 index 0000000000..eba72085bb --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/gzguts.h @@ -0,0 +1,214 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# undef _FILE_OFFSET_BITS +# undef _TIME_BITS +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#if defined(_WIN32) +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc(uInt size); + extern void free(voidpf ptr); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + int reset; /* true if a reset is pending after a Z_FINISH */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error(gz_statep, int, const char *); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror(DWORD error); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +unsigned ZLIB_INTERNAL gz_intmax(void); +#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) diff --git a/widget/milsko/milskosrc/external/libz/include/inffast.h b/widget/milsko/milskosrc/external/libz/include/inffast.h new file mode 100644 index 0000000000..49c6d156c5 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); diff --git a/widget/milsko/milskosrc/external/libz/include/inffixed.h b/widget/milsko/milskosrc/external/libz/include/inffixed.h new file mode 100644 index 0000000000..d628327769 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/widget/milsko/milskosrc/external/libz/include/inflate.h b/widget/milsko/milskosrc/external/libz/include/inflate.h new file mode 100644 index 0000000000..f127b6b1fa --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/inflate.h @@ -0,0 +1,126 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/widget/milsko/milskosrc/external/libz/include/inftrees.h b/widget/milsko/milskosrc/external/libz/include/inftrees.h new file mode 100644 index 0000000000..396f74b5da --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns 852, and "enough 30 6 15" for distance codes returns 592. The + initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work); diff --git a/widget/milsko/milskosrc/external/libz/include/trees.h b/widget/milsko/milskosrc/external/libz/include/trees.h new file mode 100644 index 0000000000..d35639d82a --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/widget/milsko/milskosrc/external/libz/include/zconf.h b/widget/milsko/milskosrc/external/libz/include/zconf.h new file mode 100644 index 0000000000..44a29f213d --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/zconf.h @@ -0,0 +1,547 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO +# ifdef _WIN64 + typedef unsigned long long z_size_t; +# else + typedef unsigned long z_size_t; +# endif +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifndef _WIN32 +#define HAVE_UNISTD_H +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/widget/milsko/milskosrc/external/libz/include/zlib.h b/widget/milsko/milskosrc/external/libz/include/zlib.h new file mode 100644 index 0000000000..8d4b932eaf --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/zlib.h @@ -0,0 +1,1938 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.3.1, January 22nd, 2024 + + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.3.1" +#define ZLIB_VERNUM 0x1310 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 1 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); +typedef void (*free_func)(voidpf opaque, voidpf address); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion(void); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. total_in, total_out, adler, and msg are initialized. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more output + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit(z_streamp strm); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy); + + This is another version of deflateInit with more compression options. The + fields zalloc, zfree and opaque must be initialized before by the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy(z_streamp dest, + z_streamp source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset(z_streamp strm); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. total_in, total_out, adler, and msg are initialized. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams(z_streamp strm, + int level, + int strategy); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune(z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, + uLong sourceLen); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending(z_streamp strm, + unsigned *pending, + int *bits); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime(z_streamp strm, + int bits, + int value); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm, + gz_headerp head); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2(z_streamp strm, + int windowBits); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync(z_streamp strm); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, + z_streamp source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset(z_streamp strm); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, + int windowBits); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, + int bits, + int value); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark(z_streamp strm); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, + gz_headerp head); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, + unsigned char FAR *window); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func)(void FAR *, + z_const unsigned char FAR * FAR *); +typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); + +ZEXTERN int ZEXPORT inflateBack(z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags(void); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode); + + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode); +/* + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size); +/* + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy); +/* + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len); +/* + Read and decompress up to len uncompressed bytes from file into buf. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, + gzFile file); +/* + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. If the library + defines size_t, then z_size_t is identical to size_t. If not, then z_size_t + is an unsigned integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevertheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, resetting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len); +/* + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, + z_size_t nitems, gzFile file); +/* + Compress and write nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); +/* + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf(), + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s); +/* + Compress and write the given null-terminated string s to file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len); +/* + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc(gzFile file, int c); +/* + Compress and write c, converted to an unsigned char, into file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc(gzFile file); +/* + Read and decompress one byte from file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); +/* + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush(gzFile file, int flush); +/* + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek(gzFile file, + z_off_t offset, int whence); + + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind(gzFile file); +/* + Rewind file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell(gzFile file); + + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file); + + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof(gzFile file); +/* + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect(gzFile file); +/* + Return true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose(gzFile file); +/* + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r(gzFile file); +ZEXTERN int ZEXPORT gzclose_w(gzFile file); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum); +/* + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr(gzFile file); +/* + Clear the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, + z_size_t len); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, + z_off_t len2); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf, + z_size_t len); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. len2 must be non-negative. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); + + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). len2 must be non-negative. +*/ + +ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateInit_(z_streamp strm, + const char *version, int stream_size); +ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size); +ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# define z_crc32_combine_gen z_crc32_combine_gen64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# define crc32_combine_gen crc32_combine_gen64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError(int); +ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); +ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); +ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); +ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); +ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, + const char *mode); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, + const char *format, + va_list va); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/widget/milsko/milskosrc/external/libz/include/zutil.h b/widget/milsko/milskosrc/external/libz/include/zutil.h new file mode 100644 index 0000000000..48dd7febae --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/include/zutil.h @@ -0,0 +1,254 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) +# include +# if (ULONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long +# elif (ULLONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long long +# elif (UINT_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned +# endif +#endif + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) +# define OS_CODE 7 +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); + int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len); + void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len); +#endif + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error(char *m); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, + unsigned size); + void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/widget/milsko/milskosrc/external/libz/src/adler32.c b/widget/milsko/milskosrc/external/libz/src/adler32.c new file mode 100644 index 0000000000..04b81d29ba --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/adler32.c @@ -0,0 +1,164 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { + return adler32_z(adler, buf, len); +} + +/* ========================================================================= */ +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { + return adler32_combine_(adler1, adler2, len2); +} diff --git a/widget/milsko/milskosrc/external/libz/src/compress.c b/widget/milsko/milskosrc/external/libz/src/compress.c new file mode 100644 index 0000000000..f43bacf7ab --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/compress.c @@ -0,0 +1,75 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen, int level) { + z_stream stream; + int err; + const uInt max = (uInt)-1; + uLong left; + + left = *destLen; + *destLen = 0; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + stream.next_out = dest; + stream.avail_out = 0; + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; + sourceLen -= stream.avail_in; + } + err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); + } while (err == Z_OK); + + *destLen = stream.total_out; + deflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : err; +} + +/* =========================================================================== + */ +int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen) { + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound(uLong sourceLen) { + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/widget/milsko/milskosrc/external/libz/src/crc32.c b/widget/milsko/milskosrc/external/libz/src/crc32.c new file mode 100644 index 0000000000..6c38f5c04c --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/crc32.c @@ -0,0 +1,1049 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + MAKECRCH can be #defined to write out crc32.h. A main() routine is also + produced, so that this one source file can be compiled to an executable. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */ + + /* + A CRC of a message is computed on N braids of words in the message, where + each word consists of W bytes (4 or 8). If N is 3, for example, then three + running sparse CRCs are calculated respectively on each braid, at these + indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... + This is done starting at a word boundary, and continues until as many blocks + of N * W bytes as are available have been processed. The results are combined + into a single CRC at the end. For this code, N must be in the range 1..6 and + W must be 4 or 8. The upper limit on N can be increased if desired by adding + more #if blocks, extending the patterns apparent in the code. In addition, + crc32.h would need to be regenerated, if the maximum N value is increased. + + N and W are chosen empirically by benchmarking the execution time on a given + processor. The choices for N and W below were based on testing on Intel Kaby + Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 + Octeon II processors. The Intel, AMD, and ARM processors were all fastest + with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. + They were all tested with either gcc or clang, all using the -O3 optimization + level. Your mileage may vary. + */ + +/* Define N */ +#ifdef Z_TESTN +# define N Z_TESTN +#else +# define N 5 +#endif +#if N < 1 || N > 6 +# error N must be in 1..6 +#endif + +/* + z_crc_t must be at least 32 bits. z_word_t must be at least as long as + z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and + that bytes are eight bits. + */ + +/* + Define W and the associated z_word_t type. If W is not defined, then a + braided calculation is not used, and the associated tables and code are not + compiled. + */ +#ifdef Z_TESTW +# if Z_TESTW-1 != -1 +# define W Z_TESTW +# endif +#else +# ifdef MAKECRCH +# define W 8 /* required for MAKECRCH */ +# else +# if defined(__x86_64__) || defined(__aarch64__) +# define W 8 +# else +# define W 4 +# endif +# endif +#endif +#ifdef W +# if W == 8 && defined(Z_U8) + typedef Z_U8 z_word_t; +# elif defined(Z_U4) +# undef W +# define W 4 + typedef Z_U4 z_word_t; +# else +# undef W +# endif +#endif + +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) +/* + Swap the bytes in a z_word_t to convert between little and big endian. Any + self-respecting compiler will optimize this to a single machine byte-swap + instruction, if one is available. This assumes that word_t is either 32 bits + or 64 bits. + */ +local z_word_t byte_swap(z_word_t word) { +# if W == 8 + return + (word & 0xff00000000000000) >> 56 | + (word & 0xff000000000000) >> 40 | + (word & 0xff0000000000) >> 24 | + (word & 0xff00000000) >> 8 | + (word & 0xff000000) << 8 | + (word & 0xff0000) << 24 | + (word & 0xff00) << 40 | + (word & 0xff) << 56; +# else /* W == 4 */ + return + (word & 0xff000000) >> 24 | + (word & 0xff0000) >> 8 | + (word & 0xff00) << 8 | + (word & 0xff) << 24; +# endif +} +#endif + +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Table of powers of x for combining CRC-32s, filled in by make_crc_table() + * below. + */ + local z_crc_t FAR x2n_table[32]; +#else +/* ========================================================================= + * Tables for byte-wise and braided CRC-32 calculations, and a table of powers + * of x for combining CRC-32s, all made by make_crc_table(). + */ +# include "crc32.h" +#endif + +/* CRC polynomial. */ +#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ + +/* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +local z_crc_t multmodp(z_crc_t a, z_crc_t b) { + z_crc_t m, p; + + m = (z_crc_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} + +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +local z_crc_t x2nmodp(z_off64_t n, unsigned k) { + z_crc_t p; + + p = (z_crc_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} + +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Build the tables for byte-wise and braided CRC-32 calculations, and a table + * of powers of x for combining CRC-32s. + */ +local z_crc_t FAR crc_table[256]; +#ifdef W + local z_word_t FAR crc_big_table[256]; + local z_crc_t FAR crc_braid_table[W][256]; + local z_word_t FAR crc_braid_big_table[W][256]; + local void braid(z_crc_t [][256], z_word_t [][256], int, int); +#endif +#ifdef MAKECRCH + local void write_table(FILE *, const z_crc_t FAR *, int); + local void write_table32hi(FILE *, const z_word_t FAR *, int); + local void write_table64(FILE *, const z_word_t FAR *, int); +#endif /* MAKECRCH */ + +/* + Define a once() function depending on the availability of atomics. If this is + compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in + multiple threads, and if atomics are not available, then get_crc_table() must + be called to initialize the tables and must return before any threads are + allowed to compute or combine CRCs. + */ + +/* Definition of once functionality. */ +typedef struct once_s once_t; + +/* Check for the availability of atomics. */ +#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ + !defined(__STDC_NO_ATOMICS__) + +#include + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + atomic_flag begun; + atomic_int done; +}; +#define ONCE_INIT {ATOMIC_FLAG_INIT, 0} + +/* + Run the provided init() function exactly once, even if multiple threads + invoke once() at the same time. The state must be a once_t initialized with + ONCE_INIT. + */ +local void once(once_t *state, void (*init)(void)) { + if (!atomic_load(&state->done)) { + if (atomic_flag_test_and_set(&state->begun)) + while (!atomic_load(&state->done)) + ; + else { + init(); + atomic_store(&state->done, 1); + } + } +} + +#else /* no atomics */ + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + volatile int begun; + volatile int done; +}; +#define ONCE_INIT {0, 0} + +/* Test and set. Alas, not atomic, but tries to minimize the period of + vulnerability. */ +local int test_and_set(int volatile *flag) { + int was; + + was = *flag; + *flag = 1; + return was; +} + +/* Run the provided init() function once. This is not thread-safe. */ +local void once(once_t *state, void (*init)(void)) { + if (!state->done) { + if (test_and_set(&state->begun)) + while (!state->done) + ; + else { + init(); + state->done = 1; + } + } +} + +#endif + +/* State for once(). */ +local once_t made = ONCE_INIT; + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x + (which is shifting right by one and adding x^32 mod p if the bit shifted out + is a one). We start with the highest power (least significant bit) of q and + repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all the + information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. + */ + +local void make_crc_table(void) { + unsigned i, j, n; + z_crc_t p; + + /* initialize the CRC of bytes tables */ + for (i = 0; i < 256; i++) { + p = i; + for (j = 0; j < 8; j++) + p = p & 1 ? (p >> 1) ^ POLY : p >> 1; + crc_table[i] = p; +#ifdef W + crc_big_table[i] = byte_swap(p); +#endif + } + + /* initialize the x^2^n mod p(x) table */ + p = (z_crc_t)1 << 30; /* x^1 */ + x2n_table[0] = p; + for (n = 1; n < 32; n++) + x2n_table[n] = p = multmodp(p, p); + +#ifdef W + /* initialize the braiding tables -- needs x2n_table[] */ + braid(crc_braid_table, crc_braid_big_table, N, W); +#endif + +#ifdef MAKECRCH + { + /* + The crc32.h header file contains tables for both 32-bit and 64-bit + z_word_t's, and so requires a 64-bit type be available. In that case, + z_word_t must be defined to be 64-bits. This code then also generates + and writes out the tables for the case that z_word_t is 32 bits. + */ +#if !defined(W) || W != 8 +# error Need a 64-bit integer type in order to generate crc32.h. +#endif + FILE *out; + int k, n; + z_crc_t ltl[8][256]; + z_word_t big[8][256]; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + + /* write out little-endian CRC table to crc32.h */ + fprintf(out, + "/* crc32.h -- tables for rapid CRC calculation\n" + " * Generated automatically by crc32.c\n */\n" + "\n" + "local const z_crc_t FAR crc_table[] = {\n" + " "); + write_table(out, crc_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#ifdef W\n" + "\n" + "#if W == 8\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table64(out, crc_big_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table32hi(out, crc_big_table, 256); + fprintf(out, + "};\n" + "\n" + "#endif\n"); + + /* write out braid tables for each value of N */ + for (n = 1; n <= 6; n++) { + fprintf(out, + "\n" + "#if N == %d\n", n); + + /* compute braid tables for this N and 64-bit word_t */ + braid(ltl, big, n, 8); + + /* write out braid tables for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#if W == 8\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table64(out, big[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n"); + + /* compute braid tables for this N and 32-bit word_t */ + braid(ltl, big, n, 4); + + /* write out braid tables for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table32hi(out, big[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "#endif\n" + "\n" + "#endif\n"); + } + fprintf(out, + "\n" + "#endif\n"); + + /* write out zeros operator table to crc32.h */ + fprintf(out, + "\n" + "local const z_crc_t FAR x2n_table[] = {\n" + " "); + write_table(out, x2n_table, 32); + fprintf(out, + "};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH + +/* + Write the 32-bit values in table[0..k-1] to out, five per line in + hexadecimal separated by commas. + */ +local void write_table(FILE *out, const z_crc_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the high 32-bits of each value in table[0..k-1] to out, five per line + in hexadecimal separated by commas. + */ +local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n] >> 32), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the 64-bit values in table[0..k-1] to out, three per line in + hexadecimal separated by commas. This assumes that if there is a 64-bit + type, then there is also a long long integer type, and it is at least 64 + bits. If not, then the type cast and format string can be adjusted + accordingly. + */ +local void write_table64(FILE *out, const z_word_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ", + (unsigned long long)(table[n]), + n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); +} + +/* Actually do the deed. */ +int main(void) { + make_crc_table(); + return 0; +} + +#endif /* MAKECRCH */ + +#ifdef W +/* + Generate the little and big-endian braid tables for the given n and z_word_t + size w. Each array must have room for w blocks of 256 elements. + */ +local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { + int k; + z_crc_t i, p, q; + for (k = 0; k < w; k++) { + p = x2nmodp((n * w + 3 - k) << 3, 0); + ltl[k][0] = 0; + big[w - 1 - k][0] = 0; + for (i = 1; i < 256; i++) { + ltl[k][i] = q = multmodp(i << 24, p); + big[w - 1 - k][i] = byte_swap(q); + } + } +} +#endif + +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32(), and to force the + * generation of the CRC tables in a threaded application. + */ +const z_crc_t FAR * ZEXPORT get_crc_table(void) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +/* ========================================================================= + * Use ARM machine instructions if available. This will compute the CRC about + * ten times faster than the braided calculation. This code does not check for + * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will + * only be defined if the compilation specifies an ARM processor architecture + * that has the instructions. For example, compiling with -march=armv8.1-a or + * -march=armv8-a+crc, or -march=native if the compile machine has the crc32 + * instructions. + */ +#ifdef ARMCRC32 + +/* + Constants empirically determined to maximize speed. These values are from + measurements on a Cortex-A57. Your mileage may vary. + */ +#define Z_BATCH 3990 /* number of words in a batch */ +#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ +#define Z_BATCH_MIN 800 /* fewest words in a final batch */ + +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { + z_crc_t val; + z_word_t crc1, crc2; + const z_word_t *word; + z_word_t val0, val1, val2; + z_size_t last, last2, i; + z_size_t num; + + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + + /* Compute the CRC up to a word boundary. */ + while (len && ((z_size_t)buf & 7) != 0) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */ + word = (z_word_t const *)buf; + num = len >> 3; + len &= 7; + + /* Do three interleaved CRCs to realize the throughput of one crc32x + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ + while (num >= 3 * Z_BATCH) { + crc1 = 0; + crc2 = 0; + for (i = 0; i < Z_BATCH; i++) { + val0 = word[i]; + val1 = word[i + Z_BATCH]; + val2 = word[i + 2 * Z_BATCH]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * Z_BATCH; + num -= 3 * Z_BATCH; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2; + } + + /* Do one last smaller batch with the remaining words, if there are enough + to pay for the combination of CRCs. */ + last = num / 3; + if (last >= Z_BATCH_MIN) { + last2 = last << 1; + crc1 = 0; + crc2 = 0; + for (i = 0; i < last; i++) { + val0 = word[i]; + val1 = word[i + last]; + val2 = word[i + last2]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * last; + num -= 3 * last; + val = x2nmodp(last, 6); + crc = multmodp(val, crc) ^ crc1; + crc = multmodp(val, crc) ^ crc2; + } + + /* Compute the CRC on any remaining words. */ + for (i = 0; i < num; i++) { + val0 = word[i]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + } + word += num; + + /* Complete the CRC on any remaining bytes. */ + buf = (const unsigned char FAR *)word; + while (len) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#else + +#ifdef W + +/* + Return the CRC of the W bytes in the word_t data, taking the + least-significant byte of the word as the first byte of data, without any pre + or post conditioning. This is used to combine the CRCs of each braid. + */ +local z_crc_t crc_word(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data >> 8) ^ crc_table[data & 0xff]; + return (z_crc_t)data; +} + +local z_word_t crc_word_big(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data << 8) ^ + crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; + return data; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + +#ifdef W + + /* If provided enough bytes, do a braided CRC calculation. */ + if (len >= N * W + W - 1) { + z_size_t blks; + z_word_t const *words; + unsigned endian; + int k; + + /* Compute the CRC up to a z_word_t boundary. */ + while (len && ((z_size_t)buf & (W - 1)) != 0) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Compute the CRC on as many N z_word_t blocks as are available. */ + blks = len / (N * W); + len -= blks * N * W; + words = (z_word_t const *)buf; + + /* Do endian check at execution time instead of compile time, since ARM + processors can change the endianness at execution time. If the + compiler knows what the endianness will be, it can optimize out the + check and the unused branch. */ + endian = 1; + if (*(unsigned char *)&endian) { + /* Little endian. */ + + z_crc_t crc0; + z_word_t word0; +#if N > 1 + z_crc_t crc1; + z_word_t word1; +#if N > 2 + z_crc_t crc2; + z_word_t word2; +#if N > 3 + z_crc_t crc3; + z_word_t word3; +#if N > 4 + z_crc_t crc4; + z_word_t word4; +#if N > 5 + z_crc_t crc5; + z_word_t word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = crc; +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + crc = crc_word(crc0 ^ words[0]); +#if N > 1 + crc = crc_word(crc1 ^ words[1] ^ crc); +#if N > 2 + crc = crc_word(crc2 ^ words[2] ^ crc); +#if N > 3 + crc = crc_word(crc3 ^ words[3] ^ crc); +#if N > 4 + crc = crc_word(crc4 ^ words[4] ^ crc); +#if N > 5 + crc = crc_word(crc5 ^ words[5] ^ crc); +#endif +#endif +#endif +#endif +#endif + words += N; + } + else { + /* Big endian. */ + + z_word_t crc0, word0, comb; +#if N > 1 + z_word_t crc1, word1; +#if N > 2 + z_word_t crc2, word2; +#if N > 3 + z_word_t crc3, word3; +#if N > 4 + z_word_t crc4, word4; +#if N > 5 + z_word_t crc5, word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = byte_swap(crc); +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_big_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_big_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_big_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_big_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_big_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_big_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + comb = crc_word_big(crc0 ^ words[0]); +#if N > 1 + comb = crc_word_big(crc1 ^ words[1] ^ comb); +#if N > 2 + comb = crc_word_big(crc2 ^ words[2] ^ comb); +#if N > 3 + comb = crc_word_big(crc3 ^ words[3] ^ comb); +#if N > 4 + comb = crc_word_big(crc4 ^ words[4] ^ comb); +#if N > 5 + comb = crc_word_big(crc5 ^ words[5] ^ comb); +#endif +#endif +#endif +#endif +#endif + words += N; + crc = byte_swap(comb); + } + + /* + Update the pointer to the remaining bytes to process. + */ + buf = (unsigned char const *)words; + } + +#endif /* W */ + + /* Complete the computation of the CRC on any remaining bytes. */ + while (len >= 8) { + len -= 8; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + while (len) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, + uInt len) { + return crc32_z(crc, buf, len); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { + return crc32_combine64(crc1, crc2, (z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return x2nmodp(len2, 3); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen(z_off_t len2) { + return crc32_combine_gen64((z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) { + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); +} diff --git a/widget/milsko/milskosrc/external/libz/src/deflate.c b/widget/milsko/milskosrc/external/libz/src/deflate.c new file mode 100644 index 0000000000..012ea8148e --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/deflate.c @@ -0,0 +1,2139 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://tools.ietf.org/html/rfc1951 + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func)(deflate_state *s, int flush); +/* Compression function. Returns the block state after the call. */ + +local block_state deflate_stored(deflate_state *s, int flush); +local block_state deflate_fast(deflate_state *s, int flush); +#ifndef FASTEST +local block_state deflate_slow(deflate_state *s, int flush); +#endif +local block_state deflate_rle(deflate_state *s, int flush); +local block_state deflate_huff(deflate_state *s, int flush); + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to UPDATE_HASH are made with consecutive input + * characters, so that a running hash key can be computed from the previous + * key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + do { \ + s->head[s->hash_size - 1] = NIL; \ + zmemzero((Bytef *)s->head, \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ + } while (0) + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __attribute__((no_sanitize("memory"))) +# endif +#endif +local void slide_hash(deflate_state *s) { + unsigned n, m; + Posf *p; + uInt wsize = s->w_size; + + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + } while (--n); + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) { + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(deflate_state *s) { + unsigned n; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize + MAX_DIST(s)) { + + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + if (s->insert > s->strstart) + s->insert = s->strstart; + slide_hash(s); + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + +/* ========================================================================= */ +int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, + int stream_size) { + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, int strategy, + const char *version, int stream_size) { + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + s->status = INIT_STATE; /* to pass state test in deflateReset() */ + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = (uInt)windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = (uInt)memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + /* We overlay pending_buf and sym_buf. This works since the average size + * for length/distance pairs over any compressed block is assured to be 31 + * bits or less. + * + * Analysis: The longest fixed codes are a length code of 8 bits plus 5 + * extra bits, for lengths 131 to 257. The longest fixed distance codes are + * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest + * possible fixed-codes length/distance pair is then 31 bits total. + * + * sym_buf starts one-fourth of the way into pending_buf. So there are + * three bytes in sym_buf for every four bytes in pending_buf. Each symbol + * in sym_buf is three bytes -- two for the distance and one for the + * literal/length. As each symbol is consumed, the pointer to the next + * sym_buf value to read moves forward three bytes. From that symbol, up to + * 31 bits are written to pending_buf. The closest the written pending_buf + * bits gets to the next sym_buf symbol to read is just before the last + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 + * symbols are written.) The closest the writing gets to what is unread is + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and + * can range from 128 to 32768. + * + * Therefore, at a minimum, there are 142 bits of space between what is + * written and what is read in the overlain buffers, so the symbols cannot + * be overwritten by the compressed data. That space is actually 139 bits, + * due to the three-bit fixed-code block header. + * + * That covers the case where either Z_FIXED is specified, forcing fixed + * codes, or when the use of fixed codes is chosen, because that choice + * results in a smaller compressed block than dynamic codes. That latter + * condition then assures that the above analysis also covers all dynamic + * blocks. A dynamic-code block will only be chosen to be emitted if it has + * fewer bits than a fixed-code block would for the same set of symbols. + * Therefore its average symbol length is assured to be less than 31. So + * the compressed data for a dynamic block also cannot overwrite the + * symbols from which it is being constructed. + */ + + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS); + s->pending_buf_size = (ulg)s->lit_bufsize * 4; + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } +#ifdef LIT_MEM + s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1)); + s->l_buf = s->pending_buf + (s->lit_bufsize << 2); + s->sym_end = s->lit_bufsize - 1; +#else + s->sym_buf = s->pending_buf + s->lit_bufsize; + s->sym_end = (s->lit_bufsize - 1) * 3; +#endif + /* We avoid equality with lit_bufsize*3 because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +local int deflateStateCheck(z_streamp strm) { + deflate_state *s; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + s = strm->state; + if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && +#ifdef GZIP + s->status != GZIP_STATE && +#endif + s->status != EXTRA_STATE && + s->status != NAME_STATE && + s->status != COMMENT_STATE && + s->status != HCRC_STATE && + s->status != BUSY_STATE && + s->status != FINISH_STATE)) + return 1; + return 0; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { + deflate_state *s; + uInt str, n; + int wrap; + unsigned avail; + z_const unsigned char *next; + + if (deflateStateCheck(strm) || dictionary == Z_NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; + } + + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); + } + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { + deflate_state *s; + uInt len; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + len = s->strstart + s->lookahead; + if (len > s->w_size) + len = s->w_size; + if (dictionary != Z_NULL && len) + zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != Z_NULL) + *dictLength = len; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateResetKeep(z_streamp strm) { + deflate_state *s; + + if (deflateStateCheck(strm)) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = +#ifdef GZIP + s->wrap == 2 ? GZIP_STATE : +#endif + INIT_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = -2; + + _tr_init(s); + + return Z_OK; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init(deflate_state *s) { + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset(z_streamp strm) { + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) { + if (deflateStateCheck(strm) || strm->state->wrap != 2) + return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) { + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { + deflate_state *s; + int put; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; +#ifdef LIT_MEM + if (bits < 0 || bits > 16 || + (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; +#else + if (bits < 0 || bits > 16 || + s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; +#endif + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) { + deflate_state *s; + compress_func func; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + s->last_flush != -2) { + /* Flush the last buffer: */ + int err = deflate(strm, Z_BLOCK); + if (err == Z_STREAM_ERROR) + return err; + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) + return Z_BUF_ERROR; + } + if (s->level != level) { + if (s->level == 0 && s->matches != 0) { + if (s->matches == 1) + slide_hash(s); + else + CLEAR_HASH(s); + s->matches = 0; + } + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, + int nice_length, int max_chain) { + deflate_state *s; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = (uInt)good_length; + s->max_lazy_match = (uInt)max_lazy; + s->nice_match = nice_length; + s->max_chain_length = (uInt)max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. + * + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. + * + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. + * + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. + */ +uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) { + deflate_state *s; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; + + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; + + /* if can't get parameters, return larger bound plus a zlib wrapper */ + if (deflateStateCheck(strm)) + return (fixedlen > storelen ? fixedlen : storelen) + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; +#ifdef GZIP + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + Bytef *str; + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; +#endif + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return one of the conservative bounds */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + + wraplen; + + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB(deflate_state *s, uInt b) { + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). + */ +local void flush_pending(z_streamp strm) { + unsigned len; + deflate_state *s = strm->state; + + _tr_flush_bits(s); + len = s->pending; + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* =========================================================================== + * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. + */ +#define HCRC_UPDATE(beg) \ + do { \ + if (s->gzhead->hcrc && s->pending > (beg)) \ + strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ + s->pending - (beg)); \ + } while (0) + +/* ========================================================================= */ +int ZEXPORT deflate(z_streamp strm, int flush) { + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->avail_in != 0 && strm->next_in == Z_NULL) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + old_flush = s->last_flush; + s->last_flush = flush; + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Write the header */ + if (s->status == INIT_STATE && s->wrap == 0) + s->status = BUSY_STATE; + if (s->status == INIT_STATE) { + /* zlib header */ + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#ifdef GZIP + if (s->status == GZIP_STATE) { + /* gzip header */ + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; + while (s->pending + left > s->pending_buf_size) { + uInt copy = s->pending_buf_size - s->pending; + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, copy); + s->pending = s->pending_buf_size; + HCRC_UPDATE(beg); + s->gzindex += copy; + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + left -= copy; + } + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, left); + s->pending += left; + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + } + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) { + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + } + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#endif + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->level == 0 ? deflate_stored(s, flush) : + s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd(z_streamp strm) { + int status; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + + status = strm->state->status; + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { +#ifdef MAXSEG_64K + (void)dest; + (void)source; + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + + + if (deflateStateCheck(source) || dest == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS); + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); +#ifdef LIT_MEM + ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1)); + ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2); +#else + ds->sym_buf = ds->pending_buf + ds->lit_bufsize; +#endif + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +local uInt longest_match(deflate_state *s, IPos cur_match) { + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = (int)s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan + best_len - 1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len - 1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match + best_len - 1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart + 3, + 5, up to strstart + 257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend - scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len - 1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart + 258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan + best_len - 1); +#else + scan_end1 = scan[best_len - 1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(deflate_state *s, IPos cur_match) { + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len - 1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart + 258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef ZLIB_DEBUG + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(deflate_state *s, IPos start, IPos match, int length) { + /* check that the match is indeed a match */ + Bytef *back = s->window + (int)match, *here = s->window + start; + IPos len = length; + if (match == (IPos)-1) { + /* match starts one byte before the current window -- just compare the + subsequent length-1 bytes */ + back++; + here++; + len--; + } + if (zmemcmp(back, here, len) != EQUAL) { + fprintf(stderr, " start %u, match %d, length %d\n", + start, (int)match, length); + do { + fprintf(stderr, "(%02x %02x)", *back++, *here++); + } while (--len != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start - match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* ZLIB_DEBUG */ + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunities to have a single copy from next_in to next_out. + */ +local block_state deflate_stored(deflate_state *s, int flush) { + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. + */ + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); + + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. + */ + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = s->strstart - s->block_start; /* bytes left in window */ + if (len > (ulg)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + if (len > have) + len = have; /* limit len to the output */ + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || + flush == Z_NO_FLUSH || + len != left + s->strm->avail_in)) + break; + + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ + s->pending_buf[s->pending - 4] = len; + s->pending_buf[s->pending - 3] = len >> 8; + s->pending_buf[s->pending - 2] = ~len; + s->pending_buf[s->pending - 1] = ~len >> 8; + + /* Write the stored block header bytes. */ + flush_pending(s->strm); + +#ifdef ZLIB_DEBUG + /* Update debugging counts for the data about to be copied. */ + s->compressed_len += len << 3; + s->bits_sent += len << 3; +#endif + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) + left = len; + zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += left; + len -= left; + } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + read_buf(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; + } + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + s->insert = s->strstart; + } + else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + s->insert += MIN(used, s->w_size - s->insert); + } + s->block_start = s->strstart; + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* If the last block was written to next_out, then done. */ + if (last) + return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && + s->strm->avail_in == 0 && (long)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart; + if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { + /* Slide the window down. */ + s->block_start -= s->w_size; + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + if (have > s->strm->avail_in) + have = s->strm->avail_in; + if (have) { + read_buf(s->strm, s->window + s->strstart, have); + s->strstart += have; + s->insert += MIN(have, s->w_size - s->insert); + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = s->strstart - s->block_start; + if (left >= min_block || + ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && + s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && + len == left ? 1 : 0; + _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); + s->block_start += len; + flush_pending(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(deflate_state *s, int flush) { + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart + 2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(deflate_state *s, int flush) { + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart + 2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart - 1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length - 1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); + s->match_available = 0; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(deflate_state *s, int flush) { + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= MAX_MATCH) { + fill_window(s); + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (uInt)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(deflate_state *s, int flush) { + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/widget/milsko/milskosrc/external/libz/src/gzclose.c b/widget/milsko/milskosrc/external/libz/src/gzclose.c new file mode 100644 index 0000000000..48d6a86f04 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/gzclose.c @@ -0,0 +1,23 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(gzFile file) { +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/widget/milsko/milskosrc/external/libz/src/gzlib.c b/widget/milsko/milskosrc/external/libz/src/gzlib.c new file mode 100644 index 0000000000..983153cc8e --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/gzlib.c @@ -0,0 +1,582 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_WIN32) && !defined(__BORLANDC__) +# define LSEEK _lseeki64 +#else +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif +#endif + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror(DWORD error) { + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(gz_statep state) { + state->x.have = 0; /* no output data available */ + if (state->mode == GZ_READ) { /* for reading ... */ + state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ + state->how = LOOK; /* look for gzip header */ + } + else /* for writing ... */ + state->reset = 0; /* no deflateReset pending */ + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->x.pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(const void *path, int fd, const char *mode) { + gz_statep state; + z_size_t len; + int oflag; +#ifdef O_CLOEXEC + int cloexec = 0; +#endif +#ifdef O_EXCL + int exclusive = 0; +#endif + + /* check input */ + if (path == NULL) + return NULL; + + /* allocate gzFile structure to return */ + state = (gz_statep)malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; +#ifdef O_CLOEXEC + case 'e': + cloexec = 1; + break; +#endif +#ifdef O_EXCL + case 'x': + exclusive = 1; + break; +#endif + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + break; + case 'T': + state->direct = 1; + break; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + + /* save the path name for error messages */ +#ifdef WIDECHAR + if (fd == -2) { + len = wcstombs(NULL, path, 0); + if (len == (z_size_t)-1) + len = 0; + } + else +#endif + len = strlen((const char *)path); + state->path = (char *)malloc(len + 1); + if (state->path == NULL) { + free(state); + return NULL; + } +#ifdef WIDECHAR + if (fd == -2) + if (len) + wcstombs(state->path, path, len + 1); + else + *(state->path) = 0; + else +#endif +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->path, len + 1, "%s", (const char *)path); +#else + strcpy(state->path, path); +#endif + + /* compute the flags for open() */ + oflag = +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif +#ifdef O_CLOEXEC + (cloexec ? O_CLOEXEC : 0) | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | +#ifdef O_EXCL + (exclusive ? O_EXCL : 0) | +#endif + (state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))); + + /* open the file with the appropriate flags (or just use fd) */ + state->fd = fd > -1 ? fd : ( +#ifdef WIDECHAR + fd == -2 ? _wopen(path, oflag, 0666) : +#endif + open((const char *)path, oflag, 0666)); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) { + LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ + state->mode = GZ_WRITE; /* simplify later checks */ + } + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(const char *path, const char *mode) { + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(const char *path, const char *mode) { + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(int fd, const char *mode) { + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); +#else + sprintf(path, "", fd); /* for debugging */ +#endif + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +#ifdef WIDECHAR +gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) { + return gz_open(path, -2, mode); +} +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(gzFile file, unsigned size) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if ((size << 1) < size) + return -1; /* need to be able to double it */ + if (size < 8) + size = 8; /* needed to behave well with flushing */ + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(gzFile file) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) { + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->x.pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); + if (ret == -1) + return -1; + state->x.have = 0; + state->eof = 0; + state->past = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->x.pos += offset; + return state->x.pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->x.pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->x.pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) { + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(gzFile file) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->x.pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(gzFile file) { + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(gzFile file) { + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(gzFile file) { + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(gzFile file) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? state->past : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(gzFile file, int *errnum) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->err == Z_MEM_ERROR ? "out of memory" : + (state->msg == NULL ? "" : state->msg); +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(gzFile file) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) { + state->eof = 0; + state->past = 0; + } + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) { + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, return literal string when requested */ + if (err == Z_MEM_ERROR) + return; + + /* construct error message with path */ + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == + NULL) { + state->err = Z_MEM_ERROR; + return; + } +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); +#else + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); +#endif +} + +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax(void) { +#ifdef INT_MAX + return INT_MAX; +#else + unsigned p = 1, q; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +#endif +} diff --git a/widget/milsko/milskosrc/external/libz/src/gzread.c b/widget/milsko/milskosrc/external/libz/src/gzread.c new file mode 100644 index 0000000000..4168cbc887 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/gzread.c @@ -0,0 +1,602 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(gz_statep state, unsigned char *buf, unsigned len, + unsigned *have) { + int ret; + unsigned get, max = ((unsigned)-1 >> 2) + 1; + + *have = 0; + do { + get = len - *have; + if (get > max) + get = max; + ret = read(state->fd, buf + *have, get); + if (ret <= 0) + break; + *have += (unsigned)ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ +local int gz_avail(gz_statep state) { + unsigned got; + z_streamp strm = &(state->strm); + + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + if (state->eof == 0) { + if (strm->avail_in) { /* copy what's there to the start */ + unsigned char *p = state->in; + unsigned const char *q = strm->next_in; + unsigned n = strm->avail_in; + do { + *p++ = *q++; + } while (--n); + } + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) + return -1; + strm->avail_in += got; + strm->next_in = state->in; + } + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression. If direct copying, then leftover input + data from the input buffer will be copied to the output buffer. In that + case, all further file reads will be directly to either the output buffer or + a user buffer. If decompressing, the inflate state will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +local int gz_look(gz_statep state) { + z_streamp strm = &(state->strm); + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = (unsigned char *)malloc(state->want); + state->out = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + inflateReset(strm); + state->how = GZIP; + state->direct = 0; + return 0; + } + + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, copy any leftover input to output -- this assumes that + the output buffer is larger than the input buffer, which also assures + space for gzungetc() */ + state->x.next = state->out; + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ +local int gz_decomp(gz_statep state) { + int ret = Z_OK; + unsigned had; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); + break; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; + + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; + + /* good decompression */ + return 0; +} + +/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +local int gz_fetch(gz_statep state) { + z_streamp strm = &(state->strm); + + do { + switch(state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; + return 0; + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(gz_statep state, z_off64_t len) { + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + } + return 0; +} + +/* Read len bytes into buf from file, or less than len up to the end of the + input. Return the number of bytes read. If zero is returned, either the + end of file was reached, or there was an error. state->err must be + consulted in that case to determine which. */ +local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { + z_size_t got; + unsigned n; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return 0; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* set n to the maximum amount of len that fits in an unsigned int */ + n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + + /* first just try copying data from the output buffer */ + if (state->x.have) { + if (state->x.have < n) + n = state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) { + state->past = 1; /* tried to read past end */ + break; + } + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || n < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return 0; + continue; /* no progress yet -- go back to copy above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, (unsigned char *)buf, n, &n) == -1) + return 0; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + state->strm.avail_out = n; + state->strm.next_out = (unsigned char *)buf; + if (gz_decomp(state) == -1) + return 0; + n = state->x.have; + state->x.have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->x.pos += n; + } while (len); + + /* return number of bytes read into user buffer */ + return got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); + return -1; + } + + /* read len or fewer bytes to buf */ + len = (unsigned)gz_read(state, buf, len); + + /* check for an error */ + if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* return the number of bytes read (this is assured to fit in an int) */ + return (int)len; +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) { + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* read len or fewer bytes to buf, return the number of full items read */ + return len ? gz_read(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +#else +# undef gzgetc +#endif +int ZEXPORT gzgetc(gzFile file) { + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; + } + + /* nothing there -- try gz_read() */ + return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; +} + +int ZEXPORT gzgetc_(gzFile file) { + return gzgetc(file); +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(int c, gzFile file) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* in case this was just opened, set up the input buffer */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->x.next = dest; + } + state->x.have++; + state->x.next--; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(gzFile file, char *buf, int len) { + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } + + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(gzFile file) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* return 1 if transparent, 0 if processing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(gzFile file) { + int ret, err; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : err; +} diff --git a/widget/milsko/milskosrc/external/libz/src/gzwrite.c b/widget/milsko/milskosrc/external/libz/src/gzwrite.c new file mode 100644 index 0000000000..435b4621b5 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/gzwrite.c @@ -0,0 +1,631 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on a memory allocation failure, or 0 on + success. */ +local int gz_init(gz_statep state) { + int ret; + z_streamp strm = &(state->strm); + + /* allocate input buffer (double size for gzprintf) */ + state->in = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)malloc(state->want); + if (state->out == NULL) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + strm->next_in = NULL; + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = strm->next_out; + } + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file or if gz_init() + fails to allocate memory, otherwise 0. flush is assumed to be a valid + deflate() flush value. If flush is Z_FINISH, then the deflate() state is + reset to start a new gzip stream. If gz->direct is true, then simply write + to the output file without compressing, and ignore flush. */ +local int gz_comp(gz_statep state, int flush) { + int ret, writ; + unsigned have, put, max = ((unsigned)-1 >> 2) + 1; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* write directly if requested */ + if (state->direct) { + while (strm->avail_in) { + put = strm->avail_in > max ? max : strm->avail_in; + writ = write(state->fd, strm->next_in, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in -= (unsigned)writ; + strm->next_in += writ; + } + return 0; + } + + /* check for a pending reset */ + if (state->reset) { + /* don't start a new gzip member unless there is data to write */ + if (strm->avail_in == 0) + return 0; + deflateReset(strm); + state->reset = 0; + } + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + while (strm->next_out > state->x.next) { + put = strm->next_out - state->x.next > (int)max ? max : + (unsigned)(strm->next_out - state->x.next); + writ = write(state->fd, state->x.next, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + state->x.next += writ; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = state->out; + } + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + state->reset = 1; + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on a write error or memory + allocation failure by gz_comp(), or 0 on success. */ +local int gz_zero(gz_statep state, z_off64_t len) { + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* Write len bytes from buf to file. Return the number of bytes written. If + the returned value is less than len, then there was an error. */ +local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) { + z_size_t put = len; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + unsigned have, copy; + + if (state->strm.avail_in == 0) + state->strm.next_in = state->in; + have = (unsigned)((state->strm.next_in + state->strm.avail_in) - + state->in); + copy = state->size - have; + if (copy > len) + copy = (unsigned)len; + memcpy(state->in + have, buf, copy); + state->strm.avail_in += copy; + state->x.pos += copy; + buf = (const char *)buf + copy; + len -= copy; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + state->strm.next_in = (z_const Bytef *)buf; + do { + unsigned n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + state->strm.avail_in = n; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + len -= n; + } while (len); + } + + /* input was all buffered or compressed */ + return put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* write len bytes from buf (the return value will fit in an int) */ + return (int)gz_write(state, buf, len); +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems, + gzFile file) { + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* write len bytes to buf, return the number of full items written */ + return len ? gz_write(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(gzFile file, int c) { + unsigned have; + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (have < state->size) { + state->in[have] = (unsigned char)c; + strm->avail_in++; + state->x.pos++; + return c & 0xff; + } + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = (unsigned char)c; + if (gz_write(state, buf, 1) != 1) + return -1; + return c & 0xff; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(gzFile file, const char *s) { + z_size_t len, put; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* write string */ + len = strlen(s); + if ((int)len < 0 || (unsigned)len != len) { + gz_error(state, Z_STREAM_ERROR, "string length does not fit in int"); + return -1; + } + put = gz_write(state, s, len); + return put < len ? -1 : (int)len; +} + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { + int len; + unsigned left; + char *next; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->err; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(next, format, va); + for (len = 0; len < state->size; len++) + if (next[len] == 0) break; +# else + len = vsprintf(next, format, va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(next, state->size, format, va); + len = strlen(next); +# else + len = vsnprintf(next, state->size, format, va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += (unsigned)len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memmove(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return len; +} + +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { + va_list va; + int ret; + + va_start(va, format); + ret = gzvprintf(file, format, va); + va_end(va); + return ret; +} + +#else /* !STDC && !Z_HAVE_STDARG_H */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3, + int a4, int a5, int a6, int a7, int a8, int a9, int a10, + int a11, int a12, int a13, int a14, int a15, int a16, + int a17, int a18, int a19, int a20) { + unsigned len, left; + char *next; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return Z_STREAM_ERROR; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->error; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->error; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(strm->next_in + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (next[len] == 0) + break; +# else + len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(next); +# else + len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memmove(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return (int)len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(gzFile file, int flush) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* compress remaining data with requested flush */ + (void)gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(gzFile file, int level, int strategy) { + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(gzFile file) { + int ret = Z_OK; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + ret = state->err; + } + + /* flush, free memory, and close file */ + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (state->size) { + if (!state->direct) { + (void)deflateEnd(&(state->strm)); + free(state->out); + } + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + if (close(state->fd) == -1) + ret = Z_ERRNO; + free(state); + return ret; +} diff --git a/widget/milsko/milskosrc/external/libz/src/infback.c b/widget/milsko/milskosrc/external/libz/src/infback.c new file mode 100644 index 0000000000..e7b25b307a --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/infback.c @@ -0,0 +1,628 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, const char *version, + int stream_size) { + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = (uInt)windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + state->sane = 1; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(struct inflate_state FAR *state) { +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc) { + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + /* fallthrough */ + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly */ + ret = Z_STREAM_END; + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: + /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Write leftover output and return unused input */ + inf_leave: + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left) && + ret == Z_STREAM_END) + ret = Z_BUF_ERROR; + } + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(z_streamp strm) { + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/widget/milsko/milskosrc/external/libz/src/inffast.c b/widget/milsko/milskosrc/external/libz/src/inffast.c new file mode 100644 index 0000000000..9354676e78 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/inffast.c @@ -0,0 +1,320 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) { + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code const *here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - 5); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode + (hold & lmask); + dolen: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op == 0) { /* literal */ + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = dcode + (hold & dmask); + dodist: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode + here->val + (hold & ((1U << op) - 1)); + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode + here->val + (hold & ((1U << op) - 1)); + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/widget/milsko/milskosrc/external/libz/src/inflate.c b/widget/milsko/milskosrc/external/libz/src/inflate.c new file mode 100644 index 0000000000..94ecff015a --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/inflate.c @@ -0,0 +1,1526 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +local int inflateStateCheck(z_streamp strm) { + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int ZEXPORT inflateResetKeep(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->flags = -1; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(z_streamp strm, int windowBits) { + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size) { + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->strm = strm; + state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(z_streamp strm, const char *version, + int stream_size) { + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + if (bits == 0) + return Z_OK; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(struct inflate_state FAR *state) { +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed(void) +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) { + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE_CHECK(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(z_streamp strm, int flush) { + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + /* fallthrough */ + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + /* fallthrough */ + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + /* fallthrough */ + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + /* fallthrough */ + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + /* fallthrough */ + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + /* fallthrough */ + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + /* fallthrough */ + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + /* fallthrough */ + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + /* fallthrough */ + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case COPY_: + state->mode = COPY; + /* fallthrough */ + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + /* fallthrough */ + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + /* fallthrough */ + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case LEN_: + state->mode = LEN; + /* fallthrough */ + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + /* fallthrough */ + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + /* fallthrough */ + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + /* fallthrough */ + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + /* fallthrough */ + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, put - out, out); + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + /* fallthrough */ + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + /* fallthrough */ + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* fallthrough */ + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, strm->next_out - out, out); + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(z_streamp strm) { + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) { + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, + unsigned len) { + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(z_streamp strm) { + unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold >>= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->flags = flags; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) { + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(z_streamp strm, int subvert) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +int ZEXPORT inflateValidate(z_streamp strm, int check) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check && state->wrap) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/widget/milsko/milskosrc/external/libz/src/inftrees.c b/widget/milsko/milskosrc/external/libz/src/inftrees.c new file mode 100644 index 0000000000..98cfe16445 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/inftrees.c @@ -0,0 +1,299 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.3.1 Copyright 1995-2024 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work) { + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/widget/milsko/milskosrc/external/libz/src/trees.c b/widget/milsko/milskosrc/external/libz/src/trees.c new file mode 100644 index 0000000000..6a523ef34e --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/trees.c @@ -0,0 +1,1117 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2024 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef ZLIB_DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +#ifdef NO_INIT_GLOBAL_POINTERS +# define TCONST +#else +# define TCONST const +#endif + +local TCONST static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local TCONST static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local TCONST static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(unsigned code, int len) { + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(deflate_state *s) { + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(deflate_state *s) { + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent + 7) & ~7; +#endif +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) { + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = (ush)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); + } +} + +#ifdef GEN_TREES_H +local void gen_trees_header(void); +#endif + +#ifndef ZLIB_DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* !ZLIB_DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef ZLIB_DEBUG +local void send_bits(deflate_state *s, int value, int length) { + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !ZLIB_DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = (int)value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* ZLIB_DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init(void) { +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + _length_code[length++] = (uch)code; + } + } + Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length - 1] = (uch)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + _dist_code[dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Generate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef ZLIB_DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) + +void gen_trees_header(void) { + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(deflate_state *s) { + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->sym_next = s->matches = 0; +} + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(deflate_state *s) { + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(deflate_state *s, ct_data *tree, int k) { + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(deflate_state *s, tree_desc *desc) { + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n - base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (unsigned)(bits + xbits); + if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); + } + if (overflow == 0) return; + + Tracev((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +#ifdef DUMP_BL_TREE +# include +#endif + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +local void build_tree(deflate_state *s, tree_desc *desc) { + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree(deflate_state *s, ct_data *tree, int max_code) { + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code + 1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree(deflate_state *s, ct_data *tree, int max_code) { + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code + 1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(deflate_state *s) { + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(deflate_state *s, int lcodes, int dcodes, + int blcodes) { + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ + bi_windup(s); /* align on byte boundary */ + put_short(s, (ush)stored_len); + put_short(s, (ush)~stored_len); + if (stored_len) + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + s->pending += stored_len; +#ifdef ZLIB_DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + s->bits_sent += 2*16; + s->bits_sent += stored_len << 3; +#endif +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) { + bi_flush(s); +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +void ZLIB_INTERNAL _tr_align(deflate_state *s) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef ZLIB_DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(deflate_state *s, const ct_data *ltree, + const ct_data *dtree) { + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned sx = 0; /* running index in symbol buffers */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->sym_next != 0) do { +#ifdef LIT_MEM + dist = s->d_buf[sx]; + lc = s->l_buf[sx++]; +#else + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; +#endif + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS + 1, ltree); /* send length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check for no overlay of pending_buf on needed symbols */ +#ifdef LIT_MEM + Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow"); +#else + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); +#endif + + } while (sx < s->sym_next); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "block list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(deflate_state *s) { + /* block_mask is the bit mask of block-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long block_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("block-listed") bytes. */ + for (n = 0; n <= 31; n++, block_mask >>= 1) + if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("allow-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "block-listed" or "allow-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and write out the encoded block. + */ +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->sym_next / 3)); + +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef ZLIB_DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { +#ifdef LIT_MEM + s->d_buf[s->sym_next] = (ush)dist; + s->l_buf[s->sym_next++] = (uch)lc; +#else + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; +#endif + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + return (s->sym_next == s->sym_end); +} diff --git a/widget/milsko/milskosrc/external/libz/src/uncompr.c b/widget/milsko/milskosrc/external/libz/src/uncompr.c new file mode 100644 index 0000000000..5e256663b4 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/uncompr.c @@ -0,0 +1,85 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. *sourceLen is + the byte length of the source buffer. Upon entry, *destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, + *destLen is the size of the decompressed data and *sourceLen is the number + of source bytes consumed. Upon return, source + *sourceLen points to the + first unused input byte. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, or + Z_DATA_ERROR if the input data was corrupted, including if the input data is + an incomplete zlib stream. +*/ +int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong *sourceLen) { + z_stream stream; + int err; + const uInt max = (uInt)-1; + uLong len, left; + Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ + + len = *sourceLen; + if (*destLen) { + left = *destLen; + *destLen = 0; + } + else { + left = 1; + dest = buf; + } + + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + stream.next_out = dest; + stream.avail_out = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = len > (uLong)max ? max : (uInt)len; + len -= stream.avail_in; + } + err = inflate(&stream, Z_NO_FLUSH); + } while (err == Z_OK); + + *sourceLen -= len + stream.avail_in; + if (dest != buf) + *destLen = stream.total_out; + else if (stream.total_out && err == Z_BUF_ERROR) + left = 1; + + inflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : + err == Z_NEED_DICT ? Z_DATA_ERROR : + err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : + err; +} + +int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen) { + return uncompress2(dest, destLen, source, &sourceLen); +} diff --git a/widget/milsko/milskosrc/external/libz/src/zutil.c b/widget/milsko/milskosrc/external/libz/src/zutil.c new file mode 100644 index 0000000000..b1c5d2d3c6 --- /dev/null +++ b/widget/milsko/milskosrc/external/libz/src/zutil.c @@ -0,0 +1,299 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + + +const char * ZEXPORT zlibVersion(void) { + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags(void) { + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif + /* +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif + */ +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +#include +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error(char *m) { + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(int err) { + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { + voidpf buf; + ulg bsize = (ulg)items*size; + + (void)opaque; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + int n; + + (void)opaque; + + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { + (void)opaque; + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + (void)opaque; + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc(uInt size); +extern voidp calloc(uInt items, uInt size); +extern void free(voidpf ptr); +#endif + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { + (void)opaque; + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + (void)opaque; + free(ptr); +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/widget/milsko/milskosrc/external/stb_ds.c b/widget/milsko/milskosrc/external/stb_ds.c new file mode 100644 index 0000000000..9df32fd7b7 --- /dev/null +++ b/widget/milsko/milskosrc/external/stb_ds.c @@ -0,0 +1,2 @@ +#define STB_DS_IMPLEMENTATION +#include "stb_ds.h" diff --git a/widget/milsko/milskosrc/external/stb_ds.h b/widget/milsko/milskosrc/external/stb_ds.h new file mode 100644 index 0000000000..e84c82d1d5 --- /dev/null +++ b/widget/milsko/milskosrc/external/stb_ds.h @@ -0,0 +1,1895 @@ +/* stb_ds.h - v0.67 - public domain data structures - Sean Barrett 2019 + + This is a single-header-file library that provides easy-to-use + dynamic arrays and hash tables for C (also works in C++). + + For a gentle introduction: + http://nothings.org/stb_ds + + To use this library, do this in *one* C or C++ file: + #define STB_DS_IMPLEMENTATION + #include "stb_ds.h" + +TABLE OF CONTENTS + + Table of Contents + Compile-time options + License + Documentation + Notes + Notes - Dynamic arrays + Notes - Hash maps + Credits + +COMPILE-TIME OPTIONS + + #define STBDS_NO_SHORT_NAMES + + This flag needs to be set globally. + + By default stb_ds exposes shorter function names that are not qualified + with the "stbds_" prefix. If these names conflict with the names in your + code, define this flag. + + #define STBDS_SIPHASH_2_4 + + This flag only needs to be set in the file containing #define STB_DS_IMPLEMENTATION. + + By default stb_ds.h hashes using a weaker variant of SipHash and a custom hash for + 4- and 8-byte keys. On 64-bit platforms, you can define the above flag to force + stb_ds.h to use specification-compliant SipHash-2-4 for all keys. Doing so makes + hash table insertion about 20% slower on 4- and 8-byte keys, 5% slower on + 64-byte keys, and 10% slower on 256-byte keys on my test computer. + + #define STBDS_REALLOC(context,ptr,size) better_realloc + #define STBDS_FREE(context,ptr) better_free + + These defines only need to be set in the file containing #define STB_DS_IMPLEMENTATION. + + By default stb_ds uses stdlib realloc() and free() for memory management. You can + substitute your own functions instead by defining these symbols. You must either + define both, or neither. Note that at the moment, 'context' will always be NULL. + @TODO add an array/hash initialization function that takes a memory context pointer. + + #define STBDS_UNIT_TESTS + + Defines a function stbds_unit_tests() that checks the functioning of the data structures. + + Note that on older versions of gcc (e.g. 5.x.x) you may need to build with '-std=c++0x' + (or equivalentally '-std=c++11') when using anonymous structures as seen on the web + page or in STBDS_UNIT_TESTS. + +LICENSE + + Placed in the public domain and also MIT licensed. + See end of file for detailed license information. + +DOCUMENTATION + + Dynamic Arrays + + Non-function interface: + + Declare an empty dynamic array of type T + T* foo = NULL; + + Access the i'th item of a dynamic array 'foo' of type T, T* foo: + foo[i] + + Functions (actually macros) + + arrfree: + void arrfree(T*); + Frees the array. + + arrlen: + ptrdiff_t arrlen(T*); + Returns the number of elements in the array. + + arrlenu: + size_t arrlenu(T*); + Returns the number of elements in the array as an unsigned type. + + arrpop: + T arrpop(T* a) + Removes the final element of the array and returns it. + + arrput: + T arrput(T* a, T b); + Appends the item b to the end of array a. Returns b. + + arrins: + T arrins(T* a, int p, T b); + Inserts the item b into the middle of array a, into a[p], + moving the rest of the array over. Returns b. + + arrinsn: + void arrinsn(T* a, int p, int n); + Inserts n uninitialized items into array a starting at a[p], + moving the rest of the array over. + + arraddnptr: + T* arraddnptr(T* a, int n) + Appends n uninitialized items onto array at the end. + Returns a pointer to the first uninitialized item added. + + arraddnindex: + size_t arraddnindex(T* a, int n) + Appends n uninitialized items onto array at the end. + Returns the index of the first uninitialized item added. + + arrdel: + void arrdel(T* a, int p); + Deletes the element at a[p], moving the rest of the array over. + + arrdeln: + void arrdeln(T* a, int p, int n); + Deletes n elements starting at a[p], moving the rest of the array over. + + arrdelswap: + void arrdelswap(T* a, int p); + Deletes the element at a[p], replacing it with the element from + the end of the array. O(1) performance. + + arrsetlen: + void arrsetlen(T* a, int n); + Changes the length of the array to n. Allocates uninitialized + slots at the end if necessary. + + arrsetcap: + size_t arrsetcap(T* a, int n); + Sets the length of allocated storage to at least n. It will not + change the length of the array. + + arrcap: + size_t arrcap(T* a); + Returns the number of total elements the array can contain without + needing to be reallocated. + + Hash maps & String hash maps + + Given T is a structure type: struct { TK key; TV value; }. Note that some + functions do not require TV value and can have other fields. For string + hash maps, TK must be 'char *'. + + Special interface: + + stbds_rand_seed: + void stbds_rand_seed(size_t seed); + For security against adversarially chosen data, you should seed the + library with a strong random number. Or at least seed it with time(). + + stbds_hash_string: + size_t stbds_hash_string(char *str, size_t seed); + Returns a hash value for a string. + + stbds_hash_bytes: + size_t stbds_hash_bytes(void *p, size_t len, size_t seed); + These functions hash an arbitrary number of bytes. The function + uses a custom hash for 4- and 8-byte data, and a weakened version + of SipHash for everything else. On 64-bit platforms you can get + specification-compliant SipHash-2-4 on all data by defining + STBDS_SIPHASH_2_4, at a significant cost in speed. + + Non-function interface: + + Declare an empty hash map of type T + T* foo = NULL; + + Access the i'th entry in a hash table T* foo: + foo[i] + + Function interface (actually macros): + + hmfree + shfree + void hmfree(T*); + void shfree(T*); + Frees the hashmap and sets the pointer to NULL. + + hmlen + shlen + ptrdiff_t hmlen(T*) + ptrdiff_t shlen(T*) + Returns the number of elements in the hashmap. + + hmlenu + shlenu + size_t hmlenu(T*) + size_t shlenu(T*) + Returns the number of elements in the hashmap. + + hmgeti + shgeti + hmgeti_ts + ptrdiff_t hmgeti(T*, TK key) + ptrdiff_t shgeti(T*, char* key) + ptrdiff_t hmgeti_ts(T*, TK key, ptrdiff_t tempvar) + Returns the index in the hashmap which has the key 'key', or -1 + if the key is not present. + + hmget + hmget_ts + shget + TV hmget(T*, TK key) + TV shget(T*, char* key) + TV hmget_ts(T*, TK key, ptrdiff_t tempvar) + Returns the value corresponding to 'key' in the hashmap. + The structure must have a 'value' field + + hmgets + shgets + T hmgets(T*, TK key) + T shgets(T*, char* key) + Returns the structure corresponding to 'key' in the hashmap. + + hmgetp + shgetp + hmgetp_ts + hmgetp_null + shgetp_null + T* hmgetp(T*, TK key) + T* shgetp(T*, char* key) + T* hmgetp_ts(T*, TK key, ptrdiff_t tempvar) + T* hmgetp_null(T*, TK key) + T* shgetp_null(T*, char *key) + Returns a pointer to the structure corresponding to 'key' in + the hashmap. Functions ending in "_null" return NULL if the key + is not present in the hashmap; the others return a pointer to a + structure holding the default value (but not the searched-for key). + + hmdefault + shdefault + TV hmdefault(T*, TV value) + TV shdefault(T*, TV value) + Sets the default value for the hashmap, the value which will be + returned by hmget/shget if the key is not present. + + hmdefaults + shdefaults + TV hmdefaults(T*, T item) + TV shdefaults(T*, T item) + Sets the default struct for the hashmap, the contents which will be + returned by hmgets/shgets if the key is not present. + + hmput + shput + TV hmput(T*, TK key, TV value) + TV shput(T*, char* key, TV value) + Inserts a pair into the hashmap. If the key is already + present in the hashmap, updates its value. + + hmputs + shputs + T hmputs(T*, T item) + T shputs(T*, T item) + Inserts a struct with T.key into the hashmap. If the struct is already + present in the hashmap, updates it. + + hmdel + shdel + int hmdel(T*, TK key) + int shdel(T*, char* key) + If 'key' is in the hashmap, deletes its entry and returns 1. + Otherwise returns 0. + + Function interface (actually macros) for strings only: + + sh_new_strdup + void sh_new_strdup(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate and free + each string key using realloc/free + + sh_new_arena + void sh_new_arena(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate each string + key to a string arena. Every string key ever used by this + hash table remains in the arena until the arena is freed. + Additionally, any key which is deleted and reinserted will + be allocated multiple times in the string arena. + +NOTES + + * These data structures are realloc'd when they grow, and the macro + "functions" write to the provided pointer. This means: (a) the pointer + must be an lvalue, and (b) the pointer to the data structure is not + stable, and you must maintain it the same as you would a realloc'd + pointer. For example, if you pass a pointer to a dynamic array to a + function which updates it, the function must return back the new + pointer to the caller. This is the price of trying to do this in C. + + * The following are the only functions that are thread-safe on a single data + structure, i.e. can be run in multiple threads simultaneously on the same + data structure + hmlen shlen + hmlenu shlenu + hmget_ts shget_ts + hmgeti_ts shgeti_ts + hmgets_ts shgets_ts + + * You iterate over the contents of a dynamic array and a hashmap in exactly + the same way, using arrlen/hmlen/shlen: + + for (i=0; i < arrlen(foo); ++i) + ... foo[i] ... + + * All operations except arrins/arrdel are O(1) amortized, but individual + operations can be slow, so these data structures may not be suitable + for real time use. Dynamic arrays double in capacity as needed, so + elements are copied an average of once. Hash tables double/halve + their size as needed, with appropriate hysteresis to maintain O(1) + performance. + +NOTES - DYNAMIC ARRAY + + * If you know how long a dynamic array is going to be in advance, you can avoid + extra memory allocations by using arrsetlen to allocate it to that length in + advance and use foo[n] while filling it out, or arrsetcap to allocate the memory + for that length and use arrput/arrpush as normal. + + * Unlike some other versions of the dynamic array, this version should + be safe to use with strict-aliasing optimizations. + +NOTES - HASH MAP + + * For compilers other than GCC and clang (e.g. Visual Studio), for hmput/hmget/hmdel + and variants, the key must be an lvalue (so the macro can take the address of it). + Extensions are used that eliminate this requirement if you're using C99 and later + in GCC or clang, or if you're using C++ in GCC. But note that this can make your + code less portable. + + * To test for presence of a key in a hashmap, just do 'hmgeti(foo,key) >= 0'. + + * The iteration order of your data in the hashmap is determined solely by the + order of insertions and deletions. In particular, if you never delete, new + keys are always added at the end of the array. This will be consistent + across all platforms and versions of the library. However, you should not + attempt to serialize the internal hash table, as the hash is not consistent + between different platforms, and may change with future versions of the library. + + * Use sh_new_arena() for string hashmaps that you never delete from. Initialize + with NULL if you're managing the memory for your strings, or your strings are + never freed (at least until the hashmap is freed). Otherwise, use sh_new_strdup(). + @TODO: make an arena variant that garbage collects the strings with a trivial + copy collector into a new arena whenever the table shrinks / rebuilds. Since + current arena recommendation is to only use arena if it never deletes, then + this can just replace current arena implementation. + + * If adversarial input is a serious concern and you're on a 64-bit platform, + enable STBDS_SIPHASH_2_4 (see the 'Compile-time options' section), and pass + a strong random number to stbds_rand_seed. + + * The default value for the hash table is stored in foo[-1], so if you + use code like 'hmget(T,k)->value = 5' you can accidentally overwrite + the value stored by hmdefault if 'k' is not present. + +CREDITS + + Sean Barrett -- library, idea for dynamic array API/implementation + Per Vognsen -- idea for hash table API/implementation + Rafael Sachetto -- arrpop() + github:HeroicKatora -- arraddn() reworking + + Bugfixes: + Andy Durdin + Shane Liesegang + Vinh Truong + Andreas Molzer + github:hashitaku + github:srdjanstipic + Macoy Madson + Andreas Vennstrom + Tobias Mansfield-Williams +*/ + +#ifdef STBDS_UNIT_TESTS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef INCLUDE_STB_DS_H +#define INCLUDE_STB_DS_H + +#include +#include + +#ifndef STBDS_NO_SHORT_NAMES +#define arrlen stbds_arrlen +#define arrlenu stbds_arrlenu +#define arrput stbds_arrput +#define arrpush stbds_arrput +#define arrpop stbds_arrpop +#define arrfree stbds_arrfree +#define arraddn stbds_arraddn // deprecated, use one of the following instead: +#define arraddnptr stbds_arraddnptr +#define arraddnindex stbds_arraddnindex +#define arrsetlen stbds_arrsetlen +#define arrlast stbds_arrlast +#define arrins stbds_arrins +#define arrinsn stbds_arrinsn +#define arrdel stbds_arrdel +#define arrdeln stbds_arrdeln +#define arrdelswap stbds_arrdelswap +#define arrcap stbds_arrcap +#define arrsetcap stbds_arrsetcap + +#define hmput stbds_hmput +#define hmputs stbds_hmputs +#define hmget stbds_hmget +#define hmget_ts stbds_hmget_ts +#define hmgets stbds_hmgets +#define hmgetp stbds_hmgetp +#define hmgetp_ts stbds_hmgetp_ts +#define hmgetp_null stbds_hmgetp_null +#define hmgeti stbds_hmgeti +#define hmgeti_ts stbds_hmgeti_ts +#define hmdel stbds_hmdel +#define hmlen stbds_hmlen +#define hmlenu stbds_hmlenu +#define hmfree stbds_hmfree +#define hmdefault stbds_hmdefault +#define hmdefaults stbds_hmdefaults + +#define shput stbds_shput +#define shputi stbds_shputi +#define shputs stbds_shputs +#define shget stbds_shget +#define shgeti stbds_shgeti +#define shgets stbds_shgets +#define shgetp stbds_shgetp +#define shgetp_null stbds_shgetp_null +#define shdel stbds_shdel +#define shlen stbds_shlen +#define shlenu stbds_shlenu +#define shfree stbds_shfree +#define shdefault stbds_shdefault +#define shdefaults stbds_shdefaults +#define sh_new_arena stbds_sh_new_arena +#define sh_new_strdup stbds_sh_new_strdup + +#define stralloc stbds_stralloc +#define strreset stbds_strreset +#endif + +#if defined(STBDS_REALLOC) && !defined(STBDS_FREE) || !defined(STBDS_REALLOC) && defined(STBDS_FREE) +#error "You must define both STBDS_REALLOC and STBDS_FREE, or neither." +#endif +#if !defined(STBDS_REALLOC) && !defined(STBDS_FREE) +#include +#define STBDS_REALLOC(c,p,s) realloc(p,s) +#define STBDS_FREE(c,p) free(p) +#endif + +#ifdef _MSC_VER +#define STBDS_NOTUSED(v) (void)(v) +#else +#define STBDS_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// for security against attackers, seed the library with a random number, at least time() but stronger is better +extern void stbds_rand_seed(size_t seed); + +// these are the hash functions used internally if you want to test them or use them for other purposes +extern size_t stbds_hash_bytes(void *p, size_t len, size_t seed); +extern size_t stbds_hash_string(char *str, size_t seed); + +// this is a simple string arena allocator, initialize with e.g. 'stbds_string_arena my_arena={0}'. +typedef struct stbds_string_arena stbds_string_arena; +extern char * stbds_stralloc(stbds_string_arena *a, char *str); +extern void stbds_strreset(stbds_string_arena *a); + +// have to #define STBDS_UNIT_TESTS to call this +extern void stbds_unit_tests(void); + +/////////////// +// +// Everything below here is implementation details +// + +extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap); +extern void stbds_arrfreef(void *a); +extern void stbds_hmfree_func(void *p, size_t elemsize); +extern void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); +extern void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode); +extern void * stbds_hmput_default(void *a, size_t elemsize); +extern void * stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); +extern void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode); +extern void * stbds_shmode_func(size_t elemsize, int mode); + +#ifdef __cplusplus +} +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define STBDS_HAS_TYPEOF +#ifdef __cplusplus +//#define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang +#endif +#endif + +#if !defined(__cplusplus) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define STBDS_HAS_LITERAL_ARRAY +#endif +#endif + +// this macro takes the address of the argument, but on gcc/clang can accept rvalues +#if defined(STBDS_HAS_LITERAL_ARRAY) && defined(STBDS_HAS_TYPEOF) + #if __clang__ + #define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value + #else + #define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value + #endif +#else +#define STBDS_ADDRESSOF(typevar, value) &(value) +#endif + +#define STBDS_OFFSETOF(var,field) ((char *) &(var)->field - (char *) (var)) + +#define stbds_header(t) ((stbds_array_header *) (t) - 1) +#define stbds_temp(t) stbds_header(t)->temp +#define stbds_temp_key(t) (*(char **) stbds_header(t)->hash_table) + +#define stbds_arrsetcap(a,n) (stbds_arrgrow(a,0,n)) +#define stbds_arrsetlen(a,n) ((stbds_arrcap(a) < (size_t) (n) ? stbds_arrsetcap((a),(size_t)(n)),0 : 0), (a) ? stbds_header(a)->length = (size_t) (n) : 0) +#define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0) +#define stbds_arrlen(a) ((a) ? (ptrdiff_t) stbds_header(a)->length : 0) +#define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0) +#define stbds_arrput(a,v) (stbds_arrmaybegrow(a,1), (a)[stbds_header(a)->length++] = (v)) +#define stbds_arrpush stbds_arrput // synonym +#define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length]) +#define stbds_arraddn(a,n) ((void)(stbds_arraddnindex(a, n))) // deprecated, use one of the following instead: +#define stbds_arraddnptr(a,n) (stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), &(a)[stbds_header(a)->length-(n)]) : (a)) +#define stbds_arraddnindex(a,n)(stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), stbds_header(a)->length-(n)) : stbds_arrlen(a)) +#define stbds_arraddnoff stbds_arraddnindex +#define stbds_arrlast(a) ((a)[stbds_header(a)->length-1]) +#define stbds_arrfree(a) ((void) ((a) ? STBDS_FREE(NULL,stbds_header(a)) : (void)0), (a)=NULL) +#define stbds_arrdel(a,i) stbds_arrdeln(a,i,1) +#define stbds_arrdeln(a,i,n) (memmove(&(a)[i], &(a)[(i)+(n)], sizeof *(a) * (stbds_header(a)->length-(n)-(i))), stbds_header(a)->length -= (n)) +#define stbds_arrdelswap(a,i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) +#define stbds_arrinsn(a,i,n) (stbds_arraddn((a),(n)), memmove(&(a)[(i)+(n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length-(n)-(i)))) +#define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v)) + +#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ + ? (stbds_arrgrow(a,n,0),0) : 0) + +#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) + +#define stbds_hmput(t, k, v) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, 0), \ + (t)[stbds_temp((t)-1)].key = (k), \ + (t)[stbds_temp((t)-1)].value = (v)) + +#define stbds_hmputs(t, s) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof (s).key, STBDS_HM_BINARY), \ + (t)[stbds_temp((t)-1)] = (s)) + +#define stbds_hmgeti(t,k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_HM_BINARY), \ + stbds_temp((t)-1)) + +#define stbds_hmgeti_ts(t,k,temp) \ + ((t) = stbds_hmget_key_ts_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, &(temp), STBDS_HM_BINARY), \ + (temp)) + +#define stbds_hmgetp(t, k) \ + ((void) stbds_hmgeti(t,k), &(t)[stbds_temp((t)-1)]) + +#define stbds_hmgetp_ts(t, k, temp) \ + ((void) stbds_hmgeti_ts(t,k,temp), &(t)[temp]) + +#define stbds_hmdel(t,k) \ + (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_BINARY)),(t)?stbds_temp((t)-1):0) + +#define stbds_hmdefault(t, v) \ + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) + +#define stbds_hmdefaults(t, s) \ + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) + +#define stbds_hmfree(p) \ + ((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p)),0 : 0),(p)=NULL) + +#define stbds_hmgets(t, k) (*stbds_hmgetp(t,k)) +#define stbds_hmget(t, k) (stbds_hmgetp(t,k)->value) +#define stbds_hmget_ts(t, k, temp) (stbds_hmgetp_ts(t,k,temp)->value) +#define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0) +#define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0) +#define stbds_hmgetp_null(t,k) (stbds_hmgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) + +#define stbds_shput(t, k, v) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ + (t)[stbds_temp((t)-1)].value = (v)) + +#define stbds_shputi(t, k, v) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ + (t)[stbds_temp((t)-1)].value = (v), stbds_temp((t)-1)) + +#define stbds_shputs(t, s) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (s).key, sizeof (s).key, STBDS_HM_STRING), \ + (t)[stbds_temp((t)-1)] = (s), \ + (t)[stbds_temp((t)-1)].key = stbds_temp_key((t)-1)) // above line overwrites whole structure, so must rewrite key here if it was allocated internally + +#define stbds_pshput(t, p) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (p)->key, sizeof (p)->key, STBDS_HM_PTR_TO_STRING), \ + (t)[stbds_temp((t)-1)] = (p)) + +#define stbds_shgeti(t,k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ + stbds_temp((t)-1)) + +#define stbds_pshgeti(t,k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_HM_PTR_TO_STRING), \ + stbds_temp((t)-1)) + +#define stbds_shgetp(t, k) \ + ((void) stbds_shgeti(t,k), &(t)[stbds_temp((t)-1)]) + +#define stbds_pshget(t, k) \ + ((void) stbds_pshgeti(t,k), (t)[stbds_temp((t)-1)]) + +#define stbds_shdel(t,k) \ + (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_STRING)),(t)?stbds_temp((t)-1):0) +#define stbds_pshdel(t,k) \ + (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_OFFSETOF(*(t),key), STBDS_HM_PTR_TO_STRING)),(t)?stbds_temp((t)-1):0) + +#define stbds_sh_new_arena(t) \ + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA)) +#define stbds_sh_new_strdup(t) \ + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP)) + +#define stbds_shdefault(t, v) stbds_hmdefault(t,v) +#define stbds_shdefaults(t, s) stbds_hmdefaults(t,s) + +#define stbds_shfree stbds_hmfree +#define stbds_shlenu stbds_hmlenu + +#define stbds_shgets(t, k) (*stbds_shgetp(t,k)) +#define stbds_shget(t, k) (stbds_shgetp(t,k)->value) +#define stbds_shgetp_null(t,k) (stbds_shgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) +#define stbds_shlen stbds_hmlen + +typedef struct +{ + size_t length; + size_t capacity; + void * hash_table; + ptrdiff_t temp; +} stbds_array_header; + +typedef struct stbds_string_block +{ + struct stbds_string_block *next; + char storage[8]; +} stbds_string_block; + +struct stbds_string_arena +{ + stbds_string_block *storage; + size_t remaining; + unsigned char block; + unsigned char mode; // this isn't used by the string arena itself +}; + +#define STBDS_HM_BINARY 0 +#define STBDS_HM_STRING 1 + +enum +{ + STBDS_SH_NONE, + STBDS_SH_DEFAULT, + STBDS_SH_STRDUP, + STBDS_SH_ARENA +}; + +#ifdef __cplusplus +// in C we use implicit assignment from these void*-returning functions to T*. +// in C++ these templates make the same code work +template static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap) { + return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap); +} +template static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { + return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode); +} +template static T * stbds_hmget_key_ts_wrapper(T *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) { + return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode); +} +template static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) { + return (T*)stbds_hmput_default((void *)a, elemsize); +} +template static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { + return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); +} +template static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode){ + return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); +} +template static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int mode) { + return (T*)stbds_shmode_func(elemsize, mode); +} +#else +#define stbds_arrgrowf_wrapper stbds_arrgrowf +#define stbds_hmget_key_wrapper stbds_hmget_key +#define stbds_hmget_key_ts_wrapper stbds_hmget_key_ts +#define stbds_hmput_default_wrapper stbds_hmput_default +#define stbds_hmput_key_wrapper stbds_hmput_key +#define stbds_hmdel_key_wrapper stbds_hmdel_key +#define stbds_shmode_func_wrapper(t,e,m) stbds_shmode_func(e,m) +#endif + +#endif // INCLUDE_STB_DS_H + + +////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION +// + +#ifdef STB_DS_IMPLEMENTATION +#include +#include + +#ifndef STBDS_ASSERT +#define STBDS_ASSERT_WAS_UNDEFINED +#define STBDS_ASSERT(x) ((void) 0) +#endif + +#ifdef STBDS_STATISTICS +#define STBDS_STATS(x) x +size_t stbds_array_grow; +size_t stbds_hash_grow; +size_t stbds_hash_shrink; +size_t stbds_hash_rebuild; +size_t stbds_hash_probes; +size_t stbds_hash_alloc; +size_t stbds_rehash_probes; +size_t stbds_rehash_items; +#else +#define STBDS_STATS(x) +#endif + +// +// stbds_arr implementation +// + +//int *prev_allocs[65536]; +//int num_prev; + +void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap) +{ + stbds_array_header temp={0}; // force debugging + void *b; + size_t min_len = stbds_arrlen(a) + addlen; + (void) sizeof(temp); + + // compute the minimum capacity needed + if (min_len > min_cap) + min_cap = min_len; + + if (min_cap <= stbds_arrcap(a)) + return a; + + // increase needed capacity to guarantee O(1) amortized + if (min_cap < 2 * stbds_arrcap(a)) + min_cap = 2 * stbds_arrcap(a); + else if (min_cap < 4) + min_cap = 4; + + //if (num_prev < 65536) if (a) prev_allocs[num_prev++] = (int *) ((char *) a+1); + //if (num_prev == 2201) + // num_prev = num_prev; + b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header)); + //if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b; + b = (char *) b + sizeof(stbds_array_header); + if (a == NULL) { + stbds_header(b)->length = 0; + stbds_header(b)->hash_table = 0; + stbds_header(b)->temp = 0; + } else { + STBDS_STATS(++stbds_array_grow); + } + stbds_header(b)->capacity = min_cap; + + return b; +} + +void stbds_arrfreef(void *a) +{ + STBDS_FREE(NULL, stbds_header(a)); +} + +// +// stbds_hm hash table implementation +// + +#ifdef STBDS_INTERNAL_SMALL_BUCKET +#define STBDS_BUCKET_LENGTH 4 +#else +#define STBDS_BUCKET_LENGTH 8 +#endif + +#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) +#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH-1) +#define STBDS_CACHE_LINE_SIZE 64 + +#define STBDS_ALIGN_FWD(n,a) (((n) + (a) - 1) & ~((a)-1)) + +typedef struct +{ + size_t hash [STBDS_BUCKET_LENGTH]; + ptrdiff_t index[STBDS_BUCKET_LENGTH]; +} stbds_hash_bucket; // in 32-bit, this is one 64-byte cache line; in 64-bit, each array is one 64-byte cache line + +typedef struct +{ + char * temp_key; // this MUST be the first field of the hash table + size_t slot_count; + size_t used_count; + size_t used_count_threshold; + size_t used_count_shrink_threshold; + size_t tombstone_count; + size_t tombstone_count_threshold; + size_t seed; + size_t slot_count_log2; + stbds_string_arena string; + stbds_hash_bucket *storage; // not a separate allocation, just 64-byte aligned storage after this struct +} stbds_hash_index; + +#define STBDS_INDEX_EMPTY -1 +#define STBDS_INDEX_DELETED -2 +#define STBDS_INDEX_IN_USE(x) ((x) >= 0) + +#define STBDS_HASH_EMPTY 0 +#define STBDS_HASH_DELETED 1 + +static size_t stbds_hash_seed=0x31415926; + +void stbds_rand_seed(size_t seed) +{ + stbds_hash_seed = seed; +} + +#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ + temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ + var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ + var ^= temp ^ v32 + +#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8) + +static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) +{ + size_t pos; + STBDS_NOTUSED(slot_log2); + pos = hash & (slot_count-1); + #ifdef STBDS_INTERNAL_BUCKET_START + pos &= ~STBDS_BUCKET_MASK; + #endif + return pos; +} + +static size_t stbds_log2(size_t slot_count) +{ + size_t n=0; + while (slot_count > 1) { + slot_count >>= 1; + ++n; + } + return n; +} + +static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot) +{ + stbds_hash_index *t; + t = (stbds_hash_index *) STBDS_REALLOC(NULL,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1); + t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE); + t->slot_count = slot_count; + t->slot_count_log2 = stbds_log2(slot_count); + t->tombstone_count = 0; + t->used_count = 0; + + #if 0 // A1 + t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink + #elif 1 // A2 + //t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow + //t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild + //t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink + + // compute without overflowing + t->used_count_threshold = slot_count - (slot_count>>2); + t->tombstone_count_threshold = (slot_count>>3) + (slot_count>>4); + t->used_count_shrink_threshold = slot_count >> 2; + + #elif 0 // B1 + t->used_count_threshold = slot_count*13/16; // if 13/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 5/16; // if table is only 5/16th full, shrink + #else // C1 + t->used_count_threshold = slot_count*14/16; // if 14/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 6/16; // if table is only 6/16th full, shrink + #endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // A1 A2 B1 C1 + // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table + // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table + // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table + // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table + // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table + // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table + // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table + // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table + // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table + // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table + // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table + + if (slot_count <= STBDS_BUCKET_LENGTH) + t->used_count_shrink_threshold = 0; + // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes + STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); + STBDS_STATS(++stbds_hash_alloc); + if (ot) { + t->string = ot->string; + // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing + t->seed = ot->seed; + } else { + size_t a,b,temp; + memset(&t->string, 0, sizeof(t->string)); + t->seed = stbds_hash_seed; + // LCG + // in 32-bit, a = 2147001325 b = 715136305 + // in 64-bit, a = 2862933555777941757 b = 3037000493 + stbds_load_32_or_64(a,temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); + stbds_load_32_or_64(b,temp, 715136305, 0, 0xb504f32d); + stbds_hash_seed = stbds_hash_seed * a + b; + } + + { + size_t i,j; + for (i=0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket *b = &t->storage[i]; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) + b->hash[j] = STBDS_HASH_EMPTY; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) + b->index[j] = STBDS_INDEX_EMPTY; + } + } + + // copy out the old data, if any + if (ot) { + size_t i,j; + t->used_count = ot->used_count; + for (i=0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket *ob = &ot->storage[i]; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) { + if (STBDS_INDEX_IN_USE(ob->index[j])) { + size_t hash = ob->hash[j]; + size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); + size_t step = STBDS_BUCKET_LENGTH; + STBDS_STATS(++stbds_rehash_items); + for (;;) { + size_t limit,z; + stbds_hash_bucket *bucket; + bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; + STBDS_STATS(++stbds_rehash_probes); + + for (z=pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { + if (bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } + + limit = pos & STBDS_BUCKET_MASK; + for (z = 0; z < limit; ++z) { + if (bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } + + pos += step; // quadratic probing + step += STBDS_BUCKET_LENGTH; + pos &= (t->slot_count-1); + } + } + done: + ; + } + } + } + + return t; +} + +#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) +#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) + +size_t stbds_hash_string(char *str, size_t seed) +{ + size_t hash = seed; + while (*str) + hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++; + + // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits + hash ^= seed; + hash = (~hash) + (hash << 18); + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,31); + hash = hash * 21; + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,11); + hash += (hash << 6); + hash ^= STBDS_ROTATE_RIGHT(hash,22); + return hash+seed; +} + +#ifdef STBDS_SIPHASH_2_4 +#define STBDS_SIPHASH_C_ROUNDS 2 +#define STBDS_SIPHASH_D_ROUNDS 4 +typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) == 8 ? 1 : -1]; +#endif + +#ifndef STBDS_SIPHASH_C_ROUNDS +#define STBDS_SIPHASH_C_ROUNDS 1 +#endif +#ifndef STBDS_SIPHASH_D_ROUNDS +#define STBDS_SIPHASH_D_ROUNDS 1 +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()== +#endif + +static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed) +{ + unsigned char *d = (unsigned char *) p; + size_t i,j; + size_t v0,v1,v2,v3, data; + + // hash that works on 32- or 64-bit registers without knowing which we have + // (computes different results on 32-bit and 64-bit platform) + // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit + v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; + v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; + v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; + v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; + + #ifdef STBDS_TEST_SIPHASH_2_4 + // hardcoded with key material in the siphash test vectors + v0 ^= 0x0706050403020100ull ^ seed; + v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; + v2 ^= 0x0706050403020100ull ^ seed; + v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; + #endif + + #define STBDS_SIPROUND() \ + do { \ + v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \ + v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \ + v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \ + v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \ + } while (0) + + for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { + data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 + + v3 ^= data; + for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + } + data = len << (STBDS_SIZE_T_BITS-8); + switch (len - i) { + case 7: data |= ((size_t) d[6] << 24) << 24; // fall through + case 6: data |= ((size_t) d[5] << 20) << 20; // fall through + case 5: data |= ((size_t) d[4] << 16) << 16; // fall through + case 4: data |= (d[3] << 24); // fall through + case 3: data |= (d[2] << 16); // fall through + case 2: data |= (d[1] << 8); // fall through + case 1: data |= d[0]; // fall through + case 0: break; + } + v3 ^= data; + for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + v2 ^= 0xff; + for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j) + STBDS_SIPROUND(); + +#ifdef STBDS_SIPHASH_2_4 + return v0^v1^v2^v3; +#else + return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply +#endif +} + +size_t stbds_hash_bytes(void *p, size_t len, size_t seed) +{ +#ifdef STBDS_SIPHASH_2_4 + return stbds_siphash_bytes(p,len,seed); +#else + unsigned char *d = (unsigned char *) p; + + if (len == 4) { + unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + #if 0 + // HASH32-A Bob Jenkin's hash function w/o large constants + hash ^= seed; + hash -= (hash<<6); + hash ^= (hash>>17); + hash -= (hash<<9); + hash ^= seed; + hash ^= (hash<<4); + hash -= (hash<<3); + hash ^= (hash<<10); + hash ^= (hash>>15); + #elif 1 + // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. + // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm + // not really sure what's going on. + hash ^= seed; + hash = (hash ^ 61) ^ (hash >> 16); + hash = hash + (hash << 3); + hash = hash ^ (hash >> 4); + hash = hash * 0x27d4eb2d; + hash ^= seed; + hash = hash ^ (hash >> 15); + #else // HASH32-C - Murmur3 + hash ^= seed; + hash *= 0xcc9e2d51; + hash = (hash << 17) | (hash >> 15); + hash *= 0x1b873593; + hash ^= seed; + hash = (hash << 19) | (hash >> 13); + hash = hash*5 + 0xe6546b64; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= seed; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + #endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // HASH32-A // HASH32-BB // HASH32-C + // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table + // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table + // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table + // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table + // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table + // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table + // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table + // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table + // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table + // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table + // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table + // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing + + return (((size_t) hash << 16 << 16) | hash) ^ seed; + } else if (len == 8 && sizeof(size_t) == 8) { + size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 + hash ^= seed; + hash = (~hash) + (hash << 21); + hash ^= STBDS_ROTATE_RIGHT(hash,24); + hash *= 265; + hash ^= STBDS_ROTATE_RIGHT(hash,14); + hash ^= seed; + hash *= 21; + hash ^= STBDS_ROTATE_RIGHT(hash,28); + hash += (hash << 31); + hash = (~hash) + (hash << 18); + return hash; + } else { + return stbds_siphash_bytes(p,len,seed); + } +#endif +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, size_t i) +{ + if (mode >= STBDS_HM_STRING) + return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i + keyoffset)); + else + return 0==memcmp(key, (char *) a + elemsize*i + keyoffset, keysize); +} + +#define STBDS_HASH_TO_ARR(x,elemsize) ((char*) (x) - (elemsize)) +#define STBDS_ARR_TO_HASH(x,elemsize) ((char*) (x) + (elemsize)) + +#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table) + +void stbds_hmfree_func(void *a, size_t elemsize) +{ + if (a == NULL) return; + if (stbds_hash_table(a) != NULL) { + if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) { + size_t i; + // skip 0th element, which is default + for (i=1; i < stbds_header(a)->length; ++i) + STBDS_FREE(NULL, *(char**) ((char *) a + elemsize*i)); + } + stbds_strreset(&stbds_hash_table(a)->string); + } + STBDS_FREE(NULL, stbds_header(a)->hash_table); + STBDS_FREE(NULL, stbds_header(a)); +} + +static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) +{ + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + stbds_hash_index *table = stbds_hash_table(raw_a); + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t limit,i; + size_t pos; + stbds_hash_bucket *bucket; + + if (hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots + + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + + for (;;) { + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + + // start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache + for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK)+i; + } + } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } + + // search from beginning of bucket to pos + limit = pos & STBDS_BUCKET_MASK; + for (i = 0; i < limit; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK)+i; + } + } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } + + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count-1); + } + /* NOTREACHED */ +} + +void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) +{ + size_t keyoffset = 0; + if (a == NULL) { + // make it non-empty so we can return a temp + a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_header(a)->length += 1; + memset(a, 0, elemsize); + *temp = STBDS_INDEX_EMPTY; + // adjust a to point after the default element + return STBDS_ARR_TO_HASH(a,elemsize); + } else { + stbds_hash_index *table; + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + // adjust a to point to the default element + table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; + if (table == 0) { + *temp = -1; + } else { + ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); + if (slot < 0) { + *temp = STBDS_INDEX_EMPTY; + } else { + stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + *temp = b->index[slot & STBDS_BUCKET_MASK]; + } + } + return a; + } +} + +void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) +{ + ptrdiff_t temp; + void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode); + stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp; + return p; +} + +void * stbds_hmput_default(void *a, size_t elemsize) +{ + // three cases: + // a is NULL <- allocate + // a has a hash table but no entries, because of shmode <- grow + // a has entries <- do nothing + if (a == NULL || stbds_header(STBDS_HASH_TO_ARR(a,elemsize))->length == 0) { + a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a,elemsize) : NULL, elemsize, 0, 1); + stbds_header(a)->length += 1; + memset(a, 0, elemsize); + a=STBDS_ARR_TO_HASH(a,elemsize); + } + return a; +} + +static char *stbds_strdup(char *str); + +void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) +{ + size_t keyoffset=0; + void *raw_a; + stbds_hash_index *table; + + if (a == NULL) { + a = stbds_arrgrowf(0, elemsize, 0, 1); + memset(a, 0, elemsize); + stbds_header(a)->length += 1; + // adjust a to point AFTER the default element + a = STBDS_ARR_TO_HASH(a,elemsize); + } + + // adjust a to point to the default element + raw_a = a; + a = STBDS_HASH_TO_ARR(a,elemsize); + + table = (stbds_hash_index *) stbds_header(a)->hash_table; + + if (table == NULL || table->used_count >= table->used_count_threshold) { + stbds_hash_index *nt; + size_t slot_count; + + slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2; + nt = stbds_make_hash_index(slot_count, table); + if (table) + STBDS_FREE(NULL, table); + else + nt->string.mode = mode >= STBDS_HM_STRING ? STBDS_SH_DEFAULT : 0; + stbds_header(a)->hash_table = table = nt; + STBDS_STATS(++stbds_hash_grow); + } + + // we iterate hash table explicitly because we want to track if we saw a tombstone + { + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t pos; + ptrdiff_t tombstone = -1; + stbds_hash_bucket *bucket; + + // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly + if (hash < 2) hash += 2; + + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + + for (;;) { + size_t limit, i; + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + + // start searching from pos to end of bucket + for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + if (mode >= STBDS_HM_STRING) + stbds_temp_key(a) = * (char **) ((char *) raw_a + elemsize*bucket->index[i] + keyoffset); + return STBDS_ARR_TO_HASH(a,elemsize); + } + } else if (bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if (tombstone < 0) { + if (bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); + } + } + + // search from beginning of bucket to pos + limit = pos & STBDS_BUCKET_MASK; + for (i = 0; i < limit; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + return STBDS_ARR_TO_HASH(a,elemsize); + } + } else if (bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if (tombstone < 0) { + if (bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); + } + } + + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count-1); + } + found_empty_slot: + if (tombstone >= 0) { + pos = tombstone; + --table->tombstone_count; + } + ++table->used_count; + + { + ptrdiff_t i = (ptrdiff_t) stbds_arrlen(a); + // we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type + if ((size_t) i+1 > stbds_arrcap(a)) + *(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0); + raw_a = STBDS_ARR_TO_HASH(a,elemsize); + + STBDS_ASSERT((size_t) i+1 <= stbds_arrcap(a)); + stbds_header(a)->length = i+1; + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + bucket->hash[pos & STBDS_BUCKET_MASK] = hash; + bucket->index[pos & STBDS_BUCKET_MASK] = i-1; + stbds_temp(a) = i-1; + + switch (table->string.mode) { + case STBDS_SH_STRDUP: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break; + case STBDS_SH_ARENA: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break; + case STBDS_SH_DEFAULT: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = (char *) key; break; + default: memcpy((char *) a + elemsize*i, key, keysize); break; + } + } + return STBDS_ARR_TO_HASH(a,elemsize); + } +} + +void * stbds_shmode_func(size_t elemsize, int mode) +{ + void *a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_hash_index *h; + memset(a, 0, elemsize); + stbds_header(a)->length = 1; + stbds_header(a)->hash_table = h = (stbds_hash_index *) stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL); + h->string.mode = (unsigned char) mode; + return STBDS_ARR_TO_HASH(a,elemsize); +} + +void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) +{ + if (a == NULL) { + return 0; + } else { + stbds_hash_index *table; + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; + stbds_temp(raw_a) = 0; + if (table == 0) { + return a; + } else { + ptrdiff_t slot; + slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); + if (slot < 0) + return a; + else { + stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + int i = slot & STBDS_BUCKET_MASK; + ptrdiff_t old_index = b->index[i]; + ptrdiff_t final_index = (ptrdiff_t) stbds_arrlen(raw_a)-1-1; // minus one for the raw_a vs a, and minus one for 'last' + STBDS_ASSERT(slot < (ptrdiff_t) table->slot_count); + --table->used_count; + ++table->tombstone_count; + stbds_temp(raw_a) = 1; + STBDS_ASSERT(table->used_count >= 0); + //STBDS_ASSERT(table->tombstone_count < table->slot_count/4); + b->hash[i] = STBDS_HASH_DELETED; + b->index[i] = STBDS_INDEX_DELETED; + + if (mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) + STBDS_FREE(NULL, *(char**) ((char *) a+elemsize*old_index)); + + // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip + if (old_index != final_index) { + // swap delete + memmove((char*) a + elemsize*old_index, (char*) a + elemsize*final_index, elemsize); + + // now find the slot for the last element + if (mode == STBDS_HM_STRING) + slot = stbds_hm_find_slot(a, elemsize, *(char**) ((char *) a+elemsize*old_index + keyoffset), keysize, keyoffset, mode); + else + slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, keyoffset, mode); + STBDS_ASSERT(slot >= 0); + b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + i = slot & STBDS_BUCKET_MASK; + STBDS_ASSERT(b->index[i] == final_index); + b->index[i] = old_index; + } + stbds_header(raw_a)->length -= 1; + + if (table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count>>1, table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_shrink); + } else if (table->tombstone_count > table->tombstone_count_threshold) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count , table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_rebuild); + } + + return a; + } + } + } + /* NOTREACHED */ +} + +static char *stbds_strdup(char *str) +{ + // to keep replaceable allocator simple, we don't want to use strdup. + // rolling our own also avoids problem of strdup vs _strdup + size_t len = strlen(str)+1; + char *p = (char*) STBDS_REALLOC(NULL, 0, len); + memmove(p, str, len); + return p; +} + +#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN +#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u +#endif +#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX +#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20) +#endif + +char *stbds_stralloc(stbds_string_arena *a, char *str) +{ + char *p; + size_t len = strlen(str)+1; + if (len > a->remaining) { + // compute the next blocksize + size_t blocksize = a->block; + + // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that + // there are log(SIZE) allocations to free when we destroy the table + blocksize = (size_t) (STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize>>1); + + // if size is under 1M, advance to next blocktype + if (blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) + ++a->block; + + if (len > blocksize) { + // if string is larger than blocksize, then just allocate the full size. + // note that we still advance string_block so block size will continue + // increasing, so e.g. if somebody only calls this with 1000-long strings, + // eventually the arena will start doubling and handling those as well + stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + len); + memmove(sb->storage, str, len); + if (a->storage) { + // insert it after the first element, so that we don't waste the space there + sb->next = a->storage->next; + a->storage->next = sb; + } else { + sb->next = 0; + a->storage = sb; + a->remaining = 0; // this is redundant, but good for clarity + } + return sb->storage; + } else { + stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + blocksize); + sb->next = a->storage; + a->storage = sb; + a->remaining = blocksize; + } + } + + STBDS_ASSERT(len <= a->remaining); + p = a->storage->storage + a->remaining - len; + a->remaining -= len; + memmove(p, str, len); + return p; +} + +void stbds_strreset(stbds_string_arena *a) +{ + stbds_string_block *x,*y; + x = a->storage; + while (x) { + y = x->next; + STBDS_FREE(NULL, x); + x = y; + } + memset(a, 0, sizeof(*a)); +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// UNIT TESTS +// + +#ifdef STBDS_UNIT_TESTS +#include +#ifdef STBDS_ASSERT_WAS_UNDEFINED +#undef STBDS_ASSERT +#endif +#ifndef STBDS_ASSERT +#define STBDS_ASSERT assert +#include +#endif + +typedef struct { int key,b,c,d; } stbds_struct; +typedef struct { int key[2],b,c,d; } stbds_struct2; + +static char buffer[256]; +char *strkey(int n) +{ +#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) + sprintf_s(buffer, sizeof(buffer), "test_%d", n); +#else + sprintf(buffer, "test_%d", n); +#endif + return buffer; +} + +void stbds_unit_tests(void) +{ +#if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus) + // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! + STBDS_ASSERT(0); +#else + const int testsize = 100000; + const int testsize2 = testsize/20; + int *arr=NULL; + struct { int key; int value; } *intmap = NULL; + struct { char *key; int value; } *strmap = NULL, s; + struct { stbds_struct key; int value; } *map = NULL; + stbds_struct *map2 = NULL; + stbds_struct2 *map3 = NULL; + stbds_string_arena sa = { 0 }; + int key3[2] = { 1,2 }; + ptrdiff_t temp; + + int i,j; + + STBDS_ASSERT(arrlen(arr)==0); + for (i=0; i < 20000; i += 50) { + for (j=0; j < i; ++j) + arrpush(arr,j); + arrfree(arr); + } + + for (i=0; i < 4; ++i) { + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + arrdel(arr,i); + arrfree(arr); + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + arrdelswap(arr,i); + arrfree(arr); + } + + for (i=0; i < 5; ++i) { + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + stbds_arrins(arr,i,5); + STBDS_ASSERT(arr[i] == 5); + if (i < 4) + STBDS_ASSERT(arr[4] == 4); + arrfree(arr); + } + + i = 1; + STBDS_ASSERT(hmgeti(intmap,i) == -1); + hmdefault(intmap, -2); + STBDS_ASSERT(hmgeti(intmap, i) == -1); + STBDS_ASSERT(hmget (intmap, i) == -2); + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*5); + for (i=0; i < testsize; i+=1) { + if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); + else STBDS_ASSERT(hmget(intmap, i) == i*5); + if (i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp) == -2 ); + else STBDS_ASSERT(hmget_ts(intmap, i, temp) == i*5); + } + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*3); + for (i=0; i < testsize; i+=1) + if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); + else STBDS_ASSERT(hmget(intmap, i) == i*3); + for (i=2; i < testsize; i+=4) + hmdel(intmap, i); // delete half the entries + for (i=0; i < testsize; i+=1) + if (i & 3) STBDS_ASSERT(hmget(intmap, i) == -2 ); + else STBDS_ASSERT(hmget(intmap, i) == i*3); + for (i=0; i < testsize; i+=1) + hmdel(intmap, i); // delete the rest of the entries + for (i=0; i < testsize; i+=1) + STBDS_ASSERT(hmget(intmap, i) == -2 ); + hmfree(intmap); + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*3); + hmfree(intmap); + + #if defined(__clang__) || defined(__GNUC__) + #ifndef __cplusplus + intmap = NULL; + hmput(intmap, 15, 7); + hmput(intmap, 11, 3); + hmput(intmap, 9, 5); + STBDS_ASSERT(hmget(intmap, 9) == 5); + STBDS_ASSERT(hmget(intmap, 11) == 3); + STBDS_ASSERT(hmget(intmap, 15) == 7); + #endif + #endif + + for (i=0; i < testsize; ++i) + stralloc(&sa, strkey(i)); + strreset(&sa); + + { + s.key = "a", s.value = 1; + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key == s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } + + { + s.key = "a", s.value = 1; + sh_new_strdup(strmap); + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key != s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } + + { + s.key = "a", s.value = 1; + sh_new_arena(strmap); + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key != s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } + + for (j=0; j < 2; ++j) { + STBDS_ASSERT(shgeti(strmap,"foo") == -1); + if (j == 0) + sh_new_strdup(strmap); + else + sh_new_arena(strmap); + STBDS_ASSERT(shgeti(strmap,"foo") == -1); + shdefault(strmap, -2); + STBDS_ASSERT(shgeti(strmap,"foo") == -1); + for (i=0; i < testsize; i+=2) + shput(strmap, strkey(i), i*3); + for (i=0; i < testsize; i+=1) + if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); + else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); + for (i=2; i < testsize; i+=4) + shdel(strmap, strkey(i)); // delete half the entries + for (i=0; i < testsize; i+=1) + if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); + else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); + for (i=0; i < testsize; i+=1) + shdel(strmap, strkey(i)); // delete the rest of the entries + for (i=0; i < testsize; i+=1) + STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); + shfree(strmap); + } + + { + struct { char *key; char value; } *hash = NULL; + char name[4] = "jen"; + shput(hash, "bob" , 'h'); + shput(hash, "sally" , 'e'); + shput(hash, "fred" , 'l'); + shput(hash, "jen" , 'x'); + shput(hash, "doug" , 'o'); + + shput(hash, name , 'l'); + shfree(hash); + } + + for (i=0; i < testsize; i += 2) { + stbds_struct s = { i,i*2,i*3,i*4 }; + hmput(map, s, i*5); + } + + for (i=0; i < testsize; i += 1) { + stbds_struct s = { i,i*2,i*3 ,i*4 }; + stbds_struct t = { i,i*2,i*3+1,i*4 }; + if (i & 1) STBDS_ASSERT(hmget(map, s) == 0); + else STBDS_ASSERT(hmget(map, s) == i*5); + if (i & 1) STBDS_ASSERT(hmget_ts(map, s, temp) == 0); + else STBDS_ASSERT(hmget_ts(map, s, temp) == i*5); + //STBDS_ASSERT(hmget(map, t.key) == 0); + } + + for (i=0; i < testsize; i += 2) { + stbds_struct s = { i,i*2,i*3,i*4 }; + hmputs(map2, s); + } + hmfree(map); + + for (i=0; i < testsize; i += 1) { + stbds_struct s = { i,i*2,i*3,i*4 }; + stbds_struct t = { i,i*2,i*3+1,i*4 }; + if (i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0); + else STBDS_ASSERT(hmgets(map2, s.key).d == i*4); + //STBDS_ASSERT(hmgetp(map2, t.key) == 0); + } + hmfree(map2); + + for (i=0; i < testsize; i += 2) { + stbds_struct2 s = { { i,i*2 }, i*3,i*4, i*5 }; + hmputs(map3, s); + } + for (i=0; i < testsize; i += 1) { + stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 }; + stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 }; + if (i & 1) STBDS_ASSERT(hmgets(map3, s.key).d == 0); + else STBDS_ASSERT(hmgets(map3, s.key).d == i*5); + //STBDS_ASSERT(hmgetp(map3, t.key) == 0); + } +#endif +} +#endif + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2019 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/widget/milsko/milskosrc/external/stb_image.c b/widget/milsko/milskosrc/external/stb_image.c new file mode 100644 index 0000000000..cd4c8b0441 --- /dev/null +++ b/widget/milsko/milskosrc/external/stb_image.c @@ -0,0 +1,4 @@ +#ifdef USE_STB_IMAGE +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +#endif diff --git a/widget/milsko/milskosrc/external/stb_image.h b/widget/milsko/milskosrc/external/stb_image.h new file mode 100644 index 0000000000..6eac58c8d8 --- /dev/null +++ b/widget/milsko/milskosrc/external/stb_image.h @@ -0,0 +1,7988 @@ +/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.30 (2024-05-31) avoid erroneous gcc warning + 2.29 (2023-05-xx) optimizations + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data); +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if defined(_MSC_VER) || defined(__SYMBIAN32__) || defined(__BORLANDC__) +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { + h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + j->marker = stbi__skip_jpeg_junk_at_end(j); + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); + } else { + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); + } + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + int hit_zeof_once; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); + } + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } + return 1; + } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (len > a->zout_end - zout) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + a->hit_zeof_once = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub +}; + +static int stbi__paeth(int a, int b, int c) +{ + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + + for (j=0; j < y; ++j) { + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; + int filter = *raw++; + + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; + } + + raw += nk; + + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; + + // expand bits to bytes first + if (depth == 4) { + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; + } + } else if (depth == 2) { + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; + } + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; + } + } + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); + if (img_n == 1) { + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; + } + } else { + STBI_ASSERT(img_n == 3); + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; + } + } + } + } + } + + STBI_FREE(filter_buf); + if (!all_ok) return 0; + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + } + // even with SCAN_header, have to scan to see if we have a tRNS + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } + if (z->depth == 16) { + for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n && k < 3; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } + + if (req_comp && req_comp != s->img_n) { + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/widget/milsko/milskosrc/external/stb_truetype.c b/widget/milsko/milskosrc/external/stb_truetype.c new file mode 100644 index 0000000000..fc4efcbacf --- /dev/null +++ b/widget/milsko/milskosrc/external/stb_truetype.c @@ -0,0 +1,4 @@ +#ifdef USE_STB_TRUETYPE +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" +#endif diff --git a/widget/milsko/milskosrc/external/stb_truetype.h b/widget/milsko/milskosrc/external/stb_truetype.h new file mode 100644 index 0000000000..90a5c2e2b3 --- /dev/null +++ b/widget/milsko/milskosrc/external/stb_truetype.h @@ -0,0 +1,5079 @@ +// stb_truetype.h - v1.26 - public domain +// authored from 2009-2021 by Sean Barrett / RAD Game Tools +// +// ======================================================================= +// +// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES +// +// This library does no range checking of the offsets found in the file, +// meaning an attacker can use it to read arbitrary memory. +// +// ======================================================================= +// +// This library processes TrueType files: +// parse files +// extract glyph metrics +// extract glyph shapes +// render glyphs to one-channel bitmaps with antialiasing (box filter) +// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// +// Todo: +// non-MS cmaps +// crashproof on bad data +// hinting? (no longer patented) +// cleartype-style AA? +// optimize: use simple memory allocator for intermediates +// optimize: build edge-list directly from curves +// optimize: rasterize directly from curves? +// +// ADDITIONAL CONTRIBUTORS +// +// Mikko Mononen: compound shape support, more cmap formats +// Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning +// +// Misc other: +// Ryan Gordon +// Simon Glass +// github:IntellectualKitty +// Imanol Celaya +// Daniel Ribeiro Maciel +// +// Bug/warning reports/fixes: +// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe +// Cass Everitt Martins Mozeiko github:aloucks +// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam +// Brian Hook Omar Cornut github:vassvik +// Walter van Niftrik Ryan Griege +// David Gow Peter LaValle +// David Given Sergey Popov +// Ivan-Assen Ivanov Giumo X. Clanjor +// Anthony Pesch Higor Euripedes +// Johan Duparc Thomas Fields +// Hou Qiming Derek Vinyard +// Rob Loach Cort Stratton +// Kenney Phillis Jr. Brian Costabile +// Ken Voskuil (kaesve) Yakov Galka +// +// VERSION HISTORY +// +// 1.26 (2021-08-28) fix broken rasterizer +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// variant PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// +// Full history can be found at the end of this file. +// +// LICENSE +// +// See end of file for license information. +// +// USAGE +// +// Include this file in whatever places need to refer to it. In ONE C/C++ +// file, write: +// #define STB_TRUETYPE_IMPLEMENTATION +// before the #include of this file. This expands out the actual +// implementation into that C/C++ file. +// +// To make the implementation private to the file that generates the implementation, +// #define STBTT_STATIC +// +// Simple 3D API (don't ship this, but it's fine for tools and quick start) +// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture +// stbtt_GetBakedQuad() -- compute quad to draw for a given char +// +// Improved 3D API (more shippable): +// #include "stb_rect_pack.h" -- optional, but you really want it +// stbtt_PackBegin() +// stbtt_PackSetOversampling() -- for improved quality on small fonts +// stbtt_PackFontRanges() -- pack and renders +// stbtt_PackEnd() +// stbtt_GetPackedQuad() +// +// "Load" a font file from a memory buffer (you have to keep the buffer loaded) +// stbtt_InitFont() +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections +// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections +// +// Render a unicode codepoint to a bitmap +// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap +// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide +// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be +// +// Character advance/positioning +// stbtt_GetCodepointHMetrics() +// stbtt_GetFontVMetrics() +// stbtt_GetFontVMetricsOS2() +// stbtt_GetCodepointKernAdvance() +// +// Starting with version 1.06, the rasterizer was replaced with a new, +// faster and generally-more-precise rasterizer. The new rasterizer more +// accurately measures pixel coverage for anti-aliasing, except in the case +// where multiple shapes overlap, in which case it overestimates the AA pixel +// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If +// this turns out to be a problem, you can re-enable the old rasterizer with +// #define STBTT_RASTERIZER_VERSION 1 +// which will incur about a 15% speed hit. +// +// ADDITIONAL DOCUMENTATION +// +// Immediately after this block comment are a series of sample programs. +// +// After the sample programs is the "header file" section. This section +// includes documentation for each API function. +// +// Some important concepts to understand to use this library: +// +// Codepoint +// Characters are defined by unicode codepoints, e.g. 65 is +// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is +// the hiragana for "ma". +// +// Glyph +// A visual character shape (every codepoint is rendered as +// some glyph) +// +// Glyph index +// A font-specific integer ID representing a glyph +// +// Baseline +// Glyph shapes are defined relative to a baseline, which is the +// bottom of uppercase characters. Characters extend both above +// and below the baseline. +// +// Current Point +// As you draw text to the screen, you keep track of a "current point" +// which is the origin of each character. The current point's vertical +// position is the baseline. Even "baked fonts" use this model. +// +// Vertical Font Metrics +// The vertical qualities of the font, used to vertically position +// and space the characters. See docs for stbtt_GetFontVMetrics. +// +// Font Size in Pixels or Points +// The preferred interface for specifying font sizes in stb_truetype +// is to specify how tall the font's vertical extent should be in pixels. +// If that sounds good enough, skip the next paragraph. +// +// Most font APIs instead use "points", which are a common typographic +// measurement for describing font size, defined as 72 points per inch. +// stb_truetype provides a point API for compatibility. However, true +// "per inch" conventions don't make much sense on computer displays +// since different monitors have different number of pixels per +// inch. For example, Windows traditionally uses a convention that +// there are 96 pixels per inch, thus making 'inch' measurements have +// nothing to do with inches, and thus effectively defining a point to +// be 1.333 pixels. Additionally, the TrueType font data provides +// an explicit scale factor to scale a given font's glyphs to points, +// but the author has observed that this scale factor is often wrong +// for non-commercial fonts, thus making fonts scaled in points +// according to the TrueType spec incoherently sized in practice. +// +// DETAILED USAGE: +// +// Scale: +// Select how high you want the font to be, in points or pixels. +// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute +// a scale factor SF that will be used by all other functions. +// +// Baseline: +// You need to select a y-coordinate that is the baseline of where +// your text will appear. Call GetFontBoundingBox to get the baseline-relative +// bounding box for all characters. SF*-y0 will be the distance in pixels +// that the worst-case character could extend above the baseline, so if +// you want the top edge of characters to appear at the top of the +// screen where y=0, then you would set the baseline to SF*-y0. +// +// Current point: +// Set the current point where the first character will appear. The +// first character could extend left of the current point; this is font +// dependent. You can either choose a current point that is the leftmost +// point and hope, or add some padding, or check the bounding box or +// left-side-bearing of the first character to be displayed and set +// the current point based on that. +// +// Displaying a character: +// Compute the bounding box of the character. It will contain signed values +// relative to . I.e. if it returns x0,y0,x1,y1, +// then the character should be displayed in the rectangle from +// to = 32 && *text < 128) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); + } + ++text; + } + glEnd(); +} +#endif +// +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program (this compiles): get a single bitmap, print as ASCII art +// +#if 0 +#include +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#include "stb_truetype.h" + +char ttf_buffer[1<<25]; + +int main(int argc, char **argv) +{ + stbtt_fontinfo font; + unsigned char *bitmap; + int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); + + fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); + + stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); + bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); + + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) + putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); + putchar('\n'); + } + return 0; +} +#endif +// +// Output: +// +// .ii. +// @@@@@@. +// V@Mio@@o +// :i. V@V +// :oM@@M +// :@@@MM@M +// @@o o@M +// :@@. M@M +// @@@o@@@@ +// :M@@V:@@. +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program: print "Hello World!" banner, with bugs +// +#if 0 +char buffer[24<<20]; +unsigned char screen[20][79]; + +int main(int arg, char **argv) +{ + stbtt_fontinfo font; + int i,j,ascent,baseline,ch=0; + float scale, xpos=2; // leave a little padding in case the character extends left + char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness + + fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); + stbtt_InitFont(&font, buffer, 0); + + scale = stbtt_ScaleForPixelHeight(&font, 15); + stbtt_GetFontVMetrics(&font, &ascent,0,0); + baseline = (int) (ascent*scale); + + while (text[ch]) { + int advance,lsb,x0,y0,x1,y1; + float x_shift = xpos - (float) floor(xpos); + stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); + stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); + stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); + // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong + // because this API is really for baking character bitmaps into textures. if you want to render + // a sequence of characters, you really need to render each bitmap to a temp buffer, then + // "alpha blend" that into the working buffer + xpos += (advance * scale); + if (text[ch+1]) + xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); + ++ch; + } + + for (j=0; j < 20; ++j) { + for (i=0; i < 78; ++i) + putchar(" .:ioVM@"[screen[j][i]>>5]); + putchar('\n'); + } + + return 0; +} +#endif + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +//// +//// INTEGRATION WITH YOUR CODEBASE +//// +//// The following sections allow you to supply alternate definitions +//// of C library functions used by stb_truetype, e.g. if you don't +//// link with the C runtime library. + +#ifdef STB_TRUETYPE_IMPLEMENTATION + // #define your own (u)stbtt_int8/16/32 before including to override this + #ifndef stbtt_uint8 + typedef unsigned char stbtt_uint8; + typedef signed char stbtt_int8; + typedef unsigned short stbtt_uint16; + typedef signed short stbtt_int16; + typedef unsigned int stbtt_uint32; + typedef signed int stbtt_int32; + #endif + + typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; + typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; + + // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h + #ifndef STBTT_ifloor + #include + #define STBTT_ifloor(x) ((int) floor(x)) + #define STBTT_iceil(x) ((int) ceil(x)) + #endif + + #ifndef STBTT_sqrt + #include + #define STBTT_sqrt(x) sqrt(x) + #define STBTT_pow(x,y) pow(x,y) + #endif + + #ifndef STBTT_fmod + #include + #define STBTT_fmod(x,y) fmod(x,y) + #endif + + #ifndef STBTT_cos + #include + #define STBTT_cos(x) cos(x) + #define STBTT_acos(x) acos(x) + #endif + + #ifndef STBTT_fabs + #include + #define STBTT_fabs(x) fabs(x) + #endif + + // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h + #ifndef STBTT_malloc + #include + #define STBTT_malloc(x,u) ((void)(u),malloc(x)) + #define STBTT_free(x,u) ((void)(u),free(x)) + #endif + + #ifndef STBTT_assert + #include + #define STBTT_assert(x) assert(x) + #endif + + #ifndef STBTT_strlen + #include + #define STBTT_strlen(x) strlen(x) + #endif + + #ifndef STBTT_memcpy + #include + #define STBTT_memcpy memcpy + #define STBTT_memset memset + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// INTERFACE +//// +//// + +#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ +#define __STB_INCLUDE_STB_TRUETYPE_H__ + +#ifdef STBTT_STATIC +#define STBTT_DEF static +#else +#define STBTT_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// private structure +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + +////////////////////////////////////////////////////////////////////////////// +// +// TEXTURE BAKING API +// +// If you use this API, you only have to call two functions ever. +// + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; +} stbtt_bakedchar; + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +// if return is positive, the first unused row of the bitmap +// if return is negative, returns the negative of the number of characters that fit +// if return is 0, no characters fit and no rows were used +// This uses a very crappy packing. + +typedef struct +{ + float x0,y0,s0,t0; // top-left + float x1,y1,s1,t1; // bottom-right +} stbtt_aligned_quad; + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +// Call GetBakedQuad with char_index = 'character - first_char', and it +// creates the quad you need to draw and advances the current position. +// +// The coordinate system used assumes y increases downwards. +// +// Characters will extend both above and below the current position; +// see discussion of "BASELINE" above. +// +// It's inefficient; you might want to c&p it and optimize it. + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +// Query the font vertical metrics without having to create a font first. + + +////////////////////////////////////////////////////////////////////////////// +// +// NEW TEXTURE BAKING API +// +// This provides options for packing multiple fonts into one atlas, not +// perfectly but better than nothing. + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; + float xoff2,yoff2; +} stbtt_packedchar; + +typedef struct stbtt_pack_context stbtt_pack_context; +typedef struct stbtt_fontinfo stbtt_fontinfo; +#ifndef STB_RECT_PACK_VERSION +typedef struct stbrp_rect stbrp_rect; +#endif + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +// Initializes a packing context stored in the passed-in stbtt_pack_context. +// Future calls using this context will pack characters into the bitmap passed +// in here: a 1-channel bitmap that is width * height. stride_in_bytes is +// the distance from one row to the next (or 0 to mean they are packed tightly +// together). "padding" is the amount of padding to leave between each +// character (normally you want '1' for bitmaps you'll use as textures with +// bilinear filtering). +// +// Returns 0 on failure, 1 on success. + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +// Cleans up the packing context and frees all memory. + +#define STBTT_POINT_SIZE(x) (-(x)) + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +// Creates character bitmaps from the font_index'th font found in fontdata (use +// font_index=0 if you don't know what that is). It creates num_chars_in_range +// bitmaps for characters with unicode values starting at first_unicode_char_in_range +// and increasing. Data for how to render them is stored in chardata_for_range; +// pass these to stbtt_GetPackedQuad to get back renderable quads. +// +// font_size is the full height of the character from ascender to descender, +// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed +// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() +// and pass that result as 'font_size': +// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall + +typedef struct +{ + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, v_oversample; // don't set these, they're used internally +} stbtt_pack_range; + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +// Creates character bitmaps from multiple ranges of characters stored in +// ranges. This will usually create a better-packed bitmap than multiple +// calls to stbtt_PackFontRange. Note that you can call this multiple +// times within a single PackBegin/PackEnd. + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +// Oversampling a font increases the quality by allowing higher-quality subpixel +// positioning, and is especially valuable at smaller text sizes. +// +// This function sets the amount of oversampling for all following calls to +// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given +// pack context. The default (no oversampling) is achieved by h_oversample=1 +// and v_oversample=1. The total number of pixels required is +// h_oversample*v_oversample larger than the default; for example, 2x2 +// oversampling requires 4x the storage of 1x1. For best results, render +// oversampled textures with bilinear filtering. Look at the readme in +// stb/tests/oversample for information about oversampled fonts +// +// To use with PackFontRangesGather etc., you must set it before calls +// call to PackFontRangesGatherRects. + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +// If skip != 0, this tells stb_truetype to skip any codepoints for which +// there is no corresponding glyph. If skip=0, which is the default, then +// codepoints without a glyph recived the font's "missing character" glyph, +// typically an empty box by convention. + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); + +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +// Calling these functions in sequence is roughly equivalent to calling +// stbtt_PackFontRanges(). If you more control over the packing of multiple +// fonts, or if you want to pack custom data into a font texture, take a look +// at the source to of stbtt_PackFontRanges() and create a custom version +// using these functions, e.g. call GatherRects multiple times, +// building up a single array of rects, then call PackRects once, +// then call RenderIntoRects repeatedly. This may result in a +// better packing than calling PackFontRanges multiple times +// (or it may not). + +// this is an opaque structure that you shouldn't mess with which holds +// all the context needed from PackBegin to PackEnd. +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// FONT LOADING +// +// + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +// This function will determine the number of fonts in a font file. TrueType +// collection (.ttc) files may contain multiple fonts, while TrueType font +// (.ttf) files only contain one font. The number of fonts can be used for +// indexing with the previous function where the index is between zero and one +// less than the total fonts. If an error occurs, -1 is returned. + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); +// Each .ttf/.ttc file may have more than one font. Each font has a sequential +// index number starting from 0. Call this function to get the font offset for +// a given index; it returns -1 if the index is out of range. A regular .ttf +// file will only define one font and it always be at offset 0, so it will +// return '0' for index 0, and -1 for all other indices. + +// The following structure is defined publicly so you can declare one on +// the stack or as a global or etc, but you should treat it as opaque. +struct stbtt_fontinfo +{ + void * userdata; + unsigned char * data; // pointer to .ttf file + int fontstart; // offset of start of font + + int numGlyphs; // number of glyphs, needed for range checking + + int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict +}; + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); +// Given an offset into the file that defines a font, this function builds +// the necessary cached info for the rest of the system. You must allocate +// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't +// need to do anything special to free it, because the contents are pure +// value data with no additional data structures. Returns 0 on failure. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER TO GLYPH-INDEX CONVERSIOn + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); +// If you're going to perform multiple operations on the same character +// and you want a speed-up, call this function with the character you're +// going to process, then use glyph-based functions instead of the +// codepoint-based functions. +// Returns 0 if the character codepoint is not defined in the font. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER PROPERTIES +// + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose "height" is 'pixels' tall. +// Height is measured as the distance from the highest ascender to the lowest +// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics +// and computing: +// scale = pixels / (ascent - descent) +// so if you prefer to measure height by the ascent only, use a similar calculation. + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose EM size is mapped to +// 'pixels' tall. This is probably what traditional APIs compute, but +// I'm not positive. + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +// ascent is the coordinate above the baseline the font extends; descent +// is the coordinate below the baseline the font extends (i.e. it is typically negative) +// lineGap is the spacing between one row's descent and the next row's ascent... +// so you should advance the vertical position by "*ascent - *descent + *lineGap" +// these are expressed in unscaled coordinates, so you must multiply by +// the scale factor for a given size + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 +// table (specific to MS/Windows TTF files). +// +// Returns 1 on success (table present), 0 on failure. + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +// the bounding box around all possible characters + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +// leftSideBearing is the offset from the current horizontal position to the left edge of the character +// advanceWidth is the offset from the current horizontal position to the next horizontal position +// these are expressed in unscaled coordinates + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +// an additional amount to add to the 'advance' value between ch1 and ch2 + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); +// Gets the bounding box of the visible part of the glyph, in unscaled coordinates + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); +// as above, but takes one or more glyph indices for greater efficiency + +typedef struct stbtt_kerningentry +{ + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; +} stbtt_kerningentry; + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +// Retrieves a complete list of all of the kerning pairs provided by the font +// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. +// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) + +////////////////////////////////////////////////////////////////////////////// +// +// GLYPH SHAPES (you probably don't need these, but they have to go before +// the bitmaps for C declaration-order reasons) +// + +#ifndef STBTT_vmove // you can predefine these to use different values (but why?) + enum { + STBTT_vmove=1, + STBTT_vline, + STBTT_vcurve, + STBTT_vcubic + }; +#endif + +#ifndef stbtt_vertex // you can predefine this to use different values + // (we share this with other code at RAD) + #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file + typedef struct + { + stbtt_vertex_type x,y,cx,cy,cx1,cy1; + unsigned char type,padding; + } stbtt_vertex; +#endif + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); +// returns non-zero if nothing is drawn for this glyph + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); +// returns # of vertices and fills *vertices with the pointer to them +// these are expressed in "unscaled" coordinates +// +// The shape is a series of contours. Each one starts with +// a STBTT_moveto, then consists of a series of mixed +// STBTT_lineto and STBTT_curveto segments. A lineto +// draws a line from previous endpoint to its x,y; a curveto +// draws a quadratic bezier from previous endpoint to +// its x,y, using cx,cy as the bezier control point. + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +// frees the data allocated above + +STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); +// fills svg with the character's SVG data. +// returns data size or 0 if SVG not found. + +////////////////////////////////////////////////////////////////////////////// +// +// BITMAP RENDERING +// + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); +// frees the bitmap allocated below + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// allocates a large-enough single-channel 8bpp bitmap and renders the +// specified character/glyph at the specified scale into it, with +// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). +// *width & *height are filled out with the width & height of the bitmap, +// which is stored left-to-right, top-to-bottom. +// +// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap +// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap +// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the +// width and height and positioning info for it first. + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering +// is performed (see stbtt_PackSetOversampling) + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +// get the bbox of the bitmap centered around the glyph origin; so the +// bitmap width is ix1-ix0, height is iy1-iy0, and location to place +// the bitmap top left is (leftSideBearing*scale,iy0). +// (Note that the bitmap uses y-increases-down, but the shape uses +// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel +// shift for the character + +// the following functions are equivalent to the above functions, but operate +// on glyph indices instead of Unicode codepoints (for efficiency) +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); + + +// @TODO: don't expose this structure +typedef struct +{ + int w,h,stride; + unsigned char *pixels; +} stbtt__bitmap; + +// rasterize a shape with quadratic beziers into a bitmap +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC + +////////////////////////////////////////////////////////////////////////////// +// +// Signed Distance Function (or Field) rendering + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); +// frees the SDF bitmap allocated below + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +// These functions compute a discretized SDF field for a single character, suitable for storing +// in a single-channel texture, sampling with bilinear filtering, and testing against +// larger than some threshold to produce scalable fonts. +// info -- the font +// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap +// glyph/codepoint -- the character to generate the SDF for +// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// which allows effects like bit outlines +// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) +// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) +// if positive, > onedge_value is inside; if negative, < onedge_value is inside +// width,height -- output height & width of the SDF bitmap (including padding) +// xoff,yoff -- output origin of the character +// return value -- a 2D array of bytes 0..255, width*height in size +// +// pixel_dist_scale & onedge_value are a scale & bias that allows you to make +// optimal use of the limited 0..255 for your application, trading off precision +// and special effects. SDF values outside the range 0..255 are clamped to 0..255. +// +// Example: +// scale = stbtt_ScaleForPixelHeight(22) +// padding = 5 +// onedge_value = 180 +// pixel_dist_scale = 180/5.0 = 36.0 +// +// This will create an SDF bitmap in which the character is about 22 pixels +// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled +// shape, sample the SDF at each pixel and fill the pixel if the SDF value +// is greater than or equal to 180/255. (You'll actually want to antialias, +// which is beyond the scope of this example.) Additionally, you can compute +// offset outlines (e.g. to stroke the character border inside & outside, +// or only outside). For example, to fill outside the character up to 3 SDF +// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above +// choice of variables maps a range from 5 pixels outside the shape to +// 2 pixels inside the shape to 0..255; this is intended primarily for apply +// outside effects only (the interior range is needed to allow proper +// antialiasing of the font at *smaller* sizes) +// +// The function computes the SDF analytically at each SDF pixel, not by e.g. +// building a higher-res bitmap and approximating it. In theory the quality +// should be as high as possible for an SDF of this size & representation, but +// unclear if this is true in practice (perhaps building a higher-res bitmap +// and computing from that can allow drop-out prevention). +// +// The algorithm has not been optimized at all, so expect it to be slow +// if computing lots of characters or very large sizes. + + + +////////////////////////////////////////////////////////////////////////////// +// +// Finding the right font... +// +// You should really just solve this offline, keep your own tables +// of what font is what, and don't try to get it out of the .ttf file. +// That's because getting it out of the .ttf file is really hard, because +// the names in the file can appear in many possible encodings, in many +// possible languages, and e.g. if you need a case-insensitive comparison, +// the details of that depend on the encoding & language in a complex way +// (actually underspecified in truetype, but also gigantic). +// +// But you can use the provided functions in two possible ways: +// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on +// unicode-encoded names to try to find the font you want; +// you can run this before calling stbtt_InitFont() +// +// stbtt_GetFontNameString() lets you get any of the various strings +// from the file yourself and do your own comparisons on them. +// You have to have called stbtt_InitFont() first. + + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +// returns the offset (not index) of the font that matches, or -1 if none +// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". +// if you use any other flag, use a font name like "Arial"; this checks +// the 'macStyle' header field; i don't know if fonts set this consistently +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +// returns 1/0 whether the first string interpreted as utf8 is identical to +// the second string interpreted as big-endian utf16... useful for strings from next func + +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +// returns the string (which may be big-endian double byte, e.g. for unicode) +// and puts the length in bytes in *length. +// +// some of the values for the IDs are below; for more see the truetype spec: +// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html +// http://www.microsoft.com/typography/otspec/name.htm + +enum { // platformID + STBTT_PLATFORM_ID_UNICODE =0, + STBTT_PLATFORM_ID_MAC =1, + STBTT_PLATFORM_ID_ISO =2, + STBTT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_UNICODE + STBTT_UNICODE_EID_UNICODE_1_0 =0, + STBTT_UNICODE_EID_UNICODE_1_1 =1, + STBTT_UNICODE_EID_ISO_10646 =2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT + STBTT_MS_EID_SYMBOL =0, + STBTT_MS_EID_UNICODE_BMP =1, + STBTT_MS_EID_SHIFTJIS =2, + STBTT_MS_EID_UNICODE_FULL =10 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes + STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, + STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, + STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, + STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 +}; + +enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... + // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs + STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, + STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, + STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, + STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, + STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, + STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D +}; + +enum { // languageID for STBTT_PLATFORM_ID_MAC + STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, + STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, + STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, + STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , + STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , + STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, + STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 +}; + +#ifdef __cplusplus +} +#endif + +#endif // __STB_INCLUDE_STB_TRUETYPE_H__ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// IMPLEMENTATION +//// +//// + +#ifdef STB_TRUETYPE_IMPLEMENTATION + +#ifndef STBTT_MAX_OVERSAMPLE +#define STBTT_MAX_OVERSAMPLE 8 +#endif + +#if STBTT_MAX_OVERSAMPLE > 255 +#error "STBTT_MAX_OVERSAMPLE cannot be > 255" +#endif + +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; + +#ifndef STBTT_RASTERIZER_VERSION +#define STBTT_RASTERIZER_VERSION 2 +#endif + +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + +////////////////////////////////////////////////////////////////////////// +// +// stbtt__buf helpers to parse data from file +// + +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; +} + +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; +} + +static void stbtt__buf_seek(stbtt__buf *b, int o) +{ + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; +} + +static void stbtt__buf_skip(stbtt__buf *b, int o) +{ + stbtt__buf_seek(b, b->cursor + o); +} + +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) +{ + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; +} + +static stbtt__buf stbtt__new_buf(const void *p, size_t size) +{ + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8*) p; + r.size = (int) size; + r.cursor = 0; + return r; +} + +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) + +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) +{ + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; + r.data = b->data + o; + r.size = s; + return r; +} + +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) +{ + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); +} + +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) +{ + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) return b0 - 139; + else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) return stbtt__buf_get16(b); + else if (b0 == 29) return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; +} + +static void stbtt__cff_skip_operand(stbtt__buf *b) { + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) +{ + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) op = stbtt__buf_get8(b) | 0x100; + if (op == key) return stbtt__buf_range(b, start, end-start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) +{ + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) +{ + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) +{ + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i*offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +} + +////////////////////////////////////////////////////////////////////////// +// +// accessors to parse data from file +// + +// on platforms that don't allow misaligned reads, if we want to allow +// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE + +#define ttBYTE(p) (* (stbtt_uint8 *) (p)) +#define ttCHAR(p) (* (stbtt_int8 *) (p)) +#define ttFixed(p) ttLONG(p) + +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } + +#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) + +static int stbtt__isfont(stbtt_uint8 *font) +{ + // check the version number + if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF + if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts + return 0; +} + +// @OPTIMIZE: binary search +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) +{ + stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i=0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16*i; + if (stbtt_tag(data+loc+0, tag)) + return ttULONG(data+loc+8); + } + return 0; +} + +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) +{ + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection+8); + if (index >= n) + return -1; + return ttULONG(font_collection+12+index*4); + } + } + return -1; +} + +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) +{ + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + return ttLONG(font_collection+8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) +{ + stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1]+subrsoff); + return stbtt__cff_get_index(&cff); +} + +// since most people won't use this, find this table the first time it's needed +static int stbtt__get_svg(stbtt_fontinfo *info) +{ + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) +{ + stbtt_uint32 cmap, t; + stbtt_int32 i,numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data+t+4); + else + info->numGlyphs = 0xffff; + + info->svg = -1; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch(ttUSHORT(data+encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data+encoding_record+2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + // Mac/iOS has these + // all the encodingIDs are unicode, so we don't bother to check it + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data+info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) +{ + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes-6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges + stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); + stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) + search += rangeShift*2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange*2); + if (unicode_codepoint > end) + search += searchRange*2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start, last; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + last = ttUSHORT(data + endCount + 2*item); + if (unicode_codepoint < start || unicode_codepoint > last) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + + return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data+index_map+12); + stbtt_int32 low,high; + low = 0; high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); + stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); + if ((stbtt_uint32) unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32) unicode_codepoint > end_char) + low = mid+1; + else { + stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); + if (format == 12) + return start_glyph + unicode_codepoint-start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; +} + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) +{ + return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +} + +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) +{ + v->type = type; + v->x = (stbtt_int16) x; + v->y = (stbtt_int16) y; + v->cx = (stbtt_int16) cx; + v->cy = (stbtt_int16) cy; +} + +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) +{ + int g1,g2; + + STBTT_assert(!info->cff.size); + + if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); + } + + return g1==g2 ? -1 : g1; // if length is 0, return -1 +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); + +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; + + if (x0) *x0 = ttSHORT(info->data + g + 2); + if (y0) *y0 = ttSHORT(info->data + g + 4); + if (x1) *x1 = ttSHORT(info->data + g + 6); + if (y1) *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) +{ + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, + stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) +{ + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices=0; + int num_vertices=0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags=0,flagcount; + stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; + stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); + + m = n + 2*numberOfContours; // a loose bound on how many vertices we might need + vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated + + // first load flags + + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off+i].type = flags; + } + + // now load x coordinates + x=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? + } else { + if (!(flags & 16)) { + x = x + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].x = (stbtt_int16) x; + } + + // now load y coordinates + y=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? + } else { + if (!(flags & 32)) { + y = y + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].y = (stbtt_int16) y; + } + + // now convert them to our format + num_vertices=0; + sx = sy = cx = cy = scx = scy = 0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + x = (stbtt_int16) vertices[off+i].x; + y = (stbtt_int16) vertices[off+i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find a point on the curve + // where we can start, and we need to save some state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + // next point is also a curve point, so interpolate an on-point curve + sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; + sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32) vertices[off+i+1].x; + sy = (stbtt_int32) vertices[off+i+1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours+j*2); + ++j; + } else { + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + } else if (numberOfContours < 0) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1,0,0,1,0,0}, m, n; + + flags = ttSHORT(comp); comp+=2; + gidx = ttSHORT(comp); comp+=2; + + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); comp+=2; + mtx[5] = ttSHORT(comp); comp+=2; + } else { + mtx[4] = ttCHAR(comp); comp+=1; + mtx[5] = ttCHAR(comp); comp+=1; + } + } + else { + // @TODO handle matching point + STBTT_assert(0); + } + if (flags & (1<<3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } + + // Find transformation scales. + m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex* v = &comp_verts[i]; + stbtt_vertex_type x,y; + x=v->x; y=v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + x=v->cx; y=v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); + if (!tmp) { + if (vertices) STBTT_free(vertices, info->userdata); + if (comp_verts) STBTT_free(comp_verts, info->userdata); + return 0; + } + if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); + STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); + if (vertices) STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; + } + // More components ? + more = flags & (1<<5); + } + } else { + // numberOfCounters == 0, do nothing + } + + *pvertices = vertices; + return num_vertices; +} + +typedef struct +{ + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; +} stbtt__csctx; + +#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) +{ + if (x > c->max_x || !c->started) c->max_x = x; + if (y > c->max_y || !c->started) c->max_y = y; + if (x < c->min_x || !c->started) c->min_x = x; + if (y < c->min_y || !c->started) c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) +{ + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) +{ + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) +{ + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) +{ + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) +{ + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) +{ + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); +} + +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) +{ + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; + +#define STBTT__CSERR(s) (0) + + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; + + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: // rlineto + if (sp < 2) return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; + + case 0x1F: // hvcurveto + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); + i += 4; + } + break; + + case 0x08: // rrcurveto + if (sp < 6) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x18: // rcurveline + if (sp < 8) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + case 0x19: // rlinecurve + if (sp < 8) return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { f = s[i]; i++; } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); + f = 0.0; + } + break; + + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // FALLTHROUGH + case 0x1D: // callgsubr + if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); + v = (int) s[--sp]; + if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; + + case 0x0B: // return + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + //fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1+dx2+dx3+dx4+dx5; + dy = dy1+dy2+dy3+dy4+dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + default: + return STBTT__CSERR("unimplemented"); + } + } break; + + default: + if (b0 != 255 && b0 != 28 && b0 < 32) + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) sp = 0; + } + return STBTT__CSERR("no endchar"); + +#undef STBTT__CSERR +} + +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) *x0 = r ? c.min_x : 0; + if (y0) *y0 = r ? c.min_y : 0; + if (x1) *x1 = r ? c.max_x : 0; + if (y1) *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) +{ + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); + } else { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); + } +} + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) +{ + stbtt_uint8 *data = info->data + info->kern; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + return ttUSHORT(data+10); +} + +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) +{ + stbtt_uint8 *data = info->data + info->kern; + int k, length; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + length = ttUSHORT(data+10); + if (table_length < length) + length = table_length; + + for (k = 0; k < length; k++) + { + table[k].glyph1 = ttUSHORT(data+18+(k*6)); + table[k].glyph2 = ttUSHORT(data+20+(k*6)); + table[k].advance = ttSHORT(data+22+(k*6)); + } + + return length; +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + l = 0; + r = ttUSHORT(data+10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data+18+(m*6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data+22+(m*6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +{ + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch (coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; + } + } + break; + } + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } + } + break; + } + + default: return -1; // unsupported + } + + return -1; +} + +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) +{ + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch (classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + break; + } + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + break; + } + + default: + return -1; // Unsupported definition type, return an error. + } + + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; +} + +// Define to STBTT_assert(x) if you want to break on unimplemented formats. +#define STBTT_GPOS_TODO_assert(x) + +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i, sti; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i= pairSetCount) return 0; + + needle=glyph2; + r=pairValueCount-1; + l=0; + + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } else + return 0; + break; + } + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + stbtt_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; + } + + default: + return 0; // Unsupported position format + } + } + } + + return 0; +} + +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) +{ + int xAdvance = 0; + + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + + return xAdvance; +} + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) +{ + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +} + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) +{ + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +} + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) +{ + if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); + if (descent) *descent = ttSHORT(info->data+info->hhea + 6); + if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +} + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) +{ + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); + if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); + if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); + return 1; +} + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) +{ + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); +} + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) +{ + int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); + return (float) height / fheight; +} + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) +{ + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; +} + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) +{ + STBTT_free(v, info->userdata); +} + +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) +{ + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); + + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; + + for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; +} + +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) +{ + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; + + if (info->svg == 0) + return 0; + + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } +} + +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) +{ + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +} + +////////////////////////////////////////////////////////////////////////////// +// +// antialiasing software rasterizer +// + +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + // e.g. space character + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels get touched)? + if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); + if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); + if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); + } +} + +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Rasterizer + +typedef struct stbtt__hheap_chunk +{ + struct stbtt__hheap_chunk *next; +} stbtt__hheap_chunk; + +typedef struct stbtt__hheap +{ + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; +} stbtt__hheap; + +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) +{ + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = * (void **) p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; + } +} + +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) +{ + *(void **) p = hh->first_free; + hh->first_free = p; +} + +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) +{ + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } +} + +typedef struct stbtt__edge { + float x0,y0, x1,y1; + int invert; +} stbtt__edge; + + +typedef struct stbtt__active_edge +{ + struct stbtt__active_edge *next; + #if STBTT_RASTERIZER_VERSION==1 + int x,dx; + float ey; + int direction; + #elif STBTT_RASTERIZER_VERSION==2 + float fx,fdx,fdy; + float direction; + float sy; + float ey; + #else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" + #endif +} stbtt__active_edge; + +#if STBTT_RASTERIZER_VERSION == 1 +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX-1) + +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) return z; + + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + + z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; + + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; +} +#elif STBTT_RASTERIZER_VERSION == 2 +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + //STBTT_assert(e->y0 <= start_point); + if (!z) return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#if STBTT_RASTERIZER_VERSION == 1 +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) +{ + // non-zero winding fill + int x0=0, w=0; + + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->direction; + } else { + int x1 = e->x; w += e->direction; + // if we went to zero, we need to draw + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8) max_weight; + } + } + } + } + + e = e->next; + } +} + +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; + + if (result->w > 512) + scanline = (unsigned char *) STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; + + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; + + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s=0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for(;;) { + int changed=0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; + + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); + + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} + +#elif STBTT_RASTERIZER_VERSION == 2 + +// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 +// (i.e. it has already been clipped to those) +static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) +{ + if (y0 == y1) return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) return; + if (y1 < e->sy) return; + if (y0 < e->sy) { + x0 += (x1-x0) * (e->sy - y0) / (y1-y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1-x0) * (e->ey - y1) / (y1-y0); + y1 = e->ey; + } + + if (x0 == x) + STBTT_assert(x1 <= x+1); + else if (x0 == x+1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x+1) + STBTT_assert(x1 >= x+1); + else + STBTT_assert(x1 >= x && x1 <= x+1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1-y0); + else if (x0 >= x+1 && x1 >= x+1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); + scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position + } +} + +static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) +{ + STBTT_assert(top_width >= 0); + STBTT_assert(bottom_width >= 0); + return (top_width + bottom_width) / 2.0f * height; +} + +static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) +{ + return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); +} + +static float stbtt__sized_triangle_area(float height, float width) +{ + return height * width / 2; +} + +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) +{ + float y_bottom = y_top+1; + + while (e) { + // brute force every pixel + + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); + + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); + stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0,sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; + } else { + x_top = x0; + sy0 = y_top; + } + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; + } else { + x_bottom = xb; + sy1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int) x_top == (int) x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int) x_top; + height = (sy1 - sy0) * e->direction; + STBTT_assert(x >= 0 && x < len); + scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); + scanline_fill[x] += height; // everything right of this pixel is filled + } else { + int x,x1,x2; + float y_crossing, y_final, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + } + STBTT_assert(dy >= 0); + STBTT_assert(dx >= 0); + + x1 = (int) x_top; + x2 = (int) x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = y_top + dy * (x1+1 - x0); + + // compute intersection with y axis at x2 + y_final = y_top + dy * (x2 - x0); + + // x1 x_top x2 x_bottom + // y_top +------|-----+------------+------------+--------|---+------------+ + // | | | | | | + // | | | | | | + // sy0 | Txxxxx|............|............|............|............| + // y_crossing | *xxxxx.......|............|............|............| + // | | xxxxx..|............|............|............| + // | | /- xx*xxxx........|............|............| + // | | dy < | xxxxxx..|............|............| + // y_final | | \- | xx*xxx.........|............| + // sy1 | | | | xxxxxB...|............| + // | | | | | | + // | | | | | | + // y_bottom +------------+------------+------------+------------+------------+ + // + // goal is to measure the area covered by '.' in each pixel + + // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 + // @TODO: maybe test against sy1 rather than y_bottom? + if (y_crossing > y_bottom) + y_crossing = y_bottom; + + sign = e->direction; + + // area of the rectangle covered from sy0..y_crossing + area = sign * (y_crossing-sy0); + + // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) + scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); + + // check if final y_crossing is blown up; no test case for this + if (y_final > y_bottom) { + y_final = y_bottom; + dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom + } + + // in second pixel, area covered by line segment found in first pixel + // is always a rectangle 1 wide * the height of that line segment; this + // is exactly what the variable 'area' stores. it also gets a contribution + // from the line segment within it. the THIRD pixel will get the first + // pixel's rectangle contribution, the second pixel's rectangle contribution, + // and its own contribution. the 'own contribution' is the same in every pixel except + // the leftmost and rightmost, a trapezoid that slides down in each pixel. + // the second pixel's contribution to the third pixel will be the + // rectangle 1 wide times the height change in the second pixel, which is dy. + + step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, + // which multiplied by 1-pixel-width is how much pixel area changes for each step in x + // so the area advances by 'step' every time + + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; // area of trapezoid is 1*step/2 + area += step; + } + STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down + STBTT_assert(sy1 > y_final-0.01f); + + // area covered in the last pixel is the rectangle from all the pixels to the left, + // plus the trapezoid filled by the line segment in this pixel all the way to the right edge + scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); + + // the rest of the line is filled based on the total height of the line segment in this pixel + scanline_fill[x2] += sign * (sy1-sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + // note though that this does happen some of the time because + // x_top and x_bottom can be extrapolated at the top & bottom of + // the shape and actually lie outside the bounding box + int x; + for (x=0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any intersection + // with left or right edges can be handled by splitting into two (or three) + // regions. intersections with top & bottom do not necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & right edges, + // then used some simple logic to produce up to three segments in sorted order + // from top-to-bottom. however, this had a problem: if an x edge was epsilon + // across the x border, then the corresponding y position might not be distinct + // from the other y segment, and it might ignored as an empty segment. to avoid + // that, we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x1 && x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); + } + } + } + } + e = e->next; + } +} + +// directly AA rasterize edges w/o supersampling +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0, i; + float scanline_data[129], *scanline, *scanline2; + + STBTT__NOTUSED(vsubsample); + + if (result->w > 64) + scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); + else + scanline = scanline_data; + + scanline2 = scanline + result->w; + + y = off_y; + e[n].y0 = (float) (off_y + result->h) + 1; + + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; + + STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); + + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list + } + } + + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds + // insert at front + z->next = active; + active = z; + } + } + ++e; + } + + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i=0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float) STBTT_fabs(k)*255 + 0.5f; + m = (int) k; + if (m > 255) m = 255; + result->pixels[j*result->stride + i] = (unsigned char) m; + } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + + ++y; + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) + +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) +{ + int i,j; + for (i=1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j-1]; + int c = STBTT__COMPARE(a,b); + if (!c) break; + p[j] = p[j-1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) +{ + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01,c12,c,m,i,j; + + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0],&p[m]); + c12 = STBTT__COMPARE(&p[m],&p[n-1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0],&p[n-1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i=1; + j=n-1; + for(;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;;++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!STBTT__COMPARE(&p[0], &p[j])) break; + } + /* make sure we haven't crossed */ + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n-i)) { + stbtt__sort_edges_quicksort(p,j); + p = p+i; + n = n-i; + } else { + stbtt__sort_edges_quicksort(p+i, n-i); + n = j; + } + } +} + +static void stbtt__sort_edges(stbtt__edge *p, int n) +{ + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); +} + +typedef struct +{ + float x,y; +} stbtt__point; + +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) +{ + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n,i,j,k,m; +#if STBTT_RASTERIZER_VERSION == 1 + int vsubsample = result->h < 8 ? 15 : 5; +#elif STBTT_RASTERIZER_VERSION == 2 + int vsubsample = 1; +#else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel + if (e == 0) return; + n = 0; + + m=0; + for (i=0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i]-1; + for (k=0; k < wcount[i]; j=k++) { + int a=k,b=j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a=j,b=k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } + + // now sort the edges by their highest point (should snap to integer, and then by x) + //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); + + // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + + STBTT_free(e, userdata); +} + +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) +{ + if (!points) return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; +} + +// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) +{ + // midpoint + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + // versus directly drawn line + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA + stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x2,y2); + *num_points = *num_points+1; + } + return 1; +} + +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) +{ + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1-x0; + float dy0 = y1-y0; + float dx1 = x2-x1; + float dy1 = y2-y1; + float dx2 = x3-x2; + float dy2 = y3-y2; + float dx = x3-x0; + float dy = y3-y0; + float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); + float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); + float flatness_squared = longlen*longlen-shortlen*shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0+x1)/2; + float y01 = (y0+y1)/2; + float x12 = (x1+x2)/2; + float y12 = (y1+y2)/2; + float x23 = (x2+x3)/2; + float y23 = (y2+y3)/2; + + float xa = (x01+x12)/2; + float ya = (y01+y12)/2; + float xb = (x12+x23)/2; + float yb = (y12+y23)/2; + + float mx = (xa+xb)/2; + float my = (ya+yb)/2; + + stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x3,y3); + *num_points = *num_points+1; + } +} + +// returns number of contours +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) +{ + stbtt__point *points=0; + int num_points=0; + + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i,n=0,start=0, pass; + + // count how many "moves" there are to get the contour count + for (i=0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; + + *num_contours = n; + if (n == 0) return 0; + + *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + // make two passes through the points so we don't need to realloc + for (pass=0; pass < 2; ++pass) { + float x=0,y=0; + if (pass == 1) { + points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); + if (points == NULL) goto error; + } + num_points = 0; + n= -1; + for (i=0; i < num_verts; ++i) { + switch (vertices[i].type) { + case STBTT_vmove: + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x,y); + break; + case STBTT_vline: + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vcurve: + stbtt__tesselate_curve(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + } + } + (*contour_lengths)[n] = num_points - start; + } + + return points; +error: + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; +} + +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) +{ + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } +} + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + int ix0,iy0,ix1,iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error + + if (width ) *width = gbm.w; + if (height) *height = gbm.h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; + + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) +{ + int ix0,iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; + + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + + STBTT_free(vertices, info->userdata); +} + +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) +{ + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +} + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-CRAPPY packing to keep source code small + +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) +{ + float scale; + int x,y,bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + x=y=1; + bottom_y = 1; + + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + + for (i=0; i < num_chars; ++i) { + int advance, lsb, x0,y0,x1,y1,gw,gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); + gw = x1-x0; + gh = y1-y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x+gw < pw); + STBTT_assert(y+gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); + chardata[i].x0 = (stbtt_int16) x; + chardata[i].y0 = (stbtt_int16) y; + chardata[i].x1 = (stbtt_int16) (x + gw); + chardata[i].y1 = (stbtt_int16) (y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float) x0; + chardata[i].yoff = (float) y0; + x = x + gw + 1; + if (y+gh+1 > bottom_y) + bottom_y = y+gh+1; + } + return bottom_y; +} + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) +{ + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); + + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// rectangle packing replacement routines if you don't have stb_rect_pack.h +// + +#ifndef STB_RECT_PACK_VERSION + +typedef int stbrp_coord; + +//////////////////////////////////////////////////////////////////////////////////// +// // +// // +// COMPILER WARNING ?!?!? // +// // +// // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// // +//////////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int width,height; + int x,y,bottom_y; +} stbrp_context; + +typedef struct +{ + unsigned char x; +} stbrp_node; + +struct stbrp_rect +{ + stbrp_coord x,y; + int id,w,h,was_packed; +}; + +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) +{ + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) +{ + int i; + for (i=0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for ( ; i < num_rects; ++i) + rects[i].was_packed = 0; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If +// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) +{ + stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) STBTT_free(context, alloc_context); + if (nodes != NULL) STBTT_free(nodes , alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; + + stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + + if (pixels) + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + + return 1; +} + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) +{ + STBTT_free(spc->nodes , spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) +{ + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) +{ + spc->skip_missing = skip; +} + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char) (total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < h; ++i) { + STBTT_assert(pixels[i*stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + + pixels += 1; + } +} + +static float stbtt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k; + int missing_glyph_added = 0; + + k=0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char) spc->h_oversample; + ranges[i].v_oversample = (unsigned char) spc->v_oversample; + for (j=0; j < ranges[i].num_chars; ++j) { + int x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + if (glyph == 0) + missing_glyph_added = 1; + } + ++k; + } + } + + return k; +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, + output, + out_w - (prefilter_x - 1), + out_h - (prefilter_y - 1), + out_stride, + scale_x, + scale_y, + shift_x, + shift_y, + glyph); + + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k, missing_glyph = -1, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h,recip_v,sub_x,sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j=0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord) spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + &x0,&y0,&x1,&y1); + stbtt_MakeGlyphBitmapSubpixel(info, + spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w - spc->h_oversample+1, + r->h - spc->v_oversample+1, + spc->stride_in_bytes, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + + bc->x0 = (stbtt_int16) r->x; + bc->y0 = (stbtt_int16) r->y; + bc->x1 = (stbtt_int16) (r->x + r->w); + bc->y1 = (stbtt_int16) (r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; + } else { + return_value = 0; // if any fail, report failure + } + + ++k; + } + } + + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; +} + +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) +{ + stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); +} + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) +{ + stbtt_fontinfo info; + int i,j,n, return_value = 1; + //stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; + + // flag all characters as NOT packed + for (i=0; i < num_ranges; ++i) + for (j=0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = + ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i=0; i < num_ranges; ++i) + n += ranges[i].num_chars; + + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; + + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + + stbtt_PackFontRangesPackRects(spc, rects, n); + + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + + STBTT_free(rects, spc->user_allocator_context); + return return_value; +} + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) +{ + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +} + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) +{ + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float) i_ascent * scale; + *descent = (float) i_descent * scale; + *lineGap = (float) i_lineGap * scale; +} + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) +{ + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; + + if (align_to_integer) { + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// sdf computation +// + +#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) + +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) +{ + float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; + float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; + float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; + float roperp = orig[1]*ray[0] - orig[0]*ray[1]; + + float a = q0perp - 2*q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; + + float s0 = 0., s1 = 0.; + int num_s = 0; + + if (a != 0.0) { + float discr = b*b - a*c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float) STBTT_sqrt(discr); + s0 = (b+d) * rcpna; + s1 = (b-d) * rcpna; + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) s0 = s1; + ++num_s; + } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0]*rayn_x + q0[1]*rayn_y; + float q1d = q1[0]*rayn_x + q1[1]*rayn_y; + float q2d = q2[0]*rayn_x + q2[1]*rayn_y; + float rod = orig[0]*rayn_x + orig[1]*rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; + hits[0][1] = a*s0+b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; + hits[1][1] = a*s1+b; + return 2; + } else { + return 1; + } + } +} + +static int equal(float *a, float *b) +{ + return (a[0] == b[0] && a[1] == b[1]); +} + +static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) +{ + int i; + float orig[2], ray[2] = { 1, 0 }; + float y_frac; + int winding = 0; + + // make sure y never passes through a vertex of the shape + y_frac = (float) STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; + + orig[0] = x; + orig[1] = y; + + // test a ray from (-infinity,y) to (x,y) + for (i=0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; + int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; + int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; + int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; + int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); + int by = STBTT_max(y0,STBTT_max(y1,y2)); + if (y > ay && y < by && x > ax) { + float q0[2],q1[2],q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0,q1) || equal(q1,q2)) { + x0 = (int)verts[i-1].x; + y0 = (int)verts[i-1].y; + x1 = (int)verts[i ].x; + y1 = (int)verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } + } + } + } + return winding; +} + +static float stbtt__cuberoot( float x ) +{ + if (x<0) + return -(float) STBTT_pow(-x,1.0f/3.0f); + else + return (float) STBTT_pow( x,1.0f/3.0f); +} + +// x^3 + a*x^2 + b*x + c = 0 +static int stbtt__solve_cubic(float a, float b, float c, float* r) +{ + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; + float p3 = p*p*p; + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); + float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); + + //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? + //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); + //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } +} + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + float scale_x = scale, scale_y = scale; + int ix0,iy0,ix1,iy1; + int w,h; + unsigned char *data; + + if (scale == 0) return NULL; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; + + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; + + w = (ix1 - ix0); + h = (iy1 - iy0); + + if (width ) *width = w; + if (height) *height = h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + // invert for y-downwards bitmaps + scale_y = -scale_y; + + { + // distance from singular values (in the same units as the pixel grid) + const float eps = 1./1024, eps2 = eps*eps; + int x,y,i,j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *) STBTT_malloc(w * h, info->userdata); + precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); + + for (i=0,j=num_verts-1; i < num_verts; j=i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; + float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); + precompute[i] = (dist < eps) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; + float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; + float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float len2 = bx*bx + by*by; + if (len2 >= eps2) + precompute[i] = 1.0f / len2; + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } + + for (y=iy0; y < iy1; ++y) { + for (x=ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float) x + 0.5f; + float sy = (float) y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); + + int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path + + for (i=0; i < num_verts; ++i) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + + if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + // coarse culling against bbox + //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) + dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1-x0, dy = y1-y0; + float px = x0-sx, py = y0-sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy + // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px*dx + py*dy) / (dx*dx + dy*dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; + } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; + float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; + float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); + float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); + float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); + float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); + // coarse culling against bbox to avoid computing cubic unnecessarily + if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { + int num=0; + float ax = x1-x0, ay = y1-y0; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3] = {0.f,0.f,0.f}; + float px,py,t,it,dist2; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula + float a = 3*(ax*bx + ay*by); + float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); + float c = mx*ax+my*ay; + if (STBTT_fabs(a) < eps2) { // if a is 0, it's linear + if (STBTT_fabs(b) >= eps2) { + res[num++] = -c/b; + } + } else { + float discriminant = b*b - 4*a*c; + if (discriminant < 0) + num = 0; + else { + float root = (float) STBTT_sqrt(discriminant); + res[0] = (-b - root)/(2*a); + res[1] = (-b + root)/(2*a); + num = 2; // don't bother distinguishing 1-solution case, as code below will still work + } + } + } else { + float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point + float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; + float d = (mx*ax+my*ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; + } + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; +} + +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// font name matching -- recommended not to use this +// + +// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{ + stbtt_int32 i=0; + + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0]*256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) return -1; + if (s1[i++] != ch) return -1; + } else if (ch < 0x800) { + if (i+1 >= len1) return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2]*256 + s2[3]; + if (i+3 >= len1) return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; + s2 += 2; // plus another 2 below + len2 -= 2; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i+2 >= len1) return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; + } + s2 += 2; + len2 -= 2; + } + return i; +} + +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +{ + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +} + +// returns results in whatever encoding you request... but note that 2-byte encodings +// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) +{ + stbtt_int32 i,count,stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return NULL; + + count = ttUSHORT(fc+nm+2); + stringOffset = nm + ttUSHORT(fc+nm+4); + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) + && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { + *length = ttUSHORT(fc+loc+8); + return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); + } + } + return NULL; +} + +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) +{ + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc+nm+2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); + + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc+loc+6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc+loc+8); + stbtt_int32 off = ttUSHORT(fc+loc+10); + + // check if there's a prefix match + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & language + if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { + slen = ttUSHORT(fc+loc+12+8); + off = ttUSHORT(fc+loc+12+10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) + return 1; + } + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } + } + + // @TODO handle other encodings + } + } + return 0; +} + +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) +{ + stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); + stbtt_uint32 nm,hd; + if (!stbtt__isfont(fc+offset)) return 0; + + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; + } + + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return 0; + + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } + + return 0; +} + +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) +{ + stbtt_int32 i; + for (i=0;;++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) return off; + if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) + return off; + } +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, + float pixel_height, unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, stbtt_bakedchar *chardata) +{ + return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +} + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) +{ + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +} + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) +{ + return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +} + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) +{ + return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +} + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) +{ + return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +} + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +{ + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif // STB_TRUETYPE_IMPLEMENTATION + + +// FULL VERSION HISTORY +// +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) allow user-defined fabs() replacement +// fix memory leak if fontsize=0.0 +// fix warning from duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// allow PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) +// also more precise AA rasterizer, except if shapes overlap +// remove need for STBTT_sort +// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC +// 1.04 (2015-04-15) typo in example +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes +// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ +// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// non-oversampled; STBTT_POINT_SIZE for packed case only +// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling +// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) +// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID +// 0.8b (2014-07-07) fix a warning +// 0.8 (2014-05-25) fix a few more warnings +// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back +// 0.6c (2012-07-24) improve documentation +// 0.6b (2012-07-20) fix a few more warnings +// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, +// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty +// 0.5 (2011-12-09) bugfixes: +// subpixel glyph renderer computed wrong bounding box +// first vertex of shape can be off-curve (FreeSans) +// 0.4b (2011-12-03) fixed an error in the font baking example +// 0.4 (2011-12-01) kerning, subpixel rendering (tor) +// bugfixes for: +// codepoint-to-glyph conversion using table fmt=12 +// codepoint-to-glyph conversion using table fmt=4 +// stbtt_GetBakedQuad with non-square texture (Zer) +// updated Hello World! sample to use kerning and subpixel +// fixed some warnings +// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) +// userdata, malloc-from-userdata, non-zero fill (stb) +// 0.2 (2009-03-11) Fix unsigned/signed char warnings +// 0.1 (2009-03-09) First public release +// + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/widget/milsko/milskosrc/include/Mw/Abstract/CharSet.h b/widget/milsko/milskosrc/include/Mw/Abstract/CharSet.h new file mode 100644 index 0000000000..f0a42f7d03 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Abstract/CharSet.h @@ -0,0 +1,22 @@ +/*! + * @file Mw/Abstract/CharSet.h + * @brief CharSet + */ +#ifndef __MW_ABSTRACT_CHARSET_H__ +#define __MW_ABSTRACT_CHARSET_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +MWDECL char* MWAPI MwACPToUTF8(const char* input); + +MWDECL char* MWAPI MwUTF8ToACP(const char* input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Abstract/Directory.h b/widget/milsko/milskosrc/include/Mw/Abstract/Directory.h new file mode 100644 index 0000000000..1e1db49cc2 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Abstract/Directory.h @@ -0,0 +1,59 @@ +/*! + * @file Mw/Abstract/Directory.h + * @brief Directory functions + */ +#ifndef __MW_ABSTRACT_DIRECTORY_H__ +#define __MW_ABSTRACT_DIRECTORY_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Opens a directory + * @param path Path + * @return Handle + */ +MWDECL void* MWAPI MwDirectoryOpen(const char* path); + +/*! + * @brief Closes a directory + * @param handle Handle + */ +MWDECL void MWAPI MwDirectoryClose(void* handle); + +/*! + * @brief Reads a directory + * @param handle Handle + * @return Directory entry + */ +MWDECL MwDirectoryEntry* MWAPI MwDirectoryRead(void* handle); + +/*! + * @brief Frees a directory entry + * @param entry Entry + */ +MWDECL void MWAPI MwDirectoryFreeEntry(MwDirectoryEntry* entry); + +/*! + * @brief Gets a current directory + * @param Directory + */ +MWDECL char* MWAPI MwDirectoryCurrent(void); + +/*! + * @brief Joins 2 paths + * @param a Path + * @param b Path + * @return Path + */ +MWDECL char* MWAPI MwDirectoryJoin(char* a, char* b); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Abstract/Dynamic.h b/widget/milsko/milskosrc/include/Mw/Abstract/Dynamic.h new file mode 100644 index 0000000000..ead5070613 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Abstract/Dynamic.h @@ -0,0 +1,38 @@ +/*! + * @file Mw/Abstract/Dynamic.h + * @brief Dynamic library + */ +#ifndef __MW_ABSTRACT_DYNAMIC_H__ +#define __MW_ABSTRACT_DYNAMIC_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Opens a dynamic library + * @param path Path + * @return Handle + */ +MWDECL void* MWAPI MwDynamicOpen(const char* path); + +/*! + * @brief Gets a symbol from the dynamic library + * @param handle Handle + * @param symbol Symbol + */ +MWDECL void* MWAPI MwDynamicSymbol(void* handle, const char* symbol); + +/*! + * @brief Closes a dynamic library + * @param handle Handle + */ +MWDECL void MWAPI MwDynamicClose(void* handle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Abstract/Time.h b/widget/milsko/milskosrc/include/Mw/Abstract/Time.h new file mode 100644 index 0000000000..c8ffbf6bfd --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Abstract/Time.h @@ -0,0 +1,30 @@ +/*! + * @file Mw/Abstract/Time.h + * @brief Time + */ +#ifndef __MW_ABSTRACT_TIME_H__ +#define __MW_ABSTRACT_TIME_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Sleeps for milliseconds + * @param ms Milliseconds + */ +MWDECL void MWAPI MwTimeSleep(int ms); + +/*! + * @brief Gets a monotonic time + * @return Monotonic time + */ +MWDECL long MWAPI MwTimeGetTick(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/BaseTypes.h b/widget/milsko/milskosrc/include/Mw/BaseTypes.h new file mode 100644 index 0000000000..313215eca1 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/BaseTypes.h @@ -0,0 +1,113 @@ +/*! + * @file Mw/BaseTypes.h + * @brief Base type definitions + */ +#ifndef __MW_BASETYPES_H__ +#define __MW_BASETYPES_H__ + +typedef struct _MwPoint MwPoint; +typedef struct _MwRect MwRect; +typedef struct _MwSizeHints MwSizeHints; +typedef struct _MwFont MwFont; +typedef struct _MwCursor MwCursor; +typedef struct _MwRGB MwRGB; + +typedef unsigned char MwBool; +#define MwTRUE ((MwBool)1) +#define MwFALSE ((MwBool)0) + +#if __STDC_VERSION__ >= 199901L +#include + +typedef int64_t MwI64; +typedef uint64_t MwU64; + +typedef int32_t MwI32; +typedef uint32_t MwU32; + +typedef int16_t MwI16; +typedef uint16_t MwU16; + +typedef int8_t MwI8; +typedef uint8_t MwU8; + +#define MW_OTHER_TYPES_DEFINED +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) || defined(__clang__)) +typedef long long MwI64; +typedef unsigned long long MwU64; +#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) +typedef __int64 MwI64; +typedef unsigned __int64 MwU64; + +typedef __int32 MwI32; +typedef unsigned __int32 MwU32; + +typedef __int16 MwI16; +typedef unsigned __int16 MwU16; + +typedef __int8 MwI8; +typedef unsigned __int8 MwU8; + +#define MW_OTHER_TYPES_DEFINED +#else +/* out of hope */ +typedef long MwI64; +typedef unsigned long MwU64; +#endif + +#ifdef MW_OTHER_TYPES_DEFINED +#undef MW_OTHER_TYPES_DEFINED +#else +typedef int MwI32; +typedef unsigned int MwU32; + +typedef short MwI16; +typedef unsigned short MwU16; + +typedef signed char MwI8; +typedef unsigned char MwU8; +#endif + +typedef MwI64 MwOffset; + +struct _MwPoint { + int x; + int y; +}; + +struct _MwRect { + int x; + int y; + int width; + int height; +}; + +struct _MwSizeHints { + int min_width; + int min_height; + int max_width; + int max_height; +}; + +#define MwCursorDataHeight 16 +struct _MwCursor { + int width; + int height; + int x; + int y; + unsigned int data[MwCursorDataHeight]; +}; + +struct _MwFont { + int left; + int top; + unsigned char data[16]; +}; + +struct _MwRGB { + MwU16 red; + MwU16 green; + MwU16 blue; +}; + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Constants.h b/widget/milsko/milskosrc/include/Mw/Constants.h new file mode 100644 index 0000000000..15853ff7bc --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Constants.h @@ -0,0 +1,142 @@ +/*! + * @file Mw/Constants.h + * @brief Constants + */ +#ifndef __MW_CONSTANTS_H__ +#define __MW_CONSTANTS_H__ + +/*! + * @brief Direction enumeration + */ +enum MwDIRECTION { + MwNORTH = 0, + MwSOUTH, + MwEAST, + MwWEST +}; + +/*! + * @brief Orientation + */ +enum MwORIENTATION { + MwVERTICAL = 0, + MwHORIZONTAL +}; + +/*! + * @brief Alignment + */ +enum MwALIGNMENT { + MwALIGNMENT_CENTER = 0, + MwALIGNMENT_BEGINNING, + MwALIGNMENT_END +}; + +/*! + * @brief Default + */ +#define MwDEFAULT 0x0fffffff + +/*! + * @brief Directory entry type + */ +enum MwDIRECTORY_TYPE { + MwDIRECTORY_FILE = 0, + MwDIRECTORY_DIRECTORY +}; + +/*! + * @brief Icon mask + */ +#define MwMB_ICONMASK 0xf + +enum MwMB_ICON { + MwMB_ICONWARNING = 0x1, + MwMB_ICONINFO, + MwMB_ICONNOTE, + MwMB_ICONNEWS, + MwMB_ICONERROR, + MwMB_ICONCLOCK +}; + +/*! + * @brief Button mask + */ +#define MwMB_BUTTONMASK 0xf0 + +/*! + * @brief OK button + */ +#define MwMB_BUTTONOK 0x10 + +/*! + * @brief Cancel button + */ +#define MwMB_BUTTONCANCEL 0x20 + +/*! + * @brief Yes button + */ +#define MwMB_BUTTONYES 0x40 + +/*! + * @brief No button + */ +#define MwMB_BUTTONNO 0x80 + +/*! + * @brief Ok and Cancel button + */ +#define MwMB_BUTTONOKCANCEL (MwMB_BUTTONCANCEL | MwMB_BUTTONOK) + +/*! + * @brief Yes and No button + */ +#define MwMB_BUTTONYESNO (MwMB_BUTTONYES | MwMB_BUTTONNO) + +/*! + * @brief Yes, No and Cancel button + */ +#define MwMB_BUTTONYESNOCANCEL (MwMB_BUTTONYES | MwMB_BUTTONNO | MwMB_BUTTONCANCEL) + +/* Whether or not GetXY/SetXY works with global or local coordinates */ +enum MwCOORDINATE { + MwCOORDINATE_GLOBAL = 0, + MwCOORDINATE_LOCAL, +}; + +/* The clipboard type that MwGetClipboard should return */ +enum MwCLIPBOARD { + /* the clipboard that is present on every platform that supports it */ + MwCLIPBOARD_MAIN = 0, + /* the "primary" clipboard that Wayland stores to emulate X11's behavior. */ + MwCLIPBOARD_PRIMARY, +}; + +enum MwMOUSE { + MwMOUSE_LEFT = 1, + MwMOUSE_MIDDLE, + MwMOUSE_RIGHT, + MwMOUSE_WHEELUP, + MwMOUSE_WHEELDOWN +}; + +#define MwKEY_FLAG 0x80000000 +#define MwKEY_CONTROL_FLAG MwKEY_FLAG | 0x40000000 +#define MwKEY_ALT_FLAG MwKEY_FLAG | 0x20000000 + +enum MwKEY { + MwKEY_BACKSPACE = MwKEY_FLAG | 1, + MwKEY_LEFT, + MwKEY_RIGHT, + MwKEY_UP, + MwKEY_DOWN, + MwKEY_ENTER, + MwKEY_ESCAPE, + MwKEY_LEFTSHIFT, + MwKEY_RIGHTSHIFT, + MwKEY_ALT, + MwKEY_CONTROL +}; + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Core.h b/widget/milsko/milskosrc/include/Mw/Core.h new file mode 100644 index 0000000000..61cb085505 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Core.h @@ -0,0 +1,405 @@ +/*! + * @file Mw/Core.h + * @brief Core + */ +#ifndef __MW_CORE_H__ +#define __MW_CORE_H__ + +#include +#include + +/*! + * @warning Used internally + * @brief Dispatches the handler of widget class + * @param x Widget + * @param y Handler name + */ +#define MwDispatch(x, y) \ + if(!x->destroyed && x->widget_class != NULL && x->widget_class->y != NULL) x->widget_class->y(x) + +/*! + * @warning Used internally + * @brief Dispatches the handler of widget class + * @param x Widget + * @param y Handler name + * @return `0` for success, otherwise failed + */ +#define MwDispatch2(x, y) \ + ((!x->destroyed && x->widget_class != NULL && x->widget_class->y != NULL) ? x->widget_class->y(x) : 0) + +/*! + * @warning Used internally + * @brief Dispatches the handler of widget class + * @param x Widget + * @param y Handler name + * @param z Argument + */ +#define MwDispatch3(x, y, z) \ + if(!x->destroyed && x->widget_class != NULL && x->widget_class->y != NULL) x->widget_class->y(x, z) + +/*! + * @warning Used internally + * @brief Dispatches the handler of widget class + * @param x Widget + * @param y Handler name + * @param z Argument + * @param w Argument + */ +#define MwDispatch4(x, y, z, w) \ + if(!x->destroyed && x->widget_class != NULL && x->widget_class->y != NULL) x->widget_class->y(x, z, w) + +#define MwWaitMS 30 + +#define MwDoubleClickTimeout 250 + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Initializes the Milsko Toolkit + * @return `0` if successful + */ +MWDECL int MWAPI MwLibraryInit(void); + +/*! + * @brief Creates a widget + * @param widget_class Widget class + * @param name Widget name + * @param parent Parent widget or `NULL` + * @param x X + * @param y Y + * @param width Width + * @param height Height + * @return Widget + */ +MWDECL MwWidget MWAPI MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height); + +/*! + * @brief Creates a widget + * @param widget_class Widget class + * @param name Widget name + * @param parent Parent widget or `NULL` + * @param x X + * @param y Y + * @param width Width + * @param height Height + * @param ... Same with MwVaApply + * @return Widget + */ +MWDECL MwWidget MWAPI MwVaCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, ...); + +/*! + * @brief Creates a widget + * @param widget_class Widget class + * @param name Widget name + * @param parent Parent widget or `NULL` + * @param x X + * @param y Y + * @param width Width + * @param height Height + * @param va Same with MwVaListApply + * @return Widget + */ +MWDECL MwWidget MWAPI MwVaListCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, va_list va); + +/*! + * @brief Destroys the widget and its child widgets + * @param handle Widget + */ +MWDECL void MWAPI MwDestroyWidget(MwWidget handle); + +/*! + * @brief Executes a method specific to the widget (varadic version). + * @warning Prefer using corresponding functions for better code clarity and type safety. + * @param handle Widget + * @param ... Widget function arguments. + */ +MWDECL void MWAPI MwVaWidgetExecute(MwWidget handle, const char* func_name, void* out, ...); + +/*! + * @brief Executes a method specific to the widget (va_list version). + * @warning Prefer using corresponding functions for better code clarity and type safety. + * @param handle Widget + * @param va Widget function arguments. + */ +MWDECL void MWAPI MwVaListWidgetExecute(MwWidget handle, const char* func_name, void* out, va_list va); + +/*! + * @brief Runs the main loop + * @param handle Widget + */ +MWDECL void MWAPI MwLoop(MwWidget handle); + +/*! + * @brief Runs the single step + * @param handle Widget + * @return `0` if successful + */ +MWDECL int MWAPI MwStep(MwWidget handle); + +/*! + * @brief Check if any event is pending + * @param handle Widget + * @return `1` if any event is pending + */ +MWDECL int MWAPI MwPending(MwWidget handle); + +/*! + * @brief Sets an integer property + * @param handle Widget + * @param key Key + * @param n Value + */ +MWDECL void MWAPI MwSetInteger(MwWidget handle, const char* key, int n); + +/*! + * @brief Sets a text property + * @param handle Widget + * @param key Key + * @param value Value + */ +MWDECL void MWAPI MwSetText(MwWidget handle, const char* key, const char* value); + +/*! + * @brief Sets a void pointer property + * @param handle Widget + * @param key Key + * @param value Value + */ +MWDECL void MWAPI MwSetVoid(MwWidget handle, const char* key, void* value); + +/*! + * @brief Gets the integer property + * @param handle Widget + * @param key Key + * @return Value + */ +MWDECL int MWAPI MwGetInteger(MwWidget handle, const char* key); + +/*! + * @brief Gets the text property + * @param handle Widget + * @param key Key + * @return Value + */ +MWDECL const char* MWAPI MwGetText(MwWidget handle, const char* key); + +/*! + * @brief Gets the void pointer property + * @param handle Widget + * @param key Key + * @return Value + */ +MWDECL void* MWAPI MwGetVoid(MwWidget handle, const char* key); + +/*! + * @brief Sets the default property + * @param handle Widget + * @warning This is called when widget is created + */ +MWDECL void MWAPI MwSetDefault(MwWidget handle); + +/*! + * @brief Sets the properties + * @param handle Widget + * @param ... Properties + */ +MWDECL void MWAPI MwVaApply(MwWidget handle, ...); + +/*! + * @brief Sets properties + * @param handle Widget + * @param va Properties + */ +MWDECL void MWAPI MwVaListApply(MwWidget handle, va_list va); + +/*! + * @brief Sets a user handler + * @param handle Widget + * @param key Key + * @param handler Handler + * @param user_data User data passed to handler + */ +MWDECL void MWAPI MwAddUserHandler(MwWidget handle, const char* key, MwUserHandler handler, void* user_data); + +/*! + * @brief Dispatches the user handler + * @param handle Widget + * @param key Key + * @param handler_data Handler data passed to handler + */ +MWDECL void MWAPI MwDispatchUserHandler(MwWidget handle, const char* key, void* handler_data); + +/*! + * @brief Sets an error handler + * @param handle Widget + * @param handler Handler + * @param user_data User data passed to handler + */ +MWDECL void MWAPI MwSetErrorHandler(MwErrorHandler handler, void* user_data); + +/*! + * @brief Dispatches the error handler + * @param code Error code + * @param message Error message + */ +MWDECL void MWAPI MwDispatchError(int code, const char* message); + +/*! + * @brief Forcefully makes widget render + * @param handle Widget + */ +MWDECL void MWAPI MwForceRender(MwWidget handle); + +/*! + * @brief Forcefully makes widget render + * @param handle Widget + * @param ptr Ignored + */ +MWDECL void MWAPI MwForceRender2(MwWidget handle, void* ptr); + +/*! + * @brief Adds an widget to tick handler list + * @param handle Widget + */ +MWDECL void MWAPI MwAddTickList(MwWidget handle); + +/*! + * @brief Focus the widget + * @param handle Widget + */ +MWDECL void MWAPI MwFocus(MwWidget handle); + +/*! + * @brief Grabs the pointer + * @param handle Widget + * @param toggle Toggle + */ +MWDECL void MWAPI MwGrabPointer(MwWidget handle, int toggle); + +/*! + * @brief Hides the cursor + * @param handle Widget + */ +MWDECL void MWAPI MwHideCursor(MwWidget handle); + +/*! + * @brief Toggles the dark theme + * @param handle Widget + * @param toggle Toggle + * @deprecated Use MwNdarkTheme instead + */ +MWDECL void MWAPI MwSetDarkTheme(MwWidget handle, int toggle); + +/*! + * @brief Gets the parent widget + * @param handle Widget + * @return Parent widget + */ +MWDECL MwWidget MWAPI MwGetParent(MwWidget handle); + +/*! + * @brief Show widget + * @param handle Widget + * @param toggle Toggle + */ +MWDECL void MWAPI MwShow(MwWidget handle, int toggle); + +/*! + * @brief Reparents widget + * @param handle Widget + * @param new_parent New parent + */ +MWDECL void MWAPI MwReparent(MwWidget handle, MwWidget new_parent); + +/*! + * @brief Gets class of widget + * @param handle Widget + * @return Class + */ +MWDECL MwClass MWAPI MwGetClass(MwWidget handle); + +/*! + * @brief Gets name of widget + * @param handle Widget + * @return Name + */ +MWDECL const char* MWAPI MwGetName(MwWidget handle); + +/*! + * @brief Gets children of widget + * @param handle Widget + * @return Children (NULL-terminated array) + */ +MWDECL MwWidget* MWAPI MwGetChildren(MwWidget handle); + +/*! + * @brief Gets the cursor coordinate + * @param handle Widget + * @param point Point + */ +MWDECL void MWAPI MwGetCursorCoord(MwWidget handle, MwPoint* point); + +/*! + * @brief Gets the screen size + * @param handle Widget + * @param rect Rectangle + */ +MWDECL void MWAPI MwGetScreenSize(MwWidget handle, MwRect* rect); + +/*! + * @brief Reports whether a widget reports global or local coordinates upon GetXY/SetXY. Anything with a parent reports local, and most backends report global coordinates being supported for top level windows, but some (Wayland) do not. + * @param handle Widget + */ +MWDECL int MWAPI MwGetCoordinateType(MwWidget handle); + +/*! + * @brief Queue to get clipboard content + * @param handle Widget + * @param clipboard_type The Clipboard Type to get. See MwClipboardType. This is ignored on backends that aren't X11/Wayland, so if you're unsure, just use MwClipboardMain + */ +MWDECL void MWAPI MwGetClipboard(MwWidget handle, int clipboard_type); + +/*! + * @brief Set user pointer + * @param handle Widget + * @param user User pointer + */ +MWDECL void MWAPI MwSetUser(MwWidget handle, void* user); + +/*! + * @brief Get user pointer + * @param handle Widget + * @return User pointer + */ +MWDECL void* MWAPI MwGetUser(MwWidget handle); + +/*! + * @brief Free the widget + * @param handle Widget + * @warning This is used internally! + * @note You can call this on toplevel widget safely if you're sure no event loops will be ran, e.g. after `MwLoop`. + */ +MWDECL void MWAPI MwFreeWidget(MwWidget handle); + +/*! + * @brief Gets the frame of the widget + * @param handle Widget + * @param rect Frame + */ +MWDECL void MWAPI MwGetFrame(MwWidget handle, MwRect* rect); + +#ifdef _MILSKO +MWDECL void MwForceRender_Internal(MwWidget handle); +MWDECL void MwForceRender2_Internal(MwWidget handle, void* ptr); + +#define MwForceRender MwForceRender_Internal +#define MwForceRender2 MwForceRender2_Internal +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Default.h b/widget/milsko/milskosrc/include/Mw/Default.h new file mode 100644 index 0000000000..322082b281 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Default.h @@ -0,0 +1,96 @@ +/*! + * @file Mw/Default.h + * @brief Default properties + */ +#ifndef __MW_DEFAULT_H__ +#define __MW_DEFAULT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Default background color + */ +MWDECL const char* MwDefaultBackground; + +/*! + * @brief Default foreground color + */ +MWDECL const char* MwDefaultForeground; + +/*! + * @brief Default sub background color + */ +MWDECL const char* MwDefaultSubBackground; + +/*! + * @brief Default sub foreground color + */ +MWDECL const char* MwDefaultSubForeground; + +/*! + * @brief Default title background color + */ +MWDECL const char* MwDefaultTitleBackground; + +/*! + * @brief Default title foreground color + */ +MWDECL const char* MwDefaultTitleForeground; + +/*! + * @brief Default dark theme background color + */ +MWDECL const char* MwDefaultDarkBackground; + +/*! + * @brief Default dark theme foreground color + */ +MWDECL const char* MwDefaultDarkForeground; + +/*! + * @brief Default dark theme sub background color + */ +MWDECL const char* MwDefaultDarkSubBackground; + +/*! + * @brief Default dark theme sub foreground color + */ +MWDECL const char* MwDefaultDarkSubForeground; + +/*! + * @brief Default dark theme title background color + */ +MWDECL const char* MwDefaultDarkTitleBackground; + +/*! + * @brief Default dark theme title foreground color + */ +MWDECL const char* MwDefaultDarkTitleForeground; + +/*! + * @brief Default shadow difference + */ +MWDECL const int MwDefaultShadow; + +/*! + * @brief Gets default border width + * @param handle Widget + */ +MWDECL int MWAPI MwDefaultBorderWidth(MwWidget handle); + +/*! + * @brief Gets default thin border width + * @param handle Widget + */ +MWDECL int MwDefaultThinBorderWidth(MwWidget handle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Dialog/ColorPicker.h b/widget/milsko/milskosrc/include/Mw/Dialog/ColorPicker.h new file mode 100644 index 0000000000..b143fdf50d --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Dialog/ColorPicker.h @@ -0,0 +1,27 @@ +/*! + * @file Mw/Dialog/ColorPicker.h + * @brief Color picker + */ +#ifndef __MW_COLORPICKER_H__ +#define __MW_COLORPICKER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Creates a color picker + * @param handle Widget + * @param title Title text + * @return Widget + */ +MWDECL MwWidget MWAPI MwColorPicker(MwWidget handle, const char* title); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Dialog/DirectoryChooser.h b/widget/milsko/milskosrc/include/Mw/Dialog/DirectoryChooser.h new file mode 100644 index 0000000000..cc6853c309 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Dialog/DirectoryChooser.h @@ -0,0 +1,27 @@ +/*! + * @file Mw/Dialog/DirectoryChooser.h + * @brief Directory chooser + */ +#ifndef __MW_DIRECTORYCHOOSER_H__ +#define __MW_DIRECTORYCHOOSER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Creates a directory chooser + * @param handle Widget + * @param title Title text + * @return Widget + */ +MWDECL MwWidget MWAPI MwDirectoryChooser(MwWidget handle, const char* title); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Dialog/FileChooser.h b/widget/milsko/milskosrc/include/Mw/Dialog/FileChooser.h new file mode 100644 index 0000000000..f6aa094ed1 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Dialog/FileChooser.h @@ -0,0 +1,36 @@ +/*! + * @file Mw/Dialog/FileChooser.h + * @brief File chooser + */ +#ifndef __MW_FILECHOOSER_H__ +#define __MW_FILECHOOSER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Creates a file chooser + * @param handle Widget + * @param title Title text + * @return Widget + */ +MWDECL MwWidget MWAPI MwFileChooser(MwWidget handle, const char* title); + +/*! + * @brief Creates a file chooser + * @param handle Widget + * @param title Title text + * @param dir Show directory only or not + * @return Widget + */ +MWDECL MwWidget MWAPI MwFileChooserEx(MwWidget handle, const char* title, int dir); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Dialog/MessageBox.h b/widget/milsko/milskosrc/include/Mw/Dialog/MessageBox.h new file mode 100644 index 0000000000..a8a5a462d9 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Dialog/MessageBox.h @@ -0,0 +1,36 @@ +/*! + * @file Mw/Dialog/MessageBox.h + * @brief Message box + */ +#ifndef __MW_MESSAGEBOX_H__ +#define __MW_MESSAGEBOX_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Creates a message box + * @param handle Widget + * @param text Text + * @param title Title text + * @param flag Flag + * @return Widget + */ +MWDECL MwWidget MWAPI MwMessageBox(MwWidget handle, const char* text, const char* title, unsigned int flag); + +/*! + * @brief Gets a child of the message box + * @param handle Widget + * @param child Child + */ +MWDECL MwWidget MWAPI MwMessageBoxGetChild(MwWidget handle, int child); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Draw.h b/widget/milsko/milskosrc/include/Mw/Draw.h new file mode 100644 index 0000000000..deefe0fce0 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Draw.h @@ -0,0 +1,242 @@ +/*! + * @file Mw/Draw.h + * @brief Common drawing API + */ +#ifndef __MW_DRAW_H__ +#define __MW_DRAW_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Parses a color text + * @param handle Widget + * @param text Color text + * @return Color + */ +MWDECL MwLLColor MWAPI MwParseColor(MwWidget handle, const char* text); + +/*! + * @brief Parses a color text + * @param text Color text + * @param rgb RGB + */ +MWDECL void MWAPI MwParseColorNoAllocate(const char* text, MwRGB* rgb); + +/*! + * @brief Initialize color table + * @warning This is called in MwLibraryInit - you do not have to call this + */ +MWDECL void MWAPI MwColorTableInit(void); + +/*! + * @brief Lighten a color + * @param handle Widget + * @param color Color + * @param r Red + * @param g Green + * @param b Blue + * @return Color + */ +MWDECL MwLLColor MWAPI MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b); + +/*! + * @brief Draws a filled rectangle + * @param handle Widget + * @param rect Rectangle area + * @param color Color + */ +MWDECL void MWAPI MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color); + +/*! + * @brief Draws a filled rectangle that fades to a darker color + * @param handle Widget + * @param rect Rectangle area + * @param color Color + */ +MWDECL void MWAPI MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color); + +/*! + * @brief Draws a frame + * @param handle Widget + * @param rect Rectangle area + * @param color Color + * @param invert Invert the 3D border color or not + * @warning `rect` gets changed to the area of rectangle inside + */ +MWDECL void MWAPI MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert); + +/*! + * @brief Draws a frame + * @param handle Widget + * @param rect Rectangle area + * @param color Color + * @param invert Invert the 3D border color or not + * @param border Border + * @warning `rect` gets changed to the area of rectangle inside + */ +MWDECL void MWAPI MwDrawFrameWithBorder(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border); + +/*! + * @brief Does the DrawFrame/DrawRect combo used for drawing widget. + * @param handle Widget + * @param rect Rectangle area + * @param color Color + * @param invert Invert the 3D border color or not + * @warning `rect` gets changed to the area of rectangle inside + */ +MWDECL void MWAPI MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border); + +/*! + * @brief Draws a triangle + * @param handle Widget + * @param rect Rectangle area + * @param color Color + * @param invert Invert the 3D border color or not + */ +MWDECL void MWAPI MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int direction); + +/*! + * @brief Draws a frame with specified border width + * @param handle Widget + * @param rect Rectangle area + * @param color Color + * @param invert Invert the 3D border color or not + * @param border Border width + * @param diff Difference (set this to 0 if you don't know what this does) + * @param same Same as dark color + * @warning `rect` gets changed to the area of rectangle inside + */ +MWDECL void MWAPI MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same); + +/*! + * @brief Creates a pixmap from image + * @param handle Widget + * @param path Path + * @return Pixmap + */ +MWDECL MwLLPixmap MWAPI MwLoadImage(MwWidget handle, const char* path); + +/*! + * @brief Get color components + * @param color Color + * @param red Pointer to red color + * @param green Pointer to green color + * @param blue Pointer to blue color + */ +MWDECL void MWAPI MwColorGet(MwLLColor color, int* red, int* green, int* blue); + +/*! + * @brief Creates a pixmap from raw data + * @param handle Widget + * @param rgb RGBA data + * @param width Width + * @param height Height + * @return Pixmap + */ +MWDECL MwLLPixmap MWAPI MwLoadRaw(MwWidget handle, unsigned char* rgb, int width, int height); + +/*! + * @brief Updates a pixmap using raw data + * @param pixmap Pixmap to update + * @param rgb RGBA data + */ +MWDECL void MWAPI MwPixmapReloadRaw(MwLLPixmap pixmap, unsigned char* rgb); + +/*! + * @brief Gets the raw data of pixmap + * @param pixmap Pixmap + * @return RGBA data + */ +MWDECL unsigned char* MWAPI MwPixmapGetRaw(MwLLPixmap pixmap); + +/*! + * @brief Gets the size of pixmap + * @param pixmap Pixmap + * @param rect Size + */ +MWDECL void MWAPI MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect); + +/*! + * @brief Creates a pixmap from XPM data + * @param handle Widget + * @param data Data + * @return Pixmap + */ +MWDECL MwLLPixmap MWAPI MwLoadXPM(MwWidget handle, char** data); + +/*! + * @brief Creates a pixmap from icon data + * @param handle Widget + * @param data Data + * @return Pixmap + */ +MWDECL MwLLPixmap MWAPI MwLoadIcon(MwWidget handle, MwU32* data); + +/*! + * @brief Draws a diamond + * @param handle Widget + * @param rect Rectangle area + * @param color Color + * @param invert Invert the 3D border color or not + */ +MWDECL void MWAPI MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert); + +/* text.c */ + +/*! + * @brief Draws a text + * @param handle Widget + * @param ttf TTF, NULLable + * @param point Center point of the text + * @param text Text + * @param align Align + * @param color Color + */ +MWDECL void MWAPI MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, int align, MwLLColor color); + +/*! + * @brief Calculates a text width + * @param handle Widget + * @param text Text + * @param font Font, NULLable + * @return Text width + */ +MWDECL int MWAPI MwTextWidth(MwWidget handle, MwFLFont font, const char* text); + +/*! + * @brief Calculates a text height + * @param handle Widget + * @param text Text + * @param font Font, NULLable + * @return Text height + */ +MWDECL int MWAPI MwTextHeight(MwWidget handle, MwFLFont font, const char* text); + +/* color.c */ + +/*! + * @brief Parses a color name + * @param handle Widget + * @param color Color name + * @return Color + */ +MWDECL MwLLColor MWAPI MwParseColorName(MwWidget handle, const char* color); + +/*! + * @brief Parses a color name + * @param color Color name + * @param rgb RGB + */ +MWDECL void MWAPI MwParseColorNameNoAllocate(const char* color, MwRGB* rgb); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Font.h b/widget/milsko/milskosrc/include/Mw/Font.h new file mode 100644 index 0000000000..9902af69e0 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Font.h @@ -0,0 +1,33 @@ +/*! + * @file Mw/Font.h + * @brief Font + */ +#ifndef __MW_FONT_H__ +#define __MW_FONT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Loads a TTF Font + * @param data Data + * @param size Data size + * @return Font handle + */ +MWDECL void* MWAPI MwFontLoad(unsigned char* data, unsigned int size); + +/*! + * @brief Frees a font handle + * @param handle Handle + */ +MWDECL void MWAPI MwFontFree(void* handle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel.h b/widget/milsko/milskosrc/include/Mw/LowLevel.h new file mode 100644 index 0000000000..a2be271932 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel.h @@ -0,0 +1,363 @@ +/*! + * @file Mw/LowLevel.h + * @brief Low-level drawing API + * @warning This is used internally + */ +#ifndef __MW_LOWLEVEL_H__ +#define __MW_LOWLEVEL_H__ + +#include +#include + +typedef struct _MwLLHandler* MwLLHandler; +typedef struct _MwLLCommon* MwLLCommon; +typedef struct _MwLLCommonColor* MwLLCommonColor; +typedef struct _MwLLCommonPixmap* MwLLCommonPixmap; +#ifdef _MILSKO +typedef union _MwLL* MwLL; +typedef union _MwLLColor* MwLLColor; +typedef union _MwLLPixmap* MwLLPixmap; +typedef struct _MwFLFont* MwFLFont; +#else +typedef void* MwLL; +typedef void* MwLLColor; +typedef void* MwLLPixmap; +typedef void* MwFLFont; +#endif + +enum MwLLBackends { + MwLLBackendX11 = 0, + MwLLBackendGDI, + MwLLBackendWayland, + MwLLBackendCocoa, + MwLLBackendHaiku +}; + +struct _MwLLCommon { + void* user; + int copy_buffer; + int type; + int coordinate_type; + MwBool supports_transparency; + + MwLLHandler handler; +}; + +struct _MwLLCommonColor { + MwU8 red; + MwU8 green; + MwU8 blue; +}; + +struct _MwLLCommonPixmap { + int width; + int height; + unsigned char* raw; + void* user; +}; + +#ifdef USE_DBUS +typedef struct _MwLLDBusFuncTable { + void* lib; + + void (*dbus_error_init)(DBusError* error); + DBusConnection* (*dbus_bus_get)(DBusBusType type, DBusError* error); + dbus_bool_t (*dbus_error_is_set)(const DBusError* error); + void (*dbus_error_free)(DBusError* error); + DBusMessage* (*dbus_message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); + void (*dbus_message_iter_init_append)(DBusMessage* message, DBusMessageIter* iter); + dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter* iter, int type, const void* value); + void (*dbus_connection_flush)(DBusConnection* connection); + dbus_bool_t (*dbus_connection_read_write)(DBusConnection* connection, int timeout_milliseconds); + DBusMessage* (*dbus_connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); + DBusMessage* (*dbus_connection_pop_message)(DBusConnection* connection); + void (*dbus_bus_add_match)(DBusConnection* connection, const char* rule, DBusError* error); + void (*dbus_message_unref)(DBusMessage* message); + dbus_bool_t (*dbus_message_iter_init)(DBusMessage* message, DBusMessageIter* iter); + dbus_bool_t (*dbus_message_is_signal)(DBusMessage* message, const char* iface, const char* signal_name); + int (*dbus_message_iter_get_arg_type)(DBusMessageIter* iter); + void (*dbus_message_iter_recurse)(DBusMessageIter* iter, DBusMessageIter* sub); + void (*dbus_message_iter_next)(DBusMessageIter* iter); + void (*dbus_connection_unref)(DBusConnection* connection); + void (*dbus_message_iter_get_basic)(DBusMessageIter* iter, void* value); +} MwLLDBusFuncTable; + +typedef struct _MwLLDBusContext { + DBusConnection* dbus_conn; + DBusError dbus_err; + DBusMessage* dbus_msg; + DBusMessage* dbus_reply; +} MwLLDBusContext; + +typedef void (*MwLLDBusPortalPollListener)(MwLL handle, MwU32 new_value); + +/* setup the dbus func table. Returns false and prints a warning if dbus couldn't be found. */ +MWDECL MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl); + +MWDECL MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); +MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out); +MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal); +MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener); +MWDECL void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); + +#endif + +#ifdef _MILSKO +#ifdef USE_X11 +#include +#endif +#ifdef USE_GDI +#include +#endif +#ifdef USE_WAYLAND +#include +#endif +#ifdef USE_COCOA +#include +#endif +#ifdef CLASSIC_MAC_OS +#include +#endif +#ifdef USE_HAIKU +#include +#endif + +union _MwLL { + struct _MwLLCommon common; +#ifdef USE_X11 + struct _MwLLX11 x11; +#endif +#ifdef USE_GDI + struct _MwLLGDI gdi; +#endif +#ifdef USE_WAYLAND + struct _MwLLWayland wayland; + struct _MwLLCairo cairo; +#endif +#ifdef USE_COCOA + struct _MwLLCocoa cocoa; +#endif +#ifdef CLASSIC_MAC_OS + struct _MwLLClassicMacOS cmacos; +#endif +#ifdef USE_HAIKU + struct _MwLLHaiku haiku; +#endif +}; + +union _MwLLColor { + struct _MwLLCommonColor common; +#ifdef USE_X11 + struct _MwLLX11Color x11; +#endif +#ifdef USE_GDI + struct _MwLLGDIColor gdi; +#endif +#ifdef USE_WAYLAND + struct _MwLLCairoColor wayland; +#endif +#ifdef USE_COCOA + struct _MwLLCocoaColor cocoa; +#endif +#ifdef USE_HAIKU + struct _MwLLHaikuColor haiku; +#endif +}; + +union _MwLLPixmap { + struct _MwLLCommonPixmap common; +#ifdef USE_X11 + struct _MwLLX11Pixmap x11; +#endif +#ifdef USE_GDI + struct _MwLLGDIPixmap gdi; +#endif +#ifdef USE_WAYLAND + struct _MwLLWaylandPixmap wayland; + struct _MwLLCairoPixmap cairo; /* same structure but we do this for code clarity */ +#endif +#ifdef USE_COCOA + struct _MwLLCocoaPixmap cocoa; +#endif +#ifdef CLASSIC_MAC_OS + struct _MwLLClassicMacOSPixmap cmacos; +#endif +#ifdef USE_HAIKU + struct _MwLLHaikuPixmap haiku; +#endif +}; +#endif +#include + +#define MwLLDispatch(x, y, z) \ + if(x->common.handler != NULL && x->common.handler->y != NULL) x->common.handler->y(x, z) + +struct _MwLLHandler { + void (*draw)(MwLL handle, void* data); + void (*up)(MwLL handle, void* data); + void (*down)(MwLL handle, void* data); + void (*resize)(MwLL handle, void* data); + void (*close)(MwLL handle, void* data); + void (*move)(MwLL handle, void* data); + void (*key)(MwLL handle, void* data); + void (*key_released)(MwLL handle, void* data); + void (*focus_in)(MwLL handle, void* data); + void (*focus_out)(MwLL handle, void* data); + void (*clipboard)(MwLL handle, void* data); + void (*dark_theme)(MwLL handle, void* data); +}; + +struct _MwLLTextDispatchTable { + int (*drawText)(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color); + int (*textWidth)(MwWidget handle, const char* text); + int (*textHeight)(MwWidget handle, int count); + void* (*fontLoad)(unsigned char* data, unsigned int size); + void (*fontFree)(void* handle); +}; + +#define MwFLFlagMonospace (1 << 0) +#define MwFLFlagBold (1 << 1) +#define MwFLFlagBitmap (1 << 2) +#define MwFLBuildFont(x) ((MwFLFont)(void*)(size_t)(x)) + +#ifdef __cplusplus +extern "C" { +#endif + +/* lowlevel.c, common part */ +MWDECL void MwLLCreateCommon(MwLL handle); +MWDECL void MwLLDestroyCommon(MwLL handle); + +/* driver-specific, these get assigned by backend */ +MWDECL MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height); +MWDECL void (*MwLLDestroy)(MwLL handle); + +MWDECL void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); +MWDECL void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); + +/*! + * @brief Begin drawing sequence + * @param handle Handle + */ +MWDECL void (*MwLLBeginDraw)(MwLL handle); + +/*! + * @brief End drawing sequence + * @param handle Handle + */ +MWDECL void (*MwLLEndDraw)(MwLL handle); + +MWDECL MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); +MWDECL void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b); +MWDECL void (*MwLLFreeColor)(MwLLColor color); + +MWDECL void (*MwLLGetXYWH)(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h); +MWDECL void (*MwLLSetXY)(MwLL handle, int x, int y); +MWDECL void (*MwLLSetWH)(MwLL handle, int w, int h); + +MWDECL void (*MwLLSetTitle)(MwLL handle, const char* title); + +MWDECL int (*MwLLPending)(MwLL handle); +MWDECL void (*MwLLNextEvent)(MwLL handle); + +MWDECL MwLLPixmap (*MwLLCreatePixmap)(MwLL handle, unsigned char* data, int width, int height); +MWDECL void (*MwLLPixmapUpdate)(MwLLPixmap pixmap); +MWDECL void (*MwLLDestroyPixmap)(MwLLPixmap pixmap); +MWDECL void (*MwLLDrawPixmap)(MwLL handle, MwRect* rect, MwLLPixmap pixmap); +MWDECL void (*MwLLSetIcon)(MwLL handle, MwLLPixmap pixmap); + +MWDECL void (*MwLLForceRender)(MwLL handle); + +MWDECL void (*MwLLSetCursor)(MwLL handle, MwCursor* image, MwCursor* mask); + +/*! + * @brief Detach handle and make it toplevel window + * @param handle Handle + * @param point Point to be detached at, relative from the parent handle + */ +MWDECL void (*MwLLDetach)(MwLL handle, MwPoint* point); +MWDECL void (*MwLLShow)(MwLL handle, int show); + +MWDECL void (*MwLLSetSizeHints)(MwLL handle, int minx, int miny, int maxx, int maxy); +MWDECL void (*MwLLMakeBorderless)(MwLL handle, int toggle); + +/*! + * @brief Make handle "tool" window, e.g. Submenu, combobox menu, and etc. + * @param handle Handle + */ +MWDECL void (*MwLLMakeToolWindow)(MwLL handle); +MWDECL void (*MwLLMakePopup)(MwLL handle, MwLL parent); + +/*! + * @brief Begin changing state (has to be called before `MwLLSetSizeHints`, `MwLLMakeBorderless`, `MwLLMakeToolWindow`, and `MwLLMakePopup`) + * @param handle Handle + */ +MWDECL void (*MwLLBeginStateChange)(MwLL handle); + +/*! + * @brief End changing state + * @param handle Handle + */ +MWDECL void (*MwLLEndStateChange)(MwLL handle); + +MWDECL void (*MwLLFocus)(MwLL handle); + +/*! + * @brief Grab pointer, and keep moving pointer to center of handle + * @param handle Handle + * @param toggle Toggle + */ +MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle); + +MWDECL void (*MwLLSetClipboard)(MwLL handle, const char* text, int clipboard_type); +MWDECL void (*MwLLGetClipboard)(MwLL handle, int clipboard_type); + +MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); +MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); + +/*! + * @brief Set any extra parameters for dark theme + * @param handle Handle + * @param toggle Toggle + * @warning Do not run `handle->common.handler->dark_theme` when this function gets called + * @warning This is for stuff like, i.e. setting the accent color on modern Windows. The user themselves sets dark theme with MwNdarkTheme. + */ +MWDECL void (*MwLLSetDarkTheme)(MwLL handle, int toggle); + +/*! + * @brief Whether or not the platform should default to modern theme. + * @param handle Handle + * @return whether to default. + */ +MWDECL MwBool (*MwLLDoModern)(MwLL handle); + +MWDECL void (*MwLLRaise)(MwLL handle); + +MWDECL void (*MwLLClip)(MwLL handle, MwRect* rect); + +/* font renderer */ +MWDECL void MwFLSetup(void); + +#ifdef USE_FREETYPE2 +MWDECL int MwFL_FT2Setup(void); +#endif +#ifdef USE_STB_TRUETYPE +MWDECL int MwFL_STBTTSetup(void); +#endif + +#ifdef USE_GDI_TEXT +MWDECL int MwFL_GDISetup(void); +#endif + +MWDECL int (*MwFLDrawText)(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color); +MWDECL int (*MwFLTextWidth)(MwFLFont ttf, const char* text); +MWDECL int (*MwFLTextHeight)(MwFLFont ttf, int count); +MWDECL int (*MwFLTextHeightWithText)(MwFLFont ttf, const char* text); +MWDECL void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px); +MWDECL void (*MwFLFontFree)(void* handle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/Cairo.h b/widget/milsko/milskosrc/include/Mw/LowLevel/Cairo.h new file mode 100644 index 0000000000..dd2cfa3226 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/Cairo.h @@ -0,0 +1,229 @@ +/*! + * @file Mw/LowLevel/Cairo.h + * @brief Cairo Backend + * @warning This is used MEGA internally. + */ +#ifndef __MW_LOWLEVEL_CAIRO_H__ +#define __MW_LOWLEVEL_CAIRO_H__ + +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +MWDECL int MwLLCairoCallInit(void); + +#ifdef __cplusplus +} +#endif + +#define CSD_BORDER_FRAME_LEFT 5 +#define CSD_BORDER_FRAME_RIGHT 5 +#define CSD_BORDER_FRAME_TOP 23 +#define CSD_BORDER_FRAME_BOTTOM 4 + +typedef struct cairo_call_table { + void* cairo_lib; + + void (*cairo_set_line_width)(cairo_t* cr, + double width); + void (*cairo_scale)(cairo_t* cr, + double sx, + double sy); + cairo_t* (*cairo_create)(cairo_surface_t* target); + void (*cairo_move_to)(cairo_t* cr, + double x, + double y); + + void (*cairo_rectangle)(cairo_t* cr, + double x, + double y, + double width, + double height); + void (*cairo_new_path)(cairo_t* cr); + void (*cairo_set_line_cap)(cairo_t* cr, + cairo_line_cap_t line_cap); + void (*cairo_set_source_rgba)(cairo_t* cr, + double red, + double green, + double blue, + double alpha); + void (*cairo_set_source_rgb)(cairo_t* cr, + double red, + double green, + double blue); + void (*cairo_reset_clip)(cairo_t* cr); + unsigned char* (*cairo_image_surface_get_data)(cairo_surface_t* surface); + void (*cairo_line_to)(cairo_t* cr, + double x, + double y); + cairo_status_t (*cairo_surface_write_to_png)(cairo_surface_t* surface, const char* filename); + void (*cairo_surface_destroy)(cairo_surface_t* surface); + cairo_surface_t* (*cairo_image_surface_create_for_data)(unsigned char* data, + cairo_format_t format, + int width, + int height, + int stride); + cairo_surface_t* (*cairo_image_surface_create)(cairo_format_t format, + int width, + int height); + void (*cairo_destroy)(cairo_t* cr); + cairo_pattern_t* (*cairo_get_source)(cairo_t* cr); + void (*cairo_close_path)(cairo_t* cr); + void (*cairo_paint)(cairo_t* cr); + void (*cairo_surface_flush)(cairo_surface_t* surface); + void (*cairo_clip)(cairo_t* cr); + void (*cairo_save)(cairo_t* cr); + void (*cairo_restore)(cairo_t* cr); + void (*cairo_surface_mark_dirty)(cairo_surface_t* surface); + void (*cairo_stroke)(cairo_t* cr); + void (*cairo_set_source_surface)(cairo_t* cr, + cairo_surface_t* surface, + double x, + double y); + void (*cairo_fill)(cairo_t* cr); + void (*cairo_pattern_set_filter)(cairo_pattern_t* pattern, + cairo_filter_t filter); + void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); + void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); + +} cairo_call_table_t; + +extern cairo_call_table_t cairo_call_tbl; + +/* defined inline right here so that it doesn't conflict with the other macros */ +MwInline int cairo_load_funcs() { +#ifdef __APPLE__ + cairo_call_tbl.cairo_lib = MwDynamicOpen("libcairo.dylib"); +#else + cairo_call_tbl.cairo_lib = MwDynamicOpen("libcairo.so"); +#endif + if(!cairo_call_tbl.cairo_lib) { + printf("(libcairo not found, cannot use Wayland or Cairo backend.)\n"); + return 1; + } + +#define CAIRO_FUNC(x) \ + cairo_call_tbl.x = MwDynamicSymbol(cairo_call_tbl.cairo_lib, #x); \ + if(!cairo_call_tbl.x) { \ + printf("WARNING: Could use Wayland/Cairo backend if " #x " was not found. Do you have libcairo?\n"); \ + return 1; \ + }; + + CAIRO_FUNC(cairo_set_line_width); + CAIRO_FUNC(cairo_scale); + CAIRO_FUNC(cairo_create); + CAIRO_FUNC(cairo_move_to); + CAIRO_FUNC(cairo_rectangle); + CAIRO_FUNC(cairo_new_path); + CAIRO_FUNC(cairo_set_line_cap); + CAIRO_FUNC(cairo_set_antialias); + CAIRO_FUNC(cairo_set_source_rgba); + CAIRO_FUNC(cairo_set_source_rgb); + CAIRO_FUNC(cairo_reset_clip); + CAIRO_FUNC(cairo_image_surface_get_data); + CAIRO_FUNC(cairo_line_to); + CAIRO_FUNC(cairo_surface_write_to_png); + CAIRO_FUNC(cairo_surface_destroy); + CAIRO_FUNC(cairo_image_surface_create_for_data); + CAIRO_FUNC(cairo_image_surface_create); + CAIRO_FUNC(cairo_destroy); + CAIRO_FUNC(cairo_get_source); + CAIRO_FUNC(cairo_close_path); + CAIRO_FUNC(cairo_paint); + CAIRO_FUNC(cairo_surface_flush); + CAIRO_FUNC(cairo_clip); + CAIRO_FUNC(cairo_save); + CAIRO_FUNC(cairo_restore); + CAIRO_FUNC(cairo_surface_mark_dirty); + CAIRO_FUNC(cairo_stroke); + CAIRO_FUNC(cairo_set_source_surface); + CAIRO_FUNC(cairo_fill); + CAIRO_FUNC(cairo_set_operator); + CAIRO_FUNC(cairo_pattern_set_filter); +#undef CAIRO_FUNC + + return 0; +} + +#define cairo_set_line_width cairo_call_tbl.cairo_set_line_width +#define cairo_scale cairo_call_tbl.cairo_scale +#define cairo_create cairo_call_tbl.cairo_create +#define cairo_move_to cairo_call_tbl.cairo_move_to +#define cairo_rectangle cairo_call_tbl.cairo_rectangle +#define cairo_new_path cairo_call_tbl.cairo_new_path +#define cairo_set_line_cap cairo_call_tbl.cairo_set_line_cap +#define cairo_set_antialias cairo_call_tbl.cairo_set_antialias +#define cairo_set_source_rgba cairo_call_tbl.cairo_set_source_rgba +#define cairo_set_source_rgb cairo_call_tbl.cairo_set_source_rgb +#define cairo_reset_clip cairo_call_tbl.cairo_reset_clip +#define cairo_image_surface_get_data cairo_call_tbl.cairo_image_surface_get_data +#define cairo_line_to cairo_call_tbl.cairo_line_to +#define cairo_surface_write_to_png cairo_call_tbl.cairo_surface_write_to_png +#define cairo_surface_destroy cairo_call_tbl.cairo_surface_destroy +#define cairo_image_surface_create_for_data cairo_call_tbl.cairo_image_surface_create_for_data +#define cairo_image_surface_create cairo_call_tbl.cairo_image_surface_create +#define cairo_destroy cairo_call_tbl.cairo_destroy +#define cairo_get_source cairo_call_tbl.cairo_get_source +#define cairo_close_path cairo_call_tbl.cairo_close_path +#define cairo_paint cairo_call_tbl.cairo_paint +#define cairo_surface_flush cairo_call_tbl.cairo_surface_flush +#define cairo_clip cairo_call_tbl.cairo_clip +#define cairo_save cairo_call_tbl.cairo_save +#define cairo_restore cairo_call_tbl.cairo_restore +#define cairo_surface_mark_dirty cairo_call_tbl.cairo_surface_mark_dirty +#define cairo_stroke cairo_call_tbl.cairo_stroke +#define cairo_set_source_surface cairo_call_tbl.cairo_set_source_surface +#define cairo_fill cairo_call_tbl.cairo_fill +#define cairo_set_operator cairo_call_tbl.cairo_set_operator +#define cairo_pattern_set_filter cairo_call_tbl.cairo_pattern_set_filter + +struct _MwLLCairo { + struct _MwLLCommon common; + + cairo_surface_t* front_cs; + cairo_surface_t* back_cs; + cairo_t* front_cairo; + cairo_t* back_cairo; + /* The cairo to actually use for draw operations. Typically is front_cairo, but wayland's MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ + cairo_t* selected_cairo; + + int x; + int y; + int width; + int height; + + MwBool toplevel; + MwLL parent; +}; + +struct _MwLLCairoColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLCairoPixmap { + struct _MwLLCommonPixmap common; + + cairo_surface_t* cs; +}; + +void MwLLCairoFrontSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height); +void MwLLCairoBackSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height); +void MwLLCairoFrontDestroy(struct _MwLLCairo* cairo); +void MwLLCairoBackDestroy(struct _MwLLCairo* cairo); +void MwLLCairoPolygon(struct _MwLLCairo handle, MwPoint* points, int points_count, MwLLColor color); +void MwLLCairoLine(struct _MwLLCairo handle, MwPoint* points, MwLLColor color); +MwLLPixmap MwLLCairoCreatePixmap(struct _MwLLCairo handle, unsigned char* data, int width, int height); +void MwLLCairoPixmapUpdate(MwLLPixmap handle); +void MwLLCairoDestroyPixmap(MwLLPixmap pixmap); +void MwLLCairoDrawPixmap(struct _MwLLCairo handle, MwRect* rect, MwLLPixmap pixmap); + +void MwLLCairoDestroy(struct _MwLLCairo handle); + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/ClassicMacOS.h b/widget/milsko/milskosrc/include/Mw/LowLevel/ClassicMacOS.h new file mode 100644 index 0000000000..9d76e202e8 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/ClassicMacOS.h @@ -0,0 +1,43 @@ +/*! + * @file Mw/LowLevel/ClassicMacOS.h + * @brief ClassicMacOS Backend + * @warning This is used internally + */ +#ifndef __MW_LOWLEVEL_ClassicMacOS_H__ +#define __MW_LOWLEVEL_ClassicMacOS_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct _MwLLClassicMacOS { + struct _MwLLCommon common; + + MwLL parent; + + WindowRef window; + ControlHandle control; + EventRecord event; + Rect winRect; +}; + +struct _MwLLClassicMacOSColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLClassicMacOSPixmap { + struct _MwLLCommonPixmap common; + BitMap bmp; +}; + +MWDECL int MwLLClassicMacOSCallInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/Cocoa.h b/widget/milsko/milskosrc/include/Mw/LowLevel/Cocoa.h new file mode 100644 index 0000000000..1f18006f9e --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/Cocoa.h @@ -0,0 +1,189 @@ +/*! + * @file Mw/LowLevel/Cocoa.h + * @brief Work in progress Cocoa Backend + * @warning This is used internally. + */ +#ifndef __MW_LOWLEVEL_COCOA_H__ +#define __MW_LOWLEVEL_COCOA_H__ + +#include +#include +#include + +typedef struct { + enum { + COCOA_DRAW_COMMAND_POLY = 0, + COCOA_DRAW_COMMAND_LINES, + COCOA_DRAW_COMMAND_PIXMAP, + } type; + union { + struct { + MwPoint* points; + int points_count; + struct _MwLLCommonColor color; + } poly; + struct { + MwPoint* points; + struct _MwLLCommonColor color; + } lines; + struct { + MwRect rect; + MwLLPixmap pixmap; + } pixmap; + }; +} draw_command; + +#ifdef __OBJC__ +#import +#import +#import + +@interface MilskoCocoaApplication : NSApplication { + MwBool doPending; +} +- (MwBool)pending; +@end + +// Note: implements NSApplicationDelegate +@interface MilskoCocoaApplicationDelegate : NSObject { + MilskoCocoaApplication* appl; +} +- (MilskoCocoaApplicationDelegate*)initWithAppl:(MilskoCocoaApplication*)appl; +@end + +@interface MilskoCocoaWindow : NSWindow { +} +@end + +// Note: implements NSWindowDelegate +@interface MilskoCocoaWindowDelegate : NSObject { + NSWindow* w; +} +- (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win; +@end + +/* + So we want to associate each NSWindow with its corresponding MwLL handle. The + conventional way of doing this is through "associative pointers", however + this is a feature that Apple added in 10.6 (marketted back then as "Objective + C 2" iirc). For 10.4 compatibility, we have to do a bit of an ugly hack that + might seem like horrifically undefined behavior, but I've tested this on + both 10.4 and modern Mac OS and as long as we're careful there's no + problems: we override NSView, use NSView's "frame" property to store the + pointer, and then override functions appropriately so that this frame is never + actually used. This can then be attached to an NSWindow with addSubview and + retrieved appropriately. + */ +@interface MilskoFakePointer : NSView { + void* ptr; +} + +- (void)setPointer:(void*)ptr; +- (void*)pointer; + +@end + +@interface MilskoCocoaPixmap : NSObject { + @public + MwBool valid; + int width; + int height; + unsigned char* buf; + NSImage* image; + NSBitmapImageRep* rep; +} + ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; +- (void)updateWithData:(unsigned char*)data; +- (void)destroy; + +/* using @property to create instance variables fucks up 10.4 gcc for some + * reason? */ +- (NSImage*)image; + +@end + +@interface MilskoCocoaView : NSView { + MwBool _child; + + @public + draw_command* commands; +} + +- (void)destroy; +- (void)setChild; +@end + +@interface MilskoCocoaSubView : MilskoCocoaView { +} +@end + +@interface MilskoCocoa : NSObject { + @public + MilskoCocoaApplication* application; + MwBool _forceRender; + MwBool _eventsPending; + MwBool isClosing; + NSWindow* window; + NSRect rect; + MilskoCocoaView* view; + MwLL parent; + MilskoFakePointer* handle; + unsigned int strHash; + NSEvent* lastEvent; + + MilskoCocoaPixmap* cursorPixmap; + NSCursor* cursor; + NSModalSession modalSession; + + MwBool pointerLocked; + MwBool mouseMoved; + + MwBool rejectFirstTest; +} +- (void)destroy; +- (void)sendClipboardEvent; + +- (MwLL)getParent; +- (NSView*)getView; +- (NSWindow*)getWindow; +- (void)nudge; + +- (void)pushCursor; +- (void)popCursor; + +- (MilskoFakePointer*)getHandle; + +@end +#define OBJC(x) x +#else +#define OBJC(x) void* +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct _MwLLCocoa { + struct _MwLLCommon common; + OBJC(MilskoCocoa*) + real; +}; + +struct _MwLLCocoaColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLCocoaPixmap { + struct _MwLLCommonPixmap common; + OBJC(MilskoCocoaPixmap*) + real; +}; + +MWDECL int MwLLCocoaCallInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/GDI.h b/widget/milsko/milskosrc/include/Mw/LowLevel/GDI.h new file mode 100644 index 0000000000..e505b0a407 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/GDI.h @@ -0,0 +1,57 @@ +/*! + * @file Mw/LowLevel/GDI.h + * @brief GDI Backend + * @warning This is used internally + */ +#ifndef __MW_LOWLEVEL_GDI_H__ +#define __MW_LOWLEVEL_GDI_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct _MwLLGDI { + struct _MwLLCommon common; + + HINSTANCE hInstance; + HWND hWnd; + HDC hDC; + HCURSOR cursor; + HICON icon; + + HRGN clip; + + int grabbed; + int force_render; + int get_clipboard; + int get_darktheme; +}; + +struct _MwLLGDIColor { + struct _MwLLCommonColor common; + + COLORREF color; + HBRUSH brush; +}; + +struct _MwLLGDIPixmap { + struct _MwLLCommonPixmap common; + + RGBQUAD* quad; + HBITMAP hBitmap; + HBITMAP hMask; + HBITMAP hMask2; +}; + +MWDECL int MwLLGDICallInit(void); +MWDECL HCURSOR MwLLGDICreateCursor(MwCursor* image, MwCursor* mask); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/Haiku.h b/widget/milsko/milskosrc/include/Mw/LowLevel/Haiku.h new file mode 100644 index 0000000000..32c1c027cf --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/Haiku.h @@ -0,0 +1,173 @@ +/*! + * @file Mw/LowLevel/Haiku.h + * @brief Haiku Backend + * @warning This is used internally + */ +#ifndef __MW_LOWLEVEL_HAIKU_H__ +#define __MW_LOWLEVEL_HAIKU_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +class MwApplication; +class MwView; +class MwWindow; + +class MwApplication : public BApplication { + public: + MwApplication(MwRect rc, MwLL handle); + ~MwApplication(); + + void MessageReceived(BMessage* message); +}; + +class MwView : public BView { + public: + MwLL handle; + BLocker* locker; + uint32 buttons; + BBitmap* bitmap; + + MwView(MwLL handle, BRect rc, uint32 resizingMode, uint32 flags); + ~MwView(); + + void MessageReceived(BMessage* message); + void PostMessage(BMessage* message); + void PostMessage(uint32 command); + status_t SendMessage(BMessage* message); + status_t SendMessage(uint32 command); + void Invalidate(); + + void AttachedToWindow(); + void Draw(BRect updateRect); + void FrameResized(float width, float height); + void MouseDown(BPoint point); + void MouseUp(BPoint point); + void MouseMoved(BPoint point, uint32 transit, const BMessage* message); + + void SetColor(MwLLColor color); +}; + +class MwWindow : public BWindow { + public: + MwWindow(BRect rc, window_type type, uint32 flags); + + void MessageReceived(BMessage* message); + + void FrameMoved(BPoint newLocation); + bool QuitRequested(); +}; + +typedef BBitmap MwBBitmap; +#else +typedef void MwApplication; +typedef void MwView; +typedef void MwWindow; +typedef void MwBBitmap; +#endif + +typedef union _MwLLHaikuEvent MwLLHaikuEvent; + +enum BAPP_MW_WHAT { + BAPP_MW_DESTROY = 0 +}; + +enum BVIEW_MW_WHAT { + BVIEW_MW_DESTROY = 0, + BVIEW_MW_DETACH, + BVIEW_MW_RESIZE, + BVIEW_MW_MOVE, + BVIEW_MW_SHOW, + BVIEW_MW_HIDE, + BVIEW_MW_SET_COLOR, + BVIEW_MW_POLYGON, + BVIEW_MW_LINE, + BVIEW_MW_BITMAP, + BVIEW_MW_RENDER, + BVIEW_MW_RAISE, + BVIEW_MW_GET_MOUSE +}; + +enum BWIN_MW_WHAT { + BWIN_MW_DESTROY = 0, + BWIN_MW_SET_TITLE, + BWIN_MW_SET_TYPE +}; + +enum MwLLHAIKU_EVENT { + MwLLHAIKU_EVENT_DRAW = 0, + MwLLHAIKU_EVENT_CLOSE, + MwLLHAIKU_EVENT_FRAMERESIZED, + MwLLHAIKU_EVENT_FRAMEMOVED, + MwLLHAIKU_EVENT_MOUSEDOWN, + MwLLHAIKU_EVENT_MOUSEUP, + MwLLHAIKU_EVENT_MOUSEMOVED +}; + +struct _MwLLHaikuEventMouse { + int type; + MwPoint point; + int button; +}; + +struct _MwLLHaikuEventFrameResized { + int type; + float width; + float height; +}; + +struct _MwLLHaikuEventFrameMoved { + int type; + MwPoint point; +}; + +union _MwLLHaikuEvent { + int type; + struct _MwLLHaikuEventMouse mouse; + struct _MwLLHaikuEventFrameResized frame_resized; + struct _MwLLHaikuEventFrameMoved frame_moved; +}; + +struct _MwLLHaiku { + struct _MwLLCommon common; + + int type; + + int x; + int y; + int width; + int height; + + MwLL parent; + MwApplication* app; + MwWindow* window; + MwView* view; + thread_id app_thread; + int force_render; + + MwLLHaikuEvent* events; +}; + +struct _MwLLHaikuColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLHaikuPixmap { + struct _MwLLCommonPixmap common; + + MwBBitmap* bitmap; +}; + +MWDECL int MwLLHaikuCallInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland.h b/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland.h new file mode 100644 index 0000000000..ccd1f2f0f2 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland.h @@ -0,0 +1,517 @@ +/*! + * @file Mw/LowLevel/Wayland.h + * @brief Wayland Backend + * @warning This is used internally. + */ +#ifndef __MW_LOWLEVEL_WAYLAND_H__ +#define __MW_LOWLEVEL_WAYLAND_H__ + +#include +#include +#include +#include + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +MWDECL int MwLLWaylandCallInit(void); + +#ifdef __cplusplus +} +#endif + +#define CSD_BORDER_FRAME_LEFT 5 +#define CSD_BORDER_FRAME_RIGHT 5 +#define CSD_BORDER_FRAME_TOP 23 +#define CSD_BORDER_FRAME_BOTTOM 4 + +struct _MwLLWayland; + +#include + +#if WAYLAND_LOAD_OPENGL +#include +#include +#endif + +typedef struct wayland_call_table { + void* lib; + void* xkb_lib; +#ifdef USE_DBUS + MwLLDBusFuncTable dbus; + MwBool has_dbus; +#endif + + int (*wl_display_dispatch)(struct wl_display* display); + int (*wl_display_dispatch_pending)(struct wl_display* display); + void (*wl_display_disconnect)(struct wl_display* display); + void (*wl_display_cancel_read)(struct wl_display* display); + int (*wl_display_prepare_read)(struct wl_display* display); + int (*wl_display_read_events)(struct wl_display* display); + int (*wl_display_flush)(struct wl_display* display); + int (*wl_display_get_fd)(struct wl_display* display); + int (*wl_display_roundtrip)(struct wl_display* display); + int (*wl_proxy_add_listener)(struct wl_proxy* proxy, void (**implementation)(void), void* data); + void (*wl_proxy_destroy)(struct wl_proxy* proxy); + void (*wl_log_set_handler_client)(wl_log_func_t handler); + struct wl_proxy* (*wl_proxy_marshal_flags)(struct wl_proxy* proxy, uint32_t opcode, + const struct wl_interface* interface, + uint32_t version, + uint32_t flags, ...); + struct wl_display* (*wl_display_connect)(const char* name); + uint32_t (*wl_proxy_get_version)(struct wl_proxy* proxy); + struct wl_display* (*wl_display_connect_to_fd)(int fd); + int (*wl_display_get_error)(struct wl_display* display); + + struct xkb_context* (*xkb_context_new)(enum xkb_context_flags flags); + void (*xkb_context_unref)(struct xkb_context* context); + struct xkb_state* (*xkb_state_new)(struct xkb_keymap* keymap); + void (*xkb_state_unref)(struct xkb_state* state); + struct xkb_keymap* (*xkb_keymap_new_from_string)(struct xkb_context* context, const char* string, enum xkb_keymap_format format, enum xkb_keymap_compile_flags flags); + xkb_level_index_t (*xkb_keymap_num_levels_for_key)(struct xkb_keymap* keymap, xkb_keycode_t key, xkb_layout_index_t layout); + int (*xkb_keymap_key_get_syms_by_level)(struct xkb_keymap* keymap, xkb_keycode_t key, xkb_layout_index_t layout, xkb_level_index_t level, const xkb_keysym_t** syms_out); + xkb_layout_index_t (*xkb_state_key_get_layout)(struct xkb_state* state, xkb_keycode_t key); + void (*xkb_keymap_unref)(struct xkb_keymap* keymap); + +} wayland_call_table_t; + +extern wayland_call_table_t wl_call_tbl; +#ifdef MW_VULKAN +extern MwBool MwWaylandVulkan; +#else +#define MwWaylandVulkan 0 +#endif + +MWDECL MwBool MwWaylandCairoOnly; + +/* defined inline right here so that it doesn't conflict with the other macros */ +MwInline int wayland_load_funcs() { +#ifdef __APPLE__ + wl_call_tbl.lib = MwDynamicOpen("libwayland-client.dylib"); +#else + wl_call_tbl.lib = MwDynamicOpen("libwayland-client.so"); +#endif + if(!wl_call_tbl.lib) { + printf("(libwayland-client not found, falling back to X11)\n"); + return 1; + } +#ifdef __APPLE__ + wl_call_tbl.xkb_lib = MwDynamicOpen("libxkbcommon.dylib"); +#else + wl_call_tbl.xkb_lib = MwDynamicOpen("libxkbcommon.so"); +#endif + if(!wl_call_tbl.xkb_lib) { + printf("(libxkbcommon not found, cannot use Wayland backend.)\n"); + return 1; + } + +#define WAYLAND_FUNC(x) \ + wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.lib, #x); \ + if(!wl_call_tbl.x) { \ + printf("WARNING: Could use Wayland backend if " #x " was found.\n"); \ + return 1; \ + }; + + WAYLAND_FUNC(wl_display_dispatch) + WAYLAND_FUNC(wl_display_dispatch_pending) + WAYLAND_FUNC(wl_display_disconnect) + WAYLAND_FUNC(wl_display_cancel_read) + WAYLAND_FUNC(wl_display_prepare_read) + WAYLAND_FUNC(wl_display_read_events) + WAYLAND_FUNC(wl_display_flush) + WAYLAND_FUNC(wl_display_get_fd) + WAYLAND_FUNC(wl_display_roundtrip) + WAYLAND_FUNC(wl_proxy_add_listener) + WAYLAND_FUNC(wl_proxy_destroy) + WAYLAND_FUNC(wl_log_set_handler_client) + WAYLAND_FUNC(wl_proxy_marshal_flags) + WAYLAND_FUNC(wl_display_connect) + WAYLAND_FUNC(wl_proxy_get_version) + WAYLAND_FUNC(wl_display_connect_to_fd) + WAYLAND_FUNC(wl_display_get_error) + +#undef WAYLAND_FUNC + +#define XKB_FUNC(x) \ + wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.xkb_lib, #x); \ + if(!wl_call_tbl.x) { \ + printf("WARNING: Could use Wayland backend if " #x " was found. Do you have libxkbcommon?\n"); \ + return 1; \ + }; + + XKB_FUNC(xkb_state_unref) + XKB_FUNC(xkb_context_new) + XKB_FUNC(xkb_context_unref) + XKB_FUNC(xkb_state_new) + XKB_FUNC(xkb_keymap_new_from_string) + XKB_FUNC(xkb_keymap_unref) + XKB_FUNC(xkb_keymap_num_levels_for_key) + XKB_FUNC(xkb_keymap_key_get_syms_by_level) + XKB_FUNC(xkb_state_key_get_layout) +#undef XKB_FUNC + + if(cairo_load_funcs() != 0) { + return 1; + } + +#ifdef USE_DBUS + wl_call_tbl.has_dbus = MwLLDBusFuncSetup(&wl_call_tbl.dbus); +#endif + + return 0; +} + +#define wl_display_dispatch wl_call_tbl.wl_display_dispatch +#define wl_display_dispatch_pending wl_call_tbl.wl_display_dispatch_pending +#define wl_display_disconnect wl_call_tbl.wl_display_disconnect +#define wl_display_cancel_read wl_call_tbl.wl_display_cancel_read +#define wl_display_prepare_read wl_call_tbl.wl_display_prepare_read +#define wl_display_read_events wl_call_tbl.wl_display_read_events +#define wl_display_flush wl_call_tbl.wl_display_flush +#define wl_display_get_fd wl_call_tbl.wl_display_get_fd +#define wl_display_roundtrip wl_call_tbl.wl_display_roundtrip +#define wl_proxy_add_listener wl_call_tbl.wl_proxy_add_listener +#define wl_proxy_destroy wl_call_tbl.wl_proxy_destroy +#define wl_log_set_handler_client wl_call_tbl.wl_log_set_handler_client +#define wl_proxy_marshal_flags wl_call_tbl.wl_proxy_marshal_flags +#define wl_display_connect wl_call_tbl.wl_display_connect +#define wl_proxy_get_version wl_call_tbl.wl_proxy_get_version +#define wl_display_connect_to_fd wl_call_tbl.wl_display_connect_to_fd +#define wl_display_get_error wl_call_tbl.wl_display_get_error + +#define xkb_state_unref wl_call_tbl.xkb_state_unref +#define xkb_context_new wl_call_tbl.xkb_context_new +#define xkb_context_unref wl_call_tbl.xkb_context_unref +#define xkb_state_new wl_call_tbl.xkb_state_new +#define xkb_keymap_new_from_string wl_call_tbl.xkb_keymap_new_from_string +#define xkb_keymap_unref wl_call_tbl.xkb_keymap_unref +#define xkb_keymap_num_levels_for_key wl_call_tbl.xkb_keymap_num_levels_for_key +#define xkb_keymap_key_get_syms_by_level wl_call_tbl.xkb_keymap_key_get_syms_by_level +#define xkb_state_key_get_layout wl_call_tbl.xkb_state_key_get_layout + +#ifndef WL_PROTOCOLS_DEFINED +#define WL_PROTOCOLS_DEFINED +#include "Wayland/wayland-core-protocol.h" +#include "Wayland/xdg-shell-client-protocol.h" +#include "Wayland/viewporter-client-protocol.h" +#include "Wayland/xdg-decoration-client-protocol.h" +#include "Wayland/cursor-shape-client-protocol.h" +#include "Wayland/primary-selection-client-protocol.h" +#include "Wayland/pointer-constraints-client-protocol.h" +#include "Wayland/relative-pointer-client-protocol.h" +#include "Wayland/xdg-toplevel-icon-client-protocol.h" +#include "Wayland/wlr-layer-shell-client-protocol.h" +#endif + +typedef struct wayland_protocol { + void* listener; + void* context; +} wayland_protocol_t; + +typedef wayland_protocol_t*(wl_setup_func)(MwU32, struct _MwLLWayland*, MwU32 version); +typedef void(wl_destroy_func)(struct _MwLLWayland* wayland, wayland_protocol_t* data); + +typedef struct wayland_protocol_callback_table { + wl_setup_func* setup; + wl_destroy_func* destroy; +} wayland_protocol_callback_table_t; + +struct _MwLLWaylandTopLevel { + struct xdg_surface* xdg_surface; + struct xdg_toplevel* xdg_top_level; + struct xdg_toplevel_listener xdg_toplevel_listener; + struct xdg_surface_listener xdg_surface_listener; + MwBool maxim_state; + + MwBool compositor_created; + MwBool xdg_wm_base_created; + MwBool xdg_surface_created; + + struct wl_subsurface* ssurface; + struct wl_subcompositor* scompositor; +}; + +struct _MwLLWaylandSublevel { + struct wl_subsurface* subsurface; + struct wl_subcompositor* subcompositor; + + MwLL parent; + + struct xdg_surface* xdg_surface; +}; + +struct _MwLLWaylandPopup { + struct xdg_surface* xdg_surface; + struct xdg_popup* xdg_popup; + struct xdg_positioner* xdg_positioner; + struct xdg_surface_listener xdg_surface_listener; + struct xdg_wm_base* xdg_wm_base; + MwLL topmost_parent; +}; + +struct _MwLLWaylandLayerSurface { + struct zwlr_layer_surface_v1* surface; +}; + +/* Shared set of anything needed for a shm buffer. */ +struct _MwLLWaylandShmBuffer { + struct wl_shm* shm; + struct wl_shm_pool* shm_pool; + struct wl_buffer* shm_buffer; + struct wl_shm_pool* shm_pool_back; + struct wl_buffer* shm_buffer_back; + struct wl_surface* surface; + struct wl_output* output; + + MwU8* buf; + MwU8* buf_back; + MwU64 buf_size; + int fd; + int fd_back; + MwBool setup; +}; + +enum _MwLLWaylandType { + MwLL_WAYLAND_UNKNOWN = 0, + MwLL_WAYLAND_TOPLEVEL, + MwLL_WAYLAND_SUBLEVEL, + MwLL_WAYLAND_POPUP, + MwLL_WAYLAND_LAYER_SURFACE, +}; + +typedef struct wl_clipboard_device_context { + struct { + struct wl_data_device* wl; + struct zwp_primary_selection_device_v1* zwp; + } device; + struct { + struct wl_data_offer* wl; + struct zwp_primary_selection_offer_v1* zwp; + } offer; + + MwLL ll; + // struct wl_seat* seat; +} wl_clipboard_device_context_t; + +struct _MwLLWayland { + struct _MwLLCommon common; + struct _MwLLCairo cairo; + + union { + /* Pointer for data that's only loaded if the widget is a toplevel */ + struct _MwLLWaylandTopLevel* toplevel; + /* Pointer for data that's only loaded if the widget is a sublevel */ + struct _MwLLWaylandSublevel* sublevel; + /* Pointer for data that's only loaded if the widget is a popup */ + struct _MwLLWaylandPopup* popup; + /* Pointer for data that's only loaded if the widget is a layer surface */ + struct _MwLLWaylandLayerSurface* layer_surface; + }; + + enum _MwLLWaylandType type; + enum _MwLLWaylandType type_to_be; + + MwRect clipping_rect; + MwBool no; + + MwBool changing; + MwBool detatching; + MwPoint detach_point; + + MwBool did_initial_resize; + + MwBool is_toplevel; + + MwBool is_clipping; + MwRect clip; + + /* Map of Wayland interfaces to their relevant setup functions. */ + struct { + char* key; + wayland_protocol_callback_table_t* value; + }* wl_protocol_setup_map; + + /* Map of Wayland interfaces to any information we keep about them once we've registered them. */ + struct { + char* key; + wayland_protocol_t* value; + }* wl_protocol_map; + + MwBool do_csd; + MwBool has_decorations; + char title[256]; + + struct xkb_context* xkb_context; + struct xkb_keymap* xkb_keymap; + struct xkb_state* xkb_state; + + struct wl_display* display; + struct wl_registry* registry; + struct wl_compositor* compositor; + struct wl_registry_listener registry_listener; + struct wl_region* o_region; + struct wl_region* region; + struct wl_output* output; + + struct wp_viewport* vp; + + MwBool do_lock_pointer; + struct zwp_pointer_constraints_v1* pointer_constraints; + struct zwp_relative_pointer_manager_v1* relative_pointer_manager; + struct zwp_relative_pointer_v1* relative_pointer; + struct zwp_locked_pointer_v1* locked_pointer; + MwBool pointer_constrained; + MwBool valid; + +#ifdef USE_DBUS + MwLLDBusContext dbus; +#endif + + MwBool dark_theme_detection; + MwU32 dark_theme; + + /* clipboard related stuff. + * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ + + struct { + struct wl_data_device_manager* wl; + struct zwp_primary_selection_device_manager_v1* zwp; + } clipboard_manager; + union { + struct wl_data_source* wl; + struct zwp_primary_selection_source_v1* zwp; + } clipboard_source; + char* clipboard_buffer; + MwBool supports_zwp; + MwBool zwp_setup; + + uint32_t clipboard_serial; + wl_clipboard_device_context_t** clipboard_devices_wl; + wl_clipboard_device_context_t** clipboard_devices_zwp; + + struct wl_pointer* pointer; + MwU32 pointer_serial; + struct wl_seat* pointer_seat; + + struct wl_keyboard* keyboard; + MwU32 keyboard_serial; + + MwU64 events_pending; + + MwU32 mod_state; + + MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ + + MwBool held_down; + + MwI32 x, y; + MwI32 ox, oy; + MwU32 ww, wh; /* Window position */ + MwPoint cur_mouse_pos; /* Currently known mouse position */ + MwLL currentlyHeldWidget; + MwLL focusedWidget; + + int resizing; + int setting_wh; + + MwU32 mw, mh; /* Monitor width and height as advertised by wl_output.mode */ + + MwLL parent; + + MwBool force_render; + MwBool did_event_loop_early; + + MwBool dispatching_resize; + + MwBool is_toplevel_menu; + + struct _MwLLWaylandShmBuffer framebuffer; + struct _MwLLWaylandShmBuffer backbuffer; + struct _MwLLWaylandShmBuffer cursor; + struct _MwLLWaylandShmBuffer* icon; + + MwLLPixmap icon_pixmap; + + pthread_mutex_t eventsMutex; + + int cancelEvent; + int numCallbacksRunning; + + uint32_t last_time; + + MwBool moving; + + MwI64 keyboard_rate; + MwI32 keyboard_delay; + int last_pressed_key; + MwBool holding_key; + MwU64 next_elapsed; + long start_time; + long end_time; +}; + +struct _MwLLWaylandColor { + struct _MwLLCommonColor common; +}; + +#define _MwLLWaylandPixmap _MwLLCairoPixmap + +/* Setup the framebuffer with the saved width/height */ +void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland); +/* Destroy the framebuffer */ +void MwLLWaylandFramebufferDestroy(struct _MwLLWayland* handle); + +/* Setup the framebuffer with the saved width/height */ +void MwLLWaylandBackbufferSetup(struct _MwLLWayland* wayland); +/* Destroy the backbuffer */ +void MwLLWaylandBackbufferDestroy(struct _MwLLWayland* handle); + +void MwLLWaylandBufferSetup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height); +void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer); +void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer); + +void MwLLWaylandRegionSetup(MwLL handle); +void MwLLWaylandRegionInvalidate(MwLL handle); + +void MwLLWaylandHangUntilConfigured(MwLL handle); + +MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); +void MwLLWaylandWidgetUndestroy(MwLL self); + +/* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ +void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland); + +void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_type); + +/* Flush Wayland events */ +void MwLLWaylandFlush(MwLL handle); + +/* Standard procedure before event callbacks in Wayland */ +#define WAYLAND_EVENT_OP_START(self) \ + if(MwLLWaylandWidgetIsDestroyed(self)) { \ + return; \ + } + +/* Footer for WAYLAND_EVENT_OP_START */ +#define WAYLAND_EVENT_OP_END(self) + +#define WIDGET_CHECK(handle) \ + if(!handle->wayland.valid) { \ + return; \ + } + +/* the two decoration manager constructs */ +typedef struct zxdg_decoration_manager_v1_context { + struct zxdg_decoration_manager_v1* manager; + struct zxdg_toplevel_decoration_v1* decoration; +} zxdg_decoration_manager_v1_context_t; + +extern struct zwp_relative_pointer_v1_listener MwLLWaylandRelativePointerListener; + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland/.gitignore b/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland/.gitignore new file mode 100644 index 0000000000..25a4663fa2 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland/.gitignore @@ -0,0 +1 @@ +*protocol.h diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland/README.md b/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland/README.md new file mode 100644 index 0000000000..e0c17e81f2 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/Wayland/README.md @@ -0,0 +1 @@ +Folder for wayland-scanner to place any of its files. diff --git a/widget/milsko/milskosrc/include/Mw/LowLevel/X11.h b/widget/milsko/milskosrc/include/Mw/LowLevel/X11.h new file mode 100644 index 0000000000..e1b74169c5 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/LowLevel/X11.h @@ -0,0 +1,97 @@ +/*! + * @file Mw/LowLevel/X11.h + * @brief X11 Backend + * @warning This is used internally + */ +#ifndef __MW_LOWLEVEL_X11_H__ +#define __MW_LOWLEVEL_X11_H__ + +#include +#include +#include + +#include +#include +#include +#ifdef USE_XRENDER +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct _MwLLX11 { + struct _MwLLCommon common; + + unsigned int width; + unsigned int height; + + Display* display; + Window window; + Pixmap pixmap; + GC gc; + Colormap colormap; + Atom wm_delete; + Atom wm_protocols; + Atom utf8_string; + Atom compound_text; + Atom text; + Atom clipboard; + Atom selection; + XIM xim; + XIC xic; + + long clipboard_time; + int clipboard_pending; /* 1 if UTF8_STRING, 2 if COMPOUND_TEXT, 3 if TEXT, 4 if STRING, otherwise 0 */ + + int top; + int toplevel; + int grabbed; + int force_render; + + unsigned long red_mask; + unsigned long red_max; + unsigned long red_shift; + + unsigned long green_mask; + unsigned long green_max; + unsigned long green_shift; + + unsigned long blue_mask; + unsigned long blue_max; + unsigned long blue_shift; + +#ifdef USE_DBUS + MwLLDBusContext dbus; +#endif + + MwBool dark_theme_detection; +}; + +struct _MwLLX11Color { + struct _MwLLCommonColor common; + + unsigned long pixel; +}; + +struct _MwLLX11Pixmap { + struct _MwLLCommonPixmap common; + + int depth; + unsigned char* data; + MwLL handle; + int use_xrender; + Display* display; + XImage* image; + XImage* mask; +}; + +MWDECL int MwLLX11CallInit(void); +MWDECL Cursor MwLLX11CreateCursor(Display* display, MwCursor* image, MwCursor* mask); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/MachDep.h b/widget/milsko/milskosrc/include/Mw/MachDep.h new file mode 100644 index 0000000000..4c98b24da3 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/MachDep.h @@ -0,0 +1,123 @@ +/*! + * @file Mw/MachDep.h + * @brief Machine dependent headers and macros + */ +#ifndef __MW_MACHDEP_H__ +#define __MW_MACHDEP_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199409L +#include +#define MW_HAS_WCHAR +#endif +#ifdef _WIN32 +#include + +#ifdef _MILSKO +#include +#include +#ifndef GWLP_USERDATA +#define GWLP_USERDATA GWL_USERDATA +#define GWLP_WNDPROC GWL_WNDPROC +#define GCLP_HICON GCL_HICON +#define GCLP_HCURSOR GCL_HCURSOR +#define SetWindowLongPtr SetWindowLong +#define GetWindowLongPtr GetWindowLong +#define SetClassLongPtr SetClassLong +#define GetClassLongPtr GetClassLong +#endif +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020a +#define GET_WHEEL_DELTA_WPARAM(x) ((short)HIWORD(x)) +#endif +#endif +#elif defined(CLASSIC_MAC_OS) +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif + +#if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) +#include +#include +#endif + +#ifdef __HAIKU__ +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#include +#endif +#include +#endif + +#ifdef __APPLE__ +#include +#include +#endif + +#ifdef USE_DBUS +#include +#endif + +#ifndef M_PI +#define M_PI 3.14159265 +#endif + +/* Windows */ +#if defined(_MILSKO) && defined(_MILSKO_BUILD) && defined(_WIN32) +#define MWDECL extern __declspec(dllexport) +#elif defined(_WIN32) +#define MWDECL extern __declspec(dllimport) +/* GCC/Clang */ +/* First check if we have __has_attribute and can check for the existence of visibility */ +#elif defined(__has_attribute) +#if __has_attribute(visibility) +#define MWDECL extern __attribute__((visibility("default"))) +#else +#define MWDECL extern +#endif +/* It might be that we're on an old version of GCC (like the one Apple ships with older versions of Mac OS). + * If we're on gcc 3 or above, assume it's there + */ +#elif __GNUC__ >= 3 +#define MWDECL extern __attribute__((visibility("default"))) +#else +/* all else fails */ +#define MWDECL extern +#endif + +#if defined(_WIN32) +#define MWAPI __cdecl +#else +#define MWAPI +#endif + +#define MwInline static __inline + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Milsko.h b/widget/milsko/milskosrc/include/Mw/Milsko.h new file mode 100644 index 0000000000..9860990ca4 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Milsko.h @@ -0,0 +1,60 @@ +/*! + * @file Mw/Milsko.h + * @brief Includes all headers + */ +#ifndef __MW_MILSKO_H__ +#define __MW_MILSKO_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Resource/Cursor.h b/widget/milsko/milskosrc/include/Mw/Resource/Cursor.h new file mode 100644 index 0000000000..9a4780286d --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Resource/Cursor.h @@ -0,0 +1,70 @@ +/*! + * @file Mw/Resource/Cursor.h + * @brief Cursor externs + */ + +#ifndef __MW_RESOURCE_CURSOR_H__ +#define __MW_RESOURCE_CURSOR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Default cursor + */ +MWDECL MwCursor MwCursorDefault; + +/*! + * @brief Default cursor mask + */ +MWDECL MwCursor MwCursorDefaultMask; + +/*! + * @brief Arrow cursor + */ +MWDECL MwCursor MwCursorArrow; + +/*! + * @brief Arrow cursor mask + */ +MWDECL MwCursor MwCursorArrowMask; + +/*! + * @brief Cross cursor + */ +MWDECL MwCursor MwCursorCross; + +/*! + * @brief Cross cursor mask + */ +MWDECL MwCursor MwCursorCrossMask; + +/*! + * @brief Text cursor + */ +MWDECL MwCursor MwCursorText; + +/*! + * @brief Text cursor mask + */ +MWDECL MwCursor MwCursorTextMask; + +/*! + * @brief Hidden cursor + */ +MWDECL MwCursor MwCursorHidden; + +/*! + * @brief Hidden cursor mask + */ +MWDECL MwCursor MwCursorHiddenMask; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Resource/Font.h b/widget/milsko/milskosrc/include/Mw/Resource/Font.h new file mode 100644 index 0000000000..d178a25b95 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Resource/Font.h @@ -0,0 +1,69 @@ +/*! + * @file Mw/Resource/Font.h + * @brief Default font resources + */ +#ifndef __MW_RESOURCE_FONT_H__ +#define __MW_RESOURCE_FONT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Default font data + */ +MWDECL MwFont MwFontData[]; + +/*! + * @brief Default bold font data + */ +MWDECL MwFont MwBoldFontData[]; + +/*! + * @brief Default TTF font data + */ +MWDECL unsigned char MwTTFData[]; + +/*! + * @brief Default TTF font size + */ +MWDECL unsigned int MwTTFDataSize; + +/*! + * @brief Default bold TTF font data + */ +MWDECL unsigned char MwBoldTTFData[]; + +/*! + * @brief Default bold TTF font size + */ +MWDECL unsigned int MwBoldTTFDataSize; + +/*! + * @brief Default monospace TTF font data + */ +MWDECL unsigned char MwMonospaceTTFData[]; + +/*! + * @brief Default monospace TTF font size + */ +MWDECL unsigned int MwMonospaceTTFDataSize; + +/*! + * @brief Default bold monospace TTF font data + */ +MWDECL unsigned char MwBoldMonospaceTTFData[]; + +/*! + * @brief Default bold monospace TTF font size + */ +MWDECL unsigned int MwBoldMonospaceTTFDataSize; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Resource/Icon.h b/widget/milsko/milskosrc/include/Mw/Resource/Icon.h new file mode 100644 index 0000000000..93eb2c6a0c --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Resource/Icon.h @@ -0,0 +1,98 @@ +/*! + * @file Mw/Resource/Icon.h + * @brief Icon + */ +#ifndef __MW_RESOURCE_ICON_H__ +#define __MW_RESOURCE_ICON_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Back icon + */ +MWDECL MwU32 MwIconBack[]; + +/*! + * @brief Clock icon + */ +MWDECL MwU32 MwIconClock[]; + +/*! + * @brief Computer icon + */ +MWDECL MwU32 MwIconComputer[]; + +/*! + * @brief Directory icon + */ +MWDECL MwU32 MwIconDirectory[]; + +/*! + * @brief Down icon + */ +MWDECL MwU32 MwIconDown[]; + +/*! + * @brief Error icon + */ +MWDECL MwU32 MwIconError[]; + +/*! + * @brief File icon + */ +MWDECL MwU32 MwIconFile[]; + +/*! + * @brief Forward icon + */ +MWDECL MwU32 MwIconForward[]; + +/*! + * @brief Info icon + */ +MWDECL MwU32 MwIconInfo[]; + +/*! + * @brief Left icon + */ +MWDECL MwU32 MwIconLeft[]; + +/*! + * @brief News icon + */ +MWDECL MwU32 MwIconNews[]; + +/*! + * @brief Note icon + */ +MWDECL MwU32 MwIconNote[]; + +/*! + * @brief Right icon + */ +MWDECL MwU32 MwIconRight[]; + +/*! + * @brief Search icon + */ +MWDECL MwU32 MwIconSearch[]; + +/*! + * @brief Up icon + */ +MWDECL MwU32 MwIconUp[]; + +/*! + * @brief Warning icon + */ +MWDECL MwU32 MwIconWarning[]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/String.h b/widget/milsko/milskosrc/include/Mw/String.h new file mode 100644 index 0000000000..5333d01905 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/String.h @@ -0,0 +1,63 @@ +/*! + * @file Mw/String.h + * @brief String utilities + */ +#ifndef __MW_STRING_H__ +#define __MW_STRING_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Duplicates a string + * @param str String + * @return String + */ +MWDECL char* MWAPI MwStringDuplicate(const char* str); + +/*! + * @brief Concatenates 2 strings + * @param str1 String + * @param str2 String + * @return String + */ +MWDECL char* MWAPI MwStringConcat(const char* str1, const char* str2); + +/*! + * @brief Converts size to string + * @param out Output + * @param size Size + */ +MWDECL void MWAPI MwStringSize(char* out, MwOffset size); + +/*! + * @brief Converts time to string + * @param out Output + * @param t Time + */ +MWDECL void MWAPI MwStringTime(char* out, time_t t); + +/*! + * @brief Prints up to n characters into a bufferMwStringPrintIntoBuffer. + * @note On compilers that support C99, this uses vsnprintf to safely print into a buffer; on compilers that don't, vsprintf is used. + * @param out Buffer + * @param size Max size + */ +MWDECL void MWAPI MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...); + +/*! + * @brief Check if the given key is UTF8 + * @param key Input + * @return whether its utf8 + */ +MWDECL MwBool MWAPI MwStringIsKeyUTF8(MwU32 key); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/StringDefs.h b/widget/milsko/milskosrc/include/Mw/StringDefs.h new file mode 100644 index 0000000000..b95fe93033 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/StringDefs.h @@ -0,0 +1,102 @@ +/*! + * @file Mw/StringDefs.h + * @brief String definitions for property + */ +#ifndef __MW_STRINGDEFS_H__ +#define __MW_STRINGDEFS_H__ + +#define MwNx "Ix" +#define MwNy "Iy" +#define MwNwidth "Iwidth" +#define MwNheight "Iheight" +#define MwNorientation "Iorientation" +#define MwNminValue "IminValue" +#define MwNmaxValue "ImaxValue" +#define MwNvalue "Ivalue" +#define MwNchangedBy "IchangedBy" +#define MwNareaShown "IareaShown" +#define MwNchecked "Ichecked" +#define MwNalignment "Ialignment" +#define MwNbold "Ibold" +#define MwNmain "Imain" +#define MwNleftPadding "IleftPadding" +#define MwNhasHeading "IhasHeading" +#define MwNhasBorder "IhasBorder" +#define MwNinverted "Iinverted" +#define MwNmodernLook "ImodernLook" +#define MwNwaitMS "IwaitMS" +#define MwNhideInput "IhideInput" +#define MwNsingleClickSelectable "IsingleClickSelectable" +#define MwNflat "Iflat" +#define MwNshowArrows "IshowArrows" +#define MwNpadding "Ipadding" +#define MwNborderWidth "IborderWidth" +#define MwNfillArea "IfillArea" +#define MwNratio "Iratio" +#define MwNfixedSize "IfixedSize" +#define MwNmargin "Imargin" +#define MwNbitmapFont "IbitmapFont" +#define MwNsevenSegment "IsevenSegment" +#define MwNlength "Ilength" +#define MwNforceInverted "IforceInverted" +#define MwNisRounded "IisRounded" +#define MwNdarkTheme "IdarkTheme" +#define MwNuseMonospace "IuseMonospace" +#define MwNdarkThemeAutomatic "IdarkThemeAutomatic" +#define MwNyear "Iyear" +#define MwNmonth "Imonth" +#define MwNdate "Idate" +#define MwNday "Iday" +#define MwNwaitLayout "IwaitLayout" +#define MwNscale "Iscale" +#define MwNcolumns "Icolumns" +#define MwNcolumnSpan "IcolumnSpan" +#define MwNrowSpan "IrowSpan" +#define MwNdisabled "Idisabled" + +#define MwNtitle "Stitle" +#define MwNtext "Stext" +#define MwNbackground "Sbackground" +#define MwNsubBackground "SsubBackground" +#define MwNtitleBackground "StitleBackground" +#define MwNforeground "Sforeground" +#define MwNsubForeground "SsubForeground" +#define MwNtitleForeground "StitleForeground" + +#define MwNvulkanExtension "SEvulkanExtension" +#define MwNvulkanLayer "SEvulkanLayer" +#define MwNvulkanConfig "VEvulkanConfig" + +#define MwNpixmap "Vpixmap" +#define MwNiconPixmap "ViconPixmap" +#define MwNsizeHints "VsizeHints" +#define MwNfont "Vfont" +#define MwNboldFont "VboldFont" +#define MwNbackgroundPixmap "VbackgroundPixmap" +#define MwNmonospaceFont "VmonospaceFont" +#define MwNboldMonospaceFont "VboldMonospaceFont" + +#define MwNactivateHandler "Cactivate" +#define MwNlistBoxActivateHandler "ClistBoxActivate" +#define MwNtreeViewActivateHandler "CtreeViewActivate" +#define MwNresizeHandler "Cresize" +#define MwNtickHandler "Ctick" +#define MwNmenuHandler "Cmenu" +#define MwNmouseDownHandler "CmouseDown" +#define MwNmouseUpHandler "CmouseUp" +#define MwNmouseMoveHandler "CmouseMove" +#define MwNchangedHandler "Cchanged" +#define MwNcomboBoxChangedHandler "CcomboBoxChanged" +#define MwNkeyHandler "Ckey" +#define MwNkeyReleaseHandler "CkeyRelease" +#define MwNcloseHandler "Cclose" +#define MwNfocusInHandler "CfocusIn" +#define MwNfocusOutHandler "CfocusOut" +#define MwNfileChosenHandler "CfileChosen" +#define MwNdirectoryChosenHandler "CdirectoryChosen" +#define MwNcolorChosenHandler "CcolorChosen" +#define MwNdrawHandler "Cdraw" +#define MwNclipboardHandler "Cclipboard" +#define MwNdarkThemeHandler "CdarkTheme" + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/TrueType.h b/widget/milsko/milskosrc/include/Mw/TrueType.h new file mode 100644 index 0000000000..eea90c95f2 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/TrueType.h @@ -0,0 +1,33 @@ +/*! + * @file Mw/TrueType.h + * @brief TrueType utilities + */ +#ifndef __MW_TRUETYPE_H__ +#define __MW_TRUETYPE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Get the TrueType font information + * @param data Font data + * @param size Font size + * @return Information + */ +MWDECL MwTTFInfo MwTTFGetInfo(unsigned char* data, int size); + +/*! + * @brief Free the TrueType font information + * @param info Information + */ +MWDECL void MwTTFFreeInfo(MwTTFInfo info); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/TypeDefs.h b/widget/milsko/milskosrc/include/Mw/TypeDefs.h new file mode 100644 index 0000000000..5989e1ba41 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/TypeDefs.h @@ -0,0 +1,282 @@ +/*! + * @file Mw/TypeDefs.h + * @brief Type definitions + */ +#ifndef __MW_TYPEDEFS_H__ +#define __MW_TYPEDEFS_H__ + +#include +#include + +typedef struct _MwClass * MwClass, MwClassRec; +typedef struct _MwIntegerKeyValue MwIntegerKeyValue; +typedef struct _MwTextKeyValue MwTextKeyValue; +typedef struct _MwUserHandlerArray MwUserHandlerArray; +typedef struct _MwUserHandlerKeyValue MwUserHandlerKeyValue; +typedef struct _MwVoidKeyValue MwVoidKeyValue; +typedef struct _MwMenu* MwMenu; +typedef struct _MwEntry* MwEntry; +typedef struct _MwViewport* MwViewport; +typedef struct _MwListBox* MwListBox; +typedef struct _MwComboBox* MwComboBox; +typedef struct _MwTreeView* MwTreeView; +typedef struct _MwScrollBar* MwScrollBar; +typedef struct _MwLabel* MwLabel; +typedef struct _MwLabelSegment MwLabelSegment; +typedef struct _MwListBoxEntry MwListBoxEntry; +typedef struct _MwTreeViewEntry MwTreeViewEntry; +typedef struct _MwDirectoryEntry MwDirectoryEntry; +typedef struct _MwBox* MwBox; +typedef struct _MwSubWindow* MwSubWindow; +typedef struct _MwTab* MwTab; +typedef struct _MwTable* MwTable; +typedef struct _MwMouse MwMouse; +typedef struct _MwTTFInfo* MwTTFInfo; +#ifdef _MILSKO +typedef struct _MwWidget* MwWidget; +#else +typedef void* MwWidget; +#endif +typedef void (*MwHandler)(MwWidget handle); +typedef int (*MwHandlerWithStatus)(MwWidget handle); +typedef void (*MwHandlerProps)(MwWidget handle, char** key); +typedef void (*MwHandlerProp)(MwWidget handle, const char* key); +typedef void (*MwHandlerChildrenUpdate)(MwWidget handle, MwWidget child, int new_child); +typedef void (*MwHandlerChildrenProp)(MwWidget handle, MwWidget child, const char* key); +typedef void (*MwHandlerKey)(MwWidget handle, int key); +typedef void (*MwHandlerMouse)(MwWidget handle, void* ptr); +typedef void (*MwHandlerExecute)(MwWidget handle, const char* name, void* out, va_list args); +typedef void (*MwHandlerClipboardReceived)(MwWidget handle, const char* data); + +typedef void(MWAPI* MwUserHandler)(MwWidget handle, void* user_data, void* call_data); +typedef void(MWAPI* MwErrorHandler)(int code, const char* message, void* user_data); + +struct _MwTextKeyValue { + char* key; + char* value; +}; + +struct _MwIntegerKeyValue { + char* key; + int value; +}; + +struct _MwUserHandlerArray { + void* user_data; + MwUserHandler handler; +}; + +struct _MwUserHandlerKeyValue { + char* key; + MwUserHandlerArray* value; +}; + +struct _MwVoidKeyValue { + char* key; + void* value; +}; + +#include + +#ifdef _MILSKO +struct _MwWidget { + char* name; + MwLLColor bgcolor; + + MwLL lowlevel; + MwWidget parent; + MwWidget* children; + MwClass widget_class; + + int pressed; + MwPoint mouse_point; + int close; + int prop_event; + + void* internal; + void* opaque; + void* user; + void (*draw_inject)(MwWidget handle); + void (*destroy_inject)(MwWidget handle); + + MwIntegerKeyValue* integer; + MwTextKeyValue* text; + MwUserHandlerKeyValue* handler; + MwVoidKeyValue* data; + + MwWidget* destroy_queue; + MwWidget* tick_list; + + int destroyed; + + void* root_font; + void* root_boldfont; + void* root_monofont; + void* root_boldmonofont; + + int top_step; + MwWidget* draw_queue; + MwWidget* resize_queue; + MwWidget* monitored_entries; + + int berserk; + long last_tick; + + MwBool is_menu; +}; +#endif + +struct _MwMenu { + char* name; + int keep; + MwWidget wsub; + MwMenu* sub; + void* opaque; + int cleaned; +}; + +struct _MwEntry { + int cursor; + int right; + int length; + int active; + int cursor_blink_timer; + MwPoint mouse; +}; + +struct _MwViewport { + MwWidget vscroll; + MwWidget hscroll; + MwWidget frame; + MwWidget inframe; + int vchanged; + int hchanged; +}; + +struct _MwListBoxEntry { + char** name; + MwLLPixmap pixmap; +}; + +struct _MwListBox { + MwWidget vscroll; + MwWidget frame; + MwListBoxEntry* list; + unsigned long click_time; + int pressed; + int* width; + int* alignment; + int changed; +}; + +struct _MwComboBox { + char** list; + int opened; + MwWidget listbox; +}; + +struct _MwTreeViewEntry { + char* label; + MwLLPixmap pixmap; + MwTreeViewEntry** tree; + int opened; + int selected; + unsigned long click_time; + MwTreeViewEntry* parent; +}; + +struct _MwTreeView { + MwWidget frame; + MwWidget vscroll; + int changed; + MwTreeViewEntry** tree; + + MwPoint pressed; +}; + +struct _MwScrollBar { + MwPoint point; + int drag; + int pos; +}; + +struct _MwLabel { + MwLabelSegment* segment; + MwHandler draw; +}; + +struct _MwLabelSegment { + int key; + unsigned char value; +}; + +struct _MwDirectoryEntry { + char* name; + int type; + MwOffset size; + time_t mtime; +}; + +struct _MwBox { + int layout; +}; + +struct _MwTable { + int layout; + MwWidget* widgets; +}; + +struct _MwSubWindow { + MwWidget frame; + MwWidget minimize; + MwWidget maximize; + MwWidget close; + int maximized; + int minimized; + int x; + int y; + int width; + int height; + MwPoint cursor_start; + MwPoint base; +}; + +struct _MwTab { + MwWidget* frames; + char** names; +}; + +struct _MwMouse { + MwPoint point; + int button; +}; + +struct _MwTTFInfo { + char* family; + int weight; +}; + +struct _MwClass { + MwHandlerWithStatus create; + MwHandler destroy; + MwHandler draw; + MwHandler click; + MwHandler parent_resize; + MwHandlerProp prop_change; + MwHandler mouse_move; + MwHandlerMouse mouse_up; + MwHandlerMouse mouse_down; + MwHandlerKey key; + MwHandlerExecute execute; + MwHandler tick; + MwHandler resize; + MwHandlerChildrenUpdate children_update; + MwHandlerChildrenProp children_prop_change; + MwHandlerClipboardReceived clipboard; + MwHandlerProps props_change; + void* reserved1; + void* reserved2; + void* reserved3; +}; + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Unicode.h b/widget/milsko/milskosrc/include/Mw/Unicode.h new file mode 100644 index 0000000000..32edeaabcc --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Unicode.h @@ -0,0 +1,53 @@ +/*! + * @file Mw/Unicode.h + * @brief Handles UTF8 stuff + */ +#ifndef __MW_UNICODE_H__ +#define __MW_UNICODE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Converts UTF-8 to UTF-32 + * @brief input Input + * @brief output Output + * @return Bytes this multibyte takes + */ +MWDECL int MWAPI MwUTF8ToUTF32(const char* input, int* output); + +/*! + * @brief Calculates UTF-8 string length + * @brief input Input + * @return Length + */ +MWDECL int MWAPI MwUTF8Length(const char* input); + +/*! + * @brief Copies UTF-8 string to other string + * @brief src Source + * @brief srcskip Length to be skipped + * @brief dst Destination + * @brief dstskip Length to be skipped + * @brief len Length + * @return Copied length in bytes + */ +MWDECL int MWAPI MwUTF8Copy(const char* src, int srcskip, char* dst, int dstskip, int len); + +/*! + * @brief Converts UTF-32 to UTF-8 + * @brief input Input + * @brief output Output + * @return Bytes this wide byte takes + */ +MWDECL int MWAPI MwUTF32ToUTF8(int input, char* output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Version.h b/widget/milsko/milskosrc/include/Mw/Version.h new file mode 100644 index 0000000000..9821dc6a4b --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Version.h @@ -0,0 +1,33 @@ +/*! + * @file Mw/Version.h + * @brief Version informations + */ +#ifndef __MW_VERSION_H__ +#define __MW_VERSION_H__ + +/*! + * @brief Major version + */ +#define MwMAJOR 1 + +/*! + * @brief Minor version + */ +#define MwMINOR 3 + +/*! + * @brief Patchlevel of version, if patchlevel_alphabet is a or bigger, this value is calculated by `patchlevel_alphabet - 'a' + 1`. Otherwise 0 + */ +#define MwPATCH 0 + +/*! + * @brief Version in string + */ +#define MwVERSION "1.4" + +/*! + * @brief Version in string + */ +MWDECL const char* MwVersionString; + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Box.h b/widget/milsko/milskosrc/include/Mw/Widget/Box.h new file mode 100644 index 0000000000..172e5f6e28 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Box.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Box.h + * @brief Box widget + */ +#ifndef __MW_WIDGET_BOX_H__ +#define __MW_WIDGET_BOX_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Box widget class + */ +MWDECL MwClass MwBoxClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Button.h b/widget/milsko/milskosrc/include/Mw/Widget/Button.h new file mode 100644 index 0000000000..a8c6ca8bcc --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Button.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Button.h + * @brief Button widget + */ +#ifndef __MW_WIDGET_BUTTON_H__ +#define __MW_WIDGET_BUTTON_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Button widget class + */ +MWDECL MwClass MwButtonClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Calendar.h b/widget/milsko/milskosrc/include/Mw/Widget/Calendar.h new file mode 100644 index 0000000000..a01968fc68 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Calendar.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Calendar.h + * @brief Calendar widget + */ +#ifndef __MW_WIDGET_CALENDAR_H__ +#define __MW_WIDGET_CALENDAR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Calendar widget class + */ +MWDECL MwClass MwCalendarClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/CheckBox.h b/widget/milsko/milskosrc/include/Mw/Widget/CheckBox.h new file mode 100644 index 0000000000..0b7cb1de52 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/CheckBox.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/CheckBox.h + * @brief CheckBox widget + */ +#ifndef __MW_WIDGET_CHECKBOX_H__ +#define __MW_WIDGET_CHECKBOX_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief CheckBox widget class + */ +MWDECL MwClass MwCheckBoxClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/ComboBox.h b/widget/milsko/milskosrc/include/Mw/Widget/ComboBox.h new file mode 100644 index 0000000000..7b2dc2fca5 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/ComboBox.h @@ -0,0 +1,48 @@ +/*! + * @file Mw/Widget/ComboBox.h + * @brief ComboBox widget + */ +#ifndef __MW_WIDGET_COMBOBOX_H__ +#define __MW_WIDGET_COMBOBOX_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief ComboBox widget class + */ +MWDECL MwClass MwComboBoxClass; + +/*! + * @brief Adds the entry to combobox + * @param handle Widget + * @param index Index + * @param text Text + */ +MwInline void MwComboBoxAdd(MwWidget handle, int index, const char* text) { + MwVaWidgetExecute(handle, "mwComboBoxAdd", NULL, index, text); +} + +/*! + * @brief Gets the entry from combobox + * @param handle Widget + * @param index Index + * @return Text + */ +MwInline const char* MwComboBoxGet(MwWidget handle, int index) { + const char* text; + MwVaWidgetExecute(handle, "mwComboBoxGet", (void*)&text, index); + + return text; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Entry.h b/widget/milsko/milskosrc/include/Mw/Widget/Entry.h new file mode 100644 index 0000000000..614b578dbe --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Entry.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Entry.h + * @brief Entry widget + */ +#ifndef __MW_WIDGET_ENTRY_H__ +#define __MW_WIDGET_ENTRY_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Entry widget class + */ +MWDECL MwClass MwEntryClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Frame.h b/widget/milsko/milskosrc/include/Mw/Widget/Frame.h new file mode 100644 index 0000000000..658392e1e4 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Frame.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Frame.h + * @brief Frame widget + */ +#ifndef __MW_WIDGET_FRAME_H__ +#define __MW_WIDGET_FRAME_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Frame widget class + */ +MWDECL MwClass MwFrameClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Image.h b/widget/milsko/milskosrc/include/Mw/Widget/Image.h new file mode 100644 index 0000000000..39834cbd5e --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Image.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Image.h + * @brief Image widget + */ +#ifndef __MW_WIDGET_IMAGE_H__ +#define __MW_WIDGET_IMAGE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Image widget class + */ +MWDECL MwClass MwImageClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Label.h b/widget/milsko/milskosrc/include/Mw/Widget/Label.h new file mode 100644 index 0000000000..f9338e337e --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Label.h @@ -0,0 +1,36 @@ +/*! + * @file Mw/Widget/Label.h + * @brief Label widget + */ +#ifndef __MW_WIDGET_LABEL_H__ +#define __MW_WIDGET_LABEL_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Label widget class + */ +MWDECL MwClass MwLabelClass; + +/*! + * @brief Sets the custom data for seven segment + * @param handle Widget + * @param index Index + * @param data Data, `GFEDCBA` as 7-bit value + * @note See https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg for what alphabets mean here + * */ +MwInline void MwLabelSetSevenSegment(MwWidget handle, int index, int data) { + MwVaWidgetExecute(handle, "mwLabelSetSevenSegment", NULL, index, data); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/ListBox.h b/widget/milsko/milskosrc/include/Mw/Widget/ListBox.h new file mode 100644 index 0000000000..f4fe48f462 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/ListBox.h @@ -0,0 +1,100 @@ +/*! + * @file Mw/Widget/ListBox.h + * @brief ListBox widget + */ +#ifndef __MW_WIDGET_LISTBOX_H__ +#define __MW_WIDGET_LISTBOX_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief ListBox widget class + */ +MWDECL MwClass MwListBoxClass; + +/*! + * @brief Sets item on the listbox + * @param handle Widget + * @param row Row + * @param col Column + * @param text Text + * @return Index + */ +MwInline int MwListBoxSet(MwWidget handle, int row, int col, const char* text) { + int out; + + MwVaWidgetExecute(handle, "mwListBoxSet", (void*)&out, row, col, text); + + return out; +} + +/*! + * @brief Sets the icon of the row + * @param handle Widget + * @param index Index + * @param icon Icon + */ +MwInline void MwListBoxSetIcon(MwWidget handle, int index, MwLLPixmap icon) { + MwVaWidgetExecute(handle, "mwListBoxSetIcon", NULL, index, icon); +} + +/*! + * @brief Deletes item from the listbox + * @param handle Widget + * @param index Index + */ +MwInline void MwListBoxDelete(MwWidget handle, int index) { + MwVaWidgetExecute(handle, "mwListBoxDelete", NULL, index); +} + +/*! + * @brief Gets item from the listbox + * @param handle Widget + * @param index Index + * @return Item + */ +MwInline const char* MwListBoxGet(MwWidget handle, int index) { + const char* out; + MwVaWidgetExecute(handle, "mwListBoxGet", (void*)&out, index); + return out; +} + +/*! + * @brief Sets an item width of the listbox + * @param handle Widget + * @param index Column index + * @param width Width + */ +MwInline void MwListBoxSetWidth(MwWidget handle, int index, int width) { + MwVaWidgetExecute(handle, "mwListBoxSetWidth", NULL, index, width); +} + +/*! + * @brief Sets an item alignment of the listbox + * @param handle Widget + * @param index Column index + * @param alignment Alignment + */ +MwInline void MwListBoxSetAlignment(MwWidget handle, int index, int alignment) { + MwVaWidgetExecute(handle, "mwListBoxSetAlignment", NULL, index, alignment); +} + +/*! + * @brief Resets the listbox + * @param handle Widget + */ +MwInline void MwListBoxReset(MwWidget handle) { + MwVaWidgetExecute(handle, "mwListBoxReset", NULL); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Menu.h b/widget/milsko/milskosrc/include/Mw/Widget/Menu.h new file mode 100644 index 0000000000..621ba06d93 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Menu.h @@ -0,0 +1,38 @@ +/*! + * @file Mw/Widget/Menu.h + * @brief Menu widget + */ +#ifndef __MW_WIDGET_MENU_H__ +#define __MW_WIDGET_MENU_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Menu widget class + */ +MWDECL MwClass MwMenuClass; + +/*! + * @brief Adds a menu + * @param handle Widget + * @param menu Menu + * @param name Menu name + * @return Menu + */ +MwInline MwMenu MwMenuAdd(MwWidget handle, MwMenu menu, const char* name) { + MwMenu out; + MwVaWidgetExecute(handle, "mwMenuAdd", &out, menu, name); + return out; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/NumberEntry.h b/widget/milsko/milskosrc/include/Mw/Widget/NumberEntry.h new file mode 100644 index 0000000000..802018a16a --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/NumberEntry.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/NumberEntry.h + * @brief NumberEntry widget + */ +#ifndef __MW_WIDGET_NUMBERENTRY_H__ +#define __MW_WIDGET_NUMBERENTRY_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief NumberEntry widget class + */ +MWDECL MwClass MwNumberEntryClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/OpenGL.h b/widget/milsko/milskosrc/include/Mw/Widget/OpenGL.h new file mode 100644 index 0000000000..3f7a0c4519 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/OpenGL.h @@ -0,0 +1,73 @@ +/*! + * @file Mw/Widget/OpenGL.h + * @brief OpenGL widget + */ +#ifndef __MW_WIDGET_OPENGL_H__ +#define __MW_WIDGET_OPENGL_H__ + +#include +#include +#include + +#if !defined(MW_OPENGL_NO_INCLUDE) && !defined(__gl_h_) +#ifdef _WIN32 +#include +#elif defined(__APPLE__) +#else +#include +#endif +#if defined(__APPLE__) +#include +#include +#else +#include +#include +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY APIENTRY +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief OpenGL widget class + */ +MWDECL MwClass MwOpenGLClass; + +/*! + * @brief Make a widget current OpenGL context + * @param handle Widget + */ +MwInline void MwOpenGLMakeCurrent(MwWidget handle) { + MwVaWidgetExecute(handle, "mwOpenGLMakeCurrent", NULL); +} + +/*! + * @brief Get a procedure from OpenGL + * @param handle Widget + * @param name Name + * @return Procedure + */ +MwInline void* MwOpenGLGetProcAddress(MwWidget handle, const char* name) { + void* out; + MwVaWidgetExecute(handle, "mwOpenGLGetProcAddress", &out, name); + return out; +} + +/*! + * @brief Swaps the buffer of OpenGL context + * @param handle Widget + */ +MwInline void MwOpenGLSwapBuffer(MwWidget handle) { + MwVaWidgetExecute(handle, "mwOpenGLSwapBuffer", NULL); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/ProgressBar.h b/widget/milsko/milskosrc/include/Mw/Widget/ProgressBar.h new file mode 100644 index 0000000000..96fce26130 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/ProgressBar.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/ProgressBar.h + * @brief ProgressBar widget + */ +#ifndef __MW_WIDGET_PROGRESSBAR_H__ +#define __MW_WIDGET_PROGRESSBAR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief ProgressBar widget class + */ +MWDECL MwClass MwProgressBarClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/RadioBox.h b/widget/milsko/milskosrc/include/Mw/Widget/RadioBox.h new file mode 100644 index 0000000000..9b4a400a36 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/RadioBox.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/RadioBox.h + * @brief RadioBox widget + */ +#ifndef __MW_WIDGET_RADIOBOX_H__ +#define __MW_WIDGET_RADIOBOX_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief RadioBox widget class + */ +MWDECL MwClass MwRadioBoxClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/ScrollBar.h b/widget/milsko/milskosrc/include/Mw/Widget/ScrollBar.h new file mode 100644 index 0000000000..de0d44780d --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/ScrollBar.h @@ -0,0 +1,36 @@ +/*! + * @file Mw/Widget/ScrollBar.h + * @brief ScrollBar widget + */ +#ifndef __MW_WIDGET_SCROLLBAR_H__ +#define __MW_WIDGET_SCROLLBAR_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief ScrollBar widget class + */ +MWDECL MwClass MwScrollBarClass; + +/*! + * @brief Calculates a visible length of scrollbar + * @param handle Widget + * @return Visible length + */ +MwInline int MwScrollBarGetVisibleLength(MwWidget handle) { + int out; + MwVaWidgetExecute(handle, "mwScrollBarGetVisibleLength", &out, NULL); + return out; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Separator.h b/widget/milsko/milskosrc/include/Mw/Widget/Separator.h new file mode 100644 index 0000000000..a8bbc14ca2 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Separator.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Separator.h + * @brief Separator widget + */ +#ifndef __MW_WIDGET_SEPARATOR_H__ +#define __MW_WIDGET_SEPARATOR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Separator widget class + */ +MWDECL MwClass MwSeparatorClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/SubMenu.h b/widget/milsko/milskosrc/include/Mw/Widget/SubMenu.h new file mode 100644 index 0000000000..636f29bc45 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/SubMenu.h @@ -0,0 +1,46 @@ +/*! + * @file Mw/Widget/SubMenu.h + * @brief SubMenu widget + */ +#ifndef __MW_WIDGET_SUBMENU_H__ +#define __MW_WIDGET_SUBMENU_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief SubMenu widget class + */ +MWDECL MwClass MwSubMenuClass; + +/*! + * @brief Makes submenu appear + * @param handle Handle + * @param menu Menu + * @param point Point + * @param diff_calc Toggles different way to calculate positiion + */ +MwInline void MwSubMenuAppear(MwWidget handle, MwMenu menu, MwPoint* point, int diff_calc) { + MwVaWidgetExecute(handle, "mwSubMenuAppear", NULL, menu, point, diff_calc); +} + +/*! + * @brief Calculates the size of submenu + * @param handle Handle + * @param menu Menu + * @param rect Size + */ +MwInline void MwSubMenuGetSize(MwWidget handle, MwMenu menu, MwRect* rect) { + MwVaWidgetExecute(handle, "mwSubMenuGetSize", NULL, menu, rect); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/SubWindow.h b/widget/milsko/milskosrc/include/Mw/Widget/SubWindow.h new file mode 100644 index 0000000000..c7ce2e1f2c --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/SubWindow.h @@ -0,0 +1,36 @@ +/*! + * @file Mw/Widget/SubWindow.h + * @brief SubWindow widget + */ +#ifndef __MW_WIDGET_SUBWINDOW_H__ +#define __MW_WIDGET_SUBWINDOW_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief SubWindow widget class + */ +MWDECL MwClass MwSubWindowClass; + +/*! + * @brief Get parent widget where widgets should be placed + * @param handle Widget + * @return Widget + */ +MwInline MwWidget MwSubWindowGetFrame(MwWidget handle) { + MwWidget out; + MwVaWidgetExecute(handle, "mwSubWindowGetFrame", &out); + return out; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Tab.h b/widget/milsko/milskosrc/include/Mw/Widget/Tab.h new file mode 100644 index 0000000000..9f80a0dfb7 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Tab.h @@ -0,0 +1,59 @@ +/*! + * @file Mw/Widget/Tab.h + * @brief Tab widget + */ +#ifndef __MW_WIDGET_TAB_H__ +#define __MW_WIDGET_TAB_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Tab widget class + */ +MWDECL MwClass MwTabClass; + +/*! + * @brief Adds a tab + * @param handle Widget + * @param name Tab name + * @return Frame + */ +MwInline MwWidget MwTabAdd(MwWidget handle, const char* name) { + MwWidget out; + MwVaWidgetExecute(handle, "mwTabAdd", &out, name); + return out; +} + +/*! + * @brief Gets a tab frame + * @param handle Widget + * @param name Tab name + * @return Frame + */ +MwInline MwWidget MwTabGetFrame(MwWidget handle, const char* name) { + MwWidget out; + MwVaWidgetExecute(handle, "mwTabGetFrame", &out, name); + return out; +} + +/*! + * @brief Focus on a tab frame + * @param handle Widget + * @param name Tab name + * @return Frame + */ +MwInline void MwTabFocus(MwWidget handle, const char* name) { + MwVaWidgetExecute(handle, "mwTabFocus", NULL, name); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Table.h b/widget/milsko/milskosrc/include/Mw/Widget/Table.h new file mode 100644 index 0000000000..1d39ec3082 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Table.h @@ -0,0 +1,24 @@ +/*! + * @file Mw/Widget/Table.h + * @brief Table widget + */ +#ifndef __MW_WIDGET_TABLE_H__ +#define __MW_WIDGET_TABLE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Table widget class + */ +MWDECL MwClass MwTableClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/TreeView.h b/widget/milsko/milskosrc/include/Mw/Widget/TreeView.h new file mode 100644 index 0000000000..f76f6af0a0 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/TreeView.h @@ -0,0 +1,110 @@ +/*! + * @file Mw/Widget/TreeView.h + * @brief TreeView widget + */ +#ifndef __MW_WIDGET_TREEVIEW_H__ +#define __MW_WIDGET_TREEVIEW_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief TreeView widget class + */ +MWDECL MwClass MwTreeViewClass; + +/*! + * @brief Adds item to the treeview + * @param handle Widget + * @parma parent Parent + * @parma pixmap Pixmap + * @param item Item + */ +MwInline void* MwTreeViewAdd(MwWidget handle, void* parent, MwLLPixmap pixmap, const char* item) { + void* out; + MwVaWidgetExecute(handle, "mwTreeViewAdd", &out, parent, pixmap, item); + return out; +} + +/*! + * @brief Deletes item from the treeview + * @param handle Widget + * @param item Item + */ +MwInline void MwTreeViewDelete(MwWidget handle, void* item) { + MwVaWidgetExecute(handle, "mwTreeViewDelete", NULL, item); +} + +/*! + * @brief Resets the treeview + * @param handle Widget + */ +MwInline void MwTreeViewReset(MwWidget handle) { + MwVaWidgetExecute(handle, "mwTreeViewReset", NULL); +} + +/*! + * @brief Gets item from the treeview + * @param handle Widget + * @param item Item + * @return Item + */ +MwInline const char* MwTreeViewGet(MwWidget handle, void* item) { + const char* out; + MwVaWidgetExecute(handle, "mwTreeViewGet", (void*)&out, item); + return out; +} + +/*! + * @brief Sets the label of ithe item + * @param handle Widget + * @param item Item + * @param label Label + */ +MwInline void MwTreeViewSetLabel(MwWidget handle, void* item, const char* label) { + MwVaWidgetExecute(handle, "mwTreeViewSetLabel", NULL, item, label); +} + +/*! + * @brief Sets the pixmap of ithe item + * @param handle Widget + * @param item Item + * @param pixmap Pixmap + */ +MwInline void MwTreeViewSetPixmap(MwWidget handle, void* item, MwLLPixmap pixmap) { + MwVaWidgetExecute(handle, "mwTreeViewSetPixmap", NULL, item, pixmap); +} + +/*! + * @brief Sets the opened state of ithe item + * @param handle Widget + * @param item Item + * @param opened Opened or not + */ +MwInline void MwTreeViewSetOpened(MwWidget handle, void* item, int opened) { + MwVaWidgetExecute(handle, "mwTreeViewSetOpened", NULL, item, opened); +} + +/*! + * @brief Gets the opened state of ithe item + * @param handle Widget + * @param item Item + * @return Opened or not + */ +MwInline int MwTreeViewGetOpened(MwWidget handle, void* item) { + int out; + MwVaWidgetExecute(handle, "mwTreeViewGetOpened", (void*)&out, item); + + return out; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Viewport.h b/widget/milsko/milskosrc/include/Mw/Widget/Viewport.h new file mode 100644 index 0000000000..d60848cbb4 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Viewport.h @@ -0,0 +1,46 @@ +/*! + * @file Mw/Widget/Viewport.h + * @brief Viewport widget + */ +#ifndef __MW_WIDGET_VIEWPORT_H__ +#define __MW_WIDGET_VIEWPORT_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Viewport widget class + */ +MWDECL MwClass MwViewportClass; + +/*! + * @brief Get parent widget where widgets should be placed + * @param handle Widget + * @return Widget + */ +MwInline MwWidget MwViewportGetViewport(MwWidget handle) { + MwWidget out; + MwVaWidgetExecute(handle, "mwViewportGetViewport", &out); + return out; +} + +/*! + * @brief Set viewport size + * @param handle Widget + * @param w Width + * @param h Height + */ +MwInline void MwViewportSetSize(MwWidget handle, int w, int h) { + MwVaWidgetExecute(handle, "mwViewportSetSize", NULL, w, h); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Vulkan.h b/widget/milsko/milskosrc/include/Mw/Widget/Vulkan.h new file mode 100644 index 0000000000..4c7e0bb132 --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Vulkan.h @@ -0,0 +1,112 @@ +/*! + * @file Mw/Widget/Vulkan.h + * @brief Vulkan widget + * @warning This header is not documented yet + */ + +/** + * ioixd maintains this file. nishi doesn't know vulkan at all + */ + +#ifndef __MW_WIDGET_VULKAN_H__ +#define __MW_WIDGET_VULKAN_H__ + +#if defined(MW_VULKAN) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) +#error Vulkan is unsupported on the requested platform. +#endif + +#if !defined(MW_VULKAN_NO_INCLUDE) +#include +#include +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Vulkan widget class + */ +MWDECL MwClass MwVulkanClass; + +/*! + * @brief Configuration options that can be passed to setup parts of the Vulkan widget. + */ +typedef struct _MwVulkanConfig { + /*! + * @brief Vulkan API version (default: VK_API_VERSION_1_0) + */ + MwU32 api_version; + /*! + * @brief Vulkan version (default: VK_VERSION_1_0) + */ + MwU32 vk_version; + /*! + * @brief Whether or not to enable validation layers (default: false) + */ + int validation_layers; +} MwVulkanConfig; + +/*! + * @brief Field that can be gotten from Vulkan. + */ +enum MwVULKANFIELD { + /*! + * @brief The address of the vulkan widget's vkGetInstanceProcAddr function (PFN_vkGetInstanceProcAddr) + */ + MwVULKANFIELD_GETINSTANCEPROCADDR = 0, + /*! + * @brief The address of the vulkan widget's instance (VkInstance) + */ + MwVULKANFIELD_INSTANCE, + /*! + * @brief The address of the vulkan widget's surface (VkSurfaceKHR) + */ + MwVULKANFIELD_SURFACE, + /*! + * @brief The address of the vulkan widget's physical device (VkPhysicalDevice) + */ + MwVULKANFIELD_PHYSICALDEVICE, + /*! + * @brief The address of the vulkan widget's logical device (VkDevice) + */ + MwVULKANFIELD_LOGICALDEVICE, + /*! + * @brief The address of the index that the vulkan widget uses for the graphics queue (uint32_t *) + */ + MwVULKANFIELD_GRAPHICSQUEUEINDEX, + /*! + * @brief The address of the index that the vulkan widget uses for the present queue (uint32_t *) + */ + MwVULKANFIELD_PRESENTQUEUEINDEX, + MwVULKANFIELD_GRAPHICSQUEUE, + /*! + * @brief The address of the vulkan widget's graphics queue (VkQueue) + */ + MwVULKANFIELD_PRESENTQUEUE, +}; + +/*! + * @brief Function for getting a field from within Vulkan. + * @note Consult the documentation for MwVULKANFIELD to know what type is expected for output. + */ +MwInline void* MwVulkanGetField(MwWidget handle, int field, int* err) { + void* field_out; + MwVaWidgetExecute(handle, "mwVulkanGetField", &field_out, field, err); + return field_out; +} + +/*! + * @brief Return whether Vulkan is installed on the target platform. + */ +MWDECL int MWAPI MwVulkanSupported(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/include/Mw/Widget/Window.h b/widget/milsko/milskosrc/include/Mw/Widget/Window.h new file mode 100644 index 0000000000..6a98b68a7d --- /dev/null +++ b/widget/milsko/milskosrc/include/Mw/Widget/Window.h @@ -0,0 +1,45 @@ +/*! + * @file Mw/Widget/Window.h + * @brief Window widget + */ +#ifndef __MW_WIDGET_WINDOW_H__ +#define __MW_WIDGET_WINDOW_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Window widget class + */ +MWDECL MwClass MwWindowClass; + +/*! + * @brief Makes window borderless + * @param handle Widget + * @param toggle Toggle + */ +MwInline void MwWindowMakeBorderless(MwWidget handle, int toggle) { + MwVaWidgetExecute(handle, "mwWindowMakeBorderless", NULL, toggle); +} + +/*! + * @brief Whether the window should close + * @param handle Widget + * @return bool + */ +MwInline MwBool MwWindowShouldClose(MwWidget handle) { + MwBool res = MwFALSE; + MwVaWidgetExecute(handle, "mwWindowShouldClose", NULL, &res); + return res; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/widget/milsko/milskosrc/milsko.xml b/widget/milsko/milskosrc/milsko.xml new file mode 100644 index 0000000000..a94c847ca9 --- /dev/null +++ b/widget/milsko/milskosrc/milsko.xml @@ -0,0 +1,1002 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + 0 + + + + 0 + + + + + 0x1 + + + + + + + + + 0 + + + + 0 + + + + 1 + + + + + + + 0x80000001 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0x0fffffff + + 0xf + 0xf0 + 0x10 + 0x20 + 0x40 + 0x80 + + 0x80000000 + 0xc0000000 + 0xa0000000 + + +
+ + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/widget/milsko/milskosrc/pl/ostype/ClassicMacOS.pl b/widget/milsko/milskosrc/pl/ostype/ClassicMacOS.pl new file mode 100644 index 0000000000..1f2e532d61 --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/ClassicMacOS.pl @@ -0,0 +1,12 @@ +use_backend("classicmacos"); + +print( +"Compiling for Classic Mac OS via ./configure currently outputs a broken executable and it only supports PowerPC. Help is wanted. In the mean time, use CMake." +); + +$cc = $ENV{RETRO68_TOOLCHAIN_PATH} . "/bin/powerpc-apple-macos-gcc"; +$ar = $ENV{RETRO68_TOOLCHAIN_PATH} . "/bin/powerpc-apple-macos-ar"; +add_cflags("-DCLASSIC_MAC_OS"); +add_cflags("-DSTBI_NO_THREAD_LOCALS"); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/Darwin.pl b/widget/milsko/milskosrc/pl/ostype/Darwin.pl new file mode 100644 index 0000000000..5d5baabdb0 --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/Darwin.pl @@ -0,0 +1,10 @@ +$library_suffix = ".dylib"; +set_shared_flag("-dynamiclib"); + +#use_backend("cocoa"); +new_object("src/backend/nococoa.m"); + +add_cflags("-DSTBI_NO_THREAD_LOCALS"); +add_ldflags("-framework Cocoa -lobjc"); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/FreeBSD.pl b/widget/milsko/milskosrc/pl/ostype/FreeBSD.pl new file mode 100644 index 0000000000..4d4b17a83d --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/FreeBSD.pl @@ -0,0 +1,19 @@ +my @enabled_backends = (); + +add_incdir2("-I/usr/local/include"); +add_libdir("-L/usr/local/lib -Wl,-R/usr/local/lib"); + +if (param_get("wayland") && not(param_get("tiny"))) { + push(@enabled_backends, "wayland"); +} +if (param_get("x11")) { + push(@enabled_backends, "x11"); +} + +use_backend(@enabled_backends); + +add_libs("-lpthread"); + +add_cflags("-DUSE_DBUS"); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/Haiku.pl b/widget/milsko/milskosrc/pl/ostype/Haiku.pl new file mode 100644 index 0000000000..68322b91b9 --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/Haiku.pl @@ -0,0 +1,3 @@ +use_backend("haiku"); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/Linux.pl b/widget/milsko/milskosrc/pl/ostype/Linux.pl new file mode 100644 index 0000000000..75159d562b --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/Linux.pl @@ -0,0 +1,14 @@ +my @enabled_backends = (); + +if (param_get("wayland") && not(param_get("tiny"))) { + push(@enabled_backends, "wayland"); +} +if (param_get("x11")) { + push(@enabled_backends, "x11"); +} + +add_cflags("-DUSE_DBUS"); + +use_backend(@enabled_backends); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/NetBSD.pl b/widget/milsko/milskosrc/pl/ostype/NetBSD.pl new file mode 100644 index 0000000000..6556cab20e --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/NetBSD.pl @@ -0,0 +1,9 @@ +add_incdir2("-I/usr/X11R7/include -I/usr/pkg/include"); +add_libdir( + "-L/usr/X11R7/lib -Wl,-R/usr/X11R7/lib -L/usr/pkg/lib -Wl,-R/usr/pkg/lib"); +use_backend("x11"); +add_libs("-lpthread"); + +add_cflags("-DUSE_DBUS"); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/OpenBSD.pl b/widget/milsko/milskosrc/pl/ostype/OpenBSD.pl new file mode 100644 index 0000000000..dbbc3be229 --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/OpenBSD.pl @@ -0,0 +1,8 @@ +add_incdir2("-I/usr/local/include"); +add_libdir("-L/usr/local/lib -Wl,-R/usr/local/lib"); +use_backend("x11"); +add_libs("-lpthread"); + +add_cflags("-DUSE_DBUS"); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/SunOS.pl b/widget/milsko/milskosrc/pl/ostype/SunOS.pl new file mode 100644 index 0000000000..f695e4f7fb --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/SunOS.pl @@ -0,0 +1,3 @@ +use_backend("x11"); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/UnixWare.pl b/widget/milsko/milskosrc/pl/ostype/UnixWare.pl new file mode 100644 index 0000000000..a40592bbca --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/UnixWare.pl @@ -0,0 +1,4 @@ +add_libs("-lsocket -lnsl"); +use_backend("x11"); + +1; diff --git a/widget/milsko/milskosrc/pl/ostype/Windows.pl b/widget/milsko/milskosrc/pl/ostype/Windows.pl new file mode 100644 index 0000000000..f79469fc47 --- /dev/null +++ b/widget/milsko/milskosrc/pl/ostype/Windows.pl @@ -0,0 +1,9 @@ +$library_prefix = ""; +$library_suffix = ".dll"; +$executable_suffix = ".exe"; +$math = ""; +add_ldflags("-Wl,--out-implib,src/libMw.dll.a -static-libgcc"); +use_backend("gdi"); +add_libs("-lwinmm"); + +1; diff --git a/widget/milsko/milskosrc/pl/rules.pl b/widget/milsko/milskosrc/pl/rules.pl new file mode 100644 index 0000000000..89f13e93a1 --- /dev/null +++ b/widget/milsko/milskosrc/pl/rules.pl @@ -0,0 +1,227 @@ +new_object("src/*.c"); + +my $gl_libs = ""; +if (param_get("tiny")) { + add_cflags("-Oz"); + if (defined($ENV{CC}) && grep(/^clang$/, $ENV{CC})) { + add_libs("-flto=full"); + add_cflags("-flto=full"); + } + add_cflags("-fdata-sections -ffunction-sections"); + add_libs("-Wl,--gc-sections"); + + # these don't actually disable either, they're here for the final output. + param_set("wayland", 0); + param_set("dbus", 0); +} +if (param_get("classic-theme")) { + add_cflags("-DUSE_CLASSIC_THEME"); +} +if (grep(/^x11$/, @backends)) { + add_cflags("-DUSE_X11"); + new_object("src/backend/x11.c"); + + $gl_libs = "-lGL -lGLU"; + + if (param_get("xrender")) { + add_cflags("-DUSE_XRENDER"); + } +} + +if (grep(/^gdi$/, @backends)) { + add_cflags("-DUSE_GDI"); + new_object("src/backend/gdi.c"); + add_libs("-lgdi32"); + + $gl_libs = "-lopengl32 -lglu32"; +} + +if (grep(/^classicmacos$/, @backends)) { + + #add_cflags("-DCLASSIC_MAC_OS"); + new_object("src/backend/classicmacos.c"); + + $gl_libs = ""; +} + +if (grep(/^wayland$/, @backends)) { + add_cflags("-DUSE_WAYLAND"); + new_object("src/backend/cairo.c"); + new_object("src/backend/wayland/wayland.c"); + new_object("src/backend/wayland/buffer.c"); + new_object("src/backend/wayland/interfaces.c"); + new_object("src/backend/wayland/region.c"); + + if (param_get("opengl")) { + add_cflags("-DWAYLAND_LOAD_OPENGL"); + } + + scan_wayland_protocol_core(); + scan_wayland_protocol("stable", "xdg-shell", ""); + scan_wayland_protocol("stable", "viewporter", ""); + scan_wayland_protocol("stable", "tablet", "-v2"); + scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1"); + scan_wayland_protocol("staging", "cursor-shape", "-v1"); + scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1"); + scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); + scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); + scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); + scan_wayland_protocol_from_file("wlr-layer-shell", + "wlr-layer-shell-unstable-v1.xml"); + + $gl_libs = "-lGL -lGLU"; +} + +if (not(param_get("dbus")) && not(param_get("tiny"))) { + $cflags =~ s/( |^)-DUSE_DBUS( |$)/ /; +} + +if (grep(/( |^)-DUSE_DBUS( |$)/, $cflags)) { + add_cflags(`pkg-config --cflags dbus-1`); +} + +if (grep(/^cocoa$/, @backends) || param_get("gnustep")) { + add_cflags("-DUSE_COCOA"); + new_object("src/backend/cocoa.m"); + + if (param_get("gnustep")) { + add_incdir("-I" . `gnustep-config --variable=GNUSTEP_SYSTEM_HEADERS`); + add_libdir("-L" . `gnustep-config --variable=GNUSTEP_SYSTEM_LIBRARIES`); + add_cflags("-fobjc-runtime=gnustep-2.0 -fblocks"); + add_ldflags("-lobjc -lgnustep-base -lm -lgnustep-gui"); + } + + if (param_get("opengl")) { + new_object("src/widget/opengl_cocoa.m"); + } + +# John Apple my man literally everybody and their mother who knows what opengl is knows its deprecated on macos and i'm not having you spam the console with this + add_cflags("-DGL_SILENCE_DEPRECATION"); + + $gl_libs = "-framework OpenGL"; +} + +if (grep(/^haiku$/, @backends)) { + add_cflags("-DUSE_HAIKU"); + new_object("src/backend/haiku.cc"); + add_libs("-lbe"); +} + +if (param_get("stb-image")) { + add_cflags("-DUSE_STB_IMAGE"); + if (param_get("tiny")) { + add_cflags("-DSTB_IMAGE_STATIC"); + add_cflags("-DSTB_IMAGE_IMPLEMENTATION"); + } +} +else { + new_object("external/libjpeg/src/*.c"); + new_object("external/libpng/src/*.c"); + add_incdir("-Iexternal/libjpeg/include -Iexternal/libpng/include"); +} +if (param_get("stb-truetype")) { + add_cflags("-DUSE_STB_TRUETYPE"); +} +if (param_get("allow-sloppy-focus")) { + add_cflags("-DALLOW_SLOPPY_FOCUS"); +} + +add_incdir("-Iexternal/libz/include"); + +if (param_get("freetype2")) { + add_cflags("-DUSE_FREETYPE2"); + if (!$cross) { + add_cflags(`pkg-config --cflags freetype2`); + } +} + +if (param_get("gdi-text")) { + add_cflags("-DUSE_GDI_TEXT"); +} + +if (param_get("vulkan") && param_get("vulkan-string-helper")) { + add_cflags("-DHAS_VK_ENUM_STRING_HELPER"); +} + +new_object("src/icon/*.c"); +new_object("src/cursor/*.c"); +new_object("src/text/*.c"); +new_object("src/text/font/*.c"); + +new_object("src/widget/box.c"); +new_object("src/widget/button.c"); +new_object("src/widget/calendar.c"); +new_object("src/widget/checkbox.c"); +new_object("src/widget/combobox.c"); +new_object("src/widget/entry.c"); +new_object("src/widget/frame.c"); +new_object("src/widget/image.c"); +new_object("src/widget/label.c"); +new_object("src/widget/listbox.c"); +new_object("src/widget/menu.c"); +new_object("src/widget/numberentry.c"); +new_object("src/widget/progressbar.c"); +new_object("src/widget/radiobox.c"); +new_object("src/widget/scrollbar.c"); +new_object("src/widget/separator.c"); +new_object("src/widget/submenu.c"); +new_object("src/widget/subwindow.c"); +new_object("src/widget/tab.c"); +new_object("src/widget/table.c"); +new_object("src/widget/treeview.c"); +new_object("src/widget/viewport.c"); +new_object("src/widget/window.c"); + +new_object("src/widget/opengl.c"); +new_object("src/widget/vulkan.c"); + +if (param_get("opengl")) { + add_cflags("-DMW_OPENGL"); +} +if (param_get("vulkan")) { + add_cflags("-DMW_VULKAN"); +} + +new_object("src/dialog/*.c"); + +new_object("src/abstract/*.c"); + +new_object("external/*.c"); +new_object("external/libz/src/*.c"); + +new_example("examples/basic/example"); +new_example("examples/basic/rotate"); +new_example("examples/basic/image"); +new_example("examples/basic/scrollbar"); +new_example("examples/basic/checkbox"); +new_example("examples/basic/radiobox"); +new_example("examples/basic/messagebox"); +new_example("examples/basic/viewport"); +new_example("examples/basic/listbox"); +new_example("examples/basic/progressbar"); +new_example("examples/basic/colorpicker"); +new_example("examples/basic/combobox"); +new_example("examples/basic/treeview"); +new_example("examples/basic/box"); +new_example("examples/basic/clipboard"); +new_example("examples/basic/sevensegment"); +new_example("examples/basic/calculator"); +new_example("examples/basic/filechooser"); +new_example("examples/basic/periodic"); +new_example("examples/basic/subwindow"); +new_example("examples/basic/tab"); + +if (param_get("opengl")) { + new_example("examples/gldemos/boing", $gl_libs); + new_example("examples/gldemos/clock", $gl_libs); + new_example("examples/gldemos/cube", $gl_libs); + new_example("examples/gldemos/gears", $gl_libs); + new_example("examples/gldemos/triangle", $gl_libs); + new_example("examples/gldemos/tripaint", $gl_libs); +} + +if (param_get("vulkan")) { + new_example("examples/vkdemos/vulkan"); +} + +1; diff --git a/widget/milsko/milskosrc/pl/utils.pl b/widget/milsko/milskosrc/pl/utils.pl new file mode 100644 index 0000000000..504e8dcbf5 --- /dev/null +++ b/widget/milsko/milskosrc/pl/utils.pl @@ -0,0 +1,176 @@ +sub add_incdir { + my $input = $_[0]; + $input =~ s/\r?\n/ /g; + + $incdir = "${incdir} ${input}"; +} + +sub add_incdir2 { + my $input = $_[0]; + $input =~ s/\r?\n/ /g; + + $incdir2 = "${incdir2} ${input}"; +} + +sub add_cflags { + my $input = $_[0]; + $input =~ s/\r?\n/ /g; + + $cflags = "${cflags} ${input}"; +} + +sub add_libdir { + my $input = $_[0]; + $input =~ s/\r?\n/ /g; + + $libdir = "${libdir} ${input}"; +} + +sub add_ldflags { + my $input = $_[0]; + $input =~ s/\r?\n/ /g; + + $ldflags = "${ldflags} ${input}"; +} + +sub add_libs { + my $input = $_[0]; + $input =~ s/\r?\n/ /g; + + $libs = "${libs} ${input}"; +} + +sub new_example { + if (@_ == 2) { + $examples_libs{"$_[0]${executable_suffix}"} = $_[1]; + } + push(@examples_targets, "${_[0]}${executable_suffix}"); +} + +sub set_shared_flag { + @shared = $_[0]; +} + +sub new_object { + my @l = glob($_[0]); + foreach my $e (@l) { + $e =~ s/\.(cc|c|m)$/$object_suffix/; + push(@library_targets, $e); + } +} + +sub use_backend { + foreach my $l (@_) { + push(@backends, $l); + } +} + +sub scan_wayland_protocol_core { + my $proto_c = "src/backend/wayland/wayland-core-protocol.c"; + + if ( + system( +"wayland-scanner private-code /usr/share/wayland/wayland.xml ${proto_c}" + ) != 0 + ) + { + print( +"^ Error on getting private code for /usr/share/wayland/wayland.xml\n" + ); + } + else { + new_object($proto_c); + } + if ( + system( +"wayland-scanner client-header /usr/share/wayland/wayland.xml include/Mw/LowLevel/Wayland/wayland-core-protocol.h" + ) + ) + { + print( +"^ Error on getting client header for /usr/share/wayland/wayland.xml\n" + ); + } +} + +sub scan_wayland_protocol { + my $tier = $_[0]; + my $proto = $_[1]; + my $ver = $_[2]; + + my $proto_c = "src/backend/wayland/wayland-${proto}-protocol.c"; + + if ( + system( +"wayland-scanner private-code /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${proto_c}" + ) != 0 + ) + { + print( +"^ Error on getting private code for /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml\n" + ); + } + else { + new_object($proto_c); + } + if ( + system( +"wayland-scanner client-header /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml include/Mw/LowLevel/Wayland/${proto}-client-protocol.h" + ) + ) + { + print( +"^ Error on getting client header for /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml\n" + ); + } +} + +sub scan_wayland_protocol_from_file { + my $proto = $_[0]; + my $file = $_[1]; + my $proto_c = "src/backend/wayland/wayland-${proto}-protocol.c"; + + if ( + system( + "wayland-scanner private-code ./resource/wayland/${file} ${proto_c}" + ) != 0 + ) + { + print( + "^ Error on getting private code for ./resource/wayland/${file}\n"); + } + else { + new_object($proto_c); + } + if ( + system( +"wayland-scanner client-header ./resource/wayland/${file} include/Mw/LowLevel/Wayland/${proto}-client-protocol.h" + ) + ) + { + print( + "^ Error on getting client header for ./resource/wayland/${file}\n" + ); + } +} + +our %params = (); + +sub param_set { + $params{ $_[0] } = $_[1]; +} + +sub param_get { + if (not(defined($params{ $_[0] }))) { + return 0; + } + else { + return $params{ $_[0] }; + } +} + +sub param_list { + return sort(keys(%params)); +} + +1; diff --git a/widget/milsko/milskosrc/resource/doxygen-theme/README b/widget/milsko/milskosrc/resource/doxygen-theme/README new file mode 100644 index 0000000000..fdf47695f1 --- /dev/null +++ b/widget/milsko/milskosrc/resource/doxygen-theme/README @@ -0,0 +1 @@ +https://github.com/jothepro/doxygen-awesome-css diff --git a/widget/milsko/milskosrc/resource/doxygen-theme/doxygen-awesome.css b/widget/milsko/milskosrc/resource/doxygen-theme/doxygen-awesome.css new file mode 100644 index 0000000000..f992c23295 --- /dev/null +++ b/widget/milsko/milskosrc/resource/doxygen-theme/doxygen-awesome.css @@ -0,0 +1,3020 @@ +/* SPDX-License-Identifier: MIT */ +/** + +Doxygen Awesome +https://github.com/jothepro/doxygen-awesome-css + +Copyright (c) 2021 - 2025 jothepro + +*/ + +html { + /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ + --primary-color: #1779c4; + --primary-dark-color: #335c80; + --primary-light-color: #70b1e9; + --on-primary-color: #ffffff; + + --link-color: var(--primary-color); + + /* page base colors */ + --page-background-color: #ffffff; + --page-foreground-color: #2f4153; + --page-secondary-foreground-color: #6f7e8e; + + /* color for all separators on the website: hr, borders, ... */ + --separator-color: #dedede; + + /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ + --border-radius-large: 10px; + --border-radius-small: 5px; + --border-radius-medium: 8px; + + /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */ + --spacing-small: 5px; + --spacing-medium: 10px; + --spacing-large: 16px; + --spacing-xlarge: 20px; + + /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); + + --odd-color: rgba(0,0,0,.028); + + /* font-families. will affect all text on the website + * font-family: the normal font for text, headlines, menus + * font-family-monospace: used for preformatted text in memtitle, code, fragments + */ + --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; + --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + + /* font sizes */ + --page-font-size: 15.6px; + --navigation-font-size: 14.4px; + --toc-font-size: 13.4px; + --code-font-size: 14px; /* affects code, fragment */ + --title-font-size: 22px; + + /* content text properties. These only affect the page content, not the navigation or any other ui elements */ + --content-line-height: 27px; + /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ + --content-maxwidth: 1050px; + --table-line-height: 24px; + --toc-sticky-top: var(--spacing-medium); + --toc-width: 200px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); + + /* colors for various content boxes: @warning, @note, @deprecated @bug */ + --warning-color: #faf3d8; + --warning-color-dark: #f3a600; + --warning-color-darker: #5f4204; + --note-color: #e4f3ff; + --note-color-dark: #1879C4; + --note-color-darker: #274a5c; + --todo-color: #e4dafd; + --todo-color-dark: #5b2bdd; + --todo-color-darker: #2a0d72; + --deprecated-color: #ecf0f3; + --deprecated-color-dark: #5b6269; + --deprecated-color-darker: #43454a; + --bug-color: #f8d1cc; + --bug-color-dark: #b61825; + --bug-color-darker: #75070f; + --invariant-color: #d8f1e3; + --invariant-color-dark: #44b86f; + --invariant-color-darker: #265532; + + /* blockquote colors */ + --blockquote-background: #f8f9fa; + --blockquote-foreground: #636568; + + /* table colors */ + --tablehead-background: #f1f1f1; + --tablehead-foreground: var(--page-foreground-color); + + /* menu-display: block | none + * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. + * `GENERATE_TREEVIEW` MUST be enabled! + */ + --menu-display: block; + + --menu-focus-foreground: var(--on-primary-color); + --menu-focus-background: var(--primary-color); + --menu-selected-background: rgba(0,0,0,.05); + + + --header-background: var(--page-background-color); + --header-foreground: var(--page-foreground-color); + + /* searchbar colors */ + --searchbar-background: var(--side-nav-background); + --searchbar-foreground: var(--page-foreground-color); + + /* searchbar size + * (`searchbar-width` is only applied on screens >= 768px. + * on smaller screens the searchbar will always fill the entire screen width) */ + --searchbar-height: 33px; + --searchbar-width: 210px; + --searchbar-border-radius: var(--searchbar-height); + + /* code block colors */ + --code-background: #f5f5f5; + --code-foreground: var(--page-foreground-color); + + /* fragment colors */ + --fragment-background: #F8F9FA; + --fragment-foreground: #37474F; + --fragment-keyword: #bb6bb2; + --fragment-keywordtype: #8258b3; + --fragment-keywordflow: #d67c3b; + --fragment-token: #438a59; + --fragment-comment: #969696; + --fragment-link: #5383d6; + --fragment-preprocessor: #46aaa5; + --fragment-linenumber-color: #797979; + --fragment-linenumber-background: #f4f4f5; + --fragment-linenumber-border: #e3e5e7; + --fragment-lineheight: 20px; + + /* sidebar navigation (treeview) colors */ + --side-nav-background: #fbfbfb; + --side-nav-foreground: var(--page-foreground-color); + --side-nav-arrow-opacity: 0; + --side-nav-arrow-hover-opacity: 0.9; + + --toc-background: var(--side-nav-background); + --toc-foreground: var(--side-nav-foreground); + + /* height of an item in any tree / collapsible table */ + --tree-item-height: 30px; + + --memname-font-size: var(--code-font-size); + --memtitle-font-size: 18px; + + --webkit-scrollbar-size: 7px; + --webkit-scrollbar-padding: 4px; + --webkit-scrollbar-color: var(--separator-color); + + --animation-duration: .12s +} + +@media screen and (max-width: 767px) { + html { + --page-font-size: 16px; + --navigation-font-size: 16px; + --toc-font-size: 15px; + --code-font-size: 15px; /* affects code, fragment */ + --title-font-size: 22px; + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #3b2e04; + --warning-color-dark: #f1b602; + --warning-color-darker: #ceb670; + --note-color: #163750; + --note-color-dark: #1982D2; + --note-color-darker: #dcf0fa; + --todo-color: #2a2536; + --todo-color-dark: #7661b3; + --todo-color-darker: #ae9ed6; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2e1917; + --bug-color-dark: #ad2617; + --bug-color-darker: #f5b1aa; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; + } +} + +/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ +html.dark-mode { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #3b2e04; + --warning-color-dark: #f1b602; + --warning-color-darker: #ceb670; + --note-color: #163750; + --note-color-dark: #1982D2; + --note-color-darker: #dcf0fa; + --todo-color: #2a2536; + --todo-color-dark: #7661b3; + --todo-color-darker: #ae9ed6; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2e1917; + --bug-color-dark: #ad2617; + --bug-color-darker: #f5b1aa; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; +} + +body { + color: var(--page-foreground-color); + background-color: var(--page-background-color); + font-size: var(--page-font-size); +} + +body, table, div, p, dl, #nav-tree .label, #nav-tree a, .title, +.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, +.SelectItem, #MSearchField, .navpath li.navelem a, +.navpath li.navelem a:hover, p.reference, p.definition, div.toc li, div.toc h3, +#page-nav ul.page-outline li a { + font-family: var(--font-family); +} + +h1, h2, h3, h4, h5 { + margin-top: 1em; + font-weight: 600; + line-height: initial; +} + +p, div, table, dl, p.reference, p.definition { + font-size: var(--page-font-size); +} + +p.reference, p.definition { + color: var(--page-secondary-foreground-color); +} + +a:link, a:visited, a:hover, a:focus, a:active { + color: var(--link-color) !important; + font-weight: 500; + background: none; +} + +a:hover { + text-decoration: underline; +} + +a.anchor { + scroll-margin-top: var(--spacing-large); + display: block; +} + +/* + Title and top navigation + */ + +#top { + background: var(--header-background); + border-bottom: 1px solid var(--separator-color); + position: relative; + z-index: 99; +} + +@media screen and (min-width: 768px) { + #top { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + } +} + +#main-nav { + flex-grow: 5; + padding: var(--spacing-small) var(--spacing-medium); + border-bottom: 0; +} + +#titlearea { + width: auto; + padding: var(--spacing-medium) var(--spacing-large); + background: none; + color: var(--header-foreground); + border-bottom: none; +} + +@media screen and (max-width: 767px) { + #titlearea { + padding-bottom: var(--spacing-small); + } +} + +#titlearea table tbody tr { + height: auto !important; +} + +#projectname { + font-size: var(--title-font-size); + font-weight: 600; +} + +#projectnumber { + font-family: inherit; + font-size: 60%; +} + +#projectbrief { + font-family: inherit; + font-size: 80%; +} + +#projectlogo { + vertical-align: middle; +} + +#projectlogo img { + max-height: calc(var(--title-font-size) * 2); + margin-right: var(--spacing-small); +} + +.sm-dox, .tabs, .tabs2, .tabs3 { + background: none; + padding: 0; +} + +.tabs, .tabs2, .tabs3 { + border-bottom: 1px solid var(--separator-color); + margin-bottom: -1px; +} + +.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { + background: var(--page-secondary-foreground-color); +} + +@media screen and (max-width: 767px) { + .sm-dox a span.sub-arrow { + background: var(--code-background); + } + + #main-menu a.has-submenu span.sub-arrow { + color: var(--page-secondary-foreground-color); + border-radius: var(--border-radius-medium); + } + + #main-menu a.has-submenu:hover span.sub-arrow { + color: var(--page-foreground-color); + } +} + +@media screen and (min-width: 768px) { + .sm-dox li, .tablist li { + display: var(--menu-display); + } + + .sm-dox a span.sub-arrow { + top: 15px; + right: 10px; + box-sizing: content-box; + padding: 0; + margin: 0; + display: inline-block; + width: 5px; + height: 5px; + transform: rotate(45deg); + border-width: 0; + border-right: 2px solid var(--header-foreground); + border-bottom: 2px solid var(--header-foreground); + background: none; + } + + .sm-dox a:hover span.sub-arrow { + border-color: var(--menu-focus-foreground); + background: none; + } + + .sm-dox ul a span.sub-arrow { + transform: rotate(-45deg); + border-width: 0; + border-right: 2px solid var(--header-foreground); + border-bottom: 2px solid var(--header-foreground); + } + + .sm-dox ul a:hover span.sub-arrow { + border-color: var(--menu-focus-foreground); + background: none; + } +} + +.sm-dox ul { + background: var(--page-background-color); + box-shadow: var(--box-shadow); + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium) !important; + padding: var(--spacing-small); + animation: ease-out 150ms slideInMenu; +} + +@keyframes slideInMenu { + from { + opacity: 0; + transform: translate(0px, -2px); + } + + to { + opacity: 1; + transform: translate(0px, 0px); + } +} + +.sm-dox ul a { + color: var(--page-foreground-color) !important; + background: none; + font-size: var(--navigation-font-size); +} + +.sm-dox>li>ul:after { + border-bottom-color: var(--page-background-color) !important; +} + +.sm-dox>li>ul:before { + border-bottom-color: var(--separator-color) !important; +} + +.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { + font-size: var(--navigation-font-size) !important; + color: var(--menu-focus-foreground) !important; + text-shadow: none; + background-color: var(--menu-focus-background); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { + text-shadow: none; + background: transparent; + background-image: none !important; + color: var(--header-foreground) !important; + font-weight: normal; + font-size: var(--navigation-font-size); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a:focus { + outline: auto; +} + +.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { + text-shadow: none; + font-weight: normal; + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; + border-radius: var(--border-radius-small) !important; + font-size: var(--navigation-font-size); +} + +.tablist li.current { + border-radius: var(--border-radius-small); + background: var(--menu-selected-background); +} + +.tablist li { + margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); +} + +.tablist a { + padding: 0 var(--spacing-large); +} + + +/* + Search box + */ + +#MSearchBox { + height: var(--searchbar-height); + background: var(--searchbar-background); + border-radius: var(--searchbar-border-radius); + border: 1px solid var(--separator-color); + overflow: hidden; + width: var(--searchbar-width); + position: relative; + box-shadow: none; + display: block; + margin-top: 0; + margin-right: 0; +} + +@media (min-width: 768px) { + .sm-dox li { + padding: 0; + } +} + +/* until Doxygen 1.9.4 */ +.left img#MSearchSelect { + left: 0; + user-select: none; + padding-left: 8px; +} + +/* Doxygen 1.9.5 */ +.left span#MSearchSelect { + left: 0; + user-select: none; + margin-left: 8px; + padding: 0; +} + +.left #MSearchSelect[src$=".png"] { + padding-left: 0 +} + +/* Doxygen 1.14.0 */ +.search-icon::before { + background: none; + top: 5px; +} + +.search-icon::after { + background: none; + top: 12px; +} + +.SelectionMark { + user-select: none; +} + +.tabs .left #MSearchSelect { + padding-left: 0; +} + +.tabs #MSearchBox { + position: absolute; + right: var(--spacing-medium); +} + +@media screen and (max-width: 767px) { + .tabs #MSearchBox { + position: relative; + right: 0; + margin-left: var(--spacing-medium); + margin-top: 0; + } +} + +#MSearchSelectWindow, #MSearchResultsWindow { + z-index: 9999; +} + +#MSearchBox.MSearchBoxActive { + border-color: var(--primary-color); + box-shadow: inset 0 0 0 1px var(--primary-color); +} + +#main-menu > li:last-child { + margin-right: 0; +} + +@media screen and (max-width: 767px) { + #main-menu > li:last-child { + height: 50px; + } +} + +#MSearchField { + font-size: var(--navigation-font-size); + height: calc(var(--searchbar-height) - 2px); + background: transparent; + width: calc(var(--searchbar-width) - 64px); +} + +.MSearchBoxActive #MSearchField { + color: var(--searchbar-foreground); +} + +#MSearchSelect { + top: calc(calc(var(--searchbar-height) / 2) - 11px); +} + +#MSearchBox span.left, #MSearchBox span.right { + background: none; + background-image: none; +} + +#MSearchBox span.right { + padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); + position: absolute; + right: var(--spacing-small); +} + +.tabs #MSearchBox span.right { + top: calc(calc(var(--searchbar-height) / 2) - 12px); +} + +@keyframes slideInSearchResults { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } +} + +#MSearchResultsWindow { + left: auto !important; + right: var(--spacing-medium); + border-radius: var(--border-radius-large); + border: 1px solid var(--separator-color); + transform: translate(0, 20px); + box-shadow: var(--box-shadow); + animation: ease-out 280ms slideInSearchResults; + background: var(--page-background-color); +} + +iframe#MSearchResults { + margin: 4px; +} + +iframe { + color-scheme: normal; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) iframe#MSearchResults { + filter: invert() hue-rotate(180deg); + } +} + +html.dark-mode iframe#MSearchResults { + filter: invert() hue-rotate(180deg); +} + +#MSearchResults .SRPage { + background-color: transparent; +} + +#MSearchResults .SRPage .SREntry { + font-size: 10pt; + padding: var(--spacing-small) var(--spacing-medium); +} + +#MSearchSelectWindow { + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + box-shadow: var(--box-shadow); + background: var(--page-background-color); + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); +} + +#MSearchSelectWindow a.SelectItem { + font-size: var(--navigation-font-size); + line-height: var(--content-line-height); + margin: 0 var(--spacing-small); + border-radius: var(--border-radius-small); + color: var(--page-foreground-color) !important; + font-weight: normal; +} + +#MSearchSelectWindow a.SelectItem:hover { + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; +} + +@media screen and (max-width: 767px) { + #MSearchBox { + margin-top: var(--spacing-medium); + margin-bottom: var(--spacing-medium); + width: calc(100vw - 30px); + } + + #main-menu > li:last-child { + float: none !important; + } + + #MSearchField { + width: calc(100vw - 110px); + } + + @keyframes slideInSearchResultsMobile { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } + } + + #MSearchResultsWindow { + left: var(--spacing-medium) !important; + right: var(--spacing-medium); + overflow: auto; + transform: translate(0, 20px); + animation: ease-out 280ms slideInSearchResultsMobile; + width: auto !important; + } + + /* + * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 + */ + label.main-menu-btn ~ #searchBoxPos1 { + top: 3px !important; + right: 6px !important; + left: 45px; + display: flex; + } + + label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { + margin-top: 0; + margin-bottom: 0; + flex-grow: 2; + float: left; + } +} + +/* + Tree view + */ + +#side-nav { + min-width: 8px; + max-width: 50vw; +} + + +#nav-tree, #top { + border-right: 1px solid var(--separator-color); +} + +@media screen and (max-width: 767px) { + #side-nav { + display: none; + } + + #doc-content { + margin-left: 0 !important; + } + + #top { + border-right: none; + } +} + +#nav-tree { + background: var(--side-nav-background); + margin-right: -1px; + padding: 0; +} + +#nav-tree .label { + font-size: var(--navigation-font-size); + line-height: var(--tree-item-height); +} + +#nav-tree span.label a:hover { + background: none; +} + +#nav-tree .item { + height: var(--tree-item-height); + line-height: var(--tree-item-height); + overflow: hidden; + text-overflow: ellipsis; + margin: 0; + padding: 0; +} + +#nav-tree-contents { + margin: 0; +} + +#main-menu > li:last-child { + height: auto; +} + +#nav-tree .item > a:focus { + outline: none; +} + +#nav-sync { + bottom: var(--spacing-medium); + right: var(--spacing-medium) !important; + top: auto !important; + user-select: none; +} + +div.nav-sync-icon { + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + background: var(--page-background-color); + width: 30px; + height: 20px; +} + +div.nav-sync-icon:hover { + background: var(--page-background-color); +} + +span.sync-icon-left, div.nav-sync-icon:hover span.sync-icon-left { + border-left: 2px solid var(--primary-color); + border-top: 2px solid var(--primary-color); + top: 5px; + left: 6px; +} +span.sync-icon-right, div.nav-sync-icon:hover span.sync-icon-right { + border-right: 2px solid var(--primary-color); + border-bottom: 2px solid var(--primary-color); + top: 5px; + left: initial; + right: 6px; +} + +div.nav-sync-icon.active::after, div.nav-sync-icon.active:hover::after { + border-top: 2px solid var(--primary-color); + top: 9px; + left: 6px; + width: 19px; +} + +#nav-tree .selected { + text-shadow: none; + background-image: none; + background-color: transparent; + position: relative; + color: var(--primary-color) !important; + font-weight: 500; +} + +#nav-tree .selected::after { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + width: 4px; + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + background: var(--primary-color); +} + + +#nav-tree a { + color: var(--side-nav-foreground) !important; + font-weight: normal; +} + +#nav-tree a:focus { + outline-style: auto; +} + +#nav-tree .arrow { + opacity: var(--side-nav-arrow-opacity); + background: none; +} + +#nav-tree span.arrowhead { + margin: 0 0 1px 2px; +} + +span.arrowhead { + border-color: var(--primary-light-color); +} + +.selected span.arrowhead { + border-color: var(--primary-color); +} + +#nav-tree-contents > ul > li:first-child > div > a { + opacity: 0; + pointer-events: none; +} + +.contents .arrow { + color: inherit; + cursor: pointer; + font-size: 45%; + vertical-align: middle; + margin-right: 2px; + font-family: serif; + height: auto; + padding-bottom: 4px; +} + +#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { + opacity: var(--side-nav-arrow-hover-opacity); +} + +#nav-tree .selected a { + color: var(--primary-color) !important; + font-weight: bolder; + font-weight: 600; +} + +.ui-resizable-e { + background: none; +} + +.ui-resizable-e:hover { + background: var(--separator-color); +} + +/* + Contents + */ + +div.header { + border-bottom: 1px solid var(--separator-color); + background: none; + background-image: none; +} + +@media screen and (min-width: 1000px) { + #doc-content > div > div.contents, + .PageDoc > div.contents { + display: flex; + flex-direction: row-reverse; + flex-wrap: nowrap; + align-items: flex-start; + } + + div.contents .textblock { + min-width: 200px; + flex-grow: 1; + } +} + +div.contents, div.header .title, div.header .summary { + max-width: var(--content-maxwidth); +} + +div.contents, div.header .title { + line-height: initial; + margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; +} + +div.header .summary { + margin: var(--spacing-medium) auto 0 auto; +} + +div.headertitle { + padding: 0; +} + +div.header .title { + font-weight: 600; + font-size: 225%; + padding: var(--spacing-medium) var(--spacing-xlarge); + word-break: break-word; +} + +div.header .summary { + width: auto; + display: block; + float: none; + padding: 0 var(--spacing-large); +} + +td.memSeparator { + border-color: var(--separator-color); +} + +span.mlabel { + background: var(--primary-color); + color: var(--on-primary-color); + border: none; + padding: 4px 9px; + border-radius: var(--border-radius-large); + margin-right: var(--spacing-medium); +} + +span.mlabel:last-of-type { + margin-right: 2px; +} + +div.contents { + padding: 0 var(--spacing-xlarge); +} + +div.contents p, div.contents li { + line-height: var(--content-line-height); +} + +div.contents div.dyncontent { + margin: var(--spacing-medium) 0; +} + +@media screen and (max-width: 767px) { + div.contents { + padding: 0 var(--spacing-large); + } + + div.header .title { + padding: var(--spacing-medium) var(--spacing-large); + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) div.contents div.dyncontent img, + html:not(.light-mode) div.contents center img, + html:not(.light-mode) div.contents > table img, + html:not(.light-mode) div.contents div.dyncontent iframe, + html:not(.light-mode) div.contents center iframe, + html:not(.light-mode) div.contents table iframe, + html:not(.light-mode) div.contents .dotgraph iframe { + filter: brightness(89%) hue-rotate(180deg) invert(); + } +} + +html.dark-mode div.contents div.dyncontent img, +html.dark-mode div.contents center img, +html.dark-mode div.contents > table img, +html.dark-mode div.contents div.dyncontent iframe, +html.dark-mode div.contents center iframe, +html.dark-mode div.contents table iframe, +html.dark-mode div.contents .dotgraph iframe + { + filter: brightness(89%) hue-rotate(180deg) invert(); +} + +td h2.groupheader, h2.groupheader { + border-bottom: 0px; + color: var(--page-foreground-color); + box-shadow: + 100px 0 var(--page-background-color), + -100px 0 var(--page-background-color), + 100px 0.75px var(--separator-color), + -100px 0.75px var(--separator-color), + 500px 0 var(--page-background-color), + -500px 0 var(--page-background-color), + 500px 0.75px var(--separator-color), + -500px 0.75px var(--separator-color), + 900px 0 var(--page-background-color), + -900px 0 var(--page-background-color), + 900px 0.75px var(--separator-color), + -900px 0.75px var(--separator-color), + 1400px 0 var(--page-background-color), + -1400px 0 var(--page-background-color), + 1400px 0.75px var(--separator-color), + -1400px 0.75px var(--separator-color), + 1900px 0 var(--page-background-color), + -1900px 0 var(--page-background-color), + 1900px 0.75px var(--separator-color), + -1900px 0.75px var(--separator-color); +} + +blockquote { + margin: 0 var(--spacing-medium) 0 var(--spacing-medium); + padding: var(--spacing-small) var(--spacing-large); + background: var(--blockquote-background); + color: var(--blockquote-foreground); + border-left: 0; + overflow: visible; + border-radius: var(--border-radius-medium); + overflow: visible; + position: relative; +} + +blockquote::before, blockquote::after { + font-weight: bold; + font-family: serif; + font-size: 360%; + opacity: .15; + position: absolute; +} + +blockquote::before { + content: "“"; + left: -10px; + top: 4px; +} + +blockquote::after { + content: "”"; + right: -8px; + bottom: -25px; +} + +blockquote p { + margin: var(--spacing-small) 0 var(--spacing-medium) 0; +} +.paramname, .paramname em { + font-weight: 600; + color: var(--primary-dark-color); +} + +.paramname > code { + border: 0; +} + +table.params .paramname { + font-weight: 600; + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + padding-right: var(--spacing-small); + line-height: var(--table-line-height); +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px var(--primary-light-color); +} + +.alphachar a { + color: var(--page-foreground-color); +} + +.dotgraph { + max-width: 100%; + overflow-x: scroll; +} + +.dotgraph .caption { + position: sticky; + left: 0; +} + +/* Wrap Graphviz graphs with the `interactive_dotgraph` class if `INTERACTIVE_SVG = YES` */ +.interactive_dotgraph .dotgraph iframe { + max-width: 100%; +} + +/* + Table of Contents + */ + +div.contents .toc { + max-height: var(--toc-max-height); + min-width: var(--toc-width); + border: 0; + border-left: 1px solid var(--separator-color); + border-radius: 0; + background-color: var(--page-background-color); + box-shadow: none; + position: sticky; + top: var(--toc-sticky-top); + padding: 0 var(--spacing-large); + margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); +} + +div.toc h3 { + color: var(--toc-foreground); + font-size: var(--navigation-font-size); + margin: var(--spacing-large) 0 var(--spacing-medium) 0; +} + +div.toc li { + padding: 0; + background: none; + line-height: var(--toc-font-size); + margin: var(--toc-font-size) 0 0 0; +} + +div.toc li::before { + display: none; +} + +div.toc ul { + margin-top: 0 +} + +div.toc li a { + font-size: var(--toc-font-size); + color: var(--page-foreground-color) !important; + text-decoration: none; +} + +div.toc li a:hover, div.toc li a.active { + color: var(--primary-color) !important; +} + +div.toc li a.aboveActive { + color: var(--page-secondary-foreground-color) !important; +} + + +@media screen and (max-width: 999px) { + div.contents .toc { + max-height: 45vh; + float: none; + width: auto; + margin: 0 0 var(--spacing-medium) 0; + position: relative; + top: 0; + position: relative; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + background-color: var(--toc-background); + box-shadow: var(--box-shadow); + } + + div.contents .toc.interactive { + max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); + overflow: hidden; + } + + div.contents .toc > h3 { + -webkit-tap-highlight-color: transparent; + cursor: pointer; + position: sticky; + top: 0; + background-color: var(--toc-background); + margin: 0; + padding: var(--spacing-large) 0; + display: block; + } + + div.contents .toc.interactive > h3::before { + content: ""; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + display: inline-block; + margin-right: var(--spacing-small); + margin-bottom: calc(var(--navigation-font-size) / 4); + transform: rotate(-90deg); + transition: transform var(--animation-duration) ease-out; + } + + div.contents .toc.interactive.open > h3::before { + transform: rotate(0deg); + } + + div.contents .toc.interactive.open { + max-height: 45vh; + overflow: auto; + transition: max-height 0.2s ease-in-out; + } + + div.contents .toc a, div.contents .toc a.active { + color: var(--primary-color) !important; + } + + div.contents .toc a:hover { + text-decoration: underline; + } +} + +/* + Page Outline (Doxygen >= 1.14.0) +*/ + +#page-nav { + background: var(--page-background-color); + border-left: 1px solid var(--separator-color); +} + +#page-nav #page-nav-resize-handle { + background: var(--separator-color); +} + +#page-nav #page-nav-resize-handle::after { + border-left: 1px solid var(--primary-color); + border-right: 1px solid var(--primary-color); +} + +#page-nav #page-nav-tree #page-nav-contents { + top: var(--spacing-large); +} + +#page-nav ul.page-outline { + margin: 0; + padding: 0; +} + +#page-nav ul.page-outline li a { + font-size: var(--toc-font-size) !important; + color: var(--page-secondary-foreground-color) !important; + display: inline-block; + line-height: calc(2 * var(--toc-font-size)); +} + +#page-nav ul.page-outline li a a.anchorlink { + display: none; +} + +#page-nav ul.page-outline li.vis ~ * a { + color: var(--page-foreground-color) !important; +} + +#page-nav ul.page-outline li.vis:not(.vis ~ .vis) a, #page-nav ul.page-outline li a:hover { + color: var(--primary-color) !important; +} + +#page-nav ul.page-outline .vis { + background: var(--page-background-color); + position: relative; +} + +#page-nav ul.page-outline .vis::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 4px; + background: var(--page-secondary-foreground-color); +} + +#page-nav ul.page-outline .vis:not(.vis ~ .vis)::after { + top: 1px; + border-top-right-radius: var(--border-radius-small); +} + +#page-nav ul.page-outline .vis:not(:has(~ .vis))::after { + bottom: 1px; + border-bottom-right-radius: var(--border-radius-small); +} + + +#page-nav ul.page-outline .arrow { + display: inline-block; +} + +#page-nav ul.page-outline .arrow span { + display: none; +} + +@media screen and (max-width: 767px) { + #container { + grid-template-columns: initial !important; + } + + #page-nav { + display: none; + } +} + +/* + Code & Fragments + */ + +code, div.fragment, pre.fragment, span.tt { + border: 1px solid var(--separator-color); + overflow: hidden; +} + +code, span.tt { + display: inline; + background: var(--code-background); + color: var(--code-foreground); + padding: 2px 6px; + border-radius: var(--border-radius-small); +} + +div.fragment, pre.fragment { + border-radius: var(--border-radius-medium); + margin: var(--spacing-medium) 0; + padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); + background: var(--fragment-background); + color: var(--fragment-foreground); + overflow-x: auto; +} + +@media screen and (max-width: 767px) { + div.fragment, pre.fragment { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: 0; + } + + .contents > div.fragment, + .textblock > div.fragment, + .textblock > pre.fragment, + .textblock > .tabbed > ul > li > div.fragment, + .textblock > .tabbed > ul > li > pre.fragment, + .contents > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment, + .textblock > .tabbed > ul > li > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .tabbed > ul > li > .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + border-radius: 0; + border-left: 0; + } + + .textblock li > .fragment, + .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + } + + .memdoc li > .fragment, + .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + } + + .textblock ul, .memdoc ul { + overflow: initial; + } + + .memdoc > div.fragment, + .memdoc > pre.fragment, + dl dd > div.fragment, + dl dd pre.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, + dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, + dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + border-radius: 0; + border-left: 0; + } +} + +code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span, span.tt { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size) !important; +} + +div.line:after { + margin-right: var(--spacing-medium); +} + +div.fragment .line, pre.fragment { + white-space: pre; + word-wrap: initial; + line-height: var(--fragment-lineheight); +} + +div.fragment span.keyword { + color: var(--fragment-keyword); +} + +div.fragment span.keywordtype { + color: var(--fragment-keywordtype); +} + +div.fragment span.keywordflow { + color: var(--fragment-keywordflow); +} + +div.fragment span.stringliteral { + color: var(--fragment-token) +} + +div.fragment span.comment { + color: var(--fragment-comment); +} + +div.fragment a.code { + color: var(--fragment-link) !important; +} + +div.fragment span.preprocessor { + color: var(--fragment-preprocessor); +} + +div.fragment span.lineno { + display: inline-block; + width: 27px; + border-right: none; + background: var(--fragment-linenumber-background); + color: var(--fragment-linenumber-color); +} + +div.fragment span.lineno a { + background: none; + color: var(--fragment-link) !important; +} + +div.fragment > .line:first-child .lineno { + box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); + background-color: var(--fragment-linenumber-background) !important; +} + +div.line { + border-radius: var(--border-radius-small); +} + +div.line.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +/* + dl warning, attention, note, deprecated, bug, ... + */ + +dl { + line-height: calc(1.65 * var(--page-font-size)); +} + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark { + padding: var(--spacing-medium); + margin: var(--spacing-medium) 0; + color: var(--page-background-color); + overflow: hidden; + margin-left: 0; + border-radius: var(--border-radius-small); +} + +dl.section dd { + margin-bottom: 2px; +} + +dl.warning, dl.attention { + background: var(--warning-color); + border-left: 8px solid var(--warning-color-dark); + color: var(--warning-color-darker); +} + +dl.warning dt, dl.attention dt { + color: var(--warning-color-dark); +} + +dl.note, dl.remark { + background: var(--note-color); + border-left: 8px solid var(--note-color-dark); + color: var(--note-color-darker); +} + +dl.note dt, dl.remark dt { + color: var(--note-color-dark); +} + +dl.todo { + background: var(--todo-color); + border-left: 8px solid var(--todo-color-dark); + color: var(--todo-color-darker); +} + +dl.todo dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug { + background: var(--bug-color); + border-left: 8px solid var(--bug-color-dark); + color: var(--bug-color-darker); +} + +dl.bug dt a { + color: var(--bug-color-dark) !important; +} + +dl.deprecated { + background: var(--deprecated-color); + border-left: 8px solid var(--deprecated-color-dark); + color: var(--deprecated-color-darker); +} + +dl.deprecated dt a { + color: var(--deprecated-color-dark) !important; +} + +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre, dl.post { + background: var(--invariant-color); + border-left: 8px solid var(--invariant-color-dark); + color: var(--invariant-color-darker); +} + +dl.invariant dt, dl.pre dt, dl.post dt { + color: var(--invariant-color-dark); +} + +/* + memitem + */ + +div.memdoc, div.memproto, h2.memtitle { + box-shadow: none; + background-image: none; + border: none; +} + +div.memdoc { + padding: 0 var(--spacing-medium); + background: var(--page-background-color); +} + +h2.memtitle, div.memitem { + border: 1px solid var(--separator-color); + box-shadow: var(--box-shadow); +} + +h2.memtitle { + box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); +} + +div.memitem { + transition: none; +} + +div.memproto, h2.memtitle { + background: var(--fragment-background); +} + +h2.memtitle { + font-weight: 500; + font-size: var(--memtitle-font-size); + font-family: var(--font-family-monospace); + border-bottom: none; + border-top-left-radius: var(--border-radius-medium); + border-top-right-radius: var(--border-radius-medium); + word-break: break-all; + position: relative; +} + +h2.memtitle:after { + content: ""; + display: block; + background: var(--fragment-background); + height: var(--spacing-medium); + bottom: calc(0px - var(--spacing-medium)); + left: 0; + right: -14px; + position: absolute; + border-top-right-radius: var(--border-radius-medium); +} + +h2.memtitle > span.permalink { + font-size: inherit; +} + +h2.memtitle > span.permalink > a { + text-decoration: none; + padding-left: 3px; + margin-right: -4px; + user-select: none; + display: inline-block; + margin-top: -6px; +} + +h2.memtitle > span.permalink > a:hover { + color: var(--primary-dark-color) !important; +} + +a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { + border-color: var(--primary-light-color); +} + +div.memitem { + border-top-right-radius: var(--border-radius-medium); + border-bottom-right-radius: var(--border-radius-medium); + border-bottom-left-radius: var(--border-radius-medium); + border-top-left-radius: 0; + overflow: hidden; + display: block !important; +} + +div.memdoc { + border-radius: 0; +} + +div.memproto { + border-radius: 0 var(--border-radius-small) 0 0; + overflow: auto; + border-bottom: 1px solid var(--separator-color); + padding: var(--spacing-medium); + margin-bottom: -1px; +} + +div.memtitle { + border-top-right-radius: var(--border-radius-medium); + border-top-left-radius: var(--border-radius-medium); +} + +div.memproto table.memname { + font-family: var(--font-family-monospace); + color: var(--page-foreground-color); + font-size: var(--memname-font-size); + text-shadow: none; +} + +div.memproto div.memtemplate { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--memname-font-size); + margin-left: 2px; + text-shadow: none; +} + +table.mlabels, table.mlabels > tbody { + display: block; +} + +td.mlabels-left { + width: auto; +} + +td.mlabels-right { + margin-top: 3px; + position: sticky; + left: 0; +} + +table.mlabels > tbody > tr:first-child { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.memname, .memitem span.mlabels { + margin: 0 +} + +/* + reflist + */ + +dl.reflist { + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-medium); + border: 1px solid var(--separator-color); + overflow: hidden; + padding: 0; +} + + +dl.reflist dt, dl.reflist dd { + box-shadow: none; + text-shadow: none; + background-image: none; + border: none; + padding: 12px; +} + + +dl.reflist dt { + font-weight: 500; + border-radius: 0; + background: var(--code-background); + border-bottom: 1px solid var(--separator-color); + color: var(--page-foreground-color) +} + + +dl.reflist dd { + background: none; +} + +/* + Table + */ + +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: inline-block; + max-width: 100%; +} + +.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); +} + +table.fieldtable, +table.markdownTable tbody, +table.doxtable tbody { + border: none; + margin: var(--spacing-medium) 0; + box-shadow: 0 0 0 1px var(--separator-color); + border-radius: var(--border-radius-small); +} + +table.markdownTable, table.doxtable, table.fieldtable { + padding: 1px; +} + +table.doxtable caption { + display: block; +} + +table.fieldtable { + border-collapse: collapse; + width: 100%; +} + +th.markdownTableHeadLeft, +th.markdownTableHeadRight, +th.markdownTableHeadCenter, +th.markdownTableHeadNone, +table.doxtable th { + background: var(--tablehead-background); + color: var(--tablehead-foreground); + font-weight: 600; + font-size: var(--page-font-size); +} + +th.markdownTableHeadLeft:first-child, +th.markdownTableHeadRight:first-child, +th.markdownTableHeadCenter:first-child, +th.markdownTableHeadNone:first-child, +table.doxtable tr th:first-child { + border-top-left-radius: var(--border-radius-small); +} + +th.markdownTableHeadLeft:last-child, +th.markdownTableHeadRight:last-child, +th.markdownTableHeadCenter:last-child, +th.markdownTableHeadNone:last-child, +table.doxtable tr th:last-child { + border-top-right-radius: var(--border-radius-small); +} + +table.markdownTable td, +table.markdownTable th, +table.fieldtable td, +table.fieldtable th, +table.doxtable td, +table.doxtable th { + border: 1px solid var(--separator-color); + padding: var(--spacing-small) var(--spacing-medium); +} + +table.markdownTable td:last-child, +table.markdownTable th:last-child, +table.fieldtable td:last-child, +table.fieldtable th:last-child, +table.doxtable td:last-child, +table.doxtable th:last-child { + border-right: none; +} + +table.markdownTable td:first-child, +table.markdownTable th:first-child, +table.fieldtable td:first-child, +table.fieldtable th:first-child, +table.doxtable td:first-child, +table.doxtable th:first-child { + border-left: none; +} + +table.markdownTable tr:first-child td, +table.markdownTable tr:first-child th, +table.fieldtable tr:first-child td, +table.fieldtable tr:first-child th, +table.doxtable tr:first-child td, +table.doxtable tr:first-child th { + border-top: none; +} + +table.markdownTable tr:last-child td, +table.markdownTable tr:last-child th, +table.fieldtable tr:last-child td, +table.fieldtable tr:last-child th, +table.doxtable tr:last-child td, +table.doxtable tr:last-child th { + border-bottom: none; +} + +table.markdownTable tr, table.doxtable tr { + border-bottom: 1px solid var(--separator-color); +} + +table.markdownTable tr:last-child, table.doxtable tr:last-child { + border-bottom: none; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) { + display: block; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: table; + width: 100%; +} + +table.fieldtable th { + font-size: var(--page-font-size); + font-weight: 600; + background-image: none; + background-color: var(--tablehead-background); + color: var(--tablehead-foreground); +} + +table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fieldinit, .fieldtable td.fielddoc, .fieldtable th { + border-bottom: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); +} + +table.fieldtable tr:last-child td:first-child { + border-bottom-left-radius: var(--border-radius-small); +} + +table.fieldtable tr:last-child td:last-child { + border-bottom-right-radius: var(--border-radius-small); +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +table.memberdecls { + display: block; + -webkit-tap-highlight-color: transparent; +} + +table.memberdecls tr[class^='memitem'] { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); +} + +table.memberdecls tr[class^='memitem'] .memTemplParams { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + color: var(--primary-dark-color); + white-space: normal; +} + +table.memberdecls tr.heading + tr[class^='memitem'] td.memItemLeft, +table.memberdecls tr.heading + tr[class^='memitem'] td.memItemRight, +table.memberdecls td.memItemLeft, +table.memberdecls td.memItemRight, +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .memTemplParams { + transition: none; + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + background-color: var(--fragment-background); +} + +@media screen and (min-width: 768px) { + + tr.heading + tr[class^='memitem'] td.memItemRight, tr.groupHeader + tr[class^='memitem'] td.memItemRight, tr.inherit_header + tr[class^='memitem'] td.memItemRight { + border-top-right-radius: var(--border-radius-small); + } + + table.memberdecls tr:last-child td.memItemRight, table.memberdecls tr:last-child td.mdescRight, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemRight, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemRight, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescRight, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescRight { + border-bottom-right-radius: var(--border-radius-small); + } + + table.memberdecls tr:last-child td.memItemLeft, table.memberdecls tr:last-child td.mdescLeft, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemLeft, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescLeft { + border-bottom-left-radius: var(--border-radius-small); + } + + tr.heading + tr[class^='memitem'] td.memItemLeft, tr.groupHeader + tr[class^='memitem'] td.memItemLeft, tr.inherit_header + tr[class^='memitem'] td.memItemLeft { + border-top-left-radius: var(--border-radius-small); + } + +} + +table.memname td.memname { + font-size: var(--memname-font-size); +} + +table.memberdecls .memTemplItemLeft, +table.memberdecls .template .memItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .template .memItemRight { + padding-top: 2px; +} + +table.memberdecls .memTemplParams { + border-bottom: 0; + border-left: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + padding-bottom: var(--spacing-small); +} + +table.memberdecls .memTemplItemLeft, table.memberdecls .template .memItemLeft { + border-radius: 0 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memTemplItemRight, table.memberdecls .template .memItemRight { + border-radius: 0 0 var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-left: 0; + border-top: 0; +} + +table.memberdecls .memItemLeft { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + padding-left: var(--spacing-medium); + padding-right: 0; +} + +table.memberdecls .memItemRight { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-right: var(--spacing-medium); + padding-left: 0; + +} + +table.memberdecls .mdescLeft, table.memberdecls .mdescRight { + background: none; + color: var(--page-foreground-color); + padding: var(--spacing-small) 0; + border: 0; +} + +table.memberdecls [class^="memdesc"] { + box-shadow: none; +} + + +table.memberdecls .memItemLeft, +table.memberdecls .memTemplItemLeft { + padding-right: var(--spacing-medium); +} + +table.memberdecls .memSeparator { + background: var(--page-background-color); + height: var(--spacing-large); + border: 0; + transition: none; +} + +table.memberdecls .groupheader { + margin-bottom: var(--spacing-large); +} + +table.memberdecls .inherit_header td { + padding: 0 0 var(--spacing-medium) 0; + text-indent: -12px; + color: var(--page-secondary-foreground-color); +} + +table.memberdecls span.dynarrow { + left: 10px; +} + +table.memberdecls img[src="closed.png"], +table.memberdecls img[src="open.png"], +div.dynheader img[src="open.png"], +div.dynheader img[src="closed.png"] { + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + margin-top: 8px; + display: block; + float: left; + margin-left: -10px; + transition: transform var(--animation-duration) ease-out; +} + +tr.heading + tr[class^='memitem'] td.memItemLeft, tr.groupHeader + tr[class^='memitem'] td.memItemLeft, tr.inherit_header + tr[class^='memitem'] td.memItemLeft, tr.heading + tr[class^='memitem'] td.memItemRight, tr.groupHeader + tr[class^='memitem'] td.memItemRight, tr.inherit_header + tr[class^='memitem'] td.memItemRight { + border-top: 1px solid var(--separator-color); +} + +table.memberdecls img { + margin-right: 10px; +} + +table.memberdecls img[src="closed.png"], +div.dynheader img[src="closed.png"] { + transform: rotate(-90deg); + +} + +.compoundTemplParams { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--code-font-size); +} + +@media screen and (max-width: 767px) { + + table.memberdecls .memItemLeft, + table.memberdecls .memItemRight, + table.memberdecls .mdescLeft, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemLeft, + table.memberdecls .memTemplItemRight, + table.memberdecls .memTemplParams, + table.memberdecls .template .memItemLeft, + table.memberdecls .template .memItemRight, + table.memberdecls .template .memParams { + display: block; + text-align: left; + padding-left: var(--spacing-large); + margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); + border-right: none; + border-left: none; + border-radius: 0; + white-space: normal; + } + + table.memberdecls .memItemLeft, + table.memberdecls .mdescLeft, + table.memberdecls .memTemplItemLeft, + table.memberdecls .template .memItemLeft { + border-bottom: 0 !important; + padding-bottom: 0 !important; + } + + table.memberdecls .memTemplItemLeft, + table.memberdecls .template .memItemLeft { + padding-top: 0; + } + + table.memberdecls .mdescLeft { + margin-bottom: calc(0px - var(--page-font-size)); + } + + table.memberdecls .memItemRight, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemRight, + table.memberdecls .template .memItemRight { + border-top: 0 !important; + padding-top: 0 !important; + padding-right: var(--spacing-large); + padding-bottom: var(--spacing-medium); + overflow-x: auto; + } + + table.memberdecls tr[class^='memitem']:not(.inherit) { + display: block; + width: calc(100vw - 2 * var(--spacing-large)); + } + + table.memberdecls .mdescRight { + color: var(--page-foreground-color); + } + + table.memberdecls tr.inherit { + visibility: hidden; + } + + table.memberdecls tr[style="display: table-row;"] { + display: block !important; + visibility: visible; + width: calc(100vw - 2 * var(--spacing-large)); + animation: fade .5s; + } + + @keyframes fade { + 0% { + opacity: 0; + max-height: 0; + } + + 100% { + opacity: 1; + max-height: 200px; + } + } + + tr.heading + tr[class^='memitem'] td.memItemRight, tr.groupHeader + tr[class^='memitem'] td.memItemRight, tr.inherit_header + tr[class^='memitem'] td.memItemRight { + border-top-right-radius: 0; + } + + table.memberdecls tr:last-child td.memItemRight, table.memberdecls tr:last-child td.mdescRight, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemRight, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemRight, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescRight, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescRight { + border-bottom-right-radius: 0; + } + + table.memberdecls tr:last-child td.memItemLeft, table.memberdecls tr:last-child td.mdescLeft, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemLeft, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescLeft { + border-bottom-left-radius: 0; + } + + tr.heading + tr[class^='memitem'] td.memItemLeft, tr.groupHeader + tr[class^='memitem'] td.memItemLeft, tr.inherit_header + tr[class^='memitem'] td.memItemLeft { + border-top-left-radius: 0; + } +} + + +/* + Horizontal Rule + */ + +hr { + margin-top: var(--spacing-large); + margin-bottom: var(--spacing-large); + height: 1px; + background-color: var(--separator-color); + border: 0; +} + +.contents hr { + box-shadow: 100px 0 var(--separator-color), + -100px 0 var(--separator-color), + 500px 0 var(--separator-color), + -500px 0 var(--separator-color), + 900px 0 var(--separator-color), + -900px 0 var(--separator-color), + 1400px 0 var(--separator-color), + -1400px 0 var(--separator-color), + 1900px 0 var(--separator-color), + -1900px 0 var(--separator-color); +} + +.contents img, .contents .center, .contents center, .contents div.image object { + max-width: 100%; + overflow: auto; +} + +@media screen and (max-width: 767px) { + .contents .dyncontent > .center, .contents > center { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); + } +} + +/* + Directories + */ +div.directory { + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + width: auto; +} + +table.directory { + font-family: var(--font-family); + font-size: var(--page-font-size); + font-weight: normal; + width: 100%; +} + +table.directory td.entry, table.directory td.desc { + padding: calc(var(--spacing-small) / 2) var(--spacing-small); + line-height: var(--table-line-height); +} + +table.directory tr.even td:last-child { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; +} + +table.directory tr.even td:first-child { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); +} + +table.directory tr.even:last-child td:last-child { + border-radius: 0 var(--border-radius-small) 0 0; +} + +table.directory tr.even:last-child td:first-child { + border-radius: var(--border-radius-small) 0 0 0; +} + +table.directory td.desc { + min-width: 250px; +} + +table.directory tr.even { + background-color: var(--odd-color); +} + +table.directory tr.odd { + background-color: transparent; +} + +.icona { + width: auto; + height: auto; + margin: 0 var(--spacing-small); +} + +.icon { + background: var(--primary-color); + border-radius: var(--border-radius-small); + font-size: var(--page-font-size); + padding: calc(var(--page-font-size) / 5); + line-height: var(--page-font-size); + transform: scale(0.8); + height: auto; + width: var(--page-font-size); + user-select: none; +} + +.iconfopen, .icondoc, .iconfclosed { + background-position: center; + margin-bottom: 0; + height: var(--table-line-height); +} + +.icondoc { + filter: saturate(0.2); +} + +@media screen and (max-width: 767px) { + div.directory { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode .iconfopen, html.dark-mode .iconfclosed { + filter: hue-rotate(180deg) invert(); +} + +/* + Class list + */ + +.classindex dl.odd { + background: var(--odd-color); + border-radius: var(--border-radius-small); +} + +.classindex dl.even { + background-color: transparent; +} + +/* + Class Index Doxygen 1.8 +*/ + +table.classindex { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +table.classindex table div.ah { + background-image: none; + background-color: initial; + border-color: var(--separator-color); + color: var(--page-foreground-color); + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-large); + padding: var(--spacing-small); +} + +div.qindex { + background-color: var(--odd-color); + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + padding: var(--spacing-small) 0; +} + +/* + Footer and nav-path + */ + +#nav-path { + width: 100%; +} + +#nav-path ul { + background-image: none; + background: var(--page-background-color); + border: none; + border-top: 1px solid var(--separator-color); + border-bottom: 0; + font-size: var(--navigation-font-size); +} + +img.footer { + width: 60px; +} + +.navpath li.footer { + color: var(--page-secondary-foreground-color); +} + +address.footer { + color: var(--page-secondary-foreground-color); + margin-bottom: var(--spacing-large); +} + +#nav-path li.navelem { + background-image: none; + display: flex; + align-items: center; +} + +.navpath li.navelem a { + text-shadow: none; + display: inline-block; + color: var(--primary-color) !important; +} + +.navpath li.navelem a:hover { + text-shadow: none; +} + +.navpath li.navelem b { + color: var(--primary-dark-color); + font-weight: 500; +} + +li.navelem { + padding: 0; + margin-left: -8px; +} + +li.navelem:first-child { + margin-left: var(--spacing-large); +} + +li.navelem:first-child:before { + display: none; +} + +#nav-path ul { + padding-left: 0; +} + +#nav-path li.navelem:has(.el):after { + content: ''; + border: 5px solid var(--page-background-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(4.2); + z-index: 10; + margin-left: 6px; +} + +#nav-path li.navelem:not(:has(.el)):after { + background: var(--page-background-color); + box-shadow: 1px -1px 0 1px var(--separator-color); + border-radius: 0 var(--border-radius-medium) 0 50px; +} + +#nav-path li.navelem:not(:has(.el)) { + margin-left: 0; +} + +#nav-path li.navelem:not(:has(.el)):hover, #nav-path li.navelem:not(:has(.el)):hover:after { + background-color: var(--separator-color); +} + +#nav-path li.navelem:has(.el):before { + content: ''; + border: 5px solid var(--separator-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(3.2); + margin-right: var(--spacing-small); +} + +.navpath li.navelem a:hover { + color: var(--primary-color); +} + +/* + Scrollbars for Webkit +*/ + +#nav-tree::-webkit-scrollbar, +div.fragment::-webkit-scrollbar, +pre.fragment::-webkit-scrollbar, +div.memproto::-webkit-scrollbar, +.contents center::-webkit-scrollbar, +.contents .center::-webkit-scrollbar, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, +div.contents .toc::-webkit-scrollbar, +.contents .dotgraph::-webkit-scrollbar, +.contents .tabs-overview-container::-webkit-scrollbar { + background: transparent; + width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); +} + +#nav-tree::-webkit-scrollbar-thumb, +div.fragment::-webkit-scrollbar-thumb, +pre.fragment::-webkit-scrollbar-thumb, +div.memproto::-webkit-scrollbar-thumb, +.contents center::-webkit-scrollbar-thumb, +.contents .center::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, +div.contents .toc::-webkit-scrollbar-thumb, +.contents .dotgraph::-webkit-scrollbar-thumb, +.contents .tabs-overview-container::-webkit-scrollbar-thumb { + background-color: transparent; + border: var(--webkit-scrollbar-padding) solid transparent; + border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + background-clip: padding-box; +} + +#nav-tree:hover::-webkit-scrollbar-thumb, +div.fragment:hover::-webkit-scrollbar-thumb, +pre.fragment:hover::-webkit-scrollbar-thumb, +div.memproto:hover::-webkit-scrollbar-thumb, +.contents center:hover::-webkit-scrollbar-thumb, +.contents .center:hover::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, +div.contents .toc:hover::-webkit-scrollbar-thumb, +.contents .dotgraph:hover::-webkit-scrollbar-thumb, +.contents .tabs-overview-container:hover::-webkit-scrollbar-thumb { + background-color: var(--webkit-scrollbar-color); +} + +#nav-tree::-webkit-scrollbar-track, +div.fragment::-webkit-scrollbar-track, +pre.fragment::-webkit-scrollbar-track, +div.memproto::-webkit-scrollbar-track, +.contents center::-webkit-scrollbar-track, +.contents .center::-webkit-scrollbar-track, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, +div.contents .toc::-webkit-scrollbar-track, +.contents .dotgraph::-webkit-scrollbar-track, +.contents .tabs-overview-container::-webkit-scrollbar-track { + background: transparent; +} + +#nav-tree::-webkit-scrollbar-corner { + background-color: var(--side-nav-background); +} + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + overflow-x: auto; + overflow-x: overlay; +} + +#nav-tree { + overflow-x: auto; + overflow-y: auto; + overflow-y: overlay; +} + +/* + Scrollbars for Firefox +*/ + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc, +.contents .dotgraph, +.contents .tabs-overview-container { + scrollbar-width: thin; +} + +/* + Optional Dark mode toggle button +*/ + +doxygen-awesome-dark-mode-toggle { + display: inline-block; + margin: 0 0 0 var(--spacing-small); + padding: 0; + width: var(--searchbar-height); + height: var(--searchbar-height); + background: none; + border: none; + border-radius: var(--searchbar-border-radius); + vertical-align: middle; + text-align: center; + line-height: var(--searchbar-height); + font-size: 22px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + cursor: pointer; +} + +doxygen-awesome-dark-mode-toggle > svg { + transition: transform var(--animation-duration) ease-in-out; +} + +doxygen-awesome-dark-mode-toggle:active > svg { + transform: scale(.5); +} + +doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.03); +} + +html.dark-mode doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.18); +} + +/* + Optional fragment copy button +*/ +.doxygen-awesome-fragment-wrapper { + position: relative; +} + +doxygen-awesome-fragment-copy-button { + opacity: 0; + background: var(--fragment-background); + width: 28px; + height: 28px; + position: absolute; + right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + border: 1px solid var(--fragment-foreground); + cursor: pointer; + border-radius: var(--border-radius-small); + display: flex; + justify-content: center; + align-items: center; +} + +.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { + opacity: .28; +} + +doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { + opacity: 1 !important; +} + +doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { + transform: scale(.91); +} + +doxygen-awesome-fragment-copy-button svg { + fill: var(--fragment-foreground); + width: 18px; + height: 18px; +} + +doxygen-awesome-fragment-copy-button.success svg { + fill: rgb(14, 168, 14); +} + +doxygen-awesome-fragment-copy-button.success { + border-color: rgb(14, 168, 14); +} + +@media screen and (max-width: 767px) { + .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { + right: 0; + } +} + +/* + Optional paragraph link button +*/ + +a.anchorlink { + font-size: 90%; + margin-left: var(--spacing-small); + color: var(--page-foreground-color) !important; + text-decoration: none; + opacity: .15; + display: none; + transition: opacity var(--animation-duration) ease-in-out, color var(--animation-duration) ease-in-out; +} + +a.anchorlink svg { + fill: var(--page-foreground-color); +} + +h3 a.anchorlink svg, h4 a.anchorlink svg { + margin-bottom: -3px; + margin-top: -4px; +} + +a.anchorlink:hover { + opacity: .45; +} + +h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { + display: inline-block; +} + +/* + Optional tab feature +*/ + +.tabbed > ul { + padding-inline-start: 0px; + margin: 0; + padding: var(--spacing-small) 0; +} + +.tabbed > ul > li { + display: none; +} + +.tabbed > ul > li.selected { + display: block; +} + +.tabs-overview-container { + overflow-x: auto; + display: block; + overflow-y: visible; +} + +.tabs-overview { + border-bottom: 1px solid var(--separator-color); + display: flex; + flex-direction: row; +} + +@media screen and (max-width: 767px) { + .tabs-overview-container { + margin: 0 calc(0px - var(--spacing-large)); + } + .tabs-overview { + padding: 0 var(--spacing-large) + } +} + +.tabs-overview button.tab-button { + color: var(--page-foreground-color); + margin: 0; + border: none; + background: transparent; + padding: calc(var(--spacing-large) / 2) 0; + display: inline-block; + font-size: var(--page-font-size); + cursor: pointer; + box-shadow: 0 1px 0 0 var(--separator-color); + position: relative; + + -webkit-tap-highlight-color: transparent; +} + +.tabs-overview button.tab-button .tab-title::before { + display: block; + content: attr(title); + font-weight: 600; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.tabs-overview button.tab-button .tab-title { + float: left; + white-space: nowrap; + font-weight: normal; + font-family: var(--font-family); + padding: calc(var(--spacing-large) / 2) var(--spacing-large); + border-radius: var(--border-radius-medium); + transition: background-color var(--animation-duration) ease-in-out, font-weight var(--animation-duration) ease-in-out; +} + +.tabs-overview button.tab-button:not(:last-child) .tab-title { + box-shadow: 8px 0 0 -7px var(--separator-color); +} + +.tabs-overview button.tab-button:hover .tab-title { + background: var(--separator-color); + box-shadow: none; +} + +.tabs-overview button.tab-button.active .tab-title { + font-weight: 600; +} + +.tabs-overview button.tab-button::after { + content: ''; + display: block; + position: absolute; + left: 0; + bottom: 0; + right: 0; + height: 0; + width: 0%; + margin: 0 auto; + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + background-color: var(--primary-color); + transition: width var(--animation-duration) ease-in-out, height var(--animation-duration) ease-in-out; +} + +.tabs-overview button.tab-button.active::after { + width: 100%; + box-sizing: border-box; + height: 3px; +} + + +/* + Navigation Buttons +*/ + +.section_buttons:not(:empty) { + margin-top: calc(var(--spacing-large) * 3); +} + +.section_buttons table.markdownTable { + display: block; + width: 100%; +} + +.section_buttons table.markdownTable tbody { + display: table !important; + width: 100%; + box-shadow: none; + border-spacing: 10px; +} + +.section_buttons table.markdownTable td { + padding: 0; +} + +.section_buttons table.markdownTable th { + display: none; +} + +.section_buttons table.markdownTable tr.markdownTableHead { + border: none; +} + +.section_buttons tr th, .section_buttons tr td { + background: none; + border: none; + padding: var(--spacing-large) 0 var(--spacing-small); +} + +.section_buttons a { + display: inline-block; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + color: var(--page-secondary-foreground-color) !important; + text-decoration: none; + transition: color var(--animation-duration) ease-in-out, background-color var(--animation-duration) ease-in-out; +} + +.section_buttons a:hover { + color: var(--page-foreground-color) !important; + background-color: var(--odd-color); +} + +.section_buttons tr td.markdownTableBodyLeft a { + padding: var(--spacing-medium) var(--spacing-large) var(--spacing-medium) calc(var(--spacing-large) / 2); +} + +.section_buttons tr td.markdownTableBodyRight a { + padding: var(--spacing-medium) calc(var(--spacing-large) / 2) var(--spacing-medium) var(--spacing-large); +} + +.section_buttons tr td.markdownTableBodyLeft a::before, +.section_buttons tr td.markdownTableBodyRight a::after { + color: var(--page-secondary-foreground-color) !important; + display: inline-block; + transition: color .08s ease-in-out, transform .09s ease-in-out; +} + +.section_buttons tr td.markdownTableBodyLeft a::before { + content: '〈'; + padding-right: var(--spacing-large); +} + + +.section_buttons tr td.markdownTableBodyRight a::after { + content: '〉'; + padding-left: var(--spacing-large); +} + + +.section_buttons tr td.markdownTableBodyLeft a:hover::before { + color: var(--page-foreground-color) !important; + transform: translateX(-3px); +} + +.section_buttons tr td.markdownTableBodyRight a:hover::after { + color: var(--page-foreground-color) !important; + transform: translateX(3px); +} + +@media screen and (max-width: 450px) { + .section_buttons a { + width: 100%; + box-sizing: border-box; + } + + .section_buttons tr td:nth-of-type(1).markdownTableBodyLeft a { + border-radius: var(--border-radius-medium) 0 0 var(--border-radius-medium); + border-right: none; + } + + .section_buttons tr td:nth-of-type(2).markdownTableBodyRight a { + border-radius: 0 var(--border-radius-medium) var(--border-radius-medium) 0; + } +} + +/* + Bordered image +*/ + +html.dark-mode .darkmode_inverted_image img, /* < doxygen 1.9.3 */ +html.dark-mode .darkmode_inverted_image object[type="image/svg+xml"] /* doxygen 1.9.3 */ { + filter: brightness(89%) hue-rotate(180deg) invert(); +} + +.bordered_image { + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + display: inline-block; + overflow: hidden; +} + +.bordered_image:empty { + border: none; +} + +html.dark-mode .bordered_image img, /* < doxygen 1.9.3 */ +html.dark-mode .bordered_image object[type="image/svg+xml"] /* doxygen 1.9.3 */ { + border-radius: var(--border-radius-small); +} + +/* + Button +*/ + +.primary-button { + display: inline-block; + cursor: pointer; + background: var(--primary-color); + color: var(--page-background-color) !important; + border-radius: var(--border-radius-medium); + padding: var(--spacing-small) var(--spacing-medium); + text-decoration: none; +} + +.primary-button:hover { + background: var(--primary-dark-color); +} \ No newline at end of file diff --git a/widget/milsko/milskosrc/resource/font/7x14.bdf b/widget/milsko/milskosrc/resource/font/7x14.bdf new file mode 100644 index 0000000000..6e6c13edc2 --- /dev/null +++ b/widget/milsko/milskosrc/resource/font/7x14.bdf @@ -0,0 +1,4420 @@ +STARTFONT 2.1 +COMMENT +COMMENT Donated by H. Kagotani ; public domain +COMMENT font from Japan +COMMENT +FONT -Misc-Fixed-Medium-R-Normal--14-130-75-75-C-70-ISO8859-1 +SIZE 7 75 75 +FONTBOUNDINGBOX 7 14 0 -2 +STARTPROPERTIES 19 +FONTNAME_REGISTRY "" +FOUNDRY "Misc" +FAMILY_NAME "Fixed" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 14 +POINT_SIZE 130 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 70 +CHARSET_REGISTRY "ISO8859" +CHARSET_ENCODING "1" +DEFAULT_CHAR 32 +FONT_DESCENT 2 +FONT_ASCENT 12 +COPYRIGHT "Public domain font. Share and enjoy." +ENDPROPERTIES +CHARS 209 +STARTCHAR 0001 +ENCODING 1 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +18 +3C +3C +7E +7E +3C +3C +18 +18 +00 +00 +ENDCHAR +STARTCHAR 0002 +ENCODING 2 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +54 +AA +54 +AA +54 +AA +54 +AA +54 +AA +54 +AA +54 +AA +ENDCHAR +STARTCHAR 000b +ENCODING 11 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +10 +10 +10 +10 +10 +10 +F0 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 000c +ENCODING 12 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +F0 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 000d +ENCODING 13 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +1E +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 000e +ENCODING 14 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +10 +10 +10 +10 +10 +10 +1E +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 000f +ENCODING 15 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +10 +10 +10 +10 +10 +10 +FE +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0010 +ENCODING 16 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +FE +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0011 +ENCODING 17 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +FE +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0012 +ENCODING 18 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +FE +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0013 +ENCODING 19 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +FE +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0014 +ENCODING 20 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +FE +ENDCHAR +STARTCHAR 0015 +ENCODING 21 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +10 +10 +10 +10 +10 +10 +1E +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0016 +ENCODING 22 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +10 +10 +10 +10 +10 +10 +F0 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0017 +ENCODING 23 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +10 +10 +10 +10 +10 +10 +FE +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0018 +ENCODING 24 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +FE +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0019 +ENCODING 25 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0020 +ENCODING 32 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0021 +ENCODING 33 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +10 +10 +10 +10 +10 +10 +10 +00 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 0022 +ENCODING 34 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +6C +24 +24 +48 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0023 +ENCODING 35 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +0A +0A +0A +7E +14 +14 +7E +28 +28 +28 +00 +00 +ENDCHAR +STARTCHAR 0024 +ENCODING 36 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +08 +3C +4A +4A +28 +1C +0A +4A +4A +3C +08 +00 +ENDCHAR +STARTCHAR 0025 +ENCODING 37 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +32 +4A +4C +38 +08 +10 +1C +32 +52 +4C +00 +00 +ENDCHAR +STARTCHAR 0026 +ENCODING 38 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +24 +24 +24 +18 +32 +4A +44 +4C +32 +00 +00 +ENDCHAR +STARTCHAR 0027 +ENCODING 39 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +30 +10 +10 +20 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0028 +ENCODING 40 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +02 +04 +08 +08 +10 +10 +10 +10 +10 +08 +08 +04 +02 +ENDCHAR +STARTCHAR 0029 +ENCODING 41 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +40 +20 +10 +10 +08 +08 +08 +08 +08 +10 +10 +20 +40 +ENDCHAR +STARTCHAR 002a +ENCODING 42 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +08 +2A +1C +08 +08 +1C +2A +08 +00 +00 +00 +ENDCHAR +STARTCHAR 002b +ENCODING 43 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +10 +10 +10 +7C +10 +10 +10 +00 +00 +00 +ENDCHAR +STARTCHAR 002c +ENCODING 44 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +30 +10 +10 +20 +ENDCHAR +STARTCHAR 002d +ENCODING 45 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +7E +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 002e +ENCODING 46 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 002f +ENCODING 47 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +02 +02 +04 +04 +08 +08 +08 +10 +10 +20 +20 +40 +40 +ENDCHAR +STARTCHAR 0030 +ENCODING 48 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +24 +42 +42 +42 +42 +42 +42 +24 +18 +00 +00 +ENDCHAR +STARTCHAR 0031 +ENCODING 49 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +08 +18 +28 +08 +08 +08 +08 +08 +08 +3E +00 +00 +ENDCHAR +STARTCHAR 0032 +ENCODING 50 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +02 +04 +04 +08 +10 +20 +7E +00 +00 +ENDCHAR +STARTCHAR 0033 +ENCODING 51 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +02 +1C +02 +02 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0034 +ENCODING 52 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +04 +0C +14 +14 +24 +24 +44 +7E +04 +04 +00 +00 +ENDCHAR +STARTCHAR 0035 +ENCODING 53 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7E +40 +40 +7C +42 +02 +02 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0036 +ENCODING 54 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +1C +22 +42 +40 +5C +62 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0037 +ENCODING 55 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7E +42 +44 +04 +08 +08 +08 +08 +08 +08 +00 +00 +ENDCHAR +STARTCHAR 0038 +ENCODING 56 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +24 +18 +24 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0039 +ENCODING 57 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +42 +46 +3A +02 +42 +44 +38 +00 +00 +ENDCHAR +STARTCHAR 003a +ENCODING 58 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +10 +10 +00 +00 +00 +10 +10 +00 +00 +00 +ENDCHAR +STARTCHAR 003b +ENCODING 59 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +10 +10 +00 +00 +00 +30 +10 +10 +20 +00 +ENDCHAR +STARTCHAR 003c +ENCODING 60 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +04 +08 +10 +20 +40 +20 +10 +08 +04 +00 +00 +ENDCHAR +STARTCHAR 003d +ENCODING 61 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7E +00 +00 +7E +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 003e +ENCODING 62 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +40 +20 +10 +08 +04 +08 +10 +20 +40 +00 +00 +ENDCHAR +STARTCHAR 003f +ENCODING 63 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +04 +08 +08 +08 +00 +08 +08 +00 +00 +ENDCHAR +STARTCHAR 0040 +ENCODING 64 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +1C +22 +4E +52 +52 +52 +52 +4E +20 +1E +00 +00 +ENDCHAR +STARTCHAR 0041 +ENCODING 65 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +10 +18 +28 +24 +44 +42 +7E +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 0042 +ENCODING 66 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7C +42 +42 +44 +7C +42 +42 +42 +42 +7C +00 +00 +ENDCHAR +STARTCHAR 0043 +ENCODING 67 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +40 +40 +40 +40 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0044 +ENCODING 68 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +78 +44 +42 +42 +42 +42 +42 +42 +44 +78 +00 +00 +ENDCHAR +STARTCHAR 0045 +ENCODING 69 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7E +40 +40 +40 +7C +40 +40 +40 +40 +7E +00 +00 +ENDCHAR +STARTCHAR 0046 +ENCODING 70 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7E +40 +40 +40 +7C +40 +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR 0047 +ENCODING 71 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +40 +40 +4E +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0048 +ENCODING 72 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +42 +42 +42 +7E +42 +42 +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 0049 +ENCODING 73 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3E +08 +08 +08 +08 +08 +08 +08 +08 +3E +00 +00 +ENDCHAR +STARTCHAR 004a +ENCODING 74 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +02 +02 +02 +02 +02 +02 +02 +42 +44 +38 +00 +00 +ENDCHAR +STARTCHAR 004b +ENCODING 75 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +44 +48 +50 +70 +48 +48 +44 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 004c +ENCODING 76 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +40 +40 +40 +40 +40 +40 +40 +40 +40 +7E +00 +00 +ENDCHAR +STARTCHAR 004d +ENCODING 77 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +46 +66 +6A +5A +52 +52 +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 004e +ENCODING 78 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +62 +62 +52 +52 +52 +4A +4A +4A +46 +46 +00 +00 +ENDCHAR +STARTCHAR 004f +ENCODING 79 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0050 +ENCODING 80 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7C +42 +42 +42 +42 +7C +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR 0051 +ENCODING 81 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +42 +42 +42 +72 +4A +46 +3C +04 +02 +ENDCHAR +STARTCHAR 0052 +ENCODING 82 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7C +42 +42 +42 +7C +44 +42 +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 0053 +ENCODING 83 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +20 +10 +08 +04 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0054 +ENCODING 84 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7E +10 +10 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 0055 +ENCODING 85 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +42 +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0056 +ENCODING 86 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +42 +42 +44 +24 +24 +28 +18 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 0057 +ENCODING 87 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +4A +4A +4A +4A +4A +7E +24 +24 +24 +24 +00 +00 +ENDCHAR +STARTCHAR 0058 +ENCODING 88 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +42 +24 +24 +18 +18 +24 +24 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 0059 +ENCODING 89 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +42 +44 +24 +28 +18 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 005a +ENCODING 90 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7E +02 +04 +08 +08 +10 +20 +20 +40 +7E +00 +00 +ENDCHAR +STARTCHAR 005b +ENCODING 91 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +1E +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +1E +ENDCHAR +STARTCHAR 005c +ENCODING 92 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +40 +40 +20 +20 +10 +10 +10 +08 +08 +04 +04 +02 +02 +ENDCHAR +STARTCHAR 005d +ENCODING 93 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +78 +08 +08 +08 +08 +08 +08 +08 +08 +08 +08 +08 +78 +ENDCHAR +STARTCHAR 005e +ENCODING 94 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +24 +42 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 005f +ENCODING 95 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +7E +ENDCHAR +STARTCHAR 0060 +ENCODING 96 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +0C +08 +08 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0061 +ENCODING 97 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3C +42 +0E +32 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 0062 +ENCODING 98 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +40 +40 +40 +5C +62 +42 +42 +42 +62 +5C +00 +00 +ENDCHAR +STARTCHAR 0063 +ENCODING 99 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3C +42 +40 +40 +40 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0064 +ENCODING 100 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +02 +02 +02 +3A +46 +42 +42 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 0065 +ENCODING 101 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3C +42 +42 +7E +40 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0066 +ENCODING 102 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +0C +12 +10 +10 +7C +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 0067 +ENCODING 103 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3A +44 +44 +44 +38 +20 +5C +42 +3C +ENDCHAR +STARTCHAR 0068 +ENCODING 104 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +40 +40 +40 +5C +62 +42 +42 +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 0069 +ENCODING 105 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +10 +10 +00 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 006a +ENCODING 106 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +04 +04 +00 +04 +04 +04 +04 +04 +04 +04 +44 +38 +ENDCHAR +STARTCHAR 006b +ENCODING 107 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +40 +40 +40 +44 +48 +50 +70 +48 +44 +42 +00 +00 +ENDCHAR +STARTCHAR 006c +ENCODING 108 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 006d +ENCODING 109 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7C +52 +52 +52 +52 +52 +52 +00 +00 +ENDCHAR +STARTCHAR 006e +ENCODING 110 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +5C +62 +42 +42 +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 006f +ENCODING 111 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3C +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0070 +ENCODING 112 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +5C +62 +42 +42 +42 +62 +5C +40 +40 +ENDCHAR +STARTCHAR 0071 +ENCODING 113 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3A +46 +42 +42 +42 +46 +3A +02 +02 +ENDCHAR +STARTCHAR 0072 +ENCODING 114 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +5C +62 +42 +40 +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR 0073 +ENCODING 115 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3C +42 +20 +18 +04 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 0074 +ENCODING 116 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +10 +10 +10 +7E +10 +10 +10 +10 +10 +0E +00 +00 +ENDCHAR +STARTCHAR 0075 +ENCODING 117 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +42 +42 +42 +42 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 0076 +ENCODING 118 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +42 +42 +22 +24 +14 +18 +08 +00 +00 +ENDCHAR +STARTCHAR 0077 +ENCODING 119 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +4A +4A +4A +7E +24 +24 +24 +00 +00 +ENDCHAR +STARTCHAR 0078 +ENCODING 120 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +42 +42 +24 +18 +24 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 0079 +ENCODING 121 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +42 +42 +22 +24 +14 +1C +08 +48 +30 +ENDCHAR +STARTCHAR 007a +ENCODING 122 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7E +04 +08 +10 +10 +20 +7E +00 +00 +ENDCHAR +STARTCHAR 007b +ENCODING 123 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +06 +08 +08 +08 +08 +08 +10 +08 +08 +08 +08 +08 +06 +ENDCHAR +STARTCHAR 007c +ENCODING 124 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 007d +ENCODING 125 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +60 +10 +10 +10 +10 +10 +08 +10 +10 +10 +10 +10 +60 +ENDCHAR +STARTCHAR 007e +ENCODING 126 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +20 +52 +4A +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 007f +ENCODING 127 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00a0 +ENCODING 160 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00a1 +ENCODING 161 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +10 +10 +00 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 00a2 +ENCODING 162 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +10 +3e +52 +50 +50 +50 +52 +3e +10 +00 +ENDCHAR +STARTCHAR 00a3 +ENCODING 163 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +18 +24 +20 +20 +78 +20 +20 +78 +24 +00 +00 +ENDCHAR +STARTCHAR 00a4 +ENCODING 164 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +42 +3c +24 +24 +3c +42 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00a5 +ENCODING 165 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +24 +18 +7e +08 +08 +7e +08 +08 +08 +00 +00 +ENDCHAR +STARTCHAR 00a6 +ENCODING 166 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +10 +10 +10 +10 +00 +00 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 00a7 +ENCODING 167 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +3c +42 +20 +18 +24 +42 +24 +18 +04 +42 +3c +00 +00 +ENDCHAR +STARTCHAR 00a8 +ENCODING 168 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +48 +48 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00a9 +ENCODING 169 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +3c +42 +5a +66 +62 +62 +62 +66 +5a +42 +3c +00 +00 +ENDCHAR +STARTCHAR 00aa +ENCODING 170 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +1c +22 +1e +22 +26 +1a +00 +3e +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00ab +ENCODING 171 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +0a +14 +28 +50 +28 +14 +0a +00 +00 +ENDCHAR +STARTCHAR 00ac +ENCODING 172 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +f8 +08 +08 +08 +00 +00 +ENDCHAR +STARTCHAR 00ad +ENCODING 173 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +f0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00ae +ENCODING 174 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +3c +42 +7a +66 +66 +7a +66 +66 +66 +42 +3c +00 +00 +ENDCHAR +STARTCHAR 00af +ENCODING 175 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +f0 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b0 +ENCODING 176 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +30 +48 +48 +30 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b1 +ENCODING 177 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +10 +10 +7c +10 +10 +7c +00 +00 +ENDCHAR +STARTCHAR 00b2 +ENCODING 178 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +30 +48 +08 +10 +20 +40 +78 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b3 +ENCODING 179 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +30 +48 +08 +30 +08 +48 +30 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b4 +ENCODING 180 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +08 +10 +20 +40 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b5 +ENCODING 181 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +44 +44 +44 +44 +6c +54 +40 +40 +ENDCHAR +STARTCHAR 00b6 +ENCODING 182 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +54 +54 +54 +54 +34 +14 +14 +14 +14 +14 +1c +ENDCHAR +STARTCHAR 00b7 +ENCODING 183 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +10 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b8 +ENCODING 184 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +10 +10 +20 +ENDCHAR +STARTCHAR 00b9 +ENCODING 185 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +20 +60 +20 +20 +20 +20 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00ba +ENCODING 186 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +24 +24 +18 +00 +3c +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00bb +ENCODING 187 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +50 +28 +14 +0a +14 +28 +50 +00 +00 +ENDCHAR +STARTCHAR 00bc +ENCODING 188 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +20 +62 +24 +24 +28 +12 +16 +2a +4e +42 +00 +00 +ENDCHAR +STARTCHAR 00bd +ENCODING 189 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +20 +62 +24 +24 +28 +14 +1a +22 +44 +4e +00 +00 +ENDCHAR +STARTCHAR 00be +ENCODING 190 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +62 +12 +24 +18 +68 +12 +26 +2a +4e +02 +00 +00 +ENDCHAR +STARTCHAR 00bf +ENCODING 191 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +08 +08 +00 +08 +08 +08 +08 +04 +42 +42 +3c +ENDCHAR +STARTCHAR 00c0 +ENCODING 192 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +20 +18 +00 +18 +28 +24 +44 +42 +7E +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 00c1 +ENCODING 193 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +04 +18 +00 +18 +28 +24 +44 +42 +7E +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 00c2 +ENCODING 194 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +24 +00 +18 +28 +24 +44 +42 +7E +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 00c3 +ENCODING 195 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +14 +28 +00 +18 +28 +24 +44 +42 +7E +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 00c4 +ENCODING 196 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +24 +00 +18 +28 +24 +44 +42 +7E +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 00c5 +ENCODING 197 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +00 +10 +18 +28 +24 +44 +42 +7E +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 00c6 +ENCODING 198 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3E +50 +50 +50 +9C +f0 +90 +90 +90 +9E +00 +00 +ENDCHAR +STARTCHAR 00c7 +ENCODING 199 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3C +42 +42 +40 +40 +40 +40 +42 +42 +3C +08 +10 +ENDCHAR +STARTCHAR 00c8 +ENCODING 200 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +20 +18 +00 +7e +40 +40 +40 +7c +40 +40 +40 +7E +00 +00 +ENDCHAR +STARTCHAR 00c9 +ENCODING 201 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +04 +18 +00 +7e +40 +40 +40 +7c +40 +40 +40 +7E +00 +00 +ENDCHAR +STARTCHAR 00ca +ENCODING 202 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +24 +00 +7e +40 +40 +40 +7c +40 +40 +40 +7E +00 +00 +ENDCHAR +STARTCHAR 00cb +ENCODING 203 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +24 +00 +7e +40 +40 +40 +7c +40 +40 +40 +7E +00 +00 +ENDCHAR +STARTCHAR 00cc +ENCODING 204 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +10 +0c +00 +3e +08 +08 +08 +08 +08 +08 +08 +3E +00 +00 +ENDCHAR +STARTCHAR 00cd +ENCODING 205 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +04 +18 +00 +3e +08 +08 +08 +08 +08 +08 +08 +3E +00 +00 +ENDCHAR +STARTCHAR 00ce +ENCODING 206 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +08 +14 +00 +3e +08 +08 +08 +08 +08 +08 +08 +3E +00 +00 +ENDCHAR +STARTCHAR 00cf +ENCODING 207 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +14 +00 +3e +08 +08 +08 +08 +08 +08 +08 +3E +00 +00 +ENDCHAR +STARTCHAR 00d0 +ENCODING 208 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +78 +44 +42 +42 +e2 +42 +42 +42 +44 +78 +00 +00 +ENDCHAR +STARTCHAR 00d1 +ENCODING 209 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +14 +28 +00 +62 +52 +52 +52 +4A +4A +4A +46 +46 +00 +00 +ENDCHAR +STARTCHAR 00d2 +ENCODING 210 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +20 +18 +00 +3c +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00d3 +ENCODING 211 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +04 +18 +00 +3c +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00d4 +ENCODING 212 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +24 +00 +3c +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00d5 +ENCODING 213 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +14 +28 +00 +3c +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00d6 +ENCODING 214 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +24 +00 +3c +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00d7 +ENCODING 215 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +82 +44 +28 +10 +28 +44 +82 +00 +00 +ENDCHAR +STARTCHAR 00d8 +ENCODING 216 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +02 +02 +3C +46 +4a +4a +4a +52 +52 +52 +62 +3C +40 +40 +ENDCHAR +STARTCHAR 00d9 +ENCODING 217 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +20 +18 +00 +42 +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00da +ENCODING 218 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +04 +18 +00 +42 +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00db +ENCODING 219 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +24 +00 +42 +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00dc +ENCODING 220 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +24 +00 +42 +42 +42 +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00dd +ENCODING 221 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +04 +18 +42 +42 +44 +24 +28 +18 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 00de +ENCODING 222 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +40 +40 +7c +42 +42 +42 +42 +7c +40 +40 +00 +00 +ENDCHAR +STARTCHAR 00df +ENCODING 223 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +24 +24 +24 +38 +24 +22 +22 +22 +7c +00 +00 +ENDCHAR +STARTCHAR 00e0 +ENCODING 224 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +20 +10 +08 +00 +3C +42 +0E +32 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00e1 +ENCODING 225 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +04 +08 +10 +00 +3C +42 +0E +32 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00e2 +ENCODING 226 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +24 +00 +3C +42 +0E +32 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00e3 +ENCODING 227 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +14 +28 +00 +3C +42 +0E +32 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00e4 +ENCODING 228 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +24 +00 +3C +42 +0E +32 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00e5 +ENCODING 229 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +10 +28 +10 +00 +3C +42 +0E +32 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00e6 +ENCODING 230 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7C +92 +32 +5E +90 +92 +7C +00 +00 +ENDCHAR +STARTCHAR 00e7 +ENCODING 231 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3C +42 +40 +40 +40 +42 +3C +08 +10 +ENDCHAR +STARTCHAR 00e8 +ENCODING 232 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +20 +10 +08 +00 +3C +42 +42 +7E +40 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00e9 +ENCODING 233 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +04 +08 +10 +00 +3C +42 +42 +7E +40 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00ea +ENCODING 234 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +24 +00 +3C +42 +42 +7E +40 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00eb +ENCODING 235 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +24 +00 +3C +42 +42 +7E +40 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00ec +ENCODING 236 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +20 +10 +08 +00 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 00ed +ENCODING 237 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +08 +10 +20 +00 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 00ee +ENCODING 238 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +10 +28 +00 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 00ef +ENCODING 239 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +28 +00 +10 +10 +10 +10 +10 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 00f0 +ENCODING 240 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +28 +10 +28 +04 +3c +44 +44 +44 +44 +44 +38 +00 +00 +ENDCHAR +STARTCHAR 00f1 +ENCODING 241 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +14 +28 +00 +5C +62 +42 +42 +42 +42 +42 +00 +00 +ENDCHAR +STARTCHAR 00f2 +ENCODING 242 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +20 +10 +08 +00 +3C +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00f3 +ENCODING 243 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +04 +08 +10 +00 +3C +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00f4 +ENCODING 244 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +24 +00 +3C +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00f5 +ENCODING 245 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +14 +28 +00 +3C +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00f6 +ENCODING 246 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +24 +00 +3C +42 +42 +42 +42 +42 +3C +00 +00 +ENDCHAR +STARTCHAR 00f7 +ENCODING 247 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +30 +00 +fc +00 +30 +00 +00 +ENDCHAR +STARTCHAR 00f8 +ENCODING 248 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +02 +04 +3C +4a +4a +52 +52 +62 +3C +40 +40 +ENDCHAR +STARTCHAR 00f9 +ENCODING 249 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +20 +10 +08 +42 +42 +42 +42 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00fa +ENCODING 250 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +04 +08 +10 +42 +42 +42 +42 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00fb +ENCODING 251 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +24 +00 +42 +42 +42 +42 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00fc +ENCODING 252 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +24 +00 +42 +42 +42 +42 +42 +46 +3A +00 +00 +ENDCHAR +STARTCHAR 00fd +ENCODING 253 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +04 +08 +10 +42 +42 +22 +24 +14 +1C +08 +48 +30 +ENDCHAR +STARTCHAR 00fe +ENCODING 254 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +40 +40 +40 +5C +62 +42 +42 +42 +62 +5C +40 +40 +ENDCHAR +STARTCHAR 00ff +ENCODING 255 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +24 +00 +42 +42 +22 +24 +14 +1C +08 +48 +30 +ENDCHAR +ENDFONT diff --git a/widget/milsko/milskosrc/resource/font/7x14B.bdf b/widget/milsko/milskosrc/resource/font/7x14B.bdf new file mode 100644 index 0000000000..a99d925abd --- /dev/null +++ b/widget/milsko/milskosrc/resource/font/7x14B.bdf @@ -0,0 +1,4420 @@ +STARTFONT 2.1 +COMMENT +COMMENT Donated by H. Kagotani ; public domain +COMMENT font from Japan +COMMENT +FONT -Misc-Fixed-Bold-R-Normal--14-130-75-75-C-70-ISO8859-1 +SIZE 7 75 75 +FONTBOUNDINGBOX 7 14 0 -2 +STARTPROPERTIES 19 +FONTNAME_REGISTRY "" +FOUNDRY "Misc" +FAMILY_NAME "Fixed" +WEIGHT_NAME "Bold" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 14 +POINT_SIZE 130 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 70 +CHARSET_REGISTRY "ISO8859" +CHARSET_ENCODING "1" +DEFAULT_CHAR 32 +FONT_DESCENT 2 +FONT_ASCENT 12 +COPYRIGHT "Public domain font. Share and enjoy." +ENDPROPERTIES +CHARS 209 +STARTCHAR 0001 +ENCODING 1 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +18 +3c +3c +7e +7e +3c +3c +18 +18 +00 +00 +ENDCHAR +STARTCHAR 0002 +ENCODING 2 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +76 +ee +dc +ba +76 +ee +dc +ba +76 +ee +dc +ba +76 +ee +ENDCHAR +STARTCHAR 000b +ENCODING 11 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +18 +18 +18 +18 +18 +f8 +f8 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 000c +ENCODING 12 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +f8 +f8 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 000d +ENCODING 13 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +1e +1e +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 000e +ENCODING 14 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +18 +18 +18 +18 +18 +1e +1e +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 000f +ENCODING 15 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +18 +18 +18 +18 +18 +fe +fe +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0010 +ENCODING 16 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +fe +fe +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0011 +ENCODING 17 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +fe +fe +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0012 +ENCODING 18 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +fe +fe +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0013 +ENCODING 19 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +fe +fe +00 +00 +00 +ENDCHAR +STARTCHAR 0014 +ENCODING 20 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +fe +fe +ENDCHAR +STARTCHAR 0015 +ENCODING 21 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +18 +18 +18 +18 +18 +1e +1e +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0016 +ENCODING 22 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +18 +18 +18 +18 +18 +f8 +f8 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0017 +ENCODING 23 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +18 +18 +18 +18 +18 +fe +fe +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0018 +ENCODING 24 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +fe +fe +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0019 +ENCODING 25 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0020 +ENCODING 32 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0021 +ENCODING 33 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +18 +18 +18 +18 +18 +18 +00 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 0022 +ENCODING 34 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +7e +36 +36 +6c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0023 +ENCODING 35 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +1e +1e +1e +7e +3c +3c +7e +78 +78 +78 +00 +00 +ENDCHAR +STARTCHAR 0024 +ENCODING 36 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +3c +5a +5a +38 +1c +1a +5a +5a +3c +18 +00 +ENDCHAR +STARTCHAR 0025 +ENCODING 37 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +36 +6e +6c +38 +08 +10 +1c +36 +76 +6c +00 +00 +ENDCHAR +STARTCHAR 0026 +ENCODING 38 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +1c +36 +36 +36 +1c +36 +6e +6c +6c +36 +00 +00 +ENDCHAR +STARTCHAR 0027 +ENCODING 39 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +38 +18 +18 +30 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0028 +ENCODING 40 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +06 +0c +18 +18 +30 +30 +30 +30 +30 +18 +18 +0c +06 +ENDCHAR +STARTCHAR 0029 +ENCODING 41 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +60 +30 +18 +18 +0c +0c +0c +0c +0c +18 +18 +30 +60 +ENDCHAR +STARTCHAR 002a +ENCODING 42 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +5a +5a +3c +18 +18 +3c +5a +5a +00 +00 +00 +ENDCHAR +STARTCHAR 002b +ENCODING 43 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +18 +18 +18 +7e +18 +18 +18 +00 +00 +00 +ENDCHAR +STARTCHAR 002c +ENCODING 44 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +38 +18 +18 +30 +ENDCHAR +STARTCHAR 002d +ENCODING 45 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +7e +7e +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 002e +ENCODING 46 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 002f +ENCODING 47 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +06 +06 +06 +0c +0c +18 +18 +18 +30 +30 +60 +60 +60 +ENDCHAR +STARTCHAR 0030 +ENCODING 48 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0031 +ENCODING 49 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +38 +78 +18 +18 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 0032 +ENCODING 50 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +06 +0c +0c +18 +30 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 0033 +ENCODING 51 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +06 +1c +06 +06 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0034 +ENCODING 52 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +04 +0c +0c +1c +3c +2c +6c +7e +04 +04 +00 +00 +ENDCHAR +STARTCHAR 0035 +ENCODING 53 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7e +60 +60 +7c +66 +06 +06 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0036 +ENCODING 54 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +1c +36 +66 +60 +7c +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0037 +ENCODING 55 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7e +66 +6c +0c +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 0038 +ENCODING 56 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +3c +18 +3c +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0039 +ENCODING 57 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +66 +66 +3e +06 +66 +6c +38 +00 +00 +ENDCHAR +STARTCHAR 003a +ENCODING 58 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +18 +18 +00 +00 +00 +18 +18 +00 +00 +00 +ENDCHAR +STARTCHAR 003b +ENCODING 59 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +18 +18 +00 +00 +00 +38 +18 +18 +30 +00 +ENDCHAR +STARTCHAR 003c +ENCODING 60 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +06 +0c +18 +30 +60 +30 +18 +0c +06 +00 +00 +ENDCHAR +STARTCHAR 003d +ENCODING 61 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +7e +7e +00 +7e +7e +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 003e +ENCODING 62 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +60 +30 +18 +0c +06 +0c +18 +30 +60 +00 +00 +ENDCHAR +STARTCHAR 003f +ENCODING 63 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +0c +18 +18 +18 +00 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 0040 +ENCODING 64 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +1c +36 +6e +7a +7a +7a +7a +6e +30 +1e +00 +00 +ENDCHAR +STARTCHAR 0041 +ENCODING 65 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +7e +66 +66 +66 +66 +7e +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 0042 +ENCODING 66 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7c +66 +66 +64 +7c +66 +66 +66 +66 +7c +00 +00 +ENDCHAR +STARTCHAR 0043 +ENCODING 67 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +60 +60 +60 +60 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0044 +ENCODING 68 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +78 +6c +66 +66 +66 +66 +66 +66 +6c +78 +00 +00 +ENDCHAR +STARTCHAR 0045 +ENCODING 69 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7e +60 +60 +60 +7c +60 +60 +60 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 0046 +ENCODING 70 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7e +60 +60 +60 +7c +60 +60 +60 +60 +60 +00 +00 +ENDCHAR +STARTCHAR 0047 +ENCODING 71 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +60 +60 +6e +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0048 +ENCODING 72 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +66 +66 +66 +66 +7e +66 +66 +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 0049 +ENCODING 73 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7e +18 +18 +18 +18 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 004a +ENCODING 74 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +06 +06 +06 +06 +06 +06 +06 +66 +6c +38 +00 +00 +ENDCHAR +STARTCHAR 004b +ENCODING 75 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +66 +6c +78 +70 +70 +78 +78 +6c +66 +66 +00 +00 +ENDCHAR +STARTCHAR 004c +ENCODING 76 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 004d +ENCODING 77 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +66 +66 +7e +7e +66 +66 +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 004e +ENCODING 78 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +66 +66 +76 +76 +76 +6e +6e +6e +66 +66 +00 +00 +ENDCHAR +STARTCHAR 004f +ENCODING 79 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0050 +ENCODING 80 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7c +66 +66 +66 +66 +7c +60 +60 +60 +60 +00 +00 +ENDCHAR +STARTCHAR 0051 +ENCODING 81 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +66 +66 +66 +76 +6e +66 +3c +06 +02 +ENDCHAR +STARTCHAR 0052 +ENCODING 82 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7c +66 +66 +66 +7c +6c +66 +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 0053 +ENCODING 83 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +30 +18 +18 +0c +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0054 +ENCODING 84 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7e +18 +18 +18 +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 0055 +ENCODING 85 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +66 +66 +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0056 +ENCODING 86 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +66 +66 +66 +66 +66 +66 +66 +3c +3c +18 +00 +00 +ENDCHAR +STARTCHAR 0057 +ENCODING 87 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +66 +66 +66 +66 +66 +7e +7e +7e +7e +24 +00 +00 +ENDCHAR +STARTCHAR 0058 +ENCODING 88 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +66 +66 +3c +3c +18 +18 +3c +3c +66 +66 +00 +00 +ENDCHAR +STARTCHAR 0059 +ENCODING 89 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +66 +66 +66 +3c +3c +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 005a +ENCODING 90 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7e +06 +0c +0c +18 +18 +30 +30 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 005b +ENCODING 91 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +3e +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +3e +ENDCHAR +STARTCHAR 005c +ENCODING 92 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +60 +60 +60 +30 +30 +18 +18 +18 +0c +0c +06 +06 +06 +ENDCHAR +STARTCHAR 005d +ENCODING 93 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +7c +0c +0c +0c +0c +0c +0c +0c +0c +0c +0c +0c +7c +ENDCHAR +STARTCHAR 005e +ENCODING 94 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +3c +66 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 005f +ENCODING 95 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +7e +7e +ENDCHAR +STARTCHAR 0060 +ENCODING 96 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +1c +18 +18 +0c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 0061 +ENCODING 97 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3c +66 +0e +36 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 0062 +ENCODING 98 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +60 +60 +60 +7c +66 +66 +66 +66 +66 +7c +00 +00 +ENDCHAR +STARTCHAR 0063 +ENCODING 99 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3c +66 +60 +60 +60 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0064 +ENCODING 100 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +06 +06 +06 +3e +66 +66 +66 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 0065 +ENCODING 101 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3c +66 +66 +7e +60 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0066 +ENCODING 102 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +0c +1e +18 +18 +7e +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 0067 +ENCODING 103 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3a +6e +6c +6c +38 +20 +7c +66 +3c +ENDCHAR +STARTCHAR 0068 +ENCODING 104 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +60 +60 +60 +7c +66 +66 +66 +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 0069 +ENCODING 105 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +18 +00 +18 +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 006a +ENCODING 106 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +0c +0c +00 +0c +0c +0c +0c +0c +0c +0c +6c +38 +ENDCHAR +STARTCHAR 006b +ENCODING 107 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +60 +60 +60 +64 +6c +78 +78 +6c +66 +62 +00 +00 +ENDCHAR +STARTCHAR 006c +ENCODING 108 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 006d +ENCODING 109 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +6c +7e +7e +7e +7e +7e +7e +00 +00 +ENDCHAR +STARTCHAR 006e +ENCODING 110 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7c +66 +66 +66 +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 006f +ENCODING 111 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3c +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0070 +ENCODING 112 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7c +66 +66 +66 +66 +66 +7c +60 +60 +ENDCHAR +STARTCHAR 0071 +ENCODING 113 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3e +66 +66 +66 +66 +66 +3e +06 +06 +ENDCHAR +STARTCHAR 0072 +ENCODING 114 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7c +66 +66 +60 +60 +60 +60 +00 +00 +ENDCHAR +STARTCHAR 0073 +ENCODING 115 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3c +66 +30 +18 +0c +66 +3c +00 +00 +ENDCHAR +STARTCHAR 0074 +ENCODING 116 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +18 +18 +7e +18 +18 +18 +18 +18 +0e +00 +00 +ENDCHAR +STARTCHAR 0075 +ENCODING 117 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +66 +66 +66 +66 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 0076 +ENCODING 118 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +66 +66 +66 +3c +3c +18 +18 +00 +00 +ENDCHAR +STARTCHAR 0077 +ENCODING 119 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +66 +66 +7e +7e +7e +7e +24 +00 +00 +ENDCHAR +STARTCHAR 0078 +ENCODING 120 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +66 +66 +3c +18 +3c +66 +66 +00 +00 +ENDCHAR +STARTCHAR 0079 +ENCODING 121 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +66 +66 +36 +36 +1c +1c +0c +6c +38 +ENDCHAR +STARTCHAR 007a +ENCODING 122 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7e +06 +0c +18 +30 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 007b +ENCODING 123 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +0e +18 +18 +18 +18 +18 +30 +18 +18 +18 +18 +18 +0e +ENDCHAR +STARTCHAR 007c +ENCODING 124 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 007d +ENCODING 125 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +70 +18 +18 +18 +18 +18 +0c +18 +18 +18 +18 +18 +70 +ENDCHAR +STARTCHAR 007e +ENCODING 126 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +20 +7e +7e +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 007f +ENCODING 127 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00a0 +ENCODING 160 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00a1 +ENCODING 161 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +18 +00 +18 +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 00a2 +ENCODING 162 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +18 +3e +5a +58 +58 +58 +5a +3e +18 +00 +ENDCHAR +STARTCHAR 00a3 +ENCODING 163 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +1c +36 +30 +30 +78 +30 +30 +7c +36 +00 +00 +ENDCHAR +STARTCHAR 00a4 +ENCODING 164 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +66 +3c +34 +2c +3c +66 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00a5 +ENCODING 165 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +42 +66 +3c +7e +18 +18 +7e +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 00a6 +ENCODING 166 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +18 +18 +18 +00 +00 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 00a7 +ENCODING 167 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +3c +66 +30 +18 +3c +66 +3c +18 +0c +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00a8 +ENCODING 168 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +6c +6c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00a9 +ENCODING 169 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +3c +66 +7e +76 +76 +76 +76 +76 +7e +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00aa +ENCODING 170 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +1c +36 +1e +36 +36 +1e +00 +3e +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00ab +ENCODING 171 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +0e +1e +3c +78 +3c +1e +0e +00 +00 +ENDCHAR +STARTCHAR 00ac +ENCODING 172 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +fc +fc +0c +0c +0c +00 +00 +ENDCHAR +STARTCHAR 00ad +ENCODING 173 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +f0 +f0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00ae +ENCODING 174 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +3c +66 +7e +76 +76 +7e +76 +76 +76 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00af +ENCODING 175 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +f0 +f0 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b0 +ENCODING 176 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +38 +6c +6c +38 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b1 +ENCODING 177 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +18 +18 +7e +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 00b2 +ENCODING 178 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +38 +6c +0c +18 +30 +60 +7c +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b3 +ENCODING 179 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +38 +6c +0c +38 +0c +6c +38 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b4 +ENCODING 180 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +0c +18 +30 +60 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b5 +ENCODING 181 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +66 +66 +66 +66 +6e +7e +60 +60 +ENDCHAR +STARTCHAR 00b6 +ENCODING 182 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3e +76 +76 +76 +76 +36 +16 +16 +16 +16 +16 +1e +ENDCHAR +STARTCHAR 00b7 +ENCODING 183 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +18 +18 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00b8 +ENCODING 184 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +18 +18 +30 +ENDCHAR +STARTCHAR 00b9 +ENCODING 185 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +30 +70 +30 +30 +30 +30 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00ba +ENCODING 186 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +1c +36 +36 +1c +00 +3e +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 00bb +ENCODING 187 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +70 +38 +1c +0e +1c +38 +70 +00 +00 +ENDCHAR +STARTCHAR 00bc +ENCODING 188 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +32 +76 +34 +3c +3c +1a +36 +2e +6e +46 +00 +00 +ENDCHAR +STARTCHAR 00bd +ENCODING 189 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +32 +76 +34 +3c +3c +1c +3a +26 +6c +4e +00 +00 +ENDCHAR +STARTCHAR 00be +ENCODING 190 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +62 +36 +74 +3c +78 +1e +36 +6e +4e +06 +00 +00 +ENDCHAR +STARTCHAR 00bf +ENCODING 191 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +0c +0c +00 +0c +0c +0c +0c +0c +66 +66 +3c +ENDCHAR +STARTCHAR 00c0 +ENCODING 192 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +38 +1c +00 +3c +7e +66 +66 +66 +7e +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 00c1 +ENCODING 193 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +1c +38 +00 +3c +7e +66 +66 +66 +7e +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 00c2 +ENCODING 194 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +3c +00 +3c +7e +66 +66 +66 +7e +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 00c3 +ENCODING 195 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +14 +28 +00 +3c +7e +66 +66 +66 +7e +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 00c4 +ENCODING 196 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +24 +24 +00 +3c +7e +66 +66 +66 +7e +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 00c5 +ENCODING 197 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +18 +00 +3c +7e +66 +66 +66 +7e +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 00c6 +ENCODING 198 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +7e +d8 +d8 +d8 +dc +f8 +d8 +d8 +d8 +de +00 +00 +ENDCHAR +STARTCHAR 00c7 +ENCODING 199 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +3c +66 +66 +60 +60 +60 +60 +66 +66 +3c +18 +30 +ENDCHAR +STARTCHAR 00c8 +ENCODING 200 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +38 +1c +00 +7e +60 +60 +60 +7c +60 +60 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 00c9 +ENCODING 201 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +1c +38 +00 +7e +60 +60 +60 +7c +60 +60 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 00ca +ENCODING 202 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +3c +00 +7e +60 +60 +60 +7c +60 +60 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 00cb +ENCODING 203 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +24 +24 +00 +7e +60 +60 +60 +7c +60 +60 +60 +7e +00 +00 +ENDCHAR +STARTCHAR 00cc +ENCODING 204 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +38 +1c +00 +7e +18 +18 +18 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 00cd +ENCODING 205 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +1c +38 +00 +7e +18 +18 +18 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 00ce +ENCODING 206 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +3c +00 +7e +18 +18 +18 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 00cf +ENCODING 207 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +24 +24 +00 +7e +18 +18 +18 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 00d0 +ENCODING 208 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +78 +6c +66 +66 +fe +66 +66 +66 +6c +78 +00 +00 +ENDCHAR +STARTCHAR 00d1 +ENCODING 209 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +14 +28 +00 +66 +76 +76 +76 +6e +6e +6e +66 +66 +00 +00 +ENDCHAR +STARTCHAR 00d2 +ENCODING 210 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +38 +1c +00 +3c +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00d3 +ENCODING 211 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +1c +38 +00 +3c +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00d4 +ENCODING 212 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +3c +00 +3c +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00d5 +ENCODING 213 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +14 +28 +00 +3c +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00d6 +ENCODING 214 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +24 +24 +00 +3c +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00d7 +ENCODING 215 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +c6 +6c +38 +38 +6c +c6 +82 +00 +00 +ENDCHAR +STARTCHAR 00d8 +ENCODING 216 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +02 +02 +3c +6e +6e +6e +6e +76 +76 +76 +76 +3c +40 +40 +ENDCHAR +STARTCHAR 00d9 +ENCODING 217 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +38 +1c +00 +66 +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00da +ENCODING 218 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +1c +38 +00 +66 +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00db +ENCODING 219 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +18 +3c +00 +66 +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00dc +ENCODING 220 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +24 +24 +00 +66 +66 +66 +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00dd +ENCODING 221 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +1c +38 +00 +66 +66 +66 +3c +3c +3c +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 00de +ENCODING 222 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +60 +60 +7c +66 +66 +66 +66 +7c +60 +60 +00 +00 +ENDCHAR +STARTCHAR 00df +ENCODING 223 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +1c +36 +36 +36 +3c +36 +36 +36 +36 +7c +00 +00 +ENDCHAR +STARTCHAR 00e0 +ENCODING 224 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +30 +18 +0c +00 +3c +66 +1e +36 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00e1 +ENCODING 225 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +0c +18 +30 +00 +3c +66 +1e +36 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00e2 +ENCODING 226 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +3c +00 +3c +66 +1e +36 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00e3 +ENCODING 227 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +14 +28 +00 +3c +66 +1e +36 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00e4 +ENCODING 228 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +24 +24 +00 +3c +66 +1e +36 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00e5 +ENCODING 229 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +18 +3c +18 +00 +3c +66 +1e +36 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00e6 +ENCODING 230 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +7c +da +3a +5e +d8 +de +7c +00 +00 +ENDCHAR +STARTCHAR 00e7 +ENCODING 231 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +3c +66 +60 +60 +60 +66 +3c +18 +30 +ENDCHAR +STARTCHAR 00e8 +ENCODING 232 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +30 +18 +0c +00 +3c +66 +66 +7e +60 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00e9 +ENCODING 233 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +0c +18 +30 +00 +3c +66 +66 +7e +60 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00ea +ENCODING 234 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +3c +00 +3c +66 +66 +7e +60 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00eb +ENCODING 235 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +24 +24 +00 +3c +66 +66 +7e +60 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00ec +ENCODING 236 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +30 +18 +0c +00 +18 +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 00ed +ENCODING 237 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +0c +18 +30 +00 +18 +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 00ee +ENCODING 238 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +3c +00 +18 +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 00ef +ENCODING 239 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +24 +24 +00 +18 +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 00f0 +ENCODING 240 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +28 +10 +2c +0c +3c +6c +6c +6c +6c +6c +38 +00 +00 +ENDCHAR +STARTCHAR 00f1 +ENCODING 241 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +14 +28 +00 +7c +66 +66 +66 +66 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 00f2 +ENCODING 242 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +30 +18 +0c +00 +3c +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00f3 +ENCODING 243 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +0c +18 +30 +00 +3c +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00f4 +ENCODING 244 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +3c +00 +3c +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00f5 +ENCODING 245 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +14 +28 +00 +3c +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00f6 +ENCODING 246 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +24 +24 +00 +3c +66 +66 +66 +66 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 00f7 +ENCODING 247 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +00 +00 +00 +00 +30 +00 +fc +00 +30 +00 +00 +ENDCHAR +STARTCHAR 00f8 +ENCODING 248 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +00 +02 +04 +3c +6e +6e +76 +76 +66 +3c +40 +40 +ENDCHAR +STARTCHAR 00f9 +ENCODING 249 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +20 +30 +18 +08 +66 +66 +66 +66 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00fa +ENCODING 250 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +04 +0c +18 +10 +66 +66 +66 +66 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00fb +ENCODING 251 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +18 +3c +00 +66 +66 +66 +66 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00fc +ENCODING 252 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +24 +24 +00 +66 +66 +66 +66 +66 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 00fd +ENCODING 253 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +04 +0c +18 +10 +66 +66 +66 +3c +1c +1c +18 +78 +30 +ENDCHAR +STARTCHAR 00fe +ENCODING 254 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +60 +60 +60 +7c +66 +66 +66 +66 +66 +7c +60 +60 +ENDCHAR +STARTCHAR 00ff +ENCODING 255 +SWIDTH 480 0 +DWIDTH 7 0 +BBX 7 14 0 -2 +BITMAP +00 +00 +24 +24 +00 +66 +66 +66 +3c +1c +1c +18 +78 +30 +ENDCHAR +ENDFONT diff --git a/widget/milsko/milskosrc/resource/font/IBMPlexMono-Bold.ttf b/widget/milsko/milskosrc/resource/font/IBMPlexMono-Bold.ttf new file mode 100644 index 0000000000..42f52ea7f5 Binary files /dev/null and b/widget/milsko/milskosrc/resource/font/IBMPlexMono-Bold.ttf differ diff --git a/widget/milsko/milskosrc/resource/font/IBMPlexMono-Regular.ttf b/widget/milsko/milskosrc/resource/font/IBMPlexMono-Regular.ttf new file mode 100644 index 0000000000..9c5a098588 Binary files /dev/null and b/widget/milsko/milskosrc/resource/font/IBMPlexMono-Regular.ttf differ diff --git a/widget/milsko/milskosrc/resource/font/IBMPlexSerif.ttf b/widget/milsko/milskosrc/resource/font/IBMPlexSerif.ttf new file mode 100644 index 0000000000..f4f90a8070 Binary files /dev/null and b/widget/milsko/milskosrc/resource/font/IBMPlexSerif.ttf differ diff --git a/widget/milsko/milskosrc/resource/font/OpenSans-Bold.ttf b/widget/milsko/milskosrc/resource/font/OpenSans-Bold.ttf new file mode 100644 index 0000000000..e62bd81424 Binary files /dev/null and b/widget/milsko/milskosrc/resource/font/OpenSans-Bold.ttf differ diff --git a/widget/milsko/milskosrc/resource/font/OpenSans-Regular.ttf b/widget/milsko/milskosrc/resource/font/OpenSans-Regular.ttf new file mode 100644 index 0000000000..d9b361f976 Binary files /dev/null and b/widget/milsko/milskosrc/resource/font/OpenSans-Regular.ttf differ diff --git a/widget/milsko/milskosrc/resource/font/cursor.bdf b/widget/milsko/milskosrc/resource/font/cursor.bdf new file mode 100644 index 0000000000..d78af3f8b3 --- /dev/null +++ b/widget/milsko/milskosrc/resource/font/cursor.bdf @@ -0,0 +1,3289 @@ +STARTFONT 2.1 +COMMENT Created by bitmaptobdf +FONT cursor +SIZE 31 78 78 +FONTBOUNDINGBOX 31 31 -15 -16 +STARTPROPERTIES 3 +COPYRIGHT "These ""glyphs"" are unencumbered" +FONT_ASCENT 16 +FONT_DESCENT 17 +ENDPROPERTIES +CHARS 154 +STARTCHAR X_cursor +ENCODING -1 0 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -6 -8 +BITMAP +e01d +f03c +f87c +7cf8 +3ff0 +1fe0 +0fc0 +0fc0 +1fe0 +3ff0 +7cf8 +f87c +f03c +e01c +ENDCHAR +STARTCHAR X_cursor_mask +ENCODING -1 1 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +f00f +f81f +fc3f +fe7f +7ffe +3ffc +1ff8 +0ff0 +0ff0 +1ff8 +3ffc +7ffe +fe7f +fc3f +f81f +f00f +ENDCHAR +STARTCHAR arrow +ENCODING -1 2 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -13 -14 +BITMAP +000d +003c +00f8 +03f8 +0ff0 +3ff0 +03e0 +07e0 +0ec0 +1cc0 +3880 +7080 +e000 +4000 +ENDCHAR +STARTCHAR arrow_mask +ENCODING -1 3 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -15 +BITMAP +0007 +001f +007f +01fe +07fe +1ffc +3ffc +3ff8 +07f8 +0ff0 +1ff0 +3ee0 +7ce0 +f840 +7000 +2000 +ENDCHAR +STARTCHAR based_arrow_down +ENCODING -1 4 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 8 10 -3 -1 +BITMAP +ff +00 +ff +18 +18 +18 +18 +5a +3c +18 +ENDCHAR +STARTCHAR based_arrow_down_mask +ENCODING -1 5 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 12 -4 -2 +BITMAP +ffc4 +ffc0 +ffc0 +ffc0 +ffc0 +1e00 +1e00 +7f80 +7f80 +7f80 +3f00 +1e00 +ENDCHAR +STARTCHAR based_arrow_up +ENCODING -1 6 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 8 10 -3 -1 +BITMAP +18 +3c +5a +18 +18 +18 +18 +ff +00 +ff +ENDCHAR +STARTCHAR based_arrow_up_mask +ENCODING -1 7 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 12 -4 -2 +BITMAP +0c04 +1e00 +7f80 +7f80 +7f80 +1e00 +1e00 +ffc0 +ffc0 +ffc0 +ffc0 +ffc0 +ENDCHAR +STARTCHAR boat +ENCODING -1 8 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 8 -14 -5 +BITMAP +0100 +07c0 +8860 +ffff +0018 +0020 +0040 +ffc0 +ENDCHAR +STARTCHAR boat_mask +ENCODING -1 9 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 9 -14 -5 +BITMAP +0700 +0fc0 +9fe0 +ffff +ffff +ffff +fff8 +ffe0 +ffc0 +ENDCHAR +STARTCHAR bogosity +ENCODING -1 10 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 14 -6 -8 +BITMAP +e239 +2220 +2220 +2220 +fff8 +a228 +a228 +a228 +a228 +fff8 +2220 +2220 +2220 +e238 +ENDCHAR +STARTCHAR bogosity_mask +ENCODING -1 11 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -9 +BITMAP +fbbe +fbbe +fbbe +3bb8 +fffe +fffe +fffe +fbbe +fbbe +fffe +fffe +fffe +3bb8 +fbbe +fbbe +fbbe +ENDCHAR +STARTCHAR bottom_left_corner +ENCODING -1 12 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 0 -1 +BITMAP +c001 +c000 +c410 +c420 +c440 +c480 +c500 +c600 +c7f0 +c000 +c000 +c000 +fffc +fffc +ENDCHAR +STARTCHAR bottom_left_corner_mask +ENCODING -1 13 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -1 -2 +BITMAP +f000 +f000 +f70c +f71c +f738 +f770 +f7e0 +f7c0 +f7fc +f7fc +f7fc +f000 +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR bottom_right_corner +ENCODING -1 14 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -13 -1 +BITMAP +000d +000c +208c +108c +088c +048c +028c +018c +3f8c +000c +000c +000c +fffc +fffc +ENDCHAR +STARTCHAR bottom_right_corner_mask +ENCODING -1 15 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -2 +BITMAP +000f +000f +30ef +38ef +1cef +0eef +07ef +03ef +3fef +3fef +3fef +000f +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR bottom_side +ENCODING -1 16 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 14 -6 -1 +BITMAP +0201 +0200 +0200 +0200 +0200 +0200 +2220 +1240 +0a80 +0700 +0200 +0000 +fff8 +fff8 +ENDCHAR +STARTCHAR bottom_side_mask +ENCODING -1 17 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -2 +BITMAP +0380 +0380 +0380 +0380 +0380 +0380 +3398 +3bb8 +1ff0 +0fe0 +07c0 +0380 +fffe +fffe +fffe +fffe +ENDCHAR +STARTCHAR bottom_tee +ENCODING -1 18 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 10 -7 -1 +BITMAP +0301 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +fffc +fffc +ENDCHAR +STARTCHAR bottom_tee_mask +ENCODING -1 19 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 12 -8 -2 +BITMAP +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR box_spiral +ENCODING -1 20 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -8 -8 +BITMAP +ffff +8000 +bffe +a002 +affa +a80a +abea +aa2a +aaaa +abaa +a82a +afea +a00a +bffa +8002 +fffe +ENDCHAR +STARTCHAR box_spiral_mask +ENCODING -1 21 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR center_ptr +ENCODING -1 22 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 14 -4 -14 +BITMAP +0c09 +0c00 +1e00 +1e00 +3f00 +3f00 +7f80 +7f80 +ccc0 +8c40 +0c00 +0c00 +0c00 +0c00 +ENDCHAR +STARTCHAR center_ptr_mask +ENCODING -1 23 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -5 -15 +BITMAP +0f04 +0f00 +1f80 +1f80 +3fc0 +3fc0 +7fe0 +7fe0 +fff0 +fff0 +fff0 +ef70 +0f00 +0f00 +0f00 +0f00 +ENDCHAR +STARTCHAR circle +ENCODING -1 24 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -7 +BITMAP +0781 +1fe0 +3ff0 +7878 +7038 +e01c +e01c +e01c +e01c +7038 +7878 +3ff0 +1fe0 +0780 +ENDCHAR +STARTCHAR circle_mask +ENCODING -1 25 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +07e0 +1ff8 +3ffc +7ffe +7ffe +fc3f +f81f +f81f +f81f +f81f +fc3f +7ffe +7ffe +3ffc +1ff8 +07e0 +ENDCHAR +STARTCHAR clock +ENCODING -1 26 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 16 -6 -13 +BITMAP +3ff1 +6798 +c8cc +9324 +9e24 +8844 +c78c +7ff8 +5328 +5328 +5328 +57a8 +d32c +f03c +fffc +fffc +ENDCHAR +STARTCHAR clock_mask +ENCODING -1 27 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -6 -13 +BITMAP +7ff8 +ef9c +dbee +b7b6 +bff6 +9f66 +cfce +fffc +d7ac +d7ac +d7ac +dfec +d7ae +f33e +fffe +fffe +ENDCHAR +STARTCHAR coffee_mug +ENCODING -1 28 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -7 +BITMAP +1ff1 +2008 +6006 +501a +4fe2 +c002 +c002 +4002 +4002 +591a +6aaa +ebaa +da9a +4002 +4002 +3ffc +ENDCHAR +STARTCHAR coffee_mug_mask +ENCODING -1 29 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -7 +BITMAP +1ff0 +3ff8 +7fff +7fff +ffff +ffff +ffff +ffff +7fff +7fff +ffff +ffff +ffff +ffff +7fff +3ffc +ENDCHAR +STARTCHAR cross +ENCODING -1 30 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -7 -8 +BITMAP +0280 +0280 +0280 +0280 +0280 +0280 +feff +0000 +feff +0280 +0280 +0280 +0280 +0280 +0280 +ENDCHAR +STARTCHAR cross_mask +ENCODING -1 31 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +07c0 +07c0 +07c0 +07c0 +07c0 +ffff +ffff +ffff +ffff +ffff +07c0 +07c0 +07c0 +07c0 +07c0 +07c0 +ENDCHAR +STARTCHAR cross_reverse +ENCODING -1 32 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -7 -8 +BITMAP +4284 +a28a +5294 +2aa8 +16d0 +0aa0 +fd7f +0280 +fd7f +0aa0 +16d0 +2aa8 +5294 +a28a +4284 +ENDCHAR +STARTCHAR cross_reverse_mask +ENCODING -1 33 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -7 -8 +BITMAP +66cc +b6db +def6 +6eec +36d8 +fabf +fc7f +0100 +fc7f +fabf +36d8 +6eec +def6 +b6db +66cc +ENDCHAR +STARTCHAR crosshair +ENCODING -1 34 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -7 -8 +BITMAP +0100 +0100 +0100 +0100 +0100 +0100 +0100 +feff +0100 +0100 +0100 +0100 +0100 +0100 +0100 +ENDCHAR +STARTCHAR crosshair_mask +ENCODING -1 35 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +0380 +0380 +0380 +0380 +0380 +0380 +ffff +ffff +ffff +0380 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR diamond_cross +ENCODING -1 36 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 15 -7 -8 +BITMAP +0281 +06c0 +0aa0 +1290 +2288 +4284 +fefe +0000 +fefe +4284 +2288 +1290 +0aa0 +06c0 +0280 +ENDCHAR +STARTCHAR diamond_cross_mask +ENCODING -1 37 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +07c0 +0fe0 +1ff0 +3bb8 +739c +e38e +ffff +feff +ffff +e38e +739c +3bb8 +1ff0 +0fe0 +07c0 +0380 +ENDCHAR +STARTCHAR dot +ENCODING -1 38 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 -5 -5 +BITMAP +1e09 +7f80 +7f80 +ffc0 +ffc0 +ffc0 +ffc0 +7f80 +7f80 +1e00 +ENDCHAR +STARTCHAR dot_mask +ENCODING -1 39 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -6 -6 +BITMAP +1f84 +7fe0 +7fe0 +fff0 +fff0 +fff0 +fff0 +fff0 +fff0 +7fe0 +7fe0 +1f80 +ENDCHAR +STARTCHAR dotbox +ENCODING -1 40 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -6 -7 +BITMAP +fff9 +8010 +8010 +8010 +8010 +8610 +8610 +8010 +8010 +8010 +8010 +fff0 +ENDCHAR +STARTCHAR dotbox_mask +ENCODING -1 41 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -8 +BITMAP +fffc +fffc +fffc +e01c +e01c +e79c +e79c +e79c +e79c +e01c +e01c +fffc +fffc +fffc +ENDCHAR +STARTCHAR double_arrow +ENCODING -1 42 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 14 -5 -7 +BITMAP +0c09 +1e00 +3f00 +6d80 +ccc0 +0c00 +0c00 +0c00 +0c00 +ccc0 +6d80 +3f00 +1e00 +0c00 +ENDCHAR +STARTCHAR double_arrow_mask +ENCODING -1 43 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -6 -8 +BITMAP +0f04 +1f80 +3fc0 +7fe0 +fff0 +fff0 +fff0 +0f00 +0f00 +fff0 +fff0 +fff0 +7fe0 +3fc0 +1f80 +0f00 +ENDCHAR +STARTCHAR draft_large +ENCODING -1 44 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 15 -14 -15 +BITMAP +0003 +000c +003c +00f8 +03f8 +0ff0 +3ff0 +01e0 +02e0 +04c0 +08c0 +1080 +2080 +4000 +8000 +ENDCHAR +STARTCHAR draft_large_mask +ENCODING -1 45 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -14 -16 +BITMAP +0006 +001e +007e +01fc +07f8 +1ff8 +7ff0 +7ff0 +07e0 +0fe0 +1dc0 +39c0 +7180 +e180 +c000 +8000 +ENDCHAR +STARTCHAR draft_small +ENCODING -1 46 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 15 -14 -15 +BITMAP +0002 +000c +003c +00f8 +03f8 +0070 +00b0 +0120 +0220 +0400 +0800 +1000 +2000 +4000 +8000 +ENDCHAR +STARTCHAR draft_small_mask +ENCODING -1 47 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 15 -14 -15 +BITMAP +0006 +001e +007c +01fc +07f8 +07f8 +01f0 +03f0 +0760 +0e40 +1c00 +3800 +7000 +e000 +c000 +ENDCHAR +STARTCHAR draped_box +ENCODING -1 48 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -6 -7 +BITMAP +fff8 +8910 +9990 +b0d0 +e070 +8610 +8610 +e070 +b0d0 +9990 +8910 +fff0 +ENDCHAR +STARTCHAR draped_box_mask +ENCODING -1 49 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -8 +BITMAP +fffc +fffc +cfcc +dfec +fcfc +fb7c +f7bc +f7bc +fb7c +fcfc +dfec +cfcc +fffc +fffc +ENDCHAR +STARTCHAR exchange +ENCODING -1 50 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -6 -8 +BITMAP +8fc0 +dfe0 +f830 +9010 +9800 +fc00 +0000 +0000 +00fc +0064 +2024 +307c +1fec +0fc4 +ENDCHAR +STARTCHAR exchange_mask +ENCODING -1 51 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +c7e0 +eff0 +fff8 +fffc +fc1c +ff0c +ff00 +ff00 +00ff +00ff +307f +383f +3fff +1fff +0ff7 +07e3 +ENDCHAR +STARTCHAR fleur +ENCODING -1 52 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -7 +BITMAP +0300 +0780 +0fc0 +0300 +2310 +6318 +fffc +fffc +6318 +2310 +0300 +0fc0 +0780 +0300 +ENDCHAR +STARTCHAR fleur_mask +ENCODING -1 53 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +03c0 +03e0 +07e0 +0ff0 +17e8 +3bdc +ffff +ffff +ffff +ffff +3bdc +17e8 +0ff0 +07e0 +03c0 +03c0 +ENDCHAR +STARTCHAR gobbler +ENCODING -1 54 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -14 -13 +BITMAP +0078 +0070 +8033 +9fb0 +fff0 +fe30 +fc30 +6038 +00f0 +1fe0 +0800 +0800 +0800 +0800 +1e00 +ENDCHAR +STARTCHAR gobbler_mask +ENCODING -1 55 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -13 +BITMAP +00fc +00fc +c0ff +ffff +ffff +fffc +fffc +fffc +fffc +fffc +7ff8 +1ff0 +1c00 +1c00 +3f00 +3f00 +ENDCHAR +STARTCHAR gumby +ENCODING -1 56 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -2 -16 +BITMAP +3f00 +1080 +c840 +eaa0 +c820 +cba0 +f83c +383f +0827 +0827 +092f +0927 +0920 +1110 +2108 +3ef8 +ENDCHAR +STARTCHAR gumby_mask +ENCODING -1 57 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -2 -16 +BITMAP +3f00 +df80 +efc0 +ffe0 +efe0 +effc +fffe +ffff +3fef +0fef +0fff +0fef +0fe7 +1ff0 +3ff8 +3ef8 +ENDCHAR +STARTCHAR hand1 +ENCODING -1 58 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 16 -12 -16 +BITMAP +0018 +0078 +01e0 +03c0 +0780 +0fc0 +1fe0 +5fc0 +ffe0 +bfe0 +0fc0 +0f80 +9400 +c400 +6800 +3000 +ENDCHAR +STARTCHAR hand1_mask +ENCODING -1 59 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 16 -12 -16 +BITMAP +003b +00f8 +03f0 +07e0 +0fc0 +1fe0 +7ff0 +fff0 +fff0 +fff0 +ffe0 +ffc0 +ff80 +fe00 +fc00 +7800 +ENDCHAR +STARTCHAR hand2 +ENCODING -1 60 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 14 0 -14 +BITMAP +7f80 +8040 +7e20 +1010 +0e10 +1010 +0e28 +1044 +0c82 +0304 +0248 +0110 +00a0 +0040 +ENDCHAR +STARTCHAR hand2_mask +ENCODING -1 61 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 0 -15 +BITMAP +7f80 +ffc0 +ffe0 +fff0 +7ff8 +1ff8 +3ff8 +1ffc +3ffe +1fff +0ffe +07fc +03f8 +01f0 +00e0 +0040 +ENDCHAR +STARTCHAR heart +ENCODING -1 62 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 14 -6 -6 +BITMAP +3ef8 +638c +c106 +8002 +8002 +8002 +8002 +c006 +600c +3018 +1830 +0c60 +06c0 +0380 +ENDCHAR +STARTCHAR heart_mask +ENCODING -1 63 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 14 -6 -6 +BITMAP +3ef9 +7ffc +e38e +c106 +c006 +c006 +c286 +e10e +701c +3838 +1c70 +0fe0 +07c0 +0380 +ENDCHAR +STARTCHAR icon +ENCODING -1 64 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +ffff +d555 +aaab +d555 +a00b +d005 +a00b +d005 +a00b +d005 +a00b +d005 +aaab +d555 +aaab +ffff +ENDCHAR +STARTCHAR icon_mask +ENCODING -1 65 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ENDCHAR +STARTCHAR iron_cross +ENCODING -1 66 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -8 +BITMAP +7ff8 +3ff0 +9fe4 +cfcc +e79c +f33c +fffc +fffc +f33c +e79c +cfcc +9fe4 +3ff0 +7ff8 +ENDCHAR +STARTCHAR iron_cross_mask +ENCODING -1 67 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -9 +BITMAP +3ffc +7ffe +7ffe +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +ffff +7ffe +7ffe +3ffc +ENDCHAR +STARTCHAR left_ptr +ENCODING -1 68 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 8 14 0 -14 +BITMAP +80 +c0 +e0 +f0 +f8 +fc +fe +ff +f8 +d8 +8c +0c +06 +06 +ENDCHAR +STARTCHAR left_ptr_mask +ENCODING -1 69 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 16 -1 -15 +BITMAP +c003 +e000 +f000 +f800 +fc00 +fe00 +ff00 +ff80 +ffc0 +ffc0 +fe00 +ef00 +cf00 +0780 +0780 +0300 +ENDCHAR +STARTCHAR left_side +ENCODING -1 70 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 13 0 -7 +BITMAP +c000 +c000 +c100 +c200 +c400 +c800 +dffc +c800 +c400 +c200 +c100 +c000 +c000 +ENDCHAR +STARTCHAR left_side_mask +ENCODING -1 71 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -1 -8 +BITMAP +f000 +f000 +f0c0 +f1c0 +f380 +f700 +ffff +ffff +ffff +f700 +f380 +f1c0 +f0c0 +f000 +f000 +ENDCHAR +STARTCHAR left_tee +ENCODING -1 72 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 14 0 -7 +BITMAP +c008 +c000 +c000 +c000 +c000 +c000 +ffc0 +ffc0 +c000 +c000 +c000 +c000 +c000 +c000 +ENDCHAR +STARTCHAR left_tee_mask +ENCODING -1 73 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -1 -8 +BITMAP +f003 +f000 +f000 +f000 +f000 +f000 +fff0 +fff0 +fff0 +fff0 +f000 +f000 +f000 +f000 +f000 +f000 +ENDCHAR +STARTCHAR leftbutton +ENCODING -1 74 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +8003 +7ffd +7ffd +4445 +4555 +4555 +4555 +4555 +4445 +7ffd +7ffd +7ffd +7ffd +7ffd +7ffd +8003 +ENDCHAR +STARTCHAR leftbutton_mask +ENCODING -1 75 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -8 -8 +BITMAP +7ffd +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +7ffc +ENDCHAR +STARTCHAR ll_angle +ENCODING -1 76 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 0 -1 +BITMAP +c008 +c000 +c000 +c000 +c000 +c000 +c000 +c000 +ffc0 +ffc0 +ENDCHAR +STARTCHAR ll_angle_mask +ENCODING -1 77 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -1 -2 +BITMAP +f003 +f000 +f000 +f000 +f000 +f000 +f000 +f000 +fff0 +fff0 +fff0 +fff0 +ENDCHAR +STARTCHAR lr_angle +ENCODING -1 78 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 -9 -1 +BITMAP +00c8 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +ffc0 +ffc0 +ENDCHAR +STARTCHAR lr_angle_mask +ENCODING -1 79 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -10 -2 +BITMAP +00f3 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +fff0 +fff0 +fff0 +fff0 +ENDCHAR +STARTCHAR man +ENCODING -1 80 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -11 +BITMAP +0380 +1ef0 +0280 +8100 +4387 +244b +1d70 +0540 +0440 +0280 +0440 +0920 +1290 +1450 +783c +f83f +ENDCHAR +STARTCHAR man_mask +ENCODING -1 81 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -11 +BITMAP +1fe0 +3ff0 +3ff8 +c382 +e7c7 +7fff +3ffb +1ff0 +07e0 +07c0 +0fe0 +1ff0 +3ff8 +7efc +fc7f +fc7f +ENDCHAR +STARTCHAR middlebutton +ENCODING -1 82 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +8003 +7ffd +7ffd +4445 +5455 +5455 +5455 +5455 +4445 +7ffd +7ffd +7ffd +7ffd +7ffd +7ffd +8003 +ENDCHAR +STARTCHAR middlebutton_mask +ENCODING -1 83 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -8 -8 +BITMAP +7ffd +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +7ffc +ENDCHAR +STARTCHAR mouse +ENCODING -1 84 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 14 -4 -13 +BITMAP +0700 +0c00 +0600 +0300 +7ff8 +8004 +b336 +b336 +b336 +8006 +8006 +601c +1860 +0780 +ENDCHAR +STARTCHAR mouse_mask +ENCODING -1 85 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -4 -15 +BITMAP +0f80 +1e00 +0f00 +0700 +7ff8 +fffc +ffff +ffff +ffff +ffff +ffff +ffff +3ff7 +1fe0 +0fc0 +0780 +ENDCHAR +STARTCHAR pencil +ENCODING -1 86 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 11 16 -10 -1 +BITMAP +7008 +8800 +8c00 +4a00 +7a00 +2100 +1100 +1080 +0880 +0c40 +0440 +0220 +01e0 +00e0 +0060 +0020 +ENDCHAR +STARTCHAR pencil_mask +ENCODING -1 87 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 16 -11 -1 +BITMAP +fc03 +fe00 +ff00 +7f00 +3f80 +3f80 +1fc0 +0fc0 +0fe0 +07e0 +07f0 +03f8 +01f8 +00f8 +0078 +0038 +ENDCHAR +STARTCHAR pirate +ENCODING -1 88 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -4 +BITMAP +0780 +0fc0 +1fe0 +3330 +3330 +1fe0 +0fc0 +0780 +8784 +8786 +4308 +3870 +0780 +1fe2 +f03e +8004 +ENDCHAR +STARTCHAR pirate_mask +ENCODING -1 89 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -4 +BITMAP +0fc0 +1fe0 +3ff0 +7ff8 +7ff8 +3ff0 +1fe0 +8fc1 +8fc7 +cfcf +f79c +7878 +0780 +7fe3 +ffff +f03e +ENDCHAR +STARTCHAR plus +ENCODING -1 90 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 -4 -5 +BITMAP +0c08 +0c00 +0c00 +0c00 +ffc0 +ffc0 +0c00 +0c00 +0c00 +0c00 +ENDCHAR +STARTCHAR plus_mask +ENCODING -1 91 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -5 -6 +BITMAP +0f03 +0f00 +0f00 +0f00 +fff0 +fff0 +fff0 +fff0 +0f00 +0f00 +0f00 +0f00 +ENDCHAR +STARTCHAR question_arrow +ENCODING -1 92 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 15 -4 -8 +BITMAP +3e08 +7f00 +e380 +c180 +e180 +6380 +0700 +1e00 +1c00 +1400 +1400 +7700 +3600 +1c00 +0800 +ENDCHAR +STARTCHAR question_arrow_mask +ENCODING -1 93 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 11 16 -5 -8 +BITMAP +1f03 +3f80 +7fc0 +ffe0 +f1e0 +f9e0 +7be0 +3fc0 +1f80 +1f00 +1f00 +3f80 +7fc0 +3f80 +1f00 +0e00 +ENDCHAR +STARTCHAR right_ptr +ENCODING -1 94 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 8 14 -7 -14 +BITMAP +01 +03 +07 +0f +1f +3f +7f +ff +1f +1b +31 +30 +60 +60 +ENDCHAR +STARTCHAR right_ptr_mask +ENCODING -1 95 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 16 -8 -15 +BITMAP +00c3 +01c0 +03c0 +07c0 +0fc0 +1fc0 +3fc0 +7fc0 +ffc0 +ffc0 +1fc0 +3dc0 +3cc0 +7800 +7800 +3000 +ENDCHAR +STARTCHAR right_side +ENCODING -1 96 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 13 -13 -7 +BITMAP +000c +000c +020c +010c +008c +004c +ffec +004c +008c +010c +020c +000c +000c +ENDCHAR +STARTCHAR right_side_mask +ENCODING -1 97 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 15 -14 -8 +BITMAP +000f +000f +030f +038f +01cf +00ef +ffff +ffff +ffff +00ef +01cf +038f +030f +000f +000f +ENDCHAR +STARTCHAR right_tee +ENCODING -1 98 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 14 -9 -7 +BITMAP +00c8 +00c0 +00c0 +00c0 +00c0 +00c0 +ffc0 +ffc0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +ENDCHAR +STARTCHAR right_tee_mask +ENCODING -1 99 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -10 -8 +BITMAP +00f3 +00f0 +00f0 +00f0 +00f0 +00f0 +fff0 +fff0 +fff0 +fff0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +ENDCHAR +STARTCHAR rightbutton +ENCODING -1 100 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +8003 +7ffd +7ffd +4445 +5545 +5545 +5545 +5545 +4445 +7ffd +7ffd +7ffd +7ffd +7ffd +7ffd +8003 +ENDCHAR +STARTCHAR rightbutton_mask +ENCODING -1 101 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -8 -8 +BITMAP +7ffd +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +fffe +7ffc +ENDCHAR +STARTCHAR rtl_logo +ENCODING -1 102 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -6 -8 +BITMAP +fffc +8044 +8044 +8044 +ffc4 +8844 +8844 +8844 +8844 +8ffc +8804 +8804 +8804 +fffc +ENDCHAR +STARTCHAR rtl_logo_mask +ENCODING -1 103 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +ffff +ffff +ffff +e077 +fff7 +fff7 +fff7 +ee77 +ee77 +efff +efff +efff +ee07 +ffff +ffff +ffff +ENDCHAR +STARTCHAR sailboat +ENCODING -1 104 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 13 -6 -14 +BITMAP +0108 +0100 +0580 +0580 +0d80 +0dc0 +1dc0 +1dc0 +3de0 +3de0 +7de0 +7df0 +f8e0 +ENDCHAR +STARTCHAR sailboat_mask +ENCODING -1 105 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -16 +BITMAP +00c0 +00e0 +01e0 +03f0 +03f0 +07f0 +07f8 +0ff8 +0ff8 +1ffc +1ffc +3ffc +3fff +7fff +fff8 +7fe0 +ENDCHAR +STARTCHAR sb_down_arrow +ENCODING -1 106 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 7 15 -3 0 +BITMAP +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +fe +7c +38 +10 +ENDCHAR +STARTCHAR sb_down_arrow_mask +ENCODING -1 107 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 16 -4 -1 +BITMAP +3e03 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +ff80 +ff80 +7f00 +3e00 +1c00 +0800 +ENDCHAR +STARTCHAR sb_h_double_arrow +ENCODING -1 108 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 7 -7 -4 +BITMAP +1010 +3018 +7ffc +f01e +7ffc +3018 +1010 +ENDCHAR +STARTCHAR sb_h_double_arrow_mask +ENCODING -1 109 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 9 -7 -5 +BITMAP +1831 +3838 +7ffc +fffe +fffe +fffe +7ffc +3838 +1830 +ENDCHAR +STARTCHAR sb_left_arrow +ENCODING -1 110 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 7 1 -4 +BITMAP +1000 +3000 +7ffe +f000 +7ffe +3000 +1000 +ENDCHAR +STARTCHAR sb_left_arrow_mask +ENCODING -1 111 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 9 0 -5 +BITMAP +0c00 +1c00 +3fff +7fff +ffff +7fff +3fff +1c00 +0c00 +ENDCHAR +STARTCHAR sb_right_arrow +ENCODING -1 112 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 7 -15 -4 +BITMAP +0010 +0018 +fffc +001e +fffc +0018 +0010 +ENDCHAR +STARTCHAR sb_right_arrow_mask +ENCODING -1 113 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 9 -15 -5 +BITMAP +0030 +0038 +fffc +fffe +ffff +fffe +fffc +0038 +0030 +ENDCHAR +STARTCHAR sb_up_arrow +ENCODING -1 114 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 7 15 -3 -16 +BITMAP +10 +39 +7c +fe +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +ENDCHAR +STARTCHAR sb_up_arrow_mask +ENCODING -1 115 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 16 -4 -16 +BITMAP +0803 +1c00 +3e00 +7f00 +ff80 +ff80 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +3e00 +ENDCHAR +STARTCHAR sb_v_double_arrow +ENCODING -1 116 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 7 15 -3 -8 +BITMAP +10 +39 +7c +fe +28 +28 +28 +28 +28 +28 +28 +fe +7c +38 +10 +ENDCHAR +STARTCHAR sb_v_double_arrow_mask +ENCODING -1 117 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 15 -4 -8 +BITMAP +1c03 +3e00 +7f00 +ff80 +ff80 +3e00 +3e00 +3e00 +3e00 +3e00 +ff80 +ff80 +7f00 +3e00 +1c00 +ENDCHAR +STARTCHAR shuttle +ENCODING -1 118 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -10 -16 +BITMAP +0021 +0070 +00f8 +01de +05de +09de +11de +11de +11de +11de +31de +71de +fdde +1888 +0078 +0030 +ENDCHAR +STARTCHAR shuttle_mask +ENCODING -1 119 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -11 -16 +BITMAP +0038 +007c +00fe +00ff +06ff +0eff +1eff +1eff +1eff +1eff +3eff +7eff +feff +7efe +0c7e +003c +ENDCHAR +STARTCHAR sizing +ENCODING -1 120 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -7 +BITMAP +ff03 +8000 +8000 +8000 +8fc0 +8840 +8844 +8844 +0844 +0fc4 +0024 +0014 +000c +03fc +ENDCHAR +STARTCHAR sizing_mask +ENCODING -1 121 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -8 +BITMAP +ffc0 +ffc0 +ffc0 +e000 +eff0 +eff0 +eff7 +ee77 +ee77 +eff7 +0ff7 +0fff +001f +03ff +03ff +03ff +ENDCHAR +STARTCHAR spider +ENCODING -1 122 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -6 -9 +BITMAP +2010 +1020 +1020 +0840 +0840 +8787 +6798 +1fe0 +1fe0 +6798 +8787 +0840 +0840 +1020 +1020 +2010 +ENDCHAR +STARTCHAR spider_mask +ENCODING -1 123 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -6 -9 +BITMAP +6018 +3030 +1020 +1860 +8fc1 +cfcf +6fdc +3ff0 +3fe0 +6ff8 +cfcf +8fc1 +1840 +1860 +3030 +6018 +ENDCHAR +STARTCHAR spraycan +ENCODING -1 124 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 11 16 -9 -14 +BITMAP +0067 +0100 +3460 +7900 +6860 +fc00 +8400 +e400 +a400 +e400 +a400 +e400 +e400 +8400 +8400 +fc00 +ENDCHAR +STARTCHAR spraycan_mask +ENCODING -1 125 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 16 -10 -14 +BITMAP +0032 +18b0 +3eb0 +3eb0 +7eb0 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ff00 +ENDCHAR +STARTCHAR star +ENCODING -1 126 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -9 +BITMAP +0101 +0280 +0280 +0280 +0440 +0440 +0440 +3938 +c006 +3838 +0920 +1290 +2448 +2828 +3018 +2008 +ENDCHAR +STARTCHAR star_mask +ENCODING -1 127 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -7 -9 +BITMAP +0100 +0380 +0380 +06c0 +06c0 +0c60 +1c78 +f93e +c007 +f83e +3938 +3398 +66cc +6c6c +783c +701c +ENDCHAR +STARTCHAR target +ENCODING -1 128 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 13 -7 -7 +BITMAP +0381 +0fe0 +1c70 +3018 +600c +c106 +c286 +c106 +600c +3018 +1c70 +0fe0 +0380 +ENDCHAR +STARTCHAR target_mask +ENCODING -1 129 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 14 -7 -7 +BITMAP +07c0 +0fe0 +1ff0 +3c78 +701c +e10e +c387 +c6c7 +c387 +e10e +701c +3c78 +1ff0 +07c0 +ENDCHAR +STARTCHAR tcross +ENCODING -1 130 +SWIDTH 516 0 +DWIDTH 16 0 +BBX 13 13 -6 -7 +BITMAP +0207 +0200 +0200 +0200 +0200 +0200 +fff8 +0200 +0200 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR tcross_mask +ENCODING -1 131 +SWIDTH 516 0 +DWIDTH 16 0 +BBX 15 15 -7 -8 +BITMAP +0380 +0380 +0380 +0380 +0380 +0380 +fffe +fffe +fffe +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR top_left_arrow +ENCODING -1 132 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 0 -14 +BITMAP +c003 +f000 +7c00 +7f00 +3fc0 +3ff0 +1f00 +1f00 +0c80 +0c40 +0420 +0410 +0008 +0004 +ENDCHAR +STARTCHAR top_left_arrow_mask +ENCODING -1 133 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -1 -15 +BITMAP +e000 +f800 +fe00 +7f80 +7fe0 +3ffc +3ffc +1ffc +1fc0 +0fe0 +0f70 +0738 +071c +070e +0007 +0003 +ENDCHAR +STARTCHAR top_left_corner +ENCODING -1 134 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 0 -14 +BITMAP +ffff +fffc +c000 +c000 +c000 +c7f0 +c600 +c500 +c480 +c440 +c420 +c410 +c000 +c000 +ENDCHAR +STARTCHAR top_left_corner_mask +ENCODING -1 135 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -1 -15 +BITMAP +ffff +ffff +ffff +ffff +f000 +f7fc +f7fc +f7fc +f7c0 +f7e0 +f770 +f738 +f71c +f70c +f000 +f000 +ENDCHAR +STARTCHAR top_right_corner +ENCODING -1 136 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -13 -14 +BITMAP +ffff +fffc +000c +000c +000c +3f8c +018c +028c +048c +088c +108c +208c +000c +000c +ENDCHAR +STARTCHAR top_right_corner_mask +ENCODING -1 137 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -14 -15 +BITMAP +ffff +ffff +ffff +ffff +000f +3fef +3fef +3fef +03ef +07ef +0eef +1cef +38ef +30ef +000f +000f +ENDCHAR +STARTCHAR top_side +ENCODING -1 138 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 13 14 -6 -14 +BITMAP +ffff +fff8 +0000 +0200 +0700 +0a80 +1240 +2220 +0200 +0200 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR top_side_mask +ENCODING -1 139 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 15 16 -7 -15 +BITMAP +fffe +fffe +fffe +fffe +0380 +07c0 +0fe0 +1ff0 +3bb8 +3398 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR top_tee +ENCODING -1 140 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 10 -7 -10 +BITMAP +ffff +fffc +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR top_tee_mask +ENCODING -1 141 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 12 -8 -11 +BITMAP +ffff +ffff +ffff +ffff +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +03c0 +ENDCHAR +STARTCHAR trek +ENCODING -1 142 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 7 16 -3 -16 +BITMAP +11 +01 +38 +7c +fe +ee +fe +7c +38 +10 +ba +d6 +92 +82 +82 +82 +ENDCHAR +STARTCHAR trek_mask +ENCODING -1 143 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 9 16 -4 -16 +BITMAP +1c02 +1c00 +3e00 +7f00 +ff80 +ff80 +ff80 +7f00 +3e00 +5d00 +ff80 +ff80 +ff80 +eb80 +eb80 +e380 +ENDCHAR +STARTCHAR ul_angle +ENCODING -1 144 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 0 -10 +BITMAP +ffc7 +ffc0 +c000 +c000 +c000 +c000 +c000 +c000 +c000 +c000 +ENDCHAR +STARTCHAR ul_angle_mask +ENCODING -1 145 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -1 -11 +BITMAP +fff2 +fff0 +fff0 +fff0 +f000 +f000 +f000 +f000 +f000 +f000 +f000 +f000 +ENDCHAR +STARTCHAR umbrella +ENCODING -1 146 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 14 14 -7 -12 +BITMAP +1123 +0450 +934c +4f90 +3260 +c218 +0200 +0200 +0200 +0200 +0200 +0280 +0280 +0100 +ENDCHAR +STARTCHAR umbrella_mask +ENCODING -1 147 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -8 -14 +BITMAP +176e +dffb +bffc +7fff +fffc +ffff +f39e +0380 +0380 +0380 +0380 +03e0 +03e0 +03e0 +03e0 +01c0 +ENDCHAR +STARTCHAR ur_angle +ENCODING -1 148 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 10 10 -9 -10 +BITMAP +ffc7 +ffc0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +00c0 +ENDCHAR +STARTCHAR ur_angle_mask +ENCODING -1 149 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 12 12 -10 -11 +BITMAP +fff2 +fff0 +fff0 +fff0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +00f0 +ENDCHAR +STARTCHAR watch +ENCODING -1 150 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -15 -7 +BITMAP +1fe0 +1fe0 +1fe0 +3ff0 +6118 +c10c +8107 +8387 +8387 +8407 +c80c +6018 +3ff0 +1fe0 +1fe0 +1fe0 +ENDCHAR +STARTCHAR watch_mask +ENCODING -1 151 +SWIDTH 548 0 +DWIDTH 17 0 +BBX 16 16 -15 -7 +BITMAP +3ff0 +3ff0 +3ff0 +7ff8 +fffc +ffff +ffff +ffff +ffff +ffff +ffff +fffc +7ff8 +3ff0 +3ff0 +3ff0 +ENDCHAR +STARTCHAR xterm +ENCODING -1 152 +SWIDTH 322 0 +DWIDTH 10 0 +BBX 7 14 -3 -7 +BITMAP +ef +39 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +38 +ee +ENDCHAR +STARTCHAR xterm_mask +ENCODING -1 153 +SWIDTH 322 0 +DWIDTH 10 0 +BBX 9 16 -4 -8 +BITMAP +f782 +ff80 +ff80 +3e00 +1c00 +1c00 +1c00 +1c00 +1c00 +1c00 +1c00 +1c00 +3e00 +ff80 +ff80 +f780 +ENDCHAR +ENDFONT diff --git a/widget/milsko/milskosrc/resource/harvard.txt b/widget/milsko/milskosrc/resource/harvard.txt new file mode 100644 index 0000000000..2f756d8ae6 --- /dev/null +++ b/widget/milsko/milskosrc/resource/harvard.txt @@ -0,0 +1,792 @@ +H1 Harvard Sentences + 1. The birch canoe slid on the smooth planks. + 2. Glue the sheet to the dark blue background. + 3. It's easy to tell the depth of a well. + 4. These days a chicken leg is a rare dish. + 5. Rice is often served in round bowls. + 6. The juice of lemons makes fine punch. + 7. The box was thrown beside the parked truck. + 8. The hogs were fed chopped corn and garbage. + 9. Four hours of steady work faced us. +10. A large size in stockings is hard to sell. +H2 Harvard Sentences + 1. The boy was there when the sun rose. + 2. A rod is used to catch pink salmon. + 3. The source of the huge river is the clear spring. + 4. Kick the ball straight and follow through. + 5. Help the woman get back to her feet. + 6. A pot of tea helps to pass the evening. + 7. Smoky fires lack flame and heat. + 8. The soft cushion broke the man's fall. + 9. The salt breeze came across from the sea. +10. The girl at the booth sold fifty bonds. +H3 Harvard Sentences + 1. The small pup gnawed a hole in the sock. + 2. The fish twisted and turned on the bent hook. + 3. Press the pants and sew a button on the vest. + 4. The swan dive was far short of perfect. + 5. The beauty of the view stunned the young boy. + 6. Two blue fish swam in the tank. + 7. Her purse was full of useless trash. + 8. The colt reared and threw the tall rider. + 9. It snowed, rained, and hailed the same morning. +10. Read verse out loud for pleasure. +H4 Harvard Sentences + 1. Hoist the load to your left shoulder. + 2. Take the winding path to reach the lake. + 3. Note closely the size of the gas tank. + 4. Wipe the grease off his dirty face. + 5. Mend the coat before you go out. + 6. The wrist was badly strained and hung limp. + 7. The stray cat gave birth to kittens. + 8. The young girl gave no clear response. + 9. The meal was cooked before the bell rang. +10. What joy there is in living. +H5 Harvard Sentences + 1. A king ruled the state in the early days. + 2. The ship was torn apart on the sharp reef. + 3. Sickness kept him home the third week. + 4. The wide road shimmered in the hot sun. + 5. The lazy cow lay in the cool grass. + 6. Lift the square stone over the fence. + 7. The rope will bind the seven books at once. + 8. Hop over the fence and plunge in. + 9. The friendly gang left the drug store. +10. Mesh wire keeps chicks inside. +H6 Harvard Sentences + 1. The frosty air passed through the coat. + 2. The crooked maze failed to fool the mouse. + 3. Adding fast leads to wrong sums. + 4. The show was a flop from the very start. + 5. A saw is a tool used for making boards. + 6. The wagon moved on well oiled wheels. + 7. March the soldiers past the next hill. + 8. A cup of sugar makes sweet fudge. + 9. Place a rosebush near the porch steps. +10. Both lost their lives in the raging storm. +H7 Harvard Sentences + 1. We talked of the side show in the circus. + 2. Use a pencil to write the first draft. + 3. He ran half way to the hardware store. + 4. The clock struck to mark the third period. + 5. A small creek cut across the field. + 6. Cars and busses stalled in snow drifts. + 7. The set of china hit the floor with a crash. + 8. This is a grand season for hikes on the road. + 9. The dune rose from the edge of the water. +10. Those words were the cue for the actor to leave. +H8 Harvard Sentences + 1. A yacht slid around the point into the bay. + 2. The two met while playing on the sand. + 3. The ink stain dried on the finished page. + 4. The walled town was seized without a fight. + 5. The lease ran out in sixteen weeks. + 6. A tame squirrel makes a nice pet. + 7. The horn of the car woke the sleeping cop. + 8. The heart beat strongly and with firm strokes. + 9. The pearl was worn in a thin silver ring. +10. The fruit peel was cut in thick slices. +H9 Harvard Sentences + 1. The Navy attacked the big task force. + 2. See the cat glaring at the scared mouse. + 3. There are more than two factors here. + 4. The hat brim was wide and too droopy. + 5. The lawyer tried to lose his case. + 6. The grass curled around the fence post. + 7. Cut the pie into large parts. + 8. Men strive but seldom get rich. + 9. Always close the barn door tight. +10. He lay prone and hardly moved a limb. +H10 Harvard Sentences + 1. The slush lay deep along the street. + 2. A wisp of cloud hung in the blue air. + 3. A pound of sugar costs more than eggs. + 4. The fin was sharp and cut the clear water. + 5. The play seems dull and quite stupid. + 6. Bail the boat to stop it from sinking. + 7. The term ended in late june that year. + 8. A Tusk is used to make costly gifts. + 9. Ten pins were set in order. +10. The bill was paid every third week. +H11 Harvard Sentences + 1. Oak is strong and also gives shade. + 2. Cats and Dogs each hate the other. + 3. The pipe began to rust while new. + 4. Open the crate but don't break the glass. + 5. Add the sum to the product of these three. + 6. Thieves who rob friends deserve jail. + 7. The ripe taste of cheese improves with age. + 8. Act on these orders with great speed. + 9. The hog crawled under the high fence. +10. Move the vat over the hot fire. +H12 Harvard Sentences + 1. The bark of the pine tree was shiny and dark. + 2. Leaves turn brown and yellow in the fall. + 3. The pennant waved when the wind blew. + 4. Split the log with a quick, sharp blow. + 5. Burn peat after the logs give out. + 6. He ordered peach pie with ice cream. + 7. Weave the carpet on the right hand side. + 8. Hemp is a weed found in parts of the tropics. + 9. A lame back kept his score low. +10. We find joy in the simplest things. +H13 Harvard Sentences + 1. Type out three lists of orders. + 2. The harder he tried the less he got done. + 3. The boss ran the show with a watchful eye. + 4. The cup cracked and spilled its contents. + 5. Paste can cleanse the most dirty brass. + 6. The slang word for raw whiskey is booze. + 7. It caught its hind paw in a rusty trap. + 8. The wharf could be seen at the farther shore. + 9. Feel the heat of the weak dying flame. +10. The tiny girl took off her hat. +H14 Harvard Sentences + 1. A cramp is no small danger on a swim. + 2. He said the same phrase thirty times. + 3. Pluck the bright rose without leaves. + 4. Two plus seven is less than ten. + 5. The glow deepened in the eyes of the sweet girl. + 6. Bring your problems to the wise chief. + 7. Write a fond note to the friend you cherish. + 8. Clothes and lodging are free to new men. + 9. We frown when events take a bad turn. +10. Port is a strong wine with a smoky taste. +H15 Harvard Sentences + 1. The young kid jumped the rusty gate. + 2. Guess the result from the first scores. + 3. A salt pickle tastes fine with ham. + 4. The just claim got the right verdict. + 5. Those thistles bend in a high wind. + 6. Pure bred poodles have curls. + 7. The tree top waved in a graceful way. + 8. The spot on the blotter was made by green ink. + 9. Mud was spattered on the front of his white shirt. +10. The cigar burned a hole in the desk top. +H16 Harvard Sentences + 1. The empty flask stood on the tin tray. + 2. A speedy man can beat this track mark. + 3. He broke a new shoelace that day. + 4. The coffee stand is too high for the couch. + 5. The urge to write short stories is rare. + 6. The pencils have all been used. + 7. The pirates seized the crew of the lost ship. + 8. We tried to replace the coin but failed. + 9. She sewed the torn coat quite neatly. +10. The sofa cushion is red and of light weight. +H17 Harvard Sentences + 1. The jacket hung on the back of the wide chair. + 2. At that high level the air is pure. + 3. Drop the two when you add the figures. + 4. A filing case is now hard to buy. + 5. An abrupt start does not win the prize. + 6. Wood is best for making toys and blocks. + 7. The office paint was a dull, sad tan. + 8. He knew the skill of the great young actress. + 9. A rag will soak up spilled water. +10. A shower of dirt fell from the hot pipes. +H18 Harvard Sentences + 1. Steam hissed from the broken valve. + 2. The child almost hurt the small dog. + 3. There was a sound of dry leaves outside. + 4. The sky that morning was clear and bright blue. + 5. Torn scraps littered the stone floor. + 6. Sunday is the best part of the week. + 7. The doctor cured him with these pills. + 8. The new girl was fired today at noon. + 9. They felt gay when the ship arrived in port. +10. Add the store's account to the last cent. +H19 Harvard Sentences + 1. Acid burns holes in wool cloth. + 2. Fairy tales should be fun to write. + 3. Eight miles of woodland burned to waste. + 4. The third act was dull and tired the players. + 5. A young child should not suffer fright. + 6. Add the column and put the sum here. + 7. We admire and love a good cook. + 8. There the flood mark is ten inches. + 9. He carved a head from the round block of marble. +10. She has a smart way of wearing clothes. +H20 Harvard Sentences + 1. The fruit of a fig tree is apple shaped. + 2. Corn cobs can be used to kindle a fire. + 3. Where were they when the noise started. + 4. The paper box is full of thumb tacks. + 5. Sell your gift to a buyer at a good gain. + 6. The tongs lay beside the ice pail. + 7. The petals fall with the next puff of wind. + 8. Bring your best compass to the third class. + 9. They could laugh although they were sad. +10. Farmers came in to thresh the oat crop. +H21 Harvard Sentences + 1. The brown house was on fire to the attic. + 2. The lure is used to catch trout and flounder. + 3. Float the soap on top of the bath water. + 4. A blue crane is a tall wading bird. + 5. A fresh start will work such wonders. + 6. The club rented the rink for the fifth night. + 7. After the dance, they went straight home. + 8. The hostess taught the new maid to serve. + 9. He wrote his last novel there at the inn. +10. Even the worst will beat his low score. +H22 Harvard Sentences + 1. The cement had dried when he moved it. + 2. The loss of the second ship was hard to take. + 3. The fly made its way along the wall. + 4. Do that with a wooden stick. + 5. Live wires should be kept covered. + 6. The large house had hot water taps. + 7. It is hard to erase blue or red ink. + 8. Write at once or you may forget it. + 9. The doorknob was made of bright clean brass. +10. The wreck occurred by the bank on Main Street. +H23 Harvard Sentences + 1. A pencil with black lead writes best. + 2. Coax a young calf to drink from a bucket. + 3. Schools for ladies teach charm and grace. + 4. The lamp shone with a steady green flame. + 5. They took the axe and the saw to the forest. + 6. The ancient coin was quite dull and worn. + 7. The shaky barn fell with a loud crash. + 8. Jazz and swing fans like fast music. + 9. Rake the rubbish up and then burn it. +10. Slash the gold cloth into fine ribbons. +H24 Harvard Sentences + 1. Try to have the court decide the case. + 2. They are pushed back each time they attack. + 3. He broke his ties with groups of former friends. + 4. They floated on the raft to sun their white backs. + 5. The map had an X that meant nothing. + 6. Whitings are small fish caught in nets. + 7. Some ads serve to cheat buyers. + 8. Jerk the rope and the bell rings weakly. + 9. A waxed floor makes us lose balance. +10. Madam, this is the best brand of corn. +H25 Harvard Sentences + 1. On the islands the sea breeze is soft and mild. + 2. The play began as soon as we sat down. + 3. This will lead the world to more sound and fury. + 4. Add salt before you fry the egg. + 5. The rush for funds reached its peak Tuesday. + 6. The birch looked stark white and lonesome. + 7. The box is held by a bright red snapper. + 8. To make pure ice, you freeze water. + 9. The first worm gets snapped early. +10. Jump the fence and hurry up the bank. +H26 Harvard Sentences + 1. Yell and clap as the curtain slides back. + 2. They are men who walk the middle of the road. + 3. Both brothers wear the same size. + 4. In some form or other we need fun. + 5. The prince ordered his head chopped off. + 6. The houses are built of red clay bricks. + 7. Ducks fly north but lack a compass. + 8. Fruit flavors are used in fizz drinks. + 9. These pills do less good than others. +10. Canned pears lack full flavor. +H27 Harvard Sentences + 1. The dark pot hung in the front closet. + 2. Carry the pail to the wall and spill it there. + 3. The train brought our hero to the big town. + 4. We are sure that one war is enough. + 5. Gray paint stretched for miles around. + 6. The rude laugh filled the empty room. + 7. High seats are best for football fans. + 8. Tea served from the brown jug is tasty. + 9. A dash of pepper spoils beef stew. +10. A zestful food is the hot-cross bun. +H28 Harvard Sentences + 1. The horse trotted around the field at a brisk pace. + 2. Find the twin who stole the pearl necklace. + 3. Cut the cord that binds the box tightly. + 4. The red tape bound the smuggled food. + 5. Look in the corner to find the tan shirt. + 6. The cold drizzle will halt the bond drive. + 7. Nine men were hired to dig the ruins. + 8. The junk yard had a mouldy smell. + 9. The flint sputtered and lit a pine torch. +10. Soak the cloth and drown the sharp odor. +H29 Harvard Sentences + 1. The shelves were bare of both jam or crackers. + 2. A joy to every child is the swan boat. + 3. All sat frozen and watched the screen. + 4. A cloud of dust stung his tender eyes. + 5. To reach the end he needs much courage. + 6. Shape the clay gently into block form. + 7. A ridge on a smooth surface is a bump or flaw. + 8. Hedge apples may stain your hands green. + 9. Quench your thirst, then eat the crackers. +10. Tight curls get limp on rainy days. +H30 Harvard Sentences + 1. The mute muffled the high tones of the horn. + 2. The gold ring fits only a pierced ear. + 3. The old pan was covered with hard fudge. + 4. Watch the log float in the wide river. + 5. The node on the stalk of wheat grew daily. + 6. The heap of fallen leaves was set on fire. + 7. Write fast if you want to finish early. + 8. His shirt was clean but one button was gone. + 9. The barrel of beer was a brew of malt and hops. +10. Tin cans are absent from store shelves. +H31 Harvard Sentences + 1. Slide the box into that empty space. + 2. The plant grew large and green in the window. + 3. The beam dropped down on the workman's head. + 4. Pink clouds floated with the breeze. + 5. She danced like a swan, tall and graceful. + 6. The tube was blown and the tire flat and useless. + 7. It is late morning on the old wall clock. + 8. Let's all join as we sing the last chorus. + 9. The last switch cannot be turned off. +10. The fight will end in just six minutes. +H32 Harvard Sentences + 1. The store walls were lined with colored frocks. + 2. The peace league met to discuss their plans. + 3. The rise to fame of a person takes luck. + 4. Paper is scarce, so write with much care. + 5. The quick fox jumped on the sleeping cat. + 6. The nozzle of the fire hose was bright brass. + 7. Screw the round cap on as tight as needed. + 8. Time brings us many changes. + 9. The purple tie was ten years old. +10. Men think and plan and sometimes act. +H33 Harvard Sentences + 1. Fill the ink jar with sticky glue. + 2. He smoke a big pipe with strong contents. + 3. We need grain to keep our mules healthy. + 4. Pack the records in a neat thin case. + 5. The crunch of feet in the snow was the only sound. + 6. The copper bowl shone in the sun's rays. + 7. Boards will warp unless kept dry. + 8. The plush chair leaned against the wall. + 9. Glass will clink when struck by metal. +10. Bathe and relax in the cool green grass. +H34 Harvard Sentences + 1. Nine rows of soldiers stood in a line. + 2. The beach is dry and shallow at low tide. + 3. The idea is to sew both edges straight. + 4. The kitten chased the dog down the street. + 5. Pages bound in cloth make a book. + 6. Try to trace the fine lines of the painting. + 7. Women form less than half of the group. + 8. The zones merge in the central part of town. + 9. A gem in the rough needs work to polish. +10. Code is used when secrets are sent. +H35 Harvard Sentences + 1. Most of the news is easy for us to hear. + 2. He used the lathe to make brass objects. + 3. The vane on top of the pole revolved in the wind. + 4. Mince pie is a dish served to children. + 5. The clan gathered on each dull night. + 6. Let it burn, it gives us warmth and comfort. + 7. A castle built from sand fails to endure. + 8. A child's wit saved the day for us. + 9. Tack the strip of carpet to the worn floor. +10. Next Tuesday we must vote. +H36 Harvard Sentences + 1. Pour the stew from the pot into the plate. + 2. Each penny shone like new. + 3. The man went to the woods to gather sticks. + 4. The dirt piles were lines along the road. + 5. The logs fell and tumbled into the clear stream. + 6. Just hoist it up and take it away. + 7. A ripe plum is fit for a king's palate. + 8. Our plans right now are hazy. + 9. Brass rings are sold by these natives. +10. It takes a good trap to capture a bear. +H37 Harvard Sentences + 1. Feed the white mouse some flower seeds. + 2. The thaw came early and freed the stream. + 3. He took the lead and kept it the whole distance. + 4. The key you designed will fit the lock. + 5. Plead to the council to free the poor thief. + 6. Better hash is made of rare beef. + 7. This plank was made for walking on . + 8. The lake sparkled in the red hot sun. + 9. He crawled with care along the ledge. +10. Tend the sheep while the dog wanders. +H38 Harvard Sentences + 1. It takes a lot of help to finish these. + 2. Mark the spot with a sign painted red. + 3. Take two shares as a fair profit. + 4. The fur of cats goes by many names. + 5. North winds bring colds and fevers. + 6. He asks no person to vouch for him. + 7. Go now and come here later. + 8. A sash of gold silk will trim her dress. + 9. Soap can wash most dirt away. +10. That move means the game is over. +H39 Harvard Sentences + 1. He wrote down a long list of items. + 2. A siege will crack the strong defense. + 3. Grape juice and water mix well. + 4. Roads are paved with sticky tar. + 5. Fake stones shine but cost little. + 6. The drip of the rain made a pleasant sound. + 7. Smoke poured out of every crack. + 8. Serve the hot rum to the tired heroes. + 9. Much of the story makes good sense. +10. The sun came up to light the eastern sky. +H40 Harvard Sentences + 1. Heave the line over the port side. + 2. A lathe cuts and trims any wood. + 3. It's a dense crowd in two distinct ways. + 4. His hip struck the knee of the next player. + 5. The stale smell of old beer lingers. + 6. The desk was firm on the shaky floor. + 7. It takes heat to bring out the odor. + 8. Beef is scarcer than some lamb. + 9. Raise the sail and steer the ship northward. +10. A cone costs five cents on Mondays. +H41 Harvard Sentences. + 1. A pod is what peas always grow in. + 2. Jerk that dart from the cork target. + 3. No cement will hold hard wood. + 4. We now have a new base for shipping. + 5. A list of names is carved around the base. + 6. The sheep were led home by a dog. + 7. Three for a dime, the young peddler cried. + 8. The sense of smell is better than that of touch. + 9. No hardship seemed to make him sad. +10. Grace makes up for lack of beauty. +H42 Harvard Sentences + 1. Nudge gently but wake her now. + 2. The news struck doubt into restless minds. + 3. Once we stood beside the shore. + 4. A chink in the wall allowed a draft to blow. + 5. Fasten two pins on each side. + 6. A cold dip restores health and zest. + 7. He takes the oath of office each March. + 8. The sand drifts over the sills of the old house. + 9. The point of the steel pen was bent and twisted. +10. There is a lag between thought and act. +H43 Harvard Sentences + 1. Seed is needed to plant the spring corn. + 2. Draw the chart with heavy black lines. + 3. The boy owed his pal thirty cents. + 4. The chap slipped into the crowd and was lost. + 5. Hats are worn to tea and not to dinner. + 6. The ramp led up to the wide highway. + 7. Beat the dust from the rug onto the lawn. + 8. Say it slowly but make it ring clear. + 9. The straw nest housed five robins. +10. Screen the porch with woven straw mats. +H44 Harvard Sentences. + 1. This horse will nose his way to the finish. + 2. The dry wax protects the deep scratch. + 3. He picked up the dice for a second roll. + 4. These coins will be needed to pay his debt. + 5. The nag pulled the frail cart along. + 6. Twist the valve and release hot steam. + 7. The vamp of the shoe had a gold buckle. + 8. The smell of burned rags itches my nose. + 9. New pants lack cuffs and pockets. +10. The marsh will freeze when cold enough. +H45 Harvard Sentences. + 1. They slice the sausage thin with a knife. + 2. The bloom of the rose lasts a few days. + 3. A gray mare walked before the colt. + 4. Breakfast buns are fine with a hot drink. + 5. Bottles hold four kinds of rum. + 6. The man wore a feather in his felt hat. + 7. He wheeled the bike past the winding road. + 8. Drop the ashes on the worn old rug. + 9. The desk and both chairs were painted tan. +10. Throw out the used paper cup and plate. +H46 Harvard Sentences + 1. A clean neck means a neat collar. + 2. The couch cover and hall drapes were blue. + 3. The stems of the tall glasses cracked and broke. + 4. The wall phone rang loud and often. + 5. The clothes dried on a thin wooden rack. + 6. Turn out the lantern which gives us light. + 7. The cleat sank deeply into the soft turf. + 8. The bills were mailed promptly on the tenth of the month. + 9. To have is better than to wait and hope. +10. The price is fair for a good antique clock. +H47 Harvard Sentences + 1. The music played on while they talked. + 2. Dispense with a vest on a day like this. + 3. The bunch of grapes was pressed into wine. + 4. He sent the figs, but kept the ripe cherries. + 5. The hinge on the door creaked with old age. + 6. The screen before the fire kept in the sparks. + 7. Fly by night and you waste little time. + 8. Thick glasses helped him read the print. + 9. Birth and death marks the limits of life. +10. The chair looked strong but had no bottom. +H48 Harvard Sentences + 1. The kite flew wildly in the high wind. + 2. A fur muff is stylish once more. + 3. The tin box held priceless stones. + 4. We need an end of all such matter. + 5. The case was puzzling to the old and wise. + 6. The bright lanterns were gay on the dark lawn. + 7. We don't get much money but we have fun. + 8. The youth drove with zest, but little skill. + 9. Five years he lived with a shaggy dog. +10. A fence cuts through the corner lot. +H49 Harvard Sentences + 1. The way to save money is not to spend much. + 2. Shut the hatch before the waves push it in. + 3. The odor of spring makes young hearts jump. + 4. Crack the walnut with your sharp side teeth. + 5. He offered proof in the form of a large chart. + 6. Send the stuff in a thick paper bag. + 7. A quart of milk is water for the most part. + 8. They told wild tales to frighten him. + 9. The three story house was built of stone. +10. In the rear of the ground floor was a large passage. +H50 Harvard Sentences + 1. A man in a blue sweater sat at the desk. + 2. Oats are a food eaten by horse and man. + 3. Their eyelids droop for want of sleep. + 4. A sip of tea revives his tired friend. + 5. There are many ways to do these things. + 6. Tuck the sheet under the edge of the mat. + 7. A force equal to that would move the earth. + 8. We like to see clear weather. + 9. The work of the tailor is seen on each side. +10. Take a chance and win a china doll. +H51 Harvard Sentences + 1. Shake the dust from your shoes, stranger. + 2. She was kind to sick old people. + 3. The square wooden crate was packed to be shipped. + 4. The dusty bench stood by the stone wall. + 5. We dress to suit the weather of most days. + 6. Smile when you say nasty words. + 7. A bowl of rice is free with chicken stew. + 8. The water in this well is a source of good health. + 9. Take shelter in this tent, but keep still. +10. That guy is the writer of a few banned books. +H52 Harvard Sentences. + 1. The little tales they tell are false. + 2. The door was barred, locked, and bolted as well. + 3. Ripe pears are fit for a queen's table. + 4. A big wet stain was on the round carpet. + 5. The kite dipped and swayed, but stayed aloft. + 6. The pleasant hours fly by much too soon. + 7. The room was crowded with a wild mob. + 8. This strong arm shall shield your honor. + 9. She blushed when he gave her a white orchid. +10. The beetle droned in the hot June sun. +H53 Harvard Sentences + 1. Press the pedal with your left foot. + 2. Neat plans fail without luck. + 3. The black trunk fell from the landing. + 4. The bank pressed for payment of the debt. + 5. The theft of the pearl pin was kept secret. + 6. Shake hands with this friendly child. + 7. The vast space stretched into the far distance. + 8. A rich farm is rare in this sandy waste. + 9. His wide grin earned many friends. +10. Flax makes a fine brand of paper. +H54 Harvard Sentences + 1. Hurdle the pit with the aid of a long pole. + 2. A strong bid may scare your partner stiff. + 3. Even a just cause needs power to win. + 4. Peep under the tent and see the clowns. + 5. The leaf drifts along with a slow spin. + 6. Cheap clothes are flashy but don't last. + 7. A thing of small note can cause despair. + 8. Flood the mails with requests for this book. + 9. A thick coat of black paint covered all. +10. The pencil was cut to be sharp at both ends. +H55 Harvard Sentences + 1. Those last words were a strong statement. + 2. He wrote his name boldly at the top of the sheet. + 3. Dill pickles are sour but taste fine. + 4. Down that road is the way to the grain farmer. + 5. Either mud or dust are found at all times. + 6. The best method is to fix it in place with clips. + 7. If you mumble your speech will be lost. + 8. At night the alarm roused him from a deep sleep. + 9. Read just what the meter says. +10. Fill your pack with bright trinkets for the poor. +H56 Harvard Sentences + 1. The small red neon lamp went out. + 2. Clams are small, round, soft, and tasty. + 3. The fan whirled its round blades softly. + 4. The line where the edges join was clean. + 5. Breathe deep and smell the piny air. + 6. It matters not if he reads these words or those. + 7. A brown leather bag hung from its strap. + 8. A toad and a frog are hard to tell apart. + 9. A white silk jacket goes with any shoes. +10. A break in the dam almost caused a flood. +H57 Harvard Sentences + 1. Paint the sockets in the wall dull green. + 2. The child crawled into the dense grass. + 3. Bribes fail where honest men work. + 4. Trample the spark, else the flames will spread. + 5. The hilt of the sword was carved with fine designs. + 6. A round hole was drilled through the thin board. + 7. Footprints showed the path he took up the beach. + 8. She was waiting at my front lawn. + 9. A vent near the edge brought in fresh air. +10. Prod the old mule with a crooked stick. +H58 Harvard Sentences + 1. It is a band of steel three inches wide. + 2. The pipe ran almost the length of the ditch. + 3. It was hidden from sight by a mass of leaves and shrubs. + 4. The weight of the package was seen on the high scale. + 5. Wake and rise, and step into the green outdoors. + 6. The green light in the brown box flickered. + 7. The brass tube circled the high wall. + 8. The lobes of her ears were pierced to hold rings. + 9. Hold the hammer near the end to drive the nail. +10. Next Sunday is the twelfth of the month. +H59 Harvard Sentences + 1. Every word and phrase he speaks is true. + 2. He put his last cartridge into the gun and fired. + 3. They took their kids from the public school. + 4. Drive the screw straight into the wood. + 5. Keep the hatch tight and the watch constant. + 6. Sever the twine with a quick snip of the knife. + 7. Paper will dry out when wet. + 8. Slide the catch back and open the desk. + 9. Help the weak to preserve their strength. +10. A sullen smile gets few friends. +H60 Harvard Sentences + 1. Stop whistling and watch the boys march. + 2. Jerk the cord, and out tumbles the gold. + 3. Slide the tray across the glass top. + 4. The cloud moved in a stately way and was gone. + 5. Light maple makes for a swell room. + 6. Set the piece here and say nothing. + 7. Dull stories make her laugh. + 8. A stiff cord will do to fasten your shoe. + 9. Get the trust fund to the bank early. +10. Choose between the high road and the low. +H61 Harvard Sentences + 1. A plea for funds seems to come again. + 2. He lent his coat to the tall gaunt stranger. + 3. There is a strong chance it will happen once more. + 4. The duke left the park in a silver coach. + 5. Greet the new guests and leave quickly. + 6. When the frost has come it is time for turkey. + 7. Sweet words work better than fierce. + 8. A thin stripe runs down the middle. + 9. A six comes up more often than a ten. +10. Lush ferns grow on the lofty rocks. +H62 Harvard Sentences + 1. The ram scared the school children off. + 2. The team with the best timing looks good. + 3. The farmer swapped his horse for a brown ox. + 4. Sit on the perch and tell the others what to do. + 5. A steep trail is painful for our feet. + 6. The early phase of life moves fast. + 7. Green moss grows on the northern side. + 8. Tea in thin china has a sweet taste. + 9. Pitch the straw through the door of the stable. +10. The latch on the back gate needed a nail. +H63 Harvard Sentences + 1. The goose was brought straight from the old market. + 2. The sink is the thing in which we pile dishes. + 3. A whiff of it will cure the most stubborn cold. + 4. The facts don't always show who is right. + 5. She flaps her cape as she parades the street. + 6. The loss of the cruiser was a blow to the fleet. + 7. Loop the braid to the left and then over. + 8. Plead with the lawyer to drop the lost cause. + 9. Calves thrive on tender spring grass. +10. Post no bills on this office wall. +H64 Harvard Sentences + 1. Tear a thin sheet from the yellow pad. + 2. A cruise in warm waters in a sleek yacht is fun. + 3. A streak of color ran down the left edge. + 4. It was done before the boy could see it. + 5. Crouch before you jump or miss the mark. + 6. Pack the kits and don't forget the salt. + 7. The square peg will settle in the round hole. + 8. Fine soap saves tender skin. + 9. Poached eggs and tea must suffice. +10. Bad nerves are jangled by a door slam. +H65 Harvard Sentences + 1. Ship maps are different from those for planes. + 2. Dimes showered down from all sides. + 3. They sang the same tunes at each party. + 4. The sky in the west is tinged with orange red. + 5. The pods of peas ferment in bare fields. + 6. The horse balked and threw the tall rider. + 7. The hitch between the horse and cart broke. + 8. Pile the coal high in the shed corner. + 9. A gold vase is both rare and costly. +10. The knife was hung inside its bright sheath. +H66 Harvard Sentences + 1. The rarest spice comes from the far East. + 2. The roof should be tilted at a sharp slant. + 3. A smatter of French is worse than none. + 4. The mule trod the treadmill day and night. + 5. The aim of the contest is to raise a great fund. + 6. To send it now in large amounts is bad. + 7. There is a fine hard tang in salty air. + 8. Cod is the main business of the north shore. + 9. The slab was hewn from heavy blocks of slate. +10. Dunk the stale biscuits into strong drink. +H67 Harvard Sentences + 1. Hang tinsel from both branches. + 2. Cap the jar with a tight brass cover. + 3. The poor boy missed the boat again. + 4. Be sure to set that lamp firmly in the hole. + 5. Pick a card and slip it under the pack. + 6. A round mat will cover the dull spot. + 7. The first part of the plan needs changing. + 8. A good book informs of what we ought to know. + 9. The mail comes in three batches per day. +10. You cannot brew tea in a cold pot. +H68 Harvard Sentences + 1. Dots of light betrayed the black cat. + 2. Put the chart on the mantel and tack it down. + 3. The night shift men rate extra pay. + 4. The red paper brightened the dim stage. + 5. See the player scoot to third base. + 6. Slide the bill between the two leaves. + 7. Many hands help get the job done. + 8. We don't like to admit our small faults. + 9. No doubt about the way the wind blows. +10. Dig deep in the earth for pirate's gold. +H69 Harvard Sentences + 1. The steady drip is worse than a drenching rain. + 2. A flat pack takes less luggage space. + 3. Green ice frosted the punch bowl. + 4. A stuffed chair slipped from the moving van. + 5. The stitch will serve but needs to be shortened. + 6. A thin book fits in the side pocket. + 7. The gloss on top made it unfit to read. + 8. The hail pattered on the burnt brown grass. + 9. Seven seals were stamped on great sheets. +10. Our troops are set to strike heavy blows. +H70 Harvard Sentences + 1. The store was jammed before the sale could start. + 2. It was a bad error on the part of the new judge. + 3. One step more and the board will collapse. + 4. Take the match and strike it against your shoe. + 5. The pot boiled but the contents failed to jell. + 6. The baby puts his right foot in his mouth. + 7. The bombs left most of the town in ruins. + 8. Stop and stare at the hard working man. + 9. The streets are narrow and full of sharp turns. +10. The pup jerked the leash as he saw a feline shape. +H71 Harvard Sentences + 1. Open your book to the first page. + 2. Fish evade the net and swim off. + 3. Dip the pail once and let it settle. + 4. Will you please answer that phone. + 5. The big red apple fell to the ground. + 6. The curtain rose and the show was on. + 7. The young prince became heir to the throne. + 8. He sent the boy on a short errand. + 9. Leave now and you will arrive on time. +10. The corner store was robbed last night. +H72 Harvard Sentences + 1. A gold ring will please most any girl. + 2. The long journey home took a year. + 3. She saw a cat in the neighbor's house. + 4. A pink shell was found on the sandy beach. + 5. Small children came to see him. + 6. The grass and bushes were wet with dew. + 7. The blind man counted his old coins. + 8. A severe storm tore down the barn. + 9. She called his name many times. +10. When you hear the bell, come quickly. diff --git a/widget/milsko/milskosrc/resource/icon/back.png b/widget/milsko/milskosrc/resource/icon/back.png new file mode 100644 index 0000000000..a97b41e4c1 Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/back.png differ diff --git a/widget/milsko/milskosrc/resource/icon/clock.png b/widget/milsko/milskosrc/resource/icon/clock.png new file mode 100644 index 0000000000..2fe2817c9a Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/clock.png differ diff --git a/widget/milsko/milskosrc/resource/icon/computer.png b/widget/milsko/milskosrc/resource/icon/computer.png new file mode 100644 index 0000000000..898c9e6d7d Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/computer.png differ diff --git a/widget/milsko/milskosrc/resource/icon/directory.png b/widget/milsko/milskosrc/resource/icon/directory.png new file mode 100644 index 0000000000..3fcb88e1e0 Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/directory.png differ diff --git a/widget/milsko/milskosrc/resource/icon/down.png b/widget/milsko/milskosrc/resource/icon/down.png new file mode 100644 index 0000000000..dcfc16d8ff Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/down.png differ diff --git a/widget/milsko/milskosrc/resource/icon/error.png b/widget/milsko/milskosrc/resource/icon/error.png new file mode 100644 index 0000000000..38effdeb0f Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/error.png differ diff --git a/widget/milsko/milskosrc/resource/icon/file.png b/widget/milsko/milskosrc/resource/icon/file.png new file mode 100644 index 0000000000..bd36b0855c Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/file.png differ diff --git a/widget/milsko/milskosrc/resource/icon/forward.png b/widget/milsko/milskosrc/resource/icon/forward.png new file mode 100644 index 0000000000..34ef3ae469 Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/forward.png differ diff --git a/widget/milsko/milskosrc/resource/icon/info.png b/widget/milsko/milskosrc/resource/icon/info.png new file mode 100644 index 0000000000..19e08ce5ab Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/info.png differ diff --git a/widget/milsko/milskosrc/resource/icon/left.png b/widget/milsko/milskosrc/resource/icon/left.png new file mode 100644 index 0000000000..9c686710aa Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/left.png differ diff --git a/widget/milsko/milskosrc/resource/icon/news.png b/widget/milsko/milskosrc/resource/icon/news.png new file mode 100644 index 0000000000..5df87d7a18 Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/news.png differ diff --git a/widget/milsko/milskosrc/resource/icon/note.png b/widget/milsko/milskosrc/resource/icon/note.png new file mode 100644 index 0000000000..03b1b4666a Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/note.png differ diff --git a/widget/milsko/milskosrc/resource/icon/right.png b/widget/milsko/milskosrc/resource/icon/right.png new file mode 100644 index 0000000000..7824658bfb Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/right.png differ diff --git a/widget/milsko/milskosrc/resource/icon/search.png b/widget/milsko/milskosrc/resource/icon/search.png new file mode 100644 index 0000000000..eec0334d5b Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/search.png differ diff --git a/widget/milsko/milskosrc/resource/icon/up.png b/widget/milsko/milskosrc/resource/icon/up.png new file mode 100644 index 0000000000..4aa8faf551 Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/up.png differ diff --git a/widget/milsko/milskosrc/resource/icon/warning.png b/widget/milsko/milskosrc/resource/icon/warning.png new file mode 100644 index 0000000000..662ea4c1e2 Binary files /dev/null and b/widget/milsko/milskosrc/resource/icon/warning.png differ diff --git a/widget/milsko/milskosrc/resource/logo/102x47.png b/widget/milsko/milskosrc/resource/logo/102x47.png new file mode 100644 index 0000000000..b00815fdc4 Binary files /dev/null and b/widget/milsko/milskosrc/resource/logo/102x47.png differ diff --git a/widget/milsko/milskosrc/resource/logo/102x47.pov b/widget/milsko/milskosrc/resource/logo/102x47.pov new file mode 100644 index 0000000000..99f3d2bf85 --- /dev/null +++ b/widget/milsko/milskosrc/resource/logo/102x47.pov @@ -0,0 +1,4 @@ +#declare FAR = 2.25; +#declare Y = -0.5; + +#include "resource/logo/logo.pov" diff --git a/widget/milsko/milskosrc/resource/logo/banner-nodejs.png b/widget/milsko/milskosrc/resource/logo/banner-nodejs.png new file mode 100644 index 0000000000..5d3475759c Binary files /dev/null and b/widget/milsko/milskosrc/resource/logo/banner-nodejs.png differ diff --git a/widget/milsko/milskosrc/resource/logo/banner.png b/widget/milsko/milskosrc/resource/logo/banner.png new file mode 100644 index 0000000000..cfbeb3742d Binary files /dev/null and b/widget/milsko/milskosrc/resource/logo/banner.png differ diff --git a/widget/milsko/milskosrc/resource/logo/banner.pov b/widget/milsko/milskosrc/resource/logo/banner.pov new file mode 100644 index 0000000000..0f4e3ec7f0 --- /dev/null +++ b/widget/milsko/milskosrc/resource/logo/banner.pov @@ -0,0 +1,54 @@ +#declare BASE = 1; +#include "resource/logo/logo.pov" + +#ifdef(VERSION) +object { + text { + ttf "resource/font/IBMPlexSerif.ttf", + VERSION, + 1, 0 + } + scale 5 + translate <7.5, 0, 1> + pigment { + color Red + } + finish { + phong 1 + reflection 0.3 + } +} +#end + +object { + text { + ttf "resource/font/IBMPlexSerif.ttf", +#ifdef(NODEJS) + "for Node.JS", +#else + "Milsko Toolkit", +#end + 1, 0 + } + scale 2 +#ifdef(NODEJS) + translate <5, -1, -1> +#else + translate <2.5, -1, -1> +#end + pigment { + color White + } + finish { + phong 1 + reflection 0.3 + } +} + +camera { + location <8+5, 2.5, -37.5> + look_at <7, 0.75, 0> + angle 35 + up <0, 1, 0> + right image_width / image_height * x +} diff --git a/widget/milsko/milskosrc/resource/logo/banner_10.pov b/widget/milsko/milskosrc/resource/logo/banner_10.pov new file mode 100644 index 0000000000..a306e9829b --- /dev/null +++ b/widget/milsko/milskosrc/resource/logo/banner_10.pov @@ -0,0 +1,2 @@ +#declare VERSION="1.0"; +#include "resource/logo/banner.pov" diff --git a/widget/milsko/milskosrc/resource/logo/logo.png b/widget/milsko/milskosrc/resource/logo/logo.png new file mode 100644 index 0000000000..2efaaebbb1 Binary files /dev/null and b/widget/milsko/milskosrc/resource/logo/logo.png differ diff --git a/widget/milsko/milskosrc/resource/logo/logo.pov b/widget/milsko/milskosrc/resource/logo/logo.pov new file mode 100644 index 0000000000..5348056ecd --- /dev/null +++ b/widget/milsko/milskosrc/resource/logo/logo.pov @@ -0,0 +1,97 @@ +#include "shapes.inc" +#include "colors.inc" +#include "textures.inc" +#include "skies.inc" + +object { + O_Cloud1 +} + +sky_sphere { + pigment { + gradient y + color_map { + [0.0 White*0.8] + [0.2 rgb<0.2 0.2 0.7>] + } + } +} + +union { +object { + Cube + translate <-1, 0, 1> + pigment { + color Red + } +} + +object { + Cube + translate <1, 0, 1> + pigment { + color Cyan + } +} + +object { + Cube + translate <-1, 0, -1> + pigment { + color Blue + } +} + +object { + Cube + translate <1, 0, -1> + pigment { + color Green + } +} + +object { + Cube + translate <0, 2, 0> + pigment { + color Red + } +} + +rotate <0, clock * 360, 0> +} + +plane { + y, -1 + pigment { + checker Red Gray + } + finish { + phong 1 + reflection 0.5 + } +} + +light_source { + <-250, 250, -500> + color White*2 + parallel point_at <0, 0, 0> +} + +#ifndef(FAR) +#declare FAR = 1; +#end + +#ifndef(Y) +#declare Y = 0; +#end + +#ifndef(BASE) +camera { + location <1.5 * FAR, 2.5 + Y, -10 * FAR> + look_at <0, 0.75 + Y, 0> + angle 35 + up <0, 1, 0> + right image_width / image_height * x +} +#end diff --git a/widget/milsko/milskosrc/resource/logo/overlay-102x47.png b/widget/milsko/milskosrc/resource/logo/overlay-102x47.png new file mode 100644 index 0000000000..aa3667af62 Binary files /dev/null and b/widget/milsko/milskosrc/resource/logo/overlay-102x47.png differ diff --git a/widget/milsko/milskosrc/resource/milsko.pc.in b/widget/milsko/milskosrc/resource/milsko.pc.in new file mode 100644 index 0000000000..9cdc61e920 --- /dev/null +++ b/widget/milsko/milskosrc/resource/milsko.pc.in @@ -0,0 +1,10 @@ +prefix="@CMAKE_INSTALL_PREFIX@" +includedir="@CMAKE_INSTALL_PREFIX@/include" +libdir="@CMAKE_INSTALL_PREFIX@/bin" + +Name: @PROJECT_NAME@ +Description: @PROJECT_DESCRIPTION@ +URL: @PROJECT_HOMEPAGE_URL@ +Version: @PROJECT_VERSION@ +Cflags: -I"${includedir}"/ +Libs: -L"${libdir}" -lMw diff --git a/widget/milsko/milskosrc/resource/rgb.txt b/widget/milsko/milskosrc/resource/rgb.txt new file mode 100644 index 0000000000..7096643760 --- /dev/null +++ b/widget/milsko/milskosrc/resource/rgb.txt @@ -0,0 +1,782 @@ +255 250 250 snow +248 248 255 ghost white +248 248 255 GhostWhite +245 245 245 white smoke +245 245 245 WhiteSmoke +220 220 220 gainsboro +255 250 240 floral white +255 250 240 FloralWhite +253 245 230 old lace +253 245 230 OldLace +250 240 230 linen +250 235 215 antique white +250 235 215 AntiqueWhite +255 239 213 papaya whip +255 239 213 PapayaWhip +255 235 205 blanched almond +255 235 205 BlanchedAlmond +255 228 196 bisque +255 218 185 peach puff +255 218 185 PeachPuff +255 222 173 navajo white +255 222 173 NavajoWhite +255 228 181 moccasin +255 248 220 cornsilk +255 255 240 ivory +255 250 205 lemon chiffon +255 250 205 LemonChiffon +255 245 238 seashell +240 255 240 honeydew +245 255 250 mint cream +245 255 250 MintCream +240 255 255 azure +240 248 255 alice blue +240 248 255 AliceBlue +230 230 250 lavender +255 240 245 lavender blush +255 240 245 LavenderBlush +255 228 225 misty rose +255 228 225 MistyRose +255 255 255 white + 0 0 0 black + 47 79 79 dark slate gray + 47 79 79 DarkSlateGray + 47 79 79 dark slate grey + 47 79 79 DarkSlateGrey +105 105 105 dim gray +105 105 105 DimGray +105 105 105 dim grey +105 105 105 DimGrey +112 128 144 slate gray +112 128 144 SlateGray +112 128 144 slate grey +112 128 144 SlateGrey +119 136 153 light slate gray +119 136 153 LightSlateGray +119 136 153 light slate grey +119 136 153 LightSlateGrey +190 190 190 gray +190 190 190 grey +190 190 190 x11 gray +190 190 190 X11Gray +190 190 190 x11 grey +190 190 190 X11Grey +128 128 128 web gray +128 128 128 WebGray +128 128 128 web grey +128 128 128 WebGrey +211 211 211 light grey +211 211 211 LightGrey +211 211 211 light gray +211 211 211 LightGray + 25 25 112 midnight blue + 25 25 112 MidnightBlue + 0 0 128 navy + 0 0 128 navy blue + 0 0 128 NavyBlue +100 149 237 cornflower blue +100 149 237 CornflowerBlue + 72 61 139 dark slate blue + 72 61 139 DarkSlateBlue +106 90 205 slate blue +106 90 205 SlateBlue +123 104 238 medium slate blue +123 104 238 MediumSlateBlue +132 112 255 light slate blue +132 112 255 LightSlateBlue + 0 0 205 medium blue + 0 0 205 MediumBlue + 65 105 225 royal blue + 65 105 225 RoyalBlue + 0 0 255 blue + 30 144 255 dodger blue + 30 144 255 DodgerBlue + 0 191 255 deep sky blue + 0 191 255 DeepSkyBlue +135 206 235 sky blue +135 206 235 SkyBlue +135 206 250 light sky blue +135 206 250 LightSkyBlue + 70 130 180 steel blue + 70 130 180 SteelBlue +176 196 222 light steel blue +176 196 222 LightSteelBlue +173 216 230 light blue +173 216 230 LightBlue +176 224 230 powder blue +176 224 230 PowderBlue +175 238 238 pale turquoise +175 238 238 PaleTurquoise + 0 206 209 dark turquoise + 0 206 209 DarkTurquoise + 72 209 204 medium turquoise + 72 209 204 MediumTurquoise + 64 224 208 turquoise + 0 255 255 cyan + 0 255 255 aqua +224 255 255 light cyan +224 255 255 LightCyan + 95 158 160 cadet blue + 95 158 160 CadetBlue +102 205 170 medium aquamarine +102 205 170 MediumAquamarine +127 255 212 aquamarine + 0 100 0 dark green + 0 100 0 DarkGreen + 85 107 47 dark olive green + 85 107 47 DarkOliveGreen +143 188 143 dark sea green +143 188 143 DarkSeaGreen + 46 139 87 sea green + 46 139 87 SeaGreen + 60 179 113 medium sea green + 60 179 113 MediumSeaGreen + 32 178 170 light sea green + 32 178 170 LightSeaGreen +152 251 152 pale green +152 251 152 PaleGreen + 0 255 127 spring green + 0 255 127 SpringGreen +124 252 0 lawn green +124 252 0 LawnGreen + 0 255 0 green + 0 255 0 lime + 0 255 0 x11 green + 0 255 0 X11Green + 0 128 0 web green + 0 128 0 WebGreen +127 255 0 chartreuse + 0 250 154 medium spring green + 0 250 154 MediumSpringGreen +173 255 47 green yellow +173 255 47 GreenYellow + 50 205 50 lime green + 50 205 50 LimeGreen +154 205 50 yellow green +154 205 50 YellowGreen + 34 139 34 forest green + 34 139 34 ForestGreen +107 142 35 olive drab +107 142 35 OliveDrab +189 183 107 dark khaki +189 183 107 DarkKhaki +240 230 140 khaki +238 232 170 pale goldenrod +238 232 170 PaleGoldenrod +250 250 210 light goldenrod yellow +250 250 210 LightGoldenrodYellow +255 255 224 light yellow +255 255 224 LightYellow +255 255 0 yellow +255 215 0 gold +238 221 130 light goldenrod +238 221 130 LightGoldenrod +218 165 32 goldenrod +184 134 11 dark goldenrod +184 134 11 DarkGoldenrod +188 143 143 rosy brown +188 143 143 RosyBrown +205 92 92 indian red +205 92 92 IndianRed +139 69 19 saddle brown +139 69 19 SaddleBrown +160 82 45 sienna +205 133 63 peru +222 184 135 burlywood +245 245 220 beige +245 222 179 wheat +244 164 96 sandy brown +244 164 96 SandyBrown +210 180 140 tan +210 105 30 chocolate +178 34 34 firebrick +165 42 42 brown +233 150 122 dark salmon +233 150 122 DarkSalmon +250 128 114 salmon +255 160 122 light salmon +255 160 122 LightSalmon +255 165 0 orange +255 140 0 dark orange +255 140 0 DarkOrange +255 127 80 coral +240 128 128 light coral +240 128 128 LightCoral +255 99 71 tomato +255 69 0 orange red +255 69 0 OrangeRed +255 0 0 red +255 105 180 hot pink +255 105 180 HotPink +255 20 147 deep pink +255 20 147 DeepPink +255 192 203 pink +255 182 193 light pink +255 182 193 LightPink +219 112 147 pale violet red +219 112 147 PaleVioletRed +176 48 96 maroon +176 48 96 x11 maroon +176 48 96 X11Maroon +128 0 0 web maroon +128 0 0 WebMaroon +199 21 133 medium violet red +199 21 133 MediumVioletRed +208 32 144 violet red +208 32 144 VioletRed +255 0 255 magenta +255 0 255 fuchsia +238 130 238 violet +221 160 221 plum +218 112 214 orchid +186 85 211 medium orchid +186 85 211 MediumOrchid +153 50 204 dark orchid +153 50 204 DarkOrchid +148 0 211 dark violet +148 0 211 DarkViolet +138 43 226 blue violet +138 43 226 BlueViolet +160 32 240 purple +160 32 240 x11 purple +160 32 240 X11Purple +128 0 128 web purple +128 0 128 WebPurple +147 112 219 medium purple +147 112 219 MediumPurple +216 191 216 thistle +255 250 250 snow1 +238 233 233 snow2 +205 201 201 snow3 +139 137 137 snow4 +255 245 238 seashell1 +238 229 222 seashell2 +205 197 191 seashell3 +139 134 130 seashell4 +255 239 219 AntiqueWhite1 +238 223 204 AntiqueWhite2 +205 192 176 AntiqueWhite3 +139 131 120 AntiqueWhite4 +255 228 196 bisque1 +238 213 183 bisque2 +205 183 158 bisque3 +139 125 107 bisque4 +255 218 185 PeachPuff1 +238 203 173 PeachPuff2 +205 175 149 PeachPuff3 +139 119 101 PeachPuff4 +255 222 173 NavajoWhite1 +238 207 161 NavajoWhite2 +205 179 139 NavajoWhite3 +139 121 94 NavajoWhite4 +255 250 205 LemonChiffon1 +238 233 191 LemonChiffon2 +205 201 165 LemonChiffon3 +139 137 112 LemonChiffon4 +255 248 220 cornsilk1 +238 232 205 cornsilk2 +205 200 177 cornsilk3 +139 136 120 cornsilk4 +255 255 240 ivory1 +238 238 224 ivory2 +205 205 193 ivory3 +139 139 131 ivory4 +240 255 240 honeydew1 +224 238 224 honeydew2 +193 205 193 honeydew3 +131 139 131 honeydew4 +255 240 245 LavenderBlush1 +238 224 229 LavenderBlush2 +205 193 197 LavenderBlush3 +139 131 134 LavenderBlush4 +255 228 225 MistyRose1 +238 213 210 MistyRose2 +205 183 181 MistyRose3 +139 125 123 MistyRose4 +240 255 255 azure1 +224 238 238 azure2 +193 205 205 azure3 +131 139 139 azure4 +131 111 255 SlateBlue1 +122 103 238 SlateBlue2 +105 89 205 SlateBlue3 + 71 60 139 SlateBlue4 + 72 118 255 RoyalBlue1 + 67 110 238 RoyalBlue2 + 58 95 205 RoyalBlue3 + 39 64 139 RoyalBlue4 + 0 0 255 blue1 + 0 0 238 blue2 + 0 0 205 blue3 + 0 0 139 blue4 + 30 144 255 DodgerBlue1 + 28 134 238 DodgerBlue2 + 24 116 205 DodgerBlue3 + 16 78 139 DodgerBlue4 + 99 184 255 SteelBlue1 + 92 172 238 SteelBlue2 + 79 148 205 SteelBlue3 + 54 100 139 SteelBlue4 + 0 191 255 DeepSkyBlue1 + 0 178 238 DeepSkyBlue2 + 0 154 205 DeepSkyBlue3 + 0 104 139 DeepSkyBlue4 +135 206 255 SkyBlue1 +126 192 238 SkyBlue2 +108 166 205 SkyBlue3 + 74 112 139 SkyBlue4 +176 226 255 LightSkyBlue1 +164 211 238 LightSkyBlue2 +141 182 205 LightSkyBlue3 + 96 123 139 LightSkyBlue4 +198 226 255 SlateGray1 +185 211 238 SlateGray2 +159 182 205 SlateGray3 +108 123 139 SlateGray4 +202 225 255 LightSteelBlue1 +188 210 238 LightSteelBlue2 +162 181 205 LightSteelBlue3 +110 123 139 LightSteelBlue4 +191 239 255 LightBlue1 +178 223 238 LightBlue2 +154 192 205 LightBlue3 +104 131 139 LightBlue4 +224 255 255 LightCyan1 +209 238 238 LightCyan2 +180 205 205 LightCyan3 +122 139 139 LightCyan4 +187 255 255 PaleTurquoise1 +174 238 238 PaleTurquoise2 +150 205 205 PaleTurquoise3 +102 139 139 PaleTurquoise4 +152 245 255 CadetBlue1 +142 229 238 CadetBlue2 +122 197 205 CadetBlue3 + 83 134 139 CadetBlue4 + 0 245 255 turquoise1 + 0 229 238 turquoise2 + 0 197 205 turquoise3 + 0 134 139 turquoise4 + 0 255 255 cyan1 + 0 238 238 cyan2 + 0 205 205 cyan3 + 0 139 139 cyan4 +151 255 255 DarkSlateGray1 +141 238 238 DarkSlateGray2 +121 205 205 DarkSlateGray3 + 82 139 139 DarkSlateGray4 +127 255 212 aquamarine1 +118 238 198 aquamarine2 +102 205 170 aquamarine3 + 69 139 116 aquamarine4 +193 255 193 DarkSeaGreen1 +180 238 180 DarkSeaGreen2 +155 205 155 DarkSeaGreen3 +105 139 105 DarkSeaGreen4 + 84 255 159 SeaGreen1 + 78 238 148 SeaGreen2 + 67 205 128 SeaGreen3 + 46 139 87 SeaGreen4 +154 255 154 PaleGreen1 +144 238 144 PaleGreen2 +124 205 124 PaleGreen3 + 84 139 84 PaleGreen4 + 0 255 127 SpringGreen1 + 0 238 118 SpringGreen2 + 0 205 102 SpringGreen3 + 0 139 69 SpringGreen4 + 0 255 0 green1 + 0 238 0 green2 + 0 205 0 green3 + 0 139 0 green4 +127 255 0 chartreuse1 +118 238 0 chartreuse2 +102 205 0 chartreuse3 + 69 139 0 chartreuse4 +192 255 62 OliveDrab1 +179 238 58 OliveDrab2 +154 205 50 OliveDrab3 +105 139 34 OliveDrab4 +202 255 112 DarkOliveGreen1 +188 238 104 DarkOliveGreen2 +162 205 90 DarkOliveGreen3 +110 139 61 DarkOliveGreen4 +255 246 143 khaki1 +238 230 133 khaki2 +205 198 115 khaki3 +139 134 78 khaki4 +255 236 139 LightGoldenrod1 +238 220 130 LightGoldenrod2 +205 190 112 LightGoldenrod3 +139 129 76 LightGoldenrod4 +255 255 224 LightYellow1 +238 238 209 LightYellow2 +205 205 180 LightYellow3 +139 139 122 LightYellow4 +255 255 0 yellow1 +238 238 0 yellow2 +205 205 0 yellow3 +139 139 0 yellow4 +255 215 0 gold1 +238 201 0 gold2 +205 173 0 gold3 +139 117 0 gold4 +255 193 37 goldenrod1 +238 180 34 goldenrod2 +205 155 29 goldenrod3 +139 105 20 goldenrod4 +255 185 15 DarkGoldenrod1 +238 173 14 DarkGoldenrod2 +205 149 12 DarkGoldenrod3 +139 101 8 DarkGoldenrod4 +255 193 193 RosyBrown1 +238 180 180 RosyBrown2 +205 155 155 RosyBrown3 +139 105 105 RosyBrown4 +255 106 106 IndianRed1 +238 99 99 IndianRed2 +205 85 85 IndianRed3 +139 58 58 IndianRed4 +255 130 71 sienna1 +238 121 66 sienna2 +205 104 57 sienna3 +139 71 38 sienna4 +255 211 155 burlywood1 +238 197 145 burlywood2 +205 170 125 burlywood3 +139 115 85 burlywood4 +255 231 186 wheat1 +238 216 174 wheat2 +205 186 150 wheat3 +139 126 102 wheat4 +255 165 79 tan1 +238 154 73 tan2 +205 133 63 tan3 +139 90 43 tan4 +255 127 36 chocolate1 +238 118 33 chocolate2 +205 102 29 chocolate3 +139 69 19 chocolate4 +255 48 48 firebrick1 +238 44 44 firebrick2 +205 38 38 firebrick3 +139 26 26 firebrick4 +255 64 64 brown1 +238 59 59 brown2 +205 51 51 brown3 +139 35 35 brown4 +255 140 105 salmon1 +238 130 98 salmon2 +205 112 84 salmon3 +139 76 57 salmon4 +255 160 122 LightSalmon1 +238 149 114 LightSalmon2 +205 129 98 LightSalmon3 +139 87 66 LightSalmon4 +255 165 0 orange1 +238 154 0 orange2 +205 133 0 orange3 +139 90 0 orange4 +255 127 0 DarkOrange1 +238 118 0 DarkOrange2 +205 102 0 DarkOrange3 +139 69 0 DarkOrange4 +255 114 86 coral1 +238 106 80 coral2 +205 91 69 coral3 +139 62 47 coral4 +255 99 71 tomato1 +238 92 66 tomato2 +205 79 57 tomato3 +139 54 38 tomato4 +255 69 0 OrangeRed1 +238 64 0 OrangeRed2 +205 55 0 OrangeRed3 +139 37 0 OrangeRed4 +255 0 0 red1 +238 0 0 red2 +205 0 0 red3 +139 0 0 red4 +255 20 147 DeepPink1 +238 18 137 DeepPink2 +205 16 118 DeepPink3 +139 10 80 DeepPink4 +255 110 180 HotPink1 +238 106 167 HotPink2 +205 96 144 HotPink3 +139 58 98 HotPink4 +255 181 197 pink1 +238 169 184 pink2 +205 145 158 pink3 +139 99 108 pink4 +255 174 185 LightPink1 +238 162 173 LightPink2 +205 140 149 LightPink3 +139 95 101 LightPink4 +255 130 171 PaleVioletRed1 +238 121 159 PaleVioletRed2 +205 104 137 PaleVioletRed3 +139 71 93 PaleVioletRed4 +255 52 179 maroon1 +238 48 167 maroon2 +205 41 144 maroon3 +139 28 98 maroon4 +255 62 150 VioletRed1 +238 58 140 VioletRed2 +205 50 120 VioletRed3 +139 34 82 VioletRed4 +255 0 255 magenta1 +238 0 238 magenta2 +205 0 205 magenta3 +139 0 139 magenta4 +255 131 250 orchid1 +238 122 233 orchid2 +205 105 201 orchid3 +139 71 137 orchid4 +255 187 255 plum1 +238 174 238 plum2 +205 150 205 plum3 +139 102 139 plum4 +224 102 255 MediumOrchid1 +209 95 238 MediumOrchid2 +180 82 205 MediumOrchid3 +122 55 139 MediumOrchid4 +191 62 255 DarkOrchid1 +178 58 238 DarkOrchid2 +154 50 205 DarkOrchid3 +104 34 139 DarkOrchid4 +155 48 255 purple1 +145 44 238 purple2 +125 38 205 purple3 + 85 26 139 purple4 +171 130 255 MediumPurple1 +159 121 238 MediumPurple2 +137 104 205 MediumPurple3 + 93 71 139 MediumPurple4 +255 225 255 thistle1 +238 210 238 thistle2 +205 181 205 thistle3 +139 123 139 thistle4 + 0 0 0 gray0 + 0 0 0 grey0 + 3 3 3 gray1 + 3 3 3 grey1 + 5 5 5 gray2 + 5 5 5 grey2 + 8 8 8 gray3 + 8 8 8 grey3 + 10 10 10 gray4 + 10 10 10 grey4 + 13 13 13 gray5 + 13 13 13 grey5 + 15 15 15 gray6 + 15 15 15 grey6 + 18 18 18 gray7 + 18 18 18 grey7 + 20 20 20 gray8 + 20 20 20 grey8 + 23 23 23 gray9 + 23 23 23 grey9 + 26 26 26 gray10 + 26 26 26 grey10 + 28 28 28 gray11 + 28 28 28 grey11 + 31 31 31 gray12 + 31 31 31 grey12 + 33 33 33 gray13 + 33 33 33 grey13 + 36 36 36 gray14 + 36 36 36 grey14 + 38 38 38 gray15 + 38 38 38 grey15 + 41 41 41 gray16 + 41 41 41 grey16 + 43 43 43 gray17 + 43 43 43 grey17 + 46 46 46 gray18 + 46 46 46 grey18 + 48 48 48 gray19 + 48 48 48 grey19 + 51 51 51 gray20 + 51 51 51 grey20 + 54 54 54 gray21 + 54 54 54 grey21 + 56 56 56 gray22 + 56 56 56 grey22 + 59 59 59 gray23 + 59 59 59 grey23 + 61 61 61 gray24 + 61 61 61 grey24 + 64 64 64 gray25 + 64 64 64 grey25 + 66 66 66 gray26 + 66 66 66 grey26 + 69 69 69 gray27 + 69 69 69 grey27 + 71 71 71 gray28 + 71 71 71 grey28 + 74 74 74 gray29 + 74 74 74 grey29 + 77 77 77 gray30 + 77 77 77 grey30 + 79 79 79 gray31 + 79 79 79 grey31 + 82 82 82 gray32 + 82 82 82 grey32 + 84 84 84 gray33 + 84 84 84 grey33 + 87 87 87 gray34 + 87 87 87 grey34 + 89 89 89 gray35 + 89 89 89 grey35 + 92 92 92 gray36 + 92 92 92 grey36 + 94 94 94 gray37 + 94 94 94 grey37 + 97 97 97 gray38 + 97 97 97 grey38 + 99 99 99 gray39 + 99 99 99 grey39 +102 102 102 gray40 +102 102 102 grey40 +105 105 105 gray41 +105 105 105 grey41 +107 107 107 gray42 +107 107 107 grey42 +110 110 110 gray43 +110 110 110 grey43 +112 112 112 gray44 +112 112 112 grey44 +115 115 115 gray45 +115 115 115 grey45 +117 117 117 gray46 +117 117 117 grey46 +120 120 120 gray47 +120 120 120 grey47 +122 122 122 gray48 +122 122 122 grey48 +125 125 125 gray49 +125 125 125 grey49 +127 127 127 gray50 +127 127 127 grey50 +130 130 130 gray51 +130 130 130 grey51 +133 133 133 gray52 +133 133 133 grey52 +135 135 135 gray53 +135 135 135 grey53 +138 138 138 gray54 +138 138 138 grey54 +140 140 140 gray55 +140 140 140 grey55 +143 143 143 gray56 +143 143 143 grey56 +145 145 145 gray57 +145 145 145 grey57 +148 148 148 gray58 +148 148 148 grey58 +150 150 150 gray59 +150 150 150 grey59 +153 153 153 gray60 +153 153 153 grey60 +156 156 156 gray61 +156 156 156 grey61 +158 158 158 gray62 +158 158 158 grey62 +161 161 161 gray63 +161 161 161 grey63 +163 163 163 gray64 +163 163 163 grey64 +166 166 166 gray65 +166 166 166 grey65 +168 168 168 gray66 +168 168 168 grey66 +171 171 171 gray67 +171 171 171 grey67 +173 173 173 gray68 +173 173 173 grey68 +176 176 176 gray69 +176 176 176 grey69 +179 179 179 gray70 +179 179 179 grey70 +181 181 181 gray71 +181 181 181 grey71 +184 184 184 gray72 +184 184 184 grey72 +186 186 186 gray73 +186 186 186 grey73 +189 189 189 gray74 +189 189 189 grey74 +191 191 191 gray75 +191 191 191 grey75 +194 194 194 gray76 +194 194 194 grey76 +196 196 196 gray77 +196 196 196 grey77 +199 199 199 gray78 +199 199 199 grey78 +201 201 201 gray79 +201 201 201 grey79 +204 204 204 gray80 +204 204 204 grey80 +207 207 207 gray81 +207 207 207 grey81 +209 209 209 gray82 +209 209 209 grey82 +212 212 212 gray83 +212 212 212 grey83 +214 214 214 gray84 +214 214 214 grey84 +217 217 217 gray85 +217 217 217 grey85 +219 219 219 gray86 +219 219 219 grey86 +222 222 222 gray87 +222 222 222 grey87 +224 224 224 gray88 +224 224 224 grey88 +227 227 227 gray89 +227 227 227 grey89 +229 229 229 gray90 +229 229 229 grey90 +232 232 232 gray91 +232 232 232 grey91 +235 235 235 gray92 +235 235 235 grey92 +237 237 237 gray93 +237 237 237 grey93 +240 240 240 gray94 +240 240 240 grey94 +242 242 242 gray95 +242 242 242 grey95 +245 245 245 gray96 +245 245 245 grey96 +247 247 247 gray97 +247 247 247 grey97 +250 250 250 gray98 +250 250 250 grey98 +252 252 252 gray99 +252 252 252 grey99 +255 255 255 gray100 +255 255 255 grey100 +169 169 169 dark grey +169 169 169 DarkGrey +169 169 169 dark gray +169 169 169 DarkGray + 0 0 139 dark blue + 0 0 139 DarkBlue + 0 139 139 dark cyan + 0 139 139 DarkCyan +139 0 139 dark magenta +139 0 139 DarkMagenta +139 0 0 dark red +139 0 0 DarkRed +144 238 144 light green +144 238 144 LightGreen +220 20 60 crimson + 75 0 130 indigo +128 128 0 olive +102 51 153 rebecca purple +102 51 153 RebeccaPurple +192 192 192 silver + 0 128 128 teal diff --git a/widget/milsko/milskosrc/resource/wayland/wlr-layer-shell-unstable-v1.xml b/widget/milsko/milskosrc/resource/wayland/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 0000000000..f9ee0ff7d5 --- /dev/null +++ b/widget/milsko/milskosrc/resource/wayland/wlr-layer-shell-unstable-v1.xml @@ -0,0 +1,451 @@ + + + + Copyright © 2017 Drew DeVault + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Clients can use this interface to assign the surface_layer role to + wl_surfaces. Such surfaces are assigned to a "layer" of the output and + rendered with a defined z-depth respective to each other. They may also be + anchored to the edges and corners of a screen and specify input handling + semantics. This interface should be suitable for the implementation of + many desktop shell components, and a broad number of other applications + that interact with the desktop. + + + + + Create a layer surface for an existing surface. This assigns the role of + layer_surface, or raises a protocol error if another role is already + assigned. + + Creating a layer surface from a wl_surface which has a buffer attached + or committed is a client error, and any attempts by a client to attach + or manipulate a buffer prior to the first layer_surface.configure call + must also be treated as errors. + + After creating a layer_surface object and setting it up, the client + must perform an initial commit without any buffer attached. + The compositor will reply with a layer_surface.configure event. + The client must acknowledge it and is then allowed to attach a buffer + to map the surface. + + You may pass NULL for output to allow the compositor to decide which + output to use. Generally this will be the one that the user most + recently interacted with. + + Clients can specify a namespace that defines the purpose of the layer + surface. + + + + + + + + + + + + + + + + + These values indicate which layers a surface can be rendered in. They + are ordered by z depth, bottom-most first. Traditional shell surfaces + will typically be rendered between the bottom and top layers. + Fullscreen shell surfaces are typically rendered at the top layer. + Multiple surfaces can share a single layer, and ordering within a + single layer is undefined. + + + + + + + + + + + + + This request indicates that the client will not use the layer_shell + object any more. Objects that have been created through this instance + are not affected. + + + + + + + An interface that may be implemented by a wl_surface, for surfaces that + are designed to be rendered as a layer of a stacked desktop-like + environment. + + Layer surface state (layer, size, anchor, exclusive zone, + margin, interactivity) is double-buffered, and will be applied at the + time wl_surface.commit of the corresponding wl_surface is called. + + Attaching a null buffer to a layer surface unmaps it. + + Unmapping a layer_surface means that the surface cannot be shown by the + compositor until it is explicitly mapped again. The layer_surface + returns to the state it had right after layer_shell.get_layer_surface. + The client can re-map the surface by performing a commit without any + buffer attached, waiting for a configure event and handling it as usual. + + + + + Sets the size of the surface in surface-local coordinates. The + compositor will display the surface centered with respect to its + anchors. + + If you pass 0 for either value, the compositor will assign it and + inform you of the assignment in the configure event. You must set your + anchor to opposite edges in the dimensions you omit; not doing so is a + protocol error. Both values are 0 by default. + + Size is double-buffered, see wl_surface.commit. + + + + + + + + Requests that the compositor anchor the surface to the specified edges + and corners. If two orthogonal edges are specified (e.g. 'top' and + 'left'), then the anchor point will be the intersection of the edges + (e.g. the top left corner of the output); otherwise the anchor point + will be centered on that edge, or in the center if none is specified. + + Anchor is double-buffered, see wl_surface.commit. + + + + + + + Requests that the compositor avoids occluding an area with other + surfaces. The compositor's use of this information is + implementation-dependent - do not assume that this region will not + actually be occluded. + + A positive value is only meaningful if the surface is anchored to one + edge or an edge and both perpendicular edges. If the surface is not + anchored, anchored to only two perpendicular edges (a corner), anchored + to only two parallel edges or anchored to all edges, a positive value + will be treated the same as zero. + + A positive zone is the distance from the edge in surface-local + coordinates to consider exclusive. + + Surfaces that do not wish to have an exclusive zone may instead specify + how they should interact with surfaces that do. If set to zero, the + surface indicates that it would like to be moved to avoid occluding + surfaces with a positive exclusive zone. If set to -1, the surface + indicates that it would not like to be moved to accommodate for other + surfaces, and the compositor should extend it all the way to the edges + it is anchored to. + + For example, a panel might set its exclusive zone to 10, so that + maximized shell surfaces are not shown on top of it. A notification + might set its exclusive zone to 0, so that it is moved to avoid + occluding the panel, but shell surfaces are shown underneath it. A + wallpaper or lock screen might set their exclusive zone to -1, so that + they stretch below or over the panel. + + The default value is 0. + + Exclusive zone is double-buffered, see wl_surface.commit. + + + + + + + Requests that the surface be placed some distance away from the anchor + point on the output, in surface-local coordinates. Setting this value + for edges you are not anchored to has no effect. + + The exclusive zone includes the margin. + + Margin is double-buffered, see wl_surface.commit. + + + + + + + + + + Types of keyboard interaction possible for layer shell surfaces. The + rationale for this is twofold: (1) some applications are not interested + in keyboard events and not allowing them to be focused can improve the + desktop experience; (2) some applications will want to take exclusive + keyboard focus. + + + + + This value indicates that this surface is not interested in keyboard + events and the compositor should never assign it the keyboard focus. + + This is the default value, set for newly created layer shell surfaces. + + This is useful for e.g. desktop widgets that display information or + only have interaction with non-keyboard input devices. + + + + + Request exclusive keyboard focus if this surface is above the shell surface layer. + + For the top and overlay layers, the seat will always give + exclusive keyboard focus to the top-most layer which has keyboard + interactivity set to exclusive. If this layer contains multiple + surfaces with keyboard interactivity set to exclusive, the compositor + determines the one receiving keyboard events in an implementation- + defined manner. In this case, no guarantee is made when this surface + will receive keyboard focus (if ever). + + For the bottom and background layers, the compositor is allowed to use + normal focus semantics. + + This setting is mainly intended for applications that need to ensure + they receive all keyboard events, such as a lock screen or a password + prompt. + + + + + This requests the compositor to allow this surface to be focused and + unfocused by the user in an implementation-defined manner. The user + should be able to unfocus this surface even regardless of the layer + it is on. + + Typically, the compositor will want to use its normal mechanism to + manage keyboard focus between layer shell surfaces with this setting + and regular toplevels on the desktop layer (e.g. click to focus). + Nevertheless, it is possible for a compositor to require a special + interaction to focus or unfocus layer shell surfaces (e.g. requiring + a click even if focus follows the mouse normally, or providing a + keybinding to switch focus between layers). + + This setting is mainly intended for desktop shell components (e.g. + panels) that allow keyboard interaction. Using this option can allow + implementing a desktop shell that can be fully usable without the + mouse. + + + + + + + Set how keyboard events are delivered to this surface. By default, + layer shell surfaces do not receive keyboard events; this request can + be used to change this. + + This setting is inherited by child surfaces set by the get_popup + request. + + Layer surfaces receive pointer, touch, and tablet events normally. If + you do not want to receive them, set the input region on your surface + to an empty region. + + Keyboard interactivity is double-buffered, see wl_surface.commit. + + + + + + + This assigns an xdg_popup's parent to this layer_surface. This popup + should have been created via xdg_surface::get_popup with the parent set + to NULL, and this request must be invoked before committing the popup's + initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make an ack_configure request sometime before the commit + request, passing along the serial of the configure event. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + A client is not required to commit immediately after sending + an ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, but + only the last request sent before a commit indicates which configure + event the client really is responding to. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + + diff --git a/widget/milsko/milskosrc/src/abstract/charset.c b/widget/milsko/milskosrc/src/abstract/charset.c new file mode 100644 index 0000000000..3bd76252ff --- /dev/null +++ b/widget/milsko/milskosrc/src/abstract/charset.c @@ -0,0 +1,95 @@ +#include + +#ifndef CP_UTF8 +#define CP_UTF8 65001 +#endif + +char* MwACPToUTF8(const char* input) { +#if defined(_WIN32) && defined(MW_HAS_WCHAR) + int mbbytes = (strlen(input) + 1) * 4; + int wbytes = 0; + int len; + + wchar_t* wout; + char* mbout = malloc(mbbytes); + + wbytes = MultiByteToWideChar(CP_ACP, 0, input, strlen(input), NULL, 0) * sizeof(wchar_t); + if(wbytes == 0) { + free(mbout); + return MwStringDuplicate(input); + } + + wout = malloc(wbytes + sizeof(wchar_t)); + len = wbytes / sizeof(wchar_t); + + memset(wout, 0, wbytes); + memset(mbout, 0, mbbytes); + + len = MultiByteToWideChar(CP_ACP, 0, input, strlen(input), wout, len); + if(len == 0) { + free(mbout); + free(wout); + return MwStringDuplicate(input); + } + wout[len] = 0; + + len = WideCharToMultiByte(CP_UTF8, 0, wout, len, mbout, mbbytes, 0, 0); + if(len == 0) { + free(mbout); + free(wout); + return MwStringDuplicate(input); + } + mbout[len] = 0; + + free(wout); + + return mbout; +#else + return MwStringDuplicate(input); +#endif +} + +char* MwUTF8ToACP(const char* input) { +#if defined(_WIN32) && defined(MW_HAS_WCHAR) + int mbbytes = (strlen(input) + 1) * 4; + int wbytes = 0; + int len; + + wchar_t* wout; + char* mbout = malloc(mbbytes); + + wbytes = MultiByteToWideChar(CP_UTF8, 0, input, strlen(input), NULL, 0) * sizeof(wchar_t); + if(wbytes == 0) { + free(mbout); + return MwStringDuplicate(input); + } + + wout = malloc(wbytes + sizeof(wchar_t)); + len = wbytes / sizeof(wchar_t); + + memset(wout, 0, wbytes); + memset(mbout, 0, mbbytes); + + len = MultiByteToWideChar(CP_UTF8, 0, input, strlen(input), wout, len); + if(len == 0) { + free(mbout); + free(wout); + return MwStringDuplicate(input); + } + wout[len] = 0; + + len = WideCharToMultiByte(CP_ACP, 0, wout, len, mbout, mbbytes, 0, 0); + if(len == 0) { + free(mbout); + free(wout); + return MwStringDuplicate(input); + } + mbout[len] = 0; + + free(wout); + + return mbout; +#else + return MwStringDuplicate(input); +#endif +} diff --git a/widget/milsko/milskosrc/src/abstract/directory.c b/widget/milsko/milskosrc/src/abstract/directory.c new file mode 100644 index 0000000000..ac5a382d1e --- /dev/null +++ b/widget/milsko/milskosrc/src/abstract/directory.c @@ -0,0 +1,223 @@ +#include + +#ifdef _WIN32 +typedef struct dir { + HANDLE hFind; + WIN32_FIND_DATA ffd; + int next; +} dir_t; +#elif defined(CLASSIC_MAC_OS) +typedef struct dir { + int dummy; +} dir_t; +#else +typedef struct dir { + DIR* dir; + char* base; +} dir_t; +#endif + +void* MwDirectoryOpen(const char* path) { + dir_t* dir = malloc(sizeof(*dir)); +#ifdef _WIN32 + char* p = malloc(strlen(path) + 2 + 1); + strcpy(p, path); + if(strchr(path, '/') != NULL) { + strcat(p, "/"); + } else { + strcat(p, "\\"); + } + strcat(p, "*"); + if((dir->hFind = FindFirstFile(p, &dir->ffd)) == INVALID_HANDLE_VALUE) { + free(p); + free(dir); + return NULL; + } + free(p); + dir->next = 1; +#elif defined(CLASSIC_MAC_OS) +/* todo */ +#else + if((dir->dir = opendir(path)) == NULL) { + free(dir); + return NULL; + } + dir->base = malloc(strlen(path) + 1); + strcpy(dir->base, path); +#endif + + return dir; +} + +void MwDirectoryClose(void* handle) { + dir_t* dir = handle; +#ifdef _WIN32 + FindClose(dir->hFind); +#elif defined(CLASSIC_MAC_OS) +/* todo */ +#else + closedir(dir->dir); + free(dir->base); +#endif + free(handle); +} + +MwDirectoryEntry* MwDirectoryRead(void* handle) { + dir_t* dir = handle; + MwDirectoryEntry* entry = malloc(sizeof(*entry)); +#ifdef _WIN32 + ULARGE_INTEGER* l; + + if(!dir->next) return NULL; + + entry->name = MwStringDuplicate(dir->ffd.cFileName); + if(dir->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + entry->type = MwDIRECTORY_DIRECTORY; + } else { + entry->type = MwDIRECTORY_FILE; + } + entry->size = 0; + + entry->size = entry->size << 32; + entry->size |= dir->ffd.nFileSizeHigh; + entry->size = entry->size << 32; + entry->size |= dir->ffd.nFileSizeLow; + + l = (ULARGE_INTEGER*)&dir->ffd.ftLastWriteTime; + + entry->mtime = l->QuadPart / 10000000 - 11644473600; + + dir->next = FindNextFile(dir->hFind, &dir->ffd); +#elif defined(CLASSIC_MAC_OS) +/* todo */ +#else + struct dirent* d; + struct stat s; + char* p; + if((d = readdir(dir->dir)) == NULL) { + free(entry); + return NULL; + } + entry->name = MwStringDuplicate(d->d_name); + + p = malloc(strlen(dir->base) + 1 + strlen(d->d_name) + 1); + strcpy(p, dir->base); + strcat(p, "/"); + strcat(p, d->d_name); + + stat(p, &s); + if(S_ISDIR(s.st_mode)) { + entry->type = MwDIRECTORY_DIRECTORY; + } else { + entry->type = MwDIRECTORY_FILE; + } + entry->size = s.st_size; + entry->mtime = s.st_mtime; + + free(p); +#endif + + return entry; +} + +void MwDirectoryFreeEntry(MwDirectoryEntry* entry) { + free(entry->name); + free(entry); +} + +char* MwDirectoryCurrent(void) { +#ifdef _WIN32 + int len = GetCurrentDirectory(0, NULL); + char* out = malloc(len); + + GetCurrentDirectory(len, out); + + return out; +#elif CLASSIC_MAC_OS + return ""; +#else + return getcwd(NULL, 0); +#endif +} + +#ifdef _WIN32 +#define DIRSEP '\\' +#else +#define DIRSEP '/' +#endif +static void MwDirectoryJoinSingle(char* target, char* p) { + int i; + if(strcmp(p, ".") == 0) return; + + for(i = strlen(target) - 1; i >= 0; i--) { + if(target[i] == DIRSEP) { + target[i] = 0; + } else { + break; + } + } + + if(strcmp(p, "..") == 0) { + for(i = strlen(target) - 1; i >= 0; i--) { + if(target[i] != DIRSEP) { + target[i] = 0; + } else { + break; + } + } + } else { + char b[2]; + b[0] = DIRSEP; + b[1] = 0; + + strcat(target, b); + strcat(target, p); + } + + for(i = strlen(target) - 1; i >= 0; i--) { + if(target[i] == DIRSEP) { + target[i] = 0; + } else { + break; + } + } + + if(strchr(target, DIRSEP) == NULL) { + char b[2]; + b[0] = DIRSEP; + b[1] = 0; + + strcat(target, b); + } +} + +char* MwDirectoryJoin(char* a, char* b) { + char* p = malloc(strlen(a) + 1 + strlen(b) + 1); + char* bdup = MwStringDuplicate(b); + char* b2 = bdup; + int i; + + strcpy(p, a); + for(i = strlen(p) - 1; i >= 0; i--) { + if(p[i] == DIRSEP) { + p[i] = 0; + } else { + break; + } + } + while(b2 != NULL) { + char* current = b2; + + b2 = strchr(b2, DIRSEP); + if(b2 != NULL) { + b2[0] = 0; + } + + MwDirectoryJoinSingle(p, current); + + if(b2 != NULL) b2++; + } + free(bdup); + + return p; +} diff --git a/widget/milsko/milskosrc/src/abstract/dynamic.c b/widget/milsko/milskosrc/src/abstract/dynamic.c new file mode 100644 index 0000000000..58bc8312d6 --- /dev/null +++ b/widget/milsko/milskosrc/src/abstract/dynamic.c @@ -0,0 +1,63 @@ +#include + +#if defined(_WIN32) +void* MwDynamicOpen(const char* path) { + return LoadLibrary(path); +} + +void* MwDynamicSymbol(void* handle, const char* symbol) { + return GetProcAddress(handle, symbol); +} + +void MwDynamicClose(void* handle) { + FreeLibrary(handle); +} +#elif defined(CLASSIC_MAC_OS) +void* MwDynamicOpen(const char* path) { + // CFragConnectionID connID; + // Ptr* addr; + // unsigned char err[255]; + + // if(GetSharedLibrary((ConstStr63Param)path, kPowerPCCFragArch, kPrivateCFragCopy, + // &connID, addr, err)) { + // printf("Error getting %s: %s\n", path, err); + // return NULL; + // }; + // return connID; + printf("MwDynamicOpen not implemented yet.\n"); + getchar(); + return NULL; +} + +void* MwDynamicSymbol(void* handle, const char* symbol) { + // CFragConnectionID connID = (CFragConnectionID)handle; + // Ptr* symAddr; + // CFragSymbolClass* symClass; + // OSErr err; + // if((err = FindSymbol(connID, (ConstStr63Param)symbol, symAddr, symClass))) { + // printf("Error getting %s: %d\n", symbol, err); + // return NULL; + // }; + // return symAddr; + printf("MwDynamicSymbol not implemented yet.\n"); + getchar(); + return NULL; +} + +void MwDynamicClose(void* handle) { + // CFragConnectionID connID = (CFragConnectionID)handle; + // CloseConnection(&connID); +} +#elif defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) +void* MwDynamicOpen(const char* path) { + return dlopen(path, RTLD_LOCAL | RTLD_LAZY); +} + +void* MwDynamicSymbol(void* handle, const char* symbol) { + return dlsym(handle, symbol); +} + +void MwDynamicClose(void* handle) { + dlclose(handle); +} +#endif diff --git a/widget/milsko/milskosrc/src/abstract/time.c b/widget/milsko/milskosrc/src/abstract/time.c new file mode 100644 index 0000000000..59e9774526 --- /dev/null +++ b/widget/milsko/milskosrc/src/abstract/time.c @@ -0,0 +1,79 @@ +#include + +#if defined(_WIN32) +long MwTimeGetTick(void) { + return timeGetTime(); +} + +void MwTimeSleep(int ms) { + Sleep(ms); +} +#elif defined(__APPLE__) +long MwTimeGetTick(void) { + struct timespec ts; + long n = 0; + clock_serv_t cclock; + mach_timespec_t mts; + + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + + n += ts.tv_nsec / 1000 / 1000; + n += ts.tv_sec * 1000; + + return n; +} +void MwTimeSleep(int ms) { + struct timespec ts; + + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000 * 1000; + + nanosleep(&ts, NULL); +} +#elif defined(CLASSIC_MAC_OS) +// static TMTask tm; +// static int timer; +// void timerUpdateFunc(void) { +// timer += 1; +// PrimeTime((QElemPtr)&tm, 1); +// }; + +long MwTimeGetTick(void) { + UnsignedWide h; + Microseconds(&h); + return h.lo; +} +void MwTimeSleep(int ms) { + // tm.tmAddr = NewTimerProc(timerUpdateFunc); + // tm.tmWakeUp = 0; + // tm.tmReserved = 0; + + // InsTime((QElemPtr)&tm); + // PrimeTime((QElemPtr)&tm, 1); + + // DisposeTimerUPP(tm.tmAddr); +} +#elif defined(__unix__) || defined(__HAIKU__) +long MwTimeGetTick(void) { + struct timespec ts; + long n = 0; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + n += ts.tv_nsec / 1000 / 1000; + n += ts.tv_sec * 1000; + + return n; +} + +void MwTimeSleep(int ms) { + struct timespec ts; + + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000000; + + nanosleep(&ts, NULL); +} +#endif diff --git a/widget/milsko/milskosrc/src/backend/.gitignore b/widget/milsko/milskosrc/src/backend/.gitignore new file mode 100644 index 0000000000..137387c58f --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/.gitignore @@ -0,0 +1 @@ +wayland*protocol.c diff --git a/widget/milsko/milskosrc/src/backend/cairo.c b/widget/milsko/milskosrc/src/backend/cairo.c new file mode 100644 index 0000000000..0c26ff3c61 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/cairo.c @@ -0,0 +1,265 @@ +#include + +#include "../../external/stb_ds.h" + +cairo_call_table_t cairo_call_tbl; + +void MwLLCairoPolygon(struct _MwLLCairo handle, MwPoint* points, int points_count, MwLLColor color) { + int i; + cairo_set_source_rgba(handle.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); + cairo_new_path(handle.front_cairo); + for(i = 0; i < points_count; i++) { + if(i == 0) { + cairo_move_to(handle.front_cairo, points[i].x, points[i].y); + } else { + cairo_line_to(handle.front_cairo, points[i].x, points[i].y); + } + } + cairo_close_path(handle.front_cairo); + + cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_SOURCE); + cairo_fill(handle.front_cairo); + cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_OVER); +}; + +void MwLLCairoLine(struct _MwLLCairo handle, MwPoint* points, MwLLColor color) { + int i; + + cairo_set_antialias(handle.front_cairo, CAIRO_ANTIALIAS_NONE); + cairo_set_line_cap(handle.front_cairo, CAIRO_LINE_CAP_SQUARE); + cairo_set_source_rgba(handle.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); + cairo_new_path(handle.front_cairo); + for(i = 0; i < 2; i++) { + if(i == 0) { + cairo_move_to(handle.front_cairo, points[i].x, points[i].y); + } else { + cairo_line_to(handle.front_cairo, points[i].x, points[i].y); + } + } + cairo_close_path(handle.front_cairo); + cairo_stroke(handle.front_cairo); +}; + +MwLLPixmap MwLLCairoCreatePixmap(struct _MwLLCairo handle, unsigned char* data, int width, int height) { + MwLLPixmap r = malloc(sizeof(*r)); + (void)handle; + + if(width >= INT16_MAX) width = INT16_MAX; + if(height >= INT16_MAX) height = INT16_MAX; + + r->common.width = width; + r->common.height = height; + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + r->wayland.cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + + MwLLPixmapUpdate(r); + + return r; +} + +void MwLLCairoPixmapUpdate(MwLLPixmap r) { + int i; + unsigned char* d; + + cairo_surface_flush(r->wayland.cs); + d = cairo_image_surface_get_data(r->wayland.cs); + for(i = 0; i < r->common.width * r->common.height * 4; i += 4) { + MwU32* p = (MwU32*)&d[i]; + *p <<= 8; + *p |= r->common.raw[i + 3]; + *p <<= 8; + *p |= r->common.raw[i + 0]; + *p <<= 8; + *p |= r->common.raw[i + 1]; + *p <<= 8; + *p |= r->common.raw[i + 2]; + } + cairo_surface_mark_dirty(r->wayland.cs); +} + +void MwLLCairoDestroyPixmap(MwLLPixmap pixmap) { + cairo_surface_destroy(pixmap->wayland.cs); + free(pixmap->common.raw); + free(pixmap); +} + +void MwLLCairoDrawPixmap(struct _MwLLCairo handle, MwRect* rect, MwLLPixmap pixmap) { + cairo_t* c; + cairo_surface_t* cs; + cairo_t* selected_cairo = handle.selected_cairo ? handle.selected_cairo : handle.front_cairo; + cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); + c = cairo_create(cs); + + if(rect->width <= 0 || rect->height <= 0 || pixmap->common.width <= 0 || pixmap->common.height <= 0) return; + if(rect->width >= INT16_MAX) rect->width = INT16_MAX; + if(rect->height >= INT16_MAX) rect->height = INT16_MAX; + + cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); + + cairo_set_source_surface(c, pixmap->cairo.cs, 0, 0); + cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); + + cairo_set_operator(handle.front_cairo, CAIRO_OPERATOR_OVER); + + cairo_paint(c); + + cairo_set_source_surface(selected_cairo, cs, rect->x, rect->y); + cairo_paint(selected_cairo); + + cairo_destroy(c); + cairo_surface_destroy(cs); +}; + +void MwLLCairoFrontSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) { + if(data) { + cairo->front_cs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, width * 4); + } else { + cairo->front_cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + } + cairo->front_cairo = cairo_create(cairo->front_cs); +} + +void MwLLCairoBackSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) { + if(data) { + cairo->back_cs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, width * 4); + } else { + cairo->back_cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + } + cairo->back_cairo = cairo_create(cairo->back_cs); +} + +void MwLLCairoFrontDestroy(struct _MwLLCairo* cairo) { + cairo_destroy(cairo->front_cairo); + cairo_surface_destroy(cairo->front_cs); +}; +void MwLLCairoBackDestroy(struct _MwLLCairo* cairo) { + cairo_destroy(cairo->back_cairo); + cairo_surface_destroy(cairo->back_cs); +}; + +void MwLLCairoDestroy(struct _MwLLCairo handle) { + // MwLLCairoFrontDestroy(&handle); + // MwLLCairoBackDestroy(&handle); +} + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); + MwLLCreateCommon(r); + + r->cairo.width = width; + r->cairo.height = height; + r->cairo.x = x; + r->cairo.y = x; + + r->cairo.toplevel = !parent; + r->cairo.parent = parent; + + MwLLCairoFrontSetup(&r->cairo, NULL, r->cairo.width, r->cairo.height); + MwLLCairoBackSetup(&r->cairo, NULL, r->cairo.width, r->cairo.height); + + return r; +} +static void MwLLDestroyImpl(MwLL handle) { + MwLLCairoDestroy(handle->cairo); + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + handle->cairo.selected_cairo = handle->cairo.front_cairo; +} +static void MwLLEndDrawImpl(MwLL handle) { +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + MwLLCairoPolygon(handle->cairo, points, points_count, color); +} +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + MwLLCairoLine(handle->cairo, points, color); +} +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + (void)handle; + *x = handle->cairo.x; + *y = handle->cairo.y; + *w = handle->cairo.width; + *h = handle->cairo.height; +} +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + handle->cairo.x = x; + handle->cairo.y = y; +} +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + handle->cairo.width = w; + handle->cairo.height = h; +} +static void MwLLFreeColorImpl(MwLLColor color) {} + +static MwBool lmao = MwFALSE; +static int MwLLPendingImpl(MwLL handle) { + lmao = !lmao; + return lmao; +} +static void MwLLNextEventImpl(MwLL handle) { + MwLLDispatch(handle, draw, NULL); +} +static void MwLLSetTitleImpl(MwLL handle, const char* title) {} +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + return MwLLCairoCreatePixmap(handle->cairo, data, width, height); +} +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + MwLLCairoPixmapUpdate(r); +} +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + MwLLCairoPixmapUpdate(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + MwLLCairoDrawPixmap(handle->cairo, rect, pixmap); +} +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) {} +static void MwLLForceRenderImpl(MwLL handle) {} +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) {} +static void MwLLDetachImpl(MwLL handle, MwPoint* point) {} +static void MwLLShowImpl(MwLL handle, int show) {} +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) {} +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) {} +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) {} +static void MwLLFocusImpl(MwLL handle) {} +static void MwLLGrabPointerImpl(MwLL handle, int toggle) {} +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) {} +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) {} +static void MwLLMakeToolWindowImpl(MwLL handle) {} +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) {} +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) {} +static void MwLLBeginStateChangeImpl(MwLL handle) {} +static void MwLLEndStateChangeImpl(MwLL handle) {} +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) {} +static MwBool MwLLDoModernImpl(MwLL handle) { + return MwFALSE; +} +static void MwLLRaiseImpl(MwLL handle) {} +static void MwLLClipImpl(MwLL handle, MwRect* rect) {} +static int MwLLCairoCallInitImpl(void) { + if(cairo_load_funcs() != 0) { + return 1; + } + return 0; +} +#include "call.c" +CALL(Cairo); diff --git a/widget/milsko/milskosrc/src/backend/call.c b/widget/milsko/milskosrc/src/backend/call.c new file mode 100644 index 0000000000..f84247f7d7 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/call.c @@ -0,0 +1,65 @@ +/* This file gets included by backend */ +#define CALL(NAME) \ + int MwLL##NAME##CallInit(void) { \ + int st; \ +\ + if((st = MwLL##NAME##CallInitImpl()) != 0) return st; \ +\ + MwLLCreate = MwLLCreateImpl; \ + MwLLDestroy = MwLLDestroyImpl; \ +\ + MwLLPolygon = MwLLPolygonImpl; \ + MwLLLine = MwLLLineImpl; \ + MwLLBeginDraw = MwLLBeginDrawImpl; \ + MwLLEndDraw = MwLLEndDrawImpl; \ +\ + MwLLAllocColor = MwLLAllocColorImpl; \ + MwLLColorUpdate = MwLLColorUpdateImpl; \ + MwLLFreeColor = MwLLFreeColorImpl; \ +\ + MwLLGetXYWH = MwLLGetXYWHImpl; \ + MwLLSetXY = MwLLSetXYImpl; \ + MwLLSetWH = MwLLSetWHImpl; \ +\ + MwLLSetTitle = MwLLSetTitleImpl; \ +\ + MwLLPending = MwLLPendingImpl; \ + MwLLNextEvent = MwLLNextEventImpl; \ +\ + MwLLCreatePixmap = MwLLCreatePixmapImpl; \ + MwLLPixmapUpdate = MwLLPixmapUpdateImpl; \ + MwLLDestroyPixmap = MwLLDestroyPixmapImpl; \ + MwLLDrawPixmap = MwLLDrawPixmapImpl; \ + MwLLSetIcon = MwLLSetIconImpl; \ +\ + MwLLForceRender = MwLLForceRenderImpl; \ +\ + MwLLSetCursor = MwLLSetCursorImpl; \ + MwLLDetach = MwLLDetachImpl; \ + MwLLShow = MwLLShowImpl; \ +\ + MwLLSetSizeHints = MwLLSetSizeHintsImpl; \ + MwLLMakeBorderless = MwLLMakeBorderlessImpl; \ + MwLLMakeToolWindow = MwLLMakeToolWindowImpl; \ + MwLLMakePopup = MwLLMakePopupImpl; \ +\ + MwLLBeginStateChange = MwLLBeginStateChangeImpl; \ + MwLLEndStateChange = MwLLEndStateChangeImpl; \ +\ + MwLLFocus = MwLLFocusImpl; \ + MwLLGrabPointer = MwLLGrabPointerImpl; \ +\ + MwLLSetClipboard = MwLLSetClipboardImpl; \ + MwLLGetClipboard = MwLLGetClipboardImpl; \ +\ + MwLLGetCursorCoord = MwLLGetCursorCoordImpl; \ + MwLLGetScreenSize = MwLLGetScreenSizeImpl; \ +\ + MwLLSetDarkTheme = MwLLSetDarkThemeImpl; \ + MwLLDoModern = MwLLDoModernImpl; \ +\ + MwLLRaise = MwLLRaiseImpl; \ +\ + MwLLClip = MwLLClipImpl; \ + return 0; \ + } diff --git a/widget/milsko/milskosrc/src/backend/classicmacos.c b/widget/milsko/milskosrc/src/backend/classicmacos.c new file mode 100644 index 0000000000..d3da454b12 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/classicmacos.c @@ -0,0 +1,391 @@ +#include +#include + +#include "../../external/stb_ds.h" + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); + MwLLCreateCommon(r); + + r->cmacos.parent = parent; + + if(x == MwDEFAULT) { + x = (qd.screenBits.bounds.right / 2) - (width / 2); + } + if(y == MwDEFAULT) { + y = (qd.screenBits.bounds.bottom / 2) - (height / 2); + } + + /* todo: how do we set parent windows? If we can't, what is our equivalant to MacOS's NSViews, Wayland's subsurfaces, etc.? */ + SetRect(&r->cmacos.winRect, x, y, width, height); + r->cmacos.window = newcwindow(nil, &r->cmacos.winRect, "", true, + documentProc, (WindowPtr)(-1), true, 0); + SetPort(r->cmacos.window); + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MwLLDestroyCommon(handle); + + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { +} + +static void MwLLEndDrawImpl(MwLL handle) { +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + int i; + PolyHandle p; + RGBColor col; + + SetPort(handle->cmacos.window); + BeginUpdate(handle->cmacos.window); + + p = OpenPoly(); + col.red = color->common.red * 0x101; + col.green = color->common.green * 0x101; + col.blue = color->common.blue * 0x101; + + for(i = 0; i < points_count; i++) { + if(i == 0) { + MoveTo(points[i].x, points[i].y); + } else { + LineTo(points[i].x, points[i].y); + } + } + + ClosePoly(); + + PenMode(patCopy); + RGBForeColor(&col); + PaintPoly(p); + + KillPoly(p); + + EndUpdate(handle->cmacos.window); +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + RGBColor col; + SetPort(handle->cmacos.window); + + col.red = color->common.red; + col.green = color->common.green; + col.blue = color->common.blue; + + RGBForeColor(&col); + + PenMode(patCopy); + + MoveTo(points[0].x, points[0].y); + LineTo(points[1].x, points[1].y); +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} + +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + Rect bounds; + GetWindowBounds(handle->cmacos.window, kWindowContentRgn, &bounds); + *x = bounds.left; + *y = bounds.top; + *w = bounds.right; + *h = bounds.bottom; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + MoveWindow(handle->cmacos.window, x, y, MwTRUE); +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + SizeWindow(handle->cmacos.window, w, h, MwTRUE); +} + +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} + +static int MwLLPendingImpl(MwLL handle) { + YieldToAnyThread(); + return EventAvail(everyEvent, &handle->cmacos.event); +} + +static void MwLLNextEventImpl(MwLL handle) { + EventRecord event; + GetNextEvent(everyEvent, &event); + + switch(event.what) { + case updateEvt: + { + /* + This is our blocker for getting anything running. + This needs to be called at this point to start drawing anything. + ...It locks up and/or crashes the entire system. At least on SheepShaver. + It's not a stack overflow, it's not anything in the drawing functions. + It's *something* else. But because Classic Mac OS development is like + digging up forbidden tombs while stabbing yourself in the eye several times, + I don't know what. + + Fun fact: for as much as everyone loves to glaze about AI being the future + of programming, even Claude got confused when I gave up and tried to ask it + for help. Information about Classic Mac OS probably takes up 0.0001% of its + knowledge base; god knows it's hard enough finding information online about + this! + */ + MwLLDispatch(handle, draw, NULL); + } break; + case osEvt: + break; + case mouseUp: + { + // MwLLMouse m; + // m.button = MwLLMouseLeft; + // if(___curWindow->mouseButtonCallback != NULL) { + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // if(___curWindow->keyStateMap[MK_LCTRL] == 1) { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods); + // } else { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods); + // } + // } + } + case mouseDown: + { + // // start with callback stuff + // if(___curWindow->mouseButtonCallback != NULL) { + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // if(___curWindow->keyStateMap[MK_LCTRL] == 1) { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); + // } else { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); + // } + // } + + // then do system stuff + switch(FindWindow(event.where, &handle->cmacos.window)) { + case inDrag: + DragWindow(handle->cmacos.window, event.where, &qd.screenBits.bounds); + // if(___curWindow->windowPosCallback != NULL) { + // ___curWindow->windowPosCallback(___curWindow, event.where.h, + // event.where.v); + // } + break; + case inGrow: + { + long growResult = + GrowWindow(handle->cmacos.window, event.where, &qd.screenBits.bounds); + + int width = growResult & 0xFFFF; + int height = growResult >> 16; + + SizeWindow(handle->cmacos.window, growResult & 0xFFFF, growResult >> 16, true); + + Rect rect; + GetWindowBounds(handle->cmacos.window, kWindowStructureRgn, &rect); + rect.right = width; + rect.bottom = height; + SetWindowBounds(handle->cmacos.window, kWindowStructureRgn, &rect); + + // ___curWindow->width = width; + // ___curWindow->height = height; + + // if(___curWindow->windowSizeCallback != NULL) { + // ___curWindow->windowSizeCallback(___curWindow, width, height); + // } + // if(___curWindow->windowSetFramebufferSizeCallback != NULL) { + // ___curWindow->windowSetFramebufferSizeCallback(___curWindow, + // width, height); + // } + } break; + + case inGoAway: + { + if(TrackGoAway(handle->cmacos.window, event.where)) { + MwLLDispatch(handle, close, NULL); + // if(___curWindow->windowCloseCallback != NULL) { + // ___curWindow->windowCloseCallback(___curWindow); + // } + // ___curWindow->shouldClose = true; + } + } break; + } + } + case autoKey: + case keyDown: + case keyUp: + { + // // key char stuff + // unsigned char ch = (event.message & charCodeMask); + // if(*___curWindow->charCallback != NULL) { + // ___curWindow->charCallback(___curWindow, ch); + // } + + // // key state map + // unsigned char key = (event.message & keyCodeMask) >> 8; + // ___curWindow->keyStateMap[key] = 0; + // if(event.what == keyDown || event.what == autoKey) { + // ___curWindow->keyStateMap[key] &= 1; + // } + + // if(*___curWindow->keyCallback != NULL) { + // int key = MacKeyToGLFWKey(event.message); + // int scancode = (event.message & adbAddrMask) >> 16; + + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // int action; + // if(event.what == keyUp) { + // action = GLFW_RELEASE; + // } else { + // action = GLFW_PRESS; + // } + // ___curWindow->keyCallback(___curWindow, key, scancode, action, + // mods); + // } + } + } + + FlushEvents(everyEvent, -1); + YieldToAnyThread(); +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + setwtitle(handle->cmacos.window, title); +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + MwLLPixmap r = malloc(sizeof(*r)); + + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + MwLLPixmapUpdate(r); + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { +} + +static void MwLLForceRenderImpl(MwLL handle) { +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { +} + +static void MwLLShowImpl(MwLL handle, int show) { + if(show) + ShowWindow(handle->cmacos.window); + else + HideWindow(handle->cmacos.window); +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { +} + +static void MwLLFocusImpl(MwLL handle) { + HiliteWindow(handle->cmacos.window, MwTRUE); +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + /* TODO */ + + (void)handle; + (void)text; +} + +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + MwLLShow(handle, 0); +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLLShow(handle, 1); +} + +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwFALSE; +} + +static void MwLLRaiseImpl(MwLL handle) { + (void)handle; +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + +static int MwLLClassicMacOSCallInitImpl(void) { + InitGraf(&qd.thePort); + InitFonts(); + FlushEvents(everyEvent, 0); + InitWindows(); + InitMenus(); + TEInit(); + InitDialogs(0L); + InitCursor(); + + return 0; +} + +#include "call.c" +CALL(ClassicMacOS); diff --git a/widget/milsko/milskosrc/src/backend/cocoa.m b/widget/milsko/milskosrc/src/backend/cocoa.m new file mode 100644 index 0000000000..e07eb64112 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/cocoa.m @@ -0,0 +1,1199 @@ +/* + * some implementation notes to know: + * - Mac really does not like immediate mode drawing, there was some trick I tried where I rendered to a bitmap context but it was very slow. So instead we just convert it to a commands system which gets cleared out whenever MacOS Actually draws the window. + * - We override NSApplication to intercept sendEvent and know when an event has been sent. When it is, doPending is sent. The appropriate "pending" function then returns whether that's set (before resetting it). + * - We want the application to be *functional* on old MacOS, at a minimum of 10.4. There's obviously points where newer functions will have to be used, and in that case we use ObjC's "respondsToSelector" function to know if we can call the newer function. + */ + +#include +#include "../../external/stb_ds.h" +#include "Mw/LowLevel/Cocoa.h" + +#ifdef MW_VULKAN +#include +#include +#endif + +#ifdef __clang__ +#pragma clang push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + +/* + * GNUStep has the modal session be a global singleton and once we assign it we can't do any more. This breaks several widgets. + * I barely care about supporting this so we'll just not support that, sorry. + */ +#ifndef __APPLE__ +static bool canAssignModalSession = MwTRUE; +#else +#define canAssignModalSession 1 +#endif + +/* Coordinate flipping function (global, rect) */ +static NSRect rectFlip(NSRect originFrame) { + NSScreen* zeroScreen = [[NSScreen screens] objectAtIndex:0]; + double screenHeight = [zeroScreen frame].size.height; + double originY = originFrame.origin.y; + double frameHeight = originFrame.size.height; + double destinationY = screenHeight - (originY + frameHeight); + NSRect destinationFrame = originFrame; + destinationFrame.origin.y = destinationY; + return destinationFrame; +} + +/* Coordinate flipping function (global, point) */ +static inline NSPoint pointFlip(NSPoint point) { + return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; +} + +/* Coordinate flipping function (local to view; rect) */ +static NSRect localRectFlip(NSRect originFrame, NSView* view) { + float viewHeight = [view bounds].size.height; + NSRect destinationFrame = + NSMakeRect(originFrame.origin.x, + [view bounds].size.height - + (originFrame.origin.y + originFrame.size.height), + originFrame.size.width, originFrame.size.height); + return destinationFrame; +} + +/* Coordinate flipping function (local to view; point) */ +static inline NSPoint localPointFlip(NSPoint point, NSView* view) { + return localRectFlip(NSMakeRect(point.x, point.y, 0, 0), view).origin; +} + +/* Recursively dispatch a key event to a widget and its children */ +static void recursive_dispatch_key(MwLL handle, int* k) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, key, k); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, key, k); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_key(h->children[i]->lowlevel, k); + } + } + } +}; +/* Recursively dispatch a key released event to a widget and its children */ +static void recursive_dispatch_key_released(MwLL handle, int* k) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, key_released, k); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, key_released, k); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_key_released(h->children[i]->lowlevel, k); + } + } + } +}; + +@implementation MilskoCocoaApplication +- (void)sendEvent:(NSEvent*)event { + self->doPending = MwTRUE; + [super sendEvent:event]; +} +- (MwBool)pending { + if(self->doPending) { + self->doPending = MwFALSE; + return MwTRUE; + } + return MwFALSE; +} +@end + +@implementation MilskoCocoaView +- (id)initWithFrame:(NSRect)frame { + [super initWithFrame:frame]; + self->commands = NULL; + return self; +} + +- (void)setChild { + self->_child = MwTRUE; +} +- (void)destroy { + arrfree(self->commands); +}; + +- (void)drawRect:(NSRect)dirtyRect { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + int i; + + [super drawRect:dirtyRect]; + + for(i = 0; i < arrlen(self->commands); i++) { + draw_command cmd = self->commands[i]; + switch(cmd.type) { + case COCOA_DRAW_COMMAND_POLY: + { + int n; + NSBezierPath* path = [NSBezierPath bezierPath]; + + NSColor* nscolor = + [NSColor colorWithCalibratedRed:cmd.poly.color.red / 255. + green:cmd.poly.color.green / 255. + blue:cmd.poly.color.blue / 255. + alpha:1.0]; + + [nscolor setFill]; + for(n = 0; n < cmd.poly.points_count; n++) { + NSPoint p = localPointFlip(NSMakePoint(cmd.poly.points[n].x, cmd.poly.points[n].y), self); + p.x += [self bounds].origin.x; + p.y += [self bounds].origin.y; + if(n == 0) { + [path moveToPoint:p]; + } else { + [path lineToPoint:p]; + } + } + + [path closePath]; + [path fill]; + + free(cmd.poly.points); + } break; + + case COCOA_DRAW_COMMAND_LINES: + { + int n; + NSBezierPath* path = [NSBezierPath bezierPath]; + + NSColor* nscolor = + [NSColor colorWithCalibratedRed:cmd.lines.color.red / 255. + green:cmd.lines.color.green / 255. + blue:cmd.lines.color.blue / 255. + alpha:1.0]; + + [nscolor setFill]; + for(n = 0; n < 2; n++) { + NSPoint p = localPointFlip(NSMakePoint(cmd.lines.points[n].x, cmd.lines.points[n].y), self); + p.x += [self bounds].origin.x; + p.y += [self bounds].origin.y; + if(n == 0) { + [path moveToPoint:p]; + } else { + [path lineToPoint:p]; + } + } + + [path closePath]; + [path stroke]; + + free(cmd.lines.points); + } break; + + case COCOA_DRAW_COMMAND_PIXMAP: + { + NSRect rect = localRectFlip(NSMakeRect(cmd.pixmap.rect.x, cmd.pixmap.rect.y, cmd.pixmap.rect.width, cmd.pixmap.rect.height), self); + rect.origin.x += [self bounds].origin.x; + rect.origin.y += [self bounds].origin.y; + [cmd.pixmap.pixmap->cocoa.real->image + drawInRect:rect + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0]; + MwLLDestroyPixmap(cmd.pixmap.pixmap); + } break; + } + } + + arrfree(self->commands); + + [pool release]; +} + +- (BOOL)isFlipped { + return NO; +} + +- (BOOL)canBecomeKeyView { + return YES; +} +- (BOOL)acceptsFirstResponder { + return YES; +} + +- (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll down:(MwBool)isDown { + int ch; + /* todo: consolidate these values into the below switch case. */ + enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_Return = 0x24, + kVK_Space = 0x31, + kVK_Escape = 0x35, + kVK_Shift = 0x38, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightControl = 0x3E, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E + }; +#define KEY_CASE(x, y) \ + case x: \ + ch = y; \ + break; + switch([ev keyCode]) { + KEY_CASE(kVK_ANSI_A, 'a') + KEY_CASE(kVK_ANSI_B, 'b') + KEY_CASE(kVK_ANSI_C, 'c') + KEY_CASE(kVK_ANSI_D, 'd') + KEY_CASE(kVK_ANSI_E, 'e') + KEY_CASE(kVK_ANSI_F, 'f') + KEY_CASE(kVK_ANSI_G, 'g') + KEY_CASE(kVK_ANSI_H, 'h') + KEY_CASE(kVK_ANSI_I, 'i') + KEY_CASE(kVK_ANSI_J, 'j') + KEY_CASE(kVK_ANSI_K, 'k') + KEY_CASE(kVK_ANSI_L, 'l') + KEY_CASE(kVK_ANSI_M, 'm') + KEY_CASE(kVK_ANSI_N, 'n') + KEY_CASE(kVK_ANSI_O, 'o') + KEY_CASE(kVK_ANSI_P, 'p') + KEY_CASE(kVK_ANSI_Q, 'q') + KEY_CASE(kVK_ANSI_R, 'r') + KEY_CASE(kVK_ANSI_S, 's') + KEY_CASE(kVK_ANSI_T, 't') + KEY_CASE(kVK_ANSI_U, 'u') + KEY_CASE(kVK_ANSI_V, 'v') + KEY_CASE(kVK_ANSI_W, 'w') + KEY_CASE(kVK_ANSI_X, 'x') + KEY_CASE(kVK_ANSI_Y, 'y') + KEY_CASE(kVK_ANSI_Z, 'z') + KEY_CASE(kVK_ANSI_0, '0') + KEY_CASE(kVK_ANSI_1, '1') + KEY_CASE(kVK_ANSI_2, '2') + KEY_CASE(kVK_ANSI_3, '3') + KEY_CASE(kVK_ANSI_4, '4') + KEY_CASE(kVK_ANSI_5, '5') + KEY_CASE(kVK_ANSI_6, '6') + KEY_CASE(kVK_ANSI_7, '7') + KEY_CASE(kVK_ANSI_8, '8') + KEY_CASE(kVK_ANSI_9, '9') + KEY_CASE(kVK_ANSI_Quote, '\"') + KEY_CASE(kVK_ANSI_Grave, '`') + KEY_CASE(kVK_ANSI_Backslash, '/') + KEY_CASE(kVK_ANSI_Comma, ',') + KEY_CASE(kVK_ANSI_Equal, '=') + KEY_CASE(kVK_Escape, MwKEY_ESCAPE) + KEY_CASE(kVK_ANSI_LeftBracket, '[') + KEY_CASE(kVK_ANSI_Minus, '-') + KEY_CASE(kVK_ANSI_Period, '.') + KEY_CASE(kVK_Return, MwKEY_ENTER) + KEY_CASE(kVK_ANSI_RightBracket, ']') + KEY_CASE(kVK_ANSI_Semicolon, ';') + KEY_CASE(kVK_ANSI_Slash, '\\') + KEY_CASE(kVK_Space, ' ') + KEY_CASE(kVK_Control, MwKEY_CONTROL) + KEY_CASE(kVK_RightControl, MwKEY_CONTROL) + KEY_CASE(kVK_Shift, MwKEY_LEFTSHIFT) + KEY_CASE(kVK_RightShift, MwKEY_RIGHTSHIFT) + KEY_CASE(kVK_DownArrow, MwKEY_DOWN) + KEY_CASE(kVK_LeftArrow, MwKEY_LEFT) + KEY_CASE(kVK_RightArrow, MwKEY_RIGHT) + KEY_CASE(kVK_UpArrow, MwKEY_UP) + } + if(isDown) { + recursive_dispatch_key(ll, &ch); + } else { + recursive_dispatch_key_released(ll, &ch); + } + [ll->cocoa.real nudge]; +} +- (void)mouseEntered:(NSEvent*)ev { + MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + MwLLDispatch(h, focus_in, NULL); + [h->cocoa.real pushCursor]; + [super mouseEntered:ev]; +} +- (void)mouseExited:(NSEvent*)ev { + MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + MwLLDispatch(h, focus_out, NULL); + [h->cocoa.real popCursor]; + [super mouseExited:ev]; +} +- (void)keyDown:(NSEvent*)ev { + MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + [self handleKeyEvent:ev ll:h down:MwTRUE]; + [super keyDown:ev]; +} +- (void)keyUp:(NSEvent*)ev { + MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + [self handleKeyEvent:ev ll:h down:MwFALSE]; + [super keyUp:ev]; +} + +- (void)mouseMoved:(NSEvent*)ev { + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mouse.button = MwMOUSE_LEFT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, move, &mouse); + [super mouseMoved:ev]; +} +- (BOOL)mouseDownCanMoveWindow { + return NO; +} + +- (void)mouseDown:(NSEvent*)ev { + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwMOUSE_LEFT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, down, &mouse); + [super mouseDown:ev]; +} + +- (void)mouseUp:(NSEvent*)ev { + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwMOUSE_LEFT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, up, &mouse); + [super mouseUp:ev]; +} +- (void)rightMouseDown:(NSEvent*)ev { + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwMOUSE_RIGHT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, down, &mouse); + [super rightMouseDown:ev]; +} + +- (void)rightMouseUp:(NSEvent*)ev { + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwMOUSE_RIGHT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, up, &mouse); + [super rightMouseUp:ev]; +} + +@end + +@implementation MilskoCocoaApplicationDelegate +- (MilskoCocoaApplicationDelegate*)initWithAppl:(MilskoCocoaApplication*)_appl { + self->appl = _appl; + return self; +} +@end + +@implementation MilskoCocoaWindowDelegate + +- (NSSize)windowWillResize:(NSWindow*)win toSize:(NSSize)frameSize; +{ + int i; + NSUInteger placeholder = [[[win contentView] subviews] count]; + for(i = 0; i < placeholder; i++) { + NSView* ptr = [[[win contentView] subviews] objectAtIndex:i]; + if([ptr isKindOfClass:[MilskoFakePointer class]]) { + MwLL h = [(MilskoFakePointer*)ptr pointer]; + MwLLDispatch(h, resize, NULL); + break; + } + } + return frameSize; +} + +- (void)windowDidBecomeMain:(NSNotification*)notification { + if([[[w contentView] subviews] count] != 0) { + MwLL h = [((MilskoFakePointer*)[[[w contentView] subviews] + objectAtIndex:0]) pointer]; + MwLLDispatch(h, focus_in, NULL); + } + [self->w makeKeyAndOrderFront:nil]; +} + +- (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win { + self->w = win; + return self; +} + +- (void)windowWillClose:(NSNotification*)notification { + if([[[w contentView] subviews] count] != 0) { + MwLL h = [((MilskoFakePointer*)[[[w contentView] subviews] + objectAtIndex:0]) pointer]; + MwLLDispatch(h, close, NULL); + h->cocoa.real->isClosing = MwTRUE; + } +} + +@end + +@implementation MilskoFakePointer +- (void)setPointer:(void*)pointer { + [self setFrame:*(NSRect*)&pointer]; + self->ptr = pointer; +}; +- (void*)pointer { + return self->ptr; +}; + +- (void)drawRect:(NSRect)dirtyRect { + /* explicitly do nothing */ + (void)dirtyRect; +} + +- (void)destroy { +} +@end + +@implementation MilskoCocoaWindow +- (BOOL)canBecomeKeyWindow { + return true; +} +- (BOOL)canBecomeMainWindow { + return true; +} + +@end + +@implementation MilskoCocoaPixmap ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { + MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; + + p->width = width; + p->height = height; + p->image = NULL; + + p->buf = malloc(width * height * 4); + + p->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + assert(p->rep); + + p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; + assert(p->image); + [p->image addRepresentation:p->rep]; + + return p; +} +- (void)updateWithData:(unsigned char*)_data { + memcpy(self->buf, _data, width * height * 4); + if(self->rep) { + [self->image removeRepresentation:self->rep]; + [self->rep release]; + } + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + assert(self->rep); + [self->image addRepresentation:self->rep]; +} +- (void)destroy { + free(self->buf); + [self->image removeRepresentation:self->rep]; + [self->image release]; + [self->rep release]; + self->image = NULL; + self->rep = NULL; +} +- (NSImage*)image { + return self->image; +} +@end + +@implementation MilskoCocoa +- (void)sendClipboardEvent { + /* Either uncomment this and make it use respondsToSelector and/or find out what the api proceeding NSPasteboard is. */ + /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + NSArray* items = @[ + @"public.utf8-plain-text", + @"public.utf16-external-plain-text", + @"com.apple.traditional-mac-plain-text", + ]; + MwLL this = self->handle.pointer; + + if([pasteboard canReadItemWithDataConformingToTypes:items]) { + char* data = NULL; + size_t size = 0; + for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { + for(NSString* it in items) { + NSString* itemData = [item + stringForType:(NSString*)it]; if(itemData != NULL) { if(strHash != 0 && + strHash != [itemData hash]) { char* text = malloc([itemData length]); + strncpy(text, [itemData UTF8String], + [itemData length]); MwLLDispatch(this, clipboard, text); printf("%s -> %p\n", + text, this); free(text); + } + strHash = [itemData hash]; + } + } + } + } + + [pool release];*/ +} + +- (void)destroy { + [self->handle release]; + [self->window release]; +} + +- (MwLL)getParent { + return self->parent; +} + +- (NSView*)getView { + return view; +} +- (NSWindow*)getWindow { + return window; +} + +- (void)nudge { + MwLL topmost_parent = [self->handle pointer]; + MwWidget h; + + while(topmost_parent->cocoa.real->parent) topmost_parent = topmost_parent->cocoa.real->parent; + + if(!topmost_parent->cocoa.real->isClosing) + self->_eventsPending = MwTRUE; + + [topmost_parent->cocoa.real->view setNeedsDisplay:true]; + MwLLDispatch(topmost_parent, draw, NULL); + + h = (MwWidget)topmost_parent->common.user; + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + [h->children[i]->lowlevel->cocoa.real->view setNeedsDisplay:true]; + MwLLDispatch(h->children[i]->lowlevel, draw, NULL); + } + } + + // MwLL p = self->parent; + // self->_eventsPending = MwTRUE; + + // while(p) { + // MwLLDispatch(p, draw, NULL); + // p = p->cocoa.real->parent; + // } +} + +- (void)pushCursor { + [self->cursor push]; +} +- (void)popCursor { + [self->cursor pop]; +} + +- (MilskoFakePointer*)getHandle { + return handle; +} + +@end + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MilskoCocoa* c = [MilskoCocoa alloc]; + r = malloc(sizeof(*r)); + + MwLLCreateCommon(r); + + [c retain]; + c->application = (MilskoCocoaApplication*)[MilskoCocoaApplication sharedApplication]; + [c->application retain]; + + /* + * MacOS doesn't really have a "default" window position, you're actually + * meant to center the window yourself, so if the user passes MwDEFAULT + * respond appropriately. Also for child windows just have it be 0. + */ + if(x == MwDEFAULT) { + x = parent ? 0 : ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.); + } + if(y == MwDEFAULT) { + y = parent ? 0 : ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.); + } + c->rect = NSMakeRect(x, y, width, height); + + if(parent == NULL) { + c->window = [[NSWindow alloc] + initWithContentRect:rectFlip(c->rect) + styleMask:(NSTitledWindowMask | + NSClosableWindowMask | NSMiniaturizableWindowMask | + NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:NO]; + [c->window + setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; + [c->window retain]; + + [c->window makeKeyAndOrderFront:c->application]; + [c->window makeFirstResponder:c->view]; + + c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + [c->view retain]; + [c->window setContentView:c->view]; + + /* In order for our application to be front and center when launched, we need to use this function introduced in 10.5. There's no function that works on 10.4 or below as far as I know because what you're actually supposed to do is use a feature of XCode project files to modify the settings of the compiled app to set the activation policy. */ + if([c->application respondsToSelector:@selector(setActivationPolicy:)]) { + [c->application + setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; + } + + [c->application activateIgnoringOtherApps:MwTRUE]; + [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] + initWithAppl:c->application]]; + [c->application retain]; + + [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; + if(canAssignModalSession) + c->modalSession = [c->application beginModalSessionForWindow:c->window]; + +#ifndef __APPLE__ + canAssignModalSession = MwFALSE; +#endif + + } else { + MilskoCocoa* p = parent->cocoa.real; + NSRect rect = localRectFlip(c->rect, p->view); + + c->window = p->window; + c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; + [c->view setBounds:rect]; + [c->view retain]; + [c->view setChild]; + + [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; + + [p->view addSubview:c->view]; + + c->modalSession = p->modalSession; + } + [c->window setAcceptsMouseMovedEvents:MwTRUE]; + + c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; + [c->handle retain]; + [c->handle setPointer:r]; + [c->view addSubview:c->handle]; + + c->parent = parent; + + c->_forceRender = MwTRUE; + c->strHash = 0; + + c->cursorPixmap = NULL; + + [c->application finishLaunching]; + + c->pointerLocked = MwFALSE; + + [pool release]; + + c->isClosing = MwFALSE; + + r->cocoa.real = c; + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MilskoCocoa* h = handle->cocoa.real; + + [h destroy]; + + MwLLDestroyCommon(handle); + + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; + // [handle->cocoa.real->view displayRect:[handle->cocoa.real->window frame]]; +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, + MwLLColor color) { + draw_command poly; + poly.type = COCOA_DRAW_COMMAND_POLY; + + poly.poly.color = color->common; + poly.poly.points_count = points_count; + + poly.poly.points = malloc(sizeof(MwPoint) * points_count); + memcpy(poly.poly.points, points, sizeof(MwPoint) * points_count); + + arrpush(handle->cocoa.real->view->commands, poly); + + [handle->cocoa.real nudge]; +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + draw_command lines; + lines.type = COCOA_DRAW_COMMAND_LINES; + + lines.lines.color = color->common; + + lines.lines.points = malloc(sizeof(MwPoint) * 2); + memcpy(lines.lines.points, points, sizeof(MwPoint) * 2); + + arrpush(handle->cocoa.real->view->commands, lines); + + [handle->cocoa.real nudge]; +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} + +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, + unsigned int* h) { + MilskoCocoa* self = handle->cocoa.real; + NSRect frame; + if(self->parent) { + frame = [self->view frame]; + } else { + frame = [self->window frame]; + } + + if(!self->parent) { + frame = rectFlip(frame); + } else { + frame = localRectFlip(frame, self->parent->cocoa.real->view); + } + + *x = frame.origin.x; + *y = frame.origin.y; + + *w = frame.size.width; + *h = frame.size.height; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + MilskoCocoa* self = handle->cocoa.real; + NSRect frame; + if(self->parent) { + frame = [self->view frame]; + } else { + frame = [self->window frame]; + } + + frame.origin.x = x; + frame.origin.y = y; + + if(!self->parent) { + frame = rectFlip(frame); + [self->window setFrame:frame display:MwTRUE animate:false]; + } else { + frame = localRectFlip(frame, self->parent->cocoa.real->view); + [self->view setFrame:frame]; + [self->view setBounds:frame]; + } + MwLLForceRender(handle); +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + MilskoCocoa* self = handle->cocoa.real; + NSRect frame; + if(self->parent) { + frame = [self->view frame]; + } else { + frame = [self->window frame]; + } + + frame.size.width = w; + frame.size.height = h; + + self->rect = frame; + + [self->view setFrameSize:frame.size]; + if(self->parent) { + [self->view setFrame:frame]; + [self->view setBounds:frame]; + } else { + [self->window setFrame:frame display:YES animate:false]; + } + MwLLForceRender(handle); +} + +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} + +static int MwLLPendingImpl(MwLL handle) { + MilskoCocoa* self = handle->cocoa.real; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MwBool isPending = [self->application pending]; + + if(self->modalSession) { + [self->application runModalSession:self->modalSession]; + } + [pool release]; + return !self->isClosing && (self->_forceRender || self->_eventsPending || isPending); +} + +static void MwLLNextEventImpl(MwLL handle) { + MilskoCocoa* self = handle->cocoa.real; + MwLL h = [self->handle pointer]; + if(self->_forceRender) { + MwLLDispatch(h, draw, NULL); + self->_forceRender = MwFALSE; + } + if(self->_eventsPending) { + self->_eventsPending = MwFALSE; + } + [self sendClipboardEvent]; + +#ifdef __APPLE__ + if(self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { + struct CGPoint pos; + pos.x = [self->window frame].origin.x + [self->window frame].size.width / 2; + pos.y = [self->window frame].origin.y + [self->window frame].size.height / 2; + + CGWarpMouseCursorPosition(pos); + } +#endif + + [self->application updateWindows]; +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [handle->cocoa.real->window + setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [pool release]; +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, + int width, int height) { + MwLLPixmap r = malloc(sizeof(*r)); + + (void)handle; + memset(r, 0, sizeof(*r)); + + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + r->common.width = width; + r->common.height = height; + + r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; + + MwLLPixmapUpdate(r); + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { + MilskoCocoaPixmap* self = pixmap->cocoa.real; + memcpy(self->buf, pixmap->common.raw, pixmap->common.width * pixmap->common.height * 4); + [pixmap->cocoa.real updateWithData:pixmap->common.raw]; +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap->common.raw); + [pixmap->cocoa.real destroy]; + [pixmap->cocoa.real release]; + free(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + draw_command pix; + pix.type = COCOA_DRAW_COMMAND_PIXMAP; + + pix.pixmap.rect = *rect; + + /* copy the pixmap into a new object that we'll free later */ + pix.pixmap.pixmap = MwLLCreatePixmap(handle, pixmap->common.raw, pixmap->common.width, pixmap->common.height); + + arrpush(handle->cocoa.real->view->commands, pix); + + [handle->cocoa.real nudge]; +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + [handle->cocoa.real->application setApplicationIconImage:[pixmap->cocoa.real image]]; +} + +static void MwLLForceRenderImpl(MwLL handle) { + handle->cocoa.real->_forceRender = MwTRUE; +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + MilskoCocoa* self = handle->cocoa.real; + int y, x, ys, xs; + unsigned char* di = malloc(image->width * image->height * 4); + memset(di, 0, image->width * image->height * 4); + + if(self->cursorPixmap) { + [self->cursorPixmap destroy]; + } + self->cursorPixmap = + [MilskoCocoaPixmap newWithWidth:image->width + height:image->height]; + + xs = -mask->x + image->x; + ys = MwCursorDataHeight + mask->y; + ys = MwCursorDataHeight + image->y - ys; + + for(y = 0; y < mask->height; y++) { + unsigned int d = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * mask->width) + x) * 4; + + if(d & 1) { + di[idx + 3] = 255; + }; + d = d >> 1; + } + } + for(y = 0; y < image->height; y++) { + unsigned int d = image->data[y]; + for(x = image->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * image->width) + x) * 4; + + if(d & 1) { + px = 255; + }; + + di[idx] = px; + di[idx + 1] = px; + di[idx + 2] = px; + d = d >> 1; + } + } + + [self->cursorPixmap updateWithData:di]; + + self->cursor = [[NSCursor alloc] + initWithImage:[self->cursorPixmap image] + hotSpot:NSMakePoint(image->x, image->y + image->height)]; + [self->cursor retain]; + + [self->cursor pop]; + [self->cursor push]; + + free(di); +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + (void)handle; + (void)point; +} + +static void MwLLShowImpl(MwLL handle, int show) { + (void)show; +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + (void)parent; +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, + int maxy) { + MilskoCocoa* self = handle->cocoa.real; + [self->window setMinSize:NSMakeSize(minx, miny)]; + [self->window setMaxSize:NSMakeSize(maxx, maxy)]; +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + MilskoCocoa* self = handle->cocoa.real; + MwU32 mask = [self->window styleMask]; + if(toggle) { + mask ^= NSBorderlessWindowMask; + mask |= NSTitledWindowMask; + } else { + mask |= NSBorderlessWindowMask; + mask ^= NSTitledWindowMask; + } + [self->window initWithContentRect:self->rect + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; +} + +static void MwLLFocusImpl(MwLL handle) { + [handle->cocoa.real->application activateIgnoringOtherApps:MwTRUE]; +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + handle->cocoa.real->pointerLocked = toggle; +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + (void)handle; + (void)text; + (void)clipboard_type; +} + +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + (void)handle; + (void)clipboard_type; +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { + /* If my understand of what a "tool window" usually is is correct then I + * highly doubt the Mac OS has this and if they did they probably outright + * removed it along time ago is this kind of conflicts with modern UX. So + * we'll just make it borderless idgaf */ + MwLLMakeBorderlessImpl(handle, 1); +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + NSPoint p = [NSEvent mouseLocation]; + point->x = p.x; + point->y = p.y; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + MilskoCocoa* self = handle->cocoa.real; + NSScreen* screen = [self->window screen]; + rect->x = [screen frame].origin.x; + rect->y = [screen frame].origin.y; + rect->width = [screen frame].size.width; + rect->height = [screen frame].size.height; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + MwLLShow(handle, 0); +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLLShow(handle, 1); +} + +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + (void)handle; +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + +static int MwLLCocoaCallInitImpl(void) { +#ifndef __APPLE__ + printf("Using GNUStep Backend\n"); +#endif + + [MilskoCocoaApplication sharedApplication]; + + return 0; +} + +#ifdef MW_VULKAN +VkMetalSurfaceCreateInfoEXT MwCocoaGetMetalSurfaceCreateInfo(MwWidget handle) { + VkMetalSurfaceCreateInfoEXT createInfo = { + .sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, + .pNext = NULL, + .flags = 0, + .pLayer = (CAMetalLayer*)[handle->lowlevel->cocoa.real->view layer], + }; + return createInfo; +}; +#endif + +#include "call.c" +CALL(Cocoa); diff --git a/widget/milsko/milskosrc/src/backend/gdi.c b/widget/milsko/milskosrc/src/backend/gdi.c new file mode 100644 index 0000000000..acc341e46a --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/gdi.c @@ -0,0 +1,1017 @@ +#include + +typedef struct userdata { + MwLL ll; + POINT min; + POINT max; + int min_set; + int max_set; +} userdata_t; + +static struct symtbl { + void* lib_dwmapi; + + HRESULT(WINAPI* DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); +} wsymtbl; + +static int is_plgblt_reliable = 0; + +#define DwmSetWindowAttribute wsymtbl.DwmSetWindowAttribute + +/* Dark theme detection for classic Windows: check if the user has set their theme to be dark. */ +static void detect_darktheme_classictheme(MwLL handle) { + /* Returns NULL on Windows 10+, use this to our advantage to check if the value is supported. */ + if(GetSysColorBrush(COLOR_MENU)) { + DWORD col = GetSysColor(COLOR_MENU); + int t = (GetRValue(col) <= 75 && GetGValue(col) <= 75 && GetBValue(col) <= 75); + MwLLDispatch(handle, dark_theme, &t); + } +} + +/* Dark theme detection for modern Windows: use the registry to check if dark mode is enabled. */ +static void detect_darktheme(MwLL handle) { + DWORD dw; + DWORD sz = sizeof(dw); + int err, t; + HKEY hkey; + DWORD type; + + err = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_QUERY_VALUE, &hkey); + if(err != ERROR_SUCCESS) { + detect_darktheme_classictheme(handle); + return; + } + + err = RegQueryValueEx(hkey, "AppsUseLightTheme", NULL, &type, (PBYTE)&dw, &sz); + RegCloseKey(hkey); + if(err != ERROR_SUCCESS || type != REG_DWORD) { + detect_darktheme_classictheme(handle); + return; + } + + t = dw ? 0 : 1; + + /* no don't do this here (nishi) */ +#if 0 + if(t && DwmSetWindowAttribute != NULL) { + LPARAM style = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE); + if(!(style & WS_CHILD)) MwLLSetDarkTheme(handle, 1); + } +#endif + + MwLLDispatch(handle, dark_theme, &t); +} + +static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { + userdata_t* u = (userdata_t*)GetWindowLongPtr(hWnd, GWLP_USERDATA); + + if(u == NULL) return DefWindowProc(hWnd, msg, wp, lp); + + switch(msg) { + case WM_PAINT: + { + PAINTSTRUCT ps; + RECT rc; + HBITMAP hbmp; + HDC dc, hbdc; + + u->ll->gdi.force_render = 0; + + if(u->ll->common.copy_buffer) { + GetClientRect(hWnd, &rc); + + dc = GetDC(hWnd); + hbmp = CreateCompatibleBitmap(dc, rc.right - rc.left, rc.bottom - rc.top); + hbdc = CreateCompatibleDC(dc); + SelectObject(hbdc, hbmp); + ReleaseDC(hWnd, dc); + + u->ll->gdi.hDC = hbdc; + MwLLDispatch(u->ll, draw, NULL); + + dc = BeginPaint(hWnd, &ps); + StretchBlt(dc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hbdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SRCCOPY); + EndPaint(hWnd, &ps); + + DeleteDC(hbdc); + DeleteObject(hbmp); + } else { + u->ll->gdi.hDC = BeginPaint(hWnd, &ps); + MwLLDispatch(u->ll, draw, NULL); + EndPaint(hWnd, &ps); + } + break; + } + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + MwMouse p; + p.point.x = LOWORD(lp); + p.point.y = HIWORD(lp); + if(msg == WM_LBUTTONDOWN) { + p.button = MwMOUSE_LEFT; + } else if(msg == WM_MBUTTONDOWN) { + p.button = MwMOUSE_MIDDLE; + } else if(msg == WM_RBUTTONDOWN) { + p.button = MwMOUSE_RIGHT; + } + + SetCapture(hWnd); + SetFocus(hWnd); + MwLLDispatch(u->ll, down, &p); + break; + } + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + MwMouse p; + p.point.x = LOWORD(lp); + p.point.y = HIWORD(lp); + if(msg == WM_LBUTTONUP) { + p.button = MwMOUSE_LEFT; + } else if(msg == WM_MBUTTONUP) { + p.button = MwMOUSE_MIDDLE; + } else if(msg == WM_RBUTTONUP) { + p.button = MwMOUSE_RIGHT; + } + + SetCapture(NULL); + MwLLDispatch(u->ll, up, &p); + break; + } + case WM_MOUSEWHEEL: + { + int d = GET_WHEEL_DELTA_WPARAM(wp); + MwMouse p; + p.point.x = LOWORD(lp); + p.point.y = HIWORD(lp); + + if(d > 0) { + p.button = MwMOUSE_WHEELUP; + } else if(d < 0) { + p.button = MwMOUSE_WHEELDOWN; + } + + MwLLDispatch(u->ll, down, &p); + MwLLDispatch(u->ll, up, &p); + break; + } + case WM_MOUSEMOVE: + { + MwPoint p; + p.x = LOWORD(lp); + p.y = HIWORD(lp); + + if(u->ll->gdi.grabbed) { + RECT rc; + + GetClientRect(hWnd, &rc); + p.x -= (rc.right - rc.left) / 2; + p.y -= (rc.bottom - rc.top) / 2; + } + + MwLLDispatch(u->ll, move, &p); + + if(u->ll->gdi.grabbed && (p.x != 0 || p.y != 0)) { + RECT rc; + POINT p; + + GetClientRect(hWnd, &rc); + + p.x = (rc.right - rc.left) / 2; + p.y = (rc.bottom - rc.top) / 2; + + MapWindowPoints(hWnd, HWND_DESKTOP, &p, 1); + + SetCursorPos(p.x, p.y); + } + break; + } + case WM_SIZE: + { + MwLLDispatch(u->ll, resize, NULL); + break; + } + case WM_ERASEBKGND: + { + return 1; + } + case WM_NCHITTEST: + { + LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); + if(style & WS_CHILD) return HTCLIENT; + return DefWindowProc(hWnd, msg, wp, lp); + } + case WM_DESTROY: + { + PostQuitMessage(0); + break; + } + case WM_CLOSE: + { + MwLLDispatch(u->ll, close, NULL); + break; + } + case WM_CHAR: + case WM_SYSCHAR: + { + int n = wp; + const int base = 'A' - 1; + + if(n != 0x1b && n <= 0x1f) { + n = (n + base) | MwKEY_CONTROL_FLAG; + if(!(GetKeyState(VK_LSHIFT) || GetKeyState(VK_RSHIFT))) n += 0x20; + } + if(HIBYTE(VkKeyScan(wp)) & 2) n |= MwKEY_CONTROL_FLAG; + if(msg == WM_SYSCHAR) n |= MwKEY_ALT_FLAG; + + if((0x20 <= n && n <= 0x7f) || (n & MwKEY_FLAG)) MwLLDispatch(u->ll, key, &n); + break; + } + case WM_SETFOCUS: + { + MwLLDispatch(u->ll, focus_in, NULL); + break; + } + case WM_KILLFOCUS: + { + MwLLDispatch(u->ll, focus_out, NULL); + break; + } + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + { + int n = -1; + + if(wp == VK_MENU && msg == WM_KEYUP) return 0; + switch(wp) { + case VK_LEFT: + n = MwKEY_LEFT; + break; + case VK_RIGHT: + n = MwKEY_RIGHT; + break; + case VK_UP: + n = MwKEY_UP; + break; + case VK_DOWN: + n = MwKEY_DOWN; + break; + case VK_RETURN: + n = MwKEY_ENTER; + break; + case VK_BACK: + n = MwKEY_BACKSPACE; + break; + case VK_ESCAPE: + n = MwKEY_ESCAPE; + break; + case VK_LSHIFT: + n = MwKEY_LEFTSHIFT; + break; + case VK_RSHIFT: + n = MwKEY_RIGHTSHIFT; + break; + case VK_MENU: + n = MwKEY_ALT; + break; + case VK_CONTROL: + n = MwKEY_CONTROL; + break; + } + + if((msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) && n != -1 && wp != VK_MENU) { + n |= MwKEY_ALT_FLAG; + } + if(n != -1) { + if(msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) { + MwLLDispatch(u->ll, key, &n); + } else { + MwLLDispatch(u->ll, key_released, &n); + } + } + break; + } + case WM_GETMINMAXINFO: + { + if(u->min_set || u->max_set) { + LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); + MINMAXINFO* mmi = (MINMAXINFO*)lp; + if(u->min_set) { + RECT rc; + + rc.left = 0; + rc.top = 0; + rc.right = u->min.x; + rc.bottom = u->min.y; + AdjustWindowRect(&rc, style, FALSE); + + mmi->ptMinTrackSize.x = rc.right - rc.left; + mmi->ptMinTrackSize.y = rc.bottom - rc.top; + } + if(u->max_set) { + RECT rc; + + rc.left = 0; + rc.top = 0; + rc.right = u->min.x; + rc.bottom = u->min.y; + AdjustWindowRect(&rc, style, FALSE); + + mmi->ptMaxTrackSize.x = rc.right - rc.left; + mmi->ptMaxTrackSize.y = rc.bottom - rc.top; + } + } else { + return DefWindowProc(hWnd, msg, wp, lp); + } + break; + } + case WM_SETCURSOR: + { + if(LOWORD(lp) != HTCLIENT) return DefWindowProc(hWnd, msg, wp, lp); + if(u->ll->gdi.cursor != NULL) SetCursor(u->ll->gdi.cursor); + break; + } + case WM_USER: + { + InvalidateRect(hWnd, NULL, FALSE); + UpdateWindow(hWnd); + break; + } + case WM_WININICHANGE: + { + char* s = (char*)lp; + LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); + + if(!(style & WS_CHILD)) { + if(s != NULL && strcmp(s, "ImmersiveColorSet") == 0) detect_darktheme(u->ll); + } + break; + } + default: + { + return DefWindowProc(hWnd, msg, wp, lp); + } + } + return 0; +} + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r = malloc(sizeof(*r)); + userdata_t* u = malloc(sizeof(*u)); + WNDCLASSEX wc; + + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = wndproc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = (HINSTANCE)GetModuleHandle(NULL); + wc.lpszClassName = "milsko"; + wc.lpszMenuName = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = GetSysColorBrush(COLOR_MENU); + wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); + wc.hIconSm = NULL; + + MwLLCreateCommon(r); + + RegisterClassEx(&wc); + + r->common.copy_buffer = 1; + r->common.type = MwLLBackendGDI; + + r->gdi.get_clipboard = 0; + if(parent == NULL) r->gdi.get_darktheme = 1; + r->gdi.force_render = 0; + r->gdi.grabbed = 0; + r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); + r->gdi.hInstance = wc.hInstance; + r->gdi.cursor = NULL; + r->gdi.icon = NULL; + + r->gdi.clip = NULL; + + u->ll = r; + u->min_set = 0; + u->max_set = 0; + SetWindowLongPtr(r->gdi.hWnd, GWLP_USERDATA, (LPARAM)u); + + if(parent == NULL) { + RECT rc; + + rc.left = 0; + rc.top = 0; + rc.right = width; + rc.bottom = height; + AdjustWindowRect(&rc, GetWindowLongPtr(r->gdi.hWnd, GWL_STYLE), FALSE); + SetWindowPos(r->gdi.hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE); + + ShowWindow(r->gdi.hWnd, SW_NORMAL); + UpdateWindow(r->gdi.hWnd); + + InvalidateRect(r->gdi.hWnd, NULL, FALSE); + } + + SetWindowPos(r->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MwLLDestroyCommon(handle); + + /* for safety */ + SetWindowLongPtr(handle->gdi.hWnd, GWLP_USERDATA, (LPARAM)NULL); + DestroyWindow(handle->gdi.hWnd); + + if(handle->gdi.clip != NULL) DeleteObject(handle->gdi.clip); + + if(handle->gdi.cursor != NULL) DestroyCursor(handle->gdi.cursor); + + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + POINT* p = malloc(sizeof(*p) * points_count); + HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0)); + int i; + + for(i = 0; i < points_count; i++) { + p[i].x = points[i].x; + p[i].y = points[i].y; + } + SelectObject(handle->gdi.hDC, color->gdi.brush); + SelectObject(handle->gdi.hDC, pen); + SetPolyFillMode(handle->gdi.hDC, ALTERNATE); + Polygon(handle->gdi.hDC, p, points_count); + + DeleteObject(pen); + + free(p); +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + HPEN pen = CreatePen(PS_SOLID, 1, RGB(color->common.red, color->common.green, color->common.blue)); + RECT rc; + + rc.left = points[1].x; + rc.top = points[1].y; + rc.right = rc.left + 1; + rc.bottom = rc.top + 1; + + SelectObject(handle->gdi.hDC, pen); + MoveToEx(handle->gdi.hDC, points[0].x, points[0].y, NULL); + LineTo(handle->gdi.hDC, points[1].x, points[1].y); + FillRect(handle->gdi.hDC, &rc, color->gdi.brush); + + DeleteObject(pen); +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + + c->gdi.brush = NULL; + + MwLLColorUpdate(handle, c, r, g, b); + + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + HDC dc = GetDC(handle->gdi.hWnd); + + if(r > 255) r = 255; + if(g > 255) g = 255; + if(b > 255) b = 255; + if(r < 0) r = 0; + if(g < 0) g = 0; + if(b < 0) b = 0; + + if(c->gdi.brush != NULL) DeleteObject(c->gdi.brush); + c->gdi.color = GetNearestColor(dc, RGB(r, g, b)); + c->gdi.brush = CreateSolidBrush(c->gdi.color); + c->common.red = r; + c->common.green = g; + c->common.blue = b; + + ReleaseDC(handle->gdi.hWnd, dc); +} + +static void MwLLFreeColorImpl(MwLLColor color) { + DeleteObject(color->gdi.brush); + + free(color); +} + +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + RECT rc; + + GetClientRect(handle->gdi.hWnd, &rc); + MapWindowPoints(handle->gdi.hWnd, GetParent(handle->gdi.hWnd), (LPPOINT)&rc, 2); + + *x = rc.left; + *y = rc.top; + *w = rc.right - rc.left; + *h = rc.bottom - rc.top; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + SetWindowPos(handle->gdi.hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER); + InvalidateRect(handle->gdi.hWnd, NULL, FALSE); +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + SetWindowText(handle->gdi.hWnd, title); +} + +static int MwLLPendingImpl(MwLL handle) { + MSG msg; + + (void)handle; + + if(handle->gdi.get_clipboard || handle->gdi.get_darktheme) return 1; + return PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE) ? 1 : 0; +} + +static void MwLLNextEventImpl(MwLL handle) { + MSG msg; + + (void)handle; + + if(handle->gdi.get_clipboard) { + HGLOBAL hg; + if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL) { + char* txt = malloc(GlobalSize(hg)); + char* clp = GlobalLock(hg); + + strcpy(txt, clp); + + GlobalUnlock(hg); + CloseClipboard(); + + MwLLDispatch(handle, clipboard, txt); + + free(txt); + } + + handle->gdi.get_clipboard = 0; + } + if(handle->gdi.get_darktheme) { + detect_darktheme(handle); + + handle->gdi.get_darktheme = 0; + } + while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) { + GetMessage(&msg, handle->gdi.hWnd, 0, 0); + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + MwLLPixmap r = malloc(sizeof(*r)); + HDC dc = GetDC(handle->gdi.hWnd); + BITMAPINFOHEADER bmih; + + r->common.raw = malloc(width * height * 4); + memcpy(r->common.raw, data, 4 * width * height); + + r->common.width = width; + r->common.height = height; + + bmih.biSize = sizeof(bmih); + bmih.biWidth = width; + bmih.biHeight = -(LONG)height; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = BI_RGB; + bmih.biSizeImage = 0; + bmih.biXPelsPerMeter = 0; + bmih.biYPelsPerMeter = 0; + bmih.biClrUsed = 0; + bmih.biClrImportant = 0; + + r->gdi.hBitmap = CreateDIBSection(dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&r->gdi.quad, NULL, (DWORD)0); + + r->gdi.hMask = NULL; + r->gdi.hMask2 = NULL; + + ReleaseDC(handle->gdi.hWnd, dc); + + MwLLPixmapUpdate(r); + + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + int y, x; + int w = (r->common.width + (16 - (r->common.width % 16))) / 8; + WORD* words; + WORD* words2; + + if(16 * (r->common.width / 16) == r->common.width) w -= 2; + + words = malloc(w * r->common.height); + words2 = malloc(w * r->common.height); + memset(words, 0, w * r->common.height); + memset(words2, 0, w * r->common.height); + for(y = 0; y < r->common.height; y++) { + BYTE* l = (BYTE*)&words[y * (w / 2)]; + BYTE* l2 = (BYTE*)&words2[y * (w / 2)]; + for(x = 0; x < r->common.width; x++) { + RGBQUAD* q = &r->gdi.quad[y * r->common.width + x]; + unsigned char* px = &r->common.raw[(y * r->common.width + x) * 4]; + + q->rgbRed = px[0]; + q->rgbGreen = px[1]; + q->rgbBlue = px[2]; + + if(px[3]) { + l[x / 8] |= 1 << (7 - (x % 8)); + } else { + l2[x / 8] |= 1 << (7 - (x % 8)); + } + } + } + + if(r->gdi.hMask != NULL) DeleteObject(r->gdi.hMask); + if(r->gdi.hMask2 != NULL) DeleteObject(r->gdi.hMask2); + + r->gdi.hMask = CreateBitmap(r->common.width, r->common.height, 1, 1, words); + r->gdi.hMask2 = CreateBitmap(r->common.width, r->common.height, 1, 1, words2); + + free(words); + free(words2); +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap->common.raw); + DeleteObject(pixmap->gdi.hMask); + DeleteObject(pixmap->gdi.hMask2); + DeleteObject(pixmap->gdi.hBitmap); + + free(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + HDC hmdc = CreateCompatibleDC(handle->gdi.hDC); + POINT p[3]; + SetStretchBltMode(handle->gdi.hDC, HALFTONE); + + p[0].x = rect->x; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width; + p[1].y = rect->y; + + p[2].x = rect->x; + p[2].y = rect->y + rect->height; + + SelectObject(hmdc, pixmap->gdi.hBitmap); + + if(!is_plgblt_reliable || PlgBlt(handle->gdi.hDC, p, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, pixmap->gdi.hMask, 0, 0) == 0) { + SelectObject(hmdc, pixmap->gdi.hMask2); + StretchBlt(handle->gdi.hDC, rect->x, rect->y, rect->width, rect->height, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, SRCAND); + + SelectObject(hmdc, pixmap->gdi.hBitmap); + StretchBlt(handle->gdi.hDC, rect->x, rect->y, rect->width, rect->height, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, SRCPAINT); + } + + DeleteDC(hmdc); +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + ICONINFO ii; + + memset(&ii, 0, sizeof(ii)); + ii.fIcon = TRUE; + ii.xHotspot = 0; + ii.yHotspot = 0; + ii.hbmMask = pixmap->gdi.hMask2; + ii.hbmColor = pixmap->gdi.hBitmap; + + if(handle->gdi.icon != NULL) DestroyIcon(handle->gdi.icon); + handle->gdi.icon = CreateIconIndirect(&ii); + SendMessage(handle->gdi.hWnd, WM_SETICON, ICON_SMALL, (LPARAM)handle->gdi.icon); + SendMessage(handle->gdi.hWnd, WM_SETICON, ICON_BIG, (LPARAM)handle->gdi.icon); +} + +static void MwLLForceRenderImpl(MwLL handle) { + if(!handle->gdi.force_render) { + PostMessage(handle->gdi.hWnd, WM_USER, 0, 0); + + handle->gdi.force_render = 1; + } +} + +HCURSOR MwLLGDICreateCursor(MwCursor* image, MwCursor* mask) { + HCURSOR cursor; + BYTE* dmask = malloc((MwCursorDataHeight / 8) * MwCursorDataHeight); + BYTE* dimage = malloc((MwCursorDataHeight / 8) * MwCursorDataHeight); + int y, x, ys, xs; + + xs = -mask->x + image->x; + ys = mask->height + mask->y; + ys = image->height + image->y - ys; + + if(ys < 0) ys = -ys; + + memset(dmask, 0xff, (MwCursorDataHeight / 8) * MwCursorDataHeight); + memset(dimage, 0, (MwCursorDataHeight / 8) * MwCursorDataHeight); + + for(y = 0; y < mask->height; y++) { + BYTE* l = &dmask[y * (MwCursorDataHeight / 8)]; + unsigned int n = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + l[x / 8] = l[x / 8] >> 1; + if(!(n & 1)) { + l[x / 8] |= 1 << 7; + } + + n = n >> 1; + } + } + + for(y = 0; y < image->height; y++) { + BYTE* l = &dimage[(y + ys) * (MwCursorDataHeight / 8)]; + unsigned int n = image->data[y]; + + for(x = image->width - 1; x >= 0; x--) { + if(n & 1) { + l[(x + xs) / 8] |= (1 << (7 - ((x + xs) % 8))); + } + + n = n >> 1; + } + } + + cursor = CreateCursor(GetModuleHandle(NULL), xs - image->x, ys + (MwCursorDataHeight + image->y), MwCursorDataHeight, MwCursorDataHeight, dmask, dimage); + + free(dimage); + free(dmask); + + return cursor; +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + HCURSOR cursor = MwLLGDICreateCursor(image, mask); + + if(handle->gdi.cursor != NULL) DestroyCursor(handle->gdi.cursor); + if(handle->gdi.icon != NULL) DestroyIcon(handle->gdi.icon); + handle->gdi.cursor = cursor; +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + RECT rc, rc2; + LPARAM lp = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE); + LPARAM lp2 = GetWindowLongPtr(handle->gdi.hWnd, GWL_EXSTYLE); + + lp &= WS_VISIBLE; + + GetWindowRect(GetParent(handle->gdi.hWnd), &rc); + + GetClientRect(handle->gdi.hWnd, &rc2); + + if(lp2 & WS_EX_TOOLWINDOW) { + SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)lp); + } else { + SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)WS_OVERLAPPEDWINDOW | lp); + } + SetParent(handle->gdi.hWnd, NULL); + + rc.left += point->x; + rc.top += point->y; + + AdjustWindowRect(&rc2, GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE), FALSE); + rc2.right -= rc2.left; + rc2.bottom -= rc2.top; + + SetWindowPos(handle->gdi.hWnd, HWND_TOPMOST, rc.left, rc.top, rc2.right == 0 ? 1 : rc2.right, rc2.bottom == 0 ? 1 : rc2.bottom, SWP_FRAMECHANGED | SWP_NOACTIVATE); + + handle->gdi.get_darktheme = 1; +} + +static void MwLLShowImpl(MwLL handle, int show) { + ShowWindow(handle->gdi.hWnd, show ? SW_NORMAL : SW_HIDE); + if(show) SetFocus(handle->gdi.hWnd); +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + (void)handle; + (void)parent; + /* TODO */ +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { + userdata_t* u = (userdata_t*)GetWindowLongPtr(handle->gdi.hWnd, GWLP_USERDATA); + + u->min_set = u->max_set = 1; + u->min.x = minx; + u->min.y = miny; + u->max.x = maxx; + u->max.y = maxy; +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + LPARAM lp = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE); + + if(toggle) { + lp &= ~WS_CAPTION; + } else { + lp |= WS_CAPTION; + } + + SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, lp); + + SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); +} + +static void MwLLFocusImpl(MwLL handle) { + SetFocus(handle->gdi.hWnd); +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + if(toggle) { + POINT p; + RECT rc; + + GetClientRect(handle->gdi.hWnd, &rc); + + rc.right -= rc.left; + rc.bottom -= rc.top; + + p.x = (rc.right - rc.left) / 2; + p.y = (rc.bottom - rc.top) / 2; + + MapWindowPoints(handle->gdi.hWnd, HWND_DESKTOP, &p, 1); + + handle->gdi.grabbed = 1; + + SetFocus(handle->gdi.hWnd); + + GetWindowRect(handle->gdi.hWnd, &rc); + ClipCursor(&rc); + + SetCursorPos(p.x, p.y); + } else { + handle->gdi.grabbed = 0; + ClipCursor(NULL); + } +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + HGLOBAL hg; + (void)clipboard_type; + if(OpenClipboard(handle->gdi.hWnd) != 0) { + char* lock; + + EmptyClipboard(); + hg = GlobalAlloc(GHND | GMEM_SHARE, strlen(text) + 1); + + lock = GlobalLock(hg); + strcpy(lock, text); + GlobalUnlock(hg); + + SetClipboardData(CF_TEXT, hg); + + CloseClipboard(); + } +} + +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + (void)clipboard_type; + handle->gdi.get_clipboard = 1; /* nishi: we do this to make clipboard api work similar to other backends */ +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { + LPARAM lp = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE) & (WS_VISIBLE | WS_CHILD); + RECT rc; + int w, h; + + SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)lp); + SetWindowLongPtr(handle->gdi.hWnd, GWL_EXSTYLE, (LPARAM)WS_EX_TOOLWINDOW); + + GetClientRect(handle->gdi.hWnd, &rc); + + w = rc.right - rc.left; + h = rc.bottom - rc.top; + + SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, w, h, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + POINT p; + + (void)handle; + + GetCursorPos(&p); + + point->x = p.x; + point->y = p.y; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + RECT rc; + + (void)handle; + + GetClientRect(GetDesktopWindow(), &rc); + + rect->x = rect->y = 0; + rect->width = rc.right - rc.left; + rect->height = rc.bottom - rc.top; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + (void)handle; +} + +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + BOOL v = toggle ? TRUE : FALSE; + + if(DwmSetWindowAttribute) + DwmSetWindowAttribute(handle->gdi.hWnd, 20, &v, sizeof(v)); +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + OSVERSIONINFO osvi; + + (void)handle; + + osvi.dwOSVersionInfoSize = sizeof(osvi); + + GetVersionEx(&osvi); + + if(osvi.dwMajorVersion < 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion < 1)) { + return MwFALSE; + } + + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + if(rect == NULL) { + SelectClipRgn(handle->gdi.hDC, NULL); + + if(handle->gdi.clip != NULL) { + DeleteObject(handle->gdi.clip); + handle->gdi.clip = NULL; + } + } else { + HRGN clip = CreateRectRgn(rect->x, rect->y, rect->x + rect->width, rect->y + rect->height); + + SelectClipRgn(handle->gdi.hDC, clip); + + if(handle->gdi.clip != NULL) DeleteObject(handle->gdi.clip); + + handle->gdi.clip = clip; + } +} + +static int MwLLGDICallInitImpl(void) { + void* ntdll; + + memset(&wsymtbl, 0, sizeof(wsymtbl)); + + wsymtbl.lib_dwmapi = MwDynamicOpen("dwmapi.dll"); + + if(wsymtbl.lib_dwmapi != NULL) DwmSetWindowAttribute = MwDynamicSymbol(wsymtbl.lib_dwmapi, "DwmSetWindowAttribute"); + + if((ntdll = GetModuleHandle("ntdll.dll")) != NULL && GetProcAddress(ntdll, "wine_get_version") != NULL) { + is_plgblt_reliable = 0; + } else { + is_plgblt_reliable = 1; + } + + /* TODO: check properly */ + return 0; +} + +#include "call.c" +CALL(GDI); diff --git a/widget/milsko/milskosrc/src/backend/haiku.cc b/widget/milsko/milskosrc/src/backend/haiku.cc new file mode 100644 index 0000000000..8c4f8bf135 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/haiku.cc @@ -0,0 +1,906 @@ +#include + +#include "../../external/stb_ds.h" + +MwApplication::MwApplication(MwRect rc, MwLL handle) + : BApplication("application/milsko-generic") { + BScreen* scr = new BScreen(); + float x = (scr->Frame().Width() - rc.width) / 2; + float y = (scr->Frame().Height() - rc.height) / 2; + BRect rc2; + int dx = rc.x == MwDEFAULT; + int dy = rc.y == MwDEFAULT; + + rc.x += dx ? -rc.x : 0; + rc.y += dy ? -rc.y : 0; + + if(dx) rc.x += x; + if(dy) rc.y += y; + + rc2 = BRect(rc.x, rc.y, rc.x + rc.width - 1, rc.y + rc.height - 1); + + handle->haiku.window = new MwWindow(rc2, B_TITLED_WINDOW, 0); + handle->haiku.window->Show(); + + handle->haiku.view = new MwView(handle, handle->haiku.window->Bounds(), B_FOLLOW_ALL_SIDES, B_WILL_DRAW); + + handle->haiku.window->AddChild(handle->haiku.view); + + delete scr; +} + +MwApplication::~MwApplication() { +} + +void MwApplication::MessageReceived(BMessage* message) { + switch(message->what) { + case BAPP_MW_DESTROY: + { + this->Quit(); + break; + } + default: + { + BLooper::MessageReceived(message); + break; + } + } +} + +MwView::MwView(MwLL handle, BRect frame, uint32 resizingMode, uint32 flags) + : BView(frame, NULL, resizingMode, flags | B_FRAME_EVENTS) { + this->handle = handle; + + this->locker = new BLocker(); + + this->SetDrawingMode(B_OP_OVER); + this->SetLineMode(B_BUTT_CAP, B_BUTT_JOIN); + + this->SetViewColor(B_TRANSPARENT_COLOR); + + this->buttons = 0; +} + +MwView::~MwView() { + delete this->locker; +} + +void MwView::MessageReceived(BMessage* message) { + switch(message->what) { + case BVIEW_MW_DESTROY: + { + this->RemoveSelf(); + delete this; + break; + } + case BVIEW_MW_DETACH: + { + BRect rc; + BPoint point; + + if(message->FindPoint("view-point", &point) != B_OK) break; + + point = this->ConvertToScreen(this->ConvertFromParent(point)); + + rc.left = point.x; + rc.top = point.y; + rc.right = rc.left + this->handle->haiku.width - 1; + rc.bottom = rc.top + this->handle->haiku.height - 1; + + if(this->Parent() != NULL) { + this->RemoveSelf(); + } + + this->handle->haiku.parent = NULL; + + this->handle->haiku.window = new MwWindow(rc, B_TITLED_WINDOW, 0); + this->handle->haiku.window->Show(); + + this->MoveTo(0, 0); + this->ResizeTo(this->handle->haiku.width, this->handle->haiku.height); + this->SetResizingMode(B_FOLLOW_ALL_SIDES); + this->handle->haiku.window->AddChild(this); + + while(this->Window() != this->handle->haiku.window); + + MwLLForceRender(this->handle); + break; + } + case BVIEW_MW_RESIZE: + { + int width, height; + + if(message->FindInt32("view-width", &width) != B_OK) break; + if(message->FindInt32("view-height", &height) != B_OK) break; + + if(this->handle->haiku.window == NULL) { + this->ResizeTo(width - 1, height - 1); + } else { + this->handle->haiku.window->ResizeTo(width - 1, height - 1); + this->ResizeTo(width - 1, height - 1); + } + this->Draw(BRect(0, 0, 0, 0)); + break; + } + case BVIEW_MW_MOVE: + { + int x, y; + + if(message->FindInt32("view-x", &x) != B_OK) break; + if(message->FindInt32("view-y", &y) != B_OK) break; + + if(this->handle->haiku.app == NULL) { + this->MoveTo(x, y); + } else { + this->Window()->MoveTo(x, y); + } + break; + } + case BVIEW_MW_SHOW: + { + if(this->Parent() == NULL) { + this->handle->haiku.parent->haiku.view->AddChild(this); + } + break; + } + case BVIEW_MW_HIDE: + { + if(this->Parent() != NULL) { + this->RemoveSelf(); + } + break; + } + case BVIEW_MW_SET_COLOR: + { + int32 rgb[3]; + int i; + + rgb[0] = rgb[1] = rgb[2] = 0; + + for(i = 0; i < 3 && message->FindInt32("view-color", i, &rgb[i]) == B_OK; i++); + + this->SetHighColor(rgb[0], rgb[1], rgb[2]); + + break; + } + case BVIEW_MW_POLYGON: + { + int i; + BPoint p; + BPoint points[32]; + + for(i = 0; i < 32 && message->FindPoint("view-point", i, &p) == B_OK; i++) { + points[i] = p; + } + + this->FillPolygon(points, i); + break; + } + case BVIEW_MW_LINE: + { + int i; + BPoint p; + BPoint points[2]; + + for(i = 0; i < 2 && message->FindPoint("view-point", i, &p) == B_OK; i++) { + points[i] = p; + } + + this->StrokeLine(points[0], points[1]); + break; + } + case BVIEW_MW_BITMAP: + { + BRect rc; + BBitmap* bitmap; + + if(message->FindRect("view-rect", &rc) != B_OK) break; + if(message->FindPointer("view-bitmap", (void**)&bitmap) != B_OK) break; + + this->DrawBitmap(bitmap, rc); + break; + } + case BVIEW_MW_RENDER: + { + this->Invalidate(); + break; + } + case BVIEW_MW_RAISE: + { + BView* v = this->Parent(); + + this->RemoveSelf(); + v->AddChild(this); + break; + } + case BVIEW_MW_GET_MOUSE: + { + BPoint* p; + uint32 btn; + + if(message->FindPointer("view-ppoint", (void**)&p) != B_OK) break; + + this->GetMouse(p, &btn); + + break; + } + default: + { + BView::MessageReceived(message); + break; + } + } +} + +void MwView::PostMessage(BMessage* message) { + BMessage copy = *message; + MwLL top = this->handle; + + while(top->haiku.parent != NULL) top = top->haiku.parent; + + copy.AddPointer("window-view", this); + + top->haiku.window->PostMessage(©); +} + +void MwView::PostMessage(uint32 command) { + BMessage msg(command); + + this->PostMessage(&msg); +} + +status_t MwView::SendMessage(BMessage* message) { + BMessage copy = *message; + BMessage reply; + MwLL top = this->handle; + + while(top->haiku.parent != NULL) top = top->haiku.parent; + + copy.AddPointer("window-view", this); + + return BMessenger(top->haiku.window).SendMessage(©, &reply); +} + +status_t MwView::SendMessage(uint32 command) { + BMessage msg(command); + + return this->SendMessage(&msg); +} + +void MwView::Invalidate() { + this->Draw(BRect(0, 0, 0, 0)); +} + +void MwView::AttachedToWindow() { + this->SetOrigin(0, 0); +} + +void MwView::Draw(BRect updateRect) { + MwLLHaikuEvent ev; + + (void)updateRect; + + ev.type = MwLLHAIKU_EVENT_DRAW; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::FrameResized(float width, float height) { + MwLLHaikuEvent ev; + + ev.type = MwLLHAIKU_EVENT_FRAMERESIZED; + ev.frame_resized.width = width; + ev.frame_resized.height = height; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::MouseDown(BPoint point) { + MwLLHaikuEvent ev; + uint32 btn; + BPoint p; + + this->GetMouse(&p, &btn, false); + + this->SetMouseEventMask(B_LOCK_WINDOW_FOCUS); + + ev.type = MwLLHAIKU_EVENT_MOUSEDOWN; + ev.mouse.point.x = point.x; + ev.mouse.point.y = point.y; + + if((btn & B_PRIMARY_MOUSE_BUTTON) && !(this->buttons & B_PRIMARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_LEFT; + } else if((btn & B_SECONDARY_MOUSE_BUTTON) && !(this->buttons & B_SECONDARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_RIGHT; + } else if((btn & B_TERTIARY_MOUSE_BUTTON) && !(this->buttons & B_TERTIARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_MIDDLE; + } + this->buttons = btn; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::MouseUp(BPoint point) { + MwLLHaikuEvent ev; + uint32 btn; + BPoint p; + + this->GetMouse(&p, &btn, false); + + ev.type = MwLLHAIKU_EVENT_MOUSEUP; + ev.mouse.point.x = point.x; + ev.mouse.point.y = point.y; + + if(!(btn & B_PRIMARY_MOUSE_BUTTON) && (this->buttons & B_PRIMARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_LEFT; + } else if(!(btn & B_SECONDARY_MOUSE_BUTTON) && (this->buttons & B_SECONDARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_RIGHT; + } else if(!(btn & B_TERTIARY_MOUSE_BUTTON) && (this->buttons & B_TERTIARY_MOUSE_BUTTON)) { + ev.mouse.button = MwMOUSE_MIDDLE; + } + this->buttons = btn; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::MouseMoved(BPoint point, uint32 transit, const BMessage* message) { + MwLLHaikuEvent ev; + + (void)transit; + (void)message; + + ev.type = MwLLHAIKU_EVENT_MOUSEMOVED; + ev.mouse.point.x = point.x; + ev.mouse.point.y = point.y; + ev.mouse.button = 0; + + this->locker->Lock(); + arrput(this->handle->haiku.events, ev); + this->locker->Unlock(); +} + +void MwView::SetColor(MwLLColor color) { + BMessage msg(BVIEW_MW_SET_COLOR); + + msg.AddInt32("view-color", color->common.red); + msg.AddInt32("view-color", color->common.green); + msg.AddInt32("view-color", color->common.blue); + + this->PostMessage(&msg); +} + +MwWindow::MwWindow(BRect frame, window_type type, uint32 flags) + : BWindow(frame, "Milsko", type, flags) { +} + +void MwWindow::MessageReceived(BMessage* message) { + void* ptr; + + if(message->FindPointer("window-view", &ptr) == B_OK) { + MwView* v = (MwView*)ptr; + + v->MessageReceived(message); + + return; + } + + switch(message->what) { + case BVIEW_MW_DESTROY: + { + this->Quit(); + delete this; + break; + } + case BWIN_MW_SET_TITLE: + { + const char* title; + + if(message->FindString("window-title", &title) != B_OK) break; + + this->SetTitle(title); + break; + } + case BWIN_MW_SET_TYPE: + { + int type; + + if(message->FindInt32("window-type", &type) != B_OK) break; + + this->SetType((window_type)type); + + if(type == B_UNTYPED_WINDOW) { + this->SetLook(B_NO_BORDER_WINDOW_LOOK); + } + break; + } + default: + { + BWindow::MessageReceived(message); + break; + } + } +} + +void MwWindow::FrameMoved(BPoint newLocation) { + MwLLHaikuEvent ev; + MwView* v = (MwView*)this->ChildAt(0); + + ev.type = MwLLHAIKU_EVENT_FRAMEMOVED; + ev.frame_moved.point.x = newLocation.x; + ev.frame_moved.point.y = newLocation.y; + + v->locker->Lock(); + arrput(v->handle->haiku.events, ev); + v->locker->Unlock(); +} + +bool MwWindow::QuitRequested() { + MwLLHaikuEvent ev; + MwView* v = (MwView*)this->ChildAt(0); + + ev.type = MwLLHAIKU_EVENT_CLOSE; + + v->locker->Lock(); + arrput(v->handle->haiku.events, ev); + v->locker->Unlock(); + + return false; +} + +struct app_param { + MwRect rc; + MwLL handle; +}; + +static int32 app_thread(void* data) { + struct app_param* r = (struct app_param*)data; + + r->handle->haiku.app = new MwApplication(r->rc, r->handle); + r->handle->haiku.app->Run(); + + free(r); + + return 0; +} + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r = (MwLL)malloc(sizeof(*r)); + MwRect mrc; + BRect rc = BRect(x, y, x + width - 1, y + height - 1); + + mrc.x = x; + mrc.y = y; + mrc.width = width; + mrc.height = height; + + MwLLCreateCommon(r); + + r->common.copy_buffer = 1; + r->common.type = MwLLBackendHaiku; + + r->haiku.force_render = 0; + + r->haiku.parent = parent; + + r->haiku.events = NULL; + + if(parent == NULL) { + struct app_param* p = (struct app_param*)malloc(sizeof(*p)); + + r->haiku.app = NULL; + + p->rc = mrc; + p->handle = r; + + r->haiku.app = NULL; + r->haiku.window = NULL; + r->haiku.view = NULL; + + r->haiku.app_thread = spawn_thread(app_thread, NULL, B_NORMAL_PRIORITY, p); + resume_thread(r->haiku.app_thread); + + while(r->haiku.app == NULL || r->haiku.window == NULL || r->haiku.view == NULL) MwTimeSleep(10); + } else { + MwLL top = r; + while(top->haiku.parent != NULL) { + top = top->haiku.parent; + } + + r->haiku.app = NULL; + r->haiku.window = NULL; + r->haiku.view = new MwView(r, rc, B_FOLLOW_NONE, B_WILL_DRAW); + + parent->haiku.view->AddChild(r->haiku.view); + + r->haiku.view->SendMessage(BVIEW_MW_RAISE); + } + + r->haiku.x = x; + r->haiku.y = y; + r->haiku.width = width; + r->haiku.height = height; + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MwLLDestroyCommon(handle); + + handle->haiku.view->PostMessage(BVIEW_MW_DESTROY); + + if(handle->haiku.app != NULL) { + status_t exit_value; + + handle->haiku.app->PostMessage(BAPP_MW_DESTROY); + wait_for_thread(handle->haiku.app_thread, &exit_value); + + delete handle->haiku.app; + } else if(handle->haiku.window != NULL) { + handle->haiku.window->PostMessage(BWIN_MW_DESTROY); + } + + free(handle); +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + int i; + BMessage msg(BVIEW_MW_POLYGON); + + for(i = 0; i < points_count; i++) { + BPoint p(points[i].x, points[i].y); + + msg.AddPoint("view-point", p); + } + + handle->haiku.view->SetColor(color); + handle->haiku.view->PostMessage(&msg); +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + int i; + BMessage msg(BVIEW_MW_LINE); + + for(i = 0; i < 2; i++) { + BPoint p(points[i].x, points[i].y); + + msg.AddPoint("view-point", p); + } + + handle->haiku.view->SetColor(color); + handle->haiku.view->PostMessage(&msg); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = (MwLLColor)malloc(sizeof(*c)); + + MwLLColorUpdate(handle, c, r, g, b); + + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} + +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} + +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + *x = handle->haiku.x; + *y = handle->haiku.y; + *w = handle->haiku.width; + *h = handle->haiku.height; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + BMessage msg(BVIEW_MW_MOVE); + + handle->haiku.x = x; + handle->haiku.y = y; + + msg.AddInt32("view-x", x); + msg.AddInt32("view-y", y); + + handle->haiku.view->PostMessage(&msg); +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + BMessage msg(BVIEW_MW_RESIZE); + + handle->haiku.width = w; + handle->haiku.height = h; + + msg.AddInt32("view-width", w); + msg.AddInt32("view-height", h); + + handle->haiku.view->PostMessage(&msg); + + MwLLDispatch(handle, resize, NULL); +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + BMessage msg(BWIN_MW_SET_TITLE); + + if(handle->haiku.app == NULL) return; + + msg.AddString("window-title", title); + + handle->haiku.window->PostMessage(&msg); +} + +static int MwLLPendingImpl(MwLL handle) { + handle->haiku.view->locker->Lock(); + if(arrlen(handle->haiku.events) > 0) { + handle->haiku.view->locker->Unlock(); + return 1; + } + handle->haiku.view->locker->Unlock(); + + return 0; +} + +static void MwLLNextEventImpl(MwLL handle) { + int rendered = 0; + + handle->haiku.view->locker->Lock(); + while(arrlen(handle->haiku.events) > 0) { + MwLLHaikuEvent* ev = &handle->haiku.events[0]; + MwMouse m; + + if(ev->type == MwLLHAIKU_EVENT_MOUSEDOWN || ev->type == MwLLHAIKU_EVENT_MOUSEUP) { + m.point = ev->mouse.point; + m.button = ev->mouse.button; + } + + if(ev->type == MwLLHAIKU_EVENT_DRAW) { + MwLLDispatch(handle, draw, NULL); + + rendered = 1; + } else if(ev->type == MwLLHAIKU_EVENT_CLOSE) { + MwLLDispatch(handle, close, NULL); + } else if(ev->type == MwLLHAIKU_EVENT_FRAMERESIZED) { + handle->haiku.width = ev->frame_resized.width + 1; + handle->haiku.height = ev->frame_resized.height + 1; + + MwLLDispatch(handle, resize, NULL); + } else if(ev->type == MwLLHAIKU_EVENT_FRAMEMOVED) { + handle->haiku.x = ev->frame_moved.point.x + 1; + handle->haiku.y = ev->frame_moved.point.y + 1; + } else if(ev->type == MwLLHAIKU_EVENT_MOUSEDOWN) { + MwLLDispatch(handle, down, &m); + } else if(ev->type == MwLLHAIKU_EVENT_MOUSEUP) { + MwLLDispatch(handle, up, &m); + } else if(ev->type == MwLLHAIKU_EVENT_MOUSEMOVED) { + MwLLDispatch(handle, move, &ev->mouse.point); + } + + arrdel(handle->haiku.events, 0); + } + handle->haiku.view->locker->Unlock(); + + if(rendered) handle->haiku.force_render = 0; +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + MwLLPixmap r = (MwLLPixmap)malloc(sizeof(*r)); + + (void)handle; + + r->common.raw = (unsigned char*)malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + r->common.width = width; + r->common.height = height; + + r->haiku.bitmap = NULL; + + MwLLPixmapUpdate(r); + return r; + + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { + uint32* px = (uint32*)malloc(4 * pixmap->common.width * pixmap->common.height); + int i; + + for(i = 0; i < pixmap->common.width * pixmap->common.height; i++) { + unsigned char* ipx = &pixmap->common.raw[4 * i]; + + px[i] = (ipx[3] << 24) | (ipx[0] << 16) | (ipx[1] << 8) | (ipx[2] << 0); + } + + if(pixmap->haiku.bitmap != NULL) delete pixmap->haiku.bitmap; + + pixmap->haiku.bitmap = new BBitmap(BRect(0, 0, pixmap->common.width - 1, pixmap->common.height - 1), B_RGBA32); + + pixmap->haiku.bitmap->SetBits(px, pixmap->common.width * pixmap->common.height * 4, 0, B_RGBA32); + + free(px); +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap->common.raw); + + free(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + BRect rc; + BMessage msg(BVIEW_MW_BITMAP); + + rc = BRect(rect->x, rect->y, rect->x + rect->width - 1, rect->y + rect->height - 1); + + msg.AddRect("view-rect", rc); + msg.AddPointer("view-bitmap", pixmap->haiku.bitmap); + + handle->haiku.view->PostMessage(&msg); +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + (void)handle; + (void)pixmap; +} + +static void MwLLForceRenderImpl(MwLL handle) { + if(handle->haiku.force_render) return; + + handle->haiku.force_render = 1; + handle->haiku.view->PostMessage(BVIEW_MW_RENDER); +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + (void)handle; + (void)image; + (void)mask; +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + BMessage msg(BVIEW_MW_DETACH); + + msg.AddPoint("view-point", BPoint(point->x, point->y)); + + handle->haiku.view->PostMessage(&msg); + + while(handle->haiku.window == NULL); +} + +static void MwLLShowImpl(MwLL handle, int show) { + if(show) { + handle->haiku.view->PostMessage(BVIEW_MW_SHOW); + } else { + handle->haiku.view->PostMessage(BVIEW_MW_HIDE); + } +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { + (void)handle; + (void)minx; + (void)miny; + (void)maxx; + (void)maxy; +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + if(toggle) { + handle->haiku.type = B_TITLED_WINDOW; + } else { + handle->haiku.type = B_UNTYPED_WINDOW; + } +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { + handle->haiku.type = B_UNTYPED_WINDOW; +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + (void)handle; + (void)parent; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + handle->haiku.type = handle->haiku.window == NULL ? B_TITLED_WINDOW : handle->haiku.window->Type(); +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + BMessage msg(BWIN_MW_SET_TYPE); + + msg.AddInt32("window-type", handle->haiku.type); + + BMessenger(handle->haiku.window).SendMessage(&msg); +} + +static void MwLLFocusImpl(MwLL handle) { + (void)handle; +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + (void)handle; + (void)text; + (void)clipboard_type; +} + +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + (void)handle; + (void)clipboard_type; +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + MwLL top = handle; + BMessage msg(BVIEW_MW_GET_MOUSE); + BPoint p; + while(top->haiku.parent != NULL) { + top = top->haiku.parent; + } + + msg.AddPointer("view-ppoint", &p); + top->haiku.view->SendMessage(&msg); + + point->x = p.x; + point->y = p.y; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + BScreen* screen = new BScreen(); + + (void)handle; + + if(screen->IsValid()) { + rect->width = screen->Frame().Width(); + rect->height = screen->Frame().Height(); + } + + delete screen; +} + +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + handle->haiku.view->SendMessage(BVIEW_MW_RAISE); +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + +int MwLLHaikuCallInitImpl() { + return 0; +} + +#include "call.c" +CALL(Haiku); diff --git a/widget/milsko/milskosrc/src/backend/nococoa.m b/widget/milsko/milskosrc/src/backend/nococoa.m new file mode 100644 index 0000000000..c009b38d31 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/nococoa.m @@ -0,0 +1,9 @@ +#include +#import + +void MwLLNoCocoaErrorMessage(void) { + NSAlert* alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Milsko applications currently requires XQuartz or cocoa-way. PRs are welcome for anyone who wants to finish the Cocoa backend (prefarably in Objective-C)"]; + [alert addButtonWithTitle:@"Ok"]; + [alert runModal]; +} diff --git a/widget/milsko/milskosrc/src/backend/wayland/buffer.c b/widget/milsko/milskosrc/src/backend/wayland/buffer.c new file mode 100644 index 0000000000..df1de797c5 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/wayland/buffer.c @@ -0,0 +1,114 @@ +#include +#include + +void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland) { + MwLLWaylandBufferSetup(&wayland->framebuffer, wayland->ww, wayland->wh); + + MwLLCairoFrontSetup(&wayland->cairo, wayland->framebuffer.buf_back, wayland->ww, wayland->wh); + + memset(wayland->framebuffer.buf_back, 0, wayland->framebuffer.buf_size); + if(wayland->configured) + wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0); + wl_surface_commit(wayland->framebuffer.surface); + + MwLLWaylandHangUntilConfigured((MwLL)wayland); + MwLLWaylandBufferUpdate((MwLL)wayland, &wayland->framebuffer); +}; +void MwLLWaylandFramebufferDestroy(struct _MwLLWayland* wayland) { + wl_surface_attach(wayland->framebuffer.surface, NULL, 0, 0); + MwLLWaylandBufferDestroy(&wayland->framebuffer); + MwLLCairoFrontDestroy(&wayland->cairo); +}; + +void MwLLWaylandBackbufferSetup(struct _MwLLWayland* wayland) { + if(wayland->type != MwLL_WAYLAND_TOPLEVEL) { + return; + } + MwU32 w = wayland->ww; + MwU32 h = wayland->wh; + if(!wayland->has_decorations && wayland->do_csd) { + w += (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); + h += (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + } + MwLLWaylandBufferSetup(&wayland->backbuffer, w, h); + + MwLLCairoBackSetup(&wayland->cairo, wayland->backbuffer.buf_back, w, h); + + memset(wayland->backbuffer.buf_back, 255, wayland->backbuffer.buf_size); + if(wayland->configured) + wl_surface_attach(wayland->backbuffer.surface, wayland->backbuffer.shm_buffer, 0, 0); + wl_surface_commit(wayland->backbuffer.surface); + MwLLWaylandHangUntilConfigured((MwLL)wayland); + MwLLWaylandBufferUpdate((MwLL)wayland, &wayland->backbuffer); +}; +void MwLLWaylandBackbufferDestroy(struct _MwLLWayland* wayland) { + // wl_surface_attach(wayland->backbuffer.surface, NULL, 0, 0); + MwLLWaylandBufferDestroy(&wayland->backbuffer); + MwLLCairoBackDestroy(&wayland->cairo); +}; + +void MwLLWaylandBufferSetup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { + int stride = width * 4; + char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; + char temp_name_back[] = "/tmp/milsko-wl-shm-back-XXXXXX"; + + buffer->buf_size = width * height * 4; + + buffer->fd = mkstemp(temp_name); + buffer->fd_back = mkstemp(temp_name_back); + + unlink(temp_name); + unlink(temp_name_back); + + if(posix_fallocate(buffer->fd, 0, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); + close(buffer->fd); + return; + } + if(posix_fallocate(buffer->fd_back, 0, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); + close(buffer->fd_back); + return; + } + if(ftruncate(buffer->fd, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); + close(buffer->fd); + return; + } + if(ftruncate(buffer->fd_back, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); + close(buffer->fd_back); + return; + } + + buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); + buffer->buf_back = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd_back, 0); + + fsync(buffer->fd); + fsync(buffer->fd_back); + + if(!(buffer->shm_pool = wl_shm_create_pool(buffer->shm, buffer->fd, buffer->buf_size))) { + printf("failure setting up wl_shm: could not create pool.\n"); + } + if(!(buffer->shm_pool_back = wl_shm_create_pool(buffer->shm, buffer->fd_back, buffer->buf_size))) { + printf("failure setting up wl_shm: could not create pool.\n"); + } + buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->shm_buffer_back = wl_shm_pool_create_buffer(buffer->shm_pool_back, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->setup = MwTRUE; +} + +void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer) { + if(!buffer->setup) { + return; + } + if(buffer->buf) munmap(buffer->buf, buffer->buf_size); + if(buffer->buf_back) munmap(buffer->buf_back, buffer->buf_size); + if(buffer->shm_buffer) wl_buffer_destroy(buffer->shm_buffer); + if(buffer->shm_buffer_back) wl_buffer_destroy(buffer->shm_buffer_back); + if(buffer->shm_pool) wl_shm_pool_destroy(buffer->shm_pool); + if(buffer->shm_pool_back) wl_shm_pool_destroy(buffer->shm_pool_back); + close(buffer->fd); + close(buffer->fd_back); + buffer->setup = MwFALSE; +} diff --git a/widget/milsko/milskosrc/src/backend/wayland/interfaces.c b/widget/milsko/milskosrc/src/backend/wayland/interfaces.c new file mode 100644 index 0000000000..84ed4923de --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/wayland/interfaces.c @@ -0,0 +1,1225 @@ +#include +#include +#include "../../../external/stb_ds.h" + +/* TODO: find out what FreeBSD and such wants us to include */ +#ifdef __FreeBSD__ +/* XXX: Untested (nishi) */ +#include +#else +#include +#include +#endif + +#include + +static void setup_clipboard(MwLL self, struct wl_seat* wl_seat); +static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); + +static void destroy_clipboard(MwLL self, struct wl_seat* wl_seat); +static void destroy_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); + +/* Recursively dispatch a move event to a widget and its children */ +static void recursive_dispatch_move(MwLL handle, MwMouse* p) { + MwWidget h = (MwWidget)handle->common.user; + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, move, p); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_move(h->children[i]->lowlevel, p); + } + } + } +}; + +/* `wl_registry.global` callback */ +static void new_protocol(void* data, struct wl_registry* registry, + MwU32 name, const char* interface, + MwU32 version) { + MwLL self = data; + (void)version; + (void)registry; + + WAYLAND_EVENT_OP_START(self); + + wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); + if(cb != NULL) { + shput(self->wayland.wl_protocol_map, interface, cb->setup(name, data, version)); + /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ + } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { + self->common.supports_transparency = MwTRUE; + } else { + // printf("unknown interface %s\n", interface); + } + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_registry.global_remove` callback */ +static void protocol_removed(void* data, + struct wl_registry* registry, + MwU32 name) { + (void)data; + (void)registry; + (void)name; + printf("%d destroyed\n", name); +}; + +static void wl_offer(void* data, + struct wl_data_offer* wl_data_offer, + const char* mime_type) { + wl_clipboard_device_context_t* self = data; + wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type); +}; + +struct wl_data_offer_listener offer_listener = { + .offer = wl_offer, +}; + +static void wl_data_device_data_offer(void* data, + struct wl_data_device* wl_data_device, + struct wl_data_offer* offer) { + wl_clipboard_device_context_t* self = data; + (void)wl_data_device; + + wl_data_offer_add_listener(offer, &offer_listener, data); + + self->offer.wl = offer; +}; + +static void wl_data_device_enter(void* data, + struct wl_data_device* wl_data_device, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t x, + wl_fixed_t y, + struct wl_data_offer* id) { + MwLL self = data; + (void)wl_data_device; + (void)surface; + (void)x; + (void)y; + (void)id; + + WAYLAND_EVENT_OP_START(self); + + self->wayland.clipboard_serial = serial; + + WAYLAND_EVENT_OP_END(self); +}; +static void wl_data_device_leave(void* data, + struct wl_data_device* wl_data_device) { + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); + wl_data_device_destroy(wl_data_device); + WAYLAND_EVENT_OP_END(self); +}; +static void wl_data_device_motion(void* data, + struct wl_data_device* wl_data_device, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y) { + (void)data; + (void)wl_data_device; + (void)time; + (void)x; + (void)y; +}; +static void wl_data_device_drop(void* data, + struct wl_data_device* wl_data_device) { + (void)data; + (void)wl_data_device; +}; + +static void wl_data_device_selection(void* data, + struct wl_data_device* wl_data_device, + struct wl_data_offer* id) { + (void)data; + (void)wl_data_device; + (void)id; +}; + +struct wl_data_device_listener wl_data_device_listener = { + .data_offer = wl_data_device_data_offer, + .enter = wl_data_device_enter, + .leave = wl_data_device_leave, + .motion = wl_data_device_motion, + .drop = wl_data_device_drop, + .selection = wl_data_device_selection, +}; + +static void zwp_primary_selection_device_v1_data_offer(void* data, + struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1* offer) { + wl_clipboard_device_context_t* self = data; + (void)zwp_primary_selection_device_v1; + + self->offer.zwp = offer; +}; + +static void zwp_primary_selection_device_v1_selection(void* data, + struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1* id) { + (void)data; + (void)zwp_primary_selection_device_v1; + (void)id; +}; + +struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_listener = { + .data_offer = zwp_primary_selection_device_v1_data_offer, + .selection = zwp_primary_selection_device_v1_selection, +}; + +void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_type) { + int fds[2]; + fd_set set; + char* buf = NULL; + struct timeval timeout; + int rc = 0; + + if(pipe(fds) != 0) { + return; + } + + FD_ZERO(&set); + FD_SET(fds[0], &set); + timeout.tv_sec = 0; + timeout.tv_usec = 100; + + if(clipboard_type == MwCLIPBOARD_PRIMARY && ctx->offer.zwp) { + zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]); + } else if(ctx->offer.wl) { + wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]); + } + close(fds[1]); + + MwLLWaylandFlush(ctx->ll); + wl_display_roundtrip(ctx->ll->wayland.display); + + while(MwTRUE) { + rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); + if(rc <= 0) { + break; + } else { + char b; + ssize_t n = read(fds[0], &b, sizeof(b)); + if(n <= 0) { + break; + } + arrpush(buf, b); + } + } + arrpush(buf, 0); + close(fds[0]); + + MwLLDispatch(ctx->ll, clipboard, buf); + arrfree(buf); + + ctx->ll->wayland.events_pending = 1; +} + +static void wl_data_source_listener_target(void* data, + struct wl_data_source* wl_data_source, + const char* mime_type) { + (void)data; + (void)wl_data_source; + (void)mime_type; +}; +static void wl_data_source_listener_send(void* data, + struct wl_data_source* wl_data_source, + const char* mime_type, + int32_t fd) { + MwLL self = data; + (void)wl_data_source; + (void)mime_type; + + WAYLAND_EVENT_OP_START(self); + if(self->wayland.clipboard_buffer != NULL) { + write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); + close(fd); + } + WAYLAND_EVENT_OP_END(self); +}; +static void wl_data_source_listener_cancelled(void* data, + struct wl_data_source* wl_data_source); + +struct wl_data_source_listener wl_data_source_listener = { + .target = wl_data_source_listener_target, + .send = wl_data_source_listener_send, + .cancelled = wl_data_source_listener_cancelled, +}; + +static void wl_data_source_listener_cancelled(void* data, + struct wl_data_source* wl_data_source) { + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); + + if(wl_data_source) + wl_data_source_destroy(wl_data_source); + + self->wayland.clipboard_source.wl = wl_data_device_manager_create_data_source(self->wayland.clipboard_manager.wl); + + wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain;charset=utf-8"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "TEXT"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "STRING"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "UTF8_STRING"); + + wl_data_source_add_listener(self->wayland.clipboard_source.wl, &wl_data_source_listener, self); + + WAYLAND_EVENT_OP_END(self); +}; + +static void zwp_primary_selection_source_v1_send(void* data, + struct zwp_primary_selection_source_v1* wl_data_source, + const char* mime_type, + int32_t fd) { + MwLL self = data; + (void)wl_data_source; + (void)mime_type; + + WAYLAND_EVENT_OP_START(self); + + if(self->wayland.clipboard_buffer != NULL) { + write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); + close(fd); + } + + WAYLAND_EVENT_OP_END(self); +}; +static void zwp_primary_selection_source_v1_cancelled(void* data, + struct zwp_primary_selection_source_v1* wl_data_source) { + MwLL self = data; + (void)wl_data_source; + + WAYLAND_EVENT_OP_START(self); + + zwp_primary_selection_source_v1_destroy(self->wayland.clipboard_source.zwp); + + self->wayland.clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(self->wayland.clipboard_manager.zwp); + + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "TEXT"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "STRING"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "UTF8_STRING"); + + WAYLAND_EVENT_OP_END(self); +}; + +struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_listener = { + .send = zwp_primary_selection_source_v1_send, + .cancelled = zwp_primary_selection_source_v1_cancelled, +}; + +/* wl_data_device_manager setup function */ +static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 2); + + wayland->clipboard_source.wl = wl_data_device_manager_create_data_source(wayland->clipboard_manager.wl); + + wl_data_source_offer(wayland->clipboard_source.wl, "text/plain"); + wl_data_source_offer(wayland->clipboard_source.wl, "text/plain;charset=utf-8"); + wl_data_source_offer(wayland->clipboard_source.wl, "TEXT"); + wl_data_source_offer(wayland->clipboard_source.wl, "STRING"); + wl_data_source_offer(wayland->clipboard_source.wl, "UTF8_STRING"); + + wl_data_source_add_listener(wayland->clipboard_source.wl, &wl_data_source_listener, wayland); + + if(wayland->pointer_seat) { + setup_clipboard((MwLL)wayland, wayland->pointer_seat); + } + + return NULL; +} + +static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)data; + if(wayland->clipboard_manager.wl != NULL) { + wl_data_device_manager_destroy(wayland->clipboard_manager.wl); + wayland->clipboard_manager.wl = NULL; + } + if(wayland->clipboard_source.wl) { + // wl_data_source_destroy(wayland->clipboard_source.wl); + wayland->clipboard_source.wl = NULL; + } +} + +/* zwp_primary_selection_device_manager_v1 setup function */ +static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->clipboard_manager.zwp = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); + + wayland->clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(wayland->clipboard_manager.zwp); + + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "TEXT"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "STRING"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "UTF8_STRING"); + + zwp_primary_selection_source_v1_add_listener(wayland->clipboard_source.zwp, &zwp_primary_selection_source_v1_listener, wayland); + + wayland->supports_zwp = MwTRUE; + + if(wayland->pointer_seat) { + setup_zwp_clipboard((MwLL)wayland, wayland->pointer_seat); + } + + return NULL; +} + +static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* zwp_primary_selection_device_manager_v1 setup function */ +static wayland_protocol_t* zwp_pointer_constraints_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->pointer_constraints = wl_registry_bind(wayland->registry, name, &zwp_pointer_constraints_v1_interface, 1); + return NULL; +} + +static void zwp_pointer_constraints_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +static struct wl_surface* curSurface = NULL; + +/* `wl_pointer.enter` callback */ +static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, + struct wl_surface* surface, wl_fixed_t surface_x, + wl_fixed_t surface_y) { + MwLL self = data; + MwLL topmost_parent = self; + + (void)surface_x; + (void)surface_y; + (void)wl_pointer; + + WAYLAND_EVENT_OP_START(self); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + if(self->wayland.framebuffer.surface == surface) { + curSurface = surface; + self->wayland.pointer_serial = serial; + + wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, topmost_parent->wayland.cursor.surface, 0, 0); + } + + if(self->wayland.backbuffer.surface == surface) { + curSurface = surface; + } + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_pointer.leave` callback */ +static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, + struct wl_surface* surface) { + MwLL self = data; + (void)wl_pointer; + (void)serial; + (void)surface; + WAYLAND_EVENT_OP_START(self); + curSurface = NULL; + WAYLAND_EVENT_OP_END(self); +}; + +static void xdg_borderless_step_mdown(MwLL self, MwMouse p, MwU32 serial) { + if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == curSurface) { + if(p.point.y >= (self->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM) - 5) { + if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT); + } else { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM); + } + } else if(p.point.y <= 5) { + if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT); + } else { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP); + } + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT); + } else if(p.point.x <= 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_LEFT); + } else if(p.point.y <= CSD_BORDER_FRAME_TOP) { + if(p.point.x >= CSD_BORDER_FRAME_LEFT && p.point.x <= CSD_BORDER_FRAME_LEFT + 18) { + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 21) { + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 38) { + } else { + xdg_toplevel_move(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial); + } + } + }; +} +static void xdg_borderless_step_mup(MwLL self, MwMouse p, MwU32 serial) { + (void)serial; + if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == curSurface) { + if(p.point.y <= CSD_BORDER_FRAME_TOP) { + if(p.point.x >= CSD_BORDER_FRAME_LEFT && p.point.x <= CSD_BORDER_FRAME_LEFT + 18) { + MwLLDispatch(self, close, NULL); + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 21) { + self->wayland.toplevel->maxim_state = !self->wayland.toplevel->maxim_state; + if(self->wayland.toplevel->maxim_state == 0) { + xdg_toplevel_unset_maximized(self->wayland.toplevel->xdg_top_level); + } else { + xdg_toplevel_set_maximized(self->wayland.toplevel->xdg_top_level); + } + self->wayland.setting_wh = 1; + MwLLWaylandRegionSetup(self); + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 38) { + xdg_toplevel_set_minimized(self->wayland.toplevel->xdg_top_level); + } + } + }; +} + +static void relative_pointer_motion(void* data, + struct zwp_relative_pointer_v1* pointer, + uint32_t timeHi, + uint32_t timeLo, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t dxUnaccel, + wl_fixed_t dyUnaccel) { + MwLL self = data; + MwMouse p; + + (void)pointer; + (void)timeHi; + (void)timeLo; + (void)dx; + (void)dy; + + WAYLAND_EVENT_OP_START(self); + + p.point.x = wl_fixed_to_int(dxUnaccel); + p.point.y = wl_fixed_to_int(dyUnaccel); + + recursive_dispatch_move(self, &p); + if(self->wayland.locked_pointer) zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); + + WAYLAND_EVENT_OP_END(self); +} + +struct zwp_relative_pointer_v1_listener MwLLWaylandRelativePointerListener = + { + relative_pointer_motion}; + +/* zwp_primary_selection_device_manager_v1 setup function */ +static wayland_protocol_t* zwp_relative_pointer_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->relative_pointer_manager = wl_registry_bind(wayland->registry, name, &zwp_relative_pointer_manager_v1_interface, 1); + return NULL; +} + +static void zwp_relative_pointer_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* `wl_pointer.motion` callback */ +static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, + wl_fixed_t surface_x, wl_fixed_t surface_y) { + MwLL self = data; + MwLL topmost_parent = self; + MwMouse p; + MwBool inArea = MwFALSE; + MwLL currentlyHeldWidget = NULL; + + (void)time; + (void)wl_pointer; + + WAYLAND_EVENT_OP_START(self); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + currentlyHeldWidget = topmost_parent->wayland.currentlyHeldWidget; + + if(self->wayland.framebuffer.surface) { + inArea |= self->wayland.framebuffer.surface == curSurface; + } + + if(self->wayland.backbuffer.surface) { + inArea |= self->wayland.backbuffer.surface == curSurface; + } + + self->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); + self->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); + if(currentlyHeldWidget != NULL) { + currentlyHeldWidget->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); + currentlyHeldWidget->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); + } + + if(inArea) { + p.point = self->wayland.cur_mouse_pos; + MwLLDispatch(self, move, &p); + + wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); + } else if(currentlyHeldWidget == self) { + p.point = currentlyHeldWidget->wayland.cur_mouse_pos; + MwLLDispatch(currentlyHeldWidget, move, &p); + } + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_pointer.button` callback */ +static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { + MwLL self = data; + MwMouse p; + MwBool inArea = MwFALSE; + MwLL topmost_parent = self; + + (void)wl_pointer; + (void)serial; + (void)time; + + WAYLAND_EVENT_OP_START(self); + + p.point = self->wayland.cur_mouse_pos; + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + if(self->wayland.framebuffer.surface) { + inArea |= self->wayland.framebuffer.surface == curSurface; + } + if(self->wayland.backbuffer.surface) { + inArea |= self->wayland.backbuffer.surface == curSurface; + } + if(inArea) { + switch(button) { + case BTN_LEFT: + p.button = MwMOUSE_LEFT; + break; + case BTN_MIDDLE: + p.button = MwMOUSE_MIDDLE; + break; + case BTN_RIGHT: + p.button = MwMOUSE_RIGHT; + break; + } + self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; + + switch(state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + if(button == BTN_LEFT) { + topmost_parent->wayland.focusedWidget = self; + } + MwLLDispatch(self, down, &p); + topmost_parent->wayland.currentlyHeldWidget = self; + + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + if(topmost_parent->wayland.currentlyHeldWidget != NULL) { + MwLLDispatch(topmost_parent->wayland.currentlyHeldWidget, up, &p); + topmost_parent->wayland.currentlyHeldWidget = NULL; + } else { + MwLLDispatch(self, up, &p); + } + break; + } + } + + if(!self->wayland.has_decorations && self->wayland.do_csd) { + if(state != WL_POINTER_BUTTON_STATE_RELEASED) + xdg_borderless_step_mdown(self, p, serial); + else + xdg_borderless_step_mup(self, p, serial); + } + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_pointer.axis` callback */ +static void pointer_axis(void* data, struct wl_pointer* wl_pointer, MwU32 time, + MwU32 axis, wl_fixed_t value) { + (void)data; + (void)wl_pointer; + (void)time; + (void)axis; + (void)value; +}; + +struct wl_pointer_listener pointer_listener = { + .enter = pointer_enter, + .leave = pointer_leave, + .motion = pointer_motion, + .button = pointer_button, + .axis = pointer_axis, +}; + +/* `wl_keyboard.keymap` callback */ +static void keyboard_keymap(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 format, + int32_t fd, + MwU32 size) { + MwLL self = data; + (void)wl_keyboard; + + if(!self->wayland.parent) { + assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); + + char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + assert(map_shm != MAP_FAILED); + + struct xkb_keymap* xkb_keymap = xkb_keymap_new_from_string( + self->wayland.xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(map_shm, size); + close(fd); + + struct xkb_state* xkb_state = xkb_state_new(xkb_keymap); + + self->wayland.xkb_keymap = xkb_keymap; + self->wayland.xkb_state = xkb_state; + } else { + self->wayland.xkb_keymap = self->wayland.parent->wayland.xkb_keymap; + self->wayland.xkb_state = self->wayland.parent->wayland.xkb_state; + } +}; + +/* `wl_keyboard.enter` callback */ +static void keyboard_enter(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 serial, + struct wl_surface* surface, + struct wl_array* keys) { + MwLL self = data; + (void)wl_keyboard; + (void)surface; + (void)keys; + + WAYLAND_EVENT_OP_START(self); + + self->wayland.keyboard_serial = serial; + + MwLLDispatch(self, focus_in, NULL); + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_keyboard.leave` callback */ +static void keyboard_leave(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 serial, + struct wl_surface* surface) { + MwLL self = data; + (void)wl_keyboard; + (void)serial; + (void)surface; + + WAYLAND_EVENT_OP_START(self); + + MwLLDispatch(self, focus_out, NULL); + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_keyboard.key` callback */ +static void keyboard_key(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 serial, + MwU32 _time, + MwU32 key, + MwU32 state) { + MwLL self = data; + MwBool inArea = 0; + MwLL topmost_parent = self; + + (void)wl_keyboard; + (void)serial; + (void)_time; + + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + WAYLAND_EVENT_OP_START(self); + + if(self->wayland.framebuffer.surface) { + inArea |= self->wayland.framebuffer.surface == curSurface; + } + + if(self->wayland.backbuffer.surface) { + inArea |= self->wayland.backbuffer.surface == curSurface; + } + + inArea |= (self == topmost_parent->wayland.focusedWidget); + + if(inArea) { + xkb_layout_index_t layout; + MwU32 levels; + xkb_level_index_t level = 0; + const xkb_keysym_t* syms_out; + MwU32 keycode = key + 8; + MwU64 syms_num; + int i; + + if(!self->wayland.xkb_keymap) { + WAYLAND_EVENT_OP_END(self); + return; + } + + layout = xkb_state_key_get_layout(self->wayland.xkb_state, keycode); + levels = + xkb_keymap_num_levels_for_key(self->wayland.xkb_keymap, keycode, layout); + + if((((self->wayland.mod_state & 1) == 1) || ((self->wayland.mod_state & 2) == 2)) && levels >= 2) { + level = 1; + } else if(levels >= 1) { + level = 0; + } + syms_num = xkb_keymap_key_get_syms_by_level(self->wayland.xkb_keymap, keycode, layout, level, &syms_out); + if(syms_out == NULL) { + WAYLAND_EVENT_OP_END(self); + return; + } + + for(i = 0; i < syms_num; i++) { + int sym = syms_out[i]; + int key = -1; + + switch(sym) { + case XKB_KEY_BackSpace: + key = MwKEY_BACKSPACE; + break; + case XKB_KEY_Left: + key = MwKEY_LEFT; + break; + case XKB_KEY_Right: + key = MwKEY_RIGHT; + break; + case XKB_KEY_Up: + key = MwKEY_UP; + break; + case XKB_KEY_Down: + key = MwKEY_DOWN; + break; + case XKB_KEY_Return: + key = MwKEY_ENTER; + break; + case XKB_KEY_Escape: + key = MwKEY_ESCAPE; + break; + case XKB_KEY_Shift_L: + key = MwKEY_LEFTSHIFT; + break; + case XKB_KEY_Shift_R: + key = MwKEY_RIGHTSHIFT; + break; + case XKB_KEY_Alt_L: + case XKB_KEY_Alt_R: + key = MwKEY_ALT; + break; + case XKB_KEY_Control_L: + case XKB_KEY_Control_R: + key = MwKEY_CONTROL; + break; + default: + if(MwStringIsKeyUTF8(sym)) { + key = sym; + } + } + + if((self->wayland.mod_state & 4) == 4) { + key |= MwKEY_CONTROL_FLAG; + } + if((self->wayland.mod_state & 8) == 8) { + key |= MwKEY_ALT_FLAG; + } + + if(key != -1) { + if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { + MwLL topmost_parent = self; + while(topmost_parent->wayland.parent) { + MwLLDispatch(topmost_parent, key, &key); + topmost_parent = topmost_parent->wayland.parent; + } + self->wayland.holding_key = MwTRUE; + self->wayland.last_pressed_key = key; + } else { + MwLLDispatch(self, key_released, &key); + self->wayland.holding_key = MwFALSE; + } + self->wayland.start_time = MwTimeGetTick(); + self->wayland.next_elapsed = self->wayland.keyboard_delay; + } + } + } + + if(!MwWaylandVulkan) { + MwLLDispatch(self, draw, NULL); + } + + WAYLAND_EVENT_OP_END(self); +}; + +/* `wl_keyboard.modifiers` callback */ +static void keyboard_modifiers(void* data, + struct wl_keyboard* wl_keyboard, + MwU32 serial, + MwU32 mods_depressed, + MwU32 mods_latched, + MwU32 mods_locked, + MwU32 group) { + MwLL self = data; + (void)wl_keyboard; + (void)serial; + (void)group; + (void)mods_latched; + + WAYLAND_EVENT_OP_START(self); + + self->wayland.mod_state = 0; + self->wayland.mod_state |= mods_depressed; + self->wayland.mod_state |= mods_locked; + + WAYLAND_EVENT_OP_END(self); +}; + +static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat) { + wl_clipboard_device_context_t* device_ctx_zwp = NULL; + device_ctx_zwp = malloc(sizeof(wl_clipboard_device_context_t)); + memset(device_ctx_zwp, 0, sizeof(wl_clipboard_device_context_t)); + device_ctx_zwp->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); + device_ctx_zwp->ll = self; + zwp_primary_selection_device_v1_add_listener(device_ctx_zwp->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx_zwp); + arrpush(self->wayland.clipboard_devices_zwp, device_ctx_zwp); +} +static void setup_clipboard(MwLL self, struct wl_seat* wl_seat) { + wl_clipboard_device_context_t* device_ctx_wl = malloc(sizeof(wl_clipboard_device_context_t)); + memset(device_ctx_wl, 0, sizeof(wl_clipboard_device_context_t)); + + device_ctx_wl->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); + device_ctx_wl->ll = self; + + wl_data_device_add_listener(device_ctx_wl->device.wl, &wl_data_device_listener, device_ctx_wl); + arrpush(self->wayland.clipboard_devices_wl, device_ctx_wl); +}; + +static void keyboard_repeat_info(void* data, + struct wl_keyboard* wl_keyboard, + int32_t rate, + int32_t delay) { + MwLL self = data; + + (void)wl_keyboard; + + self->wayland.keyboard_rate = rate; + self->wayland.keyboard_delay = delay; +}; + +struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_keymap, + .enter = keyboard_enter, + .leave = keyboard_leave, + .key = keyboard_key, + .modifiers = keyboard_modifiers, + .repeat_info = keyboard_repeat_info, +}; + +/* `wl_seat.name` callback */ +static void +wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) { + (void)data; + (void)wl_seat; + (void)name; +}; + +/* `wl_seat.capabilities` callback */ +static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, + MwU32 capabilities) { + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); + + if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + self->wayland.keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data); + } + if(capabilities & WL_SEAT_CAPABILITY_POINTER) { + self->wayland.pointer_seat = wl_seat; + self->wayland.pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); + } + WAYLAND_EVENT_OP_END(self); + + if(self->wayland.clipboard_manager.wl) + setup_clipboard(self, self->wayland.pointer_seat); + if(self->wayland.clipboard_manager.zwp) + setup_zwp_clipboard(self, self->wayland.pointer_seat); +}; + +static void output_geometry(void* data, + struct wl_output* wl_output, + int32_t x, + int32_t y, + int32_t physical_width, + int32_t physical_height, + int32_t subpixel, + const char* make, + const char* model, + int32_t transform) { + (void)data; + (void)wl_output; + (void)x; + (void)y; + (void)physical_width; + (void)physical_height; + (void)subpixel; + (void)make; + (void)model; + (void)transform; +}; +static void output_mode(void* data, + struct wl_output* wl_output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) { + MwLL self = data; + (void)wl_output; + (void)flags; + (void)refresh; + self->wayland.mw = width; + self->wayland.mh = height; +}; + +struct wl_output_listener output_listener = { + .geometry = output_geometry, + .mode = output_mode, +}; + +/* `xdg_wm_base.ping` callback */ +void xdg_wm_base_ping(void* data, + struct xdg_wm_base* xdg_wm_base, + MwU32 serial) { + (void)data; + xdg_wm_base_pong(xdg_wm_base, serial); +}; + +/* wl_seat setup function */ +static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + MwU32 ver = (version >= 4) ? 4 : 1; + proto->listener = malloc(sizeof(struct wl_seat_listener)); + + ((struct wl_seat_listener*)proto->listener)->name = wl_seat_name; + ((struct wl_seat_listener*)proto->listener)->capabilities = wl_seat_capabilities; + + wl_seat_add_listener(wl_registry_bind(ll->wayland.registry, name, &wl_seat_interface, ver), proto->listener, ll); + + return proto; +} + +static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + free(data->listener); + free(data); +} + +/* wl_output setup function */ +static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll, MwU32 version) { + (void)version; + ll->wayland.output = wl_registry_bind(ll->wayland.registry, name, &wl_output_interface, 1); + wl_output_add_listener(ll->wayland.output, &output_listener, ll); + + return NULL; +} + +static void wl_output_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* wl_compositor setup function */ +static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->compositor = wl_registry_bind(wayland->registry, name, &wl_compositor_interface, 1); + + return NULL; +} + +static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* wl_subcompositor setup function */ +static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { + wayland->toplevel->scompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + } else { + wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + } + + return NULL; +} + +static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)data; + if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { + wl_subcompositor_destroy(wayland->toplevel->scompositor); + } else { + wl_subcompositor_destroy(wayland->sublevel->subcompositor); + } +} + +/* xdg_wm_base setup function */ +static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + (void)version; + proto->listener = malloc(sizeof(struct xdg_wm_base_listener)); + + ((struct xdg_wm_base_listener*)proto->listener)->ping = xdg_wm_base_ping; + + proto->context = wl_registry_bind(wayland->registry, name, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(proto->context, proto->listener, wayland); + + return proto; +} + +static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + free(data->listener); + free(data); +} + +/* xdg_wm_base setup function */ +static wayland_protocol_t* wp_viewporter_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + (void)version; + proto->context = wl_registry_bind(wayland->registry, name, &wp_viewporter_interface, 1); + + return proto; +} + +static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* zxdg_decoration_manager_v1 setup function */ +static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + zxdg_decoration_manager_v1_context_t* ctx = malloc(sizeof(zxdg_decoration_manager_v1_context_t)); + (void)version; + proto->listener = NULL; + + ctx->manager = wl_registry_bind(wayland->registry, name, &zxdg_decoration_manager_v1_interface, 1); + ; + + proto->context = ctx; + + return proto; +} + +static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +/* wl_shm setup function */ +static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + (void)version; + wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->backbuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + + return NULL; +} + +static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + +static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + + (void)version; + + proto->context = wl_registry_bind(wayland->registry, name, &xdg_toplevel_icon_manager_v1_interface, 1); + proto->listener = NULL; + + return proto; +} + +static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + free(data->listener); + free(data); +} + +static wayland_protocol_t* zwlr_layer_shell_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + + proto->context = wl_registry_bind(wayland->registry, name, &zwlr_layer_shell_v1_interface, version); + proto->listener = NULL; + + return proto; +} + +static void zwlr_layer_shell_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + + free(data); +} + +/* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ +void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { +/* Convience macro for adding the interface functions to the setup map */ +#define WL_INTERFACE(interface) \ + do { \ + wayland_protocol_callback_table_t* cb = malloc(sizeof(wayland_protocol_callback_table_t)); \ + cb->setup = (wl_setup_func*)interface##_setup; \ + cb->destroy = (wl_destroy_func*)interface##_interface_destroy; \ + shput(wayland->wl_protocol_setup_map, interface##_interface.name, cb); \ + } while(0); + + wayland->registry_listener.global = new_protocol; + wayland->registry_listener.global_remove = protocol_removed; + + if(wayland->wl_protocol_map) { + shfree(wayland->wl_protocol_map); + } + if(wayland->wl_protocol_setup_map) { + shfree(wayland->wl_protocol_setup_map); + } + + wayland->wl_protocol_setup_map = NULL; + wayland->wl_protocol_map = NULL; + + sh_new_arena(wayland->wl_protocol_map); + sh_new_arena(wayland->wl_protocol_setup_map); + + WL_INTERFACE(wl_shm); + WL_INTERFACE(wl_compositor); + WL_INTERFACE(wl_seat); + WL_INTERFACE(wl_output); + WL_INTERFACE(wl_data_device_manager); + WL_INTERFACE(zwp_primary_selection_device_manager_v1); + WL_INTERFACE(zwp_pointer_constraints_v1); + WL_INTERFACE(zwp_relative_pointer_manager_v1); + WL_INTERFACE(xdg_wm_base); + WL_INTERFACE(zwlr_layer_shell_v1); /* Only used for layer surface, but we use it always if it's turned into a tool window */ + if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { + WL_INTERFACE(wp_viewporter); + WL_INTERFACE(zxdg_decoration_manager_v1); + WL_INTERFACE(xdg_toplevel_icon_manager_v1); + WL_INTERFACE(wl_subcompositor); + } else if(wayland->type == MwLL_WAYLAND_POPUP) { + } else if(wayland->type == MwLL_WAYLAND_LAYER_SURFACE) { + WL_INTERFACE(wp_viewporter); + WL_INTERFACE(wl_subcompositor); + } else { + WL_INTERFACE(wl_subcompositor); + } +#undef WL_INTERFACE +} diff --git a/widget/milsko/milskosrc/src/backend/wayland/region.c b/widget/milsko/milskosrc/src/backend/wayland/region.c new file mode 100644 index 0000000000..4b6a5ae215 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/wayland/region.c @@ -0,0 +1,45 @@ +#include + +void MwLLWaylandRegionInvalidate(MwLL handle) { + if(!handle->wayland.configured) { + return; + } + wl_region_subtract(handle->wayland.region, 0, 0, handle->wayland.ww, handle->wayland.wh); +} +void MwLLWaylandRegionSetup(MwLL handle) { + int width = (handle->wayland.clipping_rect.width == 0) ? handle->wayland.ww : handle->wayland.clipping_rect.width; + int height = (handle->wayland.clipping_rect.height == 0) ? handle->wayland.wh : handle->wayland.clipping_rect.height; + + if(!handle->wayland.has_decorations && handle->wayland.do_csd && handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + width += CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; + height += CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; + } + if(!handle->wayland.configured) { + return; + } + + if(!handle->wayland.parent) + wl_region_add(handle->wayland.o_region, 0, 0, width, height); + + if(handle->wayland.type == MwLL_WAYLAND_POPUP) { + wl_region_add(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y)); + } else { + wl_region_subtract(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y)); + wl_region_add(handle->wayland.region, handle->wayland.clipping_rect.x, handle->wayland.clipping_rect.y, handle->wayland.clipping_rect.width, handle->wayland.clipping_rect.height); + + if(!handle->wayland.parent) + wl_region_add(handle->wayland.region, 0, 0, width, height); + else { + if(!handle->wayland.parent->wayland.parent) { + wl_region_add(handle->wayland.region, 0, 0, width, height); + } + } + } + + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.o_region); + wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region); + } + wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region); + wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); +} diff --git a/widget/milsko/milskosrc/src/backend/wayland/wayland.c b/widget/milsko/milskosrc/src/backend/wayland/wayland.c new file mode 100644 index 0000000000..48d6c7601e --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/wayland/wayland.c @@ -0,0 +1,1928 @@ +#include + +#include +#include + +#include "../../../external/stb_ds.h" + +wayland_call_table_t wl_call_tbl; +#ifdef MW_VULKAN +MwBool MwWaylandVulkan = MwFALSE; +#endif + +MwBool MwWaylandCairoOnly = MwFALSE; + +static pthread_mutex_t destroyedWidgetsTableMutex; +/* + * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. + * + * To illustrate how bad this code is: if Israel and Palestine found out I was doing this then the Israel/Palestine conflict would be solved because both world leaders would come to the conclusion that this code is the worst thing ever. + */ +static MwLL* destroyedWidgetsTable; + +MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { + int i; + pthread_mutex_lock(&destroyedWidgetsTableMutex); + for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { + if(self == destroyedWidgetsTable[i]) { + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return MwTRUE; + } + } + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return MwFALSE; +} +void MwLLWaylandWidgetUndestroy(MwLL self) { + int i; + pthread_mutex_lock(&destroyedWidgetsTableMutex); + for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { + if(self == destroyedWidgetsTable[i]) { + arrdel(destroyedWidgetsTable, i); + break; + } + } + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + return; +} + +static int event_loop(MwLL handle); + +/* Recursively dispatch a resize event to a widget and its children */ +static void recursive_dispatch_resize(MwLL handle) { + MwWidget h = (MwWidget)handle->common.user; + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwDispatch(h->children[i], resize); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_resize(h->children[i]->lowlevel); + } + } + } +}; + +static void recursive_render(MwLL handle) { + int i; + WIDGET_CHECK(handle); + + for(i = 0; i < arrlen(((MwWidget)handle->common.user)->children); i++) recursive_render(((MwWidget)handle->common.user)->children[i]->lowlevel); + + MwLLForceRender(handle); +} + +/* Flush Wayland events */ +void MwLLWaylandFlush(MwLL handle) { + struct pollfd pfd; + int rc; + + pfd.fd = wl_display_get_fd(handle->wayland.display); + pfd.events = POLLIN; + while(MwTRUE) { + rc = wl_display_flush(handle->wayland.display); + if(errno != EAGAIN || rc != -1) { + break; + } + + if(poll(&pfd, 1, -1) == -1) { + break; + } + } +} + +/* Get the registered interface from r, or NULL if it doesn't currently have it. */ +#define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name) + +/* Standard Wayland event loop. */ +static int event_loop(MwLL handle) { + struct pollfd fd; + struct timespec timeout; + struct _MwLLWayland* wayland = &handle->wayland; + + timeout.tv_nsec = 1; + timeout.tv_sec = 0; + + if(wayland->display == NULL) { + return 0; + } + fd.fd = wl_display_get_fd(wayland->display); + fd.events = POLLIN; + + /* If an error other than EAGAIN happens, we have likely been disconnected from the Wayland session */ + while(wl_display_flush(wayland->display) == -1) { + if(errno != EAGAIN) { + return MwFALSE; + } + + while(poll(&fd, 1, -1) == -1) { + if(errno != EINTR && errno != EAGAIN) { + wl_display_cancel_read(wayland->display); + + MwLLDispatch(handle, close, NULL); + return 0; + } + } + } + + wl_display_prepare_read(handle->wayland.display); + /* Condition where no events are being sent. */ + if(!poll(&fd, 1, timeout.tv_nsec)) { + wl_display_cancel_read(wayland->display); + + if(wayland->configured) { + MwLLWaylandBufferUpdate(handle, &wayland->framebuffer); + if(wayland->type == MwLL_WAYLAND_TOPLEVEL) + MwLLWaylandBufferUpdate(handle, &wayland->backbuffer); + } + return 0; + } + wl_display_read_events(wayland->display); + if(wl_display_dispatch_pending(wayland->display) < 0) { + wl_display_cancel_read(wayland->display); + } + return 1; +} + +/* make the fuck sure that we're configurd */ +void MwLLWaylandHangUntilConfigured(MwLL handle) { + while(!handle->wayland.configured) { + if(wl_display_roundtrip(handle->wayland.display) == -1) { + printf("roundtrip failed: %d\n", wl_display_get_error(handle->wayland.display)); + raise(SIGTRAP); + return; + } + event_loop(handle); + } +} + +/* `xdg_toplevel.configure` callback */ +static void xdg_toplevel_configure(void* data, + struct xdg_toplevel* xdg_toplevel, + MwI32 width, MwI32 height, + struct wl_array* states) { + MwLL self = data; + (void)states; + (void)xdg_toplevel; + + /* Yes, somehow this can get called before */ + if(!self->wayland.configured) { + return; + } + + if(width == 0 || height == 0) { + width = self->wayland.ww; + height = self->wayland.wh; + /* if it's still 0 then bail */ + if(width == 0 || height == 0) { + return; + } + } + + if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + if(width < 50) width = 50; + if(height < 50) height = 50; + } + + MwLLWaylandRegionInvalidate(self); + self->wayland.ww = width; + self->wayland.wh = height; + // if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + // if(!self->wayland.has_decorations && self->wayland.toplevel->maxim_state) { + // self->wayland.ww -= CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; + // self->wayland.wh -= CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; + // } + // } + + if(self->wayland.resizing == 0) { + xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); + + MwLLWaylandBackbufferDestroy(&self->wayland); + MwLLWaylandBackbufferSetup(&self->wayland); + MwLLWaylandFramebufferDestroy(&self->wayland); + MwLLWaylandFramebufferSetup(&self->wayland); + + MwLLWaylandRegionSetup(self); + MwLLDispatch(self, resize, NULL); + + recursive_dispatch_resize(self); + + if(self->wayland.pointer_constrained) { + zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); + wl_surface_commit(self->wayland.framebuffer.surface); + } + self->wayland.resizing = 1; + } +}; + +/* `xdg_surface.close` callback */ +static void xdg_toplevel_close( + void* data, struct xdg_toplevel* xdg_toplevel) { + MwLL self = data; + (void)xdg_toplevel; + WAYLAND_EVENT_OP_START(self); + MwLLDispatch(self, close, NULL); + WAYLAND_EVENT_OP_END(self); +}; + +/* `xdg_surface.configure` callback */ +static void xdg_surface_configure( + void* data, struct xdg_surface* xdg_surface, MwU32 serial) { + MwLL self = data; + + xdg_surface_ack_configure(xdg_surface, serial); + + MwLLDispatch(self, draw, NULL); + + if(self->wayland.configured) { + MwLLWaylandBufferUpdate(self, &self->wayland.framebuffer); + MwLLWaylandBufferUpdate(self, &self->wayland.backbuffer); + } + + self->wayland.configured = MwTRUE; +} + +void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { + if(self->wayland.configured) { + memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); + if(buffer->surface) { + // Yes this is needed every time, it's how we fix weston. + if(self->wayland.configured) + wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); + wl_surface_commit(buffer->surface); + } + } +} + +/* Toplevel setup function */ +static void setup_toplevel(MwLL r, int x, int y) { + r->wayland.type = MwLL_WAYLAND_TOPLEVEL; + r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); + r->wayland.x = x; + r->wayland.y = y; + + MwLLWaylandSetupCallbacks(&r->wayland); + + /* Connect to the Wayland compositor */ + if(!r->wayland.display) { + r->wayland.display = wl_display_connect(NULL); + if(r->wayland.display == NULL) { + printf("wayland: failed to create display\n"); + raise(SIGTRAP); + return; + } + } + + /* Do a roundtrip to ensure all interfaces are setup. */ + r->wayland.registry = wl_display_get_registry(r->wayland.display); + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + /* check now if we have decorations so that everything else can act accordingly */ + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + r->wayland.has_decorations = MwTRUE; + } else { + r->wayland.do_csd = MwTRUE; + } + + r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); + wl_subsurface_set_desync(r->wayland.toplevel->ssurface); + + r->wayland.toplevel->xdg_surface = + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface); + r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); + + /* setup mandatory listeners */ + r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; + + r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure; + r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close; + + xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r); + xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener, + r); + + xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko App"); + xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); + + /* Perform the initial commit and wait for the first configure event */ + wl_surface_commit(r->wayland.backbuffer.surface); + wl_surface_commit(r->wayland.framebuffer.surface); + + while(!r->wayland.configured) { + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + } + + /* setup decorations if we can */ + if(r->wayland.has_decorations) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; + + dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + dec->manager, r->wayland.toplevel->xdg_top_level); + + zxdg_toplevel_decoration_v1_set_mode( + dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } else { + wl_subsurface_set_position(r->wayland.toplevel->ssurface, r->wayland.do_csd ? CSD_BORDER_FRAME_LEFT : 0, r->wayland.do_csd ? CSD_BORDER_FRAME_TOP : 0); + } + + MwLLWaylandFramebufferSetup(&r->wayland); + MwLLWaylandBackbufferSetup(&r->wayland); +} + +/* Toplevel destroy function */ +static void destroy_toplevel(MwLL r) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; + zxdg_toplevel_decoration_v1_destroy(dec->decoration); + zxdg_decoration_manager_v1_destroy(dec->manager); + } + + MwLLWaylandFramebufferDestroy(&r->wayland); + MwLLWaylandBackbufferDestroy(&r->wayland); + + xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); + + xdg_surface_destroy(r->wayland.toplevel->xdg_surface); + + wl_compositor_destroy(r->wayland.compositor); + + xkb_keymap_unref(r->wayland.xkb_keymap); + + xkb_state_unref(r->wayland.xkb_state); + + xkb_context_unref(r->wayland.xkb_context); + + wl_pointer_destroy(r->wayland.pointer); + wl_keyboard_destroy(r->wayland.keyboard); + + if(r->common.user) { + MwWidget w = r->common.user; + int i; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + wl_subsurface_destroy(child->wayland.sublevel->subsurface); + child->wayland.sublevel->subsurface = NULL; + } + } + } + + wl_surface_destroy(r->wayland.framebuffer.surface); + + free(r->wayland.toplevel); + + r->wayland.configured = MwFALSE; +} + +/* Sublevel setup function */ +static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { + struct wl_compositor* compositor = parent->wayland.compositor; + struct wl_surface* parent_surface = parent->wayland.framebuffer.surface; + + r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); + r->wayland.sublevel->parent = parent; + + r->wayland.type = MwLL_WAYLAND_SUBLEVEL; + + r->wayland.display = parent->wayland.display; + + MwLLWaylandSetupCallbacks(&r->wayland); + + r->wayland.registry = wl_display_get_registry(parent->wayland.display); + r->wayland.display = parent->wayland.display; + + if(parent->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + r->wayland.sublevel->xdg_surface = parent->wayland.toplevel->xdg_surface; + } else { + r->wayland.sublevel->xdg_surface = parent->wayland.sublevel->xdg_surface; + } + + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed: %d\n", wl_display_get_error(r->wayland.display)); + raise(SIGTRAP); + return; + } + + r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); + + r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface); + + wl_subsurface_set_desync(r->wayland.sublevel->subsurface); + wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); + + if(parent) { + wl_subsurface_place_above(r->wayland.sublevel->subsurface, parent->wayland.framebuffer.surface); + } + + r->wayland.xkb_keymap = parent->wayland.xkb_keymap; + r->wayland.xkb_state = parent->wayland.xkb_state; + + r->wayland.configured = MwTRUE; + + MwLLWaylandFramebufferSetup(&r->wayland); + MwLLWaylandBackbufferSetup(&r->wayland); +} + +/* Sublevel setup function */ +static void destroy_sublevel(MwLL r) { + MwLLWaylandBackbufferDestroy(&r->wayland); + MwLLWaylandFramebufferDestroy(&r->wayland); + + wl_subsurface_destroy(r->wayland.sublevel->subsurface); + + free(r->wayland.sublevel); + + r->wayland.configured = MwFALSE; +} + +static void popup_configure(void* data, + struct xdg_popup* xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height) { + MwLL self = data; + (void)xdg_popup; + + if(width < 50) width = 50; + if(height < 50) height = 50; + self->wayland.x = x; + self->wayland.y = y; + self->wayland.ww = width; + self->wayland.wh = height; +}; + +static void popup_done(void* data, + struct xdg_popup* xdg_popup) { + (void)data; + (void)xdg_popup; +}; + +static void popup_repositioned(void* data, + struct xdg_popup* xdg_popup, + uint32_t token) { + MwLL self = data; + (void)xdg_popup; + + xdg_surface_ack_configure(self->wayland.popup->xdg_surface, token); +}; + +struct xdg_popup_listener popup_listener = { + .configure = popup_configure, + .popup_done = popup_done, + .repositioned = popup_repositioned, + +}; + +/* Popup setup function */ +static void setup_popup(MwLL r, int x, int y, MwLL parent) { + MwLL topmost_parent = r->wayland.parent; + r->wayland.type = MwLL_WAYLAND_POPUP; + r->wayland.x = x; + r->wayland.y = y; + r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); + + if(parent) { + MwWidget p = parent->common.user; + while(topmost_parent->wayland.parent) { + topmost_parent = topmost_parent->wayland.parent; + } + + if(!topmost_parent->wayland.has_decorations && topmost_parent->wayland.do_csd) { + if(p->is_menu) { + r->wayland.x += round((float)CSD_BORDER_FRAME_LEFT / 2.); + r->wayland.y += ceil((float)CSD_BORDER_FRAME_TOP / 2.); + } + } + } + + MwLLWaylandSetupCallbacks(&r->wayland); + + /* Connect to the Wayland compositor */ + r->wayland.display = parent->wayland.display; + + /* Do a roundtrip to ensure all interfaces are setup. */ + r->wayland.registry = wl_display_get_registry(r->wayland.display); + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed: %d\n", wl_display_get_error(r->wayland.display)); + raise(SIGTRAP); + return; + } + + /* check now if we have decorations so that everything else can act accordingly */ + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + r->wayland.has_decorations = MwTRUE; + } else { + r->wayland.do_csd = MwTRUE; + } + + r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; + + r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base); + + xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); + xdg_positioner_set_anchor_rect( + r->wayland.popup->xdg_positioner, + topmost_parent->wayland.x, topmost_parent->wayland.y, r->wayland.ww, r->wayland.wh); + xdg_positioner_set_offset( + r->wayland.popup->xdg_positioner, + r->wayland.x, r->wayland.y); + + xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_NONE); + xdg_positioner_set_gravity(r->wayland.popup->xdg_positioner, XDG_POSITIONER_GRAVITY_NONE); + + r->wayland.xkb_keymap = topmost_parent->wayland.xkb_keymap; + r->wayland.xkb_state = topmost_parent->wayland.xkb_state; + + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + + r->wayland.popup->xdg_surface = + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); + + if(topmost_parent->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + r->wayland.popup->xdg_popup = xdg_surface_get_popup( + r->wayland.popup->xdg_surface, + topmost_parent->wayland.toplevel->xdg_surface, + r->wayland.popup->xdg_positioner); + } else if(topmost_parent->wayland.type == MwLL_WAYLAND_LAYER_SURFACE) { + r->wayland.popup->xdg_popup = xdg_surface_get_popup( + r->wayland.popup->xdg_surface, NULL, + r->wayland.popup->xdg_positioner); + zwlr_layer_surface_v1_get_popup(topmost_parent->wayland.layer_surface->surface, r->wayland.popup->xdg_popup); + } + + xdg_popup_add_listener(r->wayland.popup->xdg_popup, &popup_listener, r); + + r->wayland.popup->xdg_surface_listener.configure = xdg_surface_configure; + xdg_surface_add_listener(r->wayland.popup->xdg_surface, &r->wayland.popup->xdg_surface_listener, r); + + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + MwLLWaylandFramebufferSetup(&r->wayland); +} + +/* Popup destroy function */ +static void destroy_popup(MwLL r) { + + MwLLWaylandBackbufferDestroy(&r->wayland); + MwLLWaylandFramebufferDestroy(&r->wayland); + + xdg_surface_destroy(r->wayland.popup->xdg_surface); + + xdg_popup_destroy(r->wayland.popup->xdg_popup); + + xdg_positioner_destroy(r->wayland.popup->xdg_positioner); + + wl_surface_destroy(r->wayland.framebuffer.surface); + + wl_registry_destroy(r->wayland.registry); + + free(r->wayland.popup); + + r->wayland.configured = MwFALSE; +} + +static void layer_shell_configure(void* data, + struct zwlr_layer_surface_v1* surface, + uint32_t serial, + uint32_t width, + uint32_t height) { + MwLL self = data; + zwlr_layer_surface_v1_ack_configure(surface, serial); + + if(width < 50) width = 50; + if(height < 50) height = 50; + + self->wayland.ww = width; + self->wayland.wh = height; + + self->wayland.configured = MwTRUE; + + MwLLWaylandFramebufferSetup(&self->wayland); + MwLLWaylandRegionSetup(self); + MwLLDispatch(self, resize, NULL); + + wl_surface_commit(self->wayland.framebuffer.surface); +}; + +static void layer_shell_done(void* data, + struct zwlr_layer_surface_v1* zwlr_layer_surface_v1) { + (void)data; + (void)zwlr_layer_surface_v1; + + printf("closed\n"); +}; + +static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { + .configure = layer_shell_configure, + .closed = layer_shell_done, +}; + +/* Layer surface setup function */ +static void setup_layer_surface(MwLL r, int x, int y, int width, int height) { + wayland_protocol_t* layer_shell_protocol; + struct zwlr_layer_shell_v1* layer_shell; + r->wayland.type = MwLL_WAYLAND_LAYER_SURFACE; + r->wayland.layer_surface = malloc(sizeof(struct _MwLLWaylandLayerSurface)); + r->wayland.x = x; + r->wayland.y = y; + + MwLLWaylandSetupCallbacks(&r->wayland); + + /* Connect to the Wayland compositor */ + if(!r->wayland.display) { + r->wayland.display = wl_display_connect(NULL); + if(r->wayland.display == NULL) { + printf("wayland: failed to create display\n"); + raise(SIGTRAP); + return; + } + } + + /* Do a roundtrip to ensure all interfaces are setup. */ + r->wayland.registry = wl_display_get_registry(r->wayland.display); + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + layer_shell_protocol = WAYLAND_GET_INTERFACE(r->wayland, zwlr_layer_shell_v1); + assert(layer_shell_protocol); + + layer_shell = layer_shell_protocol->context; + + r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + + r->wayland.layer_surface->surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell, r->wayland.framebuffer.surface, NULL, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "milsko-surfaces"); + + zwlr_layer_surface_v1_set_size(r->wayland.layer_surface->surface, width, height); + zwlr_layer_surface_v1_set_margin(r->wayland.layer_surface->surface, + y, 0, 0, x); + zwlr_layer_surface_v1_set_anchor(r->wayland.layer_surface->surface, ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); + zwlr_layer_surface_v1_set_exclusive_zone(r->wayland.layer_surface->surface, 1); + zwlr_layer_surface_v1_set_keyboard_interactivity( + r->wayland.layer_surface->surface, ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND); + + zwlr_layer_surface_v1_add_listener(r->wayland.layer_surface->surface, &layer_surface_listener, r); + + /* Perform the initial commit and wait for the first configure event */ + wl_surface_commit(r->wayland.framebuffer.surface); + + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } +} + +/* Toplevel destroy function */ +static void destroy_layer_surface(MwLL r) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; + zxdg_decoration_manager_v1_destroy(dec->manager); + } + + wl_surface_destroy(r->wayland.framebuffer.surface); + + wl_compositor_destroy(r->wayland.compositor); + + xkb_keymap_unref(r->wayland.xkb_keymap); + + xkb_state_unref(r->wayland.xkb_state); + + xkb_context_unref(r->wayland.xkb_context); + + wl_registry_destroy(r->wayland.registry); + + r->wayland.configured = MwFALSE; +} + +static void destroy_widget(MwLL handle) { + int i; + + MwLLShow(handle, MwFALSE); + + switch(handle->wayland.type) { + case MwLL_WAYLAND_TOPLEVEL: + destroy_toplevel(handle); + break; + case MwLL_WAYLAND_SUBLEVEL: + destroy_sublevel(handle); + break; + case MwLL_WAYLAND_POPUP: + destroy_popup(handle); + break; + case MwLL_WAYLAND_LAYER_SURFACE: + destroy_layer_surface(handle); + break; + default: + printf("Handle with unknown type(%d) tried to be destroyed (%p)\n", handle->wayland.type, handle); + break; + } + + if(wl_display_roundtrip(handle->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + for(i = 0; i < shlen(handle->wayland.wl_protocol_setup_map); i++) { + void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key); + + if(ctx != NULL) { + handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); + } + shdel(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].value); + free(handle->wayland.wl_protocol_setup_map[i].value); + } + + shfree(handle->wayland.wl_protocol_map); + shfree(handle->wayland.wl_protocol_setup_map); + + MwLLWaylandFlush(handle); +} + +static void clip(MwLL handle) { + int i; + int x, y, cx, cy, mx, my; + MwLL toplevel = handle->wayland.parent; + MwLL* ws = NULL; + + arrput(ws, handle); + while(toplevel) { + arrput(ws, toplevel); + if(!toplevel->wayland.parent || toplevel->wayland.is_toplevel) { + break; + } + toplevel = toplevel->wayland.parent; + } + if(toplevel) { + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + /* i seriously have no fucking idea how this works, do not ask me how this really works (nishi) */ + x = 0; + y = 0; + cx = 0; + cy = 0; + mx = toplevel->wayland.ww; + my = toplevel->wayland.wh; + // ws is traversed result + // ws[ws.length - 1] is ignored bc it's toplevel + for(i = arrlen(ws) - 2; i >= 0; i--) { + int j; + int l = 0; + + x += ws[i]->wayland.x; + y += ws[i]->wayland.y; + + for(j = i - 1; j >= 0; j--) { + if(ws[j]->wayland.x > cx) l = 1; + if(ws[j]->wayland.y > cy) l = 1; + if(l) break; + } + + if(!l) { + cx = MAX(cx, ws[i]->wayland.x); + cy = MAX(cy, ws[i]->wayland.y); + } + + mx = MIN(mx, x + ws[i]->wayland.ww); + my = MIN(my, y + ws[i]->wayland.wh); + } + + if(mx < cx) mx = cx; + if(my < cy) my = cy; + + arrfree(ws); + + if(mx < cx) mx = cx; + if(my < cy) my = cy; + + handle->wayland.clipping_rect.x = cx - x; + handle->wayland.clipping_rect.y = cy - y; + handle->wayland.clipping_rect.width = mx - cx; + handle->wayland.clipping_rect.height = my - cy; + MwLLWaylandRegionSetup(handle); + + cairo_reset_clip(handle->wayland.cairo.front_cairo); + if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL && !handle->wayland.is_toplevel) { + cairo_rectangle(handle->wayland.cairo.front_cairo, cx - x, cy - y, mx - cx, my - cy); + cairo_clip(handle->wayland.cairo.front_cairo); + } + + if(handle->wayland.is_clipping) { + cairo_rectangle(handle->wayland.cairo.front_cairo, handle->wayland.clip.x, handle->wayland.clip.y, handle->wayland.clip.width, handle->wayland.clip.height); + cairo_clip(handle->wayland.cairo.front_cairo); + } + } +} + +static void wl_logger(const char* fmt, va_list args) { + vprintf(fmt, args); + raise(SIGTRAP); +} + +static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int height, enum _MwLLWaylandType ty) { + /* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this. + */ + r->common.coordinate_type = MwCOORDINATE_LOCAL; + + r->common.type = MwLLBackendWayland; + + if(width < 2) width = 2; + if(height < 2) height = 2; + + if(x == MwDEFAULT) { + x = 0; + } + if(y == MwDEFAULT) { + y = 0; + } + + r->wayland.ww = width; + r->wayland.wh = height; + r->wayland.x = x; + r->wayland.y = y; + r->wayland.parent = parent; + if(MwLLWaylandWidgetIsDestroyed(parent)) { + r->wayland.valid = MwFALSE; + return; + } else { + r->wayland.valid = MwTRUE; + } + + if(ty == MwLL_WAYLAND_UNKNOWN) { + if(parent == NULL) { + setup_toplevel(r, x, y); + } else { + setup_sublevel(parent, r, x, y); + } + } else { + switch(ty) { + case MwLL_WAYLAND_UNKNOWN: + break; + case MwLL_WAYLAND_TOPLEVEL: + setup_toplevel(r, x, y); + break; + case MwLL_WAYLAND_SUBLEVEL: + setup_sublevel(parent, r, x, y); + break; + case MwLL_WAYLAND_POPUP: + if(parent) { + setup_popup(r, x, y, parent); + } else { + /* + * We can't actually have a popup without a parent but this needs to be valid behavior. + * If we're down this code path, though, it means we can't create a layer surface. + * So we just fake it with a borderless window. + */ + setup_toplevel(r, x, y); + MwLLMakeBorderless(r, MwTRUE); + } + break; + case MwLL_WAYLAND_LAYER_SURFACE: + setup_layer_surface(r, x, y, width, height); + break; + } + } + + WIDGET_CHECK(r); + + r->wayland.region = wl_compositor_create_region(r->wayland.compositor); + r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor); + MwLLWaylandRegionSetup(r); + + MwLLForceRender(r); + if(parent != NULL) { + MwLLForceRender(parent); + } + + /* If the compositor never sets the keyboard repeat info, we'll copy KDE's default of... */ + r->wayland.keyboard_delay = 600; /* starting at 600ms... */ + r->wayland.keyboard_rate = 25; /* and going every 25ms... */ + + if(!r->wayland.has_decorations && r->wayland.do_csd) { + MwLLBeginDraw(r); + MwLLEndDraw(r); + } +} + +#ifdef USE_DBUS +static void dark_theme_listener(MwLL handle, MwU32 new_value) { + handle->wayland.dark_theme = (new_value == 1) ? 1 : 0; + + MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); +} + +static void detect_dark_theme(MwLL handle) { + MwU32 value = 0; + + MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + handle->wayland.dark_theme = (value == 1) ? 1 : 0; + + MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); + + MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); +} +#endif + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); + MwLLCreateCommon(r); + + if(MwLLWaylandWidgetIsDestroyed(r)) { + MwLLWaylandWidgetUndestroy(r); + } + + r->wayland.is_toplevel = parent == NULL; + r->wayland.is_clipping = 0; + + widget_setup(r, parent, x, y, width, height, MwLL_WAYLAND_UNKNOWN); + +#ifdef USE_DBUS + if(!parent && wl_call_tbl.has_dbus) { + wl_call_tbl.has_dbus = MwLLDBusNewContext(&wl_call_tbl.dbus, &r->wayland.dbus); + r->wayland.dark_theme_detection = MwTRUE; + r->wayland.dark_theme = -1; + } +#endif + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + int i; + struct timeval tv; + int select_ret; + + event_loop(handle); + // wl_display_cancel_read(handle->wayland.display); + + MwLLWaylandFlush(handle); + + handle->wayland.cancelEvent = MwTRUE; + + MwLLDestroyCommon(handle); + + tv.tv_sec = 0; + tv.tv_usec = 1000; + do { + select_ret = select(1, NULL, NULL, NULL, &tv); + } while((select_ret == -1) && (errno == EINTR)); + + pthread_mutex_destroy(&handle->wayland.eventsMutex); + +#ifdef USE_DBUS + if(!wl_call_tbl.has_dbus) { + MwLLDBusFreeContext(&wl_call_tbl.dbus, &handle->wayland.dbus); + } +#endif + + if(handle->wayland.valid) { + MwLLWaylandBufferDestroy(&handle->wayland.cursor); + wl_region_destroy(handle->wayland.region); + + if(handle->wayland.supports_zwp) { + zwp_primary_selection_source_v1_destroy(handle->wayland.clipboard_source.zwp); + } else { + wl_data_source_destroy(handle->wayland.clipboard_source.wl); + } + if(handle->wayland.icon != NULL) { + MwLLWaylandBufferDestroy(handle->wayland.icon); + wl_surface_destroy(handle->wayland.icon->surface); + } + + destroy_widget(handle); + } else { + printf("widget invalid\n"); + } + + pthread_mutex_lock(&destroyedWidgetsTableMutex); + arrput(destroyedWidgetsTable, handle); + pthread_mutex_unlock(&destroyedWidgetsTableMutex); + + free(handle); + + // if(topmost_parent->wayland.currentlyHeldWidget == handle) { + // topmost_parent->wayland.currentlyHeldWidget = NULL; + // } +} + +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + if(!handle->wayland.valid) { + *x = 0; + *y = 0; + *w = 1; + *h = 1; + return; + } + *x = handle->wayland.x; + *y = handle->wayland.y; + *w = handle->wayland.ww; + *h = handle->wayland.wh; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + WIDGET_CHECK(handle); + MwLLWaylandRegionInvalidate(handle); + handle->wayland.x = x; + handle->wayland.y = y; + + switch(handle->wayland.type) { + case MwLL_WAYLAND_TOPLEVEL: + /* toplevels cannot be moved */ + break; + case MwLL_WAYLAND_SUBLEVEL: + wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); + break; + case MwLL_WAYLAND_POPUP: + xdg_positioner_set_anchor_rect(handle->wayland.popup->xdg_positioner, handle->wayland.parent->wayland.x, handle->wayland.parent->wayland.y, handle->wayland.ww, handle->wayland.wh); + xdg_positioner_set_offset(handle->wayland.popup->xdg_positioner, x, y); + xdg_popup_reposition(handle->wayland.popup->xdg_popup, handle->wayland.popup->xdg_positioner, 0); + xdg_surface_set_window_geometry(handle->wayland.popup->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + break; + case MwLL_WAYLAND_LAYER_SURFACE: + zwlr_layer_surface_v1_set_margin(handle->wayland.layer_surface->surface, + y, 0, 0, x); + break; + case MwLL_WAYLAND_UNKNOWN: + break; + } + MwLLWaylandRegionSetup(handle); + + if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) recursive_render(handle); + + MwLLDispatch(handle, draw, NULL); +} + +static void actually_set_wh(MwLL handle) { + MwLLWaylandRegionInvalidate(handle); + + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL && handle->wayland.configured) { + xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + } + + if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL && handle->wayland.configured && !handle->wayland.dispatching_resize) { + handle->wayland.dispatching_resize = MwTRUE; + MwLLDispatch(handle, resize, NULL); + handle->wayland.dispatching_resize = MwFALSE; + } + + if(handle->wayland.type == MwLL_WAYLAND_POPUP) { + destroy_widget(handle); + MwLLWaylandFlush(handle); + setup_popup(handle, handle->wayland.x, handle->wayland.y, handle->wayland.parent); + } + + MwLLWaylandRegionSetup(handle); + if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL) recursive_render(handle); + + MwLLWaylandFramebufferDestroy(&handle->wayland); + MwLLWaylandFramebufferSetup(&handle->wayland); + MwLLWaylandBackbufferDestroy(&handle->wayland); + MwLLWaylandBackbufferSetup(&handle->wayland); + MwLLDispatch(handle, draw, NULL); +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + WIDGET_CHECK(handle); + + if(handle->wayland.ww == w && handle->wayland.wh == h) { + return; + } + + /* Prevent an integer underflow when the w/h is too low */ + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + if(w < 50) w = 50; + if(h < 50) h = 50; + } + + handle->wayland.ww = w; + handle->wayland.wh = h; + + if(!handle->wayland.setting_wh) { + handle->wayland.setting_wh = 1; + } + + handle->wayland.events_pending = 1; +} + +typedef struct { + double r, g, b; +} float_color; +static float_color lerp_color(float_color a, float_color b, float t) { + return (float_color){ + a.r + (b.r - a.r) * t, + a.g + (b.g - a.g) * t, + a.b + (b.b - a.b) * t}; +} +const float_color one = {.2627451, .37254902, .49411765}; +const float_color two = {.05490196, .17254902, .30588235}; + +static void MwLLBeginDrawImpl(MwLL handle) { + WIDGET_CHECK(handle); + cairo_save(handle->wayland.cairo.front_cairo); + cairo_set_source_rgba(handle->wayland.cairo.front_cairo, 0, 0, 0, 0); + cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_SOURCE); + cairo_rectangle(handle->wayland.cairo.front_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh); + cairo_fill(handle->wayland.cairo.front_cairo); + cairo_restore(handle->wayland.cairo.front_cairo); + + if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.front_cairo; + return; + } + + if(!handle->wayland.has_decorations && handle->wayland.do_csd) { + int y; + MwU32 w = handle->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; + MwU32 h = handle->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; + MwRect r; + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.back_cairo; + +#define DO_BOX(x, y, col, w, h) \ + cairo_rectangle(handle->wayland.cairo.back_cairo, x, y, w, h); \ + cairo_set_source_rgb(handle->wayland.cairo.back_cairo, col, col, col); \ + cairo_fill(handle->wayland.cairo.back_cairo); + +#define DO_LINE(off, col) \ + cairo_move_to(handle->wayland.cairo.back_cairo, off, off); \ + cairo_line_to(handle->wayland.cairo.back_cairo, off, h - (off)); \ + cairo_set_source_rgb(handle->wayland.cairo.back_cairo, col, col, col); \ + cairo_stroke(handle->wayland.cairo.back_cairo); \ + cairo_move_to(handle->wayland.cairo.back_cairo, off, off); \ + cairo_line_to(handle->wayland.cairo.back_cairo, w - (off), off); \ + cairo_set_source_rgb(handle->wayland.cairo.back_cairo, col, col, col); \ + cairo_stroke(handle->wayland.cairo.back_cairo); + + /* border */ + cairo_set_antialias(handle->wayland.cairo.back_cairo, CAIRO_ANTIALIAS_NONE); + + DO_BOX(0, 0, 0.14901961, w, h); + DO_BOX(1, 1, 0.55686275, w - 2, h - 2); + DO_BOX(2, 2, 0.82352941, w - 4, h - 4); + DO_BOX(3, 3, 0.93333333, w - 6, h - 6); + DO_BOX(4, 4, 1, w - 8, h - 8); + DO_BOX(4, 4, 0.14901961, w - CSD_BORDER_FRAME_LEFT - 4, h - CSD_BORDER_FRAME_BOTTOM - 4); + cairo_set_line_width(handle->wayland.cairo.back_cairo, 1.0); + + DO_LINE(1, 1) + DO_LINE(2, 0.93333333) + DO_LINE(3, 0.82352941) + DO_LINE(4, 0.55686275) + DO_LINE(5, 0.14901961) + + cairo_set_line_width(handle->wayland.cairo.back_cairo, 2.0); + for(y = 1; y < CSD_BORDER_FRAME_TOP - CSD_BORDER_FRAME_LEFT; y++) { + float_color c = lerp_color(one, two, (double)y / (double)(CSD_BORDER_FRAME_TOP - CSD_BORDER_FRAME_LEFT)); + + cairo_set_source_rgb(handle->wayland.cairo.back_cairo, c.r, c.g, c.b); + + cairo_move_to(handle->wayland.cairo.back_cairo, CSD_BORDER_FRAME_LEFT, y + CSD_BORDER_FRAME_LEFT); + cairo_line_to(handle->wayland.cairo.back_cairo, w - CSD_BORDER_FRAME_RIGHT, y + CSD_BORDER_FRAME_LEFT); + cairo_stroke(handle->wayland.cairo.back_cairo); + } + + /* icon */ + r.x = CSD_BORDER_FRAME_LEFT + 1; + r.y = CSD_BORDER_FRAME_RIGHT + 1; + r.width = 15; + r.height = 15; + DO_BOX(5, 5, 1, 18, 18); + DO_BOX(6, 6, 0.35294118, 17, 17); + DO_BOX(6, 6, 0.82352941, 16, 16); + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.back_cairo; + if(handle->wayland.icon_pixmap) { + MwLLDrawPixmap(handle, &r, handle->wayland.icon_pixmap); + } + + /* close */ + DO_BOX(w - 19 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 1, 1, 18, 18); + DO_BOX(w - 18 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 2, 0.35294118, 17, 17); + DO_BOX(w - 18 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 2, 0.82352941, 16, 16); + DO_BOX(w - 18 - CSD_BORDER_FRAME_LEFT + 5, CSD_BORDER_FRAME_BOTTOM + 7, 0, 6, 6); + DO_BOX(w - 18 - CSD_BORDER_FRAME_LEFT + 6, CSD_BORDER_FRAME_BOTTOM + 8, 0.82352941, 4, 4); + + /* maxim */ + DO_BOX(w - 37 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 1, 1, 18, 18); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 2, 0.35294118, 17, 17); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 2, 0.82352941, 16, 16); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT + 5, CSD_BORDER_FRAME_BOTTOM + 7, 0, 6, 6); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_BOTTOM + 9, 0.82352941, 16, 2); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT + 7, CSD_BORDER_FRAME_BOTTOM + 4, 0.82352941, 2, 14); + DO_BOX(w - 36 - CSD_BORDER_FRAME_LEFT + 6, CSD_BORDER_FRAME_BOTTOM + 8, 0.82352941, 4, 4); + + /* title */ + if(strlen(handle->wayland.title) != 0) { + int y, x; + int i = 0, sx = 0, sy = 0; + int tw, th; + unsigned char* px; + MwLLPixmap p; + tw = strlen(handle->wayland.title) * 7; + th = 14; + px = malloc(tw * th * 4); + assert(px); + + memset(px, 0, tw * th * 4); + + while(handle->wayland.title[i]) { + int out; + i += MwUTF8ToUTF32(handle->wayland.title + i, &out); + + if(out > 0xff) { + out = 0; + } + + for(y = 0; y < 14; y++) { + for(x = 0; x < 7; x++) { + unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; + int col = MwFontData[out].data[y] & (1 << ((7 - 1) - x)) ? 255 : 0; + ppx[0] = col; + ppx[1] = col; + ppx[2] = col; + ppx[3] = col; + } + } + sx += 7; + } + + p = MwLLCreatePixmap(handle, px, tw, th); + r.x = 24; + r.y = 5 + 2; + r.width = tw; + r.height = th; + + MwLLDrawPixmap(handle, &r, p); + MwLLDestroyPixmap(p); + free(px); + } + MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); + } + handle->wayland.cairo.selected_cairo = handle->wayland.cairo.front_cairo; +} + +static void MwLLEndDrawImpl(MwLL handle) { + if(handle->wayland.configured) { + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); + } + MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); + } +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + WIDGET_CHECK(handle); + + clip(handle); + + MwLLCairoPolygon(handle->wayland.cairo, points, points_count, color); + + handle->wayland.events_pending = 1; +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + int i; + WIDGET_CHECK(handle); + + clip(handle); + + MwLLCairoLine(handle->wayland.cairo, points, color); + + handle->wayland.events_pending = 1; +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + (void)handle; + + c->common.red = r; + c->common.blue = b; + c->common.green = g; + + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + c->common.red = r; + c->common.blue = b; + c->common.green = g; +} + +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} + +static int MwLLPendingImpl(MwLL handle) { + struct timespec timeout = { + .tv_nsec = 1, + .tv_sec = 0, + }; + struct pollfd fd = { + .fd = wl_display_get_fd(handle->wayland.display), + .events = POLLOUT, + }; + int pending = 0; + + if(MwLLWaylandWidgetIsDestroyed(handle) || !handle->wayland.valid) { + return 0; + } + + handle->wayland.resizing = 0; + + if(handle->wayland.setting_wh) { + actually_set_wh(handle); + handle->wayland.setting_wh = 0; + } + + handle->wayland.end_time = MwTimeGetTick(); + + if(handle->wayland.holding_key) { + float elapsed = ((float)(handle->wayland.end_time - (float)handle->wayland.start_time)); + if(elapsed >= handle->wayland.next_elapsed) { + MwLL topmost_parent = handle; + while(topmost_parent->wayland.parent) { + MwLLDispatch(topmost_parent, key, &handle->wayland.last_pressed_key); + topmost_parent = topmost_parent->wayland.parent; + } + handle->wayland.next_elapsed = elapsed + handle->wayland.keyboard_rate; + } + } + +#ifdef USE_DBUS + if(wl_call_tbl.has_dbus) { + if(handle->wayland.dark_theme_detection) { + + handle->wayland.dark_theme_detection = MwFALSE; + detect_dark_theme(handle); + MwLLDispatch(handle, draw, NULL); + } else { + MwLLDBusPortalPoll(&wl_call_tbl.dbus, &handle->wayland.dbus, handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &dark_theme_listener); + } + } +#endif + + if(!handle->wayland.did_initial_resize) { + recursive_dispatch_resize(handle); + handle->wayland.did_initial_resize = 1; + } + + if(!MwWaylandVulkan) { + wl_display_prepare_read(handle->wayland.display); + if(!poll(&fd, 1, timeout.tv_nsec)) { + wl_display_cancel_read(handle->wayland.display); + } else { + wl_display_read_events(handle->wayland.display); + if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { + wl_display_cancel_read(handle->wayland.display); + } + } + } else { + if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { + wl_display_cancel_read(handle->wayland.display); + } + return pending; + } + + MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); + } + + return handle->wayland.force_render || handle->wayland.events_pending || pending; +} + +static void MwLLNextEventImpl(MwLL handle) { + WIDGET_CHECK(handle); + if(!MwWaylandVulkan) { + if(handle->wayland.did_event_loop_early) { + handle->wayland.did_event_loop_early = MwFALSE; + } else { + event_loop(handle); + } + } + + if(handle->wayland.force_render) { + MwLLDispatch(handle, draw, NULL); + if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); + handle->wayland.force_render = 0; + } + if(handle->wayland.events_pending) { + handle->wayland.events_pending = 0; + } +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); + } + if(!handle->wayland.has_decorations && handle->wayland.do_csd) { + strncpy(handle->wayland.title, title, 255); + MwLLBeginDraw(handle); + MwLLEndDraw(handle); + + xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, (strlen(handle->wayland.title) * 8) + 64, 64); + } +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + return MwLLCairoCreatePixmap(handle->wayland.cairo, data, width, height); +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + MwLLCairoPixmapUpdate(r); +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + MwLLCairoDestroyPixmap(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + WIDGET_CHECK(handle); + + clip(handle); + + MwLLCairoDrawPixmap(handle->wayland.cairo, rect, pixmap); + + MwLLForceRender(handle); + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); +} +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + if(WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1) != NULL) { + struct xdg_toplevel_icon_manager_v1* icon_manager = WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1)->context; + struct xdg_toplevel_icon_v1* icon = xdg_toplevel_icon_manager_v1_create_icon(icon_manager); + MwU64 size = pixmap->common.width * pixmap->common.height * 4; + int i = 0; + int line = (pixmap->common.width < pixmap->common.height) ? pixmap->common.height : pixmap->common.width; + + if(handle->wayland.icon == NULL) { + handle->wayland.icon = malloc(sizeof(struct _MwLLWaylandShmBuffer)); + memset(handle->wayland.icon, 0, sizeof(struct _MwLLWaylandShmBuffer)); + handle->wayland.icon->shm = handle->wayland.framebuffer.shm; + } + + if(handle->wayland.icon->setup) { + MwLLWaylandBufferDestroy(handle->wayland.icon); + wl_surface_destroy(handle->wayland.icon->surface); + } + handle->wayland.icon->surface = wl_compositor_create_surface(handle->wayland.compositor); + + MwLLWaylandBufferSetup(handle->wayland.icon, line, line); + + wl_surface_attach(handle->wayland.icon->surface, handle->wayland.icon->shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.icon->surface); + + for(; i < size; i += 2) { + handle->wayland.icon->buf_back[i] = pixmap->common.raw[i + 2]; + handle->wayland.icon->buf_back[i + 1] = pixmap->common.raw[i + 1]; + handle->wayland.icon->buf_back[i + 2] = pixmap->common.raw[i + 0]; + handle->wayland.icon->buf_back[i + 3] = 255; + } + + if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, handle->wayland.icon); + + xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer_back, 1); + + xdg_toplevel_icon_manager_v1_set_icon(icon_manager, handle->wayland.toplevel->xdg_top_level, icon); + } + } + if(!handle->wayland.has_decorations && handle->wayland.do_csd) { + if(handle->wayland.icon_pixmap) { + MwLLDestroyPixmap(handle->wayland.icon_pixmap); + } + handle->wayland.icon_pixmap = MwLLCreatePixmap(handle, pixmap->common.raw, pixmap->common.width, pixmap->common.height); + + actually_set_wh(handle); + actually_set_wh(handle); + MwLLBeginDraw(handle); + MwLLEndDraw(handle); + } +} + +static void MwLLForceRenderImpl(MwLL handle) { + WIDGET_CHECK(handle); + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + + handle->wayland.force_render = MwTRUE; + if(handle->wayland.parent) { + handle->wayland.parent->wayland.force_render = MwTRUE; + } +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + int x, y, xs, ys; + + WIDGET_CHECK(handle); + + if(handle->wayland.cursor.setup) { + MwLLWaylandBufferDestroy(&handle->wayland.cursor); + wl_surface_destroy(handle->wayland.cursor.surface); + } + MwLLWaylandBufferSetup(&handle->wayland.cursor, mask->width, mask->height); + memset(handle->wayland.cursor.buf_back, 0, handle->wayland.cursor.buf_size); + + xs = -mask->x + image->x; + ys = mask->height + mask->y; + ys = image->height + image->y - ys; + + if(ys < 0) ys = -ys; + + for(y = 0; y < mask->height; y++) { + unsigned int d = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + int idx = ((y * mask->width) + x) * 4; + + if(d & 1) { + handle->wayland.cursor.buf_back[idx + 3] = 255; + }; + d = d >> 1; + } + } + for(y = 0; y < image->height; y++) { + unsigned int d = image->data[y]; + for(x = image->width - 1; x >= 0; x--) { + int px = 0; + int idx = (((y + ys) * mask->width) + (x + xs)) * 4; + + if(d & 1) { + px = 255; + }; + + handle->wayland.cursor.buf_back[idx] = px; + handle->wayland.cursor.buf_back[idx + 1] = px; + handle->wayland.cursor.buf_back[idx + 2] = px; + d = d >> 1; + } + } + + handle->wayland.cursor.surface = wl_compositor_create_surface(handle->wayland.compositor); + wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.cursor.surface); + MwLLWaylandBufferUpdate(handle, &handle->wayland.cursor); +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + MwLL p = handle->wayland.parent; + int x = 0, y = 0; + WIDGET_CHECK(handle); + while(p != NULL) { + if(p->wayland.type != MwLL_WAYLAND_TOPLEVEL) { + x += p->wayland.x; + y += p->wayland.y; + } else { + break; + } + p = p->wayland.parent; + } + + handle->wayland.changing = MwTRUE; + handle->wayland.detatching = MwTRUE; + handle->wayland.detach_point = *point; + handle->wayland.detach_point.x += x; + handle->wayland.detach_point.y += y; +} + +static void MwLLShowImpl(MwLL handle, int show) { + if(!handle->wayland.configured) { + return; + } + WIDGET_CHECK(handle); + /* Some guy on a mailing list said that "abusing" wl_surface_attach for this purpose is bad? This is documented behavior so please I beg of you let me know if there's a compositor that actually has a problem with this. */ + if(handle->wayland.framebuffer.surface) { + wl_surface_attach(handle->wayland.framebuffer.surface, show ? handle->wayland.framebuffer.shm_buffer : NULL, 0, 0); + wl_surface_commit(handle->wayland.framebuffer.surface); + } + if(handle->wayland.backbuffer.surface) { + wl_surface_attach(handle->wayland.backbuffer.surface, show ? handle->wayland.backbuffer.shm_buffer : NULL, 0, 0); + wl_surface_commit(handle->wayland.backbuffer.surface); + } +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + (void)handle; + (void)parent; + /* Wayland doesn't have "popups" in the Milsko sense per se. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { + WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, minx, miny); + xdg_toplevel_set_max_size(handle->wayland.toplevel->xdg_top_level, maxx, maxy); + + wl_surface_commit(handle->wayland.framebuffer.surface); + wl_surface_commit(handle->wayland.backbuffer.surface); + } +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + WIDGET_CHECK(handle); + if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { + if(WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1) != NULL) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context; + + if(!dec->decoration) { + dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + dec->manager, handle->wayland.toplevel->xdg_top_level); + } + + zxdg_toplevel_decoration_v1_unset_mode(dec->decoration); + zxdg_toplevel_decoration_v1_set_mode( + dec->decoration, toggle ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } else { + handle->wayland.do_csd = !toggle; + wl_subsurface_set_position(handle->wayland.toplevel->ssurface, handle->wayland.do_csd ? CSD_BORDER_FRAME_LEFT : 0, handle->wayland.do_csd ? CSD_BORDER_FRAME_TOP : 0); + } + } +} + +static void MwLLFocusImpl(MwLL handle) { + (void)handle; + printf("[WARNING] MwLLFocus not supported on Wayland\n"); +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + MwLL topmost_parent = handle; + WIDGET_CHECK(handle); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + if(handle->wayland.pointer_constraints && handle->wayland.relative_pointer_manager) { + if(toggle) { + topmost_parent->wayland.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(topmost_parent->wayland.pointer_constraints, topmost_parent->wayland.backbuffer.surface, topmost_parent->wayland.pointer, topmost_parent->wayland.region, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + wl_surface_commit(topmost_parent->wayland.backbuffer.surface); + zwp_locked_pointer_v1_set_cursor_position_hint(topmost_parent->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); + handle->wayland.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(handle->wayland.relative_pointer_manager, handle->wayland.pointer); + zwp_relative_pointer_v1_add_listener(handle->wayland.relative_pointer, &MwLLWaylandRelativePointerListener, topmost_parent); + } else { + if(topmost_parent->wayland.locked_pointer) { + zwp_locked_pointer_v1_destroy(topmost_parent->wayland.locked_pointer); + topmost_parent->wayland.locked_pointer = NULL; + } + if(topmost_parent->wayland.relative_pointer) { + zwp_relative_pointer_v1_destroy(topmost_parent->wayland.relative_pointer); + topmost_parent->wayland.relative_pointer = NULL; + } + } + handle->wayland.do_lock_pointer = toggle; + } else { + printf("[WARNING] MwLLGrabPointer not supported in Wayland session, zwp_pointer_constraints_v1 and relative_pointer_manager_v1 are required.\n"); + } +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + int i; + WIDGET_CHECK(handle); + + if(handle->wayland.clipboard_buffer != NULL) { + free(handle->wayland.clipboard_buffer); + } + handle->wayland.clipboard_buffer = malloc(strlen(text)); + strcpy(handle->wayland.clipboard_buffer, text); + + if(clipboard_type == MwCLIPBOARD_PRIMARY) { + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_zwp[i]; + zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); + } + } else { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_wl[i]; + wl_data_device_set_selection(device->device.wl, handle->wayland.clipboard_source.wl, handle->wayland.keyboard_serial); + } + } +} + +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + int i; + WIDGET_CHECK(handle); + if(clipboard_type == MwCLIPBOARD_PRIMARY) { + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + MwLLWaylandClipboardRead( + handle->wayland.clipboard_devices_zwp[i], clipboard_type); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); + } + } else { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + MwLLWaylandClipboardRead( + handle->wayland.clipboard_devices_wl[i], clipboard_type); + } + } + return; +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { + MwBool can_do_layer_surface = MwFALSE; + + WIDGET_CHECK(handle); + + can_do_layer_surface = (WAYLAND_GET_INTERFACE(handle->wayland, zwlr_layer_shell_v1) != NULL); + + if(!handle->wayland.parent && can_do_layer_surface) { + handle->wayland.type_to_be = MwLL_WAYLAND_LAYER_SURFACE; + } else { + handle->wayland.type_to_be = MwLL_WAYLAND_POPUP; + } + + handle->wayland.changing = MwTRUE; +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + MwLL topmost_parent = handle; + + WIDGET_CHECK(handle); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + + *point = topmost_parent->wayland.cur_mouse_pos; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + WIDGET_CHECK(handle); + + rect->x = 0; + rect->y = 0; + rect->width = handle->wayland.mw; + rect->height = handle->wayland.mh; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + (void)handle; + /* no-op */ +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLL topmost_parent; + int x, y; + WIDGET_CHECK(handle); + + if(!handle->wayland.changing) { + return; + } + handle->wayland.changing = MwFALSE; + + x = handle->wayland.detatching ? handle->wayland.detach_point.x : handle->wayland.x; + y = handle->wayland.detatching ? handle->wayland.detach_point.y : handle->wayland.y; + + topmost_parent = handle->wayland.parent; + + while(topmost_parent) { + if(topmost_parent->wayland.type != MwLL_WAYLAND_TOPLEVEL) { + topmost_parent = topmost_parent->wayland.parent; + } else { + break; + } + } + + destroy_widget(handle); + + if(wl_display_roundtrip(handle->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + + MwLLWaylandFlush(handle); + + widget_setup(handle, handle->wayland.parent, x, y, handle->wayland.ww, handle->wayland.wh, handle->wayland.type_to_be); + + handle->wayland.is_toplevel = MwTRUE; + + if(!handle->wayland.parent) + handle->wayland.dark_theme_detection = MwTRUE; + + if(handle->common.user) { + MwWidget w = handle->common.user; + int i; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + child->wayland.sublevel->xdg_surface = handle->wayland.popup->xdg_surface; + if(child->wayland.sublevel->subsurface) + wl_subsurface_destroy(child->wayland.sublevel->subsurface); + MwLLWaylandFlush(handle); + + child->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(child->wayland.sublevel->subcompositor, child->wayland.framebuffer.surface, handle->wayland.framebuffer.surface); + wl_subsurface_set_desync(child->wayland.sublevel->subsurface); + wl_subsurface_set_position(child->wayland.sublevel->subsurface, child->wayland.x, child->wayland.y); + + wl_subsurface_place_above(child->wayland.sublevel->subsurface, handle->wayland.framebuffer.surface); + MwLLEndStateChangeImpl(w->children[i]->lowlevel); + + if(topmost_parent) { + topmost_parent->wayland.currentlyHeldWidget = NULL; + } + } + } + } + + recursive_render(handle); + + handle->wayland.events_pending = 1; + + handle->wayland.detatching = MwFALSE; +} + +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + (void)toggle; + + /* Not Really what's supposed to happen with this function, but take this opprutunity to do the handlers that will force everything to redraw. */ + MwLLDispatch(handle, resize, NULL); + MwLLDispatch(handle, draw, NULL); +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + (void)handle; + /* WIDGET_CHECK(handle); + + if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL) { + MwLL topmost_parent = handle; + int children_num; + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; + children_num = arrlen(((MwWidget)topmost_parent->common.user)->children); + + if(children_num > 1) { + printf("%d\n", children_num); + MwWidget last_child = ((MwWidget)topmost_parent->common.user)->children[children_num - 1]; + wl_subsurface_place_above(handle->wayland.sublevel->subsurface, last_child->lowlevel->wayland.framebuffer.surface); + } + }*/ +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + if(rect == NULL) { + handle->wayland.is_clipping = MwFALSE; + } else { + handle->wayland.clip = *rect; + handle->wayland.is_clipping = MwTRUE; + } +} + +static int MwLLWaylandCallInitImpl(void) { +#ifdef __linux__ + MwBool loadWayland = MwFALSE; + if(getenv("MILSKO_BACKEND")) { + loadWayland |= + (strcmp(getenv("MILSKO_BACKEND"), "wayland") == 0); + } else if(getenv("WAYLAND_DISPLAY")) { + loadWayland |= (getenv("WAYLAND_DISPLAY") != NULL); + } + +#ifdef MW_OPENGL + if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { + loadWayland = 0; + } +#endif + + if(loadWayland) { + if(wayland_load_funcs()) { + return 1; + } + wl_log_set_handler_client(wl_logger); + + return 0; + } +#endif + return 1; +} + +#include "../call.c" +CALL(Wayland); diff --git a/widget/milsko/milskosrc/src/backend/x11.c b/widget/milsko/milskosrc/src/backend/x11.c new file mode 100644 index 0000000000..79ce4295c0 --- /dev/null +++ b/widget/milsko/milskosrc/src/backend/x11.c @@ -0,0 +1,1525 @@ +#include + +#include "../../external/stb_ds.h" + +#define ClipboardTimeout 100 + +#ifdef USE_XRENDER +// #undef USE_XRENDER +#endif + +static struct symtbl { + void* lib_xlib; + void* lib_xrender; + MwBool has_xrender; + +#ifdef USE_DBUS + MwLLDBusFuncTable dbus; + MwBool has_dbus; +#endif + + int (*XClearWindow)(Display* display, Window w); + XImage* (*XCreateImage)(Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int); + Display* (*XOpenDisplay)(_Xconst char*); + char* (*XKeysymToString)(KeySym); + Atom (*XInternAtom)(Display*, _Xconst char*, Bool); + Cursor (*XCreatePixmapCursor)(Display*, Pixmap, Pixmap, XColor*, XColor*, unsigned int, unsigned int); + GC (*XCreateGC)(Display*, Drawable, unsigned long, XGCValues*); + Pixmap (*XCreatePixmap)(Display*, Drawable, unsigned int, unsigned int, unsigned int); + Window (*XCreateSimpleWindow)(Display*, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long); + VisualID (*XVisualIDFromVisual)(Visual*); + Window (*XRootWindow)(Display*, int); + Status (*XSetWMProtocols)(Display*, Window, Atom*, int); + int (*XSetTransientForHint)(Display*, Window, Window); + Status (*XAllocColor)(Display*, Colormap, XColor*); + int (*XChangeProperty)(Display*, Window, Atom, Atom, int, int, _Xconst unsigned char*, int); + int (*XChangeWindowAttributes)(Display*, Window, unsigned long, XSetWindowAttributes*); + Bool (*XCheckTypedWindowEvent)(Display*, Window, int, XEvent*); + Bool (*XCheckWindowEvent)(Display*, Window, long, XEvent*); + int (*XCloseDisplay)(Display*); + int (*XConfigureWindow)(Display*, Window, unsigned int, XWindowChanges*); + int (*XConvertSelection)(Display*, Atom, Atom, Atom, Window, Time); + int (*XCopyArea)(Display*, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int); + int (*XDefaultScreen)(Display*); + int (*XDefineCursor)(Display*, Window, Cursor); + int (*XDeleteProperty)(Display*, Window, Atom); + int (*XDestroyWindow)(Display*, Window); + int (*XDrawLine)(Display*, Drawable, GC, int, int, int, int); + int (*XFillPolygon)(Display*, Drawable, GC, XPoint*, int, int, int); + int (*XFree)(void*); + int (*XFreeCursor)(Display*, Cursor); + int (*XFreeGC)(Display*, GC); + int (*XFreePixmap)(Display*, Pixmap); + Status (*XGetGeometry)(Display*, Drawable, Window*, int*, int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*); + int (*XGetWindowProperty)(Display*, Window, Atom, long, long, Bool, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**); + Status (*XGetWindowAttributes)(Display*, Window, XWindowAttributes*); + int (*XMapWindow)(Display*, Window); + int (*XNextEvent)(Display*, XEvent*); + int (*XPending)(Display*); + int (*XPutBackEvent)(Display*, XEvent*); + int (*XPutImage)(Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int); + Bool (*XQueryPointer)(Display*, Window, Window*, Window*, int*, int*, int*, int*, unsigned int*); + Status (*XQueryTree)(Display*, Window, Window*, Window*, Window**, unsigned int*); + int (*XReparentWindow)(Display*, Window, Window, int, int); + int (*XSelectInput)(Display*, Window, long); + Status (*XSendEvent)(Display*, Window, Bool, long, XEvent*); + int (*XSetClipMask)(Display*, GC, Pixmap); + int (*XSetClipOrigin)(Display*, GC, int, int); + int (*XSetClipRectangles)(Display*, GC, int, int, XRectangle[], int, int); + int (*XSetForeground)(Display*, GC, unsigned long); + int (*XSetGraphicsExposures)(Display*, GC, Bool); + int (*XSetInputFocus)(Display*, Window, int, Time); + int (*XSetWindowBackgroundPixmap)(Display*, Window, Pixmap); + int (*XSync)(Display*, Bool); + Bool (*XTranslateCoordinates)(Display*, Window, Window, int, int, int*, int*, Window*); + int (*XUnmapWindow)(Display*, Window); + int (*XWarpPointer)(Display*, Window, Window, int, int, unsigned int, unsigned int, int, int); + char* (*XSetLocaleModifiers)(const char*); + XIM (*XOpenIM)(Display*, struct _XrmHashBucketRec*, char*, char*); + Status (*XCloseIM)(XIM); + XIC (*XCreateIC)(XIM, ...); + void (*XDestroyIC)(XIC); + void (*XSetICFocus)(XIC); + XImage* (*XGetImage)(Display*, Drawable, int, int, unsigned int, unsigned int, unsigned long, int); + int (*XRaiseWindow)(Display*, Window); + + XSizeHints* (*XAllocSizeHints)(void); + XVisualInfo* (*XGetVisualInfo)(Display*, long, XVisualInfo*, int*); + Status (*XGetWMNormalHints)(Display*, Window, XSizeHints*, long*); + Status (*XGetWMSizeHints)(Display*, Window, XSizeHints*, long*, Atom); + int (*XLookupString)(XKeyEvent*, char*, int, KeySym*, XComposeStatus*); + int (*XSetStandardProperties)(Display*, Window, _Xconst char*, _Xconst char*, Pixmap, char**, int, XSizeHints*); + void (*XSetWMNormalHints)(Display*, Window, XSizeHints*); + void (*XSetWMSizeHints)(Display*, Window, XSizeHints*, Atom); + +#if USE_XRENDER + Bool (*XRenderQueryExtension)(Display* dpy, int* event_basep, int* error_basep); + + XRenderPictFormat* (*XRenderFindStandardFormat)(Display* dpy, int format); + + Picture (*XRenderCreatePicture)(Display* dpy, Drawable drawable, + _Xconst XRenderPictFormat* format, + unsigned long valuemask, + _Xconst XRenderPictureAttributes* attributes); + + void (*XRenderFreePicture)(Display* dpy, Picture picture); + + void (*XRenderSetPictureTransform)(Display* dpy, Picture picture, + XTransform* transform); + + void (*XRenderComposite)(Display* dpy, int op, Picture src, Picture mask, + Picture dst, int src_x, int src_y, int mask_x, int mask_y, + int dst_x, int dst_y, unsigned int width, + unsigned int height); +#endif +} xsymtbl; + +#define XClearWindow xsymtbl.XClearWindow +#define XCreateIC xsymtbl.XCreateIC +#define XFree xsymtbl.XFree +#define XFreeCursor xsymtbl.XFreeCursor +#define XConfigureWindow xsymtbl.XConfigureWindow +#define XCheckTypedWindowEvent xsymtbl.XCheckTypedWindowEvent +#define XGetWMNormalHints xsymtbl.XGetWMNormalHints +#define XLookupString xsymtbl.XLookupString +#define XCreateImage xsymtbl.XCreateImage +#define XSetClipMask xsymtbl.XSetClipMask +#define XConvertSelection xsymtbl.XConvertSelection +#define XGetWindowProperty xsymtbl.XGetWindowProperty +#define XSetWMNormalHints xsymtbl.XSetWMNormalHints +#define XTranslateCoordinates xsymtbl.XTranslateCoordinates +#define XCreateSimpleWindow xsymtbl.XCreateSimpleWindow +#define XGetWMSizeHints xsymtbl.XGetWMSizeHints +#define XRootWindow xsymtbl.XRootWindow +#define XOpenDisplay xsymtbl.XOpenDisplay +#define XCopyArea xsymtbl.XCopyArea +#define XDeleteProperty xsymtbl.XDeleteProperty +#define XDrawLine xsymtbl.XDrawLine +#define XSetGraphicsExposures xsymtbl.XSetGraphicsExposures +#define XDestroyWindow xsymtbl.XDestroyWindow +#define XCloseDisplay xsymtbl.XCloseDisplay +#define XSetForeground xsymtbl.XSetForeground +#define XGetGeometry xsymtbl.XGetGeometry +#define XUnmapWindow xsymtbl.XUnmapWindow +#define XSetTransientForHint xsymtbl.XSetTransientForHint +#define XSetWMSizeHints xsymtbl.XSetWMSizeHints +#define XCreatePixmapCursor xsymtbl.XCreatePixmapCursor +#define XFreeGC xsymtbl.XFreeGC +#define XNextEvent xsymtbl.XNextEvent +#define XSetWMProtocols xsymtbl.XSetWMProtocols +#define XDefaultScreen xsymtbl.XDefaultScreen +#define XKeysymToString xsymtbl.XKeysymToString +#define XMapWindow xsymtbl.XMapWindow +#define XPutBackEvent xsymtbl.XPutBackEvent +#define XCreateGC xsymtbl.XCreateGC +#define XSelectInput xsymtbl.XSelectInput +#define XSetInputFocus xsymtbl.XSetInputFocus +#define XDestroyIC xsymtbl.XDestroyIC +#define XSync xsymtbl.XSync +#define XSendEvent xsymtbl.XSendEvent +#define XSetICFocus xsymtbl.XSetICFocus +#define XWarpPointer xsymtbl.XWarpPointer +#define XPutImage xsymtbl.XPutImage +#define XFillPolygon xsymtbl.XFillPolygon +#define XOpenIM xsymtbl.XOpenIM +#define XDefineCursor xsymtbl.XDefineCursor +#define XSetWindowBackgroundPixmap xsymtbl.XSetWindowBackgroundPixmap +#define XAllocColor xsymtbl.XAllocColor +#define XInternAtom xsymtbl.XInternAtom +#define XQueryPointer xsymtbl.XQueryPointer +#define XGetVisualInfo xsymtbl.XGetVisualInfo +#define XVisualIDFromVisual xsymtbl.XVisualIDFromVisual +#define XSetLocaleModifiers xsymtbl.XSetLocaleModifiers +#define XGetWindowAttributes xsymtbl.XGetWindowAttributes +#define XSetStandardProperties xsymtbl.XSetStandardProperties +#define XChangeProperty xsymtbl.XChangeProperty +#define XAllocSizeHints xsymtbl.XAllocSizeHints +#define XCheckWindowEvent xsymtbl.XCheckWindowEvent +#define XFreePixmap xsymtbl.XFreePixmap +#define XReparentWindow xsymtbl.XReparentWindow +#define XCreatePixmap xsymtbl.XCreatePixmap +#define XSetClipOrigin xsymtbl.XSetClipOrigin +#define XSetClipRectangles xsymtbl.XSetClipRectangles +#define XCloseIM xsymtbl.XCloseIM +#define XQueryTree xsymtbl.XQueryTree +#define XPending xsymtbl.XPending +#define XChangeWindowAttributes xsymtbl.XChangeWindowAttributes +#define XGetImage xsymtbl.XGetImage +#define XRaiseWindow xsymtbl.XRaiseWindow + +#if USE_XRENDER +#define XRenderFindStandardFormat xsymtbl.XRenderFindStandardFormat +#define XRenderCreatePicture xsymtbl.XRenderCreatePicture +#define XRenderFreePicture xsymtbl.XRenderFreePicture +#define XRenderComposite xsymtbl.XRenderComposite +#define XRenderQueryExtension xsymtbl.XRenderQueryExtension +#define XRenderSetPictureTransform xsymtbl.XRenderSetPictureTransform +#endif + +typedef struct mwm_hints { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; +} mwm_hints_t; + +enum mwm_hints_enum { + MWM_HINTS_FUNCTIONS = (1L << 0), + MWM_HINTS_DECORATIONS = (1L << 1), + MWM_FUNC_ALL = (1L << 0), + MWM_FUNC_RESIZE = (1L << 1), + MWM_FUNC_MOVE = (1L << 2), + MWM_FUNC_MINIMIZE = (1L << 3), + MWM_FUNC_MAXIMIZE = (1L << 4), + MWM_FUNC_CLOSE = (1L << 5) +}; + +static unsigned long mask = ExposureMask | StructureNotifyMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | KeymapNotify | FocusChangeMask; + +static void create_pixmap(MwLL handle) { + XWindowAttributes attr; + int x, y; + unsigned int w, h; + + MwLLGetXYWH(handle, &x, &y, &w, &h); + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &attr); + + handle->x11.pixmap = XCreatePixmap(handle->x11.display, handle->x11.window, w, h, attr.depth); +} + +static void destroy_pixmap(MwLL handle) { + XFreePixmap(handle->x11.display, handle->x11.pixmap); +} + +static void sync_move(MwLL handle, int x, int y) { + XEvent* queue = NULL; + XEvent ev; + unsigned long n = MwTimeGetTick() + 100; + XWindowAttributes xwa; + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &xwa); + + XSync(handle->x11.display, False); + + while(!xwa.override_redirect && n > MwTimeGetTick()) { + XSync(handle->x11.display, False); + if(!XPending(handle->x11.display)) continue; + XNextEvent(handle->x11.display, &ev); + if(ev.type == ReparentNotify && ev.xreparent.window == handle->x11.window) { + break; + } else { + arrput(queue, ev); + } + } + + while(arrlen(queue) > 0) { + XPutBackEvent(handle->x11.display, &queue[0]); + arrdel(queue, 0); + } + arrfree(queue); + + MwLLSetXY(handle, x, y); +} + +static void wait_map(MwLL handle, int sync) { + XWindowAttributes xwa; + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &xwa); + if(xwa.map_state != IsViewable) { + XSync(handle->x11.display, False); + + XMapWindow(handle->x11.display, handle->x11.window); + XSync(handle->x11.display, False); + + if(!sync) return; + do { + XMapWindow(handle->x11.display, handle->x11.window); + XSync(handle->x11.display, False); + XGetWindowAttributes(handle->x11.display, handle->x11.window, &xwa); + } while(xwa.map_state != IsViewable); + } +} + +static void wait_unmap(MwLL handle, int sync) { + XWindowAttributes xwa; + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &xwa); + if(xwa.map_state != IsUnmapped) { + XSync(handle->x11.display, False); + + XUnmapWindow(handle->x11.display, handle->x11.window); + XSync(handle->x11.display, False); + + if(!sync) return; + do { + XUnmapWindow(handle->x11.display, handle->x11.window); + XSync(handle->x11.display, False); + XGetWindowAttributes(handle->x11.display, handle->x11.window, &xwa); + } while(xwa.map_state != IsUnmapped); + } +} + +static unsigned long generate_color(MwLL handle, unsigned long r, unsigned long g, unsigned long b) { + unsigned long c = 0; + + c |= (r * handle->x11.red_max / 255) << handle->x11.red_shift; + + c |= (g * handle->x11.green_max / 255) << handle->x11.green_shift; + + c |= (b * handle->x11.blue_max / 255) << handle->x11.blue_shift; + + return c; +} + +static XVisualInfo* get_visual_info(Display* display) { + XVisualInfo xvi; + int n; + Visual* visual = DefaultVisual(display, DefaultScreen(display)); + + xvi.visualid = XVisualIDFromVisual(visual); + + return XGetVisualInfo(display, VisualIDMask, &xvi, &n); +} + +#ifdef USE_DBUS +static void detect_dark_theme(MwLL handle) { + MwU32 value = 0; + MwU32 dark_theme = 0; + MwLLDBusPortalGet(&xsymtbl.dbus, &handle->x11.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + + dark_theme = (value == 1) ? 1 : 0; + + MwLLDispatch(handle, dark_theme, &dark_theme); +} +#endif + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + Window p; + XVisualInfo* xvi; + unsigned long n = 1; + int i; + int px = x, py = y; + XSizeHints sh; + + r = malloc(sizeof(*r)); + + MwLLCreateCommon(r); + + if(px == MwDEFAULT) px = 0; + if(py == MwDEFAULT) py = 0; + if(width < 2) width = 2; + if(height < 2) height = 2; + + if(parent == NULL) { + r->x11.display = XOpenDisplay(NULL); + p = XRootWindow(r->x11.display, XDefaultScreen(r->x11.display)); + r->x11.top = 1; + r->x11.toplevel = 1; + } else { + r->x11.display = parent->x11.display; + p = parent->x11.window; + r->x11.top = 0; + r->x11.toplevel = 0; + } + r->x11.window = XCreateSimpleWindow(r->x11.display, p, px, py, width, height, 0, 0, WhitePixel(r->x11.display, DefaultScreen(r->x11.display))); + + sh.flags = PWinGravity; + sh.win_gravity = StaticGravity; + XSetWMNormalHints(r->x11.display, r->x11.window, &sh); + + xvi = get_visual_info(r->x11.display); + + if(xvi->red_mask != 0) { + i = 0; + while(!((n << i) & xvi->red_mask)) i++; + r->x11.red_mask = xvi->red_mask; + r->x11.red_max = xvi->red_mask >> i; + r->x11.red_shift = i; + + i = 0; + while(!((n << i) & xvi->green_mask)) i++; + r->x11.green_mask = xvi->green_mask; + r->x11.green_max = xvi->green_mask >> i; + r->x11.green_shift = i; + + i = 0; + while(!((n << i) & xvi->blue_mask)) i++; + r->x11.blue_mask = xvi->blue_mask; + r->x11.blue_max = xvi->blue_mask >> i; + r->x11.blue_shift = i; + } + + XFree(xvi); + +#ifdef DO_XIM + XSetLocaleModifiers(""); + if((r->x11.xim = XOpenIM(r->x11.display, 0, 0, 0)) == NULL) { + XSetLocaleModifiers("@im=none"); + r->x11.xim = XOpenIM(r->x11.display, 0, 0, 0); + } + + r->x11.xic = XCreateIC(r->x11.xim, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, r->x11.window, + XNFocusWindow, r->x11.window, + NULL); + XSetICFocus(r->x11.xic); +#endif + + r->common.copy_buffer = 1; + r->common.type = MwLLBackendX11; + + r->x11.width = width; + r->x11.height = height; + + r->x11.grabbed = 0; + r->x11.force_render = 0; + r->x11.dark_theme_detection = 0; + + r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display)); + r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False); + r->x11.wm_protocols = XInternAtom(r->x11.display, "WM_PROTOCOLS", False); + XSetWMProtocols(r->x11.display, r->x11.window, &r->x11.wm_delete, 1); + + r->x11.utf8_string = XInternAtom(r->x11.display, "UTF8_STRING", False); + r->x11.compound_text = XInternAtom(r->x11.display, "COMPOUND_TEXT", False); + r->x11.text = XInternAtom(r->x11.display, "TEXT", False); + r->x11.clipboard = XInternAtom(r->x11.display, "CLIPBOARD", False); + r->x11.selection = XInternAtom(r->x11.display, "_MILSKO_SELECTION_", False); + + r->x11.clipboard_pending = 0; + + r->x11.gc = XCreateGC(r->x11.display, r->x11.window, 0, NULL); + + create_pixmap(r); + + XSetGraphicsExposures(r->x11.display, r->x11.gc, False); + + XSelectInput(r->x11.display, r->x11.window, mask); + + wait_map(r, 0); + + if(x != MwDEFAULT || y != MwDEFAULT) { + unsigned int dummy; + + MwLLGetXYWH(r, &px, &py, &dummy, &dummy); + + if(x == MwDEFAULT) x = px; + if(y == MwDEFAULT) y = py; + + if(parent == NULL) { + sync_move(r, x, y); + } else { + MwLLSetXY(r, x, y); + } + } + +#ifdef USE_DBUS + memset(&r->x11.dbus, 0, sizeof(r->x11.dbus)); + if(!parent && xsymtbl.has_dbus) { + xsymtbl.has_dbus = MwLLDBusNewContext(&xsymtbl.dbus, &r->x11.dbus); + r->x11.dark_theme_detection = MwTRUE; + } +#endif + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MwLLDestroyCommon(handle); + +#ifdef DO_XIM + if(handle->x11.xic) XDestroyIC(handle->x11.xic); + if(handle->x11.xim) XCloseIM(handle->x11.xim); +#endif + + destroy_pixmap(handle); + XFreeGC(handle->x11.display, handle->x11.gc); + XUnmapWindow(handle->x11.display, handle->x11.window); + XDestroyWindow(handle->x11.display, handle->x11.window); + + XSync(handle->x11.display, False); + + if(handle->x11.toplevel) XCloseDisplay(handle->x11.display); + +#ifdef USE_DBUS + if(!xsymtbl.has_dbus) { + MwLLDBusFreeContext(&xsymtbl.dbus, &handle->x11.dbus); + } +#endif + + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; + + if(handle->common.copy_buffer) XClearWindow(handle->x11.display, handle->x11.window); +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + int i; + XPoint* p = malloc(sizeof(*p) * points_count); + + XSetForeground(handle->x11.display, handle->x11.gc, color->x11.pixel); + + for(i = 0; i < points_count; i++) { + p[i].x = points[i].x; + p[i].y = points[i].y; + } + XFillPolygon(handle->x11.display, handle->x11.pixmap, handle->x11.gc, p, points_count, Nonconvex, CoordModeOrigin); + + free(p); +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + XSetForeground(handle->x11.display, handle->x11.gc, color->x11.pixel); + + XDrawLine(handle->x11.display, handle->x11.pixmap, handle->x11.gc, points[0].x, points[0].y, points[1].x, points[1].y); +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + XColor xc; + + if(handle->x11.red_mask == 0) { + if(r > 255) r = 255; + if(g > 255) g = 255; + if(b > 255) b = 255; + if(r < 0) r = 0; + if(g < 0) g = 0; + if(b < 0) b = 0; + + xc.red = 256 * r; + xc.green = 256 * g; + xc.blue = 256 * b; + XAllocColor(handle->x11.display, handle->x11.colormap, &xc); + + c->x11.pixel = xc.pixel; + } else { + c->x11.pixel = generate_color(handle, r, g, b); + } + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} + +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + Window root; + unsigned int border, depth; + + XGetGeometry(handle->x11.display, handle->x11.window, &root, x, y, w, h, &border, &depth); + if(handle->x11.top) { + int rx, ry; + Window child; + + XTranslateCoordinates(handle->x11.display, handle->x11.window, root, 0, 0, &rx, &ry, &child); + + *x = rx; + *y = ry; + } +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + XSizeHints sh; + long r; + XWindowChanges xwc; + XWindowAttributes xwa; + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &xwa); + if(xwa.x == x && xwa.y == y) return; + + sh.flags = 0; + XGetWMNormalHints(handle->x11.display, handle->x11.window, &sh, &r); + + sh.flags |= USPosition; + sh.x = x; + sh.y = y; + +#if 1 + xwc.x = x; + xwc.y = y; + XConfigureWindow(handle->x11.display, handle->x11.window, CWX | CWY, &xwc); +#else + XMoveWindow(handle->x11.display, handle->x11.window, x, y); +#endif + XSetWMNormalHints(handle->x11.display, handle->x11.window, &sh); + + XSync(handle->x11.display, False); +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + XSizeHints sh; + long r; + XWindowChanges xwc; + XWindowAttributes xwa; + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &xwa); + if(xwa.width == w && xwa.height == h) return; + + sh.flags = 0; + XGetWMNormalHints(handle->x11.display, handle->x11.window, &sh, &r); + + if(w < 2) w = 2; + if(h < 2) h = 2; + + sh.flags |= PSize; + sh.width = w; + sh.height = h; + +#if 1 + xwc.width = w; + xwc.height = h; + XConfigureWindow(handle->x11.display, handle->x11.window, CWWidth | CWHeight, &xwc); +#else + XResizeWindow(handle->x11.display, handle->x11.window, w, h); +#endif + XSetWMNormalHints(handle->x11.display, handle->x11.window, &sh); + + destroy_pixmap(handle); + create_pixmap(handle); + + /* we want events */ +#if 0 + handle->x11.width = w; + handle->x11.height = h; +#endif + + XSync(handle->x11.display, False); + + MwLLForceRender(handle); +} + +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} + +static int MwLLPendingImpl(MwLL handle) { + XEvent ev; + + if(handle->x11.dark_theme_detection) { + handle->x11.dark_theme_detection = MwFALSE; +#ifdef USE_DBUS + if(xsymtbl.has_dbus) { + detect_dark_theme(handle); + MwLLDispatch(handle, draw, NULL); + } +#endif + } + + if(handle->x11.clipboard_pending && (MwTimeGetTick() - handle->x11.clipboard_time) >= ClipboardTimeout) { + return 1; + } + + if(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, SelectionNotify, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) { + XPutBackEvent(handle->x11.display, &ev); + return 1; + } + return 0; +} + +static void MwLLNextEventImpl(MwLL handle) { + XEvent ev; + + if(handle->x11.clipboard_pending && (MwTimeGetTick() - handle->x11.clipboard_time) >= ClipboardTimeout) { + Atom a = handle->x11.selection; + + handle->x11.clipboard_pending++; + handle->x11.clipboard_time = MwTimeGetTick(); + + switch(handle->x11.clipboard_pending) { + case 2: + a = handle->x11.compound_text; + break; + case 3: + a = handle->x11.text; + break; + case 4: + a = XA_STRING; + break; + case 5: + handle->x11.clipboard_pending = 0; + break; + } + + if(a != handle->x11.selection) { + XConvertSelection(handle->x11.display, handle->x11.clipboard, a, handle->x11.selection, handle->x11.window, CurrentTime); + } + } + + while(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, SelectionNotify, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) { + int render = 0; + if(ev.type == Expose) { + handle->x11.force_render = 0; + render = 1; + } else if(ev.type == ButtonPress) { + MwMouse p; + p.point.x = ev.xbutton.x; + p.point.y = ev.xbutton.y; + if(ev.xbutton.button == Button1) { + p.button = MwMOUSE_LEFT; + } else if(ev.xbutton.button == Button2) { + p.button = MwMOUSE_MIDDLE; + } else if(ev.xbutton.button == Button3) { + p.button = MwMOUSE_RIGHT; + } else if(ev.xbutton.button == Button4) { + p.button = MwMOUSE_WHEELUP; + } else if(ev.xbutton.button == Button5) { + p.button = MwMOUSE_WHEELDOWN; + } + +#ifndef ALLOW_SLOPPY_FOCUS + XSetInputFocus(handle->x11.display, handle->x11.window, RevertToNone, CurrentTime); +#endif + + MwLLDispatch(handle, down, &p); + } else if(ev.type == ButtonRelease) { + MwMouse p; + p.point.x = ev.xbutton.x; + p.point.y = ev.xbutton.y; + if(ev.xbutton.button == Button1) { + p.button = MwMOUSE_LEFT; + } else if(ev.xbutton.button == Button2) { + p.button = MwMOUSE_MIDDLE; + } else if(ev.xbutton.button == Button3) { + p.button = MwMOUSE_RIGHT; + } else if(ev.xbutton.button == Button4) { + p.button = MwMOUSE_WHEELUP; + } else if(ev.xbutton.button == Button5) { + p.button = MwMOUSE_WHEELDOWN; + } + + MwLLDispatch(handle, up, &p); + } else if(ev.type == ConfigureNotify) { + if(handle->x11.width != (unsigned int)ev.xconfigure.width || handle->x11.height != (unsigned int)ev.xconfigure.height) { + MwLLDispatch(handle, resize, NULL); + destroy_pixmap(handle); + create_pixmap(handle); + render = 1; + } + handle->x11.width = ev.xconfigure.width; + handle->x11.height = ev.xconfigure.height; + } else if(ev.type == ClientMessage) { + if(ev.xclient.message_type == handle->x11.wm_protocols && ev.xclient.data.l[0] == (long)handle->x11.wm_delete) { + MwLLDispatch(handle, close, NULL); + } + } else if(ev.type == FocusIn) { + MwLLDispatch(handle, focus_in, NULL); + } else if(ev.type == FocusOut) { + MwLLDispatch(handle, focus_out, NULL); + } else if(ev.type == MotionNotify) { + MwPoint p; + XWindowAttributes attr; + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &attr); + + p.x = ev.xmotion.x; + p.y = ev.xmotion.y; + + if(handle->x11.grabbed) { + p.x -= attr.width / 2; + p.y -= attr.height / 2; + } + + MwLLDispatch(handle, move, &p); + if(handle->x11.grabbed && (p.x != 0 || p.y != 0)) { + XWarpPointer(handle->x11.display, None, handle->x11.window, 0, 0, 0, 0, attr.width / 2, attr.height / 2); + } + } else if(ev.type == KeyPress || ev.type == KeyRelease) { + int n = -1; + char str[512]; + KeySym sym; + + str[0] = 0; + + XLookupString(&ev.xkey, str, 512, &sym, NULL); + + /* wtf is wrong with xlib? */ + if(strlen(str) == 0 || (str[0] < 0x20)) { + char* s = XKeysymToString(sym); + + strcpy(str, s); + } + + if(MwStringIsKeyUTF8(sym)) { + char s = str[0]; + + if(ev.xkey.state & (ShiftMask | LockMask) && !(ev.xkey.state & (ControlMask | Mod1Mask))) { + n = toupper((int)s); + } else { + n = s; + } + } + + if(strcmp(str, "BackSpace") == 0) { + n = MwKEY_BACKSPACE; + } else if(strcmp(str, "Left") == 0) { + n = MwKEY_LEFT; + } else if(strcmp(str, "Right") == 0) { + n = MwKEY_RIGHT; + } else if(strcmp(str, "Up") == 0) { + n = MwKEY_UP; + } else if(strcmp(str, "Down") == 0) { + n = MwKEY_DOWN; + } else if(strcmp(str, "Return") == 0) { + n = MwKEY_ENTER; + } else if(strcmp(str, "Escape") == 0) { + n = MwKEY_ESCAPE; + } else if(strcmp(str, "Shift_L") == 0) { + n = MwKEY_LEFTSHIFT; + } else if(strcmp(str, "Shift_R") == 0) { + n = MwKEY_RIGHTSHIFT; + } else if(strcmp(str, "Alt_L") == 0 || strcmp(str, "Alt_R") == 0) { + n = MwKEY_ALT; + } else if(strcmp(str, "Control_R") == 0 || strcmp(str, "Control_R") == 0) { + n = MwKEY_CONTROL; + } + + if(n != MwKEY_CONTROL && ev.xkey.state & ControlMask) { + n |= MwKEY_CONTROL_FLAG; + } + if(n != MwKEY_ALT && ev.xkey.state & Mod1Mask) { + n |= MwKEY_ALT_FLAG; + } + + if(n != -1) { + if(ev.type == KeyPress) { + MwLLDispatch(handle, key, &n); + } else { + MwLLDispatch(handle, key_released, &n); + } + } + } else if(ev.type == SelectionNotify) { + handle->x11.clipboard_pending = 0; + + if(ev.xselection.property != None) { + Atom type; + int format; + unsigned long nitems, after, size; + unsigned char* pdat; + int ret = XGetWindowProperty(handle->x11.display, handle->x11.window, handle->x11.selection, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &pdat); + + if(pdat != NULL) XFree(pdat); + + size = after; + + if(ret == Success && type != None && format == 8) { + char* buf = malloc(size + 1); + int offset; + + for(offset = 0; after > 0; offset += nitems) { + ret = XGetWindowProperty(handle->x11.display, handle->x11.window, handle->x11.selection, offset / 4, after / 4 + 1, False, AnyPropertyType, &type, &format, &nitems, &after, &pdat); + + if(ret != Success) { + free(buf); + buf = NULL; + break; + } + + memcpy(buf + offset, pdat, nitems); + + XFree(pdat); + } + + if(buf != NULL) { + buf[size] = 0; + + MwLLDispatch(handle, clipboard, buf); + + free(buf); + } + } + + XDeleteProperty(handle->x11.display, handle->x11.window, handle->x11.selection); + } + } + if(render) { + int x, y; + unsigned int w, h; + + MwLLGetXYWH(handle, &x, &y, &w, &h); + + MwLLDispatch(handle, draw, NULL); + if(handle->common.copy_buffer) { + XCopyArea(handle->x11.display, handle->x11.pixmap, handle->x11.window, handle->x11.gc, 0, 0, w, h, 0, 0); + XSetWindowBackgroundPixmap(handle->x11.display, handle->x11.window, handle->x11.pixmap); + } + } + } +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + XSetStandardProperties(handle->x11.display, handle->x11.window, title, title, None, (char**)NULL, 0, NULL); +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + MwLLPixmap r = malloc(sizeof(*r)); + int evbase, erbase; + XWindowAttributes attr; + + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &attr); + + r->common.width = width; + r->common.height = height; + + r->x11.depth = attr.depth; + r->x11.display = handle->x11.display; + r->x11.data = malloc(sizeof(unsigned long) * width * height); + r->x11.handle = handle; + +#ifdef USE_XRENDER + if(xsymtbl.has_xrender) { + r->x11.use_xrender = XRenderQueryExtension(handle->x11.display, &evbase, &erbase) ? 1 : 0; + } +#endif + + r->x11.image = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), r->x11.depth, ZPixmap, 0, NULL, width, height, 32, 0); + r->x11.mask = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), 8, ZPixmap, 0, NULL, width, height, 32, 0); + + r->x11.image->data = malloc(r->x11.image->bytes_per_line * height); + r->x11.mask->data = malloc(r->x11.mask->bytes_per_line * height); + + MwLLPixmapUpdate(r); + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + int y, x; + for(y = 0; y < r->common.height; y++) { + for(x = 0; x < r->common.width; x++) { + unsigned char* px = &r->common.raw[(y * r->common.width + x) * 4]; + MwLLColor c = NULL; + unsigned long p; + + c = MwLLAllocColor(r->x11.handle, px[0], px[1], px[2]); + p = c->x11.pixel; + MwLLFreeColor(c); + + XPutPixel(r->x11.image, x, y, p); + *(unsigned long*)(&r->x11.data[(y * r->common.width + x) * sizeof(unsigned long)]) = (px[3] << 24) | p; + } + } + + for(y = 0; y < r->common.height; y++) { + for(x = 0; x < r->common.width; x++) { + if(r->common.raw[(y * r->common.width + x) * 4 + 3]) { + XPutPixel(r->x11.mask, x, y, 255); + } else { + XPutPixel(r->x11.mask, x, y, 0); + } + } + } +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap->common.raw); + XDestroyImage(pixmap->x11.image); + XDestroyImage(pixmap->x11.mask); + free(pixmap->x11.data); + + free(pixmap); +} + +#define DO_XRENDER(dest_px, src, format, bpp) \ + { \ + Picture src_pic, dest_pic; \ + XRenderPictFormat* fmt = XRenderFindStandardFormat(handle->x11.display, format); \ + Pixmap src_px = XCreatePixmap(handle->x11.display, handle->x11.window, pixmap->common.width, pixmap->common.height, bpp); \ + GC gc = XCreateGC(handle->x11.display, src_px, 0, NULL); \ +\ + dest_px = XCreatePixmap(handle->x11.display, handle->x11.window, rect->width, rect->height, bpp); \ +\ + XPutImage(handle->x11.display, src_px, gc, src, 0, 0, 0, 0, pixmap->common.width, pixmap->common.height); \ +\ + src_pic = XRenderCreatePicture(handle->x11.display, src_px, fmt, render_mask, &attr); \ + dest_pic = XRenderCreatePicture(handle->x11.display, dest_px, fmt, render_mask, &attr); \ +\ + XRenderSetPictureTransform(handle->x11.display, src_pic, &m); \ + XRenderComposite(handle->x11.display, PictOpSrc, src_pic, 0, dest_pic, 0, 0, 0, 0, 0, 0, rect->width, rect->height); \ +\ + XRenderFreePicture(handle->x11.display, src_pic); \ + XRenderFreePicture(handle->x11.display, dest_pic); \ + XFreePixmap(handle->x11.display, src_px); \ + XFreeGC(handle->x11.display, gc); \ + } + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + if(rect->width <= 0 || rect->height <= 0 || pixmap->common.width <= 0 || pixmap->common.height <= 0) return; + if(rect->width >= INT16_MAX) rect->width = INT16_MAX; + if(rect->height >= INT16_MAX) rect->height = INT16_MAX; + +#ifdef USE_XRENDER + if(pixmap->x11.image != NULL && pixmap->x11.use_xrender) { + Pixmap px; + Pixmap mask, mask_tmp; + XRenderPictureAttributes attr; + XTransform m; + double xsc; + double ysc; + unsigned long render_mask = 0; + XImage* mask_tmp_img; + XImage* mask_img; + int y, x; + GC mask_gc; + + memset(&attr, 0, sizeof(attr)); + + xsc = (double)pixmap->common.width / rect->width; + ysc = (double)pixmap->common.height / rect->height; + + m.matrix[0][0] = XDoubleToFixed(xsc); + m.matrix[0][1] = XDoubleToFixed(0); + m.matrix[0][2] = XDoubleToFixed(0); + + m.matrix[1][0] = XDoubleToFixed(0); + m.matrix[1][1] = XDoubleToFixed(ysc); + m.matrix[1][2] = XDoubleToFixed(0); + + m.matrix[2][0] = XDoubleToFixed(0); + m.matrix[2][1] = XDoubleToFixed(0); + m.matrix[2][2] = XDoubleToFixed(1.0); + + DO_XRENDER(px, pixmap->x11.image, PictStandardRGB24, pixmap->x11.depth); + DO_XRENDER(mask_tmp, pixmap->x11.mask, PictStandardA8, 8); + + /* FIXME: this is terrible way to do this... i hope someone who knows xrender better than me + * gives me better solution + */ + mask_tmp_img = XGetImage(handle->x11.display, mask_tmp, 0, 0, rect->width, rect->height, 0xff, ZPixmap); + mask_img = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), 1, ZPixmap, 0, NULL, rect->width, rect->height, 32, 0); + mask = XCreatePixmap(handle->x11.display, handle->x11.window, rect->width, rect->height, 1); + mask_gc = XCreateGC(handle->x11.display, mask, 0, NULL); + + mask_img->data = malloc(mask_img->bytes_per_line * rect->height); + + for(y = 0; y < rect->height; y++) { + for(x = 0; x < rect->width; x++) { + unsigned long p = XGetPixel(mask_tmp_img, x, y); + if(p == 255) { + p = 1; + } else { + p = 0; + } + XPutPixel(mask_img, x, y, p); + } + } + XPutImage(handle->x11.display, mask, mask_gc, mask_img, 0, 0, 0, 0, rect->width, rect->height); + XFreeGC(handle->x11.display, mask_gc); + XDestroyImage(mask_img); + XDestroyImage(mask_tmp_img); + /* end terrible hack */ + + XSetClipMask(handle->x11.display, handle->x11.gc, mask); + XSetClipOrigin(handle->x11.display, handle->x11.gc, rect->x, rect->y); + XCopyArea(handle->x11.display, px, handle->x11.pixmap, handle->x11.gc, 0, 0, rect->width, rect->height, rect->x, rect->y); + XSetClipMask(handle->x11.display, handle->x11.gc, None); + + XFreePixmap(handle->x11.display, mask_tmp); + XFreePixmap(handle->x11.display, mask); + XFreePixmap(handle->x11.display, px); + } else +#endif + if(pixmap->x11.image != NULL) { + XImage* dest; + XImage* destmask; + Pixmap mask = XCreatePixmap(handle->x11.display, handle->x11.window, rect->width, rect->height, 1); + GC maskgc = XCreateGC(handle->x11.display, mask, 0, NULL); + char* di = malloc(rect->width * rect->height * 4); + char* dm = malloc(rect->width * rect->height * 4); + int y, x; + + dest = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), pixmap->x11.depth, ZPixmap, 0, di, rect->width, rect->height, 32, rect->width * 4); + destmask = XCreateImage(handle->x11.display, DefaultVisual(handle->x11.display, DefaultScreen(handle->x11.display)), 1, ZPixmap, 0, dm, rect->width, rect->height, 32, rect->width * 4); + + for(y = 0; y < (int)rect->height; y++) { + for(x = 0; x < (int)rect->width; x++) { + int sy = y * pixmap->common.height / rect->height; + int sx = x * pixmap->common.width / rect->width; + char* ipx; + char* opx; + sy = (int)sy; + sx = (int)sx; + + ipx = &pixmap->x11.image->data[(pixmap->common.width * sy + sx) * (pixmap->x11.image->bitmap_unit / 8)]; + opx = &di[(rect->width * y + x) * (pixmap->x11.image->bitmap_unit / 8)]; + memcpy(opx, ipx, pixmap->x11.image->bitmap_unit / 8); + + XPutPixel(destmask, x, y, XGetPixel(pixmap->x11.mask, sx, sy)); + } + } + + XPutImage(handle->x11.display, mask, maskgc, destmask, 0, 0, 0, 0, rect->width, rect->height); + + XSetClipMask(handle->x11.display, handle->x11.gc, mask); + XSetClipOrigin(handle->x11.display, handle->x11.gc, rect->x, rect->y); + XPutImage(handle->x11.display, handle->x11.pixmap, handle->x11.gc, dest, 0, 0, rect->x, rect->y, rect->width, rect->height); + XSetClipMask(handle->x11.display, handle->x11.gc, None); + + XDestroyImage(dest); + XDestroyImage(destmask); + + XFreeGC(handle->x11.display, maskgc); + XFreePixmap(handle->x11.display, mask); + } +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + unsigned long* icon = malloc((2 + pixmap->common.width * pixmap->common.height) * sizeof(*icon)); + int i; + Atom atom = XInternAtom(handle->x11.display, "_NET_WM_ICON", False); + + icon[0] = pixmap->common.width; + icon[1] = pixmap->common.height; + + for(i = 0; i < pixmap->common.width * pixmap->common.height; i++) { + icon[2 + i] = *(unsigned long*)(&pixmap->x11.data[i * sizeof(unsigned long)]); + } + + XChangeProperty(handle->x11.display, handle->x11.window, atom, 6, 32, PropModeReplace, (unsigned char*)icon, 2 + pixmap->common.width * pixmap->common.height); + + free(icon); +} + +static void MwLLForceRenderImpl(MwLL handle) { + if(!handle->x11.force_render) { + XEvent ev; + memset(&ev, 0, sizeof(ev)); + + ev.type = Expose; + ev.xexpose.window = handle->x11.window; + XSendEvent(handle->x11.display, handle->x11.window, False, ExposureMask, &ev); + + handle->x11.force_render = 1; + } +} + +Cursor MwLLX11CreateCursor(Display* display, MwCursor* image, MwCursor* mask) { + Cursor cur; + int y, x, ys, xs; + char* di = malloc(MwCursorDataHeight * MwCursorDataHeight * 4); + char* dm = malloc(MwCursorDataHeight * MwCursorDataHeight * 4); + XImage* cimage = XCreateImage(display, DefaultVisual(display, DefaultScreen(display)), 1, ZPixmap, 0, di, MwCursorDataHeight, MwCursorDataHeight, 32, MwCursorDataHeight * 4); + XImage* cmask = XCreateImage(display, DefaultVisual(display, DefaultScreen(display)), 1, ZPixmap, 0, dm, MwCursorDataHeight, MwCursorDataHeight, 32, MwCursorDataHeight * 4); + Pixmap pimage = XCreatePixmap(display, DefaultRootWindow(display), MwCursorDataHeight, MwCursorDataHeight, 1); + Pixmap pmask = XCreatePixmap(display, DefaultRootWindow(display), MwCursorDataHeight, MwCursorDataHeight, 1); + GC imagegc = XCreateGC(display, pimage, 0, NULL); + GC maskgc = XCreateGC(display, pmask, 0, NULL); + XColor cfg, cbg; + + xs = -mask->x + image->x; + ys = mask->height + mask->y; + ys = image->height + image->y - ys; + + if(ys < 0) ys = -ys; + + memset(cimage->data, 0, cimage->bytes_per_line * cimage->height); + memset(cmask->data, 0, cmask->bytes_per_line * cmask->height); + for(y = 0; y < mask->height; y++) { + unsigned int l = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + if(l & 1) { + XPutPixel(cmask, x, y, 1); + } + l = l >> 1; + } + } + for(y = 0; y < image->height; y++) { + unsigned int l = image->data[y]; + for(x = image->width - 1; x >= 0; x--) { + int px = 0; + if(l & 1) px = 1; + XPutPixel(cimage, xs + x, ys + y, px); + + l = l >> 1; + } + } + + cfg.red = 65535; + cfg.green = 65535; + cfg.blue = 65535; + XAllocColor(display, DefaultColormap(display, DefaultScreen(display)), &cfg); + + cbg.red = 0; + cbg.green = 0; + cbg.blue = 0; + XAllocColor(display, DefaultColormap(display, DefaultScreen(display)), &cbg); + + XPutImage(display, pimage, imagegc, cimage, 0, 0, 0, 0, MwCursorDataHeight, MwCursorDataHeight); + XPutImage(display, pmask, maskgc, cmask, 0, 0, 0, 0, MwCursorDataHeight, MwCursorDataHeight); + + cur = XCreatePixmapCursor(display, pimage, pmask, &cfg, &cbg, xs - image->x, ys + (MwCursorDataHeight + image->y)); + + XFreePixmap(display, pimage); + XFreePixmap(display, pmask); + + XDestroyImage(cimage); + XDestroyImage(cmask); + + XFreeGC(display, imagegc); + XFreeGC(display, maskgc); + + return cur; +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + Cursor cur = MwLLX11CreateCursor(handle->x11.display, image, mask); + + XDefineCursor(handle->x11.display, handle->x11.window, cur); + XFreeCursor(handle->x11.display, cur); +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + int x = 0, y = 0; + Window child, root, parent; + Window* children; + unsigned int nchild; + XWindowAttributes xwa; + + handle->x11.top = 1; + + XQueryTree(handle->x11.display, handle->x11.window, &root, &parent, &children, &nchild); + if(children != NULL) XFree(children); + + XTranslateCoordinates(handle->x11.display, parent, RootWindow(handle->x11.display, DefaultScreen(handle->x11.display)), 0, 0, &x, &y, &child); + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &xwa); + + XReparentWindow(handle->x11.display, handle->x11.window, RootWindow(handle->x11.display, DefaultScreen(handle->x11.display)), x + point->x, y + point->y); + + if(xwa.map_state == IsViewable) { + sync_move(handle, x + point->x, y + point->y); + } +} + +static void MwLLShowImpl(MwLL handle, int show) { + if(show) { + wait_map(handle, 1); + +#ifndef ALLOW_SLOPPY_FOCUS + XSetInputFocus(handle->x11.display, handle->x11.window, RevertToNone, CurrentTime); +#endif + } else { + wait_unmap(handle, 1); + } +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + Atom wndtype = XInternAtom(handle->x11.display, "_NET_WM_WINDOW_TYPE", False); + Atom wnddlg = XInternAtom(handle->x11.display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + Atom wndstate = XInternAtom(handle->x11.display, "_NET_WM_STATE", False); + Atom wndmodal = XInternAtom(handle->x11.display, "_NET_WM_STATE_MODAL", False); + + if(parent != NULL) XSetTransientForHint(handle->x11.display, handle->x11.window, parent->x11.window); + XChangeProperty(handle->x11.display, handle->x11.window, wndtype, XA_ATOM, 32, PropModeReplace, (unsigned char*)&wnddlg, 1); + XChangeProperty(handle->x11.display, handle->x11.window, wndstate, XA_ATOM, 32, PropModeReplace, (unsigned char*)&wndmodal, 1); +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { + XSizeHints* hints = XAllocSizeHints(); + long ret; + + XGetWMSizeHints(handle->x11.display, handle->x11.window, hints, &ret, XA_WM_NORMAL_HINTS); + + hints->flags |= PMinSize | PMaxSize; + hints->min_width = minx; + hints->min_height = miny; + hints->max_width = maxx; + hints->max_height = maxy; + XSetWMSizeHints(handle->x11.display, handle->x11.window, hints, XA_WM_NORMAL_HINTS); + XFree(hints); +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + Atom atom = XInternAtom(handle->x11.display, "_MOTIF_WM_HINTS", 0); + mwm_hints_t hints; + + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = toggle ? 0 : 1; + XChangeProperty(handle->x11.display, handle->x11.window, atom, atom, 32, PropModeReplace, (unsigned char*)&hints, 5); +} + +static void MwLLFocusImpl(MwLL handle) { + XSetInputFocus(handle->x11.display, handle->x11.window, RevertToNone, CurrentTime); +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + XWindowAttributes attr; + + XGetWindowAttributes(handle->x11.display, handle->x11.window, &attr); + + if(toggle) { + handle->x11.grabbed = 1; + + XWarpPointer(handle->x11.display, None, handle->x11.window, 0, 0, 0, 0, attr.width / 2, attr.height / 2); + } else { + handle->x11.grabbed = 0; + } +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + /* TODO */ + + (void)handle; + (void)text; + (void)clipboard_type; +} + +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + (void)clipboard_type; + + if(handle->x11.clipboard_pending) return; + + XConvertSelection(handle->x11.display, handle->x11.clipboard, handle->x11.utf8_string, handle->x11.selection, handle->x11.window, CurrentTime); + + handle->x11.clipboard_pending = 1; + handle->x11.clipboard_time = MwTimeGetTick(); +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { + XSetWindowAttributes xswa; + Atom wndtype = XInternAtom(handle->x11.display, "_NET_WM_WINDOW_TYPE", False); + Atom wndmenu = XInternAtom(handle->x11.display, "_NET_WM_WINDOW_TYPE_MENU", False); + + xswa.override_redirect = True; + + XChangeWindowAttributes(handle->x11.display, handle->x11.window, CWOverrideRedirect, &xswa); + XChangeProperty(handle->x11.display, handle->x11.window, wndtype, XA_ATOM, 32, PropModeReplace, (unsigned char*)&wndmenu, 1); +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + Window root, child; + int rx, ry, wx, wy; + unsigned int m; + + XQueryPointer(handle->x11.display, DefaultRootWindow(handle->x11.display), &root, &child, &rx, &ry, &wx, &wy, &m); + + point->x = rx; + point->y = ry; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + XWindowAttributes xwa; + XGetWindowAttributes(handle->x11.display, DefaultRootWindow(handle->x11.display), &xwa); + + rect->x = rect->y = 0; + rect->width = xwa.width; + rect->height = xwa.height; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + MwLLShow(handle, 0); +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLLShow(handle, 1); +} + +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + +static void MwLLRaiseImpl(MwLL handle) { + XRaiseWindow(handle->x11.display, handle->x11.window); +} + +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + if(rect == NULL) { + XSetClipMask(handle->x11.display, handle->x11.gc, None); + } else { + XRectangle rc; + + rc.x = 0; + rc.y = 0; + rc.width = rect->width; + rc.height = rect->height; + + XSetClipRectangles(handle->x11.display, handle->x11.gc, rect->x, rect->y, &rc, 1, Unsorted); + } +} + +static int MwLLX11CallInitImpl(void) { + MwBool loadX11 = MwFALSE; + if(getenv("MILSKO_BACKEND")) { + loadX11 |= + (strcmp(getenv("MILSKO_BACKEND"), "x11") == 0); + } else if(getenv("DISPLAY")) { + loadX11 |= (getenv("DISPLAY") != NULL); + } + + if(!loadX11) { + return 1; + } + +#ifdef __APPLE__ + xsymtbl.lib_xlib = MwDynamicOpen("libX11.dylib"); +#else + xsymtbl.lib_xlib = MwDynamicOpen("libX11.so"); +#endif + if(!xsymtbl.lib_xlib) { + return 1; + } + + xsymtbl.has_xrender = MwFALSE; +#if USE_XRENDER + xsymtbl.lib_xrender = MwDynamicOpen("libXrender.so"); + if(xsymtbl.lib_xrender) { + xsymtbl.has_xrender = MwTRUE; + } +#endif + +#define X11_FUNC_LOAD(x) x = MwDynamicSymbol(xsymtbl.lib_xlib, #x) + + X11_FUNC_LOAD(XClearWindow); + X11_FUNC_LOAD(XCreateImage); + X11_FUNC_LOAD(XOpenDisplay); + X11_FUNC_LOAD(XKeysymToString); + X11_FUNC_LOAD(XInternAtom); + X11_FUNC_LOAD(XCreatePixmapCursor); + X11_FUNC_LOAD(XCreateGC); + X11_FUNC_LOAD(XCreatePixmap); + X11_FUNC_LOAD(XCreateSimpleWindow); + X11_FUNC_LOAD(XVisualIDFromVisual); + X11_FUNC_LOAD(XRootWindow); + X11_FUNC_LOAD(XSetWMProtocols); + X11_FUNC_LOAD(XSetTransientForHint); + X11_FUNC_LOAD(XAllocColor); + X11_FUNC_LOAD(XChangeProperty); + X11_FUNC_LOAD(XChangeWindowAttributes); + X11_FUNC_LOAD(XCheckTypedWindowEvent); + X11_FUNC_LOAD(XCheckWindowEvent); + X11_FUNC_LOAD(XCloseDisplay); + X11_FUNC_LOAD(XConfigureWindow); + X11_FUNC_LOAD(XConvertSelection); + X11_FUNC_LOAD(XCopyArea); + X11_FUNC_LOAD(XDefaultScreen); + X11_FUNC_LOAD(XDefineCursor); + X11_FUNC_LOAD(XDeleteProperty); + X11_FUNC_LOAD(XDestroyWindow); + X11_FUNC_LOAD(XDrawLine); + X11_FUNC_LOAD(XFillPolygon); + X11_FUNC_LOAD(XFree); + X11_FUNC_LOAD(XFreeCursor); + X11_FUNC_LOAD(XFreeGC); + X11_FUNC_LOAD(XFreePixmap); + X11_FUNC_LOAD(XGetGeometry); + X11_FUNC_LOAD(XGetWindowProperty); + X11_FUNC_LOAD(XGetWindowAttributes); + X11_FUNC_LOAD(XMapWindow); + X11_FUNC_LOAD(XNextEvent); + X11_FUNC_LOAD(XPending); + X11_FUNC_LOAD(XPutBackEvent); + X11_FUNC_LOAD(XPutImage); + X11_FUNC_LOAD(XQueryPointer); + X11_FUNC_LOAD(XQueryTree); + X11_FUNC_LOAD(XReparentWindow); + X11_FUNC_LOAD(XSelectInput); + X11_FUNC_LOAD(XSendEvent); + X11_FUNC_LOAD(XSetClipMask); + X11_FUNC_LOAD(XSetClipOrigin); + X11_FUNC_LOAD(XSetClipRectangles); + X11_FUNC_LOAD(XSetForeground); + X11_FUNC_LOAD(XSetGraphicsExposures); + X11_FUNC_LOAD(XSetInputFocus); + X11_FUNC_LOAD(XSetWindowBackgroundPixmap); + X11_FUNC_LOAD(XSync); + X11_FUNC_LOAD(XTranslateCoordinates); + X11_FUNC_LOAD(XUnmapWindow); + X11_FUNC_LOAD(XWarpPointer); + X11_FUNC_LOAD(XSetLocaleModifiers); + X11_FUNC_LOAD(XOpenIM); + X11_FUNC_LOAD(XCloseIM); + X11_FUNC_LOAD(XCreateIC); + X11_FUNC_LOAD(XDestroyIC); + X11_FUNC_LOAD(XSetICFocus); + X11_FUNC_LOAD(XGetImage); + X11_FUNC_LOAD(XRaiseWindow); + + X11_FUNC_LOAD(XAllocSizeHints); + X11_FUNC_LOAD(XGetVisualInfo); + X11_FUNC_LOAD(XGetWMNormalHints); + X11_FUNC_LOAD(XGetWMSizeHints); + X11_FUNC_LOAD(XLookupString); + X11_FUNC_LOAD(XSetStandardProperties); + X11_FUNC_LOAD(XSetWMNormalHints); + X11_FUNC_LOAD(XSetWMSizeHints); + +#if USE_XRENDER +#define XRENDER_FUNC_LOAD(x) x = MwDynamicSymbol(xsymtbl.lib_xrender, #x); + + XRENDER_FUNC_LOAD(XRenderQueryExtension) + XRENDER_FUNC_LOAD(XRenderFindStandardFormat) + XRENDER_FUNC_LOAD(XRenderCreatePicture) + XRENDER_FUNC_LOAD(XRenderFreePicture) + XRENDER_FUNC_LOAD(XRenderSetPictureTransform) + XRENDER_FUNC_LOAD(XRenderComposite) +#endif + +#ifdef USE_DBUS + xsymtbl.has_dbus = MwLLDBusFuncSetup(&xsymtbl.dbus); +#endif + return 0; +} + +#include "call.c" +CALL(X11); diff --git a/widget/milsko/milskosrc/src/color.c b/widget/milsko/milskosrc/src/color.c new file mode 100644 index 0000000000..ae3667ed59 --- /dev/null +++ b/widget/milsko/milskosrc/src/color.c @@ -0,0 +1,815 @@ +#include + +#include "../external/stb_ds.h" + +struct color { + char* key; + MwU32 value; +}; + +static struct color* colors = NULL; + +MwLLColor MwParseColorName(MwWidget handle, const char* color) { + MwRGB rgb; + MwParseColorNameNoAllocate(color, &rgb); + return MwLLAllocColor(handle->lowlevel, rgb.red, rgb.green, rgb.blue); +} + +void MwParseColorNameNoAllocate(const char* color, MwRGB* rgb) { + MwU32 v = shget(colors, color); + rgb->red = (v >> 16) & 0xff; + rgb->green = (v >> 8) & 0xff; + rgb->blue = (v >> 0) & 0xff; +} + +static void add_color(const char* name, int red, int green, int blue) { + MwU32 v = (red << 16) | (green << 8) | (blue << 0); + shput(colors, name, v); +} + +void MwColorTableInit(void) { + sh_new_strdup(colors); + shdefault(colors, 0); + add_color("snow", 255, 250, 250); + add_color("ghost white", 248, 248, 255); + add_color("GhostWhite", 248, 248, 255); + add_color("white smoke", 245, 245, 245); + add_color("WhiteSmoke", 245, 245, 245); + add_color("gainsboro", 220, 220, 220); + add_color("floral white", 255, 250, 240); + add_color("FloralWhite", 255, 250, 240); + add_color("old lace", 253, 245, 230); + add_color("OldLace", 253, 245, 230); + add_color("linen", 250, 240, 230); + add_color("antique white", 250, 235, 215); + add_color("AntiqueWhite", 250, 235, 215); + add_color("papaya whip", 255, 239, 213); + add_color("PapayaWhip", 255, 239, 213); + add_color("blanched almond", 255, 235, 205); + add_color("BlanchedAlmond", 255, 235, 205); + add_color("bisque", 255, 228, 196); + add_color("peach puff", 255, 218, 185); + add_color("PeachPuff", 255, 218, 185); + add_color("navajo white", 255, 222, 173); + add_color("NavajoWhite", 255, 222, 173); + add_color("moccasin", 255, 228, 181); + add_color("cornsilk", 255, 248, 220); + add_color("ivory", 255, 255, 240); + add_color("lemon chiffon", 255, 250, 205); + add_color("LemonChiffon", 255, 250, 205); + add_color("seashell", 255, 245, 238); + add_color("honeydew", 240, 255, 240); + add_color("mint cream", 245, 255, 250); + add_color("MintCream", 245, 255, 250); + add_color("azure", 240, 255, 255); + add_color("alice blue", 240, 248, 255); + add_color("AliceBlue", 240, 248, 255); + add_color("lavender", 230, 230, 250); + add_color("lavender blush", 255, 240, 245); + add_color("LavenderBlush", 255, 240, 245); + add_color("misty rose", 255, 228, 225); + add_color("MistyRose", 255, 228, 225); + add_color("white", 255, 255, 255); + add_color("black", 0, 0, 0); + add_color("dark slate gray", 47, 79, 79); + add_color("DarkSlateGray", 47, 79, 79); + add_color("dark slate grey", 47, 79, 79); + add_color("DarkSlateGrey", 47, 79, 79); + add_color("dim gray", 105, 105, 105); + add_color("DimGray", 105, 105, 105); + add_color("dim grey", 105, 105, 105); + add_color("DimGrey", 105, 105, 105); + add_color("slate gray", 112, 128, 144); + add_color("SlateGray", 112, 128, 144); + add_color("slate grey", 112, 128, 144); + add_color("SlateGrey", 112, 128, 144); + add_color("light slate gray", 119, 136, 153); + add_color("LightSlateGray", 119, 136, 153); + add_color("light slate grey", 119, 136, 153); + add_color("LightSlateGrey", 119, 136, 153); + add_color("gray", 190, 190, 190); + add_color("grey", 190, 190, 190); + add_color("x11 gray", 190, 190, 190); + add_color("X11Gray", 190, 190, 190); + add_color("x11 grey", 190, 190, 190); + add_color("X11Grey", 190, 190, 190); + add_color("web gray", 128, 128, 128); + add_color("WebGray", 128, 128, 128); + add_color("web grey", 128, 128, 128); + add_color("WebGrey", 128, 128, 128); + add_color("light grey", 211, 211, 211); + add_color("LightGrey", 211, 211, 211); + add_color("light gray", 211, 211, 211); + add_color("LightGray", 211, 211, 211); + add_color("midnight blue", 25, 25, 112); + add_color("MidnightBlue", 25, 25, 112); + add_color("navy", 0, 0, 128); + add_color("navy blue", 0, 0, 128); + add_color("NavyBlue", 0, 0, 128); + add_color("cornflower blue", 100, 149, 237); + add_color("CornflowerBlue", 100, 149, 237); + add_color("dark slate blue", 72, 61, 139); + add_color("DarkSlateBlue", 72, 61, 139); + add_color("slate blue", 106, 90, 205); + add_color("SlateBlue", 106, 90, 205); + add_color("medium slate blue", 123, 104, 238); + add_color("MediumSlateBlue", 123, 104, 238); + add_color("light slate blue", 132, 112, 255); + add_color("LightSlateBlue", 132, 112, 255); + add_color("medium blue", 0, 0, 205); + add_color("MediumBlue", 0, 0, 205); + add_color("royal blue", 65, 105, 225); + add_color("RoyalBlue", 65, 105, 225); + add_color("blue", 0, 0, 255); + add_color("dodger blue", 30, 144, 255); + add_color("DodgerBlue", 30, 144, 255); + add_color("deep sky blue", 0, 191, 255); + add_color("DeepSkyBlue", 0, 191, 255); + add_color("sky blue", 135, 206, 235); + add_color("SkyBlue", 135, 206, 235); + add_color("light sky blue", 135, 206, 250); + add_color("LightSkyBlue", 135, 206, 250); + add_color("steel blue", 70, 130, 180); + add_color("SteelBlue", 70, 130, 180); + add_color("light steel blue", 176, 196, 222); + add_color("LightSteelBlue", 176, 196, 222); + add_color("light blue", 173, 216, 230); + add_color("LightBlue", 173, 216, 230); + add_color("powder blue", 176, 224, 230); + add_color("PowderBlue", 176, 224, 230); + add_color("pale turquoise", 175, 238, 238); + add_color("PaleTurquoise", 175, 238, 238); + add_color("dark turquoise", 0, 206, 209); + add_color("DarkTurquoise", 0, 206, 209); + add_color("medium turquoise", 72, 209, 204); + add_color("MediumTurquoise", 72, 209, 204); + add_color("turquoise", 64, 224, 208); + add_color("cyan", 0, 255, 255); + add_color("aqua", 0, 255, 255); + add_color("light cyan", 224, 255, 255); + add_color("LightCyan", 224, 255, 255); + add_color("cadet blue", 95, 158, 160); + add_color("CadetBlue", 95, 158, 160); + add_color("medium aquamarine", 102, 205, 170); + add_color("MediumAquamarine", 102, 205, 170); + add_color("aquamarine", 127, 255, 212); + add_color("dark green", 0, 100, 0); + add_color("DarkGreen", 0, 100, 0); + add_color("dark olive green", 85, 107, 47); + add_color("DarkOliveGreen", 85, 107, 47); + add_color("dark sea green", 143, 188, 143); + add_color("DarkSeaGreen", 143, 188, 143); + add_color("sea green", 46, 139, 87); + add_color("SeaGreen", 46, 139, 87); + add_color("medium sea green", 60, 179, 113); + add_color("MediumSeaGreen", 60, 179, 113); + add_color("light sea green", 32, 178, 170); + add_color("LightSeaGreen", 32, 178, 170); + add_color("pale green", 152, 251, 152); + add_color("PaleGreen", 152, 251, 152); + add_color("spring green", 0, 255, 127); + add_color("SpringGreen", 0, 255, 127); + add_color("lawn green", 124, 252, 0); + add_color("LawnGreen", 124, 252, 0); + add_color("green", 0, 255, 0); + add_color("lime", 0, 255, 0); + add_color("x11 green", 0, 255, 0); + add_color("X11Green", 0, 255, 0); + add_color("web green", 0, 128, 0); + add_color("WebGreen", 0, 128, 0); + add_color("chartreuse", 127, 255, 0); + add_color("medium spring green", 0, 250, 154); + add_color("MediumSpringGreen", 0, 250, 154); + add_color("green yellow", 173, 255, 47); + add_color("GreenYellow", 173, 255, 47); + add_color("lime green", 50, 205, 50); + add_color("LimeGreen", 50, 205, 50); + add_color("yellow green", 154, 205, 50); + add_color("YellowGreen", 154, 205, 50); + add_color("forest green", 34, 139, 34); + add_color("ForestGreen", 34, 139, 34); + add_color("olive drab", 107, 142, 35); + add_color("OliveDrab", 107, 142, 35); + add_color("dark khaki", 189, 183, 107); + add_color("DarkKhaki", 189, 183, 107); + add_color("khaki", 240, 230, 140); + add_color("pale goldenrod", 238, 232, 170); + add_color("PaleGoldenrod", 238, 232, 170); + add_color("light goldenrod yellow", 250, 250, 210); + add_color("LightGoldenrodYellow", 250, 250, 210); + add_color("light yellow", 255, 255, 224); + add_color("LightYellow", 255, 255, 224); + add_color("yellow", 255, 255, 0); + add_color("gold", 255, 215, 0); + add_color("light goldenrod", 238, 221, 130); + add_color("LightGoldenrod", 238, 221, 130); + add_color("goldenrod", 218, 165, 32); + add_color("dark goldenrod", 184, 134, 11); + add_color("DarkGoldenrod", 184, 134, 11); + add_color("rosy brown", 188, 143, 143); + add_color("RosyBrown", 188, 143, 143); + add_color("indian red", 205, 92, 92); + add_color("IndianRed", 205, 92, 92); + add_color("saddle brown", 139, 69, 19); + add_color("SaddleBrown", 139, 69, 19); + add_color("sienna", 160, 82, 45); + add_color("peru", 205, 133, 63); + add_color("burlywood", 222, 184, 135); + add_color("beige", 245, 245, 220); + add_color("wheat", 245, 222, 179); + add_color("sandy brown", 244, 164, 96); + add_color("SandyBrown", 244, 164, 96); + add_color("tan", 210, 180, 140); + add_color("chocolate", 210, 105, 30); + add_color("firebrick", 178, 34, 34); + add_color("brown", 165, 42, 42); + add_color("dark salmon", 233, 150, 122); + add_color("DarkSalmon", 233, 150, 122); + add_color("salmon", 250, 128, 114); + add_color("light salmon", 255, 160, 122); + add_color("LightSalmon", 255, 160, 122); + add_color("orange", 255, 165, 0); + add_color("dark orange", 255, 140, 0); + add_color("DarkOrange", 255, 140, 0); + add_color("coral", 255, 127, 80); + add_color("light coral", 240, 128, 128); + add_color("LightCoral", 240, 128, 128); + add_color("tomato", 255, 99, 71); + add_color("orange red", 255, 69, 0); + add_color("OrangeRed", 255, 69, 0); + add_color("red", 255, 0, 0); + add_color("hot pink", 255, 105, 180); + add_color("HotPink", 255, 105, 180); + add_color("deep pink", 255, 20, 147); + add_color("DeepPink", 255, 20, 147); + add_color("pink", 255, 192, 203); + add_color("light pink", 255, 182, 193); + add_color("LightPink", 255, 182, 193); + add_color("pale violet red", 219, 112, 147); + add_color("PaleVioletRed", 219, 112, 147); + add_color("maroon", 176, 48, 96); + add_color("x11 maroon", 176, 48, 96); + add_color("X11Maroon", 176, 48, 96); + add_color("web maroon", 128, 0, 0); + add_color("WebMaroon", 128, 0, 0); + add_color("medium violet red", 199, 21, 133); + add_color("MediumVioletRed", 199, 21, 133); + add_color("violet red", 208, 32, 144); + add_color("VioletRed", 208, 32, 144); + add_color("magenta", 255, 0, 255); + add_color("fuchsia", 255, 0, 255); + add_color("violet", 238, 130, 238); + add_color("plum", 221, 160, 221); + add_color("orchid", 218, 112, 214); + add_color("medium orchid", 186, 85, 211); + add_color("MediumOrchid", 186, 85, 211); + add_color("dark orchid", 153, 50, 204); + add_color("DarkOrchid", 153, 50, 204); + add_color("dark violet", 148, 0, 211); + add_color("DarkViolet", 148, 0, 211); + add_color("blue violet", 138, 43, 226); + add_color("BlueViolet", 138, 43, 226); + add_color("purple", 160, 32, 240); + add_color("x11 purple", 160, 32, 240); + add_color("X11Purple", 160, 32, 240); + add_color("web purple", 128, 0, 128); + add_color("WebPurple", 128, 0, 128); + add_color("medium purple", 147, 112, 219); + add_color("MediumPurple", 147, 112, 219); + add_color("thistle", 216, 191, 216); + add_color("snow1", 255, 250, 250); + add_color("snow2", 238, 233, 233); + add_color("snow3", 205, 201, 201); + add_color("snow4", 139, 137, 137); + add_color("seashell1", 255, 245, 238); + add_color("seashell2", 238, 229, 222); + add_color("seashell3", 205, 197, 191); + add_color("seashell4", 139, 134, 130); + add_color("AntiqueWhite1", 255, 239, 219); + add_color("AntiqueWhite2", 238, 223, 204); + add_color("AntiqueWhite3", 205, 192, 176); + add_color("AntiqueWhite4", 139, 131, 120); + add_color("bisque1", 255, 228, 196); + add_color("bisque2", 238, 213, 183); + add_color("bisque3", 205, 183, 158); + add_color("bisque4", 139, 125, 107); + add_color("PeachPuff1", 255, 218, 185); + add_color("PeachPuff2", 238, 203, 173); + add_color("PeachPuff3", 205, 175, 149); + add_color("PeachPuff4", 139, 119, 101); + add_color("NavajoWhite1", 255, 222, 173); + add_color("NavajoWhite2", 238, 207, 161); + add_color("NavajoWhite3", 205, 179, 139); + add_color("NavajoWhite4", 139, 121, 94); + add_color("LemonChiffon1", 255, 250, 205); + add_color("LemonChiffon2", 238, 233, 191); + add_color("LemonChiffon3", 205, 201, 165); + add_color("LemonChiffon4", 139, 137, 112); + add_color("cornsilk1", 255, 248, 220); + add_color("cornsilk2", 238, 232, 205); + add_color("cornsilk3", 205, 200, 177); + add_color("cornsilk4", 139, 136, 120); + add_color("ivory1", 255, 255, 240); + add_color("ivory2", 238, 238, 224); + add_color("ivory3", 205, 205, 193); + add_color("ivory4", 139, 139, 131); + add_color("honeydew1", 240, 255, 240); + add_color("honeydew2", 224, 238, 224); + add_color("honeydew3", 193, 205, 193); + add_color("honeydew4", 131, 139, 131); + add_color("LavenderBlush1", 255, 240, 245); + add_color("LavenderBlush2", 238, 224, 229); + add_color("LavenderBlush3", 205, 193, 197); + add_color("LavenderBlush4", 139, 131, 134); + add_color("MistyRose1", 255, 228, 225); + add_color("MistyRose2", 238, 213, 210); + add_color("MistyRose3", 205, 183, 181); + add_color("MistyRose4", 139, 125, 123); + add_color("azure1", 240, 255, 255); + add_color("azure2", 224, 238, 238); + add_color("azure3", 193, 205, 205); + add_color("azure4", 131, 139, 139); + add_color("SlateBlue1", 131, 111, 255); + add_color("SlateBlue2", 122, 103, 238); + add_color("SlateBlue3", 105, 89, 205); + add_color("SlateBlue4", 71, 60, 139); + add_color("RoyalBlue1", 72, 118, 255); + add_color("RoyalBlue2", 67, 110, 238); + add_color("RoyalBlue3", 58, 95, 205); + add_color("RoyalBlue4", 39, 64, 139); + add_color("blue1", 0, 0, 255); + add_color("blue2", 0, 0, 238); + add_color("blue3", 0, 0, 205); + add_color("blue4", 0, 0, 139); + add_color("DodgerBlue1", 30, 144, 255); + add_color("DodgerBlue2", 28, 134, 238); + add_color("DodgerBlue3", 24, 116, 205); + add_color("DodgerBlue4", 16, 78, 139); + add_color("SteelBlue1", 99, 184, 255); + add_color("SteelBlue2", 92, 172, 238); + add_color("SteelBlue3", 79, 148, 205); + add_color("SteelBlue4", 54, 100, 139); + add_color("DeepSkyBlue1", 0, 191, 255); + add_color("DeepSkyBlue2", 0, 178, 238); + add_color("DeepSkyBlue3", 0, 154, 205); + add_color("DeepSkyBlue4", 0, 104, 139); + add_color("SkyBlue1", 135, 206, 255); + add_color("SkyBlue2", 126, 192, 238); + add_color("SkyBlue3", 108, 166, 205); + add_color("SkyBlue4", 74, 112, 139); + add_color("LightSkyBlue1", 176, 226, 255); + add_color("LightSkyBlue2", 164, 211, 238); + add_color("LightSkyBlue3", 141, 182, 205); + add_color("LightSkyBlue4", 96, 123, 139); + add_color("SlateGray1", 198, 226, 255); + add_color("SlateGray2", 185, 211, 238); + add_color("SlateGray3", 159, 182, 205); + add_color("SlateGray4", 108, 123, 139); + add_color("LightSteelBlue1", 202, 225, 255); + add_color("LightSteelBlue2", 188, 210, 238); + add_color("LightSteelBlue3", 162, 181, 205); + add_color("LightSteelBlue4", 110, 123, 139); + add_color("LightBlue1", 191, 239, 255); + add_color("LightBlue2", 178, 223, 238); + add_color("LightBlue3", 154, 192, 205); + add_color("LightBlue4", 104, 131, 139); + add_color("LightCyan1", 224, 255, 255); + add_color("LightCyan2", 209, 238, 238); + add_color("LightCyan3", 180, 205, 205); + add_color("LightCyan4", 122, 139, 139); + add_color("PaleTurquoise1", 187, 255, 255); + add_color("PaleTurquoise2", 174, 238, 238); + add_color("PaleTurquoise3", 150, 205, 205); + add_color("PaleTurquoise4", 102, 139, 139); + add_color("CadetBlue1", 152, 245, 255); + add_color("CadetBlue2", 142, 229, 238); + add_color("CadetBlue3", 122, 197, 205); + add_color("CadetBlue4", 83, 134, 139); + add_color("turquoise1", 0, 245, 255); + add_color("turquoise2", 0, 229, 238); + add_color("turquoise3", 0, 197, 205); + add_color("turquoise4", 0, 134, 139); + add_color("cyan1", 0, 255, 255); + add_color("cyan2", 0, 238, 238); + add_color("cyan3", 0, 205, 205); + add_color("cyan4", 0, 139, 139); + add_color("DarkSlateGray1", 151, 255, 255); + add_color("DarkSlateGray2", 141, 238, 238); + add_color("DarkSlateGray3", 121, 205, 205); + add_color("DarkSlateGray4", 82, 139, 139); + add_color("aquamarine1", 127, 255, 212); + add_color("aquamarine2", 118, 238, 198); + add_color("aquamarine3", 102, 205, 170); + add_color("aquamarine4", 69, 139, 116); + add_color("DarkSeaGreen1", 193, 255, 193); + add_color("DarkSeaGreen2", 180, 238, 180); + add_color("DarkSeaGreen3", 155, 205, 155); + add_color("DarkSeaGreen4", 105, 139, 105); + add_color("SeaGreen1", 84, 255, 159); + add_color("SeaGreen2", 78, 238, 148); + add_color("SeaGreen3", 67, 205, 128); + add_color("SeaGreen4", 46, 139, 87); + add_color("PaleGreen1", 154, 255, 154); + add_color("PaleGreen2", 144, 238, 144); + add_color("PaleGreen3", 124, 205, 124); + add_color("PaleGreen4", 84, 139, 84); + add_color("SpringGreen1", 0, 255, 127); + add_color("SpringGreen2", 0, 238, 118); + add_color("SpringGreen3", 0, 205, 102); + add_color("SpringGreen4", 0, 139, 69); + add_color("green1", 0, 255, 0); + add_color("green2", 0, 238, 0); + add_color("green3", 0, 205, 0); + add_color("green4", 0, 139, 0); + add_color("chartreuse1", 127, 255, 0); + add_color("chartreuse2", 118, 238, 0); + add_color("chartreuse3", 102, 205, 0); + add_color("chartreuse4", 69, 139, 0); + add_color("OliveDrab1", 192, 255, 62); + add_color("OliveDrab2", 179, 238, 58); + add_color("OliveDrab3", 154, 205, 50); + add_color("OliveDrab4", 105, 139, 34); + add_color("DarkOliveGreen1", 202, 255, 112); + add_color("DarkOliveGreen2", 188, 238, 104); + add_color("DarkOliveGreen3", 162, 205, 90); + add_color("DarkOliveGreen4", 110, 139, 61); + add_color("khaki1", 255, 246, 143); + add_color("khaki2", 238, 230, 133); + add_color("khaki3", 205, 198, 115); + add_color("khaki4", 139, 134, 78); + add_color("LightGoldenrod1", 255, 236, 139); + add_color("LightGoldenrod2", 238, 220, 130); + add_color("LightGoldenrod3", 205, 190, 112); + add_color("LightGoldenrod4", 139, 129, 76); + add_color("LightYellow1", 255, 255, 224); + add_color("LightYellow2", 238, 238, 209); + add_color("LightYellow3", 205, 205, 180); + add_color("LightYellow4", 139, 139, 122); + add_color("yellow1", 255, 255, 0); + add_color("yellow2", 238, 238, 0); + add_color("yellow3", 205, 205, 0); + add_color("yellow4", 139, 139, 0); + add_color("gold1", 255, 215, 0); + add_color("gold2", 238, 201, 0); + add_color("gold3", 205, 173, 0); + add_color("gold4", 139, 117, 0); + add_color("goldenrod1", 255, 193, 37); + add_color("goldenrod2", 238, 180, 34); + add_color("goldenrod3", 205, 155, 29); + add_color("goldenrod4", 139, 105, 20); + add_color("DarkGoldenrod1", 255, 185, 15); + add_color("DarkGoldenrod2", 238, 173, 14); + add_color("DarkGoldenrod3", 205, 149, 12); + add_color("DarkGoldenrod4", 139, 101, 8); + add_color("RosyBrown1", 255, 193, 193); + add_color("RosyBrown2", 238, 180, 180); + add_color("RosyBrown3", 205, 155, 155); + add_color("RosyBrown4", 139, 105, 105); + add_color("IndianRed1", 255, 106, 106); + add_color("IndianRed2", 238, 99, 99); + add_color("IndianRed3", 205, 85, 85); + add_color("IndianRed4", 139, 58, 58); + add_color("sienna1", 255, 130, 71); + add_color("sienna2", 238, 121, 66); + add_color("sienna3", 205, 104, 57); + add_color("sienna4", 139, 71, 38); + add_color("burlywood1", 255, 211, 155); + add_color("burlywood2", 238, 197, 145); + add_color("burlywood3", 205, 170, 125); + add_color("burlywood4", 139, 115, 85); + add_color("wheat1", 255, 231, 186); + add_color("wheat2", 238, 216, 174); + add_color("wheat3", 205, 186, 150); + add_color("wheat4", 139, 126, 102); + add_color("tan1", 255, 165, 79); + add_color("tan2", 238, 154, 73); + add_color("tan3", 205, 133, 63); + add_color("tan4", 139, 90, 43); + add_color("chocolate1", 255, 127, 36); + add_color("chocolate2", 238, 118, 33); + add_color("chocolate3", 205, 102, 29); + add_color("chocolate4", 139, 69, 19); + add_color("firebrick1", 255, 48, 48); + add_color("firebrick2", 238, 44, 44); + add_color("firebrick3", 205, 38, 38); + add_color("firebrick4", 139, 26, 26); + add_color("brown1", 255, 64, 64); + add_color("brown2", 238, 59, 59); + add_color("brown3", 205, 51, 51); + add_color("brown4", 139, 35, 35); + add_color("salmon1", 255, 140, 105); + add_color("salmon2", 238, 130, 98); + add_color("salmon3", 205, 112, 84); + add_color("salmon4", 139, 76, 57); + add_color("LightSalmon1", 255, 160, 122); + add_color("LightSalmon2", 238, 149, 114); + add_color("LightSalmon3", 205, 129, 98); + add_color("LightSalmon4", 139, 87, 66); + add_color("orange1", 255, 165, 0); + add_color("orange2", 238, 154, 0); + add_color("orange3", 205, 133, 0); + add_color("orange4", 139, 90, 0); + add_color("DarkOrange1", 255, 127, 0); + add_color("DarkOrange2", 238, 118, 0); + add_color("DarkOrange3", 205, 102, 0); + add_color("DarkOrange4", 139, 69, 0); + add_color("coral1", 255, 114, 86); + add_color("coral2", 238, 106, 80); + add_color("coral3", 205, 91, 69); + add_color("coral4", 139, 62, 47); + add_color("tomato1", 255, 99, 71); + add_color("tomato2", 238, 92, 66); + add_color("tomato3", 205, 79, 57); + add_color("tomato4", 139, 54, 38); + add_color("OrangeRed1", 255, 69, 0); + add_color("OrangeRed2", 238, 64, 0); + add_color("OrangeRed3", 205, 55, 0); + add_color("OrangeRed4", 139, 37, 0); + add_color("red1", 255, 0, 0); + add_color("red2", 238, 0, 0); + add_color("red3", 205, 0, 0); + add_color("red4", 139, 0, 0); + add_color("DeepPink1", 255, 20, 147); + add_color("DeepPink2", 238, 18, 137); + add_color("DeepPink3", 205, 16, 118); + add_color("DeepPink4", 139, 10, 80); + add_color("HotPink1", 255, 110, 180); + add_color("HotPink2", 238, 106, 167); + add_color("HotPink3", 205, 96, 144); + add_color("HotPink4", 139, 58, 98); + add_color("pink1", 255, 181, 197); + add_color("pink2", 238, 169, 184); + add_color("pink3", 205, 145, 158); + add_color("pink4", 139, 99, 108); + add_color("LightPink1", 255, 174, 185); + add_color("LightPink2", 238, 162, 173); + add_color("LightPink3", 205, 140, 149); + add_color("LightPink4", 139, 95, 101); + add_color("PaleVioletRed1", 255, 130, 171); + add_color("PaleVioletRed2", 238, 121, 159); + add_color("PaleVioletRed3", 205, 104, 137); + add_color("PaleVioletRed4", 139, 71, 93); + add_color("maroon1", 255, 52, 179); + add_color("maroon2", 238, 48, 167); + add_color("maroon3", 205, 41, 144); + add_color("maroon4", 139, 28, 98); + add_color("VioletRed1", 255, 62, 150); + add_color("VioletRed2", 238, 58, 140); + add_color("VioletRed3", 205, 50, 120); + add_color("VioletRed4", 139, 34, 82); + add_color("magenta1", 255, 0, 255); + add_color("magenta2", 238, 0, 238); + add_color("magenta3", 205, 0, 205); + add_color("magenta4", 139, 0, 139); + add_color("orchid1", 255, 131, 250); + add_color("orchid2", 238, 122, 233); + add_color("orchid3", 205, 105, 201); + add_color("orchid4", 139, 71, 137); + add_color("plum1", 255, 187, 255); + add_color("plum2", 238, 174, 238); + add_color("plum3", 205, 150, 205); + add_color("plum4", 139, 102, 139); + add_color("MediumOrchid1", 224, 102, 255); + add_color("MediumOrchid2", 209, 95, 238); + add_color("MediumOrchid3", 180, 82, 205); + add_color("MediumOrchid4", 122, 55, 139); + add_color("DarkOrchid1", 191, 62, 255); + add_color("DarkOrchid2", 178, 58, 238); + add_color("DarkOrchid3", 154, 50, 205); + add_color("DarkOrchid4", 104, 34, 139); + add_color("purple1", 155, 48, 255); + add_color("purple2", 145, 44, 238); + add_color("purple3", 125, 38, 205); + add_color("purple4", 85, 26, 139); + add_color("MediumPurple1", 171, 130, 255); + add_color("MediumPurple2", 159, 121, 238); + add_color("MediumPurple3", 137, 104, 205); + add_color("MediumPurple4", 93, 71, 139); + add_color("thistle1", 255, 225, 255); + add_color("thistle2", 238, 210, 238); + add_color("thistle3", 205, 181, 205); + add_color("thistle4", 139, 123, 139); + add_color("gray0", 0, 0, 0); + add_color("grey0", 0, 0, 0); + add_color("gray1", 3, 3, 3); + add_color("grey1", 3, 3, 3); + add_color("gray2", 5, 5, 5); + add_color("grey2", 5, 5, 5); + add_color("gray3", 8, 8, 8); + add_color("grey3", 8, 8, 8); + add_color("gray4", 10, 10, 10); + add_color("grey4", 10, 10, 10); + add_color("gray5", 13, 13, 13); + add_color("grey5", 13, 13, 13); + add_color("gray6", 15, 15, 15); + add_color("grey6", 15, 15, 15); + add_color("gray7", 18, 18, 18); + add_color("grey7", 18, 18, 18); + add_color("gray8", 20, 20, 20); + add_color("grey8", 20, 20, 20); + add_color("gray9", 23, 23, 23); + add_color("grey9", 23, 23, 23); + add_color("gray10", 26, 26, 26); + add_color("grey10", 26, 26, 26); + add_color("gray11", 28, 28, 28); + add_color("grey11", 28, 28, 28); + add_color("gray12", 31, 31, 31); + add_color("grey12", 31, 31, 31); + add_color("gray13", 33, 33, 33); + add_color("grey13", 33, 33, 33); + add_color("gray14", 36, 36, 36); + add_color("grey14", 36, 36, 36); + add_color("gray15", 38, 38, 38); + add_color("grey15", 38, 38, 38); + add_color("gray16", 41, 41, 41); + add_color("grey16", 41, 41, 41); + add_color("gray17", 43, 43, 43); + add_color("grey17", 43, 43, 43); + add_color("gray18", 46, 46, 46); + add_color("grey18", 46, 46, 46); + add_color("gray19", 48, 48, 48); + add_color("grey19", 48, 48, 48); + add_color("gray20", 51, 51, 51); + add_color("grey20", 51, 51, 51); + add_color("gray21", 54, 54, 54); + add_color("grey21", 54, 54, 54); + add_color("gray22", 56, 56, 56); + add_color("grey22", 56, 56, 56); + add_color("gray23", 59, 59, 59); + add_color("grey23", 59, 59, 59); + add_color("gray24", 61, 61, 61); + add_color("grey24", 61, 61, 61); + add_color("gray25", 64, 64, 64); + add_color("grey25", 64, 64, 64); + add_color("gray26", 66, 66, 66); + add_color("grey26", 66, 66, 66); + add_color("gray27", 69, 69, 69); + add_color("grey27", 69, 69, 69); + add_color("gray28", 71, 71, 71); + add_color("grey28", 71, 71, 71); + add_color("gray29", 74, 74, 74); + add_color("grey29", 74, 74, 74); + add_color("gray30", 77, 77, 77); + add_color("grey30", 77, 77, 77); + add_color("gray31", 79, 79, 79); + add_color("grey31", 79, 79, 79); + add_color("gray32", 82, 82, 82); + add_color("grey32", 82, 82, 82); + add_color("gray33", 84, 84, 84); + add_color("grey33", 84, 84, 84); + add_color("gray34", 87, 87, 87); + add_color("grey34", 87, 87, 87); + add_color("gray35", 89, 89, 89); + add_color("grey35", 89, 89, 89); + add_color("gray36", 92, 92, 92); + add_color("grey36", 92, 92, 92); + add_color("gray37", 94, 94, 94); + add_color("grey37", 94, 94, 94); + add_color("gray38", 97, 97, 97); + add_color("grey38", 97, 97, 97); + add_color("gray39", 99, 99, 99); + add_color("grey39", 99, 99, 99); + add_color("gray40", 102, 102, 102); + add_color("grey40", 102, 102, 102); + add_color("gray41", 105, 105, 105); + add_color("grey41", 105, 105, 105); + add_color("gray42", 107, 107, 107); + add_color("grey42", 107, 107, 107); + add_color("gray43", 110, 110, 110); + add_color("grey43", 110, 110, 110); + add_color("gray44", 112, 112, 112); + add_color("grey44", 112, 112, 112); + add_color("gray45", 115, 115, 115); + add_color("grey45", 115, 115, 115); + add_color("gray46", 117, 117, 117); + add_color("grey46", 117, 117, 117); + add_color("gray47", 120, 120, 120); + add_color("grey47", 120, 120, 120); + add_color("gray48", 122, 122, 122); + add_color("grey48", 122, 122, 122); + add_color("gray49", 125, 125, 125); + add_color("grey49", 125, 125, 125); + add_color("gray50", 127, 127, 127); + add_color("grey50", 127, 127, 127); + add_color("gray51", 130, 130, 130); + add_color("grey51", 130, 130, 130); + add_color("gray52", 133, 133, 133); + add_color("grey52", 133, 133, 133); + add_color("gray53", 135, 135, 135); + add_color("grey53", 135, 135, 135); + add_color("gray54", 138, 138, 138); + add_color("grey54", 138, 138, 138); + add_color("gray55", 140, 140, 140); + add_color("grey55", 140, 140, 140); + add_color("gray56", 143, 143, 143); + add_color("grey56", 143, 143, 143); + add_color("gray57", 145, 145, 145); + add_color("grey57", 145, 145, 145); + add_color("gray58", 148, 148, 148); + add_color("grey58", 148, 148, 148); + add_color("gray59", 150, 150, 150); + add_color("grey59", 150, 150, 150); + add_color("gray60", 153, 153, 153); + add_color("grey60", 153, 153, 153); + add_color("gray61", 156, 156, 156); + add_color("grey61", 156, 156, 156); + add_color("gray62", 158, 158, 158); + add_color("grey62", 158, 158, 158); + add_color("gray63", 161, 161, 161); + add_color("grey63", 161, 161, 161); + add_color("gray64", 163, 163, 163); + add_color("grey64", 163, 163, 163); + add_color("gray65", 166, 166, 166); + add_color("grey65", 166, 166, 166); + add_color("gray66", 168, 168, 168); + add_color("grey66", 168, 168, 168); + add_color("gray67", 171, 171, 171); + add_color("grey67", 171, 171, 171); + add_color("gray68", 173, 173, 173); + add_color("grey68", 173, 173, 173); + add_color("gray69", 176, 176, 176); + add_color("grey69", 176, 176, 176); + add_color("gray70", 179, 179, 179); + add_color("grey70", 179, 179, 179); + add_color("gray71", 181, 181, 181); + add_color("grey71", 181, 181, 181); + add_color("gray72", 184, 184, 184); + add_color("grey72", 184, 184, 184); + add_color("gray73", 186, 186, 186); + add_color("grey73", 186, 186, 186); + add_color("gray74", 189, 189, 189); + add_color("grey74", 189, 189, 189); + add_color("gray75", 191, 191, 191); + add_color("grey75", 191, 191, 191); + add_color("gray76", 194, 194, 194); + add_color("grey76", 194, 194, 194); + add_color("gray77", 196, 196, 196); + add_color("grey77", 196, 196, 196); + add_color("gray78", 199, 199, 199); + add_color("grey78", 199, 199, 199); + add_color("gray79", 201, 201, 201); + add_color("grey79", 201, 201, 201); + add_color("gray80", 204, 204, 204); + add_color("grey80", 204, 204, 204); + add_color("gray81", 207, 207, 207); + add_color("grey81", 207, 207, 207); + add_color("gray82", 209, 209, 209); + add_color("grey82", 209, 209, 209); + add_color("gray83", 212, 212, 212); + add_color("grey83", 212, 212, 212); + add_color("gray84", 214, 214, 214); + add_color("grey84", 214, 214, 214); + add_color("gray85", 217, 217, 217); + add_color("grey85", 217, 217, 217); + add_color("gray86", 219, 219, 219); + add_color("grey86", 219, 219, 219); + add_color("gray87", 222, 222, 222); + add_color("grey87", 222, 222, 222); + add_color("gray88", 224, 224, 224); + add_color("grey88", 224, 224, 224); + add_color("gray89", 227, 227, 227); + add_color("grey89", 227, 227, 227); + add_color("gray90", 229, 229, 229); + add_color("grey90", 229, 229, 229); + add_color("gray91", 232, 232, 232); + add_color("grey91", 232, 232, 232); + add_color("gray92", 235, 235, 235); + add_color("grey92", 235, 235, 235); + add_color("gray93", 237, 237, 237); + add_color("grey93", 237, 237, 237); + add_color("gray94", 240, 240, 240); + add_color("grey94", 240, 240, 240); + add_color("gray95", 242, 242, 242); + add_color("grey95", 242, 242, 242); + add_color("gray96", 245, 245, 245); + add_color("grey96", 245, 245, 245); + add_color("gray97", 247, 247, 247); + add_color("grey97", 247, 247, 247); + add_color("gray98", 250, 250, 250); + add_color("grey98", 250, 250, 250); + add_color("gray99", 252, 252, 252); + add_color("grey99", 252, 252, 252); + add_color("gray100", 255, 255, 255); + add_color("grey100", 255, 255, 255); + add_color("dark grey", 169, 169, 169); + add_color("DarkGrey", 169, 169, 169); + add_color("dark gray", 169, 169, 169); + add_color("DarkGray", 169, 169, 169); + add_color("dark blue", 0, 0, 139); + add_color("DarkBlue", 0, 0, 139); + add_color("dark cyan", 0, 139, 139); + add_color("DarkCyan", 0, 139, 139); + add_color("dark magenta", 139, 0, 139); + add_color("DarkMagenta", 139, 0, 139); + add_color("dark red", 139, 0, 0); + add_color("DarkRed", 139, 0, 0); + add_color("light green", 144, 238, 144); + add_color("LightGreen", 144, 238, 144); + add_color("crimson", 220, 20, 60); + add_color("indigo", 75, 0, 130); + add_color("olive", 128, 128, 0); + add_color("rebecca purple", 102, 51, 153); + add_color("RebeccaPurple", 102, 51, 153); + add_color("silver", 192, 192, 192); + add_color("teal", 0, 128, 128); +} diff --git a/widget/milsko/milskosrc/src/core.c b/widget/milsko/milskosrc/src/core.c new file mode 100644 index 0000000000..7059840f62 --- /dev/null +++ b/widget/milsko/milskosrc/src/core.c @@ -0,0 +1,1211 @@ +#include + +#include "../external/stb_ds.h" + +#ifdef USE_COCOA +#define PERIODIC +#endif + +#define RESIZE_ON_TICK + +#define DRAW(handle) \ + { \ + MwLLBeginDraw(handle->lowlevel); \ +\ + handle->bgcolor = NULL; \ + MwDispatch(handle, draw); \ + if(handle->draw_inject != NULL) handle->draw_inject(handle); \ + MwDispatchUserHandler(handle, MwNdrawHandler, NULL); \ +\ + MwLLEndDraw(handle->lowlevel); \ + } + +#define RESIZE(handle) \ + { \ + int RESIZE_i; \ + MwDispatchUserHandler(handle, MwNresizeHandler, NULL); \ + for(RESIZE_i = 0; RESIZE_i < arrlen(handle->children); RESIZE_i++) { \ + MwDispatch(handle->children[RESIZE_i], parent_resize); \ + } \ + MwDispatch(handle, resize); \ + } + +static void MWAPI MwVaListApply_Internal(MwWidget handle, va_list va, int only_early); +static MwWidget MWAPI MwCreateWidget_Internal(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, int do_prop, va_list prop); + +static void lldrawhandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; +#ifdef PERIODIC + MwWidget top; +#endif + + (void)data; + +#ifdef PERIODIC + top = h; + while(top != NULL) { + if(top->top_step) { + break; + } + + top = top->parent; + } + + if(top == NULL) { + DRAW(h); /* fallback */ + } else { + int i; + + for(i = 0; i < arrlen(top->draw_queue); i++) { + if(top->draw_queue[i] == h) break; + } + if(i == arrlen(top->draw_queue)) arrput(top->draw_queue, h); + } +#else + DRAW(h); +#endif +} + +static void lluphandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + MwMouse* p = data; + if(MwGetInteger(h, MwNdisabled) == 1) return; + + if(p->button == MwMOUSE_LEFT) h->pressed = 0; + h->mouse_point.x = p->point.x; + h->mouse_point.y = p->point.y; + + if(p->button == MwMOUSE_LEFT) MwDispatch(h, click); + MwDispatch3(h, mouse_up, data); + MwDispatchUserHandler(h, MwNmouseUpHandler, data); +} + +static void lldownhandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + MwMouse* p = data; + if(MwGetInteger(h, MwNdisabled) == 1) return; + + if(p->button == MwMOUSE_LEFT) h->pressed = 1; + h->mouse_point.x = p->point.x; + h->mouse_point.y = p->point.y; + + MwDispatch3(h, mouse_down, data); + MwDispatchUserHandler(h, MwNmouseDownHandler, data); +} + +static void llresizehandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; +#ifdef RESIZE_ON_TICK + MwWidget top; +#endif + + (void)data; + +#ifdef RESIZE_ON_TICK + top = h; + while(top != NULL) { + if(top->top_step) { + break; + } + + top = top->parent; + } + + if(top == NULL) { + RESIZE(h); /* fallback */ + } else { + int i; + + for(i = 0; i < arrlen(top->resize_queue); i++) { + if(top->resize_queue[i] == h) break; + } + if(i == arrlen(top->resize_queue)) arrput(top->resize_queue, h); + } +#else + RESIZE(h); +#endif +} + +static void llclosehandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + int n; + + (void)data; + + if((n = MwGetInteger(h, MwNmain)) != MwDEFAULT && n) { + while(h != NULL) { + h->close = 1; + MwDispatchUserHandler(h, MwNcloseHandler, NULL); + h = h->parent; + } + } else { + h->close = 1; + MwDispatchUserHandler(h, MwNcloseHandler, NULL); + } +} + +static void llmovehandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + MwPoint* p = data; + h->mouse_point.x = p->x; + h->mouse_point.y = p->y; + + MwDispatch(h, mouse_move); + MwDispatchUserHandler(h, MwNmouseMoveHandler, data); +} + +static void llkeyhandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + int key = *(int*)data; + if(MwGetInteger(h, MwNdisabled) == 1) return; + + MwDispatch3(h, key, key); + MwDispatchUserHandler(h, MwNkeyHandler, data); +} + +static void llkeyrelhandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; + + MwDispatchUserHandler(h, MwNkeyReleaseHandler, data); +} + +static void llfocusinhandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; + + MwDispatchUserHandler(h, MwNfocusInHandler, data); +} + +static void llfocusouthandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; + + MwDispatchUserHandler(h, MwNfocusOutHandler, data); +} + +static void llclipboardhandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + if(MwGetInteger(h, MwNdisabled) == 1) return; + + MwDispatch3(h, clipboard, data); + MwDispatchUserHandler(h, MwNclipboardHandler, data); +} + +/* if both of them are true + * 1. widget class is not NULL + * 2. parent is NULL + * or parent's widget class is NULL + * + * most likely this widget is first *visible* widget + * + * this macro is not used anywhere else - we could expose it if we have to + * + * (nishi) + */ +#define IsFirstVisible(handle) ((handle)->widget_class != NULL && ((handle)->parent == NULL || (handle)->parent->widget_class == NULL)) + +static void lldarkthemehandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + int* ptr = data; + int s; + + if(h->widget_class == MwWindowClass && (shgeti(h->integer, MwNdarkTheme) == -1 || ((s = MwGetInteger(h, MwNdarkThemeAutomatic)) != MwDEFAULT && s))) { + if(MwGetInteger(h, MwNmodernLook)) { + MwVaApply(h, + MwNdarkTheme, *ptr, + MwNdarkThemeAutomatic, 1, + NULL); + + MwDispatchUserHandler(h, MwNdarkThemeHandler, data); + } + } +} + +static MwWidget MwCreateWidget_Internal(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, int do_prop, va_list prop) { + MwWidget h = malloc(sizeof(*h)); + + if(name) + h->name = MwStringDuplicate(name); + else + h->name = NULL; + + h->parent = parent; + h->children = NULL; + + if(widget_class != NULL) { + if((h->lowlevel = MwLLCreate(parent == NULL ? NULL : parent->lowlevel, x, y, width, height)) == NULL) { + if(h->name) { + free(h->name); + } + free(h); + return NULL; + } + } else { + h->lowlevel = NULL; + } + h->widget_class = widget_class; + h->pressed = 0; + h->close = 0; + h->destroy_queue = NULL; + h->prop_event = 1; + h->draw_inject = NULL; + h->destroy_inject = NULL; + h->tick_list = NULL; + h->destroyed = 0; + h->bgcolor = NULL; + + h->berserk = 0; + h->last_tick = MwTimeGetTick(); + + h->internal = NULL; + h->opaque = NULL; + h->user = NULL; + + h->top_step = 0; + h->draw_queue = NULL; + h->resize_queue = NULL; + h->monitored_entries = NULL; + + if(parent == NULL) arrput(h->tick_list, h); + + if(parent == NULL) h->top_step = 1; + + if(h->lowlevel != NULL) { + h->lowlevel->common.user = h; + h->lowlevel->common.handler->draw = lldrawhandler; + h->lowlevel->common.handler->up = lluphandler; + h->lowlevel->common.handler->down = lldownhandler; + h->lowlevel->common.handler->resize = llresizehandler; + h->lowlevel->common.handler->close = llclosehandler; + h->lowlevel->common.handler->move = llmovehandler; + h->lowlevel->common.handler->key = llkeyhandler; + h->lowlevel->common.handler->key_released = llkeyrelhandler; + h->lowlevel->common.handler->focus_in = llfocusinhandler; + h->lowlevel->common.handler->focus_out = llfocusouthandler; + h->lowlevel->common.handler->clipboard = llclipboardhandler; + h->lowlevel->common.handler->dark_theme = lldarkthemehandler; + } + + if(parent != NULL) arrput(parent->children, h); + + sh_new_strdup(h->text); + sh_new_strdup(h->integer); + sh_new_strdup(h->handler); + sh_new_strdup(h->data); + + shdefault(h->integer, MwDEFAULT); + shdefault(h->text, NULL); + shdefault(h->handler, NULL); + shdefault(h->data, NULL); + + if(do_prop) MwVaListApply_Internal(h, prop, 1); + + h->prop_event = 0; + if(MwDispatch2(h, create) != 0) { + h->widget_class = NULL; + MwDestroyWidget(h); + return NULL; + } + if(h->widget_class == NULL) { + MwSetDefault(h); + } + h->prop_event = 1; + + if(h->widget_class != NULL && h->widget_class->tick != NULL) { + MwAddTickList(h); + } + +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) + if(IsFirstVisible(h)) { + font_setup: + h->root_font = MwFontLoad(MwTTFData, MwTTFDataSize); + h->root_boldfont = MwFontLoad(MwBoldTTFData, MwBoldTTFDataSize); + h->root_monofont = MwFontLoad(MwMonospaceTTFData, MwMonospaceTTFDataSize); + h->root_boldmonofont = MwFontLoad(MwBoldMonospaceTTFData, MwBoldMonospaceTTFDataSize); + if(!h->root_font) { +#ifdef USE_STB_TRUETYPE + MwFL_STBTTSetup(); + goto font_setup; +#endif + } + } else +#endif + { + h->root_font = NULL; + h->root_boldfont = NULL; + h->root_monofont = NULL; + h->root_boldmonofont = NULL; + } + + if(h->parent != NULL) MwDispatch4(h->parent, children_update, h, 1); + + return h; +} + +MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { + va_list dummy; + + memset(&dummy, 0, sizeof(dummy)); + + return MwCreateWidget_Internal(widget_class, name, parent, x, y, width, height, 0, dummy); +} + +MwWidget MwVaCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, ...) { + MwWidget h; + va_list va; + + va_start(va, height); + h = MwVaListCreateWidget(widget_class, name, parent, x, y, width, height, va); + va_end(va); + + return h; +} + +MwWidget MwVaListCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, va_list va) { + MwWidget h; + va_list va2; + +#ifdef va_copy + va_copy(va2, va); +#else + va2 = va; +#endif + + h = MwCreateWidget_Internal(widget_class, name, parent, x, y, width, height, 1, va); + MwVaListApply(h, va2); + + va_end(va2); + + return h; +} + +void MwFreeWidget(MwWidget handle) { + int i; + MwWidget root = handle; + MwWidget w; + + w = handle; + while(w != NULL) { + if(w->top_step) break; + w = w->parent; + } + + if(w != NULL) { + for(i = 0; i < arrlen(w->draw_queue); i++) { + if(w->draw_queue[i] == handle) { + arrdel(w->draw_queue, i); + i--; + } + } + } + + handle->destroyed = 0; + if(handle->destroy_inject != NULL) handle->destroy_inject(handle); + MwDispatch(handle, destroy); + + for(i = 0; i < arrlen(handle->children); i++) { + MwFreeWidget(handle->children[i]); + } + arrfree(handle->children); + + while(root->parent != NULL) root = root->parent; + for(i = 0; i < arrlen(root->tick_list); i++) { + if(handle == root->tick_list[i]) { + arrdel(root->tick_list, i); + i--; + } + } + + if(handle->name) free(handle->name); + + if(handle->lowlevel != NULL) MwLLDestroy(handle->lowlevel); + + shfree(handle->integer); + + for(i = 0; i < shlen(handle->text); i++) { + free(handle->text[i].value); + handle->text[i].value = NULL; + } + shfree(handle->text); + for(i = 0; i < shlen(handle->handler); i++) { + arrfree(handle->handler[i].value); + } + shfree(handle->handler); + shfree(handle->data); + + arrfree(handle->destroy_queue); + arrfree(handle->tick_list); + + arrfree(handle->draw_queue); + arrfree(handle->resize_queue); + + if(handle->root_font != NULL) MwFontFree(handle->root_font); + if(handle->root_boldfont != NULL) MwFontFree(handle->root_boldfont); + if(handle->root_monofont != NULL) MwFontFree(handle->root_monofont); + if(handle->root_boldmonofont != NULL) MwFontFree(handle->root_boldmonofont); + + free(handle); +} + +static void destroy_children(MwWidget handle) { + int i; + for(i = 0; i < arrlen(handle->children); i++) { + destroy_children(handle->children[i]); + } + handle->destroyed = 1; +} + +void MwDestroyWidget(MwWidget handle) { + if(handle->destroyed) return; + + if(handle->parent != NULL) { + int i; + for(i = 0; i < arrlen(handle->parent->destroy_queue); i++) { + if(handle->parent->destroy_queue[i] == handle) break; + } + if(i == arrlen(handle->parent->destroy_queue)) { + arrput(handle->parent->destroy_queue, handle); + } + + MwDispatch4(handle->parent, children_update, handle, 0); + } + destroy_children(handle); + handle->destroyed = 1; +} + +void MwVaWidgetExecute(MwWidget handle, const char* func_name, void* out, ...) { + va_list args; + va_start(args, out); + MwVaListWidgetExecute(handle, func_name, out, args); + va_end(args); +} + +void MwVaListWidgetExecute(MwWidget handle, const char* func_name, void* out, va_list va) { + if(handle->widget_class->execute != NULL) { + handle->widget_class->execute(handle, func_name, out, va); + } +} + +static void clean_destroy_queue(MwWidget handle) { + int i, j; + for(i = 0; i < arrlen(handle->destroy_queue); i++) { + MwWidget w = handle->destroy_queue[i]; + + MwFreeWidget(w); + } + for(i = 0; i < arrlen(handle->destroy_queue); i++) { + for(j = 0; j < arrlen(handle->children); j++) { + if(handle->children[j] == handle->destroy_queue[i]) { + arrdel(handle->children, j); + break; + } + } + } + arrfree(handle->destroy_queue); +} + +static void MwAfterStep(MwWidget handle) { + int i; + +#ifdef PERIODIC + if(handle->top_step) { + for(i = 0; i < arrlen(handle->draw_queue); i++) { + DRAW(handle->draw_queue[i]); + } + + arrfree(handle->draw_queue); + } +#endif + +#ifdef RESIZE_ON_TICK + if(handle->top_step) { + for(i = 0; i < arrlen(handle->resize_queue); i++) { + RESIZE(handle->resize_queue[i]); + } + + arrfree(handle->resize_queue); + } +#endif + + if(arrlen(handle->tick_list) > 0 && (MwTimeGetTick() - handle->last_tick) >= (MwGetInteger(handle, MwNwaitMS) == MwDEFAULT ? MwWaitMS : MwGetInteger(handle, MwNwaitMS))) { + for(i = 0; i < arrlen(handle->tick_list); i++) { + MwDispatch(handle->tick_list[i], tick); + MwDispatchUserHandler(handle->tick_list[i], MwNtickHandler, NULL); + } + + handle->last_tick = MwTimeGetTick(); + } +} + +int MwStep(MwWidget handle) { + int i; + MwWidget* widgets = NULL; + for(i = 0; i < arrlen(handle->children); i++) { + arrput(widgets, handle->children[i]); + } + for(i = 0; i < arrlen(widgets); i++) MwStep(widgets[i]); + + arrfree(widgets); + + handle->prop_event = 0; + + while(handle->lowlevel != NULL && MwLLPending(handle->lowlevel)) + MwLLNextEvent(handle->lowlevel); + + handle->prop_event = 1; + + if(handle->top_step) MwAfterStep(handle); + + clean_destroy_queue(handle); + if(handle->parent == NULL && handle->destroyed) { + MwFreeWidget(handle); + return 1; + } + return 0; +} + +int MwPending(MwWidget handle) { + int i; + for(i = 0; i < arrlen(handle->children); i++) { + if(MwPending(handle->children[i])) return 1; + } + return (arrlen(handle->tick_list) > 0 && (MwTimeGetTick() - handle->last_tick) >= (MwGetInteger(handle, MwNwaitMS) == MwDEFAULT ? MwWaitMS : MwGetInteger(handle, MwNwaitMS))) || (arrlen(handle->destroy_queue) > 0) || (handle->widget_class == NULL ? 0 : MwLLPending(handle->lowlevel)); +} + +void MwLoop(MwWidget handle) { + long tick = MwTimeGetTick(); + long wait = MwGetInteger(handle, MwNwaitMS); + long over = 0; + if(wait == MwDEFAULT) wait = MwWaitMS; + while(!handle->close) { + int v = 0; + long t, t2; + long more; + while(MwPending(handle)) { + if((v = MwStep(handle)) != 0) break; + } + if(v != 0) break; + + more = over % (wait / 2); + t = (tick + wait - more) - (t2 = MwTimeGetTick()); + if(t > 0) { + if(!handle->berserk) MwTimeSleep(t); + tick = MwTimeGetTick(); + over -= more; + } else { + tick = t2; + over += -t; + } + } +} + +static void force_render_all(MwWidget handle) { + int i; + for(i = 0; i < arrlen(handle->children); i++) { + force_render_all(handle->children[i]); + } + if(handle->lowlevel != NULL) MwForceRender(handle); +} + +void MwSetInteger(MwWidget handle, const char* key, int n) { + int xy; + int wh = 0; + if((xy = ((strcmp(key, MwNx) == 0 || strcmp(key, MwNy) == 0) ? 1 : 0)) || (wh = ((strcmp(key, MwNwidth) == 0 || strcmp(key, MwNheight) == 0)) ? 1 : 0)) { + int x, y; + unsigned int w, h; + + MwLLGetXYWH(handle->lowlevel, &x, &y, &w, &h); + if(strcmp(key, MwNx) == 0) x = n; + if(strcmp(key, MwNy) == 0) y = n; + if(strcmp(key, MwNwidth) == 0) w = n; + if(strcmp(key, MwNheight) == 0) h = n; + if(xy) MwLLSetXY(handle->lowlevel, x, y); + if(wh) MwLLSetWH(handle->lowlevel, w, h); + } else { + shput(handle->integer, key, n); + } + if(handle->prop_event) { + char** keys = NULL; + + arrput(keys, (char*)key); + arrput(keys, NULL); + MwDispatch3(handle, props_change, keys); + arrfree(keys); + + MwDispatch3(handle, prop_change, key); + } + + if(handle->parent != NULL && handle->parent->prop_event) { + if(handle->parent != NULL) MwDispatch4(handle->parent, children_prop_change, handle, key); + } + + if(strcmp(key, MwNforceInverted) == 0) { + MwForceRender(handle); + } + if(strcmp(key, MwNmodernLook) == 0 || strcmp(key, MwNdarkTheme) == 0 || strcmp(key, MwNbitmapFont) == 0) { + force_render_all(handle); + } + + if(strcmp(key, MwNdarkTheme) == 0) { + MwWidget h = handle; + + shdel(h->integer, MwNdarkThemeAutomatic); + + if(h->widget_class != MwWindowClass) { + while(h->parent != NULL && h->parent->widget_class != MwWindowClass) h = h->parent; + } + + if(h->lowlevel != NULL) MwLLSetDarkTheme(h->lowlevel, n); + } +} + +void MwSetText(MwWidget handle, const char* key, const char* value) { + if(handle->widget_class == MwWindowClass && strcmp(key, MwNtitle) == 0) { + MwLLSetTitle(handle->lowlevel, value); + } else { + char* v = value == NULL ? NULL : MwStringDuplicate(value); + + if(shgeti(handle->text, key) != -1) free(shget(handle->text, key)); + + if(value != NULL) { + shput(handle->text, key, v); + } else { + shdel(handle->text, key); + } + } + if(handle->prop_event) { + char** keys = NULL; + + arrput(keys, (char*)key); + arrput(keys, NULL); + MwDispatch3(handle, props_change, keys); + arrfree(keys); + + MwDispatch3(handle, prop_change, key); + } + + if(handle->parent != NULL && handle->parent->prop_event) { + if(handle->parent != NULL) MwDispatch4(handle->parent, children_prop_change, handle, key); + } + + if(strcmp(key, MwNbackground) == 0 || strcmp(key, MwNforeground) == 0 || strcmp(key, MwNsubBackground) == 0 || strcmp(key, MwNsubForeground) == 0) { + MwForceRender(handle); + } +} + +void MwSetVoid(MwWidget handle, const char* key, void* value) { + if(IsFirstVisible(handle) && strcmp(key, MwNiconPixmap) == 0) { + MwLLSetIcon(handle->lowlevel, value); + } else if(strcmp(key, MwNsizeHints) == 0) { + MwSizeHints* sz = value; + + MwLLBeginStateChange(handle->lowlevel); + MwLLSetSizeHints(handle->lowlevel, sz->min_width, sz->min_height, sz->max_width, sz->max_height); + MwLLEndStateChange(handle->lowlevel); + } else { + shput(handle->data, key, value); + } + if(handle->prop_event) { + char** keys = NULL; + + arrput(keys, (char*)key); + arrput(keys, NULL); + MwDispatch3(handle, props_change, keys); + arrfree(keys); + + MwDispatch3(handle, prop_change, key); + } + + if(handle->parent != NULL && handle->parent->prop_event) { + if(handle->parent != NULL) MwDispatch4(handle->parent, children_prop_change, handle, key); + } +} + +static int inherit_integer(MwWidget handle, const char* key, int default_v) { + int v; + + if(handle->parent != NULL && (v = MwGetInteger(handle->parent, key)) != MwDEFAULT) { + return v; + } + return default_v; +} + +int MwGetInteger(MwWidget handle, const char* key) { + if(strcmp(key, MwNx) == 0 || strcmp(key, MwNy) == 0 || strcmp(key, MwNwidth) == 0 || strcmp(key, MwNheight) == 0) { + int x, y; + unsigned int w, h; + + MwLLGetXYWH(handle->lowlevel, &x, &y, &w, &h); + + if(strcmp(key, MwNx) == 0) return x; + if(strcmp(key, MwNy) == 0) return y; + if(strcmp(key, MwNwidth) == 0) return w; + if(strcmp(key, MwNheight) == 0) return h; + return MwDEFAULT; + } else { + if(shgeti(handle->integer, key) == -1) { +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) + if(strcmp(key, MwNbitmapFont) == 0) return inherit_integer(handle, key, 0); +#else + if(strcmp(key, MwNbitmapFont) == 0) return inherit_integer(handle, key, 1); +#endif +#ifdef USE_CLASSIC_THEME + if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, 0); +#else + if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, MwLLDoModern(handle->lowlevel)); +#endif + if(strcmp(key, MwNdarkTheme) == 0) return inherit_integer(handle, key, 0); + if(strcmp(key, MwNuseMonospace) == 0) return inherit_integer(handle, key, 0); + if(strcmp(key, MwNdisabled) == 0) return inherit_integer(handle, key, 0); + } + return shget(handle->integer, key); + } +} + +const char* MwGetText(MwWidget handle, const char* key) { + if((shgeti(handle->text, key) == -1 || strcmp(shget(handle->text, key), "DEFAULT") == 0) && (strcmp(key, MwNbackground) == 0 || strcmp(key, MwNforeground) == 0 || strcmp(key, MwNsubBackground) == 0 || strcmp(key, MwNsubForeground) == 0 || strcmp(key, MwNtitleBackground) == 0 || strcmp(key, MwNtitleForeground) == 0)) { + const char* v = NULL; + if(shgeti(handle->text, key) != -1 && strcmp(shget(handle->text, key), "DEFAULT") != 0) { + MwWidget h = handle->parent; + while(h != NULL) { + if((v = MwGetText(h, key)) != NULL) break; + h = h->parent; + } + } + if(v == NULL) { + if(MwGetInteger(handle, MwNdarkTheme)) { + if(strcmp(key, MwNbackground) == 0) return MwDefaultDarkBackground; + if(strcmp(key, MwNforeground) == 0) return MwDefaultDarkForeground; + if(strcmp(key, MwNsubBackground) == 0) return MwDefaultDarkSubBackground; + if(strcmp(key, MwNsubForeground) == 0) return MwDefaultDarkSubForeground; + if(strcmp(key, MwNtitleBackground) == 0) return MwDefaultDarkTitleBackground; + if(strcmp(key, MwNtitleForeground) == 0) return MwDefaultDarkTitleForeground; + } else { + if(strcmp(key, MwNbackground) == 0) return MwDefaultBackground; + if(strcmp(key, MwNforeground) == 0) return MwDefaultForeground; + if(strcmp(key, MwNsubBackground) == 0) return MwDefaultSubBackground; + if(strcmp(key, MwNsubForeground) == 0) return MwDefaultSubForeground; + if(strcmp(key, MwNtitleBackground) == 0) return MwDefaultTitleBackground; + if(strcmp(key, MwNtitleForeground) == 0) return MwDefaultTitleForeground; + } + } + return v; + } + + return shget(handle->text, key); +} + +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) +static void* inherit_void(MwWidget handle, const char* key) { + void* v; + + if(handle->parent != NULL && (v = MwGetVoid(handle->parent, key)) != NULL) { + return v; + } + return NULL; +} +#endif + +void* MwGetVoid(MwWidget handle, const char* key) { + void* v = shget(handle->data, key); + + if(v != NULL) return v; + +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) + if(strcmp(key, MwNfont) == 0 || strcmp(key, MwNboldFont) == 0 || strcmp(key, MwNmonospaceFont) == 0 || strcmp(key, MwNboldMonospaceFont) == 0) { + v = inherit_void(handle, key); + + if(v == NULL) { + MwWidget w = handle; + + while(w != NULL && v == NULL) { + if(strcmp(key, MwNfont) == 0) { + v = w->root_font; + } else if(strcmp(key, MwNboldFont) == 0) { + v = w->root_boldfont; + } else if(strcmp(key, MwNmonospaceFont) == 0) { + v = w->root_monofont; + } else if(strcmp(key, MwNboldMonospaceFont) == 0) { + v = w->root_boldmonofont; + } + + w = w->parent; + } + } + } +#endif + + return v; +} + +void MwVaApply(MwWidget handle, ...) { + va_list va; + + va_start(va, handle); + MwVaListApply(handle, va); + va_end(va); +} + +static void MwVaListApply_Internal(MwWidget handle, va_list va, int only_early) { + char* key; + int x = MwDEFAULT, y = MwDEFAULT, w = MwDEFAULT, h = MwDEFAULT; + char** keys = NULL; + int old = handle->prop_event; + int i; + + handle->prop_event = 0; + while((key = va_arg(va, char*)) != NULL) { + if(!only_early || key[1] == 'E') { + arrput(keys, key); + } + + if(key[0] == 'I') { + int n = va_arg(va, int); + if(only_early && key[1] != 'E') continue; + + if(strcmp(key, MwNx) == 0) { + x = n; + } else if(strcmp(key, MwNy) == 0) { + y = n; + } else if(strcmp(key, MwNwidth) == 0) { + w = n; + } else if(strcmp(key, MwNheight) == 0) { + h = n; + } else { + MwSetInteger(handle, key, n); + } + } else if(key[0] == 'S') { + char* t = va_arg(va, char*); + if(only_early && key[1] != 'E') continue; + + MwSetText(handle, key, t); + } else if(key[0] == 'C') { + MwUserHandler h = va_arg(va, MwUserHandler); + if(only_early && key[1] != 'E') continue; + + MwAddUserHandler(handle, key, h, NULL); + } else if(key[0] == 'V') { + void* v = va_arg(va, void*); + if(only_early && key[1] != 'E') continue; + MwSetVoid(handle, key, v); + } + } + if(x != MwDEFAULT && y != MwDEFAULT) { + MwLLSetXY(handle->lowlevel, x, y); + if(handle->prop_event) { + MwDispatch3(handle, prop_change, MwNx); + MwDispatch3(handle, prop_change, MwNy); + } + } else { + if(x != MwDEFAULT) { + MwSetInteger(handle, MwNx, x); + } else if(y != MwDEFAULT) { + MwSetInteger(handle, MwNy, y); + } + } + if(w != MwDEFAULT && h != MwDEFAULT) { + MwLLSetWH(handle->lowlevel, w, h); + if(handle->prop_event) { + MwDispatch3(handle, prop_change, MwNwidth); + MwDispatch3(handle, prop_change, MwNheight); + } + } else { + if(w != MwDEFAULT) { + MwSetInteger(handle, MwNwidth, w); + } else if(h != MwDEFAULT) { + MwSetInteger(handle, MwNheight, h); + } + } + handle->prop_event = old; + + arrput(keys, NULL); + + if(handle->prop_event) { + for(i = 0; keys[i] != NULL; i++) { + MwDispatch3(handle, prop_change, keys[i]); + } + + MwDispatch3(handle, props_change, keys); + } + + arrfree(keys); +} + +void MwVaListApply(MwWidget handle, va_list va) { + MwVaListApply_Internal(handle, va, 0); +} + +void MwSetDefault(MwWidget handle) { + if(handle->lowlevel != NULL) MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); +} + +void MwHideCursor(MwWidget handle) { + MwLLSetCursor(handle->lowlevel, &MwCursorHidden, &MwCursorHiddenMask); +} + +void MwDispatchUserHandler(MwWidget handle, const char* key, void* handler_data) { + int ind = shgeti(handle->handler, key); + int p = handle->prop_event; + int i; + + if(ind == -1) return; + if(handle->destroyed) return; + + if(!p) handle->prop_event = 1; + for(i = 0; i < arrlen(handle->handler[ind].value); i++) { + handle->handler[ind].value[i].handler(handle, handle->handler[ind].value[i].user_data, handler_data); + } + if(!p) handle->prop_event = 0; +} + +void MwAddUserHandler(MwWidget handle, const char* key, MwUserHandler handler, void* user_data) { + int ind; + MwUserHandlerArray a; + a.handler = handler; + a.user_data = user_data; + + ind = shgeti(handle->handler, key); + if(ind == -1) { + MwUserHandlerKeyValue e; + e.key = (char*)key; + e.value = NULL; + + arrput(e.value, a); + shputs(handle->handler, e); + } else { + arrput(handle->handler[ind].value, a); + } +} + +static MwErrorHandler error_handler = NULL; +static void* error_user_data = NULL; + +void MwSetErrorHandler(MwErrorHandler handler, void* user_data) { + error_handler = handler; + error_user_data = user_data; +} + +void MwDispatchError(int code, const char* message) { + if(error_handler != NULL) { + error_handler(code, message, error_user_data); + } else { +#ifdef _WIN32 + char buffer[1024]; + MwStringPrintIntoBuffer(buffer, 1024, "Error: %s\r\nCode : %d\r\n\r\nMilsko is exiting.", message, code); + MessageBox(NULL, buffer, "Error", MB_ICONERROR | MB_OK); +#else + fprintf(stderr, "Error: %s\nCode : %d\n\nMilsko is exiting.", message, code); +#endif + exit(1); + } +} + +#undef MwForceRender +void MwForceRender(MwWidget handle) { + MwLLForceRender(handle->lowlevel); +} + +#undef MwForceRender2 +void MwForceRender2(MwWidget handle, void* ptr) { + (void)ptr; + + MwForceRender(handle); +} + +void MwForceRender_Internal(MwWidget handle) { + MwForceRender(handle); +} + +void MwForceRender2_Internal(MwWidget handle, void* ptr) { + (void)ptr; + + MwForceRender(handle); +} + +void MwAddTickList(MwWidget handle) { + MwWidget root = handle; + while(root->parent != NULL) root = root->parent; + + arrput(root->tick_list, handle); +} + +void MwFocus(MwWidget handle) { + MwLLFocus(handle->lowlevel); +} + +void MwGrabPointer(MwWidget handle, int toggle) { + if(toggle) MwFocus(handle); + MwLLGrabPointer(handle->lowlevel, toggle); +} + +void MwSetDarkTheme(MwWidget handle, int toggle) { + MwVaApply(handle, + MwNdarkTheme, toggle, + NULL); +} + +MwWidget MwGetParent(MwWidget handle) { + return handle->parent; +} + +typedef int (*call_t)(void); +int MwLibraryInit(void) { + call_t calls[] = { +#ifdef USE_WAYLAND + NULL, /* set in a bit */ +#endif +#ifdef USE_X11 + MwLLX11CallInit, +#endif +#ifdef USE_COCOA + MwLLCocoaCallInit, +#endif +#ifdef USE_GDI + MwLLGDICallInit, +#endif +#ifdef CLASSIC_MAC_OS + MwLLClassicMacOSCallInit, +#endif +#ifdef USE_HAIKU + MwLLHaikuCallInit, +#endif + NULL}; + int i; + +#ifdef _WIN32 + timeBeginPeriod(10); +#endif + +#ifdef USE_WAYLAND + if(MwWaylandCairoOnly) { + calls[0] = MwLLCairoCallInit; + } else { + calls[0] = MwLLWaylandCallInit; + } +#endif + + MwColorTableInit(); + + MwFLSetup(); + + for(i = 0; calls[i] != NULL; i++) { + if(calls[i]() == 0) return 0; + } + +#ifdef __APPLE__ + void MwLLNoCocoaErrorMessage(void); + MwLLNoCocoaErrorMessage(); +#else + printf("[WARNING] No suitable GUI backend found! Enabled:" +#ifdef USE_COCOA + " Cocoa" +#endif +#ifdef USE_WAYLAND + " Wayland" +#endif +#ifdef USE_X11 + " X11" +#endif +#ifdef USE_GDI + " GDI" +#endif +#ifdef CLASSIC_MAC_OS + " ClassicMacOS" +#endif + "\n"); +#endif + return 1; +} + +void MwShow(MwWidget handle, int toggle) { + MwLLShow(handle->lowlevel, toggle); +} + +void MwReparent(MwWidget handle, MwWidget new_parent) { + if(handle->parent != NULL) { + int i; + for(i = 0; i < arrlen(handle->parent->children); i++) { + if(handle->parent->children[i] == handle) { + arrdel(handle->parent->children, i); + break; + } + } + + MwDispatch4(handle->parent, children_update, handle, 0); + } + + handle->parent = new_parent; + if(new_parent != NULL) { + arrput(new_parent->children, handle); + + MwDispatch4(handle->parent, children_update, handle, 1); + } + + if(new_parent == NULL) { + handle->top_step = 1; + arrput(handle->tick_list, handle); + } else { + handle->top_step = 0; + arrfree(handle->tick_list); + } + + MwForceRender(handle); +} + +MwClass MwGetClass(MwWidget handle) { + return handle->widget_class; +} + +const char* MwGetName(MwWidget handle) { + return handle->name; +} + +MwWidget* MwGetChildren(MwWidget handle) { + MwWidget* c = malloc(sizeof(*c) * (arrlen(handle->children) + 1)); + int i; + + for(i = 0; i < arrlen(handle->children); i++) { + c[i] = handle->children[i]; + } + c[arrlen(handle->children)] = 0; + + return c; +} + +void MwGetCursorCoord(MwWidget handle, MwPoint* point) { + MwLLGetCursorCoord(handle->lowlevel, point); +} + +void MwGetScreenSize(MwWidget handle, MwRect* rect) { + MwLLGetScreenSize(handle->lowlevel, rect); +} + +int MwGetCoordinateType(MwWidget handle) { + if(handle->parent == NULL || handle->parent->lowlevel == NULL) { + return handle->lowlevel->common.coordinate_type; + } else { + return MwCOORDINATE_LOCAL; + } +} + +void MwGetClipboard(MwWidget handle, int clipboard_type) { + MwLLGetClipboard(handle->lowlevel, clipboard_type); +} + +void MwSetUser(MwWidget handle, void* user) { + handle->user = user; +} + +void* MwGetUser(MwWidget handle) { + return handle->user; +} + +void MwGetFrame(MwWidget handle, MwRect* rect) { + rect->x = MwGetInteger(handle, MwNx); + rect->y = MwGetInteger(handle, MwNy); + rect->width = MwGetInteger(handle, MwNwidth); + rect->height = MwGetInteger(handle, MwNheight); +} + +const char* MwVersionString = MwVERSION; diff --git a/widget/milsko/milskosrc/src/cursor/arrow.c b/widget/milsko/milskosrc/src/cursor/arrow.c new file mode 100644 index 0000000000..5a1d9bff87 --- /dev/null +++ b/widget/milsko/milskosrc/src/cursor/arrow.c @@ -0,0 +1,43 @@ +#include + +/** + * Created by bitmaptobdf + * + * Copyright notice: + * These ""glyphs"" are unencumbered + */ +MwCursor MwCursorArrow = { + 14, 14, -13, -14, {3, /* ............## */ + 15, /* ..........#### */ + 62, /* ........#####. */ + 254, /* ......#######. */ + 1020, /* ....########.. */ + 4092, /* ..##########.. */ + 248, /* ......#####... */ + 504, /* .....######... */ + 944, /* ....###.##.... */ + 1840, /* ...###..##.... */ + 3616, /* ..###...#..... */ + 7200, /* .###....#..... */ + 14336, /* ###........... */ + 4096, /* .#............ */ + 0, 0}}; +MwCursor MwCursorArrowMask = { + 16, 16, -14, -15, { + 7, /* .............### */ + 31, /* ...........##### */ + 127, /* .........####### */ + 510, /* .......########. */ + 2046, /* .....##########. */ + 8188, /* ...###########.. */ + 16380, /* ..############.. */ + 16376, /* ..###########... */ + 2040, /* .....########... */ + 4080, /* ....########.... */ + 8176, /* ...#########.... */ + 16096, /* ..#####.###..... */ + 31968, /* .#####..###..... */ + 63552, /* #####....#...... */ + 28672, /* .###............ */ + 8192 /* ..#............. */ + }}; diff --git a/widget/milsko/milskosrc/src/cursor/cross.c b/widget/milsko/milskosrc/src/cursor/cross.c new file mode 100644 index 0000000000..8c53739b33 --- /dev/null +++ b/widget/milsko/milskosrc/src/cursor/cross.c @@ -0,0 +1,8 @@ +#include + +/** + * Created by bitmaptobdf + * + * Copyright notice: + * These ""glyphs"" are unencumbered + */ diff --git a/widget/milsko/milskosrc/src/cursor/default.c b/widget/milsko/milskosrc/src/cursor/default.c new file mode 100644 index 0000000000..d4bda3cda4 --- /dev/null +++ b/widget/milsko/milskosrc/src/cursor/default.c @@ -0,0 +1,43 @@ +#include + +/** + * Created by bitmaptobdf + * + * Copyright notice: + * These ""glyphs"" are unencumbered + */ +MwCursor MwCursorDefault = { + 8, 14, 0, -14, {128, /* #....... */ + 192, /* ##...... */ + 224, /* ###..... */ + 240, /* ####.... */ + 248, /* #####... */ + 252, /* ######.. */ + 254, /* #######. */ + 255, /* ######## */ + 248, /* #####... */ + 216, /* ##.##... */ + 140, /* #...##.. */ + 12, /* ....##.. */ + 6, /* .....##. */ + 6, /* .....##. */ + 0, 0}}; +MwCursor MwCursorDefaultMask = { + 10, 16, -1, -15, { + 768, /* ##........ */ + 896, /* ###....... */ + 960, /* ####...... */ + 992, /* #####..... */ + 1008, /* ######.... */ + 1016, /* #######... */ + 1020, /* ########.. */ + 1022, /* #########. */ + 1023, /* ########## */ + 1023, /* ########## */ + 1016, /* #######... */ + 956, /* ###.####.. */ + 828, /* ##..####.. */ + 30, /* .....####. */ + 30, /* .....####. */ + 12 /* ......##.. */ + }}; diff --git a/widget/milsko/milskosrc/src/cursor/hidden.c b/widget/milsko/milskosrc/src/cursor/hidden.c new file mode 100644 index 0000000000..61cd44b522 --- /dev/null +++ b/widget/milsko/milskosrc/src/cursor/hidden.c @@ -0,0 +1,5 @@ +#include +MwCursor MwCursorHidden = { + 1, 1, 0, -1, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; +MwCursor MwCursorHiddenMask = { + 1, 1, 0, -1, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; diff --git a/widget/milsko/milskosrc/src/cursor/text.c b/widget/milsko/milskosrc/src/cursor/text.c new file mode 100644 index 0000000000..855f01a329 --- /dev/null +++ b/widget/milsko/milskosrc/src/cursor/text.c @@ -0,0 +1,43 @@ +#include + +/** + * Created by bitmaptobdf + * + * Copyright notice: + * These ""glyphs"" are unencumbered + */ +MwCursor MwCursorText = { + 7, 14, -3, -7, {119, /* ###.### */ + 28, /* ..###.. */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 8, /* ...#... */ + 28, /* ..###.. */ + 119, /* ###.### */ + 0, 0}}; +MwCursor MwCursorTextMask = { + 9, 16, -4, -8, { + 495, /* ####.#### */ + 511, /* ######### */ + 511, /* ######### */ + 124, /* ..#####.. */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 56, /* ...###... */ + 124, /* ..#####.. */ + 511, /* ######### */ + 511, /* ######### */ + 495 /* ####.#### */ + }}; diff --git a/widget/milsko/milskosrc/src/default.c b/widget/milsko/milskosrc/src/default.c new file mode 100644 index 0000000000..44e4c4d6f0 --- /dev/null +++ b/widget/milsko/milskosrc/src/default.c @@ -0,0 +1,41 @@ +#include + +const char* MwDefaultBackground = "#d2d2d2"; +const char* MwDefaultForeground = "#000"; +const char* MwDefaultSubBackground = "#fff"; +const char* MwDefaultSubForeground = "#000"; +const char* MwDefaultTitleBackground = "#008"; +const char* MwDefaultTitleForeground = "#fff"; + +const char* MwDefaultDarkBackground = "#333"; +const char* MwDefaultDarkForeground = "#ddd"; +const char* MwDefaultDarkSubBackground = "#333"; +const char* MwDefaultDarkSubForeground = "#ddd"; +const char* MwDefaultDarkTitleBackground = "#008"; +const char* MwDefaultDarkTitleForeground = "#fff"; + +const int MwDefaultShadow = -32; + +int MwDefaultBorderWidth(MwWidget handle) { + int bw = MwGetInteger(handle, MwNborderWidth); + + if(bw != MwDEFAULT) return bw; + + if(MwGetInteger(handle, MwNmodernLook)) { + return 2; + } else { + return 2; + } +} + +int MwDefaultThinBorderWidth(MwWidget handle) { + int bw = MwGetInteger(handle, MwNborderWidth); + + if(bw != MwDEFAULT) return bw; + + if(MwGetInteger(handle, MwNmodernLook)) { + return 1; + } else { + return 2; + } +} diff --git a/widget/milsko/milskosrc/src/dialog/colorpicker.c b/widget/milsko/milskosrc/src/dialog/colorpicker.c new file mode 100644 index 0000000000..926fddcbcc --- /dev/null +++ b/widget/milsko/milskosrc/src/dialog/colorpicker.c @@ -0,0 +1,380 @@ +#include + +#define WIN_SIZE 464 +#define PICKER_SIZE 364 +#define IMG_POS_X(w) ((w - PICKER_SIZE) / 2) +#define IMG_POS_Y(h) ((h - PICKER_SIZE) / 2) +#define SCROLL_BAR_WIDTH 16 +#define MARGIN (PICKER_SIZE / 32) +#define COLOR_DISPLAY_HEIGHT 12 + +#define HSV_HUE_SEXTANT 256. +#define HSV_HUE_STEPS (6. * HSV_HUE_SEXTANT) + +#define HSV_HUE_MIN 0. +#define HSV_HUE_MAX (HSV_HUE_STEPS - 1.) +#define HSV_SAT_MIN 0. +#define HSV_SAT_MAX 255. +#define HSV_VAL_MIN 0. +#define HSV_VAL_MAX 255. + +typedef struct _MwHSV { + MwBool generated : 1; + MwU16 h : 11; + MwU8 s; + MwU8 v; +} MwHSV; + +typedef struct color_picker { + MwWidget parent; + MwWidget color_picker_img; + MwWidget value_slider; + MwWidget color_display_text; + MwWidget finish; + MwLLPixmap color_picker_pixmap; + double value; + MwRGB chosen_color; + unsigned char color_picker_image_data[PICKER_SIZE * PICKER_SIZE * 4]; + MwHSV hue_table[101753]; + MwU8 doUpdate; +} color_picker_t; + +static void hsv2rgb(MwU32 h, MwU32 s, MwU32 v, MwU16* r, MwU16* g, MwU16* b) { + MwU8 sextant = h >> 8; + MwU16 ww; + MwU32 h_fraction, d; + +#define HSV_SWAPPTR(a, b) \ + do { \ + MwU16* tmp = a; \ + a = b; \ + b = tmp; \ + } while(0) + + if(sextant & 2) { + HSV_SWAPPTR(r, b); + } + if(sextant & 4) { + HSV_SWAPPTR(g, b); + } + if(!(sextant & 6)) { + if(!(sextant & 1)) { + HSV_SWAPPTR(r, g); + } + } else { + if(sextant & 1) { + HSV_SWAPPTR(r, g); + } + } + + *g = v; /* Top level */ + + /* Perform actual calculations */ + + /** + * Bottom level: v * (1.0 - s) + * --> (v * (255 - s) + error_corr + 1) / 256 + */ + ww = v * (255 - (s)); /* We don't use ~s to prevent size-promotion side effects */ + ww += 1; /* Error correction */ + ww += ww >> 8; /* Error correction */ + *b = ww >> 8; + + h_fraction = h & 0xff; /* 0...255 */ + + if(!(sextant & 1)) { + /* *r = ...slope_up...; */ + d = v * (MwU32)((0xff << 8) - (MwU16)(s * (0xff - h_fraction))); + *r = d >> 16; + } else { + /* *r = ...slope_down...; */ + d = v * (MwU32)((0xff << 8) - (MwU16)(s * h_fraction)); + *r = d >> 16; + } + return; +} + +static void color_picker_image_update(color_picker_t* picker) { + MwU16 y, x; + int n = 0; + for(y = 0; y < PICKER_SIZE; y++) { + for(x = 0; x < PICKER_SIZE; x++) { + int i = ((y * PICKER_SIZE) + x) * 4; + int _x = x - (PICKER_SIZE / 2); + int _y = y - (PICKER_SIZE / 2); + double dist = sqrt(_x * _x + _y * _y); + + if(dist >= 182.) { + picker->color_picker_image_data[i] = 0; + picker->color_picker_image_data[i + 1] = 0; + picker->color_picker_image_data[i + 2] = 0; + picker->color_picker_image_data[i + 3] = 0; + } else if(dist >= 180.) { + picker->color_picker_image_data[i] = dist; + picker->color_picker_image_data[i + 1] = dist; + picker->color_picker_image_data[i + 2] = dist; + picker->color_picker_image_data[i + 3] = 255; + } else { + MwHSV hsv_v; + MwRGB color; + if(picker->hue_table[n].generated == 0) { + double xd = (M_PI / 180.) * ((double)_x); + double yd = (M_PI / 180.) * ((double)_y); + + float angle = atan2(yd, xd) - M_PI; + float hue = (angle * 180.) / M_PI; + + if(hue < 0.0) { + hue += 360; + } + hsv_v.h = (hue) * (HSV_HUE_STEPS / 360.); + hsv_v.s = (dist) * (HSV_SAT_MAX / 180.); + picker->hue_table[n] = hsv_v; + picker->hue_table[n].generated = 1; + } + + hsv_v = picker->hue_table[n]; + hsv_v.v = HSV_VAL_MAX - (picker->value * HSV_VAL_MAX); + + hsv2rgb(hsv_v.h, hsv_v.s, hsv_v.v, &color.red, &color.green, &color.blue); + + picker->color_picker_image_data[i] = color.red; + picker->color_picker_image_data[i + 1] = color.green; + picker->color_picker_image_data[i + 2] = color.blue; + + picker->color_picker_image_data[i + 3] = 255; + n++; + } + } + } + if(picker->color_picker_pixmap == NULL) { + picker->color_picker_pixmap = MwLoadRaw( + picker->parent, picker->color_picker_image_data, PICKER_SIZE, PICKER_SIZE); + } else { + MwPixmapReloadRaw( + picker->color_picker_pixmap, picker->color_picker_image_data); + } + MwVaApply(picker->color_picker_img, MwNpixmap, picker->color_picker_pixmap, NULL); + /* printf("%d\n", n); */ +} + +static void MWAPI color_picker_click(MwWidget handle, void* user, void* call) { + color_picker_t* picker = user; + MwMouse* mouse = call; + char hexColor[8]; + int i; + char fgColor[8]; + int fr, fg, fb; + + (void)handle; + (void)user; + (void)call; + + /* color_picker_image_update(picker); */ + + i = ((mouse->point.y * PICKER_SIZE) + mouse->point.x) * 4; + + picker->chosen_color.red = picker->color_picker_image_data[i]; + picker->chosen_color.green = picker->color_picker_image_data[i + 1]; + picker->chosen_color.blue = picker->color_picker_image_data[i + 2]; + + MwStringPrintIntoBuffer(hexColor, 8, "#%02X%02X%02X", picker->chosen_color.red & 0xff, picker->chosen_color.green & 0xff, picker->chosen_color.blue & 0xff); + + fr = picker->chosen_color.red > 128 ? 0 : 255; + fg = picker->chosen_color.green > 128 ? 0 : 255; + fb = picker->chosen_color.blue > 128 ? 0 : 255; + + MwStringPrintIntoBuffer(fgColor, 8, "#%02X%02X%02X", fr, fg, fb); + MwSetText(picker->color_display_text, MwNforeground, fgColor); + + MwSetText(picker->color_display_text, MwNbackground, hexColor); + MwSetText(picker->color_display_text, MwNtext, hexColor); +} +static void MWAPI color_picker_on_change_value(MwWidget handle, void* user, + void* call) { + color_picker_t* picker = user; + + int value = MwGetInteger(handle, MwNvalue); + int diff = MwGetInteger(handle, MwNchangedBy); + + (void)diff; + (void)call; + + picker->value = ((double)value / 1024.); + + picker->doUpdate = 1; + /* color_picker_image_update(picker); */ +} + +static void MWAPI color_picker_tick(MwWidget handle, void* user, + void* call) { + color_picker_t* picker = user; + + (void)handle; + (void)call; + + if(picker->doUpdate == 1) { + color_picker_image_update(picker); + picker->doUpdate = 0; + } +} + +static void color_picker_destroy(color_picker_t* picker) { + MwLLDestroyPixmap(picker->color_picker_pixmap); + free(picker); +} + +static void MWAPI color_picker_close(MwWidget handle, void* user, + void* call) { + color_picker_t* picker = user; + + (void)call; + + color_picker_destroy(picker); + MwDestroyWidget(handle); +} + +static void MWAPI color_display_text_change(MwWidget handle, void* user, + void* call) { + color_picker_t* picker = user; + char hexColor[9]; + char fgColor[9]; + MwLLColor color; + int fr, fg, fb; + + (void)call; + + memcpy(&hexColor, MwGetText(handle, MwNtext), 8); + + color = MwParseColor(handle, hexColor); + + fr = color->common.red > 128 ? 0 : 255; + fg = color->common.green > 128 ? 0 : 255; + fb = color->common.blue > 128 ? 0 : 255; + + MwStringPrintIntoBuffer(fgColor, 9, "#%02X%02X%02X", fr, fg, fb); + MwSetText(picker->color_display_text, MwNforeground, fgColor); + + MwSetText(picker->color_display_text, MwNbackground, hexColor); + MwSetText(picker->color_display_text, MwNtext, hexColor); + + picker->chosen_color.red = color->common.red; + picker->chosen_color.green = color->common.green; + picker->chosen_color.blue = color->common.blue; + + MwLLFreeColor(color); +} + +static void MWAPI color_picker_finish(MwWidget handle, void* user, + void* call) { + color_picker_t* picker = user; + + (void)call; + + MwDispatchUserHandler(picker->parent, MwNcolorChosenHandler, &picker->chosen_color); + + color_picker_destroy(picker); + MwDestroyWidget(handle->parent); +} + +color_picker_t* color_picker_setup(MwWidget parent, int w, int h) { + color_picker_t* picker = malloc(sizeof(*picker)); + memset(picker, 0, sizeof(*picker)); + + picker->parent = parent; + + picker->color_picker_img = + MwVaCreateWidget(MwImageClass, "image", picker->parent, IMG_POS_X(w), IMG_POS_Y(h), + PICKER_SIZE, PICKER_SIZE, NULL); + + /* picker->color_picker_image_data = malloc(PICKER_SIZE * PICKER_SIZE * 4); */ + + picker->color_picker_pixmap = NULL; + picker->value = 0; + + /* color_picker_image_update(picker); */ + picker->doUpdate = 1; + + MwAddUserHandler(picker->color_picker_img, MwNmouseDownHandler, + color_picker_click, picker); + + picker->color_display_text = MwCreateWidget( + MwEntryClass, "colorDisplayText", picker->parent, IMG_POS_X(w) + (PICKER_SIZE / 2) - ((PICKER_SIZE / 4) / 2), + IMG_POS_Y(h) - (PICKER_SIZE / 16) - MARGIN, (PICKER_SIZE / 4), PICKER_SIZE / 16); + + MwSetText(picker->color_display_text, MwNbackground, "#FFFFFF"); + MwSetText(picker->color_display_text, MwNtext, "#FFFFFF"); + /* MwSetInteger(picker->color_display_text, Mwnali, MwALIGNMENT_CENTER); */ + + MwAddUserHandler(picker->color_display_text, MwNactivateHandler, + color_display_text_change, picker); + picker->value_slider = MwVaCreateWidget( + MwScrollBarClass, "value-slider", picker->parent, + /* x */ + IMG_POS_X(w) + PICKER_SIZE + MARGIN, + + /* y */ + IMG_POS_Y(h), + + /* width */ + SCROLL_BAR_WIDTH, + + /* height */ + PICKER_SIZE, + + MwNorientation, MwVERTICAL, MwNminValue, 0, MwNmaxValue, 1024, NULL); + + MwAddUserHandler(picker->value_slider, MwNchangedHandler, + color_picker_on_change_value, picker); + + picker->finish = MwCreateWidget( + MwButtonClass, "colorPickerFinish", picker->parent, IMG_POS_X(w), + IMG_POS_Y(h) + PICKER_SIZE + MARGIN, PICKER_SIZE, (WIN_SIZE - PICKER_SIZE - MARGIN * 4) / 2); + MwSetText(picker->finish, MwNtext, "Select"); + MwSetInteger(picker->finish, MwNhasBorder, 1); + MwSetInteger(picker->finish, MwNinverted, 1); + + MwAddUserHandler(picker->finish, MwNactivateHandler, + color_picker_finish, picker); + + memset(picker->hue_table, 0, sizeof(picker->hue_table)); + + return picker; +} + +MwWidget MwColorPicker(MwWidget handle, const char* title) { + color_picker_t* wheel; + MwWidget window; + MwSizeHints sh; + int wx; + int wy; + + if(handle == NULL) { + wx = wy = MwDEFAULT; + } else { + wx = MwGetInteger(handle, MwNx) + (MwGetInteger(handle, MwNwidth) - WIN_SIZE) / 2; + wy = MwGetInteger(handle, MwNy) + (MwGetInteger(handle, MwNheight) - WIN_SIZE) / 2; + } + + sh.min_width = sh.max_width = WIN_SIZE; + sh.min_height = sh.max_height = WIN_SIZE; + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, wx, wy, + WIN_SIZE, WIN_SIZE, + MwNtitle, title, + MwNsizeHints, &sh, + NULL); + if(handle != NULL) MwReparent(window, handle); + + wheel = color_picker_setup(window, WIN_SIZE, WIN_SIZE); + + MwAddUserHandler(window, MwNcloseHandler, color_picker_close, wheel); + MwAddUserHandler(window, MwNtickHandler, color_picker_tick, wheel); + MwAddTickList(window); + + MwLLBeginStateChange(window->lowlevel); + MwLLMakePopup(window->lowlevel, handle == NULL ? NULL : handle->lowlevel); + MwLLEndStateChange(window->lowlevel); + + return window; +} diff --git a/widget/milsko/milskosrc/src/dialog/directorychooser.c b/widget/milsko/milskosrc/src/dialog/directorychooser.c new file mode 100644 index 0000000000..8f9416fae1 --- /dev/null +++ b/widget/milsko/milskosrc/src/dialog/directorychooser.c @@ -0,0 +1,5 @@ +#include + +MwWidget MwDirectoryChooser(MwWidget handle, const char* title) { + return MwFileChooserEx(handle, title, 1); +} diff --git a/widget/milsko/milskosrc/src/dialog/filechooser.c b/widget/milsko/milskosrc/src/dialog/filechooser.c new file mode 100644 index 0000000000..138fc6cf00 --- /dev/null +++ b/widget/milsko/milskosrc/src/dialog/filechooser.c @@ -0,0 +1,573 @@ +#include + +#include "../external/stb_ds.h" + +typedef struct filechooser { + char* path; + char** history; + int history_seek; + int dir_only; + + MwDirectoryEntry** entries; + MwDirectoryEntry** sorted_entries; + + MwWidget nav; + MwWidget files; + MwWidget addr; + MwWidget addr_back; + MwWidget addr_fwd; + MwWidget addr_up; + MwWidget filename_label; + MwWidget filename; + MwWidget okay; + MwWidget cancel; + + MwLLPixmap dir; + MwLLPixmap file; + MwLLPixmap back; + MwLLPixmap forward; + MwLLPixmap up; + MwLLPixmap computer; +} filechooser_t; + +static void scan(MwWidget handle, const char* path, int record); + +static void destroy(MwWidget handle) { + filechooser_t* fc = handle->opaque; + int i; + + for(i = 0; i < arrlen(fc->history); i++) free(fc->history[i]); + arrfree(fc->history); + + arrfree(fc->sorted_entries); + for(i = 0; i < arrlen(fc->entries); i++) MwDirectoryFreeEntry(fc->entries[i]); + arrfree(fc->entries); + + MwLLDestroyPixmap(fc->dir); + MwLLDestroyPixmap(fc->file); + MwLLDestroyPixmap(fc->back); + MwLLDestroyPixmap(fc->forward); + MwLLDestroyPixmap(fc->up); + MwLLDestroyPixmap(fc->computer); + free(handle->opaque); +} + +static void MWAPI filecancel(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + + MwDestroyWidget(handle->parent); +} + +static void MWAPI cancel_window(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + + MwDestroyWidget(handle); +} + +static void MWAPI okay(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + + MwDestroyWidget(handle->parent); +} + +static void MWAPI msgbox_okay(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + + MwDestroyWidget(handle->parent); +} + +static void MWAPI files_activate(MwWidget handle, void* user, void* call) { + int index = *(int*)call; + filechooser_t* fc = handle->parent->opaque; + + (void)user; + + if(fc->sorted_entries[index - 1]->type == MwDIRECTORY_DIRECTORY) { + char* p = MwDirectoryJoin(fc->path, fc->sorted_entries[index - 1]->name); + + scan(handle->parent, p, 1); + + free(p); + } else { + char* p; + + p = MwDirectoryJoin(fc->path, fc->sorted_entries[MwGetInteger(fc->files, MwNvalue) - 1]->name); + MwDispatchUserHandler(handle->parent, fc->dir_only ? MwNdirectoryChosenHandler : MwNfileChosenHandler, p); + free(p); + + okay(fc->okay, NULL, NULL); + } +} + +static void MWAPI okay_activate(MwWidget handle, void* user, void* call) { + filechooser_t* fc = handle->parent->opaque; + char* t = (char*)MwGetText(fc->filename, MwNtext); + struct stat s; + char* p = NULL; + + (void)user; + (void)call; + + if(t != NULL && t[0] == '/') { + p = MwStringDuplicate(t); + } else { + p = MwDirectoryJoin(fc->path, t); + } + + if(t == NULL || strlen(t) == 0) { + MwWidget msgbox = MwMessageBox(handle->parent, fc->dir_only ? "You have to type directory!" : "You have to type filename!", "Error", MwMB_ICONERROR | MwMB_BUTTONOK); + MwAddUserHandler(MwMessageBoxGetChild(msgbox, MwMB_BUTTONOK), MwNactivateHandler, msgbox_okay, NULL); + } else if(stat(p, &s) != 0) { + MwWidget msgbox = MwMessageBox(handle->parent, "File does not exist!", "Error", MwMB_ICONERROR | MwMB_BUTTONOK); + MwAddUserHandler(MwMessageBoxGetChild(msgbox, MwMB_BUTTONOK), MwNactivateHandler, msgbox_okay, NULL); +#ifdef _S_IFDIR + } else if(fc->dir_only ? ((s.st_mode & _S_IFDIR) != _S_IFDIR) : 0) { +#else + } else if(fc->dir_only ? !S_ISDIR(s.st_mode) : 0) { +#endif + MwWidget msgbox = MwMessageBox(handle->parent, "File is not permitted here!", "Error", MwMB_ICONERROR | MwMB_BUTTONOK); + MwAddUserHandler(MwMessageBoxGetChild(msgbox, MwMB_BUTTONOK), MwNactivateHandler, msgbox_okay, NULL); + } else { + MwDispatchUserHandler(handle->parent, fc->dir_only ? MwNdirectoryChosenHandler : MwNfileChosenHandler, p); + okay(fc->okay, NULL, NULL); + } + + if(p != NULL) free(p); +} + +static void MWAPI nav_activate(MwWidget handle, void* user, void* call) { + int index = *(int*)call; + const char* e = MwListBoxGet(handle, index); + + (void)user; + + if(strcmp(e, "Home") == 0) { +#if defined(_WIN32) || defined(CLASSIC_MAC_OS) +#else + struct passwd* p = getpwuid(getuid()); + + scan(handle->parent, p->pw_dir, 1); +#endif + } +} + +static void MWAPI addr_up_activate(MwWidget handle, void* user, void* call) { + filechooser_t* fc = handle->parent->opaque; + char* p = MwDirectoryJoin(fc->path, ".."); + + (void)user; + (void)call; + + scan(handle->parent, p, 1); + + free(p); +} + +static void MWAPI addr_back_activate(MwWidget handle, void* user, void* call) { + filechooser_t* fc = handle->parent->opaque; + + (void)user; + (void)call; + + if(fc->history_seek > 1) { + fc->history_seek -= 2; + scan(handle->parent, fc->history[fc->history_seek], 0); + fc->history_seek++; + } +} + +static void MWAPI addr_fwd_activate(MwWidget handle, void* user, void* call) { + filechooser_t* fc = handle->parent->opaque; + + (void)user; + (void)call; + + if(fc->history_seek < arrlen(fc->history)) { + scan(handle->parent, fc->history[fc->history_seek++], 0); + } +} + +static void MWAPI addr_activate(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + + scan(handle->parent, MwGetText(handle, MwNtext), 1); +} + +static void layout(MwWidget handle) { + filechooser_t* fc = handle->opaque; + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + int wx, wy, ww, wh; + + wx = 5; + wy = 5 + 24 + 5; + ww = 160; + wh = h - 10 - 24 - 5 - 24 - 5 - 24 - 5; + if(fc->nav == NULL) { + int index; + + fc->nav = MwVaCreateWidget(MwListBoxClass, "nav", handle, wx, wy, ww, wh, + MwNleftPadding, 16, + NULL); + + index = MwListBoxSet(fc->nav, -1, 0, "Home"); + MwListBoxSetIcon(fc->nav, index, fc->computer); + + MwAddUserHandler(fc->nav, MwNlistBoxActivateHandler, nav_activate, NULL); + } else { + MwVaApply(fc->nav, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = 5 + 160 + 5; + wy = 5 + 24 + 5; + ww = w - 5 - 160 - 5 - 5; + wh = h - 10 - 24 - 5 - 24 - 5 - 24 - 5; + if(fc->files == NULL) { + fc->files = MwVaCreateWidget(MwListBoxClass, "files", handle, wx, wy, ww, wh, + MwNhasHeading, 1, + MwNleftPadding, 16, + NULL); + MwAddUserHandler(fc->files, MwNlistBoxActivateHandler, files_activate, NULL); + } else { + MwVaApply(fc->files, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = 5 + ((24 + 5) * 3); + wy = 5; + ww = w - 10 - ((24 + 5) * 3); + wh = 24; + if(fc->addr == NULL) { + fc->addr = MwCreateWidget(MwEntryClass, "addr", handle, wx, wy, ww, wh); + MwAddUserHandler(fc->addr, MwNactivateHandler, addr_activate, NULL); + } else { + MwVaApply(fc->addr, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = 5; + wy = 5; + ww = 24; + wh = 24; + if(fc->addr_back == NULL) { + fc->addr_back = MwVaCreateWidget(MwButtonClass, "addr_back", handle, wx, wy, ww, wh, + MwNpixmap, fc->back, + NULL); + MwAddUserHandler(fc->addr_back, MwNactivateHandler, addr_back_activate, NULL); + } else { + MwVaApply(fc->addr_back, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = 5 + 24 + 5; + wy = 5; + ww = 24; + wh = 24; + if(fc->addr_fwd == NULL) { + fc->addr_fwd = MwVaCreateWidget(MwButtonClass, "addr_fwd", handle, wx, wy, ww, wh, + MwNpixmap, fc->forward, + NULL); + MwAddUserHandler(fc->addr_fwd, MwNactivateHandler, addr_fwd_activate, NULL); + } else { + MwVaApply(fc->addr_fwd, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = 5 + 24 + 5 + 24 + 5; + wy = 5; + ww = 24; + wh = 24; + if(fc->addr_up == NULL) { + fc->addr_up = MwVaCreateWidget(MwButtonClass, "addr_up", handle, wx, wy, ww, wh, + MwNpixmap, fc->up, + NULL); + MwAddUserHandler(fc->addr_up, MwNactivateHandler, addr_up_activate, NULL); + } else { + MwVaApply(fc->addr_up, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = 5 + ((24 + 5) * 3); + wy = h - 5 - 24 - 5 - 24; + ww = w - 10 - ((24 + 5) * 3); + wh = 24; + if(fc->filename == NULL) { + fc->filename = MwCreateWidget(MwEntryClass, "filename", handle, wx, wy, ww, wh); + MwAddUserHandler(fc->filename, MwNactivateHandler, okay_activate, NULL); + } else { + MwVaApply(fc->filename, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = 5; + wy = h - 5 - 24 - 5 - 24; + ww = ((24 + 5) * 3); + wh = 24; + if(fc->filename_label == NULL) { + fc->filename_label = MwVaCreateWidget(MwLabelClass, "filename_label", handle, wx, wy, ww, wh, + MwNtext, fc->dir_only ? "Directory:" : "Filename:", + NULL); + } else { + MwVaApply(fc->filename_label, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = w - 5 - 24 * 3 - 5 - 24 * 3; + wy = h - 5 - 24; + ww = 24 * 3; + wh = 24; + if(fc->okay == NULL) { + fc->okay = MwVaCreateWidget(MwButtonClass, "ok", handle, wx, wy, ww, wh, + MwNtext, "Okay", + NULL); + + MwAddUserHandler(fc->okay, MwNactivateHandler, okay_activate, NULL); + } else { + MwVaApply(fc->okay, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } + + wx = w - 5 - 24 * 3; + wy = h - 5 - 24; + ww = 24 * 3; + wh = 24; + if(fc->cancel == NULL) { + fc->cancel = MwVaCreateWidget(MwButtonClass, "cancel", handle, wx, wy, ww, wh, + MwNtext, "Cancel", + NULL); + + MwAddUserHandler(fc->cancel, MwNactivateHandler, filecancel, NULL); + } else { + MwVaApply(fc->cancel, + MwNx, wx, + MwNy, wy, + MwNwidth, ww, + MwNheight, wh, + NULL); + } +} + +static void MWAPI resize(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + + layout(handle); +} + +static int qsort_files(const void* a, const void* b) { + MwDirectoryEntry* aent = *(MwDirectoryEntry**)a; + MwDirectoryEntry* bent = *(MwDirectoryEntry**)b; + + return strcmp(aent->name, bent->name); +} + +static void scan(MwWidget handle, const char* path, int record) { + filechooser_t* fc = handle->opaque; + void* dir = MwDirectoryOpen(path); + int i; + int index; + + if(dir != NULL) { + MwDirectoryEntry* entry; + + arrfree(fc->sorted_entries); + for(i = 0; i < arrlen(fc->entries); i++) MwDirectoryFreeEntry(fc->entries[i]); + arrfree(fc->entries); + + while((entry = MwDirectoryRead(dir)) != NULL) arrput(fc->entries, entry); + MwDirectoryClose(dir); + + qsort(fc->entries, arrlen(fc->entries), sizeof(MwDirectoryEntry*), qsort_files); + + if(record) { + char* str = MwStringDuplicate(path); + + while(arrlen(fc->history) > fc->history_seek) { + free(fc->history[fc->history_seek]); + arrdel(fc->history, fc->history_seek); + } + + arrins(fc->history, fc->history_seek, str); + + fc->history_seek++; + } + } else { + MwWidget msgbox = MwMessageBox(handle, "Directory does not exist!", "Error", MwMB_ICONERROR | MwMB_BUTTONOK); + MwAddUserHandler(MwMessageBoxGetChild(msgbox, MwMB_BUTTONOK), MwNactivateHandler, msgbox_okay, NULL); + return; + } + + if(fc->path != NULL) free(fc->path); + fc->path = MwStringDuplicate(path); + + MwVaApply(fc->addr, + MwNtext, path, + NULL); + + if(fc->dir_only) { + MwVaApply(fc->filename, + MwNtext, path, + NULL); + } else { + MwVaApply(fc->filename, + MwNtext, "", + NULL); + } + + MwListBoxReset(fc->files); + MwListBoxSetWidth(fc->files, 0, -128 - 96); + MwListBoxSetWidth(fc->files, 1, 128); + MwListBoxSetWidth(fc->files, 2, 0); + + index = MwListBoxSet(fc->files, -1, 0, "Name"); + MwListBoxSet(fc->files, index, -1, "Date modified"); + MwListBoxSet(fc->files, index, -1, "Size"); + + for(i = 0; i < arrlen(fc->entries); i++) { + if(strcmp(fc->entries[i]->name, ".") == 0 || strcmp(fc->entries[i]->name, "..") == 0) continue; + if(fc->entries[i]->type == MwDIRECTORY_DIRECTORY) { + char date[128]; + char* n = MwACPToUTF8(fc->entries[i]->name); + + MwStringTime(date, fc->entries[i]->mtime); + + index = MwListBoxSet(fc->files, -1, 0, n); + MwListBoxSet(fc->files, index, -1, date); + MwListBoxSet(fc->files, index, -1, NULL); + MwListBoxSetIcon(fc->files, index, fc->dir); + + free(n); + + arrput(fc->sorted_entries, fc->entries[i]); + } + } + for(i = 0; i < arrlen(fc->entries); i++) { + if(fc->entries[i]->type == MwDIRECTORY_FILE && !fc->dir_only) { + char date[128]; + char size[128]; + char* n = MwACPToUTF8(fc->entries[i]->name); + + MwStringTime(date, fc->entries[i]->mtime); + MwStringSize(size, fc->entries[i]->size); + + index = MwListBoxSet(fc->files, -1, 0, n); + MwListBoxSet(fc->files, index, -1, date); + MwListBoxSet(fc->files, index, -1, size); + MwListBoxSetIcon(fc->files, index, fc->file); + + free(n); + + arrput(fc->sorted_entries, fc->entries[i]); + } + } +} + +static void setup_fallback_filechooser(MwWidget window, int dir) { + char* path; + MwLLPixmap icon; + filechooser_t* fc = malloc(sizeof(*fc)); + memset(fc, 0, sizeof(*fc)); + + fc->history_seek = 0; + + fc->dir = MwLoadIcon(window, MwIconDirectory); + fc->file = MwLoadIcon(window, MwIconFile); + fc->back = MwLoadIcon(window, MwIconBack); + fc->forward = MwLoadIcon(window, MwIconForward); + fc->up = MwLoadIcon(window, MwIconUp); + fc->computer = MwLoadIcon(window, MwIconComputer); + fc->dir_only = dir; + + icon = MwLoadIcon(window, MwIconSearch); + MwVaApply(window, + MwNiconPixmap, icon, + NULL); + + window->opaque = fc; + + window->destroy_inject = destroy; + + layout(window); + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(window, MwNcloseHandler, cancel_window, NULL); + + path = MwDirectoryCurrent(); + scan(window, path, 1); + free(path); + + MwLLBeginStateChange(window->lowlevel); + MwLLMakePopup(window->lowlevel, window == NULL ? NULL : window->lowlevel); + MwLLEndStateChange(window->lowlevel); +} + +MwWidget MwFileChooserEx(MwWidget handle, const char* title, int dir) { + MwWidget window; + int w, h; + int wx; + int wy; + + w = 700; + h = w * 2 / 3; + + if(handle == NULL) { + wx = wy = MwDEFAULT; + } else { + wx = MwGetInteger(handle, MwNx) + (MwGetInteger(handle, MwNwidth) - w) / 2; + wy = MwGetInteger(handle, MwNy) + (MwGetInteger(handle, MwNheight) - h) / 2; + } + + window = MwVaCreateWidget(MwWindowClass, "filechooser", NULL, wx, wy, w, h, + MwNtitle, title, + NULL); + if(handle != NULL) MwReparent(window, handle); + + setup_fallback_filechooser(window, dir); + + return window; +} + +MwWidget MwFileChooser(MwWidget handle, const char* title) { + return MwFileChooserEx(handle, title, 0); +} diff --git a/widget/milsko/milskosrc/src/dialog/messagebox.c b/widget/milsko/milskosrc/src/dialog/messagebox.c new file mode 100644 index 0000000000..6a96f6d2f7 --- /dev/null +++ b/widget/milsko/milskosrc/src/dialog/messagebox.c @@ -0,0 +1,137 @@ +#include + +#include "../external/stb_ds.h" + +typedef struct msgbox { + int key; + MwWidget value; +} msgbox_t; + +static void spawn_button(MwWidget handle, int x, int y, int id, const char* text) { + msgbox_t* mb = handle->opaque; + MwWidget widget = MwVaCreateWidget(MwButtonClass, text, handle, x, y, 80, 24, + MwNtext, text, + NULL); + + hmput(mb, id, widget); + + handle->opaque = mb; +} + +static void messagebox_destroy_inject(MwWidget handle) { + void* px; + + if((px = MwGetVoid(handle, MwNpixmap)) != NULL) MwLLDestroyPixmap(px); +} + +static void MWAPI messagebox_close(MwWidget handle, void* user, void* call) { + (void)user; + (void)call; + MwDestroyWidget(handle); +} + +MwWidget MwMessageBox(MwWidget handle, const char* text, const char* title, unsigned int flag) { + MwWidget window; + int w, h; + int left = 8; + int th; + int x = 0; + int wx; + int wy; + MwSizeHints sh; + + w = 512; + h = 32 * 4; + + if(handle == NULL) { + wx = wy = MwDEFAULT; + } else { + wx = MwGetInteger(handle, MwNx) + (MwGetInteger(handle, MwNwidth) - w) / 2; + wy = MwGetInteger(handle, MwNy) + (MwGetInteger(handle, MwNheight) - h) / 2; + } + + sh.min_width = sh.max_width = w; + sh.min_height = sh.max_height = h; + + window = MwVaCreateWidget(MwWindowClass, "messagebox", NULL, wx, wy, w, h, + MwNtitle, title, + MwNsizeHints, &sh, + NULL); + if(handle != NULL) MwReparent(window, handle); + + window->opaque = NULL; + + if(flag & MwMB_BUTTONOK) spawn_button(window, w - (x += 8 + 80), h - 8 - 24, MwMB_BUTTONOK, "OK"); + if(flag & MwMB_BUTTONCANCEL) spawn_button(window, w - (x += 8 + 80), h - 8 - 24, MwMB_BUTTONCANCEL, "Cancel"); + + if(flag & MwMB_BUTTONNO) spawn_button(window, w - (x += 8 + 80), h - 8 - 24, MwMB_BUTTONNO, "No"); + if(flag & MwMB_BUTTONYES) spawn_button(window, w - (x += 8 + 80), h - 8 - 24, MwMB_BUTTONYES, "Yes"); + + if((flag & MwMB_ICONMASK) != 0) { + MwWidget icon; + MwLLPixmap px; + MwU32* data = NULL; + + icon = MwCreateWidget(MwImageClass, "image", window, 8, (h - 48) / 2, 48, 48); + + switch(flag & MwMB_ICONMASK) { + case MwMB_ICONWARNING: + { + data = MwIconWarning; + break; + } + case MwMB_ICONINFO: + { + data = MwIconInfo; + break; + } + case MwMB_ICONNOTE: + { + data = MwIconNote; + break; + } + case MwMB_ICONNEWS: + { + data = MwIconNews; + break; + } + case MwMB_ICONERROR: + { + data = MwIconError; + break; + } + case MwMB_ICONCLOCK: + { + data = MwIconClock; + break; + } + } + + px = MwLoadIcon(icon, data); + + MwSetVoid(icon, MwNpixmap, px); + + left = 8 + 48 + 8; + } + + th = MwTextHeight(handle, NULL, text); + (void)MwVaCreateWidget(MwLabelClass, "label", window, left, (h - th) / 2, w - left - 8, th, + MwNtext, text, + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + + MwLLBeginStateChange(window->lowlevel); + MwLLMakePopup(window->lowlevel, handle == NULL ? NULL : handle->lowlevel); + MwLLEndStateChange(window->lowlevel); + + MwAddUserHandler(window, MwNcloseHandler, messagebox_close, NULL); + window->destroy_inject = messagebox_destroy_inject; + + return window; +} + +MwWidget MwMessageBoxGetChild(MwWidget handle, int child) { + msgbox_t* mb = handle->opaque; + + return hmget(mb, child); +} diff --git a/widget/milsko/milskosrc/src/draw.c b/widget/milsko/milskosrc/src/draw.c new file mode 100644 index 0000000000..ce86d90161 --- /dev/null +++ b/widget/milsko/milskosrc/src/draw.c @@ -0,0 +1,969 @@ +#include + +#ifdef NO_IMAGE +#elif defined(USE_STB_IMAGE) +#include "../external/stb_image.h" +#else +#include +#include +#include +#endif + +#include "../external/stb_ds.h" + +static int get_color_diff(MwWidget handle) { + if(MwGetInteger(handle, MwNmodernLook)) { + return 40; + } else { + return 80; + } +} + +static int hex(const char* txt, int len) { + int i; + int r = 0; + for(i = 0; i < len; i++) { + char c = txt[i]; + int n = 0; + if('a' <= c && c <= 'f') { + n = c - 'a' + 10; + } else if('A' <= c && c <= 'F') { + n = c - 'A' + 10; + } else if('0' <= c && c <= 'g') { + n = c - '0'; + } + r = r << 4; + r |= n; + } + return r; +} + +static void color_set_disabled_if_disabled(MwWidget handle, MwLLColor rgb) { + if(MwGetInteger(handle, MwNdisabled) == 1) { + MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); + + if(c != NULL) { + rgb->common.red = rgb->common.red + (c->common.red - rgb->common.red) * 0.5; + rgb->common.green = rgb->common.green + (c->common.green - rgb->common.green) * 0.5; + rgb->common.blue = rgb->common.blue + (c->common.blue - rgb->common.blue) * 0.5; + MwLLColorUpdate(handle->lowlevel, rgb, rgb->common.red, rgb->common.green, rgb->common.blue); + + MwLLFreeColor(c); + } + } +}; + +void MwParseColorNoAllocate(const char* text, MwRGB* rgb) { + if(text[0] == '#' && strlen(text) == 4) { + rgb->red = hex(text + 1, 1); + rgb->green = hex(text + 2, 1); + rgb->blue = hex(text + 3, 1); + + rgb->red |= rgb->red << 4; + rgb->green |= rgb->green << 4; + rgb->blue |= rgb->blue << 4; + } else if(text[0] == '#' && strlen(text) == 7) { + rgb->red = hex(text + 1, 2); + rgb->green = hex(text + 3, 2); + rgb->blue = hex(text + 5, 2); + } else { + MwParseColorNameNoAllocate(text, rgb); + return; + } +} + +MwLLColor MwParseColor(MwWidget handle, const char* text) { + MwRGB rgb; + + rgb.red = 0; + rgb.green = 0; + rgb.blue = 0; + + MwParseColorNoAllocate(text, &rgb); + + return MwLLAllocColor(handle->lowlevel, rgb.red, rgb.green, rgb.blue); +} + +MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b) { + int cr = color->common.red + r; + int cg = color->common.green + g; + int cb = color->common.blue + b; + + if(cr < 0) cr = 0; + if(cg < 0) cg = 0; + if(cb < 0) cb = 0; + if(cr > 255) cr = 255; + if(cg > 255) cg = 255; + if(cb > 255) cb = 255; + + return MwLLAllocColor(handle->lowlevel, cr, cg, cb); +} + +void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { + MwPoint p[4]; + + p[0].x = rect->x; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width; + p[1].y = rect->y; + + p[2].x = rect->x + rect->width; + p[2].y = rect->y + rect->height; + + p[3].x = rect->x; + p[3].y = rect->y + rect->height; + + MwLLPolygon(handle->lowlevel, p, 4, color); +} + +void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { + MwLLPixmap pixmap; + int y; + double darken = 0.; + int ColorDiff = get_color_diff(handle); + double darkenStep = (ColorDiff / 2.) / rect->height; + unsigned long sz = 1 * rect->height * 4; + unsigned char* data = malloc(sz); + MwRect r = *rect; + if(rect->width <= 0 || rect->height <= 0) { + free(data); + return; + } + memset(data, 0, sz); + + r.x += 1; + r.y += 1; + r.width -= 2; + r.height -= 2; + + for(y = 0; y < rect->height; y++) { + MwLLColor col = MwLightenColor(handle, color, -darken, -darken, -darken); + int idx = y * 4; + color_set_disabled_if_disabled(handle, col); + data[idx] = col->common.red; + data[idx + 1] = col->common.green; + data[idx + 2] = col->common.blue; + data[idx + 3] = 255; + MwLLFreeColor(col); + darken += darkenStep; + } + + pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + MwLLDestroyPixmap(pixmap); + + free(data); +} + +void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { + MwDrawFrameWithBorder(handle, rect, color, invert, MwDefaultBorderWidth(handle)); +} + +static int translate_border(MwWidget handle, int border) { + if(border == MwDEFAULT) return MwDefaultBorderWidth(handle); + + return border; +} + +void MwDrawFrameWithBorder(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border) { + int inv; + + border = translate_border(handle, border); + + if((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv) invert = 1; + if(MwGetInteger(handle, MwNmodernLook)) { + MwDrawFrameEx(handle, rect, color, invert, border, 0, 0); + } else { + int diff = get_color_diff(handle) / 3 * 2; + + if(border >= 2) { + int i; + int st = invert ? 1 : 0; + for(i = st; i < st + 2; i++) { + if((i % 2) == 0) MwDrawFrameEx(handle, rect, color, invert, border - 1, -diff, (handle->parent == NULL || handle->parent->lowlevel == NULL) ? 1 : 0); + if((i % 2) == 1) MwDrawFrameEx(handle, rect, color, invert, 1, diff, 0); + } + } else { + MwDrawFrameEx(handle, rect, color, invert, border, 0, 0); + } + } +} + +void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border) { + MwLLColor col; + + if(rect->width <= 0 || rect->height <= 0) return; + + if(border) { + if(!handle->lowlevel->common.supports_transparency) { + MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); + + if(c != NULL) { + MwDrawRect(handle, rect, c); + MwLLFreeColor(c); + } + } + + MwDrawFrameWithBorder(handle, rect, color, invert, border); + + if(border == MwDEFAULT) { + int d = MwDefaultBorderWidth(handle) - MwDefaultThinBorderWidth(handle); + + rect->x -= d; + rect->y -= d; + rect->width += d * 2; + rect->height += d * 2; + } + } + + if(rect->width <= 0 || rect->height <= 0) return; + + col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); + color_set_disabled_if_disabled(handle, col); + + if(MwGetInteger(handle, MwNmodernLook)) { + MwDrawRectFading(handle, rect, col); + } else { + MwDrawRect(handle, rect, col); + } + MwLLFreeColor(col); +} + +void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { + MwPoint p[6]; + int border = MwDefaultBorderWidth(handle); + int ColorDiff = get_color_diff(handle) + (MwGetInteger(handle, MwNmodernLook) ? 48 : 0); + MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); + MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); + MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); + color_set_disabled_if_disabled(handle, col); + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); + + p[0].x = rect->x; + p[0].y = rect->y + rect->height / 2; + + p[1].x = rect->x + rect->width / 2; + p[1].y = rect->y; + + p[2].x = rect->x + rect->width; + p[2].y = rect->y + rect->height / 2; + + p[3].x = rect->x + rect->width - border; + p[3].y = rect->y + rect->height / 2; + + p[4].x = rect->x + rect->width / 2; + p[4].y = rect->y + border; + + p[5].x = rect->x + border; + p[5].y = rect->y + rect->height / 2; + + MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); + + p[0].x = rect->x; + p[0].y = rect->y + rect->height / 2; + + p[1].x = rect->x + rect->width / 2; + p[1].y = rect->y + rect->height; + + p[2].x = rect->x + rect->width; + p[2].y = rect->y + rect->height / 2; + + p[3].x = rect->x + rect->width - border; + p[3].y = rect->y + rect->height / 2; + + p[4].x = rect->x + rect->width / 2; + p[4].y = rect->y + rect->height - border; + + p[5].x = rect->x + border; + p[5].y = rect->y + rect->height / 2; + + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + + p[0].x = rect->x + rect->width / 2; + p[0].y = rect->y + border; + + p[1].x = rect->x + rect->width - border; + p[1].y = rect->y + rect->height / 2; + + p[2].x = rect->x + rect->width / 2; + p[2].y = rect->y + rect->height - border; + + p[3].x = rect->x + border; + p[3].y = rect->y + rect->height / 2; + + MwLLPolygon(handle->lowlevel, p, 4, col); + + MwLLFreeColor(col); + MwLLFreeColor(lighter); + MwLLFreeColor(darker); +} + +static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { + MwPoint p[7]; + int ColorDiff = get_color_diff(handle); + MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); + MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, ColorDiff - diff, ColorDiff - diff, ColorDiff - diff); + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); + + p[0].x = rect->x; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width; + p[1].y = rect->y; + + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + border; + p[3].x = rect->x + border; + p[3].y = rect->y + border; + + p[4].x = rect->x + border; + p[4].y = rect->y + rect->height - border; + + p[5].x = rect->x; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); + + p[0].x = rect->x + rect->width; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width - border; + p[1].y = rect->y + border; + + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + rect->height - border; + + p[3].x = rect->x + border; + p[3].y = rect->y + rect->height - border; + + p[4].x = rect->x; + p[4].y = rect->y + rect->height; + + p[5].x = rect->x + rect->width; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + + MwLLFreeColor(lighter); + MwLLFreeColor(darker); + + rect->x += border; + rect->y += border; + rect->width -= border * 2; + rect->height -= border * 2; +} + +static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same) { + MwPoint p[7]; + + (void)diff; + (void)same; + + p[0].x = rect->x; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width; + p[1].y = rect->y; + + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + border; + p[3].x = rect->x + border; + p[3].y = rect->y + border; + + p[4].x = rect->x + border; + p[4].y = rect->y + rect->height - border; + + p[5].x = rect->x; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + + p[0].x = rect->x + rect->width; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width - border; + p[1].y = rect->y + border; + + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + rect->height - border; + + p[3].x = rect->x + border; + p[3].y = rect->y + rect->height - border; + + p[4].x = rect->x; + p[4].y = rect->y + rect->height; + + p[5].x = rect->x + rect->width; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); +} + +static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { + int ColorDiff = get_color_diff(handle); + MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); + MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff); + MwRect r = *rect; + + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); + + frame_border_complex(handle, rect, lighter, darker, invert, border == 1 ? 1 : (border / 2), diff, same); + + if(border > 1) { + r.x += border / 2; + r.y += border / 2; + r.width -= border; + r.height -= border; + frame_border_complex(handle, &r, lighter, darker, !invert, border / 2, diff, same); + } + + MwLLFreeColor(lighter); + MwLLFreeColor(darker); + + rect->x += border; + rect->y += border; + rect->width -= border * 2; + rect->height -= border * 2; +} + +void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { + border = translate_border(handle, border); + + if(MwGetInteger(handle, MwNmodernLook)) { + MwDrawFrameEx_complex(handle, rect, color, invert, border, diff, same); + } else { + MwDrawFrameEx_simple(handle, rect, color, invert, border, diff, same); + } +} + +void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int direction) { + MwPoint p1[4], p2[4], p3[4], p4[3]; + const int border = MwGetInteger(handle, MwNmodernLook) ? 2 : MwDefaultBorderWidth(handle); + int ColorDiff = get_color_diff(handle); + MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); + MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); + MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : MwLightenColor(handle, color, 0, 0, 0); + double deg = 30 * ((direction == MwEAST || direction == MwWEST) ? 2 : 1); + double c = cos(deg / 180 * M_PI); + double s = sin(deg / 180 * M_PI); + + color_set_disabled_if_disabled(handle, col); + color_set_disabled_if_disabled(handle, darker); + color_set_disabled_if_disabled(handle, lighter); + + if(direction == MwNORTH) { + p1[0].x = rect->x + rect->width / 2; + p1[0].y = rect->y; + + p1[1].x = rect->x; + p1[1].y = rect->y + rect->height; + + p1[2].x = rect->x + c * border; + p1[2].y = rect->y + rect->height - s * border; + + p1[3].x = rect->x + rect->width / 2; + p1[3].y = rect->y + border; + + p2[0].x = rect->x + rect->width / 2; + p2[0].y = rect->y; + + p2[1].x = rect->x + rect->width; + p2[1].y = rect->y + rect->height; + + p2[2].x = rect->x + rect->width - c * border; + p2[2].y = rect->y + rect->height - s * border; + + p2[3].x = rect->x + rect->width / 2; + p2[3].y = rect->y + border; + + p3[0].x = rect->x + c * border; + p3[0].y = rect->y + rect->height - s * border; + + p3[1].x = rect->x; + p3[1].y = rect->y + rect->height; + + p3[2].x = rect->x + rect->width; + p3[2].y = rect->y + rect->height; + + p3[3].x = rect->x + rect->width - c * border; + p3[3].y = rect->y + rect->height - s * border; + + MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter); + MwLLPolygon(handle->lowlevel, p2, 4, invert ? lighter : darker); + MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker); + + p4[0].x = rect->x + c * border; + p4[0].y = rect->y + rect->height - s * border; + + p4[1].x = rect->x + rect->width - c * border; + p4[1].y = rect->y + rect->height - s * border; + + p4[2].x = rect->x + rect->width / 2; + p4[2].y = rect->y + border; + } else if(direction == MwSOUTH) { + p1[0].x = rect->x; + p1[0].y = rect->y; + + p1[1].x = rect->x + c * border; + p1[1].y = rect->y + s * border; + + p1[2].x = rect->x + rect->width - c * border; + p1[2].y = rect->y + s * border; + + p1[3].x = rect->x + rect->width; + p1[3].y = rect->y; + + p2[0].x = rect->x; + p2[0].y = rect->y; + + p2[1].x = rect->x + c * border; + p2[1].y = rect->y + s * border; + + p2[2].x = rect->x + rect->width / 2; + p2[2].y = rect->y + rect->height - border; + + p2[3].x = rect->x + rect->width / 2; + p2[3].y = rect->y + rect->height; + + p3[0].x = rect->x + rect->width; + p3[0].y = rect->y; + + p3[1].x = rect->x + rect->width / 2; + p3[1].y = rect->y + rect->height; + + p3[2].x = rect->x + rect->width / 2; + p3[2].y = rect->y + rect->height - border; + + p3[3].x = rect->x + rect->width - c * border; + p3[3].y = rect->y + s * border; + + MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter); + MwLLPolygon(handle->lowlevel, p2, 4, invert ? darker : lighter); + MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker); + + p4[0].x = rect->x + c * border; + p4[0].y = rect->y + s * border; + + p4[1].x = rect->x + rect->width - c * border; + p4[1].y = rect->y + s * border; + + p4[2].x = rect->x + rect->width / 2; + p4[2].y = rect->y + rect->height - border; + } else if(direction == MwEAST) { + p1[0].x = rect->x; + p1[0].y = rect->y; + + p1[1].x = rect->x + c * border; + p1[1].y = rect->y + s * border; + + p1[2].x = rect->x + c * border; + p1[2].y = rect->y + rect->height - s * border; + + p1[3].x = rect->x; + p1[3].y = rect->y + rect->height; + + p2[0].x = rect->x; + p2[0].y = rect->y; + + p2[1].x = rect->x + rect->width; + p2[1].y = rect->y + rect->height / 2; + + p2[2].x = rect->x + rect->width - border; + p2[2].y = rect->y + rect->height / 2; + + p2[3].x = rect->x + c * border; + p2[3].y = rect->y + s * border; + + p3[0].x = rect->x + c * border; + p3[0].y = rect->y + rect->height - s * border; + + p3[1].x = rect->x; + p3[1].y = rect->y + rect->height; + + p3[2].x = rect->x + rect->width; + p3[2].y = rect->y + rect->height / 2; + + p3[3].x = rect->x + rect->width - border; + p3[3].y = rect->y + rect->height / 2; + + MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter); + MwLLPolygon(handle->lowlevel, p2, 4, invert ? darker : lighter); + MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker); + + p4[0].x = rect->x + rect->width - border; + p4[0].y = rect->y + rect->height / 2; + + p4[1].x = rect->x + c * border; + p4[1].y = rect->y + rect->height - s * border; + + p4[2].x = rect->x + c * border; + p4[2].y = rect->y + s * border; + } else if(direction == MwWEST) { + p1[0].x = rect->x; + p1[0].y = rect->y + rect->height / 2; + + p1[1].x = rect->x + border; + p1[1].y = rect->y + rect->height / 2; + + p1[2].x = rect->x + rect->width - c * border; + p1[2].y = rect->y + s * border; + + p1[3].x = rect->x + rect->width; + p1[3].y = rect->y; + + p2[0].x = rect->x; + p2[0].y = rect->y + rect->height / 2; + + p2[1].x = rect->x + border; + p2[1].y = rect->y + rect->height / 2; + + p2[2].x = rect->x + rect->width - c * border; + p2[2].y = rect->y + rect->height - s * border; + + p2[3].x = rect->x + rect->width; + p2[3].y = rect->y + rect->height; + + p3[0].x = rect->x + rect->width; + p3[0].y = rect->y; + + p3[1].x = rect->x + rect->width - c * border; + p3[1].y = rect->y + s * border; + + p3[2].x = rect->x + rect->width - c * border; + p3[2].y = rect->y + rect->height - s * border; + + p3[3].x = rect->x + rect->width; + p3[3].y = rect->y + rect->height; + + MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter); + MwLLPolygon(handle->lowlevel, p2, 4, invert ? lighter : darker); + MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker); + + p4[0].x = rect->x + border; + p4[0].y = rect->y + rect->height / 2; + + p4[1].x = rect->x + rect->width - c * border; + p4[1].y = rect->y + rect->height - s * border; + + p4[2].x = rect->x + rect->width - c * border; + p4[2].y = rect->y + s * border; + } + MwLLPolygon(handle->lowlevel, p4, 3, col); + + MwLLFreeColor(col); + MwLLFreeColor(lighter); + MwLLFreeColor(darker); +} + +#if defined(NO_IMAGE) +#elif !defined(USE_STB_IMAGE) +static void PNGCAPI user_error(png_structp png, const char* str) { + (void)str; + + longjmp(png_jmpbuf(png), 1); +} + +static void PNGCAPI user_warning(png_structp png, const char* str) { + (void)png; + (void)str; +} + +static unsigned char* load_png(FILE* f, int* w, int* h) { + png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_infop info = png_create_info_struct(png); + int depth, type, i; + unsigned char* data; + unsigned char* row; + + if(setjmp(png_jmpbuf(png))) { + png_destroy_read_struct(&png, &info, NULL); + return NULL; + } + + png_set_error_fn(png, NULL, user_error, user_warning); + + png_init_io(png, f); + png_read_info(png, info); + + *w = png_get_image_width(png, info); + *h = png_get_image_height(png, info); + depth = png_get_bit_depth(png, info); + type = png_get_color_type(png, info); + + if(depth == 16) png_set_strip_16(png); + if(type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); + if(type == PNG_COLOR_TYPE_GRAY && depth < 8) png_set_expand_gray_1_2_4_to_8(png); + if(png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); + if(type == PNG_COLOR_TYPE_RGB || type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_PALETTE) png_set_filler(png, 0xFF, PNG_FILLER_AFTER); + if(type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); + png_read_update_info(png, info); + + data = malloc((*w) * (*h) * 4); + + row = malloc(png_get_rowbytes(png, info)); + for(i = 0; i < (*h); i++) { + png_read_row(png, row, NULL); + memcpy(&data[i * (*w) * 4], row, png_get_rowbytes(png, info)); + } + free(row); + + png_destroy_read_struct(&png, &info, NULL); + + return data; +} + +static void jpeg_err(j_common_ptr cinfo) { + jmp_buf* j = cinfo->client_data; + + longjmp(*j, 1); +} + +static unsigned char* load_jpeg(FILE* f, int* w, int* h) { + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + jmp_buf* j = malloc(sizeof(*j)); + unsigned char* data; + unsigned char* row; + int i; + + if(setjmp(*j)) { + jpeg_destroy_decompress(&cinfo); + free(j); + return NULL; + } + + cinfo.client_data = j; + cinfo.err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_err; + + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, f); + jpeg_read_header(&cinfo, TRUE); + + jpeg_start_decompress(&cinfo); + + *w = cinfo.output_width; + *h = cinfo.output_height; + + data = malloc((*w) * (*h) * 4); + row = malloc((*h) * cinfo.num_components); + for(i = 0; i < (*h); i++) { + int j; + jpeg_read_scanlines(&cinfo, &row, 1); + + for(j = 0; j < (*w); j++) { + unsigned char* from = &row[j * cinfo.num_components]; + unsigned char* to = &data[(i * (*w) + j) * 4]; + + memcpy(to, from, 3); + to[3] = 255; + } + } + free(row); + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + free(j); + + return data; +} +#endif + +static unsigned char* load_image(const char* path, int* w, int* h) { +#if defined(NO_IMAGE) + return NULL; +#elif defined(USE_STB_IMAGE) + int ch; + + return stbi_load(path, w, h, &ch, 4); +#else + FILE* f = fopen(path, "rb"); + unsigned char* d; + if(f == NULL) return NULL; + + if((d = load_png(f, w, h)) != NULL) return d; + fseek(f, 0, SEEK_SET); + + if((d = load_jpeg(f, w, h)) != NULL) return d; + fseek(f, 0, SEEK_SET); + + fclose(f); + + return NULL; +#endif +} + +MwLLPixmap MwLoadImage(MwWidget handle, const char* path) { + int width, height; + unsigned char* rgb = load_image(path, &width, &height); + MwLLPixmap px; + + if(rgb == NULL) return NULL; + + px = MwLoadRaw(handle, rgb, width, height); + + free(rgb); + + return px; +} + +MwLLPixmap MwLoadRaw(MwWidget handle, unsigned char* rgb, int width, int height) { + MwLLPixmap px = MwLLCreatePixmap(handle->lowlevel, rgb, width, height); + + px->common.user = handle; + MwPixmapReloadRaw(px, rgb); + + return px; +} + +void MwPixmapReloadRaw(MwLLPixmap px, unsigned char* rgb) { + int i; + MwWidget handle = px->common.user; + MwLLColor base = handle->bgcolor == NULL ? MwParseColor(handle, MwGetText(handle, MwNbackground)) : handle->bgcolor; + + memset(px->common.raw, 0, px->common.width * px->common.height * 4); + for(i = 0; i < px->common.width * px->common.height; i++) { + unsigned char* pin = &rgb[i * 4]; + unsigned char* pout = &px->common.raw[i * 4]; + double a = pin[3]; + + a /= 255; + if(a != 0) { + pout[0] = pin[0] * a; + pout[1] = pin[1] * a; + pout[2] = pin[2] * a; + + pout[0] += base->common.red * (1 - a); + pout[1] += base->common.green * (1 - a); + pout[2] += base->common.blue * (1 - a); + pout[3] = 255; + } + } + + if(handle->bgcolor == NULL) MwLLFreeColor(base); + + MwLLPixmapUpdate(px); +} + +unsigned char* MwPixmapGetRaw(MwLLPixmap pixmap) { + return pixmap->common.raw; +} + +void MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect) { + rect->width = pixmap->common.width; + rect->height = pixmap->common.height; +} + +void MwColorGet(MwLLColor color, int* red, int* green, int* blue) { + *red = color->common.red; + *green = color->common.green; + *blue = color->common.blue; +} + +MwLLPixmap MwLoadIcon(MwWidget handle, MwU32* data) { + int width = (data[0] >> 16) & 0xffff; + int height = (data[0]) & 0xffff; + unsigned char* rgba = malloc(width * height * 4); + MwLLPixmap px; + int i; + + memset(rgba, 0, width * height * 4); + + for(i = 0; i < width * height; i++) { + unsigned char* px = &rgba[i * 4]; + + px[0] = (data[i + 1] >> 24) & 0xff; + px[1] = (data[i + 1] >> 16) & 0xff; + px[2] = (data[i + 1] >> 8) & 0xff; + px[3] = data[i + 1] & 0xff; + } + + px = MwLoadRaw(handle, rgba, width, height); + + free(rgba); + + return px; +} + +typedef struct color { + char* key; + char* value; + int r; + int g; + int b; + int a; +} color_t; + +MwLLPixmap MwLoadXPM(MwWidget handle, char** data) { + int col, row, colors, cpp; + unsigned char* rgb; + MwLLPixmap px; + color_t* c = NULL; + int i, y, x; + char* comp; + + sh_new_strdup(c); + + sscanf(data[0], "%d %d %d %d", &col, &row, &colors, &cpp); + + for(i = 0; i < colors; i++) { + char k[128]; + char* v = data[i + 1] + cpp + 3; + int ind; + if(strcmp(v, "None") == 0) { + memcpy(k, data[i + 1], cpp); + k[cpp] = 0; + + shput(c, k, v); + ind = shgeti(c, k); + + c[ind].r = 0; + c[ind].g = 0; + c[ind].b = 0; + c[ind].a = 0; + } else { + MwLLColor color = MwParseColor(handle, v); + + memcpy(k, data[i + 1], cpp); + k[cpp] = 0; + + shput(c, k, v); + ind = shgeti(c, k); + + c[ind].r = color->common.red; + c[ind].g = color->common.green; + c[ind].b = color->common.blue; + c[ind].a = 255; + + MwLLFreeColor(color); + } + } + + rgb = malloc(row * col * 4); + comp = malloc(cpp + 1); + comp[cpp] = 0; + for(y = 0; y < row; y++) { + for(x = 0; x < col; x++) { + unsigned char* pout = &rgb[(y * col + x) * 4]; + color_t colent; + memcpy(comp, &data[1 + colors + y][x * cpp], cpp); + + colent = shgets(c, comp); + + pout[0] = colent.r; + pout[1] = colent.g; + pout[2] = colent.b; + pout[3] = colent.a; + } + } + free(comp); + + px = MwLoadRaw(handle, rgb, col, row); + + free(rgb); + + shfree(c); + + return px; +} diff --git a/widget/milsko/milskosrc/src/icon/back.c b/widget/milsko/milskosrc/src/icon/back.c new file mode 100644 index 0000000000..20f2c5c7b4 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/back.c @@ -0,0 +1,445 @@ +#include + +MwU32 MwIconBack[] = { + (20 << 16) | 22, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x666666FF, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x666666FF, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x666666FF, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x666666FF, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x999999FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x666666FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/clock.c b/widget/milsko/milskosrc/src/icon/clock.c new file mode 100644 index 0000000000..ccdafef47d --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/clock.c @@ -0,0 +1,2309 @@ +#include + +MwU32 MwIconClock[] = { + (48 << 16) | 48, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000022, + 0x0000004F, + 0x0000006C, + 0x00000077, + 0x0000006A, + 0x0000004B, + 0x00000021, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000024, + 0x00000084, + 0x000000E2, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000DC, + 0x0000008C, + 0x00000023, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001B, + 0x000000AB, + 0x000000FE, + 0x010303FF, + 0x163C3DFF, + 0x327B7CFF, + 0x48A6A7FF, + 0x58C0C1FF, + 0x62CACBFF, + 0x67C8C9FF, + 0x5FB0B0FF, + 0x4C8687FF, + 0x2A4747FF, + 0x030606FF, + 0x000000FD, + 0x000000A5, + 0x0000001A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x0000006C, + 0x000000F2, + 0x020708FF, + 0x216364FF, + 0x43B4B6FF, + 0x52CBCDFF, + 0x5AD0D1FF, + 0x61D4D5FF, + 0x69D8D9FF, + 0x71DCDDFF, + 0x79E0E1FF, + 0x81E4E5FF, + 0x88E8E9FF, + 0x90ECEDFF, + 0x8AD9DAFF, + 0x4D7676FF, + 0x060909FF, + 0x000000F2, + 0x00000074, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000D, + 0x000000AB, + 0x000000FF, + 0x113738FF, + 0x3AABACFF, + 0x4AC7C9FF, + 0x52CBCDFF, + 0x5AD0D1FF, + 0x61D4D5FF, + 0x69D8D9FF, + 0x71DCDDFF, + 0x79E0E1FF, + 0x81E4E5FF, + 0x88E8E9FF, + 0x90ECEDFF, + 0x98F0F1FF, + 0xA0F4F5FF, + 0xA8F8F9FF, + 0x99DCDDFF, + 0x374F4FFF, + 0x000000FF, + 0x000000BC, + 0x00000013, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001D, + 0x000000D4, + 0x030707FF, + 0x4D9899FF, + 0x8CE4E5FF, + 0xABF0F0FF, + 0xBBF4F5FF, + 0xC2F5F5FF, + 0xBDF2F3FF, + 0xAEECEDFF, + 0x96E6E6FF, + 0x7BE1E2FF, + 0x81E4E5FF, + 0x88E8E9FF, + 0x90ECEDFF, + 0x98F0F1FF, + 0xA0F4F5FF, + 0xA8F8F9FF, + 0xAFFCFDFF, + 0xB0FBFCFF, + 0xAAF6F7FF, + 0x699A9BFF, + 0x050707FF, + 0x000000DD, + 0x0000002C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000028, + 0x000000E2, + 0x162828FF, + 0x7ED4D6FF, + 0x86E2E2FF, + 0x7DDEDEFF, + 0x81DEDFFF, + 0x91E3E4FF, + 0xB1EDEFFF, + 0xD3F8F8FF, + 0xE0FAFAFF, + 0xE9FCFCFF, + 0xE8FAFBFF, + 0xC0F3F4FF, + 0x93EDEEFF, + 0x98F0F1FF, + 0xA0F4F5FF, + 0xA8F8F9FF, + 0xAFFCFDFF, + 0xB0FBFCFF, + 0xAAF6F7FF, + 0xA4F1F2FF, + 0x9FECEDFF, + 0x79B7B8FF, + 0x101818FF, + 0x000000EC, + 0x00000029, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002D, + 0x000000EB, + 0x0C2325FF, + 0x54C3C6FF, + 0x42C6C8FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x49C8CAFF, + 0x8ADFE1FF, + 0xD7F6F6FF, + 0xFCFEFFFF, + 0xFAFDFDFF, + 0xE5FAFAFF, + 0xB4F5F6FF, + 0xA8F8F9FF, + 0xAFFCFDFF, + 0xB0FBFCFF, + 0xAAF6F7FF, + 0xA4F1F2FF, + 0x9FECEDFF, + 0x99E7E8FF, + 0x93E2E3FF, + 0x7DC4C5FF, + 0x0F1919FF, + 0x000000E3, + 0x0000001E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000014, + 0x000000DD, + 0x091A1BFF, + 0x3DBBBDFF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x89DDDFFF, + 0xE4F9F9FF, + 0xEBF8F8FF, + 0xE3F5F5FF, + 0xC7F8F8FF, + 0xB0FBFCFF, + 0xAAF6F7FF, + 0xA4F1F2FF, + 0x9FECEDFF, + 0x99E7E8FF, + 0x93E2E3FF, + 0x8DDDDEFF, + 0x87D9DAFF, + 0x6CAFB0FF, + 0x080E0EFF, + 0x000000D5, + 0x0000000A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000091, + 0x020505FF, + 0x35A3A5FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x3CB9BBFF, + 0x37A9ABFF, + 0x3BB7B9FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x49C9CBFF, + 0xAFEAEBFF, + 0xDAF3F3FF, + 0xD3F0F0FF, + 0xC0F0F1FF, + 0xA5F1F2FF, + 0x9FECEDFF, + 0x99E7E8FF, + 0x93E2E3FF, + 0x8DDDDEFF, + 0x87D8D9FF, + 0x82D4D5FF, + 0x7CCFD0FF, + 0x579696FF, + 0x010202FF, + 0x00000095, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001A, + 0x000000F7, + 0x1C5757FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x2A8283FF, + 0x0D2929FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x061314FF, + 0x1A5051FF, + 0x339EA0FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x83DEDFFF, + 0xCAEDEEFF, + 0xC4EBEBFF, + 0xB3E9EAFF, + 0x99E7E8FF, + 0x93E2E3FF, + 0x8DDDDEFF, + 0x87D9DAFF, + 0x82D4D5FF, + 0x7CCFD0FF, + 0x76CACBFF, + 0x70C5C6FF, + 0x305758FF, + 0x000000FE, + 0x00000049, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000067, + 0x000000FF, + 0x37ABACFF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x1D5859FF, + 0x000000FF, + 0x000000FF, + 0x1E1E2EFF, + 0x46466AFF, + 0x4E4E74FF, + 0x3A3A54FF, + 0x111119FF, + 0x000000FF, + 0x143C3DFF, + 0x38ACAEFF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x63D2D4FF, + 0xB8E8E8FF, + 0xB5E5E6FF, + 0xA1E3E3FF, + 0x8DDDDEFF, + 0x87D9DAFF, + 0x82D4D5FF, + 0x7CCFD0FF, + 0x76CACBFF, + 0x70C5C6FF, + 0x6AC0C1FF, + 0x62B6B7FF, + 0x101F20FF, + 0x000000DB, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000AB, + 0x0A1E1EFF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x2B8485FF, + 0x000000FF, + 0x0B0B11FF, + 0x7474B4FF, + 0xAAAAFFFF, + 0xADADFFFF, + 0xB1B1FFFF, + 0xB4B4FFFF, + 0xB3B3FBFF, + 0x8080B2FF, + 0x262634FF, + 0x030808FF, + 0x27797AFF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x5BCECFFF, + 0xAAE3E3FF, + 0xA5E0E1FF, + 0x90DADBFF, + 0x82D4D5FF, + 0x7CCFD0FF, + 0x76CACBFF, + 0x70C5C6FF, + 0x6AC0C1FF, + 0x65BBBCFF, + 0x5FB6B7FF, + 0x3E7C7DFF, + 0x000000FF, + 0x00000064, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000D6, + 0x133B3CFF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x0A1F1FFF, + 0x010102FF, + 0x7E7EC2FF, + 0xAAAAFFFF, + 0xB8B8FFFF, + 0xDEDEFFFF, + 0xEEEEFFFF, + 0xEDEDFFFF, + 0xE1E1FFFF, + 0xCACAFFFF, + 0xBEBEFDFF, + 0x6F6F94FF, + 0x060608FF, + 0x1C5757FF, + 0x3FC3C5FF, + 0x40C5C7FF, + 0x5BCDCFFF, + 0x9CDDDEFF, + 0x95DADBFF, + 0x7ED0D1FF, + 0x76CACBFF, + 0x70C5C6FF, + 0x6AC0C1FF, + 0x65BBBCFF, + 0x5FB6B7FF, + 0x59B1B2FF, + 0x53ACADFF, + 0x112526FF, + 0x000000E0, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000EA, + 0x194E4FFF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x34A1A3FF, + 0x000000FF, + 0x393959FF, + 0xA8A8FFFF, + 0xBDBDFFFF, + 0xFAFAFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFEFEFEFF, + 0x777777FF, + 0xD1D1E0FF, + 0xCCCCFFFF, + 0x9A9AC8FF, + 0x121218FF, + 0x194C4DFF, + 0x40C4C6FF, + 0x40C5C7FF, + 0x63CECFFF, + 0x8DD7D8FF, + 0x81D1D2FF, + 0x70C5C6FF, + 0x6AC0C1FF, + 0x65BBBCFF, + 0x5FB6B7FF, + 0x59B1B2FF, + 0x53ACADFF, + 0x4DA7A8FF, + 0x327273FF, + 0x000000FF, + 0x0000004E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FB, + 0x1F5F60FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x297F80FF, + 0x000000FF, + 0x7373B1FF, + 0xACACFFFF, + 0xF2F2FFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xF6F6FEFF, + 0xD4D4EBFF, + 0xE0E0FFFF, + 0x383838FF, + 0x6F6F72FF, + 0xFCFCFFFF, + 0xD7D7FFFF, + 0xAAAAD9FF, + 0x111116FF, + 0x1E5B5CFF, + 0x40C5C7FF, + 0x30A3A5FF, + 0x6CC6C7FF, + 0x7FD3D4FF, + 0x6EC4C6FF, + 0x65BBBCFF, + 0x5FB6B7FF, + 0x59B1B2FF, + 0x53ACADFF, + 0x4DA7A8FF, + 0x47A2A3FF, + 0x419B9CFF, + 0x060E0EFF, + 0x000000AA, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x236B6CFF, + 0x000000FF, + 0x9494E0FF, + 0xC0C0FFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xE5E5FFFF, + 0xBCBCF1FF, + 0x555556FF, + 0xABABD4FF, + 0x42424EFF, + 0x3F3F4EFF, + 0xDDDDFFFF, + 0xF5F5FFFF, + 0xDCDCFFFF, + 0xA3A3CDFF, + 0x09090BFF, + 0x1F6B6CFF, + 0x30A3A5FF, + 0x31A4A6FF, + 0x71CBCCFF, + 0x6DC9C9FF, + 0x5FB6B7FF, + 0x59B1B2FF, + 0x53ACADFF, + 0x4DA7A8FF, + 0x47A2A3FF, + 0x429D9EFF, + 0x3C9899FF, + 0x184040FF, + 0x000000F7, + 0x0000000E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x236B6CFF, + 0x000000FF, + 0xA6A6F6FF, + 0xCECEECFF, + 0xD4D4D4FF, + 0xEDEDFBFF, + 0xC4C4FFFF, + 0xC8C8FFFF, + 0x50505AFF, + 0x5A5A6BFF, + 0xBEBEE6FF, + 0x9B9BB9FF, + 0xD5D5FFFF, + 0xD6D6FFFF, + 0xEAEAFFFF, + 0xD9D9FFFF, + 0x7D7D9CFF, + 0x030A0AFF, + 0x298F90FF, + 0x2FA3A5FF, + 0x41ACAFFF, + 0x68CBCCFF, + 0x5AB6B7FF, + 0x53ACADFF, + 0x4DA7A8FF, + 0x47A2A3FF, + 0x429D9EFF, + 0x3C9899FF, + 0x369394FF, + 0x24696AFF, + 0x000000FF, + 0x00000046, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x297D7EFF, + 0x000000FF, + 0xA2A2ECFF, + 0xCCCCEAFF, + 0x8D8D8DFF, + 0x83838BFF, + 0xC3C3FAFF, + 0xCBCBFFFF, + 0x777790FF, + 0x0C0C0FFF, + 0xD2D2F8FF, + 0xDADAFFFF, + 0xDBDBFFFF, + 0xDADAFFFF, + 0xD8D8FFFF, + 0xE5E5FFFF, + 0xD2D2FFFF, + 0x404051FF, + 0x0E3232FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x54BBBCFF, + 0x57BCBEFF, + 0x4DA7A8FF, + 0x47A2A3FF, + 0x429D9EFF, + 0x3C9899FF, + 0x369394FF, + 0x308E8FFF, + 0x288283FF, + 0x000202FF, + 0x0000007C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x309597FF, + 0x000000FF, + 0x9494D5FF, + 0xD2D2FFFF, + 0xD5D5D5FF, + 0x5E5E64FF, + 0xA6A6CFFF, + 0xCFCFFFFF, + 0xB8B8DDFF, + 0x000000FF, + 0x9A9AB2FF, + 0xDFDFFFFF, + 0xE1E1FFFF, + 0xFBFBFFFF, + 0xFAFAFFFF, + 0xE3E3FFFF, + 0xD9D9FFFF, + 0xB3B3DDFF, + 0x050506FF, + 0x227A7CFF, + 0x2EA3A5FF, + 0x34A6A7FF, + 0x50C1C2FF, + 0x47A3A4FF, + 0x429D9EFF, + 0x3C9899FF, + 0x369394FF, + 0x308E8FFF, + 0x2A898AFF, + 0x258485FF, + 0x051516FF, + 0x000000B1, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x3EBFC1FF, + 0x020606FF, + 0x7171A2FF, + 0xCBCBFFFF, + 0xFFFFFFFF, + 0xC5C5FCFF, + 0xCCCCFFFF, + 0xD2D2FFFF, + 0xD8D8FFFF, + 0x2D2D34FF, + 0x51515CFF, + 0xE5E5FFFF, + 0xE8E8FFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFEFEFFFF, + 0xDEDEFFFF, + 0xD2D2FFFF, + 0x57576DFF, + 0x0B2626FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x43B3B5FF, + 0x42A7A8FF, + 0x3C9899FF, + 0x369394FF, + 0x308E8FFF, + 0x2A898AFF, + 0x258485FF, + 0x1F7F80FF, + 0x082727FF, + 0x000000D0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x113334FF, + 0x454562FF, + 0xBDBDFFFF, + 0xFDFDFFFF, + 0xCBCBFFFF, + 0xCECEFFFF, + 0xD4D4FFFF, + 0xDADAFFFF, + 0x79798AFF, + 0x050506FF, + 0x1F1F22FF, + 0x111112FF, + 0x111111FF, + 0x111111FF, + 0x0C0C0CFF, + 0xA4A4B0FF, + 0xD4D4FFFF, + 0xAEAED8FF, + 0x010101FF, + 0x268687FF, + 0x2DA3A5FF, + 0x32A7A7FF, + 0x3AADAFFF, + 0x369394FF, + 0x308E8FFF, + 0x2A898AFF, + 0x258485FF, + 0x1F7F80FF, + 0x197A7BFF, + 0x072E2EFF, + 0x000000E3, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x27797BFF, + 0x0D0D13FF, + 0xB5B5F7FF, + 0xECECFFFF, + 0xD2D2FFFF, + 0xCFCFFFFF, + 0xD6D6FFFF, + 0xDCDCFFFF, + 0xCDCDE6FF, + 0x0F0F10FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x343438FF, + 0xD6D6FFFF, + 0xCFCFFFFF, + 0x31313EFF, + 0x134445FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x33AAACFF, + 0x308E8FFF, + 0x2A898AFF, + 0x258485FF, + 0x1F7F80FF, + 0x197A7BFF, + 0x137576FF, + 0x063434FF, + 0x000000F6, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x3EBEC0FF, + 0x040D0DFF, + 0x7878A4FF, + 0xD3D3FFFF, + 0xDFDFFFFF, + 0xD0D0FFFF, + 0xD6D6FFFF, + 0xDDDDFFFF, + 0xE4E4FFFF, + 0xCECEE0FF, + 0xB1B1BBFF, + 0xB5B5BBFF, + 0xB6B6C1FF, + 0xBBBBCCFF, + 0xBABACCFF, + 0xC4C4E1FF, + 0xD6D6FFFF, + 0xD0D0FFFF, + 0x696985FF, + 0x061515FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2CA5A7FF, + 0x298B8CFF, + 0x258485FF, + 0x1F7F80FF, + 0x197A7BFF, + 0x137576FF, + 0x0D7071FF, + 0x043636FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x1F5E5FFF, + 0x20202CFF, + 0xC0C0FCFF, + 0xE4E4FFFF, + 0xCFCFFFFF, + 0xD6D6FFFF, + 0xDDDDFFFF, + 0xE3E3FFFF, + 0xEAEAFFFF, + 0xF0F0FFFF, + 0xF4F4FFFF, + 0xF0F0FFFF, + 0xEAEAFFFF, + 0xE3E3FFFF, + 0xDDDDFFFF, + 0xD6D6FFFF, + 0xCFCFFFFF, + 0x9A9AC4FF, + 0x000000FF, + 0x278F90FF, + 0x2CA3A5FF, + 0x2BA0A3FF, + 0x238E8EFF, + 0x1F7F80FF, + 0x197A7BFF, + 0x137576FF, + 0x0D7071FF, + 0x086B6CFF, + 0x013334FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x3CBABCFF, + 0x061111FF, + 0x76769CFF, + 0xD3D3FFFF, + 0xD3D3FFFF, + 0xD5D5FFFF, + 0xDBDBFFFF, + 0xE2E2FFFF, + 0xE7E7FFFF, + 0xECECFFFF, + 0xEEEEFFFF, + 0xECECFFFF, + 0xE7E7FFFF, + 0xCCCCE6FF, + 0x32323AFF, + 0xA5A5C6FF, + 0xCECEFFFF, + 0xB4B4E5FF, + 0x000000FF, + 0x1E7071FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x1E8C8CFF, + 0x197A7BFF, + 0x137576FF, + 0x0D7071FF, + 0x086B6CFF, + 0x026667FF, + 0x013434FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x27797AFF, + 0x0E0E13FF, + 0xB1B1E4FF, + 0xD1D1FFFF, + 0xD3D3FFFF, + 0xD9D9FFFF, + 0xDFDFFFFF, + 0xE4E4FFFF, + 0xE7E7FFFF, + 0xE9E9FFFF, + 0xE7E7FFFF, + 0xE4E4FFFF, + 0xDCDCFCFF, + 0x292930FF, + 0x020203FF, + 0x9595B9FF, + 0xC3C3FBFF, + 0x010101FF, + 0x1A6162FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x1C898BFF, + 0x137576FF, + 0x0D7071FF, + 0x086B6CFF, + 0x026667FF, + 0x026768FF, + 0x013435FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x0F3434FF, + 0x333342FF, + 0xC8C8FCFF, + 0xD0D0FFFF, + 0xD6D6FFFF, + 0xDBDBFFFF, + 0xC3C3DFFF, + 0xD4D4EFFF, + 0xE3E3FFFF, + 0xE2E2FFFF, + 0xDFDFFFFF, + 0xDBDBFFFF, + 0xC9C9EFFF, + 0x535366FF, + 0x5D5D75FF, + 0xB8B8F0FF, + 0x000000FF, + 0x175657FF, + 0x2CA3A5FF, + 0x2BA3A5FF, + 0x1C8687FF, + 0x0D7071FF, + 0x086B6CFF, + 0x026667FF, + 0x026768FF, + 0x026869FF, + 0x013535FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x206162FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x30A3A5FF, + 0x2D9799FF, + 0x061415FF, + 0x4F4F65FF, + 0xCCCCFEFF, + 0xD2D2FFFF, + 0xD7D7FFFF, + 0x5D5D6DFF, + 0x2D2D34FF, + 0xDDDDFEFF, + 0xDDDDFFFF, + 0xDADAFFFF, + 0xD7D7FFFF, + 0xD2D2FFFF, + 0xCDCDFFFF, + 0xC8C8FFFF, + 0xA0A0D2FF, + 0x000000FF, + 0x1A6263FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x1B888AFF, + 0x086B6CFF, + 0x026667FF, + 0x026768FF, + 0x026869FF, + 0x02696AFF, + 0x013536FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FB, + 0x1F6061FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x30A3A5FF, + 0x30A3A5FF, + 0x2FA3A5FF, + 0x288B8CFF, + 0x040E0EFF, + 0x5A5A71FF, + 0xCCCCFDFF, + 0xD2D2FFFF, + 0x67677BFF, + 0x000000FF, + 0xC2C2E5FF, + 0xD7D7FFFF, + 0xD5D5FFFF, + 0xD2D2FFFF, + 0xCECEFFFF, + 0xCACAFFFF, + 0xC4C4FFFF, + 0x666688FF, + 0x000000FF, + 0x1F7476FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x1A888AFF, + 0x026667FF, + 0x026768FF, + 0x026869FF, + 0x02696AFF, + 0x026A6BFF, + 0x023637FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000DA, + 0x174647FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x40C5C7FF, + 0x30A3A5FF, + 0x30A3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x268485FF, + 0x040D0EFF, + 0x3F3F50FF, + 0xC3C3F3FF, + 0xB2B2DAFF, + 0x101013FF, + 0xBBBBE3FF, + 0xD2D2FFFF, + 0xD0D0FFFF, + 0xCDCDFFFF, + 0xCACAFFFF, + 0xC6C6FFFF, + 0xB9B9F4FF, + 0x191922FF, + 0x020707FF, + 0x299C9EFF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x178687FF, + 0x026768FF, + 0x026869FF, + 0x02696AFF, + 0x026A6BFF, + 0x036B6DFF, + 0x023637FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000AC, + 0x081717FF, + 0x3FC2C4FF, + 0x40C5C7FF, + 0x30A3A5FF, + 0x30A3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2EA3A5FF, + 0x288F90FF, + 0x081D1DFF, + 0x18181EFF, + 0x8B8BAFFF, + 0xC7C7F9FF, + 0xCDCDFFFF, + 0xCCCCFFFF, + 0xCBCBFFFF, + 0xC8C8FFFF, + 0xC5C5FFFF, + 0xBCBCF9FF, + 0x43435AFF, + 0x000000FF, + 0x113F40FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2AA3A5FF, + 0x178688FF, + 0x026869FF, + 0x02696AFF, + 0x026A6BFF, + 0x036B6DFF, + 0x036C6EFF, + 0x023738FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000048, + 0x000000FF, + 0x27797AFF, + 0x30A3A5FF, + 0x30A3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2C9B9DFF, + 0x134647FF, + 0x010202FF, + 0x252530FF, + 0x737393FF, + 0xA2A2CFFF, + 0xBBBBF2FF, + 0xAEAEE4FF, + 0x7F7FA9FF, + 0x282836FF, + 0x000000FF, + 0x051111FF, + 0x289799FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x178788FF, + 0x02696AFF, + 0x026A6BFF, + 0x036B6DFF, + 0x036C6EFF, + 0x036D6FFF, + 0x023738FF, + 0x000000FF, + 0x00000008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000C4, + 0x030909FF, + 0x288889FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x248385FF, + 0x0E3233FF, + 0x010303FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x081F20FF, + 0x268F90FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x168789FF, + 0x026A6BFF, + 0x036B6DFF, + 0x036C6EFF, + 0x036D6FFF, + 0x036E70FF, + 0x023839FF, + 0x000000FF, + 0x0000006B, + 0x0000003C, + 0x00000008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001A, + 0x000000E3, + 0x061515FF, + 0x268385FF, + 0x2FA3A5FF, + 0x2FA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2CA3A5FF, + 0x289395FF, + 0x1B6465FF, + 0x134849FF, + 0x103D3EFF, + 0x144B4CFF, + 0x207879FF, + 0x2BA2A4FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x29A3A5FF, + 0x168889FF, + 0x036B6DFF, + 0x036C6EFF, + 0x036D6FFF, + 0x036E70FF, + 0x036F71FF, + 0x023839FF, + 0x000000FF, + 0x00000071, + 0x00000071, + 0x0000006B, + 0x0000003C, + 0x00000008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000031, + 0x000000E0, + 0x010404FF, + 0x164E4FFF, + 0x2B9799FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2EA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x16888AFF, + 0x036C6EFF, + 0x036D6FFF, + 0x036E70FF, + 0x036F71FF, + 0x037072FF, + 0x023839FF, + 0x000000FF, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x0000006B, + 0x0000003C, + 0x00000008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000F, + 0x0000009F, + 0x000000FD, + 0x020808FF, + 0x154C4DFF, + 0x2A9799FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2DA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x16898AFF, + 0x036D6FFF, + 0x036E70FF, + 0x036F71FF, + 0x037072FF, + 0x037072FF, + 0x023839FF, + 0x000000FF, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x0000006A, + 0x00000035, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A8, + 0x000000FD, + 0x020808FF, + 0x154C4DFF, + 0x2A9799FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x16898BFF, + 0x036E70FF, + 0x036F71FF, + 0x037072FF, + 0x037072FF, + 0x037072FF, + 0x013334FF, + 0x000000F9, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A9, + 0x000000FD, + 0x020808FF, + 0x154C4DFF, + 0x299799FF, + 0x2CA3A5FF, + 0x2CA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x28A3A5FF, + 0x16898BFF, + 0x036F71FF, + 0x037072FF, + 0x037072FF, + 0x037072FF, + 0x036F71FF, + 0x011515FF, + 0x000000E0, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x0000003B, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A9, + 0x000000FD, + 0x020808FF, + 0x144C4DFF, + 0x289799FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2BA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x168A8CFF, + 0x037072FF, + 0x037072FF, + 0x037072FF, + 0x037072FF, + 0x012E2EFF, + 0x000000FF, + 0x000000A7, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000070, + 0x00000015, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A9, + 0x000000FD, + 0x020808FF, + 0x144C4DFF, + 0x279799FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x2AA3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x168A8CFF, + 0x037072FF, + 0x037072FF, + 0x037072FF, + 0x012E2EFF, + 0x000000FF, + 0x000000B8, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x0000003E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002C, + 0x000000A9, + 0x000000FD, + 0x020808FF, + 0x144C4DFF, + 0x279799FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x29A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x168A8CFF, + 0x037072FF, + 0x037072FF, + 0x012E2FFF, + 0x000000FF, + 0x000000B8, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x0000004D, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002A, + 0x000000A2, + 0x000000FC, + 0x020808FF, + 0x134C4DFF, + 0x269799FF, + 0x29A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x168A8CFF, + 0x037072FF, + 0x012E2FFF, + 0x000000FF, + 0x000000BD, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x0000004C, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002C, + 0x000000AA, + 0x000000FD, + 0x020A0AFF, + 0x145051FF, + 0x25989AFF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x15898BFF, + 0x012F2FFF, + 0x000000FF, + 0x000000B9, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000070, + 0x00000039, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002C, + 0x000000AA, + 0x000000FD, + 0x020A0AFF, + 0x145152FF, + 0x25989AFF, + 0x28A3A5FF, + 0x28A3A5FF, + 0x28A2A4FF, + 0x094647FF, + 0x000000FF, + 0x000000BA, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x0000005F, + 0x0000001C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002C, + 0x000000AA, + 0x000000FD, + 0x020909FF, + 0x104041FF, + 0x155657FF, + 0x0A2A2BFF, + 0x000000FF, + 0x000000BB, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000069, + 0x00000036, + 0x00000003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002C, + 0x0000009C, + 0x000000ED, + 0x000000FF, + 0x000000FF, + 0x000000BB, + 0x00000071, + 0x00000071, + 0x00000071, + 0x00000071, + 0x0000006B, + 0x00000055, + 0x0000002D, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/computer.c b/widget/milsko/milskosrc/src/icon/computer.c new file mode 100644 index 0000000000..ced71103a3 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/computer.c @@ -0,0 +1,261 @@ +#include + +MwU32 MwIconComputer[] = { + (16 << 16) | 16, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x949494FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5A6363FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x292118FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5A6363FF, + 0x5A6363FF, + 0x949494FF, + 0x949494FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x949494FF, + 0x000000FF, + 0x949494FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5A6363FF, + 0x5A6363FF, + 0x949494FF, + 0x73BDDEFF, + 0x73BDDEFF, + 0x73BDDEFF, + 0x39A5CEFF, + 0x949494FF, + 0x000000FF, + 0x949494FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5A6363FF, + 0x5A6363FF, + 0x39A5CEFF, + 0x73BDDEFF, + 0x73BDDEFF, + 0x73BDDEFF, + 0x949494FF, + 0x949494FF, + 0x000000FF, + 0x949494FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5A6363FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0xFFFFFFFF, + 0x000000FF, + 0x949494FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x39A5CEFF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x39A5CEFF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x73BDDEFF, + 0x39A5CEFF, + 0x73BDDEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x73BDDEFF, + 0x39A5CEFF, + 0x5A6363FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x73BDDEFF, + 0x73BDDEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x39A5CEFF, + 0x5A6363FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x39A5CEFF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x949494FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x949494FF, + 0x5A6363FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x949494FF, + 0x292118FF, + 0x5A6363FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x949494FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x5A6363FF, + 0x949494FF, + 0x000000FF, + 0x949494FF, + 0x00000000, + 0x00000000, + 0x5A6363FF, + 0x000000FF, + 0x292118FF, + 0x292118FF, + 0x292118FF, + 0x292118FF, + 0x292118FF, + 0x292118FF, + 0x292118FF, + 0x292118FF, + 0x292118FF, + 0x000000FF, + 0x5A6363FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/directory.c b/widget/milsko/milskosrc/src/icon/directory.c new file mode 100644 index 0000000000..ebd5440b10 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/directory.c @@ -0,0 +1,261 @@ +#include + +MwU32 MwIconDirectory[] = { + (16 << 16) | 16, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x2B251DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0x000000FF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0xFFDEADFF, + 0x2B251DFF, + 0x2B251DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0x000000FF, + 0x000000FF, + 0xB8A07DFF, + 0xFFDCAEFF, + 0x000000FF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0x2B251DFF, + 0x2B251DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0xFFDCAEFF, + 0xB8A07DFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0x2B251DFF, + 0x2B251DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0x2B251DFF, + 0x2B251DFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0x000000FF, + 0xB8A07DFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xB8A07DFF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xB8A07DFF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xB8A07DFF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x574B3BFF, + 0xB8A07DFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xB8A07DFF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x000000FF, + 0x574B3BFF, + 0xB8A07DFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xB8A07DFF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x000000FF, + 0x574B3BFF, + 0xB8A07DFF, + 0xFFDEADFF, + 0xFFDEADFF, + 0xB8A07DFF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0x2B251DFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x000000FF, + 0x574B3BFF, + 0xB8A07DFF, + 0xB8A07DFF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0x2B251DFF, + 0x2B251DFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0x574B3BFF, + 0x000000FF, + 0x2B251DFF, + 0x2B251DFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x2B251DFF, + 0x2B251DFF, + 0xC0C0C000, + 0xC0C0C000, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/down.c b/widget/milsko/milskosrc/src/icon/down.c new file mode 100644 index 0000000000..03af9d4960 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/down.c @@ -0,0 +1,445 @@ +#include + +MwU32 MwIconDown[] = { + (20 << 16) | 22, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/error.c b/widget/milsko/milskosrc/src/icon/error.c new file mode 100644 index 0000000000..f268c1792c --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/error.c @@ -0,0 +1,2309 @@ +#include + +MwU32 MwIconError[] = { + (48 << 16) | 48, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000C, + 0x00000080, + 0x000000F6, + 0x000000E6, + 0x000000AA, + 0x0000006F, + 0x00000033, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000006, + 0x00000070, + 0x000000EC, + 0x020101FF, + 0x563938FF, + 0x523534FF, + 0x170E0EFF, + 0x000000FF, + 0x000000FF, + 0x000000EB, + 0x000000B0, + 0x00000074, + 0x00000039, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000058, + 0x000000DD, + 0x000000FF, + 0x442F2EFF, + 0xCE8C89FF, + 0xFFA9A5FF, + 0xFFA4A1FF, + 0xFFA09DFF, + 0xE68C89FF, + 0xAA6563FF, + 0x663A3AFF, + 0x2B1818FF, + 0x010101FF, + 0x000000FF, + 0x000000F5, + 0x000000C0, + 0x00000082, + 0x00000047, + 0x0000000E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000041, + 0x000000CB, + 0x000000FF, + 0x2B201FFF, + 0xB3807CFF, + 0xFFB2ADFF, + 0xFFADA9FF, + 0xFFA9A5FF, + 0xFFA4A1FF, + 0xFFA09DFF, + 0xFF9B98FF, + 0xFF9794FF, + 0xFF9290FF, + 0xFF8E8CFF, + 0xE97D7CFF, + 0xB35D5DFF, + 0x773C3BFF, + 0x3C1D1DFF, + 0x060303FF, + 0x000000FF, + 0x000000FC, + 0x000000CE, + 0x00000035, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002C, + 0x000000B5, + 0x000000FF, + 0x1F1817FF, + 0xA27976FF, + 0xFDBAB5FF, + 0xFFB6B1FF, + 0xFFB2ADFF, + 0xFFADA9FF, + 0xFFA9A5FF, + 0xFFA4A1FF, + 0xFFA09DFF, + 0xFF9B98FF, + 0xFF9794FF, + 0xFF9290FF, + 0xFF8E8CFF, + 0xFF8988FF, + 0xFF8584FF, + 0xFF807FFF, + 0xFF7C7BFF, + 0xF37171FF, + 0xB85454FF, + 0x2D0E0EFF, + 0x000000FC, + 0x00000015, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000029, + 0x000000FC, + 0x110D0DFF, + 0x886A66FF, + 0xF7BEB8FF, + 0xFFBFBAFF, + 0xFFBBB6FF, + 0xFFB6B1FF, + 0xFFB2ADFF, + 0xFFADA9FF, + 0xFFA9A5FF, + 0xFFA4A1FF, + 0xFFA09DFF, + 0xFF9B98FF, + 0xFF9794FF, + 0xFF9290FF, + 0xFF8E8CFF, + 0xFF8988FF, + 0xFF8584FF, + 0xFF807FFF, + 0xFF7C7BFF, + 0xE66B6BF8, + 0x8A1D1DFF, + 0x1A0000FF, + 0x000000C2, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000002, + 0x000000E7, + 0x552422FF, + 0xCD6963FF, + 0xD08983EB, + 0xF9B7B2DB, + 0xFFBBB6FE, + 0xFFB6B1FF, + 0xFFB2ADFF, + 0xFFADA9FF, + 0xFFA9A5FF, + 0xFFA4A1FF, + 0xFFA09DFF, + 0xFF9B98FF, + 0xFF9794FF, + 0xFF9290FF, + 0xFF8E8CFF, + 0xFF8988FF, + 0xFF8584FF, + 0xFF807FFF, + 0xE96765C4, + 0x850606FB, + 0x770101FF, + 0x010000FF, + 0x00000073, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000099, + 0x0D0505FF, + 0xF75E56FF, + 0xFF6159FF, + 0xFF6159FF, + 0xFF6A62EA, + 0xFF857EC6, + 0xFFA39DC4, + 0xFFADA8EE, + 0xFFA9A5FF, + 0xFFA4A1FF, + 0xFFA09DFF, + 0xFF9B98FF, + 0xFF9794FF, + 0xFF9290FF, + 0xFF8E8CFF, + 0xFF8988FF, + 0xFE8483EC, + 0xB33332C8, + 0x800000FF, + 0x860101FF, + 0x4E0101FF, + 0x000000FF, + 0x00000024, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000049, + 0x000000FF, + 0xB64540FF, + 0xFF6159FF, + 0xFF6159FF, + 0xFE5E56FF, + 0xFD5B53FF, + 0xFC5750FF, + 0xFB554EFC, + 0xFB655FD6, + 0xFC837EC0, + 0xFF9895CD, + 0xFF9B98FA, + 0xFF9794FF, + 0xFF9290FF, + 0xFF8E8CFF, + 0xF37C7BCC, + 0x8D0F0EE9, + 0x800000FF, + 0x830000FF, + 0x880101FF, + 0x240101FF, + 0x000000D3, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000007, + 0x000000F1, + 0x662724FF, + 0xFF6159FF, + 0xFE5E56FF, + 0xFD5A53FF, + 0xFC574FFF, + 0xFB534CFF, + 0xFA5049FF, + 0xF94C46FF, + 0xF84943FF, + 0xF7453FFF, + 0xF84942EF, + 0xFA635FC6, + 0xFC817EC2, + 0xC34B4AC2, + 0x800000FF, + 0x800000FF, + 0x800000FF, + 0x850101FF, + 0x810101FF, + 0x020000FF, + 0x00000083, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000A8, + 0x170908FF, + 0xFC5C54FF, + 0xFD5A52FF, + 0xFC564FFF, + 0xFB534CFF, + 0xFA4F49FF, + 0xF94C45FF, + 0xF84842FF, + 0xF7453FFF, + 0xF6413CFF, + 0xF53E38FF, + 0xF43A35FF, + 0xDB2B28D9, + 0x800000FF, + 0x800000FF, + 0x800000FF, + 0x830000FF, + 0x880101FF, + 0x5A0101FF, + 0x000000FF, + 0x00000034, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000058, + 0x000000FF, + 0xC3453FFF, + 0xFC564EFF, + 0xFB524BFF, + 0xFA4F48FF, + 0xF94B45FF, + 0xF84742FF, + 0xF7443EFF, + 0xF6403BFF, + 0xF53D38FF, + 0xF43935FF, + 0xF33632FF, + 0xB51615C1, + 0x800000FF, + 0x800000FF, + 0x800000FF, + 0x850101FF, + 0x8B0101FF, + 0x2F0101FF, + 0x000000E4, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000D, + 0x000000F7, + 0x742724FF, + 0xFB514BFF, + 0xFA4E48FF, + 0xF94A44FF, + 0xF84741FF, + 0xF7433EFF, + 0xF6403BFF, + 0xF53C37FF, + 0xF43934FF, + 0xF33531FF, + 0xF2322EFF, + 0x930807C4, + 0x800000FF, + 0x800000FF, + 0x830000FF, + 0x880101FF, + 0x8A0202FF, + 0x070000FF, + 0x00000095, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000B6, + 0x230B0AFF, + 0xFA4D47FF, + 0xF94A44FF, + 0xF84641FF, + 0xF7433DFF, + 0xF63F3AFF, + 0xF53C37FF, + 0xF43834FF, + 0xF33531FF, + 0xF2312DFF, + 0xF12E2AFF, + 0x820101E4, + 0x800000FF, + 0x800000FF, + 0x850101FF, + 0x8B0101FF, + 0x650101FF, + 0x000000FF, + 0x00000046, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000066, + 0x000000FF, + 0xCD3C37FF, + 0xF74640FF, + 0xF6423DFF, + 0xF53F3AFF, + 0xF53B36FF, + 0xF43833FF, + 0xF33430FF, + 0xF2312DFF, + 0xF12D2AFF, + 0xE32621E7, + 0x800000FF, + 0x800000FF, + 0x820000FF, + 0x880101FF, + 0x8D0202FF, + 0x3A0101FF, + 0x000000F0, + 0x00000006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000017, + 0x000000FD, + 0x7F2321FF, + 0xF6423CFF, + 0xF53E39FF, + 0xF43B36FF, + 0xF33733FF, + 0xF23430FF, + 0xF1302CFF, + 0xF02D29FF, + 0xEF2926FF, + 0xBE1513C5, + 0x800000FF, + 0x800000FF, + 0x850101FF, + 0x8B0101FF, + 0x8F0202FF, + 0x0E0000FF, + 0x000000A7, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000C5, + 0x310D0CFF, + 0xF53E39FF, + 0xF43A35FF, + 0xF33732FF, + 0xF2332FFF, + 0xF1302CFF, + 0xF02C29FF, + 0xEF2925FF, + 0xEE2522FF, + 0x990808C1, + 0x800000FF, + 0x820000FF, + 0x880101FF, + 0x8D0202FF, + 0x720202FF, + 0x000000FF, + 0x00000058, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000075, + 0x000000FF, + 0xD5332EFF, + 0xF33632FF, + 0xF2332FFF, + 0xF12F2BFF, + 0xF02C28FF, + 0xEF2825FF, + 0xEE2522FF, + 0xED211EFF, + 0x840101D8, + 0x800000FF, + 0x850101FF, + 0x8B0101FF, + 0x900202FF, + 0x450101FF, + 0x000000FA, + 0x00000010, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000024, + 0x000000FF, + 0x8B1F1CFF, + 0xF2322EFF, + 0xF12F2BFF, + 0xF02B28FF, + 0xEF2824FF, + 0xEE2421FF, + 0xED211EFF, + 0xE61B1AF2, + 0x800000FC, + 0x820000FF, + 0x880101FF, + 0x8D0202FF, + 0x930202FF, + 0x170000FF, + 0x000000B8, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000D3, + 0x3F0D0CFF, + 0xF12E2AFF, + 0xF02B27FF, + 0xEF2724FF, + 0xEE2421FF, + 0xED201DFF, + 0xEC1D1AFF, + 0xC7100FCC, + 0x800000FF, + 0x850101FF, + 0x8A0101FF, + 0x900202FF, + 0x7E0303FF, + 0x000000FF, + 0x00000069, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000083, + 0x030100FF, + 0xDD2724FF, + 0xEF2723FF, + 0xEE2320FF, + 0xED201DFF, + 0xEC1C1AFF, + 0xEB1917FF, + 0xA20705BF, + 0x820000FF, + 0x880101FF, + 0x8D0202FF, + 0x930202FF, + 0x500202FF, + 0x000000FE, + 0x0000001C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000033, + 0x000000FF, + 0x961816FF, + 0xEE2220FF, + 0xED1F1CFF, + 0xEC1B19FF, + 0xEB1816FF, + 0xEA1413FF, + 0x880101CF, + 0x850101FF, + 0x8A0101FF, + 0x900202FF, + 0x950303FF, + 0x220101FF, + 0x000000CA, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000DF, + 0x4A0B0AFF, + 0xEC1E1CFF, + 0xEB1B19FF, + 0xEB1716FF, + 0xEA1412FF, + 0xE8100FFA, + 0x820000F5, + 0x880101FF, + 0x8D0202FF, + 0x930202FF, + 0x8A0303FF, + 0x010000FF, + 0x0000007B, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000092, + 0x080101FF, + 0xE11917FF, + 0xEA1715FF, + 0xE91312FF, + 0xE8100FFF, + 0xCC0808D4, + 0x850101FF, + 0x8A0101FF, + 0x900202FF, + 0x950303FF, + 0x5D0202FF, + 0x000000FF, + 0x0000002C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000042, + 0x000000FF, + 0xA10F0EFF, + 0xE91311FF, + 0xE80F0EFF, + 0xE70C0BFF, + 0xAA0303C0, + 0x870101FF, + 0x8D0202FF, + 0x920202FF, + 0x980303FF, + 0x2E0101FF, + 0x000000DC, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000004, + 0x000000EC, + 0x570706FF, + 0xE80F0EFF, + 0xE70B0AFF, + 0xE60807FF, + 0x920101C7, + 0x8A0101FF, + 0x900202FF, + 0x950303FF, + 0x940303FF, + 0x050000FF, + 0x0000008E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000A0, + 0x100101FF, + 0xE30B0AFF, + 0xE60707FF, + 0xE50403FF, + 0x880101E9, + 0x8D0202FF, + 0x920202FF, + 0x980303FF, + 0x4B0202FF, + 0x000000FF, + 0x0000003F, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000050, + 0x000000FF, + 0xAA0504FF, + 0xE50303FF, + 0xD50000DF, + 0x8A0101FF, + 0x900202FF, + 0x950303FF, + 0x4D0101FF, + 0x000000FF, + 0x0000009D, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000009, + 0x000000F4, + 0x620101FF, + 0xE40000FF, + 0x9F0000DE, + 0x8D0202FF, + 0x920202FF, + 0x4C0101FF, + 0x000000FF, + 0x0000009E, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000C4, + 0x180000FF, + 0xE30000FF, + 0x770101FF, + 0x8F0202FF, + 0x4A0101FF, + 0x000000FF, + 0x000000FF, + 0x000000C3, + 0x00000041, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000004, + 0x00000091, + 0x000000FF, + 0x000000FF, + 0xB60000FF, + 0x7C0202FF, + 0x490101FF, + 0x000000FF, + 0x400301FF, + 0x6D0402FF, + 0x190100FF, + 0x000000FF, + 0x00000099, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x000000AB, + 0x010000FF, + 0x6A1411FF, + 0x040101FF, + 0x610000FF, + 0x480101FF, + 0x000000FF, + 0x500502FF, + 0xCD0B04FF, + 0xCD0903FF, + 0xC40803FF, + 0x5D0301FF, + 0x000000FF, + 0x000000A9, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000075, + 0x000000FF, + 0x881A16FF, + 0xF9342CFF, + 0x410E0CFF, + 0x070000FF, + 0x000000FF, + 0x4F0502FB, + 0xD10E05FF, + 0xD10C04FF, + 0xCE0A03FF, + 0xCC0903FF, + 0xC90702FF, + 0x6D0301FF, + 0x000000FF, + 0x00000072, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000015, + 0x000000F2, + 0x4E0E0CFF, + 0xF9332BFF, + 0xFF3930FF, + 0x923C39FF, + 0x000000FF, + 0x53201DED, + 0xDC251CFF, + 0xD50F05FF, + 0xD20D04FF, + 0xD00B04FF, + 0xCD0903FF, + 0xCA0803FF, + 0xC70602FF, + 0x3D0100FF, + 0x000000F0, + 0x00000014, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000074, + 0x010000FF, + 0xD02822FF, + 0xFB362DFF, + 0xFF5E56FF, + 0xE48E8AFF, + 0x624D4CFF, + 0xF67A73C1, + 0xE5362DFF, + 0xD9180EFF, + 0xD30E05FF, + 0xD00C04FF, + 0xCD0A03FF, + 0xCB0803FF, + 0xC80602FF, + 0xA60301FF, + 0x010000FF, + 0x00000072, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000C1, + 0x300807FF, + 0xF42F28FF, + 0xFC362EFF, + 0xFF665FFF, + 0xFFADAAFF, + 0xFEEBEAFF, + 0xFDA6A2D9, + 0xE93F36CE, + 0xDA1B11FF, + 0xD30E05FF, + 0xD00C04FF, + 0xCD0A03FF, + 0xCB0803FF, + 0xC80602FF, + 0xC50401FF, + 0x260000FF, + 0x000000BF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000E6, + 0x5F100DFF, + 0xF32E27FF, + 0xFA352CFF, + 0xFF4E46FF, + 0xFF8781FF, + 0xFFA4A0FF, + 0xFF908BFF, + 0xFF5A53FF, + 0xF22D24D3, + 0xD81209C6, + 0xD00C04F9, + 0xCD0A03FF, + 0xCA0803FF, + 0xC70602FF, + 0xC50401FF, + 0x4D0100FF, + 0x000000E5, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000F9, + 0x6F120FFF, + 0xF02C25FF, + 0xF6312AFF, + 0xFC372EFF, + 0xFF4A42FF, + 0xFF5C55FF, + 0xFF5048FF, + 0xFD382FFF, + 0xF8332BFF, + 0xF12D26FF, + 0xE8241CEA, + 0xD5110CC0, + 0xCC0704D1, + 0xC80502F0, + 0xB50301FF, + 0x520201FF, + 0x000000F8, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000E6, + 0x5C0E0CFF, + 0xEC2821FF, + 0xF12D26FF, + 0xF63129FF, + 0xFA342CFF, + 0xFB352DFF, + 0xFA352CFF, + 0xF7322AFF, + 0xF22E27FF, + 0xED2922FF, + 0xE7231EFF, + 0xE01D19FF, + 0xD91713FF, + 0xD2110EFF, + 0xCA0A09FF, + 0x4C0201FF, + 0x000000E5, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000C0, + 0x2C0605FF, + 0xE6231DFF, + 0xEB2721FF, + 0xEF2B24FF, + 0xF22E26FF, + 0xF32E27FF, + 0xF22E27FF, + 0xF02C25FF, + 0xEC2822FF, + 0xE7241EFF, + 0xE21F1AFF, + 0xDC1A15FF, + 0xD51411FF, + 0xCE0E0CFF, + 0xC70806FF, + 0x240000FF, + 0x000000C0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000C, + 0x0000001C, + 0x0000002C, + 0x0000003C, + 0x0000004C, + 0x0000005B, + 0x0000006B, + 0x00000066, + 0x0000002C, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000073, + 0x010000FF, + 0xBD1915FF, + 0xE5221CFF, + 0xE8251FFF, + 0xEB2721FF, + 0xEB2821FF, + 0xEB2721FF, + 0xE9251FFF, + 0xE6221DFF, + 0xE11F1AFF, + 0xDC1A16FF, + 0xD71512FF, + 0xD1100DFF, + 0xCA0A09FF, + 0xA40303FF, + 0x000000FF, + 0x000000B1, + 0x00000046, + 0x00000009, + 0x0000000F, + 0x00000044, + 0x00000054, + 0x00000063, + 0x00000073, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000066, + 0x0000002C, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000014, + 0x000000F1, + 0x440706FF, + 0xDE1C17FF, + 0xE11E19FF, + 0xE3201BFF, + 0xE4211BFF, + 0xE3201BFF, + 0xE11F1AFF, + 0xDF1C18FF, + 0xDB1915FF, + 0xD61512FF, + 0xD1100EFF, + 0xCC0B0AFF, + 0xC60605FF, + 0x3A0000FF, + 0x000000F7, + 0x00000081, + 0x00000077, + 0x00000068, + 0x00000068, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000066, + 0x0000002C, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000073, + 0x000000FF, + 0x750B0AFF, + 0xDA1814FF, + 0xDB1915FF, + 0xDC1A16FF, + 0xDB1915FF, + 0xDA1814FF, + 0xD71612FF, + 0xD41310FF, + 0xD00F0DFF, + 0xCB0B09FF, + 0xC60705FF, + 0x680101FF, + 0x000000FF, + 0x000000B3, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000055, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x000000A9, + 0x000000FF, + 0x600806FF, + 0xCD120FFF, + 0xD41310FF, + 0xD4120FFF, + 0xD2110FFF, + 0xD00F0DFF, + 0xCD0D0BFF, + 0xCA0908FF, + 0xBF0605FF, + 0x580000FF, + 0x000000FF, + 0x000000D0, + 0x00000078, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000055, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000004, + 0x000000B8, + 0x000000FF, + 0x190101FF, + 0x6E0605FF, + 0xA70908FF, + 0xC10A09FF, + 0xC00907FF, + 0xA20504FF, + 0x680202FF, + 0x0F0000FF, + 0x000000FF, + 0x000000C4, + 0x00000079, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000055, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000010, + 0x0000008F, + 0x000000DF, + 0x000000FE, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FE, + 0x000000DE, + 0x00000098, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000068, + 0x00000068, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000055, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x00000046, + 0x00000082, + 0x000000A6, + 0x000000B3, + 0x000000B3, + 0x000000A6, + 0x00000085, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000073, + 0x00000045, + 0x00000008, + 0x0000000F, + 0x00000044, + 0x00000054, + 0x00000063, + 0x00000073, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000077, + 0x00000055, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x0000002C, + 0x0000004B, + 0x0000005F, + 0x0000006E, + 0x00000074, + 0x00000074, + 0x0000006E, + 0x0000005F, + 0x0000004B, + 0x0000002C, + 0x00000008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000C, + 0x0000001C, + 0x0000002C, + 0x0000003C, + 0x0000004C, + 0x0000005B, + 0x0000006B, + 0x00000055, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/file.c b/widget/milsko/milskosrc/src/icon/file.c new file mode 100644 index 0000000000..0ac5b5a3cb --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/file.c @@ -0,0 +1,261 @@ +#include + +MwU32 MwIconFile[] = { + (16 << 16) | 16, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x8C8C8CFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xCECECEFF, + 0xE7E7E7FF, + 0x8C8C8CFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xCECECEFF, + 0xFFFFFFFF, + 0xE7E7E7FF, + 0x8C8C8CFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xCECECEFF, + 0xCECECEFF, + 0xCECECEFF, + 0xC0C0C000, + 0x8C8C8CFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x393939FF, + 0x393939FF, + 0x393939FF, + 0x393939FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xC0C0C000, + 0xC0C0C000, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xE7E7E7FF, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xCECECEFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x6B6B6BFF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0x8C8C8CFF, + 0x6B6B6BFF, + 0x6B6B6BFF, + 0x6B6B6BFF, + 0x6B6B6BFF, + 0x6B6B6BFF, + 0x6B6B6BFF, + 0x6B6B6BFF, + 0x6B6B6BFF, + 0x6B6B6BFF, + 0x393939FF, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0xC0C0C000, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/forward.c b/widget/milsko/milskosrc/src/icon/forward.c new file mode 100644 index 0000000000..d24f5ed500 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/forward.c @@ -0,0 +1,445 @@ +#include + +MwU32 MwIconForward[] = { + (20 << 16) | 22, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0x666666FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0x666666FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0x666666FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0x666666FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x666666FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/info.c b/widget/milsko/milskosrc/src/icon/info.c new file mode 100644 index 0000000000..8a51dd6939 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/info.c @@ -0,0 +1,2309 @@ +#include + +MwU32 MwIconInfo[] = { + (48 << 16) | 48, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000015, + 0x00000074, + 0x000000C1, + 0x000000E6, + 0x000000FA, + 0x000000E6, + 0x000000C0, + 0x00000073, + 0x00000014, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000076, + 0x000000F2, + 0x000001FF, + 0x04112BFF, + 0x072256FF, + 0x082561FF, + 0x061E50FF, + 0x030D26FF, + 0x000001FF, + 0x000000F1, + 0x00000073, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000005, + 0x000000AB, + 0x000000FF, + 0x071F4AFF, + 0x1354C5FF, + 0x1664E8FF, + 0x1662E5FF, + 0x145DDFFF, + 0x1256D6FF, + 0x104DCAFF, + 0x0B39A1FF, + 0x031237FF, + 0x000000FF, + 0x000000A9, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000097, + 0x000001FF, + 0x0C3983FF, + 0x186CF3FF, + 0x1A71F8FF, + 0x1A72FAFF, + 0x196FF6FF, + 0x1869EEFF, + 0x1561E4FF, + 0x1357D7FF, + 0x104CC8FF, + 0x0C40B9FF, + 0x051D5DFF, + 0x000000FF, + 0x00000093, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000043, + 0x000000FF, + 0x0A306FFF, + 0x196FF6FF, + 0x1F79FFFF, + 0x3687FFFF, + 0x408CFFFF, + 0x297EFFFF, + 0x1B75FDFF, + 0x186AF0FF, + 0x155FE1FF, + 0x1153D1FF, + 0x0E46C1FF, + 0x0B39B1FF, + 0x03144AFF, + 0x000000FF, + 0x00000040, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000C6, + 0x030C1DFF, + 0x1768EAFF, + 0x1D77FFFF, + 0x4F95FFFF, + 0x8CBAFFFF, + 0x9AC3FFFF, + 0x73ABFFFF, + 0x297EFFFF, + 0x1A72F9FF, + 0x1665E9FF, + 0x1358D8FF, + 0x0F4AC7FF, + 0x0C3DB5FF, + 0x082FA0FF, + 0x010514FF, + 0x000000C3, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001E, + 0x000000FE, + 0x0C357DFF, + 0x196FF6FF, + 0x247BFFFF, + 0x73ABFFFF, + 0xC0D9FFFF, + 0xE3EEFFFF, + 0x9AC3FFFF, + 0x408DFFFF, + 0x1B76FFFF, + 0x1768EDFF, + 0x145BDBFF, + 0x104DCAFF, + 0x0C3FB8FF, + 0x0831A6FF, + 0x031350FF, + 0x000000FE, + 0x0000001B, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000005A, + 0x000000FF, + 0x1151BEFF, + 0x196FF6FF, + 0x217BFFFF, + 0x67A5FFFF, + 0xABCDFFFF, + 0xC0D9FFFF, + 0x8CBAFFFF, + 0x3786FFFF, + 0x1B76FFFF, + 0x1768EDFF, + 0x145BDCFF, + 0x104DCAFF, + 0x0C3FB8FF, + 0x0931A6FF, + 0x041E7BFF, + 0x000000FF, + 0x00000058, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000075, + 0x000000FF, + 0x145BD7FF, + 0x186CF2FF, + 0x1D77FFFF, + 0x2F82FFFF, + 0x67A5FFFF, + 0x73ABFFFF, + 0x4F95FFFF, + 0x227BFFFF, + 0x1A72FAFF, + 0x1765EAFF, + 0x1358D9FF, + 0x0F4BC7FF, + 0x0C3DB6FF, + 0x0830A4FF, + 0x04208CFF, + 0x000000FF, + 0x00000073, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000073, + 0x000000FF, + 0x1256D1FF, + 0x1766EAFF, + 0x1A71F8FF, + 0x1D78FFFF, + 0x237BFFFF, + 0x277DFFFF, + 0x217AFFFF, + 0x1B76FFFF, + 0x186BF1FF, + 0x1560E2FF, + 0x1254D3FF, + 0x0E47C2FF, + 0x0B3AB1FF, + 0x072DA0FF, + 0x041E87FF, + 0x000000FF, + 0x00000072, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000059, + 0x000000FF, + 0x0E45ADFF, + 0x145DDFFF, + 0x1767EBFF, + 0x196EF5FF, + 0x1A73FBFF, + 0x1A74FCFF, + 0x1A71F9FF, + 0x186BF0FF, + 0x1662E5FF, + 0x1358D8FF, + 0x104DCAFF, + 0x0D41BBFF, + 0x0935ABFF, + 0x06289BFF, + 0x00006AFF, + 0x000000FF, + 0x00000057, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001C, + 0x000000FE, + 0x08286BFF, + 0x1253D2FF, + 0x145BDDFF, + 0x1662E5FF, + 0x1765EAFF, + 0x1766EBFF, + 0x1664E8FF, + 0x155FE1FF, + 0x1358D8FF, + 0x104FCCFF, + 0x0E45BFFF, + 0x0B3AB1FF, + 0x082EA2FF, + 0x042293FF, + 0x000045FF, + 0x000000FE, + 0x0000001A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000C3, + 0x010816FF, + 0x0F46BFFF, + 0x114FCDFF, + 0x1255D4FF, + 0x1358D8FF, + 0x1358D9FF, + 0x1357D6FF, + 0x1152D1FF, + 0x104CC9FF, + 0x0E44BFFF, + 0x0B3BB3FF, + 0x0831A6FF, + 0x062798FF, + 0x00007DFF, + 0x00000FFF, + 0x000000C1, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000041, + 0x000000FF, + 0x061C54FF, + 0x0D43BDFF, + 0x0E48C3FF, + 0x0F4AC6FF, + 0x0F4BC7FF, + 0x0F49C5FF, + 0x0E45C0FF, + 0x0C40B9FF, + 0x0B39B0FF, + 0x0831A6FF, + 0x06289AFF, + 0x031E8DFF, + 0x00003AFF, + 0x000000FF, + 0x0000006C, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000036, + 0x000000C0, + 0x000000FF, + 0x000000FF, + 0x051E5FFF, + 0x0B3AB2FF, + 0x0B3CB5FF, + 0x0C3DB5FF, + 0x0B3CB3FF, + 0x0A38AFFF, + 0x0934A9FF, + 0x072DA1FF, + 0x052698FF, + 0x031E8DFF, + 0x000046FF, + 0x000000FF, + 0x010307FF, + 0x000000FF, + 0x000000D9, + 0x00000078, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000A9, + 0x000000FE, + 0x091018FF, + 0x356091FF, + 0x1C3452FF, + 0x000000FF, + 0x020E32FF, + 0x072889FF, + 0x082FA3FF, + 0x082EA2FF, + 0x072B9EFF, + 0x062799FF, + 0x042192FF, + 0x00006CFF, + 0x000027FF, + 0x000000FF, + 0x07174BFF, + 0x1442CDFF, + 0x10308AFF, + 0x040A21FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x122A4BFF, + 0x5296DBFF, + 0x5AA3F9FF, + 0x5399F5FF, + 0x2B5186FF, + 0x04080EFF, + 0x000000FF, + 0x01061DFF, + 0x020D39FF, + 0x010E42FF, + 0x000033FF, + 0x000019FF, + 0x000000FF, + 0x01040DFF, + 0x072077FF, + 0x0530D0FF, + 0x0C38D0FC, + 0x091F8BFF, + 0x01024AFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x10397FFF, + 0x1D6DF6FF, + 0x357EF0CE, + 0x5097F6CD, + 0x4E94F3FF, + 0x4280DDFF, + 0x244883FF, + 0x0F1F3CFF, + 0x050C18FF, + 0x010205FF, + 0x040A17FF, + 0x091739FF, + 0x102D7BFF, + 0x1745CAFF, + 0x1546D8FF, + 0x1442D6DB, + 0x07129ED8, + 0x030392FF, + 0x02024BFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0E3475FF, + 0x1D6EFBFF, + 0x1C6AFAFF, + 0x1A67F9FF, + 0x2871F7D4, + 0x4388F4BD, + 0x4789F0F7, + 0x4181EDFF, + 0x3B7AEAFF, + 0x3672E8FF, + 0x316BE6FF, + 0x2C65E3FF, + 0x2860E1FF, + 0x255BE0FE, + 0x1A42C9C1, + 0x03048EF8, + 0x02028FFF, + 0x030393FF, + 0x02024CFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000D5, + 0x000103FF, + 0x0F3A86FF, + 0x1B6AFAFF, + 0x1A66F9FF, + 0x1963F8FF, + 0x1760F7FF, + 0x1B61F6EA, + 0x3578F2C0, + 0x4485EFE6, + 0x4080EDFF, + 0x3B7AEBFF, + 0x3875E9FF, + 0x346FE7E5, + 0x1124A4CF, + 0x010189FF, + 0x02028CFF, + 0x030390FF, + 0x030394FF, + 0x02024CFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000B, + 0x0000009F, + 0x000000FF, + 0x092557FF, + 0x1961EFFF, + 0x1862F8FF, + 0x175FF7FF, + 0x165BF6FF, + 0x1458F5FF, + 0x1656F4F9, + 0x2D6EF2C8, + 0x4586F1D7, + 0x3B71DEC4, + 0x040989EE, + 0x010186FF, + 0x01018AFF, + 0x02028DFF, + 0x030391FF, + 0x030395FF, + 0x02024CFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000005F, + 0x000000FF, + 0x0D327CFF, + 0x1861F7FF, + 0x175EF6FF, + 0x155AF5FF, + 0x1457F4FF, + 0x1354F3FF, + 0x1150F2FF, + 0x104DF1FF, + 0x000081FF, + 0x000083FF, + 0x010187FF, + 0x02028BFF, + 0x02028EFF, + 0x030392FF, + 0x030395FF, + 0x02024DFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0C3078FF, + 0x1860F7FF, + 0x165DF6FF, + 0x1559F5FF, + 0x1456F4FF, + 0x1253F3FF, + 0x114FF2FF, + 0x104CF1FF, + 0x000081FF, + 0x010184FF, + 0x010188FF, + 0x02028BFF, + 0x02028FFF, + 0x030393FF, + 0x040496FF, + 0x02024DFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0C3078FF, + 0x175FF7FF, + 0x165CF6FF, + 0x1559F5FF, + 0x1355F4FF, + 0x1252F3FF, + 0x114FF2FF, + 0x0F4BF1FF, + 0x000081FF, + 0x010185FF, + 0x010189FF, + 0x02028CFF, + 0x020290FF, + 0x030394FF, + 0x040497FF, + 0x02024EFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0C3079FF, + 0x175EF7FF, + 0x165BF5FF, + 0x1458F4FF, + 0x1354F3FF, + 0x1251F2FF, + 0x104EF1FF, + 0x0F4AF0FF, + 0x000082FF, + 0x010186FF, + 0x010189FF, + 0x02028DFF, + 0x030391FF, + 0x030394FF, + 0x040498FF, + 0x02024EFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0C2F78FF, + 0x175DF6FF, + 0x155AF5FF, + 0x1457F4FF, + 0x1353F3FF, + 0x1150F2FF, + 0x104DF1FF, + 0x0F49F0FF, + 0x000083FF, + 0x010187FF, + 0x02028AFF, + 0x02028EFF, + 0x030392FF, + 0x030395FF, + 0x040499FF, + 0x03034FFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0B2F78FF, + 0x165CF6FF, + 0x1559F5FF, + 0x1356F4FF, + 0x1252F3FF, + 0x114FF2FF, + 0x0F4CF1FF, + 0x0E48F0FF, + 0x000084FF, + 0x010187FF, + 0x02028BFF, + 0x02028FFF, + 0x030392FF, + 0x040496FF, + 0x04049AFF, + 0x03034FFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0B2F79FF, + 0x165BF6FF, + 0x1458F5FF, + 0x1355F4FF, + 0x1251F3FF, + 0x104EF2FF, + 0x0F4BF1FF, + 0x0E47F0FF, + 0x010185FF, + 0x010188FF, + 0x02028CFF, + 0x020290FF, + 0x030393FF, + 0x040497FF, + 0x04049BFF, + 0x03034FFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000046, + 0x000000FF, + 0x0B2E79FF, + 0x155BF5FF, + 0x1457F4FF, + 0x1354F3FF, + 0x1151F2FF, + 0x104DF1FF, + 0x0F4AF0FF, + 0x0D47EFFF, + 0x010185FF, + 0x010189FF, + 0x02028DFF, + 0x030390FF, + 0x030394FF, + 0x040498FF, + 0x04049BFF, + 0x030350FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000017, + 0x000000A5, + 0x000000FF, + 0x0D1726FF, + 0x204DA1FF, + 0x155AF5FF, + 0x1456F4FF, + 0x1253F3FF, + 0x1150F2FF, + 0x104CF1FF, + 0x0E49F0FF, + 0x0D46EFFF, + 0x010186FF, + 0x01018AFF, + 0x02028EFF, + 0x030391FF, + 0x030395FF, + 0x040499FF, + 0x05059CFF, + 0x030350FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000065, + 0x000000EE, + 0x020305FF, + 0x284975FF, + 0x5195F3FF, + 0x2F64BEFB, + 0x1559F5FF, + 0x1355F4FF, + 0x1252F3FF, + 0x114FF2FF, + 0x0F4BF1FF, + 0x0E48F0FF, + 0x0D45EFFF, + 0x010187FF, + 0x02028BFF, + 0x02028EFF, + 0x030392FF, + 0x030396FF, + 0x040499FF, + 0x05059DFF, + 0x030351FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000026, + 0x000000BD, + 0x000000FF, + 0x16273DFF, + 0x4B88D3FF, + 0x579FFCFF, + 0x559CFBFF, + 0x3B80F1C6, + 0x1458F5FF, + 0x1354F4FF, + 0x1251F3FF, + 0x104EF1FF, + 0x0F4AF0FF, + 0x0E47EFFF, + 0x0C44EEFF, + 0x010188FF, + 0x02028CFF, + 0x02028FFF, + 0x030393FF, + 0x040497FF, + 0x04049AFF, + 0x05059EFF, + 0x030351FF, + 0x000000FF, + 0x00000027, + 0x00000027, + 0x00000027, + 0x00000027, + 0x00000027, + 0x00000027, + 0x00000027, + 0x00000023, + 0x00000005, + 0x00000000, + 0x0000000C, + 0x0000001C, + 0x00000026, + 0x00000027, + 0x00000026, + 0x0000001C, + 0x0000000C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FA, + 0x060B11FF, + 0x396598FF, + 0x5CA5FCFF, + 0x5AA3FCFF, + 0x58A0FCFF, + 0x569DFBFF, + 0x3F84FABF, + 0x1457F4FF, + 0x1354F3FF, + 0x1150F2FF, + 0x104DF1FF, + 0x0F4AF0FF, + 0x0D46EFFF, + 0x0C43EEFF, + 0x010189FF, + 0x02028DFF, + 0x030390FF, + 0x030394FF, + 0x040497FF, + 0x04049BFF, + 0x05059FFF, + 0x030351FF, + 0x000000FF, + 0x00000067, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x0000004F, + 0x00000048, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000047, + 0x00000024, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x113878FF, + 0x356EBDFF, + 0x5AA2F5F7, + 0x5BA5FDFF, + 0x59A2FCFF, + 0x579FFCFF, + 0x4086FABF, + 0x1456F4FF, + 0x1253F3FF, + 0x114FF2FF, + 0x104CF1FF, + 0x0E49F0FF, + 0x0D45EFFF, + 0x0C42EEFF, + 0x01018AFF, + 0x02028DFF, + 0x030391FF, + 0x030395FF, + 0x040498FF, + 0x04049CFF, + 0x0505A0FF, + 0x04085CFF, + 0x000001FF, + 0x000000FE, + 0x000000D1, + 0x00000091, + 0x0000005A, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000043, + 0x00000007, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0F367EFF, + 0x1B69FAFF, + 0x1E6AF9F3, + 0x428BFAC0, + 0x5AA2FCEF, + 0x58A0FCFF, + 0x4086F8C0, + 0x1355F4FF, + 0x1252F3FF, + 0x114EF2FF, + 0x0F4BF1FF, + 0x0E48F0FF, + 0x0D44EFFF, + 0x0B41EEFF, + 0x02028BFF, + 0x02028EFF, + 0x030392FF, + 0x030396FF, + 0x040499FF, + 0x05059DFF, + 0x041193FB, + 0x0627D9FF, + 0x0526C7FF, + 0x031979FF, + 0x01061FFF, + 0x000000FF, + 0x000000F5, + 0x000000BB, + 0x0000007C, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x0E367EFF, + 0x1B68FAFF, + 0x1A65F9FF, + 0x1861F7FF, + 0x1D62F8F0, + 0x428AF8C0, + 0x3A81FAC0, + 0x1354F3FF, + 0x1251F2FF, + 0x104DF1FF, + 0x0F4AF0FF, + 0x0E47EFFF, + 0x0C43EEFF, + 0x0B40EDFF, + 0x02028BFF, + 0x02028FFF, + 0x030393FF, + 0x040496FF, + 0x04059CF7, + 0x071DCDC3, + 0x0624D9FF, + 0x0627DCFF, + 0x062ADEFF, + 0x062DE1FF, + 0x062FE3FF, + 0x0526B6FF, + 0x02135BFF, + 0x00020CFF, + 0x000000FF, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000050, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FD, + 0x020711FF, + 0x0E3785FF, + 0x1860EFFF, + 0x1861F7FF, + 0x165DF6FF, + 0x155AF5FF, + 0x1457F4FF, + 0x1253F3FF, + 0x1150F2FF, + 0x104DF1FF, + 0x0E49F0FF, + 0x0D46EFFF, + 0x0C43EEFF, + 0x0A3FEDFF, + 0x02028CFF, + 0x020290FF, + 0x030394FF, + 0x06089FE5, + 0x051BD1D6, + 0x0620D5FF, + 0x0623D8FF, + 0x0626DAFF, + 0x0628DDFF, + 0x062BE0FF, + 0x062EE2FF, + 0x062FE3FF, + 0x0527C3FF, + 0x040959FF, + 0x000000FF, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000041, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002C, + 0x000000B3, + 0x000000FF, + 0x030A1AFF, + 0x0E3A94FF, + 0x165BF2FF, + 0x1559F5FF, + 0x1356F4FF, + 0x1252F3FF, + 0x114FF2FF, + 0x0F4CF1FF, + 0x0E48F0FF, + 0x0D45EFFF, + 0x0B42EEFF, + 0x0A3EEDFF, + 0x02028DFF, + 0x030391FF, + 0x0409A6D0, + 0x0519CEEB, + 0x051CD2FF, + 0x061FD4FF, + 0x0621D7FF, + 0x0624D9FF, + 0x0627DCFF, + 0x062ADEFF, + 0x062DE1FF, + 0x062AD2E2, + 0x070BAEFF, + 0x05055CFF, + 0x000000FF, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x0000004E, + 0x00000010, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000003E, + 0x000000C6, + 0x000000FF, + 0x030E27FF, + 0x0D3BA3FF, + 0x1355F3FF, + 0x1251F3FF, + 0x104EF2FF, + 0x0F4BF1FF, + 0x0E47F0FF, + 0x0C44EEFF, + 0x0B41EDFF, + 0x0A3DECFF, + 0x02028EFF, + 0x040BAFC2, + 0x0515CBFA, + 0x0518CEFF, + 0x051AD0FF, + 0x051DD3FF, + 0x0620D5FF, + 0x0623D8FF, + 0x0626DAFF, + 0x0628DDFF, + 0x0624C9DA, + 0x090BB6FA, + 0x0909B7FF, + 0x05055CFF, + 0x000000FF, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000053, + 0x00000038, + 0x0000000A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000051, + 0x000000D7, + 0x000000FF, + 0x041338FF, + 0x0D3DBAFF, + 0x104DF1FF, + 0x0F4AF0FF, + 0x0D46EFFF, + 0x0C43EEFF, + 0x0B40EDFF, + 0x093CECFF, + 0x1832C7B3, + 0x1B39D7CD, + 0x1A39DACD, + 0x1A3ADBCD, + 0x193ADCCD, + 0x193DDFCD, + 0x1639DDD1, + 0x1234D8DD, + 0x1235D2E4, + 0x0720BDD1, + 0x0808B2FD, + 0x0909B7FF, + 0x0808A1FF, + 0x010118FF, + 0x000000F3, + 0x00000054, + 0x00000054, + 0x00000054, + 0x00000054, + 0x0000003E, + 0x00000031, + 0x0000003A, + 0x0000003E, + 0x0000003A, + 0x00000031, + 0x00000020, + 0x00000008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000002, + 0x00000055, + 0x000000DF, + 0x000000FF, + 0x041440FF, + 0x0B3CC4FF, + 0x0D46EFFF, + 0x0C42EEFF, + 0x0A3FEDFF, + 0x093CECFF, + 0x0D3CECF3, + 0x306AF3C0, + 0x4588F8EF, + 0x4485F8FF, + 0x4282F7FF, + 0x407FF7FF, + 0x3D7CF7FF, + 0x3B79F6FF, + 0x264FCAD5, + 0x0808B1FF, + 0x0909B4FF, + 0x0808A1FF, + 0x010118FF, + 0x000000F4, + 0x00000078, + 0x00000054, + 0x00000036, + 0x0000002D, + 0x0000002A, + 0x00000003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000A, + 0x00000077, + 0x000000EF, + 0x000102FF, + 0x041750FF, + 0x0A39CFFF, + 0x0A3EEDFF, + 0x093BECFF, + 0x0737EBFF, + 0x0634EAFF, + 0x0937EAF3, + 0x2C65F2C0, + 0x4383F8EF, + 0x4181F7FF, + 0x3F7EF7FC, + 0x203FC2D2, + 0x0707AEFF, + 0x0808B1FF, + 0x0808A0FF, + 0x010118FF, + 0x000000F4, + 0x00000078, + 0x00000054, + 0x0000002A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000012, + 0x00000088, + 0x000000F6, + 0x000208FF, + 0x051C6DFF, + 0x0736DBFF, + 0x0736EAFF, + 0x0633E9FF, + 0x0430E8FF, + 0x032CE7FF, + 0x062FE8F0, + 0x2C62F0C0, + 0x1D37C6C9, + 0x0707ABFF, + 0x0808AFFF, + 0x07079CFF, + 0x010117FF, + 0x000000F4, + 0x00000078, + 0x00000054, + 0x0000002A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001C, + 0x00000099, + 0x000000FC, + 0x010410FF, + 0x041C7DFF, + 0x0530E1FF, + 0x042FE8FF, + 0x032BE7FF, + 0x0128E6FF, + 0x0025E5FF, + 0x0707A8FF, + 0x0707ACFF, + 0x07079AFF, + 0x010118FF, + 0x000000F4, + 0x00000078, + 0x00000054, + 0x0000002A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002C, + 0x000000B3, + 0x000000FF, + 0x010519FF, + 0x021C8BFF, + 0x022AE3FF, + 0x0127E6FF, + 0x0025E5FF, + 0x0707A9FF, + 0x060699FF, + 0x010117FF, + 0x000000F3, + 0x00000076, + 0x00000054, + 0x0000002A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000003E, + 0x000000C7, + 0x000000FF, + 0x000724FF, + 0x011999FF, + 0x0025E4FF, + 0x060696FF, + 0x010117FF, + 0x000000F3, + 0x00000076, + 0x00000054, + 0x0000002A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000051, + 0x000000D7, + 0x000000FF, + 0x000935FF, + 0x010115FF, + 0x000000F3, + 0x00000076, + 0x00000054, + 0x0000002A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000002, + 0x00000055, + 0x000000DF, + 0x000000F4, + 0x00000078, + 0x00000054, + 0x0000002A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/left.c b/widget/milsko/milskosrc/src/icon/left.c new file mode 100644 index 0000000000..19103cd5d3 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/left.c @@ -0,0 +1,445 @@ +#include + +MwU32 MwIconLeft[] = { + (20 << 16) | 22, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/news.c b/widget/milsko/milskosrc/src/icon/news.c new file mode 100644 index 0000000000..86c7b8fdd2 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/news.c @@ -0,0 +1,2309 @@ +#include + +MwU32 MwIconNews[] = { + (48 << 16) | 48, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000022, + 0x010101B0, + 0x0000004A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000032, + 0x010101B5, + 0x0000001E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101BB, + 0x010101FF, + 0x010101FF, + 0x010101DD, + 0x00000070, + 0x00000000, + 0x00000032, + 0x010101ED, + 0x010101FF, + 0x010101EC, + 0x0000004D, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000006B, + 0x010101FF, + 0xA0A098FF, + 0xB9B9AFFF, + 0x5B5B56FF, + 0x040404FF, + 0x010101E9, + 0x010101ED, + 0x262624FF, + 0xC9C8C0FF, + 0x4B4B47FF, + 0x010101FE, + 0x0000006A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000031, + 0x010101F7, + 0x5E5E58FF, + 0xE1E1D6FF, + 0xE2E2D7FF, + 0xE2E2D7FF, + 0xC4C4B9FF, + 0x52524EFF, + 0x2C2C2AFF, + 0xDCDCD4FF, + 0xEDEDE4FF, + 0xE9E9E0FF, + 0x666561FF, + 0x010101FE, + 0x0000006A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101DA, + 0x262624FF, + 0xDADACFFF, + 0xE2E2D7FF, + 0xDFDFD4FF, + 0xD1D1C7FF, + 0xC3C3BAFF, + 0xC4C4BDFF, + 0xEAE9E0FF, + 0xF2F1E9FF, + 0xF1F0E8FF, + 0xF0EFE6FF, + 0xEBEAE2FF, + 0x666661FF, + 0x010101FC, + 0x00000049, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101C4, + 0x0C0C0CFF, + 0xC5C5BCFF, + 0xE2E2D7FF, + 0xD6D6CCFF, + 0xC9C9C0FF, + 0xBBBBB3FF, + 0xCECDC6FF, + 0xF5F4ECFF, + 0xF6F5EEFF, + 0xF5F5EDFF, + 0xF4F3EBFF, + 0xF3F2E9FF, + 0xF1F0E7FF, + 0xEBEBE1FF, + 0x4B4B48FF, + 0x010101F1, + 0x0000002C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101AE, + 0x040404FF, + 0xB5B5ACFF, + 0xD9D9CFFF, + 0xCCCCC3FF, + 0xBFBFB7FF, + 0xBCBCB5FF, + 0xE3E2DCFF, + 0xFBFAF3FF, + 0xFBFAF2FF, + 0xFAF9F2FF, + 0xF9F8F0FF, + 0xF7F6EFFF, + 0xF5F4ECFF, + 0xF3F2EAFF, + 0xF0F0E7FF, + 0xE3E2DAFF, + 0x262624FF, + 0x010101E0, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0202029F, + 0x010101FF, + 0x999992FF, + 0xCDCDC4FF, + 0xC1C1B9FF, + 0xB6B6B0FF, + 0xD0CFC8FF, + 0xF9F8F1FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFAF9F1FF, + 0xE6ECF0FF, + 0xF5F4ECFF, + 0xF2F1E9FF, + 0xEFEEE6FF, + 0xD5D4CCFF, + 0x161615FF, + 0x010101CB, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101AE, + 0x010101FF, + 0x878780FF, + 0xC1C1B9FF, + 0xB6B6AFFF, + 0xBFBFB9FF, + 0xEDEDE6FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xDEEAF7FF, + 0xD8E7F7FF, + 0x86B8FCFF, + 0xC0D6F3FF, + 0xF3F2EAFF, + 0xF0EFE7FF, + 0xEDECE3FF, + 0xBEBEB5FF, + 0x060605FF, + 0x010101B2, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002D, + 0x010101D5, + 0x050504FF, + 0x8D8D87FF, + 0xB5B5AEFF, + 0xB8B8B2FF, + 0xE1E0DAFF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0x89BBFFFF, + 0x89BBFFFF, + 0x89BAFDFF, + 0xE9EEF0FF, + 0xF4F3EBFF, + 0xF0F0E7FF, + 0xEDECE3FF, + 0xE9E9DFFF, + 0xA8A89FFF, + 0x010101FF, + 0x0202029D, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0202028A, + 0x010101FA, + 0x1A1A19FF, + 0x9B9B94FF, + 0xB1B1ACFF, + 0xD6D6CFFF, + 0xFBFAF3FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xBDD8FAFF, + 0x89BBFFFF, + 0xB3D3FBFF, + 0xE3EDF5FF, + 0xF8F7EFFF, + 0xF4F3EBFF, + 0xF0F0E7FF, + 0xEDECE3FF, + 0xE9E8DFFF, + 0xE5E5DBFF, + 0x919188FF, + 0x010101FF, + 0x02020285, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000076, + 0x010101EC, + 0x030302FF, + 0x5E5E59FF, + 0xA6A6A2FF, + 0xCECEC7FF, + 0xF8F7F0FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xE7E6E1FF, + 0xC4C4C2FF, + 0xBAB9B8FF, + 0xF2F2EBFF, + 0xFCFBF4FF, + 0xBDD8FAFF, + 0xA7CCFCFF, + 0xD2E3F8FF, + 0xFBFAF3FF, + 0xF8F7EFFF, + 0xF4F3EBFF, + 0xF0EFE7FF, + 0xECEBE2FF, + 0xE8E8DEFF, + 0xE4E4DAFF, + 0xE1E0D5FF, + 0x7E7E76FF, + 0x010101FF, + 0x00000065, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000002, + 0x02020286, + 0x010101EF, + 0x010101FF, + 0x4D4D48FF, + 0x9A9993FF, + 0xC3C3BDFF, + 0xF2F1EBFF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xEAE9E4FF, + 0xC0C0BEFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xBBBBBAFF, + 0xFBFAF3FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFBFAF3FF, + 0xF7F6EEFF, + 0xF3F2EAFF, + 0xEFEEE6FF, + 0xEBEAE1FF, + 0xD6DDDEFF, + 0xA8C1DEFF, + 0xD0D7D5FF, + 0xDAD9CFFF, + 0x595953FF, + 0x010101F9, + 0x0000003C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001B, + 0x02020294, + 0x010101F7, + 0x040403FF, + 0x4F4F4AFF, + 0x90908AFF, + 0xB7B7B0FF, + 0xE8E8DFFF, + 0xF7F6EFFF, + 0xFBFAF3FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xF2F2EBFF, + 0xC6C6C3FF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xE1E0DCFF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xF9F9F1FF, + 0xF6F5EDFF, + 0xF2F1E8FF, + 0xEEEDE4FF, + 0xC7D5E3FF, + 0x629AE6FF, + 0x518EE2FF, + 0x528DDDFF, + 0xB7C6D1FF, + 0xD0D0C5FF, + 0x30302DFF, + 0x010101E2, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0202028F, + 0x010101F7, + 0x090909FF, + 0x5E5E5AFF, + 0x90908BFF, + 0xB1B1AAFF, + 0xDEDED6FF, + 0xF1F1E8FF, + 0xF5F4ECFF, + 0xF9F8F1FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFAF9F2FF, + 0xD4D3D0FF, + 0xAFAFAFFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xB3B3B2FF, + 0xEFEEE8FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xF8F7EFFF, + 0xF4F3EBFF, + 0xF0EFE7FF, + 0xBDD0E6FF, + 0x619AE9FF, + 0x5592E4FF, + 0x4D8BE0FF, + 0x4484DCFF, + 0x4885D6FF, + 0xC3CACAFF, + 0xBABAAFFF, + 0x080807FF, + 0x0202029C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101CB, + 0x060605FF, + 0x5E5D5BFF, + 0x91918DFF, + 0xB1B1AAFF, + 0xDAD9D1FF, + 0xEBEAE1FF, + 0xEFEEE5FF, + 0xF3F2EAFF, + 0xF7F6EEFF, + 0xFBFAF2FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xCBCAC8FF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xBCBCBBFF, + 0xF1F1EBFF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xF9F9F1FF, + 0xF6F5EDFF, + 0xF2F1E9FF, + 0xB6CEE8FF, + 0x639CEBFF, + 0x5995E6FF, + 0x518EE2FF, + 0x4888DEFF, + 0x4081D9FF, + 0x377AD5FF, + 0x6B96CDFF, + 0xCECEC1FF, + 0x7C7C74FF, + 0x010101FB, + 0x00000026, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000004C, + 0x010101FF, + 0x8F8F8AFF, + 0xB5B5AEFF, + 0xD6D6CCFF, + 0xE4E4DAFF, + 0xE8E8DEFF, + 0xECEBE2FF, + 0xF0EFE7FF, + 0xF4F3EBFF, + 0xF8F7EFFF, + 0xFBFAF3FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFAF9F2FF, + 0xC1C1BFFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xACACACFF, + 0xCFCECBFF, + 0xFAF9F2FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFBFAF2FF, + 0xF7F6EEFF, + 0xF3F2EAFF, + 0xB3CDEBFF, + 0x659EECFF, + 0x5D98E8FF, + 0x5491E4FF, + 0x4C8AE0FF, + 0x4484DBFF, + 0x3B7DD7FF, + 0x3376D3FF, + 0x2C71CEFF, + 0xB1BCC1FF, + 0xC1C1B4FF, + 0x060606FF, + 0x00000093, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x02020283, + 0x080807FF, + 0xDAD9CEFF, + 0xDEDDD2FF, + 0xE1E1D6FF, + 0xE5E5DBFF, + 0xE9E8DFFF, + 0xEDECE3FF, + 0xF1F0E7FF, + 0xF4F3EBFF, + 0xF8F7EFFF, + 0xFBFAF3FF, + 0xDBE8F7FF, + 0xEBF2F6FF, + 0xFCFBF4FF, + 0xF7F6F0FF, + 0xB6B6B5FF, + 0xACACACFF, + 0xACACACFF, + 0xB8B7B6FF, + 0xE8E7E2FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFBFAF3FF, + 0xF8F7EFFF, + 0xF4F3EBFF, + 0xBAD1ECFF, + 0x67A0EEFF, + 0x5F9AE9FF, + 0x5793E5FF, + 0x4F8DE1FF, + 0x4686DDFF, + 0x3E7FD8FF, + 0x3679D4FF, + 0x2D72D0FF, + 0x256BCCFF, + 0x7498C2FF, + 0xC6C6B8FF, + 0x383834FF, + 0x010101D3, + 0x0000003F, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x02020283, + 0x090908FF, + 0xDAD9CEFF, + 0xDEDED3FF, + 0xE2E1D7FF, + 0xE6E5DBFF, + 0xE9E9DFFF, + 0xEDECE3FF, + 0xF1F0E7FF, + 0xDEE7EDFF, + 0xC0D8F4FF, + 0xC5DBF9FF, + 0x93C1FEFF, + 0xABCEFCFF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xE3E2DDFF, + 0xB1B1B0FF, + 0xD4D3D0FF, + 0xF9F8F1FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFBFAF3FF, + 0xF8F7EFFF, + 0xECEBE4FF, + 0xF1F0E7FF, + 0xE5E7E4FF, + 0x80ADE8FF, + 0x5995E6FF, + 0x518EE2FF, + 0x4988DEFF, + 0x4081DAFF, + 0x387BD5FF, + 0x3074D1FF, + 0x286ECDFF, + 0x1F67C9FF, + 0x4E80C1FF, + 0xC4C3B5FF, + 0x262623FF, + 0x010101CE, + 0x00000074, + 0x00000025, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000058, + 0x010101FF, + 0xC7C7BCFF, + 0xDFDED3FF, + 0xE2E2D7FF, + 0xE6E5DBFF, + 0xE9E9DFFF, + 0xEDECE3FF, + 0xF0F0E7FF, + 0xA6C7F1FF, + 0x7EB2F9FF, + 0x84B7FDFF, + 0x89BBFFFF, + 0xE4EDF6FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFBFAF3FF, + 0xF7F6F0FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFAF9F2FF, + 0xF4F3ECFF, + 0xBBBBB8FF, + 0xA5A5A4FF, + 0xE8E7DFFF, + 0xEAE9E0FF, + 0xDBE0DDFF, + 0x6399E2FF, + 0x4A89DFFF, + 0x4283DAFF, + 0x3A7CD6FF, + 0x3276D2FF, + 0x2A6FCEFF, + 0x2269CAFF, + 0x1A62C6FF, + 0x7798BAFF, + 0xB1B1A3FF, + 0x050504FF, + 0x010101BB, + 0x00000074, + 0x00000052, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101DC, + 0x44433FFF, + 0xDCDBCFFF, + 0xE2E2D7FF, + 0xE6E5DBFF, + 0xE9E8DFFF, + 0xD2DDE6FF, + 0xCDDBE9FF, + 0x7DB0F5FF, + 0xA9CAF4FF, + 0xF8F7F0FF, + 0xFBFAF2FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFBFAF3FF, + 0xF9F8F0FF, + 0xF0EFE7FF, + 0xB2B2B0FF, + 0x999999FF, + 0xC0C0BBFF, + 0xEAE9DFFF, + 0xE6E6DCFF, + 0xE3E2D8FF, + 0xBECCD6FF, + 0x4684DBFF, + 0x3B7DD7FF, + 0x3377D3FF, + 0x2B71CFFF, + 0x236ACBFF, + 0x1B64C7FF, + 0x3A74BFFF, + 0xBEC0B3FF, + 0x68685FFF, + 0x010101FF, + 0x00000093, + 0x00000074, + 0x00000057, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000038, + 0x010101FB, + 0x878781FF, + 0xE1E0D6FF, + 0xE5E4DAFF, + 0xE8E8DEFF, + 0x87B1E9FF, + 0x6BA3F0FF, + 0x71A8F3FF, + 0xD0DEEEFF, + 0xF6F5EDFF, + 0xF8F7F0FF, + 0xFAF9F2FF, + 0xFBFAF3FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFCFBF4FF, + 0xFBFAF3FF, + 0xFAF9F2FF, + 0xF9F8F0FF, + 0xF7F6EEFF, + 0xE8E7E0FF, + 0xA8A8A7FF, + 0x999999FF, + 0xCDCCC6FF, + 0xE9E8DFFF, + 0xE6E5DBFF, + 0xE3E2D8FF, + 0xDFDFD4FF, + 0xDCDBD0FF, + 0x81A6D3FF, + 0x3478D3FF, + 0x2C71CFFF, + 0x256BCBFF, + 0x1D65C7FF, + 0x3371C1FF, + 0xB4BAB5FF, + 0x9A9A8EFF, + 0x060606FF, + 0x010101D7, + 0x00000074, + 0x00000074, + 0x00000038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000073, + 0x010101FF, + 0x979690FF, + 0xE4E3D9FF, + 0xE7E6DDFF, + 0xCFD9E2FF, + 0xCAD8E5FF, + 0xCCDBE9FF, + 0xEEEFE8FF, + 0xF3F3EBFF, + 0xF5F4ECFF, + 0xF7F6EEFF, + 0xF8F7EFFF, + 0xF8F7F0FF, + 0xF8F7F0FF, + 0xF8F7EFFF, + 0xF7F6EEFF, + 0xF6F5EDFF, + 0xF4F3EBFF, + 0xDBDBD5FF, + 0x9E9E9DFF, + 0x9D9D9CFF, + 0xD8D7D0FF, + 0xE8E7DEFF, + 0xE5E4DAFF, + 0xE2E1D7FF, + 0xDFDED3FF, + 0xDCDBD0FF, + 0xD8D8CCFF, + 0xCBCFC8FF, + 0x3979CEFF, + 0x256CCCFF, + 0x1D65C8FF, + 0x447AC2FF, + 0xB5BBB6FF, + 0x9B9B90FF, + 0x0B0B0AFF, + 0x010101E8, + 0x0000007E, + 0x00000074, + 0x00000061, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x02020285, + 0x010101FF, + 0xA09E99FF, + 0xE6E5DBFF, + 0xE8E8DEFF, + 0xEBEAE1FF, + 0xEDECE3FF, + 0xEFEEE5FF, + 0xF1F0E7FF, + 0xF2F1E9FF, + 0xF3F2EAFF, + 0xF4F3EBFF, + 0xF4F3EBFF, + 0xF4F3EBFF, + 0xF3F3EAFF, + 0xF3F2E9FF, + 0xF1F0E8FF, + 0xF0EFE6FF, + 0xB2B1AEFF, + 0xA2A2A0FF, + 0xDEDED5FF, + 0xE7E6DCFF, + 0xD5D4CCFF, + 0xB6B6AFFF, + 0xDEDED3FF, + 0xDBDBCFFF, + 0xD8D7CCFF, + 0xD5D4C8FF, + 0xD1D1C4FF, + 0x789CC7FF, + 0x2167C8FF, + 0x6E93BEFF, + 0xC1C2B5FF, + 0x8C8C82FF, + 0x030303FF, + 0x010101DE, + 0x0000007F, + 0x00000074, + 0x0000005F, + 0x0000000E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000006D, + 0x010101FB, + 0x070707FF, + 0xBAB9B1FF, + 0xE6E5DCFF, + 0xE8E8DEFF, + 0xEAEAE0FF, + 0xECEBE2FF, + 0xEEEDE4FF, + 0xEFEEE5FF, + 0xEFEFE6FF, + 0xF0EFE7FF, + 0xF0EFE7FF, + 0xF0EFE6FF, + 0xEFEEE6FF, + 0xE2E1DAFF, + 0xEDECE3FF, + 0xEBEBE1FF, + 0xE5E5DCFF, + 0xE2E2D9FF, + 0xE5E4DAFF, + 0xD4D4CBFF, + 0x888887FF, + 0x848483FF, + 0xD2D2C7FF, + 0xD7D7CBFF, + 0xCFCFC3FF, + 0xCDCDC1FF, + 0xCECDC0FF, + 0xB3BCBFFF, + 0xAEB9BBFF, + 0xC1C1B3FF, + 0x65655DFF, + 0x010101FF, + 0x010101CC, + 0x00000078, + 0x00000074, + 0x00000054, + 0x00000006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000038, + 0x010101CD, + 0x010101FF, + 0x353432FF, + 0xA3A29BFF, + 0xBBBAB2FF, + 0xCDCCC3FF, + 0xE6E5DBFF, + 0xE7E7DDFF, + 0xE9E8DFFF, + 0xEAE9E0FF, + 0xEBEAE1FF, + 0xECEBE2FF, + 0xECEBE2FF, + 0xECEBE2FF, + 0xECEBE2FF, + 0xC4C4BFFF, + 0x929292FF, + 0xC3C3BDFF, + 0xE7E6DCFF, + 0xE5E4DAFF, + 0xE3E2D8FF, + 0xD2D1C8FF, + 0x858584FF, + 0x828281FF, + 0xC9C8BFFF, + 0xD6D6CAFF, + 0xCECEC2FF, + 0x7E7E7BFF, + 0x80807CFF, + 0xCACABCFF, + 0xC7C6B8FF, + 0xBDBDB0FF, + 0x494943FF, + 0x010101FE, + 0x000000B8, + 0x00000075, + 0x00000074, + 0x00000046, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x02020291, + 0x010101FD, + 0x191918FF, + 0x8E8D89FF, + 0xCECDC5FF, + 0xC8C6BFFF, + 0xC1C0B8FF, + 0xB9B1ACFF, + 0xCAA4A6FF, + 0xE4E4DAFF, + 0xE6E5DBFF, + 0xE7E6DCFF, + 0xE7E7DDFF, + 0xE8E7DEFF, + 0xE8E7DEFF, + 0xE0DFD6FF, + 0xA6A6A3FF, + 0x898989FF, + 0xA3A3A0FF, + 0xDBDAD1FF, + 0xE2E2D7FF, + 0xE1E0D5FF, + 0xDFDED3FF, + 0xAFAFA9FF, + 0x7F7F7DFF, + 0xC7C7BDFF, + 0xD5D4C8FF, + 0xCDCDC1FF, + 0x7D7D7AFF, + 0x616161FF, + 0xA5A59BFF, + 0xC6C6B8FF, + 0xB7B7A8FF, + 0x2D2D29FF, + 0x010101FB, + 0x000000A6, + 0x00000074, + 0x00000073, + 0x00000032, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000048, + 0x010101E9, + 0x060605FF, + 0x656562FF, + 0xD6D4CDFF, + 0xDBD9D2FF, + 0xD4D3CCFF, + 0xCDCCC5FF, + 0xC5ADACFF, + 0xB7596EFF, + 0xAE425BFF, + 0xC89B9FFF, + 0xE2E2D7FF, + 0xE3E2D8FF, + 0xE4E3D9FF, + 0xE4E3D9FF, + 0xCAC9C2FF, + 0x8D8D8CFF, + 0x878787FF, + 0xBABAB4FF, + 0xE1E0D6FF, + 0xE0DFD4FF, + 0xDEDDD3FF, + 0xD2D2C8FF, + 0xDADACEFF, + 0xD8D8CCFF, + 0xCECDC2FF, + 0xD3D3C6FF, + 0xCCCBC0FF, + 0x7B7B78FF, + 0x5F5F5FFF, + 0xA3A39AFF, + 0xC5C5B7FF, + 0xA7A79AFF, + 0x141412FF, + 0x010101F2, + 0x00000091, + 0x00000074, + 0x0000006F, + 0x00000023, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000057, + 0x010101FB, + 0x2D2D2CFF, + 0xCAC8C3FF, + 0xEDECE5FF, + 0xE7E6DFFF, + 0xE1DFD8FF, + 0xDAD7D1FF, + 0xD19CA4FF, + 0xC55972FF, + 0xBC4F68FF, + 0xB34660FF, + 0xAB3F58FF, + 0xC6999EFF, + 0xDFDFD4FF, + 0xE0DFD4FF, + 0xCCCBC3FF, + 0x808080FF, + 0x8F8F8DFF, + 0xCECEC4FF, + 0xDEDDD2FF, + 0xDDDCD1FF, + 0xDBDBCFFF, + 0xC0BFB7FF, + 0x797878FF, + 0xAAA9A2FF, + 0xD4D3C7FF, + 0xD1D1C4FF, + 0xCACABEFF, + 0x797976FF, + 0x5D5D5DFF, + 0xA2A299FF, + 0xC4C4B6FF, + 0x939387FF, + 0x070706FF, + 0x010101E6, + 0x00000085, + 0x00000074, + 0x00000068, + 0x00000017, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002E, + 0x010101FB, + 0x424240FF, + 0xEBE9E4FF, + 0xF9F7F1FF, + 0xF4F2ECFF, + 0xEDEBE5FF, + 0xE6DBD7FF, + 0xDB8D9EFF, + 0xD3657FFF, + 0xCA5C76FF, + 0xC1546DFF, + 0xB84B65FF, + 0xAF425CFF, + 0xA73C54FF, + 0xC69EA0FF, + 0xDCDBD0FF, + 0xDCDBD0FF, + 0xB7B7B0FF, + 0xD8D8CDFF, + 0xDADACEFF, + 0xD9D9CDFF, + 0xD8D8CCFF, + 0xAFAFA7FF, + 0x707070FF, + 0x7D7D7BFF, + 0xC5C5B9FF, + 0xCFCFC2FF, + 0xCDCDC0FF, + 0xB1B0A7FF, + 0x5E5E5EFF, + 0xA1A097FF, + 0xC2C2B3FF, + 0x79796FFF, + 0x010101FF, + 0x010101D6, + 0x0000007B, + 0x00000074, + 0x0000005F, + 0x0000000E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101B0, + 0x161616FF, + 0xDBDAD4FF, + 0xF1EFE8FF, + 0xF7F5EFFF, + 0xF7F5EFFF, + 0xF1D4D6FF, + 0xE8869CFF, + 0xDF718BFF, + 0xD76982FF, + 0xCE607AFF, + 0xC55871FF, + 0xBC4F68FF, + 0xB34660FF, + 0xAA3E57FF, + 0xA3374FFF, + 0xC4A4A4FF, + 0xD8D7CBFF, + 0xD7D7CBFF, + 0xD7D6CAFF, + 0xD6D6CAFF, + 0xD4D4C7FF, + 0x9D9C96FF, + 0x696969FF, + 0x848481FF, + 0xC9C9BCFF, + 0xCDCDC0FF, + 0xCBCBBDFF, + 0xC9C9BBFF, + 0xC6C6B8FF, + 0xBBBBADFF, + 0xBEBEB0FF, + 0x56564FFF, + 0x010101FF, + 0x010101C2, + 0x00000076, + 0x00000074, + 0x00000054, + 0x00000006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101E7, + 0x5C5C59FF, + 0xE4E2DCFF, + 0xEAE9E2FF, + 0xF0EEE7FF, + 0xF2CBD0FF, + 0xEF839DFF, + 0xE97A94FF, + 0xE1738DFF, + 0xD96B85FF, + 0xD0637CFF, + 0xC85A74FF, + 0xBF526BFF, + 0xB64963FF, + 0xAE415AFF, + 0xA75063FF, + 0xA99F9AFF, + 0xC7C6BBFF, + 0xD3D3C6FF, + 0xD2D2C6FF, + 0xCFCEC3FF, + 0x8B8B87FF, + 0x646464FF, + 0x8D8D88FF, + 0xCACABDFF, + 0xCACABDFF, + 0xC9C8BBFF, + 0xC7C6B8FF, + 0xC4C4B6FF, + 0xC2C2B3FF, + 0xBBBBACFF, + 0x44443FFF, + 0x010101FD, + 0x000000AD, + 0x00000074, + 0x00000074, + 0x00000046, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010101DD, + 0x232321FF, + 0xB2B1ABFF, + 0xE0DED6FF, + 0xE6E4DEFF, + 0xEBDCD9FF, + 0xEAAFB8FF, + 0xE67F96FF, + 0xE0728CFF, + 0xD96B85FF, + 0xD1637DFF, + 0xC95B75FF, + 0xC1536DFF, + 0xB84B65FF, + 0xB26272FF, + 0xB2ABA5FF, + 0xABABA2FF, + 0x96968FFF, + 0xB9B8AEFF, + 0xCECEC1FF, + 0xB6B6ACFF, + 0x636363FF, + 0x999991FF, + 0xC9C9BCFF, + 0xC8C8BAFF, + 0xC1C1B3FF, + 0x878781FF, + 0xBEBEAFFF, + 0xC0C0B1FF, + 0xB9B9ABFF, + 0x363631FF, + 0x010101FA, + 0x0000009F, + 0x00000074, + 0x00000074, + 0x0000003A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000003B, + 0x010101E7, + 0x020202FF, + 0x42413FFF, + 0xB1AFA9FF, + 0xDAD9D0FF, + 0xE2E1DAFF, + 0xE2DCD6FF, + 0xDEADB4FF, + 0xD7778DFF, + 0xD0627CFF, + 0xC95B75FF, + 0xC1546DFF, + 0xBC7684FF, + 0xBBB8B0FF, + 0xB4B3ABFF, + 0x9C9B94FF, + 0x40403FFF, + 0x4E4E4BFF, + 0xC7C7B8FF, + 0xC9C9BBFF, + 0xBDBDB0FF, + 0xC6C6B8FF, + 0xC5C5B7FF, + 0xBEBEB0FF, + 0x6A6A66FF, + 0x4D4D4DFF, + 0xA2A297FF, + 0xBABAABFF, + 0x373733FF, + 0x010101FA, + 0x00000097, + 0x00000074, + 0x00000074, + 0x00000032, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000E, + 0x00000079, + 0x010101EA, + 0x010101FF, + 0x2D2D2BFF, + 0x9A9A93FF, + 0xD1D0C7FF, + 0xD9D7D0FF, + 0xD6D4CEFF, + 0xD2ABB0FF, + 0xC97485FF, + 0xC38792FF, + 0xC1BFB7FF, + 0xBBBAB2FF, + 0xA3A39CFF, + 0x4B4B4AFF, + 0x40403FFF, + 0x8D8C85FF, + 0xAAAA9EFF, + 0xC4C4B6FF, + 0xC3C3B5FF, + 0xC2C2B3FF, + 0xBCBCADFF, + 0x676763FF, + 0x4B4B4BFF, + 0x96968DFF, + 0xBBBBADFF, + 0x3C3C37FF, + 0x010101FA, + 0x00000099, + 0x00000074, + 0x00000073, + 0x0000002C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000A, + 0x0000006B, + 0x010101DC, + 0x010101FF, + 0x21201FFF, + 0x92928BFF, + 0xC7C6BCFF, + 0xCFCEC6FF, + 0xCBCAC2FF, + 0xC6C5BDFF, + 0xC0BFB7FF, + 0xAAA9A2FF, + 0x545453FF, + 0x4A4A49FF, + 0x94938CFF, + 0xA0A097FF, + 0x5B5A56FF, + 0x8B8B80FF, + 0xBFBFB0FF, + 0xBABAABFF, + 0x676763FF, + 0x4B4B4BFF, + 0x96968DFF, + 0xBDBDADFF, + 0x464642FF, + 0x010101FC, + 0x0000009C, + 0x00000074, + 0x00000072, + 0x00000025, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000003, + 0x00000054, + 0x010101C8, + 0x010101FF, + 0x1A1A18FF, + 0x8C8C83FF, + 0xBFBFB5FF, + 0xC2C1BAFF, + 0xBEBDB5FF, + 0xACABA4FF, + 0x5E5E5CFF, + 0x9C9B94FF, + 0xA7A69DFF, + 0x60605CFF, + 0x252525FF, + 0x595954FF, + 0xBDBDAEFF, + 0xBBBBACFF, + 0x6D6D68FF, + 0x98988EFF, + 0xBCBCAEFF, + 0x4A4A46FF, + 0x010101FD, + 0x000000A0, + 0x00000074, + 0x00000074, + 0x0000002D, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000003C, + 0x010101B1, + 0x010101FE, + 0x4A4A44FF, + 0xAEAEA2FF, + 0xBCBCB2FF, + 0xB6B6ADFF, + 0xB1B0A8FF, + 0xACABA2FF, + 0x86857FFF, + 0x2D2D2DFF, + 0x575753FF, + 0x939389FF, + 0xB3B3A6FF, + 0xBFBFB0FF, + 0xBFBFB0FF, + 0xBCBCADFF, + 0x4E4E48FF, + 0x010101FE, + 0x000000A5, + 0x00000074, + 0x00000074, + 0x00000035, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000003E, + 0x010101D2, + 0x11110FFF, + 0x94948AFF, + 0xB8B8ABFF, + 0xB2B1A7FF, + 0xAAA9A0FF, + 0xA4A49BFF, + 0x7E7E78FF, + 0x98988FFF, + 0x929289FF, + 0xB7B7A8FF, + 0xBFBFB0FF, + 0xBABAABFF, + 0x42423EFF, + 0x010101FD, + 0x000000A7, + 0x00000074, + 0x00000074, + 0x0000003C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000004, + 0x00000074, + 0x010101F8, + 0x444440FF, + 0xB3B2A4FF, + 0xB7B7AAFF, + 0xA9A99EFF, + 0x9D9C93FF, + 0x97978DFF, + 0x9E9E93FF, + 0xBFBFB0FF, + 0xAFAFA0FF, + 0x272724FF, + 0x010101FB, + 0x000000A0, + 0x00000074, + 0x00000074, + 0x0000004A, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000030, + 0x010101D6, + 0x020202FF, + 0x5A5954FF, + 0xA2A295FF, + 0xB5B5A8FF, + 0xB4B4A6FF, + 0xADADA0FF, + 0x6E6E65FF, + 0x060606FF, + 0x010101EE, + 0x00000090, + 0x00000074, + 0x00000074, + 0x0000004F, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000007, + 0x0000007A, + 0x010101EB, + 0x010101FF, + 0x010101FF, + 0x010101FF, + 0x010101FF, + 0x010101FB, + 0x010101C0, + 0x0000007D, + 0x00000074, + 0x0000006C, + 0x00000041, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000007, + 0x00000041, + 0x0000006C, + 0x00000083, + 0x00000072, + 0x00000043, + 0x0000002C, + 0x00000022, + 0x00000014, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/note.c b/widget/milsko/milskosrc/src/icon/note.c new file mode 100644 index 0000000000..91938d4893 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/note.c @@ -0,0 +1,2309 @@ +#include + +MwU32 MwIconNote[] = { + (48 << 16) | 48, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000023, + 0x0000006A, + 0x020000A6, + 0x010000CE, + 0x010000EC, + 0x010000FA, + 0x010000FA, + 0x010000EC, + 0x010000CE, + 0x020000A5, + 0x00000069, + 0x00000022, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000003, + 0x00000058, + 0x010000C4, + 0x010000FF, + 0x010000FF, + 0x1F1D11FF, + 0x4C4728FF, + 0x6D6637FF, + 0x787139FF, + 0x787036FF, + 0x6D662CFF, + 0x4B451BFF, + 0x1F1C0AFF, + 0x010000FF, + 0x010000FE, + 0x010000C3, + 0x00000056, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000045, + 0x010000D8, + 0x010000FF, + 0x2A281BFF, + 0x8B865AFF, + 0xDED68EFF, + 0xFFF59FFF, + 0xFFF59AFF, + 0xFFF493FF, + 0xFFF38BFF, + 0xFFF281FF, + 0xFFF177FF, + 0xFFF06CFF, + 0xFFEF60FF, + 0xDCCC48FF, + 0x897F26FF, + 0x282409FF, + 0x010000FF, + 0x010000D5, + 0x00000042, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x02000099, + 0x010000FF, + 0x28261BFF, + 0xAFAA7CFF, + 0xFEF7B5FF, + 0xFFF8B6FF, + 0xFFF7B4FF, + 0xFFF7B0FF, + 0xFFF6AAFF, + 0xFFF6A3FF, + 0xFFF59AFF, + 0xFFF490FF, + 0xFFF384FF, + 0xFFF178FF, + 0xFFF06CFF, + 0xFFEF5EFF, + 0xFFED50FF, + 0xFDEA41FF, + 0xAC9E22FF, + 0x252105FF, + 0x010000FF, + 0x02000095, + 0x00000007, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000014, + 0x010000CA, + 0x030201FF, + 0x7A7658FF, + 0xF8F2BCFF, + 0xFFF9C5FF, + 0xFFF9C8FF, + 0xFFF9C8FF, + 0xFFF9C5FF, + 0xFFF9C1FF, + 0xFFF8BAFF, + 0xFFF7B2FF, + 0xFFF6A8FF, + 0xFFF59DFF, + 0xFFF491FF, + 0xFFF384FF, + 0xFFF177FF, + 0xFFF069FF, + 0xFFEE5AFF, + 0xFFED4BFF, + 0xFFEB3CFF, + 0xF7E32CFF, + 0x756A0DFF, + 0x020100FF, + 0x010000C7, + 0x00000013, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000014, + 0x010000D5, + 0x0B0A07FF, + 0xB2AE87FF, + 0xFFFACAFF, + 0xFFFAD1FF, + 0xFFFBD6FF, + 0xFFFBD9FF, + 0xFFFBD9FF, + 0xFFFBD6FF, + 0xFFFAD1FF, + 0xFFFACAFF, + 0xFFF9C1FF, + 0xFFF8B6FF, + 0xFFF6AAFF, + 0xFFF59DFF, + 0xFFF490FF, + 0xFFF281FF, + 0xFFF173FF, + 0xFFEF64FF, + 0xFFEE54FF, + 0xFFEC44FF, + 0xFFEA34FF, + 0xFFE924FF, + 0xAE9E0EFF, + 0x0A0800FF, + 0x010000D4, + 0x00000013, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x010000C9, + 0x0B0A07FF, + 0xC2BD94FF, + 0xFFFACFFF, + 0xFFFBD9FF, + 0xFFFCE2FF, + 0xFFFDE8FF, + 0xFFFDEBFF, + 0xFFFDEBFF, + 0xFFFDE8FF, + 0xFFFCE2FF, + 0xFFFBD9FF, + 0xFFFACFFF, + 0xFFF9C3FF, + 0xFFF8B6FF, + 0xFFF6A8FF, + 0xFFF59AFF, + 0xFFF38BFF, + 0xFFF27BFF, + 0xFFF06CFF, + 0xFFEE5CFF, + 0xFFED4BFF, + 0xFFEB3BFF, + 0xFFE92BFF, + 0xFFE81AFF, + 0xBFAC07FF, + 0x0A0800FF, + 0x010000C6, + 0x00000007, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x02000097, + 0x030201FF, + 0xB1AD86FF, + 0xFFFACFFF, + 0xFFFBDCFF, + 0xFFFDE8FF, + 0xFFFEF1FF, + 0xFFFEF8FF, + 0xFFFFFCFF, + 0xFFFFFCFF, + 0xFFFEF8FF, + 0xFFFEF1FF, + 0xFFFDE8FF, + 0xFFFBDCFF, + 0xFFFACFFF, + 0xFFF9C1FF, + 0xFFF7B2FF, + 0xFFF6A3FF, + 0xFFF493FF, + 0xFFF283FF, + 0xFFF173FF, + 0xFFEF62FF, + 0xFFED52FF, + 0xFFEC41FF, + 0xFFEA30FF, + 0xFFE81FFF, + 0xFFE60EFF, + 0xAD9B00FF, + 0x020100FF, + 0x02000092, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000043, + 0x010000FF, + 0x777356FF, + 0xFFFACAFF, + 0xFFFBD9FF, + 0xFFFDE8FF, + 0xFFFEF5FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFEF5FF, + 0xFFFDE8FF, + 0xFFFBD9FF, + 0xFFFACAFF, + 0xFFF8BAFF, + 0xFFF6AAFF, + 0xFFF59AFF, + 0xFFF389FF, + 0xFFF178FF, + 0xFFF068FF, + 0xFFEE57FF, + 0xFFEC46FF, + 0xFFEA34FF, + 0xFFE923FF, + 0xFFE712FF, + 0xFFE501FF, + 0x736300FF, + 0x010000FE, + 0x0000003F, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000003, + 0x010000D6, + 0x252319FF, + 0xF7F1BBFF, + 0xFFFAD1FF, + 0xFFFCE2FF, + 0xFFFEF1FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFEF1FF, + 0xFFFCE2FF, + 0xFFFAD1FF, + 0xFFF9C1FF, + 0xFFF7B0FF, + 0xFFF59FFF, + 0xFFF38EFF, + 0xFFF27DFF, + 0xFFF06CFF, + 0xFFEE5AFF, + 0xFFEC49FF, + 0xFFEB38FF, + 0xFFE926FF, + 0xFFE715FF, + 0xFFE504FF, + 0xF6D700FF, + 0x231D00FF, + 0x010000D2, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000057, + 0x010000FF, + 0xADA87AFF, + 0xFFF9C5FF, + 0xFFFBD6FF, + 0xFFFDE8FF, + 0xFFFEF8FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFEF8FF, + 0xFFFDE8FF, + 0xFFFBD6FF, + 0xFFF9C5FF, + 0xFFF7B4FF, + 0xFFF6A3FF, + 0xFFF491FF, + 0xFFF280FF, + 0xFFF06EFF, + 0xFFEE5DFF, + 0xFFED4BFF, + 0xFFEB3AFF, + 0xFFE928FF, + 0xFFE717FF, + 0xFFE605FF, + 0xFFE000FF, + 0xA98F00FF, + 0x010000FF, + 0x00000054, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000C5, + 0x29271AFF, + 0xFDF6B5FF, + 0xFFF9C8FF, + 0xFFFBD9FF, + 0xFFFDEBFF, + 0xFFFFFCFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFCFF, + 0xFFFDEBFF, + 0xFFFBD9FF, + 0xFFF9C8FF, + 0xFFF8B6FF, + 0xFFF6A5FF, + 0xFFF493FF, + 0xFFF281FF, + 0xFFF070FF, + 0xFFEF5EFF, + 0xFFED4DFF, + 0xFFEB3BFF, + 0xFFE92AFF, + 0xFFE718FF, + 0xFFE606FF, + 0xFFE000FF, + 0xFDD600FF, + 0x271F00FF, + 0x010000C0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000022, + 0x010000FE, + 0x8A8559FF, + 0xFFF8B6FF, + 0xFFF9C8FF, + 0xFFFBD9FF, + 0xFFFDEBFF, + 0xFFFFFCFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFCFF, + 0xFFFDEBFF, + 0xFFFBD9FF, + 0xFFF9C8FF, + 0xFFF8B6FF, + 0xFFF6A5FF, + 0xFFF493FF, + 0xFFF281FF, + 0xFFF070FF, + 0xFFEF5EFF, + 0xFFED4DFF, + 0xFFEB3BFF, + 0xFFE92AFF, + 0xFFE718FF, + 0xFFE606FF, + 0xFFE000FF, + 0xFFD800FF, + 0x856C00FF, + 0x010000FE, + 0x0000001E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000069, + 0x010000FF, + 0xDCD48DFF, + 0xFFF7B4FF, + 0xFFF9C5FF, + 0xFFFBD6FF, + 0xFFFDE8FF, + 0xFFFEF8FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFEF8FF, + 0xFFFDE8FF, + 0xFFFBD6FF, + 0xFFF9C5FF, + 0xFFF7B4FF, + 0xFFF6A3FF, + 0xFFF491FF, + 0xFFF280FF, + 0xFFF06EFF, + 0xFFEE5DFF, + 0xFFED4BFF, + 0xFFEB3AFF, + 0xFFE928FF, + 0xFFE717FF, + 0xFFE605FF, + 0xFFE000FF, + 0xFFD800FF, + 0xD8B000FF, + 0x010000FF, + 0x00000065, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x020000A5, + 0x1E1C10FF, + 0xFFF59FFF, + 0xFFF7B0FF, + 0xFFF9C1FF, + 0xFFFAD1FF, + 0xFFFCE2FF, + 0xFFFEF1FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFEF1FF, + 0xFFFCE2FF, + 0xFFFAD1FF, + 0xFFF9C1FF, + 0xFFF7B0FF, + 0xFFF59FFF, + 0xFFF38EFF, + 0xFFF27DFF, + 0xFFF06CFF, + 0xFFEE5AFF, + 0xFFEC49FF, + 0xFFEB38FF, + 0xFFE926FF, + 0xFFE715FF, + 0xFFE504FF, + 0xFFDF00FF, + 0xFFD700FF, + 0xFFCF00FF, + 0x1B1400FF, + 0x020000A2, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000CF, + 0x4C4728FF, + 0xFFF59AFF, + 0xFFF6AAFF, + 0xFFF8BAFF, + 0xFFFACAFF, + 0xFFFBD9FF, + 0xFFFDE8FF, + 0xFFFEF5FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFBECFF, + 0xFFE8A3FF, + 0xFFDE7CFF, + 0xFFDC76FF, + 0xFFE387FF, + 0xFFF4A5FF, + 0xFFF59AFF, + 0xFFF389FF, + 0xFFF178FF, + 0xFFF068FF, + 0xFFEE57FF, + 0xFFEC46FF, + 0xFFEA34FF, + 0xFFE923FF, + 0xFFE712FF, + 0xFFE501FF, + 0xFFDD00FF, + 0xFFD600FF, + 0xFFCE00FF, + 0x483800FF, + 0x010000CB, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000EC, + 0x6C6637FF, + 0xFFF493FF, + 0xFFF6A3FF, + 0xFFF7B2FF, + 0xFFF9C1FF, + 0xFFFACFFF, + 0xFFFBDCFF, + 0xFFFDE8FF, + 0xFFFEF1FF, + 0xFFFEF8FF, + 0xFFFFFCFF, + 0xFFFFFCFF, + 0xFFFEF8FF, + 0xFFFBE8FF, + 0xFFE28FFF, + 0xFFDB76FF, + 0xFFDA71FF, + 0xFFD86BFF, + 0xFFD765FF, + 0xFFDB6BFF, + 0xFFF28FFF, + 0xFFF283FF, + 0xFFF173FF, + 0xFFEF62FF, + 0xFFED52FF, + 0xFFEC41FF, + 0xFFEA30FF, + 0xFFE81FFF, + 0xFFE60EFF, + 0xFFE400FF, + 0xFFDC00FF, + 0xFFD400FF, + 0xFFCC00FF, + 0x6A5200FF, + 0x010000E9, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000F9, + 0x7B743BFF, + 0xFFF38BFF, + 0xFFF59AFF, + 0xFFF6A8FF, + 0xFFF8B6FF, + 0xFFF9C3FF, + 0xFFFACFFF, + 0xFFFBD9FF, + 0xFFFCE2FF, + 0xFFFDE8FF, + 0xFFFDEBFF, + 0xFFFDEBFF, + 0xFFFDE8FF, + 0xFFE9A2FF, + 0xFFDB75FF, + 0xFFDA71FF, + 0xFFD96CFF, + 0xFFD767FF, + 0xFFD661FF, + 0xFFD45BFF, + 0xFFE06AFF, + 0xFFF27BFF, + 0xFFF06CFF, + 0xFFEE5CFF, + 0xFFED4BFF, + 0xFFEB3BFF, + 0xFFE92BFF, + 0xFFE81AFF, + 0xFFE609FF, + 0xFFE200FF, + 0xFFDA00FF, + 0xFFD200FF, + 0xFFCA00FF, + 0x795E00FF, + 0x010000F8, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000F4, + 0x756E34FF, + 0xFFF281FF, + 0xFFF490FF, + 0xFFF59DFF, + 0xFFF6AAFF, + 0xFFF8B6FF, + 0xFFF9C1FF, + 0xFFFACAFF, + 0xFFFAD1FF, + 0xFFFBD6FF, + 0xFFFBD9FF, + 0xFFFBD9FF, + 0xFFF8CEFF, + 0xFFDB75FF, + 0xFFD96FFF, + 0xFFD86BFF, + 0xFFEE9EFF, + 0xFFEC94FF, + 0xFFD55CFF, + 0xFFD357FF, + 0xFFD453FF, + 0xFFEE70FF, + 0xFFEF64FF, + 0xFFEE54FF, + 0xFFEC44FF, + 0xFFEA34FF, + 0xFFE924FF, + 0xFFE714FF, + 0xFFE504FF, + 0xFFDF00FF, + 0xFFD800FF, + 0xFFD000FF, + 0xFFC800FF, + 0x745A00FF, + 0x010000F2, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000DD, + 0x5E5826FF, + 0xFFF177FF, + 0xFFF384FF, + 0xFFF491FF, + 0xFFF59DFF, + 0xFFF6A8FF, + 0xFFF7B2FF, + 0xFFF8BAFF, + 0xFFF9C1FF, + 0xFFF9C5FF, + 0xFFF9C8FF, + 0xFFF9C8FF, + 0xFFF0ABFF, + 0xFFD86BFF, + 0xFFD868FF, + 0xFFDE77FF, + 0xFFF6A8FF, + 0xFFF59DFF, + 0xFFDB64FF, + 0xFFD252FF, + 0xFFD14CFF, + 0xFFE65FFF, + 0xFFEE5AFF, + 0xFFED4BFF, + 0xFFEB3CFF, + 0xFFEA2DFF, + 0xFFE81DFF, + 0xFFE60DFF, + 0xFFE400FF, + 0xFFDC00FF, + 0xFFD500FF, + 0xFFCD00FF, + 0xFFC800FF, + 0x5C4700FF, + 0x010000DA, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000C6, + 0x47421AFF, + 0xFFF06CFF, + 0xFFF178FF, + 0xFFF384FF, + 0xFFF490FF, + 0xFFF59AFF, + 0xFFF6A3FF, + 0xFFF6AAFF, + 0xFFF7B0FF, + 0xFFF7B4FF, + 0xFFF8B6FF, + 0xFFF8B6FF, + 0xFFE992FF, + 0xFFD764FF, + 0xFFD662FF, + 0xFFE37CFF, + 0xFFF59AFF, + 0xFFF490FF, + 0xFFE068FF, + 0xFFD14DFF, + 0xFFD048FF, + 0xFFE151FF, + 0xFFED50FF, + 0xFFEC42FF, + 0xFFEA33FF, + 0xFFE924FF, + 0xFFE715FF, + 0xFFE605FF, + 0xFFE000FF, + 0xFFD900FF, + 0xFFD200FF, + 0xFFCA00FF, + 0xFFC800FF, + 0x453500FF, + 0x010000C4, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0200009F, + 0x151307FF, + 0xFDED5FFF, + 0xFFF06CFF, + 0xFFF177FF, + 0xFFF281FF, + 0xFFF38BFF, + 0xFFF493FF, + 0xFFF59AFF, + 0xFFF59FFF, + 0xFFF6A3FF, + 0xFFF6A5FF, + 0xFFF6A5FF, + 0xFFE885FF, + 0xFFD55DFF, + 0xFFD45BFF, + 0xFFE272FF, + 0xFFF38BFF, + 0xFFF281FF, + 0xFFDF5EFF, + 0xFFD048FF, + 0xFFCF42FF, + 0xFFDF49FF, + 0xFFEC46FF, + 0xFFEB38FF, + 0xFFE92AFF, + 0xFFE81BFF, + 0xFFE60CFF, + 0xFFE400FF, + 0xFFDD00FF, + 0xFFD600FF, + 0xFFCE00FF, + 0xFFC800FF, + 0xFDC600FF, + 0x161000FF, + 0x0200009C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000059, + 0x010000FF, + 0xCBBD42FF, + 0xFFEF5EFF, + 0xFFF069FF, + 0xFFF173FF, + 0xFFF27BFF, + 0xFFF283FF, + 0xFFF389FF, + 0xFFF38EFF, + 0xFFF491FF, + 0xFFF493FF, + 0xFFF493FF, + 0xFFEA7FFF, + 0xFFD356FF, + 0xFFD354FF, + 0xFFD95CFF, + 0xFFF27BFF, + 0xFFF173FF, + 0xFFD84DFF, + 0xFFCF42FF, + 0xFFCD3DFF, + 0xFFE342FF, + 0xFFEB3AFF, + 0xFFEA2DFF, + 0xFFE81FFF, + 0xFFE711FF, + 0xFFE503FF, + 0xFFE000FF, + 0xFFD900FF, + 0xFFD200FF, + 0xFFCB00FF, + 0xFFC800FF, + 0xC89D00FF, + 0x010000FF, + 0x00000056, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000013, + 0x010000FC, + 0x807623FF, + 0xFFED50FF, + 0xFFEE5AFF, + 0xFFEF64FF, + 0xFFF06CFF, + 0xFFF173FF, + 0xFFF178FF, + 0xFFF27DFF, + 0xFFF280FF, + 0xFFF281FF, + 0xFFF281FF, + 0xFFEF7CFF, + 0xFFD351FF, + 0xFFD14DFF, + 0xFFD14AFF, + 0xFFE661FF, + 0xFFE55AFF, + 0xFFCE40FF, + 0xFFCD3CFF, + 0xFFCD38FF, + 0xFFE939FF, + 0xFFEA2EFF, + 0xFFE821FF, + 0xFFE714FF, + 0xFFE606FF, + 0xFFE200FF, + 0xFFDB00FF, + 0xFFD400FF, + 0xFFCE00FF, + 0xFFC800FF, + 0xFFC800FF, + 0x7F6300FF, + 0x010000FC, + 0x00000012, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000B6, + 0x181505FF, + 0xF5E33FFF, + 0xFFED4BFF, + 0xFFEE54FF, + 0xFFEE5CFF, + 0xFFEF62FF, + 0xFFF068FF, + 0xFFF06CFF, + 0xFFF06EFF, + 0xFFF070FF, + 0xFFF070FF, + 0xFFF06EFF, + 0xFFDD56FF, + 0xFFCF46FF, + 0xFFCF44FF, + 0xFFCE41FF, + 0xFFCE3EFF, + 0xFFCD3AFF, + 0xFFCC36FF, + 0xFFD835FF, + 0xFFEA2DFF, + 0xFFE821FF, + 0xFFE715FF, + 0xFFE608FF, + 0xFFE300FF, + 0xFFDD00FF, + 0xFFD600FF, + 0xFFD000FF, + 0xFFC900FF, + 0xFFC800FF, + 0xF5C000FF, + 0x171100FF, + 0x010000B4, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000003B, + 0x010000FF, + 0x91851DFF, + 0xFFEB3CFF, + 0xFFEC44FF, + 0xFFED4BFF, + 0xFFED52FF, + 0xFFEE57FF, + 0xFFEE5AFF, + 0xFFEE5DFF, + 0xFFEF5EFF, + 0xFFEF5EFF, + 0xFFEE5DFF, + 0xFFEC59FF, + 0xFFD443FF, + 0xFFCD3DFF, + 0xFFCD3AFF, + 0xFFCC37FF, + 0xFFCB34FF, + 0xFFD031FF, + 0xFFE62AFF, + 0xFFE81FFF, + 0xFFE714FF, + 0xFFE608FF, + 0xFFE300FF, + 0xFFDD00FF, + 0xFFD800FF, + 0xFFD100FF, + 0xFFCB00FF, + 0xFFC800FF, + 0xFFC800FF, + 0x8D6F00FF, + 0x010000FF, + 0x00000038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000BD, + 0x161303FF, + 0xE6D329FF, + 0xFFEA34FF, + 0xFFEB3BFF, + 0xFFEC41FF, + 0xFFEC46FF, + 0xFFEC49FF, + 0xFFED4BFF, + 0xFFED4DFF, + 0xFFED4DFF, + 0xFFED4BFF, + 0xFFEC49FF, + 0xFFE945FF, + 0xFFD238FF, + 0xFFCB33FF, + 0xFFCA30FF, + 0xFFD02DFF, + 0xFFE724FF, + 0xFFE81BFF, + 0xFFE711FF, + 0xFFE606FF, + 0xFFE300FF, + 0xFFDD00FF, + 0xFFD800FF, + 0xFFD200FF, + 0xFFCC00FF, + 0xFFC800FF, + 0xFFC800FF, + 0xE5B400FF, + 0x151000FF, + 0x010000BA, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000028, + 0x010000F4, + 0x413A07FF, + 0xFCE624FF, + 0xFFE92BFF, + 0xFFEA30FF, + 0xFFEA34FF, + 0xFFEB38FF, + 0xFFEB3AFF, + 0xFFEB3BFF, + 0xFFEB3BFF, + 0xFFEB3AFF, + 0xFFEB38FF, + 0xFFEA34FF, + 0xFFDA30FF, + 0xFFC92CFF, + 0xFFC92AFF, + 0xFFD822FF, + 0xFFE715FF, + 0xFFE60CFF, + 0xFFE503FF, + 0xFFE200FF, + 0xFFDD00FF, + 0xFFD800FF, + 0xFFD200FF, + 0xFFCD00FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFDC600FF, + 0x453500FF, + 0x010000F3, + 0x00000025, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000061, + 0x010000FF, + 0x776B09FF, + 0xFFE81AFF, + 0xFFE81FFF, + 0xFFE923FF, + 0xFFE926FF, + 0xFFE928FF, + 0xFFE92AFF, + 0xFFE92AFF, + 0xFFE928FF, + 0xFFE926FF, + 0xFFE923FF, + 0xFFD823FF, + 0xFFC825FF, + 0xFFC723FF, + 0xFFD716FF, + 0xFFE605FF, + 0xFFE400FF, + 0xFFE000FF, + 0xFFDB00FF, + 0xFFD600FF, + 0xFFD100FF, + 0xFFCC00FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0x755B00FF, + 0x010000FF, + 0x0000005E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x02000094, + 0x010000FF, + 0x6B6004FF, + 0xFEE50EFF, + 0xFFE712FF, + 0xFFE715FF, + 0xFFE717FF, + 0xFFE718FF, + 0xFFE718FF, + 0xFFE717FF, + 0xFFE715FF, + 0xFFE712FF, + 0xFFD717FF, + 0xFFC61EFF, + 0xFFC61CFF, + 0xFFD50DFF, + 0xFFE000FF, + 0xFFDD00FF, + 0xFFD900FF, + 0xFFD400FF, + 0xFFD000FF, + 0xFFCB00FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFEC700FF, + 0x725900FF, + 0x010000FF, + 0x02000092, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x0200008D, + 0x010000FF, + 0x594F00FF, + 0xEED601FF, + 0xFFE504FF, + 0xFFE605FF, + 0xFFE606FF, + 0xFFE606FF, + 0xFFE605FF, + 0xFFE504FF, + 0xFFE501FF, + 0xFFD50DFF, + 0xFFC517FF, + 0xFFC415FF, + 0xFFD00AFF, + 0xFFD900FF, + 0xFFD600FF, + 0xFFD200FF, + 0xFFCE00FF, + 0xFFC900FF, + 0xFFC800FF, + 0xFFC800FF, + 0xEDBA00FF, + 0x574300FF, + 0x010000FF, + 0x0200008B, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000077, + 0x010000FA, + 0x1C1700FF, + 0x8C7A00FF, + 0xFFE000FF, + 0xFFE000FF, + 0xFFE000FF, + 0xFFE000FF, + 0xFFDF00FF, + 0xFFDD00FF, + 0xFFD009FF, + 0xFFC310FF, + 0xFFC20EFF, + 0xFFCB06FF, + 0xFFD200FF, + 0xFFCE00FF, + 0xFFCB00FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0x8A6C00FF, + 0x1B1400FF, + 0x010000F9, + 0x00000074, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000030, + 0x010000E5, + 0x181300FF, + 0x4B3F00FF, + 0xAA9000FF, + 0xFCD500FF, + 0xFFD800FF, + 0xFFD700FF, + 0xFFD600FF, + 0xFFCB06FF, + 0xFFC109FF, + 0xFFC107FF, + 0xFFC603FF, + 0xFFCA00FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFCC500FF, + 0xAD8800FF, + 0x4B3A00FF, + 0x181200FF, + 0x010000E5, + 0x0000002F, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x010000BE, + 0x403300FF, + 0xF7C900FF, + 0xBE9B00FF, + 0x977B00FF, + 0xB79500FF, + 0xE8BC00FF, + 0xFFCE00FF, + 0xFFC602FF, + 0xFFC002FF, + 0xFFBF00FF, + 0xFFC202FF, + 0xFFC800FF, + 0xE8B600FF, + 0xB79000FF, + 0x977600FF, + 0xBE9500FF, + 0xF7C200FF, + 0x403100FF, + 0x010000BE, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x020000A7, + 0x291F00FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC202FF, + 0xFFBB03FF, + 0xFFBB03FF, + 0xFFC202FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0x271E00FF, + 0x020000A6, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000007D, + 0x050300FF, + 0xE5B400FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC202FF, + 0xFFBB03FF, + 0xFFBB03FF, + 0xFFC202FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xE4B300FF, + 0x040200FF, + 0x00000080, + 0x00000009, + 0x00000007, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000021, + 0x010000FD, + 0x765C00FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC301FF, + 0xFFBB03FF, + 0xFFBB03FF, + 0xFFC301FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0x745A00FF, + 0x010000FD, + 0x0000003A, + 0x0000001C, + 0x0000001A, + 0x00000016, + 0x00000013, + 0x0000000E, + 0x0000000A, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x02000099, + 0x050300FF, + 0xBD9400FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC301FF, + 0xFFC301FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xBA9200FF, + 0x040200FF, + 0x010000AB, + 0x00000032, + 0x00000030, + 0x0000002C, + 0x00000028, + 0x00000024, + 0x0000001F, + 0x0000001A, + 0x00000014, + 0x0000000E, + 0x00000008, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000E, + 0x010000E3, + 0x0C0900FF, + 0xAF8900FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xAD8800FF, + 0x0B0800FF, + 0x010000E9, + 0x0000004D, + 0x00000044, + 0x00000042, + 0x0000003E, + 0x00000039, + 0x00000034, + 0x0000002E, + 0x00000028, + 0x00000021, + 0x0000001A, + 0x00000014, + 0x0000000C, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000002, + 0x0000008E, + 0x010000FF, + 0x010000FF, + 0x574300FF, + 0xCEA200FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xFFC800FF, + 0xCDA100FF, + 0x544100FF, + 0x010000FF, + 0x010000FF, + 0x000000A9, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000041, + 0x0000003A, + 0x00000033, + 0x0000002C, + 0x00000024, + 0x0000001D, + 0x00000015, + 0x0000000D, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000006, + 0x00000087, + 0x010000FF, + 0x7B7B7BFF, + 0x0F0E0EFF, + 0x010000FF, + 0x231B00FF, + 0x5C4700FF, + 0x745A00FF, + 0x745A00FF, + 0x5C4700FF, + 0x221A00FF, + 0x010000FF, + 0x0C0B0BFF, + 0x727272FF, + 0x010000FF, + 0x000000A2, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000043, + 0x0000003B, + 0x00000033, + 0x0000002B, + 0x00000023, + 0x0000001B, + 0x00000012, + 0x0000000A, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x00000088, + 0x010000FF, + 0xF1F1F1FF, + 0xE5E5E5FF, + 0x8F8F8FFF, + 0x4F4E4EFF, + 0x212020FF, + 0x0B0A0AFF, + 0x0B0A0AFF, + 0x1C1B1BFF, + 0x373636FF, + 0x5E5E5EFF, + 0xB6B6B6FF, + 0xD5D5D5FF, + 0x010000FF, + 0x000000A2, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x0000003D, + 0x00000035, + 0x0000002D, + 0x00000024, + 0x0000001C, + 0x00000014, + 0x0000000C, + 0x00000003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000006, + 0x00000078, + 0x010000FF, + 0xA6A6A6FF, + 0xC8C8C8FF, + 0xD7D7D7FF, + 0xDEDEDEFF, + 0xDBDBDBFF, + 0xCFCFCFFF, + 0xBABABAFF, + 0x9F9F9FFF, + 0x9A9A9AFF, + 0xB9B9B9FF, + 0xD9D9D9FF, + 0xA2A2A2FF, + 0x010000FF, + 0x00000095, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000042, + 0x0000003A, + 0x00000032, + 0x0000002A, + 0x00000022, + 0x0000001A, + 0x00000012, + 0x0000000A, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000047, + 0x010000FF, + 0x6F6F6FFF, + 0x999999FF, + 0x8F8F8FFF, + 0x969696FF, + 0x959595FF, + 0x8F8F8FFF, + 0x9B9B9BFF, + 0xADADADFF, + 0xC4C4C4FF, + 0xDDDDDDFF, + 0xB1B1B1FF, + 0x4C4C4CFF, + 0x010000FF, + 0x00000071, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000044, + 0x00000040, + 0x00000039, + 0x00000032, + 0x0000002B, + 0x00000023, + 0x0000001C, + 0x00000014, + 0x0000000C, + 0x00000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x010000D3, + 0x191818FF, + 0xBFBFBFFF, + 0xCBCBCBFF, + 0xC5C5C5FF, + 0xC5C5C5FF, + 0xC9C9C9FF, + 0xD3D3D3FF, + 0xE1E1E1FF, + 0xBFBFBFFF, + 0x959595FF, + 0x5A5A5AFF, + 0x0A0909FF, + 0x010000DD, + 0x00000045, + 0x00000044, + 0x00000043, + 0x00000040, + 0x0000003C, + 0x00000037, + 0x00000032, + 0x0000002C, + 0x00000026, + 0x00000020, + 0x00000019, + 0x00000012, + 0x0000000B, + 0x00000004, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002F, + 0x010000F0, + 0x0F0E0EFF, + 0x636363FF, + 0x9D9D9DFF, + 0xA1A1A1FF, + 0x9C9C9CFF, + 0x8E8E8EFF, + 0x797979FF, + 0x5B5B5BFF, + 0x3C3C3CFF, + 0x0B0A0AFF, + 0x010000F2, + 0x00000057, + 0x00000033, + 0x00000032, + 0x00000030, + 0x0000002D, + 0x0000002A, + 0x00000026, + 0x00000022, + 0x0000001D, + 0x00000018, + 0x00000012, + 0x0000000C, + 0x00000006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002E, + 0x010000D1, + 0x010000FF, + 0x0A0909FF, + 0x201F1FFF, + 0x2A2929FF, + 0x2A2929FF, + 0x1F1E1EFF, + 0x0A0909FF, + 0x010000FF, + 0x010000D4, + 0x00000046, + 0x0000001E, + 0x0000001E, + 0x0000001E, + 0x0000001C, + 0x0000001A, + 0x00000017, + 0x00000014, + 0x00000010, + 0x0000000C, + 0x00000008, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000004, + 0x00000052, + 0x020000A8, + 0x010000DF, + 0x010000F6, + 0x010000F6, + 0x010000DF, + 0x020000A8, + 0x00000054, + 0x0000000B, + 0x00000009, + 0x0000000A, + 0x0000000A, + 0x00000008, + 0x00000007, + 0x00000005, + 0x00000003, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/right.c b/widget/milsko/milskosrc/src/icon/right.c new file mode 100644 index 0000000000..871fee18de --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/right.c @@ -0,0 +1,445 @@ +#include + +MwU32 MwIconRight[] = { + (20 << 16) | 22, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/search.c b/widget/milsko/milskosrc/src/icon/search.c new file mode 100644 index 0000000000..e275db2425 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/search.c @@ -0,0 +1,445 @@ +#include + +MwU32 MwIconSearch[] = { + (20 << 16) | 22, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0xFFFFFFFF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x000000FF, + 0x333333FF, + 0x000000FF, + 0x333333FF, + 0x000000FF, + 0x333333FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x999999FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0x333333FF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x333333FF, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0x999999FF, + 0x66CCFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x999999FF, + 0x000000FF, + 0x333333FF, + 0x000000FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0x66CCFFFF, + 0x66CCFFFF, + 0xFFFFFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x000000FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x333333FF, + 0x000000FF, + 0x333333FF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x000000FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x000000FF, + 0x333333FF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0x999999FF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x999999FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x333333FF, + 0x333333FF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x333333FF, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0x66CCFFFF, + 0x66CCFFFF, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x999999FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x333333FF, + 0x999999FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x999999FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0x333333FF, + 0x333333FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x999999FF, + 0x333333FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/up.c b/widget/milsko/milskosrc/src/icon/up.c new file mode 100644 index 0000000000..41d1056716 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/up.c @@ -0,0 +1,445 @@ +#include + +MwU32 MwIconUp[] = { + (20 << 16) | 22, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0x000000FF, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0xCCFFFF00, + 0}; diff --git a/widget/milsko/milskosrc/src/icon/warning.c b/widget/milsko/milskosrc/src/icon/warning.c new file mode 100644 index 0000000000..08236e2363 --- /dev/null +++ b/widget/milsko/milskosrc/src/icon/warning.c @@ -0,0 +1,2309 @@ +#include + +MwU32 MwIconWarning[] = { + (48 << 16) | 48, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A2, + 0x000000FA, + 0x000000D5, + 0x00000099, + 0x00000055, + 0x00000012, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002E, + 0x000000AC, + 0x000000FE, + 0x10100FFF, + 0x676660FF, + 0x3F3F3AFF, + 0x080807FF, + 0x000000FF, + 0x000000FC, + 0x000000CB, + 0x0000008C, + 0x0000004C, + 0x0000000F, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002E, + 0x000000AC, + 0x000000FE, + 0x0D0D0DFF, + 0x777772FF, + 0xEEECE0FF, + 0xFFFDEBFF, + 0xFFFCE6FF, + 0xFBF8DEFF, + 0xCCC9B1FF, + 0x888673FF, + 0x444338FF, + 0x090907FF, + 0x000000FF, + 0x000000FC, + 0x000000CB, + 0x0000008C, + 0x0000004C, + 0x0000000F, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000AC, + 0x000000FE, + 0x0D0D0DFF, + 0x777776FF, + 0xEEEDE7FF, + 0xFFFEF2FF, + 0xFFFDEDFF, + 0xFFFDE9FF, + 0xFFFCE4FF, + 0xFFFBDFFF, + 0xFFFBDAFF, + 0xFFFAD5FF, + 0xFFFAD1FF, + 0xFBF5C9FF, + 0xCCC79FFF, + 0x888467FF, + 0x444232FF, + 0x090907FF, + 0x000000FF, + 0x000000FC, + 0x000000CB, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x4A4838FF, + 0xCBCAC5FF, + 0xFFFEF9FF, + 0xFFFEF4FF, + 0xFFFDF0FF, + 0xFFFDEBFF, + 0xFFFCE6FF, + 0xFFFCE1FF, + 0xFFFBDCFF, + 0xFFFBD8FF, + 0xFFFAD3FF, + 0xFFFACEFF, + 0xFFF9C9FF, + 0xFFF9C5FF, + 0xFFF8C0FF, + 0xFFF8BBFF, + 0xF7EFB0FF, + 0xBAB17DFF, + 0x413215FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80794CFF, + 0xFFEF93FF, + 0xFAE99AE9, + 0xFFF4C1C2, + 0xFFFBE1CA, + 0xFFFCE8FA, + 0xFFFCE3FF, + 0xFFFBDFFF, + 0xFFFBDAFF, + 0xFFFAD5FF, + 0xFFFAD0FF, + 0xFFF9CCFF, + 0xFFF9C7FF, + 0xFFF8C2FF, + 0xFFF8BDFF, + 0xFFF7B8FF, + 0xDFC476EA, + 0xD28A18FF, + 0x7A500EFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80784BFF, + 0xFFEE91FF, + 0xFFEB8DFF, + 0xFFE988FF, + 0xFFE783FF, + 0xFFE686EE, + 0xFFEEA6C6, + 0xFFF6CBC4, + 0xFFFBD6F3, + 0xFFFAD3FF, + 0xFFFACEFF, + 0xFFF9C9FF, + 0xFFF9C4FF, + 0xFFF8BFFF, + 0xFEF1AEEF, + 0xF2AC31C2, + 0xF09B12FE, + 0xF29E18FF, + 0x7A510FFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80784AFF, + 0xFFED90FF, + 0xFFEA8BFF, + 0xFFE886FF, + 0xFFE681FF, + 0xFFE37DFF, + 0xFFE178FF, + 0xFFDF73FF, + 0xFFDD73F7, + 0xFFE691CA, + 0xFFF1B5C2, + 0xFFFAC5E9, + 0xFFF8C2FF, + 0xF7CD6FC6, + 0xEE9609EC, + 0xEF980DFF, + 0xF09B13FF, + 0xF29E18FF, + 0x7A510FFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80774AFF, + 0xFFEC8EFF, + 0xFFEA89FF, + 0xFFE784FF, + 0xFFE580FF, + 0xFFE27BFF, + 0xFFE076FF, + 0xFFDE71FF, + 0xFFDB6DFF, + 0xFFD968FF, + 0xFFD763FF, + 0xFFD65FFC, + 0xF4AF31B8, + 0xED9406FF, + 0xEE9509FF, + 0xEF980EFF, + 0xF19B13FF, + 0xF29E19FF, + 0x7A510FFF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807749FF, + 0xFFEB8CFF, + 0xFFE987FF, + 0xFFE683FF, + 0xFFE47EFF, + 0xFFE279FF, + 0xFFDF74FF, + 0xFFDD70FF, + 0xFFDA6BFF, + 0xFFD866FF, + 0xFFD661FF, + 0xFFD35DFF, + 0xF3A721C0, + 0xED9406FF, + 0xEE9609FF, + 0xEF990FFF, + 0xF19C14FF, + 0xF29F19FF, + 0x7A5110FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807648FF, + 0xFFEA8AFF, + 0xFFE885FF, + 0xFFE581FF, + 0xFFE37CFF, + 0xFFE177FF, + 0xFFDE72FF, + 0xFFDC6EFF, + 0xFFDA69FF, + 0xFFD764FF, + 0xFFD560FF, + 0xFFD25BFF, + 0xF3A720C0, + 0xED9406FF, + 0xEE960AFF, + 0xEF990FFF, + 0xF19C14FF, + 0xF29F1AFF, + 0x7A5110FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807647FF, + 0xFFE988FF, + 0xFFE784FF, + 0xFFE47FFF, + 0xFFE27AFF, + 0xFFE075FF, + 0xFFDD71FF, + 0xFFDB6CFF, + 0xFFD967FF, + 0xFFD662FF, + 0xFFD45EFF, + 0xFFD159FF, + 0xF3A720C0, + 0xED9406FF, + 0xEE960AFF, + 0xF09910FF, + 0xF19C15FF, + 0xF39F1AFF, + 0x7A5110FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807646FF, + 0xFFE887FF, + 0xFFE682FF, + 0xFFE47DFF, + 0xFFE178FF, + 0xFFDF74FF, + 0xFFDC6FFF, + 0xFFDA6AFF, + 0xFFD865FF, + 0xFFD561FF, + 0xFFD35CFF, + 0xFFD157FF, + 0xF3A61FC0, + 0xED9406FF, + 0xEE970BFF, + 0xF09A10FF, + 0xF19D16FF, + 0xF39F1BFF, + 0x7A5110FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807545FF, + 0xFFE785FF, + 0xFFE580FF, + 0xFFE37BFF, + 0xFFE077FF, + 0xFFDE72FF, + 0xFFDC6DFF, + 0xFFD968FF, + 0xFFD764FF, + 0xFFD45FFF, + 0xFFD25AFF, + 0xFFD055FF, + 0xF3A61FC0, + 0xED9406FF, + 0xEE970BFF, + 0xF09A11FF, + 0xF19D16FF, + 0xF3A01CFF, + 0x7A5211FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807544FF, + 0xFFE683FF, + 0xFFE47EFF, + 0xFFE279FF, + 0xFFDF75FF, + 0xFFDD70FF, + 0xFFDB6BFF, + 0xFFD867FF, + 0xFFD662FF, + 0xFFD45DFF, + 0xFFD158FF, + 0xFFCF54FF, + 0xF3A61FC0, + 0xED9407FF, + 0xEF970CFF, + 0xF09A11FF, + 0xF29D17FF, + 0xF3A01CFF, + 0x7A5211FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807443FF, + 0xFFE681FF, + 0xFFE37CFF, + 0xFFE178FF, + 0xFFDE73FF, + 0xFFDC6EFF, + 0xFFDA69FF, + 0xFFD765FF, + 0xFFD560FF, + 0xFFD35BFF, + 0xFFD056FF, + 0xFFCE52FF, + 0xF3A61DC0, + 0xED9507FF, + 0xEF980DFF, + 0xF09A12FF, + 0xF29D17FF, + 0xF3A01DFF, + 0x7B5211FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807442FF, + 0xFFE57FFF, + 0xFFE27BFF, + 0xFFE076FF, + 0xFFDE71FF, + 0xFFDB6CFF, + 0xFFD968FF, + 0xFFD663FF, + 0xFFD45EFF, + 0xFFD259FF, + 0xFFCF55FF, + 0xFFCD50FF, + 0xF3A61DC0, + 0xED9508FF, + 0xEF980DFF, + 0xF09B12FF, + 0xF29E18FF, + 0xF3A11DFF, + 0x7B5212FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807341FF, + 0xFFE47EFF, + 0xFFE179FF, + 0xFFDF74FF, + 0xFFDD6FFF, + 0xFFDA6BFF, + 0xFFD866FF, + 0xFFD661FF, + 0xFFD35CFF, + 0xFFD158FF, + 0xFFCE53FF, + 0xFFCC4EFF, + 0xF3A51CC0, + 0xEE9508FF, + 0xEF980EFF, + 0xF19B13FF, + 0xF29E18FF, + 0xF3A11EFF, + 0x7B5212FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807340FF, + 0xFFE37CFF, + 0xFFE177FF, + 0xFFDE72FF, + 0xFFDC6EFF, + 0xFFD969FF, + 0xFFD764FF, + 0xFFD55FFF, + 0xFFD25BFF, + 0xFFD056FF, + 0xFFCE51FF, + 0xFFCB4CFF, + 0xF3A51CC0, + 0xEE9609FF, + 0xEF980EFF, + 0xF19B14FF, + 0xF29E19FF, + 0xF4A11EFF, + 0x7B5212FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x807240FF, + 0xFFE27AFF, + 0xFFE075FF, + 0xFFDD70FF, + 0xFFDB6CFF, + 0xFFD867FF, + 0xFFD662FF, + 0xFFD45DFF, + 0xFFD159FF, + 0xFFCF54FF, + 0xFFCD4FFF, + 0xFFCA4AFF, + 0xF3A51BC0, + 0xEE9609FF, + 0xEF990FFF, + 0xF19C14FF, + 0xF29F1AFF, + 0xF4A21FFF, + 0x7B5312FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80723FFF, + 0xFFE178FF, + 0xFFDF73FF, + 0xFFDC6FFF, + 0xFFDA6AFF, + 0xFFD865FF, + 0xFFD560FF, + 0xFFD35CFF, + 0xFFD057FF, + 0xFFCE52FF, + 0xFFCC4DFF, + 0xFFC949FF, + 0xF3A51BC0, + 0xEE960AFF, + 0xF0990FFF, + 0xF19C15FF, + 0xF29F1AFF, + 0xF4A220FF, + 0x7B5313FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80723EFF, + 0xFFE076FF, + 0xFFDE72FF, + 0xFFDB6DFF, + 0xFFD968FF, + 0xFFD763FF, + 0xFFD45FFF, + 0xFFD25AFF, + 0xFFD055FF, + 0xFFCD50FF, + 0xFFCB4CFF, + 0xFFC847FF, + 0xF3A319C0, + 0xEE960BFF, + 0xF09910FF, + 0xF19C15FF, + 0xF39F1BFF, + 0xF4A220FF, + 0x7B5313FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80713DFF, + 0xFFDF75FF, + 0xFFDD70FF, + 0xFFDB6BFF, + 0xFFD866FF, + 0xFFD662FF, + 0xFFD35DFF, + 0xFFD158FF, + 0xFFCF53FF, + 0xFFCC4FFF, + 0xFFCA4AFF, + 0xFFC845FF, + 0xF3A319C0, + 0xEE970BFF, + 0xF09A11FF, + 0xF19D16FF, + 0xF3A01BFF, + 0xF4A321FF, + 0x7B5313FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80713CFF, + 0xFFDE73FF, + 0xFFDC6EFF, + 0xFFDA69FF, + 0xFFD764FF, + 0xFFD560FF, + 0xFFD25BFF, + 0xFFD056FF, + 0xFFCE51FF, + 0xFFCB4DFF, + 0xFFC948FF, + 0xFFC743FF, + 0xF3A318C0, + 0xEF970CFF, + 0xF09A11FF, + 0xF19D16FF, + 0xF3A01CFF, + 0xF4A321FF, + 0x7B5314FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x80703BFF, + 0xFFDD71FF, + 0xFFDB6CFF, + 0xFFD967FF, + 0xFFD663FF, + 0xFFD45EFF, + 0xFFD259FF, + 0xFFCF54FF, + 0xFFCD50FF, + 0xFFCA4BFF, + 0xFFC846FF, + 0xFFC641FF, + 0xF3A319C0, + 0xEF970CFF, + 0xF09A12FF, + 0xF29D17FF, + 0xF3A01CFF, + 0xF5A322FF, + 0x7B5314FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x4E4423FF, + 0xE8C965FF, + 0xFFDA6AFF, + 0xFFD866FF, + 0xFFD561FF, + 0xFFD35CFF, + 0xFFD157FF, + 0xFFCE53FF, + 0xFFCC4EFF, + 0xFFCA49FF, + 0xFFC744FF, + 0xFFC540FF, + 0xF3A319C0, + 0xEF980DFF, + 0xF09B12FF, + 0xF29E18FF, + 0xF3A11DFF, + 0xF5A322FF, + 0x7B5314FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000B3, + 0x000000FD, + 0x060503FF, + 0x554823FF, + 0xC8A94EFF, + 0xFFD55FFF, + 0xFFD25AFF, + 0xFFD056FF, + 0xFFCD51FF, + 0xFFCB4CFF, + 0xFFC947FF, + 0xFFC643FF, + 0xFFC43EFF, + 0xEA9E17C7, + 0xEF980DFF, + 0xF09B13FF, + 0xF29E18FF, + 0xF3A11EFF, + 0xDE9520FF, + 0x362509FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000023, + 0x0000008D, + 0x000000F9, + 0x000000FF, + 0x3C3216FF, + 0xAA8B3BFF, + 0xFBCC53FF, + 0xFFCC4FFF, + 0xFFCA4AFF, + 0xFFC845FF, + 0xFFC541FF, + 0xFFC33CFF, + 0xB77B13FF, + 0xEF980EFF, + 0xF19B13FF, + 0xF29E19FF, + 0xB77916FF, + 0x191104FF, + 0x000000F6, + 0x00000066, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000028, + 0x000000D2, + 0x010100FF, + 0x3E3114FF, + 0x1E1709FF, + 0x000000FF, + 0x211B0BFF, + 0x886D29FF, + 0xEEBC43FF, + 0xFFC744FF, + 0xFFC43FFF, + 0xFFC23AFF, + 0xCF8812FF, + 0xEF990FFF, + 0xF09B14FF, + 0x81550DFF, + 0x030200FF, + 0x000000E0, + 0x0000002B, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000060, + 0x000000F4, + 0x151209FF, + 0xB2984AFF, + 0xF5CB5DFF, + 0xF0C153FF, + 0xA37E33FF, + 0x382A10FF, + 0x000000FF, + 0x0D0A04FF, + 0x664F1AFF, + 0xD7A533FF, + 0xFFC138FF, + 0xB77B12FF, + 0xDB8C0EFF, + 0x432B06FF, + 0x000000FF, + 0x040200FF, + 0x000000FF, + 0x000000DA, + 0x0000007B, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x35301BFF, + 0xE4D170FF, + 0xFADF73FF, + 0xF8D76AFF, + 0xF6CF61FF, + 0xF4C758FF, + 0xF2BF4FFF, + 0xC09238FF, + 0x563F16FF, + 0x060401FF, + 0x020200FF, + 0x503C11FF, + 0x7E560EFF, + 0x170E02FF, + 0x090500FF, + 0x8C4B00FF, + 0xD57300FF, + 0x8D4C00FF, + 0x271602FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x806D35FF, + 0xD9B757FF, + 0xF1D369CC, + 0xFBE176F6, + 0xF9DA6EFF, + 0xF7D265FF, + 0xF5CB5CFF, + 0xF3C353FF, + 0xF1BB4AFF, + 0xD9A33BFF, + 0x7E5B1EFF, + 0x181105FF, + 0x000000FF, + 0x241705FF, + 0xBD7210FF, + 0xE3830BFF, + 0xE17B02FF, + 0xB46D0EFF, + 0x785115FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x806D34FF, + 0xFFD662FF, + 0xFFD45EFF, + 0xFFD159EB, + 0xFED560C0, + 0xFBDC6DE7, + 0xF8D669FF, + 0xF6CE60FF, + 0xF4C657FF, + 0xF2BE4EFF, + 0xF0B645FF, + 0xE7A93AFF, + 0x9C6E22FF, + 0xE09728FF, + 0xE89721FF, + 0xE68F18FF, + 0xEE9719C0, + 0xF5A526FF, + 0x7C5516FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x806C33FF, + 0xFFD561FF, + 0xFFD35CFF, + 0xFFD157FF, + 0xFFCE52FF, + 0xFFCC4EF9, + 0xFFCD50C6, + 0xFAD563D4, + 0xF7D264FF, + 0xF5CA5BFF, + 0xF3C252FF, + 0xF1BA49FF, + 0xEFB240FF, + 0xEDAA37FF, + 0xEBA22DFB, + 0xF19F1EC2, + 0xF5A322FF, + 0xF6A627FF, + 0x7C5516FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x806C32FF, + 0xFFD45FFF, + 0xFFD25AFF, + 0xFFD055FF, + 0xFFCD51FF, + 0xFFCB4CFF, + 0xFFC947FF, + 0xFFC642FF, + 0xFFC642D2, + 0xFBCD54C6, + 0xF6CD5FFB, + 0xF4C556FF, + 0xF2BD4DFF, + 0xEFB443F4, + 0xF19E1ACB, + 0xF3A01DFF, + 0xF5A322FF, + 0xF6A627FF, + 0x7C5517FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x806B31FF, + 0xFFD35DFF, + 0xFFD158FF, + 0xFFCF53FF, + 0xFFCC4FFF, + 0xFFCA4AFF, + 0xFFC845FF, + 0xFFC541FF, + 0xFFC33CFF, + 0xFFC137FF, + 0xFEBE34E3, + 0xFBC444C4, + 0xF3C34EDC, + 0xF09D15D7, + 0xF29E18FF, + 0xF3A11DFF, + 0xF5A423FF, + 0xF6A728FF, + 0x7C5517FF, + 0x000000FF, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x806B30FF, + 0xFFD35BFF, + 0xFFD056FF, + 0xFFCE52FF, + 0xFFCB4DFF, + 0xFFC948FF, + 0xFFC743FF, + 0xFFC43FFF, + 0xFFC23AFF, + 0xFFC035FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xF4A319C0, + 0xF19B13FF, + 0xF29E18FF, + 0xF4A11EFF, + 0xF5A423FF, + 0xF6A729FF, + 0x7C5517FF, + 0x000000FF, + 0x00000061, + 0x0000003A, + 0x0000003F, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x0000006E, + 0x00000046, + 0x00000017, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x806A2FFF, + 0xFFD259FF, + 0xFFCF55FF, + 0xFFCD50FF, + 0xFFCB4BFF, + 0xFFC846FF, + 0xFFC642FF, + 0xFFC33DFF, + 0xFFC138FF, + 0xFFBF33FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xF4A319C0, + 0xF19B14FF, + 0xF29E19FF, + 0xF4A11EFF, + 0xF5A424FF, + 0xF7A729FF, + 0x7C5518FF, + 0x000000FF, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x0000005D, + 0x0000002E, + 0x00000006, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FF, + 0x806A2EFF, + 0xFFD158FF, + 0xFFCE53FF, + 0xFFCC4EFF, + 0xFFCA49FF, + 0xFFC745FF, + 0xFFC540FF, + 0xFFC33BFF, + 0xFFC036FF, + 0xFFBE32FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xF4A51BC0, + 0xF19C14FF, + 0xF29F1AFF, + 0xF4A21FFF, + 0xF5A524FF, + 0xF7A72AFF, + 0x7C5518FF, + 0x000000FF, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x0000006E, + 0x00000046, + 0x00000017, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000FE, + 0x0D0B05FF, + 0x776128FF, + 0xEEBF4CFF, + 0xFFCB4CFF, + 0xFFC947FF, + 0xFFC643FF, + 0xFFC43EFF, + 0xFFC239FF, + 0xFFBF35FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xF4A51BC0, + 0xF19C15FF, + 0xF29F1AFF, + 0xF4A220FF, + 0xF5A525FF, + 0xDA9425FF, + 0x211706FF, + 0x000000F5, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000045, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A2, + 0x000000FC, + 0x0D0A04FF, + 0x775E23FF, + 0xEEBB41FF, + 0xFFC541FF, + 0xFFC33CFF, + 0xFFC137FF, + 0xFFBE33FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xF4A51BC0, + 0xF19C15FF, + 0xF39F1BFF, + 0xF4A220FF, + 0xD99221FF, + 0x211606FF, + 0x000000F6, + 0x00000091, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x0000005A, + 0x00000003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A2, + 0x000000FC, + 0x0D0A03FF, + 0x775C1DFF, + 0xEEB536FF, + 0xFFC036FF, + 0xFFBD31FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xF4A51CC0, + 0xF19D16FF, + 0xF3A01BFF, + 0xD7901DFF, + 0x211605FF, + 0x000000F6, + 0x00000091, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000069, + 0x0000000C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A2, + 0x000000FC, + 0x0D0A03FF, + 0x775918FF, + 0xEEB02DFF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xFFBD30FF, + 0xE69B1ACC, + 0xF19D16FF, + 0xD68D19FF, + 0x211604FF, + 0x000000F6, + 0x00000091, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000072, + 0x0000001C, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002E, + 0x000000AC, + 0x000000FE, + 0x0D0A02FF, + 0x775816FF, + 0xEEB02DFF, + 0xFFBD30FF, + 0xB97D15FD, + 0xD68B14FF, + 0x201504FF, + 0x000000F5, + 0x0000008F, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x0000002E, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002E, + 0x000000AC, + 0x000000FE, + 0x100C03FF, + 0x805F18FF, + 0xA06E14FF, + 0x1E1403FF, + 0x000000F5, + 0x0000008F, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000045, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002B, + 0x000000A2, + 0x000000FC, + 0x000000FF, + 0x000000F5, + 0x00000091, + 0x00000074, + 0x00000074, + 0x00000066, + 0x00000015, + 0x00000036, + 0x0000006C, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x00000074, + 0x0000005A, + 0x00000003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000002E, + 0x000000AC, + 0x00000064, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000000F, + 0x00000000, + 0x00000000, + 0x00000007, + 0x00000035, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000003E, + 0x0000000B, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0}; diff --git a/widget/milsko/milskosrc/src/lowlevel.c b/widget/milsko/milskosrc/src/lowlevel.c new file mode 100644 index 0000000000..bc9e55b7cd --- /dev/null +++ b/widget/milsko/milskosrc/src/lowlevel.c @@ -0,0 +1,315 @@ +#include + +MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height) = NULL; +void (*MwLLDestroy)(MwLL handle) = NULL; + +void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color) = NULL; +void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color) = NULL; + +void (*MwLLBeginDraw)(MwLL handle) = NULL; +void (*MwLLEndDraw)(MwLL handle) = NULL; + +MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b) = NULL; +void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b) = NULL; +void (*MwLLFreeColor)(MwLLColor color) = NULL; + +void (*MwLLGetXYWH)(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) = NULL; +void (*MwLLSetXY)(MwLL handle, int x, int y) = NULL; +void (*MwLLSetWH)(MwLL handle, int w, int h) = NULL; + +void (*MwLLSetTitle)(MwLL handle, const char* title) = NULL; + +int (*MwLLPending)(MwLL handle) = NULL; +void (*MwLLNextEvent)(MwLL handle) = NULL; + +MwLLPixmap (*MwLLCreatePixmap)(MwLL handle, unsigned char* data, int width, int height) = NULL; +void (*MwLLPixmapUpdate)(MwLLPixmap pixmap) = NULL; +void (*MwLLDestroyPixmap)(MwLLPixmap pixmap) = NULL; +void (*MwLLDrawPixmap)(MwLL handle, MwRect* rect, MwLLPixmap pixmap) = NULL; +void (*MwLLSetIcon)(MwLL handle, MwLLPixmap pixmap) = NULL; + +void (*MwLLForceRender)(MwLL handle) = NULL; + +void (*MwLLSetCursor)(MwLL handle, MwCursor* image, MwCursor* mask) = NULL; +void (*MwLLDetach)(MwLL handle, MwPoint* point) = NULL; +void (*MwLLShow)(MwLL handle, int show) = NULL; + +void (*MwLLSetSizeHints)(MwLL handle, int minx, int miny, int maxx, int maxy) = NULL; +void (*MwLLMakeBorderless)(MwLL handle, int toggle) = NULL; +void (*MwLLMakeToolWindow)(MwLL handle) = NULL; +void (*MwLLMakePopup)(MwLL handle, MwLL parent) = NULL; + +void (*MwLLBeginStateChange)(MwLL handle) = NULL; +void (*MwLLEndStateChange)(MwLL handle) = NULL; + +void (*MwLLFocus)(MwLL handle) = NULL; +void (*MwLLGrabPointer)(MwLL handle, int toggle) = NULL; + +void (*MwLLSetClipboard)(MwLL handle, const char* text, int clipboard_type) = NULL; +void (*MwLLGetClipboard)(MwLL, int clipboard_type) = NULL; + +void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point) = NULL; +void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect) = NULL; + +void (*MwLLSetDarkTheme)(MwLL handle, int toggle) = NULL; + +MwBool (*MwLLDoModern)(MwLL handle) = NULL; + +void (*MwLLRaise)(MwLL handle) = NULL; + +void (*MwLLClip)(MwLL handle, MwRect* rect) = NULL; + +void MwLLCreateCommon(MwLL handle) { + handle->common.handler = malloc(sizeof(*handle->common.handler)); + memset(handle->common.handler, 0, sizeof(*handle->common.handler)); + + handle->common.supports_transparency = 0; +} + +void MwLLDestroyCommon(MwLL handle) { + free(handle->common.handler); +} + +#ifdef USE_DBUS +MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl) { +#ifdef __APPLE__ + tbl->lib = MwDynamicOpen("libdbus-1.dylib"); +#else + tbl->lib = MwDynamicOpen("libdbus-1.so"); +#endif + if(!tbl->lib) { + fprintf(stderr, "[WARNING] dbus library (libdbus-1.so) not found, will not be able to check for any XDG settings.\n"); + return MwFALSE; + } + +#define DBUS_FUNC(x) \ + tbl->x = MwDynamicSymbol(tbl->lib, #x); \ + if(!tbl->x) { \ + fprintf(stderr, "[WARNING] dbus function %s not found, will not be able to check for any XDG settings.\n", #x); \ + dlclose(tbl->lib); \ + return MwFALSE; \ + } + + DBUS_FUNC(dbus_error_init); + DBUS_FUNC(dbus_bus_get); + DBUS_FUNC(dbus_bus_add_match); + DBUS_FUNC(dbus_error_is_set); + DBUS_FUNC(dbus_error_free); + DBUS_FUNC(dbus_message_new_method_call); + DBUS_FUNC(dbus_message_is_signal); + DBUS_FUNC(dbus_message_iter_init_append); + DBUS_FUNC(dbus_message_iter_append_basic); + DBUS_FUNC(dbus_connection_flush); + DBUS_FUNC(dbus_connection_pop_message); + DBUS_FUNC(dbus_connection_read_write); + DBUS_FUNC(dbus_connection_send_with_reply_and_block); + DBUS_FUNC(dbus_message_unref); + DBUS_FUNC(dbus_message_iter_init); + DBUS_FUNC(dbus_message_iter_get_arg_type); + DBUS_FUNC(dbus_message_iter_recurse); + DBUS_FUNC(dbus_message_iter_next); + DBUS_FUNC(dbus_connection_unref); + DBUS_FUNC(dbus_message_iter_get_basic); + + return MwTRUE; +} +#endif + +#ifdef USE_DBUS +MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { + if(!tbl->lib) { + return MwFALSE; + } + + tbl->dbus_error_init(&ctx->dbus_err); + + ctx->dbus_conn = tbl->dbus_bus_get(DBUS_BUS_SESSION, &ctx->dbus_err); + if(tbl->dbus_error_is_set(&ctx->dbus_err)) { + fprintf(stderr, "[WARNING] Could not initialize dbus: Connection error: %s\n", ctx->dbus_err.message); + tbl->dbus_error_free(&ctx->dbus_err); + return MwFALSE; + } + if(!ctx->dbus_conn) { + fprintf(stderr, "[WARNING] Could not initialize dbus: Failed to connect to session bus\n"); + return MwFALSE; + } + return MwTRUE; +}; + +MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out) { + DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; + char arg_type; + if(!ctx->dbus_conn) { + return MwFALSE; + } + + ctx->dbus_msg = tbl->dbus_message_new_method_call( + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + portal, + "Read"); + if(!ctx->dbus_msg) { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Failed to create message\n", namespace, key); + return MwFALSE; + } + + tbl->dbus_message_iter_init_append(ctx->dbus_msg, &dbus_args); + tbl->dbus_message_iter_append_basic(&dbus_args, 's', &namespace); + tbl->dbus_message_iter_append_basic(&dbus_args, 's', &key); + + ctx->dbus_reply = tbl->dbus_connection_send_with_reply_and_block(ctx->dbus_conn, ctx->dbus_msg, 100, &ctx->dbus_err); + + if(tbl->dbus_error_is_set(&ctx->dbus_err)) { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Send error: %s\n", namespace, key, ctx->dbus_err.message); + tbl->dbus_error_free(&ctx->dbus_err); + return MwFALSE; + } + if(!ctx->dbus_reply) { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: No reply received\n", namespace, key); + return MwFALSE; + } + + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &dbus_args)) { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Reply has no arguments\n", namespace, key); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + + if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_args)) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_recurse(&dbus_args, &dbus_variant); + + /* Some portals wrap the value in a second variant */ + arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_variant); + if(arg_type == 'v') { + tbl->dbus_message_iter_recurse(&dbus_variant, &dbus_inner_variant); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_inner_variant)) != 'u') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&dbus_inner_variant, out); + } else if(arg_type == 'u') { + tbl->dbus_message_iter_get_basic(&dbus_variant, out); + } else { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_unref(ctx->dbus_msg); + + return MwTRUE; +} + +MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal) { + char filter_string[2048]; + if(!ctx->dbus_conn) { + return MwFALSE; + } + + MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); + + tbl->dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); + tbl->dbus_connection_flush(ctx->dbus_conn); + + return MwTRUE; +} + +/* Technically this will swallow all other results, so this is not usable multiple times. + TODO: Use a hashmap instead */ +MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener listener) { + DBusMessageIter args, msg_value, msg_value_inner; + const char* msg_namespace; + const char* msg_key; + MwU32 msg_value_content; + char arg_type; + + if(!ctx->dbus_conn) { + return MwFALSE; + } + + tbl->dbus_connection_read_write(ctx->dbus_conn, 0); + tbl->dbus_connection_read_write(ctx->dbus_conn, 0); + ctx->dbus_reply = tbl->dbus_connection_pop_message(ctx->dbus_conn); + + if(tbl->dbus_error_is_set(&ctx->dbus_err)) { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Poll error: %s\n", portal, ctx->dbus_err.message); + tbl->dbus_error_free(&ctx->dbus_err); + return MwFALSE; + } + if(!ctx->dbus_reply) { + return MwFALSE; + } + + /* check if the message is a signal from the correct interface and with the correct name */ + if(tbl->dbus_message_is_signal(ctx->dbus_reply, portal, "SettingChanged")) { + /* read the parameters */ + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &args)) + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged has no arguments\n", portal); + else { + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'namespace', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&args, &msg_namespace); + + tbl->dbus_message_iter_next(&args); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'key', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&args, &msg_key); + + /* Check that key and namespace match */ + if(strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { + /* Assuming the value is a basic type */ + tbl->dbus_message_iter_next(&args); + + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_recurse(&args, &msg_value); + + /* Some portals wrap the value in a second variant */ + arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value); + if(arg_type == 'v') { + tbl->dbus_message_iter_recurse(&msg_value, &msg_value_inner); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value_inner)) != 'u') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&msg_value_inner, &msg_value_content); + } else if(arg_type == 'u') { + tbl->dbus_message_iter_get_basic(&msg_value, &msg_value_content); + } else { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + + listener(handle, msg_value_content); + } + } + } + + /* free the message */ + tbl->dbus_message_unref(ctx->dbus_reply); + return MwTRUE; +} + +void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { + if(!tbl->lib) { + return; + } + if(ctx->dbus_reply) tbl->dbus_message_unref(ctx->dbus_reply); + if(ctx->dbus_conn) tbl->dbus_connection_unref(ctx->dbus_conn); +}; +#endif diff --git a/widget/milsko/milskosrc/src/string.c b/widget/milsko/milskosrc/src/string.c new file mode 100644 index 0000000000..f56b9acb7f --- /dev/null +++ b/widget/milsko/milskosrc/src/string.c @@ -0,0 +1,116 @@ +#include + +char* MwStringDuplicate(const char* str) { + char* r = malloc(strlen(str) + 1); + strcpy(r, str); + + return r; +} + +char* MwStringConcat(const char* str1, const char* str2) { + char* r = malloc(strlen(str1) + strlen(str2) + 1); + strcpy(r, str1); + strcat(r, str2); + + return r; +} + +void MwStringSize(char* out, MwOffset size) { + if(size / 1024 == 0) { + sprintf(out, "%d", (int)size); + } else if(size / 1024 / 1024 == 0) { + sprintf(out, "%.1fK", (double)size / 1024); + } else if(size / 1024 / 1024 / 1024 == 0) { + sprintf(out, "%.1fM", (double)size / 1024 / 1024); + } else { + sprintf(out, "%.1fG", (double)size / 1024 / 1024 / 1024); + } +} + +void MwStringTime(char* out, time_t t) { + struct tm* tm = localtime(&t); + const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if(tm == NULL) { + sprintf(out, "localtime error"); + } else { + sprintf(out, "%s %2d %02d:%02d %d", months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, 1900 + tm->tm_year); + } +} +void MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...) { + va_list va; + va_start(va, fmt); + +#if __STDC_VERSION__ >= 199901L + vsnprintf(out, size, fmt, va); +#else + vsprintf(out, fmt, va); +#endif + + va_end(va); +}; + +MWDECL MwBool MwStringIsKeyUTF8(MwU32 key) { + unsigned char bytes[4]; + int i; + bytes[0] = (key & 0x000000FF); + bytes[1] = (key & 0x0000FF00) >> 8; + bytes[2] = (key & 0x00FF0000) >> 16; + bytes[3] = (key & 0xFF000000) >> 24; + + for(i = 0; i < sizeof(MwU32); i++) { + if(( // ASCII + // use bytes[0] <= 0x7F to allow ASCII control characters + bytes[0] == 0x09 || + bytes[0] == 0x0A || + bytes[0] == 0x0D || + (0x20 <= bytes[0] && bytes[0] <= 0x7E))) { + continue; + } + + if(( // non-overlong 2-byte + (0xC2 <= bytes[0] && bytes[0] <= 0xDF) && + (0x80 <= bytes[1] && bytes[1] <= 0xBF))) { + continue; + } + + if(( // excluding overlongs + bytes[0] == 0xE0 && + (0xA0 <= bytes[1] && bytes[1] <= 0xBF) && + (0x80 <= bytes[2] && bytes[2] <= 0xBF)) || + ( // straight 3-byte + ((0xE1 <= bytes[0] && bytes[0] <= 0xEC) || + bytes[0] == 0xEE || + bytes[0] == 0xEF) && + (0x80 <= bytes[1] && bytes[1] <= 0xBF) && + (0x80 <= bytes[2] && bytes[2] <= 0xBF)) || + ( // excluding surrogates + bytes[0] == 0xED && + (0x80 <= bytes[1] && bytes[1] <= 0x9F) && + (0x80 <= bytes[2] && bytes[2] <= 0xBF))) { + continue; + } + + if(( // planes 1-3 + bytes[0] == 0xF0 && + (0x90 <= bytes[1] && bytes[1] <= 0xBF) && + (0x80 <= bytes[2] && bytes[2] <= 0xBF) && + (0x80 <= bytes[3] && bytes[3] <= 0xBF)) || + ( // planes 4-15 + (0xF1 <= bytes[0] && bytes[0] <= 0xF3) && + (0x80 <= bytes[1] && bytes[1] <= 0xBF) && + (0x80 <= bytes[2] && bytes[2] <= 0xBF) && + (0x80 <= bytes[3] && bytes[3] <= 0xBF)) || + ( // plane 16 + bytes[0] == 0xF4 && + (0x80 <= bytes[1] && bytes[1] <= 0x8F) && + (0x80 <= bytes[2] && bytes[2] <= 0xBF) && + (0x80 <= bytes[3] && bytes[3] <= 0xBF))) { + continue; + } + + return 0; + } + + return 1; +} diff --git a/widget/milsko/milskosrc/src/text/font/boldfont.c b/widget/milsko/milskosrc/src/text/font/boldfont.c new file mode 100644 index 0000000000..c63be2c4e0 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/font/boldfont.c @@ -0,0 +1,264 @@ +#include + +/** + * Copyright notice: + * "Public domain font. Share and enjoy." + */ +MwFont MwBoldFontData[] = { + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0 */ + {0, 12, {0, 0, 12, 12, 30, 30, 63, 63, 30, 30, 12, 12, 0, 0}}, /* 1 */ + {0, 12, {59, 119, 110, 93, 59, 119, 110, 93, 59, 119, 110, 93, 59, 119}}, /* 2 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 3 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 4 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 5 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 6 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 7 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 8 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 9 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 10 */ + {0, 12, {12, 12, 12, 12, 12, 12, 124, 124, 0, 0, 0, 0, 0, 0}}, /* 11 */ + {0, 12, {0, 0, 0, 0, 0, 0, 124, 124, 12, 12, 12, 12, 12, 12}}, /* 12 */ + {0, 12, {0, 0, 0, 0, 0, 0, 15, 15, 12, 12, 12, 12, 12, 12}}, /* 13 */ + {0, 12, {12, 12, 12, 12, 12, 12, 15, 15, 0, 0, 0, 0, 0, 0}}, /* 14 */ + {0, 12, {12, 12, 12, 12, 12, 12, 127, 127, 12, 12, 12, 12, 12, 12}}, /* 15 */ + {0, 12, {127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 16 */ + {0, 12, {0, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 17 */ + {0, 12, {0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0}}, /* 18 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0}}, /* 19 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127}}, /* 20 */ + {0, 12, {12, 12, 12, 12, 12, 12, 15, 15, 12, 12, 12, 12, 12, 12}}, /* 21 */ + {0, 12, {12, 12, 12, 12, 12, 12, 124, 124, 12, 12, 12, 12, 12, 12}}, /* 22 */ + {0, 12, {12, 12, 12, 12, 12, 12, 127, 127, 0, 0, 0, 0, 0, 0}}, /* 23 */ + {0, 12, {0, 0, 0, 0, 0, 0, 127, 127, 12, 12, 12, 12, 12, 12}}, /* 24 */ + {0, 12, {12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}}, /* 25 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 26 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 27 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 28 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 29 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 30 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 31 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 32 */ + {0, 12, {0, 0, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 0, 0}}, /* 33 */ + {0, 12, {63, 27, 27, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 34 */ + {0, 12, {0, 0, 15, 15, 15, 63, 30, 30, 63, 60, 60, 60, 0, 0}}, /* 35 */ + {0, 12, {0, 0, 12, 30, 45, 45, 28, 14, 13, 45, 45, 30, 12, 0}}, /* 36 */ + {0, 12, {0, 0, 27, 55, 54, 28, 4, 8, 14, 27, 59, 54, 0, 0}}, /* 37 */ + {0, 12, {0, 0, 14, 27, 27, 27, 14, 27, 55, 54, 54, 27, 0, 0}}, /* 38 */ + {0, 12, {28, 12, 12, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 39 */ + {0, 12, {0, 3, 6, 12, 12, 24, 24, 24, 24, 24, 12, 12, 6, 3}}, /* 40 */ + {0, 12, {0, 48, 24, 12, 12, 6, 6, 6, 6, 6, 12, 12, 24, 48}}, /* 41 */ + {0, 12, {0, 0, 0, 45, 45, 30, 12, 12, 30, 45, 45, 0, 0, 0}}, /* 42 */ + {0, 12, {0, 0, 0, 0, 12, 12, 12, 63, 12, 12, 12, 0, 0, 0}}, /* 43 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 12, 12, 24}}, /* 44 */ + {0, 12, {0, 0, 0, 0, 0, 0, 63, 63, 0, 0, 0, 0, 0, 0}}, /* 45 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0}}, /* 46 */ + {0, 12, {0, 3, 3, 3, 6, 6, 12, 12, 12, 24, 24, 48, 48, 48}}, /* 47 */ + {0, 12, {0, 0, 30, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 48 */ + {0, 12, {0, 0, 12, 28, 60, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 49 */ + {0, 12, {0, 0, 30, 51, 51, 3, 6, 6, 12, 24, 48, 63, 0, 0}}, /* 50 */ + {0, 12, {0, 0, 30, 51, 51, 3, 14, 3, 3, 51, 51, 30, 0, 0}}, /* 51 */ + {0, 12, {0, 0, 2, 6, 6, 14, 30, 22, 54, 63, 2, 2, 0, 0}}, /* 52 */ + {0, 12, {0, 0, 63, 48, 48, 62, 51, 3, 3, 51, 51, 30, 0, 0}}, /* 53 */ + {0, 12, {0, 0, 14, 27, 51, 48, 62, 51, 51, 51, 51, 30, 0, 0}}, /* 54 */ + {0, 12, {0, 0, 63, 51, 54, 6, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 55 */ + {0, 12, {0, 0, 30, 51, 51, 30, 12, 30, 51, 51, 51, 30, 0, 0}}, /* 56 */ + {0, 12, {0, 0, 30, 51, 51, 51, 51, 31, 3, 51, 54, 28, 0, 0}}, /* 57 */ + {0, 12, {0, 0, 0, 0, 12, 12, 0, 0, 0, 12, 12, 0, 0, 0}}, /* 58 */ + {0, 12, {0, 0, 0, 0, 12, 12, 0, 0, 0, 28, 12, 12, 24, 0}}, /* 59 */ + {0, 12, {0, 0, 0, 3, 6, 12, 24, 48, 24, 12, 6, 3, 0, 0}}, /* 60 */ + {0, 12, {0, 0, 0, 0, 63, 63, 0, 63, 63, 0, 0, 0, 0, 0}}, /* 61 */ + {0, 12, {0, 0, 0, 48, 24, 12, 6, 3, 6, 12, 24, 48, 0, 0}}, /* 62 */ + {0, 12, {0, 0, 30, 51, 51, 6, 12, 12, 12, 0, 12, 12, 0, 0}}, /* 63 */ + {0, 12, {0, 0, 14, 27, 55, 61, 61, 61, 61, 55, 24, 15, 0, 0}}, /* 64 */ + {0, 12, {0, 0, 30, 63, 51, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 65 */ + {0, 12, {0, 0, 62, 51, 51, 50, 62, 51, 51, 51, 51, 62, 0, 0}}, /* 66 */ + {0, 12, {0, 0, 30, 51, 51, 48, 48, 48, 48, 51, 51, 30, 0, 0}}, /* 67 */ + {0, 12, {0, 0, 60, 54, 51, 51, 51, 51, 51, 51, 54, 60, 0, 0}}, /* 68 */ + {0, 12, {0, 0, 63, 48, 48, 48, 62, 48, 48, 48, 48, 63, 0, 0}}, /* 69 */ + {0, 12, {0, 0, 63, 48, 48, 48, 62, 48, 48, 48, 48, 48, 0, 0}}, /* 70 */ + {0, 12, {0, 0, 30, 51, 51, 48, 48, 55, 51, 51, 51, 30, 0, 0}}, /* 71 */ + {0, 12, {0, 0, 51, 51, 51, 51, 63, 51, 51, 51, 51, 51, 0, 0}}, /* 72 */ + {0, 12, {0, 0, 63, 12, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 73 */ + {0, 12, {0, 0, 3, 3, 3, 3, 3, 3, 3, 51, 54, 28, 0, 0}}, /* 74 */ + {0, 12, {0, 0, 51, 54, 60, 56, 56, 60, 60, 54, 51, 51, 0, 0}}, /* 75 */ + {0, 12, {0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 63, 0, 0}}, /* 76 */ + {0, 12, {0, 0, 33, 51, 51, 63, 63, 51, 51, 51, 51, 51, 0, 0}}, /* 77 */ + {0, 12, {0, 0, 51, 51, 59, 59, 59, 55, 55, 55, 51, 51, 0, 0}}, /* 78 */ + {0, 12, {0, 0, 30, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 79 */ + {0, 12, {0, 0, 62, 51, 51, 51, 51, 62, 48, 48, 48, 48, 0, 0}}, /* 80 */ + {0, 12, {0, 0, 30, 51, 51, 51, 51, 51, 59, 55, 51, 30, 3, 1}}, /* 81 */ + {0, 12, {0, 0, 62, 51, 51, 51, 62, 54, 51, 51, 51, 51, 0, 0}}, /* 82 */ + {0, 12, {0, 0, 30, 51, 51, 24, 12, 12, 6, 51, 51, 30, 0, 0}}, /* 83 */ + {0, 12, {0, 0, 63, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 84 */ + {0, 12, {0, 0, 51, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 85 */ + {0, 12, {0, 0, 51, 51, 51, 51, 51, 51, 51, 30, 30, 12, 0, 0}}, /* 86 */ + {0, 12, {0, 0, 51, 51, 51, 51, 51, 63, 63, 63, 63, 18, 0, 0}}, /* 87 */ + {0, 12, {0, 0, 51, 51, 30, 30, 12, 12, 30, 30, 51, 51, 0, 0}}, /* 88 */ + {0, 12, {0, 0, 51, 51, 51, 30, 30, 12, 12, 12, 12, 12, 0, 0}}, /* 89 */ + {0, 12, {0, 0, 63, 3, 6, 6, 12, 12, 24, 24, 48, 63, 0, 0}}, /* 90 */ + {0, 12, {0, 31, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 31}}, /* 91 */ + {0, 12, {0, 48, 48, 48, 24, 24, 12, 12, 12, 6, 6, 3, 3, 3}}, /* 92 */ + {0, 12, {0, 62, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 62}}, /* 93 */ + {0, 12, {12, 30, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 94 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 63}}, /* 95 */ + {0, 12, {14, 12, 12, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 96 */ + {0, 12, {0, 0, 0, 0, 0, 30, 51, 7, 27, 51, 51, 31, 0, 0}}, /* 97 */ + {0, 12, {0, 0, 48, 48, 48, 62, 51, 51, 51, 51, 51, 62, 0, 0}}, /* 98 */ + {0, 12, {0, 0, 0, 0, 0, 30, 51, 48, 48, 48, 51, 30, 0, 0}}, /* 99 */ + {0, 12, {0, 0, 3, 3, 3, 31, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 100 */ + {0, 12, {0, 0, 0, 0, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 101 */ + {0, 12, {0, 0, 6, 15, 12, 12, 63, 12, 12, 12, 12, 12, 0, 0}}, /* 102 */ + {0, 12, {0, 0, 0, 0, 0, 29, 55, 54, 54, 28, 16, 62, 51, 30}}, /* 103 */ + {0, 12, {0, 0, 48, 48, 48, 62, 51, 51, 51, 51, 51, 51, 0, 0}}, /* 104 */ + {0, 12, {0, 0, 12, 12, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 105 */ + {0, 12, {0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 54, 28}}, /* 106 */ + {0, 12, {0, 0, 48, 48, 48, 50, 54, 60, 60, 54, 51, 49, 0, 0}}, /* 107 */ + {0, 12, {0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 108 */ + {0, 12, {0, 0, 0, 0, 0, 54, 63, 63, 63, 63, 63, 63, 0, 0}}, /* 109 */ + {0, 12, {0, 0, 0, 0, 0, 62, 51, 51, 51, 51, 51, 51, 0, 0}}, /* 110 */ + {0, 12, {0, 0, 0, 0, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 111 */ + {0, 12, {0, 0, 0, 0, 0, 62, 51, 51, 51, 51, 51, 62, 48, 48}}, /* 112 */ + {0, 12, {0, 0, 0, 0, 0, 31, 51, 51, 51, 51, 51, 31, 3, 3}}, /* 113 */ + {0, 12, {0, 0, 0, 0, 0, 62, 51, 51, 48, 48, 48, 48, 0, 0}}, /* 114 */ + {0, 12, {0, 0, 0, 0, 0, 30, 51, 24, 12, 6, 51, 30, 0, 0}}, /* 115 */ + {0, 12, {0, 0, 12, 12, 12, 63, 12, 12, 12, 12, 12, 7, 0, 0}}, /* 116 */ + {0, 12, {0, 0, 0, 0, 0, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 117 */ + {0, 12, {0, 0, 0, 0, 0, 51, 51, 51, 30, 30, 12, 12, 0, 0}}, /* 118 */ + {0, 12, {0, 0, 0, 0, 0, 51, 51, 63, 63, 63, 63, 18, 0, 0}}, /* 119 */ + {0, 12, {0, 0, 0, 0, 0, 51, 51, 30, 12, 30, 51, 51, 0, 0}}, /* 120 */ + {0, 12, {0, 0, 0, 0, 0, 51, 51, 27, 27, 14, 14, 6, 54, 28}}, /* 121 */ + {0, 12, {0, 0, 0, 0, 0, 63, 3, 6, 12, 24, 48, 63, 0, 0}}, /* 122 */ + {0, 12, {0, 7, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 7}}, /* 123 */ + {0, 12, {0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}}, /* 124 */ + {0, 12, {0, 56, 12, 12, 12, 12, 12, 6, 12, 12, 12, 12, 12, 56}}, /* 125 */ + {0, 12, {0, 16, 63, 63, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 126 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 127 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 128 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 129 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 130 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 131 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 132 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 133 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 134 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 135 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 136 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 137 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 138 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 139 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 140 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 141 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 142 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 143 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 144 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 145 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 146 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 147 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 148 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 149 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 150 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 151 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 152 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 153 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 154 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 155 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 156 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 157 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 158 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 159 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 160 */ + {0, 12, {0, 0, 12, 12, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 161 */ + {0, 12, {0, 0, 0, 0, 12, 31, 45, 44, 44, 44, 45, 31, 12, 0}}, /* 162 */ + {0, 12, {0, 0, 0, 14, 27, 24, 24, 60, 24, 24, 62, 27, 0, 0}}, /* 163 */ + {0, 12, {0, 0, 0, 0, 51, 30, 26, 22, 30, 51, 0, 0, 0, 0}}, /* 164 */ + {0, 12, {0, 0, 33, 51, 30, 63, 12, 12, 63, 12, 12, 12, 0, 0}}, /* 165 */ + {0, 12, {0, 0, 12, 12, 12, 12, 0, 0, 12, 12, 12, 12, 0, 0}}, /* 166 */ + {0, 12, {0, 30, 51, 24, 12, 30, 51, 30, 12, 6, 51, 30, 0, 0}}, /* 167 */ + {0, 12, {0, 54, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 168 */ + {0, 12, {0, 30, 51, 63, 59, 59, 59, 59, 59, 63, 51, 30, 0, 0}}, /* 169 */ + {0, 12, {0, 14, 27, 15, 27, 27, 15, 0, 31, 0, 0, 0, 0, 0}}, /* 170 */ + {0, 12, {0, 0, 0, 0, 0, 7, 15, 30, 60, 30, 15, 7, 0, 0}}, /* 171 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 126, 126, 6, 6, 6, 0, 0}}, /* 172 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 120, 120, 0, 0, 0, 0, 0}}, /* 173 */ + {0, 12, {0, 30, 51, 63, 59, 59, 63, 59, 59, 59, 51, 30, 0, 0}}, /* 174 */ + {0, 12, {0, 0, 120, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 175 */ + {0, 12, {0, 28, 54, 54, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 176 */ + {0, 12, {0, 0, 0, 0, 0, 0, 12, 12, 63, 12, 12, 63, 0, 0}}, /* 177 */ + {0, 12, {0, 28, 54, 6, 12, 24, 48, 62, 0, 0, 0, 0, 0, 0}}, /* 178 */ + {0, 12, {0, 28, 54, 6, 28, 6, 54, 28, 0, 0, 0, 0, 0, 0}}, /* 179 */ + {0, 12, {0, 6, 12, 24, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 180 */ + {0, 12, {0, 0, 0, 0, 0, 0, 51, 51, 51, 51, 55, 63, 48, 48}}, /* 181 */ + {0, 12, {0, 0, 31, 59, 59, 59, 59, 27, 11, 11, 11, 11, 11, 15}}, /* 182 */ + {0, 12, {0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, 0}}, /* 183 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 24}}, /* 184 */ + {0, 12, {0, 0, 24, 56, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0}}, /* 185 */ + {0, 12, {0, 0, 14, 27, 27, 14, 0, 31, 0, 0, 0, 0, 0, 0}}, /* 186 */ + {0, 12, {0, 0, 0, 0, 0, 56, 28, 14, 7, 14, 28, 56, 0, 0}}, /* 187 */ + {0, 12, {0, 0, 25, 59, 26, 30, 30, 13, 27, 23, 55, 35, 0, 0}}, /* 188 */ + {0, 12, {0, 0, 25, 59, 26, 30, 30, 14, 29, 19, 54, 39, 0, 0}}, /* 189 */ + {0, 12, {0, 0, 49, 27, 58, 30, 60, 15, 27, 55, 39, 3, 0, 0}}, /* 190 */ + {0, 12, {0, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 51, 51, 30}}, /* 191 */ + {0, 12, {28, 14, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 192 */ + {0, 12, {14, 28, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 193 */ + {0, 12, {12, 30, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 194 */ + {0, 12, {10, 20, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 195 */ + {0, 12, {18, 18, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 196 */ + {0, 12, {12, 12, 0, 30, 63, 51, 51, 51, 63, 51, 51, 51, 0, 0}}, /* 197 */ + {0, 12, {0, 0, 63, 108, 108, 108, 110, 124, 108, 108, 108, 111, 0, 0}}, /* 198 */ + {0, 12, {0, 0, 30, 51, 51, 48, 48, 48, 48, 51, 51, 30, 12, 24}}, /* 199 */ + {0, 12, {28, 14, 0, 63, 48, 48, 48, 62, 48, 48, 48, 63, 0, 0}}, /* 200 */ + {0, 12, {14, 28, 0, 63, 48, 48, 48, 62, 48, 48, 48, 63, 0, 0}}, /* 201 */ + {0, 12, {12, 30, 0, 63, 48, 48, 48, 62, 48, 48, 48, 63, 0, 0}}, /* 202 */ + {0, 12, {18, 18, 0, 63, 48, 48, 48, 62, 48, 48, 48, 63, 0, 0}}, /* 203 */ + {0, 12, {28, 14, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 204 */ + {0, 12, {14, 28, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 205 */ + {0, 12, {12, 30, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 206 */ + {0, 12, {18, 18, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0}}, /* 207 */ + {0, 12, {0, 0, 60, 54, 51, 51, 127, 51, 51, 51, 54, 60, 0, 0}}, /* 208 */ + {0, 12, {10, 20, 0, 51, 59, 59, 59, 55, 55, 55, 51, 51, 0, 0}}, /* 209 */ + {0, 12, {28, 14, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 210 */ + {0, 12, {14, 28, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 211 */ + {0, 12, {12, 30, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 212 */ + {0, 12, {10, 20, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 213 */ + {0, 12, {18, 18, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 214 */ + {0, 12, {0, 0, 0, 0, 0, 99, 54, 28, 28, 54, 99, 65, 0, 0}}, /* 215 */ + {0, 12, {1, 1, 30, 55, 55, 55, 55, 59, 59, 59, 59, 30, 32, 32}}, /* 216 */ + {0, 12, {28, 14, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 217 */ + {0, 12, {14, 28, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 218 */ + {0, 12, {12, 30, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 219 */ + {0, 12, {18, 18, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 220 */ + {0, 12, {14, 28, 0, 51, 51, 51, 30, 30, 30, 12, 12, 12, 0, 0}}, /* 221 */ + {0, 12, {0, 0, 48, 48, 62, 51, 51, 51, 51, 62, 48, 48, 0, 0}}, /* 222 */ + {0, 12, {0, 0, 14, 27, 27, 27, 30, 27, 27, 27, 27, 62, 0, 0}}, /* 223 */ + {0, 12, {0, 24, 12, 6, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 224 */ + {0, 12, {0, 6, 12, 24, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 225 */ + {0, 12, {0, 0, 12, 30, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 226 */ + {0, 12, {0, 0, 10, 20, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 227 */ + {0, 12, {0, 0, 18, 18, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 228 */ + {0, 12, {0, 12, 30, 12, 0, 30, 51, 15, 27, 51, 51, 31, 0, 0}}, /* 229 */ + {0, 12, {0, 0, 0, 0, 0, 62, 109, 29, 47, 108, 111, 62, 0, 0}}, /* 230 */ + {0, 12, {0, 0, 0, 0, 0, 30, 51, 48, 48, 48, 51, 30, 12, 24}}, /* 231 */ + {0, 12, {0, 24, 12, 6, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 232 */ + {0, 12, {0, 6, 12, 24, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 233 */ + {0, 12, {0, 0, 12, 30, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 234 */ + {0, 12, {0, 0, 18, 18, 0, 30, 51, 51, 63, 48, 51, 30, 0, 0}}, /* 235 */ + {0, 12, {0, 24, 12, 6, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 236 */ + {0, 12, {0, 6, 12, 24, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 237 */ + {0, 12, {0, 0, 12, 30, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 238 */ + {0, 12, {0, 0, 18, 18, 0, 12, 12, 12, 12, 12, 12, 12, 0, 0}}, /* 239 */ + {0, 12, {0, 20, 8, 22, 6, 30, 54, 54, 54, 54, 54, 28, 0, 0}}, /* 240 */ + {0, 12, {0, 0, 10, 20, 0, 62, 51, 51, 51, 51, 51, 51, 0, 0}}, /* 241 */ + {0, 12, {0, 24, 12, 6, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 242 */ + {0, 12, {0, 6, 12, 24, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 243 */ + {0, 12, {0, 0, 12, 30, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 244 */ + {0, 12, {0, 0, 10, 20, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 245 */ + {0, 12, {0, 0, 18, 18, 0, 30, 51, 51, 51, 51, 51, 30, 0, 0}}, /* 246 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 24, 0, 126, 0, 24, 0, 0}}, /* 247 */ + {0, 12, {0, 0, 0, 1, 2, 30, 55, 55, 59, 59, 51, 30, 32, 32}}, /* 248 */ + {0, 12, {0, 16, 24, 12, 4, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 249 */ + {0, 12, {0, 2, 6, 12, 8, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 250 */ + {0, 12, {0, 0, 12, 30, 0, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 251 */ + {0, 12, {0, 0, 18, 18, 0, 51, 51, 51, 51, 51, 51, 31, 0, 0}}, /* 252 */ + {0, 12, {0, 2, 6, 12, 8, 51, 51, 51, 30, 14, 14, 12, 60, 24}}, /* 253 */ + {0, 12, {0, 0, 48, 48, 48, 62, 51, 51, 51, 51, 51, 62, 48, 48}}, /* 254 */ + {0, 12, {0, 0, 18, 18, 0, 51, 51, 51, 30, 14, 14, 12, 60, 24}} /* 255 */ +}; diff --git a/widget/milsko/milskosrc/src/text/font/boldmonottf.c b/widget/milsko/milskosrc/src/text/font/boldmonottf.c new file mode 100644 index 0000000000..8526c1b053 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/font/boldmonottf.c @@ -0,0 +1,3022 @@ +#include + +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) +unsigned char MwBoldMonospaceTTFData[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x04, 0x00, 0x10, + 0x46, 0x46, 0x54, 0x4d, 0xac, 0x0d, 0xe4, 0x44, 0x00, 0x00, 0x8d, 0x3c, + 0x00, 0x00, 0x00, 0x1c, 0x4f, 0x53, 0x2f, 0x32, 0xa4, 0xe6, 0xab, 0x72, + 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70, + 0x0a, 0x08, 0xe7, 0x8a, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x01, 0x5a, + 0x63, 0x76, 0x74, 0x20, 0x03, 0xff, 0x11, 0xcf, 0x00, 0x00, 0x09, 0x34, + 0x00, 0x00, 0x00, 0x4a, 0x66, 0x65, 0x61, 0x74, 0x40, 0x36, 0x0d, 0x66, + 0x00, 0x00, 0x8a, 0xd8, 0x00, 0x00, 0x00, 0x5c, 0x66, 0x70, 0x67, 0x6d, + 0x06, 0x59, 0x9c, 0x37, 0x00, 0x00, 0x05, 0xbc, 0x00, 0x00, 0x01, 0x73, + 0x67, 0x61, 0x73, 0x70, 0x00, 0x18, 0x00, 0x23, 0x00, 0x00, 0x8a, 0xc8, + 0x00, 0x00, 0x00, 0x10, 0x67, 0x6c, 0x79, 0x66, 0xf8, 0x0d, 0xdb, 0x5e, + 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x6d, 0x38, 0x68, 0x65, 0x61, 0x64, + 0x28, 0x83, 0x41, 0xdc, 0x00, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x00, 0x36, + 0x68, 0x68, 0x65, 0x61, 0x06, 0x5b, 0x03, 0x44, 0x00, 0x00, 0x01, 0x54, + 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 0x0f, 0x76, 0x25, 0x59, + 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x02, 0x66, 0x6c, 0x6f, 0x63, 0x61, + 0xee, 0xf2, 0xd4, 0xb0, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x01, 0x86, + 0x6d, 0x61, 0x78, 0x70, 0x02, 0xd9, 0x01, 0x94, 0x00, 0x00, 0x01, 0x78, + 0x00, 0x00, 0x00, 0x20, 0x6d, 0x6f, 0x72, 0x78, 0x02, 0x7c, 0xa9, 0x72, + 0x00, 0x00, 0x8b, 0x34, 0x00, 0x00, 0x02, 0x08, 0x6e, 0x61, 0x6d, 0x65, + 0xb2, 0x36, 0x4e, 0x6c, 0x00, 0x00, 0x78, 0x40, 0x00, 0x00, 0x10, 0xc7, + 0x70, 0x6f, 0x73, 0x74, 0x26, 0x62, 0xd0, 0xd4, 0x00, 0x00, 0x89, 0x08, + 0x00, 0x00, 0x01, 0xbe, 0x70, 0x72, 0x65, 0x70, 0x48, 0x01, 0x73, 0x29, + 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x02, 0x02, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x06, 0x07, 0xe3, 0xc8, 0x87, 0x5f, 0x0f, 0x3c, 0xf5, + 0x00, 0x1f, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xe1, 0xa9, 0xde, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0xe5, 0x4d, 0x1e, 0x99, 0xff, 0xfc, 0xff, 0x2c, + 0x02, 0x5b, 0x03, 0xed, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, 0xfe, 0xed, + 0x00, 0x00, 0x03, 0xe8, 0xff, 0xfc, 0xff, 0xfd, 0x02, 0x5b, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x71, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x59, + 0x00, 0x06, 0x00, 0x47, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x04, 0x02, 0x58, 0x02, 0xbc, 0x00, 0x05, 0x00, 0x00, 0x02, 0x8a, + 0x02, 0x58, 0x00, 0x00, 0x00, 0x4b, 0x02, 0x8a, 0x02, 0x58, 0x00, 0x00, + 0x01, 0x5e, 0x00, 0x64, 0x01, 0x35, 0x08, 0x09, 0x02, 0x0b, 0x08, 0x09, + 0x05, 0x02, 0x03, 0x00, 0x02, 0x03, 0xa0, 0x00, 0x02, 0x6f, 0x40, 0x00, + 0x38, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x42, + 0x4d, 0x20, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, 0x0c, 0xff, 0x24, + 0x01, 0x2c, 0x04, 0x01, 0x01, 0x13, 0x60, 0x00, 0x01, 0x97, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x04, 0x02, 0xba, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, + 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, + 0x02, 0x58, 0x00, 0x00, 0x02, 0x58, 0x00, 0xca, 0x02, 0x58, 0x00, 0x7a, + 0x02, 0x58, 0x00, 0x09, 0x02, 0x58, 0x00, 0x1e, 0x02, 0x58, 0x00, 0x02, + 0x02, 0x58, 0x00, 0x0e, 0x02, 0x58, 0x00, 0xea, 0x02, 0x58, 0x00, 0xae, + 0x02, 0x58, 0x00, 0x46, 0x02, 0x58, 0x00, 0x1e, 0x02, 0x58, 0x00, 0x3e, + 0x02, 0x58, 0x00, 0xaa, 0x02, 0x58, 0x00, 0x8c, 0x02, 0x58, 0x00, 0xc3, + 0x02, 0x58, 0x00, 0x49, 0x02, 0x58, 0x00, 0x1b, 0x02, 0x58, 0x00, 0x23, + 0x02, 0x58, 0x00, 0x26, 0x02, 0x58, 0x00, 0x18, 0x02, 0x58, 0x00, 0x19, + 0x02, 0x58, 0x00, 0x2a, 0x02, 0x58, 0x00, 0x26, 0x02, 0x58, 0x00, 0x33, + 0x02, 0x58, 0x00, 0x24, 0x02, 0x58, 0x00, 0x1f, 0x02, 0x58, 0x00, 0xc3, + 0x02, 0x58, 0x00, 0xaa, 0x02, 0x58, 0x00, 0x55, 0x02, 0x58, 0x00, 0x3e, + 0x02, 0x58, 0x00, 0x55, 0x02, 0x58, 0x00, 0x3d, 0x02, 0x58, 0x00, 0x26, + 0x02, 0x58, 0x00, 0x05, 0x02, 0x58, 0x00, 0x4d, 0x02, 0x58, 0x00, 0x29, + 0x02, 0x58, 0x00, 0x40, 0x02, 0x58, 0x00, 0x50, 0x02, 0x58, 0x00, 0x50, + 0x02, 0x58, 0x00, 0x23, 0x02, 0x58, 0x00, 0x3d, 0x02, 0x58, 0x00, 0x4b, + 0x02, 0x58, 0x00, 0x26, 0x02, 0x58, 0x00, 0x44, 0x02, 0x58, 0x00, 0x5c, + 0x02, 0x58, 0x00, 0x27, 0x02, 0x58, 0x00, 0x3d, 0x02, 0x58, 0x00, 0x1b, + 0x02, 0x58, 0x00, 0x4c, 0x02, 0x58, 0x00, 0x1b, 0x02, 0x58, 0x00, 0x4c, + 0x02, 0x58, 0x00, 0x1f, 0x02, 0x58, 0x00, 0x18, 0x02, 0x58, 0x00, 0x37, + 0x02, 0x58, 0x00, 0x09, 0x02, 0x58, 0x00, 0x0b, 0x02, 0x58, 0x00, 0x09, + 0x02, 0x58, 0x00, 0x04, 0x02, 0x58, 0x00, 0x30, 0x02, 0x58, 0x00, 0xb7, + 0x02, 0x58, 0x00, 0x49, 0x02, 0x58, 0x00, 0x5d, 0x02, 0x58, 0x00, 0x1b, + 0x02, 0x58, 0x00, 0x3c, 0x02, 0x58, 0x00, 0x96, 0x02, 0x58, 0x00, 0x34, + 0x02, 0x58, 0x00, 0x3b, 0x02, 0x58, 0x00, 0x3c, 0x02, 0x58, 0x00, 0x27, + 0x02, 0x58, 0x00, 0x32, 0x02, 0x58, 0x00, 0x3d, 0x02, 0x58, 0x00, 0x2f, + 0x02, 0x58, 0x00, 0x41, 0x02, 0x58, 0x00, 0x5e, 0x02, 0x58, 0x00, 0x5a, + 0x02, 0x58, 0x00, 0x41, 0x02, 0x58, 0x00, 0x44, 0x02, 0x58, 0x00, 0x1e, + 0x02, 0x58, 0x00, 0x41, 0x02, 0x58, 0x00, 0x29, 0x02, 0x58, 0x00, 0x3b, + 0x02, 0x58, 0x00, 0x27, 0x02, 0x58, 0x00, 0x4a, 0x02, 0x58, 0x00, 0x31, + 0x02, 0x58, 0x00, 0x2a, 0x02, 0x58, 0x00, 0x3d, 0x02, 0x58, 0x00, 0x1b, + 0x02, 0x58, 0x00, 0x07, 0x02, 0x58, 0x00, 0x17, 0x02, 0x58, 0x00, 0x13, + 0x02, 0x58, 0x00, 0x42, 0x02, 0x58, 0x00, 0x5c, 0x02, 0x58, 0x00, 0xed, + 0x02, 0x58, 0x00, 0x5c, 0x02, 0x58, 0x00, 0x24, 0x02, 0x58, 0x00, 0x00, + 0x02, 0x58, 0x00, 0xca, 0x02, 0x58, 0x00, 0x3c, 0x02, 0x58, 0x00, 0x2e, + 0x02, 0x58, 0x00, 0x2e, 0x02, 0x58, 0x00, 0x00, 0x02, 0x58, 0x00, 0xed, + 0x02, 0x58, 0x00, 0x41, 0x02, 0x58, 0x00, 0x6e, 0x02, 0x58, 0x00, 0x00, + 0x02, 0x58, 0x00, 0x7d, 0x02, 0x58, 0x00, 0x3c, 0x02, 0x58, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x75, 0x00, 0x93, 0x00, 0x70, + 0x00, 0x3e, 0x00, 0x96, 0x00, 0x8a, 0x00, 0xe4, 0x00, 0x41, 0x00, 0x14, + 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xa4, 0x00, 0x77, 0x00, 0x32, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x49, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, + 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0xff, 0xfc, 0x00, 0x29, 0x00, 0x50, + 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x4b, + 0x00, 0x4b, 0x00, 0x0a, 0x00, 0x3d, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x1b, + 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x46, 0x00, 0x13, 0x00, 0x37, 0x00, 0x37, + 0x00, 0x37, 0x00, 0x37, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x34, + 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x04, + 0x00, 0x3c, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x5e, + 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x28, 0x00, 0x41, 0x00, 0x29, + 0x00, 0x29, 0x00, 0x29, 0x00, 0x29, 0x00, 0x29, 0x00, 0x3e, 0x00, 0x17, + 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x13, 0x00, 0x3b, + 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, + 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x7e, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x20, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf5, + 0xff, 0xe3, 0xff, 0xc2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, + 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x00, 0x86, 0x87, 0x89, 0x8b, 0x93, 0x98, + 0x9e, 0xa3, 0xa2, 0xa4, 0xa6, 0xa5, 0xa7, 0xa9, 0xab, 0xaa, 0xac, 0xad, + 0xaf, 0xae, 0xb0, 0xb1, 0xb3, 0xb5, 0xb4, 0xb6, 0xb8, 0xb7, 0xbc, 0xbb, + 0xbd, 0xbe, 0x00, 0x72, 0x64, 0x65, 0x69, 0x00, 0x78, 0xa1, 0x70, 0x6b, + 0x00, 0x76, 0x6a, 0x00, 0x88, 0x9a, 0x00, 0x73, 0x00, 0x00, 0x67, 0x77, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x00, 0xa8, 0xba, 0x81, 0x63, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x7d, 0x00, 0x62, 0x82, 0x85, 0x97, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, 0xc1, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x84, + 0x8c, 0x83, 0x8d, 0x8a, 0x8f, 0x90, 0x91, 0x8e, 0x95, 0x96, 0x00, 0x94, + 0x9c, 0x9d, 0x9b, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x2c, 0x4b, 0xb8, 0x00, 0x09, + 0x50, 0x58, 0xb1, 0x01, 0x01, 0x8e, 0x59, 0xb8, 0x01, 0xff, 0x85, 0xb8, + 0x00, 0x44, 0x1d, 0xb9, 0x00, 0x09, 0x00, 0x03, 0x5f, 0x5e, 0x2d, 0xb8, + 0x00, 0x01, 0x2c, 0x20, 0x20, 0x45, 0x69, 0x44, 0xb0, 0x01, 0x60, 0x2d, + 0xb8, 0x00, 0x02, 0x2c, 0xb8, 0x00, 0x01, 0x2a, 0x21, 0x2d, 0xb8, 0x00, + 0x03, 0x2c, 0x20, 0x46, 0xb0, 0x03, 0x25, 0x46, 0x52, 0x58, 0x23, 0x59, + 0x20, 0x8a, 0x20, 0x8a, 0x49, 0x64, 0x8a, 0x20, 0x46, 0x20, 0x68, 0x61, + 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, 0x68, 0x61, 0x64, 0x52, 0x58, 0x23, + 0x65, 0x8a, 0x59, 0x2f, 0x20, 0xb0, 0x00, 0x53, 0x58, 0x69, 0x20, 0xb0, + 0x00, 0x54, 0x58, 0x21, 0xb0, 0x40, 0x59, 0x1b, 0x69, 0x20, 0xb0, 0x00, + 0x54, 0x58, 0x21, 0xb0, 0x40, 0x65, 0x59, 0x59, 0x3a, 0x2d, 0xb8, 0x00, + 0x04, 0x2c, 0x20, 0x46, 0xb0, 0x04, 0x25, 0x46, 0x52, 0x58, 0x23, 0x8a, + 0x59, 0x20, 0x46, 0x20, 0x6a, 0x61, 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, + 0x6a, 0x61, 0x64, 0x52, 0x58, 0x23, 0x8a, 0x59, 0x2f, 0xfd, 0x2d, 0xb8, + 0x00, 0x05, 0x2c, 0x4b, 0x20, 0xb0, 0x03, 0x26, 0x50, 0x58, 0x51, 0x58, + 0xb0, 0x80, 0x44, 0x1b, 0xb0, 0x40, 0x44, 0x59, 0x1b, 0x21, 0x21, 0x20, + 0x45, 0xb0, 0xc0, 0x50, 0x58, 0xb0, 0xc0, 0x44, 0x1b, 0x21, 0x59, 0x59, + 0x2d, 0xb8, 0x00, 0x06, 0x2c, 0x20, 0x20, 0x45, 0x69, 0x44, 0xb0, 0x01, + 0x60, 0x20, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0xb0, 0x01, 0x60, 0x2d, + 0xb8, 0x00, 0x07, 0x2c, 0xb8, 0x00, 0x06, 0x2a, 0x2d, 0xb8, 0x00, 0x08, + 0x2c, 0x4b, 0x20, 0xb0, 0x03, 0x26, 0x53, 0x58, 0xb0, 0x40, 0x1b, 0xb0, + 0x00, 0x59, 0x8a, 0x8a, 0x20, 0xb0, 0x03, 0x26, 0x53, 0x58, 0x23, 0x21, + 0xb0, 0x80, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03, 0x26, + 0x53, 0x58, 0x23, 0x21, 0xb8, 0x00, 0xc0, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, + 0x59, 0x20, 0xb0, 0x03, 0x26, 0x53, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x00, + 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03, 0x26, 0x53, 0x58, + 0x23, 0x21, 0xb8, 0x01, 0x40, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, + 0xb8, 0x00, 0x03, 0x26, 0x53, 0x58, 0xb0, 0x03, 0x25, 0x45, 0xb8, 0x01, + 0x80, 0x50, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x80, 0x23, 0x21, 0x1b, 0xb0, + 0x03, 0x25, 0x45, 0x23, 0x21, 0x23, 0x21, 0x59, 0x1b, 0x21, 0x59, 0x44, + 0x2d, 0xb8, 0x00, 0x09, 0x2c, 0x4b, 0x53, 0x58, 0x45, 0x44, 0x1b, 0x21, + 0x21, 0x59, 0x2d, 0x00, 0xb8, 0x00, 0x00, 0x2b, 0x00, 0xba, 0x00, 0x01, + 0x00, 0x0e, 0x00, 0x02, 0x2b, 0x01, 0xba, 0x00, 0x0f, 0x00, 0x02, 0x00, + 0x02, 0x2b, 0x01, 0xbf, 0x00, 0x0f, 0x00, 0x25, 0x00, 0x1e, 0x00, 0x18, + 0x00, 0x11, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x10, + 0x00, 0x25, 0x00, 0x1e, 0x00, 0x18, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x08, 0x2b, 0x00, 0xbf, 0x00, 0x01, 0x00, 0x45, 0x00, 0x39, 0x00, + 0x29, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x02, 0x00, 0x39, 0x00, 0x30, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x03, 0x00, 0x2f, 0x00, 0x27, 0x00, + 0x1f, 0x00, 0x17, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x04, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x26, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x05, 0x00, 0x54, 0x00, 0x51, 0x00, + 0x36, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x06, 0x00, 0x34, 0x00, 0x2b, 0x00, 0x21, 0x00, 0x16, 0x00, 0x0e, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x07, 0x00, 0x21, 0x00, 0x1b, 0x00, + 0x17, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x08, 0x00, 0x54, 0x00, 0x3c, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x13, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x09, 0x00, 0x30, 0x00, 0x27, 0x00, + 0x1e, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x0a, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x0b, 0x00, 0x83, 0x00, 0x6c, 0x00, + 0x54, 0x00, 0x3c, 0x00, 0x24, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x0c, 0x00, 0x4b, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x21, 0x00, 0x12, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x0d, 0x00, 0x2b, 0x00, 0x27, 0x00, + 0x1e, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x0e, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0x00, 0xba, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x07, + 0x2b, 0xb8, 0x00, 0x00, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0xba, 0x00, + 0x40, 0x00, 0x15, 0x00, 0x01, 0x74, 0xba, 0x00, 0x10, 0x00, 0x15, 0x00, + 0x01, 0x74, 0xba, 0x00, 0x3f, 0x00, 0x15, 0x00, 0x01, 0x74, 0xba, 0x00, + 0x70, 0x00, 0x15, 0x00, 0x01, 0x74, 0xba, 0x00, 0xa0, 0x00, 0x15, 0x00, + 0x01, 0x74, 0xba, 0x00, 0x10, 0x00, 0x15, 0x00, 0x01, 0x75, 0xba, 0x00, + 0x3f, 0x00, 0x15, 0x00, 0x01, 0x75, 0xba, 0x00, 0x40, 0x00, 0x15, 0x00, + 0x01, 0x75, 0xba, 0x00, 0x3f, 0x00, 0x17, 0x00, 0x01, 0x74, 0xba, 0x00, + 0x40, 0x00, 0x17, 0x00, 0x01, 0x74, 0xba, 0x00, 0x70, 0x00, 0x17, 0x00, + 0x01, 0x74, 0xba, 0x00, 0x9f, 0x00, 0x17, 0x00, 0x01, 0x74, 0xba, 0x00, + 0xa0, 0x00, 0x17, 0x00, 0x01, 0x74, 0xba, 0x00, 0xcf, 0x00, 0x17, 0x00, + 0x01, 0x74, 0xba, 0x00, 0x6f, 0x00, 0x19, 0x00, 0x01, 0x74, 0xba, 0x00, + 0x60, 0x00, 0x1b, 0x00, 0x01, 0x73, 0xba, 0x00, 0x6f, 0x00, 0x1b, 0x00, + 0x01, 0x75, 0xba, 0x00, 0x0f, 0x00, 0x1b, 0x00, 0x01, 0x75, 0xba, 0x00, + 0x9f, 0x00, 0x1b, 0x00, 0x01, 0x75, 0xba, 0x00, 0x6f, 0x00, 0x1b, 0x00, + 0x01, 0x74, 0xba, 0x00, 0x70, 0x00, 0x23, 0x00, 0x01, 0x73, 0xba, 0x00, + 0x3f, 0x00, 0x23, 0x00, 0x01, 0x74, 0xba, 0x00, 0x40, 0x00, 0x23, 0x00, + 0x01, 0x74, 0x00, 0x00, 0x00, 0x17, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x7b, + 0x00, 0x35, 0x00, 0x48, 0x00, 0x6b, 0x00, 0xa9, 0x00, 0x42, 0x00, 0x74, + 0x00, 0xc9, 0x00, 0x2a, 0x00, 0x4a, 0x00, 0x79, 0x00, 0x9e, 0x00, 0x96, + 0x00, 0x98, 0x00, 0x00, 0x00, 0x0c, 0xff, 0x38, 0x00, 0x0c, 0x01, 0x49, + 0x00, 0x06, 0x01, 0x6b, 0x00, 0x06, 0x01, 0x4f, 0x00, 0x06, 0x01, 0x71, + 0x00, 0x06, 0x02, 0x04, 0x00, 0x0c, 0x02, 0xba, 0x00, 0x0c, 0x02, 0xe4, + 0x00, 0x0c, 0x02, 0x18, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x4e, 0x00, 0xc2, + 0x01, 0x64, 0x02, 0x1e, 0x02, 0xd6, 0x02, 0xf2, 0x03, 0x22, 0x03, 0x52, + 0x03, 0x78, 0x03, 0xa0, 0x03, 0xb8, 0x03, 0xd0, 0x03, 0xf4, 0x04, 0x0e, + 0x04, 0x96, 0x04, 0xda, 0x05, 0x34, 0x05, 0xc0, 0x06, 0x0c, 0x06, 0x82, + 0x06, 0xf6, 0x07, 0x2c, 0x07, 0xee, 0x08, 0x62, 0x08, 0x6e, 0x08, 0x7a, + 0x08, 0x98, 0x08, 0xc4, 0x08, 0xe2, 0x09, 0x48, 0x09, 0xe0, 0x0a, 0x2c, + 0x0a, 0x98, 0x0a, 0xea, 0x0b, 0x30, 0x0b, 0x72, 0x0b, 0xae, 0x0c, 0x22, + 0x0c, 0x86, 0x0c, 0xc0, 0x0d, 0x02, 0x0d, 0x50, 0x0d, 0x7a, 0x0d, 0xd2, + 0x0e, 0x1a, 0x0e, 0x64, 0x0e, 0xb4, 0x0f, 0x16, 0x0f, 0x78, 0x0f, 0xe8, + 0x10, 0x1a, 0x10, 0x66, 0x10, 0x9e, 0x10, 0xfc, 0x11, 0x58, 0x11, 0x9c, + 0x11, 0xdc, 0x12, 0x02, 0x12, 0x1c, 0x12, 0x42, 0x12, 0x66, 0x12, 0x7e, + 0x12, 0xa2, 0x13, 0x22, 0x13, 0x98, 0x13, 0xea, 0x14, 0x64, 0x14, 0xd2, + 0x15, 0x2a, 0x16, 0x06, 0x16, 0x64, 0x16, 0xbc, 0x17, 0x10, 0x17, 0x5c, + 0x17, 0x94, 0x18, 0x1c, 0x18, 0x78, 0x18, 0xcc, 0x19, 0x42, 0x19, 0xbc, + 0x1a, 0x18, 0x1a, 0x8e, 0x1a, 0xde, 0x1b, 0x38, 0x1b, 0x70, 0x1b, 0xcc, + 0x1c, 0x28, 0x1c, 0x72, 0x1c, 0xb2, 0x1d, 0x26, 0x1d, 0x3e, 0x1d, 0xb4, + 0x1e, 0x04, 0x1e, 0x04, 0x1e, 0x3e, 0x1e, 0xb2, 0x1f, 0x20, 0x1f, 0xb0, + 0x20, 0x0c, 0x20, 0x34, 0x20, 0xe6, 0x21, 0x46, 0x21, 0xe4, 0x22, 0x66, + 0x22, 0x84, 0x22, 0xa0, 0x22, 0xa0, 0x23, 0x70, 0x23, 0x8a, 0x23, 0xd8, + 0x24, 0x14, 0x24, 0x6e, 0x24, 0xfc, 0x25, 0x20, 0x25, 0x8a, 0x25, 0xc2, + 0x25, 0xe6, 0x26, 0x30, 0x26, 0x74, 0x26, 0xc8, 0x26, 0xe6, 0x27, 0x1e, + 0x27, 0x68, 0x27, 0xc4, 0x28, 0x20, 0x28, 0x42, 0x28, 0x66, 0x28, 0x8e, + 0x28, 0xce, 0x29, 0x0c, 0x29, 0x54, 0x29, 0xbc, 0x2a, 0x4c, 0x2a, 0x6c, + 0x2a, 0x8c, 0x2a, 0xb0, 0x2a, 0xec, 0x2b, 0x0a, 0x2b, 0x28, 0x2b, 0x4a, + 0x2b, 0x84, 0x2b, 0xac, 0x2b, 0xea, 0x2c, 0x1a, 0x2c, 0x4a, 0x2c, 0x7e, + 0x2c, 0xcc, 0x2d, 0x18, 0x2d, 0x4a, 0x2d, 0xda, 0x2e, 0x0a, 0x2e, 0x3a, + 0x2e, 0x70, 0x2e, 0xbc, 0x2e, 0xdc, 0x2f, 0x34, 0x2f, 0xa8, 0x2f, 0xb4, + 0x2f, 0xc0, 0x30, 0x0a, 0x30, 0x6c, 0x30, 0x78, 0x30, 0xe2, 0x31, 0xac, + 0x32, 0x3a, 0x32, 0x46, 0x32, 0x52, 0x32, 0x94, 0x32, 0xa0, 0x32, 0xbc, + 0x32, 0xd8, 0x32, 0xfa, 0x33, 0x32, 0x33, 0xc6, 0x34, 0x14, 0x34, 0x20, + 0x34, 0x2c, 0x34, 0x6a, 0x34, 0xc2, 0x34, 0xce, 0x35, 0x20, 0x35, 0xb6, + 0x35, 0xc2, 0x35, 0xce, 0x36, 0x00, 0x36, 0x0c, 0x36, 0x18, 0x36, 0x90, + 0x36, 0x9c, 0x00, 0x00, 0x00, 0x02, 0x00, 0xca, 0xff, 0xf4, 0x01, 0x8e, + 0x02, 0xba, 0x00, 0x05, 0x00, 0x13, 0x00, 0x43, 0xba, 0x00, 0x06, 0x00, + 0x14, 0x00, 0x15, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x06, 0x10, 0xb8, 0x00, + 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x02, 0x2f, + 0x1b, 0xb9, 0x00, 0x02, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x11, 0x3e, + 0x59, 0xb9, 0x00, 0x0d, 0x00, 0x0a, 0xf4, 0xb9, 0x00, 0x05, 0x00, 0x08, + 0xf4, 0x30, 0x31, 0x25, 0x27, 0x35, 0x33, 0x15, 0x0f, 0x01, 0x22, 0x26, + 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x01, + 0x14, 0x39, 0xa2, 0x39, 0x18, 0x36, 0x2c, 0x2d, 0x35, 0x35, 0x2d, 0x2c, + 0xf3, 0xfc, 0xcb, 0xcb, 0xfc, 0xff, 0x2e, 0x20, 0x20, 0x1f, 0x2e, 0x2e, + 0x1f, 0x20, 0x20, 0x2e, 0xff, 0xff, 0x00, 0x7a, 0x01, 0x9e, 0x01, 0xdf, + 0x02, 0xe4, 0x12, 0x26, 0x00, 0x0a, 0x90, 0x00, 0x10, 0x06, 0x00, 0x0a, + 0x71, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x02, 0x4f, + 0x02, 0xba, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x9d, 0xba, 0x00, 0x17, 0x00, + 0x18, 0x00, 0x19, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x17, 0x10, 0xb8, 0x00, + 0x09, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, + 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0c, 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, 0x1f, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, + 0x00, 0x0b, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x17, 0x2f, 0x1b, 0xb9, 0x00, 0x17, 0x00, 0x11, 0x3e, 0x59, 0xba, + 0x00, 0x03, 0x00, 0x08, 0x00, 0x0b, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x03, + 0x2f, 0xb9, 0x00, 0x00, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x0b, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x04, 0x2f, 0xb9, 0x00, 0x07, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x0e, 0xd0, 0xb8, 0x00, 0x04, 0x10, 0xb8, + 0x00, 0x11, 0xd0, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x12, 0xd0, 0xb8, + 0x00, 0x00, 0x10, 0xb8, 0x00, 0x15, 0xd0, 0x30, 0x31, 0x37, 0x23, 0x35, + 0x33, 0x37, 0x23, 0x35, 0x33, 0x37, 0x33, 0x03, 0x23, 0x01, 0x33, 0x07, + 0x33, 0x15, 0x23, 0x07, 0x33, 0x15, 0x23, 0x07, 0x23, 0x75, 0x6c, 0x80, + 0x0f, 0x69, 0x7d, 0x22, 0x75, 0x7b, 0x75, 0x01, 0x3d, 0x75, 0x22, 0x6c, + 0x80, 0x0f, 0x69, 0x7d, 0x22, 0x75, 0xc2, 0x6e, 0x5a, 0x6e, 0xc2, 0xfd, + 0x46, 0x02, 0xba, 0xc2, 0x6e, 0x5a, 0x6e, 0xc2, 0x00, 0x03, 0x00, 0x1e, + 0xff, 0x8f, 0x02, 0x38, 0x03, 0x2b, 0x00, 0x24, 0x00, 0x2b, 0x00, 0x32, + 0x00, 0xa7, 0xba, 0x00, 0x07, 0x00, 0x33, 0x00, 0x34, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, 0x28, 0xd0, 0xb8, 0x00, 0x07, 0x10, + 0xb8, 0x00, 0x30, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0f, 0x2f, 0x1b, 0xb9, 0x00, 0x0f, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x07, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x0f, + 0x10, 0xb9, 0x00, 0x29, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x08, 0x00, 0x29, + 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0f, 0x10, 0xb8, 0x00, 0x11, + 0xdc, 0xb8, 0x00, 0x0f, 0x10, 0xb8, 0x00, 0x12, 0xd0, 0xb8, 0x00, 0x29, + 0x10, 0xb8, 0x00, 0x18, 0xd0, 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, 0x30, + 0xd0, 0xba, 0x00, 0x19, 0x00, 0x12, 0x00, 0x30, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x00, 0x10, 0xb8, 0x00, 0x22, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, + 0x00, 0x23, 0xdc, 0xba, 0x00, 0x28, 0x00, 0x0f, 0x00, 0x07, 0x11, 0x12, + 0x39, 0xba, 0x00, 0x2f, 0x00, 0x18, 0x00, 0x22, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x17, 0x2e, 0x01, 0x27, 0x37, 0x1e, 0x01, 0x17, 0x35, 0x27, 0x2e, + 0x01, 0x35, 0x34, 0x36, 0x37, 0x35, 0x33, 0x15, 0x1e, 0x01, 0x17, 0x07, + 0x26, 0x27, 0x15, 0x17, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x02, 0x07, 0x15, + 0x23, 0x03, 0x14, 0x16, 0x17, 0x35, 0x0e, 0x01, 0x13, 0x34, 0x26, 0x27, + 0x15, 0x3e, 0x01, 0xfd, 0x4b, 0x71, 0x23, 0x57, 0x20, 0x49, 0x29, 0x17, + 0x60, 0x5c, 0x68, 0x61, 0x72, 0x3f, 0x59, 0x1e, 0x56, 0x2a, 0x40, 0x17, + 0x60, 0x5c, 0x1b, 0x33, 0x4b, 0x30, 0x72, 0x3c, 0x21, 0x25, 0x25, 0x21, + 0xeb, 0x22, 0x25, 0x24, 0x23, 0x0a, 0x06, 0x37, 0x2d, 0x5f, 0x22, 0x26, + 0x06, 0xb8, 0x04, 0x11, 0x6b, 0x4d, 0x55, 0x6a, 0x0d, 0x69, 0x68, 0x08, + 0x30, 0x23, 0x60, 0x2e, 0x0e, 0xa7, 0x04, 0x12, 0x67, 0x4c, 0x29, 0x48, + 0x38, 0x27, 0x09, 0x6c, 0x02, 0x6c, 0x20, 0x21, 0x0a, 0x97, 0x06, 0x26, + 0xfe, 0xaf, 0x22, 0x22, 0x09, 0xa5, 0x08, 0x2d, 0x00, 0x06, 0x00, 0x02, + 0xff, 0xf4, 0x02, 0x56, 0x02, 0xc6, 0x00, 0x0b, 0x00, 0x19, 0x00, 0x1d, + 0x00, 0x21, 0x00, 0x2d, 0x00, 0x3b, 0x00, 0xc5, 0xba, 0x00, 0x25, 0x00, + 0x3c, 0x00, 0x3d, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x25, 0x10, 0xb8, 0x00, + 0x09, 0xd0, 0xb8, 0x00, 0x25, 0x10, 0xb8, 0x00, 0x0f, 0xd0, 0xb8, 0x00, + 0x25, 0x10, 0xb8, 0x00, 0x1d, 0xd0, 0xb8, 0x00, 0x25, 0x10, 0xb8, 0x00, + 0x1f, 0xd0, 0xb8, 0x00, 0x25, 0x10, 0xb8, 0x00, 0x39, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, + 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1a, + 0x2f, 0x1b, 0xb9, 0x00, 0x1a, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x21, 0x2f, 0x1b, 0xb9, 0x00, 0x21, 0x00, 0x11, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x22, 0x2f, 0x1b, + 0xb9, 0x00, 0x22, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x00, 0x00, 0x21, + 0x00, 0x06, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, 0x2f, 0xb9, 0x00, 0x0c, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x13, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x22, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x28, 0x2f, 0xb8, 0x00, 0x1c, 0xdc, 0xb8, 0x00, 0x00, 0x10, 0xb8, + 0x00, 0x1e, 0xdc, 0xb8, 0x00, 0x22, 0x10, 0xb9, 0x00, 0x2e, 0x00, 0x09, + 0xf4, 0xb8, 0x00, 0x28, 0x10, 0xb9, 0x00, 0x35, 0x00, 0x09, 0xf4, 0x30, + 0x31, 0x13, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, + 0x01, 0x14, 0x16, 0x01, 0x33, 0x03, 0x23, 0x07, 0x33, 0x03, 0x23, 0x05, + 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0xa5, 0x4b, 0x52, 0x52, 0x4b, 0x4b, 0x52, 0x52, 0x4b, 0x1d, 0x17, + 0x17, 0x1d, 0x1d, 0x17, 0x17, 0x01, 0x5d, 0x71, 0x97, 0x71, 0xb5, 0x71, + 0x97, 0x71, 0x01, 0xb2, 0x4b, 0x52, 0x52, 0x4b, 0x4b, 0x52, 0x52, 0x4b, + 0x1d, 0x17, 0x17, 0x1d, 0x1d, 0x17, 0x17, 0x01, 0x52, 0x63, 0x57, 0x57, + 0x63, 0x63, 0x57, 0x57, 0x63, 0x57, 0x2a, 0x23, 0x2c, 0x23, 0x2a, 0x2a, + 0x23, 0x2c, 0x23, 0x2a, 0x01, 0x11, 0xfe, 0xd4, 0x62, 0xfe, 0xd4, 0x0c, + 0x63, 0x57, 0x57, 0x63, 0x63, 0x57, 0x57, 0x63, 0x57, 0x2a, 0x23, 0x2c, + 0x23, 0x2a, 0x2a, 0x23, 0x2c, 0x23, 0x2a, 0x00, 0x00, 0x02, 0x00, 0x0e, + 0xff, 0xf4, 0x02, 0x57, 0x02, 0xc6, 0x00, 0x36, 0x00, 0x41, 0x00, 0xb6, + 0xba, 0x00, 0x22, 0x00, 0x42, 0x00, 0x43, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x22, 0x10, 0xb8, 0x00, 0x3a, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, + 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x32, 0x2f, 0x1b, 0xb9, 0x00, 0x32, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x10, 0xb9, 0x00, 0x37, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x22, 0x00, + 0x10, 0x00, 0x37, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x10, 0x10, 0xb9, 0x00, + 0x19, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x3b, 0x00, 0x19, 0x00, 0x00, 0x11, + 0x12, 0x39, 0xba, 0x00, 0x08, 0x00, 0x22, 0x00, 0x3b, 0x11, 0x12, 0x39, + 0xba, 0x00, 0x24, 0x00, 0x10, 0x00, 0x37, 0x11, 0x12, 0x39, 0xba, 0x00, + 0x2d, 0x00, 0x10, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x2d, 0x2f, + 0xb9, 0x00, 0x2b, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x33, 0x00, 0x19, 0x00, + 0x00, 0x11, 0x12, 0x39, 0xba, 0x00, 0x30, 0x00, 0x24, 0x00, 0x33, 0x11, + 0x12, 0x39, 0xba, 0x00, 0x3a, 0x00, 0x24, 0x00, 0x33, 0x11, 0x12, 0x39, + 0x30, 0x31, 0x17, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x36, 0x37, 0x2e, 0x01, + 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x17, 0x07, 0x2e, 0x01, + 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x1f, 0x02, 0x33, 0x3e, + 0x03, 0x35, 0x33, 0x15, 0x23, 0x0e, 0x01, 0x07, 0x17, 0x23, 0x27, 0x23, + 0x0e, 0x01, 0x27, 0x32, 0x36, 0x37, 0x27, 0x0e, 0x01, 0x1d, 0x01, 0x14, + 0x16, 0xcf, 0x2f, 0x48, 0x31, 0x19, 0x3c, 0x3a, 0x20, 0x21, 0x1d, 0x35, + 0x47, 0x2a, 0x25, 0x40, 0x31, 0x21, 0x08, 0x66, 0x0b, 0x2e, 0x1e, 0x1e, + 0x25, 0x08, 0x14, 0x1f, 0x18, 0x39, 0x30, 0x06, 0x03, 0x04, 0x03, 0x01, + 0xb2, 0x46, 0x05, 0x14, 0x10, 0x82, 0x9e, 0x50, 0x07, 0x07, 0x4e, 0x19, + 0x17, 0x28, 0x0e, 0x81, 0x1a, 0x10, 0x33, 0x0c, 0x21, 0x37, 0x49, 0x29, + 0x3f, 0x5e, 0x22, 0x2d, 0x46, 0x26, 0x25, 0x41, 0x2f, 0x1b, 0x15, 0x22, + 0x2d, 0x18, 0x37, 0x20, 0x25, 0x24, 0x1d, 0x05, 0x0e, 0x19, 0x1f, 0x29, + 0x1e, 0x48, 0x4a, 0x11, 0x29, 0x2b, 0x29, 0x11, 0x6e, 0x20, 0x43, 0x23, + 0x9e, 0x61, 0x33, 0x3a, 0x71, 0x11, 0x17, 0xa4, 0x19, 0x33, 0x1d, 0x02, + 0x30, 0x31, 0x00, 0x00, 0x00, 0x01, 0x00, 0xea, 0x01, 0x9e, 0x01, 0x6e, + 0x02, 0xe4, 0x00, 0x03, 0x00, 0x1e, 0xba, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x05, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x21, 0x3e, 0x59, 0x30, 0x31, + 0x13, 0x11, 0x33, 0x11, 0xea, 0x84, 0x01, 0x9e, 0x01, 0x46, 0xfe, 0xba, + 0x00, 0x01, 0x00, 0xae, 0xff, 0x76, 0x02, 0x12, 0x02, 0xf8, 0x00, 0x16, + 0x00, 0x15, 0xba, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x18, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x05, 0x2f, 0xb8, 0x00, 0x12, 0x2f, 0x30, 0x31, 0x13, + 0x34, 0x3e, 0x02, 0x37, 0x33, 0x0e, 0x03, 0x1d, 0x01, 0x14, 0x1e, 0x02, + 0x17, 0x23, 0x2e, 0x03, 0xae, 0x21, 0x39, 0x4c, 0x2a, 0x94, 0x2f, 0x54, + 0x3f, 0x26, 0x26, 0x3f, 0x54, 0x2f, 0x94, 0x2a, 0x4c, 0x39, 0x21, 0x01, + 0x37, 0x49, 0x87, 0x74, 0x5d, 0x20, 0x20, 0x55, 0x66, 0x74, 0x3f, 0x66, + 0x3f, 0x74, 0x66, 0x55, 0x20, 0x1f, 0x5e, 0x74, 0x87, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x46, 0xff, 0x76, 0x01, 0xaa, 0x02, 0xf8, 0x00, 0x16, + 0x00, 0x15, 0xba, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x18, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x11, 0x2f, 0xb8, 0x00, 0x06, 0x2f, 0x30, 0x31, 0x01, + 0x14, 0x0e, 0x02, 0x07, 0x23, 0x3e, 0x03, 0x3d, 0x01, 0x34, 0x2e, 0x02, + 0x27, 0x33, 0x1e, 0x03, 0x01, 0xaa, 0x21, 0x39, 0x4c, 0x2a, 0x94, 0x2e, + 0x55, 0x3f, 0x26, 0x26, 0x3f, 0x55, 0x2e, 0x94, 0x2a, 0x4c, 0x39, 0x21, + 0x01, 0x37, 0x49, 0x87, 0x74, 0x5e, 0x1f, 0x20, 0x55, 0x66, 0x74, 0x3f, + 0x66, 0x3f, 0x74, 0x66, 0x55, 0x20, 0x20, 0x5d, 0x74, 0x87, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x1e, 0x00, 0x3c, 0x02, 0x3a, 0x02, 0x38, 0x00, 0x0e, + 0x00, 0x11, 0xba, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x06, 0x2f, 0x30, 0x31, 0x37, 0x27, 0x37, 0x27, 0x37, + 0x17, 0x35, 0x33, 0x15, 0x37, 0x17, 0x07, 0x17, 0x07, 0x27, 0xbf, 0x68, + 0x72, 0xab, 0x27, 0xa7, 0x80, 0xa7, 0x27, 0xab, 0x72, 0x68, 0x6d, 0x3c, + 0x45, 0x96, 0x3a, 0x73, 0x3d, 0xb1, 0xb1, 0x3d, 0x73, 0x3a, 0x96, 0x45, + 0x95, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3e, 0x00, 0x3e, 0x02, 0x1a, + 0x02, 0x24, 0x00, 0x0b, 0x00, 0x27, 0xba, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0d, 0x11, 0x12, 0x39, 0x00, 0xbb, 0x00, 0x02, 0x00, 0x09, 0x00, 0x03, + 0x00, 0x04, 0x2b, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x07, 0xd0, 0xb8, + 0x00, 0x02, 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0x30, 0x31, 0x37, 0x35, 0x23, + 0x35, 0x33, 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0xec, 0xae, 0xae, + 0x80, 0xae, 0xae, 0x3e, 0xb8, 0x76, 0xb8, 0xb8, 0x76, 0xb8, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xaa, 0xff, 0x69, 0x01, 0xa1, 0x00, 0xae, 0x00, 0x03, + 0x00, 0x15, 0xba, 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x2f, 0xb8, 0x00, 0x03, 0x2f, 0x30, 0x31, 0x37, + 0x33, 0x03, 0x23, 0xe3, 0xbe, 0x89, 0x6e, 0xae, 0xfe, 0xbb, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x8c, 0x00, 0xea, 0x01, 0xcc, 0x01, 0x78, 0x00, 0x03, + 0x00, 0x17, 0xba, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xbb, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x2b, 0x30, + 0x31, 0x37, 0x35, 0x21, 0x15, 0x8c, 0x01, 0x40, 0xea, 0x8e, 0x8e, 0x00, + 0x00, 0x01, 0x00, 0xc3, 0xff, 0xf4, 0x01, 0x95, 0x00, 0xbd, 0x00, 0x0d, + 0x00, 0x17, 0xba, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0f, 0x11, 0x12, 0x39, + 0x00, 0xbb, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x2b, 0x30, + 0x31, 0x05, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, + 0x01, 0x14, 0x06, 0x01, 0x2c, 0x38, 0x31, 0x31, 0x38, 0x38, 0x31, 0x31, + 0x0c, 0x31, 0x22, 0x23, 0x22, 0x31, 0x31, 0x22, 0x23, 0x22, 0x31, 0x00, + 0x00, 0x01, 0x00, 0x49, 0xff, 0x76, 0x02, 0x0f, 0x02, 0xf8, 0x00, 0x03, + 0x00, 0x15, 0xba, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x01, 0x2f, 0xb8, 0x00, 0x00, 0x2f, 0x30, 0x31, 0x17, + 0x01, 0x33, 0x01, 0x49, 0x01, 0x41, 0x85, 0xfe, 0xbf, 0x8a, 0x03, 0x82, + 0xfc, 0x7e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1b, 0xff, 0xf4, 0x02, 0x3d, + 0x02, 0xc6, 0x00, 0x0b, 0x00, 0x19, 0x00, 0x27, 0x00, 0x9d, 0xba, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x29, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0c, 0xd0, + 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x1a, 0xd0, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x0c, 0x00, 0x0d, + 0xf4, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x13, 0x00, 0x0d, 0xf4, 0xba, + 0x00, 0x1a, 0x00, 0x13, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1a, + 0x2f, 0x41, 0x03, 0x00, 0x4f, 0x00, 0x1a, 0x00, 0x01, 0x71, 0x41, 0x05, + 0x00, 0x90, 0x00, 0x1a, 0x00, 0xa0, 0x00, 0x1a, 0x00, 0x02, 0x5d, 0x41, + 0x05, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x30, 0x00, 0x1a, 0x00, 0x02, 0x5d, + 0xb9, 0x00, 0x21, 0x00, 0x07, 0xf4, 0x41, 0x03, 0x00, 0xcf, 0x00, 0x21, + 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0x10, 0x00, 0x21, 0x00, 0x01, 0x71, + 0x41, 0x03, 0x00, 0x00, 0x00, 0x21, 0x00, 0x01, 0x5d, 0x30, 0x31, 0x05, + 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0x37, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, + 0x01, 0x14, 0x06, 0x01, 0x2c, 0x8c, 0x85, 0x85, 0x8c, 0x8c, 0x85, 0x85, + 0x8c, 0x43, 0x35, 0x35, 0x43, 0x43, 0x35, 0x35, 0x43, 0x23, 0x1b, 0x1b, + 0x23, 0x23, 0x1b, 0x1b, 0x0c, 0xbe, 0xab, 0xab, 0xbe, 0xbe, 0xab, 0xab, + 0xbe, 0x76, 0x5e, 0x54, 0x82, 0x54, 0x5e, 0x5e, 0x54, 0x82, 0x54, 0x5e, + 0xb8, 0x1c, 0x14, 0x16, 0x14, 0x1c, 0x1c, 0x14, 0x16, 0x14, 0x1c, 0x00, + 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x02, 0x44, 0x02, 0xba, 0x00, 0x0b, + 0x00, 0x5b, 0xba, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, + 0x00, 0x08, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb9, + 0x00, 0x01, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x08, 0x10, 0xb9, 0x00, 0x04, + 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x05, 0x00, 0x09, 0xf4, 0xb8, + 0x00, 0x01, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x30, 0x31, 0x33, 0x35, 0x33, + 0x11, 0x23, 0x07, 0x27, 0x37, 0x33, 0x11, 0x33, 0x15, 0x5e, 0xbc, 0x09, + 0x8e, 0x60, 0xa7, 0xe6, 0x94, 0x79, 0x01, 0xd4, 0xba, 0x4b, 0xdc, 0xfd, + 0xbf, 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x26, 0x00, 0x00, 0x02, 0x2b, + 0x02, 0xc6, 0x00, 0x1f, 0x00, 0x53, 0xba, 0x00, 0x13, 0x00, 0x20, 0x00, + 0x21, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, + 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x1e, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x03, + 0x00, 0x13, 0x00, 0x1e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x13, 0x10, 0xb9, + 0x00, 0x0a, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x1d, 0x00, 0x0a, 0x00, 0x01, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x29, 0x01, 0x35, 0x37, 0x3e, 0x01, 0x3d, + 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, + 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x0f, 0x01, 0x21, 0x02, 0x2b, 0xfe, + 0x0a, 0xdc, 0x39, 0x32, 0x34, 0x2c, 0x32, 0x36, 0x0b, 0x83, 0x0c, 0x2a, + 0x41, 0x56, 0x38, 0x39, 0x5a, 0x3e, 0x20, 0x1d, 0x33, 0x45, 0x27, 0x85, + 0x01, 0x50, 0x89, 0xb7, 0x31, 0x48, 0x28, 0x0a, 0x2c, 0x2d, 0x3a, 0x28, + 0x32, 0x24, 0x41, 0x30, 0x1d, 0x20, 0x38, 0x4d, 0x2d, 0x2c, 0x49, 0x40, + 0x3c, 0x1e, 0x67, 0x00, 0x00, 0x01, 0x00, 0x18, 0xff, 0xf4, 0x02, 0x2b, + 0x02, 0xc6, 0x00, 0x35, 0x00, 0x80, 0xba, 0x00, 0x10, 0x00, 0x36, 0x00, + 0x37, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x23, 0x2f, 0x1b, 0xb9, 0x00, 0x23, 0x00, + 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x10, 0x10, 0xb9, 0x00, 0x07, 0x00, 0x0d, + 0xf4, 0xba, 0x00, 0x34, 0x00, 0x10, 0x00, 0x23, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x34, 0x2f, 0x41, 0x03, 0x00, 0xcf, 0x00, 0x34, 0x00, 0x01, 0x5d, + 0x41, 0x03, 0x00, 0x5f, 0x00, 0x34, 0x00, 0x01, 0x5d, 0x41, 0x05, 0x00, + 0x2f, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x02, 0x5d, 0xb9, 0x00, + 0x35, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x1a, 0x00, 0x35, 0x00, 0x34, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x23, 0x10, 0xb9, 0x00, 0x2c, 0x00, 0x0d, 0xf4, + 0x30, 0x31, 0x01, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, + 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, + 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, + 0x01, 0x35, 0x01, 0x11, 0x3a, 0x35, 0x33, 0x2f, 0x2b, 0x4b, 0x1a, 0x5f, + 0x14, 0x30, 0x3a, 0x49, 0x2e, 0x39, 0x5c, 0x41, 0x24, 0x16, 0x25, 0x31, + 0x1c, 0x40, 0x55, 0x27, 0x47, 0x65, 0x3e, 0x35, 0x51, 0x3e, 0x2d, 0x11, + 0x6f, 0x17, 0x45, 0x3a, 0x36, 0x3a, 0x42, 0x3b, 0x41, 0x01, 0xa6, 0x2c, + 0x20, 0x07, 0x26, 0x2d, 0x2b, 0x28, 0x58, 0x1a, 0x2b, 0x1f, 0x11, 0x1a, + 0x31, 0x44, 0x2a, 0x21, 0x36, 0x28, 0x19, 0x05, 0x06, 0x0b, 0x55, 0x48, + 0x2f, 0x4c, 0x36, 0x1d, 0x16, 0x25, 0x31, 0x1a, 0x56, 0x2b, 0x37, 0x32, + 0x2c, 0x07, 0x2b, 0x2b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x19, + 0x00, 0x00, 0x02, 0x3d, 0x02, 0xba, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x5f, + 0xba, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x10, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x04, 0x10, 0xb8, 0x00, 0x0e, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, + 0x00, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x01, 0x2f, 0xb9, 0x00, 0x0c, 0x00, 0x09, + 0xf4, 0xb8, 0x00, 0x06, 0xd0, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x09, + 0xd0, 0xb8, 0x00, 0x05, 0x10, 0xb8, 0x00, 0x0d, 0xd0, 0x30, 0x31, 0x21, + 0x35, 0x21, 0x35, 0x01, 0x33, 0x11, 0x33, 0x15, 0x23, 0x15, 0x25, 0x33, + 0x11, 0x23, 0x01, 0x53, 0xfe, 0xc6, 0x01, 0x16, 0xb4, 0x5a, 0x5a, 0xfe, + 0xaf, 0xc1, 0x09, 0x86, 0x80, 0x01, 0xb4, 0xfe, 0x40, 0x74, 0x86, 0xfa, + 0x01, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2a, 0xff, 0xf4, 0x02, 0x37, + 0x02, 0xba, 0x00, 0x2a, 0x00, 0x6d, 0xba, 0x00, 0x24, 0x00, 0x2b, 0x00, + 0x2c, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x29, 0x2f, 0x1b, 0xb9, 0x00, 0x29, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x12, 0x2f, 0x1b, 0xb9, 0x00, 0x12, 0x00, + 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x29, 0x10, 0xb9, 0x00, 0x01, 0x00, 0x0d, + 0xf4, 0xba, 0x00, 0x24, 0x00, 0x12, 0x00, 0x29, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x24, 0x2f, 0x41, 0x03, 0x00, 0xcf, 0x00, 0x24, 0x00, 0x01, 0x5d, + 0x41, 0x05, 0x00, 0x4f, 0x00, 0x24, 0x00, 0x5f, 0x00, 0x24, 0x00, 0x02, + 0x5d, 0xb9, 0x00, 0x08, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x12, 0x10, 0xb9, + 0x00, 0x1d, 0x00, 0x0d, 0xf4, 0x30, 0x31, 0x01, 0x21, 0x07, 0x33, 0x3e, + 0x03, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, + 0x02, 0x27, 0x37, 0x1e, 0x03, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x23, 0x22, 0x06, 0x07, 0x27, 0x13, 0x21, 0x02, 0x0d, 0xfe, 0xbd, 0x10, + 0x09, 0x0b, 0x1c, 0x26, 0x32, 0x20, 0x2b, 0x4d, 0x3b, 0x22, 0x24, 0x45, + 0x66, 0x41, 0x33, 0x50, 0x3d, 0x2d, 0x10, 0x6d, 0x0c, 0x1b, 0x23, 0x2b, + 0x1c, 0x38, 0x39, 0x3a, 0x33, 0x2a, 0x37, 0x0e, 0x7b, 0x1a, 0x01, 0xb1, + 0x02, 0x37, 0xdd, 0x18, 0x29, 0x1d, 0x10, 0x1e, 0x39, 0x53, 0x34, 0x35, + 0x5a, 0x42, 0x25, 0x16, 0x25, 0x31, 0x1a, 0x56, 0x14, 0x24, 0x1b, 0x0f, + 0x3d, 0x33, 0x08, 0x31, 0x38, 0x21, 0x10, 0x11, 0x01, 0x8b, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x26, 0xff, 0xf4, 0x02, 0x39, 0x02, 0xba, 0x00, 0x1f, + 0x00, 0x2d, 0x00, 0x63, 0xba, 0x00, 0x20, 0x00, 0x2e, 0x00, 0x2f, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x20, 0x10, 0xb8, 0x00, 0x00, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, + 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, + 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x27, + 0x00, 0x0a, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x27, 0x2f, 0xb9, + 0x00, 0x16, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x11, 0x00, 0x27, 0x00, 0x16, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x2f, 0xb8, 0x00, 0x00, 0x10, 0xb9, + 0x00, 0x20, 0x00, 0x09, 0xf4, 0x30, 0x31, 0x05, 0x22, 0x2e, 0x02, 0x35, + 0x34, 0x3e, 0x02, 0x37, 0x33, 0x0e, 0x03, 0x07, 0x17, 0x3e, 0x03, 0x33, + 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, 0x01, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x30, 0x3f, + 0x63, 0x44, 0x24, 0x2e, 0x49, 0x5b, 0x2d, 0xcf, 0x41, 0x67, 0x4d, 0x31, + 0x0b, 0x09, 0x09, 0x1a, 0x26, 0x33, 0x22, 0x2c, 0x4c, 0x37, 0x20, 0x26, + 0x45, 0x62, 0x3d, 0x36, 0x38, 0x39, 0x35, 0x33, 0x3a, 0x37, 0x0c, 0x27, + 0x49, 0x66, 0x3f, 0x49, 0x83, 0x6f, 0x58, 0x1e, 0x2d, 0x53, 0x53, 0x58, + 0x33, 0x03, 0x14, 0x26, 0x1d, 0x12, 0x1f, 0x39, 0x50, 0x32, 0x35, 0x5a, + 0x41, 0x24, 0x75, 0x39, 0x34, 0x0e, 0x34, 0x37, 0x37, 0x34, 0x0e, 0x34, + 0x39, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0x00, 0x00, 0x02, 0x29, + 0x02, 0xba, 0x00, 0x08, 0x00, 0x47, 0xba, 0x00, 0x08, 0x00, 0x09, 0x00, + 0x0a, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x02, 0x00, 0x0d, + 0xf4, 0xba, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x04, 0x2f, 0x30, 0x31, 0x33, 0x13, 0x23, 0x15, 0x23, 0x35, 0x21, + 0x15, 0x03, 0xa4, 0xf0, 0xe2, 0x7f, 0x01, 0xf6, 0xe7, 0x02, 0x40, 0x7f, + 0xf9, 0x82, 0xfd, 0xc8, 0x00, 0x03, 0x00, 0x24, 0xff, 0xf4, 0x02, 0x34, + 0x02, 0xc6, 0x00, 0x21, 0x00, 0x2f, 0x00, 0x3d, 0x00, 0xd7, 0xba, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x3f, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x22, 0xd0, + 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x30, 0xd0, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x11, 0x2f, 0x1b, 0xb9, 0x00, 0x11, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x11, 0x10, 0xb9, + 0x00, 0x37, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x22, + 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x29, 0x00, 0x37, 0x00, 0x22, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x29, 0x2f, 0x41, 0x05, 0x00, 0x00, 0x00, 0x29, 0x00, + 0x10, 0x00, 0x29, 0x00, 0x02, 0x72, 0x41, 0x07, 0x00, 0xd0, 0x00, 0x29, + 0x00, 0xe0, 0x00, 0x29, 0x00, 0xf0, 0x00, 0x29, 0x00, 0x03, 0x72, 0x41, + 0x05, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x02, 0x5d, + 0x41, 0x03, 0x00, 0xcf, 0x00, 0x29, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, + 0x5f, 0x00, 0x29, 0x00, 0x01, 0x5d, 0x41, 0x05, 0x00, 0x40, 0x00, 0x29, + 0x00, 0x50, 0x00, 0x29, 0x00, 0x02, 0x72, 0x41, 0x05, 0x00, 0x60, 0x00, + 0x29, 0x00, 0x70, 0x00, 0x29, 0x00, 0x02, 0x71, 0x41, 0x03, 0x00, 0xd0, + 0x00, 0x29, 0x00, 0x01, 0x5d, 0xb9, 0x00, 0x30, 0x00, 0x09, 0xf4, 0xba, + 0x00, 0x08, 0x00, 0x30, 0x00, 0x29, 0x11, 0x12, 0x39, 0xba, 0x00, 0x1a, + 0x00, 0x30, 0x00, 0x29, 0x11, 0x12, 0x39, 0x30, 0x31, 0x05, 0x22, 0x2e, + 0x02, 0x35, 0x34, 0x36, 0x37, 0x35, 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, + 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, 0x15, + 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, + 0x06, 0x1d, 0x01, 0x14, 0x16, 0x13, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x2c, 0x3f, 0x62, 0x44, + 0x23, 0x4e, 0x3d, 0x34, 0x42, 0x20, 0x3e, 0x5a, 0x3b, 0x3a, 0x5b, 0x3e, + 0x20, 0x42, 0x34, 0x3d, 0x4e, 0x23, 0x44, 0x62, 0x3f, 0x34, 0x37, 0x36, + 0x35, 0x35, 0x36, 0x37, 0x34, 0x32, 0x34, 0x35, 0x31, 0x31, 0x35, 0x34, + 0x0c, 0x1f, 0x36, 0x4b, 0x2c, 0x44, 0x53, 0x11, 0x08, 0x13, 0x4e, 0x3d, + 0x28, 0x44, 0x31, 0x1b, 0x1b, 0x31, 0x44, 0x28, 0x3d, 0x4e, 0x13, 0x08, + 0x11, 0x53, 0x44, 0x2c, 0x4b, 0x36, 0x1f, 0x73, 0x30, 0x29, 0x14, 0x2a, + 0x2f, 0x2f, 0x2a, 0x14, 0x29, 0x30, 0x01, 0x34, 0x2e, 0x27, 0x0f, 0x27, + 0x2d, 0x2d, 0x27, 0x0f, 0x27, 0x2e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1f, + 0x00, 0x00, 0x02, 0x32, 0x02, 0xc6, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x63, + 0xba, 0x00, 0x20, 0x00, 0x2e, 0x00, 0x2f, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x20, 0x10, 0xb8, 0x00, 0x1b, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x1b, 0x2f, 0x1b, 0xb9, 0x00, 0x1b, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, + 0x05, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x20, 0x00, 0x1b, 0x00, 0x05, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x20, 0x2f, 0xb9, 0x00, 0x11, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x20, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x0c, 0x2f, 0xb8, 0x00, 0x1b, 0x10, 0xb9, 0x00, 0x27, 0x00, 0x09, + 0xf4, 0x30, 0x31, 0x01, 0x14, 0x0e, 0x02, 0x07, 0x23, 0x3e, 0x03, 0x37, + 0x27, 0x0e, 0x03, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, + 0x32, 0x1e, 0x02, 0x05, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, + 0x06, 0x1d, 0x01, 0x14, 0x16, 0x02, 0x32, 0x2e, 0x49, 0x5b, 0x2d, 0xcf, + 0x41, 0x67, 0x4d, 0x31, 0x0b, 0x09, 0x09, 0x1b, 0x25, 0x33, 0x22, 0x2c, + 0x4c, 0x37, 0x20, 0x26, 0x45, 0x62, 0x3c, 0x3f, 0x63, 0x44, 0x24, 0xfe, + 0xf7, 0x33, 0x3a, 0x37, 0x36, 0x36, 0x38, 0x39, 0x01, 0xb1, 0x4a, 0x82, + 0x6f, 0x58, 0x1e, 0x2d, 0x53, 0x53, 0x58, 0x33, 0x03, 0x14, 0x26, 0x1d, + 0x12, 0x1f, 0x39, 0x50, 0x32, 0x35, 0x5a, 0x41, 0x24, 0x27, 0x49, 0x66, + 0x85, 0x37, 0x34, 0x0e, 0x34, 0x39, 0x39, 0x34, 0x0e, 0x34, 0x37, 0x00, + 0xff, 0xff, 0x00, 0xc3, 0xff, 0xf4, 0x01, 0x95, 0x02, 0x10, 0x12, 0x26, + 0x00, 0x11, 0x00, 0x00, 0x10, 0x07, 0x00, 0x11, 0x00, 0x00, 0x01, 0x53, + 0xff, 0xff, 0x00, 0xaa, 0xff, 0x69, 0x01, 0xa1, 0x02, 0x10, 0x12, 0x26, + 0x00, 0x0f, 0x00, 0x00, 0x10, 0x07, 0x00, 0x11, 0x00, 0x00, 0x01, 0x53, + 0x00, 0x01, 0x00, 0x55, 0x00, 0x06, 0x02, 0x03, 0x02, 0x5c, 0x00, 0x07, + 0x00, 0x15, 0xba, 0x00, 0x05, 0x00, 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, + 0x00, 0xba, 0x00, 0x07, 0x00, 0x02, 0x00, 0x03, 0x2b, 0x30, 0x31, 0x37, + 0x35, 0x25, 0x15, 0x05, 0x15, 0x05, 0x15, 0x55, 0x01, 0xae, 0xfe, 0xd7, + 0x01, 0x29, 0xec, 0x8a, 0xe6, 0x8a, 0x9d, 0x08, 0x9d, 0x8a, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x3e, 0x00, 0x83, 0x02, 0x1a, 0x01, 0xdf, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x32, 0xba, 0x00, 0x04, 0x00, 0x08, 0x00, 0x09, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, 0x00, 0xd0, 0x00, 0xbb, + 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x2b, 0xbb, 0x00, 0x05, + 0x00, 0x09, 0x00, 0x04, 0x00, 0x04, 0x2b, 0x41, 0x03, 0x00, 0x1f, 0x00, + 0x04, 0x00, 0x01, 0x5d, 0x30, 0x31, 0x13, 0x35, 0x21, 0x15, 0x05, 0x35, + 0x21, 0x15, 0x3e, 0x01, 0xdc, 0xfe, 0x24, 0x01, 0xdc, 0x01, 0x69, 0x76, + 0x76, 0xe6, 0x76, 0x76, 0x00, 0x01, 0x00, 0x55, 0x00, 0x06, 0x02, 0x03, + 0x02, 0x5c, 0x00, 0x07, 0x00, 0x15, 0xba, 0x00, 0x01, 0x00, 0x08, 0x00, + 0x09, 0x11, 0x12, 0x39, 0x00, 0xba, 0x00, 0x07, 0x00, 0x04, 0x00, 0x03, + 0x2b, 0x30, 0x31, 0x37, 0x25, 0x35, 0x25, 0x35, 0x05, 0x15, 0x05, 0x55, + 0x01, 0x29, 0xfe, 0xd7, 0x01, 0xae, 0xfe, 0x52, 0x90, 0x9d, 0x08, 0x9d, + 0x8a, 0xe6, 0x8a, 0xe6, 0x00, 0x02, 0x00, 0x3d, 0xff, 0xf4, 0x02, 0x0f, + 0x02, 0xc6, 0x00, 0x1c, 0x00, 0x2a, 0x00, 0x51, 0xba, 0x00, 0x11, 0x00, + 0x2b, 0x00, 0x2c, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x10, 0xb8, 0x00, + 0x1d, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x11, 0x2f, + 0x1b, 0xb9, 0x00, 0x11, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x1d, 0x2f, 0x1b, 0xb9, 0x00, 0x1d, 0x00, 0x11, 0x3e, + 0x59, 0xb8, 0x00, 0x11, 0x10, 0xb9, 0x00, 0x08, 0x00, 0x0d, 0xf4, 0xb8, + 0x00, 0x1d, 0x10, 0xb9, 0x00, 0x24, 0x00, 0x0a, 0xf4, 0xb9, 0x00, 0x1c, + 0x00, 0x08, 0xf4, 0x30, 0x31, 0x37, 0x35, 0x3e, 0x01, 0x3d, 0x01, 0x34, + 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, 0x1e, 0x02, + 0x15, 0x14, 0x0e, 0x02, 0x07, 0x15, 0x07, 0x22, 0x26, 0x3d, 0x01, 0x34, + 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0xd0, 0x4b, 0x58, 0x31, + 0x24, 0x29, 0x34, 0x0a, 0x7a, 0x09, 0x23, 0x38, 0x4e, 0x34, 0x35, 0x57, + 0x3e, 0x22, 0x1d, 0x31, 0x41, 0x24, 0x44, 0x35, 0x2d, 0x2d, 0x35, 0x35, + 0x2e, 0x2d, 0xe9, 0x99, 0x03, 0x2e, 0x39, 0x0e, 0x2a, 0x24, 0x2f, 0x26, + 0x33, 0x1e, 0x39, 0x2d, 0x1c, 0x1e, 0x36, 0x4c, 0x2d, 0x2a, 0x45, 0x33, + 0x20, 0x06, 0x48, 0xf5, 0x2e, 0x20, 0x20, 0x20, 0x2d, 0x2e, 0x1f, 0x20, + 0x20, 0x2e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x26, 0xff, 0x8f, 0x02, 0x29, + 0x02, 0xc6, 0x00, 0x33, 0x00, 0x41, 0x00, 0x80, 0xba, 0x00, 0x0b, 0x00, + 0x42, 0x00, 0x43, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x10, 0xb8, 0x00, + 0x3f, 0xd0, 0x00, 0xb8, 0x00, 0x43, 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x43, 0x10, 0xb8, 0x00, 0x01, 0xdc, 0xba, 0x00, 0x11, 0x00, + 0x0b, 0x00, 0x43, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x2f, 0xb8, 0x00, + 0x17, 0xd0, 0xb9, 0x00, 0x34, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x13, 0x00, + 0x34, 0x00, 0x17, 0x11, 0x12, 0x39, 0xba, 0x00, 0x1d, 0x00, 0x17, 0x00, + 0x0b, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1d, 0x2f, 0xb8, 0x00, 0x0b, 0x10, + 0xb9, 0x00, 0x27, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x01, 0x10, 0xb9, 0x00, + 0x32, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x1d, 0x10, 0xb9, 0x00, 0x3b, 0x00, + 0x09, 0xf4, 0x30, 0x31, 0x05, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, + 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x11, 0x23, 0x35, 0x23, 0x0e, 0x01, + 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x17, 0x33, 0x35, + 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, + 0x3b, 0x01, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x1d, 0x01, 0x14, 0x16, 0x01, 0xbe, 0x69, 0x53, 0x74, 0x48, 0x20, 0x23, + 0x43, 0x62, 0x3f, 0x41, 0x5f, 0x3e, 0x1e, 0x6b, 0x07, 0x0b, 0x30, 0x23, + 0x3b, 0x41, 0x41, 0x3b, 0x23, 0x30, 0x0b, 0x07, 0x14, 0x25, 0x33, 0x1f, + 0x25, 0x3a, 0x29, 0x15, 0x15, 0x2e, 0x48, 0x34, 0x69, 0x39, 0x1c, 0x1d, + 0x1d, 0x1c, 0x1b, 0x1d, 0x1d, 0x71, 0x34, 0x68, 0x9d, 0x69, 0x72, 0x9b, + 0x5f, 0x29, 0x26, 0x43, 0x5a, 0x34, 0xfe, 0x8c, 0x3d, 0x25, 0x24, 0x67, + 0x70, 0x70, 0x67, 0x24, 0x25, 0x1b, 0x2a, 0x3a, 0x24, 0x10, 0x18, 0x3a, + 0x64, 0x4b, 0x81, 0x3a, 0x5c, 0x3f, 0x21, 0xb6, 0x20, 0x1b, 0x8c, 0x1b, + 0x20, 0x28, 0x38, 0x42, 0x38, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, + 0x00, 0x00, 0x02, 0x53, 0x02, 0xba, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x64, + 0xba, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x08, 0x10, 0xb8, 0x00, 0x01, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, + 0x04, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, + 0x0a, 0x00, 0x05, 0x00, 0x04, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0a, 0x2f, + 0xb9, 0x00, 0x02, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb8, 0x00, + 0x09, 0xd0, 0x30, 0x31, 0x21, 0x27, 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, + 0x01, 0x23, 0x03, 0x33, 0x01, 0xb3, 0x2c, 0xbf, 0x2b, 0x98, 0xbd, 0xd4, + 0xbd, 0xfe, 0xd9, 0x08, 0x44, 0x90, 0xa8, 0xa8, 0x02, 0xba, 0xfd, 0x46, + 0x02, 0x29, 0xfe, 0xf8, 0x00, 0x03, 0x00, 0x4d, 0x00, 0x00, 0x02, 0x2c, + 0x02, 0xba, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x23, 0x00, 0x6d, 0xba, 0x00, + 0x10, 0x00, 0x24, 0x00, 0x25, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x10, 0x10, + 0xb8, 0x00, 0x01, 0xd0, 0xb8, 0x00, 0x10, 0x10, 0xb8, 0x00, 0x1a, 0xd0, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, + 0x00, 0x00, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x0f, 0x2f, 0x1b, 0xb9, 0x00, 0x0f, 0x00, 0x11, 0x3e, 0x59, 0xb9, + 0x00, 0x19, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x23, 0x00, 0x00, 0x00, 0x19, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x23, 0x2f, 0xb9, 0x00, 0x18, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x07, 0x00, 0x23, 0x00, 0x18, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x00, 0x10, 0xb9, 0x00, 0x22, 0x00, 0x0d, 0xf4, 0x30, 0x31, 0x13, + 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, + 0x06, 0x23, 0x21, 0x37, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, + 0x15, 0x13, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x15, 0x4d, + 0xf5, 0x67, 0x6d, 0x3b, 0x37, 0x41, 0x47, 0x6f, 0x64, 0xfe, 0xf4, 0xde, + 0x36, 0x32, 0x32, 0x36, 0x4c, 0x39, 0x35, 0x30, 0x30, 0x35, 0x39, 0x02, + 0xba, 0x64, 0x56, 0x3c, 0x47, 0x10, 0x06, 0x10, 0x50, 0x47, 0x58, 0x68, + 0x69, 0x24, 0x30, 0x1d, 0x30, 0x24, 0xc5, 0x01, 0x29, 0x23, 0x2e, 0x1e, + 0x2e, 0x22, 0xbf, 0x00, 0x00, 0x01, 0x00, 0x29, 0xff, 0xf4, 0x02, 0x33, + 0x02, 0xc6, 0x00, 0x20, 0x00, 0x43, 0xba, 0x00, 0x18, 0x00, 0x21, 0x00, + 0x22, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x0d, + 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x18, 0x00, 0x0d, 0xf4, 0x30, + 0x31, 0x05, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x1e, 0x02, 0x17, + 0x07, 0x2e, 0x03, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x33, 0x32, + 0x36, 0x37, 0x17, 0x0e, 0x03, 0x01, 0x3c, 0x8c, 0x87, 0x87, 0x8c, 0x36, + 0x53, 0x3c, 0x27, 0x0b, 0x8c, 0x06, 0x10, 0x19, 0x25, 0x1a, 0x3d, 0x33, + 0x33, 0x3d, 0x34, 0x2f, 0x0b, 0x8c, 0x0b, 0x27, 0x3c, 0x53, 0x0c, 0xbd, + 0xac, 0xac, 0xbd, 0x1d, 0x34, 0x4a, 0x2e, 0x22, 0x19, 0x2a, 0x1e, 0x11, + 0x5f, 0x54, 0x7a, 0x54, 0x5f, 0x40, 0x32, 0x22, 0x2e, 0x4a, 0x35, 0x1c, + 0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x02, 0x36, 0x02, 0xba, 0x00, 0x08, + 0x00, 0x12, 0x00, 0x4b, 0xba, 0x00, 0x07, 0x00, 0x13, 0x00, 0x14, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, + 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, + 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x10, 0xb9, 0x00, 0x11, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x08, 0x10, 0xb9, + 0x00, 0x12, 0x00, 0x0d, 0xf4, 0x30, 0x31, 0x13, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x06, 0x2b, 0x01, 0x37, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, + 0x01, 0x11, 0x40, 0xe1, 0x8d, 0x88, 0x88, 0x8d, 0xe1, 0xd7, 0x43, 0x3e, + 0x3e, 0x43, 0x43, 0x02, 0xba, 0xb4, 0xa9, 0xa9, 0xb4, 0x76, 0x56, 0x52, + 0x7f, 0x51, 0x56, 0xfe, 0x32, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x50, + 0x00, 0x00, 0x02, 0x0e, 0x02, 0xba, 0x00, 0x0b, 0x00, 0x57, 0xba, 0x00, + 0x09, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x01, 0x10, 0xb9, + 0x00, 0x04, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x08, 0x2f, 0xb9, 0x00, 0x05, 0x00, 0x0d, + 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x09, 0x00, 0x0d, 0xf4, 0x30, + 0x31, 0x33, 0x11, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, + 0x15, 0x50, 0x01, 0xbe, 0xfe, 0xd8, 0x01, 0x1e, 0xfe, 0xe2, 0x01, 0x28, + 0x02, 0xba, 0x7b, 0xa0, 0x7b, 0xa9, 0x7b, 0x00, 0x00, 0x01, 0x00, 0x50, + 0x00, 0x00, 0x02, 0x1f, 0x02, 0xba, 0x00, 0x09, 0x00, 0x4d, 0xba, 0x00, + 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x01, 0x10, 0xb9, + 0x00, 0x04, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x08, 0x2f, 0xb9, 0x00, 0x05, 0x00, 0x0d, + 0xf4, 0x30, 0x31, 0x33, 0x11, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, + 0x11, 0x50, 0x01, 0xcf, 0xfe, 0xc7, 0x01, 0x18, 0xfe, 0xe8, 0x02, 0xba, + 0x7b, 0xa0, 0x7b, 0xfe, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x23, + 0xff, 0xf4, 0x02, 0x21, 0x02, 0xc6, 0x00, 0x29, 0x00, 0x72, 0xba, 0x00, + 0x0e, 0x00, 0x2a, 0x00, 0x2b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0e, 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, + 0xb9, 0x00, 0x06, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x29, 0x2f, 0x1b, 0xb9, 0x00, 0x29, 0x00, 0x11, 0x3e, 0x59, + 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x20, 0x00, 0x09, 0xf4, 0xba, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x20, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0e, 0x10, + 0xb9, 0x00, 0x19, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x25, 0x00, 0x19, 0x00, + 0x06, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x25, 0x2f, 0xb9, 0x00, 0x26, 0x00, + 0x09, 0xf4, 0x30, 0x31, 0x25, 0x23, 0x0e, 0x03, 0x23, 0x22, 0x2e, 0x02, + 0x35, 0x34, 0x36, 0x33, 0x32, 0x1e, 0x02, 0x17, 0x07, 0x2e, 0x03, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x23, + 0x35, 0x33, 0x11, 0x23, 0x01, 0x9b, 0x09, 0x09, 0x1a, 0x26, 0x33, 0x20, + 0x33, 0x4f, 0x36, 0x1b, 0x82, 0x88, 0x36, 0x52, 0x3b, 0x26, 0x0b, 0x8c, + 0x06, 0x0f, 0x18, 0x24, 0x1a, 0x39, 0x2f, 0x33, 0x41, 0x33, 0x32, 0x77, + 0xfd, 0x86, 0x63, 0x16, 0x28, 0x1f, 0x12, 0x30, 0x5c, 0x84, 0x53, 0xb2, + 0xbd, 0x1d, 0x35, 0x4a, 0x2d, 0x22, 0x16, 0x29, 0x20, 0x13, 0x5e, 0x55, + 0x72, 0x55, 0x66, 0x3c, 0x2f, 0x33, 0x6a, 0xfe, 0x8b, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x3d, 0x00, 0x00, 0x02, 0x1b, 0x02, 0xba, 0x00, 0x0b, + 0x00, 0x9a, 0xba, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, + 0x00, 0x04, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1f, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x03, 0x2f, 0x1b, 0xb9, 0x00, 0x03, + 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, + 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x01, + 0x00, 0x04, 0x00, 0x03, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x01, 0x2f, 0x41, + 0x05, 0x00, 0x9f, 0x00, 0x01, 0x00, 0xaf, 0x00, 0x01, 0x00, 0x02, 0x5d, + 0x41, 0x03, 0x00, 0x3f, 0x00, 0x01, 0x00, 0x01, 0x71, 0x41, 0x03, 0x00, + 0xbf, 0x00, 0x01, 0x00, 0x01, 0x71, 0x41, 0x03, 0x00, 0x5f, 0x00, 0x01, + 0x00, 0x01, 0x5d, 0x41, 0x05, 0x00, 0x2f, 0x00, 0x01, 0x00, 0x3f, 0x00, + 0x01, 0x00, 0x02, 0x5d, 0xb9, 0x00, 0x06, 0x00, 0x0d, 0xf4, 0x30, 0x31, + 0x01, 0x23, 0x11, 0x23, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x23, + 0x01, 0x84, 0xb0, 0x97, 0x97, 0xb0, 0x97, 0x97, 0x01, 0x24, 0xfe, 0xdc, + 0x02, 0xba, 0xfe, 0xe5, 0x01, 0x1b, 0xfd, 0x46, 0x00, 0x01, 0x00, 0x4b, + 0x00, 0x00, 0x02, 0x0d, 0x02, 0xba, 0x00, 0x0b, 0x00, 0x4b, 0xba, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x01, 0x00, 0x09, + 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x04, 0x00, 0x09, 0xf4, 0xb8, + 0x00, 0x08, 0xd0, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x30, + 0x31, 0x33, 0x35, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, 0x23, 0x11, 0x33, + 0x15, 0x4b, 0x96, 0x96, 0x01, 0xc2, 0x96, 0x96, 0x6f, 0x01, 0xdc, 0x6f, + 0x6f, 0xfe, 0x24, 0x6f, 0x00, 0x01, 0x00, 0x26, 0xff, 0xf4, 0x01, 0xff, + 0x02, 0xba, 0x00, 0x13, 0x00, 0x3f, 0xba, 0x00, 0x06, 0x00, 0x14, 0x00, + 0x15, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, + 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x0d, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x13, + 0x10, 0xb9, 0x00, 0x12, 0x00, 0x0d, 0xf4, 0x30, 0x31, 0x01, 0x11, 0x14, + 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, + 0x35, 0x11, 0x23, 0x35, 0x01, 0xff, 0x21, 0x3d, 0x56, 0x35, 0x6b, 0x75, + 0x10, 0x8e, 0x08, 0x2d, 0x2d, 0x26, 0x2b, 0xe6, 0x02, 0xba, 0xfe, 0x09, + 0x2f, 0x4d, 0x36, 0x1d, 0x6b, 0x57, 0x1d, 0x2d, 0x38, 0x31, 0x33, 0x01, + 0x6d, 0x7b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x00, 0x00, 0x02, 0x5b, + 0x02, 0xba, 0x00, 0x0d, 0x00, 0x63, 0xba, 0x00, 0x08, 0x00, 0x0e, 0x00, + 0x0f, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, + 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x03, 0x2f, + 0x1b, 0xb9, 0x00, 0x03, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0d, 0x2f, 0x1b, 0xb9, 0x00, 0x0d, 0x00, 0x11, 0x3e, + 0x59, 0xba, 0x00, 0x06, 0x00, 0x09, 0x00, 0x03, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x06, 0x10, 0xb8, 0x00, 0x01, 0xd0, 0x30, 0x31, 0x01, 0x07, 0x15, + 0x23, 0x11, 0x33, 0x11, 0x33, 0x3f, 0x01, 0x33, 0x03, 0x13, 0x23, 0x01, + 0x18, 0x3e, 0x96, 0x96, 0x08, 0x4c, 0x7b, 0xa8, 0xd1, 0xdb, 0xa9, 0x01, + 0x23, 0x57, 0xcc, 0x02, 0xba, 0xfe, 0xdc, 0x74, 0xb0, 0xfe, 0xd9, 0xfe, + 0x6d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5c, 0x00, 0x00, 0x02, 0x1f, + 0x02, 0xba, 0x00, 0x05, 0x00, 0x35, 0xba, 0x00, 0x03, 0x00, 0x06, 0x00, + 0x07, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x03, 0x00, 0x0d, 0xf4, 0x30, 0x31, 0x33, + 0x11, 0x33, 0x11, 0x21, 0x15, 0x5c, 0x97, 0x01, 0x2c, 0x02, 0xba, 0xfd, + 0xc1, 0x7b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x00, 0x00, 0x02, 0x31, + 0x02, 0xba, 0x00, 0x10, 0x00, 0x71, 0xba, 0x00, 0x03, 0x00, 0x11, 0x00, + 0x12, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0d, 0x2f, 0x1b, 0xb9, 0x00, 0x0d, 0x00, + 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, + 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x11, 0x3e, + 0x59, 0xb8, 0x00, 0x0d, 0x10, 0xb8, 0x00, 0x02, 0xd0, 0xb8, 0x00, 0x08, + 0x10, 0xb8, 0x00, 0x03, 0xdc, 0xb8, 0x00, 0x09, 0x10, 0xb8, 0x00, 0x05, + 0xd0, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x0b, 0xd0, 0x30, 0x31, 0x01, + 0x37, 0x23, 0x0b, 0x01, 0x23, 0x17, 0x11, 0x23, 0x11, 0x33, 0x17, 0x33, + 0x37, 0x33, 0x11, 0x23, 0x01, 0xaf, 0x08, 0x09, 0x82, 0x82, 0x09, 0x08, + 0x82, 0xb1, 0x56, 0x08, 0x56, 0xa5, 0x82, 0x01, 0x37, 0xc3, 0xfe, 0x99, + 0x01, 0x67, 0xc3, 0xfe, 0xc9, 0x02, 0xba, 0xeb, 0xeb, 0xfd, 0x46, 0x00, + 0x00, 0x01, 0x00, 0x3d, 0x00, 0x00, 0x02, 0x1b, 0x02, 0xba, 0x00, 0x0b, + 0x00, 0x61, 0xba, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, + 0x00, 0x04, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1f, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x03, 0x2f, 0x1b, 0xb9, 0x00, 0x03, + 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, + 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x04, + 0x10, 0xb8, 0x00, 0x00, 0xd0, 0xb8, 0x00, 0x0b, 0x10, 0xb8, 0x00, 0x07, + 0xd0, 0x30, 0x31, 0x13, 0x23, 0x11, 0x23, 0x11, 0x33, 0x13, 0x33, 0x11, + 0x33, 0x11, 0x23, 0xc8, 0x0b, 0x80, 0xb4, 0x9f, 0x0b, 0x80, 0xb4, 0x01, + 0xd0, 0xfe, 0x30, 0x02, 0xba, 0xfe, 0x30, 0x01, 0xd0, 0xfd, 0x46, 0x00, + 0x00, 0x02, 0x00, 0x1b, 0xff, 0xf4, 0x02, 0x3d, 0x02, 0xc6, 0x00, 0x0b, + 0x00, 0x19, 0x00, 0x43, 0xba, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x1b, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0c, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, + 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x0c, 0x00, 0x0d, 0xf4, 0xb8, + 0x00, 0x06, 0x10, 0xb9, 0x00, 0x13, 0x00, 0x0d, 0xf4, 0x30, 0x31, 0x05, + 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0x01, 0x2c, 0x8c, 0x85, 0x85, 0x8c, 0x8c, 0x85, 0x85, 0x8c, 0x40, + 0x31, 0x31, 0x40, 0x40, 0x31, 0x31, 0x0c, 0xbe, 0xab, 0xab, 0xbe, 0xbe, + 0xab, 0xab, 0xbe, 0x79, 0x5f, 0x55, 0x79, 0x54, 0x5f, 0x5f, 0x54, 0x7a, + 0x54, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x02, 0x30, + 0x02, 0xba, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x55, 0xba, 0x00, 0x10, 0x00, + 0x19, 0x00, 0x1a, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x10, 0x10, 0xb8, 0x00, + 0x0c, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, + 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, + 0x59, 0xba, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x0f, 0x2f, 0xb9, 0x00, 0x0d, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x01, + 0x10, 0xb9, 0x00, 0x18, 0x00, 0x0d, 0xf4, 0x30, 0x31, 0x33, 0x11, 0x21, + 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x2b, 0x01, 0x15, 0x11, 0x33, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x4c, 0x01, 0x0e, 0x33, + 0x50, 0x37, 0x1c, 0x1c, 0x37, 0x50, 0x33, 0x77, 0x51, 0x35, 0x29, 0x29, + 0x35, 0x51, 0x02, 0xba, 0x1f, 0x3a, 0x52, 0x33, 0x33, 0x52, 0x3a, 0x1f, + 0xfe, 0x01, 0x77, 0x28, 0x2e, 0x1e, 0x2e, 0x28, 0x00, 0x02, 0x00, 0x1b, + 0xff, 0x41, 0x02, 0x3d, 0x02, 0xc6, 0x00, 0x13, 0x00, 0x21, 0x00, 0x61, + 0xba, 0x00, 0x14, 0x00, 0x22, 0x00, 0x23, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x14, 0x10, 0xb8, 0x00, 0x0b, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, + 0x05, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x12, 0xd0, 0xb8, 0x00, 0x12, + 0x2f, 0xb9, 0x00, 0x01, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb8, + 0x00, 0x11, 0xd0, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x14, 0x00, 0x09, + 0xf4, 0xb8, 0x00, 0x0b, 0x10, 0xb9, 0x00, 0x1b, 0x00, 0x0d, 0xf4, 0x30, + 0x31, 0x05, 0x23, 0x22, 0x26, 0x3d, 0x01, 0x2e, 0x01, 0x35, 0x34, 0x36, + 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x15, 0x33, 0x27, 0x32, 0x36, + 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x02, + 0x0e, 0x8e, 0x51, 0x44, 0x6b, 0x65, 0x85, 0x8c, 0x8c, 0x85, 0x65, 0x6b, + 0xa1, 0xe2, 0x40, 0x31, 0x31, 0x40, 0x40, 0x31, 0x31, 0xbf, 0x4e, 0x42, + 0x29, 0x15, 0xb7, 0x97, 0xab, 0xbe, 0xbe, 0xab, 0x97, 0xb7, 0x15, 0x4e, + 0xc1, 0x5f, 0x55, 0x79, 0x54, 0x5f, 0x5f, 0x54, 0x7a, 0x54, 0x5f, 0x00, + 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x02, 0x3e, 0x02, 0xba, 0x00, 0x0f, + 0x00, 0x19, 0x00, 0x70, 0xba, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x1b, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0e, 0x10, 0xb8, 0x00, 0x10, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x02, 0x2f, 0x1b, 0xb9, 0x00, 0x02, + 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, + 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0d, 0x2f, 0x1b, 0xb9, 0x00, 0x0d, 0x00, 0x11, + 0x3e, 0x59, 0xba, 0x00, 0x19, 0x00, 0x02, 0x00, 0x01, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x19, 0x2f, 0xb9, 0x00, 0x0f, 0x00, 0x0d, 0xf4, 0xba, 0x00, + 0x0b, 0x00, 0x19, 0x00, 0x0f, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x02, 0x10, + 0xb9, 0x00, 0x18, 0x00, 0x0d, 0xf4, 0x30, 0x31, 0x33, 0x23, 0x11, 0x21, + 0x32, 0x1e, 0x02, 0x15, 0x14, 0x06, 0x07, 0x13, 0x23, 0x03, 0x23, 0x37, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x15, 0xe0, 0x94, 0x01, + 0x0e, 0x33, 0x50, 0x37, 0x1c, 0x40, 0x3b, 0x89, 0xa4, 0x75, 0x45, 0x56, + 0x35, 0x29, 0x29, 0x35, 0x56, 0x02, 0xba, 0x1f, 0x3a, 0x52, 0x33, 0x4a, + 0x6a, 0x11, 0xfe, 0xe9, 0x01, 0x03, 0x74, 0x28, 0x2e, 0x1e, 0x2e, 0x28, + 0xca, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1f, 0xff, 0xf4, 0x02, 0x2c, + 0x02, 0xc6, 0x00, 0x28, 0x00, 0x63, 0xba, 0x00, 0x07, 0x00, 0x29, 0x00, + 0x2a, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x14, 0x2f, 0x1b, 0xb9, 0x00, 0x14, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x07, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x14, + 0x10, 0xb9, 0x00, 0x1b, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x0e, 0x00, 0x1b, + 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0e, 0x10, 0xb8, 0x00, 0x0d, + 0xd0, 0xba, 0x00, 0x20, 0x00, 0x14, 0x00, 0x07, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x20, 0x10, 0xb8, 0x00, 0x21, 0xd0, 0x30, 0x31, 0x05, 0x22, 0x26, + 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2f, 0x01, + 0x2e, 0x01, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x17, 0x07, 0x2e, 0x01, + 0x23, 0x22, 0x15, 0x14, 0x16, 0x1f, 0x01, 0x1e, 0x01, 0x15, 0x14, 0x0e, + 0x02, 0x01, 0x21, 0x58, 0x82, 0x28, 0x57, 0x26, 0x5b, 0x2f, 0x36, 0x38, + 0x2b, 0x33, 0x49, 0x5e, 0x54, 0x84, 0x77, 0x51, 0x78, 0x25, 0x55, 0x1c, + 0x4c, 0x30, 0x65, 0x2d, 0x33, 0x49, 0x55, 0x5c, 0x22, 0x44, 0x63, 0x0c, + 0x3a, 0x32, 0x60, 0x2a, 0x28, 0x30, 0x2d, 0x25, 0x26, 0x08, 0x0c, 0x10, + 0x6b, 0x4d, 0x65, 0x6f, 0x32, 0x2b, 0x5f, 0x1f, 0x23, 0x53, 0x24, 0x24, + 0x09, 0x0d, 0x0f, 0x62, 0x53, 0x31, 0x53, 0x3d, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x02, 0x40, 0x02, 0xba, 0x00, 0x07, + 0x00, 0x3d, 0xba, 0x00, 0x02, 0x00, 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, + 0x00, 0x05, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x02, 0x2f, 0x1b, 0xb9, 0x00, 0x02, 0x00, 0x11, 0x3e, 0x59, 0xb8, + 0x00, 0x05, 0x10, 0xb9, 0x00, 0x04, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x00, + 0xd0, 0x30, 0x31, 0x01, 0x11, 0x23, 0x11, 0x23, 0x35, 0x21, 0x15, 0x01, + 0x77, 0x96, 0xc9, 0x02, 0x28, 0x02, 0x3f, 0xfd, 0xc1, 0x02, 0x3f, 0x7b, + 0x7b, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0xff, 0xf4, 0x02, 0x21, + 0x02, 0xba, 0x00, 0x19, 0x00, 0x46, 0xba, 0x00, 0x13, 0x00, 0x1a, 0x00, + 0x1b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x19, 0x2f, 0x1b, 0xb9, 0x00, 0x19, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0c, 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, + 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x13, 0x2f, + 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x06, 0x00, + 0x0d, 0xf4, 0x30, 0x31, 0x13, 0x11, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x3e, + 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, + 0x35, 0x11, 0xcd, 0x05, 0x13, 0x26, 0x21, 0x21, 0x26, 0x13, 0x05, 0x96, + 0x13, 0x36, 0x60, 0x4c, 0x4c, 0x60, 0x36, 0x13, 0x02, 0xba, 0xfe, 0x46, + 0x21, 0x37, 0x26, 0x15, 0x15, 0x26, 0x37, 0x21, 0x01, 0xba, 0xfe, 0x5a, + 0x48, 0x6c, 0x48, 0x24, 0x24, 0x48, 0x6c, 0x48, 0x01, 0xa6, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x02, 0x4f, 0x02, 0xba, 0x00, 0x09, + 0x00, 0x44, 0xba, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, + 0x00, 0x01, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, 0x1f, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, + 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x04, 0xd0, 0x30, 0x31, 0x33, 0x03, + 0x33, 0x13, 0x17, 0x33, 0x37, 0x13, 0x33, 0x03, 0xc2, 0xb9, 0xa7, 0x52, + 0x29, 0x08, 0x2a, 0x53, 0x9f, 0xb9, 0x02, 0xba, 0xfe, 0x9d, 0xc9, 0xc9, + 0x01, 0x63, 0xfd, 0x46, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x02, 0x4d, + 0x02, 0xba, 0x00, 0x11, 0x00, 0x77, 0xba, 0x00, 0x10, 0x00, 0x12, 0x00, + 0x13, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, + 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0e, 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x11, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x04, 0xd0, 0xba, 0x00, 0x06, + 0x00, 0x01, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x06, 0x2f, 0xb8, + 0x00, 0x04, 0x10, 0xb8, 0x00, 0x08, 0xd0, 0xb8, 0x00, 0x06, 0x10, 0xb8, + 0x00, 0x10, 0xd0, 0x30, 0x31, 0x33, 0x03, 0x33, 0x13, 0x17, 0x33, 0x13, + 0x33, 0x13, 0x33, 0x37, 0x13, 0x33, 0x03, 0x23, 0x03, 0x23, 0x03, 0x36, + 0x2b, 0x81, 0x14, 0x06, 0x09, 0x3c, 0x87, 0x3c, 0x09, 0x06, 0x14, 0x7c, + 0x2b, 0xbe, 0x33, 0x0a, 0x33, 0x02, 0xba, 0xfe, 0x5e, 0x84, 0x01, 0x8e, + 0xfe, 0x72, 0x80, 0x01, 0xa6, 0xfd, 0x46, 0x01, 0x81, 0xfe, 0x7f, 0x00, + 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x02, 0x4f, 0x02, 0xba, 0x00, 0x11, + 0x00, 0x77, 0xba, 0x00, 0x03, 0x00, 0x12, 0x00, 0x13, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, + 0x00, 0x09, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x0f, 0x2f, 0x1b, 0xb9, 0x00, 0x0f, 0x00, 0x1f, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, + 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, + 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x04, + 0x00, 0x0f, 0x00, 0x01, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0c, 0x00, 0x09, + 0x00, 0x07, 0x11, 0x12, 0x39, 0xba, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x08, 0x10, 0xb8, 0x00, 0x11, 0xd0, 0x30, + 0x31, 0x21, 0x23, 0x2f, 0x01, 0x23, 0x0f, 0x01, 0x23, 0x13, 0x03, 0x33, + 0x1f, 0x01, 0x33, 0x3f, 0x01, 0x33, 0x03, 0x02, 0x4f, 0xab, 0x48, 0x31, + 0x09, 0x32, 0x4a, 0x9d, 0xc4, 0xb7, 0xab, 0x39, 0x33, 0x08, 0x34, 0x3c, + 0x9d, 0xb7, 0x8b, 0x6e, 0x6e, 0x8b, 0x01, 0x69, 0x01, 0x51, 0x6f, 0x70, + 0x70, 0x6f, 0xfe, 0xad, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x02, 0x54, + 0x02, 0xba, 0x00, 0x0b, 0x00, 0x5a, 0xba, 0x00, 0x05, 0x00, 0x0c, 0x00, + 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x02, 0x2f, 0x1b, 0xb9, 0x00, 0x02, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, + 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x05, 0x2f, 0xb8, 0x00, + 0x01, 0xd0, 0xb8, 0x00, 0x05, 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0x30, 0x31, + 0x33, 0x35, 0x03, 0x33, 0x1f, 0x01, 0x33, 0x3f, 0x01, 0x33, 0x03, 0x15, + 0xe1, 0xdd, 0xa7, 0x4a, 0x36, 0x08, 0x36, 0x4a, 0xa1, 0xdd, 0xf7, 0x01, + 0xc3, 0xa2, 0x89, 0x89, 0xa2, 0xfe, 0x3d, 0xf7, 0x00, 0x01, 0x00, 0x30, + 0x00, 0x00, 0x02, 0x27, 0x02, 0xba, 0x00, 0x09, 0x00, 0x53, 0xba, 0x00, + 0x03, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, + 0xb9, 0x00, 0x01, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x08, 0x00, 0x0d, + 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x04, 0x00, 0x0d, 0xf4, 0xba, + 0x00, 0x07, 0x00, 0x04, 0x00, 0x08, 0x11, 0x12, 0x39, 0xba, 0x00, 0x02, + 0x00, 0x08, 0x00, 0x07, 0x11, 0x12, 0x39, 0x30, 0x31, 0x29, 0x01, 0x35, + 0x01, 0x21, 0x35, 0x21, 0x15, 0x01, 0x21, 0x02, 0x27, 0xfe, 0x09, 0x01, + 0x45, 0xfe, 0xc5, 0x01, 0xe3, 0xfe, 0xbb, 0x01, 0x4f, 0x83, 0x01, 0xbc, + 0x7b, 0x83, 0xfe, 0x44, 0x00, 0x01, 0x00, 0xb7, 0xff, 0x76, 0x01, 0xfb, + 0x02, 0xf8, 0x00, 0x07, 0x00, 0x29, 0xba, 0x00, 0x05, 0x00, 0x08, 0x00, + 0x09, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x01, 0x2f, 0xb8, 0x00, 0x00, + 0x2f, 0xb8, 0x00, 0x01, 0x10, 0xb9, 0x00, 0x04, 0x00, 0x09, 0xf4, 0xb8, + 0x00, 0x00, 0x10, 0xb9, 0x00, 0x05, 0x00, 0x09, 0xf4, 0x30, 0x31, 0x17, + 0x11, 0x21, 0x15, 0x23, 0x11, 0x33, 0x15, 0xb7, 0x01, 0x44, 0xcd, 0xcd, + 0x8a, 0x03, 0x82, 0x63, 0xfd, 0x44, 0x63, 0x00, 0x00, 0x01, 0x00, 0x49, + 0xff, 0x76, 0x02, 0x0f, 0x02, 0xf8, 0x00, 0x03, 0x00, 0x15, 0xba, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x01, + 0x2f, 0xb8, 0x00, 0x00, 0x2f, 0x30, 0x31, 0x05, 0x01, 0x33, 0x01, 0x01, + 0x8a, 0xfe, 0xbf, 0x85, 0x01, 0x41, 0x8a, 0x03, 0x82, 0xfc, 0x7e, 0x00, + 0x00, 0x01, 0x00, 0x5d, 0xff, 0x76, 0x01, 0xa1, 0x02, 0xf8, 0x00, 0x07, + 0x00, 0x25, 0xba, 0x00, 0x04, 0x00, 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x07, 0x2f, 0xb8, 0x00, 0x02, 0x2f, 0xb9, 0x00, 0x03, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x07, 0x10, 0xb9, 0x00, 0x06, 0x00, 0x09, + 0xf4, 0x30, 0x31, 0x01, 0x11, 0x21, 0x35, 0x33, 0x11, 0x23, 0x35, 0x01, + 0xa1, 0xfe, 0xbc, 0xcd, 0xcd, 0x02, 0xf8, 0xfc, 0x7e, 0x63, 0x02, 0xbc, + 0x63, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1b, 0x00, 0xef, 0x02, 0x3d, + 0x02, 0xba, 0x00, 0x07, 0x00, 0x1e, 0xba, 0x00, 0x01, 0x00, 0x08, 0x00, + 0x09, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1f, 0x3e, 0x59, 0x30, 0x31, + 0x25, 0x03, 0x23, 0x03, 0x27, 0x13, 0x33, 0x13, 0x01, 0xc8, 0x99, 0x0c, + 0x99, 0x6f, 0xc3, 0x9d, 0xc2, 0xef, 0x01, 0x43, 0xfe, 0xbd, 0x36, 0x01, + 0x95, 0xfe, 0x6b, 0x00, 0x00, 0x01, 0x00, 0x3c, 0xff, 0x40, 0x02, 0x1c, + 0xff, 0xb9, 0x00, 0x03, 0x00, 0x17, 0xba, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x05, 0x11, 0x12, 0x39, 0x00, 0xbb, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x00, + 0x00, 0x04, 0x2b, 0x30, 0x31, 0x17, 0x35, 0x21, 0x15, 0x3c, 0x01, 0xe0, + 0xc0, 0x79, 0x79, 0x00, 0x00, 0x01, 0x00, 0x96, 0x02, 0x3a, 0x01, 0x74, + 0x03, 0x27, 0x00, 0x03, 0x00, 0x2c, 0xba, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x05, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x03, 0x2f, 0x41, 0x03, 0x00, + 0x4f, 0x00, 0x03, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0x2f, 0x00, 0x03, + 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x01, 0x5d, + 0x30, 0x31, 0x13, 0x37, 0x17, 0x07, 0x96, 0x7b, 0x63, 0x58, 0x02, 0xea, + 0x3d, 0xc2, 0x2b, 0x00, 0x00, 0x02, 0x00, 0x34, 0xff, 0xf4, 0x02, 0x3c, + 0x02, 0x10, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x88, 0xba, 0x00, 0x19, 0x00, + 0x2b, 0x00, 0x2c, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x19, 0x10, 0xb8, 0x00, + 0x25, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x19, 0x2f, + 0x1b, 0xb9, 0x00, 0x19, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, 0x11, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, + 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x07, 0x10, 0xb9, 0x00, + 0x20, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x19, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0d, 0x2f, 0xb9, 0x00, 0x25, 0x00, 0x01, 0xf4, + 0xba, 0x00, 0x04, 0x00, 0x20, 0x00, 0x25, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x04, 0x2f, 0xb8, 0x00, 0x19, 0x10, 0xb9, 0x00, 0x12, 0x00, 0x09, 0xf4, + 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x1d, 0x00, 0x09, 0xf4, 0x30, 0x31, + 0x21, 0x22, 0x26, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, + 0x36, 0x3b, 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, + 0x01, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x33, 0x15, 0x25, 0x32, 0x36, 0x3d, + 0x01, 0x23, 0x22, 0x1d, 0x01, 0x14, 0x16, 0x01, 0xe7, 0x2e, 0x38, 0x05, + 0x05, 0x0e, 0x53, 0x3c, 0x4b, 0x5b, 0x76, 0x72, 0x53, 0x2b, 0x33, 0x2f, + 0x3a, 0x15, 0x51, 0x1a, 0x6f, 0x57, 0x6a, 0x77, 0x39, 0xfe, 0xd6, 0x27, + 0x36, 0x4f, 0x5b, 0x2a, 0x2f, 0x2c, 0x33, 0x34, 0x51, 0x49, 0x51, 0x4e, + 0x1a, 0x2e, 0x2f, 0x24, 0x1d, 0x48, 0x2c, 0x39, 0x61, 0x62, 0xe2, 0x6b, + 0x55, 0x26, 0x24, 0x3e, 0x3d, 0x14, 0x1b, 0x1c, 0x00, 0x02, 0x00, 0x3b, + 0xff, 0xf4, 0x02, 0x31, 0x02, 0xe4, 0x00, 0x16, 0x00, 0x24, 0x00, 0x81, + 0xba, 0x00, 0x17, 0x00, 0x25, 0x00, 0x26, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x17, 0x10, 0xb8, 0x00, 0x10, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x21, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, + 0x06, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x15, 0x2f, 0x1b, 0xb9, 0x00, 0x15, 0x00, + 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x1e, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x06, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x10, 0x10, 0xb9, 0x00, 0x17, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x13, + 0x00, 0x17, 0x00, 0x10, 0x11, 0x12, 0x39, 0x30, 0x31, 0x13, 0x33, 0x11, + 0x33, 0x3e, 0x01, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x23, + 0x22, 0x26, 0x27, 0x23, 0x15, 0x23, 0x37, 0x32, 0x36, 0x3d, 0x01, 0x34, + 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x3b, 0x94, 0x07, 0x13, + 0x48, 0x3e, 0x2b, 0x47, 0x33, 0x1d, 0x1d, 0x33, 0x47, 0x2b, 0x3e, 0x48, + 0x13, 0x07, 0x94, 0xf4, 0x32, 0x36, 0x36, 0x32, 0x27, 0x39, 0x39, 0x02, + 0xe4, 0xfe, 0xc2, 0x2e, 0x3c, 0x20, 0x42, 0x66, 0x46, 0x46, 0x66, 0x42, + 0x20, 0x3b, 0x2f, 0x5e, 0x67, 0x3d, 0x36, 0x50, 0x36, 0x3d, 0x26, 0x29, + 0x98, 0x29, 0x26, 0x00, 0x00, 0x01, 0x00, 0x3c, 0xff, 0xf4, 0x02, 0x1f, + 0x02, 0x10, 0x00, 0x1e, 0x00, 0x43, 0xba, 0x00, 0x11, 0x00, 0x1f, 0x00, + 0x20, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x09, + 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x18, 0x00, 0x09, 0xf4, 0x30, + 0x31, 0x05, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, + 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x33, + 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, 0x01, 0x41, 0x3d, 0x61, 0x43, 0x24, + 0x24, 0x43, 0x61, 0x3c, 0x55, 0x67, 0x1b, 0x72, 0x0e, 0x2d, 0x2a, 0x33, + 0x37, 0x37, 0x35, 0x2b, 0x31, 0x11, 0x70, 0x1c, 0x6b, 0x0c, 0x25, 0x46, + 0x64, 0x3f, 0x3f, 0x64, 0x46, 0x25, 0x45, 0x39, 0x3e, 0x1e, 0x28, 0x3b, + 0x33, 0x54, 0x33, 0x3b, 0x28, 0x20, 0x40, 0x39, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x27, 0xff, 0xf4, 0x02, 0x1d, 0x02, 0xe4, 0x00, 0x18, + 0x00, 0x26, 0x00, 0x81, 0xba, 0x00, 0x19, 0x00, 0x27, 0x00, 0x28, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x19, 0x10, 0xb8, 0x00, 0x04, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x16, 0x2f, 0x1b, 0xb9, 0x00, 0x16, + 0x00, 0x21, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, + 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x11, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x18, 0x2f, 0x1b, + 0xb9, 0x00, 0x18, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x04, 0x10, 0xb9, + 0x00, 0x19, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x01, 0x00, 0x19, 0x00, 0x04, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0e, 0x10, 0xb9, 0x00, 0x20, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x13, 0x00, 0x20, 0x00, 0x0e, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x25, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, + 0x02, 0x33, 0x32, 0x1e, 0x02, 0x17, 0x33, 0x11, 0x33, 0x11, 0x23, 0x27, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0x01, 0x89, 0x07, 0x14, 0x47, 0x3e, 0x2b, 0x47, 0x33, 0x1d, 0x1d, + 0x33, 0x47, 0x2b, 0x1f, 0x30, 0x25, 0x1b, 0x0a, 0x07, 0x94, 0x94, 0x60, + 0x27, 0x39, 0x39, 0x27, 0x32, 0x36, 0x36, 0x5e, 0x2f, 0x3b, 0x20, 0x42, + 0x66, 0x46, 0x46, 0x66, 0x42, 0x20, 0x10, 0x1c, 0x27, 0x17, 0x01, 0x3e, + 0xfd, 0x1c, 0x67, 0x26, 0x29, 0x98, 0x29, 0x26, 0x3d, 0x36, 0x50, 0x36, + 0x3d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x32, 0xff, 0xf4, 0x02, 0x26, + 0x02, 0x10, 0x00, 0x19, 0x00, 0x22, 0x00, 0x74, 0xba, 0x00, 0x08, 0x00, + 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x08, 0x10, 0xb8, 0x00, + 0x1a, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, + 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, + 0x59, 0xb9, 0x00, 0x13, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x08, 0x10, 0xb9, + 0x00, 0x1a, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x1a, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0f, 0x2f, 0x41, 0x03, 0x00, 0x50, 0x00, + 0x0f, 0x00, 0x01, 0x71, 0xb8, 0x00, 0x0e, 0xd0, 0xb8, 0x00, 0x16, 0xd0, + 0xb8, 0x00, 0x16, 0x2f, 0xb8, 0x00, 0x0f, 0x10, 0xb9, 0x00, 0x1e, 0x00, + 0x01, 0xf4, 0x30, 0x31, 0x05, 0x22, 0x26, 0x35, 0x34, 0x3e, 0x02, 0x33, + 0x32, 0x1e, 0x02, 0x1d, 0x01, 0x21, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, + 0x37, 0x17, 0x0e, 0x01, 0x03, 0x22, 0x06, 0x1d, 0x01, 0x33, 0x35, 0x34, + 0x26, 0x01, 0x3a, 0x82, 0x86, 0x23, 0x41, 0x5d, 0x3a, 0x3a, 0x5c, 0x40, + 0x23, 0xfe, 0x9f, 0x3e, 0x3c, 0x2e, 0x42, 0x18, 0x50, 0x1e, 0x6c, 0x5f, + 0x30, 0x39, 0xd0, 0x37, 0x0c, 0x90, 0x7c, 0x3f, 0x65, 0x47, 0x25, 0x25, + 0x44, 0x61, 0x3c, 0x2c, 0x09, 0x32, 0x3d, 0x23, 0x1d, 0x57, 0x25, 0x36, + 0x01, 0xb2, 0x3b, 0x32, 0x08, 0x08, 0x33, 0x3a, 0x00, 0x01, 0x00, 0x3d, + 0x00, 0x00, 0x02, 0x2c, 0x02, 0xe4, 0x00, 0x14, 0x00, 0x72, 0xba, 0x00, + 0x11, 0x00, 0x15, 0x00, 0x16, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x21, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, + 0xb9, 0x00, 0x04, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x14, 0x2f, 0x1b, 0xb9, 0x00, 0x14, 0x00, 0x11, 0x3e, 0x59, + 0xb9, 0x00, 0x00, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, + 0x03, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x09, 0x10, 0xb9, 0x00, 0x0c, 0x00, + 0x09, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, 0x0d, 0xd0, 0xb8, 0x00, + 0x03, 0x10, 0xb8, 0x00, 0x10, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, + 0x11, 0xd0, 0x30, 0x31, 0x37, 0x33, 0x11, 0x23, 0x35, 0x33, 0x35, 0x34, + 0x36, 0x3b, 0x01, 0x15, 0x23, 0x15, 0x33, 0x15, 0x23, 0x11, 0x33, 0x15, + 0x21, 0x47, 0x98, 0xa2, 0xa2, 0x4d, 0x51, 0xaf, 0xb9, 0xb9, 0xb9, 0xa2, + 0xfe, 0x32, 0x73, 0x01, 0x1e, 0x73, 0x4b, 0x42, 0x53, 0x73, 0x6d, 0x73, + 0xfe, 0xe2, 0x73, 0x00, 0x00, 0x03, 0x00, 0x2f, 0xff, 0x2c, 0x02, 0x47, + 0x02, 0x67, 0x00, 0x3d, 0x00, 0x4a, 0x00, 0x58, 0x00, 0xcb, 0xba, 0x00, + 0x03, 0x00, 0x59, 0x00, 0x5a, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x03, 0x10, + 0xb8, 0x00, 0x47, 0xd0, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x4b, 0xd0, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1b, 0x2f, 0x1b, 0xb9, + 0x00, 0x1b, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x23, 0x2f, 0x1b, 0xb9, 0x00, 0x23, 0x00, 0x1d, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x03, 0x2f, 0x1b, 0xb9, 0x00, 0x03, + 0x00, 0x13, 0x3e, 0x59, 0xb8, 0x00, 0x23, 0x10, 0xb9, 0x00, 0x22, 0x00, + 0x09, 0xf4, 0xba, 0x00, 0x2d, 0x00, 0x03, 0x00, 0x1b, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x2d, 0x2f, 0x41, 0x03, 0x00, 0x70, 0x00, 0x2d, 0x00, 0x01, + 0x71, 0x41, 0x03, 0x00, 0xd0, 0x00, 0x2d, 0x00, 0x01, 0x5d, 0xb8, 0x00, + 0x03, 0x10, 0xb9, 0x00, 0x48, 0x00, 0x09, 0xf4, 0x41, 0x03, 0x00, 0xd0, + 0x00, 0x48, 0x00, 0x01, 0x5d, 0xba, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x48, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x39, 0x2f, 0x41, 0x05, 0x00, 0x6f, 0x00, + 0x39, 0x00, 0x7f, 0x00, 0x39, 0x00, 0x02, 0x71, 0xb9, 0x00, 0x41, 0x00, + 0x0d, 0xf4, 0x41, 0x03, 0x00, 0xc0, 0x00, 0x41, 0x00, 0x01, 0x5d, 0xb8, + 0x00, 0x2d, 0x10, 0xb9, 0x00, 0x4b, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x1b, + 0x10, 0xb9, 0x00, 0x52, 0x00, 0x09, 0xf4, 0x30, 0x31, 0x05, 0x14, 0x06, + 0x23, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x36, 0x37, 0x35, 0x2e, 0x01, 0x35, + 0x34, 0x36, 0x37, 0x35, 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, + 0x17, 0x35, 0x34, 0x36, 0x3b, 0x01, 0x15, 0x23, 0x15, 0x1e, 0x01, 0x15, + 0x14, 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x0e, 0x01, 0x15, 0x14, 0x1e, + 0x02, 0x3b, 0x01, 0x32, 0x1e, 0x02, 0x07, 0x34, 0x26, 0x2b, 0x01, 0x06, + 0x15, 0x14, 0x16, 0x3b, 0x01, 0x32, 0x36, 0x03, 0x32, 0x36, 0x3d, 0x01, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x02, 0x47, 0x8a, + 0x94, 0x4a, 0x60, 0x39, 0x17, 0x34, 0x2f, 0x21, 0x27, 0x33, 0x2a, 0x2e, + 0x33, 0x20, 0x3b, 0x52, 0x33, 0x31, 0x2a, 0x2a, 0x25, 0x5b, 0x7c, 0x2a, + 0x2f, 0x20, 0x3c, 0x53, 0x33, 0x17, 0x2a, 0x13, 0x0b, 0x0f, 0x0c, 0x15, + 0x1c, 0x0f, 0x76, 0x37, 0x4e, 0x32, 0x16, 0x8c, 0x20, 0x2d, 0xb1, 0x14, + 0x29, 0x31, 0x57, 0x33, 0x2e, 0x95, 0x2d, 0x29, 0x29, 0x2d, 0x2c, 0x28, + 0x28, 0x34, 0x52, 0x4e, 0x11, 0x20, 0x2c, 0x1a, 0x2c, 0x2d, 0x0c, 0x06, + 0x0a, 0x25, 0x22, 0x26, 0x24, 0x0a, 0x06, 0x16, 0x50, 0x39, 0x2d, 0x45, + 0x2e, 0x18, 0x0b, 0x1c, 0x1e, 0x28, 0x6c, 0x09, 0x16, 0x4d, 0x37, 0x2d, + 0x44, 0x2f, 0x18, 0x05, 0x05, 0x06, 0x12, 0x0e, 0x0c, 0x0e, 0x07, 0x02, + 0x16, 0x28, 0x36, 0x2c, 0x14, 0x17, 0x11, 0x19, 0x18, 0x1f, 0x1c, 0x01, + 0x57, 0x2c, 0x22, 0x18, 0x22, 0x2c, 0x2c, 0x22, 0x18, 0x22, 0x2c, 0x00, + 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x02, 0x1b, 0x02, 0xe4, 0x00, 0x19, + 0x00, 0x6b, 0xba, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x1b, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, + 0x00, 0x01, 0x00, 0x21, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1d, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x18, 0x2f, 0x1b, 0xb9, 0x00, 0x18, + 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, + 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x08, + 0x10, 0xb9, 0x00, 0x12, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x02, 0x00, 0x12, + 0x00, 0x08, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, 0x02, 0x2f, 0x18, 0x30, + 0x31, 0x13, 0x33, 0x11, 0x33, 0x3e, 0x03, 0x33, 0x32, 0x1e, 0x02, 0x15, + 0x11, 0x23, 0x11, 0x34, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x11, 0x23, 0x41, + 0x94, 0x06, 0x09, 0x1a, 0x25, 0x31, 0x1f, 0x25, 0x3e, 0x2c, 0x19, 0x94, + 0x57, 0x11, 0x21, 0x1a, 0x0f, 0x94, 0x02, 0xe4, 0xfe, 0xc2, 0x16, 0x26, + 0x1d, 0x11, 0x19, 0x32, 0x48, 0x2f, 0xfe, 0xb2, 0x01, 0x3a, 0x64, 0x09, + 0x13, 0x1c, 0x13, 0xfe, 0xad, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e, + 0x00, 0x00, 0x02, 0x2e, 0x02, 0xef, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x5f, + 0xba, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x0f, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x12, 0x2f, + 0x1b, 0xb9, 0x00, 0x12, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x17, 0x2f, 0x1b, 0xb9, 0x00, 0x17, 0x00, 0x11, 0x3e, + 0x59, 0xb8, 0x00, 0x12, 0x10, 0xb9, 0x00, 0x00, 0x00, 0x08, 0xf4, 0xb9, + 0x00, 0x07, 0x00, 0x07, 0xf4, 0xb8, 0x00, 0x17, 0x10, 0xb9, 0x00, 0x0e, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x12, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x09, + 0xf4, 0xb8, 0x00, 0x0e, 0x10, 0xb8, 0x00, 0x14, 0xd0, 0x30, 0x31, 0x01, + 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, + 0x06, 0x01, 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x01, + 0x4c, 0x32, 0x27, 0x27, 0x32, 0x32, 0x27, 0x27, 0xfe, 0xe0, 0xa4, 0xa4, + 0x01, 0x38, 0x98, 0xfe, 0x30, 0x02, 0x46, 0x29, 0x1d, 0x1d, 0x1e, 0x28, + 0x28, 0x1e, 0x1d, 0x1d, 0x29, 0xfe, 0x2d, 0x01, 0x1e, 0x73, 0xfe, 0x6f, + 0x73, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5a, 0xff, 0x38, 0x01, 0xc5, + 0x02, 0xef, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x57, 0xba, 0x00, 0x01, 0x00, + 0x19, 0x00, 0x1a, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, + 0x0e, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, + 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x13, 0x3e, + 0x59, 0xb9, 0x00, 0x00, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, + 0x00, 0x03, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x0b, + 0x00, 0x08, 0xf4, 0xb9, 0x00, 0x12, 0x00, 0x07, 0xf4, 0x30, 0x31, 0x17, + 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x14, 0x06, 0x2b, 0x01, 0x01, 0x22, + 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, + 0x5c, 0xc6, 0xc8, 0x01, 0x5c, 0x4e, 0x4f, 0xbd, 0x01, 0x10, 0x32, 0x27, + 0x27, 0x32, 0x31, 0x28, 0x28, 0x55, 0x01, 0xe6, 0x73, 0xfd, 0xc9, 0x41, + 0x54, 0x03, 0x0e, 0x29, 0x1d, 0x1d, 0x1e, 0x28, 0x28, 0x1e, 0x1d, 0x1d, + 0x29, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x02, 0x4c, + 0x02, 0xe4, 0x00, 0x0d, 0x00, 0x63, 0xba, 0x00, 0x04, 0x00, 0x0e, 0x00, + 0x0f, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x21, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, + 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0d, 0x2f, 0x1b, 0xb9, 0x00, 0x0d, 0x00, 0x11, 0x3e, + 0x59, 0xba, 0x00, 0x02, 0x00, 0x05, 0x00, 0x0d, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x02, 0x10, 0xb8, 0x00, 0x0b, 0xd0, 0x30, 0x31, 0x13, 0x33, 0x11, + 0x33, 0x3f, 0x01, 0x33, 0x07, 0x13, 0x23, 0x27, 0x07, 0x15, 0x23, 0x41, + 0x94, 0x07, 0x45, 0x6c, 0xaa, 0xc8, 0xdd, 0xb0, 0x96, 0x31, 0x94, 0x02, + 0xe4, 0xfe, 0x5c, 0x51, 0x73, 0xcc, 0xfe, 0xc8, 0xe4, 0x31, 0xb3, 0x00, + 0x00, 0x01, 0x00, 0x44, 0x00, 0x00, 0x02, 0x14, 0x02, 0xe4, 0x00, 0x09, + 0x00, 0x47, 0xba, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, + 0x00, 0x04, 0x00, 0x21, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x11, 0x3e, 0x59, 0xb9, + 0x00, 0x00, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x03, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x06, 0xd0, 0x30, + 0x31, 0x37, 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x44, + 0x9e, 0x9e, 0x01, 0x32, 0x9e, 0xfe, 0x30, 0x73, 0x01, 0xfe, 0x73, 0xfd, + 0x8f, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x02, 0x3a, + 0x02, 0x10, 0x00, 0x24, 0x00, 0xa7, 0xba, 0x00, 0x09, 0x00, 0x25, 0x00, + 0x26, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0f, 0x2f, + 0x1b, 0xb9, 0x00, 0x0f, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1c, 0x2f, 0x1b, 0xb9, + 0x00, 0x1c, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x11, 0x3e, 0x59, 0xb8, + 0x00, 0x07, 0x10, 0xb9, 0x00, 0x20, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x03, + 0x00, 0x20, 0x00, 0x07, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, 0x03, 0x2f, + 0x18, 0xb8, 0x00, 0x0f, 0x10, 0xb9, 0x00, 0x17, 0x00, 0x09, 0xf4, 0xba, + 0x00, 0x09, 0x00, 0x17, 0x00, 0x0f, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, + 0x09, 0x2f, 0x18, 0x30, 0x31, 0x33, 0x11, 0x33, 0x15, 0x33, 0x3e, 0x01, + 0x33, 0x32, 0x17, 0x33, 0x3e, 0x03, 0x33, 0x32, 0x15, 0x11, 0x23, 0x11, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, 0x23, 0x11, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x15, 0x11, 0x1e, 0x77, 0x07, 0x0c, 0x2d, 0x29, 0x4b, 0x11, + 0x06, 0x06, 0x12, 0x1a, 0x24, 0x18, 0x6c, 0x77, 0x19, 0x14, 0x13, 0x1b, + 0x78, 0x17, 0x14, 0x14, 0x1c, 0x02, 0x04, 0x4c, 0x24, 0x34, 0x58, 0x12, + 0x20, 0x18, 0x0e, 0x9f, 0xfe, 0x8f, 0x01, 0x62, 0x24, 0x1d, 0x19, 0x1a, + 0xfe, 0x90, 0x01, 0x62, 0x24, 0x1d, 0x19, 0x1a, 0xfe, 0x90, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x02, 0x1b, 0x02, 0x10, 0x00, 0x19, + 0x00, 0x6b, 0xba, 0x00, 0x13, 0x00, 0x1a, 0x00, 0x1b, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, + 0x00, 0x09, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, + 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x10, + 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x09, + 0x10, 0xb9, 0x00, 0x13, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x13, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, 0x03, 0x2f, 0x18, 0x30, + 0x31, 0x33, 0x11, 0x33, 0x15, 0x33, 0x3e, 0x03, 0x33, 0x32, 0x1e, 0x02, + 0x15, 0x11, 0x23, 0x11, 0x34, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x11, 0x41, + 0x94, 0x06, 0x09, 0x1a, 0x25, 0x31, 0x1f, 0x25, 0x3e, 0x2c, 0x19, 0x94, + 0x57, 0x11, 0x21, 0x1a, 0x0f, 0x02, 0x04, 0x5e, 0x16, 0x26, 0x1d, 0x11, + 0x19, 0x32, 0x48, 0x2f, 0xfe, 0xb2, 0x01, 0x3a, 0x64, 0x09, 0x13, 0x1c, + 0x13, 0xfe, 0xad, 0x00, 0x00, 0x02, 0x00, 0x29, 0xff, 0xf4, 0x02, 0x2f, + 0x02, 0x10, 0x00, 0x13, 0x00, 0x21, 0x00, 0x43, 0xba, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x23, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, + 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x14, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x1b, 0x00, 0x09, + 0xf4, 0x30, 0x31, 0x05, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, + 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, 0x01, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x2c, 0x3c, + 0x60, 0x43, 0x24, 0x24, 0x43, 0x60, 0x3c, 0x3c, 0x60, 0x43, 0x24, 0x24, + 0x43, 0x60, 0x3c, 0x32, 0x38, 0x38, 0x32, 0x32, 0x38, 0x38, 0x0c, 0x25, + 0x46, 0x64, 0x3f, 0x3f, 0x64, 0x46, 0x25, 0x25, 0x46, 0x64, 0x3f, 0x3f, + 0x64, 0x46, 0x25, 0x6e, 0x3e, 0x39, 0x52, 0x39, 0x3e, 0x3e, 0x39, 0x52, + 0x39, 0x3e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3b, 0xff, 0x38, 0x02, 0x31, + 0x02, 0x10, 0x00, 0x16, 0x00, 0x24, 0x00, 0x81, 0xba, 0x00, 0x17, 0x00, + 0x25, 0x00, 0x26, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x17, 0x10, 0xb8, 0x00, + 0x10, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1d, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x16, 0x2f, 0x1b, 0xb9, + 0x00, 0x16, 0x00, 0x13, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x11, 0x3e, 0x59, 0xb8, + 0x00, 0x06, 0x10, 0xb9, 0x00, 0x1e, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x02, + 0x00, 0x1e, 0x00, 0x06, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x10, 0x10, 0xb9, + 0x00, 0x17, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x14, 0x00, 0x17, 0x00, 0x10, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x13, 0x33, 0x15, 0x33, 0x3e, 0x01, 0x33, + 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x23, + 0x11, 0x23, 0x13, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x1d, 0x01, 0x14, 0x16, 0x3b, 0x94, 0x07, 0x13, 0x48, 0x3e, 0x2b, 0x47, + 0x33, 0x1d, 0x1d, 0x33, 0x47, 0x2b, 0x3e, 0x48, 0x13, 0x07, 0x94, 0xf4, + 0x32, 0x36, 0x36, 0x32, 0x27, 0x39, 0x39, 0x02, 0x04, 0x5e, 0x2e, 0x3c, + 0x20, 0x42, 0x66, 0x46, 0x46, 0x66, 0x42, 0x20, 0x3b, 0x2f, 0xfe, 0xda, + 0x01, 0x2f, 0x3d, 0x36, 0x50, 0x36, 0x3d, 0x26, 0x29, 0x98, 0x29, 0x26, + 0x00, 0x02, 0x00, 0x27, 0xff, 0x38, 0x02, 0x1d, 0x02, 0x10, 0x00, 0x18, + 0x00, 0x26, 0x00, 0x81, 0xba, 0x00, 0x19, 0x00, 0x27, 0x00, 0x28, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x19, 0x10, 0xb8, 0x00, 0x04, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x15, 0x2f, 0x1b, 0xb9, 0x00, 0x15, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, + 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x11, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x18, 0x2f, 0x1b, + 0xb9, 0x00, 0x18, 0x00, 0x13, 0x3e, 0x59, 0xb8, 0x00, 0x04, 0x10, 0xb9, + 0x00, 0x19, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x00, 0x00, 0x19, 0x00, 0x04, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0e, 0x10, 0xb9, 0x00, 0x20, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x14, 0x00, 0x20, 0x00, 0x0e, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x25, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, + 0x02, 0x33, 0x32, 0x1e, 0x02, 0x17, 0x33, 0x35, 0x33, 0x11, 0x23, 0x03, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0x01, 0x89, 0x07, 0x14, 0x47, 0x3e, 0x2b, 0x47, 0x33, 0x1d, 0x1d, + 0x33, 0x47, 0x2b, 0x1f, 0x30, 0x25, 0x1b, 0x0a, 0x07, 0x94, 0x94, 0x60, + 0x27, 0x39, 0x39, 0x27, 0x32, 0x36, 0x36, 0x5e, 0x2f, 0x3b, 0x20, 0x42, + 0x66, 0x46, 0x46, 0x66, 0x42, 0x20, 0x10, 0x1c, 0x27, 0x17, 0x5e, 0xfd, + 0x34, 0x01, 0x2f, 0x26, 0x29, 0x98, 0x29, 0x26, 0x3d, 0x36, 0x50, 0x36, + 0x3d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x4a, 0x00, 0x00, 0x02, 0x32, + 0x02, 0x04, 0x00, 0x16, 0x00, 0x72, 0xba, 0x00, 0x13, 0x00, 0x17, 0x00, + 0x18, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0c, 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x16, 0x2f, + 0x1b, 0xb9, 0x00, 0x16, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x00, 0x00, + 0x09, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x03, 0x00, 0x09, 0xf4, + 0xba, 0x00, 0x06, 0x00, 0x16, 0x00, 0x0c, 0x11, 0x12, 0x39, 0x7d, 0xb8, + 0x00, 0x06, 0x2f, 0x18, 0xb8, 0x00, 0x0c, 0x10, 0xb9, 0x00, 0x0f, 0x00, + 0x0d, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x13, 0xd0, 0x30, 0x31, + 0x37, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, 0x33, 0x3e, 0x03, 0x3b, 0x01, + 0x15, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x33, 0x15, 0x21, 0x4a, 0x77, 0x77, + 0x01, 0x0b, 0x07, 0x07, 0x19, 0x27, 0x38, 0x26, 0x31, 0x6e, 0x37, 0x38, + 0xaa, 0xfe, 0x4b, 0x73, 0x01, 0x1e, 0x73, 0x92, 0x1c, 0x35, 0x29, 0x18, + 0x88, 0x41, 0x2f, 0x99, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x31, + 0xff, 0xf4, 0x02, 0x16, 0x02, 0x10, 0x00, 0x2a, 0x00, 0x6f, 0xba, 0x00, + 0x07, 0x00, 0x2b, 0x00, 0x2c, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x16, 0x2f, 0x1b, 0xb9, 0x00, 0x16, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x16, 0x10, 0xb9, + 0x00, 0x1d, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x0e, 0x00, 0x1d, 0x00, 0x00, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x07, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x07, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x22, 0x00, 0x07, 0x00, 0x16, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x22, + 0x2f, 0xba, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x22, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x05, 0x22, 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, + 0x34, 0x26, 0x2f, 0x01, 0x2e, 0x03, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x15, 0x14, 0x16, 0x1f, 0x01, 0x1e, + 0x03, 0x15, 0x14, 0x06, 0x01, 0x26, 0x56, 0x7f, 0x20, 0x53, 0x1e, 0x51, + 0x34, 0x2c, 0x32, 0x22, 0x1e, 0x53, 0x23, 0x3c, 0x2c, 0x1a, 0x7c, 0x70, + 0x4c, 0x6b, 0x20, 0x4a, 0x17, 0x48, 0x33, 0x56, 0x22, 0x1e, 0x52, 0x23, + 0x3c, 0x2d, 0x1a, 0x7d, 0x0c, 0x34, 0x2d, 0x4d, 0x21, 0x25, 0x1b, 0x1c, + 0x16, 0x11, 0x05, 0x0d, 0x05, 0x15, 0x24, 0x34, 0x25, 0x51, 0x5c, 0x29, + 0x26, 0x54, 0x19, 0x22, 0x34, 0x17, 0x11, 0x05, 0x0d, 0x05, 0x15, 0x24, + 0x34, 0x25, 0x51, 0x5e, 0x00, 0x01, 0x00, 0x2a, 0x00, 0x00, 0x02, 0x13, + 0x02, 0xba, 0x00, 0x13, 0x00, 0x64, 0xba, 0x00, 0x11, 0x00, 0x14, 0x00, + 0x15, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x06, 0x10, + 0xb9, 0x00, 0x05, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x06, 0x10, 0xb8, 0x00, + 0x0d, 0xd0, 0xb8, 0x00, 0x05, 0x10, 0xb8, 0x00, 0x10, 0xd0, 0xb8, 0x00, + 0x00, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x09, 0xf4, 0x30, 0x31, 0x21, 0x22, + 0x26, 0x3d, 0x01, 0x23, 0x35, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x33, 0x15, + 0x33, 0x15, 0x23, 0x11, 0x33, 0x15, 0x01, 0x54, 0x50, 0x4e, 0x8c, 0x5b, + 0x21, 0x1c, 0x88, 0xc9, 0xc9, 0xc9, 0x54, 0x41, 0xfc, 0x73, 0x1a, 0x23, + 0x79, 0xb6, 0x73, 0xfe, 0xe2, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3d, + 0xff, 0xf4, 0x02, 0x17, 0x02, 0x04, 0x00, 0x17, 0x00, 0x69, 0xba, 0x00, + 0x0e, 0x00, 0x18, 0x00, 0x19, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x14, 0x2f, 0x1b, + 0xb9, 0x00, 0x14, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x11, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x17, 0x2f, 0x1b, 0xb9, 0x00, + 0x17, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x0e, + 0x00, 0x09, 0xf4, 0xba, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x04, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x00, 0x2f, 0x30, 0x31, 0x25, 0x23, 0x0e, 0x01, 0x23, + 0x22, 0x2e, 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x33, 0x32, 0x3e, 0x02, + 0x35, 0x11, 0x33, 0x11, 0x23, 0x01, 0x83, 0x06, 0x11, 0x49, 0x3e, 0x25, + 0x3e, 0x2c, 0x19, 0x94, 0x57, 0x11, 0x21, 0x19, 0x10, 0x94, 0x94, 0x5e, + 0x2c, 0x3e, 0x19, 0x32, 0x48, 0x2f, 0x01, 0x4e, 0xfe, 0xc6, 0x64, 0x09, + 0x13, 0x1c, 0x13, 0x01, 0x53, 0xfd, 0xfc, 0x00, 0x00, 0x01, 0x00, 0x1b, + 0x00, 0x00, 0x02, 0x3d, 0x02, 0x04, 0x00, 0x09, 0x00, 0x44, 0xba, 0x00, + 0x04, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, + 0xb9, 0x00, 0x08, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, + 0xb8, 0x00, 0x05, 0xd0, 0x30, 0x31, 0x33, 0x03, 0x33, 0x1f, 0x01, 0x33, + 0x3f, 0x01, 0x33, 0x03, 0xd4, 0xb9, 0x9c, 0x43, 0x31, 0x08, 0x31, 0x43, + 0x96, 0xb9, 0x02, 0x04, 0xdd, 0xac, 0xac, 0xdd, 0xfd, 0xfc, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x02, 0x51, 0x02, 0x04, 0x00, 0x0f, + 0x00, 0x7a, 0xba, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x11, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, + 0x00, 0x00, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1d, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0f, + 0x2f, 0x1b, 0xb9, 0x00, 0x0f, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x11, + 0x3e, 0x59, 0xb8, 0x00, 0x0f, 0x10, 0xb8, 0x00, 0x02, 0xd0, 0xb8, 0x00, + 0x02, 0x2f, 0xb8, 0x00, 0x06, 0xd0, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, + 0x0d, 0xd0, 0x30, 0x31, 0x13, 0x33, 0x13, 0x33, 0x13, 0x33, 0x13, 0x33, + 0x13, 0x33, 0x03, 0x23, 0x03, 0x23, 0x03, 0x23, 0x07, 0x7b, 0x25, 0x0a, + 0x3d, 0x82, 0x3c, 0x0a, 0x26, 0x75, 0x3d, 0xb0, 0x33, 0x0a, 0x33, 0xb0, + 0x02, 0x04, 0xfe, 0x5e, 0x01, 0xa2, 0xfe, 0x5e, 0x01, 0xa2, 0xfd, 0xfc, + 0x01, 0x64, 0xfe, 0x9c, 0x00, 0x01, 0x00, 0x17, 0x00, 0x00, 0x02, 0x41, + 0x02, 0x04, 0x00, 0x11, 0x00, 0x77, 0xba, 0x00, 0x05, 0x00, 0x12, 0x00, + 0x13, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x02, 0x2f, 0x1b, 0xb9, 0x00, 0x02, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0c, 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, 0x11, 0x3e, + 0x59, 0xba, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x0e, 0x00, 0x08, 0x00, 0x0c, 0x11, 0x12, 0x39, 0xba, 0x00, 0x01, + 0x00, 0x05, 0x00, 0x0e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x01, 0x10, 0xb8, + 0x00, 0x0a, 0xd0, 0x30, 0x31, 0x33, 0x13, 0x27, 0x33, 0x1f, 0x01, 0x33, + 0x3f, 0x01, 0x33, 0x07, 0x13, 0x23, 0x2f, 0x01, 0x23, 0x0f, 0x01, 0x17, + 0xc1, 0xb4, 0xa9, 0x37, 0x2a, 0x08, 0x2b, 0x38, 0x9b, 0xb4, 0xc1, 0xaa, + 0x41, 0x2d, 0x08, 0x2c, 0x42, 0x01, 0x06, 0xfe, 0x53, 0x43, 0x43, 0x53, + 0xf6, 0xfe, 0xf2, 0x61, 0x45, 0x45, 0x61, 0x00, 0x00, 0x01, 0x00, 0x13, + 0xff, 0x38, 0x02, 0x45, 0x02, 0x04, 0x00, 0x0f, 0x00, 0x58, 0xba, 0x00, + 0x0d, 0x00, 0x10, 0x00, 0x11, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x13, 0x3e, 0x59, + 0xb9, 0x00, 0x07, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x0d, 0x00, 0x0a, 0x00, + 0x06, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0d, 0x10, 0xb8, 0x00, 0x09, 0xd0, + 0x30, 0x31, 0x01, 0x33, 0x03, 0x0e, 0x01, 0x2b, 0x01, 0x35, 0x33, 0x37, + 0x03, 0x33, 0x1f, 0x01, 0x33, 0x37, 0x01, 0xae, 0x97, 0xf3, 0x17, 0x4c, + 0x42, 0x66, 0x7c, 0x20, 0xd0, 0x9f, 0x4b, 0x2f, 0x08, 0x2d, 0x02, 0x04, + 0xfd, 0xa9, 0x39, 0x3c, 0x73, 0x58, 0x02, 0x01, 0xd9, 0x96, 0x96, 0x00, + 0x00, 0x01, 0x00, 0x42, 0x00, 0x00, 0x02, 0x16, 0x02, 0x04, 0x00, 0x09, + 0x00, 0x53, 0xba, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, + 0x00, 0x04, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x11, 0x3e, 0x59, 0xb9, + 0x00, 0x08, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x03, + 0x00, 0x09, 0xf4, 0xba, 0x00, 0x01, 0x00, 0x08, 0x00, 0x03, 0x11, 0x12, + 0x39, 0xba, 0x00, 0x06, 0x00, 0x03, 0x00, 0x08, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x33, 0x35, 0x01, 0x21, 0x35, 0x21, 0x15, 0x01, 0x21, 0x15, 0x42, + 0x01, 0x1f, 0xfe, 0xeb, 0x01, 0xc0, 0xfe, 0xe1, 0x01, 0x29, 0x7b, 0x01, + 0x16, 0x73, 0x7b, 0xfe, 0xea, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5c, + 0xff, 0x76, 0x01, 0xfc, 0x02, 0xf8, 0x00, 0x3b, 0x00, 0x47, 0xba, 0x00, + 0x2f, 0x00, 0x3c, 0x00, 0x3d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x21, + 0x2f, 0xb8, 0x00, 0x00, 0x2f, 0xb8, 0x00, 0x21, 0x10, 0xb9, 0x00, 0x24, + 0x00, 0x09, 0xf4, 0xba, 0x00, 0x0f, 0x00, 0x24, 0x00, 0x00, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x0f, 0x2f, 0xb9, 0x00, 0x12, 0x00, 0x09, 0xf4, 0xba, + 0x00, 0x2e, 0x00, 0x12, 0x00, 0x0f, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, + 0x10, 0xb9, 0x00, 0x39, 0x00, 0x09, 0xf4, 0x30, 0x31, 0x05, 0x22, 0x26, + 0x3d, 0x01, 0x34, 0x3e, 0x02, 0x37, 0x3e, 0x01, 0x35, 0x34, 0x26, 0x2b, + 0x01, 0x35, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x27, 0x2e, 0x03, 0x3d, + 0x01, 0x34, 0x36, 0x3b, 0x01, 0x15, 0x23, 0x15, 0x14, 0x16, 0x17, 0x1e, + 0x01, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x07, + 0x0e, 0x01, 0x1d, 0x01, 0x33, 0x15, 0x01, 0x4a, 0x44, 0x3a, 0x0b, 0x10, + 0x14, 0x09, 0x11, 0x0d, 0x36, 0x36, 0x5a, 0x5a, 0x36, 0x36, 0x0d, 0x11, + 0x09, 0x14, 0x10, 0x0b, 0x3a, 0x44, 0xb2, 0xb9, 0x19, 0x0f, 0x11, 0x1e, + 0x3a, 0x3c, 0x3c, 0x3a, 0x1e, 0x11, 0x0f, 0x19, 0xb9, 0x8a, 0x3d, 0x2f, + 0x2d, 0x19, 0x26, 0x1e, 0x17, 0x0b, 0x14, 0x1d, 0x10, 0x1a, 0x1c, 0x64, + 0x1c, 0x1a, 0x10, 0x1d, 0x14, 0x0a, 0x18, 0x1e, 0x26, 0x19, 0x2d, 0x2f, + 0x3d, 0x63, 0x30, 0x26, 0x28, 0x14, 0x15, 0x30, 0x20, 0x2a, 0x32, 0x07, + 0x08, 0x07, 0x32, 0x2a, 0x20, 0x30, 0x15, 0x14, 0x28, 0x26, 0x30, 0x63, + 0x00, 0x01, 0x00, 0xed, 0xff, 0x76, 0x01, 0x6b, 0x02, 0xf8, 0x00, 0x03, + 0x00, 0x15, 0xba, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x01, 0x2f, 0xb8, 0x00, 0x00, 0x2f, 0x30, 0x31, 0x17, + 0x11, 0x33, 0x11, 0xed, 0x7e, 0x8a, 0x03, 0x82, 0xfc, 0x7e, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x5c, 0xff, 0x76, 0x01, 0xfc, 0x02, 0xf8, 0x00, 0x3b, + 0x00, 0x47, 0xba, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x3d, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x3b, 0x2f, 0xb8, 0x00, 0x22, 0x2f, 0xb8, 0x00, 0x3b, + 0x10, 0xb9, 0x00, 0x3a, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x12, 0x00, 0x3a, + 0x00, 0x22, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x12, 0x2f, 0xb9, 0x00, 0x0f, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x22, 0x10, 0xb9, 0x00, 0x23, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x2e, 0x00, 0x0f, 0x00, 0x12, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x01, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x0e, 0x02, 0x07, 0x0e, 0x01, + 0x15, 0x14, 0x16, 0x3b, 0x01, 0x15, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, + 0x17, 0x1e, 0x03, 0x1d, 0x01, 0x14, 0x06, 0x2b, 0x01, 0x35, 0x33, 0x35, + 0x34, 0x26, 0x27, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, 0x35, 0x2e, 0x01, + 0x35, 0x34, 0x36, 0x37, 0x3e, 0x01, 0x3d, 0x01, 0x23, 0x35, 0x01, 0x0e, + 0x44, 0x3a, 0x0b, 0x10, 0x14, 0x09, 0x11, 0x0d, 0x36, 0x36, 0x5a, 0x5a, + 0x36, 0x36, 0x0d, 0x11, 0x09, 0x14, 0x10, 0x0b, 0x3a, 0x44, 0xb2, 0xb9, + 0x19, 0x0f, 0x11, 0x1e, 0x3a, 0x3c, 0x3c, 0x3a, 0x1e, 0x11, 0x0f, 0x19, + 0xb9, 0x02, 0xf8, 0x3d, 0x2f, 0x2d, 0x19, 0x26, 0x1e, 0x18, 0x0a, 0x14, + 0x1d, 0x10, 0x1a, 0x1c, 0x64, 0x1c, 0x1a, 0x10, 0x1d, 0x14, 0x0b, 0x17, + 0x1e, 0x26, 0x19, 0x2d, 0x2f, 0x3d, 0x63, 0x30, 0x26, 0x28, 0x14, 0x15, + 0x30, 0x20, 0x2a, 0x32, 0x07, 0x08, 0x07, 0x32, 0x2a, 0x20, 0x30, 0x15, + 0x14, 0x28, 0x26, 0x30, 0x63, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x24, + 0x00, 0xad, 0x02, 0x34, 0x01, 0xb4, 0x00, 0x19, 0x00, 0x49, 0xba, 0x00, + 0x03, 0x00, 0x1a, 0x00, 0x1b, 0x11, 0x12, 0x39, 0x00, 0xbb, 0x00, 0x06, + 0x00, 0x09, 0x00, 0x0d, 0x00, 0x04, 0x2b, 0xb8, 0x00, 0x06, 0x10, 0xb8, + 0x00, 0x00, 0xdc, 0xba, 0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x11, 0x12, + 0x39, 0x7d, 0xb8, 0x00, 0x09, 0x2f, 0x18, 0xb8, 0x00, 0x00, 0x10, 0xb9, + 0x00, 0x13, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x13, + 0x11, 0x12, 0x39, 0x7c, 0xb8, 0x00, 0x16, 0x2f, 0x18, 0x30, 0x31, 0x25, + 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, + 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, + 0x01, 0x01, 0x88, 0x29, 0x3c, 0x1b, 0x14, 0x1a, 0x11, 0x19, 0x19, 0x09, + 0x6a, 0x10, 0x55, 0x47, 0x29, 0x3c, 0x1b, 0x14, 0x1a, 0x11, 0x19, 0x19, + 0x09, 0x6a, 0x10, 0x55, 0xad, 0x26, 0x26, 0x1e, 0x22, 0x44, 0x3c, 0x14, + 0x7a, 0x6d, 0x26, 0x26, 0x1e, 0x22, 0x44, 0x3c, 0x14, 0x7a, 0x6d, 0x00, + 0x00, 0x02, 0x00, 0xca, 0xff, 0x4a, 0x01, 0x8e, 0x02, 0x10, 0x00, 0x05, + 0x00, 0x13, 0x00, 0x32, 0xba, 0x00, 0x06, 0x00, 0x14, 0x00, 0x15, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x06, 0x10, 0xb8, 0x00, 0x02, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0d, 0x2f, 0x1b, 0xb9, 0x00, 0x0d, + 0x00, 0x1d, 0x3e, 0x59, 0xb9, 0x00, 0x06, 0x00, 0x0a, 0xf4, 0xb9, 0x00, + 0x03, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x17, 0x35, 0x37, 0x33, 0x17, 0x15, + 0x03, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, + 0x14, 0x06, 0xdb, 0x39, 0x30, 0x39, 0x51, 0x35, 0x2d, 0x2c, 0x36, 0x36, + 0x2c, 0x2d, 0xb6, 0xcb, 0xfc, 0xfc, 0xcb, 0x02, 0x0b, 0x2d, 0x20, 0x20, + 0x20, 0x2e, 0x2e, 0x20, 0x20, 0x20, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x3c, + 0xff, 0x8e, 0x02, 0x1f, 0x02, 0x76, 0x00, 0x1a, 0x00, 0x22, 0x00, 0x73, + 0xba, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x1e, 0x10, 0xb8, 0x00, 0x01, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, 0x1d, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, + 0x01, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, 0x09, + 0xdc, 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0xb8, 0x00, 0x07, + 0x10, 0xb9, 0x00, 0x1f, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x11, 0xd0, 0xb8, + 0x00, 0x01, 0x10, 0xb9, 0x00, 0x1e, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x12, + 0xd0, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x19, 0xd0, 0xb8, 0x00, 0x01, + 0x10, 0xb8, 0x00, 0x1a, 0xdc, 0x30, 0x31, 0x05, 0x35, 0x2e, 0x01, 0x35, + 0x34, 0x36, 0x37, 0x35, 0x33, 0x15, 0x1e, 0x01, 0x17, 0x07, 0x2e, 0x01, + 0x27, 0x11, 0x3e, 0x01, 0x37, 0x17, 0x0e, 0x01, 0x07, 0x15, 0x03, 0x14, + 0x16, 0x17, 0x11, 0x0e, 0x01, 0x15, 0x01, 0x02, 0x5e, 0x68, 0x68, 0x5e, + 0x72, 0x3e, 0x4e, 0x17, 0x6b, 0x0a, 0x20, 0x17, 0x1a, 0x25, 0x0c, 0x69, + 0x17, 0x54, 0x40, 0xaa, 0x21, 0x21, 0x20, 0x22, 0x72, 0x6c, 0x11, 0x8a, + 0x6d, 0x6d, 0x8a, 0x11, 0x6c, 0x6a, 0x0a, 0x40, 0x30, 0x3a, 0x15, 0x24, + 0x0a, 0xfe, 0xcd, 0x09, 0x25, 0x17, 0x3b, 0x30, 0x40, 0x0a, 0x6a, 0x01, + 0x4a, 0x27, 0x39, 0x0e, 0x01, 0x30, 0x0d, 0x39, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x2e, 0x00, 0x00, 0x02, 0x2f, 0x02, 0xc6, 0x00, 0x2a, + 0x00, 0x63, 0xba, 0x00, 0x22, 0x00, 0x2b, 0x00, 0x2c, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x11, 0x2f, 0x1b, 0xb9, + 0x00, 0x11, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, + 0x00, 0x11, 0x10, 0xb9, 0x00, 0x18, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x00, + 0x10, 0xb9, 0x00, 0x28, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x07, 0x00, 0x18, + 0x00, 0x28, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x07, 0x2f, 0xb9, 0x00, 0x08, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x1e, 0xd0, 0xb8, 0x00, 0x07, 0x10, 0xb8, + 0x00, 0x21, 0xd0, 0x30, 0x31, 0x33, 0x35, 0x3e, 0x01, 0x35, 0x34, 0x27, + 0x23, 0x35, 0x33, 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, + 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x17, 0x33, + 0x15, 0x23, 0x15, 0x14, 0x0e, 0x02, 0x07, 0x15, 0x21, 0x15, 0x45, 0x28, + 0x2d, 0x01, 0x6b, 0x47, 0x0c, 0x13, 0x24, 0x41, 0x5c, 0x38, 0x4c, 0x6e, + 0x26, 0x63, 0x17, 0x37, 0x2a, 0x2f, 0x36, 0x11, 0x0b, 0xaf, 0x8c, 0x0e, + 0x17, 0x1c, 0x0d, 0x01, 0x49, 0x88, 0x11, 0x3e, 0x2a, 0x08, 0x04, 0x6e, + 0x1c, 0x3d, 0x24, 0x2e, 0x4c, 0x36, 0x1e, 0x36, 0x33, 0x5d, 0x1e, 0x27, + 0x35, 0x30, 0x1c, 0x31, 0x18, 0x6e, 0x07, 0x1a, 0x28, 0x1e, 0x16, 0x07, + 0x09, 0x80, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2e, 0x00, 0x10, 0x02, 0x2a, + 0x02, 0xaa, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x95, 0xba, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x2f, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x20, 0xd0, 0x00, 0xb8, + 0x00, 0x10, 0x2f, 0x41, 0x03, 0x00, 0x20, 0x00, 0x10, 0x00, 0x01, 0x5d, + 0xba, 0x00, 0x00, 0x00, 0x10, 0x00, 0x2e, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x00, 0x2f, 0x41, 0x05, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, + 0x00, 0x02, 0x5d, 0xb8, 0x00, 0x10, 0x10, 0xb9, 0x00, 0x27, 0x00, 0x09, + 0xf4, 0xba, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x02, 0x10, 0xb8, 0x00, 0x05, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb9, + 0x00, 0x20, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x20, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0e, 0x10, 0xb8, 0x00, 0x0b, 0xd0, 0xba, + 0x00, 0x12, 0x00, 0x10, 0x00, 0x20, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x12, + 0x10, 0xb8, 0x00, 0x15, 0xd0, 0xba, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1e, 0x10, 0xb8, 0x00, 0x1b, 0xd0, 0x30, + 0x31, 0x25, 0x22, 0x27, 0x07, 0x27, 0x37, 0x2e, 0x01, 0x35, 0x34, 0x36, + 0x37, 0x27, 0x37, 0x17, 0x36, 0x33, 0x32, 0x17, 0x37, 0x17, 0x07, 0x1e, + 0x01, 0x15, 0x14, 0x06, 0x07, 0x17, 0x07, 0x27, 0x06, 0x27, 0x32, 0x36, + 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, + 0x2c, 0x31, 0x2a, 0x3e, 0x65, 0x42, 0x18, 0x1b, 0x1b, 0x18, 0x42, 0x65, + 0x3e, 0x2a, 0x31, 0x31, 0x2a, 0x3e, 0x65, 0x42, 0x18, 0x1b, 0x1b, 0x18, + 0x42, 0x65, 0x3e, 0x2a, 0x31, 0x2b, 0x30, 0x30, 0x2b, 0x2b, 0x30, 0x30, + 0x6b, 0x0e, 0x69, 0x3b, 0x70, 0x1f, 0x51, 0x32, 0x32, 0x51, 0x1f, 0x70, + 0x3b, 0x69, 0x0e, 0x0e, 0x69, 0x3b, 0x70, 0x1f, 0x51, 0x32, 0x32, 0x51, + 0x1f, 0x70, 0x3b, 0x69, 0x0e, 0x6b, 0x38, 0x33, 0x38, 0x33, 0x38, 0x38, + 0x33, 0x38, 0x33, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, + 0x02, 0xba, 0x00, 0x13, 0x00, 0x76, 0xba, 0x00, 0x08, 0x00, 0x14, 0x00, + 0x15, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, + 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x13, 0x2f, + 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x00, 0x00, + 0x09, 0xf4, 0xba, 0x00, 0x03, 0x00, 0x06, 0x00, 0x13, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x03, 0x10, 0xb9, 0x00, 0x04, 0x00, 0x09, 0xf4, 0xb8, 0x00, + 0x08, 0xd0, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, 0x0c, 0xd0, 0xb8, 0x00, + 0x03, 0x10, 0xb8, 0x00, 0x0f, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, + 0x10, 0xd0, 0x30, 0x31, 0x37, 0x33, 0x35, 0x23, 0x35, 0x33, 0x03, 0x33, + 0x13, 0x33, 0x13, 0x33, 0x03, 0x33, 0x15, 0x23, 0x15, 0x33, 0x15, 0x21, + 0x38, 0xad, 0xad, 0x68, 0xa0, 0x9c, 0x8d, 0x0a, 0x8e, 0x97, 0x9f, 0x67, + 0xad, 0xad, 0xfe, 0x18, 0x71, 0x6c, 0x71, 0x01, 0x6c, 0xfe, 0x94, 0x01, + 0x6c, 0xfe, 0x94, 0x71, 0x6c, 0x71, 0x00, 0x00, 0x00, 0x02, 0x00, 0xed, + 0xff, 0x76, 0x01, 0x6b, 0x02, 0xf8, 0x00, 0x03, 0x00, 0x07, 0x00, 0x25, + 0xba, 0x00, 0x04, 0x00, 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x04, 0x10, 0xb8, 0x00, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x01, 0x2f, 0xb8, + 0x00, 0x04, 0x2f, 0xba, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x2b, 0x30, + 0x31, 0x13, 0x11, 0x33, 0x11, 0x03, 0x11, 0x33, 0x11, 0xed, 0x7e, 0x7e, + 0x7e, 0x01, 0x91, 0x01, 0x67, 0xfe, 0x99, 0xfd, 0xe5, 0x01, 0x67, 0xfe, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x41, 0xff, 0x50, 0x02, 0x1e, + 0x02, 0xc6, 0x00, 0x3d, 0x00, 0x51, 0x00, 0x7a, 0xba, 0x00, 0x12, 0x00, + 0x52, 0x00, 0x53, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x12, 0x10, 0xb8, 0x00, + 0x4b, 0xd0, 0x00, 0xb8, 0x00, 0x05, 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x24, 0x2f, 0x1b, 0xb9, 0x00, 0x24, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x0c, 0x00, 0x09, 0xf4, 0xb8, 0x00, + 0x24, 0x10, 0xb9, 0x00, 0x2b, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x12, 0x00, + 0x2b, 0x00, 0x05, 0x11, 0x12, 0x39, 0xba, 0x00, 0x31, 0x00, 0x24, 0x00, + 0x0c, 0x11, 0x12, 0x39, 0xba, 0x00, 0x45, 0x00, 0x2b, 0x00, 0x05, 0x11, + 0x12, 0x39, 0xba, 0x00, 0x1c, 0x00, 0x31, 0x00, 0x45, 0x11, 0x12, 0x39, + 0xba, 0x00, 0x4f, 0x00, 0x24, 0x00, 0x0c, 0x11, 0x12, 0x39, 0xba, 0x00, + 0x3a, 0x00, 0x4f, 0x00, 0x12, 0x11, 0x12, 0x39, 0x30, 0x31, 0x25, 0x14, + 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, + 0x35, 0x34, 0x26, 0x2f, 0x01, 0x2e, 0x03, 0x35, 0x34, 0x36, 0x37, 0x35, + 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, 0x17, 0x07, 0x2e, + 0x01, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x1f, 0x01, 0x1e, 0x03, 0x15, + 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, 0x27, 0x34, 0x26, 0x2f, 0x01, 0x2e, + 0x01, 0x27, 0x0e, 0x01, 0x15, 0x14, 0x16, 0x1f, 0x01, 0x1e, 0x01, 0x17, + 0x3e, 0x01, 0x01, 0xff, 0x21, 0x3a, 0x52, 0x31, 0x34, 0x69, 0x2c, 0x49, + 0x1a, 0x41, 0x26, 0x2c, 0x34, 0x2b, 0x2e, 0x4e, 0x2b, 0x3b, 0x24, 0x10, + 0x35, 0x39, 0x2a, 0x25, 0x21, 0x3a, 0x52, 0x31, 0x34, 0x69, 0x2c, 0x49, + 0x1a, 0x41, 0x26, 0x2c, 0x34, 0x2b, 0x2e, 0x4e, 0x2b, 0x3b, 0x24, 0x10, + 0x35, 0x39, 0x2a, 0x25, 0x5c, 0x21, 0x32, 0x4d, 0x09, 0x10, 0x08, 0x12, + 0x14, 0x21, 0x32, 0x4d, 0x09, 0x10, 0x08, 0x12, 0x14, 0x03, 0x29, 0x42, + 0x2f, 0x19, 0x20, 0x28, 0x58, 0x1a, 0x1d, 0x25, 0x1f, 0x1b, 0x1f, 0x0c, + 0x15, 0x0c, 0x21, 0x27, 0x2c, 0x16, 0x2b, 0x47, 0x17, 0x10, 0x1a, 0x48, + 0x2a, 0x29, 0x42, 0x2f, 0x19, 0x20, 0x28, 0x58, 0x1a, 0x1d, 0x25, 0x1f, + 0x1b, 0x1f, 0x0c, 0x15, 0x0c, 0x21, 0x27, 0x2c, 0x16, 0x2b, 0x47, 0x17, + 0x10, 0x1a, 0x48, 0xcf, 0x1a, 0x2a, 0x0e, 0x15, 0x02, 0x06, 0x03, 0x14, + 0x29, 0x17, 0x1a, 0x2a, 0x0e, 0x15, 0x02, 0x06, 0x03, 0x14, 0x29, 0x00, + 0x00, 0x02, 0x00, 0x6e, 0x02, 0x4f, 0x01, 0xea, 0x02, 0xe6, 0x00, 0x0d, + 0x00, 0x1b, 0x00, 0x6c, 0xba, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x1d, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x10, 0xb8, 0x00, 0x11, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x2f, 0x41, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x5d, + 0x41, 0x03, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x01, 0x5d, 0xb9, 0x00, 0x07, 0x00, 0x07, 0xf4, + 0x41, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x07, 0x00, 0x20, + 0x00, 0x07, 0x00, 0x03, 0x5d, 0x41, 0x07, 0x00, 0x60, 0x00, 0x07, 0x00, + 0x70, 0x00, 0x07, 0x00, 0x80, 0x00, 0x07, 0x00, 0x03, 0x5d, 0xb8, 0x00, + 0x00, 0x10, 0xb8, 0x00, 0x0e, 0xd0, 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, + 0x15, 0xd0, 0x30, 0x31, 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, + 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0xbe, 0x2d, 0x23, 0x23, + 0x2d, 0x2d, 0x24, 0x24, 0xaf, 0x2d, 0x24, 0x24, 0x2d, 0x2d, 0x23, 0x23, + 0x02, 0x4f, 0x25, 0x1a, 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, + 0x25, 0x1a, 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x12, 0x02, 0x58, 0x02, 0xa8, 0x00, 0x13, + 0x00, 0x29, 0x00, 0x4a, 0x00, 0x6d, 0xba, 0x00, 0x00, 0x00, 0x4b, 0x00, + 0x4c, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, 0xb8, 0x00, 0x00, 0x10, + 0xb8, 0x00, 0x2a, 0xd0, 0x00, 0xb8, 0x00, 0x0a, 0x2f, 0xb8, 0x00, 0x00, + 0x2f, 0xb9, 0x00, 0x14, 0x00, 0x04, 0xf4, 0xb8, 0x00, 0x0a, 0x10, 0xb9, + 0x00, 0x1f, 0x00, 0x04, 0xf4, 0xb8, 0x00, 0x14, 0x10, 0xb8, 0x00, 0x2a, + 0xdc, 0xb8, 0x00, 0x1f, 0x10, 0xb8, 0x00, 0x34, 0xdc, 0xb9, 0x00, 0x3b, + 0x00, 0x01, 0xf4, 0xb8, 0x00, 0x2a, 0x10, 0xb9, 0x00, 0x42, 0x00, 0x01, + 0xf4, 0xba, 0x00, 0x38, 0x00, 0x3b, 0x00, 0x42, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x38, 0x2f, 0xba, 0x00, 0x45, 0x00, 0x3b, 0x00, 0x42, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x45, 0x2f, 0x30, 0x31, 0x25, 0x22, 0x2e, 0x02, 0x35, + 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, + 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, + 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x37, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, + 0x02, 0x33, 0x32, 0x16, 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x1d, + 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x03, 0x01, 0x2c, + 0x3f, 0x6d, 0x51, 0x2f, 0x2f, 0x51, 0x6d, 0x3f, 0x3f, 0x6d, 0x51, 0x2f, + 0x2f, 0x51, 0x6d, 0x3f, 0x33, 0x57, 0x3f, 0x24, 0x24, 0x3f, 0x57, 0x33, + 0x33, 0x57, 0x3f, 0x24, 0x24, 0x3f, 0x57, 0x3c, 0x2a, 0x44, 0x30, 0x1a, + 0x1b, 0x31, 0x43, 0x29, 0x3e, 0x4a, 0x12, 0x55, 0x0a, 0x1f, 0x1a, 0x1e, + 0x22, 0x22, 0x1f, 0x1c, 0x21, 0x0b, 0x55, 0x09, 0x1a, 0x27, 0x34, 0x12, + 0x2e, 0x56, 0x7a, 0x4d, 0x4c, 0x7b, 0x56, 0x2e, 0x2e, 0x56, 0x7b, 0x4c, + 0x4d, 0x7a, 0x56, 0x2e, 0x37, 0x26, 0x43, 0x5a, 0x33, 0x3c, 0x33, 0x5a, + 0x43, 0x26, 0x26, 0x43, 0x5a, 0x33, 0x3c, 0x33, 0x5a, 0x43, 0x26, 0x50, + 0x1c, 0x33, 0x48, 0x2c, 0x2d, 0x49, 0x33, 0x1c, 0x39, 0x2d, 0x2b, 0x17, + 0x1d, 0x25, 0x1d, 0x49, 0x1d, 0x26, 0x1e, 0x16, 0x2b, 0x14, 0x25, 0x1c, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x7d, 0x01, 0x4c, 0x01, 0xe9, + 0x02, 0xc6, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x88, 0xba, 0x00, 0x19, 0x00, + 0x2b, 0x00, 0x2c, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x19, 0x10, 0xb8, 0x00, + 0x20, 0xd0, 0x00, 0xb8, 0x00, 0x1f, 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x19, 0x2f, 0x1b, 0xb9, 0x00, 0x19, 0x00, 0x1f, 0x3e, 0x59, + 0x41, 0x03, 0x00, 0x7f, 0x00, 0x1f, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, + 0xff, 0x00, 0x1f, 0x00, 0x01, 0x5d, 0xb8, 0x00, 0x1f, 0x10, 0xb9, 0x00, + 0x1e, 0x00, 0x0c, 0xf4, 0xba, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x1f, 0x11, + 0x12, 0x39, 0xba, 0x00, 0x26, 0x00, 0x1e, 0x00, 0x1f, 0x11, 0x12, 0x39, + 0x7c, 0xb8, 0x00, 0x26, 0x2f, 0x18, 0xb9, 0x00, 0x07, 0x00, 0x0c, 0xf4, + 0xba, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x1e, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x0d, 0x2f, 0xb8, 0x00, 0x19, 0x10, 0xb9, 0x00, 0x12, 0x00, 0x0c, 0xf4, + 0xb8, 0x00, 0x0d, 0x10, 0xb9, 0x00, 0x20, 0x00, 0x04, 0xf4, 0x30, 0x31, + 0x01, 0x22, 0x26, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, + 0x36, 0x3b, 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, + 0x01, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x33, 0x15, 0x27, 0x22, 0x1d, 0x01, + 0x14, 0x16, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x01, 0xad, 0x20, 0x27, 0x03, + 0x04, 0x0a, 0x3a, 0x2a, 0x35, 0x3f, 0x53, 0x4f, 0x3a, 0x1e, 0x23, 0x21, + 0x29, 0x0f, 0x38, 0x12, 0x4e, 0x3d, 0x4a, 0x53, 0x28, 0xc7, 0x40, 0x1d, + 0x19, 0x1c, 0x25, 0x01, 0x54, 0x21, 0x1f, 0x23, 0x25, 0x39, 0x33, 0x39, + 0x36, 0x12, 0x20, 0x21, 0x19, 0x14, 0x32, 0x1f, 0x28, 0x44, 0x45, 0x9e, + 0x4b, 0x9b, 0x2b, 0x0e, 0x13, 0x13, 0x1a, 0x1a, 0x2b, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x3c, 0x00, 0x26, 0x02, 0x27, 0x01, 0xfa, 0x00, 0x06, + 0x00, 0x0d, 0x00, 0x00, 0x25, 0x27, 0x35, 0x37, 0x17, 0x07, 0x17, 0x05, + 0x27, 0x35, 0x37, 0x17, 0x07, 0x17, 0x01, 0xfa, 0xc8, 0xc8, 0x2d, 0x82, + 0x82, 0xfe, 0xdd, 0xc8, 0xc8, 0x2d, 0x82, 0x82, 0x26, 0xa8, 0x84, 0xa8, + 0x60, 0x8a, 0x8b, 0x5f, 0xa8, 0x84, 0xa8, 0x60, 0x8a, 0x8b, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x3e, 0x00, 0x36, 0x02, 0x0a, 0x01, 0x6c, 0x00, 0x05, + 0x00, 0x17, 0xba, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x11, 0x12, 0x39, + 0x00, 0xbb, 0x00, 0x03, 0x00, 0x09, 0x00, 0x02, 0x00, 0x04, 0x2b, 0x30, + 0x31, 0x25, 0x35, 0x21, 0x35, 0x21, 0x11, 0x01, 0x91, 0xfe, 0xad, 0x01, + 0xcc, 0x36, 0xc0, 0x76, 0xfe, 0xca, 0x00, 0x00, 0x00, 0x04, 0x00, 0x75, + 0x01, 0x5a, 0x01, 0xe3, 0x02, 0xc6, 0x00, 0x13, 0x00, 0x29, 0x00, 0x36, + 0x00, 0x3e, 0x00, 0xf2, 0xba, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x40, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, + 0x35, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x37, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, + 0x00, 0x1f, 0x3e, 0x59, 0xb9, 0x00, 0x1f, 0x00, 0x0b, 0xf4, 0xba, 0x00, + 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x11, 0x12, 0x39, 0x7c, 0xb8, 0x00, 0x2b, + 0x2f, 0x18, 0x41, 0x03, 0x00, 0x10, 0x00, 0x2b, 0x00, 0x01, 0x72, 0x41, + 0x03, 0x00, 0xa0, 0x00, 0x2b, 0x00, 0x01, 0x71, 0x41, 0x03, 0x00, 0x30, + 0x00, 0x2b, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0xf0, 0x00, 0x2b, 0x00, + 0x01, 0x5d, 0x41, 0x05, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x10, 0x00, 0x2b, + 0x00, 0x02, 0x71, 0x41, 0x09, 0x00, 0xa0, 0x00, 0x2b, 0x00, 0xb0, 0x00, + 0x2b, 0x00, 0xc0, 0x00, 0x2b, 0x00, 0xd0, 0x00, 0x2b, 0x00, 0x04, 0x5d, + 0xba, 0x00, 0x14, 0x00, 0x2b, 0x00, 0x3f, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x14, 0x2f, 0x41, 0x05, 0x00, 0x30, 0x00, 0x14, 0x00, 0x40, 0x00, 0x14, + 0x00, 0x02, 0x71, 0xb9, 0x00, 0x00, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x2c, + 0x00, 0x1f, 0x00, 0x14, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x2c, 0x2f, 0x41, + 0x03, 0x00, 0xbf, 0x00, 0x2c, 0x00, 0x01, 0x71, 0xb9, 0x00, 0x3d, 0x00, + 0x0b, 0xf4, 0xba, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x2b, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x3e, 0x2f, 0xb9, 0x00, 0x36, 0x00, 0x0b, 0xf4, 0xba, 0x00, + 0x32, 0x00, 0x3e, 0x00, 0x36, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x2b, 0x10, + 0xb8, 0x00, 0x34, 0xd0, 0x30, 0x31, 0x01, 0x22, 0x2e, 0x02, 0x35, 0x34, + 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, + 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, 0x1d, + 0x01, 0x14, 0x1e, 0x02, 0x37, 0x23, 0x35, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x07, 0x17, 0x23, 0x27, 0x23, 0x37, 0x32, 0x3d, 0x01, 0x34, 0x2b, 0x01, + 0x15, 0x01, 0x2c, 0x26, 0x43, 0x32, 0x1c, 0x1c, 0x32, 0x43, 0x26, 0x26, + 0x43, 0x31, 0x1d, 0x1d, 0x31, 0x43, 0x26, 0x1d, 0x31, 0x24, 0x15, 0x15, + 0x24, 0x31, 0x1d, 0x1d, 0x31, 0x24, 0x15, 0x15, 0x24, 0x31, 0x07, 0x38, + 0x5c, 0x26, 0x22, 0x22, 0x27, 0x3d, 0x1e, 0x16, 0x18, 0x1a, 0x1a, 0x18, + 0x01, 0x5a, 0x1c, 0x30, 0x43, 0x27, 0x27, 0x43, 0x30, 0x1c, 0x1c, 0x30, + 0x43, 0x27, 0x27, 0x43, 0x30, 0x1c, 0x29, 0x13, 0x22, 0x30, 0x1e, 0x14, + 0x1e, 0x30, 0x22, 0x13, 0x13, 0x22, 0x30, 0x1e, 0x14, 0x1e, 0x30, 0x22, + 0x13, 0x31, 0xb9, 0x24, 0x1b, 0x29, 0x10, 0x41, 0x36, 0x29, 0x14, 0x07, + 0x14, 0x2f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x93, 0x02, 0x67, 0x01, 0xc5, + 0x02, 0xce, 0x00, 0x03, 0x00, 0x17, 0xba, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x05, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x03, 0x2f, 0xb9, 0x00, 0x00, + 0x00, 0x06, 0xf4, 0x30, 0x31, 0x13, 0x21, 0x15, 0x21, 0x93, 0x01, 0x32, + 0xfe, 0xce, 0x02, 0xce, 0x67, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, + 0x01, 0x4e, 0x01, 0xe8, 0x02, 0xc6, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x3a, + 0xba, 0x00, 0x00, 0x00, 0x20, 0x00, 0x21, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x14, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x14, 0x00, 0x0c, 0xf4, 0xb8, 0x00, + 0x0a, 0x10, 0xb9, 0x00, 0x1a, 0x00, 0x0c, 0xf4, 0x30, 0x31, 0x01, 0x22, + 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, + 0x0e, 0x02, 0x27, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, + 0x14, 0x16, 0x01, 0x2c, 0x28, 0x44, 0x33, 0x1d, 0x1d, 0x33, 0x44, 0x28, + 0x28, 0x44, 0x33, 0x1d, 0x1d, 0x33, 0x44, 0x28, 0x27, 0x2f, 0x2f, 0x27, + 0x27, 0x2f, 0x2f, 0x01, 0x4e, 0x1d, 0x32, 0x45, 0x28, 0x28, 0x45, 0x32, + 0x1d, 0x1d, 0x32, 0x45, 0x28, 0x28, 0x45, 0x32, 0x1d, 0x5f, 0x36, 0x27, + 0x27, 0x36, 0x36, 0x27, 0x27, 0x36, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, + 0x00, 0x00, 0x02, 0x1a, 0x02, 0x7a, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x43, + 0xba, 0x00, 0x00, 0x00, 0x10, 0x00, 0x11, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x0c, 0xd0, 0x00, 0xbb, 0x00, 0x03, 0x00, 0x09, 0x00, 0x02, 0x00, 0x04, + 0x2b, 0xbb, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x04, 0x2b, 0xba, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, + 0x2f, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x07, 0xd0, 0xb8, 0x00, 0x02, + 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0x30, 0x31, 0x37, 0x35, 0x23, 0x35, 0x33, + 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x05, 0x35, 0x21, 0x15, 0xec, + 0xae, 0xae, 0x80, 0xae, 0xae, 0xfe, 0xd2, 0x01, 0xdc, 0xb8, 0xa6, 0x76, + 0xa6, 0xa6, 0x76, 0xa6, 0xb8, 0x77, 0x77, 0x00, 0x00, 0x01, 0x00, 0x96, + 0x01, 0x49, 0x01, 0xc2, 0x02, 0xc0, 0x00, 0x1d, 0x00, 0x57, 0xba, 0x00, + 0x13, 0x00, 0x1e, 0x00, 0x1f, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, + 0xb9, 0x00, 0x01, 0x00, 0x15, 0x3e, 0x59, 0xb9, 0x00, 0x1c, 0x00, 0x0c, + 0xf4, 0xb8, 0x00, 0x02, 0xd0, 0xba, 0x00, 0x03, 0x00, 0x13, 0x00, 0x1c, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x13, 0x10, 0xb9, 0x00, 0x0c, 0x00, 0x0c, + 0xf4, 0xba, 0x00, 0x1b, 0x00, 0x0c, 0x00, 0x01, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x01, 0x21, 0x35, 0x37, 0x3e, 0x03, 0x3d, 0x01, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x14, 0x0e, + 0x02, 0x0f, 0x01, 0x33, 0x01, 0xc2, 0xfe, 0xdf, 0x76, 0x12, 0x16, 0x0d, + 0x05, 0x18, 0x13, 0x17, 0x1b, 0x05, 0x59, 0x0e, 0x4d, 0x3f, 0x42, 0x4c, + 0x12, 0x1f, 0x29, 0x18, 0x3b, 0xb1, 0x01, 0x49, 0x58, 0x5a, 0x0e, 0x13, + 0x11, 0x11, 0x09, 0x01, 0x11, 0x11, 0x19, 0x14, 0x21, 0x2a, 0x38, 0x40, + 0x31, 0x19, 0x2a, 0x24, 0x1e, 0x0d, 0x21, 0x00, 0x00, 0x01, 0x00, 0x8a, + 0x01, 0x43, 0x01, 0xc2, 0x02, 0xc0, 0x00, 0x2b, 0x00, 0x9f, 0xba, 0x00, + 0x0e, 0x00, 0x2c, 0x00, 0x2d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0e, 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1b, 0x2f, 0x1b, + 0xb9, 0x00, 0x1b, 0x00, 0x15, 0x3e, 0x59, 0xba, 0x00, 0x29, 0x00, 0x0e, + 0x00, 0x1b, 0x11, 0x12, 0x39, 0x7c, 0xb8, 0x00, 0x29, 0x2f, 0x18, 0x41, + 0x05, 0x00, 0x10, 0x00, 0x29, 0x00, 0x20, 0x00, 0x29, 0x00, 0x02, 0x71, + 0x41, 0x09, 0x00, 0xc0, 0x00, 0x29, 0x00, 0xd0, 0x00, 0x29, 0x00, 0xe0, + 0x00, 0x29, 0x00, 0xf0, 0x00, 0x29, 0x00, 0x04, 0x72, 0x41, 0x03, 0x00, + 0xe0, 0x00, 0x29, 0x00, 0x01, 0x5d, 0x41, 0x07, 0x00, 0x40, 0x00, 0x29, + 0x00, 0x50, 0x00, 0x29, 0x00, 0x60, 0x00, 0x29, 0x00, 0x03, 0x5d, 0xb9, + 0x00, 0x00, 0x00, 0x04, 0xf4, 0xb8, 0x00, 0x0e, 0x10, 0xb9, 0x00, 0x07, + 0x00, 0x0c, 0xf4, 0xba, 0x00, 0x15, 0x00, 0x00, 0x00, 0x29, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x1b, 0x10, 0xb9, 0x00, 0x22, 0x00, 0x0c, 0xf4, 0x30, + 0x31, 0x01, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, + 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, + 0x01, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x35, 0x01, 0x1d, 0x1b, + 0x18, 0x17, 0x16, 0x15, 0x2b, 0x10, 0x3e, 0x1a, 0x42, 0x35, 0x47, 0x4f, + 0x2d, 0x1f, 0x26, 0x2c, 0x57, 0x46, 0x41, 0x46, 0x14, 0x4c, 0x0b, 0x26, + 0x1e, 0x17, 0x1b, 0x22, 0x1b, 0x1f, 0x02, 0x2e, 0x12, 0x0d, 0x04, 0x0d, + 0x13, 0x16, 0x15, 0x3b, 0x1f, 0x20, 0x38, 0x2d, 0x23, 0x2a, 0x04, 0x04, + 0x06, 0x2c, 0x23, 0x33, 0x3b, 0x2c, 0x1f, 0x3a, 0x17, 0x1f, 0x13, 0x11, + 0x02, 0x14, 0x10, 0x52, 0x00, 0x01, 0x00, 0xe4, 0x02, 0x3a, 0x01, 0xc2, + 0x03, 0x27, 0x00, 0x03, 0x00, 0x2c, 0xba, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x05, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x2f, 0x41, 0x03, 0x00, + 0x4f, 0x00, 0x00, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0x2f, 0x00, 0x00, + 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x5d, + 0x30, 0x31, 0x01, 0x27, 0x37, 0x17, 0x01, 0x3c, 0x58, 0x63, 0x7b, 0x02, + 0x3a, 0x2b, 0xc2, 0x3d, 0x00, 0x01, 0x00, 0x41, 0xff, 0x38, 0x02, 0x17, + 0x02, 0x04, 0x00, 0x1b, 0x00, 0x82, 0xba, 0x00, 0x05, 0x00, 0x1c, 0x00, + 0x1d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, 0x2f, + 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x13, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x15, 0x2f, 0x1b, 0xb9, + 0x00, 0x15, 0x00, 0x11, 0x3e, 0x59, 0xb9, 0x00, 0x05, 0x00, 0x09, 0xf4, + 0xba, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x05, 0x11, 0x12, 0x39, 0x7c, 0xb8, + 0x00, 0x0f, 0x2f, 0x18, 0xba, 0x00, 0x18, 0x00, 0x05, 0x00, 0x15, 0x11, + 0x12, 0x39, 0x30, 0x31, 0x17, 0x11, 0x33, 0x11, 0x14, 0x33, 0x32, 0x3e, + 0x02, 0x35, 0x11, 0x33, 0x11, 0x23, 0x35, 0x23, 0x0e, 0x03, 0x23, 0x22, + 0x26, 0x27, 0x23, 0x17, 0x15, 0x41, 0x94, 0x55, 0x11, 0x20, 0x19, 0x0f, + 0x94, 0x94, 0x06, 0x06, 0x14, 0x1e, 0x26, 0x18, 0x14, 0x24, 0x11, 0x06, + 0x1d, 0xc8, 0x02, 0xcc, 0xfe, 0xd0, 0x6e, 0x09, 0x13, 0x1c, 0x13, 0x01, + 0x53, 0xfd, 0xfc, 0x5e, 0x14, 0x26, 0x1e, 0x12, 0x11, 0x19, 0x85, 0x61, + 0x00, 0x01, 0x00, 0x14, 0xff, 0x6b, 0x02, 0x28, 0x02, 0xba, 0x00, 0x11, + 0x00, 0x34, 0xba, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x11, 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1f, 0x3e, 0x59, 0xb9, 0x00, + 0x0f, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x00, 0xdc, 0xb8, 0x00, 0x11, 0x10, + 0xb8, 0x00, 0x0d, 0xd0, 0x30, 0x31, 0x37, 0x22, 0x2e, 0x02, 0x35, 0x34, + 0x3e, 0x02, 0x33, 0x21, 0x11, 0x23, 0x11, 0x23, 0x11, 0x23, 0xf5, 0x2f, + 0x51, 0x3e, 0x23, 0x23, 0x3e, 0x51, 0x2f, 0x01, 0x33, 0x77, 0x45, 0x77, + 0xf6, 0x22, 0x3c, 0x53, 0x31, 0x31, 0x53, 0x3c, 0x22, 0xfc, 0xb1, 0x02, + 0xdb, 0xfd, 0x25, 0x00, 0x00, 0x01, 0x00, 0xc3, 0x00, 0xcc, 0x01, 0x95, + 0x01, 0x95, 0x00, 0x0d, 0x00, 0x17, 0xba, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x0f, 0x11, 0x12, 0x39, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x07, + 0x00, 0x04, 0x2b, 0x30, 0x31, 0x25, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, + 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x01, 0x2c, 0x38, 0x31, 0x31, + 0x38, 0x38, 0x31, 0x31, 0xcc, 0x31, 0x22, 0x23, 0x22, 0x31, 0x31, 0x22, + 0x23, 0x22, 0x31, 0x00, 0x00, 0x01, 0x00, 0xbe, 0xff, 0x2c, 0x01, 0xbe, + 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x34, 0xba, 0x00, 0x07, 0x00, 0x1f, 0x00, + 0x20, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x12, 0x2f, 0xb8, 0x00, 0x17, + 0xdc, 0x41, 0x07, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x17, 0x00, + 0x2f, 0x00, 0x17, 0x00, 0x03, 0x5d, 0xb8, 0x00, 0x0f, 0xd0, 0xb8, 0x00, + 0x07, 0xdc, 0xb9, 0x00, 0x00, 0x00, 0x04, 0xf4, 0x30, 0x31, 0x05, 0x22, + 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x2e, 0x02, + 0x2f, 0x01, 0x37, 0x33, 0x07, 0x17, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x0e, 0x02, 0x01, 0x3a, 0x34, 0x3b, 0x0d, 0x2e, 0x0a, 0x21, 0x17, + 0x13, 0x19, 0x06, 0x11, 0x1d, 0x17, 0x15, 0x16, 0x43, 0x12, 0x04, 0x0c, + 0x18, 0x0c, 0x1e, 0x2b, 0x16, 0x25, 0x30, 0xd4, 0x1d, 0x0f, 0x38, 0x0c, + 0x11, 0x0c, 0x0d, 0x06, 0x0c, 0x0b, 0x09, 0x02, 0x02, 0x68, 0x55, 0x04, + 0x03, 0x04, 0x20, 0x25, 0x1a, 0x22, 0x16, 0x09, 0x00, 0x01, 0x00, 0xa4, + 0x01, 0x49, 0x01, 0xcf, 0x02, 0xba, 0x00, 0x0a, 0x00, 0x5b, 0xba, 0x00, + 0x02, 0x00, 0x0b, 0x00, 0x0c, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x15, 0x3e, 0x59, 0xb9, 0x00, 0x01, 0x00, 0x0c, + 0xf4, 0xb8, 0x00, 0x07, 0x10, 0xb9, 0x00, 0x03, 0x00, 0x0c, 0xf4, 0xba, + 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x04, + 0x10, 0xb9, 0x00, 0x05, 0x00, 0x0c, 0xf4, 0xb8, 0x00, 0x01, 0x10, 0xb8, + 0x00, 0x08, 0xd0, 0x30, 0x31, 0x13, 0x35, 0x33, 0x35, 0x07, 0x27, 0x37, + 0x33, 0x11, 0x33, 0x15, 0xbc, 0x5d, 0x4f, 0x26, 0x70, 0x6a, 0x51, 0x01, + 0x49, 0x4f, 0xc6, 0x24, 0x48, 0x38, 0xfe, 0xde, 0x4f, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x77, 0x01, 0x4c, 0x01, 0xe1, 0x02, 0xc6, 0x00, 0x0b, + 0x00, 0x19, 0x00, 0x55, 0xba, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x1b, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0c, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x2f, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, + 0x00, 0x1f, 0x3e, 0x59, 0x41, 0x03, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x01, + 0x5d, 0x41, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0x5d, 0x41, 0x03, + 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x71, 0xb8, 0x00, 0x00, 0x10, 0xb9, + 0x00, 0x0c, 0x00, 0x0c, 0xf4, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x13, + 0x00, 0x0c, 0xf4, 0x30, 0x31, 0x01, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x2c, 0x55, 0x60, 0x60, + 0x55, 0x55, 0x60, 0x60, 0x55, 0x23, 0x27, 0x27, 0x23, 0x23, 0x27, 0x27, + 0x01, 0x4c, 0x65, 0x58, 0x58, 0x65, 0x65, 0x58, 0x58, 0x65, 0x4d, 0x2b, + 0x28, 0x3a, 0x28, 0x2b, 0x2b, 0x28, 0x3a, 0x28, 0x2b, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x32, 0x00, 0x26, 0x02, 0x1d, 0x01, 0xfa, 0x00, 0x06, + 0x00, 0x0d, 0x00, 0x00, 0x25, 0x37, 0x27, 0x37, 0x17, 0x15, 0x07, 0x25, + 0x37, 0x27, 0x37, 0x17, 0x15, 0x07, 0x01, 0x28, 0x82, 0x82, 0x2d, 0xc8, + 0xc8, 0xfe, 0xdd, 0x82, 0x82, 0x2d, 0xc8, 0xc8, 0x85, 0x8b, 0x8a, 0x60, + 0xa8, 0x84, 0xa8, 0x5f, 0x8b, 0x8a, 0x60, 0xa8, 0x84, 0xa8, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x02, 0x57, 0x02, 0xba, 0x00, 0x0a, + 0x00, 0x0e, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x00, 0x25, 0x23, + 0x35, 0x37, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x23, 0x3d, 0x01, 0x23, + 0x07, 0x01, 0x33, 0x35, 0x07, 0x27, 0x37, 0x33, 0x11, 0x33, 0x15, 0x23, + 0x01, 0x33, 0x03, 0x23, 0x07, 0x33, 0x03, 0x23, 0x01, 0xce, 0x97, 0x83, + 0x68, 0x2c, 0x2c, 0x54, 0x05, 0x54, 0xfe, 0xb0, 0x55, 0x4c, 0x20, 0x66, + 0x5e, 0x4b, 0xf8, 0x01, 0xcb, 0x67, 0xad, 0x67, 0x95, 0x67, 0xad, 0x67, + 0x3f, 0x4a, 0xc6, 0xd3, 0x3d, 0x3f, 0x7c, 0x7e, 0x7e, 0x01, 0x34, 0xc2, + 0x27, 0x3a, 0x35, 0xfe, 0xf6, 0x45, 0x01, 0x4f, 0xfe, 0xd4, 0x62, 0xfe, + 0xd4, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x02, 0x57, + 0x02, 0xba, 0x00, 0x1b, 0x00, 0x26, 0x00, 0x2a, 0x00, 0x2e, 0x00, 0x00, + 0x25, 0x37, 0x3e, 0x01, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, + 0x27, 0x3e, 0x03, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x0f, 0x01, 0x33, + 0x15, 0x21, 0x01, 0x33, 0x35, 0x07, 0x27, 0x37, 0x33, 0x11, 0x33, 0x15, + 0x23, 0x01, 0x33, 0x03, 0x23, 0x07, 0x33, 0x03, 0x23, 0x01, 0x41, 0x6a, + 0x23, 0x17, 0x17, 0x13, 0x15, 0x1d, 0x08, 0x49, 0x06, 0x14, 0x20, 0x2e, + 0x1f, 0x3b, 0x48, 0x3b, 0x2e, 0x36, 0xa4, 0xfe, 0xfa, 0xfe, 0xe4, 0x55, + 0x4c, 0x20, 0x66, 0x5e, 0x4b, 0xf8, 0x01, 0xcb, 0x67, 0xad, 0x67, 0x95, + 0x67, 0xad, 0x67, 0x4b, 0x50, 0x1b, 0x20, 0x16, 0x02, 0x0f, 0x12, 0x19, + 0x16, 0x1c, 0x11, 0x1f, 0x1a, 0x0f, 0x38, 0x2e, 0x27, 0x40, 0x1e, 0x25, + 0x45, 0x01, 0xb0, 0xc2, 0x27, 0x3a, 0x35, 0xfe, 0xf6, 0x45, 0x01, 0x4f, + 0xfe, 0xd4, 0x62, 0xfe, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, + 0x00, 0x00, 0x02, 0x57, 0x02, 0xc0, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x38, + 0x00, 0x3c, 0x00, 0x40, 0x00, 0x00, 0x25, 0x23, 0x35, 0x37, 0x33, 0x15, + 0x33, 0x15, 0x23, 0x15, 0x23, 0x3d, 0x01, 0x23, 0x07, 0x27, 0x22, 0x26, + 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, + 0x35, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x07, 0x27, + 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, + 0x15, 0x14, 0x06, 0x01, 0x33, 0x03, 0x23, 0x07, 0x33, 0x03, 0x23, 0x01, + 0xce, 0x97, 0x83, 0x68, 0x2c, 0x2c, 0x54, 0x05, 0x54, 0xe0, 0x39, 0x40, + 0x11, 0x3f, 0x0b, 0x23, 0x1b, 0x30, 0x22, 0x1a, 0x1b, 0x1f, 0x1c, 0x18, + 0x17, 0x14, 0x2e, 0x20, 0x34, 0x18, 0x3a, 0x30, 0x3f, 0x48, 0x2a, 0x1d, + 0x23, 0x2a, 0x4d, 0x01, 0x1c, 0x67, 0xad, 0x67, 0x95, 0x67, 0xad, 0x67, + 0x3f, 0x4a, 0xc6, 0xd3, 0x3d, 0x3f, 0x7c, 0x7e, 0x7e, 0xe9, 0x28, 0x1a, + 0x2a, 0x13, 0x17, 0x22, 0x08, 0x13, 0x13, 0x3f, 0x14, 0x0e, 0x08, 0x0d, + 0x11, 0x29, 0x32, 0x1b, 0x1e, 0x32, 0x29, 0x20, 0x28, 0x04, 0x04, 0x05, + 0x26, 0x21, 0x2e, 0x36, 0x01, 0x55, 0xfe, 0xd4, 0x62, 0xfe, 0xd4, 0x00, + 0x00, 0x02, 0x00, 0x49, 0xff, 0x3e, 0x02, 0x1b, 0x02, 0x10, 0x00, 0x1c, + 0x00, 0x2a, 0x00, 0x3c, 0xba, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x2c, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x1d, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x2f, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x24, 0x2f, 0x1b, 0xb9, 0x00, 0x24, + 0x00, 0x1d, 0x3e, 0x59, 0xb9, 0x00, 0x1d, 0x00, 0x0a, 0xf4, 0xb9, 0x00, + 0x0c, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x14, 0x00, + 0x0d, 0xf4, 0x30, 0x31, 0x05, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, + 0x37, 0x35, 0x33, 0x15, 0x0e, 0x01, 0x1d, 0x01, 0x14, 0x16, 0x33, 0x32, + 0x36, 0x37, 0x17, 0x0e, 0x03, 0x03, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, + 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x01, 0x35, 0x35, 0x57, 0x3e, + 0x22, 0x1d, 0x31, 0x41, 0x24, 0x8c, 0x4b, 0x58, 0x31, 0x24, 0x29, 0x34, + 0x0a, 0x7a, 0x09, 0x23, 0x38, 0x4e, 0x29, 0x35, 0x2e, 0x2d, 0x36, 0x35, + 0x2d, 0x2d, 0xc2, 0x1e, 0x36, 0x4c, 0x2d, 0x2a, 0x45, 0x33, 0x20, 0x06, + 0x48, 0x99, 0x03, 0x2e, 0x39, 0x0e, 0x2a, 0x24, 0x2f, 0x26, 0x33, 0x1e, + 0x3a, 0x2d, 0x1b, 0x02, 0x17, 0x2d, 0x20, 0x20, 0x20, 0x2e, 0x2e, 0x20, + 0x20, 0x20, 0x2d, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x02, 0x53, + 0x03, 0xd1, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00, 0x13, 0x37, + 0x17, 0x07, 0x13, 0x27, 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, + 0x03, 0x33, 0x96, 0x7b, 0x63, 0x58, 0x97, 0x2c, 0xbf, 0x2b, 0x98, 0xbd, + 0xd4, 0xbd, 0xfe, 0xd9, 0x08, 0x44, 0x90, 0x03, 0x94, 0x3d, 0xc2, 0x2b, + 0xfd, 0x1c, 0xa8, 0xa8, 0x02, 0xba, 0xfd, 0x46, 0x02, 0x29, 0xfe, 0xf8, + 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x02, 0x53, 0x03, 0xd1, 0x00, 0x03, + 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x27, 0x37, 0x17, 0x03, 0x27, + 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, 0x01, 0x3c, + 0x58, 0x63, 0x7b, 0x0f, 0x2c, 0xbf, 0x2b, 0x98, 0xbd, 0xd4, 0xbd, 0xfe, + 0xd9, 0x08, 0x44, 0x90, 0x02, 0xe4, 0x2b, 0xc2, 0x3d, 0xfc, 0x6c, 0xa8, + 0xa8, 0x02, 0xba, 0xfd, 0x46, 0x02, 0x29, 0xfe, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x02, 0x53, 0x03, 0xbc, 0x00, 0x06, + 0x00, 0x0e, 0x00, 0x12, 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, + 0x37, 0x13, 0x27, 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, 0x03, + 0x33, 0x01, 0x6a, 0x84, 0x4b, 0x79, 0x79, 0x47, 0x84, 0xc5, 0x2c, 0xbf, + 0x2b, 0x98, 0xbd, 0xd4, 0xbd, 0xfe, 0xd9, 0x08, 0x44, 0x90, 0x03, 0xbc, + 0x9f, 0x3a, 0x73, 0x73, 0x3a, 0x9f, 0xfc, 0x44, 0xa8, 0xa8, 0x02, 0xba, + 0xfd, 0x46, 0x02, 0x29, 0xfe, 0xf8, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, + 0x00, 0x00, 0x02, 0x53, 0x03, 0x8f, 0x00, 0x19, 0x00, 0x21, 0x00, 0x25, + 0x00, 0x00, 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, + 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, + 0x37, 0x17, 0x0e, 0x01, 0x13, 0x27, 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, + 0x01, 0x23, 0x03, 0x33, 0x01, 0x78, 0x17, 0x23, 0x13, 0x16, 0x24, 0x14, + 0x11, 0x1a, 0x10, 0x34, 0x12, 0x38, 0x28, 0x17, 0x23, 0x13, 0x16, 0x24, + 0x14, 0x11, 0x1a, 0x10, 0x34, 0x12, 0x38, 0x13, 0x2c, 0xbf, 0x2b, 0x98, + 0xbd, 0xd4, 0xbd, 0xfe, 0xd9, 0x08, 0x44, 0x90, 0x02, 0xfa, 0x0c, 0x08, + 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, 0x25, 0x0c, 0x08, 0x09, 0x0d, 0x0c, + 0x0d, 0x44, 0x1b, 0x25, 0xfd, 0x06, 0xa8, 0xa8, 0x02, 0xba, 0xfd, 0x46, + 0x02, 0x29, 0xfe, 0xf8, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x02, 0x53, + 0x03, 0x90, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, + 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, + 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x1d, 0x01, 0x14, 0x06, 0x03, 0x27, 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, + 0x01, 0x23, 0x03, 0x33, 0xbe, 0x2d, 0x23, 0x23, 0x2d, 0x2d, 0x24, 0x24, + 0xaf, 0x2d, 0x24, 0x24, 0x2d, 0x2d, 0x23, 0x23, 0x14, 0x2c, 0xbf, 0x2b, + 0x98, 0xbd, 0xd4, 0xbd, 0xfe, 0xd9, 0x08, 0x44, 0x90, 0x02, 0xf9, 0x25, + 0x1a, 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, 0x25, 0x1a, 0x1a, + 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, 0xfd, 0x07, 0xa8, 0xa8, 0x02, + 0xba, 0xfd, 0x46, 0x02, 0x29, 0xfe, 0xf8, 0x00, 0x00, 0x04, 0x00, 0x05, + 0x00, 0x00, 0x02, 0x53, 0x03, 0xed, 0x00, 0x13, 0x00, 0x21, 0x00, 0x29, + 0x00, 0x2d, 0x00, 0x00, 0x01, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, + 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x13, 0x27, + 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, 0x01, 0x2c, + 0x1f, 0x36, 0x28, 0x17, 0x17, 0x28, 0x36, 0x1f, 0x1f, 0x36, 0x28, 0x17, + 0x17, 0x28, 0x36, 0x1f, 0x19, 0x1a, 0x1a, 0x19, 0x19, 0x1a, 0x1a, 0xa0, + 0x2c, 0xbf, 0x2b, 0x98, 0xbd, 0xd4, 0xbd, 0xfe, 0xd9, 0x08, 0x44, 0x90, + 0x02, 0xcf, 0x15, 0x26, 0x35, 0x1f, 0x1f, 0x34, 0x26, 0x16, 0x15, 0x26, + 0x35, 0x1f, 0x1f, 0x34, 0x26, 0x16, 0x4b, 0x1c, 0x17, 0x22, 0x18, 0x1b, + 0x1c, 0x17, 0x22, 0x18, 0x1b, 0xfc, 0xe6, 0xa8, 0xa8, 0x02, 0xba, 0xfd, + 0x46, 0x02, 0x29, 0xfe, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xfc, + 0x00, 0x00, 0x02, 0x3c, 0x02, 0xba, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x8c, + 0xba, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x15, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x0f, 0x10, 0xb8, 0x00, 0x12, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, 0x2f, 0x1b, 0xb9, 0x00, + 0x0e, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x02, 0x2f, 0x1b, 0xb9, 0x00, 0x02, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, + 0x11, 0x00, 0x05, 0x00, 0x0e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x2f, + 0xb9, 0x00, 0x01, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, + 0x06, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0e, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x2f, 0xb9, 0x00, 0x08, 0x00, 0x0d, 0xf4, + 0xb8, 0x00, 0x0e, 0x10, 0xb9, 0x00, 0x0d, 0x00, 0x0d, 0xf4, 0xb8, 0x00, + 0x06, 0x10, 0xb8, 0x00, 0x13, 0xd0, 0x30, 0x31, 0x25, 0x23, 0x07, 0x23, + 0x13, 0x21, 0x15, 0x23, 0x15, 0x33, 0x15, 0x23, 0x15, 0x33, 0x15, 0x21, + 0x0b, 0x01, 0x33, 0x11, 0x01, 0x17, 0x68, 0x21, 0x92, 0x9f, 0x01, 0xa1, + 0x9b, 0x91, 0x91, 0x9b, 0xfe, 0xdb, 0x16, 0x3c, 0x52, 0xa8, 0xa8, 0x02, + 0xba, 0x6f, 0xb2, 0x6f, 0xbb, 0x6f, 0x02, 0x52, 0xfe, 0xc5, 0x01, 0x3b, + 0x00, 0x01, 0x00, 0x29, 0xff, 0x2c, 0x02, 0x33, 0x02, 0xc6, 0x00, 0x3c, + 0x00, 0x72, 0xba, 0x00, 0x22, 0x00, 0x3d, 0x00, 0x3e, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x32, 0x2f, 0x1b, 0xb9, + 0x00, 0x32, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x0e, 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x11, 0x3e, 0x59, 0xb8, + 0x00, 0x32, 0x10, 0xb9, 0x00, 0x00, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x0e, + 0x10, 0xb9, 0x00, 0x07, 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x0e, 0x10, 0xb8, + 0x00, 0x13, 0xdc, 0x41, 0x07, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x1f, 0x00, + 0x13, 0x00, 0x2f, 0x00, 0x13, 0x00, 0x03, 0x5d, 0xb8, 0x00, 0x2a, 0xdc, + 0xb8, 0x00, 0x22, 0xdc, 0xb9, 0x00, 0x1b, 0x00, 0x04, 0xf4, 0xb8, 0x00, + 0x0e, 0x10, 0xb8, 0x00, 0x2c, 0xd0, 0x30, 0x31, 0x01, 0x22, 0x06, 0x1d, + 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, 0x0f, 0x01, + 0x17, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, + 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x2e, 0x02, + 0x2f, 0x01, 0x37, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x33, 0x32, 0x1e, 0x02, + 0x17, 0x07, 0x2e, 0x03, 0x01, 0x39, 0x3d, 0x33, 0x33, 0x3d, 0x34, 0x2f, + 0x0b, 0x8c, 0x14, 0x6e, 0x64, 0x09, 0x04, 0x0c, 0x18, 0x0c, 0x1e, 0x2b, + 0x16, 0x25, 0x30, 0x19, 0x34, 0x3b, 0x0d, 0x2e, 0x0a, 0x21, 0x17, 0x13, + 0x19, 0x06, 0x11, 0x1d, 0x17, 0x15, 0x0e, 0x74, 0x6e, 0x87, 0x8c, 0x36, + 0x53, 0x3c, 0x27, 0x0b, 0x8c, 0x06, 0x10, 0x19, 0x25, 0x02, 0x4d, 0x5f, + 0x54, 0x7a, 0x54, 0x5f, 0x40, 0x32, 0x22, 0x58, 0x6b, 0x05, 0x2c, 0x04, + 0x03, 0x04, 0x20, 0x25, 0x1a, 0x22, 0x16, 0x09, 0x1d, 0x0f, 0x38, 0x0c, + 0x11, 0x0c, 0x0d, 0x06, 0x0c, 0x0b, 0x09, 0x02, 0x02, 0x42, 0x10, 0xb8, + 0x9d, 0xac, 0xbd, 0x1d, 0x34, 0x4a, 0x2e, 0x22, 0x19, 0x2a, 0x1e, 0x11, + 0x00, 0x02, 0x00, 0x50, 0x00, 0x00, 0x02, 0x0e, 0x03, 0xd1, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x00, 0x13, 0x37, 0x17, 0x07, 0x03, 0x11, 0x21, 0x15, + 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x99, 0x7b, 0x63, 0x58, + 0xcf, 0x01, 0xbe, 0xfe, 0xd8, 0x01, 0x1e, 0xfe, 0xe2, 0x01, 0x28, 0x03, + 0x94, 0x3d, 0xc2, 0x2b, 0xfd, 0x1c, 0x02, 0xba, 0x7b, 0xa0, 0x7b, 0xa9, + 0x7b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x50, 0x00, 0x00, 0x02, 0x0e, + 0x03, 0xd1, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x27, 0x37, 0x17, + 0x01, 0x11, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, + 0x01, 0x3f, 0x58, 0x63, 0x7b, 0xfe, 0x8b, 0x01, 0xbe, 0xfe, 0xd8, 0x01, + 0x1e, 0xfe, 0xe2, 0x01, 0x28, 0x02, 0xe4, 0x2b, 0xc2, 0x3d, 0xfc, 0x6c, + 0x02, 0xba, 0x7b, 0xa0, 0x7b, 0xa9, 0x7b, 0x00, 0x00, 0x02, 0x00, 0x50, + 0x00, 0x00, 0x02, 0x0e, 0x03, 0xbc, 0x00, 0x06, 0x00, 0x12, 0x00, 0x00, + 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x03, 0x11, 0x21, 0x15, 0x21, + 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x01, 0x6d, 0x84, 0x4b, 0x79, + 0x79, 0x47, 0x84, 0xa1, 0x01, 0xbe, 0xfe, 0xd8, 0x01, 0x1e, 0xfe, 0xe2, + 0x01, 0x28, 0x03, 0xbc, 0x9f, 0x3a, 0x73, 0x73, 0x3a, 0x9f, 0xfc, 0x44, + 0x02, 0xba, 0x7b, 0xa0, 0x7b, 0xa9, 0x7b, 0x00, 0x00, 0x03, 0x00, 0x50, + 0x00, 0x00, 0x02, 0x0e, 0x03, 0x90, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x27, + 0x00, 0x00, 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x01, 0x11, 0x21, 0x15, 0x21, 0x15, + 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0xc1, 0x2d, 0x23, 0x23, 0x2d, 0x2d, + 0x24, 0x24, 0xaf, 0x2d, 0x24, 0x24, 0x2d, 0x2d, 0x23, 0x23, 0xfe, 0x86, + 0x01, 0xbe, 0xfe, 0xd8, 0x01, 0x1e, 0xfe, 0xe2, 0x01, 0x28, 0x02, 0xf9, + 0x25, 0x1a, 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, 0x25, 0x1a, + 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, 0xfd, 0x07, 0x02, 0xba, + 0x7b, 0xa0, 0x7b, 0xa9, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4b, + 0x00, 0x00, 0x02, 0x0d, 0x03, 0xd1, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, + 0x13, 0x37, 0x17, 0x07, 0x03, 0x35, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, + 0x23, 0x11, 0x33, 0x15, 0x96, 0x7b, 0x63, 0x58, 0xd1, 0x96, 0x96, 0x01, + 0xc2, 0x96, 0x96, 0x03, 0x94, 0x3d, 0xc2, 0x2b, 0xfd, 0x1c, 0x6f, 0x01, + 0xdc, 0x6f, 0x6f, 0xfe, 0x24, 0x6f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4b, + 0x00, 0x00, 0x02, 0x0d, 0x03, 0xd1, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, + 0x01, 0x27, 0x37, 0x17, 0x01, 0x35, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, + 0x23, 0x11, 0x33, 0x15, 0x01, 0x3c, 0x58, 0x63, 0x7b, 0xfe, 0x89, 0x96, + 0x96, 0x01, 0xc2, 0x96, 0x96, 0x02, 0xe4, 0x2b, 0xc2, 0x3d, 0xfc, 0x6c, + 0x6f, 0x01, 0xdc, 0x6f, 0x6f, 0xfe, 0x24, 0x6f, 0x00, 0x02, 0x00, 0x4b, + 0x00, 0x00, 0x02, 0x0d, 0x03, 0xbc, 0x00, 0x06, 0x00, 0x12, 0x00, 0x00, + 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x03, 0x35, 0x33, 0x11, 0x23, + 0x35, 0x21, 0x15, 0x23, 0x11, 0x33, 0x15, 0x01, 0x6a, 0x84, 0x4b, 0x79, + 0x79, 0x47, 0x84, 0xa3, 0x96, 0x96, 0x01, 0xc2, 0x96, 0x96, 0x03, 0xbc, + 0x9f, 0x3a, 0x73, 0x73, 0x3a, 0x9f, 0xfc, 0x44, 0x6f, 0x01, 0xdc, 0x6f, + 0x6f, 0xfe, 0x24, 0x6f, 0x00, 0x03, 0x00, 0x4b, 0x00, 0x00, 0x02, 0x0d, + 0x03, 0x90, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x00, 0x13, 0x22, + 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, + 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, + 0x14, 0x06, 0x01, 0x35, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, 0x23, 0x11, + 0x33, 0x15, 0xbe, 0x2d, 0x23, 0x23, 0x2d, 0x2d, 0x24, 0x24, 0xaf, 0x2d, + 0x24, 0x24, 0x2d, 0x2d, 0x23, 0x23, 0xfe, 0x84, 0x96, 0x96, 0x01, 0xc2, + 0x96, 0x96, 0x02, 0xf9, 0x25, 0x1a, 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, + 0x1a, 0x25, 0x25, 0x1a, 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, + 0xfd, 0x07, 0x6f, 0x01, 0xdc, 0x6f, 0x6f, 0xfe, 0x24, 0x6f, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x36, 0x02, 0xba, 0x00, 0x0c, + 0x00, 0x1a, 0x00, 0x00, 0x13, 0x23, 0x35, 0x33, 0x11, 0x33, 0x32, 0x16, + 0x15, 0x14, 0x06, 0x2b, 0x01, 0x37, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x2b, 0x01, 0x15, 0x33, 0x15, 0x23, 0x15, 0x45, 0x3b, 0x3b, 0xdc, 0x8d, + 0x88, 0x88, 0x8d, 0xdc, 0xd2, 0x43, 0x3e, 0x3e, 0x43, 0x3e, 0x6e, 0x6e, + 0x01, 0x37, 0x72, 0x01, 0x11, 0xb4, 0xa9, 0xa9, 0xb4, 0x76, 0x56, 0x52, + 0x7f, 0x51, 0x56, 0xa0, 0x68, 0xc6, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3d, + 0x00, 0x00, 0x02, 0x1b, 0x03, 0x8f, 0x00, 0x19, 0x00, 0x25, 0x00, 0x00, + 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, + 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, + 0x0e, 0x01, 0x03, 0x23, 0x11, 0x23, 0x11, 0x33, 0x13, 0x33, 0x11, 0x33, + 0x11, 0x23, 0x01, 0x78, 0x17, 0x23, 0x13, 0x16, 0x24, 0x14, 0x11, 0x1a, + 0x10, 0x34, 0x12, 0x38, 0x28, 0x17, 0x23, 0x13, 0x16, 0x24, 0x14, 0x11, + 0x1a, 0x10, 0x34, 0x12, 0x38, 0xd8, 0x0b, 0x80, 0xb4, 0x9f, 0x0b, 0x80, + 0xb4, 0x02, 0xfa, 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, 0x25, + 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, 0x25, 0xfe, 0xd6, 0xfe, + 0x30, 0x02, 0xba, 0xfe, 0x30, 0x01, 0xd0, 0xfd, 0x46, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x1b, 0xff, 0xf4, 0x02, 0x3d, 0x03, 0xd1, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x00, 0x13, 0x37, 0x17, 0x07, 0x13, 0x22, + 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, 0x32, + 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, + 0x96, 0x7b, 0x63, 0x58, 0x10, 0x8c, 0x85, 0x85, 0x8c, 0x8c, 0x85, 0x85, + 0x8c, 0x40, 0x31, 0x31, 0x40, 0x40, 0x31, 0x31, 0x03, 0x94, 0x3d, 0xc2, + 0x2b, 0xfd, 0x10, 0xbe, 0xab, 0xab, 0xbe, 0xbe, 0xab, 0xab, 0xbe, 0x79, + 0x5f, 0x55, 0x79, 0x54, 0x5f, 0x5f, 0x54, 0x7a, 0x54, 0x5f, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x1b, 0xff, 0xf4, 0x02, 0x3d, 0x03, 0xd1, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x00, 0x01, 0x27, 0x37, 0x17, 0x03, 0x22, + 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, 0x32, + 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, + 0x01, 0x3c, 0x58, 0x63, 0x7b, 0x96, 0x8c, 0x85, 0x85, 0x8c, 0x8c, 0x85, + 0x85, 0x8c, 0x40, 0x31, 0x31, 0x40, 0x40, 0x31, 0x31, 0x02, 0xe4, 0x2b, + 0xc2, 0x3d, 0xfc, 0x60, 0xbe, 0xab, 0xab, 0xbe, 0xbe, 0xab, 0xab, 0xbe, + 0x79, 0x5f, 0x55, 0x79, 0x54, 0x5f, 0x5f, 0x54, 0x7a, 0x54, 0x5f, 0x00, + 0x00, 0x03, 0x00, 0x1b, 0xff, 0xf4, 0x02, 0x3d, 0x03, 0xbc, 0x00, 0x06, + 0x00, 0x12, 0x00, 0x20, 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, + 0x37, 0x13, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, + 0x01, 0x14, 0x16, 0x01, 0x6a, 0x84, 0x4b, 0x79, 0x79, 0x47, 0x84, 0x3e, + 0x8c, 0x85, 0x85, 0x8c, 0x8c, 0x85, 0x85, 0x8c, 0x40, 0x31, 0x31, 0x40, + 0x40, 0x31, 0x31, 0x03, 0xbc, 0x9f, 0x3a, 0x73, 0x73, 0x3a, 0x9f, 0xfc, + 0x38, 0xbe, 0xab, 0xab, 0xbe, 0xbe, 0xab, 0xab, 0xbe, 0x79, 0x5f, 0x55, + 0x79, 0x54, 0x5f, 0x5f, 0x54, 0x7a, 0x54, 0x5f, 0x00, 0x03, 0x00, 0x1b, + 0xff, 0xf4, 0x02, 0x3d, 0x03, 0x8f, 0x00, 0x19, 0x00, 0x25, 0x00, 0x33, + 0x00, 0x00, 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, + 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, + 0x37, 0x17, 0x0e, 0x01, 0x03, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, + 0x16, 0x15, 0x14, 0x06, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x78, 0x17, 0x23, 0x13, 0x16, + 0x24, 0x14, 0x11, 0x1a, 0x10, 0x34, 0x12, 0x38, 0x28, 0x17, 0x23, 0x13, + 0x16, 0x24, 0x14, 0x11, 0x1a, 0x10, 0x34, 0x12, 0x38, 0x74, 0x8c, 0x85, + 0x85, 0x8c, 0x8c, 0x85, 0x85, 0x8c, 0x40, 0x31, 0x31, 0x40, 0x40, 0x31, + 0x31, 0x02, 0xfa, 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, 0x25, + 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, 0x25, 0xfc, 0xfa, 0xbe, + 0xab, 0xab, 0xbe, 0xbe, 0xab, 0xab, 0xbe, 0x79, 0x5f, 0x55, 0x79, 0x54, + 0x5f, 0x5f, 0x54, 0x7a, 0x54, 0x5f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x1b, + 0xff, 0xf4, 0x02, 0x3d, 0x03, 0x90, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x27, + 0x00, 0x35, 0x00, 0x00, 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, + 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x03, 0x22, 0x26, 0x35, + 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0xbe, 0x2d, + 0x23, 0x23, 0x2d, 0x2d, 0x24, 0x24, 0xaf, 0x2d, 0x24, 0x24, 0x2d, 0x2d, + 0x23, 0x23, 0x9b, 0x8c, 0x85, 0x85, 0x8c, 0x8c, 0x85, 0x85, 0x8c, 0x40, + 0x31, 0x31, 0x40, 0x40, 0x31, 0x31, 0x02, 0xf9, 0x25, 0x1a, 0x1a, 0x1a, + 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, 0x25, 0x1a, 0x1a, 0x1a, 0x24, 0x24, + 0x1a, 0x1a, 0x1a, 0x25, 0xfc, 0xfb, 0xbe, 0xab, 0xab, 0xbe, 0xbe, 0xab, + 0xab, 0xbe, 0x79, 0x5f, 0x55, 0x79, 0x54, 0x5f, 0x5f, 0x54, 0x7a, 0x54, + 0x5f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00, 0x4b, 0x02, 0x12, + 0x02, 0x17, 0x00, 0x0b, 0x00, 0x2f, 0xba, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, + 0x1d, 0x3e, 0x59, 0x30, 0x31, 0x25, 0x07, 0x27, 0x37, 0x27, 0x37, 0x17, + 0x37, 0x17, 0x07, 0x17, 0x07, 0x01, 0x2c, 0x91, 0x55, 0x91, 0x91, 0x55, + 0x91, 0x91, 0x55, 0x91, 0x91, 0x55, 0xdc, 0x91, 0x55, 0x91, 0x91, 0x55, + 0x91, 0x91, 0x55, 0x91, 0x91, 0x55, 0x00, 0x00, 0x00, 0x03, 0x00, 0x13, + 0xff, 0xbe, 0x02, 0x45, 0x02, 0xfc, 0x00, 0x13, 0x00, 0x1d, 0x00, 0x27, + 0x00, 0x9f, 0xba, 0x00, 0x00, 0x00, 0x28, 0x00, 0x29, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x1a, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x1e, 0xd0, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, + 0x00, 0x0a, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, + 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x1a, 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x1a, 0x11, 0x12, 0x39, 0xba, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x1a, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x1e, + 0x00, 0x0d, 0xf4, 0xba, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x1e, 0x11, 0x12, + 0x39, 0xba, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x1e, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x17, 0x00, 0x1e, 0x00, 0x0a, 0x11, 0x12, 0x39, 0xba, 0x00, 0x18, + 0x00, 0x1a, 0x00, 0x00, 0x11, 0x12, 0x39, 0xba, 0x00, 0x25, 0x00, 0x1a, + 0x00, 0x00, 0x11, 0x12, 0x39, 0xba, 0x00, 0x26, 0x00, 0x1e, 0x00, 0x0a, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x05, 0x22, 0x27, 0x07, 0x27, 0x37, 0x26, + 0x35, 0x34, 0x36, 0x33, 0x32, 0x17, 0x37, 0x17, 0x07, 0x16, 0x15, 0x14, + 0x06, 0x03, 0x1c, 0x01, 0x17, 0x13, 0x26, 0x23, 0x22, 0x06, 0x15, 0x13, + 0x32, 0x36, 0x3d, 0x01, 0x3c, 0x01, 0x27, 0x03, 0x16, 0x01, 0x2c, 0x4f, + 0x37, 0x35, 0x5e, 0x42, 0x3a, 0x85, 0x8c, 0x4f, 0x37, 0x35, 0x5e, 0x42, + 0x3a, 0x85, 0xfd, 0x02, 0xb6, 0x1a, 0x2d, 0x40, 0x31, 0x71, 0x40, 0x31, + 0x02, 0xb6, 0x19, 0x0c, 0x1f, 0x55, 0x36, 0x6b, 0x5b, 0xa3, 0xab, 0xbe, + 0x1f, 0x55, 0x36, 0x6b, 0x5b, 0xa3, 0xab, 0xbe, 0x01, 0x2c, 0x0b, 0x12, + 0x0a, 0x01, 0x3c, 0x18, 0x5f, 0x54, 0xfe, 0xd3, 0x5f, 0x54, 0x7a, 0x0b, + 0x11, 0x0b, 0xfe, 0xc4, 0x18, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, + 0xff, 0xf4, 0x02, 0x21, 0x03, 0xd1, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, + 0x13, 0x37, 0x17, 0x0f, 0x01, 0x11, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x3e, + 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, + 0x35, 0x11, 0x96, 0x7b, 0x63, 0x58, 0x4f, 0x05, 0x13, 0x26, 0x21, 0x21, + 0x26, 0x13, 0x05, 0x96, 0x13, 0x36, 0x60, 0x4c, 0x4c, 0x60, 0x36, 0x13, + 0x03, 0x94, 0x3d, 0xc2, 0x2b, 0x2a, 0xfe, 0x46, 0x21, 0x37, 0x26, 0x15, + 0x15, 0x26, 0x37, 0x21, 0x01, 0xba, 0xfe, 0x5a, 0x48, 0x6c, 0x48, 0x24, + 0x24, 0x48, 0x6c, 0x48, 0x01, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, + 0xff, 0xf4, 0x02, 0x21, 0x03, 0xd1, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, + 0x01, 0x27, 0x37, 0x17, 0x07, 0x11, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x3e, + 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, + 0x35, 0x11, 0x01, 0x3c, 0x58, 0x63, 0x7b, 0xf5, 0x05, 0x13, 0x26, 0x21, + 0x21, 0x26, 0x13, 0x05, 0x96, 0x13, 0x36, 0x60, 0x4c, 0x4c, 0x60, 0x36, + 0x13, 0x02, 0xe4, 0x2b, 0xc2, 0x3d, 0xda, 0xfe, 0x46, 0x21, 0x37, 0x26, + 0x15, 0x15, 0x26, 0x37, 0x21, 0x01, 0xba, 0xfe, 0x5a, 0x48, 0x6c, 0x48, + 0x24, 0x24, 0x48, 0x6c, 0x48, 0x01, 0xa6, 0x00, 0x00, 0x02, 0x00, 0x37, + 0xff, 0xf4, 0x02, 0x21, 0x03, 0xbc, 0x00, 0x06, 0x00, 0x20, 0x00, 0x00, + 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x03, 0x11, 0x14, 0x1e, 0x02, + 0x33, 0x32, 0x3e, 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, + 0x22, 0x2e, 0x02, 0x35, 0x11, 0x01, 0x6a, 0x84, 0x4b, 0x79, 0x79, 0x47, + 0x84, 0x21, 0x05, 0x13, 0x26, 0x21, 0x21, 0x26, 0x13, 0x05, 0x96, 0x13, + 0x36, 0x60, 0x4c, 0x4c, 0x60, 0x36, 0x13, 0x03, 0xbc, 0x9f, 0x3a, 0x73, + 0x73, 0x3a, 0x9f, 0xfe, 0xfe, 0xfe, 0x46, 0x21, 0x37, 0x26, 0x15, 0x15, + 0x26, 0x37, 0x21, 0x01, 0xba, 0xfe, 0x5a, 0x48, 0x6c, 0x48, 0x24, 0x24, + 0x48, 0x6c, 0x48, 0x01, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x37, + 0xff, 0xf4, 0x02, 0x21, 0x03, 0x90, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x35, + 0x00, 0x00, 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x07, 0x11, 0x14, 0x1e, 0x02, 0x33, + 0x32, 0x3e, 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, 0x22, + 0x2e, 0x02, 0x35, 0x11, 0xbe, 0x2d, 0x23, 0x23, 0x2d, 0x2d, 0x24, 0x24, + 0xaf, 0x2d, 0x24, 0x24, 0x2d, 0x2d, 0x23, 0x23, 0xfa, 0x05, 0x13, 0x26, + 0x21, 0x21, 0x26, 0x13, 0x05, 0x96, 0x13, 0x36, 0x60, 0x4c, 0x4c, 0x60, + 0x36, 0x13, 0x02, 0xf9, 0x25, 0x1a, 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, + 0x1a, 0x25, 0x25, 0x1a, 0x1a, 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, + 0x3f, 0xfe, 0x46, 0x21, 0x37, 0x26, 0x15, 0x15, 0x26, 0x37, 0x21, 0x01, + 0xba, 0xfe, 0x5a, 0x48, 0x6c, 0x48, 0x24, 0x24, 0x48, 0x6c, 0x48, 0x01, + 0xa6, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x02, 0x54, + 0x03, 0xd1, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x27, 0x37, 0x17, + 0x03, 0x35, 0x03, 0x33, 0x1f, 0x01, 0x33, 0x3f, 0x01, 0x33, 0x03, 0x15, + 0x01, 0x3c, 0x58, 0x63, 0x7b, 0xe1, 0xdd, 0xa7, 0x4a, 0x36, 0x08, 0x36, + 0x4a, 0xa1, 0xdd, 0x02, 0xe4, 0x2b, 0xc2, 0x3d, 0xfc, 0x6c, 0xf7, 0x01, + 0xc3, 0xa2, 0x89, 0x89, 0xa2, 0xfe, 0x3d, 0xf7, 0x00, 0x02, 0x00, 0x4c, + 0x00, 0x00, 0x02, 0x2b, 0x02, 0xba, 0x00, 0x10, 0x00, 0x1a, 0x00, 0x63, + 0xba, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x1c, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x12, 0x10, 0xb8, 0x00, 0x0e, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, + 0x00, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x03, 0x2f, 0xba, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0x01, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0f, 0x2f, 0xb9, 0x00, 0x11, + 0x00, 0x0d, 0xf4, 0xb8, 0x00, 0x03, 0x10, 0xb9, 0x00, 0x1a, 0x00, 0x0d, + 0xf4, 0x30, 0x31, 0x33, 0x11, 0x33, 0x15, 0x33, 0x32, 0x1e, 0x02, 0x15, + 0x14, 0x0e, 0x02, 0x2b, 0x01, 0x15, 0x35, 0x33, 0x32, 0x36, 0x3d, 0x01, + 0x34, 0x26, 0x2b, 0x01, 0x4c, 0x97, 0x72, 0x34, 0x50, 0x36, 0x1c, 0x1c, + 0x36, 0x50, 0x34, 0x72, 0x4d, 0x35, 0x29, 0x29, 0x35, 0x4d, 0x02, 0xba, + 0x79, 0x20, 0x3a, 0x52, 0x32, 0x32, 0x52, 0x3a, 0x20, 0x85, 0xfe, 0x28, + 0x2e, 0x1e, 0x2e, 0x28, 0x00, 0x01, 0x00, 0x3c, 0xff, 0x38, 0x02, 0x3e, + 0x02, 0xe4, 0x00, 0x20, 0x00, 0x8d, 0xba, 0x00, 0x14, 0x00, 0x21, 0x00, + 0x22, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x21, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x11, 0x2f, + 0x1b, 0xb9, 0x00, 0x11, 0x00, 0x13, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x20, 0x2f, 0x1b, 0xb9, 0x00, 0x20, 0x00, 0x11, 0x3e, + 0x59, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x07, 0x00, 0x09, 0xf4, 0xba, + 0x00, 0x1d, 0x00, 0x08, 0x00, 0x20, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1d, + 0x2f, 0xb9, 0x00, 0x1c, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x0b, 0x00, 0x1d, + 0x00, 0x1c, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x10, 0xb9, 0x00, 0x14, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x08, 0x10, 0xb9, 0x00, 0x1f, 0x00, 0x09, + 0xf4, 0x30, 0x31, 0x33, 0x11, 0x34, 0x36, 0x3b, 0x01, 0x15, 0x23, 0x15, + 0x21, 0x15, 0x07, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x2b, 0x01, 0x35, 0x33, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x35, 0x37, 0x23, 0x11, + 0x3c, 0x4d, 0x51, 0x9e, 0xac, 0x01, 0x50, 0x8b, 0x51, 0x5c, 0x8e, 0x78, + 0x42, 0x39, 0x3f, 0x3b, 0x3e, 0x42, 0x18, 0x7b, 0xc0, 0x02, 0x4f, 0x42, + 0x53, 0x6f, 0x71, 0x6a, 0xc5, 0x0f, 0x61, 0x55, 0x6b, 0x6d, 0x6f, 0x2c, + 0x30, 0x17, 0x31, 0x2c, 0x6f, 0xaf, 0xfe, 0x6b, 0xff, 0xff, 0x00, 0x34, + 0xff, 0xf4, 0x02, 0x3c, 0x03, 0x27, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x43, 0xf9, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x34, + 0xff, 0xf4, 0x02, 0x3c, 0x03, 0x27, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x76, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x34, + 0xff, 0xf4, 0x02, 0x3c, 0x03, 0x12, 0x00, 0x06, 0x00, 0x26, 0x00, 0x31, + 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x01, 0x22, 0x26, + 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3b, 0x01, + 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, + 0x16, 0x1d, 0x01, 0x33, 0x15, 0x25, 0x32, 0x36, 0x3d, 0x01, 0x23, 0x22, + 0x1d, 0x01, 0x14, 0x16, 0x01, 0x63, 0x84, 0x4b, 0x79, 0x79, 0x47, 0x84, + 0x01, 0x00, 0x2e, 0x38, 0x05, 0x05, 0x0e, 0x53, 0x3c, 0x4b, 0x5b, 0x76, + 0x72, 0x53, 0x2b, 0x33, 0x2f, 0x3a, 0x15, 0x51, 0x1a, 0x6f, 0x57, 0x6a, + 0x77, 0x39, 0xfe, 0xd6, 0x27, 0x36, 0x4f, 0x5b, 0x2a, 0x03, 0x12, 0x9f, + 0x3a, 0x73, 0x73, 0x3a, 0x9f, 0xfc, 0xee, 0x2f, 0x2c, 0x33, 0x34, 0x51, + 0x49, 0x51, 0x4e, 0x1a, 0x2e, 0x2f, 0x24, 0x1d, 0x48, 0x2c, 0x39, 0x61, + 0x62, 0xe2, 0x6b, 0x55, 0x26, 0x24, 0x3e, 0x3d, 0x14, 0x1b, 0x1c, 0x00, + 0x00, 0x03, 0x00, 0x34, 0xff, 0xf4, 0x02, 0x3c, 0x02, 0xe5, 0x00, 0x19, + 0x00, 0x39, 0x00, 0x44, 0x00, 0x00, 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, + 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, + 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, 0x13, 0x22, 0x26, 0x27, + 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3b, 0x01, 0x35, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, + 0x1d, 0x01, 0x33, 0x15, 0x25, 0x32, 0x36, 0x3d, 0x01, 0x23, 0x22, 0x1d, + 0x01, 0x14, 0x16, 0x01, 0x71, 0x17, 0x23, 0x13, 0x16, 0x24, 0x14, 0x11, + 0x1a, 0x10, 0x34, 0x12, 0x38, 0x28, 0x17, 0x23, 0x13, 0x16, 0x24, 0x14, + 0x11, 0x1a, 0x10, 0x34, 0x12, 0x38, 0x4e, 0x2e, 0x38, 0x05, 0x05, 0x0e, + 0x53, 0x3c, 0x4b, 0x5b, 0x76, 0x72, 0x53, 0x2b, 0x33, 0x2f, 0x3a, 0x15, + 0x51, 0x1a, 0x6f, 0x57, 0x6a, 0x77, 0x39, 0xfe, 0xd6, 0x27, 0x36, 0x4f, + 0x5b, 0x2a, 0x02, 0x50, 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, + 0x25, 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, 0x25, 0xfd, 0xb0, + 0x2f, 0x2c, 0x33, 0x34, 0x51, 0x49, 0x51, 0x4e, 0x1a, 0x2e, 0x2f, 0x24, + 0x1d, 0x48, 0x2c, 0x39, 0x61, 0x62, 0xe2, 0x6b, 0x55, 0x26, 0x24, 0x3e, + 0x3d, 0x14, 0x1b, 0x1c, 0xff, 0xff, 0x00, 0x34, 0xff, 0xf4, 0x02, 0x3c, + 0x02, 0xe6, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, 0x10, 0x06, 0x00, 0x6a, + 0xf9, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x34, 0xff, 0xf4, 0x02, 0x3c, + 0x03, 0x43, 0x00, 0x13, 0x00, 0x21, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x00, + 0x01, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, + 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x13, 0x22, 0x26, 0x27, 0x23, 0x0e, + 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3b, 0x01, 0x35, 0x34, 0x26, + 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x1d, 0x01, + 0x33, 0x15, 0x25, 0x32, 0x36, 0x3d, 0x01, 0x23, 0x22, 0x1d, 0x01, 0x14, + 0x16, 0x01, 0x25, 0x1f, 0x36, 0x28, 0x17, 0x17, 0x28, 0x36, 0x1f, 0x1f, + 0x36, 0x28, 0x17, 0x17, 0x28, 0x36, 0x1f, 0x19, 0x1a, 0x1a, 0x19, 0x19, + 0x1a, 0x1a, 0xdb, 0x2e, 0x38, 0x05, 0x05, 0x0e, 0x53, 0x3c, 0x4b, 0x5b, + 0x76, 0x72, 0x53, 0x2b, 0x33, 0x2f, 0x3a, 0x15, 0x51, 0x1a, 0x6f, 0x57, + 0x6a, 0x77, 0x39, 0xfe, 0xd6, 0x27, 0x36, 0x4f, 0x5b, 0x2a, 0x02, 0x25, + 0x15, 0x26, 0x35, 0x1f, 0x1f, 0x34, 0x26, 0x16, 0x15, 0x26, 0x35, 0x1f, + 0x1f, 0x34, 0x26, 0x16, 0x4b, 0x1c, 0x17, 0x22, 0x18, 0x1b, 0x1c, 0x17, + 0x22, 0x18, 0x1b, 0xfd, 0x90, 0x2f, 0x2c, 0x33, 0x34, 0x51, 0x49, 0x51, + 0x4e, 0x1a, 0x2e, 0x2f, 0x24, 0x1d, 0x48, 0x2c, 0x39, 0x61, 0x62, 0xe2, + 0x6b, 0x55, 0x26, 0x24, 0x3e, 0x3d, 0x14, 0x1b, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x04, 0xff, 0xf4, 0x02, 0x48, 0x02, 0x10, 0x00, 0x33, + 0x00, 0x3f, 0x00, 0x48, 0x00, 0xcd, 0xba, 0x00, 0x17, 0x00, 0x49, 0x00, + 0x4a, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x17, 0x10, 0xb8, 0x00, 0x37, 0xd0, + 0xb8, 0x00, 0x17, 0x10, 0xb8, 0x00, 0x44, 0xd0, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x19, 0x2f, 0x1b, + 0xb9, 0x00, 0x19, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x2d, 0x2f, 0x1b, 0xb9, 0x00, + 0x2d, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x13, 0x10, 0xb9, 0x00, 0x0c, + 0x00, 0x02, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x34, 0x00, 0x02, + 0xf4, 0xba, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x34, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x08, 0x2f, 0xba, 0x00, 0x16, 0x00, 0x13, 0x00, 0x0c, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x19, 0x10, 0xb9, 0x00, 0x40, 0x00, 0x02, 0xf4, 0xb8, + 0x00, 0x2d, 0x10, 0xb9, 0x00, 0x24, 0x00, 0x02, 0xf4, 0xba, 0x00, 0x20, + 0x00, 0x40, 0x00, 0x24, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x20, 0x2f, 0xb8, + 0x00, 0x08, 0x10, 0xb9, 0x00, 0x39, 0x00, 0x01, 0xf4, 0xba, 0x00, 0x31, + 0x00, 0x34, 0x00, 0x39, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x20, 0x10, 0xb9, + 0x00, 0x44, 0x00, 0x01, 0xf4, 0x30, 0x31, 0x17, 0x22, 0x2e, 0x02, 0x35, + 0x34, 0x36, 0x3b, 0x01, 0x35, 0x34, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, + 0x01, 0x33, 0x32, 0x16, 0x17, 0x33, 0x36, 0x33, 0x32, 0x1e, 0x02, 0x1d, + 0x01, 0x23, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x03, + 0x23, 0x22, 0x26, 0x27, 0x23, 0x0e, 0x01, 0x27, 0x32, 0x36, 0x3d, 0x01, + 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x22, 0x06, 0x1d, 0x01, + 0x33, 0x35, 0x34, 0x26, 0x89, 0x1c, 0x31, 0x24, 0x14, 0x5e, 0x58, 0x28, + 0x3b, 0x1a, 0x1b, 0x09, 0x5c, 0x11, 0x50, 0x3a, 0x2e, 0x3e, 0x11, 0x04, + 0x2a, 0x4d, 0x26, 0x3e, 0x2c, 0x18, 0xef, 0x25, 0x23, 0x1c, 0x1c, 0x08, + 0x61, 0x08, 0x19, 0x27, 0x35, 0x22, 0x35, 0x56, 0x12, 0x04, 0x09, 0x40, + 0x10, 0x20, 0x19, 0x1d, 0x25, 0x28, 0x18, 0x01, 0x0a, 0x21, 0x20, 0x82, + 0x20, 0x0c, 0x13, 0x26, 0x3a, 0x26, 0x51, 0x53, 0x2b, 0x58, 0x24, 0x20, + 0x21, 0x41, 0x3e, 0x26, 0x23, 0x49, 0x22, 0x3e, 0x58, 0x37, 0x3d, 0x0f, + 0x3a, 0x47, 0x2b, 0x1d, 0x1b, 0x1d, 0x34, 0x26, 0x16, 0x37, 0x3e, 0x3d, + 0x38, 0x5a, 0x34, 0x31, 0x31, 0x24, 0x23, 0x13, 0x1c, 0x20, 0x01, 0x68, + 0x3b, 0x2a, 0x20, 0x20, 0x2a, 0x3b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3c, + 0xff, 0x2c, 0x02, 0x1f, 0x02, 0x10, 0x00, 0x3a, 0x00, 0x72, 0xba, 0x00, + 0x29, 0x00, 0x3b, 0x00, 0x3c, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x33, 0x2f, 0x1b, + 0xb9, 0x00, 0x33, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x10, 0xb9, + 0x00, 0x07, 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x33, 0x10, 0xb9, 0x00, 0x0e, + 0x00, 0x09, 0xf4, 0xb8, 0x00, 0x33, 0x10, 0xb8, 0x00, 0x15, 0xd0, 0xb8, + 0x00, 0x33, 0x10, 0xb8, 0x00, 0x1a, 0xdc, 0x41, 0x07, 0x00, 0x0f, 0x00, + 0x1a, 0x00, 0x1f, 0x00, 0x1a, 0x00, 0x2f, 0x00, 0x1a, 0x00, 0x03, 0x5d, + 0xb8, 0x00, 0x31, 0xdc, 0xb8, 0x00, 0x29, 0xdc, 0xb9, 0x00, 0x22, 0x00, + 0x0b, 0xf4, 0x30, 0x31, 0x01, 0x32, 0x16, 0x17, 0x07, 0x2e, 0x01, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, + 0x01, 0x0f, 0x01, 0x17, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x14, 0x0e, + 0x02, 0x23, 0x22, 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, + 0x34, 0x2e, 0x02, 0x2f, 0x01, 0x37, 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, + 0x01, 0x40, 0x55, 0x67, 0x1b, 0x72, 0x0e, 0x2d, 0x2a, 0x33, 0x37, 0x37, + 0x35, 0x2b, 0x31, 0x11, 0x70, 0x1b, 0x67, 0x52, 0x09, 0x04, 0x0c, 0x18, + 0x0c, 0x1e, 0x2b, 0x16, 0x25, 0x30, 0x19, 0x34, 0x3b, 0x0d, 0x2e, 0x0a, + 0x21, 0x17, 0x13, 0x19, 0x06, 0x11, 0x1d, 0x17, 0x15, 0x0e, 0x61, 0x6c, + 0x24, 0x43, 0x61, 0x02, 0x10, 0x45, 0x39, 0x3e, 0x1e, 0x28, 0x3b, 0x33, + 0x54, 0x33, 0x3b, 0x28, 0x20, 0x40, 0x37, 0x45, 0x02, 0x2b, 0x04, 0x03, + 0x04, 0x20, 0x25, 0x1a, 0x22, 0x16, 0x09, 0x1d, 0x0f, 0x38, 0x0c, 0x11, + 0x0c, 0x0d, 0x06, 0x0c, 0x0b, 0x09, 0x02, 0x02, 0x43, 0x10, 0x8a, 0x6f, + 0x3f, 0x64, 0x46, 0x25, 0xff, 0xff, 0x00, 0x32, 0xff, 0xf4, 0x02, 0x26, + 0x03, 0x27, 0x12, 0x26, 0x00, 0x48, 0x00, 0x00, 0x10, 0x06, 0x00, 0x43, + 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x32, 0xff, 0xf4, 0x02, 0x26, + 0x03, 0x27, 0x12, 0x26, 0x00, 0x48, 0x00, 0x00, 0x10, 0x06, 0x00, 0x76, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x32, 0xff, 0xf4, 0x02, 0x26, + 0x03, 0x12, 0x00, 0x06, 0x00, 0x20, 0x00, 0x29, 0x00, 0x00, 0x01, 0x17, + 0x07, 0x27, 0x07, 0x27, 0x37, 0x13, 0x22, 0x26, 0x35, 0x34, 0x3e, 0x02, + 0x33, 0x32, 0x1e, 0x02, 0x1d, 0x01, 0x21, 0x15, 0x14, 0x16, 0x33, 0x32, + 0x36, 0x37, 0x17, 0x0e, 0x01, 0x03, 0x22, 0x06, 0x1d, 0x01, 0x33, 0x35, + 0x34, 0x26, 0x01, 0x6b, 0x84, 0x4b, 0x79, 0x79, 0x47, 0x84, 0x4b, 0x82, + 0x86, 0x23, 0x41, 0x5d, 0x3a, 0x3a, 0x5c, 0x40, 0x23, 0xfe, 0x9f, 0x3e, + 0x3c, 0x2e, 0x42, 0x18, 0x50, 0x1e, 0x6c, 0x5f, 0x30, 0x39, 0xd0, 0x37, + 0x03, 0x12, 0x9f, 0x3a, 0x73, 0x73, 0x3a, 0x9f, 0xfc, 0xe2, 0x90, 0x7c, + 0x3f, 0x65, 0x47, 0x25, 0x25, 0x44, 0x61, 0x3c, 0x2c, 0x09, 0x32, 0x3d, + 0x23, 0x1d, 0x57, 0x25, 0x36, 0x01, 0xb2, 0x3b, 0x32, 0x08, 0x08, 0x33, + 0x3a, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x32, 0xff, 0xf4, 0x02, 0x26, + 0x02, 0xe6, 0x12, 0x26, 0x00, 0x48, 0x00, 0x00, 0x10, 0x06, 0x00, 0x6a, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e, 0x00, 0x00, 0x02, 0x2e, + 0x03, 0x27, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x37, 0x33, 0x11, 0x23, + 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x13, 0x37, 0x17, 0x07, 0x5e, 0xa4, + 0xa4, 0x01, 0x38, 0x98, 0xfe, 0x30, 0x58, 0x7b, 0x63, 0x58, 0x73, 0x01, + 0x1e, 0x73, 0xfe, 0x6f, 0x73, 0x02, 0xea, 0x3d, 0xc2, 0x2b, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x5e, 0x00, 0x00, 0x02, 0x2e, 0x03, 0x27, 0x00, 0x09, + 0x00, 0x0d, 0x00, 0x00, 0x37, 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, + 0x15, 0x21, 0x13, 0x27, 0x37, 0x17, 0x5e, 0xa4, 0xa4, 0x01, 0x38, 0x98, + 0xfe, 0x30, 0xfe, 0x58, 0x63, 0x7b, 0x73, 0x01, 0x1e, 0x73, 0xfe, 0x6f, + 0x73, 0x02, 0x3a, 0x2b, 0xc2, 0x3d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e, + 0x00, 0x00, 0x02, 0x2e, 0x03, 0x12, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, + 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x03, 0x33, 0x11, 0x23, 0x35, + 0x21, 0x11, 0x33, 0x15, 0x21, 0x01, 0x8a, 0x84, 0x4b, 0x79, 0x79, 0x47, + 0x84, 0xb0, 0xa4, 0xa4, 0x01, 0x38, 0x98, 0xfe, 0x30, 0x03, 0x12, 0x9f, + 0x3a, 0x73, 0x73, 0x3a, 0x9f, 0xfd, 0x61, 0x01, 0x1e, 0x73, 0xfe, 0x6f, + 0x73, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x5e, 0x00, 0x00, 0x02, 0x2e, + 0x02, 0xe6, 0x00, 0x09, 0x00, 0x17, 0x00, 0x25, 0x00, 0x00, 0x37, 0x33, + 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x13, 0x22, 0x26, 0x3d, + 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, + 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, + 0x5e, 0xa4, 0xa4, 0x01, 0x38, 0x98, 0xfe, 0x30, 0x80, 0x2d, 0x23, 0x23, + 0x2d, 0x2d, 0x24, 0x24, 0xaf, 0x2d, 0x24, 0x24, 0x2d, 0x2d, 0x23, 0x23, + 0x73, 0x01, 0x1e, 0x73, 0xfe, 0x6f, 0x73, 0x02, 0x4f, 0x25, 0x1a, 0x1a, + 0x1a, 0x24, 0x24, 0x1a, 0x1a, 0x1a, 0x25, 0x25, 0x1a, 0x1a, 0x1a, 0x24, + 0x24, 0x1a, 0x1a, 0x1a, 0x25, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x28, + 0xff, 0xf4, 0x02, 0x31, 0x02, 0xf1, 0x00, 0x27, 0x00, 0x35, 0x00, 0x87, + 0xba, 0x00, 0x2f, 0x00, 0x36, 0x00, 0x37, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x2f, 0x10, 0xb8, 0x00, 0x0b, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x22, 0x2f, 0x1b, 0xb9, 0x00, 0x22, 0x00, 0x21, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, + 0x0b, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x15, 0x00, 0x22, 0x00, 0x0b, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x15, 0x2f, 0xba, 0x00, 0x26, 0x00, 0x22, + 0x00, 0x15, 0x11, 0x12, 0x39, 0xba, 0x00, 0x1c, 0x00, 0x26, 0x00, 0x15, + 0x11, 0x12, 0x39, 0xba, 0x00, 0x01, 0x00, 0x26, 0x00, 0x1c, 0x11, 0x12, + 0x39, 0xb9, 0x00, 0x2f, 0x00, 0x01, 0xf4, 0xba, 0x00, 0x18, 0x00, 0x2f, + 0x00, 0x15, 0x11, 0x12, 0x39, 0xba, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x1c, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x10, 0xb9, 0x00, 0x28, 0x00, 0x09, + 0xf4, 0x30, 0x31, 0x01, 0x07, 0x1e, 0x03, 0x15, 0x14, 0x0e, 0x02, 0x23, + 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, 0x17, 0x37, + 0x2e, 0x01, 0x27, 0x07, 0x27, 0x37, 0x2e, 0x01, 0x27, 0x33, 0x1e, 0x01, + 0x17, 0x37, 0x03, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x1d, 0x01, 0x14, 0x16, 0x01, 0xe3, 0x4b, 0x21, 0x38, 0x29, 0x17, 0x25, + 0x44, 0x5f, 0x3a, 0x3e, 0x62, 0x43, 0x24, 0x1d, 0x35, 0x4a, 0x2e, 0x39, + 0x4c, 0x18, 0x09, 0x0e, 0x3a, 0x2a, 0x5c, 0x33, 0x52, 0x24, 0x51, 0x2d, + 0xe2, 0x0d, 0x19, 0x0d, 0x55, 0x83, 0x32, 0x38, 0x3a, 0x31, 0x33, 0x39, + 0x3b, 0x02, 0xb5, 0x2c, 0x21, 0x4f, 0x5c, 0x6a, 0x3d, 0x4c, 0x6e, 0x46, + 0x22, 0x25, 0x44, 0x62, 0x3e, 0x38, 0x5b, 0x41, 0x23, 0x33, 0x2d, 0x04, + 0x2e, 0x57, 0x29, 0x36, 0x3c, 0x30, 0x1d, 0x34, 0x17, 0x08, 0x13, 0x0a, + 0x32, 0xfd, 0x71, 0x3e, 0x39, 0x38, 0x39, 0x3a, 0x3c, 0x39, 0x36, 0x39, + 0x3e, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x41, 0x00, 0x00, 0x02, 0x1b, + 0x02, 0xe5, 0x00, 0x19, 0x00, 0x33, 0x00, 0x00, 0x01, 0x22, 0x26, 0x27, + 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, + 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, 0x01, 0x11, + 0x33, 0x15, 0x33, 0x3e, 0x03, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x11, 0x23, + 0x11, 0x34, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x11, 0x01, 0x7a, 0x17, 0x23, + 0x13, 0x16, 0x24, 0x14, 0x11, 0x1a, 0x10, 0x34, 0x12, 0x38, 0x28, 0x17, + 0x23, 0x13, 0x16, 0x24, 0x14, 0x11, 0x1a, 0x10, 0x34, 0x12, 0x38, 0xfe, + 0x9f, 0x94, 0x06, 0x09, 0x1a, 0x25, 0x31, 0x1f, 0x25, 0x3e, 0x2c, 0x19, + 0x94, 0x57, 0x11, 0x21, 0x1a, 0x0f, 0x02, 0x50, 0x0c, 0x08, 0x09, 0x0d, + 0x0c, 0x0d, 0x44, 0x1b, 0x25, 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, + 0x1b, 0x25, 0xfd, 0xb0, 0x02, 0x04, 0x5e, 0x16, 0x26, 0x1d, 0x11, 0x19, + 0x32, 0x48, 0x2f, 0xfe, 0xb2, 0x01, 0x3a, 0x64, 0x09, 0x13, 0x1c, 0x13, + 0xfe, 0xad, 0x00, 0x00, 0xff, 0xff, 0x00, 0x29, 0xff, 0xf4, 0x02, 0x2f, + 0x03, 0x27, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x10, 0x06, 0x00, 0x43, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x29, 0xff, 0xf4, 0x02, 0x2f, + 0x03, 0x27, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x10, 0x06, 0x00, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x29, 0xff, 0xf4, 0x02, 0x2f, + 0x03, 0x12, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x28, 0x00, 0x00, 0x01, 0x17, + 0x07, 0x27, 0x07, 0x27, 0x37, 0x13, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, + 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, + 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, + 0x6a, 0x84, 0x4b, 0x79, 0x79, 0x47, 0x84, 0x3e, 0x3c, 0x60, 0x43, 0x24, + 0x24, 0x43, 0x60, 0x3c, 0x3c, 0x60, 0x43, 0x24, 0x24, 0x43, 0x60, 0x3c, + 0x32, 0x38, 0x38, 0x32, 0x32, 0x38, 0x38, 0x03, 0x12, 0x9f, 0x3a, 0x73, + 0x73, 0x3a, 0x9f, 0xfc, 0xe2, 0x25, 0x46, 0x64, 0x3f, 0x3f, 0x64, 0x46, + 0x25, 0x25, 0x46, 0x64, 0x3f, 0x3f, 0x64, 0x46, 0x25, 0x6e, 0x3e, 0x39, + 0x52, 0x39, 0x3e, 0x3e, 0x39, 0x52, 0x39, 0x3e, 0x00, 0x03, 0x00, 0x29, + 0xff, 0xf4, 0x02, 0x2f, 0x02, 0xe5, 0x00, 0x19, 0x00, 0x2d, 0x00, 0x3b, + 0x00, 0x00, 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, + 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, + 0x37, 0x17, 0x0e, 0x01, 0x03, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, + 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x78, + 0x17, 0x23, 0x13, 0x16, 0x24, 0x14, 0x11, 0x1a, 0x10, 0x34, 0x12, 0x38, + 0x28, 0x17, 0x23, 0x13, 0x16, 0x24, 0x14, 0x11, 0x1a, 0x10, 0x34, 0x12, + 0x38, 0x74, 0x3c, 0x60, 0x43, 0x24, 0x24, 0x43, 0x60, 0x3c, 0x3c, 0x60, + 0x43, 0x24, 0x24, 0x43, 0x60, 0x3c, 0x32, 0x38, 0x38, 0x32, 0x32, 0x38, + 0x38, 0x02, 0x50, 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, 0x25, + 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x0d, 0x44, 0x1b, 0x25, 0xfd, 0xa4, 0x25, + 0x46, 0x64, 0x3f, 0x3f, 0x64, 0x46, 0x25, 0x25, 0x46, 0x64, 0x3f, 0x3f, + 0x64, 0x46, 0x25, 0x6e, 0x3e, 0x39, 0x52, 0x39, 0x3e, 0x3e, 0x39, 0x52, + 0x39, 0x3e, 0x00, 0x00, 0xff, 0xff, 0x00, 0x29, 0xff, 0xf4, 0x02, 0x2f, + 0x02, 0xe6, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x10, 0x06, 0x00, 0x6a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x1d, 0x02, 0x1a, + 0x02, 0x45, 0x00, 0x03, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x43, 0xba, 0x00, + 0x04, 0x00, 0x20, 0x00, 0x21, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x04, 0x10, + 0xb8, 0x00, 0x00, 0xd0, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, 0x12, 0xd0, + 0x00, 0xbb, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x2b, 0xb8, + 0x00, 0x00, 0x10, 0xb8, 0x00, 0x0b, 0xdc, 0xb9, 0x00, 0x04, 0x00, 0x07, + 0xf4, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x12, 0xdc, 0xb9, 0x00, 0x19, + 0x00, 0x07, 0xf4, 0x30, 0x31, 0x37, 0x35, 0x21, 0x15, 0x07, 0x22, 0x26, + 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x03, + 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, + 0x06, 0x3e, 0x01, 0xdc, 0xee, 0x30, 0x28, 0x28, 0x30, 0x30, 0x28, 0x28, + 0x30, 0x30, 0x28, 0x28, 0x30, 0x30, 0x28, 0x28, 0xf6, 0x76, 0x76, 0xd9, + 0x28, 0x1d, 0x18, 0x1d, 0x28, 0x28, 0x1d, 0x18, 0x1d, 0x28, 0x01, 0x86, + 0x28, 0x1d, 0x18, 0x1d, 0x28, 0x28, 0x1d, 0x18, 0x1d, 0x28, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x17, 0xff, 0xc5, 0x02, 0x41, 0x02, 0x3f, 0x00, 0x19, + 0x00, 0x23, 0x00, 0x2d, 0x00, 0x9f, 0xba, 0x00, 0x15, 0x00, 0x2e, 0x00, + 0x2f, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x15, 0x10, 0xb8, 0x00, 0x1a, 0xd0, + 0xb8, 0x00, 0x15, 0x10, 0xb8, 0x00, 0x24, 0xd0, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x15, 0x2f, 0x1b, + 0xb9, 0x00, 0x15, 0x00, 0x11, 0x3e, 0x59, 0xba, 0x00, 0x01, 0x00, 0x08, + 0x00, 0x15, 0x11, 0x12, 0x39, 0xb9, 0x00, 0x24, 0x00, 0x09, 0xf4, 0xba, + 0x00, 0x0b, 0x00, 0x08, 0x00, 0x24, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0e, + 0x00, 0x08, 0x00, 0x24, 0x11, 0x12, 0x39, 0xba, 0x00, 0x18, 0x00, 0x08, + 0x00, 0x15, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x08, 0x10, 0xb9, 0x00, 0x1a, + 0x00, 0x09, 0xf4, 0xba, 0x00, 0x21, 0x00, 0x08, 0x00, 0x24, 0x11, 0x12, + 0x39, 0xba, 0x00, 0x22, 0x00, 0x1a, 0x00, 0x15, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x15, 0x11, 0x12, 0x39, 0xba, 0x00, 0x2c, + 0x00, 0x08, 0x00, 0x24, 0x11, 0x12, 0x39, 0x30, 0x31, 0x3f, 0x01, 0x26, + 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, 0x17, 0x37, 0x17, 0x07, 0x16, + 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x07, 0x13, 0x22, 0x06, + 0x1d, 0x01, 0x1c, 0x01, 0x17, 0x37, 0x26, 0x03, 0x32, 0x36, 0x3d, 0x01, + 0x3c, 0x01, 0x27, 0x07, 0x16, 0x17, 0x45, 0x33, 0x24, 0x43, 0x60, 0x3c, + 0x26, 0x42, 0x1b, 0x40, 0x52, 0x45, 0x33, 0x24, 0x43, 0x60, 0x3c, 0x26, + 0x42, 0x1b, 0x40, 0xc3, 0x32, 0x38, 0x02, 0xa5, 0x19, 0x24, 0x32, 0x38, + 0x02, 0xa5, 0x19, 0x01, 0x53, 0x43, 0x6b, 0x3f, 0x64, 0x46, 0x25, 0x10, + 0x0e, 0x4d, 0x3c, 0x53, 0x44, 0x6a, 0x3f, 0x64, 0x46, 0x25, 0x10, 0x0e, + 0x4d, 0x01, 0xdd, 0x3e, 0x39, 0x4a, 0x06, 0x0e, 0x05, 0xc9, 0x11, 0xfe, + 0xc0, 0x3e, 0x39, 0x4a, 0x06, 0x0e, 0x05, 0xc9, 0x11, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x3d, 0xff, 0xf4, 0x02, 0x17, 0x03, 0x27, 0x12, 0x26, + 0x00, 0x58, 0x00, 0x00, 0x10, 0x06, 0x00, 0x43, 0xff, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x3d, 0xff, 0xf4, 0x02, 0x17, 0x03, 0x27, 0x12, 0x26, + 0x00, 0x58, 0x00, 0x00, 0x10, 0x06, 0x00, 0x76, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x3d, 0xff, 0xf4, 0x02, 0x17, 0x03, 0x12, 0x00, 0x06, + 0x00, 0x1e, 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x13, + 0x23, 0x0e, 0x01, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, + 0x33, 0x32, 0x3e, 0x02, 0x35, 0x11, 0x33, 0x11, 0x23, 0x01, 0x69, 0x84, + 0x4b, 0x79, 0x79, 0x47, 0x84, 0x96, 0x06, 0x11, 0x49, 0x3e, 0x25, 0x3e, + 0x2c, 0x19, 0x94, 0x57, 0x11, 0x21, 0x19, 0x10, 0x94, 0x94, 0x03, 0x12, + 0x9f, 0x3a, 0x73, 0x73, 0x3a, 0x9f, 0xfd, 0x4c, 0x2c, 0x3e, 0x19, 0x32, + 0x48, 0x2f, 0x01, 0x4e, 0xfe, 0xc6, 0x64, 0x09, 0x13, 0x1c, 0x13, 0x01, + 0x53, 0xfd, 0xfc, 0x00, 0xff, 0xff, 0x00, 0x3d, 0xff, 0xf4, 0x02, 0x17, + 0x02, 0xe6, 0x12, 0x26, 0x00, 0x58, 0x00, 0x00, 0x10, 0x06, 0x00, 0x6a, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x13, 0xff, 0x38, 0x02, 0x45, + 0x03, 0x27, 0x12, 0x26, 0x00, 0x5c, 0x00, 0x00, 0x10, 0x06, 0x00, 0x76, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3b, 0xff, 0x38, 0x02, 0x31, + 0x02, 0xe4, 0x00, 0x16, 0x00, 0x24, 0x00, 0x81, 0xba, 0x00, 0x17, 0x00, + 0x25, 0x00, 0x26, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x17, 0x10, 0xb8, 0x00, + 0x10, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x21, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1d, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x16, 0x2f, 0x1b, 0xb9, + 0x00, 0x16, 0x00, 0x13, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x11, 0x3e, 0x59, 0xb8, + 0x00, 0x06, 0x10, 0xb9, 0x00, 0x1e, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x02, + 0x00, 0x1e, 0x00, 0x06, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x10, 0x10, 0xb9, + 0x00, 0x17, 0x00, 0x09, 0xf4, 0xba, 0x00, 0x13, 0x00, 0x17, 0x00, 0x10, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x13, 0x33, 0x11, 0x33, 0x3e, 0x01, 0x33, + 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x23, + 0x11, 0x23, 0x13, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x1d, 0x01, 0x14, 0x16, 0x3b, 0x94, 0x07, 0x13, 0x48, 0x3e, 0x2b, 0x47, + 0x33, 0x1d, 0x1d, 0x33, 0x47, 0x2b, 0x3e, 0x48, 0x13, 0x07, 0x94, 0xf4, + 0x32, 0x36, 0x36, 0x32, 0x27, 0x39, 0x39, 0x02, 0xe4, 0xfe, 0xc2, 0x2e, + 0x3c, 0x20, 0x42, 0x66, 0x46, 0x46, 0x66, 0x42, 0x20, 0x3b, 0x2f, 0xfe, + 0xda, 0x01, 0x2f, 0x3d, 0x36, 0x50, 0x36, 0x3d, 0x26, 0x29, 0x98, 0x29, + 0x26, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x13, 0xff, 0x38, 0x02, 0x45, + 0x02, 0xe6, 0x12, 0x26, 0x00, 0x5c, 0x00, 0x00, 0x10, 0x06, 0x00, 0x6a, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x04, 0x9e, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x5c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0xa6, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0xbe, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1b, 0x00, 0xfb, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x01, 0x3d, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x6c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x01, 0x9c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x51, 0x02, 0x51, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x02, 0xbb, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x33, 0x03, 0x2f, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x19, 0x03, 0x97, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x12, 0x03, 0xd7, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x90, 0x05, 0x0c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x05, 0xd3, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x3a, 0x06, 0x64, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x12, 0x0c, 0x16, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x18, 0x06, 0x9f, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x12, 0x0b, 0xdd, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x11, 0x07, 0x26, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x13, 0x0b, 0xa3, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x09, 0x07, 0x5d, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x11, 0x0b, 0x69, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x0b, 0x07, 0x79, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x1a, 0x0b, 0x2a, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x11, 0x07, 0xa5, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x15, 0x0a, 0xde, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x18, 0x08, 0x14, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x09, 0x08, 0x7b, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x18, 0x0a, 0x99, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x00, 0x09, 0x08, 0xb8, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x0c, 0x08, 0xf6, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x12, 0x09, 0x3e, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x12, 0x09, 0x9e, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x12, 0x0a, 0x05, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x18, 0x06, 0xb8, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x12, 0x07, 0x38, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x09, 0x07, 0x67, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x12, 0x07, 0x85, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x04, 0x00, 0x1f, 0x07, 0xb7, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x05, 0x00, 0x1a, 0x08, 0x2d, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00, 0x13, 0x08, 0x85, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x13, 0x08, 0xc2, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x10, 0x09, 0x03, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x16, 0x09, 0x51, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x1f, 0x09, 0xb1, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x0b, 0x00, 0x23, 0x0a, 0x18, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x21, 0x06, 0xd1, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x04, 0x00, 0x17, 0x07, 0xd7, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x05, 0x00, 0x06, 0x08, 0x48, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x0c, 0x08, 0x99, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x07, 0x00, 0x0c, 0x08, 0xd6, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x08, 0x00, 0x0b, 0x09, 0x14, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x09, 0x00, 0x10, 0x09, 0x68, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x0a, 0x00, 0x10, 0x09, 0xd1, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x0b, 0x00, 0x0f, 0x0a, 0x3c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x15, 0x06, 0xf3, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x04, 0x00, 0x11, 0x07, 0xef, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x05, 0x00, 0x11, 0x08, 0x4f, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x06, 0x00, 0x05, 0x08, 0xa6, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x07, 0x00, 0x06, 0x08, 0xe3, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x08, 0x00, 0x10, 0x09, 0x20, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x09, 0x00, 0x12, 0x09, 0x79, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x0a, 0x00, 0x13, 0x09, 0xe2, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x0b, 0x00, 0x0c, 0x0a, 0x4c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x1c, 0x07, 0x09, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x11, 0x07, 0x4b, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x00, 0x07, 0x07, 0x71, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x03, 0x00, 0x0c, 0x07, 0x98, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x04, 0x00, 0x12, 0x08, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x05, 0x00, 0x19, 0x08, 0x61, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x06, 0x00, 0x0b, 0x08, 0xac, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x07, 0x00, 0x0b, 0x08, 0xea, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x08, 0x00, 0x0c, 0x09, 0x31, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x09, 0x00, 0x11, 0x09, 0x8c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x0a, 0x00, 0x0e, 0x09, 0xf6, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x0b, 0x00, 0x0d, 0x0a, 0x59, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x8a, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x08, 0x00, 0xb4, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x36, 0x00, 0xc3, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x24, 0x01, 0x17, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x1a, 0x01, 0x50, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x20, 0x01, 0x7a, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x07, 0x00, 0xa2, 0x01, 0xad, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x08, 0x00, 0x16, 0x02, 0xa3, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x09, 0x00, 0x66, 0x02, 0xc7, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0b, 0x00, 0x32, 0x03, 0x63, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0c, 0x00, 0x24, 0x03, 0xb1, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0d, 0x01, 0x20, 0x03, 0xea, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0e, 0x00, 0x34, 0x05, 0x9d, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x13, 0x00, 0x74, 0x05, 0xee, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x00, 0x00, 0x24, 0x0b, 0xf0, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x01, 0x00, 0x24, 0x0b, 0xb7, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x02, 0x00, 0x26, 0x0b, 0x7b, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x03, 0x00, 0x22, 0x0b, 0x45, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x04, 0x00, 0x34, 0x0a, 0xf4, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x05, 0x00, 0x2a, 0x0a, 0xb2, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x06, 0x00, 0x30, 0x0a, 0x67, 0x00, 0x43, + 0x00, 0x6f, 0x00, 0x70, 0x00, 0x79, 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, + 0x00, 0x68, 0x00, 0x74, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, + 0x00, 0x37, 0x00, 0x20, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, + 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x2e, 0x00, 0x20, + 0x00, 0x41, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x72, 0x00, 0x69, + 0x00, 0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x73, 0x00, 0x20, 0x00, 0x72, + 0x00, 0x65, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x65, + 0x00, 0x64, 0x00, 0x2e, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x32, 0x30, 0x31, 0x37, 0x20, 0x49, 0x42, 0x4d, + 0x20, 0x43, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x2e, 0x00, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, + 0x00, 0x50, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, 0x20, 0x00, 0x4d, + 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x00, 0x49, 0x42, 0x4d, 0x20, + 0x50, 0x6c, 0x65, 0x78, 0x20, 0x4d, 0x6f, 0x6e, 0x6f, 0x00, 0x00, 0x42, + 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x00, 0x42, 0x6f, 0x6c, 0x64, + 0x00, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x34, 0x00, + 0x3b, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, 0x00, 0x3b, 0x00, + 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x65, 0x00, + 0x78, 0x00, 0x4d, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x2d, 0x00, + 0x42, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x00, 0x32, 0x2e, 0x30, + 0x30, 0x34, 0x3b, 0x49, 0x42, 0x4d, 0x20, 0x3b, 0x49, 0x42, 0x4d, 0x50, + 0x6c, 0x65, 0x78, 0x4d, 0x6f, 0x6e, 0x6f, 0x2d, 0x42, 0x6f, 0x6c, 0x64, + 0x00, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, 0x00, 0x50, 0x00, + 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, 0x20, 0x00, 0x4d, 0x00, 0x6f, 0x00, + 0x6e, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6c, 0x00, + 0x64, 0x00, 0x00, 0x49, 0x42, 0x4d, 0x20, 0x50, 0x6c, 0x65, 0x78, 0x20, + 0x4d, 0x6f, 0x6e, 0x6f, 0x20, 0x42, 0x6f, 0x6c, 0x64, 0x00, 0x00, 0x56, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, + 0x00, 0x20, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x34, + 0x00, 0x00, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x2e, + 0x30, 0x30, 0x34, 0x00, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x50, + 0x00, 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, 0x4d, 0x00, 0x6f, 0x00, 0x6e, + 0x00, 0x6f, 0x00, 0x2d, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, + 0x00, 0x00, 0x49, 0x42, 0x4d, 0x50, 0x6c, 0x65, 0x78, 0x4d, 0x6f, 0x6e, + 0x6f, 0x2d, 0x42, 0x6f, 0x6c, 0x64, 0x00, 0x00, 0x49, 0x00, 0x42, 0x00, + 0x4d, 0x00, 0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, + 0xae, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, + 0x20, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, + 0x6d, 0x00, 0x61, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x6f, 0x00, + 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, 0x00, + 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x2c, 0x00, 0x20, 0x00, + 0x72, 0x00, 0x65, 0x00, 0x67, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x69, 0x00, + 0x6e, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x79, 0x00, + 0x20, 0x00, 0x6a, 0x00, 0x75, 0x00, 0x72, 0x00, 0x69, 0x00, 0x73, 0x00, + 0x64, 0x00, 0x69, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, + 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x72, 0x00, + 0x6c, 0x00, 0x64, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, 0x00, + 0x2e, 0x00, 0x00, 0x49, 0x42, 0x4d, 0x20, 0x50, 0x6c, 0x65, 0x78, 0xa8, + 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x61, 0x64, 0x65, 0x6d, + 0x61, 0x72, 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x49, 0x42, 0x4d, 0x20, 0x43, + 0x6f, 0x72, 0x70, 0x2c, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, + 0x6a, 0x75, 0x72, 0x69, 0x73, 0x64, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x77, 0x69, 0x64, 0x65, 0x2e, + 0x00, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x20, 0x00, + 0x4d, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x79, 0x00, + 0x00, 0x42, 0x6f, 0x6c, 0x64, 0x20, 0x4d, 0x6f, 0x6e, 0x64, 0x61, 0x79, + 0x00, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x6b, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x41, 0x00, 0x62, 0x00, 0x62, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6b, 0x00, + 0x2c, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61, 0x00, 0x75, 0x00, 0x6c, 0x00, + 0x20, 0x00, 0x76, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x64, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x61, 0x00, 0x61, 0x00, + 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x50, 0x00, 0x69, 0x00, 0x65, 0x00, + 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x76, 0x00, 0x61, 0x00, + 0x6e, 0x00, 0x20, 0x00, 0x52, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6d, 0x00, + 0x61, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x4d, 0x69, 0x6b, + 0x65, 0x20, 0x41, 0x62, 0x62, 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x50, 0x61, + 0x75, 0x6c, 0x20, 0x76, 0x61, 0x6e, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4c, + 0x61, 0x61, 0x6e, 0x2c, 0x20, 0x50, 0x69, 0x65, 0x74, 0x65, 0x72, 0x20, + 0x76, 0x61, 0x6e, 0x20, 0x52, 0x6f, 0x73, 0x6d, 0x61, 0x6c, 0x65, 0x6e, + 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, + 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, + 0x62, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x6f, 0x00, + 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x79, 0x00, 0x2e, 0x00, 0x63, 0x00, + 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x62, 0x6f, 0x6c, 0x64, 0x6d, 0x6f, 0x6e, 0x64, + 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, + 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, + 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x69, 0x00, 0x62, 0x00, 0x6d, 0x00, + 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x62, 0x6d, 0x2e, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, + 0x00, 0x20, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, + 0x00, 0x53, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x77, 0x00, 0x61, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, + 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, + 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4c, 0x00, 0x20, 0x00, 0x4f, + 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6f, + 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x63, + 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00, 0x20, + 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, + 0x00, 0x6e, 0x00, 0x20, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x2e, + 0x00, 0x20, 0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, + 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, + 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, + 0x00, 0x76, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x62, + 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x74, + 0x00, 0x68, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x46, 0x00, 0x41, + 0x00, 0x51, 0x00, 0x20, 0x00, 0x61, 0x00, 0x74, 0x00, 0x3a, 0x00, 0x20, + 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, + 0x00, 0x2f, 0x00, 0x73, 0x00, 0x63, 0x00, 0x72, 0x00, 0x69, 0x00, 0x70, + 0x00, 0x74, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6c, + 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x4f, + 0x00, 0x46, 0x00, 0x4c, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x46, + 0x6f, 0x6e, 0x74, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x20, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x64, + 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, + 0x49, 0x4c, 0x20, 0x4f, 0x70, 0x65, 0x6e, 0x20, 0x46, 0x6f, 0x6e, 0x74, + 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x31, 0x2e, 0x20, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, + 0x69, 0x73, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x46, 0x41, 0x51, 0x20, + 0x61, 0x74, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x2e, 0x73, 0x69, 0x6c, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x4f, 0x46, 0x4c, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, + 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x73, 0x00, + 0x63, 0x00, 0x72, 0x00, 0x69, 0x00, 0x70, 0x00, 0x74, 0x00, 0x73, 0x00, + 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6f, 0x00, + 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x4c, 0x00, + 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x73, 0x2e, 0x73, 0x69, 0x6c, 0x2e, 0x6f, 0x72, 0x67, 0x2f, + 0x4f, 0x46, 0x4c, 0x00, 0x00, 0x48, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x20, + 0x00, 0x72, 0x00, 0x61, 0x00, 0x7a, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x62, + 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x2d, 0x00, 0x6a, 0x00, 0x75, + 0x00, 0x6d, 0x00, 0x70, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x20, + 0x00, 0x66, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x73, 0x00, 0x20, + 0x00, 0x63, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x65, + 0x00, 0x76, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x73, 0x00, 0x69, + 0x00, 0x78, 0x00, 0x20, 0x00, 0x70, 0x00, 0x69, 0x00, 0x71, 0x00, 0x75, + 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x67, 0x00, 0x79, 0x00, 0x6d, + 0x00, 0x6e, 0x00, 0x61, 0x00, 0x73, 0x00, 0x74, 0x00, 0x73, 0x00, 0x21, + 0x00, 0x00, 0x48, 0x6f, 0x77, 0x20, 0x72, 0x61, 0x7a, 0x6f, 0x72, 0x62, + 0x61, 0x63, 0x6b, 0x2d, 0x6a, 0x75, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x20, + 0x66, 0x72, 0x6f, 0x67, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x20, 0x73, 0x69, 0x78, 0x20, 0x70, 0x69, 0x71, 0x75, + 0x65, 0x64, 0x20, 0x67, 0x79, 0x6d, 0x6e, 0x61, 0x73, 0x74, 0x73, 0x21, + 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x54, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x00, 0x46, 0x6f, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, + 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x71, 0x75, + 0x65, 0x73, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x6f, + 0x67, 0x72, 0x61, 0x66, 0x69, 0x73, 0x63, 0x68, 0x65, 0x6e, 0x20, 0x4d, + 0x9a, 0x67, 0x6c, 0x69, 0x63, 0x68, 0x6b, 0x65, 0x69, 0x74, 0x65, 0x6e, + 0x00, 0x46, 0x75, 0x6e, 0x7a, 0x69, 0x6f, 0x6e, 0x69, 0x20, 0x54, 0x69, + 0x70, 0x6f, 0x67, 0x72, 0x61, 0x66, 0x69, 0x63, 0x68, 0x65, 0x00, 0x41, + 0x6c, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x66, + 0x69, 0x73, 0x63, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x6e, 0x6d, 0x65, 0x72, + 0x6b, 0x65, 0x6e, 0x00, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, + 0x20, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x50, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x56, 0x65, 0x72, 0x74, 0x69, + 0x63, 0x61, 0x6c, 0x65, 0x00, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, + 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x65, 0x00, 0x46, + 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x46, 0x72, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x42, 0x72, 0x65, 0x75, 0x6b, + 0x65, 0x6e, 0x00, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x43, 0x61, + 0x73, 0x65, 0x00, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x64, 0x65, 0x73, + 0x20, 0x43, 0x68, 0x69, 0x66, 0x66, 0x72, 0x65, 0x73, 0x00, 0x4e, 0x75, + 0x6d, 0x6d, 0x65, 0x72, 0x68, 0x6f, 0x6f, 0x67, 0x74, 0x65, 0x00, 0x41, + 0x6c, 0x6c, 0x20, 0x54, 0x79, 0x70, 0x65, 0x20, 0x46, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x00, 0x54, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x20, + 0x66, 0x6f, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x79, + 0x70, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x71, 0x75, 0x65, 0x73, + 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, 0x41, 0x75, 0x73, 0x7a, 0x65, 0x69, + 0x63, 0x68, 0x6e, 0x75, 0x6e, 0x67, 0x73, 0x61, 0x72, 0x74, 0x65, 0x6e, + 0x00, 0x54, 0x75, 0x74, 0x74, 0x65, 0x20, 0x6c, 0x65, 0x20, 0x46, 0x75, + 0x6e, 0x7a, 0x69, 0x6f, 0x6e, 0x69, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, + 0x74, 0x79, 0x70, 0x65, 0x6b, 0x65, 0x6e, 0x6d, 0x65, 0x72, 0x6b, 0x65, + 0x6e, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x20, 0x56, 0x65, 0x72, + 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x00, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x4e, 0x6f, + 0x72, 0x6d, 0x61, 0x6c, 0x65, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, + 0x00, 0x50, 0x6f, 0x73, 0x69, 0x7a, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x4e, + 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x65, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, + 0x6c, 0x65, 0x20, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x65, + 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x65, 0x00, 0x53, 0x75, 0x70, + 0x65, 0x72, 0x69, 0x6f, 0x72, 0x73, 0x00, 0x50, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x75, 0x70, 0x8e, 0x72, 0x69, 0x65, 0x75, + 0x72, 0x65, 0x00, 0x48, 0x6f, 0x63, 0x68, 0x67, 0x65, 0x73, 0x74, 0x65, + 0x6c, 0x6c, 0x74, 0x00, 0x41, 0x70, 0x69, 0x63, 0x65, 0x00, 0x53, 0x75, + 0x70, 0x65, 0x72, 0x69, 0x65, 0x75, 0x72, 0x65, 0x6e, 0x00, 0x49, 0x6e, + 0x66, 0x65, 0x72, 0x69, 0x6f, 0x72, 0x73, 0x00, 0x50, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x6e, 0x66, 0x8e, 0x72, 0x69, 0x65, + 0x75, 0x72, 0x65, 0x00, 0x54, 0x69, 0x65, 0x66, 0x67, 0x65, 0x73, 0x74, + 0x65, 0x6c, 0x6c, 0x74, 0x00, 0x50, 0x65, 0x64, 0x69, 0x63, 0x65, 0x00, + 0x49, 0x6e, 0x66, 0x65, 0x72, 0x69, 0x65, 0x75, 0x72, 0x65, 0x6e, 0x00, + 0x4e, 0x6f, 0x20, 0x46, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x00, 0x50, 0x61, 0x73, 0x20, 0x64, 0x65, 0x20, 0x46, 0x72, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x4b, 0x65, 0x69, 0x6e, 0x20, 0x42, + 0x72, 0x75, 0x63, 0x68, 0x65, 0x00, 0x4e, 0x65, 0x73, 0x73, 0x75, 0x6e, + 0x61, 0x20, 0x46, 0x72, 0x61, 0x7a, 0x69, 0x6f, 0x6e, 0x65, 0x00, 0x47, + 0x65, 0x65, 0x6e, 0x20, 0x62, 0x72, 0x65, 0x75, 0x6b, 0x65, 0x6e, 0x00, + 0x44, 0x69, 0x61, 0x67, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x46, 0x72, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x46, 0x72, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x65, 0x6e, 0x20, 0x44, 0x69, 0x61, 0x67, + 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x00, 0x44, 0x69, 0x61, 0x67, 0x6f, 0x6e, + 0x61, 0x6c, 0x65, 0x72, 0x20, 0x42, 0x72, 0x75, 0x63, 0x68, 0x00, 0x46, + 0x72, 0x61, 0x7a, 0x69, 0x6f, 0x6e, 0x69, 0x20, 0x44, 0x69, 0x61, 0x67, + 0x6f, 0x6e, 0x61, 0x6c, 0x69, 0x00, 0x44, 0x69, 0x61, 0x67, 0x6f, 0x6e, + 0x61, 0x6c, 0x65, 0x20, 0x62, 0x72, 0x65, 0x75, 0x6b, 0x65, 0x6e, 0x00, + 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x43, 0x61, 0x73, 0x65, 0x20, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00, 0x43, 0x68, 0x69, 0x66, 0x66, + 0x72, 0x65, 0x73, 0x20, 0x41, 0x6e, 0x63, 0x69, 0x65, 0x6e, 0x73, 0x20, + 0x28, 0x62, 0x61, 0x73, 0x20, 0x64, 0x65, 0x20, 0x63, 0x61, 0x73, 0x73, + 0x65, 0x29, 0x00, 0x4d, 0x65, 0x64, 0x69, 0xbe, 0x76, 0x61, 0x6c, 0x2d, + 0x5a, 0x69, 0x66, 0x66, 0x65, 0x72, 0x6e, 0x00, 0x53, 0x6f, 0x70, 0x72, + 0x61, 0x20, 0x6c, 0x61, 0x20, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x20, 0x42, + 0x61, 0x73, 0x65, 0x00, 0x4b, 0x6c, 0x65, 0x69, 0x6e, 0x65, 0x20, 0x6e, + 0x75, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x00, 0x55, 0x70, 0x70, 0x65, 0x72, + 0x20, 0x43, 0x61, 0x73, 0x65, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x00, 0x43, 0x68, 0x69, 0x66, 0x66, 0x72, 0x65, 0x73, 0x20, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x20, 0x28, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x61, 0x6e, 0x74, 0x73, + 0x29, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x65, 0x20, 0x5a, 0x69, + 0x66, 0x66, 0x65, 0x72, 0x6e, 0x00, 0x54, 0x72, 0x61, 0x64, 0x69, 0x7a, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x00, 0x47, 0x72, 0x6f, 0x74, 0x65, + 0x20, 0x6e, 0x75, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x00, 0x00, 0x42, 0x00, + 0x75, 0x00, 0x6c, 0x00, 0x67, 0x00, 0x61, 0x00, 0x72, 0x00, 0x69, 0x00, + 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x43, 0x00, 0x79, 0x00, 0x72, 0x00, + 0x69, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x20, 0x00, + 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x00, 0x42, + 0x75, 0x6c, 0x67, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x43, 0x79, 0x72, + 0x69, 0x6c, 0x6c, 0x69, 0x63, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x00, + 0x00, 0x61, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, + 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x75, + 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x73, + 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x00, 0x61, 0x6c, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x20, 0x73, 0x69, 0x67, 0x6e, 0x00, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x74, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x65, 0x00, 0x72, + 0x00, 0x63, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x20, 0x00, 0x65, + 0x00, 0x73, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x00, + 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x6c, 0x6f, + 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, 0x65, 0x73, 0x7a, 0x65, + 0x74, 0x74, 0x00, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x69, 0x00, + 0x6e, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x6f, 0x00, 0x00, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x7a, 0x65, 0x72, 0x6f, 0x00, 0x00, 0x73, 0x00, + 0x6c, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x65, 0x00, 0x64, 0x00, + 0x20, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, + 0x72, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6f, 0x00, + 0x00, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x7a, 0x65, 0x72, 0x6f, 0x00, 0x00, 0x73, 0x00, + 0x69, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x6c, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x65, 0x00, 0x72, 0x00, 0x63, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x20, 0x00, 0x67, 0x00, 0x00, 0x73, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, + 0x61, 0x73, 0x65, 0x20, 0x67, 0x00, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6d, + 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x6f, + 0x00, 0x77, 0x00, 0x65, 0x00, 0x72, 0x00, 0x63, 0x00, 0x61, 0x00, 0x73, + 0x00, 0x65, 0x00, 0x20, 0x00, 0x61, 0x00, 0x00, 0x73, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, + 0x20, 0x61, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x9c, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, + 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, + 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, + 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, + 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, + 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, + 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, + 0x00, 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, + 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, + 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x40, + 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, + 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, + 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, + 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, + 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, + 0x00, 0x5f, 0x00, 0x60, 0x00, 0x61, 0x01, 0x03, 0x00, 0xa3, 0x00, 0x84, + 0x00, 0x85, 0x00, 0xbd, 0x00, 0x96, 0x00, 0xe8, 0x00, 0x86, 0x00, 0x8e, + 0x00, 0x8b, 0x00, 0x9d, 0x00, 0xa9, 0x00, 0xa4, 0x01, 0x04, 0x00, 0x8a, + 0x00, 0xda, 0x00, 0x83, 0x00, 0x93, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0x8d, + 0x00, 0x97, 0x00, 0x88, 0x00, 0xc3, 0x00, 0xde, 0x00, 0xf1, 0x00, 0x9e, + 0x00, 0xaa, 0x00, 0xf5, 0x00, 0xf4, 0x00, 0xf6, 0x00, 0xa2, 0x00, 0xad, + 0x00, 0xc9, 0x00, 0xc7, 0x00, 0xae, 0x00, 0x62, 0x00, 0x63, 0x00, 0x90, + 0x00, 0x64, 0x00, 0xcb, 0x00, 0x65, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcf, + 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xe9, 0x00, 0x66, 0x00, 0xd3, + 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xaf, 0x00, 0x67, 0x00, 0xf0, 0x00, 0x91, + 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0x68, 0x00, 0xeb, 0x00, 0xed, + 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x6b, 0x00, 0x6d, 0x00, 0x6c, + 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x70, 0x00, 0x72, + 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0xea, + 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x7c, + 0x00, 0xb8, 0x00, 0xa1, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x81, + 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, + 0x30, 0x44, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, 0x41, 0x30, 0x07, 0x75, + 0x6e, 0x69, 0x30, 0x30, 0x41, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, + 0x00, 0x08, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x07, 0xff, 0xff, 0x00, 0x0f, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x00, 0x01, 0x01, + 0x00, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0xc0, 0x00, 0x01, 0x02, + 0x00, 0x15, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0xc0, 0x01, 0x01, 0x03, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x05, 0x00, 0x01, 0x01, 0x06, + 0x00, 0x02, 0x01, 0x07, 0x00, 0x00, 0x01, 0x08, 0x00, 0x02, 0x01, 0x09, + 0x00, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x01, 0x0b, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfd, 0x00, 0x0b, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, 0x00, 0x0a, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0xef, 0x00, 0x0a, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xf7, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x15, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xdf, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0xb0, + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x16, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x12, 0x00, 0x12, 0x00, 0x1e, 0x00, 0x17, 0x00, 0x14, 0x00, 0x20, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, + 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa0, 0x00, 0x00, 0x03, 0x00, 0x05, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa0, 0x00, 0x00, 0x06, 0x3f, 0xff, 0xff, 0xeb, 0x3f, 0xff, 0xff, 0xef, + 0xbf, 0xff, 0xff, 0xee, 0x3f, 0xff, 0xff, 0xec, 0x3f, 0xff, 0xff, 0xf2, + 0xbf, 0xff, 0xff, 0xf1, 0x3f, 0xff, 0xff, 0xef, 0x3f, 0xff, 0xff, 0xf5, + 0xbf, 0xff, 0xff, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x7e, 0x00, 0x80, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x14, 0x00, 0x18, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x75, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x16, 0xe7, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0xe1, 0xa9, 0xde, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0xe5, 0x4d, 0x1e, 0x99}; +unsigned int MwBoldMonospaceTTFDataSize = 36184; +#endif diff --git a/widget/milsko/milskosrc/src/text/font/boldttf.c b/widget/milsko/milskosrc/src/text/font/boldttf.c new file mode 100644 index 0000000000..2ec91c7ff0 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/font/boldttf.c @@ -0,0 +1,3052 @@ +#include + +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) +unsigned char MwBoldTTFData[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04, 0x00, 0x20, + 0x46, 0x46, 0x54, 0x4d, 0x94, 0x9f, 0x60, 0x18, 0x00, 0x00, 0x8e, 0xa8, + 0x00, 0x00, 0x00, 0x1c, 0x4f, 0x53, 0x2f, 0x32, 0xa2, 0x6c, 0xa1, 0xa5, + 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70, + 0x09, 0xe8, 0xe7, 0x70, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x01, 0x4a, + 0x63, 0x76, 0x74, 0x20, 0x13, 0x2d, 0x1a, 0x94, 0x00, 0x00, 0x0f, 0x34, + 0x00, 0x00, 0x00, 0xaa, 0x66, 0x65, 0x61, 0x74, 0xc0, 0x1a, 0x05, 0x59, + 0x00, 0x00, 0x8e, 0x78, 0x00, 0x00, 0x00, 0x30, 0x66, 0x70, 0x67, 0x6d, + 0xbb, 0x73, 0xa4, 0x75, 0x00, 0x00, 0x06, 0x5c, 0x00, 0x00, 0x07, 0xe0, + 0x67, 0x61, 0x73, 0x70, 0x00, 0x08, 0x00, 0x1b, 0x00, 0x00, 0x8d, 0xf4, + 0x00, 0x00, 0x00, 0x0c, 0x67, 0x6c, 0x79, 0x66, 0x5b, 0x0c, 0x09, 0x3e, + 0x00, 0x00, 0x11, 0x68, 0x00, 0x00, 0x57, 0x30, 0x68, 0x65, 0x61, 0x64, + 0x15, 0x93, 0x86, 0x3a, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x00, 0x36, + 0x68, 0x68, 0x65, 0x61, 0x0f, 0xb4, 0x05, 0xf1, 0x00, 0x00, 0x01, 0x64, + 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 0x81, 0x02, 0x45, 0x0f, + 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x03, 0x08, 0x6b, 0x65, 0x72, 0x6e, + 0x4a, 0x11, 0x58, 0x96, 0x00, 0x00, 0x68, 0x98, 0x00, 0x00, 0x1a, 0x76, + 0x6c, 0x6f, 0x63, 0x61, 0xcc, 0x0a, 0xb6, 0xe0, 0x00, 0x00, 0x0f, 0xe0, + 0x00, 0x00, 0x01, 0x86, 0x6d, 0x61, 0x78, 0x70, 0x02, 0x3a, 0x01, 0x34, + 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x20, 0x6d, 0x6f, 0x72, 0x78, + 0x00, 0x32, 0x00, 0xbb, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x6e, 0x61, 0x6d, 0x65, 0x1f, 0x23, 0x2a, 0x61, 0x00, 0x00, 0x83, 0x10, + 0x00, 0x00, 0x09, 0x2c, 0x70, 0x6f, 0x73, 0x74, 0xb1, 0xe2, 0x4e, 0x7c, + 0x00, 0x00, 0x8c, 0x3c, 0x00, 0x00, 0x01, 0xb8, 0x70, 0x72, 0x65, 0x70, + 0xc8, 0x09, 0xfc, 0x6b, 0x00, 0x00, 0x0e, 0x3c, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x19, 0x9a, 0x79, 0x05, 0xaf, 0x87, + 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x1f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc9, 0x42, 0x17, 0xa0, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xf9, 0x0a, 0x7c, + 0xff, 0x68, 0xfe, 0x14, 0x07, 0xbc, 0x07, 0x73, 0x00, 0x01, 0x00, 0x08, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x08, 0x8d, 0xfd, 0xa8, 0x00, 0x00, 0x08, 0x00, 0xff, 0x68, 0xff, 0x86, + 0x07, 0xbc, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xc2, 0x00, 0x41, 0x00, 0x05, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x02, + 0x00, 0x10, 0x00, 0x2f, 0x00, 0x5c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x86, + 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x04, 0x9c, 0x02, 0xbc, 0x00, 0x05, + 0x00, 0x00, 0x05, 0x9a, 0x05, 0x33, 0x00, 0x00, 0x01, 0x1f, 0x05, 0x9a, + 0x05, 0x33, 0x00, 0x00, 0x03, 0xd1, 0x00, 0x66, 0x01, 0xfc, 0x08, 0x02, + 0x02, 0x0b, 0x08, 0x06, 0x03, 0x05, 0x04, 0x02, 0x02, 0x04, 0xe0, 0x00, + 0x02, 0xef, 0x40, 0x00, 0x20, 0x5b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x00, 0x31, 0x41, 0x53, 0x43, 0x00, 0x20, 0x00, 0x20, 0x00, 0xff, + 0x06, 0x1f, 0xfe, 0x14, 0x00, 0x84, 0x08, 0x8d, 0x02, 0x58, 0x20, 0x00, + 0x01, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5e, 0x05, 0xb6, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x02, 0x4a, 0x00, 0x75, + 0x03, 0xc7, 0x00, 0x85, 0x05, 0x2b, 0x00, 0x2d, 0x04, 0x91, 0x00, 0x58, + 0x07, 0x35, 0x00, 0x3f, 0x06, 0x00, 0x00, 0x52, 0x02, 0x21, 0x00, 0x85, + 0x02, 0xb6, 0x00, 0x52, 0x02, 0xb6, 0x00, 0x3d, 0x04, 0x5c, 0x00, 0x3f, + 0x04, 0x91, 0x00, 0x58, 0x02, 0x52, 0x00, 0x3f, 0x02, 0x93, 0x00, 0x3d, + 0x02, 0x48, 0x00, 0x75, 0x03, 0x4e, 0x00, 0x0e, 0x04, 0x91, 0x00, 0x4a, + 0x04, 0x91, 0x00, 0x79, 0x04, 0x91, 0x00, 0x4e, 0x04, 0x91, 0x00, 0x4e, + 0x04, 0x91, 0x00, 0x23, 0x04, 0x91, 0x00, 0x64, 0x04, 0x91, 0x00, 0x48, + 0x04, 0x91, 0x00, 0x37, 0x04, 0x91, 0x00, 0x48, 0x04, 0x91, 0x00, 0x42, + 0x02, 0x48, 0x00, 0x75, 0x02, 0x52, 0x00, 0x3f, 0x04, 0x91, 0x00, 0x58, + 0x04, 0x91, 0x00, 0x58, 0x04, 0x91, 0x00, 0x58, 0x03, 0xd1, 0x00, 0x06, + 0x07, 0x2d, 0x00, 0x66, 0x05, 0x85, 0x00, 0x00, 0x05, 0x60, 0x00, 0xb8, + 0x05, 0x19, 0x00, 0x77, 0x05, 0xec, 0x00, 0xb8, 0x04, 0x7b, 0x00, 0xb8, + 0x04, 0x64, 0x00, 0xb8, 0x05, 0xcb, 0x00, 0x77, 0x06, 0x1f, 0x00, 0xb8, + 0x02, 0xa6, 0x00, 0xb8, 0x02, 0xa6, 0xff, 0x68, 0x05, 0x50, 0x00, 0xb8, + 0x04, 0x85, 0x00, 0xb8, 0x07, 0x8b, 0x00, 0xb8, 0x06, 0x81, 0x00, 0xb8, + 0x06, 0x5e, 0x00, 0x77, 0x05, 0x06, 0x00, 0xb8, 0x06, 0x5e, 0x00, 0x77, + 0x05, 0x48, 0x00, 0xb8, 0x04, 0x68, 0x00, 0x5e, 0x04, 0xa2, 0x00, 0x29, + 0x06, 0x0c, 0x00, 0xae, 0x05, 0x33, 0x00, 0x00, 0x07, 0xbc, 0x00, 0x00, + 0x05, 0x56, 0x00, 0x00, 0x04, 0xfe, 0x00, 0x00, 0x04, 0xa2, 0x00, 0x31, + 0x02, 0xa6, 0x00, 0x8f, 0x03, 0x4e, 0x00, 0x0c, 0x02, 0xa6, 0x00, 0x33, + 0x04, 0x42, 0x00, 0x08, 0x03, 0x4a, 0xff, 0xfc, 0x04, 0xdb, 0x01, 0x4c, + 0x04, 0xd5, 0x00, 0x56, 0x05, 0x10, 0x00, 0xa0, 0x04, 0x1d, 0x00, 0x5c, + 0x05, 0x10, 0x00, 0x5c, 0x04, 0xba, 0x00, 0x5c, 0x03, 0x19, 0x00, 0x29, + 0x04, 0x85, 0x00, 0x06, 0x05, 0x42, 0x00, 0xa0, 0x02, 0x71, 0x00, 0x93, + 0x02, 0x71, 0xff, 0x7d, 0x04, 0xf6, 0x00, 0xa0, 0x02, 0x71, 0x00, 0xa0, + 0x07, 0xdb, 0x00, 0xa0, 0x05, 0x42, 0x00, 0xa0, 0x04, 0xf4, 0x00, 0x5c, + 0x05, 0x10, 0x00, 0xa0, 0x05, 0x10, 0x00, 0x5c, 0x03, 0xa2, 0x00, 0xa0, + 0x03, 0xfa, 0x00, 0x5c, 0x03, 0x79, 0x00, 0x2f, 0x05, 0x42, 0x00, 0x9a, + 0x04, 0x8d, 0x00, 0x00, 0x06, 0xd9, 0x00, 0x14, 0x04, 0xa0, 0x00, 0x0a, + 0x04, 0x8d, 0x00, 0x00, 0x03, 0xe7, 0x00, 0x37, 0x03, 0x27, 0x00, 0x1f, + 0x04, 0x68, 0x01, 0xc7, 0x03, 0x27, 0x00, 0x52, 0x04, 0x91, 0x00, 0x58, + 0x02, 0x14, 0x00, 0x00, 0x02, 0x4a, 0x00, 0x75, 0x04, 0x91, 0x00, 0x8f, + 0x04, 0x91, 0x00, 0x52, 0x04, 0x91, 0x00, 0x71, 0x04, 0x91, 0x00, 0x06, + 0x04, 0x68, 0x01, 0xc7, 0x03, 0xe3, 0x00, 0x6a, 0x04, 0xdb, 0x01, 0x17, + 0x06, 0xa8, 0x00, 0x64, 0x03, 0x10, 0x00, 0x2f, 0x04, 0xec, 0x00, 0x52, + 0x04, 0x91, 0x00, 0x58, 0x02, 0x93, 0x00, 0x3d, 0x06, 0xa8, 0x00, 0x64, + 0x04, 0x00, 0xff, 0xfa, 0x03, 0x6d, 0x00, 0x5c, 0x04, 0x91, 0x00, 0x58, + 0x03, 0x08, 0x00, 0x2f, 0x03, 0x08, 0x00, 0x3b, 0x04, 0xdb, 0x01, 0x4c, + 0x05, 0x48, 0x00, 0xa0, 0x05, 0x3d, 0x00, 0x71, 0x02, 0x48, 0x00, 0x75, + 0x01, 0xa4, 0xff, 0xdb, 0x03, 0x08, 0x00, 0x5c, 0x03, 0x1b, 0x00, 0x39, + 0x04, 0xec, 0x00, 0x52, 0x07, 0x0c, 0x00, 0x2e, 0x07, 0x0c, 0x00, 0x2e, + 0x07, 0x0c, 0x00, 0x5a, 0x03, 0xd1, 0x00, 0x3d, 0x05, 0x85, 0x00, 0x00, + 0x05, 0x85, 0x00, 0x00, 0x05, 0x85, 0x00, 0x00, 0x05, 0x85, 0x00, 0x00, + 0x05, 0x85, 0x00, 0x00, 0x05, 0x85, 0x00, 0x00, 0x07, 0x9e, 0x00, 0x00, + 0x05, 0x19, 0x00, 0x77, 0x04, 0x7b, 0x00, 0xb8, 0x04, 0x7b, 0x00, 0xb8, + 0x04, 0x7b, 0x00, 0xaf, 0x04, 0x7b, 0x00, 0xb8, 0x02, 0xa6, 0xff, 0xc6, + 0x02, 0xa6, 0x00, 0xa7, 0x02, 0xa6, 0xff, 0xa0, 0x02, 0xa6, 0xff, 0xfd, + 0x05, 0xec, 0x00, 0x2f, 0x06, 0x81, 0x00, 0xb8, 0x06, 0x5e, 0x00, 0x77, + 0x06, 0x5e, 0x00, 0x77, 0x06, 0x5e, 0x00, 0x77, 0x06, 0x5e, 0x00, 0x77, + 0x06, 0x5e, 0x00, 0x77, 0x04, 0x91, 0x00, 0x81, 0x06, 0x5e, 0x00, 0x77, + 0x06, 0x0c, 0x00, 0xae, 0x06, 0x0c, 0x00, 0xae, 0x06, 0x0c, 0x00, 0xae, + 0x06, 0x0c, 0x00, 0xae, 0x04, 0xfe, 0x00, 0x00, 0x05, 0x06, 0x00, 0xb8, + 0x05, 0xb0, 0x00, 0xa0, 0x04, 0xd5, 0x00, 0x56, 0x04, 0xd5, 0x00, 0x56, + 0x04, 0xd5, 0x00, 0x56, 0x04, 0xd5, 0x00, 0x56, 0x04, 0xd5, 0x00, 0x56, + 0x04, 0xd5, 0x00, 0x56, 0x07, 0x56, 0x00, 0x56, 0x04, 0x1d, 0x00, 0x5c, + 0x04, 0xba, 0x00, 0x5c, 0x04, 0xba, 0x00, 0x5c, 0x04, 0xba, 0x00, 0x5c, + 0x04, 0xba, 0x00, 0x5c, 0x02, 0x71, 0xff, 0x9b, 0x02, 0x71, 0x00, 0x91, + 0x02, 0x71, 0xff, 0x86, 0x02, 0x71, 0xff, 0xe3, 0x04, 0xf4, 0x00, 0x5c, + 0x05, 0x42, 0x00, 0xa0, 0x04, 0xf4, 0x00, 0x5c, 0x04, 0xf4, 0x00, 0x5c, + 0x04, 0xf4, 0x00, 0x5c, 0x04, 0xf4, 0x00, 0x5c, 0x04, 0xf4, 0x00, 0x5c, + 0x04, 0x91, 0x00, 0x58, 0x04, 0xf4, 0x00, 0x5c, 0x05, 0x42, 0x00, 0x9a, + 0x05, 0x42, 0x00, 0x9a, 0x05, 0x42, 0x00, 0x9a, 0x05, 0x42, 0x00, 0x9a, + 0x04, 0x8d, 0x00, 0x00, 0x05, 0x10, 0x00, 0xa0, 0x04, 0x8d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x7e, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x20, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xc2, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x00, 0x86, 0x87, + 0x89, 0x8b, 0x93, 0x98, 0x9e, 0xa3, 0xa2, 0xa4, 0xa6, 0xa5, 0xa7, 0xa9, + 0xab, 0xaa, 0xac, 0xad, 0xaf, 0xae, 0xb0, 0xb1, 0xb3, 0xb5, 0xb4, 0xb6, + 0xb8, 0xb7, 0xbc, 0xbb, 0xbd, 0xbe, 0x00, 0x72, 0x64, 0x65, 0x69, 0x00, + 0x78, 0xa1, 0x70, 0x6b, 0x00, 0x76, 0x6a, 0x00, 0x88, 0x9a, 0x00, 0x73, + 0x00, 0x00, 0x67, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x00, + 0xa8, 0xba, 0x81, 0x63, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x7d, 0x00, + 0x62, 0x82, 0x85, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb9, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, + 0x00, 0x00, 0x00, 0x84, 0x8c, 0x83, 0x8d, 0x8a, 0x8f, 0x90, 0x91, 0x8e, + 0x95, 0x96, 0x00, 0x94, 0x9c, 0x9d, 0x9b, 0x00, 0x00, 0x00, 0x71, 0x00, + 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x47, 0x5b, 0x5a, + 0x59, 0x58, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4c, + 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, + 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x31, + 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, + 0x21, 0x1f, 0x18, 0x14, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a, 0x09, + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x2c, 0x20, 0xb0, + 0x01, 0x60, 0x45, 0xb0, 0x03, 0x25, 0x20, 0x11, 0x46, 0x61, 0x23, 0x45, + 0x23, 0x61, 0x48, 0x2d, 0x2c, 0x20, 0x45, 0x18, 0x68, 0x44, 0x2d, 0x2c, + 0x45, 0x23, 0x46, 0x60, 0xb0, 0x20, 0x61, 0x20, 0xb0, 0x46, 0x60, 0xb0, + 0x04, 0x26, 0x23, 0x48, 0x48, 0x2d, 0x2c, 0x45, 0x23, 0x46, 0x23, 0x61, + 0xb0, 0x20, 0x60, 0x20, 0xb0, 0x26, 0x61, 0xb0, 0x20, 0x61, 0xb0, 0x04, + 0x26, 0x23, 0x48, 0x48, 0x2d, 0x2c, 0x45, 0x23, 0x46, 0x60, 0xb0, 0x40, + 0x61, 0x20, 0xb0, 0x66, 0x60, 0xb0, 0x04, 0x26, 0x23, 0x48, 0x48, 0x2d, + 0x2c, 0x45, 0x23, 0x46, 0x23, 0x61, 0xb0, 0x40, 0x60, 0x20, 0xb0, 0x26, + 0x61, 0xb0, 0x40, 0x61, 0xb0, 0x04, 0x26, 0x23, 0x48, 0x48, 0x2d, 0x2c, + 0x01, 0x10, 0x20, 0x3c, 0x00, 0x3c, 0x2d, 0x2c, 0x20, 0x45, 0x23, 0x20, + 0xb0, 0xcd, 0x44, 0x23, 0x20, 0xb8, 0x01, 0x5a, 0x51, 0x58, 0x23, 0x20, + 0xb0, 0x8d, 0x44, 0x23, 0x59, 0x20, 0xb0, 0xed, 0x51, 0x58, 0x23, 0x20, + 0xb0, 0x4d, 0x44, 0x23, 0x59, 0x20, 0xb0, 0x04, 0x26, 0x51, 0x58, 0x23, + 0x20, 0xb0, 0x0d, 0x44, 0x23, 0x59, 0x21, 0x21, 0x2d, 0x2c, 0x20, 0x20, + 0x45, 0x18, 0x68, 0x44, 0x20, 0xb0, 0x01, 0x60, 0x20, 0x45, 0xb0, 0x46, + 0x76, 0x68, 0x8a, 0x45, 0x60, 0x44, 0x2d, 0x2c, 0x01, 0xb1, 0x0b, 0x0a, + 0x43, 0x23, 0x43, 0x65, 0x0a, 0x2d, 0x2c, 0x00, 0xb1, 0x0a, 0x0b, 0x43, + 0x23, 0x43, 0x0b, 0x2d, 0x2c, 0x00, 0xb0, 0x28, 0x23, 0x70, 0xb1, 0x01, + 0x28, 0x3e, 0x01, 0xb0, 0x28, 0x23, 0x70, 0xb1, 0x02, 0x28, 0x45, 0x3a, + 0xb1, 0x02, 0x00, 0x08, 0x0d, 0x2d, 0x2c, 0x20, 0x45, 0xb0, 0x03, 0x25, + 0x45, 0x61, 0x64, 0xb0, 0x50, 0x51, 0x58, 0x45, 0x44, 0x1b, 0x21, 0x21, + 0x59, 0x2d, 0x2c, 0x49, 0xb0, 0x0e, 0x23, 0x44, 0x2d, 0x2c, 0x20, 0x45, + 0xb0, 0x00, 0x43, 0x60, 0x44, 0x2d, 0x2c, 0x01, 0xb0, 0x06, 0x43, 0xb0, + 0x07, 0x43, 0x65, 0x0a, 0x2d, 0x2c, 0x20, 0x69, 0xb0, 0x40, 0x61, 0xb0, + 0x00, 0x8b, 0x20, 0xb1, 0x2c, 0xc0, 0x8a, 0x8c, 0xb8, 0x10, 0x00, 0x62, + 0x60, 0x2b, 0x0c, 0x64, 0x23, 0x64, 0x61, 0x5c, 0x58, 0xb0, 0x03, 0x61, + 0x59, 0x2d, 0x2c, 0x8a, 0x03, 0x45, 0x8a, 0x8a, 0x87, 0xb0, 0x11, 0x2b, + 0xb0, 0x29, 0x23, 0x44, 0xb0, 0x29, 0x7a, 0xe4, 0x18, 0x2d, 0x2c, 0x45, + 0x65, 0xb0, 0x2c, 0x23, 0x44, 0x45, 0xb0, 0x2b, 0x23, 0x44, 0x2d, 0x2c, + 0x4b, 0x52, 0x58, 0x45, 0x44, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x4b, + 0x51, 0x58, 0x45, 0x44, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x01, 0xb0, + 0x05, 0x25, 0x10, 0x23, 0x20, 0x8a, 0xf5, 0x00, 0xb0, 0x01, 0x60, 0x23, + 0xed, 0xec, 0x2d, 0x2c, 0x01, 0xb0, 0x05, 0x25, 0x10, 0x23, 0x20, 0x8a, + 0xf5, 0x00, 0xb0, 0x01, 0x61, 0x23, 0xed, 0xec, 0x2d, 0x2c, 0x01, 0xb0, + 0x06, 0x25, 0x10, 0xf5, 0x00, 0xed, 0xec, 0x2d, 0x2c, 0xb0, 0x02, 0x43, + 0xb0, 0x01, 0x52, 0x58, 0x21, 0x21, 0x21, 0x21, 0x21, 0x1b, 0x46, 0x23, + 0x46, 0x60, 0x8a, 0x8a, 0x46, 0x23, 0x20, 0x46, 0x8a, 0x60, 0x8a, 0x61, + 0xb8, 0xff, 0x80, 0x62, 0x23, 0x20, 0x10, 0x23, 0x8a, 0xb1, 0x0c, 0x0c, + 0x8a, 0x70, 0x45, 0x60, 0x20, 0xb0, 0x00, 0x50, 0x58, 0xb0, 0x01, 0x61, + 0xb8, 0xff, 0xba, 0x8b, 0x1b, 0xb0, 0x46, 0x8c, 0x59, 0xb0, 0x10, 0x60, + 0x68, 0x01, 0x3a, 0x59, 0x2d, 0x2c, 0x20, 0x45, 0xb0, 0x03, 0x25, 0x46, + 0x52, 0x4b, 0xb0, 0x13, 0x51, 0x5b, 0x58, 0xb0, 0x02, 0x25, 0x46, 0x20, + 0x68, 0x61, 0xb0, 0x03, 0x25, 0xb0, 0x03, 0x25, 0x3f, 0x23, 0x21, 0x38, + 0x1b, 0x21, 0x11, 0x59, 0x2d, 0x2c, 0x20, 0x45, 0xb0, 0x03, 0x25, 0x46, + 0x50, 0x58, 0xb0, 0x02, 0x25, 0x46, 0x20, 0x68, 0x61, 0xb0, 0x03, 0x25, + 0xb0, 0x03, 0x25, 0x3f, 0x23, 0x21, 0x38, 0x1b, 0x21, 0x11, 0x59, 0x2d, + 0x2c, 0x00, 0xb0, 0x07, 0x43, 0xb0, 0x06, 0x43, 0x0b, 0x2d, 0x2c, 0x21, + 0x21, 0x0c, 0x64, 0x23, 0x64, 0x8b, 0xb8, 0x40, 0x00, 0x62, 0x2d, 0x2c, + 0x21, 0xb0, 0x80, 0x51, 0x58, 0x0c, 0x64, 0x23, 0x64, 0x8b, 0xb8, 0x20, + 0x00, 0x62, 0x1b, 0xb2, 0x00, 0x40, 0x2f, 0x2b, 0x59, 0xb0, 0x02, 0x60, + 0x2d, 0x2c, 0x21, 0xb0, 0xc0, 0x51, 0x58, 0x0c, 0x64, 0x23, 0x64, 0x8b, + 0xb8, 0x15, 0x55, 0x62, 0x1b, 0xb2, 0x00, 0x80, 0x2f, 0x2b, 0x59, 0xb0, + 0x02, 0x60, 0x2d, 0x2c, 0x0c, 0x64, 0x23, 0x64, 0x8b, 0xb8, 0x40, 0x00, + 0x62, 0x60, 0x23, 0x21, 0x2d, 0x2c, 0x4b, 0x53, 0x58, 0x8a, 0xb0, 0x04, + 0x25, 0x49, 0x64, 0x23, 0x45, 0x69, 0xb0, 0x40, 0x8b, 0x61, 0xb0, 0x80, + 0x62, 0xb0, 0x20, 0x61, 0x6a, 0xb0, 0x0e, 0x23, 0x44, 0x23, 0x10, 0xb0, + 0x0e, 0xf6, 0x1b, 0x21, 0x23, 0x8a, 0x12, 0x11, 0x20, 0x39, 0x2f, 0x59, + 0x2d, 0x2c, 0x4b, 0x53, 0x58, 0x20, 0xb0, 0x03, 0x25, 0x49, 0x64, 0x69, + 0x20, 0xb0, 0x05, 0x26, 0xb0, 0x06, 0x25, 0x49, 0x64, 0x23, 0x61, 0xb0, + 0x80, 0x62, 0xb0, 0x20, 0x61, 0x6a, 0xb0, 0x0e, 0x23, 0x44, 0xb0, 0x04, + 0x26, 0x10, 0xb0, 0x0e, 0xf6, 0x8a, 0x10, 0xb0, 0x0e, 0x23, 0x44, 0xb0, + 0x0e, 0xf6, 0xb0, 0x0e, 0x23, 0x44, 0xb0, 0x0e, 0xed, 0x1b, 0x8a, 0xb0, + 0x04, 0x26, 0x11, 0x12, 0x20, 0x39, 0x23, 0x20, 0x39, 0x2f, 0x2f, 0x59, + 0x2d, 0x2c, 0x45, 0x23, 0x45, 0x60, 0x23, 0x45, 0x60, 0x23, 0x45, 0x60, + 0x23, 0x76, 0x68, 0x18, 0xb0, 0x80, 0x62, 0x20, 0x2d, 0x2c, 0xb0, 0x48, + 0x2b, 0x2d, 0x2c, 0x20, 0x45, 0xb0, 0x00, 0x54, 0x58, 0xb0, 0x40, 0x44, + 0x20, 0x45, 0xb0, 0x40, 0x61, 0x44, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, + 0x45, 0xb1, 0x30, 0x2f, 0x45, 0x23, 0x45, 0x61, 0x60, 0xb0, 0x01, 0x60, + 0x69, 0x44, 0x2d, 0x2c, 0x4b, 0x51, 0x58, 0xb0, 0x2f, 0x23, 0x70, 0xb0, + 0x14, 0x23, 0x42, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x4b, 0x51, 0x58, + 0x20, 0xb0, 0x03, 0x25, 0x45, 0x69, 0x53, 0x58, 0x44, 0x1b, 0x21, 0x21, + 0x59, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x45, 0xb0, 0x14, 0x43, 0xb0, + 0x00, 0x60, 0x63, 0xb0, 0x01, 0x60, 0x69, 0x44, 0x2d, 0x2c, 0xb0, 0x2f, + 0x45, 0x44, 0x2d, 0x2c, 0x45, 0x23, 0x20, 0x45, 0x8a, 0x60, 0x44, 0x2d, + 0x2c, 0x46, 0x23, 0x46, 0x60, 0x8a, 0x8a, 0x46, 0x23, 0x20, 0x46, 0x8a, + 0x60, 0x8a, 0x61, 0xb8, 0xff, 0x80, 0x62, 0x23, 0x20, 0x10, 0x23, 0x8a, + 0xb1, 0x0c, 0x0c, 0x8a, 0x70, 0x45, 0x60, 0x20, 0xb0, 0x00, 0x50, 0x58, + 0xb0, 0x01, 0x61, 0xb8, 0xff, 0x80, 0x8b, 0x1b, 0xb0, 0x81, 0x8c, 0x59, + 0x68, 0x3a, 0x2d, 0x2c, 0x4b, 0x23, 0x51, 0x58, 0xb9, 0x00, 0x33, 0xff, + 0xe0, 0xb1, 0x34, 0x20, 0x1b, 0xb3, 0x33, 0x00, 0x34, 0x00, 0x59, 0x44, + 0x44, 0x2d, 0x2c, 0xb0, 0x16, 0x43, 0x58, 0xb0, 0x03, 0x26, 0x45, 0x8a, + 0x58, 0x64, 0x66, 0xb0, 0x1f, 0x60, 0x1b, 0x64, 0xb0, 0x20, 0x60, 0x66, + 0x20, 0x58, 0x1b, 0x21, 0xb0, 0x40, 0x59, 0xb0, 0x01, 0x61, 0x59, 0x23, + 0x58, 0x65, 0x59, 0xb0, 0x29, 0x23, 0x44, 0x23, 0x10, 0xb0, 0x29, 0xe0, + 0x1b, 0x21, 0x21, 0x21, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x02, 0x43, + 0x54, 0x58, 0x4b, 0x53, 0x23, 0x4b, 0x51, 0x5a, 0x58, 0x38, 0x1b, 0x21, + 0x21, 0x59, 0x1b, 0x21, 0x21, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x16, + 0x43, 0x58, 0xb0, 0x04, 0x25, 0x45, 0x64, 0xb0, 0x20, 0x60, 0x66, 0x20, + 0x58, 0x1b, 0x21, 0xb0, 0x40, 0x59, 0xb0, 0x01, 0x61, 0x23, 0x58, 0x1b, + 0x65, 0x59, 0xb0, 0x29, 0x23, 0x44, 0xb0, 0x05, 0x25, 0xb0, 0x08, 0x25, + 0x08, 0x20, 0x58, 0x02, 0x1b, 0x03, 0x59, 0xb0, 0x04, 0x25, 0x10, 0xb0, + 0x05, 0x25, 0x20, 0x46, 0xb0, 0x04, 0x25, 0x23, 0x42, 0x3c, 0xb0, 0x04, + 0x25, 0xb0, 0x07, 0x25, 0x08, 0xb0, 0x07, 0x25, 0x10, 0xb0, 0x06, 0x25, + 0x20, 0x46, 0xb0, 0x04, 0x25, 0xb0, 0x01, 0x60, 0x23, 0x42, 0x3c, 0x20, + 0x58, 0x01, 0x1b, 0x00, 0x59, 0xb0, 0x04, 0x25, 0x10, 0xb0, 0x05, 0x25, + 0xb0, 0x29, 0xe0, 0xb0, 0x29, 0x20, 0x45, 0x65, 0x44, 0xb0, 0x07, 0x25, + 0x10, 0xb0, 0x06, 0x25, 0xb0, 0x29, 0xe0, 0xb0, 0x05, 0x25, 0xb0, 0x08, + 0x25, 0x08, 0x20, 0x58, 0x02, 0x1b, 0x03, 0x59, 0xb0, 0x05, 0x25, 0xb0, + 0x03, 0x25, 0x43, 0x48, 0xb0, 0x04, 0x25, 0xb0, 0x07, 0x25, 0x08, 0xb0, + 0x06, 0x25, 0xb0, 0x03, 0x25, 0xb0, 0x01, 0x60, 0x43, 0x48, 0x1b, 0x21, + 0x59, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2d, 0x2c, 0x02, 0xb0, + 0x04, 0x25, 0x20, 0x20, 0x46, 0xb0, 0x04, 0x25, 0x23, 0x42, 0xb0, 0x05, + 0x25, 0x08, 0xb0, 0x03, 0x25, 0x45, 0x48, 0x21, 0x21, 0x21, 0x21, 0x2d, + 0x2c, 0x02, 0xb0, 0x03, 0x25, 0x20, 0xb0, 0x04, 0x25, 0x08, 0xb0, 0x02, + 0x25, 0x43, 0x48, 0x21, 0x21, 0x21, 0x2d, 0x2c, 0x45, 0x23, 0x20, 0x45, + 0x18, 0x20, 0xb0, 0x00, 0x50, 0x20, 0x58, 0x23, 0x65, 0x23, 0x59, 0x23, + 0x68, 0x20, 0xb0, 0x40, 0x50, 0x58, 0x21, 0xb0, 0x40, 0x59, 0x23, 0x58, + 0x65, 0x59, 0x8a, 0x60, 0x44, 0x2d, 0x2c, 0x4b, 0x53, 0x23, 0x4b, 0x51, + 0x5a, 0x58, 0x20, 0x45, 0x8a, 0x60, 0x44, 0x1b, 0x21, 0x21, 0x59, 0x2d, + 0x2c, 0x4b, 0x54, 0x58, 0x20, 0x45, 0x8a, 0x60, 0x44, 0x1b, 0x21, 0x21, + 0x59, 0x2d, 0x2c, 0x4b, 0x53, 0x23, 0x4b, 0x51, 0x5a, 0x58, 0x38, 0x1b, + 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x00, 0x21, 0x4b, 0x54, 0x58, 0x38, + 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x02, 0x43, 0x54, 0x58, 0xb0, + 0x46, 0x2b, 0x1b, 0x21, 0x21, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x02, + 0x43, 0x54, 0x58, 0xb0, 0x47, 0x2b, 0x1b, 0x21, 0x21, 0x21, 0x59, 0x2d, + 0x2c, 0xb0, 0x02, 0x43, 0x54, 0x58, 0xb0, 0x48, 0x2b, 0x1b, 0x21, 0x21, + 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x02, 0x43, 0x54, 0x58, 0xb0, 0x49, + 0x2b, 0x1b, 0x21, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x20, 0x8a, 0x08, 0x23, + 0x4b, 0x53, 0x8a, 0x4b, 0x51, 0x5a, 0x58, 0x23, 0x38, 0x1b, 0x21, 0x21, + 0x59, 0x2d, 0x2c, 0x00, 0xb0, 0x02, 0x25, 0x49, 0xb0, 0x00, 0x53, 0x58, + 0x20, 0xb0, 0x40, 0x38, 0x11, 0x1b, 0x21, 0x59, 0x2d, 0x2c, 0x01, 0x46, + 0x23, 0x46, 0x60, 0x23, 0x46, 0x61, 0x23, 0x20, 0x10, 0x20, 0x46, 0x8a, + 0x61, 0xb8, 0xff, 0x80, 0x62, 0x8a, 0xb1, 0x40, 0x40, 0x8a, 0x70, 0x45, + 0x60, 0x68, 0x3a, 0x2d, 0x2c, 0x20, 0x8a, 0x23, 0x49, 0x64, 0x8a, 0x23, + 0x53, 0x58, 0x3c, 0x1b, 0x21, 0x59, 0x2d, 0x2c, 0x4b, 0x52, 0x58, 0x7d, + 0x1b, 0x7a, 0x59, 0x2d, 0x2c, 0xb0, 0x12, 0x00, 0x4b, 0x01, 0x4b, 0x54, + 0x42, 0x2d, 0x2c, 0xb1, 0x02, 0x00, 0x42, 0xb1, 0x23, 0x01, 0x88, 0x51, + 0xb1, 0x40, 0x01, 0x88, 0x53, 0x5a, 0x58, 0xb9, 0x10, 0x00, 0x00, 0x20, + 0x88, 0x54, 0x58, 0xb2, 0x02, 0x01, 0x02, 0x43, 0x60, 0x42, 0x59, 0xb1, + 0x24, 0x01, 0x88, 0x51, 0x58, 0xb9, 0x20, 0x00, 0x00, 0x40, 0x88, 0x54, + 0x58, 0xb2, 0x02, 0x02, 0x02, 0x43, 0x60, 0x42, 0xb1, 0x24, 0x01, 0x88, + 0x54, 0x58, 0xb2, 0x02, 0x20, 0x02, 0x43, 0x60, 0x42, 0x00, 0x4b, 0x01, + 0x4b, 0x52, 0x58, 0xb2, 0x02, 0x08, 0x02, 0x43, 0x60, 0x42, 0x59, 0x1b, + 0xb9, 0x40, 0x00, 0x00, 0x80, 0x88, 0x54, 0x58, 0xb2, 0x02, 0x04, 0x02, + 0x43, 0x60, 0x42, 0x59, 0xb9, 0x40, 0x00, 0x00, 0x80, 0x63, 0xb8, 0x01, + 0x00, 0x88, 0x54, 0x58, 0xb2, 0x02, 0x08, 0x02, 0x43, 0x60, 0x42, 0x59, + 0xb9, 0x40, 0x00, 0x01, 0x00, 0x63, 0xb8, 0x02, 0x00, 0x88, 0x54, 0x58, + 0xb2, 0x02, 0x10, 0x02, 0x43, 0x60, 0x42, 0x59, 0xb1, 0x26, 0x01, 0x88, + 0x51, 0x58, 0xb9, 0x40, 0x00, 0x02, 0x00, 0x63, 0xb8, 0x04, 0x00, 0x88, + 0x54, 0x58, 0xb2, 0x02, 0x40, 0x02, 0x43, 0x60, 0x42, 0x59, 0xb9, 0x40, + 0x00, 0x04, 0x00, 0x63, 0xb8, 0x08, 0x00, 0x88, 0x54, 0x58, 0xb2, 0x02, + 0x80, 0x02, 0x43, 0x60, 0x42, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0xb1, + 0x00, 0x02, 0x43, 0x54, 0x58, 0x40, 0x0a, 0x05, 0x40, 0x08, 0x40, 0x09, + 0x40, 0x0c, 0x02, 0x0d, 0x02, 0x1b, 0xb1, 0x01, 0x02, 0x43, 0x54, 0x58, + 0xb2, 0x05, 0x40, 0x08, 0xba, 0x01, 0x00, 0x00, 0x09, 0x01, 0x00, 0xb3, + 0x0c, 0x01, 0x0d, 0x01, 0x1b, 0xb1, 0x80, 0x02, 0x43, 0x52, 0x58, 0xb2, + 0x05, 0x40, 0x08, 0xb8, 0x01, 0x80, 0xb1, 0x09, 0x40, 0x1b, 0xb2, 0x05, + 0x40, 0x08, 0xba, 0x01, 0x80, 0x00, 0x09, 0x01, 0x40, 0x59, 0xb9, 0x40, + 0x00, 0x00, 0x80, 0x88, 0x55, 0xb9, 0x40, 0x00, 0x02, 0x00, 0x63, 0xb8, + 0x04, 0x00, 0x88, 0x55, 0x5a, 0x58, 0xb3, 0x0c, 0x00, 0x0d, 0x01, 0x1b, + 0xb3, 0x0c, 0x00, 0x0d, 0x01, 0x59, 0x59, 0x59, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x2d, 0x2c, 0x45, 0x18, 0x68, 0x23, 0x4b, 0x51, 0x58, 0x23, 0x20, + 0x45, 0x20, 0x64, 0xb0, 0x40, 0x50, 0x58, 0x7c, 0x59, 0x68, 0x8a, 0x60, + 0x59, 0x44, 0x2d, 0x2c, 0xb0, 0x00, 0x16, 0xb0, 0x02, 0x25, 0xb0, 0x02, + 0x25, 0x01, 0xb0, 0x01, 0x23, 0x3e, 0x00, 0xb0, 0x02, 0x23, 0x3e, 0xb1, + 0x01, 0x02, 0x06, 0x0c, 0xb0, 0x0a, 0x23, 0x65, 0x42, 0xb0, 0x0b, 0x23, + 0x42, 0x01, 0xb0, 0x01, 0x23, 0x3f, 0x00, 0xb0, 0x02, 0x23, 0x3f, 0xb1, + 0x01, 0x02, 0x06, 0x0c, 0xb0, 0x06, 0x23, 0x65, 0x42, 0xb0, 0x07, 0x23, + 0x42, 0xb0, 0x01, 0x16, 0x01, 0x2d, 0x2c, 0xb0, 0x80, 0xb0, 0x02, 0x43, + 0x50, 0xb0, 0x01, 0xb0, 0x02, 0x43, 0x54, 0x5b, 0x58, 0x21, 0x23, 0x10, + 0xb0, 0x20, 0x1a, 0xc9, 0x1b, 0x8a, 0x10, 0xed, 0x59, 0x2d, 0x2c, 0xb0, + 0x59, 0x2b, 0x2d, 0x2c, 0x8a, 0x10, 0xe5, 0x2d, 0x40, 0x8b, 0x09, 0x21, + 0x48, 0x20, 0x55, 0x20, 0x01, 0x03, 0x55, 0x1f, 0x48, 0x03, 0x55, 0x1e, + 0x03, 0xff, 0x1f, 0x50, 0x4c, 0x16, 0x1f, 0x4f, 0x4d, 0x64, 0x1f, 0x4e, + 0x4c, 0x64, 0x1f, 0x26, 0x34, 0x10, 0x55, 0x25, 0x33, 0x24, 0x55, 0x19, + 0x13, 0xff, 0x1f, 0x07, 0x04, 0xff, 0x1f, 0x06, 0x03, 0xff, 0x1f, 0x4d, + 0x4c, 0x1e, 0x1f, 0x64, 0x4c, 0x01, 0x4c, 0x46, 0x0d, 0x1f, 0x13, 0x33, + 0x12, 0x55, 0x05, 0x01, 0x03, 0x55, 0x04, 0x33, 0x03, 0x55, 0x1f, 0x03, + 0x01, 0x0f, 0x03, 0x3f, 0x03, 0xaf, 0x03, 0x03, 0x06, 0x4b, 0x46, 0xcb, + 0x46, 0xdb, 0x46, 0x03, 0x23, 0x33, 0x22, 0x55, 0x1c, 0x33, 0x1b, 0x55, + 0x16, 0x33, 0x15, 0x55, 0x11, 0x01, 0x0f, 0x55, 0x10, 0x33, 0x0f, 0x55, + 0xaf, 0x0f, 0xcf, 0x0f, 0x02, 0x30, 0x0f, 0x01, 0x01, 0x33, 0x00, 0x55, + 0x6f, 0x00, 0x7f, 0x00, 0xaf, 0x00, 0xef, 0x00, 0x04, 0x10, 0x00, 0x01, + 0x80, 0x16, 0x01, 0x05, 0x01, 0xb8, 0x01, 0x90, 0xb1, 0x54, 0x53, 0x2b, + 0x2b, 0x4b, 0xb8, 0x07, 0xff, 0x52, 0x4b, 0xb0, 0x09, 0x50, 0x5b, 0xb0, + 0x01, 0x88, 0xb0, 0x25, 0x53, 0xb0, 0x01, 0x88, 0xb0, 0x40, 0x51, 0x5a, + 0xb0, 0x06, 0x88, 0xb0, 0x00, 0x55, 0x5a, 0x5b, 0x58, 0xb1, 0x01, 0x01, + 0x8e, 0x59, 0x85, 0x8d, 0x8d, 0x00, 0x42, 0x1d, 0x4b, 0xb0, 0x32, 0x53, + 0x58, 0xb0, 0x20, 0x1d, 0x59, 0x4b, 0xb0, 0x64, 0x53, 0x58, 0xb0, 0x10, + 0x1d, 0xb1, 0x16, 0x00, 0x42, 0x59, 0x73, 0x73, 0x2b, 0x73, 0x73, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x73, 0x5e, 0x73, 0x74, 0x2b, 0x2b, 0x2b, 0x2b, + 0x74, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x18, 0x5e, 0x06, 0x14, 0x00, 0x17, 0x00, 0x00, 0x05, 0xb6, + 0x00, 0x17, 0x00, 0x75, 0x05, 0xb6, 0x05, 0xcd, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5e, + 0x00, 0x17, 0x00, 0x7b, 0x00, 0x00, 0xff, 0xec, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xec, 0x00, 0x00, 0x00, 0x00, 0xff, 0xec, 0x00, 0x00, 0xfe, 0x14, + 0xff, 0xec, 0x00, 0x00, 0x05, 0xb6, 0x00, 0x15, 0xfc, 0x94, 0xff, 0xeb, + 0xfe, 0x8f, 0xff, 0xe0, 0xfe, 0xbc, 0xff, 0xec, 0x00, 0x12, 0xfe, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe5, 0x00, 0xf6, 0x01, 0x00, 0x01, 0x2b, 0x00, 0xd3, 0x00, 0xb2, + 0x01, 0x02, 0x00, 0xf6, 0x01, 0x02, 0x00, 0xf6, 0x00, 0xed, 0x00, 0xdf, + 0x00, 0xb2, 0x00, 0x00, 0x01, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x56, 0x00, 0xcc, + 0x01, 0x58, 0x01, 0xc6, 0x02, 0x4e, 0x02, 0x66, 0x02, 0x94, 0x02, 0xc2, + 0x03, 0x00, 0x03, 0x2c, 0x03, 0x4a, 0x03, 0x60, 0x03, 0x82, 0x03, 0xa0, + 0x03, 0xe2, 0x04, 0x10, 0x04, 0x5e, 0x04, 0xc6, 0x05, 0x10, 0x05, 0x6c, + 0x05, 0xc8, 0x05, 0xf2, 0x06, 0x66, 0x06, 0xc2, 0x06, 0xfa, 0x07, 0x32, + 0x07, 0x5c, 0x07, 0x82, 0x07, 0xae, 0x08, 0x0a, 0x08, 0x9a, 0x08, 0xde, + 0x09, 0x3e, 0x09, 0x80, 0x09, 0xb8, 0x09, 0xf4, 0x0a, 0x24, 0x0a, 0x7a, + 0x0a, 0xb0, 0x0a, 0xc6, 0x0a, 0xf2, 0x0b, 0x32, 0x0b, 0x52, 0x0b, 0x98, + 0x0b, 0xd4, 0x0c, 0x16, 0x0c, 0x56, 0x0c, 0xac, 0x0d, 0x00, 0x0d, 0x60, + 0x0d, 0x86, 0x0d, 0xbc, 0x0d, 0xee, 0x0e, 0x4a, 0x0e, 0x8c, 0x0e, 0xc0, + 0x0e, 0xf6, 0x0f, 0x18, 0x0f, 0x36, 0x0f, 0x58, 0x0f, 0x84, 0x0f, 0x9c, + 0x0f, 0xc0, 0x10, 0x1a, 0x10, 0x6e, 0x10, 0xaa, 0x10, 0xfe, 0x11, 0x54, + 0x11, 0x96, 0x12, 0x32, 0x12, 0x70, 0x12, 0x9c, 0x12, 0xda, 0x13, 0x22, + 0x13, 0x3a, 0x13, 0x96, 0x13, 0xd2, 0x14, 0x16, 0x14, 0x6c, 0x14, 0xc2, + 0x14, 0xf4, 0x15, 0x4c, 0x15, 0x8e, 0x15, 0xca, 0x15, 0xfc, 0x16, 0x58, + 0x16, 0x9e, 0x16, 0xee, 0x17, 0x24, 0x17, 0x70, 0x17, 0x88, 0x17, 0xd8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x4a, 0x18, 0x9a, 0x18, 0xf4, 0x19, 0x50, + 0x19, 0xae, 0x19, 0xd4, 0x1a, 0x52, 0x1a, 0x8a, 0x1b, 0x04, 0x1b, 0x5a, + 0x1b, 0xae, 0x1b, 0xcc, 0x1b, 0xd4, 0x1c, 0x62, 0x1c, 0x7a, 0x1c, 0xb0, + 0x1c, 0xea, 0x1d, 0x24, 0x1d, 0x7a, 0x1d, 0x9e, 0x1d, 0xe8, 0x1e, 0x1c, + 0x1e, 0x3e, 0x1e, 0x78, 0x1e, 0xa6, 0x1e, 0xdc, 0x1f, 0x30, 0x1f, 0x6e, + 0x1f, 0xb0, 0x20, 0x0c, 0x20, 0x6c, 0x20, 0x7e, 0x20, 0x90, 0x20, 0xc8, + 0x21, 0x0c, 0x21, 0x1e, 0x21, 0x62, 0x21, 0xc2, 0x21, 0xce, 0x21, 0xe0, + 0x21, 0xf2, 0x22, 0x20, 0x22, 0x32, 0x22, 0x44, 0x22, 0x56, 0x22, 0x7a, + 0x22, 0x8c, 0x22, 0xdc, 0x23, 0x1e, 0x23, 0x30, 0x23, 0x42, 0x23, 0x86, + 0x23, 0xd4, 0x23, 0xe6, 0x24, 0x16, 0x24, 0x74, 0x24, 0x86, 0x24, 0x98, + 0x24, 0xd0, 0x24, 0xe2, 0x24, 0xf4, 0x25, 0x36, 0x25, 0xae, 0x25, 0xbe, + 0x25, 0xce, 0x26, 0x1a, 0x26, 0x72, 0x26, 0x84, 0x26, 0xda, 0x27, 0x74, + 0x27, 0x80, 0x27, 0x90, 0x27, 0xa0, 0x27, 0xe8, 0x27, 0xfa, 0x28, 0x16, + 0x28, 0x32, 0x28, 0x56, 0x28, 0x84, 0x29, 0x02, 0x29, 0x46, 0x29, 0x56, + 0x29, 0x68, 0x29, 0xac, 0x29, 0xfc, 0x2a, 0x0e, 0x2a, 0x50, 0x2a, 0xae, + 0x2a, 0xbe, 0x2a, 0xd0, 0x2b, 0x0a, 0x2b, 0x1c, 0x2b, 0x2c, 0x2b, 0x86, + 0x2b, 0x98, 0x00, 0x00, 0x00, 0x02, 0x00, 0x75, 0xff, 0xe5, 0x01, 0xd3, + 0x05, 0xb6, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x26, 0x40, 0x12, 0x03, 0x0a, + 0x0a, 0x02, 0x04, 0x04, 0x10, 0x11, 0x01, 0x07, 0x0d, 0x07, 0x54, 0x59, + 0x0d, 0x13, 0x02, 0x03, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x11, + 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x23, + 0x03, 0x21, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x01, 0xa0, 0xf4, 0x33, 0x01, 0x5a, 0xfe, 0xa2, 0x5a, 0x56, + 0x53, 0x5b, 0x5c, 0x52, 0x54, 0x5c, 0x01, 0xe5, 0x03, 0xd1, 0xfa, 0xd9, + 0x54, 0x56, 0x58, 0x52, 0x4f, 0x5b, 0x59, 0x00, 0x00, 0x02, 0x00, 0x85, + 0x03, 0xa6, 0x03, 0x42, 0x05, 0xb6, 0x00, 0x03, 0x00, 0x07, 0x00, 0x1b, + 0x40, 0x0b, 0x04, 0x07, 0x00, 0x03, 0x03, 0x08, 0x06, 0x02, 0x07, 0x03, + 0x03, 0x00, 0x3f, 0x33, 0xcd, 0x32, 0x11, 0x01, 0x33, 0x11, 0x33, 0xcc, + 0x32, 0x31, 0x30, 0x01, 0x03, 0x23, 0x03, 0x21, 0x03, 0x23, 0x03, 0x01, + 0x9c, 0x29, 0xc5, 0x29, 0x02, 0xbd, 0x29, 0xc5, 0x29, 0x05, 0xb6, 0xfd, + 0xf0, 0x02, 0x10, 0xfd, 0xf0, 0x02, 0x10, 0x00, 0x00, 0x02, 0x00, 0x2d, + 0x00, 0x00, 0x04, 0xfe, 0x05, 0xb4, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x7d, + 0x40, 0x44, 0x08, 0x1c, 0x1f, 0x15, 0x04, 0x14, 0x09, 0x09, 0x0a, 0x04, + 0x01, 0x00, 0x19, 0x04, 0x18, 0x05, 0x05, 0x06, 0x12, 0x0f, 0x0e, 0x0b, + 0x04, 0x0a, 0x13, 0x13, 0x14, 0x16, 0x1e, 0x1d, 0x07, 0x04, 0x06, 0x17, + 0x17, 0x18, 0x18, 0x14, 0x06, 0x0a, 0x04, 0x20, 0x21, 0x08, 0x04, 0x0b, + 0x0b, 0x1c, 0x01, 0x0e, 0x1f, 0x00, 0x0f, 0x0f, 0x19, 0x15, 0x12, 0x0e, + 0x12, 0x0e, 0x12, 0x0a, 0x17, 0x13, 0x03, 0x06, 0x0a, 0x12, 0x00, 0x3f, + 0x33, 0x3f, 0x33, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x11, 0x33, 0x33, 0x33, + 0x11, 0x33, 0x33, 0x11, 0x33, 0x33, 0x33, 0x11, 0x33, 0x33, 0x11, 0x12, + 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, 0x11, 0x33, 0x11, + 0x12, 0x17, 0x39, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, 0x11, 0x33, 0x11, + 0x12, 0x17, 0x39, 0x31, 0x30, 0x01, 0x07, 0x21, 0x15, 0x21, 0x03, 0x23, + 0x13, 0x23, 0x03, 0x23, 0x13, 0x23, 0x35, 0x21, 0x37, 0x23, 0x35, 0x21, + 0x13, 0x33, 0x03, 0x33, 0x13, 0x33, 0x03, 0x33, 0x15, 0x05, 0x33, 0x37, + 0x23, 0x03, 0xe7, 0x2f, 0x01, 0x02, 0xfe, 0xd7, 0x4d, 0xdc, 0x4e, 0xc2, + 0x4c, 0xd7, 0x4a, 0xee, 0x01, 0x15, 0x2f, 0xfc, 0x01, 0x21, 0x4d, 0xdb, + 0x4d, 0xc6, 0x4e, 0xd7, 0x4e, 0xf0, 0xfd, 0x1d, 0xc4, 0x2f, 0xc4, 0x03, + 0x4c, 0xe8, 0xce, 0xfe, 0x6a, 0x01, 0x96, 0xfe, 0x6a, 0x01, 0x96, 0xce, + 0xe8, 0xd1, 0x01, 0x97, 0xfe, 0x69, 0x01, 0x97, 0xfe, 0x69, 0xd1, 0xe8, + 0xe8, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x58, 0xff, 0x89, 0x04, 0x44, + 0x06, 0x12, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2c, 0x00, 0x86, 0x40, 0x45, + 0x24, 0x17, 0x03, 0x1d, 0x1d, 0x14, 0x0d, 0x06, 0x2a, 0x2a, 0x21, 0x29, + 0x1e, 0x27, 0x00, 0x27, 0x08, 0x0f, 0x23, 0x11, 0x21, 0x21, 0x19, 0x00, + 0x11, 0x00, 0x2d, 0x2e, 0x2a, 0x1d, 0x27, 0x00, 0x00, 0x0d, 0x24, 0x11, + 0x21, 0x11, 0x27, 0x2b, 0x1a, 0x27, 0x21, 0x09, 0x25, 0x06, 0x0c, 0x1c, + 0x17, 0x1c, 0x4f, 0x59, 0x14, 0x17, 0x06, 0x0c, 0x50, 0x59, 0x05, 0x06, + 0x03, 0x06, 0x17, 0x06, 0x17, 0x06, 0x2d, 0x15, 0x00, 0x00, 0x3f, 0x12, + 0x39, 0x39, 0x2f, 0x2f, 0x11, 0x33, 0x10, 0xcd, 0x2b, 0x11, 0x00, 0x33, + 0x2b, 0x11, 0x12, 0x00, 0x17, 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, + 0x33, 0x11, 0x12, 0x39, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, + 0x33, 0x11, 0x12, 0x39, 0x39, 0x32, 0x32, 0x11, 0x12, 0x39, 0x39, 0x11, + 0x39, 0x11, 0x33, 0x33, 0x33, 0x33, 0x11, 0x33, 0x33, 0x33, 0x31, 0x30, + 0x01, 0x14, 0x06, 0x07, 0x15, 0x23, 0x35, 0x26, 0x27, 0x11, 0x1e, 0x01, + 0x17, 0x11, 0x27, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, 0x35, 0x33, 0x15, + 0x16, 0x17, 0x07, 0x26, 0x27, 0x11, 0x1e, 0x02, 0x05, 0x34, 0x26, 0x27, + 0x15, 0x36, 0x01, 0x14, 0x16, 0x17, 0x35, 0x06, 0x04, 0x44, 0xe6, 0xcf, + 0x89, 0xf4, 0xb8, 0x57, 0xf5, 0x60, 0x43, 0xc6, 0xa5, 0xe3, 0xcb, 0x89, + 0xe5, 0xb9, 0x5e, 0x9c, 0xa4, 0xc3, 0xa5, 0x4d, 0xfe, 0xd3, 0x44, 0x44, + 0x88, 0xfe, 0x6e, 0x3d, 0x44, 0x81, 0x01, 0xc9, 0x9f, 0xc1, 0x13, 0xcd, + 0xc9, 0x05, 0x51, 0x01, 0x08, 0x2b, 0x42, 0x06, 0x01, 0x36, 0x1a, 0x4e, + 0xb7, 0x87, 0x91, 0xbb, 0x14, 0x99, 0x95, 0x0a, 0x52, 0xea, 0x40, 0x0e, + 0xfe, 0xd9, 0x4b, 0x6e, 0x84, 0x67, 0x2a, 0x3a, 0x1f, 0xf9, 0x17, 0x02, + 0xbe, 0x2c, 0x39, 0x1e, 0xeb, 0x13, 0x00, 0x00, 0x00, 0x05, 0x00, 0x3f, + 0xff, 0xee, 0x06, 0xf6, 0x05, 0xcb, 0x00, 0x09, 0x00, 0x14, 0x00, 0x18, + 0x00, 0x22, 0x00, 0x2d, 0x00, 0x4a, 0x40, 0x24, 0x16, 0x17, 0x17, 0x05, + 0x05, 0x0a, 0x10, 0x00, 0x10, 0x18, 0x15, 0x15, 0x19, 0x19, 0x29, 0x23, + 0x1e, 0x23, 0x10, 0x23, 0x2e, 0x2f, 0x20, 0x2b, 0x1c, 0x26, 0x19, 0x18, + 0x06, 0x17, 0x18, 0x03, 0x0d, 0x07, 0x12, 0x07, 0x00, 0x3f, 0x33, 0xc4, + 0x32, 0x3f, 0x3f, 0x3f, 0x33, 0xc4, 0x32, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x11, 0x33, 0x10, 0xc0, 0x32, 0x12, 0x39, 0x11, 0x33, 0x11, 0x33, 0x10, + 0xc0, 0x32, 0x12, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x16, 0x33, + 0x32, 0x35, 0x34, 0x23, 0x22, 0x06, 0x05, 0x14, 0x06, 0x23, 0x22, 0x26, + 0x35, 0x10, 0x21, 0x32, 0x16, 0x25, 0x01, 0x23, 0x01, 0x13, 0x14, 0x16, + 0x33, 0x32, 0x35, 0x34, 0x23, 0x22, 0x06, 0x05, 0x14, 0x06, 0x23, 0x22, + 0x26, 0x35, 0x10, 0x21, 0x32, 0x16, 0x01, 0x3b, 0x2d, 0x32, 0x60, 0x60, + 0x32, 0x2d, 0x01, 0xbb, 0xb2, 0xac, 0xa5, 0xb4, 0x01, 0x59, 0xa9, 0xb5, + 0x02, 0xb0, 0xfc, 0xd5, 0xf0, 0x03, 0x2b, 0x85, 0x2d, 0x32, 0x60, 0x60, + 0x32, 0x2d, 0x01, 0xbb, 0xb2, 0xac, 0xa5, 0xb4, 0x01, 0x59, 0xa9, 0xb5, + 0x04, 0x00, 0x7f, 0x7d, 0xfc, 0xfa, 0x7b, 0x7d, 0xe6, 0xe7, 0xed, 0xe0, + 0x01, 0xc9, 0xed, 0xd8, 0xfa, 0x4a, 0x05, 0xb6, 0xfc, 0x02, 0x7f, 0x7d, + 0xfc, 0xfa, 0x7b, 0x7d, 0xe5, 0xe7, 0xed, 0xdf, 0x01, 0xc9, 0xed, 0x00, + 0x00, 0x03, 0x00, 0x52, 0xff, 0xec, 0x06, 0x00, 0x05, 0xcb, 0x00, 0x1d, + 0x00, 0x26, 0x00, 0x31, 0x00, 0x71, 0x40, 0x39, 0x2d, 0x0d, 0x23, 0x0a, + 0x01, 0x1d, 0x16, 0x00, 0x0a, 0x16, 0x0d, 0x13, 0x13, 0x27, 0x19, 0x1a, + 0x1a, 0x27, 0x0d, 0x03, 0x07, 0x01, 0x00, 0x00, 0x33, 0x1e, 0x07, 0x07, + 0x32, 0x17, 0x21, 0x1a, 0x16, 0x0a, 0x24, 0x24, 0x2f, 0x2f, 0x10, 0x1a, + 0x1a, 0x04, 0x10, 0x10, 0x2a, 0x4d, 0x59, 0x10, 0x04, 0x04, 0x21, 0x4c, + 0x59, 0x04, 0x13, 0x01, 0x12, 0x00, 0x3f, 0x3f, 0x2b, 0x00, 0x18, 0x3f, + 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x12, 0x39, 0x11, 0x33, 0x12, + 0x39, 0x39, 0x11, 0x12, 0x39, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x12, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, + 0x39, 0x11, 0x12, 0x39, 0x11, 0x12, 0x39, 0x11, 0x33, 0x31, 0x30, 0x29, + 0x01, 0x27, 0x06, 0x23, 0x22, 0x24, 0x35, 0x34, 0x36, 0x37, 0x2e, 0x01, + 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x01, 0x36, + 0x37, 0x21, 0x06, 0x02, 0x07, 0x25, 0x14, 0x16, 0x33, 0x32, 0x37, 0x01, + 0x0e, 0x01, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, 0x17, 0x3e, + 0x01, 0x06, 0x00, 0xfe, 0x87, 0x73, 0xbf, 0xf1, 0xf4, 0xfe, 0xe2, 0x79, + 0x93, 0x4b, 0x44, 0xe9, 0xc3, 0xba, 0xdf, 0x8a, 0x9a, 0x01, 0x1c, 0x47, + 0x34, 0x01, 0x3e, 0x24, 0x7e, 0x50, 0xfc, 0xc0, 0x81, 0x65, 0x7e, 0x65, + 0xfe, 0xb4, 0x3a, 0x43, 0x01, 0x67, 0x48, 0x39, 0x43, 0x4d, 0x5f, 0x56, + 0x5c, 0x71, 0x85, 0xe0, 0xbf, 0x89, 0xc1, 0x54, 0x56, 0x9d, 0x5d, 0x98, + 0xba, 0xad, 0x91, 0x77, 0xc5, 0x59, 0xfe, 0xeb, 0x75, 0xb8, 0x87, 0xfe, + 0xff, 0x63, 0x83, 0x56, 0x66, 0x3d, 0x01, 0x4a, 0x2c, 0x60, 0x02, 0x86, + 0x35, 0x3d, 0x40, 0x3b, 0x58, 0x6a, 0x30, 0x5d, 0x00, 0x01, 0x00, 0x85, + 0x03, 0xa6, 0x01, 0x9c, 0x05, 0xb6, 0x00, 0x03, 0x00, 0x12, 0xb6, 0x00, + 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x00, 0x3f, 0xcd, 0x11, 0x01, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x03, 0x23, 0x03, 0x01, 0x9c, 0x29, 0xc5, + 0x29, 0x05, 0xb6, 0xfd, 0xf0, 0x02, 0x10, 0x00, 0x00, 0x01, 0x00, 0x52, + 0xfe, 0xbc, 0x02, 0x79, 0x05, 0xb6, 0x00, 0x0d, 0x00, 0x20, 0x40, 0x0e, + 0x0b, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x00, 0x07, 0x07, 0x0f, 0x0b, 0x24, + 0x03, 0x03, 0x00, 0x3f, 0x3f, 0x11, 0x01, 0x33, 0x11, 0x33, 0x33, 0x11, + 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x10, 0x12, 0x37, 0x33, 0x06, + 0x02, 0x15, 0x14, 0x12, 0x17, 0x23, 0x26, 0x02, 0x52, 0x9b, 0x92, 0xfa, + 0x8d, 0x90, 0x93, 0x88, 0xf8, 0x93, 0x9a, 0x02, 0x31, 0x01, 0x09, 0x01, + 0xce, 0xae, 0xc1, 0xfe, 0x32, 0xf4, 0xf5, 0xfe, 0x37, 0xb9, 0xaa, 0x01, + 0xc6, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3d, 0xfe, 0xbc, 0x02, 0x64, + 0x05, 0xb6, 0x00, 0x0d, 0x00, 0x20, 0x40, 0x0e, 0x03, 0x04, 0x04, 0x0b, + 0x0a, 0x0a, 0x00, 0x07, 0x07, 0x0e, 0x0a, 0x03, 0x04, 0x24, 0x00, 0x3f, + 0x3f, 0x11, 0x01, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, + 0x31, 0x30, 0x01, 0x10, 0x02, 0x07, 0x23, 0x36, 0x12, 0x35, 0x34, 0x02, + 0x27, 0x33, 0x16, 0x12, 0x02, 0x64, 0x9b, 0x92, 0xf8, 0x87, 0x94, 0x90, + 0x8d, 0xfa, 0x93, 0x9a, 0x02, 0x31, 0xfe, 0xf9, 0xfe, 0x3a, 0xa8, 0xb8, + 0x01, 0xc9, 0xf6, 0xf4, 0x01, 0xce, 0xc1, 0xaf, 0xfe, 0x31, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x3f, 0x02, 0x56, 0x04, 0x1d, 0x06, 0x14, 0x00, 0x0e, + 0x00, 0x35, 0x40, 0x18, 0x09, 0x0b, 0x0b, 0x05, 0x03, 0x03, 0x0d, 0x01, + 0x07, 0x07, 0x10, 0x0f, 0x04, 0x0a, 0x0a, 0x07, 0x07, 0x01, 0x0d, 0x0d, + 0x06, 0x08, 0x0e, 0x00, 0x00, 0x3f, 0xc4, 0x32, 0x39, 0x11, 0x33, 0x33, + 0x12, 0x39, 0x11, 0x33, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x33, + 0x12, 0x39, 0x33, 0x12, 0x39, 0x31, 0x30, 0x01, 0x03, 0x25, 0x17, 0x05, + 0x13, 0x07, 0x0b, 0x01, 0x27, 0x13, 0x25, 0x37, 0x05, 0x03, 0x02, 0xb0, + 0x29, 0x01, 0x75, 0x21, 0xfe, 0xac, 0xdf, 0xe3, 0x9c, 0x89, 0xec, 0xdd, + 0xfe, 0xae, 0x27, 0x01, 0x6d, 0x29, 0x06, 0x14, 0xfe, 0x90, 0x68, 0xfc, + 0x18, 0xfe, 0xd7, 0x79, 0x01, 0x39, 0xfe, 0xc9, 0x77, 0x01, 0x29, 0x1a, + 0xfa, 0x68, 0x01, 0x70, 0x00, 0x01, 0x00, 0x58, 0x00, 0xe3, 0x04, 0x39, + 0x04, 0xc5, 0x00, 0x0b, 0x00, 0x26, 0x40, 0x10, 0x08, 0x06, 0x09, 0x09, + 0x03, 0x01, 0x00, 0x00, 0x0c, 0x0d, 0x0b, 0x09, 0x00, 0x06, 0x04, 0x03, + 0x00, 0x2f, 0x33, 0x33, 0x33, 0x32, 0x32, 0x11, 0x12, 0x01, 0x39, 0x11, + 0x33, 0x33, 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x01, 0x21, 0x35, 0x21, + 0x11, 0x33, 0x11, 0x21, 0x15, 0x21, 0x11, 0x23, 0x01, 0xdb, 0xfe, 0x7d, + 0x01, 0x83, 0xdb, 0x01, 0x83, 0xfe, 0x7d, 0xdb, 0x02, 0x64, 0xdb, 0x01, + 0x86, 0xfe, 0x7a, 0xdb, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3f, + 0xfe, 0xf8, 0x01, 0xcb, 0x00, 0xee, 0x00, 0x06, 0x00, 0x15, 0xb7, 0x02, + 0x03, 0x00, 0x05, 0x05, 0x07, 0x03, 0x05, 0x00, 0x2f, 0xc6, 0x11, 0x01, + 0x33, 0x11, 0x33, 0xc2, 0x32, 0x31, 0x30, 0x25, 0x06, 0x03, 0x23, 0x12, + 0x37, 0x21, 0x01, 0xcb, 0x34, 0x7c, 0xdc, 0x41, 0x24, 0x01, 0x18, 0xd7, + 0xca, 0xfe, 0xeb, 0x01, 0x0a, 0xec, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3d, + 0x01, 0xa8, 0x02, 0x56, 0x02, 0xa2, 0x00, 0x03, 0x00, 0x11, 0xb5, 0x03, + 0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x2f, 0x33, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x13, 0x35, 0x21, 0x15, 0x3d, 0x02, 0x19, 0x01, 0xa8, + 0xfa, 0xfa, 0x00, 0x00, 0x00, 0x01, 0x00, 0x75, 0xff, 0xe5, 0x01, 0xd3, + 0x01, 0x39, 0x00, 0x0b, 0x00, 0x16, 0x40, 0x0a, 0x06, 0x00, 0x00, 0x0c, + 0x09, 0x03, 0x54, 0x59, 0x09, 0x13, 0x00, 0x3f, 0x2b, 0x11, 0x01, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x37, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x23, 0x22, 0x26, 0x75, 0x5a, 0x56, 0x53, 0x5b, 0x5c, 0x52, 0x54, + 0x5c, 0x8f, 0x54, 0x56, 0x58, 0x52, 0x4f, 0x5b, 0x59, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x03, 0x44, 0x05, 0xb6, 0x00, 0x03, + 0x00, 0x1c, 0x40, 0x0c, 0x01, 0x02, 0x03, 0x00, 0x02, 0x00, 0x04, 0x05, + 0x03, 0x03, 0x02, 0x12, 0x00, 0x3f, 0x3f, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x09, 0x01, 0x21, 0x01, 0x03, 0x44, + 0xfd, 0xdf, 0xfe, 0xeb, 0x02, 0x21, 0x05, 0xb6, 0xfa, 0x4a, 0x05, 0xb6, + 0x00, 0x02, 0x00, 0x4a, 0xff, 0xec, 0x04, 0x48, 0x05, 0xcd, 0x00, 0x0b, + 0x00, 0x17, 0x00, 0x28, 0x40, 0x14, 0x0c, 0x06, 0x12, 0x00, 0x06, 0x00, + 0x18, 0x19, 0x09, 0x15, 0x4f, 0x59, 0x09, 0x07, 0x03, 0x0f, 0x4f, 0x59, + 0x03, 0x19, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x01, + 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x02, 0x21, + 0x22, 0x00, 0x11, 0x10, 0x12, 0x21, 0x32, 0x00, 0x01, 0x10, 0x16, 0x33, + 0x32, 0x36, 0x11, 0x10, 0x26, 0x23, 0x22, 0x06, 0x04, 0x48, 0xfb, 0xfe, + 0xfb, 0xfd, 0xfe, 0xff, 0xfa, 0x01, 0x04, 0xfd, 0x01, 0x03, 0xfd, 0x35, + 0x5d, 0x6e, 0x6c, 0x60, 0x61, 0x6b, 0x6d, 0x5e, 0x02, 0xdb, 0xfe, 0x81, + 0xfe, 0x90, 0x01, 0x7c, 0x01, 0x73, 0x01, 0x83, 0x01, 0x6f, 0xfe, 0x80, + 0xfe, 0x8e, 0xfe, 0xf3, 0xe9, 0xec, 0x01, 0x0a, 0x01, 0x0d, 0xeb, 0xeb, + 0x00, 0x01, 0x00, 0x79, 0x00, 0x00, 0x03, 0x4e, 0x05, 0xb6, 0x00, 0x0a, + 0x00, 0x2a, 0x40, 0x13, 0x09, 0x04, 0x00, 0x00, 0x08, 0x01, 0x01, 0x0b, + 0x0c, 0x08, 0x07, 0x07, 0x01, 0x04, 0x04, 0x09, 0x06, 0x01, 0x18, 0x00, + 0x3f, 0x3f, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x11, 0x12, 0x01, 0x39, + 0x11, 0x33, 0x33, 0x12, 0x39, 0x39, 0x31, 0x30, 0x29, 0x01, 0x11, 0x3f, + 0x01, 0x06, 0x0f, 0x01, 0x27, 0x01, 0x33, 0x03, 0x4e, 0xfe, 0xcb, 0x03, + 0x05, 0x4d, 0x1e, 0xa8, 0x95, 0x01, 0xd7, 0xfe, 0x03, 0x4e, 0x8b, 0x98, + 0x4d, 0x18, 0x87, 0xba, 0x01, 0x77, 0x00, 0x00, 0x00, 0x01, 0x00, 0x4e, + 0x00, 0x00, 0x04, 0x50, 0x05, 0xcb, 0x00, 0x1d, 0x00, 0x3d, 0x40, 0x1e, + 0x1c, 0x0e, 0x01, 0x07, 0x00, 0x16, 0x01, 0x16, 0x1e, 0x1f, 0x16, 0x07, + 0x07, 0x02, 0x0a, 0x12, 0x0a, 0x4e, 0x59, 0x12, 0x07, 0x02, 0x01, 0x1c, + 0x01, 0x1c, 0x4e, 0x59, 0x01, 0x18, 0x00, 0x3f, 0x2b, 0x11, 0x12, 0x00, + 0x39, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, 0x33, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x29, + 0x01, 0x35, 0x01, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, + 0x27, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x01, 0x0f, + 0x01, 0x15, 0x21, 0x04, 0x50, 0xfc, 0x02, 0x01, 0x6f, 0xa3, 0x64, 0x2c, + 0x61, 0x51, 0x55, 0xa0, 0x57, 0xa8, 0x6c, 0x8e, 0xa8, 0x68, 0x89, 0xd2, + 0x74, 0x47, 0x95, 0xbc, 0xbc, 0x02, 0x7d, 0xd7, 0x01, 0x73, 0xa7, 0x81, + 0x6e, 0x3b, 0x58, 0x56, 0x4e, 0x48, 0xc7, 0x5c, 0x4c, 0x29, 0x64, 0xb4, + 0x74, 0x65, 0xb1, 0xba, 0xac, 0xb1, 0x0e, 0x00, 0x00, 0x01, 0x00, 0x4e, + 0xff, 0xec, 0x04, 0x42, 0x05, 0xcb, 0x00, 0x26, 0x00, 0x5b, 0x40, 0x2f, + 0x22, 0x17, 0x0d, 0x13, 0x13, 0x07, 0x03, 0x1c, 0x1c, 0x00, 0x00, 0x07, + 0x0d, 0x07, 0x27, 0x28, 0x21, 0x1e, 0x24, 0x1e, 0x4f, 0x59, 0x03, 0x18, + 0x17, 0x18, 0x17, 0x50, 0x59, 0x0c, 0x18, 0x01, 0x0d, 0x03, 0x18, 0x18, + 0x0a, 0x24, 0x07, 0x0d, 0x10, 0x0a, 0x10, 0x4f, 0x59, 0x0a, 0x19, 0x00, + 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x18, 0x3f, 0x12, 0x39, 0x2f, 0x5f, 0x5e, + 0x5d, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x12, 0x39, 0x39, 0x31, 0x30, 0x01, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, + 0x15, 0x14, 0x04, 0x21, 0x22, 0x27, 0x11, 0x1e, 0x01, 0x33, 0x32, 0x36, + 0x35, 0x34, 0x26, 0x2b, 0x01, 0x35, 0x33, 0x32, 0x36, 0x35, 0x34, 0x23, + 0x22, 0x06, 0x07, 0x27, 0x36, 0x21, 0x32, 0x04, 0x04, 0x17, 0xa6, 0x96, + 0xb1, 0xb6, 0xfe, 0xce, 0xfe, 0xe4, 0xee, 0xb8, 0x55, 0xcc, 0x64, 0x99, + 0x92, 0xa8, 0xb8, 0x6f, 0x71, 0xaa, 0x9d, 0xd0, 0x48, 0x95, 0x5b, 0x8f, + 0xc8, 0x01, 0x15, 0xe3, 0x01, 0x07, 0x04, 0x6f, 0x89, 0xc0, 0x24, 0x06, + 0x16, 0xab, 0x91, 0xd3, 0xeb, 0x4f, 0x01, 0x07, 0x2b, 0x36, 0x68, 0x73, + 0x67, 0x56, 0xed, 0x59, 0x6c, 0xa6, 0x30, 0x3b, 0xd5, 0x90, 0xb8, 0x00, + 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x04, 0x71, 0x05, 0xb6, 0x00, 0x0a, + 0x00, 0x13, 0x00, 0x46, 0x40, 0x22, 0x0f, 0x07, 0x03, 0x09, 0x02, 0x02, + 0x0b, 0x03, 0x03, 0x05, 0x00, 0x00, 0x15, 0x13, 0x05, 0x05, 0x14, 0x06, + 0x13, 0x01, 0x05, 0x13, 0x05, 0x50, 0x59, 0x09, 0x13, 0x13, 0x03, 0x0f, + 0x07, 0x06, 0x03, 0x18, 0x00, 0x3f, 0x3f, 0x33, 0x12, 0x39, 0x2f, 0x33, + 0x2b, 0x11, 0x00, 0x33, 0x12, 0x39, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x12, 0x39, 0x39, + 0x31, 0x30, 0x01, 0x23, 0x11, 0x21, 0x11, 0x21, 0x35, 0x01, 0x21, 0x11, + 0x33, 0x21, 0x35, 0x34, 0x36, 0x37, 0x23, 0x06, 0x07, 0x01, 0x04, 0x71, + 0xb0, 0xfe, 0xd2, 0xfd, 0x90, 0x02, 0x81, 0x01, 0x1d, 0xb0, 0xfe, 0x22, + 0x0a, 0x03, 0x08, 0x25, 0x34, 0xfe, 0xf4, 0x01, 0x2f, 0xfe, 0xd1, 0x01, + 0x2f, 0xd7, 0x03, 0xb0, 0xfc, 0x69, 0xf8, 0x3e, 0xec, 0x13, 0x52, 0x4e, + 0xfe, 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x64, 0xff, 0xec, 0x04, 0x35, + 0x05, 0xb6, 0x00, 0x1b, 0x00, 0x56, 0x40, 0x2b, 0x18, 0x15, 0x15, 0x17, + 0x03, 0x19, 0x14, 0x14, 0x0e, 0x08, 0x0e, 0x03, 0x08, 0x03, 0x1c, 0x1d, + 0x14, 0x13, 0x09, 0x13, 0x0c, 0x10, 0x00, 0x10, 0x4f, 0x59, 0x19, 0x00, + 0x00, 0x06, 0x15, 0x15, 0x18, 0x4e, 0x59, 0x15, 0x06, 0x06, 0x0c, 0x4f, + 0x59, 0x06, 0x19, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x18, 0x2f, 0x33, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x11, + 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, + 0x33, 0x12, 0x39, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x32, 0x16, 0x15, + 0x14, 0x00, 0x21, 0x22, 0x27, 0x11, 0x1e, 0x01, 0x33, 0x20, 0x35, 0x34, + 0x21, 0x22, 0x06, 0x07, 0x27, 0x13, 0x21, 0x11, 0x21, 0x03, 0x37, 0x36, + 0x02, 0x66, 0xd4, 0xfb, 0xfe, 0xd2, 0xfe, 0xe7, 0xf4, 0x96, 0x4f, 0xd2, + 0x5e, 0x01, 0x1b, 0xfe, 0xdb, 0x35, 0x80, 0x28, 0x7b, 0x37, 0x03, 0x19, + 0xfd, 0xf6, 0x1b, 0x23, 0x3d, 0x03, 0xa6, 0xee, 0xcf, 0xf5, 0xfe, 0xf8, + 0x4f, 0x01, 0x0b, 0x2a, 0x35, 0xe8, 0xdd, 0x15, 0x0c, 0x42, 0x02, 0xe9, + 0xfe, 0xfa, 0xfe, 0xe1, 0x07, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x48, + 0xff, 0xec, 0x04, 0x50, 0x05, 0xc7, 0x00, 0x18, 0x00, 0x24, 0x00, 0x41, + 0x40, 0x21, 0x06, 0x12, 0x0c, 0x0c, 0x22, 0x22, 0x00, 0x1c, 0x12, 0x00, + 0x12, 0x25, 0x26, 0x0f, 0x1f, 0x50, 0x59, 0x0f, 0x0f, 0x15, 0x03, 0x15, + 0x19, 0x4f, 0x59, 0x15, 0x19, 0x03, 0x08, 0x4f, 0x59, 0x03, 0x07, 0x00, + 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, + 0x2b, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, + 0x11, 0x12, 0x39, 0x31, 0x30, 0x13, 0x10, 0x00, 0x21, 0x32, 0x17, 0x15, + 0x26, 0x23, 0x22, 0x0e, 0x01, 0x07, 0x33, 0x36, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x00, 0x23, 0x22, 0x26, 0x02, 0x05, 0x32, 0x36, 0x35, 0x34, 0x26, + 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x48, 0x01, 0x6f, 0x01, 0x6e, 0x7d, + 0x47, 0x59, 0x57, 0x9f, 0xc9, 0x64, 0x09, 0x0d, 0x63, 0xda, 0xc4, 0xde, + 0xfe, 0xf8, 0xea, 0xa2, 0xf1, 0x83, 0x02, 0x10, 0x63, 0x6a, 0x63, 0x64, + 0x5e, 0x85, 0x7d, 0x02, 0x6d, 0x01, 0xb2, 0x01, 0xa8, 0x0f, 0xf7, 0x14, + 0x60, 0xbc, 0xad, 0xaa, 0xf6, 0xd9, 0xea, 0xfe, 0xef, 0x96, 0x01, 0x20, + 0xbf, 0x85, 0x7b, 0x6b, 0x7b, 0x7a, 0x51, 0x77, 0xa4, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x37, 0x00, 0x00, 0x04, 0x50, 0x05, 0xb4, 0x00, 0x06, + 0x00, 0x2e, 0x40, 0x16, 0x06, 0x00, 0x00, 0x02, 0x01, 0x01, 0x05, 0x02, + 0x05, 0x07, 0x08, 0x05, 0x03, 0x02, 0x03, 0x02, 0x4e, 0x59, 0x03, 0x06, + 0x00, 0x18, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x31, 0x30, + 0x33, 0x01, 0x21, 0x11, 0x21, 0x15, 0x01, 0xe3, 0x02, 0x25, 0xfd, 0x2f, + 0x04, 0x19, 0xfd, 0xd7, 0x04, 0xb0, 0x01, 0x04, 0xc2, 0xfb, 0x0e, 0x00, + 0x00, 0x03, 0x00, 0x48, 0xff, 0xec, 0x04, 0x4a, 0x05, 0xc9, 0x00, 0x17, + 0x00, 0x22, 0x00, 0x2e, 0x00, 0x53, 0x40, 0x29, 0x12, 0x06, 0x15, 0x2c, + 0x03, 0x03, 0x18, 0x09, 0x18, 0x26, 0x15, 0x15, 0x0f, 0x1e, 0x1e, 0x09, + 0x0f, 0x09, 0x2f, 0x30, 0x06, 0x12, 0x12, 0x21, 0x21, 0x29, 0x29, 0x0c, + 0x00, 0x0c, 0x1b, 0x51, 0x59, 0x0c, 0x19, 0x00, 0x23, 0x51, 0x59, 0x00, + 0x07, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, + 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, + 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x32, 0x11, 0x12, 0x39, 0x11, 0x33, + 0x12, 0x39, 0x39, 0x31, 0x30, 0x01, 0x32, 0x04, 0x15, 0x14, 0x06, 0x07, + 0x1e, 0x01, 0x15, 0x14, 0x04, 0x23, 0x22, 0x24, 0x35, 0x34, 0x36, 0x37, + 0x2e, 0x01, 0x35, 0x34, 0x24, 0x03, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, + 0x34, 0x26, 0x27, 0x06, 0x13, 0x22, 0x06, 0x15, 0x14, 0x16, 0x17, 0x3e, + 0x01, 0x35, 0x34, 0x26, 0x02, 0x4a, 0xd2, 0x01, 0x01, 0x7c, 0x8a, 0xa4, + 0x8f, 0xfe, 0xe6, 0xe6, 0xf0, 0xfe, 0xee, 0x85, 0x93, 0x7d, 0x6e, 0x01, + 0x04, 0x13, 0x78, 0x68, 0x73, 0x72, 0x71, 0x7f, 0xd5, 0xe2, 0x4f, 0x61, + 0x4d, 0x65, 0x62, 0x4e, 0x64, 0x05, 0xc9, 0xbf, 0xa2, 0x70, 0xaf, 0x45, + 0x58, 0xbf, 0x72, 0xb4, 0xdb, 0xcc, 0xbb, 0x7d, 0xc2, 0x4a, 0x4f, 0xb4, + 0x6b, 0x9d, 0xc2, 0xfb, 0xbc, 0x56, 0x60, 0x63, 0x51, 0x43, 0x75, 0x42, + 0x62, 0x02, 0xcc, 0x51, 0x44, 0x3c, 0x5f, 0x32, 0x2e, 0x60, 0x3f, 0x45, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x42, 0xff, 0xec, 0x04, 0x4a, + 0x05, 0xc7, 0x00, 0x19, 0x00, 0x25, 0x00, 0x3f, 0x40, 0x20, 0x1d, 0x05, + 0x13, 0x0c, 0x0c, 0x23, 0x23, 0x00, 0x13, 0x00, 0x26, 0x27, 0x10, 0x20, + 0x50, 0x59, 0x10, 0x10, 0x03, 0x16, 0x16, 0x1a, 0x4f, 0x59, 0x16, 0x07, + 0x03, 0x08, 0x50, 0x59, 0x03, 0x19, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, + 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x01, 0x39, + 0x39, 0x11, 0x33, 0x12, 0x39, 0x11, 0x12, 0x39, 0x32, 0x31, 0x30, 0x01, + 0x10, 0x00, 0x21, 0x22, 0x27, 0x35, 0x16, 0x33, 0x32, 0x3e, 0x01, 0x37, + 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x00, 0x33, 0x32, 0x16, + 0x12, 0x25, 0x22, 0x06, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, + 0x26, 0x04, 0x4a, 0xfe, 0x94, 0xfe, 0x8f, 0x82, 0x43, 0x54, 0x5c, 0x9b, + 0xc8, 0x6a, 0x08, 0x0c, 0x3a, 0x98, 0x72, 0xbf, 0xdc, 0x01, 0x0b, 0xe6, + 0xa2, 0xf3, 0x82, 0xfd, 0xef, 0x60, 0x6c, 0x62, 0x64, 0x5e, 0x86, 0x7d, + 0x03, 0x46, 0xfe, 0x50, 0xfe, 0x56, 0x0e, 0xf8, 0x15, 0x5b, 0xc3, 0xab, + 0x5e, 0x4c, 0xf5, 0xda, 0xeb, 0x01, 0x11, 0x98, 0xfe, 0xdf, 0xc1, 0x84, + 0x7c, 0x6a, 0x7c, 0x7b, 0x50, 0x77, 0xa4, 0x00, 0x00, 0x02, 0x00, 0x75, + 0xff, 0xe5, 0x01, 0xd3, 0x04, 0x73, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x26, + 0x40, 0x13, 0x12, 0x06, 0x06, 0x0c, 0x00, 0x00, 0x18, 0x0f, 0x15, 0x54, + 0x59, 0x0f, 0x10, 0x09, 0x03, 0x54, 0x59, 0x09, 0x13, 0x00, 0x3f, 0x2b, + 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, + 0x31, 0x30, 0x37, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x11, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x75, 0x5a, 0x56, 0x53, 0x5b, 0x5c, 0x52, 0x54, 0x5c, 0x5a, + 0x56, 0x53, 0x5b, 0x5d, 0x51, 0x54, 0x5c, 0x8f, 0x54, 0x56, 0x58, 0x52, + 0x4f, 0x5b, 0x59, 0x03, 0x8b, 0x54, 0x56, 0x58, 0x52, 0x51, 0x59, 0x58, + 0x00, 0x02, 0x00, 0x3f, 0xfe, 0xf8, 0x01, 0xd3, 0x04, 0x73, 0x00, 0x06, + 0x00, 0x12, 0x00, 0x28, 0x40, 0x13, 0x0d, 0x07, 0x07, 0x13, 0x03, 0x04, + 0x06, 0x01, 0x06, 0x06, 0x13, 0x0a, 0x10, 0x54, 0x59, 0x0a, 0x10, 0x04, + 0x06, 0x00, 0x2f, 0xc6, 0x3f, 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, 0x10, + 0xc2, 0x32, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x25, 0x17, 0x06, 0x03, + 0x23, 0x12, 0x37, 0x03, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, + 0x23, 0x22, 0x26, 0x01, 0xbc, 0x0f, 0x34, 0x7c, 0xdc, 0x41, 0x24, 0x2f, + 0x5a, 0x56, 0x53, 0x5b, 0x5d, 0x51, 0x54, 0x5c, 0xee, 0x17, 0xca, 0xfe, + 0xeb, 0x01, 0x0a, 0xec, 0x02, 0xdb, 0x54, 0x56, 0x58, 0x52, 0x51, 0x59, + 0x58, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x58, 0x00, 0xcb, 0x04, 0x39, + 0x05, 0x00, 0x00, 0x06, 0x00, 0x27, 0x40, 0x10, 0x05, 0x01, 0x04, 0x00, + 0x01, 0x00, 0x07, 0x08, 0x04, 0x03, 0x03, 0x06, 0x00, 0x02, 0x01, 0x05, + 0x00, 0x3d, 0x2f, 0x33, 0x33, 0x33, 0x32, 0x33, 0x11, 0x33, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x25, 0x01, 0x35, + 0x01, 0x15, 0x09, 0x01, 0x04, 0x39, 0xfc, 0x1f, 0x03, 0xe1, 0xfd, 0x54, + 0x02, 0xac, 0xcb, 0x01, 0xb6, 0x8f, 0x01, 0xf0, 0xf0, 0xfe, 0xc3, 0xfe, + 0xe7, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x58, 0x01, 0xa2, 0x04, 0x39, + 0x04, 0x00, 0x00, 0x03, 0x00, 0x07, 0x00, 0x24, 0x40, 0x11, 0x07, 0x03, + 0x03, 0x09, 0x04, 0x00, 0x08, 0x05, 0x50, 0x04, 0x60, 0x04, 0x02, 0x04, + 0x04, 0x00, 0x01, 0x00, 0x2f, 0x33, 0x33, 0x2f, 0x5d, 0x33, 0x11, 0x01, + 0x33, 0x32, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x35, 0x21, 0x15, + 0x01, 0x35, 0x21, 0x15, 0x58, 0x03, 0xe1, 0xfc, 0x1f, 0x03, 0xe1, 0x03, + 0x25, 0xdb, 0xdb, 0xfe, 0x7d, 0xdb, 0xdb, 0x00, 0x00, 0x01, 0x00, 0x58, + 0x00, 0xcb, 0x04, 0x39, 0x05, 0x00, 0x00, 0x06, 0x00, 0x2b, 0x40, 0x12, + 0x02, 0x00, 0x01, 0x05, 0x00, 0x05, 0x07, 0x08, 0x00, 0x06, 0x06, 0x01, + 0x02, 0x03, 0x03, 0x05, 0x04, 0x01, 0x00, 0x3d, 0x2f, 0x33, 0x33, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x09, 0x01, 0x35, 0x01, 0x15, 0x01, + 0x58, 0x02, 0xac, 0xfd, 0x54, 0x03, 0xe1, 0xfc, 0x1f, 0x01, 0xba, 0x01, + 0x19, 0x01, 0x3d, 0xf0, 0xfe, 0x10, 0x8f, 0xfe, 0x4a, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x06, 0xff, 0xe5, 0x03, 0xa0, 0x05, 0xcb, 0x00, 0x19, + 0x00, 0x25, 0x00, 0x44, 0x40, 0x22, 0x20, 0x1a, 0x1a, 0x19, 0x00, 0x00, + 0x0d, 0x07, 0x07, 0x12, 0x0d, 0x12, 0x26, 0x27, 0x0f, 0x00, 0x01, 0x09, + 0x03, 0x00, 0x00, 0x23, 0x23, 0x1d, 0x54, 0x59, 0x23, 0x13, 0x0f, 0x0a, + 0x4f, 0x59, 0x0f, 0x04, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x00, 0x33, 0x18, 0x2f, 0x5f, 0x5e, 0x5d, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x01, 0x35, 0x34, 0x36, 0x37, 0x3e, 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, + 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x0e, 0x01, + 0x1d, 0x01, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x01, 0x14, 0x52, 0x6d, 0x69, 0x43, 0x60, 0x56, 0x96, 0xc0, + 0x6d, 0xdf, 0xfa, 0xce, 0xf3, 0x64, 0x8c, 0x60, 0x33, 0xfe, 0xd7, 0x5a, + 0x56, 0x53, 0x5b, 0x5c, 0x52, 0x54, 0x5c, 0x01, 0xe5, 0x4a, 0x60, 0x8e, + 0x50, 0x4b, 0x5e, 0x3a, 0x41, 0x44, 0x62, 0xdb, 0x7d, 0xc6, 0xa5, 0x6e, + 0xa0, 0x64, 0x47, 0x4a, 0x3c, 0x3c, 0xfe, 0xaa, 0x54, 0x56, 0x58, 0x52, + 0x4f, 0x5b, 0x59, 0x00, 0x00, 0x02, 0x00, 0x66, 0xff, 0x66, 0x06, 0xc7, + 0x05, 0xc9, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x59, 0x40, 0x2b, 0x07, 0x39, + 0x39, 0x14, 0x14, 0x13, 0x35, 0x35, 0x0d, 0x3b, 0x13, 0x28, 0x13, 0x0d, + 0x03, 0x21, 0x19, 0x21, 0x2d, 0x19, 0x00, 0x2d, 0x00, 0x40, 0x41, 0x16, + 0x08, 0x37, 0x37, 0x04, 0x0a, 0x3d, 0x10, 0x0a, 0x10, 0x0a, 0x10, 0x2a, + 0x1d, 0x31, 0x04, 0x24, 0x2a, 0x00, 0x2f, 0x33, 0x3f, 0x33, 0x12, 0x39, + 0x39, 0x2f, 0x2f, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x33, 0x11, + 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x12, 0x39, 0x31, + 0x30, 0x01, 0x14, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x27, 0x23, 0x06, 0x23, + 0x22, 0x26, 0x35, 0x34, 0x00, 0x33, 0x32, 0x16, 0x17, 0x03, 0x14, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x2e, 0x01, 0x23, 0x22, 0x04, 0x02, 0x15, 0x10, + 0x00, 0x21, 0x32, 0x36, 0x37, 0x15, 0x06, 0x21, 0x20, 0x00, 0x11, 0x34, + 0x12, 0x24, 0x21, 0x32, 0x04, 0x12, 0x01, 0x14, 0x33, 0x32, 0x36, 0x3f, + 0x01, 0x26, 0x23, 0x22, 0x06, 0x06, 0xc7, 0x5c, 0xa8, 0x6f, 0x4a, 0x72, + 0x19, 0x10, 0x6c, 0xa7, 0xb1, 0xcc, 0x01, 0x0c, 0xd8, 0x56, 0xcf, 0x43, + 0x17, 0x4c, 0x40, 0x4c, 0x86, 0xf3, 0x9c, 0xca, 0xfe, 0xd6, 0x9f, 0x01, + 0x27, 0x01, 0x18, 0x6a, 0xfe, 0x7b, 0xd6, 0xfe, 0xfb, 0xfe, 0x84, 0xfe, + 0x57, 0xd9, 0x01, 0x91, 0x01, 0x05, 0xdc, 0x01, 0x5a, 0xbc, 0xfc, 0x00, + 0xac, 0x5a, 0x5e, 0x0a, 0x0d, 0x33, 0x40, 0x7d, 0x8b, 0x02, 0xf0, 0x90, + 0xef, 0x88, 0x47, 0x3a, 0x81, 0xd5, 0xb9, 0xd3, 0x01, 0x02, 0x21, 0x17, + 0xfe, 0x17, 0x8b, 0xbb, 0x97, 0xa1, 0xf7, 0x82, 0xa6, 0xfe, 0xc7, 0xcd, + 0xfe, 0xec, 0xfe, 0xd9, 0x2f, 0x2d, 0xc0, 0x5b, 0x01, 0x90, 0x01, 0x64, + 0xf7, 0x01, 0x93, 0xe5, 0xb4, 0xfe, 0xb4, 0xfe, 0xaa, 0xd3, 0x7f, 0x8f, + 0xdd, 0x0b, 0x9c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x05, 0x85, + 0x05, 0xbc, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x43, 0x40, 0x21, 0x02, 0x0d, + 0x03, 0x08, 0x01, 0x00, 0x06, 0x05, 0x0b, 0x0b, 0x03, 0x00, 0x00, 0x07, + 0x07, 0x0f, 0x03, 0x04, 0x04, 0x0e, 0x0d, 0x02, 0x4c, 0x59, 0x0d, 0x0d, + 0x03, 0x0b, 0x05, 0x03, 0x00, 0x03, 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x33, + 0x12, 0x39, 0x2f, 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x33, 0x12, 0x39, 0x39, 0x12, 0x39, + 0x39, 0x31, 0x30, 0x21, 0x03, 0x21, 0x03, 0x21, 0x01, 0x21, 0x09, 0x01, + 0x02, 0x26, 0x27, 0x06, 0x03, 0x04, 0x37, 0x6a, 0xfd, 0xeb, 0x6a, 0xfe, + 0xb2, 0x02, 0x04, 0x01, 0x7b, 0x02, 0x06, 0xfd, 0xfe, 0x93, 0x25, 0x08, + 0x21, 0x9c, 0x01, 0x5c, 0xfe, 0xa4, 0x05, 0xbc, 0xfa, 0x44, 0x02, 0x60, + 0x01, 0xd9, 0x7c, 0x24, 0x80, 0xfe, 0x07, 0x00, 0x00, 0x03, 0x00, 0xb8, + 0x00, 0x00, 0x04, 0xf4, 0x05, 0xb6, 0x00, 0x0f, 0x00, 0x18, 0x00, 0x20, + 0x00, 0x56, 0x40, 0x2c, 0x07, 0x14, 0x14, 0x04, 0x04, 0x1a, 0x1e, 0x0b, + 0x0b, 0x22, 0x10, 0x1a, 0x1a, 0x0f, 0x0f, 0x21, 0x08, 0x10, 0x19, 0x10, + 0x19, 0x4d, 0x59, 0x0c, 0x10, 0x01, 0x0d, 0x03, 0x10, 0x10, 0x0f, 0x00, + 0x0f, 0x1a, 0x4c, 0x59, 0x0f, 0x12, 0x00, 0x18, 0x4c, 0x59, 0x00, 0x03, + 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, + 0x2f, 0x5f, 0x5e, 0x5d, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, 0x01, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, + 0x12, 0x39, 0x31, 0x30, 0x13, 0x21, 0x20, 0x04, 0x15, 0x14, 0x06, 0x07, + 0x15, 0x1e, 0x01, 0x15, 0x14, 0x04, 0x23, 0x21, 0x01, 0x33, 0x32, 0x36, + 0x35, 0x34, 0x26, 0x2b, 0x01, 0x19, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, + 0x21, 0xb8, 0x01, 0xc7, 0x01, 0x37, 0x01, 0x19, 0x7b, 0x66, 0x8b, 0x7b, + 0xfe, 0xdf, 0xf8, 0xfd, 0xdd, 0x01, 0x36, 0xb4, 0x7e, 0x71, 0x7b, 0x85, + 0xa3, 0xca, 0x80, 0x7a, 0xfe, 0xfc, 0x05, 0xb6, 0xb1, 0xc1, 0x83, 0xa8, + 0x11, 0x0a, 0x1f, 0xaa, 0x8d, 0xc8, 0xe0, 0x03, 0x73, 0x4e, 0x5a, 0x54, + 0x49, 0xfd, 0xc5, 0xfe, 0x83, 0x62, 0x65, 0xb6, 0x00, 0x01, 0x00, 0x77, + 0xff, 0xec, 0x04, 0xd1, 0x05, 0xcb, 0x00, 0x16, 0x00, 0x31, 0x40, 0x18, + 0x07, 0x13, 0x13, 0x18, 0x03, 0x0d, 0x0d, 0x17, 0x14, 0x00, 0x11, 0x00, + 0x4c, 0x59, 0x11, 0x04, 0x07, 0x05, 0x0a, 0x05, 0x4c, 0x59, 0x0a, 0x13, + 0x00, 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x18, 0x3f, 0x2b, 0x11, 0x00, 0x33, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, + 0x22, 0x02, 0x15, 0x10, 0x21, 0x32, 0x37, 0x11, 0x06, 0x23, 0x20, 0x00, + 0x11, 0x34, 0x12, 0x24, 0x33, 0x32, 0x17, 0x07, 0x2e, 0x01, 0x03, 0x25, + 0xaf, 0xc0, 0x01, 0x6f, 0x9a, 0xdb, 0xb4, 0xde, 0xfe, 0xc1, 0xfe, 0xae, + 0xa6, 0x01, 0x37, 0xd1, 0xd5, 0xd7, 0x64, 0x52, 0xa6, 0x04, 0xc9, 0xfe, + 0xf9, 0xeb, 0xfe, 0x17, 0x4d, 0xfe, 0xfc, 0x4b, 0x01, 0x83, 0x01, 0x6a, + 0xe4, 0x01, 0x57, 0xb7, 0x67, 0xfc, 0x27, 0x3a, 0x00, 0x02, 0x00, 0xb8, + 0x00, 0x00, 0x05, 0x75, 0x05, 0xb6, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x28, + 0x40, 0x14, 0x09, 0x00, 0x00, 0x11, 0x0d, 0x04, 0x04, 0x10, 0x05, 0x0c, + 0x4c, 0x59, 0x05, 0x03, 0x04, 0x0d, 0x4c, 0x59, 0x04, 0x12, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x00, 0x29, 0x01, 0x11, 0x21, 0x20, + 0x00, 0x01, 0x10, 0x21, 0x23, 0x11, 0x33, 0x20, 0x05, 0x75, 0xfe, 0x65, + 0xfe, 0x7c, 0xfe, 0x62, 0x01, 0xcb, 0x01, 0x66, 0x01, 0x8c, 0xfe, 0xbe, + 0xfe, 0x60, 0xa5, 0x85, 0x01, 0xc0, 0x02, 0xe9, 0xfe, 0x97, 0xfe, 0x80, + 0x05, 0xb6, 0xfe, 0x86, 0xfe, 0xa5, 0x01, 0xd7, 0xfc, 0x48, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x04, 0x02, 0x05, 0xb6, 0x00, 0x0b, + 0x00, 0x45, 0x40, 0x24, 0x08, 0x04, 0x00, 0x00, 0x0d, 0x06, 0x0a, 0x0a, + 0x01, 0x01, 0x0c, 0x06, 0x09, 0x4c, 0x59, 0x0c, 0x06, 0x01, 0x0d, 0x03, + 0x06, 0x06, 0x01, 0x02, 0x02, 0x05, 0x4c, 0x59, 0x02, 0x03, 0x01, 0x0a, + 0x4c, 0x59, 0x01, 0x12, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x18, 0x2f, 0x5f, 0x5e, 0x5d, 0x2b, 0x11, 0x01, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x29, + 0x01, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x04, + 0x02, 0xfc, 0xb6, 0x03, 0x4a, 0xfd, 0xec, 0x01, 0xef, 0xfe, 0x11, 0x02, + 0x14, 0x05, 0xb6, 0xfe, 0xfe, 0xbf, 0xfe, 0xfe, 0x87, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x03, 0xfe, 0x05, 0xb6, 0x00, 0x09, + 0x00, 0x34, 0x40, 0x1a, 0x08, 0x03, 0x03, 0x0b, 0x06, 0x00, 0x00, 0x01, + 0x01, 0x0a, 0x06, 0x09, 0x4c, 0x59, 0x06, 0x06, 0x01, 0x02, 0x02, 0x05, + 0x4c, 0x59, 0x02, 0x03, 0x01, 0x12, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x21, 0x15, 0x21, + 0x11, 0x21, 0x15, 0x21, 0x01, 0xe9, 0xfe, 0xcf, 0x03, 0x46, 0xfd, 0xeb, + 0x01, 0xf0, 0xfe, 0x10, 0x05, 0xb6, 0xfe, 0xfe, 0x87, 0xfd, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x77, 0xff, 0xec, 0x05, 0x27, 0x05, 0xcb, 0x00, 0x1a, + 0x00, 0x4c, 0x40, 0x27, 0x1a, 0x18, 0x18, 0x02, 0x0e, 0x0d, 0x0d, 0x02, + 0x02, 0x13, 0x1c, 0x13, 0x08, 0x08, 0x1b, 0x0e, 0x10, 0x0b, 0x10, 0x4c, + 0x59, 0x00, 0x1a, 0x4c, 0x59, 0x00, 0x00, 0x05, 0x0b, 0x04, 0x18, 0x16, + 0x05, 0x16, 0x4c, 0x59, 0x02, 0x05, 0x13, 0x00, 0x3f, 0x33, 0x2b, 0x11, + 0x00, 0x33, 0x18, 0x3f, 0x12, 0x39, 0x2f, 0x2b, 0x2b, 0x11, 0x00, 0x33, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x39, 0x31, 0x30, 0x01, 0x21, 0x11, 0x0e, 0x01, 0x23, + 0x20, 0x00, 0x11, 0x10, 0x00, 0x21, 0x32, 0x17, 0x07, 0x26, 0x23, 0x22, + 0x02, 0x15, 0x14, 0x16, 0x33, 0x32, 0x37, 0x11, 0x21, 0x02, 0xe3, 0x02, + 0x44, 0x8d, 0xf9, 0x82, 0xfe, 0xb5, 0xfe, 0xa3, 0x01, 0x95, 0x01, 0x67, + 0xe1, 0xd1, 0x67, 0xa0, 0xad, 0xc9, 0xf2, 0xc3, 0xba, 0x61, 0x64, 0xfe, + 0xeb, 0x03, 0x35, 0xfd, 0x0a, 0x2e, 0x25, 0x01, 0x85, 0x01, 0x6c, 0x01, + 0x62, 0x01, 0x8c, 0x5a, 0xf8, 0x50, 0xfe, 0xf2, 0xe4, 0xee, 0xfb, 0x14, + 0x01, 0x31, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x05, 0x66, + 0x05, 0xb6, 0x00, 0x0b, 0x00, 0x37, 0x40, 0x1c, 0x09, 0x01, 0x01, 0x00, + 0x00, 0x0d, 0x08, 0x04, 0x04, 0x05, 0x05, 0x0c, 0x08, 0x03, 0x4c, 0x59, + 0x4c, 0x08, 0x01, 0x08, 0x08, 0x05, 0x0a, 0x06, 0x03, 0x01, 0x05, 0x12, + 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, 0x2f, 0x5d, 0x2b, 0x11, 0x01, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x29, 0x01, 0x11, 0x21, 0x11, 0x21, 0x11, 0x21, 0x11, 0x21, 0x11, + 0x21, 0x05, 0x66, 0xfe, 0xcb, 0xfd, 0xbd, 0xfe, 0xca, 0x01, 0x36, 0x02, + 0x43, 0x01, 0x35, 0x02, 0x77, 0xfd, 0x89, 0x05, 0xb6, 0xfd, 0xc3, 0x02, + 0x3d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x01, 0xee, + 0x05, 0xb6, 0x00, 0x03, 0x00, 0x11, 0xb6, 0x00, 0x04, 0x05, 0x01, 0x03, + 0x00, 0x12, 0x00, 0x3f, 0x3f, 0x11, 0x12, 0x01, 0x39, 0x31, 0x30, 0x33, + 0x11, 0x21, 0x11, 0xb8, 0x01, 0x36, 0x05, 0xb6, 0xfa, 0x4a, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x68, 0xfe, 0x52, 0x01, 0xee, 0x05, 0xb6, 0x00, 0x0d, + 0x00, 0x1f, 0x40, 0x0e, 0x0b, 0x02, 0x08, 0x08, 0x0e, 0x03, 0x05, 0x00, + 0x05, 0x4c, 0x59, 0x00, 0x09, 0x03, 0x00, 0x3f, 0xc4, 0x2b, 0x11, 0x00, + 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x13, 0x22, 0x27, + 0x11, 0x16, 0x33, 0x32, 0x36, 0x35, 0x11, 0x21, 0x11, 0x10, 0x02, 0x1f, + 0x69, 0x4e, 0x50, 0x42, 0x66, 0x58, 0x01, 0x36, 0xea, 0xfe, 0x52, 0x16, + 0x01, 0x02, 0x14, 0x7f, 0x87, 0x05, 0x5a, 0xfa, 0xa8, 0xff, 0x00, 0xfe, + 0xf4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x05, 0x50, + 0x05, 0xb6, 0x00, 0x0c, 0x00, 0x42, 0x40, 0x1f, 0x0c, 0x02, 0x02, 0x0a, + 0x0b, 0x0b, 0x01, 0x00, 0x00, 0x0e, 0x08, 0x03, 0x05, 0x05, 0x0d, 0x0c, + 0x02, 0x02, 0x03, 0x0b, 0x0b, 0x06, 0x03, 0x08, 0x08, 0x05, 0x06, 0x03, + 0x01, 0x05, 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x12, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x32, + 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x39, 0x11, 0x33, 0x31, 0x30, + 0x29, 0x01, 0x01, 0x07, 0x11, 0x21, 0x11, 0x21, 0x11, 0x37, 0x01, 0x21, + 0x01, 0x05, 0x50, 0xfe, 0xa0, 0xfe, 0x81, 0x83, 0xfe, 0xca, 0x01, 0x36, + 0x7a, 0x01, 0x8c, 0x01, 0x58, 0xfe, 0x02, 0x02, 0x68, 0x5e, 0xfd, 0xf6, + 0x05, 0xb6, 0xfd, 0x63, 0xac, 0x01, 0xf1, 0xfd, 0x79, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x04, 0x3f, 0x05, 0xb6, 0x00, 0x05, + 0x00, 0x1f, 0x40, 0x0e, 0x04, 0x07, 0x03, 0x00, 0x00, 0x06, 0x01, 0x03, + 0x00, 0x03, 0x4c, 0x59, 0x00, 0x12, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x33, 0x11, 0x21, + 0x11, 0x21, 0x11, 0xb8, 0x01, 0x36, 0x02, 0x51, 0x05, 0xb6, 0xfb, 0x4a, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x06, 0xd3, + 0x05, 0xb6, 0x00, 0x14, 0x00, 0x3a, 0x40, 0x1c, 0x14, 0x00, 0x09, 0x0b, + 0x09, 0x08, 0x03, 0x05, 0x0e, 0x0e, 0x0d, 0x0d, 0x16, 0x05, 0x06, 0x15, + 0x12, 0x02, 0x09, 0x02, 0x06, 0x0b, 0x07, 0x03, 0x0e, 0x00, 0x06, 0x12, + 0x00, 0x3f, 0x33, 0x33, 0x3f, 0x33, 0x12, 0x39, 0x39, 0x11, 0x33, 0x11, + 0x01, 0x33, 0x32, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, 0x11, + 0x33, 0x33, 0x31, 0x30, 0x21, 0x01, 0x23, 0x12, 0x15, 0x11, 0x21, 0x11, + 0x21, 0x01, 0x33, 0x01, 0x21, 0x11, 0x21, 0x11, 0x34, 0x36, 0x13, 0x23, + 0x01, 0x03, 0x23, 0xfe, 0xa0, 0x09, 0x13, 0xfe, 0xeb, 0x01, 0xa6, 0x01, + 0x5a, 0x06, 0x01, 0x6f, 0x01, 0xa6, 0xfe, 0xdf, 0x03, 0x0c, 0x09, 0xfe, + 0x87, 0x04, 0x7b, 0xfe, 0xa2, 0x75, 0xfd, 0x58, 0x05, 0xb6, 0xfb, 0xa2, + 0x04, 0x5e, 0xfa, 0x4a, 0x02, 0xb4, 0x31, 0x80, 0x01, 0x14, 0xfb, 0x87, + 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x05, 0xc9, 0x05, 0xb6, 0x00, 0x0f, + 0x00, 0x36, 0x40, 0x19, 0x0a, 0x00, 0x09, 0x01, 0x06, 0x0d, 0x0d, 0x00, + 0x00, 0x11, 0x03, 0x05, 0x06, 0x06, 0x07, 0x10, 0x0b, 0x03, 0x07, 0x0e, + 0x08, 0x03, 0x01, 0x07, 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, + 0x39, 0x11, 0x01, 0x33, 0x32, 0x11, 0x33, 0x39, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x12, 0x39, 0x39, 0x12, 0x39, 0x31, 0x30, 0x29, 0x01, 0x01, 0x23, + 0x12, 0x15, 0x11, 0x21, 0x11, 0x21, 0x01, 0x33, 0x02, 0x35, 0x11, 0x21, + 0x05, 0xc9, 0xfe, 0x76, 0xfd, 0x84, 0x09, 0x13, 0xfe, 0xeb, 0x01, 0x87, + 0x02, 0x7b, 0x07, 0x0f, 0x01, 0x17, 0x04, 0x52, 0xfe, 0xdb, 0x7d, 0xfd, + 0x50, 0x05, 0xb6, 0xfb, 0xb9, 0x01, 0x1d, 0x76, 0x02, 0xb4, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x77, 0xff, 0xec, 0x05, 0xe7, 0x05, 0xcd, 0x00, 0x0b, + 0x00, 0x15, 0x00, 0x28, 0x40, 0x14, 0x11, 0x00, 0x00, 0x17, 0x0c, 0x06, + 0x06, 0x16, 0x09, 0x13, 0x4c, 0x59, 0x09, 0x04, 0x03, 0x0f, 0x4c, 0x59, + 0x03, 0x13, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x01, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x00, 0x21, + 0x20, 0x00, 0x11, 0x10, 0x00, 0x21, 0x20, 0x00, 0x01, 0x14, 0x16, 0x33, + 0x20, 0x11, 0x10, 0x21, 0x22, 0x06, 0x05, 0xe7, 0xfe, 0x98, 0xfe, 0xb0, + 0xfe, 0xb0, 0xfe, 0x98, 0x01, 0x69, 0x01, 0x51, 0x01, 0x51, 0x01, 0x65, + 0xfb, 0xd5, 0xba, 0xb9, 0x01, 0x73, 0xfe, 0x8f, 0xb9, 0xbc, 0x02, 0xdd, + 0xfe, 0x95, 0xfe, 0x7a, 0x01, 0x86, 0x01, 0x6d, 0x01, 0x6d, 0x01, 0x81, + 0xfe, 0x7c, 0xfe, 0x94, 0xf5, 0xf8, 0x01, 0xed, 0x01, 0xee, 0xf9, 0x00, + 0x00, 0x02, 0x00, 0xb8, 0x00, 0x00, 0x04, 0xaa, 0x05, 0xb6, 0x00, 0x08, + 0x00, 0x13, 0x00, 0x34, 0x40, 0x1a, 0x04, 0x09, 0x09, 0x15, 0x00, 0x0e, + 0x0e, 0x0f, 0x0f, 0x14, 0x0d, 0x00, 0x4c, 0x59, 0x0d, 0x0d, 0x0f, 0x10, + 0x10, 0x08, 0x4c, 0x59, 0x10, 0x03, 0x0f, 0x12, 0x00, 0x3f, 0x3f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x33, 0x32, 0x36, + 0x35, 0x34, 0x26, 0x2b, 0x01, 0x05, 0x14, 0x04, 0x21, 0x23, 0x11, 0x21, + 0x11, 0x21, 0x20, 0x04, 0x01, 0xee, 0x66, 0x8f, 0x8e, 0x77, 0x7f, 0x8d, + 0x02, 0xbc, 0xfe, 0xd9, 0xfe, 0xf0, 0x85, 0xfe, 0xca, 0x01, 0xd3, 0x01, + 0x0a, 0x01, 0x15, 0x03, 0x06, 0x71, 0x6c, 0x6d, 0x68, 0xca, 0xec, 0xfa, + 0xfd, 0xf8, 0x05, 0xb6, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x77, + 0xfe, 0xa4, 0x05, 0xe7, 0x05, 0xcd, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x42, + 0x40, 0x22, 0x06, 0x03, 0x05, 0x04, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0a, + 0x15, 0x00, 0x00, 0x1b, 0x10, 0x0a, 0x0a, 0x1a, 0x03, 0x07, 0x0d, 0x0d, + 0x17, 0x4c, 0x59, 0x0d, 0x04, 0x07, 0x13, 0x4c, 0x59, 0x05, 0x07, 0x13, + 0x00, 0x3f, 0xc6, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, 0x17, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x02, 0x07, 0x01, 0x21, + 0x01, 0x23, 0x20, 0x00, 0x11, 0x10, 0x00, 0x21, 0x20, 0x00, 0x01, 0x14, + 0x16, 0x33, 0x20, 0x11, 0x10, 0x21, 0x22, 0x06, 0x05, 0xe7, 0xb7, 0xb1, + 0x01, 0x60, 0xfe, 0x73, 0xfe, 0xf4, 0x17, 0xfe, 0xb0, 0xfe, 0x98, 0x01, + 0x69, 0x01, 0x51, 0x01, 0x51, 0x01, 0x65, 0xfb, 0xd5, 0xba, 0xb9, 0x01, + 0x73, 0xfe, 0x8f, 0xb9, 0xbc, 0x02, 0xdd, 0xfe, 0xfe, 0xfe, 0xa3, 0x51, + 0xfe, 0x77, 0x01, 0x48, 0x01, 0x86, 0x01, 0x6d, 0x01, 0x6d, 0x01, 0x81, + 0xfe, 0x7c, 0xfe, 0x94, 0xf5, 0xf8, 0x01, 0xed, 0x01, 0xee, 0xf9, 0x00, + 0x00, 0x02, 0x00, 0xb8, 0x00, 0x00, 0x05, 0x48, 0x05, 0xb6, 0x00, 0x08, + 0x00, 0x17, 0x00, 0x4e, 0x40, 0x26, 0x13, 0x17, 0x17, 0x04, 0x0a, 0x04, + 0x10, 0x10, 0x0a, 0x16, 0x15, 0x19, 0x00, 0x0a, 0x0a, 0x0b, 0x0b, 0x18, + 0x13, 0x09, 0x0c, 0x00, 0x09, 0x4d, 0x59, 0x00, 0x00, 0x0b, 0x0c, 0x0c, + 0x08, 0x4c, 0x59, 0x0c, 0x03, 0x16, 0x0b, 0x12, 0x00, 0x3f, 0x33, 0x3f, + 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x00, 0x39, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x10, 0x18, 0xc4, 0x32, 0x11, + 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x19, 0x01, 0x21, 0x11, 0x21, + 0x20, 0x04, 0x15, 0x14, 0x06, 0x07, 0x00, 0x17, 0x21, 0x01, 0x01, 0xee, + 0x64, 0x93, 0x8c, 0x8f, 0x96, 0x5e, 0xfe, 0xca, 0x01, 0xaa, 0x01, 0x2a, + 0x01, 0x1e, 0x8e, 0x82, 0x01, 0x4a, 0x64, 0xfe, 0xa8, 0xfe, 0xa3, 0x03, + 0x2d, 0x62, 0x69, 0x68, 0x58, 0xfd, 0x79, 0xfd, 0xcf, 0x05, 0xb6, 0xd9, + 0xdd, 0x81, 0xc9, 0x39, 0xfe, 0x13, 0x90, 0x02, 0x31, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x5e, 0xff, 0xec, 0x04, 0x17, 0x05, 0xcb, 0x00, 0x27, + 0x00, 0x45, 0x40, 0x22, 0x1b, 0x1a, 0x1a, 0x21, 0x00, 0x21, 0x05, 0x14, + 0x0c, 0x00, 0x14, 0x00, 0x28, 0x29, 0x14, 0x21, 0x00, 0x0c, 0x21, 0x0c, + 0x1e, 0x09, 0x17, 0x1e, 0x4c, 0x59, 0x17, 0x04, 0x03, 0x09, 0x4c, 0x59, + 0x03, 0x13, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, + 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, + 0x14, 0x04, 0x23, 0x22, 0x27, 0x11, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, + 0x34, 0x2e, 0x01, 0x27, 0x2e, 0x02, 0x35, 0x34, 0x24, 0x33, 0x32, 0x16, + 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x15, 0x14, 0x1e, 0x01, 0x17, + 0x1e, 0x01, 0x04, 0x17, 0xfe, 0xe3, 0xfe, 0xea, 0xb4, 0x94, 0xcd, 0x55, + 0x66, 0x6d, 0x30, 0x5d, 0x8f, 0x86, 0x86, 0x50, 0x01, 0x07, 0xe8, 0x72, + 0xcf, 0x71, 0x64, 0x75, 0x99, 0x4a, 0x58, 0x5e, 0x26, 0x53, 0x9b, 0xcd, + 0x98, 0x01, 0x96, 0xc6, 0xe4, 0x58, 0x01, 0x20, 0x42, 0x36, 0x4e, 0x4d, + 0x2b, 0x43, 0x3e, 0x44, 0x3f, 0x74, 0x9a, 0x67, 0xc2, 0xde, 0x36, 0x31, + 0xf1, 0x30, 0x26, 0x52, 0x42, 0x29, 0x3d, 0x39, 0x4a, 0x62, 0xc5, 0x00, + 0x00, 0x01, 0x00, 0x29, 0x00, 0x00, 0x04, 0x79, 0x05, 0xb6, 0x00, 0x07, + 0x00, 0x26, 0x40, 0x12, 0x06, 0x00, 0x00, 0x03, 0x01, 0x01, 0x08, 0x09, + 0x07, 0x03, 0x04, 0x03, 0x4c, 0x59, 0x04, 0x03, 0x01, 0x12, 0x00, 0x3f, + 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x21, 0x11, 0x21, 0x11, 0x21, + 0x02, 0xec, 0xfe, 0xca, 0xfe, 0x73, 0x04, 0x50, 0xfe, 0x73, 0x04, 0xb4, + 0x01, 0x02, 0xfe, 0xfe, 0x00, 0x01, 0x00, 0xae, 0xff, 0xec, 0x05, 0x5e, + 0x05, 0xb6, 0x00, 0x12, 0x00, 0x25, 0x40, 0x11, 0x11, 0x01, 0x01, 0x14, + 0x0b, 0x08, 0x08, 0x13, 0x12, 0x09, 0x03, 0x05, 0x0e, 0x4c, 0x59, 0x05, + 0x13, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x33, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x11, 0x14, 0x06, 0x04, + 0x23, 0x20, 0x00, 0x35, 0x11, 0x21, 0x11, 0x14, 0x16, 0x33, 0x32, 0x36, + 0x35, 0x11, 0x05, 0x5e, 0x91, 0xfe, 0xee, 0xbb, 0xfe, 0xe6, 0xfe, 0xc8, + 0x01, 0x35, 0x88, 0x9d, 0x98, 0x89, 0x05, 0xb6, 0xfc, 0x4e, 0xa2, 0xf4, + 0x82, 0x01, 0x21, 0xfb, 0x03, 0xae, 0xfc, 0x81, 0xa9, 0x9e, 0x9f, 0xaa, + 0x03, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x33, + 0x05, 0xb6, 0x00, 0x0b, 0x00, 0x2a, 0x40, 0x13, 0x03, 0x02, 0x09, 0x09, + 0x05, 0x00, 0x01, 0x01, 0x0d, 0x05, 0x04, 0x04, 0x0c, 0x00, 0x04, 0x03, + 0x09, 0x03, 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x39, 0x11, 0x33, 0x33, 0x31, 0x30, + 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x1e, 0x01, 0x17, 0x36, 0x37, + 0x03, 0xfa, 0x01, 0x39, 0xfe, 0x0f, 0xfe, 0xae, 0xfe, 0x10, 0x01, 0x39, + 0x01, 0x13, 0x17, 0x31, 0x06, 0x0b, 0x40, 0x05, 0xb6, 0xfa, 0x4a, 0x05, + 0xb6, 0xfc, 0x9a, 0x4d, 0xcd, 0x28, 0x5c, 0xe6, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xbc, 0x05, 0xb6, 0x00, 0x1d, 0x00, 0x46, 0x40, 0x22, + 0x0a, 0x09, 0x0f, 0x14, 0x13, 0x05, 0x01, 0x00, 0x18, 0x18, 0x05, 0x0f, + 0x03, 0x0c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1f, 0x0c, 0x0b, 0x0b, 0x1e, 0x1c, + 0x13, 0x05, 0x0b, 0x03, 0x18, 0x0f, 0x0f, 0x01, 0x0a, 0x12, 0x00, 0x3f, + 0x33, 0x33, 0x11, 0x33, 0x3f, 0x33, 0x33, 0x33, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, 0x11, 0x33, 0x33, + 0x11, 0x33, 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x29, 0x01, 0x03, 0x26, + 0x02, 0x27, 0x0e, 0x01, 0x07, 0x03, 0x21, 0x01, 0x21, 0x13, 0x16, 0x17, + 0x3e, 0x01, 0x37, 0x13, 0x21, 0x13, 0x1e, 0x01, 0x17, 0x3e, 0x01, 0x37, + 0x13, 0x21, 0x06, 0x48, 0xfe, 0x9f, 0xc6, 0x0b, 0x35, 0x04, 0x06, 0x30, + 0x0d, 0xc5, 0xfe, 0xa0, 0xfe, 0x8b, 0x01, 0x31, 0xbb, 0x31, 0x16, 0x06, + 0x2b, 0x13, 0xd5, 0x01, 0x25, 0xd5, 0x0e, 0x2a, 0x0b, 0x0a, 0x2c, 0x12, + 0xba, 0x01, 0x31, 0x03, 0x00, 0x29, 0x01, 0x01, 0x2c, 0x36, 0xef, 0x33, + 0xfd, 0x02, 0x05, 0xb6, 0xfc, 0xe2, 0xdd, 0xa2, 0x39, 0xef, 0x42, 0x03, + 0x33, 0xfc, 0xcd, 0x37, 0xe2, 0x51, 0x4e, 0xe9, 0x48, 0x03, 0x1e, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x56, 0x05, 0xb6, 0x00, 0x0b, + 0x00, 0x44, 0x40, 0x20, 0x0b, 0x05, 0x02, 0x08, 0x08, 0x07, 0x09, 0x07, + 0x06, 0x09, 0x0a, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x0d, 0x03, 0x04, 0x0c, + 0x0b, 0x08, 0x02, 0x05, 0x05, 0x04, 0x09, 0x06, 0x03, 0x01, 0x04, 0x12, + 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, 0x11, 0x33, 0x33, 0x33, 0x11, + 0x01, 0x33, 0x32, 0x11, 0x33, 0x11, 0x33, 0x39, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x33, 0x33, 0x31, 0x30, 0x29, 0x01, + 0x09, 0x01, 0x21, 0x09, 0x01, 0x21, 0x09, 0x01, 0x21, 0x01, 0x05, 0x56, + 0xfe, 0x9e, 0xfe, 0xac, 0xfe, 0xac, 0xfe, 0xb4, 0x01, 0xe5, 0xfe, 0x3a, + 0x01, 0x56, 0x01, 0x3b, 0x01, 0x35, 0x01, 0x4e, 0xfe, 0x35, 0x02, 0x29, + 0xfd, 0xd7, 0x02, 0xf2, 0x02, 0xc4, 0xfd, 0xf2, 0x02, 0x0e, 0xfd, 0x2b, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0x05, 0xb6, 0x00, 0x08, + 0x00, 0x36, 0x40, 0x19, 0x08, 0x07, 0x07, 0x05, 0x01, 0x02, 0x02, 0x00, + 0x04, 0x04, 0x05, 0x05, 0x09, 0x0a, 0x03, 0x06, 0x06, 0x00, 0x00, 0x05, + 0x01, 0x07, 0x03, 0x05, 0x12, 0x00, 0x3f, 0x3f, 0x33, 0x12, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x12, 0x39, 0x32, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x09, 0x01, 0x21, 0x01, + 0x11, 0x21, 0x11, 0x01, 0x21, 0x02, 0x7f, 0x01, 0x31, 0x01, 0x4e, 0xfe, + 0x1b, 0xfe, 0xcc, 0xfe, 0x1b, 0x01, 0x50, 0x03, 0x5c, 0x02, 0x5a, 0xfc, + 0x83, 0xfd, 0xc7, 0x02, 0x2f, 0x03, 0x87, 0x00, 0x00, 0x01, 0x00, 0x31, + 0x00, 0x00, 0x04, 0x71, 0x05, 0xb6, 0x00, 0x09, 0x00, 0x3b, 0x40, 0x1d, + 0x08, 0x04, 0x01, 0x03, 0x07, 0x07, 0x00, 0x01, 0x00, 0x0a, 0x0b, 0x07, + 0x04, 0x05, 0x05, 0x04, 0x4c, 0x59, 0x05, 0x03, 0x02, 0x01, 0x08, 0x01, + 0x08, 0x4c, 0x59, 0x01, 0x12, 0x00, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, + 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x29, 0x01, 0x35, + 0x01, 0x21, 0x11, 0x21, 0x15, 0x01, 0x21, 0x04, 0x71, 0xfb, 0xc0, 0x02, + 0xbd, 0xfd, 0x56, 0x04, 0x1a, 0xfd, 0x44, 0x02, 0xcf, 0xc9, 0x03, 0xed, + 0x01, 0x00, 0xc8, 0xfc, 0x12, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x8f, + 0xfe, 0xbc, 0x02, 0x73, 0x05, 0xb6, 0x00, 0x07, 0x00, 0x1e, 0x40, 0x0d, + 0x06, 0x01, 0x01, 0x08, 0x04, 0x00, 0x09, 0x05, 0x02, 0x03, 0x06, 0x01, + 0x24, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x11, 0x01, 0x33, 0x32, 0x11, 0x39, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x21, 0x11, 0x21, 0x15, 0x23, 0x11, 0x33, + 0x02, 0x73, 0xfe, 0x1c, 0x01, 0xe4, 0xe0, 0xe0, 0xfe, 0xbc, 0x06, 0xfa, + 0xd3, 0xfa, 0xac, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x42, + 0x05, 0xb6, 0x00, 0x03, 0x00, 0x1c, 0x40, 0x0c, 0x00, 0x03, 0x03, 0x04, + 0x02, 0x01, 0x01, 0x05, 0x03, 0x03, 0x02, 0x12, 0x00, 0x3f, 0x3f, 0x11, + 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x09, 0x01, + 0x21, 0x01, 0x01, 0x21, 0x02, 0x21, 0xfe, 0xeb, 0xfd, 0xdf, 0x05, 0xb6, + 0xfa, 0x4a, 0x05, 0xb6, 0x00, 0x01, 0x00, 0x33, 0xfe, 0xbc, 0x02, 0x17, + 0x05, 0xb6, 0x00, 0x07, 0x00, 0x20, 0x40, 0x0e, 0x01, 0x06, 0x06, 0x09, + 0x03, 0x07, 0x07, 0x08, 0x00, 0x07, 0x24, 0x03, 0x04, 0x03, 0x00, 0x3f, + 0x33, 0x3f, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, + 0x31, 0x30, 0x17, 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x21, 0x33, 0xdf, + 0xdf, 0x01, 0xe4, 0xfe, 0x1c, 0x71, 0x05, 0x54, 0xd3, 0xf9, 0x06, 0x00, + 0x00, 0x01, 0x00, 0x08, 0x02, 0x08, 0x04, 0x3d, 0x05, 0xbe, 0x00, 0x06, + 0x00, 0x2d, 0x40, 0x14, 0x02, 0x01, 0x05, 0x05, 0x06, 0x04, 0x04, 0x03, + 0x03, 0x08, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x07, 0x05, 0x02, 0x06, + 0x00, 0x3f, 0x33, 0x12, 0x39, 0x2f, 0x33, 0x01, 0x32, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x33, 0x31, 0x30, 0x13, + 0x01, 0x33, 0x01, 0x23, 0x09, 0x01, 0x08, 0x01, 0xb6, 0x90, 0x01, 0xef, + 0xef, 0xfe, 0xbe, 0xfe, 0xe8, 0x02, 0x08, 0x03, 0xb6, 0xfc, 0x4a, 0x02, + 0x83, 0xfd, 0x7d, 0x00, 0x00, 0x01, 0xff, 0xfc, 0xfe, 0xbc, 0x03, 0x4e, + 0xff, 0x48, 0x00, 0x03, 0x00, 0x12, 0xb6, 0x00, 0x05, 0x01, 0x04, 0x02, + 0x01, 0x24, 0x00, 0x3f, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x01, 0x21, 0x35, 0x21, 0x03, 0x4e, 0xfc, 0xae, 0x03, 0x52, 0xfe, 0xbc, + 0x8c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x4c, 0x04, 0xd9, 0x03, 0x8d, + 0x06, 0x21, 0x00, 0x08, 0x00, 0x1c, 0x40, 0x0b, 0x00, 0x07, 0x40, 0x03, + 0x05, 0x05, 0x09, 0x0a, 0x05, 0x80, 0x00, 0x00, 0x2f, 0x1a, 0xdd, 0x11, + 0x12, 0x01, 0x39, 0x11, 0x33, 0x1a, 0xca, 0x32, 0x31, 0x30, 0x01, 0x2e, + 0x01, 0x27, 0x35, 0x21, 0x16, 0x17, 0x15, 0x02, 0xc3, 0x3f, 0xf4, 0x44, + 0x01, 0x56, 0x3f, 0xac, 0x04, 0xd9, 0x2c, 0xc5, 0x42, 0x15, 0x65, 0xc8, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x56, 0xff, 0xec, 0x04, 0x3b, + 0x04, 0x75, 0x00, 0x18, 0x00, 0x22, 0x00, 0x4a, 0x40, 0x26, 0x12, 0x0c, + 0x08, 0x0c, 0x02, 0x22, 0x22, 0x18, 0x18, 0x24, 0x1d, 0x08, 0x08, 0x23, + 0x0c, 0x19, 0x4b, 0x59, 0x0c, 0x0c, 0x05, 0x14, 0x14, 0x0f, 0x46, 0x59, + 0x14, 0x10, 0x02, 0x1f, 0x05, 0x1f, 0x46, 0x59, 0x05, 0x16, 0x00, 0x15, + 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x18, 0x3f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x12, 0x39, 0x32, 0x11, 0x12, 0x39, 0x31, 0x30, 0x21, 0x27, + 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3f, 0x01, 0x35, + 0x34, 0x23, 0x22, 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, 0x15, 0x11, 0x01, + 0x07, 0x0e, 0x01, 0x15, 0x14, 0x33, 0x32, 0x36, 0x35, 0x03, 0x66, 0x3b, + 0x08, 0x4d, 0xa3, 0x83, 0xa1, 0xb9, 0xf9, 0xfb, 0xc2, 0xae, 0x86, 0xb5, + 0x65, 0xc1, 0xeb, 0xe1, 0xf0, 0xfe, 0xd1, 0x76, 0x85, 0x82, 0x94, 0x6a, + 0x7f, 0x98, 0x61, 0x4b, 0xb8, 0xaa, 0xb2, 0xa9, 0x09, 0x06, 0x31, 0xaa, + 0x51, 0xce, 0x65, 0xc4, 0xc8, 0xfd, 0x17, 0x02, 0x06, 0x04, 0x04, 0x58, + 0x5a, 0x81, 0x7a, 0x65, 0x00, 0x02, 0x00, 0xa0, 0xff, 0xec, 0x04, 0xb4, + 0x06, 0x14, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x42, 0x40, 0x21, 0x1d, 0x03, + 0x03, 0x21, 0x09, 0x10, 0x0b, 0x0e, 0x17, 0x17, 0x0b, 0x0b, 0x20, 0x0c, + 0x00, 0x0b, 0x15, 0x09, 0x10, 0x06, 0x00, 0x06, 0x1a, 0x47, 0x59, 0x06, + 0x16, 0x00, 0x13, 0x47, 0x59, 0x00, 0x10, 0x00, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x18, 0x3f, 0x3f, 0x11, 0x01, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, + 0x31, 0x30, 0x01, 0x32, 0x12, 0x11, 0x10, 0x02, 0x23, 0x22, 0x27, 0x23, + 0x07, 0x23, 0x11, 0x21, 0x11, 0x14, 0x07, 0x33, 0x36, 0x17, 0x22, 0x06, + 0x07, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x03, 0x0e, + 0xc6, 0xe0, 0xe7, 0xc7, 0xc5, 0x70, 0x15, 0x33, 0xe9, 0x01, 0x31, 0x0c, + 0x0c, 0x6b, 0x70, 0x71, 0x68, 0x02, 0x6b, 0x74, 0x5e, 0x6f, 0x70, 0x04, + 0x73, 0xfe, 0xcb, 0xfe, 0xf3, 0xfe, 0xeb, 0xfe, 0xd0, 0x8f, 0x7b, 0x06, + 0x14, 0xfe, 0x96, 0x45, 0x98, 0xa6, 0xf4, 0x8b, 0xa0, 0x21, 0xb4, 0x9c, + 0xad, 0xa5, 0xa5, 0xa5, 0x00, 0x01, 0x00, 0x5c, 0xff, 0xec, 0x03, 0xdd, + 0x04, 0x73, 0x00, 0x15, 0x00, 0x2a, 0x40, 0x15, 0x13, 0x0d, 0x07, 0x07, + 0x17, 0x0d, 0x02, 0x02, 0x16, 0x05, 0x0b, 0x47, 0x59, 0x05, 0x10, 0x00, + 0x0f, 0x47, 0x59, 0x00, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x31, 0x30, + 0x05, 0x20, 0x11, 0x10, 0x00, 0x21, 0x32, 0x17, 0x07, 0x2e, 0x01, 0x23, + 0x22, 0x11, 0x10, 0x33, 0x32, 0x36, 0x37, 0x11, 0x0e, 0x01, 0x02, 0x66, + 0xfd, 0xf6, 0x01, 0x1c, 0x01, 0x09, 0xc2, 0x9a, 0x5a, 0x48, 0x7c, 0x3e, + 0xee, 0xee, 0x58, 0x96, 0x4b, 0x4a, 0x97, 0x14, 0x02, 0x3d, 0x01, 0x1d, + 0x01, 0x2d, 0x4c, 0xec, 0x1d, 0x25, 0xfe, 0xae, 0xfe, 0xb8, 0x2f, 0x32, + 0xfe, 0xfb, 0x2f, 0x24, 0x00, 0x02, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x71, + 0x06, 0x14, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x40, 0x40, 0x21, 0x09, 0x16, + 0x10, 0x03, 0x0b, 0x0b, 0x0e, 0x0e, 0x21, 0x1d, 0x03, 0x03, 0x20, 0x0f, + 0x15, 0x0c, 0x00, 0x11, 0x09, 0x00, 0x06, 0x06, 0x1a, 0x47, 0x59, 0x06, + 0x10, 0x00, 0x13, 0x47, 0x59, 0x00, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x18, 0x3f, 0x3f, 0x11, 0x01, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, 0x17, 0x39, 0x31, 0x30, + 0x05, 0x22, 0x02, 0x11, 0x10, 0x12, 0x33, 0x32, 0x17, 0x33, 0x26, 0x35, + 0x11, 0x21, 0x11, 0x23, 0x27, 0x23, 0x06, 0x27, 0x32, 0x36, 0x37, 0x35, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x02, 0x02, 0xc5, 0xe1, + 0xe5, 0xc9, 0xd3, 0x6f, 0x0a, 0x17, 0x01, 0x32, 0xea, 0x3b, 0x0d, 0x68, + 0x6a, 0x75, 0x6d, 0x05, 0x6f, 0x7d, 0x66, 0x71, 0x72, 0x14, 0x01, 0x32, + 0x01, 0x0f, 0x01, 0x13, 0x01, 0x33, 0xa4, 0x7d, 0x62, 0x01, 0x66, 0xf9, + 0xec, 0x91, 0xa5, 0xf3, 0x88, 0xa3, 0x21, 0xb4, 0x9c, 0xad, 0xa5, 0xa5, + 0xa5, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x62, + 0x04, 0x73, 0x00, 0x06, 0x00, 0x1b, 0x00, 0x46, 0x40, 0x23, 0x03, 0x12, + 0x04, 0x04, 0x19, 0x11, 0x11, 0x1d, 0x12, 0x0a, 0x0a, 0x1c, 0x18, 0x15, + 0x12, 0x03, 0x12, 0x4a, 0x59, 0x03, 0x03, 0x07, 0x0d, 0x0d, 0x00, 0x4a, + 0x59, 0x0d, 0x10, 0x07, 0x15, 0x46, 0x59, 0x07, 0x16, 0x00, 0x3f, 0x2b, + 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x33, 0x11, 0x12, 0x39, 0x31, 0x30, 0x01, 0x22, 0x06, 0x07, 0x21, 0x2e, + 0x01, 0x03, 0x20, 0x00, 0x11, 0x10, 0x00, 0x33, 0x32, 0x00, 0x1d, 0x01, + 0x21, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x15, 0x0e, 0x01, 0x02, 0x6f, + 0x61, 0x6e, 0x08, 0x01, 0xac, 0x02, 0x72, 0x36, 0xfe, 0xf2, 0xfe, 0xd0, + 0x01, 0x19, 0xf8, 0xed, 0x01, 0x08, 0xfd, 0x2f, 0x05, 0x90, 0x82, 0x65, + 0xb4, 0x62, 0x50, 0xb6, 0x03, 0x9a, 0x7b, 0x71, 0x71, 0x7b, 0xfc, 0x52, + 0x01, 0x2a, 0x01, 0x11, 0x01, 0x19, 0x01, 0x33, 0xfe, 0xf2, 0xee, 0x94, + 0x82, 0x92, 0x2a, 0x2e, 0xec, 0x28, 0x27, 0x00, 0x00, 0x01, 0x00, 0x29, + 0x00, 0x00, 0x03, 0x75, 0x06, 0x1f, 0x00, 0x15, 0x00, 0x3c, 0x40, 0x1e, + 0x14, 0x02, 0x02, 0x07, 0x05, 0x03, 0x03, 0x16, 0x17, 0x0d, 0x00, 0x00, + 0x17, 0x05, 0x01, 0x14, 0x01, 0x46, 0x59, 0x07, 0x14, 0x0f, 0x0b, 0x10, + 0x47, 0x59, 0x0b, 0x00, 0x03, 0x15, 0x00, 0x3f, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x33, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, + 0x12, 0x39, 0x11, 0x33, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x21, + 0x11, 0x21, 0x11, 0x23, 0x35, 0x37, 0x35, 0x34, 0x36, 0x33, 0x32, 0x17, + 0x07, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x21, 0x03, 0x0a, 0xfe, 0xf8, + 0xfe, 0xcf, 0xa8, 0xa8, 0xbc, 0xcf, 0x9e, 0x7b, 0x4e, 0x5c, 0x4e, 0x41, + 0x3a, 0x01, 0x08, 0x03, 0x79, 0xfc, 0x87, 0x03, 0x79, 0x93, 0x52, 0x52, + 0xbf, 0xb0, 0x2f, 0xe0, 0x1d, 0x4d, 0x3c, 0x46, 0x00, 0x03, 0x00, 0x06, + 0xfe, 0x14, 0x04, 0x6d, 0x04, 0x73, 0x00, 0x29, 0x00, 0x36, 0x00, 0x40, + 0x00, 0x80, 0x40, 0x44, 0x0b, 0x1d, 0x1d, 0x3d, 0x3d, 0x04, 0x30, 0x11, + 0x11, 0x02, 0x29, 0x07, 0x20, 0x04, 0x23, 0x01, 0x04, 0x04, 0x42, 0x1a, + 0x2a, 0x2a, 0x17, 0x17, 0x37, 0x23, 0x23, 0x41, 0x1a, 0x0d, 0x00, 0x0d, + 0x01, 0x0d, 0x06, 0x0d, 0x34, 0x07, 0x3a, 0x4b, 0x59, 0x09, 0x20, 0x04, + 0x03, 0x07, 0x07, 0x26, 0x34, 0x29, 0x02, 0x4a, 0x59, 0x29, 0x29, 0x26, + 0x26, 0x3f, 0x4b, 0x59, 0x26, 0x10, 0x14, 0x2d, 0x4a, 0x59, 0x14, 0x1b, + 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x18, 0x2f, + 0x2b, 0x00, 0x18, 0x2f, 0x12, 0x39, 0x2f, 0x17, 0x39, 0x2b, 0x11, 0x00, + 0x33, 0x5f, 0x5e, 0x5d, 0x12, 0x39, 0x11, 0x01, 0x33, 0x11, 0x33, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, 0x17, 0x39, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x15, + 0x07, 0x16, 0x15, 0x14, 0x06, 0x23, 0x2f, 0x01, 0x06, 0x15, 0x14, 0x3b, + 0x01, 0x32, 0x16, 0x15, 0x14, 0x04, 0x21, 0x22, 0x26, 0x35, 0x34, 0x36, + 0x37, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, 0x2e, 0x01, 0x35, 0x34, 0x36, + 0x33, 0x32, 0x16, 0x17, 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, + 0x26, 0x2b, 0x01, 0x22, 0x06, 0x13, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, + 0x34, 0x23, 0x22, 0x04, 0x6d, 0xaf, 0x30, 0xfb, 0xdf, 0x37, 0x2d, 0x2f, + 0xa8, 0xbe, 0xb8, 0xc1, 0xfe, 0xb9, 0xfe, 0xce, 0xea, 0xf7, 0x7e, 0x7a, + 0x2f, 0x46, 0x4a, 0x46, 0x58, 0x67, 0xee, 0xdd, 0x2f, 0x81, 0x12, 0xfe, + 0x27, 0x79, 0x6d, 0xa4, 0xba, 0x6e, 0x73, 0x9e, 0x54, 0x71, 0x6f, 0x53, + 0x55, 0x56, 0x50, 0xa6, 0xa8, 0x04, 0x5e, 0x9b, 0x2d, 0x4b, 0x5d, 0xb4, + 0xc9, 0x03, 0x05, 0x24, 0x2c, 0x42, 0x9e, 0x99, 0xc4, 0xd8, 0xa3, 0x93, + 0x65, 0x88, 0x1d, 0x14, 0x5b, 0x33, 0x40, 0x55, 0x29, 0x26, 0xa8, 0x72, + 0xb7, 0xc8, 0x11, 0x04, 0xfb, 0x04, 0x3f, 0x48, 0x5a, 0x4e, 0x3f, 0x30, + 0x4f, 0x03, 0x4d, 0x5b, 0x6a, 0x6a, 0x5b, 0xca, 0x00, 0x01, 0x00, 0xa0, + 0x00, 0x00, 0x04, 0xa8, 0x06, 0x14, 0x00, 0x15, 0x00, 0x35, 0x40, 0x1a, + 0x01, 0x00, 0x00, 0x17, 0x0f, 0x09, 0x0c, 0x08, 0x08, 0x09, 0x09, 0x16, + 0x0f, 0x04, 0x12, 0x12, 0x04, 0x47, 0x59, 0x12, 0x10, 0x0a, 0x00, 0x01, + 0x09, 0x15, 0x00, 0x3f, 0x33, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x34, 0x23, 0x22, 0x06, 0x15, 0x11, + 0x21, 0x11, 0x21, 0x11, 0x14, 0x0f, 0x01, 0x33, 0x36, 0x33, 0x32, 0x16, + 0x15, 0x04, 0xa8, 0xfe, 0xcf, 0xb4, 0x80, 0x72, 0xfe, 0xcf, 0x01, 0x31, + 0x07, 0x07, 0x10, 0x66, 0xde, 0xc5, 0xcc, 0x02, 0x8d, 0xf2, 0xae, 0xc3, + 0xfd, 0xf2, 0x06, 0x14, 0xfe, 0xc3, 0x25, 0x89, 0x5a, 0xa4, 0xd4, 0xc6, + 0x00, 0x02, 0x00, 0x93, 0x00, 0x00, 0x01, 0xdf, 0x06, 0x14, 0x00, 0x08, + 0x00, 0x0c, 0x00, 0x24, 0x40, 0x11, 0x04, 0x09, 0x09, 0x00, 0x0a, 0x0a, + 0x0d, 0x0b, 0x0f, 0x0a, 0x15, 0x02, 0x07, 0x49, 0x59, 0x02, 0x00, 0x00, + 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x3f, 0x11, 0x01, 0x33, 0x11, 0x33, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x13, 0x34, 0x33, 0x32, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x01, 0x21, 0x11, 0x21, 0x93, 0xa6, 0xa6, 0x53, 0x53, 0xa6, 0x01, + 0x3e, 0xfe, 0xcf, 0x01, 0x31, 0x05, 0x7f, 0x95, 0x95, 0x47, 0x4f, 0xfb, + 0x17, 0x04, 0x5e, 0x00, 0x00, 0x02, 0xff, 0x7d, 0xfe, 0x14, 0x01, 0xdf, + 0x06, 0x14, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x2f, 0x40, 0x18, 0x12, 0x0b, + 0x0b, 0x0e, 0x02, 0x08, 0x08, 0x17, 0x10, 0x15, 0x49, 0x59, 0x10, 0x00, + 0x09, 0x0f, 0x03, 0x05, 0x00, 0x05, 0x47, 0x59, 0x00, 0x1b, 0x00, 0x3f, + 0x2b, 0x11, 0x00, 0x33, 0x18, 0x3f, 0x3f, 0x2b, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x22, 0x27, 0x35, 0x16, + 0x33, 0x32, 0x36, 0x35, 0x11, 0x21, 0x11, 0x14, 0x06, 0x03, 0x34, 0x33, + 0x32, 0x15, 0x14, 0x06, 0x23, 0x22, 0x46, 0x75, 0x54, 0x46, 0x49, 0x4d, + 0x47, 0x01, 0x31, 0xce, 0x70, 0xa6, 0xa6, 0x53, 0x53, 0xa6, 0xfe, 0x14, + 0x19, 0xf0, 0x13, 0x56, 0x54, 0x04, 0xaa, 0xfb, 0x29, 0xb2, 0xc1, 0x07, + 0x6b, 0x95, 0x95, 0x47, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xa0, + 0x00, 0x00, 0x04, 0xf6, 0x06, 0x14, 0x00, 0x0e, 0x00, 0x49, 0x40, 0x23, + 0x04, 0x07, 0x07, 0x08, 0x02, 0x03, 0x03, 0x06, 0x05, 0x05, 0x10, 0x0e, + 0x0a, 0x0d, 0x0d, 0x08, 0x08, 0x0a, 0x0a, 0x0f, 0x0b, 0x00, 0x04, 0x07, + 0x07, 0x08, 0x08, 0x0e, 0x0e, 0x03, 0x06, 0x0a, 0x15, 0x03, 0x0f, 0x00, + 0x3f, 0x3f, 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, 0x39, 0x11, 0x33, 0x3f, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, + 0x37, 0x01, 0x21, 0x09, 0x01, 0x21, 0x01, 0x07, 0x11, 0x21, 0x11, 0x21, + 0x11, 0x07, 0x01, 0xc5, 0x85, 0x01, 0x39, 0x01, 0x58, 0xfe, 0x44, 0x01, + 0xd7, 0xfe, 0xa0, 0xfe, 0xbe, 0x83, 0xfe, 0xcf, 0x01, 0x31, 0x10, 0x02, + 0x60, 0xaa, 0x01, 0x54, 0xfe, 0x1b, 0xfd, 0x87, 0x01, 0xc5, 0x69, 0xfe, + 0xa4, 0x06, 0x14, 0xfd, 0x4a, 0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0xa0, + 0x00, 0x00, 0x01, 0xd1, 0x06, 0x14, 0x00, 0x03, 0x00, 0x13, 0xb7, 0x00, + 0x01, 0x01, 0x04, 0x02, 0x00, 0x01, 0x15, 0x00, 0x3f, 0x3f, 0x11, 0x01, + 0x33, 0x11, 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x21, 0x01, 0xd1, 0xfe, + 0xcf, 0x01, 0x31, 0x06, 0x14, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xa0, + 0x00, 0x00, 0x07, 0x42, 0x04, 0x73, 0x00, 0x23, 0x00, 0x4d, 0x40, 0x26, + 0x14, 0x13, 0x13, 0x00, 0x00, 0x01, 0x01, 0x0a, 0x1c, 0x1c, 0x1b, 0x1b, + 0x25, 0x0d, 0x09, 0x09, 0x0a, 0x0a, 0x24, 0x13, 0x0d, 0x0d, 0x11, 0x20, + 0x05, 0x11, 0x05, 0x47, 0x59, 0x17, 0x11, 0x10, 0x0b, 0x0f, 0x1c, 0x01, + 0x0a, 0x15, 0x00, 0x3f, 0x33, 0x33, 0x3f, 0x3f, 0x33, 0x2b, 0x11, 0x00, + 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x12, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x12, 0x39, 0x11, + 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, + 0x11, 0x21, 0x11, 0x33, 0x17, 0x33, 0x3e, 0x01, 0x33, 0x32, 0x17, 0x33, + 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x11, 0x21, 0x11, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x15, 0x04, 0x89, 0xfe, 0xcf, 0x51, 0x57, 0x75, 0x6a, 0xfe, + 0xcf, 0xe9, 0x29, 0x11, 0x2d, 0xaa, 0x6e, 0xfb, 0x59, 0x1b, 0x2d, 0xaf, + 0x6e, 0xbe, 0xc3, 0xfe, 0xce, 0x51, 0x57, 0x70, 0x6f, 0x02, 0x8d, 0x79, + 0x79, 0xac, 0xc5, 0xfd, 0xf2, 0x04, 0x5e, 0x8f, 0x4d, 0x57, 0xa4, 0x4e, + 0x56, 0xc3, 0xd7, 0xfd, 0x27, 0x02, 0x8d, 0x79, 0x79, 0xa0, 0xae, 0x00, + 0x00, 0x01, 0x00, 0xa0, 0x00, 0x00, 0x04, 0xa8, 0x04, 0x73, 0x00, 0x14, + 0x00, 0x31, 0x40, 0x18, 0x01, 0x00, 0x00, 0x16, 0x0d, 0x09, 0x09, 0x0a, + 0x0a, 0x15, 0x0d, 0x05, 0x11, 0x11, 0x05, 0x47, 0x59, 0x11, 0x10, 0x0b, + 0x0f, 0x01, 0x0a, 0x15, 0x00, 0x3f, 0x33, 0x3f, 0x3f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x11, 0x01, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, + 0x11, 0x21, 0x11, 0x33, 0x17, 0x33, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, + 0x04, 0xa8, 0xfe, 0xcf, 0x56, 0x5e, 0x80, 0x72, 0xfe, 0xcf, 0xe9, 0x29, + 0x11, 0x33, 0xb3, 0x72, 0xc3, 0xca, 0x02, 0x8d, 0x79, 0x79, 0xab, 0xc6, + 0xfd, 0xf2, 0x04, 0x5e, 0x8f, 0x51, 0x53, 0xd3, 0xc7, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x98, 0x04, 0x73, 0x00, 0x0b, + 0x00, 0x19, 0x00, 0x28, 0x40, 0x14, 0x06, 0x0c, 0x0c, 0x1b, 0x00, 0x13, + 0x13, 0x1a, 0x16, 0x09, 0x47, 0x59, 0x16, 0x10, 0x0f, 0x03, 0x47, 0x59, + 0x0f, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x01, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x16, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x05, 0x10, 0x00, 0x21, + 0x22, 0x26, 0x02, 0x35, 0x10, 0x00, 0x21, 0x32, 0x16, 0x12, 0x01, 0x93, + 0x6d, 0x7b, 0x7a, 0x6b, 0x6c, 0x7b, 0x7a, 0x6c, 0x03, 0x05, 0xfe, 0xe0, + 0xfe, 0xff, 0xa1, 0xf6, 0x84, 0x01, 0x1e, 0x01, 0x03, 0xa1, 0xf6, 0x84, + 0x02, 0x31, 0xa6, 0xaa, 0xa9, 0xa7, 0xa6, 0xa6, 0xa5, 0xa7, 0xfe, 0xef, + 0xfe, 0xcc, 0x8d, 0x01, 0x08, 0xb0, 0x01, 0x12, 0x01, 0x30, 0x8c, 0xfe, + 0xfa, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xa0, 0xfe, 0x14, 0x04, 0xb4, + 0x04, 0x73, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x43, 0x40, 0x22, 0x18, 0x06, + 0x06, 0x07, 0x0a, 0x03, 0x03, 0x07, 0x1d, 0x10, 0x07, 0x10, 0x20, 0x21, + 0x03, 0x0a, 0x00, 0x0d, 0x0d, 0x14, 0x47, 0x59, 0x0d, 0x10, 0x08, 0x0f, + 0x07, 0x1b, 0x00, 0x1b, 0x47, 0x59, 0x00, 0x16, 0x00, 0x3f, 0x2b, 0x00, + 0x18, 0x3f, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x05, 0x22, 0x27, 0x23, 0x16, 0x15, 0x11, 0x21, 0x11, + 0x33, 0x17, 0x33, 0x36, 0x33, 0x32, 0x12, 0x11, 0x14, 0x02, 0x06, 0x03, + 0x22, 0x06, 0x07, 0x15, 0x14, 0x16, 0x33, 0x32, 0x11, 0x34, 0x26, 0x03, + 0x06, 0xc5, 0x70, 0x10, 0x10, 0xfe, 0xcf, 0xf8, 0x2b, 0x0e, 0x6b, 0xd2, + 0xc6, 0xe0, 0x69, 0xc2, 0xdd, 0x71, 0x68, 0x02, 0x6b, 0x74, 0xcd, 0x65, + 0x14, 0x8f, 0x8c, 0x16, 0xfe, 0x3b, 0x06, 0x4a, 0x91, 0xa6, 0xfe, 0xce, + 0xfe, 0xf0, 0xb3, 0xfe, 0xf8, 0x8a, 0x03, 0x93, 0x8b, 0xa0, 0x21, 0xb4, + 0x9c, 0x01, 0x52, 0xa5, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5c, + 0xfe, 0x14, 0x04, 0x71, 0x04, 0x73, 0x00, 0x0b, 0x00, 0x20, 0x00, 0x42, + 0x40, 0x21, 0x16, 0x03, 0x1d, 0x03, 0x1a, 0x1a, 0x19, 0x19, 0x22, 0x09, + 0x0f, 0x0f, 0x21, 0x1a, 0x1b, 0x17, 0x0f, 0x1e, 0x16, 0x0c, 0x12, 0x12, + 0x07, 0x47, 0x59, 0x12, 0x10, 0x0c, 0x00, 0x47, 0x59, 0x0c, 0x16, 0x00, + 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x18, + 0x3f, 0x3f, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, + 0x39, 0x39, 0x11, 0x33, 0x31, 0x30, 0x25, 0x32, 0x36, 0x37, 0x35, 0x34, + 0x26, 0x23, 0x22, 0x11, 0x14, 0x16, 0x17, 0x22, 0x02, 0x11, 0x10, 0x12, + 0x33, 0x32, 0x16, 0x17, 0x33, 0x37, 0x21, 0x11, 0x21, 0x11, 0x34, 0x37, + 0x23, 0x0e, 0x01, 0x02, 0x6f, 0x74, 0x6c, 0x05, 0x6f, 0x7b, 0xd7, 0x6b, + 0x04, 0xc6, 0xe0, 0xe5, 0xc7, 0x6a, 0x9e, 0x3c, 0x08, 0x1b, 0x01, 0x02, + 0xfe, 0xce, 0x0d, 0x0d, 0x31, 0xa2, 0xdb, 0x85, 0xa6, 0x25, 0xb4, 0x9c, + 0xfe, 0xae, 0xa8, 0xa6, 0xef, 0x01, 0x31, 0x01, 0x10, 0x01, 0x12, 0x01, + 0x34, 0x50, 0x54, 0x8f, 0xf9, 0xb6, 0x01, 0xd5, 0x3d, 0x6b, 0x51, 0x54, + 0x00, 0x01, 0x00, 0xa0, 0x00, 0x00, 0x03, 0x77, 0x04, 0x73, 0x00, 0x10, + 0x00, 0x25, 0x40, 0x11, 0x02, 0x12, 0x0d, 0x09, 0x09, 0x0a, 0x0a, 0x11, + 0x0b, 0x0f, 0x0a, 0x15, 0x0d, 0x05, 0x05, 0x00, 0x10, 0x00, 0x3f, 0x32, + 0x11, 0x39, 0x3f, 0x3f, 0x11, 0x01, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x32, 0x17, 0x03, 0x26, 0x23, 0x22, 0x06, 0x15, + 0x11, 0x21, 0x11, 0x33, 0x17, 0x33, 0x3e, 0x01, 0x03, 0x10, 0x3e, 0x29, + 0x17, 0x25, 0x35, 0x92, 0xa3, 0xfe, 0xcf, 0xe7, 0x2d, 0x0f, 0x34, 0xb1, + 0x04, 0x73, 0x09, 0xfe, 0xe2, 0x0a, 0x96, 0x87, 0xfd, 0xc7, 0x04, 0x5e, + 0xbc, 0x5e, 0x73, 0x00, 0x00, 0x01, 0x00, 0x5c, 0xff, 0xec, 0x03, 0xac, + 0x04, 0x73, 0x00, 0x25, 0x00, 0x3f, 0x40, 0x1f, 0x06, 0x19, 0x14, 0x0c, + 0x00, 0x00, 0x27, 0x1f, 0x14, 0x14, 0x26, 0x00, 0x0c, 0x14, 0x1f, 0x0c, + 0x1f, 0x0a, 0x1d, 0x17, 0x1d, 0x46, 0x59, 0x17, 0x10, 0x03, 0x0a, 0x46, + 0x59, 0x03, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x39, 0x31, 0x30, 0x01, 0x14, 0x06, + 0x23, 0x22, 0x26, 0x27, 0x35, 0x1e, 0x01, 0x33, 0x32, 0x35, 0x34, 0x2e, + 0x01, 0x27, 0x2e, 0x02, 0x35, 0x34, 0x36, 0x33, 0x32, 0x17, 0x07, 0x2e, + 0x01, 0x23, 0x22, 0x15, 0x14, 0x16, 0x17, 0x1e, 0x02, 0x03, 0xac, 0xef, + 0xee, 0x7a, 0xac, 0x4b, 0x55, 0xd5, 0x51, 0xa6, 0x2c, 0x6c, 0x5a, 0x81, + 0x79, 0x37, 0xe7, 0xd4, 0xca, 0xbf, 0x5c, 0x54, 0x92, 0x4c, 0x87, 0x57, + 0x93, 0x83, 0x7a, 0x3a, 0x01, 0x4c, 0xac, 0xb4, 0x21, 0x20, 0xfc, 0x28, + 0x36, 0x60, 0x24, 0x2d, 0x39, 0x26, 0x36, 0x5c, 0x77, 0x57, 0x95, 0xa3, + 0x58, 0xdc, 0x24, 0x2e, 0x49, 0x29, 0x3c, 0x3b, 0x35, 0x5c, 0x78, 0x00, + 0x00, 0x01, 0x00, 0x2f, 0xff, 0xec, 0x03, 0x37, 0x05, 0x4c, 0x00, 0x15, + 0x00, 0x3d, 0x40, 0x1e, 0x0c, 0x08, 0x0f, 0x0f, 0x13, 0x13, 0x0a, 0x08, + 0x02, 0x11, 0x08, 0x11, 0x16, 0x17, 0x0a, 0x12, 0x0f, 0x12, 0x46, 0x59, + 0x0d, 0x0c, 0x0f, 0x0f, 0x05, 0x00, 0x47, 0x59, 0x05, 0x16, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x33, 0xc1, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x12, + 0x39, 0x31, 0x30, 0x25, 0x32, 0x37, 0x15, 0x06, 0x23, 0x22, 0x26, 0x35, + 0x11, 0x23, 0x35, 0x3f, 0x01, 0x33, 0x15, 0x21, 0x15, 0x21, 0x11, 0x14, + 0x16, 0x02, 0x77, 0x50, 0x70, 0x72, 0xa6, 0xb7, 0xa7, 0x92, 0xa8, 0x58, + 0xc3, 0x01, 0x39, 0xfe, 0xc7, 0x49, 0xdf, 0x23, 0xe3, 0x33, 0xb9, 0xb9, + 0x02, 0x1b, 0x81, 0x66, 0xec, 0xee, 0xe5, 0xfd, 0xe5, 0x41, 0x3e, 0x00, + 0x00, 0x01, 0x00, 0x9a, 0xff, 0xec, 0x04, 0xa2, 0x04, 0x5e, 0x00, 0x14, + 0x00, 0x32, 0x40, 0x18, 0x02, 0x11, 0x11, 0x14, 0x14, 0x16, 0x0b, 0x08, + 0x08, 0x15, 0x12, 0x09, 0x0f, 0x02, 0x05, 0x0e, 0x05, 0x0e, 0x47, 0x59, + 0x05, 0x16, 0x00, 0x15, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, + 0x18, 0x3f, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x12, 0x39, 0x31, 0x30, 0x21, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, + 0x35, 0x11, 0x21, 0x11, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x11, 0x21, + 0x11, 0x03, 0xb8, 0x29, 0x10, 0x31, 0xb4, 0x73, 0xc5, 0xc8, 0x01, 0x31, + 0x56, 0x5e, 0x80, 0x72, 0x01, 0x31, 0x8f, 0x4e, 0x55, 0xd3, 0xc6, 0x02, + 0xd9, 0xfd, 0x73, 0x79, 0x79, 0xab, 0xc6, 0x02, 0x0e, 0xfb, 0xa2, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x8d, 0x04, 0x5e, 0x00, 0x0b, + 0x00, 0x2c, 0x40, 0x14, 0x0b, 0x00, 0x05, 0x05, 0x02, 0x09, 0x09, 0x0a, + 0x0a, 0x0d, 0x02, 0x01, 0x01, 0x0c, 0x09, 0x01, 0x0f, 0x05, 0x00, 0x15, + 0x00, 0x3f, 0x32, 0x3f, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x33, 0x31, 0x30, 0x21, 0x01, + 0x21, 0x13, 0x16, 0x17, 0x33, 0x36, 0x37, 0x13, 0x21, 0x01, 0x01, 0xaa, + 0xfe, 0x56, 0x01, 0x3f, 0xd8, 0x24, 0x09, 0x06, 0x05, 0x28, 0xd7, 0x01, + 0x3f, 0xfe, 0x56, 0x04, 0x5e, 0xfd, 0x83, 0x79, 0x6c, 0x60, 0x85, 0x02, + 0x7d, 0xfb, 0xa2, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x06, 0xc5, + 0x04, 0x5e, 0x00, 0x1d, 0x00, 0x4a, 0x40, 0x24, 0x05, 0x04, 0x0a, 0x10, + 0x0f, 0x03, 0x1d, 0x00, 0x17, 0x17, 0x03, 0x0a, 0x03, 0x07, 0x1b, 0x1b, + 0x1c, 0x1c, 0x1f, 0x07, 0x06, 0x06, 0x1e, 0x17, 0x0a, 0x0a, 0x03, 0x05, + 0x0f, 0x0f, 0x1b, 0x06, 0x0f, 0x00, 0x05, 0x15, 0x00, 0x3f, 0x33, 0x3f, + 0x33, 0x33, 0x11, 0x12, 0x39, 0x39, 0x11, 0x33, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, 0x11, 0x33, 0x33, + 0x11, 0x33, 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x21, 0x0b, 0x01, 0x23, + 0x03, 0x21, 0x01, 0x21, 0x13, 0x16, 0x17, 0x33, 0x36, 0x3f, 0x01, 0x13, + 0x21, 0x13, 0x1e, 0x03, 0x17, 0x33, 0x3e, 0x01, 0x37, 0x13, 0x21, 0x01, + 0x04, 0x37, 0x56, 0x74, 0x07, 0xcc, 0xfe, 0xb8, 0xfe, 0xc2, 0x01, 0x30, + 0x81, 0x1f, 0x20, 0x06, 0x04, 0x1f, 0x10, 0x8a, 0x01, 0x50, 0x83, 0x04, + 0x11, 0x10, 0x0d, 0x01, 0x06, 0x09, 0x2e, 0x0a, 0x86, 0x01, 0x2b, 0xfe, + 0xbe, 0x01, 0x87, 0x01, 0xee, 0xfc, 0x8b, 0x04, 0x5e, 0xfe, 0x11, 0x85, + 0xea, 0x4c, 0xa5, 0x55, 0x02, 0x18, 0xfd, 0xe8, 0x16, 0x56, 0x61, 0x5d, + 0x1c, 0x48, 0xfb, 0x2c, 0x01, 0xef, 0xfb, 0xa2, 0x00, 0x01, 0x00, 0x0a, + 0x00, 0x00, 0x04, 0x96, 0x04, 0x5e, 0x00, 0x0b, 0x00, 0x4c, 0x40, 0x24, + 0x06, 0x05, 0x00, 0x01, 0x09, 0x03, 0x03, 0x02, 0x04, 0x02, 0x01, 0x04, + 0x05, 0x01, 0x05, 0x0b, 0x08, 0x07, 0x07, 0x0d, 0x0a, 0x0b, 0x0b, 0x0c, + 0x09, 0x06, 0x03, 0x00, 0x00, 0x01, 0x08, 0x0b, 0x15, 0x04, 0x01, 0x0f, + 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, 0x11, 0x33, 0x33, 0x33, 0x11, + 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x12, 0x39, 0x12, 0x39, + 0x31, 0x30, 0x09, 0x01, 0x21, 0x1b, 0x01, 0x21, 0x09, 0x01, 0x21, 0x0b, + 0x01, 0x21, 0x01, 0x85, 0xfe, 0x98, 0x01, 0x5a, 0xd9, 0xdb, 0x01, 0x5a, + 0xfe, 0x94, 0x01, 0x7d, 0xfe, 0xa5, 0xeb, 0xec, 0xfe, 0xa6, 0x02, 0x3b, + 0x02, 0x23, 0xfe, 0x9c, 0x01, 0x64, 0xfd, 0xdd, 0xfd, 0xc5, 0x01, 0x7f, + 0xfe, 0x81, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xfe, 0x14, 0x04, 0x8d, + 0x04, 0x5e, 0x00, 0x16, 0x00, 0x4c, 0x40, 0x25, 0x0b, 0x14, 0x14, 0x10, + 0x16, 0x16, 0x04, 0x04, 0x01, 0x08, 0x08, 0x09, 0x09, 0x18, 0x10, 0x01, + 0x00, 0x00, 0x17, 0x0b, 0x14, 0x14, 0x12, 0x04, 0x16, 0x15, 0x10, 0x12, + 0x0d, 0x12, 0x47, 0x59, 0x0d, 0x1b, 0x08, 0x00, 0x0f, 0x00, 0x3f, 0x32, + 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x18, 0x3f, 0x33, 0x12, 0x39, 0x11, 0x33, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, + 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x31, 0x30, 0x11, 0x21, + 0x13, 0x16, 0x17, 0x33, 0x36, 0x37, 0x13, 0x21, 0x01, 0x0e, 0x01, 0x23, + 0x22, 0x27, 0x35, 0x16, 0x33, 0x32, 0x36, 0x3f, 0x01, 0x01, 0x4e, 0xd3, + 0x1b, 0x0a, 0x06, 0x0b, 0x20, 0xcf, 0x01, 0x47, 0xfe, 0x27, 0x41, 0xf1, + 0xa1, 0x4f, 0x4c, 0x37, 0x41, 0x51, 0x79, 0x22, 0x12, 0x04, 0x5e, 0xfd, + 0x8b, 0x52, 0x70, 0x67, 0x5b, 0x02, 0x75, 0xfb, 0x13, 0xaf, 0xae, 0x11, + 0xf2, 0x0d, 0x63, 0x64, 0x37, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, + 0x00, 0x00, 0x03, 0xaa, 0x04, 0x5e, 0x00, 0x09, 0x00, 0x3d, 0x40, 0x1e, + 0x03, 0x07, 0x04, 0x07, 0x01, 0x00, 0x00, 0x0b, 0x08, 0x01, 0x01, 0x0a, + 0x07, 0x04, 0x05, 0x05, 0x04, 0x46, 0x59, 0x05, 0x0f, 0x02, 0x08, 0x01, + 0x01, 0x08, 0x46, 0x59, 0x01, 0x15, 0x00, 0x3f, 0x2b, 0x11, 0x12, 0x00, + 0x39, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, 0x11, 0x33, 0x31, 0x30, 0x29, + 0x01, 0x35, 0x01, 0x21, 0x35, 0x21, 0x15, 0x01, 0x21, 0x03, 0xaa, 0xfc, + 0x8d, 0x02, 0x06, 0xfe, 0x19, 0x03, 0x42, 0xfe, 0x08, 0x02, 0x0a, 0xb4, + 0x02, 0xc1, 0xe9, 0xc6, 0xfd, 0x51, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1f, + 0xfe, 0xbc, 0x02, 0xd5, 0x05, 0xb6, 0x00, 0x1f, 0x00, 0x36, 0x40, 0x19, + 0x03, 0x14, 0x08, 0x1f, 0x1f, 0x11, 0x18, 0x18, 0x20, 0x0d, 0x1c, 0x1c, + 0x21, 0x04, 0x03, 0x13, 0x13, 0x0d, 0x1b, 0x1b, 0x1c, 0x24, 0x0d, 0x0c, + 0x03, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x33, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, + 0x33, 0x39, 0x31, 0x30, 0x01, 0x34, 0x26, 0x23, 0x35, 0x32, 0x36, 0x3d, + 0x01, 0x11, 0x34, 0x36, 0x33, 0x15, 0x0e, 0x01, 0x15, 0x11, 0x06, 0x07, + 0x15, 0x16, 0x1d, 0x01, 0x11, 0x14, 0x16, 0x17, 0x15, 0x22, 0x26, 0x35, + 0x01, 0x1f, 0x83, 0x7d, 0x7e, 0x82, 0xc2, 0xf4, 0x63, 0x4b, 0x06, 0xe4, + 0xea, 0x4a, 0x64, 0xf4, 0xc2, 0x01, 0x0e, 0x57, 0x5c, 0xef, 0x58, 0x52, + 0x08, 0x01, 0x3e, 0x99, 0x7d, 0xe1, 0x03, 0x46, 0x44, 0xfe, 0xd5, 0xbc, + 0x22, 0x0c, 0x23, 0xb1, 0x09, 0xfe, 0xd5, 0x44, 0x46, 0x03, 0xe2, 0x7d, + 0x9a, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xc7, 0xfe, 0x2f, 0x02, 0xa2, + 0x06, 0x0e, 0x00, 0x03, 0x00, 0x14, 0xb7, 0x02, 0x03, 0x03, 0x04, 0x05, + 0x03, 0x00, 0x00, 0x00, 0x3f, 0x2f, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, + 0x31, 0x30, 0x01, 0x33, 0x11, 0x23, 0x01, 0xc7, 0xdb, 0xdb, 0x06, 0x0e, + 0xf8, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x52, 0xfe, 0xbc, 0x03, 0x08, + 0x05, 0xb6, 0x00, 0x22, 0x00, 0x36, 0x40, 0x19, 0x1f, 0x1a, 0x0d, 0x00, + 0x00, 0x10, 0x08, 0x08, 0x24, 0x14, 0x04, 0x04, 0x23, 0x1f, 0x1e, 0x0e, + 0x0e, 0x14, 0x05, 0x14, 0x15, 0x03, 0x05, 0x04, 0x24, 0x00, 0x3f, 0x33, + 0x3f, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x33, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x12, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x33, 0x39, 0x31, 0x30, + 0x05, 0x14, 0x0e, 0x01, 0x23, 0x35, 0x3e, 0x01, 0x35, 0x11, 0x35, 0x34, + 0x36, 0x37, 0x35, 0x26, 0x27, 0x11, 0x34, 0x26, 0x27, 0x35, 0x32, 0x1e, + 0x01, 0x15, 0x11, 0x15, 0x14, 0x16, 0x33, 0x15, 0x22, 0x06, 0x15, 0x02, + 0x08, 0x52, 0xbd, 0xa7, 0x63, 0x4b, 0x76, 0x73, 0xe3, 0x06, 0x4a, 0x64, + 0xa7, 0xbe, 0x51, 0x7b, 0x85, 0x7d, 0x83, 0x2d, 0x70, 0x72, 0x35, 0xe2, + 0x02, 0x44, 0x47, 0x01, 0x2b, 0x0b, 0x56, 0x6b, 0x11, 0x0c, 0x22, 0xbc, + 0x01, 0x2b, 0x46, 0x44, 0x03, 0xe1, 0x35, 0x73, 0x6e, 0xfe, 0xc2, 0x0a, + 0x54, 0x54, 0xef, 0x52, 0x61, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x58, + 0x02, 0x27, 0x04, 0x39, 0x03, 0x7d, 0x00, 0x15, 0x00, 0x37, 0x40, 0x18, + 0x06, 0x00, 0x11, 0x0b, 0x00, 0x0b, 0x03, 0x0f, 0x0f, 0x17, 0x03, 0x16, + 0x0f, 0x0e, 0x0e, 0x06, 0x04, 0x03, 0x03, 0x0b, 0x11, 0x11, 0x00, 0x06, + 0x00, 0x2f, 0x33, 0x32, 0x7d, 0x2f, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x22, 0x06, 0x07, 0x35, 0x36, 0x33, + 0x32, 0x16, 0x17, 0x16, 0x33, 0x32, 0x36, 0x37, 0x15, 0x06, 0x23, 0x22, + 0x26, 0x27, 0x26, 0x01, 0x42, 0x37, 0x7d, 0x36, 0x67, 0x99, 0x49, 0x81, + 0x4b, 0x81, 0x62, 0x35, 0x7e, 0x36, 0x65, 0x9b, 0x42, 0x78, 0x5a, 0x83, + 0x02, 0xa0, 0x43, 0x36, 0xe7, 0x6d, 0x20, 0x20, 0x37, 0x40, 0x39, 0xe7, + 0x6d, 0x1a, 0x25, 0x38, 0x00, 0x02, 0x00, 0x75, 0xfe, 0x8f, 0x01, 0xd3, + 0x04, 0x5e, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x26, 0x40, 0x12, 0x03, 0x0a, + 0x0a, 0x02, 0x04, 0x04, 0x11, 0x10, 0x00, 0x07, 0x0d, 0x07, 0x54, 0x59, + 0x0d, 0x0f, 0x03, 0x22, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x11, + 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x33, + 0x13, 0x21, 0x01, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, + 0x32, 0x16, 0xa8, 0xf4, 0x33, 0xfe, 0xa6, 0x01, 0x5e, 0x5a, 0x56, 0x53, + 0x5b, 0x5d, 0x51, 0x54, 0x5c, 0x02, 0x5e, 0xfc, 0x31, 0x05, 0x25, 0x54, + 0x56, 0x58, 0x52, 0x51, 0x59, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x8f, + 0xff, 0xec, 0x04, 0x10, 0x05, 0xcb, 0x00, 0x1b, 0x00, 0x44, 0x40, 0x23, + 0x11, 0x08, 0x1a, 0x1a, 0x05, 0x1b, 0x1b, 0x02, 0x17, 0x17, 0x0a, 0x02, + 0x0a, 0x1c, 0x1d, 0x19, 0x13, 0x4f, 0x59, 0x08, 0x0e, 0x4f, 0x59, 0x00, + 0x05, 0x08, 0x19, 0x08, 0x19, 0x08, 0x06, 0x1b, 0x19, 0x06, 0x07, 0x00, + 0x3f, 0x3f, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x12, 0x39, 0x39, 0x2b, 0x2b, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, + 0x33, 0x11, 0x33, 0x32, 0x31, 0x30, 0x25, 0x24, 0x11, 0x10, 0x12, 0x37, + 0x35, 0x33, 0x15, 0x16, 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x15, + 0x10, 0x33, 0x32, 0x36, 0x37, 0x15, 0x06, 0x07, 0x15, 0x23, 0x02, 0x33, + 0xfe, 0x5c, 0xd1, 0xd3, 0xb2, 0xa6, 0x85, 0x5a, 0x48, 0x7c, 0x3e, 0x79, + 0x74, 0xed, 0x52, 0x84, 0x64, 0x7f, 0x8a, 0xb2, 0xb0, 0x3b, 0x01, 0xfa, + 0x01, 0x05, 0x01, 0x1c, 0x1f, 0xa6, 0x9e, 0x09, 0x41, 0xeb, 0x1d, 0x24, + 0xa7, 0xab, 0xfe, 0xb9, 0x1f, 0x2d, 0xfe, 0x3d, 0x09, 0xbc, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x52, 0x00, 0x00, 0x04, 0x6a, 0x05, 0xcb, 0x00, 0x1d, + 0x00, 0x58, 0x40, 0x2c, 0x0f, 0x12, 0x0b, 0x02, 0x09, 0x0d, 0x0d, 0x1a, + 0x16, 0x16, 0x02, 0x18, 0x10, 0x18, 0x12, 0x12, 0x10, 0x1e, 0x1f, 0x0c, + 0x18, 0x19, 0x18, 0x51, 0x59, 0x09, 0x19, 0x19, 0x00, 0x13, 0x12, 0x0f, + 0x12, 0x0f, 0x4e, 0x59, 0x12, 0x18, 0x00, 0x05, 0x4f, 0x59, 0x00, 0x07, + 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, + 0x39, 0x18, 0x2f, 0x33, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, 0x01, 0x39, + 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, + 0x12, 0x39, 0x12, 0x39, 0x31, 0x30, 0x01, 0x32, 0x17, 0x07, 0x26, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x21, 0x15, 0x21, 0x15, 0x14, 0x07, 0x21, 0x11, + 0x21, 0x35, 0x3e, 0x01, 0x3d, 0x01, 0x23, 0x35, 0x33, 0x35, 0x34, 0x36, + 0x02, 0xbc, 0xc3, 0xc3, 0x5d, 0x9d, 0x73, 0x4e, 0x54, 0x01, 0x77, 0xfe, + 0x89, 0x97, 0x02, 0xce, 0xfb, 0xe8, 0x67, 0x4d, 0xb2, 0xb2, 0xe5, 0x05, + 0xcb, 0x52, 0xe6, 0x40, 0x59, 0x53, 0xc1, 0xdb, 0x8f, 0xaa, 0x4e, 0xfe, + 0xfc, 0xf8, 0x2c, 0x72, 0x64, 0x91, 0xdb, 0xc3, 0xc9, 0xd9, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x71, 0x00, 0xfe, 0x04, 0x21, 0x04, 0xaa, 0x00, 0x1b, + 0x00, 0x27, 0x00, 0x3c, 0x40, 0x22, 0x10, 0x0c, 0x13, 0x09, 0x05, 0x17, + 0x1a, 0x02, 0x08, 0x00, 0x0e, 0x0e, 0x22, 0x1c, 0x00, 0x1c, 0x1c, 0x28, + 0x29, 0x17, 0x13, 0x10, 0x1a, 0x02, 0x0c, 0x09, 0x05, 0x08, 0x07, 0x15, + 0x15, 0x1f, 0x07, 0x25, 0x00, 0x2f, 0x33, 0xc6, 0x32, 0x11, 0x12, 0x17, + 0x39, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x10, 0xc2, 0x32, 0x11, 0x12, + 0x17, 0x39, 0x31, 0x30, 0x13, 0x34, 0x37, 0x27, 0x37, 0x17, 0x36, 0x33, + 0x32, 0x17, 0x37, 0x17, 0x07, 0x16, 0x15, 0x14, 0x07, 0x17, 0x07, 0x27, + 0x06, 0x23, 0x22, 0x27, 0x07, 0x27, 0x37, 0x26, 0x37, 0x14, 0x16, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0xbc, 0x36, 0x81, 0x93, + 0x7f, 0x5b, 0x6a, 0x69, 0x5b, 0x7f, 0x96, 0x81, 0x35, 0x35, 0x7d, 0x92, + 0x7f, 0x5f, 0x65, 0x73, 0x54, 0x7d, 0x91, 0x7f, 0x36, 0xcf, 0x6d, 0x50, + 0x51, 0x6f, 0x71, 0x4f, 0x4e, 0x6f, 0x02, 0xd3, 0x66, 0x5f, 0x7f, 0x93, + 0x7f, 0x35, 0x37, 0x81, 0x8f, 0x81, 0x59, 0x6e, 0x6b, 0x5c, 0x7d, 0x91, + 0x7d, 0x33, 0x33, 0x7b, 0x91, 0x7d, 0x5d, 0x68, 0x4d, 0x6f, 0x6e, 0x4e, + 0x50, 0x6e, 0x70, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x04, 0x89, + 0x05, 0xb6, 0x00, 0x16, 0x00, 0x71, 0x40, 0x38, 0x0e, 0x12, 0x14, 0x12, + 0x15, 0x0d, 0x11, 0x11, 0x00, 0x09, 0x05, 0x03, 0x05, 0x02, 0x0a, 0x06, + 0x06, 0x00, 0x00, 0x16, 0x01, 0x01, 0x02, 0x02, 0x18, 0x16, 0x15, 0x15, + 0x17, 0x06, 0x12, 0x13, 0x12, 0x52, 0x59, 0x00, 0x03, 0x01, 0x03, 0x13, + 0x0f, 0x0a, 0x0e, 0x0f, 0x0e, 0x52, 0x59, 0x07, 0x0f, 0x0f, 0x0c, 0x01, + 0x15, 0x06, 0x0c, 0x18, 0x00, 0x3f, 0x3f, 0x33, 0x12, 0x39, 0x2f, 0x33, + 0x2b, 0x11, 0x00, 0x33, 0x18, 0x10, 0xc6, 0x32, 0x11, 0x12, 0x39, 0x2b, + 0x11, 0x00, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x12, 0x39, 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x39, 0x11, 0x33, 0x31, 0x30, 0x09, + 0x01, 0x21, 0x01, 0x33, 0x15, 0x23, 0x15, 0x33, 0x15, 0x23, 0x15, 0x21, + 0x35, 0x23, 0x35, 0x33, 0x35, 0x23, 0x35, 0x33, 0x01, 0x21, 0x02, 0x48, + 0x01, 0x08, 0x01, 0x39, 0xfe, 0x81, 0xc3, 0xf6, 0xf6, 0xf6, 0xfe, 0xe1, + 0xf7, 0xf7, 0xf7, 0xbe, 0xfe, 0x87, 0x01, 0x3c, 0x03, 0x5c, 0x02, 0x5a, + 0xfd, 0x15, 0xb2, 0x8a, 0xb2, 0xdd, 0xdd, 0xb2, 0x8a, 0xb2, 0x02, 0xeb, + 0x00, 0x02, 0x01, 0xc7, 0xfe, 0x2f, 0x02, 0xa2, 0x06, 0x0e, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x23, 0x40, 0x0f, 0x02, 0x06, 0x06, 0x03, 0x07, 0x07, + 0x08, 0x09, 0x04, 0x03, 0x04, 0x03, 0x07, 0x00, 0x00, 0x00, 0x3f, 0x2f, + 0x39, 0x39, 0x2f, 0x2f, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x33, 0x11, 0x23, 0x11, 0x33, 0x11, 0x23, 0x01, + 0xc7, 0xdb, 0xdb, 0xdb, 0xdb, 0x06, 0x0e, 0xfc, 0xd1, 0xfe, 0x7f, 0xfc, + 0xd1, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x6a, 0xff, 0xec, 0x03, 0x7f, + 0x06, 0x29, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x55, 0x40, 0x2a, 0x0a, 0x11, + 0x17, 0x11, 0x05, 0x05, 0x2e, 0x22, 0x00, 0x27, 0x1c, 0x1c, 0x33, 0x17, + 0x00, 0x17, 0x39, 0x3a, 0x03, 0x36, 0x36, 0x13, 0x19, 0x31, 0x31, 0x2a, + 0x13, 0x2a, 0x0e, 0x25, 0x1f, 0x25, 0x4b, 0x59, 0x1f, 0x16, 0x08, 0x0e, + 0x4b, 0x59, 0x08, 0x01, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x33, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x31, 0x30, 0x13, 0x34, 0x36, + 0x37, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x17, 0x07, 0x2e, 0x01, 0x23, + 0x22, 0x06, 0x15, 0x14, 0x16, 0x17, 0x1e, 0x01, 0x15, 0x14, 0x07, 0x1e, + 0x01, 0x15, 0x14, 0x06, 0x23, 0x22, 0x27, 0x35, 0x1e, 0x01, 0x33, 0x32, + 0x35, 0x34, 0x2e, 0x01, 0x27, 0x2e, 0x01, 0x37, 0x14, 0x16, 0x17, 0x36, + 0x35, 0x34, 0x26, 0x27, 0x0e, 0x01, 0x79, 0x48, 0x3d, 0x85, 0xdf, 0xb6, + 0xaa, 0xc1, 0x52, 0x44, 0x8d, 0x4e, 0x51, 0x4a, 0x63, 0x72, 0xa3, 0x9a, + 0x7d, 0x3e, 0x3f, 0xef, 0xc9, 0xcb, 0x92, 0x51, 0xc6, 0x46, 0xc2, 0x25, + 0x5a, 0x50, 0xb7, 0x8a, 0xdf, 0x82, 0x74, 0x4e, 0x65, 0x85, 0x25, 0x35, + 0x03, 0x25, 0x4f, 0x83, 0x28, 0x54, 0x95, 0x83, 0x9e, 0x54, 0xbe, 0x20, + 0x33, 0x2e, 0x30, 0x31, 0x4a, 0x2d, 0x40, 0xa9, 0x6d, 0xb1, 0x53, 0x28, + 0x69, 0x4a, 0x94, 0xaf, 0x4f, 0xcf, 0x29, 0x39, 0x75, 0x27, 0x30, 0x33, + 0x22, 0x4a, 0x9d, 0x8b, 0x43, 0x68, 0x2e, 0x39, 0x59, 0x44, 0x5e, 0x31, + 0x0e, 0x4f, 0x00, 0x00, 0x00, 0x02, 0x01, 0x17, 0x04, 0xf8, 0x03, 0xc5, + 0x06, 0x04, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x20, 0x40, 0x0d, 0x12, 0x0c, + 0x00, 0x06, 0x00, 0x00, 0x18, 0x19, 0x0f, 0x03, 0x03, 0x15, 0x09, 0x00, + 0x2f, 0x33, 0x33, 0x11, 0x33, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x10, + 0xcc, 0x32, 0x31, 0x30, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x23, 0x22, 0x26, 0x25, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x23, 0x22, 0x26, 0x01, 0x17, 0x4b, 0x40, 0x42, 0x4b, 0x4c, 0x41, + 0x40, 0x4b, 0x01, 0x93, 0x51, 0x3c, 0x41, 0x4d, 0x4e, 0x40, 0x3c, 0x51, + 0x05, 0x7d, 0x41, 0x46, 0x4a, 0x3d, 0x3c, 0x49, 0x46, 0x3f, 0x46, 0x41, + 0x48, 0x3f, 0x3d, 0x48, 0x41, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x64, + 0xff, 0xec, 0x06, 0x44, 0x05, 0xcb, 0x00, 0x15, 0x00, 0x25, 0x00, 0x35, + 0x00, 0x42, 0x40, 0x1f, 0x03, 0x0e, 0x09, 0x13, 0x0e, 0x13, 0x26, 0x2e, + 0x26, 0x16, 0x2e, 0x1e, 0x16, 0x1e, 0x36, 0x37, 0x05, 0x0b, 0x00, 0x11, + 0x0b, 0x11, 0x0b, 0x11, 0x1a, 0x2a, 0x22, 0x13, 0x32, 0x1a, 0x04, 0x00, + 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, + 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x22, 0x06, 0x15, + 0x10, 0x33, 0x32, 0x36, 0x37, 0x15, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, + 0x36, 0x33, 0x32, 0x17, 0x07, 0x26, 0x01, 0x34, 0x12, 0x24, 0x33, 0x32, + 0x04, 0x12, 0x15, 0x14, 0x02, 0x04, 0x23, 0x22, 0x24, 0x02, 0x37, 0x14, + 0x12, 0x04, 0x33, 0x32, 0x24, 0x12, 0x35, 0x34, 0x02, 0x24, 0x23, 0x22, + 0x04, 0x02, 0x03, 0x7f, 0x61, 0x6a, 0xcb, 0x39, 0x84, 0x39, 0x78, 0x84, + 0xcc, 0xe0, 0xdd, 0xc7, 0x95, 0x9c, 0x4a, 0x71, 0xfc, 0x7d, 0xc8, 0x01, + 0x5e, 0xca, 0xc8, 0x01, 0x5e, 0xca, 0xc2, 0xfe, 0xa2, 0xd0, 0xcf, 0xfe, + 0xa2, 0xc3, 0x8e, 0xa4, 0x01, 0x1c, 0xa2, 0xa4, 0x01, 0x1b, 0xa3, 0xa4, + 0xfe, 0xe4, 0xa2, 0xa4, 0xfe, 0xe5, 0xa3, 0x03, 0xf2, 0x94, 0x83, 0xfe, + 0xe8, 0x1e, 0x1d, 0xbf, 0x39, 0xfa, 0xdd, 0xdc, 0xf5, 0x4e, 0xa8, 0x3a, + 0xfe, 0xe9, 0xc8, 0x01, 0x5e, 0xca, 0xc8, 0xfe, 0xa2, 0xca, 0xc5, 0xfe, + 0xa6, 0xd0, 0xcf, 0x01, 0x5a, 0xc6, 0xa4, 0xfe, 0xe5, 0xa3, 0xa4, 0x01, + 0x1c, 0xa2, 0xa4, 0x01, 0x1b, 0xa3, 0xa4, 0xfe, 0xe4, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x2f, 0x02, 0xf0, 0x02, 0xb8, 0x05, 0xc7, 0x00, 0x17, + 0x00, 0x21, 0x00, 0x41, 0x40, 0x1e, 0x18, 0x07, 0x01, 0x17, 0x17, 0x1e, + 0x10, 0x07, 0x0b, 0x0b, 0x1e, 0x07, 0x1e, 0x22, 0x23, 0x0f, 0x0d, 0x0d, + 0x1f, 0x0b, 0x0b, 0x13, 0x01, 0x1b, 0x1b, 0x00, 0x00, 0x04, 0x13, 0x1f, + 0x00, 0x3f, 0xc4, 0x39, 0x2f, 0x32, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, + 0x32, 0x12, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x12, + 0x39, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x27, 0x0e, + 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3f, 0x01, 0x34, 0x23, 0x22, + 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x11, 0x25, 0x14, 0x16, + 0x33, 0x32, 0x36, 0x3d, 0x01, 0x07, 0x06, 0x02, 0x31, 0x1f, 0x2b, 0x7c, + 0x4a, 0x75, 0x7d, 0xa5, 0xb9, 0x63, 0x7f, 0x51, 0x88, 0x42, 0x42, 0x9f, + 0x63, 0x89, 0x95, 0xfe, 0x44, 0x2e, 0x20, 0x4d, 0x59, 0x63, 0x91, 0x02, + 0xfc, 0x6e, 0x3a, 0x40, 0x75, 0x6a, 0x6d, 0x6d, 0x09, 0x04, 0x75, 0x3d, + 0x87, 0x20, 0x32, 0x8e, 0x83, 0xfe, 0x46, 0xd5, 0x26, 0x24, 0x53, 0x41, + 0x24, 0x06, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x52, 0x00, 0x5e, 0x04, 0x9a, + 0x04, 0x04, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x5c, 0x40, 0x2b, 0x0a, 0x0d, + 0x0c, 0x09, 0x0b, 0x0b, 0x0c, 0x03, 0x06, 0x02, 0x04, 0x04, 0x01, 0x05, + 0x0c, 0x08, 0x0c, 0x0c, 0x0f, 0x0d, 0x06, 0x06, 0x03, 0x07, 0x00, 0x00, + 0x0a, 0x03, 0x03, 0x02, 0x0b, 0x04, 0x04, 0x0c, 0x05, 0x05, 0x01, 0x0e, + 0x09, 0x02, 0x02, 0x08, 0x01, 0x00, 0x2f, 0x33, 0x33, 0x11, 0x33, 0x11, + 0x12, 0x39, 0x2f, 0x33, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x10, + 0xd6, 0x32, 0x32, 0x11, 0x33, 0xc1, 0x32, 0x11, 0x33, 0x11, 0x33, 0x10, + 0xc1, 0x32, 0x31, 0x30, 0x13, 0x01, 0x17, 0x09, 0x01, 0x07, 0x01, 0x25, + 0x01, 0x17, 0x09, 0x01, 0x07, 0x01, 0x52, 0x01, 0x73, 0xdb, 0xfe, 0xe9, + 0x01, 0x17, 0xdb, 0xfe, 0x8d, 0x01, 0xfa, 0x01, 0x72, 0xdc, 0xfe, 0xe9, + 0x01, 0x17, 0xdc, 0xfe, 0x8e, 0x02, 0x3d, 0x01, 0xc7, 0x77, 0xfe, 0xa4, + 0xfe, 0xa4, 0x77, 0x01, 0xc5, 0x1a, 0x01, 0xc7, 0x77, 0xfe, 0xa4, 0xfe, + 0xa4, 0x77, 0x01, 0xc5, 0x00, 0x01, 0x00, 0x58, 0x00, 0xf8, 0x04, 0x39, + 0x03, 0x3f, 0x00, 0x05, 0x00, 0x1a, 0x40, 0x0a, 0x01, 0x00, 0x00, 0x07, + 0x03, 0x01, 0x01, 0x06, 0x03, 0x04, 0x00, 0x2f, 0x33, 0x12, 0x39, 0x2f, + 0x01, 0x32, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x25, 0x23, 0x11, 0x21, + 0x35, 0x21, 0x04, 0x39, 0xdb, 0xfc, 0xfa, 0x03, 0xe1, 0xf8, 0x01, 0x6c, + 0xdb, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x3d, 0x01, 0xa8, 0x02, 0x56, + 0x02, 0xa2, 0x12, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x64, + 0xff, 0xec, 0x06, 0x44, 0x05, 0xcb, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x25, + 0x00, 0x35, 0x00, 0x66, 0x40, 0x31, 0x04, 0x03, 0x02, 0x05, 0x05, 0x07, + 0x00, 0x11, 0x11, 0x0d, 0x03, 0x0d, 0x07, 0x07, 0x08, 0x03, 0x08, 0x2e, + 0x26, 0x26, 0x16, 0x2e, 0x1e, 0x16, 0x1e, 0x36, 0x37, 0x02, 0x06, 0x06, + 0x0d, 0x0d, 0x04, 0x15, 0x04, 0x08, 0x15, 0x09, 0x08, 0x09, 0x08, 0x09, + 0x1a, 0x2a, 0x22, 0x13, 0x32, 0x1a, 0x04, 0x00, 0x3f, 0x33, 0x3f, 0x33, + 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, + 0x11, 0x33, 0x12, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x12, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, + 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, + 0x07, 0x13, 0x23, 0x03, 0x23, 0x11, 0x23, 0x11, 0x21, 0x32, 0x16, 0x01, + 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x01, 0x34, 0x12, 0x24, + 0x33, 0x32, 0x04, 0x12, 0x15, 0x14, 0x02, 0x04, 0x23, 0x22, 0x24, 0x02, + 0x37, 0x14, 0x12, 0x04, 0x33, 0x32, 0x24, 0x12, 0x35, 0x34, 0x02, 0x24, + 0x23, 0x22, 0x04, 0x02, 0x04, 0x85, 0x8f, 0xed, 0xfe, 0xb2, 0x2f, 0xe5, + 0x01, 0x08, 0xb5, 0xa9, 0xfe, 0x7f, 0x1f, 0x42, 0x39, 0x38, 0x45, 0x1d, + 0xfd, 0x60, 0xc8, 0x01, 0x5e, 0xca, 0xc8, 0x01, 0x5e, 0xca, 0xc2, 0xfe, + 0xa2, 0xd0, 0xcf, 0xfe, 0xa2, 0xc3, 0x8e, 0xa4, 0x01, 0x1c, 0xa2, 0xa4, + 0x01, 0x1b, 0xa3, 0xa4, 0xfe, 0xe4, 0xa2, 0xa4, 0xfe, 0xe5, 0xa3, 0x03, + 0x89, 0xaa, 0x3f, 0xfe, 0x70, 0x01, 0x52, 0xfe, 0xae, 0x03, 0x94, 0x8c, + 0xfe, 0xf2, 0x39, 0x42, 0x41, 0x36, 0xfe, 0xdf, 0xc8, 0x01, 0x5e, 0xca, + 0xc8, 0xfe, 0xa2, 0xca, 0xc5, 0xfe, 0xa6, 0xd0, 0xcf, 0x01, 0x5a, 0xc6, + 0xa4, 0xfe, 0xe5, 0xa3, 0xa4, 0x01, 0x1c, 0xa2, 0xa4, 0x01, 0x1b, 0xa3, + 0xa4, 0xfe, 0xe4, 0x00, 0x00, 0x01, 0xff, 0xfa, 0x06, 0x14, 0x04, 0x06, + 0x06, 0xdd, 0x00, 0x03, 0x00, 0x12, 0xb6, 0x00, 0x05, 0x01, 0x04, 0x02, + 0x01, 0x00, 0x00, 0x3f, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x01, 0x21, 0x35, 0x21, 0x04, 0x06, 0xfb, 0xf4, 0x04, 0x0c, 0x06, 0x14, + 0xc9, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5c, 0x03, 0x19, 0x03, 0x10, + 0x05, 0xcb, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x18, 0x40, 0x09, 0x00, 0x0f, + 0x0f, 0x1c, 0x1b, 0x12, 0x0c, 0x18, 0x04, 0x00, 0x2f, 0x33, 0xc4, 0x32, + 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x31, 0x30, 0x13, 0x34, 0x3e, 0x01, + 0x33, 0x32, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x37, + 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x5c, + 0x5c, 0xa0, 0x5e, 0x5c, 0xa1, 0x5d, 0x5d, 0xa0, 0x5d, 0x91, 0xc9, 0xbf, + 0x59, 0x42, 0x42, 0x5a, 0x5b, 0x41, 0x40, 0x5b, 0x04, 0x71, 0x5c, 0xa0, + 0x5e, 0x5c, 0xa2, 0x5c, 0x5d, 0xa1, 0x5a, 0xc7, 0x91, 0x40, 0x5a, 0x5c, + 0x3e, 0x3f, 0x5e, 0x5c, 0x00, 0x02, 0x00, 0x58, 0x00, 0x00, 0x04, 0x39, + 0x05, 0x02, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x36, 0x40, 0x18, 0x0f, 0x07, + 0x07, 0x06, 0x0a, 0x0a, 0x0b, 0x0c, 0x01, 0x01, 0x03, 0x0b, 0x0b, 0x10, + 0x11, 0x0d, 0x0c, 0x0b, 0x09, 0x01, 0x01, 0x06, 0x04, 0x02, 0x00, 0x2f, + 0x33, 0x33, 0x33, 0x11, 0x33, 0x33, 0x2f, 0x33, 0x11, 0x12, 0x01, 0x39, + 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, + 0x31, 0x30, 0x01, 0x21, 0x35, 0x21, 0x11, 0x33, 0x11, 0x21, 0x15, 0x21, + 0x11, 0x23, 0x01, 0x35, 0x21, 0x15, 0x01, 0xdb, 0xfe, 0x7d, 0x01, 0x83, + 0xdb, 0x01, 0x83, 0xfe, 0x7d, 0xdb, 0xfe, 0x7d, 0x03, 0xe1, 0x02, 0xa2, + 0xdb, 0x01, 0x85, 0xfe, 0x7b, 0xdb, 0xfe, 0x7f, 0xfe, 0xdf, 0xdb, 0xdb, + 0x00, 0x01, 0x00, 0x2f, 0x02, 0x4a, 0x02, 0xbe, 0x05, 0xcb, 0x00, 0x16, + 0x00, 0x28, 0x40, 0x12, 0x15, 0x0c, 0x01, 0x06, 0x00, 0x11, 0x01, 0x11, + 0x17, 0x18, 0x09, 0x0e, 0x1f, 0x02, 0x15, 0x15, 0x01, 0x20, 0x00, 0x3f, + 0x33, 0x12, 0x39, 0x3f, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, + 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x01, 0x21, 0x35, 0x37, 0x3e, 0x01, + 0x35, 0x34, 0x26, 0x23, 0x22, 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x06, 0x0f, 0x01, 0x21, 0x02, 0xbe, 0xfd, 0x79, 0xe0, 0x66, 0x39, + 0x30, 0x28, 0x51, 0x63, 0x7b, 0x93, 0xbd, 0x89, 0x9e, 0x5e, 0x81, 0x69, + 0x01, 0x60, 0x02, 0x4a, 0xa8, 0xdb, 0x64, 0x59, 0x32, 0x26, 0x28, 0x58, + 0x98, 0x81, 0x85, 0x75, 0x55, 0x96, 0x75, 0x5f, 0x00, 0x01, 0x00, 0x3b, + 0x02, 0x39, 0x02, 0xb6, 0x05, 0xc9, 0x00, 0x25, 0x00, 0x3e, 0x40, 0x1d, + 0x14, 0x0b, 0x02, 0x19, 0x19, 0x00, 0x00, 0x20, 0x06, 0x20, 0x0b, 0x10, + 0x06, 0x0b, 0x06, 0x26, 0x27, 0x03, 0x14, 0x14, 0x15, 0x15, 0x09, 0x1c, + 0x23, 0x1f, 0x0e, 0x09, 0x21, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, + 0x2f, 0x33, 0x12, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x31, 0x30, + 0x01, 0x14, 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x23, 0x22, 0x27, + 0x35, 0x16, 0x33, 0x32, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x35, 0x33, 0x32, + 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, + 0x32, 0x16, 0x02, 0x9a, 0xaa, 0x5e, 0x68, 0xb0, 0xba, 0x8f, 0x82, 0x94, + 0x7b, 0x8f, 0x58, 0x4e, 0x70, 0x5c, 0x53, 0x51, 0x32, 0x33, 0x2f, 0x54, + 0x39, 0x65, 0x3e, 0x97, 0x67, 0x7f, 0xa2, 0x04, 0xe1, 0x8f, 0x37, 0x0d, + 0x14, 0x6e, 0x4f, 0x79, 0x8b, 0x46, 0xbe, 0x5a, 0x6b, 0x35, 0x35, 0xa0, + 0x34, 0x39, 0x26, 0x32, 0x26, 0x28, 0x8d, 0x2f, 0x3e, 0x80, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x4c, 0x04, 0xd9, 0x03, 0x8d, 0x06, 0x21, 0x00, 0x08, + 0x00, 0x1c, 0x40, 0x0b, 0x03, 0x04, 0x40, 0x08, 0x00, 0x00, 0x09, 0x0a, + 0x04, 0x80, 0x00, 0x00, 0x2f, 0x1a, 0xcd, 0x11, 0x12, 0x01, 0x39, 0x11, + 0x33, 0x1a, 0xc9, 0x32, 0x31, 0x30, 0x01, 0x35, 0x36, 0x37, 0x21, 0x15, + 0x0e, 0x01, 0x07, 0x01, 0x4c, 0xac, 0x3f, 0x01, 0x56, 0x34, 0xfb, 0x47, + 0x04, 0xd9, 0x1b, 0xc8, 0x65, 0x15, 0x34, 0xcd, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xa0, 0xfe, 0x14, 0x04, 0xa8, 0x04, 0x5e, 0x00, 0x18, + 0x00, 0x3f, 0x40, 0x1f, 0x0b, 0x06, 0x06, 0x09, 0x09, 0x1a, 0x12, 0x16, + 0x00, 0x15, 0x15, 0x16, 0x16, 0x19, 0x07, 0x17, 0x0f, 0x16, 0x1b, 0x12, + 0x0c, 0x0f, 0x03, 0x0f, 0x03, 0x47, 0x59, 0x0f, 0x16, 0x0a, 0x15, 0x00, + 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x18, 0x3f, 0x3f, 0x33, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x12, 0x39, 0x31, 0x30, 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, + 0x11, 0x21, 0x11, 0x23, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x27, + 0x1f, 0x01, 0x11, 0x21, 0x11, 0x21, 0x01, 0xd1, 0x58, 0x5e, 0x7e, 0x72, + 0x01, 0x31, 0xe7, 0x2b, 0x0f, 0x2a, 0x78, 0x58, 0x3e, 0x68, 0x20, 0x05, + 0x05, 0xfe, 0xcf, 0x01, 0x31, 0x01, 0xd1, 0x79, 0x79, 0xad, 0xc4, 0x02, + 0x0e, 0xfb, 0xa2, 0x96, 0x55, 0x55, 0x2e, 0x2c, 0x55, 0x9d, 0xfe, 0xc0, + 0x06, 0x4a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x71, 0xfe, 0xfc, 0x04, 0x8f, + 0x06, 0x14, 0x00, 0x0f, 0x00, 0x2f, 0x40, 0x15, 0x0b, 0x10, 0x04, 0x05, + 0x01, 0x00, 0x01, 0x01, 0x10, 0x11, 0x08, 0x08, 0x01, 0x0e, 0x0e, 0x03, + 0x4d, 0x59, 0x0e, 0x05, 0x01, 0x00, 0x2f, 0x33, 0x2f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x18, 0x2f, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x10, 0xc4, + 0x32, 0x11, 0x39, 0x31, 0x30, 0x01, 0x23, 0x11, 0x23, 0x11, 0x23, 0x11, + 0x06, 0x23, 0x22, 0x26, 0x35, 0x10, 0x36, 0x33, 0x21, 0x04, 0x8f, 0xa1, + 0xa6, 0xa2, 0x3e, 0x54, 0xd8, 0xcb, 0xda, 0xe8, 0x02, 0x5c, 0xfe, 0xfc, + 0x06, 0x50, 0xf9, 0xb0, 0x03, 0x33, 0x12, 0xfa, 0xfb, 0x01, 0x04, 0xfe, + 0x00, 0x01, 0x00, 0x75, 0x02, 0x29, 0x01, 0xd3, 0x03, 0x7d, 0x00, 0x0b, + 0x00, 0x15, 0x40, 0x09, 0x06, 0x00, 0x00, 0x0c, 0x03, 0x09, 0x54, 0x59, + 0x03, 0x00, 0x2f, 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, + 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x75, + 0x5a, 0x56, 0x53, 0x5b, 0x5d, 0x51, 0x54, 0x5c, 0x02, 0xd3, 0x54, 0x56, + 0x58, 0x52, 0x51, 0x59, 0x58, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, + 0xfe, 0x14, 0x01, 0xa2, 0x00, 0x00, 0x00, 0x12, 0x00, 0x34, 0x40, 0x17, + 0x10, 0x0d, 0x0d, 0x05, 0x05, 0x00, 0x0b, 0x0b, 0x13, 0x14, 0x10, 0x10, + 0x0d, 0x14, 0x0d, 0x13, 0x09, 0x0e, 0x06, 0x09, 0x09, 0x03, 0x1b, 0x00, + 0x3f, 0x33, 0x11, 0x33, 0x2f, 0x11, 0x12, 0x39, 0x11, 0x12, 0x39, 0x7c, + 0x2f, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x12, 0x39, 0x11, 0x33, + 0x31, 0x30, 0x05, 0x14, 0x06, 0x23, 0x22, 0x27, 0x35, 0x1e, 0x01, 0x33, + 0x32, 0x35, 0x34, 0x27, 0x37, 0x33, 0x07, 0x1e, 0x01, 0x01, 0xa2, 0x97, + 0x9e, 0x4e, 0x44, 0x1b, 0x5b, 0x19, 0x48, 0xa6, 0x4e, 0xc1, 0x1b, 0x4a, + 0x58, 0xfa, 0x80, 0x72, 0x15, 0xa8, 0x07, 0x0e, 0x3e, 0x53, 0x19, 0x9a, + 0x3d, 0x18, 0x65, 0x00, 0x00, 0x01, 0x00, 0x5c, 0x02, 0x4a, 0x02, 0x48, + 0x05, 0xb6, 0x00, 0x0a, 0x00, 0x2a, 0x40, 0x13, 0x04, 0x09, 0x00, 0x00, + 0x08, 0x01, 0x01, 0x0b, 0x0c, 0x08, 0x07, 0x07, 0x01, 0x04, 0x04, 0x09, + 0x1e, 0x01, 0x20, 0x00, 0x3f, 0x3f, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, + 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x12, 0x39, 0x39, 0x31, 0x30, + 0x01, 0x23, 0x11, 0x3f, 0x01, 0x06, 0x0f, 0x01, 0x27, 0x25, 0x33, 0x02, + 0x48, 0xee, 0x03, 0x05, 0x1b, 0x30, 0x4e, 0x6d, 0x01, 0x2d, 0xbf, 0x02, + 0x4a, 0x01, 0xbe, 0x70, 0x5f, 0x24, 0x2a, 0x3d, 0x7f, 0xeb, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x39, 0x02, 0xf0, 0x02, 0xe1, 0x05, 0xc7, 0x00, 0x0b, + 0x00, 0x17, 0x00, 0x1f, 0x40, 0x0d, 0x0c, 0x06, 0x12, 0x00, 0x06, 0x00, + 0x18, 0x19, 0x0f, 0x03, 0x15, 0x09, 0x1f, 0x00, 0x3f, 0x33, 0xc4, 0x32, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, + 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x05, + 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x02, + 0xe1, 0xb7, 0x9f, 0x99, 0xb9, 0xb3, 0xa3, 0x98, 0xba, 0xfe, 0x23, 0x41, + 0x48, 0x48, 0x3f, 0x3f, 0x48, 0x48, 0x41, 0x04, 0x5c, 0xab, 0xc1, 0xc5, + 0xa7, 0xa9, 0xc2, 0xc5, 0xa6, 0x64, 0x65, 0x65, 0x64, 0x64, 0x63, 0x63, + 0x00, 0x02, 0x00, 0x52, 0x00, 0x5e, 0x04, 0x9a, 0x04, 0x04, 0x00, 0x06, + 0x00, 0x0d, 0x00, 0x5a, 0x40, 0x2a, 0x0b, 0x09, 0x09, 0x0a, 0x07, 0x08, + 0x04, 0x02, 0x02, 0x03, 0x00, 0x05, 0x01, 0x08, 0x0c, 0x08, 0x08, 0x0e, + 0x0d, 0x06, 0x06, 0x03, 0x07, 0x00, 0x00, 0x0a, 0x03, 0x03, 0x04, 0x09, + 0x02, 0x02, 0x08, 0x01, 0x01, 0x05, 0x0e, 0x0b, 0x04, 0x04, 0x0c, 0x05, + 0x00, 0x2f, 0x33, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x2f, 0x33, 0x33, + 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x10, 0xd6, 0x32, 0xc1, 0x32, 0x33, + 0x11, 0x33, 0x10, 0xc1, 0x32, 0x33, 0x11, 0x33, 0x31, 0x30, 0x09, 0x01, + 0x27, 0x09, 0x01, 0x37, 0x01, 0x05, 0x01, 0x27, 0x09, 0x01, 0x37, 0x01, + 0x04, 0x9a, 0xfe, 0x8d, 0xdb, 0x01, 0x16, 0xfe, 0xea, 0xdb, 0x01, 0x73, + 0xfe, 0x06, 0xfe, 0x8d, 0xdb, 0x01, 0x16, 0xfe, 0xea, 0xdb, 0x01, 0x73, + 0x02, 0x23, 0xfe, 0x3b, 0x77, 0x01, 0x5c, 0x01, 0x5c, 0x77, 0xfe, 0x39, + 0x1a, 0xfe, 0x3b, 0x77, 0x01, 0x5c, 0x01, 0x5c, 0x77, 0xfe, 0x39, 0x00, + 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x06, 0x92, 0x05, 0xb6, 0x00, 0x0a, + 0x00, 0x12, 0x00, 0x16, 0x00, 0x21, 0x00, 0x00, 0x25, 0x23, 0x15, 0x23, + 0x35, 0x21, 0x35, 0x01, 0x33, 0x11, 0x33, 0x21, 0x35, 0x34, 0x37, 0x0e, + 0x01, 0x0f, 0x01, 0x13, 0x01, 0x23, 0x09, 0x01, 0x23, 0x11, 0x3f, 0x01, + 0x06, 0x0f, 0x01, 0x27, 0x25, 0x33, 0x06, 0x92, 0x7d, 0xee, 0xfe, 0x81, + 0x01, 0x81, 0xec, 0x7d, 0xfe, 0x95, 0x06, 0x09, 0x35, 0x0f, 0x7f, 0xf9, + 0xfc, 0xd5, 0xef, 0x03, 0x2b, 0xfd, 0xaf, 0xee, 0x03, 0x05, 0x1b, 0x30, + 0x4e, 0x6d, 0x01, 0x2d, 0xbf, 0x98, 0x97, 0x97, 0x9a, 0x02, 0x41, 0xfd, + 0xcd, 0xa4, 0x56, 0x62, 0x1a, 0x6c, 0x17, 0xbf, 0x04, 0x76, 0xfa, 0x4a, + 0x05, 0xb6, 0xfc, 0x94, 0x01, 0xbe, 0x70, 0x5f, 0x24, 0x2a, 0x3d, 0x7f, + 0xeb, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2e, 0x00, 0x00, 0x06, 0xb4, + 0x05, 0xb6, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x25, 0x00, 0x00, 0x09, 0x01, + 0x23, 0x09, 0x01, 0x23, 0x11, 0x3f, 0x01, 0x06, 0x0f, 0x01, 0x27, 0x25, + 0x33, 0x01, 0x21, 0x35, 0x37, 0x3e, 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, + 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x0f, 0x01, 0x21, + 0x05, 0x5a, 0xfc, 0xd5, 0xef, 0x03, 0x2b, 0xfd, 0xaf, 0xee, 0x03, 0x05, + 0x1b, 0x30, 0x4e, 0x6d, 0x01, 0x2d, 0xbf, 0x04, 0x9a, 0xfd, 0x79, 0xe0, + 0x66, 0x39, 0x30, 0x28, 0x51, 0x63, 0x7b, 0x93, 0xbd, 0x89, 0x9e, 0x5e, + 0x81, 0x69, 0x01, 0x60, 0x05, 0xb6, 0xfa, 0x4a, 0x05, 0xb6, 0xfc, 0x94, + 0x01, 0xbe, 0x70, 0x5f, 0x24, 0x2a, 0x3d, 0x7f, 0xeb, 0xfa, 0x4b, 0xa8, + 0xdb, 0x64, 0x59, 0x32, 0x26, 0x28, 0x58, 0x98, 0x81, 0x85, 0x75, 0x55, + 0x96, 0x75, 0x5f, 0x00, 0x00, 0x04, 0x00, 0x5a, 0x00, 0x00, 0x06, 0xb0, + 0x05, 0xc9, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x16, 0x00, 0x3c, 0x00, 0x00, + 0x25, 0x23, 0x15, 0x23, 0x35, 0x21, 0x35, 0x01, 0x33, 0x11, 0x33, 0x21, + 0x35, 0x34, 0x37, 0x0e, 0x01, 0x0f, 0x01, 0x09, 0x01, 0x23, 0x01, 0x05, + 0x14, 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x23, 0x22, 0x27, 0x35, + 0x16, 0x33, 0x32, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x35, 0x33, 0x32, 0x36, + 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, + 0x16, 0x06, 0xb0, 0x7d, 0xee, 0xfe, 0x81, 0x01, 0x81, 0xec, 0x7d, 0xfe, + 0x95, 0x06, 0x09, 0x35, 0x0f, 0x7f, 0x01, 0x22, 0xfc, 0xd5, 0xef, 0x03, + 0x2b, 0xfe, 0x07, 0xaa, 0x5e, 0x68, 0xb0, 0xba, 0x8f, 0x82, 0x94, 0x7b, + 0x8f, 0x58, 0x4e, 0x70, 0x5c, 0x53, 0x51, 0x32, 0x33, 0x2f, 0x54, 0x39, + 0x65, 0x3e, 0x97, 0x67, 0x7f, 0xa2, 0x98, 0x97, 0x97, 0x9a, 0x02, 0x41, + 0xfd, 0xcd, 0xa4, 0x56, 0x62, 0x1a, 0x6c, 0x17, 0xbf, 0x04, 0x76, 0xfa, + 0x4a, 0x05, 0xb6, 0xd5, 0x8f, 0x37, 0x0d, 0x14, 0x6e, 0x4f, 0x79, 0x8b, + 0x46, 0xbe, 0x5a, 0x6b, 0x35, 0x35, 0xa0, 0x34, 0x39, 0x26, 0x32, 0x26, + 0x28, 0x8d, 0x2f, 0x3e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3d, + 0xfe, 0x79, 0x03, 0xd7, 0x04, 0x5e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x46, + 0x40, 0x24, 0x22, 0x1c, 0x1c, 0x1b, 0x00, 0x00, 0x07, 0x07, 0x14, 0x14, + 0x0e, 0x28, 0x0e, 0x29, 0x00, 0x1b, 0x10, 0x1b, 0x02, 0x09, 0x03, 0x1b, + 0x1b, 0x25, 0x25, 0x1f, 0x54, 0x59, 0x25, 0x0f, 0x11, 0x0a, 0x4f, 0x59, + 0x11, 0x23, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x00, 0x33, + 0x18, 0x2f, 0x5f, 0x5e, 0x5d, 0x11, 0x01, 0x33, 0x11, 0x12, 0x39, 0x11, + 0x33, 0x11, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x15, + 0x14, 0x06, 0x07, 0x0e, 0x01, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, 0x37, + 0x17, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x37, 0x3e, 0x01, + 0x3d, 0x01, 0x01, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x02, 0xc9, 0x59, 0x6c, 0x6d, 0x39, 0x57, 0x59, 0x4f, 0xb4, + 0x60, 0x66, 0x62, 0xf7, 0x6a, 0xdc, 0xfb, 0x61, 0x8f, 0x5f, 0x35, 0x01, + 0x28, 0x5a, 0x56, 0x53, 0x5b, 0x5d, 0x51, 0x54, 0x5c, 0x02, 0x5e, 0x4a, + 0x62, 0x8e, 0x4d, 0x4e, 0x58, 0x3f, 0x39, 0x4a, 0x3a, 0x2a, 0xdd, 0x38, + 0x45, 0xc1, 0xa9, 0x6c, 0x9e, 0x69, 0x46, 0x4a, 0x3d, 0x3b, 0x01, 0x56, + 0x54, 0x56, 0x58, 0x52, 0x51, 0x59, 0x58, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x85, 0x07, 0x73, 0x12, 0x26, 0x00, 0x24, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x43, 0x00, 0x06, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x02, + 0x16, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x85, 0x07, 0x73, 0x12, 0x26, 0x00, 0x24, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x76, 0x00, 0xd1, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x02, + 0x16, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x85, 0x07, 0x73, 0x00, 0x0d, 0x00, 0x15, 0x00, 0x1b, + 0x00, 0x00, 0x01, 0x26, 0x27, 0x06, 0x07, 0x23, 0x35, 0x36, 0x37, 0x21, + 0x1e, 0x01, 0x17, 0x15, 0x0b, 0x01, 0x21, 0x03, 0x21, 0x01, 0x21, 0x09, + 0x01, 0x02, 0x26, 0x27, 0x06, 0x03, 0x03, 0xaa, 0x9d, 0x4d, 0x4e, 0x97, + 0xcb, 0xbd, 0x43, 0x01, 0x65, 0x1f, 0x99, 0x48, 0x3e, 0x6a, 0xfd, 0xeb, + 0x6a, 0xfe, 0xb2, 0x02, 0x04, 0x01, 0x7b, 0x02, 0x06, 0xfd, 0xfe, 0x93, + 0x25, 0x08, 0x21, 0x9c, 0x06, 0x2b, 0x5d, 0x53, 0x51, 0x5f, 0x1b, 0xbd, + 0x70, 0x34, 0xb3, 0x46, 0x1b, 0xf9, 0xd5, 0x01, 0x5c, 0xfe, 0xa4, 0x05, + 0xbc, 0xfa, 0x44, 0x02, 0x60, 0x01, 0xd9, 0x7c, 0x24, 0x80, 0xfe, 0x07, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x85, 0x07, 0x60, 0x00, 0x17, + 0x00, 0x1f, 0x00, 0x25, 0x00, 0x00, 0x01, 0x22, 0x06, 0x07, 0x23, 0x3e, + 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, + 0x23, 0x22, 0x2e, 0x02, 0x01, 0x03, 0x21, 0x03, 0x21, 0x01, 0x21, 0x09, + 0x01, 0x02, 0x26, 0x27, 0x06, 0x03, 0x02, 0x1f, 0x1f, 0x39, 0x0d, 0x95, + 0x0b, 0x8f, 0x76, 0x29, 0x4f, 0x4d, 0x4a, 0x24, 0x1f, 0x39, 0x0d, 0x95, + 0x0b, 0x91, 0x74, 0x29, 0x4f, 0x4d, 0x4a, 0x01, 0xf4, 0x6a, 0xfd, 0xeb, + 0x6a, 0xfe, 0xb2, 0x02, 0x04, 0x01, 0x7b, 0x02, 0x06, 0xfd, 0xfe, 0x93, + 0x25, 0x08, 0x21, 0x9c, 0x06, 0x94, 0x35, 0x36, 0x91, 0xa4, 0x21, 0x27, + 0x20, 0x34, 0x36, 0x91, 0xa4, 0x21, 0x27, 0x21, 0xf9, 0x6c, 0x01, 0x5c, + 0xfe, 0xa4, 0x05, 0xbc, 0xfa, 0x44, 0x02, 0x60, 0x01, 0xd9, 0x7c, 0x24, + 0x80, 0xfe, 0x07, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x05, 0x85, + 0x07, 0x56, 0x12, 0x26, 0x00, 0x24, 0x00, 0x00, 0x11, 0x07, 0x00, 0x6a, + 0x00, 0x56, 0x01, 0x52, 0x00, 0x0a, 0xb4, 0x03, 0x02, 0x23, 0x05, 0x26, + 0x00, 0x2b, 0x35, 0x35, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0x85, + 0x07, 0x0a, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x00, + 0x01, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x07, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, + 0x01, 0x03, 0x21, 0x03, 0x21, 0x01, 0x21, 0x09, 0x01, 0x02, 0x26, 0x27, + 0x06, 0x03, 0x03, 0xbf, 0x8e, 0x70, 0x70, 0x88, 0x87, 0x71, 0x6e, 0x90, + 0x9e, 0x36, 0x2a, 0x2a, 0x36, 0x30, 0x30, 0x2a, 0x36, 0x01, 0x16, 0x6a, + 0xfd, 0xeb, 0x6a, 0xfe, 0xb2, 0x02, 0x04, 0x01, 0x7b, 0x02, 0x06, 0xfd, + 0xfe, 0x93, 0x25, 0x08, 0x21, 0x9c, 0x06, 0x1f, 0x6c, 0x84, 0x80, 0x6e, + 0x6c, 0x81, 0x84, 0x69, 0x2d, 0x33, 0x33, 0x2d, 0x2d, 0x34, 0x34, 0xfa, + 0x10, 0x01, 0x5c, 0xfe, 0xa4, 0x05, 0xbc, 0xfa, 0x44, 0x02, 0x60, 0x01, + 0xd9, 0x7c, 0x24, 0x80, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x25, 0x05, 0xb6, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x6f, + 0x40, 0x3c, 0x06, 0x13, 0x03, 0x10, 0x13, 0x03, 0x11, 0x04, 0x11, 0x01, + 0x0a, 0x0e, 0x0e, 0x01, 0x01, 0x05, 0x0c, 0x08, 0x00, 0x00, 0x15, 0x04, + 0x05, 0x05, 0x14, 0x10, 0x03, 0x4c, 0x59, 0x0a, 0x0d, 0x4c, 0x59, 0x0c, + 0x0a, 0x01, 0x0d, 0x03, 0x10, 0x0a, 0x10, 0x0a, 0x01, 0x06, 0x13, 0x09, + 0x06, 0x09, 0x4c, 0x59, 0x06, 0x03, 0x04, 0x12, 0x01, 0x0e, 0x4c, 0x59, + 0x01, 0x12, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x3f, 0x2b, 0x11, 0x00, + 0x33, 0x11, 0x12, 0x39, 0x39, 0x18, 0x2f, 0x2f, 0x5f, 0x5e, 0x5d, 0x2b, + 0x2b, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x33, 0x12, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, 0x11, + 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x21, 0x03, 0x21, 0x01, 0x21, 0x15, + 0x21, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x01, 0x21, 0x11, 0x23, 0x07, + 0x25, 0xfc, 0x97, 0xfe, 0x15, 0x96, 0xfe, 0xc5, 0x02, 0x8f, 0x04, 0x96, + 0xfd, 0xcd, 0x02, 0x0e, 0xfd, 0xf2, 0x02, 0x33, 0xfb, 0x1d, 0x01, 0x7a, + 0x7f, 0x01, 0x5c, 0xfe, 0xa4, 0x05, 0xb6, 0xfe, 0xfe, 0xbf, 0xfe, 0xfe, + 0x87, 0x01, 0x60, 0x02, 0x4e, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x77, + 0xfe, 0x14, 0x04, 0xd1, 0x05, 0xcb, 0x12, 0x26, 0x00, 0x26, 0x00, 0x00, + 0x10, 0x07, 0x00, 0x7a, 0x02, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x00, 0xb8, + 0x00, 0x00, 0x04, 0x02, 0x07, 0x73, 0x12, 0x26, 0x00, 0x28, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x43, 0xff, 0xb7, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x14, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0xb8, + 0x00, 0x00, 0x04, 0x02, 0x07, 0x73, 0x12, 0x26, 0x00, 0x28, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x76, 0x00, 0x5c, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x14, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0xaf, + 0x00, 0x00, 0x04, 0x14, 0x07, 0x73, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x00, + 0x01, 0x26, 0x27, 0x06, 0x07, 0x23, 0x35, 0x36, 0x37, 0x21, 0x1e, 0x01, + 0x17, 0x15, 0x03, 0x21, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x15, 0x21, + 0x11, 0x21, 0x03, 0x49, 0x9d, 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, 0x01, + 0x65, 0x1f, 0x99, 0x48, 0x12, 0xfc, 0xb6, 0x03, 0x4a, 0xfd, 0xec, 0x01, + 0xef, 0xfe, 0x11, 0x02, 0x14, 0x06, 0x2b, 0x5d, 0x53, 0x51, 0x5f, 0x1b, + 0xbd, 0x70, 0x34, 0xb3, 0x46, 0x1b, 0xf9, 0xd5, 0x05, 0xb6, 0xfe, 0xfe, + 0xbf, 0xfe, 0xfe, 0x87, 0xff, 0xff, 0x00, 0xb8, 0x00, 0x00, 0x04, 0x02, + 0x07, 0x56, 0x12, 0x26, 0x00, 0x28, 0x00, 0x00, 0x11, 0x07, 0x00, 0x6a, + 0xff, 0xf9, 0x01, 0x52, 0x00, 0x0a, 0xb4, 0x02, 0x01, 0x21, 0x05, 0x26, + 0x00, 0x2b, 0x35, 0x35, 0xff, 0xff, 0xff, 0xc6, 0x00, 0x00, 0x02, 0x07, + 0x07, 0x73, 0x12, 0x26, 0x00, 0x2c, 0x00, 0x00, 0x11, 0x07, 0x00, 0x43, + 0xfe, 0x7a, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, 0x0c, 0x05, 0x26, 0x00, + 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0xa7, 0x00, 0x00, 0x02, 0xe8, + 0x07, 0x73, 0x12, 0x26, 0x00, 0x2c, 0x00, 0x00, 0x11, 0x07, 0x00, 0x76, + 0xff, 0x5b, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, 0x0c, 0x05, 0x26, 0x00, + 0x2b, 0x35, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa0, 0x00, 0x00, 0x03, 0x05, + 0x07, 0x73, 0x00, 0x0d, 0x00, 0x11, 0x00, 0x00, 0x01, 0x26, 0x27, 0x06, + 0x07, 0x23, 0x35, 0x36, 0x37, 0x21, 0x1e, 0x01, 0x17, 0x15, 0x01, 0x11, + 0x21, 0x11, 0x02, 0x3a, 0x9d, 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, 0x01, + 0x65, 0x1f, 0x99, 0x48, 0xfd, 0xb3, 0x01, 0x36, 0x06, 0x2b, 0x5d, 0x53, + 0x51, 0x5f, 0x1b, 0xbd, 0x70, 0x34, 0xb3, 0x46, 0x1b, 0xf9, 0xd5, 0x05, + 0xb6, 0xfa, 0x4a, 0x00, 0xff, 0xff, 0xff, 0xfd, 0x00, 0x00, 0x02, 0xab, + 0x07, 0x56, 0x12, 0x26, 0x00, 0x2c, 0x00, 0x00, 0x11, 0x07, 0x00, 0x6a, + 0xfe, 0xe6, 0x01, 0x52, 0x00, 0x0a, 0xb4, 0x02, 0x01, 0x19, 0x05, 0x26, + 0x00, 0x2b, 0x35, 0x35, 0x00, 0x02, 0x00, 0x2f, 0x00, 0x00, 0x05, 0x75, + 0x05, 0xb6, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x48, 0x40, 0x24, 0x0d, 0x06, + 0x06, 0x1a, 0x14, 0x12, 0x16, 0x16, 0x0c, 0x01, 0x0a, 0x0a, 0x19, 0x15, + 0x0c, 0x00, 0x0c, 0x4c, 0x59, 0x12, 0x00, 0x00, 0x0a, 0x02, 0x0a, 0x16, + 0x4c, 0x59, 0x0a, 0x12, 0x02, 0x11, 0x4c, 0x59, 0x02, 0x03, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x33, + 0x2b, 0x11, 0x00, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x33, 0x33, 0x11, + 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x33, 0x11, 0x21, + 0x20, 0x00, 0x11, 0x10, 0x00, 0x29, 0x01, 0x11, 0x23, 0x25, 0x34, 0x26, + 0x2b, 0x01, 0x11, 0x33, 0x15, 0x23, 0x11, 0x33, 0x20, 0x2f, 0x89, 0x01, + 0xcb, 0x01, 0x66, 0x01, 0x8c, 0xfe, 0x65, 0xfe, 0x7c, 0xfe, 0x62, 0x89, + 0x04, 0x04, 0xd0, 0xd2, 0xa3, 0xed, 0xed, 0x83, 0x01, 0xc2, 0x03, 0x52, + 0x02, 0x64, 0xfe, 0x86, 0xfe, 0xad, 0xfe, 0x97, 0xfe, 0x80, 0x02, 0x54, + 0x8d, 0xe8, 0xef, 0xfe, 0x9a, 0xfe, 0xfe, 0xac, 0x00, 0x02, 0x00, 0xb8, + 0x00, 0x00, 0x05, 0xc9, 0x07, 0x60, 0x00, 0x17, 0x00, 0x27, 0x00, 0x00, + 0x01, 0x22, 0x06, 0x07, 0x23, 0x3e, 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, + 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, 0x23, 0x22, 0x2e, 0x02, 0x01, 0x21, + 0x01, 0x23, 0x12, 0x15, 0x11, 0x21, 0x11, 0x21, 0x01, 0x33, 0x02, 0x35, + 0x11, 0x21, 0x02, 0x9c, 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x8f, 0x76, 0x29, + 0x4f, 0x4d, 0x4a, 0x24, 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x91, 0x74, 0x29, + 0x4f, 0x4d, 0x4a, 0x03, 0x09, 0xfe, 0x76, 0xfd, 0x84, 0x09, 0x13, 0xfe, + 0xeb, 0x01, 0x87, 0x02, 0x7b, 0x07, 0x0f, 0x01, 0x17, 0x06, 0x94, 0x35, + 0x36, 0x91, 0xa4, 0x21, 0x27, 0x20, 0x34, 0x36, 0x91, 0xa4, 0x21, 0x27, + 0x21, 0xf9, 0x6c, 0x04, 0x52, 0xfe, 0xdb, 0x7d, 0xfd, 0x50, 0x05, 0xb6, + 0xfb, 0xb9, 0x01, 0x1d, 0x76, 0x02, 0xb4, 0x00, 0xff, 0xff, 0x00, 0x77, + 0xff, 0xec, 0x05, 0xe7, 0x07, 0x73, 0x12, 0x26, 0x00, 0x32, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x43, 0x00, 0x75, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x02, + 0x1e, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0x77, + 0xff, 0xec, 0x05, 0xe7, 0x07, 0x73, 0x12, 0x26, 0x00, 0x32, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x76, 0x01, 0x46, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x02, + 0x1e, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x77, + 0xff, 0xec, 0x05, 0xe7, 0x07, 0x73, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, + 0x00, 0x00, 0x01, 0x26, 0x27, 0x06, 0x07, 0x23, 0x35, 0x36, 0x37, 0x21, + 0x1e, 0x01, 0x17, 0x15, 0x01, 0x10, 0x00, 0x21, 0x20, 0x00, 0x11, 0x10, + 0x00, 0x21, 0x20, 0x00, 0x01, 0x14, 0x16, 0x33, 0x20, 0x11, 0x10, 0x21, + 0x22, 0x06, 0x04, 0x17, 0x9d, 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, 0x01, + 0x65, 0x1f, 0x99, 0x48, 0x01, 0x05, 0xfe, 0x98, 0xfe, 0xb0, 0xfe, 0xb0, + 0xfe, 0x98, 0x01, 0x69, 0x01, 0x51, 0x01, 0x51, 0x01, 0x65, 0xfb, 0xd5, + 0xba, 0xb9, 0x01, 0x73, 0xfe, 0x8f, 0xb9, 0xbc, 0x06, 0x2b, 0x5d, 0x53, + 0x51, 0x5f, 0x1b, 0xbd, 0x70, 0x34, 0xb3, 0x46, 0x1b, 0xfc, 0xb2, 0xfe, + 0x95, 0xfe, 0x7a, 0x01, 0x86, 0x01, 0x6d, 0x01, 0x6d, 0x01, 0x81, 0xfe, + 0x7c, 0xfe, 0x94, 0xf5, 0xf8, 0x01, 0xed, 0x01, 0xee, 0xf9, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x77, 0xff, 0xec, 0x05, 0xe7, 0x07, 0x60, 0x00, 0x17, + 0x00, 0x23, 0x00, 0x2d, 0x00, 0x00, 0x01, 0x22, 0x06, 0x07, 0x23, 0x3e, + 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, + 0x23, 0x22, 0x2e, 0x02, 0x01, 0x10, 0x00, 0x21, 0x20, 0x00, 0x11, 0x10, + 0x00, 0x21, 0x20, 0x00, 0x01, 0x14, 0x16, 0x33, 0x20, 0x11, 0x10, 0x21, + 0x22, 0x06, 0x02, 0x8c, 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x8f, 0x76, 0x29, + 0x4f, 0x4d, 0x4a, 0x24, 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x91, 0x74, 0x29, + 0x4f, 0x4d, 0x4a, 0x03, 0x37, 0xfe, 0x98, 0xfe, 0xb0, 0xfe, 0xb0, 0xfe, + 0x98, 0x01, 0x69, 0x01, 0x51, 0x01, 0x51, 0x01, 0x65, 0xfb, 0xd5, 0xba, + 0xb9, 0x01, 0x73, 0xfe, 0x8f, 0xb9, 0xbc, 0x06, 0x94, 0x35, 0x36, 0x91, + 0xa4, 0x21, 0x27, 0x20, 0x34, 0x36, 0x91, 0xa4, 0x21, 0x27, 0x21, 0xfc, + 0x49, 0xfe, 0x95, 0xfe, 0x7a, 0x01, 0x86, 0x01, 0x6d, 0x01, 0x6d, 0x01, + 0x81, 0xfe, 0x7c, 0xfe, 0x94, 0xf5, 0xf8, 0x01, 0xed, 0x01, 0xee, 0xf9, + 0xff, 0xff, 0x00, 0x77, 0xff, 0xec, 0x05, 0xe7, 0x07, 0x56, 0x12, 0x26, + 0x00, 0x32, 0x00, 0x00, 0x11, 0x07, 0x00, 0x6a, 0x00, 0xc3, 0x01, 0x52, + 0x00, 0x0a, 0xb4, 0x03, 0x02, 0x2b, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x35, + 0x00, 0x01, 0x00, 0x81, 0x01, 0x0c, 0x04, 0x10, 0x04, 0x9a, 0x00, 0x0b, + 0x00, 0x1d, 0x40, 0x0b, 0x06, 0x03, 0x00, 0x09, 0x09, 0x0c, 0x0d, 0x09, + 0x06, 0x03, 0x00, 0x00, 0x19, 0x2f, 0x32, 0x32, 0x32, 0x11, 0x12, 0x01, + 0x39, 0x11, 0x33, 0x33, 0x33, 0x31, 0x30, 0x09, 0x01, 0x37, 0x09, 0x01, + 0x17, 0x09, 0x01, 0x07, 0x09, 0x01, 0x27, 0x01, 0xac, 0xfe, 0xd5, 0x98, + 0x01, 0x2d, 0x01, 0x31, 0x99, 0xfe, 0xcf, 0x01, 0x2d, 0x95, 0xfe, 0xcf, + 0xfe, 0xd3, 0x96, 0x02, 0xd3, 0x01, 0x2d, 0x9a, 0xfe, 0xd5, 0x01, 0x2b, + 0x96, 0xfe, 0xcf, 0xfe, 0xd1, 0x98, 0x01, 0x2d, 0xfe, 0xd5, 0x98, 0x00, + 0x00, 0x03, 0x00, 0x77, 0xff, 0xa6, 0x05, 0xe7, 0x06, 0x04, 0x00, 0x13, + 0x00, 0x1b, 0x00, 0x22, 0x00, 0x39, 0x40, 0x1c, 0x17, 0x1f, 0x1c, 0x14, + 0x14, 0x0a, 0x1c, 0x00, 0x0a, 0x00, 0x23, 0x24, 0x16, 0x1e, 0x21, 0x19, + 0x0d, 0x19, 0x4c, 0x59, 0x0d, 0x04, 0x03, 0x21, 0x4c, 0x59, 0x03, 0x13, + 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, + 0x39, 0x31, 0x30, 0x01, 0x10, 0x00, 0x21, 0x22, 0x27, 0x07, 0x27, 0x37, + 0x26, 0x11, 0x10, 0x00, 0x21, 0x32, 0x17, 0x37, 0x17, 0x07, 0x16, 0x01, + 0x14, 0x17, 0x01, 0x26, 0x23, 0x22, 0x06, 0x05, 0x34, 0x27, 0x01, 0x16, + 0x33, 0x20, 0x05, 0xe7, 0xfe, 0x98, 0xfe, 0xb0, 0xc5, 0x8b, 0x5a, 0xa2, + 0x5a, 0xc6, 0x01, 0x69, 0x01, 0x51, 0xc6, 0x92, 0x54, 0xa0, 0x58, 0xc2, + 0xfb, 0xd5, 0x38, 0x01, 0xfa, 0x54, 0x69, 0xb9, 0xbc, 0x02, 0xe6, 0x33, + 0xfe, 0x0c, 0x4c, 0x68, 0x01, 0x73, 0x02, 0xdd, 0xfe, 0x95, 0xfe, 0x7a, + 0x41, 0x87, 0x6c, 0x88, 0xc2, 0x01, 0x83, 0x01, 0x6d, 0x01, 0x81, 0x46, + 0x7d, 0x68, 0x83, 0xc2, 0xfe, 0x86, 0xbf, 0x74, 0x02, 0xf4, 0x2d, 0xf9, + 0xf5, 0xb4, 0x75, 0xfd, 0x11, 0x27, 0x00, 0x00, 0xff, 0xff, 0x00, 0xae, + 0xff, 0xec, 0x05, 0x5e, 0x07, 0x73, 0x12, 0x26, 0x00, 0x38, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x43, 0x00, 0x2b, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x1b, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0xae, + 0xff, 0xec, 0x05, 0x5e, 0x07, 0x73, 0x12, 0x26, 0x00, 0x38, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x76, 0x01, 0x0e, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x1b, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0xae, + 0xff, 0xec, 0x05, 0x5e, 0x07, 0x73, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x00, + 0x01, 0x26, 0x27, 0x06, 0x07, 0x23, 0x35, 0x36, 0x37, 0x21, 0x1e, 0x01, + 0x17, 0x15, 0x17, 0x11, 0x14, 0x06, 0x04, 0x23, 0x20, 0x00, 0x35, 0x11, + 0x21, 0x11, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x11, 0x03, 0xee, 0x9d, + 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, 0x01, 0x65, 0x1f, 0x99, 0x48, 0xa5, + 0x91, 0xfe, 0xee, 0xbb, 0xfe, 0xe6, 0xfe, 0xc8, 0x01, 0x35, 0x88, 0x9d, + 0x98, 0x89, 0x06, 0x2b, 0x5d, 0x53, 0x51, 0x5f, 0x1b, 0xbd, 0x70, 0x34, + 0xb3, 0x46, 0x1b, 0x75, 0xfc, 0x4e, 0xa2, 0xf4, 0x82, 0x01, 0x21, 0xfb, + 0x03, 0xae, 0xfc, 0x81, 0xa9, 0x9e, 0x9f, 0xaa, 0x03, 0x7d, 0x00, 0x00, + 0xff, 0xff, 0x00, 0xae, 0xff, 0xec, 0x05, 0x5e, 0x07, 0x56, 0x12, 0x26, + 0x00, 0x38, 0x00, 0x00, 0x11, 0x07, 0x00, 0x6a, 0x00, 0x9a, 0x01, 0x52, + 0x00, 0x0a, 0xb4, 0x02, 0x01, 0x28, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x35, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0x07, 0x73, 0x12, 0x26, + 0x00, 0x3c, 0x00, 0x00, 0x11, 0x07, 0x00, 0x76, 0x00, 0x81, 0x01, 0x52, + 0x00, 0x08, 0xb3, 0x01, 0x11, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, + 0x00, 0x02, 0x00, 0xb8, 0x00, 0x00, 0x04, 0xaa, 0x05, 0xb6, 0x00, 0x0c, + 0x00, 0x15, 0x00, 0x36, 0x40, 0x1c, 0x11, 0x00, 0x00, 0x17, 0x0d, 0x09, + 0x05, 0x05, 0x06, 0x06, 0x16, 0x04, 0x0d, 0x4d, 0x59, 0x09, 0x15, 0x4d, + 0x59, 0x04, 0x09, 0x04, 0x09, 0x06, 0x07, 0x03, 0x06, 0x12, 0x00, 0x3f, + 0x3f, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x2b, 0x2b, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, + 0x04, 0x21, 0x23, 0x11, 0x21, 0x11, 0x21, 0x15, 0x33, 0x32, 0x04, 0x01, + 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x04, 0xaa, 0xfe, 0xe3, + 0xfe, 0xfa, 0x99, 0xfe, 0xca, 0x01, 0x36, 0xb2, 0xfe, 0x01, 0x0c, 0xfd, + 0x44, 0x64, 0x91, 0x8e, 0x7f, 0x88, 0x7c, 0x03, 0x02, 0xe5, 0xf8, 0xfe, + 0xdb, 0x05, 0xb6, 0xe5, 0xee, 0xfe, 0x3c, 0x69, 0x7a, 0x6b, 0x68, 0x00, + 0x00, 0x01, 0x00, 0xa0, 0xff, 0xec, 0x05, 0x68, 0x06, 0x1f, 0x00, 0x35, + 0x00, 0x54, 0x40, 0x2b, 0x14, 0x07, 0x21, 0x21, 0x27, 0x27, 0x00, 0x00, + 0x2e, 0x1a, 0x0e, 0x0e, 0x37, 0x2e, 0x2f, 0x2f, 0x36, 0x0e, 0x1a, 0x21, + 0x07, 0x00, 0x27, 0x27, 0x07, 0x1a, 0x03, 0x18, 0x2a, 0x33, 0x2a, 0x47, + 0x59, 0x33, 0x00, 0x2f, 0x15, 0x11, 0x18, 0x4a, 0x59, 0x11, 0x16, 0x00, + 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x17, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, 0x39, 0x11, 0x33, 0x33, + 0x31, 0x30, 0x01, 0x14, 0x0e, 0x04, 0x15, 0x14, 0x16, 0x17, 0x1e, 0x02, + 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x27, 0x35, 0x1e, 0x01, 0x33, 0x32, + 0x35, 0x34, 0x2e, 0x01, 0x27, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, 0x3e, + 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, 0x21, 0x11, 0x34, + 0x24, 0x21, 0x32, 0x04, 0x04, 0xe1, 0x2a, 0x40, 0x4a, 0x40, 0x2a, 0x35, + 0x42, 0x92, 0x69, 0x33, 0xe9, 0xe3, 0x63, 0x90, 0x3c, 0x35, 0xa5, 0x40, + 0xa8, 0x20, 0x52, 0x4a, 0x7e, 0x62, 0x46, 0x46, 0x4d, 0x3e, 0x7f, 0x64, + 0x74, 0x82, 0xfe, 0xcf, 0x01, 0x25, 0x01, 0x02, 0xf4, 0x01, 0x26, 0x04, + 0xd9, 0x40, 0x61, 0x4c, 0x3a, 0x30, 0x2a, 0x16, 0x1b, 0x34, 0x28, 0x5b, + 0x62, 0x7a, 0x4e, 0xac, 0xae, 0x1d, 0x22, 0xf2, 0x24, 0x32, 0x7b, 0x29, + 0x33, 0x3c, 0x2a, 0x48, 0x77, 0x51, 0x40, 0x6a, 0x31, 0x37, 0x50, 0x2e, + 0x3c, 0x51, 0x69, 0x60, 0xfb, 0x98, 0x04, 0x73, 0xc9, 0xe3, 0xb1, 0x00, + 0xff, 0xff, 0x00, 0x56, 0xff, 0xec, 0x04, 0x3b, 0x06, 0x21, 0x12, 0x26, + 0x00, 0x44, 0x00, 0x00, 0x11, 0x06, 0x00, 0x43, 0xa3, 0x00, 0x00, 0x08, + 0xb3, 0x02, 0x2b, 0x11, 0x26, 0x00, 0x2b, 0x35, 0xff, 0xff, 0x00, 0x56, + 0xff, 0xec, 0x04, 0x3b, 0x06, 0x21, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x76, 0x6d, 0x00, 0x00, 0x08, 0xb3, 0x02, 0x2b, 0x11, + 0x26, 0x00, 0x2b, 0x35, 0x00, 0x03, 0x00, 0x56, 0xff, 0xec, 0x04, 0x3b, + 0x06, 0x20, 0x00, 0x0d, 0x00, 0x26, 0x00, 0x30, 0x00, 0x00, 0x01, 0x26, + 0x27, 0x06, 0x07, 0x23, 0x35, 0x36, 0x37, 0x21, 0x1e, 0x01, 0x17, 0x15, + 0x03, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3f, + 0x01, 0x35, 0x34, 0x23, 0x22, 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, 0x15, + 0x11, 0x01, 0x07, 0x0e, 0x01, 0x15, 0x14, 0x33, 0x32, 0x36, 0x35, 0x03, + 0x4b, 0x9d, 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, 0x01, 0x65, 0x1f, 0x99, + 0x48, 0xb0, 0x3b, 0x08, 0x4d, 0xa3, 0x83, 0xa1, 0xb9, 0xf9, 0xfb, 0xc2, + 0xae, 0x86, 0xb5, 0x65, 0xc1, 0xeb, 0xe1, 0xf0, 0xfe, 0xd1, 0x76, 0x85, + 0x82, 0x94, 0x6a, 0x7f, 0x04, 0xd8, 0x5d, 0x53, 0x51, 0x5f, 0x1b, 0xbd, + 0x70, 0x34, 0xb3, 0x46, 0x1b, 0xfb, 0x28, 0x98, 0x61, 0x4b, 0xb8, 0xaa, + 0xb2, 0xa9, 0x09, 0x06, 0x31, 0xaa, 0x51, 0xce, 0x65, 0xc4, 0xc8, 0xfd, + 0x17, 0x02, 0x06, 0x04, 0x04, 0x58, 0x5a, 0x81, 0x7a, 0x65, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x56, 0xff, 0xec, 0x04, 0x3b, 0x06, 0x0e, 0x00, 0x17, + 0x00, 0x30, 0x00, 0x3a, 0x00, 0x00, 0x01, 0x22, 0x06, 0x07, 0x23, 0x3e, + 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, + 0x23, 0x22, 0x2e, 0x02, 0x01, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, + 0x35, 0x34, 0x36, 0x3f, 0x01, 0x35, 0x34, 0x23, 0x22, 0x07, 0x27, 0x36, + 0x33, 0x32, 0x16, 0x15, 0x11, 0x01, 0x07, 0x0e, 0x01, 0x15, 0x14, 0x33, + 0x32, 0x36, 0x35, 0x01, 0xd3, 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x8f, 0x76, + 0x29, 0x4f, 0x4d, 0x4a, 0x24, 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x91, 0x74, + 0x29, 0x4f, 0x4d, 0x4a, 0x01, 0x6f, 0x3b, 0x08, 0x4d, 0xa3, 0x83, 0xa1, + 0xb9, 0xf9, 0xfb, 0xc2, 0xae, 0x86, 0xb5, 0x65, 0xc1, 0xeb, 0xe1, 0xf0, + 0xfe, 0xd1, 0x76, 0x85, 0x82, 0x94, 0x6a, 0x7f, 0x05, 0x42, 0x35, 0x36, + 0x91, 0xa4, 0x21, 0x27, 0x20, 0x34, 0x36, 0x91, 0xa4, 0x21, 0x27, 0x21, + 0xfa, 0xbe, 0x98, 0x61, 0x4b, 0xb8, 0xaa, 0xb2, 0xa9, 0x09, 0x06, 0x31, + 0xaa, 0x51, 0xce, 0x65, 0xc4, 0xc8, 0xfd, 0x17, 0x02, 0x06, 0x04, 0x04, + 0x58, 0x5a, 0x81, 0x7a, 0x65, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x56, + 0xff, 0xec, 0x04, 0x3b, 0x06, 0x04, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x6a, 0x06, 0x00, 0x00, 0x0a, 0xb4, 0x03, 0x02, 0x38, + 0x11, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x00, 0x00, 0x04, 0x00, 0x56, + 0xff, 0xec, 0x04, 0x3b, 0x06, 0xb2, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x30, + 0x00, 0x3a, 0x00, 0x00, 0x01, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, + 0x36, 0x33, 0x32, 0x16, 0x07, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, + 0x16, 0x33, 0x32, 0x36, 0x13, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, + 0x35, 0x34, 0x36, 0x3f, 0x01, 0x35, 0x34, 0x23, 0x22, 0x07, 0x27, 0x36, + 0x33, 0x32, 0x16, 0x15, 0x11, 0x01, 0x07, 0x0e, 0x01, 0x15, 0x14, 0x33, + 0x32, 0x36, 0x35, 0x03, 0x73, 0x8e, 0x70, 0x70, 0x88, 0x87, 0x71, 0x6e, + 0x90, 0x9e, 0x36, 0x2a, 0x2a, 0x36, 0x30, 0x30, 0x2a, 0x36, 0x91, 0x3b, + 0x08, 0x4d, 0xa3, 0x83, 0xa1, 0xb9, 0xf9, 0xfb, 0xc2, 0xae, 0x86, 0xb5, + 0x65, 0xc1, 0xeb, 0xe1, 0xf0, 0xfe, 0xd1, 0x76, 0x85, 0x82, 0x94, 0x6a, + 0x7f, 0x05, 0xc7, 0x6c, 0x84, 0x80, 0x6e, 0x6c, 0x81, 0x84, 0x69, 0x2d, + 0x33, 0x33, 0x2d, 0x2d, 0x34, 0x34, 0xfa, 0x68, 0x98, 0x61, 0x4b, 0xb8, + 0xaa, 0xb2, 0xa9, 0x09, 0x06, 0x31, 0xaa, 0x51, 0xce, 0x65, 0xc4, 0xc8, + 0xfd, 0x17, 0x02, 0x06, 0x04, 0x04, 0x58, 0x5a, 0x81, 0x7a, 0x65, 0x00, + 0x00, 0x03, 0x00, 0x56, 0xff, 0xec, 0x06, 0xfe, 0x04, 0x75, 0x00, 0x28, + 0x00, 0x32, 0x00, 0x38, 0x00, 0x85, 0x40, 0x45, 0x35, 0x36, 0x03, 0x18, + 0x20, 0x20, 0x32, 0x14, 0x0d, 0x0d, 0x32, 0x32, 0x09, 0x36, 0x36, 0x26, + 0x1f, 0x1f, 0x3a, 0x2d, 0x09, 0x09, 0x39, 0x25, 0x20, 0x23, 0x35, 0x20, + 0x4a, 0x59, 0x35, 0x35, 0x06, 0x03, 0x18, 0x00, 0x1b, 0x1b, 0x33, 0x4a, + 0x59, 0x1b, 0x10, 0x0d, 0x29, 0x4b, 0x59, 0x0d, 0x0d, 0x16, 0x06, 0x16, + 0x11, 0x46, 0x59, 0x16, 0x10, 0x00, 0x23, 0x46, 0x59, 0x00, 0x06, 0x06, + 0x2f, 0x46, 0x59, 0x06, 0x16, 0x00, 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x2b, + 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x00, + 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x12, 0x39, 0x18, 0x2f, + 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x33, 0x11, 0x12, 0x39, 0x11, 0x33, 0x11, 0x39, 0x11, 0x33, + 0x12, 0x39, 0x39, 0x11, 0x39, 0x31, 0x30, 0x05, 0x22, 0x26, 0x27, 0x0e, + 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3f, 0x01, 0x35, 0x34, 0x26, + 0x23, 0x22, 0x07, 0x27, 0x36, 0x33, 0x32, 0x17, 0x3e, 0x01, 0x33, 0x32, + 0x00, 0x1d, 0x01, 0x21, 0x1e, 0x01, 0x33, 0x32, 0x37, 0x15, 0x0e, 0x01, + 0x01, 0x07, 0x0e, 0x01, 0x15, 0x14, 0x33, 0x32, 0x36, 0x35, 0x01, 0x22, + 0x07, 0x21, 0x2e, 0x01, 0x05, 0x31, 0x89, 0xe1, 0x48, 0x62, 0xc5, 0x9e, + 0xa1, 0xc3, 0xf2, 0xf1, 0xbf, 0x59, 0x4d, 0x8c, 0xa5, 0x63, 0xbd, 0xe9, + 0xe3, 0x73, 0x42, 0xad, 0x78, 0xdd, 0x01, 0x00, 0xfd, 0x2d, 0x05, 0x90, + 0x82, 0xc4, 0xb8, 0x4f, 0xb8, 0xfd, 0x41, 0x71, 0x7c, 0x7c, 0x8c, 0x65, + 0x78, 0x02, 0x23, 0xd9, 0x11, 0x01, 0xae, 0x02, 0x6a, 0x14, 0x65, 0x69, + 0x75, 0x59, 0xbd, 0xa5, 0xb2, 0xa9, 0x09, 0x06, 0x54, 0x45, 0x42, 0x4d, + 0xca, 0x65, 0x83, 0x40, 0x41, 0xfe, 0xed, 0xe9, 0x94, 0x82, 0x92, 0x58, + 0xec, 0x27, 0x28, 0x02, 0x1a, 0x04, 0x04, 0x57, 0x5b, 0x81, 0x7a, 0x65, + 0x01, 0xf0, 0xec, 0x70, 0x7c, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x5c, + 0xfe, 0x14, 0x03, 0xdd, 0x04, 0x73, 0x12, 0x26, 0x00, 0x46, 0x00, 0x00, + 0x10, 0x07, 0x00, 0x7a, 0x01, 0x83, 0x00, 0x00, 0xff, 0xff, 0x00, 0x5c, + 0xff, 0xec, 0x04, 0x62, 0x06, 0x21, 0x12, 0x26, 0x00, 0x48, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x43, 0xa9, 0x00, 0x00, 0x08, 0xb3, 0x02, 0x24, 0x11, + 0x26, 0x00, 0x2b, 0x35, 0xff, 0xff, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x62, + 0x06, 0x21, 0x12, 0x26, 0x00, 0x48, 0x00, 0x00, 0x11, 0x06, 0x00, 0x76, + 0x73, 0x00, 0x00, 0x08, 0xb3, 0x02, 0x24, 0x11, 0x26, 0x00, 0x2b, 0x35, + 0x00, 0x03, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x62, 0x06, 0x21, 0x00, 0x0d, + 0x00, 0x14, 0x00, 0x29, 0x00, 0x00, 0x01, 0x26, 0x27, 0x06, 0x07, 0x23, + 0x35, 0x36, 0x37, 0x21, 0x1e, 0x01, 0x17, 0x15, 0x01, 0x22, 0x06, 0x07, + 0x21, 0x2e, 0x01, 0x03, 0x20, 0x00, 0x11, 0x10, 0x00, 0x33, 0x32, 0x00, + 0x1d, 0x01, 0x21, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x15, 0x0e, 0x01, + 0x03, 0x5c, 0x9d, 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, 0x01, 0x65, 0x1f, + 0x99, 0x48, 0xfe, 0x48, 0x61, 0x6e, 0x08, 0x01, 0xac, 0x02, 0x72, 0x36, + 0xfe, 0xf2, 0xfe, 0xd0, 0x01, 0x19, 0xf8, 0xed, 0x01, 0x08, 0xfd, 0x2f, + 0x05, 0x90, 0x82, 0x65, 0xb4, 0x62, 0x50, 0xb6, 0x04, 0xd9, 0x5d, 0x53, + 0x51, 0x5f, 0x1b, 0xbd, 0x70, 0x34, 0xb3, 0x46, 0x1b, 0xfe, 0xc1, 0x7b, + 0x71, 0x71, 0x7b, 0xfc, 0x52, 0x01, 0x2a, 0x01, 0x11, 0x01, 0x19, 0x01, + 0x33, 0xfe, 0xf2, 0xee, 0x94, 0x82, 0x92, 0x2a, 0x2e, 0xec, 0x28, 0x27, + 0xff, 0xff, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x62, 0x06, 0x04, 0x12, 0x26, + 0x00, 0x48, 0x00, 0x00, 0x11, 0x06, 0x00, 0x6a, 0x12, 0x00, 0x00, 0x0a, + 0xb4, 0x03, 0x02, 0x31, 0x11, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x00, + 0x00, 0x02, 0xff, 0x9b, 0x00, 0x00, 0x01, 0xdc, 0x06, 0x21, 0x00, 0x03, + 0x00, 0x0c, 0x00, 0x00, 0x29, 0x01, 0x11, 0x21, 0x27, 0x2e, 0x01, 0x27, + 0x35, 0x21, 0x16, 0x17, 0x15, 0x01, 0xd1, 0xfe, 0xcf, 0x01, 0x31, 0xbf, + 0x3f, 0xf4, 0x44, 0x01, 0x56, 0x3f, 0xac, 0x04, 0x5e, 0x7b, 0x2c, 0xc5, + 0x42, 0x15, 0x65, 0xc8, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x91, + 0x00, 0x00, 0x02, 0xd2, 0x06, 0x21, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x00, + 0x29, 0x01, 0x11, 0x21, 0x25, 0x35, 0x36, 0x37, 0x21, 0x15, 0x0e, 0x01, + 0x07, 0x01, 0xd1, 0xfe, 0xcf, 0x01, 0x31, 0xfe, 0xc0, 0xac, 0x3f, 0x01, + 0x56, 0x34, 0xfb, 0x47, 0x04, 0x5e, 0x7b, 0x1b, 0xc8, 0x65, 0x15, 0x34, + 0xcd, 0x32, 0x00, 0x00, 0x00, 0x02, 0xff, 0x86, 0x00, 0x00, 0x02, 0xeb, + 0x06, 0x21, 0x00, 0x0d, 0x00, 0x11, 0x00, 0x00, 0x01, 0x26, 0x27, 0x06, + 0x07, 0x23, 0x35, 0x36, 0x37, 0x21, 0x1e, 0x01, 0x17, 0x15, 0x01, 0x21, + 0x11, 0x21, 0x02, 0x20, 0x9d, 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, 0x01, + 0x65, 0x1f, 0x99, 0x48, 0xfe, 0xe6, 0xfe, 0xcf, 0x01, 0x31, 0x04, 0xd9, + 0x5d, 0x53, 0x51, 0x5f, 0x1b, 0xbd, 0x70, 0x34, 0xb3, 0x46, 0x1b, 0xfb, + 0x27, 0x04, 0x5e, 0x00, 0x00, 0x03, 0xff, 0xe3, 0x00, 0x00, 0x02, 0x91, + 0x06, 0x04, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x1b, 0x00, 0x00, 0x29, 0x01, + 0x11, 0x21, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x25, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x01, 0xd1, 0xfe, 0xcf, 0x01, 0x31, 0xfe, 0x12, 0x4b, 0x40, + 0x42, 0x4b, 0x4c, 0x41, 0x40, 0x4b, 0x01, 0x93, 0x51, 0x3c, 0x41, 0x4d, + 0x4e, 0x40, 0x3c, 0x51, 0x04, 0x5e, 0x01, 0x1f, 0x41, 0x46, 0x4a, 0x3d, + 0x3c, 0x49, 0x46, 0x3f, 0x46, 0x41, 0x48, 0x3f, 0x3d, 0x48, 0x41, 0x00, + 0x00, 0x02, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x98, 0x06, 0x23, 0x00, 0x1b, + 0x00, 0x27, 0x00, 0x76, 0x40, 0x3b, 0x00, 0x19, 0x02, 0x17, 0x17, 0x1c, + 0x05, 0x08, 0x03, 0x0b, 0x03, 0x02, 0x02, 0x11, 0x1c, 0x1c, 0x0b, 0x0b, + 0x29, 0x22, 0x11, 0x11, 0x28, 0x19, 0x00, 0x18, 0x02, 0x05, 0x08, 0x03, + 0x09, 0x09, 0x18, 0x18, 0x02, 0x16, 0x16, 0x1f, 0x14, 0x14, 0x1f, 0x46, + 0x59, 0x14, 0x14, 0x0e, 0x02, 0x0e, 0x25, 0x46, 0x59, 0x0e, 0x16, 0x03, + 0x02, 0x4b, 0x59, 0x03, 0x01, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, + 0x12, 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, 0x11, 0x12, 0x39, 0x39, + 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, + 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, + 0x31, 0x30, 0x01, 0x26, 0x27, 0x37, 0x16, 0x17, 0x37, 0x17, 0x07, 0x16, + 0x12, 0x15, 0x10, 0x00, 0x23, 0x22, 0x00, 0x35, 0x34, 0x00, 0x33, 0x32, + 0x17, 0x37, 0x26, 0x27, 0x07, 0x27, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, 0x01, 0xfe, 0x50, 0x48, 0x65, 0x90, + 0x72, 0xe1, 0x64, 0xaa, 0x9c, 0x94, 0xfe, 0xde, 0xff, 0xf5, 0xfe, 0xda, + 0x01, 0x04, 0xdd, 0xcd, 0x46, 0x08, 0x43, 0x7d, 0xe6, 0x64, 0x02, 0x12, + 0x7a, 0x6b, 0x79, 0x6f, 0x78, 0x70, 0x7b, 0x6a, 0x05, 0x17, 0x35, 0x27, + 0xb0, 0x41, 0x4c, 0x8b, 0x9a, 0x68, 0x8f, 0xfe, 0x95, 0xe8, 0xfe, 0xe8, + 0xfe, 0xc7, 0x01, 0x12, 0xeb, 0xe9, 0x01, 0x11, 0x62, 0x04, 0xa2, 0x77, + 0x8e, 0x9c, 0xfd, 0x68, 0x6c, 0x82, 0x89, 0x92, 0x8c, 0x8e, 0xa4, 0x00, + 0x00, 0x02, 0x00, 0xa0, 0x00, 0x00, 0x04, 0xa8, 0x06, 0x0e, 0x00, 0x17, + 0x00, 0x2c, 0x00, 0x00, 0x01, 0x22, 0x06, 0x07, 0x23, 0x3e, 0x01, 0x33, + 0x32, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, 0x23, 0x22, + 0x2e, 0x02, 0x01, 0x21, 0x11, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, + 0x21, 0x11, 0x33, 0x17, 0x33, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x01, + 0xfc, 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x8f, 0x76, 0x29, 0x4f, 0x4d, 0x4a, + 0x24, 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x91, 0x74, 0x29, 0x4f, 0x4d, 0x4a, + 0x02, 0x88, 0xfe, 0xcf, 0x56, 0x5e, 0x80, 0x72, 0xfe, 0xcf, 0xe9, 0x29, + 0x11, 0x33, 0xb3, 0x72, 0xc3, 0xca, 0x05, 0x42, 0x35, 0x36, 0x91, 0xa4, + 0x21, 0x27, 0x20, 0x34, 0x36, 0x91, 0xa4, 0x21, 0x27, 0x21, 0xfa, 0xbe, + 0x02, 0x8d, 0x79, 0x79, 0xab, 0xc6, 0xfd, 0xf2, 0x04, 0x5e, 0x8f, 0x51, + 0x53, 0xd3, 0xc7, 0x00, 0xff, 0xff, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x98, + 0x06, 0x21, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x11, 0x06, 0x00, 0x43, + 0xa1, 0x00, 0x00, 0x08, 0xb3, 0x02, 0x22, 0x11, 0x26, 0x00, 0x2b, 0x35, + 0xff, 0xff, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x98, 0x06, 0x21, 0x12, 0x26, + 0x00, 0x52, 0x00, 0x00, 0x11, 0x07, 0x00, 0x76, 0x00, 0x87, 0x00, 0x00, + 0x00, 0x08, 0xb3, 0x02, 0x22, 0x11, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x98, 0x06, 0x21, 0x00, 0x0d, + 0x00, 0x19, 0x00, 0x27, 0x00, 0x00, 0x01, 0x26, 0x27, 0x06, 0x07, 0x23, + 0x35, 0x36, 0x37, 0x21, 0x1e, 0x01, 0x17, 0x15, 0x01, 0x14, 0x16, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x05, 0x10, 0x00, 0x21, + 0x22, 0x26, 0x02, 0x35, 0x10, 0x00, 0x21, 0x32, 0x16, 0x12, 0x03, 0x60, + 0x9d, 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, 0x01, 0x65, 0x1f, 0x99, 0x48, + 0xfd, 0x68, 0x6d, 0x7b, 0x7a, 0x6b, 0x6c, 0x7b, 0x7a, 0x6c, 0x03, 0x05, + 0xfe, 0xe0, 0xfe, 0xff, 0xa1, 0xf6, 0x84, 0x01, 0x1e, 0x01, 0x03, 0xa1, + 0xf6, 0x84, 0x04, 0xd9, 0x5d, 0x53, 0x51, 0x5f, 0x1b, 0xbd, 0x70, 0x34, + 0xb3, 0x46, 0x1b, 0xfd, 0x58, 0xa6, 0xaa, 0xa9, 0xa7, 0xa6, 0xa6, 0xa5, + 0xa7, 0xfe, 0xef, 0xfe, 0xcc, 0x8d, 0x01, 0x08, 0xb0, 0x01, 0x12, 0x01, + 0x30, 0x8c, 0xfe, 0xfa, 0x00, 0x03, 0x00, 0x5c, 0xff, 0xec, 0x04, 0x98, + 0x06, 0x0e, 0x00, 0x17, 0x00, 0x23, 0x00, 0x31, 0x00, 0x00, 0x01, 0x22, + 0x06, 0x07, 0x23, 0x3e, 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, 0x32, 0x36, + 0x37, 0x33, 0x0e, 0x01, 0x23, 0x22, 0x2e, 0x02, 0x03, 0x14, 0x16, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x05, 0x10, 0x00, 0x21, + 0x22, 0x26, 0x02, 0x35, 0x10, 0x00, 0x21, 0x32, 0x16, 0x12, 0x01, 0xd5, + 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x8f, 0x76, 0x29, 0x4f, 0x4d, 0x4a, 0x24, + 0x1f, 0x39, 0x0d, 0x95, 0x0b, 0x91, 0x74, 0x29, 0x4f, 0x4d, 0x4a, 0x66, + 0x6d, 0x7b, 0x7a, 0x6b, 0x6c, 0x7b, 0x7a, 0x6c, 0x03, 0x05, 0xfe, 0xe0, + 0xfe, 0xff, 0xa1, 0xf6, 0x84, 0x01, 0x1e, 0x01, 0x03, 0xa1, 0xf6, 0x84, + 0x05, 0x42, 0x35, 0x36, 0x91, 0xa4, 0x21, 0x27, 0x20, 0x34, 0x36, 0x91, + 0xa4, 0x21, 0x27, 0x21, 0xfc, 0xef, 0xa6, 0xaa, 0xa9, 0xa7, 0xa6, 0xa6, + 0xa5, 0xa7, 0xfe, 0xef, 0xfe, 0xcc, 0x8d, 0x01, 0x08, 0xb0, 0x01, 0x12, + 0x01, 0x30, 0x8c, 0xfe, 0xfa, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x5c, + 0xff, 0xec, 0x04, 0x98, 0x06, 0x04, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x6a, 0x0c, 0x00, 0x00, 0x0a, 0xb4, 0x03, 0x02, 0x2f, + 0x11, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x58, + 0x00, 0xdd, 0x04, 0x39, 0x04, 0xc7, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x1b, + 0x00, 0x2a, 0x40, 0x12, 0x16, 0x0a, 0x0a, 0x10, 0x04, 0x04, 0x00, 0x03, + 0x03, 0x1d, 0x00, 0x1c, 0x19, 0x13, 0x0d, 0x07, 0x00, 0x01, 0x00, 0x2f, + 0x33, 0xc4, 0x32, 0xc4, 0x32, 0x11, 0x01, 0x33, 0x11, 0x33, 0x11, 0x12, + 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x35, 0x21, 0x15, + 0x05, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, + 0x11, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, + 0x58, 0x03, 0xe1, 0xfd, 0x83, 0x4a, 0x42, 0x42, 0x49, 0x4a, 0x41, 0x41, + 0x4b, 0x4a, 0x42, 0x43, 0x48, 0x4a, 0x41, 0x41, 0x4b, 0x02, 0x64, 0xdb, + 0xdb, 0xef, 0x4c, 0x4b, 0x4e, 0x49, 0x46, 0x52, 0x4e, 0x03, 0x04, 0x4b, + 0x4d, 0x51, 0x47, 0x46, 0x51, 0x4e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x5c, + 0xff, 0xb4, 0x04, 0x98, 0x04, 0x91, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x23, + 0x00, 0x39, 0x40, 0x1c, 0x17, 0x1f, 0x1c, 0x14, 0x14, 0x0a, 0x1c, 0x00, + 0x0a, 0x00, 0x25, 0x24, 0x16, 0x1e, 0x21, 0x19, 0x0d, 0x19, 0x47, 0x59, + 0x0d, 0x10, 0x03, 0x21, 0x47, 0x59, 0x03, 0x16, 0x00, 0x3f, 0x2b, 0x00, + 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x11, 0x12, 0x01, 0x39, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, 0x31, 0x30, 0x01, + 0x10, 0x00, 0x21, 0x22, 0x27, 0x07, 0x27, 0x37, 0x26, 0x11, 0x10, 0x00, + 0x21, 0x32, 0x17, 0x37, 0x17, 0x07, 0x16, 0x01, 0x14, 0x17, 0x01, 0x26, + 0x23, 0x22, 0x06, 0x05, 0x34, 0x27, 0x01, 0x16, 0x33, 0x32, 0x36, 0x04, + 0x98, 0xfe, 0xe0, 0xfe, 0xff, 0x7e, 0x6c, 0x43, 0x9a, 0x44, 0x98, 0x01, + 0x1e, 0x01, 0x03, 0x84, 0x74, 0x37, 0x98, 0x3a, 0x8e, 0xfc, 0xfb, 0x13, + 0x01, 0x3d, 0x2b, 0x3f, 0x7a, 0x6c, 0x01, 0xcd, 0x0c, 0xfe, 0xcb, 0x26, + 0x36, 0x7a, 0x6b, 0x02, 0x31, 0xfe, 0xef, 0xfe, 0xcc, 0x2d, 0x65, 0x69, + 0x64, 0x9c, 0x01, 0x14, 0x01, 0x12, 0x01, 0x30, 0x34, 0x52, 0x6c, 0x54, + 0x9b, 0xfe, 0xfb, 0x5e, 0x48, 0x01, 0xdb, 0x17, 0xa5, 0xa7, 0x51, 0x3c, + 0xfe, 0x32, 0x0f, 0xa9, 0xff, 0xff, 0x00, 0x9a, 0xff, 0xec, 0x04, 0xa2, + 0x06, 0x21, 0x12, 0x26, 0x00, 0x58, 0x00, 0x00, 0x11, 0x06, 0x00, 0x43, + 0xa9, 0x00, 0x00, 0x08, 0xb3, 0x01, 0x1d, 0x11, 0x26, 0x00, 0x2b, 0x35, + 0xff, 0xff, 0x00, 0x9a, 0xff, 0xec, 0x04, 0xa2, 0x06, 0x21, 0x12, 0x26, + 0x00, 0x58, 0x00, 0x00, 0x11, 0x07, 0x00, 0x76, 0x00, 0xa6, 0x00, 0x00, + 0x00, 0x08, 0xb3, 0x01, 0x1d, 0x11, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x9a, 0xff, 0xec, 0x04, 0xa2, 0x06, 0x21, 0x00, 0x0d, + 0x00, 0x22, 0x00, 0x00, 0x01, 0x26, 0x27, 0x06, 0x07, 0x23, 0x35, 0x36, + 0x37, 0x21, 0x1e, 0x01, 0x17, 0x15, 0x03, 0x27, 0x23, 0x0e, 0x01, 0x23, + 0x22, 0x26, 0x35, 0x11, 0x21, 0x11, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, + 0x11, 0x21, 0x11, 0x03, 0x85, 0x9d, 0x4d, 0x4e, 0x97, 0xcb, 0xbd, 0x43, + 0x01, 0x65, 0x1f, 0x99, 0x48, 0x98, 0x29, 0x10, 0x31, 0xb4, 0x73, 0xc5, + 0xc8, 0x01, 0x31, 0x56, 0x5e, 0x80, 0x72, 0x01, 0x31, 0x04, 0xd9, 0x5d, + 0x53, 0x51, 0x5f, 0x1b, 0xbd, 0x70, 0x34, 0xb3, 0x46, 0x1b, 0xfb, 0x27, + 0x8f, 0x4e, 0x55, 0xd3, 0xc6, 0x02, 0xd9, 0xfd, 0x73, 0x79, 0x79, 0xab, + 0xc6, 0x02, 0x0e, 0xfb, 0xa2, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x9a, + 0xff, 0xec, 0x04, 0xa2, 0x06, 0x04, 0x12, 0x26, 0x00, 0x58, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x6a, 0x2f, 0x00, 0x00, 0x0a, 0xb4, 0x02, 0x01, 0x2a, + 0x11, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xfe, 0x14, 0x04, 0x8d, 0x06, 0x21, 0x12, 0x26, 0x00, 0x5c, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x76, 0x3d, 0x00, 0x00, 0x08, 0xb3, 0x01, 0x1f, 0x11, + 0x26, 0x00, 0x2b, 0x35, 0x00, 0x02, 0x00, 0xa0, 0xfe, 0x14, 0x04, 0xb4, + 0x06, 0x14, 0x00, 0x15, 0x00, 0x21, 0x00, 0x44, 0x40, 0x22, 0x1f, 0x06, + 0x06, 0x23, 0x15, 0x0c, 0x10, 0x1a, 0x13, 0x0f, 0x0f, 0x10, 0x10, 0x22, + 0x11, 0x00, 0x10, 0x1b, 0x0c, 0x15, 0x09, 0x03, 0x09, 0x1d, 0x47, 0x59, + 0x09, 0x16, 0x03, 0x16, 0x47, 0x59, 0x03, 0x10, 0x00, 0x3f, 0x2b, 0x00, + 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x18, 0x3f, 0x3f, 0x11, + 0x01, 0x33, 0x11, 0x33, 0x11, 0x33, 0x33, 0x12, 0x39, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x3e, 0x01, 0x33, 0x32, 0x12, 0x11, 0x10, + 0x02, 0x23, 0x22, 0x27, 0x23, 0x1f, 0x01, 0x11, 0x21, 0x11, 0x21, 0x11, + 0x0f, 0x01, 0x17, 0x22, 0x06, 0x07, 0x15, 0x14, 0x16, 0x33, 0x32, 0x11, + 0x34, 0x26, 0x01, 0xd1, 0x32, 0xa2, 0x69, 0xc6, 0xe0, 0xdf, 0xc7, 0xd5, + 0x68, 0x0e, 0x07, 0x07, 0xfe, 0xcf, 0x01, 0x31, 0x07, 0x07, 0xe9, 0x71, + 0x68, 0x02, 0x6b, 0x74, 0xcd, 0x65, 0x03, 0xcd, 0x51, 0x55, 0xfe, 0xcb, + 0xfe, 0xf3, 0xfe, 0xef, 0xfe, 0xcc, 0x89, 0x3e, 0x5e, 0xfe, 0x3b, 0x08, + 0x00, 0xfe, 0x79, 0x78, 0x48, 0x4e, 0x8b, 0xa0, 0x21, 0xb4, 0x9c, 0x01, + 0x52, 0xa5, 0xa5, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x14, 0x04, 0x8d, + 0x06, 0x04, 0x12, 0x26, 0x00, 0x5c, 0x00, 0x00, 0x11, 0x06, 0x00, 0x6a, + 0xdc, 0x00, 0x00, 0x0a, 0xb4, 0x02, 0x01, 0x2c, 0x11, 0x26, 0x00, 0x2b, + 0x35, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x72, + 0x00, 0x01, 0x04, 0x66, 0x18, 0x00, 0x00, 0x0a, 0x02, 0x64, 0x00, 0x05, + 0x00, 0x24, 0xff, 0x71, 0x00, 0x05, 0x00, 0x37, 0x00, 0x29, 0x00, 0x05, + 0x00, 0x39, 0x00, 0x29, 0x00, 0x05, 0x00, 0x3a, 0x00, 0x29, 0x00, 0x05, + 0x00, 0x3c, 0x00, 0x14, 0x00, 0x05, 0x00, 0x44, 0xff, 0xae, 0x00, 0x05, + 0x00, 0x46, 0xff, 0x85, 0x00, 0x05, 0x00, 0x47, 0xff, 0x85, 0x00, 0x05, + 0x00, 0x48, 0xff, 0x85, 0x00, 0x05, 0x00, 0x4a, 0xff, 0xc3, 0x00, 0x05, + 0x00, 0x50, 0xff, 0xc3, 0x00, 0x05, 0x00, 0x51, 0xff, 0xc3, 0x00, 0x05, + 0x00, 0x52, 0xff, 0x85, 0x00, 0x05, 0x00, 0x53, 0xff, 0xc3, 0x00, 0x05, + 0x00, 0x54, 0xff, 0x85, 0x00, 0x05, 0x00, 0x55, 0xff, 0xc3, 0x00, 0x05, + 0x00, 0x56, 0xff, 0xc3, 0x00, 0x05, 0x00, 0x58, 0xff, 0xc3, 0x00, 0x05, + 0x00, 0x82, 0xff, 0x71, 0x00, 0x05, 0x00, 0x83, 0xff, 0x71, 0x00, 0x05, + 0x00, 0x84, 0xff, 0x71, 0x00, 0x05, 0x00, 0x85, 0xff, 0x71, 0x00, 0x05, + 0x00, 0x86, 0xff, 0x71, 0x00, 0x05, 0x00, 0x87, 0xff, 0x71, 0x00, 0x05, + 0x00, 0x9f, 0x00, 0x14, 0x00, 0x05, 0x00, 0xa2, 0xff, 0x85, 0x00, 0x05, + 0x00, 0xa3, 0xff, 0xae, 0x00, 0x05, 0x00, 0xa4, 0xff, 0xae, 0x00, 0x05, + 0x00, 0xa5, 0xff, 0xae, 0x00, 0x05, 0x00, 0xa6, 0xff, 0xae, 0x00, 0x05, + 0x00, 0xa7, 0xff, 0xae, 0x00, 0x05, 0x00, 0xa8, 0xff, 0xae, 0x00, 0x05, + 0x00, 0xa9, 0xff, 0x85, 0x00, 0x05, 0x00, 0xaa, 0xff, 0x85, 0x00, 0x05, + 0x00, 0xab, 0xff, 0x85, 0x00, 0x05, 0x00, 0xac, 0xff, 0x85, 0x00, 0x05, + 0x00, 0xad, 0xff, 0x85, 0x00, 0x05, 0x00, 0xb4, 0xff, 0x85, 0x00, 0x05, + 0x00, 0xb5, 0xff, 0x85, 0x00, 0x05, 0x00, 0xb6, 0xff, 0x85, 0x00, 0x05, + 0x00, 0xb7, 0xff, 0x85, 0x00, 0x05, 0x00, 0xb8, 0xff, 0x85, 0x00, 0x05, + 0x00, 0xba, 0xff, 0x85, 0x00, 0x05, 0x00, 0xbb, 0xff, 0xc3, 0x00, 0x05, + 0x00, 0xbc, 0xff, 0xc3, 0x00, 0x05, 0x00, 0xbd, 0xff, 0xc3, 0x00, 0x05, + 0x00, 0xbe, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0x24, 0xff, 0x71, 0x00, 0x0a, + 0x00, 0x37, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x39, 0x00, 0x29, 0x00, 0x0a, + 0x00, 0x3a, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x3c, 0x00, 0x14, 0x00, 0x0a, + 0x00, 0x44, 0xff, 0xae, 0x00, 0x0a, 0x00, 0x46, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0x47, 0xff, 0x85, 0x00, 0x0a, 0x00, 0x48, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0x4a, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0x50, 0xff, 0xc3, 0x00, 0x0a, + 0x00, 0x51, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0x52, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0x53, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0x54, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0x55, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0x56, 0xff, 0xc3, 0x00, 0x0a, + 0x00, 0x58, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0x82, 0xff, 0x71, 0x00, 0x0a, + 0x00, 0x83, 0xff, 0x71, 0x00, 0x0a, 0x00, 0x84, 0xff, 0x71, 0x00, 0x0a, + 0x00, 0x85, 0xff, 0x71, 0x00, 0x0a, 0x00, 0x86, 0xff, 0x71, 0x00, 0x0a, + 0x00, 0x87, 0xff, 0x71, 0x00, 0x0a, 0x00, 0x9f, 0x00, 0x14, 0x00, 0x0a, + 0x00, 0xa2, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xa3, 0xff, 0xae, 0x00, 0x0a, + 0x00, 0xa4, 0xff, 0xae, 0x00, 0x0a, 0x00, 0xa5, 0xff, 0xae, 0x00, 0x0a, + 0x00, 0xa6, 0xff, 0xae, 0x00, 0x0a, 0x00, 0xa7, 0xff, 0xae, 0x00, 0x0a, + 0x00, 0xa8, 0xff, 0xae, 0x00, 0x0a, 0x00, 0xa9, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0xaa, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xab, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0xac, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xad, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0xb4, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xb5, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0xb6, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xb7, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0xb8, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xba, 0xff, 0x85, 0x00, 0x0a, + 0x00, 0xbb, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0xbc, 0xff, 0xc3, 0x00, 0x0a, + 0x00, 0xbd, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0xbe, 0xff, 0xc3, 0x00, 0x0b, + 0x00, 0x2d, 0x00, 0xb8, 0x00, 0x0f, 0x00, 0x26, 0xff, 0x9a, 0x00, 0x0f, + 0x00, 0x2a, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x32, 0xff, 0x9a, 0x00, 0x0f, + 0x00, 0x34, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x37, 0xff, 0x71, 0x00, 0x0f, + 0x00, 0x38, 0xff, 0xd7, 0x00, 0x0f, 0x00, 0x39, 0xff, 0x85, 0x00, 0x0f, + 0x00, 0x3a, 0xff, 0x85, 0x00, 0x0f, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x0f, + 0x00, 0x89, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x94, 0xff, 0x9a, 0x00, 0x0f, + 0x00, 0x95, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x96, 0xff, 0x9a, 0x00, 0x0f, + 0x00, 0x97, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x98, 0xff, 0x9a, 0x00, 0x0f, + 0x00, 0x9a, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x9b, 0xff, 0xd7, 0x00, 0x0f, + 0x00, 0x9c, 0xff, 0xd7, 0x00, 0x0f, 0x00, 0x9d, 0xff, 0xd7, 0x00, 0x0f, + 0x00, 0x9e, 0xff, 0xd7, 0x00, 0x0f, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x10, + 0x00, 0x37, 0xff, 0xae, 0x00, 0x11, 0x00, 0x26, 0xff, 0x9a, 0x00, 0x11, + 0x00, 0x2a, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x32, 0xff, 0x9a, 0x00, 0x11, + 0x00, 0x34, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x37, 0xff, 0x71, 0x00, 0x11, + 0x00, 0x38, 0xff, 0xd7, 0x00, 0x11, 0x00, 0x39, 0xff, 0x85, 0x00, 0x11, + 0x00, 0x3a, 0xff, 0x85, 0x00, 0x11, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x11, + 0x00, 0x89, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x94, 0xff, 0x9a, 0x00, 0x11, + 0x00, 0x95, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x96, 0xff, 0x9a, 0x00, 0x11, + 0x00, 0x97, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x98, 0xff, 0x9a, 0x00, 0x11, + 0x00, 0x9a, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x9b, 0xff, 0xd7, 0x00, 0x11, + 0x00, 0x9c, 0xff, 0xd7, 0x00, 0x11, 0x00, 0x9d, 0xff, 0xd7, 0x00, 0x11, + 0x00, 0x9e, 0xff, 0xd7, 0x00, 0x11, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x24, + 0x00, 0x05, 0xff, 0x71, 0x00, 0x24, 0x00, 0x0a, 0xff, 0x71, 0x00, 0x24, + 0x00, 0x26, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x24, + 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x24, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x24, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x37, 0xff, 0x71, 0x00, 0x24, + 0x00, 0x39, 0xff, 0xae, 0x00, 0x24, 0x00, 0x3a, 0xff, 0xae, 0x00, 0x24, + 0x00, 0x3c, 0xff, 0x85, 0x00, 0x24, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x24, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x24, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x24, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x24, + 0x00, 0x9f, 0xff, 0x85, 0x00, 0x25, 0x00, 0x0f, 0xff, 0xae, 0x00, 0x25, + 0x00, 0x11, 0xff, 0xae, 0x00, 0x25, 0x00, 0x24, 0xff, 0xd7, 0x00, 0x25, + 0x00, 0x37, 0xff, 0xc3, 0x00, 0x25, 0x00, 0x39, 0xff, 0xec, 0x00, 0x25, + 0x00, 0x3a, 0xff, 0xec, 0x00, 0x25, 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x25, + 0x00, 0x3c, 0xff, 0xec, 0x00, 0x25, 0x00, 0x3d, 0xff, 0xec, 0x00, 0x25, + 0x00, 0x82, 0xff, 0xd7, 0x00, 0x25, 0x00, 0x83, 0xff, 0xd7, 0x00, 0x25, + 0x00, 0x84, 0xff, 0xd7, 0x00, 0x25, 0x00, 0x85, 0xff, 0xd7, 0x00, 0x25, + 0x00, 0x86, 0xff, 0xd7, 0x00, 0x25, 0x00, 0x87, 0xff, 0xd7, 0x00, 0x25, + 0x00, 0x9f, 0xff, 0xec, 0x00, 0x26, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x26, + 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x26, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x26, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x26, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x26, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x27, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x27, 0x00, 0x11, 0xff, 0xae, 0x00, 0x27, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x27, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x27, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x27, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x27, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x27, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x27, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x27, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x27, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x28, + 0x00, 0x2d, 0x00, 0x7b, 0x00, 0x29, 0x00, 0x0f, 0xff, 0x85, 0x00, 0x29, + 0x00, 0x11, 0xff, 0x85, 0x00, 0x29, 0x00, 0x22, 0x00, 0x29, 0x00, 0x29, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x29, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x29, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x29, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x29, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x29, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x29, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x2e, + 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x2e, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x2e, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x2e, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x2e, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x2f, + 0x00, 0x05, 0xff, 0x5c, 0x00, 0x2f, 0x00, 0x0a, 0xff, 0x5c, 0x00, 0x2f, + 0x00, 0x26, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x2f, + 0x00, 0x32, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x2f, + 0x00, 0x37, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x38, 0xff, 0xec, 0x00, 0x2f, + 0x00, 0x39, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x3a, 0xff, 0xd7, 0x00, 0x2f, + 0x00, 0x3c, 0xff, 0xc3, 0x00, 0x2f, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x2f, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x2f, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x2f, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x2f, + 0x00, 0x9b, 0xff, 0xec, 0x00, 0x2f, 0x00, 0x9c, 0xff, 0xec, 0x00, 0x2f, + 0x00, 0x9d, 0xff, 0xec, 0x00, 0x2f, 0x00, 0x9e, 0xff, 0xec, 0x00, 0x2f, + 0x00, 0x9f, 0xff, 0xc3, 0x00, 0x32, 0x00, 0x0f, 0xff, 0xae, 0x00, 0x32, + 0x00, 0x11, 0xff, 0xae, 0x00, 0x32, 0x00, 0x24, 0xff, 0xd7, 0x00, 0x32, + 0x00, 0x37, 0xff, 0xc3, 0x00, 0x32, 0x00, 0x39, 0xff, 0xec, 0x00, 0x32, + 0x00, 0x3a, 0xff, 0xec, 0x00, 0x32, 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x32, + 0x00, 0x3c, 0xff, 0xec, 0x00, 0x32, 0x00, 0x3d, 0xff, 0xec, 0x00, 0x32, + 0x00, 0x82, 0xff, 0xd7, 0x00, 0x32, 0x00, 0x83, 0xff, 0xd7, 0x00, 0x32, + 0x00, 0x84, 0xff, 0xd7, 0x00, 0x32, 0x00, 0x85, 0xff, 0xd7, 0x00, 0x32, + 0x00, 0x86, 0xff, 0xd7, 0x00, 0x32, 0x00, 0x87, 0xff, 0xd7, 0x00, 0x32, + 0x00, 0x9f, 0xff, 0xec, 0x00, 0x33, 0x00, 0x0f, 0xfe, 0xf6, 0x00, 0x33, + 0x00, 0x11, 0xfe, 0xf6, 0x00, 0x33, 0x00, 0x24, 0xff, 0x9a, 0x00, 0x33, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x33, 0x00, 0x3d, 0xff, 0xec, 0x00, 0x33, + 0x00, 0x82, 0xff, 0x9a, 0x00, 0x33, 0x00, 0x83, 0xff, 0x9a, 0x00, 0x33, + 0x00, 0x84, 0xff, 0x9a, 0x00, 0x33, 0x00, 0x85, 0xff, 0x9a, 0x00, 0x33, + 0x00, 0x86, 0xff, 0x9a, 0x00, 0x33, 0x00, 0x87, 0xff, 0x9a, 0x00, 0x34, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x34, 0x00, 0x11, 0xff, 0xae, 0x00, 0x34, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x34, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x34, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x34, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x34, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x34, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x34, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x34, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x34, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x34, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x34, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x34, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x34, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x34, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x37, + 0x00, 0x0f, 0xff, 0x85, 0x00, 0x37, 0x00, 0x10, 0xff, 0xae, 0x00, 0x37, + 0x00, 0x11, 0xff, 0x85, 0x00, 0x37, 0x00, 0x22, 0x00, 0x29, 0x00, 0x37, + 0x00, 0x24, 0xff, 0x71, 0x00, 0x37, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x37, + 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x37, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x37, 0x00, 0x29, 0x00, 0x37, + 0x00, 0x44, 0xff, 0x5c, 0x00, 0x37, 0x00, 0x46, 0xff, 0x71, 0x00, 0x37, + 0x00, 0x47, 0xff, 0x71, 0x00, 0x37, 0x00, 0x48, 0xff, 0x71, 0x00, 0x37, + 0x00, 0x4a, 0xff, 0x71, 0x00, 0x37, 0x00, 0x50, 0xff, 0x9a, 0x00, 0x37, + 0x00, 0x51, 0xff, 0x9a, 0x00, 0x37, 0x00, 0x52, 0xff, 0x71, 0x00, 0x37, + 0x00, 0x53, 0xff, 0x9a, 0x00, 0x37, 0x00, 0x54, 0xff, 0x71, 0x00, 0x37, + 0x00, 0x55, 0xff, 0x9a, 0x00, 0x37, 0x00, 0x56, 0xff, 0x85, 0x00, 0x37, + 0x00, 0x58, 0xff, 0x9a, 0x00, 0x37, 0x00, 0x59, 0xff, 0xd7, 0x00, 0x37, + 0x00, 0x5a, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x5b, 0xff, 0xd7, 0x00, 0x37, + 0x00, 0x5c, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x5d, 0xff, 0xae, 0x00, 0x37, + 0x00, 0x82, 0xff, 0x71, 0x00, 0x37, 0x00, 0x83, 0xff, 0x71, 0x00, 0x37, + 0x00, 0x84, 0xff, 0x71, 0x00, 0x37, 0x00, 0x85, 0xff, 0x71, 0x00, 0x37, + 0x00, 0x86, 0xff, 0x71, 0x00, 0x37, 0x00, 0x87, 0xff, 0x71, 0x00, 0x37, + 0x00, 0x89, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x37, + 0x00, 0x95, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x37, + 0x00, 0x97, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x37, + 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x37, 0x00, 0xa2, 0xff, 0x71, 0x00, 0x37, + 0x00, 0xa3, 0xff, 0x5c, 0x00, 0x37, 0x00, 0xa4, 0xff, 0x5c, 0x00, 0x37, + 0x00, 0xa5, 0xff, 0x5c, 0x00, 0x37, 0x00, 0xa6, 0xff, 0x5c, 0x00, 0x37, + 0x00, 0xa7, 0xff, 0x5c, 0x00, 0x37, 0x00, 0xa8, 0xff, 0x5c, 0x00, 0x37, + 0x00, 0xa9, 0xff, 0x71, 0x00, 0x37, 0x00, 0xaa, 0xff, 0x71, 0x00, 0x37, + 0x00, 0xab, 0xff, 0x71, 0x00, 0x37, 0x00, 0xac, 0xff, 0x71, 0x00, 0x37, + 0x00, 0xad, 0xff, 0x71, 0x00, 0x37, 0x00, 0xb4, 0xff, 0x71, 0x00, 0x37, + 0x00, 0xb5, 0xff, 0x71, 0x00, 0x37, 0x00, 0xb6, 0xff, 0x71, 0x00, 0x37, + 0x00, 0xb7, 0xff, 0x71, 0x00, 0x37, 0x00, 0xb8, 0xff, 0x71, 0x00, 0x37, + 0x00, 0xba, 0xff, 0x71, 0x00, 0x37, 0x00, 0xbb, 0xff, 0x9a, 0x00, 0x37, + 0x00, 0xbc, 0xff, 0x9a, 0x00, 0x37, 0x00, 0xbd, 0xff, 0x9a, 0x00, 0x37, + 0x00, 0xbe, 0xff, 0x9a, 0x00, 0x37, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0x38, + 0x00, 0x0f, 0xff, 0xd7, 0x00, 0x38, 0x00, 0x11, 0xff, 0xd7, 0x00, 0x38, + 0x00, 0x24, 0xff, 0xec, 0x00, 0x38, 0x00, 0x82, 0xff, 0xec, 0x00, 0x38, + 0x00, 0x83, 0xff, 0xec, 0x00, 0x38, 0x00, 0x84, 0xff, 0xec, 0x00, 0x38, + 0x00, 0x85, 0xff, 0xec, 0x00, 0x38, 0x00, 0x86, 0xff, 0xec, 0x00, 0x38, + 0x00, 0x87, 0xff, 0xec, 0x00, 0x39, 0x00, 0x0f, 0xff, 0x9a, 0x00, 0x39, + 0x00, 0x11, 0xff, 0x9a, 0x00, 0x39, 0x00, 0x22, 0x00, 0x29, 0x00, 0x39, + 0x00, 0x24, 0xff, 0xae, 0x00, 0x39, 0x00, 0x26, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x2a, 0xff, 0xec, 0x00, 0x39, 0x00, 0x32, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x34, 0xff, 0xec, 0x00, 0x39, 0x00, 0x44, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0x46, 0xff, 0xd7, 0x00, 0x39, 0x00, 0x47, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0x48, 0xff, 0xd7, 0x00, 0x39, 0x00, 0x4a, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x50, 0xff, 0xec, 0x00, 0x39, 0x00, 0x51, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x52, 0xff, 0xd7, 0x00, 0x39, 0x00, 0x53, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x54, 0xff, 0xd7, 0x00, 0x39, 0x00, 0x55, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x56, 0xff, 0xec, 0x00, 0x39, 0x00, 0x58, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x82, 0xff, 0xae, 0x00, 0x39, 0x00, 0x83, 0xff, 0xae, 0x00, 0x39, + 0x00, 0x84, 0xff, 0xae, 0x00, 0x39, 0x00, 0x85, 0xff, 0xae, 0x00, 0x39, + 0x00, 0x86, 0xff, 0xae, 0x00, 0x39, 0x00, 0x87, 0xff, 0xae, 0x00, 0x39, + 0x00, 0x89, 0xff, 0xec, 0x00, 0x39, 0x00, 0x94, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x95, 0xff, 0xec, 0x00, 0x39, 0x00, 0x96, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x97, 0xff, 0xec, 0x00, 0x39, 0x00, 0x98, 0xff, 0xec, 0x00, 0x39, + 0x00, 0x9a, 0xff, 0xec, 0x00, 0x39, 0x00, 0xa2, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xa3, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xa4, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xa5, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xa6, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xa7, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xa8, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xa9, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xaa, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xab, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xac, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xad, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xb4, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xb5, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xb6, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xb7, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xb8, 0xff, 0xd7, 0x00, 0x39, + 0x00, 0xba, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xbb, 0xff, 0xec, 0x00, 0x39, + 0x00, 0xbc, 0xff, 0xec, 0x00, 0x39, 0x00, 0xbd, 0xff, 0xec, 0x00, 0x39, + 0x00, 0xbe, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x0f, 0xff, 0x9a, 0x00, 0x3a, + 0x00, 0x11, 0xff, 0x9a, 0x00, 0x3a, 0x00, 0x22, 0x00, 0x29, 0x00, 0x3a, + 0x00, 0x24, 0xff, 0xae, 0x00, 0x3a, 0x00, 0x26, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x2a, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x32, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x34, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x44, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0x46, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0x47, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0x48, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0x4a, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x50, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x51, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x52, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0x53, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x54, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0x55, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x56, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x58, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x82, 0xff, 0xae, 0x00, 0x3a, 0x00, 0x83, 0xff, 0xae, 0x00, 0x3a, + 0x00, 0x84, 0xff, 0xae, 0x00, 0x3a, 0x00, 0x85, 0xff, 0xae, 0x00, 0x3a, + 0x00, 0x86, 0xff, 0xae, 0x00, 0x3a, 0x00, 0x87, 0xff, 0xae, 0x00, 0x3a, + 0x00, 0x89, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x94, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x95, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x96, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x97, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x98, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0x9a, 0xff, 0xec, 0x00, 0x3a, 0x00, 0xa2, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xa3, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xa4, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xa5, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xa6, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xa7, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xa8, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xa9, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xaa, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xab, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xac, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xad, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xb4, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xb5, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xb6, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xb7, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xb8, 0xff, 0xd7, 0x00, 0x3a, + 0x00, 0xba, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xbb, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0xbc, 0xff, 0xec, 0x00, 0x3a, 0x00, 0xbd, 0xff, 0xec, 0x00, 0x3a, + 0x00, 0xbe, 0xff, 0xec, 0x00, 0x3b, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x3b, + 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x3b, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x3b, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x3b, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x3b, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x3c, + 0x00, 0x0f, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x11, 0xff, 0x85, 0x00, 0x3c, + 0x00, 0x22, 0x00, 0x29, 0x00, 0x3c, 0x00, 0x24, 0xff, 0x85, 0x00, 0x3c, + 0x00, 0x26, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x3c, + 0x00, 0x32, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x3c, + 0x00, 0x44, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0x46, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0x47, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0x48, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0x4a, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x50, 0xff, 0xc3, 0x00, 0x3c, + 0x00, 0x51, 0xff, 0xc3, 0x00, 0x3c, 0x00, 0x52, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0x53, 0xff, 0xc3, 0x00, 0x3c, 0x00, 0x54, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0x55, 0xff, 0xc3, 0x00, 0x3c, 0x00, 0x56, 0xff, 0xae, 0x00, 0x3c, + 0x00, 0x58, 0xff, 0xc3, 0x00, 0x3c, 0x00, 0x5d, 0xff, 0xd7, 0x00, 0x3c, + 0x00, 0x82, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x83, 0xff, 0x85, 0x00, 0x3c, + 0x00, 0x84, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x85, 0xff, 0x85, 0x00, 0x3c, + 0x00, 0x86, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x87, 0xff, 0x85, 0x00, 0x3c, + 0x00, 0x89, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x3c, + 0x00, 0x95, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x3c, + 0x00, 0x97, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x3c, + 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0xa2, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xa3, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xa4, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xa5, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xa6, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xa7, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xa8, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xa9, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xaa, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xab, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xac, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xad, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xb4, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xb5, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xb6, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xb7, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xb8, 0xff, 0x9a, 0x00, 0x3c, + 0x00, 0xba, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xbb, 0xff, 0xc3, 0x00, 0x3c, + 0x00, 0xbc, 0xff, 0xc3, 0x00, 0x3c, 0x00, 0xbd, 0xff, 0xc3, 0x00, 0x3c, + 0x00, 0xbe, 0xff, 0xc3, 0x00, 0x3d, 0x00, 0x26, 0xff, 0xec, 0x00, 0x3d, + 0x00, 0x2a, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x32, 0xff, 0xec, 0x00, 0x3d, + 0x00, 0x34, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x89, 0xff, 0xec, 0x00, 0x3d, + 0x00, 0x94, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x95, 0xff, 0xec, 0x00, 0x3d, + 0x00, 0x96, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x97, 0xff, 0xec, 0x00, 0x3d, + 0x00, 0x98, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x9a, 0xff, 0xec, 0x00, 0x3e, + 0x00, 0x2d, 0x00, 0xb8, 0x00, 0x44, 0x00, 0x05, 0xff, 0xec, 0x00, 0x44, + 0x00, 0x0a, 0xff, 0xec, 0x00, 0x45, 0x00, 0x05, 0xff, 0xec, 0x00, 0x45, + 0x00, 0x0a, 0xff, 0xec, 0x00, 0x45, 0x00, 0x59, 0xff, 0xd7, 0x00, 0x45, + 0x00, 0x5a, 0xff, 0xd7, 0x00, 0x45, 0x00, 0x5b, 0xff, 0xd7, 0x00, 0x45, + 0x00, 0x5c, 0xff, 0xd7, 0x00, 0x45, 0x00, 0x5d, 0xff, 0xec, 0x00, 0x45, + 0x00, 0xbf, 0xff, 0xd7, 0x00, 0x46, 0x00, 0x05, 0x00, 0x29, 0x00, 0x46, + 0x00, 0x0a, 0x00, 0x29, 0x00, 0x48, 0x00, 0x05, 0xff, 0xec, 0x00, 0x48, + 0x00, 0x0a, 0xff, 0xec, 0x00, 0x48, 0x00, 0x59, 0xff, 0xd7, 0x00, 0x48, + 0x00, 0x5a, 0xff, 0xd7, 0x00, 0x48, 0x00, 0x5b, 0xff, 0xd7, 0x00, 0x48, + 0x00, 0x5c, 0xff, 0xd7, 0x00, 0x48, 0x00, 0x5d, 0xff, 0xec, 0x00, 0x48, + 0x00, 0xbf, 0xff, 0xd7, 0x00, 0x49, 0x00, 0x05, 0x00, 0x7b, 0x00, 0x49, + 0x00, 0x0a, 0x00, 0x7b, 0x00, 0x4b, 0x00, 0x05, 0xff, 0xec, 0x00, 0x4b, + 0x00, 0x0a, 0xff, 0xec, 0x00, 0x4e, 0x00, 0x46, 0xff, 0xd7, 0x00, 0x4e, + 0x00, 0x47, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0x48, 0xff, 0xd7, 0x00, 0x4e, + 0x00, 0x52, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0x54, 0xff, 0xd7, 0x00, 0x4e, + 0x00, 0xa2, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xa9, 0xff, 0xd7, 0x00, 0x4e, + 0x00, 0xaa, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xab, 0xff, 0xd7, 0x00, 0x4e, + 0x00, 0xac, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xad, 0xff, 0xd7, 0x00, 0x4e, + 0x00, 0xb4, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xb5, 0xff, 0xd7, 0x00, 0x4e, + 0x00, 0xb6, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xb7, 0xff, 0xd7, 0x00, 0x4e, + 0x00, 0xb8, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xba, 0xff, 0xd7, 0x00, 0x50, + 0x00, 0x05, 0xff, 0xec, 0x00, 0x50, 0x00, 0x0a, 0xff, 0xec, 0x00, 0x51, + 0x00, 0x05, 0xff, 0xec, 0x00, 0x51, 0x00, 0x0a, 0xff, 0xec, 0x00, 0x52, + 0x00, 0x05, 0xff, 0xec, 0x00, 0x52, 0x00, 0x0a, 0xff, 0xec, 0x00, 0x52, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0x52, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0x52, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0x52, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0x52, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0x52, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0x53, + 0x00, 0x05, 0xff, 0xec, 0x00, 0x53, 0x00, 0x0a, 0xff, 0xec, 0x00, 0x53, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0x53, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0x53, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0x53, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0x53, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0x53, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0x05, 0x00, 0x52, 0x00, 0x55, 0x00, 0x0a, 0x00, 0x52, 0x00, 0x55, + 0x00, 0x44, 0xff, 0xd7, 0x00, 0x55, 0x00, 0x46, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0x47, 0xff, 0xd7, 0x00, 0x55, 0x00, 0x48, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0x4a, 0xff, 0xec, 0x00, 0x55, 0x00, 0x52, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0x54, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xa2, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xa3, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xa4, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xa5, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xa6, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xa7, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xa8, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xa9, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xaa, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xab, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xac, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xad, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xb4, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xb5, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xb6, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xb7, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xb8, 0xff, 0xd7, 0x00, 0x55, + 0x00, 0xba, 0xff, 0xd7, 0x00, 0x57, 0x00, 0x05, 0x00, 0x29, 0x00, 0x57, + 0x00, 0x0a, 0x00, 0x29, 0x00, 0x59, 0x00, 0x05, 0x00, 0x52, 0x00, 0x59, + 0x00, 0x0a, 0x00, 0x52, 0x00, 0x59, 0x00, 0x0f, 0xff, 0xae, 0x00, 0x59, + 0x00, 0x11, 0xff, 0xae, 0x00, 0x59, 0x00, 0x22, 0x00, 0x29, 0x00, 0x5a, + 0x00, 0x05, 0x00, 0x52, 0x00, 0x5a, 0x00, 0x0a, 0x00, 0x52, 0x00, 0x5a, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x5a, 0x00, 0x11, 0xff, 0xae, 0x00, 0x5a, + 0x00, 0x22, 0x00, 0x29, 0x00, 0x5b, 0x00, 0x46, 0xff, 0xd7, 0x00, 0x5b, + 0x00, 0x47, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0x48, 0xff, 0xd7, 0x00, 0x5b, + 0x00, 0x52, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0x54, 0xff, 0xd7, 0x00, 0x5b, + 0x00, 0xa2, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xa9, 0xff, 0xd7, 0x00, 0x5b, + 0x00, 0xaa, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xab, 0xff, 0xd7, 0x00, 0x5b, + 0x00, 0xac, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xad, 0xff, 0xd7, 0x00, 0x5b, + 0x00, 0xb4, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xb5, 0xff, 0xd7, 0x00, 0x5b, + 0x00, 0xb6, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xb7, 0xff, 0xd7, 0x00, 0x5b, + 0x00, 0xb8, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xba, 0xff, 0xd7, 0x00, 0x5c, + 0x00, 0x05, 0x00, 0x52, 0x00, 0x5c, 0x00, 0x0a, 0x00, 0x52, 0x00, 0x5c, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x5c, 0x00, 0x11, 0xff, 0xae, 0x00, 0x5c, + 0x00, 0x22, 0x00, 0x29, 0x00, 0x5e, 0x00, 0x2d, 0x00, 0xb8, 0x00, 0x82, + 0x00, 0x05, 0xff, 0x71, 0x00, 0x82, 0x00, 0x0a, 0xff, 0x71, 0x00, 0x82, + 0x00, 0x26, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x82, + 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x82, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x82, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x37, 0xff, 0x71, 0x00, 0x82, + 0x00, 0x39, 0xff, 0xae, 0x00, 0x82, 0x00, 0x3a, 0xff, 0xae, 0x00, 0x82, + 0x00, 0x3c, 0xff, 0x85, 0x00, 0x82, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x82, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x82, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x82, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x82, + 0x00, 0x9f, 0xff, 0x85, 0x00, 0x83, 0x00, 0x05, 0xff, 0x71, 0x00, 0x83, + 0x00, 0x0a, 0xff, 0x71, 0x00, 0x83, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x83, + 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x83, + 0x00, 0x32, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x83, + 0x00, 0x37, 0xff, 0x71, 0x00, 0x83, 0x00, 0x39, 0xff, 0xae, 0x00, 0x83, + 0x00, 0x3a, 0xff, 0xae, 0x00, 0x83, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x83, + 0x00, 0x89, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x83, + 0x00, 0x95, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x83, + 0x00, 0x97, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x83, + 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x84, + 0x00, 0x05, 0xff, 0x71, 0x00, 0x84, 0x00, 0x0a, 0xff, 0x71, 0x00, 0x84, + 0x00, 0x26, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x84, + 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x84, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x84, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x37, 0xff, 0x71, 0x00, 0x84, + 0x00, 0x39, 0xff, 0xae, 0x00, 0x84, 0x00, 0x3a, 0xff, 0xae, 0x00, 0x84, + 0x00, 0x3c, 0xff, 0x85, 0x00, 0x84, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x84, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x84, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x84, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x84, + 0x00, 0x9f, 0xff, 0x85, 0x00, 0x85, 0x00, 0x05, 0xff, 0x71, 0x00, 0x85, + 0x00, 0x0a, 0xff, 0x71, 0x00, 0x85, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x85, + 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x85, + 0x00, 0x32, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x85, + 0x00, 0x37, 0xff, 0x71, 0x00, 0x85, 0x00, 0x39, 0xff, 0xae, 0x00, 0x85, + 0x00, 0x3a, 0xff, 0xae, 0x00, 0x85, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x85, + 0x00, 0x89, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x85, + 0x00, 0x95, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x85, + 0x00, 0x97, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x85, + 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x86, + 0x00, 0x05, 0xff, 0x71, 0x00, 0x86, 0x00, 0x0a, 0xff, 0x71, 0x00, 0x86, + 0x00, 0x26, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x86, + 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x86, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x86, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x37, 0xff, 0x71, 0x00, 0x86, + 0x00, 0x39, 0xff, 0xae, 0x00, 0x86, 0x00, 0x3a, 0xff, 0xae, 0x00, 0x86, + 0x00, 0x3c, 0xff, 0x85, 0x00, 0x86, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x86, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x86, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x86, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x86, + 0x00, 0x9f, 0xff, 0x85, 0x00, 0x87, 0x00, 0x05, 0xff, 0x71, 0x00, 0x87, + 0x00, 0x0a, 0xff, 0x71, 0x00, 0x87, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x87, + 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x87, + 0x00, 0x32, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x87, + 0x00, 0x37, 0xff, 0x71, 0x00, 0x87, 0x00, 0x39, 0xff, 0xae, 0x00, 0x87, + 0x00, 0x3a, 0xff, 0xae, 0x00, 0x87, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x87, + 0x00, 0x89, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x87, + 0x00, 0x95, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x87, + 0x00, 0x97, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x87, + 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x88, + 0x00, 0x2d, 0x00, 0x7b, 0x00, 0x89, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x89, + 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x89, + 0x00, 0x34, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x89, + 0x00, 0x94, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x89, + 0x00, 0x96, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x89, + 0x00, 0x98, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x8a, + 0x00, 0x2d, 0x00, 0x7b, 0x00, 0x8b, 0x00, 0x2d, 0x00, 0x7b, 0x00, 0x8c, + 0x00, 0x2d, 0x00, 0x7b, 0x00, 0x8d, 0x00, 0x2d, 0x00, 0x7b, 0x00, 0x92, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x92, 0x00, 0x11, 0xff, 0xae, 0x00, 0x92, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x92, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x92, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x92, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x92, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x92, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x92, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x92, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x92, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x92, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x92, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x92, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x92, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x92, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x94, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x94, 0x00, 0x11, 0xff, 0xae, 0x00, 0x94, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x94, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x94, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x94, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x94, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x94, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x94, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x94, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x94, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x94, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x94, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x94, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x94, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x94, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x95, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x95, 0x00, 0x11, 0xff, 0xae, 0x00, 0x95, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x95, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x95, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x95, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x95, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x95, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x95, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x95, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x95, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x95, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x95, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x95, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x95, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x95, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x96, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x96, 0x00, 0x11, 0xff, 0xae, 0x00, 0x96, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x96, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x96, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x96, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x96, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x96, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x96, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x96, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x96, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x96, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x96, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x96, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x96, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x96, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x97, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x97, 0x00, 0x11, 0xff, 0xae, 0x00, 0x97, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x97, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x97, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x97, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x97, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x97, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x97, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x97, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x97, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x97, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x97, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x97, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x97, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x97, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x98, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x98, 0x00, 0x11, 0xff, 0xae, 0x00, 0x98, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x98, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x98, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x98, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x98, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x98, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x98, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x98, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x98, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x98, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x98, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x98, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x98, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x98, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x9a, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0x9a, 0x00, 0x11, 0xff, 0xae, 0x00, 0x9a, + 0x00, 0x24, 0xff, 0xd7, 0x00, 0x9a, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x9a, + 0x00, 0x39, 0xff, 0xec, 0x00, 0x9a, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x9a, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x9a, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x9a, + 0x00, 0x3d, 0xff, 0xec, 0x00, 0x9a, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x9a, + 0x00, 0x83, 0xff, 0xd7, 0x00, 0x9a, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x9a, + 0x00, 0x85, 0xff, 0xd7, 0x00, 0x9a, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x9a, + 0x00, 0x87, 0xff, 0xd7, 0x00, 0x9a, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x9b, + 0x00, 0x0f, 0xff, 0xd7, 0x00, 0x9b, 0x00, 0x11, 0xff, 0xd7, 0x00, 0x9b, + 0x00, 0x24, 0xff, 0xec, 0x00, 0x9b, 0x00, 0x82, 0xff, 0xec, 0x00, 0x9b, + 0x00, 0x83, 0xff, 0xec, 0x00, 0x9b, 0x00, 0x84, 0xff, 0xec, 0x00, 0x9b, + 0x00, 0x85, 0xff, 0xec, 0x00, 0x9b, 0x00, 0x86, 0xff, 0xec, 0x00, 0x9b, + 0x00, 0x87, 0xff, 0xec, 0x00, 0x9c, 0x00, 0x0f, 0xff, 0xd7, 0x00, 0x9c, + 0x00, 0x11, 0xff, 0xd7, 0x00, 0x9c, 0x00, 0x24, 0xff, 0xec, 0x00, 0x9c, + 0x00, 0x82, 0xff, 0xec, 0x00, 0x9c, 0x00, 0x83, 0xff, 0xec, 0x00, 0x9c, + 0x00, 0x84, 0xff, 0xec, 0x00, 0x9c, 0x00, 0x85, 0xff, 0xec, 0x00, 0x9c, + 0x00, 0x86, 0xff, 0xec, 0x00, 0x9c, 0x00, 0x87, 0xff, 0xec, 0x00, 0x9d, + 0x00, 0x0f, 0xff, 0xd7, 0x00, 0x9d, 0x00, 0x11, 0xff, 0xd7, 0x00, 0x9d, + 0x00, 0x24, 0xff, 0xec, 0x00, 0x9d, 0x00, 0x82, 0xff, 0xec, 0x00, 0x9d, + 0x00, 0x83, 0xff, 0xec, 0x00, 0x9d, 0x00, 0x84, 0xff, 0xec, 0x00, 0x9d, + 0x00, 0x85, 0xff, 0xec, 0x00, 0x9d, 0x00, 0x86, 0xff, 0xec, 0x00, 0x9d, + 0x00, 0x87, 0xff, 0xec, 0x00, 0x9e, 0x00, 0x0f, 0xff, 0xd7, 0x00, 0x9e, + 0x00, 0x11, 0xff, 0xd7, 0x00, 0x9e, 0x00, 0x24, 0xff, 0xec, 0x00, 0x9e, + 0x00, 0x82, 0xff, 0xec, 0x00, 0x9e, 0x00, 0x83, 0xff, 0xec, 0x00, 0x9e, + 0x00, 0x84, 0xff, 0xec, 0x00, 0x9e, 0x00, 0x85, 0xff, 0xec, 0x00, 0x9e, + 0x00, 0x86, 0xff, 0xec, 0x00, 0x9e, 0x00, 0x87, 0xff, 0xec, 0x00, 0x9f, + 0x00, 0x0f, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x11, 0xff, 0x85, 0x00, 0x9f, + 0x00, 0x22, 0x00, 0x29, 0x00, 0x9f, 0x00, 0x24, 0xff, 0x85, 0x00, 0x9f, + 0x00, 0x26, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x9f, + 0x00, 0x32, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x9f, + 0x00, 0x44, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0x46, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0x47, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0x48, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0x4a, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x50, 0xff, 0xc3, 0x00, 0x9f, + 0x00, 0x51, 0xff, 0xc3, 0x00, 0x9f, 0x00, 0x52, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0x53, 0xff, 0xc3, 0x00, 0x9f, 0x00, 0x54, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0x55, 0xff, 0xc3, 0x00, 0x9f, 0x00, 0x56, 0xff, 0xae, 0x00, 0x9f, + 0x00, 0x58, 0xff, 0xc3, 0x00, 0x9f, 0x00, 0x5d, 0xff, 0xd7, 0x00, 0x9f, + 0x00, 0x82, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x83, 0xff, 0x85, 0x00, 0x9f, + 0x00, 0x84, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x85, 0xff, 0x85, 0x00, 0x9f, + 0x00, 0x86, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x87, 0xff, 0x85, 0x00, 0x9f, + 0x00, 0x89, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x9f, + 0x00, 0x95, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x9f, + 0x00, 0x97, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x9f, + 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0xa2, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xa3, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xa5, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xa6, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xa7, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xa8, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xa9, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xaa, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xab, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xac, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xad, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xb4, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xb5, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xb6, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xb7, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xb8, 0xff, 0x9a, 0x00, 0x9f, + 0x00, 0xba, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xbb, 0xff, 0xc3, 0x00, 0x9f, + 0x00, 0xbc, 0xff, 0xc3, 0x00, 0x9f, 0x00, 0xbd, 0xff, 0xc3, 0x00, 0x9f, + 0x00, 0xbe, 0xff, 0xc3, 0x00, 0xa0, 0x00, 0x0f, 0xfe, 0xf6, 0x00, 0xa0, + 0x00, 0x11, 0xfe, 0xf6, 0x00, 0xa0, 0x00, 0x24, 0xff, 0x9a, 0x00, 0xa0, + 0x00, 0x3b, 0xff, 0xd7, 0x00, 0xa0, 0x00, 0x3d, 0xff, 0xec, 0x00, 0xa0, + 0x00, 0x82, 0xff, 0x9a, 0x00, 0xa0, 0x00, 0x83, 0xff, 0x9a, 0x00, 0xa0, + 0x00, 0x84, 0xff, 0x9a, 0x00, 0xa0, 0x00, 0x85, 0xff, 0x9a, 0x00, 0xa0, + 0x00, 0x86, 0xff, 0x9a, 0x00, 0xa0, 0x00, 0x87, 0xff, 0x9a, 0x00, 0xa2, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xa2, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa3, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xa3, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa4, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xa4, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa5, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xa5, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa6, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xa6, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa7, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xa7, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xaa, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xaa, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xaa, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xaa, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xaa, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xaa, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xaa, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xaa, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xab, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xab, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xab, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xab, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xab, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xab, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xab, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xab, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xac, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xac, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xac, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xac, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xac, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xac, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xac, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xac, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xad, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xad, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xad, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xad, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xad, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xad, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xad, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xad, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb2, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xb2, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xb2, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xb2, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xb2, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xb2, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xb2, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xb2, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb4, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xb4, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xb4, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xb4, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xb4, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xb4, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xb4, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xb4, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb5, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xb5, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xb5, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xb5, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xb5, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xb5, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xb5, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xb5, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb6, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xb6, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xb6, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xb6, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xb6, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xb6, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xb6, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xb6, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb8, + 0x00, 0x05, 0xff, 0xd7, 0x00, 0xb8, 0x00, 0x0a, 0xff, 0xd7, 0x00, 0xba, + 0x00, 0x05, 0xff, 0xec, 0x00, 0xba, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xba, + 0x00, 0x59, 0xff, 0xd7, 0x00, 0xba, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xba, + 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xba, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xba, + 0x00, 0x5d, 0xff, 0xec, 0x00, 0xba, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xbf, + 0x00, 0x05, 0x00, 0x52, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x52, 0x00, 0xbf, + 0x00, 0x0f, 0xff, 0xae, 0x00, 0xbf, 0x00, 0x11, 0xff, 0xae, 0x00, 0xbf, + 0x00, 0x22, 0x00, 0x29, 0x00, 0xc0, 0x00, 0x05, 0xff, 0xec, 0x00, 0xc0, + 0x00, 0x0a, 0xff, 0xec, 0x00, 0xc0, 0x00, 0x59, 0xff, 0xd7, 0x00, 0xc0, + 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xc0, 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xc0, + 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xc0, 0x00, 0x5d, 0xff, 0xec, 0x00, 0xc0, + 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xc1, 0x00, 0x05, 0x00, 0x52, 0x00, 0xc1, + 0x00, 0x0a, 0x00, 0x52, 0x00, 0xc1, 0x00, 0x0f, 0xff, 0xae, 0x00, 0xc1, + 0x00, 0x11, 0xff, 0xae, 0x00, 0xc1, 0x00, 0x22, 0x00, 0x29, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x31, 0x02, 0x52, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x39, 0x00, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x09, 0x00, 0xc2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x04, 0x00, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x23, 0x01, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x0e, 0x01, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x0c, 0x01, 0x8e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x0d, 0x01, 0xb7, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x52, 0x02, 0x6b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x14, 0x02, 0xe8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0b, 0x00, 0x1c, 0x03, 0x37, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x2e, 0x03, 0xb2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x2e, 0x04, 0x3f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x2a, 0x04, 0xc4, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x18, 0x04, 0xef, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x0b, 0x05, 0x76, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x11, 0x05, 0xa2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x03, 0x00, 0x12, 0x06, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x12, 0x06, 0x78, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x18, 0x05, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x12, 0x05, 0x82, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x00, 0x1f, 0x05, 0xb4, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x03, 0x00, 0x1f, 0x06, 0x24, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x04, 0x00, 0x23, 0x06, 0x8b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x21, 0x05, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + 0x01, 0x02, 0x00, 0x17, 0x05, 0xd4, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + 0x01, 0x03, 0x00, 0x10, 0x06, 0x44, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + 0x01, 0x04, 0x00, 0x0f, 0x06, 0xaf, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x01, 0x00, 0x00, 0x15, 0x05, 0x43, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x01, 0x02, 0x00, 0x11, 0x05, 0xec, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x01, 0x03, 0x00, 0x13, 0x06, 0x55, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x01, 0x04, 0x00, 0x0c, 0x06, 0xbf, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x01, 0x00, 0x00, 0x1c, 0x05, 0x59, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x01, 0x01, 0x00, 0x0c, 0x05, 0x95, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x01, 0x02, 0x00, 0x12, 0x05, 0xfe, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x01, 0x03, 0x00, 0x0e, 0x06, 0x69, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x01, 0x04, 0x00, 0x0d, 0x06, 0xcc, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x01, 0x00, 0x12, 0x00, 0xae, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x02, 0x00, 0x08, 0x00, 0xcc, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x03, 0x00, 0x46, 0x00, 0xdb, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x04, 0x00, 0x1c, 0x01, 0x47, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x05, 0x00, 0x18, 0x01, 0x74, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x06, 0x00, 0x1a, 0x01, 0x9b, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x07, 0x00, 0xa4, 0x01, 0xc5, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x08, 0x00, 0x28, 0x02, 0xbe, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x0b, 0x00, 0x38, 0x02, 0xfd, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x0c, 0x00, 0x5c, 0x03, 0x54, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x0d, 0x00, 0x5c, 0x03, 0xe1, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x0e, 0x00, 0x54, 0x04, 0x6e, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, + 0x00, 0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x64, + 0x00, 0x20, 0x00, 0x64, 0x00, 0x61, 0x00, 0x74, 0x00, 0x61, 0x00, 0x20, + 0x00, 0x63, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x79, 0x00, 0x72, 0x00, 0x69, + 0x00, 0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x20, 0x00, 0xa9, 0x00, 0x20, + 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x32, + 0x00, 0x30, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x47, + 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, + 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, + 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2e, + 0x00, 0x00, 0x44, 0x69, 0x67, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x20, + 0x64, 0x61, 0x74, 0x61, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x20, 0xa9, 0x20, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x32, 0x30, + 0x31, 0x31, 0x2c, 0x20, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x43, + 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x00, + 0x00, 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x53, + 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x00, 0x4f, 0x70, 0x65, 0x6e, + 0x20, 0x53, 0x61, 0x6e, 0x73, 0x00, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6c, + 0x00, 0x64, 0x00, 0x00, 0x42, 0x6f, 0x6c, 0x64, 0x00, 0x00, 0x41, 0x00, + 0x73, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x65, 0x00, + 0x72, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x4f, 0x00, 0x70, 0x00, + 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, 0x00, + 0x73, 0x00, 0x20, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, 0x00, + 0x20, 0x00, 0x42, 0x00, 0x75, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x64, 0x00, + 0x20, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x41, 0x73, 0x63, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x2d, 0x20, 0x4f, 0x70, 0x65, 0x6e, + 0x20, 0x53, 0x61, 0x6e, 0x73, 0x20, 0x42, 0x6f, 0x6c, 0x64, 0x20, 0x42, + 0x75, 0x69, 0x6c, 0x64, 0x20, 0x31, 0x30, 0x30, 0x00, 0x00, 0x4f, 0x00, + 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x53, 0x00, 0x61, 0x00, + 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6c, 0x00, + 0x64, 0x00, 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x20, 0x53, 0x61, 0x6e, 0x73, + 0x20, 0x42, 0x6f, 0x6c, 0x64, 0x00, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, + 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x31, + 0x00, 0x2e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x00, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x31, 0x30, 0x00, 0x00, 0x4f, 0x00, + 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, 0x00, + 0x73, 0x00, 0x2d, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, 0x00, + 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x61, 0x6e, 0x73, 0x2d, 0x42, 0x6f, + 0x6c, 0x64, 0x00, 0x00, 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, + 0x20, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, + 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x74, 0x00, + 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x61, 0x00, + 0x72, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, + 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, + 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x6d, 0x00, + 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x72, 0x00, 0x65, 0x00, 0x67, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x69, 0x00, + 0x6e, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, + 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x6a, 0x00, 0x75, 0x00, + 0x72, 0x00, 0x69, 0x00, 0x73, 0x00, 0x64, 0x00, 0x69, 0x00, 0x63, 0x00, + 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x2e, 0x00, + 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x20, 0x53, 0x61, 0x6e, 0x73, 0x20, 0x69, + 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x61, 0x64, 0x65, 0x6d, 0x61, 0x72, + 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, + 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6a, 0x75, 0x72, + 0x69, 0x73, 0x64, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x00, + 0x00, 0x41, 0x00, 0x73, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x64, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, + 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, + 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, + 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, + 0x2e, 0x00, 0x61, 0x00, 0x73, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, + 0x64, 0x00, 0x65, 0x00, 0x72, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x72, 0x00, + 0x70, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2f, 0x00, + 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, + 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, 0x77, + 0x00, 0x77, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x73, 0x00, 0x63, 0x00, 0x65, + 0x00, 0x6e, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x00, 0x63, 0x00, 0x6f, + 0x00, 0x72, 0x00, 0x70, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, + 0x00, 0x2f, 0x00, 0x74, 0x00, 0x79, 0x00, 0x70, 0x00, 0x65, 0x00, 0x64, + 0x00, 0x65, 0x00, 0x73, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x65, + 0x00, 0x72, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x68, 0x00, 0x74, 0x00, 0x6d, + 0x00, 0x6c, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x79, 0x70, 0x65, + 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x00, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, + 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x75, 0x00, + 0x6e, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x74, 0x00, + 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x41, 0x00, 0x70, 0x00, 0x61, 0x00, + 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x69, 0x00, + 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00, + 0x20, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, + 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, 0x00, + 0x00, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x64, 0x20, 0x75, 0x6e, + 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x41, 0x70, 0x61, 0x63, + 0x68, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x2e, 0x30, 0x00, + 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, + 0x00, 0x2f, 0x00, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x61, + 0x00, 0x70, 0x00, 0x61, 0x00, 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x2e, + 0x00, 0x6f, 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x6c, 0x00, 0x69, + 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00, 0x73, + 0x00, 0x2f, 0x00, 0x4c, 0x00, 0x49, 0x00, 0x43, 0x00, 0x45, 0x00, 0x4e, + 0x00, 0x53, 0x00, 0x45, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, + 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x2f, + 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x2f, 0x4c, 0x49, 0x43, + 0x45, 0x4e, 0x53, 0x45, 0x2d, 0x32, 0x2e, 0x30, 0x00, 0x41, 0x6c, 0x6c, + 0x20, 0x54, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, + 0x20, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x00, 0x46, 0x6f, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x79, 0x70, 0x6f, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x71, 0x75, 0x65, 0x73, 0x00, 0x41, + 0x6c, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x66, + 0x69, 0x73, 0x63, 0x68, 0x65, 0x6e, 0x20, 0x4d, 0x9a, 0x67, 0x6c, 0x69, + 0x63, 0x68, 0x6b, 0x65, 0x69, 0x74, 0x65, 0x6e, 0x00, 0x46, 0x75, 0x6e, + 0x7a, 0x69, 0x6f, 0x6e, 0x69, 0x20, 0x54, 0x69, 0x70, 0x6f, 0x67, 0x72, + 0x61, 0x66, 0x69, 0x63, 0x68, 0x65, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, + 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x66, 0x69, 0x73, 0x63, 0x68, + 0x65, 0x20, 0x6b, 0x65, 0x6e, 0x6d, 0x65, 0x72, 0x6b, 0x65, 0x6e, 0x00, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x43, 0x61, 0x73, 0x65, 0x00, + 0x53, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x64, 0x65, 0x73, 0x20, 0x43, 0x68, + 0x69, 0x66, 0x66, 0x72, 0x65, 0x73, 0x00, 0x4e, 0x75, 0x6d, 0x6d, 0x65, + 0x72, 0x68, 0x6f, 0x6f, 0x67, 0x74, 0x65, 0x00, 0x41, 0x6c, 0x6c, 0x20, + 0x54, 0x79, 0x70, 0x65, 0x20, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x00, 0x54, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x20, 0x66, 0x6f, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x79, 0x70, 0x6f, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x69, 0x71, 0x75, 0x65, 0x73, 0x00, 0x41, 0x6c, + 0x6c, 0x65, 0x20, 0x41, 0x75, 0x73, 0x7a, 0x65, 0x69, 0x63, 0x68, 0x6e, + 0x75, 0x6e, 0x67, 0x73, 0x61, 0x72, 0x74, 0x65, 0x6e, 0x00, 0x54, 0x75, + 0x74, 0x74, 0x65, 0x20, 0x6c, 0x65, 0x20, 0x46, 0x75, 0x6e, 0x7a, 0x69, + 0x6f, 0x6e, 0x69, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, + 0x65, 0x6b, 0x65, 0x6e, 0x6d, 0x65, 0x72, 0x6b, 0x65, 0x6e, 0x00, 0x4c, + 0x6f, 0x77, 0x65, 0x72, 0x20, 0x43, 0x61, 0x73, 0x65, 0x20, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00, 0x43, 0x68, 0x69, 0x66, 0x66, 0x72, + 0x65, 0x73, 0x20, 0x41, 0x6e, 0x63, 0x69, 0x65, 0x6e, 0x73, 0x20, 0x28, + 0x62, 0x61, 0x73, 0x20, 0x64, 0x65, 0x20, 0x63, 0x61, 0x73, 0x73, 0x65, + 0x29, 0x00, 0x4d, 0x65, 0x64, 0x69, 0xbe, 0x76, 0x61, 0x6c, 0x2d, 0x5a, + 0x69, 0x66, 0x66, 0x65, 0x72, 0x6e, 0x00, 0x53, 0x6f, 0x70, 0x72, 0x61, + 0x20, 0x6c, 0x61, 0x20, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x20, 0x42, 0x61, + 0x73, 0x65, 0x00, 0x4b, 0x6c, 0x65, 0x69, 0x6e, 0x65, 0x20, 0x6e, 0x75, + 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x00, 0x55, 0x70, 0x70, 0x65, 0x72, 0x20, + 0x43, 0x61, 0x73, 0x65, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x00, 0x43, 0x68, 0x69, 0x66, 0x66, 0x72, 0x65, 0x73, 0x20, 0x43, 0x6f, + 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, 0x73, + 0x20, 0x28, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x61, 0x6e, 0x74, 0x73, 0x29, + 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x65, 0x20, 0x5a, 0x69, 0x66, + 0x66, 0x65, 0x72, 0x6e, 0x00, 0x54, 0x72, 0x61, 0x64, 0x69, 0x7a, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x00, 0x47, 0x72, 0x6f, 0x74, 0x65, 0x20, + 0x6e, 0x75, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x66, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, + 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, + 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, + 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, + 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, + 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, + 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, + 0x00, 0x27, 0x00, 0x28, 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, + 0x00, 0x2d, 0x00, 0x2e, 0x00, 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, + 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, + 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, + 0x00, 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, + 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, + 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, + 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, + 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, + 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x60, 0x00, 0x61, 0x00, 0xac, + 0x00, 0xa3, 0x00, 0x84, 0x00, 0x85, 0x00, 0xbd, 0x00, 0x96, 0x00, 0xe8, + 0x00, 0x86, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x9d, 0x00, 0xa9, 0x00, 0xa4, + 0x01, 0x02, 0x00, 0x8a, 0x01, 0x03, 0x00, 0x83, 0x00, 0x93, 0x00, 0xf2, + 0x00, 0xf3, 0x00, 0x8d, 0x00, 0x97, 0x00, 0x88, 0x00, 0xc3, 0x00, 0xde, + 0x00, 0xf1, 0x00, 0x9e, 0x00, 0xaa, 0x00, 0xf5, 0x00, 0xf4, 0x00, 0xf6, + 0x00, 0xa2, 0x00, 0xad, 0x00, 0xc9, 0x00, 0xc7, 0x00, 0xae, 0x00, 0x62, + 0x00, 0x63, 0x00, 0x90, 0x00, 0x64, 0x00, 0xcb, 0x00, 0x65, 0x00, 0xc8, + 0x00, 0xca, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xe9, + 0x00, 0x66, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xaf, 0x00, 0x67, + 0x00, 0xf0, 0x00, 0x91, 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0x68, + 0x00, 0xeb, 0x00, 0xed, 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x6b, + 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, 0x00, 0x71, + 0x00, 0x70, 0x00, 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, 0x00, 0x76, + 0x00, 0x77, 0x00, 0xea, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x7b, + 0x00, 0x7d, 0x00, 0x7c, 0x00, 0xb8, 0x00, 0xa1, 0x00, 0x7f, 0x00, 0x7e, + 0x00, 0x80, 0x00, 0x81, 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, 0x07, 0x75, + 0x6e, 0x69, 0x30, 0x30, 0x41, 0x44, 0x09, 0x6f, 0x76, 0x65, 0x72, 0x73, + 0x63, 0x6f, 0x72, 0x65, 0x00, 0x01, 0x00, 0x02, 0x00, 0x08, 0x00, 0x0a, + 0xff, 0xff, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x15, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x15, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, + 0xc0, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x03, + 0x00, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xe5, 0x64, 0x3d, 0xfb, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x42, 0x17, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0xe5, 0xf9, 0x0a, 0x7c}; +unsigned int MwBoldTTFDataSize = 36548; +#endif diff --git a/widget/milsko/milskosrc/src/text/font/font.c b/widget/milsko/milskosrc/src/text/font/font.c new file mode 100644 index 0000000000..e1c5d89fb0 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/font/font.c @@ -0,0 +1,264 @@ +#include + +/** + * Copyright notice: + * "Public domain font. Share and enjoy." + */ +MwFont MwFontData[] = { + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0 */ + {0, 12, {0, 0, 12, 12, 30, 30, 63, 63, 30, 30, 12, 12, 0, 0}}, /* 1 */ + {0, 12, {42, 85, 42, 85, 42, 85, 42, 85, 42, 85, 42, 85, 42, 85}}, /* 2 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 3 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 4 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 5 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 6 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 7 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 8 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 9 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 10 */ + {0, 12, {8, 8, 8, 8, 8, 8, 8, 120, 0, 0, 0, 0, 0, 0}}, /* 11 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 120, 8, 8, 8, 8, 8, 8}}, /* 12 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 15, 8, 8, 8, 8, 8, 8}}, /* 13 */ + {0, 12, {8, 8, 8, 8, 8, 8, 8, 15, 0, 0, 0, 0, 0, 0}}, /* 14 */ + {0, 12, {8, 8, 8, 8, 8, 8, 8, 127, 8, 8, 8, 8, 8, 8}}, /* 15 */ + {0, 12, {127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 16 */ + {0, 12, {0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 17 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0}}, /* 18 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0}}, /* 19 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127}}, /* 20 */ + {0, 12, {8, 8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8}}, /* 21 */ + {0, 12, {8, 8, 8, 8, 8, 8, 8, 120, 8, 8, 8, 8, 8, 8}}, /* 22 */ + {0, 12, {8, 8, 8, 8, 8, 8, 8, 127, 0, 0, 0, 0, 0, 0}}, /* 23 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 127, 8, 8, 8, 8, 8, 8}}, /* 24 */ + {0, 12, {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, /* 25 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 26 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 27 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 28 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 29 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 30 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 31 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 32 */ + {0, 12, {0, 0, 8, 8, 8, 8, 8, 8, 8, 0, 8, 8, 0, 0}}, /* 33 */ + {0, 12, {54, 18, 18, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 34 */ + {0, 12, {0, 0, 5, 5, 5, 63, 10, 10, 63, 20, 20, 20, 0, 0}}, /* 35 */ + {0, 12, {0, 0, 4, 30, 37, 37, 20, 14, 5, 37, 37, 30, 4, 0}}, /* 36 */ + {0, 12, {0, 0, 25, 37, 38, 28, 4, 8, 14, 25, 41, 38, 0, 0}}, /* 37 */ + {0, 12, {0, 0, 12, 18, 18, 18, 12, 25, 37, 34, 38, 25, 0, 0}}, /* 38 */ + {0, 12, {24, 8, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 39 */ + {0, 12, {0, 1, 2, 4, 4, 8, 8, 8, 8, 8, 4, 4, 2, 1}}, /* 40 */ + {0, 12, {0, 32, 16, 8, 8, 4, 4, 4, 4, 4, 8, 8, 16, 32}}, /* 41 */ + {0, 12, {0, 0, 0, 4, 21, 14, 4, 4, 14, 21, 4, 0, 0, 0}}, /* 42 */ + {0, 12, {0, 0, 0, 0, 8, 8, 8, 62, 8, 8, 8, 0, 0, 0}}, /* 43 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 8, 8, 16}}, /* 44 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0}}, /* 45 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0}}, /* 46 */ + {0, 12, {0, 1, 1, 2, 2, 4, 4, 4, 8, 8, 16, 16, 32, 32}}, /* 47 */ + {0, 12, {0, 0, 12, 18, 33, 33, 33, 33, 33, 33, 18, 12, 0, 0}}, /* 48 */ + {0, 12, {0, 0, 4, 12, 20, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 49 */ + {0, 12, {0, 0, 30, 33, 33, 1, 2, 2, 4, 8, 16, 63, 0, 0}}, /* 50 */ + {0, 12, {0, 0, 30, 33, 33, 1, 14, 1, 1, 33, 33, 30, 0, 0}}, /* 51 */ + {0, 12, {0, 0, 2, 6, 10, 10, 18, 18, 34, 63, 2, 2, 0, 0}}, /* 52 */ + {0, 12, {0, 0, 63, 32, 32, 62, 33, 1, 1, 33, 33, 30, 0, 0}}, /* 53 */ + {0, 12, {0, 0, 14, 17, 33, 32, 46, 49, 33, 33, 33, 30, 0, 0}}, /* 54 */ + {0, 12, {0, 0, 63, 33, 34, 2, 4, 4, 4, 4, 4, 4, 0, 0}}, /* 55 */ + {0, 12, {0, 0, 30, 33, 33, 18, 12, 18, 33, 33, 33, 30, 0, 0}}, /* 56 */ + {0, 12, {0, 0, 30, 33, 33, 33, 35, 29, 1, 33, 34, 28, 0, 0}}, /* 57 */ + {0, 12, {0, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0}}, /* 58 */ + {0, 12, {0, 0, 0, 0, 8, 8, 0, 0, 0, 24, 8, 8, 16, 0}}, /* 59 */ + {0, 12, {0, 0, 0, 2, 4, 8, 16, 32, 16, 8, 4, 2, 0, 0}}, /* 60 */ + {0, 12, {0, 0, 0, 0, 0, 63, 0, 0, 63, 0, 0, 0, 0, 0}}, /* 61 */ + {0, 12, {0, 0, 0, 32, 16, 8, 4, 2, 4, 8, 16, 32, 0, 0}}, /* 62 */ + {0, 12, {0, 0, 30, 33, 33, 2, 4, 4, 4, 0, 4, 4, 0, 0}}, /* 63 */ + {0, 12, {0, 0, 14, 17, 39, 41, 41, 41, 41, 39, 16, 15, 0, 0}}, /* 64 */ + {0, 12, {0, 0, 8, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 65 */ + {0, 12, {0, 0, 62, 33, 33, 34, 62, 33, 33, 33, 33, 62, 0, 0}}, /* 66 */ + {0, 12, {0, 0, 30, 33, 33, 32, 32, 32, 32, 33, 33, 30, 0, 0}}, /* 67 */ + {0, 12, {0, 0, 60, 34, 33, 33, 33, 33, 33, 33, 34, 60, 0, 0}}, /* 68 */ + {0, 12, {0, 0, 63, 32, 32, 32, 62, 32, 32, 32, 32, 63, 0, 0}}, /* 69 */ + {0, 12, {0, 0, 63, 32, 32, 32, 62, 32, 32, 32, 32, 32, 0, 0}}, /* 70 */ + {0, 12, {0, 0, 30, 33, 33, 32, 32, 39, 33, 33, 33, 30, 0, 0}}, /* 71 */ + {0, 12, {0, 0, 33, 33, 33, 33, 63, 33, 33, 33, 33, 33, 0, 0}}, /* 72 */ + {0, 12, {0, 0, 31, 4, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 73 */ + {0, 12, {0, 0, 1, 1, 1, 1, 1, 1, 1, 33, 34, 28, 0, 0}}, /* 74 */ + {0, 12, {0, 0, 33, 34, 36, 40, 56, 36, 36, 34, 33, 33, 0, 0}}, /* 75 */ + {0, 12, {0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 63, 0, 0}}, /* 76 */ + {0, 12, {0, 0, 33, 35, 51, 53, 45, 41, 41, 33, 33, 33, 0, 0}}, /* 77 */ + {0, 12, {0, 0, 49, 49, 41, 41, 41, 37, 37, 37, 35, 35, 0, 0}}, /* 78 */ + {0, 12, {0, 0, 30, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 79 */ + {0, 12, {0, 0, 62, 33, 33, 33, 33, 62, 32, 32, 32, 32, 0, 0}}, /* 80 */ + {0, 12, {0, 0, 30, 33, 33, 33, 33, 33, 57, 37, 35, 30, 2, 1}}, /* 81 */ + {0, 12, {0, 0, 62, 33, 33, 33, 62, 34, 33, 33, 33, 33, 0, 0}}, /* 82 */ + {0, 12, {0, 0, 30, 33, 33, 16, 8, 4, 2, 33, 33, 30, 0, 0}}, /* 83 */ + {0, 12, {0, 0, 63, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 84 */ + {0, 12, {0, 0, 33, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 85 */ + {0, 12, {0, 0, 33, 33, 33, 34, 18, 18, 20, 12, 8, 8, 0, 0}}, /* 86 */ + {0, 12, {0, 0, 37, 37, 37, 37, 37, 63, 18, 18, 18, 18, 0, 0}}, /* 87 */ + {0, 12, {0, 0, 33, 33, 18, 18, 12, 12, 18, 18, 33, 33, 0, 0}}, /* 88 */ + {0, 12, {0, 0, 33, 33, 34, 18, 20, 12, 8, 8, 8, 8, 0, 0}}, /* 89 */ + {0, 12, {0, 0, 63, 1, 2, 4, 4, 8, 16, 16, 32, 63, 0, 0}}, /* 90 */ + {0, 12, {0, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 15}}, /* 91 */ + {0, 12, {0, 32, 32, 16, 16, 8, 8, 8, 4, 4, 2, 2, 1, 1}}, /* 92 */ + {0, 12, {0, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 60}}, /* 93 */ + {0, 12, {12, 18, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 94 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63}}, /* 95 */ + {0, 12, {6, 4, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 96 */ + {0, 12, {0, 0, 0, 0, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 97 */ + {0, 12, {0, 0, 32, 32, 32, 46, 49, 33, 33, 33, 49, 46, 0, 0}}, /* 98 */ + {0, 12, {0, 0, 0, 0, 0, 30, 33, 32, 32, 32, 33, 30, 0, 0}}, /* 99 */ + {0, 12, {0, 0, 1, 1, 1, 29, 35, 33, 33, 33, 35, 29, 0, 0}}, /* 100 */ + {0, 12, {0, 0, 0, 0, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 101 */ + {0, 12, {0, 0, 6, 9, 8, 8, 62, 8, 8, 8, 8, 8, 0, 0}}, /* 102 */ + {0, 12, {0, 0, 0, 0, 0, 29, 34, 34, 34, 28, 16, 46, 33, 30}}, /* 103 */ + {0, 12, {0, 0, 32, 32, 32, 46, 49, 33, 33, 33, 33, 33, 0, 0}}, /* 104 */ + {0, 12, {0, 0, 8, 8, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 105 */ + {0, 12, {0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 34, 28}}, /* 106 */ + {0, 12, {0, 0, 32, 32, 32, 34, 36, 40, 56, 36, 34, 33, 0, 0}}, /* 107 */ + {0, 12, {0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 108 */ + {0, 12, {0, 0, 0, 0, 0, 62, 41, 41, 41, 41, 41, 41, 0, 0}}, /* 109 */ + {0, 12, {0, 0, 0, 0, 0, 46, 49, 33, 33, 33, 33, 33, 0, 0}}, /* 110 */ + {0, 12, {0, 0, 0, 0, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 111 */ + {0, 12, {0, 0, 0, 0, 0, 46, 49, 33, 33, 33, 49, 46, 32, 32}}, /* 112 */ + {0, 12, {0, 0, 0, 0, 0, 29, 35, 33, 33, 33, 35, 29, 1, 1}}, /* 113 */ + {0, 12, {0, 0, 0, 0, 0, 46, 49, 33, 32, 32, 32, 32, 0, 0}}, /* 114 */ + {0, 12, {0, 0, 0, 0, 0, 30, 33, 16, 12, 2, 33, 30, 0, 0}}, /* 115 */ + {0, 12, {0, 0, 8, 8, 8, 63, 8, 8, 8, 8, 8, 7, 0, 0}}, /* 116 */ + {0, 12, {0, 0, 0, 0, 0, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 117 */ + {0, 12, {0, 0, 0, 0, 0, 33, 33, 17, 18, 10, 12, 4, 0, 0}}, /* 118 */ + {0, 12, {0, 0, 0, 0, 0, 37, 37, 37, 63, 18, 18, 18, 0, 0}}, /* 119 */ + {0, 12, {0, 0, 0, 0, 0, 33, 33, 18, 12, 18, 33, 33, 0, 0}}, /* 120 */ + {0, 12, {0, 0, 0, 0, 0, 33, 33, 17, 18, 10, 14, 4, 36, 24}}, /* 121 */ + {0, 12, {0, 0, 0, 0, 0, 63, 2, 4, 8, 8, 16, 63, 0, 0}}, /* 122 */ + {0, 12, {0, 3, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 3}}, /* 123 */ + {0, 12, {0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}}, /* 124 */ + {0, 12, {0, 48, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 48}}, /* 125 */ + {0, 12, {0, 16, 41, 37, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 126 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 127 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 128 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 129 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 130 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 131 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 132 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 133 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 134 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 135 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 136 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 137 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 138 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 139 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 140 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 141 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 142 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 143 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 144 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 145 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 146 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 147 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 148 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 149 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 150 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 151 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 152 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 153 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 154 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 155 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 156 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 157 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 158 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 159 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 160 */ + {0, 12, {0, 0, 8, 8, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 161 */ + {0, 12, {0, 0, 0, 0, 8, 31, 41, 40, 40, 40, 41, 31, 8, 0}}, /* 162 */ + {0, 12, {0, 0, 0, 12, 18, 16, 16, 60, 16, 16, 60, 18, 0, 0}}, /* 163 */ + {0, 12, {0, 0, 0, 0, 33, 30, 18, 18, 30, 33, 0, 0, 0, 0}}, /* 164 */ + {0, 12, {0, 0, 33, 18, 12, 63, 4, 4, 63, 4, 4, 4, 0, 0}}, /* 165 */ + {0, 12, {0, 0, 8, 8, 8, 8, 0, 0, 8, 8, 8, 8, 0, 0}}, /* 166 */ + {0, 12, {0, 30, 33, 16, 12, 18, 33, 18, 12, 2, 33, 30, 0, 0}}, /* 167 */ + {0, 12, {0, 36, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 168 */ + {0, 12, {0, 30, 33, 45, 51, 49, 49, 49, 51, 45, 33, 30, 0, 0}}, /* 169 */ + {0, 12, {0, 14, 17, 15, 17, 19, 13, 0, 31, 0, 0, 0, 0, 0}}, /* 170 */ + {0, 12, {0, 0, 0, 0, 0, 5, 10, 20, 40, 20, 10, 5, 0, 0}}, /* 171 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 124, 4, 4, 4, 0, 0}}, /* 172 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0}}, /* 173 */ + {0, 12, {0, 30, 33, 61, 51, 51, 61, 51, 51, 51, 33, 30, 0, 0}}, /* 174 */ + {0, 12, {0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 175 */ + {0, 12, {0, 24, 36, 36, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 176 */ + {0, 12, {0, 0, 0, 0, 0, 0, 8, 8, 62, 8, 8, 62, 0, 0}}, /* 177 */ + {0, 12, {0, 24, 36, 4, 8, 16, 32, 60, 0, 0, 0, 0, 0, 0}}, /* 178 */ + {0, 12, {0, 24, 36, 4, 24, 4, 36, 24, 0, 0, 0, 0, 0, 0}}, /* 179 */ + {0, 12, {0, 4, 8, 16, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 180 */ + {0, 12, {0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 54, 42, 32, 32}}, /* 181 */ + {0, 12, {0, 0, 30, 42, 42, 42, 42, 26, 10, 10, 10, 10, 10, 14}}, /* 182 */ + {0, 12, {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0}}, /* 183 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 16}}, /* 184 */ + {0, 12, {0, 0, 16, 48, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0}}, /* 185 */ + {0, 12, {0, 0, 12, 18, 18, 12, 0, 30, 0, 0, 0, 0, 0, 0}}, /* 186 */ + {0, 12, {0, 0, 0, 0, 0, 40, 20, 10, 5, 10, 20, 40, 0, 0}}, /* 187 */ + {0, 12, {0, 0, 16, 49, 18, 18, 20, 9, 11, 21, 39, 33, 0, 0}}, /* 188 */ + {0, 12, {0, 0, 16, 49, 18, 18, 20, 10, 13, 17, 34, 39, 0, 0}}, /* 189 */ + {0, 12, {0, 0, 49, 9, 18, 12, 52, 9, 19, 21, 39, 1, 0, 0}}, /* 190 */ + {0, 12, {0, 0, 0, 4, 4, 0, 4, 4, 4, 4, 2, 33, 33, 30}}, /* 191 */ + {0, 12, {16, 12, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 192 */ + {0, 12, {2, 12, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 193 */ + {0, 12, {12, 18, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 194 */ + {0, 12, {10, 20, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 195 */ + {0, 12, {0, 18, 0, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 196 */ + {0, 12, {8, 0, 8, 12, 20, 18, 34, 33, 63, 33, 33, 33, 0, 0}}, /* 197 */ + {0, 12, {0, 0, 31, 40, 40, 40, 78, 120, 72, 72, 72, 79, 0, 0}}, /* 198 */ + {0, 12, {0, 0, 30, 33, 33, 32, 32, 32, 32, 33, 33, 30, 4, 8}}, /* 199 */ + {0, 12, {16, 12, 0, 63, 32, 32, 32, 62, 32, 32, 32, 63, 0, 0}}, /* 200 */ + {0, 12, {2, 12, 0, 63, 32, 32, 32, 62, 32, 32, 32, 63, 0, 0}}, /* 201 */ + {0, 12, {12, 18, 0, 63, 32, 32, 32, 62, 32, 32, 32, 63, 0, 0}}, /* 202 */ + {0, 12, {0, 18, 0, 63, 32, 32, 32, 62, 32, 32, 32, 63, 0, 0}}, /* 203 */ + {0, 12, {8, 6, 0, 31, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 204 */ + {0, 12, {2, 12, 0, 31, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 205 */ + {0, 12, {4, 10, 0, 31, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 206 */ + {0, 12, {0, 10, 0, 31, 4, 4, 4, 4, 4, 4, 4, 31, 0, 0}}, /* 207 */ + {0, 12, {0, 0, 60, 34, 33, 33, 113, 33, 33, 33, 34, 60, 0, 0}}, /* 208 */ + {0, 12, {10, 20, 0, 49, 41, 41, 41, 37, 37, 37, 35, 35, 0, 0}}, /* 209 */ + {0, 12, {16, 12, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 210 */ + {0, 12, {2, 12, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 211 */ + {0, 12, {12, 18, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 212 */ + {0, 12, {10, 20, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 213 */ + {0, 12, {0, 18, 0, 30, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 214 */ + {0, 12, {0, 0, 0, 0, 0, 65, 34, 20, 8, 20, 34, 65, 0, 0}}, /* 215 */ + {0, 12, {1, 1, 30, 35, 37, 37, 37, 41, 41, 41, 49, 30, 32, 32}}, /* 216 */ + {0, 12, {16, 12, 0, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 217 */ + {0, 12, {2, 12, 0, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 218 */ + {0, 12, {12, 18, 0, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 219 */ + {0, 12, {0, 18, 0, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 220 */ + {0, 12, {2, 12, 33, 33, 34, 18, 20, 12, 8, 8, 8, 8, 0, 0}}, /* 221 */ + {0, 12, {0, 0, 32, 32, 62, 33, 33, 33, 33, 62, 32, 32, 0, 0}}, /* 222 */ + {0, 12, {0, 0, 12, 18, 18, 18, 28, 18, 17, 17, 17, 62, 0, 0}}, /* 223 */ + {0, 12, {0, 16, 8, 4, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 224 */ + {0, 12, {0, 2, 4, 8, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 225 */ + {0, 12, {0, 0, 12, 18, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 226 */ + {0, 12, {0, 0, 10, 20, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 227 */ + {0, 12, {0, 0, 0, 18, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 228 */ + {0, 12, {0, 8, 20, 8, 0, 30, 33, 7, 25, 33, 35, 29, 0, 0}}, /* 229 */ + {0, 12, {0, 0, 0, 0, 0, 62, 73, 25, 47, 72, 73, 62, 0, 0}}, /* 230 */ + {0, 12, {0, 0, 0, 0, 0, 30, 33, 32, 32, 32, 33, 30, 4, 8}}, /* 231 */ + {0, 12, {0, 16, 8, 4, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 232 */ + {0, 12, {0, 2, 4, 8, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 233 */ + {0, 12, {0, 0, 12, 18, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 234 */ + {0, 12, {0, 0, 0, 18, 0, 30, 33, 33, 63, 32, 33, 30, 0, 0}}, /* 235 */ + {0, 12, {0, 16, 8, 4, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 236 */ + {0, 12, {0, 4, 8, 16, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 237 */ + {0, 12, {0, 0, 8, 20, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 238 */ + {0, 12, {0, 0, 0, 20, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0}}, /* 239 */ + {0, 12, {0, 20, 8, 20, 2, 30, 34, 34, 34, 34, 34, 28, 0, 0}}, /* 240 */ + {0, 12, {0, 0, 10, 20, 0, 46, 49, 33, 33, 33, 33, 33, 0, 0}}, /* 241 */ + {0, 12, {0, 16, 8, 4, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 242 */ + {0, 12, {0, 2, 4, 8, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 243 */ + {0, 12, {0, 0, 12, 18, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 244 */ + {0, 12, {0, 0, 10, 20, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 245 */ + {0, 12, {0, 0, 0, 18, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0}}, /* 246 */ + {0, 12, {0, 0, 0, 0, 0, 0, 0, 24, 0, 126, 0, 24, 0, 0}}, /* 247 */ + {0, 12, {0, 0, 0, 1, 2, 30, 37, 37, 41, 41, 49, 30, 32, 32}}, /* 248 */ + {0, 12, {0, 0, 16, 8, 4, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 249 */ + {0, 12, {0, 0, 2, 4, 8, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 250 */ + {0, 12, {0, 0, 12, 18, 0, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 251 */ + {0, 12, {0, 0, 0, 18, 0, 33, 33, 33, 33, 33, 35, 29, 0, 0}}, /* 252 */ + {0, 12, {0, 0, 2, 4, 8, 33, 33, 17, 18, 10, 14, 4, 36, 24}}, /* 253 */ + {0, 12, {0, 0, 32, 32, 32, 46, 49, 33, 33, 33, 49, 46, 32, 32}}, /* 254 */ + {0, 12, {0, 0, 0, 18, 0, 33, 33, 17, 18, 10, 14, 4, 36, 24}} /* 255 */ +}; diff --git a/widget/milsko/milskosrc/src/text/font/monottf.c b/widget/milsko/milskosrc/src/text/font/monottf.c new file mode 100644 index 0000000000..7a89f94391 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/font/monottf.c @@ -0,0 +1,3022 @@ +#include + +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) +unsigned char MwMonospaceTTFData[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x04, 0x00, 0x10, + 0x46, 0x46, 0x54, 0x4d, 0xac, 0x0d, 0xe4, 0x23, 0x00, 0x00, 0x8d, 0x3c, + 0x00, 0x00, 0x00, 0x1c, 0x4f, 0x53, 0x2f, 0x32, 0xa3, 0xba, 0xa8, 0x6a, + 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70, + 0x0a, 0x08, 0xe7, 0x8a, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x01, 0x5a, + 0x63, 0x76, 0x74, 0x20, 0x02, 0xeb, 0x10, 0xb0, 0x00, 0x00, 0x09, 0x08, + 0x00, 0x00, 0x00, 0x46, 0x66, 0x65, 0x61, 0x74, 0x40, 0x36, 0x0d, 0x66, + 0x00, 0x00, 0x8a, 0xd8, 0x00, 0x00, 0x00, 0x5c, 0x66, 0x70, 0x67, 0x6d, + 0x06, 0x59, 0x9c, 0x37, 0x00, 0x00, 0x05, 0xbc, 0x00, 0x00, 0x01, 0x73, + 0x67, 0x61, 0x73, 0x70, 0x00, 0x18, 0x00, 0x23, 0x00, 0x00, 0x8a, 0xc8, + 0x00, 0x00, 0x00, 0x10, 0x67, 0x6c, 0x79, 0x66, 0x52, 0xd9, 0xef, 0x7c, + 0x00, 0x00, 0x0a, 0xd8, 0x00, 0x00, 0x6d, 0x74, 0x68, 0x65, 0x61, 0x64, + 0x28, 0x83, 0x41, 0x9e, 0x00, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x00, 0x36, + 0x68, 0x68, 0x65, 0x61, 0x06, 0x5b, 0x03, 0x47, 0x00, 0x00, 0x01, 0x54, + 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 0x12, 0xa2, 0x30, 0xf9, + 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x02, 0x66, 0x6c, 0x6f, 0x63, 0x61, + 0xe2, 0xac, 0xc8, 0x8e, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x01, 0x86, + 0x6d, 0x61, 0x78, 0x70, 0x02, 0xd9, 0x01, 0x90, 0x00, 0x00, 0x01, 0x78, + 0x00, 0x00, 0x00, 0x20, 0x6d, 0x6f, 0x72, 0x78, 0x02, 0x7c, 0xa9, 0x72, + 0x00, 0x00, 0x8b, 0x34, 0x00, 0x00, 0x02, 0x08, 0x6e, 0x61, 0x6d, 0x65, + 0x11, 0x8f, 0xe7, 0xf9, 0x00, 0x00, 0x78, 0x4c, 0x00, 0x00, 0x10, 0xbb, + 0x70, 0x6f, 0x73, 0x74, 0x26, 0x3a, 0xd0, 0xac, 0x00, 0x00, 0x89, 0x08, + 0x00, 0x00, 0x01, 0xbe, 0x70, 0x72, 0x65, 0x70, 0xd4, 0xb6, 0xaf, 0x59, + 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x06, 0x91, 0x31, 0xff, 0xb3, 0x5f, 0x0f, 0x3c, 0xf5, + 0x00, 0x1f, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xe1, 0xa9, 0xde, 0x41, + 0x00, 0x00, 0x00, 0x00, 0xe5, 0x4d, 0x1e, 0x76, 0x00, 0x00, 0xff, 0x2c, + 0x02, 0x58, 0x03, 0xd0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, 0xfe, 0xed, + 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x71, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x55, + 0x00, 0x06, 0x00, 0x4c, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00, 0xed, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x04, 0x02, 0x58, 0x01, 0x90, 0x00, 0x05, 0x00, 0x00, 0x02, 0x8a, + 0x02, 0x58, 0x00, 0x00, 0x00, 0x4b, 0x02, 0x8a, 0x02, 0x58, 0x00, 0x00, + 0x01, 0x5e, 0x00, 0x3c, 0x01, 0x35, 0x08, 0x09, 0x02, 0x0b, 0x05, 0x09, + 0x05, 0x02, 0x03, 0x00, 0x02, 0x03, 0xa0, 0x00, 0x02, 0x6f, 0x40, 0x00, + 0x38, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x42, + 0x4d, 0x20, 0x01, 0x40, 0x00, 0x00, 0x00, 0xff, 0x03, 0x0c, 0xff, 0x24, + 0x01, 0x2c, 0x04, 0x01, 0x01, 0x13, 0x60, 0x00, 0x01, 0x97, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x04, 0x02, 0xba, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, + 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, + 0x02, 0x58, 0x00, 0x00, 0x02, 0x58, 0x00, 0xe2, 0x02, 0x58, 0x00, 0xae, + 0x02, 0x58, 0x00, 0x10, 0x02, 0x58, 0x00, 0x32, 0x02, 0x58, 0x00, 0x12, + 0x02, 0x58, 0x00, 0x19, 0x02, 0x58, 0x01, 0x06, 0x02, 0x58, 0x00, 0xcd, + 0x02, 0x58, 0x00, 0x6a, 0x02, 0x58, 0x00, 0x2b, 0x02, 0x58, 0x00, 0x3e, + 0x02, 0x58, 0x00, 0xcc, 0x02, 0x58, 0x00, 0x9b, 0x02, 0x58, 0x00, 0xe2, + 0x02, 0x58, 0x00, 0x5a, 0x02, 0x58, 0x00, 0x38, 0x02, 0x58, 0x00, 0x35, + 0x02, 0x58, 0x00, 0x41, 0x02, 0x58, 0x00, 0x30, 0x02, 0x58, 0x00, 0x22, + 0x02, 0x58, 0x00, 0x49, 0x02, 0x58, 0x00, 0x40, 0x02, 0x58, 0x00, 0x41, + 0x02, 0x58, 0x00, 0x37, 0x02, 0x58, 0x00, 0x40, 0x02, 0x58, 0x00, 0xe2, + 0x02, 0x58, 0x00, 0xcc, 0x02, 0x58, 0x00, 0x55, 0x02, 0x58, 0x00, 0x3e, + 0x02, 0x58, 0x00, 0x55, 0x02, 0x58, 0x00, 0x4d, 0x02, 0x58, 0x00, 0x3e, + 0x02, 0x58, 0x00, 0x1f, 0x02, 0x58, 0x00, 0x58, 0x02, 0x58, 0x00, 0x46, + 0x02, 0x58, 0x00, 0x5f, 0x02, 0x58, 0x00, 0x5a, 0x02, 0x58, 0x00, 0x5a, + 0x02, 0x58, 0x00, 0x38, 0x02, 0x58, 0x00, 0x50, 0x02, 0x58, 0x00, 0x54, + 0x02, 0x58, 0x00, 0x4a, 0x02, 0x58, 0x00, 0x55, 0x02, 0x58, 0x00, 0x78, + 0x02, 0x58, 0x00, 0x44, 0x02, 0x58, 0x00, 0x50, 0x02, 0x58, 0x00, 0x38, + 0x02, 0x58, 0x00, 0x5a, 0x02, 0x58, 0x00, 0x38, 0x02, 0x58, 0x00, 0x5a, + 0x02, 0x58, 0x00, 0x2d, 0x02, 0x58, 0x00, 0x19, 0x02, 0x58, 0x00, 0x50, + 0x02, 0x58, 0x00, 0x24, 0x02, 0x58, 0x00, 0x23, 0x02, 0x58, 0x00, 0x1a, + 0x02, 0x58, 0x00, 0x11, 0x02, 0x58, 0x00, 0x30, 0x02, 0x58, 0x00, 0xe1, + 0x02, 0x58, 0x00, 0x5a, 0x02, 0x58, 0x00, 0x5f, 0x02, 0x58, 0x00, 0x2d, + 0x02, 0x58, 0x00, 0x3c, 0x02, 0x58, 0x00, 0xbb, 0x02, 0x58, 0x00, 0x42, + 0x02, 0x58, 0x00, 0x5f, 0x02, 0x58, 0x00, 0x54, 0x02, 0x58, 0x00, 0x3c, + 0x02, 0x58, 0x00, 0x43, 0x02, 0x58, 0x00, 0x49, 0x02, 0x58, 0x00, 0x43, + 0x02, 0x58, 0x00, 0x62, 0x02, 0x58, 0x00, 0x6a, 0x02, 0x58, 0x00, 0x5d, + 0x02, 0x58, 0x00, 0x69, 0x02, 0x58, 0x00, 0x50, 0x02, 0x58, 0x00, 0x36, + 0x02, 0x58, 0x00, 0x62, 0x02, 0x58, 0x00, 0x42, 0x02, 0x58, 0x00, 0x5f, + 0x02, 0x58, 0x00, 0x3c, 0x02, 0x58, 0x00, 0x4d, 0x02, 0x58, 0x00, 0x43, + 0x02, 0x58, 0x00, 0x27, 0x02, 0x58, 0x00, 0x5c, 0x02, 0x58, 0x00, 0x40, + 0x02, 0x58, 0x00, 0x1e, 0x02, 0x58, 0x00, 0x3d, 0x02, 0x58, 0x00, 0x35, + 0x02, 0x58, 0x00, 0x55, 0x02, 0x58, 0x00, 0x69, 0x02, 0x58, 0x01, 0x09, + 0x02, 0x58, 0x00, 0x69, 0x02, 0x58, 0x00, 0x34, 0x02, 0x58, 0x00, 0x00, + 0x02, 0x58, 0x00, 0xe2, 0x02, 0x58, 0x00, 0x54, 0x02, 0x58, 0x00, 0x34, + 0x02, 0x58, 0x00, 0x4c, 0x02, 0x58, 0x00, 0x16, 0x02, 0x58, 0x01, 0x09, + 0x02, 0x58, 0x00, 0x51, 0x02, 0x58, 0x00, 0x96, 0x02, 0x58, 0x00, 0x00, + 0x02, 0x58, 0x00, 0x8a, 0x02, 0x58, 0x00, 0x4a, 0x02, 0x58, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, 0x00, 0x75, 0x00, 0xa0, 0x00, 0x81, + 0x00, 0x3e, 0x00, 0xa1, 0x00, 0x97, 0x00, 0xff, 0x00, 0x62, 0x00, 0x2d, + 0x00, 0xe2, 0x00, 0xd5, 0x00, 0x9a, 0x00, 0x8c, 0x00, 0x43, 0x00, 0x12, + 0x00, 0x12, 0x00, 0x12, 0x00, 0x5a, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, + 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x46, 0x00, 0x5a, + 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x54, 0x00, 0x54, 0x00, 0x54, + 0x00, 0x54, 0x00, 0x16, 0x00, 0x50, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, + 0x00, 0x38, 0x00, 0x38, 0x00, 0x58, 0x00, 0x2f, 0x00, 0x50, 0x00, 0x50, + 0x00, 0x50, 0x00, 0x50, 0x00, 0x11, 0x00, 0x5a, 0x00, 0x66, 0x00, 0x42, + 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x0a, + 0x00, 0x54, 0x00, 0x43, 0x00, 0x43, 0x00, 0x43, 0x00, 0x43, 0x00, 0x6a, + 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x42, 0x00, 0x62, 0x00, 0x42, + 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x2f, + 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x35, 0x00, 0x5f, + 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, + 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x7e, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x20, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf5, + 0xff, 0xe3, 0xff, 0xc2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, + 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x00, 0x86, 0x87, 0x89, 0x8b, 0x93, 0x98, + 0x9e, 0xa3, 0xa2, 0xa4, 0xa6, 0xa5, 0xa7, 0xa9, 0xab, 0xaa, 0xac, 0xad, + 0xaf, 0xae, 0xb0, 0xb1, 0xb3, 0xb5, 0xb4, 0xb6, 0xb8, 0xb7, 0xbc, 0xbb, + 0xbd, 0xbe, 0x00, 0x72, 0x64, 0x65, 0x69, 0x00, 0x78, 0xa1, 0x70, 0x6b, + 0x00, 0x76, 0x6a, 0x00, 0x88, 0x9a, 0x00, 0x73, 0x00, 0x00, 0x67, 0x77, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x00, 0xa8, 0xba, 0x81, 0x63, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x7d, 0x00, 0x62, 0x82, 0x85, 0x97, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, 0xc1, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x84, + 0x8c, 0x83, 0x8d, 0x8a, 0x8f, 0x90, 0x91, 0x8e, 0x95, 0x96, 0x00, 0x94, + 0x9c, 0x9d, 0x9b, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x2c, 0x4b, 0xb8, 0x00, 0x09, + 0x50, 0x58, 0xb1, 0x01, 0x01, 0x8e, 0x59, 0xb8, 0x01, 0xff, 0x85, 0xb8, + 0x00, 0x44, 0x1d, 0xb9, 0x00, 0x09, 0x00, 0x03, 0x5f, 0x5e, 0x2d, 0xb8, + 0x00, 0x01, 0x2c, 0x20, 0x20, 0x45, 0x69, 0x44, 0xb0, 0x01, 0x60, 0x2d, + 0xb8, 0x00, 0x02, 0x2c, 0xb8, 0x00, 0x01, 0x2a, 0x21, 0x2d, 0xb8, 0x00, + 0x03, 0x2c, 0x20, 0x46, 0xb0, 0x03, 0x25, 0x46, 0x52, 0x58, 0x23, 0x59, + 0x20, 0x8a, 0x20, 0x8a, 0x49, 0x64, 0x8a, 0x20, 0x46, 0x20, 0x68, 0x61, + 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, 0x68, 0x61, 0x64, 0x52, 0x58, 0x23, + 0x65, 0x8a, 0x59, 0x2f, 0x20, 0xb0, 0x00, 0x53, 0x58, 0x69, 0x20, 0xb0, + 0x00, 0x54, 0x58, 0x21, 0xb0, 0x40, 0x59, 0x1b, 0x69, 0x20, 0xb0, 0x00, + 0x54, 0x58, 0x21, 0xb0, 0x40, 0x65, 0x59, 0x59, 0x3a, 0x2d, 0xb8, 0x00, + 0x04, 0x2c, 0x20, 0x46, 0xb0, 0x04, 0x25, 0x46, 0x52, 0x58, 0x23, 0x8a, + 0x59, 0x20, 0x46, 0x20, 0x6a, 0x61, 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, + 0x6a, 0x61, 0x64, 0x52, 0x58, 0x23, 0x8a, 0x59, 0x2f, 0xfd, 0x2d, 0xb8, + 0x00, 0x05, 0x2c, 0x4b, 0x20, 0xb0, 0x03, 0x26, 0x50, 0x58, 0x51, 0x58, + 0xb0, 0x80, 0x44, 0x1b, 0xb0, 0x40, 0x44, 0x59, 0x1b, 0x21, 0x21, 0x20, + 0x45, 0xb0, 0xc0, 0x50, 0x58, 0xb0, 0xc0, 0x44, 0x1b, 0x21, 0x59, 0x59, + 0x2d, 0xb8, 0x00, 0x06, 0x2c, 0x20, 0x20, 0x45, 0x69, 0x44, 0xb0, 0x01, + 0x60, 0x20, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0xb0, 0x01, 0x60, 0x2d, + 0xb8, 0x00, 0x07, 0x2c, 0xb8, 0x00, 0x06, 0x2a, 0x2d, 0xb8, 0x00, 0x08, + 0x2c, 0x4b, 0x20, 0xb0, 0x03, 0x26, 0x53, 0x58, 0xb0, 0x40, 0x1b, 0xb0, + 0x00, 0x59, 0x8a, 0x8a, 0x20, 0xb0, 0x03, 0x26, 0x53, 0x58, 0x23, 0x21, + 0xb0, 0x80, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03, 0x26, + 0x53, 0x58, 0x23, 0x21, 0xb8, 0x00, 0xc0, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, + 0x59, 0x20, 0xb0, 0x03, 0x26, 0x53, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x00, + 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03, 0x26, 0x53, 0x58, + 0x23, 0x21, 0xb8, 0x01, 0x40, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, + 0xb8, 0x00, 0x03, 0x26, 0x53, 0x58, 0xb0, 0x03, 0x25, 0x45, 0xb8, 0x01, + 0x80, 0x50, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x80, 0x23, 0x21, 0x1b, 0xb0, + 0x03, 0x25, 0x45, 0x23, 0x21, 0x23, 0x21, 0x59, 0x1b, 0x21, 0x59, 0x44, + 0x2d, 0xb8, 0x00, 0x09, 0x2c, 0x4b, 0x53, 0x58, 0x45, 0x44, 0x1b, 0x21, + 0x21, 0x59, 0x2d, 0x00, 0xb8, 0x00, 0x00, 0x2b, 0x00, 0xba, 0x00, 0x01, + 0x00, 0x0c, 0x00, 0x02, 0x2b, 0x01, 0xba, 0x00, 0x0d, 0x00, 0x02, 0x00, + 0x02, 0x2b, 0x01, 0xbf, 0x00, 0x0d, 0x00, 0x44, 0x00, 0x37, 0x00, 0x2b, + 0x00, 0x1f, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x0e, + 0x00, 0x40, 0x00, 0x35, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x08, 0x2b, 0x00, 0xbf, 0x00, 0x01, 0x00, 0x5c, 0x00, 0x4b, 0x00, + 0x3b, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x02, 0x00, 0x51, 0x00, 0x43, 0x00, 0x34, 0x00, 0x26, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x03, 0x00, 0x68, 0x00, 0x55, 0x00, + 0x43, 0x00, 0x2c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x04, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x20, 0x00, 0x14, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x05, 0x00, 0x50, 0x00, 0x42, 0x00, + 0x33, 0x00, 0x25, 0x00, 0x16, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x06, 0x00, 0x2f, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x17, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x07, 0x00, 0x31, 0x00, 0x26, 0x00, + 0x23, 0x00, 0x15, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x08, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x09, 0x00, 0x2a, 0x00, 0x22, 0x00, + 0x1a, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x0a, 0x00, 0x91, 0x00, 0x77, 0x00, 0x5d, 0x00, 0x42, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, 0x0b, 0x00, 0x4b, 0x00, 0x3e, 0x00, + 0x30, 0x00, 0x24, 0x00, 0x16, 0x00, 0x00, 0x00, 0x08, 0x2b, 0xbf, 0x00, + 0x0c, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x08, 0x2b, 0x00, 0xba, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x07, + 0x2b, 0xb8, 0x00, 0x00, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0xba, 0x00, + 0x40, 0x00, 0x13, 0x00, 0x01, 0x75, 0xba, 0x00, 0x10, 0x00, 0x13, 0x00, + 0x01, 0x74, 0xba, 0x00, 0x3f, 0x00, 0x13, 0x00, 0x01, 0x74, 0xba, 0x00, + 0x40, 0x00, 0x13, 0x00, 0x01, 0x74, 0xba, 0x00, 0x70, 0x00, 0x13, 0x00, + 0x01, 0x74, 0xba, 0x00, 0xa0, 0x00, 0x13, 0x00, 0x01, 0x74, 0xba, 0x00, + 0x10, 0x00, 0x13, 0x00, 0x01, 0x75, 0xba, 0x00, 0x3f, 0x00, 0x13, 0x00, + 0x01, 0x75, 0xba, 0x00, 0x40, 0x00, 0x15, 0x00, 0x01, 0x74, 0xba, 0x00, + 0x3f, 0x00, 0x15, 0x00, 0x01, 0x74, 0xba, 0x00, 0x9f, 0x00, 0x15, 0x00, + 0x01, 0x74, 0xba, 0x00, 0xa0, 0x00, 0x15, 0x00, 0x01, 0x74, 0xba, 0x00, + 0xcf, 0x00, 0x15, 0x00, 0x01, 0x74, 0xba, 0x00, 0x70, 0x00, 0x15, 0x00, + 0x01, 0x74, 0xba, 0x00, 0x6f, 0x00, 0x17, 0x00, 0x01, 0x74, 0xba, 0x00, + 0x60, 0x00, 0x19, 0x00, 0x01, 0x73, 0xba, 0x00, 0x6f, 0x00, 0x19, 0x00, + 0x01, 0x74, 0xba, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x01, 0x75, 0xba, 0x00, + 0x6f, 0x00, 0x19, 0x00, 0x01, 0x75, 0xba, 0x00, 0x9f, 0x00, 0x19, 0x00, + 0x01, 0x75, 0xba, 0x00, 0x70, 0x00, 0x21, 0x00, 0x01, 0x73, 0xba, 0x00, + 0xcf, 0x00, 0x21, 0x00, 0x01, 0x73, 0x00, 0x00, 0x00, 0x17, 0x00, 0x3c, + 0x00, 0x44, 0x00, 0x35, 0x00, 0x5a, 0x00, 0x42, 0x00, 0x76, 0x00, 0x72, + 0x00, 0x45, 0x00, 0x8a, 0x00, 0x26, 0x00, 0x49, 0x00, 0x9e, 0x00, 0x52, + 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0xff, 0x38, 0x00, 0x0c, 0x01, 0x49, + 0x00, 0x06, 0x01, 0x6b, 0x00, 0x06, 0x01, 0x4f, 0x00, 0x06, 0x01, 0x71, + 0x00, 0x06, 0x02, 0x04, 0x00, 0x0c, 0x02, 0xba, 0x00, 0x0c, 0x02, 0xe4, + 0x00, 0x0c, 0x02, 0x18, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x50, 0x00, 0xc4, + 0x01, 0x6c, 0x02, 0x20, 0x02, 0xda, 0x02, 0xf8, 0x03, 0x28, 0x03, 0x58, + 0x03, 0x7e, 0x03, 0xa6, 0x03, 0xbe, 0x03, 0xd6, 0x04, 0x00, 0x04, 0x1a, + 0x04, 0x98, 0x04, 0xdc, 0x05, 0x36, 0x05, 0xba, 0x06, 0x06, 0x06, 0x70, + 0x06, 0xe4, 0x07, 0x1c, 0x07, 0xae, 0x08, 0x22, 0x08, 0x2e, 0x08, 0x3a, + 0x08, 0x58, 0x08, 0x80, 0x08, 0x9e, 0x09, 0x04, 0x09, 0x9c, 0x09, 0xe8, + 0x0a, 0x56, 0x0a, 0xac, 0x0a, 0xf2, 0x0b, 0x34, 0x0b, 0x70, 0x0b, 0xe6, + 0x0c, 0x3e, 0x0c, 0x78, 0x0c, 0xbc, 0x0d, 0x0a, 0x0d, 0x34, 0x0d, 0x8c, + 0x0d, 0xd4, 0x0e, 0x32, 0x0e, 0x7e, 0x0e, 0xf2, 0x0f, 0x50, 0x0f, 0xc2, + 0x0f, 0xf4, 0x10, 0x40, 0x10, 0x7a, 0x10, 0xd8, 0x11, 0x34, 0x11, 0x7a, + 0x11, 0xba, 0x11, 0xe0, 0x11, 0xfa, 0x12, 0x20, 0x12, 0x44, 0x12, 0x5c, + 0x12, 0x7c, 0x13, 0x04, 0x13, 0x78, 0x13, 0xce, 0x14, 0x42, 0x14, 0xb6, + 0x15, 0x0e, 0x15, 0xe2, 0x16, 0x3e, 0x16, 0x98, 0x16, 0xec, 0x17, 0x38, + 0x17, 0x70, 0x17, 0xf8, 0x18, 0x54, 0x18, 0xa8, 0x19, 0x1c, 0x19, 0x90, + 0x19, 0xe8, 0x1a, 0x68, 0x1a, 0xb8, 0x1b, 0x14, 0x1b, 0x4c, 0x1b, 0xa8, + 0x1c, 0x04, 0x1c, 0x50, 0x1c, 0x90, 0x1d, 0x04, 0x1d, 0x1c, 0x1d, 0x92, + 0x1d, 0xe2, 0x1d, 0xe2, 0x1e, 0x1e, 0x1e, 0x92, 0x1f, 0x02, 0x1f, 0x82, + 0x1f, 0xde, 0x20, 0x06, 0x20, 0xb2, 0x20, 0xf2, 0x21, 0x88, 0x22, 0x12, + 0x22, 0x30, 0x22, 0x4c, 0x22, 0x4c, 0x23, 0x1a, 0x23, 0x4a, 0x23, 0x9c, + 0x23, 0xd8, 0x24, 0x30, 0x24, 0xa4, 0x24, 0xc4, 0x25, 0x2e, 0x25, 0x66, + 0x25, 0x8a, 0x25, 0xd0, 0x26, 0x14, 0x26, 0x68, 0x26, 0x86, 0x26, 0xbe, + 0x27, 0x04, 0x27, 0x62, 0x27, 0xbe, 0x27, 0xe0, 0x28, 0x04, 0x28, 0x2c, + 0x28, 0x6c, 0x28, 0xaa, 0x28, 0xf2, 0x29, 0x5a, 0x29, 0xec, 0x2a, 0x0c, + 0x2a, 0x2c, 0x2a, 0x50, 0x2a, 0x8c, 0x2a, 0xaa, 0x2a, 0xc8, 0x2a, 0xea, + 0x2b, 0x24, 0x2b, 0x4c, 0x2b, 0x88, 0x2b, 0xcc, 0x2c, 0x10, 0x2c, 0x58, + 0x2c, 0xba, 0x2d, 0x1a, 0x2d, 0x4c, 0x2d, 0xec, 0x2e, 0x1c, 0x2e, 0x4c, + 0x2e, 0x80, 0x2e, 0xcc, 0x2e, 0xee, 0x2f, 0x42, 0x2f, 0xba, 0x2f, 0xc6, + 0x2f, 0xd2, 0x30, 0x22, 0x30, 0x8c, 0x30, 0x98, 0x31, 0x08, 0x31, 0xd8, + 0x32, 0x68, 0x32, 0x74, 0x32, 0x80, 0x32, 0xcc, 0x32, 0xd8, 0x32, 0xf4, + 0x33, 0x10, 0x33, 0x32, 0x33, 0x6a, 0x33, 0xe6, 0x34, 0x32, 0x34, 0x3e, + 0x34, 0x4a, 0x34, 0x88, 0x34, 0xe0, 0x34, 0xec, 0x35, 0x3e, 0x35, 0xd6, + 0x35, 0xe2, 0x35, 0xee, 0x36, 0x22, 0x36, 0x2e, 0x36, 0x3a, 0x36, 0xae, + 0x36, 0xba, 0x00, 0x00, 0x00, 0x02, 0x00, 0xe2, 0xff, 0xf7, 0x01, 0x76, + 0x02, 0xba, 0x00, 0x05, 0x00, 0x13, 0x00, 0x43, 0xba, 0x00, 0x06, 0x00, + 0x14, 0x00, 0x15, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x06, 0x10, 0xb8, 0x00, + 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x02, 0x2f, + 0x1b, 0xb9, 0x00, 0x02, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x0f, 0x3e, + 0x59, 0xb9, 0x00, 0x0d, 0x00, 0x09, 0xf4, 0xb9, 0x00, 0x05, 0x00, 0x07, + 0xf4, 0x30, 0x31, 0x25, 0x03, 0x35, 0x33, 0x15, 0x03, 0x07, 0x22, 0x26, + 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x01, + 0x1c, 0x1c, 0x58, 0x1c, 0x10, 0x29, 0x21, 0x21, 0x29, 0x29, 0x21, 0x21, + 0xe9, 0x01, 0x06, 0xcb, 0xcb, 0xfe, 0xfa, 0xf2, 0x22, 0x1a, 0x12, 0x1a, + 0x22, 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x00, 0x00, 0xff, 0xff, 0x00, 0xae, + 0x01, 0xcf, 0x01, 0xab, 0x02, 0xe4, 0x12, 0x26, 0x00, 0x0a, 0xa8, 0x00, + 0x10, 0x06, 0x00, 0x0a, 0x59, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, + 0x00, 0x00, 0x02, 0x48, 0x02, 0xba, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x9d, + 0xba, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x17, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1d, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0c, 0x2f, 0x1b, 0xb9, 0x00, + 0x0c, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x17, 0x2f, 0x1b, 0xb9, 0x00, 0x17, 0x00, + 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0b, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x03, 0x2f, 0xb9, 0x00, 0x00, 0x00, 0x08, 0xf4, 0xba, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x0b, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x04, + 0x2f, 0xb9, 0x00, 0x07, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x0e, 0xd0, 0xb8, + 0x00, 0x04, 0x10, 0xb8, 0x00, 0x11, 0xd0, 0xb8, 0x00, 0x03, 0x10, 0xb8, + 0x00, 0x12, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x15, 0xd0, 0x30, + 0x31, 0x37, 0x23, 0x35, 0x33, 0x37, 0x23, 0x35, 0x33, 0x37, 0x33, 0x03, + 0x23, 0x01, 0x33, 0x07, 0x33, 0x15, 0x23, 0x07, 0x33, 0x15, 0x23, 0x07, + 0x23, 0x94, 0x84, 0x90, 0x17, 0x83, 0x8f, 0x26, 0x49, 0x7b, 0x49, 0x01, + 0x33, 0x49, 0x26, 0x84, 0x90, 0x17, 0x83, 0x8f, 0x26, 0x49, 0xd8, 0x42, + 0x86, 0x42, 0xd8, 0xfd, 0x46, 0x02, 0xba, 0xd8, 0x42, 0x86, 0x42, 0xd8, + 0x00, 0x03, 0x00, 0x32, 0xff, 0x8f, 0x02, 0x28, 0x03, 0x2b, 0x00, 0x27, + 0x00, 0x2e, 0x00, 0x35, 0x00, 0xa7, 0xba, 0x00, 0x07, 0x00, 0x36, 0x00, + 0x37, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, 0x2b, 0xd0, + 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, 0x33, 0xd0, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x11, 0x2f, 0x1b, 0xb9, 0x00, 0x11, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x07, 0x00, 0x0b, + 0xf4, 0xb8, 0x00, 0x11, 0x10, 0xb9, 0x00, 0x2c, 0x00, 0x0b, 0xf4, 0xba, + 0x00, 0x08, 0x00, 0x2c, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, + 0x10, 0xb8, 0x00, 0x12, 0xdc, 0xb8, 0x00, 0x11, 0x10, 0xb8, 0x00, 0x14, + 0xd0, 0xb8, 0x00, 0x2c, 0x10, 0xb8, 0x00, 0x1b, 0xd0, 0xb8, 0x00, 0x07, + 0x10, 0xb8, 0x00, 0x33, 0xd0, 0xba, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x33, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x25, 0xd0, 0xb8, + 0x00, 0x00, 0x10, 0xb8, 0x00, 0x27, 0xdc, 0xba, 0x00, 0x2b, 0x00, 0x11, + 0x00, 0x07, 0x11, 0x12, 0x39, 0xba, 0x00, 0x32, 0x00, 0x1b, 0x00, 0x25, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x05, 0x2e, 0x01, 0x27, 0x37, 0x1e, 0x01, + 0x17, 0x11, 0x27, 0x2e, 0x03, 0x35, 0x34, 0x36, 0x37, 0x35, 0x33, 0x15, + 0x1e, 0x01, 0x17, 0x07, 0x2e, 0x01, 0x27, 0x15, 0x17, 0x1e, 0x03, 0x15, + 0x14, 0x06, 0x07, 0x15, 0x23, 0x03, 0x14, 0x16, 0x17, 0x35, 0x0e, 0x01, + 0x01, 0x34, 0x26, 0x27, 0x15, 0x3e, 0x01, 0x01, 0x17, 0x53, 0x6e, 0x24, + 0x3d, 0x24, 0x50, 0x35, 0x17, 0x34, 0x46, 0x2a, 0x12, 0x6d, 0x5f, 0x3e, + 0x45, 0x65, 0x26, 0x3f, 0x1b, 0x45, 0x32, 0x1e, 0x33, 0x46, 0x2b, 0x12, + 0x6d, 0x66, 0x3e, 0x7b, 0x39, 0x43, 0x3c, 0x40, 0x01, 0x3b, 0x3d, 0x46, + 0x3f, 0x44, 0x0b, 0x05, 0x43, 0x32, 0x32, 0x2d, 0x32, 0x05, 0x01, 0x05, + 0x04, 0x09, 0x25, 0x33, 0x3f, 0x22, 0x55, 0x61, 0x07, 0x66, 0x66, 0x05, + 0x39, 0x33, 0x2d, 0x24, 0x2c, 0x05, 0xf5, 0x05, 0x09, 0x24, 0x33, 0x40, + 0x23, 0x58, 0x6a, 0x08, 0x66, 0x02, 0x79, 0x31, 0x38, 0x0e, 0xec, 0x06, + 0x3b, 0xfe, 0x82, 0x36, 0x38, 0x0c, 0xfa, 0x07, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x12, 0xff, 0xf4, 0x02, 0x46, 0x02, 0xc6, 0x00, 0x0b, + 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x2d, 0x00, 0x3b, 0x00, 0xb9, + 0xba, 0x00, 0x25, 0x00, 0x3c, 0x00, 0x3d, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x25, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0xb8, 0x00, 0x25, 0x10, 0xb8, 0x00, + 0x0f, 0xd0, 0xb8, 0x00, 0x25, 0x10, 0xb8, 0x00, 0x1d, 0xd0, 0xb8, 0x00, + 0x25, 0x10, 0xb8, 0x00, 0x1f, 0xd0, 0xb8, 0x00, 0x25, 0x10, 0xb8, 0x00, + 0x39, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, + 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x1a, 0x2f, 0x1b, 0xb9, 0x00, 0x1a, 0x00, 0x1d, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x21, 0x2f, 0x1b, 0xb9, + 0x00, 0x21, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x22, 0x2f, 0x1b, 0xb9, 0x00, 0x22, 0x00, 0x0f, 0x3e, 0x59, 0xba, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x06, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, + 0x2f, 0xb9, 0x00, 0x0c, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x06, 0x10, 0xb9, + 0x00, 0x13, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x22, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x28, 0x2f, 0xb8, 0x00, 0x22, 0x10, 0xb9, + 0x00, 0x2e, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x28, 0x10, 0xb9, 0x00, 0x35, + 0x00, 0x08, 0xf4, 0x30, 0x31, 0x13, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x33, 0x03, 0x23, 0x07, + 0x33, 0x03, 0x23, 0x05, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x15, 0x14, 0x06, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, + 0x06, 0x1d, 0x01, 0x14, 0x16, 0xa9, 0x42, 0x53, 0x53, 0x42, 0x42, 0x53, + 0x53, 0x42, 0x24, 0x2d, 0x2d, 0x24, 0x24, 0x2d, 0x2d, 0x01, 0x79, 0x48, + 0xa0, 0x48, 0xac, 0x48, 0xa0, 0x48, 0x01, 0x9d, 0x42, 0x53, 0x53, 0x42, + 0x42, 0x53, 0x53, 0x42, 0x24, 0x2d, 0x2d, 0x24, 0x24, 0x2d, 0x2d, 0x01, + 0x64, 0x59, 0x58, 0x58, 0x59, 0x59, 0x58, 0x58, 0x59, 0x36, 0x32, 0x30, + 0x32, 0x30, 0x32, 0x32, 0x30, 0x32, 0x30, 0x32, 0x01, 0x20, 0xfe, 0xd4, + 0x62, 0xfe, 0xd4, 0x0c, 0x59, 0x58, 0x58, 0x59, 0x59, 0x58, 0x58, 0x59, + 0x36, 0x32, 0x30, 0x32, 0x30, 0x32, 0x32, 0x30, 0x32, 0x30, 0x32, 0x00, + 0x00, 0x02, 0x00, 0x19, 0xff, 0xf4, 0x02, 0x3c, 0x02, 0xc6, 0x00, 0x38, + 0x00, 0x43, 0x00, 0xb6, 0xba, 0x00, 0x25, 0x00, 0x44, 0x00, 0x45, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x25, 0x10, 0xb8, 0x00, 0x39, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x12, 0x2f, 0x1b, 0xb9, 0x00, 0x12, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, + 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x34, 0x2f, 0x1b, 0xb9, 0x00, 0x34, 0x00, 0x0f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x39, 0x00, 0x08, 0xf4, + 0xba, 0x00, 0x24, 0x00, 0x12, 0x00, 0x39, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x12, 0x10, 0xb9, 0x00, 0x1b, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x3d, 0x00, + 0x1b, 0x00, 0x00, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0a, 0x00, 0x24, 0x00, + 0x3d, 0x11, 0x12, 0x39, 0xba, 0x00, 0x26, 0x00, 0x12, 0x00, 0x39, 0x11, + 0x12, 0x39, 0xba, 0x00, 0x2d, 0x00, 0x12, 0x00, 0x00, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x2d, 0x2f, 0xb9, 0x00, 0x2b, 0x00, 0x08, 0xf4, 0xba, 0x00, + 0x35, 0x00, 0x1b, 0x00, 0x00, 0x11, 0x12, 0x39, 0xba, 0x00, 0x32, 0x00, + 0x26, 0x00, 0x35, 0x11, 0x12, 0x39, 0xba, 0x00, 0x3c, 0x00, 0x26, 0x00, + 0x35, 0x11, 0x12, 0x39, 0x30, 0x31, 0x17, 0x22, 0x2e, 0x02, 0x35, 0x34, + 0x3e, 0x02, 0x37, 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, + 0x02, 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x1e, + 0x02, 0x1f, 0x02, 0x33, 0x3e, 0x01, 0x37, 0x33, 0x15, 0x23, 0x0e, 0x03, + 0x07, 0x17, 0x23, 0x27, 0x23, 0x0e, 0x01, 0x27, 0x32, 0x36, 0x37, 0x27, + 0x0e, 0x01, 0x1d, 0x01, 0x14, 0x16, 0xd9, 0x2e, 0x47, 0x31, 0x1a, 0x0c, + 0x1e, 0x31, 0x26, 0x1c, 0x25, 0x1d, 0x31, 0x42, 0x25, 0x21, 0x37, 0x2a, + 0x1d, 0x07, 0x42, 0x0d, 0x34, 0x27, 0x2d, 0x35, 0x08, 0x11, 0x1b, 0x13, + 0x5a, 0x49, 0x05, 0x07, 0x04, 0x02, 0x8d, 0x4b, 0x03, 0x06, 0x08, 0x0a, + 0x09, 0x7a, 0x5f, 0x57, 0x05, 0x0e, 0x56, 0x2f, 0x2b, 0x42, 0x13, 0xae, + 0x2e, 0x26, 0x48, 0x0c, 0x1e, 0x35, 0x46, 0x28, 0x1a, 0x38, 0x35, 0x31, + 0x13, 0x24, 0x4c, 0x2d, 0x26, 0x3e, 0x2d, 0x18, 0x13, 0x1e, 0x26, 0x13, + 0x22, 0x1f, 0x29, 0x37, 0x2b, 0x08, 0x10, 0x1e, 0x21, 0x26, 0x18, 0x6f, + 0x5a, 0x27, 0x64, 0x30, 0x43, 0x18, 0x2a, 0x28, 0x29, 0x17, 0x90, 0x67, + 0x34, 0x3f, 0x47, 0x24, 0x20, 0xd2, 0x1d, 0x49, 0x2b, 0x0f, 0x36, 0x40, + 0x00, 0x01, 0x01, 0x06, 0x01, 0xcf, 0x01, 0x52, 0x02, 0xe4, 0x00, 0x03, + 0x00, 0x1e, 0xba, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, + 0x00, 0x01, 0x00, 0x1f, 0x3e, 0x59, 0x30, 0x31, 0x01, 0x11, 0x33, 0x11, + 0x01, 0x06, 0x4c, 0x01, 0xcf, 0x01, 0x15, 0xfe, 0xeb, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xcd, 0xff, 0x76, 0x01, 0xee, 0x02, 0xf8, 0x00, 0x16, + 0x00, 0x15, 0xba, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x18, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x05, 0x2f, 0xb8, 0x00, 0x12, 0x2f, 0x30, 0x31, 0x13, + 0x34, 0x3e, 0x02, 0x37, 0x33, 0x0e, 0x03, 0x1d, 0x01, 0x14, 0x1e, 0x02, + 0x17, 0x23, 0x2e, 0x03, 0xcd, 0x21, 0x39, 0x4c, 0x2a, 0x51, 0x2c, 0x4d, + 0x3b, 0x22, 0x22, 0x3b, 0x4d, 0x2c, 0x51, 0x2a, 0x4c, 0x39, 0x21, 0x01, + 0x37, 0x49, 0x87, 0x74, 0x5d, 0x20, 0x21, 0x57, 0x67, 0x77, 0x40, 0x56, + 0x40, 0x77, 0x67, 0x57, 0x21, 0x1f, 0x5e, 0x74, 0x87, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x6a, 0xff, 0x76, 0x01, 0x8b, 0x02, 0xf8, 0x00, 0x16, + 0x00, 0x15, 0xba, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x18, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x11, 0x2f, 0xb8, 0x00, 0x06, 0x2f, 0x30, 0x31, 0x01, + 0x14, 0x0e, 0x02, 0x07, 0x23, 0x3e, 0x03, 0x3d, 0x01, 0x34, 0x2e, 0x02, + 0x27, 0x33, 0x1e, 0x03, 0x01, 0x8b, 0x21, 0x39, 0x4c, 0x2a, 0x51, 0x2b, + 0x4e, 0x3b, 0x22, 0x22, 0x3b, 0x4e, 0x2b, 0x51, 0x2a, 0x4c, 0x39, 0x21, + 0x01, 0x37, 0x49, 0x87, 0x74, 0x5e, 0x1f, 0x21, 0x57, 0x67, 0x77, 0x40, + 0x56, 0x40, 0x77, 0x67, 0x57, 0x21, 0x20, 0x5d, 0x74, 0x87, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x2b, 0x00, 0x48, 0x02, 0x2d, 0x02, 0x38, 0x00, 0x0e, + 0x00, 0x11, 0xba, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x06, 0x2f, 0x30, 0x31, 0x37, 0x27, 0x37, 0x27, 0x37, + 0x17, 0x35, 0x33, 0x15, 0x37, 0x17, 0x07, 0x17, 0x07, 0x27, 0xaf, 0x39, + 0x7c, 0xc7, 0x15, 0xc7, 0x4a, 0xc7, 0x15, 0xc7, 0x7c, 0x39, 0x7d, 0x48, + 0x2a, 0xaa, 0x42, 0x42, 0x40, 0xd8, 0xd8, 0x40, 0x42, 0x42, 0xaa, 0x2a, + 0xac, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3e, 0x00, 0x3e, 0x02, 0x1a, + 0x02, 0x24, 0x00, 0x0b, 0x00, 0x27, 0xba, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0d, 0x11, 0x12, 0x39, 0x00, 0xbb, 0x00, 0x02, 0x00, 0x08, 0x00, 0x03, + 0x00, 0x04, 0x2b, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x07, 0xd0, 0xb8, + 0x00, 0x02, 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0x30, 0x31, 0x25, 0x35, 0x23, + 0x35, 0x33, 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x01, 0x06, 0xc8, + 0xc8, 0x4c, 0xc8, 0xc8, 0x3e, 0xd1, 0x44, 0xd1, 0xd1, 0x44, 0xd1, 0x00, + 0x00, 0x01, 0x00, 0xcc, 0xff, 0x73, 0x01, 0x82, 0x00, 0x88, 0x00, 0x03, + 0x00, 0x15, 0xba, 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x2f, 0xb8, 0x00, 0x03, 0x2f, 0x30, 0x31, 0x25, + 0x33, 0x03, 0x23, 0x01, 0x01, 0x81, 0x73, 0x43, 0x88, 0xfe, 0xeb, 0x00, + 0x00, 0x01, 0x00, 0x9b, 0x01, 0x06, 0x01, 0xbd, 0x01, 0x5a, 0x00, 0x03, + 0x00, 0x17, 0xba, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xbb, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x2b, 0x30, + 0x31, 0x13, 0x35, 0x21, 0x15, 0x9b, 0x01, 0x22, 0x01, 0x06, 0x54, 0x54, + 0x00, 0x01, 0x00, 0xe2, 0xff, 0xf7, 0x01, 0x76, 0x00, 0x81, 0x00, 0x0d, + 0x00, 0x24, 0xba, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0f, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, + 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x07, 0x00, 0x09, 0xf4, + 0x30, 0x31, 0x05, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x1d, 0x01, 0x14, 0x06, 0x01, 0x2c, 0x29, 0x21, 0x21, 0x29, 0x29, 0x21, + 0x21, 0x09, 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x22, 0x1a, 0x12, 0x1a, 0x22, + 0x00, 0x01, 0x00, 0x5a, 0xff, 0x76, 0x01, 0xfe, 0x02, 0xf8, 0x00, 0x03, + 0x00, 0x15, 0xba, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x01, 0x2f, 0xb8, 0x00, 0x00, 0x2f, 0x30, 0x31, 0x17, + 0x01, 0x33, 0x01, 0x5a, 0x01, 0x5c, 0x48, 0xfe, 0xa4, 0x8a, 0x03, 0x82, + 0xfc, 0x7e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x38, 0xff, 0xf4, 0x02, 0x20, + 0x02, 0xc6, 0x00, 0x13, 0x00, 0x29, 0x00, 0x37, 0x00, 0x5f, 0xba, 0x00, + 0x00, 0x00, 0x38, 0x00, 0x39, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, + 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x2a, 0xd0, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x14, 0x00, 0x0b, + 0xf4, 0xb8, 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x1f, 0x00, 0x0b, 0xf4, 0xba, + 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x2a, + 0x2f, 0xb9, 0x00, 0x31, 0x00, 0x06, 0xf4, 0x30, 0x31, 0x05, 0x22, 0x2e, + 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, + 0x02, 0x27, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, + 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x37, 0x22, 0x26, 0x3d, 0x01, + 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x01, 0x2c, 0x40, + 0x5c, 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x40, 0x5c, 0x3c, 0x1c, 0x1c, + 0x3c, 0x5c, 0x40, 0x2a, 0x3c, 0x25, 0x12, 0x12, 0x25, 0x3c, 0x2a, 0x2a, + 0x3c, 0x25, 0x12, 0x12, 0x25, 0x3c, 0x2a, 0x23, 0x1b, 0x1b, 0x23, 0x23, + 0x1b, 0x1b, 0x0c, 0x31, 0x5c, 0x86, 0x56, 0x55, 0x87, 0x5c, 0x31, 0x31, + 0x5c, 0x87, 0x55, 0x56, 0x86, 0x5c, 0x31, 0x49, 0x21, 0x3c, 0x55, 0x35, + 0x72, 0x34, 0x56, 0x3c, 0x21, 0x21, 0x3c, 0x56, 0x34, 0x72, 0x35, 0x55, + 0x3c, 0x21, 0xe5, 0x1c, 0x14, 0x16, 0x14, 0x1c, 0x1c, 0x14, 0x16, 0x14, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x35, 0x00, 0x00, 0x02, 0x29, + 0x02, 0xba, 0x00, 0x0b, 0x00, 0x5b, 0xba, 0x00, 0x02, 0x00, 0x0c, 0x00, + 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x01, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x08, + 0x10, 0xb9, 0x00, 0x04, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x06, 0x00, 0x04, + 0x00, 0x01, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x05, + 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x30, + 0x31, 0x33, 0x35, 0x33, 0x11, 0x23, 0x07, 0x27, 0x37, 0x33, 0x11, 0x33, + 0x15, 0x55, 0xc8, 0x07, 0xb0, 0x31, 0xb9, 0x83, 0xb8, 0x49, 0x02, 0x33, + 0xa4, 0x35, 0xad, 0xfd, 0x8f, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, + 0x00, 0x00, 0x02, 0x19, 0x02, 0xc6, 0x00, 0x1f, 0x00, 0x53, 0xba, 0x00, + 0x03, 0x00, 0x20, 0x00, 0x21, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, + 0xb9, 0x00, 0x01, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x1e, 0x00, 0x0b, + 0xf4, 0xba, 0x00, 0x03, 0x00, 0x13, 0x00, 0x1e, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x13, 0x10, 0xb9, 0x00, 0x0a, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x1d, + 0x00, 0x0a, 0x00, 0x01, 0x11, 0x12, 0x39, 0x30, 0x31, 0x29, 0x01, 0x35, + 0x37, 0x3e, 0x01, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, + 0x3e, 0x03, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x0f, 0x01, + 0x21, 0x02, 0x19, 0xfe, 0x2e, 0xe9, 0x33, 0x42, 0x42, 0x41, 0x40, 0x45, + 0x11, 0x4b, 0x0a, 0x23, 0x36, 0x4d, 0x33, 0x34, 0x51, 0x37, 0x1d, 0x17, + 0x29, 0x39, 0x23, 0xc3, 0x01, 0x7b, 0x56, 0xd2, 0x2e, 0x61, 0x36, 0x0c, + 0x3f, 0x45, 0x41, 0x36, 0x1c, 0x1f, 0x3b, 0x2e, 0x1c, 0x1e, 0x36, 0x4a, + 0x2c, 0x28, 0x46, 0x40, 0x3d, 0x1e, 0xaa, 0x00, 0x00, 0x01, 0x00, 0x30, + 0xff, 0xf4, 0x02, 0x06, 0x02, 0xc6, 0x00, 0x39, 0x00, 0x6a, 0xba, 0x00, + 0x10, 0x00, 0x3a, 0x00, 0x3b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x25, 0x2f, 0x1b, + 0xb9, 0x00, 0x25, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x10, 0x10, 0xb9, + 0x00, 0x07, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x38, 0x00, 0x10, 0x00, 0x25, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x38, 0x2f, 0x41, 0x03, 0x00, 0xe0, 0x00, + 0x38, 0x00, 0x01, 0x5d, 0xb9, 0x00, 0x39, 0x00, 0x0b, 0xf4, 0xba, 0x00, + 0x1a, 0x00, 0x39, 0x00, 0x38, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x25, 0x10, + 0xb9, 0x00, 0x30, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x01, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, + 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x07, 0x15, 0x1e, 0x03, 0x15, 0x14, + 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, 0x27, 0x37, 0x1e, 0x03, 0x33, 0x32, + 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x35, 0x01, 0x0e, 0x49, 0x49, + 0x47, 0x39, 0x38, 0x45, 0x16, 0x3f, 0x0d, 0x26, 0x33, 0x43, 0x2b, 0x2d, + 0x4e, 0x3a, 0x21, 0x15, 0x25, 0x32, 0x1c, 0x1d, 0x36, 0x2a, 0x19, 0x23, + 0x3f, 0x59, 0x36, 0x2e, 0x47, 0x37, 0x29, 0x10, 0x3f, 0x0e, 0x1e, 0x27, + 0x32, 0x21, 0x4a, 0x4f, 0x4d, 0x4d, 0x53, 0x01, 0x92, 0x41, 0x33, 0x07, + 0x38, 0x38, 0x31, 0x28, 0x30, 0x15, 0x29, 0x20, 0x14, 0x17, 0x2d, 0x42, + 0x2a, 0x22, 0x36, 0x28, 0x1c, 0x07, 0x04, 0x06, 0x1b, 0x2b, 0x3d, 0x27, + 0x2d, 0x4b, 0x35, 0x1e, 0x14, 0x22, 0x2a, 0x17, 0x30, 0x15, 0x22, 0x19, + 0x0e, 0x44, 0x3f, 0x08, 0x3e, 0x44, 0x48, 0x00, 0x00, 0x02, 0x00, 0x22, + 0x00, 0x00, 0x02, 0x32, 0x02, 0xba, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x5f, + 0xba, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x10, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x04, 0x10, 0xb8, 0x00, 0x0e, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1d, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, + 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x01, 0x2f, 0xb9, 0x00, 0x0c, 0x00, 0x0b, + 0xf4, 0xb8, 0x00, 0x06, 0xd0, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x09, + 0xd0, 0xb8, 0x00, 0x05, 0x10, 0xb8, 0x00, 0x0d, 0xd0, 0x30, 0x31, 0x21, + 0x35, 0x21, 0x35, 0x01, 0x33, 0x11, 0x33, 0x15, 0x23, 0x15, 0x25, 0x21, + 0x11, 0x23, 0x01, 0x7a, 0xfe, 0xa8, 0x01, 0x2e, 0x7a, 0x68, 0x68, 0xfe, + 0xa3, 0x01, 0x0d, 0x04, 0x89, 0x4a, 0x01, 0xe7, 0xfe, 0x14, 0x45, 0x89, + 0xce, 0x01, 0xab, 0x00, 0x00, 0x01, 0x00, 0x49, 0xff, 0xf4, 0x02, 0x15, + 0x02, 0xba, 0x00, 0x28, 0x00, 0x57, 0xba, 0x00, 0x1b, 0x00, 0x29, 0x00, + 0x2a, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x27, 0x2f, 0x1b, 0xb9, 0x00, 0x27, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, + 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x27, 0x10, 0xb9, 0x00, 0x01, 0x00, 0x0b, + 0xf4, 0xba, 0x00, 0x22, 0x00, 0x10, 0x00, 0x27, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x22, 0x2f, 0xb9, 0x00, 0x06, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x10, + 0x10, 0xb9, 0x00, 0x1b, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x01, 0x21, 0x03, + 0x33, 0x3e, 0x01, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x23, + 0x22, 0x2e, 0x02, 0x27, 0x37, 0x1e, 0x03, 0x33, 0x32, 0x36, 0x3d, 0x01, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x13, 0x21, 0x01, 0xf5, 0xfe, + 0xc8, 0x14, 0x07, 0x1a, 0x40, 0x38, 0x2e, 0x4d, 0x38, 0x20, 0x20, 0x3e, + 0x58, 0x38, 0x2c, 0x45, 0x35, 0x28, 0x10, 0x3f, 0x0e, 0x1d, 0x26, 0x30, + 0x20, 0x48, 0x4d, 0x4e, 0x49, 0x32, 0x37, 0x17, 0x47, 0x19, 0x01, 0x7c, + 0x02, 0x71, 0xfe, 0xf5, 0x23, 0x29, 0x1d, 0x38, 0x4f, 0x33, 0x33, 0x55, + 0x3d, 0x22, 0x14, 0x22, 0x2a, 0x17, 0x30, 0x15, 0x22, 0x19, 0x0e, 0x4e, + 0x45, 0x08, 0x45, 0x4e, 0x22, 0x19, 0x0a, 0x01, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x40, 0xff, 0xf4, 0x02, 0x18, 0x02, 0xba, 0x00, 0x1d, + 0x00, 0x2b, 0x00, 0x67, 0xba, 0x00, 0x1e, 0x00, 0x2c, 0x00, 0x2d, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x1e, 0x10, 0xb8, 0x00, 0x00, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, + 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x25, + 0x00, 0x0a, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x25, 0x2f, 0xb8, + 0x00, 0x00, 0x10, 0xb9, 0x00, 0x1e, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x11, + 0x00, 0x25, 0x00, 0x1e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x2f, 0xb8, + 0x00, 0x25, 0x10, 0xb9, 0x00, 0x14, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x05, + 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x37, 0x33, 0x0e, 0x03, 0x07, + 0x17, 0x3e, 0x01, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0x01, 0x2d, 0x37, 0x58, 0x3d, 0x21, 0x2f, 0x49, 0x5a, 0x2b, 0x6c, + 0x39, 0x59, 0x44, 0x2e, 0x0f, 0x05, 0x19, 0x52, 0x41, 0x2e, 0x4c, 0x38, + 0x1f, 0x22, 0x3d, 0x57, 0x36, 0x48, 0x4f, 0x4f, 0x48, 0x48, 0x4f, 0x4f, + 0x0c, 0x25, 0x45, 0x64, 0x3e, 0x4e, 0x89, 0x71, 0x57, 0x1b, 0x29, 0x4e, + 0x55, 0x61, 0x3d, 0x02, 0x2b, 0x39, 0x1e, 0x38, 0x50, 0x31, 0x33, 0x55, + 0x3d, 0x22, 0x47, 0x4e, 0x47, 0x08, 0x47, 0x4e, 0x4e, 0x47, 0x08, 0x47, + 0x4e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x02, 0x13, + 0x02, 0xba, 0x00, 0x08, 0x00, 0x47, 0xba, 0x00, 0x08, 0x00, 0x09, 0x00, + 0x0a, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x02, 0x00, 0x0b, + 0xf4, 0xba, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x04, 0x2f, 0x30, 0x31, 0x33, 0x01, 0x21, 0x15, 0x23, 0x35, 0x21, + 0x15, 0x01, 0xad, 0x01, 0x11, 0xfe, 0xce, 0x4b, 0x01, 0xd2, 0xfe, 0xf4, + 0x02, 0x72, 0x82, 0xca, 0x4a, 0xfd, 0x90, 0x00, 0x00, 0x03, 0x00, 0x37, + 0xff, 0xf4, 0x02, 0x21, 0x02, 0xc6, 0x00, 0x1d, 0x00, 0x2b, 0x00, 0x39, + 0x00, 0x80, 0xba, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x3b, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x1e, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x2c, 0xd0, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0f, 0x2f, 0x1b, 0xb9, + 0x00, 0x0f, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb8, + 0x00, 0x0f, 0x10, 0xb9, 0x00, 0x33, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x00, + 0x10, 0xb9, 0x00, 0x1e, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x25, 0x00, 0x33, + 0x00, 0x1e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x25, 0x2f, 0x41, 0x03, 0x00, + 0xe0, 0x00, 0x25, 0x00, 0x01, 0x5d, 0xb9, 0x00, 0x2c, 0x00, 0x0b, 0xf4, + 0xba, 0x00, 0x08, 0x00, 0x2c, 0x00, 0x25, 0x11, 0x12, 0x39, 0xba, 0x00, + 0x16, 0x00, 0x2c, 0x00, 0x25, 0x11, 0x12, 0x39, 0x30, 0x31, 0x05, 0x22, + 0x2e, 0x02, 0x35, 0x34, 0x36, 0x37, 0x35, 0x2e, 0x01, 0x35, 0x34, 0x36, + 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, + 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x1d, 0x01, 0x14, 0x16, 0x13, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x2c, 0x3d, 0x5c, 0x3d, 0x1f, + 0x4e, 0x40, 0x38, 0x41, 0x76, 0x6a, 0x6a, 0x76, 0x41, 0x38, 0x40, 0x4e, + 0x1f, 0x3e, 0x5b, 0x3d, 0x4a, 0x54, 0x53, 0x4b, 0x4b, 0x53, 0x54, 0x4a, + 0x44, 0x47, 0x49, 0x42, 0x42, 0x49, 0x47, 0x0c, 0x1f, 0x36, 0x4a, 0x2b, + 0x48, 0x54, 0x11, 0x08, 0x13, 0x55, 0x3c, 0x50, 0x5f, 0x5f, 0x50, 0x3c, + 0x55, 0x13, 0x08, 0x11, 0x54, 0x48, 0x2b, 0x4a, 0x36, 0x1f, 0x47, 0x42, + 0x3c, 0x16, 0x3c, 0x42, 0x42, 0x3c, 0x16, 0x3c, 0x42, 0x01, 0x56, 0x3a, + 0x36, 0x0e, 0x36, 0x3a, 0x3a, 0x36, 0x0e, 0x36, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x02, 0x18, 0x02, 0xc6, 0x00, 0x1d, + 0x00, 0x2b, 0x00, 0x67, 0xba, 0x00, 0x1e, 0x00, 0x2c, 0x00, 0x2d, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x1e, 0x10, 0xb8, 0x00, 0x19, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x19, 0x2f, 0x1b, 0xb9, 0x00, 0x19, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, + 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x19, + 0x10, 0xb9, 0x00, 0x25, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x1e, 0x00, 0x19, + 0x00, 0x05, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1e, 0x2f, 0xba, 0x00, 0x0c, + 0x00, 0x25, 0x00, 0x1e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0c, 0x2f, 0xb8, + 0x00, 0x1e, 0x10, 0xb9, 0x00, 0x0f, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x01, + 0x14, 0x0e, 0x02, 0x07, 0x23, 0x3e, 0x03, 0x37, 0x27, 0x0e, 0x01, 0x23, + 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x07, + 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0x02, 0x18, 0x2f, 0x4a, 0x59, 0x2b, 0x6c, 0x39, 0x59, 0x44, 0x2e, + 0x0f, 0x05, 0x1a, 0x51, 0x41, 0x2e, 0x4d, 0x37, 0x1f, 0x21, 0x3e, 0x57, + 0x35, 0x37, 0x58, 0x3d, 0x21, 0xec, 0x48, 0x4f, 0x4f, 0x48, 0x48, 0x4f, + 0x4f, 0x01, 0xba, 0x4e, 0x89, 0x71, 0x57, 0x1b, 0x29, 0x4e, 0x55, 0x61, + 0x3d, 0x02, 0x2b, 0x39, 0x1e, 0x38, 0x4f, 0x32, 0x33, 0x55, 0x3d, 0x22, + 0x25, 0x45, 0x64, 0xab, 0x4e, 0x47, 0x08, 0x47, 0x4e, 0x4e, 0x47, 0x08, + 0x47, 0x4e, 0x00, 0x00, 0xff, 0xff, 0x00, 0xe2, 0xff, 0xf7, 0x01, 0x76, + 0x02, 0x0d, 0x12, 0x26, 0x00, 0x11, 0x00, 0x00, 0x10, 0x07, 0x00, 0x11, + 0x00, 0x00, 0x01, 0x8c, 0xff, 0xff, 0x00, 0xcc, 0xff, 0x73, 0x01, 0x82, + 0x02, 0x0d, 0x12, 0x26, 0x00, 0x0f, 0x00, 0x00, 0x10, 0x07, 0x00, 0x11, + 0x00, 0x00, 0x01, 0x8c, 0x00, 0x01, 0x00, 0x55, 0x00, 0x10, 0x02, 0x03, + 0x02, 0x52, 0x00, 0x07, 0x00, 0x15, 0xba, 0x00, 0x05, 0x00, 0x08, 0x00, + 0x09, 0x11, 0x12, 0x39, 0x00, 0xba, 0x00, 0x07, 0x00, 0x02, 0x00, 0x03, + 0x2b, 0x30, 0x31, 0x13, 0x35, 0x25, 0x15, 0x05, 0x15, 0x05, 0x15, 0x55, + 0x01, 0xae, 0xfe, 0x9d, 0x01, 0x63, 0x01, 0x09, 0x50, 0xf9, 0x53, 0xc9, + 0x08, 0xc9, 0x55, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0xac, 0x02, 0x1a, + 0x01, 0xb8, 0x00, 0x03, 0x00, 0x07, 0x00, 0x29, 0xba, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, + 0x00, 0xd0, 0x00, 0xbb, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x2b, 0xbb, 0x00, 0x05, 0x00, 0x08, 0x00, 0x04, 0x00, 0x04, 0x2b, 0x30, + 0x31, 0x13, 0x35, 0x21, 0x15, 0x05, 0x35, 0x21, 0x15, 0x3e, 0x01, 0xdc, + 0xfe, 0x24, 0x01, 0xdc, 0x01, 0x74, 0x44, 0x44, 0xc8, 0x44, 0x44, 0x00, + 0x00, 0x01, 0x00, 0x55, 0x00, 0x10, 0x02, 0x03, 0x02, 0x52, 0x00, 0x07, + 0x00, 0x15, 0xba, 0x00, 0x01, 0x00, 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, + 0x00, 0xba, 0x00, 0x07, 0x00, 0x04, 0x00, 0x03, 0x2b, 0x30, 0x31, 0x37, + 0x25, 0x35, 0x25, 0x35, 0x05, 0x15, 0x05, 0x55, 0x01, 0x63, 0xfe, 0x9d, + 0x01, 0xae, 0xfe, 0x52, 0x63, 0xc9, 0x08, 0xc9, 0x55, 0xf9, 0x50, 0xf9, + 0x00, 0x02, 0x00, 0x4d, 0xff, 0xf7, 0x01, 0xfe, 0x02, 0xc6, 0x00, 0x1c, + 0x00, 0x2a, 0x00, 0x51, 0xba, 0x00, 0x11, 0x00, 0x2b, 0x00, 0x2c, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x11, 0x10, 0xb8, 0x00, 0x1d, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x11, 0x2f, 0x1b, 0xb9, 0x00, 0x11, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1d, + 0x2f, 0x1b, 0xb9, 0x00, 0x1d, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x11, + 0x10, 0xb9, 0x00, 0x08, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x1d, 0x10, 0xb9, + 0x00, 0x24, 0x00, 0x09, 0xf4, 0xb9, 0x00, 0x1c, 0x00, 0x07, 0xf4, 0x30, + 0x31, 0x37, 0x35, 0x3e, 0x01, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, + 0x07, 0x15, 0x07, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x1d, 0x01, 0x14, 0x06, 0xef, 0x56, 0x62, 0x43, 0x3a, 0x3c, 0x48, 0x0e, + 0x4b, 0x0a, 0x24, 0x37, 0x4b, 0x30, 0x30, 0x4d, 0x36, 0x1e, 0x22, 0x36, + 0x45, 0x23, 0x24, 0x29, 0x21, 0x21, 0x29, 0x29, 0x21, 0x21, 0xd7, 0x9d, + 0x04, 0x43, 0x44, 0x0e, 0x38, 0x38, 0x42, 0x33, 0x1c, 0x21, 0x3b, 0x2c, + 0x1a, 0x1b, 0x31, 0x46, 0x2b, 0x2f, 0x47, 0x32, 0x1f, 0x06, 0x65, 0xe0, + 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x3e, 0xff, 0x90, 0x02, 0x0d, 0x02, 0xc6, 0x00, 0x31, + 0x00, 0x3f, 0x00, 0x86, 0xba, 0x00, 0x0b, 0x00, 0x40, 0x00, 0x41, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x10, 0xb8, 0x00, 0x3d, 0xd0, 0x00, 0xb8, + 0x00, 0x41, 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, + 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x41, 0x10, + 0xb8, 0x00, 0x01, 0xdc, 0xba, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x41, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x11, 0x2f, 0xb8, 0x00, 0x17, 0xd0, 0xb9, 0x00, + 0x32, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x0b, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x1d, 0x2f, 0xb9, 0x00, 0x39, 0x00, 0x08, 0xf4, + 0xba, 0x00, 0x13, 0x00, 0x32, 0x00, 0x39, 0x11, 0x12, 0x39, 0xba, 0x00, + 0x22, 0x00, 0x39, 0x00, 0x32, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x10, + 0xb9, 0x00, 0x27, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x01, 0x10, 0xb9, 0x00, + 0x30, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x05, 0x23, 0x22, 0x2e, 0x02, 0x35, + 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x11, 0x23, 0x35, 0x23, + 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x1e, 0x02, + 0x17, 0x33, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x1e, + 0x02, 0x3b, 0x01, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, + 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0xc6, 0x7b, 0x4c, 0x67, 0x3f, 0x1b, + 0x1f, 0x3c, 0x59, 0x3b, 0x3c, 0x55, 0x36, 0x19, 0x47, 0x05, 0x0a, 0x2e, + 0x2c, 0x3d, 0x48, 0x48, 0x3d, 0x16, 0x21, 0x18, 0x10, 0x05, 0x05, 0x47, + 0x50, 0x59, 0x4d, 0x10, 0x2b, 0x4b, 0x3c, 0x7b, 0x4f, 0x24, 0x2b, 0x2b, + 0x24, 0x2a, 0x2b, 0x2b, 0x70, 0x33, 0x67, 0x9a, 0x68, 0x74, 0x9d, 0x60, + 0x29, 0x26, 0x42, 0x5b, 0x34, 0xfe, 0x8c, 0x39, 0x1a, 0x2b, 0x67, 0x6f, + 0x6f, 0x68, 0x0c, 0x14, 0x18, 0x0d, 0x18, 0x55, 0x62, 0x89, 0x97, 0x81, + 0x3a, 0x65, 0x4b, 0x2b, 0xbb, 0x28, 0x26, 0x99, 0x26, 0x28, 0x39, 0x43, + 0x3d, 0x43, 0x39, 0x00, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x3a, + 0x02, 0xba, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x64, 0xba, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x08, 0x10, 0xb8, 0x00, + 0x05, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, + 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x0f, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, + 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x0a, 0x00, 0x05, 0x00, + 0x04, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0a, 0x2f, 0xb9, 0x00, 0x02, 0x00, + 0x0b, 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x30, 0x31, + 0x21, 0x27, 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, + 0x01, 0xe1, 0x3b, 0xf5, 0x3b, 0x57, 0xd6, 0x6f, 0xd6, 0xfe, 0xf6, 0x09, + 0x62, 0xcd, 0xc7, 0xc7, 0x02, 0xba, 0xfd, 0x46, 0x02, 0x61, 0xfe, 0xaf, + 0x00, 0x03, 0x00, 0x58, 0x00, 0x00, 0x02, 0x1f, 0x02, 0xba, 0x00, 0x11, + 0x00, 0x1b, 0x00, 0x25, 0x00, 0x6d, 0xba, 0x00, 0x1c, 0x00, 0x26, 0x00, + 0x27, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1c, 0x10, 0xb8, 0x00, 0x01, 0xd0, + 0xb8, 0x00, 0x1c, 0x10, 0xb8, 0x00, 0x12, 0xd0, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x11, 0x2f, 0x1b, + 0xb9, 0x00, 0x11, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x1b, 0x00, 0x0b, + 0xf4, 0xba, 0x00, 0x25, 0x00, 0x00, 0x00, 0x1b, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x25, 0x2f, 0xb9, 0x00, 0x1a, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x07, + 0x00, 0x25, 0x00, 0x1a, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, 0x10, 0xb9, + 0x00, 0x24, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x13, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x21, + 0x37, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x15, 0x13, 0x32, + 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x15, 0x58, 0xed, 0x5a, 0x66, + 0x3d, 0x30, 0x3b, 0x4c, 0x1c, 0x33, 0x45, 0x28, 0xfe, 0xf5, 0xf2, 0x3a, + 0x42, 0x42, 0x3a, 0x9e, 0x90, 0x35, 0x3c, 0x3c, 0x35, 0x90, 0x02, 0xba, + 0x62, 0x52, 0x3f, 0x48, 0x0f, 0x03, 0x0e, 0x4d, 0x49, 0x2a, 0x4a, 0x36, + 0x1f, 0x49, 0x34, 0x36, 0x29, 0x35, 0x35, 0xfd, 0x01, 0x42, 0x2f, 0x30, + 0x27, 0x30, 0x30, 0xe6, 0x00, 0x01, 0x00, 0x46, 0xff, 0xf4, 0x02, 0x1a, + 0x02, 0xc6, 0x00, 0x22, 0x00, 0x43, 0xba, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x24, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x0b, + 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x18, 0x00, 0x0b, 0xf4, 0x30, + 0x31, 0x05, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x1e, 0x02, 0x17, + 0x07, 0x2e, 0x03, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x33, 0x32, + 0x3e, 0x02, 0x37, 0x17, 0x0e, 0x03, 0x01, 0x43, 0x80, 0x7d, 0x7d, 0x80, + 0x30, 0x46, 0x32, 0x22, 0x0d, 0x48, 0x09, 0x18, 0x21, 0x2d, 0x20, 0x53, + 0x51, 0x51, 0x53, 0x20, 0x2d, 0x21, 0x18, 0x09, 0x48, 0x0d, 0x22, 0x32, + 0x46, 0x0c, 0xba, 0xaf, 0xaf, 0xba, 0x1a, 0x2c, 0x37, 0x1c, 0x21, 0x17, + 0x29, 0x1f, 0x12, 0x7e, 0x69, 0x72, 0x69, 0x7e, 0x12, 0x1f, 0x29, 0x17, + 0x21, 0x1d, 0x36, 0x2c, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5f, + 0x00, 0x00, 0x02, 0x20, 0x02, 0xba, 0x00, 0x08, 0x00, 0x12, 0x00, 0x4b, + 0xba, 0x00, 0x07, 0x00, 0x13, 0x00, 0x14, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x07, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x1d, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, + 0x08, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x11, + 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x08, 0x10, 0xb9, 0x00, 0x12, 0x00, 0x0b, + 0xf4, 0x30, 0x31, 0x13, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x2b, 0x01, + 0x37, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x11, 0x5f, 0xc3, + 0x80, 0x7e, 0x7e, 0x80, 0xc3, 0xbf, 0x54, 0x55, 0x55, 0x54, 0x6b, 0x02, + 0xba, 0xb0, 0xad, 0xad, 0xb0, 0x49, 0x74, 0x6a, 0x6c, 0x6a, 0x74, 0xfd, + 0xd8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x02, 0x08, + 0x02, 0xba, 0x00, 0x0b, 0x00, 0x57, 0xba, 0x00, 0x09, 0x00, 0x0c, 0x00, + 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x01, 0x10, 0xb9, 0x00, 0x04, 0x00, 0x0b, + 0xf4, 0xba, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x08, 0x2f, 0xb9, 0x00, 0x05, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x00, + 0x10, 0xb9, 0x00, 0x09, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x33, 0x11, 0x21, + 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x5a, 0x01, 0xae, + 0xfe, 0xa6, 0x01, 0x4e, 0xfe, 0xb2, 0x01, 0x5a, 0x02, 0xba, 0x49, 0xeb, + 0x49, 0xf4, 0x49, 0x00, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x02, 0x12, + 0x02, 0xba, 0x00, 0x09, 0x00, 0x4d, 0xba, 0x00, 0x09, 0x00, 0x0a, 0x00, + 0x0b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x01, 0x10, 0xb9, 0x00, 0x04, 0x00, 0x0b, + 0xf4, 0xba, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x08, 0x2f, 0xb9, 0x00, 0x05, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x33, + 0x11, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x11, 0x5a, 0x01, 0xb8, + 0xfe, 0x9c, 0x01, 0x46, 0xfe, 0xba, 0x02, 0xba, 0x49, 0xeb, 0x49, 0xfe, + 0xc3, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0xff, 0xf4, 0x02, 0x0a, + 0x02, 0xc6, 0x00, 0x29, 0x00, 0x76, 0xba, 0x00, 0x20, 0x00, 0x2a, 0x00, + 0x2b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0c, 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, + 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x29, 0x2f, + 0x1b, 0xb9, 0x00, 0x29, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x0c, 0x10, + 0xb9, 0x00, 0x17, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x25, 0x00, 0x17, 0x00, + 0x06, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x25, 0x2f, 0xb8, 0x00, 0x06, 0x10, + 0xb9, 0x00, 0x20, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x20, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x25, 0x10, 0xb9, 0x00, 0x26, 0x00, + 0x0b, 0xf4, 0x30, 0x31, 0x25, 0x23, 0x0e, 0x03, 0x23, 0x22, 0x26, 0x35, + 0x34, 0x36, 0x33, 0x32, 0x1e, 0x02, 0x17, 0x07, 0x2e, 0x03, 0x23, 0x22, + 0x06, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x23, + 0x35, 0x33, 0x11, 0x23, 0x01, 0xbc, 0x05, 0x09, 0x18, 0x25, 0x34, 0x24, + 0x72, 0x6f, 0x7a, 0x7f, 0x31, 0x48, 0x33, 0x22, 0x0b, 0x48, 0x09, 0x17, + 0x21, 0x2e, 0x1f, 0x54, 0x4f, 0x10, 0x25, 0x3b, 0x2b, 0x44, 0x4c, 0x93, + 0xe1, 0x4e, 0x5d, 0x14, 0x26, 0x1d, 0x12, 0xb8, 0xac, 0xb4, 0xba, 0x1a, + 0x2c, 0x37, 0x1c, 0x21, 0x17, 0x29, 0x1f, 0x12, 0x7e, 0x69, 0x6c, 0x35, + 0x57, 0x40, 0x23, 0x52, 0x41, 0x48, 0x43, 0xfe, 0xa7, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x50, 0x00, 0x00, 0x02, 0x08, 0x02, 0xba, 0x00, 0x0b, + 0x00, 0x80, 0xba, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, + 0x00, 0x04, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1d, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x03, 0x2f, 0x1b, 0xb9, 0x00, 0x03, + 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, + 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x01, + 0x00, 0x04, 0x00, 0x03, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x01, 0x2f, 0x41, + 0x03, 0x00, 0x8f, 0x00, 0x01, 0x00, 0x01, 0x71, 0x41, 0x03, 0x00, 0xbf, + 0x00, 0x01, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0x8f, 0x00, 0x01, 0x00, + 0x01, 0x5d, 0xb9, 0x00, 0x06, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x01, 0x21, + 0x11, 0x23, 0x11, 0x33, 0x11, 0x21, 0x11, 0x33, 0x11, 0x23, 0x01, 0xb4, + 0xfe, 0xf0, 0x54, 0x54, 0x01, 0x10, 0x54, 0x54, 0x01, 0x3d, 0xfe, 0xc3, + 0x02, 0xba, 0xfe, 0xcc, 0x01, 0x34, 0xfd, 0x46, 0x00, 0x01, 0x00, 0x54, + 0x00, 0x00, 0x02, 0x04, 0x02, 0xba, 0x00, 0x0b, 0x00, 0x4b, 0xba, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x01, 0x00, 0x0b, + 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x04, 0x00, 0x0b, 0xf4, 0xb8, + 0x00, 0x08, 0xd0, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x30, + 0x31, 0x33, 0x35, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, 0x23, 0x11, 0x33, + 0x15, 0x54, 0xae, 0xae, 0x01, 0xb0, 0xae, 0xae, 0x43, 0x02, 0x34, 0x43, + 0x43, 0xfd, 0xcc, 0x43, 0x00, 0x01, 0x00, 0x4a, 0xff, 0xf4, 0x01, 0xe0, + 0x02, 0xba, 0x00, 0x15, 0x00, 0x3f, 0xba, 0x00, 0x0f, 0x00, 0x16, 0x00, + 0x17, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x15, 0x2f, 0x1b, 0xb9, 0x00, 0x15, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, + 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x0f, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x15, + 0x10, 0xb9, 0x00, 0x14, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x01, 0x11, 0x14, + 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x37, 0x1e, 0x03, 0x33, 0x32, 0x36, + 0x35, 0x11, 0x23, 0x35, 0x01, 0xe0, 0x1e, 0x37, 0x4c, 0x2d, 0x50, 0x68, + 0x10, 0x50, 0x05, 0x11, 0x1d, 0x2a, 0x1d, 0x39, 0x3f, 0xfc, 0x02, 0xba, + 0xfd, 0xfb, 0x2c, 0x48, 0x32, 0x1b, 0x53, 0x4b, 0x11, 0x15, 0x25, 0x1b, + 0x10, 0x41, 0x45, 0x01, 0xad, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x55, + 0x00, 0x00, 0x02, 0x42, 0x02, 0xba, 0x00, 0x0d, 0x00, 0x63, 0xba, 0x00, + 0x0b, 0x00, 0x0e, 0x00, 0x0f, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, + 0xb9, 0x00, 0x09, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x03, 0x2f, 0x1b, 0xb9, 0x00, 0x03, 0x00, 0x0f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0d, 0x2f, 0x1b, 0xb9, 0x00, + 0x0d, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x06, 0x00, 0x04, 0x00, 0x03, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x06, 0x10, 0xb8, 0x00, 0x01, 0xd0, 0x30, + 0x31, 0x01, 0x07, 0x15, 0x23, 0x11, 0x33, 0x11, 0x33, 0x3f, 0x01, 0x33, + 0x03, 0x13, 0x23, 0x01, 0x0d, 0x64, 0x54, 0x54, 0x03, 0x5c, 0xce, 0x65, + 0xf5, 0xfc, 0x62, 0x01, 0x56, 0x76, 0xe0, 0x02, 0xba, 0xfe, 0x94, 0x74, + 0xf8, 0xfe, 0xda, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x78, + 0x00, 0x00, 0x02, 0x17, 0x02, 0xba, 0x00, 0x05, 0x00, 0x35, 0xba, 0x00, + 0x03, 0x00, 0x06, 0x00, 0x07, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x03, 0x00, 0x0b, + 0xf4, 0x30, 0x31, 0x33, 0x11, 0x33, 0x11, 0x21, 0x15, 0x78, 0x54, 0x01, + 0x4b, 0x02, 0xba, 0xfd, 0x8f, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, + 0x00, 0x00, 0x02, 0x14, 0x02, 0xba, 0x00, 0x10, 0x00, 0x71, 0xba, 0x00, + 0x03, 0x00, 0x11, 0x00, 0x12, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0d, 0x2f, 0x1b, + 0xb9, 0x00, 0x0d, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x0f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, + 0x10, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x0d, 0x10, 0xb8, 0x00, 0x02, + 0xd0, 0xb8, 0x00, 0x08, 0x10, 0xb8, 0x00, 0x03, 0xdc, 0xb8, 0x00, 0x09, + 0x10, 0xb8, 0x00, 0x05, 0xd0, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x0b, + 0xd0, 0x30, 0x31, 0x01, 0x35, 0x23, 0x0b, 0x01, 0x23, 0x15, 0x11, 0x23, + 0x11, 0x33, 0x13, 0x33, 0x13, 0x33, 0x11, 0x23, 0x01, 0xc7, 0x08, 0x93, + 0x93, 0x08, 0x4d, 0x6c, 0x7b, 0x06, 0x7b, 0x68, 0x4d, 0x01, 0x5e, 0xdd, + 0xfe, 0x99, 0x01, 0x67, 0xdd, 0xfe, 0xa2, 0x02, 0xba, 0xfe, 0xcc, 0x01, + 0x34, 0xfd, 0x46, 0x00, 0x00, 0x01, 0x00, 0x50, 0x00, 0x00, 0x02, 0x08, + 0x02, 0xba, 0x00, 0x0b, 0x00, 0x61, 0xba, 0x00, 0x0b, 0x00, 0x0c, 0x00, + 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x03, 0x2f, + 0x1b, 0xb9, 0x00, 0x03, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x0f, 0x3e, + 0x59, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, 0x00, 0xd0, 0xb8, 0x00, 0x0b, + 0x10, 0xb8, 0x00, 0x07, 0xd0, 0x30, 0x31, 0x13, 0x23, 0x11, 0x23, 0x11, + 0x33, 0x13, 0x33, 0x11, 0x33, 0x11, 0x23, 0xa3, 0x07, 0x4c, 0x77, 0xee, + 0x07, 0x4c, 0x77, 0x02, 0x4c, 0xfd, 0xb4, 0x02, 0xba, 0xfd, 0xb4, 0x02, + 0x4c, 0xfd, 0x46, 0x00, 0x00, 0x02, 0x00, 0x38, 0xff, 0xf4, 0x02, 0x20, + 0x02, 0xc6, 0x00, 0x13, 0x00, 0x29, 0x00, 0x43, 0xba, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x2b, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, + 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x14, + 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x1f, 0x00, 0x0b, + 0xf4, 0x30, 0x31, 0x05, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, + 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x3e, 0x02, 0x3d, + 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, + 0x02, 0x01, 0x2c, 0x40, 0x5c, 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x40, + 0x5c, 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x2a, 0x3a, 0x26, 0x11, 0x11, + 0x26, 0x3a, 0x2a, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x0c, 0x31, + 0x5c, 0x86, 0x56, 0x55, 0x87, 0x5c, 0x31, 0x31, 0x5c, 0x87, 0x55, 0x56, + 0x86, 0x5c, 0x31, 0x49, 0x21, 0x3c, 0x55, 0x35, 0x72, 0x34, 0x56, 0x3c, + 0x21, 0x21, 0x3c, 0x56, 0x34, 0x72, 0x35, 0x55, 0x3c, 0x21, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x5a, 0x00, 0x00, 0x02, 0x1f, 0x02, 0xba, 0x00, 0x0a, + 0x00, 0x14, 0x00, 0x55, 0xba, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x16, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0c, 0x10, 0xb8, 0x00, 0x08, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, + 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x0b, + 0x00, 0x01, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x2f, 0xb9, + 0x00, 0x09, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x01, 0x10, 0xb9, 0x00, 0x14, + 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x33, 0x11, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x2b, 0x01, 0x19, 0x01, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x2b, 0x01, 0x5a, 0xfe, 0x61, 0x66, 0x66, 0x61, 0xaa, 0xa8, 0x35, 0x3b, + 0x3b, 0x35, 0xa8, 0x02, 0xba, 0x6a, 0x5f, 0x5f, 0x6a, 0xfe, 0xd8, 0x01, + 0x71, 0x35, 0x31, 0x34, 0x31, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0x38, + 0xff, 0x5c, 0x02, 0x20, 0x02, 0xc6, 0x00, 0x19, 0x00, 0x2f, 0x00, 0x61, + 0xba, 0x00, 0x1a, 0x00, 0x30, 0x00, 0x31, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x1a, 0x10, 0xb8, 0x00, 0x0f, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x0f, 0x2f, 0x1b, 0xb9, 0x00, 0x0f, 0x00, 0x1d, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, + 0x05, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x18, 0xd0, 0xb8, 0x00, 0x18, + 0x2f, 0xb9, 0x00, 0x01, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb8, + 0x00, 0x17, 0xd0, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x1a, 0x00, 0x0b, + 0xf4, 0xb8, 0x00, 0x0f, 0x10, 0xb9, 0x00, 0x25, 0x00, 0x0b, 0xf4, 0x30, + 0x31, 0x05, 0x23, 0x22, 0x26, 0x3d, 0x01, 0x2e, 0x03, 0x35, 0x34, 0x3e, + 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x06, 0x07, 0x15, 0x33, 0x27, + 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, + 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x01, 0xeb, 0x75, 0x3b, 0x37, 0x35, 0x4d, + 0x32, 0x18, 0x1c, 0x3c, 0x5c, 0x40, 0x40, 0x5c, 0x3c, 0x1c, 0x62, 0x6a, + 0x97, 0xbf, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x2a, 0x2a, 0x3a, + 0x26, 0x11, 0x11, 0x26, 0x3a, 0xa4, 0x42, 0x34, 0x25, 0x07, 0x37, 0x5b, + 0x7f, 0x4e, 0x55, 0x87, 0x5c, 0x31, 0x31, 0x5c, 0x87, 0x55, 0x9d, 0xbb, + 0x0e, 0x57, 0x9d, 0x21, 0x3c, 0x55, 0x35, 0x72, 0x34, 0x56, 0x3c, 0x21, + 0x21, 0x3c, 0x56, 0x34, 0x72, 0x35, 0x55, 0x3c, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x5a, 0x00, 0x00, 0x02, 0x25, 0x02, 0xba, 0x00, 0x0d, + 0x00, 0x17, 0x00, 0x70, 0xba, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x19, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0c, 0x10, 0xb8, 0x00, 0x0e, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x02, 0x2f, 0x1b, 0xb9, 0x00, 0x02, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, + 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x0f, + 0x3e, 0x59, 0xba, 0x00, 0x17, 0x00, 0x02, 0x00, 0x01, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x17, 0x2f, 0xb9, 0x00, 0x0d, 0x00, 0x08, 0xf4, 0xba, 0x00, + 0x09, 0x00, 0x17, 0x00, 0x0d, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x02, 0x10, + 0xb9, 0x00, 0x16, 0x00, 0x0b, 0xf4, 0x30, 0x31, 0x33, 0x23, 0x11, 0x33, + 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x13, 0x23, 0x03, 0x23, 0x37, 0x32, + 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, 0x01, 0x11, 0xae, 0x54, 0xfe, 0x61, + 0x66, 0x58, 0x54, 0xb2, 0x5e, 0xaa, 0x6f, 0xa8, 0x35, 0x3b, 0x3b, 0x35, + 0xa8, 0x02, 0xba, 0x6a, 0x5f, 0x55, 0x66, 0x08, 0xfe, 0xd2, 0x01, 0x2a, + 0x47, 0x35, 0x31, 0x34, 0x31, 0x35, 0xff, 0x00, 0x00, 0x01, 0x00, 0x2d, + 0xff, 0xf4, 0x02, 0x1e, 0x02, 0xc6, 0x00, 0x2b, 0x00, 0x63, 0xba, 0x00, + 0x07, 0x00, 0x2c, 0x00, 0x2d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x16, 0x2f, 0x1b, 0xb9, 0x00, 0x16, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x07, 0x00, 0x0b, + 0xf4, 0xb8, 0x00, 0x16, 0x10, 0xb9, 0x00, 0x1d, 0x00, 0x0b, 0xf4, 0xba, + 0x00, 0x0e, 0x00, 0x1d, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0e, + 0x10, 0xb8, 0x00, 0x0d, 0xd0, 0xba, 0x00, 0x23, 0x00, 0x16, 0x00, 0x07, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x23, 0x10, 0xb8, 0x00, 0x24, 0xd0, 0x30, + 0x31, 0x05, 0x22, 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, + 0x34, 0x26, 0x2f, 0x01, 0x2e, 0x03, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x1f, 0x01, + 0x1e, 0x03, 0x15, 0x14, 0x06, 0x01, 0x2a, 0x5e, 0x78, 0x27, 0x3d, 0x29, + 0x5b, 0x3f, 0x4c, 0x50, 0x3a, 0x48, 0x4e, 0x33, 0x45, 0x2a, 0x12, 0x7e, + 0x6b, 0x54, 0x73, 0x23, 0x3b, 0x1d, 0x52, 0x41, 0x47, 0x4c, 0x39, 0x4a, + 0x4b, 0x33, 0x46, 0x2b, 0x12, 0x7f, 0x0c, 0x45, 0x36, 0x32, 0x33, 0x32, + 0x46, 0x3f, 0x33, 0x39, 0x0c, 0x0d, 0x09, 0x24, 0x33, 0x3d, 0x21, 0x60, + 0x62, 0x38, 0x33, 0x33, 0x26, 0x30, 0x3c, 0x3c, 0x2f, 0x3b, 0x0d, 0x0d, + 0x09, 0x24, 0x32, 0x3e, 0x22, 0x61, 0x6e, 0x00, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x00, 0x02, 0x3f, 0x02, 0xba, 0x00, 0x07, 0x00, 0x3d, 0xba, 0x00, + 0x02, 0x00, 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x02, 0x2f, 0x1b, + 0xb9, 0x00, 0x02, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x05, 0x10, 0xb9, + 0x00, 0x04, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x00, 0xd0, 0x30, 0x31, 0x01, + 0x11, 0x23, 0x11, 0x23, 0x35, 0x21, 0x15, 0x01, 0x56, 0x54, 0xe9, 0x02, + 0x26, 0x02, 0x71, 0xfd, 0x8f, 0x02, 0x71, 0x49, 0x49, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x50, 0xff, 0xf4, 0x02, 0x08, 0x02, 0xba, 0x00, 0x19, + 0x00, 0x46, 0xba, 0x00, 0x13, 0x00, 0x1a, 0x00, 0x1b, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x19, 0x2f, 0x1b, 0xb9, + 0x00, 0x19, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x0c, 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, 0x1d, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, + 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x06, 0x00, 0x0b, 0xf4, 0x30, 0x31, + 0x13, 0x11, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x11, 0x33, + 0x11, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x11, 0xa4, 0x06, + 0x1a, 0x37, 0x31, 0x31, 0x37, 0x1a, 0x06, 0x54, 0x0f, 0x2f, 0x57, 0x47, + 0x47, 0x57, 0x2f, 0x0f, 0x02, 0xba, 0xfe, 0x5d, 0x33, 0x50, 0x39, 0x1e, + 0x1e, 0x39, 0x50, 0x33, 0x01, 0xa3, 0xfe, 0x71, 0x4e, 0x74, 0x4e, 0x27, + 0x27, 0x4e, 0x74, 0x4e, 0x01, 0x8f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x24, + 0x00, 0x00, 0x02, 0x34, 0x02, 0xba, 0x00, 0x09, 0x00, 0x44, 0xba, 0x00, + 0x04, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, + 0xb9, 0x00, 0x07, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, + 0xb8, 0x00, 0x04, 0xd0, 0x30, 0x31, 0x33, 0x03, 0x33, 0x1b, 0x01, 0x33, + 0x1b, 0x01, 0x33, 0x03, 0xf3, 0xcf, 0x59, 0x63, 0x4b, 0x05, 0x4b, 0x63, + 0x56, 0xcf, 0x02, 0xba, 0xfe, 0xa3, 0xfe, 0xf8, 0x01, 0x08, 0x01, 0x5d, + 0xfd, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x02, 0x35, + 0x02, 0xba, 0x00, 0x11, 0x00, 0x77, 0xba, 0x00, 0x10, 0x00, 0x12, 0x00, + 0x13, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0e, 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x0f, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x04, 0xd0, 0xba, 0x00, 0x06, + 0x00, 0x01, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x06, 0x2f, 0xb8, + 0x00, 0x04, 0x10, 0xb8, 0x00, 0x08, 0xd0, 0xb8, 0x00, 0x06, 0x10, 0xb8, + 0x00, 0x10, 0xd0, 0x30, 0x31, 0x33, 0x03, 0x33, 0x13, 0x17, 0x33, 0x13, + 0x33, 0x13, 0x33, 0x37, 0x13, 0x33, 0x03, 0x23, 0x03, 0x23, 0x03, 0x5a, + 0x37, 0x4b, 0x1d, 0x0f, 0x08, 0x5c, 0x5e, 0x5c, 0x08, 0x0f, 0x1d, 0x49, + 0x37, 0x79, 0x55, 0x08, 0x55, 0x02, 0xba, 0xfe, 0x70, 0xd3, 0x01, 0xad, + 0xfe, 0x53, 0xd3, 0x01, 0x90, 0xfd, 0x46, 0x01, 0xa1, 0xfe, 0x5f, 0x00, + 0x00, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x02, 0x3f, 0x02, 0xba, 0x00, 0x11, + 0x00, 0x77, 0xba, 0x00, 0x04, 0x00, 0x12, 0x00, 0x13, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, + 0x00, 0x09, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x0f, 0x2f, 0x1b, 0xb9, 0x00, 0x0f, 0x00, 0x1d, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, + 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, + 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x04, + 0x00, 0x0f, 0x00, 0x01, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0c, 0x00, 0x09, + 0x00, 0x07, 0x11, 0x12, 0x39, 0xba, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x08, 0x10, 0xb8, 0x00, 0x11, 0xd0, 0x30, + 0x31, 0x21, 0x23, 0x2f, 0x01, 0x23, 0x0f, 0x01, 0x23, 0x13, 0x03, 0x33, + 0x1f, 0x01, 0x33, 0x3f, 0x01, 0x33, 0x03, 0x02, 0x3f, 0x5f, 0x53, 0x5c, + 0x04, 0x5f, 0x58, 0x5c, 0xe4, 0xd7, 0x5f, 0x51, 0x57, 0x04, 0x56, 0x54, + 0x5c, 0xd8, 0x8b, 0x98, 0x98, 0x8b, 0x01, 0x64, 0x01, 0x56, 0x87, 0x8d, + 0x8d, 0x87, 0xfe, 0xab, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x02, 0x47, + 0x02, 0xba, 0x00, 0x0b, 0x00, 0x5a, 0xba, 0x00, 0x05, 0x00, 0x0c, 0x00, + 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x02, 0x2f, 0x1b, 0xb9, 0x00, 0x02, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, + 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x05, 0x2f, 0xb8, 0x00, + 0x01, 0xd0, 0xb8, 0x00, 0x05, 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0x30, 0x31, + 0x21, 0x11, 0x03, 0x33, 0x1f, 0x01, 0x33, 0x3f, 0x01, 0x33, 0x03, 0x11, + 0x01, 0x02, 0xf1, 0x60, 0x64, 0x55, 0x04, 0x57, 0x64, 0x5e, 0xf1, 0x01, + 0x12, 0x01, 0xa8, 0xb6, 0x9f, 0x9f, 0xb6, 0xfe, 0x58, 0xfe, 0xee, 0x00, + 0x00, 0x01, 0x00, 0x30, 0x00, 0x00, 0x02, 0x28, 0x02, 0xba, 0x00, 0x09, + 0x00, 0x53, 0xba, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, + 0x00, 0x05, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x0f, 0x3e, 0x59, 0xb9, + 0x00, 0x08, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x04, + 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x07, 0x00, 0x04, 0x00, 0x08, 0x11, 0x12, + 0x39, 0xba, 0x00, 0x02, 0x00, 0x08, 0x00, 0x07, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x29, 0x01, 0x35, 0x01, 0x21, 0x35, 0x21, 0x15, 0x01, 0x21, 0x02, + 0x28, 0xfe, 0x08, 0x01, 0x8b, 0xfe, 0x86, 0x01, 0xd6, 0xfe, 0x74, 0x01, + 0x9d, 0x4b, 0x02, 0x26, 0x49, 0x4b, 0xfd, 0xda, 0x00, 0x01, 0x00, 0xe1, + 0xff, 0x76, 0x01, 0xf9, 0x02, 0xf8, 0x00, 0x07, 0x00, 0x29, 0xba, 0x00, + 0x05, 0x00, 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x01, + 0x2f, 0xb8, 0x00, 0x00, 0x2f, 0xb8, 0x00, 0x01, 0x10, 0xb9, 0x00, 0x04, + 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x05, 0x00, 0x08, + 0xf4, 0x30, 0x31, 0x17, 0x11, 0x21, 0x15, 0x23, 0x11, 0x33, 0x15, 0xe1, + 0x01, 0x18, 0xd3, 0xd3, 0x8a, 0x03, 0x82, 0x3e, 0xfc, 0xfa, 0x3e, 0x00, + 0x00, 0x01, 0x00, 0x5a, 0xff, 0x76, 0x01, 0xfe, 0x02, 0xf8, 0x00, 0x03, + 0x00, 0x15, 0xba, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x01, 0x2f, 0xb8, 0x00, 0x00, 0x2f, 0x30, 0x31, 0x05, + 0x01, 0x33, 0x01, 0x01, 0xb6, 0xfe, 0xa4, 0x48, 0x01, 0x5c, 0x8a, 0x03, + 0x82, 0xfc, 0x7e, 0x00, 0x00, 0x01, 0x00, 0x5f, 0xff, 0x76, 0x01, 0x77, + 0x02, 0xf8, 0x00, 0x07, 0x00, 0x25, 0xba, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x09, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x07, 0x2f, 0xb8, 0x00, 0x02, + 0x2f, 0xb9, 0x00, 0x03, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x07, 0x10, 0xb9, + 0x00, 0x06, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x01, 0x11, 0x21, 0x35, 0x33, + 0x11, 0x23, 0x35, 0x01, 0x77, 0xfe, 0xe8, 0xd3, 0xd3, 0x02, 0xf8, 0xfc, + 0x7e, 0x3e, 0x03, 0x06, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2d, + 0x01, 0x1f, 0x02, 0x2b, 0x02, 0xba, 0x00, 0x07, 0x00, 0x1e, 0xba, 0x00, + 0x01, 0x00, 0x08, 0x00, 0x09, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1d, + 0x3e, 0x59, 0x30, 0x31, 0x01, 0x03, 0x23, 0x03, 0x27, 0x13, 0x33, 0x13, + 0x01, 0xe9, 0xbd, 0x04, 0xbd, 0x3e, 0xd2, 0x5a, 0xd2, 0x01, 0x1f, 0x01, + 0x56, 0xfe, 0xaa, 0x1f, 0x01, 0x7c, 0xfe, 0x84, 0x00, 0x01, 0x00, 0x3c, + 0xff, 0x57, 0x02, 0x1c, 0xff, 0xa1, 0x00, 0x03, 0x00, 0x17, 0xba, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, 0x00, 0xbb, 0x00, 0x01, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x2b, 0x30, 0x31, 0x17, 0x35, 0x21, + 0x15, 0x3c, 0x01, 0xe0, 0xa9, 0x4a, 0x4a, 0x00, 0x00, 0x01, 0x00, 0xbb, + 0x02, 0x49, 0x01, 0x59, 0x03, 0x0b, 0x00, 0x03, 0x00, 0x23, 0xba, 0x00, + 0x03, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x03, + 0x2f, 0x41, 0x03, 0x00, 0x2f, 0x00, 0x03, 0x00, 0x01, 0x5d, 0x41, 0x03, + 0x00, 0x0f, 0x00, 0x03, 0x00, 0x01, 0x5d, 0x30, 0x31, 0x13, 0x37, 0x17, + 0x07, 0xbb, 0x49, 0x55, 0x34, 0x02, 0xe8, 0x23, 0xaa, 0x18, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x42, 0xff, 0xf4, 0x02, 0x26, 0x02, 0x10, 0x00, 0x21, + 0x00, 0x2f, 0x00, 0x8a, 0xba, 0x00, 0x29, 0x00, 0x30, 0x00, 0x31, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x29, 0x10, 0xb8, 0x00, 0x0d, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1b, 0x2f, 0x1b, 0xb9, 0x00, 0x1b, + 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, + 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, + 0x3e, 0x59, 0xb8, 0x00, 0x07, 0x10, 0xb9, 0x00, 0x22, 0x00, 0x08, 0xf4, + 0xba, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x1b, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x0d, 0x2f, 0xb9, 0x00, 0x29, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x04, 0x00, + 0x22, 0x00, 0x29, 0x11, 0x12, 0x39, 0x7c, 0xb8, 0x00, 0x04, 0x2f, 0x18, + 0xb8, 0x00, 0x1b, 0x10, 0xb9, 0x00, 0x12, 0x00, 0x08, 0xf4, 0xb8, 0x00, + 0x00, 0x10, 0xb9, 0x00, 0x1f, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x21, 0x22, + 0x26, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3b, + 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, + 0x32, 0x16, 0x15, 0x11, 0x33, 0x15, 0x25, 0x32, 0x3e, 0x02, 0x3d, 0x01, + 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0xef, 0x2f, 0x28, 0x05, + 0x05, 0x11, 0x4b, 0x3f, 0x51, 0x60, 0x69, 0x75, 0x6e, 0x40, 0x3b, 0x34, + 0x42, 0x14, 0x36, 0x0a, 0x22, 0x32, 0x40, 0x27, 0x5b, 0x6b, 0x48, 0xfe, + 0xdb, 0x1f, 0x33, 0x26, 0x15, 0x6e, 0x48, 0x42, 0x39, 0x30, 0x24, 0x2d, + 0x33, 0x54, 0x49, 0x48, 0x4e, 0x33, 0x39, 0x39, 0x29, 0x23, 0x28, 0x14, + 0x26, 0x1d, 0x11, 0x5c, 0x52, 0xfe, 0xe4, 0x46, 0x37, 0x0f, 0x19, 0x23, + 0x14, 0x55, 0x28, 0x26, 0x15, 0x28, 0x29, 0x00, 0x00, 0x02, 0x00, 0x5f, + 0xff, 0xf4, 0x02, 0x1c, 0x02, 0xe4, 0x00, 0x10, 0x00, 0x22, 0x00, 0x81, + 0xba, 0x00, 0x11, 0x00, 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x11, 0x10, 0xb8, 0x00, 0x0b, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1f, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, + 0x05, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0f, 0x2f, 0x1b, 0xb9, 0x00, 0x0f, 0x00, + 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x18, 0x00, 0x08, + 0xf4, 0xb8, 0x00, 0x0b, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x08, 0xf4, 0xba, + 0x00, 0x03, 0x00, 0x18, 0x00, 0x11, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0d, + 0x00, 0x11, 0x00, 0x18, 0x11, 0x12, 0x39, 0x30, 0x31, 0x13, 0x33, 0x11, + 0x33, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x27, 0x23, + 0x15, 0x23, 0x37, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x0e, + 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x5f, 0x50, 0x04, 0x32, 0x6d, 0x5f, + 0x6b, 0x6b, 0x5f, 0x6d, 0x32, 0x04, 0x50, 0xd4, 0x46, 0x4d, 0x4d, 0x46, + 0x1b, 0x30, 0x24, 0x15, 0x15, 0x24, 0x30, 0x02, 0xe4, 0xfe, 0xcc, 0x60, + 0x8e, 0x80, 0x80, 0x8e, 0x60, 0x54, 0x3b, 0x55, 0x46, 0x58, 0x46, 0x55, + 0x0e, 0x1b, 0x27, 0x1a, 0xba, 0x1a, 0x27, 0x1b, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x54, 0xff, 0xf4, 0x02, 0x04, 0x02, 0x10, 0x00, 0x22, + 0x00, 0x43, 0xba, 0x00, 0x11, 0x00, 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, + 0x00, 0x0a, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb8, + 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x00, + 0x10, 0xb9, 0x00, 0x1c, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x05, 0x22, 0x2e, + 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, 0x17, 0x07, 0x2e, 0x01, + 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x36, + 0x37, 0x17, 0x0e, 0x01, 0x01, 0x3e, 0x38, 0x57, 0x3c, 0x1f, 0x20, 0x3c, + 0x56, 0x37, 0x4b, 0x5e, 0x16, 0x40, 0x0e, 0x41, 0x30, 0x23, 0x37, 0x26, + 0x13, 0x13, 0x26, 0x38, 0x24, 0x34, 0x44, 0x14, 0x39, 0x17, 0x61, 0x0c, + 0x27, 0x46, 0x64, 0x3d, 0x3d, 0x64, 0x47, 0x26, 0x42, 0x35, 0x22, 0x28, + 0x2c, 0x17, 0x2a, 0x3a, 0x22, 0x58, 0x22, 0x3a, 0x2a, 0x17, 0x30, 0x2a, + 0x27, 0x34, 0x44, 0x00, 0x00, 0x02, 0x00, 0x3c, 0xff, 0xf4, 0x01, 0xf9, + 0x02, 0xe4, 0x00, 0x10, 0x00, 0x22, 0x00, 0x81, 0xba, 0x00, 0x11, 0x00, + 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x10, 0xb8, 0x00, + 0x03, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, 0x2f, + 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x1b, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x03, 0x2f, 0x1b, 0xb9, + 0x00, 0x03, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x0f, 0x3e, 0x59, 0xb8, + 0x00, 0x03, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x09, + 0x10, 0xb9, 0x00, 0x1c, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x01, 0x00, 0x11, + 0x00, 0x1c, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x11, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x25, 0x23, 0x06, 0x23, 0x22, 0x26, 0x35, + 0x34, 0x36, 0x33, 0x32, 0x17, 0x33, 0x11, 0x33, 0x11, 0x23, 0x27, 0x32, + 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x06, 0x1d, 0x01, + 0x14, 0x16, 0x01, 0xa9, 0x04, 0x32, 0x6d, 0x5f, 0x6b, 0x6b, 0x5f, 0x6d, + 0x32, 0x04, 0x50, 0x50, 0x84, 0x1b, 0x30, 0x24, 0x15, 0x15, 0x24, 0x30, + 0x1b, 0x46, 0x4d, 0x4d, 0x54, 0x60, 0x8e, 0x80, 0x80, 0x8e, 0x60, 0x01, + 0x34, 0xfd, 0x1c, 0x3b, 0x0e, 0x1b, 0x27, 0x1a, 0xba, 0x1a, 0x27, 0x1b, + 0x0e, 0x55, 0x46, 0x58, 0x46, 0x55, 0x00, 0x00, 0x00, 0x02, 0x00, 0x43, + 0xff, 0xf4, 0x02, 0x15, 0x02, 0x10, 0x00, 0x1d, 0x00, 0x2a, 0x00, 0x6b, + 0xba, 0x00, 0x1e, 0x00, 0x2b, 0x00, 0x2c, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x1e, 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1b, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, + 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x17, 0x00, 0x08, 0xf4, 0xb8, + 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x1e, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x11, + 0x00, 0x17, 0x00, 0x1e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x2f, 0xb8, + 0x00, 0x10, 0xd0, 0xb8, 0x00, 0x1a, 0xd0, 0xb8, 0x00, 0x1a, 0x2f, 0xb8, + 0x00, 0x11, 0x10, 0xb9, 0x00, 0x24, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x05, + 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x1d, + 0x01, 0x21, 0x15, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, + 0x01, 0x03, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x21, 0x35, 0x34, 0x2e, 0x02, + 0x01, 0x35, 0x38, 0x59, 0x3f, 0x22, 0x23, 0x3e, 0x57, 0x35, 0x34, 0x55, + 0x3c, 0x20, 0xfe, 0x82, 0x16, 0x29, 0x3b, 0x24, 0x34, 0x4c, 0x14, 0x3b, + 0x17, 0x6b, 0x52, 0x21, 0x38, 0x29, 0x17, 0x01, 0x28, 0x15, 0x25, 0x35, + 0x0c, 0x26, 0x47, 0x63, 0x3d, 0x3e, 0x64, 0x47, 0x26, 0x26, 0x43, 0x5c, + 0x37, 0x26, 0x18, 0x22, 0x3a, 0x2a, 0x17, 0x30, 0x2a, 0x28, 0x34, 0x43, + 0x01, 0xda, 0x18, 0x2a, 0x39, 0x22, 0x07, 0x0b, 0x22, 0x38, 0x29, 0x16, + 0x00, 0x01, 0x00, 0x49, 0x00, 0x00, 0x02, 0x20, 0x02, 0xe4, 0x00, 0x14, + 0x00, 0x72, 0xba, 0x00, 0x11, 0x00, 0x15, 0x00, 0x16, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, + 0x00, 0x09, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1b, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x14, 0x2f, 0x1b, 0xb9, 0x00, 0x14, + 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x00, 0x00, 0x08, 0xf4, 0xb8, 0x00, + 0x04, 0x10, 0xb9, 0x00, 0x03, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x09, 0x10, + 0xb9, 0x00, 0x0c, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, + 0x0d, 0xd0, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x10, 0xd0, 0xb8, 0x00, + 0x00, 0x10, 0xb8, 0x00, 0x11, 0xd0, 0x30, 0x31, 0x37, 0x33, 0x11, 0x23, + 0x35, 0x33, 0x35, 0x34, 0x36, 0x3b, 0x01, 0x15, 0x23, 0x15, 0x33, 0x15, + 0x23, 0x11, 0x33, 0x15, 0x21, 0x53, 0xae, 0xb8, 0xb8, 0x37, 0x3b, 0xad, + 0xcf, 0xcf, 0xcf, 0xb8, 0xfe, 0x4a, 0x44, 0x01, 0x7c, 0x44, 0x6a, 0x34, + 0x42, 0x44, 0x9c, 0x44, 0xfe, 0x84, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, + 0xff, 0x2c, 0x02, 0x31, 0x02, 0x4a, 0x00, 0x39, 0x00, 0x46, 0x00, 0x54, + 0x00, 0xc6, 0xba, 0x00, 0x03, 0x00, 0x55, 0x00, 0x56, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x44, 0xd0, 0xb8, 0x00, 0x03, 0x10, + 0xb8, 0x00, 0x47, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x19, 0x2f, 0x1b, 0xb9, 0x00, 0x19, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x21, 0x2f, 0x1b, 0xb9, 0x00, 0x21, 0x00, + 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x03, 0x2f, + 0x1b, 0xb9, 0x00, 0x03, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x21, 0x10, + 0xb9, 0x00, 0x20, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x2b, 0x00, 0x03, 0x00, + 0x19, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x2b, 0x2f, 0x41, 0x03, 0x00, 0x10, + 0x00, 0x2b, 0x00, 0x01, 0x72, 0x41, 0x05, 0x00, 0x60, 0x00, 0x2b, 0x00, + 0x70, 0x00, 0x2b, 0x00, 0x02, 0x5d, 0xba, 0x00, 0x3d, 0x00, 0x03, 0x00, + 0x2b, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x3d, 0x2f, 0x41, 0x05, 0x00, 0x9f, + 0x00, 0x3d, 0x00, 0xaf, 0x00, 0x3d, 0x00, 0x02, 0x71, 0x41, 0x03, 0x00, + 0xd0, 0x00, 0x3d, 0x00, 0x01, 0x5d, 0xb9, 0x00, 0x37, 0x00, 0x0b, 0xf4, + 0xb8, 0x00, 0x03, 0x10, 0xb9, 0x00, 0x43, 0x00, 0x08, 0xf4, 0xb8, 0x00, + 0x2b, 0x10, 0xb9, 0x00, 0x47, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x19, 0x10, + 0xb9, 0x00, 0x4e, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x05, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x35, 0x34, 0x36, 0x37, 0x35, 0x2e, 0x01, 0x35, 0x34, 0x36, + 0x37, 0x35, 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x17, 0x35, + 0x34, 0x36, 0x3b, 0x01, 0x15, 0x23, 0x15, 0x1e, 0x01, 0x15, 0x14, 0x0e, + 0x02, 0x23, 0x22, 0x26, 0x27, 0x0e, 0x03, 0x15, 0x14, 0x16, 0x3b, 0x01, + 0x32, 0x16, 0x07, 0x34, 0x26, 0x2b, 0x01, 0x06, 0x15, 0x14, 0x16, 0x3b, + 0x01, 0x32, 0x36, 0x03, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, + 0x06, 0x1d, 0x01, 0x14, 0x16, 0x02, 0x31, 0x82, 0x82, 0x7d, 0x6d, 0x2c, + 0x28, 0x16, 0x18, 0x35, 0x28, 0x30, 0x35, 0x1c, 0x35, 0x4a, 0x2d, 0x3a, + 0x2c, 0x1c, 0x22, 0x5f, 0x74, 0x1c, 0x1e, 0x1d, 0x34, 0x4b, 0x2d, 0x0d, + 0x18, 0x0c, 0x0c, 0x1a, 0x16, 0x0e, 0x2e, 0x25, 0x72, 0x64, 0x5a, 0x4b, + 0x32, 0x3e, 0xb3, 0x34, 0x36, 0x3f, 0x4e, 0x46, 0x4e, 0xbd, 0x3c, 0x39, + 0x39, 0x3c, 0x3c, 0x38, 0x38, 0x3b, 0x4e, 0x4b, 0x42, 0x3e, 0x2a, 0x2e, + 0x0b, 0x0c, 0x0b, 0x22, 0x1a, 0x28, 0x28, 0x0a, 0x04, 0x15, 0x52, 0x37, + 0x27, 0x42, 0x2f, 0x1a, 0x15, 0x09, 0x1e, 0x28, 0x46, 0x23, 0x18, 0x42, + 0x29, 0x27, 0x42, 0x2f, 0x1a, 0x02, 0x02, 0x02, 0x09, 0x0f, 0x14, 0x0d, + 0x17, 0x0f, 0x4b, 0x43, 0x1f, 0x25, 0x15, 0x31, 0x22, 0x31, 0x2b, 0x01, + 0x53, 0x38, 0x2e, 0x1d, 0x2e, 0x37, 0x37, 0x2e, 0x1d, 0x2e, 0x38, 0x00, + 0x00, 0x01, 0x00, 0x62, 0x00, 0x00, 0x01, 0xfc, 0x02, 0xe4, 0x00, 0x18, + 0x00, 0x6b, 0xba, 0x00, 0x11, 0x00, 0x19, 0x00, 0x1a, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, + 0x00, 0x01, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x1b, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x17, 0x2f, 0x1b, 0xb9, 0x00, 0x17, + 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0c, + 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x08, + 0x10, 0xb9, 0x00, 0x11, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x02, 0x00, 0x11, + 0x00, 0x17, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, 0x02, 0x2f, 0x18, 0x30, + 0x31, 0x13, 0x33, 0x11, 0x33, 0x3e, 0x03, 0x33, 0x32, 0x16, 0x15, 0x11, + 0x23, 0x11, 0x34, 0x26, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x11, 0x23, 0x62, + 0x50, 0x04, 0x08, 0x18, 0x23, 0x30, 0x20, 0x51, 0x62, 0x50, 0x3e, 0x3c, + 0x18, 0x2e, 0x24, 0x16, 0x50, 0x02, 0xe4, 0xfe, 0xcc, 0x13, 0x23, 0x1a, + 0x10, 0x67, 0x5e, 0xfe, 0xb5, 0x01, 0x3d, 0x47, 0x45, 0x0c, 0x18, 0x26, + 0x19, 0xfe, 0x9a, 0x00, 0x00, 0x02, 0x00, 0x6a, 0x00, 0x00, 0x02, 0x22, + 0x02, 0xec, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x63, 0xba, 0x00, 0x0f, 0x00, + 0x18, 0x00, 0x19, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0f, 0x10, 0xb8, 0x00, + 0x03, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x12, 0x2f, + 0x1b, 0xb9, 0x00, 0x12, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x17, 0x2f, 0x1b, 0xb9, 0x00, 0x17, 0x00, 0x0f, 0x3e, + 0x59, 0xb8, 0x00, 0x12, 0x10, 0xb9, 0x00, 0x00, 0x00, 0x07, 0xf4, 0xb9, + 0x00, 0x07, 0x00, 0x06, 0xf4, 0xb8, 0x00, 0x17, 0x10, 0xb9, 0x00, 0x0e, + 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x12, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x08, + 0xf4, 0xb8, 0x00, 0x0e, 0x10, 0xb8, 0x00, 0x14, 0xd0, 0x30, 0x31, 0x01, + 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, + 0x06, 0x01, 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x01, + 0x4c, 0x23, 0x1c, 0x1c, 0x23, 0x23, 0x1c, 0x1c, 0xfe, 0xfb, 0xba, 0xba, + 0x01, 0x0a, 0xae, 0xfe, 0x48, 0x02, 0x76, 0x1d, 0x16, 0x10, 0x16, 0x1d, + 0x1d, 0x16, 0x10, 0x16, 0x1d, 0xfd, 0xce, 0x01, 0x7c, 0x44, 0xfe, 0x40, + 0x44, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5d, 0xff, 0x38, 0x01, 0xc7, + 0x02, 0xec, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x57, 0xba, 0x00, 0x09, 0x00, + 0x19, 0x00, 0x1a, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x09, 0x10, 0xb8, 0x00, + 0x0e, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, + 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x11, 0x3e, + 0x59, 0xb9, 0x00, 0x00, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, + 0x00, 0x03, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x0b, + 0x00, 0x07, 0xf4, 0xb9, 0x00, 0x12, 0x00, 0x06, 0xf4, 0x30, 0x31, 0x17, + 0x33, 0x11, 0x21, 0x35, 0x21, 0x11, 0x14, 0x06, 0x2b, 0x01, 0x01, 0x22, + 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, + 0x66, 0xfa, 0xfe, 0xfd, 0x01, 0x53, 0x37, 0x3b, 0xd8, 0x01, 0x22, 0x23, + 0x1c, 0x1c, 0x23, 0x23, 0x1c, 0x1c, 0x84, 0x02, 0x44, 0x44, 0xfd, 0xaa, + 0x34, 0x42, 0x03, 0x3e, 0x1d, 0x16, 0x10, 0x16, 0x1d, 0x1d, 0x16, 0x10, + 0x16, 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x69, 0x00, 0x00, 0x02, 0x3e, + 0x02, 0xe4, 0x00, 0x0d, 0x00, 0x63, 0xba, 0x00, 0x04, 0x00, 0x0e, 0x00, + 0x0f, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, + 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, + 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0d, 0x2f, 0x1b, 0xb9, 0x00, 0x0d, 0x00, 0x0f, 0x3e, + 0x59, 0xba, 0x00, 0x02, 0x00, 0x05, 0x00, 0x0d, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x02, 0x10, 0xb8, 0x00, 0x0b, 0xd0, 0x30, 0x31, 0x13, 0x33, 0x11, + 0x33, 0x3f, 0x01, 0x33, 0x07, 0x13, 0x23, 0x03, 0x07, 0x15, 0x23, 0x69, + 0x50, 0x04, 0x5a, 0xac, 0x62, 0xd6, 0xef, 0x63, 0xc9, 0x59, 0x50, 0x02, + 0xe4, 0xfe, 0x2d, 0x55, 0x9e, 0xca, 0xfe, 0xc6, 0x01, 0x0c, 0x51, 0xbb, + 0x00, 0x01, 0x00, 0x50, 0x00, 0x00, 0x02, 0x08, 0x02, 0xe4, 0x00, 0x09, + 0x00, 0x47, 0xba, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, + 0x00, 0x04, 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x0f, 0x3e, 0x59, 0xb9, + 0x00, 0x00, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x03, + 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x06, 0xd0, 0x30, + 0x31, 0x37, 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x50, + 0xb4, 0xb4, 0x01, 0x04, 0xb4, 0xfe, 0x48, 0x44, 0x02, 0x5c, 0x44, 0xfd, + 0x60, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x36, 0x00, 0x00, 0x02, 0x22, + 0x02, 0x10, 0x00, 0x24, 0x00, 0xa7, 0xba, 0x00, 0x0a, 0x00, 0x25, 0x00, + 0x26, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, + 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, 0x2f, + 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1c, 0x2f, 0x1b, 0xb9, + 0x00, 0x1c, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x0f, 0x3e, 0x59, 0xb8, + 0x00, 0x07, 0x10, 0xb9, 0x00, 0x20, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x03, + 0x00, 0x20, 0x00, 0x00, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, 0x03, 0x2f, + 0x18, 0xb8, 0x00, 0x0e, 0x10, 0xb9, 0x00, 0x17, 0x00, 0x08, 0xf4, 0xba, + 0x00, 0x0a, 0x00, 0x17, 0x00, 0x1c, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, + 0x0a, 0x2f, 0x18, 0x30, 0x31, 0x33, 0x11, 0x33, 0x15, 0x33, 0x3e, 0x01, + 0x33, 0x32, 0x16, 0x17, 0x33, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x11, + 0x23, 0x11, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, 0x23, 0x11, 0x34, + 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, 0x36, 0x4a, 0x04, 0x0c, 0x2c, 0x2b, + 0x2d, 0x2c, 0x05, 0x03, 0x0e, 0x34, 0x2e, 0x3f, 0x2b, 0x4a, 0x1b, 0x24, + 0x20, 0x28, 0x4a, 0x1b, 0x23, 0x20, 0x29, 0x02, 0x04, 0x3c, 0x1e, 0x2a, + 0x2d, 0x24, 0x23, 0x2e, 0x58, 0x52, 0xfe, 0x9a, 0x01, 0x59, 0x42, 0x33, + 0x29, 0x2a, 0xfe, 0x85, 0x01, 0x59, 0x42, 0x33, 0x29, 0x2a, 0xfe, 0x85, + 0x00, 0x01, 0x00, 0x62, 0x00, 0x00, 0x01, 0xfc, 0x02, 0x10, 0x00, 0x18, + 0x00, 0x6b, 0xba, 0x00, 0x12, 0x00, 0x19, 0x00, 0x1a, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, + 0x00, 0x01, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x1b, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, + 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, + 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x09, + 0x10, 0xb9, 0x00, 0x12, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x03, 0x00, 0x12, + 0x00, 0x00, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, 0x03, 0x2f, 0x18, 0x30, + 0x31, 0x33, 0x11, 0x33, 0x15, 0x33, 0x3e, 0x03, 0x33, 0x32, 0x16, 0x15, + 0x11, 0x23, 0x11, 0x34, 0x26, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x11, 0x62, + 0x50, 0x04, 0x08, 0x18, 0x23, 0x30, 0x20, 0x51, 0x62, 0x50, 0x3e, 0x3c, + 0x18, 0x2e, 0x24, 0x16, 0x02, 0x04, 0x54, 0x13, 0x23, 0x1a, 0x10, 0x67, + 0x5e, 0xfe, 0xb5, 0x01, 0x3d, 0x47, 0x45, 0x0c, 0x18, 0x26, 0x19, 0xfe, + 0x9a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x42, 0xff, 0xf4, 0x02, 0x16, + 0x02, 0x10, 0x00, 0x13, 0x00, 0x21, 0x00, 0x43, 0xba, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x23, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, + 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, + 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x14, + 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x1b, 0x00, 0x08, + 0xf4, 0x30, 0x31, 0x05, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, + 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, 0x01, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x2c, 0x36, + 0x57, 0x3d, 0x20, 0x20, 0x3d, 0x57, 0x36, 0x36, 0x57, 0x3d, 0x20, 0x20, + 0x3d, 0x57, 0x36, 0x43, 0x52, 0x52, 0x43, 0x43, 0x52, 0x52, 0x0c, 0x26, + 0x47, 0x63, 0x3e, 0x3d, 0x64, 0x47, 0x26, 0x26, 0x47, 0x64, 0x3d, 0x3e, + 0x63, 0x47, 0x26, 0x45, 0x50, 0x54, 0x4a, 0x54, 0x50, 0x50, 0x54, 0x4a, + 0x54, 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5f, 0xff, 0x38, 0x02, 0x1c, + 0x02, 0x10, 0x00, 0x10, 0x00, 0x22, 0x00, 0x81, 0xba, 0x00, 0x11, 0x00, + 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x10, 0xb8, 0x00, + 0x0b, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1b, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x10, 0x2f, 0x1b, 0xb9, + 0x00, 0x10, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x0f, 0x3e, 0x59, 0xb8, + 0x00, 0x05, 0x10, 0xb9, 0x00, 0x18, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x0b, + 0x10, 0xb9, 0x00, 0x11, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x02, 0x00, 0x18, + 0x00, 0x11, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0e, 0x00, 0x11, 0x00, 0x18, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x13, 0x33, 0x15, 0x33, 0x36, 0x33, 0x32, + 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x27, 0x23, 0x11, 0x23, 0x13, 0x32, + 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, + 0x1e, 0x02, 0x5f, 0x50, 0x04, 0x32, 0x6d, 0x5f, 0x6b, 0x6b, 0x5f, 0x6d, + 0x32, 0x04, 0x50, 0xd4, 0x46, 0x4d, 0x4d, 0x46, 0x1b, 0x30, 0x24, 0x15, + 0x15, 0x24, 0x30, 0x02, 0x04, 0x54, 0x60, 0x8e, 0x80, 0x80, 0x8e, 0x60, + 0xfe, 0xe4, 0x01, 0x03, 0x55, 0x46, 0x58, 0x46, 0x55, 0x0e, 0x1b, 0x27, + 0x1a, 0xba, 0x1a, 0x27, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3c, + 0xff, 0x38, 0x01, 0xf9, 0x02, 0x10, 0x00, 0x10, 0x00, 0x22, 0x00, 0x81, + 0xba, 0x00, 0x11, 0x00, 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x11, 0x10, 0xb8, 0x00, 0x03, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x0d, 0x2f, 0x1b, 0xb9, 0x00, 0x0d, 0x00, 0x1b, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, + 0x09, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x03, 0x2f, 0x1b, 0xb9, 0x00, 0x03, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, + 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x03, 0x10, 0xb9, 0x00, 0x11, 0x00, 0x08, + 0xf4, 0xb8, 0x00, 0x09, 0x10, 0xb9, 0x00, 0x1c, 0x00, 0x08, 0xf4, 0xba, + 0x00, 0x00, 0x00, 0x11, 0x00, 0x1c, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0c, + 0x00, 0x1c, 0x00, 0x11, 0x11, 0x12, 0x39, 0x30, 0x31, 0x25, 0x23, 0x06, + 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x17, 0x33, 0x35, 0x33, + 0x11, 0x23, 0x03, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0xa9, 0x04, 0x32, 0x6d, 0x5f, + 0x6b, 0x6b, 0x5f, 0x6d, 0x32, 0x04, 0x50, 0x50, 0x84, 0x1b, 0x30, 0x24, + 0x15, 0x15, 0x24, 0x30, 0x1b, 0x46, 0x4d, 0x4d, 0x54, 0x60, 0x8e, 0x80, + 0x80, 0x8e, 0x60, 0x54, 0xfd, 0x34, 0x01, 0x03, 0x0e, 0x1b, 0x27, 0x1a, + 0xba, 0x1a, 0x27, 0x1b, 0x0e, 0x55, 0x46, 0x58, 0x46, 0x55, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x4d, 0x00, 0x00, 0x02, 0x2f, 0x02, 0x04, 0x00, 0x14, + 0x00, 0x72, 0xba, 0x00, 0x11, 0x00, 0x15, 0x00, 0x16, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, + 0x00, 0x04, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1b, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x14, 0x2f, 0x1b, 0xb9, 0x00, 0x14, + 0x00, 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x00, 0x00, 0x08, 0xf4, 0xb8, 0x00, + 0x04, 0x10, 0xb9, 0x00, 0x03, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x0a, 0x10, + 0xb9, 0x00, 0x0d, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x06, 0x00, 0x0d, 0x00, + 0x00, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, 0x06, 0x2f, 0x18, 0xb8, 0x00, + 0x00, 0x10, 0xb8, 0x00, 0x11, 0xd0, 0x30, 0x31, 0x37, 0x33, 0x11, 0x23, + 0x35, 0x33, 0x15, 0x33, 0x3e, 0x01, 0x3b, 0x01, 0x15, 0x23, 0x22, 0x06, + 0x1d, 0x01, 0x33, 0x15, 0x21, 0x4d, 0x97, 0x97, 0xe7, 0x05, 0x10, 0x59, + 0x45, 0x48, 0x61, 0x45, 0x55, 0xc8, 0xfe, 0x51, 0x44, 0x01, 0x7c, 0x44, + 0x82, 0x3d, 0x45, 0x50, 0x50, 0x41, 0xdf, 0x44, 0x00, 0x01, 0x00, 0x43, + 0xff, 0xf4, 0x02, 0x0c, 0x02, 0x10, 0x00, 0x33, 0x00, 0x6b, 0xba, 0x00, + 0x23, 0x00, 0x34, 0x00, 0x35, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x1a, 0x2f, 0x1b, 0xb9, 0x00, 0x1a, 0x00, 0x1b, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x1a, 0x10, 0xb9, + 0x00, 0x23, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x10, 0x00, 0x23, 0x00, 0x00, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x07, 0x00, 0x08, + 0xf4, 0xba, 0x00, 0x04, 0x00, 0x10, 0x00, 0x07, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x2b, 0x00, 0x07, 0x00, 0x1a, 0x11, 0x12, 0x39, 0xba, 0x00, 0x1e, + 0x00, 0x23, 0x00, 0x2b, 0x11, 0x12, 0x39, 0x30, 0x31, 0x05, 0x22, 0x26, + 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x2e, 0x02, 0x2f, + 0x01, 0x2e, 0x03, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, 0x17, 0x07, + 0x2e, 0x03, 0x23, 0x22, 0x06, 0x15, 0x14, 0x1e, 0x02, 0x1f, 0x01, 0x1e, + 0x03, 0x15, 0x14, 0x06, 0x01, 0x32, 0x51, 0x75, 0x29, 0x36, 0x25, 0x58, + 0x3e, 0x3c, 0x4d, 0x0f, 0x1a, 0x20, 0x12, 0x51, 0x1b, 0x3f, 0x34, 0x23, + 0x1f, 0x38, 0x4c, 0x2d, 0x46, 0x67, 0x25, 0x34, 0x09, 0x1b, 0x27, 0x34, + 0x22, 0x3d, 0x41, 0x0f, 0x1a, 0x21, 0x11, 0x51, 0x1c, 0x3e, 0x34, 0x23, + 0x77, 0x0c, 0x37, 0x2e, 0x2f, 0x27, 0x2a, 0x2b, 0x2e, 0x14, 0x1b, 0x10, + 0x09, 0x03, 0x0c, 0x04, 0x0e, 0x1f, 0x34, 0x2a, 0x27, 0x39, 0x27, 0x13, + 0x2c, 0x27, 0x31, 0x0b, 0x17, 0x13, 0x0c, 0x2a, 0x28, 0x14, 0x1b, 0x10, + 0x09, 0x03, 0x0c, 0x04, 0x0e, 0x1f, 0x34, 0x2a, 0x4d, 0x54, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x27, 0x00, 0x00, 0x02, 0x0e, 0x02, 0xba, 0x00, 0x13, + 0x00, 0x64, 0xba, 0x00, 0x11, 0x00, 0x14, 0x00, 0x15, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, + 0x00, 0x0b, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1b, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, + 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x05, 0x00, + 0x08, 0xf4, 0xb8, 0x00, 0x06, 0x10, 0xb8, 0x00, 0x0d, 0xd0, 0xb8, 0x00, + 0x05, 0x10, 0xb8, 0x00, 0x10, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, + 0x11, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x21, 0x22, 0x26, 0x35, 0x11, 0x23, + 0x35, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x33, 0x15, 0x33, 0x15, 0x23, 0x11, + 0x33, 0x15, 0x01, 0x45, 0x3b, 0x37, 0xac, 0x80, 0x1a, 0x15, 0x4d, 0xeb, + 0xeb, 0xeb, 0x42, 0x34, 0x01, 0x4a, 0x44, 0x15, 0x1a, 0x87, 0xb6, 0x44, + 0xfe, 0x84, 0x44, 0x00, 0x00, 0x01, 0x00, 0x5c, 0xff, 0xf4, 0x01, 0xf6, + 0x02, 0x04, 0x00, 0x18, 0x00, 0x69, 0xba, 0x00, 0x0f, 0x00, 0x19, 0x00, + 0x1a, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x15, 0x2f, 0x1b, 0xb9, 0x00, 0x15, 0x00, + 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, + 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x18, 0x2f, 0x1b, 0xb9, 0x00, 0x18, 0x00, 0x0f, 0x3e, + 0x59, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x0f, 0x00, 0x08, 0xf4, 0xba, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0a, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, + 0x2f, 0x30, 0x31, 0x25, 0x23, 0x0e, 0x03, 0x23, 0x22, 0x26, 0x35, 0x11, + 0x33, 0x11, 0x14, 0x16, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x11, 0x33, 0x11, + 0x23, 0x01, 0xa6, 0x04, 0x08, 0x18, 0x23, 0x30, 0x20, 0x51, 0x62, 0x50, + 0x3e, 0x3c, 0x18, 0x2e, 0x24, 0x16, 0x50, 0x50, 0x54, 0x13, 0x23, 0x1a, + 0x10, 0x67, 0x5e, 0x01, 0x4b, 0xfe, 0xc3, 0x47, 0x45, 0x0c, 0x18, 0x25, + 0x1a, 0x01, 0x66, 0xfd, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, + 0x00, 0x00, 0x02, 0x18, 0x02, 0x04, 0x00, 0x09, 0x00, 0x44, 0xba, 0x00, + 0x04, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1b, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, + 0xb9, 0x00, 0x08, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, + 0xb8, 0x00, 0x05, 0xd0, 0x30, 0x31, 0x33, 0x03, 0x33, 0x1f, 0x01, 0x33, + 0x3f, 0x01, 0x33, 0x03, 0xf9, 0xb9, 0x51, 0x4a, 0x50, 0x04, 0x50, 0x4a, + 0x4f, 0xb9, 0x02, 0x04, 0xd8, 0xe9, 0xe9, 0xd8, 0xfd, 0xfc, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x02, 0x3a, 0x02, 0x04, 0x00, 0x0f, + 0x00, 0x7a, 0xba, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x11, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, + 0x00, 0x00, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1b, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, + 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0f, + 0x2f, 0x1b, 0xb9, 0x00, 0x0f, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x0f, + 0x3e, 0x59, 0xb8, 0x00, 0x0f, 0x10, 0xb8, 0x00, 0x02, 0xd0, 0xb8, 0x00, + 0x02, 0x2f, 0xb8, 0x00, 0x06, 0xd0, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, + 0x0d, 0xd0, 0x30, 0x31, 0x13, 0x33, 0x13, 0x33, 0x13, 0x33, 0x13, 0x33, + 0x13, 0x33, 0x03, 0x23, 0x03, 0x23, 0x03, 0x23, 0x1e, 0x47, 0x3b, 0x09, + 0x58, 0x58, 0x58, 0x09, 0x3b, 0x45, 0x4f, 0x68, 0x52, 0x08, 0x54, 0x68, + 0x02, 0x04, 0xfe, 0x42, 0x01, 0xbe, 0xfe, 0x42, 0x01, 0xbe, 0xfd, 0xfc, + 0x01, 0xb0, 0xfe, 0x50, 0x00, 0x01, 0x00, 0x3d, 0x00, 0x00, 0x02, 0x1c, + 0x02, 0x04, 0x00, 0x11, 0x00, 0x77, 0xba, 0x00, 0x0e, 0x00, 0x12, 0x00, + 0x13, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x02, 0x2f, 0x1b, 0xb9, 0x00, 0x02, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, + 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, + 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0c, 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, 0x0f, 0x3e, + 0x59, 0xba, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x0e, 0x00, 0x08, 0x00, 0x0c, 0x11, 0x12, 0x39, 0xba, 0x00, 0x01, + 0x00, 0x05, 0x00, 0x0e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x01, 0x10, 0xb8, + 0x00, 0x0a, 0xd0, 0x30, 0x31, 0x33, 0x13, 0x27, 0x33, 0x1f, 0x01, 0x33, + 0x3f, 0x01, 0x33, 0x07, 0x13, 0x23, 0x2f, 0x01, 0x23, 0x0f, 0x01, 0x3d, + 0xc0, 0xbb, 0x60, 0x4e, 0x3e, 0x04, 0x3c, 0x4d, 0x5c, 0xbd, 0xc2, 0x60, + 0x57, 0x3b, 0x04, 0x39, 0x54, 0x01, 0x06, 0xfe, 0x6d, 0x56, 0x56, 0x6d, + 0xfd, 0xfe, 0xf9, 0x79, 0x52, 0x52, 0x79, 0x00, 0x00, 0x01, 0x00, 0x35, + 0xff, 0x38, 0x02, 0x23, 0x02, 0x04, 0x00, 0x11, 0x00, 0x58, 0xba, 0x00, + 0x0f, 0x00, 0x12, 0x00, 0x13, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x0c, 0x2f, 0x1b, 0xb9, 0x00, 0x0c, 0x00, 0x1b, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x08, 0x2f, 0x1b, 0xb9, 0x00, 0x08, 0x00, 0x11, 0x3e, 0x59, + 0xb9, 0x00, 0x09, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x0f, 0x00, 0x0c, 0x00, + 0x08, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0f, 0x10, 0xb8, 0x00, 0x0b, 0xd0, + 0x30, 0x31, 0x01, 0x33, 0x01, 0x0e, 0x03, 0x2b, 0x01, 0x35, 0x33, 0x37, + 0x03, 0x33, 0x1f, 0x01, 0x33, 0x37, 0x01, 0xd3, 0x50, 0xff, 0x00, 0x09, + 0x16, 0x1e, 0x2a, 0x1d, 0x4c, 0x78, 0x3a, 0xd0, 0x52, 0x57, 0x4d, 0x04, + 0x4d, 0x02, 0x04, 0xfd, 0x8b, 0x16, 0x21, 0x15, 0x0b, 0x44, 0x8e, 0x01, + 0xfa, 0xd8, 0xc4, 0xc4, 0x00, 0x01, 0x00, 0x55, 0x00, 0x00, 0x02, 0x03, + 0x02, 0x04, 0x00, 0x09, 0x00, 0x53, 0xba, 0x00, 0x02, 0x00, 0x0a, 0x00, + 0x0b, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, + 0x0f, 0x3e, 0x59, 0xb9, 0x00, 0x08, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x04, + 0x10, 0xb9, 0x00, 0x03, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x01, 0x00, 0x08, + 0x00, 0x03, 0x11, 0x12, 0x39, 0xba, 0x00, 0x06, 0x00, 0x03, 0x00, 0x08, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x33, 0x35, 0x01, 0x21, 0x35, 0x21, 0x15, + 0x01, 0x21, 0x15, 0x55, 0x01, 0x4d, 0xfe, 0xbe, 0x01, 0x99, 0xfe, 0xb3, + 0x01, 0x57, 0x4d, 0x01, 0x73, 0x44, 0x4d, 0xfe, 0x8d, 0x44, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x69, 0xff, 0x76, 0x01, 0xef, 0x02, 0xf8, 0x00, 0x3b, + 0x00, 0x47, 0xba, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x3d, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x21, 0x2f, 0xb8, 0x00, 0x00, 0x2f, 0xb8, 0x00, 0x21, + 0x10, 0xb9, 0x00, 0x24, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x0f, 0x00, 0x24, + 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0f, 0x2f, 0xb9, 0x00, 0x12, + 0x00, 0x08, 0xf4, 0xba, 0x00, 0x2e, 0x00, 0x12, 0x00, 0x0f, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x39, 0x00, 0x08, 0xf4, 0x30, + 0x31, 0x05, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x3e, 0x02, 0x37, 0x3e, 0x01, + 0x35, 0x34, 0x26, 0x2b, 0x01, 0x35, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, + 0x27, 0x2e, 0x03, 0x3d, 0x01, 0x34, 0x36, 0x3b, 0x01, 0x15, 0x23, 0x15, + 0x14, 0x16, 0x17, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, + 0x15, 0x14, 0x06, 0x07, 0x0e, 0x01, 0x1d, 0x01, 0x33, 0x15, 0x01, 0x3f, + 0x2a, 0x2a, 0x0b, 0x10, 0x14, 0x09, 0x11, 0x0d, 0x46, 0x44, 0x4e, 0x4e, + 0x44, 0x46, 0x0d, 0x11, 0x09, 0x14, 0x10, 0x0b, 0x2a, 0x2a, 0xb0, 0xbf, + 0x18, 0x10, 0x11, 0x1e, 0x3b, 0x33, 0x33, 0x3b, 0x1e, 0x11, 0x10, 0x18, + 0xbf, 0x8a, 0x2f, 0x23, 0x3f, 0x1b, 0x28, 0x20, 0x19, 0x0b, 0x14, 0x1d, + 0x10, 0x26, 0x23, 0x3e, 0x23, 0x26, 0x10, 0x1d, 0x14, 0x0b, 0x19, 0x1f, + 0x29, 0x1b, 0x3f, 0x23, 0x2f, 0x3e, 0x4d, 0x29, 0x2c, 0x15, 0x16, 0x2f, + 0x20, 0x2a, 0x34, 0x07, 0x04, 0x07, 0x34, 0x2a, 0x20, 0x2f, 0x16, 0x15, + 0x2c, 0x29, 0x4d, 0x3e, 0x00, 0x01, 0x01, 0x09, 0xff, 0x76, 0x01, 0x4f, + 0x02, 0xf8, 0x00, 0x03, 0x00, 0x15, 0xba, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x05, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x01, 0x2f, 0xb8, 0x00, 0x00, + 0x2f, 0x30, 0x31, 0x05, 0x11, 0x33, 0x11, 0x01, 0x09, 0x46, 0x8a, 0x03, + 0x82, 0xfc, 0x7e, 0x00, 0x00, 0x01, 0x00, 0x69, 0xff, 0x76, 0x01, 0xef, + 0x02, 0xf8, 0x00, 0x3b, 0x00, 0x47, 0xba, 0x00, 0x25, 0x00, 0x3c, 0x00, + 0x3d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x3b, 0x2f, 0xb8, 0x00, 0x22, + 0x2f, 0xb8, 0x00, 0x3b, 0x10, 0xb9, 0x00, 0x3a, 0x00, 0x08, 0xf4, 0xba, + 0x00, 0x12, 0x00, 0x3a, 0x00, 0x22, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x12, + 0x2f, 0xb9, 0x00, 0x0f, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x22, 0x10, 0xb9, + 0x00, 0x23, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x2e, 0x00, 0x0f, 0x00, 0x12, + 0x11, 0x12, 0x39, 0x30, 0x31, 0x01, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x0e, + 0x02, 0x07, 0x0e, 0x01, 0x15, 0x14, 0x16, 0x3b, 0x01, 0x15, 0x23, 0x22, + 0x06, 0x15, 0x14, 0x16, 0x17, 0x1e, 0x03, 0x1d, 0x01, 0x14, 0x06, 0x2b, + 0x01, 0x35, 0x33, 0x35, 0x34, 0x26, 0x27, 0x2e, 0x01, 0x35, 0x34, 0x36, + 0x37, 0x35, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, 0x3e, 0x01, 0x3d, 0x01, + 0x23, 0x35, 0x01, 0x19, 0x2a, 0x2a, 0x0b, 0x10, 0x14, 0x09, 0x11, 0x0d, + 0x46, 0x44, 0x4e, 0x4e, 0x44, 0x46, 0x0d, 0x11, 0x09, 0x14, 0x10, 0x0b, + 0x2a, 0x2a, 0xb0, 0xbf, 0x18, 0x10, 0x11, 0x1e, 0x3b, 0x33, 0x33, 0x3b, + 0x1e, 0x11, 0x10, 0x18, 0xbf, 0x02, 0xf8, 0x2f, 0x23, 0x3f, 0x1b, 0x29, + 0x1f, 0x19, 0x0b, 0x14, 0x1d, 0x10, 0x26, 0x23, 0x3e, 0x23, 0x26, 0x10, + 0x1d, 0x14, 0x0b, 0x19, 0x20, 0x28, 0x1b, 0x3f, 0x23, 0x2f, 0x3e, 0x4d, + 0x29, 0x2c, 0x15, 0x16, 0x2f, 0x20, 0x2a, 0x34, 0x07, 0x04, 0x07, 0x34, + 0x2a, 0x20, 0x2f, 0x16, 0x15, 0x2c, 0x29, 0x4d, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x34, 0x00, 0xc5, 0x02, 0x24, 0x01, 0x9d, 0x00, 0x19, + 0x00, 0x49, 0xba, 0x00, 0x10, 0x00, 0x1a, 0x00, 0x1b, 0x11, 0x12, 0x39, + 0x00, 0xbb, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x04, 0x2b, 0xb8, + 0x00, 0x06, 0x10, 0xb8, 0x00, 0x00, 0xdc, 0xba, 0x00, 0x09, 0x00, 0x06, + 0x00, 0x00, 0x11, 0x12, 0x39, 0x7d, 0xb8, 0x00, 0x09, 0x2f, 0x18, 0xb8, + 0x00, 0x00, 0x10, 0xb9, 0x00, 0x13, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x16, + 0x00, 0x0d, 0x00, 0x13, 0x11, 0x12, 0x39, 0x7c, 0xb8, 0x00, 0x16, 0x2f, + 0x18, 0x30, 0x31, 0x25, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, + 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x3e, + 0x01, 0x37, 0x17, 0x0e, 0x01, 0x01, 0x92, 0x26, 0x35, 0x1d, 0x1a, 0x28, + 0x13, 0x1d, 0x27, 0x10, 0x3d, 0x11, 0x46, 0x3b, 0x26, 0x34, 0x1c, 0x1c, + 0x28, 0x13, 0x21, 0x26, 0x0d, 0x3d, 0x16, 0x48, 0xc5, 0x2b, 0x22, 0x22, + 0x26, 0x3e, 0x4d, 0x0e, 0x5c, 0x64, 0x2a, 0x21, 0x24, 0x26, 0x01, 0x4b, + 0x3f, 0x0e, 0x6b, 0x55, 0x00, 0x02, 0x00, 0xe2, 0xff, 0x4a, 0x01, 0x76, + 0x02, 0x0d, 0x00, 0x05, 0x00, 0x13, 0x00, 0x32, 0xba, 0x00, 0x06, 0x00, + 0x14, 0x00, 0x15, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x06, 0x10, 0xb8, 0x00, + 0x02, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0d, 0x2f, + 0x1b, 0xb9, 0x00, 0x0d, 0x00, 0x1b, 0x3e, 0x59, 0xb9, 0x00, 0x06, 0x00, + 0x09, 0xf4, 0xb9, 0x00, 0x03, 0x00, 0x07, 0xf4, 0x30, 0x31, 0x05, 0x35, + 0x13, 0x33, 0x13, 0x15, 0x03, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x01, 0x00, 0x1c, 0x20, 0x1c, 0x2c, + 0x29, 0x21, 0x21, 0x29, 0x29, 0x21, 0x21, 0xb6, 0xcb, 0x01, 0x06, 0xfe, + 0xfa, 0xcb, 0x02, 0x39, 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x22, 0x1a, 0x12, + 0x1a, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x54, 0xff, 0x8e, 0x02, 0x04, + 0x02, 0x76, 0x00, 0x1a, 0x00, 0x22, 0x00, 0x73, 0xba, 0x00, 0x1e, 0x00, + 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1e, 0x10, 0xb8, 0x00, + 0x01, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, + 0x1b, 0xb9, 0x00, 0x07, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x0f, 0x3e, + 0x59, 0xb8, 0x00, 0x07, 0x10, 0xb8, 0x00, 0x09, 0xdc, 0xb8, 0x00, 0x07, + 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0xb8, 0x00, 0x07, 0x10, 0xb9, 0x00, 0x1f, + 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x11, 0xd0, 0xb8, 0x00, 0x01, 0x10, 0xb9, + 0x00, 0x1e, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x12, 0xd0, 0xb8, 0x00, 0x01, + 0x10, 0xb8, 0x00, 0x19, 0xd0, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x1a, + 0xdc, 0x30, 0x31, 0x05, 0x35, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, 0x35, + 0x33, 0x15, 0x1e, 0x01, 0x17, 0x07, 0x2e, 0x01, 0x27, 0x11, 0x3e, 0x01, + 0x37, 0x17, 0x0e, 0x01, 0x07, 0x15, 0x03, 0x14, 0x16, 0x17, 0x11, 0x0e, + 0x01, 0x15, 0x01, 0x17, 0x5e, 0x65, 0x66, 0x5d, 0x3e, 0x41, 0x52, 0x14, + 0x40, 0x0d, 0x34, 0x27, 0x2b, 0x3b, 0x11, 0x39, 0x15, 0x56, 0x44, 0xab, + 0x38, 0x36, 0x36, 0x38, 0x72, 0x69, 0x0d, 0x8e, 0x70, 0x70, 0x8e, 0x0d, + 0x69, 0x67, 0x05, 0x41, 0x30, 0x22, 0x23, 0x2b, 0x05, 0xfe, 0x70, 0x05, + 0x2e, 0x26, 0x27, 0x30, 0x42, 0x05, 0x67, 0x01, 0x48, 0x3b, 0x53, 0x0b, + 0x01, 0x8a, 0x0b, 0x53, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x34, + 0x00, 0x00, 0x02, 0x26, 0x02, 0xc6, 0x00, 0x2c, 0x00, 0x63, 0xba, 0x00, + 0x19, 0x00, 0x2d, 0x00, 0x2e, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x12, 0x2f, 0x1b, 0xb9, 0x00, 0x12, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x12, 0x10, 0xb9, + 0x00, 0x19, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x2a, + 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x08, 0x00, 0x19, 0x00, 0x2a, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x08, 0x2f, 0xb9, 0x00, 0x09, 0x00, 0x08, 0xf4, 0xb8, + 0x00, 0x1f, 0xd0, 0xb8, 0x00, 0x08, 0x10, 0xb8, 0x00, 0x22, 0xd0, 0x30, + 0x31, 0x33, 0x35, 0x3e, 0x01, 0x35, 0x34, 0x26, 0x27, 0x23, 0x35, 0x33, + 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, 0x17, 0x07, 0x2e, + 0x01, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x17, 0x33, 0x15, 0x23, 0x16, + 0x15, 0x14, 0x0e, 0x02, 0x07, 0x15, 0x21, 0x15, 0x4b, 0x2a, 0x25, 0x03, + 0x02, 0x61, 0x4e, 0x0b, 0x15, 0x20, 0x3d, 0x57, 0x36, 0x50, 0x69, 0x21, + 0x3f, 0x1c, 0x4b, 0x39, 0x42, 0x4d, 0x13, 0x0b, 0xc9, 0xb6, 0x03, 0x0f, + 0x18, 0x1d, 0x0e, 0x01, 0x80, 0x69, 0x11, 0x44, 0x2f, 0x0d, 0x18, 0x0c, + 0x45, 0x22, 0x44, 0x2a, 0x2e, 0x4e, 0x38, 0x1f, 0x3f, 0x33, 0x2d, 0x29, + 0x2d, 0x42, 0x4d, 0x29, 0x42, 0x20, 0x45, 0x14, 0x13, 0x1f, 0x33, 0x29, + 0x1e, 0x09, 0x05, 0x50, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x15, 0x02, 0x0c, + 0x02, 0xa5, 0x00, 0x1b, 0x00, 0x29, 0x00, 0x7f, 0xba, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x2b, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1c, 0xd0, 0x00, 0xb8, + 0x00, 0x0e, 0x2f, 0xba, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x2a, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x00, 0x2f, 0xb8, 0x00, 0x0e, 0x10, 0xb9, 0x00, 0x23, + 0x00, 0x08, 0xf4, 0xba, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x02, 0x10, 0xb8, 0x00, 0x05, 0xd0, 0xb8, 0x00, 0x00, + 0x10, 0xb9, 0x00, 0x1c, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x0c, 0x00, 0x0e, + 0x00, 0x1c, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0c, 0x10, 0xb8, 0x00, 0x09, + 0xd0, 0xba, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x1c, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x10, 0x10, 0xb8, 0x00, 0x13, 0xd0, 0xba, 0x00, 0x1a, 0x00, 0x00, + 0x00, 0x23, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1a, 0x10, 0xb8, 0x00, 0x17, + 0xd0, 0x30, 0x31, 0x25, 0x22, 0x27, 0x07, 0x27, 0x37, 0x26, 0x35, 0x34, + 0x37, 0x27, 0x37, 0x17, 0x36, 0x33, 0x32, 0x17, 0x37, 0x17, 0x07, 0x16, + 0x15, 0x14, 0x07, 0x17, 0x07, 0x27, 0x06, 0x27, 0x32, 0x36, 0x3d, 0x01, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x2c, 0x34, + 0x2a, 0x45, 0x3d, 0x4a, 0x36, 0x36, 0x4a, 0x3d, 0x45, 0x2a, 0x34, 0x34, + 0x2a, 0x45, 0x3d, 0x4a, 0x36, 0x36, 0x4a, 0x3d, 0x45, 0x2a, 0x34, 0x36, + 0x41, 0x41, 0x36, 0x36, 0x41, 0x41, 0x77, 0x14, 0x76, 0x23, 0x7e, 0x3e, + 0x69, 0x69, 0x3e, 0x7e, 0x23, 0x76, 0x14, 0x14, 0x76, 0x23, 0x7e, 0x3e, + 0x69, 0x69, 0x3e, 0x7e, 0x23, 0x76, 0x14, 0x43, 0x41, 0x42, 0x40, 0x42, + 0x41, 0x41, 0x42, 0x40, 0x42, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16, + 0x00, 0x00, 0x02, 0x42, 0x02, 0xba, 0x00, 0x13, 0x00, 0x76, 0xba, 0x00, + 0x08, 0x00, 0x14, 0x00, 0x15, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, + 0xb9, 0x00, 0x0a, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x0f, 0x3e, 0x59, + 0xb9, 0x00, 0x00, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x03, 0x00, 0x06, 0x00, + 0x13, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x03, 0x2f, 0xb9, 0x00, 0x04, 0x00, + 0x0b, 0xf4, 0xb8, 0x00, 0x08, 0xd0, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, + 0x0c, 0xd0, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x0f, 0xd0, 0xb8, 0x00, + 0x00, 0x10, 0xb8, 0x00, 0x10, 0xd0, 0x30, 0x31, 0x37, 0x33, 0x35, 0x23, + 0x35, 0x33, 0x03, 0x33, 0x13, 0x33, 0x13, 0x33, 0x03, 0x33, 0x15, 0x23, + 0x15, 0x33, 0x15, 0x21, 0x4b, 0xb9, 0xb9, 0x8d, 0xc2, 0x5d, 0xb8, 0x04, + 0xb8, 0x5b, 0xc2, 0x8d, 0xb9, 0xb9, 0xfe, 0x3e, 0x45, 0xba, 0x45, 0x01, + 0x76, 0xfe, 0x8a, 0x01, 0x76, 0xfe, 0x8a, 0x45, 0xba, 0x45, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x09, 0xff, 0x76, 0x01, 0x4f, 0x02, 0xf8, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x25, 0xba, 0x00, 0x04, 0x00, 0x08, 0x00, 0x09, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, 0x00, 0xd0, 0x00, 0xb8, + 0x00, 0x01, 0x2f, 0xb8, 0x00, 0x04, 0x2f, 0xba, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x03, 0x2b, 0x30, 0x31, 0x01, 0x11, 0x33, 0x11, 0x03, 0x11, 0x33, + 0x11, 0x01, 0x09, 0x46, 0x46, 0x46, 0x01, 0x91, 0x01, 0x67, 0xfe, 0x99, + 0xfd, 0xe5, 0x01, 0x67, 0xfe, 0x99, 0x00, 0x00, 0x00, 0x02, 0x00, 0x51, + 0xff, 0x65, 0x02, 0x0b, 0x02, 0xc6, 0x00, 0x39, 0x00, 0x4b, 0x00, 0x7a, + 0xba, 0x00, 0x12, 0x00, 0x4c, 0x00, 0x4d, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x12, 0x10, 0xb8, 0x00, 0x46, 0xd0, 0x00, 0xb8, 0x00, 0x05, 0x2f, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x22, 0x2f, 0x1b, 0xb9, 0x00, 0x22, + 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x0c, 0x00, + 0x08, 0xf4, 0xb8, 0x00, 0x22, 0x10, 0xb9, 0x00, 0x29, 0x00, 0x08, 0xf4, + 0xba, 0x00, 0x12, 0x00, 0x29, 0x00, 0x05, 0x11, 0x12, 0x39, 0xba, 0x00, + 0x2f, 0x00, 0x22, 0x00, 0x0c, 0x11, 0x12, 0x39, 0xba, 0x00, 0x40, 0x00, + 0x29, 0x00, 0x05, 0x11, 0x12, 0x39, 0xba, 0x00, 0x1a, 0x00, 0x2f, 0x00, + 0x40, 0x11, 0x12, 0x39, 0xba, 0x00, 0x49, 0x00, 0x22, 0x00, 0x0c, 0x11, + 0x12, 0x39, 0xba, 0x00, 0x36, 0x00, 0x49, 0x00, 0x12, 0x11, 0x12, 0x39, + 0x30, 0x31, 0x25, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x37, 0x1e, + 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2f, 0x01, 0x2e, 0x01, 0x35, + 0x34, 0x36, 0x37, 0x35, 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, + 0x16, 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x1f, + 0x01, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, 0x27, 0x34, + 0x26, 0x2f, 0x01, 0x26, 0x27, 0x0e, 0x01, 0x15, 0x14, 0x16, 0x1f, 0x01, + 0x16, 0x17, 0x3e, 0x01, 0x01, 0xe7, 0x1d, 0x35, 0x4a, 0x2d, 0x2e, 0x59, + 0x23, 0x2f, 0x18, 0x3e, 0x26, 0x39, 0x40, 0x37, 0x33, 0x40, 0x53, 0x4a, + 0x3a, 0x36, 0x27, 0x25, 0x1d, 0x35, 0x4a, 0x2d, 0x2e, 0x59, 0x23, 0x2f, + 0x18, 0x3e, 0x26, 0x39, 0x40, 0x37, 0x33, 0x40, 0x53, 0x4a, 0x3a, 0x36, + 0x27, 0x25, 0x2b, 0x3a, 0x3e, 0x3f, 0x11, 0x11, 0x1f, 0x24, 0x3a, 0x3e, + 0x3f, 0x11, 0x11, 0x1f, 0x24, 0x03, 0x24, 0x3a, 0x2a, 0x16, 0x1a, 0x1e, + 0x38, 0x14, 0x17, 0x2f, 0x29, 0x26, 0x2d, 0x0e, 0x12, 0x17, 0x51, 0x33, + 0x30, 0x4a, 0x15, 0x05, 0x18, 0x44, 0x28, 0x24, 0x3a, 0x2a, 0x16, 0x1a, + 0x1e, 0x38, 0x14, 0x17, 0x2f, 0x29, 0x26, 0x2d, 0x0e, 0x12, 0x17, 0x51, + 0x33, 0x30, 0x4a, 0x15, 0x05, 0x18, 0x44, 0xdc, 0x2b, 0x34, 0x11, 0x11, + 0x04, 0x07, 0x15, 0x37, 0x23, 0x2b, 0x34, 0x11, 0x11, 0x04, 0x07, 0x15, + 0x37, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x96, 0x02, 0x6a, 0x01, 0xc2, + 0x02, 0xd4, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x2d, 0xba, 0x00, 0x0b, 0x00, + 0x1c, 0x00, 0x1d, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x10, 0xb8, 0x00, + 0x11, 0xd0, 0x00, 0xba, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x2b, 0xb8, + 0x00, 0x00, 0x10, 0xb8, 0x00, 0x0e, 0xd0, 0xb8, 0x00, 0x07, 0x10, 0xb8, + 0x00, 0x15, 0xd0, 0x30, 0x31, 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, + 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, + 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0xcf, 0x1f, 0x1a, + 0x1a, 0x1f, 0x1f, 0x1a, 0x1a, 0x9b, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, 0x1a, + 0x1a, 0x02, 0x6a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, + 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x12, 0x02, 0x58, 0x02, 0xa8, 0x00, 0x13, + 0x00, 0x29, 0x00, 0x44, 0x00, 0x6d, 0xba, 0x00, 0x00, 0x00, 0x45, 0x00, + 0x46, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, 0xb8, 0x00, 0x00, 0x10, + 0xb8, 0x00, 0x2a, 0xd0, 0x00, 0xb8, 0x00, 0x0a, 0x2f, 0xb8, 0x00, 0x00, + 0x2f, 0xb9, 0x00, 0x14, 0x00, 0x03, 0xf4, 0xb8, 0x00, 0x0a, 0x10, 0xb9, + 0x00, 0x1f, 0x00, 0x03, 0xf4, 0xb8, 0x00, 0x14, 0x10, 0xb8, 0x00, 0x2a, + 0xdc, 0xb8, 0x00, 0x1f, 0x10, 0xb8, 0x00, 0x30, 0xdc, 0xb9, 0x00, 0x37, + 0x00, 0x03, 0xf4, 0xb8, 0x00, 0x2a, 0x10, 0xb9, 0x00, 0x3e, 0x00, 0x03, + 0xf4, 0xba, 0x00, 0x34, 0x00, 0x37, 0x00, 0x3e, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x34, 0x2f, 0xba, 0x00, 0x41, 0x00, 0x37, 0x00, 0x3e, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x41, 0x2f, 0x30, 0x31, 0x25, 0x22, 0x2e, 0x02, 0x35, + 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, + 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, + 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x37, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x17, 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, 0x01, 0x2c, 0x3f, 0x6d, + 0x51, 0x2f, 0x2f, 0x51, 0x6d, 0x3f, 0x3f, 0x6d, 0x51, 0x2f, 0x2f, 0x51, + 0x6d, 0x3f, 0x33, 0x57, 0x3f, 0x24, 0x24, 0x3f, 0x57, 0x33, 0x33, 0x57, + 0x3f, 0x24, 0x24, 0x3f, 0x57, 0x38, 0x49, 0x51, 0x52, 0x48, 0x30, 0x3d, + 0x11, 0x35, 0x0b, 0x22, 0x1c, 0x27, 0x2b, 0x2a, 0x29, 0x1e, 0x24, 0x0e, + 0x32, 0x11, 0x41, 0x12, 0x2e, 0x56, 0x7a, 0x4d, 0x4c, 0x7b, 0x56, 0x2e, + 0x2e, 0x56, 0x7b, 0x4c, 0x4d, 0x7a, 0x56, 0x2e, 0x37, 0x26, 0x43, 0x5a, + 0x33, 0x3c, 0x33, 0x5a, 0x43, 0x26, 0x26, 0x43, 0x5a, 0x33, 0x3c, 0x33, + 0x5a, 0x43, 0x26, 0x62, 0x61, 0x51, 0x52, 0x60, 0x2c, 0x24, 0x1d, 0x18, + 0x1c, 0x33, 0x29, 0x39, 0x2a, 0x33, 0x1e, 0x19, 0x1f, 0x23, 0x2e, 0x00, + 0x00, 0x02, 0x00, 0x8a, 0x01, 0x5d, 0x01, 0xcf, 0x02, 0xc6, 0x00, 0x20, + 0x00, 0x2b, 0x00, 0x9a, 0xba, 0x00, 0x0d, 0x00, 0x2c, 0x00, 0x2d, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0d, 0x10, 0xb8, 0x00, 0x21, 0xd0, 0x00, 0xb8, + 0x00, 0x20, 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1a, 0x2f, + 0x1b, 0xb9, 0x00, 0x1a, 0x00, 0x1d, 0x3e, 0x59, 0x41, 0x03, 0x00, 0xa0, + 0x00, 0x20, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0x10, 0x00, 0x20, 0x00, + 0x01, 0x5d, 0x41, 0x03, 0x00, 0x20, 0x00, 0x20, 0x00, 0x01, 0x71, 0x41, + 0x03, 0x00, 0xd0, 0x00, 0x20, 0x00, 0x01, 0x5d, 0xb8, 0x00, 0x20, 0x10, + 0xb9, 0x00, 0x1f, 0x00, 0x03, 0xf4, 0xba, 0x00, 0x03, 0x00, 0x1f, 0x00, + 0x20, 0x11, 0x12, 0x39, 0xba, 0x00, 0x27, 0x00, 0x1f, 0x00, 0x20, 0x11, + 0x12, 0x39, 0x7c, 0xb8, 0x00, 0x27, 0x2f, 0x18, 0xb9, 0x00, 0x07, 0x00, + 0x03, 0xf4, 0xba, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x1f, 0x11, 0x12, 0x39, + 0xb8, 0x00, 0x0d, 0x2f, 0xb8, 0x00, 0x1a, 0x10, 0xb9, 0x00, 0x11, 0x00, + 0x03, 0xf4, 0xb8, 0x00, 0x0d, 0x10, 0xb9, 0x00, 0x21, 0x00, 0x03, 0xf4, + 0x30, 0x31, 0x01, 0x22, 0x26, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, + 0x35, 0x34, 0x36, 0x3b, 0x01, 0x35, 0x34, 0x23, 0x22, 0x06, 0x07, 0x27, + 0x3e, 0x03, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x33, 0x15, 0x27, 0x22, 0x06, + 0x1d, 0x01, 0x14, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x01, 0xad, 0x21, 0x1c, + 0x02, 0x04, 0x0b, 0x37, 0x2f, 0x36, 0x39, 0x4f, 0x48, 0x49, 0x4d, 0x23, + 0x2f, 0x0b, 0x2a, 0x07, 0x19, 0x22, 0x2c, 0x1c, 0x40, 0x49, 0x26, 0xb0, + 0x2a, 0x2c, 0x3d, 0x28, 0x3c, 0x01, 0x65, 0x1c, 0x19, 0x17, 0x26, 0x36, + 0x2d, 0x36, 0x32, 0x1c, 0x4e, 0x1d, 0x17, 0x22, 0x0d, 0x19, 0x14, 0x0c, + 0x42, 0x3d, 0xaa, 0x38, 0x95, 0x18, 0x17, 0x0a, 0x31, 0x23, 0x1e, 0x29, + 0x00, 0x02, 0x00, 0x4a, 0x00, 0x38, 0x02, 0x16, 0x01, 0xe4, 0x00, 0x06, + 0x00, 0x0d, 0x00, 0x00, 0x25, 0x27, 0x35, 0x37, 0x17, 0x07, 0x17, 0x07, + 0x27, 0x35, 0x37, 0x17, 0x07, 0x17, 0x01, 0xfd, 0xce, 0xce, 0x19, 0x94, + 0x94, 0xfe, 0xce, 0xce, 0x19, 0x94, 0x94, 0x38, 0xae, 0x50, 0xae, 0x39, + 0x9d, 0x9d, 0x39, 0xae, 0x50, 0xae, 0x39, 0x9d, 0x9d, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x3e, 0x00, 0x4e, 0x02, 0x0a, 0x01, 0x53, 0x00, 0x05, + 0x00, 0x17, 0xba, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x11, 0x12, 0x39, + 0x00, 0xbb, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00, 0x04, 0x2b, 0x30, + 0x31, 0x25, 0x35, 0x21, 0x35, 0x21, 0x11, 0x01, 0xc5, 0xfe, 0x79, 0x01, + 0xcc, 0x4e, 0xc1, 0x44, 0xfe, 0xfb, 0x00, 0x00, 0x00, 0x04, 0x00, 0x75, + 0x01, 0x5a, 0x01, 0xe3, 0x02, 0xc6, 0x00, 0x13, 0x00, 0x29, 0x00, 0x36, + 0x00, 0x3e, 0x00, 0xed, 0xba, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x40, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, + 0x35, 0xd0, 0xb8, 0x00, 0x00, 0x10, 0xb8, 0x00, 0x37, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, + 0x00, 0x1d, 0x3e, 0x59, 0xb9, 0x00, 0x1f, 0x00, 0x0a, 0xf4, 0xba, 0x00, + 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x11, 0x12, 0x39, 0x7c, 0xb8, 0x00, 0x2b, + 0x2f, 0x18, 0x41, 0x07, 0x00, 0xa0, 0x00, 0x2b, 0x00, 0xb0, 0x00, 0x2b, + 0x00, 0xc0, 0x00, 0x2b, 0x00, 0x03, 0x71, 0x41, 0x09, 0x00, 0xa0, 0x00, + 0x2b, 0x00, 0xb0, 0x00, 0x2b, 0x00, 0xc0, 0x00, 0x2b, 0x00, 0xd0, 0x00, + 0x2b, 0x00, 0x04, 0x5d, 0x41, 0x03, 0x00, 0x10, 0x00, 0x2b, 0x00, 0x01, + 0x72, 0x41, 0x03, 0x00, 0xf0, 0x00, 0x2b, 0x00, 0x01, 0x5d, 0x41, 0x05, + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x10, 0x00, 0x2b, 0x00, 0x02, 0x71, 0x41, + 0x03, 0x00, 0x30, 0x00, 0x2b, 0x00, 0x01, 0x5d, 0xba, 0x00, 0x14, 0x00, + 0x2b, 0x00, 0x3f, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x14, 0x2f, 0x41, 0x03, + 0x00, 0x40, 0x00, 0x14, 0x00, 0x01, 0x71, 0xb9, 0x00, 0x00, 0x00, 0x0a, + 0xf4, 0xba, 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x14, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x2c, 0x2f, 0xb9, 0x00, 0x3d, 0x00, 0x0a, 0xf4, 0xba, 0x00, 0x3e, + 0x00, 0x3d, 0x00, 0x2b, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x3e, 0x2f, 0xb9, + 0x00, 0x36, 0x00, 0x0a, 0xf4, 0xba, 0x00, 0x32, 0x00, 0x3e, 0x00, 0x36, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x2b, 0x10, 0xb8, 0x00, 0x34, 0xd0, 0x30, + 0x31, 0x01, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, + 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, + 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x27, + 0x23, 0x35, 0x33, 0x32, 0x16, 0x15, 0x14, 0x07, 0x17, 0x23, 0x27, 0x23, + 0x37, 0x32, 0x3d, 0x01, 0x34, 0x2b, 0x01, 0x15, 0x01, 0x2c, 0x26, 0x43, + 0x32, 0x1c, 0x1c, 0x32, 0x43, 0x26, 0x26, 0x43, 0x31, 0x1d, 0x1d, 0x31, + 0x43, 0x26, 0x1d, 0x31, 0x24, 0x15, 0x15, 0x24, 0x31, 0x1d, 0x1d, 0x31, + 0x24, 0x15, 0x15, 0x24, 0x31, 0x01, 0x28, 0x55, 0x1c, 0x1f, 0x25, 0x2e, + 0x2d, 0x27, 0x1d, 0x24, 0x1a, 0x1a, 0x24, 0x01, 0x5a, 0x1c, 0x30, 0x43, + 0x27, 0x27, 0x43, 0x30, 0x1c, 0x1c, 0x30, 0x43, 0x27, 0x27, 0x43, 0x30, + 0x1c, 0x29, 0x13, 0x22, 0x30, 0x1e, 0x14, 0x1e, 0x30, 0x22, 0x13, 0x13, + 0x22, 0x30, 0x1e, 0x14, 0x1e, 0x30, 0x22, 0x13, 0x31, 0xb9, 0x1f, 0x1a, + 0x27, 0x0d, 0x4c, 0x46, 0x1d, 0x18, 0x07, 0x18, 0x37, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xa0, 0x02, 0x7d, 0x01, 0xb8, 0x02, 0xc1, 0x00, 0x03, + 0x00, 0x44, 0xba, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x03, 0x2f, 0x41, 0x03, 0x00, 0xc0, 0x00, 0x03, 0x00, + 0x01, 0x71, 0x41, 0x03, 0x00, 0xcf, 0x00, 0x03, 0x00, 0x01, 0x5d, 0x41, + 0x03, 0x00, 0x30, 0x00, 0x03, 0x00, 0x01, 0x5d, 0x41, 0x03, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x01, 0x71, 0x41, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, + 0x01, 0x71, 0xb9, 0x00, 0x00, 0x00, 0x05, 0xf4, 0x30, 0x31, 0x13, 0x21, + 0x15, 0x21, 0xa0, 0x01, 0x18, 0xfe, 0xe8, 0x02, 0xc1, 0x44, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x81, 0x01, 0x70, 0x01, 0xd7, 0x02, 0xc6, 0x00, 0x13, + 0x00, 0x1f, 0x00, 0x43, 0xba, 0x00, 0x00, 0x00, 0x20, 0x00, 0x21, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x14, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x2f, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, 0x00, 0x0a, + 0x00, 0x1d, 0x3e, 0x59, 0x41, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, + 0x5d, 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x14, 0x00, 0x03, 0xf4, 0xb8, + 0x00, 0x0a, 0x10, 0xb9, 0x00, 0x1a, 0x00, 0x03, 0xf4, 0x30, 0x31, 0x01, + 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, + 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, + 0x15, 0x14, 0x16, 0x01, 0x2c, 0x24, 0x3e, 0x2f, 0x1a, 0x1a, 0x2f, 0x3e, + 0x24, 0x24, 0x3e, 0x2f, 0x1a, 0x1a, 0x2f, 0x3e, 0x24, 0x2e, 0x37, 0x37, + 0x2e, 0x2e, 0x37, 0x37, 0x01, 0x70, 0x1a, 0x2e, 0x3f, 0x24, 0x24, 0x3f, + 0x2e, 0x1a, 0x1a, 0x2e, 0x3f, 0x24, 0x24, 0x3f, 0x2e, 0x1a, 0x40, 0x3e, + 0x2d, 0x2d, 0x3e, 0x3e, 0x2d, 0x2d, 0x3e, 0x00, 0x00, 0x02, 0x00, 0x3e, + 0x00, 0x00, 0x02, 0x1a, 0x02, 0x6a, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x43, + 0xba, 0x00, 0x00, 0x00, 0x10, 0x00, 0x11, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x0c, 0xd0, 0x00, 0xbb, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00, 0x04, + 0x2b, 0xbb, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04, 0x2b, 0xba, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, + 0x2f, 0xb8, 0x00, 0x03, 0x10, 0xb8, 0x00, 0x07, 0xd0, 0xb8, 0x00, 0x02, + 0x10, 0xb8, 0x00, 0x0a, 0xd0, 0x30, 0x31, 0x25, 0x35, 0x23, 0x35, 0x33, + 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x05, 0x35, 0x21, 0x15, 0x01, + 0x06, 0xc8, 0xc8, 0x4c, 0xc8, 0xc8, 0xfe, 0xec, 0x01, 0xdc, 0x98, 0xc7, + 0x44, 0xc7, 0xc7, 0x44, 0xc7, 0x98, 0x44, 0x44, 0x00, 0x01, 0x00, 0xa1, + 0x01, 0x49, 0x01, 0xb6, 0x02, 0xc0, 0x00, 0x1b, 0x00, 0x57, 0xba, 0x00, + 0x13, 0x00, 0x1c, 0x00, 0x1d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, + 0xb9, 0x00, 0x01, 0x00, 0x13, 0x3e, 0x59, 0xb9, 0x00, 0x1a, 0x00, 0x03, + 0xf4, 0xb8, 0x00, 0x02, 0xd0, 0xba, 0x00, 0x03, 0x00, 0x13, 0x00, 0x1a, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x13, 0x10, 0xb9, 0x00, 0x0a, 0x00, 0x03, + 0xf4, 0xba, 0x00, 0x19, 0x00, 0x0a, 0x00, 0x01, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x01, 0x21, 0x35, 0x37, 0x3e, 0x01, 0x3d, 0x01, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, + 0x0f, 0x01, 0x33, 0x01, 0xb6, 0xfe, 0xf0, 0x82, 0x1d, 0x21, 0x21, 0x20, + 0x23, 0x23, 0x08, 0x36, 0x06, 0x15, 0x21, 0x2e, 0x1e, 0x3e, 0x42, 0x35, + 0x2a, 0x61, 0xcd, 0x01, 0x49, 0x39, 0x69, 0x18, 0x2f, 0x1b, 0x06, 0x1a, + 0x1f, 0x22, 0x18, 0x14, 0x12, 0x20, 0x19, 0x0f, 0x3d, 0x30, 0x2c, 0x41, + 0x20, 0x4b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x97, 0x01, 0x43, 0x01, 0xae, + 0x02, 0xc0, 0x00, 0x2a, 0x00, 0x6e, 0xba, 0x00, 0x0e, 0x00, 0x2b, 0x00, + 0x2c, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0e, 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x1b, 0x2f, 0x1b, 0xb9, 0x00, 0x1b, 0x00, + 0x13, 0x3e, 0x59, 0xba, 0x00, 0x28, 0x00, 0x0e, 0x00, 0x1b, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x28, 0x2f, 0x41, 0x05, 0x00, 0x40, 0x00, 0x28, 0x00, + 0x50, 0x00, 0x28, 0x00, 0x02, 0x72, 0xb9, 0x00, 0x00, 0x00, 0x03, 0xf4, + 0xb8, 0x00, 0x0e, 0x10, 0xb9, 0x00, 0x07, 0x00, 0x03, 0xf4, 0xba, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x28, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x1b, 0x10, + 0xb9, 0x00, 0x22, 0x00, 0x03, 0xf4, 0x30, 0x31, 0x01, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, + 0x16, 0x15, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x34, + 0x2b, 0x01, 0x35, 0x01, 0x1a, 0x26, 0x25, 0x23, 0x1e, 0x1d, 0x28, 0x0e, + 0x2b, 0x11, 0x3d, 0x32, 0x39, 0x49, 0x2e, 0x20, 0x22, 0x32, 0x4d, 0x42, + 0x37, 0x3e, 0x13, 0x2f, 0x0e, 0x28, 0x23, 0x26, 0x27, 0x4d, 0x2d, 0x02, + 0x22, 0x1d, 0x17, 0x04, 0x19, 0x1b, 0x18, 0x15, 0x22, 0x19, 0x24, 0x32, + 0x2d, 0x24, 0x2a, 0x07, 0x03, 0x06, 0x2c, 0x28, 0x31, 0x3b, 0x28, 0x1a, + 0x22, 0x16, 0x1c, 0x20, 0x1d, 0x06, 0x37, 0x33, 0x00, 0x01, 0x00, 0xff, + 0x02, 0x49, 0x01, 0x9d, 0x03, 0x0b, 0x00, 0x03, 0x00, 0x23, 0xba, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x05, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x2f, 0x41, 0x03, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x01, 0x5d, 0x41, 0x03, + 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x5d, 0x30, 0x31, 0x01, 0x27, 0x37, + 0x17, 0x01, 0x33, 0x34, 0x55, 0x49, 0x02, 0x49, 0x18, 0xaa, 0x23, 0x00, + 0x00, 0x01, 0x00, 0x62, 0xff, 0x38, 0x01, 0xf6, 0x02, 0x04, 0x00, 0x1a, + 0x00, 0x82, 0xba, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x1c, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, + 0x00, 0x01, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x0b, 0x2f, 0x1b, 0xb9, 0x00, 0x0b, 0x00, 0x1b, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0e, 0x2f, 0x1b, 0xb9, 0x00, 0x0e, + 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, + 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, 0x11, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x15, 0x2f, 0x1b, 0xb9, 0x00, 0x15, 0x00, 0x0f, + 0x3e, 0x59, 0xb9, 0x00, 0x05, 0x00, 0x08, 0xf4, 0xba, 0x00, 0x0f, 0x00, + 0x01, 0x00, 0x05, 0x11, 0x12, 0x39, 0x7c, 0xb8, 0x00, 0x0f, 0x2f, 0x18, + 0xba, 0x00, 0x17, 0x00, 0x05, 0x00, 0x15, 0x11, 0x12, 0x39, 0x30, 0x31, + 0x17, 0x11, 0x33, 0x11, 0x14, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x11, 0x33, + 0x11, 0x23, 0x35, 0x23, 0x0e, 0x03, 0x23, 0x22, 0x27, 0x23, 0x17, 0x15, + 0x62, 0x50, 0x77, 0x18, 0x2d, 0x23, 0x15, 0x50, 0x50, 0x04, 0x09, 0x17, + 0x21, 0x2d, 0x1e, 0x4b, 0x1c, 0x04, 0x07, 0xc8, 0x02, 0xcc, 0xfe, 0xc3, + 0x8c, 0x0c, 0x18, 0x25, 0x1a, 0x01, 0x66, 0xfd, 0xfc, 0x54, 0x14, 0x23, + 0x1a, 0x0f, 0x34, 0x54, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2d, + 0xff, 0x6b, 0x01, 0xf8, 0x02, 0xba, 0x00, 0x11, 0x00, 0x34, 0xba, 0x00, + 0x11, 0x00, 0x12, 0x00, 0x13, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x11, + 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0a, 0x2f, 0x1b, 0xb9, + 0x00, 0x0a, 0x00, 0x1d, 0x3e, 0x59, 0xb9, 0x00, 0x0f, 0x00, 0x08, 0xf4, + 0xb8, 0x00, 0x00, 0xdc, 0xb8, 0x00, 0x11, 0x10, 0xb8, 0x00, 0x0d, 0xd0, + 0x30, 0x31, 0x25, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x3b, 0x01, + 0x11, 0x23, 0x11, 0x23, 0x11, 0x23, 0x01, 0x0e, 0x2f, 0x51, 0x3e, 0x23, + 0x23, 0x3e, 0x51, 0x2f, 0xea, 0x48, 0x5a, 0x48, 0xf6, 0x22, 0x3c, 0x53, + 0x31, 0x31, 0x53, 0x3c, 0x22, 0xfc, 0xb1, 0x03, 0x0f, 0xfc, 0xf1, 0x00, + 0x00, 0x01, 0x00, 0xe2, 0x00, 0xeb, 0x01, 0x76, 0x01, 0x75, 0x00, 0x0d, + 0x00, 0x17, 0xba, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0f, 0x11, 0x12, 0x39, + 0x00, 0xbb, 0x00, 0x07, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x2b, 0x30, + 0x31, 0x25, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, + 0x01, 0x14, 0x06, 0x01, 0x2c, 0x29, 0x21, 0x21, 0x29, 0x29, 0x21, 0x21, + 0xeb, 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x00, + 0x00, 0x01, 0x00, 0xd5, 0xff, 0x31, 0x01, 0xa7, 0x00, 0x14, 0x00, 0x1b, + 0x00, 0x34, 0xba, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1d, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x10, 0x2f, 0xb8, 0x00, 0x14, 0xdc, 0x41, 0x07, 0x00, + 0x0f, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x2f, 0x00, 0x14, 0x00, + 0x03, 0x5d, 0xb8, 0x00, 0x0d, 0xd0, 0xb8, 0x00, 0x07, 0xdc, 0xb9, 0x00, + 0x00, 0x00, 0x03, 0xf4, 0x30, 0x31, 0x05, 0x22, 0x26, 0x27, 0x37, 0x1e, + 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2f, 0x01, 0x37, 0x33, 0x07, + 0x17, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x0e, 0x02, 0x01, 0x38, 0x29, + 0x2f, 0x0b, 0x26, 0x09, 0x1e, 0x16, 0x13, 0x19, 0x1a, 0x2a, 0x1c, 0x13, + 0x32, 0x10, 0x03, 0x13, 0x14, 0x1d, 0x27, 0x12, 0x1f, 0x28, 0xcf, 0x1b, + 0x0e, 0x29, 0x0b, 0x11, 0x0f, 0x10, 0x0e, 0x15, 0x06, 0x04, 0x61, 0x51, + 0x03, 0x06, 0x22, 0x20, 0x15, 0x20, 0x14, 0x0a, 0x00, 0x01, 0x00, 0x9a, + 0x01, 0x49, 0x01, 0xbe, 0x02, 0xba, 0x00, 0x0a, 0x00, 0x5b, 0xba, 0x00, + 0x02, 0x00, 0x0b, 0x00, 0x0c, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, 0xb9, 0x00, 0x07, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, + 0xb9, 0x00, 0x00, 0x00, 0x13, 0x3e, 0x59, 0xb9, 0x00, 0x01, 0x00, 0x03, + 0xf4, 0xb8, 0x00, 0x07, 0x10, 0xb9, 0x00, 0x03, 0x00, 0x03, 0xf4, 0xba, + 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x04, + 0x10, 0xb9, 0x00, 0x05, 0x00, 0x03, 0xf4, 0xb8, 0x00, 0x01, 0x10, 0xb8, + 0x00, 0x08, 0xd0, 0x30, 0x31, 0x13, 0x35, 0x33, 0x11, 0x07, 0x27, 0x37, + 0x33, 0x11, 0x33, 0x15, 0xb0, 0x6d, 0x6a, 0x19, 0x7e, 0x44, 0x62, 0x01, + 0x49, 0x32, 0x01, 0x09, 0x37, 0x2c, 0x41, 0xfe, 0xc1, 0x32, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x8c, 0x01, 0x5d, 0x01, 0xcc, 0x02, 0xc6, 0x00, 0x0b, + 0x00, 0x19, 0x00, 0x55, 0xba, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x1b, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x0c, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x2f, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x06, 0x2f, 0x1b, 0xb9, 0x00, 0x06, + 0x00, 0x1d, 0x3e, 0x59, 0x41, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x5d, 0x41, 0x03, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x01, 0x5d, 0x41, 0x03, + 0x00, 0xd0, 0x00, 0x00, 0x00, 0x01, 0x5d, 0xb8, 0x00, 0x00, 0x10, 0xb9, + 0x00, 0x0c, 0x00, 0x03, 0xf4, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x13, + 0x00, 0x03, 0xf4, 0x30, 0x31, 0x01, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x15, 0x14, 0x06, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x2c, 0x4c, 0x54, 0x55, + 0x4b, 0x4b, 0x55, 0x55, 0x4b, 0x2d, 0x2e, 0x2e, 0x2d, 0x2d, 0x2e, 0x2e, + 0x01, 0x5d, 0x60, 0x55, 0x54, 0x60, 0x60, 0x54, 0x55, 0x60, 0x35, 0x37, + 0x2b, 0x3b, 0x2b, 0x37, 0x37, 0x2b, 0x3b, 0x2b, 0x37, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x43, 0x00, 0x38, 0x02, 0x0f, 0x01, 0xe4, 0x00, 0x06, + 0x00, 0x0d, 0x00, 0x00, 0x25, 0x37, 0x27, 0x37, 0x17, 0x15, 0x07, 0x27, + 0x37, 0x27, 0x37, 0x17, 0x15, 0x07, 0x01, 0x28, 0x94, 0x94, 0x19, 0xce, + 0xce, 0xfe, 0x94, 0x94, 0x19, 0xce, 0xce, 0x71, 0x9d, 0x9d, 0x39, 0xae, + 0x50, 0xae, 0x39, 0x9d, 0x9d, 0x39, 0xae, 0x50, 0xae, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x02, 0x49, 0x02, 0xba, 0x00, 0x0a, + 0x00, 0x0e, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x00, 0x25, 0x23, + 0x35, 0x37, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x23, 0x3d, 0x01, 0x23, + 0x07, 0x01, 0x33, 0x35, 0x07, 0x27, 0x37, 0x33, 0x11, 0x33, 0x15, 0x23, + 0x01, 0x33, 0x03, 0x23, 0x07, 0x33, 0x03, 0x23, 0x01, 0xdd, 0xa3, 0x8e, + 0x52, 0x2f, 0x2f, 0x3d, 0x03, 0x72, 0xfe, 0xc0, 0x5e, 0x59, 0x18, 0x6c, + 0x44, 0x53, 0xf0, 0x01, 0xd6, 0x48, 0xa0, 0x48, 0xac, 0x48, 0xa0, 0x48, + 0x40, 0x3b, 0xd4, 0xdf, 0x30, 0x40, 0x70, 0xaa, 0xaa, 0x01, 0x2d, 0xe6, + 0x2d, 0x2c, 0x38, 0xfe, 0xe3, 0x32, 0x01, 0x4f, 0xfe, 0xd4, 0x62, 0xfe, + 0xd4, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x02, 0x46, + 0x02, 0xba, 0x00, 0x18, 0x00, 0x23, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x00, + 0x25, 0x37, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, + 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x0f, 0x01, 0x33, 0x15, + 0x23, 0x01, 0x33, 0x35, 0x07, 0x27, 0x37, 0x33, 0x11, 0x33, 0x15, 0x23, + 0x01, 0x33, 0x03, 0x23, 0x07, 0x33, 0x03, 0x23, 0x01, 0x49, 0x71, 0x36, + 0x1b, 0x1a, 0x1a, 0x1f, 0x0a, 0x35, 0x0b, 0x3d, 0x35, 0x39, 0x39, 0x35, + 0x25, 0x4d, 0xb4, 0xf6, 0xfe, 0xdf, 0x5e, 0x59, 0x18, 0x6c, 0x44, 0x53, + 0xf0, 0x01, 0xd6, 0x48, 0xa0, 0x48, 0xac, 0x48, 0xa0, 0x48, 0x3a, 0x5a, + 0x2b, 0x2f, 0x05, 0x13, 0x1b, 0x1d, 0x1a, 0x16, 0x22, 0x33, 0x39, 0x28, + 0x2a, 0x40, 0x1d, 0x3b, 0x32, 0x01, 0x9d, 0xe6, 0x2d, 0x2c, 0x38, 0xfe, + 0xe3, 0x32, 0x01, 0x4f, 0xfe, 0xd4, 0x62, 0xfe, 0xd4, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x02, 0x49, 0x02, 0xc0, 0x00, 0x0a, + 0x00, 0x0e, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x00, 0x25, 0x23, + 0x35, 0x37, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x23, 0x3d, 0x01, 0x23, + 0x07, 0x27, 0x22, 0x26, 0x27, 0x37, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x26, 0x2b, 0x01, 0x35, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x34, + 0x26, 0x23, 0x22, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x07, 0x15, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x01, 0x33, 0x03, 0x23, + 0x07, 0x33, 0x03, 0x23, 0x01, 0xdd, 0xa3, 0x8e, 0x52, 0x2f, 0x2f, 0x3d, + 0x03, 0x72, 0xd8, 0x34, 0x3a, 0x10, 0x2f, 0x0c, 0x23, 0x20, 0x1d, 0x21, + 0x24, 0x21, 0x23, 0x23, 0x20, 0x1f, 0x1e, 0x1a, 0x2f, 0x19, 0x2a, 0x12, + 0x36, 0x2c, 0x36, 0x40, 0x29, 0x1d, 0x20, 0x2c, 0x45, 0x01, 0x35, 0x48, + 0xa0, 0x48, 0xac, 0x48, 0xa0, 0x48, 0x40, 0x3b, 0xd4, 0xdf, 0x30, 0x40, + 0x70, 0xaa, 0xaa, 0xf5, 0x2b, 0x1c, 0x21, 0x17, 0x1e, 0x1b, 0x17, 0x07, + 0x17, 0x17, 0x32, 0x18, 0x11, 0x07, 0x14, 0x18, 0x29, 0x22, 0x1a, 0x20, + 0x2f, 0x28, 0x21, 0x27, 0x05, 0x04, 0x05, 0x28, 0x23, 0x2d, 0x36, 0x01, + 0x55, 0xfe, 0xd4, 0x62, 0xfe, 0xd4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5a, + 0xff, 0x3e, 0x02, 0x0b, 0x02, 0x0d, 0x00, 0x1c, 0x00, 0x2a, 0x00, 0x3c, + 0xba, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x2c, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x1d, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x2f, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x24, 0x2f, 0x1b, 0xb9, 0x00, 0x24, 0x00, 0x1b, 0x3e, 0x59, + 0xb9, 0x00, 0x1d, 0x00, 0x09, 0xf4, 0xb9, 0x00, 0x0c, 0x00, 0x07, 0xf4, + 0xb8, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x14, 0x00, 0x0b, 0xf4, 0x30, 0x31, + 0x05, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x37, 0x35, 0x33, 0x15, + 0x0e, 0x01, 0x1d, 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, + 0x03, 0x03, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, + 0x01, 0x14, 0x06, 0x01, 0x2b, 0x30, 0x4d, 0x36, 0x1e, 0x22, 0x36, 0x45, + 0x23, 0x4f, 0x56, 0x62, 0x43, 0x3a, 0x3c, 0x48, 0x0e, 0x4b, 0x0a, 0x24, + 0x37, 0x4b, 0x1d, 0x29, 0x21, 0x21, 0x29, 0x29, 0x21, 0x21, 0xc2, 0x1b, + 0x31, 0x46, 0x2b, 0x2f, 0x47, 0x32, 0x1f, 0x06, 0x65, 0x9d, 0x04, 0x43, + 0x44, 0x0e, 0x38, 0x38, 0x42, 0x33, 0x1c, 0x21, 0x3b, 0x2c, 0x1a, 0x02, + 0x45, 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x22, 0x1a, 0x12, 0x1a, 0x22, 0x00, + 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x3a, 0x03, 0xb5, 0x00, 0x03, + 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00, 0x13, 0x37, 0x17, 0x07, 0x13, 0x27, + 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, 0xbb, 0x49, + 0x55, 0x34, 0xbc, 0x3b, 0xf5, 0x3b, 0x57, 0xd6, 0x6f, 0xd6, 0xfe, 0xf6, + 0x09, 0x62, 0xcd, 0x03, 0x92, 0x23, 0xaa, 0x18, 0xfd, 0x0d, 0xc7, 0xc7, + 0x02, 0xba, 0xfd, 0x46, 0x02, 0x61, 0xfe, 0xaf, 0x00, 0x03, 0x00, 0x1f, + 0x00, 0x00, 0x02, 0x3a, 0x03, 0xb5, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x0f, + 0x00, 0x00, 0x01, 0x27, 0x37, 0x17, 0x13, 0x27, 0x23, 0x07, 0x23, 0x13, + 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, 0x01, 0x33, 0x34, 0x55, 0x49, 0x44, + 0x3b, 0xf5, 0x3b, 0x57, 0xd6, 0x6f, 0xd6, 0xfe, 0xf6, 0x09, 0x62, 0xcd, + 0x02, 0xf3, 0x18, 0xaa, 0x23, 0xfc, 0x6e, 0xc7, 0xc7, 0x02, 0xba, 0xfd, + 0x46, 0x02, 0x61, 0xfe, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1f, + 0x00, 0x00, 0x02, 0x3a, 0x03, 0xa7, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x12, + 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x13, 0x27, 0x23, + 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, 0x01, 0x5e, 0x6f, + 0x2d, 0x75, 0x75, 0x2b, 0x6f, 0xe7, 0x3b, 0xf5, 0x3b, 0x57, 0xd6, 0x6f, + 0xd6, 0xfe, 0xf6, 0x09, 0x62, 0xcd, 0x03, 0xa7, 0x8f, 0x1f, 0x75, 0x75, + 0x1f, 0x8f, 0xfc, 0x59, 0xc7, 0xc7, 0x02, 0xba, 0xfd, 0x46, 0x02, 0x61, + 0xfe, 0xaf, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x3a, + 0x03, 0x82, 0x00, 0x19, 0x00, 0x21, 0x00, 0x25, 0x00, 0x00, 0x01, 0x22, + 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, + 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, + 0x13, 0x27, 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, + 0x01, 0x75, 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, 0x0f, 0x21, + 0x0e, 0x2e, 0x23, 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, 0x0f, + 0x21, 0x0e, 0x2e, 0x49, 0x3b, 0xf5, 0x3b, 0x57, 0xd6, 0x6f, 0xd6, 0xfe, + 0xf6, 0x09, 0x62, 0xcd, 0x03, 0x0e, 0x12, 0x08, 0x0d, 0x0b, 0x0e, 0x0d, + 0x28, 0x14, 0x21, 0x12, 0x08, 0x0d, 0x0b, 0x0e, 0x0d, 0x28, 0x14, 0x21, + 0xfc, 0xf2, 0xc7, 0xc7, 0x02, 0xba, 0xfd, 0x46, 0x02, 0x61, 0xfe, 0xaf, + 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x3a, 0x03, 0x7e, 0x00, 0x0d, + 0x00, 0x1b, 0x00, 0x23, 0x00, 0x27, 0x00, 0x00, 0x13, 0x22, 0x26, 0x3d, + 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, + 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, + 0x13, 0x27, 0x23, 0x07, 0x23, 0x13, 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, + 0xcf, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, 0x1a, 0x1a, 0x9b, 0x1f, 0x1a, 0x1a, + 0x1f, 0x1f, 0x1a, 0x1a, 0x39, 0x3b, 0xf5, 0x3b, 0x57, 0xd6, 0x6f, 0xd6, + 0xfe, 0xf6, 0x09, 0x62, 0xcd, 0x03, 0x14, 0x1a, 0x14, 0x0e, 0x14, 0x1a, + 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, + 0x0e, 0x14, 0x1a, 0xfc, 0xec, 0xc7, 0xc7, 0x02, 0xba, 0xfd, 0x46, 0x02, + 0x61, 0xfe, 0xaf, 0x00, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x3a, + 0x03, 0xd0, 0x00, 0x13, 0x00, 0x21, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x00, + 0x01, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, + 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x13, 0x27, 0x23, 0x07, 0x23, 0x13, + 0x33, 0x13, 0x01, 0x23, 0x03, 0x33, 0x01, 0x2c, 0x18, 0x2b, 0x1f, 0x12, + 0x12, 0x1f, 0x2b, 0x18, 0x18, 0x2b, 0x1f, 0x12, 0x12, 0x1f, 0x2b, 0x18, + 0x1b, 0x1f, 0x1f, 0x1b, 0x1b, 0x1f, 0x1f, 0xd0, 0x3b, 0xf5, 0x3b, 0x57, + 0xd6, 0x6f, 0xd6, 0xfe, 0xf6, 0x09, 0x62, 0xcd, 0x02, 0xea, 0x11, 0x1f, + 0x2a, 0x19, 0x19, 0x2a, 0x1f, 0x11, 0x11, 0x1f, 0x2a, 0x19, 0x19, 0x2a, + 0x1f, 0x11, 0x31, 0x1d, 0x1a, 0x16, 0x1a, 0x1d, 0x1d, 0x1a, 0x16, 0x1a, + 0x1d, 0xfc, 0xe5, 0xc7, 0xc7, 0x02, 0xba, 0xfd, 0x46, 0x02, 0x61, 0xfe, + 0xaf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x02, 0x30, + 0x02, 0xba, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x8c, 0xba, 0x00, 0x0f, 0x00, + 0x14, 0x00, 0x15, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0f, 0x10, 0xb8, 0x00, + 0x12, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, + 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, + 0x58, 0xb8, 0x00, 0x0e, 0x2f, 0x1b, 0xb9, 0x00, 0x0e, 0x00, 0x0f, 0x3e, + 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x02, 0x2f, 0x1b, 0xb9, + 0x00, 0x02, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x11, 0x00, 0x05, 0x00, + 0x0e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x11, 0x2f, 0xb9, 0x00, 0x01, 0x00, + 0x0b, 0xf4, 0xb8, 0x00, 0x05, 0x10, 0xb9, 0x00, 0x06, 0x00, 0x0b, 0xf4, + 0xba, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0e, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x0b, 0x2f, 0xb9, 0x00, 0x08, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x0e, 0x10, + 0xb9, 0x00, 0x0d, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x06, 0x10, 0xb8, 0x00, + 0x13, 0xd0, 0x30, 0x31, 0x25, 0x23, 0x07, 0x23, 0x13, 0x21, 0x15, 0x23, + 0x15, 0x33, 0x15, 0x23, 0x15, 0x33, 0x15, 0x23, 0x0b, 0x01, 0x33, 0x11, + 0x01, 0x38, 0x98, 0x38, 0x54, 0xce, 0x01, 0x4e, 0xa8, 0x9c, 0x9c, 0xa8, + 0xf8, 0x1f, 0x67, 0x86, 0xc9, 0xc9, 0x02, 0xba, 0x45, 0xf1, 0x45, 0xfa, + 0x45, 0x02, 0x7e, 0xfe, 0x90, 0x01, 0x70, 0x00, 0x00, 0x01, 0x00, 0x46, + 0xff, 0x31, 0x02, 0x1a, 0x02, 0xc6, 0x00, 0x3d, 0x00, 0x72, 0xba, 0x00, + 0x2b, 0x00, 0x3e, 0x00, 0x3f, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x33, 0x2f, 0x1b, 0xb9, 0x00, 0x33, 0x00, 0x1d, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x12, 0x2f, 0x1b, + 0xb9, 0x00, 0x12, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x33, 0x10, 0xb9, + 0x00, 0x00, 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x12, 0x10, 0xb9, 0x00, 0x07, + 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x12, 0x10, 0xb8, 0x00, 0x16, 0xdc, 0x41, + 0x07, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x2f, 0x00, + 0x16, 0x00, 0x03, 0x5d, 0xb8, 0x00, 0x2b, 0xdc, 0xb8, 0x00, 0x25, 0xdc, + 0xb9, 0x00, 0x1e, 0x00, 0x03, 0xf4, 0xb8, 0x00, 0x12, 0x10, 0xb8, 0x00, + 0x2d, 0xd0, 0x30, 0x31, 0x01, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x33, + 0x32, 0x3e, 0x02, 0x37, 0x17, 0x0e, 0x03, 0x0f, 0x01, 0x17, 0x36, 0x33, + 0x32, 0x16, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x37, 0x1e, + 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2f, 0x01, 0x37, 0x2e, 0x01, + 0x35, 0x34, 0x36, 0x33, 0x32, 0x1e, 0x02, 0x17, 0x07, 0x2e, 0x03, 0x01, + 0x43, 0x53, 0x51, 0x51, 0x53, 0x20, 0x2d, 0x21, 0x18, 0x09, 0x48, 0x0d, + 0x21, 0x31, 0x43, 0x2e, 0x09, 0x03, 0x13, 0x14, 0x1d, 0x27, 0x12, 0x1f, + 0x28, 0x16, 0x29, 0x2f, 0x0b, 0x26, 0x09, 0x1e, 0x16, 0x13, 0x19, 0x1a, + 0x2a, 0x1c, 0x0d, 0x6b, 0x68, 0x7d, 0x80, 0x30, 0x46, 0x32, 0x22, 0x0d, + 0x48, 0x09, 0x18, 0x21, 0x2d, 0x02, 0x7d, 0x7e, 0x69, 0x72, 0x69, 0x7e, + 0x12, 0x1f, 0x29, 0x17, 0x21, 0x1c, 0x36, 0x2b, 0x1b, 0x01, 0x31, 0x03, + 0x06, 0x22, 0x20, 0x15, 0x20, 0x14, 0x0a, 0x1b, 0x0e, 0x29, 0x0b, 0x11, + 0x0f, 0x10, 0x0e, 0x15, 0x06, 0x04, 0x44, 0x0f, 0xb6, 0xa1, 0xaf, 0xba, + 0x1a, 0x2c, 0x37, 0x1c, 0x21, 0x17, 0x29, 0x1f, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x5a, 0x00, 0x00, 0x02, 0x08, 0x03, 0xb5, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x00, 0x13, 0x37, 0x17, 0x07, 0x03, 0x11, 0x21, 0x15, + 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0xc0, 0x49, 0x55, 0x34, + 0xd0, 0x01, 0xae, 0xfe, 0xa6, 0x01, 0x4e, 0xfe, 0xb2, 0x01, 0x5a, 0x03, + 0x92, 0x23, 0xaa, 0x18, 0xfd, 0x0d, 0x02, 0xba, 0x49, 0xeb, 0x49, 0xf4, + 0x49, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5a, 0x00, 0x00, 0x02, 0x08, + 0x03, 0xb5, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x27, 0x37, 0x17, + 0x01, 0x11, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, + 0x01, 0x38, 0x34, 0x55, 0x49, 0xfe, 0xb8, 0x01, 0xae, 0xfe, 0xa6, 0x01, + 0x4e, 0xfe, 0xb2, 0x01, 0x5a, 0x02, 0xf3, 0x18, 0xaa, 0x23, 0xfc, 0x6e, + 0x02, 0xba, 0x49, 0xeb, 0x49, 0xf4, 0x49, 0x00, 0x00, 0x02, 0x00, 0x5a, + 0x00, 0x00, 0x02, 0x08, 0x03, 0xa7, 0x00, 0x06, 0x00, 0x12, 0x00, 0x00, + 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x03, 0x11, 0x21, 0x15, 0x21, + 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x01, 0x63, 0x6f, 0x2d, 0x75, + 0x75, 0x2b, 0x6f, 0xa5, 0x01, 0xae, 0xfe, 0xa6, 0x01, 0x4e, 0xfe, 0xb2, + 0x01, 0x5a, 0x03, 0xa7, 0x8f, 0x1f, 0x75, 0x75, 0x1f, 0x8f, 0xfc, 0x59, + 0x02, 0xba, 0x49, 0xeb, 0x49, 0xf4, 0x49, 0x00, 0x00, 0x03, 0x00, 0x5a, + 0x00, 0x00, 0x02, 0x08, 0x03, 0x7e, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x27, + 0x00, 0x00, 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x01, 0x11, 0x21, 0x15, 0x21, 0x15, + 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0xd4, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, + 0x1a, 0x1a, 0x9b, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, 0x1a, 0x1a, 0xfe, 0xad, + 0x01, 0xae, 0xfe, 0xa6, 0x01, 0x4e, 0xfe, 0xb2, 0x01, 0x5a, 0x03, 0x14, + 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, + 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0xfc, 0xec, 0x02, 0xba, + 0x49, 0xeb, 0x49, 0xf4, 0x49, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x54, + 0x00, 0x00, 0x02, 0x04, 0x03, 0xb5, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, + 0x13, 0x37, 0x17, 0x07, 0x03, 0x35, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, + 0x23, 0x11, 0x33, 0x15, 0xbb, 0x49, 0x55, 0x34, 0xd1, 0xae, 0xae, 0x01, + 0xb0, 0xae, 0xae, 0x03, 0x92, 0x23, 0xaa, 0x18, 0xfd, 0x0d, 0x43, 0x02, + 0x34, 0x43, 0x43, 0xfd, 0xcc, 0x43, 0x00, 0x00, 0x00, 0x02, 0x00, 0x54, + 0x00, 0x00, 0x02, 0x04, 0x03, 0xb5, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, + 0x01, 0x27, 0x37, 0x17, 0x01, 0x35, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, + 0x23, 0x11, 0x33, 0x15, 0x01, 0x33, 0x34, 0x55, 0x49, 0xfe, 0xb7, 0xae, + 0xae, 0x01, 0xb0, 0xae, 0xae, 0x02, 0xf3, 0x18, 0xaa, 0x23, 0xfc, 0x6e, + 0x43, 0x02, 0x34, 0x43, 0x43, 0xfd, 0xcc, 0x43, 0x00, 0x02, 0x00, 0x54, + 0x00, 0x00, 0x02, 0x04, 0x03, 0xa7, 0x00, 0x06, 0x00, 0x12, 0x00, 0x00, + 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x03, 0x35, 0x33, 0x11, 0x23, + 0x35, 0x21, 0x15, 0x23, 0x11, 0x33, 0x15, 0x01, 0x5e, 0x6f, 0x2d, 0x75, + 0x75, 0x2b, 0x6f, 0xa6, 0xae, 0xae, 0x01, 0xb0, 0xae, 0xae, 0x03, 0xa7, + 0x8f, 0x1f, 0x75, 0x75, 0x1f, 0x8f, 0xfc, 0x59, 0x43, 0x02, 0x34, 0x43, + 0x43, 0xfd, 0xcc, 0x43, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x02, 0x04, + 0x03, 0x7e, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x00, 0x13, 0x22, + 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, + 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, + 0x14, 0x06, 0x01, 0x35, 0x33, 0x11, 0x23, 0x35, 0x21, 0x15, 0x23, 0x11, + 0x33, 0x15, 0xcf, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, 0x1a, 0x1a, 0x9b, 0x1f, + 0x1a, 0x1a, 0x1f, 0x1f, 0x1a, 0x1a, 0xfe, 0xac, 0xae, 0xae, 0x01, 0xb0, + 0xae, 0xae, 0x03, 0x14, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, + 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, + 0xfc, 0xec, 0x43, 0x02, 0x34, 0x43, 0x43, 0xfd, 0xcc, 0x43, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x16, 0x00, 0x00, 0x02, 0x20, 0x02, 0xba, 0x00, 0x0c, + 0x00, 0x1a, 0x00, 0x00, 0x13, 0x23, 0x35, 0x33, 0x11, 0x33, 0x32, 0x16, + 0x15, 0x14, 0x06, 0x2b, 0x01, 0x37, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x2b, 0x01, 0x15, 0x33, 0x15, 0x23, 0x11, 0x66, 0x50, 0x50, 0xbc, 0x80, + 0x7e, 0x7e, 0x80, 0xbc, 0xb8, 0x54, 0x55, 0x55, 0x54, 0x64, 0x8d, 0x8d, + 0x01, 0x50, 0x40, 0x01, 0x2a, 0xb0, 0xad, 0xad, 0xb0, 0x49, 0x74, 0x6a, + 0x6c, 0x6a, 0x74, 0xe1, 0x40, 0xfe, 0xf9, 0x00, 0x00, 0x02, 0x00, 0x50, + 0x00, 0x00, 0x02, 0x08, 0x03, 0x82, 0x00, 0x19, 0x00, 0x25, 0x00, 0x00, + 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, + 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, + 0x0e, 0x01, 0x07, 0x23, 0x11, 0x23, 0x11, 0x33, 0x13, 0x33, 0x11, 0x33, + 0x11, 0x23, 0x01, 0x75, 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, + 0x0f, 0x21, 0x0e, 0x2e, 0x23, 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, + 0x1a, 0x0f, 0x21, 0x0e, 0x2e, 0xf5, 0x07, 0x4c, 0x77, 0xee, 0x07, 0x4c, + 0x77, 0x03, 0x0e, 0x12, 0x08, 0x0d, 0x0b, 0x0e, 0x0d, 0x28, 0x14, 0x21, + 0x12, 0x08, 0x0d, 0x0b, 0x0e, 0x0d, 0x28, 0x14, 0x21, 0xc2, 0xfd, 0xb4, + 0x02, 0xba, 0xfd, 0xb4, 0x02, 0x4c, 0xfd, 0x46, 0x00, 0x03, 0x00, 0x38, + 0xff, 0xf4, 0x02, 0x20, 0x03, 0xb5, 0x00, 0x03, 0x00, 0x17, 0x00, 0x2d, + 0x00, 0x00, 0x13, 0x37, 0x17, 0x07, 0x13, 0x22, 0x2e, 0x02, 0x35, 0x34, + 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, + 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, 0x1d, + 0x01, 0x14, 0x1e, 0x02, 0xbb, 0x49, 0x55, 0x34, 0x07, 0x40, 0x5c, 0x3c, + 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x40, 0x5c, 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, + 0x40, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x2a, 0x2a, 0x3a, 0x26, + 0x11, 0x11, 0x26, 0x3a, 0x03, 0x92, 0x23, 0xaa, 0x18, 0xfd, 0x01, 0x31, + 0x5c, 0x86, 0x56, 0x55, 0x87, 0x5c, 0x31, 0x31, 0x5c, 0x87, 0x55, 0x56, + 0x86, 0x5c, 0x31, 0x49, 0x21, 0x3c, 0x55, 0x35, 0x72, 0x34, 0x56, 0x3c, + 0x21, 0x21, 0x3c, 0x56, 0x34, 0x72, 0x35, 0x55, 0x3c, 0x21, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x38, 0xff, 0xf4, 0x02, 0x20, 0x03, 0xb5, 0x00, 0x03, + 0x00, 0x17, 0x00, 0x2d, 0x00, 0x00, 0x01, 0x27, 0x37, 0x17, 0x03, 0x22, + 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, + 0x0e, 0x02, 0x27, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, + 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x01, 0x33, 0x34, 0x55, + 0x49, 0x71, 0x40, 0x5c, 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x40, 0x5c, + 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, + 0x3a, 0x2a, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x02, 0xf3, 0x18, + 0xaa, 0x23, 0xfc, 0x62, 0x31, 0x5c, 0x86, 0x56, 0x55, 0x87, 0x5c, 0x31, + 0x31, 0x5c, 0x87, 0x55, 0x56, 0x86, 0x5c, 0x31, 0x49, 0x21, 0x3c, 0x55, + 0x35, 0x72, 0x34, 0x56, 0x3c, 0x21, 0x21, 0x3c, 0x56, 0x34, 0x72, 0x35, + 0x55, 0x3c, 0x21, 0x00, 0x00, 0x03, 0x00, 0x38, 0xff, 0xf4, 0x02, 0x20, + 0x03, 0xa7, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x30, 0x00, 0x00, 0x01, 0x17, + 0x07, 0x27, 0x07, 0x27, 0x37, 0x13, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, + 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x3e, + 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, + 0x14, 0x1e, 0x02, 0x01, 0x5e, 0x6f, 0x2d, 0x75, 0x75, 0x2b, 0x6f, 0x32, + 0x40, 0x5c, 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x40, 0x5c, 0x3c, 0x1c, + 0x1c, 0x3c, 0x5c, 0x40, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x2a, + 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x03, 0xa7, 0x8f, 0x1f, 0x75, + 0x75, 0x1f, 0x8f, 0xfc, 0x4d, 0x31, 0x5c, 0x86, 0x56, 0x55, 0x87, 0x5c, + 0x31, 0x31, 0x5c, 0x87, 0x55, 0x56, 0x86, 0x5c, 0x31, 0x49, 0x21, 0x3c, + 0x55, 0x35, 0x72, 0x34, 0x56, 0x3c, 0x21, 0x21, 0x3c, 0x56, 0x34, 0x72, + 0x35, 0x55, 0x3c, 0x21, 0x00, 0x03, 0x00, 0x38, 0xff, 0xf4, 0x02, 0x20, + 0x03, 0x82, 0x00, 0x19, 0x00, 0x2d, 0x00, 0x43, 0x00, 0x00, 0x01, 0x22, + 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, + 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, + 0x03, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, + 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, + 0x02, 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x01, 0x75, + 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, 0x0f, 0x21, 0x0e, 0x2e, + 0x23, 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, 0x0f, 0x21, 0x0e, + 0x2e, 0x6c, 0x40, 0x5c, 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x40, 0x5c, + 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, + 0x3a, 0x2a, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x03, 0x0e, 0x12, + 0x08, 0x0d, 0x0b, 0x0e, 0x0d, 0x28, 0x14, 0x21, 0x12, 0x08, 0x0d, 0x0b, + 0x0e, 0x0d, 0x28, 0x14, 0x21, 0xfc, 0xe6, 0x31, 0x5c, 0x86, 0x56, 0x55, + 0x87, 0x5c, 0x31, 0x31, 0x5c, 0x87, 0x55, 0x56, 0x86, 0x5c, 0x31, 0x49, + 0x21, 0x3c, 0x55, 0x35, 0x72, 0x34, 0x56, 0x3c, 0x21, 0x21, 0x3c, 0x56, + 0x34, 0x72, 0x35, 0x55, 0x3c, 0x21, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38, + 0xff, 0xf4, 0x02, 0x20, 0x03, 0x7e, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x2f, + 0x00, 0x45, 0x00, 0x00, 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, + 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, + 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x03, 0x22, 0x2e, 0x02, + 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, + 0x27, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x34, 0x2e, 0x02, 0x23, 0x22, 0x0e, + 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0xcf, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, + 0x1a, 0x1a, 0x9b, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, 0x1a, 0x1a, 0x7c, 0x40, + 0x5c, 0x3c, 0x1c, 0x1c, 0x3c, 0x5c, 0x40, 0x40, 0x5c, 0x3c, 0x1c, 0x1c, + 0x3c, 0x5c, 0x40, 0x2a, 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x2a, 0x2a, + 0x3a, 0x26, 0x11, 0x11, 0x26, 0x3a, 0x03, 0x14, 0x1a, 0x14, 0x0e, 0x14, + 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, + 0x14, 0x0e, 0x14, 0x1a, 0xfc, 0xe0, 0x31, 0x5c, 0x86, 0x56, 0x55, 0x87, + 0x5c, 0x31, 0x31, 0x5c, 0x87, 0x55, 0x56, 0x86, 0x5c, 0x31, 0x49, 0x21, + 0x3c, 0x55, 0x35, 0x72, 0x34, 0x56, 0x3c, 0x21, 0x21, 0x3c, 0x56, 0x34, + 0x72, 0x35, 0x55, 0x3c, 0x21, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x58, + 0x00, 0x5d, 0x02, 0x00, 0x02, 0x05, 0x00, 0x0b, 0x00, 0x2f, 0xba, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x0d, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x05, 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1b, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x07, 0x2f, 0x1b, + 0xb9, 0x00, 0x07, 0x00, 0x1b, 0x3e, 0x59, 0x30, 0x31, 0x01, 0x07, 0x27, + 0x37, 0x27, 0x37, 0x17, 0x37, 0x17, 0x07, 0x17, 0x07, 0x01, 0x2c, 0xa3, + 0x31, 0xa3, 0xa3, 0x31, 0xa3, 0xa3, 0x31, 0xa3, 0xa3, 0x31, 0x01, 0x00, + 0xa3, 0x31, 0xa3, 0xa3, 0x31, 0xa3, 0xa3, 0x31, 0xa3, 0xa3, 0x31, 0x00, + 0x00, 0x03, 0x00, 0x2f, 0xff, 0xd4, 0x02, 0x29, 0x02, 0xe6, 0x00, 0x19, + 0x00, 0x26, 0x00, 0x33, 0x00, 0x9f, 0xba, 0x00, 0x00, 0x00, 0x34, 0x00, + 0x35, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x21, 0xd0, 0xb8, 0x00, 0x00, 0x10, + 0xb8, 0x00, 0x27, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, + 0x0d, 0x2f, 0x1b, 0xb9, 0x00, 0x0d, 0x00, 0x1d, 0x3e, 0x59, 0xb8, 0x00, + 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, 0x00, + 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x0d, 0x10, 0xb9, 0x00, 0x21, 0x00, 0x0b, + 0xf4, 0xba, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x21, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x00, + 0x10, 0xb9, 0x00, 0x27, 0x00, 0x0b, 0xf4, 0xba, 0x00, 0x0f, 0x00, 0x0d, + 0x00, 0x27, 0x11, 0x12, 0x39, 0xba, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x27, + 0x11, 0x12, 0x39, 0xba, 0x00, 0x1d, 0x00, 0x27, 0x00, 0x0d, 0x11, 0x12, + 0x39, 0xba, 0x00, 0x1e, 0x00, 0x21, 0x00, 0x00, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x30, 0x00, 0x21, 0x00, 0x00, 0x11, 0x12, 0x39, 0xba, 0x00, 0x31, + 0x00, 0x27, 0x00, 0x0d, 0x11, 0x12, 0x39, 0x30, 0x31, 0x05, 0x22, 0x27, + 0x07, 0x27, 0x37, 0x2e, 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x17, + 0x37, 0x17, 0x07, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x02, 0x03, 0x14, 0x16, + 0x17, 0x13, 0x2e, 0x01, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x13, 0x32, 0x3e, + 0x02, 0x3d, 0x01, 0x34, 0x26, 0x27, 0x03, 0x1e, 0x01, 0x01, 0x2c, 0x5b, + 0x37, 0x2f, 0x3c, 0x3c, 0x1a, 0x19, 0x1c, 0x3c, 0x5c, 0x40, 0x5a, 0x38, + 0x2f, 0x3c, 0x3c, 0x1a, 0x19, 0x1c, 0x3c, 0x5c, 0xdb, 0x06, 0x08, 0xf8, + 0x13, 0x35, 0x23, 0x2a, 0x3a, 0x26, 0x11, 0x9b, 0x2a, 0x3a, 0x26, 0x11, + 0x06, 0x08, 0xf8, 0x13, 0x35, 0x0c, 0x30, 0x50, 0x24, 0x66, 0x2e, 0x80, + 0x51, 0x55, 0x87, 0x5c, 0x31, 0x30, 0x50, 0x24, 0x66, 0x2e, 0x80, 0x51, + 0x56, 0x86, 0x5c, 0x31, 0x01, 0x30, 0x22, 0x3b, 0x19, 0x01, 0xa1, 0x16, + 0x18, 0x21, 0x3c, 0x56, 0x34, 0xfe, 0xa7, 0x21, 0x3c, 0x55, 0x35, 0x72, + 0x22, 0x3b, 0x19, 0xfe, 0x5f, 0x16, 0x18, 0x00, 0x00, 0x02, 0x00, 0x50, + 0xff, 0xf4, 0x02, 0x08, 0x03, 0xb5, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, + 0x13, 0x37, 0x17, 0x0f, 0x01, 0x11, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x3e, + 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, + 0x35, 0x11, 0xbb, 0x49, 0x55, 0x34, 0x81, 0x06, 0x1a, 0x37, 0x31, 0x31, + 0x37, 0x1a, 0x06, 0x54, 0x0f, 0x2f, 0x57, 0x47, 0x47, 0x57, 0x2f, 0x0f, + 0x03, 0x92, 0x23, 0xaa, 0x18, 0x39, 0xfe, 0x5d, 0x33, 0x50, 0x39, 0x1e, + 0x1e, 0x39, 0x50, 0x33, 0x01, 0xa3, 0xfe, 0x71, 0x4e, 0x74, 0x4e, 0x27, + 0x27, 0x4e, 0x74, 0x4e, 0x01, 0x8f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x50, + 0xff, 0xf4, 0x02, 0x08, 0x03, 0xb5, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, + 0x01, 0x27, 0x37, 0x17, 0x07, 0x11, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x3e, + 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, + 0x35, 0x11, 0x01, 0x33, 0x34, 0x55, 0x49, 0xf9, 0x06, 0x1a, 0x37, 0x31, + 0x31, 0x37, 0x1a, 0x06, 0x54, 0x0f, 0x2f, 0x57, 0x47, 0x47, 0x57, 0x2f, + 0x0f, 0x02, 0xf3, 0x18, 0xaa, 0x23, 0xd8, 0xfe, 0x5d, 0x33, 0x50, 0x39, + 0x1e, 0x1e, 0x39, 0x50, 0x33, 0x01, 0xa3, 0xfe, 0x71, 0x4e, 0x74, 0x4e, + 0x27, 0x27, 0x4e, 0x74, 0x4e, 0x01, 0x8f, 0x00, 0x00, 0x02, 0x00, 0x50, + 0xff, 0xf4, 0x02, 0x08, 0x03, 0xa7, 0x00, 0x06, 0x00, 0x20, 0x00, 0x00, + 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x07, 0x11, 0x14, 0x1e, 0x02, + 0x33, 0x32, 0x3e, 0x02, 0x35, 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, + 0x22, 0x2e, 0x02, 0x35, 0x11, 0x01, 0x5e, 0x6f, 0x2d, 0x75, 0x75, 0x2b, + 0x6f, 0x56, 0x06, 0x1a, 0x37, 0x31, 0x31, 0x37, 0x1a, 0x06, 0x54, 0x0f, + 0x2f, 0x57, 0x47, 0x47, 0x57, 0x2f, 0x0f, 0x03, 0xa7, 0x8f, 0x1f, 0x75, + 0x75, 0x1f, 0x8f, 0xed, 0xfe, 0x5d, 0x33, 0x50, 0x39, 0x1e, 0x1e, 0x39, + 0x50, 0x33, 0x01, 0xa3, 0xfe, 0x71, 0x4e, 0x74, 0x4e, 0x27, 0x27, 0x4e, + 0x74, 0x4e, 0x01, 0x8f, 0x00, 0x03, 0x00, 0x50, 0xff, 0xf4, 0x02, 0x08, + 0x03, 0x7e, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x35, 0x00, 0x00, 0x13, 0x22, + 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, + 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, + 0x14, 0x06, 0x05, 0x11, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x3e, 0x02, 0x35, + 0x11, 0x33, 0x11, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x11, + 0xcf, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, 0x1a, 0x1a, 0x9b, 0x1f, 0x1a, 0x1a, + 0x1f, 0x1f, 0x1a, 0x1a, 0xfe, 0xfc, 0x06, 0x1a, 0x37, 0x31, 0x31, 0x37, + 0x1a, 0x06, 0x54, 0x0f, 0x2f, 0x57, 0x47, 0x47, 0x57, 0x2f, 0x0f, 0x03, + 0x14, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, + 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x5a, 0xfe, 0x5d, + 0x33, 0x50, 0x39, 0x1e, 0x1e, 0x39, 0x50, 0x33, 0x01, 0xa3, 0xfe, 0x71, + 0x4e, 0x74, 0x4e, 0x27, 0x27, 0x4e, 0x74, 0x4e, 0x01, 0x8f, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x02, 0x47, 0x03, 0xb5, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x00, 0x01, 0x27, 0x37, 0x17, 0x03, 0x11, 0x03, 0x33, + 0x1f, 0x01, 0x33, 0x3f, 0x01, 0x33, 0x03, 0x11, 0x01, 0x33, 0x34, 0x55, + 0x49, 0x9b, 0xf1, 0x60, 0x64, 0x55, 0x04, 0x57, 0x64, 0x5e, 0xf1, 0x02, + 0xf3, 0x18, 0xaa, 0x23, 0xfc, 0x6e, 0x01, 0x12, 0x01, 0xa8, 0xb6, 0x9f, + 0x9f, 0xb6, 0xfe, 0x58, 0xfe, 0xee, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5a, + 0x00, 0x00, 0x02, 0x1f, 0x02, 0xba, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x63, + 0xba, 0x00, 0x0a, 0x00, 0x17, 0x00, 0x18, 0x11, 0x12, 0x39, 0xb8, 0x00, + 0x0a, 0x10, 0xb8, 0x00, 0x0e, 0xd0, 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x01, 0x2f, 0x1b, 0xb9, 0x00, 0x01, 0x00, 0x1d, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, + 0x00, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x03, 0x2f, 0xba, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x01, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x0b, 0x2f, 0xb9, 0x00, 0x0d, + 0x00, 0x0b, 0xf4, 0xb8, 0x00, 0x03, 0x10, 0xb9, 0x00, 0x16, 0x00, 0x0b, + 0xf4, 0x30, 0x31, 0x33, 0x11, 0x33, 0x15, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x2b, 0x01, 0x15, 0x35, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, + 0x2b, 0x01, 0x5a, 0x54, 0xaa, 0x61, 0x66, 0x66, 0x61, 0xaa, 0xaa, 0x35, + 0x3b, 0x3b, 0x35, 0xaa, 0x02, 0xba, 0x91, 0x6b, 0x5c, 0x5c, 0x6b, 0x9b, + 0xe4, 0x34, 0x30, 0x34, 0x30, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x66, + 0xff, 0x38, 0x02, 0x3c, 0x02, 0xe4, 0x00, 0x22, 0x00, 0x8d, 0xba, 0x00, + 0x1d, 0x00, 0x23, 0x00, 0x24, 0x11, 0x12, 0x39, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x04, 0x2f, 0x1b, 0xb9, 0x00, 0x04, 0x00, 0x1f, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x08, 0x2f, 0x1b, + 0xb9, 0x00, 0x08, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, + 0xb8, 0x00, 0x13, 0x2f, 0x1b, 0xb9, 0x00, 0x13, 0x00, 0x11, 0x3e, 0x59, + 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x22, 0x2f, 0x1b, 0xb9, 0x00, + 0x22, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x04, 0x10, 0xb9, 0x00, 0x07, + 0x00, 0x08, 0xf4, 0xba, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x22, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x1f, 0x2f, 0xb9, 0x00, 0x1e, 0x00, 0x08, 0xf4, 0xba, + 0x00, 0x0b, 0x00, 0x1f, 0x00, 0x1e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x13, + 0x10, 0xb9, 0x00, 0x16, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x08, 0x10, 0xb9, + 0x00, 0x21, 0x00, 0x08, 0xf4, 0x30, 0x31, 0x33, 0x11, 0x34, 0x36, 0x3b, + 0x01, 0x15, 0x23, 0x15, 0x21, 0x15, 0x07, 0x1e, 0x01, 0x15, 0x14, 0x0e, + 0x02, 0x2b, 0x01, 0x35, 0x33, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x2b, + 0x01, 0x35, 0x37, 0x21, 0x11, 0x66, 0x37, 0x3b, 0x89, 0xab, 0x01, 0x57, + 0xad, 0x67, 0x75, 0x25, 0x44, 0x61, 0x3c, 0x42, 0x42, 0x5a, 0x57, 0x5d, + 0x66, 0x10, 0xb0, 0xfe, 0xf2, 0x02, 0x6e, 0x34, 0x42, 0x45, 0x9b, 0x4f, + 0xe1, 0x07, 0x60, 0x5f, 0x34, 0x50, 0x36, 0x1c, 0x44, 0x40, 0x47, 0x19, + 0x43, 0x39, 0x44, 0xe4, 0xfe, 0x40, 0x00, 0x00, 0xff, 0xff, 0x00, 0x42, + 0xff, 0xf4, 0x02, 0x26, 0x03, 0x0b, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x43, 0xf0, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x42, + 0xff, 0xf4, 0x02, 0x26, 0x03, 0x0b, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x76, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x42, + 0xff, 0xf4, 0x02, 0x26, 0x02, 0xfd, 0x00, 0x06, 0x00, 0x28, 0x00, 0x36, + 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x01, 0x22, 0x26, + 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3b, 0x01, + 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, + 0x16, 0x15, 0x11, 0x33, 0x15, 0x25, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x23, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x4e, 0x6f, 0x2d, 0x75, 0x75, + 0x2b, 0x6f, 0x01, 0x05, 0x2f, 0x28, 0x05, 0x05, 0x11, 0x4b, 0x3f, 0x51, + 0x60, 0x69, 0x75, 0x6e, 0x40, 0x3b, 0x34, 0x42, 0x14, 0x36, 0x0a, 0x22, + 0x32, 0x40, 0x27, 0x5b, 0x6b, 0x48, 0xfe, 0xdb, 0x1f, 0x33, 0x26, 0x15, + 0x6e, 0x48, 0x42, 0x39, 0x02, 0xfd, 0x8f, 0x1f, 0x75, 0x75, 0x1f, 0x8f, + 0xfd, 0x03, 0x30, 0x24, 0x2d, 0x33, 0x54, 0x49, 0x48, 0x4e, 0x33, 0x39, + 0x39, 0x29, 0x23, 0x28, 0x14, 0x26, 0x1d, 0x11, 0x5c, 0x52, 0xfe, 0xe4, + 0x46, 0x37, 0x0f, 0x19, 0x23, 0x14, 0x55, 0x28, 0x26, 0x15, 0x28, 0x29, + 0x00, 0x03, 0x00, 0x42, 0xff, 0xf4, 0x02, 0x26, 0x02, 0xd8, 0x00, 0x19, + 0x00, 0x3b, 0x00, 0x49, 0x00, 0x00, 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, + 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, + 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, 0x13, 0x22, 0x26, 0x27, + 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3b, 0x01, 0x35, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, 0x16, + 0x15, 0x11, 0x33, 0x15, 0x25, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x23, 0x22, + 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x65, 0x1a, 0x26, 0x10, 0x18, 0x21, + 0x0d, 0x11, 0x1a, 0x0f, 0x21, 0x0e, 0x2e, 0x23, 0x1a, 0x26, 0x10, 0x18, + 0x21, 0x0d, 0x11, 0x1a, 0x0f, 0x21, 0x0e, 0x2e, 0x67, 0x2f, 0x28, 0x05, + 0x05, 0x11, 0x4b, 0x3f, 0x51, 0x60, 0x69, 0x75, 0x6e, 0x40, 0x3b, 0x34, + 0x42, 0x14, 0x36, 0x0a, 0x22, 0x32, 0x40, 0x27, 0x5b, 0x6b, 0x48, 0xfe, + 0xdb, 0x1f, 0x33, 0x26, 0x15, 0x6e, 0x48, 0x42, 0x39, 0x02, 0x64, 0x12, + 0x08, 0x0d, 0x0b, 0x0e, 0x0d, 0x28, 0x14, 0x21, 0x12, 0x08, 0x0d, 0x0b, + 0x0e, 0x0d, 0x28, 0x14, 0x21, 0xfd, 0x9c, 0x30, 0x24, 0x2d, 0x33, 0x54, + 0x49, 0x48, 0x4e, 0x33, 0x39, 0x39, 0x29, 0x23, 0x28, 0x14, 0x26, 0x1d, + 0x11, 0x5c, 0x52, 0xfe, 0xe4, 0x46, 0x37, 0x0f, 0x19, 0x23, 0x14, 0x55, + 0x28, 0x26, 0x15, 0x28, 0x29, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x42, + 0xff, 0xf4, 0x02, 0x26, 0x02, 0xd4, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x6a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x42, + 0xff, 0xf4, 0x02, 0x26, 0x03, 0x26, 0x00, 0x13, 0x00, 0x21, 0x00, 0x43, + 0x00, 0x51, 0x00, 0x00, 0x01, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, + 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x13, 0x22, + 0x26, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x3b, + 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, + 0x32, 0x16, 0x15, 0x11, 0x33, 0x15, 0x25, 0x32, 0x3e, 0x02, 0x3d, 0x01, + 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x1c, 0x18, 0x2b, 0x1f, + 0x12, 0x12, 0x1f, 0x2b, 0x18, 0x18, 0x2b, 0x1f, 0x12, 0x12, 0x1f, 0x2b, + 0x18, 0x1b, 0x1f, 0x1f, 0x1b, 0x1b, 0x1f, 0x1f, 0xee, 0x2f, 0x28, 0x05, + 0x05, 0x11, 0x4b, 0x3f, 0x51, 0x60, 0x69, 0x75, 0x6e, 0x40, 0x3b, 0x34, + 0x42, 0x14, 0x36, 0x0a, 0x22, 0x32, 0x40, 0x27, 0x5b, 0x6b, 0x48, 0xfe, + 0xdb, 0x1f, 0x33, 0x26, 0x15, 0x6e, 0x48, 0x42, 0x39, 0x02, 0x40, 0x11, + 0x1f, 0x2a, 0x19, 0x19, 0x2a, 0x1f, 0x11, 0x11, 0x1f, 0x2a, 0x19, 0x19, + 0x2a, 0x1f, 0x11, 0x31, 0x1d, 0x1a, 0x16, 0x1a, 0x1d, 0x1d, 0x1a, 0x16, + 0x1a, 0x1d, 0xfd, 0x8f, 0x30, 0x24, 0x2d, 0x33, 0x54, 0x49, 0x48, 0x4e, + 0x33, 0x39, 0x39, 0x29, 0x23, 0x28, 0x14, 0x26, 0x1d, 0x11, 0x5c, 0x52, + 0xfe, 0xe4, 0x46, 0x37, 0x0f, 0x19, 0x23, 0x14, 0x55, 0x28, 0x26, 0x15, + 0x28, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0a, 0xff, 0xf4, 0x02, 0x46, + 0x02, 0x10, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4c, 0x00, 0xcd, 0xba, 0x00, + 0x18, 0x00, 0x4d, 0x00, 0x4e, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x18, 0x10, + 0xb8, 0x00, 0x3b, 0xd0, 0xb8, 0x00, 0x18, 0x10, 0xb8, 0x00, 0x48, 0xd0, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x14, 0x2f, 0x1b, 0xb9, + 0x00, 0x14, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x1b, 0x2f, 0x1b, 0xb9, 0x00, 0x1b, 0x00, 0x1b, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, + 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x2f, + 0x2f, 0x1b, 0xb9, 0x00, 0x2f, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x14, + 0x10, 0xb9, 0x00, 0x0b, 0x00, 0x01, 0xf4, 0xb8, 0x00, 0x00, 0x10, 0xb9, + 0x00, 0x36, 0x00, 0x01, 0xf4, 0xba, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x36, + 0x11, 0x12, 0x39, 0xb8, 0x00, 0x06, 0x2f, 0xba, 0x00, 0x17, 0x00, 0x0b, + 0x00, 0x36, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x2f, 0x10, 0xb9, 0x00, 0x24, + 0x00, 0x01, 0xf4, 0xb8, 0x00, 0x1b, 0x10, 0xb9, 0x00, 0x44, 0x00, 0x01, + 0xf4, 0xba, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x44, 0x11, 0x12, 0x39, 0xb8, + 0x00, 0x1f, 0x2f, 0xba, 0x00, 0x33, 0x00, 0x36, 0x00, 0x0b, 0x11, 0x12, + 0x39, 0xb8, 0x00, 0x06, 0x10, 0xb9, 0x00, 0x3d, 0x00, 0x01, 0xf4, 0xb8, + 0x00, 0x1f, 0x10, 0xb9, 0x00, 0x49, 0x00, 0x01, 0xf4, 0x30, 0x31, 0x17, + 0x22, 0x26, 0x35, 0x34, 0x36, 0x3b, 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, + 0x06, 0x07, 0x27, 0x3e, 0x03, 0x33, 0x32, 0x16, 0x17, 0x33, 0x3e, 0x01, + 0x33, 0x32, 0x16, 0x1d, 0x01, 0x21, 0x15, 0x14, 0x16, 0x33, 0x32, 0x3e, + 0x02, 0x37, 0x17, 0x0e, 0x03, 0x23, 0x22, 0x26, 0x27, 0x23, 0x0e, 0x01, + 0x27, 0x32, 0x3e, 0x02, 0x3d, 0x01, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, + 0x16, 0x01, 0x22, 0x06, 0x1d, 0x01, 0x33, 0x35, 0x34, 0x26, 0x8d, 0x39, + 0x4a, 0x5b, 0x57, 0x3f, 0x2b, 0x26, 0x26, 0x2b, 0x0e, 0x35, 0x08, 0x1b, + 0x25, 0x31, 0x1e, 0x2d, 0x3e, 0x11, 0x03, 0x14, 0x41, 0x27, 0x4e, 0x50, + 0xfe, 0xfe, 0x31, 0x2f, 0x13, 0x1f, 0x17, 0x11, 0x06, 0x3a, 0x08, 0x1b, + 0x27, 0x33, 0x1f, 0x33, 0x4a, 0x15, 0x03, 0x0e, 0x43, 0x21, 0x18, 0x24, + 0x18, 0x0c, 0x34, 0x37, 0x3d, 0x20, 0x01, 0x31, 0x2e, 0x32, 0xc0, 0x32, + 0x0c, 0x4c, 0x4a, 0x4e, 0x4f, 0x35, 0x43, 0x35, 0x2c, 0x23, 0x21, 0x14, + 0x26, 0x1e, 0x12, 0x28, 0x26, 0x2b, 0x23, 0x77, 0x75, 0x36, 0x19, 0x47, + 0x5a, 0x0f, 0x19, 0x20, 0x11, 0x1b, 0x17, 0x2d, 0x24, 0x16, 0x3c, 0x36, + 0x3b, 0x37, 0x3e, 0x11, 0x1d, 0x25, 0x15, 0x54, 0x28, 0x2e, 0x0f, 0x29, + 0x2e, 0x01, 0xa4, 0x45, 0x48, 0x22, 0x22, 0x48, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x54, 0xff, 0x31, 0x02, 0x04, 0x02, 0x10, 0x00, 0x3b, + 0x00, 0x72, 0xba, 0x00, 0x32, 0x00, 0x3c, 0x00, 0x3d, 0x11, 0x12, 0x39, + 0x00, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, + 0x00, 0x00, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, + 0x00, 0x34, 0x2f, 0x1b, 0xb9, 0x00, 0x34, 0x00, 0x0f, 0x3e, 0x59, 0xb8, + 0x00, 0x00, 0x10, 0xb9, 0x00, 0x07, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x34, + 0x10, 0xb9, 0x00, 0x12, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x34, 0x10, 0xb8, + 0x00, 0x19, 0xd0, 0xb8, 0x00, 0x34, 0x10, 0xb8, 0x00, 0x1d, 0xdc, 0x41, + 0x07, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x2f, 0x00, + 0x1d, 0x00, 0x03, 0x5d, 0xb8, 0x00, 0x32, 0xdc, 0xb8, 0x00, 0x2c, 0xdc, + 0xb9, 0x00, 0x25, 0x00, 0x03, 0xf4, 0x30, 0x31, 0x01, 0x32, 0x16, 0x17, + 0x07, 0x2e, 0x01, 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, + 0x33, 0x32, 0x36, 0x37, 0x17, 0x0e, 0x01, 0x0f, 0x01, 0x17, 0x36, 0x33, + 0x32, 0x16, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x37, 0x1e, + 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2f, 0x01, 0x37, 0x2e, 0x01, + 0x35, 0x34, 0x3e, 0x02, 0x01, 0x3d, 0x4b, 0x5e, 0x16, 0x40, 0x0e, 0x41, + 0x30, 0x23, 0x37, 0x26, 0x13, 0x13, 0x26, 0x38, 0x24, 0x34, 0x44, 0x14, + 0x39, 0x17, 0x5c, 0x4b, 0x0a, 0x03, 0x13, 0x14, 0x1d, 0x27, 0x12, 0x1f, + 0x28, 0x16, 0x29, 0x2f, 0x0b, 0x26, 0x09, 0x1e, 0x16, 0x13, 0x19, 0x1a, + 0x2a, 0x1c, 0x0e, 0x5c, 0x65, 0x20, 0x3c, 0x56, 0x02, 0x10, 0x42, 0x35, + 0x22, 0x28, 0x2c, 0x17, 0x2a, 0x3a, 0x22, 0x58, 0x22, 0x3a, 0x2a, 0x17, + 0x30, 0x2a, 0x27, 0x33, 0x43, 0x02, 0x31, 0x03, 0x06, 0x22, 0x20, 0x15, + 0x20, 0x14, 0x0a, 0x1b, 0x0e, 0x29, 0x0b, 0x11, 0x0f, 0x10, 0x0e, 0x15, + 0x06, 0x04, 0x44, 0x0e, 0x8e, 0x6f, 0x3d, 0x64, 0x47, 0x26, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x43, 0xff, 0xf4, 0x02, 0x15, 0x03, 0x0b, 0x12, 0x26, + 0x00, 0x48, 0x00, 0x00, 0x10, 0x06, 0x00, 0x43, 0x02, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x43, 0xff, 0xf4, 0x02, 0x15, 0x03, 0x0b, 0x12, 0x26, + 0x00, 0x48, 0x00, 0x00, 0x10, 0x06, 0x00, 0x76, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0xff, 0xf4, 0x02, 0x15, 0x02, 0xfd, 0x00, 0x06, + 0x00, 0x24, 0x00, 0x31, 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, + 0x37, 0x13, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, + 0x02, 0x1d, 0x01, 0x21, 0x15, 0x14, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x37, + 0x17, 0x0e, 0x01, 0x03, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x21, 0x35, 0x34, + 0x2e, 0x02, 0x01, 0x60, 0x6f, 0x2d, 0x75, 0x75, 0x2b, 0x6f, 0x39, 0x38, + 0x59, 0x3f, 0x22, 0x23, 0x3e, 0x57, 0x35, 0x34, 0x55, 0x3c, 0x20, 0xfe, + 0x82, 0x16, 0x29, 0x3b, 0x24, 0x34, 0x4c, 0x14, 0x3b, 0x17, 0x6b, 0x52, + 0x21, 0x38, 0x29, 0x17, 0x01, 0x28, 0x15, 0x25, 0x35, 0x02, 0xfd, 0x8f, + 0x1f, 0x75, 0x75, 0x1f, 0x8f, 0xfc, 0xf7, 0x26, 0x47, 0x63, 0x3d, 0x3e, + 0x64, 0x47, 0x26, 0x26, 0x43, 0x5c, 0x37, 0x26, 0x18, 0x22, 0x3a, 0x2a, + 0x17, 0x30, 0x2a, 0x28, 0x34, 0x43, 0x01, 0xda, 0x18, 0x2a, 0x39, 0x22, + 0x07, 0x0b, 0x22, 0x38, 0x29, 0x16, 0x00, 0x00, 0xff, 0xff, 0x00, 0x43, + 0xff, 0xf4, 0x02, 0x15, 0x02, 0xd4, 0x12, 0x26, 0x00, 0x48, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x6a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x6a, + 0x00, 0x00, 0x02, 0x22, 0x03, 0x0b, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, + 0x37, 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x13, 0x37, + 0x17, 0x07, 0x6a, 0xba, 0xba, 0x01, 0x0a, 0xae, 0xfe, 0x48, 0x71, 0x49, + 0x55, 0x34, 0x44, 0x01, 0x7c, 0x44, 0xfe, 0x40, 0x44, 0x02, 0xe8, 0x23, + 0xaa, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x6a, 0x00, 0x00, 0x02, 0x22, + 0x03, 0x0b, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x37, 0x33, 0x11, 0x23, + 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x13, 0x27, 0x37, 0x17, 0x6a, 0xba, + 0xba, 0x01, 0x0a, 0xae, 0xfe, 0x48, 0xe9, 0x34, 0x55, 0x49, 0x44, 0x01, + 0x7c, 0x44, 0xfe, 0x40, 0x44, 0x02, 0x49, 0x18, 0xaa, 0x23, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x6a, 0x00, 0x00, 0x02, 0x22, 0x02, 0xfd, 0x00, 0x06, + 0x00, 0x10, 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x03, + 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, 0x01, 0x7e, 0x6f, + 0x2d, 0x75, 0x75, 0x2b, 0x6f, 0xb0, 0xba, 0xba, 0x01, 0x0a, 0xae, 0xfe, + 0x48, 0x02, 0xfd, 0x8f, 0x1f, 0x75, 0x75, 0x1f, 0x8f, 0xfd, 0x47, 0x01, + 0x7c, 0x44, 0xfe, 0x40, 0x44, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x6a, + 0x00, 0x00, 0x02, 0x22, 0x02, 0xd4, 0x00, 0x09, 0x00, 0x17, 0x00, 0x25, + 0x00, 0x00, 0x37, 0x33, 0x11, 0x23, 0x35, 0x21, 0x11, 0x33, 0x15, 0x21, + 0x13, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, + 0x14, 0x06, 0x33, 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x1d, 0x01, 0x14, 0x06, 0x6a, 0xba, 0xba, 0x01, 0x0a, 0xae, 0xfe, 0x48, + 0x85, 0x1f, 0x1a, 0x1a, 0x1f, 0x1f, 0x1a, 0x1a, 0x9b, 0x1f, 0x1a, 0x1a, + 0x1f, 0x1f, 0x1a, 0x1a, 0x44, 0x01, 0x7c, 0x44, 0xfe, 0x40, 0x44, 0x02, + 0x6a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x1a, + 0x14, 0x0e, 0x14, 0x1a, 0x1a, 0x14, 0x0e, 0x14, 0x1a, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x42, 0xff, 0xf4, 0x02, 0x16, 0x02, 0xf1, 0x00, 0x25, + 0x00, 0x33, 0x00, 0x5f, 0xba, 0x00, 0x26, 0x00, 0x34, 0x00, 0x35, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x26, 0x10, 0xb8, 0x00, 0x09, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x20, 0x2f, 0x1b, 0xb9, 0x00, 0x20, + 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x09, + 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x13, + 0x00, 0x20, 0x00, 0x09, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x13, 0x2f, 0xb9, + 0x00, 0x2d, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x09, 0x10, 0xb9, 0x00, 0x26, + 0x00, 0x08, 0xf4, 0xba, 0x00, 0x16, 0x00, 0x2d, 0x00, 0x26, 0x11, 0x12, + 0x39, 0x30, 0x31, 0x01, 0x07, 0x1e, 0x03, 0x15, 0x14, 0x06, 0x23, 0x22, + 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, 0x17, 0x37, 0x2e, + 0x01, 0x27, 0x07, 0x27, 0x37, 0x2e, 0x01, 0x27, 0x33, 0x1e, 0x01, 0x17, + 0x37, 0x03, 0x32, 0x36, 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, + 0x01, 0x14, 0x16, 0x01, 0xcb, 0x57, 0x1f, 0x3b, 0x2d, 0x1b, 0x7c, 0x6b, + 0x38, 0x58, 0x3d, 0x20, 0x20, 0x39, 0x4e, 0x2f, 0x3d, 0x50, 0x18, 0x04, + 0x19, 0x43, 0x2a, 0x63, 0x26, 0x5c, 0x21, 0x48, 0x26, 0x7e, 0x11, 0x25, + 0x14, 0x5e, 0x79, 0x43, 0x52, 0x52, 0x43, 0x43, 0x52, 0x52, 0x02, 0xc4, + 0x3d, 0x1f, 0x4e, 0x5e, 0x71, 0x41, 0x8c, 0x8a, 0x24, 0x44, 0x5f, 0x3b, + 0x3b, 0x5f, 0x44, 0x24, 0x38, 0x28, 0x02, 0x3e, 0x60, 0x28, 0x46, 0x2d, + 0x40, 0x1a, 0x2e, 0x15, 0x0b, 0x19, 0x10, 0x41, 0xfd, 0x48, 0x4c, 0x4e, + 0x46, 0x4e, 0x4c, 0x4c, 0x4e, 0x46, 0x4e, 0x4c, 0x00, 0x02, 0x00, 0x62, + 0x00, 0x00, 0x01, 0xfc, 0x02, 0xd8, 0x00, 0x19, 0x00, 0x32, 0x00, 0x00, + 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, + 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x17, + 0x0e, 0x01, 0x01, 0x11, 0x33, 0x15, 0x33, 0x3e, 0x03, 0x33, 0x32, 0x16, + 0x15, 0x11, 0x23, 0x11, 0x34, 0x26, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x11, + 0x01, 0x78, 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, 0x0f, 0x21, + 0x0e, 0x2e, 0x23, 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, 0x0f, + 0x21, 0x0e, 0x2e, 0xfe, 0xc7, 0x50, 0x04, 0x08, 0x18, 0x23, 0x30, 0x20, + 0x51, 0x62, 0x50, 0x3e, 0x3c, 0x18, 0x2e, 0x24, 0x16, 0x02, 0x64, 0x12, + 0x08, 0x0d, 0x0b, 0x0e, 0x0d, 0x28, 0x14, 0x21, 0x12, 0x08, 0x0d, 0x0b, + 0x0e, 0x0d, 0x28, 0x14, 0x21, 0xfd, 0x9c, 0x02, 0x04, 0x54, 0x13, 0x23, + 0x1a, 0x10, 0x67, 0x5e, 0xfe, 0xb5, 0x01, 0x3d, 0x47, 0x45, 0x0c, 0x18, + 0x26, 0x19, 0xfe, 0x9a, 0xff, 0xff, 0x00, 0x42, 0xff, 0xf4, 0x02, 0x16, + 0x03, 0x0b, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x10, 0x06, 0x00, 0x43, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x42, 0xff, 0xf4, 0x02, 0x16, + 0x03, 0x0b, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x10, 0x06, 0x00, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x42, 0xff, 0xf4, 0x02, 0x16, + 0x02, 0xfd, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x28, 0x00, 0x00, 0x01, 0x17, + 0x07, 0x27, 0x07, 0x27, 0x37, 0x13, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, + 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, + 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, + 0x5e, 0x6f, 0x2d, 0x75, 0x75, 0x2b, 0x6f, 0x32, 0x36, 0x57, 0x3d, 0x20, + 0x20, 0x3d, 0x57, 0x36, 0x36, 0x57, 0x3d, 0x20, 0x20, 0x3d, 0x57, 0x36, + 0x43, 0x52, 0x52, 0x43, 0x43, 0x52, 0x52, 0x02, 0xfd, 0x8f, 0x1f, 0x75, + 0x75, 0x1f, 0x8f, 0xfc, 0xf7, 0x26, 0x47, 0x63, 0x3e, 0x3d, 0x64, 0x47, + 0x26, 0x26, 0x47, 0x64, 0x3d, 0x3e, 0x63, 0x47, 0x26, 0x45, 0x50, 0x54, + 0x4a, 0x54, 0x50, 0x50, 0x54, 0x4a, 0x54, 0x50, 0x00, 0x03, 0x00, 0x42, + 0xff, 0xf4, 0x02, 0x16, 0x02, 0xd8, 0x00, 0x19, 0x00, 0x2d, 0x00, 0x3b, + 0x00, 0x00, 0x01, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x07, + 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, + 0x37, 0x17, 0x0e, 0x01, 0x03, 0x22, 0x2e, 0x02, 0x35, 0x34, 0x3e, 0x02, + 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x0e, 0x02, 0x27, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x14, 0x16, 0x01, 0x75, + 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, 0x0f, 0x21, 0x0e, 0x2e, + 0x23, 0x1a, 0x26, 0x10, 0x18, 0x21, 0x0d, 0x11, 0x1a, 0x0f, 0x21, 0x0e, + 0x2e, 0x6c, 0x36, 0x57, 0x3d, 0x20, 0x20, 0x3d, 0x57, 0x36, 0x36, 0x57, + 0x3d, 0x20, 0x20, 0x3d, 0x57, 0x36, 0x43, 0x52, 0x52, 0x43, 0x43, 0x52, + 0x52, 0x02, 0x64, 0x12, 0x08, 0x0d, 0x0b, 0x0e, 0x0d, 0x28, 0x14, 0x21, + 0x12, 0x08, 0x0d, 0x0b, 0x0e, 0x0d, 0x28, 0x14, 0x21, 0xfd, 0x90, 0x26, + 0x47, 0x63, 0x3e, 0x3d, 0x64, 0x47, 0x26, 0x26, 0x47, 0x64, 0x3d, 0x3e, + 0x63, 0x47, 0x26, 0x45, 0x50, 0x54, 0x4a, 0x54, 0x50, 0x50, 0x54, 0x4a, + 0x54, 0x50, 0x00, 0x00, 0xff, 0xff, 0x00, 0x42, 0xff, 0xf4, 0x02, 0x16, + 0x02, 0xd4, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x10, 0x06, 0x00, 0x6a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x34, 0x02, 0x1a, + 0x02, 0x2e, 0x00, 0x03, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x43, 0xba, 0x00, + 0x04, 0x00, 0x20, 0x00, 0x21, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x04, 0x10, + 0xb8, 0x00, 0x00, 0xd0, 0xb8, 0x00, 0x04, 0x10, 0xb8, 0x00, 0x12, 0xd0, + 0x00, 0xbb, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x2b, 0xb8, + 0x00, 0x00, 0x10, 0xb8, 0x00, 0x0b, 0xdc, 0xb9, 0x00, 0x04, 0x00, 0x06, + 0xf4, 0xb8, 0x00, 0x01, 0x10, 0xb8, 0x00, 0x12, 0xdc, 0xb9, 0x00, 0x19, + 0x00, 0x06, 0xf4, 0x30, 0x31, 0x13, 0x35, 0x21, 0x15, 0x07, 0x22, 0x26, + 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, 0x06, 0x03, + 0x22, 0x26, 0x3d, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x1d, 0x01, 0x14, + 0x06, 0x3e, 0x01, 0xdc, 0xee, 0x23, 0x1b, 0x1b, 0x23, 0x23, 0x1b, 0x1b, + 0x23, 0x23, 0x1b, 0x1b, 0x23, 0x23, 0x1b, 0x1b, 0x01, 0x0f, 0x44, 0x44, + 0xdb, 0x1c, 0x14, 0x16, 0x14, 0x1c, 0x1c, 0x14, 0x16, 0x14, 0x1c, 0x01, + 0x84, 0x1c, 0x14, 0x16, 0x14, 0x1c, 0x1c, 0x14, 0x16, 0x14, 0x1c, 0x00, + 0x00, 0x03, 0x00, 0x2f, 0xff, 0xd8, 0x02, 0x29, 0x02, 0x2c, 0x00, 0x1b, + 0x00, 0x24, 0x00, 0x2d, 0x00, 0x9f, 0xba, 0x00, 0x17, 0x00, 0x2e, 0x00, + 0x2f, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x17, 0x10, 0xb8, 0x00, 0x1c, 0xd0, + 0xb8, 0x00, 0x17, 0x10, 0xb8, 0x00, 0x25, 0xd0, 0x00, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x09, 0x2f, 0x1b, 0xb9, 0x00, 0x09, 0x00, 0x1b, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x17, 0x2f, 0x1b, + 0xb9, 0x00, 0x17, 0x00, 0x0f, 0x3e, 0x59, 0xba, 0x00, 0x01, 0x00, 0x09, + 0x00, 0x17, 0x11, 0x12, 0x39, 0xb9, 0x00, 0x25, 0x00, 0x08, 0xf4, 0xba, + 0x00, 0x0c, 0x00, 0x09, 0x00, 0x25, 0x11, 0x12, 0x39, 0xba, 0x00, 0x0f, + 0x00, 0x09, 0x00, 0x25, 0x11, 0x12, 0x39, 0xba, 0x00, 0x1a, 0x00, 0x09, + 0x00, 0x17, 0x11, 0x12, 0x39, 0xb8, 0x00, 0x09, 0x10, 0xb9, 0x00, 0x1c, + 0x00, 0x08, 0xf4, 0xba, 0x00, 0x22, 0x00, 0x09, 0x00, 0x25, 0x11, 0x12, + 0x39, 0xba, 0x00, 0x23, 0x00, 0x1c, 0x00, 0x17, 0x11, 0x12, 0x39, 0xba, + 0x00, 0x2b, 0x00, 0x1c, 0x00, 0x17, 0x11, 0x12, 0x39, 0xba, 0x00, 0x2c, + 0x00, 0x09, 0x00, 0x25, 0x11, 0x12, 0x39, 0x30, 0x31, 0x17, 0x37, 0x2e, + 0x01, 0x35, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x16, 0x17, 0x37, 0x17, 0x07, + 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x26, 0x27, 0x07, 0x13, + 0x22, 0x06, 0x1d, 0x01, 0x14, 0x17, 0x13, 0x26, 0x03, 0x32, 0x36, 0x3d, + 0x01, 0x34, 0x27, 0x03, 0x16, 0x2f, 0x45, 0x18, 0x1a, 0x20, 0x3d, 0x57, + 0x36, 0x2c, 0x48, 0x1d, 0x3f, 0x2d, 0x45, 0x18, 0x1a, 0x20, 0x3d, 0x57, + 0x36, 0x2c, 0x48, 0x1d, 0x3f, 0xd0, 0x43, 0x52, 0x0f, 0xeb, 0x25, 0x40, + 0x43, 0x52, 0x0f, 0xeb, 0x25, 0x06, 0x54, 0x23, 0x5b, 0x36, 0x3d, 0x64, + 0x47, 0x26, 0x1a, 0x17, 0x4d, 0x22, 0x54, 0x23, 0x5b, 0x36, 0x3e, 0x63, + 0x47, 0x26, 0x1a, 0x17, 0x4d, 0x01, 0xf3, 0x50, 0x54, 0x4a, 0x32, 0x21, + 0x01, 0x1f, 0x22, 0xfe, 0x6e, 0x50, 0x54, 0x4a, 0x32, 0x21, 0xfe, 0xe1, + 0x22, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x5c, 0xff, 0xf4, 0x01, 0xf6, + 0x03, 0x0b, 0x12, 0x26, 0x00, 0x58, 0x00, 0x00, 0x10, 0x06, 0x00, 0x43, + 0xfe, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x5c, 0xff, 0xf4, 0x01, 0xf6, + 0x03, 0x0b, 0x12, 0x26, 0x00, 0x58, 0x00, 0x00, 0x10, 0x06, 0x00, 0x76, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5c, 0xff, 0xf4, 0x01, 0xf6, + 0x02, 0xfd, 0x00, 0x06, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x17, 0x07, 0x27, + 0x07, 0x27, 0x37, 0x13, 0x23, 0x0e, 0x03, 0x23, 0x22, 0x26, 0x35, 0x11, + 0x33, 0x11, 0x14, 0x16, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x11, 0x33, 0x11, + 0x23, 0x01, 0x5c, 0x6f, 0x2d, 0x75, 0x75, 0x2b, 0x6f, 0xae, 0x04, 0x08, + 0x18, 0x23, 0x30, 0x20, 0x51, 0x62, 0x50, 0x3e, 0x3c, 0x18, 0x2e, 0x24, + 0x16, 0x50, 0x50, 0x02, 0xfd, 0x8f, 0x1f, 0x75, 0x75, 0x1f, 0x8f, 0xfd, + 0x57, 0x13, 0x23, 0x1a, 0x10, 0x67, 0x5e, 0x01, 0x4b, 0xfe, 0xc3, 0x47, + 0x45, 0x0c, 0x18, 0x25, 0x1a, 0x01, 0x66, 0xfd, 0xfc, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x5c, 0xff, 0xf4, 0x01, 0xf6, 0x02, 0xd4, 0x12, 0x26, + 0x00, 0x58, 0x00, 0x00, 0x10, 0x06, 0x00, 0x6a, 0xfe, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x35, 0xff, 0x38, 0x02, 0x23, 0x03, 0x0b, 0x12, 0x26, + 0x00, 0x5c, 0x00, 0x00, 0x10, 0x06, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x5f, 0xff, 0x38, 0x02, 0x1c, 0x02, 0xe4, 0x00, 0x10, + 0x00, 0x22, 0x00, 0x81, 0xba, 0x00, 0x11, 0x00, 0x23, 0x00, 0x24, 0x11, + 0x12, 0x39, 0xb8, 0x00, 0x11, 0x10, 0xb8, 0x00, 0x0b, 0xd0, 0x00, 0xb8, + 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x00, 0x2f, 0x1b, 0xb9, 0x00, 0x00, + 0x00, 0x1f, 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x05, + 0x2f, 0x1b, 0xb9, 0x00, 0x05, 0x00, 0x1b, 0x3e, 0x59, 0xb8, 0x00, 0x00, + 0x45, 0x58, 0xb8, 0x00, 0x10, 0x2f, 0x1b, 0xb9, 0x00, 0x10, 0x00, 0x11, + 0x3e, 0x59, 0xb8, 0x00, 0x00, 0x45, 0x58, 0xb8, 0x00, 0x0b, 0x2f, 0x1b, + 0xb9, 0x00, 0x0b, 0x00, 0x0f, 0x3e, 0x59, 0xb8, 0x00, 0x05, 0x10, 0xb9, + 0x00, 0x18, 0x00, 0x08, 0xf4, 0xb8, 0x00, 0x0b, 0x10, 0xb9, 0x00, 0x11, + 0x00, 0x08, 0xf4, 0xba, 0x00, 0x02, 0x00, 0x18, 0x00, 0x11, 0x11, 0x12, + 0x39, 0xba, 0x00, 0x0d, 0x00, 0x11, 0x00, 0x18, 0x11, 0x12, 0x39, 0x30, + 0x31, 0x13, 0x33, 0x11, 0x33, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, + 0x23, 0x22, 0x27, 0x23, 0x11, 0x23, 0x13, 0x32, 0x36, 0x3d, 0x01, 0x34, + 0x26, 0x23, 0x22, 0x0e, 0x02, 0x1d, 0x01, 0x14, 0x1e, 0x02, 0x5f, 0x50, + 0x04, 0x32, 0x6d, 0x5f, 0x6b, 0x6b, 0x5f, 0x6d, 0x32, 0x04, 0x50, 0xd4, + 0x46, 0x4d, 0x4d, 0x46, 0x1b, 0x30, 0x24, 0x15, 0x15, 0x24, 0x30, 0x02, + 0xe4, 0xfe, 0xcc, 0x60, 0x8e, 0x80, 0x80, 0x8e, 0x60, 0xfe, 0xe4, 0x01, + 0x03, 0x55, 0x46, 0x58, 0x46, 0x55, 0x0e, 0x1b, 0x27, 0x1a, 0xba, 0x1a, + 0x27, 0x1b, 0x0e, 0x00, 0xff, 0xff, 0x00, 0x35, 0xff, 0x38, 0x02, 0x23, + 0x02, 0xd4, 0x12, 0x26, 0x00, 0x5c, 0x00, 0x00, 0x10, 0x06, 0x00, 0x6a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x04, 0x9e, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x5c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0xa6, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0xc4, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1e, 0x01, 0x0a, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0d, 0x01, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x6f, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x01, 0x95, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x51, 0x02, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x02, 0xaf, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x33, 0x03, 0x23, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x19, 0x03, 0x8b, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x12, 0x03, 0xcb, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x90, 0x05, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x05, 0xc7, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x3a, 0x06, 0x58, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x12, 0x0c, 0x0a, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x18, 0x06, 0x93, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x12, 0x0b, 0xd1, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x11, 0x07, 0x1a, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x13, 0x0b, 0x97, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x09, 0x07, 0x51, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x11, 0x0b, 0x5d, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x0b, 0x07, 0x6d, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x1a, 0x0b, 0x1e, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x11, 0x07, 0x99, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x15, 0x0a, 0xd2, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x18, 0x08, 0x08, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x09, 0x08, 0x6f, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x18, 0x0a, 0x8d, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x00, 0x09, 0x08, 0xac, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x0c, 0x08, 0xea, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x12, 0x09, 0x32, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x12, 0x09, 0x92, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x12, 0x09, 0xf9, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x18, 0x06, 0xac, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x12, 0x07, 0x2c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x09, 0x07, 0x5b, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x12, 0x07, 0x79, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x04, 0x00, 0x1f, 0x07, 0xab, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x05, 0x00, 0x1a, 0x08, 0x21, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00, 0x13, 0x08, 0x79, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x13, 0x08, 0xb6, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x10, 0x08, 0xf7, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x16, 0x09, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x1f, 0x09, 0xa5, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x0b, 0x00, 0x23, 0x0a, 0x0c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x21, 0x06, 0xc5, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x04, 0x00, 0x17, 0x07, 0xcb, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x05, 0x00, 0x06, 0x08, 0x3c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x0c, 0x08, 0x8d, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x07, 0x00, 0x0c, 0x08, 0xca, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x08, 0x00, 0x0b, 0x09, 0x08, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x09, 0x00, 0x10, 0x09, 0x5c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x0a, 0x00, 0x10, 0x09, 0xc5, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x0b, 0x00, 0x0f, 0x0a, 0x30, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x15, 0x06, 0xe7, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x04, 0x00, 0x11, 0x07, 0xe3, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x05, 0x00, 0x11, 0x08, 0x43, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x06, 0x00, 0x05, 0x08, 0x9a, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x07, 0x00, 0x06, 0x08, 0xd7, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x08, 0x00, 0x10, 0x09, 0x14, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x09, 0x00, 0x12, 0x09, 0x6d, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x0a, 0x00, 0x13, 0x09, 0xd6, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x0b, 0x00, 0x0c, 0x0a, 0x40, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x1c, 0x06, 0xfd, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x11, 0x07, 0x3f, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x00, 0x07, 0x07, 0x65, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x03, 0x00, 0x0c, 0x07, 0x8c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x04, 0x00, 0x12, 0x07, 0xf5, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x05, 0x00, 0x19, 0x08, 0x55, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x06, 0x00, 0x0b, 0x08, 0xa0, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x07, 0x00, 0x0b, 0x08, 0xde, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x08, 0x00, 0x0c, 0x09, 0x25, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x09, 0x00, 0x11, 0x09, 0x80, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x0a, 0x00, 0x0e, 0x09, 0xea, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x0b, 0x00, 0x0d, 0x0a, 0x4d, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x8a, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0e, 0x00, 0xb4, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x3c, 0x00, 0xcc, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x1a, 0x01, 0x29, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x1a, 0x01, 0x53, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x16, 0x01, 0x7d, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x07, 0x00, 0xa2, 0x01, 0xa1, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x08, 0x00, 0x16, 0x02, 0x97, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x09, 0x00, 0x66, 0x02, 0xbb, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0b, 0x00, 0x32, 0x03, 0x57, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0c, 0x00, 0x24, 0x03, 0xa5, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0d, 0x01, 0x20, 0x03, 0xde, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0e, 0x00, 0x34, 0x05, 0x91, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x13, 0x00, 0x74, 0x05, 0xe2, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x00, 0x00, 0x24, 0x0b, 0xe4, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x01, 0x00, 0x24, 0x0b, 0xab, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x02, 0x00, 0x26, 0x0b, 0x6f, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x03, 0x00, 0x22, 0x0b, 0x39, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x04, 0x00, 0x34, 0x0a, 0xe8, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x05, 0x00, 0x2a, 0x0a, 0xa6, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x01, 0x06, 0x00, 0x30, 0x0a, 0x5b, 0x00, 0x43, + 0x00, 0x6f, 0x00, 0x70, 0x00, 0x79, 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, + 0x00, 0x68, 0x00, 0x74, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, + 0x00, 0x37, 0x00, 0x20, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, + 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x2e, 0x00, 0x20, + 0x00, 0x41, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x72, 0x00, 0x69, + 0x00, 0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x73, 0x00, 0x20, 0x00, 0x72, + 0x00, 0x65, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x65, + 0x00, 0x64, 0x00, 0x2e, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x32, 0x30, 0x31, 0x37, 0x20, 0x49, 0x42, 0x4d, + 0x20, 0x43, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x2e, 0x00, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, + 0x00, 0x50, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, 0x20, 0x00, 0x4d, + 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x00, 0x49, 0x42, 0x4d, 0x20, + 0x50, 0x6c, 0x65, 0x78, 0x20, 0x4d, 0x6f, 0x6e, 0x6f, 0x00, 0x00, 0x52, + 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x72, + 0x00, 0x00, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x00, 0x32, + 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x49, + 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, 0x00, 0x3b, 0x00, 0x49, 0x00, 0x42, + 0x00, 0x4d, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, 0x4d, + 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x2d, 0x00, 0x52, 0x00, 0x65, + 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, + 0x32, 0x2e, 0x30, 0x30, 0x34, 0x3b, 0x49, 0x42, 0x4d, 0x20, 0x3b, 0x49, + 0x42, 0x4d, 0x50, 0x6c, 0x65, 0x78, 0x4d, 0x6f, 0x6e, 0x6f, 0x2d, 0x52, + 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x00, 0x49, 0x00, 0x42, 0x00, + 0x4d, 0x00, 0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, + 0x20, 0x00, 0x4d, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x00, 0x49, + 0x42, 0x4d, 0x20, 0x50, 0x6c, 0x65, 0x78, 0x20, 0x4d, 0x6f, 0x6e, 0x6f, + 0x00, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, + 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, 0x00, + 0x30, 0x00, 0x34, 0x00, 0x00, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x20, 0x32, 0x2e, 0x30, 0x30, 0x34, 0x00, 0x00, 0x49, 0x00, 0x42, 0x00, + 0x4d, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, 0x4d, 0x00, + 0x6f, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x00, 0x49, 0x42, 0x4d, 0x50, 0x6c, + 0x65, 0x78, 0x4d, 0x6f, 0x6e, 0x6f, 0x00, 0x00, 0x49, 0x00, 0x42, 0x00, + 0x4d, 0x00, 0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x78, 0x00, + 0xae, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, + 0x20, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, + 0x6d, 0x00, 0x61, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x6f, 0x00, + 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x20, 0x00, + 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x2c, 0x00, 0x20, 0x00, + 0x72, 0x00, 0x65, 0x00, 0x67, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x69, 0x00, + 0x6e, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x79, 0x00, + 0x20, 0x00, 0x6a, 0x00, 0x75, 0x00, 0x72, 0x00, 0x69, 0x00, 0x73, 0x00, + 0x64, 0x00, 0x69, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, + 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x72, 0x00, + 0x6c, 0x00, 0x64, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, 0x00, + 0x2e, 0x00, 0x00, 0x49, 0x42, 0x4d, 0x20, 0x50, 0x6c, 0x65, 0x78, 0xa8, + 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x61, 0x64, 0x65, 0x6d, + 0x61, 0x72, 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x49, 0x42, 0x4d, 0x20, 0x43, + 0x6f, 0x72, 0x70, 0x2c, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, + 0x6a, 0x75, 0x72, 0x69, 0x73, 0x64, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x77, 0x69, 0x64, 0x65, 0x2e, + 0x00, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x20, 0x00, + 0x4d, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x79, 0x00, + 0x00, 0x42, 0x6f, 0x6c, 0x64, 0x20, 0x4d, 0x6f, 0x6e, 0x64, 0x61, 0x79, + 0x00, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x6b, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x41, 0x00, 0x62, 0x00, 0x62, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6b, 0x00, + 0x2c, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61, 0x00, 0x75, 0x00, 0x6c, 0x00, + 0x20, 0x00, 0x76, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x64, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x61, 0x00, 0x61, 0x00, + 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x50, 0x00, 0x69, 0x00, 0x65, 0x00, + 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x76, 0x00, 0x61, 0x00, + 0x6e, 0x00, 0x20, 0x00, 0x52, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6d, 0x00, + 0x61, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x4d, 0x69, 0x6b, + 0x65, 0x20, 0x41, 0x62, 0x62, 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x50, 0x61, + 0x75, 0x6c, 0x20, 0x76, 0x61, 0x6e, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4c, + 0x61, 0x61, 0x6e, 0x2c, 0x20, 0x50, 0x69, 0x65, 0x74, 0x65, 0x72, 0x20, + 0x76, 0x61, 0x6e, 0x20, 0x52, 0x6f, 0x73, 0x6d, 0x61, 0x6c, 0x65, 0x6e, + 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, + 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, + 0x62, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x6f, 0x00, + 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x79, 0x00, 0x2e, 0x00, 0x63, 0x00, + 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x62, 0x6f, 0x6c, 0x64, 0x6d, 0x6f, 0x6e, 0x64, + 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, + 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, + 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x69, 0x00, 0x62, 0x00, 0x6d, 0x00, + 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x62, 0x6d, 0x2e, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, + 0x00, 0x20, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, + 0x00, 0x53, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x77, 0x00, 0x61, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, + 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, + 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4c, 0x00, 0x20, 0x00, 0x4f, + 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6f, + 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x63, + 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00, 0x20, + 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, + 0x00, 0x6e, 0x00, 0x20, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x2e, + 0x00, 0x20, 0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, + 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, + 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, + 0x00, 0x76, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x62, + 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x74, + 0x00, 0x68, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x46, 0x00, 0x41, + 0x00, 0x51, 0x00, 0x20, 0x00, 0x61, 0x00, 0x74, 0x00, 0x3a, 0x00, 0x20, + 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, + 0x00, 0x2f, 0x00, 0x73, 0x00, 0x63, 0x00, 0x72, 0x00, 0x69, 0x00, 0x70, + 0x00, 0x74, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6c, + 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x4f, + 0x00, 0x46, 0x00, 0x4c, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x46, + 0x6f, 0x6e, 0x74, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x20, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x64, + 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, + 0x49, 0x4c, 0x20, 0x4f, 0x70, 0x65, 0x6e, 0x20, 0x46, 0x6f, 0x6e, 0x74, + 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x31, 0x2e, 0x20, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, + 0x69, 0x73, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x46, 0x41, 0x51, 0x20, + 0x61, 0x74, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x2e, 0x73, 0x69, 0x6c, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x4f, 0x46, 0x4c, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, + 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x73, 0x00, + 0x63, 0x00, 0x72, 0x00, 0x69, 0x00, 0x70, 0x00, 0x74, 0x00, 0x73, 0x00, + 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6f, 0x00, + 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x4c, 0x00, + 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x73, 0x2e, 0x73, 0x69, 0x6c, 0x2e, 0x6f, 0x72, 0x67, 0x2f, + 0x4f, 0x46, 0x4c, 0x00, 0x00, 0x48, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x20, + 0x00, 0x72, 0x00, 0x61, 0x00, 0x7a, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x62, + 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x2d, 0x00, 0x6a, 0x00, 0x75, + 0x00, 0x6d, 0x00, 0x70, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x20, + 0x00, 0x66, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x73, 0x00, 0x20, + 0x00, 0x63, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x65, + 0x00, 0x76, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x73, 0x00, 0x69, + 0x00, 0x78, 0x00, 0x20, 0x00, 0x70, 0x00, 0x69, 0x00, 0x71, 0x00, 0x75, + 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x67, 0x00, 0x79, 0x00, 0x6d, + 0x00, 0x6e, 0x00, 0x61, 0x00, 0x73, 0x00, 0x74, 0x00, 0x73, 0x00, 0x21, + 0x00, 0x00, 0x48, 0x6f, 0x77, 0x20, 0x72, 0x61, 0x7a, 0x6f, 0x72, 0x62, + 0x61, 0x63, 0x6b, 0x2d, 0x6a, 0x75, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x20, + 0x66, 0x72, 0x6f, 0x67, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x20, 0x73, 0x69, 0x78, 0x20, 0x70, 0x69, 0x71, 0x75, + 0x65, 0x64, 0x20, 0x67, 0x79, 0x6d, 0x6e, 0x61, 0x73, 0x74, 0x73, 0x21, + 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x54, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x00, 0x46, 0x6f, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, + 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x71, 0x75, + 0x65, 0x73, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x6f, + 0x67, 0x72, 0x61, 0x66, 0x69, 0x73, 0x63, 0x68, 0x65, 0x6e, 0x20, 0x4d, + 0x9a, 0x67, 0x6c, 0x69, 0x63, 0x68, 0x6b, 0x65, 0x69, 0x74, 0x65, 0x6e, + 0x00, 0x46, 0x75, 0x6e, 0x7a, 0x69, 0x6f, 0x6e, 0x69, 0x20, 0x54, 0x69, + 0x70, 0x6f, 0x67, 0x72, 0x61, 0x66, 0x69, 0x63, 0x68, 0x65, 0x00, 0x41, + 0x6c, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x66, + 0x69, 0x73, 0x63, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x6e, 0x6d, 0x65, 0x72, + 0x6b, 0x65, 0x6e, 0x00, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, + 0x20, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x50, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x56, 0x65, 0x72, 0x74, 0x69, + 0x63, 0x61, 0x6c, 0x65, 0x00, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, + 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x65, 0x00, 0x46, + 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x46, 0x72, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x42, 0x72, 0x65, 0x75, 0x6b, + 0x65, 0x6e, 0x00, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x43, 0x61, + 0x73, 0x65, 0x00, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x64, 0x65, 0x73, + 0x20, 0x43, 0x68, 0x69, 0x66, 0x66, 0x72, 0x65, 0x73, 0x00, 0x4e, 0x75, + 0x6d, 0x6d, 0x65, 0x72, 0x68, 0x6f, 0x6f, 0x67, 0x74, 0x65, 0x00, 0x41, + 0x6c, 0x6c, 0x20, 0x54, 0x79, 0x70, 0x65, 0x20, 0x46, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x00, 0x54, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x20, + 0x66, 0x6f, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x79, + 0x70, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x71, 0x75, 0x65, 0x73, + 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, 0x41, 0x75, 0x73, 0x7a, 0x65, 0x69, + 0x63, 0x68, 0x6e, 0x75, 0x6e, 0x67, 0x73, 0x61, 0x72, 0x74, 0x65, 0x6e, + 0x00, 0x54, 0x75, 0x74, 0x74, 0x65, 0x20, 0x6c, 0x65, 0x20, 0x46, 0x75, + 0x6e, 0x7a, 0x69, 0x6f, 0x6e, 0x69, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, + 0x74, 0x79, 0x70, 0x65, 0x6b, 0x65, 0x6e, 0x6d, 0x65, 0x72, 0x6b, 0x65, + 0x6e, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x20, 0x56, 0x65, 0x72, + 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x00, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x4e, 0x6f, + 0x72, 0x6d, 0x61, 0x6c, 0x65, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, + 0x00, 0x50, 0x6f, 0x73, 0x69, 0x7a, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x4e, + 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x65, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, + 0x6c, 0x65, 0x20, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x65, + 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x65, 0x00, 0x53, 0x75, 0x70, + 0x65, 0x72, 0x69, 0x6f, 0x72, 0x73, 0x00, 0x50, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x75, 0x70, 0x8e, 0x72, 0x69, 0x65, 0x75, + 0x72, 0x65, 0x00, 0x48, 0x6f, 0x63, 0x68, 0x67, 0x65, 0x73, 0x74, 0x65, + 0x6c, 0x6c, 0x74, 0x00, 0x41, 0x70, 0x69, 0x63, 0x65, 0x00, 0x53, 0x75, + 0x70, 0x65, 0x72, 0x69, 0x65, 0x75, 0x72, 0x65, 0x6e, 0x00, 0x49, 0x6e, + 0x66, 0x65, 0x72, 0x69, 0x6f, 0x72, 0x73, 0x00, 0x50, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x6e, 0x66, 0x8e, 0x72, 0x69, 0x65, + 0x75, 0x72, 0x65, 0x00, 0x54, 0x69, 0x65, 0x66, 0x67, 0x65, 0x73, 0x74, + 0x65, 0x6c, 0x6c, 0x74, 0x00, 0x50, 0x65, 0x64, 0x69, 0x63, 0x65, 0x00, + 0x49, 0x6e, 0x66, 0x65, 0x72, 0x69, 0x65, 0x75, 0x72, 0x65, 0x6e, 0x00, + 0x4e, 0x6f, 0x20, 0x46, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x00, 0x50, 0x61, 0x73, 0x20, 0x64, 0x65, 0x20, 0x46, 0x72, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x4b, 0x65, 0x69, 0x6e, 0x20, 0x42, + 0x72, 0x75, 0x63, 0x68, 0x65, 0x00, 0x4e, 0x65, 0x73, 0x73, 0x75, 0x6e, + 0x61, 0x20, 0x46, 0x72, 0x61, 0x7a, 0x69, 0x6f, 0x6e, 0x65, 0x00, 0x47, + 0x65, 0x65, 0x6e, 0x20, 0x62, 0x72, 0x65, 0x75, 0x6b, 0x65, 0x6e, 0x00, + 0x44, 0x69, 0x61, 0x67, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x46, 0x72, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x46, 0x72, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x65, 0x6e, 0x20, 0x44, 0x69, 0x61, 0x67, + 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x00, 0x44, 0x69, 0x61, 0x67, 0x6f, 0x6e, + 0x61, 0x6c, 0x65, 0x72, 0x20, 0x42, 0x72, 0x75, 0x63, 0x68, 0x00, 0x46, + 0x72, 0x61, 0x7a, 0x69, 0x6f, 0x6e, 0x69, 0x20, 0x44, 0x69, 0x61, 0x67, + 0x6f, 0x6e, 0x61, 0x6c, 0x69, 0x00, 0x44, 0x69, 0x61, 0x67, 0x6f, 0x6e, + 0x61, 0x6c, 0x65, 0x20, 0x62, 0x72, 0x65, 0x75, 0x6b, 0x65, 0x6e, 0x00, + 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x43, 0x61, 0x73, 0x65, 0x20, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00, 0x43, 0x68, 0x69, 0x66, 0x66, + 0x72, 0x65, 0x73, 0x20, 0x41, 0x6e, 0x63, 0x69, 0x65, 0x6e, 0x73, 0x20, + 0x28, 0x62, 0x61, 0x73, 0x20, 0x64, 0x65, 0x20, 0x63, 0x61, 0x73, 0x73, + 0x65, 0x29, 0x00, 0x4d, 0x65, 0x64, 0x69, 0xbe, 0x76, 0x61, 0x6c, 0x2d, + 0x5a, 0x69, 0x66, 0x66, 0x65, 0x72, 0x6e, 0x00, 0x53, 0x6f, 0x70, 0x72, + 0x61, 0x20, 0x6c, 0x61, 0x20, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x20, 0x42, + 0x61, 0x73, 0x65, 0x00, 0x4b, 0x6c, 0x65, 0x69, 0x6e, 0x65, 0x20, 0x6e, + 0x75, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x00, 0x55, 0x70, 0x70, 0x65, 0x72, + 0x20, 0x43, 0x61, 0x73, 0x65, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x00, 0x43, 0x68, 0x69, 0x66, 0x66, 0x72, 0x65, 0x73, 0x20, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x20, 0x28, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x61, 0x6e, 0x74, 0x73, + 0x29, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x65, 0x20, 0x5a, 0x69, + 0x66, 0x66, 0x65, 0x72, 0x6e, 0x00, 0x54, 0x72, 0x61, 0x64, 0x69, 0x7a, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x00, 0x47, 0x72, 0x6f, 0x74, 0x65, + 0x20, 0x6e, 0x75, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x00, 0x00, 0x42, 0x00, + 0x75, 0x00, 0x6c, 0x00, 0x67, 0x00, 0x61, 0x00, 0x72, 0x00, 0x69, 0x00, + 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x43, 0x00, 0x79, 0x00, 0x72, 0x00, + 0x69, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x20, 0x00, + 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x00, 0x42, + 0x75, 0x6c, 0x67, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x43, 0x79, 0x72, + 0x69, 0x6c, 0x6c, 0x69, 0x63, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x00, + 0x00, 0x61, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, + 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x75, + 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x73, + 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x00, 0x61, 0x6c, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x20, 0x73, 0x69, 0x67, 0x6e, 0x00, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x74, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x65, 0x00, 0x72, + 0x00, 0x63, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x20, 0x00, 0x65, + 0x00, 0x73, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x00, + 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x6c, 0x6f, + 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, 0x65, 0x73, 0x7a, 0x65, + 0x74, 0x74, 0x00, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x69, 0x00, + 0x6e, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x6f, 0x00, 0x00, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x7a, 0x65, 0x72, 0x6f, 0x00, 0x00, 0x73, 0x00, + 0x6c, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x65, 0x00, 0x64, 0x00, + 0x20, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, + 0x72, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6f, 0x00, + 0x00, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x7a, 0x65, 0x72, 0x6f, 0x00, 0x00, 0x73, 0x00, + 0x69, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x6c, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x65, 0x00, 0x72, 0x00, 0x63, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x20, 0x00, 0x67, 0x00, 0x00, 0x73, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, + 0x61, 0x73, 0x65, 0x20, 0x67, 0x00, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6d, + 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x6f, + 0x00, 0x77, 0x00, 0x65, 0x00, 0x72, 0x00, 0x63, 0x00, 0x61, 0x00, 0x73, + 0x00, 0x65, 0x00, 0x20, 0x00, 0x61, 0x00, 0x00, 0x73, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, + 0x20, 0x61, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x74, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, + 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, + 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, + 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, + 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, + 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, + 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, + 0x00, 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, + 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, + 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x40, + 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, + 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, + 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, + 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, + 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, + 0x00, 0x5f, 0x00, 0x60, 0x00, 0x61, 0x01, 0x03, 0x00, 0xa3, 0x00, 0x84, + 0x00, 0x85, 0x00, 0xbd, 0x00, 0x96, 0x00, 0xe8, 0x00, 0x86, 0x00, 0x8e, + 0x00, 0x8b, 0x00, 0x9d, 0x00, 0xa9, 0x00, 0xa4, 0x01, 0x04, 0x00, 0x8a, + 0x00, 0xda, 0x00, 0x83, 0x00, 0x93, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0x8d, + 0x00, 0x97, 0x00, 0x88, 0x00, 0xc3, 0x00, 0xde, 0x00, 0xf1, 0x00, 0x9e, + 0x00, 0xaa, 0x00, 0xf5, 0x00, 0xf4, 0x00, 0xf6, 0x00, 0xa2, 0x00, 0xad, + 0x00, 0xc9, 0x00, 0xc7, 0x00, 0xae, 0x00, 0x62, 0x00, 0x63, 0x00, 0x90, + 0x00, 0x64, 0x00, 0xcb, 0x00, 0x65, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcf, + 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xe9, 0x00, 0x66, 0x00, 0xd3, + 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xaf, 0x00, 0x67, 0x00, 0xf0, 0x00, 0x91, + 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0x68, 0x00, 0xeb, 0x00, 0xed, + 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x6b, 0x00, 0x6d, 0x00, 0x6c, + 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x70, 0x00, 0x72, + 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0xea, + 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x7c, + 0x00, 0xb8, 0x00, 0xa1, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x81, + 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, + 0x30, 0x44, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, 0x41, 0x30, 0x07, 0x75, + 0x6e, 0x69, 0x30, 0x30, 0x41, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, + 0x00, 0x08, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x07, 0xff, 0xff, 0x00, 0x0f, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x00, 0x01, 0x01, + 0x00, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0xc0, 0x00, 0x01, 0x02, + 0x00, 0x15, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0xc0, 0x01, 0x01, 0x03, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x05, 0x00, 0x01, 0x01, 0x06, + 0x00, 0x02, 0x01, 0x07, 0x00, 0x00, 0x01, 0x08, 0x00, 0x02, 0x01, 0x09, + 0x00, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x01, 0x0b, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfd, 0x00, 0x0b, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, 0x00, 0x0a, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0xef, 0x00, 0x0a, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xf7, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x15, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xdf, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0xb0, + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x16, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x12, 0x00, 0x12, 0x00, 0x1e, 0x00, 0x17, 0x00, 0x14, 0x00, 0x20, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, + 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa0, 0x00, 0x00, 0x03, 0x00, 0x05, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa0, 0x00, 0x00, 0x06, 0x3f, 0xff, 0xff, 0xeb, 0x3f, 0xff, 0xff, 0xef, + 0xbf, 0xff, 0xff, 0xee, 0x3f, 0xff, 0xff, 0xec, 0x3f, 0xff, 0xff, 0xf2, + 0xbf, 0xff, 0xff, 0xf1, 0x3f, 0xff, 0xff, 0xef, 0x3f, 0xff, 0xff, 0xf5, + 0xbf, 0xff, 0xff, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x7e, 0x00, 0x80, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x14, 0x00, 0x18, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x75, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x16, 0xe7, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0xe1, 0xa9, 0xde, 0x41, 0x00, 0x00, 0x00, 0x00, + 0xe5, 0x4d, 0x1e, 0x76}; +unsigned int MwMonospaceTTFDataSize = 36184; +#endif diff --git a/widget/milsko/milskosrc/src/text/font/ttf.c b/widget/milsko/milskosrc/src/text/font/ttf.c new file mode 100644 index 0000000000..7eeea07b56 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/font/ttf.c @@ -0,0 +1,2945 @@ +#include + +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_GDI_TEXT) +unsigned char MwTTFData[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04, 0x00, 0x20, + 0x46, 0x46, 0x54, 0x4d, 0x94, 0x92, 0x79, 0xd4, 0x00, 0x00, 0x89, 0xa4, + 0x00, 0x00, 0x00, 0x1c, 0x4f, 0x53, 0x2f, 0x32, 0xa1, 0x35, 0x9f, 0x72, + 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70, + 0x09, 0xe8, 0xe7, 0x70, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x01, 0x4a, + 0x63, 0x76, 0x74, 0x20, 0x0f, 0x4d, 0x18, 0xa4, 0x00, 0x00, 0x0f, 0x1c, + 0x00, 0x00, 0x00, 0xa2, 0x66, 0x65, 0x61, 0x74, 0xc0, 0x1a, 0x05, 0x59, + 0x00, 0x00, 0x89, 0x74, 0x00, 0x00, 0x00, 0x30, 0x66, 0x70, 0x67, 0x6d, + 0x7e, 0x61, 0xb6, 0x11, 0x00, 0x00, 0x06, 0x5c, 0x00, 0x00, 0x07, 0xb4, + 0x67, 0x61, 0x73, 0x70, 0x00, 0x15, 0x00, 0x23, 0x00, 0x00, 0x88, 0xec, + 0x00, 0x00, 0x00, 0x10, 0x67, 0x6c, 0x79, 0x66, 0x65, 0x79, 0x59, 0xb7, + 0x00, 0x00, 0x11, 0x48, 0x00, 0x00, 0x52, 0x6c, 0x68, 0x65, 0x61, 0x64, + 0x15, 0x0d, 0x9f, 0xf2, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x00, 0x36, + 0x68, 0x68, 0x65, 0x61, 0x0f, 0x3c, 0x06, 0x13, 0x00, 0x00, 0x01, 0x64, + 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 0x53, 0x6d, 0x50, 0x6f, + 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x03, 0x08, 0x6b, 0x65, 0x72, 0x6e, + 0x4a, 0x11, 0x58, 0x96, 0x00, 0x00, 0x63, 0xb4, 0x00, 0x00, 0x1a, 0x76, + 0x6c, 0x6f, 0x63, 0x61, 0x41, 0xac, 0x2d, 0xdc, 0x00, 0x00, 0x0f, 0xc0, + 0x00, 0x00, 0x01, 0x86, 0x6d, 0x61, 0x78, 0x70, 0x02, 0x48, 0x01, 0x4a, + 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x20, 0x6d, 0x6f, 0x72, 0x78, + 0x00, 0x32, 0x00, 0xbb, 0x00, 0x00, 0x88, 0xfc, 0x00, 0x00, 0x00, 0x78, + 0x6e, 0x61, 0x6d, 0x65, 0x56, 0x44, 0xff, 0x7a, 0x00, 0x00, 0x7e, 0x2c, + 0x00, 0x00, 0x09, 0x08, 0x70, 0x6f, 0x73, 0x74, 0xb1, 0xe2, 0x4e, 0x7c, + 0x00, 0x00, 0x87, 0x34, 0x00, 0x00, 0x01, 0xb8, 0x70, 0x72, 0x65, 0x70, + 0x43, 0xb7, 0x96, 0xa4, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x01, 0x09, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x19, 0x9a, 0xf4, 0xa4, 0xd1, 0x4e, + 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x1f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc9, 0x35, 0x31, 0x8b, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xf9, 0x0a, 0x4d, + 0xff, 0x60, 0xfe, 0x10, 0x07, 0x4c, 0x07, 0x73, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x08, 0x8d, 0xfd, 0xa8, 0x00, 0x00, 0x08, 0x00, 0xff, 0x60, 0xff, 0xa8, + 0x07, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xc2, 0x00, 0x42, 0x00, 0x05, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x02, + 0x00, 0x10, 0x00, 0x2f, 0x00, 0x5c, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x99, + 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x04, 0x5f, 0x01, 0x90, 0x00, 0x05, + 0x00, 0x00, 0x05, 0x9a, 0x05, 0x33, 0x00, 0x00, 0x01, 0x1f, 0x05, 0x9a, + 0x05, 0x33, 0x00, 0x00, 0x03, 0xd1, 0x00, 0x66, 0x01, 0xf1, 0x08, 0x02, + 0x02, 0x0b, 0x06, 0x06, 0x03, 0x05, 0x04, 0x02, 0x02, 0x04, 0xe0, 0x00, + 0x02, 0xef, 0x40, 0x00, 0x20, 0x5b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x00, 0x31, 0x41, 0x53, 0x43, 0x00, 0x40, 0x00, 0x20, 0x00, 0xff, + 0x06, 0x1f, 0xfe, 0x14, 0x00, 0x84, 0x08, 0x8d, 0x02, 0x58, 0x20, 0x00, + 0x01, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x04, 0x48, 0x05, 0xb6, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x02, 0x23, 0x00, 0x98, + 0x03, 0x35, 0x00, 0x85, 0x05, 0x2b, 0x00, 0x33, 0x04, 0x93, 0x00, 0x83, + 0x06, 0x96, 0x00, 0x68, 0x05, 0xd7, 0x00, 0x71, 0x01, 0xc5, 0x00, 0x85, + 0x02, 0x5e, 0x00, 0x52, 0x02, 0x5e, 0x00, 0x3d, 0x04, 0x6a, 0x00, 0x56, + 0x04, 0x93, 0x00, 0x68, 0x01, 0xf6, 0x00, 0x3f, 0x02, 0x93, 0x00, 0x54, + 0x02, 0x21, 0x00, 0x98, 0x02, 0xf0, 0x00, 0x14, 0x04, 0x93, 0x00, 0x66, + 0x04, 0x93, 0x00, 0xbc, 0x04, 0x93, 0x00, 0x64, 0x04, 0x93, 0x00, 0x5e, + 0x04, 0x93, 0x00, 0x2b, 0x04, 0x93, 0x00, 0x85, 0x04, 0x93, 0x00, 0x75, + 0x04, 0x93, 0x00, 0x5e, 0x04, 0x93, 0x00, 0x68, 0x04, 0x93, 0x00, 0x6a, + 0x02, 0x21, 0x00, 0x98, 0x02, 0x21, 0x00, 0x3f, 0x04, 0x93, 0x00, 0x68, + 0x04, 0x93, 0x00, 0x77, 0x04, 0x93, 0x00, 0x68, 0x03, 0x6f, 0x00, 0x1b, + 0x07, 0x31, 0x00, 0x79, 0x05, 0x10, 0x00, 0x00, 0x05, 0x2f, 0x00, 0xc9, + 0x05, 0x0c, 0x00, 0x7d, 0x05, 0xd5, 0x00, 0xc9, 0x04, 0x73, 0x00, 0xc9, + 0x04, 0x21, 0x00, 0xc9, 0x05, 0xd3, 0x00, 0x7d, 0x05, 0xe7, 0x00, 0xc9, + 0x02, 0x3b, 0x00, 0xc9, 0x02, 0x23, 0xff, 0x60, 0x04, 0xe9, 0x00, 0xc9, + 0x04, 0x27, 0x00, 0xc9, 0x07, 0x39, 0x00, 0xc9, 0x06, 0x08, 0x00, 0xc9, + 0x06, 0x3b, 0x00, 0x7d, 0x04, 0xd1, 0x00, 0xc9, 0x06, 0x3b, 0x00, 0x7d, + 0x04, 0xf2, 0x00, 0xc9, 0x04, 0x64, 0x00, 0x6a, 0x04, 0x6d, 0x00, 0x12, + 0x05, 0xd3, 0x00, 0xba, 0x04, 0xc3, 0x00, 0x00, 0x07, 0x68, 0x00, 0x1b, + 0x04, 0x9e, 0x00, 0x08, 0x04, 0x7b, 0x00, 0x00, 0x04, 0x91, 0x00, 0x52, + 0x02, 0xa2, 0x00, 0xa6, 0x02, 0xf0, 0x00, 0x17, 0x02, 0xa2, 0x00, 0x33, + 0x04, 0x56, 0x00, 0x31, 0x03, 0x96, 0xff, 0xfc, 0x04, 0x9e, 0x01, 0x89, + 0x04, 0x73, 0x00, 0x5e, 0x04, 0xe7, 0x00, 0xb0, 0x03, 0xcf, 0x00, 0x73, + 0x04, 0xe7, 0x00, 0x73, 0x04, 0x7d, 0x00, 0x73, 0x02, 0xb6, 0x00, 0x1d, + 0x04, 0x62, 0x00, 0x27, 0x04, 0xe9, 0x00, 0xb0, 0x02, 0x06, 0x00, 0xa2, + 0x02, 0x06, 0xff, 0x91, 0x04, 0x33, 0x00, 0xb0, 0x02, 0x06, 0x00, 0xb0, + 0x07, 0x71, 0x00, 0xb0, 0x04, 0xe9, 0x00, 0xb0, 0x04, 0xd5, 0x00, 0x73, + 0x04, 0xe7, 0x00, 0xb0, 0x04, 0xe7, 0x00, 0x73, 0x03, 0x44, 0x00, 0xb0, + 0x03, 0xd1, 0x00, 0x6a, 0x02, 0xd3, 0x00, 0x1f, 0x04, 0xe9, 0x00, 0xa4, + 0x04, 0x02, 0x00, 0x00, 0x06, 0x39, 0x00, 0x17, 0x04, 0x31, 0x00, 0x27, + 0x04, 0x08, 0x00, 0x02, 0x03, 0xbe, 0x00, 0x52, 0x03, 0x08, 0x00, 0x3d, + 0x04, 0x68, 0x01, 0xee, 0x03, 0x08, 0x00, 0x48, 0x04, 0x93, 0x00, 0x68, + 0x02, 0x14, 0x00, 0x00, 0x02, 0x23, 0x00, 0x98, 0x04, 0x93, 0x00, 0xbe, + 0x04, 0x93, 0x00, 0x3f, 0x04, 0x93, 0x00, 0x7b, 0x04, 0x93, 0x00, 0x1f, + 0x04, 0x68, 0x01, 0xee, 0x04, 0x21, 0x00, 0x7b, 0x04, 0x9e, 0x01, 0x35, + 0x06, 0xa8, 0x00, 0x64, 0x02, 0xd5, 0x00, 0x46, 0x03, 0xfa, 0x00, 0x52, + 0x04, 0x93, 0x00, 0x68, 0x02, 0x93, 0x00, 0x54, 0x06, 0xa8, 0x00, 0x64, + 0x04, 0x00, 0xff, 0xfa, 0x03, 0x6d, 0x00, 0x7f, 0x04, 0x93, 0x00, 0x68, + 0x02, 0xc7, 0x00, 0x31, 0x02, 0xc7, 0x00, 0x21, 0x04, 0x9e, 0x01, 0x89, + 0x04, 0xf4, 0x00, 0xb0, 0x05, 0x3d, 0x00, 0x71, 0x02, 0x21, 0x00, 0x98, + 0x01, 0xd1, 0x00, 0x25, 0x02, 0xc7, 0x00, 0x4c, 0x03, 0x00, 0x00, 0x42, + 0x03, 0xfa, 0x00, 0x50, 0x06, 0x3d, 0x00, 0x4b, 0x06, 0x3d, 0x00, 0x2e, + 0x06, 0x3d, 0x00, 0x1a, 0x03, 0x6f, 0x00, 0x33, 0x05, 0x10, 0x00, 0x00, + 0x05, 0x10, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, + 0x05, 0x10, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x06, 0xfc, 0xff, 0xfe, + 0x05, 0x0c, 0x00, 0x7d, 0x04, 0x73, 0x00, 0xc9, 0x04, 0x73, 0x00, 0xc9, + 0x04, 0x73, 0x00, 0xc9, 0x04, 0x73, 0x00, 0xc9, 0x02, 0x3b, 0x00, 0x05, + 0x02, 0x3b, 0x00, 0xb3, 0x02, 0x3b, 0xff, 0xc7, 0x02, 0x3b, 0x00, 0x05, + 0x05, 0xc7, 0x00, 0x2f, 0x06, 0x08, 0x00, 0xc9, 0x06, 0x3b, 0x00, 0x7d, + 0x06, 0x3b, 0x00, 0x7d, 0x06, 0x3b, 0x00, 0x7d, 0x06, 0x3b, 0x00, 0x7d, + 0x06, 0x3b, 0x00, 0x7d, 0x04, 0x93, 0x00, 0x85, 0x06, 0x3b, 0x00, 0x7d, + 0x05, 0xd3, 0x00, 0xba, 0x05, 0xd3, 0x00, 0xba, 0x05, 0xd3, 0x00, 0xba, + 0x05, 0xd3, 0x00, 0xba, 0x04, 0x7b, 0x00, 0x00, 0x04, 0xe3, 0x00, 0xc9, + 0x04, 0xfa, 0x00, 0xb0, 0x04, 0x73, 0x00, 0x5e, 0x04, 0x73, 0x00, 0x5e, + 0x04, 0x73, 0x00, 0x5e, 0x04, 0x73, 0x00, 0x5e, 0x04, 0x73, 0x00, 0x5e, + 0x04, 0x73, 0x00, 0x5e, 0x06, 0xdd, 0x00, 0x5e, 0x03, 0xcf, 0x00, 0x73, + 0x04, 0x7d, 0x00, 0x73, 0x04, 0x7d, 0x00, 0x73, 0x04, 0x7d, 0x00, 0x73, + 0x04, 0x7d, 0x00, 0x73, 0x02, 0x06, 0xff, 0xda, 0x02, 0x06, 0x00, 0xa9, + 0x02, 0x06, 0xff, 0xb3, 0x02, 0x06, 0xff, 0xec, 0x04, 0xc5, 0x00, 0x71, + 0x04, 0xe9, 0x00, 0xb0, 0x04, 0xd5, 0x00, 0x73, 0x04, 0xd5, 0x00, 0x73, + 0x04, 0xd5, 0x00, 0x73, 0x04, 0xd5, 0x00, 0x73, 0x04, 0xd5, 0x00, 0x73, + 0x04, 0x93, 0x00, 0x68, 0x04, 0xd5, 0x00, 0x73, 0x04, 0xe9, 0x00, 0xa4, + 0x04, 0xe9, 0x00, 0xa4, 0x04, 0xe9, 0x00, 0xa4, 0x04, 0xe9, 0x00, 0xa4, + 0x04, 0x08, 0x00, 0x02, 0x04, 0xe7, 0x00, 0xb0, 0x04, 0x08, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x7e, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x20, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xc2, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x00, 0x86, 0x87, + 0x89, 0x8b, 0x93, 0x98, 0x9e, 0xa3, 0xa2, 0xa4, 0xa6, 0xa5, 0xa7, 0xa9, + 0xab, 0xaa, 0xac, 0xad, 0xaf, 0xae, 0xb0, 0xb1, 0xb3, 0xb5, 0xb4, 0xb6, + 0xb8, 0xb7, 0xbc, 0xbb, 0xbd, 0xbe, 0x00, 0x72, 0x64, 0x65, 0x69, 0x00, + 0x78, 0xa1, 0x70, 0x6b, 0x00, 0x76, 0x6a, 0x00, 0x88, 0x9a, 0x00, 0x73, + 0x00, 0x00, 0x67, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x00, + 0xa8, 0xba, 0x81, 0x63, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x7d, 0x00, + 0x62, 0x82, 0x85, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb9, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, + 0x00, 0x00, 0x00, 0x84, 0x8c, 0x83, 0x8d, 0x8a, 0x8f, 0x90, 0x91, 0x8e, + 0x95, 0x96, 0x00, 0x94, 0x9c, 0x9d, 0x9b, 0x00, 0x00, 0x00, 0x71, 0x00, + 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x47, 0x5b, 0x5a, + 0x59, 0x58, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4c, + 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, + 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x31, + 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, + 0x21, 0x1f, 0x18, 0x14, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a, 0x09, + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x2c, 0x20, 0xb0, + 0x01, 0x60, 0x45, 0xb0, 0x03, 0x25, 0x20, 0x11, 0x46, 0x61, 0x23, 0x45, + 0x23, 0x61, 0x48, 0x2d, 0x2c, 0x20, 0x45, 0x18, 0x68, 0x44, 0x2d, 0x2c, + 0x45, 0x23, 0x46, 0x60, 0xb0, 0x20, 0x61, 0x20, 0xb0, 0x46, 0x60, 0xb0, + 0x04, 0x26, 0x23, 0x48, 0x48, 0x2d, 0x2c, 0x45, 0x23, 0x46, 0x23, 0x61, + 0xb0, 0x20, 0x60, 0x20, 0xb0, 0x26, 0x61, 0xb0, 0x20, 0x61, 0xb0, 0x04, + 0x26, 0x23, 0x48, 0x48, 0x2d, 0x2c, 0x45, 0x23, 0x46, 0x60, 0xb0, 0x40, + 0x61, 0x20, 0xb0, 0x66, 0x60, 0xb0, 0x04, 0x26, 0x23, 0x48, 0x48, 0x2d, + 0x2c, 0x45, 0x23, 0x46, 0x23, 0x61, 0xb0, 0x40, 0x60, 0x20, 0xb0, 0x26, + 0x61, 0xb0, 0x40, 0x61, 0xb0, 0x04, 0x26, 0x23, 0x48, 0x48, 0x2d, 0x2c, + 0x01, 0x10, 0x20, 0x3c, 0x00, 0x3c, 0x2d, 0x2c, 0x20, 0x45, 0x23, 0x20, + 0xb0, 0xcd, 0x44, 0x23, 0x20, 0xb8, 0x01, 0x5a, 0x51, 0x58, 0x23, 0x20, + 0xb0, 0x8d, 0x44, 0x23, 0x59, 0x20, 0xb0, 0xed, 0x51, 0x58, 0x23, 0x20, + 0xb0, 0x4d, 0x44, 0x23, 0x59, 0x20, 0xb0, 0x04, 0x26, 0x51, 0x58, 0x23, + 0x20, 0xb0, 0x0d, 0x44, 0x23, 0x59, 0x21, 0x21, 0x2d, 0x2c, 0x20, 0x20, + 0x45, 0x18, 0x68, 0x44, 0x20, 0xb0, 0x01, 0x60, 0x20, 0x45, 0xb0, 0x46, + 0x76, 0x68, 0x8a, 0x45, 0x60, 0x44, 0x2d, 0x2c, 0x01, 0xb1, 0x0b, 0x0a, + 0x43, 0x23, 0x43, 0x65, 0x0a, 0x2d, 0x2c, 0x00, 0xb1, 0x0a, 0x0b, 0x43, + 0x23, 0x43, 0x0b, 0x2d, 0x2c, 0x00, 0xb0, 0x28, 0x23, 0x70, 0xb1, 0x01, + 0x28, 0x3e, 0x01, 0xb0, 0x28, 0x23, 0x70, 0xb1, 0x02, 0x28, 0x45, 0x3a, + 0xb1, 0x02, 0x00, 0x08, 0x0d, 0x2d, 0x2c, 0x20, 0x45, 0xb0, 0x03, 0x25, + 0x45, 0x61, 0x64, 0xb0, 0x50, 0x51, 0x58, 0x45, 0x44, 0x1b, 0x21, 0x21, + 0x59, 0x2d, 0x2c, 0x49, 0xb0, 0x0e, 0x23, 0x44, 0x2d, 0x2c, 0x20, 0x45, + 0xb0, 0x00, 0x43, 0x60, 0x44, 0x2d, 0x2c, 0x01, 0xb0, 0x06, 0x43, 0xb0, + 0x07, 0x43, 0x65, 0x0a, 0x2d, 0x2c, 0x20, 0x69, 0xb0, 0x40, 0x61, 0xb0, + 0x00, 0x8b, 0x20, 0xb1, 0x2c, 0xc0, 0x8a, 0x8c, 0xb8, 0x10, 0x00, 0x62, + 0x60, 0x2b, 0x0c, 0x64, 0x23, 0x64, 0x61, 0x5c, 0x58, 0xb0, 0x03, 0x61, + 0x59, 0x2d, 0x2c, 0x8a, 0x03, 0x45, 0x8a, 0x8a, 0x87, 0xb0, 0x11, 0x2b, + 0xb0, 0x29, 0x23, 0x44, 0xb0, 0x29, 0x7a, 0xe4, 0x18, 0x2d, 0x2c, 0x45, + 0x65, 0xb0, 0x2c, 0x23, 0x44, 0x45, 0xb0, 0x2b, 0x23, 0x44, 0x2d, 0x2c, + 0x4b, 0x52, 0x58, 0x45, 0x44, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x4b, + 0x51, 0x58, 0x45, 0x44, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x01, 0xb0, + 0x05, 0x25, 0x10, 0x23, 0x20, 0x8a, 0xf5, 0x00, 0xb0, 0x01, 0x60, 0x23, + 0xed, 0xec, 0x2d, 0x2c, 0x01, 0xb0, 0x05, 0x25, 0x10, 0x23, 0x20, 0x8a, + 0xf5, 0x00, 0xb0, 0x01, 0x61, 0x23, 0xed, 0xec, 0x2d, 0x2c, 0x01, 0xb0, + 0x06, 0x25, 0x10, 0xf5, 0x00, 0xed, 0xec, 0x2d, 0x2c, 0xb0, 0x02, 0x43, + 0xb0, 0x01, 0x52, 0x58, 0x21, 0x21, 0x21, 0x21, 0x21, 0x1b, 0x46, 0x23, + 0x46, 0x60, 0x8a, 0x8a, 0x46, 0x23, 0x20, 0x46, 0x8a, 0x60, 0x8a, 0x61, + 0xb8, 0xff, 0x80, 0x62, 0x23, 0x20, 0x10, 0x23, 0x8a, 0xb1, 0x0c, 0x0c, + 0x8a, 0x70, 0x45, 0x60, 0x20, 0xb0, 0x00, 0x50, 0x58, 0xb0, 0x01, 0x61, + 0xb8, 0xff, 0xba, 0x8b, 0x1b, 0xb0, 0x46, 0x8c, 0x59, 0xb0, 0x10, 0x60, + 0x68, 0x01, 0x3a, 0x59, 0x2d, 0x2c, 0x20, 0x45, 0xb0, 0x03, 0x25, 0x46, + 0x52, 0x4b, 0xb0, 0x13, 0x51, 0x5b, 0x58, 0xb0, 0x02, 0x25, 0x46, 0x20, + 0x68, 0x61, 0xb0, 0x03, 0x25, 0xb0, 0x03, 0x25, 0x3f, 0x23, 0x21, 0x38, + 0x1b, 0x21, 0x11, 0x59, 0x2d, 0x2c, 0x20, 0x45, 0xb0, 0x03, 0x25, 0x46, + 0x50, 0x58, 0xb0, 0x02, 0x25, 0x46, 0x20, 0x68, 0x61, 0xb0, 0x03, 0x25, + 0xb0, 0x03, 0x25, 0x3f, 0x23, 0x21, 0x38, 0x1b, 0x21, 0x11, 0x59, 0x2d, + 0x2c, 0x00, 0xb0, 0x07, 0x43, 0xb0, 0x06, 0x43, 0x0b, 0x2d, 0x2c, 0x21, + 0x21, 0x0c, 0x64, 0x23, 0x64, 0x8b, 0xb8, 0x40, 0x00, 0x62, 0x2d, 0x2c, + 0x21, 0xb0, 0x80, 0x51, 0x58, 0x0c, 0x64, 0x23, 0x64, 0x8b, 0xb8, 0x20, + 0x00, 0x62, 0x1b, 0xb2, 0x00, 0x40, 0x2f, 0x2b, 0x59, 0xb0, 0x02, 0x60, + 0x2d, 0x2c, 0x21, 0xb0, 0xc0, 0x51, 0x58, 0x0c, 0x64, 0x23, 0x64, 0x8b, + 0xb8, 0x15, 0x55, 0x62, 0x1b, 0xb2, 0x00, 0x80, 0x2f, 0x2b, 0x59, 0xb0, + 0x02, 0x60, 0x2d, 0x2c, 0x0c, 0x64, 0x23, 0x64, 0x8b, 0xb8, 0x40, 0x00, + 0x62, 0x60, 0x23, 0x21, 0x2d, 0x2c, 0x4b, 0x53, 0x58, 0x8a, 0xb0, 0x04, + 0x25, 0x49, 0x64, 0x23, 0x45, 0x69, 0xb0, 0x40, 0x8b, 0x61, 0xb0, 0x80, + 0x62, 0xb0, 0x20, 0x61, 0x6a, 0xb0, 0x0e, 0x23, 0x44, 0x23, 0x10, 0xb0, + 0x0e, 0xf6, 0x1b, 0x21, 0x23, 0x8a, 0x12, 0x11, 0x20, 0x39, 0x2f, 0x59, + 0x2d, 0x2c, 0x4b, 0x53, 0x58, 0x20, 0xb0, 0x03, 0x25, 0x49, 0x64, 0x69, + 0x20, 0xb0, 0x05, 0x26, 0xb0, 0x06, 0x25, 0x49, 0x64, 0x23, 0x61, 0xb0, + 0x80, 0x62, 0xb0, 0x20, 0x61, 0x6a, 0xb0, 0x0e, 0x23, 0x44, 0xb0, 0x04, + 0x26, 0x10, 0xb0, 0x0e, 0xf6, 0x8a, 0x10, 0xb0, 0x0e, 0x23, 0x44, 0xb0, + 0x0e, 0xf6, 0xb0, 0x0e, 0x23, 0x44, 0xb0, 0x0e, 0xed, 0x1b, 0x8a, 0xb0, + 0x04, 0x26, 0x11, 0x12, 0x20, 0x39, 0x23, 0x20, 0x39, 0x2f, 0x2f, 0x59, + 0x2d, 0x2c, 0x45, 0x23, 0x45, 0x60, 0x23, 0x45, 0x60, 0x23, 0x45, 0x60, + 0x23, 0x76, 0x68, 0x18, 0xb0, 0x80, 0x62, 0x20, 0x2d, 0x2c, 0xb0, 0x48, + 0x2b, 0x2d, 0x2c, 0x20, 0x45, 0xb0, 0x00, 0x54, 0x58, 0xb0, 0x40, 0x44, + 0x20, 0x45, 0xb0, 0x40, 0x61, 0x44, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, + 0x45, 0xb1, 0x30, 0x2f, 0x45, 0x23, 0x45, 0x61, 0x60, 0xb0, 0x01, 0x60, + 0x69, 0x44, 0x2d, 0x2c, 0x4b, 0x51, 0x58, 0xb0, 0x2f, 0x23, 0x70, 0xb0, + 0x14, 0x23, 0x42, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x4b, 0x51, 0x58, + 0x20, 0xb0, 0x03, 0x25, 0x45, 0x69, 0x53, 0x58, 0x44, 0x1b, 0x21, 0x21, + 0x59, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x45, 0xb0, 0x14, 0x43, 0xb0, + 0x00, 0x60, 0x63, 0xb0, 0x01, 0x60, 0x69, 0x44, 0x2d, 0x2c, 0xb0, 0x2f, + 0x45, 0x44, 0x2d, 0x2c, 0x45, 0x23, 0x20, 0x45, 0x8a, 0x60, 0x44, 0x2d, + 0x2c, 0x45, 0x23, 0x45, 0x60, 0x44, 0x2d, 0x2c, 0x4b, 0x23, 0x51, 0x58, + 0xb9, 0x00, 0x33, 0xff, 0xe0, 0xb1, 0x34, 0x20, 0x1b, 0xb3, 0x33, 0x00, + 0x34, 0x00, 0x59, 0x44, 0x44, 0x2d, 0x2c, 0xb0, 0x16, 0x43, 0x58, 0xb0, + 0x03, 0x26, 0x45, 0x8a, 0x58, 0x64, 0x66, 0xb0, 0x1f, 0x60, 0x1b, 0x64, + 0xb0, 0x20, 0x60, 0x66, 0x20, 0x58, 0x1b, 0x21, 0xb0, 0x40, 0x59, 0xb0, + 0x01, 0x61, 0x59, 0x23, 0x58, 0x65, 0x59, 0xb0, 0x29, 0x23, 0x44, 0x23, + 0x10, 0xb0, 0x29, 0xe0, 0x1b, 0x21, 0x21, 0x21, 0x21, 0x21, 0x59, 0x2d, + 0x2c, 0xb0, 0x02, 0x43, 0x54, 0x58, 0x4b, 0x53, 0x23, 0x4b, 0x51, 0x5a, + 0x58, 0x38, 0x1b, 0x21, 0x21, 0x59, 0x1b, 0x21, 0x21, 0x21, 0x21, 0x59, + 0x2d, 0x2c, 0xb0, 0x16, 0x43, 0x58, 0xb0, 0x04, 0x25, 0x45, 0x64, 0xb0, + 0x20, 0x60, 0x66, 0x20, 0x58, 0x1b, 0x21, 0xb0, 0x40, 0x59, 0xb0, 0x01, + 0x61, 0x23, 0x58, 0x1b, 0x65, 0x59, 0xb0, 0x29, 0x23, 0x44, 0xb0, 0x05, + 0x25, 0xb0, 0x08, 0x25, 0x08, 0x20, 0x58, 0x02, 0x1b, 0x03, 0x59, 0xb0, + 0x04, 0x25, 0x10, 0xb0, 0x05, 0x25, 0x20, 0x46, 0xb0, 0x04, 0x25, 0x23, + 0x42, 0x3c, 0xb0, 0x04, 0x25, 0xb0, 0x07, 0x25, 0x08, 0xb0, 0x07, 0x25, + 0x10, 0xb0, 0x06, 0x25, 0x20, 0x46, 0xb0, 0x04, 0x25, 0xb0, 0x01, 0x60, + 0x23, 0x42, 0x3c, 0x20, 0x58, 0x01, 0x1b, 0x00, 0x59, 0xb0, 0x04, 0x25, + 0x10, 0xb0, 0x05, 0x25, 0xb0, 0x29, 0xe0, 0xb0, 0x29, 0x20, 0x45, 0x65, + 0x44, 0xb0, 0x07, 0x25, 0x10, 0xb0, 0x06, 0x25, 0xb0, 0x29, 0xe0, 0xb0, + 0x05, 0x25, 0xb0, 0x08, 0x25, 0x08, 0x20, 0x58, 0x02, 0x1b, 0x03, 0x59, + 0xb0, 0x05, 0x25, 0xb0, 0x03, 0x25, 0x43, 0x48, 0xb0, 0x04, 0x25, 0xb0, + 0x07, 0x25, 0x08, 0xb0, 0x06, 0x25, 0xb0, 0x03, 0x25, 0xb0, 0x01, 0x60, + 0x43, 0x48, 0x1b, 0x21, 0x59, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x2d, 0x2c, 0x02, 0xb0, 0x04, 0x25, 0x20, 0x20, 0x46, 0xb0, 0x04, 0x25, + 0x23, 0x42, 0xb0, 0x05, 0x25, 0x08, 0xb0, 0x03, 0x25, 0x45, 0x48, 0x21, + 0x21, 0x21, 0x21, 0x2d, 0x2c, 0x02, 0xb0, 0x03, 0x25, 0x20, 0xb0, 0x04, + 0x25, 0x08, 0xb0, 0x02, 0x25, 0x43, 0x48, 0x21, 0x21, 0x21, 0x2d, 0x2c, + 0x45, 0x23, 0x20, 0x45, 0x18, 0x20, 0xb0, 0x00, 0x50, 0x20, 0x58, 0x23, + 0x65, 0x23, 0x59, 0x23, 0x68, 0x20, 0xb0, 0x40, 0x50, 0x58, 0x21, 0xb0, + 0x40, 0x59, 0x23, 0x58, 0x65, 0x59, 0x8a, 0x60, 0x44, 0x2d, 0x2c, 0x4b, + 0x53, 0x23, 0x4b, 0x51, 0x5a, 0x58, 0x20, 0x45, 0x8a, 0x60, 0x44, 0x1b, + 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x4b, 0x54, 0x58, 0x20, 0x45, 0x8a, 0x60, + 0x44, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x4b, 0x53, 0x23, 0x4b, 0x51, + 0x5a, 0x58, 0x38, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x00, 0x21, + 0x4b, 0x54, 0x58, 0x38, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x02, + 0x43, 0x54, 0x58, 0xb0, 0x46, 0x2b, 0x1b, 0x21, 0x21, 0x21, 0x21, 0x59, + 0x2d, 0x2c, 0xb0, 0x02, 0x43, 0x54, 0x58, 0xb0, 0x47, 0x2b, 0x1b, 0x21, + 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x02, 0x43, 0x54, 0x58, 0xb0, 0x48, + 0x2b, 0x1b, 0x21, 0x21, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0xb0, 0x02, 0x43, + 0x54, 0x58, 0xb0, 0x49, 0x2b, 0x1b, 0x21, 0x21, 0x21, 0x59, 0x2d, 0x2c, + 0x20, 0x8a, 0x08, 0x23, 0x4b, 0x53, 0x8a, 0x4b, 0x51, 0x5a, 0x58, 0x23, + 0x38, 0x1b, 0x21, 0x21, 0x59, 0x2d, 0x2c, 0x00, 0xb0, 0x02, 0x25, 0x49, + 0xb0, 0x00, 0x53, 0x58, 0x20, 0xb0, 0x40, 0x38, 0x11, 0x1b, 0x21, 0x59, + 0x2d, 0x2c, 0x01, 0x46, 0x23, 0x46, 0x60, 0x23, 0x46, 0x61, 0x23, 0x20, + 0x10, 0x20, 0x46, 0x8a, 0x61, 0xb8, 0xff, 0x80, 0x62, 0x8a, 0xb1, 0x40, + 0x40, 0x8a, 0x70, 0x45, 0x60, 0x68, 0x3a, 0x2d, 0x2c, 0x20, 0x8a, 0x23, + 0x49, 0x64, 0x8a, 0x23, 0x53, 0x58, 0x3c, 0x1b, 0x21, 0x59, 0x2d, 0x2c, + 0x4b, 0x52, 0x58, 0x7d, 0x1b, 0x7a, 0x59, 0x2d, 0x2c, 0xb0, 0x12, 0x00, + 0x4b, 0x01, 0x4b, 0x54, 0x42, 0x2d, 0x2c, 0xb1, 0x02, 0x00, 0x42, 0xb1, + 0x23, 0x01, 0x88, 0x51, 0xb1, 0x40, 0x01, 0x88, 0x53, 0x5a, 0x58, 0xb9, + 0x10, 0x00, 0x00, 0x20, 0x88, 0x54, 0x58, 0xb2, 0x02, 0x01, 0x02, 0x43, + 0x60, 0x42, 0x59, 0xb1, 0x24, 0x01, 0x88, 0x51, 0x58, 0xb9, 0x20, 0x00, + 0x00, 0x40, 0x88, 0x54, 0x58, 0xb2, 0x02, 0x02, 0x02, 0x43, 0x60, 0x42, + 0xb1, 0x24, 0x01, 0x88, 0x54, 0x58, 0xb2, 0x02, 0x20, 0x02, 0x43, 0x60, + 0x42, 0x00, 0x4b, 0x01, 0x4b, 0x52, 0x58, 0xb2, 0x02, 0x08, 0x02, 0x43, + 0x60, 0x42, 0x59, 0x1b, 0xb9, 0x40, 0x00, 0x00, 0x80, 0x88, 0x54, 0x58, + 0xb2, 0x02, 0x04, 0x02, 0x43, 0x60, 0x42, 0x59, 0xb9, 0x40, 0x00, 0x00, + 0x80, 0x63, 0xb8, 0x01, 0x00, 0x88, 0x54, 0x58, 0xb2, 0x02, 0x08, 0x02, + 0x43, 0x60, 0x42, 0x59, 0xb9, 0x40, 0x00, 0x01, 0x00, 0x63, 0xb8, 0x02, + 0x00, 0x88, 0x54, 0x58, 0xb2, 0x02, 0x10, 0x02, 0x43, 0x60, 0x42, 0x59, + 0xb1, 0x26, 0x01, 0x88, 0x51, 0x58, 0xb9, 0x40, 0x00, 0x02, 0x00, 0x63, + 0xb8, 0x04, 0x00, 0x88, 0x54, 0x58, 0xb2, 0x02, 0x40, 0x02, 0x43, 0x60, + 0x42, 0x59, 0xb9, 0x40, 0x00, 0x04, 0x00, 0x63, 0xb8, 0x08, 0x00, 0x88, + 0x54, 0x58, 0xb2, 0x02, 0x80, 0x02, 0x43, 0x60, 0x42, 0x59, 0x59, 0x59, + 0x59, 0x59, 0x59, 0xb1, 0x00, 0x02, 0x43, 0x54, 0x58, 0x40, 0x0a, 0x05, + 0x40, 0x08, 0x40, 0x09, 0x40, 0x0c, 0x02, 0x0d, 0x02, 0x1b, 0xb1, 0x01, + 0x02, 0x43, 0x54, 0x58, 0xb2, 0x05, 0x40, 0x08, 0xba, 0x01, 0x00, 0x00, + 0x09, 0x01, 0x00, 0xb3, 0x0c, 0x01, 0x0d, 0x01, 0x1b, 0xb1, 0x80, 0x02, + 0x43, 0x52, 0x58, 0xb2, 0x05, 0x40, 0x08, 0xb8, 0x01, 0x80, 0xb1, 0x09, + 0x40, 0x1b, 0xb2, 0x05, 0x40, 0x08, 0xba, 0x01, 0x80, 0x00, 0x09, 0x01, + 0x40, 0x59, 0xb9, 0x40, 0x00, 0x00, 0x80, 0x88, 0x55, 0xb9, 0x40, 0x00, + 0x02, 0x00, 0x63, 0xb8, 0x04, 0x00, 0x88, 0x55, 0x5a, 0x58, 0xb3, 0x0c, + 0x00, 0x0d, 0x01, 0x1b, 0xb3, 0x0c, 0x00, 0x0d, 0x01, 0x59, 0x59, 0x59, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x2d, 0x2c, 0x45, 0x18, 0x68, 0x23, 0x4b, + 0x51, 0x58, 0x23, 0x20, 0x45, 0x20, 0x64, 0xb0, 0x40, 0x50, 0x58, 0x7c, + 0x59, 0x68, 0x8a, 0x60, 0x59, 0x44, 0x2d, 0x2c, 0xb0, 0x00, 0x16, 0xb0, + 0x02, 0x25, 0xb0, 0x02, 0x25, 0x01, 0xb0, 0x01, 0x23, 0x3e, 0x00, 0xb0, + 0x02, 0x23, 0x3e, 0xb1, 0x01, 0x02, 0x06, 0x0c, 0xb0, 0x0a, 0x23, 0x65, + 0x42, 0xb0, 0x0b, 0x23, 0x42, 0x01, 0xb0, 0x01, 0x23, 0x3f, 0x00, 0xb0, + 0x02, 0x23, 0x3f, 0xb1, 0x01, 0x02, 0x06, 0x0c, 0xb0, 0x06, 0x23, 0x65, + 0x42, 0xb0, 0x07, 0x23, 0x42, 0xb0, 0x01, 0x16, 0x01, 0x2d, 0x2c, 0xb0, + 0x80, 0xb0, 0x02, 0x43, 0x50, 0xb0, 0x01, 0xb0, 0x02, 0x43, 0x54, 0x5b, + 0x58, 0x21, 0x23, 0x10, 0xb0, 0x20, 0x1a, 0xc9, 0x1b, 0x8a, 0x10, 0xed, + 0x59, 0x2d, 0x2c, 0xb0, 0x59, 0x2b, 0x2d, 0x2c, 0x8a, 0x10, 0xe5, 0x2d, + 0x40, 0x99, 0x09, 0x21, 0x48, 0x20, 0x55, 0x20, 0x01, 0x1e, 0x55, 0x1f, + 0x48, 0x03, 0x55, 0x1f, 0x1e, 0x01, 0x0f, 0x1e, 0x3f, 0x1e, 0xaf, 0x1e, + 0x03, 0x4d, 0x4b, 0x26, 0x1f, 0x4c, 0x4b, 0x33, 0x1f, 0x4b, 0x46, 0x25, + 0x1f, 0x26, 0x34, 0x10, 0x55, 0x25, 0x33, 0x24, 0x55, 0x19, 0x13, 0xff, + 0x1f, 0x07, 0x04, 0xff, 0x1f, 0x06, 0x03, 0xff, 0x1f, 0x4a, 0x49, 0x33, + 0x1f, 0x49, 0x46, 0x25, 0x1f, 0x13, 0x33, 0x12, 0x55, 0x05, 0x01, 0x03, + 0x55, 0x04, 0x33, 0x03, 0x55, 0x1f, 0x03, 0x01, 0x0f, 0x03, 0x3f, 0x03, + 0xaf, 0x03, 0x03, 0x47, 0x46, 0x19, 0x1f, 0xeb, 0x46, 0x01, 0x23, 0x33, + 0x22, 0x55, 0x1c, 0x33, 0x1b, 0x55, 0x16, 0x33, 0x15, 0x55, 0x11, 0x01, + 0x0f, 0x55, 0x10, 0x33, 0x0f, 0x55, 0x0f, 0x0f, 0x4f, 0x0f, 0x02, 0x1f, + 0x0f, 0xcf, 0x0f, 0x02, 0x0f, 0x0f, 0xff, 0x0f, 0x02, 0x06, 0x02, 0x01, + 0x00, 0x55, 0x01, 0x33, 0x00, 0x55, 0x6f, 0x00, 0x7f, 0x00, 0xaf, 0x00, + 0xef, 0x00, 0x04, 0x10, 0x00, 0x01, 0x80, 0x16, 0x01, 0x05, 0x01, 0xb8, + 0x01, 0x90, 0xb1, 0x54, 0x53, 0x2b, 0x2b, 0x4b, 0xb8, 0x07, 0xff, 0x52, + 0x4b, 0xb0, 0x09, 0x50, 0x5b, 0xb0, 0x01, 0x88, 0xb0, 0x25, 0x53, 0xb0, + 0x01, 0x88, 0xb0, 0x40, 0x51, 0x5a, 0xb0, 0x06, 0x88, 0xb0, 0x00, 0x55, + 0x5a, 0x5b, 0x58, 0xb1, 0x01, 0x01, 0x8e, 0x59, 0x85, 0x8d, 0x8d, 0x00, + 0x42, 0x1d, 0x4b, 0xb0, 0x32, 0x53, 0x58, 0xb0, 0x20, 0x1d, 0x59, 0x4b, + 0xb0, 0x64, 0x53, 0x58, 0xb0, 0x10, 0x1d, 0xb1, 0x16, 0x00, 0x42, 0x59, + 0x73, 0x73, 0x2b, 0x2b, 0x5e, 0x73, 0x74, 0x75, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x74, 0x2b, 0x73, 0x74, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x73, 0x74, 0x2b, 0x2b, 0x2b, 0x18, + 0x5e, 0x00, 0x00, 0x00, 0x06, 0x14, 0x00, 0x17, 0x00, 0x4e, 0x05, 0xb6, + 0x00, 0x17, 0x00, 0x75, 0x05, 0xb6, 0x05, 0xcd, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x48, + 0x00, 0x14, 0x00, 0x91, 0x00, 0x00, 0xff, 0xec, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xec, 0x00, 0x00, 0x00, 0x00, 0xff, 0xec, 0x00, 0x00, 0xfe, 0x14, + 0xff, 0xec, 0x00, 0x00, 0x05, 0xb6, 0x00, 0x13, 0xfc, 0x94, 0xff, 0xed, + 0xfe, 0x85, 0xff, 0xea, 0xfe, 0xa9, 0xff, 0xec, 0x00, 0x18, 0xfe, 0xbc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x8b, 0x00, 0x81, 0x00, 0xdd, 0x00, 0x98, 0x00, 0x8f, 0x00, 0x8e, + 0x00, 0x99, 0x00, 0x88, 0x00, 0x81, 0x01, 0x0f, 0x00, 0x8a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, + 0x00, 0x58, 0x00, 0xe0, 0x01, 0x5c, 0x01, 0xce, 0x02, 0x4c, 0x02, 0x66, + 0x02, 0x92, 0x02, 0xbe, 0x02, 0xfa, 0x03, 0x26, 0x03, 0x44, 0x03, 0x5a, + 0x03, 0x7c, 0x03, 0x96, 0x03, 0xd8, 0x04, 0x02, 0x04, 0x44, 0x04, 0xa2, + 0x04, 0xe4, 0x05, 0x30, 0x05, 0x8e, 0x05, 0xb0, 0x06, 0x20, 0x06, 0x7e, + 0x06, 0xb4, 0x06, 0xe8, 0x07, 0x08, 0x07, 0x32, 0x07, 0x52, 0x07, 0xaa, + 0x08, 0x32, 0x08, 0x72, 0x08, 0xce, 0x09, 0x0c, 0x09, 0x48, 0x09, 0x7e, + 0x09, 0xac, 0x09, 0xfc, 0x0a, 0x2e, 0x0a, 0x44, 0x0a, 0x6c, 0x0a, 0x9c, + 0x0a, 0xba, 0x0a, 0xf8, 0x0b, 0x30, 0x0b, 0x76, 0x0b, 0xb4, 0x0c, 0x08, + 0x0c, 0x56, 0x0c, 0xaa, 0x0c, 0xce, 0x0d, 0x02, 0x0d, 0x2a, 0x0d, 0x6e, + 0x0d, 0x9e, 0x0d, 0xc6, 0x0d, 0xf2, 0x0e, 0x16, 0x0e, 0x30, 0x0e, 0x54, + 0x0e, 0x76, 0x0e, 0x8c, 0x0e, 0xac, 0x0f, 0x08, 0x0f, 0x5e, 0x0f, 0x9a, + 0x0f, 0xee, 0x10, 0x3c, 0x10, 0x7c, 0x11, 0x10, 0x11, 0x4e, 0x11, 0x7c, + 0x11, 0xba, 0x11, 0xf8, 0x12, 0x10, 0x12, 0x68, 0x12, 0xa2, 0x12, 0xe4, + 0x13, 0x3a, 0x13, 0x8e, 0x13, 0xc2, 0x14, 0x14, 0x14, 0x54, 0x14, 0x92, + 0x14, 0xba, 0x15, 0x06, 0x15, 0x36, 0x15, 0x70, 0x15, 0x9c, 0x15, 0xde, + 0x15, 0xf6, 0x16, 0x3c, 0x16, 0x76, 0x16, 0x76, 0x16, 0xa8, 0x16, 0xf4, + 0x17, 0x46, 0x17, 0x94, 0x17, 0xe8, 0x18, 0x0e, 0x18, 0x8a, 0x18, 0xc0, + 0x19, 0x3c, 0x19, 0x8a, 0x19, 0xc6, 0x19, 0xe4, 0x19, 0xec, 0x1a, 0x76, + 0x1a, 0x8c, 0x1a, 0xc4, 0x1a, 0xe2, 0x1b, 0x1c, 0x1b, 0x6c, 0x1b, 0x8c, + 0x1b, 0xcc, 0x1b, 0xfc, 0x1c, 0x1e, 0x1c, 0x50, 0x1c, 0x78, 0x1c, 0xb2, + 0x1c, 0xea, 0x1d, 0x28, 0x1d, 0x6a, 0x1d, 0xc4, 0x1e, 0x22, 0x1e, 0x34, + 0x1e, 0x46, 0x1e, 0x80, 0x1e, 0xc4, 0x1e, 0xd6, 0x1f, 0x1a, 0x1f, 0x68, + 0x1f, 0x74, 0x1f, 0x86, 0x1f, 0x98, 0x1f, 0xc8, 0x1f, 0xda, 0x1f, 0xec, + 0x1f, 0xfe, 0x20, 0x22, 0x20, 0x34, 0x20, 0x8c, 0x20, 0xce, 0x20, 0xe0, + 0x20, 0xf2, 0x21, 0x3c, 0x21, 0x90, 0x21, 0xa2, 0x21, 0xd0, 0x22, 0x3c, + 0x22, 0x4e, 0x22, 0x60, 0x22, 0x98, 0x22, 0xaa, 0x22, 0xbc, 0x22, 0xfe, + 0x23, 0x66, 0x23, 0x76, 0x23, 0x86, 0x23, 0xd6, 0x24, 0x30, 0x24, 0x42, + 0x24, 0x9c, 0x25, 0x28, 0x25, 0x34, 0x25, 0x44, 0x25, 0x54, 0x25, 0x9a, + 0x25, 0xac, 0x25, 0xc8, 0x25, 0xe4, 0x26, 0x08, 0x26, 0x36, 0x26, 0x9e, + 0x26, 0xe2, 0x26, 0xf2, 0x27, 0x02, 0x27, 0x46, 0x27, 0x94, 0x27, 0xa6, + 0x27, 0xec, 0x28, 0x52, 0x28, 0x62, 0x28, 0x72, 0x28, 0xaa, 0x28, 0xbc, + 0x28, 0xcc, 0x29, 0x24, 0x29, 0x36, 0x00, 0x00, 0x00, 0x02, 0x00, 0x98, + 0xff, 0xe3, 0x01, 0x89, 0x05, 0xb6, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x2b, + 0x40, 0x14, 0x03, 0x09, 0x09, 0x02, 0x04, 0x04, 0x0f, 0x10, 0x01, 0x01, + 0x0c, 0x02, 0x0c, 0x06, 0x4f, 0x59, 0x0c, 0x16, 0x02, 0x03, 0x00, 0x3f, + 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x11, 0x12, 0x01, 0x39, + 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x23, 0x03, 0x33, 0x03, + 0x34, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x01, 0x46, + 0x69, 0x33, 0xcf, 0xe1, 0x78, 0x3a, 0x3f, 0x40, 0x39, 0x34, 0x44, 0x01, + 0x93, 0x04, 0x23, 0xfa, 0xb4, 0x88, 0x46, 0x42, 0x40, 0x47, 0x3f, 0x00, + 0x00, 0x02, 0x00, 0x85, 0x03, 0xa6, 0x02, 0xb0, 0x05, 0xb6, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x1f, 0x40, 0x0d, 0x00, 0x03, 0x07, 0x04, 0x03, 0x04, + 0x08, 0x09, 0x06, 0x02, 0x07, 0x03, 0x03, 0x00, 0x3f, 0x33, 0xcd, 0x32, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, + 0x03, 0x23, 0x03, 0x21, 0x03, 0x23, 0x03, 0x01, 0x3f, 0x28, 0x69, 0x29, + 0x02, 0x2b, 0x29, 0x68, 0x29, 0x05, 0xb6, 0xfd, 0xf0, 0x02, 0x10, 0xfd, + 0xf0, 0x02, 0x10, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x04, 0xf6, + 0x05, 0xb6, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x99, 0x40, 0x55, 0x08, 0x1f, + 0x1c, 0x15, 0x04, 0x14, 0x09, 0x11, 0x0c, 0x0c, 0x09, 0x12, 0x0f, 0x0e, + 0x0b, 0x04, 0x0a, 0x13, 0x13, 0x14, 0x16, 0x1d, 0x1e, 0x07, 0x04, 0x06, + 0x17, 0x04, 0x01, 0x00, 0x19, 0x04, 0x18, 0x05, 0x05, 0x06, 0x14, 0x06, + 0x0a, 0x21, 0x03, 0x1a, 0x17, 0x03, 0x18, 0x0a, 0x18, 0x20, 0x21, 0x08, + 0x04, 0x0c, 0x0d, 0x0c, 0x4e, 0x59, 0x1c, 0x01, 0x0d, 0x1f, 0x00, 0x10, + 0x11, 0x10, 0x4e, 0x59, 0x19, 0x15, 0x11, 0x4f, 0x0d, 0x01, 0x4f, 0x11, + 0x01, 0x0d, 0x11, 0x0d, 0x11, 0x05, 0x17, 0x13, 0x03, 0x0a, 0x05, 0x00, + 0x2f, 0x33, 0x3f, 0x33, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x5d, 0x5d, 0x11, + 0x33, 0x33, 0x2b, 0x11, 0x00, 0x33, 0x33, 0x11, 0x33, 0x33, 0x2b, 0x11, + 0x00, 0x33, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x17, 0x33, 0x11, + 0x12, 0x39, 0x39, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, 0x11, 0x12, 0x17, + 0x39, 0x11, 0x33, 0x11, 0x12, 0x17, 0x39, 0x32, 0x32, 0x11, 0x33, 0x11, + 0x12, 0x17, 0x39, 0x31, 0x30, 0x01, 0x03, 0x21, 0x15, 0x21, 0x03, 0x23, + 0x13, 0x21, 0x03, 0x23, 0x13, 0x21, 0x35, 0x21, 0x13, 0x21, 0x35, 0x21, + 0x13, 0x33, 0x03, 0x21, 0x13, 0x33, 0x03, 0x21, 0x15, 0x01, 0x21, 0x13, + 0x21, 0x03, 0xd5, 0x42, 0x01, 0x1b, 0xfe, 0xcd, 0x54, 0x89, 0x54, 0xfe, + 0xd1, 0x52, 0x88, 0x50, 0xfe, 0xfa, 0x01, 0x1f, 0x44, 0xfe, 0xeb, 0x01, + 0x2b, 0x52, 0x8b, 0x52, 0x01, 0x31, 0x54, 0x86, 0x54, 0x01, 0x08, 0xfc, + 0xe5, 0x01, 0x2f, 0x42, 0xfe, 0xd1, 0x03, 0x83, 0xfe, 0xac, 0x81, 0xfe, + 0x52, 0x01, 0xae, 0xfe, 0x52, 0x01, 0xae, 0x81, 0x01, 0x54, 0x7f, 0x01, + 0xb4, 0xfe, 0x4c, 0x01, 0xb4, 0xfe, 0x4c, 0x7f, 0xfe, 0xac, 0x01, 0x54, + 0x00, 0x03, 0x00, 0x83, 0xff, 0x89, 0x04, 0x0c, 0x06, 0x12, 0x00, 0x20, + 0x00, 0x26, 0x00, 0x2d, 0x00, 0x66, 0x40, 0x35, 0x27, 0x11, 0x25, 0x1d, + 0x17, 0x04, 0x04, 0x2a, 0x14, 0x0d, 0x05, 0x21, 0x00, 0x00, 0x19, 0x05, + 0x11, 0x09, 0x05, 0x2e, 0x2f, 0x25, 0x0d, 0x06, 0x0d, 0x4d, 0x59, 0x03, + 0x06, 0x24, 0x0e, 0x2a, 0x0e, 0x4c, 0x59, 0x1d, 0x2a, 0x2b, 0x1c, 0x14, + 0x1c, 0x4d, 0x59, 0x17, 0x2a, 0x14, 0x06, 0x14, 0x06, 0x14, 0x05, 0x16, + 0x05, 0x00, 0x2f, 0x2f, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x12, 0x39, 0x32, + 0x2b, 0x11, 0x00, 0x33, 0x11, 0x33, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x33, + 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x33, 0x33, 0x33, 0x11, 0x33, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x01, 0x14, 0x06, 0x07, 0x15, 0x23, 0x35, 0x22, 0x26, 0x27, 0x35, 0x1e, + 0x01, 0x33, 0x11, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, 0x35, 0x33, 0x15, + 0x16, 0x17, 0x07, 0x26, 0x27, 0x11, 0x1e, 0x02, 0x07, 0x34, 0x26, 0x27, + 0x11, 0x36, 0x01, 0x14, 0x16, 0x17, 0x11, 0x0e, 0x01, 0x04, 0x0c, 0xcc, + 0xb7, 0x81, 0x70, 0xd2, 0x43, 0x53, 0xd9, 0x59, 0xcd, 0xa5, 0xcb, 0xa7, + 0x81, 0xb8, 0xab, 0x34, 0x95, 0x9a, 0x9d, 0x9c, 0x4a, 0xaa, 0x59, 0x80, + 0xd9, 0xfd, 0xdd, 0x5a, 0x6f, 0x63, 0x66, 0x01, 0xc1, 0x88, 0xb1, 0x17, + 0xe8, 0xdf, 0x23, 0x1f, 0x9c, 0x25, 0x2f, 0x01, 0xb8, 0x41, 0xac, 0x88, + 0x83, 0xa8, 0x12, 0xb6, 0xb4, 0x05, 0x45, 0x83, 0x3b, 0x0b, 0xfe, 0x4e, + 0x32, 0x5f, 0x7b, 0x65, 0x48, 0x59, 0x2c, 0xfe, 0x7b, 0x1e, 0x03, 0x07, + 0x4c, 0x5c, 0x29, 0x01, 0x83, 0x10, 0x5d, 0x00, 0x00, 0x05, 0x00, 0x68, + 0xff, 0xec, 0x06, 0x2d, 0x05, 0xcb, 0x00, 0x09, 0x00, 0x15, 0x00, 0x21, + 0x00, 0x2d, 0x00, 0x31, 0x00, 0x45, 0x40, 0x24, 0x00, 0x10, 0x05, 0x0a, + 0x16, 0x28, 0x1c, 0x22, 0x22, 0x2e, 0x28, 0x0a, 0x30, 0x10, 0x06, 0x32, + 0x33, 0x03, 0x0d, 0x1f, 0x2b, 0x0d, 0x2b, 0x0d, 0x2b, 0x30, 0x31, 0x06, + 0x30, 0x18, 0x19, 0x25, 0x19, 0x07, 0x13, 0x07, 0x00, 0x3f, 0x33, 0x3f, + 0x33, 0x3f, 0x3f, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x13, 0x14, 0x16, 0x33, 0x32, 0x11, 0x10, 0x23, 0x22, + 0x06, 0x05, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, + 0x16, 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, + 0x06, 0x05, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, + 0x16, 0x09, 0x01, 0x23, 0x01, 0xf2, 0x4a, 0x53, 0xa4, 0xa4, 0x53, 0x4a, + 0x01, 0xca, 0x99, 0x94, 0x8c, 0x9b, 0x95, 0x92, 0x91, 0x9c, 0x01, 0xa6, + 0x4a, 0x54, 0x54, 0x50, 0x50, 0x54, 0x54, 0x4a, 0x01, 0xcb, 0x99, 0x94, + 0x8e, 0x99, 0x95, 0x92, 0x8e, 0x9f, 0xfe, 0xfe, 0xfc, 0xd5, 0x93, 0x03, + 0x2b, 0x04, 0x02, 0xaa, 0xaa, 0x01, 0x54, 0x01, 0x52, 0xa8, 0xaa, 0xe4, + 0xe9, 0xee, 0xdf, 0xe3, 0xe6, 0xee, 0xfc, 0xdb, 0xab, 0xa9, 0xa7, 0xad, + 0xab, 0xa5, 0xa5, 0xab, 0xe3, 0xe9, 0xee, 0xde, 0xe3, 0xe6, 0xeb, 0x03, + 0x20, 0xfa, 0x4a, 0x05, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x71, + 0xff, 0xec, 0x05, 0xd3, 0x05, 0xcd, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x35, + 0x00, 0x51, 0x40, 0x30, 0x13, 0x16, 0x00, 0x1d, 0x06, 0x23, 0x2a, 0x2b, + 0x2e, 0x2b, 0x2d, 0x23, 0x0e, 0x26, 0x19, 0x1d, 0x16, 0x09, 0x36, 0x37, + 0x33, 0x0c, 0x49, 0x59, 0x33, 0x13, 0x0f, 0x27, 0x2d, 0x0e, 0x30, 0x05, + 0x2f, 0x03, 0x19, 0x26, 0x03, 0x2a, 0x2a, 0x20, 0x2f, 0x12, 0x20, 0x09, + 0x4a, 0x59, 0x20, 0x04, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x12, 0x39, + 0x2f, 0x17, 0x39, 0x12, 0x17, 0x39, 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x17, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, + 0x14, 0x16, 0x17, 0x3e, 0x01, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x13, + 0x32, 0x37, 0x01, 0x0e, 0x02, 0x15, 0x14, 0x16, 0x25, 0x34, 0x36, 0x37, + 0x2e, 0x02, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, + 0x01, 0x3e, 0x01, 0x37, 0x33, 0x02, 0x07, 0x01, 0x23, 0x27, 0x0e, 0x01, + 0x23, 0x22, 0x26, 0x01, 0x9e, 0x48, 0x57, 0x81, 0x65, 0x67, 0x56, 0x59, + 0x6f, 0x9b, 0xf1, 0x9f, 0xfe, 0x4b, 0x6f, 0x5c, 0x2c, 0x9b, 0xfe, 0xb9, + 0x8b, 0xb4, 0x55, 0x3d, 0x24, 0xc4, 0xaf, 0xa2, 0xba, 0x88, 0x9d, 0x01, + 0x97, 0x38, 0x43, 0x17, 0xa8, 0x44, 0x89, 0x01, 0x2b, 0xe5, 0xb9, 0x76, + 0xf4, 0x96, 0xd7, 0xed, 0x04, 0x93, 0x45, 0x7d, 0x58, 0x4b, 0x7f, 0x53, + 0x4d, 0x61, 0x60, 0xfb, 0x9d, 0x9a, 0x01, 0xa8, 0x44, 0x59, 0x66, 0x41, + 0x75, 0x89, 0xfa, 0x82, 0xc8, 0x66, 0x5f, 0x62, 0x6a, 0x39, 0x96, 0xa8, + 0xa7, 0x95, 0x6b, 0xb5, 0x5d, 0xfe, 0x79, 0x3e, 0xa7, 0x63, 0xfe, 0xe2, + 0x94, 0xfe, 0xdd, 0xb2, 0x6a, 0x5c, 0xd4, 0x00, 0x00, 0x01, 0x00, 0x85, + 0x03, 0xa6, 0x01, 0x3f, 0x05, 0xb6, 0x00, 0x03, 0x00, 0x14, 0xb7, 0x00, + 0x03, 0x03, 0x04, 0x05, 0x02, 0x03, 0x03, 0x00, 0x3f, 0xcd, 0x11, 0x12, + 0x01, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x03, 0x23, 0x03, 0x01, 0x3f, + 0x28, 0x69, 0x29, 0x05, 0xb6, 0xfd, 0xf0, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x52, 0xfe, 0xbc, 0x02, 0x21, 0x05, 0xb6, 0x00, 0x0d, + 0x00, 0x1c, 0x40, 0x0c, 0x07, 0x00, 0x0a, 0x04, 0x00, 0x04, 0x0e, 0x0f, + 0x0b, 0x27, 0x03, 0x03, 0x00, 0x3f, 0x3f, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x10, 0x12, 0x37, 0x33, 0x06, + 0x02, 0x15, 0x14, 0x12, 0x17, 0x23, 0x26, 0x02, 0x52, 0x9b, 0x92, 0xa2, + 0x90, 0x91, 0x94, 0x8b, 0xa0, 0x93, 0x9a, 0x02, 0x31, 0x01, 0x09, 0x01, + 0xce, 0xae, 0xc1, 0xfe, 0x32, 0xf4, 0xf0, 0xfe, 0x36, 0xbd, 0xaa, 0x01, + 0xc6, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3d, 0xfe, 0xbc, 0x02, 0x0c, + 0x05, 0xb6, 0x00, 0x0d, 0x00, 0x1c, 0x40, 0x0c, 0x04, 0x0a, 0x07, 0x00, + 0x0a, 0x00, 0x0e, 0x0f, 0x0a, 0x03, 0x04, 0x27, 0x00, 0x3f, 0x3f, 0x11, + 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, + 0x02, 0x07, 0x23, 0x36, 0x12, 0x35, 0x34, 0x02, 0x27, 0x33, 0x16, 0x12, + 0x02, 0x0c, 0x9b, 0x92, 0xa0, 0x8b, 0x94, 0x91, 0x90, 0xa2, 0x93, 0x9a, + 0x02, 0x31, 0xfe, 0xf9, 0xfe, 0x3a, 0xa8, 0xbc, 0x01, 0xcb, 0xf0, 0xf4, + 0x01, 0xce, 0xc1, 0xaf, 0xfe, 0x31, 0x00, 0x00, 0x00, 0x01, 0x00, 0x56, + 0x02, 0x7f, 0x04, 0x0e, 0x06, 0x14, 0x00, 0x0e, 0x00, 0x30, 0x40, 0x1b, + 0x03, 0x05, 0x04, 0x01, 0x07, 0x0d, 0x0a, 0x09, 0x0b, 0x09, 0x0f, 0x10, + 0x04, 0x0a, 0x01, 0x0d, 0x02, 0x0c, 0x0c, 0x0d, 0x0a, 0x07, 0x04, 0x06, + 0x08, 0x0e, 0x00, 0x00, 0x3f, 0xc4, 0x32, 0x17, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x31, 0x30, 0x01, 0x03, + 0x25, 0x17, 0x05, 0x13, 0x07, 0x0b, 0x01, 0x27, 0x13, 0x25, 0x37, 0x05, + 0x03, 0x02, 0x91, 0x2b, 0x01, 0x8e, 0x1a, 0xfe, 0x83, 0xf8, 0xac, 0xb0, + 0xa0, 0xb0, 0xf2, 0xfe, 0x87, 0x1d, 0x01, 0x87, 0x2b, 0x06, 0x14, 0xfe, + 0x75, 0x6f, 0xb6, 0x1f, 0xfe, 0xba, 0x5e, 0x01, 0x6a, 0xfe, 0x96, 0x5e, + 0x01, 0x46, 0x1f, 0xb6, 0x6f, 0x01, 0x8b, 0x00, 0x00, 0x01, 0x00, 0x68, + 0x00, 0xe3, 0x04, 0x29, 0x04, 0xc3, 0x00, 0x0b, 0x00, 0x28, 0x40, 0x13, + 0x00, 0x04, 0x04, 0x09, 0x05, 0x05, 0x0c, 0x0d, 0x03, 0x07, 0x08, 0x07, + 0x50, 0x59, 0x00, 0x0f, 0x08, 0x01, 0x08, 0x00, 0x2f, 0x5d, 0x33, 0x2b, + 0x11, 0x00, 0x33, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, + 0x31, 0x30, 0x01, 0x21, 0x15, 0x21, 0x11, 0x23, 0x11, 0x21, 0x35, 0x21, + 0x11, 0x33, 0x02, 0x8d, 0x01, 0x9c, 0xfe, 0x64, 0x8b, 0xfe, 0x66, 0x01, + 0x9a, 0x8b, 0x03, 0x17, 0x8a, 0xfe, 0x56, 0x01, 0xaa, 0x8a, 0x01, 0xac, + 0x00, 0x01, 0x00, 0x3f, 0xfe, 0xf8, 0x01, 0x6d, 0x00, 0xee, 0x00, 0x08, + 0x00, 0x11, 0xb5, 0x05, 0x00, 0x09, 0x0a, 0x05, 0x00, 0x00, 0x2f, 0xcd, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x31, 0x30, 0x25, 0x17, 0x06, 0x02, 0x07, + 0x23, 0x36, 0x12, 0x37, 0x01, 0x5e, 0x0f, 0x1a, 0x62, 0x35, 0x7d, 0x1b, + 0x41, 0x0d, 0xee, 0x17, 0x64, 0xfe, 0xf7, 0x72, 0x68, 0x01, 0x32, 0x5c, + 0x00, 0x01, 0x00, 0x54, 0x01, 0xd9, 0x02, 0x3f, 0x02, 0x71, 0x00, 0x03, + 0x00, 0x11, 0xb5, 0x02, 0x00, 0x05, 0x04, 0x00, 0x01, 0x00, 0x2f, 0x33, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x31, 0x30, 0x13, 0x35, 0x21, 0x15, 0x54, + 0x01, 0xeb, 0x01, 0xd9, 0x98, 0x98, 0x00, 0x00, 0x00, 0x01, 0x00, 0x98, + 0xff, 0xe3, 0x01, 0x89, 0x00, 0xf2, 0x00, 0x0b, 0x00, 0x18, 0x40, 0x0b, + 0x06, 0x00, 0x00, 0x0c, 0x0d, 0x09, 0x03, 0x4f, 0x59, 0x09, 0x16, 0x00, + 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x31, 0x30, 0x37, 0x34, + 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x98, 0x3d, + 0x39, 0x3a, 0x41, 0x42, 0x39, 0x33, 0x43, 0x6a, 0x43, 0x45, 0x45, 0x43, + 0x41, 0x46, 0x3f, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x02, 0xdb, + 0x05, 0xb6, 0x00, 0x03, 0x00, 0x13, 0xb7, 0x02, 0x00, 0x04, 0x05, 0x03, + 0x03, 0x02, 0x12, 0x00, 0x3f, 0x3f, 0x11, 0x12, 0x01, 0x39, 0x39, 0x31, + 0x30, 0x09, 0x01, 0x23, 0x01, 0x02, 0xdb, 0xfd, 0xdf, 0xa6, 0x02, 0x21, + 0x05, 0xb6, 0xfa, 0x4a, 0x05, 0xb6, 0x00, 0x00, 0x00, 0x02, 0x00, 0x66, + 0xff, 0xec, 0x04, 0x2d, 0x05, 0xcd, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x28, + 0x40, 0x14, 0x12, 0x00, 0x0c, 0x06, 0x00, 0x06, 0x19, 0x18, 0x09, 0x15, + 0x4b, 0x59, 0x09, 0x07, 0x03, 0x0f, 0x4b, 0x59, 0x03, 0x19, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x02, 0x23, 0x22, 0x02, 0x11, 0x10, + 0x12, 0x33, 0x32, 0x12, 0x01, 0x10, 0x12, 0x33, 0x32, 0x12, 0x11, 0x10, + 0x02, 0x23, 0x22, 0x02, 0x04, 0x2d, 0xef, 0xf6, 0xec, 0xf6, 0xee, 0xf4, + 0xee, 0xf7, 0xfc, 0xe1, 0x96, 0xa4, 0xa6, 0x95, 0x95, 0xa6, 0xa4, 0x96, + 0x02, 0xdd, 0xfe, 0x85, 0xfe, 0x8a, 0x01, 0x7f, 0x01, 0x72, 0x01, 0x7e, + 0x01, 0x72, 0xfe, 0x7e, 0xfe, 0x92, 0xfe, 0xc1, 0xfe, 0xdd, 0x01, 0x27, + 0x01, 0x3b, 0x01, 0x3b, 0x01, 0x25, 0xfe, 0xdf, 0x00, 0x01, 0x00, 0xbc, + 0x00, 0x00, 0x02, 0xcb, 0x05, 0xb6, 0x00, 0x0a, 0x00, 0x24, 0x40, 0x10, + 0x09, 0x00, 0x01, 0x08, 0x01, 0x0b, 0x0c, 0x04, 0x09, 0x07, 0x07, 0x01, + 0x09, 0x06, 0x01, 0x18, 0x00, 0x3f, 0x3f, 0x12, 0x39, 0x2f, 0x12, 0x39, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x33, 0x31, 0x30, 0x21, 0x23, + 0x11, 0x34, 0x37, 0x0e, 0x01, 0x07, 0x27, 0x01, 0x33, 0x02, 0xcb, 0xa2, + 0x08, 0x15, 0x34, 0xd4, 0x58, 0x01, 0x83, 0x8c, 0x04, 0x12, 0x82, 0x74, + 0x15, 0x2e, 0xac, 0x72, 0x01, 0x2b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x64, + 0x00, 0x00, 0x04, 0x25, 0x05, 0xcb, 0x00, 0x19, 0x00, 0x2b, 0x40, 0x17, + 0x18, 0x01, 0x07, 0x13, 0x00, 0x13, 0x0e, 0x01, 0x04, 0x1a, 0x1b, 0x10, + 0x0a, 0x4b, 0x59, 0x10, 0x07, 0x01, 0x18, 0x4c, 0x59, 0x01, 0x18, 0x00, + 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x31, 0x30, 0x29, 0x01, 0x35, 0x01, 0x3e, 0x02, 0x35, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x02, 0x07, 0x01, 0x15, 0x21, 0x04, 0x25, 0xfc, 0x3f, 0x01, 0x81, + 0xb0, 0x70, 0x38, 0x8e, 0x7e, 0x5b, 0xa3, 0x64, 0x58, 0xca, 0xee, 0xce, + 0xea, 0x9c, 0xd6, 0xfe, 0xc0, 0x02, 0xf0, 0x8f, 0x01, 0x83, 0xb2, 0x98, + 0x90, 0x53, 0x75, 0x89, 0x3c, 0x4f, 0x71, 0xa8, 0xd3, 0xb2, 0x8b, 0xfe, + 0xf0, 0xd0, 0xfe, 0xc7, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5e, + 0xff, 0xec, 0x04, 0x1b, 0x05, 0xcb, 0x00, 0x27, 0x00, 0x43, 0x40, 0x24, + 0x1b, 0x00, 0x13, 0x07, 0x07, 0x00, 0x03, 0x16, 0x22, 0x0d, 0x06, 0x28, + 0x29, 0x03, 0x17, 0x16, 0x17, 0x16, 0x4b, 0x59, 0x17, 0x17, 0x0a, 0x25, + 0x25, 0x1e, 0x4b, 0x59, 0x25, 0x07, 0x0a, 0x11, 0x4b, 0x59, 0x0a, 0x19, + 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, + 0x2f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x06, 0x07, 0x15, 0x1e, 0x01, + 0x15, 0x14, 0x04, 0x21, 0x22, 0x26, 0x27, 0x35, 0x1e, 0x01, 0x33, 0x20, + 0x11, 0x10, 0x21, 0x23, 0x35, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x03, 0xee, 0x9d, + 0x90, 0xb0, 0xaa, 0xfe, 0xde, 0xfe, 0xf5, 0x74, 0xc1, 0x5b, 0x5f, 0xd7, + 0x60, 0x01, 0x7b, 0xfe, 0x5e, 0x90, 0x92, 0xab, 0xc8, 0x93, 0x7e, 0x60, + 0xaa, 0x6d, 0x54, 0x5a, 0xeb, 0x82, 0xd5, 0xec, 0x04, 0x5e, 0x8c, 0xb2, + 0x1e, 0x08, 0x16, 0xb4, 0x92, 0xd1, 0xe1, 0x23, 0x2c, 0x9e, 0x2f, 0x31, + 0x01, 0x29, 0x01, 0x0a, 0x8f, 0x97, 0x86, 0x6b, 0x7a, 0x34, 0x46, 0x70, + 0x47, 0x51, 0xc3, 0x00, 0x00, 0x02, 0x00, 0x2b, 0x00, 0x00, 0x04, 0x6a, + 0x05, 0xbe, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x3c, 0x40, 0x1e, 0x12, 0x05, + 0x09, 0x02, 0x02, 0x0b, 0x07, 0x03, 0x00, 0x03, 0x05, 0x03, 0x13, 0x14, + 0x01, 0x05, 0x12, 0x05, 0x4c, 0x59, 0x09, 0x0f, 0x07, 0x12, 0x12, 0x03, + 0x07, 0x06, 0x03, 0x18, 0x00, 0x3f, 0x3f, 0x12, 0x39, 0x2f, 0x12, 0x39, + 0x33, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, + 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x23, 0x11, 0x23, + 0x11, 0x21, 0x35, 0x01, 0x33, 0x11, 0x33, 0x21, 0x11, 0x34, 0x37, 0x23, + 0x06, 0x07, 0x01, 0x04, 0x6a, 0xd9, 0x9f, 0xfd, 0x39, 0x02, 0xb6, 0xb0, + 0xd9, 0xfe, 0x88, 0x0a, 0x08, 0x30, 0x2a, 0xfe, 0x37, 0x01, 0x50, 0xfe, + 0xb0, 0x01, 0x50, 0x91, 0x03, 0xdd, 0xfc, 0x29, 0x01, 0xe6, 0x8f, 0xb4, + 0x60, 0x3f, 0xfd, 0x76, 0x00, 0x01, 0x00, 0x85, 0xff, 0xec, 0x04, 0x1d, + 0x05, 0xb6, 0x00, 0x1a, 0x00, 0x3a, 0x40, 0x1f, 0x0f, 0x03, 0x19, 0x14, + 0x08, 0x14, 0x17, 0x03, 0x04, 0x1c, 0x1b, 0x00, 0x11, 0x4b, 0x59, 0x00, + 0x00, 0x06, 0x15, 0x15, 0x18, 0x4c, 0x59, 0x15, 0x06, 0x06, 0x0c, 0x4b, + 0x59, 0x06, 0x19, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x32, 0x04, 0x15, 0x14, 0x00, 0x23, 0x22, + 0x27, 0x35, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, 0x10, 0x21, 0x22, 0x07, + 0x27, 0x13, 0x21, 0x15, 0x21, 0x03, 0x36, 0x02, 0x2d, 0xe7, 0x01, 0x09, + 0xfe, 0xdf, 0xfe, 0xf7, 0x82, 0x46, 0xd0, 0x65, 0xb0, 0xc3, 0xfe, 0x89, + 0x5f, 0x9f, 0x56, 0x37, 0x02, 0xd7, 0xfd, 0xb7, 0x25, 0x73, 0x03, 0x7d, + 0xe5, 0xc7, 0xe3, 0xfe, 0xfe, 0x4f, 0xa0, 0x2d, 0x33, 0xa6, 0x9d, 0x01, + 0x32, 0x1d, 0x37, 0x02, 0xac, 0x99, 0xfe, 0x49, 0x17, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x75, 0xff, 0xec, 0x04, 0x2f, 0x05, 0xcb, 0x00, 0x16, + 0x00, 0x24, 0x00, 0x44, 0x40, 0x23, 0x1a, 0x11, 0x0b, 0x21, 0x21, 0x00, + 0x00, 0x06, 0x11, 0x03, 0x26, 0x25, 0x0c, 0x0b, 0x0e, 0x1d, 0x4d, 0x59, + 0x0b, 0x0e, 0x0e, 0x14, 0x03, 0x14, 0x17, 0x4b, 0x59, 0x14, 0x19, 0x03, + 0x08, 0x4d, 0x59, 0x03, 0x07, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x39, 0x2b, 0x11, 0x00, 0x33, 0x11, + 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x13, 0x10, 0x00, 0x21, 0x32, 0x17, 0x15, 0x26, 0x23, 0x22, 0x02, 0x03, + 0x33, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x02, 0x23, 0x22, 0x00, 0x05, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x0e, 0x01, 0x15, 0x14, 0x1e, + 0x01, 0x75, 0x01, 0x4f, 0x01, 0x48, 0x71, 0x41, 0x4d, 0x63, 0xeb, 0xf8, + 0x0c, 0x0c, 0x6e, 0xee, 0xc5, 0xe3, 0xf9, 0xd4, 0xe3, 0xfe, 0xf6, 0x01, + 0xeb, 0x8e, 0x9d, 0x92, 0x91, 0x5a, 0x96, 0x59, 0x50, 0x93, 0x02, 0x71, + 0x01, 0xaf, 0x01, 0xab, 0x13, 0x8f, 0x19, 0xfe, 0xdb, 0xfe, 0xc6, 0xac, + 0xee, 0xcc, 0xe4, 0xfe, 0xfb, 0x01, 0x55, 0xc8, 0xb3, 0xa9, 0x91, 0xa6, + 0x4a, 0x82, 0x46, 0x67, 0xb2, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5e, + 0x00, 0x00, 0x04, 0x2b, 0x05, 0xb6, 0x00, 0x06, 0x00, 0x1f, 0x40, 0x10, + 0x01, 0x05, 0x05, 0x00, 0x02, 0x03, 0x07, 0x08, 0x03, 0x02, 0x4c, 0x59, + 0x03, 0x06, 0x00, 0x18, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x17, + 0x39, 0x11, 0x33, 0x31, 0x30, 0x21, 0x01, 0x21, 0x35, 0x21, 0x15, 0x01, + 0x01, 0x1d, 0x02, 0x5e, 0xfc, 0xe3, 0x03, 0xcd, 0xfd, 0xaa, 0x05, 0x1d, + 0x99, 0x85, 0xfa, 0xcf, 0x00, 0x03, 0x00, 0x68, 0xff, 0xec, 0x04, 0x29, + 0x05, 0xcb, 0x00, 0x16, 0x00, 0x22, 0x00, 0x2e, 0x00, 0x4d, 0x40, 0x29, + 0x17, 0x0f, 0x26, 0x14, 0x2c, 0x03, 0x1d, 0x09, 0x09, 0x03, 0x06, 0x11, + 0x14, 0x0f, 0x06, 0x2f, 0x30, 0x06, 0x11, 0x29, 0x20, 0x29, 0x20, 0x4b, + 0x59, 0x29, 0x29, 0x0c, 0x00, 0x0c, 0x1a, 0x4d, 0x59, 0x0c, 0x19, 0x00, + 0x23, 0x4d, 0x59, 0x00, 0x07, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, + 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x32, 0x16, 0x15, 0x14, 0x06, 0x07, 0x1e, 0x01, + 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x25, 0x2e, 0x01, 0x35, + 0x34, 0x36, 0x03, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x27, + 0x0e, 0x01, 0x01, 0x22, 0x06, 0x15, 0x14, 0x16, 0x17, 0x3e, 0x01, 0x35, + 0x34, 0x26, 0x02, 0x48, 0xc8, 0xea, 0x86, 0x93, 0xb2, 0x96, 0xfe, 0xdd, + 0xea, 0xfc, 0x01, 0x32, 0x8a, 0x78, 0xeb, 0x77, 0xa7, 0x97, 0x95, 0xa6, + 0x9c, 0xc2, 0x95, 0x86, 0x01, 0x3a, 0x7d, 0x8e, 0x76, 0x9f, 0x8f, 0x77, + 0x91, 0x05, 0xcb, 0xba, 0xa4, 0x6c, 0xb2, 0x49, 0x55, 0xbb, 0x7b, 0xb6, + 0xd9, 0xcd, 0xbc, 0xfb, 0x8c, 0x4e, 0xb5, 0x70, 0x9f, 0xbd, 0xfb, 0xa6, + 0x78, 0x86, 0x8c, 0x7a, 0x61, 0x97, 0x47, 0x40, 0x9b, 0x03, 0x67, 0x78, + 0x64, 0x5c, 0x84, 0x42, 0x3c, 0x8a, 0x5c, 0x65, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x6a, 0xff, 0xec, 0x04, 0x25, 0x05, 0xcb, 0x00, 0x17, + 0x00, 0x25, 0x00, 0x41, 0x40, 0x22, 0x1b, 0x11, 0x22, 0x0a, 0x0a, 0x00, + 0x00, 0x04, 0x11, 0x03, 0x26, 0x27, 0x0e, 0x1e, 0x4d, 0x59, 0x0b, 0x14, + 0x0e, 0x0e, 0x02, 0x14, 0x14, 0x18, 0x4b, 0x59, 0x14, 0x07, 0x02, 0x07, + 0x4d, 0x59, 0x02, 0x19, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x18, 0x2f, 0x12, 0x39, 0x2b, 0x11, 0x12, 0x01, 0x17, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x21, + 0x22, 0x27, 0x35, 0x16, 0x33, 0x32, 0x12, 0x13, 0x23, 0x0e, 0x01, 0x23, + 0x22, 0x26, 0x35, 0x34, 0x00, 0x33, 0x32, 0x16, 0x12, 0x01, 0x22, 0x06, + 0x15, 0x14, 0x16, 0x33, 0x32, 0x3e, 0x01, 0x35, 0x34, 0x2e, 0x01, 0x04, + 0x25, 0xfd, 0x68, 0x74, 0x44, 0x50, 0x66, 0xf0, 0xf5, 0x0b, 0x0c, 0x37, + 0xb6, 0x72, 0xc2, 0xe4, 0x00, 0xff, 0xd0, 0x95, 0xdf, 0x78, 0xfe, 0x14, + 0x8f, 0x9c, 0x90, 0x93, 0x5b, 0x99, 0x58, 0x52, 0x93, 0x03, 0x46, 0xfc, + 0xa6, 0x14, 0x8f, 0x1a, 0x01, 0x29, 0x01, 0x33, 0x53, 0x57, 0xe8, 0xd0, + 0xe4, 0x01, 0x08, 0x99, 0xfe, 0xdb, 0x01, 0x30, 0xb8, 0xa4, 0x90, 0xa5, + 0x4a, 0x80, 0x46, 0x69, 0xb2, 0x66, 0x00, 0x00, 0x00, 0x02, 0x00, 0x98, + 0xff, 0xe3, 0x01, 0x89, 0x04, 0x64, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x28, + 0x40, 0x14, 0x10, 0x06, 0x06, 0x0c, 0x00, 0x00, 0x16, 0x17, 0x0e, 0x13, + 0x4f, 0x59, 0x0e, 0x10, 0x09, 0x03, 0x4f, 0x59, 0x09, 0x16, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x37, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x23, 0x22, 0x26, 0x11, 0x34, 0x33, 0x32, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x98, 0x3d, 0x39, 0x3a, 0x41, 0x42, 0x39, 0x33, 0x43, 0x76, + 0x7b, 0x42, 0x39, 0x33, 0x43, 0x6a, 0x43, 0x45, 0x45, 0x43, 0x41, 0x46, + 0x3f, 0x03, 0xbb, 0x87, 0x87, 0x41, 0x46, 0x3f, 0x00, 0x02, 0x00, 0x3f, + 0xfe, 0xf8, 0x01, 0x85, 0x04, 0x64, 0x00, 0x08, 0x00, 0x12, 0x00, 0x22, + 0x40, 0x10, 0x01, 0x0d, 0x0d, 0x05, 0x09, 0x09, 0x14, 0x13, 0x0b, 0x10, + 0x4f, 0x59, 0x0b, 0x10, 0x05, 0x00, 0x00, 0x2f, 0xcd, 0x3f, 0x2b, 0x11, + 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x25, 0x17, + 0x06, 0x02, 0x07, 0x23, 0x36, 0x12, 0x37, 0x03, 0x34, 0x33, 0x32, 0x15, + 0x14, 0x06, 0x23, 0x22, 0x26, 0x01, 0x5e, 0x0f, 0x1a, 0x62, 0x35, 0x7d, + 0x1b, 0x41, 0x0d, 0x15, 0x77, 0x7b, 0x42, 0x39, 0x3a, 0x3d, 0xee, 0x17, + 0x64, 0xfe, 0xf7, 0x72, 0x68, 0x01, 0x32, 0x5c, 0x02, 0xef, 0x87, 0x87, + 0x41, 0x46, 0x46, 0x00, 0x00, 0x01, 0x00, 0x68, 0x00, 0xf2, 0x04, 0x29, + 0x04, 0xd9, 0x00, 0x06, 0x00, 0x15, 0x40, 0x09, 0x04, 0x00, 0x05, 0x01, + 0x04, 0x07, 0x08, 0x03, 0x00, 0x00, 0x2f, 0x2f, 0x11, 0x12, 0x01, 0x17, + 0x39, 0x31, 0x30, 0x25, 0x01, 0x35, 0x01, 0x15, 0x09, 0x01, 0x04, 0x29, + 0xfc, 0x3f, 0x03, 0xc1, 0xfc, 0xf2, 0x03, 0x0e, 0xf2, 0x01, 0xa6, 0x62, + 0x01, 0xdf, 0x95, 0xfe, 0x8d, 0xfe, 0xb8, 0x00, 0x00, 0x02, 0x00, 0x77, + 0x01, 0xc1, 0x04, 0x19, 0x03, 0xe3, 0x00, 0x03, 0x00, 0x07, 0x00, 0x2a, + 0x40, 0x15, 0x07, 0x02, 0x04, 0x00, 0x02, 0x00, 0x09, 0x08, 0x04, 0x05, + 0x50, 0x59, 0x04, 0x01, 0x00, 0x50, 0x59, 0x0f, 0x01, 0x01, 0x01, 0x00, + 0x2f, 0x5d, 0x2b, 0x00, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x35, 0x21, 0x15, 0x01, 0x35, + 0x21, 0x15, 0x77, 0x03, 0xa2, 0xfc, 0x5e, 0x03, 0xa2, 0x03, 0x5a, 0x89, + 0x89, 0xfe, 0x67, 0x89, 0x89, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x68, + 0x00, 0xf2, 0x04, 0x29, 0x04, 0xd9, 0x00, 0x06, 0x00, 0x15, 0x40, 0x09, + 0x05, 0x01, 0x02, 0x00, 0x04, 0x07, 0x08, 0x06, 0x03, 0x00, 0x2f, 0x2f, + 0x11, 0x12, 0x01, 0x17, 0x39, 0x31, 0x30, 0x13, 0x09, 0x01, 0x35, 0x01, + 0x15, 0x01, 0x68, 0x03, 0x0f, 0xfc, 0xf1, 0x03, 0xc1, 0xfc, 0x3f, 0x01, + 0x89, 0x01, 0x46, 0x01, 0x75, 0x95, 0xfe, 0x21, 0x62, 0xfe, 0x5a, 0x00, + 0x00, 0x02, 0x00, 0x1b, 0xff, 0xe3, 0x03, 0x39, 0x05, 0xcb, 0x00, 0x1b, + 0x00, 0x26, 0x00, 0x39, 0x40, 0x1d, 0x21, 0x1c, 0x1b, 0x00, 0x07, 0x13, + 0x13, 0x00, 0x1c, 0x0e, 0x04, 0x27, 0x28, 0x00, 0x00, 0x24, 0x10, 0x24, + 0x1e, 0x4f, 0x59, 0x24, 0x16, 0x10, 0x0a, 0x49, 0x59, 0x10, 0x04, 0x00, + 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, + 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x01, 0x35, 0x34, 0x36, 0x37, 0x3e, 0x01, 0x35, 0x34, 0x26, 0x23, + 0x22, 0x06, 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x0e, 0x01, + 0x07, 0x0e, 0x01, 0x1d, 0x01, 0x03, 0x34, 0x33, 0x32, 0x16, 0x15, 0x14, + 0x06, 0x23, 0x22, 0x26, 0x01, 0x21, 0x48, 0x62, 0x88, 0x47, 0x83, 0x7b, + 0x4f, 0x96, 0x61, 0x3b, 0xbd, 0xce, 0xbf, 0xd4, 0x27, 0x4c, 0x7e, 0x65, + 0x41, 0xb2, 0x78, 0x3a, 0x3f, 0x40, 0x39, 0x34, 0x44, 0x01, 0x93, 0x36, + 0x75, 0x97, 0x54, 0x73, 0x74, 0x52, 0x66, 0x6f, 0x25, 0x31, 0x87, 0x63, + 0xbc, 0xab, 0x49, 0x6f, 0x63, 0x6e, 0x56, 0x72, 0x5f, 0x21, 0xfe, 0xd7, + 0x88, 0x46, 0x42, 0x40, 0x47, 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x79, + 0xff, 0x46, 0x06, 0xb8, 0x05, 0xb4, 0x00, 0x35, 0x00, 0x3f, 0x00, 0x45, + 0x40, 0x22, 0x23, 0x2e, 0x36, 0x0e, 0x3b, 0x07, 0x14, 0x1b, 0x00, 0x00, + 0x29, 0x14, 0x0e, 0x2e, 0x05, 0x40, 0x41, 0x18, 0x38, 0x38, 0x04, 0x3d, + 0x08, 0x11, 0x0b, 0x11, 0x0b, 0x11, 0x2b, 0x1f, 0x32, 0x03, 0x26, 0x2b, + 0x00, 0x2f, 0x33, 0x3f, 0x33, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x12, 0x39, + 0x32, 0x33, 0x33, 0x11, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x0e, + 0x01, 0x23, 0x22, 0x26, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, + 0x34, 0x12, 0x33, 0x32, 0x16, 0x17, 0x03, 0x15, 0x14, 0x33, 0x32, 0x36, + 0x35, 0x34, 0x02, 0x24, 0x23, 0x22, 0x04, 0x02, 0x15, 0x10, 0x00, 0x21, + 0x32, 0x37, 0x15, 0x06, 0x23, 0x20, 0x00, 0x11, 0x10, 0x12, 0x24, 0x21, + 0x32, 0x04, 0x12, 0x01, 0x14, 0x33, 0x32, 0x1b, 0x01, 0x26, 0x23, 0x22, + 0x06, 0x06, 0xb8, 0x58, 0xa0, 0x68, 0x56, 0x76, 0x0b, 0x08, 0x28, 0x95, + 0x66, 0x96, 0xa9, 0xec, 0xc0, 0x44, 0xac, 0x45, 0x19, 0x85, 0x5b, 0x72, + 0x94, 0xfe, 0xef, 0xb1, 0xdf, 0xfe, 0xb6, 0xae, 0x01, 0x42, 0x01, 0x2f, + 0xd2, 0xe2, 0xc0, 0xf4, 0xfe, 0x95, 0xfe, 0x6f, 0xd6, 0x01, 0x8c, 0x01, + 0x00, 0xd7, 0x01, 0x4f, 0xb7, 0xfb, 0xf6, 0xc3, 0xcf, 0x12, 0x0e, 0x48, + 0x55, 0x82, 0x93, 0x02, 0xd9, 0x8e, 0xec, 0x82, 0x68, 0x51, 0x57, 0x62, + 0xcd, 0xb0, 0xcc, 0x00, 0xff, 0x19, 0x16, 0xfe, 0x2a, 0x16, 0xb2, 0xd7, + 0xac, 0xb5, 0x01, 0x10, 0x93, 0xb9, 0xfe, 0xa9, 0xe1, 0xfe, 0xcf, 0xfe, + 0xb8, 0x56, 0x85, 0x54, 0x01, 0x8f, 0x01, 0x66, 0x01, 0x04, 0x01, 0x96, + 0xdf, 0xb5, 0xfe, 0xb3, 0xfe, 0xa4, 0xfe, 0x01, 0x39, 0x01, 0x05, 0x14, + 0xb4, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x05, 0xbc, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x39, 0x40, 0x1e, 0x02, 0x0e, + 0x0b, 0x08, 0x01, 0x05, 0x00, 0x03, 0x00, 0x07, 0x03, 0x04, 0x07, 0x04, + 0x10, 0x0f, 0x0e, 0x02, 0x49, 0x59, 0x0b, 0x05, 0x0e, 0x0e, 0x04, 0x05, + 0x03, 0x00, 0x04, 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x12, 0x39, 0x2f, 0x12, + 0x39, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x12, 0x17, 0x39, 0x31, 0x30, 0x21, 0x03, 0x21, 0x03, 0x23, 0x01, 0x33, + 0x09, 0x01, 0x03, 0x26, 0x27, 0x06, 0x07, 0x03, 0x04, 0x60, 0xb6, 0xfd, + 0xb6, 0xb4, 0xac, 0x02, 0x42, 0x8f, 0x02, 0x3f, 0xfe, 0x65, 0xaa, 0x21, + 0x23, 0x16, 0x29, 0xac, 0x01, 0xd1, 0xfe, 0x2f, 0x05, 0xbc, 0xfa, 0x44, + 0x02, 0x6a, 0x01, 0xc5, 0x56, 0x7d, 0x60, 0x73, 0xfe, 0x3b, 0x00, 0x00, + 0x00, 0x03, 0x00, 0xc9, 0x00, 0x00, 0x04, 0xbe, 0x05, 0xb6, 0x00, 0x0e, + 0x00, 0x17, 0x00, 0x20, 0x00, 0x49, 0x40, 0x26, 0x13, 0x04, 0x1d, 0x0a, + 0x0f, 0x19, 0x19, 0x0e, 0x0a, 0x04, 0x07, 0x0e, 0x04, 0x21, 0x22, 0x08, + 0x0f, 0x18, 0x0f, 0x18, 0x4a, 0x59, 0x0f, 0x0f, 0x0e, 0x00, 0x0e, 0x19, + 0x4a, 0x59, 0x0e, 0x12, 0x00, 0x17, 0x4a, 0x59, 0x00, 0x03, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x21, 0x20, 0x04, 0x15, + 0x14, 0x06, 0x07, 0x15, 0x04, 0x11, 0x14, 0x04, 0x23, 0x21, 0x13, 0x21, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x19, 0x01, 0x21, 0x32, 0x36, + 0x35, 0x34, 0x26, 0x23, 0xc9, 0x01, 0x9d, 0x01, 0x23, 0x01, 0x04, 0x91, + 0x8b, 0x01, 0x4d, 0xfe, 0xf7, 0xee, 0xfe, 0x02, 0xaa, 0x01, 0x18, 0xb4, + 0x9e, 0xb0, 0xc0, 0xfa, 0x01, 0x31, 0xb1, 0xb3, 0xb7, 0xbb, 0x05, 0xb6, + 0xae, 0xbc, 0x82, 0xa9, 0x19, 0x0a, 0x39, 0xfe, 0xdb, 0xc4, 0xdc, 0x03, + 0x44, 0x71, 0x86, 0x7b, 0x6d, 0xfd, 0x91, 0xfd, 0xdd, 0x89, 0x92, 0x88, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x7d, 0xff, 0xec, 0x04, 0xcf, + 0x05, 0xcb, 0x00, 0x16, 0x00, 0x26, 0x40, 0x14, 0x03, 0x0e, 0x14, 0x09, + 0x0e, 0x03, 0x17, 0x18, 0x12, 0x00, 0x49, 0x59, 0x12, 0x04, 0x0b, 0x06, + 0x49, 0x59, 0x0b, 0x13, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x22, 0x00, 0x11, + 0x10, 0x00, 0x33, 0x32, 0x37, 0x15, 0x06, 0x23, 0x20, 0x00, 0x11, 0x34, + 0x12, 0x24, 0x33, 0x32, 0x17, 0x07, 0x26, 0x03, 0x3b, 0xf1, 0xfe, 0xe9, + 0x01, 0x0d, 0xf9, 0x99, 0xc4, 0x98, 0xdf, 0xfe, 0xbd, 0xfe, 0xa1, 0xa9, + 0x01, 0x3f, 0xd8, 0xe6, 0xac, 0x48, 0xa6, 0x05, 0x33, 0xfe, 0xbf, 0xfe, + 0xe9, 0xfe, 0xe1, 0xfe, 0xc7, 0x37, 0x95, 0x39, 0x01, 0x88, 0x01, 0x69, + 0xe2, 0x01, 0x54, 0xb8, 0x54, 0x92, 0x4e, 0x00, 0x00, 0x02, 0x00, 0xc9, + 0x00, 0x00, 0x05, 0x58, 0x05, 0xb6, 0x00, 0x08, 0x00, 0x11, 0x00, 0x28, + 0x40, 0x14, 0x0e, 0x04, 0x09, 0x00, 0x04, 0x00, 0x12, 0x13, 0x05, 0x0d, + 0x4a, 0x59, 0x05, 0x03, 0x04, 0x0e, 0x4a, 0x59, 0x04, 0x12, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x00, 0x29, 0x01, 0x11, 0x21, 0x20, + 0x00, 0x03, 0x10, 0x00, 0x21, 0x23, 0x11, 0x33, 0x20, 0x00, 0x05, 0x58, + 0xfe, 0x77, 0xfe, 0x8f, 0xfe, 0x6b, 0x01, 0xc0, 0x01, 0x55, 0x01, 0x7a, + 0xb4, 0xfe, 0xe1, 0xfe, 0xe5, 0xf7, 0xcf, 0x01, 0x30, 0x01, 0x32, 0x02, + 0xe9, 0xfe, 0x96, 0xfe, 0x81, 0x05, 0xb6, 0xfe, 0x86, 0xfe, 0xa7, 0x01, + 0x1e, 0x01, 0x22, 0xfb, 0x70, 0x01, 0x2b, 0x00, 0x00, 0x01, 0x00, 0xc9, + 0x00, 0x00, 0x03, 0xf8, 0x05, 0xb6, 0x00, 0x0b, 0x00, 0x3a, 0x40, 0x1f, + 0x06, 0x0a, 0x0a, 0x01, 0x04, 0x00, 0x08, 0x01, 0x04, 0x0c, 0x0d, 0x06, + 0x09, 0x49, 0x59, 0x06, 0x06, 0x01, 0x02, 0x02, 0x05, 0x49, 0x59, 0x02, + 0x03, 0x01, 0x0a, 0x49, 0x59, 0x01, 0x12, 0x00, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x01, + 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x21, + 0x15, 0x21, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x03, 0xf8, 0xfc, 0xd1, + 0x03, 0x2f, 0xfd, 0x7b, 0x02, 0x5e, 0xfd, 0xa2, 0x02, 0x85, 0x05, 0xb6, + 0x97, 0xfe, 0x29, 0x96, 0xfd, 0xe6, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc9, + 0x00, 0x00, 0x03, 0xf8, 0x05, 0xb6, 0x00, 0x09, 0x00, 0x32, 0x40, 0x1a, + 0x06, 0x00, 0x00, 0x01, 0x03, 0x08, 0x01, 0x03, 0x0a, 0x0b, 0x06, 0x09, + 0x49, 0x59, 0x06, 0x06, 0x01, 0x02, 0x02, 0x05, 0x49, 0x59, 0x02, 0x03, + 0x01, 0x12, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, + 0x2b, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x21, 0x23, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x15, 0x21, 0x01, 0x73, + 0xaa, 0x03, 0x2f, 0xfd, 0x7b, 0x02, 0x5e, 0xfd, 0xa2, 0x05, 0xb6, 0x97, + 0xfd, 0xe9, 0x97, 0x00, 0x00, 0x01, 0x00, 0x7d, 0xff, 0xec, 0x05, 0x3d, + 0x05, 0xcb, 0x00, 0x1b, 0x00, 0x3a, 0x40, 0x1f, 0x14, 0x08, 0x19, 0x02, + 0x02, 0x0e, 0x1b, 0x08, 0x04, 0x1c, 0x1d, 0x00, 0x1b, 0x49, 0x59, 0x00, + 0x00, 0x05, 0x0c, 0x0c, 0x11, 0x49, 0x59, 0x0c, 0x04, 0x05, 0x17, 0x49, + 0x59, 0x05, 0x13, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x21, 0x11, 0x0e, 0x01, 0x23, 0x20, 0x00, + 0x11, 0x34, 0x12, 0x24, 0x33, 0x32, 0x17, 0x07, 0x26, 0x23, 0x20, 0x00, + 0x11, 0x10, 0x00, 0x21, 0x32, 0x37, 0x11, 0x21, 0x03, 0x4c, 0x01, 0xf1, + 0x74, 0xf0, 0x9e, 0xfe, 0xb4, 0xfe, 0x8e, 0xb7, 0x01, 0x58, 0xe7, 0xea, + 0xca, 0x42, 0xc6, 0xb7, 0xfe, 0xf5, 0xfe, 0xd4, 0x01, 0x21, 0x01, 0x18, + 0x98, 0x91, 0xfe, 0xb9, 0x02, 0xfe, 0xfd, 0x39, 0x25, 0x26, 0x01, 0x8b, + 0x01, 0x64, 0xe4, 0x01, 0x57, 0xb5, 0x56, 0x96, 0x54, 0xfe, 0xc2, 0xfe, + 0xe6, 0xfe, 0xd8, 0xfe, 0xce, 0x23, 0x01, 0xc2, 0x00, 0x01, 0x00, 0xc9, + 0x00, 0x00, 0x05, 0x1f, 0x05, 0xb6, 0x00, 0x0b, 0x00, 0x33, 0x40, 0x19, + 0x09, 0x01, 0x01, 0x00, 0x08, 0x04, 0x04, 0x05, 0x00, 0x05, 0x0d, 0x0c, + 0x08, 0x03, 0x49, 0x59, 0x08, 0x08, 0x05, 0x0a, 0x06, 0x03, 0x01, 0x05, + 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, 0x2f, 0x2b, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x21, 0x23, 0x11, 0x21, 0x11, 0x23, 0x11, 0x33, 0x11, 0x21, 0x11, + 0x33, 0x05, 0x1f, 0xaa, 0xfc, 0xfe, 0xaa, 0xaa, 0x03, 0x02, 0xaa, 0x02, + 0xb0, 0xfd, 0x50, 0x05, 0xb6, 0xfd, 0x92, 0x02, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xc9, 0x00, 0x00, 0x01, 0x73, 0x05, 0xb6, 0x00, 0x03, + 0x00, 0x11, 0xb6, 0x00, 0x04, 0x05, 0x01, 0x03, 0x00, 0x12, 0x00, 0x3f, + 0x3f, 0x11, 0x12, 0x01, 0x39, 0x31, 0x30, 0x33, 0x11, 0x33, 0x11, 0xc9, + 0xaa, 0x05, 0xb6, 0xfa, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x60, + 0xfe, 0x7f, 0x01, 0x68, 0x05, 0xb6, 0x00, 0x0d, 0x00, 0x1d, 0x40, 0x0d, + 0x0b, 0x08, 0x08, 0x0e, 0x0f, 0x09, 0x03, 0x00, 0x05, 0x49, 0x59, 0x00, + 0x22, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x11, 0x12, 0x01, 0x39, 0x11, + 0x33, 0x31, 0x30, 0x03, 0x22, 0x27, 0x35, 0x16, 0x33, 0x32, 0x36, 0x35, + 0x11, 0x33, 0x11, 0x14, 0x06, 0x0c, 0x5e, 0x36, 0x47, 0x4d, 0x63, 0x67, + 0xaa, 0xc0, 0xfe, 0x7f, 0x1b, 0x91, 0x14, 0x78, 0x71, 0x05, 0xb6, 0xfa, + 0x58, 0xbe, 0xd1, 0x00, 0x00, 0x01, 0x00, 0xc9, 0x00, 0x00, 0x04, 0xe9, + 0x05, 0xb6, 0x00, 0x0b, 0x00, 0x2a, 0x40, 0x15, 0x08, 0x04, 0x04, 0x05, + 0x05, 0x02, 0x0b, 0x0a, 0x00, 0x05, 0x0d, 0x0c, 0x02, 0x08, 0x05, 0x09, + 0x06, 0x03, 0x01, 0x05, 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, + 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x21, 0x23, 0x01, 0x07, 0x11, 0x23, 0x11, 0x33, 0x11, 0x01, 0x33, 0x01, + 0x04, 0xe9, 0xc8, 0xfd, 0xeb, 0x99, 0xaa, 0xaa, 0x02, 0x97, 0xc9, 0xfd, + 0xb4, 0x02, 0xc5, 0x88, 0xfd, 0xc3, 0x05, 0xb6, 0xfd, 0x2b, 0x02, 0xd5, + 0xfd, 0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc9, 0x00, 0x00, 0x03, 0xf8, + 0x05, 0xb6, 0x00, 0x05, 0x00, 0x1f, 0x40, 0x0e, 0x03, 0x00, 0x00, 0x04, + 0x06, 0x07, 0x01, 0x03, 0x00, 0x03, 0x49, 0x59, 0x00, 0x12, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x31, + 0x30, 0x33, 0x11, 0x33, 0x11, 0x21, 0x15, 0xc9, 0xaa, 0x02, 0x85, 0x05, + 0xb6, 0xfa, 0xe4, 0x9a, 0x00, 0x01, 0x00, 0xc9, 0x00, 0x00, 0x06, 0x71, + 0x05, 0xb6, 0x00, 0x13, 0x00, 0x32, 0x40, 0x18, 0x08, 0x05, 0x05, 0x06, + 0x0b, 0x0e, 0x0e, 0x0d, 0x06, 0x0d, 0x14, 0x15, 0x01, 0x0a, 0x11, 0x03, + 0x06, 0x0b, 0x07, 0x03, 0x0e, 0x00, 0x06, 0x12, 0x00, 0x3f, 0x33, 0x33, + 0x3f, 0x33, 0x12, 0x17, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x21, 0x01, 0x23, 0x16, + 0x15, 0x11, 0x23, 0x11, 0x21, 0x01, 0x33, 0x01, 0x33, 0x11, 0x23, 0x11, + 0x34, 0x37, 0x23, 0x01, 0x03, 0x50, 0xfe, 0x10, 0x08, 0x0e, 0x9d, 0x01, + 0x00, 0x01, 0xcf, 0x08, 0x01, 0xd3, 0xfe, 0xaa, 0x0e, 0x08, 0xfe, 0x0c, + 0x05, 0x10, 0x9a, 0xd4, 0xfc, 0x5e, 0x05, 0xb6, 0xfb, 0x4a, 0x04, 0xb6, + 0xfa, 0x4a, 0x03, 0xae, 0xa2, 0xbe, 0xfa, 0xf2, 0x00, 0x01, 0x00, 0xc9, + 0x00, 0x00, 0x05, 0x3f, 0x05, 0xb6, 0x00, 0x10, 0x00, 0x2e, 0x40, 0x15, + 0x09, 0x06, 0x06, 0x07, 0x01, 0x0f, 0x0f, 0x00, 0x07, 0x00, 0x11, 0x12, + 0x0b, 0x03, 0x07, 0x0f, 0x08, 0x03, 0x01, 0x07, 0x12, 0x00, 0x3f, 0x33, + 0x3f, 0x33, 0x12, 0x39, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x21, 0x23, 0x01, 0x23, + 0x16, 0x15, 0x11, 0x23, 0x11, 0x33, 0x01, 0x33, 0x26, 0x02, 0x37, 0x11, + 0x33, 0x05, 0x3f, 0xc2, 0xfc, 0xe1, 0x08, 0x10, 0x9d, 0xc0, 0x03, 0x1d, + 0x08, 0x02, 0x0e, 0x02, 0x9f, 0x04, 0xcb, 0xd8, 0xb4, 0xfc, 0xc1, 0x05, + 0xb6, 0xfb, 0x3a, 0x1b, 0x01, 0x25, 0x3f, 0x03, 0x47, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x7d, 0xff, 0xec, 0x05, 0xbe, 0x05, 0xcd, 0x00, 0x0b, + 0x00, 0x17, 0x00, 0x28, 0x40, 0x14, 0x12, 0x00, 0x0c, 0x06, 0x00, 0x06, + 0x19, 0x18, 0x09, 0x15, 0x49, 0x59, 0x09, 0x04, 0x03, 0x0f, 0x49, 0x59, + 0x03, 0x13, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x01, + 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x00, 0x21, + 0x20, 0x00, 0x11, 0x10, 0x00, 0x21, 0x20, 0x00, 0x01, 0x10, 0x12, 0x33, + 0x32, 0x12, 0x11, 0x10, 0x02, 0x23, 0x22, 0x02, 0x05, 0xbe, 0xfe, 0x9d, + 0xfe, 0xc4, 0xfe, 0xbd, 0xfe, 0xa1, 0x01, 0x60, 0x01, 0x44, 0x01, 0x3b, + 0x01, 0x62, 0xfb, 0x73, 0xfd, 0xf1, 0xf3, 0xf8, 0xf7, 0xf2, 0xf3, 0xfd, + 0x02, 0xdd, 0xfe, 0xa1, 0xfe, 0x6e, 0x01, 0x8b, 0x01, 0x68, 0x01, 0x65, + 0x01, 0x89, 0xfe, 0x70, 0xfe, 0xa0, 0xfe, 0xd7, 0xfe, 0xcd, 0x01, 0x32, + 0x01, 0x2a, 0x01, 0x27, 0x01, 0x31, 0xfe, 0xcd, 0x00, 0x02, 0x00, 0xc9, + 0x00, 0x00, 0x04, 0x68, 0x05, 0xb6, 0x00, 0x09, 0x00, 0x12, 0x00, 0x34, + 0x40, 0x1a, 0x0a, 0x05, 0x05, 0x06, 0x0e, 0x00, 0x06, 0x00, 0x13, 0x14, + 0x0a, 0x04, 0x4a, 0x59, 0x0a, 0x0a, 0x06, 0x07, 0x07, 0x12, 0x4a, 0x59, + 0x07, 0x03, 0x06, 0x12, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, + 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x04, 0x21, 0x23, 0x11, 0x23, 0x11, + 0x21, 0x20, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x04, + 0x68, 0xfe, 0xd1, 0xfe, 0xe6, 0xac, 0xaa, 0x01, 0x7b, 0x02, 0x24, 0xfd, + 0x0b, 0x99, 0xe2, 0xca, 0xbe, 0xc9, 0xbe, 0x04, 0x0c, 0xde, 0xef, 0xfd, + 0xc1, 0x05, 0xb6, 0xfd, 0x1b, 0x92, 0xa1, 0x91, 0x8e, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x7d, 0xfe, 0xa4, 0x05, 0xbe, 0x05, 0xcd, 0x00, 0x0f, + 0x00, 0x1b, 0x00, 0x34, 0x40, 0x1b, 0x10, 0x0a, 0x16, 0x00, 0x00, 0x04, + 0x03, 0x0a, 0x04, 0x1c, 0x1d, 0x03, 0x0d, 0x07, 0x0d, 0x19, 0x49, 0x59, + 0x0d, 0x04, 0x07, 0x13, 0x49, 0x59, 0x05, 0x07, 0x13, 0x00, 0x3f, 0xc6, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, 0x12, 0x01, + 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x02, 0x07, + 0x01, 0x23, 0x01, 0x07, 0x20, 0x00, 0x11, 0x10, 0x00, 0x21, 0x20, 0x00, + 0x01, 0x10, 0x12, 0x33, 0x32, 0x12, 0x11, 0x10, 0x02, 0x23, 0x22, 0x02, + 0x05, 0xbe, 0xe2, 0xce, 0x01, 0x5c, 0xf7, 0xfe, 0xe3, 0x37, 0xfe, 0xbd, + 0xfe, 0xa1, 0x01, 0x60, 0x01, 0x44, 0x01, 0x3b, 0x01, 0x62, 0xfb, 0x73, + 0xfd, 0xf1, 0xf3, 0xf8, 0xf7, 0xf2, 0xf3, 0xfd, 0x02, 0xdd, 0xfe, 0xe7, + 0xfe, 0x8c, 0x42, 0xfe, 0x96, 0x01, 0x4a, 0x02, 0x01, 0x8b, 0x01, 0x68, + 0x01, 0x65, 0x01, 0x89, 0xfe, 0x70, 0xfe, 0xa0, 0xfe, 0xd7, 0xfe, 0xcd, + 0x01, 0x32, 0x01, 0x2a, 0x01, 0x27, 0x01, 0x31, 0xfe, 0xcd, 0x00, 0x00, + 0x00, 0x02, 0x00, 0xc9, 0x00, 0x00, 0x04, 0xcf, 0x05, 0xb6, 0x00, 0x0c, + 0x00, 0x15, 0x00, 0x48, 0x40, 0x25, 0x0d, 0x01, 0x01, 0x02, 0x0c, 0x09, + 0x11, 0x07, 0x0b, 0x0a, 0x0a, 0x07, 0x09, 0x02, 0x04, 0x16, 0x17, 0x09, + 0x0d, 0x00, 0x0d, 0x00, 0x4a, 0x59, 0x0d, 0x0d, 0x02, 0x03, 0x03, 0x15, + 0x49, 0x59, 0x03, 0x03, 0x0b, 0x02, 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, + 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x11, 0x23, 0x11, 0x21, 0x20, 0x04, 0x15, + 0x10, 0x05, 0x01, 0x23, 0x01, 0x25, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, + 0x2b, 0x01, 0x01, 0x73, 0xaa, 0x01, 0x91, 0x01, 0x0d, 0x01, 0x01, 0xfe, + 0xda, 0x01, 0x8d, 0xc9, 0xfe, 0x9e, 0xfe, 0xcf, 0xe9, 0xb4, 0xa8, 0xab, + 0xbd, 0xdd, 0x02, 0x60, 0xfd, 0xa0, 0x05, 0xb6, 0xce, 0xcf, 0xfe, 0xde, + 0x66, 0xfd, 0x6f, 0x02, 0x60, 0x92, 0x8f, 0x8f, 0x91, 0x80, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x6a, 0xff, 0xec, 0x04, 0x02, 0x05, 0xcb, 0x00, 0x24, + 0x00, 0x34, 0x40, 0x1b, 0x1e, 0x13, 0x0c, 0x00, 0x00, 0x18, 0x13, 0x05, + 0x04, 0x25, 0x26, 0x0c, 0x1e, 0x03, 0x16, 0x16, 0x1b, 0x49, 0x59, 0x16, + 0x04, 0x03, 0x09, 0x49, 0x59, 0x03, 0x13, 0x00, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x04, 0x23, 0x20, 0x27, + 0x35, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x2e, 0x01, 0x27, 0x2e, + 0x01, 0x35, 0x34, 0x36, 0x33, 0x32, 0x17, 0x07, 0x26, 0x23, 0x22, 0x06, + 0x15, 0x14, 0x1e, 0x01, 0x17, 0x1e, 0x01, 0x04, 0x02, 0xfe, 0xe8, 0xf0, + 0xfe, 0xfc, 0x8c, 0x5a, 0xd4, 0x68, 0xaa, 0xac, 0x3d, 0x8f, 0x92, 0xcc, + 0xaf, 0xfe, 0xd1, 0xda, 0xb7, 0x35, 0xb5, 0xab, 0x87, 0x98, 0x38, 0x85, + 0x89, 0xe6, 0xad, 0x01, 0x85, 0xc1, 0xd8, 0x43, 0xa4, 0x26, 0x2c, 0x81, + 0x73, 0x4c, 0x61, 0x52, 0x34, 0x49, 0xc8, 0xa1, 0xa9, 0xc8, 0x50, 0x94, + 0x4c, 0x74, 0x67, 0x4c, 0x61, 0x51, 0x31, 0x52, 0xbc, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x04, 0x5a, 0x05, 0xb6, 0x00, 0x07, + 0x00, 0x24, 0x40, 0x12, 0x00, 0x01, 0x05, 0x01, 0x03, 0x03, 0x08, 0x09, + 0x07, 0x03, 0x04, 0x03, 0x49, 0x59, 0x04, 0x03, 0x01, 0x12, 0x00, 0x3f, + 0x3f, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, + 0x31, 0x30, 0x21, 0x23, 0x11, 0x21, 0x35, 0x21, 0x15, 0x21, 0x02, 0x8b, + 0xaa, 0xfe, 0x31, 0x04, 0x48, 0xfe, 0x31, 0x05, 0x1f, 0x97, 0x97, 0x00, + 0x00, 0x01, 0x00, 0xba, 0xff, 0xec, 0x05, 0x19, 0x05, 0xb6, 0x00, 0x11, + 0x00, 0x25, 0x40, 0x11, 0x10, 0x01, 0x0a, 0x07, 0x01, 0x07, 0x13, 0x12, + 0x11, 0x08, 0x03, 0x04, 0x0d, 0x49, 0x59, 0x04, 0x13, 0x00, 0x3f, 0x2b, + 0x00, 0x18, 0x3f, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x11, 0x14, 0x00, 0x21, 0x20, 0x00, 0x35, 0x11, + 0x33, 0x11, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x11, 0x05, 0x19, 0xfe, + 0xd2, 0xfe, 0xf8, 0xfe, 0xf8, 0xfe, 0xdf, 0xaa, 0xc8, 0xc2, 0xb9, 0xc8, + 0x05, 0xb6, 0xfc, 0x4e, 0xfa, 0xfe, 0xe2, 0x01, 0x20, 0xfc, 0x03, 0xae, + 0xfc, 0x46, 0xb7, 0xc4, 0xc5, 0xb8, 0x03, 0xb8, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xc3, 0x05, 0xb6, 0x00, 0x0a, 0x00, 0x1a, 0x40, 0x0b, + 0x01, 0x04, 0x0c, 0x0b, 0x08, 0x03, 0x00, 0x04, 0x03, 0x03, 0x12, 0x00, + 0x3f, 0x3f, 0x33, 0x12, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, 0x31, 0x30, + 0x01, 0x33, 0x01, 0x23, 0x01, 0x33, 0x01, 0x16, 0x17, 0x36, 0x37, 0x04, + 0x0c, 0xb7, 0xfd, 0xf1, 0xa8, 0xfd, 0xf4, 0xb4, 0x01, 0x50, 0x3a, 0x22, + 0x24, 0x3a, 0x05, 0xb6, 0xfa, 0x4a, 0x05, 0xb6, 0xfc, 0x4e, 0xa3, 0x9a, + 0xa2, 0xa1, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x07, 0x4c, + 0x05, 0xb6, 0x00, 0x19, 0x00, 0x24, 0x40, 0x10, 0x19, 0x0a, 0x1b, 0x1a, + 0x15, 0x0e, 0x0e, 0x05, 0x09, 0x18, 0x11, 0x0a, 0x03, 0x01, 0x09, 0x12, + 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x33, 0x12, 0x39, 0x39, 0x11, 0x33, 0x11, + 0x12, 0x01, 0x39, 0x39, 0x31, 0x30, 0x21, 0x23, 0x01, 0x2e, 0x01, 0x27, + 0x06, 0x07, 0x01, 0x23, 0x01, 0x33, 0x13, 0x16, 0x17, 0x36, 0x37, 0x01, + 0x33, 0x01, 0x16, 0x17, 0x36, 0x37, 0x13, 0x33, 0x05, 0xc5, 0xa8, 0xfe, + 0xd9, 0x15, 0x34, 0x01, 0x16, 0x30, 0xfe, 0xe2, 0xa8, 0xfe, 0x7b, 0xb4, + 0xe7, 0x30, 0x16, 0x1b, 0x35, 0x01, 0x06, 0xb4, 0x01, 0x13, 0x30, 0x21, + 0x13, 0x35, 0xe6, 0xb4, 0x03, 0xd3, 0x41, 0xc6, 0x14, 0x84, 0x9d, 0xfc, + 0x33, 0x05, 0xb6, 0xfc, 0x79, 0xbe, 0x9a, 0xb7, 0xaf, 0x03, 0x79, 0xfc, + 0x7f, 0x9b, 0xc3, 0x8e, 0xcc, 0x03, 0x85, 0x00, 0x00, 0x01, 0x00, 0x08, + 0x00, 0x00, 0x04, 0x96, 0x05, 0xb6, 0x00, 0x0b, 0x00, 0x23, 0x40, 0x12, + 0x04, 0x06, 0x05, 0x0b, 0x0a, 0x00, 0x06, 0x0d, 0x0c, 0x02, 0x08, 0x04, + 0x09, 0x06, 0x03, 0x01, 0x04, 0x12, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, + 0x39, 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x31, 0x30, 0x21, 0x23, 0x09, + 0x01, 0x23, 0x09, 0x01, 0x33, 0x09, 0x01, 0x33, 0x01, 0x04, 0x96, 0xc1, + 0xfe, 0x77, 0xfe, 0x70, 0xb4, 0x01, 0xe6, 0xfe, 0x3b, 0xbc, 0x01, 0x6b, + 0x01, 0x6e, 0xb5, 0xfe, 0x3b, 0x02, 0x83, 0xfd, 0x7d, 0x02, 0xfc, 0x02, + 0xba, 0xfd, 0xbd, 0x02, 0x43, 0xfd, 0x4c, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x7b, 0x05, 0xb6, 0x00, 0x08, 0x00, 0x20, 0x40, 0x0f, + 0x04, 0x05, 0x02, 0x05, 0x07, 0x03, 0x09, 0x0a, 0x00, 0x05, 0x01, 0x07, + 0x03, 0x05, 0x12, 0x00, 0x3f, 0x3f, 0x33, 0x12, 0x39, 0x11, 0x12, 0x01, + 0x17, 0x39, 0x11, 0x33, 0x31, 0x30, 0x09, 0x01, 0x33, 0x01, 0x11, 0x23, + 0x11, 0x01, 0x33, 0x02, 0x3d, 0x01, 0x86, 0xb8, 0xfe, 0x18, 0xac, 0xfe, + 0x19, 0xba, 0x02, 0xdb, 0x02, 0xdb, 0xfc, 0x81, 0xfd, 0xc9, 0x02, 0x2f, + 0x03, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00, 0x52, 0x00, 0x00, 0x04, 0x3f, + 0x05, 0xb6, 0x00, 0x09, 0x00, 0x2b, 0x40, 0x17, 0x08, 0x01, 0x03, 0x07, + 0x00, 0x07, 0x04, 0x01, 0x04, 0x0a, 0x0b, 0x05, 0x04, 0x49, 0x59, 0x05, + 0x03, 0x01, 0x08, 0x49, 0x59, 0x01, 0x12, 0x00, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x29, 0x01, 0x35, 0x01, 0x21, 0x35, 0x21, 0x15, 0x01, 0x21, 0x04, + 0x3f, 0xfc, 0x13, 0x03, 0x08, 0xfd, 0x10, 0x03, 0xbf, 0xfc, 0xf8, 0x03, + 0x1e, 0x85, 0x04, 0x98, 0x99, 0x85, 0xfb, 0x69, 0x00, 0x01, 0x00, 0xa6, + 0xfe, 0xbc, 0x02, 0x6f, 0x05, 0xb6, 0x00, 0x07, 0x00, 0x20, 0x40, 0x0e, + 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x08, 0x09, 0x05, 0x02, 0x03, 0x06, + 0x01, 0x27, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x21, 0x11, 0x21, 0x15, 0x21, + 0x11, 0x21, 0x02, 0x6f, 0xfe, 0x37, 0x01, 0xc9, 0xfe, 0xdf, 0x01, 0x21, + 0xfe, 0xbc, 0x06, 0xfa, 0x8d, 0xfa, 0x21, 0x00, 0x00, 0x01, 0x00, 0x17, + 0x00, 0x00, 0x02, 0xdd, 0x05, 0xb6, 0x00, 0x03, 0x00, 0x13, 0xb7, 0x03, + 0x01, 0x04, 0x05, 0x03, 0x03, 0x02, 0x12, 0x00, 0x3f, 0x3f, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x31, 0x30, 0x13, 0x01, 0x23, 0x01, 0xba, 0x02, 0x23, + 0xa6, 0xfd, 0xe0, 0x05, 0xb6, 0xfa, 0x4a, 0x05, 0xb6, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x33, 0xfe, 0xbc, 0x01, 0xfc, 0x05, 0xb6, 0x00, 0x07, + 0x00, 0x20, 0x40, 0x0e, 0x03, 0x00, 0x01, 0x06, 0x00, 0x06, 0x08, 0x09, + 0x00, 0x07, 0x27, 0x03, 0x04, 0x03, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x11, + 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x17, 0x21, + 0x11, 0x21, 0x35, 0x21, 0x11, 0x21, 0x33, 0x01, 0x21, 0xfe, 0xdf, 0x01, + 0xc9, 0xfe, 0x37, 0xb6, 0x05, 0xdf, 0x8d, 0xf9, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x31, 0x02, 0x27, 0x04, 0x23, 0x05, 0xc1, 0x00, 0x06, + 0x00, 0x18, 0x40, 0x09, 0x00, 0x03, 0x07, 0x08, 0x05, 0x02, 0x00, 0x04, + 0x02, 0x00, 0x2f, 0x2f, 0x33, 0x12, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x31, 0x30, 0x13, 0x01, 0x33, 0x01, 0x23, 0x09, 0x01, 0x31, 0x01, 0xb2, + 0x63, 0x01, 0xdd, 0x98, 0xfe, 0x8c, 0xfe, 0xb2, 0x02, 0x27, 0x03, 0x9a, + 0xfc, 0x66, 0x02, 0xe9, 0xfd, 0x17, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfc, + 0xfe, 0xc5, 0x03, 0x9a, 0xff, 0x48, 0x00, 0x03, 0x00, 0x11, 0xb5, 0x00, + 0x05, 0x01, 0x04, 0x01, 0x02, 0x00, 0x2f, 0x33, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x21, 0x35, 0x21, 0x03, 0x9a, 0xfc, 0x62, 0x03, + 0x9e, 0xfe, 0xc5, 0x83, 0x00, 0x01, 0x01, 0x89, 0x04, 0xd9, 0x03, 0x12, + 0x06, 0x21, 0x00, 0x09, 0x00, 0x13, 0xb6, 0x00, 0x04, 0x0b, 0x0a, 0x06, + 0x80, 0x01, 0x00, 0x2f, 0x1a, 0xcd, 0x11, 0x12, 0x01, 0x39, 0x39, 0x31, + 0x30, 0x01, 0x23, 0x2e, 0x01, 0x27, 0x35, 0x33, 0x1e, 0x01, 0x17, 0x03, + 0x12, 0x6e, 0x41, 0xb2, 0x28, 0xcb, 0x20, 0x72, 0x2c, 0x04, 0xd9, 0x34, + 0xc0, 0x3f, 0x15, 0x45, 0xb5, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e, + 0xff, 0xec, 0x03, 0xcd, 0x04, 0x5a, 0x00, 0x19, 0x00, 0x24, 0x00, 0x47, + 0x40, 0x25, 0x22, 0x08, 0x0b, 0x1e, 0x1e, 0x19, 0x19, 0x12, 0x08, 0x03, + 0x25, 0x26, 0x01, 0x02, 0x0b, 0x1e, 0x47, 0x59, 0x02, 0x0b, 0x0b, 0x00, + 0x15, 0x15, 0x0f, 0x46, 0x59, 0x15, 0x10, 0x05, 0x1a, 0x46, 0x59, 0x05, + 0x16, 0x00, 0x15, 0x00, 0x3f, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x18, 0x2f, 0x39, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, + 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x21, + 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x10, 0x25, 0x37, 0x35, + 0x34, 0x26, 0x23, 0x22, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, + 0x11, 0x25, 0x32, 0x36, 0x3d, 0x01, 0x07, 0x0e, 0x01, 0x15, 0x14, 0x16, + 0x03, 0x52, 0x21, 0x08, 0x52, 0xa3, 0x7a, 0xa3, 0xb9, 0x02, 0x13, 0xba, + 0x6f, 0x7a, 0x89, 0xad, 0x33, 0x51, 0xc1, 0x61, 0xc4, 0xbd, 0xfe, 0x0e, + 0x9b, 0xb1, 0xa6, 0xc6, 0xaf, 0x6d, 0x9c, 0x67, 0x49, 0xa8, 0x9b, 0x01, + 0x4c, 0x10, 0x06, 0x44, 0x81, 0x7b, 0x54, 0x7f, 0x2c, 0x32, 0xae, 0xc0, + 0xfd, 0x14, 0x75, 0xaa, 0x99, 0x63, 0x07, 0x07, 0x6d, 0x73, 0x5a, 0x5e, + 0x00, 0x02, 0x00, 0xb0, 0xff, 0xec, 0x04, 0x75, 0x06, 0x14, 0x00, 0x13, + 0x00, 0x1f, 0x00, 0x44, 0x40, 0x22, 0x0a, 0x17, 0x17, 0x0f, 0x0f, 0x0c, + 0x1d, 0x03, 0x0c, 0x03, 0x20, 0x21, 0x0d, 0x00, 0x0c, 0x15, 0x12, 0x11, + 0x0a, 0x11, 0x06, 0x00, 0x06, 0x1a, 0x46, 0x59, 0x06, 0x16, 0x00, 0x14, + 0x46, 0x59, 0x00, 0x10, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x39, 0x11, 0x33, 0x18, 0x3f, 0x3f, 0x11, 0x12, 0x01, + 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x01, 0x32, 0x12, 0x11, 0x10, 0x02, 0x23, 0x22, 0x26, 0x27, 0x23, 0x07, + 0x23, 0x11, 0x33, 0x11, 0x14, 0x07, 0x33, 0x36, 0x17, 0x22, 0x06, 0x15, + 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x02, 0xae, 0xd8, 0xef, + 0xf1, 0xd6, 0x6b, 0xb1, 0x3c, 0x0c, 0x23, 0x77, 0xa6, 0x08, 0x08, 0x74, + 0xcc, 0xaa, 0x96, 0x9a, 0xaa, 0x99, 0x96, 0x96, 0x04, 0x5a, 0xfe, 0xd9, + 0xfe, 0xf2, 0xfe, 0xf2, 0xfe, 0xd5, 0x4f, 0x52, 0x8d, 0x06, 0x14, 0xfe, + 0x86, 0x7f, 0x65, 0xa4, 0x8b, 0xc3, 0xe7, 0xe7, 0xc7, 0xdf, 0xd1, 0xd6, + 0xd2, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x73, 0xff, 0xec, 0x03, 0x8b, + 0x04, 0x5c, 0x00, 0x16, 0x00, 0x26, 0x40, 0x14, 0x0f, 0x03, 0x03, 0x15, + 0x09, 0x03, 0x18, 0x17, 0x06, 0x0d, 0x46, 0x59, 0x06, 0x10, 0x00, 0x12, + 0x46, 0x59, 0x00, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x31, 0x30, 0x05, 0x22, 0x00, 0x11, + 0x10, 0x00, 0x33, 0x32, 0x16, 0x17, 0x07, 0x2e, 0x01, 0x23, 0x20, 0x11, + 0x14, 0x16, 0x33, 0x32, 0x37, 0x15, 0x06, 0x02, 0x66, 0xee, 0xfe, 0xfb, + 0x01, 0x09, 0xf5, 0x4f, 0x9e, 0x2d, 0x33, 0x37, 0x82, 0x32, 0xfe, 0xb2, + 0xa3, 0xa0, 0x89, 0x90, 0x6e, 0x14, 0x01, 0x25, 0x01, 0x0c, 0x01, 0x13, + 0x01, 0x2c, 0x22, 0x17, 0x8d, 0x16, 0x1d, 0xfe, 0x56, 0xca, 0xd8, 0x3b, + 0x93, 0x39, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0xff, 0xec, 0x04, 0x37, + 0x06, 0x14, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x42, 0x40, 0x21, 0x1d, 0x06, + 0x17, 0x00, 0x0e, 0x0e, 0x11, 0x06, 0x11, 0x20, 0x21, 0x12, 0x15, 0x0f, + 0x00, 0x00, 0x01, 0x01, 0x0c, 0x03, 0x09, 0x09, 0x1a, 0x46, 0x59, 0x09, + 0x10, 0x03, 0x13, 0x46, 0x59, 0x03, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x11, 0x33, 0x18, 0x3f, 0x3f, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, + 0x31, 0x30, 0x25, 0x23, 0x06, 0x23, 0x22, 0x02, 0x11, 0x10, 0x12, 0x33, + 0x32, 0x17, 0x33, 0x2f, 0x01, 0x11, 0x33, 0x11, 0x23, 0x25, 0x32, 0x36, + 0x3d, 0x01, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x03, 0x9a, + 0x09, 0x73, 0xe5, 0xd7, 0xef, 0xf0, 0xd6, 0xdf, 0x77, 0x0d, 0x07, 0x04, + 0xa6, 0x87, 0xfe, 0x9e, 0xaa, 0x99, 0x9b, 0xaa, 0x92, 0x9b, 0x9a, 0x93, + 0xa7, 0x01, 0x26, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x2c, 0xa2, 0x4f, 0x4d, + 0x01, 0xbe, 0xf9, 0xec, 0x77, 0xb9, 0xce, 0x23, 0xe9, 0xc7, 0xe3, 0xcf, + 0xd2, 0xd6, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0xff, 0xec, 0x04, 0x12, + 0x04, 0x5c, 0x00, 0x13, 0x00, 0x1a, 0x00, 0x3b, 0x40, 0x1f, 0x18, 0x0a, + 0x17, 0x0b, 0x03, 0x03, 0x11, 0x0a, 0x03, 0x1c, 0x1b, 0x17, 0x0b, 0x46, + 0x59, 0x17, 0x17, 0x00, 0x06, 0x06, 0x14, 0x46, 0x59, 0x06, 0x10, 0x00, + 0x0e, 0x46, 0x59, 0x00, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x2b, 0x11, 0x12, 0x01, 0x17, 0x39, + 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x05, 0x22, 0x00, 0x11, 0x10, + 0x00, 0x33, 0x32, 0x12, 0x1d, 0x01, 0x21, 0x1e, 0x01, 0x33, 0x32, 0x37, + 0x15, 0x0e, 0x01, 0x03, 0x22, 0x06, 0x07, 0x21, 0x34, 0x26, 0x02, 0x7f, + 0xf3, 0xfe, 0xe7, 0x01, 0x05, 0xdc, 0xce, 0xf0, 0xfd, 0x0d, 0x05, 0xb9, + 0xa8, 0xb1, 0xad, 0x58, 0x9d, 0x9c, 0x84, 0x9d, 0x0e, 0x02, 0x3d, 0x8c, + 0x14, 0x01, 0x28, 0x01, 0x07, 0x01, 0x09, 0x01, 0x38, 0xfe, 0xf1, 0xde, + 0x69, 0xc1, 0xc8, 0x4a, 0x94, 0x26, 0x21, 0x03, 0xe5, 0xac, 0x98, 0x9d, + 0xa7, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x03, 0x0e, + 0x06, 0x1f, 0x00, 0x14, 0x00, 0x39, 0x40, 0x1d, 0x14, 0x0c, 0x0c, 0x13, + 0x02, 0x02, 0x07, 0x03, 0x05, 0x03, 0x15, 0x16, 0x0a, 0x0f, 0x46, 0x59, + 0x0a, 0x00, 0x01, 0x05, 0x07, 0x05, 0x46, 0x59, 0x13, 0x07, 0x0f, 0x03, + 0x15, 0x00, 0x3f, 0x3f, 0x33, 0x2b, 0x11, 0x00, 0x33, 0x18, 0x3f, 0x2b, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x33, 0x12, + 0x39, 0x31, 0x30, 0x01, 0x21, 0x11, 0x23, 0x11, 0x23, 0x35, 0x37, 0x35, + 0x10, 0x21, 0x32, 0x17, 0x07, 0x26, 0x23, 0x22, 0x06, 0x1d, 0x01, 0x21, + 0x02, 0x9e, 0xfe, 0xe9, 0xa6, 0xc4, 0xc4, 0x01, 0x61, 0x57, 0x75, 0x2b, + 0x60, 0x44, 0x5e, 0x5a, 0x01, 0x17, 0x03, 0xc7, 0xfc, 0x39, 0x03, 0xc7, + 0x4b, 0x3c, 0x3d, 0x01, 0x94, 0x23, 0x85, 0x1f, 0x7d, 0x8a, 0x47, 0x00, + 0x00, 0x03, 0x00, 0x27, 0xfe, 0x14, 0x04, 0x31, 0x04, 0x5c, 0x00, 0x2a, + 0x00, 0x37, 0x00, 0x41, 0x00, 0x6e, 0x40, 0x3e, 0x2b, 0x19, 0x38, 0x25, + 0x0c, 0x1f, 0x3d, 0x05, 0x31, 0x13, 0x01, 0x13, 0x05, 0x02, 0x2a, 0x22, + 0x1c, 0x1f, 0x25, 0x19, 0x0a, 0x42, 0x43, 0x1c, 0x0f, 0x35, 0x0f, 0x35, + 0x46, 0x59, 0x08, 0x3b, 0x47, 0x59, 0x0a, 0x22, 0x08, 0x2a, 0x0f, 0x08, + 0x0f, 0x08, 0x16, 0x2a, 0x2a, 0x02, 0x47, 0x59, 0x2a, 0x0f, 0x28, 0x3f, + 0x47, 0x59, 0x28, 0x10, 0x16, 0x2e, 0x47, 0x59, 0x16, 0x1b, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, + 0x39, 0x39, 0x18, 0x2f, 0x2f, 0x11, 0x12, 0x39, 0x39, 0x2b, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x15, 0x07, 0x1e, + 0x01, 0x15, 0x14, 0x06, 0x23, 0x22, 0x27, 0x06, 0x15, 0x14, 0x16, 0x3b, + 0x01, 0x32, 0x16, 0x15, 0x14, 0x04, 0x21, 0x22, 0x26, 0x35, 0x34, 0x36, + 0x37, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, 0x2e, 0x01, 0x35, 0x34, 0x36, + 0x33, 0x32, 0x17, 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, + 0x2b, 0x01, 0x22, 0x06, 0x13, 0x14, 0x16, 0x33, 0x32, 0x35, 0x34, 0x23, + 0x22, 0x06, 0x04, 0x31, 0xcb, 0x1c, 0x2c, 0xdc, 0xc0, 0x31, 0x2b, 0x6a, + 0x4a, 0x5a, 0xc2, 0xb2, 0xbf, 0xfe, 0xdc, 0xfe, 0xe8, 0xd7, 0xe9, 0x80, + 0x74, 0x2a, 0x39, 0x40, 0x45, 0x55, 0x6b, 0xd8, 0xc6, 0x56, 0x45, 0xfe, + 0x11, 0x96, 0x8c, 0xd1, 0xc9, 0x6e, 0x98, 0xc7, 0x71, 0x7e, 0x5a, 0x82, + 0x74, 0xf3, 0xf6, 0x75, 0x7e, 0x04, 0x48, 0x69, 0x18, 0x23, 0x71, 0x47, + 0xa1, 0xc0, 0x08, 0x38, 0x55, 0x2d, 0x2b, 0x96, 0x8f, 0xb6, 0xbf, 0xa0, + 0x92, 0x64, 0x92, 0x1a, 0x13, 0x50, 0x35, 0x3c, 0x5a, 0x2a, 0x23, 0xa8, + 0x6c, 0xb4, 0xc3, 0x14, 0xfb, 0x00, 0x59, 0x5c, 0x7d, 0x6b, 0x59, 0x45, + 0x6c, 0x03, 0x3c, 0x73, 0x76, 0xec, 0xf7, 0x7e, 0x00, 0x01, 0x00, 0xb0, + 0x00, 0x00, 0x04, 0x44, 0x06, 0x14, 0x00, 0x16, 0x00, 0x33, 0x40, 0x19, + 0x0e, 0x0c, 0x08, 0x08, 0x09, 0x00, 0x16, 0x09, 0x16, 0x17, 0x18, 0x0e, + 0x09, 0x12, 0x12, 0x04, 0x46, 0x59, 0x12, 0x10, 0x0a, 0x00, 0x00, 0x09, + 0x15, 0x00, 0x3f, 0x33, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x11, + 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x33, 0x31, + 0x30, 0x21, 0x11, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, 0x23, 0x11, + 0x33, 0x11, 0x14, 0x07, 0x33, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x11, + 0x03, 0x9e, 0x7a, 0x82, 0xad, 0x9f, 0xa6, 0xa6, 0x08, 0x0a, 0x31, 0xb5, + 0x74, 0xc9, 0xc9, 0x02, 0xc5, 0x86, 0x84, 0xbc, 0xd6, 0xfd, 0xc3, 0x06, + 0x14, 0xfe, 0x29, 0x55, 0x38, 0x4f, 0x5b, 0xbf, 0xd0, 0xfd, 0x35, 0x00, + 0x00, 0x02, 0x00, 0xa2, 0x00, 0x00, 0x01, 0x66, 0x05, 0xdf, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x23, 0x40, 0x11, 0x0a, 0x00, 0x00, 0x04, 0x01, 0x01, + 0x10, 0x11, 0x0d, 0x07, 0x48, 0x59, 0x0d, 0x02, 0x0f, 0x01, 0x15, 0x00, + 0x3f, 0x3f, 0xce, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x21, 0x23, 0x11, 0x33, 0x03, 0x34, 0x36, 0x33, 0x32, + 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x01, 0x56, 0xa6, 0xa6, 0xb4, + 0x38, 0x2a, 0x28, 0x3a, 0x3a, 0x28, 0x2a, 0x38, 0x04, 0x48, 0x01, 0x29, + 0x39, 0x35, 0x36, 0x38, 0x38, 0x37, 0x37, 0x00, 0x00, 0x02, 0xff, 0x91, + 0xfe, 0x14, 0x01, 0x66, 0x05, 0xdf, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x2c, + 0x40, 0x16, 0x13, 0x0b, 0x0b, 0x0d, 0x08, 0x08, 0x19, 0x1a, 0x16, 0x10, + 0x48, 0x59, 0x16, 0x40, 0x09, 0x0f, 0x00, 0x05, 0x46, 0x59, 0x00, 0x1b, + 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x1a, 0xce, 0x2b, 0x11, 0x12, 0x01, + 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x22, 0x27, 0x35, + 0x16, 0x33, 0x32, 0x36, 0x35, 0x11, 0x33, 0x11, 0x10, 0x03, 0x34, 0x36, + 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x2b, 0x5f, 0x3b, + 0x45, 0x43, 0x4e, 0x49, 0xa6, 0xb4, 0x38, 0x2a, 0x28, 0x3a, 0x3a, 0x28, + 0x2a, 0x38, 0xfe, 0x14, 0x19, 0x87, 0x14, 0x55, 0x57, 0x04, 0xfc, 0xfb, + 0x10, 0xfe, 0xbc, 0x07, 0x5d, 0x39, 0x35, 0x36, 0x38, 0x38, 0x37, 0x37, + 0x00, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x04, 0x1d, 0x06, 0x14, 0x00, 0x10, + 0x00, 0x36, 0x40, 0x1b, 0x10, 0x0e, 0x0a, 0x0a, 0x0b, 0x0b, 0x08, 0x06, + 0x04, 0x05, 0x08, 0x04, 0x11, 0x12, 0x0c, 0x00, 0x00, 0x10, 0x10, 0x08, + 0x08, 0x03, 0x07, 0x0b, 0x15, 0x03, 0x0f, 0x00, 0x3f, 0x3f, 0x33, 0x12, + 0x39, 0x2f, 0x39, 0x11, 0x33, 0x3f, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x01, 0x36, 0x37, 0x01, + 0x33, 0x09, 0x01, 0x23, 0x01, 0x07, 0x11, 0x23, 0x11, 0x33, 0x11, 0x14, + 0x07, 0x01, 0x54, 0x2b, 0x58, 0x01, 0x62, 0xc5, 0xfe, 0x44, 0x01, 0xdb, + 0xc9, 0xfe, 0x7d, 0x7d, 0xa4, 0xa4, 0x08, 0x02, 0x31, 0x3d, 0x63, 0x01, + 0x77, 0xfe, 0x2d, 0xfd, 0x8b, 0x02, 0x06, 0x6c, 0xfe, 0x66, 0x06, 0x14, + 0xfc, 0xc7, 0x37, 0x73, 0x00, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x01, 0x56, + 0x06, 0x14, 0x00, 0x03, 0x00, 0x16, 0x40, 0x09, 0x00, 0x01, 0x01, 0x04, + 0x05, 0x02, 0x00, 0x01, 0x15, 0x00, 0x3f, 0x3f, 0x11, 0x12, 0x01, 0x39, + 0x11, 0x33, 0x31, 0x30, 0x21, 0x23, 0x11, 0x33, 0x01, 0x56, 0xa6, 0xa6, + 0x06, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x06, 0xcb, + 0x04, 0x5c, 0x00, 0x23, 0x00, 0x46, 0x40, 0x23, 0x15, 0x11, 0x11, 0x12, + 0x08, 0x09, 0x00, 0x23, 0x09, 0x12, 0x23, 0x03, 0x24, 0x25, 0x1c, 0x16, + 0x15, 0x15, 0x12, 0x19, 0x04, 0x0d, 0x19, 0x0d, 0x46, 0x59, 0x1f, 0x19, + 0x10, 0x13, 0x0f, 0x09, 0x00, 0x12, 0x15, 0x00, 0x3f, 0x33, 0x33, 0x3f, + 0x3f, 0x33, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, 0x39, 0x18, 0x2f, 0x33, + 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x21, 0x11, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, + 0x11, 0x23, 0x11, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, 0x23, 0x11, + 0x33, 0x17, 0x33, 0x3e, 0x01, 0x33, 0x20, 0x17, 0x33, 0x3e, 0x01, 0x33, + 0x32, 0x16, 0x15, 0x11, 0x06, 0x25, 0x70, 0x76, 0x9b, 0x94, 0xa6, 0x70, + 0x77, 0x9c, 0x91, 0xa6, 0x87, 0x1b, 0x08, 0x2f, 0xab, 0x6a, 0x01, 0x01, + 0x4f, 0x08, 0x31, 0xba, 0x77, 0xba, 0xb9, 0x02, 0xc9, 0x83, 0x83, 0xb2, + 0xb9, 0xfd, 0x9c, 0x02, 0xc9, 0x83, 0x83, 0xbb, 0xd5, 0xfd, 0xc1, 0x04, + 0x48, 0x96, 0x50, 0x5a, 0xba, 0x56, 0x64, 0xbf, 0xd2, 0xfd, 0x35, 0x00, + 0x00, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x04, 0x44, 0x04, 0x5c, 0x00, 0x14, + 0x00, 0x31, 0x40, 0x18, 0x00, 0x14, 0x0c, 0x08, 0x08, 0x09, 0x14, 0x09, + 0x16, 0x15, 0x0c, 0x09, 0x10, 0x10, 0x04, 0x46, 0x59, 0x10, 0x10, 0x0a, + 0x0f, 0x00, 0x09, 0x15, 0x00, 0x3f, 0x33, 0x3f, 0x3f, 0x2b, 0x11, 0x12, + 0x00, 0x39, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x21, 0x11, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, + 0x23, 0x11, 0x33, 0x17, 0x33, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x15, 0x11, + 0x03, 0x9e, 0x7a, 0x82, 0xac, 0xa0, 0xa6, 0x87, 0x1b, 0x08, 0x33, 0xb8, + 0x71, 0xc6, 0xc8, 0x02, 0xc5, 0x86, 0x84, 0xba, 0xd6, 0xfd, 0xc1, 0x04, + 0x48, 0x96, 0x51, 0x59, 0xbf, 0xd2, 0xfd, 0x35, 0x00, 0x02, 0x00, 0x73, + 0xff, 0xec, 0x04, 0x62, 0x04, 0x5c, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x28, + 0x40, 0x14, 0x13, 0x00, 0x0d, 0x07, 0x00, 0x07, 0x1a, 0x19, 0x0a, 0x16, + 0x46, 0x59, 0x0a, 0x10, 0x03, 0x10, 0x46, 0x59, 0x03, 0x16, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x00, 0x23, 0x22, 0x26, 0x02, 0x35, + 0x10, 0x00, 0x33, 0x32, 0x00, 0x01, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x04, 0x62, 0xfe, 0xf2, 0xee, 0x93, 0xe4, + 0x7c, 0x01, 0x0c, 0xee, 0xe6, 0x01, 0x0f, 0xfc, 0xbd, 0xa8, 0xa3, 0xa3, + 0xa9, 0xa9, 0xa5, 0xa3, 0xa6, 0x02, 0x25, 0xfe, 0xf4, 0xfe, 0xd3, 0x8a, + 0x01, 0x02, 0xad, 0x01, 0x0c, 0x01, 0x2b, 0xfe, 0xce, 0xfe, 0xfb, 0xd2, + 0xdc, 0xdb, 0xd3, 0xd1, 0xd9, 0xd6, 0x00, 0x00, 0x00, 0x02, 0x00, 0xb0, + 0xfe, 0x14, 0x04, 0x75, 0x04, 0x5c, 0x00, 0x14, 0x00, 0x21, 0x00, 0x3f, + 0x40, 0x20, 0x19, 0x0b, 0x04, 0x07, 0x07, 0x08, 0x1f, 0x12, 0x08, 0x12, + 0x22, 0x23, 0x04, 0x0b, 0x00, 0x0f, 0x0f, 0x15, 0x46, 0x59, 0x0f, 0x10, + 0x09, 0x0f, 0x08, 0x1b, 0x00, 0x1c, 0x46, 0x59, 0x00, 0x16, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x33, + 0x33, 0x31, 0x30, 0x05, 0x22, 0x26, 0x27, 0x23, 0x16, 0x15, 0x11, 0x23, + 0x11, 0x33, 0x17, 0x33, 0x3e, 0x01, 0x33, 0x32, 0x12, 0x11, 0x10, 0x02, + 0x03, 0x22, 0x06, 0x07, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, + 0x26, 0x02, 0xae, 0x6b, 0xb1, 0x3c, 0x0c, 0x0c, 0xa6, 0x87, 0x17, 0x08, + 0x40, 0xaa, 0x6e, 0xda, 0xed, 0xf1, 0xee, 0xa8, 0x96, 0x02, 0x9a, 0xaa, + 0x8e, 0xa1, 0xa1, 0x14, 0x4f, 0x52, 0x60, 0x56, 0xfe, 0x3d, 0x06, 0x34, + 0x96, 0x5a, 0x50, 0xfe, 0xd6, 0xfe, 0xf3, 0xfe, 0xf2, 0xfe, 0xd5, 0x03, + 0xe3, 0xba, 0xcb, 0x25, 0xe7, 0xc7, 0xe6, 0xca, 0xcd, 0xdb, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x73, 0xfe, 0x14, 0x04, 0x37, 0x04, 0x5c, 0x00, 0x0c, + 0x00, 0x1f, 0x00, 0x44, 0x40, 0x22, 0x0a, 0x10, 0x1d, 0x16, 0x03, 0x1a, + 0x1a, 0x19, 0x10, 0x19, 0x20, 0x21, 0x1a, 0x1b, 0x17, 0x0f, 0x1d, 0x1e, + 0x1e, 0x16, 0x0d, 0x13, 0x13, 0x07, 0x46, 0x59, 0x13, 0x10, 0x0d, 0x00, + 0x46, 0x59, 0x0d, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x39, 0x11, 0x33, 0x18, 0x3f, 0x3f, 0x11, 0x12, 0x01, + 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x25, 0x32, 0x36, 0x37, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, + 0x16, 0x17, 0x22, 0x02, 0x11, 0x10, 0x12, 0x33, 0x32, 0x17, 0x33, 0x37, + 0x33, 0x11, 0x23, 0x11, 0x34, 0x37, 0x23, 0x06, 0x02, 0x4e, 0xa6, 0x98, + 0x05, 0x9c, 0xa9, 0x92, 0x9b, 0x99, 0x7d, 0xd4, 0xee, 0xf0, 0xd6, 0xe1, + 0x79, 0x09, 0x18, 0x83, 0xa6, 0x0b, 0x0d, 0x73, 0x77, 0xb2, 0xd3, 0x25, + 0xe6, 0xca, 0xe3, 0xcf, 0xcf, 0xd9, 0x8b, 0x01, 0x2a, 0x01, 0x0b, 0x01, + 0x0d, 0x01, 0x2e, 0xaa, 0x96, 0xf9, 0xcc, 0x01, 0xd5, 0x64, 0x46, 0xa7, + 0x00, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x03, 0x27, 0x04, 0x5c, 0x00, 0x10, + 0x00, 0x2a, 0x40, 0x14, 0x0d, 0x09, 0x09, 0x0a, 0x0a, 0x02, 0x11, 0x12, + 0x0b, 0x0f, 0x0d, 0x00, 0x0a, 0x15, 0x00, 0x05, 0x46, 0x59, 0x00, 0x10, + 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x12, 0x39, 0x3f, 0x11, 0x12, 0x01, + 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x32, 0x17, 0x07, + 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, 0x23, 0x11, 0x33, 0x17, 0x33, 0x3e, + 0x01, 0x02, 0xa4, 0x49, 0x3a, 0x17, 0x44, 0x34, 0x85, 0xbd, 0xa6, 0x89, + 0x13, 0x08, 0x3d, 0xac, 0x04, 0x5c, 0x0c, 0x9a, 0x0f, 0xd8, 0xa1, 0xfd, + 0xb4, 0x04, 0x48, 0xcb, 0x6b, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, + 0xff, 0xec, 0x03, 0x73, 0x04, 0x5c, 0x00, 0x24, 0x00, 0x36, 0x40, 0x1c, + 0x1e, 0x13, 0x0c, 0x00, 0x00, 0x18, 0x05, 0x13, 0x04, 0x25, 0x26, 0x0c, + 0x1e, 0x03, 0x16, 0x16, 0x1b, 0x46, 0x59, 0x16, 0x10, 0x06, 0x03, 0x09, + 0x46, 0x59, 0x03, 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x2f, 0x3f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x06, 0x23, 0x22, 0x27, 0x35, 0x1e, + 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x27, 0x2e, 0x02, 0x35, 0x34, + 0x36, 0x33, 0x32, 0x17, 0x07, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, 0x1e, + 0x01, 0x17, 0x1e, 0x01, 0x03, 0x73, 0xe4, 0xce, 0xda, 0x7a, 0x4f, 0xb5, + 0x54, 0x82, 0x8c, 0x6f, 0xa1, 0x99, 0x81, 0x3f, 0xda, 0xbe, 0xb1, 0xa9, + 0x3b, 0xa5, 0x86, 0x76, 0x78, 0x2d, 0x64, 0x8e, 0xc3, 0x89, 0x01, 0x2b, + 0x99, 0xa6, 0x45, 0x9a, 0x28, 0x2e, 0x53, 0x55, 0x40, 0x5b, 0x3e, 0x39, + 0x55, 0x6c, 0x4b, 0x86, 0x9b, 0x48, 0x87, 0x44, 0x4a, 0x41, 0x2c, 0x3e, + 0x38, 0x35, 0x47, 0x90, 0x00, 0x01, 0x00, 0x1f, 0xff, 0xec, 0x02, 0xa8, + 0x05, 0x46, 0x00, 0x16, 0x00, 0x34, 0x40, 0x1b, 0x10, 0x14, 0x14, 0x09, + 0x0b, 0x09, 0x12, 0x03, 0x04, 0x18, 0x17, 0x0a, 0x13, 0x10, 0x13, 0x47, + 0x59, 0x0e, 0x40, 0x10, 0x0f, 0x07, 0x00, 0x46, 0x59, 0x07, 0x16, 0x00, + 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x1a, 0xcd, 0x2b, 0x11, 0x00, 0x33, 0x11, + 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x25, 0x32, + 0x36, 0x37, 0x15, 0x0e, 0x01, 0x23, 0x20, 0x19, 0x01, 0x23, 0x35, 0x3f, + 0x01, 0x33, 0x15, 0x21, 0x15, 0x21, 0x11, 0x14, 0x16, 0x02, 0x12, 0x2c, + 0x52, 0x18, 0x1b, 0x69, 0x2a, 0xfe, 0xc2, 0x9d, 0x9d, 0x46, 0x60, 0x01, + 0x3e, 0xfe, 0xc2, 0x5e, 0x75, 0x0d, 0x07, 0x7f, 0x0d, 0x11, 0x01, 0x4f, + 0x02, 0x8c, 0x50, 0x45, 0xea, 0xfe, 0x81, 0xfd, 0x7b, 0x63, 0x6a, 0x00, + 0x00, 0x01, 0x00, 0xa4, 0xff, 0xec, 0x04, 0x39, 0x04, 0x48, 0x00, 0x14, + 0x00, 0x34, 0x40, 0x19, 0x01, 0x13, 0x07, 0x0c, 0x0c, 0x0a, 0x13, 0x0a, + 0x15, 0x16, 0x0c, 0x0d, 0x0d, 0x10, 0x08, 0x14, 0x0f, 0x10, 0x04, 0x46, + 0x59, 0x10, 0x16, 0x0b, 0x15, 0x00, 0x3f, 0x3f, 0x2b, 0x00, 0x18, 0x3f, + 0x33, 0x12, 0x39, 0x11, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x11, 0x14, 0x16, 0x33, 0x32, + 0x36, 0x35, 0x11, 0x33, 0x11, 0x23, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, + 0x26, 0x35, 0x11, 0x01, 0x4c, 0x7a, 0x82, 0xac, 0x9f, 0xa6, 0x89, 0x18, + 0x09, 0x33, 0xb5, 0x74, 0xc8, 0xc7, 0x04, 0x48, 0xfd, 0x39, 0x86, 0x84, + 0xbc, 0xd5, 0x02, 0x40, 0xfb, 0xb8, 0x93, 0x51, 0x56, 0xbe, 0xd1, 0x02, + 0xcd, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, + 0x04, 0x48, 0x00, 0x0b, 0x00, 0x18, 0x40, 0x0a, 0x01, 0x0a, 0x0c, 0x0d, + 0x05, 0x09, 0x01, 0x0f, 0x00, 0x15, 0x00, 0x3f, 0x3f, 0x33, 0x39, 0x11, + 0x12, 0x01, 0x39, 0x39, 0x31, 0x30, 0x21, 0x01, 0x33, 0x13, 0x16, 0x17, + 0x33, 0x36, 0x12, 0x13, 0x33, 0x01, 0x01, 0xa0, 0xfe, 0x60, 0xb2, 0xec, + 0x50, 0x0e, 0x08, 0x0b, 0x75, 0xcc, 0xb2, 0xfe, 0x60, 0x04, 0x48, 0xfd, + 0x76, 0xe4, 0x44, 0x35, 0x01, 0x4d, 0x02, 0x30, 0xfb, 0xb8, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x17, 0x00, 0x00, 0x06, 0x23, 0x04, 0x48, 0x00, 0x1c, + 0x00, 0x2c, 0x40, 0x14, 0x09, 0x1b, 0x1d, 0x1e, 0x17, 0x16, 0x0e, 0x0d, + 0x03, 0x04, 0x0d, 0x04, 0x08, 0x1a, 0x12, 0x09, 0x0f, 0x00, 0x08, 0x15, + 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x33, 0x12, 0x39, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x33, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x31, 0x30, 0x21, 0x03, + 0x26, 0x27, 0x23, 0x06, 0x07, 0x03, 0x23, 0x01, 0x33, 0x1a, 0x01, 0x17, + 0x33, 0x3e, 0x01, 0x37, 0x13, 0x33, 0x13, 0x16, 0x17, 0x33, 0x3e, 0x01, + 0x13, 0x33, 0x01, 0x04, 0x2f, 0xc9, 0x13, 0x34, 0x08, 0x28, 0x1e, 0xcf, + 0xc0, 0xfe, 0xd5, 0xae, 0x6a, 0x6f, 0x08, 0x08, 0x0b, 0x31, 0x12, 0xc9, + 0xb4, 0xc4, 0x38, 0x14, 0x08, 0x04, 0x23, 0xbf, 0xac, 0xfe, 0xd1, 0x02, + 0x83, 0x3b, 0xd1, 0xaf, 0x5f, 0xfd, 0x7f, 0x04, 0x48, 0xfe, 0x63, 0xfe, + 0x50, 0x4b, 0x39, 0xb5, 0x35, 0x02, 0x75, 0xfd, 0x8b, 0xac, 0x75, 0x24, + 0x96, 0x02, 0xdc, 0xfb, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, + 0x00, 0x00, 0x04, 0x08, 0x04, 0x48, 0x00, 0x0b, 0x00, 0x22, 0x40, 0x11, + 0x07, 0x05, 0x06, 0x00, 0x01, 0x05, 0x0c, 0x0d, 0x09, 0x03, 0x01, 0x08, + 0x0b, 0x15, 0x04, 0x01, 0x0f, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, 0x39, + 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x31, 0x30, 0x09, 0x01, 0x33, 0x09, + 0x01, 0x33, 0x09, 0x01, 0x23, 0x09, 0x01, 0x23, 0x01, 0xb8, 0xfe, 0x83, + 0xbd, 0x01, 0x21, 0x01, 0x20, 0xbb, 0xfe, 0x83, 0x01, 0x91, 0xbc, 0xfe, + 0xcd, 0xfe, 0xca, 0xbc, 0x02, 0x31, 0x02, 0x17, 0xfe, 0x5c, 0x01, 0xa4, + 0xfd, 0xe9, 0xfd, 0xcf, 0x01, 0xbc, 0xfe, 0x44, 0x00, 0x01, 0x00, 0x02, + 0xfe, 0x14, 0x04, 0x06, 0x04, 0x48, 0x00, 0x15, 0x00, 0x24, 0x40, 0x12, + 0x09, 0x0f, 0x00, 0x03, 0x16, 0x17, 0x04, 0x0d, 0x00, 0x0d, 0x12, 0x46, + 0x59, 0x0d, 0x1b, 0x08, 0x00, 0x0f, 0x00, 0x3f, 0x32, 0x3f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x31, 0x30, 0x13, 0x33, + 0x13, 0x16, 0x17, 0x33, 0x3e, 0x01, 0x13, 0x33, 0x01, 0x0e, 0x01, 0x23, + 0x22, 0x27, 0x35, 0x16, 0x33, 0x32, 0x3f, 0x01, 0x02, 0xb2, 0xf0, 0x4f, + 0x13, 0x08, 0x0d, 0x53, 0xe6, 0xb2, 0xfe, 0x29, 0x46, 0xbb, 0x88, 0x4c, + 0x4a, 0x37, 0x44, 0xab, 0x49, 0x3d, 0x04, 0x48, 0xfd, 0x8f, 0xd6, 0x5f, + 0x33, 0xf7, 0x02, 0x7c, 0xfb, 0x20, 0xb9, 0x9b, 0x11, 0x85, 0x0c, 0xc0, + 0x9c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x52, 0x00, 0x00, 0x03, 0x6d, + 0x04, 0x48, 0x00, 0x09, 0x00, 0x2b, 0x40, 0x17, 0x08, 0x01, 0x03, 0x07, + 0x00, 0x07, 0x04, 0x01, 0x04, 0x0a, 0x0b, 0x05, 0x04, 0x47, 0x59, 0x05, + 0x0f, 0x01, 0x08, 0x47, 0x59, 0x01, 0x15, 0x00, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x2b, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x29, 0x01, 0x35, 0x01, 0x21, 0x35, 0x21, 0x15, 0x01, 0x21, 0x03, + 0x6d, 0xfc, 0xe5, 0x02, 0x56, 0xfd, 0xcf, 0x02, 0xe7, 0xfd, 0xb2, 0x02, + 0x5d, 0x71, 0x03, 0x56, 0x81, 0x81, 0xfc, 0xba, 0x00, 0x01, 0x00, 0x3d, + 0xfe, 0xbc, 0x02, 0xc1, 0x05, 0xb6, 0x00, 0x1c, 0x00, 0x2c, 0x40, 0x15, + 0x19, 0x1a, 0x1a, 0x0b, 0x17, 0x00, 0x00, 0x0f, 0x07, 0x14, 0x03, 0x03, + 0x07, 0x0b, 0x03, 0x1d, 0x1e, 0x13, 0x03, 0x04, 0x27, 0x00, 0x3f, 0x3f, + 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x25, 0x14, 0x16, 0x17, 0x15, 0x2e, + 0x01, 0x35, 0x11, 0x34, 0x26, 0x23, 0x35, 0x3e, 0x01, 0x35, 0x11, 0x34, + 0x36, 0x33, 0x15, 0x06, 0x15, 0x11, 0x14, 0x07, 0x15, 0x16, 0x15, 0x01, + 0xdb, 0x75, 0x71, 0xbe, 0xd0, 0x7e, 0x78, 0x82, 0x74, 0xd8, 0xb6, 0xe6, + 0xdf, 0xdf, 0x0c, 0x66, 0x5c, 0x02, 0x8c, 0x02, 0xaa, 0x9a, 0x01, 0x2f, + 0x68, 0x59, 0x8d, 0x02, 0x5c, 0x60, 0x01, 0x32, 0x9b, 0xac, 0x8b, 0x06, + 0xc1, 0xfe, 0xd9, 0xd7, 0x27, 0x0c, 0x27, 0xd7, 0x00, 0x01, 0x01, 0xee, + 0xfe, 0x10, 0x02, 0x7b, 0x06, 0x14, 0x00, 0x03, 0x00, 0x16, 0x40, 0x09, + 0x02, 0x03, 0x03, 0x04, 0x05, 0x03, 0x1b, 0x00, 0x00, 0x00, 0x3f, 0x3f, + 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x33, 0x11, 0x23, + 0x01, 0xee, 0x8d, 0x8d, 0x06, 0x14, 0xf7, 0xfc, 0x00, 0x01, 0x00, 0x48, + 0xfe, 0xbc, 0x02, 0xcb, 0x05, 0xb6, 0x00, 0x1d, 0x00, 0x2c, 0x40, 0x15, + 0x15, 0x05, 0x0a, 0x12, 0x12, 0x02, 0x19, 0x00, 0x1d, 0x1d, 0x0e, 0x0e, + 0x19, 0x05, 0x03, 0x1e, 0x1f, 0x15, 0x27, 0x06, 0x03, 0x00, 0x3f, 0x3f, + 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x26, 0x35, 0x11, 0x34, 0x27, + 0x35, 0x32, 0x16, 0x15, 0x11, 0x14, 0x16, 0x17, 0x15, 0x22, 0x06, 0x15, + 0x11, 0x14, 0x06, 0x07, 0x35, 0x3e, 0x01, 0x35, 0x11, 0x34, 0x36, 0x37, + 0x02, 0x0a, 0xdf, 0xe3, 0xb8, 0xd3, 0x76, 0x82, 0x7a, 0x7e, 0xcd, 0xbe, + 0x6f, 0x74, 0x6e, 0x71, 0x02, 0x3f, 0x27, 0xd7, 0x01, 0x27, 0xc1, 0x06, + 0x8b, 0xae, 0x99, 0xfe, 0xce, 0x61, 0x5b, 0x02, 0x8d, 0x59, 0x68, 0xfe, + 0xd1, 0x99, 0xab, 0x02, 0x8c, 0x02, 0x5c, 0x66, 0x01, 0x29, 0x72, 0x78, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x68, 0x02, 0x50, 0x04, 0x29, + 0x03, 0x54, 0x00, 0x17, 0x00, 0x24, 0x40, 0x11, 0x03, 0x0f, 0x18, 0x19, + 0x12, 0x0c, 0x50, 0x59, 0x03, 0x12, 0x0f, 0x06, 0x06, 0x00, 0x50, 0x59, + 0x06, 0x00, 0x2f, 0x2b, 0x00, 0x10, 0x18, 0xc4, 0x2f, 0xc4, 0x2b, 0x11, + 0x12, 0x01, 0x39, 0x39, 0x31, 0x30, 0x01, 0x22, 0x06, 0x07, 0x35, 0x36, + 0x33, 0x32, 0x16, 0x17, 0x1e, 0x01, 0x33, 0x32, 0x36, 0x37, 0x15, 0x06, + 0x23, 0x22, 0x26, 0x27, 0x2e, 0x01, 0x01, 0x52, 0x35, 0x7f, 0x36, 0x64, + 0x90, 0x44, 0x71, 0x59, 0x42, 0x62, 0x2f, 0x36, 0x80, 0x36, 0x66, 0x8e, + 0x48, 0x7e, 0x48, 0x4b, 0x5a, 0x02, 0xc9, 0x43, 0x36, 0x97, 0x6d, 0x1c, + 0x26, 0x1c, 0x1b, 0x40, 0x39, 0x96, 0x6e, 0x21, 0x20, 0x20, 0x18, 0x00, + 0x00, 0x02, 0x00, 0x98, 0xfe, 0x8b, 0x01, 0x89, 0x04, 0x5e, 0x00, 0x03, + 0x00, 0x0e, 0x00, 0x2b, 0x40, 0x14, 0x02, 0x04, 0x04, 0x03, 0x09, 0x09, + 0x0f, 0x10, 0x00, 0x00, 0x03, 0x0c, 0x0c, 0x06, 0x4f, 0x59, 0x0c, 0x10, + 0x03, 0x22, 0x00, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, + 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, + 0x33, 0x13, 0x23, 0x13, 0x14, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, + 0x32, 0x16, 0xdb, 0x69, 0x33, 0xcf, 0xe1, 0x79, 0x3c, 0x3c, 0x3f, 0x39, + 0x33, 0x46, 0x02, 0xac, 0xfb, 0xdf, 0x05, 0x4c, 0x87, 0x47, 0x40, 0x3f, + 0x48, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0xbe, 0xff, 0xec, 0x03, 0xdb, + 0x05, 0xcb, 0x00, 0x1b, 0x00, 0x3e, 0x40, 0x1e, 0x16, 0x08, 0x0d, 0x03, + 0x03, 0x0a, 0x04, 0x00, 0x10, 0x10, 0x04, 0x08, 0x03, 0x1c, 0x1d, 0x19, + 0x05, 0x02, 0x13, 0x0a, 0x0d, 0x02, 0x0d, 0x02, 0x0d, 0x04, 0x0b, 0x07, + 0x04, 0x19, 0x00, 0x3f, 0x3f, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x11, 0x33, + 0x33, 0x11, 0x33, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x25, 0x06, 0x07, 0x15, + 0x23, 0x35, 0x26, 0x02, 0x35, 0x10, 0x25, 0x35, 0x33, 0x15, 0x1e, 0x01, + 0x17, 0x07, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x33, 0x32, 0x37, + 0x03, 0xcb, 0x69, 0x93, 0x85, 0xcb, 0xc1, 0x01, 0x8c, 0x87, 0x4b, 0x8e, + 0x31, 0x31, 0x85, 0x6d, 0xac, 0xa2, 0x9f, 0xa7, 0x8d, 0x8e, 0xf0, 0x36, + 0x06, 0xc8, 0xce, 0x20, 0x01, 0x11, 0xfa, 0x01, 0xfc, 0x3e, 0xac, 0xa4, + 0x03, 0x21, 0x17, 0x8c, 0x33, 0xd3, 0xd9, 0xd4, 0xcb, 0x3b, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x3f, 0x00, 0x00, 0x04, 0x44, 0x05, 0xc9, 0x00, 0x1d, + 0x00, 0x48, 0x40, 0x26, 0x18, 0x13, 0x09, 0x0d, 0x0d, 0x1a, 0x16, 0x11, + 0x02, 0x0b, 0x16, 0x13, 0x05, 0x1e, 0x1f, 0x0c, 0x18, 0x19, 0x18, 0x4e, + 0x59, 0x09, 0x19, 0x19, 0x13, 0x00, 0x13, 0x10, 0x4c, 0x59, 0x13, 0x18, + 0x00, 0x05, 0x4b, 0x59, 0x00, 0x07, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, + 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, 0x33, 0x2b, 0x11, 0x00, 0x33, + 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, + 0x31, 0x30, 0x01, 0x32, 0x17, 0x07, 0x26, 0x23, 0x22, 0x06, 0x15, 0x11, + 0x21, 0x15, 0x21, 0x15, 0x14, 0x06, 0x07, 0x21, 0x15, 0x21, 0x35, 0x36, + 0x3d, 0x01, 0x23, 0x35, 0x33, 0x11, 0x34, 0x36, 0x02, 0xaa, 0xbe, 0xaa, + 0x3d, 0x9a, 0x8f, 0x7b, 0x7d, 0x01, 0xa6, 0xfe, 0x5a, 0x41, 0x4a, 0x03, + 0x1b, 0xfb, 0xfb, 0xcd, 0xc6, 0xc6, 0xe0, 0x05, 0xc9, 0x54, 0x85, 0x4d, + 0x7c, 0x8c, 0xfe, 0xd9, 0x7f, 0xdd, 0x64, 0x88, 0x2c, 0x9a, 0x8d, 0x2f, + 0xf4, 0xdf, 0x7f, 0x01, 0x3c, 0xb2, 0xcd, 0x00, 0x00, 0x02, 0x00, 0x7b, + 0x01, 0x06, 0x04, 0x17, 0x04, 0xa0, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x20, + 0x40, 0x0d, 0x1c, 0x00, 0x22, 0x0e, 0x00, 0x0e, 0x28, 0x29, 0x1f, 0x15, + 0x15, 0x25, 0x07, 0x00, 0x2f, 0x33, 0x33, 0x2f, 0x33, 0x11, 0x12, 0x01, + 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x34, 0x37, 0x27, + 0x37, 0x17, 0x36, 0x33, 0x32, 0x17, 0x37, 0x17, 0x07, 0x16, 0x15, 0x14, + 0x07, 0x17, 0x07, 0x27, 0x06, 0x23, 0x22, 0x27, 0x07, 0x27, 0x37, 0x26, + 0x37, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, + 0xb8, 0x4a, 0x87, 0x5e, 0x87, 0x68, 0x82, 0x7f, 0x66, 0x89, 0x5f, 0x86, + 0x4a, 0x4a, 0x83, 0x5c, 0x89, 0x66, 0x7f, 0x86, 0x64, 0x87, 0x5c, 0x85, + 0x4a, 0x81, 0x9d, 0x74, 0x74, 0x9e, 0xa0, 0x72, 0x74, 0x9d, 0x02, 0xd3, + 0x7a, 0x6b, 0x8c, 0x5c, 0x85, 0x49, 0x49, 0x85, 0x5c, 0x8a, 0x71, 0x76, + 0x83, 0x67, 0x87, 0x5c, 0x85, 0x47, 0x49, 0x85, 0x5c, 0x88, 0x6b, 0x7c, + 0x70, 0xa0, 0x9f, 0x71, 0x72, 0xa2, 0xa4, 0x00, 0x00, 0x01, 0x00, 0x1f, + 0x00, 0x00, 0x04, 0x71, 0x05, 0xb6, 0x00, 0x16, 0x00, 0x56, 0x40, 0x2e, + 0x12, 0x0e, 0x07, 0x0b, 0x0b, 0x10, 0x0c, 0x05, 0x09, 0x02, 0x09, 0x03, + 0x0c, 0x14, 0x0e, 0x15, 0x07, 0x17, 0x18, 0x0a, 0x0e, 0x0e, 0x07, 0x0f, + 0x06, 0x12, 0x12, 0x03, 0x00, 0x13, 0x15, 0x0f, 0x13, 0x1f, 0x13, 0x02, + 0x0f, 0x13, 0x0f, 0x13, 0x0c, 0x01, 0x15, 0x06, 0x0c, 0x18, 0x00, 0x3f, + 0x3f, 0x33, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x5d, 0x11, 0x12, 0x39, 0x32, + 0x32, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x12, 0x01, 0x17, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x09, 0x01, 0x33, 0x01, 0x21, 0x15, 0x21, 0x15, 0x21, 0x15, 0x21, 0x11, + 0x23, 0x11, 0x21, 0x35, 0x21, 0x35, 0x21, 0x35, 0x21, 0x01, 0x33, 0x02, + 0x48, 0x01, 0x7b, 0xae, 0xfe, 0x60, 0x01, 0x06, 0xfe, 0xc3, 0x01, 0x3d, + 0xfe, 0xc3, 0xa4, 0xfe, 0xc4, 0x01, 0x3c, 0xfe, 0xc4, 0x01, 0x00, 0xfe, + 0x65, 0xb2, 0x02, 0xdf, 0x02, 0xd7, 0xfc, 0xfe, 0x7f, 0xaa, 0x7f, 0xfe, + 0xf4, 0x01, 0x0c, 0x7f, 0xaa, 0x7f, 0x03, 0x02, 0x00, 0x02, 0x01, 0xee, + 0xfe, 0x10, 0x02, 0x7b, 0x06, 0x14, 0x00, 0x03, 0x00, 0x07, 0x00, 0x24, + 0x40, 0x10, 0x02, 0x06, 0x06, 0x03, 0x07, 0x07, 0x08, 0x09, 0x04, 0x03, + 0x04, 0x03, 0x07, 0x1b, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x39, 0x39, 0x2f, + 0x2f, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x01, 0x33, 0x11, 0x23, 0x11, 0x33, 0x11, 0x23, 0x01, 0xee, 0x8d, 0x8d, + 0x8d, 0x8d, 0x06, 0x14, 0xfc, 0xf8, 0xfe, 0x0d, 0xfc, 0xf7, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x7b, 0xff, 0xf8, 0x03, 0x96, 0x06, 0x1d, 0x00, 0x31, + 0x00, 0x3d, 0x00, 0x43, 0x40, 0x26, 0x32, 0x00, 0x13, 0x06, 0x2a, 0x1e, + 0x38, 0x19, 0x19, 0x1e, 0x0c, 0x06, 0x00, 0x23, 0x06, 0x3e, 0x3f, 0x15, + 0x03, 0x3b, 0x36, 0x1c, 0x2d, 0x06, 0x21, 0x09, 0x21, 0x27, 0x47, 0x59, + 0x21, 0x15, 0x09, 0x10, 0x47, 0x59, 0x09, 0x00, 0x00, 0x3f, 0x2b, 0x00, + 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x17, 0x39, 0x11, 0x12, 0x01, 0x17, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, + 0x34, 0x36, 0x37, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x17, + 0x07, 0x2e, 0x01, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x17, 0x1e, 0x01, + 0x15, 0x14, 0x06, 0x07, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x27, 0x35, + 0x1e, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x2e, 0x01, 0x27, 0x2e, 0x02, + 0x37, 0x14, 0x16, 0x1f, 0x01, 0x36, 0x35, 0x34, 0x26, 0x27, 0x0e, 0x01, + 0x8b, 0x56, 0x4e, 0x4a, 0x54, 0xcf, 0xc5, 0x5e, 0x9f, 0x61, 0x35, 0x62, + 0x87, 0x4c, 0x74, 0x74, 0x7b, 0x9a, 0xba, 0x96, 0x52, 0x4a, 0x99, 0xea, + 0xd4, 0xda, 0x80, 0x4e, 0xc2, 0x52, 0x86, 0x8d, 0x30, 0x6c, 0x73, 0x8e, + 0x86, 0x42, 0x92, 0x84, 0xa7, 0x31, 0x89, 0x93, 0xb9, 0x44, 0x55, 0x03, + 0x29, 0x56, 0x89, 0x25, 0x28, 0x6f, 0x55, 0x79, 0x8b, 0x1d, 0x27, 0x83, + 0x27, 0x1b, 0x3b, 0x40, 0x3c, 0x54, 0x37, 0x44, 0x97, 0x6b, 0x5a, 0x8d, + 0x29, 0x51, 0x92, 0x8c, 0x99, 0x41, 0x94, 0x25, 0x2d, 0x4c, 0x47, 0x2e, + 0x3a, 0x3a, 0x2b, 0x34, 0x5a, 0x72, 0x62, 0x4d, 0x69, 0x3d, 0x13, 0x50, + 0x6f, 0x53, 0x70, 0x39, 0x13, 0x64, 0x00, 0x00, 0x00, 0x02, 0x01, 0x35, + 0x05, 0x0e, 0x03, 0x68, 0x05, 0xd3, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x1e, + 0x40, 0x0c, 0x06, 0x00, 0x0c, 0x12, 0x00, 0x12, 0x18, 0x19, 0x0f, 0x03, + 0x15, 0x09, 0x00, 0x2f, 0x33, 0xcd, 0x32, 0x11, 0x12, 0x01, 0x39, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x25, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x01, 0x35, 0x35, 0x25, 0x26, 0x37, + 0x37, 0x26, 0x25, 0x35, 0x01, 0x7d, 0x35, 0x25, 0x25, 0x37, 0x37, 0x25, + 0x25, 0x35, 0x05, 0x71, 0x34, 0x2e, 0x2e, 0x34, 0x32, 0x31, 0x31, 0x32, + 0x34, 0x2e, 0x2e, 0x34, 0x32, 0x31, 0x31, 0x00, 0x00, 0x03, 0x00, 0x64, + 0xff, 0xec, 0x06, 0x44, 0x05, 0xcb, 0x00, 0x16, 0x00, 0x26, 0x00, 0x36, + 0x00, 0x46, 0x40, 0x27, 0x27, 0x17, 0x03, 0x0f, 0x2f, 0x1f, 0x1f, 0x14, + 0x09, 0x0f, 0x17, 0x05, 0x37, 0x38, 0x06, 0x0c, 0x00, 0x12, 0x0f, 0x0c, + 0x1f, 0x0c, 0x02, 0x00, 0x12, 0x10, 0x12, 0x02, 0x0c, 0x12, 0x0c, 0x12, + 0x1b, 0x2b, 0x23, 0x13, 0x33, 0x1b, 0x04, 0x00, 0x3f, 0x33, 0x3f, 0x33, + 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x5d, 0x5d, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, + 0x01, 0x22, 0x06, 0x15, 0x14, 0x16, 0x33, 0x32, 0x37, 0x15, 0x0e, 0x01, + 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x17, 0x07, 0x26, 0x01, + 0x34, 0x12, 0x24, 0x33, 0x32, 0x04, 0x12, 0x15, 0x14, 0x02, 0x04, 0x23, + 0x22, 0x24, 0x02, 0x37, 0x14, 0x12, 0x04, 0x33, 0x32, 0x24, 0x12, 0x35, + 0x34, 0x02, 0x24, 0x23, 0x22, 0x04, 0x02, 0x03, 0x7d, 0x7d, 0x87, 0x7f, + 0x83, 0x56, 0x7d, 0x30, 0x65, 0x46, 0xc2, 0xd0, 0xdd, 0xbf, 0x80, 0x76, + 0x3a, 0x6c, 0xfc, 0x97, 0xc8, 0x01, 0x5e, 0xca, 0xc8, 0x01, 0x5e, 0xca, + 0xc2, 0xfe, 0xa2, 0xd0, 0xcf, 0xfe, 0xa2, 0xc3, 0x69, 0xae, 0x01, 0x2d, + 0xac, 0xae, 0x01, 0x2a, 0xaf, 0xae, 0xfe, 0xd7, 0xb0, 0xae, 0xfe, 0xd6, + 0xaf, 0x04, 0x23, 0xae, 0x9a, 0xa8, 0xa2, 0x2d, 0x7c, 0x14, 0x1c, 0xf1, + 0xd8, 0xd1, 0xf6, 0x3c, 0x76, 0x33, 0xfe, 0xb8, 0xc8, 0x01, 0x5e, 0xca, + 0xc8, 0xfe, 0xa2, 0xca, 0xc5, 0xfe, 0xa6, 0xd0, 0xcf, 0x01, 0x5a, 0xc6, + 0xad, 0xfe, 0xd3, 0xad, 0xae, 0x01, 0x29, 0xb0, 0xae, 0x01, 0x2a, 0xaf, + 0xae, 0xfe, 0xd7, 0x00, 0x00, 0x02, 0x00, 0x46, 0x03, 0x14, 0x02, 0x71, + 0x05, 0xc7, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x37, 0x40, 0x1c, 0x17, 0x06, + 0x1b, 0x0a, 0x01, 0x01, 0x16, 0x16, 0x10, 0x06, 0x03, 0x20, 0x21, 0x1c, + 0x0a, 0x0a, 0x12, 0x19, 0x16, 0x00, 0x03, 0x10, 0x03, 0x02, 0x03, 0x0d, + 0x12, 0x1f, 0x00, 0x3f, 0x33, 0xd4, 0x5d, 0xc4, 0x33, 0x12, 0x39, 0x2f, + 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x27, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, + 0x3f, 0x01, 0x35, 0x34, 0x23, 0x22, 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, + 0x15, 0x11, 0x25, 0x14, 0x33, 0x32, 0x3d, 0x01, 0x07, 0x0e, 0x01, 0x02, + 0x14, 0x18, 0x5c, 0x8c, 0x5f, 0x6f, 0x9a, 0xa5, 0x75, 0x94, 0x64, 0x68, + 0x2b, 0x72, 0x85, 0x82, 0x89, 0xfe, 0x50, 0x70, 0xc9, 0x62, 0x70, 0x67, + 0x03, 0x21, 0x54, 0x61, 0x63, 0x66, 0x66, 0x69, 0x06, 0x04, 0x27, 0x85, + 0x33, 0x60, 0x38, 0x69, 0x79, 0xfe, 0x3c, 0xbc, 0x64, 0xb4, 0x31, 0x04, + 0x04, 0x39, 0x00, 0x00, 0x00, 0x02, 0x00, 0x52, 0x00, 0x75, 0x03, 0xaa, + 0x03, 0xbe, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x29, 0x40, 0x13, 0x03, 0x06, + 0x0a, 0x0d, 0x02, 0x04, 0x0b, 0x09, 0x09, 0x04, 0x0d, 0x06, 0x04, 0x0e, + 0x0f, 0x0c, 0x05, 0x08, 0x01, 0x00, 0x2f, 0x33, 0x2f, 0x33, 0x11, 0x12, + 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x13, 0x01, 0x17, 0x09, 0x01, 0x07, 0x01, 0x25, 0x01, 0x17, 0x09, + 0x01, 0x07, 0x01, 0x52, 0x01, 0x56, 0x77, 0xfe, 0xdf, 0x01, 0x21, 0x77, + 0xfe, 0xaa, 0x01, 0x8b, 0x01, 0x58, 0x75, 0xfe, 0xe1, 0x01, 0x1f, 0x75, + 0xfe, 0xa8, 0x02, 0x27, 0x01, 0x97, 0x45, 0xfe, 0xa2, 0xfe, 0xa1, 0x47, + 0x01, 0x97, 0x1b, 0x01, 0x97, 0x45, 0xfe, 0xa2, 0xfe, 0xa1, 0x47, 0x01, + 0x97, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x68, 0x01, 0x08, 0x04, 0x29, + 0x03, 0x17, 0x00, 0x05, 0x00, 0x1b, 0x40, 0x0c, 0x02, 0x01, 0x04, 0x01, + 0x06, 0x07, 0x05, 0x04, 0x50, 0x59, 0x05, 0x02, 0x00, 0x2f, 0x2f, 0x2b, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x31, 0x30, 0x01, 0x11, 0x23, + 0x11, 0x21, 0x35, 0x04, 0x29, 0x89, 0xfc, 0xc8, 0x03, 0x17, 0xfd, 0xf1, + 0x01, 0x85, 0x8a, 0x00, 0xff, 0xff, 0x00, 0x54, 0x01, 0xd9, 0x02, 0x3f, + 0x02, 0x71, 0x12, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x64, + 0xff, 0xec, 0x06, 0x44, 0x05, 0xcb, 0x00, 0x08, 0x00, 0x16, 0x00, 0x26, + 0x00, 0x36, 0x00, 0x5d, 0x40, 0x33, 0x27, 0x17, 0x00, 0x11, 0x11, 0x12, + 0x04, 0x09, 0x2f, 0x1f, 0x1f, 0x0d, 0x09, 0x0c, 0x12, 0x17, 0x06, 0x37, + 0x38, 0x0c, 0x10, 0x10, 0x00, 0x00, 0x0e, 0x13, 0x0e, 0x12, 0x08, 0x13, + 0x0f, 0x12, 0x1f, 0x12, 0x02, 0x00, 0x13, 0x10, 0x13, 0x02, 0x12, 0x13, + 0x12, 0x13, 0x1b, 0x2b, 0x23, 0x13, 0x33, 0x1b, 0x04, 0x00, 0x3f, 0x33, + 0x3f, 0x33, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x5d, 0x5d, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x12, 0x39, 0x2f, 0x33, 0x11, 0x33, 0x11, 0x12, 0x01, 0x17, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x01, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x05, 0x14, + 0x06, 0x07, 0x13, 0x23, 0x03, 0x23, 0x11, 0x23, 0x11, 0x21, 0x32, 0x16, + 0x01, 0x34, 0x12, 0x24, 0x33, 0x32, 0x04, 0x12, 0x15, 0x14, 0x02, 0x04, + 0x23, 0x22, 0x24, 0x02, 0x37, 0x14, 0x12, 0x04, 0x33, 0x32, 0x24, 0x12, + 0x35, 0x34, 0x02, 0x24, 0x23, 0x22, 0x04, 0x02, 0x02, 0xd3, 0x6c, 0x50, + 0x61, 0x56, 0x5d, 0x6a, 0x01, 0xb2, 0x55, 0x4d, 0xee, 0xa8, 0xcf, 0x87, + 0x94, 0x01, 0x05, 0xa6, 0x9b, 0xfb, 0xdf, 0xc8, 0x01, 0x5e, 0xca, 0xc8, + 0x01, 0x5e, 0xca, 0xc2, 0xfe, 0xa2, 0xd0, 0xcf, 0xfe, 0xa2, 0xc3, 0x69, + 0xae, 0x01, 0x2d, 0xac, 0xae, 0x01, 0x2a, 0xaf, 0xae, 0xfe, 0xd7, 0xb0, + 0xae, 0xfe, 0xd6, 0xaf, 0x02, 0xfa, 0x53, 0x40, 0x4b, 0x41, 0x88, 0x50, + 0x7b, 0x1e, 0xfe, 0x75, 0x01, 0x62, 0xfe, 0x9e, 0x03, 0x7b, 0x82, 0xfe, + 0xc5, 0xc8, 0x01, 0x5e, 0xca, 0xc8, 0xfe, 0xa2, 0xca, 0xc5, 0xfe, 0xa6, + 0xd0, 0xcf, 0x01, 0x5a, 0xc6, 0xad, 0xfe, 0xd3, 0xad, 0xae, 0x01, 0x29, + 0xb0, 0xae, 0x01, 0x2a, 0xaf, 0xae, 0xfe, 0xd7, 0x00, 0x01, 0xff, 0xfa, + 0x06, 0x14, 0x04, 0x06, 0x06, 0x93, 0x00, 0x03, 0x00, 0x11, 0xb5, 0x00, + 0x05, 0x01, 0x04, 0x01, 0x02, 0x00, 0x2f, 0x33, 0x11, 0x01, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x21, 0x35, 0x21, 0x04, 0x06, 0xfb, 0xf4, 0x04, + 0x0c, 0x06, 0x14, 0x7f, 0x00, 0x02, 0x00, 0x7f, 0x03, 0x5c, 0x02, 0xee, + 0x05, 0xcb, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x21, 0x40, 0x0e, 0x0d, 0x00, + 0x13, 0x06, 0x00, 0x06, 0x19, 0x1a, 0x10, 0x0a, 0xc0, 0x16, 0x03, 0x04, + 0x00, 0x3f, 0x33, 0x1a, 0xcc, 0x32, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x31, 0x30, 0x13, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x37, 0x14, 0x16, 0x33, 0x32, 0x36, + 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x7f, 0xb5, 0x82, 0x82, 0xb6, 0x52, + 0x92, 0x54, 0x82, 0xb5, 0x73, 0x75, 0x51, 0x50, 0x73, 0x71, 0x52, 0x53, + 0x73, 0x04, 0x93, 0x82, 0xb6, 0xb5, 0x83, 0x54, 0x8f, 0x54, 0xb4, 0x83, + 0x52, 0x72, 0x71, 0x53, 0x54, 0x71, 0x72, 0x00, 0x00, 0x02, 0x00, 0x68, + 0x00, 0x01, 0x04, 0x29, 0x04, 0xc3, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, + 0x37, 0x35, 0x21, 0x15, 0x01, 0x21, 0x15, 0x21, 0x11, 0x23, 0x11, 0x21, + 0x35, 0x21, 0x11, 0x33, 0x68, 0x03, 0xc1, 0xfe, 0x64, 0x01, 0x9c, 0xfe, + 0x64, 0x8b, 0xfe, 0x66, 0x01, 0x9a, 0x8b, 0x01, 0x8a, 0x8a, 0x03, 0x16, + 0x8a, 0xfe, 0x56, 0x01, 0xaa, 0x8a, 0x01, 0xac, 0x00, 0x01, 0x00, 0x31, + 0x02, 0x4a, 0x02, 0x8d, 0x05, 0xc9, 0x00, 0x18, 0x00, 0x23, 0x40, 0x11, + 0x07, 0x13, 0x17, 0x01, 0x01, 0x0e, 0x13, 0x00, 0x04, 0x1a, 0x19, 0x0a, + 0x10, 0x1f, 0x17, 0x01, 0x20, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x11, 0x12, + 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x21, 0x35, + 0x37, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x36, + 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x0f, 0x01, 0x21, 0x02, 0x8d, 0xfd, + 0xa4, 0xec, 0x59, 0x52, 0x21, 0x50, 0x3f, 0x34, 0x62, 0x45, 0x42, 0x83, + 0x98, 0x84, 0x93, 0x59, 0x93, 0xae, 0x01, 0xb8, 0x02, 0x4a, 0x68, 0xe6, + 0x56, 0x61, 0x4c, 0x36, 0x44, 0x45, 0x26, 0x32, 0x58, 0x6f, 0x82, 0x70, + 0x50, 0x97, 0x8a, 0xa5, 0x00, 0x01, 0x00, 0x21, 0x02, 0x39, 0x02, 0x8d, + 0x05, 0xc9, 0x00, 0x23, 0x00, 0x39, 0x40, 0x22, 0x0f, 0x05, 0x05, 0x00, + 0x03, 0x12, 0x1e, 0x0a, 0x06, 0x24, 0x25, 0x12, 0x5d, 0x13, 0x6d, 0x13, + 0x02, 0x4c, 0x13, 0x01, 0x0b, 0x13, 0x1b, 0x13, 0x02, 0x13, 0x13, 0x08, + 0x1a, 0x21, 0x1f, 0x0d, 0x08, 0x21, 0x00, 0x3f, 0x33, 0x3f, 0x33, 0x12, + 0x39, 0x2f, 0x5d, 0x5d, 0x5d, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x14, 0x06, 0x07, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x27, 0x35, 0x16, 0x33, 0x32, 0x35, 0x34, 0x2b, 0x01, 0x35, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, + 0x33, 0x32, 0x16, 0x02, 0x73, 0x52, 0x44, 0xb0, 0xb8, 0xa8, 0x98, 0x74, + 0x93, 0x7b, 0xd3, 0xe7, 0x75, 0x77, 0x67, 0x63, 0x50, 0x43, 0x42, 0x70, + 0x38, 0x45, 0x3f, 0x8c, 0x5e, 0x88, 0x9d, 0x04, 0xe7, 0x50, 0x67, 0x17, + 0x2f, 0xa2, 0x80, 0x8f, 0x38, 0x7b, 0x44, 0xa2, 0x91, 0x6b, 0x4f, 0x44, + 0x3d, 0x44, 0x2b, 0x23, 0x5a, 0x2d, 0x36, 0x77, 0x00, 0x01, 0x01, 0x89, + 0x04, 0xd9, 0x03, 0x12, 0x06, 0x21, 0x00, 0x09, 0x00, 0x13, 0xb6, 0x09, + 0x04, 0x0a, 0x0b, 0x04, 0x80, 0x09, 0x00, 0x2f, 0x1a, 0xcd, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x31, 0x30, 0x01, 0x3e, 0x01, 0x37, 0x33, 0x15, 0x0e, + 0x01, 0x07, 0x23, 0x01, 0x89, 0x30, 0x6f, 0x20, 0xca, 0x2c, 0xae, 0x40, + 0x6f, 0x04, 0xf2, 0x3e, 0xb0, 0x41, 0x15, 0x41, 0xbe, 0x34, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xb0, 0xfe, 0x14, 0x04, 0x44, 0x04, 0x48, 0x00, 0x16, + 0x00, 0x35, 0x40, 0x1a, 0x05, 0x0a, 0x0a, 0x08, 0x10, 0x00, 0x13, 0x13, + 0x14, 0x08, 0x14, 0x18, 0x17, 0x06, 0x15, 0x0f, 0x14, 0x1b, 0x0d, 0x02, + 0x46, 0x59, 0x0d, 0x16, 0x09, 0x15, 0x00, 0x3f, 0x3f, 0x2b, 0x00, 0x18, + 0x3f, 0x3f, 0x33, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, + 0x33, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x33, 0x32, 0x36, + 0x35, 0x11, 0x33, 0x11, 0x23, 0x27, 0x23, 0x06, 0x23, 0x22, 0x27, 0x23, + 0x16, 0x15, 0x11, 0x23, 0x11, 0x33, 0x01, 0x56, 0xfe, 0xab, 0x9f, 0xa6, + 0x88, 0x1a, 0x0a, 0x6f, 0xe5, 0x96, 0x58, 0x0a, 0x0a, 0xa6, 0xa6, 0x01, + 0x7d, 0xfe, 0xfa, 0xbd, 0xd4, 0x02, 0x40, 0xfb, 0xb8, 0x93, 0xa7, 0x5c, + 0x54, 0xa0, 0xfe, 0xc0, 0x06, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x71, + 0xfe, 0xfc, 0x04, 0x60, 0x06, 0x14, 0x00, 0x0f, 0x00, 0x27, 0x40, 0x12, + 0x04, 0x05, 0x01, 0x00, 0x00, 0x05, 0x0b, 0x03, 0x10, 0x11, 0x08, 0x08, + 0x05, 0x03, 0x0f, 0x05, 0x01, 0x05, 0x00, 0x2f, 0x33, 0x3f, 0x33, 0x12, + 0x39, 0x2f, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x01, 0x23, 0x11, 0x23, 0x11, 0x23, 0x11, 0x06, 0x23, 0x22, 0x26, + 0x35, 0x10, 0x36, 0x33, 0x21, 0x04, 0x60, 0x72, 0xd5, 0x73, 0x3e, 0x54, + 0xd8, 0xcb, 0xda, 0xe8, 0x02, 0x2d, 0xfe, 0xfc, 0x06, 0xb0, 0xf9, 0x50, + 0x03, 0x33, 0x12, 0xfa, 0xfb, 0x01, 0x04, 0xfe, 0x00, 0x01, 0x00, 0x98, + 0x02, 0x4c, 0x01, 0x89, 0x03, 0x5a, 0x00, 0x0b, 0x00, 0x17, 0x40, 0x0a, + 0x06, 0x00, 0x00, 0x0d, 0x0c, 0x03, 0x09, 0x4f, 0x59, 0x03, 0x00, 0x2f, + 0x2b, 0x11, 0x12, 0x01, 0x39, 0x11, 0x33, 0x31, 0x30, 0x13, 0x34, 0x36, + 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, 0x22, 0x26, 0x98, 0x3e, 0x38, + 0x3a, 0x41, 0x42, 0x39, 0x33, 0x43, 0x02, 0xd3, 0x42, 0x45, 0x45, 0x42, + 0x41, 0x46, 0x3f, 0x00, 0x00, 0x01, 0x00, 0x25, 0xfe, 0x14, 0x01, 0xb4, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x24, 0x40, 0x10, 0x11, 0x0e, 0x0b, 0x00, + 0x00, 0x0e, 0x05, 0x03, 0x13, 0x14, 0x0e, 0x11, 0x11, 0x08, 0x03, 0x10, + 0x00, 0x2f, 0xcc, 0x32, 0x39, 0x2f, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x06, 0x23, 0x22, 0x27, + 0x35, 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x27, 0x37, 0x33, 0x07, + 0x16, 0x01, 0xb4, 0x99, 0x96, 0x33, 0x2d, 0x2d, 0x3b, 0x4f, 0x51, 0x4f, + 0x6d, 0x58, 0x6e, 0x37, 0xb4, 0xfe, 0xdf, 0x61, 0x6a, 0x09, 0x6a, 0x08, + 0x28, 0x36, 0x2b, 0x35, 0x11, 0xb2, 0x73, 0x27, 0x00, 0x01, 0x00, 0x4c, + 0x02, 0x4a, 0x01, 0xe1, 0x05, 0xb6, 0x00, 0x0a, 0x00, 0x20, 0x40, 0x0e, + 0x02, 0x00, 0x03, 0x03, 0x0a, 0x0c, 0x0b, 0x09, 0x09, 0x03, 0x20, 0x06, + 0x00, 0x1e, 0x00, 0x3f, 0x32, 0x3f, 0x39, 0x2f, 0x11, 0x12, 0x01, 0x39, + 0x39, 0x11, 0x33, 0x33, 0x31, 0x30, 0x01, 0x33, 0x11, 0x23, 0x11, 0x34, + 0x37, 0x0e, 0x01, 0x07, 0x27, 0x01, 0x52, 0x8f, 0x85, 0x06, 0x16, 0x36, + 0x87, 0x43, 0x05, 0xb6, 0xfc, 0x94, 0x02, 0x43, 0x5b, 0x5a, 0x16, 0x2d, + 0x5f, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x42, 0x03, 0x14, 0x02, 0xbe, + 0x05, 0xc7, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x25, 0x40, 0x12, 0x0c, 0x06, + 0x12, 0x00, 0x06, 0x00, 0x18, 0x19, 0x0f, 0x00, 0x03, 0x10, 0x03, 0x02, + 0x03, 0x15, 0x09, 0x1f, 0x00, 0x3f, 0x33, 0xc4, 0x5d, 0x32, 0x11, 0x12, + 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x14, 0x06, + 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x05, 0x14, 0x16, + 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x02, 0xbe, 0xab, + 0x96, 0x92, 0xa9, 0xa8, 0x97, 0x98, 0xa5, 0xfd, 0xfe, 0x5b, 0x68, 0x69, + 0x5c, 0x5c, 0x69, 0x67, 0x5c, 0x04, 0x6f, 0xa4, 0xb7, 0xba, 0xa1, 0xa3, + 0xb5, 0xb6, 0xa2, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x76, 0x76, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x50, 0x00, 0x75, 0x03, 0xa8, 0x03, 0xbe, 0x00, 0x06, + 0x00, 0x0d, 0x00, 0x23, 0x40, 0x11, 0x0b, 0x09, 0x04, 0x02, 0x00, 0x03, + 0x07, 0x02, 0x0a, 0x09, 0x06, 0x0e, 0x0f, 0x0c, 0x05, 0x08, 0x01, 0x00, + 0x2f, 0x33, 0x2f, 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x09, 0x01, 0x27, 0x09, 0x01, 0x37, 0x01, 0x05, 0x01, + 0x27, 0x09, 0x01, 0x37, 0x01, 0x03, 0xa8, 0xfe, 0xa8, 0x75, 0x01, 0x1f, + 0xfe, 0xe1, 0x75, 0x01, 0x58, 0xfe, 0x75, 0xfe, 0xa8, 0x75, 0x01, 0x1f, + 0xfe, 0xe1, 0x75, 0x01, 0x58, 0x02, 0x0c, 0xfe, 0x69, 0x47, 0x01, 0x5f, + 0x01, 0x5e, 0x45, 0xfe, 0x69, 0x1b, 0xfe, 0x69, 0x47, 0x01, 0x5f, 0x01, + 0x5e, 0x45, 0xfe, 0x69, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x05, 0xd1, + 0x05, 0xb6, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x18, 0x00, 0x23, 0x00, 0x00, + 0x25, 0x23, 0x15, 0x23, 0x35, 0x21, 0x35, 0x01, 0x33, 0x11, 0x33, 0x21, + 0x35, 0x34, 0x37, 0x0e, 0x03, 0x0f, 0x01, 0x09, 0x01, 0x23, 0x01, 0x21, + 0x33, 0x11, 0x23, 0x11, 0x34, 0x37, 0x0e, 0x01, 0x07, 0x27, 0x05, 0xd1, + 0x7d, 0x91, 0xfe, 0x6e, 0x01, 0x98, 0x8b, 0x7d, 0xfe, 0xf2, 0x06, 0x05, + 0x18, 0x1e, 0x1e, 0x0b, 0xa8, 0x01, 0x55, 0xfc, 0x79, 0x8f, 0x03, 0x87, + 0xfc, 0xce, 0x8f, 0x85, 0x06, 0x16, 0x36, 0x87, 0x43, 0xcb, 0xca, 0xca, + 0x65, 0x02, 0x43, 0xfd, 0xcd, 0xc3, 0x86, 0x4b, 0x0c, 0x27, 0x2d, 0x2d, + 0x11, 0xf6, 0x04, 0x76, 0xfa, 0x4a, 0x05, 0xb6, 0xfc, 0x94, 0x02, 0x43, + 0x5b, 0x5a, 0x16, 0x2d, 0x5f, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2e, + 0x00, 0x00, 0x05, 0xdb, 0x05, 0xb6, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x27, + 0x00, 0x00, 0x09, 0x01, 0x23, 0x01, 0x21, 0x33, 0x11, 0x23, 0x11, 0x34, + 0x37, 0x0e, 0x01, 0x07, 0x27, 0x01, 0x21, 0x35, 0x37, 0x3e, 0x02, 0x35, + 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x36, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x06, 0x0f, 0x01, 0x21, 0x04, 0xce, 0xfc, 0x79, 0x8f, 0x03, 0x87, + 0xfc, 0xf5, 0x8f, 0x85, 0x06, 0x16, 0x36, 0x87, 0x43, 0x05, 0xad, 0xfd, + 0xa4, 0xec, 0x59, 0x52, 0x21, 0x50, 0x3f, 0x34, 0x62, 0x45, 0x42, 0x83, + 0x98, 0x84, 0x93, 0x59, 0x93, 0xae, 0x01, 0xb8, 0x05, 0xb6, 0xfa, 0x4a, + 0x05, 0xb6, 0xfc, 0x94, 0x02, 0x43, 0x5b, 0x5a, 0x16, 0x2d, 0x5f, 0x60, + 0xfb, 0x01, 0x68, 0xe6, 0x56, 0x61, 0x4c, 0x36, 0x44, 0x45, 0x26, 0x32, + 0x58, 0x6f, 0x82, 0x70, 0x50, 0x97, 0x8a, 0xa5, 0x00, 0x04, 0x00, 0x1a, + 0x00, 0x00, 0x06, 0x21, 0x05, 0xc9, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x18, + 0x00, 0x3c, 0x00, 0x00, 0x25, 0x23, 0x15, 0x23, 0x35, 0x21, 0x35, 0x01, + 0x33, 0x11, 0x33, 0x21, 0x35, 0x34, 0x37, 0x0e, 0x03, 0x0f, 0x01, 0x09, + 0x01, 0x23, 0x01, 0x05, 0x14, 0x06, 0x07, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x27, 0x35, 0x16, 0x33, 0x32, 0x35, 0x34, 0x2b, 0x01, 0x35, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x07, 0x27, 0x3e, 0x01, + 0x33, 0x32, 0x16, 0x06, 0x21, 0x7d, 0x91, 0xfe, 0x6e, 0x01, 0x98, 0x8b, + 0x7d, 0xfe, 0xf2, 0x06, 0x05, 0x18, 0x1e, 0x1e, 0x0b, 0xa8, 0x01, 0x61, + 0xfc, 0x79, 0x8f, 0x03, 0x87, 0xfd, 0x8d, 0x52, 0x44, 0xb0, 0xb8, 0xa8, + 0x98, 0x74, 0x93, 0x7b, 0xd3, 0xe7, 0x75, 0x77, 0x67, 0x63, 0x50, 0x43, + 0x42, 0x70, 0x38, 0x45, 0x3f, 0x8c, 0x5e, 0x88, 0x9d, 0xcb, 0xca, 0xca, + 0x65, 0x02, 0x43, 0xfd, 0xcd, 0xc3, 0x86, 0x4b, 0x0c, 0x27, 0x2d, 0x2d, + 0x11, 0xf6, 0x04, 0x76, 0xfa, 0x4a, 0x05, 0xb6, 0xcf, 0x50, 0x67, 0x17, + 0x2f, 0xa2, 0x80, 0x8f, 0x38, 0x7b, 0x44, 0xa2, 0x91, 0x6b, 0x4f, 0x44, + 0x3d, 0x44, 0x2b, 0x23, 0x5a, 0x2d, 0x36, 0x77, 0x00, 0x02, 0x00, 0x33, + 0xfe, 0x77, 0x03, 0x54, 0x04, 0x5e, 0x00, 0x1d, 0x00, 0x28, 0x00, 0x41, + 0x40, 0x22, 0x08, 0x14, 0x1e, 0x23, 0x01, 0x1c, 0x0f, 0x1c, 0x23, 0x14, + 0x04, 0x29, 0x2a, 0x00, 0x1d, 0x01, 0x0c, 0x03, 0x1d, 0x1d, 0x11, 0x26, + 0x26, 0x20, 0x4f, 0x59, 0x26, 0x10, 0x11, 0x0b, 0x49, 0x59, 0x11, 0x23, + 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, + 0x2f, 0x5f, 0x5e, 0x5d, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x15, 0x14, 0x06, 0x07, 0x0e, 0x02, + 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, 0x37, 0x17, 0x06, 0x23, 0x22, 0x26, + 0x35, 0x34, 0x3e, 0x02, 0x37, 0x3e, 0x01, 0x3d, 0x01, 0x13, 0x14, 0x23, + 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, 0x02, 0x4e, 0x4b, 0x61, + 0x79, 0x3d, 0x19, 0x84, 0x7a, 0x50, 0x96, 0x62, 0x3b, 0xc5, 0xc6, 0xbe, + 0xd8, 0x23, 0x40, 0x59, 0x36, 0x65, 0x41, 0xb4, 0x79, 0x3b, 0x3e, 0x42, + 0x37, 0x33, 0x46, 0x02, 0xac, 0x33, 0x7a, 0x94, 0x54, 0x6a, 0x4b, 0x4d, + 0x38, 0x64, 0x71, 0x26, 0x30, 0x87, 0x60, 0xba, 0xaa, 0x46, 0x69, 0x59, + 0x52, 0x2f, 0x58, 0x74, 0x5d, 0x1f, 0x01, 0x2b, 0x87, 0x45, 0x42, 0x40, + 0x47, 0x40, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x07, 0x73, 0x12, 0x26, 0x00, 0x24, 0x00, 0x00, 0x11, 0x07, 0x00, 0x43, + 0xff, 0xc2, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x02, 0x10, 0x05, 0x26, 0x00, + 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x07, 0x73, 0x12, 0x26, 0x00, 0x24, 0x00, 0x00, 0x11, 0x07, 0x00, 0x76, + 0x00, 0x85, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x02, 0x18, 0x05, 0x26, 0x00, + 0x2b, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x07, 0x73, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x00, 0x01, 0x3e, + 0x01, 0x37, 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, 0x06, 0x07, + 0x23, 0x01, 0x03, 0x21, 0x03, 0x23, 0x01, 0x33, 0x09, 0x01, 0x03, 0x26, + 0x27, 0x06, 0x07, 0x03, 0x01, 0x2f, 0x7f, 0x66, 0x17, 0xa6, 0x16, 0x6d, + 0x7d, 0x77, 0x58, 0x85, 0x88, 0x53, 0x73, 0x03, 0x31, 0xb6, 0xfd, 0xb6, + 0xb4, 0xac, 0x02, 0x42, 0x8f, 0x02, 0x3f, 0xfe, 0x65, 0xaa, 0x21, 0x23, + 0x16, 0x29, 0xac, 0x06, 0x42, 0x88, 0x80, 0x29, 0x2a, 0x85, 0x82, 0x17, + 0x37, 0x83, 0x86, 0x34, 0xf9, 0xd5, 0x01, 0xd1, 0xfe, 0x2f, 0x05, 0xbc, + 0xfa, 0x44, 0x02, 0x6a, 0x01, 0xc5, 0x56, 0x7d, 0x60, 0x73, 0xfe, 0x3b, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, 0x07, 0x2f, 0x00, 0x17, + 0x00, 0x1f, 0x00, 0x26, 0x00, 0x00, 0x01, 0x22, 0x2e, 0x02, 0x23, 0x22, + 0x06, 0x07, 0x23, 0x3e, 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, 0x32, 0x36, + 0x37, 0x33, 0x0e, 0x01, 0x13, 0x03, 0x21, 0x03, 0x23, 0x01, 0x33, 0x09, + 0x01, 0x03, 0x26, 0x27, 0x06, 0x07, 0x03, 0x03, 0x18, 0x2b, 0x52, 0x4f, + 0x49, 0x22, 0x32, 0x33, 0x0e, 0x62, 0x0d, 0x73, 0x5b, 0x2e, 0x56, 0x4e, + 0x48, 0x20, 0x31, 0x30, 0x0f, 0x63, 0x0d, 0x71, 0xea, 0xb6, 0xfd, 0xb6, + 0xb4, 0xac, 0x02, 0x42, 0x8f, 0x02, 0x3f, 0xfe, 0x65, 0xaa, 0x21, 0x23, + 0x16, 0x29, 0xac, 0x06, 0x2d, 0x25, 0x2d, 0x25, 0x3c, 0x3d, 0x79, 0x89, + 0x25, 0x2d, 0x25, 0x3b, 0x3e, 0x79, 0x89, 0xf9, 0xd3, 0x01, 0xd1, 0xfe, + 0x2f, 0x05, 0xbc, 0xfa, 0x44, 0x02, 0x6a, 0x01, 0xc5, 0x56, 0x7d, 0x60, + 0x73, 0xfe, 0x3b, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x07, 0x25, 0x12, 0x26, 0x00, 0x24, 0x00, 0x00, 0x11, 0x07, 0x00, 0x6a, + 0x00, 0x37, 0x01, 0x52, 0x00, 0x0a, 0xb4, 0x03, 0x02, 0x24, 0x05, 0x26, + 0x00, 0x2b, 0x35, 0x35, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x07, 0x06, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x00, + 0x01, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, 0x36, 0x33, 0x32, 0x16, + 0x07, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, 0x16, 0x33, 0x32, 0x36, + 0x01, 0x03, 0x21, 0x03, 0x23, 0x01, 0x33, 0x09, 0x01, 0x03, 0x26, 0x27, + 0x06, 0x07, 0x03, 0x03, 0x66, 0x7b, 0x66, 0x65, 0x78, 0x79, 0x64, 0x65, + 0x7c, 0x6c, 0x42, 0x33, 0x33, 0x42, 0x3c, 0x39, 0x34, 0x41, 0x01, 0x66, + 0xb6, 0xfd, 0xb6, 0xb4, 0xac, 0x02, 0x42, 0x8f, 0x02, 0x3f, 0xfe, 0x65, + 0xaa, 0x21, 0x23, 0x16, 0x29, 0xac, 0x06, 0x33, 0x62, 0x77, 0x75, 0x62, + 0x62, 0x73, 0x77, 0x5e, 0x38, 0x3d, 0x3d, 0x38, 0x38, 0x3d, 0x3d, 0xfa, + 0x07, 0x01, 0xd1, 0xfe, 0x2f, 0x05, 0xbc, 0xfa, 0x44, 0x02, 0x6a, 0x01, + 0xc5, 0x56, 0x7d, 0x60, 0x73, 0xfe, 0x3b, 0x00, 0x00, 0x02, 0xff, 0xfe, + 0x00, 0x00, 0x06, 0x81, 0x05, 0xb6, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x4e, + 0x40, 0x2c, 0x0a, 0x0e, 0x0e, 0x11, 0x01, 0x00, 0x08, 0x0c, 0x01, 0x10, + 0x05, 0x05, 0x15, 0x05, 0x14, 0x09, 0x13, 0x06, 0x13, 0x49, 0x59, 0x10, + 0x03, 0x49, 0x59, 0x0a, 0x0d, 0x49, 0x59, 0x10, 0x0a, 0x10, 0x0a, 0x01, + 0x06, 0x03, 0x05, 0x12, 0x01, 0x0e, 0x49, 0x59, 0x01, 0x12, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x3f, 0x12, 0x39, 0x39, 0x2f, 0x2f, 0x2b, 0x2b, + 0x2b, 0x11, 0x00, 0x33, 0x11, 0x01, 0x33, 0x11, 0x12, 0x17, 0x39, 0x11, + 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x29, 0x01, 0x11, 0x21, 0x03, 0x23, + 0x01, 0x21, 0x15, 0x21, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x01, 0x21, + 0x11, 0x23, 0x06, 0x81, 0xfd, 0x12, 0xfd, 0xfe, 0xe3, 0xb0, 0x02, 0xba, + 0x03, 0xc9, 0xfd, 0xbc, 0x02, 0x1d, 0xfd, 0xe3, 0x02, 0x44, 0xfb, 0x54, + 0x01, 0xbe, 0x76, 0x01, 0xd1, 0xfe, 0x2f, 0x05, 0xb6, 0x97, 0xfe, 0x29, + 0x96, 0xfd, 0xe6, 0x01, 0xd2, 0x02, 0xb5, 0x00, 0xff, 0xff, 0x00, 0x7d, + 0xfe, 0x14, 0x04, 0xcf, 0x05, 0xcb, 0x12, 0x26, 0x00, 0x26, 0x00, 0x00, + 0x10, 0x07, 0x00, 0x7a, 0x02, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0xc9, + 0x00, 0x00, 0x03, 0xf8, 0x07, 0x73, 0x12, 0x26, 0x00, 0x28, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x43, 0xff, 0xb7, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x0d, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0xc9, + 0x00, 0x00, 0x03, 0xf8, 0x07, 0x73, 0x12, 0x26, 0x00, 0x28, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x76, 0x00, 0x3f, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x15, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0xc9, + 0x00, 0x00, 0x03, 0xf8, 0x07, 0x73, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x00, + 0x01, 0x3e, 0x01, 0x37, 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, + 0x06, 0x07, 0x23, 0x01, 0x21, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x15, + 0x21, 0x11, 0x21, 0x01, 0x07, 0x7f, 0x66, 0x17, 0xa6, 0x16, 0x6d, 0x7d, + 0x77, 0x58, 0x85, 0x88, 0x53, 0x73, 0x02, 0xf1, 0xfc, 0xd1, 0x03, 0x2f, + 0xfd, 0x7b, 0x02, 0x5e, 0xfd, 0xa2, 0x02, 0x85, 0x06, 0x42, 0x88, 0x80, + 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, 0x86, 0x34, 0xf9, 0xd5, 0x05, + 0xb6, 0x97, 0xfe, 0x29, 0x96, 0xfd, 0xe6, 0x00, 0xff, 0xff, 0x00, 0xc9, + 0x00, 0x00, 0x03, 0xf8, 0x07, 0x25, 0x12, 0x26, 0x00, 0x28, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x6a, 0x00, 0x12, 0x01, 0x52, 0x00, 0x0a, 0xb4, 0x02, + 0x01, 0x21, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x35, 0xff, 0xff, 0x00, 0x05, + 0x00, 0x00, 0x01, 0x8e, 0x07, 0x73, 0x12, 0x26, 0x00, 0x2c, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x43, 0xfe, 0x7c, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x05, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0xb3, + 0x00, 0x00, 0x02, 0x3c, 0x07, 0x73, 0x12, 0x26, 0x00, 0x2c, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x76, 0xff, 0x2a, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x0d, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc7, + 0x00, 0x00, 0x02, 0x69, 0x07, 0x73, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x00, + 0x03, 0x3e, 0x01, 0x37, 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, + 0x06, 0x07, 0x23, 0x01, 0x11, 0x33, 0x11, 0x39, 0x7f, 0x66, 0x17, 0xa6, + 0x16, 0x6d, 0x7d, 0x77, 0x58, 0x85, 0x88, 0x53, 0x73, 0x01, 0x02, 0xaa, + 0x06, 0x42, 0x88, 0x80, 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, 0x86, + 0x34, 0xf9, 0xd5, 0x05, 0xb6, 0xfa, 0x4a, 0x00, 0xff, 0xff, 0x00, 0x05, + 0x00, 0x00, 0x02, 0x38, 0x07, 0x25, 0x12, 0x26, 0x00, 0x2c, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x6a, 0xfe, 0xd0, 0x01, 0x52, 0x00, 0x0a, 0xb4, 0x02, + 0x01, 0x19, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x02, 0x00, 0x2f, + 0x00, 0x00, 0x05, 0x48, 0x05, 0xb6, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x57, + 0x40, 0x32, 0x11, 0x15, 0x15, 0x08, 0x04, 0x0d, 0x00, 0x00, 0x13, 0x04, + 0x06, 0x04, 0x18, 0x19, 0x14, 0x06, 0x07, 0x06, 0x49, 0x59, 0x11, 0x0f, + 0x07, 0x3f, 0x07, 0xaf, 0x07, 0xcf, 0x07, 0xdf, 0x07, 0x05, 0x0b, 0x03, + 0x07, 0x07, 0x04, 0x09, 0x09, 0x10, 0x4a, 0x59, 0x09, 0x03, 0x04, 0x15, + 0x4a, 0x59, 0x04, 0x12, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, 0x11, + 0x12, 0x00, 0x39, 0x18, 0x2f, 0x5f, 0x5e, 0x5d, 0x33, 0x2b, 0x11, 0x00, + 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x10, 0x00, 0x29, 0x01, 0x11, 0x23, 0x35, 0x33, + 0x11, 0x21, 0x20, 0x00, 0x03, 0x10, 0x21, 0x23, 0x11, 0x21, 0x15, 0x21, + 0x11, 0x33, 0x20, 0x05, 0x48, 0xfe, 0x77, 0xfe, 0x8f, 0xfe, 0x7b, 0x9a, + 0x9a, 0x01, 0xb2, 0x01, 0x51, 0x01, 0x7c, 0xb5, 0xfd, 0xc7, 0xe7, 0x01, + 0x7b, 0xfe, 0x85, 0xbe, 0x02, 0x62, 0x02, 0xe9, 0xfe, 0x96, 0xfe, 0x81, + 0x02, 0x89, 0x96, 0x02, 0x97, 0xfe, 0x89, 0xfe, 0xa4, 0x02, 0x40, 0xfd, + 0xfc, 0x96, 0xfe, 0x0a, 0x00, 0x02, 0x00, 0xc9, 0x00, 0x00, 0x05, 0x3f, + 0x07, 0x2f, 0x00, 0x17, 0x00, 0x28, 0x00, 0x00, 0x01, 0x22, 0x2e, 0x02, + 0x23, 0x22, 0x06, 0x07, 0x23, 0x3e, 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, + 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, 0x01, 0x23, 0x01, 0x23, 0x16, 0x15, + 0x11, 0x23, 0x11, 0x33, 0x01, 0x33, 0x26, 0x02, 0x37, 0x11, 0x33, 0x03, + 0xa7, 0x2b, 0x52, 0x4f, 0x49, 0x22, 0x32, 0x33, 0x0e, 0x62, 0x0d, 0x73, + 0x5b, 0x2e, 0x56, 0x4e, 0x48, 0x20, 0x31, 0x30, 0x0f, 0x63, 0x0d, 0x71, + 0x01, 0x3a, 0xc2, 0xfc, 0xe1, 0x08, 0x10, 0x9d, 0xc0, 0x03, 0x1d, 0x08, + 0x02, 0x0e, 0x02, 0x9f, 0x06, 0x2d, 0x25, 0x2d, 0x25, 0x3c, 0x3d, 0x79, + 0x89, 0x25, 0x2d, 0x25, 0x3b, 0x3e, 0x79, 0x89, 0xf9, 0xd3, 0x04, 0xcb, + 0xd8, 0xb4, 0xfc, 0xc1, 0x05, 0xb6, 0xfb, 0x3a, 0x1b, 0x01, 0x25, 0x3f, + 0x03, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x7d, 0xff, 0xec, 0x05, 0xbe, + 0x07, 0x73, 0x12, 0x26, 0x00, 0x32, 0x00, 0x00, 0x11, 0x07, 0x00, 0x43, + 0x00, 0x79, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x02, 0x19, 0x05, 0x26, 0x00, + 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0x7d, 0xff, 0xec, 0x05, 0xbe, + 0x07, 0x73, 0x12, 0x26, 0x00, 0x32, 0x00, 0x00, 0x11, 0x07, 0x00, 0x76, + 0x01, 0x0a, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x02, 0x21, 0x05, 0x26, 0x00, + 0x2b, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x7d, 0xff, 0xec, 0x05, 0xbe, + 0x07, 0x73, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x26, 0x00, 0x00, 0x01, 0x3e, + 0x01, 0x37, 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, 0x06, 0x07, + 0x23, 0x01, 0x10, 0x00, 0x21, 0x20, 0x00, 0x11, 0x10, 0x00, 0x21, 0x20, + 0x00, 0x01, 0x10, 0x12, 0x33, 0x32, 0x12, 0x11, 0x10, 0x02, 0x23, 0x22, + 0x02, 0x01, 0xc0, 0x7f, 0x66, 0x17, 0xa6, 0x16, 0x6d, 0x7d, 0x77, 0x58, + 0x85, 0x88, 0x53, 0x73, 0x03, 0xfe, 0xfe, 0x9d, 0xfe, 0xc4, 0xfe, 0xbd, + 0xfe, 0xa1, 0x01, 0x60, 0x01, 0x44, 0x01, 0x3b, 0x01, 0x62, 0xfb, 0x73, + 0xfd, 0xf1, 0xf3, 0xf8, 0xf7, 0xf2, 0xf3, 0xfd, 0x06, 0x42, 0x88, 0x80, + 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, 0x86, 0x34, 0xfc, 0xb2, 0xfe, + 0xa1, 0xfe, 0x6e, 0x01, 0x8b, 0x01, 0x68, 0x01, 0x65, 0x01, 0x89, 0xfe, + 0x70, 0xfe, 0xa0, 0xfe, 0xd7, 0xfe, 0xcd, 0x01, 0x32, 0x01, 0x2a, 0x01, + 0x27, 0x01, 0x31, 0xfe, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x7d, + 0xff, 0xec, 0x05, 0xbe, 0x07, 0x2f, 0x00, 0x17, 0x00, 0x23, 0x00, 0x2f, + 0x00, 0x00, 0x01, 0x22, 0x2e, 0x02, 0x23, 0x22, 0x06, 0x07, 0x23, 0x3e, + 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, + 0x01, 0x10, 0x00, 0x21, 0x20, 0x00, 0x11, 0x10, 0x00, 0x21, 0x20, 0x00, + 0x01, 0x10, 0x12, 0x33, 0x32, 0x12, 0x11, 0x10, 0x02, 0x23, 0x22, 0x02, + 0x03, 0xae, 0x2b, 0x52, 0x4f, 0x49, 0x22, 0x32, 0x33, 0x0e, 0x62, 0x0d, + 0x73, 0x5b, 0x2e, 0x56, 0x4e, 0x48, 0x20, 0x31, 0x30, 0x0f, 0x63, 0x0d, + 0x71, 0x01, 0xb2, 0xfe, 0x9d, 0xfe, 0xc4, 0xfe, 0xbd, 0xfe, 0xa1, 0x01, + 0x60, 0x01, 0x44, 0x01, 0x3b, 0x01, 0x62, 0xfb, 0x73, 0xfd, 0xf1, 0xf3, + 0xf8, 0xf7, 0xf2, 0xf3, 0xfd, 0x06, 0x2d, 0x25, 0x2d, 0x25, 0x3c, 0x3d, + 0x79, 0x89, 0x25, 0x2d, 0x25, 0x3b, 0x3e, 0x79, 0x89, 0xfc, 0xb0, 0xfe, + 0xa1, 0xfe, 0x6e, 0x01, 0x8b, 0x01, 0x68, 0x01, 0x65, 0x01, 0x89, 0xfe, + 0x70, 0xfe, 0xa0, 0xfe, 0xd7, 0xfe, 0xcd, 0x01, 0x32, 0x01, 0x2a, 0x01, + 0x27, 0x01, 0x31, 0xfe, 0xcd, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x7d, + 0xff, 0xec, 0x05, 0xbe, 0x07, 0x25, 0x12, 0x26, 0x00, 0x32, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x6a, 0x00, 0xd5, 0x01, 0x52, 0x00, 0x0a, 0xb4, 0x03, + 0x02, 0x2d, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x01, 0x00, 0x85, + 0x01, 0x10, 0x04, 0x0c, 0x04, 0x98, 0x00, 0x0b, 0x00, 0x19, 0x40, 0x09, + 0x07, 0x09, 0x03, 0x01, 0x09, 0x01, 0x0c, 0x0d, 0x08, 0x00, 0x19, 0x2f, + 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, + 0x17, 0x09, 0x01, 0x07, 0x09, 0x01, 0x27, 0x09, 0x01, 0x37, 0x01, 0x03, + 0xac, 0x60, 0xfe, 0xa0, 0x01, 0x5e, 0x60, 0xfe, 0x9e, 0xfe, 0xa4, 0x65, + 0x01, 0x5e, 0xfe, 0xa0, 0x64, 0x01, 0x61, 0x04, 0x98, 0x63, 0xfe, 0x9e, + 0xfe, 0xa0, 0x63, 0x01, 0x5f, 0xfe, 0xa1, 0x63, 0x01, 0x60, 0x01, 0x60, + 0x65, 0xfe, 0x9d, 0x00, 0x00, 0x03, 0x00, 0x7d, 0xff, 0xc3, 0x05, 0xbe, + 0x05, 0xf6, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x23, 0x00, 0x4e, 0x40, 0x2c, + 0x16, 0x1f, 0x17, 0x1e, 0x04, 0x1c, 0x14, 0x1c, 0x0a, 0x14, 0x00, 0x00, + 0x12, 0x0f, 0x05, 0x08, 0x0a, 0x06, 0x24, 0x25, 0x16, 0x1e, 0x21, 0x19, + 0x0d, 0x21, 0x49, 0x59, 0x0f, 0x12, 0x08, 0x05, 0x04, 0x03, 0x10, 0x0d, + 0x04, 0x03, 0x19, 0x49, 0x59, 0x06, 0x03, 0x13, 0x00, 0x3f, 0xc6, 0x2b, + 0x00, 0x18, 0x3f, 0xc6, 0x12, 0x17, 0x39, 0x2b, 0x11, 0x12, 0x00, 0x39, + 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x12, + 0x17, 0x39, 0x31, 0x30, 0x01, 0x10, 0x00, 0x21, 0x22, 0x27, 0x07, 0x27, + 0x37, 0x26, 0x11, 0x10, 0x00, 0x21, 0x32, 0x17, 0x37, 0x17, 0x07, 0x16, + 0x03, 0x10, 0x27, 0x01, 0x16, 0x33, 0x32, 0x12, 0x01, 0x10, 0x17, 0x01, + 0x26, 0x23, 0x22, 0x02, 0x05, 0xbe, 0xfe, 0x9d, 0xfe, 0xc4, 0xeb, 0x94, + 0x65, 0x78, 0x6c, 0xb2, 0x01, 0x60, 0x01, 0x44, 0xd1, 0x9d, 0x61, 0x78, + 0x6a, 0xc0, 0xb4, 0x6e, 0xfd, 0x60, 0x73, 0xb0, 0xf3, 0xf8, 0xfc, 0x27, + 0x65, 0x02, 0x9d, 0x6a, 0xa8, 0xf3, 0xfd, 0x02, 0xdd, 0xfe, 0xa1, 0xfe, + 0x6e, 0x64, 0x8d, 0x4f, 0x9a, 0xc6, 0x01, 0x6d, 0x01, 0x65, 0x01, 0x89, + 0x5e, 0x87, 0x50, 0x94, 0xca, 0xfe, 0x95, 0x01, 0x10, 0x9a, 0xfc, 0x4c, + 0x52, 0x01, 0x32, 0x01, 0x2a, 0xfe, 0xfa, 0x9a, 0x03, 0xaf, 0x49, 0xfe, + 0xcd, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xba, 0xff, 0xec, 0x05, 0x19, + 0x07, 0x73, 0x12, 0x26, 0x00, 0x38, 0x00, 0x00, 0x11, 0x07, 0x00, 0x43, + 0x00, 0x46, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, 0x13, 0x05, 0x26, 0x00, + 0x2b, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0xba, 0xff, 0xec, 0x05, 0x19, + 0x07, 0x73, 0x12, 0x26, 0x00, 0x38, 0x00, 0x00, 0x11, 0x07, 0x00, 0x76, + 0x00, 0xcf, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, 0x1b, 0x05, 0x26, 0x00, + 0x2b, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0xba, 0xff, 0xec, 0x05, 0x19, + 0x07, 0x73, 0x00, 0x0e, 0x00, 0x20, 0x00, 0x00, 0x01, 0x3e, 0x01, 0x37, + 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, 0x06, 0x07, 0x23, 0x05, + 0x11, 0x14, 0x00, 0x21, 0x20, 0x00, 0x35, 0x11, 0x33, 0x11, 0x14, 0x16, + 0x33, 0x32, 0x36, 0x35, 0x11, 0x01, 0x89, 0x7f, 0x66, 0x17, 0xa6, 0x16, + 0x6d, 0x7d, 0x77, 0x58, 0x85, 0x88, 0x53, 0x73, 0x03, 0x90, 0xfe, 0xd2, + 0xfe, 0xf8, 0xfe, 0xf8, 0xfe, 0xdf, 0xaa, 0xc8, 0xc2, 0xb9, 0xc8, 0x06, + 0x42, 0x88, 0x80, 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, 0x86, 0x34, + 0x75, 0xfc, 0x4e, 0xfa, 0xfe, 0xe2, 0x01, 0x20, 0xfc, 0x03, 0xae, 0xfc, + 0x46, 0xb7, 0xc4, 0xc5, 0xb8, 0x03, 0xb8, 0x00, 0xff, 0xff, 0x00, 0xba, + 0xff, 0xec, 0x05, 0x19, 0x07, 0x25, 0x12, 0x26, 0x00, 0x38, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x6a, 0x00, 0x98, 0x01, 0x52, 0x00, 0x0a, 0xb4, 0x02, + 0x01, 0x27, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x35, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x7b, 0x07, 0x73, 0x12, 0x26, 0x00, 0x3c, 0x00, 0x00, + 0x11, 0x07, 0x00, 0x76, 0x00, 0x31, 0x01, 0x52, 0x00, 0x08, 0xb3, 0x01, + 0x12, 0x05, 0x26, 0x00, 0x2b, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0xc9, + 0x00, 0x00, 0x04, 0x79, 0x05, 0xb6, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x36, + 0x40, 0x1c, 0x0d, 0x09, 0x05, 0x05, 0x06, 0x11, 0x00, 0x06, 0x00, 0x16, + 0x17, 0x0d, 0x04, 0x4a, 0x59, 0x09, 0x15, 0x4a, 0x59, 0x0d, 0x09, 0x0d, + 0x09, 0x06, 0x07, 0x03, 0x06, 0x12, 0x00, 0x3f, 0x3f, 0x12, 0x39, 0x39, + 0x2f, 0x2f, 0x2b, 0x2b, 0x11, 0x12, 0x01, 0x39, 0x39, 0x11, 0x33, 0x11, + 0x33, 0x11, 0x33, 0x33, 0x31, 0x30, 0x01, 0x14, 0x04, 0x21, 0x23, 0x11, + 0x23, 0x11, 0x33, 0x11, 0x33, 0x20, 0x04, 0x01, 0x33, 0x32, 0x36, 0x35, + 0x34, 0x26, 0x2b, 0x01, 0x04, 0x79, 0xfe, 0xd1, 0xfe, 0xe1, 0xb8, 0xaa, + 0xaa, 0xd7, 0x01, 0x19, 0x01, 0x16, 0xfc, 0xfa, 0xa8, 0xe2, 0xca, 0xbe, + 0xca, 0xcc, 0x03, 0x10, 0xe3, 0xee, 0xfe, 0xc1, 0x05, 0xb6, 0xff, 0x00, + 0xcf, 0xfd, 0xea, 0x8f, 0xa4, 0x95, 0x8a, 0x00, 0x00, 0x01, 0x00, 0xb0, + 0xff, 0xec, 0x04, 0x9c, 0x06, 0x1f, 0x00, 0x30, 0x00, 0x41, 0x40, 0x22, + 0x29, 0x2a, 0x05, 0x1d, 0x23, 0x00, 0x17, 0x0c, 0x0c, 0x00, 0x1d, 0x11, + 0x2a, 0x05, 0x31, 0x32, 0x12, 0x12, 0x2a, 0x2e, 0x2e, 0x26, 0x46, 0x59, + 0x2e, 0x00, 0x2a, 0x15, 0x0f, 0x15, 0x46, 0x59, 0x0f, 0x16, 0x00, 0x3f, + 0x2b, 0x00, 0x18, 0x3f, 0x3f, 0x2b, 0x11, 0x12, 0x00, 0x39, 0x18, 0x2f, + 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x11, 0x33, 0x11, 0x33, 0x11, + 0x33, 0x31, 0x30, 0x01, 0x14, 0x07, 0x0e, 0x01, 0x15, 0x14, 0x1e, 0x01, + 0x17, 0x1e, 0x01, 0x15, 0x14, 0x06, 0x23, 0x22, 0x27, 0x35, 0x1e, 0x01, + 0x33, 0x32, 0x35, 0x34, 0x26, 0x27, 0x2e, 0x01, 0x35, 0x34, 0x36, 0x37, + 0x3e, 0x01, 0x35, 0x34, 0x26, 0x23, 0x20, 0x15, 0x11, 0x23, 0x11, 0x34, + 0x36, 0x33, 0x32, 0x16, 0x04, 0x19, 0x8f, 0x58, 0x38, 0x1b, 0x47, 0x4e, + 0x8c, 0x66, 0xc2, 0xb3, 0xbc, 0x6b, 0x3f, 0x9c, 0x48, 0xd7, 0x53, 0x6e, + 0x7f, 0x60, 0x45, 0x47, 0x4b, 0x40, 0x88, 0x7f, 0xfe, 0xec, 0xa6, 0xdc, + 0xde, 0xce, 0xe1, 0x04, 0xf2, 0x87, 0x73, 0x46, 0x43, 0x21, 0x20, 0x2a, + 0x39, 0x33, 0x5f, 0x9d, 0x65, 0xa0, 0xab, 0x45, 0x9a, 0x27, 0x2f, 0xb6, + 0x4b, 0x6b, 0x46, 0x52, 0x7b, 0x54, 0x3f, 0x6a, 0x35, 0x39, 0x5a, 0x35, + 0x50, 0x55, 0xdf, 0xfb, 0x4c, 0x04, 0xb2, 0xb2, 0xbb, 0x9d, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x5e, 0xff, 0xec, 0x03, 0xcd, 0x06, 0x21, 0x12, 0x26, + 0x00, 0x44, 0x00, 0x00, 0x11, 0x06, 0x00, 0x43, 0x8e, 0x00, 0x00, 0x08, + 0xb3, 0x02, 0x26, 0x11, 0x26, 0x00, 0x2b, 0x35, 0xff, 0xff, 0x00, 0x5e, + 0xff, 0xec, 0x03, 0xcd, 0x06, 0x21, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x76, 0x2b, 0x00, 0x00, 0x08, 0xb3, 0x02, 0x2e, 0x11, + 0x26, 0x00, 0x2b, 0x35, 0x00, 0x03, 0x00, 0x5e, 0xff, 0xec, 0x03, 0xcd, + 0x06, 0x21, 0x00, 0x0e, 0x00, 0x28, 0x00, 0x33, 0x00, 0x00, 0x13, 0x3e, + 0x01, 0x37, 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, 0x06, 0x07, + 0x23, 0x01, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x10, 0x25, + 0x37, 0x35, 0x34, 0x26, 0x23, 0x22, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, + 0x16, 0x15, 0x11, 0x25, 0x32, 0x36, 0x3d, 0x01, 0x07, 0x0e, 0x01, 0x15, + 0x14, 0x16, 0xe4, 0x7f, 0x66, 0x17, 0xa6, 0x16, 0x6d, 0x7d, 0x77, 0x58, + 0x85, 0x88, 0x53, 0x73, 0x02, 0x6e, 0x21, 0x08, 0x52, 0xa3, 0x7a, 0xa3, + 0xb9, 0x02, 0x13, 0xba, 0x6f, 0x7a, 0x89, 0xad, 0x33, 0x51, 0xc1, 0x61, + 0xc4, 0xbd, 0xfe, 0x0e, 0x9b, 0xb1, 0xa6, 0xc6, 0xaf, 0x6d, 0x04, 0xf0, + 0x88, 0x80, 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, 0x86, 0x34, 0xfb, + 0x27, 0x9c, 0x67, 0x49, 0xa8, 0x9b, 0x01, 0x4c, 0x10, 0x06, 0x44, 0x81, + 0x7b, 0x54, 0x7f, 0x2c, 0x32, 0xae, 0xc0, 0xfd, 0x14, 0x75, 0xaa, 0x99, + 0x63, 0x07, 0x07, 0x6d, 0x73, 0x5a, 0x5e, 0x00, 0x00, 0x03, 0x00, 0x5e, + 0xff, 0xec, 0x03, 0xcd, 0x05, 0xdd, 0x00, 0x17, 0x00, 0x31, 0x00, 0x3c, + 0x00, 0x00, 0x01, 0x22, 0x2e, 0x02, 0x23, 0x22, 0x06, 0x07, 0x23, 0x3e, + 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, + 0x13, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x10, 0x25, 0x37, + 0x35, 0x34, 0x26, 0x23, 0x22, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, + 0x15, 0x11, 0x25, 0x32, 0x36, 0x3d, 0x01, 0x07, 0x0e, 0x01, 0x15, 0x14, + 0x16, 0x02, 0xd1, 0x2b, 0x52, 0x4f, 0x49, 0x22, 0x32, 0x33, 0x0e, 0x62, + 0x0d, 0x73, 0x5b, 0x2e, 0x56, 0x4e, 0x48, 0x20, 0x31, 0x30, 0x0f, 0x63, + 0x0d, 0x71, 0x23, 0x21, 0x08, 0x52, 0xa3, 0x7a, 0xa3, 0xb9, 0x02, 0x13, + 0xba, 0x6f, 0x7a, 0x89, 0xad, 0x33, 0x51, 0xc1, 0x61, 0xc4, 0xbd, 0xfe, + 0x0e, 0x9b, 0xb1, 0xa6, 0xc6, 0xaf, 0x6d, 0x04, 0xdb, 0x25, 0x2d, 0x25, + 0x3c, 0x3d, 0x79, 0x89, 0x25, 0x2d, 0x25, 0x3b, 0x3e, 0x79, 0x89, 0xfb, + 0x25, 0x9c, 0x67, 0x49, 0xa8, 0x9b, 0x01, 0x4c, 0x10, 0x06, 0x44, 0x81, + 0x7b, 0x54, 0x7f, 0x2c, 0x32, 0xae, 0xc0, 0xfd, 0x14, 0x75, 0xaa, 0x99, + 0x63, 0x07, 0x07, 0x6d, 0x73, 0x5a, 0x5e, 0x00, 0xff, 0xff, 0x00, 0x5e, + 0xff, 0xec, 0x03, 0xcd, 0x05, 0xd3, 0x12, 0x26, 0x00, 0x44, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x6a, 0xe2, 0x00, 0x00, 0x0a, 0xb4, 0x03, 0x02, 0x3a, + 0x11, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x00, 0x00, 0x04, 0x00, 0x5e, + 0xff, 0xec, 0x03, 0xcd, 0x06, 0x85, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x31, + 0x00, 0x3c, 0x00, 0x00, 0x01, 0x14, 0x06, 0x23, 0x22, 0x26, 0x35, 0x34, + 0x36, 0x33, 0x32, 0x16, 0x07, 0x34, 0x26, 0x23, 0x22, 0x06, 0x15, 0x14, + 0x16, 0x33, 0x32, 0x36, 0x13, 0x27, 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, + 0x35, 0x10, 0x25, 0x37, 0x35, 0x34, 0x26, 0x23, 0x22, 0x07, 0x27, 0x3e, + 0x01, 0x33, 0x32, 0x16, 0x15, 0x11, 0x25, 0x32, 0x36, 0x3d, 0x01, 0x07, + 0x0e, 0x01, 0x15, 0x14, 0x16, 0x03, 0x24, 0x7b, 0x66, 0x65, 0x78, 0x79, + 0x64, 0x65, 0x7c, 0x6c, 0x42, 0x33, 0x33, 0x42, 0x3c, 0x39, 0x34, 0x41, + 0x9a, 0x21, 0x08, 0x52, 0xa3, 0x7a, 0xa3, 0xb9, 0x02, 0x13, 0xba, 0x6f, + 0x7a, 0x89, 0xad, 0x33, 0x51, 0xc1, 0x61, 0xc4, 0xbd, 0xfe, 0x0e, 0x9b, + 0xb1, 0xa6, 0xc6, 0xaf, 0x6d, 0x05, 0xb2, 0x62, 0x77, 0x75, 0x62, 0x62, + 0x73, 0x77, 0x5e, 0x38, 0x3d, 0x3d, 0x38, 0x38, 0x3d, 0x3d, 0xfa, 0x88, + 0x9c, 0x67, 0x49, 0xa8, 0x9b, 0x01, 0x4c, 0x10, 0x06, 0x44, 0x81, 0x7b, + 0x54, 0x7f, 0x2c, 0x32, 0xae, 0xc0, 0xfd, 0x14, 0x75, 0xaa, 0x99, 0x63, + 0x07, 0x07, 0x6d, 0x73, 0x5a, 0x5e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x5e, + 0xff, 0xec, 0x06, 0x73, 0x04, 0x5c, 0x00, 0x29, 0x00, 0x34, 0x00, 0x3b, + 0x00, 0x61, 0x40, 0x33, 0x2a, 0x00, 0x24, 0x11, 0x30, 0x38, 0x19, 0x19, + 0x04, 0x30, 0x39, 0x18, 0x18, 0x1f, 0x30, 0x0b, 0x00, 0x05, 0x3c, 0x3d, + 0x1b, 0x2d, 0x27, 0x2d, 0x46, 0x59, 0x19, 0x31, 0x04, 0x31, 0x47, 0x59, + 0x38, 0x24, 0x27, 0x11, 0x04, 0x04, 0x0e, 0x22, 0x27, 0x16, 0x35, 0x08, + 0x0e, 0x08, 0x46, 0x59, 0x14, 0x0e, 0x10, 0x00, 0x3f, 0x33, 0x2b, 0x11, + 0x00, 0x33, 0x18, 0x3f, 0x33, 0x12, 0x39, 0x2f, 0x39, 0x12, 0x39, 0x33, + 0x2b, 0x11, 0x00, 0x33, 0x2b, 0x11, 0x00, 0x33, 0x11, 0x12, 0x01, 0x17, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x12, 0x39, 0x39, 0x11, + 0x33, 0x31, 0x30, 0x13, 0x34, 0x36, 0x3f, 0x01, 0x35, 0x34, 0x26, 0x23, + 0x22, 0x07, 0x27, 0x3e, 0x01, 0x33, 0x32, 0x16, 0x17, 0x3e, 0x01, 0x33, + 0x32, 0x12, 0x1d, 0x01, 0x21, 0x12, 0x21, 0x32, 0x36, 0x37, 0x15, 0x0e, + 0x01, 0x23, 0x20, 0x27, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x37, 0x14, 0x16, + 0x33, 0x32, 0x36, 0x3d, 0x01, 0x07, 0x0e, 0x01, 0x01, 0x22, 0x06, 0x07, + 0x21, 0x34, 0x26, 0x5e, 0xf8, 0xfe, 0xb8, 0x74, 0x77, 0x90, 0xa3, 0x34, + 0x4a, 0xc7, 0x62, 0x82, 0xa5, 0x29, 0x35, 0xab, 0x6e, 0xc0, 0xe8, 0xfd, + 0x43, 0x08, 0x01, 0x3a, 0x5b, 0x9d, 0x54, 0x56, 0x95, 0x65, 0xfe, 0xdf, + 0x7d, 0x51, 0xc5, 0x86, 0xa3, 0xb9, 0xae, 0x6b, 0x58, 0x91, 0xa8, 0x9e, + 0xba, 0xa4, 0x03, 0xbd, 0x79, 0x8b, 0x0b, 0x02, 0x07, 0x80, 0x01, 0x2f, + 0xa1, 0xb3, 0x08, 0x06, 0x44, 0x81, 0x7b, 0x54, 0x7f, 0x29, 0x35, 0x57, + 0x5f, 0x58, 0x60, 0xfe, 0xf5, 0xde, 0x6b, 0xfe, 0x75, 0x23, 0x27, 0x94, + 0x26, 0x21, 0xe9, 0x7f, 0x6a, 0xaa, 0x97, 0x5f, 0x59, 0xa9, 0x9a, 0x63, + 0x07, 0x08, 0x6d, 0x02, 0x32, 0xa6, 0x9e, 0x9c, 0xa8, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x73, 0xfe, 0x14, 0x03, 0x8b, 0x04, 0x5c, 0x12, 0x26, + 0x00, 0x46, 0x00, 0x00, 0x10, 0x07, 0x00, 0x7a, 0x01, 0x46, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x73, 0xff, 0xec, 0x04, 0x12, 0x06, 0x21, 0x12, 0x26, + 0x00, 0x48, 0x00, 0x00, 0x11, 0x06, 0x00, 0x43, 0xb5, 0x00, 0x00, 0x08, + 0xb3, 0x02, 0x1c, 0x11, 0x26, 0x00, 0x2b, 0x35, 0xff, 0xff, 0x00, 0x73, + 0xff, 0xec, 0x04, 0x12, 0x06, 0x21, 0x12, 0x26, 0x00, 0x48, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x76, 0x4e, 0x00, 0x00, 0x08, 0xb3, 0x02, 0x24, 0x11, + 0x26, 0x00, 0x2b, 0x35, 0x00, 0x03, 0x00, 0x73, 0xff, 0xec, 0x04, 0x12, + 0x06, 0x21, 0x00, 0x0e, 0x00, 0x22, 0x00, 0x29, 0x00, 0x00, 0x01, 0x3e, + 0x01, 0x37, 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, 0x06, 0x07, + 0x23, 0x01, 0x22, 0x00, 0x11, 0x10, 0x00, 0x33, 0x32, 0x12, 0x1d, 0x01, + 0x21, 0x1e, 0x01, 0x33, 0x32, 0x37, 0x15, 0x0e, 0x01, 0x03, 0x22, 0x06, + 0x07, 0x21, 0x34, 0x26, 0x01, 0x03, 0x7f, 0x66, 0x17, 0xa6, 0x16, 0x6d, + 0x7d, 0x77, 0x58, 0x85, 0x88, 0x53, 0x73, 0x01, 0x7c, 0xf3, 0xfe, 0xe7, + 0x01, 0x05, 0xdc, 0xce, 0xf0, 0xfd, 0x0d, 0x05, 0xb9, 0xa8, 0xb1, 0xad, + 0x58, 0x9d, 0x9c, 0x84, 0x9d, 0x0e, 0x02, 0x3d, 0x8c, 0x04, 0xf0, 0x88, + 0x80, 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, 0x86, 0x34, 0xfb, 0x13, + 0x01, 0x28, 0x01, 0x07, 0x01, 0x09, 0x01, 0x38, 0xfe, 0xf1, 0xde, 0x69, + 0xc1, 0xc8, 0x4a, 0x94, 0x26, 0x21, 0x03, 0xe5, 0xac, 0x98, 0x9d, 0xa7, + 0xff, 0xff, 0x00, 0x73, 0xff, 0xec, 0x04, 0x12, 0x05, 0xd3, 0x12, 0x26, + 0x00, 0x48, 0x00, 0x00, 0x11, 0x06, 0x00, 0x6a, 0x0a, 0x00, 0x00, 0x0a, + 0xb4, 0x03, 0x02, 0x30, 0x11, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x00, + 0x00, 0x02, 0xff, 0xda, 0x00, 0x00, 0x01, 0x63, 0x06, 0x21, 0x00, 0x03, + 0x00, 0x0d, 0x00, 0x00, 0x21, 0x23, 0x11, 0x33, 0x37, 0x23, 0x2e, 0x01, + 0x27, 0x35, 0x33, 0x1e, 0x01, 0x17, 0x01, 0x56, 0xa6, 0xa6, 0x0d, 0x6e, + 0x41, 0xb2, 0x28, 0xcb, 0x20, 0x72, 0x2c, 0x04, 0x48, 0x91, 0x34, 0xc0, + 0x3f, 0x15, 0x45, 0xb5, 0x35, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xa9, + 0x00, 0x00, 0x02, 0x32, 0x06, 0x21, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x00, + 0x21, 0x23, 0x11, 0x33, 0x27, 0x3e, 0x01, 0x37, 0x33, 0x15, 0x0e, 0x01, + 0x07, 0x23, 0x01, 0x56, 0xa6, 0xa6, 0xad, 0x30, 0x6f, 0x20, 0xca, 0x2c, + 0xae, 0x40, 0x6f, 0x04, 0x48, 0xaa, 0x3e, 0xb0, 0x41, 0x15, 0x41, 0xbe, + 0x34, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb3, 0x00, 0x00, 0x02, 0x55, + 0x06, 0x21, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x00, 0x03, 0x3e, 0x01, 0x37, + 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, 0x06, 0x07, 0x23, 0x01, + 0x23, 0x11, 0x33, 0x4d, 0x7f, 0x66, 0x17, 0xa6, 0x16, 0x6d, 0x7d, 0x77, + 0x58, 0x85, 0x88, 0x53, 0x73, 0x01, 0xa3, 0xa6, 0xa6, 0x04, 0xf0, 0x88, + 0x80, 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, 0x86, 0x34, 0xfb, 0x27, + 0x04, 0x48, 0x00, 0x00, 0x00, 0x03, 0xff, 0xec, 0x00, 0x00, 0x02, 0x1f, + 0x05, 0xd3, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x1b, 0x00, 0x00, 0x21, 0x23, + 0x11, 0x33, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x25, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, 0x14, 0x06, 0x23, + 0x22, 0x26, 0x01, 0x56, 0xa6, 0xa6, 0xfe, 0x96, 0x35, 0x25, 0x26, 0x37, + 0x37, 0x26, 0x25, 0x35, 0x01, 0x7d, 0x35, 0x25, 0x25, 0x37, 0x37, 0x25, + 0x25, 0x35, 0x04, 0x48, 0x01, 0x29, 0x34, 0x2e, 0x2e, 0x34, 0x32, 0x31, + 0x31, 0x32, 0x34, 0x2e, 0x2e, 0x34, 0x32, 0x31, 0x31, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x71, 0xff, 0xec, 0x04, 0x62, 0x06, 0x21, 0x00, 0x1b, + 0x00, 0x26, 0x00, 0x4a, 0x40, 0x2b, 0x21, 0x06, 0x0c, 0x1c, 0x1c, 0x00, + 0x00, 0x18, 0x19, 0x16, 0x0e, 0x11, 0x13, 0x10, 0x06, 0x09, 0x27, 0x28, + 0x09, 0x1f, 0x46, 0x59, 0x0b, 0x03, 0x16, 0x11, 0x19, 0x0e, 0x0f, 0x05, + 0x14, 0x09, 0x09, 0x03, 0x17, 0x14, 0x01, 0x03, 0x24, 0x46, 0x59, 0x03, + 0x16, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x33, 0x12, 0x39, 0x2f, 0x12, + 0x17, 0x39, 0x12, 0x39, 0x2b, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, + 0x11, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x10, 0x00, 0x23, 0x22, 0x00, + 0x35, 0x34, 0x00, 0x33, 0x32, 0x17, 0x37, 0x26, 0x27, 0x05, 0x27, 0x37, + 0x26, 0x27, 0x37, 0x16, 0x17, 0x37, 0x17, 0x07, 0x16, 0x12, 0x03, 0x34, + 0x26, 0x23, 0x20, 0x11, 0x14, 0x16, 0x33, 0x32, 0x36, 0x04, 0x62, 0xfe, + 0xfb, 0xf7, 0xde, 0xfe, 0xe9, 0x01, 0x07, 0xdc, 0xe2, 0x64, 0x08, 0x39, + 0xcd, 0xfe, 0xf1, 0x49, 0xe9, 0x5c, 0x5e, 0x45, 0x9c, 0x66, 0xee, 0x4c, + 0xcf, 0x98, 0xa5, 0xa8, 0xb4, 0x9c, 0xfe, 0xaf, 0xaf, 0xa2, 0xaf, 0xa1, + 0x02, 0x33, 0xfe, 0xe7, 0xfe, 0xd2, 0x01, 0x0d, 0xe2, 0xe6, 0x01, 0x06, + 0x79, 0x04, 0xd6, 0xbf, 0x9b, 0x6c, 0x85, 0x3e, 0x31, 0x75, 0x49, 0x4b, + 0x8a, 0x6b, 0x77, 0x8f, 0xfe, 0x72, 0xfe, 0xe8, 0x93, 0xaa, 0xfe, 0x98, + 0xa7, 0xb7, 0xc9, 0x00, 0x00, 0x02, 0x00, 0xb0, 0x00, 0x00, 0x04, 0x44, + 0x05, 0xdd, 0x00, 0x17, 0x00, 0x2c, 0x00, 0x00, 0x01, 0x22, 0x2e, 0x02, + 0x23, 0x22, 0x06, 0x07, 0x23, 0x3e, 0x01, 0x33, 0x32, 0x1e, 0x02, 0x33, + 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, 0x13, 0x11, 0x34, 0x26, 0x23, 0x22, + 0x06, 0x15, 0x11, 0x23, 0x11, 0x33, 0x17, 0x33, 0x3e, 0x01, 0x33, 0x32, + 0x16, 0x15, 0x11, 0x03, 0x22, 0x2b, 0x52, 0x4f, 0x49, 0x22, 0x32, 0x33, + 0x0e, 0x62, 0x0d, 0x73, 0x5b, 0x2e, 0x56, 0x4e, 0x48, 0x20, 0x31, 0x30, + 0x0f, 0x63, 0x0d, 0x71, 0x1e, 0x7a, 0x82, 0xac, 0xa0, 0xa6, 0x87, 0x1b, + 0x08, 0x33, 0xb8, 0x71, 0xc6, 0xc8, 0x04, 0xdb, 0x25, 0x2d, 0x25, 0x3c, + 0x3d, 0x79, 0x89, 0x25, 0x2d, 0x25, 0x3b, 0x3e, 0x79, 0x89, 0xfb, 0x25, + 0x02, 0xc5, 0x86, 0x84, 0xba, 0xd6, 0xfd, 0xc1, 0x04, 0x48, 0x96, 0x51, + 0x59, 0xbf, 0xd2, 0xfd, 0x35, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x73, + 0xff, 0xec, 0x04, 0x62, 0x06, 0x21, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x43, 0xd4, 0x00, 0x00, 0x08, 0xb3, 0x02, 0x1a, 0x11, + 0x26, 0x00, 0x2b, 0x35, 0xff, 0xff, 0x00, 0x73, 0xff, 0xec, 0x04, 0x62, + 0x06, 0x21, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x11, 0x06, 0x00, 0x76, + 0x56, 0x00, 0x00, 0x08, 0xb3, 0x02, 0x22, 0x11, 0x26, 0x00, 0x2b, 0x35, + 0x00, 0x03, 0x00, 0x73, 0xff, 0xec, 0x04, 0x62, 0x06, 0x21, 0x00, 0x0e, + 0x00, 0x1b, 0x00, 0x27, 0x00, 0x00, 0x01, 0x3e, 0x01, 0x37, 0x33, 0x1e, + 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, 0x06, 0x07, 0x23, 0x01, 0x10, 0x00, + 0x23, 0x22, 0x26, 0x02, 0x35, 0x10, 0x00, 0x33, 0x32, 0x00, 0x01, 0x14, + 0x16, 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x01, 0x1a, + 0x7f, 0x66, 0x17, 0xa6, 0x16, 0x6d, 0x7d, 0x77, 0x58, 0x85, 0x88, 0x53, + 0x73, 0x03, 0x48, 0xfe, 0xf2, 0xee, 0x93, 0xe4, 0x7c, 0x01, 0x0c, 0xee, + 0xe6, 0x01, 0x0f, 0xfc, 0xbd, 0xa8, 0xa3, 0xa3, 0xa9, 0xa9, 0xa5, 0xa3, + 0xa6, 0x04, 0xf0, 0x88, 0x80, 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, + 0x86, 0x34, 0xfd, 0x4c, 0xfe, 0xf4, 0xfe, 0xd3, 0x8a, 0x01, 0x02, 0xad, + 0x01, 0x0c, 0x01, 0x2b, 0xfe, 0xce, 0xfe, 0xfb, 0xd2, 0xdc, 0xdb, 0xd3, + 0xd1, 0xd9, 0xd6, 0x00, 0x00, 0x03, 0x00, 0x73, 0xff, 0xec, 0x04, 0x62, + 0x05, 0xdd, 0x00, 0x17, 0x00, 0x24, 0x00, 0x30, 0x00, 0x00, 0x01, 0x22, + 0x2e, 0x02, 0x23, 0x22, 0x06, 0x07, 0x23, 0x3e, 0x01, 0x33, 0x32, 0x1e, + 0x02, 0x33, 0x32, 0x36, 0x37, 0x33, 0x0e, 0x01, 0x01, 0x10, 0x00, 0x23, + 0x22, 0x26, 0x02, 0x35, 0x10, 0x00, 0x33, 0x32, 0x00, 0x01, 0x14, 0x16, + 0x33, 0x32, 0x36, 0x35, 0x34, 0x26, 0x23, 0x22, 0x06, 0x03, 0x05, 0x2b, + 0x52, 0x4f, 0x49, 0x22, 0x32, 0x33, 0x0e, 0x62, 0x0d, 0x73, 0x5b, 0x2e, + 0x56, 0x4e, 0x48, 0x20, 0x31, 0x30, 0x0f, 0x63, 0x0d, 0x71, 0x00, 0xff, + 0xfe, 0xf2, 0xee, 0x93, 0xe4, 0x7c, 0x01, 0x0c, 0xee, 0xe6, 0x01, 0x0f, + 0xfc, 0xbd, 0xa8, 0xa3, 0xa3, 0xa9, 0xa9, 0xa5, 0xa3, 0xa6, 0x04, 0xdb, + 0x25, 0x2d, 0x25, 0x3c, 0x3d, 0x79, 0x89, 0x25, 0x2d, 0x25, 0x3b, 0x3e, + 0x79, 0x89, 0xfd, 0x4a, 0xfe, 0xf4, 0xfe, 0xd3, 0x8a, 0x01, 0x02, 0xad, + 0x01, 0x0c, 0x01, 0x2b, 0xfe, 0xce, 0xfe, 0xfb, 0xd2, 0xdc, 0xdb, 0xd3, + 0xd1, 0xd9, 0xd6, 0x00, 0xff, 0xff, 0x00, 0x73, 0xff, 0xec, 0x04, 0x62, + 0x05, 0xd3, 0x12, 0x26, 0x00, 0x52, 0x00, 0x00, 0x11, 0x06, 0x00, 0x6a, + 0x1b, 0x00, 0x00, 0x0a, 0xb4, 0x03, 0x02, 0x2e, 0x11, 0x26, 0x00, 0x2b, + 0x35, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x68, 0x00, 0xfc, 0x04, 0x29, + 0x04, 0xa8, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x1b, 0x00, 0x33, 0x40, 0x18, + 0x16, 0x0a, 0x0a, 0x10, 0x04, 0x02, 0x04, 0x01, 0x03, 0x1c, 0x1d, 0x19, + 0x13, 0x13, 0x01, 0x07, 0x0d, 0x0d, 0x01, 0x01, 0x00, 0x50, 0x59, 0x01, + 0x00, 0x2f, 0x2b, 0x11, 0x00, 0x33, 0x18, 0x2f, 0x33, 0x11, 0x33, 0x2f, + 0x33, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, + 0x30, 0x13, 0x35, 0x21, 0x15, 0x01, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x06, 0x23, 0x22, 0x26, 0x11, 0x34, 0x36, 0x33, 0x32, 0x16, 0x15, + 0x14, 0x06, 0x23, 0x22, 0x26, 0x68, 0x03, 0xc1, 0xfd, 0xae, 0x3b, 0x36, + 0x34, 0x3a, 0x3b, 0x33, 0x34, 0x3d, 0x3b, 0x36, 0x34, 0x3a, 0x3b, 0x33, + 0x34, 0x3d, 0x02, 0x8d, 0x8a, 0x8a, 0xfe, 0xe8, 0x3c, 0x3d, 0x3f, 0x3a, + 0x39, 0x40, 0x3f, 0x02, 0xf4, 0x3c, 0x3d, 0x3f, 0x3a, 0x39, 0x40, 0x3f, + 0x00, 0x03, 0x00, 0x73, 0xff, 0xbc, 0x04, 0x62, 0x04, 0x87, 0x00, 0x13, + 0x00, 0x1b, 0x00, 0x23, 0x00, 0x4b, 0x40, 0x29, 0x17, 0x1f, 0x1c, 0x14, + 0x14, 0x0a, 0x1c, 0x00, 0x00, 0x12, 0x0f, 0x05, 0x08, 0x0a, 0x06, 0x24, + 0x25, 0x16, 0x1e, 0x21, 0x19, 0x0d, 0x19, 0x46, 0x59, 0x0f, 0x12, 0x08, + 0x05, 0x04, 0x03, 0x10, 0x0d, 0x10, 0x03, 0x21, 0x46, 0x59, 0x06, 0x03, + 0x16, 0x00, 0x3f, 0xc6, 0x2b, 0x00, 0x18, 0x3f, 0xc6, 0x12, 0x17, 0x39, + 0x2b, 0x11, 0x12, 0x00, 0x39, 0x39, 0x11, 0x12, 0x01, 0x17, 0x39, 0x11, + 0x33, 0x11, 0x33, 0x11, 0x12, 0x39, 0x39, 0x31, 0x30, 0x01, 0x10, 0x00, + 0x23, 0x22, 0x27, 0x07, 0x27, 0x37, 0x26, 0x11, 0x10, 0x00, 0x33, 0x32, + 0x17, 0x37, 0x17, 0x07, 0x16, 0x05, 0x14, 0x17, 0x01, 0x26, 0x23, 0x22, + 0x06, 0x05, 0x34, 0x27, 0x01, 0x16, 0x33, 0x32, 0x36, 0x04, 0x62, 0xfe, + 0xf2, 0xee, 0x9a, 0x70, 0x54, 0x72, 0x5e, 0x81, 0x01, 0x0c, 0xee, 0x9a, + 0x74, 0x54, 0x75, 0x61, 0x7f, 0xfc, 0xbd, 0x35, 0x01, 0xd1, 0x4b, 0x72, + 0xa3, 0xa6, 0x02, 0x97, 0x33, 0xfe, 0x2f, 0x47, 0x71, 0xa3, 0xa9, 0x02, + 0x25, 0xfe, 0xf4, 0xfe, 0xd3, 0x45, 0x75, 0x4e, 0x83, 0x98, 0x01, 0x00, + 0x01, 0x0c, 0x01, 0x2b, 0x4c, 0x77, 0x4c, 0x85, 0x98, 0xf9, 0xab, 0x66, + 0x02, 0x86, 0x35, 0xd6, 0xd4, 0xa4, 0x64, 0xfd, 0x7d, 0x33, 0xdb, 0x00, + 0xff, 0xff, 0x00, 0xa4, 0xff, 0xec, 0x04, 0x39, 0x06, 0x21, 0x12, 0x26, + 0x00, 0x58, 0x00, 0x00, 0x11, 0x06, 0x00, 0x43, 0xc4, 0x00, 0x00, 0x08, + 0xb3, 0x01, 0x16, 0x11, 0x26, 0x00, 0x2b, 0x35, 0xff, 0xff, 0x00, 0xa4, + 0xff, 0xec, 0x04, 0x39, 0x06, 0x21, 0x12, 0x26, 0x00, 0x58, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x76, 0x71, 0x00, 0x00, 0x08, 0xb3, 0x01, 0x1e, 0x11, + 0x26, 0x00, 0x2b, 0x35, 0x00, 0x02, 0x00, 0xa4, 0xff, 0xec, 0x04, 0x39, + 0x06, 0x21, 0x00, 0x0e, 0x00, 0x23, 0x00, 0x00, 0x01, 0x3e, 0x01, 0x37, + 0x33, 0x1e, 0x01, 0x17, 0x15, 0x23, 0x26, 0x27, 0x06, 0x07, 0x23, 0x17, + 0x11, 0x14, 0x16, 0x33, 0x32, 0x36, 0x35, 0x11, 0x33, 0x11, 0x23, 0x27, + 0x23, 0x0e, 0x01, 0x23, 0x22, 0x26, 0x35, 0x11, 0x01, 0x1e, 0x7f, 0x66, + 0x17, 0xa6, 0x16, 0x6d, 0x7d, 0x77, 0x58, 0x85, 0x88, 0x53, 0x73, 0x2e, + 0x7a, 0x82, 0xac, 0x9f, 0xa6, 0x89, 0x18, 0x09, 0x33, 0xb5, 0x74, 0xc8, + 0xc7, 0x04, 0xf0, 0x88, 0x80, 0x29, 0x2a, 0x85, 0x82, 0x17, 0x37, 0x83, + 0x86, 0x34, 0x91, 0xfd, 0x39, 0x86, 0x84, 0xbc, 0xd5, 0x02, 0x40, 0xfb, + 0xb8, 0x93, 0x51, 0x56, 0xbe, 0xd1, 0x02, 0xcd, 0xff, 0xff, 0x00, 0xa4, + 0xff, 0xec, 0x04, 0x39, 0x05, 0xd3, 0x12, 0x26, 0x00, 0x58, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x6a, 0x21, 0x00, 0x00, 0x0a, 0xb4, 0x02, 0x01, 0x2a, + 0x11, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x00, 0xff, 0xff, 0x00, 0x02, + 0xfe, 0x14, 0x04, 0x06, 0x06, 0x21, 0x12, 0x26, 0x00, 0x5c, 0x00, 0x00, + 0x11, 0x06, 0x00, 0x76, 0x12, 0x00, 0x00, 0x08, 0xb3, 0x01, 0x1f, 0x11, + 0x26, 0x00, 0x2b, 0x35, 0x00, 0x02, 0x00, 0xb0, 0xfe, 0x14, 0x04, 0x75, + 0x06, 0x14, 0x00, 0x16, 0x00, 0x22, 0x00, 0x3e, 0x40, 0x1f, 0x20, 0x06, + 0x1b, 0x14, 0x10, 0x10, 0x11, 0x06, 0x11, 0x24, 0x23, 0x12, 0x00, 0x11, + 0x1b, 0x0c, 0x16, 0x09, 0x03, 0x09, 0x1e, 0x46, 0x59, 0x09, 0x16, 0x03, + 0x17, 0x46, 0x59, 0x03, 0x10, 0x00, 0x3f, 0x2b, 0x00, 0x18, 0x3f, 0x2b, + 0x11, 0x12, 0x00, 0x39, 0x39, 0x18, 0x3f, 0x3f, 0x11, 0x12, 0x01, 0x39, + 0x39, 0x11, 0x33, 0x11, 0x33, 0x33, 0x11, 0x33, 0x31, 0x30, 0x01, 0x3e, + 0x01, 0x33, 0x32, 0x12, 0x11, 0x10, 0x02, 0x23, 0x22, 0x27, 0x23, 0x17, + 0x16, 0x15, 0x11, 0x23, 0x11, 0x33, 0x11, 0x14, 0x07, 0x25, 0x22, 0x06, + 0x07, 0x15, 0x14, 0x16, 0x33, 0x20, 0x11, 0x34, 0x26, 0x01, 0x58, 0x42, + 0xaa, 0x6a, 0xd7, 0xf0, 0xf1, 0xd6, 0xde, 0x7a, 0x0c, 0x04, 0x08, 0xa6, + 0xa6, 0x06, 0x01, 0x48, 0xa8, 0x98, 0x02, 0x9a, 0xaa, 0x01, 0x2f, 0x94, + 0x03, 0xb4, 0x59, 0x4f, 0xfe, 0xd4, 0xfe, 0xf5, 0xfe, 0xf4, 0xfe, 0xd3, + 0xa1, 0x22, 0x4d, 0x3f, 0xfe, 0x35, 0x08, 0x00, 0xfe, 0x2e, 0x34, 0x5a, + 0x1b, 0xb8, 0xc9, 0x29, 0xe7, 0xc7, 0x01, 0xb0, 0xd7, 0xd1, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x02, 0xfe, 0x14, 0x04, 0x06, 0x05, 0xd3, 0x12, 0x26, + 0x00, 0x5c, 0x00, 0x00, 0x11, 0x06, 0x00, 0x6a, 0xb5, 0x00, 0x00, 0x0a, + 0xb4, 0x02, 0x01, 0x2b, 0x11, 0x26, 0x00, 0x2b, 0x35, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x72, 0x00, 0x01, 0x04, 0x66, + 0x18, 0x00, 0x00, 0x0a, 0x02, 0x64, 0x00, 0x05, 0x00, 0x24, 0xff, 0x71, + 0x00, 0x05, 0x00, 0x37, 0x00, 0x29, 0x00, 0x05, 0x00, 0x39, 0x00, 0x29, + 0x00, 0x05, 0x00, 0x3a, 0x00, 0x29, 0x00, 0x05, 0x00, 0x3c, 0x00, 0x14, + 0x00, 0x05, 0x00, 0x44, 0xff, 0xae, 0x00, 0x05, 0x00, 0x46, 0xff, 0x85, + 0x00, 0x05, 0x00, 0x47, 0xff, 0x85, 0x00, 0x05, 0x00, 0x48, 0xff, 0x85, + 0x00, 0x05, 0x00, 0x4a, 0xff, 0xc3, 0x00, 0x05, 0x00, 0x50, 0xff, 0xc3, + 0x00, 0x05, 0x00, 0x51, 0xff, 0xc3, 0x00, 0x05, 0x00, 0x52, 0xff, 0x85, + 0x00, 0x05, 0x00, 0x53, 0xff, 0xc3, 0x00, 0x05, 0x00, 0x54, 0xff, 0x85, + 0x00, 0x05, 0x00, 0x55, 0xff, 0xc3, 0x00, 0x05, 0x00, 0x56, 0xff, 0xc3, + 0x00, 0x05, 0x00, 0x58, 0xff, 0xc3, 0x00, 0x05, 0x00, 0x82, 0xff, 0x71, + 0x00, 0x05, 0x00, 0x83, 0xff, 0x71, 0x00, 0x05, 0x00, 0x84, 0xff, 0x71, + 0x00, 0x05, 0x00, 0x85, 0xff, 0x71, 0x00, 0x05, 0x00, 0x86, 0xff, 0x71, + 0x00, 0x05, 0x00, 0x87, 0xff, 0x71, 0x00, 0x05, 0x00, 0x9f, 0x00, 0x14, + 0x00, 0x05, 0x00, 0xa2, 0xff, 0x85, 0x00, 0x05, 0x00, 0xa3, 0xff, 0xae, + 0x00, 0x05, 0x00, 0xa4, 0xff, 0xae, 0x00, 0x05, 0x00, 0xa5, 0xff, 0xae, + 0x00, 0x05, 0x00, 0xa6, 0xff, 0xae, 0x00, 0x05, 0x00, 0xa7, 0xff, 0xae, + 0x00, 0x05, 0x00, 0xa8, 0xff, 0xae, 0x00, 0x05, 0x00, 0xa9, 0xff, 0x85, + 0x00, 0x05, 0x00, 0xaa, 0xff, 0x85, 0x00, 0x05, 0x00, 0xab, 0xff, 0x85, + 0x00, 0x05, 0x00, 0xac, 0xff, 0x85, 0x00, 0x05, 0x00, 0xad, 0xff, 0x85, + 0x00, 0x05, 0x00, 0xb4, 0xff, 0x85, 0x00, 0x05, 0x00, 0xb5, 0xff, 0x85, + 0x00, 0x05, 0x00, 0xb6, 0xff, 0x85, 0x00, 0x05, 0x00, 0xb7, 0xff, 0x85, + 0x00, 0x05, 0x00, 0xb8, 0xff, 0x85, 0x00, 0x05, 0x00, 0xba, 0xff, 0x85, + 0x00, 0x05, 0x00, 0xbb, 0xff, 0xc3, 0x00, 0x05, 0x00, 0xbc, 0xff, 0xc3, + 0x00, 0x05, 0x00, 0xbd, 0xff, 0xc3, 0x00, 0x05, 0x00, 0xbe, 0xff, 0xc3, + 0x00, 0x0a, 0x00, 0x24, 0xff, 0x71, 0x00, 0x0a, 0x00, 0x37, 0x00, 0x29, + 0x00, 0x0a, 0x00, 0x39, 0x00, 0x29, 0x00, 0x0a, 0x00, 0x3a, 0x00, 0x29, + 0x00, 0x0a, 0x00, 0x3c, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x44, 0xff, 0xae, + 0x00, 0x0a, 0x00, 0x46, 0xff, 0x85, 0x00, 0x0a, 0x00, 0x47, 0xff, 0x85, + 0x00, 0x0a, 0x00, 0x48, 0xff, 0x85, 0x00, 0x0a, 0x00, 0x4a, 0xff, 0xc3, + 0x00, 0x0a, 0x00, 0x50, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0x51, 0xff, 0xc3, + 0x00, 0x0a, 0x00, 0x52, 0xff, 0x85, 0x00, 0x0a, 0x00, 0x53, 0xff, 0xc3, + 0x00, 0x0a, 0x00, 0x54, 0xff, 0x85, 0x00, 0x0a, 0x00, 0x55, 0xff, 0xc3, + 0x00, 0x0a, 0x00, 0x56, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0x58, 0xff, 0xc3, + 0x00, 0x0a, 0x00, 0x82, 0xff, 0x71, 0x00, 0x0a, 0x00, 0x83, 0xff, 0x71, + 0x00, 0x0a, 0x00, 0x84, 0xff, 0x71, 0x00, 0x0a, 0x00, 0x85, 0xff, 0x71, + 0x00, 0x0a, 0x00, 0x86, 0xff, 0x71, 0x00, 0x0a, 0x00, 0x87, 0xff, 0x71, + 0x00, 0x0a, 0x00, 0x9f, 0x00, 0x14, 0x00, 0x0a, 0x00, 0xa2, 0xff, 0x85, + 0x00, 0x0a, 0x00, 0xa3, 0xff, 0xae, 0x00, 0x0a, 0x00, 0xa4, 0xff, 0xae, + 0x00, 0x0a, 0x00, 0xa5, 0xff, 0xae, 0x00, 0x0a, 0x00, 0xa6, 0xff, 0xae, + 0x00, 0x0a, 0x00, 0xa7, 0xff, 0xae, 0x00, 0x0a, 0x00, 0xa8, 0xff, 0xae, + 0x00, 0x0a, 0x00, 0xa9, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xaa, 0xff, 0x85, + 0x00, 0x0a, 0x00, 0xab, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xac, 0xff, 0x85, + 0x00, 0x0a, 0x00, 0xad, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xb4, 0xff, 0x85, + 0x00, 0x0a, 0x00, 0xb5, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xb6, 0xff, 0x85, + 0x00, 0x0a, 0x00, 0xb7, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xb8, 0xff, 0x85, + 0x00, 0x0a, 0x00, 0xba, 0xff, 0x85, 0x00, 0x0a, 0x00, 0xbb, 0xff, 0xc3, + 0x00, 0x0a, 0x00, 0xbc, 0xff, 0xc3, 0x00, 0x0a, 0x00, 0xbd, 0xff, 0xc3, + 0x00, 0x0a, 0x00, 0xbe, 0xff, 0xc3, 0x00, 0x0b, 0x00, 0x2d, 0x00, 0xb8, + 0x00, 0x0f, 0x00, 0x26, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x2a, 0xff, 0x9a, + 0x00, 0x0f, 0x00, 0x32, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x34, 0xff, 0x9a, + 0x00, 0x0f, 0x00, 0x37, 0xff, 0x71, 0x00, 0x0f, 0x00, 0x38, 0xff, 0xd7, + 0x00, 0x0f, 0x00, 0x39, 0xff, 0x85, 0x00, 0x0f, 0x00, 0x3a, 0xff, 0x85, + 0x00, 0x0f, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x0f, 0x00, 0x89, 0xff, 0x9a, + 0x00, 0x0f, 0x00, 0x94, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x95, 0xff, 0x9a, + 0x00, 0x0f, 0x00, 0x96, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x97, 0xff, 0x9a, + 0x00, 0x0f, 0x00, 0x98, 0xff, 0x9a, 0x00, 0x0f, 0x00, 0x9a, 0xff, 0x9a, + 0x00, 0x0f, 0x00, 0x9b, 0xff, 0xd7, 0x00, 0x0f, 0x00, 0x9c, 0xff, 0xd7, + 0x00, 0x0f, 0x00, 0x9d, 0xff, 0xd7, 0x00, 0x0f, 0x00, 0x9e, 0xff, 0xd7, + 0x00, 0x0f, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x10, 0x00, 0x37, 0xff, 0xae, + 0x00, 0x11, 0x00, 0x26, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x2a, 0xff, 0x9a, + 0x00, 0x11, 0x00, 0x32, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x34, 0xff, 0x9a, + 0x00, 0x11, 0x00, 0x37, 0xff, 0x71, 0x00, 0x11, 0x00, 0x38, 0xff, 0xd7, + 0x00, 0x11, 0x00, 0x39, 0xff, 0x85, 0x00, 0x11, 0x00, 0x3a, 0xff, 0x85, + 0x00, 0x11, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x11, 0x00, 0x89, 0xff, 0x9a, + 0x00, 0x11, 0x00, 0x94, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x95, 0xff, 0x9a, + 0x00, 0x11, 0x00, 0x96, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x97, 0xff, 0x9a, + 0x00, 0x11, 0x00, 0x98, 0xff, 0x9a, 0x00, 0x11, 0x00, 0x9a, 0xff, 0x9a, + 0x00, 0x11, 0x00, 0x9b, 0xff, 0xd7, 0x00, 0x11, 0x00, 0x9c, 0xff, 0xd7, + 0x00, 0x11, 0x00, 0x9d, 0xff, 0xd7, 0x00, 0x11, 0x00, 0x9e, 0xff, 0xd7, + 0x00, 0x11, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x24, 0x00, 0x05, 0xff, 0x71, + 0x00, 0x24, 0x00, 0x0a, 0xff, 0x71, 0x00, 0x24, 0x00, 0x26, 0xff, 0xd7, + 0x00, 0x24, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x2d, 0x01, 0x0a, + 0x00, 0x24, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x24, 0x00, 0x37, 0xff, 0x71, 0x00, 0x24, 0x00, 0x39, 0xff, 0xae, + 0x00, 0x24, 0x00, 0x3a, 0xff, 0xae, 0x00, 0x24, 0x00, 0x3c, 0xff, 0x85, + 0x00, 0x24, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x24, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x24, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x24, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x24, 0x00, 0x9f, 0xff, 0x85, + 0x00, 0x25, 0x00, 0x0f, 0xff, 0xae, 0x00, 0x25, 0x00, 0x11, 0xff, 0xae, + 0x00, 0x25, 0x00, 0x24, 0xff, 0xd7, 0x00, 0x25, 0x00, 0x37, 0xff, 0xc3, + 0x00, 0x25, 0x00, 0x39, 0xff, 0xec, 0x00, 0x25, 0x00, 0x3a, 0xff, 0xec, + 0x00, 0x25, 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x25, 0x00, 0x3c, 0xff, 0xec, + 0x00, 0x25, 0x00, 0x3d, 0xff, 0xec, 0x00, 0x25, 0x00, 0x82, 0xff, 0xd7, + 0x00, 0x25, 0x00, 0x83, 0xff, 0xd7, 0x00, 0x25, 0x00, 0x84, 0xff, 0xd7, + 0x00, 0x25, 0x00, 0x85, 0xff, 0xd7, 0x00, 0x25, 0x00, 0x86, 0xff, 0xd7, + 0x00, 0x25, 0x00, 0x87, 0xff, 0xd7, 0x00, 0x25, 0x00, 0x9f, 0xff, 0xec, + 0x00, 0x26, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x2a, 0xff, 0xd7, + 0x00, 0x26, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x26, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x26, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x26, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x26, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x26, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x27, 0x00, 0x11, 0xff, 0xae, 0x00, 0x27, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x27, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x27, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x27, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x27, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x27, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x27, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x27, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x27, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x27, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x27, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x27, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x7b, + 0x00, 0x29, 0x00, 0x0f, 0xff, 0x85, 0x00, 0x29, 0x00, 0x11, 0xff, 0x85, + 0x00, 0x29, 0x00, 0x22, 0x00, 0x29, 0x00, 0x29, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x29, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x29, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x29, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x29, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x29, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x29, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x2e, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x2a, 0xff, 0xd7, + 0x00, 0x2e, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x2e, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x2e, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x2e, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x2e, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x2e, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x05, 0xff, 0x5c, + 0x00, 0x2f, 0x00, 0x0a, 0xff, 0x5c, 0x00, 0x2f, 0x00, 0x26, 0xff, 0xd7, + 0x00, 0x2f, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x32, 0xff, 0xd7, + 0x00, 0x2f, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x37, 0xff, 0xd7, + 0x00, 0x2f, 0x00, 0x38, 0xff, 0xec, 0x00, 0x2f, 0x00, 0x39, 0xff, 0xd7, + 0x00, 0x2f, 0x00, 0x3a, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x3c, 0xff, 0xc3, + 0x00, 0x2f, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x2f, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x2f, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x2f, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x2f, 0x00, 0x9b, 0xff, 0xec, + 0x00, 0x2f, 0x00, 0x9c, 0xff, 0xec, 0x00, 0x2f, 0x00, 0x9d, 0xff, 0xec, + 0x00, 0x2f, 0x00, 0x9e, 0xff, 0xec, 0x00, 0x2f, 0x00, 0x9f, 0xff, 0xc3, + 0x00, 0x32, 0x00, 0x0f, 0xff, 0xae, 0x00, 0x32, 0x00, 0x11, 0xff, 0xae, + 0x00, 0x32, 0x00, 0x24, 0xff, 0xd7, 0x00, 0x32, 0x00, 0x37, 0xff, 0xc3, + 0x00, 0x32, 0x00, 0x39, 0xff, 0xec, 0x00, 0x32, 0x00, 0x3a, 0xff, 0xec, + 0x00, 0x32, 0x00, 0x3b, 0xff, 0xd7, 0x00, 0x32, 0x00, 0x3c, 0xff, 0xec, + 0x00, 0x32, 0x00, 0x3d, 0xff, 0xec, 0x00, 0x32, 0x00, 0x82, 0xff, 0xd7, + 0x00, 0x32, 0x00, 0x83, 0xff, 0xd7, 0x00, 0x32, 0x00, 0x84, 0xff, 0xd7, + 0x00, 0x32, 0x00, 0x85, 0xff, 0xd7, 0x00, 0x32, 0x00, 0x86, 0xff, 0xd7, + 0x00, 0x32, 0x00, 0x87, 0xff, 0xd7, 0x00, 0x32, 0x00, 0x9f, 0xff, 0xec, + 0x00, 0x33, 0x00, 0x0f, 0xfe, 0xf6, 0x00, 0x33, 0x00, 0x11, 0xfe, 0xf6, + 0x00, 0x33, 0x00, 0x24, 0xff, 0x9a, 0x00, 0x33, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x33, 0x00, 0x3d, 0xff, 0xec, 0x00, 0x33, 0x00, 0x82, 0xff, 0x9a, + 0x00, 0x33, 0x00, 0x83, 0xff, 0x9a, 0x00, 0x33, 0x00, 0x84, 0xff, 0x9a, + 0x00, 0x33, 0x00, 0x85, 0xff, 0x9a, 0x00, 0x33, 0x00, 0x86, 0xff, 0x9a, + 0x00, 0x33, 0x00, 0x87, 0xff, 0x9a, 0x00, 0x34, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x34, 0x00, 0x11, 0xff, 0xae, 0x00, 0x34, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x34, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x34, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x34, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x34, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x34, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x34, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x34, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x34, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x34, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x34, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x34, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x34, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x34, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x37, 0x00, 0x0f, 0xff, 0x85, + 0x00, 0x37, 0x00, 0x10, 0xff, 0xae, 0x00, 0x37, 0x00, 0x11, 0xff, 0x85, + 0x00, 0x37, 0x00, 0x22, 0x00, 0x29, 0x00, 0x37, 0x00, 0x24, 0xff, 0x71, + 0x00, 0x37, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x2a, 0xff, 0xd7, + 0x00, 0x37, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x37, 0x00, 0x37, 0x00, 0x29, 0x00, 0x37, 0x00, 0x44, 0xff, 0x5c, + 0x00, 0x37, 0x00, 0x46, 0xff, 0x71, 0x00, 0x37, 0x00, 0x47, 0xff, 0x71, + 0x00, 0x37, 0x00, 0x48, 0xff, 0x71, 0x00, 0x37, 0x00, 0x4a, 0xff, 0x71, + 0x00, 0x37, 0x00, 0x50, 0xff, 0x9a, 0x00, 0x37, 0x00, 0x51, 0xff, 0x9a, + 0x00, 0x37, 0x00, 0x52, 0xff, 0x71, 0x00, 0x37, 0x00, 0x53, 0xff, 0x9a, + 0x00, 0x37, 0x00, 0x54, 0xff, 0x71, 0x00, 0x37, 0x00, 0x55, 0xff, 0x9a, + 0x00, 0x37, 0x00, 0x56, 0xff, 0x85, 0x00, 0x37, 0x00, 0x58, 0xff, 0x9a, + 0x00, 0x37, 0x00, 0x59, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x5a, 0xff, 0xd7, + 0x00, 0x37, 0x00, 0x5b, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x5c, 0xff, 0xd7, + 0x00, 0x37, 0x00, 0x5d, 0xff, 0xae, 0x00, 0x37, 0x00, 0x82, 0xff, 0x71, + 0x00, 0x37, 0x00, 0x83, 0xff, 0x71, 0x00, 0x37, 0x00, 0x84, 0xff, 0x71, + 0x00, 0x37, 0x00, 0x85, 0xff, 0x71, 0x00, 0x37, 0x00, 0x86, 0xff, 0x71, + 0x00, 0x37, 0x00, 0x87, 0xff, 0x71, 0x00, 0x37, 0x00, 0x89, 0xff, 0xd7, + 0x00, 0x37, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x95, 0xff, 0xd7, + 0x00, 0x37, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x97, 0xff, 0xd7, + 0x00, 0x37, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x37, 0x00, 0x9a, 0xff, 0xd7, + 0x00, 0x37, 0x00, 0xa2, 0xff, 0x71, 0x00, 0x37, 0x00, 0xa3, 0xff, 0x5c, + 0x00, 0x37, 0x00, 0xa4, 0xff, 0x5c, 0x00, 0x37, 0x00, 0xa5, 0xff, 0x5c, + 0x00, 0x37, 0x00, 0xa6, 0xff, 0x5c, 0x00, 0x37, 0x00, 0xa7, 0xff, 0x5c, + 0x00, 0x37, 0x00, 0xa8, 0xff, 0x5c, 0x00, 0x37, 0x00, 0xa9, 0xff, 0x71, + 0x00, 0x37, 0x00, 0xaa, 0xff, 0x71, 0x00, 0x37, 0x00, 0xab, 0xff, 0x71, + 0x00, 0x37, 0x00, 0xac, 0xff, 0x71, 0x00, 0x37, 0x00, 0xad, 0xff, 0x71, + 0x00, 0x37, 0x00, 0xb4, 0xff, 0x71, 0x00, 0x37, 0x00, 0xb5, 0xff, 0x71, + 0x00, 0x37, 0x00, 0xb6, 0xff, 0x71, 0x00, 0x37, 0x00, 0xb7, 0xff, 0x71, + 0x00, 0x37, 0x00, 0xb8, 0xff, 0x71, 0x00, 0x37, 0x00, 0xba, 0xff, 0x71, + 0x00, 0x37, 0x00, 0xbb, 0xff, 0x9a, 0x00, 0x37, 0x00, 0xbc, 0xff, 0x9a, + 0x00, 0x37, 0x00, 0xbd, 0xff, 0x9a, 0x00, 0x37, 0x00, 0xbe, 0xff, 0x9a, + 0x00, 0x37, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0x38, 0x00, 0x0f, 0xff, 0xd7, + 0x00, 0x38, 0x00, 0x11, 0xff, 0xd7, 0x00, 0x38, 0x00, 0x24, 0xff, 0xec, + 0x00, 0x38, 0x00, 0x82, 0xff, 0xec, 0x00, 0x38, 0x00, 0x83, 0xff, 0xec, + 0x00, 0x38, 0x00, 0x84, 0xff, 0xec, 0x00, 0x38, 0x00, 0x85, 0xff, 0xec, + 0x00, 0x38, 0x00, 0x86, 0xff, 0xec, 0x00, 0x38, 0x00, 0x87, 0xff, 0xec, + 0x00, 0x39, 0x00, 0x0f, 0xff, 0x9a, 0x00, 0x39, 0x00, 0x11, 0xff, 0x9a, + 0x00, 0x39, 0x00, 0x22, 0x00, 0x29, 0x00, 0x39, 0x00, 0x24, 0xff, 0xae, + 0x00, 0x39, 0x00, 0x26, 0xff, 0xec, 0x00, 0x39, 0x00, 0x2a, 0xff, 0xec, + 0x00, 0x39, 0x00, 0x32, 0xff, 0xec, 0x00, 0x39, 0x00, 0x34, 0xff, 0xec, + 0x00, 0x39, 0x00, 0x44, 0xff, 0xd7, 0x00, 0x39, 0x00, 0x46, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0x47, 0xff, 0xd7, 0x00, 0x39, 0x00, 0x48, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0x4a, 0xff, 0xec, 0x00, 0x39, 0x00, 0x50, 0xff, 0xec, + 0x00, 0x39, 0x00, 0x51, 0xff, 0xec, 0x00, 0x39, 0x00, 0x52, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0x53, 0xff, 0xec, 0x00, 0x39, 0x00, 0x54, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0x55, 0xff, 0xec, 0x00, 0x39, 0x00, 0x56, 0xff, 0xec, + 0x00, 0x39, 0x00, 0x58, 0xff, 0xec, 0x00, 0x39, 0x00, 0x82, 0xff, 0xae, + 0x00, 0x39, 0x00, 0x83, 0xff, 0xae, 0x00, 0x39, 0x00, 0x84, 0xff, 0xae, + 0x00, 0x39, 0x00, 0x85, 0xff, 0xae, 0x00, 0x39, 0x00, 0x86, 0xff, 0xae, + 0x00, 0x39, 0x00, 0x87, 0xff, 0xae, 0x00, 0x39, 0x00, 0x89, 0xff, 0xec, + 0x00, 0x39, 0x00, 0x94, 0xff, 0xec, 0x00, 0x39, 0x00, 0x95, 0xff, 0xec, + 0x00, 0x39, 0x00, 0x96, 0xff, 0xec, 0x00, 0x39, 0x00, 0x97, 0xff, 0xec, + 0x00, 0x39, 0x00, 0x98, 0xff, 0xec, 0x00, 0x39, 0x00, 0x9a, 0xff, 0xec, + 0x00, 0x39, 0x00, 0xa2, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xa3, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xa4, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xa5, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xa6, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xa7, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xa8, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xa9, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xaa, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xab, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xac, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xad, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xb4, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xb5, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xb6, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xb7, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xb8, 0xff, 0xd7, 0x00, 0x39, 0x00, 0xba, 0xff, 0xd7, + 0x00, 0x39, 0x00, 0xbb, 0xff, 0xec, 0x00, 0x39, 0x00, 0xbc, 0xff, 0xec, + 0x00, 0x39, 0x00, 0xbd, 0xff, 0xec, 0x00, 0x39, 0x00, 0xbe, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0x0f, 0xff, 0x9a, 0x00, 0x3a, 0x00, 0x11, 0xff, 0x9a, + 0x00, 0x3a, 0x00, 0x22, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x24, 0xff, 0xae, + 0x00, 0x3a, 0x00, 0x26, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x2a, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0x32, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x34, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0x44, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0x46, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0x47, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0x48, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0x4a, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x50, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0x51, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x52, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0x53, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x54, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0x55, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x56, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0x58, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x82, 0xff, 0xae, + 0x00, 0x3a, 0x00, 0x83, 0xff, 0xae, 0x00, 0x3a, 0x00, 0x84, 0xff, 0xae, + 0x00, 0x3a, 0x00, 0x85, 0xff, 0xae, 0x00, 0x3a, 0x00, 0x86, 0xff, 0xae, + 0x00, 0x3a, 0x00, 0x87, 0xff, 0xae, 0x00, 0x3a, 0x00, 0x89, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0x94, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x95, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0x96, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x97, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0x98, 0xff, 0xec, 0x00, 0x3a, 0x00, 0x9a, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0xa2, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xa3, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xa4, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xa5, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xa6, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xa7, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xa8, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xa9, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xaa, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xab, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xac, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xad, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xb4, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xb5, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xb6, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xb7, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xb8, 0xff, 0xd7, 0x00, 0x3a, 0x00, 0xba, 0xff, 0xd7, + 0x00, 0x3a, 0x00, 0xbb, 0xff, 0xec, 0x00, 0x3a, 0x00, 0xbc, 0xff, 0xec, + 0x00, 0x3a, 0x00, 0xbd, 0xff, 0xec, 0x00, 0x3a, 0x00, 0xbe, 0xff, 0xec, + 0x00, 0x3b, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x2a, 0xff, 0xd7, + 0x00, 0x3b, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x3b, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x3b, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x3b, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x3b, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x3b, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x0f, 0xff, 0x85, + 0x00, 0x3c, 0x00, 0x11, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x22, 0x00, 0x29, + 0x00, 0x3c, 0x00, 0x24, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x26, 0xff, 0xd7, + 0x00, 0x3c, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x32, 0xff, 0xd7, + 0x00, 0x3c, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x44, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0x46, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0x47, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0x48, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0x4a, 0xff, 0xd7, + 0x00, 0x3c, 0x00, 0x50, 0xff, 0xc3, 0x00, 0x3c, 0x00, 0x51, 0xff, 0xc3, + 0x00, 0x3c, 0x00, 0x52, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0x53, 0xff, 0xc3, + 0x00, 0x3c, 0x00, 0x54, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0x55, 0xff, 0xc3, + 0x00, 0x3c, 0x00, 0x56, 0xff, 0xae, 0x00, 0x3c, 0x00, 0x58, 0xff, 0xc3, + 0x00, 0x3c, 0x00, 0x5d, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x82, 0xff, 0x85, + 0x00, 0x3c, 0x00, 0x83, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x84, 0xff, 0x85, + 0x00, 0x3c, 0x00, 0x85, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x86, 0xff, 0x85, + 0x00, 0x3c, 0x00, 0x87, 0xff, 0x85, 0x00, 0x3c, 0x00, 0x89, 0xff, 0xd7, + 0x00, 0x3c, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x95, 0xff, 0xd7, + 0x00, 0x3c, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x97, 0xff, 0xd7, + 0x00, 0x3c, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x3c, 0x00, 0x9a, 0xff, 0xd7, + 0x00, 0x3c, 0x00, 0xa2, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xa3, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xa4, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xa5, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xa6, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xa7, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xa8, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xa9, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xaa, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xab, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xac, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xad, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xb4, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xb5, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xb6, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xb7, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xb8, 0xff, 0x9a, 0x00, 0x3c, 0x00, 0xba, 0xff, 0x9a, + 0x00, 0x3c, 0x00, 0xbb, 0xff, 0xc3, 0x00, 0x3c, 0x00, 0xbc, 0xff, 0xc3, + 0x00, 0x3c, 0x00, 0xbd, 0xff, 0xc3, 0x00, 0x3c, 0x00, 0xbe, 0xff, 0xc3, + 0x00, 0x3d, 0x00, 0x26, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x2a, 0xff, 0xec, + 0x00, 0x3d, 0x00, 0x32, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x34, 0xff, 0xec, + 0x00, 0x3d, 0x00, 0x89, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x94, 0xff, 0xec, + 0x00, 0x3d, 0x00, 0x95, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x96, 0xff, 0xec, + 0x00, 0x3d, 0x00, 0x97, 0xff, 0xec, 0x00, 0x3d, 0x00, 0x98, 0xff, 0xec, + 0x00, 0x3d, 0x00, 0x9a, 0xff, 0xec, 0x00, 0x3e, 0x00, 0x2d, 0x00, 0xb8, + 0x00, 0x44, 0x00, 0x05, 0xff, 0xec, 0x00, 0x44, 0x00, 0x0a, 0xff, 0xec, + 0x00, 0x45, 0x00, 0x05, 0xff, 0xec, 0x00, 0x45, 0x00, 0x0a, 0xff, 0xec, + 0x00, 0x45, 0x00, 0x59, 0xff, 0xd7, 0x00, 0x45, 0x00, 0x5a, 0xff, 0xd7, + 0x00, 0x45, 0x00, 0x5b, 0xff, 0xd7, 0x00, 0x45, 0x00, 0x5c, 0xff, 0xd7, + 0x00, 0x45, 0x00, 0x5d, 0xff, 0xec, 0x00, 0x45, 0x00, 0xbf, 0xff, 0xd7, + 0x00, 0x46, 0x00, 0x05, 0x00, 0x29, 0x00, 0x46, 0x00, 0x0a, 0x00, 0x29, + 0x00, 0x48, 0x00, 0x05, 0xff, 0xec, 0x00, 0x48, 0x00, 0x0a, 0xff, 0xec, + 0x00, 0x48, 0x00, 0x59, 0xff, 0xd7, 0x00, 0x48, 0x00, 0x5a, 0xff, 0xd7, + 0x00, 0x48, 0x00, 0x5b, 0xff, 0xd7, 0x00, 0x48, 0x00, 0x5c, 0xff, 0xd7, + 0x00, 0x48, 0x00, 0x5d, 0xff, 0xec, 0x00, 0x48, 0x00, 0xbf, 0xff, 0xd7, + 0x00, 0x49, 0x00, 0x05, 0x00, 0x7b, 0x00, 0x49, 0x00, 0x0a, 0x00, 0x7b, + 0x00, 0x4b, 0x00, 0x05, 0xff, 0xec, 0x00, 0x4b, 0x00, 0x0a, 0xff, 0xec, + 0x00, 0x4e, 0x00, 0x46, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0x47, 0xff, 0xd7, + 0x00, 0x4e, 0x00, 0x48, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0x52, 0xff, 0xd7, + 0x00, 0x4e, 0x00, 0x54, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xa2, 0xff, 0xd7, + 0x00, 0x4e, 0x00, 0xa9, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xaa, 0xff, 0xd7, + 0x00, 0x4e, 0x00, 0xab, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xac, 0xff, 0xd7, + 0x00, 0x4e, 0x00, 0xad, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xb4, 0xff, 0xd7, + 0x00, 0x4e, 0x00, 0xb5, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xb6, 0xff, 0xd7, + 0x00, 0x4e, 0x00, 0xb7, 0xff, 0xd7, 0x00, 0x4e, 0x00, 0xb8, 0xff, 0xd7, + 0x00, 0x4e, 0x00, 0xba, 0xff, 0xd7, 0x00, 0x50, 0x00, 0x05, 0xff, 0xec, + 0x00, 0x50, 0x00, 0x0a, 0xff, 0xec, 0x00, 0x51, 0x00, 0x05, 0xff, 0xec, + 0x00, 0x51, 0x00, 0x0a, 0xff, 0xec, 0x00, 0x52, 0x00, 0x05, 0xff, 0xec, + 0x00, 0x52, 0x00, 0x0a, 0xff, 0xec, 0x00, 0x52, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0x52, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0x52, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0x52, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0x52, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0x52, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0x53, 0x00, 0x05, 0xff, 0xec, + 0x00, 0x53, 0x00, 0x0a, 0xff, 0xec, 0x00, 0x53, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0x53, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0x53, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0x53, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0x53, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0x53, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0x55, 0x00, 0x05, 0x00, 0x52, + 0x00, 0x55, 0x00, 0x0a, 0x00, 0x52, 0x00, 0x55, 0x00, 0x44, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0x46, 0xff, 0xd7, 0x00, 0x55, 0x00, 0x47, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0x48, 0xff, 0xd7, 0x00, 0x55, 0x00, 0x4a, 0xff, 0xec, + 0x00, 0x55, 0x00, 0x52, 0xff, 0xd7, 0x00, 0x55, 0x00, 0x54, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xa2, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xa3, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xa4, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xa5, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xa6, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xa7, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xa8, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xa9, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xaa, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xab, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xac, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xad, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xb4, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xb5, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xb6, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xb7, 0xff, 0xd7, + 0x00, 0x55, 0x00, 0xb8, 0xff, 0xd7, 0x00, 0x55, 0x00, 0xba, 0xff, 0xd7, + 0x00, 0x57, 0x00, 0x05, 0x00, 0x29, 0x00, 0x57, 0x00, 0x0a, 0x00, 0x29, + 0x00, 0x59, 0x00, 0x05, 0x00, 0x52, 0x00, 0x59, 0x00, 0x0a, 0x00, 0x52, + 0x00, 0x59, 0x00, 0x0f, 0xff, 0xae, 0x00, 0x59, 0x00, 0x11, 0xff, 0xae, + 0x00, 0x59, 0x00, 0x22, 0x00, 0x29, 0x00, 0x5a, 0x00, 0x05, 0x00, 0x52, + 0x00, 0x5a, 0x00, 0x0a, 0x00, 0x52, 0x00, 0x5a, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x5a, 0x00, 0x11, 0xff, 0xae, 0x00, 0x5a, 0x00, 0x22, 0x00, 0x29, + 0x00, 0x5b, 0x00, 0x46, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0x47, 0xff, 0xd7, + 0x00, 0x5b, 0x00, 0x48, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0x52, 0xff, 0xd7, + 0x00, 0x5b, 0x00, 0x54, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xa2, 0xff, 0xd7, + 0x00, 0x5b, 0x00, 0xa9, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xaa, 0xff, 0xd7, + 0x00, 0x5b, 0x00, 0xab, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xac, 0xff, 0xd7, + 0x00, 0x5b, 0x00, 0xad, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xb4, 0xff, 0xd7, + 0x00, 0x5b, 0x00, 0xb5, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xb6, 0xff, 0xd7, + 0x00, 0x5b, 0x00, 0xb7, 0xff, 0xd7, 0x00, 0x5b, 0x00, 0xb8, 0xff, 0xd7, + 0x00, 0x5b, 0x00, 0xba, 0xff, 0xd7, 0x00, 0x5c, 0x00, 0x05, 0x00, 0x52, + 0x00, 0x5c, 0x00, 0x0a, 0x00, 0x52, 0x00, 0x5c, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x5c, 0x00, 0x11, 0xff, 0xae, 0x00, 0x5c, 0x00, 0x22, 0x00, 0x29, + 0x00, 0x5e, 0x00, 0x2d, 0x00, 0xb8, 0x00, 0x82, 0x00, 0x05, 0xff, 0x71, + 0x00, 0x82, 0x00, 0x0a, 0xff, 0x71, 0x00, 0x82, 0x00, 0x26, 0xff, 0xd7, + 0x00, 0x82, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x2d, 0x01, 0x0a, + 0x00, 0x82, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x82, 0x00, 0x37, 0xff, 0x71, 0x00, 0x82, 0x00, 0x39, 0xff, 0xae, + 0x00, 0x82, 0x00, 0x3a, 0xff, 0xae, 0x00, 0x82, 0x00, 0x3c, 0xff, 0x85, + 0x00, 0x82, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x82, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x82, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x82, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x82, 0x00, 0x9f, 0xff, 0x85, + 0x00, 0x83, 0x00, 0x05, 0xff, 0x71, 0x00, 0x83, 0x00, 0x0a, 0xff, 0x71, + 0x00, 0x83, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x2a, 0xff, 0xd7, + 0x00, 0x83, 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x83, 0x00, 0x32, 0xff, 0xd7, + 0x00, 0x83, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x37, 0xff, 0x71, + 0x00, 0x83, 0x00, 0x39, 0xff, 0xae, 0x00, 0x83, 0x00, 0x3a, 0xff, 0xae, + 0x00, 0x83, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x83, 0x00, 0x89, 0xff, 0xd7, + 0x00, 0x83, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x95, 0xff, 0xd7, + 0x00, 0x83, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x97, 0xff, 0xd7, + 0x00, 0x83, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x83, 0x00, 0x9a, 0xff, 0xd7, + 0x00, 0x83, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x84, 0x00, 0x05, 0xff, 0x71, + 0x00, 0x84, 0x00, 0x0a, 0xff, 0x71, 0x00, 0x84, 0x00, 0x26, 0xff, 0xd7, + 0x00, 0x84, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x2d, 0x01, 0x0a, + 0x00, 0x84, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x84, 0x00, 0x37, 0xff, 0x71, 0x00, 0x84, 0x00, 0x39, 0xff, 0xae, + 0x00, 0x84, 0x00, 0x3a, 0xff, 0xae, 0x00, 0x84, 0x00, 0x3c, 0xff, 0x85, + 0x00, 0x84, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x84, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x84, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x84, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x84, 0x00, 0x9f, 0xff, 0x85, + 0x00, 0x85, 0x00, 0x05, 0xff, 0x71, 0x00, 0x85, 0x00, 0x0a, 0xff, 0x71, + 0x00, 0x85, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x2a, 0xff, 0xd7, + 0x00, 0x85, 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x85, 0x00, 0x32, 0xff, 0xd7, + 0x00, 0x85, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x37, 0xff, 0x71, + 0x00, 0x85, 0x00, 0x39, 0xff, 0xae, 0x00, 0x85, 0x00, 0x3a, 0xff, 0xae, + 0x00, 0x85, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x85, 0x00, 0x89, 0xff, 0xd7, + 0x00, 0x85, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x95, 0xff, 0xd7, + 0x00, 0x85, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x97, 0xff, 0xd7, + 0x00, 0x85, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x85, 0x00, 0x9a, 0xff, 0xd7, + 0x00, 0x85, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x86, 0x00, 0x05, 0xff, 0x71, + 0x00, 0x86, 0x00, 0x0a, 0xff, 0x71, 0x00, 0x86, 0x00, 0x26, 0xff, 0xd7, + 0x00, 0x86, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x2d, 0x01, 0x0a, + 0x00, 0x86, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x86, 0x00, 0x37, 0xff, 0x71, 0x00, 0x86, 0x00, 0x39, 0xff, 0xae, + 0x00, 0x86, 0x00, 0x3a, 0xff, 0xae, 0x00, 0x86, 0x00, 0x3c, 0xff, 0x85, + 0x00, 0x86, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x86, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x86, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x86, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x86, 0x00, 0x9f, 0xff, 0x85, + 0x00, 0x87, 0x00, 0x05, 0xff, 0x71, 0x00, 0x87, 0x00, 0x0a, 0xff, 0x71, + 0x00, 0x87, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x2a, 0xff, 0xd7, + 0x00, 0x87, 0x00, 0x2d, 0x01, 0x0a, 0x00, 0x87, 0x00, 0x32, 0xff, 0xd7, + 0x00, 0x87, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x37, 0xff, 0x71, + 0x00, 0x87, 0x00, 0x39, 0xff, 0xae, 0x00, 0x87, 0x00, 0x3a, 0xff, 0xae, + 0x00, 0x87, 0x00, 0x3c, 0xff, 0x85, 0x00, 0x87, 0x00, 0x89, 0xff, 0xd7, + 0x00, 0x87, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x95, 0xff, 0xd7, + 0x00, 0x87, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x97, 0xff, 0xd7, + 0x00, 0x87, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x87, 0x00, 0x9a, 0xff, 0xd7, + 0x00, 0x87, 0x00, 0x9f, 0xff, 0x85, 0x00, 0x88, 0x00, 0x2d, 0x00, 0x7b, + 0x00, 0x89, 0x00, 0x26, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x2a, 0xff, 0xd7, + 0x00, 0x89, 0x00, 0x32, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x34, 0xff, 0xd7, + 0x00, 0x89, 0x00, 0x89, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x94, 0xff, 0xd7, + 0x00, 0x89, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x89, 0x00, 0x97, 0xff, 0xd7, 0x00, 0x89, 0x00, 0x98, 0xff, 0xd7, + 0x00, 0x89, 0x00, 0x9a, 0xff, 0xd7, 0x00, 0x8a, 0x00, 0x2d, 0x00, 0x7b, + 0x00, 0x8b, 0x00, 0x2d, 0x00, 0x7b, 0x00, 0x8c, 0x00, 0x2d, 0x00, 0x7b, + 0x00, 0x8d, 0x00, 0x2d, 0x00, 0x7b, 0x00, 0x92, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x92, 0x00, 0x11, 0xff, 0xae, 0x00, 0x92, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x92, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x92, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x92, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x92, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x92, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x92, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x92, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x92, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x92, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x92, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x92, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x92, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x92, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x94, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x94, 0x00, 0x11, 0xff, 0xae, 0x00, 0x94, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x94, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x94, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x94, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x94, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x94, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x94, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x94, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x94, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x94, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x94, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x94, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x94, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x94, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x95, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x95, 0x00, 0x11, 0xff, 0xae, 0x00, 0x95, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x95, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x95, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x95, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x95, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x95, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x95, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x95, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x95, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x95, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x95, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x95, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x95, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x95, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x96, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x96, 0x00, 0x11, 0xff, 0xae, 0x00, 0x96, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x96, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x96, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x96, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x96, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x96, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x96, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x96, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x96, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x96, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x96, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x96, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x96, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x96, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x97, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x97, 0x00, 0x11, 0xff, 0xae, 0x00, 0x97, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x97, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x97, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x97, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x97, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x97, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x97, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x97, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x97, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x97, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x97, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x97, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x97, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x97, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x98, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x98, 0x00, 0x11, 0xff, 0xae, 0x00, 0x98, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x98, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x98, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x98, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x98, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x98, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x98, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x98, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x98, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x98, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x98, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x98, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x98, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x98, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x9a, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0x9a, 0x00, 0x11, 0xff, 0xae, 0x00, 0x9a, 0x00, 0x24, 0xff, 0xd7, + 0x00, 0x9a, 0x00, 0x37, 0xff, 0xc3, 0x00, 0x9a, 0x00, 0x39, 0xff, 0xec, + 0x00, 0x9a, 0x00, 0x3a, 0xff, 0xec, 0x00, 0x9a, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0x9a, 0x00, 0x3c, 0xff, 0xec, 0x00, 0x9a, 0x00, 0x3d, 0xff, 0xec, + 0x00, 0x9a, 0x00, 0x82, 0xff, 0xd7, 0x00, 0x9a, 0x00, 0x83, 0xff, 0xd7, + 0x00, 0x9a, 0x00, 0x84, 0xff, 0xd7, 0x00, 0x9a, 0x00, 0x85, 0xff, 0xd7, + 0x00, 0x9a, 0x00, 0x86, 0xff, 0xd7, 0x00, 0x9a, 0x00, 0x87, 0xff, 0xd7, + 0x00, 0x9a, 0x00, 0x9f, 0xff, 0xec, 0x00, 0x9b, 0x00, 0x0f, 0xff, 0xd7, + 0x00, 0x9b, 0x00, 0x11, 0xff, 0xd7, 0x00, 0x9b, 0x00, 0x24, 0xff, 0xec, + 0x00, 0x9b, 0x00, 0x82, 0xff, 0xec, 0x00, 0x9b, 0x00, 0x83, 0xff, 0xec, + 0x00, 0x9b, 0x00, 0x84, 0xff, 0xec, 0x00, 0x9b, 0x00, 0x85, 0xff, 0xec, + 0x00, 0x9b, 0x00, 0x86, 0xff, 0xec, 0x00, 0x9b, 0x00, 0x87, 0xff, 0xec, + 0x00, 0x9c, 0x00, 0x0f, 0xff, 0xd7, 0x00, 0x9c, 0x00, 0x11, 0xff, 0xd7, + 0x00, 0x9c, 0x00, 0x24, 0xff, 0xec, 0x00, 0x9c, 0x00, 0x82, 0xff, 0xec, + 0x00, 0x9c, 0x00, 0x83, 0xff, 0xec, 0x00, 0x9c, 0x00, 0x84, 0xff, 0xec, + 0x00, 0x9c, 0x00, 0x85, 0xff, 0xec, 0x00, 0x9c, 0x00, 0x86, 0xff, 0xec, + 0x00, 0x9c, 0x00, 0x87, 0xff, 0xec, 0x00, 0x9d, 0x00, 0x0f, 0xff, 0xd7, + 0x00, 0x9d, 0x00, 0x11, 0xff, 0xd7, 0x00, 0x9d, 0x00, 0x24, 0xff, 0xec, + 0x00, 0x9d, 0x00, 0x82, 0xff, 0xec, 0x00, 0x9d, 0x00, 0x83, 0xff, 0xec, + 0x00, 0x9d, 0x00, 0x84, 0xff, 0xec, 0x00, 0x9d, 0x00, 0x85, 0xff, 0xec, + 0x00, 0x9d, 0x00, 0x86, 0xff, 0xec, 0x00, 0x9d, 0x00, 0x87, 0xff, 0xec, + 0x00, 0x9e, 0x00, 0x0f, 0xff, 0xd7, 0x00, 0x9e, 0x00, 0x11, 0xff, 0xd7, + 0x00, 0x9e, 0x00, 0x24, 0xff, 0xec, 0x00, 0x9e, 0x00, 0x82, 0xff, 0xec, + 0x00, 0x9e, 0x00, 0x83, 0xff, 0xec, 0x00, 0x9e, 0x00, 0x84, 0xff, 0xec, + 0x00, 0x9e, 0x00, 0x85, 0xff, 0xec, 0x00, 0x9e, 0x00, 0x86, 0xff, 0xec, + 0x00, 0x9e, 0x00, 0x87, 0xff, 0xec, 0x00, 0x9f, 0x00, 0x0f, 0xff, 0x85, + 0x00, 0x9f, 0x00, 0x11, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x22, 0x00, 0x29, + 0x00, 0x9f, 0x00, 0x24, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x26, 0xff, 0xd7, + 0x00, 0x9f, 0x00, 0x2a, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x32, 0xff, 0xd7, + 0x00, 0x9f, 0x00, 0x34, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x44, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0x46, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0x47, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0x48, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0x4a, 0xff, 0xd7, + 0x00, 0x9f, 0x00, 0x50, 0xff, 0xc3, 0x00, 0x9f, 0x00, 0x51, 0xff, 0xc3, + 0x00, 0x9f, 0x00, 0x52, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0x53, 0xff, 0xc3, + 0x00, 0x9f, 0x00, 0x54, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0x55, 0xff, 0xc3, + 0x00, 0x9f, 0x00, 0x56, 0xff, 0xae, 0x00, 0x9f, 0x00, 0x58, 0xff, 0xc3, + 0x00, 0x9f, 0x00, 0x5d, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x82, 0xff, 0x85, + 0x00, 0x9f, 0x00, 0x83, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x84, 0xff, 0x85, + 0x00, 0x9f, 0x00, 0x85, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x86, 0xff, 0x85, + 0x00, 0x9f, 0x00, 0x87, 0xff, 0x85, 0x00, 0x9f, 0x00, 0x89, 0xff, 0xd7, + 0x00, 0x9f, 0x00, 0x94, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x95, 0xff, 0xd7, + 0x00, 0x9f, 0x00, 0x96, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x97, 0xff, 0xd7, + 0x00, 0x9f, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x9f, 0x00, 0x9a, 0xff, 0xd7, + 0x00, 0x9f, 0x00, 0xa2, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xa3, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xa4, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xa5, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xa6, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xa7, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xa8, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xa9, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xaa, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xab, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xac, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xad, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xb4, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xb5, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xb6, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xb7, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xb8, 0xff, 0x9a, 0x00, 0x9f, 0x00, 0xba, 0xff, 0x9a, + 0x00, 0x9f, 0x00, 0xbb, 0xff, 0xc3, 0x00, 0x9f, 0x00, 0xbc, 0xff, 0xc3, + 0x00, 0x9f, 0x00, 0xbd, 0xff, 0xc3, 0x00, 0x9f, 0x00, 0xbe, 0xff, 0xc3, + 0x00, 0xa0, 0x00, 0x0f, 0xfe, 0xf6, 0x00, 0xa0, 0x00, 0x11, 0xfe, 0xf6, + 0x00, 0xa0, 0x00, 0x24, 0xff, 0x9a, 0x00, 0xa0, 0x00, 0x3b, 0xff, 0xd7, + 0x00, 0xa0, 0x00, 0x3d, 0xff, 0xec, 0x00, 0xa0, 0x00, 0x82, 0xff, 0x9a, + 0x00, 0xa0, 0x00, 0x83, 0xff, 0x9a, 0x00, 0xa0, 0x00, 0x84, 0xff, 0x9a, + 0x00, 0xa0, 0x00, 0x85, 0xff, 0x9a, 0x00, 0xa0, 0x00, 0x86, 0xff, 0x9a, + 0x00, 0xa0, 0x00, 0x87, 0xff, 0x9a, 0x00, 0xa2, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xa2, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa3, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xa3, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa4, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xa4, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa5, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xa5, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa6, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xa6, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xa7, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xa7, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xaa, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xaa, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xaa, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xaa, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xaa, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xaa, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xaa, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xaa, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xab, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xab, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xab, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xab, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xab, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xab, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xab, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xab, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xac, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xac, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xac, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xac, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xac, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xac, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xac, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xac, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xad, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xad, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xad, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xad, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xad, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xad, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xad, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xad, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb2, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xb2, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xb2, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xb2, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xb2, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xb2, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xb2, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xb2, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb4, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xb4, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xb4, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xb4, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xb4, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xb4, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xb4, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xb4, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb5, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xb5, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xb5, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xb5, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xb5, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xb5, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xb5, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xb5, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb6, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xb6, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xb6, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xb6, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xb6, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xb6, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xb6, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xb6, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xb8, 0x00, 0x05, 0xff, 0xd7, + 0x00, 0xb8, 0x00, 0x0a, 0xff, 0xd7, 0x00, 0xba, 0x00, 0x05, 0xff, 0xec, + 0x00, 0xba, 0x00, 0x0a, 0xff, 0xec, 0x00, 0xba, 0x00, 0x59, 0xff, 0xd7, + 0x00, 0xba, 0x00, 0x5a, 0xff, 0xd7, 0x00, 0xba, 0x00, 0x5b, 0xff, 0xd7, + 0x00, 0xba, 0x00, 0x5c, 0xff, 0xd7, 0x00, 0xba, 0x00, 0x5d, 0xff, 0xec, + 0x00, 0xba, 0x00, 0xbf, 0xff, 0xd7, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x52, + 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x52, 0x00, 0xbf, 0x00, 0x0f, 0xff, 0xae, + 0x00, 0xbf, 0x00, 0x11, 0xff, 0xae, 0x00, 0xbf, 0x00, 0x22, 0x00, 0x29, + 0x00, 0xc0, 0x00, 0x05, 0xff, 0xec, 0x00, 0xc0, 0x00, 0x0a, 0xff, 0xec, + 0x00, 0xc0, 0x00, 0x59, 0xff, 0xd7, 0x00, 0xc0, 0x00, 0x5a, 0xff, 0xd7, + 0x00, 0xc0, 0x00, 0x5b, 0xff, 0xd7, 0x00, 0xc0, 0x00, 0x5c, 0xff, 0xd7, + 0x00, 0xc0, 0x00, 0x5d, 0xff, 0xec, 0x00, 0xc0, 0x00, 0xbf, 0xff, 0xd7, + 0x00, 0xc1, 0x00, 0x05, 0x00, 0x52, 0x00, 0xc1, 0x00, 0x0a, 0x00, 0x52, + 0x00, 0xc1, 0x00, 0x0f, 0xff, 0xae, 0x00, 0xc1, 0x00, 0x11, 0xff, 0xae, + 0x00, 0xc1, 0x00, 0x22, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, + 0x02, 0x52, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, + 0x00, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, + 0x00, 0xc2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, + 0x00, 0xdc, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1e, + 0x01, 0x22, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, + 0x01, 0x55, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0c, + 0x01, 0x79, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, + 0x01, 0x98, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x52, + 0x02, 0x47, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, + 0x02, 0xc4, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x1c, + 0x03, 0x13, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x2e, + 0x03, 0x8e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x2e, + 0x04, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x2a, + 0x04, 0xa0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x18, + 0x04, 0xcb, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x0b, + 0x05, 0x52, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x11, + 0x05, 0x7e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x12, + 0x05, 0xed, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x12, + 0x06, 0x54, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x18, + 0x04, 0xe4, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x12, + 0x05, 0x5e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x1f, + 0x05, 0x90, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x1f, + 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x04, 0x00, 0x23, + 0x06, 0x67, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x21, + 0x04, 0xfd, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x02, 0x00, 0x17, + 0x05, 0xb0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x10, + 0x06, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x04, 0x00, 0x0f, + 0x06, 0x8b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x15, + 0x05, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x00, 0x11, + 0x05, 0xc8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x01, 0x03, 0x00, 0x13, + 0x06, 0x31, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x01, 0x04, 0x00, 0x0c, + 0x06, 0x9b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x1c, + 0x05, 0x35, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x0c, + 0x05, 0x71, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x00, 0x12, + 0x05, 0xda, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x01, 0x03, 0x00, 0x0e, + 0x06, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x01, 0x04, 0x00, 0x0d, + 0x06, 0xa8, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x72, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x12, + 0x00, 0xae, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0e, + 0x00, 0xcc, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x3c, + 0x00, 0xe4, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x12, + 0x01, 0x41, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x18, + 0x01, 0x5f, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x10, + 0x01, 0x86, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x07, 0x00, 0xa4, + 0x01, 0xa1, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x08, 0x00, 0x28, + 0x02, 0x9a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x0b, 0x00, 0x38, + 0x02, 0xd9, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x0c, 0x00, 0x5c, + 0x03, 0x30, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x0d, 0x00, 0x5c, + 0x03, 0xbd, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x0e, 0x00, 0x54, + 0x04, 0x4a, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74, + 0x00, 0x69, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x64, + 0x00, 0x61, 0x00, 0x74, 0x00, 0x61, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, + 0x00, 0x70, 0x00, 0x79, 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, + 0x00, 0x74, 0x00, 0x20, 0x00, 0xa9, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, + 0x00, 0x31, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, + 0x00, 0x31, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, + 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, + 0x00, 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, + 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x00, 0x44, 0x69, + 0x67, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, + 0x20, 0x63, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0xa9, + 0x20, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x32, 0x30, 0x31, 0x31, 0x2c, 0x20, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x00, 0x00, 0x4f, 0x00, 0x70, + 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, + 0x00, 0x73, 0x00, 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x20, 0x53, 0x61, 0x6e, + 0x73, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, + 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, + 0x72, 0x00, 0x00, 0x41, 0x00, 0x73, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, + 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, + 0x00, 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x53, + 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, 0x42, 0x00, 0x75, + 0x00, 0x69, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x20, 0x00, 0x31, 0x00, 0x30, + 0x00, 0x30, 0x00, 0x00, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x20, 0x2d, 0x20, 0x4f, 0x70, 0x65, 0x6e, 0x20, 0x53, 0x61, 0x6e, 0x73, + 0x20, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x20, 0x31, 0x30, 0x30, 0x00, 0x00, + 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x53, 0x00, + 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x20, + 0x53, 0x61, 0x6e, 0x73, 0x00, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x31, 0x00, + 0x2e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x00, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x31, 0x30, 0x00, 0x00, 0x4f, 0x00, 0x70, + 0x00, 0x65, 0x00, 0x6e, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, + 0x00, 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x61, 0x6e, 0x73, 0x00, 0x00, + 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x53, 0x00, + 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, + 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, + 0x64, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x72, 0x00, 0x6b, 0x00, + 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x47, 0x00, 0x6f, 0x00, + 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x61, 0x00, + 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x79, 0x00, + 0x20, 0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, 0x72, 0x00, 0x65, 0x00, + 0x67, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x20, 0x00, + 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x61, 0x00, 0x69, 0x00, + 0x6e, 0x00, 0x20, 0x00, 0x6a, 0x00, 0x75, 0x00, 0x72, 0x00, 0x69, 0x00, + 0x73, 0x00, 0x64, 0x00, 0x69, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, + 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x00, 0x4f, 0x70, 0x65, + 0x6e, 0x20, 0x53, 0x61, 0x6e, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, + 0x74, 0x72, 0x61, 0x64, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x20, 0x6f, 0x66, + 0x20, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x65, 0x72, + 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6a, 0x75, 0x72, 0x69, 0x73, 0x64, 0x69, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x00, 0x00, 0x41, 0x00, 0x73, + 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, + 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x6f, + 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, + 0x00, 0x00, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x43, + 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, + 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, + 0x2f, 0x00, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x61, 0x00, + 0x73, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x65, 0x00, + 0x72, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x2e, 0x00, + 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2f, 0x00, 0x00, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x73, 0x63, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, + 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x2e, + 0x00, 0x61, 0x00, 0x73, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x64, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, + 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2f, 0x00, 0x74, + 0x00, 0x79, 0x00, 0x70, 0x00, 0x65, 0x00, 0x64, 0x00, 0x65, 0x00, 0x73, + 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, + 0x00, 0x2e, 0x00, 0x68, 0x00, 0x74, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x00, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, + 0x73, 0x63, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0x00, + 0x4c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, + 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, + 0x20, 0x00, 0x41, 0x00, 0x70, 0x00, 0x61, 0x00, 0x63, 0x00, 0x68, 0x00, + 0x65, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, + 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x56, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, + 0x20, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x00, 0x4c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x64, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x4c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x2e, 0x30, 0x00, 0x00, 0x68, 0x00, 0x74, + 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, + 0x00, 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x70, 0x00, 0x61, + 0x00, 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x72, + 0x00, 0x67, 0x00, 0x2f, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, + 0x00, 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x4c, + 0x00, 0x49, 0x00, 0x43, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x53, 0x00, 0x45, + 0x00, 0x2d, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x00, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x61, + 0x63, 0x68, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x6c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x73, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, + 0x2d, 0x32, 0x2e, 0x30, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x54, 0x79, 0x70, + 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x65, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x00, 0x46, 0x6f, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x69, 0x71, 0x75, 0x65, 0x73, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, + 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x66, 0x69, 0x73, 0x63, 0x68, + 0x65, 0x6e, 0x20, 0x4d, 0x9a, 0x67, 0x6c, 0x69, 0x63, 0x68, 0x6b, 0x65, + 0x69, 0x74, 0x65, 0x6e, 0x00, 0x46, 0x75, 0x6e, 0x7a, 0x69, 0x6f, 0x6e, + 0x69, 0x20, 0x54, 0x69, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x66, 0x69, 0x63, + 0x68, 0x65, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x6f, + 0x67, 0x72, 0x61, 0x66, 0x69, 0x73, 0x63, 0x68, 0x65, 0x20, 0x6b, 0x65, + 0x6e, 0x6d, 0x65, 0x72, 0x6b, 0x65, 0x6e, 0x00, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x20, 0x43, 0x61, 0x73, 0x65, 0x00, 0x53, 0x74, 0x79, 0x6c, + 0x65, 0x20, 0x64, 0x65, 0x73, 0x20, 0x43, 0x68, 0x69, 0x66, 0x66, 0x72, + 0x65, 0x73, 0x00, 0x4e, 0x75, 0x6d, 0x6d, 0x65, 0x72, 0x68, 0x6f, 0x6f, + 0x67, 0x74, 0x65, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x54, 0x79, 0x70, 0x65, + 0x20, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x00, 0x54, 0x6f, + 0x75, 0x74, 0x65, 0x73, 0x20, 0x66, 0x6f, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x20, 0x74, 0x79, 0x70, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x69, 0x71, 0x75, 0x65, 0x73, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x20, 0x41, + 0x75, 0x73, 0x7a, 0x65, 0x69, 0x63, 0x68, 0x6e, 0x75, 0x6e, 0x67, 0x73, + 0x61, 0x72, 0x74, 0x65, 0x6e, 0x00, 0x54, 0x75, 0x74, 0x74, 0x65, 0x20, + 0x6c, 0x65, 0x20, 0x46, 0x75, 0x6e, 0x7a, 0x69, 0x6f, 0x6e, 0x69, 0x00, + 0x41, 0x6c, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x6b, 0x65, 0x6e, + 0x6d, 0x65, 0x72, 0x6b, 0x65, 0x6e, 0x00, 0x4c, 0x6f, 0x77, 0x65, 0x72, + 0x20, 0x43, 0x61, 0x73, 0x65, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x00, 0x43, 0x68, 0x69, 0x66, 0x66, 0x72, 0x65, 0x73, 0x20, 0x41, + 0x6e, 0x63, 0x69, 0x65, 0x6e, 0x73, 0x20, 0x28, 0x62, 0x61, 0x73, 0x20, + 0x64, 0x65, 0x20, 0x63, 0x61, 0x73, 0x73, 0x65, 0x29, 0x00, 0x4d, 0x65, + 0x64, 0x69, 0xbe, 0x76, 0x61, 0x6c, 0x2d, 0x5a, 0x69, 0x66, 0x66, 0x65, + 0x72, 0x6e, 0x00, 0x53, 0x6f, 0x70, 0x72, 0x61, 0x20, 0x6c, 0x61, 0x20, + 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x20, 0x42, 0x61, 0x73, 0x65, 0x00, 0x4b, + 0x6c, 0x65, 0x69, 0x6e, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x6d, 0x65, 0x72, + 0x73, 0x00, 0x55, 0x70, 0x70, 0x65, 0x72, 0x20, 0x43, 0x61, 0x73, 0x65, + 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00, 0x43, 0x68, 0x69, + 0x66, 0x66, 0x72, 0x65, 0x73, 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x6e, + 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x20, 0x28, 0x61, 0x6c, + 0x69, 0x67, 0x6e, 0x61, 0x6e, 0x74, 0x73, 0x29, 0x00, 0x4e, 0x6f, 0x72, + 0x6d, 0x61, 0x6c, 0x65, 0x20, 0x5a, 0x69, 0x66, 0x66, 0x65, 0x72, 0x6e, + 0x00, 0x54, 0x72, 0x61, 0x64, 0x69, 0x7a, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x65, 0x00, 0x47, 0x72, 0x6f, 0x74, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x6d, + 0x65, 0x72, 0x73, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x66, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, + 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, + 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, + 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, + 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, + 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, + 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, + 0x00, 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, + 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, + 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x40, + 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, + 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, + 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, + 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, + 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, + 0x00, 0x5f, 0x00, 0x60, 0x00, 0x61, 0x00, 0xac, 0x00, 0xa3, 0x00, 0x84, + 0x00, 0x85, 0x00, 0xbd, 0x00, 0x96, 0x00, 0xe8, 0x00, 0x86, 0x00, 0x8e, + 0x00, 0x8b, 0x00, 0x9d, 0x00, 0xa9, 0x00, 0xa4, 0x01, 0x02, 0x00, 0x8a, + 0x01, 0x03, 0x00, 0x83, 0x00, 0x93, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0x8d, + 0x00, 0x97, 0x00, 0x88, 0x00, 0xc3, 0x00, 0xde, 0x00, 0xf1, 0x00, 0x9e, + 0x00, 0xaa, 0x00, 0xf5, 0x00, 0xf4, 0x00, 0xf6, 0x00, 0xa2, 0x00, 0xad, + 0x00, 0xc9, 0x00, 0xc7, 0x00, 0xae, 0x00, 0x62, 0x00, 0x63, 0x00, 0x90, + 0x00, 0x64, 0x00, 0xcb, 0x00, 0x65, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcf, + 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xe9, 0x00, 0x66, 0x00, 0xd3, + 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xaf, 0x00, 0x67, 0x00, 0xf0, 0x00, 0x91, + 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0x68, 0x00, 0xeb, 0x00, 0xed, + 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x6b, 0x00, 0x6d, 0x00, 0x6c, + 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x70, 0x00, 0x72, + 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0xea, + 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x7c, + 0x00, 0xb8, 0x00, 0xa1, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x81, + 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, + 0x41, 0x44, 0x09, 0x6f, 0x76, 0x65, 0x72, 0x73, 0x63, 0x6f, 0x72, 0x65, + 0x00, 0x01, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x07, + 0xff, 0xff, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x15, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x15, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, + 0xc0, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x03, + 0x00, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xe5, 0x64, 0x3d, 0xfb, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x35, 0x31, 0x8b, + 0x00, 0x00, 0x00, 0x00, 0xe5, 0xf9, 0x0a, 0x4d}; +unsigned int MwTTFDataSize = 35264; +#endif diff --git a/widget/milsko/milskosrc/src/text/ft2.c b/widget/milsko/milskosrc/src/text/ft2.c new file mode 100644 index 0000000000..13e8208c14 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/ft2.c @@ -0,0 +1,188 @@ +#ifdef USE_FREETYPE2 +#include + +#include +#include FT_FREETYPE_H + +static struct ft_table { + FT_Error (*FT_Init_FreeType)(FT_Library* alibrary); + FT_Error (*FT_New_Memory_Face)(FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face* aface); + FT_Error (*FT_Set_Pixel_Sizes)(FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height); + FT_Error (*FT_Load_Char)(FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags); + FT_Error (*FT_Get_Kerning)(FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector* akerning); + FT_Error (*FT_Done_Face)(FT_Face face); + FT_Error (*FT_Done_FreeType)(FT_Library library); + +} ft_table; + +struct _MwFLFont { + FT_Library library; + FT_Face face; + void* data; + int px; +}; +static int ft2_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color) { + int tw, th; + unsigned char* px; + MwLLPixmap p; + MwRect r; + int x = 0, y = 0; + + tw = MwTextWidth(handle, ttf, text); + th = MwTextHeight(handle, ttf, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + while(text[0] != 0) { + FT_Bitmap* bmp; + int cy, cx; + int c, c2; + FT_Vector vec; + const char* old_text; + + text += MwUTF8ToUTF32(text, &c); + + ft_table.FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); + bmp = &ttf->face->glyph->bitmap; + + for(cy = 0; cy < bmp->rows; cy++) { + for(cx = 0; cx < bmp->width; cx++) { + int ox = x + cx + ttf->face->glyph->bitmap_left; + int oy = y + (ttf->face->height * ttf->px / ttf->face->units_per_EM) - ttf->face->glyph->bitmap_top + cy + (ttf->face->descender * ttf->px / ttf->face->units_per_EM); + unsigned char* opx = &px[(oy * tw + ox) * 4]; + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + /* overflow check */ + if(opx[3] + bmp->buffer[cy * bmp->pitch + cx] < opx[3]) { + opx[3] = 255; + } else { + opx[3] = bmp->buffer[cy * bmp->pitch + cx]; + } + } + } + + x += (ttf->face->glyph->advance.x >> 6); + + old_text = text; + text += MwUTF8ToUTF32(text, &c2); + + ft_table.FT_Get_Kerning(ttf->face, c, c2, FT_KERNING_DEFAULT, &vec); + + x += vec.x >> 6; + + text = old_text; + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + return 0; +} + +static int ft2_MwTextWidth(MwFLFont ttf, const char* text) { + int tw = 0; + FT_Vector vec; + + while(text[0] != 0) { + int c, c2; + const char* old_text; + + text += MwUTF8ToUTF32(text, &c); + + ft_table.FT_Load_Char(ttf->face, c, FT_LOAD_DEFAULT); + + tw += ttf->face->glyph->advance.x >> 6; + + old_text = text; + text += MwUTF8ToUTF32(text, &c2); + + ft_table.FT_Get_Kerning(ttf->face, c, c2, FT_KERNING_DEFAULT, &vec); + + tw += vec.x >> 6; + + text = old_text; + } + + if(tw > 0) { + tw -= vec.x >> 6; + tw -= ttf->face->glyph->advance.x >> 6; + tw += ttf->face->glyph->bitmap_left + ttf->face->glyph->bitmap.width; + } + + return tw + 1; +} + +static int ft2_MwTextHeight(MwFLFont ttf, int count) { + return ceil((ttf->face->height * ttf->px / ttf->face->units_per_EM) * count); +} + +static void* ft2_MwFontLoad(unsigned char* data, unsigned int size, int px) { + MwFLFont ttf = malloc(sizeof(*ttf)); + ttf->data = malloc(size); + memcpy(ttf->data, data, size); + ft_table.FT_Init_FreeType(&ttf->library); + ft_table.FT_New_Memory_Face(ttf->library, ttf->data, size, 0, &ttf->face); + + ttf->px = px; + ft_table.FT_Set_Pixel_Sizes(ttf->face, 0, ttf->px); + + return ttf; +} + +static void ft2_MwFontFree(void* handle) { + MwFLFont ttf = handle; + + ft_table.FT_Done_Face(ttf->face); + ft_table.FT_Done_FreeType(ttf->library); + + free(ttf->data); + free(ttf); +} + +int MwFL_FT2Setup(void) { + /* Try and load FreeType2. If it fails, return 1, signifying we default to stbtt. */ + void* ftlib; +#ifdef __APPLE__ + if(!(ftlib = MwDynamicOpen("libfreetype.dylib"))) { +#else + if(!(ftlib = MwDynamicOpen("libfreetype.so"))) { +#endif + return 1; + } + + ft_table.FT_Init_FreeType = MwDynamicSymbol(ftlib, "FT_Init_FreeType"); + ft_table.FT_New_Memory_Face = MwDynamicSymbol(ftlib, "FT_New_Memory_Face"); + ft_table.FT_Set_Pixel_Sizes = MwDynamicSymbol(ftlib, "FT_Set_Pixel_Sizes"); + ft_table.FT_Load_Char = MwDynamicSymbol(ftlib, "FT_Load_Char"); + ft_table.FT_Get_Kerning = MwDynamicSymbol(ftlib, "FT_Get_Kerning"); + ft_table.FT_Done_Face = MwDynamicSymbol(ftlib, "FT_Done_Face"); + ft_table.FT_Done_FreeType = MwDynamicSymbol(ftlib, "FT_Done_FreeType"); + + MwFLDrawText = ft2_MwDrawText; + MwFLTextWidth = ft2_MwTextWidth; + MwFLTextHeight = ft2_MwTextHeight; + MwFLFontLoad = ft2_MwFontLoad; + MwFLFontFree = ft2_MwFontFree; + return 0; +} +#endif diff --git a/widget/milsko/milskosrc/src/text/gdi.c b/widget/milsko/milskosrc/src/text/gdi.c new file mode 100644 index 0000000000..b764353d7a --- /dev/null +++ b/widget/milsko/milskosrc/src/text/gdi.c @@ -0,0 +1,269 @@ +#ifdef USE_GDI_TEXT +#include + +static HANDLE(WINAPI* _AddFontMemResourceEx)(PVOID pFileView, DWORD cjSize, PVOID pvResrved, DWORD* pNumFonts) = NULL; +static BOOL(WINAPI* _RemoveFontMemResourceEx)(HANDLE h) = NULL; +static HANDLE WINAPI _AddFontMemResourceExPolyFill(PVOID pFileView, DWORD cjSize, PVOID pvResrved, DWORD* pNumFonts); +static BOOL WINAPI _RemoveFontMemResourceExPolyFill(HANDLE h); + +struct _MwFLFont { + HANDLE handle; + HFONT font; + HDC dc; +}; + +static int GDI_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color) { + BITMAPINFOHEADER bmih; + int tw; + int th; + HBITMAP hbm; + RGBQUAD* bits = NULL; + HDC hmdc; + char* t = MwUTF8ToACP(text); + unsigned char* px; + int y, x; + MwRect r; + MwLLPixmap p; + + tw = MwTextWidth(handle, ttf, text); + th = MwTextHeight(handle, ttf, text); + + if(handle->lowlevel->common.type == MwLLBackendGDI && MwGetInteger(handle, MwNmodernLook) == MwFALSE) { + HFONT old_font = SelectObject(handle->lowlevel->gdi.hDC, ttf->font); + int old_bkmode = SetBkMode(handle->lowlevel->gdi.hDC, TRANSPARENT); + COLORREF old_color = SetTextColor(handle->lowlevel->gdi.hDC, color->gdi.color); + + TextOut(handle->lowlevel->gdi.hDC, point->x, point->y - th / 2, t, strlen(t)); + + SetTextColor(handle->lowlevel->gdi.hDC, old_color); + SetBkMode(handle->lowlevel->gdi.hDC, old_bkmode); + SelectObject(handle->lowlevel->gdi.hDC, old_font); + + free(t); + + return 0; + } + + px = malloc(tw * th * 4); + + bmih.biSize = sizeof(bmih); + bmih.biWidth = tw; + bmih.biHeight = -(LONG)th; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = BI_RGB; + bmih.biSizeImage = 0; + bmih.biXPelsPerMeter = 0; + bmih.biYPelsPerMeter = 0; + bmih.biClrUsed = 0; + bmih.biClrImportant = 0; + + hbm = CreateDIBSection(ttf->dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + + hmdc = CreateCompatibleDC(ttf->dc); + SelectObject(hmdc, hbm); + SelectObject(hmdc, ttf->font); + + TextOut(hmdc, 0, 0, t, strlen(t)); + + DeleteDC(hmdc); + + for(y = 0; y < th; y++) { + for(x = 0; x < tw; x++) { + unsigned char* opx = &px[(y * tw + x) * 4]; + + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + opx[3] = 255 - bits[y * tw + x].rgbRed; + } + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + DeleteObject(hbm); + free(t); + + return 0; +} + +static int GDI_MwTextWidth(MwFLFont ttf, const char* text) { + char* t = MwUTF8ToACP(text); + SIZE sz; + + GetTextExtentPoint32(ttf->dc, t, strlen(t), &sz); + + free(t); + + return sz.cx; +} + +static int GDI_MwTextHeight(MwFLFont ttf, int count) { + TEXTMETRIC tm; + + GetTextMetrics(ttf->dc, &tm); + + return tm.tmHeight * count; +} + +static void* GDI_MwFontLoad(unsigned char* data, unsigned int size, int px) { + MwFLFont ttf = malloc(sizeof(*ttf)); + DWORD c; + MwTTFInfo info; + + if((info = MwTTFGetInfo(data, size)) == NULL) { + free(ttf); + return NULL; + } + + ttf->dc = GetDC(NULL); + + ttf->handle = NULL; + + if(_AddFontMemResourceEx) { + if((ttf->handle = _AddFontMemResourceEx(data, size, 0, &c)) == NULL) { + ReleaseDC(NULL, ttf->dc); + MwTTFFreeInfo(info); + free(ttf); + return NULL; + } + } /*else { + if((ttf->handle = _AddFontMemResourceExPolyFill(data, size, 0, &c)) == NULL) { + ReleaseDC(NULL, ttf->dc); + MwTTFFreeInfo(info); + free(ttf); + return NULL; + } + }*/ + + if((ttf->font = CreateFont(-px, 0, 0, 0, info->weight, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, ttf->handle ? info->family : "Sans Serif")) == NULL) { + if(_RemoveFontMemResourceEx) { + _RemoveFontMemResourceEx(ttf->handle); + } else { + _RemoveFontMemResourceExPolyFill(ttf->handle); + } + ReleaseDC(NULL, ttf->dc); + MwTTFFreeInfo(info); + free(ttf); + return NULL; + } + + MwTTFFreeInfo(info); + + SelectObject(ttf->dc, ttf->font); + + return ttf; +} + +static void GDI_MwFontFree(void* handle) { + MwFLFont ttf = handle; + + DeleteObject(ttf->font); + if(_RemoveFontMemResourceEx) { + _RemoveFontMemResourceEx(ttf->handle); + } else { + _RemoveFontMemResourceExPolyFill(ttf->handle); + } + ReleaseDC(NULL, ttf->dc); + free(ttf); +} + +static HANDLE WINAPI _AddFontMemResourceExPolyFill(PVOID pFileView, DWORD cjSize, PVOID pvResrved, DWORD* pNumFonts) { + CHAR temp_path_dir[MAX_PATH]; + CHAR temp_path_name[MAX_PATH]; + HANDLE tempFile = NULL; + int hr; + + (void)pvResrved; + + hr = GetTempPathA(MAX_PATH, temp_path_dir); + if(hr == 0) { + printf("GetTempPathA error %08lX\n", hr); + return hr; + } + hr = GetTempFileNameA(temp_path_dir, TEXT("MILSKO"), 0, temp_path_name); + if(hr == 0) { + printf("GetTempFileNameA error %08lX\n", hr); + return hr; + } + + printf("extracting mem font to %s\n", temp_path_name); + + tempFile = CreateFileA(temp_path_name, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + + if(tempFile == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError(); + if(err == ERROR_ALREADY_EXISTS) { + tempFile = CreateFileA(temp_path_name, + GENERIC_WRITE, + 0, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + printf("%d\n", tempFile); + if(tempFile != INVALID_HANDLE_VALUE) { + goto success; + } else { + err = GetLastError(); + } + } + printf("CreateFileA error %08lX\n", err); + return hr; + } + +success: + hr = WriteFile(tempFile, pFileView, cjSize, NULL, NULL); + if(hr != 0) { + printf("WriteFile error %08lX\n", hr); + return 0; + } + + *pNumFonts = AddFontResource(temp_path_name); + + return tempFile; +}; +static BOOL WINAPI _RemoveFontMemResourceExPolyFill(HANDLE h) { + if(h) + CloseHandle(h); + return TRUE; +}; + +int MwFL_GDISetup(void) { + void* gdilib = LoadLibrary("gdi32.dll"); + if(!gdilib) { + printf("gdi32.dll not found(?????)\n"); + } else { + _AddFontMemResourceEx = (void*)GetProcAddress(gdilib, "AddFontMemResourceEx"); + if(!_AddFontMemResourceEx) { + _AddFontMemResourceEx = _AddFontMemResourceExPolyFill; + } + _RemoveFontMemResourceEx = (void*)GetProcAddress(gdilib, "RemoveFontMemResourceEx"); + if(!_RemoveFontMemResourceEx) { + _RemoveFontMemResourceEx = _RemoveFontMemResourceExPolyFill; + } + } + + MwFLDrawText = GDI_MwDrawText; + MwFLTextWidth = GDI_MwTextWidth; + MwFLTextHeight = GDI_MwTextHeight; + MwFLFontLoad = GDI_MwFontLoad; + MwFLFontFree = GDI_MwFontFree; + return 0; +} + +#endif diff --git a/widget/milsko/milskosrc/src/text/stbtt.c b/widget/milsko/milskosrc/src/text/stbtt.c new file mode 100644 index 0000000000..bd26741455 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/stbtt.c @@ -0,0 +1,159 @@ +#ifdef USE_STB_TRUETYPE +#include + +#include "../../external/stb_truetype.h" + +struct _MwFLFont { + stbtt_fontinfo font; + void* data; + float scale; + int ascent; + int descent; +}; + +static int stbtt_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color) { + unsigned char* px; + int tw, th; + MwRect r; + MwLLPixmap p; + int ax, lsb; + int x = 0, y = 0; + + tw = MwTextWidth(handle, ttf, text); + th = MwTextHeight(handle, ttf, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + while(text[0] != 0) { + int c, c2; + int x0, y0, x1, y1, cx, cy; + int ow, oh; + unsigned char* out; + int kern; + const char* old_text; + + text += MwUTF8ToUTF32(text, &c); + + stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); + + stbtt_GetCodepointBitmapBox(&ttf->font, c, ttf->scale, ttf->scale, &x0, &y0, &x1, &y1); + ow = x1 - x0; + oh = y1 - y0; + out = malloc(ow * oh); + stbtt_MakeCodepointBitmap(&ttf->font, out, ow, oh, ow, ttf->scale, ttf->scale, c); + + for(cy = 0; cy < oh; cy++) { + for(cx = 0; cx < ow; cx++) { + int ox = x + ceil(lsb * ttf->scale) + cx; + int oy = y + ceil(ttf->ascent * ttf->scale) + y0 + cy; + unsigned char* opx = &px[(oy * tw + ox) * 4]; + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + /* overflow check */ + if(opx[3] + out[cy * ow + cx] < opx[3]) { + opx[3] = 255; + } else { + opx[3] = out[cy * ow + cx]; + } + } + } + + x += ceil(ax * ttf->scale); + + old_text = text; + text += MwUTF8ToUTF32(text, &c2); + + kern = stbtt_GetCodepointKernAdvance(&ttf->font, c, c2); + + x += ceil(kern * ttf->scale); + + text = old_text; + + free(out); + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + return 0; +} + +static int stbtt_MwTextWidth(MwFLFont ttf, const char* text) { + int ax, lsb; + int tw = 0; + int c; + int x0, y0, x1, y1; + int kern; + + while(text[0] != 0) { + int c2; + const char* old_text; + + text += MwUTF8ToUTF32(text, &c); + + stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); + + tw += ceil(ax * ttf->scale); + + old_text = text; + text += MwUTF8ToUTF32(text, &c2); + + kern = stbtt_GetCodepointKernAdvance(&ttf->font, c, c2); + + tw += ceil(kern * ttf->scale); + + text = old_text; + } + + if(tw > 0) { + tw -= ceil(kern * ttf->scale); + tw -= ceil(ax * ttf->scale); + stbtt_GetCodepointBitmapBox(&ttf->font, c, ttf->scale, ttf->scale, &x0, &y0, &x1, &y1); + tw += ceil(lsb * ttf->scale); + tw += x1 - x0; + } + + return tw + 1; +} + +static int stbtt_MwTextHeight(MwFLFont ttf, int count) { + return ceil((ttf->ascent - ttf->descent) * ttf->scale * count); +} + +static void* stbtt_MwFontLoad(unsigned char* data, unsigned int size, int px) { + MwFLFont ttf = malloc(sizeof(*ttf)); + ttf->data = malloc(size); + memcpy(ttf->data, data, size); + stbtt_InitFont(&ttf->font, ttf->data, 0); + + ttf->scale = stbtt_ScaleForMappingEmToPixels(&ttf->font, px); + stbtt_GetFontVMetrics(&ttf->font, &ttf->ascent, &ttf->descent, 0); + + return ttf; +} + +static void stbtt_MwFontFree(void* handle) { + MwFLFont ttf = handle; + + free(ttf->data); + free(ttf); +} + +int MwFL_STBTTSetup(void) { + MwFLDrawText = stbtt_MwDrawText; + MwFLTextWidth = stbtt_MwTextWidth; + MwFLTextHeight = stbtt_MwTextHeight; + MwFLFontLoad = stbtt_MwFontLoad; + MwFLFontFree = stbtt_MwFontFree; + return 0; +} + +#endif diff --git a/widget/milsko/milskosrc/src/text/text.c b/widget/milsko/milskosrc/src/text/text.c new file mode 100644 index 0000000000..9ad1e940f9 --- /dev/null +++ b/widget/milsko/milskosrc/src/text/text.c @@ -0,0 +1,318 @@ +#include + +int (*MwFLDrawText)(MwWidget handle, MwFLFont font, MwPoint* point, const char* text, MwLLColor color) = NULL; +int (*MwFLTextWidth)(MwFLFont font, const char* text) = NULL; +int (*MwFLTextHeight)(MwFLFont font, int count) = NULL; +int (*MwFLTextHeightWithText)(MwFLFont ttf, const char* text) = NULL; +void* (*MwFLFontLoad)(unsigned char* data, unsigned int size, int px) = NULL; +void (*MwFLFontFree)(void* handle) = NULL; + +#if defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE) || defined(USE_GDI_TEXT) +#define TTF +#endif + +#define FontWidth 7 +#define FontHeight 14 + +static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, MwLLColor color); + +static int count_nl(const char* text) { + int c = 1; + int i = 0; + while(text[i] != 0) { + int out; + int l = MwUTF8ToUTF32(text + i, &out); + if(l == 0) break; + i += l; + + if(out == '\n') c++; + } + + return c; +} + +static int is_bold(MwWidget handle, MwFLFont ttf) { + size_t u = (size_t)ttf; + int s; + + if(u & MwFLFlagBold) return 1; + + s = MwGetInteger(handle, MwNbold); + if(s == MwDEFAULT) return 0; + return s; +} + +#ifdef TTF +static int is_bitmap(MwWidget handle, MwFLFont ttf) { + size_t u = (size_t)ttf; + int s; + + if(u & MwFLFlagBitmap) return 1; + + s = MwGetInteger(handle, MwNbitmapFont); + if(s == MwDEFAULT) return 0; + return s; +} + +static int is_monospace(MwWidget handle, MwFLFont ttf) { + size_t u = (size_t)ttf; + int s; + + if(u & MwFLFlagMonospace) return 1; + + s = MwGetInteger(handle, MwNuseMonospace); + if(s == MwDEFAULT) return 0; + return s; +} +#endif + +#ifdef TTF + +static MwFLFont assume_ttf(MwWidget handle, MwFLFont ttf) { + if(is_bitmap(handle, ttf)) return NULL; + + if(is_monospace(handle, ttf)) return is_bold(handle, ttf) ? MwGetVoid(handle, MwNboldMonospaceFont) : MwGetVoid(handle, MwNmonospaceFont); + return is_bold(handle, ttf) ? MwGetVoid(handle, MwNboldFont) : MwGetVoid(handle, MwNfont); +} +#endif + +void MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, int align, MwLLColor color) { + MwPoint p = *point; + char* input = (char*)text; + char* last = input; + int cp; + MwLLColor fadedColor = NULL; + + if(MwGetInteger(handle, MwNdisabled) == 1) { + MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); + + if(c != NULL) { + fadedColor = MwLLAllocColor(handle->lowlevel, color->common.red, color->common.blue, color->common.green); + fadedColor->common.red = fadedColor->common.red + (c->common.red - fadedColor->common.red) * 0.5; + fadedColor->common.green = fadedColor->common.green + (c->common.green - fadedColor->common.green) * 0.5; + fadedColor->common.blue = fadedColor->common.blue + (c->common.blue - fadedColor->common.blue) * 0.5; + + MwLLFreeColor(c); + } + } + +#ifdef TTF + if(ttf <= MwFLBuildFont(0xff) && !is_bitmap(handle, ttf)) ttf = assume_ttf(handle, ttf); +#endif + + p.y -= (MwTextHeight(handle, ttf, text) - (MwTextHeight(handle, ttf, text) / count_nl(text))) / 2; + + while(*input != 0) { + input += MwUTF8ToUTF32(input, &cp); + + if(*input == 0 || cp == '\n') { + char* line = malloc(input - last + 1); + int i; + + memcpy(line, last, input - last); + + line[input - last] = 0; + + for(i = 0; line[i] != 0; i++) { + if(line[i] == '\r' || line[i] == '\n') { + line[i] = 0; + break; + } + } + + if(strlen(line) == 0) { + free(line); + + last = input; + + continue; + } + + p.x = point->x; + if(align == MwALIGNMENT_CENTER) { + p.x -= MwTextWidth(handle, ttf, line) / 2; + } else if(align == MwALIGNMENT_END) { + p.x -= MwTextWidth(handle, ttf, line); + } + +#ifdef TTF + if(MwFLDrawText) + if(is_bitmap(handle, ttf) || ttf == NULL || MwFLDrawText(handle, ttf, &p, line, fadedColor ? fadedColor : color)) +#endif + bitmap_MwDrawText(handle, &p, line, is_bold(handle, ttf), fadedColor ? fadedColor : color); + + p.y += MwTextHeight(handle, ttf, line); + + free(line); + + last = input; + } + } + + if(fadedColor) { + MwLLFreeColor(fadedColor); + } +} + +int MwTextWidth(MwWidget handle, MwFLFont ttf, const char* text) { + int len = 0; + int st; + int cp; + char* input = (char*)text; + char* last = input; +#ifndef TTF + (void)handle; + (void)ttf; +#endif + +#ifdef TTF + if(ttf <= MwFLBuildFont(0xff)) ttf = assume_ttf(handle, ttf); +#endif + + while(*input != 0) { + input += MwUTF8ToUTF32(input, &cp); + + if(*input == 0 || cp == '\n') { + char* line = malloc(input - last + 1); + int i; + + memcpy(line, last, input - last); + + line[input - last] = 0; + + for(i = 0; line[i] != 0; i++) { + if(line[i] == '\r' || line[i] == '\n') { + line[i] = 0; + break; + } + } + +#ifdef TTF + if(MwFLTextWidth && !MwGetInteger(handle, MwNbitmapFont) && ttf != NULL && (st = MwFLTextWidth(ttf, line)) != -1) { + } else +#endif + st = MwUTF8Length(line) * FontWidth; + + if(st > len) len = st; + + free(line); + + last = input; + } + } + + return len; +} + +int MwTextHeight(MwWidget handle, MwFLFont ttf, const char* text) { + int c = count_nl(text); +#ifdef TTF + int st; +#endif + +#ifdef TTF + if(ttf <= MwFLBuildFont(0xff)) ttf = assume_ttf(handle, ttf); +#else + (void)handle; + (void)text; + (void)ttf; +#endif + +#ifdef TTF + if(MwFLTextHeight) + if(!MwGetInteger(handle, MwNbitmapFont) && ttf != NULL && (st = MwFLTextHeight(ttf, c)) != -1) return st; + if(MwFLTextHeightWithText) + if(!MwGetInteger(handle, MwNbitmapFont) && ttf != NULL && (st = MwFLTextHeightWithText(ttf, text)) != -1) return st; +#endif + return FontHeight * c; +} + +void* MwFontLoad(unsigned char* data, unsigned int size) { + if(MwFLFontLoad) + return MwFLFontLoad(data, size, 14); + return NULL; +} + +void MwFontFree(void* handle) { + if(MwFLFontFree) MwFLFontFree(handle); +} + +static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, MwLLColor color) { + int i = 0, x, y, sx, sy; + int tw, th; + unsigned char* px; + MwRect r; + MwLLPixmap p; + + if(strlen(text) == 0) text = " "; + tw = MwTextWidth(handle, NULL, text); + th = MwTextHeight(handle, NULL, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + + sx = 0; + sy = 0; + + while(text[i] != 0) { + int out; + i += MwUTF8ToUTF32(text + i, &out); + + if(out > 0xff) { + out = 0; + } + + if(out == '\n') { + sx = 0; + sy += FontHeight; + } else { + for(y = 0; y < FontHeight; y++) { + for(x = 0; x < FontWidth; x++) { + unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; + if((bold ? MwBoldFontData : MwFontData)[out].data[y] & (1 << ((FontWidth - 1) - x))) { + ppx[0] = color->common.red; + ppx[1] = color->common.green; + ppx[2] = color->common.blue; + ppx[3] = 255; + } else { + ppx[0] = 0; + ppx[1] = 0; + ppx[2] = 0; + ppx[3] = 0; + } + } + } + sx += FontWidth; + } + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); +} + +typedef int (*call_t)(void); +void MwFLSetup(void) { + call_t calls[] = { +#ifdef USE_GDI_TEXT + MwFL_GDISetup, +#endif +#ifdef USE_FREETYPE2 + MwFL_FT2Setup, +#endif +#ifdef USE_STB_TRUETYPE + MwFL_STBTTSetup, +#endif + NULL}; + int i; + + for(i = 0; calls[i] != NULL; i++) { + if(calls[i]() == 0) return; + } +} diff --git a/widget/milsko/milskosrc/src/truetype.c b/widget/milsko/milskosrc/src/truetype.c new file mode 100644 index 0000000000..4f2c8196dc --- /dev/null +++ b/widget/milsko/milskosrc/src/truetype.c @@ -0,0 +1,142 @@ +#include + +#define REMAIN (size - (data - old)) + +MwTTFInfo MwTTFGetInfo(unsigned char* data, int size) { + unsigned short n = 0; + int i; + unsigned char* old = data; + MwTTFInfo info = malloc(sizeof(*info)); + + memset(info, 0, sizeof(*info)); + + if(size < 12) { + MwTTFFreeInfo(info); + return NULL; + } + n |= data[4 + 0]; + n = n << 8; + n |= data[4 + 1]; + + data += 12; + for(i = 0; REMAIN > 0 && i < n; i++) { + unsigned int offset = 0; + unsigned int length = 0; + int j; + + if(REMAIN < (4 + 4 + 4 + 4)) { + MwTTFFreeInfo(info); + return NULL; + } + + for(j = 0; j < 4; j++) { + offset = offset << 8; + offset |= data[4 + 4 + j]; + + length = length << 8; + length |= data[4 + 4 + 4 + j]; + } + + if(memcmp(data, "OS/2", 4) == 0) { + if(length >= 68) { + unsigned char* rev = data; + unsigned short us_weight = 0; + + data = old + offset; + if(REMAIN < 68) { + MwTTFFreeInfo(info); + return NULL; + } + + for(j = 0; j < 2; j++) { + us_weight = us_weight << 8; + us_weight |= data[0x4 + j]; + } + + info->weight = us_weight; + + data = rev; + } + } else if(memcmp(data, "name", 4) == 0) { + if(length >= 6) { + unsigned short count = 0; + unsigned char* rev = data; + unsigned short str_off = 0; + unsigned char* beg; + + data = old + offset; + if(REMAIN < (2 + 2 + 2)) { + MwTTFFreeInfo(info); + return NULL; + } + + beg = data; + + for(j = 0; j < 2; j++) { + count = count << 8; + count |= data[2 + j]; + + str_off = str_off << 8; + str_off |= data[2 + 2 + j]; + } + + data += 2 + 2 + 2; + for(j = 0; j < count; j++) { + unsigned short platform = 0; + unsigned short name = 0; + unsigned short nam_len = 0; + unsigned short nam_off = 0; + int k; + + if(REMAIN < (2 + 2 + 2 + 2 + 2 + 2)) { + MwTTFFreeInfo(info); + return NULL; + } + + for(k = 0; k < 2; k++) { + platform = platform << 8; + platform |= data[0 + k]; + + name = name << 8; + name |= data[2 + 2 + 2 + k]; + + nam_len = nam_len << 8; + nam_len |= data[2 + 2 + 2 + 2 + k]; + + nam_off = nam_off << 8; + nam_off |= data[2 + 2 + 2 + 2 + 2 + k]; + } + + /* FIXME: this does not work with surrogate */ + if((platform == 0 || platform == 3) && name == 1) { + data = beg + str_off + nam_off; + if(REMAIN < nam_len) { + MwTTFFreeInfo(info); + return NULL; + } + + if(info->family != NULL) free(info->family); + + info->family = malloc(nam_len / 2 + 1); + + for(k = 0; k < nam_len / 2; k++) info->family[k] = data[k * 2 + 1]; + info->family[k] = 0; + } + + data += 2 + 2 + 2 + 2 + 2 + 2; + } + + data = rev; + } + } + + data += 4 + 4 + 4 + 4; + } + + return info; +} + +void MwTTFFreeInfo(MwTTFInfo info) { + if(info->family != NULL) free(info->family); + free(info); +} diff --git a/widget/milsko/milskosrc/src/unicode.c b/widget/milsko/milskosrc/src/unicode.c new file mode 100644 index 0000000000..f6c7685482 --- /dev/null +++ b/widget/milsko/milskosrc/src/unicode.c @@ -0,0 +1,120 @@ +#include + +/* this code was taken from my old code... :) */ + +#define CAST_I32(x) ((int)(x)) + +static int utf8_count(unsigned char c) { + if(c < 0x80) { + return 1; + } + if(0xc2 <= c && c < 0xe0) { + return 2; + } + if(0xe0 <= c && c < 0xf0) { + return 3; + } + if(0xf0 <= c && c < 0xf8) { + return 4; + } + return 0; +} + +static int utf8_later(unsigned char c) { + return 0x80 <= c && c < 0xc0; +} + +int MwUTF8ToUTF32(const char* input, int* output) { + const unsigned char* inbuf = (const unsigned char*)input; + int b = utf8_count(inbuf[0]); + if(b == 0) return 0; + + if(b == 1) *output = inbuf[0]; + if(b == 2) { + if(!utf8_later(inbuf[1])) return 0; + if((inbuf[0] & 0x1e) == 0) return 0; + + *output = CAST_I32(inbuf[0] & 0x1f) << 6; + *output |= CAST_I32(inbuf[1] & 0x3f); + } + if(b == 3) { + if(!utf8_later(inbuf[1]) || !utf8_later(inbuf[2])) return 0; + if((inbuf[0] & 0x0f) == 0 && (inbuf[1] & 0x20) == 0) return 0; + + *output = CAST_I32(inbuf[0] & 0x0f) << 12; + *output |= CAST_I32(inbuf[1] & 0x3f) << 6; + *output |= CAST_I32(inbuf[2] & 0x3f); + } + if(b == 4) { + if(!utf8_later(inbuf[1]) || !utf8_later(inbuf[2]) || !utf8_later(inbuf[3])) return 0; + if((inbuf[0] & 0x07) == 0 && (inbuf[1] & 0x30) == 0) return 0; + + *output = CAST_I32(inbuf[0] & 0x07) << 18; + *output |= CAST_I32(inbuf[1] & 0x3f) << 12; + *output |= CAST_I32(inbuf[2] & 0x3f) << 6; + *output |= CAST_I32(inbuf[3] & 0x3f); + } + + return b; +} + +int MwUTF8Length(const char* input) { + int out; + int len = 0; + + while(input[0] != 0) { + int new; + + input += (new = MwUTF8ToUTF32(input, &out)); + len++; + + if(new == 0) return -1; + } + + return len; +} + +int MwUTF8Copy(const char* src, int srcskip, char* dst, int dstskip, int len) { + int i; + int out; + int total = 0; + for(i = 0; i < srcskip; i++) src += MwUTF8ToUTF32(src, &out); + for(i = 0; i < dstskip; i++) dst += MwUTF8ToUTF32(dst, &out); + for(i = 0; i < len; i++) { + int len; + if(src[0] == 0) break; + + len = MwUTF8ToUTF32(src, &out); + + memcpy(dst, src, len); + + src += len; + dst += len; + total += len; + } + dst[0] = 0; + + return total; +} + +int MwUTF32ToUTF8(int input, char* output) { + if(input < 128) { + output[0] = input; + return 1; + } else if(input < 2048) { + output[0] = 0xc0 | (input >> 6); + output[1] = 0x80 | (input & 0x3f); + return 2; + } else if(input < 65536) { + output[0] = 0xe0 | (input >> 12); + output[1] = 0x80 | ((input >> 6) & 0x3f); + output[2] = 0x80 | (input & 0x3f); + return 3; + } else { + output[0] = 0xf0 | (input >> 18); + output[1] = 0x80 | ((input >> 12) & 0x3f); + output[2] = 0x80 | ((input >> 6) & 0x3f); + output[3] = 0x80 | (input & 0x3f); + return 4; + } +} diff --git a/widget/milsko/milskosrc/src/widget/box.c b/widget/milsko/milskosrc/src/widget/box.c new file mode 100644 index 0000000000..00b5723e74 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/box.c @@ -0,0 +1,166 @@ +#include + +#include "../../external/stb_ds.h" + +static int wcreate(MwWidget handle) { + MwBox b = malloc(sizeof(*b)); + memset(b, 0, sizeof(*b)); + + handle->internal = b; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNorientation, MwHORIZONTAL); + MwSetInteger(handle, MwNmargin, 0); + MwSetInteger(handle, MwNpadding, 0); + MwSetInteger(handle, MwNhasBorder, 0); + MwSetInteger(handle, MwNinverted, 1); + MwSetInteger(handle, MwNwaitLayout, 0); + + b->layout = 0; + + return 0; +} + +static void destroy(MwWidget handle) { + MwBox b = handle->internal; + free(b); +} + +#define Margin ((i != (arrlen(handle->children) - 1)) ? MwGetInteger(handle, MwNmargin) : 0) + +static void layout(MwWidget handle) { + int i; + int sum = 0; + int horiz = MwGetInteger(handle, MwNorientation) == MwHORIZONTAL ? 1 : 0; + int sz = MwGetInteger(handle, horiz ? MwNwidth : MwNheight) - (MwGetInteger(handle, MwNpadding) + (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0)) * 2; + int fsz = MwGetInteger(handle, horiz ? MwNheight : MwNwidth) - (MwGetInteger(handle, MwNpadding) + (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0)) * 2; + int sk = MwGetInteger(handle, MwNpadding) + (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0); + + for(i = 0; i < arrlen(handle->children); i++) { + int n = MwGetInteger(handle->children[i], MwNratio); + int s = MwGetInteger(handle->children[i], MwNfixedSize); + if(n == MwDEFAULT) n = 1; + + if(handle->children[i]->destroyed) continue; + + if(s != MwDEFAULT) { + sz -= s + Margin; + } else { + sum += n; + sz -= Margin; + } + } + + for(i = 0; i < arrlen(handle->children); i++) { + int n = MwGetInteger(handle->children[i], MwNratio); + int s = MwGetInteger(handle->children[i], MwNfixedSize); + int wsz; + if(n == MwDEFAULT) n = 1; + + if(handle->children[i]->destroyed) continue; + + if(s != MwDEFAULT) { + wsz = s; + } else { + wsz = sz * n / sum; + } + + MwVaApply(handle->children[i], + horiz ? MwNx : MwNy, sk, /* this is what gets changed */ + horiz ? MwNy : MwNx, MwGetInteger(handle, MwNpadding) + (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0), /* fixed between widgets */ + horiz ? MwNwidth : MwNheight, wsz, /* this is what gets changed */ + horiz ? MwNheight : MwNwidth, fsz, /* fixed between widgets */ + NULL); + sk += wsz + Margin; + } +} + +static void draw(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + if(MwGetInteger(handle, MwNhasBorder)) { + MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted)); + } + + MwDrawRect(handle, &r, base); + + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNorientation) == 0 || strcmp(key, MwNhasBorder) == 0 || strcmp(key, MwNinverted) == 0 || strcmp(key, MwNpadding) == 0 || strcmp(key, MwNmargin) == 0) { + MwBox b = handle->internal; + b->layout = 1; + + MwForceRender(handle); + } +} + +static void tick(MwWidget handle) { + MwBox b = handle->internal; + + if(b->layout && !MwGetInteger(handle, MwNwaitLayout)) { + layout(handle); + + b->layout = 0; + } +} + +static void resize(MwWidget handle) { + MwBox b = handle->internal; + b->layout = 1; + + MwForceRender(handle); +} + +static void children_update(MwWidget handle, MwWidget child, int new_child) { + MwBox b = handle->internal; + + (void)child; + (void)new_child; + + b->layout = 1; + + MwForceRender(handle); +} + +static void children_prop_change(MwWidget handle, MwWidget child, const char* key) { + (void)child; + + if(strcmp(key, MwNratio) == 0 || strcmp(key, MwNfixedSize) == 0) { + MwBox b = handle->internal; + b->layout = 1; + + MwForceRender(handle); + } +} + +MwClassRec MwBoxClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + tick, /* tick */ + resize, /* resize */ + children_update, /* children_update */ + children_prop_change, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwBoxClass = &MwBoxClassRec; diff --git a/widget/milsko/milskosrc/src/widget/button.c b/widget/milsko/milskosrc/src/widget/button.c new file mode 100644 index 0000000000..51337e69db --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/button.c @@ -0,0 +1,115 @@ +#include + +#include "../../external/stb_ds.h" + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNflat, 0); + MwSetInteger(handle, MwNpadding, 0); + MwSetInteger(handle, MwNfillArea, 1); + + return 0; +} + +static void draw(MwWidget handle) { + MwRect r; + MwPoint point; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + const char* str = MwGetText(handle, MwNtext); + MwLLPixmap px = MwGetVoid(handle, MwNpixmap); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + int inv; + + if(str == NULL) str = ""; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + if(MwGetInteger(handle, MwNflat)) { + if(handle->pressed || ((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv)) { + MwDrawWidgetBack(handle, &r, base, handle->pressed, MwDEFAULT); + } else { + MwDrawRect(handle, &r, base); + } + } else { + MwDrawWidgetBack(handle, &r, base, handle->pressed, MwDEFAULT); + } + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + if(MwGetInteger(handle, MwNflat) && !(handle->pressed || ((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv))) { + r.x += MwDefaultBorderWidth(handle); + r.y += MwDefaultBorderWidth(handle); + r.width -= MwDefaultBorderWidth(handle) * 2; + r.height -= MwDefaultBorderWidth(handle) * 2; + } + + if(px != NULL) { + int ow = r.width; + int oh = r.height; + + if(MwGetInteger(handle, MwNfillArea)) { + double sw = (double)ow / px->common.width; + double sh = (double)oh / px->common.height; + + if(sw < sh) { + r.width = px->common.width * sw; + r.height = px->common.height * sw; + } else { + r.width = px->common.width * sh; + r.height = px->common.height * sh; + } + r.width -= MwGetInteger(handle, MwNpadding) * 2; + r.height -= MwGetInteger(handle, MwNpadding) * 2; + } else { + r.width = px->common.width; + r.height = px->common.height; + } + + r.x += (double)(ow - r.width) / 2; + r.y += (double)(oh - r.height) / 2; + + MwLLDrawPixmap(handle->lowlevel, &r, px); + } else { + point.x = r.x + r.width / 2; + point.y = r.x + r.height / 2; + + MwDrawText(handle, NULL, &point, str, MwALIGNMENT_CENTER, text); + } + + MwLLFreeColor(text); + MwLLFreeColor(base); +} + +static void click(MwWidget handle) { + MwDispatchUserHandler(handle, MwNactivateHandler, NULL); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNpixmap) == 0 || strcmp(key, MwNflat) == 0 || strcmp(key, MwNpadding) == 0 || strcmp(key, MwNfillArea) == 0) MwForceRender(handle); +} + +MwClassRec MwButtonClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + click, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + MwForceRender2, /* mouse_up */ + MwForceRender2, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwButtonClass = &MwButtonClassRec; diff --git a/widget/milsko/milskosrc/src/widget/calendar.c b/widget/milsko/milskosrc/src/widget/calendar.c new file mode 100644 index 0000000000..3fa304b98d --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/calendar.c @@ -0,0 +1,248 @@ +#include + +static unsigned int font[] = { + 0x00000000, 0x00401084, 0x0000014a, 0x00afabea, 0x01fa7cbf, 0x01111111, + 0x0126c8a2, 0x00000084, 0x00821088, 0x00221082, 0x015711d5, 0x00427c84, + 0x00220000, 0x00007c00, 0x00400000, 0x00111110, 0x00e9d72e, 0x00421084, + 0x01f2222e, 0x00e8b22e, 0x008fa54c, 0x01f87c3f, 0x00e8bc2e, 0x0042221f, + 0x00e8ba2e, 0x00e87a2e, 0x00020080, 0x00220080, 0x00820888, 0x000f83e0, + 0x00222082, 0x0042222e, 0x00ead72e, 0x011fc544, 0x00f8be2f, 0x00e8862e, + 0x00f8c62f, 0x01f0fc3f, 0x0010bc3f, 0x00e8e42e, 0x0118fe31, 0x00e2108e, + 0x00e8c210, 0x01149d31, 0x01f08421, 0x0118d771, 0x011cd671, 0x00e8c62e, + 0x0010be2f, 0x01ecc62e, 0x0114be2f, 0x00f8383e, 0x0042109f, 0x00e8c631, + 0x00454631, 0x00aad6b5, 0x01151151, 0x00421151, 0x01f1111f, 0x00e1084e, + 0x01041041, 0x00e4210e, 0x00000144, 0x01f00000, 0x00000082, 0x0164a4c0, + 0x00749c20, 0x00e085c0, 0x00e4b908, 0x0060bd26, 0x0042388c, 0x00c8724c, + 0x00a51842, 0x00420080, 0x00621004, 0x00a32842, 0x00421086, 0x015ab800, + 0x00949800, 0x0064a4c0, 0x0013a4c0, 0x008724c0, 0x00108da0, 0x0064104c, + 0x00c23880, 0x0164a520, 0x00452800, 0x00aad400, 0x00a22800, 0x00111140, + 0x00e221c0, 0x00c2088c, 0x00421084, 0x00622086, 0x000022a2}; + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNyear, 1970); + MwSetInteger(handle, MwNmonth, 0); + MwSetInteger(handle, MwNdate, 1); + MwSetInteger(handle, MwNday, 3); + MwSetInteger(handle, MwNscale, 1); + return 0; +} + +static MwLLPixmap blit(MwWidget handle, const char* str, MwLLColor bg, MwLLColor fg, int scale) { + int i; + unsigned char* buf; + MwLLPixmap px; + int w = (5 * strlen(str) + (strlen(str) - 1)) * scale; + int h = 5 * scale; + int y, x, s; + int r, g, b; + + MwColorGet(bg, &r, &g, &b); + + buf = malloc(w * h * 4); + for(i = 0; i < w * h; i++) { + buf[4 * i + 0] = r; + buf[4 * i + 1] = g; + buf[4 * i + 2] = b; + buf[4 * i + 3] = 255; + } + + MwColorGet(fg, &r, &g, &b); + + for(y = 0; y < h; y++) { + for(i = 0; str[i] != 0; i++) { + unsigned int n = font[str[i] - 0x20]; + + n = n >> (5 * (y / scale)); + + for(x = 0; x < 5; x++) { + for(s = 0; s < scale; s++) { + if(n & 1) { + unsigned char* opx = &buf[(y * w + i * (6 * scale) + x * scale + s) * 4]; + + opx[0] = r; + opx[1] = g; + opx[2] = b; + opx[3] = 255; + } + } + + n = n >> 1; + } + } + } + + px = MwLoadRaw(handle, buf, w, h); + + free(buf); + + return px; +} + +static void draw(MwWidget handle) { + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor cf = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor cb = MwParseColor(handle, "#fff"); + MwLLColor cb_g = MwParseColor(handle, "#666"); + MwLLColor ct = MwParseColor(handle, "#000"); + MwRect r, r2, r3; + MwPoint p[6]; + int h = 32 * MwGetInteger(handle, MwNscale); + int pw = h / 16; /* parallelogram width */ + int ph = pw * 3; /* parallelogram height */ + int gh = h / 32; /* gray area height */ + int sh = gh * 5 + gh * 2; /* shift height for year */ + char buf[5]; + const char* months[] = { + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC"}; + const char* days[] = { + "SUN", + "MON", + "TUE", + "WED", + "THU", + "FRI", + "SAT"}; + MwLLPixmap px; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, c); + + p[0].x = (r.width - h) / 2; + p[0].y = (r.height - h - sh) / 2; + p[1].x = p[0].x; + p[1].y = p[0].y + h + gh; + p[2].x = p[1].x + gh * 3; + p[2].y = p[1].y + gh * 3; + p[3].x = p[1].x + h + gh * 7; + p[3].y = p[2].y; + p[4].x = p[3].x; + p[4].y = p[0].y + gh * 7; + p[5].x = p[0].x + h; + p[5].y = p[0].y; + MwLLPolygon(handle->lowlevel, p, 6, cb_g); + + p[0].x = (r.width - h) / 2; + p[0].y = (r.height - h - sh) / 2; + p[1].x = p[0].x; + p[1].y = p[0].y + h + gh; + p[2].x = p[1].x + gh * 2; + p[2].y = p[1].y + gh * 2; + p[3].x = p[1].x + h + gh * 3; + p[3].y = p[2].y; + p[4].x = p[3].x; + p[4].y = p[0].y + gh * 3; + p[5].x = p[0].x + h; + p[5].y = p[0].y; + MwLLPolygon(handle->lowlevel, p, 6, ct); + + r2.width = h; + r2.height = h - ph - gh; + r2.x = (r.width - r2.width) / 2; + r2.y = (r.height - r2.height - ph - gh - sh) / 2; + MwDrawRect(handle, &r2, cb); + + r3.x = r2.x; + r3.y = r2.y + r2.height; + r3.width = r2.width; + r3.height = ph + gh; + MwDrawRect(handle, &r3, cb_g); + + r3.y += r3.height; + r3.height = gh; + MwDrawRect(handle, &r3, cb); + + p[0].x = r2.x; + p[0].y = r2.y + r2.height; + p[1].x = r2.x - pw; + p[1].y = r2.y + r2.height + ph; + p[2].x = r2.x + r2.width - pw; + p[2].y = r2.y + r2.height + ph; + p[3].x = r2.x + r2.width; + p[3].y = r2.y + r2.height; + MwLLPolygon(handle->lowlevel, p, 4, cb); + + p[0].x = r.width / 2; + p[0].y = (r.height - sh) / 2; + MwStringPrintIntoBuffer(buf, 3, "%d", MwGetInteger(handle, MwNdate)); + MwDrawText(handle, MwFLBuildFont(MwFLFlagBold), p, buf, MwALIGNMENT_CENTER, ct); + + r3 = r2; + + px = blit(handle, days[MwGetInteger(handle, MwNday)], cb, ct, gh); + r2 = r3; + r2.width = px->common.width; + r2.height = px->common.height; + r2.x = (r.width - r2.width) / 2; + r2.y = r2.y + gh * 2; + MwLLDrawPixmap(handle->lowlevel, &r2, px); + MwLLDestroyPixmap(px); + + px = blit(handle, months[MwGetInteger(handle, MwNmonth)], cb, ct, gh); + r2 = r3; + r2.width = px->common.width; + r2.height = px->common.height; + r2.x = (r.width - r2.width) / 2; + r2.y = r2.y + h - gh * 2 - r2.height; + MwLLDrawPixmap(handle->lowlevel, &r2, px); + MwLLDestroyPixmap(px); + + MwStringPrintIntoBuffer(buf, 5, "%d", MwGetInteger(handle, MwNyear)); + + px = blit(handle, buf, c, cf, gh); + r2 = r3; + r2.width = px->common.width; + r2.height = px->common.height; + r2.x = (r.width - r2.width) / 2; + r2.y = r2.y + h + gh * 6; + MwLLDrawPixmap(handle->lowlevel, &r2, px); + MwLLDestroyPixmap(px); + + MwLLFreeColor(cf); + MwLLFreeColor(ct); + MwLLFreeColor(cb_g); + MwLLFreeColor(cb); + MwLLFreeColor(c); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNmonth) == 0 || strcmp(key, MwNdate) == 0 || strcmp(key, MwNday) == 0) MwForceRender(handle); +} + +MwClassRec MwCalendarClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwCalendarClass = &MwCalendarClassRec; diff --git a/widget/milsko/milskosrc/src/widget/checkbox.c b/widget/milsko/milskosrc/src/widget/checkbox.c new file mode 100644 index 0000000000..f196954d34 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/checkbox.c @@ -0,0 +1,70 @@ +#include + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNchecked, 0); + + return 0; +} + +static void draw(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, base); + + if(r.width < r.height) { + r.height = r.width; + } else { + r.width = r.height; + } + r.x = (MwGetInteger(handle, MwNwidth) - r.width) / 2; + r.y = (MwGetInteger(handle, MwNheight) - r.height) / 2; + + MwDrawWidgetBack(handle, &r, base, (handle->pressed || MwGetInteger(handle, MwNchecked)) ? 1 : 0, MwDEFAULT); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + if(handle->pressed || MwGetInteger(handle, MwNchecked)) { + /* TODO: write check mark */ + } + + MwLLFreeColor(base); +} + +static void click(MwWidget handle) { + MwSetInteger(handle, MwNchecked, MwGetInteger(handle, MwNchecked) ? 0 : 1); + + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNchecked) == 0) MwForceRender(handle); +} + +MwClassRec MwCheckBoxClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + click, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + MwForceRender2, /* mouse_up */ + MwForceRender2, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + MwForceRender, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwCheckBoxClass = &MwCheckBoxClassRec; diff --git a/widget/milsko/milskosrc/src/widget/combobox.c b/widget/milsko/milskosrc/src/widget/combobox.c new file mode 100644 index 0000000000..e53647dde4 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/combobox.c @@ -0,0 +1,205 @@ +#include + +#include "../../external/stb_ds.h" + +static int wcreate(MwWidget handle) { + MwComboBox cb = malloc(sizeof(*cb)); + + cb->list = NULL; + cb->opened = 0; + cb->listbox = NULL; + handle->internal = cb; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNareaShown, 6); + MwSetInteger(handle, MwNvalue, 0); + + return 0; +} + +static void destroy(MwWidget handle) { + MwComboBox cb = handle->internal; + int i; + + for(i = 0; i < arrlen(cb->list); i++) { + free(cb->list[i]); + } + arrfree(cb->list); + free(handle->internal); +} + +static void draw(MwWidget handle) { + MwRect r, rc; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwComboBox cb = handle->internal; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawWidgetBack(handle, &r, base, 0, MwDEFAULT); + + rc = r; + + /* draw text */ + if(arrlen(cb->list) > MwGetInteger(handle, MwNvalue)) { + MwPoint p; + + p.x = MwDefaultBorderWidth(handle) * 2 + 4; + p.y = MwGetInteger(handle, MwNheight) / 2; + + MwDrawText(handle, NULL, &p, cb->list[MwGetInteger(handle, MwNvalue)], MwALIGNMENT_BEGINNING, text); + } + + r = rc; + r.width = r.height * 3 / 5; + r.height = r.width - MwDefaultBorderWidth(handle) * 2; + r.x = MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) - r.width - MwDefaultBorderWidth(handle) * 2; + r.y = (MwGetInteger(handle, MwNheight) - (r.height + MwDefaultBorderWidth(handle) * 2)) / 2; + MwDrawTriangle(handle, &r, base, cb->opened, MwSOUTH); + + r.y += r.height; + r.height = MwDefaultBorderWidth(handle) * 2; + MwDrawFrame(handle, &r, base, 0); + + MwLLFreeColor(text); + MwLLFreeColor(base); +} + +static void MWAPI listbox_activate(MwWidget handle, void* user, void* client) { + MwComboBox cb = handle->parent->internal; + + (void)user; + + MwSetInteger(handle->parent, MwNvalue, *(int*)client); + cb->opened = 0; + cb->listbox = NULL; + + MwForceRender(handle->parent); + + MwDispatchUserHandler(handle->parent, MwNcomboBoxChangedHandler, client); + + MwDestroyWidget(handle); +} + +static void click(MwWidget handle) { + MwComboBox cb = handle->internal; + + cb->opened = cb->opened ? 0 : 1; + if(cb->opened) { + MwPoint p; + int i; + int width = MwGetInteger(handle, MwNwidth); + int ent = MwGetInteger(handle, MwNareaShown); + + if(arrlen(cb->list) == 0) { + cb->opened = 0; + return; + } + + if(ent > arrlen(cb->list)) ent = arrlen(cb->list); + + MwLLSetCursor(handle->lowlevel, &MwCursorArrow, &MwCursorArrowMask); + + for(i = 0; i < arrlen(cb->list); i++) { + int l = MwTextWidth(handle, NULL, cb->list[i]) + MwDefaultBorderWidth(handle) * 2; + if(l > width) width = l; + } + + cb->listbox = MwVaCreateWidget(MwListBoxClass, "listbox", handle, 0, MwGetInteger(handle, MwNheight), width, MwTextHeight(handle, NULL, "M") * ent + MwDefaultBorderWidth(handle) * 2 + MwTextHeight(handle, NULL, "M") / 4, + MwNsingleClickSelectable, 1, + NULL); + + MwLLSetCursor(((MwListBox)cb->listbox->internal)->frame->lowlevel, &MwCursorArrow, &MwCursorArrowMask); + + for(i = 0; i < arrlen(cb->list); i++) { + MwListBoxSet(cb->listbox, -1, 0, cb->list[i]); + } + + MwAddUserHandler(cb->listbox, MwNlistBoxActivateHandler, listbox_activate, NULL); + + p.x = 0; + p.y = MwGetInteger(handle, MwNheight); + MwLLBeginStateChange(cb->listbox->lowlevel); + MwLLDetach(cb->listbox->lowlevel, &p); + MwLLMakeToolWindow(cb->listbox->lowlevel); + MwLLEndStateChange(cb->listbox->lowlevel); + } else { + MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); + + if(cb->listbox != NULL) { + MwDestroyWidget(cb->listbox); + cb->listbox = NULL; + } + } + + MwForceRender(handle); +} + +static void prop_change(MwWidget handle, const char* prop) { + if(strcmp(prop, MwNvalue) == 0) { + MwForceRender(handle); + } +} + +static void mwComboBoxAddImpl(MwWidget handle, int index, const char* text) { + MwComboBox cb = handle->internal; + char* t = MwStringDuplicate(text); + + if(index == -1) index = arrlen(cb->list); + + arrins(cb->list, index, t); + + if(index <= MwGetInteger(handle, MwNvalue)) MwForceRender(handle); +} + +static const char* mwComboBoxGetImpl(MwWidget handle, int index) { + MwComboBox cb = handle->internal; + + return cb->list[index]; +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwComboBoxAdd") == 0) { + int index = va_arg(va, int); + const char* text = va_arg(va, const char*); + mwComboBoxAddImpl(handle, index, text); + } + if(strcmp(name, "mwComboBoxGet") == 0) { + int index = va_arg(va, int); + *(const char**)out = mwComboBoxGetImpl(handle, index); + } +} + +static void parent_resize(MwWidget handle) { + MwComboBox cb = handle->internal; + if(cb->opened) { + click(handle); + } +} + +MwClassRec MwComboBoxClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + click, /* click */ + parent_resize, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + MwForceRender2, /* mouse_up */ + MwForceRender2, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwComboBoxClass = &MwComboBoxClassRec; diff --git a/widget/milsko/milskosrc/src/widget/entry.c b/widget/milsko/milskosrc/src/widget/entry.c new file mode 100644 index 0000000000..65cd90382e --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/entry.c @@ -0,0 +1,253 @@ +#include +#include "../../external/stb_ds.h" + +static int wcreate(MwWidget handle) { + MwEntry t = malloc(sizeof(*t)); + MwWidget topmost_parent = handle->parent; + + t->cursor = 0; + t->right = 0; + t->length = 0; + t->cursor_blink_timer = 0; + handle->internal = t; + + while(topmost_parent->parent) topmost_parent = topmost_parent->parent; + arrpush(topmost_parent->monitored_entries, handle); + + MwSetDefault(handle); + + MwLLSetCursor(handle->lowlevel, &MwCursorText, &MwCursorTextMask); + + return 0; +} + +static void destroy(MwWidget handle) { + int i; + MwWidget topmost_parent = handle->parent; + + while(topmost_parent->parent) topmost_parent = topmost_parent->parent; + for(i = 0; i < arrlen(topmost_parent->monitored_entries); i++) { + if(topmost_parent->monitored_entries[i] == handle) { + arrdel(topmost_parent->monitored_entries, i); + break; + } + } + free(handle->internal); +} +static void tick(MwWidget handle) { + MwEntry t = handle->internal; + if(t->active) { + if(++t->cursor_blink_timer >= 30) { + t->cursor_blink_timer = 0; + } + MwDispatch(handle, draw); + } +} +static void draw(MwWidget handle) { + MwRect r; + MwEntry t = handle->internal; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + const char* str = MwGetText(handle, MwNtext); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + MwFLFont font = MwFLBuildFont(MwFLFlagMonospace); + if(str == NULL) str = ""; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth) - t->right; + r.height = MwGetInteger(handle, MwNheight); + + MwDrawWidgetBack(handle, &r, base, 1, MwDEFAULT); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + if(str != NULL) { + int w = MwTextWidth(handle, font, "M"); + int h = MwTextHeight(handle, font, "M"); + MwPoint p; + char* show; + int len; + int i; + int start; + int textlen; + int attr; + MwRect currc; + + p.x = (r.width - (r.width / w * w)) / 2; + p.y = r.height / 2; + + len = (r.width - p.x * 2) / w; + + if(len > 0) { + show = malloc(len * 4 + 1); + memset(show, 0, len * 4 + 1); + + start = (t->cursor - 1) / len; + start *= len; + if((attr = MwGetInteger(handle, MwNhideInput)) == MwDEFAULT || !attr) { + MwUTF8Copy(str, start, show, 0, len); + } else { + for(i = 0; i < MwUTF8Length(str) - start; i++) show[i] = '*'; + } + + MwDrawText(handle, font, &p, show, MwALIGNMENT_BEGINNING, text); + + textlen = (t->cursor - 1) % len + 1; + for(i = 0; i < textlen; i++) show[i] = 'M'; + show[i] = 0; + + if(t->active && t->cursor_blink_timer <= 15) { + currc.x = p.x + MwTextWidth(handle, font, show); + currc.y = (r.height - h) / 2 + MwDefaultBorderWidth(handle); + currc.width = 1; + currc.height = h; + MwDrawRect(handle, &currc, text); + } + + free(show); + } + } + + MwLLFreeColor(text); + MwLLFreeColor(base); +} + +static void key(MwWidget handle, int code) { + MwEntry t = handle->internal; + const char* str = MwGetText(handle, MwNtext); + char* out; + if(str == NULL) str = ""; + + if(code == MwKEY_BACKSPACE) { + if(t->cursor == 0) return; + out = malloc(strlen(str) + 1); + + t->cursor--; + + MwUTF8Copy(str, 0, out, 0, t->cursor); + MwUTF8Copy(str, t->cursor + 1, out, t->cursor, MwUTF8Length(str) - (t->cursor + 1)); + + MwSetText(handle, MwNtext, out); + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); + + free(out); + } else if(code == MwKEY_LEFT) { + if(t->cursor == 0) return; + t->cursor--; + } else if(code == MwKEY_RIGHT) { + if(t->cursor == MwUTF8Length(str)) return; + t->cursor++; + } else if(code == MwKEY_ENTER) { + MwDispatchUserHandler(handle, MwNactivateHandler, NULL); + } else if(code == (MwKEY_CONTROL_FLAG | 'v')) { + MwLLGetClipboard(handle->lowlevel, MwCLIPBOARD_MAIN); + } else if(!(code & MwKEY_FLAG)) { + int incr = 0; + out = malloc(strlen(str) + 5 + 1); + incr += MwUTF8Copy(str, 0, out, 0, t->cursor); + MwUTF32ToUTF8(code, out + incr); + MwUTF8Copy(str, t->cursor, out, t->cursor + 1, MwUTF8Length(str) - t->cursor); + + t->cursor++; + + MwSetText(handle, MwNtext, out); + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); + + free(out); + } + + if(MwGetText(handle, MwNtext) != NULL) t->length = MwUTF8Length(MwGetText(handle, MwNtext)); + + MwForceRender(handle); +} + +#if defined(USE_X11) || defined(USE_WAYLAND) +static void mouse_up(MwWidget handle, void* ptr) { + if(handle->lowlevel->common.type == MwLLBackendWayland || handle->lowlevel->common.type == MwLLBackendX11) { + MwMouse* mouse = ptr; + if(mouse->button == MwMOUSE_MIDDLE) { + MwLLGetClipboard(handle->lowlevel, MwCLIPBOARD_PRIMARY); + } + } + MwForceRender2(handle, NULL); +} +#else +#define mouse_up MwForceRender2 +#endif + +static void mouse_down(MwWidget handle, void* ptr) { + int i = 0; + MwEntry t = handle->internal; + MwWidget topmost_parent = handle->parent; + + while(topmost_parent->parent) topmost_parent = topmost_parent->parent; + + for(i = 0; i < arrlen(topmost_parent->monitored_entries); i++) { + MwEntry t = topmost_parent->monitored_entries[i]->internal; + t->active = MwFALSE; + t->cursor_blink_timer = 0; + MwDispatch(topmost_parent->monitored_entries[i], draw); + } + t->active = MwTRUE; + MwForceRender2(handle, NULL); +} + +static void prop_change(MwWidget handle, const char* prop) { + if(strcmp(prop, MwNtext) == 0 || strcmp(prop, MwNhideInput) == 0) MwForceRender(handle); + + if(strcmp(prop, MwNtext) == 0) { + MwEntry t = handle->internal; + int len = MwUTF8Length(MwGetText(handle, MwNtext)); + if(len < t->cursor) { + t->cursor = len; + } else if(t->length == t->cursor) { + t->cursor = len; + } + t->length = len; + } +} + +static void clipboard(MwWidget handle, const char* data) { + MwEntry t = handle->internal; + const char* str = MwGetText(handle, MwNtext); + char* out; + if(!str) { + str = ""; + } + out = malloc(strlen(str) + strlen(data) + 1); + + if(str == NULL) str = ""; + + MwUTF8Copy(str, 0, out, 0, t->cursor); + MwUTF8Copy(data, 0, out, t->cursor, MwUTF8Length(data)); + MwUTF8Copy(str, t->cursor, out, t->cursor + MwUTF8Length(data), MwUTF8Length(str) - t->cursor); + + t->cursor += MwUTF8Length(data); + + MwSetText(handle, MwNtext, out); + free(out); + + MwForceRender(handle); +} + +MwClassRec MwEntryClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + mouse_up, /* mouse_up */ + mouse_down, /* mouse_down */ + key, /* key */ + NULL, /* execute */ + tick, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + clipboard, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwEntryClass = &MwEntryClassRec; diff --git a/widget/milsko/milskosrc/src/widget/frame.c b/widget/milsko/milskosrc/src/widget/frame.c new file mode 100644 index 0000000000..f2af108026 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/frame.c @@ -0,0 +1,69 @@ +#include + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNhasBorder, 0); + MwSetInteger(handle, MwNinverted, 1); + + return 0; +} + +static void draw(MwWidget handle) { + MwRect fr; + MwRect rr; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + int inverted; + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + + if(MwGetInteger(handle, MwNhasBorder)) { + inverted = MwGetInteger(handle, MwNinverted); + fr.x = 0; + fr.y = 0; + fr.width = MwGetInteger(handle, MwNwidth); + fr.height = MwGetInteger(handle, MwNheight); + MwDrawFrame(handle, &fr, base, inverted); + + rr.x = MwDefaultBorderWidth(handle); + rr.y = MwDefaultBorderWidth(handle); + rr.width = MwGetInteger(handle, MwNwidth) - (MwDefaultBorderWidth(handle) * 2); + rr.height = MwGetInteger(handle, MwNheight) - (MwDefaultBorderWidth(handle) * 2); + } else { + rr.x = 0; + rr.y = 0; + rr.width = MwGetInteger(handle, MwNwidth); + rr.height = MwGetInteger(handle, MwNheight); + } + + MwDrawRect(handle, &rr, base); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &rr, bgpx); + + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNhasBorder) == 0 || strcmp(key, MwNinverted) == 0) MwForceRender(handle); +} + +MwClassRec MwFrameClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwFrameClass = &MwFrameClassRec; diff --git a/widget/milsko/milskosrc/src/widget/image.c b/widget/milsko/milskosrc/src/widget/image.c new file mode 100644 index 0000000000..c8e0680021 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/image.c @@ -0,0 +1,65 @@ +#include + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNhasBorder, 0); + MwSetInteger(handle, MwNinverted, 1); + MwSetInteger(handle, MwNfillArea, 1); + + return 0; +} + +static void draw(MwWidget handle) { + MwRect r; + MwLLPixmap px = MwGetVoid(handle, MwNpixmap); + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted)); + + MwDrawRect(handle, &r, base); + if(px != NULL) { + if(!MwGetInteger(handle, MwNfillArea)) { + r.x = (r.width - px->common.width) / 2; + r.y = (r.height - px->common.height) / 2; + r.width = px->common.width; + r.height = px->common.height; + } + + MwLLDrawPixmap(handle->lowlevel, &r, px); + } + + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNpixmap) == 0 || strcmp(key, MwNhasBorder) == 0 || strcmp(key, MwNinverted) == 0) MwForceRender(handle); +} + +MwClassRec MwImageClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwImageClass = &MwImageClassRec; diff --git a/widget/milsko/milskosrc/src/widget/label.c b/widget/milsko/milskosrc/src/widget/label.c new file mode 100644 index 0000000000..a0be9ca586 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/label.c @@ -0,0 +1,425 @@ +#include + +#include "../../external/stb_ds.h" + +#define Spacing 1 + +static int wcreate(MwWidget handle) { + MwLabel lab = malloc(sizeof(*lab)); + memset(lab, 0, sizeof(*lab)); + + handle->internal = lab; + + MwSetDefault(handle); + MwSetInteger(handle, MwNalignment, MwALIGNMENT_CENTER); + MwSetInteger(handle, MwNbold, 0); + MwSetInteger(handle, MwNsevenSegment, 0); + MwSetInteger(handle, MwNlength, 4); + MwSetInteger(handle, MwNleftPadding, 0); + + return 0; +} + +static void destroy(MwWidget handle) { + MwLabel lab = handle->internal; + + hmfree(lab->segment); + + free(handle->internal); +} + +static void draw_v(MwWidget handle, unsigned char* raw, int x, int y, int stride, MwLLColor text) { + int cy, cx, b; + + int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); + int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; + + for(cy = y; cy < y + l_one; cy++) { + for(cx = x; cx < x + s_one; cx++) { + unsigned char* px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = y - (s_one - 1) / 2; + for(cy = b; cy < b + (s_one - 1) / 2; cy++) { + int w = (cy - b) * 2 + 1; + int b2 = x + (s_one - w) / 2; + for(cx = b2; cx < b2 + w; cx++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = y + l_one; + for(cy = b; cy < b + (s_one - 1) / 2; cy++) { + int w = ((s_one - 1) / 2 - 1 - (cy - b)) * 2 + 1; + int b2 = x + (s_one - w) / 2; + for(cx = b2; cx < b2 + w; cx++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } +} + +static void draw_h(MwWidget handle, unsigned char* raw, int x, int y, int stride, MwLLColor text) { + int cy, cx, b; + + int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); + int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; + + for(cx = x; cx < x + l_one; cx++) { + for(cy = y; cy < y + s_one; cy++) { + unsigned char* px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = x - (s_one - 1) / 2; + for(cx = b; cx < b + (s_one - 1) / 2; cx++) { + int w = (cx - b) * 2 + 1; + int b2 = y + (s_one - w) / 2; + for(cy = b2; cy < b2 + w; cy++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = x + l_one; + for(cx = b; cx < b + (s_one - 1) / 2; cx++) { + int w = ((s_one - 1) / 2 - 1 - (cx - b)) * 2 + 1; + int b2 = y + (s_one - w) / 2; + for(cy = b2; cy < b2 + w; cy++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } +} + +static void draw_seven_segment(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor shadow = MwLightenColor(handle, base, MwDefaultShadow, MwDefaultShadow, MwDefaultShadow); + int align; + const char* str = MwGetText(handle, MwNtext); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + MwLabel lab = handle->internal; + int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); + int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; + MwLLPixmap px; + unsigned char* raw; + int w = 0, h = s_one * 3 + l_one * 2, i; + int x = 0; + + if(str == NULL) str = ""; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawRect(handle, &r, base); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + + align = MwGetInteger(handle, MwNalignment); + + /* so - this mode cannot do unicode. + * but you wouldn't show unicode on 7 segment anyways + */ + + /* L + * S <---> + * + * S + * ^ + * | + * L | + * | + * v + */ + + for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { + if(i > 0 && ((hmgeti(lab->segment, i) != -1) || str[i] != '.')) w += Spacing; + if(hmgeti(lab->segment, i) != -1 || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { + w += l_one + s_one * 2; + } else if(str[i] == ':' || str[i] == ' ') { + w += s_one; + } + } + + w++; + h++; + + raw = malloc(w * h * 4); + memset(raw, 0, w * h * 4); + + for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { + if((hmgeti(lab->segment, i) != -1) || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { + int la = 0, lb = 0, lc = 0, ld = 0, le = 0, lf = 0, lg = 0; + int j; + + /* https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg */ + + if(hmgeti(lab->segment, i) != -1) { + unsigned char c = hmget(lab->segment, i); + + if(c & (1 << 0)) la = 1; + if(c & (1 << 1)) lb = 1; + if(c & (1 << 2)) lc = 1; + if(c & (1 << 3)) ld = 1; + if(c & (1 << 4)) le = 1; + if(c & (1 << 5)) lf = 1; + if(c & (1 << 6)) lg = 1; + } else { + if(str[i] == '0') { + la = lb = lc = ld = le = lf = 1; + } else if(str[i] == '1') { + lb = lc = 1; + } else if(str[i] == '2') { + la = lb = ld = le = lg = 1; + } else if(str[i] == '3') { + la = lb = lc = ld = lg = 1; + } else if(str[i] == '4') { + lb = lc = lf = lg = 1; + } else if(str[i] == '5') { + la = lc = ld = lf = lg = 1; + } else if(str[i] == '6') { + la = lc = ld = le = lf = lg = 1; + } else if(str[i] == '7') { + la = lb = lc = 1; + } else if(str[i] == '8') { + la = lb = lc = ld = le = lf = lg = 1; + } else if(str[i] == '9') { + la = lb = lc = ld = lf = lg = 1; + } else if(str[i] == 'A' || str[i] == 'a') { + la = lb = lc = le = lf = lg = 1; + } else if(str[i] == 'B' || str[i] == 'b') { + lc = ld = le = lf = lg = 1; + } else if(str[i] == 'C' || str[i] == 'c') { + ld = le = lg = 1; + } else if(str[i] == 'D' || str[i] == 'd') { + lb = lc = ld = le = lg = 1; + } else if(str[i] == 'E' || str[i] == 'e') { + la = ld = le = lf = lg = 1; + } else if(str[i] == 'F' || str[i] == 'f') { + la = le = lf = lg = 1; + } + } + + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; + + if(la) draw_h(handle, raw, x + s_one + j, j, w, cl); + if(lb) draw_v(handle, raw, x + s_one + l_one + j, s_one + j, w, cl); + if(lc) draw_v(handle, raw, x + s_one + l_one + j, s_one * 2 + l_one + j, w, cl); + if(ld) draw_h(handle, raw, x + s_one + j, s_one * 2 + l_one * 2 + j, w, cl); + if(le) draw_v(handle, raw, x + j, s_one * 2 + l_one + j, w, cl); + if(lf) draw_v(handle, raw, x + j, s_one + j, w, cl); + if(lg) draw_h(handle, raw, x + s_one + j, s_one + l_one + j, w, cl); + } + + x += l_one + s_one * 2; + } else if(str[i] == ':') { + int cy, cx; + int j; + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; + for(cy = 1; cy < h - 1; cy++) { + int h = s_one / 2; + int c = (l_one - h) / 2 + s_one; + + int c1 = (c <= cy && cy <= (c + h)) ? 1 : 0; + int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + h)) ? 1 : 0; + + if(c1 || c2) { + for(cx = x; cx < x + s_one; cx++) { + unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; + px[0] = cl->common.red; + px[1] = cl->common.green; + px[2] = cl->common.blue; + px[3] = 255; + } + } + } + } + x += s_one; + } else if(str[i] == ' ') { + x += s_one; + } else if(str[i] == '.') { + int cy, cx; + int j; + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; + for(cy = h - (s_one - 1) / 2 - 1; cy < h; cy++) { + for(cx = x - Spacing - (s_one - 1) / 2 - 1; cx < (x - Spacing); cx++) { + unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; + px[0] = cl->common.red; + px[1] = cl->common.green; + px[2] = cl->common.blue; + px[3] = 255; + } + } + } + continue; + } + + x += Spacing; + } + + px = MwLoadRaw(handle, raw, w, h); + + r.y = (r.height - h) / 2; + r.height = h; + if(align == MwALIGNMENT_CENTER) { + r.x = (r.width - w) / 2; + } else if(align == MwALIGNMENT_BEGINNING) { + r.x = 0; + } else if(align == MwALIGNMENT_END) { + r.x = r.width - w; + } + r.width = w; + MwLLDrawPixmap(handle->lowlevel, &r, px); + + free(raw); + + MwLLDestroyPixmap(px); +} + +static void draw_normal(MwWidget handle) { + MwRect r; + MwPoint p; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor shadow = MwLightenColor(handle, base, MwDefaultShadow, MwDefaultShadow, MwDefaultShadow); + int align; + const char* str = MwGetText(handle, MwNtext); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + + if(str == NULL) str = ""; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawRect(handle, &r, base); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + + align = MwGetInteger(handle, MwNalignment); + + r.width -= MwGetInteger(handle, MwNleftPadding); + +#if 1 + if(align == MwALIGNMENT_CENTER) { + p.x = r.width / 2; + } else if(align == MwALIGNMENT_BEGINNING) { + p.x = MwTextWidth(handle, NULL, str) / 2; + } else if(align == MwALIGNMENT_END) { + p.x = r.width - MwTextWidth(handle, NULL, str) / 2; + } +#else + p.x = 0; +#endif + p.y = r.height / 2; + + p.x += MwGetInteger(handle, MwNleftPadding); + + p.x += 1; + p.y += 1; + MwDrawText(handle, NULL, &p, str, MwALIGNMENT_CENTER, shadow); + + p.x -= 1; + p.y -= 1; + MwDrawText(handle, NULL, &p, str, MwALIGNMENT_CENTER, text); + + MwLLFreeColor(shadow); + MwLLFreeColor(text); + MwLLFreeColor(base); +} + +static void draw(MwWidget handle) { + MwLabel lab = handle->internal; + if(!lab->draw) { + lab->draw = draw_normal; + } + lab->draw(handle); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0 || strcmp(key, MwNsevenSegment) == 0 || strcmp(key, MwNlength) == 0 || strcmp(key, MwNleftPadding) == 0) MwForceRender(handle); + + if(strcmp(key, MwNsevenSegment) == 0) { + MwLabel lab = handle->internal; + if(MwGetInteger(handle, MwNsevenSegment)) + lab->draw = draw_seven_segment; + else + lab->draw = draw_normal; + } +} + +static void mwLabelSetSevenSegmentImpl(MwWidget handle, int index, unsigned char data) { + MwLabel lab = handle->internal; + + hmput(lab->segment, index, data); +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + (void)out; + + if(strcmp(name, "mwLabelSetSevenSegment") == 0) { + int index = va_arg(va, int); + int data = va_arg(va, int); + + mwLabelSetSevenSegmentImpl(handle, index, data); + } +} + +MwClassRec MwLabelClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwLabelClass = &MwLabelClassRec; diff --git a/widget/milsko/milskosrc/src/widget/listbox.c b/widget/milsko/milskosrc/src/widget/listbox.c new file mode 100644 index 0000000000..32be8875bd --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/listbox.c @@ -0,0 +1,625 @@ +#include + +#include "../../external/stb_ds.h" + +#define Padding 2 + +#define Font MwFLBuildFont(MwFLFlagMonospace) + +static int get_first_entry(MwWidget handle, MwListBox lb) { + int st = 0; + int y = MwGetInteger(handle, MwNhasHeading) ? 1 : 0; + + st = MwGetInteger(lb->vscroll, MwNvalue); + st = st * (MwGetInteger(lb->vscroll, MwNmaxValue) - MwGetInteger(lb->vscroll, MwNareaShown)) / MwGetInteger(lb->vscroll, MwNmaxValue); + if(st < y) st = y; + + return st; +} + +static int get_col_width(MwListBox lb, int ind) { + int total = MwGetInteger(lb->frame, MwNwidth); + int wid, i; + if(arrlen(lb->width) <= ind) { + wid = 0; + } else { + wid = lb->width[ind]; + } + if(wid > 0) return wid; + + if(wid == 0) { + for(i = 0; i < arrlen(lb->width) && i < ind; i++) { + int w = lb->width[i]; + if(w < 0) { + total -= total + w; + } else if(wid > 0) { + total -= w; + } + } + return total; + } + + if(wid < 0) { + for(i = 0; i < arrlen(lb->width) && i < ind; i++) { + int w = lb->width[i]; + if(w < 0) { + total -= total + w; + } else if(wid > 0) { + total -= w; + } + } + return total + wid; + } + + return 0; +} + +static void MWAPI vscroll_changed(MwWidget handle, void* user, void* call) { + MwListBox lb = handle->parent->internal; + + (void)user; + (void)call; + + lb->changed = 1; +} + +static void MWAPI frame_mouse_down(MwWidget handle, void* user, void* call) { + MwListBox lb = handle->parent->internal; + MwMouse* m = call; + + (void)user; + + if(m->button == MwMOUSE_LEFT) { + int st = 0; + int i; + int y = MwDefaultBorderWidth(handle); + int h = MwGetInteger(handle, MwNheight); + + st = get_first_entry(handle->parent, lb); + for(i = 0; (st + i) < arrlen(lb->list) && i < (h - MwDefaultBorderWidth(handle) * 2) / (MwTextHeight(handle, Font, "M") + Padding) + 2; i++) { + if(y <= m->point.y && m->point.y <= (y + MwTextHeight(handle, Font, "M") + Padding)) { + unsigned long t; + int old = MwGetInteger(handle->parent, MwNvalue); + + MwSetInteger(handle->parent, MwNvalue, st + i); + + if((((t = MwTimeGetTick()) - lb->click_time) < MwDoubleClickTimeout && old == st + i) || MwGetInteger(handle->parent, MwNsingleClickSelectable)) { + int n = MwGetInteger(handle->parent, MwNvalue); + MwDispatchUserHandler(handle->parent, MwNlistBoxActivateHandler, &n); + } + + lb->click_time = t; + } + y += MwTextHeight(handle, Font, "M") + Padding; + } + + MwForceRender(lb->frame); + lb->pressed = 1; + } +} + +static void MWAPI frame_mouse_up(MwWidget handle, void* user, void* call) { + MwListBox lb = handle->parent->internal; + MwMouse* m = call; + + (void)user; + + if(m->button == MwMOUSE_LEFT) { + lb->pressed = 0; + } +} + +static void MWAPI frame_mouse_move(MwWidget handle, void* user, void* call) { + MwListBox lb = handle->parent->internal; + MwPoint* p = call; + + (void)user; + + if(lb->pressed) { + int st = 0; + int i; + int y = MwDefaultBorderWidth(handle); + int h = MwGetInteger(handle, MwNheight); + + st = get_first_entry(handle->parent, lb); + for(i = 0; (st + i) < arrlen(lb->list) && i < (h - MwDefaultBorderWidth(handle) * 2) / (MwTextHeight(handle, Font, "M") + Padding) + 2; i++) { + if(y <= p->y && p->y <= (y + MwTextHeight(handle, Font, "M") + Padding)) { + MwSetInteger(handle->parent, MwNvalue, st + i); + } + y += MwTextHeight(handle, Font, "M") + Padding; + } + + MwForceRender(lb->frame); + } +} + +static void frame_draw(MwWidget handle) { + MwRect r, r2; + MwListBox lb = handle->parent->internal; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor base2 = MwParseColor(handle, MwGetText(handle, MwNsubBackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor text2 = MwParseColor(handle, MwGetText(handle, MwNsubForeground)); + int i; + MwPoint p; + int st = 0; + int ent; + int area; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + r2 = r; + + p.x = MwDefaultBorderWidth(handle); + p.y = MwDefaultBorderWidth(handle); + + MwDrawFrame(handle, &r, base, 1); + MwDrawRect(handle, &r, base2); + + r = r2; + + st = get_first_entry(handle->parent, lb); + + area = r.height - MwDefaultBorderWidth(handle) * 2; + ent = area / (MwTextHeight(handle, Font, "M") + Padding) + 2; + + for(i = st; i < arrlen(lb->list) && i < st + ent; i++) { + int selected = MwGetInteger(handle->parent, MwNvalue) == i ? 1 : 0; + int j; + + if(selected) { + MwRect r2; + r2.x = MwDefaultBorderWidth(handle) + MwGetInteger(handle->parent, MwNleftPadding); + r2.y = p.y; + r2.width = r.width - r2.x; + r2.height = MwTextHeight(handle, Font, "M") + Padding; + MwDrawRect(handle, &r2, text2); + handle->bgcolor = text2; + } + if(lb->list[i].pixmap != NULL) { + MwRect r2; + int h = (lb->list[i].pixmap->common.height > (MwTextHeight(handle, Font, "M") + Padding)) ? (MwTextHeight(handle, Font, "M") + Padding) : lb->list[i].pixmap->common.height; + r2.x = MwDefaultBorderWidth(handle); + r2.y = p.y + (MwTextHeight(handle, Font, "M") + Padding - h) / 2; + r2.width = h * lb->list[i].pixmap->common.width / lb->list[i].pixmap->common.height; + r2.height = h; + MwLLDrawPixmap(handle->lowlevel, &r2, lb->list[i].pixmap); + } + p.x = MwDefaultBorderWidth(handle) + MwGetInteger(handle->parent, MwNleftPadding); + for(j = 0; j < arrlen(lb->list[i].name); j++) { + char* t = lb->list[i].name[j]; + char* str; + int l = (j == 0 ? MwGetInteger(handle->parent, MwNleftPadding) : 0); + MwPoint p2 = p; + p2.y += (MwTextHeight(handle, Font, "M") + Padding) / 2; + + if(t == NULL) t = ""; + + str = MwStringDuplicate(t); + if(MwUTF8Length(str) > (get_col_width(lb, j) - l) / MwTextWidth(handle, Font, "M")) { + int ind = (get_col_width(lb, j) - l) / MwTextWidth(handle, Font, "M") - 3; + int seek = 0; + int l = 0; + char* old = str; + + if(ind < 0) ind = 0; + + str = malloc(strlen(old) + 5); + strcpy(str, old); + free(old); + + while(str[seek] != 0) { + int cp; + if(l == ind) break; + + seek += MwUTF8ToUTF32(str + seek, &cp); + + l++; + } + + memset(str + seek, '.', 3); + str[seek + 3] = 0; + } + + if(j == (arrlen(lb->list[i].name) - 1)) p.x -= MwDefaultBorderWidth(handle); + if(arrlen(lb->alignment) <= j || lb->alignment[j] == MwALIGNMENT_BEGINNING) { + p.x += 4; + p2.x = p.x; + MwDrawText(handle, Font, &p2, str, MwALIGNMENT_BEGINNING, selected ? base2 : text2); + p.x -= 4; + p.x += get_col_width(lb, j); + + } else if(lb->alignment[j] == MwALIGNMENT_CENTER) { + p.x += (get_col_width(lb, j) - l) / 2; + p2.x = p.x; + MwDrawText(handle, Font, &p2, str, MwALIGNMENT_CENTER, selected ? base2 : text2); + p.x += (get_col_width(lb, j) - l) / 2; + p.x += l; + } else if(lb->alignment[j] == MwALIGNMENT_END) { + p.x += get_col_width(lb, j); + p.x -= 4; + p2.x = p.x; + MwDrawText(handle, Font, &p2, str, MwALIGNMENT_END, selected ? base2 : text2); + p.x += 4; + } + free(str); + + if(j == 0) p.x -= MwGetInteger(handle->parent, MwNleftPadding); + } + p.y += MwTextHeight(handle, Font, "M") + Padding; + handle->bgcolor = NULL; + } + + MwDrawFrame(handle, &r, base, 1); + + MwLLFreeColor(text2); + MwLLFreeColor(text); + MwLLFreeColor(base2); + MwLLFreeColor(base); +} + +static void resize(MwWidget handle, int no_resize) { + MwListBox lb = handle->internal; + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + int ih, y; + int m = 0; + + y = MwGetInteger(handle, MwNhasHeading) ? (MwTextHeight(handle, Font, "M") + MwDefaultBorderWidth(handle) * 2) : 0; + + if(lb->vscroll == NULL) { + lb->vscroll = MwVaCreateWidget(MwScrollBarClass, "vscroll", handle, w - 16, 0, 16, h, NULL); + MwAddUserHandler(lb->vscroll, MwNchangedHandler, vscroll_changed, NULL); + } else if(!no_resize) { + MwVaApply(lb->vscroll, + MwNx, w - 16, + MwNy, 0, + MwNwidth, 16, + MwNheight, h, + NULL); + } + + ih = arrlen(lb->list); + if(ih == 0) ih = 1; + + h -= y; + + if(ih <= (h / (MwTextHeight(handle, Font, "M") + Padding))) { + MwLLShow(lb->vscroll->lowlevel, 0); + } else { + MwLLShow(lb->vscroll->lowlevel, 1); + m = 16; + } + + if(lb->frame == NULL) { + lb->frame = MwVaCreateWidget(MwFrameClass, "frame", handle, 0, y, w - m, h, NULL); + lb->frame->draw_inject = frame_draw; + MwAddUserHandler(lb->frame, MwNmouseDownHandler, frame_mouse_down, NULL); + MwAddUserHandler(lb->frame, MwNmouseUpHandler, frame_mouse_up, NULL); + MwAddUserHandler(lb->frame, MwNmouseMoveHandler, frame_mouse_move, NULL); + } else if(!no_resize || MwGetInteger(lb->frame, MwNwidth) != (w - m)) { + MwVaApply(lb->frame, + MwNx, 0, + MwNy, y, + MwNwidth, w - m, + MwNheight, h, + NULL); + } + h -= MwDefaultBorderWidth(handle) * 2; + + MwVaApply(lb->vscroll, + MwNareaShown, h / (MwTextHeight(handle, Font, "M") + Padding), + MwNmaxValue, ih, + NULL); +} + +static int wcreate(MwWidget handle) { + MwListBox lb = malloc(sizeof(*lb)); + memset(lb, 0, sizeof(*lb)); + + handle->internal = lb; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNsingleClickSelectable, 0); + MwSetInteger(handle, MwNhasHeading, 0); + MwSetInteger(handle, MwNleftPadding, 0); + MwSetInteger(handle, MwNvalue, -1); + + resize(handle, 0); + lb->list = NULL; + lb->click_time = 0; + lb->width = NULL; + lb->alignment = NULL; + lb->changed = 0; + + return 0; +} + +static void destroy(MwWidget handle) { + MwListBox lb = handle->internal; + MwListBoxReset(handle); + arrfree(lb->list); + arrfree(lb->width); + arrfree(lb->alignment); + free(handle->internal); +} + +static void draw(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwListBox lb = handle->internal; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawRect(handle, &r, base); + if(MwGetInteger(handle, MwNhasHeading) && arrlen(lb->list) > 0) { + MwPoint p; + int i; + int x = 0; + + r.width -= 16; + + for(i = 0; i < arrlen(lb->list[0].name); i++) { + r.x = x; + r.y = 0; + r.width = get_col_width(lb, i); + r.height = MwDefaultBorderWidth(handle) * 2 + MwTextHeight(handle, Font, "M"); + MwDrawFrame(handle, &r, base, 0); + + x += MwDefaultBorderWidth(handle); + + if(arrlen(lb->alignment) <= i || lb->alignment[i] == MwALIGNMENT_BEGINNING) { + p.x = 4 + x; + p.y = r.y + r.height / 2; + MwDrawText(handle, NULL, &p, lb->list[0].name[i], MwALIGNMENT_BEGINNING, text); + } else if(lb->alignment[i] == MwALIGNMENT_CENTER) { + p.x = x + r.width / 2; + p.y = r.y + r.height / 2; + MwDrawText(handle, NULL, &p, lb->list[0].name[i], MwALIGNMENT_CENTER, text); + } else if(lb->alignment[i] == MwALIGNMENT_END) { + p.x = x + r.width - 4; + p.y = r.y + r.height / 2; + MwDrawText(handle, NULL, &p, lb->list[0].name[i], MwALIGNMENT_END, text); + } + + x += r.width; + + x += MwDefaultBorderWidth(handle); + } + } + + MwLLFreeColor(text); + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* prop) { + MwListBox lb = handle->internal; + if(strcmp(prop, MwNleftPadding) == 0) { + MwForceRender(lb->frame); + } + if(strcmp(prop, MwNhasHeading) == 0) { + MwForceRender(handle); + } +} + +static void redrawIfNeeded(MwWidget handle, int row) { + MwListBox lb = handle->internal; + + if(MwGetInteger(lb->vscroll, MwNvalue) <= row && row <= (MwGetInteger(lb->vscroll, MwNvalue) + MwGetInteger(lb->vscroll, MwNareaShown))) { + MwForceRender(lb->frame); + } +} + +static int mwListBoxSetImpl(MwWidget handle, int row, int col, const char* text) { + MwListBox lb = handle->internal; + MwListBoxEntry entry; + char* t = text == NULL ? NULL : MwStringDuplicate(text); + int new = 0; + if(row == -1) row = arrlen(lb->list); + + entry.name = NULL; + entry.pixmap = NULL; + if(row < arrlen(lb->list)) { + entry = lb->list[row]; + } + + if(col == -1) col = arrlen(entry.name); + arrins(entry.name, col, t); + + if(row < arrlen(lb->list)) { + lb->list[row] = entry; + } else { + arrins(lb->list, row, entry); + new = 1; + } + + if(new) resize(handle, 1); + redrawIfNeeded(handle, row); + + return row; +} + +static void mwListBoxSetIconImpl(MwWidget handle, int index, MwLLPixmap icon) { + MwListBox lb = handle->internal; + MwListBoxEntry entry; + int new = 0; + if(index == -1) index = arrlen(lb->list); + + entry.name = NULL; + entry.pixmap = NULL; + if(index < arrlen(lb->list)) { + entry = lb->list[index]; + } + + entry.pixmap = icon; + + if(index < arrlen(lb->list)) { + lb->list[index] = entry; + } else { + arrins(lb->list, index, entry); + new = 1; + } + + if(new) resize(handle, 1); + redrawIfNeeded(handle, index); +} + +static void mwListBoxDeleteImpl(MwWidget handle, int index) { + MwListBox lb = handle->internal; + int i; + + if(index == -1) index = arrlen(lb->list) - 1; + for(i = 0; i < arrlen(lb->list[index].name); i++) { + free(lb->list[index].name[i]); + } + arrfree(lb->list[index].name); + arrdel(lb->list, index); + + if(MwGetInteger(handle, MwNvalue) >= arrlen(lb->list)) { + MwSetInteger(handle, MwNvalue, arrlen(lb->list) - 1); + } + if(MwGetInteger(handle, MwNvalue) < (MwGetInteger(handle, MwNhasHeading) ? 1 : 0)) { + MwSetInteger(handle, MwNvalue, -1); + } + + resize(handle, 1); + if(index < (MwGetInteger(lb->vscroll, MwNvalue) + MwGetInteger(lb->vscroll, MwNareaShown))) { + MwForceRender(lb->frame); + } +} + +static void mwListBoxResetImpl(MwWidget handle) { + MwListBox lb = handle->internal; + int i; + + while(arrlen(lb->list) > 0) { + for(i = 0; i < arrlen(lb->list[0].name); i++) { + if(lb->list[0].name[i] != NULL) free(lb->list[0].name[i]); + } + arrfree(lb->list[0].name); + arrdel(lb->list, 0); + } + + MwSetInteger(handle, MwNvalue, -1); + + MwSetInteger(lb->vscroll, MwNvalue, 0); + + resize(handle, 0); + MwForceRender(lb->frame); +} + +static const char* mwListBoxGetImpl(MwWidget handle, int index) { + MwListBox lb = handle->internal; + + if(index < 0) return NULL; + if(index >= arrlen(lb->list)) return NULL; + + return lb->list[index].name[0]; +} + +static void mwListBoxSetWidthImpl(MwWidget handle, int index, int width) { + MwListBox lb = handle->internal; + + while(((index + 1) - arrlen(lb->width)) > 0) arrput(lb->width, 0); + + lb->width[index] = width; + + MwForceRender(handle); + MwForceRender(lb->frame); +} + +static void mwListBoxSetAlignmentImpl(MwWidget handle, int index, int alignment) { + MwListBox lb = handle->internal; + + while(((index + 1) - arrlen(lb->alignment)) > 0) arrput(lb->alignment, MwALIGNMENT_BEGINNING); + + lb->alignment[index] = alignment; + + MwForceRender(handle); + MwForceRender(lb->frame); +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwListBoxDelete") == 0) { + int index = va_arg(va, int); + mwListBoxDeleteImpl(handle, index); + } + if(strcmp(name, "mwListBoxReset") == 0) { + mwListBoxResetImpl(handle); + } + if(strcmp(name, "mwListBoxGet") == 0) { + int index = va_arg(va, int); + *(const char**)out = mwListBoxGetImpl(handle, index); + } + if(strcmp(name, "mwListBoxSetWidth") == 0) { + int index = va_arg(va, int); + int width = va_arg(va, int); + mwListBoxSetWidthImpl(handle, index, width); + } + if(strcmp(name, "mwListBoxSetAlignment") == 0) { + int index = va_arg(va, int); + int alignment = va_arg(va, int); + mwListBoxSetAlignmentImpl(handle, index, alignment); + } + if(strcmp(name, "mwListBoxSet") == 0) { + int row = va_arg(va, int); + int col = va_arg(va, int); + const char* text = va_arg(va, const char*); + *(int*)out = mwListBoxSetImpl(handle, row, col, text); + } + if(strcmp(name, "mwListBoxSetIcon") == 0) { + int index = va_arg(va, int); + MwLLPixmap icon = va_arg(va, MwLLPixmap); + mwListBoxSetIconImpl(handle, index, icon); + } +} + +static void tick(MwWidget handle) { + MwListBox lb = handle->internal; + + if(lb->changed) { + lb->changed = 0; + MwForceRender(lb->frame); + } +} + +static void props_change(MwWidget handle, char** props) { + int i; + int rsz = 0; + + for(i = 0; props[i] != NULL; i++) { + if(strcmp(props[i], MwNwidth) == 0 || strcmp(props[i], MwNheight) == 0 || strcmp(props[i], MwNhasHeading) == 0) rsz = 1; + } + + if(rsz) resize(handle, 0); +} + +MwClassRec MwListBoxClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + tick, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + props_change, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwListBoxClass = &MwListBoxClassRec; diff --git a/widget/milsko/milskosrc/src/widget/menu.c b/widget/milsko/milskosrc/src/widget/menu.c new file mode 100644 index 0000000000..8dd3d7a997 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/menu.c @@ -0,0 +1,265 @@ +#include + +#include "../../external/stb_ds.h" + +static void set_xywh(MwWidget handle) { + int height = 0; + int diff = MwDefaultBorderWidth(handle); + diff = 0; + + height = MwTextHeight(handle, NULL, "M") + 10; + + MwVaApply(handle, + MwNx, -diff, + MwNy, -diff, + MwNwidth, MwGetInteger(handle->parent, MwNwidth) + diff * 2, + MwNheight, height + diff, + NULL); +} + +static int wcreate(MwWidget handle) { + MwMenu m = malloc(sizeof(*m)); + + m->name = NULL; + m->wsub = NULL; + m->sub = NULL; + handle->internal = m; + handle->is_menu = MwTRUE; + + MwSetDefault(handle); + + set_xywh(handle); + + return 0; +} + +static void recursive_free(MwMenu m) { + int i; + + for(i = 0; i < arrlen(m->sub); i++) { + recursive_free(m->sub[i]); + } + + if(m->sub != NULL) arrfree(m->sub); + if(m->name != NULL) free(m->name); + free(m); +} + +static void destroy(MwWidget handle) { + MwMenu m = handle->internal; + + recursive_free(m); +} + +#define MENU_LOOP_DECL \ + int i; \ + MwMenu m = handle->internal; \ + MwPoint p; \ + MwRect r; \ + int rx; \ + int in_area; + +#define MENU_LOOP_INIT \ + p.x = 0; \ + p.y = (MwGetInteger(handle, MwNheight) - MwDefaultBorderWidth(handle)) / 2 + MwDefaultBorderWidth(handle); \ +\ + r.x = 0; \ + r.y = 0; \ + r.width = MwGetInteger(handle, MwNwidth); \ + r.height = MwGetInteger(handle, MwNheight); \ +\ + rx = r.width; + +#define BEGIN_MENU_LOOP \ + for(i = 0; i < arrlen(m->sub); i++) { \ + int incr = m->sub[i]->name[0] == '?' ? 1 : 0; \ + int tw = MwTextWidth(handle, MwFLBuildFont(MwFLFlagBold), m->sub[i]->name + incr); \ + int th = MwTextHeight(handle, MwFLBuildFont(MwFLFlagBold), m->sub[i]->name + incr); \ +\ + if(incr) { \ + p.x = rx -= 10 + tw; \ + } \ +\ + r.x = p.x; \ + r.y = p.y + ((MwGetInteger(handle, MwNheight) - p.y * 2) - (th + 10)) / 2; \ + r.width = tw + 10; \ + r.height = th + 10; \ +\ + in_area = (r.x <= handle->mouse_point.x && r.y <= handle->mouse_point.y && handle->mouse_point.x <= (int)(r.x + r.width) && handle->mouse_point.y <= (int)(r.y + r.height)) ? 1 : 0; \ + p.x += 5 + tw / 2; + +#define END_MENU_LOOP \ + p.x += tw / 2 + 5; \ + } + +#define NEW_SUBMENU \ + MwPoint p2; \ +\ + p2.x = p.x - 5 - tw / 2; \ + p2.y = p.y + th / 2 + 5; \ +\ + m->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, MwGetInteger(handle, MwNheight), 0, 0); \ + MwSubMenuAppear(m->sub[i]->wsub, m->sub[i], &p2, 0); \ + m->sub[i]->cleaned = 0; + +static void draw(MwWidget handle) { + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MENU_LOOP_DECL; + + MENU_LOOP_INIT; + + MwDrawWidgetBack(handle, &r, base, 0, MwDEFAULT); + + BEGIN_MENU_LOOP; + if(m->sub[i]->wsub != NULL || (in_area && handle->pressed)) { + MwDrawFrame(handle, &r, base, MwFALSE); + MwDrawWidgetBack(handle, &r, base, 0, 0); + } + + MwDrawText(handle, MwFLBuildFont((m->sub[i]->wsub != NULL || (in_area && handle->pressed)) ? MwFLFlagBold : 0), &p, m->sub[i]->name + incr, MwALIGNMENT_CENTER, text); + END_MENU_LOOP; + + MwLLFreeColor(text); + MwLLFreeColor(base); +} + +static void parent_resize(MwWidget handle) { + set_xywh(handle); +} + +static void mouse_down(MwWidget handle, void* ptr) { + MENU_LOOP_DECL; + + MENU_LOOP_INIT; + + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; + + BEGIN_MENU_LOOP; + if(in_area) { + if(m->sub[i]->wsub == NULL && arrlen(m->sub[i]->sub) > 0) { + NEW_SUBMENU; + } else if(m->sub[i]->wsub != NULL && m->sub[i]->keep) { + MwDestroyWidget(m->sub[i]->wsub); + m->sub[i]->wsub = NULL; + m->sub[i]->keep = 0; + m->sub[i]->cleaned = 1; + } + } else if(m->sub[i]->keep && m->sub[i]->wsub != NULL) { + MwDestroyWidget(m->sub[i]->wsub); + m->sub[i]->wsub = NULL; + m->sub[i]->keep = 0; + m->sub[i]->cleaned = 1; + } + END_MENU_LOOP; + + MwForceRender(handle); +} + +static void mouse_move(MwWidget handle) { + int matched = 0; + MENU_LOOP_DECL; + + MENU_LOOP_INIT; + + if(!handle->pressed) return; + + BEGIN_MENU_LOOP; + if(in_area && m->sub[i]->wsub == NULL) { + matched = 1; + } + END_MENU_LOOP; + + MENU_LOOP_INIT; + BEGIN_MENU_LOOP; + if(matched && m->sub[i]->wsub != NULL) { + MwDestroyWidget(m->sub[i]->wsub); + m->sub[i]->wsub = NULL; + m->sub[i]->keep = 0; + m->sub[i]->cleaned = 0; + } + END_MENU_LOOP; + + MENU_LOOP_INIT; + BEGIN_MENU_LOOP; + if(matched && in_area) { + if(m->sub[i]->wsub == NULL && arrlen(m->sub[i]->sub) > 0 && !m->sub[i]->cleaned) { + NEW_SUBMENU; + } + } + END_MENU_LOOP; + + if(matched) MwForceRender(handle); +} + +static void mouse_up(MwWidget handle, void* ptr) { + MENU_LOOP_DECL; + + MENU_LOOP_INIT; + + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; + + BEGIN_MENU_LOOP; + if(in_area && m->sub[i]->wsub != NULL) { + m->sub[i]->keep = 1; + } else if(in_area) { + if(arrlen(m->sub[i]->sub) == 0) { + MwDispatchUserHandler(handle, MwNmenuHandler, m->sub[i]); + } + } else if(m->sub[i]->wsub != NULL) { + MwDestroyWidget(m->sub[i]->wsub); + m->sub[i]->wsub = NULL; + m->sub[i]->keep = 0; + m->sub[i]->cleaned = 0; + } + END_MENU_LOOP; + + MwForceRender(handle); +} + +static MwMenu mwMenuAddImpl(MwWidget handle, MwMenu menu, const char* name) { + MwMenu m = menu == NULL ? handle->internal : menu; + MwMenu new = malloc(sizeof(*new)); + new->name = MwStringDuplicate(name); + new->sub = NULL; + new->wsub = NULL; + new->keep = 0; + new->cleaned = 0; + + arrput(m->sub, new); + + set_xywh(handle); + + return new; +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwMenuAdd") == 0) { + MwMenu menu = va_arg(va, MwMenu); + const char* name = va_arg(va, const char*); + *(MwMenu*)out = mwMenuAddImpl(handle, menu, name); + } +} + +MwClassRec MwMenuClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + parent_resize, /* parent_resize */ + NULL, /* prop_change */ + mouse_move, /* mouse_move */ + mouse_up, /* mouse_up */ + mouse_down, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwMenuClass = &MwMenuClassRec; diff --git a/widget/milsko/milskosrc/src/widget/numberentry.c b/widget/milsko/milskosrc/src/widget/numberentry.c new file mode 100644 index 0000000000..f3a80e94c7 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/numberentry.c @@ -0,0 +1,153 @@ +#include + +static int wcreate(MwWidget handle) { + int st; + MwEntry e; + + if((st = MwEntryClass->create(handle)) != 0) return st; + + e = handle->internal; + e->right = 32; + + MwSetText(handle, MwNtext, "0"); + + return 0; +} + +static void destroy(MwWidget handle) { + MwEntryClass->destroy(handle); +} + +static void draw(MwWidget handle) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + MwEntry e = handle->internal; + MwRect r; + int pr; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + + MwEntryClass->draw(handle); + + pr = (handle->pressed && e->mouse.x >= (w - e->right) && e->mouse.y < (h / 2)) ? 1 : 0; + r.x = w - e->right; + r.y = 0; + r.width = e->right; + r.height = h / 2; + MwDrawWidgetBack(handle, &r, base, pr, MwDEFAULT); + + if(r.width > r.height) { + r.width = r.height; + } else { + r.height = r.width; + } + r.x = r.x + (e->right - r.width) / 2; + r.y = r.y + (h / 2 - r.height) / 2; + MwDrawTriangle(handle, &r, base, pr, MwNORTH); + + pr = (handle->pressed && e->mouse.x >= (w - e->right) && e->mouse.y >= (h / 2)) ? 1 : 0; + r.x = w - e->right; + r.y = h / 2; + r.width = e->right; + r.height = h / 2; + MwDrawWidgetBack(handle, &r, base, pr, MwDEFAULT); + + if(r.width > r.height) { + r.width = r.height; + } else { + r.height = r.width; + } + r.x = r.x + (e->right - r.width) / 2; + r.y = r.y + (h / 2 - r.height) / 2; + MwDrawTriangle(handle, &r, base, pr, MwSOUTH); + + MwLLFreeColor(base); +} + +static void key(MwWidget handle, int code) { + MwEntry e = handle->internal; + const char* str = MwGetText(handle, MwNtext); + int ok = 0; + if(str == NULL) str = ""; + + if(code == '-' && e->cursor == 0 && strchr(str, (int)'-') == NULL) { + ok = 1; + } else if('0' <= code && code <= '9') { + ok = 1; + } else if(code == '.' && strchr(str, (int)'.') == NULL) { + ok = 1; + } else if(code == MwKEY_BACKSPACE || code == MwKEY_LEFT || code == MwKEY_RIGHT) { + ok = 1; + } + + if(ok) MwEntryClass->key(handle, code); +} + +static void mouse_move(MwWidget handle) { + MwEntry e = handle->internal; + int w = MwGetInteger(handle, MwNwidth); + if(handle->mouse_point.x >= (w - e->right)) { + MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); + } else { + MwLLSetCursor(handle->lowlevel, &MwCursorText, &MwCursorTextMask); + } +} + +static void mouse_up(MwWidget handle, void* ptr) { + MwEntry e = handle->internal; + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + const char* str = MwGetText(handle, MwNtext); + + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; + + if(e->mouse.x >= (w - e->right)) { + char s[512]; + if(e->mouse.y >= (h / 2)) { + MwStringPrintIntoBuffer(s, 512, "%g", atof(str) - 1); + } else { + MwStringPrintIntoBuffer(s, 512, "%g", atof(str) + 1); + } + MwSetText(handle, MwNtext, s); + + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); + } + + MwForceRender(handle); +} + +static void mouse_down(MwWidget handle, void* ptr) { + MwEntry e = handle->internal; + + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; + + e->mouse = handle->mouse_point; + + MwForceRender(handle); +} + +static void prop_change(MwWidget handle, const char* prop) { + if(strcmp(prop, MwNtext) == 0) MwForceRender(handle); +} + +MwClassRec MwNumberEntryClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + mouse_move, /* mouse_move */ + mouse_up, /* mouse_up */ + mouse_down, /* mouse_down */ + key, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwNumberEntryClass = &MwNumberEntryClassRec; diff --git a/widget/milsko/milskosrc/src/widget/opengl.c b/widget/milsko/milskosrc/src/widget/opengl.c new file mode 100644 index 0000000000..30a1cee896 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/opengl.c @@ -0,0 +1,685 @@ +#ifndef __APPLE__ + +#include + +#ifndef MW_OPENGL +#define MW_OPENGL_NO_INCLUDE +#endif +#include + +#ifdef MW_OPENGL +#ifdef USE_GDI +typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); +typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); +typedef PROC(WINAPI* MWwglGetProcAddress)(LPCSTR); +typedef BOOL(WINAPI* MWwglDeleteContext)(HGLRC); + +typedef struct gdiopengl { + HDC dc; + HGLRC gl; + + void* lib; + + MWwglCreateContext wglCreateContext; + MWwglMakeCurrent wglMakeCurrent; + MWwglDeleteContext wglDeleteContext; + MWwglGetProcAddress wglGetProcAddress; +} gdiopengl_t; +#endif +#ifdef USE_X11 +typedef XVisualInfo* (*MWglXChooseVisual)(Display* dpy, int screen, + int* attribList); +typedef GLXContext (*MWglXCreateContext)(Display* dpy, XVisualInfo* vis, + GLXContext shareList, Bool direct); +typedef void (*MWglXDestroyContext)(Display* dpy, GLXContext ctx); +typedef Bool (*MWglXMakeCurrent)(Display* dpy, GLXDrawable drawable, + GLXContext ctx); +typedef void (*MWglXSwapBuffers)(Display* dpy, GLXDrawable drawable); +typedef void* (*MWglXGetProcAddress)(const GLubyte* procname); + +typedef struct x11opengl { + XVisualInfo* visual; + GLXContext gl; + + void* lib; + + MWglXChooseVisual glXChooseVisual; + MWglXCreateContext glXCreateContext; + MWglXDestroyContext glXDestroyContext; + MWglXMakeCurrent glXMakeCurrent; + MWglXSwapBuffers glXSwapBuffers; + MWglXGetProcAddress glXGetProcAddress; +} x11opengl_t; +#endif + +#ifdef USE_WAYLAND +#include +#include +#include +#include + +/* +Note that for Wayland we create a GBM buffer manually and handle blitting it ourselves instead of using wayland-egl. Doing this allows us greater freedom over event handling; wayland-egl constantly pumps events, making us have to add a weird exception to wayland.c to make this work. Doing this also allows us to clip the OpenGL widget, something that was harder (impossible) with egl wayland. +*/ +typedef struct waylandopengl { + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; + EGLConfig egl_config; + struct gbm_device* gbm; + struct gbm_surface* gbm_surface; + struct gbm_bo* previous_bo; + int drm_fd; + MwLLPixmap frontbuffer; + MwU8* frontbuffer_data; + + void* gllib; + void* gbmlib; + EGLBoolean (*eglGetConfigs)(EGLDisplay display, + EGLConfig* configs, + EGLint config_size, + EGLint* num_config); + EGLBoolean (*eglInitialize)(EGLDisplay display, + EGLint* major, + EGLint* minor); + EGLContext (*eglCreateContext)(EGLDisplay display, + EGLConfig config, + EGLContext share_context, + EGLint const* attrib_list); + EGLBoolean (*eglMakeCurrent)(EGLDisplay display, + EGLSurface draw, + EGLSurface read, + EGLContext context); + void* (*eglGetProcAddress)(char const* procname); + EGLBoolean (*eglSwapBuffers)(EGLDisplay display, + EGLSurface surface); + EGLBoolean (*eglSwapInterval)(EGLDisplay display, + EGLint interval); + EGLint (*eglGetError)(void); + EGLBoolean (*eglBindAPI)(EGLenum api); + EGLDisplay (*eglGetDisplay)(NativeDisplayType native_display); + EGLDisplay (*eglGetPlatformDisplay)(EGLenum platform, void* native_display, const EGLAttrib* attrib_list); + EGLSurface (*eglCreatePlatformWindowSurface)(EGLDisplay display, + EGLConfig config, + void* native_window, + EGLint const* attrib_list); + EGLBoolean (*eglChooseConfig)(EGLDisplay display, + EGLint const* attrib_list, + EGLConfig* configs, + EGLint config_size, + EGLint* num_config); + EGLBoolean (*eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value); + EGLBoolean (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); + + struct gbm_device* (*gbm_create_device)(int fd); + struct gbm_surface* (*gbm_surface_create)(struct gbm_device* gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags); + void (*gbm_surface_destroy)(struct gbm_surface* surface); + + struct gbm_bo* (*gbm_surface_lock_front_buffer)(struct gbm_surface* surface); + union gbm_bo_handle (*gbm_bo_get_handle)(struct gbm_bo* bo); + uint32_t (*gbm_bo_get_stride)(struct gbm_bo* bo); + uint32_t (*gbm_bo_get_width)(struct gbm_bo* bo); + uint32_t (*gbm_bo_get_height)(struct gbm_bo* bo); + void (*gbm_surface_release_buffer)(struct gbm_surface* surface, struct gbm_bo* bo); + void* (*gbm_bo_map)(struct gbm_bo* bo, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t flags, uint32_t* stride, void** map_data); + void (*gbm_bo_unmap)(struct gbm_bo* bo, void* map_data); + +} waylandopengl_t; +#endif + +static int wcreate(MwWidget handle) { + void* r = NULL; + MwWidget w = handle; + +#ifdef USE_GDI + if(handle->lowlevel->common.type == MwLLBackendGDI) { + PIXELFORMATDESCRIPTOR pfd; + int pf; + gdiopengl_t* o = r = malloc(sizeof(*o)); + + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.cDepthBits = 32; + pfd.cColorBits = 32; + + o->dc = GetDC(handle->lowlevel->gdi.hWnd); + + pf = ChoosePixelFormat(o->dc, &pfd); + SetPixelFormat(o->dc, pf, &pfd); + + o->lib = MwDynamicOpen("opengl32.dll"); + if(!o->lib) { + printf("Could not load OpenGL widget under WGL!\n"); + return 1; + } + +#define WGL_FUNC(x) \ + o->x = MwDynamicSymbol(o->lib, #x); \ + if(o->x == NULL) { \ + printf("Could not load OpenGL widget under WGL! " #x " missing.\n"); \ + return 1; \ + } + + WGL_FUNC(wglCreateContext); + WGL_FUNC(wglMakeCurrent); + WGL_FUNC(wglDeleteContext); + WGL_FUNC(wglGetProcAddress); + + o->gl = o->wglCreateContext(o->dc); + } +#endif +#ifdef USE_X11 + if(handle->lowlevel->common.type == MwLLBackendX11) { + int attribs[5]; + const char* glpath[] = {"libGL.so", "/usr/local/lib/libGL.so", + "/usr/X11R7/lib/libGL.so", "/usr/pkg/lib/libGL.so"}; + int glincr = 0; + x11opengl_t* o = r = malloc(sizeof(*o)); + + attribs[0] = GLX_RGBA; + attribs[1] = GLX_DOUBLEBUFFER; + attribs[2] = GLX_DEPTH_SIZE; + attribs[3] = 24; + attribs[4] = None; + + while(glpath[glincr] != NULL && + (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL); + + o->glXChooseVisual = + (MWglXChooseVisual)MwDynamicSymbol(o->lib, "glXChooseVisual"); + o->glXCreateContext = + (MWglXCreateContext)MwDynamicSymbol(o->lib, "glXCreateContext"); + o->glXDestroyContext = + (MWglXDestroyContext)MwDynamicSymbol(o->lib, "glXDestroyContext"); + o->glXMakeCurrent = + (MWglXMakeCurrent)MwDynamicSymbol(o->lib, "glXMakeCurrent"); + o->glXSwapBuffers = + (MWglXSwapBuffers)MwDynamicSymbol(o->lib, "glXSwapBuffers"); + o->glXGetProcAddress = + (MWglXGetProcAddress)MwDynamicSymbol(o->lib, "glXGetProcAddress"); + + /* XXX: fix this */ + o->visual = o->glXChooseVisual(handle->lowlevel->x11.display, + DefaultScreen(handle->lowlevel->x11.display), + attribs); + o->gl = o->glXCreateContext(handle->lowlevel->x11.display, o->visual, NULL, + GL_TRUE); + } +#endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + EGLint numConfigs; + EGLint numConfigsMatched; + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLSurface surface; + EGLint fbAttribs[] = {EGL_SURFACE_TYPE, + EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_DEPTH_SIZE, + 24, + EGL_NONE}; + EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, + 1, + EGL_CONTEXT_MAJOR_VERSION, + 1, + EGL_CONTEXT_MINOR_VERSION, + 1, + EGL_NONE}; + EGLDisplay display; + waylandopengl_t* o = r = malloc(sizeof(*o)); + int gbm_format = 0; + EGLConfig egl_configs[1024]; + memset(o, 0, sizeof(waylandopengl_t)); + + o->gllib = MwDynamicOpen("libEGL.so"); + if(!o->gllib) { + printf("Could not load OpenGL widget under Wayland! libEGL.so missing.\n"); + return 1; + } + o->gbmlib = MwDynamicOpen("libgbm.so"); + if(!o->gbmlib) { + printf("Could not load OpenGL widget under Wayland! libgbm.so missing.\n"); + return 1; + } +#define EGL_FUNC(x) \ + o->x = MwDynamicSymbol(o->gllib, #x); \ + if(!o->x) { \ + printf("Could not load OpenGL widget under Wayland! " #x " missing.\n"); \ + return 1; \ + }; +#define GBM_FUNC(x) \ + o->x = MwDynamicSymbol(o->gbmlib, #x); \ + if(!o->x) { \ + printf("Could not load OpenGL widget under Wayland! " #x " missing.\n"); \ + return 1; \ + }; + EGL_FUNC(eglGetConfigs) + EGL_FUNC(eglInitialize) + EGL_FUNC(eglCreateContext) + EGL_FUNC(eglMakeCurrent) + EGL_FUNC(eglGetProcAddress) + EGL_FUNC(eglSwapBuffers) + EGL_FUNC(eglSwapInterval) + EGL_FUNC(eglGetError) + EGL_FUNC(eglBindAPI) + EGL_FUNC(eglGetDisplay) + EGL_FUNC(eglCreatePlatformWindowSurface) + EGL_FUNC(eglChooseConfig) + EGL_FUNC(eglGetPlatformDisplay) + EGL_FUNC(eglGetConfigAttrib) + EGL_FUNC(eglDestroySurface) + GBM_FUNC(gbm_create_device) + GBM_FUNC(gbm_surface_create) + GBM_FUNC(gbm_surface_destroy) + GBM_FUNC(gbm_surface_lock_front_buffer) + GBM_FUNC(gbm_bo_get_handle) + GBM_FUNC(gbm_bo_get_stride) + GBM_FUNC(gbm_bo_get_width) + GBM_FUNC(gbm_bo_get_height) + GBM_FUNC(gbm_surface_release_buffer) + GBM_FUNC(gbm_bo_map) + GBM_FUNC(gbm_bo_unmap) + +#define eglGetConfigs o->eglGetConfigs +#define eglInitialize o->eglInitialize +#define eglCreateContext o->eglCreateContext +#define eglMakeCurrent o->eglMakeCurrent +#define eglGetProcAddress o->eglGetProcAddress +#define eglSwapBuffers o->eglSwapBuffers +#define eglSwapInterval o->eglSwapInterval +#define eglGetError o->eglGetError +#define eglBindAPI o->eglBindAPI +#define eglGetDisplay o->eglGetDisplay +#define eglCreatePlatformWindowSurface o->eglCreatePlatformWindowSurface +#define eglDestroySurface o->eglDestroySurface +#define eglChooseConfig o->eglChooseConfig +#define eglGetPlatformDisplay o->eglGetPlatformDisplay + + o->drm_fd = open("/dev/dri/renderD128", O_RDWR); + assert(o->drm_fd > 0); + o->gbm = o->gbm_create_device(o->drm_fd); + assert(o->gbm != NULL); + + display = eglGetPlatformDisplay(0x31D7, o->gbm, NULL); + if(display == EGL_NO_DISPLAY) { + printf("ERROR: eglGetDisplay, %0X\n", eglGetError()); + return 1; + } + + /* Initialize EGL */ + if(!eglInitialize(display, &majorVersion, &minorVersion)) { + printf("ERROR: eglInitialize, %0X\n", eglGetError()); + return 1; + } + + eglBindAPI(EGL_OPENGL_API); + + /* Get configs */ + if((eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE)) { + printf("ERROR: eglGetConfigs, %0X\n", eglGetError()); + return 1; + } + + /* Choose config */ + if((eglChooseConfig(display, fbAttribs, egl_configs, numConfigs, &numConfigsMatched) != + EGL_TRUE)) { + printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); + return 1; + } + + for(int i = 0; i < numConfigsMatched; i++) { + if(o->eglGetConfigAttrib(display, egl_configs[i], + EGL_NATIVE_VISUAL_ID, + &gbm_format) == EGL_FALSE) { + printf("ERROR: eglGetConfigAttrib, %0X\n", eglGetError()); + } else { + if(gbm_format == GBM_FORMAT_ARGB8888) { + o->egl_config = egl_configs[i]; + break; + } + } + } + + /* Create a GL context */ + context = eglCreateContext(display, o->egl_config, EGL_NO_CONTEXT, + contextAttribs); + if(context == EGL_NO_CONTEXT) { + printf("ERROR: eglCreateContext, %0X\n", eglGetError()); + return 1; + } + + o->gbm_surface = o->gbm_surface_create(o->gbm, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, GBM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING); + + /* Create a surface */ + surface = eglCreatePlatformWindowSurface(display, o->egl_config, + o->gbm_surface, NULL); + if(surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreatePlatformWindowSurface, %0X\n", eglGetError()); + return 1; + } + + if(!eglMakeCurrent(display, surface, surface, context)) { + printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); + } + + o->frontbuffer_data = malloc(handle->lowlevel->wayland.ww * handle->lowlevel->wayland.wh * 4); + memset(o->frontbuffer_data, 255, handle->lowlevel->wayland.ww * handle->lowlevel->wayland.wh * 4); + + o->frontbuffer = MwLoadRaw(handle, o->frontbuffer_data, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); + + MwVaApply(handle, MwNpixmap, o->frontbuffer, NULL); + + o->egl_display = display; + o->egl_surface = surface; + o->egl_context = context; + } +#endif + + handle->internal = r; + handle->lowlevel->common.copy_buffer = 0; + + MwSetDefault(handle); + + while(w->parent != NULL) + w = w->parent; + + w->berserk++; + + return 0; +} + +static void destroy(MwWidget handle) { + MwWidget w = handle; + +#ifdef USE_GDI + if(handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t* o = handle->internal; + + o->wglMakeCurrent(NULL, NULL); + DeleteDC(o->dc); + o->wglDeleteContext(o->gl); + + MwDynamicClose(o->lib); + } +#endif +#ifdef USE_X11 + if(handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t* o = handle->internal; + + o->glXMakeCurrent(handle->lowlevel->x11.display, None, NULL); + o->glXDestroyContext(handle->lowlevel->x11.display, o->gl); + + MwDynamicClose(o->lib); + } +#endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ + } +#endif + + while(w->parent != NULL) + w = w->parent; + + w->berserk--; + + free(handle->internal); +} + +static void mwOpenGLMakeCurrentImpl(MwWidget handle) { + /* these swap interval functions belonging here actually stink! */ + +#ifdef USE_GDI + if(handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t* o = handle->internal; + BOOL(APIENTRY * swap_interval_ext)(int) = NULL; + + o->wglMakeCurrent(o->dc, o->gl); + + if((swap_interval_ext = + MwOpenGLGetProcAddress(handle, "wglSwapIntervalEXT")) != NULL) { + swap_interval_ext(1); + } + } +#endif +#ifdef USE_X11 + if(handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t* o = handle->internal; + void (*swap_interval_ext)(Display*, GLXDrawable, int) = NULL; + void (*swap_interval_mesa)(unsigned int) = NULL; + void (*swap_interval_sgi)(int) = NULL; + + o->glXMakeCurrent(handle->lowlevel->x11.display, + handle->lowlevel->x11.window, o->gl); + + if((swap_interval_ext = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalEXT")) != NULL) { + swap_interval_ext(handle->lowlevel->x11.display, + handle->lowlevel->x11.window, 1); + } + + if((swap_interval_mesa = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalMESA")) != NULL) { + swap_interval_mesa(1); + } + + if((swap_interval_sgi = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalSGI")) != NULL) { + swap_interval_sgi(1); + } + } +#endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; + + if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, + o->egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + } + + MwLLForceRender(handle->lowlevel); + } +#endif +} + +static void mwOpenGLSwapBufferImpl(MwWidget handle) { +#ifdef USE_GDI + if(handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t* o = handle->internal; + + SwapBuffers(o->dc); + } +#endif +#ifdef USE_X11 + if(handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t* o = handle->internal; + + o->glXSwapBuffers(handle->lowlevel->x11.display, + handle->lowlevel->x11.window); + } +#endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; + struct gbm_bo* bo; + eglSwapInterval(o->egl_display, 0); + if(!eglSwapBuffers(o->egl_display, o->egl_surface)) { + printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); + } + bo = o->gbm_surface_lock_front_buffer(o->gbm_surface); + if(bo) { + void* gbmBoMapData = NULL; // Needed for unmapping if gbm_bo_map is used + MwU32 width = o->gbm_bo_get_width(bo); + MwU32 height = o->gbm_bo_get_height(bo); + MwU32 stride = o->gbm_bo_get_stride(bo); + void* map = o->gbm_bo_map(bo, 0, 0, width, height, GBM_BO_TRANSFER_READ, &stride, &gbmBoMapData); + MwU32 size = height * stride; + + if(map) { + for(int y = 0; y < height; y++) { + const MwU8* row = map + y * stride; + for(int x = 0; x < width; x++) { + /* Memory layout per pixel: [B][G][R][A] */ + MwU8 b = row[x * 4 + 0]; + MwU8 g = row[x * 4 + 1]; + MwU8 r = row[x * 4 + 2]; + + int out = (y * width + x) * 4; + o->frontbuffer_data[out + 0] = r; + o->frontbuffer_data[out + 1] = g; + o->frontbuffer_data[out + 2] = b; + o->frontbuffer_data[out + 3] = 255; + } + } + + MwPixmapReloadRaw( + o->frontbuffer, o->frontbuffer_data); + } + o->gbm_bo_unmap(bo, gbmBoMapData); + } + if(o->previous_bo) { + o->gbm_surface_release_buffer(o->gbm_surface, o->previous_bo); + } + o->previous_bo = bo; + + MwForceRender(handle); + } +#endif +} + +static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { +#ifdef USE_GDI + if(handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t* o = handle->internal; + + return o->wglGetProcAddress(name); + } +#endif +#ifdef USE_X11 + if(handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t* o = handle->internal; + + return o->glXGetProcAddress((const GLubyte*)name); + } +#endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; + return eglGetProcAddress(name); + } +#endif + return NULL; +} + +static void func_handler(MwWidget handle, const char* name, void* out, + va_list va) { + if(strcmp(name, "mwOpenGLMakeCurrent") == 0) { + mwOpenGLMakeCurrentImpl(handle); + } + if(strcmp(name, "mwOpenGLSwapBuffer") == 0) { + mwOpenGLSwapBufferImpl(handle); + } + if(strcmp(name, "mwOpenGLGetProcAddress") == 0) { + const char* _name = va_arg(va, const char*); + *(void**)out = mwOpenGLGetProcAddressImpl(handle, _name); + } +} + +#ifdef USE_WAYLAND +static void frontbuffer_draw(MwWidget handle) { + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; + MwRect r; + r.x = 0; + r.y = 0; + r.width = handle->lowlevel->wayland.ww; + r.height = handle->lowlevel->wayland.wh; + MwLLDrawPixmap(handle->lowlevel, &r, o->frontbuffer); + } +} +static void frontbuffer_resize(MwWidget handle) { + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; + if(o->frontbuffer_data) { + free(o->frontbuffer_data); + } + if(o->frontbuffer) { + MwLLDestroyPixmap(o->frontbuffer); + } + if(o->gbm_surface) { + o->gbm_surface_destroy(o->gbm_surface); + } + if(o->egl_surface) { + eglDestroySurface(o->egl_display, o->egl_surface); + } + + o->gbm_surface = o->gbm_surface_create(o->gbm, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, GBM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING); + + /* Create a surface */ + o->egl_surface = eglCreatePlatformWindowSurface(o->egl_display, o->egl_config, + o->gbm_surface, NULL); + if(o->egl_surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreatePlatformWindowSurface, %0X\n", eglGetError()); + } else { + } + + if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, o->egl_context)) { + printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); + } + + o->frontbuffer_data = malloc(handle->lowlevel->wayland.ww * handle->lowlevel->wayland.wh * 4); + memset(o->frontbuffer_data, 255, handle->lowlevel->wayland.ww * handle->lowlevel->wayland.wh * 4); + + o->frontbuffer = MwLoadRaw(handle, o->frontbuffer_data, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); + + MwVaApply(handle, MwNpixmap, o->frontbuffer, NULL); + } +} +#endif + +MwClassRec MwOpenGLClassRec = {wcreate, /* create */ + destroy, /* destroy */ +#ifdef USE_WAYLAND + frontbuffer_draw, /* draw */ +#else + NULL, /* draw */ +#endif + NULL, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ +#ifdef USE_WAYLAND + frontbuffer_resize, /* resize */ +#else + NULL, /* resize */ +#endif + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, NULL, NULL}; +MwClass MwOpenGLClass = &MwOpenGLClassRec; +#else +MWDECL MwClass MwOpenGLClass; + +MwClass MwOpenGLClass = NULL; +#endif + +#endif diff --git a/widget/milsko/milskosrc/src/widget/opengl_cocoa.m b/widget/milsko/milskosrc/src/widget/opengl_cocoa.m new file mode 100644 index 0000000000..a4d2bfa2f7 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/opengl_cocoa.m @@ -0,0 +1,131 @@ +#include "Mw/BaseTypes.h" +#include "Mw/Core.h" +#include "Mw/LowLevel/Cocoa.h" +#include "Mw/StringDefs.h" +#include +#include +#import + +@interface MacOpenGLWidget : NSObject { + NSOpenGLPixelFormat* pixelFormat; + NSOpenGLContext* glc; + MilskoCocoa* _win; +} + +- (MacOpenGLWidget*)initWithWindow:(MilskoCocoa*)w; +- (void)destroy; +- (void)makeCurrent; +- (void)swapBuffer; +- (void*)getProcAddressWithName:(const char*)name; + +@end + +static int wcreate(MwWidget handle) { + void* r = NULL; + MwWidget w = handle; + + int x = MwGetInteger(w, MwNx); + int y = MwGetInteger(w, MwNy); + int width = MwGetInteger(w, MwNwidth); + int height = MwGetInteger(w, MwNheight); + + printf("%d %d\n", width, height); + + handle->internal = + [[MacOpenGLWidget alloc] initWithWindow:handle->lowlevel->cocoa.real]; + handle->lowlevel->common.copy_buffer = 0; + + MwSetDefault(handle); + + while(w->parent != NULL) + w = w->parent; + + w->berserk++; + + return 0; +} + +static void destroy(MwWidget handle) { + [(MacOpenGLWidget*)handle->internal destroy]; +} + +static void mwOpenGLMakeCurrentImpl(MwWidget handle) { + [(MacOpenGLWidget*)handle->internal makeCurrent]; +} + +static void mwOpenGLSwapBufferImpl(MwWidget handle) { + [(MacOpenGLWidget*)handle->internal swapBuffer]; +} + +static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { + return [(MacOpenGLWidget*)handle->internal getProcAddressWithName:name]; +} + +static void func_handler(MwWidget handle, const char* name, void* out, + va_list va) { + if(strcmp(name, "mwOpenGLMakeCurrent") == 0) { + mwOpenGLMakeCurrentImpl(handle); + } + if(strcmp(name, "mwOpenGLSwapBuffer") == 0) { + mwOpenGLSwapBufferImpl(handle); + } + if(strcmp(name, "mwOpenGLGetProcAddress") == 0) { + const char* _name = va_arg(va, const char*); + *(void**)out = mwOpenGLGetProcAddressImpl(handle, _name); + } +} + +@implementation MacOpenGLWidget + +- (MacOpenGLWidget*)initWithWindow:(MilskoCocoa*)w { + NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = { + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAStencilSize, 8, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADoubleBuffer, NSOpenGLPFAAccelerated, + NSOpenGLPFANoRecovery, 0}; + self->pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes]; + self->glc = + [[NSOpenGLContext alloc] initWithFormat:pixelFormat + shareContext:nil]; + [self->glc setView:[w getView]]; + self->_win = w; + return self; +}; +- (void)destroy { +}; +- (void)makeCurrent { + [self->glc makeCurrentContext]; +}; +- (void)swapBuffer { + [self->glc flushBuffer]; +}; +- (void*)getProcAddressWithName:(const char*)name { + if(NSIsSymbolNameDefined(name)) { + return NSAddressOfSymbol(NSLookupAndBindSymbol(name)); + } else { + return NULL; + } +}; + +@end + +MwClassRec MwOpenGLClassRec = {wcreate, /* create */ + destroy, /* destroy */ + NULL, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, NULL, NULL, NULL}; +MwClass MwOpenGLClass = &MwOpenGLClassRec; diff --git a/widget/milsko/milskosrc/src/widget/progressbar.c b/widget/milsko/milskosrc/src/widget/progressbar.c new file mode 100644 index 0000000000..3185c233b8 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/progressbar.c @@ -0,0 +1,69 @@ +#include + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + MwVaApply(handle, + MwNminValue, 0, + MwNmaxValue, 100, + MwNvalue, 0, + NULL); + + return 0; +} + +static void draw(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor fill = MwParseColor(handle, MwGetText(handle, MwNforeground)); + double w; + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + w = MwGetInteger(handle, MwNvalue) - MwGetInteger(handle, MwNminValue); + w = w / (MwGetInteger(handle, MwNmaxValue) - MwGetInteger(handle, MwNminValue)); + + MwDrawWidgetBack(handle, &r, base, 1, MwDEFAULT); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + + r.x += MwDefaultBorderWidth(handle); + r.y += MwDefaultBorderWidth(handle); + r.width -= MwDefaultBorderWidth(handle) * 2; + r.height -= MwDefaultBorderWidth(handle) * 2; + + r.width = r.width * w; + MwDrawRect(handle, &r, fill); + + MwLLFreeColor(fill); + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNminValue) == 0 || strcmp(key, MwNmaxValue) == 0 || strcmp(key, MwNvalue) == 0) MwForceRender(handle); +} + +MwClassRec MwProgressBarClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwProgressBarClass = &MwProgressBarClassRec; diff --git a/widget/milsko/milskosrc/src/widget/radiobox.c b/widget/milsko/milskosrc/src/widget/radiobox.c new file mode 100644 index 0000000000..c93e054b4f --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/radiobox.c @@ -0,0 +1,78 @@ +#include + +#include "../../external/stb_ds.h" + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNchecked, 0); + + return 0; +} + +static void draw(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, base); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + + if(r.width < r.height) { + r.height = r.width; + } else { + r.width = r.height; + } + r.x = (MwGetInteger(handle, MwNwidth) - r.width) / 2; + r.y = (MwGetInteger(handle, MwNheight) - r.height) / 2; + + MwDrawDiamond(handle, &r, base, (handle->pressed || MwGetInteger(handle, MwNchecked)) ? 1 : 0); + + MwLLFreeColor(base); +} + +static void click(MwWidget handle) { + if(!MwGetInteger(handle, MwNchecked)) MwSetInteger(handle, MwNchecked, 1); + if(MwGetInteger(handle, MwNchecked) && handle->parent != NULL) { + int i; + for(i = 0; i < arrlen(handle->parent->children); i++) { + MwWidget w = handle->parent->children[i]; + if(w != handle && w->widget_class == MwRadioBoxClass && MwGetInteger(w, MwNchecked)) { + MwSetInteger(w, MwNchecked, 0); + } + } + } + + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNchecked) == 0) MwForceRender(handle); +} + +MwClassRec MwRadioBoxClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + click, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + MwForceRender2, /* mouse_up */ + MwForceRender2, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwRadioBoxClass = &MwRadioBoxClassRec; diff --git a/widget/milsko/milskosrc/src/widget/scrollbar.c b/widget/milsko/milskosrc/src/widget/scrollbar.c new file mode 100644 index 0000000000..346f818aba --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/scrollbar.c @@ -0,0 +1,280 @@ +#include + +static int wcreate(MwWidget handle) { + MwScrollBar scr = malloc(sizeof(*scr)); + + handle->internal = scr; + + MwSetDefault(handle); + MwVaApply(handle, + MwNminValue, 0, + MwNmaxValue, 100, + MwNvalue, 0, + MwNareaShown, 50, + MwNorientation, MwVERTICAL, + MwNshowArrows, 1, + NULL); + + return 0; +} + +static void destroy(MwWidget handle) { + free(handle->internal); +} + +static int calc_length(MwWidget handle) { + int max = MwScrollBarGetVisibleLength(handle); + int len = MwGetInteger(handle, MwNmaxValue) - MwGetInteger(handle, MwNminValue); + int area = MwGetInteger(handle, MwNareaShown); + if(area > len) area = len; + + return max * (double)area / len; +} + +static int calc_position(MwWidget handle) { + int max = MwScrollBarGetVisibleLength(handle); + int len = MwGetInteger(handle, MwNmaxValue) - MwGetInteger(handle, MwNminValue); + int val = MwGetInteger(handle, MwNvalue); + + return (max - calc_length(handle)) * (double)val / len; +} + +static void add_value(MwWidget handle, int mul) { + int val = MwGetInteger(handle, MwNvalue); + int min = MwGetInteger(handle, MwNminValue); + int max = MwGetInteger(handle, MwNmaxValue); + + val += mul * MwGetInteger(handle, MwNareaShown); + + if(val < min) val = min; + if(val > max) val = max; + + MwSetInteger(handle, MwNvalue, val); + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); +} + +static void draw(MwWidget handle) { + MwRect r, rt, rbar; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor dark = MwLightenColor(handle, base, -64, -64, -64); + MwScrollBar scr = handle->internal; + int or ; + int uy, dy, ux, dx; + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + uy = r.width; + dy = r.height - r.width; + + ux = r.height; + dx = r.width - r.height; + + MwDrawWidgetBack(handle, &r, dark, 1, MwDEFAULT); + if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); + + rt = r; + + or = MwGetInteger(handle, MwNorientation); + if(or == MwVERTICAL) { + rt.height = rt.width; + + rt.y = r.y; + if(MwGetInteger(handle, MwNshowArrows)) { + MwDrawTriangle(handle, &rt, base, (handle->pressed && scr->point.y <= uy) ? 1 : 0, MwNORTH); + if(handle->pressed && scr->point.y <= uy) { + add_value(handle, -1); + } + } else { + rt.height = 0; + } + + rbar.width = r.width; + rbar.height = calc_length(handle); + rbar.x = r.x; + rbar.y = r.y + rt.height + calc_position(handle); + + rt.y = r.y + r.height - rt.height; + if(MwGetInteger(handle, MwNshowArrows)) { + MwDrawTriangle(handle, &rt, base, (handle->pressed && scr->point.y >= dy) ? 1 : 0, MwSOUTH); + if(handle->pressed && scr->point.y >= dy) { + add_value(handle, 1); + } + } + } else if(or == MwHORIZONTAL) { + rt.width = rt.height; + + rt.x = r.x; + if(MwGetInteger(handle, MwNshowArrows)) { + MwDrawTriangle(handle, &rt, base, (handle->pressed && scr->point.x <= ux) ? 1 : 0, MwWEST); + if(handle->pressed && scr->point.x <= ux) { + add_value(handle, -1); + } + } else { + rt.width = 0; + } + + rbar.width = calc_length(handle); + rbar.height = r.height; + rbar.x = r.x + rt.width + calc_position(handle); + rbar.y = r.y; + + rt.x = r.x + r.width - rt.width; + if(MwGetInteger(handle, MwNshowArrows)) { + MwDrawTriangle(handle, &rt, base, (handle->pressed && scr->point.x >= dx) ? 1 : 0, MwEAST); + if(handle->pressed && scr->point.x >= dx) { + add_value(handle, 1); + } + } + } + + if(rbar.height >= 0) MwDrawWidgetBack(handle, &rbar, base, 0, MwDEFAULT); + + MwLLFreeColor(dark); + MwLLFreeColor(base); +} + +static void mouse_move(MwWidget handle) { + int or = MwGetInteger(handle, MwNorientation); + MwScrollBar scr = handle->internal; + + if(!handle->pressed) return; + + if(scr->drag) { + int l = 0; + double len = MwScrollBarGetVisibleLength(handle) - calc_length(handle); + int min = MwGetInteger(handle, MwNminValue); + int max = MwGetInteger(handle, MwNmaxValue); + + if(or == MwVERTICAL) { + l = handle->mouse_point.y + scr->pos; + } else if(or == MwHORIZONTAL) { + l = handle->mouse_point.x + scr->pos; + } + + len = l / len; + if(len < 0) len = 0; + if(len > 1) len = 1; + MwSetInteger(handle, MwNvalue, (int)((max - min) * len - min)); + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); + + MwForceRender(handle); + } +} + +static void mouse_down(MwWidget handle, void* ptr) { + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + int or = MwGetInteger(handle, MwNorientation); + MwScrollBar scr = handle->internal; + MwMouse* m = ptr; + + if(m->button == MwMOUSE_WHEELUP) { + int min = MwGetInteger(handle, MwNminValue); + int val = MwGetInteger(handle, MwNvalue); + int diff = MwGetInteger(handle, MwNareaShown); + + val -= diff; + + if(val < min) val = min; + + MwSetInteger(handle, MwNvalue, val); + MwSetInteger(handle, MwNchangedBy, -diff); + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); + } else if(m->button == MwMOUSE_WHEELDOWN) { + int max = MwGetInteger(handle, MwNmaxValue); + int val = MwGetInteger(handle, MwNvalue); + int diff = MwGetInteger(handle, MwNareaShown); + + val += diff; + + if(val > max) val = max; + + MwSetInteger(handle, MwNvalue, val); + MwSetInteger(handle, MwNchangedBy, diff); + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); + } + if(m->button != MwMOUSE_LEFT) return; + + scr->point = handle->mouse_point; + scr->drag = 0; + if(or == MwVERTICAL) { + int tri = (ww - MwDefaultBorderWidth(handle) * 2) + MwDefaultBorderWidth(handle); + if(!MwGetInteger(handle, MwNshowArrows)) tri = 0; + if(tri <= scr->point.y && scr->point.y <= (wh - tri)) { + scr->drag = 1; + scr->pos = calc_position(handle) - scr->point.y; + } + } else if(or == MwHORIZONTAL) { + int tri = (wh - MwDefaultBorderWidth(handle) * 2) + MwDefaultBorderWidth(handle); + if(!MwGetInteger(handle, MwNshowArrows)) tri = 0; + if(tri <= scr->point.x && scr->point.x <= (ww - tri)) { + scr->drag = 1; + scr->pos = calc_position(handle) - scr->point.x; + } + } + + MwForceRender(handle); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNminValue) == 0 || strcmp(key, MwNvalue) == 0 || strcmp(key, MwNmaxValue) == 0) { + if(MwGetInteger(handle, MwNvalue) > MwGetInteger(handle, MwNmaxValue)) MwSetInteger(handle, MwNvalue, MwGetInteger(handle, MwNmaxValue)); + MwForceRender(handle); + } + if(strcmp(key, MwNshowArrows) == 0 || strcmp(key, MwNareaShown) == 0) { + MwForceRender(handle); + } +} + +static int mwScrollBarGetVisibleLengthImpl(MwWidget handle) { + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + int or = MwGetInteger(handle, MwNorientation); + int tri = 0; + int s = 0; + + if(or == MwVERTICAL) { + tri = (ww - MwDefaultBorderWidth(handle) * 2) * 2; + s = wh; + } else if(or == MwHORIZONTAL) { + tri = (wh - MwDefaultBorderWidth(handle) * 2) * 2; + s = ww; + } + if(!MwGetInteger(handle, MwNshowArrows)) tri = 0; + return s - tri - MwDefaultBorderWidth(handle) * 2; +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + (void)va; + + if(strcmp(name, "mwScrollBarGetVisibleLength") == 0) { + *(int*)out = mwScrollBarGetVisibleLengthImpl(handle); + } +} + +MwClassRec MwScrollBarClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + mouse_move, /* mouse_move */ + MwForceRender2, /* mouse_up */ + mouse_down, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwScrollBarClass = &MwScrollBarClassRec; diff --git a/widget/milsko/milskosrc/src/widget/separator.c b/widget/milsko/milskosrc/src/widget/separator.c new file mode 100644 index 0000000000..4e70ccc7b5 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/separator.c @@ -0,0 +1,58 @@ +#include + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNorientation, MwHORIZONTAL); + + return 0; +} + +static void draw(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, base); + + if(MwGetInteger(handle, MwNorientation) == MwVERTICAL) { + r.x = (r.width - 2) / 2; + r.width = 2; + } else if(MwGetInteger(handle, MwNorientation) == MwHORIZONTAL) { + r.y = (r.height - 2) / 2; + r.height = 2; + } + MwDrawFrameEx(handle, &r, base, 1, 1, 0, 0); + + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNorientation) == 0) MwForceRender(handle); +} + +MwClassRec MwSeparatorClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwSeparatorClass = &MwSeparatorClassRec; diff --git a/widget/milsko/milskosrc/src/widget/submenu.c b/widget/milsko/milskosrc/src/widget/submenu.c new file mode 100644 index 0000000000..6bc5d550ce --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/submenu.c @@ -0,0 +1,264 @@ +#include + +#include "../../external/stb_ds.h" + +static int wcreate(MwWidget handle) { + MwLLBeginStateChange(handle->lowlevel); + + MwSetDefault(handle); + MwSetInteger(handle, MwNleftPadding, 0); + + handle->internal = NULL; + + return 0; +} + +static void null_all(MwMenu menu) { + int i; + for(i = 0; i < arrlen(menu->sub); i++) { + null_all(menu->sub[i]); + } + menu->wsub = NULL; +} + +static void destroy(MwWidget handle) { + MwMenu menu = handle->internal; + + menu->wsub = NULL; + null_all(menu); +} + +static void draw(MwWidget handle) { + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwRect r; + MwMenu menu = handle->internal; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawWidgetBack(handle, &r, base, 0, MwDEFAULT); + + if(menu != NULL) { + MwPoint p; + int i; + + p.x = 0; + p.y = 3; + + for(i = 0; i < arrlen(menu->sub); i++) { + if(strcmp(menu->sub[i]->name, "----") == 0) { + MwRect rc; + + p.y += 1; + + rc.x = MwDefaultBorderWidth(handle) * 2; + rc.y = p.y; + rc.width = r.width - (rc.x * 2) - MwGetInteger(handle, MwNleftPadding); + rc.height = 2; + + rc.x += MwGetInteger(handle, MwNleftPadding); + + MwDrawFrameEx(handle, &rc, base, 1, 1, 0, 0); + + p.y += 2 + 1; + } else { + int tw = MwTextWidth(handle, NULL, menu->sub[i]->name); + int th = MwTextHeight(handle, NULL, menu->sub[i]->name); + + if(menu->sub[i]->wsub != NULL) { + r.x = MwGetInteger(handle, MwNleftPadding); + r.y = p.y - 3; + r.width = MwGetInteger(handle, MwNwidth) - MwGetInteger(handle, MwNleftPadding); + r.height = th + 3 * 2; + MwDrawWidgetBack(handle, &r, base, 0, MwDEFAULT); + } + + p.x = 5 + tw / 2 + MwGetInteger(handle, MwNleftPadding); + + p.y += th / 2; + MwDrawText(handle, MwFLBuildFont(menu->sub[i]->wsub != NULL ? MwFLFlagBold : 0), &p, menu->sub[i]->name, MwALIGNMENT_CENTER, text); + + if(arrlen(menu->sub[i]->sub) > 0) { + MwRect tr; + + tr.x = MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) - 11 - 2; + tr.y = p.y - th / 2 + 2; + tr.width = tr.height = 11; + + MwDrawTriangle(handle, &tr, base, menu->sub[i]->wsub != NULL ? 1 : 0, MwEAST); + } + + p.y += th / 2 + 3; + } + } + } + + MwLLFreeColor(text); + MwLLFreeColor(base); +} + +static void click(MwWidget handle) { + MwWidget w = handle; + MwMenu menu = handle->internal; + + if(arrlen(menu->sub) > 0) { + int ww = 0, i; + MwRect rc; + + rc.x = 5; + rc.y = 3; + for(i = 0; i < arrlen(menu->sub); i++) { + int tw = MwTextWidth(handle, NULL, menu->sub[i]->name); + if(tw > ww) ww = tw; + } + + rc.width = ww + 15; + for(i = 0; i < arrlen(menu->sub); i++) { + int th = MwTextHeight(handle, NULL, menu->sub[i]->name); + rc.height = th; + + if(strcmp(menu->sub[i]->name, "----") == 0) { + rc.height = 2 - 1; + } + + if(MwGetInteger(handle, MwNleftPadding) <= handle->mouse_point.x && rc.y <= handle->mouse_point.y && handle->mouse_point.y <= (int)(rc.y + rc.height)) { + if(menu->sub[i]->wsub == NULL && arrlen(menu->sub[i]->sub) > 0) { + MwPoint p; + int j; + + for(j = 0; j < arrlen(menu->sub); j++) { + if(menu->sub[j]->wsub != NULL) MwDestroyWidget(menu->sub[j]->wsub); + menu->sub[j]->wsub = NULL; + } + + p.x = MwGetInteger(handle, MwNwidth); + p.y = rc.y - 3; + + menu->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, 0, 0, 0); + MwSubMenuAppear(menu->sub[i]->wsub, menu->sub[i], &p, 0); + i = -1; + } else if(menu->sub[i]->wsub != NULL && arrlen(menu->sub[i]->sub) > 0) { + while(w->parent->widget_class == MwSubMenuClass) w = w->parent; + + MwDestroyWidget(menu->sub[i]->wsub); + menu->sub[i]->wsub = NULL; + + MwForceRender(w->parent); + + MwForceRender(handle); + } else if(strcmp(menu->sub[i]->name, "----") != 0 && arrlen(menu->sub[i]->sub) == 0) { + while(w->parent->widget_class == MwSubMenuClass) w = w->parent; + + MwDestroyWidget(w); + ((MwMenu)w->internal)->wsub = NULL; + + MwForceRender(w->parent); + + MwDispatchUserHandler(w->parent, MwNmenuHandler, menu->sub[i]); + } + } + + rc.y += rc.height + 3; + } + } +} + +static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, int diff_calc) { + MwRect rc, sz; + MwPoint p = *point; + + MwSubMenuGetSize(handle, menu, &sz); + + MwGetScreenSize(handle, &rc); + + handle->internal = menu; + + if(diff_calc) { + p.y = p.y - sz.height; + } + + MwLLMakeToolWindow(handle->lowlevel); + MwLLDetach(handle->lowlevel, &p); + + if(handle->lowlevel->common.coordinate_type == MwCOORDINATE_GLOBAL) { + if(MwGetInteger(handle, MwNy) + sz.height > rc.height) { + MwVaApply(handle, + MwNy, rc.height - sz.height, + NULL); + } + } + + MwLLEndStateChange(handle->lowlevel); + + MwVaApply(handle, + MwNwidth, sz.width, + MwNheight, sz.height, + NULL); +} + +static void mwSubMenuGetSizeImpl(MwWidget handle, MwMenu menu, MwRect* rect) { + int i; + + rect->width = 0; + rect->height = 0; + + for(i = 0; i < arrlen(menu->sub); i++) { + if(strcmp(menu->sub[i]->name, "----") == 0) { + rect->height += 2 + 2; + } else { + int tw = MwTextWidth(handle, NULL, menu->sub[i]->name); + rect->height += MwTextHeight(handle, NULL, menu->sub[i]->name) + 3; + if(tw > rect->width) { + rect->width = tw; + } + } + } + + rect->width += MwGetInteger(handle, MwNleftPadding); + + rect->width += 10 + 15; + rect->height += 3; + + rect->width += 16; +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + (void)out; + + if(strcmp(name, "mwSubMenuAppear") == 0) { + MwMenu menu = va_arg(va, MwMenu); + MwPoint* point = va_arg(va, MwPoint*); + int diff_calc = va_arg(va, int); + mwSubMenuAppearImpl(handle, menu, point, diff_calc); + } else if(strcmp(name, "mwSubMenuGetSize") == 0) { + MwMenu menu = va_arg(va, MwMenu); + MwRect* rect = va_arg(va, MwRect*); + mwSubMenuGetSizeImpl(handle, menu, rect); + } +} + +MwClassRec MwSubMenuClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + click, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + MwForceRender2, /* mouse_up */ + MwForceRender2, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwSubMenuClass = &MwSubMenuClassRec; diff --git a/widget/milsko/milskosrc/src/widget/subwindow.c b/widget/milsko/milskosrc/src/widget/subwindow.c new file mode 100644 index 0000000000..81b5392181 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/subwindow.c @@ -0,0 +1,425 @@ +#include + +#include "../../external/stb_ds.h" + +#define TitleHeight 20 +#define ButtonSize 14 + +static void resize(MwWidget handle); + +static void close_draw(MwWidget handle) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + MwPoint p[2]; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNforeground)); + int bw = MwDefaultBorderWidth(handle); + + p[0].x = bw * 2; + p[0].y = bw * 2; + p[1].x = w - bw * 2 - 1; + p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].x++; + p[1].x--; + MwLLLine(handle->lowlevel, p, c); + + p[0].x = w - bw * 2 - 1; + p[0].y = bw * 2; + p[1].x = bw * 2; + p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].x--; + p[1].x++; + MwLLLine(handle->lowlevel, p, c); + + MwLLFreeColor(c); +} + +static void MWAPI close_activate(MwWidget handle, void* user, void* client) { + MwWidget w = user; + + (void)handle; + (void)client; + + MwDispatchUserHandler(w, MwNcloseHandler, NULL); + + MwLLRaise(w->lowlevel); +} + +static void maximize_draw(MwWidget handle) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + MwPoint p[2]; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNforeground)); + int bw = MwDefaultBorderWidth(handle); + + p[0].x = bw * 2; + p[0].y = bw * 2; + p[1].x = w - bw * 2 - 1; + p[1].y = bw * 2; + MwLLLine(handle->lowlevel, p, c); + + p[0].y = p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].y = p[1].y = bw * 2 + 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].x = bw * 2; + p[0].y = bw * 2; + p[1].x = bw * 2; + p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].x = p[1].x = w - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + MwLLFreeColor(c); +} + +static void MWAPI maximize_activate(MwWidget handle, void* user, void* client) { + MwWidget w = user; + MwSubWindow sw = w->internal; + + (void)handle; + (void)client; + + if(sw->minimized) return; + + if(sw->maximized) { + MwVaApply(user, + MwNx, sw->x, + MwNy, sw->y, + MwNwidth, sw->width, + MwNheight, sw->height, + NULL); + } else { + sw->x = MwGetInteger(w, MwNx); + sw->y = MwGetInteger(w, MwNy); + sw->width = MwGetInteger(w, MwNwidth); + sw->height = MwGetInteger(w, MwNheight); + + MwVaApply(user, + MwNx, 0, + MwNy, 0, + MwNwidth, MwGetInteger(w->parent, MwNwidth), + MwNheight, MwGetInteger(w->parent, MwNheight), + NULL); + } + sw->maximized = !sw->maximized; + + MwLLRaise(w->lowlevel); +} + +static void minimize_draw(MwWidget handle) { + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + MwPoint p[2]; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNforeground)); + int bw = MwDefaultBorderWidth(handle); + + p[0].x = bw * 2; + p[0].y = h - bw * 2 - 1; + p[1].x = w - bw * 2 - 1; + p[1].y = h - bw * 2 - 1; + MwLLLine(handle->lowlevel, p, c); + + p[0].y--; + p[1].y--; + MwLLLine(handle->lowlevel, p, c); + + MwLLFreeColor(c); +} + +static int sort_subwindow(const void* _a, const void* _b) { + MwWidget a = *(MwWidget*)_a; + MwWidget b = *(MwWidget*)_b; + int ax = MwGetInteger(a, MwNx); + int bx = MwGetInteger(b, MwNx); + + if(ax < bx) return -1; + if(ax > bx) return 1; + return 0; +} + +static void MWAPI minimize_activate(MwWidget handle, void* user, void* client) { + MwWidget w = user; + MwSubWindow sw = w->internal; + + (void)handle; + (void)client; + + if(sw->maximized) return; + + if(sw->minimized) { + int i; + MwWidget* ws = NULL; + int p = 0; + + for(i = 0; i < arrlen(w->parent->children); i++) { + MwWidget c = w->parent->children[i]; + if(c->widget_class == MwSubWindowClass) { + MwSubWindow csw = c->internal; + + if(!csw->minimized) continue; + + arrput(ws, c); + } + } + + if(ws != NULL) { + qsort(ws, arrlen(ws), sizeof(*ws), sort_subwindow); + + for(i = 0; i < arrlen(ws); i++) { + if(p) { + MwVaApply(ws[i], + MwNx, MwGetInteger(ws[i], MwNx) - MwGetInteger(w, MwNwidth), + NULL); + } else if(ws[i] == w) { + p = 1; + } + } + } + arrfree(ws); + + MwVaApply(user, + MwNx, sw->x, + MwNy, sw->y, + NULL); + } else { + int x = 0; + int i; + + for(i = 0; i < arrlen(w->parent->children); i++) { + MwWidget c = w->parent->children[i]; + + if(c->widget_class == MwSubWindowClass) { + MwSubWindow cw = c->internal; + + if(cw->minimized) x += MwGetInteger(c, MwNwidth); + } + } + + sw->x = MwGetInteger(w, MwNx); + sw->y = MwGetInteger(w, MwNy); + + MwVaApply(user, + MwNx, x, + MwNy, MwGetInteger(w->parent, MwNheight) - TitleHeight - MwDefaultBorderWidth(handle), + NULL); + } + sw->minimized = !sw->minimized; + + MwLLRaise(w->lowlevel); +} + +static void resize(MwWidget handle) { + MwSubWindow sw = handle->internal; + int x, y, w, h; + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + int bw = MwDefaultBorderWidth(handle); + int p; + + x = bw * 2; + y = bw * 2 + TitleHeight; + w = ww - bw * 4; + h = wh - bw * 4 - TitleHeight; + if(sw->frame == NULL) { + sw->frame = MwCreateWidget(MwFrameClass, "frame", handle, x, y, w, h); + } else { + MwVaApply(sw->frame, + MwNx, x, + MwNy, y, + MwNwidth, w, + MwNheight, h, + NULL); + } + + p = (TitleHeight - ButtonSize) / 2; + x = ww - bw - p; + y = bw + p; + w = ButtonSize; + h = ButtonSize; + +#define BUTTON(name) \ + x -= ButtonSize; \ + if(sw->name == NULL) { \ + sw->name = MwCreateWidget(MwButtonClass, #name, handle, x, y, w, h); \ + sw->name->draw_inject = name##_draw; \ + MwAddUserHandler(sw->name, MwNactivateHandler, name##_activate, handle); \ + } else { \ + MwVaApply(sw->name, \ + MwNx, x, \ + MwNy, y, \ + MwNwidth, w, \ + MwNheight, h, \ + NULL); \ + } \ + x -= p; + + BUTTON(close); + BUTTON(maximize); + BUTTON(minimize); +} + +static int wcreate(MwWidget handle) { + MwSubWindow sw = malloc(sizeof(*sw)); + memset(sw, 0, sizeof(*sw)); + + sw->maximized = 0; + sw->minimized = 0; + handle->internal = sw; + + resize(handle); + + MwSetDefault(handle); + + return 0; +} + +static void destroy(MwWidget handle) { + free(handle->internal); +} + +static void draw(MwWidget handle) { + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor tb = MwParseColor(handle, MwGetText(handle, MwNtitleBackground)); + MwLLColor tf = MwParseColor(handle, MwGetText(handle, MwNtitleForeground)); + MwRect r, r2, r3; + const char* title = MwGetText(handle, MwNtitle); + int incr = 0; + MwLLPixmap px = MwGetVoid(handle, MwNiconPixmap); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawFrame(handle, &r, c, 0); + MwDrawRect(handle, &r, c); + + r2 = r; + r2.height = TitleHeight; + MwDrawRect(handle, &r2, tb); + + if(px != NULL) { + r3 = r2; + incr = (TitleHeight - ButtonSize) / 2; + + r3.x += incr; + r3.y += incr; + r3.width = ButtonSize; + r3.height = ButtonSize; + MwLLDrawPixmap(handle->lowlevel, &r3, px); + + incr += ButtonSize; + } + + if(title != NULL) { + MwPoint p; + p.x = r2.x + (TitleHeight - ButtonSize) / 2 + incr; + p.y = r2.y + TitleHeight / 2; + handle->bgcolor = tb; + MwDrawText(handle, NULL, &p, title, MwALIGNMENT_BEGINNING, tf); + handle->bgcolor = NULL; + } + + r2.width = ButtonSize * 3 + (TitleHeight - ButtonSize) / 2 * 4; + r2.x = r.width - r2.width; + MwDrawRect(handle, &r2, tb); + + r.y += TitleHeight; + r.height -= TitleHeight; + MwDrawFrame(handle, &r, c, 1); + + MwLLFreeColor(tf); + MwLLFreeColor(tb); + MwLLFreeColor(c); +} + +static void parent_resize(MwWidget handle) { + MwSubWindow sw = handle->internal; + + if(sw->maximized) { + MwVaApply(handle, + MwNwidth, MwGetInteger(handle->parent, MwNwidth), + MwNheight, MwGetInteger(handle->parent, MwNheight), + NULL); + } else if(sw->minimized) { + MwVaApply(handle, + MwNy, MwGetInteger(handle->parent, MwNheight) - TitleHeight - MwDefaultBorderWidth(handle), + NULL); + } +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNtitle) == 0 || strcmp(key, MwNiconPixmap) == 0) MwForceRender(handle); +} + +static MwWidget mwSubWindowGetFrameImpl(MwWidget handle) { + MwSubWindow sw = handle->internal; + + return sw->frame; +} + +static void mouse_down(MwWidget handle, void* ptr) { + MwSubWindow sw = handle->internal; + MwMouse* m = ptr; + + if(m->button == MwMOUSE_LEFT && !sw->minimized && !sw->maximized) { + MwGetCursorCoord(handle, &sw->cursor_start); + sw->base.x = MwGetInteger(handle, MwNx); + sw->base.y = MwGetInteger(handle, MwNy); + } + + MwLLRaise(handle->lowlevel); +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + (void)va; + + if(strcmp(name, "mwSubWindowGetFrame") == 0) { + *(MwWidget*)out = mwSubWindowGetFrameImpl(handle); + } +} + +static void tick(MwWidget handle) { + MwSubWindow sw = handle->internal; + + if(handle->pressed && !sw->minimized && !sw->maximized) { + MwPoint p; + + MwGetCursorCoord(handle, &p); + + MwVaApply(handle, + MwNx, sw->base.x + p.x - sw->cursor_start.x, + MwNy, sw->base.y + p.y - sw->cursor_start.y, + NULL); + } +} + +MwClassRec MwSubWindowClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + parent_resize, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + mouse_down, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + tick, /* tick */ + resize, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwSubWindowClass = &MwSubWindowClassRec; diff --git a/widget/milsko/milskosrc/src/widget/tab.c b/widget/milsko/milskosrc/src/widget/tab.c new file mode 100644 index 0000000000..e5d2a3eae9 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/tab.c @@ -0,0 +1,375 @@ +#include + +#include "../../external/stb_ds.h" + +static void resize(MwWidget handle); + +static int wcreate(MwWidget handle) { + MwTab t = malloc(sizeof(*t)); + memset(t, 0, sizeof(*t)); + + handle->internal = t; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNvalue, -1); + + return 0; +} + +static void destroy(MwWidget handle) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + free(t->names[i]); + } + + arrfree(t->names); + arrfree(t->frames); + + free(handle->internal); +} + +static int tab_width(MwWidget handle, const char* text) { + return MwTextWidth(handle, NULL, text) + 20; +} + +static int tab_height(MwWidget handle) { + return MwTextHeight(handle, NULL, "M") + 10; +} + +static int icon_width(MwWidget handle, const char* text) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + if(strcmp(t->names[i], text) == 0) { + MwLLPixmap px = MwGetVoid(t->frames[i], MwNiconPixmap); + + if(px == NULL) return 0; + + return px->common.width * tab_height(handle) / px->common.height; + } + } + + return 0; +} + +static void draw(MwWidget handle) { + MwTab t = handle->internal; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor ct = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwRect r, r2; + int h = tab_height(handle); + int i; + int n; + int x = 0; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawRect(handle, &r, c); + + for(n = 0; n < 2; n++) { + x = 0; + for(i = 0; i < arrlen(t->names); i++) { + int render = 0; + int iw = icon_width(handle, t->names[i]); + + if(i == MwGetInteger(handle, MwNvalue) && n == 1) { + r.y += h; + r.height -= h; + MwDrawFrame(handle, &r, c, 0); + + render = 1; + } else if(n == 0) { + render = 1; + } + + r2.x = x; + r2.y = 0; + r2.width = tab_width(handle, t->names[i]) + iw; + r2.height = tab_height(handle) + MwDefaultBorderWidth(handle); + + x += r2.width; + + if(iw > 0) { + MwLLPixmap px = MwGetVoid(t->frames[i], MwNiconPixmap); + MwRect rp; + + rp = r2; + + rp.x += 5; + rp.y += 5; + + rp.width = iw - 10; + rp.height = rp.height * (iw - 10) / iw; + + MwLLDrawPixmap(handle->lowlevel, &rp, px); + } + + if(render) { + MwPoint p; + + if(n == 1 && i > 0) { + MwRect r3 = r2; + + r3.y = tab_height(handle); + r3.width = r3.height = MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + + r3.x -= r3.width; + r3.y -= r3.height; + r3.width *= 2; + r3.height *= 2; + MwDrawFrame(handle, &r3, c, 1); + + MwLLClip(handle->lowlevel, NULL); + } else if(n == 1 && i == 0) { + MwRect r3 = r2; + + r3.y = tab_height(handle); + r3.width = r3.height = MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + + r3.x -= r3.width; + r3.y -= r3.height; + r3.width *= 2; + r3.height *= 3; + MwDrawFrame(handle, &r3, c, 1); + + MwLLClip(handle->lowlevel, NULL); + } + + if(n == 1 && i < (arrlen(t->names) - 1)) { + MwRect r3 = r2; + + r3.x += r2.width - MwDefaultBorderWidth(handle); + r3.y = tab_height(handle); + r3.width = r3.height = MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + + r3.y -= r3.height; + r3.width *= 2; + r3.height *= 2; + MwDrawFrame(handle, &r3, c, 1); + + MwLLClip(handle->lowlevel, NULL); + } + + if(n == 1) { + MwRect r3 = r2; + + r3.height -= MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + } + + MwDrawFrame(handle, &r2, c, 0); + + MwLLClip(handle->lowlevel, NULL); + + if(n == 1) { + MwRect r3 = r2; + + r3.y += r3.height; + r3.height = MwDefaultBorderWidth(handle); + + MwDrawRect(handle, &r3, c); + } + + p.x = r2.x + (r2.width + iw / 2) / 2; + p.y = r2.y + r2.height / 2; + MwDrawText(handle, NULL, &p, t->names[i], MwALIGNMENT_CENTER, ct); + } + } + } + + MwLLFreeColor(ct); + MwLLFreeColor(c); +} + +static void show_frame(MwWidget handle) { + resize(handle); + + MwForceRender(handle); + + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); +} + +static void click(MwWidget handle) { + MwTab t = handle->internal; + int i; + int x = 0; + int h = tab_height(handle); + + for(i = 0; i < arrlen(t->names); i++) { + int w = tab_width(handle, t->names[i]); + int iw = icon_width(handle, t->names[i]); + + w += iw; + + if(MwGetInteger(handle, MwNvalue) != i && x <= handle->mouse_point.x && handle->mouse_point.x <= (x + w) && 0 <= handle->mouse_point.y && handle->mouse_point.y <= h) { + MwSetInteger(handle, MwNvalue, i); + show_frame(handle); + } + + x += w; + } +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNvalue) == 0) { + show_frame(handle); + } +} + +static MwWidget mwTabAddImpl(MwWidget handle, const char* name) { + MwTab t = handle->internal; + MwWidget f = MwCreateWidget(MwFrameClass, "tabframe", handle, MwDefaultBorderWidth(handle), tab_height(handle) + MwDefaultBorderWidth(handle), MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) * 2, MwGetInteger(handle, MwNheight) - tab_height(handle) - MwDefaultBorderWidth(handle) * 2); + char* n = MwStringDuplicate(name); + + arrput(t->frames, f); + arrput(t->names, n); + + MwForceRender(handle); + + if(MwGetInteger(handle, MwNvalue) == -1) { + MwSetInteger(handle, MwNvalue, arrlen(t->frames) - 1); + show_frame(handle); + } else { + MwLLShow(f->lowlevel, 0); + } + + return f; +} + +static MwWidget mwTabGetFrameImpl(MwWidget handle, const char* name) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + if(strcmp(t->names[i], name) == 0) return t->frames[i]; + } + + return NULL; +} + +static void mwTabFocusImpl(MwWidget handle, const char* name) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + if(strcmp(t->names[i], name) == 0) { + MwSetInteger(handle, MwNvalue, i); + show_frame(handle); + break; + } + } +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwTabAdd") == 0) { + const char* name = va_arg(va, const char*); + + *(MwWidget*)out = mwTabAddImpl(handle, name); + } else if(strcmp(name, "mwTabGetFrame") == 0) { + const char* name = va_arg(va, const char*); + + *(MwWidget*)out = mwTabGetFrameImpl(handle, name); + } else if(strcmp(name, "mwTabFocus") == 0) { + const char* name = va_arg(va, const char*); + + mwTabFocusImpl(handle, name); + } +} + +static void resize(MwWidget handle) { + MwTab t = handle->internal; + int v = MwGetInteger(handle, MwNvalue); + int i; + + for(i = 0; i < arrlen(t->frames); i++) { + int y = MwGetInteger(handle, MwNheight); + + MwLLShow(t->frames[i]->lowlevel, i == v); + if(i == v) y = tab_height(handle) + MwDefaultBorderWidth(handle); + + MwVaApply(t->frames[i], + MwNx, MwDefaultBorderWidth(handle), + MwNy, y, + MwNwidth, MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) * 2, + MwNheight, MwGetInteger(handle, MwNheight) - tab_height(handle) - MwDefaultBorderWidth(handle) * 2, + NULL); + } +} + +static void children_update(MwWidget handle, MwWidget child, int new_child) { + MwTab t = handle->internal; + int v = MwGetInteger(handle, MwNvalue); + int n; + int i; + + if(new_child) return; + + for(i = 0; i < arrlen(t->frames); i++) { + if(t->frames[i] == child) { + n = i; + break; + } + } + + free(t->names[n]); + + arrdel(t->frames, n); + arrdel(t->names, n); + + if(n <= v) { + if(v > 0) v--; + + MwSetInteger(handle, MwNvalue, v); + show_frame(handle); + } else { + MwSetInteger(handle, MwNvalue, v); + show_frame(handle); + } + + MwForceRender(handle); +} + +static void children_prop_change(MwWidget handle, MwWidget child, const char* key) { + (void)child; + + if(strcmp(key, MwNiconPixmap) == 0) { + MwForceRender(handle); + } +} + +MwClassRec MwTabClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + click, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + resize, /* resize */ + children_update, /* children_update */ + children_prop_change, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwTabClass = &MwTabClassRec; diff --git a/widget/milsko/milskosrc/src/widget/table.c b/widget/milsko/milskosrc/src/widget/table.c new file mode 100644 index 0000000000..788d5cc811 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/table.c @@ -0,0 +1,227 @@ +#include + +#include "../../external/stb_ds.h" + +static int wcreate(MwWidget handle) { + MwTable t = malloc(sizeof(*t)); + memset(t, 0, sizeof(*t)); + + handle->internal = t; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNcolumns, 1); + MwSetInteger(handle, MwNmargin, 0); + MwSetInteger(handle, MwNpadding, 0); + MwSetInteger(handle, MwNhasBorder, 0); + MwSetInteger(handle, MwNinverted, 1); + MwSetInteger(handle, MwNwaitLayout, 0); + + t->layout = 0; + + return 0; +} + +static void destroy(MwWidget handle) { + MwTable t = handle->internal; + + arrfree(t->widgets); + + free(t); +} + +typedef struct intkv { + int key; + int value; +} intkv_t; + +static void put_intkv(intkv_t** kv, int x, int y, int c, int r) { + int k = (x << 16) | y; + int v = (c << 16) | r; + + hmput(*kv, k, v); +} + +static int get_intkv(intkv_t* kv, int x, int y) { + int k = (x << 16) | y; + + return hmget(kv, k); +} + +#define LAYOUT_BEGIN \ + hmfree(kv); \ + hmdefault(kv, 0); \ + n = 0; \ + x = bw; \ + y = bw; \ + for(i = 0; i < arrlen(handle->children); i++) { \ + MwRect rc; \ + MwWidget hc = handle->children[i]; \ + int cs = MwGetInteger(hc, MwNcolumnSpan); \ + int rs = MwGetInteger(hc, MwNrowSpan); \ + int w, h; \ + int cy; \ + int s = MwGetInteger(handle, MwNmargin); \ + int v = n; \ +\ + if(cs == MwDEFAULT) cs = 1; \ + if(rs == MwDEFAULT) rs = 1; \ +\ + w = cs * cw + (cs - 1) * s; \ + h = rs * ch + (rs - 1) * s; \ +\ + MwGetFrame(hc, &rc); \ +\ + if(hc == child || rc.x != x || rc.y != y || rc.width != w || rc.height != h) { + +#define LAYOUT_END(label) \ + } \ +\ + put_intkv(&kv, n % c, n / c, cs, rs); \ +\ + n += cs; \ + repeat_##label :; \ + if((n % c) == 0) { \ + x = bw; \ + y += ch + s; \ + } else { \ + for(; v < n; v++) { \ + x += cw + s; \ + } \ + } \ +\ + for(cy = (n / c); cy >= 0; cy--) { \ + int v = get_intkv(kv, n % c, cy) & 0xffff; \ +\ + if(cy <= (n / c) && (n / c) <= (cy + v - 1)) { \ + v = n; \ + n += get_intkv(kv, n % c, cy) >> 16; \ + goto repeat_##label; \ + } \ + } \ + } + +static void layout_widget(MwWidget handle, MwWidget child) { + int i; + int c = MwGetInteger(handle, MwNcolumns); + int bw = (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0) + MwGetInteger(handle, MwNpadding); + int m = MwGetInteger(handle, MwNmargin); + int n, x, y, cw = 0, ch = 0; + int gcs; + intkv_t* kv = NULL; + + LAYOUT_BEGIN; + LAYOUT_END(1); + + gcs = (n + c - 1) / c; + cw = (MwGetInteger(handle, MwNwidth) - bw * 2 - (m * (c - 1))) / c; + ch = (MwGetInteger(handle, MwNheight) - m * (gcs - 1) - bw * 2) / gcs; + + LAYOUT_BEGIN; + MwVaApply(hc, + MwNx, x, + MwNy, y, + MwNwidth, w, + MwNheight, h, + NULL); + LAYOUT_END(2); + + hmfree(kv); +} + +static void layout(MwWidget handle) { + MwTable t = handle->internal; + int i; + + if(arrlen(t->widgets) > 0) { + for(i = 0; i < arrlen(t->widgets); i++) layout_widget(handle, t->widgets[i]); + } else { + for(i = 0; i < arrlen(handle->children[i]); i++) layout_widget(handle, handle->children[i]); + } +} + +static void draw(MwWidget handle) { + MwBoxClass->draw(handle); +} + +static void tick(MwWidget handle) { + MwTable t = handle->internal; + + if(t->layout && !MwGetInteger(handle, MwNwaitLayout)) { + layout(handle); + + t->layout = 0; + } +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNcolumns) == 0 || strcmp(key, MwNhasBorder) == 0 || strcmp(key, MwNinverted) == 0 || strcmp(key, MwNpadding) == 0 || strcmp(key, MwNmargin) == 0) { + MwTable t = handle->internal; + t->layout = 1; + + MwForceRender(handle); + } +} + +static void resize(MwWidget handle) { + MwTable t = handle->internal; + t->layout = 1; + + MwForceRender(handle); +} + +static void children_update(MwWidget handle, MwWidget child, int new_child) { + MwTable t = handle->internal; + t->layout = 1; + + if(new_child) { + arrput(t->widgets, child); + } else { + int i; + + for(i = 0; i < arrlen(t->widgets); i++) { + if(t->widgets[i] == child) { + arrdel(t->widgets, i); + i = -1; + } + } + } + + MwForceRender(handle); +} + +static void children_prop_change(MwWidget handle, MwWidget child, const char* key) { + (void)child; + + if(strcmp(key, MwNcolumnSpan) == 0 || strcmp(key, MwNrowSpan) == 0) { + MwTable t = handle->internal; + t->layout = 1; + + arrput(t->widgets, child); + + MwForceRender(handle); + } +} + +MwClassRec MwTableClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + tick, /* tick */ + resize, /* resize */ + children_update, /* children_update */ + children_prop_change, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwTableClass = &MwTableClassRec; diff --git a/widget/milsko/milskosrc/src/widget/treeview.c b/widget/milsko/milskosrc/src/widget/treeview.c new file mode 100644 index 0000000000..3fba309e53 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/treeview.c @@ -0,0 +1,526 @@ +#include + +#include "../../external/stb_ds.h" + +#define OpenerSize 11 +#define LineSpace 16 +#define LinePadding 4 + +#define Font MwFLBuildFont(MwFLFlagMonospace) + +static void MWAPI vscroll_changed(MwWidget handle, void* user, void* call) { + MwTreeView tv = handle->parent->internal; + + (void)user; + (void)call; + + tv->changed = 1; +} + +static void set_all(MwTreeViewEntry** root, int v) { + int i; + for(i = 0; i < arrlen(root); i++) { + root[i]->selected = v; + set_all(root[i]->tree, v); + } +} + +static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** root, MwLLColor base, MwLLColor text, MwLLColor base2, MwLLColor text2, MwPoint* p, int next, int shift, int* skip, int* shared, int draw, MwPoint* mouse) { + int i; + MwPoint l[2]; + int skipped = 0; + if((*skip) > 0) { + (*skip)--; + skipped = 1; + if(p->y == MwDefaultBorderWidth(handle)) p->y -= MwTextHeight(handle, Font, "M"); + } else if((*shared) < (MwGetInteger(handle, MwNheight) / MwTextHeight(handle, Font, "M") + 2)) { + MwRect r; + p->x += shift; + p->y += MwTextHeight(handle, Font, "M") / 2 + LinePadding; + + if(tree->tree != NULL || shift > LineSpace) { + l[0] = *p; + l[0].x -= LineSpace / 2; + l[1] = *p; + if(draw) MwLLLine(handle->lowlevel, &l[0], text2); + } + + if(shift > LineSpace) { + l[0] = *p; + l[0].x -= LineSpace / 2; + l[1] = l[0]; + l[0].y -= MwTextHeight(handle, Font, "M") / 2 + LinePadding; + if(next) { + l[1].y += MwTextHeight(handle, Font, "M") / 2; + } + if(draw) MwLLLine(handle->lowlevel, &l[0], text2); + } + if(tree->tree != NULL) { + r.width = OpenerSize; + r.height = OpenerSize; + r.x = p->x - LineSpace + (LineSpace - r.width) / 2; + r.y = p->y - MwTextHeight(handle, Font, "M") / 2 + (MwTextHeight(handle, Font, "M") - r.height) / 2; + if(draw) { + MwLLColor col = tree->opened ? MwLightenColor(handle, base, -8, -8, -8) : base; + MwRect r2 = r; + const int len = 4; + + MwDrawRect(handle, &r, col); + MwDrawFrame(handle, &r, base, tree->opened); + if(tree->opened) { + l[0].x = r.x + (r.width - 1 - len) / 2; + l[0].y = r.y + r.height / 2; + + l[1].x = l[0].x + len; + l[1].y = l[0].y; + + MwLLLine(handle->lowlevel, &l[0], text); + } else { + l[0].x = r.x + (r.width - len) / 2; + l[0].y = r.y + r.height / 2; + + l[1].x = l[0].x + len; + l[1].y = l[0].y; + + MwLLLine(handle->lowlevel, &l[0], text); + + l[0].x = r.x + r.width / 2; + l[0].y = r.y + (r.height - len) / 2; + + l[1].x = l[0].x; + l[1].y = l[0].y + len; + + MwLLLine(handle->lowlevel, &l[0], text); + } + r = r2; + MwDrawFrame(handle, &r, base, tree->opened); + + if(col != base) MwLLFreeColor(col); + } else { + if(r.x <= mouse->x && mouse->x <= (r.x + r.width) && r.y <= mouse->y && mouse->y <= (r.y + r.height)) { + tree->opened = tree->opened ? 0 : 1; + } + } + } + if(tree->pixmap != NULL) { + r.height = MwTextHeight(handle, Font, "M"); + r.width = r.height * tree->pixmap->common.width / tree->pixmap->common.height; + + r.x = p->x + (MwGetInteger(handle->parent, MwNleftPadding) - r.width) / 2; + r.y = p->y - MwTextHeight(handle, Font, "M") / 2; + + if(draw) MwLLDrawPixmap(handle->lowlevel, &r, tree->pixmap); + } + p->x += MwGetInteger(handle->parent, MwNleftPadding); + if(draw) { + if(tree->selected) { + r.x = p->x; + r.y = p->y - MwTextHeight(handle, Font, "M") / 2; + r.width = MwGetInteger(handle, MwNwidth) - MwGetInteger(handle->parent, MwNleftPadding) - shift; + r.height = MwTextHeight(handle, Font, "M"); + MwDrawRect(handle, &r, text2); + } + handle->bgcolor = tree->selected ? text2 : base2; + MwDrawText(handle, Font, p, tree->label, MwALIGNMENT_BEGINNING, tree->selected ? base2 : text2); + handle->bgcolor = NULL; + } else { + if(p->x <= mouse->x && mouse->x <= (p->x + MwTextWidth(handle, Font, tree->label)) && (p->y - MwTextHeight(handle, Font, "M") / 2) <= mouse->y && mouse->y <= (p->y + MwTextHeight(handle, Font, "M") / 2)) { + unsigned long t; + + set_all(root, 0); + tree->selected = 1; + if(((t = MwTimeGetTick()) - tree->click_time) < MwDoubleClickTimeout || MwGetInteger(handle->parent, MwNsingleClickSelectable)) { + MwDispatchUserHandler(handle->parent, MwNtreeViewActivateHandler, tree); + } + + tree->click_time = t; + } + } + p->x -= MwGetInteger(handle->parent, MwNleftPadding); + + p->y += MwTextHeight(handle, Font, "M") / 2; + p->x -= shift; + + (*shared)++; + } + if(!tree->opened) return; + for(i = 0; i < arrlen(tree->tree); i++) { + l[0] = *p; + l[0].x += shift + LineSpace / 2; + l[0].y += MwTextHeight(handle, Font, "M") - (MwTextHeight(handle, Font, "M") - OpenerSize) / 2; + if(tree->tree[i]->tree != NULL) { + l[0].y += OpenerSize / 2; + } + + recursion(handle, tree->tree[i], root, base, text, base2, text2, p, i != (arrlen(tree->tree) - 1) ? 1 : 0, shift + LineSpace, skip, shared, draw, mouse); + + l[1] = *p; + l[1].x += shift + LineSpace / 2; + + if(skipped && p->y > l[0].y) { + skipped = 0; + } + if(draw && !skipped && i != (arrlen(tree->tree) - 1)) MwLLLine(handle->lowlevel, &l[0], text); + } +} + +static void frame_draw(MwWidget handle) { + MwRect r, r2; + MwTreeView tv = handle->parent->internal; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor base2 = MwParseColor(handle, MwGetText(handle, MwNsubBackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor text2 = MwParseColor(handle, MwGetText(handle, MwNsubForeground)); + MwPoint p; + int shared = 0; + int i; + int skip = MwGetInteger(tv->vscroll, MwNvalue) * (MwGetInteger(tv->vscroll, MwNmaxValue) - MwGetInteger(tv->vscroll, MwNareaShown)) / MwGetInteger(tv->vscroll, MwNmaxValue); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + r2 = r; + + p.x = MwDefaultBorderWidth(handle); + p.y = MwDefaultBorderWidth(handle); + + MwDrawFrame(handle, &r, base, 1); + MwDrawRect(handle, &r, base2); + + r = r2; + + for(i = 0; i < arrlen(tv->tree); i++) { + if(shared > (r.height / MwTextHeight(handle, Font, "M"))) break; + recursion(handle, tv->tree[i], tv->tree, base, text, base2, text2, &p, 0, LineSpace, &skip, &shared, 1, NULL); + } + + MwDrawFrame(handle, &r, base, 1); + + MwLLFreeColor(text2); + MwLLFreeColor(text); + MwLLFreeColor(base2); + MwLLFreeColor(base); +} + +static int recursive_length(MwTreeViewEntry** e) { + int l = 0; + int i; + for(i = 0; i < arrlen(e); i++) { + if(e[i]->opened && e[i]->tree != NULL) l += recursive_length(e[i]->tree); + l++; + } + return l; +} + +static void MWAPI frame_mouse_down(MwWidget handle, void* user, void* call) { + MwTreeView tv = handle->parent->internal; + MwMouse* mouse = call; + + (void)user; + + if(mouse->button == MwMOUSE_LEFT) tv->pressed = mouse->point; +} + +static void resize(MwWidget handle, int no_resize); + +static void MWAPI frame_mouse_up(MwWidget handle, void* user, void* call) { + MwTreeView tv = handle->parent->internal; + int shared = 0; + int skip = MwGetInteger(tv->vscroll, MwNvalue) * (MwGetInteger(tv->vscroll, MwNmaxValue) - MwGetInteger(tv->vscroll, MwNareaShown)) / MwGetInteger(tv->vscroll, MwNmaxValue); + MwPoint p; + MwMouse* mouse = call; + + (void)user; + + if(mouse->button == MwMOUSE_LEFT) { + int i; + p.x = MwDefaultBorderWidth(tv->frame); + p.y = MwDefaultBorderWidth(tv->frame); + for(i = 0; i < arrlen(tv->tree); i++) { + if(shared > (MwGetInteger(tv->frame, MwNheight) / MwTextHeight(tv->frame, Font, "M"))) break; + recursion(tv->frame, tv->tree[i], tv->tree, NULL, NULL, NULL, NULL, &p, 0, LineSpace, &skip, &shared, 0, &tv->pressed); + } + resize(handle->parent, 1); + MwForceRender(tv->frame); + } +} + +static void resize(MwWidget handle, int no_resize) { + MwTreeView tv = handle->internal; + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + int ih = 0; + int m = 0; + + if(tv->vscroll == NULL) { + tv->vscroll = MwCreateWidget(MwScrollBarClass, "vscroll", handle, w - 16, 0, 16, h); + MwAddUserHandler(tv->vscroll, MwNchangedHandler, vscroll_changed, NULL); + MwSetInteger(tv->vscroll, MwNvalue, 5); + } else if(!no_resize) { + MwVaApply(tv->vscroll, + MwNx, w - 16, + MwNy, 0, + MwNwidth, 16, + MwNheight, h, + NULL); + } + + ih = recursive_length(tv->tree); + if(ih == 0) ih = 1; + + if(ih <= (h / (LinePadding + MwTextHeight(handle, Font, "M")))) { + MwLLShow(tv->vscroll->lowlevel, 0); + } else { + MwLLShow(tv->vscroll->lowlevel, 1); + m = 16; + } + + if(tv->frame == NULL) { + tv->frame = MwVaCreateWidget(MwFrameClass, "frame", handle, 0, 0, w - m, h, + MwNhasBorder, 1, + MwNinverted, 1, + NULL); + tv->frame->draw_inject = frame_draw; + MwAddUserHandler(tv->frame, MwNmouseDownHandler, frame_mouse_down, NULL); + MwAddUserHandler(tv->frame, MwNmouseUpHandler, frame_mouse_up, NULL); + } else if(!no_resize || MwGetInteger(tv->frame, MwNwidth) != (w - m)) { + MwVaApply(tv->frame, + MwNx, 0, + MwNy, 0, + MwNwidth, w - m, + MwNheight, h, + NULL); + } + + MwVaApply(tv->vscroll, + MwNareaShown, h / (LinePadding + MwTextHeight(handle, Font, "M")), + MwNmaxValue, ih, + NULL); +} + +static int wcreate(MwWidget handle) { + MwTreeView tv = malloc(sizeof(*tv)); + memset(tv, 0, sizeof(*tv)); + + handle->internal = tv; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNsingleClickSelectable, 0); + MwSetInteger(handle, MwNleftPadding, 0); + + resize(handle, 0); + tv->changed = 0; + + return 0; +} + +static void destroy(MwWidget handle) { + free(handle->internal); +} + +static void draw(MwWidget handle) { + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwRect r; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, c); + + MwLLFreeColor(c); +} + +static void* mwTreeViewAddImpl(MwWidget handle, void* parent, MwLLPixmap pixmap, const char* item) { + MwTreeView tv = handle->internal; + MwTreeViewEntry* t = malloc(sizeof(*t)); + + t->label = MwStringDuplicate(item); + t->pixmap = pixmap; + t->selected = 0; + t->opened = 1; + t->click_time = 0; + t->tree = NULL; + t->parent = parent; + + if(parent == NULL) { + arrput(tv->tree, t); + } else { + MwTreeViewEntry* e = parent; + + arrput(e->tree, t); + } + resize(handle, 1); + MwForceRender(tv->frame); + + return t; +} + +static void free_all(MwTreeViewEntry** tree) { + int i; + for(i = 0; i < arrlen(tree); i++) { + free(tree[i]->label); + free_all(tree[i]->tree); + free(tree[i]); + } + arrfree(tree); +} + +static void mwTreeViewDeleteImpl(MwWidget handle, void* item) { + MwTreeView tv = handle->internal; + MwTreeViewEntry* e = item; + MwTreeViewEntry* p = e->parent; + + (void)handle; + + free_all(p->tree); + p->tree = NULL; + resize(handle, 1); + MwForceRender(tv->frame); +} + +static void mwTreeViewResetImpl(MwWidget handle) { + MwTreeView tv = handle->internal; + + free_all(tv->tree); + tv->tree = NULL; + resize(handle, 1); + MwForceRender(tv->frame); +} + +static const char* mwTreeViewGetImpl(MwWidget handle, void* item) { + MwTreeViewEntry* e = item; + + (void)handle; + + return e->label; +} + +static void mwTreeViewSetLabelImpl(MwWidget handle, void* item, const char* label) { + MwTreeView tv = handle->internal; + MwTreeViewEntry* e = item; + + free(e->label); + e->label = MwStringDuplicate(label); + + if(e->parent == NULL || (e->parent != NULL && e->parent->opened)) { + resize(handle, 1); + MwForceRender(tv->frame); + } +} + +static void mwTreeViewSetPixmapImpl(MwWidget handle, void* item, MwLLPixmap pixmap) { + MwTreeView tv = handle->internal; + MwTreeViewEntry* e = item; + + e->pixmap = pixmap; + + if(e->parent == NULL || (e->parent != NULL && e->parent->opened)) { + resize(handle, 1); + MwForceRender(tv->frame); + } +} + +static void mwTreeViewSetOpenedImpl(MwWidget handle, void* item, int opened) { + MwTreeView tv = handle->internal; + MwTreeViewEntry* e = item; + + e->opened = opened; + + if(e->parent == NULL || (e->parent != NULL && e->parent->opened)) { + resize(handle, 1); + MwForceRender(tv->frame); + } +} + +static int mwTreeViewGetOpenedImpl(MwWidget handle, void* item) { + MwTreeViewEntry* e = item; + + (void)handle; + + return e->opened; +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwTreeViewAdd") == 0) { + void* parent = va_arg(va, void*); + MwLLPixmap pixmap = va_arg(va, MwLLPixmap); + const char* item = va_arg(va, const char*); + *(void**)out = mwTreeViewAddImpl(handle, parent, pixmap, item); + } + if(strcmp(name, "mwTreeViewDelete") == 0) { + void* item = va_arg(va, void*); + mwTreeViewDeleteImpl(handle, item); + } + if(strcmp(name, "mwTreeViewReset") == 0) { + mwTreeViewResetImpl(handle); + } + if(strcmp(name, "mwTreeViewGet") == 0) { + void* item = va_arg(va, void*); + *(const char**)out = mwTreeViewGetImpl(handle, item); + } + if(strcmp(name, "mwTreeViewSetLabel") == 0) { + void* item = va_arg(va, void*); + const char* label = va_arg(va, const char*); + mwTreeViewSetLabelImpl(handle, item, label); + } + if(strcmp(name, "mwTreeViewSetPixmap") == 0) { + void* item = va_arg(va, void*); + MwLLPixmap pixmap = va_arg(va, MwLLPixmap); + mwTreeViewSetPixmapImpl(handle, item, pixmap); + } + if(strcmp(name, "mwTreeViewSetOpened") == 0) { + void* item = va_arg(va, void*); + int opened = va_arg(va, int); + mwTreeViewSetOpenedImpl(handle, item, opened); + } + if(strcmp(name, "mwTreeViewGetOpened") == 0) { + void* item = va_arg(va, void*); + *(int*)out = mwTreeViewGetOpenedImpl(handle, item); + } +} + +static void tick(MwWidget handle) { + MwTreeView tv = handle->internal; + + if(tv->changed) { + tv->changed = 0; + MwForceRender(tv->frame); + } +} + +static void props_change(MwWidget handle, char** props) { + int i; + int rsz = 0; + + for(i = 0; props[i] != NULL; i++) { + if(strcmp(props[i], MwNwidth) == 0 || strcmp(props[i], MwNheight) == 0) rsz = 1; + } + + if(rsz) resize(handle, 0); +} + +MwClassRec MwTreeViewClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + tick, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + props_change, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwTreeViewClass = &MwTreeViewClassRec; diff --git a/widget/milsko/milskosrc/src/widget/viewport.c b/widget/milsko/milskosrc/src/widget/viewport.c new file mode 100644 index 0000000000..2541b65d23 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/viewport.c @@ -0,0 +1,199 @@ +#include + +static void MWAPI vscroll_changed(MwWidget handle, void* user, void* call) { + MwViewport vp = user; + + (void)handle; + (void)call; + + vp->vchanged = 1; +} + +static void MWAPI hscroll_changed(MwWidget handle, void* user, void* call) { + MwViewport vp = user; + + (void)handle; + (void)call; + + vp->hchanged = 1; +} + +static void resize(MwWidget handle) { + MwViewport vp = handle->internal; + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + int iw; + int ih; + if(vp->vscroll == NULL) { + vp->vscroll = MwVaCreateWidget(MwScrollBarClass, "vscroll", handle, w - 16, 0, 16, h - 16, NULL); + MwAddUserHandler(vp->vscroll, MwNchangedHandler, vscroll_changed, vp); + } else { + MwVaApply(vp->vscroll, + MwNx, w - 16, + MwNy, 0, + MwNwidth, 16, + MwNheight, h - 16, + NULL); + } + if(vp->hscroll == NULL) { + vp->hscroll = MwVaCreateWidget(MwScrollBarClass, "hscroll", handle, 0, h - 16, w - 16, 16, MwNorientation, MwHORIZONTAL, NULL); + MwAddUserHandler(vp->hscroll, MwNchangedHandler, hscroll_changed, vp); + } else { + MwVaApply(vp->hscroll, + MwNx, 0, + MwNy, h - 16, + MwNwidth, w - 16, + MwNheight, 16, + NULL); + } + if(vp->frame == NULL) { + vp->frame = MwCreateWidget(MwFrameClass, "frame", handle, 0, 0, w - 16, h - 16); + } else { + MwVaApply(vp->frame, + MwNx, 0, + MwNy, 0, + MwNwidth, w - 16, + MwNheight, h - 16, + NULL); + } + if(vp->inframe == NULL) { + vp->inframe = MwCreateWidget(MwFrameClass, "inframe", vp->frame, 0, 0, w - 16, h - 16); + } + + iw = MwGetInteger(vp->inframe, MwNwidth); + ih = MwGetInteger(vp->inframe, MwNheight); + + MwVaApply(vp->vscroll, + MwNareaShown, h - 16, + MwNmaxValue, ih, + NULL); + + MwVaApply(vp->hscroll, + MwNareaShown, w - 16, + MwNmaxValue, iw, + NULL); +} + +static int wcreate(MwWidget handle) { + MwViewport vp = malloc(sizeof(*vp)); + memset(vp, 0, sizeof(*vp)); + + handle->internal = vp; + + MwSetDefault(handle); + + vp->vchanged = 0; + vp->hchanged = 0; + + resize(handle); + + return 0; +} + +static void destroy(MwWidget handle) { + free(handle->internal); +} + +static void draw(MwWidget handle) { + MwRect r; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawRect(handle, &r, base); + + MwLLFreeColor(base); +} + +static void prop_change(MwWidget handle, const char* prop) { + if(strcmp(prop, MwNwidth) == 0 || strcmp(prop, MwNheight) == 0) resize(handle); +} + +static MwWidget mwViewportGetViewportImpl(MwWidget handle) { + MwViewport vp = handle->internal; + + return vp->inframe; +} + +static void mwViewportSetSizeImpl(MwWidget handle, int w, int h) { + MwViewport vp = handle->internal; + + MwVaApply(vp->inframe, + MwNwidth, w, + MwNheight, h, + NULL); + + resize(handle); +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwViewportGetViewport") == 0) { + *(MwWidget*)out = mwViewportGetViewportImpl(handle); + } + if(strcmp(name, "mwViewportSetSize") == 0) { + int w = va_arg(va, int); + int h = va_arg(va, int); + mwViewportSetSizeImpl(handle, w, h); + } +} + +static void tick(MwWidget handle) { + MwViewport vp = handle->internal; + + if(vp->vchanged) { + int v, mv, l; + + vp->vchanged = 0; + + v = MwGetInteger(vp->vscroll, MwNvalue); + mv = MwGetInteger(vp->vscroll, MwNmaxValue); + l = MwGetInteger(vp->frame, MwNheight); + v = (mv - l) * (double)v / mv; + + if(v < 0) v = 0; + MwVaApply(vp->inframe, + MwNy, -v, + NULL); + } + if(vp->hchanged) { + int v, mv, l; + + vp->vchanged = 0; + + v = MwGetInteger(vp->hscroll, MwNvalue); + mv = MwGetInteger(vp->hscroll, MwNmaxValue); + l = MwGetInteger(vp->frame, MwNwidth); + v = (mv - l) * (double)v / mv; + + if(v < 0) v = 0; + MwVaApply(vp->inframe, + MwNx, -v, + NULL); + } +} + +MwClassRec MwViewportClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + tick, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwViewportClass = &MwViewportClassRec; diff --git a/widget/milsko/milskosrc/src/widget/vulkan.c b/widget/milsko/milskosrc/src/widget/vulkan.c new file mode 100644 index 0000000000..f4c5340298 --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/vulkan.c @@ -0,0 +1,612 @@ +#include + +/** + * ioixd maintains this file. nishi doesn't know vulkan at all + */ + +#ifndef MW_VULKAN +#define MW_VULKAN_NO_INCLUDE +#endif +#include + +#ifdef MW_VULKAN +#ifdef USE_GDI +#define VK_USE_PLATFORM_WIN32_KHR 1 +#endif +#ifdef USE_X11 +#define VK_USE_PLATFORM_XLIB_KHR 1 +#endif +#ifdef USE_WAYLAND +#define VK_USE_PLATFORM_WAYLAND_KHR 1 +#endif +#include +#include + +#ifdef USE_GDI +#include +#endif +#ifdef USE_X11 +#include +#endif +#ifdef USE_WAYLAND +#include +#endif +#ifdef USE_COCOA +#include +#endif + +#ifdef HAS_VK_ENUM_STRING_HELPER +#include +#endif + +#include +#include + +#include "../../external/stb_ds.h" + +/* convienence macro for handling vulkan errors */ +#ifdef HAS_VK_ENUM_STRING_HELPER +#define VK_CMD(func) \ + vk_res = func; \ + if(vk_res != VK_SUCCESS) { \ + char buf[1024]; \ + MwStringPrintIntoBuffer(buf, 1024, "Vulkan error (%s:%d): %s\n", __FILE__, __LINE__, string_VkResult(vk_res)); \ + MwDispatchError(1, buf); \ + return 1; \ + } +#else +#define VK_CMD(func) \ + vk_res = func; \ + if(vk_res != VK_SUCCESS) { \ + char buf[1024]; \ + MwStringPrintIntoBuffer(buf, 1024, "Vulkan error (%s:%d): (error %d)\n", __FILE__, __LINE__, vk_res); \ + MwDispatchError(1, buf); \ + return 1; \ + } +#endif + +/* convienence macro for loading a vulkan function pointer into memory */ +#define LOAD_VK_FUNCTION(name) \ + PFN_##name _##name = (PFN_##name)o->vkGetInstanceProcAddr(o->vkInstance, #name); \ + VK_ASSERT(_##name); + +/* convienence macro to return an error if an assert goes wrong */ +#define VK_ASSERT(val) \ + if(!val) { \ + char buf[1024]; \ + MwStringPrintIntoBuffer(buf, 1024, "Vulkan error (%s:%d): Assertion Failed (%s != NULL)\n", __FILE__, __LINE__, #val); \ + MwDispatchError(1, buf); \ + return 1; \ + } + +typedef enum vulkan_supported_state_t { + VULKAN_SUPPORTED_UNKNOWN, + VULKAN_SUPPORTED_YES, + VULKAN_SUPPORTED_NO, +} vulkan_supported_state; + +vulkan_supported_state vulkan_supported = VULKAN_SUPPORTED_UNKNOWN; + +typedef struct vulkan { + void* vulkanLibrary; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + VkInstance vkInstance; + VkSurfaceKHR vkSurface; + + MwVulkanConfig vulkan_config; + + VkPhysicalDevice vkPhysicalDevice; + VkDevice vkLogicalDevice; + VkQueue vkGraphicsQueue; + VkQueue vkPresentQueue; + uint32_t vkGraphicsFamilyIDX; + uint32_t vkPresentFamilyIDX; + + const char** vkInstanceExtensions; + const char** vkDeviceExtensions; + const char** vkLayers; + int vkInstanceExtensionCount; + int vkDeviceExtensionCount; + int vkLayerCount; + + const char** enabledExtensions; + const char** enabledLayers; + +} vulkan_t; + +static int vulkan_instance_setup(MwWidget handle, vulkan_t* o); +static int vulkan_surface_setup(MwWidget handle, vulkan_t* o); +static int vulkan_devices_setup(MwWidget handle, vulkan_t* o); + +static int wcreate(MwWidget handle) { + int err; + if(!handle->internal) { + vulkan_t* o; + handle->internal = malloc(sizeof(vulkan_t)); + memset(handle->internal, 0, sizeof(vulkan_t)); + + o = handle->internal; + o->vulkan_config.api_version = VK_API_VERSION_1_0; + o->vulkan_config.vk_version = VK_VERSION_1_0; + o->vulkan_config.validation_layers = VK_FALSE; + } + + err = vulkan_instance_setup(handle, handle->internal); + if(err != 0) { + return 1; + } + err = vulkan_surface_setup(handle, handle->internal); + if(err != 0) { + return 1; + } + err = vulkan_devices_setup(handle, handle->internal); + if(err != 0) { + return 1; + } + + handle->lowlevel->common.copy_buffer = 0; + + MwSetDefault(handle); + + return 0; +} + +static int _destroy(MwWidget handle) { + vulkan_t* o = (vulkan_t*)handle->internal; + + LOAD_VK_FUNCTION(vkDestroyInstance); + LOAD_VK_FUNCTION(vkDestroySurfaceKHR); + LOAD_VK_FUNCTION(vkDestroyDevice); + + free(o->vkLayers); + free(o->vkDeviceExtensions); + free(o->vkInstanceExtensions); + _vkDestroyDevice(o->vkLogicalDevice, NULL); + _vkDestroySurfaceKHR(o->vkInstance, o->vkSurface, NULL); + _vkDestroyInstance(o->vkInstance, NULL); + MwDynamicClose(o->vulkanLibrary); + + free(o); + + return 0; +} + +static void destroy(MwWidget handle) { + int err = _destroy(handle); + + (void)err; +} + +static void* vulkan_lib_load() { +#ifdef _WIN32 + return MwDynamicOpen("vulkan-1.dll"); +#elif defined(__APPLE__) + return MwDynamicOpen("libvulkan.dylib"); +#else + return MwDynamicOpen("libvulkan.so"); +#endif +} + +static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { + uint32_t vulkan_version = o->vulkan_config.vk_version; + uint32_t api_version = o->vulkan_config.api_version; + uint32_t extension_count = 0; + uint32_t layer_count = 0; + unsigned long i = 0; + unsigned long n = 0; + + PFN_vkEnumerateInstanceExtensionProperties + _vkEnumerateInstanceExtensionProperties; + PFN_vkEnumerateInstanceLayerProperties _vkEnumerateInstanceLayerProperties; + PFN_vkCreateInstance _vkCreateInstance; + + VkApplicationInfo app_info; + VkInstanceCreateInfo instance_create_info; + + VkExtensionProperties* ext_props; + VkLayerProperties* layer_props; + + VkResult vk_res; + + /* Load Vulkan and any other function pointers we need. */ + o->vulkanLibrary = vulkan_lib_load(); + if(!o->vulkanLibrary) { + vulkan_supported = VULKAN_SUPPORTED_NO; + MwDispatchError(1, "Vulkan not found."); + } else { + vulkan_supported = VULKAN_SUPPORTED_YES; + } + + o->vkGetInstanceProcAddr = MwDynamicSymbol(o->vulkanLibrary, "vkGetInstanceProcAddr"); + VK_ASSERT(o->vkGetInstanceProcAddr); + _vkEnumerateInstanceExtensionProperties = MwDynamicSymbol(o->vulkanLibrary, "vkEnumerateInstanceExtensionProperties"); + VK_ASSERT(_vkEnumerateInstanceExtensionProperties); + _vkEnumerateInstanceLayerProperties = MwDynamicSymbol(o->vulkanLibrary, "vkEnumerateInstanceLayerProperties"); + VK_ASSERT(_vkEnumerateInstanceLayerProperties); + _vkCreateInstance = MwDynamicSymbol(o->vulkanLibrary, "vkCreateInstance"); + VK_ASSERT(_vkCreateInstance); + + /* setup enabled extensions */ + arrput(o->enabledExtensions, VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef USE_GDI + if(handle->lowlevel->common.type == MwLLBackendGDI) { + arrput(o->enabledExtensions, VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + } +#endif +#ifdef USE_X11 + if(handle->lowlevel->common.type == MwLLBackendX11) { + arrput(o->enabledExtensions, VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + } +#endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + arrput(o->enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); + /* take this opprutunity to set the widget to always render */ + MwWaylandVulkan = MwTRUE; + } +#endif +#ifdef USE_COCOA + if(handle->lowlevel->common.type == MwLLBackendCocoa) { + arrput(o->enabledExtensions, VK_EXT_METAL_SURFACE_EXTENSION_NAME); + } +#endif + + /* passing null gives us all the extensions provided by the current vulkan implementation */ + VK_CMD(_vkEnumerateInstanceExtensionProperties(NULL, &extension_count, NULL)); + ext_props = malloc(sizeof(VkExtensionProperties) * extension_count); + VK_CMD(_vkEnumerateInstanceExtensionProperties(NULL, &extension_count, ext_props)); + o->vkInstanceExtensions = malloc(sizeof(const char*) * (arrlen(o->enabledExtensions) + 1)); + + for(i = 0; i < extension_count; i++) { + for(n = 0; n < (unsigned long)arrlen(o->enabledExtensions); n++) { + if(strcmp(ext_props[i].extensionName, o->enabledExtensions[n]) == 0) { + printf("[Vulkan Widget] Enabling extension %s\n", ext_props[i].extensionName); + o->vkInstanceExtensions[o->vkInstanceExtensionCount] = ext_props[i].extensionName; + o->vkInstanceExtensionCount++; + break; + } + } + } + + app_info = (VkApplicationInfo){ + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = NULL, + .pApplicationName = "", + .applicationVersion = vulkan_version, + .pEngineName = "", + .engineVersion = vulkan_version, + .apiVersion = api_version, + }; + + VK_CMD(_vkEnumerateInstanceLayerProperties(&layer_count, NULL)); + layer_props = malloc(sizeof(VkLayerProperties) * layer_count); + VK_CMD(_vkEnumerateInstanceLayerProperties(&layer_count, layer_props)); + o->vkLayers = malloc(256 * (arrlen(o->enabledLayers) + 1)); + + if(o->vulkan_config.validation_layers) { + arrput(o->enabledLayers, "VK_LAYER_KHRONOS_validation"); + } + for(i = 0; i < layer_count; i++) { + for(n = 0; n < (unsigned long)arrlen(o->enabledLayers); n++) { + if(strcmp(layer_props[i].layerName, o->enabledLayers[n]) == 0) { + printf("[Vulkan Widget] Enabling layer %s\n", layer_props[i].layerName); + o->vkLayers[o->vkLayerCount] = layer_props[i].layerName; + o->vkLayerCount++; + break; + } + } + } + o->vkLayers[i++] = NULL; + + instance_create_info = (VkInstanceCreateInfo){ + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .flags = 0, + .pApplicationInfo = &app_info, + .enabledExtensionCount = o->vkInstanceExtensionCount, + .enabledLayerCount = o->vkLayerCount, + .ppEnabledExtensionNames = o->vkInstanceExtensions, + .ppEnabledLayerNames = o->vkLayers, + }; + instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + + VK_CMD(_vkCreateInstance(&instance_create_info, NULL, &o->vkInstance)); + return 0; +} + +static int vulkan_surface_setup(MwWidget handle, vulkan_t* o) { + int vk_res; +#ifdef USE_GDI + if(handle->lowlevel->common.type == MwLLBackendGDI) { + LOAD_VK_FUNCTION(vkCreateWin32SurfaceKHR); + + VkWin32SurfaceCreateInfoKHR createInfo = { + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = NULL, + .flags = 0, + .hinstance = handle->lowlevel->gdi.hInstance, + .hwnd = handle->lowlevel->gdi.hWnd, + }; + + VK_CMD(_vkCreateWin32SurfaceKHR(o->vkInstance, &createInfo, NULL, + &o->vkSurface)); + } +#endif +#ifdef USE_X11 + if(handle->lowlevel->common.type == MwLLBackendX11) { + LOAD_VK_FUNCTION(vkCreateXlibSurfaceKHR); + + VkXlibSurfaceCreateInfoKHR createInfo = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .pNext = NULL, + .flags = 0, + .dpy = handle->lowlevel->x11.display, + .window = handle->lowlevel->x11.window, + }; + VK_CMD(_vkCreateXlibSurfaceKHR(o->vkInstance, &createInfo, NULL, &o->vkSurface)); + } +#endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + LOAD_VK_FUNCTION(vkCreateWaylandSurfaceKHR); + + VkWaylandSurfaceCreateInfoKHR createInfo = { + .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, + .pNext = NULL, + .flags = 0, + .display = handle->lowlevel->wayland.display, + .surface = handle->lowlevel->wayland.framebuffer.surface, + }; + VK_CMD(_vkCreateWaylandSurfaceKHR(o->vkInstance, &createInfo, NULL, &o->vkSurface)); + } +#endif +#ifdef USE_COCOA + if(handle->lowlevel->common.type == MwLLBackendCocoa) { + VkMetalSurfaceCreateInfoEXT MwCocoaGetMetalSurfaceCreateInfo(MwWidget handle); + VkMetalSurfaceCreateInfoEXT inf = MwCocoaGetMetalSurfaceCreateInfo(handle); + + LOAD_VK_FUNCTION(vkCreateMetalSurfaceEXT); + + VK_CMD(_vkCreateMetalSurfaceEXT(o->vkInstance, &inf, NULL, &o->vkSurface)); + } +#endif + return 0; +} + +static int vulkan_devices_setup(MwWidget handle, vulkan_t* o) { + (void)(handle); + + int vk_res; + unsigned long i, n; + uint32_t deviceCount; + VkPhysicalDevice* devices; + uint32_t queueFamilyCount; + VkQueueFamilyProperties* family_props; + float queuePriority = 1.0f; + VkDeviceQueueCreateInfo queueCreateInfos[2]; + VkDeviceCreateInfo createInfo; + VkExtensionProperties* ext_props; + uint32_t extension_count; + VkBool32 has_graphics = false; + VkBool32 has_present = false; + int queueCreateCount = 0; + + LOAD_VK_FUNCTION(vkEnumeratePhysicalDevices); + LOAD_VK_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties); + LOAD_VK_FUNCTION(vkCreateDevice); + LOAD_VK_FUNCTION(vkGetDeviceQueue); + LOAD_VK_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR); + LOAD_VK_FUNCTION(vkEnumerateDeviceExtensionProperties); + + /* create the physical device */ + VK_CMD(_vkEnumeratePhysicalDevices(o->vkInstance, &deviceCount, NULL)); + devices = malloc(sizeof(VkPhysicalDevice) * deviceCount); + VK_CMD(_vkEnumeratePhysicalDevices(o->vkInstance, &deviceCount, devices)); + + for(i = 0; i < deviceCount; i++) { + _vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &queueFamilyCount, NULL); + family_props = malloc(sizeof(VkQueueFamilyProperties) * queueFamilyCount); + _vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &queueFamilyCount, family_props); + o->vkGraphicsFamilyIDX = 0; + o->vkPresentFamilyIDX = 0; + for(n = 0; n < queueFamilyCount; n++) { + if(family_props[n].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + has_graphics = true; + o->vkGraphicsFamilyIDX = n; + }; + + _vkGetPhysicalDeviceSurfaceSupportKHR(devices[i], n, o->vkSurface, + &has_present); + if(has_present) { + o->vkPresentFamilyIDX = n; + } + if(has_graphics && has_present) { + o->vkPhysicalDevice = devices[i]; + break; + } + } + free(family_props); + } + if(!has_graphics && !has_present) { + /* rare, yes, but idk maybe some shitty drivers will present this dillema idk. */ + MwDispatchError(1, "There were no devices with either a graphics or presentation queue.\n"); + return 1; + } + + /* create the logical device */ + queueCreateInfos[queueCreateCount] = (VkDeviceQueueCreateInfo){ + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .queueFamilyIndex = o->vkGraphicsFamilyIDX, + .queueCount = 1, + .pQueuePriorities = &queuePriority, + }; + if(o->vkGraphicsFamilyIDX == o->vkPresentFamilyIDX) { + queueCreateInfos[queueCreateCount++] = (VkDeviceQueueCreateInfo){ + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .queueFamilyIndex = o->vkPresentFamilyIDX, + .queueCount = 1, + .pQueuePriorities = &queuePriority, + }; + } + + VK_CMD(_vkEnumerateDeviceExtensionProperties(o->vkPhysicalDevice, NULL, &extension_count, NULL)); + ext_props = malloc(sizeof(VkExtensionProperties) * extension_count); + VK_CMD(_vkEnumerateDeviceExtensionProperties(o->vkPhysicalDevice, NULL, &extension_count, ext_props)); + o->vkDeviceExtensions = malloc(sizeof(const char*) * (arrlen(o->enabledExtensions) + 1)); + + for(i = 0; i < extension_count; i++) { + for(n = 0; n < (unsigned long)arrlen(o->enabledExtensions); n++) { + if(strcmp(ext_props[i].extensionName, o->enabledExtensions[n]) == 0) { + o->vkDeviceExtensions[o->vkDeviceExtensionCount] = ext_props[i].extensionName; + o->vkDeviceExtensionCount++; + break; + } + } + } + + createInfo = (VkDeviceCreateInfo){ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .queueCreateInfoCount = queueCreateCount, + .pQueueCreateInfos = queueCreateInfos, + .pEnabledFeatures = NULL, + .enabledExtensionCount = o->vkDeviceExtensionCount, + .ppEnabledExtensionNames = o->vkDeviceExtensions, + .enabledLayerCount = o->vkLayerCount, + .ppEnabledLayerNames = o->vkLayers, + }; + + VK_CMD(_vkCreateDevice(o->vkPhysicalDevice, &createInfo, NULL, &o->vkLogicalDevice) != VK_SUCCESS); + + _vkGetDeviceQueue(o->vkLogicalDevice, o->vkGraphicsFamilyIDX, 0, &o->vkGraphicsQueue); + if(o->vkGraphicsFamilyIDX == o->vkPresentFamilyIDX) { + o->vkPresentQueue = o->vkGraphicsQueue; + } else { + _vkGetDeviceQueue(o->vkLogicalDevice, o->vkPresentFamilyIDX, 0, &o->vkPresentQueue); + } + free(devices); + return 0; +} + +int MwVulkanSupported(void) { + if(vulkan_supported == VULKAN_SUPPORTED_UNKNOWN) { + void* lib = vulkan_lib_load(); + if(lib == NULL) { + vulkan_supported = VULKAN_SUPPORTED_NO; + } else { + vulkan_supported = VULKAN_SUPPORTED_YES; + MwDynamicClose(lib); + } + } + if(vulkan_supported == VULKAN_SUPPORTED_YES) { + return 1; + } else { + return 0; + } +}; + +static void* mwVulkanGetFieldImpl(MwWidget handle, int field, int* err) { + vulkan_t* o = handle->internal; + char buf[1024]; + + switch(field) { + case MwVULKANFIELD_GETINSTANCEPROCADDR: + return o->vkGetInstanceProcAddr; + case MwVULKANFIELD_INSTANCE: + return o->vkInstance; + case MwVULKANFIELD_SURFACE: + return o->vkSurface; + case MwVULKANFIELD_PHYSICALDEVICE: + return o->vkPhysicalDevice; + case MwVULKANFIELD_LOGICALDEVICE: + return o->vkLogicalDevice; + case MwVULKANFIELD_GRAPHICSQUEUEINDEX: + return &o->vkGraphicsFamilyIDX; + case MwVULKANFIELD_PRESENTQUEUEINDEX: + return &o->vkPresentFamilyIDX; + case MwVULKANFIELD_GRAPHICSQUEUE: + return o->vkGraphicsQueue; + case MwVULKANFIELD_PRESENTQUEUE: + return o->vkPresentQueue; + default: + MwStringPrintIntoBuffer(buf, 1024, "Unknown vulkan field request (%d given)", field); + MwDispatchError(1, buf); + if(err != NULL) { + *err = 1; + } + return NULL; + } + if(err != NULL) { + *err = 0; + } +} + +static void prop_change(MwWidget handle, const char* prop) { + vulkan_t* o = (vulkan_t*)handle->internal; + if(!o) { + handle->internal = malloc(sizeof(vulkan_t)); + o = (vulkan_t*)handle->internal; + memset(o, 0, sizeof(vulkan_t)); + o->vulkan_config.api_version = VK_API_VERSION_1_0; + o->vulkan_config.vk_version = VK_VERSION_1_0; + o->vulkan_config.validation_layers = VK_FALSE; + } + + if(strcmp(prop, MwNvulkanExtension) == 0) { + char* str = MwStringDuplicate(MwGetText(handle, MwNvulkanExtension)); + + arrput(o->enabledExtensions, str); + } else if(strcmp(prop, MwNvulkanLayer) == 0) { + char* str = MwStringDuplicate(MwGetText(handle, MwNvulkanExtension)); + + arrput(o->enabledLayers, str); + } else if(strcmp(prop, MwNvulkanConfig) == 0) { + memcpy(&o->vulkan_config, MwGetVoid(handle, MwNvulkanConfig), sizeof(MwVulkanConfig)); + } +} + +static void func_handler(MwWidget handle, const char* name, void* output, va_list va) { + if(strcmp(name, "mwVulkanGetField") == 0) { + int field = va_arg(va, int); + int* err = va_arg(va, int*); + *(void**)output = mwVulkanGetFieldImpl(handle, field, err); + } +} + +MwClassRec MwVulkanClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + NULL, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwVulkanClass = &MwVulkanClassRec; +#else +MwClass MwVulkanClass = NULL; + +void MwVulkanConfigure(MwVulkanConfig* cfg) { + (void)cfg; +} + +int MwVulkanSupported(void) { + return 0; +} +#endif diff --git a/widget/milsko/milskosrc/src/widget/window.c b/widget/milsko/milskosrc/src/widget/window.c new file mode 100644 index 0000000000..3d0afe254e --- /dev/null +++ b/widget/milsko/milskosrc/src/widget/window.c @@ -0,0 +1,75 @@ +#include + +static int wcreate(MwWidget handle) { + MwSetDefault(handle); + + MwSetInteger(handle, MwNhasBorder, 0); + MwSetInteger(handle, MwNinverted, 1); + + return 0; +} + +static void draw(MwWidget handle) { + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwRect r; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, c, MwGetInteger(handle, MwNinverted)); + + MwDrawRect(handle, &r, c); + + MwLLFreeColor(c); +} + +static void prop_change(MwWidget handle, const char* key) { + if(strcmp(key, MwNhasBorder) == 0 || strcmp(key, MwNinverted) == 0) MwForceRender(handle); +} + +static void mwWindowMakeBorderlessImpl(MwWidget handle, int toggle) { + MwLLBeginStateChange(handle->lowlevel); + MwLLMakeBorderless(handle->lowlevel, toggle); + MwLLEndStateChange(handle->lowlevel); +} + +static void mwWindowShouldCloseImpl(MwWidget handle, MwBool* out) { + *out = handle->close; +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + (void)out; + + if(strcmp(name, "mwWindowMakeBorderless") == 0) { + int toggle = va_arg(va, int); + mwWindowMakeBorderlessImpl(handle, toggle); + } + if(strcmp(name, "mwWindowShouldClose") == 0) { + MwBool* out = va_arg(va, MwBool*); + mwWindowShouldCloseImpl(handle, out); + } +} +MwClassRec MwWindowClassRec = { + wcreate, /* create */ + NULL, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwWindowClass = &MwWindowClassRec; diff --git a/widget/milsko/milskosrc/tools/.gitignore b/widget/milsko/milskosrc/tools/.gitignore new file mode 100644 index 0000000000..0581170fb4 --- /dev/null +++ b/widget/milsko/milskosrc/tools/.gitignore @@ -0,0 +1,2 @@ +font +fuzzer diff --git a/widget/milsko/milskosrc/tools/Makefile b/widget/milsko/milskosrc/tools/Makefile new file mode 100644 index 0000000000..036e365888 --- /dev/null +++ b/widget/milsko/milskosrc/tools/Makefile @@ -0,0 +1,24 @@ +CC = gcc +CFLAGS = `pkg-config --cflags freetype2` -I../include +LDFLAGS = +LIBS = `pkg-config --libs freetype2` + +.PHONY: all clean +.SUFFIXES: .c .o + +all: fuzzer font icon-converter icon-converter + +fuzzer: fuzzer.o + $(CC) -g -L../src/ -Wl,-R../src -o $@ fuzzer.o -lMw + +font: font.o + $(CC) $(LDFLAGS) -o $@ font.o $(LIBS) + +icon-converter: icon-converter.o + $(CC) -o $@ icon-converter.o -lm + +.c.o: + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f *.o font fuzzer icon-converter diff --git a/widget/milsko/milskosrc/tools/archive.sh b/widget/milsko/milskosrc/tools/archive.sh new file mode 100644 index 0000000000..2a1c1f4972 --- /dev/null +++ b/widget/milsko/milskosrc/tools/archive.sh @@ -0,0 +1,20 @@ +#!/bin/sh +MAKE=make +if which gmake >/dev/null 2>&1; then + MAKE=gmake +fi +VERSION=`cat include/Mw/Version.h | grep -E 'MwVERSION' | grep -oE '"[^"]+"' | sed 's/"//g'` + +$MAKE clean +OLD=`pwd` +rm -rf /tmp/milsko-$VERSION *.tar.gz +mkdir -p /tmp/milsko-$VERSION + +cp -rf * /tmp/milsko-$VERSION/ + +cd /tmp + +tar czvf /tmp/milsko-$VERSION.tar.gz milsko-$VERSION + +rm -rf /tmp/milsko-$VERSION +mv /tmp/milsko-$VERSION.tar.gz $OLD/ diff --git a/widget/milsko/milskosrc/tools/color.pl b/widget/milsko/milskosrc/tools/color.pl new file mode 100644 index 0000000000..eca072ca13 --- /dev/null +++ b/widget/milsko/milskosrc/tools/color.pl @@ -0,0 +1,51 @@ +#!/usr/bin/env perl +open(IN, "<", "resource/rgb.txt"); +open(OUT, ">", "src/color.c"); + +print(OUT "#include \n"); +print(OUT "\n"); +print(OUT "#include \"../external/stb_ds.h\"\n"); +print(OUT "\n"); +print(OUT "struct color {\n"); +print(OUT " char* key;\n"); +print(OUT " MwU32 value;\n"); +print(OUT "};\n"); +print(OUT "\n"); +print(OUT "static struct color* colors = NULL;\n"); +print(OUT "\n"); +print(OUT "MwLLColor MwParseColorName(MwWidget handle, const char* color){\n"); +print(OUT " MwRGB rgb;\n"); +print(OUT " MwParseColorNameNoAllocate(color, &rgb);\n"); +print(OUT +" return MwLLAllocColor(handle->lowlevel, rgb.red, rgb.green, rgb.blue);\n" +); +print(OUT "}\n"); +print(OUT "\n"); +print(OUT "void MwParseColorNameNoAllocate(const char* color, MwRGB* rgb){\n"); +print(OUT " MwU32 v = shget(colors, color);"); +print(OUT " rgb->red = (v >> 16) & 0xff;"); +print(OUT " rgb->green = (v >> 8) & 0xff;"); +print(OUT " rgb->blue = (v >> 0) & 0xff;"); +print(OUT "}\n"); +print(OUT "\n"); +print(OUT + "static void add_color(const char* name, int red, int green, int blue){\n" +); +print(OUT " MwU32 v = (red << 16) | (green << 8) | (blue << 0);\n"); +print(OUT " shput(colors, name, v);\n"); +print(OUT "}\n"); +print(OUT "\n"); +print(OUT "void MwColorTableInit(void){\n"); +print(OUT " sh_new_strdup(colors);\n"); +print(OUT " shdefault(colors, 0);\n"); + +while (my $l = ) { + $l =~ s/\r?\n$//; + if ($l =~ /^[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+(.+)$/) { + print(OUT " add_color(\"$4\", $1, $2, $3);\n"); + } +} +print(OUT "}\n"); + +close(OUT); +close(IN); diff --git a/widget/milsko/milskosrc/tools/cursor.pl b/widget/milsko/milskosrc/tools/cursor.pl new file mode 100644 index 0000000000..1d3ca04f69 --- /dev/null +++ b/widget/milsko/milskosrc/tools/cursor.pl @@ -0,0 +1,136 @@ +#!/usr/bin/env perl +my $font = $ARGV[0]; +my $name = $ARGV[1]; +my $out = $ARGV[2]; +my $char = ""; +my $bmp = 0; + +my $w = 0; +my $h = 0; +my $ln = 0; +my $com = 0; +my $nocom = 0; + +my $MAX = 16; + +if ($name) { + print("#include \n"); + print("\n"); +} + +open(IN, "<", $font) or die; +while (my $l = ) { + $l =~ s/\r?\n$//g; + if (!$name && ($l =~ /^STARTCHAR ("?)(.+)\1$/)) { + if (!($2 =~ /_mask$/)) { + print("$2\n"); + } + } + elsif ($name && ($l =~ /^COPYRIGHT ("?)(.+)\1$/)) { + if (!$com) { + print("/**\n"); + } + else { + print(" *\n"); + } + print(" * Copyright notice:\n"); + print(" * $2\n"); + if (!$com) { + print(" */\n"); + } + } + elsif ($name && ($l =~ /^COMMENT ("?)(.+)\1$/)) { + if (!$nocom) { + if (!$com) { + $com = 1; + print("/**\n"); + } + print(" * $2\n"); + } + } + elsif ($name && ($l =~ /^ENDPROPERTIES$/)) { + if ($com) { + print(" */\n"); + $com = 0; + $nocom = 1; + } + } + elsif ( + $name + && ( ($l =~ /^STARTCHAR ("?)\Q$name\E\1$/) + || ($l =~ /^STARTCHAR ("?)\Q${name}\E_(mask)\1$/)) + ) + { + my $suffix = ""; + if ($2) { + $suffix = "Mask"; + } + $char = $name; + print("MwCursor MwCursor$out$suffix = {\n"); + } + elsif ($name + && $char + && ($l =~ /^BBX (\-?[0-9]+) (\-?[0-9]+) (\-?[0-9]+) (\-?[0-9]+)$/)) + { + print(" $1, $2, $3, $4,\n"); + + $w = $1 + 0; + $h = $2 + 0; + } + elsif ($name && $char && ($l =~ /^BITMAP$/)) { + print(" {\n"); + $bmp = 1; + $ln = 0; + } + elsif ($name && $char && ($l =~ /^ENDCHAR$/)) { + $bmp = 0; + $char = ""; + for (my $i = 0 ; $i < ($MAX - $h) ; $i++) { + if ($i == ($MAX - $h - 1)) { + print(" 0\n"); + } + else { + print(" 0,\n"); + } + } + print(" }\n"); + print("};\n"); + } + elsif ($bmp) { + my $txt = ""; + + my $c = 0; + my $n = 0; + my $incr = 0; + + my $num = 0; + + while ($c < $w) { + if (($c % 8) == 0) { + $n = hex("0x" . substr($l, $incr, 2)); + $incr += 2; + } + + $num = $num << 1; + if ($n & (1 << 7)) { + $num = $num | 1; + $txt = $txt . "#"; + } + else { + $num = $num | 0; + $txt = $txt . "."; + } + + $n = $n << 1; + $c = $c + 1; + } + $ln = $ln + 1; + if ($ln == $MAX) { + print(" $num /* $txt */\n"); + } + else { + print(" $num, /* $txt */\n"); + } + } +} +close(IN); diff --git a/widget/milsko/milskosrc/tools/doxygen.sh b/widget/milsko/milskosrc/tools/doxygen.sh new file mode 100644 index 0000000000..51de42c931 --- /dev/null +++ b/widget/milsko/milskosrc/tools/doxygen.sh @@ -0,0 +1,4 @@ +#!/bin/sh +doxygen +rm -rf /var/www/milsko-doxygen +cp -rf doxygen/html /var/www/milsko-doxygen diff --git a/widget/milsko/milskosrc/tools/font.c b/widget/milsko/milskosrc/tools/font.c new file mode 100644 index 0000000000..999b47efb4 --- /dev/null +++ b/widget/milsko/milskosrc/tools/font.c @@ -0,0 +1,70 @@ +#include +#include FT_FREETYPE_H +#include FT_BITMAP_H +#include FT_BDF_H + +#include +#include + +int main(int argc, char** argv) { + FT_Library lib; + FT_Face face; + int i; + int ay = 0; + int ax = 0; + int sy = 0; + int sx = 0; + BDF_PropertyRec rec; + + FT_Init_FreeType(&lib); + if(FT_New_Face(lib, argv[1], 0, &face)) { + fprintf(stderr, "bad 1\n"); + return 1; + } + + if(FT_Set_Pixel_Sizes(face, 0, atoi(argv[2]))) { + fprintf(stderr, "bad 2\n"); + return 1; + } + + FT_Get_BDF_Property(face, "COPYRIGHT", &rec); + + printf("#include \n"); + printf("\n"); + printf("/**\n"); + printf(" * Copyright notice:\n"); + printf(" * \"%s\"\n", rec.u.atom); + printf(" */\n"); + printf("MwFont MwFontData[] = {\n"); + for(i = 0; i < 0x100; i++) { + int y, x; + FT_Bitmap bitmap; + unsigned char n; + if(FT_Load_Char(face, i, FT_LOAD_RENDER | FT_LOAD_COLOR)) { + continue; + } + + FT_Bitmap_Init(&bitmap); + FT_Bitmap_Convert(lib, &face->glyph->bitmap, &bitmap, 1); + + printf("\t{%d, %d, {", face->glyph->bitmap_left, face->glyph->bitmap_top); + for(y = 0; y < atoi(argv[2]) - bitmap.rows; y++) { + printf("0%s", y == atoi(argv[2]) - 1 ? "" : ", "); + } + for(y = 0; y < bitmap.rows; y++) { + n = 0; + for(x = 0; x < bitmap.width; x++) { + unsigned char b = bitmap.buffer[bitmap.width * y + x] ? 1 : 0; + n = n << 1; + n = n | b; + } + printf("%d%s", n, y == (bitmap.rows - 1) ? "" : ", "); + } + printf("}}%s /* %d */\n", i == (0x100 - 1) ? "" : ", ", i); + + FT_Bitmap_Done(lib, &bitmap); + + sx += face->glyph->advance.x >> 6; + } + printf("};\n"); +} diff --git a/widget/milsko/milskosrc/tools/fuzzer.c b/widget/milsko/milskosrc/tools/fuzzer.c new file mode 100644 index 0000000000..dae1dde25a --- /dev/null +++ b/widget/milsko/milskosrc/tools/fuzzer.c @@ -0,0 +1,76 @@ +#include +#include + +#define WIDGET_AMOUNT 16 + +#define H(h) {&h, #h} + +typedef struct cls_pair { + MwClass* cls; + const char* name; +} cls_pair_t; + +cls_pair_t classes[] = {H(MwBoxClass), H(MwButtonClass), H(MwCheckBoxClass), H(MwComboBoxClass), H(MwEntryClass), H(MwFrameClass), H(MwImageClass), H(MwLabelClass), H(MwListBoxClass), H(MwMenuClass), H(MwNumberEntryClass), H(MwProgressBarClass), H(MwRadioBoxClass), H(MwScrollBarClass), H(MwSeparatorClass), H(MwTreeViewClass), H(MwViewportClass)}; +char* int_params[] = {/*MwNx, MwNy, MwNwidth, MwNheight,*/ MwNorientation, MwNminValue, MwNmaxValue, MwNvalue, MwNchangedBy, MwNareaShown, MwNchecked, MwNalignment, MwNbold, MwNmain, MwNleftPadding, MwNhasHeading, MwNhasBorder, MwNinverted, MwNmodernLook, MwNwaitMS, MwNhideInput, MwNsingleClickSelectable, MwNflat, MwNshowArrows, MwNpadding, MwNborderWidth, MwNfillArea, MwNratio, MwNfixedSize, MwNmargin, MwNbitmapFont, MwNsevenSegment, MwNlength, MwNforceInverted, MwNisRounded, MwNdarkTheme}; +unsigned long maxxes[] = {UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX}; + +int main() { + int i, j = 0, max = 0; + char input; + MwWidget window, widget; + unsigned long upper_limit; + + printf("How many iteration do you want to do? Type -1 if you wanna run it forever.\n"); + scanf("%d", &max); + + printf("What upper limit of int params do you want to test?\n"); + for(i = 0; i < (sizeof(maxxes) / sizeof(unsigned long)); i++) { + printf("%d) %lu\n", i, maxxes[i]); + } +get_input: + input = getchar(); + switch(input) { + case '0': + upper_limit = maxxes[0]; + break; + case '1': + upper_limit = maxxes[1]; + break; + case '2': + upper_limit = maxxes[2]; + break; + case '3': + upper_limit = maxxes[3]; + break; + default: + upper_limit = maxxes[0]; + // printf("Invalid value. Pick 0-3.\n"); + // goto get_input; + } + + MwLibraryInit(); + + window = MwCreateWidget(MwWindowClass, "window", NULL, 0, 0, 400, 400); + + while(MwPending(window) && (max == -1 || j < max)) { + int class_num = rand() % (sizeof(classes) / sizeof(cls_pair_t)); + widget = MwCreateWidget(*classes[class_num].cls, classes[class_num].name, window, 0, 0, 100, 100); + + printf("%s\n", classes[class_num].name); + /* apply int params with random scale */ + for(i = 0; i < (sizeof(int_params) / sizeof(void*)); i++) { + unsigned long number = rand() % upper_limit; + printf("> %s = %lu\n", int_params[i], number); + MwVaApply(widget, int_params[i], number, NULL); + } + MwStep(window); + + MwDestroyWidget(widget); + + printf("\n"); + + j++; + } + + MwFreeWidget(window); +} diff --git a/widget/milsko/milskosrc/tools/gendcl.pl b/widget/milsko/milskosrc/tools/gendcl.pl new file mode 100644 index 0000000000..f2e3399c37 --- /dev/null +++ b/widget/milsko/milskosrc/tools/gendcl.pl @@ -0,0 +1,105 @@ +#!/usr/bin/env perl + +our $clean = 0; +my @objs = (); + +sub compile { + my ($source) = @_; + my $object = ""; + my $dir = ""; + + $dir = $source; + $dir =~ s/\/([^\/]+)$//; + + $source =~ s/^(.+)\/([^\/]+)$/[\/\1]\2/; + $source =~ s/\//\./g; + + $object = $source; + $object =~ s/\.c$/.obj/; + + print(OUT "\$ if f\$search(\"$object;*\") .eqs. \"\"\n"); + print(OUT "\$ then\n"); + print(OUT "\$ write sys\$output \"CC $object\"\n"); + print(OUT +"\$ cc /include_directory=(\"./include\",\"./$dir\") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=$object $source\n" + ); + print(OUT "\$ endif\n"); + + push(@objs, $object); +} + +sub clean { + my ($source) = @_; + my $object = ""; + my $dir = ""; + + $source =~ s/^(.+)\/([^\/]+)$/[\/\1]\2/; + $source =~ s/\//\./g; + + $object = $source; + $object =~ s/\.c$/.obj/; + + print(OUT + "\$ if f\$search(\"$object\") .nes. \"\" then delete $object;*\n"); +} + +sub thing { + if ($clean) { + clean($_[0]); + } + else { + compile($_[0]); + } +} + +sub scan { + my ($dir) = @_; + + opendir(my $dh, $dir); + while (my $file = readdir($dh)) { + if ( !(($dir . "/" . $file) eq "src/widget/opengl.c") + && !(($dir . "/" . $file) eq "src/widget/vulkan.c") + && !(($dir . "/" . $file) eq "external/stb_truetype.c") + && !(($dir . "/" . $file) eq "external/stb_image.c") + && ($file =~ /\.c$/)) + { + thing($dir . "/" . $file); + } + } + closedir($dh); +} + +for (my $i = 0 ; $i < 2 ; $i++) { + $clean = $i; + + open(OUT, ">", $i == 0 ? "vms/build.com" : "vms/clean.com"); + scan("src"); + scan("src/cursor"); + scan("src/widget"); + scan("src/dialog"); + scan("src/font"); + scan("src/icon"); + scan("src/abstract"); + scan("external"); + thing("src/backend/x11.c"); + + if ($i == 0) { + print(OUT "\$ if f\$search(\"[.src]MwSHR.exe;*\") .eqs. \"\"\n"); + print(OUT "\$ then\n"); + print(OUT "\$ write sys\$output \"LINK [.src]MwSHR.exe\"\n"); + print(OUT "\$ OPEN /WRITE LINK_OPT LINK.OPT\n"); + foreach my $obj (@objs) { + print(OUT "\$ WRITE LINK_OPT \"$obj\"\n"); + } + print(OUT "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DECW\$XLIBSHR/SHARE\"\n"); + print(OUT "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DPML\$SHR/SHARE\"\n"); + print(OUT "\$ CLOSE LINK_OPT\n"); + print(OUT "\$ link /SHAREABLE=[.src]MwSHR.exe LINK.OPT/options\n"); + print(OUT "\$ DELETE LINK.OPT;*\n"); + print(OUT "\$ endif\n"); + } + else { + clean("src/MwSHR.exe"); + } + close(OUT); +} diff --git a/widget/milsko/milskosrc/tools/genmk.pl b/widget/milsko/milskosrc/tools/genmk.pl new file mode 100644 index 0000000000..9903c116de --- /dev/null +++ b/widget/milsko/milskosrc/tools/genmk.pl @@ -0,0 +1,235 @@ +#!/usr/bin/env perl +my @cfiles = (); +my @examples = (); + +sub scan { + opendir(DIR, $_[0]); + my @files = readdir(DIR); + foreach my $f (@files) { + if ($f =~ /^vulkan\.c$/) { + next; + } + if ($f =~ /\.c$/) { + push(@cfiles, $_[0] . "/" . $f); + } + } + closedir(DIR); +} + +sub scan_examples { + opendir(DIR, $_[0]); + my @files = readdir(DIR); + foreach my $f (@files) { + if ($f =~ /^glutlayer\.c$/) { + next; + } + if ($f =~ /\.c$/) { + push(@examples, $_[0] . "/" . $f); + } + } + closedir(DIR); +} + +sub cobjs { + my $r = ""; + foreach my $f (@cfiles) { + my $b = $f; + $b =~ s/\.c$/.obj/; + $b =~ s/\//$_[0]/g; + + $r = $r . " " . $_[1] . $b; + } + return $r; +} + +sub generate { + my ($output, $type) = @_; + + my $cc = ""; + my $link = ""; + + my $suffix = 1; + my $symbolic = ""; + my $dir = "\\"; + my $del = "del /f /q"; + my $out = ""; + my $dllout = ""; + my $exeout = ""; + my $def = ""; + my $inc = ""; + my $cdll = ""; + my $dll = ""; + my $exe = ""; + my $prefobj = ""; + my $needlibs = ""; + my $lib = ""; + my $c_dllout = ""; + my $c_dllafter = ""; + + if ($type eq "Borland") { + $cc = "bcc32 -c"; + $link = "bcc32"; + $out = "-o"; + $dllout = "-e"; + $exeout = "-e"; + $def = "-D"; + $inc = "-I"; + $dll = "-tWD"; + $lib = "-l"; + + $c_dllafter = "implib src${dir}Mw.lib src${dir}Mw.dll"; + } + elsif ($type eq "MSVC") { + $cc = "cl /TC /c /nologo"; + $link = "link /nologo"; + $out = "/Fo"; + $dllout = "/OUT:"; + $exeout = "/OUT:"; + $def = "/D"; + $inc = "/I"; + $dll = "/DLL"; + } + elsif ($type eq "Watcom") { + $cc = "wcc386 -bt=nt -q"; + $link = "wlink option quiet"; + $out = "-fo="; + $dllout = "name "; + $exeout = "name "; + $def = "-d"; + $inc = "-i="; + $cdll = "-bd"; + $dll = "system nt_dll"; + $exe = "system nt"; + $lib = "library "; + + $suffix = 0; # watcom suffix rule works kinda strange + $symbolic = ".SYMBOLIC"; + $dir = "/"; + $del = "%erase"; + $prefobj = "file "; + $needlibs = "${lib}clib3r.lib"; + $c_dllout = "option implib=src${dir}Mw.lib"; + } + + open(OUT, ">", $output); + print(OUT "CC = $cc\n"); + print(OUT "LD = $link\n"); + print(OUT "\n"); + print(OUT +"MW_CFLAGS = ${cdll} ${inc}include ${inc}external${dir}libz${dir}include ${def}_MILSKO ${def}_MILSKO_BUILD ${def}USE_GDI ${def}USE_STB_IMAGE ${def}STBI_NO_SIMD ${def}USE_GDI_TEXT\n" + ); + print(OUT "MW_LDFLAGS = $dll\n"); + print(OUT "EXE_CFLAGS = ${inc}include\n"); + print(OUT "EXE_LDFLAGS = $exe"); + print(OUT "\n"); + + if ($suffix) { + print(OUT ".SUFFIXES: .obj .c\n"); + } + print(OUT "all: src${dir}Mw.dll"); + foreach my $f (@examples) { + $b = $f; + $b =~ s/\.c$/.exe/; + $b =~ s/\//$dir/g; + print(OUT " $b"); + } + print(OUT "\n"); + print(OUT "lib: src${dir}Mw.dll\n"); + print(OUT "examples:"); + foreach my $f (@examples) { + $b = $f; + $b =~ s/\.c$/.exe/; + $b =~ s/\//$dir/g; + print(OUT " $b"); + } + print(OUT "\n"); + print(OUT "clean: $symbolic\n"); + foreach my $f (@cfiles) { + my $b = $f; + $b =~ s/\.c$/.obj/; + $b =~ s/\//$dir/g; + print(OUT " $del $b\n"); + } + print(OUT " $del src${dir}Mw.dll\n"); + print(OUT " $del src${dir}Mw.lib\n"); + foreach my $f (@examples) { + my $b = $f; + $b =~ s/\.c$/.obj/; + $b =~ s/\//$dir/g; + print(OUT " $del $b\n"); + } + foreach my $f (@examples) { + $b = $f; + $b =~ s/\.c$/.exe/; + $b =~ s/\//$dir/g; + print(OUT " $del $b\n"); + } + print(OUT "\n"); + foreach my $f (@examples) { + my $b = $f; + $b =~ s/\.c$/.exe/; + $b =~ s/\//$dir/g; + my $o = $f; + $o =~ s/\.c$/.obj/; + $o =~ s/\//$dir/g; + print(OUT "$b: $o src${dir}Mw.dll\n"); + print(OUT +" \$(LD) \$(EXE_LDFLAGS) $exeout\$@ $prefobj$o $needlibs ${lib}src${dir}Mw.lib" + ); + + if ($f =~ /gldemos/) { + print(OUT " ${lib}opengl32.lib ${lib}glu32.lib"); + } + print(OUT "\n"); + print(OUT "\n"); + print(OUT "$o: $f\n"); + print(OUT " \$(CC) \$(EXE_CFLAGS) ${out}\$@ $f\n"); + print(OUT "\n"); + } + print(OUT "\n"); + print(OUT "src${dir}Mw.dll: " . cobjs($dir) . "\n"); + print( OUT " \$(LD) \$(MW_LDFLAGS) $c_dllout $dllout\$@ " + . cobjs($dir, $prefobj) + . " $needlibs ${lib}opengl32.lib ${lib}gdi32.lib ${lib}winmm.lib ${lib}user32.lib ${lib}advapi32.lib\n" + ); + print(OUT " $c_dllafter\n"); + print(OUT "\n"); + + if ($suffix) { + print(OUT ".c.obj:\n"); + print(OUT " \$(CC) \$(MW_CFLAGS) ${out}\$@ \$<\n"); + } + else { + print(OUT "\n"); + foreach my $f (@cfiles) { + my $o = $f; + $o =~ s/\.c$/.obj/; + print(OUT "$o: $f\n"); + print(OUT " \$(CC) \$(MW_CFLAGS) ${out}\$@ $f\n"); + } + } + close(OUT); +} + +scan("src"); +scan("external"); +scan("external/libz/src"); +scan("src/icon"); +scan("src/cursor"); +scan("src/widget"); +scan("src/text"); +scan("src/text/font"); +scan("src/dialog"); +scan("src/abstract"); +push(@cfiles, "src/backend/gdi.c"); + +@cfiles = sort(@cfiles); + +scan_examples("examples/basic"); +scan_examples("examples/gldemos"); + +@examples = sort(@examples); + +generate("BorMakefile", "Borland"); +generate("NTMakefile", "MSVC"); +generate("WatMakefile", "Watcom"); diff --git a/widget/milsko/milskosrc/tools/harvard.pl b/widget/milsko/milskosrc/tools/harvard.pl new file mode 100644 index 0000000000..ae602e2554 --- /dev/null +++ b/widget/milsko/milskosrc/tools/harvard.pl @@ -0,0 +1,12 @@ +#!/usr/bin/env perl +open(IN, "<", "resource/harvard.txt"); +print("const char* harvard[] = {\n"); +while (my $l = ) { + $l =~ s/\r?\n$//; + if ($l =~ /^[ \t]*[0-9]+\. (.+)$/) { + print(" \"" . $1 . "\",\n"); + } +} +print(" NULL\n"); +print("};\n"); +close(IN); diff --git a/widget/milsko/milskosrc/tools/icon-converter.c b/widget/milsko/milskosrc/tools/icon-converter.c new file mode 100644 index 0000000000..11dc4510e6 --- /dev/null +++ b/widget/milsko/milskosrc/tools/icon-converter.c @@ -0,0 +1,36 @@ +#define STB_IMAGE_IMPLEMENTATION +#include "../external/stb_image.h" + +#include + +int main(int argc, char** argv) { + unsigned char* rgba; + int width, height, bpp; + int i; + + if(argc != 3) { + printf("Usage: %s input name\n", argv[0]); + return 1; + } + + rgba = stbi_load(argv[1], &width, &height, &bpp, 4); + + printf("MwU32 %s[] = {\n", argv[2]); + printf(" (%d << 16) | %d,\n", width, height); + for(i = 0; i < width * height; i++) { + unsigned char* px = &rgba[i * 4]; + unsigned int p = 0; + int j; + + for(j = 0; j < 4; j++) { + p = p << 8; + p = p | px[j]; + } + + printf(" 0x%x,\n", p); + } + printf(" 0\n"); + printf("};\n"); + + free(rgba); +} diff --git a/widget/milsko/milskosrc/tools/icon.sh b/widget/milsko/milskosrc/tools/icon.sh new file mode 100644 index 0000000000..746d50464e --- /dev/null +++ b/widget/milsko/milskosrc/tools/icon.sh @@ -0,0 +1,44 @@ +#!/bin/sh +echo '/*!' > include/Mw/Resource/Icon.h +echo ' * @file Mw/Resource/Icon.h' >> include/Mw/Resource/Icon.h +echo ' * @brief Icon' >> include/Mw/Resource/Icon.h +echo ' */' >> include/Mw/Resource/Icon.h +echo '#ifndef __MW_RESOURCE_ICON_H__' >> include/Mw/Resource/Icon.h +echo '#define __MW_RESOURCE_ICON_H__' >> include/Mw/Resource/Icon.h +echo '' >> include/Mw/Resource/Icon.h +echo '#include ' >> include/Mw/Resource/Icon.h +echo '' >> include/Mw/Resource/Icon.h +echo '#ifdef __cplusplus' >> include/Mw/Resource/Icon.h +echo 'extern "C" {' >> include/Mw/Resource/Icon.h +echo '#endif' >> include/Mw/Resource/Icon.h +echo '' >> include/Mw/Resource/Icon.h +for i in resource/icon/*.png; do + LOWER=`echo $i | rev | cut -d"/" -f1 | rev | cut -d"." -f1` + OUT=src/icon/$LOWER.c + NAME=`echo -n $LOWER | perl -e 'my $l = <>;$l =~ s/^(.)/uc($1)/e;print($l);'` + NAME=MwIcon$NAME + GEO=`convert $i json:- 2>/dev/null | jq -r '(.[0].image.geometry.width | tostring) + "x" + (.[0].image.geometry.height | tostring)'` + WIDTH=`echo $GEO | cut -dx -f1` + HEIGHT=`echo $GEO | cut -dx -f2` + echo '#include ' > $OUT + echo >> $OUT + echo "MwU32 $NAME[] = {" >> $OUT + echo " ($WIDTH << 16) | $HEIGHT," >> $OUT + convert $i txt:- 2>/dev/null | grep -oE '#[0-9a-fA-F]{8}' | sed 's/^#/ 0x/' | sed -E 's/$/,/' >> $OUT + echo " 0" >> $OUT + echo "};" >> $OUT + echo $NAME +done | while read a; do + echo $a + echo '/*!' >> include/Mw/Resource/Icon.h + echo " * @brief `echo $a | sed s/MwIcon//` icon" >> include/Mw/Resource/Icon.h + echo ' */' >> include/Mw/Resource/Icon.h + echo "MWDECL MwU32 $a[];" >> include/Mw/Resource/Icon.h + echo '' >> include/Mw/Resource/Icon.h +done +echo '' >> include/Mw/Resource/Icon.h +echo '#ifdef __cplusplus' >> include/Mw/Resource/Icon.h +echo '}' >> include/Mw/Resource/Icon.h +echo '#endif' >> include/Mw/Resource/Icon.h +echo '' >> include/Mw/Resource/Icon.h +echo '#endif' >> include/Mw/Resource/Icon.h diff --git a/widget/milsko/milskosrc/tools/logo.sh b/widget/milsko/milskosrc/tools/logo.sh new file mode 100644 index 0000000000..9d346018bd --- /dev/null +++ b/widget/milsko/milskosrc/tools/logo.sh @@ -0,0 +1,9 @@ +#!/bin/sh +povray +A +W256 +H256 +Ologo.png resource/logo/logo.pov +povray +A +W1280 +H640 +Obanner.png resource/logo/banner.pov +povray +A +W1280 +H640 +Obanner-nodejs.png Declare=NODEJS=1 resource/logo/banner.pov +povray +A +W102 +H47 +O102x47.png resource/logo/102x47.pov +mv logo.png banner.png banner-nodejs.png resource/logo/ +magick resource/logo/logo.png -scale x64 resource/logo/logo64.png +magick 102x47.png resource/logo/overlay-102x47.png -compose over -composite resource/logo/102x47.png +rm -f 102x47.png diff --git a/widget/milsko/milskosrc/tools/prepare-gump.sh b/widget/milsko/milskosrc/tools/prepare-gump.sh new file mode 100644 index 0000000000..c3d4797ce6 --- /dev/null +++ b/widget/milsko/milskosrc/tools/prepare-gump.sh @@ -0,0 +1,6 @@ +#!/bin/sh +for i in linux win32 win64 doxygen; do + rm -rf ../milsko-$i + cp -rf . ../milsko-$i + rm -rf ../milsko-$i/.svn +done diff --git a/widget/milsko/milskosrc/tools/readme.pl b/widget/milsko/milskosrc/tools/readme.pl new file mode 100644 index 0000000000..d7c1909ad2 --- /dev/null +++ b/widget/milsko/milskosrc/tools/readme.pl @@ -0,0 +1,121 @@ +#!/usr/bin/env perl +our $WIDTH = 80; + +sub l { + my $len = 0; + my $last = 0; + my @msg = split(/ /, $_[0]); + foreach my $m (@msg) { + $len += 1 + length($m); + $last = 0; + if ($len > $WIDTH) { + print(OUT "\n"); + $len = 0; + $last = 1; + } + print(OUT "$m "); + } + if (!$last) { + print(OUT "\n"); + } +} + +sub c { + my ($msg) = @_; + my $len = length($msg); + if ($_[1]) { + $len = $_[1]; + } + print(OUT (" " x (($WIDTH - $len) / 2)) . "$msg\n"); +} + +sub h { + my ($msg) = @_; + print(OUT "\n"); + print(OUT "$msg\n"); + print(OUT ("-" x length($msg)) . "\n"); + print(OUT "\n"); +} + +open(IN, "<", "include/Mw/Version.h"); +my @lines = ; +close(IN); +my @match = grep(/MwVERSION/, @lines); + +my $ver = $match[0]; +$ver =~ /\"([^"]+)\"/; +$ver = $1; + +open(OUT, ">", "README.txt"); + +l(""); +l("Greetings - Welcome to the Milsko GUI Toolkit (Version " . $ver . ")"); +l(""); +l( +" This document contains a brief summary of the contents of this source distributions and building instructions for Milsko GUI Toolkit." +); + +l(""); +c("Requirements"); +l(""); +l(" Milsko requires either"); +l(" * A Windows environment with GDI (so anything NT or 9x)"); + +#l(" * A MacOS environment with Cocoa (10.4 or above supported)"); +l(" * A Unix-like environment with Wayland and/or X11 for runtime."); +l(""); +l(" To build Milsko for Windows, you must have one of following compilers:"); +l(" * Visual C++ 6.0 or newer"); +l(" * Borland C++ 5.5 or newer"); +l(" * Open Watcom 2.0 or newer"); +l(" * MinGW-w64"); +l(""); +l(" and for Unix-like and MacOS:"); +l(" * GNU C Compiler"); +l(" * Clang"); +l(""); + +l(""); +c("Contents"); +l(""); +c(" At the top level of this hierarchy there are seven directories:", 60); +l(""); +c(" src - Contains the source for Milsko library", 60); +l(""); +c(" include - Contains the headers for Milsko", 60); +l(""); +c(" doc - Contains the documentation for Milsko", 60); +l(""); +c(" external - Contains the external dependency that Milsko uses", 60); +l(""); +c(" resource - Contains the resources used by maintainers", 60); +l(""); +c(" tools - Contains the tools used by maintainers", 60); +l(""); + +l(""); +c("Building Milsko"); +l(""); +l(" Building Milsko depends on the platform you use, and the compiler you use." +); +h("A. Visual C++"); +l("1) Run `nmake -f NTMakefile'."); +h("B. Borland C++"); +l("1) Run `make -f BorMakefile'."); +h("C. Open Watcom"); +l("1) Run `wmake -f WatMakefile'."); +h("D. MinGW-w64/GCC/Clang"); +l("1) Determine if you need Vulkan and/or OpenGL."); +l(""); +l("2) Either:"); +l(" a.) Run `./configure'. For help, run `./configure --help'."); +l( +" b.) Use CMake; i.e. `cmake -B build`. (if contributing, name the build folder build as that's what's included in the .gitignore)" +); +l(""); +l("3) Run `make'."); +l(""); + +l(" -- Nishi (nishi\@nishi.boats)"); + +close(OUT); diff --git a/widget/milsko/milskosrc/tools/ttf.sh b/widget/milsko/milskosrc/tools/ttf.sh new file mode 100644 index 0000000000..eef90857ab --- /dev/null +++ b/widget/milsko/milskosrc/tools/ttf.sh @@ -0,0 +1,11 @@ +#!/bin/sh +for out in src/font/ttf.c src/font/boldttf.c; do + echo '#include ' > $out + echo '' >> $out + echo '#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2)' >> $out +done +xxd -n MwTTFData -i resource/font/IBMPlexMono.ttf | sed s/_len/Size/ >> src/font/ttf.c +xxd -n MwBoldTTFData -i resource/font/IBMPlexMono-Bold.ttf | sed s/_len/Size/ >> src/font/boldttf.c +for out in src/font/ttf.c src/font/boldttf.c; do + echo '#endif' >> $out +done diff --git a/widget/milsko/milskosrc/tools/update.sh b/widget/milsko/milskosrc/tools/update.sh new file mode 100644 index 0000000000..12e8455e81 --- /dev/null +++ b/widget/milsko/milskosrc/tools/update.sh @@ -0,0 +1,7 @@ +#!/bin/sh +MAKE=make +if which gmake >/dev/null 2>&1; then + MAKE=gmake +fi +./tools/genmk.pl +$MAKE format diff --git a/widget/milsko/milskosrc/tools/watcom-pack.sh b/widget/milsko/milskosrc/tools/watcom-pack.sh new file mode 100644 index 0000000000..e9bfb604e2 --- /dev/null +++ b/widget/milsko/milskosrc/tools/watcom-pack.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -e +wmake -f WatMakefile +rm -rf milsko +mkdir -p milsko-examples +cp src/Mw.dll milsko-examples/ +cp examples/basic/*.exe milsko-examples/ +for i in examples/gldemos/*.exe; do + cp $i milsko-examples/gl`echo $i | rev | cut -d/ -f1 | rev` +done +rm -f milsko-examples.zip +cp resource/logo/logo.png examples/picture.jpg examples/picture.png milsko-examples/ +zip -rv milsko-examples.zip milsko-examples diff --git a/xpcom/base/nsUUIDGenerator.cpp b/xpcom/base/nsUUIDGenerator.cpp index 55a8715b19..6ad03dd8e7 100644 --- a/xpcom/base/nsUUIDGenerator.cpp +++ b/xpcom/base/nsUUIDGenerator.cpp @@ -98,8 +98,6 @@ nsUUIDGenerator::GenerateUUID(nsID** aRet) NS_IMETHODIMP nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId) { - // The various code in this method is probably not threadsafe, so lock - // across the whole method. MutexAutoLock lock(mLock); #if defined(XP_WIN) @@ -107,6 +105,7 @@ nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId) if (FAILED(hr)) { return NS_ERROR_FAILURE; } + #elif defined(XP_MACOSX) CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); if (!uuid) { @@ -115,90 +114,62 @@ nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId) CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid); memcpy(aId, &bytes, sizeof(nsID)); - CFRelease(uuid); -#else /* not windows or OS X; generate randomness using random(). */ - /* XXX we should be saving the return of setstate here and switching - * back to it; instead, we use the value returned when we called - * initstate, since older glibc's have broken setstate() return values - */ + +#else /* POSIX randomness */ + #ifndef HAVE_ARC4RANDOM setstate(mState); #endif #if defined(__linux__) - // Linux does not provide arc4random_buf or arc4random. - // Use /dev/urandom for secure UUID generation. + // Try /dev/urandom first int fd = open("/dev/urandom", O_RDONLY); if (fd >= 0) { ssize_t n = read(fd, aId, sizeof(nsID)); close(fd); if (n == sizeof(nsID)) { - return NS_OK; + goto version_bits; } } - - // Fallback if /dev/urandom fails - size_t bytesLeft = sizeof(nsID); - while (bytesLeft > 0) { - long rval = random(); - const size_t mRBytes = 4; - size_t toCopy = std::min(bytesLeft, mRBytes); - memcpy(reinterpret_cast(aId) + (sizeof(nsID) - bytesLeft), - &rval, toCopy); - bytesLeft -= toCopy; - } - -#else +#endif #ifdef HAVE_ARC4RANDOM_BUF arc4random_buf(aId, sizeof(nsID)); -#else /* HAVE_ARC4RANDOM_BUF */ + +#else size_t bytesLeft = sizeof(nsID); while (bytesLeft > 0) { #ifdef HAVE_ARC4RANDOM long rval = arc4random(); - const size_t mRBytes = 4; #else long rval = random(); - const size_t mRBytes = 4; #endif + const size_t mRBytes = 4; size_t toCopy = std::min(bytesLeft, mRBytes); + memcpy(reinterpret_cast(aId) + (sizeof(nsID) - bytesLeft), &rval, toCopy); + bytesLeft -= toCopy; } #endif /* HAVE_ARC4RANDOM_BUF */ - uint8_t* src = (uint8_t*)&rval; - // We want to grab the mRBytes least significant bytes of rval, since - // mRBytes less than sizeof(rval) means the high bytes are 0. -#ifdef IS_BIG_ENDIAN - src += sizeof(rval) - mRBytes; -#endif - uint8_t* dst = ((uint8_t*)aId) + (sizeof(nsID) - bytesLeft); - size_t toWrite = (bytesLeft < mRBytes ? bytesLeft : mRBytes); - for (size_t i = 0; i < toWrite; i++) { - dst[i] = src[i]; - } +version_bits: - bytesLeft -= toWrite; - } -#endif /* HAVE_ARC4RANDOM_BUF */ - - /* Put in the version */ + /* RFC4122 version */ aId->m2 &= 0x0fff; aId->m2 |= 0x4000; - /* Put in the variant */ + /* RFC4122 variant */ aId->m3[0] &= 0x3f; aId->m3[0] |= 0x80; #ifndef HAVE_ARC4RANDOM - /* Restore the previous RNG state */ setstate(mSavedState); #endif -#endif + +#endif /* POSIX randomness */ return NS_OK; } diff --git a/xpcom/threads/TimerThread.cpp b/xpcom/threads/TimerThread.cpp index ca0cd3cb9c..30ab2f89a9 100644 --- a/xpcom/threads/TimerThread.cpp +++ b/xpcom/threads/TimerThread.cpp @@ -354,8 +354,7 @@ TimerThread::Shutdown() // might potentially call some code reentering the same lock // that leads to unexpected behavior or deadlock. // See bug 422472. - timers.AppendElements(mTimers); - mTimers.Clear(); + timers.SwapElements(mTimers); } uint32_t timersCount = timers.Length();